summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/ABI/testing/debugfs-ec20
-rw-r--r--Documentation/ABI/testing/debugfs-kmemtrace71
-rw-r--r--Documentation/ABI/testing/sysfs-bus-pci27
-rw-r--r--Documentation/ABI/testing/sysfs-devices-memory6
-rw-r--r--Documentation/ABI/testing/sysfs-devices-system-cpu2
-rw-r--r--Documentation/ABI/testing/sysfs-driver-hid-roccat-kone13
-rw-r--r--Documentation/ABI/testing/sysfs-power15
-rw-r--r--Documentation/Changes12
-rw-r--r--Documentation/DocBook/device-drivers.tmpl1
-rw-r--r--Documentation/DocBook/dvb/dvbapi.xml19
-rw-r--r--Documentation/DocBook/dvb/frontend.h.xml1
-rw-r--r--Documentation/DocBook/dvb/frontend.xml10
-rw-r--r--Documentation/DocBook/kgdb.tmpl108
-rw-r--r--Documentation/DocBook/media-entities.tmpl1
-rw-r--r--Documentation/DocBook/media.tmpl8
-rw-r--r--Documentation/DocBook/scsi.tmpl2
-rw-r--r--Documentation/DocBook/stylesheet.xsl1
-rw-r--r--Documentation/DocBook/v4l/compat.xml5
-rw-r--r--Documentation/DocBook/v4l/fdl-appendix.xml2
-rw-r--r--Documentation/DocBook/v4l/lirc_device_interface.xml235
-rw-r--r--Documentation/DocBook/v4l/remote_controllers.xml2
-rw-r--r--Documentation/HOWTO6
-rw-r--r--Documentation/PCI/pci.txt2
-rw-r--r--Documentation/RCU/RTFP.txt2
-rw-r--r--Documentation/SubmittingDrivers2
-rw-r--r--Documentation/aoe/aoe.txt2
-rw-r--r--Documentation/apparmor.txt39
-rw-r--r--Documentation/arm/IXP20002
-rw-r--r--Documentation/arm/IXP4xx14
-rw-r--r--Documentation/arm/README4
-rw-r--r--Documentation/arm/SA1100/Assabet5
-rw-r--r--Documentation/arm/SA1100/Brutus2
-rw-r--r--Documentation/arm/SA1100/FreeBird2
-rw-r--r--Documentation/arm/SA1100/GraphicsClient2
-rw-r--r--Documentation/arm/SA1100/GraphicsMaster2
-rw-r--r--Documentation/arm/SA1100/Itsy2
-rw-r--r--Documentation/arm/SA1100/PLEB2
-rw-r--r--Documentation/arm/SA1100/Victor2
-rw-r--r--Documentation/arm/SA1100/nanoEngine2
-rw-r--r--Documentation/binfmt_misc.txt2
-rw-r--r--Documentation/block/biodoc.txt2
-rw-r--r--Documentation/blockdev/paride.txt2
-rw-r--r--Documentation/cdrom/packet-writing.txt2
-rw-r--r--Documentation/cgroups/cpusets.txt2
-rw-r--r--Documentation/coccinelle.txt258
-rw-r--r--Documentation/development-process/4.Coding2
-rw-r--r--Documentation/device-mapper/dm-crypt.txt2
-rw-r--r--Documentation/devices.txt9
-rw-r--r--Documentation/dvb/faq.txt2
-rw-r--r--Documentation/dvb/get_dvb_firmware25
-rw-r--r--Documentation/fb/framebuffer.txt2
-rw-r--r--Documentation/feature-removal-schedule.txt126
-rw-r--r--Documentation/filesystems/9p.txt2
-rw-r--r--Documentation/filesystems/affs.txt2
-rw-r--r--Documentation/filesystems/befs.txt4
-rw-r--r--Documentation/filesystems/caching/fscache.txt10
-rw-r--r--Documentation/filesystems/isofs.txt2
-rw-r--r--Documentation/filesystems/nfs/nfsroot.txt2
-rw-r--r--Documentation/filesystems/nilfs2.txt12
-rw-r--r--Documentation/filesystems/proc.txt4
-rw-r--r--Documentation/filesystems/sysfs-pci.txt7
-rw-r--r--Documentation/filesystems/sysfs.txt46
-rw-r--r--Documentation/filesystems/vfat.txt3
-rw-r--r--Documentation/filesystems/xfs.txt11
-rw-r--r--Documentation/firmware_class/hotplug-script17
-rw-r--r--Documentation/hwmon/adm10262
-rw-r--r--Documentation/hwmon/g760a2
-rw-r--r--Documentation/hwmon/gl518sm3
-rw-r--r--Documentation/hwmon/hpfall.c2
-rw-r--r--Documentation/hwmon/k8temp2
-rw-r--r--Documentation/hwmon/lm856
-rw-r--r--Documentation/hwmon/pkgtemp36
-rw-r--r--Documentation/hwmon/smsc47m111
-rw-r--r--Documentation/hwmon/thmc502
-rw-r--r--Documentation/hwmon/via686a2
-rw-r--r--Documentation/hwmon/w83627hf6
-rw-r--r--Documentation/hwmon/w83781d2
-rw-r--r--Documentation/hwmon/w83792d2
-rw-r--r--Documentation/i2c/busses/i2c-ali15352
-rw-r--r--Documentation/i2c/busses/i2c-ali15632
-rw-r--r--Documentation/i2c/busses/i2c-ali15x32
-rw-r--r--Documentation/i2c/busses/i2c-piix42
-rw-r--r--Documentation/i2c/busses/i2c-sis6302
-rw-r--r--Documentation/ia64/aliasing.txt2
-rw-r--r--Documentation/ia64/serial.txt2
-rw-r--r--Documentation/infiniband/user_verbs.txt2
-rw-r--r--Documentation/input/appletouch.txt2
-rw-r--r--Documentation/input/bcm5974.txt2
-rw-r--r--Documentation/input/iforce-protocol.txt2
-rw-r--r--Documentation/input/multi-touch-protocol.txt218
-rw-r--r--Documentation/input/sentelic.txt2
-rw-r--r--Documentation/input/xpad.txt2
-rw-r--r--Documentation/intel_txt.txt12
-rw-r--r--Documentation/ioctl/ioctl-number.txt11
-rw-r--r--Documentation/isdn/INTERFACE.CAPI8
-rw-r--r--Documentation/isdn/README2
-rw-r--r--Documentation/isdn/README.HiSax2
-rw-r--r--Documentation/isdn/README.gigaset117
-rw-r--r--Documentation/ja_JP/HOWTO2
-rw-r--r--Documentation/ja_JP/SubmittingPatches6
-rw-r--r--Documentation/kbuild/kbuild.txt34
-rw-r--r--Documentation/kbuild/kconfig.txt2
-rw-r--r--Documentation/kbuild/makefiles.txt127
-rw-r--r--Documentation/kernel-docs.txt39
-rw-r--r--Documentation/kernel-parameters.txt205
-rw-r--r--Documentation/ko_KR/HOWTO8
-rw-r--r--Documentation/kprobes.txt1
-rw-r--r--Documentation/kvm/api.txt208
-rw-r--r--Documentation/kvm/mmu.txt52
-rw-r--r--Documentation/kvm/msr.txt153
-rw-r--r--Documentation/kvm/review-checklist.txt38
-rw-r--r--Documentation/laptops/acer-wmi.txt2
-rw-r--r--Documentation/laptops/thinkpad-acpi.txt71
-rw-r--r--Documentation/ldm.txt2
-rw-r--r--Documentation/md.txt2
-rw-r--r--Documentation/misc-devices/c2port.txt4
-rw-r--r--Documentation/mtd/nand_ecc.txt2
-rw-r--r--Documentation/networking/3c509.txt2
-rw-r--r--Documentation/networking/README.ipw21003
-rw-r--r--Documentation/networking/README.ipw22004
-rw-r--r--Documentation/networking/README.sb10004
-rw-r--r--Documentation/networking/arcnet.txt4
-rw-r--r--Documentation/networking/bonding.txt86
-rw-r--r--Documentation/networking/caif/spi_porting.txt208
-rw-r--r--Documentation/networking/decnet.txt2
-rw-r--r--Documentation/networking/dns_resolver.txt146
-rw-r--r--Documentation/networking/fore200e.txt2
-rw-r--r--Documentation/networking/ip-sysctl.txt2
-rw-r--r--Documentation/networking/ipddp.txt5
-rw-r--r--Documentation/networking/iphase.txt2
-rw-r--r--Documentation/networking/packet_mmap.txt30
-rw-r--r--Documentation/networking/pktgen.txt5
-rw-r--r--Documentation/networking/ray_cs.txt4
-rw-r--r--Documentation/networking/s2io.txt3
-rw-r--r--Documentation/networking/tlan.txt4
-rw-r--r--Documentation/networking/udplite.txt13
-rw-r--r--Documentation/networking/wavelan.txt3
-rw-r--r--Documentation/padata.txt97
-rw-r--r--Documentation/pcmcia/driver-changes.txt12
-rw-r--r--Documentation/power/apm-acpi.txt2
-rw-r--r--Documentation/power/basic-pm-debugging.txt3
-rw-r--r--Documentation/power/tricks.txt2
-rw-r--r--Documentation/power/video.txt12
-rw-r--r--Documentation/powerpc/booting-without-of.txt2
-rw-r--r--Documentation/powerpc/dts-bindings/fsl/diu.txt20
-rw-r--r--Documentation/powerpc/dts-bindings/fsl/i2c.txt2
-rw-r--r--Documentation/rt-mutex-design.txt2
-rw-r--r--Documentation/s390/Debugging390.txt2
-rw-r--r--Documentation/scsi/BusLogic.txt2
-rw-r--r--Documentation/scsi/ChangeLog.lpfc2
-rw-r--r--Documentation/scsi/ChangeLog.megaraid2
-rw-r--r--Documentation/scsi/FlashPoint.txt4
-rw-r--r--Documentation/scsi/Mylex.txt2
-rw-r--r--Documentation/scsi/NinjaSCSI.txt2
-rw-r--r--Documentation/scsi/aic79xx.txt2
-rw-r--r--Documentation/scsi/aic7xxx.txt2
-rw-r--r--Documentation/scsi/hpsa.txt107
-rw-r--r--Documentation/scsi/ibmmca.txt2
-rw-r--r--Documentation/scsi/osst.txt2
-rw-r--r--Documentation/scsi/ppa.txt6
-rw-r--r--Documentation/scsi/scsi-generic.txt8
-rw-r--r--Documentation/scsi/scsi.txt4
-rw-r--r--Documentation/scsi/scsi_mid_low_api.txt2
-rw-r--r--Documentation/serial/moxa-smartio2
-rw-r--r--Documentation/slow-work.txt322
-rw-r--r--Documentation/sound/alsa/ALSA-Configuration.txt2
-rw-r--r--Documentation/sound/alsa/HD-Audio-Models.txt6
-rw-r--r--Documentation/sound/alsa/HD-Audio.txt2
-rw-r--r--Documentation/sound/alsa/Procfile.txt8
-rw-r--r--Documentation/sound/alsa/alsa-parameters.txt135
-rw-r--r--Documentation/sound/alsa/soc/DAI.txt2
-rw-r--r--Documentation/sound/alsa/soc/codec.txt2
-rw-r--r--Documentation/sound/alsa/soc/platform.txt2
-rw-r--r--Documentation/sound/oss/README.OSS5
-rw-r--r--Documentation/sound/oss/oss-parameters.txt51
-rw-r--r--Documentation/sparse.txt2
-rw-r--r--Documentation/sysctl/vm.txt2
-rw-r--r--Documentation/telephony/ixj.txt9
-rw-r--r--Documentation/timers/timers-howto.txt105
-rw-r--r--Documentation/tomoyo.txt10
-rw-r--r--Documentation/trace/ftrace-design.txt153
-rw-r--r--Documentation/trace/kmemtrace.txt126
-rw-r--r--Documentation/trace/kprobetrace.txt2
-rw-r--r--Documentation/uml/UserModeLinux-HOWTO.txt73
-rw-r--r--Documentation/usb/linux.inf2
-rw-r--r--Documentation/usb/mtouchusb.txt6
-rw-r--r--Documentation/usb/usb-serial.txt4
-rw-r--r--Documentation/video4linux/API.html2
-rw-r--r--Documentation/video4linux/CARDLIST.cx238856
-rw-r--r--Documentation/video4linux/CARDLIST.em28xx1
-rw-r--r--Documentation/video4linux/CARDLIST.saa71343
-rw-r--r--Documentation/video4linux/CQcam.txt4
-rw-r--r--Documentation/video4linux/README.cpia2
-rw-r--r--Documentation/video4linux/README.ivtv2
-rw-r--r--Documentation/video4linux/Zoran6
-rw-r--r--Documentation/video4linux/bttv/Cards6
-rw-r--r--Documentation/video4linux/bttv/MAKEDEV2
-rw-r--r--Documentation/video4linux/bttv/Specs4
-rw-r--r--Documentation/video4linux/cx88/hauppauge-wintv-cx88-ir.txt2
-rw-r--r--Documentation/video4linux/gspca.txt8
-rw-r--r--Documentation/video4linux/hauppauge-wintv-cx88-ir.txt2
-rw-r--r--Documentation/video4linux/ibmcam.txt5
-rw-r--r--Documentation/video4linux/se401.txt2
-rw-r--r--Documentation/video4linux/w9966.txt2
-rw-r--r--Documentation/vm/page-types.c2
-rw-r--r--Documentation/w1/masters/ds24824
-rw-r--r--Documentation/w1/masters/mxc-w13
-rw-r--r--Documentation/w1/masters/omap-hdq2
-rw-r--r--Documentation/x86/zero-page.txt1
-rw-r--r--Documentation/zh_CN/HOWTO8
-rw-r--r--Documentation/zh_CN/SubmittingDrivers2
-rw-r--r--Documentation/zh_CN/SubmittingPatches6
-rw-r--r--Documentation/zh_CN/sparse.txt2
-rw-r--r--MAINTAINERS102
-rw-r--r--Makefile43
-rw-r--r--arch/Kconfig7
-rw-r--r--arch/alpha/Kconfig4
-rw-r--r--arch/alpha/include/asm/local64.h1
-rw-r--r--arch/arm/Kconfig4
-rw-r--r--arch/arm/include/asm/kgdb.h6
-rw-r--r--arch/arm/include/asm/local64.h1
-rw-r--r--arch/arm/kernel/kgdb.c124
-rw-r--r--arch/arm/kernel/perf_event.c18
-rw-r--r--arch/arm/mach-davinci/Kconfig12
-rw-r--r--arch/arm/mach-davinci/Makefile3
-rw-r--r--arch/arm/mach-davinci/board-da830-evm.c34
-rw-r--r--arch/arm/mach-davinci/board-da850-evm.c54
-rw-r--r--arch/arm/mach-davinci/board-dm646x-evm.c39
-rw-r--r--arch/arm/mach-davinci/board-tnetv107x-evm.c174
-rw-r--r--arch/arm/mach-davinci/da830.c5
-rw-r--r--arch/arm/mach-davinci/da850.c25
-rw-r--r--arch/arm/mach-davinci/devices-da8xx.c50
-rw-r--r--arch/arm/mach-davinci/devices-tnetv107x.c320
-rw-r--r--arch/arm/mach-davinci/dm355.c22
-rw-r--r--arch/arm/mach-davinci/dm365.c28
-rw-r--r--arch/arm/mach-davinci/dm644x.c22
-rw-r--r--arch/arm/mach-davinci/dm646x.c30
-rw-r--r--arch/arm/mach-davinci/dma.c62
-rw-r--r--arch/arm/mach-davinci/gpio-tnetv107x.c205
-rw-r--r--arch/arm/mach-davinci/include/mach/asp.h51
-rw-r--r--arch/arm/mach-davinci/include/mach/da8xx.h3
-rw-r--r--arch/arm/mach-davinci/include/mach/debug-macro.S50
-rw-r--r--arch/arm/mach-davinci/include/mach/dm646x.h1
-rw-r--r--arch/arm/mach-davinci/include/mach/edma.h11
-rw-r--r--arch/arm/mach-davinci/include/mach/gpio.h22
-rw-r--r--arch/arm/mach-davinci/include/mach/serial.h21
-rw-r--r--arch/arm/mach-davinci/include/mach/tnetv107x.h55
-rw-r--r--arch/arm/mach-davinci/include/mach/uncompress.h87
-rw-r--r--arch/arm/mach-davinci/tnetv107x.c753
-rw-r--r--arch/arm/mach-ep93xx/clock.c67
-rw-r--r--arch/arm/mach-ep93xx/core.c67
-rw-r--r--arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h10
-rw-r--r--arch/arm/mach-ep93xx/include/mach/platform.h3
-rw-r--r--arch/arm/mach-ep93xx/snappercl15.c1
-rw-r--r--arch/arm/mach-imx/dma-v1.c3
-rw-r--r--arch/arm/mach-kirkwood/common.c38
-rw-r--r--arch/arm/mach-kirkwood/common.h2
-rw-r--r--arch/arm/mach-kirkwood/include/mach/kirkwood.h3
-rw-r--r--arch/arm/mach-kirkwood/openrd-setup.c13
-rw-r--r--arch/arm/mach-msm/acpuclock-arm11.c4
-rw-r--r--arch/arm/mach-omap2/dpll3xxx.c2
-rw-r--r--arch/arm/mach-omap2/mcbsp.c10
-rw-r--r--arch/arm/mach-omap2/sleep34xx.S2
-rw-r--r--arch/arm/mach-sa1100/collie.c2
-rw-r--r--arch/arm/mach-u300/core.c7
-rw-r--r--arch/arm/mach-u300/gpio.c2
-rw-r--r--arch/arm/plat-mxc/include/mach/ssi.h3
-rw-r--r--arch/arm/plat-omap/include/plat/mcbsp.h2
-rw-r--r--arch/arm/plat-omap/mcbsp.c51
-rw-r--r--arch/arm/plat-orion/include/plat/audio.h11
-rw-r--r--arch/arm/plat-s3c24xx/clock.c2
-rw-r--r--arch/arm/plat-samsung/clock.c2
-rw-r--r--arch/arm/plat-samsung/include/plat/keypad.h43
-rw-r--r--arch/arm/plat-spear/padmux.c2
-rw-r--r--arch/avr32/Kconfig3
-rw-r--r--arch/avr32/Makefile2
-rw-r--r--arch/avr32/include/asm/local64.h1
-rw-r--r--arch/blackfin/Kconfig3
-rw-r--r--arch/blackfin/Makefile4
-rw-r--r--arch/blackfin/include/asm/local64.h1
-rw-r--r--arch/cris/Kconfig3
-rw-r--r--arch/cris/arch-v32/mm/intmem.c13
-rw-r--r--arch/cris/include/asm/local64.h1
-rw-r--r--arch/frv/Kconfig4
-rw-r--r--arch/frv/Makefile22
-rw-r--r--arch/frv/include/asm/local64.h1
-rw-r--r--arch/frv/kernel/local64.h1
-rw-r--r--arch/h8300/Kconfig4
-rw-r--r--arch/h8300/include/asm/local64.h1
-rw-r--r--arch/h8300/kernel/timer/itu.c2
-rw-r--r--arch/h8300/kernel/timer/timer16.c2
-rw-r--r--arch/h8300/kernel/timer/timer8.c2
-rw-r--r--arch/ia64/Kconfig4
-rw-r--r--arch/ia64/Makefile6
-rw-r--r--arch/ia64/configs/bigsur_defconfig1428
-rw-r--r--arch/ia64/configs/generic_defconfig1788
-rw-r--r--arch/ia64/configs/gensparse_defconfig1493
-rw-r--r--arch/ia64/configs/sim_defconfig756
-rw-r--r--arch/ia64/configs/tiger_defconfig1356
-rw-r--r--arch/ia64/configs/xen_domu_defconfig1678
-rw-r--r--arch/ia64/configs/zx1_defconfig1681
-rw-r--r--arch/ia64/include/asm/kvm_host.h1
-rw-r--r--arch/ia64/include/asm/local64.h1
-rw-r--r--arch/ia64/include/asm/page.h2
-rw-r--r--arch/ia64/kernel/msi_ia64.c2
-rw-r--r--arch/ia64/kernel/perfmon.c22
-rw-r--r--arch/ia64/kernel/smpboot.c2
-rw-r--r--arch/ia64/kernel/time.c7
-rw-r--r--arch/ia64/kernel/vmlinux.lds.S362
-rw-r--r--arch/ia64/kvm/kvm-ia64.c56
-rw-r--r--arch/ia64/sn/kernel/msi_sn.c2
-rw-r--r--arch/ia64/sn/kernel/setup.c2
-rw-r--r--arch/m32r/Kconfig3
-rw-r--r--arch/m32r/Makefile4
-rw-r--r--arch/m32r/include/asm/local64.h1
-rw-r--r--arch/m68k/Kconfig3
-rw-r--r--arch/m68k/Makefile2
-rw-r--r--arch/m68k/include/asm/local64.h1
-rw-r--r--arch/m68knommu/Kconfig4
-rw-r--r--arch/microblaze/Kconfig51
-rw-r--r--arch/microblaze/Kconfig.debug1
-rw-r--r--arch/microblaze/Makefile2
-rw-r--r--arch/microblaze/boot/Makefile11
-rw-r--r--arch/microblaze/include/asm/cacheflush.h18
-rw-r--r--arch/microblaze/include/asm/dma-mapping.h6
-rw-r--r--arch/microblaze/include/asm/elf.h2
-rw-r--r--arch/microblaze/include/asm/exceptions.h21
-rw-r--r--arch/microblaze/include/asm/irq.h24
-rw-r--r--arch/microblaze/include/asm/kgdb.h28
-rw-r--r--arch/microblaze/include/asm/local64.h1
-rw-r--r--arch/microblaze/include/asm/of_device.h44
-rw-r--r--arch/microblaze/include/asm/of_platform.h54
-rw-r--r--arch/microblaze/include/asm/page.h19
-rw-r--r--arch/microblaze/include/asm/pci-bridge.h5
-rw-r--r--arch/microblaze/include/asm/prom.h115
-rw-r--r--arch/microblaze/include/asm/pvr.h2
-rw-r--r--arch/microblaze/include/asm/setup.h2
-rw-r--r--arch/microblaze/include/asm/system.h4
-rw-r--r--arch/microblaze/include/asm/topology.h10
-rw-r--r--arch/microblaze/include/asm/uaccess.h4
-rw-r--r--arch/microblaze/include/asm/unwind.h29
-rw-r--r--arch/microblaze/kernel/Makefile7
-rw-r--r--arch/microblaze/kernel/cpu/mb.c1
-rw-r--r--arch/microblaze/kernel/entry-nommu.S28
-rw-r--r--arch/microblaze/kernel/entry.S607
-rw-r--r--arch/microblaze/kernel/exceptions.c9
-rw-r--r--arch/microblaze/kernel/head.S4
-rw-r--r--arch/microblaze/kernel/hw_exception_handler.S4
-rw-r--r--arch/microblaze/kernel/irq.c16
-rw-r--r--arch/microblaze/kernel/kgdb.c147
-rw-r--r--arch/microblaze/kernel/misc.S2
-rw-r--r--arch/microblaze/kernel/of_device.c112
-rw-r--r--arch/microblaze/kernel/of_platform.c200
-rw-r--r--arch/microblaze/kernel/process.c7
-rw-r--r--arch/microblaze/kernel/prom_parse.c877
-rw-r--r--arch/microblaze/kernel/ptrace.c17
-rw-r--r--arch/microblaze/kernel/reset.c12
-rw-r--r--arch/microblaze/kernel/setup.c6
-rw-r--r--arch/microblaze/kernel/stacktrace.c44
-rw-r--r--arch/microblaze/kernel/timer.c24
-rw-r--r--arch/microblaze/kernel/traps.c91
-rw-r--r--arch/microblaze/kernel/unwind.c318
-rw-r--r--arch/microblaze/kernel/vmlinux.lds.S16
-rw-r--r--arch/microblaze/mm/fault.c16
-rw-r--r--arch/microblaze/mm/init.c7
-rw-r--r--arch/mips/Kbuild15
-rw-r--r--arch/mips/Kbuild.platforms32
-rw-r--r--arch/mips/Kconfig34
-rw-r--r--arch/mips/Makefile528
-rw-r--r--arch/mips/alchemy/Kconfig28
-rw-r--r--arch/mips/alchemy/Platform114
-rw-r--r--arch/mips/alchemy/common/Makefile2
-rw-r--r--arch/mips/alchemy/common/clocks.c4
-rw-r--r--arch/mips/alchemy/common/platform.c17
-rw-r--r--arch/mips/alchemy/devboards/Makefile2
-rw-r--r--arch/mips/alchemy/devboards/db1200/platform.c8
-rw-r--r--arch/mips/alchemy/devboards/db1x00/board_setup.c1
-rw-r--r--arch/mips/alchemy/devboards/pb1000/board_setup.c6
-rw-r--r--arch/mips/alchemy/devboards/pb1200/Makefile2
-rw-r--r--arch/mips/alchemy/gpr/Makefile8
-rw-r--r--arch/mips/alchemy/gpr/board_setup.c93
-rw-r--r--arch/mips/alchemy/gpr/init.c63
-rw-r--r--arch/mips/alchemy/gpr/platform.c183
-rw-r--r--arch/mips/alchemy/mtx-1/Makefile5
-rw-r--r--arch/mips/alchemy/mtx-1/board_setup.c18
-rw-r--r--arch/mips/alchemy/xxs1500/Makefile4
-rw-r--r--arch/mips/alchemy/xxs1500/board_setup.c6
-rw-r--r--arch/mips/ar7/Makefile1
-rw-r--r--arch/mips/ar7/Platform6
-rw-r--r--arch/mips/ar7/platform.c42
-rw-r--r--arch/mips/bcm47xx/Platform7
-rw-r--r--arch/mips/bcm47xx/nvram.c4
-rw-r--r--arch/mips/bcm47xx/prom.c22
-rw-r--r--arch/mips/bcm63xx/Makefile2
-rw-r--r--arch/mips/bcm63xx/Platform7
-rw-r--r--arch/mips/boot/.gitignore1
-rw-r--r--arch/mips/boot/Makefile49
-rw-r--r--arch/mips/boot/compressed/Makefile81
-rw-r--r--arch/mips/boot/compressed/calc_vmlinuz_load_addr.c57
-rw-r--r--arch/mips/boot/compressed/decompress.c38
-rw-r--r--arch/mips/boot/compressed/ld.script51
-rw-r--r--arch/mips/cavium-octeon/Makefile3
-rw-r--r--arch/mips/cavium-octeon/Platform11
-rw-r--r--arch/mips/cavium-octeon/cpu.c6
-rw-r--r--arch/mips/cavium-octeon/csrc-octeon.c63
-rw-r--r--arch/mips/cavium-octeon/dma-octeon.c17
-rw-r--r--arch/mips/cavium-octeon/octeon-irq.c553
-rw-r--r--arch/mips/cavium-octeon/octeon_boot.h16
-rw-r--r--arch/mips/cavium-octeon/serial.c4
-rw-r--r--arch/mips/cavium-octeon/setup.c48
-rw-r--r--arch/mips/cavium-octeon/smp.c170
-rw-r--r--arch/mips/cobalt/Makefile2
-rw-r--r--arch/mips/cobalt/Platform6
-rw-r--r--arch/mips/configs/db1000_defconfig3
-rw-r--r--arch/mips/configs/db1100_defconfig3
-rw-r--r--arch/mips/configs/db1200_defconfig3
-rw-r--r--arch/mips/configs/db1500_defconfig3
-rw-r--r--arch/mips/configs/db1550_defconfig3
-rw-r--r--arch/mips/configs/gpr_defconfig2060
-rw-r--r--arch/mips/configs/mtx1_defconfig3
-rw-r--r--arch/mips/configs/pb1100_defconfig3
-rw-r--r--arch/mips/configs/pb1200_defconfig3
-rw-r--r--arch/mips/configs/pb1500_defconfig3
-rw-r--r--arch/mips/configs/pb1550_defconfig3
-rw-r--r--arch/mips/configs/powertv_defconfig275
-rw-r--r--arch/mips/dec/Makefile2
-rw-r--r--arch/mips/dec/Platform8
-rw-r--r--arch/mips/dec/promcon.c3
-rw-r--r--arch/mips/emma/Makefile6
-rw-r--r--arch/mips/emma/Platform4
-rw-r--r--arch/mips/emma/markeins/irq.c8
-rw-r--r--arch/mips/emma/markeins/setup.c1
-rw-r--r--arch/mips/include/asm/arch_hweight.h38
-rw-r--r--arch/mips/include/asm/bitops.h5
-rw-r--r--arch/mips/include/asm/bootinfo.h6
-rw-r--r--arch/mips/include/asm/break.h2
-rw-r--r--arch/mips/include/asm/cacheops.h2
-rw-r--r--arch/mips/include/asm/cop2.h12
-rw-r--r--arch/mips/include/asm/cpu-features.h3
-rw-r--r--arch/mips/include/asm/cpu.h9
-rw-r--r--arch/mips/include/asm/elf.h5
-rw-r--r--arch/mips/include/asm/emma/emma2rh.h84
-rw-r--r--arch/mips/include/asm/emma/markeins.h37
-rw-r--r--arch/mips/include/asm/hazards.h4
-rw-r--r--arch/mips/include/asm/inst.h15
-rw-r--r--arch/mips/include/asm/kdebug.h3
-rw-r--r--arch/mips/include/asm/kgdb.h19
-rw-r--r--arch/mips/include/asm/kprobes.h92
-rw-r--r--arch/mips/include/asm/local64.h1
-rw-r--r--arch/mips/include/asm/mach-au1x00/au1xxx_eth.h1
-rw-r--r--arch/mips/include/asm/mach-bcm47xx/nvram.h3
-rw-r--r--arch/mips/include/asm/mach-cavium-octeon/cpu-feature-overrides.h15
-rw-r--r--arch/mips/include/asm/mach-cavium-octeon/irq.h66
-rw-r--r--arch/mips/include/asm/mach-jz4740/base.h26
-rw-r--r--arch/mips/include/asm/mach-jz4740/clock.h28
-rw-r--r--arch/mips/include/asm/mach-jz4740/cpu-feature-overrides.h51
-rw-r--r--arch/mips/include/asm/mach-jz4740/dma.h90
-rw-r--r--arch/mips/include/asm/mach-jz4740/gpio.h398
-rw-r--r--arch/mips/include/asm/mach-jz4740/irq.h57
-rw-r--r--arch/mips/include/asm/mach-jz4740/jz4740_fb.h67
-rw-r--r--arch/mips/include/asm/mach-jz4740/jz4740_mmc.h15
-rw-r--r--arch/mips/include/asm/mach-jz4740/jz4740_nand.h34
-rw-r--r--arch/mips/include/asm/mach-jz4740/platform.h36
-rw-r--r--arch/mips/include/asm/mach-jz4740/timer.h22
-rw-r--r--arch/mips/include/asm/mach-jz4740/war.h25
-rw-r--r--arch/mips/include/asm/mach-loongson/loongson.h9
-rw-r--r--arch/mips/include/asm/mach-pb1x00/pb1550.h8
-rw-r--r--arch/mips/include/asm/mach-powertv/asic.h21
-rw-r--r--arch/mips/include/asm/mach-powertv/asic_reg_map.h2
-rw-r--r--arch/mips/include/asm/mach-powertv/asic_regs.h5
-rw-r--r--arch/mips/include/asm/mach-powertv/dma-coherence.h8
-rw-r--r--arch/mips/include/asm/mach-powertv/ioremap.h165
-rw-r--r--arch/mips/include/asm/mach-tx49xx/kmalloc.h4
-rw-r--r--arch/mips/include/asm/mipsregs.h1
-rw-r--r--arch/mips/include/asm/octeon/octeon.h3
-rw-r--r--arch/mips/include/asm/octeon/pci-octeon.h13
-rw-r--r--arch/mips/include/asm/pci.h5
-rw-r--r--arch/mips/include/asm/pmc-sierra/msp71xx/msp_prom.h4
-rw-r--r--arch/mips/include/asm/processor.h13
-rw-r--r--arch/mips/include/asm/ptrace.h1
-rw-r--r--arch/mips/include/asm/sn/agent.h1
-rw-r--r--arch/mips/include/asm/uasm.h51
-rw-r--r--arch/mips/jazz/Makefile2
-rw-r--r--arch/mips/jazz/Platform6
-rw-r--r--arch/mips/jz4740/Kconfig12
-rw-r--r--arch/mips/jz4740/Makefile20
-rw-r--r--arch/mips/jz4740/Platform3
-rw-r--r--arch/mips/jz4740/board-qi_lb60.c471
-rw-r--r--arch/mips/jz4740/clock-debugfs.c109
-rw-r--r--arch/mips/jz4740/clock.c924
-rw-r--r--arch/mips/jz4740/clock.h76
-rw-r--r--arch/mips/jz4740/dma.c289
-rw-r--r--arch/mips/jz4740/gpio.c604
-rw-r--r--arch/mips/jz4740/irq.c167
-rw-r--r--arch/mips/jz4740/irq.h21
-rw-r--r--arch/mips/jz4740/platform.c291
-rw-r--r--arch/mips/jz4740/pm.c56
-rw-r--r--arch/mips/jz4740/prom.c68
-rw-r--r--arch/mips/jz4740/pwm.c177
-rw-r--r--arch/mips/jz4740/reset.c79
-rw-r--r--arch/mips/jz4740/reset.h6
-rw-r--r--arch/mips/jz4740/serial.c33
-rw-r--r--arch/mips/jz4740/serial.h20
-rw-r--r--arch/mips/jz4740/setup.c29
-rw-r--r--arch/mips/jz4740/time.c144
-rw-r--r--arch/mips/jz4740/timer.c48
-rw-r--r--arch/mips/jz4740/timer.h136
-rw-r--r--arch/mips/kernel/Makefile3
-rw-r--r--arch/mips/kernel/asm-offsets.c1
-rw-r--r--arch/mips/kernel/cevt-r4k.c5
-rw-r--r--arch/mips/kernel/cpu-bugs64.c2
-rw-r--r--arch/mips/kernel/cpu-probe.c23
-rw-r--r--arch/mips/kernel/kgdb.c211
-rw-r--r--arch/mips/kernel/kprobes.c557
-rw-r--r--arch/mips/kernel/mcount.S6
-rw-r--r--arch/mips/kernel/scall64-n32.S8
-rw-r--r--arch/mips/kernel/smp.c4
-rw-r--r--arch/mips/kernel/smtc.c3
-rw-r--r--arch/mips/kernel/syscall.c49
-rw-r--r--arch/mips/kernel/traps.c50
-rw-r--r--arch/mips/lasat/Makefile2
-rw-r--r--arch/mips/lasat/Platform7
-rw-r--r--arch/mips/loongson/Platform32
-rw-r--r--arch/mips/loongson/common/cs5536/Makefile2
-rw-r--r--arch/mips/loongson/common/irq.c14
-rw-r--r--arch/mips/loongson/fuloong-2e/Makefile2
-rw-r--r--arch/mips/loongson/fuloong-2e/irq.c13
-rw-r--r--arch/mips/loongson/lemote-2f/irq.c16
-rw-r--r--arch/mips/math-emu/Makefile1
-rw-r--r--arch/mips/math-emu/dp_modf.c2
-rw-r--r--arch/mips/math-emu/dp_tint.c3
-rw-r--r--arch/mips/math-emu/dp_tlong.c3
-rw-r--r--arch/mips/math-emu/sp_modf.c2
-rw-r--r--arch/mips/math-emu/sp_tint.c3
-rw-r--r--arch/mips/math-emu/sp_tlong.c3
-rw-r--r--arch/mips/mipssim/Makefile2
-rw-r--r--arch/mips/mipssim/Platform6
-rw-r--r--arch/mips/mm/Makefile2
-rw-r--r--arch/mips/mm/fault.c16
-rw-r--r--arch/mips/mm/sc-rm7k.c163
-rw-r--r--arch/mips/mm/tlbex.c5
-rw-r--r--arch/mips/mm/uasm.c162
-rw-r--r--arch/mips/mti-malta/Makefile2
-rw-r--r--arch/mips/mti-malta/Platform7
-rw-r--r--arch/mips/nxp/pnx833x/stb22x/Makefile3
-rw-r--r--arch/mips/nxp/pnx8550/jbs/Makefile4
-rw-r--r--arch/mips/nxp/pnx8550/stb810/Makefile4
-rw-r--r--arch/mips/pci/msi-octeon.c277
-rw-r--r--arch/mips/pci/ops-titan-ht.c4
-rw-r--r--arch/mips/pci/pcie-octeon.c37
-rw-r--r--arch/mips/pmc-sierra/Platform14
-rw-r--r--arch/mips/pmc-sierra/msp71xx/msp_hwbutton.c11
-rw-r--r--arch/mips/pmc-sierra/yosemite/ht-irq.c13
-rw-r--r--arch/mips/pmc-sierra/yosemite/irq.c4
-rw-r--r--arch/mips/pnx833x/Makefile3
-rw-r--r--arch/mips/pnx833x/Platform5
-rw-r--r--arch/mips/pnx833x/common/Makefile (renamed from arch/mips/nxp/pnx833x/common/Makefile)2
-rw-r--r--arch/mips/pnx833x/common/interrupts.c (renamed from arch/mips/nxp/pnx833x/common/interrupts.c)0
-rw-r--r--arch/mips/pnx833x/common/platform.c (renamed from arch/mips/nxp/pnx833x/common/platform.c)0
-rw-r--r--arch/mips/pnx833x/common/prom.c (renamed from arch/mips/nxp/pnx833x/common/prom.c)0
-rw-r--r--arch/mips/pnx833x/common/reset.c (renamed from arch/mips/nxp/pnx833x/common/reset.c)0
-rw-r--r--arch/mips/pnx833x/common/setup.c (renamed from arch/mips/nxp/pnx833x/common/setup.c)0
-rw-r--r--arch/mips/pnx833x/stb22x/Makefile1
-rw-r--r--arch/mips/pnx833x/stb22x/board.c (renamed from arch/mips/nxp/pnx833x/stb22x/board.c)0
-rw-r--r--arch/mips/pnx8550/Makefile3
-rw-r--r--arch/mips/pnx8550/Platform7
-rw-r--r--arch/mips/pnx8550/common/Makefile (renamed from arch/mips/nxp/pnx8550/common/Makefile)2
-rw-r--r--arch/mips/pnx8550/common/int.c (renamed from arch/mips/nxp/pnx8550/common/int.c)0
-rw-r--r--arch/mips/pnx8550/common/pci.c134
-rw-r--r--arch/mips/pnx8550/common/platform.c (renamed from arch/mips/nxp/pnx8550/common/platform.c)0
-rw-r--r--arch/mips/pnx8550/common/proc.c (renamed from arch/mips/nxp/pnx8550/common/proc.c)0
-rw-r--r--arch/mips/pnx8550/common/prom.c (renamed from arch/mips/nxp/pnx8550/common/prom.c)0
-rw-r--r--arch/mips/pnx8550/common/reset.c (renamed from arch/mips/nxp/pnx8550/common/reset.c)0
-rw-r--r--arch/mips/pnx8550/common/setup.c145
-rw-r--r--arch/mips/pnx8550/common/time.c (renamed from arch/mips/nxp/pnx8550/common/time.c)0
-rw-r--r--arch/mips/pnx8550/jbs/Makefile4
-rw-r--r--arch/mips/pnx8550/jbs/board_setup.c (renamed from arch/mips/nxp/pnx8550/jbs/board_setup.c)0
-rw-r--r--arch/mips/pnx8550/jbs/init.c (renamed from arch/mips/nxp/pnx8550/jbs/init.c)0
-rw-r--r--arch/mips/pnx8550/jbs/irqmap.c (renamed from arch/mips/nxp/pnx8550/jbs/irqmap.c)0
-rw-r--r--arch/mips/pnx8550/stb810/Makefile4
-rw-r--r--arch/mips/pnx8550/stb810/board_setup.c (renamed from arch/mips/nxp/pnx8550/stb810/board_setup.c)0
-rw-r--r--arch/mips/pnx8550/stb810/irqmap.c (renamed from arch/mips/nxp/pnx8550/stb810/irqmap.c)0
-rw-r--r--arch/mips/pnx8550/stb810/prom_init.c (renamed from arch/mips/nxp/pnx8550/stb810/prom_init.c)0
-rw-r--r--arch/mips/powertv/Makefile7
-rw-r--r--arch/mips/powertv/Platform7
-rw-r--r--arch/mips/powertv/asic/Makefile6
-rw-r--r--arch/mips/powertv/asic/asic-calliope.c2
-rw-r--r--arch/mips/powertv/asic/asic-cronus.c4
-rw-r--r--arch/mips/powertv/asic/asic-gaia.c96
-rw-r--r--arch/mips/powertv/asic/asic-zeus.c2
-rw-r--r--arch/mips/powertv/asic/asic_devices.c276
-rw-r--r--arch/mips/powertv/asic/prealloc-gaia.c589
-rw-r--r--arch/mips/powertv/init.c4
-rw-r--r--arch/mips/powertv/ioremap.c136
-rw-r--r--arch/mips/powertv/memory.c341
-rw-r--r--arch/mips/powertv/powertv-usb.c403
-rw-r--r--arch/mips/powertv/powertv_setup.c6
-rw-r--r--arch/mips/rb532/Makefile2
-rw-r--r--arch/mips/rb532/Platform7
-rw-r--r--arch/mips/sgi-ip22/Makefile2
-rw-r--r--arch/mips/sgi-ip22/Platform34
-rw-r--r--arch/mips/sgi-ip27/Makefile2
-rw-r--r--arch/mips/sgi-ip27/Platform19
-rw-r--r--arch/mips/sgi-ip27/ip27-klconfig.c8
-rw-r--r--arch/mips/sgi-ip32/Makefile2
-rw-r--r--arch/mips/sgi-ip32/Platform11
-rw-r--r--arch/mips/sibyte/Makefile27
-rw-r--r--arch/mips/sibyte/Platform43
-rw-r--r--arch/mips/sibyte/bcm1480/Makefile2
-rw-r--r--arch/mips/sibyte/common/Makefile2
-rw-r--r--arch/mips/sibyte/sb1250/Makefile2
-rw-r--r--arch/mips/sni/Makefile2
-rw-r--r--arch/mips/sni/Platform11
-rw-r--r--arch/mips/txx9/Makefile17
-rw-r--r--arch/mips/txx9/Platform10
-rw-r--r--arch/mips/txx9/generic/Makefile2
-rw-r--r--arch/mips/txx9/jmr3927/Makefile2
-rw-r--r--arch/mips/txx9/rbtx4927/Makefile2
-rw-r--r--arch/mips/txx9/rbtx4938/Makefile2
-rw-r--r--arch/mips/txx9/rbtx4939/Makefile2
-rw-r--r--arch/mips/vr41xx/Platform32
-rw-r--r--arch/mips/vr41xx/common/Makefile2
-rw-r--r--arch/mips/wrppmc/Makefile (renamed from arch/mips/gt64120/wrppmc/Makefile)4
-rw-r--r--arch/mips/wrppmc/Platform7
-rw-r--r--arch/mips/wrppmc/irq.c (renamed from arch/mips/gt64120/wrppmc/irq.c)0
-rw-r--r--arch/mips/wrppmc/pci.c (renamed from arch/mips/gt64120/wrppmc/pci.c)0
-rw-r--r--arch/mips/wrppmc/reset.c (renamed from arch/mips/gt64120/wrppmc/reset.c)0
-rw-r--r--arch/mips/wrppmc/serial.c (renamed from arch/mips/gt64120/wrppmc/serial.c)0
-rw-r--r--arch/mips/wrppmc/setup.c (renamed from arch/mips/gt64120/wrppmc/setup.c)0
-rw-r--r--arch/mips/wrppmc/time.c (renamed from arch/mips/gt64120/wrppmc/time.c)0
-rw-r--r--arch/mn10300/Kconfig3
-rw-r--r--arch/mn10300/include/asm/local64.h1
-rw-r--r--arch/parisc/Kconfig4
-rw-r--r--arch/parisc/include/asm/local64.h1
-rw-r--r--arch/parisc/kernel/firmware.c12
-rw-r--r--arch/parisc/kernel/ftrace.c4
-rw-r--r--arch/powerpc/Kconfig36
-rw-r--r--arch/powerpc/Makefile2
-rw-r--r--arch/powerpc/boot/dts/canyonlands.dts4
-rw-r--r--arch/powerpc/boot/dts/glacier.dts4
-rw-r--r--arch/powerpc/boot/dts/mpc8308rdb.dts303
-rw-r--r--arch/powerpc/boot/dts/mpc8540ads.dts4
-rw-r--r--arch/powerpc/boot/dts/mpc8541cds.dts4
-rw-r--r--arch/powerpc/boot/dts/mpc8544ds.dts4
-rw-r--r--arch/powerpc/boot/dts/mpc8548cds.dts4
-rw-r--r--arch/powerpc/boot/dts/mpc8555cds.dts4
-rw-r--r--arch/powerpc/boot/dts/mpc8560ads.dts4
-rw-r--r--arch/powerpc/boot/dts/mpc8568mds.dts4
-rw-r--r--arch/powerpc/boot/dts/p1021mds.dts1
-rw-r--r--arch/powerpc/boot/dts/p1022ds.dts633
-rw-r--r--arch/powerpc/boot/dts/pdm360ng.dts410
-rw-r--r--arch/powerpc/boot/dts/stxssa8555.dts380
-rw-r--r--arch/powerpc/boot/dts/tqm8540.dts9
-rw-r--r--arch/powerpc/boot/dts/tqm8541.dts9
-rw-r--r--arch/powerpc/boot/dts/tqm8548-bigflash.dts9
-rw-r--r--arch/powerpc/boot/dts/tqm8548.dts9
-rw-r--r--arch/powerpc/boot/dts/tqm8555.dts9
-rw-r--r--arch/powerpc/boot/dts/tqm8560.dts9
-rw-r--r--arch/powerpc/boot/dts/tqm8xx.dts172
-rw-r--r--arch/powerpc/configs/mpc85xx_defconfig34
-rw-r--r--arch/powerpc/configs/mpc85xx_smp_defconfig34
-rw-r--r--arch/powerpc/configs/tqm8xx_defconfig934
-rw-r--r--arch/powerpc/include/asm/abs_addr.h2
-rw-r--r--arch/powerpc/include/asm/asm-compat.h2
-rw-r--r--arch/powerpc/include/asm/cputable.h7
-rw-r--r--arch/powerpc/include/asm/dbell.h8
-rw-r--r--arch/powerpc/include/asm/hvcall.h1
-rw-r--r--arch/powerpc/include/asm/hw_breakpoint.h74
-rw-r--r--arch/powerpc/include/asm/irq.h28
-rw-r--r--arch/powerpc/include/asm/kvm_book3s.h10
-rw-r--r--arch/powerpc/include/asm/kvm_fpu.h27
-rw-r--r--arch/powerpc/include/asm/kvm_host.h18
-rw-r--r--arch/powerpc/include/asm/local64.h1
-rw-r--r--arch/powerpc/include/asm/machdep.h5
-rw-r--r--arch/powerpc/include/asm/macio.h2
-rw-r--r--arch/powerpc/include/asm/mmu-book3e.h4
-rw-r--r--arch/powerpc/include/asm/mpc5121.h32
-rw-r--r--arch/powerpc/include/asm/of_device.h27
-rw-r--r--arch/powerpc/include/asm/of_platform.h29
-rw-r--r--arch/powerpc/include/asm/paca.h2
-rw-r--r--arch/powerpc/include/asm/pci-bridge.h5
-rw-r--r--arch/powerpc/include/asm/percpu.h3
-rw-r--r--arch/powerpc/include/asm/perf_event.h12
-rw-r--r--arch/powerpc/include/asm/ppc-opcode.h7
-rw-r--r--arch/powerpc/include/asm/processor.h8
-rw-r--r--arch/powerpc/include/asm/prom.h133
-rw-r--r--arch/powerpc/include/asm/reg.h2
-rw-r--r--arch/powerpc/include/asm/reg_booke.h5
-rw-r--r--arch/powerpc/include/asm/rtas.h13
-rw-r--r--arch/powerpc/include/asm/smu.h4
-rw-r--r--arch/powerpc/include/asm/system.h3
-rw-r--r--arch/powerpc/include/asm/time.h7
-rw-r--r--arch/powerpc/include/asm/topology.h10
-rw-r--r--arch/powerpc/include/asm/vdso_datapage.h2
-rw-r--r--arch/powerpc/kernel/Makefile6
-rw-r--r--arch/powerpc/kernel/asm-offsets.c2
-rw-r--r--arch/powerpc/kernel/cputable.c118
-rw-r--r--arch/powerpc/kernel/crash_dump.c4
-rw-r--r--arch/powerpc/kernel/dbell.c78
-rw-r--r--arch/powerpc/kernel/dma-swiotlb.c8
-rw-r--r--arch/powerpc/kernel/exceptions-64e.S50
-rw-r--r--arch/powerpc/kernel/exceptions-64s.S1
-rw-r--r--arch/powerpc/kernel/hw_breakpoint.c364
-rw-r--r--arch/powerpc/kernel/ibmebus.c8
-rw-r--r--arch/powerpc/kernel/idle_book3e.S86
-rw-r--r--arch/powerpc/kernel/irq.c30
-rw-r--r--arch/powerpc/kernel/kgdb.c2
-rw-r--r--arch/powerpc/kernel/legacy_serial.c1
-rw-r--r--arch/powerpc/kernel/machine_kexec.c22
-rw-r--r--arch/powerpc/kernel/machine_kexec_64.c78
-rw-r--r--arch/powerpc/kernel/misc.S26
-rw-r--r--arch/powerpc/kernel/of_device.c133
-rw-r--r--arch/powerpc/kernel/of_platform.c203
-rw-r--r--arch/powerpc/kernel/paca.c10
-rw-r--r--arch/powerpc/kernel/pci-common.c1
-rw-r--r--arch/powerpc/kernel/perf_event.c41
-rw-r--r--arch/powerpc/kernel/perf_event_fsl_emb.c29
-rw-r--r--arch/powerpc/kernel/ppc_ksyms.c4
-rw-r--r--arch/powerpc/kernel/process.c47
-rw-r--r--arch/powerpc/kernel/prom_init.c44
-rw-r--r--arch/powerpc/kernel/prom_parse.c924
-rw-r--r--arch/powerpc/kernel/ptrace.c64
-rw-r--r--arch/powerpc/kernel/rtas.c105
-rw-r--r--arch/powerpc/kernel/setup-common.c20
-rw-r--r--arch/powerpc/kernel/setup_64.c19
-rw-r--r--arch/powerpc/kernel/signal.c3
-rw-r--r--arch/powerpc/kernel/smp.c10
-rw-r--r--arch/powerpc/kernel/suspend.c2
-rw-r--r--arch/powerpc/kernel/time.c201
-rw-r--r--arch/powerpc/kernel/traps.c29
-rw-r--r--arch/powerpc/kernel/vdso32/gettimeofday.S184
-rw-r--r--arch/powerpc/kernel/vdso64/gettimeofday.S88
-rw-r--r--arch/powerpc/kvm/44x_tlb.c3
-rw-r--r--arch/powerpc/kvm/Makefile2
-rw-r--r--arch/powerpc/kvm/book3s.c79
-rw-r--r--arch/powerpc/kvm/book3s_32_mmu.c8
-rw-r--r--arch/powerpc/kvm/book3s_32_mmu_host.c134
-rw-r--r--arch/powerpc/kvm/book3s_64_mmu_host.c129
-rw-r--r--arch/powerpc/kvm/book3s_mmu_hpte.c277
-rw-r--r--arch/powerpc/kvm/book3s_paired_singles.c94
-rw-r--r--arch/powerpc/kvm/booke.c12
-rw-r--r--arch/powerpc/kvm/fpu.S18
-rw-r--r--arch/powerpc/kvm/powerpc.c14
-rw-r--r--arch/powerpc/kvm/timing.c2
-rw-r--r--arch/powerpc/lib/Makefile5
-rw-r--r--arch/powerpc/lib/ldstfp.S375
-rw-r--r--arch/powerpc/lib/sstep.c1514
-rw-r--r--arch/powerpc/mm/fsl_booke_mmu.c7
-rw-r--r--arch/powerpc/mm/numa.c122
-rw-r--r--arch/powerpc/mm/pgtable.c1
-rw-r--r--arch/powerpc/mm/tlb_hash32.c15
-rw-r--r--arch/powerpc/mm/tlb_nohash.c129
-rw-r--r--arch/powerpc/oprofile/Makefile2
-rw-r--r--arch/powerpc/oprofile/common.c2
-rw-r--r--arch/powerpc/platforms/40x/Kconfig16
-rw-r--r--arch/powerpc/platforms/512x/Kconfig20
-rw-r--r--arch/powerpc/platforms/512x/Makefile1
-rw-r--r--arch/powerpc/platforms/512x/clock.c20
-rw-r--r--arch/powerpc/platforms/512x/mpc5121_ads.c2
-rw-r--r--arch/powerpc/platforms/512x/mpc5121_generic.c2
-rw-r--r--arch/powerpc/platforms/512x/mpc512x.h2
-rw-r--r--arch/powerpc/platforms/512x/mpc512x_shared.c284
-rw-r--r--arch/powerpc/platforms/512x/pdm360ng.c129
-rw-r--r--arch/powerpc/platforms/52xx/lite5200.c1
-rw-r--r--arch/powerpc/platforms/52xx/lite5200_pm.c3
-rw-r--r--arch/powerpc/platforms/52xx/mpc52xx_gpio.c36
-rw-r--r--arch/powerpc/platforms/52xx/mpc52xx_gpt.c33
-rw-r--r--arch/powerpc/platforms/52xx/mpc52xx_lpbfifo.c6
-rw-r--r--arch/powerpc/platforms/52xx/mpc52xx_pm.c3
-rw-r--r--arch/powerpc/platforms/82xx/ep8248e.c4
-rw-r--r--arch/powerpc/platforms/83xx/Kconfig8
-rw-r--r--arch/powerpc/platforms/83xx/Makefile1
-rw-r--r--arch/powerpc/platforms/83xx/mcu_mpc8349emitx.c40
-rw-r--r--arch/powerpc/platforms/83xx/mpc830x_rdb.c94
-rw-r--r--arch/powerpc/platforms/83xx/suspend.c6
-rw-r--r--arch/powerpc/platforms/85xx/Kconfig8
-rw-r--r--arch/powerpc/platforms/85xx/Makefile1
-rw-r--r--arch/powerpc/platforms/85xx/mpc85xx_mds.c279
-rw-r--r--arch/powerpc/platforms/85xx/p1022_ds.c148
-rw-r--r--arch/powerpc/platforms/85xx/smp.c67
-rw-r--r--arch/powerpc/platforms/85xx/tqm85xx.c21
-rw-r--r--arch/powerpc/platforms/86xx/gef_gpio.c24
-rw-r--r--arch/powerpc/platforms/8xx/Kconfig6
-rw-r--r--arch/powerpc/platforms/8xx/Makefile1
-rw-r--r--arch/powerpc/platforms/8xx/tqm8xx_setup.c156
-rw-r--r--arch/powerpc/platforms/amigaone/setup.c3
-rw-r--r--arch/powerpc/platforms/cell/axon_msi.c4
-rw-r--r--arch/powerpc/platforms/cell/beat_iommu.c2
-rw-r--r--arch/powerpc/platforms/cell/iommu.c2
-rw-r--r--arch/powerpc/platforms/cell/qpace_setup.c14
-rw-r--r--arch/powerpc/platforms/cell/setup.c14
-rw-r--r--arch/powerpc/platforms/iseries/mf.c1
-rw-r--r--arch/powerpc/platforms/iseries/vio.c3
-rw-r--r--arch/powerpc/platforms/pasemi/gpio_mdio.c4
-rw-r--r--arch/powerpc/platforms/powermac/cpufreq_32.c8
-rw-r--r--arch/powerpc/platforms/powermac/feature.c8
-rw-r--r--arch/powerpc/platforms/powermac/low_i2c.c5
-rw-r--r--arch/powerpc/platforms/powermac/pic.c72
-rw-r--r--arch/powerpc/platforms/ps3/htab.c2
-rw-r--r--arch/powerpc/platforms/pseries/Makefile4
-rw-r--r--arch/powerpc/platforms/pseries/dlpar.c1
-rw-r--r--arch/powerpc/platforms/pseries/eeh_cache.c3
-rw-r--r--arch/powerpc/platforms/pseries/event_sources.c23
-rw-r--r--arch/powerpc/platforms/pseries/hotplug-cpu.c7
-rw-r--r--arch/powerpc/platforms/pseries/ras.c5
-rw-r--r--arch/powerpc/platforms/pseries/reconfig.c4
-rw-r--r--arch/powerpc/platforms/pseries/suspend.c214
-rw-r--r--arch/powerpc/platforms/pseries/xics.c2
-rw-r--r--arch/powerpc/sysdev/axonram.c12
-rw-r--r--arch/powerpc/sysdev/bestcomm/bestcomm.c7
-rw-r--r--arch/powerpc/sysdev/bestcomm/sram.c1
-rw-r--r--arch/powerpc/sysdev/cpm1.c10
-rw-r--r--arch/powerpc/sysdev/cpm_common.c5
-rw-r--r--arch/powerpc/sysdev/fsl_gtm.c1
-rw-r--r--arch/powerpc/sysdev/fsl_msi.c4
-rw-r--r--arch/powerpc/sysdev/fsl_pci.c1
-rw-r--r--arch/powerpc/sysdev/fsl_pmc.c3
-rw-r--r--arch/powerpc/sysdev/fsl_rio.c4
-rw-r--r--arch/powerpc/sysdev/fsl_soc.h1
-rw-r--r--arch/powerpc/sysdev/mpc8xxx_gpio.c5
-rw-r--r--arch/powerpc/sysdev/mpic.c18
-rw-r--r--arch/powerpc/sysdev/mpic.h1
-rw-r--r--arch/powerpc/sysdev/mv64x60_dev.c7
-rw-r--r--arch/powerpc/sysdev/mv64x60_pci.c1
-rw-r--r--arch/powerpc/sysdev/pmi.c6
-rw-r--r--arch/powerpc/sysdev/ppc4xx_gpio.c5
-rw-r--r--arch/powerpc/sysdev/qe_lib/gpio.c31
-rw-r--r--arch/powerpc/sysdev/qe_lib/qe.c5
-rw-r--r--arch/powerpc/sysdev/simple_gpio.c5
-rw-r--r--arch/powerpc/xmon/xmon.c152
-rw-r--r--arch/s390/Kconfig3
-rw-r--r--arch/s390/Makefile3
-rw-r--r--arch/s390/appldata/appldata_net_sum.c3
-rw-r--r--arch/s390/crypto/Makefile2
-rw-r--r--arch/s390/crypto/crypto_des.h2
-rw-r--r--arch/s390/crypto/des_s390.c238
-rw-r--r--arch/s390/include/asm/kvm_host.h5
-rw-r--r--arch/s390/include/asm/local64.h1
-rw-r--r--arch/s390/include/asm/qdio.h6
-rw-r--r--arch/s390/kernel/time.c8
-rw-r--r--arch/s390/kvm/intercept.c2
-rw-r--r--arch/s390/kvm/kvm-s390.c64
-rw-r--r--arch/s390/kvm/kvm-s390.h2
-rw-r--r--arch/score/Kconfig3
-rw-r--r--arch/score/Makefile3
-rw-r--r--arch/score/include/asm/local64.h1
-rw-r--r--arch/sh/Kconfig3
-rw-r--r--arch/sh/boards/mach-ap325rxa/setup.c2
-rw-r--r--arch/sh/include/asm/local64.h1
-rw-r--r--arch/sh/kernel/clkdev.c2
-rw-r--r--arch/sh/kernel/perf_event.c6
-rw-r--r--arch/sparc/Kconfig7
-rw-r--r--arch/sparc/boot/btfixupprep.c4
-rw-r--r--arch/sparc/include/asm/device.h11
-rw-r--r--arch/sparc/include/asm/floppy_64.h10
-rw-r--r--arch/sparc/include/asm/local64.h1
-rw-r--r--arch/sparc/include/asm/of_device.h38
-rw-r--r--arch/sparc/include/asm/of_platform.h18
-rw-r--r--arch/sparc/include/asm/parport.h12
-rw-r--r--arch/sparc/include/asm/perf_event.h8
-rw-r--r--arch/sparc/include/asm/prom.h10
-rw-r--r--arch/sparc/kernel/apc.c6
-rw-r--r--arch/sparc/kernel/auxio_64.c5
-rw-r--r--arch/sparc/kernel/central.c8
-rw-r--r--arch/sparc/kernel/chmc.c16
-rw-r--r--arch/sparc/kernel/helpers.S6
-rw-r--r--arch/sparc/kernel/ioport.c2
-rw-r--r--arch/sparc/kernel/of_device_32.c63
-rw-r--r--arch/sparc/kernel/of_device_64.c61
-rw-r--r--arch/sparc/kernel/of_device_common.c35
-rw-r--r--arch/sparc/kernel/pci.c6
-rw-r--r--arch/sparc/kernel/pci_fire.c6
-rw-r--r--arch/sparc/kernel/pci_impl.h2
-rw-r--r--arch/sparc/kernel/pci_psycho.c16
-rw-r--r--arch/sparc/kernel/pci_sabre.c16
-rw-r--r--arch/sparc/kernel/pci_schizo.c32
-rw-r--r--arch/sparc/kernel/pci_sun4v.c6
-rw-r--r--arch/sparc/kernel/perf_event.c25
-rw-r--r--arch/sparc/kernel/pmc.c4
-rw-r--r--arch/sparc/kernel/power.c6
-rw-r--r--arch/sparc/kernel/prom.h8
-rw-r--r--arch/sparc/kernel/prom_64.c6
-rw-r--r--arch/sparc/kernel/prom_common.c2
-rw-r--r--arch/sparc/kernel/prom_irqtrans.c2
-rw-r--r--arch/sparc/kernel/psycho_common.c2
-rw-r--r--arch/sparc/kernel/psycho_common.h2
-rw-r--r--arch/sparc/kernel/sbus.c16
-rw-r--r--arch/sparc/kernel/time_32.c4
-rw-r--r--arch/sparc/kernel/time_64.c12
-rw-r--r--arch/sparc/mm/io-unit.c4
-rw-r--r--arch/sparc/mm/iommu.c6
-rw-r--r--arch/um/Kconfig.common4
-rw-r--r--arch/um/drivers/hostaudio_kern.c6
-rw-r--r--arch/um/drivers/net_kern.c10
-rw-r--r--arch/um/include/asm/pgtable-3level.h4
-rw-r--r--arch/um/kernel/time.c16
-rw-r--r--arch/x86/Kconfig15
-rw-r--r--arch/x86/boot/Makefile8
-rw-r--r--arch/x86/boot/boot.h28
-rw-r--r--arch/x86/boot/cmdline.c6
-rw-r--r--arch/x86/boot/compressed/Makefile4
-rw-r--r--arch/x86/boot/compressed/cmdline.c21
-rw-r--r--arch/x86/boot/compressed/early_serial_console.c5
-rw-r--r--arch/x86/boot/compressed/head_32.S13
-rw-r--r--arch/x86/boot/compressed/head_64.S13
-rw-r--r--arch/x86/boot/compressed/misc.c56
-rw-r--r--arch/x86/boot/compressed/misc.h39
-rw-r--r--arch/x86/boot/compressed/string.c2
-rw-r--r--arch/x86/boot/compressed/vmlinux.lds.S6
-rw-r--r--arch/x86/boot/ctype.h21
-rw-r--r--arch/x86/boot/early_serial_console.c139
-rw-r--r--arch/x86/boot/main.c9
-rw-r--r--arch/x86/boot/printf.c4
-rw-r--r--arch/x86/boot/string.c63
-rw-r--r--arch/x86/boot/tty.c37
-rw-r--r--arch/x86/configs/i386_defconfig1
-rw-r--r--arch/x86/configs/x86_64_defconfig1
-rw-r--r--arch/x86/include/asm/acpi.h2
-rw-r--r--arch/x86/include/asm/alternative.h7
-rw-r--r--arch/x86/include/asm/apb_timer.h1
-rw-r--r--arch/x86/include/asm/bootparam.h11
-rw-r--r--arch/x86/include/asm/cmpxchg_32.h198
-rw-r--r--arch/x86/include/asm/cmpxchg_64.h83
-rw-r--r--arch/x86/include/asm/cpufeature.h43
-rw-r--r--arch/x86/include/asm/hw_breakpoint.h2
-rw-r--r--arch/x86/include/asm/hypervisor.h1
-rw-r--r--arch/x86/include/asm/i387.h26
-rw-r--r--arch/x86/include/asm/intel_scu_ipc.h20
-rw-r--r--arch/x86/include/asm/irq_vectors.h3
-rw-r--r--arch/x86/include/asm/kgdb.h20
-rw-r--r--arch/x86/include/asm/kvm.h22
-rw-r--r--arch/x86/include/asm/kvm_emulate.h30
-rw-r--r--arch/x86/include/asm/kvm_host.h70
-rw-r--r--arch/x86/include/asm/local64.h1
-rw-r--r--arch/x86/include/asm/mce.h4
-rw-r--r--arch/x86/include/asm/mrst.h26
-rw-r--r--arch/x86/include/asm/msr-index.h26
-rw-r--r--arch/x86/include/asm/msr.h4
-rw-r--r--arch/x86/include/asm/nmi.h2
-rw-r--r--arch/x86/include/asm/olpc_ofw.h31
-rw-r--r--arch/x86/include/asm/pci_x86.h1
-rw-r--r--arch/x86/include/asm/perf_event.h18
-rw-r--r--arch/x86/include/asm/perf_event_p4.h99
-rw-r--r--arch/x86/include/asm/processor.h21
-rw-r--r--arch/x86/include/asm/required-features.h2
-rw-r--r--arch/x86/include/asm/rwsem.h21
-rw-r--r--arch/x86/include/asm/setup.h2
-rw-r--r--arch/x86/include/asm/stacktrace.h49
-rw-r--r--arch/x86/include/asm/system.h7
-rw-r--r--arch/x86/include/asm/vmx.h5
-rw-r--r--arch/x86/include/asm/xen/hypercall.h6
-rw-r--r--arch/x86/include/asm/xsave.h40
-rw-r--r--arch/x86/kernel/Makefile1
-rw-r--r--arch/x86/kernel/acpi/realmode/wakeup.S2
-rw-r--r--arch/x86/kernel/acpi/sleep.c2
-rw-r--r--arch/x86/kernel/alternative.c1
-rw-r--r--arch/x86/kernel/amd_iommu.c8
-rw-r--r--arch/x86/kernel/apb_timer.c37
-rw-r--r--arch/x86/kernel/aperture_64.c4
-rw-r--r--arch/x86/kernel/apic/Makefile7
-rw-r--r--arch/x86/kernel/apic/apic.c2
-rw-r--r--arch/x86/kernel/apic/es7000_32.c1
-rw-r--r--arch/x86/kernel/apic/hw_nmi.c107
-rw-r--r--arch/x86/kernel/apic/io_apic.c2
-rw-r--r--arch/x86/kernel/apic/nmi.c7
-rw-r--r--arch/x86/kernel/apm_32.c2
-rw-r--r--arch/x86/kernel/cpu/Makefile4
-rw-r--r--arch/x86/kernel/cpu/amd.c77
-rw-r--r--arch/x86/kernel/cpu/common.c28
-rw-r--r--arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c7
-rw-r--r--arch/x86/kernel/cpu/cpufreq/gx-suspmod.c11
-rw-r--r--arch/x86/kernel/cpu/cpufreq/longhaul.c6
-rw-r--r--arch/x86/kernel/cpu/cpufreq/longhaul.h26
-rw-r--r--arch/x86/kernel/cpu/cpufreq/longrun.c6
-rw-r--r--arch/x86/kernel/cpu/cpufreq/p4-clockmod.c7
-rw-r--r--arch/x86/kernel/cpu/cpufreq/powernow-k7.c8
-rw-r--r--arch/x86/kernel/cpu/cpufreq/powernow-k8.c8
-rw-r--r--arch/x86/kernel/cpu/hypervisor.c3
-rw-r--r--arch/x86/kernel/cpu/intel_cacheinfo.c108
-rw-r--r--arch/x86/kernel/cpu/mcheck/mce.c35
-rw-r--r--arch/x86/kernel/cpu/mcheck/mce_intel.c9
-rw-r--r--arch/x86/kernel/cpu/mcheck/therm_throt.c206
-rw-r--r--arch/x86/kernel/cpu/mshyperv.c1
-rw-r--r--arch/x86/kernel/cpu/mtrr/cleanup.c6
-rw-r--r--arch/x86/kernel/cpu/mtrr/generic.c3
-rw-r--r--arch/x86/kernel/cpu/mtrr/main.c56
-rw-r--r--arch/x86/kernel/cpu/perf_event.c62
-rw-r--r--arch/x86/kernel/cpu/perf_event_p4.c156
-rw-r--r--arch/x86/kernel/cpu/scattered.c63
-rw-r--r--arch/x86/kernel/cpu/topology.c (renamed from arch/x86/kernel/cpu/addon_cpuid_features.c)58
-rw-r--r--arch/x86/kernel/cpu/vmware.c9
-rw-r--r--arch/x86/kernel/dumpstack.c1
-rw-r--r--arch/x86/kernel/dumpstack.h56
-rw-r--r--arch/x86/kernel/dumpstack_32.c2
-rw-r--r--arch/x86/kernel/dumpstack_64.c1
-rw-r--r--arch/x86/kernel/entry_32.S16
-rw-r--r--arch/x86/kernel/entry_64.S9
-rw-r--r--arch/x86/kernel/head32.c2
-rw-r--r--arch/x86/kernel/head_32.S6
-rw-r--r--arch/x86/kernel/head_64.S5
-rw-r--r--arch/x86/kernel/hpet.c13
-rw-r--r--arch/x86/kernel/hw_breakpoint.c51
-rw-r--r--arch/x86/kernel/i387.c42
-rw-r--r--arch/x86/kernel/kgdb.c189
-rw-r--r--arch/x86/kernel/kprobes.c33
-rw-r--r--arch/x86/kernel/mrst.c105
-rw-r--r--arch/x86/kernel/olpc.c20
-rw-r--r--arch/x86/kernel/olpc_ofw.c106
-rw-r--r--arch/x86/kernel/process.c54
-rw-r--r--arch/x86/kernel/process_32.c4
-rw-r--r--arch/x86/kernel/process_64.c5
-rw-r--r--arch/x86/kernel/setup.c6
-rw-r--r--arch/x86/kernel/smpboot.c9
-rw-r--r--arch/x86/kernel/stacktrace.c31
-rw-r--r--arch/x86/kernel/traps.c7
-rw-r--r--arch/x86/kernel/tsc.c5
-rw-r--r--arch/x86/kernel/verify_cpu_64.S3
-rw-r--r--arch/x86/kernel/vsyscall_64.c17
-rw-r--r--arch/x86/kernel/xsave.c195
-rw-r--r--arch/x86/kvm/emulate.c749
-rw-r--r--arch/x86/kvm/i8254.c146
-rw-r--r--arch/x86/kvm/i8254.h4
-rw-r--r--arch/x86/kvm/i8259.c48
-rw-r--r--arch/x86/kvm/irq.c2
-rw-r--r--arch/x86/kvm/irq.h4
-rw-r--r--arch/x86/kvm/kvm_cache_regs.h8
-rw-r--r--arch/x86/kvm/lapic.c17
-rw-r--r--arch/x86/kvm/mmu.c807
-rw-r--r--arch/x86/kvm/mmutrace.h2
-rw-r--r--arch/x86/kvm/paging_tmpl.h252
-rw-r--r--arch/x86/kvm/svm.c147
-rw-r--r--arch/x86/kvm/timer.c16
-rw-r--r--arch/x86/kvm/vmx.c261
-rw-r--r--arch/x86/kvm/x86.c1176
-rw-r--r--arch/x86/kvm/x86.h7
-rw-r--r--arch/x86/lib/Makefile1
-rw-r--r--arch/x86/lib/clear_page_64.S2
-rw-r--r--arch/x86/lib/cmpxchg.c (renamed from arch/x86/kernel/cpu/cmpxchg.c)18
-rw-r--r--arch/x86/lib/copy_page_64.S2
-rw-r--r--arch/x86/lib/copy_user_64.S2
-rw-r--r--arch/x86/lib/memcpy_64.S2
-rw-r--r--arch/x86/lib/memset_64.S2
-rw-r--r--arch/x86/mm/dump_pagetables.c32
-rw-r--r--arch/x86/mm/init_64.c2
-rw-r--r--arch/x86/mm/ioremap.c14
-rw-r--r--arch/x86/mm/kmmio.c16
-rw-r--r--arch/x86/mm/pat.c2
-rw-r--r--arch/x86/mm/pf_in.c30
-rw-r--r--arch/x86/mm/testmmiotrace.c22
-rw-r--r--arch/x86/mm/tlb.c4
-rw-r--r--arch/x86/oprofile/nmi_int.c16
-rw-r--r--arch/x86/pci/acpi.c9
-rw-r--r--arch/x86/pci/common.c20
-rw-r--r--arch/x86/pci/irq.c6
-rw-r--r--arch/x86/pci/legacy.c2
-rw-r--r--arch/x86/power/cpu.c2
-rw-r--r--arch/x86/power/hibernate_64.c2
-rw-r--r--arch/x86/vdso/Makefile3
-rwxr-xr-xarch/x86/vdso/checkundef.sh10
-rw-r--r--arch/x86/vdso/vdso32-setup.c2
-rw-r--r--arch/x86/vdso/vma.c3
-rw-r--r--arch/x86/xen/Kconfig5
-rw-r--r--arch/x86/xen/Makefile2
-rw-r--r--arch/x86/xen/enlighten.c197
-rw-r--r--arch/x86/xen/mmu.c35
-rw-r--r--arch/x86/xen/mmu.h1
-rw-r--r--arch/x86/xen/platform-pci-unplug.c137
-rw-r--r--arch/x86/xen/setup.c72
-rw-r--r--arch/x86/xen/smp.c2
-rw-r--r--arch/x86/xen/suspend.c12
-rw-r--r--arch/x86/xen/time.c96
-rw-r--r--arch/x86/xen/xen-ops.h13
-rw-r--r--arch/xtensa/Kconfig3
-rw-r--r--arch/xtensa/Makefile2
-rw-r--r--arch/xtensa/configs/iss_defconfig731
-rw-r--r--arch/xtensa/include/asm/cacheflush.h1
-rw-r--r--arch/xtensa/include/asm/coprocessor.h1
-rw-r--r--arch/xtensa/include/asm/elf.h1
-rw-r--r--arch/xtensa/include/asm/local64.h1
-rw-r--r--arch/xtensa/include/asm/pgalloc.h1
-rw-r--r--arch/xtensa/include/asm/processor.h1
-rw-r--r--arch/xtensa/include/asm/ptrace.h2
-rw-r--r--arch/xtensa/kernel/Makefile4
-rw-r--r--arch/xtensa/kernel/asm-offsets.c1
-rw-r--r--arch/xtensa/kernel/entry.S1
-rw-r--r--arch/xtensa/kernel/head.S4
-rw-r--r--arch/xtensa/platforms/iss/network.c22
-rw-r--r--crypto/Kconfig15
-rw-r--r--crypto/Makefile4
-rw-r--r--crypto/algboss.c4
-rw-r--r--crypto/authenc.c2
-rw-r--r--crypto/ctr.c2
-rw-r--r--crypto/pcrypt.c241
-rw-r--r--crypto/testmgr.c14
-rw-r--r--crypto/twofish_generic.c (renamed from crypto/twofish.c)1
-rw-r--r--crypto/xts.c2
-rw-r--r--drivers/Makefile4
-rw-r--r--drivers/acpi/Kconfig18
-rw-r--r--drivers/acpi/Makefile1
-rw-r--r--drivers/acpi/acpi_pad.c2
-rw-r--r--drivers/acpi/acpica/acevents.h4
-rw-r--r--drivers/acpi/acpica/acglobal.h7
-rw-r--r--drivers/acpi/acpica/achware.h5
-rw-r--r--drivers/acpi/acpica/aclocal.h6
-rw-r--r--drivers/acpi/acpica/acnamesp.h7
-rw-r--r--drivers/acpi/acpica/acobject.h16
-rw-r--r--drivers/acpi/acpica/acpredef.h13
-rw-r--r--drivers/acpi/acpica/acstruct.h32
-rw-r--r--drivers/acpi/acpica/dsinit.c14
-rw-r--r--drivers/acpi/acpica/dsmethod.c20
-rw-r--r--drivers/acpi/acpica/dsmthdat.c16
-rw-r--r--drivers/acpi/acpica/dsobject.c16
-rw-r--r--drivers/acpi/acpica/dsopcode.c6
-rw-r--r--drivers/acpi/acpica/dsutils.c4
-rw-r--r--drivers/acpi/acpica/evevent.c5
-rw-r--r--drivers/acpi/acpica/evgpe.c69
-rw-r--r--drivers/acpi/acpica/evgpeblk.c70
-rw-r--r--drivers/acpi/acpica/evgpeinit.c236
-rw-r--r--drivers/acpi/acpica/evrgnini.c10
-rw-r--r--drivers/acpi/acpica/evxfevnt.c249
-rw-r--r--drivers/acpi/acpica/exconfig.c2
-rw-r--r--drivers/acpi/acpica/exdump.c6
-rw-r--r--drivers/acpi/acpica/exfldio.c4
-rw-r--r--drivers/acpi/acpica/exprep.c23
-rw-r--r--drivers/acpi/acpica/exregion.c6
-rw-r--r--drivers/acpi/acpica/hwgpe.c35
-rw-r--r--drivers/acpi/acpica/hwsleep.c2
-rw-r--r--drivers/acpi/acpica/nsaccess.c9
-rw-r--r--drivers/acpi/acpica/nsalloc.c94
-rw-r--r--drivers/acpi/acpica/nsdump.c2
-rw-r--r--drivers/acpi/acpica/nsinit.c16
-rw-r--r--drivers/acpi/acpica/nsnames.c4
-rw-r--r--drivers/acpi/acpica/nsparse.c4
-rw-r--r--drivers/acpi/acpica/nsrepair.c2
-rw-r--r--drivers/acpi/acpica/nsrepair2.c7
-rw-r--r--drivers/acpi/acpica/nssearch.c15
-rw-r--r--drivers/acpi/acpica/nsutils.c113
-rw-r--r--drivers/acpi/acpica/nswalk.c15
-rw-r--r--drivers/acpi/acpica/nsxfobj.c2
-rw-r--r--drivers/acpi/acpica/utglobal.c2
-rw-r--r--drivers/acpi/acpica/utxface.c8
-rw-r--r--drivers/acpi/button.c6
-rw-r--r--drivers/acpi/ec.c146
-rw-r--r--drivers/acpi/ec_sys.c160
-rw-r--r--drivers/acpi/internal.h24
-rw-r--r--drivers/acpi/osl.c60
-rw-r--r--drivers/acpi/pci_root.c9
-rw-r--r--drivers/acpi/processor_idle.c4
-rw-r--r--drivers/acpi/scan.c7
-rw-r--r--drivers/acpi/sleep.c15
-rw-r--r--drivers/acpi/system.c6
-rw-r--r--drivers/acpi/wakeup.c18
-rw-r--r--drivers/ata/Kconfig18
-rw-r--r--drivers/ata/Makefile2
-rw-r--r--drivers/ata/ahci.c2
-rw-r--r--drivers/ata/ahci_platform.c26
-rw-r--r--drivers/ata/ata_generic.c4
-rw-r--r--drivers/ata/ata_piix.c8
-rw-r--r--drivers/ata/libata-core.c181
-rw-r--r--drivers/ata/libata-eh.c5
-rw-r--r--drivers/ata/libata-scsi.c10
-rw-r--r--drivers/ata/libata-sff.c9
-rw-r--r--drivers/ata/libata.h1
-rw-r--r--drivers/ata/pata_pcmcia.c38
-rw-r--r--drivers/ata/pata_samsung_cf.c683
-rw-r--r--drivers/ata/pata_scc.c3
-rw-r--r--drivers/ata/sata_dwc_460ex.c1756
-rw-r--r--drivers/ata/sata_fsl.c20
-rw-r--r--drivers/ata/sata_mv.c47
-rw-r--r--drivers/ata/sata_nv.c32
-rw-r--r--drivers/atm/Kconfig2
-rw-r--r--drivers/atm/adummy.c39
-rw-r--r--drivers/atm/ambassador.c6
-rw-r--r--drivers/atm/eni.c6
-rw-r--r--drivers/atm/firestream.c6
-rw-r--r--drivers/atm/fore200e.c8
-rw-r--r--drivers/atm/he.c310
-rw-r--r--drivers/atm/he.h65
-rw-r--r--drivers/atm/idt77105.c11
-rw-r--r--drivers/atm/idt77252.c5
-rw-r--r--drivers/atm/nicstar.c5196
-rw-r--r--drivers/atm/nicstar.h602
-rw-r--r--drivers/atm/nicstarmac.c364
-rw-r--r--drivers/atm/solos-pci.c6
-rw-r--r--drivers/atm/suni.c5
-rw-r--r--drivers/atm/zatm.c6
-rw-r--r--drivers/base/bus.c2
-rw-r--r--drivers/base/core.c66
-rw-r--r--drivers/base/dd.c4
-rw-r--r--drivers/base/dma-coherent.c2
-rw-r--r--drivers/base/firmware_class.c262
-rw-r--r--drivers/base/platform.c123
-rw-r--r--drivers/base/power/Makefile2
-rw-r--r--drivers/base/power/main.c1
-rw-r--r--drivers/base/power/runtime.c54
-rw-r--r--drivers/base/power/sysfs.c98
-rw-r--r--drivers/base/power/wakeup.c247
-rw-r--r--drivers/block/cciss.c2
-rw-r--r--drivers/block/drbd/drbd_receiver.c2
-rw-r--r--drivers/block/nbd.c2
-rw-r--r--drivers/block/virtio_blk.c64
-rw-r--r--drivers/block/xen-blkfront.c30
-rw-r--r--drivers/bluetooth/Kconfig12
-rw-r--r--drivers/bluetooth/Makefile1
-rw-r--r--drivers/bluetooth/bcm203x.c3
-rw-r--r--drivers/bluetooth/bluecard_cs.c32
-rw-r--r--drivers/bluetooth/bpa10x.c2
-rw-r--r--drivers/bluetooth/bt3c_cs.c27
-rw-r--r--drivers/bluetooth/btmrvl_debugfs.c2
-rw-r--r--drivers/bluetooth/btmrvl_drv.h5
-rw-r--r--drivers/bluetooth/btmrvl_main.c5
-rw-r--r--drivers/bluetooth/btmrvl_sdio.c111
-rw-r--r--drivers/bluetooth/btuart_cs.c31
-rw-r--r--drivers/bluetooth/btusb.c13
-rw-r--r--drivers/bluetooth/dtl1_cs.c37
-rw-r--r--drivers/bluetooth/hci_ath.c235
-rw-r--r--drivers/bluetooth/hci_bcsp.c4
-rw-r--r--drivers/bluetooth/hci_h4.c107
-rw-r--r--drivers/bluetooth/hci_ldisc.c20
-rw-r--r--drivers/bluetooth/hci_ll.c6
-rw-r--r--drivers/bluetooth/hci_uart.h15
-rw-r--r--drivers/char/agp/efficeon-agp.c22
-rw-r--r--drivers/char/agp/intel-agp.c26
-rw-r--r--drivers/char/agp/intel-agp.h6
-rw-r--r--drivers/char/agp/intel-gtt.c83
-rw-r--r--drivers/char/bsr.c1
-rw-r--r--drivers/char/hvc_console.c12
-rw-r--r--drivers/char/hvsi.c4
-rw-r--r--drivers/char/hw_random/n2-drv.c6
-rw-r--r--drivers/char/keyboard.c6
-rw-r--r--drivers/char/mem.c2
-rw-r--r--drivers/char/pcmcia/cm4000_cs.c30
-rw-r--r--drivers/char/pcmcia/cm4040_cs.c37
-rw-r--r--drivers/char/pcmcia/ipwireless/main.c47
-rw-r--r--drivers/char/pcmcia/ipwireless/main.h1
-rw-r--r--drivers/char/pcmcia/ipwireless/tty.h1
-rw-r--r--drivers/char/pcmcia/synclink_cs.c29
-rw-r--r--drivers/char/random.c2
-rw-r--r--drivers/char/synclink_gt.c2
-rw-r--r--drivers/char/tty_io.c4
-rw-r--r--drivers/char/vt.c78
-rw-r--r--drivers/clocksource/acpi_pm.c9
-rw-r--r--drivers/cpufreq/cpufreq.c18
-rw-r--r--drivers/cpufreq/cpufreq_ondemand.c33
-rw-r--r--drivers/cpuidle/cpuidle.c2
-rw-r--r--drivers/crypto/amcc/crypto4xx_reg_def.h2
-rw-r--r--drivers/crypto/geode-aes.c2
-rw-r--r--drivers/crypto/hifn_795x.c4
-rw-r--r--drivers/crypto/mv_cesa.c10
-rw-r--r--drivers/crypto/n2_core.c425
-rw-r--r--drivers/crypto/omap-sham.c1
-rw-r--r--drivers/crypto/talitos.c77
-rw-r--r--drivers/dma/at_hdmac.c2
-rw-r--r--drivers/dma/fsldma.c2
-rw-r--r--drivers/edac/Kconfig8
-rw-r--r--drivers/edac/amd64_edac.c213
-rw-r--r--drivers/edac/amd64_edac.h48
-rw-r--r--drivers/edac/e752x_edac.c4
-rw-r--r--drivers/edac/edac_core.h17
-rw-r--r--drivers/edac/edac_mc_sysfs.c86
-rw-r--r--drivers/edac/edac_mce_amd.c16
-rw-r--r--drivers/edac/i5100_edac.c7
-rw-r--r--drivers/firewire/Kconfig24
-rw-r--r--drivers/firewire/Makefile1
-rw-r--r--drivers/firewire/core-card.c218
-rw-r--r--drivers/firewire/core-cdev.c409
-rw-r--r--drivers/firewire/core-device.c11
-rw-r--r--drivers/firewire/core-iso.c34
-rw-r--r--drivers/firewire/core-topology.c22
-rw-r--r--drivers/firewire/core-transaction.c306
-rw-r--r--drivers/firewire/core.h24
-rw-r--r--drivers/firewire/net.c4
-rw-r--r--drivers/firewire/nosy-user.h25
-rw-r--r--drivers/firewire/nosy.c721
-rw-r--r--drivers/firewire/nosy.h237
-rw-r--r--drivers/firewire/ohci.c701
-rw-r--r--drivers/firewire/ohci.h1
-rw-r--r--drivers/firewire/sbp2.c13
-rw-r--r--drivers/firmware/Kconfig9
-rw-r--r--drivers/firmware/Makefile1
-rw-r--r--drivers/firmware/dcdbas.c5
-rw-r--r--drivers/firmware/dmi-id.c4
-rw-r--r--drivers/firmware/dmi_scan.c25
-rw-r--r--drivers/firmware/iscsi_boot_sysfs.c481
-rw-r--r--drivers/firmware/iscsi_ibft.c726
-rw-r--r--drivers/firmware/iscsi_ibft_find.c56
-rw-r--r--drivers/gpio/gpiolib.c55
-rw-r--r--drivers/gpio/xilinx_gpio.c15
-rw-r--r--drivers/gpu/drm/Kconfig11
-rw-r--r--drivers/gpu/drm/Makefile7
-rw-r--r--drivers/gpu/drm/drm_bufs.c15
-rw-r--r--drivers/gpu/drm/drm_crtc.c30
-rw-r--r--drivers/gpu/drm/drm_crtc_helper.c100
-rw-r--r--drivers/gpu/drm/drm_drv.c43
-rw-r--r--drivers/gpu/drm/drm_edid.c11
-rw-r--r--drivers/gpu/drm/drm_encoder_slave.c7
-rw-r--r--drivers/gpu/drm/drm_fb_helper.c76
-rw-r--r--drivers/gpu/drm/drm_fops.c23
-rw-r--r--drivers/gpu/drm/drm_gem.c11
-rw-r--r--drivers/gpu/drm/drm_global.c (renamed from drivers/gpu/drm/ttm/ttm_global.c)30
-rw-r--r--drivers/gpu/drm/drm_info.c23
-rw-r--r--drivers/gpu/drm/drm_ioctl.c140
-rw-r--r--drivers/gpu/drm/drm_irq.c26
-rw-r--r--drivers/gpu/drm/drm_mm.c359
-rw-r--r--drivers/gpu/drm/drm_pci.c143
-rw-r--r--drivers/gpu/drm/drm_platform.c122
-rw-r--r--drivers/gpu/drm/drm_stub.c92
-rw-r--r--drivers/gpu/drm/drm_sysfs.c3
-rw-r--r--drivers/gpu/drm/drm_trace.h66
-rw-r--r--drivers/gpu/drm/drm_trace_points.c4
-rw-r--r--drivers/gpu/drm/drm_vm.c14
-rw-r--r--drivers/gpu/drm/i2c/Makefile3
-rw-r--r--drivers/gpu/drm/i2c/ch7006_drv.c22
-rw-r--r--drivers/gpu/drm/i2c/ch7006_priv.h2
-rw-r--r--drivers/gpu/drm/i2c/sil164_drv.c462
-rw-r--r--drivers/gpu/drm/i810/i810_dma.c125
-rw-r--r--drivers/gpu/drm/i810/i810_drv.c2
-rw-r--r--drivers/gpu/drm/i810/i810_drv.h65
-rw-r--r--drivers/gpu/drm/i830/i830_dma.c137
-rw-r--r--drivers/gpu/drm/i830/i830_drv.c2
-rw-r--r--drivers/gpu/drm/i830/i830_drv.h49
-rw-r--r--drivers/gpu/drm/i830/i830_irq.c10
-rw-r--r--drivers/gpu/drm/i915/i915_dma.c24
-rw-r--r--drivers/gpu/drm/i915/i915_drv.c66
-rw-r--r--drivers/gpu/drm/i915/i915_drv.h29
-rw-r--r--drivers/gpu/drm/i915/i915_gem.c172
-rw-r--r--drivers/gpu/drm/i915/i915_gem_tiling.c2
-rw-r--r--drivers/gpu/drm/i915/i915_irq.c58
-rw-r--r--drivers/gpu/drm/i915/i915_reg.h56
-rw-r--r--drivers/gpu/drm/i915/i915_suspend.c9
-rw-r--r--drivers/gpu/drm/i915/i915_trace.h36
-rw-r--r--drivers/gpu/drm/i915/intel_display.c688
-rw-r--r--drivers/gpu/drm/i915/intel_dp.c143
-rw-r--r--drivers/gpu/drm/i915/intel_drv.h10
-rw-r--r--drivers/gpu/drm/i915/intel_fb.c2
-rw-r--r--drivers/gpu/drm/i915/intel_hdmi.c9
-rw-r--r--drivers/gpu/drm/i915/intel_lvds.c331
-rw-r--r--drivers/gpu/drm/i915/intel_overlay.c14
-rw-r--r--drivers/gpu/drm/i915/intel_sdvo.c12
-rw-r--r--drivers/gpu/drm/i915/intel_tv.c14
-rw-r--r--drivers/gpu/drm/mga/mga_dma.c103
-rw-r--r--drivers/gpu/drm/mga/mga_drv.c4
-rw-r--r--drivers/gpu/drm/mga/mga_drv.h187
-rw-r--r--drivers/gpu/drm/mga/mga_irq.c9
-rw-r--r--drivers/gpu/drm/mga/mga_state.c47
-rw-r--r--drivers/gpu/drm/mga/mga_warp.c4
-rw-r--r--drivers/gpu/drm/nouveau/Kconfig11
-rw-r--r--drivers/gpu/drm/nouveau/Makefile6
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_acpi.c38
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_bios.c636
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_bios.h4
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_bo.c11
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_calc.c4
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_channel.c8
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_connector.c404
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_connector.h7
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_dma.c8
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_dp.c41
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_drv.c41
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_drv.h137
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_encoder.h10
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_fbcon.c2
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_fence.c35
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_gem.c11
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_grctx.c160
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_i2c.c42
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_i2c.h3
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_mem.c332
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_notifier.c30
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_object.c105
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_reg.h91
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_sgdma.c46
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_state.c255
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_ttm.c20
-rw-r--r--drivers/gpu/drm/nouveau/nv04_crtc.c5
-rw-r--r--drivers/gpu/drm/nouveau/nv04_dac.c50
-rw-r--r--drivers/gpu/drm/nouveau/nv04_dfp.c12
-rw-r--r--drivers/gpu/drm/nouveau/nv04_display.c90
-rw-r--r--drivers/gpu/drm/nouveau/nv04_fifo.c20
-rw-r--r--drivers/gpu/drm/nouveau/nv04_graph.c5
-rw-r--r--drivers/gpu/drm/nouveau/nv04_instmem.c21
-rw-r--r--drivers/gpu/drm/nouveau/nv04_mc.c4
-rw-r--r--drivers/gpu/drm/nouveau/nv04_tv.c125
-rw-r--r--drivers/gpu/drm/nouveau/nv10_fifo.c10
-rw-r--r--drivers/gpu/drm/nouveau/nv10_gpio.c (renamed from drivers/gpu/drm/nouveau/nv17_gpio.c)4
-rw-r--r--drivers/gpu/drm/nouveau/nv17_tv.c65
-rw-r--r--drivers/gpu/drm/nouveau/nv20_graph.c100
-rw-r--r--drivers/gpu/drm/nouveau/nv30_fb.c87
-rw-r--r--drivers/gpu/drm/nouveau/nv40_fifo.c8
-rw-r--r--drivers/gpu/drm/nouveau/nv40_graph.c60
-rw-r--r--drivers/gpu/drm/nouveau/nv40_mc.c2
-rw-r--r--drivers/gpu/drm/nouveau/nv50_crtc.c42
-rw-r--r--drivers/gpu/drm/nouveau/nv50_dac.c43
-rw-r--r--drivers/gpu/drm/nouveau/nv50_display.c419
-rw-r--r--drivers/gpu/drm/nouveau/nv50_display.h6
-rw-r--r--drivers/gpu/drm/nouveau/nv50_fifo.c126
-rw-r--r--drivers/gpu/drm/nouveau/nv50_gpio.c35
-rw-r--r--drivers/gpu/drm/nouveau/nv50_graph.c86
-rw-r--r--drivers/gpu/drm/nouveau/nv50_instmem.c68
-rw-r--r--drivers/gpu/drm/nouveau/nv50_sor.c105
-rw-r--r--drivers/gpu/drm/nouveau/nvreg.h22
-rw-r--r--drivers/gpu/drm/r128/r128_cce.c52
-rw-r--r--drivers/gpu/drm/r128/r128_drv.c2
-rw-r--r--drivers/gpu/drm/r128/r128_drv.h122
-rw-r--r--drivers/gpu/drm/r128/r128_irq.c4
-rw-r--r--drivers/gpu/drm/r128/r128_state.c121
-rw-r--r--drivers/gpu/drm/radeon/Makefile1
-rw-r--r--drivers/gpu/drm/radeon/atom.c9
-rw-r--r--drivers/gpu/drm/radeon/atom.h2
-rw-r--r--drivers/gpu/drm/radeon/atombios_crtc.c212
-rw-r--r--drivers/gpu/drm/radeon/atombios_dp.c18
-rw-r--r--drivers/gpu/drm/radeon/evergreen.c22
-rw-r--r--drivers/gpu/drm/radeon/evergreen_reg.h5
-rw-r--r--drivers/gpu/drm/radeon/evergreend.h5
-rw-r--r--drivers/gpu/drm/radeon/r100.c55
-rw-r--r--drivers/gpu/drm/radeon/r100d.h2
-rw-r--r--drivers/gpu/drm/radeon/r300.c46
-rw-r--r--drivers/gpu/drm/radeon/r300d.h2
-rw-r--r--drivers/gpu/drm/radeon/r420.c2
-rw-r--r--drivers/gpu/drm/radeon/r500_reg.h5
-rw-r--r--drivers/gpu/drm/radeon/r520.c2
-rw-r--r--drivers/gpu/drm/radeon/r600.c49
-rw-r--r--drivers/gpu/drm/radeon/r600_audio.c22
-rw-r--r--drivers/gpu/drm/radeon/r600_blit_shaders.c1115
-rw-r--r--drivers/gpu/drm/radeon/r600_cs.c232
-rw-r--r--drivers/gpu/drm/radeon/r600_hdmi.c6
-rw-r--r--drivers/gpu/drm/radeon/r600d.h12
-rw-r--r--drivers/gpu/drm/radeon/radeon.h53
-rw-r--r--drivers/gpu/drm/radeon/radeon_acpi.c67
-rw-r--r--drivers/gpu/drm/radeon/radeon_asic.h1
-rw-r--r--drivers/gpu/drm/radeon/radeon_atombios.c75
-rw-r--r--drivers/gpu/drm/radeon/radeon_bios.c2
-rw-r--r--drivers/gpu/drm/radeon/radeon_combios.c51
-rw-r--r--drivers/gpu/drm/radeon/radeon_connectors.c48
-rw-r--r--drivers/gpu/drm/radeon/radeon_cp.c8
-rw-r--r--drivers/gpu/drm/radeon/radeon_device.c45
-rw-r--r--drivers/gpu/drm/radeon/radeon_display.c77
-rw-r--r--drivers/gpu/drm/radeon/radeon_drv.c5
-rw-r--r--drivers/gpu/drm/radeon/radeon_encoders.c15
-rw-r--r--drivers/gpu/drm/radeon/radeon_kms.c37
-rw-r--r--drivers/gpu/drm/radeon/radeon_legacy_crtc.c18
-rw-r--r--drivers/gpu/drm/radeon/radeon_legacy_encoders.c30
-rw-r--r--drivers/gpu/drm/radeon/radeon_legacy_tv.c6
-rw-r--r--drivers/gpu/drm/radeon/radeon_mode.h18
-rw-r--r--drivers/gpu/drm/radeon/radeon_object.c27
-rw-r--r--drivers/gpu/drm/radeon/radeon_pm.c114
-rw-r--r--drivers/gpu/drm/radeon/radeon_ttm.c20
-rw-r--r--drivers/gpu/drm/radeon/reg_srcs/r30013
-rw-r--r--drivers/gpu/drm/radeon/reg_srcs/r42014
-rw-r--r--drivers/gpu/drm/radeon/reg_srcs/rs60013
-rw-r--r--drivers/gpu/drm/radeon/reg_srcs/rv51513
-rw-r--r--drivers/gpu/drm/radeon/rs400.c10
-rw-r--r--drivers/gpu/drm/radeon/rs600.c16
-rw-r--r--drivers/gpu/drm/radeon/rs690.c44
-rw-r--r--drivers/gpu/drm/radeon/rv515.c25
-rw-r--r--drivers/gpu/drm/radeon/rv770.c27
-rw-r--r--drivers/gpu/drm/radeon/rv770d.h6
-rw-r--r--drivers/gpu/drm/savage/savage_bci.c26
-rw-r--r--drivers/gpu/drm/sis/sis_drv.c3
-rw-r--r--drivers/gpu/drm/sis/sis_mm.c14
-rw-r--r--drivers/gpu/drm/ttm/Makefile2
-rw-r--r--drivers/gpu/drm/ttm/ttm_bo.c10
-rw-r--r--drivers/gpu/drm/ttm/ttm_bo_util.c2
-rw-r--r--drivers/gpu/drm/ttm/ttm_module.c4
-rw-r--r--drivers/gpu/drm/via/via_dma.c120
-rw-r--r--drivers/gpu/drm/via/via_dmablit.c71
-rw-r--r--drivers/gpu/drm/via/via_dmablit.h8
-rw-r--r--drivers/gpu/drm/via/via_drv.h22
-rw-r--r--drivers/gpu/drm/via/via_irq.c13
-rw-r--r--drivers/gpu/drm/via/via_map.c4
-rw-r--r--drivers/gpu/drm/via/via_mm.c7
-rw-r--r--drivers/gpu/drm/via/via_verifier.c47
-rw-r--r--drivers/gpu/drm/via/via_verifier.h4
-rw-r--r--drivers/gpu/drm/via/via_video.c6
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_drv.c2
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_drv.h2
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_fb.c2
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_resource.c2
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_ttm_glue.c20
-rw-r--r--drivers/hid/Kconfig19
-rw-r--r--drivers/hid/Makefile2
-rw-r--r--drivers/hid/hid-axff.c172
-rw-r--r--drivers/hid/hid-core.c9
-rw-r--r--drivers/hid/hid-elecom.c57
-rw-r--r--drivers/hid/hid-ids.h92
-rw-r--r--drivers/hid/hid-input.c24
-rw-r--r--drivers/hid/hid-magicmouse.c96
-rw-r--r--drivers/hid/hid-picolcd.c199
-rw-r--r--drivers/hid/hid-roccat-kone.c25
-rw-r--r--drivers/hid/hid-roccat-kone.h2
-rw-r--r--drivers/hid/hid-roccat.c9
-rw-r--r--drivers/hid/hid-roccat.h2
-rw-r--r--drivers/hid/hid-topseed.c5
-rw-r--r--drivers/hid/hid-wacom.c2
-rw-r--r--drivers/hid/hidraw.c2
-rw-r--r--drivers/hid/usbhid/hid-quirks.c2
-rw-r--r--drivers/hid/usbhid/hiddev.c54
-rw-r--r--drivers/hwmon/Kconfig17
-rw-r--r--drivers/hwmon/Makefile2
-rw-r--r--drivers/hwmon/jz4740-hwmon.c230
-rw-r--r--drivers/hwmon/pkgtemp.c456
-rw-r--r--drivers/hwmon/ultra45_env.c4
-rw-r--r--drivers/i2c/busses/i2c-cpm.c6
-rw-r--r--drivers/i2c/busses/i2c-ibm_iic.c4
-rw-r--r--drivers/i2c/busses/i2c-mpc.c71
-rw-r--r--drivers/i2c/i2c-core.c9
-rw-r--r--drivers/ide/ide-cs.c39
-rw-r--r--drivers/ide/ide-gd.c2
-rwxr-xr-xdrivers/idle/intel_idle.c2
-rw-r--r--drivers/ieee1394/dv1394.c18
-rw-r--r--drivers/ieee1394/eth1394.c3
-rw-r--r--drivers/ieee1394/raw1394.c7
-rw-r--r--drivers/ieee1394/sbp2.c11
-rw-r--r--drivers/ieee1394/video1394.c17
-rw-r--r--drivers/infiniband/core/addr.c2
-rw-r--r--drivers/infiniband/core/cm.c10
-rw-r--r--drivers/infiniband/core/user_mad.c2
-rw-r--r--drivers/infiniband/core/verbs.c4
-rw-r--r--drivers/infiniband/hw/cxgb3/iwch_cm.c6
-rw-r--r--drivers/infiniband/hw/cxgb3/iwch_qp.c8
-rw-r--r--drivers/infiniband/hw/cxgb4/cm.c95
-rw-r--r--drivers/infiniband/hw/cxgb4/cq.c4
-rw-r--r--drivers/infiniband/hw/cxgb4/iw_cxgb4.h1
-rw-r--r--drivers/infiniband/hw/cxgb4/mem.c2
-rw-r--r--drivers/infiniband/hw/cxgb4/qp.c244
-rw-r--r--drivers/infiniband/hw/cxgb4/t4.h32
-rw-r--r--drivers/infiniband/hw/cxgb4/t4fw_ri_api.h10
-rw-r--r--drivers/infiniband/hw/ehca/ehca_eq.c8
-rw-r--r--drivers/infiniband/hw/ehca/ehca_main.c3
-rw-r--r--drivers/infiniband/hw/ehca/ehca_mrmw.c5
-rw-r--r--drivers/infiniband/hw/ehca/ehca_qp.c2
-rw-r--r--drivers/infiniband/hw/ehca/hcp_if.c32
-rw-r--r--drivers/infiniband/hw/ehca/hcp_if.h2
-rw-r--r--drivers/infiniband/hw/ehca/hcp_phyp.c11
-rw-r--r--drivers/infiniband/hw/ehca/hcp_phyp.h2
-rw-r--r--drivers/infiniband/hw/ipath/ipath_driver.c13
-rw-r--r--drivers/infiniband/hw/ipath/ipath_file_ops.c2
-rw-r--r--drivers/infiniband/hw/mthca/mthca_cmd.c2
-rw-r--r--drivers/infiniband/hw/nes/nes.c37
-rw-r--r--drivers/infiniband/hw/nes/nes.h2
-rw-r--r--drivers/infiniband/hw/nes/nes_cm.c12
-rw-r--r--drivers/infiniband/hw/nes/nes_hw.c23
-rw-r--r--drivers/infiniband/hw/nes/nes_hw.h3
-rw-r--r--drivers/infiniband/hw/nes/nes_nic.c23
-rw-r--r--drivers/infiniband/hw/nes/nes_utils.c5
-rw-r--r--drivers/infiniband/hw/nes/nes_verbs.c21
-rw-r--r--drivers/infiniband/hw/qib/qib.h4
-rw-r--r--drivers/infiniband/hw/qib/qib_common.h16
-rw-r--r--drivers/infiniband/hw/qib/qib_driver.c2
-rw-r--r--drivers/infiniband/hw/qib/qib_file_ops.c203
-rw-r--r--drivers/infiniband/hw/qib/qib_fs.c18
-rw-r--r--drivers/infiniband/hw/qib/qib_iba7322.c4
-rw-r--r--drivers/infiniband/hw/qib/qib_init.c2
-rw-r--r--drivers/infiniband/hw/qib/qib_qp.c2
-rw-r--r--drivers/infiniband/hw/qib/qib_rc.c47
-rw-r--r--drivers/infiniband/hw/qib/qib_sdma.c2
-rw-r--r--drivers/infiniband/hw/qib/qib_sysfs.c21
-rw-r--r--drivers/infiniband/hw/qib/qib_tx.c2
-rw-r--r--drivers/infiniband/hw/qib/qib_uc.c6
-rw-r--r--drivers/infiniband/hw/qib/qib_ud.c17
-rw-r--r--drivers/infiniband/hw/qib/qib_verbs.c7
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib_ethtool.c7
-rw-r--r--drivers/infiniband/ulp/iser/iser_initiator.c2
-rw-r--r--drivers/infiniband/ulp/srp/ib_srp.c118
-rw-r--r--drivers/input/evdev.c54
-rw-r--r--drivers/input/input.c182
-rw-r--r--drivers/input/joydev.c7
-rw-r--r--drivers/input/joystick/xpad.c108
-rw-r--r--drivers/input/keyboard/Kconfig21
-rw-r--r--drivers/input/keyboard/Makefile2
-rw-r--r--drivers/input/keyboard/adp5588-keys.c351
-rw-r--r--drivers/input/keyboard/gpio_keys.c19
-rw-r--r--drivers/input/keyboard/lm8323.c12
-rw-r--r--drivers/input/keyboard/matrix_keypad.c108
-rw-r--r--drivers/input/keyboard/mcs_touchkey.c239
-rw-r--r--drivers/input/keyboard/samsung-keypad.c491
-rw-r--r--drivers/input/misc/Kconfig48
-rw-r--r--drivers/input/misc/Makefile4
-rw-r--r--drivers/input/misc/ad714x.c2
-rw-r--r--drivers/input/misc/adxl34x-i2c.c163
-rw-r--r--drivers/input/misc/adxl34x-spi.c145
-rw-r--r--drivers/input/misc/adxl34x.c915
-rw-r--r--drivers/input/misc/adxl34x.h30
-rw-r--r--drivers/input/misc/atlas_btns.c38
-rw-r--r--drivers/input/misc/ixp4xx-beeper.c3
-rw-r--r--drivers/input/misc/pwm-beeper.c199
-rw-r--r--drivers/input/misc/sparcspkr.c12
-rw-r--r--drivers/input/misc/twl4030-pwrbutton.c12
-rw-r--r--drivers/input/misc/wistron_btns.c4
-rw-r--r--drivers/input/mouse/bcm5974.c23
-rw-r--r--drivers/input/mouse/synaptics.c8
-rw-r--r--drivers/input/mousedev.c15
-rw-r--r--drivers/input/serio/i8042-io.h5
-rw-r--r--drivers/input/serio/i8042-ppcio.h75
-rw-r--r--drivers/input/serio/i8042-sparcio.h13
-rw-r--r--drivers/input/serio/i8042.c65
-rw-r--r--drivers/input/tablet/wacom_wac.c44
-rw-r--r--drivers/input/tablet/wacom_wac.h1
-rw-r--r--drivers/input/touchscreen/Kconfig67
-rw-r--r--drivers/input/touchscreen/Makefile6
-rw-r--r--drivers/input/touchscreen/ad7879-i2c.c143
-rw-r--r--drivers/input/touchscreen/ad7879-spi.c198
-rw-r--r--drivers/input/touchscreen/ad7879.c625
-rw-r--r--drivers/input/touchscreen/ad7879.h30
-rw-r--r--drivers/input/touchscreen/ads7846.c206
-rw-r--r--drivers/input/touchscreen/cy8ctmg110_ts.c363
-rw-r--r--drivers/input/touchscreen/mcs5000_ts.c6
-rw-r--r--drivers/input/touchscreen/qt602240_ts.c1401
-rw-r--r--drivers/input/touchscreen/tps6507x-ts.c3
-rw-r--r--drivers/input/touchscreen/usbtouchscreen.c215
-rw-r--r--drivers/input/xen-kbdfront.c2
-rw-r--r--drivers/isdn/capi/capi.c12
-rw-r--r--drivers/isdn/capi/capidrv.c7
-rw-r--r--drivers/isdn/divert/divert_procfs.c7
-rw-r--r--drivers/isdn/gigaset/Kconfig4
-rw-r--r--drivers/isdn/gigaset/bas-gigaset.c69
-rw-r--r--drivers/isdn/gigaset/capi.c66
-rw-r--r--drivers/isdn/gigaset/common.c2
-rw-r--r--drivers/isdn/gigaset/ev-layer.c226
-rw-r--r--drivers/isdn/gigaset/gigaset.h16
-rw-r--r--drivers/isdn/gigaset/i4l.c4
-rw-r--r--drivers/isdn/gigaset/interface.c37
-rw-r--r--drivers/isdn/gigaset/ser-gigaset.c27
-rw-r--r--drivers/isdn/gigaset/usb-gigaset.c29
-rw-r--r--drivers/isdn/hardware/avm/avm_cs.c25
-rw-r--r--drivers/isdn/hardware/eicon/divamnt.c7
-rw-r--r--drivers/isdn/hardware/eicon/divasi.c2
-rw-r--r--drivers/isdn/hardware/eicon/divasmain.c71
-rw-r--r--drivers/isdn/hardware/mISDN/avmfritz.c2
-rw-r--r--drivers/isdn/hardware/mISDN/hfcmulti.c13
-rw-r--r--drivers/isdn/hardware/mISDN/hfcpci.c94
-rw-r--r--drivers/isdn/hardware/mISDN/mISDNinfineon.c41
-rw-r--r--drivers/isdn/hardware/mISDN/speedfax.c2
-rw-r--r--drivers/isdn/hardware/mISDN/w6692.c2
-rw-r--r--drivers/isdn/hisax/avma1_cs.c29
-rw-r--r--drivers/isdn/hisax/callc.c2
-rw-r--r--drivers/isdn/hisax/config.c84
-rw-r--r--drivers/isdn/hisax/elsa_cs.c32
-rw-r--r--drivers/isdn/hisax/q931.c13
-rw-r--r--drivers/isdn/hisax/sedlbauer_cs.c83
-rw-r--r--drivers/isdn/hisax/tei.c2
-rw-r--r--drivers/isdn/hisax/teles_cs.c30
-rw-r--r--drivers/isdn/hysdn/hysdn_procconf.c21
-rw-r--r--drivers/isdn/hysdn/hysdn_proclog.c51
-rw-r--r--drivers/isdn/i4l/isdn_common.c27
-rw-r--r--drivers/isdn/i4l/isdn_net.c7
-rw-r--r--drivers/isdn/i4l/isdn_ppp.c13
-rw-r--r--drivers/isdn/i4l/isdn_tty.c6
-rw-r--r--drivers/isdn/mISDN/tei.c2
-rw-r--r--drivers/isdn/mISDN/timerdev.c7
-rw-r--r--drivers/isdn/pcbit/drv.c10
-rw-r--r--drivers/isdn/sc/ioctl.c23
-rw-r--r--drivers/leds/leds-bd2802.c4
-rw-r--r--drivers/macintosh/macio_sysfs.c5
-rw-r--r--drivers/macintosh/via-pmu.c9
-rw-r--r--drivers/media/IR/Kconfig35
-rw-r--r--drivers/media/IR/Makefile3
-rw-r--r--drivers/media/IR/imon.c11
-rw-r--r--drivers/media/IR/ir-core-priv.h54
-rw-r--r--drivers/media/IR/ir-jvc-decoder.c152
-rw-r--r--drivers/media/IR/ir-keytable.c5
-rw-r--r--drivers/media/IR/ir-lirc-codec.c278
-rw-r--r--drivers/media/IR/ir-nec-decoder.c151
-rw-r--r--drivers/media/IR/ir-raw-event.c167
-rw-r--r--drivers/media/IR/ir-rc5-decoder.c167
-rw-r--r--drivers/media/IR/ir-rc6-decoder.c153
-rw-r--r--drivers/media/IR/ir-sony-decoder.c155
-rw-r--r--drivers/media/IR/ir-sysfs.c251
-rw-r--r--drivers/media/IR/keymaps/Makefile4
-rw-r--r--drivers/media/IR/keymaps/rc-dib0700-nec.c124
-rw-r--r--drivers/media/IR/keymaps/rc-dib0700-rc5.c235
-rw-r--r--drivers/media/IR/keymaps/rc-lirc.c41
-rw-r--r--drivers/media/IR/keymaps/rc-rc6-mce.c105
-rw-r--r--drivers/media/IR/lirc_dev.c764
-rw-r--r--drivers/media/IR/mceusb.c1143
-rw-r--r--drivers/media/common/saa7146_fops.c2
-rw-r--r--drivers/media/common/saa7146_vbi.c4
-rw-r--r--drivers/media/common/saa7146_video.c4
-rw-r--r--drivers/media/common/tuners/tda18271-fe.c8
-rw-r--r--drivers/media/common/tuners/tuner-simple.c3
-rw-r--r--drivers/media/common/tuners/xc5000.c59
-rw-r--r--drivers/media/dvb/bt8xx/dst_ca.c2
-rw-r--r--drivers/media/dvb/dvb-core/dmxdev.c2
-rw-r--r--drivers/media/dvb/dvb-core/dvb_ca_en50221.c10
-rw-r--r--drivers/media/dvb/dvb-core/dvb_demux.c10
-rw-r--r--drivers/media/dvb/dvb-core/dvb_frontend.c10
-rw-r--r--drivers/media/dvb/dvb-usb/a800.c12
-rw-r--r--drivers/media/dvb/dvb-usb/af9005-remote.c4
-rw-r--r--drivers/media/dvb/dvb-usb/af9005.c71
-rw-r--r--drivers/media/dvb/dvb-usb/af9005.h2
-rw-r--r--drivers/media/dvb/dvb-usb/af9015.c42
-rw-r--r--drivers/media/dvb/dvb-usb/af9015.h18
-rw-r--r--drivers/media/dvb/dvb-usb/anysee.c28
-rw-r--r--drivers/media/dvb/dvb-usb/az6027.c13
-rw-r--r--drivers/media/dvb/dvb-usb/cinergyT2-core.c12
-rw-r--r--drivers/media/dvb/dvb-usb/cxusb.c128
-rw-r--r--drivers/media/dvb/dvb-usb/dib0700.h1
-rw-r--r--drivers/media/dvb/dvb-usb/dib0700_core.c266
-rw-r--r--drivers/media/dvb/dvb-usb/dib0700_devices.c614
-rw-r--r--drivers/media/dvb/dvb-usb/dibusb-common.c2
-rw-r--r--drivers/media/dvb/dvb-usb/dibusb-mb.c40
-rw-r--r--drivers/media/dvb/dvb-usb/dibusb-mc.c10
-rw-r--r--drivers/media/dvb/dvb-usb/dibusb.h2
-rw-r--r--drivers/media/dvb/dvb-usb/digitv.c20
-rw-r--r--drivers/media/dvb/dvb-usb/dtt200u.c42
-rw-r--r--drivers/media/dvb/dvb-usb/dvb-usb-ids.h1
-rw-r--r--drivers/media/dvb/dvb-usb/dvb-usb-init.c60
-rw-r--r--drivers/media/dvb/dvb-usb/dvb-usb-remote.c198
-rw-r--r--drivers/media/dvb/dvb-usb/dvb-usb.h92
-rw-r--r--drivers/media/dvb/dvb-usb/dw2102.c67
-rw-r--r--drivers/media/dvb/dvb-usb/gp8psk-fe.c2
-rw-r--r--drivers/media/dvb/dvb-usb/m920x.c44
-rw-r--r--drivers/media/dvb/dvb-usb/nova-t-usb2.c14
-rw-r--r--drivers/media/dvb/dvb-usb/opera1.c16
-rw-r--r--drivers/media/dvb/dvb-usb/vp702x.c14
-rw-r--r--drivers/media/dvb/dvb-usb/vp7045.c14
-rw-r--r--drivers/media/dvb/firewire/firedtv-fw.c4
-rw-r--r--drivers/media/dvb/frontends/Kconfig1
-rw-r--r--drivers/media/dvb/frontends/af9013.c52
-rw-r--r--drivers/media/dvb/frontends/af9013.h2
-rw-r--r--drivers/media/dvb/frontends/af9013_priv.h8
-rw-r--r--drivers/media/dvb/frontends/dib3000mb.c9
-rw-r--r--drivers/media/dvb/frontends/dib3000mb_priv.h4
-rw-r--r--drivers/media/dvb/frontends/dib3000mc.c2
-rw-r--r--drivers/media/dvb/frontends/lgdt3305.c267
-rw-r--r--drivers/media/dvb/frontends/lgdt3305.h10
-rw-r--r--drivers/media/dvb/frontends/lgs8gxx.c50
-rw-r--r--drivers/media/dvb/frontends/mb86a16.c1
-rw-r--r--drivers/media/dvb/frontends/tda10048.c43
-rw-r--r--drivers/media/dvb/mantis/Kconfig14
-rw-r--r--drivers/media/dvb/mantis/mantis_input.c5
-rw-r--r--drivers/media/dvb/siano/sms-cards.c2
-rw-r--r--drivers/media/dvb/siano/sms-cards.h2
-rw-r--r--drivers/media/dvb/siano/smscoreapi.c6
-rw-r--r--drivers/media/dvb/siano/smsir.c261
-rw-r--r--drivers/media/dvb/siano/smsir.h63
-rw-r--r--drivers/media/dvb/siano/smsusb.c3
-rw-r--r--drivers/media/radio/si470x/radio-si470x-common.c2
-rw-r--r--drivers/media/radio/si4713-i2c.c12
-rw-r--r--drivers/media/video/Kconfig183
-rw-r--r--drivers/media/video/Makefile9
-rw-r--r--drivers/media/video/ak881x.c6
-rw-r--r--drivers/media/video/au0828/Makefile2
-rw-r--r--drivers/media/video/au0828/au0828-vbi.c138
-rw-r--r--drivers/media/video/au0828/au0828-video.c443
-rw-r--r--drivers/media/video/au0828/au0828.h20
-rw-r--r--drivers/media/video/bt8xx/bttv-risc.c2
-rw-r--r--drivers/media/video/cpia_usb.c3
-rw-r--r--drivers/media/video/cx18/cx18-ioctl.c2
-rw-r--r--drivers/media/video/cx23885/cx23885-cards.c40
-rw-r--r--drivers/media/video/cx23885/cx23885-core.c11
-rw-r--r--drivers/media/video/cx23885/cx23885-dvb.c2
-rw-r--r--drivers/media/video/cx23885/cx23885-input.c317
-rw-r--r--drivers/media/video/cx23885/cx23885-ir.c2
-rw-r--r--drivers/media/video/cx23885/cx23885.h12
-rw-r--r--drivers/media/video/cx88/cx88-alsa.c37
-rw-r--r--drivers/media/video/cx88/cx88-cards.c9
-rw-r--r--drivers/media/video/cx88/cx88-core.c2
-rw-r--r--drivers/media/video/cx88/cx88-i2c.c6
-rw-r--r--drivers/media/video/cx88/cx88-input.c46
-rw-r--r--drivers/media/video/cx88/cx88.h1
-rw-r--r--drivers/media/video/dabusb.c13
-rw-r--r--drivers/media/video/davinci/Kconfig93
-rw-r--r--drivers/media/video/em28xx/em28xx-cards.c28
-rw-r--r--drivers/media/video/em28xx/em28xx-dvb.c33
-rw-r--r--drivers/media/video/em28xx/em28xx-input.c80
-rw-r--r--drivers/media/video/em28xx/em28xx-video.c4
-rw-r--r--drivers/media/video/em28xx/em28xx.h2
-rw-r--r--drivers/media/video/fsl-viu.c1632
-rw-r--r--drivers/media/video/gspca/Kconfig18
-rw-r--r--drivers/media/video/gspca/Makefile4
-rw-r--r--drivers/media/video/gspca/conex.c8
-rw-r--r--drivers/media/video/gspca/cpia1.c19
-rw-r--r--drivers/media/video/gspca/gl860/gl860-mi2020.c731
-rw-r--r--drivers/media/video/gspca/gl860/gl860-ov9655.c4
-rw-r--r--drivers/media/video/gspca/gl860/gl860.c42
-rw-r--r--drivers/media/video/gspca/gl860/gl860.h13
-rw-r--r--drivers/media/video/gspca/gspca.c340
-rw-r--r--drivers/media/video/gspca/gspca.h22
-rw-r--r--drivers/media/video/gspca/jeilinj.c6
-rw-r--r--drivers/media/video/gspca/m5602/m5602_bridge.h1
-rw-r--r--drivers/media/video/gspca/m5602/m5602_core.c15
-rw-r--r--drivers/media/video/gspca/m5602/m5602_s5k83a.c1
-rw-r--r--drivers/media/video/gspca/mars.c13
-rw-r--r--drivers/media/video/gspca/ov519.c28
-rw-r--r--drivers/media/video/gspca/ov534.c7
-rw-r--r--drivers/media/video/gspca/pac7302.c31
-rw-r--r--drivers/media/video/gspca/pac7311.c29
-rw-r--r--drivers/media/video/gspca/sn9c20x.c18
-rw-r--r--drivers/media/video/gspca/sonixb.c8
-rw-r--r--drivers/media/video/gspca/sonixj.c38
-rw-r--r--drivers/media/video/gspca/spca1528.c605
-rw-r--r--drivers/media/video/gspca/spca500.c13
-rw-r--r--drivers/media/video/gspca/sq930x.c1402
-rw-r--r--drivers/media/video/gspca/stk014.c17
-rw-r--r--drivers/media/video/gspca/stv06xx/stv06xx.h1
-rw-r--r--drivers/media/video/gspca/sunplus.c17
-rw-r--r--drivers/media/video/gspca/t613.c408
-rw-r--r--drivers/media/video/gspca/tv8532.c227
-rw-r--r--drivers/media/video/gspca/vc032x.c228
-rw-r--r--drivers/media/video/gspca/w996Xcf.c16
-rw-r--r--drivers/media/video/gspca/zc3xx.c92
-rw-r--r--drivers/media/video/hdpvr/hdpvr-core.c5
-rw-r--r--drivers/media/video/hdpvr/hdpvr-video.c4
-rw-r--r--drivers/media/video/ir-kbd-i2c.c14
-rw-r--r--drivers/media/video/ivtv/ivtv-driver.c40
-rw-r--r--drivers/media/video/ivtv/ivtv-driver.h12
-rw-r--r--drivers/media/video/ivtv/ivtv-fileops.c30
-rw-r--r--drivers/media/video/ivtv/ivtv-firmware.c122
-rw-r--r--drivers/media/video/ivtv/ivtv-firmware.h1
-rw-r--r--drivers/media/video/ivtv/ivtv-irq.c15
-rw-r--r--drivers/media/video/ivtv/ivtv-irq.h2
-rw-r--r--drivers/media/video/ivtv/ivtv-mailbox.c8
-rw-r--r--drivers/media/video/ivtv/ivtv-mailbox.h1
-rw-r--r--drivers/media/video/ivtv/ivtv-streams.c11
-rw-r--r--drivers/media/video/ivtv/ivtv-version.h2
-rw-r--r--drivers/media/video/ivtv/ivtvfb.c45
-rw-r--r--drivers/media/video/mem2mem_testdev.c4
-rw-r--r--drivers/media/video/mt9m111.c16
-rw-r--r--drivers/media/video/mt9t112.c12
-rw-r--r--drivers/media/video/omap/omap_vout.c8
-rw-r--r--drivers/media/video/omap24xxcam.c2
-rw-r--r--drivers/media/video/ov511.c5995
-rw-r--r--drivers/media/video/ov511.h573
-rw-r--r--drivers/media/video/ov772x.c8
-rw-r--r--drivers/media/video/ov9640.c14
-rw-r--r--drivers/media/video/ovcamchip/Makefile4
-rw-r--r--drivers/media/video/ovcamchip/ov6x20.c414
-rw-r--r--drivers/media/video/ovcamchip/ov6x30.c373
-rw-r--r--drivers/media/video/ovcamchip/ov76be.c302
-rw-r--r--drivers/media/video/ovcamchip/ov7x10.c334
-rw-r--r--drivers/media/video/ovcamchip/ov7x20.c454
-rw-r--r--drivers/media/video/ovcamchip/ovcamchip_core.c395
-rw-r--r--drivers/media/video/ovcamchip/ovcamchip_priv.h101
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-ioread.c5
-rw-r--r--drivers/media/video/pxa_camera.c10
-rw-r--r--drivers/media/video/rj54n1cb0c.c10
-rw-r--r--drivers/media/video/s2255drv.c724
-rw-r--r--drivers/media/video/saa7134/saa7134-alsa.c14
-rw-r--r--drivers/media/video/saa7134/saa7134-cards.c31
-rw-r--r--drivers/media/video/saa7134/saa7134-core.c2
-rw-r--r--drivers/media/video/saa7134/saa7134-dvb.c23
-rw-r--r--drivers/media/video/saa7134/saa7134.h1
-rw-r--r--drivers/media/video/sh_mobile_ceu_camera.c149
-rw-r--r--drivers/media/video/sh_mobile_csi2.c354
-rw-r--r--drivers/media/video/sh_vou.c65
-rw-r--r--drivers/media/video/soc_camera.c3
-rw-r--r--drivers/media/video/soc_camera_platform.c42
-rw-r--r--drivers/media/video/soc_mediabus.c8
-rw-r--r--drivers/media/video/stv680.c1565
-rw-r--r--drivers/media/video/stv680.h227
-rw-r--r--drivers/media/video/tlg2300/pd-main.c3
-rw-r--r--drivers/media/video/tw9910.c8
-rw-r--r--drivers/media/video/usbvideo/Kconfig14
-rw-r--r--drivers/media/video/usbvideo/Makefile1
-rw-r--r--drivers/media/video/usbvideo/quickcam_messenger.c1126
-rw-r--r--drivers/media/video/usbvideo/quickcam_messenger.h112
-rw-r--r--drivers/media/video/usbvideo/vicam.c2
-rw-r--r--drivers/media/video/uvc/uvc_ctrl.c105
-rw-r--r--drivers/media/video/uvc/uvc_driver.c15
-rw-r--r--drivers/media/video/uvc/uvc_v4l2.c103
-rw-r--r--drivers/media/video/uvc/uvcvideo.h45
-rw-r--r--drivers/media/video/v4l2-compat-ioctl32.c2
-rw-r--r--drivers/media/video/v4l2-dev.c6
-rw-r--r--drivers/media/video/videobuf-core.c84
-rw-r--r--drivers/media/video/videobuf-dma-contig.c6
-rw-r--r--drivers/media/video/videobuf-dma-sg.c76
-rw-r--r--drivers/media/video/videobuf-vmalloc.c36
-rw-r--r--drivers/media/video/w9968cf.c3620
-rw-r--r--drivers/media/video/w9968cf.h333
-rw-r--r--drivers/media/video/w9968cf_decoder.h86
-rw-r--r--drivers/media/video/w9968cf_vpp.h40
-rw-r--r--drivers/media/video/zc0301/Kconfig15
-rw-r--r--drivers/media/video/zc0301/Makefile3
-rw-r--r--drivers/media/video/zc0301/zc0301.h196
-rw-r--r--drivers/media/video/zc0301/zc0301_core.c2098
-rw-r--r--drivers/media/video/zc0301/zc0301_pas202bcb.c362
-rw-r--r--drivers/media/video/zc0301/zc0301_pb0330.c188
-rw-r--r--drivers/media/video/zc0301/zc0301_sensor.h107
-rw-r--r--drivers/media/video/zoran/videocodec.c5
-rw-r--r--drivers/media/video/zoran/zoran.h2
-rw-r--r--drivers/media/video/zoran/zoran_device.c2
-rw-r--r--drivers/media/video/zoran/zr36050.c2
-rw-r--r--drivers/media/video/zoran/zr36060.c2
-rw-r--r--drivers/message/fusion/mptbase.c53
-rw-r--r--drivers/message/fusion/mptbase.h13
-rw-r--r--drivers/message/fusion/mptctl.c38
-rw-r--r--drivers/message/fusion/mptfc.c9
-rw-r--r--drivers/message/fusion/mptlan.c4
-rw-r--r--drivers/message/fusion/mptsas.c278
-rw-r--r--drivers/message/fusion/mptsas.h1
-rw-r--r--drivers/message/fusion/mptscsih.c54
-rw-r--r--drivers/message/fusion/mptspi.c9
-rw-r--r--drivers/misc/Kconfig4
-rw-r--r--drivers/misc/enclosure.c7
-rw-r--r--drivers/mmc/host/Kconfig9
-rw-r--r--drivers/mmc/host/Makefile1
-rw-r--r--drivers/mmc/host/jz4740_mmc.c1029
-rw-r--r--drivers/mmc/host/mmc_spi.c8
-rw-r--r--drivers/mmc/host/sdricoh_cs.c1
-rw-r--r--drivers/mtd/maps/Kconfig2
-rw-r--r--drivers/mtd/maps/pcmciamtd.c15
-rw-r--r--drivers/mtd/maps/redwood.c43
-rw-r--r--drivers/mtd/maps/sun_uflash.c4
-rw-r--r--drivers/mtd/nand/Kconfig6
-rw-r--r--drivers/mtd/nand/Makefile1
-rw-r--r--drivers/mtd/nand/denali.c2
-rw-r--r--drivers/mtd/nand/jz4740_nand.c516
-rw-r--r--drivers/mtd/ubi/build.c3
-rw-r--r--drivers/mtd/ubi/eba.c49
-rw-r--r--drivers/mtd/ubi/io.c60
-rw-r--r--drivers/mtd/ubi/scan.c131
-rw-r--r--drivers/mtd/ubi/scan.h19
-rw-r--r--drivers/mtd/ubi/ubi.h10
-rw-r--r--drivers/net/3c527.c4
-rw-r--r--drivers/net/3c527.h6
-rw-r--r--drivers/net/3c59x.c392
-rw-r--r--drivers/net/8139cp.c2
-rw-r--r--drivers/net/8139too.c8
-rw-r--r--drivers/net/82596.c64
-rw-r--r--drivers/net/Kconfig47
-rw-r--r--drivers/net/Makefile6
-rw-r--r--drivers/net/Space.c6
-rw-r--r--drivers/net/ac3200.c2
-rw-r--r--drivers/net/appletalk/ipddp.c2
-rw-r--r--drivers/net/arcnet/capmode.c177
-rw-r--r--drivers/net/arcnet/com20020-isa.c4
-rw-r--r--drivers/net/arcnet/com90io.c2
-rw-r--r--drivers/net/arm/ixp4xx_eth.c14
-rw-r--r--drivers/net/arm/w90p910_ether.c3
-rw-r--r--drivers/net/at1700.c4
-rw-r--r--drivers/net/atl1c/atl1c.h9
-rw-r--r--drivers/net/atl1c/atl1c_hw.c107
-rw-r--r--drivers/net/atl1c/atl1c_hw.h49
-rw-r--r--drivers/net/atl1c/atl1c_main.c348
-rw-r--r--drivers/net/atlx/atl1.h4
-rw-r--r--drivers/net/au1000_eth.c33
-rw-r--r--drivers/net/ax88796.c4
-rw-r--r--drivers/net/b44.c146
-rw-r--r--drivers/net/bcm63xx_enet.c2
-rw-r--r--drivers/net/benet/be.h31
-rw-r--r--drivers/net/benet/be_cmds.c91
-rw-r--r--drivers/net/benet/be_cmds.h48
-rw-r--r--drivers/net/benet/be_ethtool.c58
-rw-r--r--drivers/net/benet/be_hw.h14
-rw-r--r--drivers/net/benet/be_main.c376
-rw-r--r--drivers/net/bfin_mac.c123
-rw-r--r--drivers/net/bfin_mac.h5
-rw-r--r--drivers/net/bnx2.c264
-rw-r--r--drivers/net/bnx2.h12
-rw-r--r--drivers/net/bnx2x/Makefile7
-rw-r--r--drivers/net/bnx2x/bnx2x.h (renamed from drivers/net/bnx2x.h)235
-rw-r--r--drivers/net/bnx2x/bnx2x_cmn.c2252
-rw-r--r--drivers/net/bnx2x/bnx2x_cmn.h652
-rw-r--r--drivers/net/bnx2x/bnx2x_dump.h (renamed from drivers/net/bnx2x_dump.h)0
-rw-r--r--drivers/net/bnx2x/bnx2x_ethtool.c1971
-rw-r--r--drivers/net/bnx2x/bnx2x_fw_defs.h (renamed from drivers/net/bnx2x_fw_defs.h)0
-rw-r--r--drivers/net/bnx2x/bnx2x_fw_file_hdr.h (renamed from drivers/net/bnx2x_fw_file_hdr.h)0
-rw-r--r--drivers/net/bnx2x/bnx2x_hsi.h (renamed from drivers/net/bnx2x_hsi.h)0
-rw-r--r--drivers/net/bnx2x/bnx2x_init.h (renamed from drivers/net/bnx2x_init.h)0
-rw-r--r--drivers/net/bnx2x/bnx2x_init_ops.h (renamed from drivers/net/bnx2x_init_ops.h)0
-rw-r--r--drivers/net/bnx2x/bnx2x_link.c (renamed from drivers/net/bnx2x_link.c)8
-rw-r--r--drivers/net/bnx2x/bnx2x_link.h (renamed from drivers/net/bnx2x_link.h)0
-rw-r--r--drivers/net/bnx2x/bnx2x_main.c (renamed from drivers/net/bnx2x_main.c)5976
-rw-r--r--drivers/net/bnx2x/bnx2x_reg.h (renamed from drivers/net/bnx2x_reg.h)0
-rw-r--r--drivers/net/bnx2x/bnx2x_stats.c1411
-rw-r--r--drivers/net/bnx2x/bnx2x_stats.h239
-rw-r--r--drivers/net/bonding/bond_alb.c37
-rw-r--r--drivers/net/bonding/bond_ipv6.c2
-rw-r--r--drivers/net/bonding/bond_main.c222
-rw-r--r--drivers/net/bonding/bond_sysfs.c316
-rw-r--r--drivers/net/bonding/bonding.h14
-rw-r--r--drivers/net/caif/Kconfig22
-rw-r--r--drivers/net/caif/Makefile14
-rw-r--r--drivers/net/caif/caif_serial.c12
-rw-r--r--drivers/net/caif/caif_spi.c850
-rw-r--r--drivers/net/caif/caif_spi_slave.c252
-rw-r--r--drivers/net/can/Kconfig9
-rw-r--r--drivers/net/can/Makefile1
-rw-r--r--drivers/net/can/flexcan.c1030
-rw-r--r--drivers/net/can/mscan/mscan.h2
-rw-r--r--drivers/net/can/usb/Kconfig6
-rw-r--r--drivers/net/can/usb/Makefile1
-rw-r--r--drivers/net/can/usb/ems_usb.c2
-rw-r--r--drivers/net/can/usb/esd_usb2.c1132
-rw-r--r--drivers/net/cassini.c25
-rw-r--r--drivers/net/cassini.h4
-rw-r--r--drivers/net/chelsio/common.h1
-rw-r--r--drivers/net/chelsio/subr.c49
-rw-r--r--drivers/net/cnic.c373
-rw-r--r--drivers/net/cnic.h23
-rw-r--r--drivers/net/cnic_if.h4
-rw-r--r--drivers/net/cpmac.c13
-rw-r--r--drivers/net/cris/eth_v10.c4
-rw-r--r--drivers/net/cs89x0.c162
-rw-r--r--drivers/net/cs89x0.h4
-rw-r--r--drivers/net/cxgb3/cxgb3_main.c12
-rw-r--r--drivers/net/cxgb3/sge.c14
-rw-r--r--drivers/net/cxgb3/t3_hw.c16
-rw-r--r--drivers/net/cxgb3/version.h4
-rw-r--r--drivers/net/cxgb4/cxgb4.h11
-rw-r--r--drivers/net/cxgb4/cxgb4_main.c755
-rw-r--r--drivers/net/cxgb4/cxgb4_uld.h6
-rw-r--r--drivers/net/cxgb4/l2t.c7
-rw-r--r--drivers/net/cxgb4/sge.c67
-rw-r--r--drivers/net/cxgb4/t4_hw.c109
-rw-r--r--drivers/net/cxgb4/t4_hw.h45
-rw-r--r--drivers/net/cxgb4/t4_msg.h16
-rw-r--r--drivers/net/cxgb4/t4_regs.h7
-rw-r--r--drivers/net/cxgb4/t4fw_api.h63
-rw-r--r--drivers/net/cxgb4vf/Makefile7
-rw-r--r--drivers/net/cxgb4vf/adapter.h540
-rw-r--r--drivers/net/cxgb4vf/cxgb4vf_main.c2888
-rw-r--r--drivers/net/cxgb4vf/sge.c2454
-rw-r--r--drivers/net/cxgb4vf/t4vf_common.h273
-rw-r--r--drivers/net/cxgb4vf/t4vf_defs.h121
-rw-r--r--drivers/net/cxgb4vf/t4vf_hw.c1333
-rw-r--r--drivers/net/davinci_emac.c200
-rw-r--r--drivers/net/depca.c29
-rw-r--r--drivers/net/dm9000.c2
-rw-r--r--drivers/net/dnet.c9
-rw-r--r--drivers/net/e1000/e1000.h22
-rw-r--r--drivers/net/e1000/e1000_ethtool.c27
-rw-r--r--drivers/net/e1000/e1000_main.c86
-rw-r--r--drivers/net/e1000e/82571.c2
-rw-r--r--drivers/net/e1000e/defines.h4
-rw-r--r--drivers/net/e1000e/e1000.h10
-rw-r--r--drivers/net/e1000e/es2lan.c2
-rw-r--r--drivers/net/e1000e/ethtool.c144
-rw-r--r--drivers/net/e1000e/hw.h17
-rw-r--r--drivers/net/e1000e/ich8lan.c456
-rw-r--r--drivers/net/e1000e/lib.c2
-rw-r--r--drivers/net/e1000e/netdev.c375
-rw-r--r--drivers/net/e1000e/param.c2
-rw-r--r--drivers/net/e1000e/phy.c5
-rw-r--r--drivers/net/ehea/ehea_main.c2
-rw-r--r--drivers/net/ehea/ehea_qmr.h2
-rw-r--r--drivers/net/enic/cq_desc.h2
-rw-r--r--drivers/net/enic/cq_enet_desc.h20
-rw-r--r--drivers/net/enic/enic.h21
-rw-r--r--drivers/net/enic/enic_main.c517
-rw-r--r--drivers/net/enic/enic_res.c53
-rw-r--r--drivers/net/enic/enic_res.h33
-rw-r--r--drivers/net/enic/rq_enet_desc.h2
-rw-r--r--drivers/net/enic/vnic_cq.c4
-rw-r--r--drivers/net/enic/vnic_cq.h2
-rw-r--r--drivers/net/enic/vnic_dev.c272
-rw-r--r--drivers/net/enic/vnic_dev.h21
-rw-r--r--drivers/net/enic/vnic_devcmd.h35
-rw-r--r--drivers/net/enic/vnic_enet.h4
-rw-r--r--drivers/net/enic/vnic_intr.c5
-rw-r--r--drivers/net/enic/vnic_intr.h8
-rw-r--r--drivers/net/enic/vnic_nic.h2
-rw-r--r--drivers/net/enic/vnic_resource.h2
-rw-r--r--drivers/net/enic/vnic_rq.c40
-rw-r--r--drivers/net/enic/vnic_rq.h16
-rw-r--r--drivers/net/enic/vnic_rss.h2
-rw-r--r--drivers/net/enic/vnic_stats.h2
-rw-r--r--drivers/net/enic/vnic_vic.c8
-rw-r--r--drivers/net/enic/vnic_vic.h2
-rw-r--r--drivers/net/enic/vnic_wq.c25
-rw-r--r--drivers/net/enic/vnic_wq.h16
-rw-r--r--drivers/net/enic/wq_enet_desc.h2
-rw-r--r--drivers/net/epic100.c47
-rw-r--r--drivers/net/eth16i.c4
-rw-r--r--drivers/net/ethoc.c160
-rw-r--r--drivers/net/fealnx.c68
-rw-r--r--drivers/net/fec.c110
-rw-r--r--drivers/net/fec_mpc52xx.c40
-rw-r--r--drivers/net/fec_mpc52xx_phy.c24
-rw-r--r--drivers/net/forcedeth.c62
-rw-r--r--drivers/net/fs_enet/fs_enet-main.c3
-rw-r--r--drivers/net/fsl_pq_mdio.c1
-rw-r--r--drivers/net/fsl_pq_mdio.h2
-rw-r--r--drivers/net/gianfar.c154
-rw-r--r--drivers/net/gianfar.h13
-rw-r--r--drivers/net/greth.c1
-rw-r--r--drivers/net/hamachi.c63
-rw-r--r--drivers/net/hp100.c55
-rw-r--r--drivers/net/ibm_newemac/core.c6
-rw-r--r--drivers/net/igb/e1000_82575.c143
-rw-r--r--drivers/net/igb/e1000_defines.h16
-rw-r--r--drivers/net/igb/igb_ethtool.c8
-rw-r--r--drivers/net/igb/igb_main.c43
-rw-r--r--drivers/net/igbvf/netdev.c11
-rw-r--r--drivers/net/ioc3-eth.c49
-rw-r--r--drivers/net/irda/donauboe.h2
-rw-r--r--drivers/net/irda/irda-usb.h2
-rw-r--r--drivers/net/irda/ks959-sir.c2
-rw-r--r--drivers/net/irda/ksdazzle-sir.c2
-rw-r--r--drivers/net/irda/sh_irda.c2
-rw-r--r--drivers/net/irda/sh_sir.c2
-rw-r--r--drivers/net/irda/smsc-ircc2.c5
-rw-r--r--drivers/net/irda/vlsi_ir.h6
-rw-r--r--drivers/net/ixgbe/ixgbe.h9
-rw-r--r--drivers/net/ixgbe/ixgbe_82599.c18
-rw-r--r--drivers/net/ixgbe/ixgbe_common.h25
-rw-r--r--drivers/net/ixgbe/ixgbe_dcb_82599.c2
-rw-r--r--drivers/net/ixgbe/ixgbe_dcb_nl.c2
-rw-r--r--drivers/net/ixgbe/ixgbe_ethtool.c107
-rw-r--r--drivers/net/ixgbe/ixgbe_fcoe.c56
-rw-r--r--drivers/net/ixgbe/ixgbe_main.c425
-rw-r--r--drivers/net/ixgbe/ixgbe_phy.c33
-rw-r--r--drivers/net/ixgbe/ixgbe_phy.h1
-rw-r--r--drivers/net/ixgbe/ixgbe_sriov.c30
-rw-r--r--drivers/net/ixgbe/ixgbe_type.h2
-rw-r--r--drivers/net/ixgbevf/ixgbevf_main.c18
-rw-r--r--drivers/net/jazzsonic.c17
-rw-r--r--drivers/net/ks8842.c706
-rw-r--r--drivers/net/ksz884x.c61
-rw-r--r--drivers/net/lance.c56
-rw-r--r--drivers/net/ll_temac_main.c65
-rw-r--r--drivers/net/loopback.c33
-rw-r--r--drivers/net/mac8390.c57
-rw-r--r--drivers/net/mac89x0.c52
-rw-r--r--drivers/net/macb.c2
-rw-r--r--drivers/net/macsonic.c37
-rw-r--r--drivers/net/macvlan.c95
-rw-r--r--drivers/net/macvtap.c2
-rw-r--r--drivers/net/mlx4/catas.c4
-rw-r--r--drivers/net/mlx4/en_ethtool.c38
-rw-r--r--drivers/net/mlx4/en_main.c29
-rw-r--r--drivers/net/mlx4/en_netdev.c1
-rw-r--r--drivers/net/mlx4/eq.c20
-rw-r--r--drivers/net/mlx4/main.c16
-rw-r--r--drivers/net/mlx4/mlx4.h15
-rw-r--r--drivers/net/mlx4/mlx4_en.h62
-rw-r--r--drivers/net/mlx4/mr.c2
-rw-r--r--drivers/net/mv643xx_eth.c12
-rw-r--r--drivers/net/myri10ge/myri10ge.c10
-rw-r--r--drivers/net/myri_sbus.c6
-rw-r--r--drivers/net/natsemi.c56
-rw-r--r--drivers/net/netxen/netxen_nic_ctx.c16
-rw-r--r--drivers/net/netxen/netxen_nic_ethtool.c13
-rw-r--r--drivers/net/ni52.c37
-rw-r--r--drivers/net/niu.c28
-rw-r--r--drivers/net/niu.h4
-rw-r--r--drivers/net/ns83820.c44
-rw-r--r--drivers/net/octeon/octeon_mgmt.c8
-rw-r--r--drivers/net/pcmcia/3c574_cs.c14
-rw-r--r--drivers/net/pcmcia/3c589_cs.c14
-rw-r--r--drivers/net/pcmcia/axnet_cs.c48
-rw-r--r--drivers/net/pcmcia/com20020_cs.c22
-rw-r--r--drivers/net/pcmcia/fmvj18x_cs.c48
-rw-r--r--drivers/net/pcmcia/ibmtr_cs.c29
-rw-r--r--drivers/net/pcmcia/nmclan_cs.c32
-rw-r--r--drivers/net/pcmcia/pcnet_cs.c63
-rw-r--r--drivers/net/pcmcia/smc91c92_cs.c71
-rw-r--r--drivers/net/pcmcia/xirc2ps_cs.c60
-rw-r--r--drivers/net/phy/broadcom.c46
-rw-r--r--drivers/net/phy/icplus.c2
-rw-r--r--drivers/net/phy/marvell.c77
-rw-r--r--drivers/net/phy/mdio-octeon.c6
-rw-r--r--drivers/net/phy/micrel.c167
-rw-r--r--drivers/net/phy/phy.c8
-rw-r--r--drivers/net/phy/phy_device.c2
-rw-r--r--drivers/net/ppp_generic.c37
-rw-r--r--drivers/net/pppoe.c3
-rw-r--r--drivers/net/ps3_gelic_wireless.h10
-rw-r--r--drivers/net/qla3xxx.c1435
-rw-r--r--drivers/net/qlcnic/qlcnic.h225
-rw-r--r--drivers/net/qlcnic/qlcnic_ctx.c526
-rw-r--r--drivers/net/qlcnic/qlcnic_ethtool.c42
-rw-r--r--drivers/net/qlcnic/qlcnic_hdr.h78
-rw-r--r--drivers/net/qlcnic/qlcnic_hw.c62
-rw-r--r--drivers/net/qlcnic/qlcnic_init.c136
-rw-r--r--drivers/net/qlcnic/qlcnic_main.c1139
-rw-r--r--drivers/net/qlge/qlge.h30
-rw-r--r--drivers/net/qlge/qlge_dbg.c814
-rw-r--r--drivers/net/qlge/qlge_main.c47
-rw-r--r--drivers/net/qlge/qlge_mpi.c17
-rw-r--r--drivers/net/r6040.c302
-rw-r--r--drivers/net/r8169.c18
-rw-r--r--drivers/net/s2io-regs.h2
-rw-r--r--drivers/net/s2io.c83
-rw-r--r--drivers/net/s2io.h2
-rw-r--r--drivers/net/sb1250-mac.c2
-rw-r--r--drivers/net/sfc/efx.c304
-rw-r--r--drivers/net/sfc/efx.h9
-rw-r--r--drivers/net/sfc/ethtool.c167
-rw-r--r--drivers/net/sfc/falcon.c200
-rw-r--r--drivers/net/sfc/falcon_boards.c35
-rw-r--r--drivers/net/sfc/falcon_xmac.c5
-rw-r--r--drivers/net/sfc/io.h37
-rw-r--r--drivers/net/sfc/mcdi.c98
-rw-r--r--drivers/net/sfc/mcdi_mac.c8
-rw-r--r--drivers/net/sfc/mcdi_phy.c41
-rw-r--r--drivers/net/sfc/mdio_10g.c39
-rw-r--r--drivers/net/sfc/mdio_10g.h3
-rw-r--r--drivers/net/sfc/mtd.c23
-rw-r--r--drivers/net/sfc/net_driver.h88
-rw-r--r--drivers/net/sfc/nic.c553
-rw-r--r--drivers/net/sfc/nic.h9
-rw-r--r--drivers/net/sfc/qt202x_phy.c42
-rw-r--r--drivers/net/sfc/rx.c469
-rw-r--r--drivers/net/sfc/selftest.c154
-rw-r--r--drivers/net/sfc/siena.c68
-rw-r--r--drivers/net/sfc/tenxpress.c12
-rw-r--r--drivers/net/sfc/tx.c41
-rw-r--r--drivers/net/sfc/workarounds.h2
-rw-r--r--drivers/net/sh_eth.c57
-rw-r--r--drivers/net/sky2.c40
-rw-r--r--drivers/net/sky2.h6
-rw-r--r--drivers/net/smc91x.h37
-rw-r--r--drivers/net/smsc911x.c94
-rw-r--r--drivers/net/smsc9420.c2
-rw-r--r--drivers/net/starfire.c47
-rw-r--r--drivers/net/stmmac/common.h1
-rw-r--r--drivers/net/stmmac/dwmac1000.h2
-rw-r--r--drivers/net/stmmac/dwmac1000_core.c2
-rw-r--r--drivers/net/stmmac/dwmac100_core.c2
-rw-r--r--drivers/net/stmmac/enh_desc.c2
-rw-r--r--drivers/net/stmmac/stmmac_main.c37
-rw-r--r--drivers/net/sun3_82586.c35
-rw-r--r--drivers/net/sunbmac.c6
-rw-r--r--drivers/net/sunhme.c10
-rw-r--r--drivers/net/sunlance.c6
-rw-r--r--drivers/net/sunqe.c10
-rw-r--r--drivers/net/tc35815.c2
-rw-r--r--drivers/net/tehuti.h2
-rw-r--r--drivers/net/tg3.c799
-rw-r--r--drivers/net/tg3.h98
-rw-r--r--drivers/net/tulip/de2104x.c4
-rw-r--r--drivers/net/tulip/dmfe.c20
-rw-r--r--drivers/net/tulip/eeprom.c10
-rw-r--r--drivers/net/tulip/tulip.h64
-rw-r--r--drivers/net/tulip/tulip_core.c132
-rw-r--r--drivers/net/tulip/winbond-840.c4
-rw-r--r--drivers/net/tun.c10
-rw-r--r--drivers/net/typhoon.c2
-rw-r--r--drivers/net/typhoon.h26
-rw-r--r--drivers/net/ucc_geth.c16
-rw-r--r--drivers/net/ucc_geth.h46
-rw-r--r--drivers/net/usb/asix.c2
-rw-r--r--drivers/net/usb/cdc-phonet.c8
-rw-r--r--drivers/net/usb/hso.c8
-rw-r--r--drivers/net/usb/ipheth.c13
-rw-r--r--drivers/net/usb/kaweth.c2
-rw-r--r--drivers/net/usb/net1080.c4
-rw-r--r--drivers/net/usb/pegasus.c125
-rw-r--r--drivers/net/usb/pegasus.h296
-rw-r--r--drivers/net/usb/sierra_net.c2
-rw-r--r--drivers/net/usb/usbnet.c17
-rw-r--r--drivers/net/via-velocity.h12
-rw-r--r--drivers/net/vmxnet3/vmxnet3_defs.h6
-rw-r--r--drivers/net/vmxnet3/vmxnet3_drv.c46
-rw-r--r--drivers/net/vmxnet3/vmxnet3_ethtool.c18
-rw-r--r--drivers/net/vmxnet3/vmxnet3_int.h4
-rw-r--r--drivers/net/vxge/Makefile2
-rw-r--r--drivers/net/vxge/vxge-config.c4
-rw-r--r--drivers/net/vxge/vxge-config.h4
-rw-r--r--drivers/net/vxge/vxge-ethtool.c4
-rw-r--r--drivers/net/vxge/vxge-ethtool.h4
-rw-r--r--drivers/net/vxge/vxge-main.c599
-rw-r--r--drivers/net/vxge/vxge-main.h27
-rw-r--r--drivers/net/vxge/vxge-reg.h4
-rw-r--r--drivers/net/vxge/vxge-traffic.c8
-rw-r--r--drivers/net/vxge/vxge-traffic.h4
-rw-r--r--drivers/net/vxge/vxge-version.h9
-rw-r--r--drivers/net/wan/cosa.c10
-rw-r--r--drivers/net/wan/farsync.c125
-rw-r--r--drivers/net/wan/hd64570.h2
-rw-r--r--drivers/net/wan/hdlc_cisco.c4
-rw-r--r--drivers/net/wan/hdlc_fr.c2
-rw-r--r--drivers/net/wan/sdla.c13
-rw-r--r--drivers/net/wd.c4
-rw-r--r--drivers/net/wimax/i2400m/control.c4
-rw-r--r--drivers/net/wimax/i2400m/fw.c8
-rw-r--r--drivers/net/wimax/i2400m/op-rfkill.c2
-rw-r--r--drivers/net/wireless/adm8211.c58
-rw-r--r--drivers/net/wireless/adm8211.h6
-rw-r--r--drivers/net/wireless/airo.c56
-rw-r--r--drivers/net/wireless/airo_cs.c74
-rw-r--r--drivers/net/wireless/at76c50x-usb.c270
-rw-r--r--drivers/net/wireless/at76c50x-usb.h41
-rw-r--r--drivers/net/wireless/ath/ar9170/cmd.c7
-rw-r--r--drivers/net/wireless/ath/ar9170/led.c4
-rw-r--r--drivers/net/wireless/ath/ar9170/main.c191
-rw-r--r--drivers/net/wireless/ath/ar9170/phy.c8
-rw-r--r--drivers/net/wireless/ath/ath5k/Makefile1
-rw-r--r--drivers/net/wireless/ath/ath5k/ani.c20
-rw-r--r--drivers/net/wireless/ath/ath5k/ath5k.h19
-rw-r--r--drivers/net/wireless/ath/ath5k/attach.c2
-rw-r--r--drivers/net/wireless/ath/ath5k/base.c438
-rw-r--r--drivers/net/wireless/ath/ath5k/base.h4
-rw-r--r--drivers/net/wireless/ath/ath5k/caps.c7
-rw-r--r--drivers/net/wireless/ath/ath5k/debug.c99
-rw-r--r--drivers/net/wireless/ath/ath5k/debug.h9
-rw-r--r--drivers/net/wireless/ath/ath5k/desc.c152
-rw-r--r--drivers/net/wireless/ath/ath5k/desc.h310
-rw-r--r--drivers/net/wireless/ath/ath5k/dma.c13
-rw-r--r--drivers/net/wireless/ath/ath5k/eeprom.c3
-rw-r--r--drivers/net/wireless/ath/ath5k/gpio.c7
-rw-r--r--drivers/net/wireless/ath/ath5k/pcu.c24
-rw-r--r--drivers/net/wireless/ath/ath5k/phy.c82
-rw-r--r--drivers/net/wireless/ath/ath5k/qcu.c9
-rw-r--r--drivers/net/wireless/ath/ath5k/reset.c64
-rw-r--r--drivers/net/wireless/ath/ath5k/sysfs.c116
-rw-r--r--drivers/net/wireless/ath/ath9k/Makefile3
-rw-r--r--drivers/net/wireless/ath/ath9k/ahb.c7
-rw-r--r--drivers/net/wireless/ath/ath9k/ani.c743
-rw-r--r--drivers/net/wireless/ath/ath9k/ani.h78
-rw-r--r--drivers/net/wireless/ath/ath9k/ar5008_initvals.h1319
-rw-r--r--drivers/net/wireless/ath/ath9k/ar5008_phy.c492
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9001_initvals.h2479
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9002_calib.c2
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9002_hw.c196
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9002_initvals.h8251
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9002_mac.c1
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9002_phy.c71
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9002_phy.h33
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9003_2p0_initvals.h (renamed from drivers/net/wireless/ath/ath9k/ar9003_initvals.h)254
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h1785
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9003_calib.c10
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9003_eeprom.c15
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9003_eeprom.h4
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9003_hw.c185
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9003_mac.c44
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9003_mac.h8
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9003_paprd.c714
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9003_phy.c699
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9003_phy.h298
-rw-r--r--drivers/net/wireless/ath/ath9k/ath9k.h92
-rw-r--r--drivers/net/wireless/ath/ath9k/beacon.c3
-rw-r--r--drivers/net/wireless/ath/ath9k/calib.c138
-rw-r--r--drivers/net/wireless/ath/ath9k/calib.h7
-rw-r--r--drivers/net/wireless/ath/ath9k/common.c318
-rw-r--r--drivers/net/wireless/ath/ath9k/common.h77
-rw-r--r--drivers/net/wireless/ath/ath9k/debug.c68
-rw-r--r--drivers/net/wireless/ath/ath9k/debug.h2
-rw-r--r--drivers/net/wireless/ath/ath9k/eeprom.c29
-rw-r--r--drivers/net/wireless/ath/ath9k/eeprom.h7
-rw-r--r--drivers/net/wireless/ath/ath9k/eeprom_4k.c12
-rw-r--r--drivers/net/wireless/ath/ath9k/eeprom_9287.c616
-rw-r--r--drivers/net/wireless/ath/ath9k/eeprom_def.c14
-rw-r--r--drivers/net/wireless/ath/ath9k/gpio.c9
-rw-r--r--drivers/net/wireless/ath/ath9k/hif_usb.c71
-rw-r--r--drivers/net/wireless/ath/ath9k/hif_usb.h2
-rw-r--r--drivers/net/wireless/ath/ath9k/htc.h38
-rw-r--r--drivers/net/wireless/ath/ath9k/htc_drv_beacon.c23
-rw-r--r--drivers/net/wireless/ath/ath9k/htc_drv_init.c163
-rw-r--r--drivers/net/wireless/ath/ath9k/htc_drv_main.c512
-rw-r--r--drivers/net/wireless/ath/ath9k/htc_drv_txrx.c86
-rw-r--r--drivers/net/wireless/ath/ath9k/htc_hst.c3
-rw-r--r--drivers/net/wireless/ath/ath9k/hw-ops.h22
-rw-r--r--drivers/net/wireless/ath/ath9k/hw.c314
-rw-r--r--drivers/net/wireless/ath/ath9k/hw.h123
-rw-r--r--drivers/net/wireless/ath/ath9k/init.c61
-rw-r--r--drivers/net/wireless/ath/ath9k/mac.c14
-rw-r--r--drivers/net/wireless/ath/ath9k/mac.h16
-rw-r--r--drivers/net/wireless/ath/ath9k/main.c475
-rw-r--r--drivers/net/wireless/ath/ath9k/pci.c8
-rw-r--r--drivers/net/wireless/ath/ath9k/rc.c633
-rw-r--r--drivers/net/wireless/ath/ath9k/rc.h89
-rw-r--r--drivers/net/wireless/ath/ath9k/recv.c292
-rw-r--r--drivers/net/wireless/ath/ath9k/reg.h90
-rw-r--r--drivers/net/wireless/ath/ath9k/virtual.c8
-rw-r--r--drivers/net/wireless/ath/ath9k/wmi.c3
-rw-r--r--drivers/net/wireless/ath/ath9k/xmit.c251
-rw-r--r--drivers/net/wireless/atmel_cs.c25
-rw-r--r--drivers/net/wireless/b43/b43.h6
-rw-r--r--drivers/net/wireless/b43/dma.c69
-rw-r--r--drivers/net/wireless/b43/dma.h8
-rw-r--r--drivers/net/wireless/b43/main.c4
-rw-r--r--drivers/net/wireless/b43/pcmcia.c13
-rw-r--r--drivers/net/wireless/b43/phy_g.c2
-rw-r--r--drivers/net/wireless/b43/phy_lp.c8
-rw-r--r--drivers/net/wireless/b43/phy_n.c16
-rw-r--r--drivers/net/wireless/b43/sdio.c1
-rw-r--r--drivers/net/wireless/b43/wa.c8
-rw-r--r--drivers/net/wireless/b43/xmit.h20
-rw-r--r--drivers/net/wireless/b43legacy/b43legacy.h6
-rw-r--r--drivers/net/wireless/b43legacy/dma.c49
-rw-r--r--drivers/net/wireless/b43legacy/dma.h8
-rw-r--r--drivers/net/wireless/b43legacy/xmit.h10
-rw-r--r--drivers/net/wireless/hostap/hostap_80211.h18
-rw-r--r--drivers/net/wireless/hostap/hostap_ap.c5
-rw-r--r--drivers/net/wireless/hostap/hostap_common.h10
-rw-r--r--drivers/net/wireless/hostap/hostap_cs.c136
-rw-r--r--drivers/net/wireless/hostap/hostap_hw.c2
-rw-r--r--drivers/net/wireless/hostap/hostap_main.c4
-rw-r--r--drivers/net/wireless/hostap/hostap_wlan.h32
-rw-r--r--drivers/net/wireless/ipw2x00/ipw2100.c34
-rw-r--r--drivers/net/wireless/ipw2x00/ipw2100.h16
-rw-r--r--drivers/net/wireless/ipw2x00/ipw2200.c7
-rw-r--r--drivers/net/wireless/ipw2x00/ipw2200.h122
-rw-r--r--drivers/net/wireless/ipw2x00/libipw.h63
-rw-r--r--drivers/net/wireless/ipw2x00/libipw_module.c4
-rw-r--r--drivers/net/wireless/ipw2x00/libipw_tx.c16
-rw-r--r--drivers/net/wireless/ipw2x00/libipw_wx.c6
-rw-r--r--drivers/net/wireless/iwlwifi/Kconfig15
-rw-r--r--drivers/net/wireless/iwlwifi/Makefile4
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-1000.c12
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-3945-debugfs.c28
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-3945-fh.h4
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-3945-hw.h10
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-3945.c208
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-4965-hw.h2
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-4965.c98
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-5000.c80
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-6000.c538
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-calib.c (renamed from drivers/net/wireless/iwlwifi/iwl-calib.c)223
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-debugfs.c239
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-debugfs.h7
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-hcmd.c32
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-hw.h2
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-lib.c320
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-rs.c20
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-rx.c351
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-tx.c89
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-ucode.c123
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn.c594
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn.h48
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-calib.h6
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-commands.h422
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-core.c395
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-core.h44
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-csr.h1
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-debugfs.c144
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-dev.h123
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-eeprom.c3
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-eeprom.h17
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-fh.h13
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-hcmd.c1
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-helpers.h27
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-rx.c246
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-scan.c67
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-spectrum.h10
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-sta.c164
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-sta.h32
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-tx.c33
-rw-r--r--drivers/net/wireless/iwlwifi/iwl3945-base.c160
-rw-r--r--drivers/net/wireless/iwmc3200wifi/cfg80211.c12
-rw-r--r--drivers/net/wireless/iwmc3200wifi/commands.h50
-rw-r--r--drivers/net/wireless/iwmc3200wifi/hal.c2
-rw-r--r--drivers/net/wireless/iwmc3200wifi/iwm.h2
-rw-r--r--drivers/net/wireless/iwmc3200wifi/lmac.h32
-rw-r--r--drivers/net/wireless/iwmc3200wifi/rx.c4
-rw-r--r--drivers/net/wireless/iwmc3200wifi/umac.h60
-rw-r--r--drivers/net/wireless/libertas/Makefile3
-rw-r--r--drivers/net/wireless/libertas/README12
-rw-r--r--drivers/net/wireless/libertas/assoc.c2264
-rw-r--r--drivers/net/wireless/libertas/assoc.h155
-rw-r--r--drivers/net/wireless/libertas/cfg.c1861
-rw-r--r--drivers/net/wireless/libertas/cfg.h15
-rw-r--r--drivers/net/wireless/libertas/cmd.c767
-rw-r--r--drivers/net/wireless/libertas/cmd.h27
-rw-r--r--drivers/net/wireless/libertas/cmdresp.c190
-rw-r--r--drivers/net/wireless/libertas/debugfs.c191
-rw-r--r--drivers/net/wireless/libertas/decl.h7
-rw-r--r--drivers/net/wireless/libertas/defs.h18
-rw-r--r--drivers/net/wireless/libertas/dev.h68
-rw-r--r--drivers/net/wireless/libertas/ethtool.c29
-rw-r--r--drivers/net/wireless/libertas/host.h250
-rw-r--r--drivers/net/wireless/libertas/if_cs.c16
-rw-r--r--drivers/net/wireless/libertas/if_sdio.c58
-rw-r--r--drivers/net/wireless/libertas/if_usb.c16
-rw-r--r--drivers/net/wireless/libertas/main.c326
-rw-r--r--drivers/net/wireless/libertas/mesh.c222
-rw-r--r--drivers/net/wireless/libertas/mesh.h19
-rw-r--r--drivers/net/wireless/libertas/radiotap.h4
-rw-r--r--drivers/net/wireless/libertas/rx.c129
-rw-r--r--drivers/net/wireless/libertas/scan.c1354
-rw-r--r--drivers/net/wireless/libertas/scan.h63
-rw-r--r--drivers/net/wireless/libertas/tx.c12
-rw-r--r--drivers/net/wireless/libertas/types.h66
-rw-r--r--drivers/net/wireless/libertas/wext.c2353
-rw-r--r--drivers/net/wireless/libertas/wext.h17
-rw-r--r--drivers/net/wireless/libertas_tf/if_usb.c5
-rw-r--r--drivers/net/wireless/libertas_tf/libertas_tf.h7
-rw-r--r--drivers/net/wireless/libertas_tf/main.c18
-rw-r--r--drivers/net/wireless/mac80211_hwsim.c106
-rw-r--r--drivers/net/wireless/mwl8k.c254
-rw-r--r--drivers/net/wireless/orinoco/cfg.c5
-rw-r--r--drivers/net/wireless/orinoco/fw.c2
-rw-r--r--drivers/net/wireless/orinoco/hermes.h18
-rw-r--r--drivers/net/wireless/orinoco/hermes_dld.c10
-rw-r--r--drivers/net/wireless/orinoco/hw.c6
-rw-r--r--drivers/net/wireless/orinoco/main.c10
-rw-r--r--drivers/net/wireless/orinoco/orinoco.h2
-rw-r--r--drivers/net/wireless/orinoco/orinoco_cs.c30
-rw-r--r--drivers/net/wireless/orinoco/orinoco_usb.c18
-rw-r--r--drivers/net/wireless/orinoco/spectrum_cs.c62
-rw-r--r--drivers/net/wireless/orinoco/wext.c6
-rw-r--r--drivers/net/wireless/p54/eeprom.c80
-rw-r--r--drivers/net/wireless/p54/fwio.c53
-rw-r--r--drivers/net/wireless/p54/led.c8
-rw-r--r--drivers/net/wireless/p54/main.c17
-rw-r--r--drivers/net/wireless/p54/net2280.h16
-rw-r--r--drivers/net/wireless/p54/p54pci.c3
-rw-r--r--drivers/net/wireless/p54/p54pci.h6
-rw-r--r--drivers/net/wireless/p54/p54spi.c5
-rw-r--r--drivers/net/wireless/p54/p54spi.h2
-rw-r--r--drivers/net/wireless/p54/p54usb.c6
-rw-r--r--drivers/net/wireless/p54/p54usb.h6
-rw-r--r--drivers/net/wireless/p54/txrx.c36
-rw-r--r--drivers/net/wireless/prism54/isl_ioctl.c15
-rw-r--r--drivers/net/wireless/prism54/isl_oid.h18
-rw-r--r--drivers/net/wireless/prism54/islpci_eth.h4
-rw-r--r--drivers/net/wireless/prism54/islpci_mgt.h2
-rw-r--r--drivers/net/wireless/ray_cs.c50
-rw-r--r--drivers/net/wireless/rndis_wlan.c90
-rw-r--r--drivers/net/wireless/rt2x00/rt2400pci.c85
-rw-r--r--drivers/net/wireless/rt2x00/rt2500pci.c87
-rw-r--r--drivers/net/wireless/rt2x00/rt2500usb.c63
-rw-r--r--drivers/net/wireless/rt2x00/rt2800.h93
-rw-r--r--drivers/net/wireless/rt2x00/rt2800lib.c734
-rw-r--r--drivers/net/wireless/rt2x00/rt2800lib.h54
-rw-r--r--drivers/net/wireless/rt2x00/rt2800pci.c366
-rw-r--r--drivers/net/wireless/rt2x00/rt2800pci.h19
-rw-r--r--drivers/net/wireless/rt2x00/rt2800usb.c293
-rw-r--r--drivers/net/wireless/rt2x00/rt2800usb.h37
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00.h69
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00config.c16
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00debug.c1
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00dev.c139
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00dump.h9
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00ht.c47
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00lib.h52
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00link.c73
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00mac.c75
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00pci.c39
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00pci.h10
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00queue.c90
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00queue.h20
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00reg.h5
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00usb.c118
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00usb.h39
-rw-r--r--drivers/net/wireless/rt2x00/rt61pci.c130
-rw-r--r--drivers/net/wireless/rt2x00/rt61pci.h4
-rw-r--r--drivers/net/wireless/rt2x00/rt73usb.c59
-rw-r--r--drivers/net/wireless/rt2x00/rt73usb.h4
-rw-r--r--drivers/net/wireless/rtl818x/rtl8180.h4
-rw-r--r--drivers/net/wireless/rtl818x/rtl8180_dev.c34
-rw-r--r--drivers/net/wireless/rtl818x/rtl8180_grf5101.c12
-rw-r--r--drivers/net/wireless/rtl818x/rtl8180_max2820.c19
-rw-r--r--drivers/net/wireless/rtl818x/rtl8180_rtl8225.c5
-rw-r--r--drivers/net/wireless/rtl818x/rtl8180_sa2400.c28
-rw-r--r--drivers/net/wireless/rtl818x/rtl8187.h8
-rw-r--r--drivers/net/wireless/rtl818x/rtl8187_dev.c11
-rw-r--r--drivers/net/wireless/rtl818x/rtl8187_rtl8225.c8
-rw-r--r--drivers/net/wireless/rtl818x/rtl818x.h3
-rw-r--r--drivers/net/wireless/wl12xx/Kconfig4
-rw-r--r--drivers/net/wireless/wl12xx/Makefile2
-rw-r--r--drivers/net/wireless/wl12xx/wl1251.h3
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_acx.h102
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_boot.c8
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_cmd.h34
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_event.h4
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_main.c27
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_rx.c6
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_rx.h2
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_sdio.c40
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_spi.c1
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_tx.c10
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_tx.h14
-rw-r--r--drivers/net/wireless/wl12xx/wl1271.h58
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_acx.c41
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_acx.h117
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_boot.c4
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_cmd.c275
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_cmd.h124
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_conf.h16
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_event.c99
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_event.h5
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_ini.h123
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_main.c289
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_rx.c11
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_rx.h2
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_scan.c257
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_scan.h109
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_sdio.c2
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_spi.c1
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_testmode.c11
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_tx.c36
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_tx.h7
-rw-r--r--drivers/net/wireless/wl12xx/wl12xx_80211.h26
-rw-r--r--drivers/net/wireless/wl3501.h16
-rw-r--r--drivers/net/wireless/wl3501_cs.c24
-rw-r--r--drivers/net/wireless/zd1211rw/zd_mac.c5
-rw-r--r--drivers/net/wireless/zd1211rw/zd_mac.h15
-rw-r--r--drivers/net/wireless/zd1211rw/zd_usb.c2
-rw-r--r--drivers/net/wireless/zd1211rw/zd_usb.h14
-rw-r--r--drivers/net/xen-netfront.c1
-rw-r--r--drivers/net/xilinx_emaclite.c2
-rw-r--r--drivers/net/xtsonic.c12
-rw-r--r--drivers/of/Kconfig40
-rw-r--r--drivers/of/Makefile2
-rw-r--r--drivers/of/address.c595
-rw-r--r--drivers/of/base.c76
-rw-r--r--drivers/of/device.c91
-rw-r--r--drivers/of/fdt.c26
-rw-r--r--drivers/of/gpio.c93
-rw-r--r--drivers/of/irq.c349
-rw-r--r--drivers/of/of_i2c.c50
-rw-r--r--drivers/of/of_mdio.c1
-rw-r--r--drivers/of/of_spi.c11
-rw-r--r--drivers/of/platform.c384
-rw-r--r--drivers/oprofile/event_buffer.c3
-rw-r--r--drivers/parisc/ccio-dma.c4
-rw-r--r--drivers/parisc/led.c3
-rw-r--r--drivers/parport/parport_cs.c23
-rw-r--r--drivers/parport/parport_sunbpp.c6
-rw-r--r--drivers/pci/Makefile3
-rw-r--r--drivers/pci/bus.c4
-rw-r--r--drivers/pci/hotplug/fakephp.c2
-rw-r--r--drivers/pci/hotplug/pciehp_pci.c2
-rw-r--r--drivers/pci/hotplug/shpchp_hpc.c2
-rw-r--r--drivers/pci/hotplug/shpchp_pci.c19
-rw-r--r--drivers/pci/intel-iommu.c2
-rw-r--r--drivers/pci/intr_remapping.c8
-rw-r--r--drivers/pci/msi.c29
-rw-r--r--drivers/pci/pci-acpi.c7
-rw-r--r--drivers/pci/pci-driver.c32
-rw-r--r--drivers/pci/pci-label.c143
-rw-r--r--drivers/pci/pci-sysfs.c75
-rw-r--r--drivers/pci/pci.c24
-rw-r--r--drivers/pci/pci.h10
-rw-r--r--drivers/pci/pcie/Kconfig20
-rw-r--r--drivers/pci/pcie/aer/aerdrv_core.c17
-rw-r--r--drivers/pci/pcie/aspm.c16
-rw-r--r--drivers/pci/pcie/pme/pcie_pme.c5
-rw-r--r--drivers/pci/probe.c10
-rw-r--r--drivers/pci/proc.c6
-rw-r--r--drivers/pci/quirks.c48
-rw-r--r--drivers/pci/search.c2
-rw-r--r--drivers/pci/setup-bus.c12
-rw-r--r--drivers/pci/setup-irq.c3
-rw-r--r--drivers/pcmcia/Kconfig4
-rw-r--r--drivers/pcmcia/Makefile1
-rw-r--r--drivers/pcmcia/au1000_generic.h1
-rw-r--r--drivers/pcmcia/au1000_pb1x00.c2
-rw-r--r--drivers/pcmcia/cistpl.c11
-rw-r--r--drivers/pcmcia/cs.c79
-rw-r--r--drivers/pcmcia/cs_internal.h62
-rw-r--r--drivers/pcmcia/db1xxx_ss.c1
-rw-r--r--drivers/pcmcia/ds.c184
-rw-r--r--drivers/pcmcia/i82092.c1
-rw-r--r--drivers/pcmcia/i82365.c1
-rw-r--r--drivers/pcmcia/m32r_cfc.c1
-rw-r--r--drivers/pcmcia/m32r_pcc.c1
-rw-r--r--drivers/pcmcia/m8xx_pcmcia.c1
-rw-r--r--drivers/pcmcia/pcmcia_cis.c1
-rw-r--r--drivers/pcmcia/pcmcia_ioctl.c1077
-rw-r--r--drivers/pcmcia/pcmcia_resource.c331
-rw-r--r--drivers/pcmcia/pd6729.c1
-rw-r--r--drivers/pcmcia/pxa2xx_base.c1
-rw-r--r--drivers/pcmcia/rsrc_iodyn.c8
-rw-r--r--drivers/pcmcia/rsrc_mgr.c6
-rw-r--r--drivers/pcmcia/rsrc_nonstatic.c15
-rw-r--r--drivers/pcmcia/sa1100_generic.c1
-rw-r--r--drivers/pcmcia/sa11xx_base.c2
-rw-r--r--drivers/pcmcia/soc_common.h1
-rw-r--r--drivers/pcmcia/socket_sysfs.c1
-rw-r--r--drivers/pcmcia/tcic.c1
-rw-r--r--drivers/pcmcia/xxs1500_ss.c1
-rw-r--r--drivers/pcmcia/yenta_socket.c1
-rw-r--r--drivers/platform/x86/Kconfig44
-rw-r--r--drivers/platform/x86/Makefile4
-rw-r--r--drivers/platform/x86/acer-wmi.c79
-rw-r--r--drivers/platform/x86/acerhdf.c151
-rw-r--r--drivers/platform/x86/asus-laptop.c29
-rw-r--r--drivers/platform/x86/asus_acpi.c7
-rw-r--r--drivers/platform/x86/classmate-laptop.c13
-rw-r--r--drivers/platform/x86/compal-laptop.c929
-rw-r--r--drivers/platform/x86/dell-laptop.c9
-rw-r--r--drivers/platform/x86/dell-wmi.c11
-rw-r--r--drivers/platform/x86/eeepc-laptop.c2
-rw-r--r--drivers/platform/x86/fujitsu-laptop.c16
-rw-r--r--drivers/platform/x86/hp-wmi.c281
-rw-r--r--drivers/platform/x86/intel_ips.c1660
-rw-r--r--drivers/platform/x86/intel_menlow.c33
-rw-r--r--drivers/platform/x86/intel_pmic_gpio.c340
-rw-r--r--drivers/platform/x86/intel_rar_register.c (renamed from drivers/staging/rar_register/rar_register.c)8
-rw-r--r--drivers/platform/x86/intel_scu_ipc.c180
-rw-r--r--drivers/platform/x86/msi-laptop.c8
-rw-r--r--drivers/platform/x86/msi-wmi.c2
-rw-r--r--drivers/platform/x86/panasonic-laptop.c7
-rw-r--r--drivers/platform/x86/sony-laptop.c13
-rw-r--r--drivers/platform/x86/thinkpad_acpi.c73
-rw-r--r--drivers/platform/x86/toshiba_acpi.c135
-rw-r--r--drivers/platform/x86/wmi.c28
-rw-r--r--drivers/pnp/core.c3
-rw-r--r--drivers/pnp/pnpacpi/core.c23
-rw-r--r--drivers/power/Kconfig11
-rw-r--r--drivers/power/Makefile1
-rw-r--r--drivers/power/jz4740-battery.c445
-rw-r--r--drivers/rapidio/rio.c2
-rw-r--r--drivers/regulator/core.c1
-rw-r--r--drivers/rtc/Kconfig13
-rw-r--r--drivers/rtc/Makefile1
-rw-r--r--drivers/rtc/rtc-fm3130.c2
-rw-r--r--drivers/rtc/rtc-jz4740.c345
-rw-r--r--drivers/rtc/rtc-rx8025.c2
-rw-r--r--drivers/s390/cio/qdio_setup.c2
-rw-r--r--drivers/s390/net/claw.c2
-rw-r--r--drivers/s390/net/qeth_core.h27
-rw-r--r--drivers/s390/net/qeth_core_main.c423
-rw-r--r--drivers/s390/net/qeth_core_mpc.h5
-rw-r--r--drivers/s390/net/qeth_core_sys.c5
-rw-r--r--drivers/s390/net/qeth_l2_main.c108
-rw-r--r--drivers/s390/net/qeth_l3.h1
-rw-r--r--drivers/s390/net/qeth_l3_main.c262
-rw-r--r--drivers/s390/net/qeth_l3_sys.c14
-rw-r--r--drivers/s390/net/smsgiucv.c11
-rw-r--r--drivers/s390/scsi/zfcp_aux.c10
-rw-r--r--drivers/s390/scsi/zfcp_cfdc.c12
-rw-r--r--drivers/s390/scsi/zfcp_dbf.c5
-rw-r--r--drivers/s390/scsi/zfcp_dbf.h1
-rw-r--r--drivers/s390/scsi/zfcp_def.h5
-rw-r--r--drivers/s390/scsi/zfcp_erp.c24
-rw-r--r--drivers/s390/scsi/zfcp_ext.h11
-rw-r--r--drivers/s390/scsi/zfcp_fc.c54
-rw-r--r--drivers/s390/scsi/zfcp_fc.h27
-rw-r--r--drivers/s390/scsi/zfcp_fsf.c169
-rw-r--r--drivers/s390/scsi/zfcp_fsf.h34
-rw-r--r--drivers/s390/scsi/zfcp_qdio.c206
-rw-r--r--drivers/s390/scsi/zfcp_qdio.h95
-rw-r--r--drivers/s390/scsi/zfcp_scsi.c103
-rw-r--r--drivers/s390/scsi/zfcp_sysfs.c12
-rw-r--r--drivers/sbus/char/bbc_i2c.c10
-rw-r--r--drivers/sbus/char/display7seg.c12
-rw-r--r--drivers/sbus/char/envctrl.c6
-rw-r--r--drivers/sbus/char/flash.c19
-rw-r--r--drivers/sbus/char/openprom.c15
-rw-r--r--drivers/sbus/char/uctrl.c13
-rw-r--r--drivers/scsi/Kconfig4
-rw-r--r--drivers/scsi/Makefile1
-rw-r--r--drivers/scsi/aacraid/linit.c14
-rw-r--r--drivers/scsi/advansys.c2
-rw-r--r--drivers/scsi/aic7xxx/aic7770.c12
-rw-r--r--drivers/scsi/aic7xxx/aic7770_osm.c2
-rw-r--r--drivers/scsi/aic7xxx/aic79xx_core.c624
-rw-r--r--drivers/scsi/aic7xxx/aic79xx_osm.c108
-rw-r--r--drivers/scsi/aic7xxx/aic79xx_osm.h7
-rw-r--r--drivers/scsi/aic7xxx/aic79xx_osm_pci.c8
-rw-r--r--drivers/scsi/aic7xxx/aic79xx_pci.c56
-rw-r--r--drivers/scsi/aic7xxx/aic79xx_proc.c13
-rw-r--r--drivers/scsi/aic7xxx/aic7xxx_93cx6.c10
-rw-r--r--drivers/scsi/aic7xxx/aic7xxx_core.c430
-rw-r--r--drivers/scsi/aic7xxx/aic7xxx_osm.c76
-rw-r--r--drivers/scsi/aic7xxx/aic7xxx_osm.h7
-rw-r--r--drivers/scsi/aic7xxx/aic7xxx_osm_pci.c8
-rw-r--r--drivers/scsi/aic7xxx/aic7xxx_pci.c74
-rw-r--r--drivers/scsi/aic7xxx/aic7xxx_proc.c15
-rw-r--r--drivers/scsi/aic7xxx_old/aic7xxx.seq2
-rw-r--r--drivers/scsi/aic94xx/aic94xx_seq.c4
-rw-r--r--drivers/scsi/aic94xx/aic94xx_task.c2
-rw-r--r--drivers/scsi/arcmsr/arcmsr.h315
-rw-r--r--drivers/scsi/arcmsr/arcmsr_attr.c3
-rw-r--r--drivers/scsi/arcmsr/arcmsr_hba.c2309
-rw-r--r--drivers/scsi/be2iscsi/Kconfig2
-rw-r--r--drivers/scsi/be2iscsi/be.h6
-rw-r--r--drivers/scsi/be2iscsi/be_cmds.c116
-rw-r--r--drivers/scsi/be2iscsi/be_cmds.h27
-rw-r--r--drivers/scsi/be2iscsi/be_iscsi.c199
-rw-r--r--drivers/scsi/be2iscsi/be_iscsi.h2
-rw-r--r--drivers/scsi/be2iscsi/be_main.c333
-rw-r--r--drivers/scsi/be2iscsi/be_main.h29
-rw-r--r--drivers/scsi/be2iscsi/be_mgmt.c64
-rw-r--r--drivers/scsi/be2iscsi/be_mgmt.h19
-rw-r--r--drivers/scsi/bfa/Makefile2
-rw-r--r--drivers/scsi/bfa/bfa_cb_ioim_macros.h7
-rw-r--r--drivers/scsi/bfa/bfa_core.c3
-rw-r--r--drivers/scsi/bfa/bfa_fcpim.c29
-rw-r--r--drivers/scsi/bfa/bfa_fcpim_priv.h6
-rw-r--r--drivers/scsi/bfa/bfa_fcport.c139
-rw-r--r--drivers/scsi/bfa/bfa_fcs.c20
-rw-r--r--drivers/scsi/bfa/bfa_fcs_lport.c3
-rw-r--r--drivers/scsi/bfa/bfa_fcxp.c14
-rw-r--r--drivers/scsi/bfa/bfa_fwimg_priv.h25
-rw-r--r--drivers/scsi/bfa/bfa_hw_cb.c7
-rw-r--r--drivers/scsi/bfa/bfa_hw_ct.c7
-rw-r--r--drivers/scsi/bfa/bfa_intr.c1
-rw-r--r--drivers/scsi/bfa/bfa_ioc.c172
-rw-r--r--drivers/scsi/bfa/bfa_ioc.h12
-rw-r--r--drivers/scsi/bfa/bfa_ioc_cb.c36
-rw-r--r--drivers/scsi/bfa/bfa_ioc_ct.c71
-rw-r--r--drivers/scsi/bfa/bfa_iocfc.c107
-rw-r--r--drivers/scsi/bfa/bfa_iocfc.h19
-rw-r--r--drivers/scsi/bfa/bfa_ioim.c65
-rw-r--r--drivers/scsi/bfa/bfa_log_module.c86
-rw-r--r--drivers/scsi/bfa/bfa_lps.c6
-rw-r--r--drivers/scsi/bfa/bfa_port.c31
-rw-r--r--drivers/scsi/bfa/bfa_port_priv.h7
-rw-r--r--drivers/scsi/bfa/bfa_priv.h3
-rw-r--r--drivers/scsi/bfa/bfa_rport.c5
-rw-r--r--drivers/scsi/bfa/bfa_sgpg.c5
-rw-r--r--drivers/scsi/bfa/bfa_uf.c10
-rw-r--r--drivers/scsi/bfa/bfad.c114
-rw-r--r--drivers/scsi/bfa/bfad_attr.c46
-rw-r--r--drivers/scsi/bfa/bfad_debugfs.c547
-rw-r--r--drivers/scsi/bfa/bfad_drv.h36
-rw-r--r--drivers/scsi/bfa/bfad_fwimg.c76
-rw-r--r--drivers/scsi/bfa/bfad_im.c33
-rw-r--r--drivers/scsi/bfa/bfad_im_compat.h13
-rw-r--r--drivers/scsi/bfa/bfad_intr.c8
-rw-r--r--drivers/scsi/bfa/fabric.c44
-rw-r--r--drivers/scsi/bfa/fcpim.c32
-rw-r--r--drivers/scsi/bfa/fcs_fabric.h5
-rw-r--r--drivers/scsi/bfa/fcs_rport.h3
-rw-r--r--drivers/scsi/bfa/fcs_vport.h1
-rw-r--r--drivers/scsi/bfa/fdmi.c6
-rw-r--r--drivers/scsi/bfa/include/aen/bfa_aen_ioc.h8
-rw-r--r--drivers/scsi/bfa/include/bfa.h4
-rw-r--r--drivers/scsi/bfa/include/bfa_fcpim.h20
-rw-r--r--drivers/scsi/bfa/include/bfa_svc.h1
-rw-r--r--drivers/scsi/bfa/include/bfi/bfi_ctreg.h3
-rw-r--r--drivers/scsi/bfa/include/bfi/bfi_ioc.h20
-rw-r--r--drivers/scsi/bfa/include/bfi/bfi_iocfc.h2
-rw-r--r--drivers/scsi/bfa/include/bfi/bfi_pbc.h62
-rw-r--r--drivers/scsi/bfa/include/cna/port/bfa_port.h1
-rw-r--r--drivers/scsi/bfa/include/cs/bfa_debug.h3
-rw-r--r--drivers/scsi/bfa/include/defs/bfa_defs_adapter.h3
-rw-r--r--drivers/scsi/bfa/include/defs/bfa_defs_auth.h6
-rw-r--r--drivers/scsi/bfa/include/defs/bfa_defs_boot.h10
-rw-r--r--drivers/scsi/bfa/include/defs/bfa_defs_driver.h2
-rw-r--r--drivers/scsi/bfa/include/defs/bfa_defs_fcport.h26
-rw-r--r--drivers/scsi/bfa/include/defs/bfa_defs_ioc.h7
-rw-r--r--drivers/scsi/bfa/include/defs/bfa_defs_iocfc.h12
-rw-r--r--drivers/scsi/bfa/include/defs/bfa_defs_itnim.h10
-rw-r--r--drivers/scsi/bfa/include/defs/bfa_defs_mfg.h41
-rw-r--r--drivers/scsi/bfa/include/defs/bfa_defs_pci.h11
-rw-r--r--drivers/scsi/bfa/include/defs/bfa_defs_port.h14
-rw-r--r--drivers/scsi/bfa/include/defs/bfa_defs_pport.h29
-rw-r--r--drivers/scsi/bfa/include/defs/bfa_defs_status.h46
-rw-r--r--drivers/scsi/bfa/include/fcb/bfa_fcb_vport.h3
-rw-r--r--drivers/scsi/bfa/include/fcs/bfa_fcs.h4
-rw-r--r--drivers/scsi/bfa/include/fcs/bfa_fcs_fcpim.h1
-rw-r--r--drivers/scsi/bfa/include/fcs/bfa_fcs_rport.h1
-rw-r--r--drivers/scsi/bfa/include/fcs/bfa_fcs_vport.h4
-rw-r--r--drivers/scsi/bfa/include/log/bfa_log_linux.h6
-rw-r--r--drivers/scsi/bfa/include/protocol/fc.h1
-rw-r--r--drivers/scsi/bfa/lport_api.c30
-rw-r--r--drivers/scsi/bfa/ms.c9
-rw-r--r--drivers/scsi/bfa/ns.c14
-rw-r--r--drivers/scsi/bfa/rport.c88
-rw-r--r--drivers/scsi/bfa/rport_api.c11
-rw-r--r--drivers/scsi/bfa/rport_ftrs.c14
-rw-r--r--drivers/scsi/bfa/scn.c2
-rw-r--r--drivers/scsi/bfa/vport.c56
-rw-r--r--drivers/scsi/bnx2i/bnx2i.h14
-rw-r--r--drivers/scsi/bnx2i/bnx2i_hwi.c4
-rw-r--r--drivers/scsi/bnx2i/bnx2i_init.c37
-rw-r--r--drivers/scsi/bnx2i/bnx2i_iscsi.c236
-rw-r--r--drivers/scsi/cxgb3i/cxgb3i_ddp.c2
-rw-r--r--drivers/scsi/cxgb3i/cxgb3i_offload.c9
-rw-r--r--drivers/scsi/device_handler/scsi_dh_rdac.c1
-rw-r--r--drivers/scsi/dpt_i2o.c26
-rw-r--r--drivers/scsi/fcoe/fcoe.c154
-rw-r--r--drivers/scsi/fcoe/libfcoe.c1519
-rw-r--r--drivers/scsi/fnic/fnic_main.c11
-rw-r--r--drivers/scsi/fnic/fnic_scsi.c22
-rw-r--r--drivers/scsi/hosts.c14
-rw-r--r--drivers/scsi/hpsa.c754
-rw-r--r--drivers/scsi/hpsa.h1
-rw-r--r--drivers/scsi/hpsa_cmd.h4
-rw-r--r--drivers/scsi/hptiop.c2
-rw-r--r--drivers/scsi/ibmvscsi/ibmvfc.c85
-rw-r--r--drivers/scsi/ibmvscsi/ibmvfc.h6
-rw-r--r--drivers/scsi/ibmvscsi/ibmvscsi.c157
-rw-r--r--drivers/scsi/ibmvscsi/ibmvscsi.h4
-rw-r--r--drivers/scsi/ibmvscsi/ibmvstgt.c4
-rw-r--r--drivers/scsi/ibmvscsi/rpa_vscsi.c16
-rw-r--r--drivers/scsi/ipr.c148
-rw-r--r--drivers/scsi/ipr.h30
-rw-r--r--drivers/scsi/libfc/fc_disc.c39
-rw-r--r--drivers/scsi/libfc/fc_elsct.c2
-rw-r--r--drivers/scsi/libfc/fc_exch.c219
-rw-r--r--drivers/scsi/libfc/fc_fcp.c15
-rw-r--r--drivers/scsi/libfc/fc_libfc.c78
-rw-r--r--drivers/scsi/libfc/fc_libfc.h2
-rw-r--r--drivers/scsi/libfc/fc_lport.c216
-rw-r--r--drivers/scsi/libfc/fc_rport.c709
-rw-r--r--drivers/scsi/libsas/sas_ata.c12
-rw-r--r--drivers/scsi/libsas/sas_expander.c2
-rw-r--r--drivers/scsi/libsas/sas_scsi_host.c4
-rw-r--r--drivers/scsi/libsas/sas_task.c6
-rw-r--r--drivers/scsi/lpfc/lpfc.h17
-rw-r--r--drivers/scsi/lpfc/lpfc_attr.c97
-rw-r--r--drivers/scsi/lpfc/lpfc_bsg.c36
-rw-r--r--drivers/scsi/lpfc/lpfc_crtn.h11
-rw-r--r--drivers/scsi/lpfc/lpfc_disc.h2
-rw-r--r--drivers/scsi/lpfc/lpfc_els.c112
-rw-r--r--drivers/scsi/lpfc/lpfc_hbadisc.c220
-rw-r--r--drivers/scsi/lpfc/lpfc_hw.h17
-rw-r--r--drivers/scsi/lpfc/lpfc_init.c279
-rw-r--r--drivers/scsi/lpfc/lpfc_mbox.c23
-rw-r--r--drivers/scsi/lpfc/lpfc_nportdisc.c31
-rw-r--r--drivers/scsi/lpfc/lpfc_scsi.c86
-rw-r--r--drivers/scsi/lpfc/lpfc_sli.c345
-rw-r--r--drivers/scsi/lpfc/lpfc_sli.h2
-rw-r--r--drivers/scsi/lpfc/lpfc_sli4.h8
-rw-r--r--drivers/scsi/lpfc/lpfc_version.h2
-rw-r--r--drivers/scsi/lpfc/lpfc_vport.c2
-rw-r--r--drivers/scsi/mpt2sas/mpi/mpi2.h17
-rw-r--r--drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h193
-rw-r--r--drivers/scsi/mpt2sas/mpi/mpi2_init.h17
-rw-r--r--drivers/scsi/mpt2sas/mpi/mpi2_ioc.h119
-rw-r--r--drivers/scsi/mpt2sas/mpt2sas_base.c172
-rw-r--r--drivers/scsi/mpt2sas/mpt2sas_base.h36
-rw-r--r--drivers/scsi/mpt2sas/mpt2sas_config.c6
-rw-r--r--drivers/scsi/mpt2sas/mpt2sas_ctl.c411
-rw-r--r--drivers/scsi/mpt2sas/mpt2sas_scsih.c748
-rw-r--r--drivers/scsi/mpt2sas/mpt2sas_transport.c575
-rw-r--r--drivers/scsi/mvsas/mv_sas.c20
-rw-r--r--drivers/scsi/pcmcia/aha152x_stub.c17
-rw-r--r--drivers/scsi/pcmcia/fdomain_stub.c15
-rw-r--r--drivers/scsi/pcmcia/nsp_cs.c61
-rw-r--r--drivers/scsi/pcmcia/qlogic_stub.c33
-rw-r--r--drivers/scsi/pcmcia/sym53c500_cs.c31
-rw-r--r--drivers/scsi/pm8001/pm8001_hwi.c18
-rw-r--r--drivers/scsi/pm8001/pm8001_sas.c4
-rw-r--r--drivers/scsi/pmcraid.c893
-rw-r--r--drivers/scsi/pmcraid.h305
-rw-r--r--drivers/scsi/qla2xxx/qla_attr.c33
-rw-r--r--drivers/scsi/qla2xxx/qla_bsg.c294
-rw-r--r--drivers/scsi/qla2xxx/qla_bsg.h9
-rw-r--r--drivers/scsi/qla2xxx/qla_dbg.c2
-rw-r--r--drivers/scsi/qla2xxx/qla_dbg.h2
-rw-r--r--drivers/scsi/qla2xxx/qla_def.h54
-rw-r--r--drivers/scsi/qla2xxx/qla_dfs.c2
-rw-r--r--drivers/scsi/qla2xxx/qla_fw.h2
-rw-r--r--drivers/scsi/qla2xxx/qla_gbl.h29
-rw-r--r--drivers/scsi/qla2xxx/qla_gs.c74
-rw-r--r--drivers/scsi/qla2xxx/qla_init.c178
-rw-r--r--drivers/scsi/qla2xxx/qla_inline.h2
-rw-r--r--drivers/scsi/qla2xxx/qla_iocb.c259
-rw-r--r--drivers/scsi/qla2xxx/qla_isr.c206
-rw-r--r--drivers/scsi/qla2xxx/qla_mbx.c158
-rw-r--r--drivers/scsi/qla2xxx/qla_mid.c61
-rw-r--r--drivers/scsi/qla2xxx/qla_nx.c550
-rw-r--r--drivers/scsi/qla2xxx/qla_nx.h45
-rw-r--r--drivers/scsi/qla2xxx/qla_os.c109
-rw-r--r--drivers/scsi/qla2xxx/qla_settings.h2
-rw-r--r--drivers/scsi/qla2xxx/qla_sup.c49
-rw-r--r--drivers/scsi/qla2xxx/qla_version.h8
-rw-r--r--drivers/scsi/qla4xxx/Kconfig8
-rw-r--r--drivers/scsi/qla4xxx/Makefile2
-rw-r--r--drivers/scsi/qla4xxx/ql4_def.h143
-rw-r--r--drivers/scsi/qla4xxx/ql4_fw.h139
-rw-r--r--drivers/scsi/qla4xxx/ql4_glbl.h106
-rw-r--r--drivers/scsi/qla4xxx/ql4_init.c242
-rw-r--r--drivers/scsi/qla4xxx/ql4_inline.h2
-rw-r--r--drivers/scsi/qla4xxx/ql4_iocb.c73
-rw-r--r--drivers/scsi/qla4xxx/ql4_isr.c396
-rw-r--r--drivers/scsi/qla4xxx/ql4_mbx.c191
-rw-r--r--drivers/scsi/qla4xxx/ql4_nvram.c2
-rw-r--r--drivers/scsi/qla4xxx/ql4_nvram.h10
-rw-r--r--drivers/scsi/qla4xxx/ql4_nx.c2321
-rw-r--r--drivers/scsi/qla4xxx/ql4_nx.h779
-rw-r--r--drivers/scsi/qla4xxx/ql4_os.c758
-rw-r--r--drivers/scsi/qla4xxx/ql4_version.h2
-rw-r--r--drivers/scsi/qlogicpti.c8
-rw-r--r--drivers/scsi/scsi_debug.c6
-rw-r--r--drivers/scsi/scsi_error.c29
-rw-r--r--drivers/scsi/scsi_pm.c206
-rw-r--r--drivers/scsi/scsi_priv.h17
-rw-r--r--drivers/scsi/scsi_scan.c24
-rw-r--r--drivers/scsi/scsi_sysfs.c70
-rw-r--r--drivers/scsi/scsi_transport_fc.c2
-rw-r--r--drivers/scsi/scsi_transport_iscsi.c81
-rw-r--r--drivers/scsi/sd.c21
-rw-r--r--drivers/scsi/sg.c12
-rw-r--r--drivers/scsi/sun_esp.c6
-rw-r--r--drivers/serial/68360serial.c6
-rw-r--r--drivers/serial/8250.c13
-rw-r--r--drivers/serial/Kconfig8
-rw-r--r--drivers/serial/cpm_uart/cpm_uart_core.c2
-rw-r--r--drivers/serial/kgdboc.c18
-rw-r--r--drivers/serial/mpc52xx_uart.c145
-rw-r--r--drivers/serial/nwpserial.c2
-rw-r--r--drivers/serial/serial_cs.c68
-rw-r--r--drivers/serial/sn_console.c6
-rw-r--r--drivers/serial/sunhv.c8
-rw-r--r--drivers/serial/sunsab.c6
-rw-r--r--drivers/serial/sunsu.c4
-rw-r--r--drivers/serial/sunzilog.c16
-rw-r--r--drivers/serial/uartlite.c1
-rw-r--r--drivers/spi/mpc512x_psc_spi.c2
-rw-r--r--drivers/spi/mpc52xx_psc_spi.c11
-rw-r--r--drivers/spi/mpc52xx_spi.c3
-rw-r--r--drivers/spi/spi.c4
-rw-r--r--drivers/spi/spi_mpc8xxx.c4
-rw-r--r--drivers/spi/spi_ppc4xx.c2
-rw-r--r--drivers/spi/xilinx_spi.c3
-rw-r--r--drivers/spi/xilinx_spi_of.c4
-rw-r--r--drivers/ssb/driver_chipcommon.c25
-rw-r--r--drivers/ssb/driver_chipcommon_pmu.c17
-rw-r--r--drivers/ssb/main.c77
-rw-r--r--drivers/ssb/pci.c15
-rw-r--r--drivers/ssb/pcmcia.c15
-rw-r--r--drivers/ssb/scan.c1
-rw-r--r--drivers/staging/Kconfig18
-rw-r--r--drivers/staging/Makefile10
-rw-r--r--drivers/staging/adis16255/adis16255.c4
-rw-r--r--drivers/staging/batman-adv/CHANGELOG12
-rw-r--r--drivers/staging/batman-adv/Kconfig2
-rw-r--r--drivers/staging/batman-adv/Makefile4
-rw-r--r--drivers/staging/batman-adv/README2
-rw-r--r--drivers/staging/batman-adv/TODO9
-rw-r--r--drivers/staging/batman-adv/aggregation.c9
-rw-r--r--drivers/staging/batman-adv/aggregation.h5
-rw-r--r--drivers/staging/batman-adv/bat_debugfs.c341
-rw-r--r--drivers/staging/batman-adv/bat_debugfs.h33
-rw-r--r--drivers/staging/batman-adv/bat_sysfs.c300
-rw-r--r--drivers/staging/batman-adv/bat_sysfs.h13
-rw-r--r--drivers/staging/batman-adv/bitarray.c17
-rw-r--r--drivers/staging/batman-adv/bitarray.h13
-rw-r--r--drivers/staging/batman-adv/device.c354
-rw-r--r--drivers/staging/batman-adv/hard-interface.c76
-rw-r--r--drivers/staging/batman-adv/hard-interface.h5
-rw-r--r--drivers/staging/batman-adv/hash.c2
-rw-r--r--drivers/staging/batman-adv/hash.h12
-rw-r--r--drivers/staging/batman-adv/icmp_socket.c334
-rw-r--r--drivers/staging/batman-adv/icmp_socket.h (renamed from drivers/staging/batman-adv/device.h)24
-rw-r--r--drivers/staging/batman-adv/main.c62
-rw-r--r--drivers/staging/batman-adv/main.h82
-rw-r--r--drivers/staging/batman-adv/originator.c156
-rw-r--r--drivers/staging/batman-adv/originator.h10
-rw-r--r--drivers/staging/batman-adv/packet.h32
-rw-r--r--drivers/staging/batman-adv/ring_buffer.h5
-rw-r--r--drivers/staging/batman-adv/routing.c406
-rw-r--r--drivers/staging/batman-adv/routing.h13
-rw-r--r--drivers/staging/batman-adv/send.c81
-rw-r--r--drivers/staging/batman-adv/send.h7
-rw-r--r--drivers/staging/batman-adv/soft-interface.c165
-rw-r--r--drivers/staging/batman-adv/soft-interface.h13
-rw-r--r--drivers/staging/batman-adv/sysfs-class-net-batman-adv14
-rw-r--r--drivers/staging/batman-adv/sysfs-class-net-mesh33
-rw-r--r--drivers/staging/batman-adv/translation-table.c171
-rw-r--r--drivers/staging/batman-adv/translation-table.h14
-rw-r--r--drivers/staging/batman-adv/types.h43
-rw-r--r--drivers/staging/batman-adv/vis.c147
-rw-r--r--drivers/staging/batman-adv/vis.h13
-rw-r--r--drivers/staging/comedi/TODO1
-rw-r--r--drivers/staging/comedi/comedi_fops.c11
-rw-r--r--drivers/staging/comedi/comedidev.h58
-rw-r--r--drivers/staging/comedi/drivers/8255.c17
-rw-r--r--drivers/staging/comedi/drivers/acl7225b.c17
-rw-r--r--drivers/staging/comedi/drivers/addi-data/addi_amcc_s5933.h6
-rw-r--r--drivers/staging/comedi/drivers/addi-data/addi_common.c38
-rw-r--r--drivers/staging/comedi/drivers/addi-data/addi_eeprom.c12
-rw-r--r--drivers/staging/comedi/drivers/addi-data/hwdrv_apci3120.c8
-rw-r--r--drivers/staging/comedi/drivers/addi_apci_035.c4
-rw-r--r--drivers/staging/comedi/drivers/addi_apci_1032.c4
-rw-r--r--drivers/staging/comedi/drivers/addi_apci_1500.c4
-rw-r--r--drivers/staging/comedi/drivers/addi_apci_1516.c4
-rw-r--r--drivers/staging/comedi/drivers/addi_apci_1564.c4
-rw-r--r--drivers/staging/comedi/drivers/addi_apci_16xx.c4
-rw-r--r--drivers/staging/comedi/drivers/addi_apci_2016.c4
-rw-r--r--drivers/staging/comedi/drivers/addi_apci_2032.c4
-rw-r--r--drivers/staging/comedi/drivers/addi_apci_2200.c4
-rw-r--r--drivers/staging/comedi/drivers/addi_apci_3001.c4
-rw-r--r--drivers/staging/comedi/drivers/addi_apci_3120.c4
-rw-r--r--drivers/staging/comedi/drivers/addi_apci_3501.c4
-rw-r--r--drivers/staging/comedi/drivers/addi_apci_3xxx.c4
-rw-r--r--drivers/staging/comedi/drivers/adl_pci6208.c48
-rw-r--r--drivers/staging/comedi/drivers/adl_pci7230.c51
-rw-r--r--drivers/staging/comedi/drivers/adl_pci7296.c51
-rw-r--r--drivers/staging/comedi/drivers/adl_pci7432.c51
-rw-r--r--drivers/staging/comedi/drivers/adl_pci8164.c51
-rw-r--r--drivers/staging/comedi/drivers/adl_pci9111.c213
-rw-r--r--drivers/staging/comedi/drivers/adl_pci9118.c42
-rw-r--r--drivers/staging/comedi/drivers/adq12b.c17
-rw-r--r--drivers/staging/comedi/drivers/adv_pci1710.c89
-rw-r--r--drivers/staging/comedi/drivers/adv_pci1723.c42
-rw-r--r--drivers/staging/comedi/drivers/adv_pci_dio.c355
-rw-r--r--drivers/staging/comedi/drivers/aio_aio12_8.c17
-rw-r--r--drivers/staging/comedi/drivers/aio_iiro_16.c17
-rw-r--r--drivers/staging/comedi/drivers/am9513.h22
-rw-r--r--drivers/staging/comedi/drivers/amplc_dio200.c57
-rw-r--r--drivers/staging/comedi/drivers/amplc_pc236.c57
-rw-r--r--drivers/staging/comedi/drivers/amplc_pc263.c57
-rw-r--r--drivers/staging/comedi/drivers/amplc_pci224.c44
-rw-r--r--drivers/staging/comedi/drivers/amplc_pci230.c50
-rw-r--r--drivers/staging/comedi/drivers/c6xdigio.c17
-rw-r--r--drivers/staging/comedi/drivers/cb_das16_cs.c63
-rw-r--r--drivers/staging/comedi/drivers/cb_pcidas.c48
-rw-r--r--drivers/staging/comedi/drivers/cb_pcidas64.c48
-rw-r--r--drivers/staging/comedi/drivers/cb_pcidda.c48
-rw-r--r--drivers/staging/comedi/drivers/cb_pcidio.c46
-rw-r--r--drivers/staging/comedi/drivers/cb_pcimdas.c50
-rw-r--r--drivers/staging/comedi/drivers/cb_pcimdda.c46
-rw-r--r--drivers/staging/comedi/drivers/comedi_bond.c37
-rw-r--r--drivers/staging/comedi/drivers/comedi_parport.c17
-rw-r--r--drivers/staging/comedi/drivers/comedi_test.c17
-rw-r--r--drivers/staging/comedi/drivers/contec_pci_dio.c49
-rw-r--r--drivers/staging/comedi/drivers/daqboard2000.c44
-rw-r--r--drivers/staging/comedi/drivers/das08.c71
-rw-r--r--drivers/staging/comedi/drivers/das08_cs.c49
-rw-r--r--drivers/staging/comedi/drivers/das16.c17
-rw-r--r--drivers/staging/comedi/drivers/das16m1.c17
-rw-r--r--drivers/staging/comedi/drivers/das1800.c17
-rw-r--r--drivers/staging/comedi/drivers/das6402.c17
-rw-r--r--drivers/staging/comedi/drivers/das800.c17
-rw-r--r--drivers/staging/comedi/drivers/dmm32at.c99
-rw-r--r--drivers/staging/comedi/drivers/dt2801.c17
-rw-r--r--drivers/staging/comedi/drivers/dt2811.c17
-rw-r--r--drivers/staging/comedi/drivers/dt2814.c17
-rw-r--r--drivers/staging/comedi/drivers/dt2815.c17
-rw-r--r--drivers/staging/comedi/drivers/dt2817.c17
-rw-r--r--drivers/staging/comedi/drivers/dt282x.c17
-rw-r--r--drivers/staging/comedi/drivers/dt3000.c42
-rw-r--r--drivers/staging/comedi/drivers/dt9812.c6
-rw-r--r--drivers/staging/comedi/drivers/fl512.c17
-rw-r--r--drivers/staging/comedi/drivers/gsc_hpdi.c72
-rw-r--r--drivers/staging/comedi/drivers/icp_multi.c17
-rw-r--r--drivers/staging/comedi/drivers/icp_multi.h6
-rw-r--r--drivers/staging/comedi/drivers/ii_pci20kc.c17
-rw-r--r--drivers/staging/comedi/drivers/jr3_pci.c69
-rw-r--r--drivers/staging/comedi/drivers/ke_counter.c48
-rw-r--r--drivers/staging/comedi/drivers/me4000.c464
-rw-r--r--drivers/staging/comedi/drivers/me_daq.c48
-rw-r--r--drivers/staging/comedi/drivers/mite.c10
-rw-r--r--drivers/staging/comedi/drivers/mpc624.c17
-rw-r--r--drivers/staging/comedi/drivers/mpc8260cpm.c13
-rw-r--r--drivers/staging/comedi/drivers/multiq3.c17
-rw-r--r--drivers/staging/comedi/drivers/ni_6527.c38
-rw-r--r--drivers/staging/comedi/drivers/ni_65xx.c38
-rw-r--r--drivers/staging/comedi/drivers/ni_660x.c40
-rw-r--r--drivers/staging/comedi/drivers/ni_670x.c38
-rw-r--r--drivers/staging/comedi/drivers/ni_at_a2150.c17
-rw-r--r--drivers/staging/comedi/drivers/ni_at_ao.c17
-rw-r--r--drivers/staging/comedi/drivers/ni_atmio.c13
-rw-r--r--drivers/staging/comedi/drivers/ni_atmio16d.c17
-rw-r--r--drivers/staging/comedi/drivers/ni_daq_700.c75
-rw-r--r--drivers/staging/comedi/drivers/ni_daq_dio24.c76
-rw-r--r--drivers/staging/comedi/drivers/ni_labpc.c121
-rw-r--r--drivers/staging/comedi/drivers/ni_labpc_cs.c73
-rw-r--r--drivers/staging/comedi/drivers/ni_mio_cs.c19
-rw-r--r--drivers/staging/comedi/drivers/ni_pcidio.c38
-rw-r--r--drivers/staging/comedi/drivers/ni_pcimio.c38
-rw-r--r--drivers/staging/comedi/drivers/ni_tio.c54
-rw-r--r--drivers/staging/comedi/drivers/pcl711.c31
-rw-r--r--drivers/staging/comedi/drivers/pcl724.c17
-rw-r--r--drivers/staging/comedi/drivers/pcl725.c17
-rw-r--r--drivers/staging/comedi/drivers/pcl726.c17
-rw-r--r--drivers/staging/comedi/drivers/pcl730.c17
-rw-r--r--drivers/staging/comedi/drivers/pcl812.c493
-rw-r--r--drivers/staging/comedi/drivers/pcl816.c240
-rw-r--r--drivers/staging/comedi/drivers/pcl818.c17
-rw-r--r--drivers/staging/comedi/drivers/pcm3724.c19
-rw-r--r--drivers/staging/comedi/drivers/pcm3730.c17
-rw-r--r--drivers/staging/comedi/drivers/pcm_common.c4
-rw-r--r--drivers/staging/comedi/drivers/pcmad.c17
-rw-r--r--drivers/staging/comedi/drivers/pcmda12.c29
-rw-r--r--drivers/staging/comedi/drivers/pcmmio.c34
-rw-r--r--drivers/staging/comedi/drivers/pcmuio.c17
-rw-r--r--drivers/staging/comedi/drivers/poc.c17
-rw-r--r--drivers/staging/comedi/drivers/quatech_daqp_cs.c103
-rw-r--r--drivers/staging/comedi/drivers/rtd520.c42
-rw-r--r--drivers/staging/comedi/drivers/rti800.c17
-rw-r--r--drivers/staging/comedi/drivers/rti802.c17
-rw-r--r--drivers/staging/comedi/drivers/s526.c17
-rw-r--r--drivers/staging/comedi/drivers/s626.c163
-rw-r--r--drivers/staging/comedi/drivers/s626.h9
-rw-r--r--drivers/staging/comedi/drivers/serial2002.c115
-rw-r--r--drivers/staging/comedi/drivers/skel.c109
-rw-r--r--drivers/staging/comedi/drivers/ssv_dnp.c17
-rw-r--r--drivers/staging/comedi/drivers/unioxx5.c26
-rw-r--r--drivers/staging/comedi/drivers/usbdux.c4
-rw-r--r--drivers/staging/comedi/drivers/usbduxfast.c2
-rw-r--r--drivers/staging/comedi/kcomedilib/kcomedilib_main.c4
-rw-r--r--drivers/staging/crystalhd/crystalhd_lnx.c22
-rw-r--r--drivers/staging/cx25821/Makefile11
-rw-r--r--drivers/staging/cx25821/cx25821-alsa.c37
-rw-r--r--drivers/staging/cx25821/cx25821-audio-upstream.c38
-rw-r--r--drivers/staging/cx25821/cx25821-audio.h13
-rw-r--r--drivers/staging/cx25821/cx25821-audups11.c420
-rw-r--r--drivers/staging/cx25821/cx25821-core.c86
-rw-r--r--drivers/staging/cx25821/cx25821-i2c.c3
-rw-r--r--drivers/staging/cx25821/cx25821-medusa-defines.h15
-rw-r--r--drivers/staging/cx25821/cx25821-medusa-reg.h32
-rw-r--r--drivers/staging/cx25821/cx25821-medusa-video.c18
-rw-r--r--drivers/staging/cx25821/cx25821-medusa-video.h4
-rw-r--r--drivers/staging/cx25821/cx25821-reg.h1826
-rw-r--r--drivers/staging/cx25821/cx25821-sram.h50
-rw-r--r--drivers/staging/cx25821/cx25821-video-upstream-ch2.c91
-rw-r--r--drivers/staging/cx25821/cx25821-video-upstream-ch2.h2
-rw-r--r--drivers/staging/cx25821/cx25821-video-upstream.c72
-rw-r--r--drivers/staging/cx25821/cx25821-video-upstream.h2
-rw-r--r--drivers/staging/cx25821/cx25821-video.c905
-rw-r--r--drivers/staging/cx25821/cx25821-video.h20
-rw-r--r--drivers/staging/cx25821/cx25821-video0.c434
-rw-r--r--drivers/staging/cx25821/cx25821-video1.c434
-rw-r--r--drivers/staging/cx25821/cx25821-video2.c436
-rw-r--r--drivers/staging/cx25821/cx25821-video3.c435
-rw-r--r--drivers/staging/cx25821/cx25821-video4.c434
-rw-r--r--drivers/staging/cx25821/cx25821-video5.c434
-rw-r--r--drivers/staging/cx25821/cx25821-video6.c434
-rw-r--r--drivers/staging/cx25821/cx25821-video7.c433
-rw-r--r--drivers/staging/cx25821/cx25821-videoioctl.c480
-rw-r--r--drivers/staging/cx25821/cx25821-vidups10.c418
-rw-r--r--drivers/staging/cx25821/cx25821-vidups9.c416
-rw-r--r--drivers/staging/cx25821/cx25821.h49
-rw-r--r--drivers/staging/cxt1e1/functions.c12
-rw-r--r--drivers/staging/cxt1e1/hwprobe.c6
-rw-r--r--drivers/staging/cxt1e1/linux.c163
-rw-r--r--drivers/staging/cxt1e1/musycc.c204
-rw-r--r--drivers/staging/cxt1e1/pmc93x6_eeprom.c4
-rw-r--r--drivers/staging/cxt1e1/pmcc4.h4
-rw-r--r--drivers/staging/cxt1e1/pmcc4_drv.c158
-rw-r--r--drivers/staging/cxt1e1/sbecom_inline_linux.h11
-rw-r--r--drivers/staging/dream/camera/msm_vfe8x.c45
-rw-r--r--drivers/staging/dream/pmem.c46
-rw-r--r--drivers/staging/dt3155/Kconfig4
-rw-r--r--drivers/staging/dt3155/Makefile6
-rw-r--r--drivers/staging/dt3155/TODO10
-rw-r--r--drivers/staging/dt3155/allocator.README98
-rw-r--r--drivers/staging/dt3155/allocator.c294
-rw-r--r--drivers/staging/dt3155/allocator.h28
-rw-r--r--drivers/staging/dt3155/dt3155.h161
-rw-r--r--drivers/staging/dt3155/dt3155.sysvinit60
-rw-r--r--drivers/staging/dt3155/dt3155_drv.c1099
-rw-r--r--drivers/staging/dt3155/dt3155_drv.h45
-rw-r--r--drivers/staging/dt3155/dt3155_io.c165
-rw-r--r--drivers/staging/dt3155/dt3155_io.h358
-rw-r--r--drivers/staging/dt3155/dt3155_isr.c509
-rw-r--r--drivers/staging/dt3155/dt3155_isr.h77
-rw-r--r--drivers/staging/dt3155v4l/dt3155v4l.c31
-rw-r--r--drivers/staging/easycap/Kconfig17
-rw-r--r--drivers/staging/easycap/Makefile13
-rw-r--r--drivers/staging/easycap/README130
-rw-r--r--drivers/staging/easycap/easycap.h642
-rw-r--r--drivers/staging/easycap/easycap_debug.h27
-rw-r--r--drivers/staging/easycap/easycap_ioctl.c2687
-rw-r--r--drivers/staging/easycap/easycap_ioctl.h28
-rw-r--r--drivers/staging/easycap/easycap_low.c1041
-rw-r--r--drivers/staging/easycap/easycap_main.c4354
-rw-r--r--drivers/staging/easycap/easycap_settings.c489
-rw-r--r--drivers/staging/easycap/easycap_sound.c1046
-rw-r--r--drivers/staging/easycap/easycap_sound.h28
-rw-r--r--drivers/staging/easycap/easycap_standard.h27
-rw-r--r--drivers/staging/easycap/easycap_testcard.c392
-rw-r--r--drivers/staging/et131x/et1310_phy.c8
-rw-r--r--drivers/staging/hv/Kconfig2
-rw-r--r--drivers/staging/hv/Makefile2
-rw-r--r--drivers/staging/hv/blkvsc.c12
-rw-r--r--drivers/staging/hv/blkvsc_drv.c26
-rw-r--r--drivers/staging/hv/channel.c54
-rw-r--r--drivers/staging/hv/channel_mgmt.c43
-rw-r--r--drivers/staging/hv/channel_mgmt.h8
-rw-r--r--drivers/staging/hv/connection.c23
-rw-r--r--drivers/staging/hv/hv.c29
-rw-r--r--drivers/staging/hv/hv_timesource.c101
-rw-r--r--drivers/staging/hv/hv_utils.c12
-rw-r--r--drivers/staging/hv/logging.h17
-rw-r--r--drivers/staging/hv/netvsc.c65
-rw-r--r--drivers/staging/hv/netvsc_drv.c51
-rw-r--r--drivers/staging/hv/ring_buffer.c71
-rw-r--r--drivers/staging/hv/ring_buffer.h35
-rw-r--r--drivers/staging/hv/rndis_filter.c86
-rw-r--r--drivers/staging/hv/storvsc.c36
-rw-r--r--drivers/staging/hv/storvsc_drv.c49
-rw-r--r--drivers/staging/hv/vmbus.c18
-rw-r--r--drivers/staging/hv/vmbus_drv.c99
-rw-r--r--drivers/staging/iio/Documentation/overview.txt2
-rw-r--r--drivers/staging/iio/Kconfig2
-rw-r--r--drivers/staging/iio/Makefile4
-rw-r--r--drivers/staging/iio/TODO2
-rw-r--r--drivers/staging/iio/accel/Kconfig50
-rw-r--r--drivers/staging/iio/accel/Makefile3
-rw-r--r--drivers/staging/iio/accel/adis16209.h33
-rw-r--r--drivers/staging/iio/accel/adis16209_core.c15
-rw-r--r--drivers/staging/iio/accel/adis16209_ring.c94
-rw-r--r--drivers/staging/iio/accel/adis16209_trigger.c10
-rw-r--r--drivers/staging/iio/accel/adis16220.h1
-rw-r--r--drivers/staging/iio/accel/adis16220_core.c20
-rw-r--r--drivers/staging/iio/accel/adis16240.h27
-rw-r--r--drivers/staging/iio/accel/adis16240_core.c17
-rw-r--r--drivers/staging/iio/accel/adis16240_ring.c91
-rw-r--r--drivers/staging/iio/accel/adis16240_trigger.c10
-rw-r--r--drivers/staging/iio/accel/kxsd9.c6
-rw-r--r--drivers/staging/iio/accel/lis3l02dq.h35
-rw-r--r--drivers/staging/iio/accel/lis3l02dq_core.c144
-rw-r--r--drivers/staging/iio/accel/lis3l02dq_ring.c210
-rw-r--r--drivers/staging/iio/accel/sca3000.h14
-rw-r--r--drivers/staging/iio/accel/sca3000_core.c14
-rw-r--r--drivers/staging/iio/adc/Makefile2
-rw-r--r--drivers/staging/iio/adc/adc.h3
-rw-r--r--drivers/staging/iio/adc/max1363.h69
-rw-r--r--drivers/staging/iio/adc/max1363_core.c861
-rw-r--r--drivers/staging/iio/adc/max1363_ring.c60
-rw-r--r--drivers/staging/iio/chrdev.h3
-rw-r--r--drivers/staging/iio/gyro/Makefile2
-rw-r--r--drivers/staging/iio/gyro/adis16260.h25
-rw-r--r--drivers/staging/iio/gyro/adis16260_core.c12
-rw-r--r--drivers/staging/iio/gyro/adis16260_ring.c92
-rw-r--r--drivers/staging/iio/gyro/adis16260_trigger.c10
-rw-r--r--drivers/staging/iio/iio.h51
-rw-r--r--drivers/staging/iio/imu/Kconfig18
-rw-r--r--drivers/staging/iio/imu/Makefile3
-rw-r--r--drivers/staging/iio/imu/adis16300.h28
-rw-r--r--drivers/staging/iio/imu/adis16300_core.c160
-rw-r--r--drivers/staging/iio/imu/adis16300_ring.c142
-rw-r--r--drivers/staging/iio/imu/adis16300_trigger.c10
-rw-r--r--drivers/staging/iio/imu/adis16350.h40
-rw-r--r--drivers/staging/iio/imu/adis16350_core.c17
-rw-r--r--drivers/staging/iio/imu/adis16350_ring.c91
-rw-r--r--drivers/staging/iio/imu/adis16350_trigger.c10
-rw-r--r--drivers/staging/iio/imu/adis16400.h45
-rw-r--r--drivers/staging/iio/imu/adis16400_core.c101
-rw-r--r--drivers/staging/iio/imu/adis16400_ring.c137
-rw-r--r--drivers/staging/iio/imu/adis16400_trigger.c10
-rw-r--r--drivers/staging/iio/industrialio-core.c22
-rw-r--r--drivers/staging/iio/industrialio-ring.c4
-rw-r--r--drivers/staging/iio/industrialio-trigger.c51
-rw-r--r--drivers/staging/iio/light/Kconfig1
-rw-r--r--drivers/staging/iio/light/light.h7
-rw-r--r--drivers/staging/iio/light/tsl2563.c389
-rw-r--r--drivers/staging/iio/magnetometer/Kconfig15
-rw-r--r--drivers/staging/iio/magnetometer/Makefile5
-rw-r--r--drivers/staging/iio/magnetometer/hmc5843.c624
-rw-r--r--drivers/staging/iio/ring_generic.h23
-rw-r--r--drivers/staging/iio/ring_sw.c69
-rw-r--r--drivers/staging/iio/ring_sw.h15
-rw-r--r--drivers/staging/iio/sysfs.h14
-rw-r--r--drivers/staging/iio/trigger.h24
-rw-r--r--drivers/staging/iio/trigger/Makefile3
-rw-r--r--drivers/staging/iio/trigger/iio-trig-gpio.c12
-rw-r--r--drivers/staging/iio/trigger/iio-trig-periodic-rtc.c15
-rw-r--r--drivers/staging/line6/Kconfig1
-rw-r--r--drivers/staging/line6/driver.c68
-rw-r--r--drivers/staging/lirc/Kconfig110
-rw-r--r--drivers/staging/lirc/Makefile19
-rw-r--r--drivers/staging/lirc/TODO8
-rw-r--r--drivers/staging/lirc/TODO.lirc_i2c3
-rw-r--r--drivers/staging/lirc/lirc_bt829.c383
-rw-r--r--drivers/staging/lirc/lirc_ene0100.c646
-rw-r--r--drivers/staging/lirc/lirc_ene0100.h169
-rw-r--r--drivers/staging/lirc/lirc_i2c.c536
-rw-r--r--drivers/staging/lirc/lirc_igorplugusb.c555
-rw-r--r--drivers/staging/lirc/lirc_imon.c1058
-rw-r--r--drivers/staging/lirc/lirc_it87.c1019
-rw-r--r--drivers/staging/lirc/lirc_it87.h116
-rw-r--r--drivers/staging/lirc/lirc_ite8709.c542
-rw-r--r--drivers/staging/lirc/lirc_parallel.c705
-rw-r--r--drivers/staging/lirc/lirc_parallel.h26
-rw-r--r--drivers/staging/lirc/lirc_sasem.c933
-rw-r--r--drivers/staging/lirc/lirc_serial.c1313
-rw-r--r--drivers/staging/lirc/lirc_sir.c1282
-rw-r--r--drivers/staging/lirc/lirc_streamzap.c821
-rw-r--r--drivers/staging/lirc/lirc_ttusbir.c396
-rw-r--r--drivers/staging/lirc/lirc_zilog.c1387
-rw-r--r--drivers/staging/memrar/TODO2
-rw-r--r--drivers/staging/memrar/memrar-abi4
-rw-r--r--drivers/staging/memrar/memrar_handler.c40
-rw-r--r--drivers/staging/msm/Kconfig10
-rw-r--r--drivers/staging/msm/Makefile5
-rw-r--r--drivers/staging/msm/lcdc_grapefruit.c60
-rw-r--r--drivers/staging/msm/lcdc_st1_wxga.c54
-rw-r--r--drivers/staging/msm/lcdc_wxga.c56
-rw-r--r--drivers/staging/msm/mddi_toshiba_wvga.c63
-rw-r--r--drivers/staging/msm/mddihost.h2
-rw-r--r--drivers/staging/msm/mdp4_debugfs.c10
-rw-r--r--drivers/staging/msm/mdp4_overlay.c8
-rw-r--r--drivers/staging/msm/msm_fb_def.h4
-rw-r--r--drivers/staging/msm/staging-devices.c13
-rw-r--r--drivers/staging/octeon/cvmx-cmd-queue.c6
-rw-r--r--drivers/staging/octeon/cvmx-fau.h2
-rw-r--r--drivers/staging/octeon/ethernet-mdio.c2
-rw-r--r--drivers/staging/octeon/ethernet-spi.c2
-rw-r--r--drivers/staging/otus/80211core/ctxrx.c2
-rw-r--r--drivers/staging/otus/TODO16
-rw-r--r--drivers/staging/otus/apdbg.c24
-rw-r--r--drivers/staging/otus/hal/hpani.c16
-rw-r--r--drivers/staging/otus/hal/hpmain.c28
-rw-r--r--drivers/staging/otus/hal/hpreg.c17
-rw-r--r--drivers/staging/otus/ioctl.c55
-rw-r--r--drivers/staging/otus/wrap_sec.c2
-rw-r--r--drivers/staging/otus/wrap_usb.c5
-rw-r--r--drivers/staging/otus/wwrap.c968
-rw-r--r--drivers/staging/otus/zdusb.c251
-rw-r--r--drivers/staging/panel/panel.c1071
-rw-r--r--drivers/staging/pohmelfs/inode.c6
-rw-r--r--drivers/staging/quatech_usb2/quatech_usb2.c24
-rw-r--r--drivers/staging/quickstart/Kconfig10
-rw-r--r--drivers/staging/quickstart/Makefile1
-rw-r--r--drivers/staging/quickstart/quickstart.c474
-rw-r--r--drivers/staging/ramzswap/Kconfig21
-rw-r--r--drivers/staging/ramzswap/Makefile3
-rw-r--r--drivers/staging/ramzswap/ramzswap.txt51
-rw-r--r--drivers/staging/ramzswap/ramzswap_drv.c837
-rw-r--r--drivers/staging/rar_register/Kconfig30
-rw-r--r--drivers/staging/rar_register/Makefile2
-rw-r--r--drivers/staging/rt2860/ap.h6
-rw-r--r--drivers/staging/rt2860/chlist.h50
-rw-r--r--drivers/staging/rt2860/common/cmm_wpa.c4
-rw-r--r--drivers/staging/rt2860/common/rtmp_timer.c4
-rw-r--r--drivers/staging/rt2860/mlme.h21
-rw-r--r--drivers/staging/rt2860/rt_linux.c2
-rw-r--r--drivers/staging/rt2860/rtmp.h4
-rw-r--r--drivers/staging/rt2860/usb_main_dev.c9
-rw-r--r--drivers/staging/rt3070/md4.h42
-rw-r--r--drivers/staging/rtl8187se/Kconfig1
-rw-r--r--drivers/staging/rtl8192e/Kconfig1
-rw-r--r--drivers/staging/rtl8192e/ieee80211/dot11d.c18
-rw-r--r--drivers/staging/rtl8192e/ieee80211/ieee80211.h97
-rw-r--r--drivers/staging/rtl8192e/ieee80211/ieee80211_crypt.c20
-rw-r--r--drivers/staging/rtl8192e/ieee80211/ieee80211_crypt.h8
-rw-r--r--drivers/staging/rtl8192e/ieee80211/ieee80211_crypt_ccmp.c48
-rw-r--r--drivers/staging/rtl8192e/ieee80211/ieee80211_crypt_tkip.c198
-rw-r--r--drivers/staging/rtl8192e/ieee80211/ieee80211_crypt_wep.c96
-rw-r--r--drivers/staging/rtl8192e/ieee80211/ieee80211_module.c68
-rw-r--r--drivers/staging/rtl8192e/ieee80211/ieee80211_rx.c16
-rw-r--r--drivers/staging/rtl8192e/ieee80211/ieee80211_softmac.c185
-rw-r--r--drivers/staging/rtl8192e/ieee80211/ieee80211_softmac_wx.c73
-rw-r--r--drivers/staging/rtl8192e/ieee80211/ieee80211_tx.c9
-rw-r--r--drivers/staging/rtl8192e/ieee80211/ieee80211_wx.c132
-rw-r--r--drivers/staging/rtl8192e/ieee80211/rtl819x_HTProc.c17
-rw-r--r--drivers/staging/rtl8192e/r8190_rtl8256.c6
-rw-r--r--drivers/staging/rtl8192e/r8192E.h4
-rw-r--r--drivers/staging/rtl8192e/r8192E_core.c69
-rw-r--r--drivers/staging/rtl8192e/r8192E_dm.c22
-rw-r--r--drivers/staging/rtl8192e/r8192E_wx.c157
-rw-r--r--drivers/staging/rtl8192e/r819xE_phy.c2
-rw-r--r--drivers/staging/rtl8192su/Kconfig1
-rw-r--r--drivers/staging/rtl8192su/TODO7
-rw-r--r--drivers/staging/rtl8192su/ieee80211/dot11d.c28
-rw-r--r--drivers/staging/rtl8192su/ieee80211/dot11d.h25
-rw-r--r--drivers/staging/rtl8192su/ieee80211/ieee80211.h32
-rw-r--r--drivers/staging/rtl8192su/ieee80211/ieee80211_crypt.c5
-rw-r--r--drivers/staging/rtl8192su/ieee80211/ieee80211_crypt.h2
-rw-r--r--drivers/staging/rtl8192su/ieee80211/ieee80211_crypt_ccmp.c7
-rw-r--r--drivers/staging/rtl8192su/ieee80211/ieee80211_crypt_tkip.c31
-rw-r--r--drivers/staging/rtl8192su/ieee80211/ieee80211_crypt_wep.c6
-rw-r--r--drivers/staging/rtl8192su/ieee80211/ieee80211_module.c26
-rw-r--r--drivers/staging/rtl8192su/ieee80211/ieee80211_r8192s.h43
-rw-r--r--drivers/staging/rtl8192su/ieee80211/ieee80211_rx.c2
-rw-r--r--drivers/staging/rtl8192su/ieee80211/ieee80211_softmac.c290
-rw-r--r--drivers/staging/rtl8192su/ieee80211/ieee80211_tx.c11
-rw-r--r--drivers/staging/rtl8192su/ieee80211/ieee80211_wx.c17
-rw-r--r--drivers/staging/rtl8192su/ieee80211/rtl819x_BA.h30
-rw-r--r--drivers/staging/rtl8192su/ieee80211/rtl819x_BAProc.c50
-rw-r--r--drivers/staging/rtl8192su/ieee80211/rtl819x_HT.h42
-rw-r--r--drivers/staging/rtl8192su/ieee80211/rtl819x_HTProc.c147
-rw-r--r--drivers/staging/rtl8192su/ieee80211/rtl819x_Qos.h88
-rw-r--r--drivers/staging/rtl8192su/ieee80211/rtl819x_TS.h23
-rw-r--r--drivers/staging/rtl8192su/ieee80211/rtl819x_TSProc.c41
-rw-r--r--drivers/staging/rtl8192su/r8192SU_HWImg.c37
-rw-r--r--drivers/staging/rtl8192su/r8192SU_HWImg.h22
-rw-r--r--drivers/staging/rtl8192su/r8192SU_led.c9
-rw-r--r--drivers/staging/rtl8192su/r8192S_Efuse.c510
-rw-r--r--drivers/staging/rtl8192su/r8192S_Efuse.h70
-rw-r--r--drivers/staging/rtl8192su/r8192S_firmware.c26
-rw-r--r--drivers/staging/rtl8192su/r8192S_firmware.h100
-rw-r--r--drivers/staging/rtl8192su/r8192S_hw.h152
-rw-r--r--drivers/staging/rtl8192su/r8192S_phy.c659
-rw-r--r--drivers/staging/rtl8192su/r8192U.h309
-rw-r--r--drivers/staging/rtl8192su/r8192U_core.c169
-rw-r--r--drivers/staging/rtl8192su/r8192U_dm.c29
-rw-r--r--drivers/staging/rtl8192su/r8192U_wx.c128
-rw-r--r--drivers/staging/rtl8192su/r819xU_cmdpkt.c44
-rw-r--r--drivers/staging/rtl8192su/r819xU_cmdpkt.h1
-rw-r--r--drivers/staging/rtl8192u/Kconfig1
-rw-r--r--drivers/staging/rtl8192u/dot11d.h2
-rw-r--r--drivers/staging/rtl8192u/ieee80211.h2595
-rw-r--r--drivers/staging/rtl8192u/ieee80211/ieee80211_wx.c2
-rw-r--r--drivers/staging/rtl8192u/r8192U.h2
-rw-r--r--drivers/staging/rtl8192u/r8192U_core.c73
-rw-r--r--drivers/staging/rtl8192u/r8192U_wx.h2
-rw-r--r--drivers/staging/rtl8192u/r819xU_firmware.c2
-rw-r--r--drivers/staging/sep/sep_driver_api.h2
-rw-r--r--drivers/staging/slicoss/slic.h12
-rw-r--r--drivers/staging/slicoss/slicoss.c3952
-rw-r--r--drivers/staging/sm7xx/smtcfb.c2
-rw-r--r--drivers/staging/solo6x10/Kconfig7
-rw-r--r--drivers/staging/solo6x10/Makefile6
-rw-r--r--drivers/staging/solo6x10/TODO28
-rw-r--r--drivers/staging/solo6x10/solo6010-core.c282
-rw-r--r--drivers/staging/solo6x10/solo6010-disp.c271
-rw-r--r--drivers/staging/solo6x10/solo6010-enc.c229
-rw-r--r--drivers/staging/solo6x10/solo6010-g723.c398
-rw-r--r--drivers/staging/solo6x10/solo6010-gpio.c103
-rw-r--r--drivers/staging/solo6x10/solo6010-i2c.c331
-rw-r--r--drivers/staging/solo6x10/solo6010-jpeg.h105
-rw-r--r--drivers/staging/solo6x10/solo6010-offsets.h78
-rw-r--r--drivers/staging/solo6x10/solo6010-osd-font.h154
-rw-r--r--drivers/staging/solo6x10/solo6010-p2m.c208
-rw-r--r--drivers/staging/solo6x10/solo6010-registers.h657
-rw-r--r--drivers/staging/solo6x10/solo6010-tw28.c823
-rw-r--r--drivers/staging/solo6x10/solo6010-tw28.h65
-rw-r--r--drivers/staging/solo6x10/solo6010-v4l2-enc.c1564
-rw-r--r--drivers/staging/solo6x10/solo6010-v4l2.c859
-rw-r--r--drivers/staging/solo6x10/solo6010.h317
-rw-r--r--drivers/staging/spectra/Kconfig40
-rw-r--r--drivers/staging/spectra/Makefile11
-rw-r--r--drivers/staging/spectra/README29
-rw-r--r--drivers/staging/spectra/ffsdefs.h58
-rw-r--r--drivers/staging/spectra/ffsport.c827
-rw-r--r--drivers/staging/spectra/ffsport.h84
-rw-r--r--drivers/staging/spectra/flash.c4731
-rw-r--r--drivers/staging/spectra/flash.h198
-rw-r--r--drivers/staging/spectra/lld.c339
-rw-r--r--drivers/staging/spectra/lld.h111
-rw-r--r--drivers/staging/spectra/lld_cdma.c910
-rw-r--r--drivers/staging/spectra/lld_cdma.h123
-rw-r--r--drivers/staging/spectra/lld_emu.c780
-rw-r--r--drivers/staging/spectra/lld_emu.h51
-rw-r--r--drivers/staging/spectra/lld_mtd.c687
-rw-r--r--drivers/staging/spectra/lld_mtd.h51
-rw-r--r--drivers/staging/spectra/lld_nand.c2601
-rw-r--r--drivers/staging/spectra/lld_nand.h131
-rw-r--r--drivers/staging/spectra/nand_regs.h619
-rw-r--r--drivers/staging/spectra/spectraswconfig.h82
-rw-r--r--drivers/staging/ti-st/Kconfig2
-rw-r--r--drivers/staging/ti-st/TODO13
-rw-r--r--drivers/staging/ti-st/bt_drv.c29
-rw-r--r--drivers/staging/ti-st/st.h66
-rw-r--r--drivers/staging/ti-st/st_core.c202
-rw-r--r--drivers/staging/ti-st/st_core.h74
-rw-r--r--drivers/staging/ti-st/st_kim.c347
-rw-r--r--drivers/staging/ti-st/st_kim.h94
-rw-r--r--drivers/staging/ti-st/st_ll.c8
-rw-r--r--drivers/staging/ti-st/st_ll.h9
-rw-r--r--drivers/staging/ti-st/sysfs-uim12
-rw-r--r--drivers/staging/tidspbridge/Documentation/CONTRIBUTORS45
-rw-r--r--drivers/staging/tidspbridge/Documentation/README70
-rw-r--r--drivers/staging/tidspbridge/Documentation/error-codes157
-rw-r--r--drivers/staging/tidspbridge/Kconfig90
-rw-r--r--drivers/staging/tidspbridge/Makefile34
-rw-r--r--drivers/staging/tidspbridge/TODO18
-rw-r--r--drivers/staging/tidspbridge/core/_cmm.h45
-rw-r--r--drivers/staging/tidspbridge/core/_deh.h35
-rw-r--r--drivers/staging/tidspbridge/core/_msg_sm.h142
-rw-r--r--drivers/staging/tidspbridge/core/_tiomap.h371
-rw-r--r--drivers/staging/tidspbridge/core/_tiomap_pwr.h85
-rw-r--r--drivers/staging/tidspbridge/core/chnl_sm.c1014
-rw-r--r--drivers/staging/tidspbridge/core/dsp-clock.c422
-rw-r--r--drivers/staging/tidspbridge/core/io_sm.c2333
-rw-r--r--drivers/staging/tidspbridge/core/msg_sm.c673
-rw-r--r--drivers/staging/tidspbridge/core/tiomap3430.c1802
-rw-r--r--drivers/staging/tidspbridge/core/tiomap3430_pwr.c550
-rw-r--r--drivers/staging/tidspbridge/core/tiomap_io.c455
-rw-r--r--drivers/staging/tidspbridge/core/tiomap_io.h104
-rw-r--r--drivers/staging/tidspbridge/core/ue_deh.c273
-rw-r--r--drivers/staging/tidspbridge/core/wdt.c150
-rw-r--r--drivers/staging/tidspbridge/dynload/cload.c1953
-rw-r--r--drivers/staging/tidspbridge/dynload/dload_internal.h344
-rw-r--r--drivers/staging/tidspbridge/dynload/doff.h354
-rw-r--r--drivers/staging/tidspbridge/dynload/getsection.c407
-rw-r--r--drivers/staging/tidspbridge/dynload/header.h49
-rw-r--r--drivers/staging/tidspbridge/dynload/module_list.h159
-rw-r--r--drivers/staging/tidspbridge/dynload/params.h226
-rw-r--r--drivers/staging/tidspbridge/dynload/reloc.c484
-rw-r--r--drivers/staging/tidspbridge/dynload/reloc_table.h102
-rw-r--r--drivers/staging/tidspbridge/dynload/reloc_table_c6000.c257
-rw-r--r--drivers/staging/tidspbridge/dynload/tramp.c1143
-rw-r--r--drivers/staging/tidspbridge/dynload/tramp_table_c6000.c164
-rw-r--r--drivers/staging/tidspbridge/gen/gb.c167
-rw-r--r--drivers/staging/tidspbridge/gen/gh.c215
-rw-r--r--drivers/staging/tidspbridge/gen/gs.c89
-rw-r--r--drivers/staging/tidspbridge/gen/uuidutil.c113
-rw-r--r--drivers/staging/tidspbridge/hw/EasiGlobal.h41
-rw-r--r--drivers/staging/tidspbridge/hw/MMUAccInt.h76
-rw-r--r--drivers/staging/tidspbridge/hw/MMURegAcM.h225
-rw-r--r--drivers/staging/tidspbridge/hw/hw_defs.h58
-rw-r--r--drivers/staging/tidspbridge/hw/hw_mmu.c562
-rw-r--r--drivers/staging/tidspbridge/hw/hw_mmu.h163
-rw-r--r--drivers/staging/tidspbridge/include/dspbridge/_chnl_sm.h181
-rw-r--r--drivers/staging/tidspbridge/include/dspbridge/brddefs.h39
-rw-r--r--drivers/staging/tidspbridge/include/dspbridge/cfg.h222
-rw-r--r--drivers/staging/tidspbridge/include/dspbridge/cfgdefs.h81
-rw-r--r--drivers/staging/tidspbridge/include/dspbridge/chnl.h130
-rw-r--r--drivers/staging/tidspbridge/include/dspbridge/chnldefs.h66
-rw-r--r--drivers/staging/tidspbridge/include/dspbridge/chnlpriv.h98
-rw-r--r--drivers/staging/tidspbridge/include/dspbridge/clk.h101
-rw-r--r--drivers/staging/tidspbridge/include/dspbridge/cmm.h386
-rw-r--r--drivers/staging/tidspbridge/include/dspbridge/cmmdefs.h105
-rw-r--r--drivers/staging/tidspbridge/include/dspbridge/cod.h369
-rw-r--r--drivers/staging/tidspbridge/include/dspbridge/dbc.h46
-rw-r--r--drivers/staging/tidspbridge/include/dspbridge/dbdcd.h358
-rw-r--r--drivers/staging/tidspbridge/include/dspbridge/dbdcddef.h78
-rw-r--r--drivers/staging/tidspbridge/include/dspbridge/dbdefs.h514
-rw-r--r--drivers/staging/tidspbridge/include/dspbridge/dbldefs.h141
-rw-r--r--drivers/staging/tidspbridge/include/dspbridge/dbll.h62
-rw-r--r--drivers/staging/tidspbridge/include/dspbridge/dblldefs.h496
-rw-r--r--drivers/staging/tidspbridge/include/dspbridge/dehdefs.h32
-rw-r--r--drivers/staging/tidspbridge/include/dspbridge/dev.h702
-rw-r--r--drivers/staging/tidspbridge/include/dspbridge/devdefs.h26
-rw-r--r--drivers/staging/tidspbridge/include/dspbridge/disp.h204
-rw-r--r--drivers/staging/tidspbridge/include/dspbridge/dispdefs.h35
-rw-r--r--drivers/staging/tidspbridge/include/dspbridge/dmm.h75
-rw-r--r--drivers/staging/tidspbridge/include/dspbridge/drv.h521
-rw-r--r--drivers/staging/tidspbridge/include/dspbridge/drvdefs.h25
-rw-r--r--drivers/staging/tidspbridge/include/dspbridge/dspapi-ioctl.h475
-rw-r--r--drivers/staging/tidspbridge/include/dspbridge/dspapi.h167
-rw-r--r--drivers/staging/tidspbridge/include/dspbridge/dspchnl.h72
-rw-r--r--drivers/staging/tidspbridge/include/dspbridge/dspdefs.h1054
-rw-r--r--drivers/staging/tidspbridge/include/dspbridge/dspdeh.h43
-rw-r--r--drivers/staging/tidspbridge/include/dspbridge/dspdrv.h62
-rw-r--r--drivers/staging/tidspbridge/include/dspbridge/dspio.h41
-rw-r--r--drivers/staging/tidspbridge/include/dspbridge/dspioctl.h73
-rw-r--r--drivers/staging/tidspbridge/include/dspbridge/dspmsg.h56
-rw-r--r--drivers/staging/tidspbridge/include/dspbridge/dynamic_loader.h492
-rw-r--r--drivers/staging/tidspbridge/include/dspbridge/gb.h79
-rw-r--r--drivers/staging/tidspbridge/include/dspbridge/getsection.h108
-rw-r--r--drivers/staging/tidspbridge/include/dspbridge/gh.h34
-rw-r--r--drivers/staging/tidspbridge/include/dspbridge/gs.h59
-rw-r--r--drivers/staging/tidspbridge/include/dspbridge/host_os.h88
-rw-r--r--drivers/staging/tidspbridge/include/dspbridge/io.h114
-rw-r--r--drivers/staging/tidspbridge/include/dspbridge/io_sm.h298
-rw-r--r--drivers/staging/tidspbridge/include/dspbridge/iodefs.h36
-rw-r--r--drivers/staging/tidspbridge/include/dspbridge/ldr.h29
-rw-r--r--drivers/staging/tidspbridge/include/dspbridge/list.h225
-rw-r--r--drivers/staging/tidspbridge/include/dspbridge/mbx_sh.h184
-rw-r--r--drivers/staging/tidspbridge/include/dspbridge/memdefs.h30
-rw-r--r--drivers/staging/tidspbridge/include/dspbridge/mgr.h205
-rw-r--r--drivers/staging/tidspbridge/include/dspbridge/mgrpriv.h45
-rw-r--r--drivers/staging/tidspbridge/include/dspbridge/msg.h86
-rw-r--r--drivers/staging/tidspbridge/include/dspbridge/msgdefs.h29
-rw-r--r--drivers/staging/tidspbridge/include/dspbridge/nldr.h57
-rw-r--r--drivers/staging/tidspbridge/include/dspbridge/nldrdefs.h293
-rw-r--r--drivers/staging/tidspbridge/include/dspbridge/node.h583
-rw-r--r--drivers/staging/tidspbridge/include/dspbridge/nodedefs.h28
-rw-r--r--drivers/staging/tidspbridge/include/dspbridge/nodepriv.h182
-rw-r--r--drivers/staging/tidspbridge/include/dspbridge/ntfy.h217
-rw-r--r--drivers/staging/tidspbridge/include/dspbridge/proc.h621
-rw-r--r--drivers/staging/tidspbridge/include/dspbridge/procpriv.h25
-rw-r--r--drivers/staging/tidspbridge/include/dspbridge/pwr.h107
-rw-r--r--drivers/staging/tidspbridge/include/dspbridge/pwr_sh.h33
-rw-r--r--drivers/staging/tidspbridge/include/dspbridge/resourcecleanup.h52
-rw-r--r--drivers/staging/tidspbridge/include/dspbridge/rmm.h181
-rw-r--r--drivers/staging/tidspbridge/include/dspbridge/rms_sh.h95
-rw-r--r--drivers/staging/tidspbridge/include/dspbridge/rmstypes.h24
-rw-r--r--drivers/staging/tidspbridge/include/dspbridge/services.h50
-rw-r--r--drivers/staging/tidspbridge/include/dspbridge/strm.h404
-rw-r--r--drivers/staging/tidspbridge/include/dspbridge/strmdefs.h46
-rw-r--r--drivers/staging/tidspbridge/include/dspbridge/sync.h109
-rw-r--r--drivers/staging/tidspbridge/include/dspbridge/utildefs.h39
-rw-r--r--drivers/staging/tidspbridge/include/dspbridge/uuidutil.h62
-rw-r--r--drivers/staging/tidspbridge/include/dspbridge/wdt.h79
-rw-r--r--drivers/staging/tidspbridge/pmgr/chnl.c163
-rw-r--r--drivers/staging/tidspbridge/pmgr/chnlobj.h46
-rw-r--r--drivers/staging/tidspbridge/pmgr/cmm.c1154
-rw-r--r--drivers/staging/tidspbridge/pmgr/cod.c652
-rw-r--r--drivers/staging/tidspbridge/pmgr/dbll.c1585
-rw-r--r--drivers/staging/tidspbridge/pmgr/dev.c1151
-rw-r--r--drivers/staging/tidspbridge/pmgr/dmm.c533
-rw-r--r--drivers/staging/tidspbridge/pmgr/dspapi.c1906
-rw-r--r--drivers/staging/tidspbridge/pmgr/io.c142
-rw-r--r--drivers/staging/tidspbridge/pmgr/ioobj.h38
-rw-r--r--drivers/staging/tidspbridge/pmgr/msg.c129
-rw-r--r--drivers/staging/tidspbridge/pmgr/msgobj.h38
-rw-r--r--drivers/staging/tidspbridge/rmgr/dbdcd.c1512
-rw-r--r--drivers/staging/tidspbridge/rmgr/disp.c752
-rw-r--r--drivers/staging/tidspbridge/rmgr/drv.c929
-rw-r--r--drivers/staging/tidspbridge/rmgr/drv_interface.c656
-rw-r--r--drivers/staging/tidspbridge/rmgr/drv_interface.h28
-rw-r--r--drivers/staging/tidspbridge/rmgr/dspdrv.c142
-rw-r--r--drivers/staging/tidspbridge/rmgr/mgr.c375
-rw-r--r--drivers/staging/tidspbridge/rmgr/nldr.c1974
-rw-r--r--drivers/staging/tidspbridge/rmgr/node.c3234
-rw-r--r--drivers/staging/tidspbridge/rmgr/proc.c1936
-rw-r--r--drivers/staging/tidspbridge/rmgr/pwr.c176
-rw-r--r--drivers/staging/tidspbridge/rmgr/rmm.c537
-rw-r--r--drivers/staging/tidspbridge/rmgr/strm.c853
-rw-r--r--drivers/staging/tidspbridge/services/cfg.c253
-rw-r--r--drivers/staging/tidspbridge/services/ntfy.c31
-rw-r--r--drivers/staging/tidspbridge/services/services.c70
-rw-r--r--drivers/staging/tidspbridge/services/sync.c104
-rw-r--r--drivers/staging/tm6000/Kconfig4
-rw-r--r--drivers/staging/tm6000/Makefile8
-rw-r--r--drivers/staging/tm6000/tm6000-alsa.c263
-rw-r--r--drivers/staging/tm6000/tm6000-cards.c58
-rw-r--r--drivers/staging/tm6000/tm6000-core.c182
-rw-r--r--drivers/staging/tm6000/tm6000-dvb.c173
-rw-r--r--drivers/staging/tm6000/tm6000-i2c.c25
-rw-r--r--drivers/staging/tm6000/tm6000-input.c364
-rw-r--r--drivers/staging/tm6000/tm6000-stds.c36
-rw-r--r--drivers/staging/tm6000/tm6000-usb-isoc.h5
-rw-r--r--drivers/staging/tm6000/tm6000-video.c335
-rw-r--r--drivers/staging/tm6000/tm6000.h88
-rw-r--r--drivers/staging/usbip/stub.h17
-rw-r--r--drivers/staging/usbip/stub_dev.c101
-rw-r--r--drivers/staging/usbip/stub_main.c65
-rw-r--r--drivers/staging/usbip/stub_rx.c101
-rw-r--r--drivers/staging/usbip/usbip_common.h2
-rw-r--r--drivers/staging/vme/bridges/vme_ca91cx42.c12
-rw-r--r--drivers/staging/vme/bridges/vme_tsi148.c10
-rw-r--r--drivers/staging/vme/devices/vme_user.c99
-rw-r--r--drivers/staging/vt6655/80211hdr.h118
-rw-r--r--drivers/staging/vt6655/80211mgr.c118
-rw-r--r--drivers/staging/vt6655/80211mgr.h336
-rw-r--r--drivers/staging/vt6655/IEEE11h.c68
-rw-r--r--drivers/staging/vt6655/IEEE11h.h2
-rw-r--r--drivers/staging/vt6655/Makefile1
-rw-r--r--drivers/staging/vt6655/TODO3
-rw-r--r--drivers/staging/vt6655/aes_ccmp.c112
-rw-r--r--drivers/staging/vt6655/aes_ccmp.h2
-rw-r--r--drivers/staging/vt6655/baseband.c196
-rw-r--r--drivers/staging/vt6655/baseband.h52
-rw-r--r--drivers/staging/vt6655/bssdb.c351
-rw-r--r--drivers/staging/vt6655/bssdb.h246
-rw-r--r--drivers/staging/vt6655/card.c1369
-rw-r--r--drivers/staging/vt6655/card.h158
-rw-r--r--drivers/staging/vt6655/channel.c835
-rw-r--r--drivers/staging/vt6655/channel.h58
-rw-r--r--drivers/staging/vt6655/country.h15
-rw-r--r--drivers/staging/vt6655/datarate.c90
-rw-r--r--drivers/staging/vt6655/datarate.h24
-rw-r--r--drivers/staging/vt6655/desc.h352
-rw-r--r--drivers/staging/vt6655/device.h526
-rw-r--r--drivers/staging/vt6655/device_cfg.h8
-rw-r--r--drivers/staging/vt6655/device_main.c566
-rw-r--r--drivers/staging/vt6655/dpc.c516
-rw-r--r--drivers/staging/vt6655/dpc.h2
-rw-r--r--drivers/staging/vt6655/hostap.c84
-rw-r--r--drivers/staging/vt6655/iocmd.h347
-rw-r--r--drivers/staging/vt6655/ioctl.c128
-rw-r--r--drivers/staging/vt6655/ioctl.h6
-rw-r--r--drivers/staging/vt6655/iwctl.c152
-rw-r--r--drivers/staging/vt6655/key.c288
-rw-r--r--drivers/staging/vt6655/key.h114
-rw-r--r--drivers/staging/vt6655/mac.c363
-rw-r--r--drivers/staging/vt6655/mac.h203
-rw-r--r--drivers/staging/vt6655/mib.c110
-rw-r--r--drivers/staging/vt6655/mib.h429
-rw-r--r--drivers/staging/vt6655/michael.c46
-rw-r--r--drivers/staging/vt6655/michael.h6
-rw-r--r--drivers/staging/vt6655/power.c74
-rw-r--r--drivers/staging/vt6655/power.h12
-rw-r--r--drivers/staging/vt6655/rc4.c40
-rw-r--r--drivers/staging/vt6655/rc4.h12
-rw-r--r--drivers/staging/vt6655/rf.c196
-rw-r--r--drivers/staging/vt6655/rf.h20
-rw-r--r--drivers/staging/vt6655/rxtx.c1104
-rw-r--r--drivers/staging/vt6655/rxtx.h62
-rw-r--r--drivers/staging/vt6655/srom.c82
-rw-r--r--drivers/staging/vt6655/srom.h80
-rw-r--r--drivers/staging/vt6655/tcrc.c12
-rw-r--r--drivers/staging/vt6655/tcrc.h6
-rw-r--r--drivers/staging/vt6655/tether.c20
-rw-r--r--drivers/staging/vt6655/tether.h60
-rw-r--r--drivers/staging/vt6655/tkip.c14
-rw-r--r--drivers/staging/vt6655/tkip.h10
-rw-r--r--drivers/staging/vt6655/tmacro.h12
-rw-r--r--drivers/staging/vt6655/ttype.h57
-rw-r--r--drivers/staging/vt6655/upc.h22
-rw-r--r--drivers/staging/vt6655/vntwifi.c174
-rw-r--r--drivers/staging/vt6655/vntwifi.h82
-rw-r--r--drivers/staging/vt6655/wcmd.c169
-rw-r--r--drivers/staging/vt6655/wcmd.h18
-rw-r--r--drivers/staging/vt6655/wctl.c62
-rw-r--r--drivers/staging/vt6655/wctl.h9
-rw-r--r--drivers/staging/vt6655/wmgr.c807
-rw-r--r--drivers/staging/vt6655/wmgr.h192
-rw-r--r--drivers/staging/vt6655/wpa.c62
-rw-r--r--drivers/staging/vt6655/wpa.h8
-rw-r--r--drivers/staging/vt6655/wpa2.c70
-rw-r--r--drivers/staging/vt6655/wpa2.h8
-rw-r--r--drivers/staging/vt6655/wpactl.c80
-rw-r--r--drivers/staging/vt6655/wpactl.h4
-rw-r--r--drivers/staging/vt6655/wroute.c44
-rw-r--r--drivers/staging/vt6655/wroute.h2
-rw-r--r--drivers/staging/vt6656/80211mgr.c516
-rw-r--r--drivers/staging/vt6656/80211mgr.h33
-rw-r--r--drivers/staging/vt6656/aes_ccmp.c4
-rw-r--r--drivers/staging/vt6656/baseband.c6
-rw-r--r--drivers/staging/vt6656/baseband.h19
-rw-r--r--drivers/staging/vt6656/bssdb.c117
-rw-r--r--drivers/staging/vt6656/bssdb.h12
-rw-r--r--drivers/staging/vt6656/card.c7
-rw-r--r--drivers/staging/vt6656/channel.c45
-rw-r--r--drivers/staging/vt6656/channel.h12
-rw-r--r--drivers/staging/vt6656/control.c2
-rw-r--r--drivers/staging/vt6656/control.h14
-rw-r--r--drivers/staging/vt6656/datarate.c69
-rw-r--r--drivers/staging/vt6656/desc.h79
-rw-r--r--drivers/staging/vt6656/device.h52
-rw-r--r--drivers/staging/vt6656/device_cfg.h16
-rw-r--r--drivers/staging/vt6656/dpc.c48
-rw-r--r--drivers/staging/vt6656/firmware.c2
-rw-r--r--drivers/staging/vt6656/int.c7
-rw-r--r--drivers/staging/vt6656/int.h8
-rw-r--r--drivers/staging/vt6656/iocmd.h16
-rw-r--r--drivers/staging/vt6656/ioctl.c12
-rw-r--r--drivers/staging/vt6656/iowpa.h47
-rw-r--r--drivers/staging/vt6656/iwctl.c131
-rw-r--r--drivers/staging/vt6656/iwctl.h4
-rw-r--r--drivers/staging/vt6656/key.c34
-rw-r--r--drivers/staging/vt6656/mac.c4
-rw-r--r--drivers/staging/vt6656/mac.h8
-rw-r--r--drivers/staging/vt6656/main_usb.c321
-rw-r--r--drivers/staging/vt6656/mib.c25
-rw-r--r--drivers/staging/vt6656/mib.h25
-rw-r--r--drivers/staging/vt6656/michael.c4
-rw-r--r--drivers/staging/vt6656/michael.h6
-rw-r--r--drivers/staging/vt6656/power.c10
-rw-r--r--drivers/staging/vt6656/power.h2
-rw-r--r--drivers/staging/vt6656/rf.h19
-rw-r--r--drivers/staging/vt6656/rndis.h2
-rw-r--r--drivers/staging/vt6656/rxtx.c79
-rw-r--r--drivers/staging/vt6656/rxtx.h6
-rw-r--r--drivers/staging/vt6656/tether.h41
-rw-r--r--drivers/staging/vt6656/tkip.c6
-rw-r--r--drivers/staging/vt6656/ttype.h31
-rw-r--r--drivers/staging/vt6656/usbpipe.c99
-rw-r--r--drivers/staging/vt6656/usbpipe.h33
-rw-r--r--drivers/staging/vt6656/wcmd.c41
-rw-r--r--drivers/staging/vt6656/wcmd.h3
-rw-r--r--drivers/staging/vt6656/wctl.c24
-rw-r--r--drivers/staging/vt6656/wmgr.c75
-rw-r--r--drivers/staging/vt6656/wmgr.h11
-rw-r--r--drivers/staging/vt6656/wpa.c6
-rw-r--r--drivers/staging/vt6656/wpa2.h18
-rw-r--r--drivers/staging/vt6656/wpactl.c12
-rw-r--r--drivers/staging/winbond/mac_structures.h144
-rw-r--r--drivers/staging/winbond/phy_calibration.c834
-rw-r--r--drivers/staging/winbond/reg.c36
-rw-r--r--drivers/staging/winbond/wbusb.c4
-rw-r--r--drivers/staging/wlags49_h2/hcf.c2
-rw-r--r--drivers/staging/wlags49_h2/mdd.h4
-rw-r--r--drivers/staging/wlags49_h2/wl_cs.c500
-rw-r--r--drivers/staging/wlags49_h2/wl_cs.h2
-rw-r--r--drivers/staging/wlags49_h2/wl_internal.h1
-rw-r--r--drivers/staging/wlags49_h2/wl_netdev.c4
-rw-r--r--drivers/staging/wlags49_h2/wl_pci.c16
-rw-r--r--drivers/staging/wlags49_h2/wl_pci.h8
-rw-r--r--drivers/staging/wlags49_h2/wl_profile.c2
-rw-r--r--drivers/staging/wlags49_h2/wl_util.c37
-rw-r--r--drivers/staging/wlags49_h2/wl_util.h2
-rw-r--r--drivers/staging/wlan-ng/Kconfig2
-rw-r--r--drivers/staging/wlan-ng/Makefile1
-rw-r--r--drivers/staging/wlan-ng/cfg80211.c760
-rw-r--r--drivers/staging/wlan-ng/hfa384x.h4
-rw-r--r--drivers/staging/wlan-ng/hfa384x_usb.c34
-rw-r--r--drivers/staging/wlan-ng/p80211conv.c70
-rw-r--r--drivers/staging/wlan-ng/p80211conv.h42
-rw-r--r--drivers/staging/wlan-ng/p80211hdr.h24
-rw-r--r--drivers/staging/wlan-ng/p80211ioctl.h4
-rw-r--r--drivers/staging/wlan-ng/p80211meta.h16
-rw-r--r--drivers/staging/wlan-ng/p80211metastruct.h62
-rw-r--r--drivers/staging/wlan-ng/p80211mgmt.h24
-rw-r--r--drivers/staging/wlan-ng/p80211msg.h4
-rw-r--r--drivers/staging/wlan-ng/p80211netdev.c77
-rw-r--r--drivers/staging/wlan-ng/p80211netdev.h9
-rw-r--r--drivers/staging/wlan-ng/p80211req.c18
-rw-r--r--drivers/staging/wlan-ng/p80211wext.c1690
-rw-r--r--drivers/staging/wlan-ng/prism2fw.c118
-rw-r--r--drivers/staging/wlan-ng/prism2mgmt.c24
-rw-r--r--drivers/staging/wlan-ng/prism2mib.c76
-rw-r--r--drivers/staging/wlan-ng/prism2sta.c91
-rw-r--r--drivers/staging/wlan-ng/prism2usb.c2
-rw-r--r--drivers/staging/xgifb/XGI.h10
-rw-r--r--drivers/staging/xgifb/XGI_accel.c307
-rw-r--r--drivers/staging/xgifb/XGI_accel.h14
-rw-r--r--drivers/staging/xgifb/XGI_main.h182
-rw-r--r--drivers/staging/xgifb/XGI_main_26.c255
-rw-r--r--drivers/staging/xgifb/XGIfb.h31
-rw-r--r--drivers/staging/xgifb/osdef.h153
-rw-r--r--drivers/staging/xgifb/vb_def.h4
-rw-r--r--drivers/staging/xgifb/vb_ext.c510
-rw-r--r--drivers/staging/xgifb/vb_ext.h26
-rw-r--r--drivers/staging/xgifb/vb_init.c895
-rw-r--r--drivers/staging/xgifb/vb_init.h4
-rw-r--r--drivers/staging/xgifb/vb_setmode.c2060
-rw-r--r--drivers/staging/xgifb/vb_setmode.h66
-rw-r--r--drivers/staging/xgifb/vb_struct.h951
-rw-r--r--drivers/staging/xgifb/vb_table.h633
-rw-r--r--drivers/staging/xgifb/vb_util.c137
-rw-r--r--drivers/staging/xgifb/vb_util.h20
-rw-r--r--drivers/staging/xgifb/vgatypes.h271
-rw-r--r--drivers/staging/zram/Kconfig29
-rw-r--r--drivers/staging/zram/Makefile3
-rw-r--r--drivers/staging/zram/xvmalloc.c (renamed from drivers/staging/ramzswap/xvmalloc.c)0
-rw-r--r--drivers/staging/zram/xvmalloc.h (renamed from drivers/staging/ramzswap/xvmalloc.h)0
-rw-r--r--drivers/staging/zram/xvmalloc_int.h (renamed from drivers/staging/ramzswap/xvmalloc_int.h)0
-rw-r--r--drivers/staging/zram/zram.txt62
-rw-r--r--drivers/staging/zram/zram_drv.c805
-rw-r--r--drivers/staging/zram/zram_drv.h (renamed from drivers/staging/ramzswap/ramzswap_drv.h)71
-rw-r--r--drivers/staging/zram/zram_ioctl.h (renamed from drivers/staging/ramzswap/ramzswap_ioctl.h)21
-rw-r--r--drivers/telephony/ixj_pcmcia.c20
-rw-r--r--drivers/uio/uio_cif.c2
-rw-r--r--drivers/uio/uio_pdrv_genirq.c1
-rw-r--r--drivers/uio/uio_sercos3.c2
-rw-r--r--drivers/usb/Kconfig3
-rw-r--r--drivers/usb/atm/cxacru.c18
-rw-r--r--drivers/usb/atm/speedtch.c10
-rw-r--r--drivers/usb/atm/ueagle-atm.c13
-rw-r--r--drivers/usb/class/cdc-acm.c2
-rw-r--r--drivers/usb/class/usblp.c2
-rw-r--r--drivers/usb/gadget/f_audio.c6
-rw-r--r--drivers/usb/gadget/f_uvc.c16
-rw-r--r--drivers/usb/gadget/f_uvc.h352
-rw-r--r--drivers/usb/gadget/fsl_qe_udc.c1
-rw-r--r--drivers/usb/gadget/gmidi.c2
-rw-r--r--drivers/usb/gadget/rndis.c5
-rw-r--r--drivers/usb/gadget/uvc.h36
-rw-r--r--drivers/usb/gadget/webcam.c24
-rw-r--r--drivers/usb/host/fhci-sched.c2
-rw-r--r--drivers/usb/host/ohci-hcd.c7
-rw-r--r--drivers/usb/host/ohci-jz4740.c276
-rw-r--r--drivers/usb/host/sl811_cs.c24
-rw-r--r--drivers/usb/serial/kl5kusb105.c2
-rw-r--r--drivers/usb/wusbcore/wusbhc.c2
-rw-r--r--drivers/uwb/wlp/wss-lc.c2
-rw-r--r--drivers/vhost/net.c306
-rw-r--r--drivers/vhost/vhost.c232
-rw-r--r--drivers/vhost/vhost.h55
-rw-r--r--drivers/video/Kconfig10
-rw-r--r--drivers/video/Makefile1
-rw-r--r--drivers/video/backlight/locomolcd.c4
-rw-r--r--drivers/video/bw2.c4
-rw-r--r--drivers/video/carminefb.c2
-rw-r--r--drivers/video/cg14.c4
-rw-r--r--drivers/video/cg3.c4
-rw-r--r--drivers/video/cg6.c4
-rw-r--r--drivers/video/console/fbcon.c26
-rw-r--r--drivers/video/console/fbcon.h1
-rw-r--r--drivers/video/controlfb.c2
-rw-r--r--drivers/video/ffb.c4
-rw-r--r--drivers/video/fsl-diu-fb.c137
-rw-r--r--drivers/video/jz4740_fb.c847
-rw-r--r--drivers/video/leo.c4
-rw-r--r--drivers/video/offb.c3
-rw-r--r--drivers/video/omap2/displays/panel-acx565akm.c4
-rw-r--r--drivers/video/p9100.c4
-rw-r--r--drivers/video/sunxvr1000.c4
-rw-r--r--drivers/video/tcx.c4
-rw-r--r--drivers/video/tdfxfb.c4
-rw-r--r--drivers/video/tgafb.c2
-rw-r--r--drivers/video/xen-fbfront.c2
-rw-r--r--drivers/video/xilinxfb.c2
-rw-r--r--drivers/watchdog/Kconfig18
-rw-r--r--drivers/watchdog/Makefile2
-rw-r--r--drivers/watchdog/cpwd.c6
-rw-r--r--drivers/watchdog/octeon-wdt-main.c745
-rw-r--r--drivers/watchdog/octeon-wdt-nmi.S64
-rw-r--r--drivers/watchdog/riowd.c4
-rw-r--r--drivers/xen/Kconfig9
-rw-r--r--drivers/xen/Makefile3
-rw-r--r--drivers/xen/events.c96
-rw-r--r--drivers/xen/grant-table.c77
-rw-r--r--drivers/xen/manage.c46
-rw-r--r--drivers/xen/platform-pci.c207
-rw-r--r--drivers/xen/xenbus/xenbus_probe.c52
-rw-r--r--drivers/xen/xenbus/xenbus_xs.c57
-rw-r--r--drivers/xen/xenfs/super.c4
-rw-r--r--drivers/xen/xenfs/xenbus.c3
-rw-r--r--firmware/Makefile2
-rw-r--r--firmware/cxgb3/t3fw-7.10.0.bin.ihex1935
-rw-r--r--firmware/cxgb3/t3fw-7.4.0.bin.ihex1917
-rw-r--r--fs/9p/Makefile4
-rw-r--r--fs/9p/fid.c111
-rw-r--r--fs/9p/v9fs.c3
-rw-r--r--fs/9p/v9fs.h1
-rw-r--r--fs/9p/v9fs_vfs.h1
-rw-r--r--fs/9p/vfs_dir.c134
-rw-r--r--fs/9p/vfs_file.c26
-rw-r--r--fs/9p/vfs_inode.c757
-rw-r--r--fs/9p/vfs_super.c50
-rw-r--r--fs/9p/xattr.c160
-rw-r--r--fs/9p/xattr.h27
-rw-r--r--fs/9p/xattr_user.c80
-rw-r--r--fs/Kconfig2
-rw-r--r--fs/afs/Kconfig1
-rw-r--r--fs/afs/cell.c40
-rw-r--r--fs/afs/main.c9
-rw-r--r--fs/aio.c21
-rw-r--r--fs/befs/linuxvfs.c2
-rw-r--r--fs/block_dev.c4
-rw-r--r--fs/cachefiles/namei.c13
-rw-r--r--fs/cachefiles/rdwr.c4
-rw-r--r--fs/char_dev.c1
-rw-r--r--fs/cifs/Kconfig27
-rw-r--r--fs/cifs/Makefile2
-rw-r--r--fs/cifs/README5
-rw-r--r--fs/cifs/cache.c331
-rw-r--r--fs/cifs/cifs_debug.c25
-rw-r--r--fs/cifs/cifs_dfs_ref.c33
-rw-r--r--fs/cifs/cifs_fs_sb.h1
-rw-r--r--fs/cifs/cifs_spnego.c7
-rw-r--r--fs/cifs/cifsfs.c33
-rw-r--r--fs/cifs/cifsfs.h2
-rw-r--r--fs/cifs/cifsglob.h48
-rw-r--r--fs/cifs/cifsproto.h4
-rw-r--r--fs/cifs/connect.c181
-rw-r--r--fs/cifs/dir.c8
-rw-r--r--fs/cifs/dns_resolve.c231
-rw-r--r--fs/cifs/dns_resolve.h2
-rw-r--r--fs/cifs/file.c104
-rw-r--r--fs/cifs/fscache.c236
-rw-r--r--fs/cifs/fscache.h136
-rw-r--r--fs/cifs/inode.c63
-rw-r--r--fs/cifs/ioctl.c3
-rw-r--r--fs/cifs/misc.c20
-rw-r--r--fs/cifs/netmisc.c63
-rw-r--r--fs/cifs/readdir.c5
-rw-r--r--fs/cifs/smberr.h1
-rw-r--r--fs/compat.c2
-rw-r--r--fs/compat_ioctl.c11
-rw-r--r--fs/direct-io.c26
-rw-r--r--fs/dlm/lowcomms.c2
-rw-r--r--fs/dlm/netlink.c15
-rw-r--r--fs/ecryptfs/crypto.c2
-rw-r--r--fs/exec.c8
-rw-r--r--fs/ext3/Kconfig1
-rw-r--r--fs/ext3/inode.c80
-rw-r--r--fs/ext3/namei.c3
-rw-r--r--fs/ext3/resize.c2
-rw-r--r--fs/ext3/super.c17
-rw-r--r--fs/ext4/acl.c1
-rw-r--r--fs/ext4/balloc.c6
-rw-r--r--fs/ext4/block_validity.c8
-rw-r--r--fs/ext4/dir.c23
-rw-r--r--fs/ext4/ext4.h152
-rw-r--r--fs/ext4/ext4_jbd2.c71
-rw-r--r--fs/ext4/ext4_jbd2.h56
-rw-r--r--fs/ext4/extents.c20
-rw-r--r--fs/ext4/file.c5
-rw-r--r--fs/ext4/ialloc.c4
-rw-r--r--fs/ext4/inode.c205
-rw-r--r--fs/ext4/mballoc.c155
-rw-r--r--fs/ext4/migrate.c2
-rw-r--r--fs/ext4/move_extent.c10
-rw-r--r--fs/ext4/namei.c40
-rw-r--r--fs/ext4/resize.c8
-rw-r--r--fs/ext4/super.c336
-rw-r--r--fs/ext4/xattr.c3
-rw-r--r--fs/file.c3
-rw-r--r--fs/freevxfs/vxfs_super.c2
-rw-r--r--fs/fscache/Kconfig1
-rw-r--r--fs/fscache/internal.h8
-rw-r--r--fs/fscache/main.c106
-rw-r--r--fs/fscache/object-list.c11
-rw-r--r--fs/fscache/object.c106
-rw-r--r--fs/fscache/operation.c67
-rw-r--r--fs/fscache/page.c36
-rw-r--r--fs/fuse/dev.c229
-rw-r--r--fs/fuse/dir.c2
-rw-r--r--fs/fuse/file.c2
-rw-r--r--fs/fuse/fuse_i.h3
-rw-r--r--fs/gfs2/Kconfig1
-rw-r--r--fs/gfs2/aops.c9
-rw-r--r--fs/gfs2/bmap.c17
-rw-r--r--fs/gfs2/bmap.h2
-rw-r--r--fs/gfs2/dir.c11
-rw-r--r--fs/gfs2/file.c4
-rw-r--r--fs/gfs2/glock.c105
-rw-r--r--fs/gfs2/incore.h4
-rw-r--r--fs/gfs2/main.c14
-rw-r--r--fs/gfs2/ops_fstype.c35
-rw-r--r--fs/gfs2/quota.c25
-rw-r--r--fs/gfs2/recovery.c54
-rw-r--r--fs/gfs2/recovery.h6
-rw-r--r--fs/gfs2/super.c9
-rw-r--r--fs/gfs2/sys.c60
-rw-r--r--fs/jbd/journal.c7
-rw-r--r--fs/jbd/recovery.c11
-rw-r--r--fs/jbd2/checkpoint.c18
-rw-r--r--fs/jbd2/commit.c50
-rw-r--r--fs/jbd2/journal.c121
-rw-r--r--fs/jbd2/recovery.c10
-rw-r--r--fs/jbd2/transaction.c233
-rw-r--r--fs/namei.c6
-rw-r--r--fs/ncpfs/inode.c4
-rw-r--r--fs/nfs/Kconfig10
-rw-r--r--fs/nfs/callback_proc.c19
-rw-r--r--fs/nfs/client.c21
-rw-r--r--fs/nfs/delegation.c16
-rw-r--r--fs/nfs/delegation.h4
-rw-r--r--fs/nfs/dir.c11
-rw-r--r--fs/nfs/direct.c29
-rw-r--r--fs/nfs/file.c51
-rw-r--r--fs/nfs/inode.c74
-rw-r--r--fs/nfs/internal.h7
-rw-r--r--fs/nfs/nfs2xdr.c7
-rw-r--r--fs/nfs/nfs3xdr.c8
-rw-r--r--fs/nfs/nfs4_fs.h57
-rw-r--r--fs/nfs/nfs4proc.c474
-rw-r--r--fs/nfs/nfs4renewd.c4
-rw-r--r--fs/nfs/nfs4state.c82
-rw-r--r--fs/nfs/nfs4xdr.c107
-rw-r--r--fs/nfs/pagelist.c8
-rw-r--r--fs/nfs/read.c3
-rw-r--r--fs/nfs/super.c4
-rw-r--r--fs/nfs/unlink.c2
-rw-r--r--fs/nfs/write.c9
-rw-r--r--fs/nfsd/nfs3proc.c8
-rw-r--r--fs/nfsd/nfs4callback.c57
-rw-r--r--fs/nfsd/nfs4state.c381
-rw-r--r--fs/nfsd/nfs4xdr.c3
-rw-r--r--fs/nfsd/nfsctl.c24
-rw-r--r--fs/nfsd/nfsd.h1
-rw-r--r--fs/nfsd/nfsproc.c4
-rw-r--r--fs/nfsd/nfssvc.c151
-rw-r--r--fs/nfsd/state.h40
-rw-r--r--fs/nfsd/vfs.c79
-rw-r--r--fs/nfsd/vfs.h4
-rw-r--r--fs/nilfs2/bmap.c6
-rw-r--r--fs/nilfs2/bmap.h16
-rw-r--r--fs/nilfs2/btnode.c23
-rw-r--r--fs/nilfs2/btnode.h4
-rw-r--r--fs/nilfs2/btree.c914
-rw-r--r--fs/nilfs2/btree.h12
-rw-r--r--fs/nilfs2/dir.c33
-rw-r--r--fs/nilfs2/direct.c96
-rw-r--r--fs/nilfs2/direct.h11
-rw-r--r--fs/nilfs2/gcinode.c17
-rw-r--r--fs/nilfs2/mdt.c1
-rw-r--r--fs/nilfs2/nilfs.h22
-rw-r--r--fs/nilfs2/page.c5
-rw-r--r--fs/nilfs2/page.h2
-rw-r--r--fs/nilfs2/recovery.c348
-rw-r--r--fs/nilfs2/segbuf.h24
-rw-r--r--fs/nilfs2/segment.c19
-rw-r--r--fs/nilfs2/segment.h10
-rw-r--r--fs/nilfs2/super.c333
-rw-r--r--fs/nilfs2/the_nilfs.c161
-rw-r--r--fs/nilfs2/the_nilfs.h23
-rw-r--r--fs/ocfs2/aops.c7
-rw-r--r--fs/ocfs2/dlm/dlmdebug.c6
-rw-r--r--fs/ocfs2/dlmfs/dlmfs.c3
-rw-r--r--fs/ocfs2/dlmglue.c4
-rw-r--r--fs/ocfs2/journal.c4
-rw-r--r--fs/ocfs2/super.c2
-rw-r--r--fs/open.c11
-rw-r--r--fs/partitions/check.c1
-rw-r--r--fs/quota/dquot.c79
-rw-r--r--fs/quota/quota_tree.c85
-rw-r--r--fs/quota/quota_tree.h6
-rw-r--r--fs/quota/quota_v1.c3
-rw-r--r--fs/quota/quota_v2.c11
-rw-r--r--fs/reiserfs/inode.c2
-rw-r--r--fs/sysfs/file.c3
-rw-r--r--fs/ubifs/lpt.c14
-rw-r--r--fs/ubifs/lpt_commit.c2
-rw-r--r--fs/ubifs/recovery.c23
-rw-r--r--fs/ubifs/super.c4
-rw-r--r--fs/udf/file.c1
-rw-r--r--fs/udf/super.c2
-rw-r--r--fs/xfs/Makefile4
-rw-r--r--fs/xfs/linux-2.6/xfs_acl.c2
-rw-r--r--fs/xfs/linux-2.6/xfs_aops.c611
-rw-r--r--fs/xfs/linux-2.6/xfs_aops.h4
-rw-r--r--fs/xfs/linux-2.6/xfs_buf.c62
-rw-r--r--fs/xfs/linux-2.6/xfs_buf.h119
-rw-r--r--fs/xfs/linux-2.6/xfs_dmapi_priv.h28
-rw-r--r--fs/xfs/linux-2.6/xfs_export.c8
-rw-r--r--fs/xfs/linux-2.6/xfs_file.c104
-rw-r--r--fs/xfs/linux-2.6/xfs_fs_subr.c4
-rw-r--r--fs/xfs/linux-2.6/xfs_fs_subr.h25
-rw-r--r--fs/xfs/linux-2.6/xfs_ioctl.c27
-rw-r--r--fs/xfs/linux-2.6/xfs_ioctl32.c6
-rw-r--r--fs/xfs/linux-2.6/xfs_iops.c10
-rw-r--r--fs/xfs/linux-2.6/xfs_linux.h1
-rw-r--r--fs/xfs/linux-2.6/xfs_quotaops.c11
-rw-r--r--fs/xfs/linux-2.6/xfs_super.c171
-rw-r--r--fs/xfs/linux-2.6/xfs_super.h7
-rw-r--r--fs/xfs/linux-2.6/xfs_sync.c49
-rw-r--r--fs/xfs/linux-2.6/xfs_sync.h3
-rw-r--r--fs/xfs/linux-2.6/xfs_trace.c4
-rw-r--r--fs/xfs/linux-2.6/xfs_trace.h128
-rw-r--r--fs/xfs/quota/xfs_dquot.c114
-rw-r--r--fs/xfs/quota/xfs_dquot_item.c301
-rw-r--r--fs/xfs/quota/xfs_qm.c15
-rw-r--r--fs/xfs/quota/xfs_qm_bhv.c10
-rw-r--r--fs/xfs/quota/xfs_qm_stats.c10
-rw-r--r--fs/xfs/quota/xfs_qm_syscalls.c121
-rw-r--r--fs/xfs/quota/xfs_trans_dquot.c35
-rw-r--r--fs/xfs/support/debug.c1
-rw-r--r--fs/xfs/xfs_alloc.c15
-rw-r--r--fs/xfs/xfs_alloc.h20
-rw-r--r--fs/xfs/xfs_alloc_btree.c5
-rw-r--r--fs/xfs/xfs_attr.c91
-rw-r--r--fs/xfs/xfs_attr_leaf.c5
-rw-r--r--fs/xfs/xfs_bmap.c327
-rw-r--r--fs/xfs/xfs_bmap.h37
-rw-r--r--fs/xfs/xfs_bmap_btree.c5
-rw-r--r--fs/xfs/xfs_btree.c5
-rw-r--r--fs/xfs/xfs_buf_item.c228
-rw-r--r--fs/xfs/xfs_buf_item.h2
-rw-r--r--fs/xfs/xfs_da_btree.c20
-rw-r--r--fs/xfs/xfs_dfrag.c16
-rw-r--r--fs/xfs/xfs_dir2.c11
-rw-r--r--fs/xfs/xfs_dir2_block.c8
-rw-r--r--fs/xfs/xfs_dir2_data.c2
-rw-r--r--fs/xfs/xfs_dir2_leaf.c4
-rw-r--r--fs/xfs/xfs_dir2_node.c2
-rw-r--r--fs/xfs/xfs_dir2_sf.c2
-rw-r--r--fs/xfs/xfs_dmapi.h170
-rw-r--r--fs/xfs/xfs_dmops.c55
-rw-r--r--fs/xfs/xfs_error.c4
-rw-r--r--fs/xfs/xfs_extfree_item.c278
-rw-r--r--fs/xfs/xfs_filestream.c84
-rw-r--r--fs/xfs/xfs_filestream.h82
-rw-r--r--fs/xfs/xfs_fsops.c7
-rw-r--r--fs/xfs/xfs_ialloc.c4
-rw-r--r--fs/xfs/xfs_ialloc_btree.c4
-rw-r--r--fs/xfs/xfs_iget.c108
-rw-r--r--fs/xfs/xfs_inode.c60
-rw-r--r--fs/xfs/xfs_inode.h4
-rw-r--r--fs/xfs/xfs_inode_item.c273
-rw-r--r--fs/xfs/xfs_inode_item.h12
-rw-r--r--fs/xfs/xfs_iomap.c76
-rw-r--r--fs/xfs/xfs_iomap.h22
-rw-r--r--fs/xfs/xfs_itable.c8
-rw-r--r--fs/xfs/xfs_log.c16
-rw-r--r--fs/xfs/xfs_log.h11
-rw-r--r--fs/xfs/xfs_log_cil.c4
-rw-r--r--fs/xfs/xfs_log_recover.c42
-rw-r--r--fs/xfs/xfs_mount.c3
-rw-r--r--fs/xfs/xfs_mount.h69
-rw-r--r--fs/xfs/xfs_rename.c63
-rw-r--r--fs/xfs/xfs_rtalloc.c9
-rw-r--r--fs/xfs/xfs_rw.c15
-rw-r--r--fs/xfs/xfs_trans.c211
-rw-r--r--fs/xfs/xfs_trans.h117
-rw-r--r--fs/xfs/xfs_trans_ail.c1
-rw-r--r--fs/xfs/xfs_trans_buf.c75
-rw-r--r--fs/xfs/xfs_trans_extfree.c23
-rw-r--r--fs/xfs/xfs_trans_inode.c74
-rw-r--r--fs/xfs/xfs_trans_item.c441
-rw-r--r--fs/xfs/xfs_trans_priv.h18
-rw-r--r--fs/xfs/xfs_utils.c87
-rw-r--r--fs/xfs/xfs_utils.h1
-rw-r--r--fs/xfs/xfs_vnodeops.c293
-rw-r--r--include/acpi/acoutput.h3
-rw-r--r--include/acpi/acpixf.h13
-rw-r--r--include/acpi/actbl2.h48
-rw-r--r--include/acpi/actypes.h8
-rw-r--r--include/asm-generic/gpio.h15
-rw-r--r--include/asm-generic/local64.h96
-rw-r--r--include/asm-generic/vmlinux.lds.h5
-rw-r--r--include/drm/drm.h2
-rw-r--r--include/drm/drmP.h62
-rw-r--r--include/drm/drm_crtc.h3
-rw-r--r--include/drm/drm_crtc_helper.h5
-rw-r--r--include/drm/drm_fb_helper.h5
-rw-r--r--include/drm/drm_global.h53
-rw-r--r--include/drm/drm_mm.h27
-rw-r--r--include/drm/drm_mode.h1
-rw-r--r--include/drm/drm_pciids.h7
-rw-r--r--include/drm/i2c/sil164.h63
-rw-r--r--include/drm/i915_drm.h9
-rw-r--r--include/drm/radeon_drm.h2
-rw-r--r--include/drm/ttm/ttm_bo_driver.h7
-rw-r--r--include/drm/ttm/ttm_module.h20
-rw-r--r--include/keys/dns_resolver-type.h23
-rw-r--r--include/linux/Kbuild1
-rw-r--r--include/linux/ahci_platform.h4
-rw-r--r--include/linux/atmdev.h17
-rw-r--r--include/linux/brcmphy.h7
-rw-r--r--include/linux/caif/caif_socket.h34
-rw-r--r--include/linux/can/platform/flexcan.h20
-rw-r--r--include/linux/capability.h3
-rw-r--r--include/linux/cgroup.h7
-rw-r--r--include/linux/clocksource.h17
-rw-r--r--include/linux/compiler.h2
-rw-r--r--include/linux/console.h18
-rw-r--r--include/linux/cpu.h27
-rw-r--r--include/linux/cpufreq.h5
-rw-r--r--include/linux/cpuset.h6
-rw-r--r--include/linux/delay.h1
-rw-r--r--include/linux/device.h127
-rw-r--r--include/linux/dmi.h9
-rw-r--r--include/linux/dns_resolver.h34
-rw-r--r--include/linux/dqblk_xfs.h24
-rw-r--r--include/linux/dvb/frontend.h1
-rw-r--r--include/linux/dvb/version.h2
-rw-r--r--include/linux/eeprom_93cx6.h1
-rw-r--r--include/linux/etherdevice.h14
-rw-r--r--include/linux/ethtool.h57
-rw-r--r--include/linux/ext3_fs.h1
-rw-r--r--include/linux/fb.h13
-rw-r--r--include/linux/fdtable.h1
-rw-r--r--include/linux/filter.h48
-rw-r--r--include/linux/firewire-cdev.h501
-rw-r--r--include/linux/firewire.h62
-rw-r--r--include/linux/fs.h4
-rw-r--r--include/linux/fscache-cache.h47
-rw-r--r--include/linux/fscache.h3
-rw-r--r--include/linux/fsl-diu-fb.h (renamed from drivers/video/fsl-diu-fb.h)0
-rw-r--r--include/linux/ftrace.h5
-rw-r--r--include/linux/ftrace_event.h18
-rw-r--r--include/linux/fuse.h34
-rw-r--r--include/linux/hid.h1
-rw-r--r--include/linux/i2c/adp5588.h37
-rw-r--r--include/linux/i2c/mcs.h34
-rw-r--r--include/linux/i2c/mcs5000_ts.h24
-rw-r--r--include/linux/i2c/qt602240_ts.h38
-rw-r--r--include/linux/ide.h2
-rw-r--r--include/linux/if.h2
-rw-r--r--include/linux/if_bonding.h1
-rw-r--r--include/linux/if_bridge.h2
-rw-r--r--include/linux/if_ether.h2
-rw-r--r--include/linux/if_fddi.h8
-rw-r--r--include/linux/if_frad.h2
-rw-r--r--include/linux/if_hippi.h8
-rw-r--r--include/linux/if_link.h5
-rw-r--r--include/linux/if_macvlan.h23
-rw-r--r--include/linux/if_packet.h1
-rw-r--r--include/linux/if_pppox.h8
-rw-r--r--include/linux/in.h1
-rw-r--r--include/linux/input.h60
-rw-r--r--include/linux/input/adxl34x.h349
-rw-r--r--include/linux/input/cy8ctmg110_pdata.h10
-rw-r--r--include/linux/input/matrix_keypad.h6
-rw-r--r--include/linux/intel_pmic_gpio.h15
-rw-r--r--include/linux/interrupt.h7
-rw-r--r--include/linux/io-mapping.h16
-rw-r--r--include/linux/io.h4
-rw-r--r--include/linux/iommu.h1
-rw-r--r--include/linux/ip_vs.h2
-rw-r--r--include/linux/ipv6.h6
-rw-r--r--include/linux/iscsi_boot_sysfs.h123
-rw-r--r--include/linux/iscsi_ibft.h12
-rw-r--r--include/linux/isdnif.h2
-rw-r--r--include/linux/jbd2.h16
-rw-r--r--include/linux/jffs2.h2
-rw-r--r--include/linux/kdb.h4
-rw-r--r--include/linux/kernel.h23
-rw-r--r--include/linux/kgdb.h15
-rw-r--r--include/linux/kmemtrace.h25
-rw-r--r--include/linux/ks8842.h4
-rw-r--r--include/linux/kthread.h65
-rw-r--r--include/linux/kvm.h13
-rw-r--r--include/linux/kvm_host.h35
-rw-r--r--include/linux/kvm_types.h4
-rw-r--r--include/linux/libata.h1
-rw-r--r--include/linux/lru_cache.h2
-rw-r--r--include/linux/lsm_audit.h32
-rw-r--r--include/linux/mISDNif.h2
-rw-r--r--include/linux/marvell_phy.h1
-rw-r--r--include/linux/mm.h8
-rw-r--r--include/linux/msi.h2
-rw-r--r--include/linux/nbd.h2
-rw-r--r--include/linux/ncp.h10
-rw-r--r--include/linux/ncp_fs_sb.h14
-rw-r--r--include/linux/netdevice.h169
-rw-r--r--include/linux/netfilter/Kbuild6
-rw-r--r--include/linux/netfilter/nf_conntrack_common.h4
-rw-r--r--include/linux/netfilter/nfnetlink_log.h1
-rw-r--r--include/linux/netfilter/xt_CHECKSUM.h20
-rw-r--r--include/linux/netfilter/xt_IDLETIMER.h45
-rw-r--r--include/linux/netfilter/xt_cpu.h11
-rw-r--r--include/linux/netfilter/xt_ipvs.h27
-rw-r--r--include/linux/netfilter/xt_quota.h2
-rw-r--r--include/linux/netfilter_ipv4/ipt_LOG.h3
-rw-r--r--include/linux/netfilter_ipv6/ip6t_LOG.h3
-rw-r--r--include/linux/netpoll.h24
-rw-r--r--include/linux/nfs4.h1
-rw-r--r--include/linux/nfs_fs.h13
-rw-r--r--include/linux/nfs_fs_sb.h7
-rw-r--r--include/linux/nfs_mount.h1
-rw-r--r--include/linux/nfs_page.h1
-rw-r--r--include/linux/nfs_xdr.h12
-rw-r--r--include/linux/nilfs2_fs.h65
-rw-r--r--include/linux/nl80211.h24
-rw-r--r--include/linux/nmi.h13
-rw-r--r--include/linux/notifier.h1
-rw-r--r--include/linux/of.h10
-rw-r--r--include/linux/of_address.h44
-rw-r--r--include/linux/of_device.h61
-rw-r--r--include/linux/of_gpio.h35
-rw-r--r--include/linux/of_i2c.h13
-rw-r--r--include/linux/of_irq.h70
-rw-r--r--include/linux/of_platform.h53
-rw-r--r--include/linux/of_spi.h11
-rw-r--r--include/linux/padata.h121
-rw-r--r--include/linux/page-flags.h2
-rw-r--r--include/linux/pci.h2
-rw-r--r--include/linux/pci_ids.h12
-rw-r--r--include/linux/percpu.h20
-rw-r--r--include/linux/perf_event.h97
-rw-r--r--include/linux/phonet.h4
-rw-r--r--include/linux/phy.h24
-rw-r--r--include/linux/platform_device.h62
-rw-r--r--include/linux/plist.h29
-rw-r--r--include/linux/pm.h16
-rw-r--r--include/linux/pm_qos_params.h13
-rw-r--r--include/linux/pm_wakeup.h10
-rw-r--r--include/linux/pnp.h1
-rw-r--r--include/linux/power/jz4740-battery.h24
-rw-r--r--include/linux/ptp_classify.h126
-rw-r--r--include/linux/quotaops.h26
-rw-r--r--include/linux/rar_register.h (renamed from drivers/staging/rar_register/rar_register.h)0
-rw-r--r--include/linux/rcupdate.h82
-rw-r--r--include/linux/rds.h12
-rw-r--r--include/linux/reiserfs_fs.h2
-rw-r--r--include/linux/rtnetlink.h1
-rw-r--r--include/linux/sched.h83
-rw-r--r--include/linux/sctp.h80
-rw-r--r--include/linux/security.h11
-rw-r--r--include/linux/skbuff.h70
-rw-r--r--include/linux/slab.h6
-rw-r--r--include/linux/slab_def.h3
-rw-r--r--include/linux/slow-work.h163
-rw-r--r--include/linux/slub_def.h3
-rw-r--r--include/linux/snmp.h1
-rw-r--r--include/linux/socket.h5
-rw-r--r--include/linux/spi/ads7846.h3
-rw-r--r--include/linux/ssb/ssb.h159
-rw-r--r--include/linux/sunrpc/auth.h21
-rw-r--r--include/linux/sunrpc/cache.h1
-rw-r--r--include/linux/sunrpc/clnt.h5
-rw-r--r--include/linux/sunrpc/sched.h7
-rw-r--r--include/linux/sunrpc/xprt.h1
-rw-r--r--include/linux/suspend.h17
-rw-r--r--include/linux/swiotlb.h27
-rw-r--r--include/linux/syscalls.h2
-rw-r--r--include/linux/sysfs.h12
-rw-r--r--include/linux/time.h21
-rw-r--r--include/linux/timer.h15
-rw-r--r--include/linux/topology.h1
-rw-r--r--include/linux/tty.h3
-rw-r--r--include/linux/types.h5
-rw-r--r--include/linux/u64_stats_sync.h140
-rw-r--r--include/linux/usb/audio-v2.h17
-rw-r--r--include/linux/usb/audio.h12
-rw-r--r--include/linux/usb/video.h404
-rw-r--r--include/linux/user_namespace.h14
-rw-r--r--include/linux/virtio_9p.h1
-rw-r--r--include/linux/vmalloc.h2
-rw-r--r--include/linux/wlp.h22
-rw-r--r--include/linux/workqueue.h158
-rw-r--r--include/linux/xattr.h14
-rw-r--r--include/media/ir-core.h8
-rw-r--r--include/media/ir-kbd-i2c.h2
-rw-r--r--include/media/lirc.h165
-rw-r--r--include/media/lirc_dev.h225
-rw-r--r--include/media/rc-map.h10
-rw-r--r--include/media/sh_mobile_ceu.h3
-rw-r--r--include/media/sh_mobile_csi2.h46
-rw-r--r--include/media/soc_camera.h3
-rw-r--r--include/media/v4l2-mediabus.h13
-rw-r--r--include/media/videobuf-core.h6
-rw-r--r--include/media/videobuf-dma-sg.h39
-rw-r--r--include/media/videobuf-vmalloc.h2
-rw-r--r--include/net/9p/9p.h113
-rw-r--r--include/net/9p/client.h33
-rw-r--r--include/net/act_api.h2
-rw-r--r--include/net/af_unix.h4
-rw-r--r--include/net/bluetooth/bluetooth.h3
-rw-r--r--include/net/bluetooth/hci.h187
-rw-r--r--include/net/bluetooth/hci_core.h30
-rw-r--r--include/net/bluetooth/l2cap.h34
-rw-r--r--include/net/bluetooth/rfcomm.h14
-rw-r--r--include/net/caif/caif_dev.h8
-rw-r--r--include/net/caif/caif_layer.h6
-rw-r--r--include/net/caif/caif_spi.h153
-rw-r--r--include/net/caif/cfcnfg.h16
-rw-r--r--include/net/caif/cfsrvl.h15
-rw-r--r--include/net/cfg80211.h221
-rw-r--r--include/net/dn_dev.h8
-rw-r--r--include/net/dn_nsp.h16
-rw-r--r--include/net/dn_route.h4
-rw-r--r--include/net/genetlink.h15
-rw-r--r--include/net/inet_common.h59
-rw-r--r--include/net/inet_frag.h1
-rw-r--r--include/net/inet_sock.h3
-rw-r--r--include/net/inetpeer.h30
-rw-r--r--include/net/ip.h29
-rw-r--r--include/net/ip6_fib.h10
-rw-r--r--include/net/ip6_tunnel.h2
-rw-r--r--include/net/ip_vs.h14
-rw-r--r--include/net/ipip.h2
-rw-r--r--include/net/ipv6.h16
-rw-r--r--include/net/ipx.h8
-rw-r--r--include/net/irda/irda.h4
-rw-r--r--include/net/irda/irlap_frame.h18
-rw-r--r--include/net/lib80211.h3
-rw-r--r--include/net/mac80211.h145
-rw-r--r--include/net/mip6.h2
-rw-r--r--include/net/ndisc.h2
-rw-r--r--include/net/neighbour.h2
-rw-r--r--include/net/netfilter/nf_conntrack.h17
-rw-r--r--include/net/netfilter/nf_conntrack_acct.h12
-rw-r--r--include/net/netfilter/nf_conntrack_core.h2
-rw-r--r--include/net/netfilter/nf_conntrack_extend.h9
-rw-r--r--include/net/netfilter/nf_nat_protocol.h8
-rw-r--r--include/net/netfilter/nf_nat_rule.h2
-rw-r--r--include/net/netfilter/nfnetlink_log.h2
-rw-r--r--include/net/netfilter/xt_rateest.h11
-rw-r--r--include/net/netlink.h2
-rw-r--r--include/net/phonet/pn_dev.h1
-rw-r--r--include/net/pkt_sched.h2
-rw-r--r--include/net/regulatory.h1
-rw-r--r--include/net/route.h6
-rw-r--r--include/net/sch_generic.h38
-rw-r--r--include/net/scm.h30
-rw-r--r--include/net/sctp/structs.h4
-rw-r--r--include/net/snmp.h75
-rw-r--r--include/net/sock.h14
-rw-r--r--include/net/tcp.h260
-rw-r--r--include/net/udp.h38
-rw-r--r--include/pcmcia/cistpl.h2
-rw-r--r--include/pcmcia/cs.h157
-rw-r--r--include/pcmcia/cs_types.h40
-rw-r--r--include/pcmcia/ds.h251
-rw-r--r--include/pcmcia/ss.h25
-rw-r--r--include/rdma/ib_verbs.h2
-rw-r--r--include/rxrpc/packet.h8
-rw-r--r--include/scsi/fc/fc_els.h11
-rw-r--r--include/scsi/fc/fc_fcoe.h15
-rw-r--r--include/scsi/fc/fc_fip.h46
-rw-r--r--include/scsi/fc/fc_ns.h7
-rw-r--r--include/scsi/fc_encode.h7
-rw-r--r--include/scsi/fc_frame.h52
-rw-r--r--include/scsi/iscsi_if.h2
-rw-r--r--include/scsi/libfc.h75
-rw-r--r--include/scsi/libfcoe.h72
-rw-r--r--include/scsi/libsas.h11
-rw-r--r--include/scsi/scsi_device.h8
-rw-r--r--include/scsi/scsi_transport_iscsi.h2
-rw-r--r--include/sound/asound.h6
-rw-r--r--include/sound/pcm.h8
-rw-r--r--include/sound/sh_fsi.h49
-rw-r--r--include/sound/soc-dapm.h2
-rw-r--r--include/sound/soc.h21
-rw-r--r--include/sound/tlv320dac33-plat.h2
-rw-r--r--include/sound/uda134x.h12
-rw-r--r--include/trace/boot.h60
-rw-r--r--include/trace/events/ext4.h20
-rw-r--r--include/trace/events/power.h27
-rw-r--r--include/trace/events/sched.h32
-rw-r--r--include/trace/events/timer.h80
-rw-r--r--include/trace/events/workqueue.h92
-rw-r--r--include/trace/ftrace.h23
-rw-r--r--include/trace/syscall.h1
-rw-r--r--include/xen/events.h7
-rw-r--r--include/xen/grant_table.h4
-rw-r--r--include/xen/hvm.h30
-rw-r--r--include/xen/interface/features.h6
-rw-r--r--include/xen/interface/grant_table.h1
-rw-r--r--include/xen/interface/hvm/hvm_op.h46
-rw-r--r--include/xen/interface/hvm/params.h95
-rw-r--r--include/xen/platform_pci.h49
-rw-r--r--include/xen/xen-ops.h3
-rw-r--r--init/Kconfig24
-rw-r--r--init/main.c37
-rw-r--r--kernel/Makefile4
-rw-r--r--kernel/async.c141
-rw-r--r--kernel/audit.c2
-rw-r--r--kernel/cgroup.c36
-rw-r--r--kernel/cpu.c6
-rw-r--r--kernel/cpuset.c23
-rw-r--r--kernel/debug/debug_core.c4
-rw-r--r--kernel/debug/gdbstub.c191
-rw-r--r--kernel/debug/kdb/kdb_main.c136
-rw-r--r--kernel/debug/kdb/kdb_private.h2
-rw-r--r--kernel/fork.c2
-rw-r--r--kernel/hrtimer.c17
-rw-r--r--kernel/hw_breakpoint.c90
-rw-r--r--kernel/irq/manage.c2
-rw-r--r--kernel/kthread.c164
-rw-r--r--kernel/lockdep.c2
-rw-r--r--kernel/module.c1088
-rw-r--r--kernel/padata.c755
-rw-r--r--kernel/perf_event.c460
-rw-r--r--kernel/pm_qos_params.c215
-rw-r--r--kernel/posix-cpu-timers.c36
-rw-r--r--kernel/posix-timers.c11
-rw-r--r--kernel/power/hibernate.c26
-rw-r--r--kernel/power/main.c55
-rw-r--r--kernel/power/process.c21
-rw-r--r--kernel/power/snapshot.c2
-rw-r--r--kernel/power/suspend.c13
-rw-r--r--kernel/power/swap.c6
-rw-r--r--kernel/printk.c33
-rw-r--r--kernel/rcupdate.c160
-rw-r--r--kernel/rcutiny.c2
-rw-r--r--kernel/rcutorture.c3
-rw-r--r--kernel/rcutree.c2
-rw-r--r--kernel/sched.c397
-rw-r--r--kernel/sched_clock.c95
-rw-r--r--kernel/sched_cpupri.c8
-rw-r--r--kernel/sched_cpupri.h2
-rw-r--r--kernel/sched_debug.c2
-rw-r--r--kernel/sched_fair.c532
-rw-r--r--kernel/sched_rt.c3
-rw-r--r--kernel/sched_stats.h27
-rw-r--r--kernel/signal.c9
-rw-r--r--kernel/slow-work-debugfs.c227
-rw-r--r--kernel/slow-work.c1068
-rw-r--r--kernel/slow-work.h72
-rw-r--r--kernel/softlockup.c293
-rw-r--r--kernel/sysctl.c65
-rw-r--r--kernel/time.c16
-rw-r--r--kernel/time/Kconfig4
-rw-r--r--kernel/time/clocksource.c33
-rw-r--r--kernel/time/tick-broadcast.c2
-rw-r--r--kernel/time/tick-sched.c15
-rw-r--r--kernel/time/timekeeping.c79
-rw-r--r--kernel/timer.c53
-rw-r--r--kernel/trace/Kconfig83
-rw-r--r--kernel/trace/Makefile7
-rw-r--r--kernel/trace/ftrace.c5
-rw-r--r--kernel/trace/kmemtrace.c529
-rw-r--r--kernel/trace/ring_buffer.c40
-rw-r--r--kernel/trace/trace.c178
-rw-r--r--kernel/trace/trace.h107
-rw-r--r--kernel/trace/trace_boot.c185
-rw-r--r--kernel/trace/trace_clock.c7
-rw-r--r--kernel/trace/trace_entries.h94
-rw-r--r--kernel/trace/trace_event_perf.c27
-rw-r--r--kernel/trace/trace_events.c299
-rw-r--r--kernel/trace/trace_events_filter.c27
-rw-r--r--kernel/trace/trace_export.c8
-rw-r--r--kernel/trace/trace_functions.c6
-rw-r--r--kernel/trace/trace_functions_graph.c3
-rw-r--r--kernel/trace/trace_irqsoff.c3
-rw-r--r--kernel/trace/trace_kdb.c136
-rw-r--r--kernel/trace/trace_kprobe.c383
-rw-r--r--kernel/trace/trace_ksym.c508
-rw-r--r--kernel/trace/trace_output.c69
-rw-r--r--kernel/trace/trace_sched_wakeup.c7
-rw-r--r--kernel/trace/trace_selftest.c87
-rw-r--r--kernel/trace/trace_stack.c6
-rw-r--r--kernel/trace/trace_syscalls.c7
-rw-r--r--kernel/trace/trace_sysprof.c329
-rw-r--r--kernel/user_namespace.c44
-rw-r--r--kernel/watchdog.c567
-rw-r--r--kernel/workqueue.c3175
-rw-r--r--kernel/workqueue_sched.h9
-rw-r--r--lib/Kconfig.debug63
-rw-r--r--lib/devres.c2
-rw-r--r--lib/ioremap.c10
-rw-r--r--lib/random32.c2
-rw-r--r--lib/swiotlb.c137
-rw-r--r--lib/vsprintf.c9
-rw-r--r--mm/backing-dev.c1
-rw-r--r--mm/highmem.c7
-rw-r--r--mm/memory-failure.c33
-rw-r--r--mm/mmap.c6
-rw-r--r--mm/percpu.c85
-rw-r--r--mm/slab.c3
-rw-r--r--mm/slob.c14
-rw-r--r--mm/slub.c87
-rw-r--r--mm/vmalloc.c2
-rw-r--r--net/8021q/vlan.c13
-rw-r--r--net/8021q/vlan.h13
-rw-r--r--net/8021q/vlan_core.c26
-rw-r--r--net/8021q/vlan_dev.c161
-rw-r--r--net/8021q/vlanproc.c16
-rw-r--r--net/9p/client.c393
-rw-r--r--net/9p/protocol.c72
-rw-r--r--net/9p/trans_fd.c2
-rw-r--r--net/Kconfig13
-rw-r--r--net/Makefile5
-rw-r--r--net/atm/br2684.c66
-rw-r--r--net/atm/clip.c2
-rw-r--r--net/atm/common.c30
-rw-r--r--net/bluetooth/Kconfig13
-rw-r--r--net/bluetooth/bnep/bnep.h8
-rw-r--r--net/bluetooth/hci_conn.c34
-rw-r--r--net/bluetooth/hci_core.c204
-rw-r--r--net/bluetooth/hci_event.c39
-rw-r--r--net/bluetooth/hci_sock.c90
-rw-r--r--net/bluetooth/hci_sysfs.c38
-rw-r--r--net/bluetooth/l2cap.c669
-rw-r--r--net/bluetooth/rfcomm/sock.c2
-rw-r--r--net/bluetooth/rfcomm/tty.c4
-rw-r--r--net/bridge/br.c2
-rw-r--r--net/bridge/br_device.c142
-rw-r--r--net/bridge/br_fdb.c6
-rw-r--r--net/bridge/br_forward.c11
-rw-r--r--net/bridge/br_if.c33
-rw-r--r--net/bridge/br_input.c24
-rw-r--r--net/bridge/br_multicast.c11
-rw-r--r--net/bridge/br_netfilter.c60
-rw-r--r--net/bridge/br_netlink.c9
-rw-r--r--net/bridge/br_notify.c5
-rw-r--r--net/bridge/br_private.h67
-rw-r--r--net/bridge/br_stp_bpdu.c7
-rw-r--r--net/bridge/br_sysfs_br.c72
-rw-r--r--net/bridge/netfilter/ebt_redirect.c3
-rw-r--r--net/bridge/netfilter/ebt_ulog.c8
-rw-r--r--net/bridge/netfilter/ebtables.c11
-rw-r--r--net/caif/Kconfig7
-rw-r--r--net/caif/Makefile14
-rw-r--r--net/caif/caif_config_util.c5
-rw-r--r--net/caif/caif_dev.c12
-rw-r--r--net/caif/caif_socket.c61
-rw-r--r--net/caif/cfcnfg.c54
-rw-r--r--net/caif/cfctrl.c8
-rw-r--r--net/caif/cfdbgl.c2
-rw-r--r--net/caif/cfdgml.c7
-rw-r--r--net/caif/cfpkt_skbuff.c5
-rw-r--r--net/caif/cfrfml.c318
-rw-r--r--net/caif/cfserl.c7
-rw-r--r--net/caif/cfsrvl.c26
-rw-r--r--net/caif/cfutill.c8
-rw-r--r--net/caif/cfveil.c7
-rw-r--r--net/caif/cfvidl.c2
-rw-r--r--net/caif/chnl_net.c67
-rw-r--r--net/can/raw.c15
-rw-r--r--net/compat.c53
-rw-r--r--net/core/Makefile2
-rw-r--r--net/core/datagram.c8
-rw-r--r--net/core/dev.c387
-rw-r--r--net/core/drop_monitor.c33
-rw-r--r--net/core/dst.c2
-rw-r--r--net/core/ethtool.c108
-rw-r--r--net/core/filter.c212
-rw-r--r--net/core/flow.c9
-rw-r--r--net/core/gen_estimator.c1
-rw-r--r--net/core/gen_stats.c14
-rw-r--r--net/core/iovec.c9
-rw-r--r--net/core/link_watch.c1
-rw-r--r--net/core/net-sysfs.c19
-rw-r--r--net/core/netevent.c5
-rw-r--r--net/core/netpoll.c182
-rw-r--r--net/core/pktgen.c212
-rw-r--r--net/core/rtnetlink.c11
-rw-r--r--net/core/scm.c33
-rw-r--r--net/core/skbuff.c3
-rw-r--r--net/core/sock.c49
-rw-r--r--net/core/stream.c6
-rw-r--r--net/core/timestamping.c126
-rw-r--r--net/core/utils.c3
-rw-r--r--net/dccp/ackvec.c4
-rw-r--r--net/dccp/ccids/ccid3.c4
-rw-r--r--net/dccp/dccp.h12
-rw-r--r--net/dccp/input.c13
-rw-r--r--net/dccp/ipv4.c4
-rw-r--r--net/dccp/ipv6.c30
-rw-r--r--net/dccp/options.c20
-rw-r--r--net/dccp/proto.c14
-rw-r--r--net/decnet/dn_route.c158
-rw-r--r--net/dns_resolver/Kconfig27
-rw-r--r--net/dns_resolver/Makefile7
-rw-r--r--net/dns_resolver/dns_key.c211
-rw-r--r--net/dns_resolver/dns_query.c160
-rw-r--r--net/dns_resolver/internal.h44
-rw-r--r--net/dsa/slave.c3
-rw-r--r--net/econet/af_econet.c27
-rw-r--r--net/ethernet/eth.c5
-rw-r--r--net/ethernet/pe2.c3
-rw-r--r--net/ipv4/af_inet.c84
-rw-r--r--net/ipv4/arp.c51
-rw-r--r--net/ipv4/datagram.c4
-rw-r--r--net/ipv4/devinet.c1
-rw-r--r--net/ipv4/fib_frontend.c13
-rw-r--r--net/ipv4/icmp.c37
-rw-r--r--net/ipv4/igmp.c32
-rw-r--r--net/ipv4/inet_connection_sock.c21
-rw-r--r--net/ipv4/inet_fragment.c1
-rw-r--r--net/ipv4/inet_hashtables.c4
-rw-r--r--net/ipv4/inetpeer.c244
-rw-r--r--net/ipv4/ip_forward.c10
-rw-r--r--net/ipv4/ip_fragment.c27
-rw-r--r--net/ipv4/ip_gre.c16
-rw-r--r--net/ipv4/ip_input.c26
-rw-r--r--net/ipv4/ip_output.c78
-rw-r--r--net/ipv4/ip_sockglue.c45
-rw-r--r--net/ipv4/ipconfig.c7
-rw-r--r--net/ipv4/ipip.c8
-rw-r--r--net/ipv4/ipmr.c8
-rw-r--r--net/ipv4/netfilter.c12
-rw-r--r--net/ipv4/netfilter/arp_tables.c22
-rw-r--r--net/ipv4/netfilter/ip_queue.c57
-rw-r--r--net/ipv4/netfilter/ip_tables.c16
-rw-r--r--net/ipv4/netfilter/ipt_CLUSTERIP.c50
-rw-r--r--net/ipv4/netfilter/ipt_LOG.c54
-rw-r--r--net/ipv4/netfilter/ipt_NETMAP.c6
-rw-r--r--net/ipv4/netfilter/ipt_REJECT.c12
-rw-r--r--net/ipv4/netfilter/nf_defrag_ipv4.c5
-rw-r--r--net/ipv4/netfilter/nf_nat_core.c29
-rw-r--r--net/ipv4/netfilter/nf_nat_proto_common.c12
-rw-r--r--net/ipv4/netfilter/nf_nat_proto_dccp.c6
-rw-r--r--net/ipv4/netfilter/nf_nat_proto_gre.c12
-rw-r--r--net/ipv4/netfilter/nf_nat_proto_icmp.c10
-rw-r--r--net/ipv4/netfilter/nf_nat_proto_sctp.c6
-rw-r--r--net/ipv4/netfilter/nf_nat_proto_tcp.c5
-rw-r--r--net/ipv4/netfilter/nf_nat_proto_udp.c5
-rw-r--r--net/ipv4/netfilter/nf_nat_proto_udplite.c6
-rw-r--r--net/ipv4/netfilter/nf_nat_proto_unknown.c4
-rw-r--r--net/ipv4/netfilter/nf_nat_rule.c10
-rw-r--r--net/ipv4/netfilter/nf_nat_standalone.c10
-rw-r--r--net/ipv4/proc.c16
-rw-r--r--net/ipv4/protocol.c3
-rw-r--r--net/ipv4/raw.c22
-rw-r--r--net/ipv4/route.c518
-rw-r--r--net/ipv4/syncookies.c105
-rw-r--r--net/ipv4/tcp.c78
-rw-r--r--net/ipv4/tcp_input.c20
-rw-r--r--net/ipv4/tcp_ipv4.c175
-rw-r--r--net/ipv4/tcp_minisocks.c9
-rw-r--r--net/ipv4/tcp_output.c77
-rw-r--r--net/ipv4/tcp_timer.c1
-rw-r--r--net/ipv4/tunnel4.c2
-rw-r--r--net/ipv4/udp.c4
-rw-r--r--net/ipv4/udplite.c3
-rw-r--r--net/ipv4/xfrm4_input.c1
-rw-r--r--net/ipv4/xfrm4_policy.c2
-rw-r--r--net/ipv6/addrconf.c53
-rw-r--r--net/ipv6/addrlabel.c6
-rw-r--r--net/ipv6/af_inet6.c32
-rw-r--r--net/ipv6/anycast.c96
-rw-r--r--net/ipv6/datagram.c18
-rw-r--r--net/ipv6/exthdrs.c34
-rw-r--r--net/ipv6/fib6_rules.c10
-rw-r--r--net/ipv6/inet6_connection_sock.c9
-rw-r--r--net/ipv6/ip6_fib.c30
-rw-r--r--net/ipv6/ip6_output.c38
-rw-r--r--net/ipv6/ip6_tunnel.c8
-rw-r--r--net/ipv6/ipv6_sockglue.c2
-rw-r--r--net/ipv6/mcast.c190
-rw-r--r--net/ipv6/ndisc.c8
-rw-r--r--net/ipv6/netfilter.c4
-rw-r--r--net/ipv6/netfilter/ip6_queue.c57
-rw-r--r--net/ipv6/netfilter/ip6_tables.c21
-rw-r--r--net/ipv6/netfilter/ip6t_LOG.c81
-rw-r--r--net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c2
-rw-r--r--net/ipv6/netfilter/nf_conntrack_reasm.c20
-rw-r--r--net/ipv6/proc.c17
-rw-r--r--net/ipv6/raw.c32
-rw-r--r--net/ipv6/reassembly.c21
-rw-r--r--net/ipv6/route.c319
-rw-r--r--net/ipv6/sit.c16
-rw-r--r--net/ipv6/syncookies.c58
-rw-r--r--net/ipv6/tcp_ipv6.c47
-rw-r--r--net/ipv6/udp.c11
-rw-r--r--net/irda/irnet/irnet_ppp.c10
-rw-r--r--net/irda/irttp.c14
-rw-r--r--net/iucv/iucv.c14
-rw-r--r--net/l2tp/l2tp_ip.c6
-rw-r--r--net/mac80211/Kconfig8
-rw-r--r--net/mac80211/Makefile4
-rw-r--r--net/mac80211/agg-rx.c123
-rw-r--r--net/mac80211/agg-tx.c554
-rw-r--r--net/mac80211/cfg.c124
-rw-r--r--net/mac80211/debugfs.c154
-rw-r--r--net/mac80211/debugfs_key.c2
-rw-r--r--net/mac80211/debugfs_sta.c65
-rw-r--r--net/mac80211/driver-ops.h102
-rw-r--r--net/mac80211/driver-trace.h210
-rw-r--r--net/mac80211/ht.c52
-rw-r--r--net/mac80211/ibss.c171
-rw-r--r--net/mac80211/ieee80211_i.h81
-rw-r--r--net/mac80211/iface.c190
-rw-r--r--net/mac80211/key.c295
-rw-r--r--net/mac80211/key.h33
-rw-r--r--net/mac80211/main.c124
-rw-r--r--net/mac80211/mesh.c73
-rw-r--r--net/mac80211/mesh.h2
-rw-r--r--net/mac80211/mesh_hwmp.c4
-rw-r--r--net/mac80211/mesh_pathtbl.c4
-rw-r--r--net/mac80211/mesh_plink.c42
-rw-r--r--net/mac80211/mlme.c284
-rw-r--r--net/mac80211/pm.c18
-rw-r--r--net/mac80211/rate.h13
-rw-r--r--net/mac80211/rc80211_minstrel.c1
-rw-r--r--net/mac80211/rc80211_minstrel_ht.c827
-rw-r--r--net/mac80211/rc80211_minstrel_ht.h130
-rw-r--r--net/mac80211/rc80211_minstrel_ht_debugfs.c118
-rw-r--r--net/mac80211/rx.c195
-rw-r--r--net/mac80211/scan.c6
-rw-r--r--net/mac80211/sta_info.c24
-rw-r--r--net/mac80211/sta_info.h113
-rw-r--r--net/mac80211/status.c6
-rw-r--r--net/mac80211/tkip.c8
-rw-r--r--net/mac80211/tkip.h2
-rw-r--r--net/mac80211/tx.c112
-rw-r--r--net/mac80211/util.c42
-rw-r--r--net/mac80211/wep.c29
-rw-r--r--net/mac80211/wep.h2
-rw-r--r--net/mac80211/work.c45
-rw-r--r--net/mac80211/wpa.c13
-rw-r--r--net/netfilter/Kconfig71
-rw-r--r--net/netfilter/Makefile4
-rw-r--r--net/netfilter/ipvs/Kconfig11
-rw-r--r--net/netfilter/ipvs/ip_vs_app.c43
-rw-r--r--net/netfilter/ipvs/ip_vs_conn.c55
-rw-r--r--net/netfilter/ipvs/ip_vs_core.c57
-rw-r--r--net/netfilter/ipvs/ip_vs_ctl.c10
-rw-r--r--net/netfilter/ipvs/ip_vs_ftp.c176
-rw-r--r--net/netfilter/ipvs/ip_vs_lblc.c2
-rw-r--r--net/netfilter/ipvs/ip_vs_lblcr.c2
-rw-r--r--net/netfilter/ipvs/ip_vs_proto.c1
-rw-r--r--net/netfilter/ipvs/ip_vs_proto_sctp.c55
-rw-r--r--net/netfilter/ipvs/ip_vs_proto_tcp.c50
-rw-r--r--net/netfilter/ipvs/ip_vs_proto_udp.c56
-rw-r--r--net/netfilter/ipvs/ip_vs_xmit.c115
-rw-r--r--net/netfilter/nf_conntrack_acct.c14
-rw-r--r--net/netfilter/nf_conntrack_core.c49
-rw-r--r--net/netfilter/nf_conntrack_extend.c22
-rw-r--r--net/netfilter/nf_conntrack_h323_main.c12
-rw-r--r--net/netfilter/nf_conntrack_netbios_ns.c2
-rw-r--r--net/netfilter/nf_conntrack_netlink.c2
-rw-r--r--net/netfilter/nf_conntrack_proto_tcp.c42
-rw-r--r--net/netfilter/nfnetlink_log.c73
-rw-r--r--net/netfilter/nfnetlink_queue.c39
-rw-r--r--net/netfilter/xt_CHECKSUM.c70
-rw-r--r--net/netfilter/xt_CT.c4
-rw-r--r--net/netfilter/xt_IDLETIMER.c315
-rw-r--r--net/netfilter/xt_NOTRACK.c2
-rw-r--r--net/netfilter/xt_RATEEST.c12
-rw-r--r--net/netfilter/xt_TCPMSS.c8
-rw-r--r--net/netfilter/xt_TEE.c8
-rw-r--r--net/netfilter/xt_TPROXY.c6
-rw-r--r--net/netfilter/xt_cluster.c2
-rw-r--r--net/netfilter/xt_connbytes.c10
-rw-r--r--net/netfilter/xt_conntrack.c11
-rw-r--r--net/netfilter/xt_cpu.c63
-rw-r--r--net/netfilter/xt_ipvs.c189
-rw-r--r--net/netfilter/xt_quota.c12
-rw-r--r--net/netfilter/xt_sctp.c3
-rw-r--r--net/netfilter/xt_socket.c2
-rw-r--r--net/netfilter/xt_state.c14
-rw-r--r--net/netfilter/xt_statistic.c19
-rw-r--r--net/netlink/af_netlink.c42
-rw-r--r--net/netlink/genetlink.c15
-rw-r--r--net/packet/af_packet.c37
-rw-r--r--net/phonet/pn_dev.c15
-rw-r--r--net/rose/rose_route.c4
-rw-r--r--net/rxrpc/ar-peer.c4
-rw-r--r--net/sched/act_api.c11
-rw-r--r--net/sched/act_mirred.c12
-rw-r--r--net/sched/act_nat.c34
-rw-r--r--net/sched/act_pedit.c3
-rw-r--r--net/sched/act_police.c12
-rw-r--r--net/sched/act_simple.c4
-rw-r--r--net/sched/cls_u32.c6
-rw-r--r--net/sched/sch_atm.c98
-rw-r--r--net/sched/sch_generic.c25
-rw-r--r--net/sched/sch_htb.c2
-rw-r--r--net/sctp/associola.c2
-rw-r--r--net/sctp/protocol.c9
-rw-r--r--net/sctp/sm_make_chunk.c2
-rw-r--r--net/socket.c177
-rw-r--r--net/sunrpc/auth.c157
-rw-r--r--net/sunrpc/auth_generic.c23
-rw-r--r--net/sunrpc/auth_gss/auth_gss.c29
-rw-r--r--net/sunrpc/auth_null.c2
-rw-r--r--net/sunrpc/auth_unix.c21
-rw-r--r--net/sunrpc/cache.c8
-rw-r--r--net/sunrpc/clnt.c182
-rw-r--r--net/sunrpc/sched.c104
-rw-r--r--net/sunrpc/sunrpc_syms.c16
-rw-r--r--net/sunrpc/xprt.c3
-rw-r--r--net/unix/af_unix.c99
-rw-r--r--net/wanrouter/wanmain.c7
-rw-r--r--net/wanrouter/wanproc.c7
-rw-r--r--net/wireless/chan.c5
-rw-r--r--net/wireless/core.c65
-rw-r--r--net/wireless/core.h1
-rw-r--r--net/wireless/genregdb.awk1
-rw-r--r--net/wireless/ibss.c4
-rw-r--r--net/wireless/lib80211_crypt_ccmp.c1
-rw-r--r--net/wireless/lib80211_crypt_tkip.c3
-rw-r--r--net/wireless/lib80211_crypt_wep.c1
-rw-r--r--net/wireless/mlme.c16
-rw-r--r--net/wireless/nl80211.c93
-rw-r--r--net/wireless/reg.c668
-rw-r--r--net/wireless/reg.h2
-rw-r--r--net/wireless/scan.c5
-rw-r--r--net/wireless/sme.c2
-rw-r--r--net/wireless/util.c4
-rw-r--r--net/wireless/wext-compat.c11
-rw-r--r--net/xfrm/xfrm_policy.c3
-rw-r--r--samples/kprobes/kprobe_example.c9
-rw-r--r--scripts/Makefile.build37
-rw-r--r--scripts/Makefile.help3
-rw-r--r--scripts/Makefile.modpost9
-rwxr-xr-xscripts/checkkconfigsymbols.sh2
-rwxr-xr-xscripts/coccicheck80
-rw-r--r--scripts/coccinelle/alloc/drop_kmalloc_cast.cocci67
-rw-r--r--scripts/coccinelle/alloc/kzalloc-simple.cocci82
-rw-r--r--scripts/coccinelle/deref_null.cocci293
-rw-r--r--scripts/coccinelle/err_cast.cocci56
-rw-r--r--scripts/coccinelle/resource_size.cocci93
-rwxr-xr-xscripts/decodecode10
-rw-r--r--scripts/dtc/fstree.c1
-rw-r--r--scripts/kconfig/.gitignore1
-rw-r--r--scripts/kconfig/Makefile77
-rw-r--r--scripts/kconfig/conf.c181
-rw-r--r--scripts/kconfig/confdata.c221
-rw-r--r--scripts/kconfig/expr.c2
-rw-r--r--scripts/kconfig/expr.h3
-rw-r--r--scripts/kconfig/gconf.c7
-rw-r--r--scripts/kconfig/lkc.h2
-rw-r--r--scripts/kconfig/lkc_proto.h1
-rw-r--r--scripts/kconfig/lxdialog/checklist.c10
-rw-r--r--scripts/kconfig/mconf.c2
-rw-r--r--scripts/kconfig/menu.c27
-rw-r--r--scripts/kconfig/qconf.cc106
-rw-r--r--scripts/kconfig/qconf.h17
-rw-r--r--scripts/kconfig/symbol.c292
-rw-r--r--scripts/mod/file2alias.c6
-rw-r--r--scripts/mod/modpost.c102
-rw-r--r--scripts/mod/modpost.h43
-rw-r--r--scripts/package/Makefile37
-rw-r--r--scripts/package/builddeb5
-rwxr-xr-xscripts/recordmcount.pl2
-rw-r--r--security/Kconfig6
-rw-r--r--security/Makefile2
-rw-r--r--security/apparmor/.gitignore5
-rw-r--r--security/apparmor/Kconfig31
-rw-r--r--security/apparmor/Makefile24
-rw-r--r--security/apparmor/apparmorfs.c239
-rw-r--r--security/apparmor/audit.c215
-rw-r--r--security/apparmor/capability.c141
-rw-r--r--security/apparmor/context.c216
-rw-r--r--security/apparmor/domain.c823
-rw-r--r--security/apparmor/file.c457
-rw-r--r--security/apparmor/include/apparmor.h92
-rw-r--r--security/apparmor/include/apparmorfs.h20
-rw-r--r--security/apparmor/include/audit.h123
-rw-r--r--security/apparmor/include/capability.h45
-rw-r--r--security/apparmor/include/context.h154
-rw-r--r--security/apparmor/include/domain.h36
-rw-r--r--security/apparmor/include/file.h217
-rw-r--r--security/apparmor/include/ipc.h28
-rw-r--r--security/apparmor/include/match.h132
-rw-r--r--security/apparmor/include/path.h31
-rw-r--r--security/apparmor/include/policy.h305
-rw-r--r--security/apparmor/include/policy_unpack.h20
-rw-r--r--security/apparmor/include/procattr.h26
-rw-r--r--security/apparmor/include/resource.h46
-rw-r--r--security/apparmor/include/sid.h24
-rw-r--r--security/apparmor/ipc.c114
-rw-r--r--security/apparmor/lib.c133
-rw-r--r--security/apparmor/lsm.c938
-rw-r--r--security/apparmor/match.c353
-rw-r--r--security/apparmor/path.c235
-rw-r--r--security/apparmor/policy.c1184
-rw-r--r--security/apparmor/policy_unpack.c703
-rw-r--r--security/apparmor/procattr.c170
-rw-r--r--security/apparmor/resource.c134
-rw-r--r--security/apparmor/sid.c55
-rw-r--r--security/capability.c5
-rw-r--r--security/inode.c4
-rw-r--r--security/integrity/ima/ima_fs.c9
-rw-r--r--security/keys/internal.h5
-rw-r--r--security/keys/keyctl.c29
-rw-r--r--security/keys/proc.c20
-rw-r--r--security/keys/process_keys.c64
-rw-r--r--security/keys/request_key.c3
-rw-r--r--security/security.c5
-rw-r--r--security/selinux/Makefile2
-rw-r--r--security/selinux/avc.c25
-rw-r--r--security/selinux/hooks.c292
-rw-r--r--security/selinux/include/classmap.h16
-rw-r--r--security/selinux/netnode.c2
-rw-r--r--security/selinux/selinuxfs.c16
-rw-r--r--security/selinux/ss/avtab.c39
-rw-r--r--security/selinux/ss/conditional.c65
-rw-r--r--security/selinux/ss/policydb.c658
-rw-r--r--security/selinux/ss/policydb.h4
-rw-r--r--security/selinux/ss/services.c7
-rw-r--r--security/selinux/ss/symtab.c2
-rw-r--r--security/smack/smack.h10
-rw-r--r--security/smack/smack_lsm.c18
-rw-r--r--security/tomoyo/Makefile2
-rw-r--r--security/tomoyo/common.c2836
-rw-r--r--security/tomoyo/common.h850
-rw-r--r--security/tomoyo/domain.c855
-rw-r--r--security/tomoyo/file.c1533
-rw-r--r--security/tomoyo/gc.c360
-rw-r--r--security/tomoyo/group.c130
-rw-r--r--security/tomoyo/load_policy.c81
-rw-r--r--security/tomoyo/memory.c282
-rw-r--r--security/tomoyo/mount.c284
-rw-r--r--security/tomoyo/path_group.c172
-rw-r--r--security/tomoyo/realpath.c426
-rw-r--r--security/tomoyo/securityfs_if.c155
-rw-r--r--security/tomoyo/tomoyo.c35
-rw-r--r--security/tomoyo/util.c963
-rw-r--r--sound/core/pcm_lib.c25
-rw-r--r--sound/core/pcm_misc.c16
-rw-r--r--sound/core/pcm_native.c13
-rw-r--r--sound/drivers/Kconfig26
-rw-r--r--sound/isa/msnd/msnd_pinnacle.c5
-rw-r--r--sound/isa/sb/emu8000_pcm.c9
-rw-r--r--sound/oss/au1550_ac97.c91
-rw-r--r--sound/oss/dmasound/dmasound_core.c63
-rw-r--r--sound/oss/midi_synth.c4
-rw-r--r--sound/oss/msnd_pinnacle.c35
-rw-r--r--sound/oss/sh_dac_audio.c27
-rw-r--r--sound/oss/soundcard.c20
-rw-r--r--sound/oss/swarm_cs4297a.c41
-rw-r--r--sound/oss/vidc.c3
-rw-r--r--sound/oss/vwsnd.c32
-rw-r--r--sound/oss/waveartist.c10
-rw-r--r--sound/pci/als4000.c4
-rw-r--r--sound/pci/asihpi/asihpi.c16
-rw-r--r--sound/pci/asihpi/hpi.h68
-rw-r--r--sound/pci/asihpi/hpi6000.c7
-rw-r--r--sound/pci/asihpi/hpi_internal.h40
-rw-r--r--sound/pci/asihpi/hpicmn.c10
-rw-r--r--sound/pci/asihpi/hpidebug.c2
-rw-r--r--sound/pci/asihpi/hpidebug.h4
-rw-r--r--sound/pci/asihpi/hpifunc.c327
-rw-r--r--sound/pci/asihpi/hpimsgx.c2
-rw-r--r--sound/pci/asihpi/hpioctl.c21
-rw-r--r--sound/pci/echoaudio/echoaudio.c2
-rw-r--r--sound/pci/hda/hda_codec.c97
-rw-r--r--sound/pci/hda/hda_codec.h32
-rw-r--r--sound/pci/hda/hda_hwdep.c4
-rw-r--r--sound/pci/hda/hda_intel.c5
-rw-r--r--sound/pci/hda/hda_proc.c7
-rw-r--r--sound/pci/hda/patch_analog.c7
-rw-r--r--sound/pci/hda/patch_conexant.c95
-rw-r--r--sound/pci/hda/patch_hdmi.c43
-rw-r--r--sound/pci/hda/patch_intelhdmi.c3
-rw-r--r--sound/pci/hda/patch_nvhdmi.c3
-rw-r--r--sound/pci/hda/patch_realtek.c720
-rw-r--r--sound/pci/hda/patch_sigmatel.c12
-rw-r--r--sound/pci/hda/patch_via.c32
-rw-r--r--sound/pci/riptide/riptide.c18
-rw-r--r--sound/pci/sis7019.c16
-rw-r--r--sound/pci/trident/trident_main.c2
-rw-r--r--sound/pci/via82xx.c9
-rw-r--r--sound/pcmcia/pdaudiocf/pdaudiocf.c9
-rw-r--r--sound/pcmcia/pdaudiocf/pdaudiocf.h1
-rw-r--r--sound/pcmcia/vx/vxpocket.c9
-rw-r--r--sound/pcmcia/vx/vxpocket.h1
-rw-r--r--sound/soc/Kconfig4
-rw-r--r--sound/soc/Makefile4
-rw-r--r--sound/soc/atmel/atmel-pcm.c1
-rw-r--r--sound/soc/atmel/atmel_ssc_dai.c1
-rw-r--r--sound/soc/au1x/psc-ac97.c13
-rw-r--r--sound/soc/au1x/psc-i2s.c13
-rw-r--r--sound/soc/au1x/psc.h1
-rw-r--r--sound/soc/blackfin/bf5xx-ac97.c6
-rw-r--r--sound/soc/blackfin/bf5xx-tdm.c6
-rw-r--r--sound/soc/codecs/Kconfig20
-rw-r--r--sound/soc/codecs/Makefile6
-rw-r--r--sound/soc/codecs/ad1836.c1
-rw-r--r--sound/soc/codecs/ad193x.c41
-rw-r--r--sound/soc/codecs/ad193x.h5
-rw-r--r--sound/soc/codecs/ak4642.c36
-rw-r--r--sound/soc/codecs/cs42l51.c763
-rw-r--r--sound/soc/codecs/cs42l51.h163
-rw-r--r--sound/soc/codecs/da7210.c48
-rw-r--r--sound/soc/codecs/jz4740.c511
-rw-r--r--sound/soc/codecs/jz4740.h20
-rw-r--r--sound/soc/codecs/spdif_transciever.c94
-rw-r--r--sound/soc/codecs/spdif_transciever.h1
-rw-r--r--sound/soc/codecs/tlv320aic23.c7
-rw-r--r--sound/soc/codecs/tlv320dac33.c180
-rw-r--r--sound/soc/codecs/twl4030.c388
-rw-r--r--sound/soc/codecs/twl4030.h4
-rw-r--r--sound/soc/codecs/twl6040.c58
-rw-r--r--sound/soc/codecs/uda134x.c64
-rw-r--r--sound/soc/codecs/uda134x.h5
-rw-r--r--sound/soc/codecs/wm2000.c2
-rw-r--r--sound/soc/codecs/wm8523.c10
-rw-r--r--sound/soc/codecs/wm8711.c3
-rw-r--r--sound/soc/codecs/wm8741.c579
-rw-r--r--sound/soc/codecs/wm8741.h214
-rw-r--r--sound/soc/codecs/wm8750.c11
-rw-r--r--sound/soc/codecs/wm8904.c13
-rw-r--r--sound/soc/codecs/wm8940.c7
-rw-r--r--sound/soc/codecs/wm8955.c10
-rw-r--r--sound/soc/codecs/wm8960.c99
-rw-r--r--sound/soc/codecs/wm8961.c9
-rw-r--r--sound/soc/codecs/wm8974.c3
-rw-r--r--sound/soc/codecs/wm8978.c10
-rw-r--r--sound/soc/codecs/wm8990.c4
-rw-r--r--sound/soc/codecs/wm8994.c75
-rw-r--r--sound/soc/codecs/wm8994.h3
-rw-r--r--sound/soc/codecs/wm9081.c11
-rw-r--r--sound/soc/codecs/wm_hubs.c2
-rw-r--r--sound/soc/davinci/davinci-i2s.c163
-rw-r--r--sound/soc/davinci/davinci-i2s.h5
-rw-r--r--sound/soc/davinci/davinci-mcasp.c6
-rw-r--r--sound/soc/davinci/davinci-pcm.c7
-rw-r--r--sound/soc/davinci/davinci-pcm.h3
-rw-r--r--sound/soc/davinci/davinci-vcif.c2
-rw-r--r--sound/soc/ep93xx/Kconfig18
-rw-r--r--sound/soc/ep93xx/Makefile11
-rw-r--r--sound/soc/ep93xx/ep93xx-i2s.c487
-rw-r--r--sound/soc/ep93xx/ep93xx-i2s.h18
-rw-r--r--sound/soc/ep93xx/ep93xx-pcm.c319
-rw-r--r--sound/soc/ep93xx/ep93xx-pcm.h22
-rw-r--r--sound/soc/ep93xx/snappercl15.c150
-rw-r--r--sound/soc/fsl/mpc5200_psc_i2s.c1
-rw-r--r--sound/soc/fsl/mpc5200_psc_i2s.h12
-rw-r--r--sound/soc/fsl/mpc8610_hpcd.c2
-rw-r--r--sound/soc/imx/Kconfig19
-rw-r--r--sound/soc/imx/Makefile2
-rw-r--r--sound/soc/imx/eukrea-tlv320.c137
-rw-r--r--sound/soc/imx/imx-pcm-dma-mx2.c6
-rw-r--r--sound/soc/imx/imx-pcm-fiq.c6
-rw-r--r--sound/soc/imx/imx-ssi.c13
-rw-r--r--sound/soc/jz4740/Kconfig23
-rw-r--r--sound/soc/jz4740/Makefile13
-rw-r--r--sound/soc/jz4740/jz4740-i2s.c540
-rw-r--r--sound/soc/jz4740/jz4740-i2s.h18
-rw-r--r--sound/soc/jz4740/jz4740-pcm.c373
-rw-r--r--sound/soc/jz4740/jz4740-pcm.h22
-rw-r--r--sound/soc/jz4740/qi_lb60.c166
-rw-r--r--sound/soc/kirkwood/Kconfig20
-rw-r--r--sound/soc/kirkwood/Makefile9
-rw-r--r--sound/soc/kirkwood/kirkwood-dma.c383
-rw-r--r--sound/soc/kirkwood/kirkwood-dma.h17
-rw-r--r--sound/soc/kirkwood/kirkwood-i2s.c495
-rw-r--r--sound/soc/kirkwood/kirkwood-i2s.h17
-rw-r--r--sound/soc/kirkwood/kirkwood-openrd.c126
-rw-r--r--sound/soc/kirkwood/kirkwood.h129
-rw-r--r--sound/soc/nuc900/Kconfig27
-rw-r--r--sound/soc/nuc900/Makefile11
-rw-r--r--sound/soc/nuc900/nuc900-ac97.c430
-rw-r--r--sound/soc/nuc900/nuc900-audio.c81
-rw-r--r--sound/soc/nuc900/nuc900-audio.h117
-rw-r--r--sound/soc/nuc900/nuc900-pcm.c354
-rw-r--r--sound/soc/omap/omap-mcbsp.c175
-rw-r--r--sound/soc/omap/omap3pandora.c36
-rw-r--r--sound/soc/omap/rx51.c73
-rw-r--r--sound/soc/s3c24xx/Kconfig10
-rw-r--r--sound/soc/s3c24xx/Makefile2
-rw-r--r--sound/soc/s3c24xx/s3c-ac97.c1
-rw-r--r--sound/soc/s3c24xx/s3c-i2s-v2.c3
-rw-r--r--sound/soc/s3c24xx/smartq_wm8987.c295
-rw-r--r--sound/soc/s3c24xx/smdk_wm9713.c3
-rw-r--r--sound/soc/s6000/s6000-i2s.c38
-rw-r--r--sound/soc/sh/Kconfig4
-rw-r--r--sound/soc/sh/fsi-ak4642.c13
-rw-r--r--sound/soc/sh/fsi-da7210.c13
-rw-r--r--sound/soc/sh/fsi.c257
-rw-r--r--sound/soc/soc-core.c117
-rw-r--r--sound/sound_core.c9
-rw-r--r--sound/sparc/amd7930.c6
-rw-r--r--sound/sparc/cs4231.c18
-rw-r--r--sound/sparc/dbri.c6
-rw-r--r--sound/usb/card.c2
-rw-r--r--sound/usb/clock.c59
-rw-r--r--sound/usb/clock.h4
-rw-r--r--sound/usb/endpoint.c5
-rw-r--r--sound/usb/format.c9
-rw-r--r--sound/usb/midi.c14
-rw-r--r--sound/usb/mixer.c77
-rw-r--r--sound/usb/mixer.h1
-rw-r--r--sound/usb/pcm.c2
-rw-r--r--sound/usb/pcm.h3
-rw-r--r--sound/usb/quirks-table.h30
-rw-r--r--sound/usb/quirks.c1
-rw-r--r--tools/firewire/Makefile19
-rw-r--r--tools/firewire/decode-fcp.c213
-rw-r--r--tools/firewire/list.h62
-rw-r--r--tools/firewire/nosy-dump.c1031
-rw-r--r--tools/firewire/nosy-dump.h173
-rw-r--r--tools/perf/.gitignore2
-rw-r--r--tools/perf/Documentation/perf-buildid-cache.txt8
-rw-r--r--tools/perf/Documentation/perf-probe.txt8
-rw-r--r--tools/perf/Documentation/perf-record.txt13
-rw-r--r--tools/perf/Documentation/perf-stat.txt7
-rw-r--r--tools/perf/Documentation/perf-top.txt8
-rw-r--r--tools/perf/MANIFEST12
-rw-r--r--tools/perf/Makefile113
-rw-r--r--tools/perf/arch/sh/Makefile4
-rw-r--r--tools/perf/arch/sh/util/dwarf-regs.c (renamed from fs/nilfs2/bmap_union.h)53
-rw-r--r--tools/perf/builtin-annotate.c6
-rw-r--r--tools/perf/builtin-buildid-cache.c3
-rw-r--r--tools/perf/builtin-buildid-list.c4
-rw-r--r--tools/perf/builtin-diff.c9
-rw-r--r--tools/perf/builtin-probe.c3
-rw-r--r--tools/perf/builtin-record.c81
-rw-r--r--tools/perf/builtin-report.c27
-rw-r--r--tools/perf/builtin-stat.c14
-rw-r--r--tools/perf/builtin-timechart.c11
-rw-r--r--tools/perf/builtin-top.c40
-rw-r--r--tools/perf/builtin-trace.c32
-rw-r--r--tools/perf/feature-tests.mak119
-rw-r--r--tools/perf/perf-archive.sh20
-rw-r--r--tools/perf/perf.c2
-rw-r--r--tools/perf/scripts/python/Perf-Trace-Util/lib/Perf/Trace/Core.py30
-rw-r--r--tools/perf/scripts/python/Perf-Trace-Util/lib/Perf/Trace/SchedGui.py184
-rw-r--r--tools/perf/scripts/python/bin/sched-migration-record2
-rw-r--r--tools/perf/scripts/python/bin/sched-migration-report3
-rw-r--r--tools/perf/scripts/python/sched-migration.py461
-rw-r--r--tools/perf/util/build-id.c28
-rw-r--r--tools/perf/util/cache.h1
-rw-r--r--tools/perf/util/callchain.c2
-rw-r--r--tools/perf/util/callchain.h2
-rw-r--r--tools/perf/util/config.c64
-rw-r--r--tools/perf/util/cpumap.c57
-rw-r--r--tools/perf/util/cpumap.h2
-rw-r--r--tools/perf/util/debug.c10
-rw-r--r--tools/perf/util/event.c107
-rw-r--r--tools/perf/util/event.h6
-rw-r--r--tools/perf/util/header.c13
-rw-r--r--tools/perf/util/hist.c214
-rw-r--r--tools/perf/util/hist.h30
-rw-r--r--tools/perf/util/map.c116
-rw-r--r--tools/perf/util/map.h14
-rw-r--r--tools/perf/util/newt.c1164
-rw-r--r--tools/perf/util/parse-events.c11
-rw-r--r--tools/perf/util/probe-event.c271
-rw-r--r--tools/perf/util/probe-event.h29
-rw-r--r--tools/perf/util/probe-finder.c248
-rw-r--r--tools/perf/util/probe-finder.h10
-rw-r--r--tools/perf/util/session.c62
-rw-r--r--tools/perf/util/sort.c40
-rw-r--r--tools/perf/util/sort.h22
-rw-r--r--tools/perf/util/symbol.c299
-rw-r--r--tools/perf/util/symbol.h18
-rw-r--r--tools/perf/util/thread.c7
-rw-r--r--tools/perf/util/thread.h2
-rw-r--r--tools/perf/util/util.h3
-rw-r--r--virt/kvm/assigned-dev.c7
-rw-r--r--virt/kvm/coalesced_mmio.c1
-rw-r--r--virt/kvm/eventfd.c1
-rw-r--r--virt/kvm/ioapic.c3
-rw-r--r--virt/kvm/iommu.c12
-rw-r--r--virt/kvm/irq_comm.c15
-rw-r--r--virt/kvm/kvm_main.c106
5302 files changed, 346241 insertions, 181261 deletions
diff --git a/Documentation/ABI/testing/debugfs-ec b/Documentation/ABI/testing/debugfs-ec
new file mode 100644
index 00000000000..6546115a94d
--- /dev/null
+++ b/Documentation/ABI/testing/debugfs-ec
@@ -0,0 +1,20 @@
+What: /sys/kernel/debug/ec/*/{gpe,use_global_lock,io}
+Date: July 2010
+Contact: Thomas Renninger <trenn@suse.de>
+Description:
+
+General information like which GPE is assigned to the EC and whether
+the global lock should get used.
+Knowing the EC GPE one can watch the amount of HW events related to
+the EC here (XY -> GPE number from /sys/kernel/debug/ec/*/gpe):
+/sys/firmware/acpi/interrupts/gpeXY
+
+The io file is binary and a userspace tool located here:
+ftp://ftp.suse.com/pub/people/trenn/sources/ec/
+should get used to read out the 256 Embedded Controller registers
+or writing to them.
+
+CAUTION: Do not write to the Embedded Controller if you don't know
+what you are doing! Rebooting afterwards also is a good idea.
+This can influence the way your machine is cooled and fans may
+not get switched on again after you did a wrong write.
diff --git a/Documentation/ABI/testing/debugfs-kmemtrace b/Documentation/ABI/testing/debugfs-kmemtrace
deleted file mode 100644
index 5e6a92a02d8..00000000000
--- a/Documentation/ABI/testing/debugfs-kmemtrace
+++ /dev/null
@@ -1,71 +0,0 @@
-What: /sys/kernel/debug/kmemtrace/
-Date: July 2008
-Contact: Eduard - Gabriel Munteanu <eduard.munteanu@linux360.ro>
-Description:
-
-In kmemtrace-enabled kernels, the following files are created:
-
-/sys/kernel/debug/kmemtrace/
- cpu<n> (0400) Per-CPU tracing data, see below. (binary)
- total_overruns (0400) Total number of bytes which were dropped from
- cpu<n> files because of full buffer condition,
- non-binary. (text)
- abi_version (0400) Kernel's kmemtrace ABI version. (text)
-
-Each per-CPU file should be read according to the relay interface. That is,
-the reader should set affinity to that specific CPU and, as currently done by
-the userspace application (though there are other methods), use poll() with
-an infinite timeout before every read(). Otherwise, erroneous data may be
-read. The binary data has the following _core_ format:
-
- Event ID (1 byte) Unsigned integer, one of:
- 0 - represents an allocation (KMEMTRACE_EVENT_ALLOC)
- 1 - represents a freeing of previously allocated memory
- (KMEMTRACE_EVENT_FREE)
- Type ID (1 byte) Unsigned integer, one of:
- 0 - this is a kmalloc() / kfree()
- 1 - this is a kmem_cache_alloc() / kmem_cache_free()
- 2 - this is a __get_free_pages() et al.
- Event size (2 bytes) Unsigned integer representing the
- size of this event. Used to extend
- kmemtrace. Discard the bytes you
- don't know about.
- Sequence number (4 bytes) Signed integer used to reorder data
- logged on SMP machines. Wraparound
- must be taken into account, although
- it is unlikely.
- Caller address (8 bytes) Return address to the caller.
- Pointer to mem (8 bytes) Pointer to target memory area. Can be
- NULL, but not all such calls might be
- recorded.
-
-In case of KMEMTRACE_EVENT_ALLOC events, the next fields follow:
-
- Requested bytes (8 bytes) Total number of requested bytes,
- unsigned, must not be zero.
- Allocated bytes (8 bytes) Total number of actually allocated
- bytes, unsigned, must not be lower
- than requested bytes.
- Requested flags (4 bytes) GFP flags supplied by the caller.
- Target CPU (4 bytes) Signed integer, valid for event id 1.
- If equal to -1, target CPU is the same
- as origin CPU, but the reverse might
- not be true.
-
-The data is made available in the same endianness the machine has.
-
-Other event ids and type ids may be defined and added. Other fields may be
-added by increasing event size, but see below for details.
-Every modification to the ABI, including new id definitions, are followed
-by bumping the ABI version by one.
-
-Adding new data to the packet (features) is done at the end of the mandatory
-data:
- Feature size (2 byte)
- Feature ID (1 byte)
- Feature data (Feature size - 3 bytes)
-
-
-Users:
- kmemtrace-user - git://repo.or.cz/kmemtrace-user.git
-
diff --git a/Documentation/ABI/testing/sysfs-bus-pci b/Documentation/ABI/testing/sysfs-bus-pci
index 25be3250f7d..f979d825d11 100644
--- a/Documentation/ABI/testing/sysfs-bus-pci
+++ b/Documentation/ABI/testing/sysfs-bus-pci
@@ -139,3 +139,30 @@ Contact: linux-pci@vger.kernel.org
Description:
This symbolic link points to the PCI hotplug controller driver
module that manages the hotplug slot.
+
+What: /sys/bus/pci/devices/.../label
+Date: July 2010
+Contact: Narendra K <narendra_k@dell.com>, linux-bugs@dell.com
+Description:
+ Reading this attribute will provide the firmware
+ given name(SMBIOS type 41 string) of the PCI device.
+ The attribute will be created only if the firmware
+ has given a name to the PCI device.
+Users:
+ Userspace applications interested in knowing the
+ firmware assigned name of the PCI device.
+
+What: /sys/bus/pci/devices/.../index
+Date: July 2010
+Contact: Narendra K <narendra_k@dell.com>, linux-bugs@dell.com
+Description:
+ Reading this attribute will provide the firmware
+ given instance(SMBIOS type 41 device type instance)
+ of the PCI device. The attribute will be created
+ only if the firmware has given a device type instance
+ to the PCI device.
+Users:
+ Userspace applications interested in knowing the
+ firmware assigned device type instance of the PCI
+ device that can help in understanding the firmware
+ intended order of the PCI device.
diff --git a/Documentation/ABI/testing/sysfs-devices-memory b/Documentation/ABI/testing/sysfs-devices-memory
index aba7d989208..7405de26ee6 100644
--- a/Documentation/ABI/testing/sysfs-devices-memory
+++ b/Documentation/ABI/testing/sysfs-devices-memory
@@ -7,7 +7,7 @@ Description:
added or removed dynamically to represent hot-add/remove
operations.
Users: hotplug memory add/remove tools
- https://w3.opensource.ibm.com/projects/powerpc-utils/
+ http://www.ibm.com/developerworks/wikis/display/LinuxP/powerpc-utils
What: /sys/devices/system/memory/memoryX/removable
Date: June 2008
@@ -19,7 +19,7 @@ Description:
identify removable sections of the memory before attempting
potentially expensive hot-remove memory operation
Users: hotplug memory remove tools
- https://w3.opensource.ibm.com/projects/powerpc-utils/
+ http://www.ibm.com/developerworks/wikis/display/LinuxP/powerpc-utils
What: /sys/devices/system/memory/memoryX/phys_device
Date: September 2008
@@ -58,7 +58,7 @@ Description:
by root to offline that section.
# echo offline > /sys/devices/system/memory/memory22/state
Users: hotplug memory remove tools
- https://w3.opensource.ibm.com/projects/powerpc-utils/
+ http://www.ibm.com/developerworks/wikis/display/LinuxP/powerpc-utils
What: /sys/devices/system/memoryX/nodeY
diff --git a/Documentation/ABI/testing/sysfs-devices-system-cpu b/Documentation/ABI/testing/sysfs-devices-system-cpu
index 84a710f87c6..7564e88bfa4 100644
--- a/Documentation/ABI/testing/sysfs-devices-system-cpu
+++ b/Documentation/ABI/testing/sysfs-devices-system-cpu
@@ -197,7 +197,7 @@ Description: These files exist in every cpu's cache index directories.
Currently, only AMD Family 10h Processors support cache index
disable, and only for their L3 caches. See the BIOS and
Kernel Developer's Guide at
- http://www.amd.com/us-en/assets/content_type/white_papers_and_tech_docs/31116-Public-GH-BKDG_3.20_2-4-09.pdf
+ http://support.amd.com/us/Embedded_TechDocs/31116-Public-GH-BKDG_3-28_5-28-09.pdf
for formatting information and other details on the
cache index disable.
Users: joachim.deguara@amd.com
diff --git a/Documentation/ABI/testing/sysfs-driver-hid-roccat-kone b/Documentation/ABI/testing/sysfs-driver-hid-roccat-kone
index 88340a23ce9..063bda7fe70 100644
--- a/Documentation/ABI/testing/sysfs-driver-hid-roccat-kone
+++ b/Documentation/ABI/testing/sysfs-driver-hid-roccat-kone
@@ -33,19 +33,6 @@ Description: When read, this file returns the raw integer version number of the
left. E.g. a returned value of 138 means 1.38
This file is readonly.
-What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/kone_driver_version
-Date: March 2010
-Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
-Description: When read, this file returns the driver version.
- The format of the string is "v<major>.<minor>.<patchlevel>".
- This attribute is used by the userland tools to find the sysfs-
- paths of installed kone-mice and determine the capabilites of
- the driver. Versions of this driver for old kernels replace
- usbhid instead of generic-usb. The way to scan for this file
- has been chosen to provide a consistent way for all supported
- kernel versions.
- This file is readonly.
-
What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/profile[1-5]
Date: March 2010
Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
diff --git a/Documentation/ABI/testing/sysfs-power b/Documentation/ABI/testing/sysfs-power
index d6a801f45b4..2875f1f74a0 100644
--- a/Documentation/ABI/testing/sysfs-power
+++ b/Documentation/ABI/testing/sysfs-power
@@ -114,3 +114,18 @@ Description:
if this file contains "1", which is the default. It may be
disabled by writing "0" to this file, in which case all devices
will be suspended and resumed synchronously.
+
+What: /sys/power/wakeup_count
+Date: July 2010
+Contact: Rafael J. Wysocki <rjw@sisk.pl>
+Description:
+ The /sys/power/wakeup_count file allows user space to put the
+ system into a sleep state while taking into account the
+ concurrent arrival of wakeup events. Reading from it returns
+ the current number of registered wakeup events and it blocks if
+ some wakeup events are being processed at the time the file is
+ read from. Writing to it will only succeed if the current
+ number of wakeup events is equal to the written value and, if
+ successful, will make the kernel abort a subsequent transition
+ to a sleep state if any wakeup events are reported after the
+ write has returned.
diff --git a/Documentation/Changes b/Documentation/Changes
index eca9f6e6fbe..4fb88f15f2e 100644
--- a/Documentation/Changes
+++ b/Documentation/Changes
@@ -331,7 +331,7 @@ o <ftp://ftp.kernel.org/pub/linux/kernel/people/rusty/modules/>
Mkinitrd
--------
-o <ftp://rawhide.redhat.com/pub/rawhide/SRPMS/SRPMS/>
+o <https://code.launchpad.net/initrd-tools/main>
E2fsprogs
---------
@@ -343,11 +343,11 @@ o <http://jfs.sourceforge.net/>
Reiserfsprogs
-------------
-o <http://www.namesys.com/pub/reiserfsprogs/reiserfsprogs-3.6.3.tar.gz>
+o <http://www.kernel.org/pub/linux/utils/fs/reiserfs/>
Xfsprogs
--------
-o <ftp://oss.sgi.com/projects/xfs/download/>
+o <ftp://oss.sgi.com/projects/xfs/>
Pcmciautils
-----------
@@ -387,18 +387,18 @@ o <http://sourceforge.net/projects/fuse>
mcelog
------
-o <ftp://ftp.kernel.org/pub/linux/utils/cpu/mce/mcelog/>
+o <ftp://ftp.kernel.org/pub/linux/utils/cpu/mce/>
Networking
**********
PPP
---
-o <ftp://ftp.samba.org/pub/ppp/ppp-2.4.0.tar.gz>
+o <ftp://ftp.samba.org/pub/ppp/>
Isdn4k-utils
------------
-o <ftp://ftp.isdn4linux.de/pub/isdn4linux/utils/isdn4k-utils.v3.1pre1.tar.gz>
+o <ftp://ftp.isdn4linux.de/pub/isdn4linux/utils/>
NFS-utils
---------
diff --git a/Documentation/DocBook/device-drivers.tmpl b/Documentation/DocBook/device-drivers.tmpl
index 1b2dd4fc3db..ecd35e9d441 100644
--- a/Documentation/DocBook/device-drivers.tmpl
+++ b/Documentation/DocBook/device-drivers.tmpl
@@ -111,6 +111,7 @@ X!Edrivers/base/attribute_container.c
<!--
X!Edrivers/base/interface.c
-->
+!Iinclude/linux/platform_device.h
!Edrivers/base/platform.c
!Edrivers/base/bus.c
</sect1>
diff --git a/Documentation/DocBook/dvb/dvbapi.xml b/Documentation/DocBook/dvb/dvbapi.xml
index 63c528fee62..e3a97fdd62a 100644
--- a/Documentation/DocBook/dvb/dvbapi.xml
+++ b/Documentation/DocBook/dvb/dvbapi.xml
@@ -12,10 +12,12 @@
<othername role="mi">O. C.</othername>
<affiliation><address><email>rjkm@metzlerbros.de</email></address></affiliation>
</author>
+</authorgroup>
+<authorgroup>
<author>
<firstname>Mauro</firstname>
-<surname>Chehab</surname>
<othername role="mi">Carvalho</othername>
+<surname>Chehab</surname>
<affiliation><address><email>mchehab@redhat.com</email></address></affiliation>
<contrib>Ported document to Docbook XML.</contrib>
</author>
@@ -23,13 +25,24 @@
<copyright>
<year>2002</year>
<year>2003</year>
- <year>2009</year>
<holder>Convergence GmbH</holder>
</copyright>
+<copyright>
+ <year>2009-2010</year>
+ <holder>Mauro Carvalho Chehab</holder>
+</copyright>
<revhistory>
<!-- Put document revisions here, newest first. -->
<revision>
+ <revnumber>2.0.3</revnumber>
+ <date>2010-07-03</date>
+ <authorinitials>mcc</authorinitials>
+ <revremark>
+ Add some frontend capabilities flags, present on kernel, but missing at the specs.
+ </revremark>
+</revision>
+<revision>
<revnumber>2.0.2</revnumber>
<date>2009-10-25</date>
<authorinitials>mcc</authorinitials>
@@ -63,7 +76,7 @@ Added ISDB-T test originally written by Patrick Boettcher
<title>LINUX DVB API</title>
-<subtitle>Version 3</subtitle>
+<subtitle>Version 5.2</subtitle>
<!-- ADD THE CHAPTERS HERE -->
<chapter id="dvb_introdution">
&sub-intro;
diff --git a/Documentation/DocBook/dvb/frontend.h.xml b/Documentation/DocBook/dvb/frontend.h.xml
index b99644f5340..d08e0d40141 100644
--- a/Documentation/DocBook/dvb/frontend.h.xml
+++ b/Documentation/DocBook/dvb/frontend.h.xml
@@ -63,6 +63,7 @@ typedef enum fe_caps {
FE_CAN_8VSB = 0x200000,
FE_CAN_16VSB = 0x400000,
FE_HAS_EXTENDED_CAPS = 0x800000, /* We need more bitspace for newer APIs, indicate this. */
+ FE_CAN_TURBO_FEC = 0x8000000, /* frontend supports "turbo fec modulation" */
FE_CAN_2G_MODULATION = 0x10000000, /* frontend supports "2nd generation modulation" (DVB-S2) */
FE_NEEDS_BENDING = 0x20000000, /* not supported anymore, don't use (frontend requires frequency bending) */
FE_CAN_RECOVER = 0x40000000, /* frontend can recover from a cable unplug automatically */
diff --git a/Documentation/DocBook/dvb/frontend.xml b/Documentation/DocBook/dvb/frontend.xml
index 300ba1f0417..78d756de590 100644
--- a/Documentation/DocBook/dvb/frontend.xml
+++ b/Documentation/DocBook/dvb/frontend.xml
@@ -64,8 +64,14 @@ a specific frontend type.</para>
FE_CAN_BANDWIDTH_AUTO = 0x40000,
FE_CAN_GUARD_INTERVAL_AUTO = 0x80000,
FE_CAN_HIERARCHY_AUTO = 0x100000,
- FE_CAN_MUTE_TS = 0x80000000,
- FE_CAN_CLEAN_SETUP = 0x40000000
+ FE_CAN_8VSB = 0x200000,
+ FE_CAN_16VSB = 0x400000,
+ FE_HAS_EXTENDED_CAPS = 0x800000,
+ FE_CAN_TURBO_FEC = 0x8000000,
+ FE_CAN_2G_MODULATION = 0x10000000,
+ FE_NEEDS_BENDING = 0x20000000,
+ FE_CAN_RECOVER = 0x40000000,
+ FE_CAN_MUTE_TS = 0x80000000
} fe_caps_t;
</programlisting>
</section>
diff --git a/Documentation/DocBook/kgdb.tmpl b/Documentation/DocBook/kgdb.tmpl
index 55f12ac37ac..490d862c5f0 100644
--- a/Documentation/DocBook/kgdb.tmpl
+++ b/Documentation/DocBook/kgdb.tmpl
@@ -199,10 +199,33 @@
may be configured as a kernel built-in or a kernel loadable module.
You can only make use of <constant>kgdbwait</constant> and early
debugging if you build kgdboc into the kernel as a built-in.
+ <para>Optionally you can elect to activate kms (Kernel Mode
+ Setting) integration. When you use kms with kgdboc and you have a
+ video driver that has atomic mode setting hooks, it is possible to
+ enter the debugger on the graphics console. When the kernel
+ execution is resumed, the previous graphics mode will be restored.
+ This integration can serve as a useful tool to aid in diagnosing
+ crashes or doing analysis of memory with kdb while allowing the
+ full graphics console applications to run.
+ </para>
</para>
<sect2 id="kgdbocArgs">
<title>kgdboc arguments</title>
- <para>Usage: <constant>kgdboc=[kbd][[,]serial_device][,baud]</constant></para>
+ <para>Usage: <constant>kgdboc=[kms][[,]kbd][[,]serial_device][,baud]</constant></para>
+ <para>The order listed above must be observed if you use any of the
+ optional configurations together.
+ </para>
+ <para>Abbreviations:
+ <itemizedlist>
+ <listitem><para>kms = Kernel Mode Setting</para></listitem>
+ <listitem><para>kbd = Keyboard</para></listitem>
+ </itemizedlist>
+ </para>
+ <para>You can configure kgdboc to use the keyboard, and or a serial
+ device depending on if you are using kdb and or kgdb, in one of the
+ following scenarios. The order listed above must be observed if
+ you use any of the optional configurations together. Using kms +
+ only gdb is generally not a useful combination.</para>
<sect3 id="kgdbocArgs1">
<title>Using loadable module or built-in</title>
<para>
@@ -212,7 +235,7 @@
<listitem>
<para>As a kernel loadable module:</para>
<para>Use the command: <constant>modprobe kgdboc kgdboc=&lt;tty-device&gt;,[baud]</constant></para>
- <para>Here are two examples of how you might formate the kgdboc
+ <para>Here are two examples of how you might format the kgdboc
string. The first is for an x86 target using the first serial port.
The second example is for the ARM Versatile AB using the second
serial port.
@@ -240,6 +263,9 @@
</sect3>
<sect3 id="kgdbocArgs3">
<title>More examples</title>
+ <para>You can configure kgdboc to use the keyboard, and or a serial
+ device depending on if you are using kdb and or kgdb, in one of the
+ following scenarios.</para>
<para>You can configure kgdboc to use the keyboard, and or a serial device
depending on if you are using kdb and or kgdb, in one of the
following scenarios.
@@ -255,6 +281,12 @@
<listitem><para>kdb with a keyboard</para>
<para><constant>kgdboc=kbd</constant></para>
</listitem>
+ <listitem><para>kdb with kernel mode setting</para>
+ <para><constant>kgdboc=kms,kbd</constant></para>
+ </listitem>
+ <listitem><para>kdb with kernel mode setting and kgdb over a serial port</para>
+ <para><constant>kgdboc=kms,kbd,ttyS0,115200</constant></para>
+ </listitem>
</orderedlist>
</para>
</sect3>
@@ -637,6 +669,8 @@ Task Addr Pid Parent [*] cpu State Thread Command
<listitem><para>The logic to perform safe memory reads and writes to memory while using the debugger</para></listitem>
<listitem><para>A full implementation for software breakpoints unless overridden by the arch</para></listitem>
<listitem><para>The API to invoke either the kdb or kgdb frontend to the debug core.</para></listitem>
+ <listitem><para>The structures and callback API for atomic kernel mode setting.</para>
+ <para>NOTE: kgdboc is where the kms callbacks are invoked.</para></listitem>
</itemizedlist>
</para>
</listitem>
@@ -747,6 +781,8 @@ Task Addr Pid Parent [*] cpu State Thread Command
</sect1>
<sect1 id="kgdbocDesign">
<title>kgdboc internals</title>
+ <sect2>
+ <title>kgdboc and uarts</title>
<para>
The kgdboc driver is actually a very thin driver that relies on the
underlying low level to the hardware driver having "polling hooks"
@@ -754,11 +790,8 @@ Task Addr Pid Parent [*] cpu State Thread Command
implementation of kgdboc it the serial_core was changed to expose a
low level UART hook for doing polled mode reading and writing of a
single character while in an atomic context. When kgdb makes an I/O
- request to the debugger, kgdboc invokes a call back in the serial
- core which in turn uses the call back in the UART driver. It is
- certainly possible to extend kgdboc to work with non-UART based
- consoles in the future.
- </para>
+ request to the debugger, kgdboc invokes a callback in the serial
+ core which in turn uses the callback in the UART driver.</para>
<para>
When using kgdboc with a UART, the UART driver must implement two callbacks in the <constant>struct uart_ops</constant>. Example from drivers/8250.c:<programlisting>
#ifdef CONFIG_CONSOLE_POLL
@@ -772,9 +805,68 @@ Task Addr Pid Parent [*] cpu State Thread Command
that they can be called from an atomic context and have to restore
the state of the UART chip on return such that the system can return
to normal when the debugger detaches. You need to be very careful
- with any kind of lock you consider, because failing here is most
+ with any kind of lock you consider, because failing here is most likely
going to mean pressing the reset button.
</para>
+ </sect2>
+ <sect2 id="kgdbocKbd">
+ <title>kgdboc and keyboards</title>
+ <para>The kgdboc driver contains logic to configure communications
+ with an attached keyboard. The keyboard infrastructure is only
+ compiled into the kernel when CONFIG_KDB_KEYBOARD=y is set in the
+ kernel configuration.</para>
+ <para>The core polled keyboard driver driver for PS/2 type keyboards
+ is in drivers/char/kdb_keyboard.c. This driver is hooked into the
+ debug core when kgdboc populates the callback in the array
+ called <constant>kdb_poll_funcs[]</constant>. The
+ kdb_get_kbd_char() is the top-level function which polls hardware
+ for single character input.
+ </para>
+ </sect2>
+ <sect2 id="kgdbocKms">
+ <title>kgdboc and kms</title>
+ <para>The kgdboc driver contains logic to request the graphics
+ display to switch to a text context when you are using
+ "kgdboc=kms,kbd", provided that you have a video driver which has a
+ frame buffer console and atomic kernel mode setting support.</para>
+ <para>
+ Every time the kernel
+ debugger is entered it calls kgdboc_pre_exp_handler() which in turn
+ calls con_debug_enter() in the virtual console layer. On resuming kernel
+ execution, the kernel debugger calls kgdboc_post_exp_handler() which
+ in turn calls con_debug_leave().</para>
+ <para>Any video driver that wants to be compatible with the kernel
+ debugger and the atomic kms callbacks must implement the
+ mode_set_base_atomic, fb_debug_enter and fb_debug_leave operations.
+ For the fb_debug_enter and fb_debug_leave the option exists to use
+ the generic drm fb helper functions or implement something custom for
+ the hardware. The following example shows the initialization of the
+ .mode_set_base_atomic operation in
+ drivers/gpu/drm/i915/intel_display.c:
+ <informalexample>
+ <programlisting>
+static const struct drm_crtc_helper_funcs intel_helper_funcs = {
+[...]
+ .mode_set_base_atomic = intel_pipe_set_base_atomic,
+[...]
+};
+ </programlisting>
+ </informalexample>
+ </para>
+ <para>Here is an example of how the i915 driver initializes the fb_debug_enter and fb_debug_leave functions to use the generic drm helpers in
+ drivers/gpu/drm/i915/intel_fb.c:
+ <informalexample>
+ <programlisting>
+static struct fb_ops intelfb_ops = {
+[...]
+ .fb_debug_enter = drm_fb_helper_debug_enter,
+ .fb_debug_leave = drm_fb_helper_debug_leave,
+[...]
+};
+ </programlisting>
+ </informalexample>
+ </para>
+ </sect2>
</sect1>
</chapter>
<chapter id="credits">
diff --git a/Documentation/DocBook/media-entities.tmpl b/Documentation/DocBook/media-entities.tmpl
index 5d4d40f429a..6ae97157b1c 100644
--- a/Documentation/DocBook/media-entities.tmpl
+++ b/Documentation/DocBook/media-entities.tmpl
@@ -218,6 +218,7 @@
<!ENTITY sub-dev-teletext SYSTEM "v4l/dev-teletext.xml">
<!ENTITY sub-driver SYSTEM "v4l/driver.xml">
<!ENTITY sub-libv4l SYSTEM "v4l/libv4l.xml">
+<!ENTITY sub-lirc_device_interface SYSTEM "v4l/lirc_device_interface.xml">
<!ENTITY sub-remote_controllers SYSTEM "v4l/remote_controllers.xml">
<!ENTITY sub-fdl-appendix SYSTEM "v4l/fdl-appendix.xml">
<!ENTITY sub-close SYSTEM "v4l/func-close.xml">
diff --git a/Documentation/DocBook/media.tmpl b/Documentation/DocBook/media.tmpl
index eea564bb12c..f11048d4053 100644
--- a/Documentation/DocBook/media.tmpl
+++ b/Documentation/DocBook/media.tmpl
@@ -28,7 +28,7 @@
<title>LINUX MEDIA INFRASTRUCTURE API</title>
<copyright>
- <year>2009</year>
+ <year>2009-2010</year>
<holder>LinuxTV Developers</holder>
</copyright>
@@ -61,7 +61,7 @@ Foundation. A copy of the license is included in the chapter entitled
in fact it covers several different video standards including
DVB-T, DVB-S, DVB-C and ATSC. The API is currently being updated
to documment support also for DVB-S2, ISDB-T and ISDB-S.</para>
- <para>The third part covers other API's used by all media infrastructure devices</para>
+ <para>The third part covers Remote Controller API</para>
<para>For additional information and for the latest development code,
see: <ulink url="http://linuxtv.org">http://linuxtv.org</ulink>.</para>
<para>For discussing improvements, reporting troubles, sending new drivers, etc, please mail to: <ulink url="http://vger.kernel.org/vger-lists.html#linux-media">Linux Media Mailing List (LMML).</ulink>.</para>
@@ -86,7 +86,7 @@ Foundation. A copy of the license is included in the chapter entitled
</author>
</authorgroup>
<copyright>
- <year>2009</year>
+ <year>2009-2010</year>
<holder>Mauro Carvalho Chehab</holder>
</copyright>
@@ -101,7 +101,7 @@ Foundation. A copy of the license is included in the chapter entitled
</revhistory>
</partinfo>
-<title>Other API's used by media infrastructure drivers</title>
+<title>Remote Controller API</title>
<chapter id="remote_controllers">
&sub-remote_controllers;
</chapter>
diff --git a/Documentation/DocBook/scsi.tmpl b/Documentation/DocBook/scsi.tmpl
index d87f4569e76..324b53494f0 100644
--- a/Documentation/DocBook/scsi.tmpl
+++ b/Documentation/DocBook/scsi.tmpl
@@ -393,7 +393,7 @@
</para>
<para>
For documentation see
- <ulink url='http://www.torque.net/sg/sdebug26.html'>http://www.torque.net/sg/sdebug26.html</ulink>
+ <ulink url='http://sg.danny.cz/sg/sdebug26.html'>http://sg.danny.cz/sg/sdebug26.html</ulink>
</para>
<!-- !Edrivers/scsi/scsi_debug.c -->
</sect2>
diff --git a/Documentation/DocBook/stylesheet.xsl b/Documentation/DocBook/stylesheet.xsl
index 254c1d5d2e5..85b25275196 100644
--- a/Documentation/DocBook/stylesheet.xsl
+++ b/Documentation/DocBook/stylesheet.xsl
@@ -6,4 +6,5 @@
<param name="callout.graphics">0</param>
<!-- <param name="paper.type">A4</param> -->
<param name="generate.section.toc.level">2</param>
+<param name="use.id.as.filename">1</param>
</stylesheet>
diff --git a/Documentation/DocBook/v4l/compat.xml b/Documentation/DocBook/v4l/compat.xml
index b42b935913c..54447f0d078 100644
--- a/Documentation/DocBook/v4l/compat.xml
+++ b/Documentation/DocBook/v4l/compat.xml
@@ -1091,8 +1091,9 @@ signed 64-bit integer. Output devices should not send a buffer out
until the time in the timestamp field has arrived. I would like to
follow SGI's lead, and adopt a multimedia timestamping system like
their UST (Unadjusted System Time). See
-http://reality.sgi.com/cpirazzi_engr/lg/time/intro.html. [This link is
-no longer valid.] UST uses timestamps that are 64-bit signed integers
+http://web.archive.org/web/*/http://reality.sgi.com
+/cpirazzi_engr/lg/time/intro.html.
+UST uses timestamps that are 64-bit signed integers
(not struct timeval's) and given in nanosecond units. The UST clock
starts at zero when the system is booted and runs continuously and
uniformly. It takes a little over 292 years for UST to overflow. There
diff --git a/Documentation/DocBook/v4l/fdl-appendix.xml b/Documentation/DocBook/v4l/fdl-appendix.xml
index b6ce50dbe49..ae22394ba99 100644
--- a/Documentation/DocBook/v4l/fdl-appendix.xml
+++ b/Documentation/DocBook/v4l/fdl-appendix.xml
@@ -2,7 +2,7 @@
The GNU Free Documentation License 1.1 in DocBook
Markup by Eric Baudais <baudais@okstate.edu>
Maintained by the GNOME Documentation Project
- http://developer.gnome.org/projects/gdp
+ http://live.gnome.org/DocumentationProject
Version: 1.0.1
Last Modified: Nov 16, 2000
-->
diff --git a/Documentation/DocBook/v4l/lirc_device_interface.xml b/Documentation/DocBook/v4l/lirc_device_interface.xml
new file mode 100644
index 00000000000..0413234023d
--- /dev/null
+++ b/Documentation/DocBook/v4l/lirc_device_interface.xml
@@ -0,0 +1,235 @@
+<section id="lirc_dev">
+<title>LIRC Device Interface</title>
+
+
+<section id="lirc_dev_intro">
+<title>Introduction</title>
+
+<para>The LIRC device interface is a bi-directional interface for
+transporting raw IR data between userspace and kernelspace. Fundamentally,
+it is just a chardev (/dev/lircX, for X = 0, 1, 2, ...), with a number
+of standard struct file_operations defined on it. With respect to
+transporting raw IR data to and fro, the essential fops are read, write
+and ioctl.</para>
+
+<para>Example dmesg output upon a driver registering w/LIRC:</para>
+ <blockquote>
+ <para>$ dmesg |grep lirc_dev</para>
+ <para>lirc_dev: IR Remote Control driver registered, major 248</para>
+ <para>rc rc0: lirc_dev: driver ir-lirc-codec (mceusb) registered at minor = 0</para>
+ </blockquote>
+
+<para>What you should see for a chardev:</para>
+ <blockquote>
+ <para>$ ls -l /dev/lirc*</para>
+ <para>crw-rw---- 1 root root 248, 0 Jul 2 22:20 /dev/lirc0</para>
+ </blockquote>
+</section>
+
+<section id="lirc_read">
+<title>LIRC read fop</title>
+
+<para>The lircd userspace daemon reads raw IR data from the LIRC chardev. The
+exact format of the data depends on what modes a driver supports, and what
+mode has been selected. lircd obtains supported modes and sets the active mode
+via the ioctl interface, detailed at <xref linkend="lirc_ioctl"/>. The generally
+preferred mode is LIRC_MODE_MODE2, in which packets containing an int value
+describing an IR signal are read from the chardev.</para>
+
+<para>See also <ulink url="http://www.lirc.org/html/technical.html">http://www.lirc.org/html/technical.html</ulink> for more info.</para>
+</section>
+
+<section id="lirc_write">
+<title>LIRC write fop</title>
+
+<para>The data written to the chardev is a pulse/space sequence of integer
+values. Pulses and spaces are only marked implicitly by their position. The
+data must start and end with a pulse, therefore, the data must always include
+an unevent number of samples. The write function must block until the data has
+been transmitted by the hardware.</para>
+</section>
+
+<section id="lirc_ioctl">
+<title>LIRC ioctl fop</title>
+
+<para>The LIRC device's ioctl definition is bound by the ioctl function
+definition of struct file_operations, leaving us with an unsigned int
+for the ioctl command and an unsigned long for the arg. For the purposes
+of ioctl portability across 32-bit and 64-bit, these values are capped
+to their 32-bit sizes.</para>
+
+<para>The following ioctls can be used to change specific hardware settings.
+In general each driver should have a default set of settings. The driver
+implementation is expected to re-apply the default settings when the device
+is closed by user-space, so that every application opening the device can rely
+on working with the default settings initially.</para>
+
+<variablelist>
+ <varlistentry>
+ <term>LIRC_GET_FEATURES</term>
+ <listitem>
+ <para>Obviously, get the underlying hardware device's features. If a driver
+ does not announce support of certain features, calling of the corresponding
+ ioctls is undefined.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>LIRC_GET_SEND_MODE</term>
+ <listitem>
+ <para>Get supported transmit mode. Only LIRC_MODE_PULSE is supported by lircd.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>LIRC_GET_REC_MODE</term>
+ <listitem>
+ <para>Get supported receive modes. Only LIRC_MODE_MODE2 and LIRC_MODE_LIRCCODE
+ are supported by lircd.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>LIRC_GET_SEND_CARRIER</term>
+ <listitem>
+ <para>Get carrier frequency (in Hz) currently used for transmit.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>LIRC_GET_REC_CARRIER</term>
+ <listitem>
+ <para>Get carrier frequency (in Hz) currently used for IR reception.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>LIRC_{G,S}ET_{SEND,REC}_DUTY_CYCLE</term>
+ <listitem>
+ <para>Get/set the duty cycle (from 0 to 100) of the carrier signal. Currently,
+ no special meaning is defined for 0 or 100, but this could be used to switch
+ off carrier generation in the future, so these values should be reserved.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>LIRC_GET_REC_RESOLUTION</term>
+ <listitem>
+ <para>Some receiver have maximum resolution which is defined by internal
+ sample rate or data format limitations. E.g. it's common that signals can
+ only be reported in 50 microsecond steps. This integer value is used by
+ lircd to automatically adjust the aeps tolerance value in the lircd
+ config file.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>LIRC_GET_M{IN,AX}_TIMEOUT</term>
+ <listitem>
+ <para>Some devices have internal timers that can be used to detect when
+ there's no IR activity for a long time. This can help lircd in detecting
+ that a IR signal is finished and can speed up the decoding process.
+ Returns an integer value with the minimum/maximum timeout that can be
+ set. Some devices have a fixed timeout, in that case both ioctls will
+ return the same value even though the timeout cannot be changed.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>LIRC_GET_M{IN,AX}_FILTER_{PULSE,SPACE}</term>
+ <listitem>
+ <para>Some devices are able to filter out spikes in the incoming signal
+ using given filter rules. These ioctls return the hardware capabilities
+ that describe the bounds of the possible filters. Filter settings depend
+ on the IR protocols that are expected. lircd derives the settings from
+ all protocols definitions found in its config file.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>LIRC_GET_LENGTH</term>
+ <listitem>
+ <para>Retrieves the code length in bits (only for LIRC_MODE_LIRCCODE).
+ Reads on the device must be done in blocks matching the bit count.
+ The bit could should be rounded up so that it matches full bytes.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>LIRC_SET_{SEND,REC}_MODE</term>
+ <listitem>
+ <para>Set send/receive mode. Largely obsolete for send, as only
+ LIRC_MODE_PULSE is supported.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>LIRC_SET_{SEND,REC}_CARRIER</term>
+ <listitem>
+ <para>Set send/receive carrier (in Hz).</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>LIRC_SET_TRANSMITTER_MASK</term>
+ <listitem>
+ <para>This enables the given set of transmitters. The first transmitter
+ is encoded by the least significant bit, etc. When an invalid bit mask
+ is given, i.e. a bit is set, even though the device does not have so many
+ transitters, then this ioctl returns the number of available transitters
+ and does nothing otherwise.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>LIRC_SET_REC_TIMEOUT</term>
+ <listitem>
+ <para>Sets the integer value for IR inactivity timeout (cf.
+ LIRC_GET_MIN_TIMEOUT and LIRC_GET_MAX_TIMEOUT). A value of 0 (if
+ supported by the hardware) disables all hardware timeouts and data should
+ be reported as soon as possible. If the exact value cannot be set, then
+ the next possible value _greater_ than the given value should be set.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>LIRC_SET_REC_TIMEOUT_REPORTS</term>
+ <listitem>
+ <para>Enable (1) or disable (0) timeout reports in LIRC_MODE_MODE2. By
+ default, timeout reports should be turned off.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>LIRC_SET_REC_FILTER_{,PULSE,SPACE}</term>
+ <listitem>
+ <para>Pulses/spaces shorter than this are filtered out by hardware. If
+ filters cannot be set independently for pulse/space, the corresponding
+ ioctls must return an error and LIRC_SET_REC_FILTER shall be used instead.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>LIRC_SET_MEASURE_CARRIER_MODE</term>
+ <listitem>
+ <para>Enable (1)/disable (0) measure mode. If enabled, from the next key
+ press on, the driver will send LIRC_MODE2_FREQUENCY packets. By default
+ this should be turned off.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>LIRC_SET_REC_{DUTY_CYCLE,CARRIER}_RANGE</term>
+ <listitem>
+ <para>To set a range use LIRC_SET_REC_DUTY_CYCLE_RANGE/LIRC_SET_REC_CARRIER_RANGE
+ with the lower bound first and later LIRC_SET_REC_DUTY_CYCLE/LIRC_SET_REC_CARRIER
+ with the upper bound.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>LIRC_NOTIFY_DECODE</term>
+ <listitem>
+ <para>This ioctl is called by lircd whenever a successful decoding of an
+ incoming IR signal could be done. This can be used by supporting hardware
+ to give visual feedback to the user e.g. by flashing a LED.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>LIRC_SETUP_{START,END}</term>
+ <listitem>
+ <para>Setting of several driver parameters can be optimized by encapsulating
+ the according ioctl calls with LIRC_SETUP_START/LIRC_SETUP_END. When a
+ driver receives a LIRC_SETUP_START ioctl it can choose to not commit
+ further setting changes to the hardware until a LIRC_SETUP_END is received.
+ But this is open to the driver implementation and every driver must also
+ handle parameter changes which are not encapsulated by LIRC_SETUP_START
+ and LIRC_SETUP_END. Drivers can also choose to ignore these ioctls.</para>
+ </listitem>
+ </varlistentry>
+</variablelist>
+
+</section>
+</section>
diff --git a/Documentation/DocBook/v4l/remote_controllers.xml b/Documentation/DocBook/v4l/remote_controllers.xml
index 73f5eab091f..3c3b667b28e 100644
--- a/Documentation/DocBook/v4l/remote_controllers.xml
+++ b/Documentation/DocBook/v4l/remote_controllers.xml
@@ -173,3 +173,5 @@ keymapping.</para>
<para>This program demonstrates how to replace the keymap tables.</para>
&sub-keytable-c;
</section>
+
+&sub-lirc_device_interface;
diff --git a/Documentation/HOWTO b/Documentation/HOWTO
index 40ada93b820..365bda9a0d9 100644
--- a/Documentation/HOWTO
+++ b/Documentation/HOWTO
@@ -187,7 +187,7 @@ apply a patch.
If you do not know where you want to start, but you want to look for
some task to start doing to join into the kernel development community,
go to the Linux Kernel Janitor's project:
- http://janitor.kernelnewbies.org/
+ http://kernelnewbies.org/KernelJanitors
It is a great place to start. It describes a list of relatively simple
problems that need to be cleaned up and fixed within the Linux kernel
source tree. Working with the developers in charge of this project, you
@@ -315,7 +315,7 @@ process is tracked with the tool patchwork. Patchwork offers a web
interface which shows patch postings, any comments on a patch or
revisions to it, and maintainers can mark patches as under review,
accepted, or rejected. Most of these patchwork sites are listed at
-http://patchwork.kernel.org/ or http://patchwork.ozlabs.org/.
+http://patchwork.kernel.org/.
2.6.x -next kernel tree for integration tests
---------------------------------------------
@@ -595,7 +595,7 @@ start exactly where you are now.
----------
Thanks to Paolo Ciarrocchi who allowed the "Development Process"
-(http://linux.tar.bz/articles/2.6-development_process) section
+(http://lwn.net/Articles/94386/) section
to be based on text he had written, and to Randy Dunlap and Gerrit
Huizenga for some of the list of things you should and should not say.
Also thanks to Pat Mochel, Hanna Linder, Randy Dunlap, Kay Sievers,
diff --git a/Documentation/PCI/pci.txt b/Documentation/PCI/pci.txt
index 7f6de6ea5b4..6148d4080f8 100644
--- a/Documentation/PCI/pci.txt
+++ b/Documentation/PCI/pci.txt
@@ -581,7 +581,7 @@ to be handled by platform and generic code, not individual drivers.
8. Vendor and device identifications
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-One is not not required to add new device ids to include/linux/pci_ids.h.
+One is not required to add new device ids to include/linux/pci_ids.h.
Please add PCI_VENDOR_ID_xxx for vendors and a hex constant for device ids.
PCI_VENDOR_ID_xxx constants are re-used. The device ids are arbitrary
diff --git a/Documentation/RCU/RTFP.txt b/Documentation/RCU/RTFP.txt
index 5aea459e3dd..c43460dade0 100644
--- a/Documentation/RCU/RTFP.txt
+++ b/Documentation/RCU/RTFP.txt
@@ -606,7 +606,7 @@ Suparna Bhattacharya"
,Year="2006"
,pages="v2 123-138"
,note="Available:
-\url{http://www.linuxsymposium.org/2006/view_abstract.php?content_key=184}
+\url{http://www.linuxsymposium.org/2006/index_2006.php}
\url{http://www.rdrop.com/users/paulmck/RCU/OLSrtRCU.2006.08.11a.pdf}
[Viewed January 1, 2007]"
,annotation="
diff --git a/Documentation/SubmittingDrivers b/Documentation/SubmittingDrivers
index 4947fd8fb18..38d2aab59ca 100644
--- a/Documentation/SubmittingDrivers
+++ b/Documentation/SubmittingDrivers
@@ -161,7 +161,7 @@ How to NOT write kernel driver by Arjan van de Ven:
http://www.fenrus.org/how-to-not-write-a-device-driver-paper.pdf
Kernel Janitor:
- http://janitor.kernelnewbies.org/
+ http://kernelnewbies.org/KernelJanitors
GIT, Fast Version Control System:
http://git-scm.com/
diff --git a/Documentation/aoe/aoe.txt b/Documentation/aoe/aoe.txt
index 3a4dbe4663c..b5aada9f20c 100644
--- a/Documentation/aoe/aoe.txt
+++ b/Documentation/aoe/aoe.txt
@@ -1,6 +1,6 @@
The EtherDrive (R) HOWTO for users of 2.6 kernels is found at ...
- http://www.coraid.com/support/linux/EtherDrive-2.6-HOWTO.html
+ http://www.coraid.com/SUPPORT/EtherDrive-HBA
It has many tips and hints!
diff --git a/Documentation/apparmor.txt b/Documentation/apparmor.txt
new file mode 100644
index 00000000000..93c1fd7d063
--- /dev/null
+++ b/Documentation/apparmor.txt
@@ -0,0 +1,39 @@
+--- What is AppArmor? ---
+
+AppArmor is MAC style security extension for the Linux kernel. It implements
+a task centered policy, with task "profiles" being created and loaded
+from user space. Tasks on the system that do not have a profile defined for
+them run in an unconfined state which is equivalent to standard Linux DAC
+permissions.
+
+--- How to enable/disable ---
+
+set CONFIG_SECURITY_APPARMOR=y
+
+If AppArmor should be selected as the default security module then
+ set CONFIG_DEFAULT_SECURITY="apparmor"
+ and CONFIG_SECURITY_APPARMOR_BOOTPARAM_VALUE=1
+
+Build the kernel
+
+If AppArmor is not the default security module it can be enabled by passing
+security=apparmor on the kernel's command line.
+
+If AppArmor is the default security module it can be disabled by passing
+apparmor=0, security=XXXX (where XXX is valid security module), on the
+kernel's command line
+
+For AppArmor to enforce any restrictions beyond standard Linux DAC permissions
+policy must be loaded into the kernel from user space (see the Documentation
+and tools links).
+
+--- Documentation ---
+
+Documentation can be found on the wiki.
+
+--- Links ---
+
+Mailing List - apparmor@lists.ubuntu.com
+Wiki - http://apparmor.wiki.kernel.org/
+User space tools - https://launchpad.net/apparmor
+Kernel module - git://git.kernel.org/pub/scm/linux/kernel/git/jj/apparmor-dev.git
diff --git a/Documentation/arm/IXP2000 b/Documentation/arm/IXP2000
index e0148b6b2c4..68d21d92a30 100644
--- a/Documentation/arm/IXP2000
+++ b/Documentation/arm/IXP2000
@@ -14,7 +14,7 @@ telecom systems. In addition to an XScale core, it contains up to 8
interfaces (UTOPIA, SPI, etc), a PCI host bridge, one serial port,
flash interface, and some other odds and ends. For more information, see:
-http://developer.intel.com/design/network/products/npfamily/ixp2xxx.htm
+http://developer.intel.com
2. Linux Support
diff --git a/Documentation/arm/IXP4xx b/Documentation/arm/IXP4xx
index 72fbcc4fcab..133c5fa6c7a 100644
--- a/Documentation/arm/IXP4xx
+++ b/Documentation/arm/IXP4xx
@@ -45,7 +45,7 @@ require the use of Intel's propietary CSR softare:
If you need to use any of the above, you need to download Intel's
software from:
- http://developer.intel.com/design/network/products/npfamily/ixp425swr1.htm
+ http://developer.intel.com/design/network/products/npfamily/ixp425.htm
DO NOT POST QUESTIONS TO THE LINUX MAILING LISTS REGARDING THE PROPIETARY
SOFTWARE.
@@ -53,7 +53,7 @@ SOFTWARE.
There are several websites that provide directions/pointers on using
Intel's software:
-http://ixp4xx-osdg.sourceforge.net/
+ http://sourceforge.net/projects/ixp4xx-osdg/
Open Source Developer's Guide for using uClinux and the Intel libraries
http://gatewaymaker.sourceforge.net/
@@ -112,21 +112,21 @@ http://www.adiengineering.com/productsCoyote.html
Finally, there is an IDE port hanging off the expansion bus.
Gateworks Avila Network Platform
-http://www.gateworks.com/avila_sbc.htm
+http://www.gateworks.com/support/overview.php
The Avila platform is basically and IXDP425 with the 4 PCI slots
replaced with mini-PCI slots and a CF IDE interface hanging off
the expansion bus.
Intel IXDP425 Development Platform
-http://developer.intel.com/design/network/products/npfamily/ixdp425.htm
+http://www.intel.com/design/network/products/npfamily/ixdpg425.htm
This is Intel's standard reference platform for the IXDP425 and is
also known as the Richfield board. It contains 4 PCI slots, 16MB
of flash, two 10/100 ports and one ADSL port.
Intel IXDP465 Development Platform
-http://developer.intel.com/design/network/products/npfamily/ixdp465.htm
+http://www.intel.com/design/network/products/npfamily/ixdp465.htm
This is basically an IXDP425 with an IXP465 and 32M of flash instead
of just 16.
@@ -141,15 +141,13 @@ Intel IXDPG425 Development Platform
a pivot_root to NFS.
Motorola PrPMC1100 Processor Mezanine Card
-http://www.fountainsys.com/datasheet/PrPMC1100.pdf
+http://www.fountainsys.com
The PrPMC1100 is based on the IXCP1100 and is meant to plug into
and IXP2400/2800 system to act as the system controller. It simply
contains a CPU and 16MB of flash on the board and needs to be
plugged into a carrier board to function. Currently Linux only
supports the Motorola PrPMC carrier board for this platform.
- See https://mcg.motorola.com/us/ds/pdf/ds0144.pdf for info
- on the carrier board.
5. TODO LIST
diff --git a/Documentation/arm/README b/Documentation/arm/README
index d98783fbe0c..aea34095cdc 100644
--- a/Documentation/arm/README
+++ b/Documentation/arm/README
@@ -41,12 +41,12 @@ Bug reports etc
---------------
Please send patches to the patch system. For more information, see
- http://www.arm.linux.org.uk/patches/info.html Always include some
+ http://www.arm.linux.org.uk/developer/patches/info.php Always include some
explanation as to what the patch does and why it is needed.
Bug reports should be sent to linux-arm-kernel@lists.arm.linux.org.uk,
or submitted through the web form at
- http://www.arm.linux.org.uk/forms/solution.shtml
+ http://www.arm.linux.org.uk/developer/
When sending bug reports, please ensure that they contain all relevant
information, eg. the kernel messages that were printed before/during
diff --git a/Documentation/arm/SA1100/Assabet b/Documentation/arm/SA1100/Assabet
index 91f7ce7ba42..08b885d3567 100644
--- a/Documentation/arm/SA1100/Assabet
+++ b/Documentation/arm/SA1100/Assabet
@@ -2,8 +2,7 @@ The Intel Assabet (SA-1110 evaluation) board
============================================
Please see:
-http://developer.intel.com/design/strong/quicklist/eval-plat/sa-1110.htm
-http://developer.intel.com/design/strong/guides/278278.htm
+http://developer.intel.com
Also some notes from John G Dorsey <jd5q@andrew.cmu.edu>:
http://www.cs.cmu.edu/~wearable/software/assabet.html
@@ -64,7 +63,7 @@ Initial RedBoot configuration
-----------------------------
The commands used here are explained in The RedBoot User's Guide available
-on-line at http://sources.redhat.com/ecos/docs-latest/redboot/redboot.html.
+on-line at http://sources.redhat.com/ecos/docs.html.
Please refer to it for explanations.
If you have a CF network card (my Assabet kit contained a CF+ LP-E from
diff --git a/Documentation/arm/SA1100/Brutus b/Documentation/arm/SA1100/Brutus
index b1cfd405dcc..6a3aa95e9bf 100644
--- a/Documentation/arm/SA1100/Brutus
+++ b/Documentation/arm/SA1100/Brutus
@@ -1,7 +1,7 @@
Brutus is an evaluation platform for the SA1100 manufactured by Intel.
For more details, see:
-http://developer.intel.com/design/strong/applnots/sa1100lx/getstart.htm
+http://developer.intel.com
To compile for Brutus, you must issue the following commands:
diff --git a/Documentation/arm/SA1100/FreeBird b/Documentation/arm/SA1100/FreeBird
index eda28b3232e..fb23b770aaf 100644
--- a/Documentation/arm/SA1100/FreeBird
+++ b/Documentation/arm/SA1100/FreeBird
@@ -1,5 +1,5 @@
Freebird-1.1 is produced by Legned(C) ,Inc.
-(http://www.legend.com.cn)
+http://web.archive.org/web/*/http://www.legend.com.cn
and software/linux mainatined by Coventive(C),Inc.
(http://www.coventive.com)
diff --git a/Documentation/arm/SA1100/GraphicsClient b/Documentation/arm/SA1100/GraphicsClient
index 6c9c4f5a36e..867bb35943a 100644
--- a/Documentation/arm/SA1100/GraphicsClient
+++ b/Documentation/arm/SA1100/GraphicsClient
@@ -71,7 +71,7 @@ Supported peripherals:
- serial ports (ttyS[0-2])
- ttyS0 is default for serial console
- Smart I/O (ADC, keypad, digital inputs, etc)
- See http://www.applieddata.com/developers/linux for IOCTL documentation
+ See http://www.eurotech-inc.com/linux-sbc.asp for IOCTL documentation
and example user space code. ps/2 keybd is multiplexed through this driver
To do:
diff --git a/Documentation/arm/SA1100/GraphicsMaster b/Documentation/arm/SA1100/GraphicsMaster
index ee7c6595f23..9145088a0ba 100644
--- a/Documentation/arm/SA1100/GraphicsMaster
+++ b/Documentation/arm/SA1100/GraphicsMaster
@@ -28,7 +28,7 @@ Supported peripherals:
- serial ports (ttyS[0-2])
- ttyS0 is default for serial console
- Smart I/O (ADC, keypad, digital inputs, etc)
- See http://www.applieddata.com/developers/linux for IOCTL documentation
+ See http://www.eurotech-inc.com/linux-sbc.asp for IOCTL documentation
and example user space code. ps/2 keybd is multiplexed through this driver
To do:
diff --git a/Documentation/arm/SA1100/Itsy b/Documentation/arm/SA1100/Itsy
index 3b594534323..44b94997fa0 100644
--- a/Documentation/arm/SA1100/Itsy
+++ b/Documentation/arm/SA1100/Itsy
@@ -4,7 +4,7 @@ research projects at Compaq that are related to pocket computing.
For more information, see:
- http://www.research.digital.com/wrl/itsy/index.html
+ http://www.hpl.hp.com/downloads/crl/itsy/
Notes on initial 2.4 Itsy support (8/27/2000) :
The port was done on an Itsy version 1.5 machine with a daughtercard with
diff --git a/Documentation/arm/SA1100/PLEB b/Documentation/arm/SA1100/PLEB
index 92cae066908..b9c8a631a35 100644
--- a/Documentation/arm/SA1100/PLEB
+++ b/Documentation/arm/SA1100/PLEB
@@ -6,6 +6,6 @@ PLEB support has yet to be fully integrated.
For more information, see:
- http://www.cse.unsw.edu.au/~pleb/
+ http://www.cse.unsw.edu.au
diff --git a/Documentation/arm/SA1100/Victor b/Documentation/arm/SA1100/Victor
index f938a29fdc2..9cff415da5a 100644
--- a/Documentation/arm/SA1100/Victor
+++ b/Documentation/arm/SA1100/Victor
@@ -3,7 +3,7 @@ VisuAide, Inc. to be used by blind people.
For more information related to Victor, see:
- http://www.visuaide.com/victor
+ http://www.humanware.com/en-usa/products
Of course Victor is using Linux as its main operating system.
The Victor implementation for Linux is maintained by Nicolas Pitre:
diff --git a/Documentation/arm/SA1100/nanoEngine b/Documentation/arm/SA1100/nanoEngine
index fc431cbfefc..48a7934f95f 100644
--- a/Documentation/arm/SA1100/nanoEngine
+++ b/Documentation/arm/SA1100/nanoEngine
@@ -7,5 +7,5 @@ for more info.
(Ref: Stuart Adams <sja@brightstareng.com>)
Also visit Larry Doolittle's "Linux for the nanoEngine" site:
-http://recycle.lbl.gov/~ldoolitt/bse/
+http://www.brightstareng.com/arm/nanoeng.htm
diff --git a/Documentation/binfmt_misc.txt b/Documentation/binfmt_misc.txt
index f609ebf9c78..c1ed6948ba8 100644
--- a/Documentation/binfmt_misc.txt
+++ b/Documentation/binfmt_misc.txt
@@ -111,6 +111,6 @@ cause unexpected behaviour and can be a security hazard.
There is a web page about binfmt_misc at
-http://www.tat.physik.uni-tuebingen.de/~rguenth/linux/binfmt_misc.html
+http://www.tat.physik.uni-tuebingen.de
Richard Günther <rguenth@tat.physik.uni-tuebingen.de>
diff --git a/Documentation/block/biodoc.txt b/Documentation/block/biodoc.txt
index 508b5b2b028..b9a83dd2473 100644
--- a/Documentation/block/biodoc.txt
+++ b/Documentation/block/biodoc.txt
@@ -7,7 +7,7 @@ Notes Written on Jan 15, 2002:
Last Updated May 2, 2002
September 2003: Updated I/O Scheduler portions
- Nick Piggin <piggin@cyberone.com.au>
+ Nick Piggin <npiggin@kernel.dk>
Introduction:
diff --git a/Documentation/blockdev/paride.txt b/Documentation/blockdev/paride.txt
index e4312676bdd..ee6717e3771 100644
--- a/Documentation/blockdev/paride.txt
+++ b/Documentation/blockdev/paride.txt
@@ -412,6 +412,6 @@ have in your mail headers, when sending mail to the list server.
You might also find some useful information on the linux-parport
web pages (although they are not always up to date) at
- http://www.torque.net/parport/
+ http://web.archive.org/web/*/http://www.torque.net/parport/
diff --git a/Documentation/cdrom/packet-writing.txt b/Documentation/cdrom/packet-writing.txt
index 1c407778c8b..13c251d5add 100644
--- a/Documentation/cdrom/packet-writing.txt
+++ b/Documentation/cdrom/packet-writing.txt
@@ -95,7 +95,7 @@ Using the pktcdvd sysfs interface
Since Linux 2.6.20, the pktcdvd module has a sysfs interface
and can be controlled by it. For example the "pktcdvd" tool uses
-this interface. (see http://people.freenet.de/BalaGi#pktcdvd )
+this interface. (see http://tom.ist-im-web.de/download/pktcdvd )
"pktcdvd" works similar to "pktsetup", e.g.:
diff --git a/Documentation/cgroups/cpusets.txt b/Documentation/cgroups/cpusets.txt
index 51682ab2dd1..5d0d5692a36 100644
--- a/Documentation/cgroups/cpusets.txt
+++ b/Documentation/cgroups/cpusets.txt
@@ -691,7 +691,7 @@ There are ways to query or modify cpusets:
cat, rmdir commands from the shell, or their equivalent from C.
- via the C library libcpuset.
- via the C library libcgroup.
- (http://sourceforge.net/proects/libcg/)
+ (http://sourceforge.net/projects/libcg/)
- via the python application cset.
(http://developer.novell.com/wiki/index.php/Cpuset)
diff --git a/Documentation/coccinelle.txt b/Documentation/coccinelle.txt
new file mode 100644
index 00000000000..cd2b0283706
--- /dev/null
+++ b/Documentation/coccinelle.txt
@@ -0,0 +1,258 @@
+Copyright 2010 Nicolas Palix <npalix@diku.dk>
+Copyright 2010 Julia Lawall <julia@diku.dk>
+Copyright 2010 Gilles Muller <Gilles.Muller@lip6.fr>
+
+
+ Getting Coccinelle
+~~~~~~~~~~~~~~~~~~~~
+
+The semantic patches included in the kernel use the 'virtual rule'
+feature which was introduced in Coccinelle version 0.1.11.
+
+Coccinelle (>=0.2.0) is available through the package manager
+of many distributions, e.g. :
+
+ - Debian (>=squeeze)
+ - Fedora (>=13)
+ - Ubuntu (>=10.04 Lucid Lynx)
+ - OpenSUSE
+ - Arch Linux
+ - NetBSD
+ - FreeBSD
+
+
+You can get the latest version released from the Coccinelle homepage at
+http://coccinelle.lip6.fr/
+
+Once you have it, run the following command:
+
+ ./configure
+ make
+
+as a regular user, and install it with
+
+ sudo make install
+
+
+ Using Coccinelle on the Linux kernel
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+A Coccinelle-specific target is defined in the top level
+Makefile. This target is named 'coccicheck' and calls the 'coccicheck'
+front-end in the 'scripts' directory.
+
+Four modes are defined: report, patch, context, and org. The mode to
+use is specified by setting the MODE variable with 'MODE=<mode>'.
+
+'report' generates a list in the following format:
+ file:line:column-column: message
+
+'patch' proposes a fix, when possible.
+
+'context' highlights lines of interest and their context in a
+diff-like style.Lines of interest are indicated with '-'.
+
+'org' generates a report in the Org mode format of Emacs.
+
+Note that not all semantic patches implement all modes.
+
+To make a report for every semantic patch, run the following command:
+
+ make coccicheck MODE=report
+
+NB: The 'report' mode is the default one.
+
+To produce patches, run:
+
+ make coccicheck MODE=patch
+
+
+The coccicheck target applies every semantic patch available in the
+subdirectories of 'scripts/coccinelle' to the entire Linux kernel.
+
+For each semantic patch, a changelog message is proposed. It gives a
+description of the problem being checked by the semantic patch, and
+includes a reference to Coccinelle.
+
+As any static code analyzer, Coccinelle produces false
+positives. Thus, reports must be carefully checked, and patches
+reviewed.
+
+
+ Using Coccinelle with a single semantic patch
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The optional make variable COCCI can be used to check a single
+semantic patch. In that case, the variable must be initialized with
+the name of the semantic patch to apply.
+
+For instance:
+
+ make coccicheck COCCI=<my_SP.cocci> MODE=patch
+or
+ make coccicheck COCCI=<my_SP.cocci> MODE=report
+
+
+ Proposing new semantic patches
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+New semantic patches can be proposed and submitted by kernel
+developers. For sake of clarity, they should be organized in the
+subdirectories of 'scripts/coccinelle/'.
+
+
+ Detailed description of the 'report' mode
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+'report' generates a list in the following format:
+ file:line:column-column: message
+
+Example:
+
+Running
+
+ make coccicheck MODE=report COCCI=scripts/coccinelle/err_cast.cocci
+
+will execute the following part of the SmPL script.
+
+<smpl>
+@r depends on !context && !patch && (org || report)@
+expression x;
+position p;
+@@
+
+ ERR_PTR@p(PTR_ERR(x))
+
+@script:python depends on report@
+p << r.p;
+x << r.x;
+@@
+
+msg="ERR_CAST can be used with %s" % (x)
+coccilib.report.print_report(p[0], msg)
+</smpl>
+
+This SmPL excerpt generates entries on the standard output, as
+illustrated below:
+
+/home/user/linux/crypto/ctr.c:188:9-16: ERR_CAST can be used with alg
+/home/user/linux/crypto/authenc.c:619:9-16: ERR_CAST can be used with auth
+/home/user/linux/crypto/xts.c:227:9-16: ERR_CAST can be used with alg
+
+
+ Detailed description of the 'patch' mode
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+When the 'patch' mode is available, it proposes a fix for each problem
+identified.
+
+Example:
+
+Running
+ make coccicheck MODE=patch COCCI=scripts/coccinelle/err_cast.cocci
+
+will execute the following part of the SmPL script.
+
+<smpl>
+@ depends on !context && patch && !org && !report @
+expression x;
+@@
+
+- ERR_PTR(PTR_ERR(x))
++ ERR_CAST(x)
+</smpl>
+
+This SmPL excerpt generates patch hunks on the standard output, as
+illustrated below:
+
+diff -u -p a/crypto/ctr.c b/crypto/ctr.c
+--- a/crypto/ctr.c 2010-05-26 10:49:38.000000000 +0200
++++ b/crypto/ctr.c 2010-06-03 23:44:49.000000000 +0200
+@@ -185,7 +185,7 @@ static struct crypto_instance *crypto_ct
+ alg = crypto_attr_alg(tb[1], CRYPTO_ALG_TYPE_CIPHER,
+ CRYPTO_ALG_TYPE_MASK);
+ if (IS_ERR(alg))
+- return ERR_PTR(PTR_ERR(alg));
++ return ERR_CAST(alg);
+
+ /* Block size must be >= 4 bytes. */
+ err = -EINVAL;
+
+ Detailed description of the 'context' mode
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+'context' highlights lines of interest and their context
+in a diff-like style.
+
+NOTE: The diff-like output generated is NOT an applicable patch. The
+ intent of the 'context' mode is to highlight the important lines
+ (annotated with minus, '-') and gives some surrounding context
+ lines around. This output can be used with the diff mode of
+ Emacs to review the code.
+
+Example:
+
+Running
+ make coccicheck MODE=context COCCI=scripts/coccinelle/err_cast.cocci
+
+will execute the following part of the SmPL script.
+
+<smpl>
+@ depends on context && !patch && !org && !report@
+expression x;
+@@
+
+* ERR_PTR(PTR_ERR(x))
+</smpl>
+
+This SmPL excerpt generates diff hunks on the standard output, as
+illustrated below:
+
+diff -u -p /home/user/linux/crypto/ctr.c /tmp/nothing
+--- /home/user/linux/crypto/ctr.c 2010-05-26 10:49:38.000000000 +0200
++++ /tmp/nothing
+@@ -185,7 +185,6 @@ static struct crypto_instance *crypto_ct
+ alg = crypto_attr_alg(tb[1], CRYPTO_ALG_TYPE_CIPHER,
+ CRYPTO_ALG_TYPE_MASK);
+ if (IS_ERR(alg))
+- return ERR_PTR(PTR_ERR(alg));
+
+ /* Block size must be >= 4 bytes. */
+ err = -EINVAL;
+
+ Detailed description of the 'org' mode
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+'org' generates a report in the Org mode format of Emacs.
+
+Example:
+
+Running
+ make coccicheck MODE=org COCCI=scripts/coccinelle/err_cast.cocci
+
+will execute the following part of the SmPL script.
+
+<smpl>
+@r depends on !context && !patch && (org || report)@
+expression x;
+position p;
+@@
+
+ ERR_PTR@p(PTR_ERR(x))
+
+@script:python depends on org@
+p << r.p;
+x << r.x;
+@@
+
+msg="ERR_CAST can be used with %s" % (x)
+msg_safe=msg.replace("[","@(").replace("]",")")
+coccilib.org.print_todo(p[0], msg_safe)
+</smpl>
+
+This SmPL excerpt generates Org entries on the standard output, as
+illustrated below:
+
+* TODO [[view:/home/user/linux/crypto/ctr.c::face=ovl-face1::linb=188::colb=9::cole=16][ERR_CAST can be used with alg]]
+* TODO [[view:/home/user/linux/crypto/authenc.c::face=ovl-face1::linb=619::colb=9::cole=16][ERR_CAST can be used with auth]]
+* TODO [[view:/home/user/linux/crypto/xts.c::face=ovl-face1::linb=227::colb=9::cole=16][ERR_CAST can be used with alg]]
diff --git a/Documentation/development-process/4.Coding b/Documentation/development-process/4.Coding
index a5a3450faaa..2278693c8ff 100644
--- a/Documentation/development-process/4.Coding
+++ b/Documentation/development-process/4.Coding
@@ -281,7 +281,7 @@ With sparse, the programmer can be warned about confusion between
user-space and kernel-space addresses, mixture of big-endian and
small-endian quantities, the passing of integer values where a set of bit
flags is expected, and so on. Sparse must be installed separately (it can
-be found at http://www.kernel.org/pub/software/devel/sparse/ if your
+be found at https://sparse.wiki.kernel.org/index.php/Main_Page if your
distributor does not package it); it can then be run on the code by adding
"C=1" to your make command.
diff --git a/Documentation/device-mapper/dm-crypt.txt b/Documentation/device-mapper/dm-crypt.txt
index 6680cab2c70..524de926290 100644
--- a/Documentation/device-mapper/dm-crypt.txt
+++ b/Documentation/device-mapper/dm-crypt.txt
@@ -36,7 +36,7 @@ Example scripts
===============
LUKS (Linux Unified Key Setup) is now the preferred way to set up disk
encryption with dm-crypt using the 'cryptsetup' utility, see
-http://luks.endorphin.org/
+http://clemens.endorphin.org/cryptography
[[
#!/bin/sh
diff --git a/Documentation/devices.txt b/Documentation/devices.txt
index 1d83d124056..f2da781705b 100644
--- a/Documentation/devices.txt
+++ b/Documentation/devices.txt
@@ -1517,7 +1517,7 @@ Your cooperation is appreciated.
...
The driver and documentation may be obtained from
- http://www.proximity.com.au/~brian/winradio/
+ http://www.winradio.com/
82 block I2O hard disk
0 = /dev/i2o/hdag 33rd I2O hard disk, whole disk
@@ -1723,7 +1723,7 @@ Your cooperation is appreciated.
1 = /dev/comedi1 Second comedi device
...
- See http://stm.lbl.gov/comedi or http://www.llp.fu-berlin.de/.
+ See http://stm.lbl.gov/comedi.
98 block User-mode virtual block device
0 = /dev/ubda First user-mode block device
@@ -1984,7 +1984,7 @@ Your cooperation is appreciated.
256 NetWare volumes can be supported in a single
machine.
- http://www.kernel.org/pub/linux/kernel/people/jmerkey/nwfs
+ http://cgfa.telepac.pt/ftp2/kernel.org/linux/kernel/people/jmerkey/nwfs/
0 = /dev/nwfs/v0 First NetWare (NWFS) Logical Volume
1 = /dev/nwfs/v1 Second NetWare (NWFS) Logical Volume
@@ -2591,7 +2591,8 @@ Your cooperation is appreciated.
1 = /dev/intermezzo1 Second cache manager
...
- See http://www.inter-mezzo.org/ for more information.
+ See http://web.archive.org/web/20080115195241/
+ http://inter-mezzo.org/index.html
186 char Object-based storage control device
0 = /dev/obd0 First obd control device
diff --git a/Documentation/dvb/faq.txt b/Documentation/dvb/faq.txt
index 2511a335abd..121832e5d89 100644
--- a/Documentation/dvb/faq.txt
+++ b/Documentation/dvb/faq.txt
@@ -76,7 +76,7 @@ Some very frequently asked questions about linuxtv-dvb
the TuxBox CVS many interesting DVB applications and the dBox2
DVB source
- http://sourceforge.net/projects/dvbsak/
+ http://www.linuxtv.org/downloads/
DVB Swiss Army Knife library and utilities
http://www.nenie.org/misc/mpsys/
diff --git a/Documentation/dvb/get_dvb_firmware b/Documentation/dvb/get_dvb_firmware
index 239cbdbf4d1..350959f4e41 100644
--- a/Documentation/dvb/get_dvb_firmware
+++ b/Documentation/dvb/get_dvb_firmware
@@ -26,7 +26,7 @@ use IO::Handle;
"dec3000s", "vp7041", "dibusb", "nxt2002", "nxt2004",
"or51211", "or51132_qam", "or51132_vsb", "bluebird",
"opera1", "cx231xx", "cx18", "cx23885", "pvrusb2", "mpc718",
- "af9015", "ngene");
+ "af9015", "ngene", "az6027");
# Check args
syntax() if (scalar(@ARGV) != 1);
@@ -518,11 +518,11 @@ sub bluebird {
sub af9015 {
my $sourcefile = "download.ashx?file=57";
my $url = "http://www.ite.com.tw/EN/Services/$sourcefile";
- my $hash = "ff5b096ed47c080870eacdab2de33ad6";
+ my $hash = "e3f08935158038d385ad382442f4bb2d";
my $outfile = "dvb-usb-af9015.fw";
my $tmpdir = tempdir(DIR => "/tmp", CLEANUP => 1);
- my $fwoffset = 0x22708;
- my $fwlength = 18225;
+ my $fwoffset = 0x25690;
+ my $fwlength = 18725;
my ($chunklength, $buf, $rcount);
checkstandard();
@@ -567,6 +567,23 @@ sub ngene {
"$file1, $file2";
}
+sub az6027{
+ my $file = "AZ6027_Linux_Driver.tar.gz";
+ my $url = "http://linux.terratec.de/files/$file";
+ my $firmware = "dvb-usb-az6027-03.fw";
+
+ wgetfile($file, $url);
+
+ #untar
+ if( system("tar xzvf $file $firmware")){
+ die "failed to untar firmware";
+ }
+ if( system("rm $file")){
+ die ("unable to remove unnecessary files");
+ }
+
+ $firmware;
+}
# ---------------------------------------------------------------
# Utilities
diff --git a/Documentation/fb/framebuffer.txt b/Documentation/fb/framebuffer.txt
index fe79e3c8847..58c5ae2e9f5 100644
--- a/Documentation/fb/framebuffer.txt
+++ b/Documentation/fb/framebuffer.txt
@@ -330,7 +330,7 @@ and on its mirrors.
The latest version of fbset can be found at
- http://home.tvd.be/cr26864/Linux/fbdev/
+ http://www.linux-fbdev.org/
10. Credits
diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt
index 1571c0c83db..71f0fea1058 100644
--- a/Documentation/feature-removal-schedule.txt
+++ b/Documentation/feature-removal-schedule.txt
@@ -93,7 +93,7 @@ Why: Broken design for runtime control over driver power states, confusing
inputs. This framework was never widely used, and most attempts to
use it were broken. Drivers should instead be exposing domain-specific
interfaces either to kernel or to userspace.
-Who: Pavel Machek <pavel@suse.cz>
+Who: Pavel Machek <pavel@ucw.cz>
---------------------------
@@ -116,29 +116,6 @@ Who: Mauro Carvalho Chehab <mchehab@infradead.org>
---------------------------
-What: PCMCIA control ioctl (needed for pcmcia-cs [cardmgr, cardctl])
-When: 2.6.35/2.6.36
-Files: drivers/pcmcia/: pcmcia_ioctl.c
-Why: With the 16-bit PCMCIA subsystem now behaving (almost) like a
- normal hotpluggable bus, and with it using the default kernel
- infrastructure (hotplug, driver core, sysfs) keeping the PCMCIA
- control ioctl needed by cardmgr and cardctl from pcmcia-cs is
- unnecessary and potentially harmful (it does not provide for
- proper locking), and makes further cleanups and integration of the
- PCMCIA subsystem into the Linux kernel device driver model more
- difficult. The features provided by cardmgr and cardctl are either
- handled by the kernel itself now or are available in the new
- pcmciautils package available at
- http://kernel.org/pub/linux/utils/kernel/pcmcia/
-
- For all architectures except ARM, the associated config symbol
- has been removed from kernel 2.6.34; for ARM, it will be likely
- be removed from kernel 2.6.35. The actual code will then likely
- be removed from kernel 2.6.36.
-Who: Dominik Brodowski <linux@dominikbrodowski.net>
-
----------------------------
-
What: sys_sysctl
When: September 2010
Option: CONFIG_SYSCTL_SYSCALL
@@ -303,15 +280,6 @@ Who: Johannes Berg <johannes@sipsolutions.net>
---------------------------
-What: CONFIG_NF_CT_ACCT
-When: 2.6.29
-Why: Accounting can now be enabled/disabled without kernel recompilation.
- Currently used only to set a default value for a feature that is also
- controlled by a kernel/module/sysfs/sysctl parameter.
-Who: Krzysztof Piotr Oledzki <ole@ans.pl>
-
----------------------------
-
What: sysfs ui for changing p4-clockmod parameters
When: September 2009
Why: See commits 129f8ae9b1b5be94517da76009ea956e89104ce8 and
@@ -377,16 +345,6 @@ Who: Eric Paris <eparis@redhat.com>
----------------------------
-What: lock_policy_rwsem_* and unlock_policy_rwsem_* will not be
- exported interface anymore.
-When: 2.6.33
-Why: cpu_policy_rwsem has a new cleaner definition making it local to
- cpufreq core and contained inside cpufreq.c. Other dependent
- drivers should not use it in order to safely avoid lockdep issues.
-Who: Venkatesh Pallipadi <venkatesh.pallipadi@intel.com>
-
-----------------------------
-
What: sound-slot/service-* module aliases and related clutters in
sound/sound_core.c
When: August 2010
@@ -459,57 +417,6 @@ Who: Corentin Chary <corentin.chary@gmail.com>
----------------------------
-What: usbvideo quickcam_messenger driver
-When: 2.6.35
-Files: drivers/media/video/usbvideo/quickcam_messenger.[ch]
-Why: obsolete v4l1 driver replaced by gspca_stv06xx
-Who: Hans de Goede <hdegoede@redhat.com>
-
-----------------------------
-
-What: ov511 v4l1 driver
-When: 2.6.35
-Files: drivers/media/video/ov511.[ch]
-Why: obsolete v4l1 driver replaced by gspca_ov519
-Who: Hans de Goede <hdegoede@redhat.com>
-
-----------------------------
-
-What: w9968cf v4l1 driver
-When: 2.6.35
-Files: drivers/media/video/w9968cf*.[ch]
-Why: obsolete v4l1 driver replaced by gspca_ov519
-Who: Hans de Goede <hdegoede@redhat.com>
-
-----------------------------
-
-What: ovcamchip sensor framework
-When: 2.6.35
-Files: drivers/media/video/ovcamchip/*
-Why: Only used by obsoleted v4l1 drivers
-Who: Hans de Goede <hdegoede@redhat.com>
-
-----------------------------
-
-What: stv680 v4l1 driver
-When: 2.6.35
-Files: drivers/media/video/stv680.[ch]
-Why: obsolete v4l1 driver replaced by gspca_stv0680
-Who: Hans de Goede <hdegoede@redhat.com>
-
-----------------------------
-
-What: zc0301 v4l driver
-When: 2.6.35
-Files: drivers/media/video/zc0301/*
-Why: Duplicate functionality with the gspca_zc3xx driver, zc0301 only
- supports 2 USB-ID's (because it only supports a limited set of
- sensors) wich are also supported by the gspca_zc3xx driver
- (which supports 53 USB-ID's in total)
-Who: Hans de Goede <hdegoede@redhat.com>
-
-----------------------------
-
What: sysfs-class-rfkill state file
When: Feb 2014
Files: net/rfkill/core.c
@@ -538,37 +445,6 @@ Who: Jan Kiszka <jan.kiszka@web.de>
----------------------------
-What: KVM memory aliases support
-When: July 2010
-Why: Memory aliasing support is used for speeding up guest vga access
- through the vga windows.
-
- Modern userspace no longer uses this feature, so it's just bitrotted
- code and can be removed with no impact.
-Who: Avi Kivity <avi@redhat.com>
-
-----------------------------
-
-What: xtime, wall_to_monotonic
-When: 2.6.36+
-Files: kernel/time/timekeeping.c include/linux/time.h
-Why: Cleaning up timekeeping internal values. Please use
- existing timekeeping accessor functions to access
- the equivalent functionality.
-Who: John Stultz <johnstul@us.ibm.com>
-
-----------------------------
-
-What: KVM kernel-allocated memory slots
-When: July 2010
-Why: Since 2.6.25, kvm supports user-allocated memory slots, which are
- much more flexible than kernel-allocated slots. All current userspace
- supports the newer interface and this code can be removed with no
- impact.
-Who: Avi Kivity <avi@redhat.com>
-
-----------------------------
-
What: KVM paravirt mmu host support
When: January 2011
Why: The paravirt mmu host support is slower than non-paravirt mmu, both
diff --git a/Documentation/filesystems/9p.txt b/Documentation/filesystems/9p.txt
index c0236e753bc..f9765e8cf08 100644
--- a/Documentation/filesystems/9p.txt
+++ b/Documentation/filesystems/9p.txt
@@ -128,7 +128,7 @@ OPTIONS
RESOURCES
=========
-Our current recommendation is to use Inferno (http://www.vitanuova.com/inferno)
+Our current recommendation is to use Inferno (http://www.vitanuova.com/nferno/index.html)
as the 9p server. You can start a 9p server under Inferno by issuing the
following command:
; styxlisten -A tcp!*!564 export '#U*'
diff --git a/Documentation/filesystems/affs.txt b/Documentation/filesystems/affs.txt
index 2d1524469c2..81ac488e375 100644
--- a/Documentation/filesystems/affs.txt
+++ b/Documentation/filesystems/affs.txt
@@ -216,4 +216,4 @@ due to an incompatibility with the Amiga floppy controller.
If you are interested in an Amiga Emulator for Linux, look at
-http://www.freiburg.linux.de/~uae/
+http://web.archive.org/web/*/http://www.freiburg.linux.de/~uae/
diff --git a/Documentation/filesystems/befs.txt b/Documentation/filesystems/befs.txt
index 67391a15949..6e49c363938 100644
--- a/Documentation/filesystems/befs.txt
+++ b/Documentation/filesystems/befs.txt
@@ -31,7 +31,7 @@ Current maintainer: Sergey S. Kostyliov <rathamahata@php4.ru>
WHAT IS THIS DRIVER?
==================
-This module implements the native filesystem of BeOS <http://www.be.com/>
+This module implements the native filesystem of BeOS http://www.beincorporated.com/
for the linux 2.4.1 and later kernels. Currently it is a read-only
implementation.
@@ -61,7 +61,7 @@ step 2. Configuration & make kernel
The linux kernel has many compile-time options. Most of them are beyond the
scope of this document. I suggest the Kernel-HOWTO document as a good general
-reference on this topic. <http://www.linux.com/howto/Kernel-HOWTO.html>
+reference on this topic. http://www.linuxdocs.org/HOWTOs/Kernel-HOWTO-4.html
However, to use the BeFS module, you must enable it at configure time.
diff --git a/Documentation/filesystems/caching/fscache.txt b/Documentation/filesystems/caching/fscache.txt
index a91e2e2095b..770267af5b3 100644
--- a/Documentation/filesystems/caching/fscache.txt
+++ b/Documentation/filesystems/caching/fscache.txt
@@ -343,8 +343,8 @@ This will look something like:
[root@andromeda ~]# head /proc/fs/fscache/objects
OBJECT PARENT STAT CHLDN OPS OOP IPR EX READS EM EV F S | NETFS_COOKIE_DEF TY FL NETFS_DATA OBJECT_KEY, AUX_DATA
======== ======== ==== ===== === === === == ===== == == = = | ================ == == ================ ================
- 17e4b 2 ACTV 0 0 0 0 0 0 7b 4 0 8 | NFS.fh DT 0 ffff88001dd82820 010006017edcf8bbc93b43298fdfbe71e50b57b13a172c0117f38472, e567634700000000000000000000000063f2404a000000000000000000000000c9030000000000000000000063f2404a
- 1693a 2 ACTV 0 0 0 0 0 0 7b 4 0 8 | NFS.fh DT 0 ffff88002db23380 010006017edcf8bbc93b43298fdfbe71e50b57b1e0162c01a2df0ea6, 420ebc4a000000000000000000000000420ebc4a0000000000000000000000000e1801000000000000000000420ebc4a
+ 17e4b 2 ACTV 0 0 0 0 0 0 7b 4 0 0 | NFS.fh DT 0 ffff88001dd82820 010006017edcf8bbc93b43298fdfbe71e50b57b13a172c0117f38472, e567634700000000000000000000000063f2404a000000000000000000000000c9030000000000000000000063f2404a
+ 1693a 2 ACTV 0 0 0 0 0 0 7b 4 0 0 | NFS.fh DT 0 ffff88002db23380 010006017edcf8bbc93b43298fdfbe71e50b57b1e0162c01a2df0ea6, 420ebc4a000000000000000000000000420ebc4a0000000000000000000000000e1801000000000000000000420ebc4a
where the first set of columns before the '|' describe the object:
@@ -362,7 +362,7 @@ where the first set of columns before the '|' describe the object:
EM Object's event mask
EV Events raised on this object
F Object flags
- S Object slow-work work item flags
+ S Object work item busy state mask (1:pending 2:running)
and the second set of columns describe the object's cookie, if present:
@@ -395,8 +395,8 @@ and the following paired letters:
w Show objects that don't have pending writes
R Show objects that have outstanding reads
r Show objects that don't have outstanding reads
- S Show objects that have slow work queued
- s Show objects that don't have slow work queued
+ S Show objects that have work queued
+ s Show objects that don't have work queued
If neither side of a letter pair is given, then both are implied. For example:
diff --git a/Documentation/filesystems/isofs.txt b/Documentation/filesystems/isofs.txt
index 3c367c3b360..ba0a93384de 100644
--- a/Documentation/filesystems/isofs.txt
+++ b/Documentation/filesystems/isofs.txt
@@ -41,7 +41,7 @@ Mount options unique to the isofs filesystem.
sbsector=xxx Session begins from sector xxx
Recommended documents about ISO 9660 standard are located at:
-http://www.y-adagio.com/public/standards/iso_cdromr/tocont.htm
+http://www.y-adagio.com/
ftp://ftp.ecma.ch/ecma-st/Ecma-119.pdf
Quoting from the PDF "This 2nd Edition of Standard ECMA-119 is technically
identical with ISO 9660.", so it is a valid and gratis substitute of the
diff --git a/Documentation/filesystems/nfs/nfsroot.txt b/Documentation/filesystems/nfs/nfsroot.txt
index 3ba0b945aaf..f2430a7974e 100644
--- a/Documentation/filesystems/nfs/nfsroot.txt
+++ b/Documentation/filesystems/nfs/nfsroot.txt
@@ -124,6 +124,8 @@ ip=<client-ip>:<server-ip>:<gw-ip>:<netmask>:<hostname>:<device>:<autoconf>
<hostname> Name of the client. May be supplied by autoconfiguration,
but its absence will not trigger autoconfiguration.
+ If specified and DHCP is used, the user provided hostname will
+ be carried in the DHCP request to hopefully update DNS record.
Default: Client IP address is used in ASCII notation.
diff --git a/Documentation/filesystems/nilfs2.txt b/Documentation/filesystems/nilfs2.txt
index d3e7673995e..d5c0cef38a7 100644
--- a/Documentation/filesystems/nilfs2.txt
+++ b/Documentation/filesystems/nilfs2.txt
@@ -49,7 +49,10 @@ Mount options
NILFS2 supports the following mount options:
(*) == default
-nobarrier Disables barriers.
+barrier(*) This enables/disables the use of write barriers. This
+nobarrier requires an IO stack which can support barriers, and
+ if nilfs gets an error on a barrier write, it will
+ disable again with a warning.
errors=continue Keep going on a filesystem error.
errors=remount-ro(*) Remount the filesystem read-only on an error.
errors=panic Panic and halt the machine if an error occurs.
@@ -74,9 +77,10 @@ norecovery Disable recovery of the filesystem on mount.
This disables every write access on the device for
read-only mounts or snapshots. This option will fail
for r/w mounts on an unclean volume.
-discard Issue discard/TRIM commands to the underlying block
- device when blocks are freed. This is useful for SSD
- devices and sparse/thinly-provisioned LUNs.
+discard This enables/disables the use of discard/TRIM commands.
+nodiscard(*) The discard/TRIM commands are sent to the underlying
+ block device when blocks are freed. This is useful
+ for SSD devices and sparse/thinly-provisioned LUNs.
NILFS2 usage
============
diff --git a/Documentation/filesystems/proc.txt b/Documentation/filesystems/proc.txt
index 9fb6cbe70bd..8fe8895894d 100644
--- a/Documentation/filesystems/proc.txt
+++ b/Documentation/filesystems/proc.txt
@@ -73,9 +73,9 @@ contact Bodo Bauer at bb@ricochet.net. We'll be happy to add them to this
document.
The latest version of this document is available online at
-http://skaro.nightcrawler.com/~bb/Docs/Proc as HTML version.
+http://tldp.org/LDP/Linux-Filesystem-Hierarchy/html/proc.html
-If the above direction does not works for you, ypu could try the kernel
+If the above direction does not works for you, you could try the kernel
mailing list at linux-kernel@vger.kernel.org and/or try to reach me at
comandante@zaralinux.com.
diff --git a/Documentation/filesystems/sysfs-pci.txt b/Documentation/filesystems/sysfs-pci.txt
index 85354b32d73..74eaac26f8b 100644
--- a/Documentation/filesystems/sysfs-pci.txt
+++ b/Documentation/filesystems/sysfs-pci.txt
@@ -39,7 +39,7 @@ files, each with their own function.
local_cpus nearby CPU mask (cpumask, ro)
remove remove device from kernel's list (ascii, wo)
resource PCI resource host addresses (ascii, ro)
- resource0..N PCI resource N, if present (binary, mmap)
+ resource0..N PCI resource N, if present (binary, mmap, rw[1])
resource0_wc..N_wc PCI WC map resource N, if prefetchable (binary, mmap)
rom PCI ROM resource, if present (binary, ro)
subsystem_device PCI subsystem device (ascii, ro)
@@ -54,13 +54,16 @@ files, each with their own function.
binary - file contains binary data
cpumask - file contains a cpumask type
+[1] rw for RESOURCE_IO (I/O port) regions only
+
The read only files are informational, writes to them will be ignored, with
the exception of the 'rom' file. Writable files can be used to perform
actions on the device (e.g. changing config space, detaching a device).
mmapable files are available via an mmap of the file at offset 0 and can be
used to do actual device programming from userspace. Note that some platforms
don't support mmapping of certain resources, so be sure to check the return
-value from any attempted mmap.
+value from any attempted mmap. The most notable of these are I/O port
+resources, which also provide read/write access.
The 'enable' file provides a counter that indicates how many times the device
has been enabled. If the 'enable' file currently returns '4', and a '1' is
diff --git a/Documentation/filesystems/sysfs.txt b/Documentation/filesystems/sysfs.txt
index 931c806642c..5d1335faec2 100644
--- a/Documentation/filesystems/sysfs.txt
+++ b/Documentation/filesystems/sysfs.txt
@@ -4,7 +4,7 @@ sysfs - _The_ filesystem for exporting kernel objects.
Patrick Mochel <mochel@osdl.org>
Mike Murphy <mamurph@cs.clemson.edu>
-Revised: 22 February 2009
+Revised: 15 July 2010
Original: 10 January 2003
@@ -124,7 +124,7 @@ show and store methods of the attribute owners.
struct sysfs_ops {
ssize_t (*show)(struct kobject *, struct attribute *, char *);
- ssize_t (*store)(struct kobject *, struct attribute *, const char *);
+ ssize_t (*store)(struct kobject *, struct attribute *, const char *, size_t);
};
[ Subsystems should have already defined a struct kobj_type as a
@@ -139,18 +139,22 @@ calls the associated methods.
To illustrate:
+#define to_dev(obj) container_of(obj, struct device, kobj)
#define to_dev_attr(_attr) container_of(_attr, struct device_attribute, attr)
-#define to_dev(d) container_of(d, struct device, kobj)
-static ssize_t
-dev_attr_show(struct kobject * kobj, struct attribute * attr, char * buf)
+static ssize_t dev_attr_show(struct kobject *kobj, struct attribute *attr,
+ char *buf)
{
- struct device_attribute * dev_attr = to_dev_attr(attr);
- struct device * dev = to_dev(kobj);
- ssize_t ret = 0;
+ struct device_attribute *dev_attr = to_dev_attr(attr);
+ struct device *dev = to_dev(kobj);
+ ssize_t ret = -EIO;
if (dev_attr->show)
- ret = dev_attr->show(dev, buf);
+ ret = dev_attr->show(dev, dev_attr, buf);
+ if (ret >= (ssize_t)PAGE_SIZE) {
+ print_symbol("dev_attr_show: %s returned bad count\n",
+ (unsigned long)dev_attr->show);
+ }
return ret;
}
@@ -163,10 +167,9 @@ To read or write attributes, show() or store() methods must be
specified when declaring the attribute. The method types should be as
simple as those defined for device attributes:
-ssize_t (*show)(struct device * dev, struct device_attribute * attr,
- char * buf);
-ssize_t (*store)(struct device * dev, struct device_attribute * attr,
- const char * buf);
+ssize_t (*show)(struct device *dev, struct device_attribute *attr, char *buf);
+ssize_t (*store)(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count);
IOW, they should take only an object, an attribute, and a buffer as parameters.
@@ -209,8 +212,8 @@ Other notes:
- show() should always use snprintf().
-- store() should return the number of bytes used from the buffer. This
- can be done using strlen().
+- store() should return the number of bytes used from the buffer. If the
+ entire buffer has been used, just return the count argument.
- show() or store() can always return errors. If a bad value comes
through, be sure to return an error.
@@ -223,15 +226,18 @@ Other notes:
A very simple (and naive) implementation of a device attribute is:
-static ssize_t show_name(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t show_name(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
return snprintf(buf, PAGE_SIZE, "%s\n", dev->name);
}
-static ssize_t store_name(struct device * dev, const char * buf)
+static ssize_t store_name(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
{
- sscanf(buf, "%20s", dev->name);
- return strnlen(buf, PAGE_SIZE);
+ snprintf(dev->name, sizeof(dev->name), "%.*s",
+ (int)min(count, sizeof(dev->name) - 1), buf);
+ return count;
}
static DEVICE_ATTR(name, S_IRUGO, show_name, store_name);
@@ -327,7 +333,7 @@ Structure:
struct bus_attribute {
struct attribute attr;
ssize_t (*show)(struct bus_type *, char * buf);
- ssize_t (*store)(struct bus_type *, const char * buf);
+ ssize_t (*store)(struct bus_type *, const char * buf, size_t count);
};
Declaring:
diff --git a/Documentation/filesystems/vfat.txt b/Documentation/filesystems/vfat.txt
index eed520fd0c8..ead764b2728 100644
--- a/Documentation/filesystems/vfat.txt
+++ b/Documentation/filesystems/vfat.txt
@@ -165,7 +165,8 @@ TEST SUITE
If you plan to make any modifications to the vfat filesystem, please
get the test suite that comes with the vfat distribution at
- http://bmrc.berkeley.edu/people/chaffee/vfat.html
+ http://web.archive.org/web/*/http://bmrc.berkeley.edu/
+ people/chaffee/vfat.html
This tests quite a few parts of the vfat filesystem and additional
tests for new features or untested features would be appreciated.
diff --git a/Documentation/filesystems/xfs.txt b/Documentation/filesystems/xfs.txt
index 9878f50d6ed..7bff3e4f35d 100644
--- a/Documentation/filesystems/xfs.txt
+++ b/Documentation/filesystems/xfs.txt
@@ -131,17 +131,6 @@ When mounting an XFS filesystem, the following options are accepted.
Don't check for double mounted file systems using the file system uuid.
This is useful to mount LVM snapshot volumes.
- osyncisosync
- Make O_SYNC writes implement true O_SYNC. WITHOUT this option,
- Linux XFS behaves as if an "osyncisdsync" option is used,
- which will make writes to files opened with the O_SYNC flag set
- behave as if the O_DSYNC flag had been used instead.
- This can result in better performance without compromising
- data safety.
- However if this option is not in effect, timestamp updates from
- O_SYNC writes can be lost if the system crashes.
- If timestamp updates are critical, use the osyncisosync option.
-
uquota/usrquota/uqnoenforce/quota
User disk quota accounting enabled, and limits (optionally)
enforced. Refer to xfs_quota(8) for further details.
diff --git a/Documentation/firmware_class/hotplug-script b/Documentation/firmware_class/hotplug-script
index 1990130f2ab..8143a950b60 100644
--- a/Documentation/firmware_class/hotplug-script
+++ b/Documentation/firmware_class/hotplug-script
@@ -6,11 +6,12 @@
HOTPLUG_FW_DIR=/usr/lib/hotplug/firmware/
-echo 1 > /sys/$DEVPATH/loading
-cat $HOTPLUG_FW_DIR/$FIRMWARE > /sys/$DEVPATH/data
-echo 0 > /sys/$DEVPATH/loading
-
-# To cancel the load in case of error:
-#
-# echo -1 > /sys/$DEVPATH/loading
-#
+if [ "$SUBSYSTEM" == "firmware" -a "$ACTION" == "add" ]; then
+ if [ -f $HOTPLUG_FW_DIR/$FIRMWARE ]; then
+ echo 1 > /sys/$DEVPATH/loading
+ cat $HOTPLUG_FW_DIR/$FIRMWARE > /sys/$DEVPATH/data
+ echo 0 > /sys/$DEVPATH/loading
+ else
+ echo -1 > /sys/$DEVPATH/loading
+ fi
+fi
diff --git a/Documentation/hwmon/adm1026 b/Documentation/hwmon/adm1026
index f4327db2307..d8fabe0c23a 100644
--- a/Documentation/hwmon/adm1026
+++ b/Documentation/hwmon/adm1026
@@ -6,7 +6,7 @@ Supported chips:
Prefix: 'adm1026'
Addresses scanned: I2C 0x2c, 0x2d, 0x2e
Datasheet: Publicly available at the Analog Devices website
- http://www.analog.com/en/prod/0,,766_825_ADM1026,00.html
+ http://www.onsemi.com/PowerSolutions/product.do?id=ADM1026
Authors:
Philip Pokorny <ppokorny@penguincomputing.com> for Penguin Computing
diff --git a/Documentation/hwmon/g760a b/Documentation/hwmon/g760a
index e032eeb7562..cfc89453706 100644
--- a/Documentation/hwmon/g760a
+++ b/Documentation/hwmon/g760a
@@ -5,7 +5,7 @@ Supported chips:
* Global Mixed-mode Technology Inc. G760A
Prefix: 'g760a'
Datasheet: Publicly available at the GMT website
- http://www.gmt.com.tw/datasheet/g760a.pdf
+ http://www.gmt.com.tw/product/datasheet/EDS-760A.pdf
Author: Herbert Valerio Riedel <hvr@gnu.org>
diff --git a/Documentation/hwmon/gl518sm b/Documentation/hwmon/gl518sm
index 229f8b78918..26f9f3c02dc 100644
--- a/Documentation/hwmon/gl518sm
+++ b/Documentation/hwmon/gl518sm
@@ -5,11 +5,10 @@ Supported chips:
* Genesys Logic GL518SM release 0x00
Prefix: 'gl518sm'
Addresses scanned: I2C 0x2c and 0x2d
- Datasheet: http://www.genesyslogic.com/pdf
* Genesys Logic GL518SM release 0x80
Prefix: 'gl518sm'
Addresses scanned: I2C 0x2c and 0x2d
- Datasheet: http://www.genesyslogic.com/pdf
+ Datasheet: http://www.genesyslogic.com/
Authors:
Frodo Looijaard <frodol@dds.nl>,
diff --git a/Documentation/hwmon/hpfall.c b/Documentation/hwmon/hpfall.c
index 681ec22b9d0..a4a8fc5d05d 100644
--- a/Documentation/hwmon/hpfall.c
+++ b/Documentation/hwmon/hpfall.c
@@ -1,7 +1,7 @@
/* Disk protection for HP machines.
*
* Copyright 2008 Eric Piel
- * Copyright 2009 Pavel Machek <pavel@suse.cz>
+ * Copyright 2009 Pavel Machek <pavel@ucw.cz>
*
* GPLv2.
*/
diff --git a/Documentation/hwmon/k8temp b/Documentation/hwmon/k8temp
index 0005c716614..716dc24c723 100644
--- a/Documentation/hwmon/k8temp
+++ b/Documentation/hwmon/k8temp
@@ -5,7 +5,7 @@ Supported chips:
* AMD Athlon64/FX or Opteron CPUs
Prefix: 'k8temp'
Addresses scanned: PCI space
- Datasheet: http://www.amd.com/us-en/assets/content_type/white_papers_and_tech_docs/32559.pdf
+ Datasheet: http://support.amd.com/us/Processor_TechDocs/32559.pdf
Author: Rudolf Marek
Contact: Rudolf Marek <r.marek@assembler.cz>
diff --git a/Documentation/hwmon/lm85 b/Documentation/hwmon/lm85
index a76aefeeb68..b98e0e0d191 100644
--- a/Documentation/hwmon/lm85
+++ b/Documentation/hwmon/lm85
@@ -9,15 +9,15 @@ Supported chips:
* Analog Devices ADM1027
Prefix: 'adm1027'
Addresses scanned: I2C 0x2c, 0x2d, 0x2e
- Datasheet: http://www.analog.com/en/prod/0,,766_825_ADM1027,00.html
+ Datasheet: http://www.onsemi.com/PowerSolutions/product.do?id=ADM1027
* Analog Devices ADT7463
Prefix: 'adt7463'
Addresses scanned: I2C 0x2c, 0x2d, 0x2e
- Datasheet: http://www.analog.com/en/prod/0,,766_825_ADT7463,00.html
+ Datasheet: http://www.onsemi.com/PowerSolutions/product.do?id=ADT7463
* SMSC EMC6D100, SMSC EMC6D101
Prefix: 'emc6d100'
Addresses scanned: I2C 0x2c, 0x2d, 0x2e
- Datasheet: http://www.smsc.com/main/tools/discontinued/6d100.pdf
+ Datasheet: http://www.smsc.com/media/Downloads_Public/discontinued/6d100.pdf
* SMSC EMC6D102
Prefix: 'emc6d102'
Addresses scanned: I2C 0x2c, 0x2d, 0x2e
diff --git a/Documentation/hwmon/pkgtemp b/Documentation/hwmon/pkgtemp
new file mode 100644
index 00000000000..c8e1fb0fadd
--- /dev/null
+++ b/Documentation/hwmon/pkgtemp
@@ -0,0 +1,36 @@
+Kernel driver pkgtemp
+======================
+
+Supported chips:
+ * Intel family
+ Prefix: 'pkgtemp'
+ CPUID:
+ Datasheet: Intel 64 and IA-32 Architectures Software Developer's Manual
+ Volume 3A: System Programming Guide
+
+Author: Fenghua Yu
+
+Description
+-----------
+
+This driver permits reading package level temperature sensor embedded inside
+Intel CPU package. The sensors can be in core, uncore, memory controller, or
+other components in a package. The feature is first implemented in Intel Sandy
+Bridge platform.
+
+Temperature is measured in degrees Celsius and measurement resolution is
+1 degree C. Valid temperatures are from 0 to TjMax degrees C, because the actual
+value of temperature register is in fact a delta from TjMax.
+
+Temperature known as TjMax is the maximum junction temperature of package.
+We get this from MSR_IA32_TEMPERATURE_TARGET. If the MSR is not accessible,
+we define TjMax as 100 degrees Celsius. At this temperature, protection
+mechanism will perform actions to forcibly cool down the package. Alarm
+may be raised, if the temperature grows enough (more than TjMax) to trigger
+the Out-Of-Spec bit. Following table summarizes the exported sysfs files:
+
+temp1_input - Package temperature (in millidegrees Celsius).
+temp1_max - All cooling devices should be turned on.
+temp1_crit - Maximum junction temperature (in millidegrees Celsius).
+temp1_crit_alarm - Set when Out-of-spec bit is set, never clears.
+ Correct CPU operation is no longer guaranteed.
diff --git a/Documentation/hwmon/smsc47m1 b/Documentation/hwmon/smsc47m1
index 42c8431b3c9..2a13378dcf2 100644
--- a/Documentation/hwmon/smsc47m1
+++ b/Documentation/hwmon/smsc47m1
@@ -7,13 +7,10 @@ Supported chips:
Addresses scanned: none, address read from Super I/O config space
Prefix: 'smsc47m1'
Datasheets:
- http://www.smsc.com/main/datasheets/47b27x.pdf
- http://www.smsc.com/main/datasheets/47m10x.pdf
- http://www.smsc.com/main/datasheets/47m112.pdf
- http://www.smsc.com/main/tools/discontinued/47m13x.pdf
- http://www.smsc.com/main/datasheets/47m14x.pdf
- http://www.smsc.com/main/tools/discontinued/47m15x.pdf
- http://www.smsc.com/main/datasheets/47m192.pdf
+ http://www.smsc.com/media/Downloads_Public/Data_Sheets/47b272.pdf
+ http://www.smsc.com/media/Downloads_Public/Data_Sheets/47m10x.pdf
+ http://www.smsc.com/media/Downloads_Public/Data_Sheets/47m112.pdf
+ http://www.smsc.com/
* SMSC LPC47M292
Addresses scanned: none, address read from Super I/O config space
Prefix: 'smsc47m2'
diff --git a/Documentation/hwmon/thmc50 b/Documentation/hwmon/thmc50
index 9639ca93d55..8a7772ade8d 100644
--- a/Documentation/hwmon/thmc50
+++ b/Documentation/hwmon/thmc50
@@ -9,7 +9,7 @@ Supported chips:
* Texas Instruments THMC50
Prefix: 'thmc50'
Addresses scanned: I2C 0x2c - 0x2e
- Datasheet: http://focus.ti.com/docs/prod/folders/print/thmc50.html
+ Datasheet: http://www.ti.com/
Author: Krzysztof Helt <krzysztof.h1@wp.pl>
diff --git a/Documentation/hwmon/via686a b/Documentation/hwmon/via686a
index d651b25f751..e5f90ab5c48 100644
--- a/Documentation/hwmon/via686a
+++ b/Documentation/hwmon/via686a
@@ -5,7 +5,7 @@ Supported chips:
* Via VT82C686A, VT82C686B Southbridge Integrated Hardware Monitor
Prefix: 'via686a'
Addresses scanned: ISA in PCI-space encoded address
- Datasheet: On request through web form (http://www.via.com.tw/en/support/datasheets/)
+ Datasheet: On request through web form (http://www.via.com.tw/en/resources/download-center/)
Authors:
Kyösti Mälkki <kmalkki@cc.hut.fi>,
diff --git a/Documentation/hwmon/w83627hf b/Documentation/hwmon/w83627hf
index 44dd2bcc72b..fb145e5e722 100644
--- a/Documentation/hwmon/w83627hf
+++ b/Documentation/hwmon/w83627hf
@@ -5,23 +5,19 @@ Supported chips:
* Winbond W83627HF (ISA accesses ONLY)
Prefix: 'w83627hf'
Addresses scanned: ISA address retrieved from Super I/O registers
- Datasheet: http://www.winbond.com/PDF/sheet/w83627hf.pdf
* Winbond W83627THF
Prefix: 'w83627thf'
Addresses scanned: ISA address retrieved from Super I/O registers
- Datasheet: http://www.winbond.com/PDF/sheet/w83627thf.pdf
* Winbond W83697HF
Prefix: 'w83697hf'
Addresses scanned: ISA address retrieved from Super I/O registers
- Datasheet: http://www.winbond.com/PDF/sheet/697hf.pdf
* Winbond W83637HF
Prefix: 'w83637hf'
Addresses scanned: ISA address retrieved from Super I/O registers
- Datasheet: http://www.winbond.com/PDF/sheet/w83637hf.pdf
* Winbond W83687THF
Prefix: 'w83687thf'
Addresses scanned: ISA address retrieved from Super I/O registers
- Datasheet: Provided by Winbond on request
+ Datasheet: Provided by Winbond on request(http://www.winbond.com/hq/enu)
Authors:
Frodo Looijaard <frodol@dds.nl>,
diff --git a/Documentation/hwmon/w83781d b/Documentation/hwmon/w83781d
index c91e0b63ea1..ecbc1e4574b 100644
--- a/Documentation/hwmon/w83781d
+++ b/Documentation/hwmon/w83781d
@@ -9,7 +9,7 @@ Supported chips:
* Winbond W83782D
Prefix: 'w83782d'
Addresses scanned: I2C 0x28 - 0x2f, ISA 0x290 (8 I/O ports)
- Datasheet: http://www.winbond.com/PDF/sheet/w83782d.pdf
+ Datasheet: http://www.winbond.com
* Winbond W83783S
Prefix: 'w83783s'
Addresses scanned: I2C 0x2d
diff --git a/Documentation/hwmon/w83792d b/Documentation/hwmon/w83792d
index 14a668ed8aa..8a023ce0b72 100644
--- a/Documentation/hwmon/w83792d
+++ b/Documentation/hwmon/w83792d
@@ -5,7 +5,7 @@ Supported chips:
* Winbond W83792D
Prefix: 'w83792d'
Addresses scanned: I2C 0x2c - 0x2f
- Datasheet: http://www.winbond.com.tw/E-WINBONDHTM/partner/PDFresult.asp?Pname=1035
+ Datasheet: http://www.winbond.com.tw
Author: Chunhao Huang
Contact: DZShen <DZShen@Winbond.com.tw>
diff --git a/Documentation/i2c/busses/i2c-ali1535 b/Documentation/i2c/busses/i2c-ali1535
index acbc65a0809..5d46342e486 100644
--- a/Documentation/i2c/busses/i2c-ali1535
+++ b/Documentation/i2c/busses/i2c-ali1535
@@ -3,7 +3,7 @@ Kernel driver i2c-ali1535
Supported adapters:
* Acer Labs, Inc. ALI 1535 (south bridge)
Datasheet: Now under NDA
- http://www.ali.com.tw/eng/support/datasheet_request.php
+ http://www.ali.com.tw/
Authors:
Frodo Looijaard <frodol@dds.nl>,
diff --git a/Documentation/i2c/busses/i2c-ali1563 b/Documentation/i2c/busses/i2c-ali1563
index 54691698d2d..41b1a077e4c 100644
--- a/Documentation/i2c/busses/i2c-ali1563
+++ b/Documentation/i2c/busses/i2c-ali1563
@@ -3,7 +3,7 @@ Kernel driver i2c-ali1563
Supported adapters:
* Acer Labs, Inc. ALI 1563 (south bridge)
Datasheet: Now under NDA
- http://www.ali.com.tw/eng/support/datasheet_request.php
+ http://www.ali.com.tw/
Author: Patrick Mochel <mochel@digitalimplant.org>
diff --git a/Documentation/i2c/busses/i2c-ali15x3 b/Documentation/i2c/busses/i2c-ali15x3
index 600da90b8f1..42888d8ac12 100644
--- a/Documentation/i2c/busses/i2c-ali15x3
+++ b/Documentation/i2c/busses/i2c-ali15x3
@@ -3,7 +3,7 @@ Kernel driver i2c-ali15x3
Supported adapters:
* Acer Labs, Inc. ALI 1533 and 1543C (south bridge)
Datasheet: Now under NDA
- http://www.ali.com.tw/eng/support/datasheet_request.php
+ http://www.ali.com.tw/
Authors:
Frodo Looijaard <frodol@dds.nl>,
diff --git a/Documentation/i2c/busses/i2c-piix4 b/Documentation/i2c/busses/i2c-piix4
index ac540c71c7e..475bb4ae072 100644
--- a/Documentation/i2c/busses/i2c-piix4
+++ b/Documentation/i2c/busses/i2c-piix4
@@ -97,4 +97,4 @@ of all affected systems, so the only safe solution was to prevent access to
the SMBus on all IBM systems (detected using DMI data.)
For additional information, read:
-http://www.lm-sensors.org/browser/lm-sensors/trunk/README.thinkpad
+http://www.lm-sensors.org/browser/lm-sensors/trunk/README
diff --git a/Documentation/i2c/busses/i2c-sis630 b/Documentation/i2c/busses/i2c-sis630
index 629ea2c356f..0b969736693 100644
--- a/Documentation/i2c/busses/i2c-sis630
+++ b/Documentation/i2c/busses/i2c-sis630
@@ -2,7 +2,7 @@ Kernel driver i2c-sis630
Supported adapters:
* Silicon Integrated Systems Corp (SiS)
- 630 chipset (Datasheet: available at http://amalysh.bei.t-online.de/docs/SIS/)
+ 630 chipset (Datasheet: available at http://www.sfr-fresh.com/linux)
730 chipset
* Possible other SiS chipsets ?
diff --git a/Documentation/ia64/aliasing.txt b/Documentation/ia64/aliasing.txt
index aa3e953f0f7..5a4dea6abeb 100644
--- a/Documentation/ia64/aliasing.txt
+++ b/Documentation/ia64/aliasing.txt
@@ -168,8 +168,6 @@ PAST PROBLEM CASES
mmap of 0x0-0x9FFFF /dev/mem by "hwinfo" on HP sx1000 with VGA enabled
- See https://bugzilla.novell.com/show_bug.cgi?id=140858.
-
The EFI memory map reports the following attributes:
0x00000-0x9FFFF WB only
0xA0000-0xBFFFF UC only (VGA frame buffer)
diff --git a/Documentation/ia64/serial.txt b/Documentation/ia64/serial.txt
index 040b9773209..6869c73de4e 100644
--- a/Documentation/ia64/serial.txt
+++ b/Documentation/ia64/serial.txt
@@ -133,7 +133,7 @@ TROUBLESHOOTING SERIAL CONSOLE PROBLEMS
-[1] http://www.dig64.org/specifications/DIG64_PCDPv20.pdf
+[1] http://www.dig64.org/specifications/agreement
The table was originally defined as the "HCDP" for "Headless
Console/Debug Port." The current version is the "PCDP" for
"Primary Console and Debug Port Devices."
diff --git a/Documentation/infiniband/user_verbs.txt b/Documentation/infiniband/user_verbs.txt
index afe3f8da901..e5092d696da 100644
--- a/Documentation/infiniband/user_verbs.txt
+++ b/Documentation/infiniband/user_verbs.txt
@@ -5,7 +5,7 @@ USERSPACE VERBS ACCESS
described in chapter 11 of the InfiniBand Architecture Specification.
To use the verbs, the libibverbs library, available from
- <http://openib.org/>, is required. libibverbs contains a
+ http://www.openfabrics.org/, is required. libibverbs contains a
device-independent API for using the ib_uverbs interface.
libibverbs also requires appropriate device-dependent kernel and
userspace driver for your InfiniBand hardware. For example, to use
diff --git a/Documentation/input/appletouch.txt b/Documentation/input/appletouch.txt
index 4f7c633a76d..b13de3f8910 100644
--- a/Documentation/input/appletouch.txt
+++ b/Documentation/input/appletouch.txt
@@ -82,4 +82,4 @@ Links:
------
[1]: http://johannes.sipsolutions.net/PowerBook/touchpad/
-[2]: http://web.telia.com/~u89404340/touchpad/index.html
+[2]: http://web.archive.org/web/*/http://web.telia.com/~u89404340/touchpad/index.html
diff --git a/Documentation/input/bcm5974.txt b/Documentation/input/bcm5974.txt
index 5e22dcf6d48..74d3876d6f3 100644
--- a/Documentation/input/bcm5974.txt
+++ b/Documentation/input/bcm5974.txt
@@ -62,4 +62,4 @@ Links
-----
[1] http://ubuntuforums.org/showthread.php?t=840040
-[2] http://http://bitmath.org/code/
+[2] http://bitmath.org/code/
diff --git a/Documentation/input/iforce-protocol.txt b/Documentation/input/iforce-protocol.txt
index 3ac92413c87..2d5fbfd6023 100644
--- a/Documentation/input/iforce-protocol.txt
+++ b/Documentation/input/iforce-protocol.txt
@@ -251,7 +251,7 @@ Check www.immerse.com for Immersion Studio, and www.fcoder.com for ComPortSpy.
** Author of this document **
Johann Deneux <johann.deneux@gmail.com>
-Home page at http://www.esil.univ-mrs.fr/~jdeneux/projects/ff/
+Home page at http://web.archive.org/web/*/http://www.esil.univ-mrs.fr
Additions by Vojtech Pavlik.
diff --git a/Documentation/input/multi-touch-protocol.txt b/Documentation/input/multi-touch-protocol.txt
index c0fc1c75fd8..bdcba154b83 100644
--- a/Documentation/input/multi-touch-protocol.txt
+++ b/Documentation/input/multi-touch-protocol.txt
@@ -6,31 +6,149 @@ Multi-touch (MT) Protocol
Introduction
------------
-In order to utilize the full power of the new multi-touch devices, a way to
-report detailed finger data to user space is needed. This document
-describes the multi-touch (MT) protocol which allows kernel drivers to
-report details for an arbitrary number of fingers.
+In order to utilize the full power of the new multi-touch and multi-user
+devices, a way to report detailed data from multiple contacts, i.e.,
+objects in direct contact with the device surface, is needed. This
+document describes the multi-touch (MT) protocol which allows kernel
+drivers to report details for an arbitrary number of contacts.
+
+The protocol is divided into two types, depending on the capabilities of the
+hardware. For devices handling anonymous contacts (type A), the protocol
+describes how to send the raw data for all contacts to the receiver. For
+devices capable of tracking identifiable contacts (type B), the protocol
+describes how to send updates for individual contacts via event slots.
+
+
+Protocol Usage
+--------------
+
+Contact details are sent sequentially as separate packets of ABS_MT
+events. Only the ABS_MT events are recognized as part of a contact
+packet. Since these events are ignored by current single-touch (ST)
+applications, the MT protocol can be implemented on top of the ST protocol
+in an existing driver.
+
+Drivers for type A devices separate contact packets by calling
+input_mt_sync() at the end of each packet. This generates a SYN_MT_REPORT
+event, which instructs the receiver to accept the data for the current
+contact and prepare to receive another.
+
+Drivers for type B devices separate contact packets by calling
+input_mt_slot(), with a slot as argument, at the beginning of each packet.
+This generates an ABS_MT_SLOT event, which instructs the receiver to
+prepare for updates of the given slot.
+
+All drivers mark the end of a multi-touch transfer by calling the usual
+input_sync() function. This instructs the receiver to act upon events
+accumulated since last EV_SYN/SYN_REPORT and prepare to receive a new set
+of events/packets.
+
+The main difference between the stateless type A protocol and the stateful
+type B slot protocol lies in the usage of identifiable contacts to reduce
+the amount of data sent to userspace. The slot protocol requires the use of
+the ABS_MT_TRACKING_ID, either provided by the hardware or computed from
+the raw data [5].
+
+For type A devices, the kernel driver should generate an arbitrary
+enumeration of the full set of anonymous contacts currently on the
+surface. The order in which the packets appear in the event stream is not
+important. Event filtering and finger tracking is left to user space [3].
+
+For type B devices, the kernel driver should associate a slot with each
+identified contact, and use that slot to propagate changes for the contact.
+Creation, replacement and destruction of contacts is achieved by modifying
+the ABS_MT_TRACKING_ID of the associated slot. A non-negative tracking id
+is interpreted as a contact, and the value -1 denotes an unused slot. A
+tracking id not previously present is considered new, and a tracking id no
+longer present is considered removed. Since only changes are propagated,
+the full state of each initiated contact has to reside in the receiving
+end. Upon receiving an MT event, one simply updates the appropriate
+attribute of the current slot.
+
+
+Protocol Example A
+------------------
+
+Here is what a minimal event sequence for a two-contact touch would look
+like for a type A device:
+
+ ABS_MT_POSITION_X x[0]
+ ABS_MT_POSITION_Y y[0]
+ SYN_MT_REPORT
+ ABS_MT_POSITION_X x[1]
+ ABS_MT_POSITION_Y y[1]
+ SYN_MT_REPORT
+ SYN_REPORT
+The sequence after moving one of the contacts looks exactly the same; the
+raw data for all present contacts are sent between every synchronization
+with SYN_REPORT.
-Usage
------
+Here is the sequence after lifting the first contact:
+
+ ABS_MT_POSITION_X x[1]
+ ABS_MT_POSITION_Y y[1]
+ SYN_MT_REPORT
+ SYN_REPORT
+
+And here is the sequence after lifting the second contact:
+
+ SYN_MT_REPORT
+ SYN_REPORT
+
+If the driver reports one of BTN_TOUCH or ABS_PRESSURE in addition to the
+ABS_MT events, the last SYN_MT_REPORT event may be omitted. Otherwise, the
+last SYN_REPORT will be dropped by the input core, resulting in no
+zero-contact event reaching userland.
-Anonymous finger details are sent sequentially as separate packets of ABS
-events. Only the ABS_MT events are recognized as part of a finger
-packet. The end of a packet is marked by calling the input_mt_sync()
-function, which generates a SYN_MT_REPORT event. This instructs the
-receiver to accept the data for the current finger and prepare to receive
-another. The end of a multi-touch transfer is marked by calling the usual
-input_sync() function. This instructs the receiver to act upon events
-accumulated since last EV_SYN/SYN_REPORT and prepare to receive a new
-set of events/packets.
+
+Protocol Example B
+------------------
+
+Here is what a minimal event sequence for a two-contact touch would look
+like for a type B device:
+
+ ABS_MT_SLOT 0
+ ABS_MT_TRACKING_ID 45
+ ABS_MT_POSITION_X x[0]
+ ABS_MT_POSITION_Y y[0]
+ ABS_MT_SLOT 1
+ ABS_MT_TRACKING_ID 46
+ ABS_MT_POSITION_X x[1]
+ ABS_MT_POSITION_Y y[1]
+ SYN_REPORT
+
+Here is the sequence after moving contact 45 in the x direction:
+
+ ABS_MT_SLOT 0
+ ABS_MT_POSITION_X x[0]
+ SYN_REPORT
+
+Here is the sequence after lifting the contact in slot 0:
+
+ ABS_MT_TRACKING_ID -1
+ SYN_REPORT
+
+The slot being modified is already 0, so the ABS_MT_SLOT is omitted. The
+message removes the association of slot 0 with contact 45, thereby
+destroying contact 45 and freeing slot 0 to be reused for another contact.
+
+Finally, here is the sequence after lifting the second contact:
+
+ ABS_MT_SLOT 1
+ ABS_MT_TRACKING_ID -1
+ SYN_REPORT
+
+
+Event Usage
+-----------
A set of ABS_MT events with the desired properties is defined. The events
are divided into categories, to allow for partial implementation. The
minimum set consists of ABS_MT_POSITION_X and ABS_MT_POSITION_Y, which
-allows for multiple fingers to be tracked. If the device supports it, the
+allows for multiple contacts to be tracked. If the device supports it, the
ABS_MT_TOUCH_MAJOR and ABS_MT_WIDTH_MAJOR may be used to provide the size
-of the contact area and approaching finger, respectively.
+of the contact area and approaching contact, respectively.
The TOUCH and WIDTH parameters have a geometrical interpretation; imagine
looking through a window at someone gently holding a finger against the
@@ -41,56 +159,26 @@ ABS_MT_TOUCH_MAJOR, the diameter of the outer region is
ABS_MT_WIDTH_MAJOR. Now imagine the person pressing the finger harder
against the glass. The inner region will increase, and in general, the
ratio ABS_MT_TOUCH_MAJOR / ABS_MT_WIDTH_MAJOR, which is always smaller than
-unity, is related to the finger pressure. For pressure-based devices,
+unity, is related to the contact pressure. For pressure-based devices,
ABS_MT_PRESSURE may be used to provide the pressure on the contact area
instead.
-In addition to the MAJOR parameters, the oval shape of the finger can be
+In addition to the MAJOR parameters, the oval shape of the contact can be
described by adding the MINOR parameters, such that MAJOR and MINOR are the
major and minor axis of an ellipse. Finally, the orientation of the oval
shape can be describe with the ORIENTATION parameter.
The ABS_MT_TOOL_TYPE may be used to specify whether the touching tool is a
-finger or a pen or something else. Devices with more granular information
+contact or a pen or something else. Devices with more granular information
may specify general shapes as blobs, i.e., as a sequence of rectangular
shapes grouped together by an ABS_MT_BLOB_ID. Finally, for the few devices
that currently support it, the ABS_MT_TRACKING_ID event may be used to
-report finger tracking from hardware [5].
+report contact tracking from hardware [5].
-Here is what a minimal event sequence for a two-finger touch would look
-like:
-
- ABS_MT_POSITION_X
- ABS_MT_POSITION_Y
- SYN_MT_REPORT
- ABS_MT_POSITION_X
- ABS_MT_POSITION_Y
- SYN_MT_REPORT
- SYN_REPORT
-
-Here is the sequence after lifting one of the fingers:
-
- ABS_MT_POSITION_X
- ABS_MT_POSITION_Y
- SYN_MT_REPORT
- SYN_REPORT
-
-And here is the sequence after lifting the remaining finger:
-
- SYN_MT_REPORT
- SYN_REPORT
-
-If the driver reports one of BTN_TOUCH or ABS_PRESSURE in addition to the
-ABS_MT events, the last SYN_MT_REPORT event may be omitted. Otherwise, the
-last SYN_REPORT will be dropped by the input core, resulting in no
-zero-finger event reaching userland.
Event Semantics
---------------
-The word "contact" is used to describe a tool which is in direct contact
-with the surface. A finger, a pen or a rubber all classify as contacts.
-
ABS_MT_TOUCH_MAJOR
The length of the major axis of the contact. The length should be given in
@@ -157,15 +245,16 @@ MT_TOOL_PEN [2].
ABS_MT_BLOB_ID
The BLOB_ID groups several packets together into one arbitrarily shaped
-contact. This is a low-level anonymous grouping, and should not be confused
-with the high-level trackingID [5]. Most kernel drivers will not have blob
-capability, and can safely omit the event.
+contact. This is a low-level anonymous grouping for type A devices, and
+should not be confused with the high-level trackingID [5]. Most type A
+devices do not have blob capability, so drivers can safely omit this event.
ABS_MT_TRACKING_ID
The TRACKING_ID identifies an initiated contact throughout its life cycle
-[5]. There are currently only a few devices that support it, so this event
-should normally be omitted.
+[5]. This event is mandatory for type B devices. The value range of the
+TRACKING_ID should be large enough to ensure unique identification of a
+contact maintained over an extended period of time.
Event Computation
@@ -192,20 +281,11 @@ finger along the X axis (1).
Finger Tracking
---------------
-The kernel driver should generate an arbitrary enumeration of the set of
-anonymous contacts currently on the surface. The order in which the packets
-appear in the event stream is not important.
-
The process of finger tracking, i.e., to assign a unique trackingID to each
-initiated contact on the surface, is left to user space; preferably the
-multi-touch X driver [3]. In that driver, the trackingID stays the same and
-unique until the contact vanishes (when the finger leaves the surface). The
-problem of assigning a set of anonymous fingers to a set of identified
-fingers is a euclidian bipartite matching problem at each event update, and
-relies on a sufficiently rapid update rate.
-
-There are a few devices that support trackingID in hardware. User space can
-make use of these native identifiers to reduce bandwidth and cpu usage.
+initiated contact on the surface, is a Euclidian Bipartite Matching
+problem. At each event synchronization, the set of actual contacts is
+matched to the set of contacts from the previous synchronization. A full
+implementation can be found in [3].
Gestures
diff --git a/Documentation/input/sentelic.txt b/Documentation/input/sentelic.txt
index b35affd5c64..b2ef125b71f 100644
--- a/Documentation/input/sentelic.txt
+++ b/Documentation/input/sentelic.txt
@@ -341,7 +341,7 @@ Byte 5~8: Don't care (Absolute packet)
FSP supports basic PS/2 commanding set and modes, refer to following URL for
details about PS/2 commands:
-http://www.computer-engineering.org/index.php?title=PS/2_Mouse_Interface
+http://www.computer-engineering.org/ps2mouse/
==============================================================================
* Programming Sequence for Determining Packet Parsing Flow
diff --git a/Documentation/input/xpad.txt b/Documentation/input/xpad.txt
index aae0d404c56..7cc9a436e6a 100644
--- a/Documentation/input/xpad.txt
+++ b/Documentation/input/xpad.txt
@@ -150,7 +150,7 @@ the basic functionality.
1. http://euc.jp/periphs/xbox-controller.ja.html (ITO Takayuki)
2. http://xpad.xbox-scene.com/
-3. http://www.xboxhackz.com/Hackz-Reference.htm
+3. http://www.markosweb.com/www/xboxhackz.com/
4. /proc/bus/usb/devices - dump from InterAct PowerPad Pro (Germany):
diff --git a/Documentation/intel_txt.txt b/Documentation/intel_txt.txt
index 5dc59b04a71..849de1a78e7 100644
--- a/Documentation/intel_txt.txt
+++ b/Documentation/intel_txt.txt
@@ -25,20 +25,18 @@ which has been updated for the new released platforms.
Intel TXT has been presented at various events over the past few
years, some of which are:
LinuxTAG 2008:
- http://www.linuxtag.org/2008/en/conf/events/vp-donnerstag/
- details.html?talkid=110
+ http://www.linuxtag.org/2008/en/conf/events/vp-donnerstag.html
TRUST2008:
- http://www.trust2008.eu/downloads/Keynote-Speakers/
+ http://www.trust-conference.eu/downloads/Keynote-Speakers/
3_David-Grawrock_The-Front-Door-of-Trusted-Computing.pdf
- IDF 2008, Shanghai:
- http://inteldeveloperforum.com.edgesuite.net/shanghai_2008/
- aep/PROS003/index.html
+ IDF, Shanghai:
+ http://www.prcidf.com.cn/index_en.html
IDFs 2006, 2007 (I'm not sure if/where they are online)
Trusted Boot Project Overview:
=============================
-Trusted Boot (tboot) is an open source, pre- kernel/VMM module that
+Trusted Boot (tboot) is an open source, pre-kernel/VMM module that
uses Intel TXT to perform a measured and verified launch of an OS
kernel/VMM.
diff --git a/Documentation/ioctl/ioctl-number.txt b/Documentation/ioctl/ioctl-number.txt
index dd5806f4fcc..33223ff121d 100644
--- a/Documentation/ioctl/ioctl-number.txt
+++ b/Documentation/ioctl/ioctl-number.txt
@@ -74,11 +74,12 @@ Code Seq#(hex) Include File Comments
0x10 00-0F drivers/char/s390/vmcp.h
0x12 all linux/fs.h
linux/blkpg.h
-0x1b all InfiniBand Subsystem <http://www.openib.org/>
+0x1b all InfiniBand Subsystem <http://infiniband.sourceforge.net/>
0x20 all drivers/cdrom/cm206.h
0x22 all scsi/sg.h
'#' 00-3F IEEE 1394 Subsystem Block for the entire subsystem
'$' 00-0F linux/perf_counter.h, linux/perf_event.h
+'&' 00-07 drivers/firewire/nosy-user.h
'1' 00-1F <linux/timepps.h> PPS kit from Ulrich Windl
<ftp://ftp.de.kernel.org/pub/linux/daemons/ntp/PPS/>
'2' 01-04 linux/i2o.h
@@ -190,7 +191,7 @@ Code Seq#(hex) Include File Comments
'[' 00-07 linux/usb/tmc.h USB Test and Measurement Devices
<mailto:gregkh@suse.de>
'a' all linux/atm*.h, linux/sonet.h ATM on linux
- <http://lrcwww.epfl.ch/linux-atm/magic.html>
+ <http://lrcwww.epfl.ch/>
'b' 00-FF conflict! bit3 vme host bridge
<mailto:natalia@nikhefk.nikhef.nl>
'b' 00-0F media/bt819.h conflict!
@@ -225,7 +226,7 @@ Code Seq#(hex) Include File Comments
'k' 00-0F linux/spi/spidev.h conflict!
'k' 00-05 video/kyro.h conflict!
'l' 00-3F linux/tcfs_fs.h transparent cryptographic file system
- <http://mikonos.dia.unisa.it/tcfs>
+ <http://web.archive.org/web/*/http://mikonos.dia.unisa.it/tcfs>
'l' 40-7F linux/udf_fs_i.h in development:
<http://sourceforge.net/projects/linux-udf/>
'm' 00-09 linux/mmtimer.h conflict!
@@ -252,7 +253,7 @@ Code Seq#(hex) Include File Comments
<mailto:giometti@linux.it>
'q' 00-1F linux/serio.h
'q' 80-FF linux/telephony.h Internet PhoneJACK, Internet LineJACK
- linux/ixjuser.h <http://www.quicknet.net>
+ linux/ixjuser.h <http://web.archive.org/web/*/http://www.quicknet.net>
'r' 00-1F linux/msdos_fs.h and fs/fat/dir.c
's' all linux/cdk.h
't' 00-7F linux/if_ppp.h
@@ -286,7 +287,7 @@ Code Seq#(hex) Include File Comments
0x89 F0-FF linux/sockios.h SIOCDEVPRIVATE range
0x8B all linux/wireless.h
0x8C 00-3F WiNRADiO driver
- <http://www.proximity.com.au/~brian/winradio/>
+ <http://www.winradio.com.au/>
0x90 00 drivers/cdrom/sbpcd.h
0x92 00-0F drivers/usb/mon/mon_bin.c
0x93 60-7F linux/auto_fs.h
diff --git a/Documentation/isdn/INTERFACE.CAPI b/Documentation/isdn/INTERFACE.CAPI
index f172091fb7c..309eb5ed942 100644
--- a/Documentation/isdn/INTERFACE.CAPI
+++ b/Documentation/isdn/INTERFACE.CAPI
@@ -113,12 +113,16 @@ char *driver_name
int (*load_firmware)(struct capi_ctr *ctrlr, capiloaddata *ldata)
(optional) pointer to a callback function for sending firmware and
configuration data to the device
+ The function may return before the operation has completed.
+ Completion must be signalled by a call to capi_ctr_ready().
Return value: 0 on success, error code on error
Called in process context.
void (*reset_ctr)(struct capi_ctr *ctrlr)
- (optional) pointer to a callback function for performing a reset on
- the device, releasing all registered applications
+ (optional) pointer to a callback function for stopping the device,
+ releasing all registered applications
+ The function may return before the operation has completed.
+ Completion must be signalled by a call to capi_ctr_down().
Called in process context.
void (*register_appl)(struct capi_ctr *ctrlr, u16 applid,
diff --git a/Documentation/isdn/README b/Documentation/isdn/README
index 6783437f21c..cfb1884342e 100644
--- a/Documentation/isdn/README
+++ b/Documentation/isdn/README
@@ -36,7 +36,7 @@ README for the ISDN-subsystem
http://www.mhessler.de/i4lfaq/
It can be viewed online, or downloaded in sgml/text/html format.
The FAQ can also be viewed online at
- http://www.isdn4inux.de/faq/
+ http://www.isdn4linux.de/faq/
or downloaded from
ftp://ftp.isdn4linux.de/pub/isdn4linux/FAQ/
diff --git a/Documentation/isdn/README.HiSax b/Documentation/isdn/README.HiSax
index 031c8d81433..99e87a61897 100644
--- a/Documentation/isdn/README.HiSax
+++ b/Documentation/isdn/README.HiSax
@@ -486,7 +486,7 @@ Appendix: Teles PCMCIA driver
-----------------------------
See
- http://www.stud.uni-wuppertal.de/~ea0141/pcmcia.html
+ http://www.linux.no/teles_cs.txt
for instructions.
Appendix: Linux and ISDN-leased lines
diff --git a/Documentation/isdn/README.gigaset b/Documentation/isdn/README.gigaset
index e472df84232..ef3343eaa00 100644
--- a/Documentation/isdn/README.gigaset
+++ b/Documentation/isdn/README.gigaset
@@ -47,9 +47,9 @@ GigaSet 307x Device Driver
1.2. Software
--------
- The driver works with ISDN4linux and so can be used with any software
- which is able to use ISDN4linux for ISDN connections (voice or data).
- Experimental Kernel CAPI support is available as a compilation option.
+ The driver works with the Kernel CAPI subsystem as well as the old
+ ISDN4Linux subsystem, so it can be used with any software which is able
+ to use CAPI 2.0 or ISDN4Linux for ISDN connections (voice or data).
There are some user space tools available at
http://sourceforge.net/projects/gigaset307x/
@@ -152,61 +152,42 @@ GigaSet 307x Device Driver
- GIGVER_FWBASE: retrieve the firmware version of the base
Upon return, version[] is filled with the requested version information.
-2.3. ISDN4linux
- ----------
- This is the "normal" mode of operation. After loading the module you can
- set up the ISDN system just as you'd do with any ISDN card supported by
- the ISDN4Linux subsystem. Most distributions provide some configuration
- utility. If not, you can use some HOWTOs like
- http://www.linuxhaven.de/dlhp/HOWTO/DE-ISDN-HOWTO-5.html
- If this doesn't work, because you have some device like SX100 where
- debug output (see section 3.2.) shows something like this when dialing
- CMD Received: ERROR
- Available Params: 0
- Connection State: 0, Response: -1
- gigaset_process_response: resp_code -1 in ConState 0 !
- Timeout occurred
- you probably need to use unimodem mode. (see section 2.5.)
-
-2.4. CAPI
+2.3. CAPI
----
If the driver is compiled with CAPI support (kernel configuration option
- GIGASET_CAPI, experimental) it can also be used with CAPI 2.0 kernel and
- user space applications. For user space access, the module capi.ko must
- be loaded. The capiinit command (included in the capi4k-utils package)
- does this for you.
-
- The CAPI variant of the driver supports legacy ISDN4Linux applications
- via the capidrv compatibility driver. The kernel module capidrv.ko must
- be loaded explicitly with the command
+ GIGASET_CAPI) the devices will show up as CAPI controllers as soon as the
+ corresponding driver module is loaded, and can then be used with CAPI 2.0
+ kernel and user space applications. For user space access, the module
+ capi.ko must be loaded.
+
+ Legacy ISDN4Linux applications are supported via the capidrv
+ compatibility driver. The kernel module capidrv.ko must be loaded
+ explicitly with the command
modprobe capidrv
if needed, and cannot be unloaded again without unloading the driver
first. (These are limitations of capidrv.)
- The note about unimodem mode in the preceding section applies here, too.
-
-2.5. Unimodem mode
- -------------
- This is needed for some devices [e.g. SX100] as they have problems with
- the "normal" commands.
+ Most distributions handle loading and unloading of the various CAPI
+ modules automatically via the command capiinit(1) from the capi4k-utils
+ package or a similar mechanism. Note that capiinit(1) cannot unload the
+ Gigaset drivers because it doesn't support more than one module per
+ driver.
- If you have installed the command line tool gigacontr, you can enter
- unimodem mode using
- gigacontr --mode unimodem
- You can switch back using
- gigacontr --mode isdn
+2.4. ISDN4Linux
+ ----------
+ If the driver is compiled without CAPI support (native ISDN4Linux
+ variant), it registers the device with the legacy ISDN4Linux subsystem
+ after loading the module. It can then be used with ISDN4Linux
+ applications only. Most distributions provide some configuration utility
+ for setting up that subsystem. Otherwise you can use some HOWTOs like
+ http://www.linuxhaven.de/dlhp/HOWTO/DE-ISDN-HOWTO-5.html
- You can also put the driver directly into Unimodem mode when it's loaded,
- by passing the module parameter startmode=0 to the hardware specific
- module, e.g.
- modprobe usb_gigaset startmode=0
- or by adding a line like
- options usb_gigaset startmode=0
- to an appropriate module configuration file, like /etc/modprobe.d/gigaset
- or /etc/modprobe.conf.local.
+2.5. Unimodem mode
+ -------------
In this mode the device works like a modem connected to a serial port
(the /dev/ttyGU0, ... mentioned above) which understands the commands
+
ATZ init, reset
=> OK or ERROR
ATD
@@ -234,6 +215,31 @@ GigaSet 307x Device Driver
to an appropriate module configuration file, like /etc/modprobe.d/gigaset
or /etc/modprobe.conf.local.
+ Unimodem mode is needed for making some devices [e.g. SX100] work which
+ do not support the regular Gigaset command set. If debug output (see
+ section 3.2.) shows something like this when dialing:
+ CMD Received: ERROR
+ Available Params: 0
+ Connection State: 0, Response: -1
+ gigaset_process_response: resp_code -1 in ConState 0 !
+ Timeout occurred
+ then switching to unimodem mode may help.
+
+ If you have installed the command line tool gigacontr, you can enter
+ unimodem mode using
+ gigacontr --mode unimodem
+ You can switch back using
+ gigacontr --mode isdn
+
+ You can also put the driver directly into Unimodem mode when it's loaded,
+ by passing the module parameter startmode=0 to the hardware specific
+ module, e.g.
+ modprobe usb_gigaset startmode=0
+ or by adding a line like
+ options usb_gigaset startmode=0
+ to an appropriate module configuration file, like /etc/modprobe.d/gigaset
+ or /etc/modprobe.conf.local.
+
2.6. Call-ID (CID) mode
------------------
Call-IDs are numbers used to tag commands to, and responses from, the
@@ -263,7 +269,22 @@ GigaSet 307x Device Driver
change its CID mode while the driver is loaded, eg.
echo 0 > /sys/class/tty/ttyGU0/cidmode
-2.7. Unregistered Wireless Devices (M101/M105)
+2.7. Dialing Numbers
+ ---------------
+ The called party number provided by an application for dialing out must
+ be a public network number according to the local dialing plan, without
+ any dial prefix for getting an outside line.
+
+ Internal calls can be made by providing an internal extension number
+ prefixed with "**" (two asterisks) as the called party number. So to dial
+ eg. the first registered DECT handset, give "**11" as the called party
+ number. Dialing "***" (three asterisks) calls all extensions
+ simultaneously (global call).
+
+ This holds for both CAPI 2.0 and ISDN4Linux applications. Unimodem mode
+ does not support internal calls.
+
+2.8. Unregistered Wireless Devices (M101/M105)
-----------------------------------------
The main purpose of the ser_gigaset and usb_gigaset drivers is to allow
the M101 and M105 wireless devices to be used as ISDN devices for ISDN
diff --git a/Documentation/ja_JP/HOWTO b/Documentation/ja_JP/HOWTO
index 55476982b5c..b63301a0381 100644
--- a/Documentation/ja_JP/HOWTO
+++ b/Documentation/ja_JP/HOWTO
@@ -223,7 +223,7 @@ web サイトã«ã¯ã€ã‚³ãƒ¼ãƒ‰ã®æ§‹æˆã€ã‚µãƒ–システムã€ç¾åœ¨å­˜åœ¨ã™ã
ã‚ãªãŸãŒã©ã“ã‹ã‚‰ã‚¹ã‚¿ãƒ¼ãƒˆã—ã¦è‰¯ã„ã‹ã‚ã‹ã‚‰ãªã„ãŒã€Linux カーãƒãƒ«é–‹ç™ºã‚³ãƒŸãƒ¥
ニティã«å‚加ã—ã¦ä½•ã‹ã™ã‚‹ã“ã¨ã‚’ã•ãŒã—ã¦ã„ã‚‹å ´åˆã«ã¯ã€Linux kernel
Janitor's プロジェクトã«ã„ã‘ã°è‰¯ã„ã§ã—ょㆠ-
- http://janitor.kernelnewbies.org/
+ http://kernelnewbies.org/KernelJanitors
ã“ã“ã¯ãã®ã‚ˆã†ãªã‚¹ã‚¿ãƒ¼ãƒˆã‚’ã™ã‚‹ã®ã«ã†ã£ã¦ã¤ã‘ã®å ´æ‰€ã§ã™ã€‚ã“ã“ã«ã¯ã€
Linux カーãƒãƒ«ã‚½ãƒ¼ã‚¹ãƒ„リーã®ä¸­ã«å«ã¾ã‚Œã‚‹ã€ãã‚Œã„ã«ã—ã€ä¿®æ­£ã—ãªã‘ã‚Œã°ãª
らãªã„ã€å˜ç´”ãªå•é¡Œã®ãƒªã‚¹ãƒˆãŒè¨˜è¿°ã•ã‚Œã¦ã„ã¾ã™ã€‚ã“ã®ãƒ—ロジェクトã«é–¢ã‚ã‚‹
diff --git a/Documentation/ja_JP/SubmittingPatches b/Documentation/ja_JP/SubmittingPatches
index a9dc1243e85..f107c834d24 100644
--- a/Documentation/ja_JP/SubmittingPatches
+++ b/Documentation/ja_JP/SubmittingPatches
@@ -97,7 +97,7 @@ Quilt:
http://savannah.nongnu.org/projects/quilt
Andrew Morton's patch scripts:
-http://www.zip.com.au/~akpm/linux/patches/
+http://userweb.kernel.org/~akpm/stuff/tpp.txt
ã“ã®ãƒªãƒ³ã‚¯ã®å…ˆã®ã‚¹ã‚¯ãƒªãƒ—トã®ä»£ã‚ã‚Šã¨ã—ã¦ã€quilt ãŒãƒ‘ッãƒãƒžãƒã‚¸ãƒ¡ãƒ³ãƒˆ
ツールã¨ã—ã¦æŽ¨å¥¨ã•ã‚Œã¦ã„ã¾ã™(上ã®ãƒªãƒ³ã‚¯ã‚’見ã¦ãã ã•ã„)。
@@ -210,7 +210,7 @@ VGER.KERNEL.ORG ã§ãƒ›ã‚¹ãƒ†ã‚£ãƒ³ã‚°ã•ã‚Œã¦ã„るメーリングリストã®ä
・移æ¤æ€§ã®ãªã„コードã‹ã‚‰ç§»æ¤æ€§ã®ã‚るコードã¸ã®ç½®ãæ›ãˆ(å°ã•ã„範囲ã§
ã‚ã‚Œã°ã‚¢ãƒ¼ã‚­ãƒ†ã‚¯ãƒãƒ£ç‰¹æœ‰ã®ã“ã¨ã§ã‚‚ä»–ã®äººãŒã‚³ãƒ”ーã§ãã¾ã™)
・作者やメンテナã«ã‚ˆã‚‹ä¿®æ­£(ã™ãªã‚ã¡ patch monkey ã®å†è»¢é€ãƒ¢ãƒ¼ãƒ‰)
-URL: <http://www.kernel.org/pub/linux/kernel/people/bunk/trivial/>
+EMAIL: <trivial@kernel.org>
7) MIME やリンクや圧縮ファイルや添付ファイルã§ã¯ãªãプレインテキストã®ã¿
@@ -534,7 +534,7 @@ gcc ã«ãŠã„ã¦ã¯ã€ãƒžã‚¯ãƒ­ã¨åŒã˜ãらã„軽ã„ã§ã™ã€‚
----------------------
Andrew Morton, "The perfect patch" (tpp).
- <http://www.zip.com.au/~akpm/linux/patches/stuff/tpp.txt>
+ <http://userweb.kernel.org/~akpm/stuff/tpp.txt>
Jeff Garzik, "Linux kernel patch submission format".
<http://linux.yyz.us/patch-format.html>
diff --git a/Documentation/kbuild/kbuild.txt b/Documentation/kbuild/kbuild.txt
index 634c625da8c..1e5165aa9e4 100644
--- a/Documentation/kbuild/kbuild.txt
+++ b/Documentation/kbuild/kbuild.txt
@@ -22,11 +22,33 @@ building C files and assembler files.
KAFLAGS
--------------------------------------------------
-Additional options to the assembler.
+Additional options to the assembler (for built-in and modules).
+
+AFLAGS_MODULE
+--------------------------------------------------
+Addtional module specific options to use for $(AS).
+
+AFLAGS_KERNEL
+--------------------------------------------------
+Addtional options for $(AS) when used for assembler
+code for code that is compiled as built-in.
KCFLAGS
--------------------------------------------------
-Additional options to the C compiler.
+Additional options to the C compiler (for built-in and modules).
+
+CFLAGS_KERNEL
+--------------------------------------------------
+Addtional options for $(CC) when used to compile
+code that is compiled as built-in.
+
+CFLAGS_MODULE
+--------------------------------------------------
+Addtional module specific options to use for $(CC).
+
+LDFLAGS_MODULE
+--------------------------------------------------
+Additional options used for $(LD) when linking modules.
KBUILD_VERBOSE
--------------------------------------------------
@@ -40,15 +62,15 @@ Set the directory to look for the kernel source when building external
modules.
The directory can be specified in several ways:
1) Use "M=..." on the command line
-2) Environmnet variable KBUILD_EXTMOD
-3) Environmnet variable SUBDIRS
+2) Environment variable KBUILD_EXTMOD
+3) Environment variable SUBDIRS
The possibilities are listed in the order they take precedence.
Using "M=..." will always override the others.
KBUILD_OUTPUT
--------------------------------------------------
Specify the output directory when building the kernel.
-The output directory can also be specificed using "O=...".
+The output directory can also be specified using "O=...".
Setting "O=..." takes precedence over KBUILD_OUTPUT.
ARCH
@@ -90,7 +112,7 @@ The script will be called with the following arguments:
$3 - kernel map file
$4 - default install path (use root directory if blank)
-The implmentation of "make install" is architecture specific
+The implementation of "make install" is architecture specific
and it may differ from the above.
INSTALLKERNEL is provided to enable the possibility to
diff --git a/Documentation/kbuild/kconfig.txt b/Documentation/kbuild/kconfig.txt
index b2cb16ebcb1..cca46b1a0f6 100644
--- a/Documentation/kbuild/kconfig.txt
+++ b/Documentation/kbuild/kconfig.txt
@@ -65,7 +65,7 @@ also use the environment variable KCONFIG_ALLCONFIG as a flag or a
filename that contains config symbols that the user requires to be
set to a specific value. If KCONFIG_ALLCONFIG is used without a
filename, "make *config" checks for a file named
-"all{yes/mod/no/random}.config" (corresponding to the *config command
+"all{yes/mod/no/def/random}.config" (corresponding to the *config command
that was used) for symbol values that are to be forced. If this file
is not found, it checks for a file named "all.config" to contain forced
values.
diff --git a/Documentation/kbuild/makefiles.txt b/Documentation/kbuild/makefiles.txt
index 71c602d6168..c375313cb12 100644
--- a/Documentation/kbuild/makefiles.txt
+++ b/Documentation/kbuild/makefiles.txt
@@ -168,7 +168,7 @@ more details, with real examples.
#drivers/isdn/i4l/Makefile
# Makefile for the kernel ISDN subsystem and device drivers.
# Each configuration option enables a list of files.
- obj-$(CONFIG_ISDN) += isdn.o
+ obj-$(CONFIG_ISDN_I4L) += isdn.o
obj-$(CONFIG_ISDN_PPP_BSDCOMP) += isdn_bsdcomp.o
--- 3.3 Loadable module goals - obj-m
@@ -187,34 +187,35 @@ more details, with real examples.
Note: In this example $(CONFIG_ISDN_PPP_BSDCOMP) evaluates to 'm'
If a kernel module is built from several source files, you specify
- that you want to build a module in the same way as above.
-
- Kbuild needs to know which the parts that you want to build your
- module from, so you have to tell it by setting an
- $(<module_name>-objs) variable.
+ that you want to build a module in the same way as above; however,
+ kbuild needs to know which object files you want to build your
+ module from, so you have to tell it by setting a $(<module_name>-y)
+ variable.
Example:
#drivers/isdn/i4l/Makefile
- obj-$(CONFIG_ISDN) += isdn.o
- isdn-objs := isdn_net_lib.o isdn_v110.o isdn_common.o
+ obj-$(CONFIG_ISDN_I4L) += isdn.o
+ isdn-y := isdn_net_lib.o isdn_v110.o isdn_common.o
In this example, the module name will be isdn.o. Kbuild will
- compile the objects listed in $(isdn-objs) and then run
+ compile the objects listed in $(isdn-y) and then run
"$(LD) -r" on the list of these files to generate isdn.o.
- Kbuild recognises objects used for composite objects by the suffix
- -objs, and the suffix -y. This allows the Makefiles to use
- the value of a CONFIG_ symbol to determine if an object is part
- of a composite object.
+ Due to kbuild recognizing $(<module_name>-y) for composite objects,
+ you can use the value of a CONFIG_ symbol to optionally include an
+ object file as part of a composite object.
Example:
#fs/ext2/Makefile
- obj-$(CONFIG_EXT2_FS) += ext2.o
- ext2-y := balloc.o bitmap.o
- ext2-$(CONFIG_EXT2_FS_XATTR) += xattr.o
+ obj-$(CONFIG_EXT2_FS) += ext2.o
+ ext2-y := balloc.o dir.o file.o ialloc.o inode.o ioctl.o \
+ namei.o super.o symlink.o
+ ext2-$(CONFIG_EXT2_FS_XATTR) += xattr.o xattr_user.o \
+ xattr_trusted.o
- In this example, xattr.o is only part of the composite object
- ext2.o if $(CONFIG_EXT2_FS_XATTR) evaluates to 'y'.
+ In this example, xattr.o, xattr_user.o and xattr_trusted.o are only
+ part of the composite object ext2.o if $(CONFIG_EXT2_FS_XATTR)
+ evaluates to 'y'.
Note: Of course, when you are building objects into the kernel,
the syntax above will also work. So, if you have CONFIG_EXT2_FS=y,
@@ -244,12 +245,12 @@ more details, with real examples.
may contain both a built-in.o and a lib.a file.
Example:
- #arch/i386/lib/Makefile
- lib-y := checksum.o delay.o
+ #arch/x86/lib/Makefile
+ lib-y := delay.o
- This will create a library lib.a based on checksum.o and delay.o.
- For kbuild to actually recognize that there is a lib.a being built,
- the directory shall be listed in libs-y.
+ This will create a library lib.a based on delay.o. For kbuild to
+ actually recognize that there is a lib.a being built, the directory
+ shall be listed in libs-y.
See also "6.3 List directories to visit when descending".
Use of lib-y is normally restricted to lib/ and arch/*/lib.
@@ -284,43 +285,40 @@ more details, with real examples.
--- 3.7 Compilation flags
ccflags-y, asflags-y and ldflags-y
- The three flags listed above applies only to the kbuild makefile
- where they are assigned. They are used for all the normal
- cc, as and ld invocation happenign during a recursive build.
+ These three flags apply only to the kbuild makefile in which they
+ are assigned. They are used for all the normal cc, as and ld
+ invocations happening during a recursive build.
Note: Flags with the same behaviour were previously named:
EXTRA_CFLAGS, EXTRA_AFLAGS and EXTRA_LDFLAGS.
- They are yet supported but their use are deprecated.
+ They are still supported but their usage is deprecated.
- ccflags-y specifies options for compiling C files with $(CC).
+ ccflags-y specifies options for compiling with $(CC).
Example:
- # drivers/sound/emu10k1/Makefile
- ccflags-y += -I$(obj)
- ccflags-$(DEBUG) += -DEMU10K1_DEBUG
-
+ # drivers/acpi/Makefile
+ ccflags-y := -Os
+ ccflags-$(CONFIG_ACPI_DEBUG) += -DACPI_DEBUG_OUTPUT
This variable is necessary because the top Makefile owns the
variable $(KBUILD_CFLAGS) and uses it for compilation flags for the
entire tree.
- asflags-y is a similar string for per-directory options
- when compiling assembly language source.
+ asflags-y specifies options for assembling with $(AS).
Example:
- #arch/x86_64/kernel/Makefile
- asflags-y := -traditional
-
+ #arch/sparc/kernel/Makefile
+ asflags-y := -ansi
- ldflags-y is a string for per-directory options to $(LD).
+ ldflags-y specifies options for linking with $(LD).
Example:
- #arch/m68k/fpsp040/Makefile
- ldflags-y := -x
+ #arch/cris/boot/compressed/Makefile
+ ldflags-y += -T $(srctree)/$(src)/decompress_$(arch-y).lds
subdir-ccflags-y, subdir-asflags-y
- The two flags listed above are similar to ccflags-y and as-falgs-y.
- The difference is that the subdir- variants has effect for the kbuild
- file where tey are present and all subdirectories.
+ The two flags listed above are similar to ccflags-y and asflags-y.
+ The difference is that the subdir- variants have effect for the kbuild
+ file where they are present and all subdirectories.
Options specified using subdir-* are added to the commandline before
the options specified using the non-subdir variants.
@@ -340,18 +338,18 @@ more details, with real examples.
CFLAGS_aha152x.o = -DAHA152X_STAT -DAUTOCONF
CFLAGS_gdth.o = # -DDEBUG_GDTH=2 -D__SERIAL__ -D__COM2__ \
-DGDTH_STATISTICS
- CFLAGS_seagate.o = -DARBITRATE -DPARITY -DSEAGATE_USE_ASM
- These three lines specify compilation flags for aha152x.o,
- gdth.o, and seagate.o
+ These two lines specify compilation flags for aha152x.o and gdth.o.
$(AFLAGS_$@) is a similar feature for source files in assembly
languages.
Example:
# arch/arm/kernel/Makefile
- AFLAGS_head-armv.o := -DTEXTADDR=$(TEXTADDR) -traditional
- AFLAGS_head-armo.o := -DTEXTADDR=$(TEXTADDR) -traditional
+ AFLAGS_head.o := -DTEXT_OFFSET=$(TEXT_OFFSET)
+ AFLAGS_crunch-bits.o := -Wa,-mcpu=ep9312
+ AFLAGS_iwmmxt.o := -Wa,-mcpu=iwmmxt
+
--- 3.9 Dependency tracking
@@ -923,16 +921,33 @@ When kbuild executes, the following steps are followed (roughly):
The first example utilises the trick that a config option expands
to 'y' when selected.
- CFLAGS_KERNEL $(CC) options specific for built-in
+ KBUILD_AFLAGS_KERNEL $(AS) options specific for built-in
+
+ $(KBUILD_AFLAGS_KERNEL) contains extra C compiler flags used to compile
+ resident kernel code.
+
+ KBUILD_AFLAGS_MODULE Options for $(AS) when building modules
+
+ $(KBUILD_AFLAGS_MODULE) is used to add arch specific options that
+ are used for $(AS).
+ From commandline AFLAGS_MODULE shall be used (see kbuild.txt).
- $(CFLAGS_KERNEL) contains extra C compiler flags used to compile
+ KBUILD_CFLAGS_KERNEL $(CC) options specific for built-in
+
+ $(KBUILD_CFLAGS_KERNEL) contains extra C compiler flags used to compile
resident kernel code.
- CFLAGS_MODULE $(CC) options specific for modules
+ KBUILD_CFLAGS_MODULE Options for $(CC) when building modules
+
+ $(KBUILD_CFLAGS_MODULE) is used to add arch specific options that
+ are used for $(CC).
+ From commandline CFLAGS_MODULE shall be used (see kbuild.txt).
- $(CFLAGS_MODULE) contains extra C compiler flags used to compile code
- for loadable kernel modules.
+ KBUILD_LDFLAGS_MODULE Options for $(LD) when linking modules
+ $(KBUILD_LDFLAGS_MODULE) is used to add arch specific options
+ used when linking modules. This is often a linker script.
+ From commandline LDFLAGS_MODULE shall be used (see kbuild.txt).
--- 6.2 Add prerequisites to archprepare:
@@ -1176,14 +1191,14 @@ When kbuild executes, the following steps are followed (roughly):
=== 7 Kbuild syntax for exported headers
The kernel include a set of headers that is exported to userspace.
-Many headers can be exported as-is but other headers requires a
+Many headers can be exported as-is but other headers require a
minimal pre-processing before they are ready for user-space.
The pre-processing does:
- drop kernel specific annotations
- drop include of compiler.h
-- drop all sections that is kernel internat (guarded by ifdef __KERNEL__)
+- drop all sections that are kernel internal (guarded by ifdef __KERNEL__)
-Each relevant directory contain a file name "Kbuild" which specify the
+Each relevant directory contains a file name "Kbuild" which specifies the
headers to be exported.
See subsequent chapter for the syntax of the Kbuild file.
diff --git a/Documentation/kernel-docs.txt b/Documentation/kernel-docs.txt
index ec8d31ee12e..715eaaf1519 100644
--- a/Documentation/kernel-docs.txt
+++ b/Documentation/kernel-docs.txt
@@ -75,7 +75,7 @@
* Title: "Conceptual Architecture of the Linux Kernel"
Author: Ivan T. Bowman.
- URL: http://plg.uwaterloo.ca/~itbowman/papers/CS746G-a1.html
+ URL: http://plg.uwaterloo.ca/
Keywords: conceptual software architecture, extracted design,
reverse engineering, system structure.
Description: Conceptual software architecture of the Linux kernel,
@@ -84,7 +84,7 @@
* Title: "Concrete Architecture of the Linux Kernel"
Author: Ivan T. Bowman, Saheem Siddiqi, and Meyer C. Tanuan.
- URL: http://plg.uwaterloo.ca/~itbowman/papers/CS746G-a2.html
+ URL: http://plg.uwaterloo.ca/
Keywords: concrete architecture, extracted design, reverse
engineering, system structure, dependencies.
Description: Concrete architecture of the Linux kernel,
@@ -95,7 +95,7 @@
* Title: "Linux as a Case Study: Its Extracted Software
Architecture"
Author: Ivan T. Bowman, Richard C. Holt and Neil V. Brewster.
- URL: http://plg.uwaterloo.ca/~itbowman/papers/linuxcase.html
+ URL: http://plg.uwaterloo.ca/
Keywords: software architecture, architecture recovery,
redocumentation.
Description: Paper appeared at ICSE'99, Los Angeles, May 16-22,
@@ -104,7 +104,7 @@
* Title: "Overview of the Virtual File System"
Author: Richard Gooch.
- URL: http://www.atnf.csiro.au/~rgooch/linux/vfs.txt
+ URL: http://www.mjmwired.net/kernel/Documentation/filesystems/vfs.txt
Keywords: VFS, File System, mounting filesystems, opening files,
dentries, dcache.
Description: Brief introduction to the Linux Virtual File System.
@@ -267,15 +267,13 @@
* Title: "Kernel API changes from 2.0 to 2.2"
Author: Richard Gooch.
URL:
- http://www.atnf.csiro.au/~rgooch/linux/docs/porting-to-2.2.html
+ http://www.linuxhq.com/guides/LKMPG/node28.html
Keywords: 2.2, changes.
Description: Kernel functions/structures/variables which changed
from 2.0.x to 2.2.x.
* Title: "Kernel API changes from 2.2 to 2.4"
Author: Richard Gooch.
- URL:
- http://www.atnf.csiro.au/~rgooch/linux/docs/porting-to-2.4.html
Keywords: 2.4, changes.
Description: Kernel functions/structures/variables which changed
from 2.2.x to 2.4.x.
@@ -290,7 +288,6 @@
* Title: "I/O Event Handling Under Linux"
Author: Richard Gooch.
- URL: http://www.atnf.csiro.au/~rgooch/linux/docs/io-events.html
Keywords: IO, I/O, select(2), poll(2), FDs, aio_read(2), readiness
event queues.
Description: From the Introduction: "I/O Event handling is about
@@ -386,64 +383,64 @@
* Title: "Porting Device Drivers To Linux 2.2: part II"
Author: Alan Cox.
- URL: http://www.linux-mag.com/1999-06/gear_01.html
+ URL: http://www.linux-mag.com/id/238
Keywords: ports, porting.
Description: Second part on porting from 2.0 to 2.2 kernels.
* Title: "How To Make Sure Your Driver Will Work On The Power
Macintosh"
Author: Paul Mackerras.
- URL: http://www.linux-mag.com/1999-07/gear_01.html
+ URL: http://www.linux-mag.com/id/261
Keywords: Mac, Power Macintosh, porting, drivers, compatibility.
Description: The title says it all.
* Title: "An Introduction to SCSI Drivers"
Author: Alan Cox.
- URL: http://www.linux-mag.com/1999-08/gear_01.html
+ URL: http://www.linux-mag.com/id/284
Keywords: SCSI, device, driver.
Description: The title says it all.
* Title: "Advanced SCSI Drivers And Other Tales"
Author: Alan Cox.
- URL: http://www.linux-mag.com/1999-09/gear_01.html
+ URL: http://www.linux-mag.com/id/307
Keywords: SCSI, device, driver, advanced.
Description: The title says it all.
* Title: "Writing Linux Mouse Drivers"
Author: Alan Cox.
- URL: http://www.linux-mag.com/1999-10/gear_01.html
+ URL: http://www.linux-mag.com/id/330
Keywords: mouse, driver, gpm.
Description: The title says it all.
* Title: "More on Mouse Drivers"
Author: Alan Cox.
- URL: http://www.linux-mag.com/1999-11/gear_01.html
+ URL: http://www.linux-mag.com/id/356
Keywords: mouse, driver, gpm, races, asynchronous I/O.
Description: The title still says it all.
* Title: "Writing Video4linux Radio Driver"
Author: Alan Cox.
- URL: http://www.linux-mag.com/1999-12/gear_01.html
+ URL: http://www.linux-mag.com/id/381
Keywords: video4linux, driver, radio, radio devices.
Description: The title says it all.
* Title: "Video4linux Drivers, Part 1: Video-Capture Device"
Author: Alan Cox.
- URL: http://www.linux-mag.com/2000-01/gear_01.html
+ URL: http://www.linux-mag.com/id/406
Keywords: video4linux, driver, video capture, capture devices,
camera driver.
Description: The title says it all.
* Title: "Video4linux Drivers, Part 2: Video-capture Devices"
Author: Alan Cox.
- URL: http://www.linux-mag.com/2000-02/gear_01.html
+ URL: http://www.linux-mag.com/id/429
Keywords: video4linux, driver, video capture, capture devices,
camera driver, control, query capabilities, capability, facility.
Description: The title says it all.
* Title: "PCI Management in Linux 2.2"
Author: Alan Cox.
- URL: http://www.linux-mag.com/2000-03/gear_01.html
+ URL: http://www.linux-mag.com/id/452
Keywords: PCI, bus, bus-mastering.
Description: The title says it all.
@@ -502,7 +499,7 @@
* Title: "A Linux vm README"
Author: Kanoj Sarcar.
- URL: http://reality.sgi.com/kanoj_engr/vm229.html
+ URL: http://kos.enix.org/pub/linux-vmm.html
Keywords: virtual memory, mm, pgd, vma, page, page flags, page
cache, swap cache, kswapd.
Description: Telegraphic, short descriptions and definitions
@@ -659,7 +656,7 @@
* Name: "Linux Kernel Source Reference"
Author: Thomas Graichen.
- URL: http://innominate.org/~graichen/projects/lksr/
+ URL: http://marc.info/?l=linux-kernel&m=96446640102205&w=4
Keywords: CVS, web, cvsweb, browsing source code.
Description: Web interface to a CVS server with the kernel
sources. "Here you can have a look at any file of the Linux kernel
@@ -682,7 +679,7 @@
produced during the week. Published every Thursday.
* Name: "Kernel Traffic"
- URL: http://kt.zork.net/kernel-traffic/
+ URL: http://kt.earth.li/kernel-traffic/index.html
Keywords: linux-kernel mailing list, weekly kernel news.
Description: Weekly newsletter covering the most relevant
discussions of the linux-kernel mailing list.
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index 2b2407d9a6d..44f6b19c50b 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -73,7 +73,6 @@ parameter is applicable:
MTD MTD (Memory Technology Device) support is enabled.
NET Appropriate network support is enabled.
NUMA NUMA support is enabled.
- GENERIC_TIME The generic timeofday code is enabled.
NFS Appropriate NFS support is enabled.
OSS OSS sound support is enabled.
PV_OPS A paravirtualized kernel is enabled.
@@ -93,6 +92,7 @@ parameter is applicable:
Documentation/scsi/.
SECURITY Different security models are enabled.
SELINUX SELinux support is enabled.
+ APPARMOR AppArmor support is enabled.
SERIAL Serial support is enabled.
SH SuperH architecture is enabled.
SMP The kernel is an SMP kernel.
@@ -115,6 +115,7 @@ parameter is applicable:
More X86-64 boot options can be found in
Documentation/x86/x86_64/boot-options.txt .
X86 Either 32bit or 64bit x86 (same as X86-32+X86-64)
+ XEN Xen support is enabled
In addition, the following text indicates that the option:
@@ -280,19 +281,12 @@ and is between 256 and 4096 characters. It is defined in the file
no: ACPI OperationRegions are not marked as reserved,
no further checks are performed.
- ad1848= [HW,OSS]
- Format: <io>,<irq>,<dma>,<dma2>,<type>
-
add_efi_memmap [EFI; X86] Include EFI memory map in
kernel's map of available physical RAM.
advansys= [HW,SCSI]
See header of drivers/scsi/advansys.c.
- aedsp16= [HW,OSS] Audio Excel DSP 16
- Format: <io>,<irq>,<dma>,<mss_io>,<mpu_io>,<mpu_irq>
- See also header of sound/oss/aedsp16.c.
-
agp= [AGP]
{ off | try_unsupported }
off: disable AGP support
@@ -311,6 +305,9 @@ and is between 256 and 4096 characters. It is defined in the file
aic79xx= [HW,SCSI]
See Documentation/scsi/aic79xx.txt.
+ ALSA [HW,ALSA]
+ See Documentation/sound/alsa/alsa-parameters.txt
+
alignment= [KNL,ARM]
Allow the default userspace alignment fault handler
behaviour to be specified. Bit 0 enables warnings,
@@ -468,7 +465,7 @@ and is between 256 and 4096 characters. It is defined in the file
clocksource is not available, it defaults to PIT.
Format: { pit | tsc | cyclone | pmtmr }
- clocksource= [GENERIC_TIME] Override the default clocksource
+ clocksource= Override the default clocksource
Format: <string>
Override the default clocksource and use the clocksource
with the name specified.
@@ -655,8 +652,6 @@ 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.
- dmasound= [HW,OSS] Sound subsystem buffers
-
dma_debug=off If the kernel is compiled with DMA_API_DEBUG support,
this option disables the debugging code at boot.
@@ -1143,9 +1138,12 @@ and is between 256 and 4096 characters. It is defined in the file
kgdboc= [KGDB,HW] kgdb over consoles.
Requires a tty driver that supports console polling,
or a supported polling keyboard driver (non-usb).
- Serial only format: <serial_device>[,baud]
- keyboard only format: kbd
- keyboard and serial format: kbd,<serial_device>[,baud]
+ Serial only format: <serial_device>[,baud]
+ keyboard only format: kbd
+ keyboard and serial format: kbd,<serial_device>[,baud]
+ Optional Kernel mode setting:
+ kms, kbd format: kms,kbd
+ kms, kbd and serial format: kms,kbd,<ser_dev>[,baud]
kgdbwait [KGDB] Stop kernel execution and enter the
kernel debugger at the earliest opportunity.
@@ -1523,9 +1521,6 @@ and is between 256 and 4096 characters. It is defined in the file
that the amount of memory usable for all allocations
is not too small.
- mpu401= [HW,OSS]
- Format: <io>,<irq>
-
MTD_Partition= [MTD]
Format: <name>,<region-number>,<size>,<offset>
@@ -1597,8 +1592,7 @@ and is between 256 and 4096 characters. It is defined in the file
[NETFILTER] Enable connection tracking flow accounting
0 to disable accounting
1 to enable accounting
- Default value depends on CONFIG_NF_CT_ACCT that is
- going to be removed in 2.6.29.
+ Default value is 0.
nfsaddrs= [NFS]
See Documentation/filesystems/nfs/nfsroot.txt.
@@ -1812,6 +1806,8 @@ and is between 256 and 4096 characters. It is defined in the file
nousb [USB] Disable the USB subsystem
+ nowatchdog [KNL] Disable the lockup detector.
+
nowb [ARM]
nox2apic [X86-64,APIC] Do not enable x2APIC mode.
@@ -1849,9 +1845,6 @@ and is between 256 and 4096 characters. It is defined in the file
For example, to override I2C bus2:
omap_mux=i2c2_scl.i2c2_scl=0x100,i2c2_sda.i2c2_sda=0x100
- opl3= [HW,OSS]
- Format: <io>
-
oprofile.timer= [HW]
Use timer interrupt instead of performance counters
@@ -1863,6 +1856,9 @@ and is between 256 and 4096 characters. It is defined in the file
perfmon on Intel CPUs instead of the
CPU specific event set.
+ OSS [HW,OSS]
+ See Documentation/sound/oss/oss-parameters.txt
+
osst= [HW,SCSI] SCSI Tape Driver
Format: <buffer_size>,<write_threshold>
See also Documentation/scsi/st.txt.
@@ -1899,9 +1895,6 @@ and is between 256 and 4096 characters. It is defined in the file
Currently this function knows 686a and 8231 chips.
Format: [spp|ps2|epp|ecp|ecpepp]
- pas2= [HW,OSS] Format:
- <io>,<irq>,<dma>,<dma16>,<sb_io>,<sb_irq>,<sb_dma>,<sb_dma16>
-
pas16= [HW,SCSI]
See header of drivers/scsi/pas16.c.
@@ -1970,6 +1963,8 @@ and is between 256 and 4096 characters. It is defined in the file
norom [X86] Do not assign address space to
expansion ROMs that do not already have
BIOS assigned address ranges.
+ nobar [X86] Do not assign address space to the
+ BARs that weren't assigned by the BIOS.
irqmask=0xMMMM [X86] Set a bit mask of IRQs allowed to be
assigned automatically to PCI devices. You can
make the kernel exclude IRQs of your ISA cards
@@ -2171,10 +2166,6 @@ and is between 256 and 4096 characters. It is defined in the file
[HW,MOUSE] Controls Logitech smartscroll autorepeat.
0 = disabled, 1 = enabled (default).
- pss= [HW,OSS] Personal Sound System (ECHO ESC614)
- Format:
- <io>,<mss_io>,<mss_irq>,<mss_dma>,<mpu_io>,<mpu_irq>
-
pt. [PARIDE]
See Documentation/blockdev/paride.txt.
@@ -2312,6 +2303,13 @@ and is between 256 and 4096 characters. It is defined in the file
If enabled at boot time, /selinux/disable can be used
later to disable prior to initial policy load.
+ apparmor= [APPARMOR] Disable or enable AppArmor at boot time
+ Format: { "0" | "1" }
+ See security/apparmor/Kconfig help text
+ 0 -- disable.
+ 1 -- enable.
+ Default value is set via kernel config option.
+
serialnumber [BUGS=X86-32]
shapers= [NET]
@@ -2383,128 +2381,6 @@ and is between 256 and 4096 characters. It is defined in the file
1: Fast pin select (default)
2: ATC IRMode
- snd-ad1816a= [HW,ALSA]
-
- snd-ad1848= [HW,ALSA]
-
- snd-ali5451= [HW,ALSA]
-
- snd-als100= [HW,ALSA]
-
- snd-als4000= [HW,ALSA]
-
- snd-azt2320= [HW,ALSA]
-
- snd-cmi8330= [HW,ALSA]
-
- snd-cmipci= [HW,ALSA]
-
- snd-cs4231= [HW,ALSA]
-
- snd-cs4232= [HW,ALSA]
-
- snd-cs4236= [HW,ALSA]
-
- snd-cs4281= [HW,ALSA]
-
- snd-cs46xx= [HW,ALSA]
-
- snd-dt019x= [HW,ALSA]
-
- snd-dummy= [HW,ALSA]
-
- snd-emu10k1= [HW,ALSA]
-
- snd-ens1370= [HW,ALSA]
-
- snd-ens1371= [HW,ALSA]
-
- snd-es968= [HW,ALSA]
-
- snd-es1688= [HW,ALSA]
-
- snd-es18xx= [HW,ALSA]
-
- snd-es1938= [HW,ALSA]
-
- snd-es1968= [HW,ALSA]
-
- snd-fm801= [HW,ALSA]
-
- snd-gusclassic= [HW,ALSA]
-
- snd-gusextreme= [HW,ALSA]
-
- snd-gusmax= [HW,ALSA]
-
- snd-hdsp= [HW,ALSA]
-
- snd-ice1712= [HW,ALSA]
-
- snd-intel8x0= [HW,ALSA]
-
- snd-interwave= [HW,ALSA]
-
- snd-interwave-stb=
- [HW,ALSA]
-
- snd-korg1212= [HW,ALSA]
-
- snd-maestro3= [HW,ALSA]
-
- snd-mpu401= [HW,ALSA]
-
- snd-mtpav= [HW,ALSA]
-
- snd-nm256= [HW,ALSA]
-
- snd-opl3sa2= [HW,ALSA]
-
- snd-opti92x-ad1848=
- [HW,ALSA]
-
- snd-opti92x-cs4231=
- [HW,ALSA]
-
- snd-opti93x= [HW,ALSA]
-
- snd-pmac= [HW,ALSA]
-
- snd-rme32= [HW,ALSA]
-
- snd-rme96= [HW,ALSA]
-
- snd-rme9652= [HW,ALSA]
-
- snd-sb8= [HW,ALSA]
-
- snd-sb16= [HW,ALSA]
-
- snd-sbawe= [HW,ALSA]
-
- snd-serial= [HW,ALSA]
-
- snd-sgalaxy= [HW,ALSA]
-
- snd-sonicvibes= [HW,ALSA]
-
- snd-sun-amd7930=
- [HW,ALSA]
-
- snd-sun-cs4231= [HW,ALSA]
-
- snd-trident= [HW,ALSA]
-
- snd-usb-audio= [HW,ALSA,USB]
-
- snd-via82xx= [HW,ALSA]
-
- snd-virmidi= [HW,ALSA]
-
- snd-wavefront= [HW,ALSA]
-
- snd-ymfpci= [HW,ALSA]
-
softlockup_panic=
[KNL] Should the soft-lockup detector generate panics.
@@ -2519,9 +2395,6 @@ and is between 256 and 4096 characters. It is defined in the file
spia_pedr=
spia_peddr=
- sscape= [HW,OSS]
- Format: <io>,<irq>,<dma>,<mpu_io>,<mpu_irq>
-
st= [HW,SCSI] SCSI tape parameters (buffers, etc.)
See Documentation/scsi/st.txt.
@@ -2661,10 +2534,6 @@ and is between 256 and 4096 characters. It is defined in the file
to facilitate early boot debugging.
See also Documentation/trace/events.txt
- trix= [HW,OSS] MediaTrix AudioTrix Pro
- Format:
- <io>,<irq>,<dma>,<dma2>,<sb_io>,<sb_irq>,<sb_dma>,<mpu_io>,<mpu_irq>
-
tsc= Disable clocksource-must-verify flag for TSC.
Format: <string>
[x86] reliable: mark tsc clocksource as reliable, this
@@ -2681,12 +2550,6 @@ and is between 256 and 4096 characters. It is defined in the file
u14-34f= [HW,SCSI] UltraStor 14F/34F SCSI host adapter
See header of drivers/scsi/u14-34f.c.
- uart401= [HW,OSS]
- Format: <io>,<irq>
-
- uart6850= [HW,OSS]
- Format: <io>,<irq>
-
uhash_entries= [KNL,NET]
Set number of hash buckets for UDP/UDP-Lite connections
@@ -2852,9 +2715,6 @@ and is between 256 and 4096 characters. It is defined in the file
overridden by individual drivers. 0 will hide
cursors, 1 will display them.
- waveartist= [HW,OSS]
- Format: <io>,<irq>,<dma>,<dma2>
-
wd33c93= [HW,SCSI]
See header of drivers/scsi/wd33c93.c.
@@ -2879,6 +2739,16 @@ and is between 256 and 4096 characters. It is defined in the file
xd= [HW,XT] Original XT pre-IDE (RLL encoded) disks.
xd_geo= See header of drivers/block/xd.c.
+ xen_emul_unplug= [HW,X86,XEN]
+ Unplug Xen emulated devices
+ Format: [unplug0,][unplug1]
+ ide-disks -- unplug primary master IDE devices
+ aux-ide-disks -- unplug non-primary-master IDE devices
+ nics -- unplug network devices
+ all -- unplug all emulated devices (NICs and IDE disks)
+ ignore -- continue loading the Xen platform PCI driver even
+ if the version check failed
+
xirc2ps_cs= [NET,PCMCIA]
Format:
<irq>,<irq_mask>,<io>,<full_duplex>,<do_sound>,<lockup_hack>[,<irq2>[,<irq3>[,<irq4>]]]
@@ -2887,5 +2757,4 @@ ______________________________________________________________________
TODO:
- Add documentation for ALSA options.
Add more DRM drivers.
diff --git a/Documentation/ko_KR/HOWTO b/Documentation/ko_KR/HOWTO
index 029fca914c0..e3a55b6091e 100644
--- a/Documentation/ko_KR/HOWTO
+++ b/Documentation/ko_KR/HOWTO
@@ -122,7 +122,7 @@ mtk.manpages@gmail.comì˜ ë©”ì¸í…Œì´ë„ˆì—게 보낼 ê²ƒì„ ê¶Œìž¥í•œë‹¤.
올바른 íŒ¨ì¹˜ë“¤ì„ ë§Œë“œëŠ” ë²•ì— ê´€í•œ 훌륭한 다른 ë¬¸ì„œë“¤ì´ ìžˆë‹¤.
"The Perfect Patch"
- http://www.zip.com.au/~akpm/linux/patches/stuff/tpp.txt
+ http://userweb.kernel.org/~akpm/stuff/tpp.txt
"Linux kernel patch submission format"
http://linux.yyz.us/patch-format.html
@@ -192,7 +192,7 @@ Documentation/DocBook/ 디렉토리 ë‚´ì—ì„œ 만들어지며 PDF, Postscript, H
ì—¬ëŸ¬ë¶„ì´ ì–´ë””ì„œ 시작해야 할진 모르지만 ì»¤ë„ ê°œë°œ ì»¤ë®¤ë‹ˆí‹°ì— ì°¸ì—¬í•  수
있는 ì¼ë“¤ì„ 찾길 ì›í•œë‹¤ë©´ 리눅스 ì»¤ë„ Janitor 프로ì íŠ¸ë¥¼ 살펴ë´ë¼.
- http://janitor.kernelnewbies.org/
+ http://kernelnewbies.org/KernelJanitors
ê·¸ê³³ì€ ì‹œìž‘í•˜ê¸°ì— í›Œë¥­í•œ 장소ì´ë‹¤. ê·¸ê³³ì€ ë¦¬ëˆ…ìŠ¤ ì»¤ë„ ì†ŒìŠ¤ 트리내ì—
간단히 정리ë˜ê³  ìˆ˜ì •ë  ìˆ˜ 있는 ë¬¸ì œë“¤ì— ê´€í•˜ì—¬ 설명한다. ì—¬ëŸ¬ë¶„ì€ ì´
프로ì íŠ¸ë¥¼ 대표하는 개발ìžë“¤ê³¼ ì¼í•˜ë©´ì„œ ìžì‹ ì˜ 패치를 리눅스 ì»¤ë„ íŠ¸ë¦¬ì—
@@ -596,7 +596,7 @@ Patì´ë¼ëŠ” ì´ë¦„ì„ ê°€ì§„ ì—¬ìžê°€ ìžˆì„ ìˆ˜ë„ ìžˆëŠ” 것ì´ë‹¤. 리눅ìŠ
ì´ê²ƒì´ 무엇ì¸ì§€ ë” ìžì„¸í•œ ê²ƒì„ ì•Œê³  싶다면 ë‹¤ìŒ ë¬¸ì„œì˜ ChageLog í•­ì„ ë´ë¼.
"The Perfect Patch"
- http://www.zip.com.au/~akpm/linux/patches/stuff/tpp.txt
+ http://userweb.kernel.org/~akpm/stuff/tpp.txt
@@ -610,7 +610,7 @@ Patì´ë¼ëŠ” ì´ë¦„ì„ ê°€ì§„ ì—¬ìžê°€ ìžˆì„ ìˆ˜ë„ ìžˆëŠ” 것ì´ë‹¤. 리눅ìŠ
----------
-"개발 프로세스"(http://linux.tar.gz/articles/2.6-development_process) 섹션ì„
+"개발 프로세스"(http://lwn.net/Articles/94386/) 섹션ì„
ìž‘ì„±í•˜ëŠ”ë° ìžˆì–´ 참고할 문서를 사용하ë„ë¡ í—ˆë½í•´ì¤€ Paolo Ciarrocchiì—게
ê°ì‚¬í•œë‹¤. ì—¬ëŸ¬ë¶„ë“¤ì´ ë§í•´ì•¼ í•  것과 ë§í•´ì„œëŠ” 안ë˜ëŠ” ê²ƒì˜ ëª©ë¡ ì¤‘ ì¼ë¶€ë¥¼ 제공해준
Randy Dunlapê³¼ Gerrit Huizengaì—게 ê°ì‚¬í•œë‹¤. ë˜í•œ 검토와 ì˜ê²¬ 그리고
diff --git a/Documentation/kprobes.txt b/Documentation/kprobes.txt
index 6653017680d..1762b81fcdf 100644
--- a/Documentation/kprobes.txt
+++ b/Documentation/kprobes.txt
@@ -285,6 +285,7 @@ architectures:
- sparc64 (Return probes not yet implemented.)
- arm
- ppc
+- mips
3. Configuring Kprobes
diff --git a/Documentation/kvm/api.txt b/Documentation/kvm/api.txt
index a237518e51b..5f5b64982b1 100644
--- a/Documentation/kvm/api.txt
+++ b/Documentation/kvm/api.txt
@@ -126,6 +126,10 @@ user fills in the size of the indices array in nmsrs, and in return
kvm adjusts nmsrs to reflect the actual number of msrs and fills in
the indices array with their numbers.
+Note: if kvm indicates supports MCE (KVM_CAP_MCE), then the MCE bank MSRs are
+not returned in the MSR list, as different vcpus can have a different number
+of banks, as set via the KVM_X86_SETUP_MCE ioctl.
+
4.4 KVM_CHECK_EXTENSION
Capability: basic
@@ -160,29 +164,7 @@ Type: vm ioctl
Parameters: struct kvm_memory_region (in)
Returns: 0 on success, -1 on error
-struct kvm_memory_region {
- __u32 slot;
- __u32 flags;
- __u64 guest_phys_addr;
- __u64 memory_size; /* bytes */
-};
-
-/* for kvm_memory_region::flags */
-#define KVM_MEM_LOG_DIRTY_PAGES 1UL
-
-This ioctl allows the user to create or modify a guest physical memory
-slot. When changing an existing slot, it may be moved in the guest
-physical memory space, or its flags may be modified. It may not be
-resized. Slots may not overlap.
-
-The flags field supports just one flag, KVM_MEM_LOG_DIRTY_PAGES, which
-instructs kvm to keep track of writes to memory within the slot. See
-the KVM_GET_DIRTY_LOG ioctl.
-
-It is recommended to use the KVM_SET_USER_MEMORY_REGION ioctl instead
-of this API, if available. This newer API allows placing guest memory
-at specified locations in the host address space, yielding better
-control and easy access.
+This ioctl is obsolete and has been removed.
4.6 KVM_CREATE_VCPU
@@ -226,17 +208,7 @@ Type: vm ioctl
Parameters: struct kvm_memory_alias (in)
Returns: 0 (success), -1 (error)
-struct kvm_memory_alias {
- __u32 slot; /* this has a different namespace than memory slots */
- __u32 flags;
- __u64 guest_phys_addr;
- __u64 memory_size;
- __u64 target_phys_addr;
-};
-
-Defines a guest physical address space region as an alias to another
-region. Useful for aliased address, for example the VGA low memory
-window. Should not be used with userspace memory.
+This ioctl is obsolete and has been removed.
4.9 KVM_RUN
@@ -892,6 +864,174 @@ arguments.
This ioctl is only useful after KVM_CREATE_IRQCHIP. Without an in-kernel
irqchip, the multiprocessing state must be maintained by userspace.
+4.39 KVM_SET_IDENTITY_MAP_ADDR
+
+Capability: KVM_CAP_SET_IDENTITY_MAP_ADDR
+Architectures: x86
+Type: vm ioctl
+Parameters: unsigned long identity (in)
+Returns: 0 on success, -1 on error
+
+This ioctl defines the physical address of a one-page region in the guest
+physical address space. The region must be within the first 4GB of the
+guest physical address space and must not conflict with any memory slot
+or any mmio address. The guest may malfunction if it accesses this memory
+region.
+
+This ioctl is required on Intel-based hosts. This is needed on Intel hardware
+because of a quirk in the virtualization implementation (see the internals
+documentation when it pops into existence).
+
+4.40 KVM_SET_BOOT_CPU_ID
+
+Capability: KVM_CAP_SET_BOOT_CPU_ID
+Architectures: x86, ia64
+Type: vm ioctl
+Parameters: unsigned long vcpu_id
+Returns: 0 on success, -1 on error
+
+Define which vcpu is the Bootstrap Processor (BSP). Values are the same
+as the vcpu id in KVM_CREATE_VCPU. If this ioctl is not called, the default
+is vcpu 0.
+
+4.41 KVM_GET_XSAVE
+
+Capability: KVM_CAP_XSAVE
+Architectures: x86
+Type: vcpu ioctl
+Parameters: struct kvm_xsave (out)
+Returns: 0 on success, -1 on error
+
+struct kvm_xsave {
+ __u32 region[1024];
+};
+
+This ioctl would copy current vcpu's xsave struct to the userspace.
+
+4.42 KVM_SET_XSAVE
+
+Capability: KVM_CAP_XSAVE
+Architectures: x86
+Type: vcpu ioctl
+Parameters: struct kvm_xsave (in)
+Returns: 0 on success, -1 on error
+
+struct kvm_xsave {
+ __u32 region[1024];
+};
+
+This ioctl would copy userspace's xsave struct to the kernel.
+
+4.43 KVM_GET_XCRS
+
+Capability: KVM_CAP_XCRS
+Architectures: x86
+Type: vcpu ioctl
+Parameters: struct kvm_xcrs (out)
+Returns: 0 on success, -1 on error
+
+struct kvm_xcr {
+ __u32 xcr;
+ __u32 reserved;
+ __u64 value;
+};
+
+struct kvm_xcrs {
+ __u32 nr_xcrs;
+ __u32 flags;
+ struct kvm_xcr xcrs[KVM_MAX_XCRS];
+ __u64 padding[16];
+};
+
+This ioctl would copy current vcpu's xcrs to the userspace.
+
+4.44 KVM_SET_XCRS
+
+Capability: KVM_CAP_XCRS
+Architectures: x86
+Type: vcpu ioctl
+Parameters: struct kvm_xcrs (in)
+Returns: 0 on success, -1 on error
+
+struct kvm_xcr {
+ __u32 xcr;
+ __u32 reserved;
+ __u64 value;
+};
+
+struct kvm_xcrs {
+ __u32 nr_xcrs;
+ __u32 flags;
+ struct kvm_xcr xcrs[KVM_MAX_XCRS];
+ __u64 padding[16];
+};
+
+This ioctl would set vcpu's xcr to the value userspace specified.
+
+4.45 KVM_GET_SUPPORTED_CPUID
+
+Capability: KVM_CAP_EXT_CPUID
+Architectures: x86
+Type: system ioctl
+Parameters: struct kvm_cpuid2 (in/out)
+Returns: 0 on success, -1 on error
+
+struct kvm_cpuid2 {
+ __u32 nent;
+ __u32 padding;
+ struct kvm_cpuid_entry2 entries[0];
+};
+
+#define KVM_CPUID_FLAG_SIGNIFCANT_INDEX 1
+#define KVM_CPUID_FLAG_STATEFUL_FUNC 2
+#define KVM_CPUID_FLAG_STATE_READ_NEXT 4
+
+struct kvm_cpuid_entry2 {
+ __u32 function;
+ __u32 index;
+ __u32 flags;
+ __u32 eax;
+ __u32 ebx;
+ __u32 ecx;
+ __u32 edx;
+ __u32 padding[3];
+};
+
+This ioctl returns x86 cpuid features which are supported by both the hardware
+and kvm. Userspace can use the information returned by this ioctl to
+construct cpuid information (for KVM_SET_CPUID2) that is consistent with
+hardware, kernel, and userspace capabilities, and with user requirements (for
+example, the user may wish to constrain cpuid to emulate older hardware,
+or for feature consistency across a cluster).
+
+Userspace invokes KVM_GET_SUPPORTED_CPUID by passing a kvm_cpuid2 structure
+with the 'nent' field indicating the number of entries in the variable-size
+array 'entries'. If the number of entries is too low to describe the cpu
+capabilities, an error (E2BIG) is returned. If the number is too high,
+the 'nent' field is adjusted and an error (ENOMEM) is returned. If the
+number is just right, the 'nent' field is adjusted to the number of valid
+entries in the 'entries' array, which is then filled.
+
+The entries returned are the host cpuid as returned by the cpuid instruction,
+with unknown or unsupported features masked out. The fields in each entry
+are defined as follows:
+
+ function: the eax value used to obtain the entry
+ index: the ecx value used to obtain the entry (for entries that are
+ affected by ecx)
+ flags: an OR of zero or more of the following:
+ KVM_CPUID_FLAG_SIGNIFCANT_INDEX:
+ if the index field is valid
+ KVM_CPUID_FLAG_STATEFUL_FUNC:
+ if cpuid for this function returns different values for successive
+ invocations; there will be several entries with the same function,
+ all with this flag set
+ KVM_CPUID_FLAG_STATE_READ_NEXT:
+ for KVM_CPUID_FLAG_STATEFUL_FUNC entries, set if this entry is
+ the first entry to be read by a cpu
+ eax, ebx, ecx, edx: the values returned by the cpuid instruction for
+ this function/index combination
+
5. The kvm_run structure
Application code obtains a pointer to the kvm_run structure by
diff --git a/Documentation/kvm/mmu.txt b/Documentation/kvm/mmu.txt
index aaed6ab9d7a..142cc513665 100644
--- a/Documentation/kvm/mmu.txt
+++ b/Documentation/kvm/mmu.txt
@@ -77,10 +77,10 @@ Memory
Guest memory (gpa) is part of the user address space of the process that is
using kvm. Userspace defines the translation between guest addresses and user
-addresses (gpa->hva); note that two gpas may alias to the same gva, but not
+addresses (gpa->hva); note that two gpas may alias to the same hva, but not
vice versa.
-These gvas may be backed using any method available to the host: anonymous
+These hvas may be backed using any method available to the host: anonymous
memory, file backed memory, and device memory. Memory might be paged by the
host at any time.
@@ -161,7 +161,7 @@ Shadow pages contain the following information:
role.cr4_pae:
Contains the value of cr4.pae for which the page is valid (e.g. whether
32-bit or 64-bit gptes are in use).
- role.cr4_nxe:
+ role.nxe:
Contains the value of efer.nxe for which the page is valid.
role.cr0_wp:
Contains the value of cr0.wp for which the page is valid.
@@ -180,7 +180,9 @@ Shadow pages contain the following information:
guest pages as leaves.
gfns:
An array of 512 guest frame numbers, one for each present pte. Used to
- perform a reverse map from a pte to a gfn.
+ perform a reverse map from a pte to a gfn. When role.direct is set, any
+ element of this array can be calculated from the gfn field when used, in
+ this case, the array of gfns is not allocated. See role.direct and gfn.
slot_bitmap:
A bitmap containing one bit per memory slot. If the page contains a pte
mapping a page from memory slot n, then bit n of slot_bitmap will be set
@@ -296,6 +298,48 @@ Host translation updates:
- look up affected sptes through reverse map
- drop (or update) translations
+Emulating cr0.wp
+================
+
+If tdp is not enabled, the host must keep cr0.wp=1 so page write protection
+works for the guest kernel, not guest guest userspace. When the guest
+cr0.wp=1, this does not present a problem. However when the guest cr0.wp=0,
+we cannot map the permissions for gpte.u=1, gpte.w=0 to any spte (the
+semantics require allowing any guest kernel access plus user read access).
+
+We handle this by mapping the permissions to two possible sptes, depending
+on fault type:
+
+- kernel write fault: spte.u=0, spte.w=1 (allows full kernel access,
+ disallows user access)
+- read fault: spte.u=1, spte.w=0 (allows full read access, disallows kernel
+ write access)
+
+(user write faults generate a #PF)
+
+Large pages
+===========
+
+The mmu supports all combinations of large and small guest and host pages.
+Supported page sizes include 4k, 2M, 4M, and 1G. 4M pages are treated as
+two separate 2M pages, on both guest and host, since the mmu always uses PAE
+paging.
+
+To instantiate a large spte, four constraints must be satisfied:
+
+- the spte must point to a large host page
+- the guest pte must be a large pte of at least equivalent size (if tdp is
+ enabled, there is no guest pte and this condition is satisified)
+- if the spte will be writeable, the large page frame may not overlap any
+ write-protected pages
+- the guest page must be wholly contained by a single memory slot
+
+To check the last two conditions, the mmu maintains a ->write_count set of
+arrays for each memory slot and large page size. Every write protected page
+causes its write_count to be incremented, thus preventing instantiation of
+a large spte. The frames at the end of an unaligned memory slot have
+artificically inflated ->write_counts so they can never be instantiated.
+
Further reading
===============
diff --git a/Documentation/kvm/msr.txt b/Documentation/kvm/msr.txt
new file mode 100644
index 00000000000..8ddcfe84c09
--- /dev/null
+++ b/Documentation/kvm/msr.txt
@@ -0,0 +1,153 @@
+KVM-specific MSRs.
+Glauber Costa <glommer@redhat.com>, Red Hat Inc, 2010
+=====================================================
+
+KVM makes use of some custom MSRs to service some requests.
+At present, this facility is only used by kvmclock.
+
+Custom MSRs have a range reserved for them, that goes from
+0x4b564d00 to 0x4b564dff. There are MSRs outside this area,
+but they are deprecated and their use is discouraged.
+
+Custom MSR list
+--------
+
+The current supported Custom MSR list is:
+
+MSR_KVM_WALL_CLOCK_NEW: 0x4b564d00
+
+ data: 4-byte alignment physical address of a memory area which must be
+ in guest RAM. This memory is expected to hold a copy of the following
+ structure:
+
+ struct pvclock_wall_clock {
+ u32 version;
+ u32 sec;
+ u32 nsec;
+ } __attribute__((__packed__));
+
+ whose data will be filled in by the hypervisor. The hypervisor is only
+ guaranteed to update this data at the moment of MSR write.
+ Users that want to reliably query this information more than once have
+ to write more than once to this MSR. Fields have the following meanings:
+
+ version: guest has to check version before and after grabbing
+ time information and check that they are both equal and even.
+ An odd version indicates an in-progress update.
+
+ sec: number of seconds for wallclock.
+
+ nsec: number of nanoseconds for wallclock.
+
+ Note that although MSRs are per-CPU entities, the effect of this
+ particular MSR is global.
+
+ Availability of this MSR must be checked via bit 3 in 0x4000001 cpuid
+ leaf prior to usage.
+
+MSR_KVM_SYSTEM_TIME_NEW: 0x4b564d01
+
+ data: 4-byte aligned physical address of a memory area which must be in
+ guest RAM, plus an enable bit in bit 0. This memory is expected to hold
+ a copy of the following structure:
+
+ struct pvclock_vcpu_time_info {
+ u32 version;
+ u32 pad0;
+ u64 tsc_timestamp;
+ u64 system_time;
+ u32 tsc_to_system_mul;
+ s8 tsc_shift;
+ u8 flags;
+ u8 pad[2];
+ } __attribute__((__packed__)); /* 32 bytes */
+
+ whose data will be filled in by the hypervisor periodically. Only one
+ write, or registration, is needed for each VCPU. The interval between
+ updates of this structure is arbitrary and implementation-dependent.
+ The hypervisor may update this structure at any time it sees fit until
+ anything with bit0 == 0 is written to it.
+
+ Fields have the following meanings:
+
+ version: guest has to check version before and after grabbing
+ time information and check that they are both equal and even.
+ An odd version indicates an in-progress update.
+
+ tsc_timestamp: the tsc value at the current VCPU at the time
+ of the update of this structure. Guests can subtract this value
+ from current tsc to derive a notion of elapsed time since the
+ structure update.
+
+ system_time: a host notion of monotonic time, including sleep
+ time at the time this structure was last updated. Unit is
+ nanoseconds.
+
+ tsc_to_system_mul: a function of the tsc frequency. One has
+ to multiply any tsc-related quantity by this value to get
+ a value in nanoseconds, besides dividing by 2^tsc_shift
+
+ tsc_shift: cycle to nanosecond divider, as a power of two, to
+ allow for shift rights. One has to shift right any tsc-related
+ quantity by this value to get a value in nanoseconds, besides
+ multiplying by tsc_to_system_mul.
+
+ With this information, guests can derive per-CPU time by
+ doing:
+
+ time = (current_tsc - tsc_timestamp)
+ time = (time * tsc_to_system_mul) >> tsc_shift
+ time = time + system_time
+
+ flags: bits in this field indicate extended capabilities
+ coordinated between the guest and the hypervisor. Availability
+ of specific flags has to be checked in 0x40000001 cpuid leaf.
+ Current flags are:
+
+ flag bit | cpuid bit | meaning
+ -------------------------------------------------------------
+ | | time measures taken across
+ 0 | 24 | multiple cpus are guaranteed to
+ | | be monotonic
+ -------------------------------------------------------------
+
+ Availability of this MSR must be checked via bit 3 in 0x4000001 cpuid
+ leaf prior to usage.
+
+
+MSR_KVM_WALL_CLOCK: 0x11
+
+ data and functioning: same as MSR_KVM_WALL_CLOCK_NEW. Use that instead.
+
+ This MSR falls outside the reserved KVM range and may be removed in the
+ future. Its usage is deprecated.
+
+ Availability of this MSR must be checked via bit 0 in 0x4000001 cpuid
+ leaf prior to usage.
+
+MSR_KVM_SYSTEM_TIME: 0x12
+
+ data and functioning: same as MSR_KVM_SYSTEM_TIME_NEW. Use that instead.
+
+ This MSR falls outside the reserved KVM range and may be removed in the
+ future. Its usage is deprecated.
+
+ Availability of this MSR must be checked via bit 0 in 0x4000001 cpuid
+ leaf prior to usage.
+
+ The suggested algorithm for detecting kvmclock presence is then:
+
+ if (!kvm_para_available()) /* refer to cpuid.txt */
+ return NON_PRESENT;
+
+ flags = cpuid_eax(0x40000001);
+ if (flags & 3) {
+ msr_kvm_system_time = MSR_KVM_SYSTEM_TIME_NEW;
+ msr_kvm_wall_clock = MSR_KVM_WALL_CLOCK_NEW;
+ return PRESENT;
+ } else if (flags & 0) {
+ msr_kvm_system_time = MSR_KVM_SYSTEM_TIME;
+ msr_kvm_wall_clock = MSR_KVM_WALL_CLOCK;
+ return PRESENT;
+ } else
+ return NON_PRESENT;
diff --git a/Documentation/kvm/review-checklist.txt b/Documentation/kvm/review-checklist.txt
new file mode 100644
index 00000000000..730475ae1b8
--- /dev/null
+++ b/Documentation/kvm/review-checklist.txt
@@ -0,0 +1,38 @@
+Review checklist for kvm patches
+================================
+
+1. The patch must follow Documentation/CodingStyle and
+ Documentation/SubmittingPatches.
+
+2. Patches should be against kvm.git master branch.
+
+3. If the patch introduces or modifies a new userspace API:
+ - the API must be documented in Documentation/kvm/api.txt
+ - the API must be discoverable using KVM_CHECK_EXTENSION
+
+4. New state must include support for save/restore.
+
+5. New features must default to off (userspace should explicitly request them).
+ Performance improvements can and should default to on.
+
+6. New cpu features should be exposed via KVM_GET_SUPPORTED_CPUID2
+
+7. Emulator changes should be accompanied by unit tests for qemu-kvm.git
+ kvm/test directory.
+
+8. Changes should be vendor neutral when possible. Changes to common code
+ are better than duplicating changes to vendor code.
+
+9. Similarly, prefer changes to arch independent code than to arch dependent
+ code.
+
+10. User/kernel interfaces and guest/host interfaces must be 64-bit clean
+ (all variables and sizes naturally aligned on 64-bit; use specific types
+ only - u64 rather than ulong).
+
+11. New guest visible features must either be documented in a hardware manual
+ or be accompanied by documentation.
+
+12. Features must be robust against reset and kexec - for example, shared
+ host/guest memory must be unshared to prevent the host from writing to
+ guest memory that the guest has not reserved for this purpose.
diff --git a/Documentation/laptops/acer-wmi.txt b/Documentation/laptops/acer-wmi.txt
index 0768fcc3ba3..4beafa663dd 100644
--- a/Documentation/laptops/acer-wmi.txt
+++ b/Documentation/laptops/acer-wmi.txt
@@ -173,7 +173,7 @@ Credits
*******
Olaf Tauber, who did the real hard work when he developed acerhk
-http://www.informatik.hu-berlin.de/~tauber/acerhk
+http://www.cakey.de/acerhk/
All the authors of laptop ACPI modules in the kernel, whose work
was an inspiration in the early days of acer_acpi
Mathieu Segaud, who solved the problem with having to modprobe the driver
diff --git a/Documentation/laptops/thinkpad-acpi.txt b/Documentation/laptops/thinkpad-acpi.txt
index fc15538d8b4..f6f80257add 100644
--- a/Documentation/laptops/thinkpad-acpi.txt
+++ b/Documentation/laptops/thinkpad-acpi.txt
@@ -960,70 +960,21 @@ Sysfs notes:
subsystem, and follow all of the hwmon guidelines at
Documentation/hwmon.
+EXPERIMENTAL: Embedded controller register dump
+-----------------------------------------------
-EXPERIMENTAL: Embedded controller register dump -- /proc/acpi/ibm/ecdump
-------------------------------------------------------------------------
-
-This 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.
-
-This feature dumps the values of 256 embedded controller
-registers. Values which have changed since the last time the registers
-were dumped are marked with a star:
-
-[root@x40 ibm-acpi]# cat /proc/acpi/ibm/ecdump
-EC +00 +01 +02 +03 +04 +05 +06 +07 +08 +09 +0a +0b +0c +0d +0e +0f
-EC 0x00: a7 47 87 01 fe 96 00 08 01 00 cb 00 00 00 40 00
-EC 0x10: 00 00 ff ff f4 3c 87 09 01 ff 42 01 ff ff 0d 00
-EC 0x20: 00 00 00 00 00 00 00 00 00 00 00 03 43 00 00 80
-EC 0x30: 01 07 1a 00 30 04 00 00 *85 00 00 10 00 50 00 00
-EC 0x40: 00 00 00 00 00 00 14 01 00 04 00 00 00 00 00 00
-EC 0x50: 00 c0 02 0d 00 01 01 02 02 03 03 03 03 *bc *02 *bc
-EC 0x60: *02 *bc *02 00 00 00 00 00 00 00 00 00 00 00 00 00
-EC 0x70: 00 00 00 00 00 12 30 40 *24 *26 *2c *27 *20 80 *1f 80
-EC 0x80: 00 00 00 06 *37 *0e 03 00 00 00 0e 07 00 00 00 00
-EC 0x90: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
-EC 0xa0: *ff 09 ff 09 ff ff *64 00 *00 *00 *a2 41 *ff *ff *e0 00
-EC 0xb0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
-EC 0xc0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
-EC 0xd0: 03 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
-EC 0xe0: 00 00 00 00 00 00 00 00 11 20 49 04 24 06 55 03
-EC 0xf0: 31 55 48 54 35 38 57 57 08 2f 45 73 07 65 6c 1a
-
-This feature can be used to determine the register holding the fan
-speed on some models. To do that, do the following:
+This feature is not included in the thinkpad driver anymore.
+Instead the EC can be accessed through /sys/kernel/debug/ec with
+a userspace tool which can be found here:
+ftp://ftp.suse.com/pub/people/trenn/sources/ec
+Use it to determine the register holding the fan
+speed on some models. To do that, do the following:
- make sure the battery is fully charged
- make sure the fan is running
- - run 'cat /proc/acpi/ibm/ecdump' several times, once per second or so
-
-The first step makes sure various charging-related values don't
-vary. The second ensures that the fan-related values do vary, since
-the fan speed fluctuates a bit. The third will (hopefully) mark the
-fan register with a star:
-
-[root@x40 ibm-acpi]# cat /proc/acpi/ibm/ecdump
-EC +00 +01 +02 +03 +04 +05 +06 +07 +08 +09 +0a +0b +0c +0d +0e +0f
-EC 0x00: a7 47 87 01 fe 96 00 08 01 00 cb 00 00 00 40 00
-EC 0x10: 00 00 ff ff f4 3c 87 09 01 ff 42 01 ff ff 0d 00
-EC 0x20: 00 00 00 00 00 00 00 00 00 00 00 03 43 00 00 80
-EC 0x30: 01 07 1a 00 30 04 00 00 85 00 00 10 00 50 00 00
-EC 0x40: 00 00 00 00 00 00 14 01 00 04 00 00 00 00 00 00
-EC 0x50: 00 c0 02 0d 00 01 01 02 02 03 03 03 03 bc 02 bc
-EC 0x60: 02 bc 02 00 00 00 00 00 00 00 00 00 00 00 00 00
-EC 0x70: 00 00 00 00 00 12 30 40 24 27 2c 27 21 80 1f 80
-EC 0x80: 00 00 00 06 *be 0d 03 00 00 00 0e 07 00 00 00 00
-EC 0x90: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
-EC 0xa0: ff 09 ff 09 ff ff 64 00 00 00 a2 41 ff ff e0 00
-EC 0xb0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
-EC 0xc0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
-EC 0xd0: 03 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
-EC 0xe0: 00 00 00 00 00 00 00 00 11 20 49 04 24 06 55 03
-EC 0xf0: 31 55 48 54 35 38 57 57 08 2f 45 73 07 65 6c 1a
-
-Another set of values that varies often is the temperature
+ - use above mentioned tool to read out the EC
+
+Often fan and temperature values vary between
readings. Since temperatures don't change vary fast, you can take
several quick dumps to eliminate them.
diff --git a/Documentation/ldm.txt b/Documentation/ldm.txt
index 718085bc9f1..4f80edd14d0 100644
--- a/Documentation/ldm.txt
+++ b/Documentation/ldm.txt
@@ -98,7 +98,7 @@ More Documentation
There is an Overview of the LDM together with complete Technical Documentation.
It is available for download.
- http://www.linux-ntfs.org/content/view/19/37/
+ http://www.linux-ntfs.org/
If you have any LDM questions that aren't answered in the documentation, email
me.
diff --git a/Documentation/md.txt b/Documentation/md.txt
index e4e893ef3e0..a81c7b4790f 100644
--- a/Documentation/md.txt
+++ b/Documentation/md.txt
@@ -1,5 +1,5 @@
Tools that manage md devices can be found at
- http://www.<country>.kernel.org/pub/linux/utils/raid/....
+ http://www.kernel.org/pub/linux/utils/raid/
Boot time assembly of RAID arrays
diff --git a/Documentation/misc-devices/c2port.txt b/Documentation/misc-devices/c2port.txt
index d9bf93ea439..ea734446561 100644
--- a/Documentation/misc-devices/c2port.txt
+++ b/Documentation/misc-devices/c2port.txt
@@ -32,10 +32,10 @@ The C2 Interface main references are at (http://www.silabs.com)
Silicon Laboratories site], see:
- AN127: FLASH Programming via the C2 Interface at
-http://www.silabs.com/public/documents/tpub_doc/anote/Microcontrollers/Small_Form_Factor/en/an127.pdf, and
+http://www.silabs.com/Support Documents/TechnicalDocs/an127.pdf
- C2 Specification at
-http://www.silabs.com/public/documents/tpub_doc/spec/Microcontrollers/en/C2spec.pdf,
+http://www.silabs.com/pages/DownloadDoc.aspx?FILEURL=Support%20Documents/TechnicalDocs/an127.pdf&src=SearchResults
however it implements a two wire serial communication protocol (bit
banging) designed to enable in-system programming, debugging, and
diff --git a/Documentation/mtd/nand_ecc.txt b/Documentation/mtd/nand_ecc.txt
index 274821b35a7..990efd7a981 100644
--- a/Documentation/mtd/nand_ecc.txt
+++ b/Documentation/mtd/nand_ecc.txt
@@ -91,7 +91,7 @@ ECC 1 rp15 rp14 rp13 rp12 rp11 rp10 rp09 rp08
ECC 2 cp5 cp4 cp3 cp2 cp1 cp0 1 1
I detected after writing this that ST application note AN1823
-(http://www.st.com/stonline/books/pdf/docs/10123.pdf) gives a much
+(http://www.st.com/stonline/) gives a much
nicer picture.(but they use line parity as term where I use row parity)
Oh well, I'm graphically challenged, so suffer with me for a moment :-)
And I could not reuse the ST picture anyway for copyright reasons.
diff --git a/Documentation/networking/3c509.txt b/Documentation/networking/3c509.txt
index 3c45d5dcd63..dcc9eaf5939 100644
--- a/Documentation/networking/3c509.txt
+++ b/Documentation/networking/3c509.txt
@@ -31,7 +31,7 @@ models:
Large portions of this documentation were heavily borrowed from the guide
written the original author of the 3c509 driver, Donald Becker. The master
copy of that document, which contains notes on older versions of the driver,
-currently resides on Scyld web server: http://www.scyld.com/network/3c509.html.
+currently resides on Scyld web server: http://www.scyld.com/.
(1) Special Driver Features
diff --git a/Documentation/networking/README.ipw2100 b/Documentation/networking/README.ipw2100
index f3fcaa41f77..6f85e1d0603 100644
--- a/Documentation/networking/README.ipw2100
+++ b/Documentation/networking/README.ipw2100
@@ -72,8 +72,7 @@ such, if you are interested in deploying or shipping a driver as part of
solution intended to be used for purposes other than development, please
obtain a tested driver from Intel Customer Support at:
-http://support.intel.com/support/notebook/sb/CS-006408.htm
-
+http://www.intel.com/support/wireless/sb/CS-006408.htm
1. Introduction
-----------------------------------------------
diff --git a/Documentation/networking/README.ipw2200 b/Documentation/networking/README.ipw2200
index 80c728522c4..616a8e540b0 100644
--- a/Documentation/networking/README.ipw2200
+++ b/Documentation/networking/README.ipw2200
@@ -85,7 +85,7 @@ such, if you are interested in deploying or shipping a driver as part of
solution intended to be used for purposes other than development, please
obtain a tested driver from Intel Customer Support at:
-http://support.intel.com/support/notebook/sb/CS-006408.htm
+http://support.intel.com
1. Introduction
@@ -171,7 +171,7 @@ Where the supported parameter are:
led
Can be used to turn on experimental LED code.
- 0 = Off, 1 = On. Default is 0.
+ 0 = Off, 1 = On. Default is 1.
mode
Can be used to set the default mode of the adapter.
diff --git a/Documentation/networking/README.sb1000 b/Documentation/networking/README.sb1000
index f82d42584e9..f92c2aac56a 100644
--- a/Documentation/networking/README.sb1000
+++ b/Documentation/networking/README.sb1000
@@ -27,8 +27,8 @@ cable modem easy.
in Franco's original source code distribution .tar.gz file. Support for
the sb1000 driver can be found at:
- http://home.adelphia.net/~siglercm/sb1000.html
- http://linuxpower.cx/~cable/
+ http://web.archive.org/web/*/http://home.adelphia.net/~siglercm/sb1000.html
+ http://web.archive.org/web/*/http://linuxpower.cx/~cable/
along with these utilities.
diff --git a/Documentation/networking/arcnet.txt b/Documentation/networking/arcnet.txt
index 79601254038..9ff57950215 100644
--- a/Documentation/networking/arcnet.txt
+++ b/Documentation/networking/arcnet.txt
@@ -68,7 +68,7 @@ REAL NAME" to listserv@tichy.ch.uj.edu.pl. Then, to submit messages to the
list, mail to linux-arcnet@tichy.ch.uj.edu.pl.
There are archives of the mailing list at:
- http://tichy.ch.uj.edu.pl/lists/linux-arcnet
+ http://epistolary.org/mailman/listinfo.cgi/arcnet
The people on linux-net@vger.kernel.org have also been known to be very
helpful, especially when we're talking about ALPHA Linux kernels that may or
@@ -79,7 +79,7 @@ Other Drivers and Info
----------------------
You can try my ARCNET page on the World Wide Web at:
- http://www.worldvisions.ca/~apenwarr/arcnet/
+ http://www.qis.net/~jschmitz/arcnet/
Also, SMC (one of the companies that makes ARCnet cards) has a WWW site you
might be interested in, which includes several drivers for various cards
diff --git a/Documentation/networking/bonding.txt b/Documentation/networking/bonding.txt
index 61f516b135b..d2b62b71b61 100644
--- a/Documentation/networking/bonding.txt
+++ b/Documentation/networking/bonding.txt
@@ -49,6 +49,7 @@ Table of Contents
3.3 Configuring Bonding Manually with Ifenslave
3.3.1 Configuring Multiple Bonds Manually
3.4 Configuring Bonding Manually via Sysfs
+3.5 Overriding Configuration for Special Cases
4. Querying Bonding Configuration
4.1 Bonding Configuration
@@ -1318,8 +1319,87 @@ echo 2000 > /sys/class/net/bond1/bonding/arp_interval
echo +eth2 > /sys/class/net/bond1/bonding/slaves
echo +eth3 > /sys/class/net/bond1/bonding/slaves
-
-4. Querying Bonding Configuration
+3.5 Overriding Configuration for Special Cases
+----------------------------------------------
+When using the bonding driver, the physical port which transmits a frame is
+typically selected by the bonding driver, and is not relevant to the user or
+system administrator. The output port is simply selected using the policies of
+the selected bonding mode. On occasion however, it is helpful to direct certain
+classes of traffic to certain physical interfaces on output to implement
+slightly more complex policies. For example, to reach a web server over a
+bonded interface in which eth0 connects to a private network, while eth1
+connects via a public network, it may be desirous to bias the bond to send said
+traffic over eth0 first, using eth1 only as a fall back, while all other traffic
+can safely be sent over either interface. Such configurations may be achieved
+using the traffic control utilities inherent in linux.
+
+By default the bonding driver is multiqueue aware and 16 queues are created
+when the driver initializes (see Documentation/networking/multiqueue.txt
+for details). If more or less queues are desired the module parameter
+tx_queues can be used to change this value. There is no sysfs parameter
+available as the allocation is done at module init time.
+
+The output of the file /proc/net/bonding/bondX has changed so the output Queue
+ID is now printed for each slave:
+
+Bonding Mode: fault-tolerance (active-backup)
+Primary Slave: None
+Currently Active Slave: eth0
+MII Status: up
+MII Polling Interval (ms): 0
+Up Delay (ms): 0
+Down Delay (ms): 0
+
+Slave Interface: eth0
+MII Status: up
+Link Failure Count: 0
+Permanent HW addr: 00:1a:a0:12:8f:cb
+Slave queue ID: 0
+
+Slave Interface: eth1
+MII Status: up
+Link Failure Count: 0
+Permanent HW addr: 00:1a:a0:12:8f:cc
+Slave queue ID: 2
+
+The queue_id for a slave can be set using the command:
+
+# echo "eth1:2" > /sys/class/net/bond0/bonding/queue_id
+
+Any interface that needs a queue_id set should set it with multiple calls
+like the one above until proper priorities are set for all interfaces. On
+distributions that allow configuration via initscripts, multiple 'queue_id'
+arguments can be added to BONDING_OPTS to set all needed slave queues.
+
+These queue id's can be used in conjunction with the tc utility to configure
+a multiqueue qdisc and filters to bias certain traffic to transmit on certain
+slave devices. For instance, say we wanted, in the above configuration to
+force all traffic bound to 192.168.1.100 to use eth1 in the bond as its output
+device. The following commands would accomplish this:
+
+# tc qdisc add dev bond0 handle 1 root multiq
+
+# tc filter add dev bond0 protocol ip parent 1: prio 1 u32 match ip dst \
+ 192.168.1.100 action skbedit queue_mapping 2
+
+These commands tell the kernel to attach a multiqueue queue discipline to the
+bond0 interface and filter traffic enqueued to it, such that packets with a dst
+ip of 192.168.1.100 have their output queue mapping value overwritten to 2.
+This value is then passed into the driver, causing the normal output path
+selection policy to be overridden, selecting instead qid 2, which maps to eth1.
+
+Note that qid values begin at 1. Qid 0 is reserved to initiate to the driver
+that normal output policy selection should take place. One benefit to simply
+leaving the qid for a slave to 0 is the multiqueue awareness in the bonding
+driver that is now present. This awareness allows tc filters to be placed on
+slave devices as well as bond devices and the bonding driver will simply act as
+a pass-through for selecting output queues on the slave device rather than
+output port selection.
+
+This feature first appeared in bonding driver version 3.7.0 and support for
+output slave selection was limited to round-robin and active-backup modes.
+
+4 Querying Bonding Configuration
=================================
4.1 Bonding Configuration
@@ -2432,7 +2512,7 @@ be found at:
https://lists.sourceforge.net/lists/listinfo/bonding-devel
Donald Becker's Ethernet Drivers and diag programs may be found at :
- - http://www.scyld.com/network/
+ - http://web.archive.org/web/*/http://www.scyld.com/network/
You will also find a lot of information regarding Ethernet, NWay, MII,
etc. at www.scyld.com.
diff --git a/Documentation/networking/caif/spi_porting.txt b/Documentation/networking/caif/spi_porting.txt
new file mode 100644
index 00000000000..61d7c924745
--- /dev/null
+++ b/Documentation/networking/caif/spi_porting.txt
@@ -0,0 +1,208 @@
+- CAIF SPI porting -
+
+- CAIF SPI basics:
+
+Running CAIF over SPI needs some extra setup, owing to the nature of SPI.
+Two extra GPIOs have been added in order to negotiate the transfers
+ between the master and the slave. The minimum requirement for running
+CAIF over SPI is a SPI slave chip and two GPIOs (more details below).
+Please note that running as a slave implies that you need to keep up
+with the master clock. An overrun or underrun event is fatal.
+
+- CAIF SPI framework:
+
+To make porting as easy as possible, the CAIF SPI has been divided in
+two parts. The first part (called the interface part) deals with all
+generic functionality such as length framing, SPI frame negotiation
+and SPI frame delivery and transmission. The other part is the CAIF
+SPI slave device part, which is the module that you have to write if
+you want to run SPI CAIF on a new hardware. This part takes care of
+the physical hardware, both with regard to SPI and to GPIOs.
+
+- Implementing a CAIF SPI device:
+
+ - Functionality provided by the CAIF SPI slave device:
+
+ In order to implement a SPI device you will, as a minimum,
+ need to implement the following
+ functions:
+
+ int (*init_xfer) (struct cfspi_xfer * xfer, struct cfspi_dev *dev):
+
+ This function is called by the CAIF SPI interface to give
+ you a chance to set up your hardware to be ready to receive
+ a stream of data from the master. The xfer structure contains
+ both physical and logical adresses, as well as the total length
+ of the transfer in both directions.The dev parameter can be used
+ to map to different CAIF SPI slave devices.
+
+ void (*sig_xfer) (bool xfer, struct cfspi_dev *dev):
+
+ This function is called by the CAIF SPI interface when the output
+ (SPI_INT) GPIO needs to change state. The boolean value of the xfer
+ variable indicates whether the GPIO should be asserted (HIGH) or
+ deasserted (LOW). The dev parameter can be used to map to different CAIF
+ SPI slave devices.
+
+ - Functionality provided by the CAIF SPI interface:
+
+ void (*ss_cb) (bool assert, struct cfspi_ifc *ifc);
+
+ This function is called by the CAIF SPI slave device in order to
+ signal a change of state of the input GPIO (SS) to the interface.
+ Only active edges are mandatory to be reported.
+ This function can be called from IRQ context (recommended in order
+ not to introduce latency). The ifc parameter should be the pointer
+ returned from the platform probe function in the SPI device structure.
+
+ void (*xfer_done_cb) (struct cfspi_ifc *ifc);
+
+ This function is called by the CAIF SPI slave device in order to
+ report that a transfer is completed. This function should only be
+ called once both the transmission and the reception are completed.
+ This function can be called from IRQ context (recommended in order
+ not to introduce latency). The ifc parameter should be the pointer
+ returned from the platform probe function in the SPI device structure.
+
+ - Connecting the bits and pieces:
+
+ - Filling in the SPI slave device structure:
+
+ Connect the necessary callback functions.
+ Indicate clock speed (used to calculate toggle delays).
+ Chose a suitable name (helps debugging if you use several CAIF
+ SPI slave devices).
+ Assign your private data (can be used to map to your structure).
+
+ - Filling in the SPI slave platform device structure:
+ Add name of driver to connect to ("cfspi_sspi").
+ Assign the SPI slave device structure as platform data.
+
+- Padding:
+
+In order to optimize throughput, a number of SPI padding options are provided.
+Padding can be enabled independently for uplink and downlink transfers.
+Padding can be enabled for the head, the tail and for the total frame size.
+The padding needs to be correctly configured on both sides of the link.
+The padding can be changed via module parameters in cfspi_sspi.c or via
+the sysfs directory of the cfspi_sspi driver (before device registration).
+
+- CAIF SPI device template:
+
+/*
+ * Copyright (C) ST-Ericsson AB 2010
+ * Author: Daniel Martensson / Daniel.Martensson@stericsson.com
+ * License terms: GNU General Public License (GPL), version 2.
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/wait.h>
+#include <linux/interrupt.h>
+#include <linux/dma-mapping.h>
+#include <net/caif/caif_spi.h>
+
+MODULE_LICENSE("GPL");
+
+struct sspi_struct {
+ struct cfspi_dev sdev;
+ struct cfspi_xfer *xfer;
+};
+
+static struct sspi_struct slave;
+static struct platform_device slave_device;
+
+static irqreturn_t sspi_irq(int irq, void *arg)
+{
+ /* You only need to trigger on an edge to the active state of the
+ * SS signal. Once a edge is detected, the ss_cb() function should be
+ * called with the parameter assert set to true. It is OK
+ * (and even advised) to call the ss_cb() function in IRQ context in
+ * order not to add any delay. */
+
+ return IRQ_HANDLED;
+}
+
+static void sspi_complete(void *context)
+{
+ /* Normally the DMA or the SPI framework will call you back
+ * in something similar to this. The only thing you need to
+ * do is to call the xfer_done_cb() function, providing the pointer
+ * to the CAIF SPI interface. It is OK to call this function
+ * from IRQ context. */
+}
+
+static int sspi_init_xfer(struct cfspi_xfer *xfer, struct cfspi_dev *dev)
+{
+ /* Store transfer info. For a normal implementation you should
+ * set up your DMA here and make sure that you are ready to
+ * receive the data from the master SPI. */
+
+ struct sspi_struct *sspi = (struct sspi_struct *)dev->priv;
+
+ sspi->xfer = xfer;
+
+ return 0;
+}
+
+void sspi_sig_xfer(bool xfer, struct cfspi_dev *dev)
+{
+ /* If xfer is true then you should assert the SPI_INT to indicate to
+ * the master that you are ready to recieve the data from the master
+ * SPI. If xfer is false then you should de-assert SPI_INT to indicate
+ * that the transfer is done.
+ */
+
+ struct sspi_struct *sspi = (struct sspi_struct *)dev->priv;
+}
+
+static void sspi_release(struct device *dev)
+{
+ /*
+ * Here you should release your SPI device resources.
+ */
+}
+
+static int __init sspi_init(void)
+{
+ /* Here you should initialize your SPI device by providing the
+ * necessary functions, clock speed, name and private data. Once
+ * done, you can register your device with the
+ * platform_device_register() function. This function will return
+ * with the CAIF SPI interface initialized. This is probably also
+ * the place where you should set up your GPIOs, interrupts and SPI
+ * resources. */
+
+ int res = 0;
+
+ /* Initialize slave device. */
+ slave.sdev.init_xfer = sspi_init_xfer;
+ slave.sdev.sig_xfer = sspi_sig_xfer;
+ slave.sdev.clk_mhz = 13;
+ slave.sdev.priv = &slave;
+ slave.sdev.name = "spi_sspi";
+ slave_device.dev.release = sspi_release;
+
+ /* Initialize platform device. */
+ slave_device.name = "cfspi_sspi";
+ slave_device.dev.platform_data = &slave.sdev;
+
+ /* Register platform device. */
+ res = platform_device_register(&slave_device);
+ if (res) {
+ printk(KERN_WARNING "sspi_init: failed to register dev.\n");
+ return -ENODEV;
+ }
+
+ return res;
+}
+
+static void __exit sspi_exit(void)
+{
+ platform_device_del(&slave_device);
+}
+
+module_init(sspi_init);
+module_exit(sspi_exit);
diff --git a/Documentation/networking/decnet.txt b/Documentation/networking/decnet.txt
index d8968958d83..e12a4900cf7 100644
--- a/Documentation/networking/decnet.txt
+++ b/Documentation/networking/decnet.txt
@@ -4,7 +4,7 @@
1) Other documentation....
o Project Home Pages
- http://www.chygwyn.com/DECnet/ - Kernel info
+ http://www.chygwyn.com/ - Kernel info
http://linux-decnet.sourceforge.net/ - Userland tools
http://www.sourceforge.net/projects/linux-decnet/ - Status page
diff --git a/Documentation/networking/dns_resolver.txt b/Documentation/networking/dns_resolver.txt
new file mode 100644
index 00000000000..aefd1e68180
--- /dev/null
+++ b/Documentation/networking/dns_resolver.txt
@@ -0,0 +1,146 @@
+ ===================
+ DNS Resolver Module
+ ===================
+
+Contents:
+
+ - Overview.
+ - Compilation.
+ - Setting up.
+ - Usage.
+ - Mechanism.
+ - Debugging.
+
+
+========
+OVERVIEW
+========
+
+The DNS resolver module provides a way for kernel services to make DNS queries
+by way of requesting a key of key type dns_resolver. These queries are
+upcalled to userspace through /sbin/request-key.
+
+These routines must be supported by userspace tools dns.upcall, cifs.upcall and
+request-key. It is under development and does not yet provide the full feature
+set. The features it does support include:
+
+ (*) Implements the dns_resolver key_type to contact userspace.
+
+It does not yet support the following AFS features:
+
+ (*) Dns query support for AFSDB resource record.
+
+This code is extracted from the CIFS filesystem.
+
+
+===========
+COMPILATION
+===========
+
+The module should be enabled by turning on the kernel configuration options:
+
+ CONFIG_DNS_RESOLVER - tristate "DNS Resolver support"
+
+
+==========
+SETTING UP
+==========
+
+To set up this facility, the /etc/request-key.conf file must be altered so that
+/sbin/request-key can appropriately direct the upcalls. For example, to handle
+basic dname to IPv4/IPv6 address resolution, the following line should be
+added:
+
+ #OP TYPE DESC CO-INFO PROGRAM ARG1 ARG2 ARG3 ...
+ #====== ============ ======= ======= ==========================
+ create dns_resolver * * /usr/sbin/cifs.upcall %k
+
+To direct a query for query type 'foo', a line of the following should be added
+before the more general line given above as the first match is the one taken.
+
+ create dns_resolver foo:* * /usr/sbin/dns.foo %k
+
+
+
+=====
+USAGE
+=====
+
+To make use of this facility, one of the following functions that are
+implemented in the module can be called after doing:
+
+ #include <linux/dns_resolver.h>
+
+ (1) int dns_query(const char *type, const char *name, size_t namelen,
+ const char *options, char **_result, time_t *_expiry);
+
+ This is the basic access function. It looks for a cached DNS query and if
+ it doesn't find it, it upcalls to userspace to make a new DNS query, which
+ may then be cached. The key description is constructed as a string of the
+ form:
+
+ [<type>:]<name>
+
+ where <type> optionally specifies the particular upcall program to invoke,
+ and thus the type of query to do, and <name> specifies the string to be
+ looked up. The default query type is a straight hostname to IP address
+ set lookup.
+
+ The name parameter is not required to be a NUL-terminated string, and its
+ length should be given by the namelen argument.
+
+ The options parameter may be NULL or it may be a set of options
+ appropriate to the query type.
+
+ The return value is a string appropriate to the query type. For instance,
+ for the default query type it is just a list of comma-separated IPv4 and
+ IPv6 addresses. The caller must free the result.
+
+ The length of the result string is returned on success, and a negative
+ error code is returned otherwise. -EKEYREJECTED will be returned if the
+ DNS lookup failed.
+
+ If _expiry is non-NULL, the expiry time (TTL) of the result will be
+ returned also.
+
+
+=========
+MECHANISM
+=========
+
+The dnsresolver module registers a key type called "dns_resolver". Keys of
+this type are used to transport and cache DNS lookup results from userspace.
+
+When dns_query() is invoked, it calls request_key() to search the local
+keyrings for a cached DNS result. If that fails to find one, it upcalls to
+userspace to get a new result.
+
+Upcalls to userspace are made through the request_key() upcall vector, and are
+directed by means of configuration lines in /etc/request-key.conf that tell
+/sbin/request-key what program to run to instantiate the key.
+
+The upcall handler program is responsible for querying the DNS, processing the
+result into a form suitable for passing to the keyctl_instantiate_key()
+routine. This then passes the data to dns_resolver_instantiate() which strips
+off and processes any options included in the data, and then attaches the
+remainder of the string to the key as its payload.
+
+The upcall handler program should set the expiry time on the key to that of the
+lowest TTL of all the records it has extracted a result from. This means that
+the key will be discarded and recreated when the data it holds has expired.
+
+dns_query() returns a copy of the value attached to the key, or an error if
+that is indicated instead.
+
+See <file:Documentation/keys-request-key.txt> for further information about
+request-key function.
+
+
+=========
+DEBUGGING
+=========
+
+Debugging messages can be turned on dynamically by writing a 1 into the
+following file:
+
+ /sys/module/dnsresolver/parameters/debug
diff --git a/Documentation/networking/fore200e.txt b/Documentation/networking/fore200e.txt
index b1f337f0f4c..6e0d2a9613e 100644
--- a/Documentation/networking/fore200e.txt
+++ b/Documentation/networking/fore200e.txt
@@ -39,7 +39,7 @@ version. Alternative binary firmware images can be found somewhere on the
ForeThought CD-ROM supplied with your adapter by FORE Systems.
You can also get the latest firmware images from FORE Systems at
-http://www.fore.com. Register TACTics Online and go to
+http://en.wikipedia.org/wiki/FORE_Systems. Register TACTics Online and go to
the 'software updates' pages. The firmware binaries are part of
the various ForeThought software distributions.
diff --git a/Documentation/networking/ip-sysctl.txt b/Documentation/networking/ip-sysctl.txt
index d0536b5a4e0..f350c69b2bb 100644
--- a/Documentation/networking/ip-sysctl.txt
+++ b/Documentation/networking/ip-sysctl.txt
@@ -903,7 +903,7 @@ arp_ignore - INTEGER
arp_notify - BOOLEAN
Define mode for notification of address and device changes.
0 - (default): do nothing
- 1 - Generate gratuitous arp replies when device is brought up
+ 1 - Generate gratuitous arp requests when device is brought up
or hardware address changes.
arp_accept - BOOLEAN
diff --git a/Documentation/networking/ipddp.txt b/Documentation/networking/ipddp.txt
index 661a5558dd8..ba5c217fffe 100644
--- a/Documentation/networking/ipddp.txt
+++ b/Documentation/networking/ipddp.txt
@@ -36,11 +36,6 @@ AppleTalk-IP to IP decapsulation.
Basic instructions for user space tools
=======================================
-To enable AppleTalk-IP decapsulation/encapsulation you will need the
-proper tools. You can get the tools for decapsulation from
-http://spacs1.spacs.k12.wi.us/~jschlst/index.html and for encapsulation
-from http://www.maths.unm.edu/~bradford/ltpc.html
-
I will briefly describe the operation of the tools, but you will
need to consult the supporting documentation for each set of tools.
diff --git a/Documentation/networking/iphase.txt b/Documentation/networking/iphase.txt
index 55eac4a784e..670b72f1658 100644
--- a/Documentation/networking/iphase.txt
+++ b/Documentation/networking/iphase.txt
@@ -22,7 +22,7 @@ The features and limitations of this driver are as follows:
- All variants of Interphase ATM PCI (i)Chip adapter cards are supported,
including x575 (OC3, control memory 128K , 512K and packet memory 128K,
512K and 1M), x525 (UTP25) and x531 (DS3 and E3). See
- http://www.iphase.com/site/iphase-web/?epi_menuItemID=e196f04b4b3b40502f150882e21046a0
+ http://www.iphase.com/
for details.
- Only x86 platforms are supported.
- SMP is supported.
diff --git a/Documentation/networking/packet_mmap.txt b/Documentation/networking/packet_mmap.txt
index 98f71a5cef0..073894d1c09 100644
--- a/Documentation/networking/packet_mmap.txt
+++ b/Documentation/networking/packet_mmap.txt
@@ -8,7 +8,7 @@ capture network traffic with utilities like tcpdump or any other that needs
raw access to network interface.
You can find the latest version of this document at:
- http://pusa.uv.es/~ulisses/packet_mmap/
+ http://wiki.ipxwarzone.com/index.php5?title=Linux_packet_mmap
Howto can be found at:
http://wiki.gnu-log.net (packet_mmap)
@@ -56,7 +56,7 @@ support for PACKET_MMAP, and also probably the libpcap included in your distribu
I'm aware of two implementations of PACKET_MMAP in libpcap:
- http://pusa.uv.es/~ulisses/packet_mmap/ (by Simon Patarin, based on libpcap 0.6.2)
+ http://wiki.ipxwarzone.com/ (by Simon Patarin, based on libpcap 0.6.2)
http://public.lanl.gov/cpw/ (by Phil Wood, based on lastest libpcap)
The rest of this document is intended for people who want to understand
@@ -493,6 +493,32 @@ The user can also use poll() to check if a buffer is available:
pfd.events = POLLOUT;
retval = poll(&pfd, 1, timeout);
+-------------------------------------------------------------------------------
++ PACKET_TIMESTAMP
+-------------------------------------------------------------------------------
+
+The PACKET_TIMESTAMP setting determines the source of the timestamp in
+the packet meta information. If your NIC is capable of timestamping
+packets in hardware, you can request those hardware timestamps to used.
+Note: you may need to enable the generation of hardware timestamps with
+SIOCSHWTSTAMP.
+
+PACKET_TIMESTAMP accepts the same integer bit field as
+SO_TIMESTAMPING. However, only the SOF_TIMESTAMPING_SYS_HARDWARE
+and SOF_TIMESTAMPING_RAW_HARDWARE values are recognized by
+PACKET_TIMESTAMP. SOF_TIMESTAMPING_SYS_HARDWARE takes precedence over
+SOF_TIMESTAMPING_RAW_HARDWARE if both bits are set.
+
+ int req = 0;
+ req |= SOF_TIMESTAMPING_SYS_HARDWARE;
+ setsockopt(fd, SOL_PACKET, PACKET_TIMESTAMP, (void *) &req, sizeof(req))
+
+If PACKET_TIMESTAMP is not set, a software timestamp generated inside
+the networking stack is used (the behavior before this setting was added).
+
+See include/linux/net_tstamp.h and Documentation/networking/timestamping
+for more information on hardware timestamps.
+
--------------------------------------------------------------------------------
+ THANKS
--------------------------------------------------------------------------------
diff --git a/Documentation/networking/pktgen.txt b/Documentation/networking/pktgen.txt
index 61bb645d50e..75e4fd708cc 100644
--- a/Documentation/networking/pktgen.txt
+++ b/Documentation/networking/pktgen.txt
@@ -151,6 +151,8 @@ Examples:
pgset stop aborts injection. Also, ^C aborts generator.
+ pgset "rate 300M" set rate to 300 Mb/s
+ pgset "ratep 1000000" set rate to 1Mpps
Example scripts
===============
@@ -241,6 +243,9 @@ src6
flows
flowlen
+rate
+ratep
+
References:
ftp://robur.slu.se/pub/Linux/net-development/pktgen-testing/
ftp://robur.slu.se/pub/Linux/net-development/pktgen-testing/examples/
diff --git a/Documentation/networking/ray_cs.txt b/Documentation/networking/ray_cs.txt
index 145d27a5239..c0c12307ed9 100644
--- a/Documentation/networking/ray_cs.txt
+++ b/Documentation/networking/ray_cs.txt
@@ -13,8 +13,8 @@ wireless LAN cards.
As of kernel 2.3.18, the ray_cs driver is part of the Linux kernel
source. My web page for the development of ray_cs is at
-http://world.std.com/~corey/raylink.html and I can be emailed at
-corey@world.std.com
+http://web.ralinktech.com/ralink/Home/Support/Linux.html
+and I can be emailed at corey@world.std.com
The kernel driver is based on ray_cs-1.62.tgz
diff --git a/Documentation/networking/s2io.txt b/Documentation/networking/s2io.txt
index c3d6b4d5d01..9d4e0f4df5a 100644
--- a/Documentation/networking/s2io.txt
+++ b/Documentation/networking/s2io.txt
@@ -133,7 +133,8 @@ bring down CPU utilization.
** For AMD opteron platforms with 8131 chipset, MMRBC=1 and MOST=1 are
recommended as safe parameters.
For more information, please review the AMD8131 errata at
-http://www.amd.com/us-en/assets/content_type/white_papers_and_tech_docs/26310.pdf
+http://vip.amd.com/us-en/assets/content_type/white_papers_and_tech_docs/
+26310_AMD-8131_HyperTransport_PCI-X_Tunnel_Revision_Guide_rev_3_18.pdf
6. Available Downloads
Neterion "s2io" driver in Red Hat and Suse 2.6-based distributions is kept up
diff --git a/Documentation/networking/tlan.txt b/Documentation/networking/tlan.txt
index 7e6aa5b20c3..34550dfcef7 100644
--- a/Documentation/networking/tlan.txt
+++ b/Documentation/networking/tlan.txt
@@ -2,7 +2,7 @@
(C) 1998 James Banks
(C) 1999-2001 Torben Mathiasen <tmm@image.dk, torben.mathiasen@compaq.com>
-For driver information/updates visit http://opensource.compaq.com
+For driver information/updates visit http://www.compaq.com
TLAN driver for Linux, version 1.14a
@@ -113,5 +113,5 @@ III. Things to try if you have problems.
There is also a tlan mailing list which you can join by sending "subscribe tlan"
in the body of an email to majordomo@vuser.vu.union.edu.
-There is also a tlan website at http://opensource.compaq.com
+There is also a tlan website at http://www.compaq.com
diff --git a/Documentation/networking/udplite.txt b/Documentation/networking/udplite.txt
index 855d8da57a2..d727a382910 100644
--- a/Documentation/networking/udplite.txt
+++ b/Documentation/networking/udplite.txt
@@ -11,11 +11,13 @@
This file briefly describes the existing kernel support and the socket API.
For in-depth information, you can consult:
- o The UDP-Lite Homepage: http://www.erg.abdn.ac.uk/users/gerrit/udp-lite/
+ o The UDP-Lite Homepage:
+ http://web.archive.org/web/*/http://www.erg.abdn.ac.uk/users/gerrit/udp-lite/
From here you can also download some example application source code.
o The UDP-Lite HOWTO on
- http://www.erg.abdn.ac.uk/users/gerrit/udp-lite/files/UDP-Lite-HOWTO.txt
+ http://web.archive.org/web/*/http://www.erg.abdn.ac.uk/users/gerrit/udp-lite/
+ files/UDP-Lite-HOWTO.txt
o The Wireshark UDP-Lite WiKi (with capture files):
http://wiki.wireshark.org/Lightweight_User_Datagram_Protocol
@@ -26,12 +28,7 @@
I) APPLICATIONS
Several applications have been ported successfully to UDP-Lite. Ethereal
- (now called wireshark) has UDP-Litev4/v6 support by default. The tarball on
-
- http://www.erg.abdn.ac.uk/users/gerrit/udp-lite/files/udplite_linux.tar.gz
-
- has source code for several v4/v6 client-server and network testing examples.
-
+ (now called wireshark) has UDP-Litev4/v6 support by default.
Porting applications to UDP-Lite is straightforward: only socket level and
IPPROTO need to be changed; senders additionally set the checksum coverage
length (default = header length = 8). Details are in the next section.
diff --git a/Documentation/networking/wavelan.txt b/Documentation/networking/wavelan.txt
index afa6e521c68..90e0ac4e15d 100644
--- a/Documentation/networking/wavelan.txt
+++ b/Documentation/networking/wavelan.txt
@@ -50,7 +50,8 @@ and a Lucent Modem, and NOT 802.11 compatible.
-----------------
o Config : Not yet in kernel
o Location : Pcmcia package 3.1.10+
- o on-line doc : http://www.fasta.fh-dortmund.de/users/andy/wvlan/
+ o on-line doc :
+ http://web.archive.org/web/*/http://www.fasta.fh-dortmund.de/users/andy/wvlan/
This is the driver for the current generation of Wavelan IEEE,
which is 802.11 compatible. Depending on version, it is 2 Mb/s or 11
diff --git a/Documentation/padata.txt b/Documentation/padata.txt
index 269d7d0d833..473ebf22cd6 100644
--- a/Documentation/padata.txt
+++ b/Documentation/padata.txt
@@ -1,5 +1,5 @@
The padata parallel execution mechanism
-Last updated for 2.6.34
+Last updated for 2.6.36
Padata is a mechanism by which the kernel can farm work out to be done in
parallel on multiple CPUs while retaining the ordering of tasks. It was
@@ -13,31 +13,86 @@ overall control of how tasks are to be run:
#include <linux/padata.h>
- struct padata_instance *padata_alloc(const struct cpumask *cpumask,
- struct workqueue_struct *wq);
+ struct padata_instance *padata_alloc(struct workqueue_struct *wq,
+ const struct cpumask *pcpumask,
+ const struct cpumask *cbcpumask);
-The cpumask describes which processors will be used to execute work
-submitted to this instance. The workqueue wq is where the work will
-actually be done; it should be a multithreaded queue, naturally.
+The pcpumask describes which processors will be used to execute work
+submitted to this instance in parallel. The cbcpumask defines which
+processors are allowed to use as the serialization callback processor.
+The workqueue wq is where the work will actually be done; it should be
+a multithreaded queue, naturally.
+
+To allocate a padata instance with the cpu_possible_mask for both
+cpumasks this helper function can be used:
+
+ struct padata_instance *padata_alloc_possible(struct workqueue_struct *wq);
+
+Note: Padata maintains two kinds of cpumasks internally. The user supplied
+cpumasks, submitted by padata_alloc/padata_alloc_possible and the 'usable'
+cpumasks. The usable cpumasks are always the subset of active cpus in the
+user supplied cpumasks, these are the cpumasks padata actually use. So
+it is legal to supply a cpumask to padata that contains offline cpus.
+Once a offline cpu in the user supplied cpumask comes online, padata
+is going to use it.
There are functions for enabling and disabling the instance:
- void padata_start(struct padata_instance *pinst);
+ int padata_start(struct padata_instance *pinst);
void padata_stop(struct padata_instance *pinst);
-These functions literally do nothing beyond setting or clearing the
-"padata_start() was called" flag; if that flag is not set, other functions
-will refuse to work.
+These functions are setting or clearing the "PADATA_INIT" flag;
+if that flag is not set, other functions will refuse to work.
+padata_start returns zero on success (flag set) or -EINVAL if the
+padata cpumask contains no active cpu (flag not set).
+padata_stop clears the flag and blocks until the padata instance
+is unused.
The list of CPUs to be used can be adjusted with these functions:
- int padata_set_cpumask(struct padata_instance *pinst,
+ int padata_set_cpumasks(struct padata_instance *pinst,
+ cpumask_var_t pcpumask,
+ cpumask_var_t cbcpumask);
+ int padata_set_cpumask(struct padata_instance *pinst, int cpumask_type,
cpumask_var_t cpumask);
- int padata_add_cpu(struct padata_instance *pinst, int cpu);
- int padata_remove_cpu(struct padata_instance *pinst, int cpu);
+ int padata_add_cpu(struct padata_instance *pinst, int cpu, int mask);
+ int padata_remove_cpu(struct padata_instance *pinst, int cpu, int mask);
+
+Changing the CPU masks are expensive operations, though, so it should not be
+done with great frequency.
+
+It's possible to change both cpumasks of a padata instance with
+padata_set_cpumasks by specifying the cpumasks for parallel execution (pcpumask)
+and for the serial callback function (cbcpumask). padata_set_cpumask is to
+change just one of the cpumasks. Here cpumask_type is one of PADATA_CPU_SERIAL,
+PADATA_CPU_PARALLEL and cpumask specifies the new cpumask to use.
+To simply add or remove one cpu from a certain cpumask the functions
+padata_add_cpu/padata_remove_cpu are used. cpu specifies the cpu to add or
+remove and mask is one of PADATA_CPU_SERIAL, PADATA_CPU_PARALLEL.
+
+If a user is interested in padata cpumask changes, he can register to
+the padata cpumask change notifier:
+
+ int padata_register_cpumask_notifier(struct padata_instance *pinst,
+ struct notifier_block *nblock);
+
+To unregister from that notifier:
+
+ int padata_unregister_cpumask_notifier(struct padata_instance *pinst,
+ struct notifier_block *nblock);
+
+The padata cpumask change notifier notifies about changes of the usable
+cpumasks, i.e. the subset of active cpus in the user supplied cpumask.
+
+Padata calls the notifier chain with:
+
+ blocking_notifier_call_chain(&pinst->cpumask_change_notifier,
+ notification_mask,
+ &pd_new->cpumask);
-Changing the CPU mask has the look of an expensive operation, though, so it
-probably should not be done with great frequency.
+Here cpumask_change_notifier is registered notifier, notification_mask
+is one of PADATA_CPU_SERIAL, PADATA_CPU_PARALLEL and cpumask is a pointer
+to a struct padata_cpumask that contains the new cpumask informations.
Actually submitting work to the padata instance requires the creation of a
padata_priv structure:
@@ -50,7 +105,7 @@ padata_priv structure:
This structure will almost certainly be embedded within some larger
structure specific to the work to be done. Most its fields are private to
-padata, but the structure should be zeroed at initialization time, and the
+padata, but the structure should be zeroed at initialisation time, and the
parallel() and serial() functions should be provided. Those functions will
be called in the process of getting the work done as we will see
momentarily.
@@ -63,12 +118,10 @@ The submission of work is done with:
The pinst and padata structures must be set up as described above; cb_cpu
specifies which CPU will be used for the final callback when the work is
done; it must be in the current instance's CPU mask. The return value from
-padata_do_parallel() is a little strange; zero is an error return
-indicating that the caller forgot the padata_start() formalities. -EBUSY
-means that somebody, somewhere else is messing with the instance's CPU
-mask, while -EINVAL is a complaint about cb_cpu not being in that CPU mask.
-If all goes well, this function will return -EINPROGRESS, indicating that
-the work is in progress.
+padata_do_parallel() is zero on success, indicating that the work is in
+progress. -EBUSY means that somebody, somewhere else is messing with the
+instance's CPU mask, while -EINVAL is a complaint about cb_cpu not being
+in that CPU mask or about a not running instance.
Each task submitted to padata_do_parallel() will, in turn, be passed to
exactly one call to the above-mentioned parallel() function, on one CPU, so
diff --git a/Documentation/pcmcia/driver-changes.txt b/Documentation/pcmcia/driver-changes.txt
index 61bc4e94311..26c0f9c0054 100644
--- a/Documentation/pcmcia/driver-changes.txt
+++ b/Documentation/pcmcia/driver-changes.txt
@@ -1,4 +1,16 @@
This file details changes in 2.6 which affect PCMCIA card driver authors:
+* pcmcia_request_io changes (as of 2.6.36)
+ Instead of io_req_t, drivers are now requested to fill out
+ struct pcmcia_device *p_dev->resource[0,1] for up to two ioport
+ ranges. After a call to pcmcia_request_io(), the ports found there
+ are reserved, after calling pcmcia_request_configuration(), they may
+ be used.
+
+* No dev_info_t, no cs_types.h (as of 2.6.36)
+ dev_info_t and a few other typedefs are removed. No longer use them
+ in PCMCIA device drivers. Also, do not include pcmcia/cs_types.h, as
+ this file is gone.
+
* No dev_node_t (as of 2.6.35)
There is no more need to fill out a "dev_node_t" structure.
diff --git a/Documentation/power/apm-acpi.txt b/Documentation/power/apm-acpi.txt
index 1bd799dc17e..6cc423d3662 100644
--- a/Documentation/power/apm-acpi.txt
+++ b/Documentation/power/apm-acpi.txt
@@ -28,5 +28,5 @@ and be sure that they are started sometime in the system boot process.
Go ahead and start both. If ACPI or APM is not available on your
system the associated daemon will exit gracefully.
- apmd: http://worldvisions.ca/~apenwarr/apmd/
+ apmd: http://ftp.debian.org/pool/main/a/apmd/
acpid: http://acpid.sf.net/
diff --git a/Documentation/power/basic-pm-debugging.txt b/Documentation/power/basic-pm-debugging.txt
index 1555001bc73..ddd78172ef7 100644
--- a/Documentation/power/basic-pm-debugging.txt
+++ b/Documentation/power/basic-pm-debugging.txt
@@ -179,8 +179,7 @@ use the PM_TRACE mechanism documented in Documentation/s2ram.txt .
To verify that the STR works, it is generally more convenient to use the s2ram
tool available from http://suspend.sf.net and documented at
-http://en.opensuse.org/s2ram . However, before doing that it is recommended to
-carry out STR testing using the facility described in section 1.
+http://en.opensuse.org/SDB:Suspend_to_RAM.
Namely, after writing "freezer", "devices", "platform", "processors", or "core"
into /sys/power/pm_test (available if the kernel is compiled with
diff --git a/Documentation/power/tricks.txt b/Documentation/power/tricks.txt
index 3b26bb502a4..a1b8f7249f4 100644
--- a/Documentation/power/tricks.txt
+++ b/Documentation/power/tricks.txt
@@ -1,6 +1,6 @@
swsusp/S3 tricks
~~~~~~~~~~~~~~~~
-Pavel Machek <pavel@suse.cz>
+Pavel Machek <pavel@ucw.cz>
If you want to trick swsusp/S3 into working, you might want to try:
diff --git a/Documentation/power/video.txt b/Documentation/power/video.txt
index 2b358498d09..3e6272bc447 100644
--- a/Documentation/power/video.txt
+++ b/Documentation/power/video.txt
@@ -67,11 +67,11 @@ There are a few types of systems where video works after S3 resume:
POSTing bios works. Ole Rohne has patch to do just that at
http://dev.gentoo.org/~marineam/patch-radeonfb-2.6.11-rc2-mm2.
-(8) on some systems, you can use the video_post utility mentioned here:
- http://bugzilla.kernel.org/show_bug.cgi?id=3670. Do echo 3 > /sys/power/state
- && /usr/sbin/video_post - which will initialize the display in console mode.
- If you are in X, you can switch to a virtual terminal and back to X using
- CTRL+ALT+F1 - CTRL+ALT+F7 to get the display working in graphical mode again.
+(8) on some systems, you can use the video_post utility and or
+ do echo 3 > /sys/power/state && /usr/sbin/video_post - which will
+ initialize the display in console mode. If you are in X, you can switch
+ to a virtual terminal and back to X using CTRL+ALT+F1 - CTRL+ALT+F7 to get
+ the display working in graphical mode again.
Now, if you pass acpi_sleep=something, and it does not work with your
bios, you'll get a hard crash during resume. Be careful. Also it is
@@ -177,7 +177,7 @@ Mainboard Graphics card hack (or "how to do it")
Asus A7V8X nVidia RIVA TNT2 model 64 s3_bios,s3_mode (4)
-(*) from http://www.ubuntulinux.org/wiki/HoaryPMResults, not sure
+(*) from https://wiki.ubuntu.com/HoaryPMResults, not sure
which options to use. If you know, please tell me.
(***) To be tested with a newer kernel.
diff --git a/Documentation/powerpc/booting-without-of.txt b/Documentation/powerpc/booting-without-of.txt
index 46d22105aa0..568fa08e82e 100644
--- a/Documentation/powerpc/booting-without-of.txt
+++ b/Documentation/powerpc/booting-without-of.txt
@@ -1048,7 +1048,7 @@ IV - "dtc", the device tree compiler
dtc source code can be found at
-<http://ozlabs.org/~dgibson/dtc/dtc.tar.gz>
+<http://git.jdl.com/gitweb/?p=dtc.git>
WARNING: This version is still in early development stage; the
resulting device-tree "blobs" have not yet been validated with the
diff --git a/Documentation/powerpc/dts-bindings/fsl/diu.txt b/Documentation/powerpc/dts-bindings/fsl/diu.txt
index deb35de7098..b66cb6d31d6 100644
--- a/Documentation/powerpc/dts-bindings/fsl/diu.txt
+++ b/Documentation/powerpc/dts-bindings/fsl/diu.txt
@@ -4,10 +4,17 @@ The Freescale DIU is a LCD controller, with proper hardware, it can also
drive DVI monitors.
Required properties:
-- compatible : should be "fsl-diu".
+- compatible : should be "fsl,diu" or "fsl,mpc5121-diu".
- reg : should contain at least address and length of the DIU register
set.
-- Interrupts : one DIU interrupt should be describe here.
+- interrupts : one DIU interrupt should be described here.
+- interrupt-parent : the phandle for the interrupt controller that
+ services interrupts for this device.
+
+Optional properties:
+- edid : verbatim EDID data block describing attached display.
+ Data from the detailed timing descriptor will be used to
+ program the display controller.
Example (MPC8610HPCD):
display@2c000 {
@@ -16,3 +23,12 @@ Example (MPC8610HPCD):
interrupts = <72 2>;
interrupt-parent = <&mpic>;
};
+
+Example for MPC5121:
+ display@2100 {
+ compatible = "fsl,mpc5121-diu";
+ reg = <0x2100 0x100>;
+ interrupts = <64 0x8>;
+ interrupt-parent = <&ipic>;
+ edid = [edid-data];
+ };
diff --git a/Documentation/powerpc/dts-bindings/fsl/i2c.txt b/Documentation/powerpc/dts-bindings/fsl/i2c.txt
index 50da2031058..1eacd6b20ed 100644
--- a/Documentation/powerpc/dts-bindings/fsl/i2c.txt
+++ b/Documentation/powerpc/dts-bindings/fsl/i2c.txt
@@ -20,6 +20,7 @@ Recommended properties :
- fsl,preserve-clocking : boolean; if defined, the clock settings
from the bootloader are preserved (not touched).
- clock-frequency : desired I2C bus clock frequency in Hz.
+ - fsl,timeout : I2C bus timeout in microseconds.
Examples :
@@ -59,4 +60,5 @@ Examples :
interrupts = <43 2>;
interrupt-parent = <&mpic>;
clock-frequency = <400000>;
+ fsl,timeout = <10000>;
};
diff --git a/Documentation/rt-mutex-design.txt b/Documentation/rt-mutex-design.txt
index 8df0b782c4d..33ed8007a84 100644
--- a/Documentation/rt-mutex-design.txt
+++ b/Documentation/rt-mutex-design.txt
@@ -364,7 +364,7 @@ process this is rather easy to know what needs to be adjusted.
The functions implementing the task adjustments are rt_mutex_adjust_prio,
__rt_mutex_adjust_prio (same as the former, but expects the task pi_lock
-to already be taken), rt_mutex_get_prio, and rt_mutex_setprio.
+to already be taken), rt_mutex_getprio, and rt_mutex_setprio.
rt_mutex_getprio and rt_mutex_setprio are only used in __rt_mutex_adjust_prio.
diff --git a/Documentation/s390/Debugging390.txt b/Documentation/s390/Debugging390.txt
index 1eb576a023b..86f9f74b2b3 100644
--- a/Documentation/s390/Debugging390.txt
+++ b/Documentation/s390/Debugging390.txt
@@ -2531,5 +2531,5 @@ Special Thanks
==============
Special thanks to Neale Ferguson who maintains a much
prettier HTML version of this page at
-http://penguinvm.princeton.edu/notes.html#Debug390
+http://linuxvm.org/penguinvm/
Bob Grainger Stefan Bader & others for reporting bugs
diff --git a/Documentation/scsi/BusLogic.txt b/Documentation/scsi/BusLogic.txt
index 98023baa0f0..d7fbc9488b9 100644
--- a/Documentation/scsi/BusLogic.txt
+++ b/Documentation/scsi/BusLogic.txt
@@ -47,7 +47,7 @@ tune driver performance and error recovery to their particular needs.
The latest information on Linux support for BusLogic SCSI Host Adapters, as
well as the most recent release of this driver and the latest firmware for the
BT-948/958/958D, will always be available from my Linux Home Page at URL
-"http://www.dandelion.com/Linux/".
+"http://sourceforge.net/projects/dandelion/".
Bug reports should be sent via electronic mail to "lnz@dandelion.com". Please
include with the bug report the complete configuration messages reported by the
diff --git a/Documentation/scsi/ChangeLog.lpfc b/Documentation/scsi/ChangeLog.lpfc
index e759e92e286..337c924cc81 100644
--- a/Documentation/scsi/ChangeLog.lpfc
+++ b/Documentation/scsi/ChangeLog.lpfc
@@ -807,7 +807,7 @@ Changes from 20040908 to 20040920
lpfc_disc_done/lpfc_do_dpc cleanup - lpfc_disc_done can return
void - move lpfc_do_dpc and lpfc_disc_done to lpfc_hbadisc.c -
remove checking of list emptiness before calling lpfc_disc_done,
- it handles the emtpy list case just fine and the additional
+ it handles the empty list case just fine and the additional
instructions cost less then the bustlocked spinlock operations.
* Integrated patch from Christoph Hellwig: This adds a new 64bit
counter instead, brd_no isn't reused anymore. Also some tiny
diff --git a/Documentation/scsi/ChangeLog.megaraid b/Documentation/scsi/ChangeLog.megaraid
index 38e9e7cadc9..5e07d320817 100644
--- a/Documentation/scsi/ChangeLog.megaraid
+++ b/Documentation/scsi/ChangeLog.megaraid
@@ -215,7 +215,7 @@ Older Version : 2.20.4.5 (scsi module), 2.20.2.5 (cmm module)
3. Convert pci_module_init to pci_register_driver
Convert from pci_module_init to pci_register_driver
- (from:http://kerneljanitors.org/TODO)
+ (from:http://kernelnewbies.org/KernelJanitors/TODO)
- Signed-off-by: Domen Puncer <domen@coderock.org>
4. Use the pre defined DMA mask constants from dma-mapping.h
diff --git a/Documentation/scsi/FlashPoint.txt b/Documentation/scsi/FlashPoint.txt
index 1540a92f6d2..5b5f29cb9f8 100644
--- a/Documentation/scsi/FlashPoint.txt
+++ b/Documentation/scsi/FlashPoint.txt
@@ -13,7 +13,7 @@ operating system support to its BusLogic brand of FlashPoint Ultra SCSI
host adapters. All of BusLogic's other SCSI host adapters, including the
MultiMaster line, currently support the Linux operating system. Linux
drivers and information will be available on October 15th at
-http://www.dandelion.com/Linux/.
+http://sourceforge.net/projects/dandelion/.
"Mylex is committed to supporting the Linux community," says Peter Shambora,
vice president of marketing for Mylex. "We have supported Linux driver
@@ -27,7 +27,7 @@ Linux is a freely-distributed implementation of UNIX for Intel x86, Sun
SPARC, SGI MIPS, Motorola 68k, Digital Alpha AXP and Motorola PowerPC
machines. It supports a wide range of software, including the X Window
System, Emacs, and TCP/IP networking. Further information is available at
-http://www.linux.org and http://www.ssc.com/linux.
+http://www.linux.org and http://www.ssc.com/.
FlashPoint Host Adapters
diff --git a/Documentation/scsi/Mylex.txt b/Documentation/scsi/Mylex.txt
index cdf69293f7d..3797f3e6c2b 100644
--- a/Documentation/scsi/Mylex.txt
+++ b/Documentation/scsi/Mylex.txt
@@ -2,4 +2,4 @@ Please see the file README.BusLogic for information about Linux support for
Mylex (formerly BusLogic) MultiMaster and FlashPoint SCSI Host Adapters.
The Mylex DAC960 PCI RAID Controllers are now supported. Please consult
-http://www.dandelion.com/Linux/ for further information on the DAC960 driver.
+http://sourceforge.net/projects/dandelion for further information on the DAC960 driver.
diff --git a/Documentation/scsi/NinjaSCSI.txt b/Documentation/scsi/NinjaSCSI.txt
index 3229b64cf24..ac8db8ceec7 100644
--- a/Documentation/scsi/NinjaSCSI.txt
+++ b/Documentation/scsi/NinjaSCSI.txt
@@ -3,8 +3,6 @@
1. Comment
This is Workbit corp.'s(http://www.workbit.co.jp/) NinjaSCSI-3
-(http://www.workbit.co.jp/ts/z_nj3r.html) and NinjaSCSI-32Bi
-(http://www.workbit.co.jp/ts/z_njsc32bi.html) PCMCIA card driver module
for Linux.
2. My Linux environment
diff --git a/Documentation/scsi/aic79xx.txt b/Documentation/scsi/aic79xx.txt
index c014eccaf19..16e054c9c70 100644
--- a/Documentation/scsi/aic79xx.txt
+++ b/Documentation/scsi/aic79xx.txt
@@ -447,7 +447,7 @@ The following information is available in this file:
http://www.adaptec.com/buy-cables/.
Europe
- - Visit our Web site at http://www.adaptec-europe.com/.
+ - Visit our Web site at http://www.adaptec.com/en-US/_common/world_index.
- To speak with a Technical Support Specialist, call, or email,
* German: +49 89 4366 5522, Monday-Friday, 9:00-17:00 CET,
http://ask-de.adaptec.com/.
diff --git a/Documentation/scsi/aic7xxx.txt b/Documentation/scsi/aic7xxx.txt
index b7e238cbb5a..18f8d1905e6 100644
--- a/Documentation/scsi/aic7xxx.txt
+++ b/Documentation/scsi/aic7xxx.txt
@@ -344,7 +344,7 @@ The following information is available in this file:
http://www.adaptec.com/buy-cables/.
Europe
- - Visit our Web site at http://www.adaptec-europe.com/.
+ - Visit our Web site at http://www.adaptec.com/en-US/_common/world_index.
- To speak with a Technical Support Specialist, call, or email,
* German: +49 89 4366 5522, Monday-Friday, 9:00-17:00 CET,
http://ask-de.adaptec.com/.
diff --git a/Documentation/scsi/hpsa.txt b/Documentation/scsi/hpsa.txt
new file mode 100644
index 00000000000..dca658362cb
--- /dev/null
+++ b/Documentation/scsi/hpsa.txt
@@ -0,0 +1,107 @@
+
+HPSA - Hewlett Packard Smart Array driver
+-----------------------------------------
+
+This file describes the hpsa SCSI driver for HP Smart Array controllers.
+The hpsa driver is intended to supplant the cciss driver for newer
+Smart Array controllers. The hpsa driver is a SCSI driver, while the
+cciss driver is a "block" driver. Actually cciss is both a block
+driver (for logical drives) AND a SCSI driver (for tape drives). This
+"split-brained" design of the cciss driver is a source of excess
+complexity and eliminating that complexity is one of the reasons
+for hpsa to exist.
+
+Supported devices:
+------------------
+
+Smart Array P212
+Smart Array P410
+Smart Array P410i
+Smart Array P411
+Smart Array P812
+Smart Array P712m
+Smart Array P711m
+StorageWorks P1210m
+
+Additionally, older Smart Arrays may work with the hpsa driver if the kernel
+boot parameter "hpsa_allow_any=1" is specified, however these are not tested
+nor supported by HP with this driver. For older Smart Arrays, the cciss
+driver should still be used.
+
+HPSA specific entries in /sys
+-----------------------------
+
+ In addition to the generic SCSI attributes available in /sys, hpsa supports
+ the following attributes:
+
+ HPSA specific host attributes:
+ ------------------------------
+
+ /sys/class/scsi_host/host*/rescan
+ /sys/class/scsi_host/host*/firmware_revision
+
+ the host "rescan" attribute is a write only attribute. Writing to this
+ attribute will cause the driver to scan for new, changed, or removed devices
+ (e.g. hot-plugged tape drives, or newly configured or deleted logical drives,
+ etc.) and notify the SCSI midlayer of any changes detected. Normally this is
+ triggered automatically by HP's Array Configuration Utility (either the GUI or
+ command line variety) so for logical drive changes, the user should not
+ normally have to use this. It may be useful when hot plugging devices like
+ tape drives, or entire storage boxes containing pre-configured logical drives.
+
+ The "firmware_revision" attribute contains the firmware version of the Smart Array.
+ For example:
+
+ root@host:/sys/class/scsi_host/host4# cat firmware_revision
+ 7.14
+
+ HPSA specific disk attributes:
+ ------------------------------
+
+ /sys/class/scsi_disk/c:b:t:l/device/unique_id
+ /sys/class/scsi_disk/c:b:t:l/device/raid_level
+ /sys/class/scsi_disk/c:b:t:l/device/lunid
+
+ (where c:b:t:l are the controller, bus, target and lun of the device)
+
+ For example:
+
+ root@host:/sys/class/scsi_disk/4:0:0:0/device# cat unique_id
+ 600508B1001044395355323037570F77
+ root@host:/sys/class/scsi_disk/4:0:0:0/device# cat lunid
+ 0x0000004000000000
+ root@host:/sys/class/scsi_disk/4:0:0:0/device# cat raid_level
+ RAID 0
+
+HPSA specific ioctls:
+---------------------
+
+ For compatibility with applications written for the cciss driver, many, but
+ not all of the ioctls supported by the cciss driver are also supported by the
+ hpsa driver. The data structures used by these are described in
+ include/linux/cciss_ioctl.h
+
+ CCISS_DEREGDISK
+ CCISS_REGNEWDISK
+ CCISS_REGNEWD
+
+ The above three ioctls all do exactly the same thing, which is to cause the driver
+ to rescan for new devices. This does exactly the same thing as writing to the
+ hpsa specific host "rescan" attribute.
+
+ CCISS_GETPCIINFO
+
+ Returns PCI domain, bus, device and function and "board ID" (PCI subsystem ID).
+
+ CCISS_GETDRIVVER
+
+ Returns driver version in three bytes encoded as:
+ (major_version << 16) | (minor_version << 8) | (subminor_version)
+
+ CCISS_PASSTHRU
+ CCISS_BIG_PASSTHRU
+
+ Allows "BMIC" and "CISS" commands to be passed through to the Smart Array.
+ These are used extensively by the HP Array Configuration Utility, SNMP storage
+ agents, etc. See cciss_vol_status at http://cciss.sf.net for some examples.
+
diff --git a/Documentation/scsi/ibmmca.txt b/Documentation/scsi/ibmmca.txt
index 3920f28710c..45d61ad8c6f 100644
--- a/Documentation/scsi/ibmmca.txt
+++ b/Documentation/scsi/ibmmca.txt
@@ -1109,7 +1109,7 @@
Q: Where can I find the latest info about this driver?
A: See the file MAINTAINERS for the current WWW-address, which offers
updates, info and Q/A lists. At this file's origin, the webaddress
- was: http://www.uni-mainz.de/~langm000/linux.html
+ was: http://www.staff.uni-mainz.de/mlang/linux.html
Q: My SCSI-adapter is not recognized by the driver, what can I do?
A: Just force it to be recognized by kernel parameters. See section 5.1.
If this really happens, do also send e-mail to the maintainer, as
diff --git a/Documentation/scsi/osst.txt b/Documentation/scsi/osst.txt
index 2b21890bc98..ad86c6d1e89 100644
--- a/Documentation/scsi/osst.txt
+++ b/Documentation/scsi/osst.txt
@@ -135,7 +135,7 @@ The driver development is coordinated through a mailing list
a CVS repository and some web pages.
The tester's pages which contain recent news and updated drivers to download
can be found on
-http://linux1.onstream.nl/test/
+http://sourceforge.net/projects/osst/
If you find any problems, please have a look at the tester's page in order
to see whether the problem is already known and solved. Otherwise, please
diff --git a/Documentation/scsi/ppa.txt b/Documentation/scsi/ppa.txt
index 067ac394e0b..05ff47dbe8d 100644
--- a/Documentation/scsi/ppa.txt
+++ b/Documentation/scsi/ppa.txt
@@ -1,13 +1,13 @@
-------- Terse where to get ZIP Drive help info --------
General Iomega ZIP drive page for Linux:
-http://www.torque.net/~campbell/
+http://web.archive.org/web/*/http://www.torque.net/~campbell/
Driver archive for old drivers:
-http://www.torque.net/~campbell/ppa/
+http://web.archive.org/web/*/http://www.torque.net/~campbell/ppa
Linux Parport page (parallel port)
-http://www.torque.net/parport/
+http://web.archive.org/web/*/http://www.torque.net/parport/
Email list for Linux Parport
linux-parport@torque.net
diff --git a/Documentation/scsi/scsi-generic.txt b/Documentation/scsi/scsi-generic.txt
index c38e2b3648e..0a22ab8ea0c 100644
--- a/Documentation/scsi/scsi-generic.txt
+++ b/Documentation/scsi/scsi-generic.txt
@@ -34,11 +34,11 @@ http://www.tldp.org/HOWTO/SCSI-Generic-HOWTO
This describes the sg version 3 driver found in the lk 2.4 series.
The LDP renders documents in single and multiple page HTML, postscript
and pdf. This document can also be found at:
-http://www.torque.net/sg/p/sg_v3_ho.html
+http://sg.danny.cz/sg/p/sg_v3_ho.html
Documentation for the version 2 sg driver found in the lk 2.2 series can
-be found at http://www.torque.net/sg/p/scsi-generic.txt . A larger version
-is at: http://www.torque.net/sg/p/scsi-generic_long.txt .
+be found at http://sg.danny.cz/sg/. A larger version
+is at: http://sg.danny.cz/sg/p/scsi-generic_long.txt.
The original documentation for the sg driver (prior to lk 2.2.6) can be
found at http://www.torque.net/sg/p/original/SCSI-Programming-HOWTO.txt
@@ -61,7 +61,7 @@ There are two packages of sg utilities:
- sg_utils for the sg version 2 (and original) driver found in lk 2.2
and earlier
Both packages will work in the lk 2.4 series however sg3_utils offers more
-capabilities. They can be found at: http://www.torque.net/sg and
+capabilities. They can be found at: http://sg.danny.cz/sg/sg3_utils.html and
freshmeat.net
Another approach is to look at the applications that use the sg driver.
diff --git a/Documentation/scsi/scsi.txt b/Documentation/scsi/scsi.txt
index dd1bbf4e98e..3d99d38cb62 100644
--- a/Documentation/scsi/scsi.txt
+++ b/Documentation/scsi/scsi.txt
@@ -4,8 +4,8 @@ The Linux Documentation Project (LDP) maintains a document describing
the SCSI subsystem in the Linux kernel (lk) 2.4 series. See:
http://www.tldp.org/HOWTO/SCSI-2.4-HOWTO . The LDP has single
and multiple page HTML renderings as well as postscript and pdf.
-It can also be found at http://www.torque.net/scsi/SCSI-2.4-HOWTO .
-
+It can also be found at:
+http://web.archive.org/web/*/http://www.torque.net/scsi/SCSI-2.4-HOWTO
Notes on using modules in the SCSI subsystem
============================================
diff --git a/Documentation/scsi/scsi_mid_low_api.txt b/Documentation/scsi/scsi_mid_low_api.txt
index de67229251d..570ef2b3d79 100644
--- a/Documentation/scsi/scsi_mid_low_api.txt
+++ b/Documentation/scsi/scsi_mid_low_api.txt
@@ -43,7 +43,7 @@ There is a SCSI documentation directory within the kernel source tree,
typically Documentation/scsi . Most documents are in plain
(i.e. ASCII) text. This file is named scsi_mid_low_api.txt and can be
found in that directory. A more recent copy of this document may be found
-at http://www.torque.net/scsi/scsi_mid_low_api.txt.gz .
+at http://web.archive.org/web/20070107183357rn_1/sg.torque.net/scsi/.
Many LLDs are documented there (e.g. aic7xxx.txt). The SCSI mid-level is
briefly described in scsi.txt which contains a url to a document
describing the SCSI subsystem in the lk 2.4 series. Two upper level
diff --git a/Documentation/serial/moxa-smartio b/Documentation/serial/moxa-smartio
index 5337e80a5b9..d1044391868 100644
--- a/Documentation/serial/moxa-smartio
+++ b/Documentation/serial/moxa-smartio
@@ -76,7 +76,7 @@ Content
GNU General Public License in this version. Please refer to GNU General
Public License announcement in each source code file for more detail.
- In Moxa's Web sites, you may always find latest driver at http://web.moxa.com.
+ In Moxa's Web sites, you may always find latest driver at http://www.moxa.com/.
This version of driver can be installed as Loadable Module (Module driver)
or built-in into kernel (Static driver). You may refer to following
diff --git a/Documentation/slow-work.txt b/Documentation/slow-work.txt
deleted file mode 100644
index 9dbf4470c7e..00000000000
--- a/Documentation/slow-work.txt
+++ /dev/null
@@ -1,322 +0,0 @@
- ====================================
- SLOW WORK ITEM EXECUTION THREAD POOL
- ====================================
-
-By: David Howells <dhowells@redhat.com>
-
-The slow work item execution thread pool is a pool of threads for performing
-things that take a relatively long time, such as making mkdir calls.
-Typically, when processing something, these items will spend a lot of time
-blocking a thread on I/O, thus making that thread unavailable for doing other
-work.
-
-The standard workqueue model is unsuitable for this class of work item as that
-limits the owner to a single thread or a single thread per CPU. For some
-tasks, however, more threads - or fewer - are required.
-
-There is just one pool per system. It contains no threads unless something
-wants to use it - and that something must register its interest first. When
-the pool is active, the number of threads it contains is dynamic, varying
-between a maximum and minimum setting, depending on the load.
-
-
-====================
-CLASSES OF WORK ITEM
-====================
-
-This pool support two classes of work items:
-
- (*) Slow work items.
-
- (*) Very slow work items.
-
-The former are expected to finish much quicker than the latter.
-
-An operation of the very slow class may do a batch combination of several
-lookups, mkdirs, and a create for instance.
-
-An operation of the ordinarily slow class may, for example, write stuff or
-expand files, provided the time taken to do so isn't too long.
-
-Operations of both types may sleep during execution, thus tying up the thread
-loaned to it.
-
-A further class of work item is available, based on the slow work item class:
-
- (*) Delayed slow work items.
-
-These are slow work items that have a timer to defer queueing of the item for
-a while.
-
-
-THREAD-TO-CLASS ALLOCATION
---------------------------
-
-Not all the threads in the pool are available to work on very slow work items.
-The number will be between one and one fewer than the number of active threads.
-This is configurable (see the "Pool Configuration" section).
-
-All the threads are available to work on ordinarily slow work items, but a
-percentage of the threads will prefer to work on very slow work items.
-
-The configuration ensures that at least one thread will be available to work on
-very slow work items, and at least one thread will be available that won't work
-on very slow work items at all.
-
-
-=====================
-USING SLOW WORK ITEMS
-=====================
-
-Firstly, a module or subsystem wanting to make use of slow work items must
-register its interest:
-
- int ret = slow_work_register_user(struct module *module);
-
-This will return 0 if successful, or a -ve error upon failure. The module
-pointer should be the module interested in using this facility (almost
-certainly THIS_MODULE).
-
-
-Slow work items may then be set up by:
-
- (1) Declaring a slow_work struct type variable:
-
- #include <linux/slow-work.h>
-
- struct slow_work myitem;
-
- (2) Declaring the operations to be used for this item:
-
- struct slow_work_ops myitem_ops = {
- .get_ref = myitem_get_ref,
- .put_ref = myitem_put_ref,
- .execute = myitem_execute,
- };
-
- [*] For a description of the ops, see section "Item Operations".
-
- (3) Initialising the item:
-
- slow_work_init(&myitem, &myitem_ops);
-
- or:
-
- delayed_slow_work_init(&myitem, &myitem_ops);
-
- or:
-
- vslow_work_init(&myitem, &myitem_ops);
-
- depending on its class.
-
-A suitably set up work item can then be enqueued for processing:
-
- int ret = slow_work_enqueue(&myitem);
-
-This will return a -ve error if the thread pool is unable to gain a reference
-on the item, 0 otherwise, or (for delayed work):
-
- int ret = delayed_slow_work_enqueue(&myitem, my_jiffy_delay);
-
-
-The items are reference counted, so there ought to be no need for a flush
-operation. But as the reference counting is optional, means to cancel
-existing work items are also included:
-
- cancel_slow_work(&myitem);
- cancel_delayed_slow_work(&myitem);
-
-can be used to cancel pending work. The above cancel function waits for
-existing work to have been executed (or prevent execution of them, depending
-on timing).
-
-
-When all a module's slow work items have been processed, and the
-module has no further interest in the facility, it should unregister its
-interest:
-
- slow_work_unregister_user(struct module *module);
-
-The module pointer is used to wait for all outstanding work items for that
-module before completing the unregistration. This prevents the put_ref() code
-from being taken away before it completes. module should almost certainly be
-THIS_MODULE.
-
-
-================
-HELPER FUNCTIONS
-================
-
-The slow-work facility provides a function by which it can be determined
-whether or not an item is queued for later execution:
-
- bool queued = slow_work_is_queued(struct slow_work *work);
-
-If it returns false, then the item is not on the queue (it may be executing
-with a requeue pending). This can be used to work out whether an item on which
-another depends is on the queue, thus allowing a dependent item to be queued
-after it.
-
-If the above shows an item on which another depends not to be queued, then the
-owner of the dependent item might need to wait. However, to avoid locking up
-the threads unnecessarily be sleeping in them, it can make sense under some
-circumstances to return the work item to the queue, thus deferring it until
-some other items have had a chance to make use of the yielded thread.
-
-To yield a thread and defer an item, the work function should simply enqueue
-the work item again and return. However, this doesn't work if there's nothing
-actually on the queue, as the thread just vacated will jump straight back into
-the item's work function, thus busy waiting on a CPU.
-
-Instead, the item should use the thread to wait for the dependency to go away,
-but rather than using schedule() or schedule_timeout() to sleep, it should use
-the following function:
-
- bool requeue = slow_work_sleep_till_thread_needed(
- struct slow_work *work,
- signed long *_timeout);
-
-This will add a second wait and then sleep, such that it will be woken up if
-either something appears on the queue that could usefully make use of the
-thread - and behind which this item can be queued, or if the event the caller
-set up to wait for happens. True will be returned if something else appeared
-on the queue and this work function should perhaps return, of false if
-something else woke it up. The timeout is as for schedule_timeout().
-
-For example:
-
- wq = bit_waitqueue(&my_flags, MY_BIT);
- init_wait(&wait);
- requeue = false;
- do {
- prepare_to_wait(wq, &wait, TASK_UNINTERRUPTIBLE);
- if (!test_bit(MY_BIT, &my_flags))
- break;
- requeue = slow_work_sleep_till_thread_needed(&my_work,
- &timeout);
- } while (timeout > 0 && !requeue);
- finish_wait(wq, &wait);
- if (!test_bit(MY_BIT, &my_flags)
- goto do_my_thing;
- if (requeue)
- return; // to slow_work
-
-
-===============
-ITEM OPERATIONS
-===============
-
-Each work item requires a table of operations of type struct slow_work_ops.
-Only ->execute() is required; the getting and putting of a reference and the
-describing of an item are all optional.
-
- (*) Get a reference on an item:
-
- int (*get_ref)(struct slow_work *work);
-
- This allows the thread pool to attempt to pin an item by getting a
- reference on it. This function should return 0 if the reference was
- granted, or a -ve error otherwise. If an error is returned,
- slow_work_enqueue() will fail.
-
- The reference is held whilst the item is queued and whilst it is being
- executed. The item may then be requeued with the same reference held, or
- the reference will be released.
-
- (*) Release a reference on an item:
-
- void (*put_ref)(struct slow_work *work);
-
- This allows the thread pool to unpin an item by releasing the reference on
- it. The thread pool will not touch the item again once this has been
- called.
-
- (*) Execute an item:
-
- void (*execute)(struct slow_work *work);
-
- This should perform the work required of the item. It may sleep, it may
- perform disk I/O and it may wait for locks.
-
- (*) View an item through /proc:
-
- void (*desc)(struct slow_work *work, struct seq_file *m);
-
- If supplied, this should print to 'm' a small string describing the work
- the item is to do. This should be no more than about 40 characters, and
- shouldn't include a newline character.
-
- See the 'Viewing executing and queued items' section below.
-
-
-==================
-POOL CONFIGURATION
-==================
-
-The slow-work thread pool has a number of configurables:
-
- (*) /proc/sys/kernel/slow-work/min-threads
-
- The minimum number of threads that should be in the pool whilst it is in
- use. This may be anywhere between 2 and max-threads.
-
- (*) /proc/sys/kernel/slow-work/max-threads
-
- The maximum number of threads that should in the pool. This may be
- anywhere between min-threads and 255 or NR_CPUS * 2, whichever is greater.
-
- (*) /proc/sys/kernel/slow-work/vslow-percentage
-
- The percentage of active threads in the pool that may be used to execute
- very slow work items. This may be between 1 and 99. The resultant number
- is bounded to between 1 and one fewer than the number of active threads.
- This ensures there is always at least one thread that can process very
- slow work items, and always at least one thread that won't.
-
-
-==================================
-VIEWING EXECUTING AND QUEUED ITEMS
-==================================
-
-If CONFIG_SLOW_WORK_DEBUG is enabled, a debugfs file is made available:
-
- /sys/kernel/debug/slow_work/runqueue
-
-through which the list of work items being executed and the queues of items to
-be executed may be viewed. The owner of a work item is given the chance to
-add some information of its own.
-
-The contents look something like the following:
-
- THR PID ITEM ADDR FL MARK DESC
- === ===== ================ == ===== ==========
- 0 3005 ffff880023f52348 a 952ms FSC: OBJ17d3: LOOK
- 1 3006 ffff880024e33668 2 160ms FSC: OBJ17e5 OP60d3b: Write1/Store fl=2
- 2 3165 ffff8800296dd180 a 424ms FSC: OBJ17e4: LOOK
- 3 4089 ffff8800262c8d78 a 212ms FSC: OBJ17ea: CRTN
- 4 4090 ffff88002792bed8 2 388ms FSC: OBJ17e8 OP60d36: Write1/Store fl=2
- 5 4092 ffff88002a0ef308 2 388ms FSC: OBJ17e7 OP60d2e: Write1/Store fl=2
- 6 4094 ffff88002abaf4b8 2 132ms FSC: OBJ17e2 OP60d4e: Write1/Store fl=2
- 7 4095 ffff88002bb188e0 a 388ms FSC: OBJ17e9: CRTN
- vsq - ffff880023d99668 1 308ms FSC: OBJ17e0 OP60f91: Write1/EnQ fl=2
- vsq - ffff8800295d1740 1 212ms FSC: OBJ16be OP4d4b6: Write1/EnQ fl=2
- vsq - ffff880025ba3308 1 160ms FSC: OBJ179a OP58dec: Write1/EnQ fl=2
- vsq - ffff880024ec83e0 1 160ms FSC: OBJ17ae OP599f2: Write1/EnQ fl=2
- vsq - ffff880026618e00 1 160ms FSC: OBJ17e6 OP60d33: Write1/EnQ fl=2
- vsq - ffff880025a2a4b8 1 132ms FSC: OBJ16a2 OP4d583: Write1/EnQ fl=2
- vsq - ffff880023cbe6d8 9 212ms FSC: OBJ17eb: LOOK
- vsq - ffff880024d37590 9 212ms FSC: OBJ17ec: LOOK
- vsq - ffff880027746cb0 9 212ms FSC: OBJ17ed: LOOK
- vsq - ffff880024d37ae8 9 212ms FSC: OBJ17ee: LOOK
- vsq - ffff880024d37cb0 9 212ms FSC: OBJ17ef: LOOK
- vsq - ffff880025036550 9 212ms FSC: OBJ17f0: LOOK
- vsq - ffff8800250368e0 9 212ms FSC: OBJ17f1: LOOK
- vsq - ffff880025036aa8 9 212ms FSC: OBJ17f2: LOOK
-
-In the 'THR' column, executing items show the thread they're occupying and
-queued threads indicate which queue they're on. 'PID' shows the process ID of
-a slow-work thread that's executing something. 'FL' shows the work item flags.
-'MARK' indicates how long since an item was queued or began executing. Lastly,
-the 'DESC' column permits the owner of an item to give some information.
-
diff --git a/Documentation/sound/alsa/ALSA-Configuration.txt b/Documentation/sound/alsa/ALSA-Configuration.txt
index 2075bbb8b3e..7f4dcebda9c 100644
--- a/Documentation/sound/alsa/ALSA-Configuration.txt
+++ b/Documentation/sound/alsa/ALSA-Configuration.txt
@@ -1285,7 +1285,7 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
about this driver. Note that it has been discontinued, but the
Voyetra Turtle Beach knowledge base entry for it is still available
at
- http://www.turtlebeach.com/site/kb_ftp/790.asp
+ http://www.turtlebeach.com
Module snd-msnd-pinnacle
------------------------
diff --git a/Documentation/sound/alsa/HD-Audio-Models.txt b/Documentation/sound/alsa/HD-Audio-Models.txt
index 1d38b0dfba9..03771d7c5dd 100644
--- a/Documentation/sound/alsa/HD-Audio-Models.txt
+++ b/Documentation/sound/alsa/HD-Audio-Models.txt
@@ -114,6 +114,11 @@ ALC662/663/272
samsung-nc10 Samsung NC10 mini notebook
auto auto-config reading BIOS (default)
+ALC680
+======
+ base Base model (ASUS NX90)
+ auto auto-config reading BIOS (default)
+
ALC882/883/885/888/889
======================
3stack-dig 3-jack with SPDIF I/O
@@ -282,6 +287,7 @@ Conexant 5051
hp HP Spartan laptop
hp-dv6736 HP dv6736
hp-f700 HP Compaq Presario F700
+ ideapad Lenovo IdeaPad laptop
lenovo-x200 Lenovo X200 laptop
toshiba Toshiba Satellite M300
diff --git a/Documentation/sound/alsa/HD-Audio.txt b/Documentation/sound/alsa/HD-Audio.txt
index bdafdbd3256..278cc2122ea 100644
--- a/Documentation/sound/alsa/HD-Audio.txt
+++ b/Documentation/sound/alsa/HD-Audio.txt
@@ -562,7 +562,7 @@ compare the codec registers directly.
Send a bug report either the followings:
kernel-bugzilla::
- http://bugme.linux-foundation.org/
+ https://bugzilla.kernel.org/
alsa-devel ML::
alsa-devel@alsa-project.org
diff --git a/Documentation/sound/alsa/Procfile.txt b/Documentation/sound/alsa/Procfile.txt
index 07301de12cc..7fcd1ad96fc 100644
--- a/Documentation/sound/alsa/Procfile.txt
+++ b/Documentation/sound/alsa/Procfile.txt
@@ -103,6 +103,8 @@ card*/pcm*/xrun_debug
bit 2 = Enable additional jiffies check
bit 3 = Log hwptr update at each period interrupt
bit 4 = Log hwptr update at each snd_pcm_update_hw_ptr()
+ bit 5 = Show last 10 positions on error
+ bit 6 = Do above only once
When the bit 0 is set, the driver will show the messages to
kernel log when an xrun is detected. The debug message is
@@ -122,6 +124,12 @@ card*/pcm*/xrun_debug
Bits 3 and 4 are for logging the hwptr records. Note that
these will give flood of kernel messages.
+ When bit 5 is set, the driver logs the last 10 xrun errors and
+ the proc file shows each jiffies, position, period_size,
+ buffer_size, old_hw_ptr, and hw_ptr_base values.
+
+ When bit 6 is set, the full xrun log is shown only once.
+
card*/pcm*/sub*/info
The general information of this PCM sub-stream.
diff --git a/Documentation/sound/alsa/alsa-parameters.txt b/Documentation/sound/alsa/alsa-parameters.txt
new file mode 100644
index 00000000000..0fa40679b08
--- /dev/null
+++ b/Documentation/sound/alsa/alsa-parameters.txt
@@ -0,0 +1,135 @@
+ ALSA Kernel Parameters
+ ~~~~~~~~~~~~~~~~~~~~~~
+
+See Documentation/kernel-parameters.txt for general information on
+specifying module parameters.
+
+This document may not be entirely up to date and comprehensive. The command
+"modinfo -p ${modulename}" shows a current list of all parameters of a loadable
+module. Loadable modules, after being loaded into the running kernel, also
+reveal their parameters in /sys/module/${modulename}/parameters/. Some of these
+parameters may be changed at runtime by the command
+"echo -n ${value} > /sys/module/${modulename}/parameters/${parm}".
+
+
+ snd-ad1816a= [HW,ALSA]
+
+ snd-ad1848= [HW,ALSA]
+
+ snd-ali5451= [HW,ALSA]
+
+ snd-als100= [HW,ALSA]
+
+ snd-als4000= [HW,ALSA]
+
+ snd-azt2320= [HW,ALSA]
+
+ snd-cmi8330= [HW,ALSA]
+
+ snd-cmipci= [HW,ALSA]
+
+ snd-cs4231= [HW,ALSA]
+
+ snd-cs4232= [HW,ALSA]
+
+ snd-cs4236= [HW,ALSA]
+
+ snd-cs4281= [HW,ALSA]
+
+ snd-cs46xx= [HW,ALSA]
+
+ snd-dt019x= [HW,ALSA]
+
+ snd-dummy= [HW,ALSA]
+
+ snd-emu10k1= [HW,ALSA]
+
+ snd-ens1370= [HW,ALSA]
+
+ snd-ens1371= [HW,ALSA]
+
+ snd-es968= [HW,ALSA]
+
+ snd-es1688= [HW,ALSA]
+
+ snd-es18xx= [HW,ALSA]
+
+ snd-es1938= [HW,ALSA]
+
+ snd-es1968= [HW,ALSA]
+
+ snd-fm801= [HW,ALSA]
+
+ snd-gusclassic= [HW,ALSA]
+
+ snd-gusextreme= [HW,ALSA]
+
+ snd-gusmax= [HW,ALSA]
+
+ snd-hdsp= [HW,ALSA]
+
+ snd-ice1712= [HW,ALSA]
+
+ snd-intel8x0= [HW,ALSA]
+
+ snd-interwave= [HW,ALSA]
+
+ snd-interwave-stb=
+ [HW,ALSA]
+
+ snd-korg1212= [HW,ALSA]
+
+ snd-maestro3= [HW,ALSA]
+
+ snd-mpu401= [HW,ALSA]
+
+ snd-mtpav= [HW,ALSA]
+
+ snd-nm256= [HW,ALSA]
+
+ snd-opl3sa2= [HW,ALSA]
+
+ snd-opti92x-ad1848=
+ [HW,ALSA]
+
+ snd-opti92x-cs4231=
+ [HW,ALSA]
+
+ snd-opti93x= [HW,ALSA]
+
+ snd-pmac= [HW,ALSA]
+
+ snd-rme32= [HW,ALSA]
+
+ snd-rme96= [HW,ALSA]
+
+ snd-rme9652= [HW,ALSA]
+
+ snd-sb8= [HW,ALSA]
+
+ snd-sb16= [HW,ALSA]
+
+ snd-sbawe= [HW,ALSA]
+
+ snd-serial= [HW,ALSA]
+
+ snd-sgalaxy= [HW,ALSA]
+
+ snd-sonicvibes= [HW,ALSA]
+
+ snd-sun-amd7930=
+ [HW,ALSA]
+
+ snd-sun-cs4231= [HW,ALSA]
+
+ snd-trident= [HW,ALSA]
+
+ snd-usb-audio= [HW,ALSA,USB]
+
+ snd-via82xx= [HW,ALSA]
+
+ snd-virmidi= [HW,ALSA]
+
+ snd-wavefront= [HW,ALSA]
+
+ snd-ymfpci= [HW,ALSA]
diff --git a/Documentation/sound/alsa/soc/DAI.txt b/Documentation/sound/alsa/soc/DAI.txt
index 0ebd7ea9706..c9679264c55 100644
--- a/Documentation/sound/alsa/soc/DAI.txt
+++ b/Documentation/sound/alsa/soc/DAI.txt
@@ -13,7 +13,7 @@ frame (FRAME) (usually 48kHz) is always driven by the controller. Each AC97
frame is 21uS long and is divided into 13 time slots.
The AC97 specification can be found at :-
-http://www.intel.com/design/chipsets/audio/ac97_r23.pdf
+http://www.intel.com/p/en_US/business/design
I2S
diff --git a/Documentation/sound/alsa/soc/codec.txt b/Documentation/sound/alsa/soc/codec.txt
index 1e95342ed72..37ba3a72cb7 100644
--- a/Documentation/sound/alsa/soc/codec.txt
+++ b/Documentation/sound/alsa/soc/codec.txt
@@ -143,7 +143,7 @@ struct snd_soc_ops {
};
Please refer to the ALSA driver PCM documentation for details.
-http://www.alsa-project.org/~iwai/writing-an-alsa-driver/c436.htm
+http://www.alsa-project.org/~iwai/writing-an-alsa-driver/
5 - DAPM description.
diff --git a/Documentation/sound/alsa/soc/platform.txt b/Documentation/sound/alsa/soc/platform.txt
index b681d17fc38..06d835987c6 100644
--- a/Documentation/sound/alsa/soc/platform.txt
+++ b/Documentation/sound/alsa/soc/platform.txt
@@ -39,7 +39,7 @@ struct snd_soc_platform {
};
Please refer to the ALSA driver documentation for details of audio DMA.
-http://www.alsa-project.org/~iwai/writing-an-alsa-driver/c436.htm
+http://www.alsa-project.org/~iwai/writing-an-alsa-driver/
An example DMA driver is soc/pxa/pxa2xx-pcm.c
diff --git a/Documentation/sound/oss/README.OSS b/Documentation/sound/oss/README.OSS
index fd42b05b2f5..c615debbf08 100644
--- a/Documentation/sound/oss/README.OSS
+++ b/Documentation/sound/oss/README.OSS
@@ -36,7 +36,7 @@ with OSS API.
Packages "snd-util-3.8.tar.gz" and "snd-data-0.1.tar.Z"
contain useful utilities to be used with this driver.
-See http://www.opensound.com/ossfree/getting.html for
+See http://www.opensound.com/ossfree/ for
download instructions.
If you are looking for the installation instructions, please
@@ -1438,7 +1438,7 @@ of this driver (see http://www.4Front-tech.com/oss.html for more info).
There are some common audio chipsets that are not supported yet. For example
Sierra Aria and IBM Mwave. It's possible that these architectures
get some support in future but I can't make any promises. Just look
-at the home page (http://www.opensound.com/ossfree/new_cards.html)
+at the home page (http://www.opensound.com/ossfree/)
for latest info.
Information about unsupported sound cards and chipsets is welcome as well
@@ -1449,7 +1449,6 @@ If you have any corrections and/or comments, please contact me.
Hannu Savolainen
hannu@opensound.com
-Personal home page: http://www.compusonic.fi/~hannu
home page of OSS/Free: http://www.opensound.com/ossfree
home page of commercial OSS
diff --git a/Documentation/sound/oss/oss-parameters.txt b/Documentation/sound/oss/oss-parameters.txt
new file mode 100644
index 00000000000..3ab391e7c29
--- /dev/null
+++ b/Documentation/sound/oss/oss-parameters.txt
@@ -0,0 +1,51 @@
+ OSS Kernel Parameters
+ ~~~~~~~~~~~~~~~~~~~~~
+
+See Documentation/kernel-parameters.txt for general information on
+specifying module parameters.
+
+This document may not be entirely up to date and comprehensive. The command
+"modinfo -p ${modulename}" shows a current list of all parameters of a loadable
+module. Loadable modules, after being loaded into the running kernel, also
+reveal their parameters in /sys/module/${modulename}/parameters/. Some of these
+parameters may be changed at runtime by the command
+"echo -n ${value} > /sys/module/${modulename}/parameters/${parm}".
+
+
+ ad1848= [HW,OSS]
+ Format: <io>,<irq>,<dma>,<dma2>,<type>
+
+ aedsp16= [HW,OSS] Audio Excel DSP 16
+ Format: <io>,<irq>,<dma>,<mss_io>,<mpu_io>,<mpu_irq>
+ See also header of sound/oss/aedsp16.c.
+
+ dmasound= [HW,OSS] Sound subsystem buffers
+
+ mpu401= [HW,OSS]
+ Format: <io>,<irq>
+
+ opl3= [HW,OSS]
+ Format: <io>
+
+ pas2= [HW,OSS] Format:
+ <io>,<irq>,<dma>,<dma16>,<sb_io>,<sb_irq>,<sb_dma>,<sb_dma16>
+
+ pss= [HW,OSS] Personal Sound System (ECHO ESC614)
+ Format:
+ <io>,<mss_io>,<mss_irq>,<mss_dma>,<mpu_io>,<mpu_irq>
+
+ sscape= [HW,OSS]
+ Format: <io>,<irq>,<dma>,<mpu_io>,<mpu_irq>
+
+ trix= [HW,OSS] MediaTrix AudioTrix Pro
+ Format:
+ <io>,<irq>,<dma>,<dma2>,<sb_io>,<sb_irq>,<sb_dma>,<mpu_io>,<mpu_irq>
+
+ uart401= [HW,OSS]
+ Format: <io>,<irq>
+
+ uart6850= [HW,OSS]
+ Format: <io>,<irq>
+
+ waveartist= [HW,OSS]
+ Format: <io>,<irq>,<dma>,<dma2>
diff --git a/Documentation/sparse.txt b/Documentation/sparse.txt
index 9b659c79a54..4909d411635 100644
--- a/Documentation/sparse.txt
+++ b/Documentation/sparse.txt
@@ -1,5 +1,5 @@
Copyright 2004 Linus Torvalds
-Copyright 2004 Pavel Machek <pavel@suse.cz>
+Copyright 2004 Pavel Machek <pavel@ucw.cz>
Copyright 2006 Bob Copeland <me@bobcopeland.com>
Using sparse for typechecking
diff --git a/Documentation/sysctl/vm.txt b/Documentation/sysctl/vm.txt
index 5fdbb612aeb..82b2da18c45 100644
--- a/Documentation/sysctl/vm.txt
+++ b/Documentation/sysctl/vm.txt
@@ -196,7 +196,7 @@ controlled by this knob are discussed in Documentation/laptops/laptop-mode.txt.
legacy_va_layout
-If non-zero, this sysctl disables the new 32-bit mmap mmap layout - the kernel
+If non-zero, this sysctl disables the new 32-bit mmap layout - the kernel
will use the legacy (2.4) layout for all processes.
==============================================================
diff --git a/Documentation/telephony/ixj.txt b/Documentation/telephony/ixj.txt
index 44d124005ba..4fb314d5170 100644
--- a/Documentation/telephony/ixj.txt
+++ b/Documentation/telephony/ixj.txt
@@ -108,14 +108,9 @@ applications.
1.4 Where to get things
-You can download the latest versions of the driver from:
-
-http://www.quicknet.net/develop.htm
-
-You can download the latest version of this document from:
-
-http://www.quicknet.net/develop.htm
+Info on latest versions of the driver are here:
+http://web.archive.org/web/*/http://www.quicknet.net/develop.htm
1.5 Mailing List
diff --git a/Documentation/timers/timers-howto.txt b/Documentation/timers/timers-howto.txt
new file mode 100644
index 00000000000..c9ef29d2ede
--- /dev/null
+++ b/Documentation/timers/timers-howto.txt
@@ -0,0 +1,105 @@
+delays - Information on the various kernel delay / sleep mechanisms
+-------------------------------------------------------------------
+
+This document seeks to answer the common question: "What is the
+RightWay (TM) to insert a delay?"
+
+This question is most often faced by driver writers who have to
+deal with hardware delays and who may not be the most intimately
+familiar with the inner workings of the Linux Kernel.
+
+
+Inserting Delays
+----------------
+
+The first, and most important, question you need to ask is "Is my
+code in an atomic context?" This should be followed closely by "Does
+it really need to delay in atomic context?" If so...
+
+ATOMIC CONTEXT:
+ You must use the *delay family of functions. These
+ functions use the jiffie estimation of clock speed
+ and will busy wait for enough loop cycles to achieve
+ the desired delay:
+
+ ndelay(unsigned long nsecs)
+ udelay(unsigned long usecs)
+ mdelay(unsgined long msecs)
+
+ udelay is the generally preferred API; ndelay-level
+ precision may not actually exist on many non-PC devices.
+
+ mdelay is macro wrapper around udelay, to account for
+ possible overflow when passing large arguments to udelay.
+ In general, use of mdelay is discouraged and code should
+ be refactored to allow for the use of msleep.
+
+NON-ATOMIC CONTEXT:
+ You should use the *sleep[_range] family of functions.
+ There are a few more options here, while any of them may
+ work correctly, using the "right" sleep function will
+ help the scheduler, power management, and just make your
+ driver better :)
+
+ -- Backed by busy-wait loop:
+ udelay(unsigned long usecs)
+ -- Backed by hrtimers:
+ usleep_range(unsigned long min, unsigned long max)
+ -- Backed by jiffies / legacy_timers
+ msleep(unsigned long msecs)
+ msleep_interruptible(unsigned long msecs)
+
+ Unlike the *delay family, the underlying mechanism
+ driving each of these calls varies, thus there are
+ quirks you should be aware of.
+
+
+ SLEEPING FOR "A FEW" USECS ( < ~10us? ):
+ * Use udelay
+
+ - Why not usleep?
+ On slower systems, (embedded, OR perhaps a speed-
+ stepped PC!) the overhead of setting up the hrtimers
+ for usleep *may* not be worth it. Such an evaluation
+ will obviously depend on your specific situation, but
+ it is something to be aware of.
+
+ SLEEPING FOR ~USECS OR SMALL MSECS ( 10us - 20ms):
+ * Use usleep_range
+
+ - Why not msleep for (1ms - 20ms)?
+ Explained originally here:
+ http://lkml.org/lkml/2007/8/3/250
+ msleep(1~20) may not do what the caller intends, and
+ will often sleep longer (~20 ms actual sleep for any
+ value given in the 1~20ms range). In many cases this
+ is not the desired behavior.
+
+ - Why is there no "usleep" / What is a good range?
+ Since usleep_range is built on top of hrtimers, the
+ wakeup will be very precise (ish), thus a simple
+ usleep function would likely introduce a large number
+ of undesired interrupts.
+
+ With the introduction of a range, the scheduler is
+ free to coalesce your wakeup with any other wakeup
+ that may have happened for other reasons, or at the
+ worst case, fire an interrupt for your upper bound.
+
+ The larger a range you supply, the greater a chance
+ that you will not trigger an interrupt; this should
+ be balanced with what is an acceptable upper bound on
+ delay / performance for your specific code path. Exact
+ tolerances here are very situation specific, thus it
+ is left to the caller to determine a reasonable range.
+
+ SLEEPING FOR LARGER MSECS ( 10ms+ )
+ * Use msleep or possibly msleep_interruptible
+
+ - What's the difference?
+ msleep sets the current task to TASK_UNINTERRUPTIBLE
+ whereas msleep_interruptible sets the current task to
+ TASK_INTERRUPTIBLE before scheduling the sleep. In
+ short, the difference is whether the sleep can be ended
+ early by a signal. In general, just use msleep unless
+ you know you have a need for the interruptible variant.
diff --git a/Documentation/tomoyo.txt b/Documentation/tomoyo.txt
index b3a232cae7f..200a2d37cbc 100644
--- a/Documentation/tomoyo.txt
+++ b/Documentation/tomoyo.txt
@@ -3,8 +3,8 @@
TOMOYO is a name-based MAC extension (LSM module) for the Linux kernel.
LiveCD-based tutorials are available at
-http://tomoyo.sourceforge.jp/en/1.6.x/1st-step/ubuntu8.04-live/
-http://tomoyo.sourceforge.jp/en/1.6.x/1st-step/centos5-live/ .
+http://tomoyo.sourceforge.jp/1.7/1st-step/ubuntu10.04-live/
+http://tomoyo.sourceforge.jp/1.7/1st-step/centos5-live/ .
Though these tutorials use non-LSM version of TOMOYO, they are useful for you
to know what TOMOYO is.
@@ -13,12 +13,12 @@ to know what TOMOYO is.
Build the kernel with CONFIG_SECURITY_TOMOYO=y and pass "security=tomoyo" on
kernel's command line.
-Please see http://tomoyo.sourceforge.jp/en/2.2.x/ for details.
+Please see http://tomoyo.sourceforge.jp/2.3/ for details.
--- Where is documentation? ---
User <-> Kernel interface documentation is available at
-http://tomoyo.sourceforge.jp/en/2.2.x/policy-reference.html .
+http://tomoyo.sourceforge.jp/2.3/policy-reference.html .
Materials we prepared for seminars and symposiums are available at
http://sourceforge.jp/projects/tomoyo/docs/?category_id=532&language_id=1 .
@@ -50,6 +50,6 @@ multiple LSM modules at the same time. We feel sorry that you have to give up
SELinux/SMACK/AppArmor etc. when you want to use TOMOYO.
We hope that LSM becomes stackable in future. Meanwhile, you can use non-LSM
-version of TOMOYO, available at http://tomoyo.sourceforge.jp/en/1.6.x/ .
+version of TOMOYO, available at http://tomoyo.sourceforge.jp/1.7/ .
LSM version of TOMOYO is a subset of non-LSM version of TOMOYO. We are planning
to port non-LSM version's functionalities to LSM versions.
diff --git a/Documentation/trace/ftrace-design.txt b/Documentation/trace/ftrace-design.txt
index f1f81afee8a..dc52bd442c9 100644
--- a/Documentation/trace/ftrace-design.txt
+++ b/Documentation/trace/ftrace-design.txt
@@ -13,6 +13,9 @@ Note that this focuses on architecture implementation details only. If you
want more explanation of a feature in terms of common code, review the common
ftrace.txt file.
+Ideally, everyone who wishes to retain performance while supporting tracing in
+their kernel should make it all the way to dynamic ftrace support.
+
Prerequisites
-------------
@@ -215,7 +218,7 @@ An arch may pass in a unique value (frame pointer) to both the entering and
exiting of a function. On exit, the value is compared and if it does not
match, then it will panic the kernel. This is largely a sanity check for bad
code generation with gcc. If gcc for your port sanely updates the frame
-pointer under different opitmization levels, then ignore this option.
+pointer under different optimization levels, then ignore this option.
However, adding support for it isn't terribly difficult. In your assembly code
that calls prepare_ftrace_return(), pass the frame pointer as the 3rd argument.
@@ -234,7 +237,7 @@ If you can't trace NMI functions, then skip this option.
HAVE_SYSCALL_TRACEPOINTS
----------------------
+------------------------
You need very few things to get the syscalls tracing in an arch.
@@ -250,12 +253,152 @@ You need very few things to get the syscalls tracing in an arch.
HAVE_FTRACE_MCOUNT_RECORD
-------------------------
-See scripts/recordmcount.pl for more info.
+See scripts/recordmcount.pl for more info. Just fill in the arch-specific
+details for how to locate the addresses of mcount call sites via objdump.
+This option doesn't make much sense without also implementing dynamic ftrace.
+
+HAVE_DYNAMIC_FTRACE
+-------------------
+
+You will first need HAVE_FTRACE_MCOUNT_RECORD and HAVE_FUNCTION_TRACER, so
+scroll your reader back up if you got over eager.
+
+Once those are out of the way, you will need to implement:
+ - asm/ftrace.h:
+ - MCOUNT_ADDR
+ - ftrace_call_adjust()
+ - struct dyn_arch_ftrace{}
+ - asm code:
+ - mcount() (new stub)
+ - ftrace_caller()
+ - ftrace_call()
+ - ftrace_stub()
+ - C code:
+ - ftrace_dyn_arch_init()
+ - ftrace_make_nop()
+ - ftrace_make_call()
+ - ftrace_update_ftrace_func()
+
+First you will need to fill out some arch details in your asm/ftrace.h.
+
+Define MCOUNT_ADDR as the address of your mcount symbol similar to:
+ #define MCOUNT_ADDR ((unsigned long)mcount)
+Since no one else will have a decl for that function, you will need to:
+ extern void mcount(void);
+
+You will also need the helper function ftrace_call_adjust(). Most people
+will be able to stub it out like so:
+ static inline unsigned long ftrace_call_adjust(unsigned long addr)
+ {
+ return addr;
+ }
<details to be filled>
+Lastly you will need the custom dyn_arch_ftrace structure. If you need
+some extra state when runtime patching arbitrary call sites, this is the
+place. For now though, create an empty struct:
+ struct dyn_arch_ftrace {
+ /* No extra data needed */
+ };
+
+With the header out of the way, we can fill out the assembly code. While we
+did already create a mcount() function earlier, dynamic ftrace only wants a
+stub function. This is because the mcount() will only be used during boot
+and then all references to it will be patched out never to return. Instead,
+the guts of the old mcount() will be used to create a new ftrace_caller()
+function. Because the two are hard to merge, it will most likely be a lot
+easier to have two separate definitions split up by #ifdefs. Same goes for
+the ftrace_stub() as that will now be inlined in ftrace_caller().
+
+Before we get confused anymore, let's check out some pseudo code so you can
+implement your own stuff in assembly:
-HAVE_DYNAMIC_FTRACE
----------------------
+void mcount(void)
+{
+ return;
+}
+
+void ftrace_caller(void)
+{
+ /* implement HAVE_FUNCTION_TRACE_MCOUNT_TEST if you desire */
+
+ /* save all state needed by the ABI (see paragraph above) */
+
+ unsigned long frompc = ...;
+ unsigned long selfpc = <return address> - MCOUNT_INSN_SIZE;
+
+ftrace_call:
+ ftrace_stub(frompc, selfpc);
+
+ /* restore all state needed by the ABI */
+
+ftrace_stub:
+ return;
+}
+
+This might look a little odd at first, but keep in mind that we will be runtime
+patching multiple things. First, only functions that we actually want to trace
+will be patched to call ftrace_caller(). Second, since we only have one tracer
+active at a time, we will patch the ftrace_caller() function itself to call the
+specific tracer in question. That is the point of the ftrace_call label.
+
+With that in mind, let's move on to the C code that will actually be doing the
+runtime patching. You'll need a little knowledge of your arch's opcodes in
+order to make it through the next section.
+
+Every arch has an init callback function. If you need to do something early on
+to initialize some state, this is the time to do that. Otherwise, this simple
+function below should be sufficient for most people:
+
+int __init ftrace_dyn_arch_init(void *data)
+{
+ /* return value is done indirectly via data */
+ *(unsigned long *)data = 0;
+
+ return 0;
+}
+
+There are two functions that are used to do runtime patching of arbitrary
+functions. The first is used to turn the mcount call site into a nop (which
+is what helps us retain runtime performance when not tracing). The second is
+used to turn the mcount call site into a call to an arbitrary location (but
+typically that is ftracer_caller()). See the general function definition in
+linux/ftrace.h for the functions:
+ ftrace_make_nop()
+ ftrace_make_call()
+The rec->ip value is the address of the mcount call site that was collected
+by the scripts/recordmcount.pl during build time.
+
+The last function is used to do runtime patching of the active tracer. This
+will be modifying the assembly code at the location of the ftrace_call symbol
+inside of the ftrace_caller() function. So you should have sufficient padding
+at that location to support the new function calls you'll be inserting. Some
+people will be using a "call" type instruction while others will be using a
+"branch" type instruction. Specifically, the function is:
+ ftrace_update_ftrace_func()
+
+
+HAVE_DYNAMIC_FTRACE + HAVE_FUNCTION_GRAPH_TRACER
+------------------------------------------------
+
+The function grapher needs a few tweaks in order to work with dynamic ftrace.
+Basically, you will need to:
+ - update:
+ - ftrace_caller()
+ - ftrace_graph_call()
+ - ftrace_graph_caller()
+ - implement:
+ - ftrace_enable_ftrace_graph_caller()
+ - ftrace_disable_ftrace_graph_caller()
<details to be filled>
+Quick notes:
+ - add a nop stub after the ftrace_call location named ftrace_graph_call;
+ stub needs to be large enough to support a call to ftrace_graph_caller()
+ - update ftrace_graph_caller() to work with being called by the new
+ ftrace_caller() since some semantics may have changed
+ - ftrace_enable_ftrace_graph_caller() will runtime patch the
+ ftrace_graph_call location with a call to ftrace_graph_caller()
+ - ftrace_disable_ftrace_graph_caller() will runtime patch the
+ ftrace_graph_call location with nops
diff --git a/Documentation/trace/kmemtrace.txt b/Documentation/trace/kmemtrace.txt
deleted file mode 100644
index 6308735e58c..00000000000
--- a/Documentation/trace/kmemtrace.txt
+++ /dev/null
@@ -1,126 +0,0 @@
- kmemtrace - Kernel Memory Tracer
-
- by Eduard - Gabriel Munteanu
- <eduard.munteanu@linux360.ro>
-
-I. Introduction
-===============
-
-kmemtrace helps kernel developers figure out two things:
-1) how different allocators (SLAB, SLUB etc.) perform
-2) how kernel code allocates memory and how much
-
-To do this, we trace every allocation and export information to the userspace
-through the relay interface. We export things such as the number of requested
-bytes, the number of bytes actually allocated (i.e. including internal
-fragmentation), whether this is a slab allocation or a plain kmalloc() and so
-on.
-
-The actual analysis is performed by a userspace tool (see section III for
-details on where to get it from). It logs the data exported by the kernel,
-processes it and (as of writing this) can provide the following information:
-- the total amount of memory allocated and fragmentation per call-site
-- the amount of memory allocated and fragmentation per allocation
-- total memory allocated and fragmentation in the collected dataset
-- number of cross-CPU allocation and frees (makes sense in NUMA environments)
-
-Moreover, it can potentially find inconsistent and erroneous behavior in
-kernel code, such as using slab free functions on kmalloc'ed memory or
-allocating less memory than requested (but not truly failed allocations).
-
-kmemtrace also makes provisions for tracing on some arch and analysing the
-data on another.
-
-II. Design and goals
-====================
-
-kmemtrace was designed to handle rather large amounts of data. Thus, it uses
-the relay interface to export whatever is logged to userspace, which then
-stores it. Analysis and reporting is done asynchronously, that is, after the
-data is collected and stored. By design, it allows one to log and analyse
-on different machines and different arches.
-
-As of writing this, the ABI is not considered stable, though it might not
-change much. However, no guarantees are made about compatibility yet. When
-deemed stable, the ABI should still allow easy extension while maintaining
-backward compatibility. This is described further in Documentation/ABI.
-
-Summary of design goals:
- - allow logging and analysis to be done across different machines
- - be fast and anticipate usage in high-load environments (*)
- - be reasonably extensible
- - make it possible for GNU/Linux distributions to have kmemtrace
- included in their repositories
-
-(*) - one of the reasons Pekka Enberg's original userspace data analysis
- tool's code was rewritten from Perl to C (although this is more than a
- simple conversion)
-
-
-III. Quick usage guide
-======================
-
-1) Get a kernel that supports kmemtrace and build it accordingly (i.e. enable
-CONFIG_KMEMTRACE).
-
-2) Get the userspace tool and build it:
-$ git clone git://repo.or.cz/kmemtrace-user.git # current repository
-$ cd kmemtrace-user/
-$ ./autogen.sh
-$ ./configure
-$ make
-
-3) Boot the kmemtrace-enabled kernel if you haven't, preferably in the
-'single' runlevel (so that relay buffers don't fill up easily), and run
-kmemtrace:
-# '$' does not mean user, but root here.
-$ mount -t debugfs none /sys/kernel/debug
-$ mount -t proc none /proc
-$ cd path/to/kmemtrace-user/
-$ ./kmemtraced
-Wait a bit, then stop it with CTRL+C.
-$ cat /sys/kernel/debug/kmemtrace/total_overruns # Check if we didn't
- # overrun, should
- # be zero.
-$ (Optionally) [Run kmemtrace_check separately on each cpu[0-9]*.out file to
- check its correctness]
-$ ./kmemtrace-report
-
-Now you should have a nice and short summary of how the allocator performs.
-
-IV. FAQ and known issues
-========================
-
-Q: 'cat /sys/kernel/debug/kmemtrace/total_overruns' is non-zero, how do I fix
-this? Should I worry?
-A: If it's non-zero, this affects kmemtrace's accuracy, depending on how
-large the number is. You can fix it by supplying a higher
-'kmemtrace.subbufs=N' kernel parameter.
----
-
-Q: kmemtrace_check reports errors, how do I fix this? Should I worry?
-A: This is a bug and should be reported. It can occur for a variety of
-reasons:
- - possible bugs in relay code
- - possible misuse of relay by kmemtrace
- - timestamps being collected unorderly
-Or you may fix it yourself and send us a patch.
----
-
-Q: kmemtrace_report shows many errors, how do I fix this? Should I worry?
-A: This is a known issue and I'm working on it. These might be true errors
-in kernel code, which may have inconsistent behavior (e.g. allocating memory
-with kmem_cache_alloc() and freeing it with kfree()). Pekka Enberg pointed
-out this behavior may work with SLAB, but may fail with other allocators.
-
-It may also be due to lack of tracing in some unusual allocator functions.
-
-We don't want bug reports regarding this issue yet.
----
-
-V. See also
-===========
-
-Documentation/kernel-parameters.txt
-Documentation/ABI/testing/debugfs-kmemtrace
-
diff --git a/Documentation/trace/kprobetrace.txt b/Documentation/trace/kprobetrace.txt
index ec94748ae65..5f77d94598d 100644
--- a/Documentation/trace/kprobetrace.txt
+++ b/Documentation/trace/kprobetrace.txt
@@ -42,7 +42,7 @@ Synopsis of kprobe_events
+|-offs(FETCHARG) : Fetch memory at FETCHARG +|- offs address.(**)
NAME=FETCHARG : Set NAME as the argument name of FETCHARG.
FETCHARG:TYPE : Set TYPE as the type of FETCHARG. Currently, basic types
- (u8/u16/u32/u64/s8/s16/s32/s64) are supported.
+ (u8/u16/u32/u64/s8/s16/s32/s64) and string are supported.
(*) only for return probe.
(**) this is useful for fetching a field of data structures.
diff --git a/Documentation/uml/UserModeLinux-HOWTO.txt b/Documentation/uml/UserModeLinux-HOWTO.txt
index 628013f944c..9b7e1904db1 100644
--- a/Documentation/uml/UserModeLinux-HOWTO.txt
+++ b/Documentation/uml/UserModeLinux-HOWTO.txt
@@ -8,62 +8,6 @@
Table of Contents
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
1. Introduction
1.1 How is User Mode Linux Different?
@@ -277,8 +221,7 @@
1. Download the latest UML patch from
- the download page <http://user-mode-linux.sourceforge.net/dl-
- sf.html>
+ the download page <http://user-mode-linux.sourceforge.net/
In this example, the file is uml-patch-2.4.0-prerelease.bz2.
@@ -438,7 +381,7 @@
as modules, especially filesystems and network protocols and filters,
so most symbols which need to be exported probably already are.
However, if you do find symbols that need exporting, let us
- <http://user-mode-linux.sourceforge.net/contacts.html> know, and
+ <http://user-mode-linux.sourceforge.net/> know, and
they'll be "taken care of".
@@ -498,8 +441,8 @@
You will need a filesystem to boot UML from. There are a number
available for download from here <http://user-mode-
- linux.sourceforge.net/dl-sf.html> . There are also several tools
- <http://user-mode-linux.sourceforge.net/fs_making.html> which can be
+ linux.sourceforge.net/> . There are also several tools
+ <http://user-mode-linux.sourceforge.net/> which can be
used to generate UML-compatible filesystem images from media.
The kernel will boot up and present you with a login prompt.
@@ -1236,7 +1179,7 @@
Harald's original README is here <http://user-mode-linux.source-
- forge.net/text/mcast.txt> and explains these in detail, as well as
+ forge.net/> and explains these in detail, as well as
some other issues.
@@ -1311,7 +1254,7 @@
kernel.
These were pointed out by Tim Robinson <timro at trkr dot net> in
- <http://www.geocrawler.com/lists/3/SourceForge/597/0/> name="this uml-
+ <http://www.geocrawler.com/> name="this uml-
user post"> .
@@ -2038,7 +1981,7 @@
uml_moo is installed with the UML deb and RPM. If you didn't install
UML from one of those packages, you can also get it from the UML
- utilities <http://user-mode-linux.sourceforge.net/dl-sf.html#UML
+ utilities <http://user-mode-linux.sourceforge.net/
utilities> tar file in tools/moo.
@@ -4599,7 +4542,7 @@
Michael Jennings <mikejen at hevanet.com> sent in some material which
is now gracing the top of the index page <http://user-mode-
- linux.sourceforge.net/index.html> of this site.
+ linux.sourceforge.net/> of this site.
SGI <http://www.sgi.com> (and more specifically Ralf Baechle <ralf at
uni-koblenz.de> ) gave me an account on oss.sgi.com
diff --git a/Documentation/usb/linux.inf b/Documentation/usb/linux.inf
index 2f7217d124f..af71d87d9e9 100644
--- a/Documentation/usb/linux.inf
+++ b/Documentation/usb/linux.inf
@@ -9,7 +9,7 @@
;
; Microsoft only directly supports RNDIS drivers, and bundled them into XP.
; The Microsoft "Remote NDIS USB Driver Kit" is currently found at:
-; http://www.microsoft.com/whdc/hwdev/resources/HWservices/rndis.mspx
+; http://www.microsoft.com/whdc/device/network/ndis/rmndis.mspx
[Version]
diff --git a/Documentation/usb/mtouchusb.txt b/Documentation/usb/mtouchusb.txt
index e43cfffaa10..86302cd53ed 100644
--- a/Documentation/usb/mtouchusb.txt
+++ b/Documentation/usb/mtouchusb.txt
@@ -54,10 +54,6 @@ generic functions like calibrations, resets, and vendor information can be
requested from the userspace (And the drivers would handle the vendor specific
tasks).
-ADDITIONAL INFORMATION/UPDATES/X CONFIGURATION EXAMPLE:
-
-http://groomlakelabs.com/grandamp/code/microtouch/
-
TODO:
Implement a control urb again to handle requests to and from the device
@@ -68,7 +64,7 @@ DISCLAIMER:
I am not a MicroTouch/3M employee, nor have I ever been. 3M does not support
this driver! If you want touch drivers only supported within X, please go to:
-http://www.3m.com/3MTouchSystems/downloads/
+http://www.3m.com/3MTouchSystems/
THANKS:
diff --git a/Documentation/usb/usb-serial.txt b/Documentation/usb/usb-serial.txt
index f4d21451025..5bd7926185e 100644
--- a/Documentation/usb/usb-serial.txt
+++ b/Documentation/usb/usb-serial.txt
@@ -83,7 +83,7 @@ HandSpring Visor, Palm USB, and Clié USB driver
parameters. e.g. modprobe visor vendor=0x54c product=0x66
There is a webpage and mailing lists for this portion of the driver at:
- http://usbvisor.sourceforge.net/
+ http://sourceforge.net/projects/usbvisor/
For any questions or problems with this driver, please contact Greg
Kroah-Hartman at greg@kroah.com
@@ -184,7 +184,7 @@ Keyspan USA-series Serial Adapters
functionality.
More information is available at:
- http://misc.nu/hugh/keyspan.html
+ http://www.carnationsoftware.com/carnation/Keyspan.html
For any questions or problems with this driver, please contact Hugh
Blemings at hugh@misc.nu
diff --git a/Documentation/video4linux/API.html b/Documentation/video4linux/API.html
index d749d41f647..d72fd2aa915 100644
--- a/Documentation/video4linux/API.html
+++ b/Documentation/video4linux/API.html
@@ -17,7 +17,7 @@
</tr>
<tr>
<td>
- <a href="http://www.linuxtv.org/downloads/video4linux/API/V4L2_API">V4L2 API</a>
+ <a href="http://v4l2spec.bytesex.org/spec-single/v4l2.html">V4L2 API</a>
</td>
<td>Should be used for new projects
</td>
diff --git a/Documentation/video4linux/CARDLIST.cx23885 b/Documentation/video4linux/CARDLIST.cx23885
index 16ca030e118..87c46347bd6 100644
--- a/Documentation/video4linux/CARDLIST.cx23885
+++ b/Documentation/video4linux/CARDLIST.cx23885
@@ -17,9 +17,9 @@
16 -> DVBWorld DVB-S2 2005 [0001:2005]
17 -> NetUP Dual DVB-S2 CI [1b55:2a2c]
18 -> Hauppauge WinTV-HVR1270 [0070:2211]
- 19 -> Hauppauge WinTV-HVR1275 [0070:2215]
- 20 -> Hauppauge WinTV-HVR1255 [0070:2251]
- 21 -> Hauppauge WinTV-HVR1210 [0070:2291,0070:2295]
+ 19 -> Hauppauge WinTV-HVR1275 [0070:2215,0070:221d,0070:22f2]
+ 20 -> Hauppauge WinTV-HVR1255 [0070:2251,0070:2259,0070:22f1]
+ 21 -> Hauppauge WinTV-HVR1210 [0070:2291,0070:2295,0070:2299,0070:229d,0070:22f0,0070:22f3,0070:22f4,0070:22f5]
22 -> Mygica X8506 DMB-TH [14f1:8651]
23 -> Magic-Pro ProHDTV Extreme 2 [14f1:8657]
24 -> Hauppauge WinTV-HVR1850 [0070:8541]
diff --git a/Documentation/video4linux/CARDLIST.em28xx b/Documentation/video4linux/CARDLIST.em28xx
index 3a623aaeae5..5c568757c30 100644
--- a/Documentation/video4linux/CARDLIST.em28xx
+++ b/Documentation/video4linux/CARDLIST.em28xx
@@ -72,3 +72,4 @@
73 -> Reddo DVB-C USB TV Box (em2870)
74 -> Actionmaster/LinXcel/Digitus VC211A (em2800)
75 -> Dikom DK300 (em2882)
+ 76 -> KWorld PlusTV 340U or UB435-Q (ATSC) (em2870) [1b80:a340]
diff --git a/Documentation/video4linux/CARDLIST.saa7134 b/Documentation/video4linux/CARDLIST.saa7134
index 1387a69ae3a..4000c29fcfb 100644
--- a/Documentation/video4linux/CARDLIST.saa7134
+++ b/Documentation/video4linux/CARDLIST.saa7134
@@ -178,4 +178,5 @@
177 -> Hawell HW-404M7
178 -> Beholder BeholdTV H7 [5ace:7190]
179 -> Beholder BeholdTV A7 [5ace:7090]
-180 -> Avermedia M733A [1461:4155,1461:4255]
+180 -> Avermedia PCI M733A [1461:4155,1461:4255]
+181 -> TechoTrend TT-budget T-3000 [13c2:2804]
diff --git a/Documentation/video4linux/CQcam.txt b/Documentation/video4linux/CQcam.txt
index d230878e473..8977e7ce4da 100644
--- a/Documentation/video4linux/CQcam.txt
+++ b/Documentation/video4linux/CQcam.txt
@@ -203,11 +203,11 @@ The V4L2 API spec:
http://v4l2spec.bytesex.org/
Some web pages about the quickcams:
- http://www.dkfz-heidelberg.de/Macromol/wedemann/mini-HOWTO-cqcam.html
+ http://www.pingouin-land.com/howto/QuickCam-HOWTO.html
http://www.crynwr.com/qcpc/ QuickCam Third-Party Drivers
http://www.crynwr.com/qcpc/re.html Some Reverse Engineering
- http://cse.unl.edu/~cluening/gqcam/ v4l client
+ http://www.wirelesscouch.net/software/gqcam/ v4l client
http://phobos.illtel.denver.co.us/pub/qcread/ doesn't use v4l
ftp://ftp.cs.unm.edu/pub/chris/quickcam/ Has lots of drivers
http://www.cs.duke.edu/~reynolds/quickcam/ Has lots of information
diff --git a/Documentation/video4linux/README.cpia b/Documentation/video4linux/README.cpia
index 19cd3bf2498..8a747fee661 100644
--- a/Documentation/video4linux/README.cpia
+++ b/Documentation/video4linux/README.cpia
@@ -185,7 +185,7 @@ THANKS (in no particular order):
---------------------------------------------------------------------------
REFERENCES
- 1. http://www.risc.uni-linz.ac.at/people/ppregler
+ 1. http://www.risc.uni-linz.ac.at/
mailto:Peter_Pregler@email.com
2. see the file COPYING in the top directory of the kernel tree
3. http://webcam.sourceforge.net/
diff --git a/Documentation/video4linux/README.ivtv b/Documentation/video4linux/README.ivtv
index 73df22c40bf..42b06686eb7 100644
--- a/Documentation/video4linux/README.ivtv
+++ b/Documentation/video4linux/README.ivtv
@@ -10,7 +10,7 @@ Hauppauge PVR-350.
NOTE: this driver requires the latest encoder firmware (version 2.06.039, size
376836 bytes). Get the firmware from here:
-http://dl.ivtvdriver.org/ivtv/firmware/firmware.tar.gz
+http://dl.ivtvdriver.org/ivtv/firmware/
NOTE: 'normal' TV applications do not work with this driver, you need
an application that can handle MPEG input such as mplayer, xine, MythTV,
diff --git a/Documentation/video4linux/Zoran b/Documentation/video4linux/Zoran
index 0e89e767629..00e3f926781 100644
--- a/Documentation/video4linux/Zoran
+++ b/Documentation/video4linux/Zoran
@@ -174,7 +174,7 @@ and is used in Argentinia, Uruguay, an a few others
We do not talk about how the audio is broadcast !
A rather good sites about the TV standards are:
-http://www.sony.jp/ServiceArea/Voltage_map/
+http://www.sony.jp/support/
http://info.electronicwerkstatt.de/bereiche/fernsehtechnik/frequenzen_und_normen/Fernsehnormen/
and http://www.cabl.com/restaurant/channel.html
@@ -330,7 +330,7 @@ These extensions are known as the v4l/mjpeg extensions. See zoran.h for
details (structs/ioctls).
Information - video4linux:
-http://roadrunner.swansea.linux.org.uk/v4lapi.shtml
+http://linux.bytesex.org/v4l2/API.html
Documentation/video4linux/API.html
/usr/include/linux/videodev.h
@@ -390,7 +390,7 @@ BUZIOC_G_STATUS
Get the status of the input lines (video source connected/norm).
For programming example, please, look at lavrec.c and lavplay.c code in
-lavtools-1.2p2 package (URL: http://www.cicese.mx/~mirsev/DC10plus/)
+lavtools-1.2p2 package (URL: http://www.cicese.mx/)
and the 'examples' directory in the original Buz driver distribution.
Additional notes for software developers:
diff --git a/Documentation/video4linux/bttv/Cards b/Documentation/video4linux/bttv/Cards
index d3389655ad9..12217fc4972 100644
--- a/Documentation/video4linux/bttv/Cards
+++ b/Documentation/video4linux/bttv/Cards
@@ -802,7 +802,7 @@ Kworld (www.kworld.com.tw)
-JTT/ Justy Corp.http://www.justy.co.jp/ (www.jtt.com.jp website down)
+JTT/ Justy Corp.(http://www.jtt.ne.jp/)
---------------------------------------------------------------------
JTT-02 (JTT TV) "TV watchmate pro" (bt848)
@@ -828,7 +828,7 @@ Eline www.eline-net.com/
Eline Vision TVMaster / TVMaster FM (ELV-TVM/ ELV-TVM-FM) = LR26 (bt878)
Eline Vision TVMaster-2000 (ELV-TVM-2000, ELV-TVM-2000-FM)= LR138 (saa713x)
-Spirit http://www.spiritmodems.com.au/
+Spirit
------
Spirit TV Tuner/Video Capture Card (bt848)
@@ -959,6 +959,6 @@ Asus www.asuscom.com
Hoontech
--------
-http://www.hoontech.com/korean/download/down_driver_list03.html
+http://www.hoontech.de/
HART Vision 848 (H-ART Vision 848)
HART Vision 878 (H-Art Vision 878)
diff --git a/Documentation/video4linux/bttv/MAKEDEV b/Documentation/video4linux/bttv/MAKEDEV
index 6c29ba43b6c..9d112f7fd5f 100644
--- a/Documentation/video4linux/bttv/MAKEDEV
+++ b/Documentation/video4linux/bttv/MAKEDEV
@@ -14,7 +14,7 @@ function makedev () {
ln -s /dev/${1}0 /dev/$1
}
-# see http://roadrunner.swansea.uk.linux.org/v4lapi.shtml
+# see http://linux.bytesex.org/v4l2/API.html
echo "*** new device names ***"
makedev video 0
diff --git a/Documentation/video4linux/bttv/Specs b/Documentation/video4linux/bttv/Specs
index 79b9e576fe7..f32466cdae0 100644
--- a/Documentation/video4linux/bttv/Specs
+++ b/Documentation/video4linux/bttv/Specs
@@ -1,3 +1,3 @@
Philips http://www.Semiconductors.COM/pip/
-Conexant http://www.conexant.com/techinfo/default.asp
-Micronas http://www.micronas.de/pages/product_documentation/index.html
+Conexant http://www.conexant.com/
+Micronas http://www.micronas.com/en/home/index.html
diff --git a/Documentation/video4linux/cx88/hauppauge-wintv-cx88-ir.txt b/Documentation/video4linux/cx88/hauppauge-wintv-cx88-ir.txt
index faccee68f60..f4329a38878 100644
--- a/Documentation/video4linux/cx88/hauppauge-wintv-cx88-ir.txt
+++ b/Documentation/video4linux/cx88/hauppauge-wintv-cx88-ir.txt
@@ -44,7 +44,7 @@ http://www.atmel.com/dyn/resources/prod_documents/doc2817.pdf
This data sheet (google search) seems to have a lovely description of the
RC5 basics
-http://users.pandora.be/nenya/electronics/rc5/ and more data
+http://www.nenya.be/beor/electronics/rc5.htm and more data
http://www.ee.washington.edu/circuit_archive/text/ir_decode.txt
and even a reference to how to decode a bi-phase data stream.
diff --git a/Documentation/video4linux/gspca.txt b/Documentation/video4linux/gspca.txt
index f13eb036c43..56ba7bba716 100644
--- a/Documentation/video4linux/gspca.txt
+++ b/Documentation/video4linux/gspca.txt
@@ -29,8 +29,12 @@ zc3xx 041e:4029 Creative WebCam Vista Pro
zc3xx 041e:4034 Creative Instant P0620
zc3xx 041e:4035 Creative Instant P0620D
zc3xx 041e:4036 Creative Live !
+sq930x 041e:4038 Creative Joy-IT
zc3xx 041e:403a Creative Nx Pro 2
spca561 041e:403b Creative Webcam Vista (VF0010)
+sq930x 041e:403c Creative Live! Ultra
+sq930x 041e:403d Creative Live! Ultra for Notebooks
+sq930x 041e:4041 Creative Live! Motion
zc3xx 041e:4051 Creative Live!Cam Notebook Pro (VF0250)
ov519 041e:4052 Creative Live! VISTA IM
zc3xx 041e:4053 Creative Live!Cam Video IM
@@ -138,6 +142,7 @@ finepix 04cb:013d Fujifilm FinePix unknown model
finepix 04cb:013f Fujifilm FinePix F420
sunplus 04f1:1001 JVC GC A50
spca561 04fc:0561 Flexcam 100
+spca1528 04fc:1528 Sunplus MD80 clone
sunplus 04fc:500c Sunplus CA500C
sunplus 04fc:504a Aiptek Mini PenCam 1.3
sunplus 04fc:504b Maxell MaxPocket LE 1.3
@@ -253,6 +258,7 @@ pac7302 093a:2620 Apollo AC-905
pac7302 093a:2621 PAC731x
pac7302 093a:2622 Genius Eye 312
pac7302 093a:2624 PAC7302
+pac7302 093a:2625 Genius iSlim 310
pac7302 093a:2626 Labtec 2200
pac7302 093a:2628 Genius iLook 300
pac7302 093a:2629 Genious iSlim 300
@@ -362,6 +368,8 @@ sq905c 2770:9052 Disney pix micro 2 (VGA)
sq905c 2770:905c All 11 known cameras with this ID
sq905 2770:9120 All 24 known cameras with this ID
sq905c 2770:913d All 4 known cameras with this ID
+sq930x 2770:930b Sweex Motion Tracking / I-Tec iCam Tracer
+sq930x 2770:930c Trust WB-3500T / NSG Robbie 2.0
spca500 2899:012c Toptro Industrial
ov519 8020:ef04 ov519
spca508 8086:0110 Intel Easy PC Camera
diff --git a/Documentation/video4linux/hauppauge-wintv-cx88-ir.txt b/Documentation/video4linux/hauppauge-wintv-cx88-ir.txt
index faccee68f60..a2fd363c40c 100644
--- a/Documentation/video4linux/hauppauge-wintv-cx88-ir.txt
+++ b/Documentation/video4linux/hauppauge-wintv-cx88-ir.txt
@@ -44,7 +44,7 @@ http://www.atmel.com/dyn/resources/prod_documents/doc2817.pdf
This data sheet (google search) seems to have a lovely description of the
RC5 basics
-http://users.pandora.be/nenya/electronics/rc5/ and more data
+http://www.nenya.be/beor/electronics/rc5.htm and more data
http://www.ee.washington.edu/circuit_archive/text/ir_decode.txt
and even a reference to how to decode a bi-phase data stream.
diff --git a/Documentation/video4linux/ibmcam.txt b/Documentation/video4linux/ibmcam.txt
index 397a94eb77b..a51055211e6 100644
--- a/Documentation/video4linux/ibmcam.txt
+++ b/Documentation/video4linux/ibmcam.txt
@@ -27,9 +27,8 @@ SUPPORTED CAMERAS:
Xirlink "C-It" camera, also known as "IBM PC Camera".
The device uses proprietary ASIC (and compression method);
-it is manufactured by Xirlink. See http://www.xirlink.com/
-(renamed to http://www.veo.com), http://www.ibmpccamera.com,
-or http://www.c-itnow.com/ for details and pictures.
+it is manufactured by Xirlink. See http://xirlinkwebcam.sourceforge.net,
+http://www.ibmpccamera.com, or http://www.c-itnow.com/ for details and pictures.
This very chipset ("X Chip", as marked at the factory)
is used in several other cameras, and they are supported
diff --git a/Documentation/video4linux/se401.txt b/Documentation/video4linux/se401.txt
index 7b9d1c960a1..bd6526ec8dd 100644
--- a/Documentation/video4linux/se401.txt
+++ b/Documentation/video4linux/se401.txt
@@ -49,6 +49,6 @@ order to increase the throughput (and thus framerate).
HELP:
The latest info on this driver can be found at:
-http://www.chello.nl/~j.vreeken/se401/
+http://members.chello.nl/~j.vreeken/se401/
And questions to me can be send to:
pe1rxq@amsat.org
diff --git a/Documentation/video4linux/w9966.txt b/Documentation/video4linux/w9966.txt
index 78a651254b8..855024525fd 100644
--- a/Documentation/video4linux/w9966.txt
+++ b/Documentation/video4linux/w9966.txt
@@ -24,7 +24,7 @@ where every two pixels take 4 bytes. In SDL (www.libsdl.org) this format
is called VIDEO_PALETTE_YUV422 (16 bpp).
A minimal test application (with source) is available from:
- http://hem.fyristorg.com/mogul/w9966.html
+ http://www.slackwaresupport.com/howtos/Webcam-HOWTO
The slow framerate is due to missing DMA ECP read support in the
parport drivers. I might add working EPP support later.
diff --git a/Documentation/vm/page-types.c b/Documentation/vm/page-types.c
index 66e9358e214..ccd951fa94e 100644
--- a/Documentation/vm/page-types.c
+++ b/Documentation/vm/page-types.c
@@ -694,7 +694,7 @@ static void usage(void)
#endif
" -l|--list Show page details in ranges\n"
" -L|--list-each Show page details one by one\n"
-" -N|--no-summary Don't show summay info\n"
+" -N|--no-summary Don't show summary info\n"
" -X|--hwpoison hwpoison pages\n"
" -x|--unpoison unpoison pages\n"
" -h|--help Show this usage message\n"
diff --git a/Documentation/w1/masters/ds2482 b/Documentation/w1/masters/ds2482
index 299b91c7609..56f8edace6a 100644
--- a/Documentation/w1/masters/ds2482
+++ b/Documentation/w1/masters/ds2482
@@ -6,8 +6,8 @@ Supported chips:
Prefix: 'ds2482'
Addresses scanned: None
Datasheets:
- http://pdfserv.maxim-ic.com/en/ds/DS2482-100-DS2482S-100.pdf
- http://pdfserv.maxim-ic.com/en/ds/DS2482-800-DS2482S-800.pdf
+ http://datasheets.maxim-ic.com/en/ds/DS2482-100.pdf
+ http://datasheets.maxim-ic.com/en/ds/DS2482-800.pdf
Author: Ben Gardner <bgardner@wabtec.com>
diff --git a/Documentation/w1/masters/mxc-w1 b/Documentation/w1/masters/mxc-w1
index 97f6199a7f3..38be1ad6553 100644
--- a/Documentation/w1/masters/mxc-w1
+++ b/Documentation/w1/masters/mxc-w1
@@ -5,7 +5,8 @@ Supported chips:
* Freescale MX27, MX31 and probably other i.MX SoCs
Datasheets:
http://www.freescale.com/files/32bit/doc/data_sheet/MCIMX31.pdf?fpsp=1
- http://www.freescale.com/files/dsp/MCIMX27.pdf?fpsp=1
+ http://cache.freescale.com/files/dsp/doc/archive/MCIMX27.pdf?fsrch=1&WT_TYPE=
+ Data%20Sheets&WT_VENDOR=FREESCALE&WT_FILE_FORMAT=pdf&WT_ASSET=Documentation
Author: Originally based on Freescale code, prepared for mainline by
Sascha Hauer <s.hauer@pengutronix.de>
diff --git a/Documentation/w1/masters/omap-hdq b/Documentation/w1/masters/omap-hdq
index ca722e09b6a..884dc284b21 100644
--- a/Documentation/w1/masters/omap-hdq
+++ b/Documentation/w1/masters/omap-hdq
@@ -7,7 +7,7 @@ Supported chips:
A useful link about HDQ basics:
===============================
-http://focus.ti.com/lit/an/slua408/slua408.pdf
+http://focus.ti.com/lit/an/slua408a/slua408a.pdf
Description:
============
diff --git a/Documentation/x86/zero-page.txt b/Documentation/x86/zero-page.txt
index feb37e17701..cf5437deda8 100644
--- a/Documentation/x86/zero-page.txt
+++ b/Documentation/x86/zero-page.txt
@@ -18,6 +18,7 @@ Offset Proto Name Meaning
080/010 ALL hd0_info hd0 disk parameter, OBSOLETE!!
090/010 ALL hd1_info hd1 disk parameter, OBSOLETE!!
0A0/010 ALL sys_desc_table System description table (struct sys_desc_table)
+0B0/010 ALL olpc_ofw_header OLPC's OpenFirmware CIF and friends
140/080 ALL edid_info Video mode setup (struct edid_info)
1C0/020 ALL efi_info EFI 32 information (struct efi_info)
1E0/004 ALL alk_mem_k Alternative mem check, in KB
diff --git a/Documentation/zh_CN/HOWTO b/Documentation/zh_CN/HOWTO
index 3d80e8af36e..69160779e43 100644
--- a/Documentation/zh_CN/HOWTO
+++ b/Documentation/zh_CN/HOWTO
@@ -112,7 +112,7 @@ Linux内核代ç ä¸­åŒ…å«æœ‰å¤§é‡çš„文档。这些文档对于学习如何与
其他关于如何正确地生æˆè¡¥ä¸çš„优秀文档包括:
"The Perfect Patch"
- http://www.zip.com.au/~akpm/linux/patches/stuff/tpp.txt
+ http://userweb.kernel.org/~akpm/stuff/tpp.txt
"Linux kernel patch submission format"
http://linux.yyz.us/patch-format.html
@@ -168,7 +168,7 @@ Linux内核代ç ä¸­åŒ…å«æœ‰å¤§é‡çš„文档。这些文档对于学习如何与
如果你想加入内核开å‘社区并å助完æˆä¸€äº›ä»»åŠ¡ï¼Œå´æ‰¾ä¸åˆ°ä»Žå“ªé‡Œå¼€å§‹ï¼Œå¯ä»¥è®¿é—®
“Linux内核房管员â€è®¡åˆ’:
- http://janitor.kernelnewbies.org/
+ http://kernelnewbies.org/KernelJanitors
这是æžä½³çš„起点。它æ供一个相对简å•çš„任务列表,列出内核代ç ä¸­éœ€è¦è¢«é‡æ–°
æ•´ç†æˆ–者改正的地方。通过和负责这个计划的开å‘者们一åŒå·¥ä½œï¼Œä½ ä¼šå­¦åˆ°å°†è¡¥ä¸
集æˆè¿›å†…核的基本原ç†ã€‚如果还没有决定下一步è¦åšä»€ä¹ˆçš„è¯ï¼Œä½ è¿˜å¯èƒ½ä¼šå¾—到方
@@ -515,7 +515,7 @@ Linux内核社区并ä¸å–œæ¬¢ä¸€ä¸‹æŽ¥æ”¶å¤§æ®µçš„代ç ã€‚修改需è¦è¢«æ°å½“
想了解它具体应该看起æ¥åƒä»€ä¹ˆï¼Œè¯·æŸ¥é˜…以下文档中的“ChangeLogâ€ç« èŠ‚:
“The Perfect Patchâ€
- http://www.zip.com.au/~akpm/linux/patches/stuff/tpp.txt
+ http://userweb.kernel.org/~akpm/stuff/tpp.txt
这些事情有时候åšèµ·æ¥å¾ˆéš¾ã€‚è¦åœ¨ä»»ä½•æ–¹é¢éƒ½åšåˆ°å®Œç¾Žå¯èƒ½éœ€è¦å¥½å‡ å¹´æ—¶é—´ã€‚这是
@@ -525,7 +525,7 @@ Linux内核社区并ä¸å–œæ¬¢ä¸€ä¸‹æŽ¥æ”¶å¤§æ®µçš„代ç ã€‚修改需è¦è¢«æ°å½“
---------------
æ„Ÿè°¢Paolo Ciarrocchiå…许“开å‘æµç¨‹â€éƒ¨åˆ†åŸºäºŽä»–所写的文章
-(http://linux.tar.bz/articles/2.6-development_process),感谢Randy
+(http://www.kerneltravel.net/newbie/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
diff --git a/Documentation/zh_CN/SubmittingDrivers b/Documentation/zh_CN/SubmittingDrivers
index 5f4815c63ec..c27b0f6cdd3 100644
--- a/Documentation/zh_CN/SubmittingDrivers
+++ b/Documentation/zh_CN/SubmittingDrivers
@@ -165,4 +165,4 @@ Linux USB项目:
http://www.fenrus.org/how-to-not-write-a-device-driver-paper.pdf
内核清æ´å·¥ (Kernel Janitor):
- http://janitor.kernelnewbies.org/
+ http://kernelnewbies.org/KernelJanitors
diff --git a/Documentation/zh_CN/SubmittingPatches b/Documentation/zh_CN/SubmittingPatches
index 985c92e20b7..9a1a6e1ed09 100644
--- a/Documentation/zh_CN/SubmittingPatches
+++ b/Documentation/zh_CN/SubmittingPatches
@@ -83,7 +83,7 @@ Quilt:
http://savannah.nongnu.org/projects/quilt
Andrew Morton çš„è¡¥ä¸è„šæœ¬:
-http://www.zip.com.au/~akpm/linux/patches/
+http://userweb.kernel.org/~akpm/stuff/patch-scripts.tar.gz
作为这些脚本的替代,quilt 是值得推èçš„è¡¥ä¸ç®¡ç†å·¥å…·(看上é¢çš„链接)。
2)æ述你的改动。
@@ -166,7 +166,7 @@ MAITAINERS 文件里的)å‘é€ä¸€ä¸ªæ‰‹å†Œé¡µï¼ˆman-pages)补ä¸ï¼Œæˆ–者至
人拷è´ï¼Œåªè¦å®ƒæ˜¯ç碎的)
任何文件的作者/维护者对该文件的改动(例如 patch monkey 在é‡ä¼ æ¨¡å¼ä¸‹ï¼‰
-URL: <http://www.kernel.org/pub/linux/kernel/people/bunk/trivial/>
+EMAIL: trivial@kernel.org
(译注,关于“ç碎补ä¸â€çš„一些说明:因为原文的这一部分写得比较简å•ï¼Œæ‰€ä»¥ä¸å¾—ä¸
è¿ä¾‹å†™ä¸€ä¸‹è¯‘注。"trivial"这个英文å•è¯çš„本æ„是“ç碎的,ä¸é‡è¦çš„。â€ä½†æ˜¯åœ¨è¿™é‡Œ
@@ -394,7 +394,7 @@ Static inline 函数相比å®æ¥è¯´ï¼Œæ˜¯å¥½å¾—多的选择。Static inline 函æ
----------------
Andrew Morton, "The perfect patch" (tpp).
- <http://www.zip.com.au/~akpm/linux/patches/stuff/tpp.txt>
+ <http://userweb.kernel.org/~akpm/stuff/tpp.txt>
Jeff Garzik, "Linux kernel patch submission format".
<http://linux.yyz.us/patch-format.html>
diff --git a/Documentation/zh_CN/sparse.txt b/Documentation/zh_CN/sparse.txt
index 75992a603ae..cc144e58151 100644
--- a/Documentation/zh_CN/sparse.txt
+++ b/Documentation/zh_CN/sparse.txt
@@ -22,7 +22,7 @@ Documentation/sparse.txt 的中文翻译
---------------------------------------------------------------------
Copyright 2004 Linus Torvalds
-Copyright 2004 Pavel Machek <pavel@suse.cz>
+Copyright 2004 Pavel Machek <pavel@ucw.cz>
Copyright 2006 Bob Copeland <me@bobcopeland.com>
使用 sparse 工具åšç±»åž‹æ£€æŸ¥
diff --git a/MAINTAINERS b/MAINTAINERS
index 02f75fccac2..3f49df2d977 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -313,11 +313,9 @@ S: Maintained
F: drivers/hwmon/adm1029.c
ADM8211 WIRELESS DRIVER
-M: Michael Wu <flamingice@sourmilk.net>
L: linux-wireless@vger.kernel.org
W: http://linuxwireless.org/
-T: git git://git.kernel.org/pub/scm/linux/kernel/git/mwu/mac80211-drivers.git
-S: Maintained
+S: Orphan
F: drivers/net/wireless/adm8211.*
ADT746X FAN DRIVER
@@ -1369,7 +1367,7 @@ BROADCOM BNX2X 10 GIGABIT ETHERNET DRIVER
M: Eilon Greenstein <eilong@broadcom.com>
L: netdev@vger.kernel.org
S: Supported
-F: drivers/net/bnx2x*
+F: drivers/net/bnx2x/
BROADCOM TG3 GIGABIT ETHERNET DRIVER
M: Matt Carlson <mcarlson@broadcom.com>
@@ -1571,6 +1569,16 @@ L: platform-driver-x86@vger.kernel.org
S: Supported
F: drivers/platform/x86/classmate-laptop.c
+COCCINELLE/Semantic Patches (SmPL)
+M: Julia Lawall <julia@diku.dk>
+M: Gilles Muller <Gilles.Muller@lip6.fr>
+M: Nicolas Palix <npalix@diku.dk>
+L: cocci@diku.dk (moderated for non-subscribers)
+W: http://coccinelle.lip6.fr/
+S: Supported
+F: scripts/coccinelle/
+F: scripts/coccicheck
+
CODA FILE SYSTEM
M: Jan Harkes <jaharkes@cs.cmu.edu>
M: coda@cs.cmu.edu
@@ -1771,6 +1779,13 @@ W: http://www.openfabrics.org
S: Supported
F: drivers/infiniband/hw/cxgb4/
+CXGB4VF ETHERNET DRIVER (CXGB4VF)
+M: Casey Leedom <leedom@chelsio.com>
+L: netdev@vger.kernel.org
+W: http://www.chelsio.com
+S: Supported
+F: drivers/net/cxgb4vf/
+
CYBERPRO FB DRIVER
M: Russell King <linux@arm.linux.org.uk>
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
@@ -2222,6 +2237,7 @@ S: Maintained
F: drivers/net/eth16i.c
EXT2 FILE SYSTEM
+M: Jan Kara <jack@suse.cz>
L: linux-ext4@vger.kernel.org
S: Maintained
F: Documentation/filesystems/ext2.txt
@@ -2229,8 +2245,9 @@ F: fs/ext2/
F: include/linux/ext2*
EXT3 FILE SYSTEM
+M: Jan Kara <jack@suse.cz>
M: Andrew Morton <akpm@linux-foundation.org>
-M: Andreas Dilger <adilger@sun.com>
+M: Andreas Dilger <adilger.kernel@dilger.ca>
L: linux-ext4@vger.kernel.org
S: Maintained
F: Documentation/filesystems/ext3.txt
@@ -2239,7 +2256,7 @@ F: include/linux/ext3*
EXT4 FILE SYSTEM
M: "Theodore Ts'o" <tytso@mit.edu>
-M: Andreas Dilger <adilger@sun.com>
+M: Andreas Dilger <adilger.kernel@dilger.ca>
L: linux-ext4@vger.kernel.org
W: http://ext4.wiki.kernel.org
Q: http://patchwork.ozlabs.org/project/linux-ext4/list/
@@ -2307,6 +2324,7 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/ieee1394/linux1394-2.6.git
S: Maintained
F: drivers/firewire/
F: include/linux/firewire*.h
+F: tools/firewire/
FIRMWARE LOADER (request_firmware)
S: Orphan
@@ -2620,6 +2638,14 @@ S: Maintained
F: Documentation/blockdev/cpqarray.txt
F: drivers/block/cpqarray.*
+HEWLETT-PACKARD SMART ARRAY RAID DRIVER (hpsa)
+M: Stephen M. Cameron <scameron@beardog.cce.hp.com>
+L: iss_storagedev@hp.com
+S: Supported
+F: Documentation/scsi/hpsa.txt
+F: drivers/scsi/hpsa*.[ch]
+F: include/linux/cciss*.h
+
HEWLETT-PACKARD SMART CISS RAID DRIVER (cciss)
M: Mike Miller <mike.miller@hp.com>
L: iss_storagedev@hp.com
@@ -3253,8 +3279,8 @@ F: fs/autofs4/
KERNEL BUILD + files below scripts/ (unless maintained elsewhere)
M: Michal Marek <mmarek@suse.cz>
-T: git git://repo.or.cz/linux-kbuild.git for-next
-T: git git://repo.or.cz/linux-kbuild.git for-linus
+T: git git://git.kernel.org/pub/scm/linux/kernel/git/mmarek/kbuild-2.6.git for-next
+T: git git://git.kernel.org/pub/scm/linux/kernel/git/mmarek/kbuild-2.6.git rc-fixes
L: linux-kbuild@vger.kernel.org
S: Maintained
F: Documentation/kbuild/
@@ -3380,13 +3406,6 @@ F: include/linux/kmemleak.h
F: mm/kmemleak.c
F: mm/kmemleak-test.c
-KMEMTRACE
-M: Eduard - Gabriel Munteanu <eduard.munteanu@linux360.ro>
-S: Maintained
-F: Documentation/trace/kmemtrace.txt
-F: include/linux/kmemtrace.h
-F: kernel/trace/kmemtrace.c
-
KPROBES
M: Ananth N Mavinakayanahalli <ananth@in.ibm.com>
M: Anil S Keshavamurthy <anil.s.keshavamurthy@intel.com>
@@ -3686,7 +3705,7 @@ F: include/linux/mv643xx.h
MARVELL MWL8K WIRELESS DRIVER
M: Lennert Buytenhek <buytenh@wantstofly.org>
L: linux-wireless@vger.kernel.org
-S: Maintained
+S: Odd Fixes
F: drivers/net/wireless/mwl8k.c
MARVELL SOC MMC/SD/SDIO CONTROLLER DRIVER
@@ -3915,17 +3934,19 @@ L: netem@lists.linux-foundation.org
S: Maintained
F: net/sched/sch_netem.c
-NETERION (S2IO) 10GbE DRIVER (xframe/vxge)
-M: Ramkrishna Vepa <ram.vepa@neterion.com>
-M: Rastapur Santosh <santosh.rastapur@neterion.com>
-M: Sivakumar Subramani <sivakumar.subramani@neterion.com>
-M: Sreenivasa Honnur <sreenivasa.honnur@neterion.com>
+NETERION 10GbE DRIVERS (s2io/vxge)
+M: Ramkrishna Vepa <ramkrishna.vepa@exar.com>
+M: Sivakumar Subramani <sivakumar.subramani@exar.com>
+M: Sreenivasa Honnur <sreenivasa.honnur@exar.com>
+M: Jon Mason <jon.mason@exar.com>
L: netdev@vger.kernel.org
W: http://trac.neterion.com/cgi-bin/trac.cgi/wiki/Linux?Anonymous
W: http://trac.neterion.com/cgi-bin/trac.cgi/wiki/X3100Linux?Anonymous
S: Supported
F: Documentation/networking/s2io.txt
F: drivers/net/s2io*
+F: Documentation/networking/vxge.txt
+F: drivers/net/vxge/
NETFILTER/IPTABLES/IPCHAINS
P: Rusty Russell
@@ -4272,10 +4293,9 @@ F: include/scsi/osd_*
F: fs/exofs/
P54 WIRELESS DRIVER
-M: Michael Wu <flamingice@sourmilk.net>
+M: Christian Lamparter <chunkeey@googlemail.com>
L: linux-wireless@vger.kernel.org
-W: http://prism54.org
-T: git git://git.kernel.org/pub/scm/linux/kernel/git/mwu/mac80211-drivers.git
+W: http://wireless.kernel.org/en/users/Drivers/p54
S: Maintained
F: drivers/net/wireless/p54/
@@ -4537,7 +4557,7 @@ PRISM54 WIRELESS DRIVER
M: "Luis R. Rodriguez" <mcgrof@gmail.com>
L: linux-wireless@vger.kernel.org
W: http://prism54.org
-S: Maintained
+S: Obsolete
F: drivers/net/wireless/prism54/
PROMISE DC4030 CACHING DISK CONTROLLER DRIVER
@@ -4717,7 +4737,7 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/ivd/rt2x00.git
F: drivers/net/wireless/rt2x00/
RAMDISK RAM BLOCK DEVICE DRIVER
-M: Nick Piggin <npiggin@suse.de>
+M: Nick Piggin <npiggin@kernel.dk>
S: Maintained
F: Documentation/blockdev/ramdisk.txt
F: drivers/block/brd.c
@@ -4733,9 +4753,8 @@ S: Maintained
F: drivers/rapidio/
RAYLINK/WEBGEAR 802.11 WIRELESS LAN DRIVER
-M: Corey Thomas <coreythomas@charter.net>
L: linux-wireless@vger.kernel.org
-S: Maintained
+S: Orphan
F: drivers/net/wireless/ray*
RCUTORTURE MODULE
@@ -5061,6 +5080,14 @@ S: Supported
F: include/linux/selinux*
F: security/selinux/
+APPARMOR SECURITY MODULE
+M: John Johansen <john.johansen@canonical.com>
+L: apparmor@lists.ubuntu.com (subscribers-only, general discussion)
+W: apparmor.wiki.kernel.org
+T: git git://git.kernel.org/pub/scm/linux/kernel/git/jj/apparmor-dev.git
+S: Supported
+F: security/apparmor/
+
SENSABLE PHANTOM
M: Jiri Slaby <jirislaby@gmail.com>
S: Maintained
@@ -5336,7 +5363,7 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/davem/sparc-2.6.git
T: git git://git.kernel.org/pub/scm/linux/kernel/git/davem/sparc-next-2.6.git
S: Maintained
F: arch/sparc/
-F: drivers/sbus
+F: drivers/sbus/
SPARC SERIAL DRIVERS
M: "David S. Miller" <davem@davemloft.net>
@@ -5605,7 +5632,7 @@ L: tomoyo-users-en@lists.sourceforge.jp (subscribers-only, for developers and us
L: tomoyo-dev@lists.sourceforge.jp (subscribers-only, for developers in Japanese)
L: tomoyo-users@lists.sourceforge.jp (subscribers-only, for users in Japanese)
W: http://tomoyo.sourceforge.jp/
-T: quilt http://svn.sourceforge.jp/svnroot/tomoyo/trunk/2.2.x/tomoyo-lsm/patches/
+T: quilt http://svn.sourceforge.jp/svnroot/tomoyo/trunk/2.3.x/tomoyo-lsm/patches/
S: Maintained
F: security/tomoyo/
@@ -5654,7 +5681,7 @@ TRACING
M: Steven Rostedt <rostedt@goodmis.org>
M: Frederic Weisbecker <fweisbec@gmail.com>
M: Ingo Molnar <mingo@redhat.com>
-T: git git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip.git tracing/core
+T: git git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip.git perf/core
S: Maintained
F: Documentation/trace/ftrace.txt
F: arch/*/*/*/ftrace.h
@@ -6060,10 +6087,9 @@ F: Documentation/video4linux/zc0301.txt
F: drivers/media/video/zc0301/
USB ZD1201 DRIVER
-M: Jeroen Vreeken <pe1rxq@amsat.org>
-L: linux-usb@vger.kernel.org
+L: linux-wireless@vger.kernel.org
W: http://linux-lc100020.sourceforge.net
-S: Maintained
+S: Orphan
F: drivers/net/wireless/zd1201.*
USB ZR364XX DRIVER
@@ -6251,14 +6277,6 @@ F: Documentation/watchdog/
F: drivers/watchdog/
F: include/linux/watchdog.h
-WAVELAN NETWORK DRIVER & WIRELESS EXTENSIONS
-M: Jean Tourrilhes <jt@hpl.hp.com>
-L: linux-wireless@vger.kernel.org
-W: http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/
-S: Maintained
-F: Documentation/networking/wavelan.txt
-F: drivers/staging/wavelan/
-
WD7000 SCSI DRIVER
M: Miroslav Zagorac <zaga@fly.cc.fer.hr>
L: linux-scsi@vger.kernel.org
diff --git a/Makefile b/Makefile
index 141da26fda4..7431c283f15 100644
--- a/Makefile
+++ b/Makefile
@@ -332,10 +332,9 @@ CHECK = sparse
CHECKFLAGS := -D__linux__ -Dlinux -D__STDC__ -Dunix -D__unix__ \
-Wbitwise -Wno-return-void $(CF)
-MODFLAGS = -DMODULE
-CFLAGS_MODULE = $(MODFLAGS)
-AFLAGS_MODULE = $(MODFLAGS)
-LDFLAGS_MODULE = -T $(srctree)/scripts/module-common.lds
+CFLAGS_MODULE =
+AFLAGS_MODULE =
+LDFLAGS_MODULE =
CFLAGS_KERNEL =
AFLAGS_KERNEL =
CFLAGS_GCOV = -fprofile-arcs -ftest-coverage
@@ -354,7 +353,12 @@ KBUILD_CFLAGS := -Wall -Wundef -Wstrict-prototypes -Wno-trigraphs \
-Werror-implicit-function-declaration \
-Wno-format-security \
-fno-delete-null-pointer-checks
+KBUILD_AFLAGS_KERNEL :=
+KBUILD_CFLAGS_KERNEL :=
KBUILD_AFLAGS := -D__ASSEMBLY__
+KBUILD_AFLAGS_MODULE := -DMODULE
+KBUILD_CFLAGS_MODULE := -DMODULE
+KBUILD_LDFLAGS_MODULE := -T $(srctree)/scripts/module-common.lds
# Read KERNELRELEASE from include/config/kernel.release (if it exists)
KERNELRELEASE = $(shell cat include/config/kernel.release 2> /dev/null)
@@ -369,6 +373,8 @@ export HOSTCXX HOSTCXXFLAGS LDFLAGS_MODULE CHECK CHECKFLAGS
export KBUILD_CPPFLAGS NOSTDINC_FLAGS LINUXINCLUDE OBJCOPYFLAGS LDFLAGS
export KBUILD_CFLAGS CFLAGS_KERNEL CFLAGS_MODULE CFLAGS_GCOV
export KBUILD_AFLAGS AFLAGS_KERNEL AFLAGS_MODULE
+export KBUILD_AFLAGS_MODULE KBUILD_CFLAGS_MODULE KBUILD_LDFLAGS_MODULE
+export KBUILD_AFLAGS_KERNEL KBUILD_CFLAGS_KERNEL
# When compiling out-of-tree modules, put MODVERDIR in the module
# tree rather than in the kernel tree. The kernel tree might
@@ -412,9 +418,9 @@ endif
# of make so .config is not included in this case either (for *config).
no-dot-config-targets := clean mrproper distclean \
- cscope TAGS tags help %docs check% \
+ cscope TAGS tags help %docs check% coccicheck \
include/linux/version.h headers_% \
- kernelrelease kernelversion
+ kernelversion %src-pkg
config-targets := 0
mixed-targets := 0
@@ -526,7 +532,7 @@ endif # $(dot-config)
# The all: target is the default when no target is given on the
# command line.
# This allow a user to issue only 'make' to build a kernel including modules
-# Defaults vmlinux but it is usually overridden in the arch makefile
+# Defaults to vmlinux, but the arch makefile usually adds further targets
all: vmlinux
ifdef CONFIG_CC_OPTIMIZE_FOR_SIZE
@@ -557,6 +563,10 @@ KBUILD_CFLAGS += -g
KBUILD_AFLAGS += -gdwarf-2
endif
+ifdef CONFIG_DEBUG_INFO_REDUCED
+KBUILD_CFLAGS += $(call cc-option, -femit-struct-debug-baseonly)
+endif
+
ifdef CONFIG_FUNCTION_TRACER
KBUILD_CFLAGS += -pg
endif
@@ -603,7 +613,7 @@ endif
# Use --build-id when available.
LDFLAGS_BUILD_ID = $(patsubst -Wl$(comma)%,%,\
$(call cc-ldoption, -Wl$(comma)--build-id,))
-LDFLAGS_MODULE += $(LDFLAGS_BUILD_ID)
+KBUILD_LDFLAGS_MODULE += $(LDFLAGS_BUILD_ID)
LDFLAGS_vmlinux += $(LDFLAGS_BUILD_ID)
ifeq ($(CONFIG_STRIP_ASM_SYMS),y)
@@ -1158,6 +1168,8 @@ distclean: mrproper
# rpm target kept for backward compatibility
package-dir := $(srctree)/scripts/package
+%src-pkg: FORCE
+ $(Q)$(MAKE) $(build)=$(package-dir) $@
%pkg: include/config/kernel.release FORCE
$(Q)$(MAKE) $(build)=$(package-dir) $@
rpm: include/config/kernel.release FORCE
@@ -1209,8 +1221,9 @@ help:
@echo ' includecheck - Check for duplicate included header files'
@echo ' export_report - List the usages of all exported symbols'
@echo ' headers_check - Sanity check on exported headers'
- @echo ' headerdep - Detect inclusion cycles in headers'; \
- echo ''
+ @echo ' headerdep - Detect inclusion cycles in headers'
+ @$(MAKE) -f $(srctree)/scripts/Makefile.help checker-help
+ @echo ''
@echo 'Kernel packaging:'
@$(MAKE) $(build)=$(package-dir) help
@echo ''
@@ -1369,6 +1382,9 @@ versioncheck:
-name '*.[hcS]' -type f -print | sort \
| xargs $(PERL) -w $(srctree)/scripts/checkversion.pl
+coccicheck:
+ $(Q)$(CONFIG_SHELL) $(srctree)/scripts/$@
+
namespacecheck:
$(PERL) $(srctree)/scripts/namespace.pl
@@ -1393,9 +1409,9 @@ checkstack:
$(OBJDUMP) -d vmlinux $$(find . -name '*.ko') | \
$(PERL) $(src)/scripts/checkstack.pl $(CHECKSTACK_ARCH)
-kernelrelease:
- $(if $(wildcard include/config/kernel.release), $(Q)echo $(KERNELRELEASE), \
- $(error kernelrelease not valid - run 'make prepare' to update it))
+kernelrelease: include/config/kernel.release
+ @echo $(KERNELRELEASE)
+
kernelversion:
@echo $(KERNELVERSION)
@@ -1472,6 +1488,7 @@ cmd_crmodverdir = $(Q)mkdir -p $(MODVERDIR) \
$(if $(KBUILD_MODULES),; rm -f $(MODVERDIR)/*)
a_flags = -Wp,-MD,$(depfile) $(KBUILD_AFLAGS) $(AFLAGS_KERNEL) \
+ $(KBUILD_AFLAGS_KERNEL) \
$(NOSTDINC_FLAGS) $(LINUXINCLUDE) $(KBUILD_CPPFLAGS) \
$(modkern_aflags) $(EXTRA_AFLAGS) $(AFLAGS_$(basetarget).o)
diff --git a/arch/Kconfig b/arch/Kconfig
index acda512da2e..4877a8c8ee1 100644
--- a/arch/Kconfig
+++ b/arch/Kconfig
@@ -151,4 +151,11 @@ config HAVE_MIXED_BREAKPOINTS_REGS
config HAVE_USER_RETURN_NOTIFIER
bool
+config HAVE_PERF_EVENTS_NMI
+ bool
+ help
+ System hardware can generate an NMI using the perf event
+ subsystem. Also has support for calculating CPU cycle events
+ to determine how many clock cycles in a given period.
+
source "kernel/gcov/Kconfig"
diff --git a/arch/alpha/Kconfig b/arch/alpha/Kconfig
index 3e2e540a0f2..b9647bb66d1 100644
--- a/arch/alpha/Kconfig
+++ b/arch/alpha/Kconfig
@@ -47,10 +47,6 @@ config GENERIC_CALIBRATE_DELAY
bool
default y
-config GENERIC_TIME
- bool
- default y
-
config GENERIC_CMOS_UPDATE
def_bool y
diff --git a/arch/alpha/include/asm/local64.h b/arch/alpha/include/asm/local64.h
new file mode 100644
index 00000000000..36c93b5cc23
--- /dev/null
+++ b/arch/alpha/include/asm/local64.h
@@ -0,0 +1 @@
+#include <asm-generic/local64.h>
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index e39caa8b0c9..9e10882c81d 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -43,10 +43,6 @@ config SYS_SUPPORTS_APM_EMULATION
config GENERIC_GPIO
bool
-config GENERIC_TIME
- bool
- default y
-
config ARCH_USES_GETTIMEOFFSET
bool
default n
diff --git a/arch/arm/include/asm/kgdb.h b/arch/arm/include/asm/kgdb.h
index 67af4b84198..08265993227 100644
--- a/arch/arm/include/asm/kgdb.h
+++ b/arch/arm/include/asm/kgdb.h
@@ -70,11 +70,11 @@ extern int kgdb_fault_expected;
#define _GP_REGS 16
#define _FP_REGS 8
#define _EXTRA_REGS 2
-#define GDB_MAX_REGS (_GP_REGS + (_FP_REGS * 3) + _EXTRA_REGS)
+#define DBG_MAX_REG_NUM (_GP_REGS + (_FP_REGS * 3) + _EXTRA_REGS)
#define KGDB_MAX_NO_CPUS 1
#define BUFMAX 400
-#define NUMREGBYTES (GDB_MAX_REGS << 2)
+#define NUMREGBYTES (DBG_MAX_REG_NUM << 2)
#define NUMCRITREGBYTES (32 << 2)
#define _R0 0
@@ -93,7 +93,7 @@ extern int kgdb_fault_expected;
#define _SPT 13
#define _LR 14
#define _PC 15
-#define _CPSR (GDB_MAX_REGS - 1)
+#define _CPSR (DBG_MAX_REG_NUM - 1)
/*
* So that we can denote the end of a frame for tracing,
diff --git a/arch/arm/include/asm/local64.h b/arch/arm/include/asm/local64.h
new file mode 100644
index 00000000000..36c93b5cc23
--- /dev/null
+++ b/arch/arm/include/asm/local64.h
@@ -0,0 +1 @@
+#include <asm-generic/local64.h>
diff --git a/arch/arm/kernel/kgdb.c b/arch/arm/kernel/kgdb.c
index c868a886411..778c2f7024f 100644
--- a/arch/arm/kernel/kgdb.c
+++ b/arch/arm/kernel/kgdb.c
@@ -10,57 +10,62 @@
* Deepak Saxena <dsaxena@plexity.net>
*/
#include <linux/irq.h>
+#include <linux/kdebug.h>
#include <linux/kgdb.h>
#include <asm/traps.h>
-/* Make a local copy of the registers passed into the handler (bletch) */
-void pt_regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *kernel_regs)
+struct dbg_reg_def_t dbg_reg_def[DBG_MAX_REG_NUM] =
{
- int regno;
-
- /* Initialize all to zero. */
- for (regno = 0; regno < GDB_MAX_REGS; regno++)
- gdb_regs[regno] = 0;
+ { "r0", 4, offsetof(struct pt_regs, ARM_r0)},
+ { "r1", 4, offsetof(struct pt_regs, ARM_r1)},
+ { "r2", 4, offsetof(struct pt_regs, ARM_r2)},
+ { "r3", 4, offsetof(struct pt_regs, ARM_r3)},
+ { "r4", 4, offsetof(struct pt_regs, ARM_r4)},
+ { "r5", 4, offsetof(struct pt_regs, ARM_r5)},
+ { "r6", 4, offsetof(struct pt_regs, ARM_r6)},
+ { "r7", 4, offsetof(struct pt_regs, ARM_r7)},
+ { "r8", 4, offsetof(struct pt_regs, ARM_r8)},
+ { "r9", 4, offsetof(struct pt_regs, ARM_r9)},
+ { "r10", 4, offsetof(struct pt_regs, ARM_r10)},
+ { "fp", 4, offsetof(struct pt_regs, ARM_fp)},
+ { "ip", 4, offsetof(struct pt_regs, ARM_ip)},
+ { "sp", 4, offsetof(struct pt_regs, ARM_sp)},
+ { "lr", 4, offsetof(struct pt_regs, ARM_lr)},
+ { "pc", 4, offsetof(struct pt_regs, ARM_pc)},
+ { "f0", 12, -1 },
+ { "f1", 12, -1 },
+ { "f2", 12, -1 },
+ { "f3", 12, -1 },
+ { "f4", 12, -1 },
+ { "f5", 12, -1 },
+ { "f6", 12, -1 },
+ { "f7", 12, -1 },
+ { "fps", 4, -1 },
+ { "cpsr", 4, offsetof(struct pt_regs, ARM_cpsr)},
+};
- gdb_regs[_R0] = kernel_regs->ARM_r0;
- gdb_regs[_R1] = kernel_regs->ARM_r1;
- gdb_regs[_R2] = kernel_regs->ARM_r2;
- gdb_regs[_R3] = kernel_regs->ARM_r3;
- gdb_regs[_R4] = kernel_regs->ARM_r4;
- gdb_regs[_R5] = kernel_regs->ARM_r5;
- gdb_regs[_R6] = kernel_regs->ARM_r6;
- gdb_regs[_R7] = kernel_regs->ARM_r7;
- gdb_regs[_R8] = kernel_regs->ARM_r8;
- gdb_regs[_R9] = kernel_regs->ARM_r9;
- gdb_regs[_R10] = kernel_regs->ARM_r10;
- gdb_regs[_FP] = kernel_regs->ARM_fp;
- gdb_regs[_IP] = kernel_regs->ARM_ip;
- gdb_regs[_SPT] = kernel_regs->ARM_sp;
- gdb_regs[_LR] = kernel_regs->ARM_lr;
- gdb_regs[_PC] = kernel_regs->ARM_pc;
- gdb_regs[_CPSR] = kernel_regs->ARM_cpsr;
+char *dbg_get_reg(int regno, void *mem, struct pt_regs *regs)
+{
+ if (regno >= DBG_MAX_REG_NUM || regno < 0)
+ return NULL;
+
+ if (dbg_reg_def[regno].offset != -1)
+ memcpy(mem, (void *)regs + dbg_reg_def[regno].offset,
+ dbg_reg_def[regno].size);
+ else
+ memset(mem, 0, dbg_reg_def[regno].size);
+ return dbg_reg_def[regno].name;
}
-/* Copy local gdb registers back to kgdb regs, for later copy to kernel */
-void gdb_regs_to_pt_regs(unsigned long *gdb_regs, struct pt_regs *kernel_regs)
+int dbg_set_reg(int regno, void *mem, struct pt_regs *regs)
{
- kernel_regs->ARM_r0 = gdb_regs[_R0];
- kernel_regs->ARM_r1 = gdb_regs[_R1];
- kernel_regs->ARM_r2 = gdb_regs[_R2];
- kernel_regs->ARM_r3 = gdb_regs[_R3];
- kernel_regs->ARM_r4 = gdb_regs[_R4];
- kernel_regs->ARM_r5 = gdb_regs[_R5];
- kernel_regs->ARM_r6 = gdb_regs[_R6];
- kernel_regs->ARM_r7 = gdb_regs[_R7];
- kernel_regs->ARM_r8 = gdb_regs[_R8];
- kernel_regs->ARM_r9 = gdb_regs[_R9];
- kernel_regs->ARM_r10 = gdb_regs[_R10];
- kernel_regs->ARM_fp = gdb_regs[_FP];
- kernel_regs->ARM_ip = gdb_regs[_IP];
- kernel_regs->ARM_sp = gdb_regs[_SPT];
- kernel_regs->ARM_lr = gdb_regs[_LR];
- kernel_regs->ARM_pc = gdb_regs[_PC];
- kernel_regs->ARM_cpsr = gdb_regs[_CPSR];
+ if (regno >= DBG_MAX_REG_NUM || regno < 0)
+ return -EINVAL;
+
+ if (dbg_reg_def[regno].offset != -1)
+ memcpy((void *)regs + dbg_reg_def[regno].offset, mem,
+ dbg_reg_def[regno].size);
+ return 0;
}
void
@@ -176,6 +181,33 @@ void kgdb_roundup_cpus(unsigned long flags)
local_irq_disable();
}
+static int __kgdb_notify(struct die_args *args, unsigned long cmd)
+{
+ struct pt_regs *regs = args->regs;
+
+ if (kgdb_handle_exception(1, args->signr, cmd, regs))
+ return NOTIFY_DONE;
+ return NOTIFY_STOP;
+}
+static int
+kgdb_notify(struct notifier_block *self, unsigned long cmd, void *ptr)
+{
+ unsigned long flags;
+ int ret;
+
+ local_irq_save(flags);
+ ret = __kgdb_notify(ptr, cmd);
+ local_irq_restore(flags);
+
+ return ret;
+}
+
+static struct notifier_block kgdb_notifier = {
+ .notifier_call = kgdb_notify,
+ .priority = -INT_MAX,
+};
+
+
/**
* kgdb_arch_init - Perform any architecture specific initalization.
*
@@ -184,6 +216,11 @@ void kgdb_roundup_cpus(unsigned long flags)
*/
int kgdb_arch_init(void)
{
+ int ret = register_die_notifier(&kgdb_notifier);
+
+ if (ret != 0)
+ return ret;
+
register_undef_hook(&kgdb_brkpt_hook);
register_undef_hook(&kgdb_compiled_brkpt_hook);
@@ -200,6 +237,7 @@ void kgdb_arch_exit(void)
{
unregister_undef_hook(&kgdb_brkpt_hook);
unregister_undef_hook(&kgdb_compiled_brkpt_hook);
+ unregister_die_notifier(&kgdb_notifier);
}
/*
diff --git a/arch/arm/kernel/perf_event.c b/arch/arm/kernel/perf_event.c
index de12536d687..417c392ddf1 100644
--- a/arch/arm/kernel/perf_event.c
+++ b/arch/arm/kernel/perf_event.c
@@ -164,20 +164,20 @@ armpmu_event_set_period(struct perf_event *event,
struct hw_perf_event *hwc,
int idx)
{
- s64 left = atomic64_read(&hwc->period_left);
+ s64 left = local64_read(&hwc->period_left);
s64 period = hwc->sample_period;
int ret = 0;
if (unlikely(left <= -period)) {
left = period;
- atomic64_set(&hwc->period_left, left);
+ local64_set(&hwc->period_left, left);
hwc->last_period = period;
ret = 1;
}
if (unlikely(left <= 0)) {
left += period;
- atomic64_set(&hwc->period_left, left);
+ local64_set(&hwc->period_left, left);
hwc->last_period = period;
ret = 1;
}
@@ -185,7 +185,7 @@ armpmu_event_set_period(struct perf_event *event,
if (left > (s64)armpmu->max_period)
left = armpmu->max_period;
- atomic64_set(&hwc->prev_count, (u64)-left);
+ local64_set(&hwc->prev_count, (u64)-left);
armpmu->write_counter(idx, (u64)(-left) & 0xffffffff);
@@ -204,18 +204,18 @@ armpmu_event_update(struct perf_event *event,
u64 delta;
again:
- prev_raw_count = atomic64_read(&hwc->prev_count);
+ prev_raw_count = local64_read(&hwc->prev_count);
new_raw_count = armpmu->read_counter(idx);
- if (atomic64_cmpxchg(&hwc->prev_count, prev_raw_count,
+ if (local64_cmpxchg(&hwc->prev_count, prev_raw_count,
new_raw_count) != prev_raw_count)
goto again;
delta = (new_raw_count << shift) - (prev_raw_count << shift);
delta >>= shift;
- atomic64_add(delta, &event->count);
- atomic64_sub(delta, &hwc->period_left);
+ local64_add(delta, &event->count);
+ local64_sub(delta, &hwc->period_left);
return new_raw_count;
}
@@ -478,7 +478,7 @@ __hw_perf_event_init(struct perf_event *event)
if (!hwc->sample_period) {
hwc->sample_period = armpmu->max_period;
hwc->last_period = hwc->sample_period;
- atomic64_set(&hwc->period_left, hwc->sample_period);
+ local64_set(&hwc->period_left, hwc->sample_period);
}
err = 0;
diff --git a/arch/arm/mach-davinci/Kconfig b/arch/arm/mach-davinci/Kconfig
index 0316e201ada..71f90f86474 100644
--- a/arch/arm/mach-davinci/Kconfig
+++ b/arch/arm/mach-davinci/Kconfig
@@ -50,6 +50,11 @@ config ARCH_DAVINCI_DM365
select AINTC
select ARCH_DAVINCI_DMx
+config ARCH_DAVINCI_TNETV107X
+ select CPU_V6
+ select CP_INTC
+ bool "TNETV107X based system"
+
comment "DaVinci Board Type"
config MACH_DAVINCI_EVM
@@ -173,6 +178,13 @@ config DA850_UI_RMII
endchoice
+config MACH_TNETV107X
+ bool "TI TNETV107X Reference Platform"
+ default ARCH_DAVINCI_TNETV107X
+ depends on ARCH_DAVINCI_TNETV107X
+ help
+ Say Y here to select the TI TNETV107X Evaluation Module.
+
config DAVINCI_MUX
bool "DAVINCI multiplexing support"
depends on ARCH_DAVINCI
diff --git a/arch/arm/mach-davinci/Makefile b/arch/arm/mach-davinci/Makefile
index 6aac880eb79..eab4c0fd667 100644
--- a/arch/arm/mach-davinci/Makefile
+++ b/arch/arm/mach-davinci/Makefile
@@ -16,6 +16,8 @@ obj-$(CONFIG_ARCH_DAVINCI_DM646x) += dm646x.o devices.o
obj-$(CONFIG_ARCH_DAVINCI_DM365) += dm365.o devices.o
obj-$(CONFIG_ARCH_DAVINCI_DA830) += da830.o devices-da8xx.o
obj-$(CONFIG_ARCH_DAVINCI_DA850) += da850.o devices-da8xx.o
+obj-$(CONFIG_ARCH_DAVINCI_TNETV107X) += tnetv107x.o devices-tnetv107x.o
+obj-$(CONFIG_ARCH_DAVINCI_TNETV107X) += gpio-tnetv107x.o
obj-$(CONFIG_AINTC) += irq.o
obj-$(CONFIG_CP_INTC) += cp_intc.o
@@ -30,6 +32,7 @@ obj-$(CONFIG_MACH_DAVINCI_DM6467_EVM) += board-dm646x-evm.o cdce949.o
obj-$(CONFIG_MACH_DAVINCI_DM365_EVM) += board-dm365-evm.o
obj-$(CONFIG_MACH_DAVINCI_DA830_EVM) += board-da830-evm.o
obj-$(CONFIG_MACH_DAVINCI_DA850_EVM) += board-da850-evm.o
+obj-$(CONFIG_MACH_TNETV107X) += board-tnetv107x-evm.o
# Power Management
obj-$(CONFIG_CPU_FREQ) += cpufreq.o
diff --git a/arch/arm/mach-davinci/board-da830-evm.c b/arch/arm/mach-davinci/board-da830-evm.c
index 212d97084bd..c3994f341e4 100644
--- a/arch/arm/mach-davinci/board-da830-evm.c
+++ b/arch/arm/mach-davinci/board-da830-evm.c
@@ -208,7 +208,7 @@ static struct snd_platform_data da830_evm_snd_data = {
.num_serializer = ARRAY_SIZE(da830_iis_serializer_direction),
.tdm_slots = 2,
.serial_dir = da830_iis_serializer_direction,
- .eventq_no = EVENTQ_0,
+ .asp_chan_q = EVENTQ_0,
.version = MCASP_VERSION_2,
.txnumevt = 1,
.rxnumevt = 1,
@@ -494,12 +494,42 @@ static struct davinci_i2c_platform_data da830_evm_i2c_0_pdata = {
.bus_delay = 0, /* usec */
};
+/*
+ * The following EDMA channels/slots are not being used by drivers (for
+ * example: Timer, GPIO, UART events etc) on da830/omap-l137 EVM, hence
+ * they are being reserved for codecs on the DSP side.
+ */
+static const s16 da830_dma_rsv_chans[][2] = {
+ /* (offset, number) */
+ { 8, 2},
+ {12, 2},
+ {24, 4},
+ {30, 2},
+ {-1, -1}
+};
+
+static const s16 da830_dma_rsv_slots[][2] = {
+ /* (offset, number) */
+ { 8, 2},
+ {12, 2},
+ {24, 4},
+ {30, 26},
+ {-1, -1}
+};
+
+static struct edma_rsv_info da830_edma_rsv[] = {
+ {
+ .rsv_chans = da830_dma_rsv_chans,
+ .rsv_slots = da830_dma_rsv_slots,
+ },
+};
+
static __init void da830_evm_init(void)
{
struct davinci_soc_info *soc_info = &davinci_soc_info;
int ret;
- ret = da8xx_register_edma();
+ ret = da830_register_edma(da830_edma_rsv);
if (ret)
pr_warning("da830_evm_init: edma registration failed: %d\n",
ret);
diff --git a/arch/arm/mach-davinci/board-da850-evm.c b/arch/arm/mach-davinci/board-da850-evm.c
index b280efb1fa1..fdc2cc500fc 100644
--- a/arch/arm/mach-davinci/board-da850-evm.c
+++ b/arch/arm/mach-davinci/board-da850-evm.c
@@ -343,7 +343,7 @@ static struct snd_platform_data da850_evm_snd_data = {
.num_serializer = ARRAY_SIZE(da850_iis_serializer_direction),
.tdm_slots = 2,
.serial_dir = da850_iis_serializer_direction,
- .eventq_no = EVENTQ_1,
+ .asp_chan_q = EVENTQ_1,
.version = MCASP_VERSION_2,
.txnumevt = 1,
.rxnumevt = 1,
@@ -637,6 +637,56 @@ static int __init da850_evm_config_emac(void)
}
device_initcall(da850_evm_config_emac);
+/*
+ * The following EDMA channels/slots are not being used by drivers (for
+ * example: Timer, GPIO, UART events etc) on da850/omap-l138 EVM, hence
+ * they are being reserved for codecs on the DSP side.
+ */
+static const s16 da850_dma0_rsv_chans[][2] = {
+ /* (offset, number) */
+ { 8, 6},
+ {24, 4},
+ {30, 2},
+ {-1, -1}
+};
+
+static const s16 da850_dma0_rsv_slots[][2] = {
+ /* (offset, number) */
+ { 8, 6},
+ {24, 4},
+ {30, 50},
+ {-1, -1}
+};
+
+static const s16 da850_dma1_rsv_chans[][2] = {
+ /* (offset, number) */
+ { 0, 28},
+ {30, 2},
+ {-1, -1}
+};
+
+static const s16 da850_dma1_rsv_slots[][2] = {
+ /* (offset, number) */
+ { 0, 28},
+ {30, 90},
+ {-1, -1}
+};
+
+static struct edma_rsv_info da850_edma_cc0_rsv = {
+ .rsv_chans = da850_dma0_rsv_chans,
+ .rsv_slots = da850_dma0_rsv_slots,
+};
+
+static struct edma_rsv_info da850_edma_cc1_rsv = {
+ .rsv_chans = da850_dma1_rsv_chans,
+ .rsv_slots = da850_dma1_rsv_slots,
+};
+
+static struct edma_rsv_info *da850_edma_rsv[2] = {
+ &da850_edma_cc0_rsv,
+ &da850_edma_cc1_rsv,
+};
+
static __init void da850_evm_init(void)
{
int ret;
@@ -646,7 +696,7 @@ static __init void da850_evm_init(void)
pr_warning("da850_evm_init: TPS65070 PMIC init failed: %d\n",
ret);
- ret = da8xx_register_edma();
+ ret = da850_register_edma(da850_edma_rsv);
if (ret)
pr_warning("da850_evm_init: edma registration failed: %d\n",
ret);
diff --git a/arch/arm/mach-davinci/board-dm646x-evm.c b/arch/arm/mach-davinci/board-dm646x-evm.c
index 6d8889342c9..4502f346b2b 100644
--- a/arch/arm/mach-davinci/board-dm646x-evm.c
+++ b/arch/arm/mach-davinci/board-dm646x-evm.c
@@ -323,7 +323,7 @@ static struct snd_platform_data dm646x_evm_snd_data[] = {
.num_serializer = ARRAY_SIZE(dm646x_iis_serializer_direction),
.tdm_slots = 2,
.serial_dir = dm646x_iis_serializer_direction,
- .eventq_no = EVENTQ_0,
+ .asp_chan_q = EVENTQ_0,
},
{
.tx_dma_offset = 0x400,
@@ -332,7 +332,7 @@ static struct snd_platform_data dm646x_evm_snd_data[] = {
.num_serializer = ARRAY_SIZE(dm646x_dit_serializer_direction),
.tdm_slots = 32,
.serial_dir = dm646x_dit_serializer_direction,
- .eventq_no = EVENTQ_0,
+ .asp_chan_q = EVENTQ_0,
},
};
@@ -721,6 +721,39 @@ static struct davinci_uart_config uart_config __initdata = {
#define DM646X_EVM_PHY_MASK (0x2)
#define DM646X_EVM_MDIO_FREQUENCY (2200000) /* PHY bus frequency */
+/*
+ * The following EDMA channels/slots are not being used by drivers (for
+ * example: Timer, GPIO, UART events etc) on dm646x, hence they are being
+ * reserved for codecs on the DSP side.
+ */
+static const s16 dm646x_dma_rsv_chans[][2] = {
+ /* (offset, number) */
+ { 0, 4},
+ {13, 3},
+ {24, 4},
+ {30, 2},
+ {54, 3},
+ {-1, -1}
+};
+
+static const s16 dm646x_dma_rsv_slots[][2] = {
+ /* (offset, number) */
+ { 0, 4},
+ {13, 3},
+ {24, 4},
+ {30, 2},
+ {54, 3},
+ {128, 384},
+ {-1, -1}
+};
+
+static struct edma_rsv_info dm646x_edma_rsv[] = {
+ {
+ .rsv_chans = dm646x_dma_rsv_chans,
+ .rsv_slots = dm646x_dma_rsv_slots,
+ },
+};
+
static __init void evm_init(void)
{
struct davinci_soc_info *soc_info = &davinci_soc_info;
@@ -732,6 +765,8 @@ static __init void evm_init(void)
platform_device_register(&davinci_nand_device);
+ dm646x_init_edma(dm646x_edma_rsv);
+
if (HAS_ATA)
davinci_init_ide();
diff --git a/arch/arm/mach-davinci/board-tnetv107x-evm.c b/arch/arm/mach-davinci/board-tnetv107x-evm.c
new file mode 100644
index 00000000000..fe2a9d9c8bb
--- /dev/null
+++ b/arch/arm/mach-davinci/board-tnetv107x-evm.c
@@ -0,0 +1,174 @@
+/*
+ * Texas Instruments TNETV107X EVM Board Support
+ *
+ * Copyright (C) 2010 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 version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/console.h>
+#include <linux/dma-mapping.h>
+#include <linux/interrupt.h>
+#include <linux/gpio.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/ratelimit.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <asm/mach/arch.h>
+#include <asm/mach-types.h>
+
+#include <mach/irqs.h>
+#include <mach/edma.h>
+#include <mach/mux.h>
+#include <mach/cp_intc.h>
+#include <mach/tnetv107x.h>
+
+#define EVM_MMC_WP_GPIO 21
+#define EVM_MMC_CD_GPIO 24
+
+static int initialize_gpio(int gpio, char *desc)
+{
+ int ret;
+
+ ret = gpio_request(gpio, desc);
+ if (ret < 0) {
+ pr_err_ratelimited("cannot open %s gpio\n", desc);
+ return -ENOSYS;
+ }
+ gpio_direction_input(gpio);
+ return gpio;
+}
+
+static int mmc_get_cd(int index)
+{
+ static int gpio;
+
+ if (!gpio)
+ gpio = initialize_gpio(EVM_MMC_CD_GPIO, "mmc card detect");
+
+ if (gpio < 0)
+ return gpio;
+
+ return gpio_get_value(gpio) ? 0 : 1;
+}
+
+static int mmc_get_ro(int index)
+{
+ static int gpio;
+
+ if (!gpio)
+ gpio = initialize_gpio(EVM_MMC_WP_GPIO, "mmc write protect");
+
+ if (gpio < 0)
+ return gpio;
+
+ return gpio_get_value(gpio) ? 1 : 0;
+}
+
+static struct davinci_mmc_config mmc_config = {
+ .get_cd = mmc_get_cd,
+ .get_ro = mmc_get_ro,
+ .wires = 4,
+ .max_freq = 50000000,
+ .caps = MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED,
+ .version = MMC_CTLR_VERSION_1,
+};
+
+static const short sdio1_pins[] __initdata = {
+ TNETV107X_SDIO1_CLK_1, TNETV107X_SDIO1_CMD_1,
+ TNETV107X_SDIO1_DATA0_1, TNETV107X_SDIO1_DATA1_1,
+ TNETV107X_SDIO1_DATA2_1, TNETV107X_SDIO1_DATA3_1,
+ TNETV107X_GPIO21, TNETV107X_GPIO24,
+ -1
+};
+
+static const short uart1_pins[] __initdata = {
+ TNETV107X_UART1_RD, TNETV107X_UART1_TD,
+ -1
+};
+
+static struct mtd_partition nand_partitions[] = {
+ /* bootloader (U-Boot, etc) in first 12 sectors */
+ {
+ .name = "bootloader",
+ .offset = 0,
+ .size = (12*SZ_128K),
+ .mask_flags = MTD_WRITEABLE, /* force read-only */
+ },
+ /* bootloader params in the next sector */
+ {
+ .name = "params",
+ .offset = MTDPART_OFS_NXTBLK,
+ .size = SZ_128K,
+ .mask_flags = MTD_WRITEABLE, /* force read-only */
+ },
+ /* kernel */
+ {
+ .name = "kernel",
+ .offset = MTDPART_OFS_NXTBLK,
+ .size = SZ_4M,
+ .mask_flags = 0,
+ },
+ /* file system */
+ {
+ .name = "filesystem",
+ .offset = MTDPART_OFS_NXTBLK,
+ .size = MTDPART_SIZ_FULL,
+ .mask_flags = 0,
+ }
+};
+
+static struct davinci_nand_pdata nand_config = {
+ .mask_cle = 0x4000,
+ .mask_ale = 0x2000,
+ .parts = nand_partitions,
+ .nr_parts = ARRAY_SIZE(nand_partitions),
+ .ecc_mode = NAND_ECC_HW,
+ .options = NAND_USE_FLASH_BBT,
+ .ecc_bits = 1,
+};
+
+static struct davinci_uart_config serial_config __initconst = {
+ .enabled_uarts = BIT(1),
+};
+
+static struct tnetv107x_device_info evm_device_info __initconst = {
+ .serial_config = &serial_config,
+ .mmc_config[1] = &mmc_config, /* controller 1 */
+ .nand_config[0] = &nand_config, /* chip select 0 */
+};
+
+static __init void tnetv107x_evm_board_init(void)
+{
+ davinci_cfg_reg_list(sdio1_pins);
+ davinci_cfg_reg_list(uart1_pins);
+
+ tnetv107x_devices_init(&evm_device_info);
+}
+
+#ifdef CONFIG_SERIAL_8250_CONSOLE
+static int __init tnetv107x_evm_console_init(void)
+{
+ return add_preferred_console("ttyS", 0, "115200");
+}
+console_initcall(tnetv107x_evm_console_init);
+#endif
+
+MACHINE_START(TNETV107X, "TNETV107X EVM")
+ .phys_io = TNETV107X_IO_BASE,
+ .io_pg_offst = (TNETV107X_IO_VIRT >> 18) & 0xfffc,
+ .boot_params = (TNETV107X_DDR_BASE + 0x100),
+ .map_io = tnetv107x_init,
+ .init_irq = cp_intc_init,
+ .timer = &davinci_timer,
+ .init_machine = tnetv107x_evm_board_init,
+MACHINE_END
diff --git a/arch/arm/mach-davinci/da830.c b/arch/arm/mach-davinci/da830.c
index 23e9eda5a37..ec23ab47362 100644
--- a/arch/arm/mach-davinci/da830.c
+++ b/arch/arm/mach-davinci/da830.c
@@ -1024,7 +1024,6 @@ static u8 da830_default_priorities[DA830_N_CP_INTC_IRQ] = {
[IRQ_DA8XX_EVTOUT4] = 7,
[IRQ_DA8XX_EVTOUT5] = 7,
[IRQ_DA8XX_EVTOUT6] = 7,
- [IRQ_DA8XX_EVTOUT6] = 7,
[IRQ_DA8XX_EVTOUT7] = 7,
[IRQ_DA8XX_CCINT0] = 7,
[IRQ_DA8XX_CCERRINT] = 7,
@@ -1042,11 +1041,7 @@ static u8 da830_default_priorities[DA830_N_CP_INTC_IRQ] = {
[IRQ_DA8XX_TINT34_1] = 7,
[IRQ_DA8XX_UARTINT0] = 7,
[IRQ_DA8XX_KEYMGRINT] = 7,
- [IRQ_DA8XX_SECINT] = 7,
- [IRQ_DA8XX_SECKEYERR] = 7,
[IRQ_DA830_MPUERR] = 7,
- [IRQ_DA830_IOPUERR] = 7,
- [IRQ_DA830_BOOTCFGERR] = 7,
[IRQ_DA8XX_CHIPINT0] = 7,
[IRQ_DA8XX_CHIPINT1] = 7,
[IRQ_DA8XX_CHIPINT2] = 7,
diff --git a/arch/arm/mach-davinci/da850.c b/arch/arm/mach-davinci/da850.c
index 6b8331bf8cf..68ed58a4825 100644
--- a/arch/arm/mach-davinci/da850.c
+++ b/arch/arm/mach-davinci/da850.c
@@ -643,7 +643,6 @@ static u8 da850_default_priorities[DA850_N_CP_INTC_IRQ] = {
[IRQ_DA8XX_EVTOUT4] = 7,
[IRQ_DA8XX_EVTOUT5] = 7,
[IRQ_DA8XX_EVTOUT6] = 7,
- [IRQ_DA8XX_EVTOUT6] = 7,
[IRQ_DA8XX_EVTOUT7] = 7,
[IRQ_DA8XX_CCINT0] = 7,
[IRQ_DA8XX_CCERRINT] = 7,
@@ -661,27 +660,7 @@ static u8 da850_default_priorities[DA850_N_CP_INTC_IRQ] = {
[IRQ_DA8XX_TINT34_1] = 7,
[IRQ_DA8XX_UARTINT0] = 7,
[IRQ_DA8XX_KEYMGRINT] = 7,
- [IRQ_DA8XX_SECINT] = 7,
- [IRQ_DA8XX_SECKEYERR] = 7,
[IRQ_DA850_MPUADDRERR0] = 7,
- [IRQ_DA850_MPUPROTERR0] = 7,
- [IRQ_DA850_IOPUADDRERR0] = 7,
- [IRQ_DA850_IOPUPROTERR0] = 7,
- [IRQ_DA850_IOPUADDRERR1] = 7,
- [IRQ_DA850_IOPUPROTERR1] = 7,
- [IRQ_DA850_IOPUADDRERR2] = 7,
- [IRQ_DA850_IOPUPROTERR2] = 7,
- [IRQ_DA850_BOOTCFG_ADDR_ERR] = 7,
- [IRQ_DA850_BOOTCFG_PROT_ERR] = 7,
- [IRQ_DA850_MPUADDRERR1] = 7,
- [IRQ_DA850_MPUPROTERR1] = 7,
- [IRQ_DA850_IOPUADDRERR3] = 7,
- [IRQ_DA850_IOPUPROTERR3] = 7,
- [IRQ_DA850_IOPUADDRERR4] = 7,
- [IRQ_DA850_IOPUPROTERR4] = 7,
- [IRQ_DA850_IOPUADDRERR5] = 7,
- [IRQ_DA850_IOPUPROTERR5] = 7,
- [IRQ_DA850_MIOPU_BOOTCFG_ERR] = 7,
[IRQ_DA8XX_CHIPINT0] = 7,
[IRQ_DA8XX_CHIPINT1] = 7,
[IRQ_DA8XX_CHIPINT2] = 7,
@@ -722,8 +701,6 @@ static u8 da850_default_priorities[DA850_N_CP_INTC_IRQ] = {
[IRQ_DA8XX_EHRPWM1] = 7,
[IRQ_DA8XX_EHRPWM1TZ] = 7,
[IRQ_DA850_SATAINT] = 7,
- [IRQ_DA850_TINT12_2] = 7,
- [IRQ_DA850_TINT34_2] = 7,
[IRQ_DA850_TINTALL_2] = 7,
[IRQ_DA8XX_ECAP0] = 7,
[IRQ_DA8XX_ECAP1] = 7,
@@ -751,8 +728,6 @@ static u8 da850_default_priorities[DA850_N_CP_INTC_IRQ] = {
[IRQ_DA850_CCINT1] = 7,
[IRQ_DA850_CCERRINT1] = 7,
[IRQ_DA850_TCERRINT2] = 7,
- [IRQ_DA850_TINT12_3] = 7,
- [IRQ_DA850_TINT34_3] = 7,
[IRQ_DA850_TINTALL_3] = 7,
[IRQ_DA850_MCBSP0RINT] = 7,
[IRQ_DA850_MCBSP0XINT] = 7,
diff --git a/arch/arm/mach-davinci/devices-da8xx.c b/arch/arm/mach-davinci/devices-da8xx.c
index 8cda729be27..52bc7b1c6ca 100644
--- a/arch/arm/mach-davinci/devices-da8xx.c
+++ b/arch/arm/mach-davinci/devices-da8xx.c
@@ -111,19 +111,21 @@ static const s8 da850_queue_priority_mapping[][2] = {
{-1, -1}
};
-static struct edma_soc_info da830_edma_info[] = {
- {
- .n_channel = 32,
- .n_region = 4,
- .n_slot = 128,
- .n_tc = 2,
- .n_cc = 1,
- .queue_tc_mapping = da8xx_queue_tc_mapping,
- .queue_priority_mapping = da8xx_queue_priority_mapping,
- },
+static struct edma_soc_info da830_edma_cc0_info = {
+ .n_channel = 32,
+ .n_region = 4,
+ .n_slot = 128,
+ .n_tc = 2,
+ .n_cc = 1,
+ .queue_tc_mapping = da8xx_queue_tc_mapping,
+ .queue_priority_mapping = da8xx_queue_priority_mapping,
+};
+
+static struct edma_soc_info *da830_edma_info[EDMA_MAX_CC] = {
+ &da830_edma_cc0_info,
};
-static struct edma_soc_info da850_edma_info[] = {
+static struct edma_soc_info da850_edma_cc_info[] = {
{
.n_channel = 32,
.n_region = 4,
@@ -144,6 +146,11 @@ static struct edma_soc_info da850_edma_info[] = {
},
};
+static struct edma_soc_info *da850_edma_info[EDMA_MAX_CC] = {
+ &da850_edma_cc_info[0],
+ &da850_edma_cc_info[1],
+};
+
static struct resource da830_edma_resources[] = {
{
.name = "edma_cc0",
@@ -248,18 +255,21 @@ static struct platform_device da850_edma_device = {
.resource = da850_edma_resources,
};
-int __init da8xx_register_edma(void)
+int __init da830_register_edma(struct edma_rsv_info *rsv)
{
- struct platform_device *pdev;
+ da830_edma_cc0_info.rsv = rsv;
- if (cpu_is_davinci_da830())
- pdev = &da830_edma_device;
- else if (cpu_is_davinci_da850())
- pdev = &da850_edma_device;
- else
- return -ENODEV;
+ return platform_device_register(&da830_edma_device);
+}
- return platform_device_register(pdev);
+int __init da850_register_edma(struct edma_rsv_info *rsv[2])
+{
+ if (rsv) {
+ da850_edma_cc_info[0].rsv = rsv[0];
+ da850_edma_cc_info[1].rsv = rsv[1];
+ }
+
+ return platform_device_register(&da850_edma_device);
}
static struct resource da8xx_i2c_resources0[] = {
diff --git a/arch/arm/mach-davinci/devices-tnetv107x.c b/arch/arm/mach-davinci/devices-tnetv107x.c
new file mode 100644
index 00000000000..2718a3a90df
--- /dev/null
+++ b/arch/arm/mach-davinci/devices-tnetv107x.c
@@ -0,0 +1,320 @@
+/*
+ * Texas Instruments TNETV107X SoC devices
+ *
+ * Copyright (C) 2010 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 version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
+#include <linux/clk.h>
+#include <linux/slab.h>
+
+#include <mach/common.h>
+#include <mach/irqs.h>
+#include <mach/edma.h>
+#include <mach/tnetv107x.h>
+
+#include "clock.h"
+
+/* Base addresses for on-chip devices */
+#define TNETV107X_TPCC_BASE 0x01c00000
+#define TNETV107X_TPTC0_BASE 0x01c10000
+#define TNETV107X_TPTC1_BASE 0x01c10400
+#define TNETV107X_WDOG_BASE 0x08086700
+#define TNETV107X_SDIO0_BASE 0x08088700
+#define TNETV107X_SDIO1_BASE 0x08088800
+#define TNETV107X_ASYNC_EMIF_CNTRL_BASE 0x08200000
+#define TNETV107X_ASYNC_EMIF_DATA_CE0_BASE 0x30000000
+#define TNETV107X_ASYNC_EMIF_DATA_CE1_BASE 0x40000000
+#define TNETV107X_ASYNC_EMIF_DATA_CE2_BASE 0x44000000
+#define TNETV107X_ASYNC_EMIF_DATA_CE3_BASE 0x48000000
+
+/* TNETV107X specific EDMA3 information */
+#define EDMA_TNETV107X_NUM_DMACH 64
+#define EDMA_TNETV107X_NUM_TCC 64
+#define EDMA_TNETV107X_NUM_PARAMENTRY 128
+#define EDMA_TNETV107X_NUM_EVQUE 2
+#define EDMA_TNETV107X_NUM_TC 2
+#define EDMA_TNETV107X_CHMAP_EXIST 0
+#define EDMA_TNETV107X_NUM_REGIONS 4
+#define TNETV107X_DMACH2EVENT_MAP0 0x3C0CE000u
+#define TNETV107X_DMACH2EVENT_MAP1 0x000FFFFFu
+
+#define TNETV107X_DMACH_SDIO0_RX 26
+#define TNETV107X_DMACH_SDIO0_TX 27
+#define TNETV107X_DMACH_SDIO1_RX 28
+#define TNETV107X_DMACH_SDIO1_TX 29
+
+static const s8 edma_tc_mapping[][2] = {
+ /* event queue no TC no */
+ { 0, 0 },
+ { 1, 1 },
+ { -1, -1 }
+};
+
+static const s8 edma_priority_mapping[][2] = {
+ /* event queue no Prio */
+ { 0, 3 },
+ { 1, 7 },
+ { -1, -1 }
+};
+
+static struct edma_soc_info edma_cc0_info = {
+ .n_channel = EDMA_TNETV107X_NUM_DMACH,
+ .n_region = EDMA_TNETV107X_NUM_REGIONS,
+ .n_slot = EDMA_TNETV107X_NUM_PARAMENTRY,
+ .n_tc = EDMA_TNETV107X_NUM_TC,
+ .n_cc = 1,
+ .queue_tc_mapping = edma_tc_mapping,
+ .queue_priority_mapping = edma_priority_mapping,
+};
+
+static struct edma_soc_info *tnetv107x_edma_info[EDMA_MAX_CC] = {
+ &edma_cc0_info,
+};
+
+static struct resource edma_resources[] = {
+ {
+ .name = "edma_cc0",
+ .start = TNETV107X_TPCC_BASE,
+ .end = TNETV107X_TPCC_BASE + SZ_32K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .name = "edma_tc0",
+ .start = TNETV107X_TPTC0_BASE,
+ .end = TNETV107X_TPTC0_BASE + SZ_1K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .name = "edma_tc1",
+ .start = TNETV107X_TPTC1_BASE,
+ .end = TNETV107X_TPTC1_BASE + SZ_1K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .name = "edma0",
+ .start = IRQ_TNETV107X_TPCC,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "edma0_err",
+ .start = IRQ_TNETV107X_TPCC_ERR,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device edma_device = {
+ .name = "edma",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(edma_resources),
+ .resource = edma_resources,
+ .dev.platform_data = tnetv107x_edma_info,
+};
+
+static struct plat_serial8250_port serial_data[] = {
+ {
+ .mapbase = TNETV107X_UART0_BASE,
+ .irq = IRQ_TNETV107X_UART0,
+ .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST |
+ UPF_FIXED_TYPE | UPF_IOREMAP,
+ .type = PORT_AR7,
+ .iotype = UPIO_MEM32,
+ .regshift = 2,
+ },
+ {
+ .mapbase = TNETV107X_UART1_BASE,
+ .irq = IRQ_TNETV107X_UART1,
+ .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST |
+ UPF_FIXED_TYPE | UPF_IOREMAP,
+ .type = PORT_AR7,
+ .iotype = UPIO_MEM32,
+ .regshift = 2,
+ },
+ {
+ .mapbase = TNETV107X_UART2_BASE,
+ .irq = IRQ_TNETV107X_UART2,
+ .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST |
+ UPF_FIXED_TYPE | UPF_IOREMAP,
+ .type = PORT_AR7,
+ .iotype = UPIO_MEM32,
+ .regshift = 2,
+ },
+ {
+ .flags = 0,
+ },
+};
+
+struct platform_device tnetv107x_serial_device = {
+ .name = "serial8250",
+ .id = PLAT8250_DEV_PLATFORM,
+ .dev.platform_data = serial_data,
+};
+
+static struct resource mmc0_resources[] = {
+ { /* Memory mapped registers */
+ .start = TNETV107X_SDIO0_BASE,
+ .end = TNETV107X_SDIO0_BASE + 0x0ff,
+ .flags = IORESOURCE_MEM
+ },
+ { /* MMC interrupt */
+ .start = IRQ_TNETV107X_MMC0,
+ .flags = IORESOURCE_IRQ
+ },
+ { /* SDIO interrupt */
+ .start = IRQ_TNETV107X_SDIO0,
+ .flags = IORESOURCE_IRQ
+ },
+ { /* DMA RX */
+ .start = EDMA_CTLR_CHAN(0, TNETV107X_DMACH_SDIO0_RX),
+ .flags = IORESOURCE_DMA
+ },
+ { /* DMA TX */
+ .start = EDMA_CTLR_CHAN(0, TNETV107X_DMACH_SDIO0_TX),
+ .flags = IORESOURCE_DMA
+ },
+};
+
+static struct resource mmc1_resources[] = {
+ { /* Memory mapped registers */
+ .start = TNETV107X_SDIO1_BASE,
+ .end = TNETV107X_SDIO1_BASE + 0x0ff,
+ .flags = IORESOURCE_MEM
+ },
+ { /* MMC interrupt */
+ .start = IRQ_TNETV107X_MMC1,
+ .flags = IORESOURCE_IRQ
+ },
+ { /* SDIO interrupt */
+ .start = IRQ_TNETV107X_SDIO1,
+ .flags = IORESOURCE_IRQ
+ },
+ { /* DMA RX */
+ .start = EDMA_CTLR_CHAN(0, TNETV107X_DMACH_SDIO1_RX),
+ .flags = IORESOURCE_DMA
+ },
+ { /* DMA TX */
+ .start = EDMA_CTLR_CHAN(0, TNETV107X_DMACH_SDIO1_TX),
+ .flags = IORESOURCE_DMA
+ },
+};
+
+static u64 mmc0_dma_mask = DMA_BIT_MASK(32);
+static u64 mmc1_dma_mask = DMA_BIT_MASK(32);
+
+static struct platform_device mmc_devices[2] = {
+ {
+ .name = "davinci_mmc",
+ .id = 0,
+ .dev = {
+ .dma_mask = &mmc0_dma_mask,
+ .coherent_dma_mask = DMA_BIT_MASK(32),
+ },
+ .num_resources = ARRAY_SIZE(mmc0_resources),
+ .resource = mmc0_resources
+ },
+ {
+ .name = "davinci_mmc",
+ .id = 1,
+ .dev = {
+ .dma_mask = &mmc1_dma_mask,
+ .coherent_dma_mask = DMA_BIT_MASK(32),
+ },
+ .num_resources = ARRAY_SIZE(mmc1_resources),
+ .resource = mmc1_resources
+ },
+};
+
+static const u32 emif_windows[] = {
+ TNETV107X_ASYNC_EMIF_DATA_CE0_BASE, TNETV107X_ASYNC_EMIF_DATA_CE1_BASE,
+ TNETV107X_ASYNC_EMIF_DATA_CE2_BASE, TNETV107X_ASYNC_EMIF_DATA_CE3_BASE,
+};
+
+static const u32 emif_window_sizes[] = { SZ_256M, SZ_64M, SZ_64M, SZ_64M };
+
+static struct resource wdt_resources[] = {
+ {
+ .start = TNETV107X_WDOG_BASE,
+ .end = TNETV107X_WDOG_BASE + SZ_4K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+struct platform_device tnetv107x_wdt_device = {
+ .name = "tnetv107x_wdt",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(wdt_resources),
+ .resource = wdt_resources,
+};
+
+static int __init nand_init(int chipsel, struct davinci_nand_pdata *data)
+{
+ struct resource res[2];
+ struct platform_device *pdev;
+ u32 range;
+ int ret;
+
+ /* Figure out the resource range from the ale/cle masks */
+ range = max(data->mask_cle, data->mask_ale);
+ range = PAGE_ALIGN(range + 4) - 1;
+
+ if (range >= emif_window_sizes[chipsel])
+ return -EINVAL;
+
+ pdev = kzalloc(sizeof(*pdev), GFP_KERNEL);
+ if (!pdev)
+ return -ENOMEM;
+
+ pdev->name = "davinci_nand";
+ pdev->id = chipsel;
+ pdev->dev.platform_data = data;
+
+ memset(res, 0, sizeof(res));
+
+ res[0].start = emif_windows[chipsel];
+ res[0].end = res[0].start + range;
+ res[0].flags = IORESOURCE_MEM;
+
+ res[1].start = TNETV107X_ASYNC_EMIF_CNTRL_BASE;
+ res[1].end = res[1].start + SZ_4K - 1;
+ res[1].flags = IORESOURCE_MEM;
+
+ ret = platform_device_add_resources(pdev, res, ARRAY_SIZE(res));
+ if (ret < 0) {
+ kfree(pdev);
+ return ret;
+ }
+
+ return platform_device_register(pdev);
+}
+
+void __init tnetv107x_devices_init(struct tnetv107x_device_info *info)
+{
+ int i;
+
+ platform_device_register(&edma_device);
+ platform_device_register(&tnetv107x_wdt_device);
+
+ if (info->serial_config)
+ davinci_serial_init(info->serial_config);
+
+ for (i = 0; i < 2; i++)
+ if (info->mmc_config[i]) {
+ mmc_devices[i].dev.platform_data = info->mmc_config[i];
+ platform_device_register(&mmc_devices[i]);
+ }
+
+ for (i = 0; i < 4; i++)
+ if (info->nand_config[i])
+ nand_init(i, info->nand_config[i]);
+}
diff --git a/arch/arm/mach-davinci/dm355.c b/arch/arm/mach-davinci/dm355.c
index 383478116ef..3d996b659ff 100644
--- a/arch/arm/mach-davinci/dm355.c
+++ b/arch/arm/mach-davinci/dm355.c
@@ -591,16 +591,18 @@ queue_priority_mapping[][2] = {
{-1, -1},
};
-static struct edma_soc_info dm355_edma_info[] = {
- {
- .n_channel = 64,
- .n_region = 4,
- .n_slot = 128,
- .n_tc = 2,
- .n_cc = 1,
- .queue_tc_mapping = queue_tc_mapping,
- .queue_priority_mapping = queue_priority_mapping,
- },
+static struct edma_soc_info edma_cc0_info = {
+ .n_channel = 64,
+ .n_region = 4,
+ .n_slot = 128,
+ .n_tc = 2,
+ .n_cc = 1,
+ .queue_tc_mapping = queue_tc_mapping,
+ .queue_priority_mapping = queue_priority_mapping,
+};
+
+static struct edma_soc_info *dm355_edma_info[EDMA_MAX_CC] = {
+ &edma_cc0_info,
};
static struct resource edma_resources[] = {
diff --git a/arch/arm/mach-davinci/dm365.c b/arch/arm/mach-davinci/dm365.c
index a146849d78f..6b6f4c64370 100644
--- a/arch/arm/mach-davinci/dm365.c
+++ b/arch/arm/mach-davinci/dm365.c
@@ -822,17 +822,19 @@ dm365_queue_priority_mapping[][2] = {
{-1, -1},
};
-static struct edma_soc_info dm365_edma_info[] = {
- {
- .n_channel = 64,
- .n_region = 4,
- .n_slot = 256,
- .n_tc = 4,
- .n_cc = 1,
- .queue_tc_mapping = dm365_queue_tc_mapping,
- .queue_priority_mapping = dm365_queue_priority_mapping,
- .default_queue = EVENTQ_3,
- },
+static struct edma_soc_info edma_cc0_info = {
+ .n_channel = 64,
+ .n_region = 4,
+ .n_slot = 256,
+ .n_tc = 4,
+ .n_cc = 1,
+ .queue_tc_mapping = dm365_queue_tc_mapping,
+ .queue_priority_mapping = dm365_queue_priority_mapping,
+ .default_queue = EVENTQ_3,
+};
+
+static struct edma_soc_info *dm365_edma_info[EDMA_MAX_CC] = {
+ &edma_cc0_info,
};
static struct resource edma_resources[] = {
@@ -1020,6 +1022,8 @@ static struct davinci_timer_info dm365_timer_info = {
.clocksource_id = T0_TOP,
};
+#define DM365_UART1_BASE (IO_PHYS + 0x106000)
+
static struct plat_serial8250_port dm365_serial_platform_data[] = {
{
.mapbase = DAVINCI_UART0_BASE,
@@ -1030,7 +1034,7 @@ static struct plat_serial8250_port dm365_serial_platform_data[] = {
.regshift = 2,
},
{
- .mapbase = DAVINCI_UART1_BASE,
+ .mapbase = DM365_UART1_BASE,
.irq = IRQ_UARTINT1,
.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST |
UPF_IOREMAP,
diff --git a/arch/arm/mach-davinci/dm644x.c b/arch/arm/mach-davinci/dm644x.c
index 7ad15208b84..40fec315c99 100644
--- a/arch/arm/mach-davinci/dm644x.c
+++ b/arch/arm/mach-davinci/dm644x.c
@@ -492,16 +492,18 @@ queue_priority_mapping[][2] = {
{-1, -1},
};
-static struct edma_soc_info dm644x_edma_info[] = {
- {
- .n_channel = 64,
- .n_region = 4,
- .n_slot = 128,
- .n_tc = 2,
- .n_cc = 1,
- .queue_tc_mapping = queue_tc_mapping,
- .queue_priority_mapping = queue_priority_mapping,
- },
+static struct edma_soc_info edma_cc0_info = {
+ .n_channel = 64,
+ .n_region = 4,
+ .n_slot = 128,
+ .n_tc = 2,
+ .n_cc = 1,
+ .queue_tc_mapping = queue_tc_mapping,
+ .queue_priority_mapping = queue_priority_mapping,
+};
+
+static struct edma_soc_info *dm644x_edma_info[EDMA_MAX_CC] = {
+ &edma_cc0_info,
};
static struct resource edma_resources[] = {
diff --git a/arch/arm/mach-davinci/dm646x.c b/arch/arm/mach-davinci/dm646x.c
index 94045656cff..e4a3df1872a 100644
--- a/arch/arm/mach-davinci/dm646x.c
+++ b/arch/arm/mach-davinci/dm646x.c
@@ -529,16 +529,18 @@ dm646x_queue_priority_mapping[][2] = {
{-1, -1},
};
-static struct edma_soc_info dm646x_edma_info[] = {
- {
- .n_channel = 64,
- .n_region = 6, /* 0-1, 4-7 */
- .n_slot = 512,
- .n_tc = 4,
- .n_cc = 1,
- .queue_tc_mapping = dm646x_queue_tc_mapping,
- .queue_priority_mapping = dm646x_queue_priority_mapping,
- },
+static struct edma_soc_info edma_cc0_info = {
+ .n_channel = 64,
+ .n_region = 6, /* 0-1, 4-7 */
+ .n_slot = 512,
+ .n_tc = 4,
+ .n_cc = 1,
+ .queue_tc_mapping = dm646x_queue_tc_mapping,
+ .queue_priority_mapping = dm646x_queue_priority_mapping,
+};
+
+static struct edma_soc_info *dm646x_edma_info[EDMA_MAX_CC] = {
+ &edma_cc0_info,
};
static struct resource edma_resources[] = {
@@ -877,6 +879,13 @@ void dm646x_setup_vpif(struct vpif_display_config *display_config,
platform_device_register(&vpif_capture_dev);
}
+int __init dm646x_init_edma(struct edma_rsv_info *rsv)
+{
+ edma_cc0_info.rsv = rsv;
+
+ return platform_device_register(&dm646x_edma_device);
+}
+
void __init dm646x_init(void)
{
dm646x_board_setup_refclk(&ref_clk);
@@ -888,7 +897,6 @@ static int __init dm646x_init_devices(void)
if (!cpu_is_davinci_dm646x())
return 0;
- platform_device_register(&dm646x_edma_device);
platform_device_register(&dm646x_emac_device);
return 0;
}
diff --git a/arch/arm/mach-davinci/dma.c b/arch/arm/mach-davinci/dma.c
index d33827aadda..2ede598b77d 100644
--- a/arch/arm/mach-davinci/dma.c
+++ b/arch/arm/mach-davinci/dma.c
@@ -99,8 +99,6 @@
#define EDMA_MAX_DMACH 64
#define EDMA_MAX_PARAMENTRY 512
-#define EDMA_MAX_CC 2
-
/*****************************************************************************/
@@ -207,6 +205,18 @@ static inline void edma_parm_or(unsigned ctlr, int offset, int param_no,
edma_or(ctlr, EDMA_PARM + offset + (param_no << 5), or);
}
+static inline void set_bits(int offset, int len, unsigned long *p)
+{
+ for (; len > 0; len--)
+ set_bit(offset + (len - 1), p);
+}
+
+static inline void clear_bits(int offset, int len, unsigned long *p)
+{
+ for (; len > 0; len--)
+ clear_bit(offset + (len - 1), p);
+}
+
/*****************************************************************************/
/* actual number of DMA channels and slots on this silicon */
@@ -1376,11 +1386,13 @@ EXPORT_SYMBOL(edma_clear_event);
static int __init edma_probe(struct platform_device *pdev)
{
- struct edma_soc_info *info = pdev->dev.platform_data;
+ struct edma_soc_info **info = pdev->dev.platform_data;
const s8 (*queue_priority_mapping)[2];
const s8 (*queue_tc_mapping)[2];
- int i, j, found = 0;
+ int i, j, off, ln, found = 0;
int status = -1;
+ const s16 (*rsv_chans)[2];
+ const s16 (*rsv_slots)[2];
int irq[EDMA_MAX_CC] = {0, 0};
int err_irq[EDMA_MAX_CC] = {0, 0};
struct resource *r[EDMA_MAX_CC] = {NULL};
@@ -1395,7 +1407,7 @@ static int __init edma_probe(struct platform_device *pdev)
sprintf(res_name, "edma_cc%d", j);
r[j] = platform_get_resource_byname(pdev, IORESOURCE_MEM,
res_name);
- if (!r[j]) {
+ if (!r[j] || !info[j]) {
if (found)
break;
else
@@ -1426,13 +1438,14 @@ static int __init edma_probe(struct platform_device *pdev)
}
memset(edma_cc[j], 0, sizeof(struct edma));
- edma_cc[j]->num_channels = min_t(unsigned, info[j].n_channel,
+ edma_cc[j]->num_channels = min_t(unsigned, info[j]->n_channel,
EDMA_MAX_DMACH);
- edma_cc[j]->num_slots = min_t(unsigned, info[j].n_slot,
+ edma_cc[j]->num_slots = min_t(unsigned, info[j]->n_slot,
EDMA_MAX_PARAMENTRY);
- edma_cc[j]->num_cc = min_t(unsigned, info[j].n_cc, EDMA_MAX_CC);
+ edma_cc[j]->num_cc = min_t(unsigned, info[j]->n_cc,
+ EDMA_MAX_CC);
- edma_cc[j]->default_queue = info[j].default_queue;
+ edma_cc[j]->default_queue = info[j]->default_queue;
if (!edma_cc[j]->default_queue)
edma_cc[j]->default_queue = EVENTQ_1;
@@ -1447,6 +1460,31 @@ static int __init edma_probe(struct platform_device *pdev)
memset(edma_cc[j]->edma_unused, 0xff,
sizeof(edma_cc[j]->edma_unused));
+ if (info[j]->rsv) {
+
+ /* Clear the reserved channels in unused list */
+ rsv_chans = info[j]->rsv->rsv_chans;
+ if (rsv_chans) {
+ for (i = 0; rsv_chans[i][0] != -1; i++) {
+ off = rsv_chans[i][0];
+ ln = rsv_chans[i][1];
+ clear_bits(off, ln,
+ edma_cc[j]->edma_unused);
+ }
+ }
+
+ /* Set the reserved slots in inuse list */
+ rsv_slots = info[j]->rsv->rsv_slots;
+ if (rsv_slots) {
+ for (i = 0; rsv_slots[i][0] != -1; i++) {
+ off = rsv_slots[i][0];
+ ln = rsv_slots[i][1];
+ set_bits(off, ln,
+ edma_cc[j]->edma_inuse);
+ }
+ }
+ }
+
sprintf(irq_name, "edma%d", j);
irq[j] = platform_get_irq_byname(pdev, irq_name);
edma_cc[j]->irq_res_start = irq[j];
@@ -1476,8 +1514,8 @@ static int __init edma_probe(struct platform_device *pdev)
for (i = 0; i < edma_cc[j]->num_channels; i++)
map_dmach_queue(j, i, EVENTQ_1);
- queue_tc_mapping = info[j].queue_tc_mapping;
- queue_priority_mapping = info[j].queue_priority_mapping;
+ queue_tc_mapping = info[j]->queue_tc_mapping;
+ queue_priority_mapping = info[j]->queue_priority_mapping;
/* Event queue to TC mapping */
for (i = 0; queue_tc_mapping[i][0] != -1; i++)
@@ -1496,7 +1534,7 @@ static int __init edma_probe(struct platform_device *pdev)
if (edma_read(j, EDMA_CCCFG) & CHMAP_EXIST)
map_dmach_param(j);
- for (i = 0; i < info[j].n_region; i++) {
+ for (i = 0; i < info[j]->n_region; i++) {
edma_write_array2(j, EDMA_DRAE, i, 0, 0x0);
edma_write_array2(j, EDMA_DRAE, i, 1, 0x0);
edma_write_array(j, EDMA_QRAE, i, 0x0);
diff --git a/arch/arm/mach-davinci/gpio-tnetv107x.c b/arch/arm/mach-davinci/gpio-tnetv107x.c
new file mode 100644
index 00000000000..d10298620e2
--- /dev/null
+++ b/arch/arm/mach-davinci/gpio-tnetv107x.c
@@ -0,0 +1,205 @@
+/*
+ * Texas Instruments TNETV107X GPIO Controller
+ *
+ * Copyright (C) 2010 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 version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/gpio.h>
+
+#include <mach/common.h>
+#include <mach/tnetv107x.h>
+
+struct tnetv107x_gpio_regs {
+ u32 idver;
+ u32 data_in[3];
+ u32 data_out[3];
+ u32 direction[3];
+ u32 enable[3];
+};
+
+#define gpio_reg_index(gpio) ((gpio) >> 5)
+#define gpio_reg_bit(gpio) BIT((gpio) & 0x1f)
+
+#define gpio_reg_rmw(reg, mask, val) \
+ __raw_writel((__raw_readl(reg) & ~(mask)) | (val), (reg))
+
+#define gpio_reg_set_bit(reg, gpio) \
+ gpio_reg_rmw((reg) + gpio_reg_index(gpio), 0, gpio_reg_bit(gpio))
+
+#define gpio_reg_clear_bit(reg, gpio) \
+ gpio_reg_rmw((reg) + gpio_reg_index(gpio), gpio_reg_bit(gpio), 0)
+
+#define gpio_reg_get_bit(reg, gpio) \
+ (__raw_readl((reg) + gpio_reg_index(gpio)) & gpio_reg_bit(gpio))
+
+#define chip2controller(chip) \
+ container_of(chip, struct davinci_gpio_controller, chip)
+
+#define TNETV107X_GPIO_CTLRS DIV_ROUND_UP(TNETV107X_N_GPIO, 32)
+
+static struct davinci_gpio_controller chips[TNETV107X_GPIO_CTLRS];
+
+static int tnetv107x_gpio_request(struct gpio_chip *chip, unsigned offset)
+{
+ struct davinci_gpio_controller *ctlr = chip2controller(chip);
+ struct tnetv107x_gpio_regs __iomem *regs = ctlr->regs;
+ unsigned gpio = chip->base + offset;
+ unsigned long flags;
+
+ spin_lock_irqsave(&ctlr->lock, flags);
+
+ gpio_reg_set_bit(&regs->enable, gpio);
+
+ spin_unlock_irqrestore(&ctlr->lock, flags);
+
+ return 0;
+}
+
+static void tnetv107x_gpio_free(struct gpio_chip *chip, unsigned offset)
+{
+ struct davinci_gpio_controller *ctlr = chip2controller(chip);
+ struct tnetv107x_gpio_regs __iomem *regs = ctlr->regs;
+ unsigned gpio = chip->base + offset;
+ unsigned long flags;
+
+ spin_lock_irqsave(&ctlr->lock, flags);
+
+ gpio_reg_clear_bit(&regs->enable, gpio);
+
+ spin_unlock_irqrestore(&ctlr->lock, flags);
+}
+
+static int tnetv107x_gpio_dir_in(struct gpio_chip *chip, unsigned offset)
+{
+ struct davinci_gpio_controller *ctlr = chip2controller(chip);
+ struct tnetv107x_gpio_regs __iomem *regs = ctlr->regs;
+ unsigned gpio = chip->base + offset;
+ unsigned long flags;
+
+ spin_lock_irqsave(&ctlr->lock, flags);
+
+ gpio_reg_set_bit(&regs->direction, gpio);
+
+ spin_unlock_irqrestore(&ctlr->lock, flags);
+
+ return 0;
+}
+
+static int tnetv107x_gpio_dir_out(struct gpio_chip *chip,
+ unsigned offset, int value)
+{
+ struct davinci_gpio_controller *ctlr = chip2controller(chip);
+ struct tnetv107x_gpio_regs __iomem *regs = ctlr->regs;
+ unsigned gpio = chip->base + offset;
+ unsigned long flags;
+
+ spin_lock_irqsave(&ctlr->lock, flags);
+
+ if (value)
+ gpio_reg_set_bit(&regs->data_out, gpio);
+ else
+ gpio_reg_clear_bit(&regs->data_out, gpio);
+
+ gpio_reg_clear_bit(&regs->direction, gpio);
+
+ spin_unlock_irqrestore(&ctlr->lock, flags);
+
+ return 0;
+}
+
+static int tnetv107x_gpio_get(struct gpio_chip *chip, unsigned offset)
+{
+ struct davinci_gpio_controller *ctlr = chip2controller(chip);
+ struct tnetv107x_gpio_regs __iomem *regs = ctlr->regs;
+ unsigned gpio = chip->base + offset;
+ int ret;
+
+ ret = gpio_reg_get_bit(&regs->data_in, gpio);
+
+ return ret ? 1 : 0;
+}
+
+static void tnetv107x_gpio_set(struct gpio_chip *chip,
+ unsigned offset, int value)
+{
+ struct davinci_gpio_controller *ctlr = chip2controller(chip);
+ struct tnetv107x_gpio_regs __iomem *regs = ctlr->regs;
+ unsigned gpio = chip->base + offset;
+ unsigned long flags;
+
+ spin_lock_irqsave(&ctlr->lock, flags);
+
+ if (value)
+ gpio_reg_set_bit(&regs->data_out, gpio);
+ else
+ gpio_reg_clear_bit(&regs->data_out, gpio);
+
+ spin_unlock_irqrestore(&ctlr->lock, flags);
+}
+
+static int __init tnetv107x_gpio_setup(void)
+{
+ int i, base;
+ unsigned ngpio;
+ struct davinci_soc_info *soc_info = &davinci_soc_info;
+ struct tnetv107x_gpio_regs *regs;
+ struct davinci_gpio_controller *ctlr;
+
+ if (soc_info->gpio_type != GPIO_TYPE_TNETV107X)
+ return 0;
+
+ ngpio = soc_info->gpio_num;
+ if (ngpio == 0) {
+ pr_err("GPIO setup: how many GPIOs?\n");
+ return -EINVAL;
+ }
+
+ if (WARN_ON(TNETV107X_N_GPIO < ngpio))
+ ngpio = TNETV107X_N_GPIO;
+
+ regs = ioremap(soc_info->gpio_base, SZ_4K);
+ if (WARN_ON(!regs))
+ return -EINVAL;
+
+ for (i = 0, base = 0; base < ngpio; i++, base += 32) {
+ ctlr = &chips[i];
+
+ ctlr->chip.label = "tnetv107x";
+ ctlr->chip.can_sleep = 0;
+ ctlr->chip.base = base;
+ ctlr->chip.ngpio = ngpio - base;
+ if (ctlr->chip.ngpio > 32)
+ ctlr->chip.ngpio = 32;
+
+ ctlr->chip.request = tnetv107x_gpio_request;
+ ctlr->chip.free = tnetv107x_gpio_free;
+ ctlr->chip.direction_input = tnetv107x_gpio_dir_in;
+ ctlr->chip.get = tnetv107x_gpio_get;
+ ctlr->chip.direction_output = tnetv107x_gpio_dir_out;
+ ctlr->chip.set = tnetv107x_gpio_set;
+
+ spin_lock_init(&ctlr->lock);
+
+ ctlr->regs = regs;
+ ctlr->set_data = &regs->data_out[i];
+ ctlr->clr_data = &regs->data_out[i];
+ ctlr->in_data = &regs->data_in[i];
+
+ gpiochip_add(&ctlr->chip);
+ }
+
+ soc_info->gpio_ctlrs = chips;
+ soc_info->gpio_ctlrs_num = DIV_ROUND_UP(ngpio, 32);
+ return 0;
+}
+pure_initcall(tnetv107x_gpio_setup);
diff --git a/arch/arm/mach-davinci/include/mach/asp.h b/arch/arm/mach-davinci/include/mach/asp.h
index 834725f1e81..9aa240909a2 100644
--- a/arch/arm/mach-davinci/include/mach/asp.h
+++ b/arch/arm/mach-davinci/include/mach/asp.h
@@ -52,7 +52,8 @@
struct snd_platform_data {
u32 tx_dma_offset;
u32 rx_dma_offset;
- enum dma_event_q eventq_no; /* event queue number */
+ enum dma_event_q asp_chan_q; /* event queue number for ASP channel */
+ enum dma_event_q ram_chan_q; /* event queue number for RAM channel */
unsigned int codec_fmt;
/*
* Allowing this is more efficient and eliminates left and right swaps
@@ -63,6 +64,49 @@ struct snd_platform_data {
unsigned sram_size_playback;
unsigned sram_size_capture;
+ /*
+ * If McBSP peripheral gets the clock from an external pin,
+ * there are three chooses, that are MCBSP_CLKX, MCBSP_CLKR
+ * and MCBSP_CLKS.
+ * Depending on different hardware connections it is possible
+ * to use this setting to change the behaviour of McBSP
+ * driver. The dm365_clk_input_pin enum is available for dm365
+ */
+ int clk_input_pin;
+
+ /*
+ * This flag works when both clock and FS are outputs for the cpu
+ * and makes clock more accurate (FS is not symmetrical and the
+ * clock is very fast.
+ * The clock becoming faster is named
+ * i2s continuous serial clock (I2S_SCK) and it is an externally
+ * visible bit clock.
+ *
+ * first line : WordSelect
+ * second line : ContinuousSerialClock
+ * third line: SerialData
+ *
+ * SYMMETRICAL APPROACH:
+ * _______________________ LEFT
+ * _| RIGHT |______________________|
+ * _ _ _ _ _ _ _ _
+ * _| |_| |_ x16 _| |_| |_| |_| |_ x16 _| |_| |_
+ * _ _ _ _ _ _ _ _
+ * _/ \_/ \_ ... _/ \_/ \_/ \_/ \_ ... _/ \_/ \_
+ * \_/ \_/ \_/ \_/ \_/ \_/ \_/ \_/
+ *
+ * ACCURATE CLOCK APPROACH:
+ * ______________ LEFT
+ * _| RIGHT |_______________________________|
+ * _ _ _ _ _ _ _ _ _
+ * _| |_ x16 _| |_| |_ x16 _| |_| |_| |_| |_| |_| |
+ * _ _ _ _ dummy cycles
+ * _/ \_ ... _/ \_/ \_ ... _/ \__________________
+ * \_/ \_/ \_/ \_/
+ *
+ */
+ bool i2s_accurate_sck;
+
/* McASP specific fields */
int tdm_slots;
u8 op_mode;
@@ -78,6 +122,11 @@ enum {
MCASP_VERSION_2, /* DA8xx/OMAPL1x */
};
+enum dm365_clk_input_pin {
+ MCBSP_CLKR = 0, /* DM365 */
+ MCBSP_CLKS,
+};
+
#define INACTIVE_MODE 0
#define TX_MODE 1
#define RX_MODE 2
diff --git a/arch/arm/mach-davinci/include/mach/da8xx.h b/arch/arm/mach-davinci/include/mach/da8xx.h
index 1b31a9aa8fb..3c07059f526 100644
--- a/arch/arm/mach-davinci/include/mach/da8xx.h
+++ b/arch/arm/mach-davinci/include/mach/da8xx.h
@@ -67,7 +67,8 @@ extern void __iomem *da8xx_syscfg1_base;
void __init da830_init(void);
void __init da850_init(void);
-int da8xx_register_edma(void);
+int da830_register_edma(struct edma_rsv_info *rsv);
+int da850_register_edma(struct edma_rsv_info *rsv[2]);
int da8xx_register_i2c(int instance, struct davinci_i2c_platform_data *pdata);
int da8xx_register_watchdog(void);
int da8xx_register_usb20(unsigned mA, unsigned potpgt);
diff --git a/arch/arm/mach-davinci/include/mach/debug-macro.S b/arch/arm/mach-davinci/include/mach/debug-macro.S
index 3cd93a801d9..f761dfdb868 100644
--- a/arch/arm/mach-davinci/include/mach/debug-macro.S
+++ b/arch/arm/mach-davinci/include/mach/debug-macro.S
@@ -17,22 +17,50 @@
*/
#include <linux/serial_reg.h>
+
+#include <asm/memory.h>
+
+#include <mach/serial.h>
+
#define UART_SHIFT 2
+ .pushsection .data
+davinci_uart_phys: .word 0
+davinci_uart_virt: .word 0
+ .popsection
+
.macro addruart, rx, tmp
+
+ /* Use davinci_uart_phys/virt if already configured */
+10: mrc p15, 0, \rx, c1, c0
+ tst \rx, #1 @ MMU enabled?
+ ldreq \rx, =__virt_to_phys(davinci_uart_phys)
+ ldrne \rx, =davinci_uart_virt
+ ldr \rx, [\rx]
+ cmp \rx, #0 @ is port configured?
+ bne 99f @ already configured
+
mrc p15, 0, \rx, c1, c0
tst \rx, #1 @ MMU enabled?
- moveq \rx, #0x01000000 @ physical base address
- movne \rx, #0xfe000000 @ virtual base
-#if defined(CONFIG_ARCH_DAVINCI_DA8XX) && defined(CONFIG_ARCH_DAVINCI_DMx)
-#error Cannot enable DaVinci and DA8XX platforms concurrently
-#elif defined(CONFIG_MACH_DAVINCI_DA830_EVM) || \
- defined(CONFIG_MACH_DAVINCI_DA850_EVM)
- orr \rx, \rx, #0x00d00000 @ physical base address
- orr \rx, \rx, #0x0000d000 @ of UART 2
-#else
- orr \rx, \rx, #0x00c20000 @ UART 0
-#endif
+
+ /* Copy uart phys address from decompressor uart info */
+ ldreq \tmp, =__virt_to_phys(davinci_uart_phys)
+ ldrne \tmp, =davinci_uart_phys
+ ldreq \rx, =DAVINCI_UART_INFO
+ ldrne \rx, =__phys_to_virt(DAVINCI_UART_INFO)
+ ldr \rx, [\rx, #0]
+ str \rx, [\tmp]
+
+ /* Copy uart virt address from decompressor uart info */
+ ldreq \tmp, =__virt_to_phys(davinci_uart_virt)
+ ldrne \tmp, =davinci_uart_virt
+ ldreq \rx, =DAVINCI_UART_INFO
+ ldrne \rx, =__phys_to_virt(DAVINCI_UART_INFO)
+ ldr \rx, [\rx, #4]
+ str \rx, [\tmp]
+
+ b 10b
+99:
.endm
.macro senduart,rd,rx
diff --git a/arch/arm/mach-davinci/include/mach/dm646x.h b/arch/arm/mach-davinci/include/mach/dm646x.h
index add6f794a36..0a27ee9a70e 100644
--- a/arch/arm/mach-davinci/include/mach/dm646x.h
+++ b/arch/arm/mach-davinci/include/mach/dm646x.h
@@ -32,6 +32,7 @@ void __init dm646x_init(void);
void __init dm646x_init_mcasp0(struct snd_platform_data *pdata);
void __init dm646x_init_mcasp1(struct snd_platform_data *pdata);
void __init dm646x_board_setup_refclk(struct clk *clk);
+int __init dm646x_init_edma(struct edma_rsv_info *rsv);
void dm646x_video_init(void);
diff --git a/arch/arm/mach-davinci/include/mach/edma.h b/arch/arm/mach-davinci/include/mach/edma.h
index ced3092af5b..dc10ef6cf57 100644
--- a/arch/arm/mach-davinci/include/mach/edma.h
+++ b/arch/arm/mach-davinci/include/mach/edma.h
@@ -230,6 +230,8 @@ enum sync_dimension {
#define EDMA_CONT_PARAMS_FIXED_EXACT 1002
#define EDMA_CONT_PARAMS_FIXED_NOT_EXACT 1003
+#define EDMA_MAX_CC 2
+
/* alloc/free DMA channels and their dedicated parameter RAM slots */
int edma_alloc_channel(int channel,
void (*callback)(unsigned channel, u16 ch_status, void *data),
@@ -269,6 +271,12 @@ void edma_clear_event(unsigned channel);
void edma_pause(unsigned channel);
void edma_resume(unsigned channel);
+struct edma_rsv_info {
+
+ const s16 (*rsv_chans)[2];
+ const s16 (*rsv_slots)[2];
+};
+
/* platform_data for EDMA driver */
struct edma_soc_info {
@@ -280,6 +288,9 @@ struct edma_soc_info {
unsigned n_cc;
enum dma_event_q default_queue;
+ /* Resource reservation for other cores */
+ struct edma_rsv_info *rsv;
+
const s8 (*queue_tc_mapping)[2];
const s8 (*queue_priority_mapping)[2];
};
diff --git a/arch/arm/mach-davinci/include/mach/gpio.h b/arch/arm/mach-davinci/include/mach/gpio.h
index 504cc180a60..fbece126c2b 100644
--- a/arch/arm/mach-davinci/include/mach/gpio.h
+++ b/arch/arm/mach-davinci/include/mach/gpio.h
@@ -25,6 +25,7 @@
enum davinci_gpio_type {
GPIO_TYPE_DAVINCI = 0,
+ GPIO_TYPE_TNETV107X,
};
/*
@@ -87,9 +88,13 @@ static inline u32 __gpio_mask(unsigned gpio)
return 1 << (gpio % 32);
}
-/* The get/set/clear functions will inline when called with constant
+/*
+ * The get/set/clear functions will inline when called with constant
* parameters referencing built-in GPIOs, for low-overhead bitbanging.
*
+ * gpio_set_value() will inline only on traditional Davinci style controllers
+ * with distinct set/clear registers.
+ *
* Otherwise, calls with variable parameters or referencing external
* GPIOs (e.g. on GPIO expander chips) use outlined functions.
*/
@@ -100,12 +105,15 @@ static inline void gpio_set_value(unsigned gpio, int value)
u32 mask;
ctlr = __gpio_to_controller(gpio);
- mask = __gpio_mask(gpio);
- if (value)
- __raw_writel(mask, ctlr->set_data);
- else
- __raw_writel(mask, ctlr->clr_data);
- return;
+
+ if (ctlr->set_data != ctlr->clr_data) {
+ mask = __gpio_mask(gpio);
+ if (value)
+ __raw_writel(mask, ctlr->set_data);
+ else
+ __raw_writel(mask, ctlr->clr_data);
+ return;
+ }
}
__gpio_set_value(gpio, value);
diff --git a/arch/arm/mach-davinci/include/mach/serial.h b/arch/arm/mach-davinci/include/mach/serial.h
index f6c4f34909a..8051110b8ac 100644
--- a/arch/arm/mach-davinci/include/mach/serial.h
+++ b/arch/arm/mach-davinci/include/mach/serial.h
@@ -11,8 +11,19 @@
#ifndef __ASM_ARCH_SERIAL_H
#define __ASM_ARCH_SERIAL_H
+#include <asm/memory.h>
+
#include <mach/hardware.h>
+/*
+ * Stolen area that contains debug uart physical and virtual addresses. These
+ * addresses are filled in by the uncompress.h code, and are used by the debug
+ * macros in debug-macro.S.
+ *
+ * This area sits just below the page tables (see arch/arm/kernel/head.S).
+ */
+#define DAVINCI_UART_INFO (PHYS_OFFSET + 0x3ff8)
+
#define DAVINCI_UART0_BASE (IO_PHYS + 0x20000)
#define DAVINCI_UART1_BASE (IO_PHYS + 0x20400)
#define DAVINCI_UART2_BASE (IO_PHYS + 0x20800)
@@ -21,16 +32,26 @@
#define DA8XX_UART1_BASE (IO_PHYS + 0x10c000)
#define DA8XX_UART2_BASE (IO_PHYS + 0x10d000)
+#define TNETV107X_UART0_BASE 0x08108100
+#define TNETV107X_UART1_BASE 0x08088400
+#define TNETV107X_UART2_BASE 0x08108300
+
+#define TNETV107X_UART0_VIRT IOMEM(0xfee08100)
+#define TNETV107X_UART1_VIRT IOMEM(0xfed88400)
+#define TNETV107X_UART2_VIRT IOMEM(0xfee08300)
+
/* DaVinci UART register offsets */
#define UART_DAVINCI_PWREMU 0x0c
#define UART_DM646X_SCR 0x10
#define UART_DM646X_SCR_TX_WATERMARK 0x08
+#ifndef __ASSEMBLY__
struct davinci_uart_config {
/* Bit field of UARTs present; bit 0 --> UART1 */
unsigned int enabled_uarts;
};
extern int davinci_serial_init(struct davinci_uart_config *);
+#endif
#endif /* __ASM_ARCH_SERIAL_H */
diff --git a/arch/arm/mach-davinci/include/mach/tnetv107x.h b/arch/arm/mach-davinci/include/mach/tnetv107x.h
new file mode 100644
index 00000000000..c7206473312
--- /dev/null
+++ b/arch/arm/mach-davinci/include/mach/tnetv107x.h
@@ -0,0 +1,55 @@
+/*
+ * Texas Instruments TNETV107X SoC Specific Defines
+ *
+ * Copyright (C) 2010 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 version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+#ifndef __ASM_ARCH_DAVINCI_TNETV107X_H
+#define __ASM_ARCH_DAVINCI_TNETV107X_H
+
+#include <asm/sizes.h>
+
+#define TNETV107X_DDR_BASE 0x80000000
+
+/*
+ * Fixed mapping for early init starts here. If low-level debug is enabled,
+ * this area also gets mapped via io_pg_offset and io_phys by the boot code.
+ * To fit in with the io_pg_offset calculation, the io base address selected
+ * here _must_ be a multiple of 2^20.
+ */
+#define TNETV107X_IO_BASE 0x08000000
+#define TNETV107X_IO_VIRT (IO_VIRT + SZ_1M)
+
+#define TNETV107X_N_GPIO 65
+
+#ifndef __ASSEMBLY__
+
+#include <linux/serial_8250.h>
+#include <mach/mmc.h>
+#include <mach/nand.h>
+#include <mach/serial.h>
+
+struct tnetv107x_device_info {
+ struct davinci_uart_config *serial_config;
+ struct davinci_mmc_config *mmc_config[2]; /* 2 controllers */
+ struct davinci_nand_pdata *nand_config[4]; /* 4 chipsels */
+};
+
+extern struct platform_device tnetv107x_wdt_device;
+extern struct platform_device tnetv107x_serial_device;
+
+extern void __init tnetv107x_init(void);
+extern void __init tnetv107x_devices_init(struct tnetv107x_device_info *);
+extern void __init tnetv107x_irq_init(void);
+
+#endif
+
+#endif /* __ASM_ARCH_DAVINCI_TNETV107X_H */
diff --git a/arch/arm/mach-davinci/include/mach/uncompress.h b/arch/arm/mach-davinci/include/mach/uncompress.h
index 33796b4db17..15a6192ad6e 100644
--- a/arch/arm/mach-davinci/include/mach/uncompress.h
+++ b/arch/arm/mach-davinci/include/mach/uncompress.h
@@ -1,8 +1,17 @@
/*
* Serial port stubs for kernel decompress status messages
*
- * Author: Anant Gole
- * (C) Copyright (C) 2006, Texas Instruments, Inc
+ * Initially based on:
+ * arch/arm/plat-omap/include/mach/uncompress.h
+ *
+ * Original copyrights follow.
+ *
+ * Copyright (C) 2000 RidgeRun, Inc.
+ * Author: Greg Lonnon <glonnon@ridgerun.com>
+ *
+ * Rewritten by:
+ * Author: <source@mvista.com>
+ * 2004 (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
@@ -11,30 +20,17 @@
#include <linux/types.h>
#include <linux/serial_reg.h>
-#include <mach/serial.h>
#include <asm/mach-types.h>
-extern unsigned int __machine_arch_type;
+#include <mach/serial.h>
static u32 *uart;
-
-static u32 *get_uart_base(void)
-{
- if (__machine_arch_type == MACH_TYPE_DAVINCI_DA830_EVM ||
- __machine_arch_type == MACH_TYPE_DAVINCI_DA850_EVM)
- return (u32 *)DA8XX_UART2_BASE;
- else
- return (u32 *)DAVINCI_UART0_BASE;
-}
+static u32 *uart_info = (u32 *)(DAVINCI_UART_INFO);
/* PORT_16C550A, in polled non-fifo mode */
-
static void putc(char c)
{
- if (!uart)
- uart = get_uart_base();
-
while (!(uart[UART_LSR] & UART_LSR_THRE))
barrier();
uart[UART_TX] = c;
@@ -42,12 +38,61 @@ static void putc(char c)
static inline void flush(void)
{
- if (!uart)
- uart = get_uart_base();
-
while (!(uart[UART_LSR] & UART_LSR_THRE))
barrier();
}
-#define arch_decomp_setup()
+static inline void set_uart_info(u32 phys, void * __iomem virt)
+{
+ uart = (u32 *)phys;
+ uart_info[0] = phys;
+ uart_info[1] = (u32)virt;
+}
+
+#define _DEBUG_LL_ENTRY(machine, phys, virt) \
+ if (machine_is_##machine()) { \
+ set_uart_info(phys, virt); \
+ break; \
+ }
+
+#define DEBUG_LL_DAVINCI(machine, port) \
+ _DEBUG_LL_ENTRY(machine, DAVINCI_UART##port##_BASE, \
+ IO_ADDRESS(DAVINCI_UART##port##_BASE))
+
+#define DEBUG_LL_DA8XX(machine, port) \
+ _DEBUG_LL_ENTRY(machine, DA8XX_UART##port##_BASE, \
+ IO_ADDRESS(DA8XX_UART##port##_BASE))
+
+#define DEBUG_LL_TNETV107X(machine, port) \
+ _DEBUG_LL_ENTRY(machine, TNETV107X_UART##port##_BASE, \
+ TNETV107X_UART##port##_VIRT)
+
+static inline void __arch_decomp_setup(unsigned long arch_id)
+{
+ /*
+ * Initialize the port based on the machine ID from the bootloader.
+ * Note that we're using macros here instead of switch statement
+ * as machine_is functions are optimized out for the boards that
+ * are not selected.
+ */
+ do {
+ /* Davinci boards */
+ DEBUG_LL_DAVINCI(davinci_evm, 0);
+ DEBUG_LL_DAVINCI(sffsdr, 0);
+ DEBUG_LL_DAVINCI(neuros_osd2, 0);
+ DEBUG_LL_DAVINCI(davinci_dm355_evm, 0);
+ DEBUG_LL_DAVINCI(dm355_leopard, 0);
+ DEBUG_LL_DAVINCI(davinci_dm6467_evm, 0);
+ DEBUG_LL_DAVINCI(davinci_dm365_evm, 0);
+
+ /* DA8xx boards */
+ DEBUG_LL_DA8XX(davinci_da830_evm, 2);
+ DEBUG_LL_DA8XX(davinci_da850_evm, 2);
+
+ /* TNETV107x boards */
+ DEBUG_LL_TNETV107X(tnetv107x, 1);
+ } while (0);
+}
+
+#define arch_decomp_setup() __arch_decomp_setup(arch_id)
#define arch_decomp_wdog()
diff --git a/arch/arm/mach-davinci/tnetv107x.c b/arch/arm/mach-davinci/tnetv107x.c
new file mode 100644
index 00000000000..864e60482c5
--- /dev/null
+++ b/arch/arm/mach-davinci/tnetv107x.c
@@ -0,0 +1,753 @@
+/*
+ * Texas Instruments TNETV107X SoC Support
+ *
+ * Copyright (C) 2010 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 version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+
+#include <asm/mach/map.h>
+
+#include <mach/common.h>
+#include <mach/time.h>
+#include <mach/cputype.h>
+#include <mach/psc.h>
+#include <mach/cp_intc.h>
+#include <mach/irqs.h>
+#include <mach/gpio.h>
+#include <mach/hardware.h>
+#include <mach/tnetv107x.h>
+
+#include "clock.h"
+#include "mux.h"
+
+/* Base addresses for on-chip devices */
+#define TNETV107X_INTC_BASE 0x03000000
+#define TNETV107X_TIMER0_BASE 0x08086500
+#define TNETV107X_TIMER1_BASE 0x08086600
+#define TNETV107X_CHIP_CFG_BASE 0x08087000
+#define TNETV107X_GPIO_BASE 0x08088000
+#define TNETV107X_CLOCK_CONTROL_BASE 0x0808a000
+#define TNETV107X_PSC_BASE 0x0808b000
+
+/* Reference clock frequencies */
+#define OSC_FREQ_ONCHIP (24000 * 1000)
+#define OSC_FREQ_OFFCHIP_SYS (25000 * 1000)
+#define OSC_FREQ_OFFCHIP_ETH (25000 * 1000)
+#define OSC_FREQ_OFFCHIP_TDM (19200 * 1000)
+
+#define N_PLLS 3
+
+/* Clock Control Registers */
+struct clk_ctrl_regs {
+ u32 pll_bypass;
+ u32 _reserved0;
+ u32 gem_lrst;
+ u32 _reserved1;
+ u32 pll_unlock_stat;
+ u32 sys_unlock;
+ u32 eth_unlock;
+ u32 tdm_unlock;
+};
+
+/* SSPLL Registers */
+struct sspll_regs {
+ u32 modes;
+ u32 post_div;
+ u32 pre_div;
+ u32 mult_factor;
+ u32 divider_range;
+ u32 bw_divider;
+ u32 spr_amount;
+ u32 spr_rate_div;
+ u32 diag;
+};
+
+/* Watchdog Timer Registers */
+struct wdt_regs {
+ u32 kick_lock;
+ u32 kick;
+ u32 change_lock;
+ u32 change ;
+ u32 disable_lock;
+ u32 disable;
+ u32 prescale_lock;
+ u32 prescale;
+};
+
+static struct clk_ctrl_regs __iomem *clk_ctrl_regs;
+
+static struct sspll_regs __iomem *sspll_regs[N_PLLS];
+static int sspll_regs_base[N_PLLS] = { 0x40, 0x80, 0xc0 };
+
+/* PLL bypass bit shifts in clk_ctrl_regs->pll_bypass register */
+static u32 bypass_mask[N_PLLS] = { BIT(0), BIT(2), BIT(1) };
+
+/* offchip (external) reference clock frequencies */
+static u32 pll_ext_freq[] = {
+ OSC_FREQ_OFFCHIP_SYS,
+ OSC_FREQ_OFFCHIP_TDM,
+ OSC_FREQ_OFFCHIP_ETH
+};
+
+/* PSC control registers */
+static u32 psc_regs[] __initconst = { TNETV107X_PSC_BASE };
+
+/* Host map for interrupt controller */
+static u32 intc_host_map[] = { 0x01010000, 0x01010101, -1 };
+
+static unsigned long clk_sspll_recalc(struct clk *clk);
+
+/* Level 1 - the PLLs */
+#define define_pll_clk(cname, pll, divmask, base) \
+ static struct pll_data pll_##cname##_data = { \
+ .num = pll, \
+ .div_ratio_mask = divmask, \
+ .phys_base = base + \
+ TNETV107X_CLOCK_CONTROL_BASE, \
+ }; \
+ static struct clk pll_##cname##_clk = { \
+ .name = "pll_" #cname "_clk", \
+ .pll_data = &pll_##cname##_data, \
+ .flags = CLK_PLL, \
+ .recalc = clk_sspll_recalc, \
+ }
+
+define_pll_clk(sys, 0, 0x1ff, 0x600);
+define_pll_clk(tdm, 1, 0x0ff, 0x200);
+define_pll_clk(eth, 2, 0x0ff, 0x400);
+
+/* Level 2 - divided outputs from the PLLs */
+#define define_pll_div_clk(pll, cname, div) \
+ static struct clk pll##_##cname##_clk = { \
+ .name = #pll "_" #cname "_clk",\
+ .parent = &pll_##pll##_clk, \
+ .flags = CLK_PLL, \
+ .div_reg = PLLDIV##div, \
+ }
+
+define_pll_div_clk(sys, arm1176, 1);
+define_pll_div_clk(sys, dsp, 2);
+define_pll_div_clk(sys, ddr, 3);
+define_pll_div_clk(sys, full, 4);
+define_pll_div_clk(sys, lcd, 5);
+define_pll_div_clk(sys, vlynq_ref, 6);
+define_pll_div_clk(sys, tsc, 7);
+define_pll_div_clk(sys, half, 8);
+
+define_pll_div_clk(eth, 5mhz, 1);
+define_pll_div_clk(eth, 50mhz, 2);
+define_pll_div_clk(eth, 125mhz, 3);
+define_pll_div_clk(eth, 250mhz, 4);
+define_pll_div_clk(eth, 25mhz, 5);
+
+define_pll_div_clk(tdm, 0, 1);
+define_pll_div_clk(tdm, extra, 2);
+define_pll_div_clk(tdm, 1, 3);
+
+
+/* Level 3 - LPSC gated clocks */
+#define __lpsc_clk(cname, _parent, mod, flg) \
+ static struct clk clk_##cname = { \
+ .name = #cname, \
+ .parent = &_parent, \
+ .lpsc = TNETV107X_LPSC_##mod,\
+ .flags = flg, \
+ }
+
+#define lpsc_clk_enabled(cname, parent, mod) \
+ __lpsc_clk(cname, parent, mod, ALWAYS_ENABLED)
+
+#define lpsc_clk(cname, parent, mod) \
+ __lpsc_clk(cname, parent, mod, 0)
+
+lpsc_clk_enabled(arm, sys_arm1176_clk, ARM);
+lpsc_clk_enabled(gem, sys_dsp_clk, GEM);
+lpsc_clk_enabled(ddr2_phy, sys_ddr_clk, DDR2_PHY);
+lpsc_clk_enabled(tpcc, sys_full_clk, TPCC);
+lpsc_clk_enabled(tptc0, sys_full_clk, TPTC0);
+lpsc_clk_enabled(tptc1, sys_full_clk, TPTC1);
+lpsc_clk_enabled(ram, sys_full_clk, RAM);
+lpsc_clk_enabled(aemif, sys_full_clk, AEMIF);
+lpsc_clk_enabled(chipcfg, sys_half_clk, CHIP_CFG);
+lpsc_clk_enabled(rom, sys_half_clk, ROM);
+lpsc_clk_enabled(secctl, sys_half_clk, SECCTL);
+lpsc_clk_enabled(keymgr, sys_half_clk, KEYMGR);
+lpsc_clk_enabled(gpio, sys_half_clk, GPIO);
+lpsc_clk_enabled(debugss, sys_half_clk, DEBUGSS);
+lpsc_clk_enabled(system, sys_half_clk, SYSTEM);
+lpsc_clk_enabled(ddr2_vrst, sys_ddr_clk, DDR2_EMIF1_VRST);
+lpsc_clk_enabled(ddr2_vctl_rst, sys_ddr_clk, DDR2_EMIF2_VCTL_RST);
+lpsc_clk_enabled(wdt_arm, sys_half_clk, WDT_ARM);
+
+lpsc_clk(mbx_lite, sys_arm1176_clk, MBX_LITE);
+lpsc_clk(ethss, eth_125mhz_clk, ETHSS);
+lpsc_clk(tsc, sys_tsc_clk, TSC);
+lpsc_clk(uart0, sys_half_clk, UART0);
+lpsc_clk(uart1, sys_half_clk, UART1);
+lpsc_clk(uart2, sys_half_clk, UART2);
+lpsc_clk(pktsec, sys_half_clk, PKTSEC);
+lpsc_clk(keypad, sys_half_clk, KEYPAD);
+lpsc_clk(mdio, sys_half_clk, MDIO);
+lpsc_clk(sdio0, sys_half_clk, SDIO0);
+lpsc_clk(sdio1, sys_half_clk, SDIO1);
+lpsc_clk(timer0, sys_half_clk, TIMER0);
+lpsc_clk(timer1, sys_half_clk, TIMER1);
+lpsc_clk(wdt_dsp, sys_half_clk, WDT_DSP);
+lpsc_clk(ssp, sys_half_clk, SSP);
+lpsc_clk(tdm0, tdm_0_clk, TDM0);
+lpsc_clk(tdm1, tdm_1_clk, TDM1);
+lpsc_clk(vlynq, sys_vlynq_ref_clk, VLYNQ);
+lpsc_clk(mcdma, sys_half_clk, MCDMA);
+lpsc_clk(usb0, sys_half_clk, USB0);
+lpsc_clk(usb1, sys_half_clk, USB1);
+lpsc_clk(usbss, sys_half_clk, USBSS);
+lpsc_clk(ethss_rgmii, eth_250mhz_clk, ETHSS_RGMII);
+lpsc_clk(imcop, sys_dsp_clk, IMCOP);
+lpsc_clk(spare, sys_half_clk, SPARE);
+
+/* LCD needs a full power down to clear controller state */
+__lpsc_clk(lcd, sys_lcd_clk, LCD, PSC_SWRSTDISABLE);
+
+
+/* Level 4 - leaf clocks for LPSC modules shared across drivers */
+static struct clk clk_rng = { .name = "rng", .parent = &clk_pktsec };
+static struct clk clk_pka = { .name = "pka", .parent = &clk_pktsec };
+
+static struct clk_lookup clks[] = {
+ CLK(NULL, "pll_sys_clk", &pll_sys_clk),
+ CLK(NULL, "pll_eth_clk", &pll_eth_clk),
+ CLK(NULL, "pll_tdm_clk", &pll_tdm_clk),
+ CLK(NULL, "sys_arm1176_clk", &sys_arm1176_clk),
+ CLK(NULL, "sys_dsp_clk", &sys_dsp_clk),
+ CLK(NULL, "sys_ddr_clk", &sys_ddr_clk),
+ CLK(NULL, "sys_full_clk", &sys_full_clk),
+ CLK(NULL, "sys_lcd_clk", &sys_lcd_clk),
+ CLK(NULL, "sys_vlynq_ref_clk", &sys_vlynq_ref_clk),
+ CLK(NULL, "sys_tsc_clk", &sys_tsc_clk),
+ CLK(NULL, "sys_half_clk", &sys_half_clk),
+ CLK(NULL, "eth_5mhz_clk", &eth_5mhz_clk),
+ CLK(NULL, "eth_50mhz_clk", &eth_50mhz_clk),
+ CLK(NULL, "eth_125mhz_clk", &eth_125mhz_clk),
+ CLK(NULL, "eth_250mhz_clk", &eth_250mhz_clk),
+ CLK(NULL, "eth_25mhz_clk", &eth_25mhz_clk),
+ CLK(NULL, "tdm_0_clk", &tdm_0_clk),
+ CLK(NULL, "tdm_extra_clk", &tdm_extra_clk),
+ CLK(NULL, "tdm_1_clk", &tdm_1_clk),
+ CLK(NULL, "clk_arm", &clk_arm),
+ CLK(NULL, "clk_gem", &clk_gem),
+ CLK(NULL, "clk_ddr2_phy", &clk_ddr2_phy),
+ CLK(NULL, "clk_tpcc", &clk_tpcc),
+ CLK(NULL, "clk_tptc0", &clk_tptc0),
+ CLK(NULL, "clk_tptc1", &clk_tptc1),
+ CLK(NULL, "clk_ram", &clk_ram),
+ CLK(NULL, "clk_mbx_lite", &clk_mbx_lite),
+ CLK("tnetv107x-fb.0", NULL, &clk_lcd),
+ CLK(NULL, "clk_ethss", &clk_ethss),
+ CLK(NULL, "aemif", &clk_aemif),
+ CLK(NULL, "clk_chipcfg", &clk_chipcfg),
+ CLK("tnetv107x-ts.0", NULL, &clk_tsc),
+ CLK(NULL, "clk_rom", &clk_rom),
+ CLK(NULL, "uart2", &clk_uart2),
+ CLK(NULL, "clk_pktsec", &clk_pktsec),
+ CLK("tnetv107x-rng.0", NULL, &clk_rng),
+ CLK("tnetv107x-pka.0", NULL, &clk_pka),
+ CLK(NULL, "clk_secctl", &clk_secctl),
+ CLK(NULL, "clk_keymgr", &clk_keymgr),
+ CLK("tnetv107x-keypad.0", NULL, &clk_keypad),
+ CLK(NULL, "clk_gpio", &clk_gpio),
+ CLK(NULL, "clk_mdio", &clk_mdio),
+ CLK("davinci_mmc.0", NULL, &clk_sdio0),
+ CLK(NULL, "uart0", &clk_uart0),
+ CLK(NULL, "uart1", &clk_uart1),
+ CLK(NULL, "timer0", &clk_timer0),
+ CLK(NULL, "timer1", &clk_timer1),
+ CLK("tnetv107x_wdt.0", NULL, &clk_wdt_arm),
+ CLK(NULL, "clk_wdt_dsp", &clk_wdt_dsp),
+ CLK("ti-ssp.0", NULL, &clk_ssp),
+ CLK(NULL, "clk_tdm0", &clk_tdm0),
+ CLK(NULL, "clk_vlynq", &clk_vlynq),
+ CLK(NULL, "clk_mcdma", &clk_mcdma),
+ CLK(NULL, "clk_usb0", &clk_usb0),
+ CLK(NULL, "clk_tdm1", &clk_tdm1),
+ CLK(NULL, "clk_debugss", &clk_debugss),
+ CLK(NULL, "clk_ethss_rgmii", &clk_ethss_rgmii),
+ CLK(NULL, "clk_system", &clk_system),
+ CLK(NULL, "clk_imcop", &clk_imcop),
+ CLK(NULL, "clk_spare", &clk_spare),
+ CLK("davinci_mmc.1", NULL, &clk_sdio1),
+ CLK(NULL, "clk_usb1", &clk_usb1),
+ CLK(NULL, "clk_usbss", &clk_usbss),
+ CLK(NULL, "clk_ddr2_vrst", &clk_ddr2_vrst),
+ CLK(NULL, "clk_ddr2_vctl_rst", &clk_ddr2_vctl_rst),
+ CLK(NULL, NULL, NULL),
+};
+
+static const struct mux_config pins[] = {
+#ifdef CONFIG_DAVINCI_MUX
+ MUX_CFG(TNETV107X, ASR_A00, 0, 0, 0x1f, 0x00, false)
+ MUX_CFG(TNETV107X, GPIO32, 0, 0, 0x1f, 0x04, false)
+ MUX_CFG(TNETV107X, ASR_A01, 0, 5, 0x1f, 0x00, false)
+ MUX_CFG(TNETV107X, GPIO33, 0, 5, 0x1f, 0x04, false)
+ MUX_CFG(TNETV107X, ASR_A02, 0, 10, 0x1f, 0x00, false)
+ MUX_CFG(TNETV107X, GPIO34, 0, 10, 0x1f, 0x04, false)
+ MUX_CFG(TNETV107X, ASR_A03, 0, 15, 0x1f, 0x00, false)
+ MUX_CFG(TNETV107X, GPIO35, 0, 15, 0x1f, 0x04, false)
+ MUX_CFG(TNETV107X, ASR_A04, 0, 20, 0x1f, 0x00, false)
+ MUX_CFG(TNETV107X, GPIO36, 0, 20, 0x1f, 0x04, false)
+ MUX_CFG(TNETV107X, ASR_A05, 0, 25, 0x1f, 0x00, false)
+ MUX_CFG(TNETV107X, GPIO37, 0, 25, 0x1f, 0x04, false)
+ MUX_CFG(TNETV107X, ASR_A06, 1, 0, 0x1f, 0x00, false)
+ MUX_CFG(TNETV107X, GPIO38, 1, 0, 0x1f, 0x04, false)
+ MUX_CFG(TNETV107X, ASR_A07, 1, 5, 0x1f, 0x00, false)
+ MUX_CFG(TNETV107X, GPIO39, 1, 5, 0x1f, 0x04, false)
+ MUX_CFG(TNETV107X, ASR_A08, 1, 10, 0x1f, 0x00, false)
+ MUX_CFG(TNETV107X, GPIO40, 1, 10, 0x1f, 0x04, false)
+ MUX_CFG(TNETV107X, ASR_A09, 1, 15, 0x1f, 0x00, false)
+ MUX_CFG(TNETV107X, GPIO41, 1, 15, 0x1f, 0x04, false)
+ MUX_CFG(TNETV107X, ASR_A10, 1, 20, 0x1f, 0x00, false)
+ MUX_CFG(TNETV107X, GPIO42, 1, 20, 0x1f, 0x04, false)
+ MUX_CFG(TNETV107X, ASR_A11, 1, 25, 0x1f, 0x00, false)
+ MUX_CFG(TNETV107X, BOOT_STRP_0, 1, 25, 0x1f, 0x04, false)
+ MUX_CFG(TNETV107X, ASR_A12, 2, 0, 0x1f, 0x00, false)
+ MUX_CFG(TNETV107X, BOOT_STRP_1, 2, 0, 0x1f, 0x04, false)
+ MUX_CFG(TNETV107X, ASR_A13, 2, 5, 0x1f, 0x00, false)
+ MUX_CFG(TNETV107X, GPIO43, 2, 5, 0x1f, 0x04, false)
+ MUX_CFG(TNETV107X, ASR_A14, 2, 10, 0x1f, 0x00, false)
+ MUX_CFG(TNETV107X, GPIO44, 2, 10, 0x1f, 0x04, false)
+ MUX_CFG(TNETV107X, ASR_A15, 2, 15, 0x1f, 0x00, false)
+ MUX_CFG(TNETV107X, GPIO45, 2, 15, 0x1f, 0x04, false)
+ MUX_CFG(TNETV107X, ASR_A16, 2, 20, 0x1f, 0x00, false)
+ MUX_CFG(TNETV107X, GPIO46, 2, 20, 0x1f, 0x04, false)
+ MUX_CFG(TNETV107X, ASR_A17, 2, 25, 0x1f, 0x00, false)
+ MUX_CFG(TNETV107X, GPIO47, 2, 25, 0x1f, 0x04, false)
+ MUX_CFG(TNETV107X, ASR_A18, 3, 0, 0x1f, 0x00, false)
+ MUX_CFG(TNETV107X, GPIO48, 3, 0, 0x1f, 0x04, false)
+ MUX_CFG(TNETV107X, SDIO1_DATA3_0, 3, 0, 0x1f, 0x1c, false)
+ MUX_CFG(TNETV107X, ASR_A19, 3, 5, 0x1f, 0x00, false)
+ MUX_CFG(TNETV107X, GPIO49, 3, 5, 0x1f, 0x04, false)
+ MUX_CFG(TNETV107X, SDIO1_DATA2_0, 3, 5, 0x1f, 0x1c, false)
+ MUX_CFG(TNETV107X, ASR_A20, 3, 10, 0x1f, 0x00, false)
+ MUX_CFG(TNETV107X, GPIO50, 3, 10, 0x1f, 0x04, false)
+ MUX_CFG(TNETV107X, SDIO1_DATA1_0, 3, 10, 0x1f, 0x1c, false)
+ MUX_CFG(TNETV107X, ASR_A21, 3, 15, 0x1f, 0x00, false)
+ MUX_CFG(TNETV107X, GPIO51, 3, 15, 0x1f, 0x04, false)
+ MUX_CFG(TNETV107X, SDIO1_DATA0_0, 3, 15, 0x1f, 0x1c, false)
+ MUX_CFG(TNETV107X, ASR_A22, 3, 20, 0x1f, 0x00, false)
+ MUX_CFG(TNETV107X, GPIO52, 3, 20, 0x1f, 0x04, false)
+ MUX_CFG(TNETV107X, SDIO1_CMD_0, 3, 20, 0x1f, 0x1c, false)
+ MUX_CFG(TNETV107X, ASR_A23, 3, 25, 0x1f, 0x00, false)
+ MUX_CFG(TNETV107X, GPIO53, 3, 25, 0x1f, 0x04, false)
+ MUX_CFG(TNETV107X, SDIO1_CLK_0, 3, 25, 0x1f, 0x1c, false)
+ MUX_CFG(TNETV107X, ASR_BA_1, 4, 0, 0x1f, 0x00, false)
+ MUX_CFG(TNETV107X, GPIO54, 4, 0, 0x1f, 0x04, false)
+ MUX_CFG(TNETV107X, SYS_PLL_CLK, 4, 0, 0x1f, 0x1c, false)
+ MUX_CFG(TNETV107X, ASR_CS0, 4, 5, 0x1f, 0x00, false)
+ MUX_CFG(TNETV107X, ASR_CS1, 4, 10, 0x1f, 0x00, false)
+ MUX_CFG(TNETV107X, ASR_CS2, 4, 15, 0x1f, 0x00, false)
+ MUX_CFG(TNETV107X, TDM_PLL_CLK, 4, 15, 0x1f, 0x1c, false)
+ MUX_CFG(TNETV107X, ASR_CS3, 4, 20, 0x1f, 0x00, false)
+ MUX_CFG(TNETV107X, ETH_PHY_CLK, 4, 20, 0x1f, 0x0c, false)
+ MUX_CFG(TNETV107X, ASR_D00, 4, 25, 0x1f, 0x00, false)
+ MUX_CFG(TNETV107X, GPIO55, 4, 25, 0x1f, 0x1c, false)
+ MUX_CFG(TNETV107X, ASR_D01, 5, 0, 0x1f, 0x00, false)
+ MUX_CFG(TNETV107X, GPIO56, 5, 0, 0x1f, 0x1c, false)
+ MUX_CFG(TNETV107X, ASR_D02, 5, 5, 0x1f, 0x00, false)
+ MUX_CFG(TNETV107X, GPIO57, 5, 5, 0x1f, 0x1c, false)
+ MUX_CFG(TNETV107X, ASR_D03, 5, 10, 0x1f, 0x00, false)
+ MUX_CFG(TNETV107X, GPIO58, 5, 10, 0x1f, 0x1c, false)
+ MUX_CFG(TNETV107X, ASR_D04, 5, 15, 0x1f, 0x00, false)
+ MUX_CFG(TNETV107X, GPIO59_0, 5, 15, 0x1f, 0x1c, false)
+ MUX_CFG(TNETV107X, ASR_D05, 5, 20, 0x1f, 0x00, false)
+ MUX_CFG(TNETV107X, GPIO60_0, 5, 20, 0x1f, 0x1c, false)
+ MUX_CFG(TNETV107X, ASR_D06, 5, 25, 0x1f, 0x00, false)
+ MUX_CFG(TNETV107X, GPIO61_0, 5, 25, 0x1f, 0x1c, false)
+ MUX_CFG(TNETV107X, ASR_D07, 6, 0, 0x1f, 0x00, false)
+ MUX_CFG(TNETV107X, GPIO62_0, 6, 0, 0x1f, 0x1c, false)
+ MUX_CFG(TNETV107X, ASR_D08, 6, 5, 0x1f, 0x00, false)
+ MUX_CFG(TNETV107X, GPIO63_0, 6, 5, 0x1f, 0x1c, false)
+ MUX_CFG(TNETV107X, ASR_D09, 6, 10, 0x1f, 0x00, false)
+ MUX_CFG(TNETV107X, GPIO64_0, 6, 10, 0x1f, 0x1c, false)
+ MUX_CFG(TNETV107X, ASR_D10, 6, 15, 0x1f, 0x00, false)
+ MUX_CFG(TNETV107X, SDIO1_DATA3_1, 6, 15, 0x1f, 0x1c, false)
+ MUX_CFG(TNETV107X, ASR_D11, 6, 20, 0x1f, 0x00, false)
+ MUX_CFG(TNETV107X, SDIO1_DATA2_1, 6, 20, 0x1f, 0x1c, false)
+ MUX_CFG(TNETV107X, ASR_D12, 6, 25, 0x1f, 0x00, false)
+ MUX_CFG(TNETV107X, SDIO1_DATA1_1, 6, 25, 0x1f, 0x1c, false)
+ MUX_CFG(TNETV107X, ASR_D13, 7, 0, 0x1f, 0x00, false)
+ MUX_CFG(TNETV107X, SDIO1_DATA0_1, 7, 0, 0x1f, 0x1c, false)
+ MUX_CFG(TNETV107X, ASR_D14, 7, 5, 0x1f, 0x00, false)
+ MUX_CFG(TNETV107X, SDIO1_CMD_1, 7, 5, 0x1f, 0x1c, false)
+ MUX_CFG(TNETV107X, ASR_D15, 7, 10, 0x1f, 0x00, false)
+ MUX_CFG(TNETV107X, SDIO1_CLK_1, 7, 10, 0x1f, 0x1c, false)
+ MUX_CFG(TNETV107X, ASR_OE, 7, 15, 0x1f, 0x00, false)
+ MUX_CFG(TNETV107X, BOOT_STRP_2, 7, 15, 0x1f, 0x04, false)
+ MUX_CFG(TNETV107X, ASR_RNW, 7, 20, 0x1f, 0x00, false)
+ MUX_CFG(TNETV107X, GPIO29_0, 7, 20, 0x1f, 0x04, false)
+ MUX_CFG(TNETV107X, ASR_WAIT, 7, 25, 0x1f, 0x00, false)
+ MUX_CFG(TNETV107X, GPIO30_0, 7, 25, 0x1f, 0x04, false)
+ MUX_CFG(TNETV107X, ASR_WE, 8, 0, 0x1f, 0x00, false)
+ MUX_CFG(TNETV107X, BOOT_STRP_3, 8, 0, 0x1f, 0x04, false)
+ MUX_CFG(TNETV107X, ASR_WE_DQM0, 8, 5, 0x1f, 0x00, false)
+ MUX_CFG(TNETV107X, GPIO31, 8, 5, 0x1f, 0x04, false)
+ MUX_CFG(TNETV107X, LCD_PD17_0, 8, 5, 0x1f, 0x1c, false)
+ MUX_CFG(TNETV107X, ASR_WE_DQM1, 8, 10, 0x1f, 0x00, false)
+ MUX_CFG(TNETV107X, ASR_BA0_0, 8, 10, 0x1f, 0x04, false)
+ MUX_CFG(TNETV107X, VLYNQ_CLK, 9, 0, 0x1f, 0x00, false)
+ MUX_CFG(TNETV107X, GPIO14, 9, 0, 0x1f, 0x04, false)
+ MUX_CFG(TNETV107X, LCD_PD19_0, 9, 0, 0x1f, 0x1c, false)
+ MUX_CFG(TNETV107X, VLYNQ_RXD0, 9, 5, 0x1f, 0x00, false)
+ MUX_CFG(TNETV107X, GPIO15, 9, 5, 0x1f, 0x04, false)
+ MUX_CFG(TNETV107X, LCD_PD20_0, 9, 5, 0x1f, 0x1c, false)
+ MUX_CFG(TNETV107X, VLYNQ_RXD1, 9, 10, 0x1f, 0x00, false)
+ MUX_CFG(TNETV107X, GPIO16, 9, 10, 0x1f, 0x04, false)
+ MUX_CFG(TNETV107X, LCD_PD21_0, 9, 10, 0x1f, 0x1c, false)
+ MUX_CFG(TNETV107X, VLYNQ_TXD0, 9, 15, 0x1f, 0x00, false)
+ MUX_CFG(TNETV107X, GPIO17, 9, 15, 0x1f, 0x04, false)
+ MUX_CFG(TNETV107X, LCD_PD22_0, 9, 15, 0x1f, 0x1c, false)
+ MUX_CFG(TNETV107X, VLYNQ_TXD1, 9, 20, 0x1f, 0x00, false)
+ MUX_CFG(TNETV107X, GPIO18, 9, 20, 0x1f, 0x04, false)
+ MUX_CFG(TNETV107X, LCD_PD23_0, 9, 20, 0x1f, 0x1c, false)
+ MUX_CFG(TNETV107X, SDIO0_CLK, 10, 0, 0x1f, 0x00, false)
+ MUX_CFG(TNETV107X, GPIO19, 10, 0, 0x1f, 0x04, false)
+ MUX_CFG(TNETV107X, SDIO0_CMD, 10, 5, 0x1f, 0x00, false)
+ MUX_CFG(TNETV107X, GPIO20, 10, 5, 0x1f, 0x04, false)
+ MUX_CFG(TNETV107X, SDIO0_DATA0, 10, 10, 0x1f, 0x00, false)
+ MUX_CFG(TNETV107X, GPIO21, 10, 10, 0x1f, 0x04, false)
+ MUX_CFG(TNETV107X, SDIO0_DATA1, 10, 15, 0x1f, 0x00, false)
+ MUX_CFG(TNETV107X, GPIO22, 10, 15, 0x1f, 0x04, false)
+ MUX_CFG(TNETV107X, SDIO0_DATA2, 10, 20, 0x1f, 0x00, false)
+ MUX_CFG(TNETV107X, GPIO23, 10, 20, 0x1f, 0x04, false)
+ MUX_CFG(TNETV107X, SDIO0_DATA3, 10, 25, 0x1f, 0x00, false)
+ MUX_CFG(TNETV107X, GPIO24, 10, 25, 0x1f, 0x04, false)
+ MUX_CFG(TNETV107X, EMU0, 11, 0, 0x1f, 0x00, false)
+ MUX_CFG(TNETV107X, EMU1, 11, 5, 0x1f, 0x00, false)
+ MUX_CFG(TNETV107X, RTCK, 12, 0, 0x1f, 0x00, false)
+ MUX_CFG(TNETV107X, TRST_N, 12, 5, 0x1f, 0x00, false)
+ MUX_CFG(TNETV107X, TCK, 12, 10, 0x1f, 0x00, false)
+ MUX_CFG(TNETV107X, TDI, 12, 15, 0x1f, 0x00, false)
+ MUX_CFG(TNETV107X, TDO, 12, 20, 0x1f, 0x00, false)
+ MUX_CFG(TNETV107X, TMS, 12, 25, 0x1f, 0x00, false)
+ MUX_CFG(TNETV107X, TDM1_CLK, 13, 0, 0x1f, 0x00, false)
+ MUX_CFG(TNETV107X, TDM1_RX, 13, 5, 0x1f, 0x00, false)
+ MUX_CFG(TNETV107X, TDM1_TX, 13, 10, 0x1f, 0x00, false)
+ MUX_CFG(TNETV107X, TDM1_FS, 13, 15, 0x1f, 0x00, false)
+ MUX_CFG(TNETV107X, KEYPAD_R0, 14, 0, 0x1f, 0x00, false)
+ MUX_CFG(TNETV107X, KEYPAD_R1, 14, 5, 0x1f, 0x00, false)
+ MUX_CFG(TNETV107X, KEYPAD_R2, 14, 10, 0x1f, 0x00, false)
+ MUX_CFG(TNETV107X, KEYPAD_R3, 14, 15, 0x1f, 0x00, false)
+ MUX_CFG(TNETV107X, KEYPAD_R4, 14, 20, 0x1f, 0x00, false)
+ MUX_CFG(TNETV107X, KEYPAD_R5, 14, 25, 0x1f, 0x00, false)
+ MUX_CFG(TNETV107X, KEYPAD_R6, 15, 0, 0x1f, 0x00, false)
+ MUX_CFG(TNETV107X, GPIO12, 15, 0, 0x1f, 0x04, false)
+ MUX_CFG(TNETV107X, KEYPAD_R7, 15, 5, 0x1f, 0x00, false)
+ MUX_CFG(TNETV107X, GPIO10, 15, 5, 0x1f, 0x04, false)
+ MUX_CFG(TNETV107X, KEYPAD_C0, 15, 10, 0x1f, 0x00, false)
+ MUX_CFG(TNETV107X, KEYPAD_C1, 15, 15, 0x1f, 0x00, false)
+ MUX_CFG(TNETV107X, KEYPAD_C2, 15, 20, 0x1f, 0x00, false)
+ MUX_CFG(TNETV107X, KEYPAD_C3, 15, 25, 0x1f, 0x00, false)
+ MUX_CFG(TNETV107X, KEYPAD_C4, 16, 0, 0x1f, 0x00, false)
+ MUX_CFG(TNETV107X, KEYPAD_C5, 16, 5, 0x1f, 0x00, false)
+ MUX_CFG(TNETV107X, KEYPAD_C6, 16, 10, 0x1f, 0x00, false)
+ MUX_CFG(TNETV107X, GPIO13, 16, 10, 0x1f, 0x04, false)
+ MUX_CFG(TNETV107X, TEST_CLK_IN, 16, 10, 0x1f, 0x0c, false)
+ MUX_CFG(TNETV107X, KEYPAD_C7, 16, 15, 0x1f, 0x00, false)
+ MUX_CFG(TNETV107X, GPIO11, 16, 15, 0x1f, 0x04, false)
+ MUX_CFG(TNETV107X, SSP0_0, 17, 0, 0x1f, 0x00, false)
+ MUX_CFG(TNETV107X, SCC_DCLK, 17, 0, 0x1f, 0x04, false)
+ MUX_CFG(TNETV107X, LCD_PD20_1, 17, 0, 0x1f, 0x0c, false)
+ MUX_CFG(TNETV107X, SSP0_1, 17, 5, 0x1f, 0x00, false)
+ MUX_CFG(TNETV107X, SCC_CS_N, 17, 5, 0x1f, 0x04, false)
+ MUX_CFG(TNETV107X, LCD_PD21_1, 17, 5, 0x1f, 0x0c, false)
+ MUX_CFG(TNETV107X, SSP0_2, 17, 10, 0x1f, 0x00, false)
+ MUX_CFG(TNETV107X, SCC_D, 17, 10, 0x1f, 0x04, false)
+ MUX_CFG(TNETV107X, LCD_PD22_1, 17, 10, 0x1f, 0x0c, false)
+ MUX_CFG(TNETV107X, SSP0_3, 17, 15, 0x1f, 0x00, false)
+ MUX_CFG(TNETV107X, SCC_RESETN, 17, 15, 0x1f, 0x04, false)
+ MUX_CFG(TNETV107X, LCD_PD23_1, 17, 15, 0x1f, 0x0c, false)
+ MUX_CFG(TNETV107X, SSP1_0, 18, 0, 0x1f, 0x00, false)
+ MUX_CFG(TNETV107X, GPIO25, 18, 0, 0x1f, 0x04, false)
+ MUX_CFG(TNETV107X, UART2_CTS, 18, 0, 0x1f, 0x0c, false)
+ MUX_CFG(TNETV107X, SSP1_1, 18, 5, 0x1f, 0x00, false)
+ MUX_CFG(TNETV107X, GPIO26, 18, 5, 0x1f, 0x04, false)
+ MUX_CFG(TNETV107X, UART2_RD, 18, 5, 0x1f, 0x0c, false)
+ MUX_CFG(TNETV107X, SSP1_2, 18, 10, 0x1f, 0x00, false)
+ MUX_CFG(TNETV107X, GPIO27, 18, 10, 0x1f, 0x04, false)
+ MUX_CFG(TNETV107X, UART2_RTS, 18, 10, 0x1f, 0x0c, false)
+ MUX_CFG(TNETV107X, SSP1_3, 18, 15, 0x1f, 0x00, false)
+ MUX_CFG(TNETV107X, GPIO28, 18, 15, 0x1f, 0x04, false)
+ MUX_CFG(TNETV107X, UART2_TD, 18, 15, 0x1f, 0x0c, false)
+ MUX_CFG(TNETV107X, UART0_CTS, 19, 0, 0x1f, 0x00, false)
+ MUX_CFG(TNETV107X, UART0_RD, 19, 5, 0x1f, 0x00, false)
+ MUX_CFG(TNETV107X, UART0_RTS, 19, 10, 0x1f, 0x00, false)
+ MUX_CFG(TNETV107X, UART0_TD, 19, 15, 0x1f, 0x00, false)
+ MUX_CFG(TNETV107X, UART1_RD, 19, 20, 0x1f, 0x00, false)
+ MUX_CFG(TNETV107X, UART1_TD, 19, 25, 0x1f, 0x00, false)
+ MUX_CFG(TNETV107X, LCD_AC_NCS, 20, 0, 0x1f, 0x00, false)
+ MUX_CFG(TNETV107X, LCD_HSYNC_RNW, 20, 5, 0x1f, 0x00, false)
+ MUX_CFG(TNETV107X, LCD_VSYNC_A0, 20, 10, 0x1f, 0x00, false)
+ MUX_CFG(TNETV107X, LCD_MCLK, 20, 15, 0x1f, 0x00, false)
+ MUX_CFG(TNETV107X, LCD_PD16_0, 20, 15, 0x1f, 0x0c, false)
+ MUX_CFG(TNETV107X, LCD_PCLK_E, 20, 20, 0x1f, 0x00, false)
+ MUX_CFG(TNETV107X, LCD_PD00, 20, 25, 0x1f, 0x00, false)
+ MUX_CFG(TNETV107X, LCD_PD01, 21, 0, 0x1f, 0x00, false)
+ MUX_CFG(TNETV107X, LCD_PD02, 21, 5, 0x1f, 0x00, false)
+ MUX_CFG(TNETV107X, LCD_PD03, 21, 10, 0x1f, 0x00, false)
+ MUX_CFG(TNETV107X, LCD_PD04, 21, 15, 0x1f, 0x00, false)
+ MUX_CFG(TNETV107X, LCD_PD05, 21, 20, 0x1f, 0x00, false)
+ MUX_CFG(TNETV107X, LCD_PD06, 21, 25, 0x1f, 0x00, false)
+ MUX_CFG(TNETV107X, LCD_PD07, 22, 0, 0x1f, 0x00, false)
+ MUX_CFG(TNETV107X, LCD_PD08, 22, 5, 0x1f, 0x00, false)
+ MUX_CFG(TNETV107X, GPIO59_1, 22, 5, 0x1f, 0x0c, false)
+ MUX_CFG(TNETV107X, LCD_PD09, 22, 10, 0x1f, 0x00, false)
+ MUX_CFG(TNETV107X, GPIO60_1, 22, 10, 0x1f, 0x0c, false)
+ MUX_CFG(TNETV107X, LCD_PD10, 22, 15, 0x1f, 0x00, false)
+ MUX_CFG(TNETV107X, ASR_BA0_1, 22, 15, 0x1f, 0x04, false)
+ MUX_CFG(TNETV107X, GPIO61_1, 22, 15, 0x1f, 0x0c, false)
+ MUX_CFG(TNETV107X, LCD_PD11, 22, 20, 0x1f, 0x00, false)
+ MUX_CFG(TNETV107X, GPIO62_1, 22, 20, 0x1f, 0x0c, false)
+ MUX_CFG(TNETV107X, LCD_PD12, 22, 25, 0x1f, 0x00, false)
+ MUX_CFG(TNETV107X, GPIO63_1, 22, 25, 0x1f, 0x0c, false)
+ MUX_CFG(TNETV107X, LCD_PD13, 23, 0, 0x1f, 0x00, false)
+ MUX_CFG(TNETV107X, GPIO64_1, 23, 0, 0x1f, 0x0c, false)
+ MUX_CFG(TNETV107X, LCD_PD14, 23, 5, 0x1f, 0x00, false)
+ MUX_CFG(TNETV107X, GPIO29_1, 23, 5, 0x1f, 0x0c, false)
+ MUX_CFG(TNETV107X, LCD_PD15, 23, 10, 0x1f, 0x00, false)
+ MUX_CFG(TNETV107X, GPIO30_1, 23, 10, 0x1f, 0x0c, false)
+ MUX_CFG(TNETV107X, EINT0, 24, 0, 0x1f, 0x00, false)
+ MUX_CFG(TNETV107X, GPIO08, 24, 0, 0x1f, 0x04, false)
+ MUX_CFG(TNETV107X, EINT1, 24, 5, 0x1f, 0x00, false)
+ MUX_CFG(TNETV107X, GPIO09, 24, 5, 0x1f, 0x04, false)
+ MUX_CFG(TNETV107X, GPIO00, 24, 10, 0x1f, 0x00, false)
+ MUX_CFG(TNETV107X, LCD_PD20_2, 24, 10, 0x1f, 0x04, false)
+ MUX_CFG(TNETV107X, TDM_CLK_IN_2, 24, 10, 0x1f, 0x0c, false)
+ MUX_CFG(TNETV107X, GPIO01, 24, 15, 0x1f, 0x00, false)
+ MUX_CFG(TNETV107X, LCD_PD21_2, 24, 15, 0x1f, 0x04, false)
+ MUX_CFG(TNETV107X, 24M_CLK_OUT_1, 24, 15, 0x1f, 0x0c, false)
+ MUX_CFG(TNETV107X, GPIO02, 24, 20, 0x1f, 0x00, false)
+ MUX_CFG(TNETV107X, LCD_PD22_2, 24, 20, 0x1f, 0x04, false)
+ MUX_CFG(TNETV107X, GPIO03, 24, 25, 0x1f, 0x00, false)
+ MUX_CFG(TNETV107X, LCD_PD23_2, 24, 25, 0x1f, 0x04, false)
+ MUX_CFG(TNETV107X, GPIO04, 25, 0, 0x1f, 0x00, false)
+ MUX_CFG(TNETV107X, LCD_PD16_1, 25, 0, 0x1f, 0x04, false)
+ MUX_CFG(TNETV107X, USB0_RXERR, 25, 0, 0x1f, 0x0c, false)
+ MUX_CFG(TNETV107X, GPIO05, 25, 5, 0x1f, 0x00, false)
+ MUX_CFG(TNETV107X, LCD_PD17_1, 25, 5, 0x1f, 0x04, false)
+ MUX_CFG(TNETV107X, TDM_CLK_IN_1, 25, 5, 0x1f, 0x0c, false)
+ MUX_CFG(TNETV107X, GPIO06, 25, 10, 0x1f, 0x00, false)
+ MUX_CFG(TNETV107X, LCD_PD18, 25, 10, 0x1f, 0x04, false)
+ MUX_CFG(TNETV107X, 24M_CLK_OUT_2, 25, 10, 0x1f, 0x0c, false)
+ MUX_CFG(TNETV107X, GPIO07, 25, 15, 0x1f, 0x00, false)
+ MUX_CFG(TNETV107X, LCD_PD19_1, 25, 15, 0x1f, 0x04, false)
+ MUX_CFG(TNETV107X, USB1_RXERR, 25, 15, 0x1f, 0x0c, false)
+ MUX_CFG(TNETV107X, ETH_PLL_CLK, 25, 15, 0x1f, 0x1c, false)
+ MUX_CFG(TNETV107X, MDIO, 26, 0, 0x1f, 0x00, false)
+ MUX_CFG(TNETV107X, MDC, 26, 5, 0x1f, 0x00, false)
+ MUX_CFG(TNETV107X, AIC_MUTE_STAT_N, 26, 10, 0x1f, 0x00, false)
+ MUX_CFG(TNETV107X, TDM0_CLK, 26, 10, 0x1f, 0x04, false)
+ MUX_CFG(TNETV107X, AIC_HNS_EN_N, 26, 15, 0x1f, 0x00, false)
+ MUX_CFG(TNETV107X, TDM0_FS, 26, 15, 0x1f, 0x04, false)
+ MUX_CFG(TNETV107X, AIC_HDS_EN_STAT_N, 26, 20, 0x1f, 0x00, false)
+ MUX_CFG(TNETV107X, TDM0_TX, 26, 20, 0x1f, 0x04, false)
+ MUX_CFG(TNETV107X, AIC_HNF_EN_STAT_N, 26, 25, 0x1f, 0x00, false)
+ MUX_CFG(TNETV107X, TDM0_RX, 26, 25, 0x1f, 0x04, false)
+#endif
+};
+
+/* FIQ are pri 0-1; otherwise 2-7, with 7 lowest priority */
+static u8 irq_prios[TNETV107X_N_CP_INTC_IRQ] = {
+ /* fill in default priority 7 */
+ [0 ... (TNETV107X_N_CP_INTC_IRQ - 1)] = 7,
+ /* now override as needed, e.g. [xxx] = 5 */
+};
+
+/* Contents of JTAG ID register used to identify exact cpu type */
+static struct davinci_id ids[] = {
+ {
+ .variant = 0x0,
+ .part_no = 0xb8a1,
+ .manufacturer = 0x017,
+ .cpu_id = DAVINCI_CPU_ID_TNETV107X,
+ .name = "tnetv107x rev1.0",
+ },
+};
+
+static struct davinci_timer_instance timer_instance[2] = {
+ {
+ .base = TNETV107X_TIMER0_BASE,
+ .bottom_irq = IRQ_TNETV107X_TIMER_0_TINT12,
+ .top_irq = IRQ_TNETV107X_TIMER_0_TINT34,
+ },
+ {
+ .base = TNETV107X_TIMER1_BASE,
+ .bottom_irq = IRQ_TNETV107X_TIMER_1_TINT12,
+ .top_irq = IRQ_TNETV107X_TIMER_1_TINT34,
+ },
+};
+
+static struct davinci_timer_info timer_info = {
+ .timers = timer_instance,
+ .clockevent_id = T0_BOT,
+ .clocksource_id = T0_TOP,
+};
+
+/*
+ * TNETV107X platforms do not use the static mappings from Davinci
+ * IO_PHYS/IO_VIRT. This SOC's interesting MMRs are at different addresses,
+ * and changing IO_PHYS would break away from existing Davinci SOCs.
+ *
+ * The primary impact of the current model is that IO_ADDRESS() is not to be
+ * used to map registers on TNETV107X.
+ *
+ * 1. The first chunk is for INTC: This needs to be mapped in via iotable
+ * because ioremap() does not seem to be operational at the time when
+ * irqs are initialized. Without this, consistent dma init bombs.
+ *
+ * 2. The second chunk maps in register areas that need to be populated into
+ * davinci_soc_info. Note that alignment restrictions come into play if
+ * low-level debug is enabled (see note in <mach/tnetv107x.h>).
+ */
+static struct map_desc io_desc[] = {
+ { /* INTC */
+ .virtual = IO_VIRT,
+ .pfn = __phys_to_pfn(TNETV107X_INTC_BASE),
+ .length = SZ_16K,
+ .type = MT_DEVICE
+ },
+ { /* Most of the rest */
+ .virtual = TNETV107X_IO_VIRT,
+ .pfn = __phys_to_pfn(TNETV107X_IO_BASE),
+ .length = IO_SIZE - SZ_1M,
+ .type = MT_DEVICE
+ },
+};
+
+static unsigned long clk_sspll_recalc(struct clk *clk)
+{
+ int pll;
+ unsigned long mult = 0, prediv = 1, postdiv = 1;
+ unsigned long ref = OSC_FREQ_ONCHIP, ret;
+ u32 tmp;
+
+ if (WARN_ON(!clk->pll_data))
+ return clk->rate;
+
+ if (!clk_ctrl_regs) {
+ void __iomem *tmp;
+
+ tmp = ioremap(TNETV107X_CLOCK_CONTROL_BASE, SZ_4K);
+
+ if (WARN(!tmp, "failed ioremap for clock control regs\n"))
+ return clk->parent ? clk->parent->rate : 0;
+
+ for (pll = 0; pll < N_PLLS; pll++)
+ sspll_regs[pll] = tmp + sspll_regs_base[pll];
+
+ clk_ctrl_regs = tmp;
+ }
+
+ pll = clk->pll_data->num;
+
+ tmp = __raw_readl(&clk_ctrl_regs->pll_bypass);
+ if (!(tmp & bypass_mask[pll])) {
+ mult = __raw_readl(&sspll_regs[pll]->mult_factor);
+ prediv = __raw_readl(&sspll_regs[pll]->pre_div) + 1;
+ postdiv = __raw_readl(&sspll_regs[pll]->post_div) + 1;
+ }
+
+ tmp = __raw_readl(clk->pll_data->base + PLLCTL);
+ if (tmp & PLLCTL_CLKMODE)
+ ref = pll_ext_freq[pll];
+
+ clk->pll_data->input_rate = ref;
+
+ tmp = __raw_readl(clk->pll_data->base + PLLCTL);
+ if (!(tmp & PLLCTL_PLLEN))
+ return ref;
+
+ ret = ref;
+ if (mult)
+ ret += ((unsigned long long)ref * mult) / 256;
+
+ ret /= (prediv * postdiv);
+
+ return ret;
+}
+
+static void tnetv107x_watchdog_reset(struct platform_device *pdev)
+{
+ struct wdt_regs __iomem *regs;
+
+ regs = ioremap(pdev->resource[0].start, SZ_4K);
+
+ /* disable watchdog */
+ __raw_writel(0x7777, &regs->disable_lock);
+ __raw_writel(0xcccc, &regs->disable_lock);
+ __raw_writel(0xdddd, &regs->disable_lock);
+ __raw_writel(0, &regs->disable);
+
+ /* program prescale */
+ __raw_writel(0x5a5a, &regs->prescale_lock);
+ __raw_writel(0xa5a5, &regs->prescale_lock);
+ __raw_writel(0, &regs->prescale);
+
+ /* program countdown */
+ __raw_writel(0x6666, &regs->change_lock);
+ __raw_writel(0xbbbb, &regs->change_lock);
+ __raw_writel(1, &regs->change);
+
+ /* enable watchdog */
+ __raw_writel(0x7777, &regs->disable_lock);
+ __raw_writel(0xcccc, &regs->disable_lock);
+ __raw_writel(0xdddd, &regs->disable_lock);
+ __raw_writel(1, &regs->disable);
+
+ /* kick */
+ __raw_writel(0x5555, &regs->kick_lock);
+ __raw_writel(0xaaaa, &regs->kick_lock);
+ __raw_writel(1, &regs->kick);
+}
+
+static struct davinci_soc_info tnetv107x_soc_info = {
+ .io_desc = io_desc,
+ .io_desc_num = ARRAY_SIZE(io_desc),
+ .ids = ids,
+ .ids_num = ARRAY_SIZE(ids),
+ .jtag_id_reg = TNETV107X_CHIP_CFG_BASE + 0x018,
+ .cpu_clks = clks,
+ .psc_bases = psc_regs,
+ .psc_bases_num = ARRAY_SIZE(psc_regs),
+ .pinmux_base = TNETV107X_CHIP_CFG_BASE + 0x150,
+ .pinmux_pins = pins,
+ .pinmux_pins_num = ARRAY_SIZE(pins),
+ .intc_type = DAVINCI_INTC_TYPE_CP_INTC,
+ .intc_base = TNETV107X_INTC_BASE,
+ .intc_irq_prios = irq_prios,
+ .intc_irq_num = TNETV107X_N_CP_INTC_IRQ,
+ .intc_host_map = intc_host_map,
+ .gpio_base = TNETV107X_GPIO_BASE,
+ .gpio_type = GPIO_TYPE_TNETV107X,
+ .gpio_num = TNETV107X_N_GPIO,
+ .timer_info = &timer_info,
+ .serial_dev = &tnetv107x_serial_device,
+ .reset = tnetv107x_watchdog_reset,
+ .reset_device = &tnetv107x_wdt_device,
+};
+
+void __init tnetv107x_init(void)
+{
+ davinci_common_init(&tnetv107x_soc_info);
+}
diff --git a/arch/arm/mach-ep93xx/clock.c b/arch/arm/mach-ep93xx/clock.c
index 7f3039761d9..8bf3cec98cf 100644
--- a/arch/arm/mach-ep93xx/clock.c
+++ b/arch/arm/mach-ep93xx/clock.c
@@ -43,7 +43,8 @@ static unsigned long get_uart_rate(struct clk *clk);
static int set_keytchclk_rate(struct clk *clk, unsigned long rate);
static int set_div_rate(struct clk *clk, unsigned long rate);
-
+static int set_i2s_sclk_rate(struct clk *clk, unsigned long rate);
+static int set_i2s_lrclk_rate(struct clk *clk, unsigned long rate);
static struct clk clk_xtali = {
.rate = EP93XX_EXT_CLK_RATE,
@@ -112,6 +113,29 @@ static struct clk clk_video = {
.set_rate = set_div_rate,
};
+static struct clk clk_i2s_mclk = {
+ .sw_locked = 1,
+ .enable_reg = EP93XX_SYSCON_I2SCLKDIV,
+ .enable_mask = EP93XX_SYSCON_CLKDIV_ENABLE,
+ .set_rate = set_div_rate,
+};
+
+static struct clk clk_i2s_sclk = {
+ .sw_locked = 1,
+ .parent = &clk_i2s_mclk,
+ .enable_reg = EP93XX_SYSCON_I2SCLKDIV,
+ .enable_mask = EP93XX_SYSCON_I2SCLKDIV_SENA,
+ .set_rate = set_i2s_sclk_rate,
+};
+
+static struct clk clk_i2s_lrclk = {
+ .sw_locked = 1,
+ .parent = &clk_i2s_sclk,
+ .enable_reg = EP93XX_SYSCON_I2SCLKDIV,
+ .enable_mask = EP93XX_SYSCON_I2SCLKDIV_SENA,
+ .set_rate = set_i2s_lrclk_rate,
+};
+
/* DMA Clocks */
static struct clk clk_m2p0 = {
.parent = &clk_h,
@@ -191,6 +215,9 @@ static struct clk_lookup clocks[] = {
INIT_CK("ep93xx-keypad", NULL, &clk_keypad),
INIT_CK("ep93xx-fb", NULL, &clk_video),
INIT_CK("ep93xx-spi.0", NULL, &clk_spi),
+ INIT_CK("ep93xx-i2s", "mclk", &clk_i2s_mclk),
+ INIT_CK("ep93xx-i2s", "sclk", &clk_i2s_sclk),
+ INIT_CK("ep93xx-i2s", "lrclk", &clk_i2s_lrclk),
INIT_CK(NULL, "pwm_clk", &clk_pwm),
INIT_CK(NULL, "m2p0", &clk_m2p0),
INIT_CK(NULL, "m2p1", &clk_m2p1),
@@ -401,6 +428,44 @@ static int set_div_rate(struct clk *clk, unsigned long rate)
return 0;
}
+static int set_i2s_sclk_rate(struct clk *clk, unsigned long rate)
+{
+ unsigned val = __raw_readl(clk->enable_reg);
+
+ if (rate == clk_i2s_mclk.rate / 2)
+ ep93xx_syscon_swlocked_write(val & ~EP93XX_I2SCLKDIV_SDIV,
+ clk->enable_reg);
+ else if (rate == clk_i2s_mclk.rate / 4)
+ ep93xx_syscon_swlocked_write(val | EP93XX_I2SCLKDIV_SDIV,
+ clk->enable_reg);
+ else
+ return -EINVAL;
+
+ clk_i2s_sclk.rate = rate;
+ return 0;
+}
+
+static int set_i2s_lrclk_rate(struct clk *clk, unsigned long rate)
+{
+ unsigned val = __raw_readl(clk->enable_reg) &
+ ~EP93XX_I2SCLKDIV_LRDIV_MASK;
+
+ if (rate == clk_i2s_sclk.rate / 32)
+ ep93xx_syscon_swlocked_write(val | EP93XX_I2SCLKDIV_LRDIV32,
+ clk->enable_reg);
+ else if (rate == clk_i2s_sclk.rate / 64)
+ ep93xx_syscon_swlocked_write(val | EP93XX_I2SCLKDIV_LRDIV64,
+ clk->enable_reg);
+ else if (rate == clk_i2s_sclk.rate / 128)
+ ep93xx_syscon_swlocked_write(val | EP93XX_I2SCLKDIV_LRDIV128,
+ clk->enable_reg);
+ else
+ return -EINVAL;
+
+ clk_i2s_lrclk.rate = rate;
+ return 0;
+}
+
int clk_set_rate(struct clk *clk, unsigned long rate)
{
if (clk->set_rate)
diff --git a/arch/arm/mach-ep93xx/core.c b/arch/arm/mach-ep93xx/core.c
index 8e37a045188..4cb55d3902f 100644
--- a/arch/arm/mach-ep93xx/core.c
+++ b/arch/arm/mach-ep93xx/core.c
@@ -758,6 +758,73 @@ void ep93xx_keypad_release_gpio(struct platform_device *pdev)
}
EXPORT_SYMBOL(ep93xx_keypad_release_gpio);
+/*************************************************************************
+ * EP93xx I2S audio peripheral handling
+ *************************************************************************/
+static struct resource ep93xx_i2s_resource[] = {
+ {
+ .start = EP93XX_I2S_PHYS_BASE,
+ .end = EP93XX_I2S_PHYS_BASE + 0x100 - 1,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+static struct platform_device ep93xx_i2s_device = {
+ .name = "ep93xx-i2s",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(ep93xx_i2s_resource),
+ .resource = ep93xx_i2s_resource,
+};
+
+void __init ep93xx_register_i2s(void)
+{
+ platform_device_register(&ep93xx_i2s_device);
+}
+
+#define EP93XX_SYSCON_DEVCFG_I2S_MASK (EP93XX_SYSCON_DEVCFG_I2SONSSP | \
+ EP93XX_SYSCON_DEVCFG_I2SONAC97)
+
+#define EP93XX_I2SCLKDIV_MASK (EP93XX_SYSCON_I2SCLKDIV_ORIDE | \
+ EP93XX_SYSCON_I2SCLKDIV_SPOL)
+
+int ep93xx_i2s_acquire(unsigned i2s_pins, unsigned i2s_config)
+{
+ unsigned val;
+
+ /* Sanity check */
+ if (i2s_pins & ~EP93XX_SYSCON_DEVCFG_I2S_MASK)
+ return -EINVAL;
+ if (i2s_config & ~EP93XX_I2SCLKDIV_MASK)
+ return -EINVAL;
+
+ /* Must have only one of I2SONSSP/I2SONAC97 set */
+ if ((i2s_pins & EP93XX_SYSCON_DEVCFG_I2SONSSP) ==
+ (i2s_pins & EP93XX_SYSCON_DEVCFG_I2SONAC97))
+ return -EINVAL;
+
+ ep93xx_devcfg_clear_bits(EP93XX_SYSCON_DEVCFG_I2S_MASK);
+ ep93xx_devcfg_set_bits(i2s_pins);
+
+ /*
+ * This is potentially racy with the clock api for i2s_mclk, sclk and
+ * lrclk. Since the i2s driver is the only user of those clocks we
+ * rely on it to prevent parallel use of this function and the
+ * clock api for the i2s clocks.
+ */
+ val = __raw_readl(EP93XX_SYSCON_I2SCLKDIV);
+ val &= ~EP93XX_I2SCLKDIV_MASK;
+ val |= i2s_config;
+ ep93xx_syscon_swlocked_write(val, EP93XX_SYSCON_I2SCLKDIV);
+
+ return 0;
+}
+EXPORT_SYMBOL(ep93xx_i2s_acquire);
+
+void ep93xx_i2s_release(void)
+{
+ ep93xx_devcfg_clear_bits(EP93XX_SYSCON_DEVCFG_I2S_MASK);
+}
+EXPORT_SYMBOL(ep93xx_i2s_release);
extern void ep93xx_gpio_init(void);
diff --git a/arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h b/arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h
index b1e096f0c2d..c54b3e56ba6 100644
--- a/arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h
+++ b/arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h
@@ -93,6 +93,7 @@
/* APB peripherals */
#define EP93XX_TIMER_BASE EP93XX_APB_IOMEM(0x00010000)
+#define EP93XX_I2S_PHYS_BASE EP93XX_APB_PHYS(0x00020000)
#define EP93XX_I2S_BASE EP93XX_APB_IOMEM(0x00020000)
#define EP93XX_SECURITY_BASE EP93XX_APB_IOMEM(0x00030000)
@@ -194,6 +195,15 @@
#define EP93XX_SYSCON_CLKDIV_ESEL (1<<14)
#define EP93XX_SYSCON_CLKDIV_PSEL (1<<13)
#define EP93XX_SYSCON_CLKDIV_PDIV_SHIFT 8
+#define EP93XX_SYSCON_I2SCLKDIV EP93XX_SYSCON_REG(0x8c)
+#define EP93XX_SYSCON_I2SCLKDIV_SENA (1<<31)
+#define EP93XX_SYSCON_I2SCLKDIV_ORIDE (1<<29)
+#define EP93XX_SYSCON_I2SCLKDIV_SPOL (1<<19)
+#define EP93XX_I2SCLKDIV_SDIV (1 << 16)
+#define EP93XX_I2SCLKDIV_LRDIV32 (0 << 17)
+#define EP93XX_I2SCLKDIV_LRDIV64 (1 << 17)
+#define EP93XX_I2SCLKDIV_LRDIV128 (2 << 17)
+#define EP93XX_I2SCLKDIV_LRDIV_MASK (3 << 17)
#define EP93XX_SYSCON_KEYTCHCLKDIV EP93XX_SYSCON_REG(0x90)
#define EP93XX_SYSCON_KEYTCHCLKDIV_TSEN (1<<31)
#define EP93XX_SYSCON_KEYTCHCLKDIV_ADIV (1<<16)
diff --git a/arch/arm/mach-ep93xx/include/mach/platform.h b/arch/arm/mach-ep93xx/include/mach/platform.h
index a6c09176334..3330b36d79e 100644
--- a/arch/arm/mach-ep93xx/include/mach/platform.h
+++ b/arch/arm/mach-ep93xx/include/mach/platform.h
@@ -58,6 +58,9 @@ void ep93xx_pwm_release_gpio(struct platform_device *pdev);
void ep93xx_register_keypad(struct ep93xx_keypad_platform_data *data);
int ep93xx_keypad_acquire_gpio(struct platform_device *pdev);
void ep93xx_keypad_release_gpio(struct platform_device *pdev);
+void ep93xx_register_i2s(void);
+int ep93xx_i2s_acquire(unsigned i2s_pins, unsigned i2s_config);
+void ep93xx_i2s_release(void);
void ep93xx_init_devices(void);
extern struct sys_timer ep93xx_timer;
diff --git a/arch/arm/mach-ep93xx/snappercl15.c b/arch/arm/mach-ep93xx/snappercl15.c
index 38deaee4039..a12c8930129 100644
--- a/arch/arm/mach-ep93xx/snappercl15.c
+++ b/arch/arm/mach-ep93xx/snappercl15.c
@@ -157,6 +157,7 @@ static void __init snappercl15_init_machine(void)
ep93xx_register_i2c(&snappercl15_i2c_gpio_data, snappercl15_i2c_data,
ARRAY_SIZE(snappercl15_i2c_data));
ep93xx_register_fb(&snappercl15_fb_info);
+ ep93xx_register_i2s();
platform_device_register(&snappercl15_nand_device);
}
diff --git a/arch/arm/mach-imx/dma-v1.c b/arch/arm/mach-imx/dma-v1.c
index fd1d9197d06..3e8c47c63ba 100644
--- a/arch/arm/mach-imx/dma-v1.c
+++ b/arch/arm/mach-imx/dma-v1.c
@@ -310,7 +310,7 @@ imx_dma_setup_sg(int channel,
imxdma->resbytes = dma_length;
if (!sg || !sgcount) {
- printk(KERN_ERR "imxdma%d: imx_dma_setup_sg epty sg list\n",
+ printk(KERN_ERR "imxdma%d: imx_dma_setup_sg empty sg list\n",
channel);
return -EINVAL;
}
@@ -760,7 +760,6 @@ EXPORT_SYMBOL(imx_dma_free);
* @name: the driver/caller own non-%NULL identification
*
* This function tries to find a free channel in the specified priority group
- * This function tries to find a free channel in the specified priority group
* if the priority cannot be achieved it tries to look for free channel
* in the higher and then even lower priority groups.
*
diff --git a/arch/arm/mach-kirkwood/common.c b/arch/arm/mach-kirkwood/common.c
index 9dd67c7b445..1c82d4290da 100644
--- a/arch/arm/mach-kirkwood/common.c
+++ b/arch/arm/mach-kirkwood/common.c
@@ -25,6 +25,7 @@
#include <asm/mach/time.h>
#include <mach/kirkwood.h>
#include <mach/bridge-regs.h>
+#include <plat/audio.h>
#include <plat/cache-feroceon-l2.h>
#include <plat/ehci-orion.h>
#include <plat/mvsdio.h>
@@ -871,6 +872,42 @@ struct sys_timer kirkwood_timer = {
.init = kirkwood_timer_init,
};
+/*****************************************************************************
+ * Audio
+ ****************************************************************************/
+static struct resource kirkwood_i2s_resources[] = {
+ [0] = {
+ .start = AUDIO_PHYS_BASE,
+ .end = AUDIO_PHYS_BASE + SZ_16K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = IRQ_KIRKWOOD_I2S,
+ .end = IRQ_KIRKWOOD_I2S,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct kirkwood_asoc_platform_data kirkwood_i2s_data = {
+ .dram = &kirkwood_mbus_dram_info,
+ .burst = 128,
+};
+
+static struct platform_device kirkwood_i2s_device = {
+ .name = "kirkwood-i2s",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(kirkwood_i2s_resources),
+ .resource = kirkwood_i2s_resources,
+ .dev = {
+ .platform_data = &kirkwood_i2s_data,
+ },
+};
+
+void __init kirkwood_audio_init(void)
+{
+ kirkwood_clk_ctrl |= CGC_AUDIO;
+ platform_device_register(&kirkwood_i2s_device);
+}
/*****************************************************************************
* General
@@ -939,6 +976,7 @@ void __init kirkwood_init(void)
kirkwood_spi_plat_data.tclk = kirkwood_tclk;
kirkwood_uart0_data[0].uartclk = kirkwood_tclk;
kirkwood_uart1_data[0].uartclk = kirkwood_tclk;
+ kirkwood_i2s_data.tclk = kirkwood_tclk;
/*
* Disable propagation of mbus errors to the CPU local bus,
diff --git a/arch/arm/mach-kirkwood/common.h b/arch/arm/mach-kirkwood/common.h
index 5b2c1c18d64..95bb0a73adf 100644
--- a/arch/arm/mach-kirkwood/common.h
+++ b/arch/arm/mach-kirkwood/common.h
@@ -17,6 +17,7 @@ struct mv_sata_platform_data;
struct mvsdio_platform_data;
struct mtd_partition;
struct mtd_info;
+struct kirkwood_asoc_platform_data;
#define KW_PCIE0 (1 << 0)
#define KW_PCIE1 (1 << 1)
@@ -46,6 +47,7 @@ void kirkwood_uart0_init(void);
void kirkwood_uart1_init(void);
void kirkwood_nand_init(struct mtd_partition *parts, int nr_parts, int delay);
void kirkwood_nand_init_rnb(struct mtd_partition *parts, int nr_parts, int (*dev_ready)(struct mtd_info *));
+void kirkwood_audio_init(void);
extern int kirkwood_tclk;
extern struct sys_timer kirkwood_timer;
diff --git a/arch/arm/mach-kirkwood/include/mach/kirkwood.h b/arch/arm/mach-kirkwood/include/mach/kirkwood.h
index d141af4c274..93fc2ec95e7 100644
--- a/arch/arm/mach-kirkwood/include/mach/kirkwood.h
+++ b/arch/arm/mach-kirkwood/include/mach/kirkwood.h
@@ -111,6 +111,9 @@
#define SDIO_PHYS_BASE (KIRKWOOD_REGS_PHYS_BASE | 0x90000)
+#define AUDIO_PHYS_BASE (KIRKWOOD_REGS_PHYS_BASE | 0xA0000)
+#define AUDIO_VIRT_BASE (KIRKWOOD_REGS_VIRT_BASE | 0xA0000)
+
/*
* Supported devices and revisions.
*/
diff --git a/arch/arm/mach-kirkwood/openrd-setup.c b/arch/arm/mach-kirkwood/openrd-setup.c
index fd64cd2b4e0..fd06be61881 100644
--- a/arch/arm/mach-kirkwood/openrd-setup.c
+++ b/arch/arm/mach-kirkwood/openrd-setup.c
@@ -15,6 +15,7 @@
#include <linux/mtd/partitions.h>
#include <linux/ata_platform.h>
#include <linux/mv643xx_eth.h>
+#include <linux/i2c.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
#include <mach/kirkwood.h>
@@ -60,6 +61,12 @@ static unsigned int openrd_mpp_config[] __initdata = {
0
};
+static struct i2c_board_info i2c_board_info[] __initdata = {
+ {
+ I2C_BOARD_INFO("cs42l51", 0x4a),
+ },
+};
+
static void __init openrd_init(void)
{
/*
@@ -86,6 +93,12 @@ static void __init openrd_init(void)
kirkwood_sdio_init(&openrd_mvsdio_data);
kirkwood_i2c_init();
+
+ if (machine_is_openrd_client()) {
+ i2c_register_board_info(0, i2c_board_info,
+ ARRAY_SIZE(i2c_board_info));
+ kirkwood_audio_init();
+ }
}
static int __init openrd_pci_init(void)
diff --git a/arch/arm/mach-msm/acpuclock-arm11.c b/arch/arm/mach-msm/acpuclock-arm11.c
index af5e85b91d0..f060a3959a7 100644
--- a/arch/arm/mach-msm/acpuclock-arm11.c
+++ b/arch/arm/mach-msm/acpuclock-arm11.c
@@ -98,7 +98,7 @@ struct clkctl_acpu_speed {
/*
* ACPU speed table. Complete table is shown but certain speeds are commented
- * out to optimized speed switching. Initalize loops_per_jiffy to 0.
+ * out to optimized speed switching. Initialize loops_per_jiffy to 0.
*
* Table stepping up/down is optimized for 256mhz jumps while staying on the
* same PLL.
@@ -494,7 +494,7 @@ uint32_t acpuclk_get_switch_time(void)
* Clock driver initialization
*---------------------------------------------------------------------------*/
-/* Initalize the lpj field in the acpu_freq_tbl. */
+/* Initialize the lpj field in the acpu_freq_tbl. */
static void __init lpj_init(void)
{
int i;
diff --git a/arch/arm/mach-omap2/dpll3xxx.c b/arch/arm/mach-omap2/dpll3xxx.c
index b32ccd954a1..ed8d330522f 100644
--- a/arch/arm/mach-omap2/dpll3xxx.c
+++ b/arch/arm/mach-omap2/dpll3xxx.c
@@ -463,7 +463,7 @@ int omap3_noncore_dpll_set_rate(struct clk *clk, unsigned long rate)
}
if (!ret) {
/*
- * Switch the parent clock in the heirarchy, and make sure
+ * Switch the parent clock in the hierarchy, and make sure
* that the new parent's usecount is correct. Note: we
* enable the new parent before disabling the old to avoid
* any unnecessary hardware disable->enable transitions.
diff --git a/arch/arm/mach-omap2/mcbsp.c b/arch/arm/mach-omap2/mcbsp.c
index 87aa4c9597c..467aae24578 100644
--- a/arch/arm/mach-omap2/mcbsp.c
+++ b/arch/arm/mach-omap2/mcbsp.c
@@ -134,7 +134,7 @@ static struct omap_mcbsp_platform_data omap34xx_mcbsp_pdata[] = {
.rx_irq = INT_24XX_MCBSP1_IRQ_RX,
.tx_irq = INT_24XX_MCBSP1_IRQ_TX,
.ops = &omap2_mcbsp_ops,
- .buffer_size = 0x6F,
+ .buffer_size = 0x80, /* The FIFO has 128 locations */
},
{
.phys_base = OMAP34XX_MCBSP2_BASE,
@@ -144,7 +144,7 @@ static struct omap_mcbsp_platform_data omap34xx_mcbsp_pdata[] = {
.rx_irq = INT_24XX_MCBSP2_IRQ_RX,
.tx_irq = INT_24XX_MCBSP2_IRQ_TX,
.ops = &omap2_mcbsp_ops,
- .buffer_size = 0x3FF,
+ .buffer_size = 0x500, /* The FIFO has 1024 + 256 locations */
},
{
.phys_base = OMAP34XX_MCBSP3_BASE,
@@ -154,7 +154,7 @@ static struct omap_mcbsp_platform_data omap34xx_mcbsp_pdata[] = {
.rx_irq = INT_24XX_MCBSP3_IRQ_RX,
.tx_irq = INT_24XX_MCBSP3_IRQ_TX,
.ops = &omap2_mcbsp_ops,
- .buffer_size = 0x6F,
+ .buffer_size = 0x80, /* The FIFO has 128 locations */
},
{
.phys_base = OMAP34XX_MCBSP4_BASE,
@@ -163,7 +163,7 @@ static struct omap_mcbsp_platform_data omap34xx_mcbsp_pdata[] = {
.rx_irq = INT_24XX_MCBSP4_IRQ_RX,
.tx_irq = INT_24XX_MCBSP4_IRQ_TX,
.ops = &omap2_mcbsp_ops,
- .buffer_size = 0x6F,
+ .buffer_size = 0x80, /* The FIFO has 128 locations */
},
{
.phys_base = OMAP34XX_MCBSP5_BASE,
@@ -172,7 +172,7 @@ static struct omap_mcbsp_platform_data omap34xx_mcbsp_pdata[] = {
.rx_irq = INT_24XX_MCBSP5_IRQ_RX,
.tx_irq = INT_24XX_MCBSP5_IRQ_TX,
.ops = &omap2_mcbsp_ops,
- .buffer_size = 0x6F,
+ .buffer_size = 0x80, /* The FIFO has 128 locations */
},
};
#define OMAP34XX_MCBSP_PDATA_SZ ARRAY_SIZE(omap34xx_mcbsp_pdata)
diff --git a/arch/arm/mach-omap2/sleep34xx.S b/arch/arm/mach-omap2/sleep34xx.S
index d522cd70bf5..ba53191ae4c 100644
--- a/arch/arm/mach-omap2/sleep34xx.S
+++ b/arch/arm/mach-omap2/sleep34xx.S
@@ -60,7 +60,7 @@
#define SDRC_DLLA_CTRL_V OMAP34XX_SDRC_REGADDR(SDRC_DLLA_CTRL)
.text
-/* Function to aquire the semaphore in scratchpad */
+/* Function to acquire the semaphore in scratchpad */
ENTRY(lock_scratchpad_sem)
stmfd sp!, {lr} @ save registers on stack
wait_sem:
diff --git a/arch/arm/mach-sa1100/collie.c b/arch/arm/mach-sa1100/collie.c
index 5d5f330c5d9..16e682d5dbb 100644
--- a/arch/arm/mach-sa1100/collie.c
+++ b/arch/arm/mach-sa1100/collie.c
@@ -11,7 +11,7 @@
* published by the Free Software Foundation.
*
* ChangeLog:
- * 2006 Pavel Machek <pavel@suse.cz>
+ * 2006 Pavel Machek <pavel@ucw.cz>
* 03-06-2004 John Lenz <lenz@cs.wisc.edu>
* 06-04-2002 Chris Larson <kergoth@digitalnemesis.net>
* 04-16-2001 Lineo Japan,Inc. ...
diff --git a/arch/arm/mach-u300/core.c b/arch/arm/mach-u300/core.c
index 5f34eb674d6..653b3e0ab7b 100644
--- a/arch/arm/mach-u300/core.c
+++ b/arch/arm/mach-u300/core.c
@@ -1561,13 +1561,6 @@ static void __init u300_init_check_chip(void)
printk(KERN_INFO "Initializing U300 system on %s baseband chip " \
"(chip ID 0x%04x)\n", chipname, val);
-#ifdef CONFIG_MACH_U300_BS26
- if ((val & 0xFF00U) != 0xc800) {
- printk(KERN_ERR "Platform configured for BS25/BS26 " \
- "with DB3150 but %s detected, expect problems!",
- chipname);
- }
-#endif
#ifdef CONFIG_MACH_U300_BS330
if ((val & 0xFF00U) != 0xd800) {
printk(KERN_ERR "Platform configured for BS330 " \
diff --git a/arch/arm/mach-u300/gpio.c b/arch/arm/mach-u300/gpio.c
index 5f61fd45a0c..d92790140fe 100644
--- a/arch/arm/mach-u300/gpio.c
+++ b/arch/arm/mach-u300/gpio.c
@@ -523,7 +523,7 @@ static void gpio_set_initial_values(void)
/*
* Put all pins that are set to either 'GPIO_OUT' or 'GPIO_NOT_USED'
- * to output and 'GPIO_IN' to input for each port. And initalize
+ * to output and 'GPIO_IN' to input for each port. And initialize
* default value on outputs.
*/
for (i = 0; i < U300_GPIO_NUM_PORTS; i++) {
diff --git a/arch/arm/plat-mxc/include/mach/ssi.h b/arch/arm/plat-mxc/include/mach/ssi.h
index c34ded523f1..63f3c280423 100644
--- a/arch/arm/plat-mxc/include/mach/ssi.h
+++ b/arch/arm/plat-mxc/include/mach/ssi.h
@@ -10,6 +10,9 @@ struct imx_ssi_platform_data {
unsigned int flags;
#define IMX_SSI_DMA (1 << 0)
#define IMX_SSI_USE_AC97 (1 << 1)
+#define IMX_SSI_NET (1 << 2)
+#define IMX_SSI_SYN (1 << 3)
+#define IMX_SSI_USE_I2S_SLAVE (1 << 4)
void (*ac97_reset) (struct snd_ac97 *ac97);
void (*ac97_warm_reset)(struct snd_ac97 *ac97);
};
diff --git a/arch/arm/plat-omap/include/plat/mcbsp.h b/arch/arm/plat-omap/include/plat/mcbsp.h
index 975744f10a5..b4ff6a11a8f 100644
--- a/arch/arm/plat-omap/include/plat/mcbsp.h
+++ b/arch/arm/plat-omap/include/plat/mcbsp.h
@@ -473,6 +473,7 @@ void omap_mcbsp_set_tx_threshold(unsigned int id, u16 threshold);
void omap_mcbsp_set_rx_threshold(unsigned int id, u16 threshold);
u16 omap_mcbsp_get_max_tx_threshold(unsigned int id);
u16 omap_mcbsp_get_max_rx_threshold(unsigned int id);
+u16 omap_mcbsp_get_fifo_size(unsigned int id);
u16 omap_mcbsp_get_tx_delay(unsigned int id);
u16 omap_mcbsp_get_rx_delay(unsigned int id);
int omap_mcbsp_get_dma_op_mode(unsigned int id);
@@ -483,6 +484,7 @@ static inline void omap_mcbsp_set_rx_threshold(unsigned int id, u16 threshold)
{ }
static inline u16 omap_mcbsp_get_max_tx_threshold(unsigned int id) { return 0; }
static inline u16 omap_mcbsp_get_max_rx_threshold(unsigned int id) { return 0; }
+static inline u16 omap_mcbsp_get_fifo_size(unsigned int id) { return 0; }
static inline u16 omap_mcbsp_get_tx_delay(unsigned int id) { return 0; }
static inline u16 omap_mcbsp_get_rx_delay(unsigned int id) { return 0; }
static inline int omap_mcbsp_get_dma_op_mode(unsigned int id) { return 0; }
diff --git a/arch/arm/plat-omap/mcbsp.c b/arch/arm/plat-omap/mcbsp.c
index 7e669c9744d..e31496e35b0 100644
--- a/arch/arm/plat-omap/mcbsp.c
+++ b/arch/arm/plat-omap/mcbsp.c
@@ -481,9 +481,9 @@ int omap_st_is_enabled(unsigned int id)
EXPORT_SYMBOL(omap_st_is_enabled);
/*
- * omap_mcbsp_set_tx_threshold configures how to deal
- * with transmit threshold. the threshold value and handler can be
- * configure in here.
+ * omap_mcbsp_set_rx_threshold configures the transmit threshold in words.
+ * The threshold parameter is 1 based, and it is converted (threshold - 1)
+ * for the THRSH2 register.
*/
void omap_mcbsp_set_tx_threshold(unsigned int id, u16 threshold)
{
@@ -498,14 +498,15 @@ void omap_mcbsp_set_tx_threshold(unsigned int id, u16 threshold)
}
mcbsp = id_to_mcbsp_ptr(id);
- MCBSP_WRITE(mcbsp, THRSH2, threshold);
+ if (threshold && threshold <= mcbsp->max_tx_thres)
+ MCBSP_WRITE(mcbsp, THRSH2, threshold - 1);
}
EXPORT_SYMBOL(omap_mcbsp_set_tx_threshold);
/*
- * omap_mcbsp_set_rx_threshold configures how to deal
- * with receive threshold. the threshold value and handler can be
- * configure in here.
+ * omap_mcbsp_set_rx_threshold configures the receive threshold in words.
+ * The threshold parameter is 1 based, and it is converted (threshold - 1)
+ * for the THRSH1 register.
*/
void omap_mcbsp_set_rx_threshold(unsigned int id, u16 threshold)
{
@@ -520,7 +521,8 @@ void omap_mcbsp_set_rx_threshold(unsigned int id, u16 threshold)
}
mcbsp = id_to_mcbsp_ptr(id);
- MCBSP_WRITE(mcbsp, THRSH1, threshold);
+ if (threshold && threshold <= mcbsp->max_rx_thres)
+ MCBSP_WRITE(mcbsp, THRSH1, threshold - 1);
}
EXPORT_SYMBOL(omap_mcbsp_set_rx_threshold);
@@ -560,8 +562,20 @@ u16 omap_mcbsp_get_max_rx_threshold(unsigned int id)
}
EXPORT_SYMBOL(omap_mcbsp_get_max_rx_threshold);
-#define MCBSP2_FIFO_SIZE 0x500 /* 1024 + 256 locations */
-#define MCBSP1345_FIFO_SIZE 0x80 /* 128 locations */
+u16 omap_mcbsp_get_fifo_size(unsigned int id)
+{
+ struct omap_mcbsp *mcbsp;
+
+ if (!omap_mcbsp_check_valid_id(id)) {
+ printk(KERN_ERR "%s: Invalid id (%d)\n", __func__, id + 1);
+ return -ENODEV;
+ }
+ mcbsp = id_to_mcbsp_ptr(id);
+
+ return mcbsp->pdata->buffer_size;
+}
+EXPORT_SYMBOL(omap_mcbsp_get_fifo_size);
+
/*
* omap_mcbsp_get_tx_delay returns the number of used slots in the McBSP FIFO
*/
@@ -580,10 +594,7 @@ u16 omap_mcbsp_get_tx_delay(unsigned int id)
buffstat = MCBSP_READ(mcbsp, XBUFFSTAT);
/* Number of slots are different in McBSP ports */
- if (mcbsp->id == 2)
- return MCBSP2_FIFO_SIZE - buffstat;
- else
- return MCBSP1345_FIFO_SIZE - buffstat;
+ return mcbsp->pdata->buffer_size - buffstat;
}
EXPORT_SYMBOL(omap_mcbsp_get_tx_delay);
@@ -1683,8 +1694,16 @@ static inline void __devinit omap34xx_device_init(struct omap_mcbsp *mcbsp)
{
mcbsp->dma_op_mode = MCBSP_DMA_MODE_ELEMENT;
if (cpu_is_omap34xx()) {
- mcbsp->max_tx_thres = max_thres(mcbsp);
- mcbsp->max_rx_thres = max_thres(mcbsp);
+ /*
+ * Initially configure the maximum thresholds to a safe value.
+ * The McBSP FIFO usage with these values should not go under
+ * 16 locations.
+ * If the whole FIFO without safety buffer is used, than there
+ * is a possibility that the DMA will be not able to push the
+ * new data on time, causing channel shifts in runtime.
+ */
+ mcbsp->max_tx_thres = max_thres(mcbsp) - 0x10;
+ mcbsp->max_rx_thres = max_thres(mcbsp) - 0x10;
/*
* REVISIT: Set dmap_op_mode to THRESHOLD as default
* for mcbsp2 instances.
diff --git a/arch/arm/plat-orion/include/plat/audio.h b/arch/arm/plat-orion/include/plat/audio.h
new file mode 100644
index 00000000000..9cf1f781329
--- /dev/null
+++ b/arch/arm/plat-orion/include/plat/audio.h
@@ -0,0 +1,11 @@
+#ifndef __PLAT_AUDIO_H
+#define __PLAT_AUDIO_H
+
+#include <linux/mbus.h>
+
+struct kirkwood_asoc_platform_data {
+ u32 tclk;
+ struct mbus_dram_target_info *dram;
+ int burst;
+};
+#endif
diff --git a/arch/arm/plat-s3c24xx/clock.c b/arch/arm/plat-s3c24xx/clock.c
index 8474d05274b..931d26d1a54 100644
--- a/arch/arm/plat-s3c24xx/clock.c
+++ b/arch/arm/plat-s3c24xx/clock.c
@@ -43,7 +43,7 @@
#include <plat/cpu.h>
#include <plat/pll.h>
-/* initalise all the clocks */
+/* initialise all the clocks */
void __init_or_cpufreq s3c24xx_setup_clocks(unsigned long fclk,
unsigned long hclk,
diff --git a/arch/arm/plat-samsung/clock.c b/arch/arm/plat-samsung/clock.c
index 8bf79f3efdf..90a20512d68 100644
--- a/arch/arm/plat-samsung/clock.c
+++ b/arch/arm/plat-samsung/clock.c
@@ -391,7 +391,7 @@ void __init s3c_disable_clocks(struct clk *clkp, int nr_clks)
(clkp->enable)(clkp, 0);
}
-/* initalise all the clocks */
+/* initialise all the clocks */
int __init s3c24xx_register_baseclocks(unsigned long xtal)
{
diff --git a/arch/arm/plat-samsung/include/plat/keypad.h b/arch/arm/plat-samsung/include/plat/keypad.h
new file mode 100644
index 00000000000..3a70c125fe5
--- /dev/null
+++ b/arch/arm/plat-samsung/include/plat/keypad.h
@@ -0,0 +1,43 @@
+/*
+ * Samsung Platform - Keypad platform data definitions
+ *
+ * Copyright (C) 2010 Samsung Electronics Co.Ltd
+ * Author: Joonyoung Shim <jy0922.shim@samsung.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 __PLAT_SAMSUNG_KEYPAD_H
+#define __PLAT_SAMSUNG_KEYPAD_H
+
+#include <linux/input/matrix_keypad.h>
+
+#define SAMSUNG_MAX_ROWS 8
+#define SAMSUNG_MAX_COLS 8
+
+/**
+ * struct samsung_keypad_platdata - Platform device data for Samsung Keypad.
+ * @keymap_data: pointer to &matrix_keymap_data.
+ * @rows: number of keypad row supported.
+ * @cols: number of keypad col supported.
+ * @no_autorepeat: disable key autorepeat.
+ * @wakeup: controls whether the device should be set up as wakeup source.
+ * @cfg_gpio: configure the GPIO.
+ *
+ * Initialisation data specific to either the machine or the platform
+ * for the device driver to use or call-back when configuring gpio.
+ */
+struct samsung_keypad_platdata {
+ const struct matrix_keymap_data *keymap_data;
+ unsigned int rows;
+ unsigned int cols;
+ bool no_autorepeat;
+ bool wakeup;
+
+ void (*cfg_gpio)(unsigned int rows, unsigned int cols);
+};
+
+#endif /* __PLAT_SAMSUNG_KEYPAD_H */
diff --git a/arch/arm/plat-spear/padmux.c b/arch/arm/plat-spear/padmux.c
index d2aab3adcde..555eec6dc1c 100644
--- a/arch/arm/plat-spear/padmux.c
+++ b/arch/arm/plat-spear/padmux.c
@@ -66,7 +66,7 @@ static int pmx_mode_set(struct pmx_mode *mode)
* If peripheral is not supported by current mode then request is rejected.
* Conflicts between peripherals are not handled and peripherals will be
* enabled in the order they are present in pmx_dev array.
- * In case of conflicts last peripheral enalbed will be present.
+ * In case of conflicts last peripheral enabled will be present.
* Returns -ve on Err otherwise 0
*/
static int pmx_devs_enable(struct pmx_dev **devs, u8 count)
diff --git a/arch/avr32/Kconfig b/arch/avr32/Kconfig
index f2b31933318..f51572772e2 100644
--- a/arch/avr32/Kconfig
+++ b/arch/avr32/Kconfig
@@ -45,9 +45,6 @@ config GENERIC_IRQ_PROBE
config RWSEM_GENERIC_SPINLOCK
def_bool y
-config GENERIC_TIME
- def_bool y
-
config GENERIC_CLOCKEVENTS
def_bool y
diff --git a/arch/avr32/Makefile b/arch/avr32/Makefile
index ead8a75203a..22fb66590dc 100644
--- a/arch/avr32/Makefile
+++ b/arch/avr32/Makefile
@@ -13,7 +13,7 @@ KBUILD_DEFCONFIG := atstk1002_defconfig
KBUILD_CFLAGS += -pipe -fno-builtin -mno-pic
KBUILD_AFLAGS += -mrelax -mno-pic
-CFLAGS_MODULE += -mno-relax
+KBUILD_CFLAGS_MODULE += -mno-relax
LDFLAGS_vmlinux += --relax
cpuflags-$(CONFIG_PLATFORM_AT32AP) += -march=ap
diff --git a/arch/avr32/include/asm/local64.h b/arch/avr32/include/asm/local64.h
new file mode 100644
index 00000000000..36c93b5cc23
--- /dev/null
+++ b/arch/avr32/include/asm/local64.h
@@ -0,0 +1 @@
+#include <asm-generic/local64.h>
diff --git a/arch/blackfin/Kconfig b/arch/blackfin/Kconfig
index f66294b4f9d..c88fd358412 100644
--- a/arch/blackfin/Kconfig
+++ b/arch/blackfin/Kconfig
@@ -614,9 +614,6 @@ comment "Kernel Timer/Scheduler"
source kernel/Kconfig.hz
-config GENERIC_TIME
- def_bool y
-
config GENERIC_CLOCKEVENTS
bool "Generic clock events"
default y
diff --git a/arch/blackfin/Makefile b/arch/blackfin/Makefile
index 5a97a31d4bb..9d5ffaf5492 100644
--- a/arch/blackfin/Makefile
+++ b/arch/blackfin/Makefile
@@ -18,8 +18,8 @@ ifeq ($(CONFIG_ROMKERNEL),y)
KBUILD_CFLAGS += -mlong-calls
endif
KBUILD_AFLAGS += $(call cc-option,-mno-fdpic)
-CFLAGS_MODULE += -mlong-calls
-LDFLAGS_MODULE += -m elf32bfin
+KBUILD_CFLAGS_MODULE += -mlong-calls
+KBUILD_LDFLAGS_MODULE += -m elf32bfin
KALLSYMS += --symbol-prefix=_
KBUILD_DEFCONFIG := BF537-STAMP_defconfig
diff --git a/arch/blackfin/include/asm/local64.h b/arch/blackfin/include/asm/local64.h
new file mode 100644
index 00000000000..36c93b5cc23
--- /dev/null
+++ b/arch/blackfin/include/asm/local64.h
@@ -0,0 +1 @@
+#include <asm-generic/local64.h>
diff --git a/arch/cris/Kconfig b/arch/cris/Kconfig
index e25bf4440b5..887ef855be2 100644
--- a/arch/cris/Kconfig
+++ b/arch/cris/Kconfig
@@ -20,9 +20,6 @@ config RWSEM_GENERIC_SPINLOCK
config RWSEM_XCHGADD_ALGORITHM
bool
-config GENERIC_TIME
- def_bool y
-
config GENERIC_CMOS_UPDATE
def_bool y
diff --git a/arch/cris/arch-v32/mm/intmem.c b/arch/cris/arch-v32/mm/intmem.c
index 9e8b69cdf19..1b17d92cef8 100644
--- a/arch/cris/arch-v32/mm/intmem.c
+++ b/arch/cris/arch-v32/mm/intmem.c
@@ -33,8 +33,8 @@ static void crisv32_intmem_init(void)
{
static int initiated = 0;
if (!initiated) {
- struct intmem_allocation* alloc =
- (struct intmem_allocation*)kmalloc(sizeof *alloc, GFP_KERNEL);
+ struct intmem_allocation* alloc;
+ alloc = kmalloc(sizeof *alloc, GFP_KERNEL);
INIT_LIST_HEAD(&intmem_allocations);
intmem_virtual = ioremap(MEM_INTMEM_START + RESERVED_SIZE,
MEM_INTMEM_SIZE - RESERVED_SIZE);
@@ -62,9 +62,8 @@ void* crisv32_intmem_alloc(unsigned size, unsigned align)
if (allocation->status == STATUS_FREE &&
allocation->size >= size + alignment) {
if (allocation->size > size + alignment) {
- struct intmem_allocation* alloc =
- (struct intmem_allocation*)
- kmalloc(sizeof *alloc, GFP_ATOMIC);
+ struct intmem_allocation* alloc;
+ alloc = kmalloc(sizeof *alloc, GFP_ATOMIC);
alloc->status = STATUS_FREE;
alloc->size = allocation->size - size -
alignment;
@@ -74,9 +73,7 @@ void* crisv32_intmem_alloc(unsigned size, unsigned align)
if (alignment) {
struct intmem_allocation *tmp;
- tmp = (struct intmem_allocation *)
- kmalloc(sizeof *tmp,
- GFP_ATOMIC);
+ tmp = kmalloc(sizeof *tmp, GFP_ATOMIC);
tmp->offset = allocation->offset;
tmp->size = alignment;
tmp->status = STATUS_FREE;
diff --git a/arch/cris/include/asm/local64.h b/arch/cris/include/asm/local64.h
new file mode 100644
index 00000000000..36c93b5cc23
--- /dev/null
+++ b/arch/cris/include/asm/local64.h
@@ -0,0 +1 @@
+#include <asm-generic/local64.h>
diff --git a/arch/frv/Kconfig b/arch/frv/Kconfig
index 4b5830bcbe2..16399bd2499 100644
--- a/arch/frv/Kconfig
+++ b/arch/frv/Kconfig
@@ -40,10 +40,6 @@ config GENERIC_HARDIRQS_NO__DO_IRQ
bool
default y
-config GENERIC_TIME
- bool
- default y
-
config TIME_LOW_RES
bool
default y
diff --git a/arch/frv/Makefile b/arch/frv/Makefile
index 310c47a663f..7ff84575b18 100644
--- a/arch/frv/Makefile
+++ b/arch/frv/Makefile
@@ -23,20 +23,14 @@
# Copyright (C) 1994 by Hamish Macdonald
#
-CCSPECS := $(shell $(CC) -v 2>&1 | grep "^Reading specs from " | head -1 | cut -c20-)
-CCDIR := $(strip $(patsubst %/specs,%,$(CCSPECS)))
-CPUCLASS := fr400
-
-# test for cross compiling
-COMPILE_ARCH = $(shell uname -m)
-
ifdef CONFIG_MMU
UTS_SYSNAME = -DUTS_SYSNAME=\"Linux\"
else
UTS_SYSNAME = -DUTS_SYSNAME=\"uClinux\"
endif
-ARCHMODFLAGS += -G0 -mlong-calls
+KBUILD_AFLAGS_MODULE += -G0 -mlong-calls
+KBUILD_CFLAGS_MODULE += -G0 -mlong-calls
ifdef CONFIG_GPREL_DATA_8
KBUILD_CFLAGS += -G8
@@ -54,7 +48,6 @@ endif
ifdef CONFIG_GC_SECTIONS
KBUILD_CFLAGS += -ffunction-sections -fdata-sections
-LINKFLAGS += --gc-sections
endif
ifndef CONFIG_FRAME_POINTER
@@ -64,16 +57,13 @@ endif
ifdef CONFIG_CPU_FR451_COMPILE
KBUILD_CFLAGS += -mcpu=fr450
KBUILD_AFLAGS += -mcpu=fr450
-ASFLAGS += -mcpu=fr450
else
ifdef CONFIG_CPU_FR551_COMPILE
KBUILD_CFLAGS += -mcpu=fr550
KBUILD_AFLAGS += -mcpu=fr550
-ASFLAGS += -mcpu=fr550
else
KBUILD_CFLAGS += -mcpu=fr400
KBUILD_AFLAGS += -mcpu=fr400
-ASFLAGS += -mcpu=fr400
endif
endif
@@ -83,14 +73,12 @@ endif
KBUILD_CFLAGS += -mno-fdpic -mgpr-32 -msoft-float -mno-media
KBUILD_CFLAGS += -ffixed-fcc3 -ffixed-cc3 -ffixed-gr15 -ffixed-icc2
KBUILD_AFLAGS += -mno-fdpic
-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
#KBUILD_CFLAGS += -O1
KBUILD_AFLAGS += -Wa,--gdwarf2
-ASFLAGS += -Wa,--gdwarf2
endif
head-y := arch/frv/kernel/head.o arch/frv/kernel/init_task.o
@@ -105,11 +93,5 @@ all: Image
Image: vmlinux
$(Q)$(MAKE) $(build)=arch/frv/boot $@
-bootstrap:
- $(Q)$(MAKEBOOT) bootstrap
-
archclean:
$(Q)$(MAKE) $(clean)=arch/frv/boot
-
-archdep: scripts/mkdep symlinks
- $(Q)$(MAKE) $(build)=arch/frv/boot dep
diff --git a/arch/frv/include/asm/local64.h b/arch/frv/include/asm/local64.h
new file mode 100644
index 00000000000..36c93b5cc23
--- /dev/null
+++ b/arch/frv/include/asm/local64.h
@@ -0,0 +1 @@
+#include <asm-generic/local64.h>
diff --git a/arch/frv/kernel/local64.h b/arch/frv/kernel/local64.h
new file mode 100644
index 00000000000..36c93b5cc23
--- /dev/null
+++ b/arch/frv/kernel/local64.h
@@ -0,0 +1 @@
+#include <asm-generic/local64.h>
diff --git a/arch/h8300/Kconfig b/arch/h8300/Kconfig
index 53cc669e6d5..988b6ff34cc 100644
--- a/arch/h8300/Kconfig
+++ b/arch/h8300/Kconfig
@@ -62,10 +62,6 @@ config GENERIC_CALIBRATE_DELAY
bool
default y
-config GENERIC_TIME
- bool
- default y
-
config GENERIC_BUG
bool
depends on BUG
diff --git a/arch/h8300/include/asm/local64.h b/arch/h8300/include/asm/local64.h
new file mode 100644
index 00000000000..36c93b5cc23
--- /dev/null
+++ b/arch/h8300/include/asm/local64.h
@@ -0,0 +1 @@
+#include <asm-generic/local64.h>
diff --git a/arch/h8300/kernel/timer/itu.c b/arch/h8300/kernel/timer/itu.c
index 4883ba7103a..a2ae5e95213 100644
--- a/arch/h8300/kernel/timer/itu.c
+++ b/arch/h8300/kernel/timer/itu.c
@@ -73,7 +73,7 @@ void __init h8300_timer_setup(void)
setup_irq(ITUIRQ, &itu_irq);
- /* initalize timer */
+ /* initialize timer */
ctrl_outb(0, TSTR);
ctrl_outb(CCLR0 | div, ITUBASE + TCR);
ctrl_outb(0x01, ITUBASE + TIER);
diff --git a/arch/h8300/kernel/timer/timer16.c b/arch/h8300/kernel/timer/timer16.c
index 042dbb53f3f..ae0d3816113 100644
--- a/arch/h8300/kernel/timer/timer16.c
+++ b/arch/h8300/kernel/timer/timer16.c
@@ -68,7 +68,7 @@ void __init h8300_timer_setup(void)
setup_irq(_16IRQ, &timer16_irq);
- /* initalize timer */
+ /* initialize timer */
ctrl_outb(0, TSTR);
ctrl_outb(CCLR0 | div, _16BASE + TCR);
ctrl_outw(cnt, _16BASE + GRA);
diff --git a/arch/h8300/kernel/timer/timer8.c b/arch/h8300/kernel/timer/timer8.c
index 38be0cabef0..3946c0fa837 100644
--- a/arch/h8300/kernel/timer/timer8.c
+++ b/arch/h8300/kernel/timer/timer8.c
@@ -94,7 +94,7 @@ void __init h8300_timer_setup(void)
ctrl_bclr(0, MSTPCRL)
#endif
- /* initalize timer */
+ /* initialize timer */
ctrl_outw(cnt, _8BASE + TCORA);
ctrl_outw(0x0000, _8BASE + _8TCSR);
ctrl_outw((CMIEA|CCLR_CMA|CKS2) << 8 | div,
diff --git a/arch/ia64/Kconfig b/arch/ia64/Kconfig
index 95610820041..8711d13cd79 100644
--- a/arch/ia64/Kconfig
+++ b/arch/ia64/Kconfig
@@ -82,10 +82,6 @@ config GENERIC_CALIBRATE_DELAY
bool
default y
-config GENERIC_TIME
- bool
- default y
-
config GENERIC_TIME_VSYSCALL
bool
default y
diff --git a/arch/ia64/Makefile b/arch/ia64/Makefile
index 8ae0d2604ce..be7bfa12b70 100644
--- a/arch/ia64/Makefile
+++ b/arch/ia64/Makefile
@@ -22,13 +22,13 @@ CHECKFLAGS += -m64 -D__ia64=1 -D__ia64__=1 -D_LP64 -D__LP64__
OBJCOPYFLAGS := --strip-all
LDFLAGS_vmlinux := -static
-LDFLAGS_MODULE += -T $(srctree)/arch/ia64/module.lds
-AFLAGS_KERNEL := -mconstant-gp
+KBUILD_LDFLAGS_MODULE += -T $(srctree)/arch/ia64/module.lds
+KBUILD_AFLAGS_KERNEL := -mconstant-gp
EXTRA :=
cflags-y := -pipe $(EXTRA) -ffixed-r13 -mfixed-range=f12-f15,f32-f127 \
-falign-functions=32 -frename-registers -fno-optimize-sibling-calls
-CFLAGS_KERNEL := -mconstant-gp
+KBUILD_CFLAGS_KERNEL := -mconstant-gp
GAS_STATUS = $(shell $(srctree)/arch/ia64/scripts/check-gas "$(CC)" "$(OBJDUMP)")
KBUILD_CPPFLAGS += $(shell $(srctree)/arch/ia64/scripts/toolchain-flags "$(CC)" "$(OBJDUMP)" "$(READELF)")
diff --git a/arch/ia64/configs/bigsur_defconfig b/arch/ia64/configs/bigsur_defconfig
index 312b12094a1..c5fe20553da 100644
--- a/arch/ia64/configs/bigsur_defconfig
+++ b/arch/ia64/configs/bigsur_defconfig
@@ -1,1358 +1,118 @@
-#
-# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.16-rc5
-# Mon Feb 27 16:10:42 2006
-#
-
-#
-# Code maturity level options
-#
-CONFIG_EXPERIMENTAL=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_POSIX_MQUEUE=y
-# CONFIG_BSD_PROCESS_ACCT is not set
-CONFIG_SYSCTL=y
-# CONFIG_AUDIT is not set
-# CONFIG_IKCONFIG is not set
-# CONFIG_CPUSETS is not set
-CONFIG_INITRAMFS_SOURCE=""
-CONFIG_CC_OPTIMIZE_FOR_SIZE=y
-# CONFIG_EMBEDDED 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=y
-CONFIG_EPOLL=y
-CONFIG_SHMEM=y
-CONFIG_CC_ALIGN_FUNCTIONS=0
-CONFIG_CC_ALIGN_LABELS=0
-CONFIG_CC_ALIGN_LOOPS=0
-CONFIG_CC_ALIGN_JUMPS=0
-CONFIG_SLUB=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
-CONFIG_OBSOLETE_MODPARM=y
-# CONFIG_MODVERSIONS is not set
-# CONFIG_MODULE_SRCVERSION_ALL is not set
-CONFIG_KMOD=y
-CONFIG_STOP_MACHINE=y
-
-#
-# Block layer
-#
-
-#
-# IO Schedulers
-#
-CONFIG_IOSCHED_NOOP=y
-CONFIG_IOSCHED_AS=y
-CONFIG_IOSCHED_DEADLINE=y
-CONFIG_IOSCHED_CFQ=y
-CONFIG_DEFAULT_AS=y
-# CONFIG_DEFAULT_DEADLINE is not set
-# CONFIG_DEFAULT_CFQ is not set
-# CONFIG_DEFAULT_NOOP is not set
-CONFIG_DEFAULT_IOSCHED="anticipatory"
-
-#
-# Processor type and features
-#
-CONFIG_IA64=y
-CONFIG_64BIT=y
-CONFIG_MMU=y
-CONFIG_SWIOTLB=y
-CONFIG_RWSEM_XCHGADD_ALGORITHM=y
-CONFIG_GENERIC_CALIBRATE_DELAY=y
-CONFIG_GENERIC_TIME=y
-CONFIG_EFI=y
-CONFIG_GENERIC_IOMAP=y
-CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y
-CONFIG_DMA_IS_DMA32=y
-# CONFIG_IA64_GENERIC is not set
-CONFIG_IA64_DIG=y
-# CONFIG_IA64_HP_ZX1 is not set
-# CONFIG_IA64_HP_ZX1_SWIOTLB is not set
-# CONFIG_IA64_SGI_SN2 is not set
-# CONFIG_IA64_HP_SIM is not set
-CONFIG_ITANIUM=y
-# CONFIG_MCKINLEY is not set
-# 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_PGTABLE_3=y
-# CONFIG_PGTABLE_4 is not set
-# CONFIG_HZ_100 is not set
-CONFIG_HZ_250=y
-# CONFIG_HZ_1000 is not set
-CONFIG_HZ=250
-CONFIG_IA64_BRL_EMU=y
-CONFIG_IA64_L1_CACHE_SHIFT=6
-# CONFIG_IA64_CYCLONE is not set
-CONFIG_IOSAPIC=y
-CONFIG_FORCE_MAX_ZONEORDER=17
-CONFIG_SMP=y
-CONFIG_NR_CPUS=2
-# CONFIG_HOTPLUG_CPU is not set
-# CONFIG_SCHED_SMT is not set
-CONFIG_PREEMPT=y
-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_ARCH_SELECT_MEMORY_MODEL=y
-CONFIG_ARCH_DISCONTIGMEM_ENABLE=y
-CONFIG_ARCH_FLATMEM_ENABLE=y
-CONFIG_ARCH_SPARSEMEM_ENABLE=y
-# CONFIG_VIRTUAL_MEM_MAP is not set
-# CONFIG_IA64_MCA_RECOVERY is not set
-CONFIG_PERFMON=y
-CONFIG_IA64_PALINFO=y
-
-#
-# Firmware Drivers
-#
-CONFIG_EFI_VARS=y
-CONFIG_EFI_PCDP=y
-CONFIG_BINFMT_ELF=y
-CONFIG_BINFMT_MISC=m
-
-#
-# Power management and ACPI
-#
-CONFIG_PM=y
-CONFIG_PM_LEGACY=y
-# CONFIG_PM_DEBUG is not set
-
-#
-# ACPI (Advanced Configuration and Power Interface) Support
-#
-CONFIG_ACPI=y
CONFIG_ACPI_BUTTON=m
CONFIG_ACPI_FAN=m
CONFIG_ACPI_PROCESSOR=m
-CONFIG_ACPI_THERMAL=m
-CONFIG_ACPI_BLACKLIST_YEAR=0
-# CONFIG_ACPI_DEBUG is not set
-CONFIG_ACPI_EC=y
-CONFIG_ACPI_POWER=y
-CONFIG_ACPI_SYSTEM=y
-# CONFIG_ACPI_CONTAINER is not set
-
-#
-# CPU Frequency scaling
-#
-# CONFIG_CPU_FREQ is not set
-
-#
-# Bus options (PCI, PCMCIA)
-#
-CONFIG_PCI=y
-CONFIG_PCI_DOMAINS=y
-# CONFIG_PCI_MSI is not set
-CONFIG_PCI_LEGACY_PROC=y
-# CONFIG_PCI_DEBUG is not set
-
-#
-# PCI Hotplug Support
-#
-# CONFIG_HOTPLUG_PCI is not set
-
-#
-# PCCARD (PCMCIA/CardBus) support
-#
-# CONFIG_PCCARD is not set
-
-#
-# Networking
-#
-CONFIG_NET=y
-
-#
-# Networking options
-#
-# CONFIG_NETDEBUG is not set
-CONFIG_PACKET=y
-CONFIG_PACKET_MMAP=y
-CONFIG_UNIX=y
-# CONFIG_NET_KEY is not set
-CONFIG_INET=y
-# CONFIG_IP_MULTICAST is not set
-# CONFIG_IP_ADVANCED_ROUTER is not set
-CONFIG_IP_FIB_HASH=y
-# CONFIG_IP_PNP is not set
-# CONFIG_NET_IPIP is not set
-# CONFIG_NET_IPGRE is not set
-# CONFIG_ARPD is not set
-# CONFIG_SYN_COOKIES is not set
-# CONFIG_INET_AH is not set
-# CONFIG_INET_ESP is not set
-# CONFIG_INET_IPCOMP is not set
-# CONFIG_INET_TUNNEL is not set
-CONFIG_INET_DIAG=y
-CONFIG_INET_TCP_DIAG=y
-# CONFIG_TCP_CONG_ADVANCED is not set
-CONFIG_TCP_CONG_BIC=y
-# CONFIG_IPV6 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_NET_DIVERT is not set
-# CONFIG_ECONET is not set
-# CONFIG_WAN_ROUTER is not set
-
-#
-# QoS and/or fair queueing
-#
-# CONFIG_NET_SCHED is not set
-
-#
-# 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
-
-#
-# 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
-
-#
-# Protocols
-#
-CONFIG_PNPACPI=y
-
-#
-# 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=m
+CONFIG_AGP_I460=m
+CONFIG_AGP=m
+CONFIG_AUTOFS4_FS=m
+CONFIG_AUTOFS_FS=m
+CONFIG_BINFMT_MISC=m
CONFIG_BLK_DEV_CRYPTOLOOP=m
-CONFIG_BLK_DEV_NBD=m
-# CONFIG_BLK_DEV_SX8 is not set
-# CONFIG_BLK_DEV_UB is not set
-CONFIG_BLK_DEV_RAM=m
-CONFIG_BLK_DEV_RAM_COUNT=16
-CONFIG_BLK_DEV_RAM_SIZE=4096
-# CONFIG_CDROM_PKTCDVD is not set
-# CONFIG_ATA_OVER_ETH is not set
-
-#
-# ATA/ATAPI/MFM/RLL support
-#
-CONFIG_IDE=m
-CONFIG_IDE_MAX_HWIFS=4
-CONFIG_BLK_DEV_IDE=m
-
-#
-# Please see Documentation/ide.txt for help/info on IDE drives
-#
-# CONFIG_BLK_DEV_IDE_SATA is not set
-CONFIG_BLK_DEV_IDEDISK=m
-# CONFIG_IDEDISK_MULTI_MODE is not set
-CONFIG_BLK_DEV_IDECD=m
-# CONFIG_BLK_DEV_IDETAPE is not set
-CONFIG_BLK_DEV_IDEFLOPPY=m
-# CONFIG_BLK_DEV_IDESCSI is not set
-# CONFIG_IDE_TASK_IOCTL is not set
-
-#
-# IDE chipset support/bugfixes
-#
-# CONFIG_IDE_GENERIC is not set
-# CONFIG_BLK_DEV_IDEPNP is not set
-CONFIG_BLK_DEV_IDEPCI=y
-CONFIG_IDEPCI_SHARE_IRQ=y
-# CONFIG_BLK_DEV_OFFBOARD is not set
+CONFIG_BLK_DEV_DM=m
CONFIG_BLK_DEV_GENERIC=m
-# 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
-# CONFIG_BLK_DEV_AMD74XX is not set
-# CONFIG_BLK_DEV_CMD64X is not set
-# CONFIG_BLK_DEV_TRIFLEX is not set
-# CONFIG_BLK_DEV_CY82C693 is not set
-# CONFIG_BLK_DEV_CS5520 is not set
-# CONFIG_BLK_DEV_CS5530 is not set
-# CONFIG_BLK_DEV_HPT34X is not set
-# CONFIG_BLK_DEV_HPT366 is not set
-# CONFIG_BLK_DEV_SC1200 is not set
+CONFIG_BLK_DEV_IDECD=m
+CONFIG_BLK_DEV_LOOP=m
+CONFIG_BLK_DEV_MD=m
+CONFIG_BLK_DEV_NBD=m
CONFIG_BLK_DEV_PIIX=m
-# CONFIG_BLK_DEV_IT821X is not set
-# CONFIG_BLK_DEV_NS87415 is not set
-# CONFIG_BLK_DEV_PDC202XX_OLD is not set
-# CONFIG_BLK_DEV_PDC202XX_NEW is not set
-# CONFIG_BLK_DEV_SVWKS is not set
-# CONFIG_BLK_DEV_SIIMAGE is not set
-# CONFIG_BLK_DEV_SLC90E66 is not set
-# CONFIG_BLK_DEV_TRM290 is not set
-# CONFIG_BLK_DEV_VIA82CXXX is not set
-# 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
-
-#
-# SCSI device support
-#
-# CONFIG_RAID_ATTRS is not set
-CONFIG_SCSI=y
-CONFIG_SCSI_PROC_FS=y
-
-#
-# SCSI support type (disk, tape, CD-ROM)
-#
+CONFIG_BLK_DEV_RAM=m
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=y
-CONFIG_SCSI_LOGGING=y
-
-#
-# SCSI Transport Attributes
-#
-CONFIG_SCSI_SPI_ATTRS=m
-# CONFIG_SCSI_FC_ATTRS is not set
-# CONFIG_SCSI_ISCSI_ATTRS is not set
-# CONFIG_SCSI_SAS_ATTRS is not set
-
-#
-# SCSI low-level drivers
-#
-# 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_MEGARAID_NEWGEN is not set
-# CONFIG_MEGARAID_LEGACY is not set
-# CONFIG_MEGARAID_SAS is not set
-# CONFIG_SCSI_SATA 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_SYM53C8XX_2 is not set
-# CONFIG_SCSI_IPR is not set
-# CONFIG_SCSI_QLOGIC_FC is not set
-CONFIG_SCSI_QLOGIC_1280=y
-# CONFIG_SCSI_QLA_FC is not set
-# CONFIG_SCSI_LPFC is not set
-# CONFIG_SCSI_DC395x is not set
-# CONFIG_SCSI_DC390T is not set
-# CONFIG_SCSI_DEBUG is not set
-
-#
-# Multi-device support (RAID and LVM)
-#
-CONFIG_MD=y
-CONFIG_BLK_DEV_MD=m
-CONFIG_MD_LINEAR=m
-CONFIG_MD_RAID0=m
-CONFIG_MD_RAID1=m
-CONFIG_MD_RAID10=m
-CONFIG_MD_RAID5=m
-CONFIG_MD_RAID6=m
-CONFIG_MD_MULTIPATH=m
-# CONFIG_MD_FAULTY is not set
-CONFIG_BLK_DEV_DM=m
+CONFIG_CIFS=m
+CONFIG_CIFS_POSIX=y
+CONFIG_CIFS_STATS=y
+CONFIG_CIFS_XATTR=y
+CONFIG_CRYPTO_DES=y
+CONFIG_CRYPTO_MD5=y
+CONFIG_DEBUG_KERNEL=y
+CONFIG_DEBUG_MUTEXES=y
CONFIG_DM_CRYPT=m
-CONFIG_DM_SNAPSHOT=m
CONFIG_DM_MIRROR=m
+CONFIG_DM_SNAPSHOT=m
CONFIG_DM_ZERO=m
-# CONFIG_DM_MULTIPATH 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_IEEE1394 is not set
-
-#
-# I2O device support
-#
-# CONFIG_I2O is not set
-
-#
-# Network device support
-#
-CONFIG_NETDEVICES=y
-CONFIG_DUMMY=y
-# CONFIG_BONDING 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=y
-# CONFIG_HAPPYMEAL is not set
-# CONFIG_SUNGEM is not set
-# CONFIG_CASSINI is not set
-# CONFIG_NET_VENDOR_3COM is not set
-
-#
-# Tulip family network device support
-#
-# CONFIG_NET_TULIP is not set
-# CONFIG_HP100 is not set
-CONFIG_NET_PCI=y
-# CONFIG_PCNET32 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=y
-# CONFIG_E100 is not set
-# CONFIG_FEALNX is not set
-# CONFIG_NATSEMI is not set
-# CONFIG_NE2K_PCI is not set
-# CONFIG_8139CP is not set
-# CONFIG_8139TOO is not set
-# CONFIG_SIS900 is not set
-# CONFIG_EPIC100 is not set
-# CONFIG_SUNDANCE 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
-
-#
-# Ethernet (10000 Mbit)
-#
-# CONFIG_CHELSIO_T1 is not set
-# CONFIG_IXGB is not set
-# CONFIG_S2IO is not set
-
-#
-# Token Ring devices
-#
-# CONFIG_TR is not set
-
-#
-# Wireless LAN (non-hamradio)
-#
-# CONFIG_NET_RADIO is not set
-
-#
-# Wan interfaces
-#
-# CONFIG_WAN is not set
-# CONFIG_FDDI is not set
-# CONFIG_HIPPI is not set
-# CONFIG_PPP is not set
-# CONFIG_SLIP is not set
-# CONFIG_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
-
-#
-# Userland interfaces
-#
-CONFIG_INPUT_MOUSEDEV=y
-CONFIG_INPUT_MOUSEDEV_PSAUX=y
-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=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_INPUT_MOUSE=y
-CONFIG_MOUSE_PS2=y
-# CONFIG_MOUSE_SERIAL is not set
-# CONFIG_MOUSE_VSXXXAA is not set
-# CONFIG_INPUT_JOYSTICK is not set
-# CONFIG_INPUT_TOUCHSCREEN is not set
-# CONFIG_INPUT_MISC is not set
-
-#
-# Hardware I/O ports
-#
-CONFIG_SERIO=y
-CONFIG_SERIO_I8042=y
-CONFIG_SERIO_SERPORT=y
-# 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=y
-CONFIG_VT_CONSOLE=y
-CONFIG_HW_CONSOLE=y
-# CONFIG_SERIAL_NONSTANDARD is not set
-
-#
-# Serial drivers
-#
-CONFIG_SERIAL_8250=y
-CONFIG_SERIAL_8250_CONSOLE=y
-CONFIG_SERIAL_8250_ACPI=y
-CONFIG_SERIAL_8250_NR_UARTS=4
-CONFIG_SERIAL_8250_RUNTIME_UARTS=4
-CONFIG_SERIAL_8250_EXTENDED=y
-CONFIG_SERIAL_8250_SHARE_IRQ=y
-# CONFIG_SERIAL_8250_DETECT_IRQ is not set
-# CONFIG_SERIAL_8250_RSA is not set
-
-#
-# Non-8250 serial port support
-#
-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
-
-#
-# 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
-
-#
-# Ftape, the floppy tape device driver
-#
-CONFIG_AGP=m
-CONFIG_AGP_I460=m
CONFIG_DRM=m
-# CONFIG_DRM_TDFX is not set
CONFIG_DRM_R128=m
-# CONFIG_DRM_RADEON is not set
-# CONFIG_DRM_MGA is not set
-# CONFIG_DRM_SIS is not set
-# CONFIG_DRM_VIA is not set
-# CONFIG_DRM_SAVAGE is not set
-# CONFIG_RAW_DRIVER is not set
-# CONFIG_HPET is not set
-# CONFIG_HANGCHECK_TIMER is not set
-
-#
-# TPM devices
-#
-# CONFIG_TCG_TPM is not set
-# CONFIG_TELCLOCK is not set
-
-#
-# I2C support
-#
-CONFIG_I2C=y
-CONFIG_I2C_CHARDEV=y
-
-#
-# I2C Algorithms
-#
-CONFIG_I2C_ALGOBIT=y
-# 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_PARPORT_LIGHT is not set
-# CONFIG_I2C_PROSAVAGE is not set
-# CONFIG_I2C_SAVAGE4 is not set
-# CONFIG_SCx200_ACB 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_VIA is not set
-# CONFIG_I2C_VIAPRO is not set
-# CONFIG_I2C_VOODOO3 is not set
-# CONFIG_I2C_PCA_ISA is not set
-
-#
-# Miscellaneous I2C Chip support
-#
-# CONFIG_SENSORS_DS1337 is not set
-# CONFIG_SENSORS_DS1374 is not set
-# CONFIG_EEPROM_LEGACY is not set
-# CONFIG_SENSORS_PCF8574 is not set
-# CONFIG_SENSORS_PCA9539 is not set
-# CONFIG_SENSORS_PCF8591 is not set
-# CONFIG_SENSORS_RTC8564 is not set
-# CONFIG_SENSORS_MAX6875 is not set
-# CONFIG_RTC_X1205_I2C is not set
-# CONFIG_I2C_DEBUG_CORE is not set
-# CONFIG_I2C_DEBUG_ALGO is not set
-# CONFIG_I2C_DEBUG_BUS is not set
-# CONFIG_I2C_DEBUG_CHIP 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_ADM1021 is not set
-# CONFIG_SENSORS_ADM1025 is not set
-# CONFIG_SENSORS_ADM1026 is not set
-# CONFIG_SENSORS_ADM1031 is not set
-# CONFIG_SENSORS_ADM9240 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_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_PC87360 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_VT8231 is not set
-# CONFIG_SENSORS_W83781D is not set
-# CONFIG_SENSORS_W83792D is not set
-# CONFIG_SENSORS_W83L785TS is not set
-# CONFIG_SENSORS_W83627HF is not set
-# CONFIG_SENSORS_W83627EHF is not set
-# CONFIG_HWMON_DEBUG_CHIP is not set
-
-#
-# Misc devices
-#
-
-#
-# Multimedia Capabilities Port drivers
-#
-
-#
-# Multimedia devices
-#
-# CONFIG_VIDEO_DEV is not set
-
-#
-# Digital Video Broadcasting Devices
-#
-# CONFIG_DVB is not set
-
-#
-# Graphics support
-#
-# CONFIG_FB is not set
-
-#
-# Console display driver support
-#
-CONFIG_VGA_CONSOLE=y
-CONFIG_DUMMY_CONSOLE=y
-
-#
-# Sound
-#
-CONFIG_SOUND=m
-
-#
-# Advanced Linux Sound Architecture
-#
-CONFIG_SND=m
-CONFIG_SND_TIMER=m
-CONFIG_SND_PCM=m
-CONFIG_SND_HWDEP=m
-CONFIG_SND_RAWMIDI=m
-CONFIG_SND_SEQUENCER=m
-# CONFIG_SND_SEQ_DUMMY is not set
-CONFIG_SND_OSSEMUL=y
-CONFIG_SND_MIXER_OSS=m
-CONFIG_SND_PCM_OSS=m
-# CONFIG_SND_SEQUENCER_OSS is not set
-# CONFIG_SND_DYNAMIC_MINORS is not set
-CONFIG_SND_SUPPORT_OLD_API=y
-# CONFIG_SND_VERBOSE_PRINTK is not set
-# CONFIG_SND_DEBUG is not set
-
-#
-# Generic devices
-#
-CONFIG_SND_OPL3_LIB=m
-CONFIG_SND_AC97_CODEC=m
-CONFIG_SND_AC97_BUS=m
-# CONFIG_SND_DUMMY is not set
-# CONFIG_SND_VIRMIDI is not set
-# CONFIG_SND_MTPAV is not set
-# CONFIG_SND_SERIAL_U16550 is not set
-# CONFIG_SND_MPU401 is not set
-
-#
-# PCI devices
-#
-# CONFIG_SND_AD1889 is not set
-# CONFIG_SND_ALI5451 is not set
-# CONFIG_SND_ATIIXP is not set
-# CONFIG_SND_ATIIXP_MODEM is not set
-# CONFIG_SND_AU8810 is not set
-# CONFIG_SND_AU8820 is not set
-# CONFIG_SND_AU8830 is not set
-# CONFIG_SND_AZT3328 is not set
-# CONFIG_SND_BT87X is not set
-# CONFIG_SND_CA0106 is not set
-# CONFIG_SND_CMIPCI is not set
-CONFIG_SND_CS4281=m
-# CONFIG_SND_CS46XX is not set
-# CONFIG_SND_EMU10K1 is not set
-# CONFIG_SND_EMU10K1X is not set
-# CONFIG_SND_ENS1370 is not set
-# CONFIG_SND_ENS1371 is not set
-# CONFIG_SND_ES1938 is not set
-# CONFIG_SND_ES1968 is not set
-# CONFIG_SND_FM801 is not set
-# CONFIG_SND_HDA_INTEL is not set
-# CONFIG_SND_HDSP is not set
-# CONFIG_SND_HDSPM is not set
-# CONFIG_SND_ICE1712 is not set
-# CONFIG_SND_ICE1724 is not set
-# CONFIG_SND_INTEL8X0 is not set
-# CONFIG_SND_INTEL8X0M is not set
-# CONFIG_SND_KORG1212 is not set
-# CONFIG_SND_MAESTRO3 is not set
-# CONFIG_SND_MIXART is not set
-# CONFIG_SND_NM256 is not set
-# CONFIG_SND_PCXHR is not set
-# CONFIG_SND_RME32 is not set
-# CONFIG_SND_RME96 is not set
-# CONFIG_SND_RME9652 is not set
-# CONFIG_SND_SONICVIBES is not set
-# CONFIG_SND_TRIDENT is not set
-# CONFIG_SND_VIA82XX is not set
-# CONFIG_SND_VIA82XX_MODEM is not set
-# CONFIG_SND_VX222 is not set
-# CONFIG_SND_YMFPCI is not set
-
-#
-# USB devices
-#
-# CONFIG_SND_USB_AUDIO is not set
-
-#
-# Open Sound System
-#
-# CONFIG_SOUND_PRIME is not set
-
-#
-# USB support
-#
-CONFIG_USB_ARCH_HAS_HCD=y
-CONFIG_USB_ARCH_HAS_OHCI=y
-CONFIG_USB=m
-# CONFIG_USB_DEBUG is not set
-
-#
-# Miscellaneous USB options
-#
-CONFIG_USB_DEVICEFS=y
-# CONFIG_USB_BANDWIDTH 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_EHCI_HCD is not set
-# CONFIG_USB_ISP116X_HCD is not set
-# CONFIG_USB_OHCI_HCD is not set
-CONFIG_USB_UHCI_HCD=m
-# CONFIG_USB_SL811_HCD is not set
-
-#
-# USB Device Class drivers
-#
-# CONFIG_OBSOLETE_OSS_USB_DRIVER is not set
-CONFIG_USB_ACM=m
-CONFIG_USB_PRINTER=m
-
-#
-# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
-#
-
-#
-# may also be needed; see USB_STORAGE Help for more information
-#
-CONFIG_USB_STORAGE=m
-# CONFIG_USB_STORAGE_DEBUG is not set
-# CONFIG_USB_STORAGE_DATAFAB is not set
-# CONFIG_USB_STORAGE_FREECOM is not set
-# CONFIG_USB_STORAGE_ISD200 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_LIBUSUAL is not set
-
-#
-# USB Input Devices
-#
-CONFIG_USB_HID=m
-CONFIG_USB_HIDINPUT=y
-# CONFIG_USB_HIDINPUT_POWERBOOK is not set
-# CONFIG_HID_FF is not set
-CONFIG_USB_HIDDEV=y
-
-#
-# 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_MTOUCH is not set
-# CONFIG_USB_ITMTOUCH is not set
-# CONFIG_USB_EGALAX 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
-
-#
-# USB Imaging devices
-#
-# CONFIG_USB_MDC800 is not set
-# CONFIG_USB_MICROTEK is not set
-
-#
-# USB Multimedia devices
-#
-# CONFIG_USB_DABUSB is not set
-
-#
-# Video4Linux support is needed for USB Multimedia device support
-#
-
-#
-# USB Network Adapters
-#
-# CONFIG_USB_CATC is not set
-# CONFIG_USB_KAWETH is not set
-# CONFIG_USB_PEGASUS is not set
-# CONFIG_USB_RTL8150 is not set
-# CONFIG_USB_USBNET is not set
-CONFIG_USB_MON=y
-
-#
-# 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_AUERSWALD is not set
-# CONFIG_USB_RIO500 is not set
-# CONFIG_USB_LEGOTOWER is not set
-# CONFIG_USB_LCD is not set
-# CONFIG_USB_LED is not set
-# CONFIG_USB_CYTHERM is not set
-# CONFIG_USB_PHIDGETKIT is not set
-# CONFIG_USB_PHIDGETSERVO is not set
-# CONFIG_USB_IDMOUSE is not set
-# CONFIG_USB_LD is not set
-# CONFIG_USB_TEST is not set
-
-#
-# USB DSL modem support
-#
-
-#
-# USB Gadget Support
-#
-# CONFIG_USB_GADGET is not set
-
-#
-# MMC/SD Card support
-#
-# CONFIG_MMC is not set
-
-#
-# InfiniBand support
-#
-# CONFIG_INFINIBAND is not set
-
-#
-# EDAC - error detection and reporting (RAS)
-#
-
-#
-# File systems
-#
+CONFIG_DUMMY=y
+CONFIG_EFI_PARTITION=y
+CONFIG_EFI_RTC=y
+CONFIG_EFI_VARS=y
+CONFIG_EXPERIMENTAL=y
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_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=y
-CONFIG_XFS_EXPORT=y
-CONFIG_XFS_QUOTA=y
-CONFIG_XFS_SECURITY=y
-CONFIG_XFS_POSIX_ACL=y
-# CONFIG_XFS_RT is not set
-# CONFIG_OCFS2_FS is not set
-# CONFIG_MINIX_FS is not set
-# CONFIG_ROMFS_FS is not set
+CONFIG_HUGETLBFS=y
+# CONFIG_HW_RANDOM is not set
+CONFIG_I2C_CHARDEV=y
+CONFIG_I2C=y
+CONFIG_IA64_DIG=y
+CONFIG_IA64_PALINFO=y
+CONFIG_IDE=m
+CONFIG_INET=y
CONFIG_INOTIFY=y
-# CONFIG_QUOTA is not set
-CONFIG_QUOTACTL=y
-CONFIG_DNOTIFY=y
-CONFIG_AUTOFS_FS=m
-CONFIG_AUTOFS4_FS=m
-# CONFIG_FUSE_FS is not set
-
-#
-# CD-ROM/DVD Filesystems
-#
+CONFIG_INPUT_EVDEV=y
+# CONFIG_IPV6 is not set
CONFIG_ISO9660_FS=m
CONFIG_JOLIET=y
-# CONFIG_ZISOFS is not set
-CONFIG_UDF_FS=m
-CONFIG_UDF_NLS=y
-
-#
-# DOS/FAT/NT Filesystems
-#
-CONFIG_FAT_FS=y
-# CONFIG_MSDOS_FS is not set
-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_KCORE=y
-CONFIG_SYSFS=y
-CONFIG_TMPFS=y
-CONFIG_HUGETLBFS=y
-CONFIG_HUGETLB_PAGE=y
-CONFIG_RAMFS=y
-# CONFIG_RELAYFS_FS is not set
-# CONFIG_CONFIGFS_FS is not set
-
-#
-# Miscellaneous filesystems
-#
-# CONFIG_ADFS_FS is not set
-# CONFIG_AFFS_FS is not set
-# CONFIG_HFS_FS is not set
-# CONFIG_HFSPLUS_FS is not set
-# CONFIG_BEFS_FS is not set
-# CONFIG_BFS_FS is not set
-# CONFIG_EFS_FS is not set
-# CONFIG_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_LOG_BUF_SHIFT=16
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_MD_LINEAR=m
+CONFIG_MD_MULTIPATH=m
+CONFIG_MD_RAID0=m
+CONFIG_MD_RAID10=m
+CONFIG_MD_RAID1=m
+CONFIG_MD=y
+CONFIG_MII=y
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_NETDEVICES=y
+CONFIG_NET_ETHERNET=y
+CONFIG_NET_PCI=y
+CONFIG_NET=y
+CONFIG_NFSD=m
+CONFIG_NFSD_V4=y
CONFIG_NFS_FS=m
CONFIG_NFS_V3=y
-# CONFIG_NFS_V3_ACL is not set
CONFIG_NFS_V4=y
-# CONFIG_NFS_DIRECTIO is not set
-CONFIG_NFSD=m
-CONFIG_NFSD_V3=y
-# CONFIG_NFSD_V3_ACL is not set
-CONFIG_NFSD_V4=y
-CONFIG_NFSD_TCP=y
-CONFIG_LOCKD=m
-CONFIG_LOCKD_V4=y
-CONFIG_EXPORTFS=y
-CONFIG_NFS_COMMON=y
-CONFIG_SUNRPC=m
-CONFIG_SUNRPC_GSS=m
-CONFIG_RPCSEC_GSS_KRB5=m
-# CONFIG_RPCSEC_GSS_SPKM3 is not set
-# CONFIG_SMB_FS is not set
-CONFIG_CIFS=m
-CONFIG_CIFS_STATS=y
-# CONFIG_CIFS_STATS2 is not set
-CONFIG_CIFS_XATTR=y
-CONFIG_CIFS_POSIX=y
-# CONFIG_CIFS_EXPERIMENTAL is not set
-# CONFIG_NCP_FS is not set
-# CONFIG_CODA_FS is not set
-# CONFIG_AFS_FS is not set
-# CONFIG_9P_FS is not set
-
-#
-# Partition Types
-#
-CONFIG_PARTITION_ADVANCED=y
-# CONFIG_ACORN_PARTITION is not set
-# CONFIG_OSF_PARTITION is not set
-# CONFIG_AMIGA_PARTITION is not set
-# CONFIG_ATARI_PARTITION is not set
-# CONFIG_MAC_PARTITION is not set
-CONFIG_MSDOS_PARTITION=y
-# CONFIG_BSD_DISKLABEL is not set
-# CONFIG_MINIX_SUBPARTITION is not set
-# CONFIG_SOLARIS_X86_PARTITION is not set
-# CONFIG_UNIXWARE_DISKLABEL is not set
-# CONFIG_LDM_PARTITION is not set
-CONFIG_SGI_PARTITION=y
-# CONFIG_ULTRIX_PARTITION is not set
-# CONFIG_SUN_PARTITION is not set
-# CONFIG_KARMA_PARTITION is not set
-CONFIG_EFI_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=m
-
-#
-# Library routines
-#
-# CONFIG_CRC_CCITT is not set
-# CONFIG_CRC16 is not set
-CONFIG_CRC32=y
-# CONFIG_LIBCRC32C is not set
-CONFIG_GENERIC_HARDIRQS=y
-CONFIG_GENERIC_IRQ_PROBE=y
-CONFIG_GENERIC_PENDING_IRQ=y
-
-#
-# Instrumentation Support
-#
-CONFIG_PROFILING=y
+CONFIG_NR_CPUS=2
CONFIG_OPROFILE=y
-# CONFIG_KPROBES is not set
-
-#
-# Kernel hacking
-#
-# CONFIG_PRINTK_TIME is not set
-CONFIG_MAGIC_SYSRQ=y
-CONFIG_DEBUG_KERNEL=y
-CONFIG_LOG_BUF_SHIFT=16
-CONFIG_DETECT_SOFTLOCKUP=y
-# CONFIG_SCHEDSTATS is not set
-# CONFIG_DEBUG_SLAB is not set
-CONFIG_DEBUG_PREEMPT=y
-CONFIG_DEBUG_MUTEXES=y
-# CONFIG_DEBUG_SPINLOCK is not set
-# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
-# CONFIG_DEBUG_KOBJECT is not set
-# CONFIG_DEBUG_INFO is not set
-# CONFIG_DEBUG_FS is not set
-# CONFIG_DEBUG_VM is not set
-CONFIG_FORCED_INLINING=y
-# CONFIG_RCU_TORTURE_TEST is not set
-# CONFIG_IA64_GRANULE_16MB is not set
-CONFIG_IA64_GRANULE_64MB=y
-# CONFIG_IA64_PRINT_HAZARDS is not set
-# 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_HMAC is not set
-# CONFIG_CRYPTO_NULL is not set
-# CONFIG_CRYPTO_MD4 is not set
-CONFIG_CRYPTO_MD5=y
-# CONFIG_CRYPTO_SHA1 is not set
-# CONFIG_CRYPTO_SHA256 is not set
-# CONFIG_CRYPTO_SHA512 is not set
-# CONFIG_CRYPTO_WP512 is not set
-# CONFIG_CRYPTO_TGR192 is not set
-CONFIG_CRYPTO_DES=y
-# CONFIG_CRYPTO_BLOWFISH is not set
-# CONFIG_CRYPTO_TWOFISH is not set
-# CONFIG_CRYPTO_SERPENT is not set
-# CONFIG_CRYPTO_AES is not set
-# CONFIG_CRYPTO_CAST5 is not set
-# CONFIG_CRYPTO_CAST6 is not set
-# CONFIG_CRYPTO_TEA is not set
-# CONFIG_CRYPTO_ARC4 is not set
-# CONFIG_CRYPTO_KHAZAD is not set
-# CONFIG_CRYPTO_ANUBIS is not set
-# CONFIG_CRYPTO_DEFLATE is not set
-# CONFIG_CRYPTO_MICHAEL_MIC is not set
-# CONFIG_CRYPTO_CRC32C is not set
-# CONFIG_CRYPTO_TEST is not set
-
-#
-# Hardware crypto devices
-#
+CONFIG_PACKET=y
+CONFIG_PARTITION_ADVANCED=y
+CONFIG_PERFMON=y
+CONFIG_POSIX_MQUEUE=y
+CONFIG_PREEMPT=y
+CONFIG_PROC_KCORE=y
+CONFIG_PROFILING=y
+CONFIG_SCSI_CONSTANTS=y
+CONFIG_SCSI_LOGGING=y
+CONFIG_SCSI_QLOGIC_1280=y
+CONFIG_SCSI_SPI_ATTRS=m
+CONFIG_SCSI=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_EXTENDED=y
+CONFIG_SERIAL_8250_SHARE_IRQ=y
+CONFIG_SERIAL_8250=y
+CONFIG_SGI_PARTITION=y
+CONFIG_SMP=y
+CONFIG_SND_CS4281=m
+CONFIG_SND=m
+CONFIG_SND_MIXER_OSS=m
+CONFIG_SND_PCM_OSS=m
+CONFIG_SND_SEQUENCER=m
+CONFIG_SOUND=m
+CONFIG_SYSVIPC=y
+CONFIG_TMPFS=y
+CONFIG_UDF_FS=m
+CONFIG_UNIX=y
+CONFIG_USB_ACM=m
+CONFIG_USB_DEVICEFS=y
+CONFIG_USB_HIDDEV=y
+CONFIG_USB=m
+CONFIG_USB_MON=m
+CONFIG_USB_PRINTER=m
+CONFIG_USB_STORAGE=m
+CONFIG_USB_UHCI_HCD=m
+CONFIG_VFAT_FS=y
+# CONFIG_VIRTUAL_MEM_MAP is not set
+CONFIG_XFS_FS=y
+CONFIG_XFS_POSIX_ACL=y
+CONFIG_XFS_QUOTA=y
diff --git a/arch/ia64/configs/generic_defconfig b/arch/ia64/configs/generic_defconfig
index 6a4cc506fb5..01ba5305e98 100644
--- a/arch/ia64/configs/generic_defconfig
+++ b/arch/ia64/configs/generic_defconfig
@@ -1,1455 +1,133 @@
-#
-# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.28-rc7
-# Mon Dec 8 08:12:07 2008
-#
-CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
-
-#
-# General setup
-#
-CONFIG_EXPERIMENTAL=y
-CONFIG_LOCK_KERNEL=y
-CONFIG_INIT_ENV_ARG_LIMIT=32
-CONFIG_LOCALVERSION=""
-CONFIG_LOCALVERSION_AUTO=y
-CONFIG_SWAP=y
-CONFIG_SYSVIPC=y
-CONFIG_SYSVIPC_SYSCTL=y
-CONFIG_POSIX_MQUEUE=y
-# CONFIG_BSD_PROCESS_ACCT is not set
-# CONFIG_TASKSTATS is not set
-# CONFIG_AUDIT is not set
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_LOG_BUF_SHIFT=20
-CONFIG_CGROUPS=y
-# CONFIG_CGROUP_DEBUG is not set
-# CONFIG_CGROUP_NS is not set
-# CONFIG_CGROUP_FREEZER is not set
-# CONFIG_CGROUP_DEVICE is not set
-CONFIG_CPUSETS=y
-# CONFIG_GROUP_SCHED is not set
-# CONFIG_CGROUP_CPUACCT is not set
-# CONFIG_RESOURCE_COUNTERS is not set
-CONFIG_SYSFS_DEPRECATED=y
-CONFIG_SYSFS_DEPRECATED_V2=y
-CONFIG_PROC_PID_CPUSET=y
-# CONFIG_RELAY is not set
-CONFIG_NAMESPACES=y
-# CONFIG_UTS_NS is not set
-# CONFIG_IPC_NS is not set
-# CONFIG_USER_NS is not set
-# CONFIG_PID_NS is not set
-CONFIG_BLK_DEV_INITRD=y
-CONFIG_INITRAMFS_SOURCE=""
-CONFIG_CC_OPTIMIZE_FOR_SIZE=y
-CONFIG_SYSCTL=y
-# CONFIG_EMBEDDED is not set
-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_COMPAT_BRK=y
-CONFIG_BASE_FULL=y
-CONFIG_FUTEX=y
-CONFIG_ANON_INODES=y
-CONFIG_EPOLL=y
-CONFIG_SIGNALFD=y
-CONFIG_TIMERFD=y
-CONFIG_EVENTFD=y
-CONFIG_SHMEM=y
-CONFIG_AIO=y
-CONFIG_VM_EVENT_COUNTERS=y
-CONFIG_PCI_QUIRKS=y
-CONFIG_SLUB_DEBUG=y
-# CONFIG_SLAB is not set
-CONFIG_SLUB=y
-# CONFIG_SLOB is not set
-# CONFIG_PROFILING is not set
-# CONFIG_MARKERS is not set
-CONFIG_HAVE_OPROFILE=y
-# CONFIG_KPROBES is not set
-CONFIG_HAVE_KPROBES=y
-CONFIG_HAVE_KRETPROBES=y
-CONFIG_HAVE_ARCH_TRACEHOOK=y
-CONFIG_HAVE_DMA_ATTRS=y
-CONFIG_USE_GENERIC_SMP_HELPERS=y
-# CONFIG_HAVE_GENERIC_DMA_COHERENT is not set
-CONFIG_SLABINFO=y
-CONFIG_RT_MUTEXES=y
-# CONFIG_TINY_SHMEM is not set
-CONFIG_BASE_SMALL=0
-CONFIG_MODULES=y
-# CONFIG_MODULE_FORCE_LOAD is not set
-CONFIG_MODULE_UNLOAD=y
-# CONFIG_MODULE_FORCE_UNLOAD is not set
-CONFIG_MODVERSIONS=y
-# CONFIG_MODULE_SRCVERSION_ALL is not set
-CONFIG_KMOD=y
-CONFIG_STOP_MACHINE=y
-CONFIG_BLOCK=y
-# CONFIG_BLK_DEV_IO_TRACE is not set
-# CONFIG_BLK_DEV_BSG is not set
-# CONFIG_BLK_DEV_INTEGRITY is not set
-CONFIG_BLOCK_COMPAT=y
-
-#
-# 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"
-CONFIG_CLASSIC_RCU=y
-# CONFIG_FREEZER is not set
-
-#
-# Processor type and features
-#
-CONFIG_IA64=y
-CONFIG_64BIT=y
-CONFIG_ZONE_DMA=y
-CONFIG_QUICKLIST=y
-CONFIG_MMU=y
-CONFIG_SWIOTLB=y
-CONFIG_IOMMU_HELPER=y
-CONFIG_RWSEM_XCHGADD_ALGORITHM=y
-CONFIG_HUGETLB_PAGE_SIZE_VARIABLE=y
-CONFIG_GENERIC_FIND_NEXT_BIT=y
-CONFIG_GENERIC_CALIBRATE_DELAY=y
-CONFIG_GENERIC_TIME=y
-CONFIG_GENERIC_TIME_VSYSCALL=y
-CONFIG_HAVE_SETUP_PER_CPU_AREA=y
-CONFIG_DMI=y
-CONFIG_EFI=y
-CONFIG_GENERIC_IOMAP=y
-CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y
-CONFIG_IA64_UNCACHED_ALLOCATOR=y
-CONFIG_AUDIT_ARCH=y
-# CONFIG_PARAVIRT_GUEST is not set
-CONFIG_IA64_GENERIC=y
-# CONFIG_IA64_DIG is not set
-# CONFIG_IA64_DIG_VTD is not set
-# CONFIG_IA64_HP_ZX1 is not set
-# CONFIG_IA64_HP_ZX1_SWIOTLB is not set
-# CONFIG_IA64_SGI_SN2 is not set
-# CONFIG_IA64_SGI_UV is not set
-# CONFIG_IA64_HP_SIM is not set
-# CONFIG_IA64_XEN_GUEST is not set
-# CONFIG_ITANIUM is not set
-CONFIG_MCKINLEY=y
-# CONFIG_IA64_PAGE_SIZE_4KB is not set
-# CONFIG_IA64_PAGE_SIZE_8KB 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=250
-# CONFIG_HZ_100 is not set
-CONFIG_HZ_250=y
-# CONFIG_HZ_300 is not set
-# CONFIG_HZ_1000 is not set
-# CONFIG_SCHED_HRTICK is not set
-CONFIG_IA64_L1_CACHE_SHIFT=7
-CONFIG_IA64_CYCLONE=y
-CONFIG_IOSAPIC=y
-CONFIG_FORCE_MAX_ZONEORDER=17
-# CONFIG_VIRT_CPU_ACCOUNTING is not set
-CONFIG_SMP=y
-CONFIG_NR_CPUS=4096
-CONFIG_HOTPLUG_CPU=y
-CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
-CONFIG_ARCH_ENABLE_MEMORY_HOTREMOVE=y
-# CONFIG_SCHED_SMT is not set
-# CONFIG_PERMIT_BSP_REMOVE is not set
-CONFIG_PREEMPT_NONE=y
-# CONFIG_PREEMPT_VOLUNTARY is not set
-# CONFIG_PREEMPT is not set
-CONFIG_SELECT_MEMORY_MODEL=y
-# CONFIG_FLATMEM_MANUAL is not set
-CONFIG_DISCONTIGMEM_MANUAL=y
-# CONFIG_SPARSEMEM_MANUAL is not set
-CONFIG_DISCONTIGMEM=y
-CONFIG_FLAT_NODE_MEM_MAP=y
-CONFIG_NEED_MULTIPLE_NODES=y
-CONFIG_SPARSEMEM_VMEMMAP_ENABLE=y
-CONFIG_PAGEFLAGS_EXTENDED=y
-CONFIG_SPLIT_PTLOCK_CPUS=4
-CONFIG_MIGRATION=y
-CONFIG_RESOURCES_64BIT=y
-CONFIG_PHYS_ADDR_T_64BIT=y
-CONFIG_ZONE_DMA_FLAG=1
-CONFIG_BOUNCE=y
-CONFIG_NR_QUICK=1
-CONFIG_VIRT_TO_BUS=y
-CONFIG_UNEVICTABLE_LRU=y
-CONFIG_ARCH_SELECT_MEMORY_MODEL=y
-CONFIG_ARCH_DISCONTIGMEM_ENABLE=y
-CONFIG_ARCH_FLATMEM_ENABLE=y
-CONFIG_ARCH_SPARSEMEM_ENABLE=y
-CONFIG_ARCH_DISCONTIGMEM_DEFAULT=y
-CONFIG_NUMA=y
-CONFIG_NODES_SHIFT=10
-CONFIG_ARCH_POPULATES_NODE_MAP=y
-CONFIG_VIRTUAL_MEM_MAP=y
-CONFIG_HOLES_IN_ZONE=y
-CONFIG_HAVE_ARCH_EARLY_PFN_TO_NID=y
-CONFIG_HAVE_ARCH_NODEDATA_EXTENSION=y
-CONFIG_COMPAT_FOR_U64_ALIGNMENT=y
-CONFIG_IA64_MCA_RECOVERY=y
-CONFIG_PERFMON=y
-CONFIG_IA64_PALINFO=y
-# CONFIG_IA64_MC_ERR_INJECT is not set
-CONFIG_SGI_SN=y
-# CONFIG_IA64_ESI is not set
-# CONFIG_IA64_HP_AML_NFW is not set
-
-#
-# SN Devices
-#
-CONFIG_SGI_IOC3=m
-CONFIG_KEXEC=y
-CONFIG_CRASH_DUMP=y
-
-#
-# Firmware Drivers
-#
-# CONFIG_FIRMWARE_MEMMAP is not set
-CONFIG_EFI_VARS=y
-CONFIG_EFI_PCDP=y
-CONFIG_DMIID=y
-CONFIG_BINFMT_ELF=y
-# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
-# CONFIG_HAVE_AOUT is not set
-CONFIG_BINFMT_MISC=m
-
-#
-# Power management and ACPI options
-#
-CONFIG_PM=y
-# CONFIG_PM_DEBUG is not set
-CONFIG_ACPI=y
-CONFIG_ACPI_PROCFS=y
-CONFIG_ACPI_PROCFS_POWER=y
-CONFIG_ACPI_SYSFS_POWER=y
-CONFIG_ACPI_PROC_EVENT=y
CONFIG_ACPI_BUTTON=m
-CONFIG_ACPI_FAN=m
+CONFIG_ACPI_CONTAINER=m
CONFIG_ACPI_DOCK=y
+CONFIG_ACPI_FAN=m
CONFIG_ACPI_PROCESSOR=m
-CONFIG_ACPI_HOTPLUG_CPU=y
-CONFIG_ACPI_THERMAL=m
-CONFIG_ACPI_NUMA=y
-# CONFIG_ACPI_CUSTOM_DSDT is not set
-CONFIG_ACPI_BLACKLIST_YEAR=0
-# CONFIG_ACPI_DEBUG is not set
-# CONFIG_ACPI_PCI_SLOT is not set
-CONFIG_ACPI_SYSTEM=y
-CONFIG_ACPI_CONTAINER=m
-
-#
-# CPU Frequency scaling
-#
-# CONFIG_CPU_FREQ is not set
-
-#
-# Bus options (PCI, PCMCIA)
-#
-CONFIG_PCI=y
-CONFIG_PCI_DOMAINS=y
-CONFIG_PCI_SYSCALL=y
-# CONFIG_PCIEPORTBUS is not set
-CONFIG_ARCH_SUPPORTS_MSI=y
-CONFIG_PCI_MSI=y
-CONFIG_PCI_LEGACY=y
-# CONFIG_PCI_DEBUG is not set
-CONFIG_HOTPLUG_PCI=m
-# CONFIG_HOTPLUG_PCI_FAKE is not set
-CONFIG_HOTPLUG_PCI_ACPI=m
-# CONFIG_HOTPLUG_PCI_ACPI_IBM is not set
-# CONFIG_HOTPLUG_PCI_CPCI is not set
-# CONFIG_HOTPLUG_PCI_SHPC is not set
-# CONFIG_HOTPLUG_PCI_SGI is not set
-# CONFIG_PCCARD is not set
-CONFIG_DMAR=y
-CONFIG_NET=y
-
-#
-# Networking options
-#
-CONFIG_PACKET=y
-# CONFIG_PACKET_MMAP is not set
-CONFIG_UNIX=y
-CONFIG_XFRM=y
-# CONFIG_XFRM_USER is not set
-# CONFIG_XFRM_SUB_POLICY is not set
-# CONFIG_XFRM_MIGRATE is not set
-# CONFIG_XFRM_STATISTICS is not set
-# CONFIG_NET_KEY is not set
-CONFIG_INET=y
-CONFIG_IP_MULTICAST=y
-# CONFIG_IP_ADVANCED_ROUTER is not set
-CONFIG_IP_FIB_HASH=y
-# CONFIG_IP_PNP is not set
-# CONFIG_NET_IPIP is not set
-# CONFIG_NET_IPGRE is not set
-# CONFIG_IP_MROUTE is not set
+CONFIG_ACPI_PROCFS=y
+CONFIG_AGP_HP_ZX1=m
+CONFIG_AGP_I460=m
+CONFIG_AGP=m
+CONFIG_AGP_SGI_TIOCA=m
CONFIG_ARPD=y
-CONFIG_SYN_COOKIES=y
-# CONFIG_INET_AH is not set
-# CONFIG_INET_ESP is not set
-# CONFIG_INET_IPCOMP is not set
-# CONFIG_INET_XFRM_TUNNEL is not set
-# CONFIG_INET_TUNNEL is not set
-CONFIG_INET_XFRM_MODE_TRANSPORT=y
-CONFIG_INET_XFRM_MODE_TUNNEL=y
-CONFIG_INET_XFRM_MODE_BEET=y
-CONFIG_INET_LRO=m
-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_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_NET_DSA is not set
-# CONFIG_VLAN_8021Q is not set
-# CONFIG_DECNET is not set
-# CONFIG_LLC2 is not set
-# CONFIG_IPX is not set
-# CONFIG_ATALK is not set
-# CONFIG_X25 is not set
-# CONFIG_LAPB is not set
-# CONFIG_ECONET is not set
-# CONFIG_WAN_ROUTER is not set
-# CONFIG_NET_SCHED is not set
-
-#
-# Network testing
-#
-# CONFIG_NET_PKTGEN is not set
-# CONFIG_HAMRADIO is not set
-# CONFIG_CAN is not set
-# CONFIG_IRDA is not set
-# CONFIG_BT is not set
-# CONFIG_AF_RXRPC is not set
-# CONFIG_PHONET is not set
-CONFIG_WIRELESS=y
-# CONFIG_CFG80211 is not set
-CONFIG_WIRELESS_OLD_REGULATORY=y
-# CONFIG_WIRELESS_EXT is not set
-# CONFIG_MAC80211 is not set
-# CONFIG_IEEE80211 is not set
-# CONFIG_RFKILL is not set
-# CONFIG_NET_9P is not set
-
-#
-# Device Drivers
-#
-
-#
-# Generic Driver Options
-#
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
-CONFIG_STANDALONE=y
-CONFIG_PREVENT_FIRMWARE_BUILD=y
-CONFIG_FW_LOADER=y
-CONFIG_FIRMWARE_IN_KERNEL=y
-CONFIG_EXTRA_FIRMWARE=""
-# CONFIG_DEBUG_DRIVER is not set
-# CONFIG_DEBUG_DEVRES is not set
-# CONFIG_SYS_HYPERVISOR is not set
-CONFIG_CONNECTOR=y
-CONFIG_PROC_EVENTS=y
-# CONFIG_MTD is not set
-# CONFIG_PARPORT is not set
-CONFIG_PNP=y
-# CONFIG_PNP_DEBUG_MESSAGES is not set
-
-#
-# Protocols
-#
-CONFIG_PNPACPI=y
-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
-# CONFIG_BLK_DEV_UMEM is not set
-# CONFIG_BLK_DEV_COW_COMMON is not set
-CONFIG_BLK_DEV_LOOP=m
+CONFIG_ATA_PIIX=y
+CONFIG_ATA=y
+CONFIG_AUTOFS4_FS=m
+CONFIG_AUTOFS_FS=m
+CONFIG_BINFMT_MISC=m
+# CONFIG_BLK_DEV_BSG is not set
+CONFIG_BLK_DEV_CMD64X=y
CONFIG_BLK_DEV_CRYPTOLOOP=m
-CONFIG_BLK_DEV_NBD=m
-# CONFIG_BLK_DEV_SX8 is not set
-# CONFIG_BLK_DEV_UB is not set
-CONFIG_BLK_DEV_RAM=y
-CONFIG_BLK_DEV_RAM_COUNT=16
-CONFIG_BLK_DEV_RAM_SIZE=4096
-# CONFIG_BLK_DEV_XIP is not set
-# CONFIG_CDROM_PKTCDVD is not set
-# CONFIG_ATA_OVER_ETH is not set
-# CONFIG_BLK_DEV_HD is not set
-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
-# CONFIG_ENCLOSURE_SERVICES is not set
-CONFIG_SGI_XP=m
-# CONFIG_HP_ILO is not set
-# CONFIG_C2PORT is not set
-CONFIG_HAVE_IDE=y
-CONFIG_IDE=y
-
-#
-# Please see Documentation/ide/ide.txt for help/info on IDE drives
-#
-CONFIG_IDE_TIMINGS=y
-CONFIG_IDE_ATAPI=y
-# CONFIG_BLK_DEV_IDE_SATA is not set
-CONFIG_IDE_GD=y
-CONFIG_IDE_GD_ATA=y
-# CONFIG_IDE_GD_ATAPI is not set
-CONFIG_BLK_DEV_IDECD=y
-CONFIG_BLK_DEV_IDECD_VERBOSE_ERRORS=y
-# CONFIG_BLK_DEV_IDETAPE is not set
-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
-#
-# CONFIG_IDE_GENERIC is not set
-# CONFIG_BLK_DEV_PLATFORM is not set
-# CONFIG_BLK_DEV_IDEPNP is not set
-CONFIG_BLK_DEV_IDEDMA_SFF=y
-
-#
-# PCI IDE chipsets support
-#
-CONFIG_BLK_DEV_IDEPCI=y
-CONFIG_IDEPCI_PCIBUS_ORDER=y
-# CONFIG_BLK_DEV_OFFBOARD is not set
+CONFIG_BLK_DEV_DM=m
CONFIG_BLK_DEV_GENERIC=y
-# CONFIG_BLK_DEV_OPTI621 is not set
-CONFIG_BLK_DEV_IDEDMA_PCI=y
-# CONFIG_BLK_DEV_AEC62XX is not set
-# CONFIG_BLK_DEV_ALI15X3 is not set
-# CONFIG_BLK_DEV_AMD74XX is not set
-CONFIG_BLK_DEV_CMD64X=y
-# CONFIG_BLK_DEV_TRIFLEX is not set
-# CONFIG_BLK_DEV_CS5520 is not set
-# CONFIG_BLK_DEV_CS5530 is not set
-# CONFIG_BLK_DEV_HPT366 is not set
-# CONFIG_BLK_DEV_JMICRON is not set
-# CONFIG_BLK_DEV_SC1200 is not set
+CONFIG_BLK_DEV_IDECD=y
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_BLK_DEV_LOOP=m
+CONFIG_BLK_DEV_MD=m
+CONFIG_BLK_DEV_NBD=m
CONFIG_BLK_DEV_PIIX=y
-# CONFIG_BLK_DEV_IT8213 is not set
-# CONFIG_BLK_DEV_IT821X is not set
-# CONFIG_BLK_DEV_NS87415 is not set
-# CONFIG_BLK_DEV_PDC202XX_OLD is not set
-# CONFIG_BLK_DEV_PDC202XX_NEW is not set
-# CONFIG_BLK_DEV_SVWKS is not set
-CONFIG_BLK_DEV_SGIIOC4=y
-# CONFIG_BLK_DEV_SIIMAGE is not set
-# CONFIG_BLK_DEV_SLC90E66 is not set
-# CONFIG_BLK_DEV_TRM290 is not set
-# CONFIG_BLK_DEV_VIA82CXXX is not set
-# CONFIG_BLK_DEV_TC86C001 is not set
-CONFIG_BLK_DEV_IDEDMA=y
-
-#
-# SCSI device support
-#
-# 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
-
-#
-# SCSI support type (disk, tape, CD-ROM)
-#
+CONFIG_BLK_DEV_RAM=y
CONFIG_BLK_DEV_SD=y
-CONFIG_CHR_DEV_ST=m
-# CONFIG_CHR_DEV_OSST is not set
+CONFIG_BLK_DEV_SGIIOC4=y
CONFIG_BLK_DEV_SR=m
-# CONFIG_BLK_DEV_SR_VENDOR is not set
+CONFIG_CGROUPS=y
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=y
-CONFIG_SCSI_FC_ATTRS=y
-# CONFIG_SCSI_ISCSI_ATTRS is not set
-CONFIG_SCSI_SAS_ATTRS=y
-# CONFIG_SCSI_SAS_LIBSAS is not set
-# CONFIG_SCSI_SRP_ATTRS is not set
-CONFIG_SCSI_LOWLEVEL=y
-# 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_ADVANSYS 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_MVSAS is not set
-# CONFIG_SCSI_STEX is not set
-CONFIG_SCSI_SYM53C8XX_2=y
-CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=1
-CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16
-CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64
-CONFIG_SCSI_SYM53C8XX_MMIO=y
-# CONFIG_SCSI_IPR is not set
-CONFIG_SCSI_QLOGIC_1280=y
-# 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_DEBUG is not set
-# CONFIG_SCSI_SRP is not set
-# CONFIG_SCSI_DH is not set
-CONFIG_ATA=y
-CONFIG_ATA_NONSTANDARD=y
-CONFIG_ATA_ACPI=y
-CONFIG_SATA_PMP=y
-# CONFIG_SATA_AHCI is not set
-# CONFIG_SATA_SIL24 is not set
-CONFIG_ATA_SFF=y
-# CONFIG_SATA_SVW is not set
-CONFIG_ATA_PIIX=y
-# 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 is not set
-# CONFIG_SATA_SIS is not set
-# CONFIG_SATA_ULI is not set
-# CONFIG_SATA_VIA is not set
-CONFIG_SATA_VITESSE=y
-# CONFIG_SATA_INIC162X is not set
-# CONFIG_PATA_ACPI 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_NINJA32 is not set
-# CONFIG_PATA_NS87410 is not set
-# CONFIG_PATA_NS87415 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_SCH is not set
-CONFIG_MD=y
-CONFIG_BLK_DEV_MD=m
-CONFIG_MD_LINEAR=m
-CONFIG_MD_RAID0=m
-CONFIG_MD_RAID1=m
-# CONFIG_MD_RAID10 is not set
-# CONFIG_MD_RAID456 is not set
-CONFIG_MD_MULTIPATH=m
-# CONFIG_MD_FAULTY is not set
-CONFIG_BLK_DEV_DM=m
-# CONFIG_DM_DEBUG is not set
+CONFIG_CHR_DEV_ST=m
+CONFIG_CIFS=m
+CONFIG_CONNECTOR=y
+CONFIG_CPUSETS=y
+CONFIG_CRASH_DUMP=y
+CONFIG_CRC_T10DIF=y
+# CONFIG_CRYPTO_ANSI_CPRNG is not set
+CONFIG_CRYPTO_ECB=m
+CONFIG_CRYPTO_MD5=y
+CONFIG_CRYPTO_PCBC=m
+CONFIG_DEBUG_KERNEL=y
+CONFIG_DEBUG_MUTEXES=y
CONFIG_DM_CRYPT=m
-CONFIG_DM_SNAPSHOT=m
CONFIG_DM_MIRROR=m
-CONFIG_DM_ZERO=m
CONFIG_DM_MULTIPATH=m
-# CONFIG_DM_DELAY is not set
-# CONFIG_DM_UEVENT is not set
-CONFIG_FUSION=y
-CONFIG_FUSION_SPI=y
-CONFIG_FUSION_FC=m
-CONFIG_FUSION_SAS=y
-CONFIG_FUSION_MAX_SGE=128
-# CONFIG_FUSION_CTL is not set
-# CONFIG_FUSION_LOGGING is not set
-
-#
-# IEEE 1394 (FireWire) support
-#
-
-#
-# Enable only one of the two stacks, unless you know what you are doing
-#
-# CONFIG_FIREWIRE is not set
-# CONFIG_IEEE1394 is not set
-# CONFIG_I2O is not set
-CONFIG_NETDEVICES=y
-CONFIG_DUMMY=m
-# CONFIG_BONDING is not set
-# CONFIG_MACVLAN is not set
-# CONFIG_EQUALIZER is not set
-# CONFIG_TUN is not set
-# CONFIG_VETH is not set
-# CONFIG_NET_SB1000 is not set
-# CONFIG_ARCNET is not set
-CONFIG_PHYLIB=y
-
-#
-# MII PHY device drivers
-#
-# CONFIG_MARVELL_PHY is not set
-# CONFIG_DAVICOM_PHY is not set
-# CONFIG_QSEMI_PHY is not set
-# CONFIG_LXT_PHY is not set
-# CONFIG_CICADA_PHY is not set
-# CONFIG_VITESSE_PHY is not set
-# CONFIG_SMSC_PHY is not set
-# CONFIG_BROADCOM_PHY is not set
-# CONFIG_ICPLUS_PHY is not set
-# CONFIG_REALTEK_PHY is not set
-# CONFIG_FIXED_PHY is not set
-# CONFIG_MDIO_BITBANG is not set
-CONFIG_NET_ETHERNET=y
-CONFIG_MII=m
-# CONFIG_HAPPYMEAL is not set
-# CONFIG_SUNGEM is not set
-# CONFIG_CASSINI is not set
-# CONFIG_NET_VENDOR_3COM is not set
-CONFIG_NET_TULIP=y
-# CONFIG_DE2104X is not set
-CONFIG_TULIP=m
-# CONFIG_TULIP_MWI is not set
-# CONFIG_TULIP_MMIO is not set
-# CONFIG_TULIP_NAPI is not set
-# CONFIG_DE4X5 is not set
-# CONFIG_WINBOND_840 is not set
-# CONFIG_DM9102 is not set
-# CONFIG_ULI526X is not set
-# CONFIG_HP100 is not set
-# CONFIG_IBM_NEW_EMAC_ZMII is not set
-# CONFIG_IBM_NEW_EMAC_RGMII is not set
-# CONFIG_IBM_NEW_EMAC_TAH is not set
-# CONFIG_IBM_NEW_EMAC_EMAC4 is not set
-# CONFIG_IBM_NEW_EMAC_NO_FLOW_CTRL is not set
-# CONFIG_IBM_NEW_EMAC_MAL_CLR_ICINTSTAT is not set
-# CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set
-CONFIG_NET_PCI=y
-# CONFIG_PCNET32 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_EEPRO100=m
-CONFIG_E100=m
-# CONFIG_FEALNX is not set
-# CONFIG_NATSEMI is not set
-# CONFIG_NE2K_PCI is not set
-# CONFIG_8139CP is not set
-# CONFIG_8139TOO is not set
-# CONFIG_R6040 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 is not set
-# CONFIG_SC92031 is not set
-# CONFIG_ATL2 is not set
-CONFIG_NETDEV_1000=y
-# CONFIG_ACENIC is not set
-# CONFIG_DL2K is not set
-CONFIG_E1000=y
-# CONFIG_E1000E is not set
-# CONFIG_IP1000 is not set
-CONFIG_IGB=y
-# CONFIG_IGB_LRO 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_VIA_VELOCITY is not set
-CONFIG_TIGON3=y
-# CONFIG_BNX2 is not set
-# CONFIG_QLA3XXX is not set
-# CONFIG_ATL1 is not set
-# CONFIG_ATL1E is not set
-# CONFIG_JME is not set
-CONFIG_NETDEV_10000=y
-# CONFIG_CHELSIO_T1 is not set
-# CONFIG_CHELSIO_T3 is not set
-# CONFIG_ENIC is not set
-# CONFIG_IXGBE 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_NIU is not set
-# CONFIG_MLX4_EN is not set
-# CONFIG_MLX4_CORE is not set
-# CONFIG_TEHUTI is not set
-# CONFIG_BNX2X is not set
-# CONFIG_QLGE is not set
-# CONFIG_SFC is not set
-# CONFIG_TR is not set
-
-#
-# Wireless LAN
-#
-# CONFIG_WLAN_PRE80211 is not set
-# CONFIG_WLAN_80211 is not set
-# CONFIG_IWLWIFI_LEDS is not set
-
-#
-# USB Network Adapters
-#
-# CONFIG_USB_CATC is not set
-# CONFIG_USB_KAWETH is not set
-# CONFIG_USB_PEGASUS is not set
-# CONFIG_USB_RTL8150 is not set
-# CONFIG_USB_USBNET is not set
-# CONFIG_WAN is not set
-# CONFIG_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_NETCONSOLE=y
-# CONFIG_NETCONSOLE_DYNAMIC is not set
-CONFIG_NETPOLL=y
-# CONFIG_NETPOLL_TRAP is not set
-CONFIG_NET_POLL_CONTROLLER=y
-# CONFIG_ISDN is not set
-# CONFIG_PHONE is not set
-
-#
-# Input device support
-#
-CONFIG_INPUT=y
-# CONFIG_INPUT_FF_MEMLESS is not set
-# CONFIG_INPUT_POLLDEV is not set
-
-#
-# Userland interfaces
-#
-CONFIG_INPUT_MOUSEDEV=y
-CONFIG_INPUT_MOUSEDEV_PSAUX=y
-CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
-CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
-# CONFIG_INPUT_JOYDEV 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=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_ELANTECH is not set
-# CONFIG_MOUSE_PS2_TOUCHKIT is not set
-# CONFIG_MOUSE_SERIAL is not set
-# CONFIG_MOUSE_APPLETOUCH is not set
-# CONFIG_MOUSE_BCM5974 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
-
-#
-# Hardware I/O ports
-#
-CONFIG_SERIO=y
-CONFIG_SERIO_I8042=y
-# CONFIG_SERIO_SERPORT is not set
-# CONFIG_SERIO_PCIPS2 is not set
-CONFIG_SERIO_LIBPS2=y
-# CONFIG_SERIO_RAW is not set
-CONFIG_GAMEPORT=m
-# CONFIG_GAMEPORT_NS558 is not set
-# CONFIG_GAMEPORT_L4 is not set
-# CONFIG_GAMEPORT_EMU10K1 is not set
-# CONFIG_GAMEPORT_FM801 is not set
-
-#
-# Character devices
-#
-CONFIG_VT=y
-CONFIG_CONSOLE_TRANSLATIONS=y
-CONFIG_VT_CONSOLE=y
-CONFIG_HW_CONSOLE=y
-# CONFIG_VT_HW_CONSOLE_BINDING is not set
-CONFIG_DEVKMEM=y
-CONFIG_SERIAL_NONSTANDARD=y
-# CONFIG_COMPUTONE is not set
-# CONFIG_ROCKETPORT is not set
-# CONFIG_CYCLADES is not set
-# CONFIG_DIGIEPCA is not set
-# CONFIG_MOXA_INTELLIO is not set
-# CONFIG_MOXA_SMARTIO is not set
-# CONFIG_ISI is not set
-# CONFIG_SYNCLINKMP is not set
-# CONFIG_SYNCLINK_GT is not set
-# CONFIG_N_HDLC is not set
-# CONFIG_RISCOM8 is not set
-# CONFIG_SPECIALIX is not set
-# CONFIG_SX is not set
-# CONFIG_RIO is not set
-# CONFIG_STALDRV is not set
-# CONFIG_NOZOMI is not set
-CONFIG_SGI_SNSC=y
-CONFIG_SGI_TIOCX=y
-CONFIG_SGI_MBCS=m
-
-#
-# Serial drivers
-#
-CONFIG_SERIAL_8250=y
-CONFIG_SERIAL_8250_CONSOLE=y
-CONFIG_SERIAL_8250_PCI=y
-CONFIG_SERIAL_8250_PNP=y
-CONFIG_SERIAL_8250_NR_UARTS=6
-CONFIG_SERIAL_8250_RUNTIME_UARTS=4
-CONFIG_SERIAL_8250_EXTENDED=y
-CONFIG_SERIAL_8250_SHARE_IRQ=y
-# CONFIG_SERIAL_8250_DETECT_IRQ is not set
-# CONFIG_SERIAL_8250_RSA is not set
-
-#
-# Non-8250 serial port support
-#
-CONFIG_SERIAL_CORE=y
-CONFIG_SERIAL_CORE_CONSOLE=y
-CONFIG_SERIAL_SGI_L1_CONSOLE=y
-# CONFIG_SERIAL_JSM is not set
-CONFIG_SERIAL_SGI_IOC4=y
-# CONFIG_SERIAL_SGI_IOC3 is not set
-CONFIG_UNIX98_PTYS=y
-CONFIG_LEGACY_PTYS=y
-CONFIG_LEGACY_PTY_COUNT=256
-# CONFIG_IPMI_HANDLER is not set
-# CONFIG_HW_RANDOM is not set
-CONFIG_EFI_RTC=y
-# CONFIG_R3964 is not set
-# CONFIG_APPLICOM is not set
-CONFIG_RAW_DRIVER=m
-CONFIG_MAX_RAW_DEVS=256
-CONFIG_HPET=y
-CONFIG_HPET_MMAP=y
-# CONFIG_HANGCHECK_TIMER is not set
-CONFIG_MMTIMER=y
-# CONFIG_TCG_TPM is not set
-CONFIG_DEVPORT=y
-# CONFIG_I2C is not set
-# CONFIG_SPI is not set
-# CONFIG_W1 is not set
-CONFIG_POWER_SUPPLY=y
-# CONFIG_POWER_SUPPLY_DEBUG is not set
-# CONFIG_PDA_POWER is not set
-# CONFIG_BATTERY_DS2760 is not set
-CONFIG_HWMON=y
-# CONFIG_HWMON_VID is not set
-# CONFIG_SENSORS_I5K_AMB is not set
-# CONFIG_SENSORS_F71805F is not set
-# CONFIG_SENSORS_F71882FG 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_SENSORS_LIS3LV02D is not set
-# CONFIG_HWMON_DEBUG_CHIP is not set
-CONFIG_THERMAL=m
-# CONFIG_THERMAL_HWMON is not set
-# CONFIG_WATCHDOG is not set
-CONFIG_SSB_POSSIBLE=y
-
-#
-# Sonics Silicon Backplane
-#
-# CONFIG_SSB is not set
-
-#
-# Multifunction device drivers
-#
-# CONFIG_MFD_CORE is not set
-# CONFIG_MFD_SM501 is not set
-# CONFIG_HTC_PASIC3 is not set
-# CONFIG_MFD_TMIO is not set
-# CONFIG_REGULATOR is not set
-
-#
-# Multimedia devices
-#
-
-#
-# Multimedia core support
-#
-# CONFIG_VIDEO_DEV is not set
-# CONFIG_DVB_CORE is not set
-# CONFIG_VIDEO_MEDIA is not set
-
-#
-# Multimedia drivers
-#
-CONFIG_DAB=y
-# CONFIG_USB_DABUSB is not set
-
-#
-# Graphics support
-#
-CONFIG_AGP=m
-CONFIG_AGP_I460=m
-CONFIG_AGP_HP_ZX1=m
-CONFIG_AGP_SGI_TIOCA=m
+CONFIG_DM_SNAPSHOT=m
+CONFIG_DM_ZERO=m
CONFIG_DRM=m
-CONFIG_DRM_TDFX=m
+CONFIG_DRM_MGA=m
CONFIG_DRM_R128=m
CONFIG_DRM_RADEON=m
-CONFIG_DRM_MGA=m
CONFIG_DRM_SIS=m
-# CONFIG_DRM_VIA is not set
-# CONFIG_DRM_SAVAGE is not set
-# CONFIG_VGASTATE is not set
-# CONFIG_VIDEO_OUTPUT_CONTROL is not set
-# CONFIG_FB is not set
-# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
-
-#
-# Display device support
-#
-# CONFIG_DISPLAY_SUPPORT is not set
-
-#
-# Console display driver support
-#
-CONFIG_VGA_CONSOLE=y
-# CONFIG_VGACON_SOFT_SCROLLBACK is not set
-CONFIG_DUMMY_CONSOLE=y
-CONFIG_SOUND=m
-CONFIG_SOUND_OSS_CORE=y
-CONFIG_SND=m
-CONFIG_SND_TIMER=m
-CONFIG_SND_PCM=m
-CONFIG_SND_HWDEP=m
-CONFIG_SND_RAWMIDI=m
-CONFIG_SND_SEQUENCER=m
-CONFIG_SND_SEQ_DUMMY=m
-CONFIG_SND_OSSEMUL=y
-CONFIG_SND_MIXER_OSS=m
-CONFIG_SND_PCM_OSS=m
-CONFIG_SND_PCM_OSS_PLUGINS=y
-CONFIG_SND_SEQUENCER_OSS=y
-# CONFIG_SND_DYNAMIC_MINORS is not set
-CONFIG_SND_SUPPORT_OLD_API=y
-CONFIG_SND_VERBOSE_PROCFS=y
-CONFIG_SND_VERBOSE_PRINTK=y
-# CONFIG_SND_DEBUG is not set
-CONFIG_SND_VMASTER=y
-CONFIG_SND_MPU401_UART=m
-CONFIG_SND_OPL3_LIB=m
-CONFIG_SND_AC97_CODEC=m
-CONFIG_SND_DRIVERS=y
-CONFIG_SND_DUMMY=m
-CONFIG_SND_VIRMIDI=m
-CONFIG_SND_MTPAV=m
-CONFIG_SND_SERIAL_U16550=m
-CONFIG_SND_MPU401=m
-# CONFIG_SND_AC97_POWER_SAVE is not set
-CONFIG_SND_PCI=y
-# CONFIG_SND_AD1889 is not set
-# CONFIG_SND_ALS300 is not set
-# CONFIG_SND_ALI5451 is not set
-# CONFIG_SND_ATIIXP is not set
-# CONFIG_SND_ATIIXP_MODEM is not set
-# CONFIG_SND_AU8810 is not set
-# CONFIG_SND_AU8820 is not set
-# CONFIG_SND_AU8830 is not set
-# CONFIG_SND_AW2 is not set
-# CONFIG_SND_AZT3328 is not set
-# CONFIG_SND_BT87X is not set
-# CONFIG_SND_CA0106 is not set
-# CONFIG_SND_CMIPCI is not set
-# CONFIG_SND_OXYGEN is not set
-CONFIG_SND_CS4281=m
-CONFIG_SND_CS46XX=m
-CONFIG_SND_CS46XX_NEW_DSP=y
-# CONFIG_SND_DARLA20 is not set
-# CONFIG_SND_GINA20 is not set
-# CONFIG_SND_LAYLA20 is not set
-# CONFIG_SND_DARLA24 is not set
-# CONFIG_SND_GINA24 is not set
-# CONFIG_SND_LAYLA24 is not set
-# CONFIG_SND_MONA is not set
-# CONFIG_SND_MIA is not set
-# CONFIG_SND_ECHO3G is not set
-# CONFIG_SND_INDIGO is not set
-# CONFIG_SND_INDIGOIO is not set
-# CONFIG_SND_INDIGODJ is not set
-CONFIG_SND_EMU10K1=m
-# CONFIG_SND_EMU10K1X is not set
-# CONFIG_SND_ENS1370 is not set
-# CONFIG_SND_ENS1371 is not set
-# CONFIG_SND_ES1938 is not set
-# CONFIG_SND_ES1968 is not set
-CONFIG_SND_FM801=m
-# CONFIG_SND_HDA_INTEL is not set
-# CONFIG_SND_HDSP is not set
-# CONFIG_SND_HDSPM is not set
-# CONFIG_SND_HIFIER is not set
-# CONFIG_SND_ICE1712 is not set
-# CONFIG_SND_ICE1724 is not set
-# CONFIG_SND_INTEL8X0 is not set
-# CONFIG_SND_INTEL8X0M is not set
-# CONFIG_SND_KORG1212 is not set
-# CONFIG_SND_MAESTRO3 is not set
-# CONFIG_SND_MIXART is not set
-# CONFIG_SND_NM256 is not set
-# CONFIG_SND_PCXHR is not set
-# CONFIG_SND_RIPTIDE is not set
-# CONFIG_SND_RME32 is not set
-# CONFIG_SND_RME96 is not set
-# CONFIG_SND_RME9652 is not set
-# CONFIG_SND_SONICVIBES is not set
-# CONFIG_SND_TRIDENT is not set
-# CONFIG_SND_VIA82XX is not set
-# CONFIG_SND_VIA82XX_MODEM is not set
-# CONFIG_SND_VIRTUOSO is not set
-# CONFIG_SND_VX222 is not set
-# CONFIG_SND_YMFPCI is not set
-CONFIG_SND_USB=y
-# CONFIG_SND_USB_AUDIO is not set
-# CONFIG_SND_USB_CAIAQ is not set
-# CONFIG_SND_SOC is not set
-# CONFIG_SOUND_PRIME is not set
-CONFIG_AC97_BUS=m
-CONFIG_HID_SUPPORT=y
-CONFIG_HID=y
-# CONFIG_HID_DEBUG is not set
-# CONFIG_HIDRAW is not set
-
-#
-# USB Input Devices
-#
-CONFIG_USB_HID=m
-# CONFIG_HID_PID 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
-
-#
-# Special HID drivers
-#
-CONFIG_HID_COMPAT=y
-CONFIG_HID_A4TECH=m
-CONFIG_HID_APPLE=m
-CONFIG_HID_BELKIN=m
-CONFIG_HID_BRIGHT=m
-CONFIG_HID_CHERRY=m
-CONFIG_HID_CHICONY=m
-CONFIG_HID_CYPRESS=m
-CONFIG_HID_DELL=m
-CONFIG_HID_EZKEY=m
+CONFIG_DRM_TDFX=m
+CONFIG_DUMMY=m
+CONFIG_E1000=y
+CONFIG_E100=m
+CONFIG_EFI_PARTITION=y
+CONFIG_EFI_RTC=y
+CONFIG_EFI_VARS=y
+CONFIG_EXPERIMENTAL=y
+CONFIG_EXT2_FS_POSIX_ACL=y
+CONFIG_EXT2_FS_SECURITY=y
+CONFIG_EXT2_FS_XATTR=y
+CONFIG_EXT2_FS=y
+CONFIG_EXT3_FS_POSIX_ACL=y
+CONFIG_EXT3_FS_SECURITY=y
+CONFIG_EXT3_FS=y
+CONFIG_FUSION_FC=m
+CONFIG_FUSION_SAS=y
+CONFIG_FUSION_SPI=y
+CONFIG_FUSION=y
+CONFIG_GAMEPORT=m
CONFIG_HID_GYRATION=m
-CONFIG_HID_LOGITECH=m
-# CONFIG_LOGITECH_FF is not set
-# CONFIG_LOGIRUMBLEPAD2_FF is not set
-CONFIG_HID_MICROSOFT=m
-CONFIG_HID_MONTEREY=m
CONFIG_HID_PANTHERLORD=m
-# CONFIG_PANTHERLORD_FF is not set
CONFIG_HID_PETALYNX=m
CONFIG_HID_SAMSUNG=m
CONFIG_HID_SONY=m
CONFIG_HID_SUNPLUS=m
-# CONFIG_THRUSTMASTER_FF is not set
-# CONFIG_ZEROPLUS_FF 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
-CONFIG_USB=m
-# CONFIG_USB_DEBUG is not set
-# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set
-
-#
-# 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_OTG is not set
-CONFIG_USB_MON=y
-# CONFIG_USB_WUSB is not set
-# CONFIG_USB_WUSB_CBAF is not set
-
-#
-# USB Host Controller Drivers
-#
-# CONFIG_USB_C67X00_HCD is not set
-CONFIG_USB_EHCI_HCD=m
-# CONFIG_USB_EHCI_ROOT_HUB_TT is not set
-# CONFIG_USB_EHCI_TT_NEWSCHED is not set
-# CONFIG_USB_ISP116X_HCD is not set
-# CONFIG_USB_ISP1760_HCD is not set
-CONFIG_USB_OHCI_HCD=m
-# 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_UHCI_HCD=m
-# CONFIG_USB_SL811_HCD is not set
-# CONFIG_USB_R8A66597_HCD is not set
-# CONFIG_USB_WHCI_HCD is not set
-# CONFIG_USB_HWA_HCD is not set
-
-#
-# Enable Host or Gadget support to see Inventra options
-#
-
-#
-# USB Device Class drivers
-#
-# CONFIG_USB_ACM is not set
-# CONFIG_USB_PRINTER is not set
-# CONFIG_USB_WDM is not set
-# CONFIG_USB_TMC is not set
-
-#
-# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may also be needed;
-#
-
-#
-# see USB_STORAGE Help for more information
-#
-CONFIG_USB_STORAGE=m
-# CONFIG_USB_STORAGE_DEBUG is not set
-# CONFIG_USB_STORAGE_DATAFAB is not set
-# CONFIG_USB_STORAGE_FREECOM is not set
-# CONFIG_USB_STORAGE_ISD200 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_ONETOUCH is not set
-# CONFIG_USB_STORAGE_KARMA is not set
-# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set
-# CONFIG_USB_LIBUSUAL is not set
-
-#
-# USB Imaging devices
-#
-# CONFIG_USB_MDC800 is not set
-# CONFIG_USB_MICROTEK is not set
-
-#
-# USB port drivers
-#
-# CONFIG_USB_SERIAL is not set
-
-#
-# USB Miscellaneous drivers
-#
-# CONFIG_USB_EMI62 is not set
-# CONFIG_USB_EMI26 is not set
-# CONFIG_USB_ADUTUX is not set
-# CONFIG_USB_SEVSEG is not set
-# CONFIG_USB_RIO500 is not set
-# CONFIG_USB_LEGOTOWER is not set
-# CONFIG_USB_LCD is not set
-# CONFIG_USB_BERRY_CHARGE is not set
-# CONFIG_USB_LED is not set
-# CONFIG_USB_CYPRESS_CY7C63 is not set
-# CONFIG_USB_CYTHERM is not set
-# CONFIG_USB_PHIDGET is not set
-# CONFIG_USB_IDMOUSE is not set
-# CONFIG_USB_FTDI_ELAN is not set
-# CONFIG_USB_APPLEDISPLAY is not set
-# CONFIG_USB_SISUSBVGA is not set
-# CONFIG_USB_LD is not set
-# CONFIG_USB_TRANCEVIBRATOR is not set
-# CONFIG_USB_IOWARRIOR is not set
-# CONFIG_USB_TEST is not set
-# CONFIG_USB_ISIGHTFW is not set
-# CONFIG_USB_VST is not set
-# CONFIG_USB_GADGET is not set
-# CONFIG_UWB is not set
-# CONFIG_MMC is not set
-# CONFIG_MEMSTICK is not set
-# CONFIG_NEW_LEDS is not set
-# CONFIG_ACCESSIBILITY is not set
+CONFIG_HOTPLUG_CPU=y
+CONFIG_HOTPLUG_PCI_ACPI=m
+CONFIG_HOTPLUG_PCI=m
+CONFIG_HPET=y
+CONFIG_HUGETLBFS=y
+# CONFIG_HW_RANDOM is not set
+CONFIG_IA64_CYCLONE=y
+CONFIG_IA64_MCA_RECOVERY=y
+CONFIG_IA64_PAGE_SIZE_64KB=y
+CONFIG_IA64_PALINFO=y
+CONFIG_IDE=y
+CONFIG_IGB=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_IKCONFIG=y
+CONFIG_INET=y
+CONFIG_INFINIBAND_IPOIB=m
CONFIG_INFINIBAND=m
-# CONFIG_INFINIBAND_USER_MAD is not set
-# CONFIG_INFINIBAND_USER_ACCESS is not set
-CONFIG_INFINIBAND_ADDR_TRANS=y
CONFIG_INFINIBAND_MTHCA=m
-CONFIG_INFINIBAND_MTHCA_DEBUG=y
-# CONFIG_INFINIBAND_IPATH is not set
-# CONFIG_INFINIBAND_AMSO1100 is not set
-# CONFIG_MLX4_INFINIBAND is not set
-# CONFIG_INFINIBAND_NES is not set
-CONFIG_INFINIBAND_IPOIB=m
-# CONFIG_INFINIBAND_IPOIB_CM is not set
-CONFIG_INFINIBAND_IPOIB_DEBUG=y
-# CONFIG_INFINIBAND_IPOIB_DEBUG_DATA is not set
-# CONFIG_INFINIBAND_SRP is not set
-# CONFIG_INFINIBAND_ISER is not set
-# CONFIG_RTC_CLASS is not set
-# CONFIG_DMADEVICES is not set
-# CONFIG_UIO is not set
-# CONFIG_STAGING is not set
-CONFIG_STAGING_EXCLUDE_BUILD=y
-
-#
-# HP Simulator drivers
-#
-# CONFIG_HP_SIMETH is not set
-# CONFIG_HP_SIMSERIAL is not set
-# CONFIG_HP_SIMSCSI is not set
-CONFIG_MSPEC=m
-
-#
-# File systems
-#
-CONFIG_EXT2_FS=y
-CONFIG_EXT2_FS_XATTR=y
-CONFIG_EXT2_FS_POSIX_ACL=y
-CONFIG_EXT2_FS_SECURITY=y
-# CONFIG_EXT2_FS_XIP is not set
-CONFIG_EXT3_FS=y
-CONFIG_EXT3_FS_XATTR=y
-CONFIG_EXT3_FS_POSIX_ACL=y
-CONFIG_EXT3_FS_SECURITY=y
-# CONFIG_EXT4_FS is not set
-CONFIG_JBD=y
-CONFIG_FS_MBCACHE=y
-CONFIG_REISERFS_FS=y
-# CONFIG_REISERFS_CHECK is not set
-# CONFIG_REISERFS_PROC_INFO is not set
-CONFIG_REISERFS_FS_XATTR=y
-CONFIG_REISERFS_FS_POSIX_ACL=y
-CONFIG_REISERFS_FS_SECURITY=y
-# CONFIG_JFS_FS is not set
-CONFIG_FS_POSIX_ACL=y
-CONFIG_FILE_LOCKING=y
-CONFIG_XFS_FS=y
-# CONFIG_XFS_QUOTA is not set
-# CONFIG_XFS_POSIX_ACL is not set
-# CONFIG_XFS_RT is not set
-# CONFIG_XFS_DEBUG is not set
-# CONFIG_GFS2_FS is not set
-# CONFIG_OCFS2_FS is not set
-CONFIG_DNOTIFY=y
CONFIG_INOTIFY=y
-CONFIG_INOTIFY_USER=y
-# CONFIG_QUOTA is not set
-CONFIG_AUTOFS_FS=m
-CONFIG_AUTOFS4_FS=m
-# CONFIG_FUSE_FS is not set
-
-#
-# CD-ROM/DVD Filesystems
-#
+CONFIG_IP_MULTICAST=y
+# CONFIG_IPV6 is not set
CONFIG_ISO9660_FS=m
CONFIG_JOLIET=y
-# CONFIG_ZISOFS is not set
-CONFIG_UDF_FS=m
-CONFIG_UDF_NLS=y
-
-#
-# DOS/FAT/NT Filesystems
-#
-CONFIG_FAT_FS=y
-# CONFIG_MSDOS_FS is not set
-CONFIG_VFAT_FS=y
-CONFIG_FAT_DEFAULT_CODEPAGE=437
-CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
-CONFIG_NTFS_FS=m
-# CONFIG_NTFS_DEBUG is not set
-# CONFIG_NTFS_RW is not set
-
-#
-# Pseudo filesystems
-#
-CONFIG_PROC_FS=y
-CONFIG_PROC_KCORE=y
-CONFIG_PROC_VMCORE=y
-CONFIG_PROC_SYSCTL=y
-CONFIG_PROC_PAGE_MONITOR=y
-CONFIG_SYSFS=y
-CONFIG_TMPFS=y
-# CONFIG_TMPFS_POSIX_ACL is not set
-CONFIG_HUGETLBFS=y
-CONFIG_HUGETLB_PAGE=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_MINIX_FS is not set
-# CONFIG_OMFS_FS is not set
-# CONFIG_HPFS_FS is not set
-# CONFIG_QNX4FS_FS is not set
-# CONFIG_ROMFS_FS is not set
-# CONFIG_SYSV_FS is not set
-# CONFIG_UFS_FS is not set
-CONFIG_NETWORK_FILESYSTEMS=y
+CONFIG_KALLSYMS_ALL=y
+CONFIG_KEXEC=y
+CONFIG_LOG_BUF_SHIFT=20
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_MCKINLEY=y
+CONFIG_MD_LINEAR=m
+CONFIG_MD_MULTIPATH=m
+CONFIG_MD_RAID0=m
+CONFIG_MD_RAID1=m
+CONFIG_MD=y
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODVERSIONS=y
+CONFIG_MSPEC=m
+CONFIG_NETCONSOLE=y
+CONFIG_NETDEVICES=y
+CONFIG_NET_ETHERNET=y
+CONFIG_NET_PCI=y
+CONFIG_NET_TULIP=y
+CONFIG_NFSD=m
+CONFIG_NFSD_V4=y
CONFIG_NFS_FS=m
CONFIG_NFS_V3=y
-# CONFIG_NFS_V3_ACL is not set
CONFIG_NFS_V4=y
-CONFIG_NFSD=m
-CONFIG_NFSD_V3=y
-# CONFIG_NFSD_V3_ACL is not set
-CONFIG_NFSD_V4=y
-CONFIG_LOCKD=m
-CONFIG_LOCKD_V4=y
-CONFIG_EXPORTFS=m
-CONFIG_NFS_COMMON=y
-CONFIG_SUNRPC=m
-CONFIG_SUNRPC_GSS=m
-CONFIG_SUNRPC_XPRT_RDMA=m
-# CONFIG_SUNRPC_REGISTER_V4 is not set
-CONFIG_RPCSEC_GSS_KRB5=m
-# CONFIG_RPCSEC_GSS_SPKM3 is not set
-CONFIG_SMB_FS=m
-CONFIG_SMB_NLS_DEFAULT=y
-CONFIG_SMB_NLS_REMOTE="cp437"
-CONFIG_CIFS=m
-# CONFIG_CIFS_STATS is not set
-# CONFIG_CIFS_WEAK_PW_HASH is not set
-# CONFIG_CIFS_XATTR is not set
-# CONFIG_CIFS_DEBUG2 is not set
-# CONFIG_CIFS_EXPERIMENTAL is not set
-# CONFIG_NCP_FS is not set
-# CONFIG_CODA_FS is not set
-# CONFIG_AFS_FS is not set
-
-#
-# Partition Types
-#
-CONFIG_PARTITION_ADVANCED=y
-# CONFIG_ACORN_PARTITION is not set
-# CONFIG_OSF_PARTITION is not set
-# CONFIG_AMIGA_PARTITION is not set
-# CONFIG_ATARI_PARTITION is not set
-# CONFIG_MAC_PARTITION is not set
-CONFIG_MSDOS_PARTITION=y
-# CONFIG_BSD_DISKLABEL is not set
-# CONFIG_MINIX_SUBPARTITION is not set
-# CONFIG_SOLARIS_X86_PARTITION is not set
-# CONFIG_UNIXWARE_DISKLABEL is not set
-# CONFIG_LDM_PARTITION is not set
-CONFIG_SGI_PARTITION=y
-# CONFIG_ULTRIX_PARTITION is not set
-# CONFIG_SUN_PARTITION is not set
-# CONFIG_KARMA_PARTITION is not set
-CONFIG_EFI_PARTITION=y
-# CONFIG_SYSV68_PARTITION is not set
-CONFIG_NLS=y
-CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_1250=m
+CONFIG_NLS_CODEPAGE_1251=m
CONFIG_NLS_CODEPAGE_437=y
CONFIG_NLS_CODEPAGE_737=m
CONFIG_NLS_CODEPAGE_775=m
@@ -1465,15 +143,14 @@ CONFIG_NLS_CODEPAGE_864=m
CONFIG_NLS_CODEPAGE_865=m
CONFIG_NLS_CODEPAGE_866=m
CONFIG_NLS_CODEPAGE_869=m
-CONFIG_NLS_CODEPAGE_936=m
-CONFIG_NLS_CODEPAGE_950=m
+CONFIG_NLS_CODEPAGE_874=m
CONFIG_NLS_CODEPAGE_932=m
+CONFIG_NLS_CODEPAGE_936=m
CONFIG_NLS_CODEPAGE_949=m
-CONFIG_NLS_CODEPAGE_874=m
-CONFIG_NLS_ISO8859_8=m
-CONFIG_NLS_CODEPAGE_1250=m
-CONFIG_NLS_CODEPAGE_1251=m
-# CONFIG_NLS_ASCII is not set
+CONFIG_NLS_CODEPAGE_950=m
+CONFIG_NLS_ISO8859_13=m
+CONFIG_NLS_ISO8859_14=m
+CONFIG_NLS_ISO8859_15=m
CONFIG_NLS_ISO8859_1=y
CONFIG_NLS_ISO8859_2=m
CONFIG_NLS_ISO8859_3=m
@@ -1481,194 +158,79 @@ CONFIG_NLS_ISO8859_4=m
CONFIG_NLS_ISO8859_5=m
CONFIG_NLS_ISO8859_6=m
CONFIG_NLS_ISO8859_7=m
+CONFIG_NLS_ISO8859_8=m
CONFIG_NLS_ISO8859_9=m
-CONFIG_NLS_ISO8859_13=m
-CONFIG_NLS_ISO8859_14=m
-CONFIG_NLS_ISO8859_15=m
CONFIG_NLS_KOI8_R=m
CONFIG_NLS_KOI8_U=m
CONFIG_NLS_UTF8=m
-# CONFIG_DLM is not set
-
-#
-# Kernel hacking
-#
-# CONFIG_PRINTK_TIME is not set
-CONFIG_ENABLE_WARN_DEPRECATED=y
-CONFIG_ENABLE_MUST_CHECK=y
-CONFIG_FRAME_WARN=2048
-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=y
-# CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set
-CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=0
-CONFIG_SCHED_DEBUG=y
-# CONFIG_SCHEDSTATS is not set
-# CONFIG_TIMER_STATS is not set
-# CONFIG_DEBUG_OBJECTS is not set
-# CONFIG_SLUB_DEBUG_ON is not set
-# CONFIG_SLUB_STATS 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=y
-# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
-# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
-# CONFIG_DEBUG_KOBJECT is not set
-# CONFIG_DEBUG_INFO is not set
-# CONFIG_DEBUG_VM is not set
-# CONFIG_DEBUG_WRITECOUNT is not set
-CONFIG_DEBUG_MEMORY_INIT=y
-# CONFIG_DEBUG_LIST is not set
-# CONFIG_DEBUG_SG is not set
-# CONFIG_BOOT_PRINTK_DELAY is not set
-# CONFIG_RCU_TORTURE_TEST is not set
+CONFIG_NTFS_FS=m
+CONFIG_PACKET=y
+CONFIG_PARTITION_ADVANCED=y
+CONFIG_PERFMON=y
+# CONFIG_PNP_DEBUG_MESSAGES is not set
+CONFIG_POSIX_MQUEUE=y
+CONFIG_PROC_KCORE=y
+CONFIG_RAW_DRIVER=m
# CONFIG_RCU_CPU_STALL_DETECTOR is not set
-# CONFIG_BACKTRACE_SELF_TEST is not set
-# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
-# CONFIG_FAULT_INJECTION is not set
+CONFIG_REISERFS_FS_POSIX_ACL=y
+CONFIG_REISERFS_FS_SECURITY=y
+CONFIG_REISERFS_FS_XATTR=y
+CONFIG_REISERFS_FS=y
+CONFIG_SATA_VITESSE=y
+CONFIG_SCSI_FC_ATTRS=y
+CONFIG_SCSI_QLOGIC_1280=y
+CONFIG_SCSI_SYM53C8XX_2=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_EXTENDED=y
+CONFIG_SERIAL_8250_NR_UARTS=6
+CONFIG_SERIAL_8250_SHARE_IRQ=y
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_NONSTANDARD=y
+CONFIG_SERIAL_SGI_IOC4=y
+CONFIG_SERIAL_SGI_L1_CONSOLE=y
+# CONFIG_SERIO_SERPORT is not set
+CONFIG_SGI_IOC4=y
+CONFIG_SGI_MBCS=m
+CONFIG_SGI_PARTITION=y
+CONFIG_SGI_SNSC=y
+CONFIG_SGI_TIOCX=y
+CONFIG_SGI_XP=m
+CONFIG_SMB_FS=m
+CONFIG_SMB_NLS_DEFAULT=y
+CONFIG_SMP=y
+CONFIG_SND_CS4281=m
+CONFIG_SND_CS46XX=m
+CONFIG_SND_DUMMY=m
+CONFIG_SND_EMU10K1=m
+CONFIG_SND_FM801=m
+CONFIG_SND=m
+CONFIG_SND_MIXER_OSS=m
+CONFIG_SND_MPU401=m
+CONFIG_SND_MTPAV=m
+CONFIG_SND_PCM_OSS=m
+CONFIG_SND_SEQ_DUMMY=m
+CONFIG_SND_SEQUENCER=m
+CONFIG_SND_SEQUENCER_OSS=y
+CONFIG_SND_SERIAL_U16550=m
+CONFIG_SND_VERBOSE_PRINTK=y
+CONFIG_SND_VIRMIDI=m
+CONFIG_SOUND=m
+CONFIG_SYN_COOKIES=y
CONFIG_SYSCTL_SYSCALL_CHECK=y
-
-#
-# Tracers
-#
-# CONFIG_SCHED_TRACER is not set
-# CONFIG_CONTEXT_SWITCH_TRACER is not set
-# CONFIG_BOOT_TRACER is not set
-# CONFIG_DYNAMIC_PRINTK_DEBUG is not set
-# CONFIG_SAMPLES is not set
-CONFIG_IA64_GRANULE_16MB=y
-# CONFIG_IA64_GRANULE_64MB is not set
-# CONFIG_IA64_PRINT_HAZARDS is not set
-# 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
-# CONFIG_SECURITYFS is not set
-# CONFIG_SECURITY_FILE_CAPABILITIES is not set
-CONFIG_CRYPTO=y
-
-#
-# Crypto core or helper
-#
-# CONFIG_CRYPTO_FIPS is not set
-CONFIG_CRYPTO_ALGAPI=y
-CONFIG_CRYPTO_AEAD=m
-CONFIG_CRYPTO_BLKCIPHER=m
-CONFIG_CRYPTO_HASH=m
-CONFIG_CRYPTO_RNG=m
-CONFIG_CRYPTO_MANAGER=m
-# CONFIG_CRYPTO_GF128MUL is not set
-# CONFIG_CRYPTO_NULL is not set
-# CONFIG_CRYPTO_CRYPTD is not set
-# CONFIG_CRYPTO_AUTHENC is not set
-# CONFIG_CRYPTO_TEST is not set
-
-#
-# Authenticated Encryption with Associated Data
-#
-# CONFIG_CRYPTO_CCM is not set
-# CONFIG_CRYPTO_GCM is not set
-# CONFIG_CRYPTO_SEQIV is not set
-
-#
-# Block modes
-#
-CONFIG_CRYPTO_CBC=m
-# CONFIG_CRYPTO_CTR is not set
-# CONFIG_CRYPTO_CTS is not set
-CONFIG_CRYPTO_ECB=m
-# CONFIG_CRYPTO_LRW is not set
-CONFIG_CRYPTO_PCBC=m
-# CONFIG_CRYPTO_XTS is not set
-
-#
-# Hash modes
-#
-# CONFIG_CRYPTO_HMAC is not set
-# CONFIG_CRYPTO_XCBC is not set
-
-#
-# Digest
-#
-# CONFIG_CRYPTO_CRC32C is not set
-# CONFIG_CRYPTO_MD4 is not set
-CONFIG_CRYPTO_MD5=y
-# CONFIG_CRYPTO_MICHAEL_MIC is not set
-# CONFIG_CRYPTO_RMD128 is not set
-# CONFIG_CRYPTO_RMD160 is not set
-# CONFIG_CRYPTO_RMD256 is not set
-# CONFIG_CRYPTO_RMD320 is not set
-# CONFIG_CRYPTO_SHA1 is not set
-# CONFIG_CRYPTO_SHA256 is not set
-# CONFIG_CRYPTO_SHA512 is not set
-# CONFIG_CRYPTO_TGR192 is not set
-# CONFIG_CRYPTO_WP512 is not set
-
-#
-# Ciphers
-#
-# CONFIG_CRYPTO_AES is not set
-# CONFIG_CRYPTO_ANUBIS is not set
-# CONFIG_CRYPTO_ARC4 is not set
-# CONFIG_CRYPTO_BLOWFISH is not set
-# CONFIG_CRYPTO_CAMELLIA is not set
-# CONFIG_CRYPTO_CAST5 is not set
-# CONFIG_CRYPTO_CAST6 is not set
-CONFIG_CRYPTO_DES=m
-# CONFIG_CRYPTO_FCRYPT is not set
-# CONFIG_CRYPTO_KHAZAD is not set
-# CONFIG_CRYPTO_SALSA20 is not set
-# CONFIG_CRYPTO_SEED is not set
-# CONFIG_CRYPTO_SERPENT is not set
-# CONFIG_CRYPTO_TEA is not set
-# CONFIG_CRYPTO_TWOFISH is not set
-
-#
-# Compression
-#
-# CONFIG_CRYPTO_DEFLATE is not set
-# CONFIG_CRYPTO_LZO is not set
-
-#
-# Random Number Generation
-#
-# CONFIG_CRYPTO_ANSI_CPRNG is not set
-CONFIG_CRYPTO_HW=y
-# CONFIG_CRYPTO_DEV_HIFN_795X is not set
-CONFIG_HAVE_KVM=y
-CONFIG_VIRTUALIZATION=y
-# CONFIG_KVM is not set
-# CONFIG_VIRTIO_PCI is not set
-# CONFIG_VIRTIO_BALLOON is not set
-
-#
-# Library routines
-#
-CONFIG_BITREVERSE=y
-# CONFIG_CRC_CCITT is not set
-# CONFIG_CRC16 is not set
-CONFIG_CRC_T10DIF=y
-CONFIG_CRC_ITU_T=m
-CONFIG_CRC32=y
-# CONFIG_CRC7 is not set
-# CONFIG_LIBCRC32C is not set
-CONFIG_GENERIC_ALLOCATOR=y
-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
-CONFIG_IRQ_PER_CPU=y
+CONFIG_SYSFS_DEPRECATED_V2=y
+CONFIG_SYSVIPC=y
+CONFIG_TIGON3=y
+CONFIG_TMPFS=y
+CONFIG_TULIP=m
+CONFIG_UDF_FS=m
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_UNIX=y
+CONFIG_USB_DEVICEFS=y
+CONFIG_USB_EHCI_HCD=m
+CONFIG_USB=m
+CONFIG_USB_MON=m
+CONFIG_USB_OHCI_HCD=m
+CONFIG_USB_STORAGE=m
+CONFIG_USB_UHCI_HCD=m
+CONFIG_VFAT_FS=y
+CONFIG_XFS_FS=y
diff --git a/arch/ia64/configs/gensparse_defconfig b/arch/ia64/configs/gensparse_defconfig
index 2dc185b0f9a..18989a08414 100644
--- a/arch/ia64/configs/gensparse_defconfig
+++ b/arch/ia64/configs/gensparse_defconfig
@@ -1,1267 +1,110 @@
-#
-# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.16-rc5
-# Thu Mar 2 16:39:10 2006
-#
-
-#
-# Code maturity level options
-#
-CONFIG_EXPERIMENTAL=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_POSIX_MQUEUE=y
-# CONFIG_BSD_PROCESS_ACCT is not set
-CONFIG_SYSCTL=y
-# CONFIG_AUDIT is not set
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-# CONFIG_CPUSETS is not set
-CONFIG_INITRAMFS_SOURCE=""
-CONFIG_CC_OPTIMIZE_FOR_SIZE=y
-# CONFIG_EMBEDDED is not set
-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_EPOLL=y
-CONFIG_SHMEM=y
-CONFIG_CC_ALIGN_FUNCTIONS=0
-CONFIG_CC_ALIGN_LABELS=0
-CONFIG_CC_ALIGN_LOOPS=0
-CONFIG_CC_ALIGN_JUMPS=0
-CONFIG_SLUB=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
-CONFIG_OBSOLETE_MODPARM=y
-CONFIG_MODVERSIONS=y
-# CONFIG_MODULE_SRCVERSION_ALL is not set
-CONFIG_KMOD=y
-CONFIG_STOP_MACHINE=y
-
-#
-# Block layer
-#
-
-#
-# IO Schedulers
-#
-CONFIG_IOSCHED_NOOP=y
-CONFIG_IOSCHED_AS=y
-CONFIG_IOSCHED_DEADLINE=y
-CONFIG_IOSCHED_CFQ=y
-CONFIG_DEFAULT_AS=y
-# CONFIG_DEFAULT_DEADLINE is not set
-# CONFIG_DEFAULT_CFQ is not set
-# CONFIG_DEFAULT_NOOP is not set
-CONFIG_DEFAULT_IOSCHED="anticipatory"
-
-#
-# Processor type and features
-#
-CONFIG_IA64=y
-CONFIG_64BIT=y
-CONFIG_MMU=y
-CONFIG_SWIOTLB=y
-CONFIG_RWSEM_XCHGADD_ALGORITHM=y
-CONFIG_GENERIC_CALIBRATE_DELAY=y
-CONFIG_GENERIC_TIME=y
-CONFIG_EFI=y
-CONFIG_GENERIC_IOMAP=y
-CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y
-CONFIG_DMA_IS_DMA32=y
-CONFIG_IA64_GENERIC=y
-# CONFIG_IA64_DIG is not set
-# CONFIG_IA64_HP_ZX1 is not set
-# CONFIG_IA64_HP_ZX1_SWIOTLB is not set
-# CONFIG_IA64_SGI_SN2 is not set
-# CONFIG_IA64_HP_SIM is not set
-# CONFIG_ITANIUM is not set
-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_PGTABLE_3=y
-# CONFIG_PGTABLE_4 is not set
-# CONFIG_HZ_100 is not set
-CONFIG_HZ_250=y
-# CONFIG_HZ_1000 is not set
-CONFIG_HZ=250
-CONFIG_IA64_L1_CACHE_SHIFT=7
-CONFIG_IA64_CYCLONE=y
-CONFIG_IOSAPIC=y
-# CONFIG_IA64_SGI_SN_XP is not set
-CONFIG_FORCE_MAX_ZONEORDER=17
-CONFIG_SMP=y
-CONFIG_NR_CPUS=512
-CONFIG_IA64_NR_NODES=256
-CONFIG_HOTPLUG_CPU=y
-# CONFIG_SCHED_SMT is not set
-# CONFIG_PREEMPT is not set
-CONFIG_SELECT_MEMORY_MODEL=y
-# CONFIG_FLATMEM_MANUAL is not set
-# CONFIG_DISCONTIGMEM_MANUAL is not set
-CONFIG_SPARSEMEM_MANUAL=y
-CONFIG_SPARSEMEM=y
-CONFIG_NEED_MULTIPLE_NODES=y
-CONFIG_HAVE_MEMORY_PRESENT=y
-# CONFIG_SPARSEMEM_STATIC is not set
-CONFIG_SPARSEMEM_EXTREME=y
-# CONFIG_MEMORY_HOTPLUG is not set
-CONFIG_SPLIT_PTLOCK_CPUS=4
-CONFIG_MIGRATION=y
-CONFIG_ARCH_SELECT_MEMORY_MODEL=y
-CONFIG_ARCH_DISCONTIGMEM_ENABLE=y
-CONFIG_ARCH_FLATMEM_ENABLE=y
-CONFIG_ARCH_SPARSEMEM_ENABLE=y
-CONFIG_ARCH_DISCONTIGMEM_DEFAULT=y
-CONFIG_NUMA=y
-CONFIG_HAVE_ARCH_EARLY_PFN_TO_NID=y
-CONFIG_IA64_MCA_RECOVERY=y
-CONFIG_PERFMON=y
-CONFIG_IA64_PALINFO=y
-CONFIG_SGI_SN=y
-
-#
-# Firmware Drivers
-#
-CONFIG_EFI_VARS=y
-CONFIG_EFI_PCDP=y
-CONFIG_BINFMT_ELF=y
-CONFIG_BINFMT_MISC=m
-
-#
-# Power management and ACPI
-#
-CONFIG_PM=y
-CONFIG_PM_LEGACY=y
-# CONFIG_PM_DEBUG is not set
-
-#
-# ACPI (Advanced Configuration and Power Interface) Support
-#
-CONFIG_ACPI=y
CONFIG_ACPI_BUTTON=m
+CONFIG_ACPI_CONTAINER=m
CONFIG_ACPI_FAN=m
CONFIG_ACPI_PROCESSOR=m
-CONFIG_ACPI_HOTPLUG_CPU=y
-CONFIG_ACPI_THERMAL=m
-CONFIG_ACPI_NUMA=y
-CONFIG_ACPI_BLACKLIST_YEAR=0
-# CONFIG_ACPI_DEBUG is not set
-CONFIG_ACPI_EC=y
-CONFIG_ACPI_POWER=y
-CONFIG_ACPI_SYSTEM=y
-CONFIG_ACPI_CONTAINER=m
-
-#
-# CPU Frequency scaling
-#
-# CONFIG_CPU_FREQ is not set
-
-#
-# Bus options (PCI, PCMCIA)
-#
-CONFIG_PCI=y
-CONFIG_PCI_DOMAINS=y
-# CONFIG_PCI_MSI is not set
-CONFIG_PCI_LEGACY_PROC=y
-# 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
-# CONFIG_HOTPLUG_PCI_ACPI_IBM is not set
-# CONFIG_HOTPLUG_PCI_CPCI is not set
-# CONFIG_HOTPLUG_PCI_SHPC is not set
-# CONFIG_HOTPLUG_PCI_SGI is not set
-
-#
-# PCCARD (PCMCIA/CardBus) support
-#
-# CONFIG_PCCARD 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_NET_KEY is not set
-CONFIG_INET=y
-CONFIG_IP_MULTICAST=y
-# CONFIG_IP_ADVANCED_ROUTER is not set
-CONFIG_IP_FIB_HASH=y
-# CONFIG_IP_PNP is not set
-# CONFIG_NET_IPIP is not set
-# CONFIG_NET_IPGRE is not set
-# CONFIG_IP_MROUTE is not set
+CONFIG_AGP_HP_ZX1=m
+CONFIG_AGP_I460=m
+CONFIG_AGP=m
+CONFIG_AGP_SGI_TIOCA=m
CONFIG_ARPD=y
-CONFIG_SYN_COOKIES=y
-# CONFIG_INET_AH is not set
-# CONFIG_INET_ESP is not set
-# CONFIG_INET_IPCOMP is not set
-# CONFIG_INET_TUNNEL is not set
-CONFIG_INET_DIAG=y
-CONFIG_INET_TCP_DIAG=y
-# CONFIG_TCP_CONG_ADVANCED is not set
-CONFIG_TCP_CONG_BIC=y
-# CONFIG_IPV6 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_NET_DIVERT is not set
-# CONFIG_ECONET is not set
-# CONFIG_WAN_ROUTER is not set
-
-#
-# QoS and/or fair queueing
-#
-# CONFIG_NET_SCHED is not set
-
-#
-# 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=m
-# CONFIG_DEBUG_DRIVER is not set
-
-#
-# Connector - unified userspace <-> kernelspace linker
-#
-# CONFIG_CONNECTOR is not set
-
-#
-# Memory Technology Devices (MTD)
-#
-# CONFIG_MTD is not set
-
-#
-# Parallel port support
-#
-# CONFIG_PARPORT is not set
-
-#
-# Plug and Play support
-#
-CONFIG_PNP=y
-# CONFIG_PNP_DEBUG is not set
-
-#
-# Protocols
-#
-CONFIG_PNPACPI=y
-
-#
-# 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=m
+CONFIG_AUTOFS4_FS=y
+CONFIG_AUTOFS_FS=y
+CONFIG_BINFMT_MISC=m
+CONFIG_BLK_DEV_CMD64X=y
CONFIG_BLK_DEV_CRYPTOLOOP=m
-CONFIG_BLK_DEV_NBD=m
-# CONFIG_BLK_DEV_SX8 is not set
-# CONFIG_BLK_DEV_UB is not set
-CONFIG_BLK_DEV_RAM=y
-CONFIG_BLK_DEV_RAM_COUNT=16
-CONFIG_BLK_DEV_RAM_SIZE=4096
-CONFIG_BLK_DEV_INITRD=y
-# CONFIG_CDROM_PKTCDVD is not set
-# CONFIG_ATA_OVER_ETH is not set
-
-#
-# ATA/ATAPI/MFM/RLL support
-#
-CONFIG_IDE=y
-CONFIG_IDE_MAX_HWIFS=4
-CONFIG_BLK_DEV_IDE=y
-
-#
-# Please see Documentation/ide.txt for help/info on IDE drives
-#
-# CONFIG_BLK_DEV_IDE_SATA is not set
-CONFIG_BLK_DEV_IDEDISK=y
-# CONFIG_IDEDISK_MULTI_MODE is not set
-CONFIG_BLK_DEV_IDECD=y
-# CONFIG_BLK_DEV_IDETAPE is not set
-CONFIG_BLK_DEV_IDEFLOPPY=y
-CONFIG_BLK_DEV_IDESCSI=m
-# CONFIG_IDE_TASK_IOCTL is not set
-
-#
-# IDE chipset support/bugfixes
-#
-CONFIG_IDE_GENERIC=y
-# CONFIG_BLK_DEV_IDEPNP is not set
-CONFIG_BLK_DEV_IDEPCI=y
-# CONFIG_IDEPCI_SHARE_IRQ is not set
-# CONFIG_BLK_DEV_OFFBOARD is not set
+CONFIG_BLK_DEV_DM=m
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
-# CONFIG_BLK_DEV_AMD74XX is not set
-CONFIG_BLK_DEV_CMD64X=y
-# CONFIG_BLK_DEV_TRIFLEX is not set
-# CONFIG_BLK_DEV_CY82C693 is not set
-# CONFIG_BLK_DEV_CS5520 is not set
-# CONFIG_BLK_DEV_CS5530 is not set
-# CONFIG_BLK_DEV_HPT34X is not set
-# CONFIG_BLK_DEV_HPT366 is not set
-# CONFIG_BLK_DEV_SC1200 is not set
+CONFIG_BLK_DEV_IDECD=y
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_BLK_DEV_LOOP=m
+CONFIG_BLK_DEV_MD=m
+CONFIG_BLK_DEV_NBD=m
CONFIG_BLK_DEV_PIIX=y
-# CONFIG_BLK_DEV_IT821X is not set
-# CONFIG_BLK_DEV_NS87415 is not set
-# CONFIG_BLK_DEV_PDC202XX_OLD is not set
-# CONFIG_BLK_DEV_PDC202XX_NEW is not set
-# CONFIG_BLK_DEV_SVWKS is not set
-CONFIG_BLK_DEV_SGIIOC4=y
-# CONFIG_BLK_DEV_SIIMAGE is not set
-# CONFIG_BLK_DEV_SLC90E66 is not set
-# CONFIG_BLK_DEV_TRM290 is not set
-# CONFIG_BLK_DEV_VIA82CXXX is not set
-# 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
-
-#
-# SCSI device support
-#
-# CONFIG_RAID_ATTRS is not set
-CONFIG_SCSI=y
-CONFIG_SCSI_PROC_FS=y
-
-#
-# SCSI support type (disk, tape, CD-ROM)
-#
+CONFIG_BLK_DEV_RAM=y
CONFIG_BLK_DEV_SD=y
-CONFIG_CHR_DEV_ST=m
-# CONFIG_CHR_DEV_OSST is not set
+CONFIG_BLK_DEV_SGIIOC4=y
CONFIG_BLK_DEV_SR=m
-# CONFIG_BLK_DEV_SR_VENDOR 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
-
-#
-# SCSI Transport Attributes
-#
-CONFIG_SCSI_SPI_ATTRS=y
-CONFIG_SCSI_FC_ATTRS=y
-# CONFIG_SCSI_ISCSI_ATTRS is not set
-# CONFIG_SCSI_SAS_ATTRS 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_MEGARAID_NEWGEN is not set
-# CONFIG_MEGARAID_LEGACY is not set
-# CONFIG_MEGARAID_SAS is not set
-CONFIG_SCSI_SATA=y
-# CONFIG_SCSI_SATA_AHCI is not set
-# CONFIG_SCSI_SATA_SVW is not set
-# CONFIG_SCSI_ATA_PIIX is not set
-# CONFIG_SCSI_SATA_MV is not set
-# CONFIG_SCSI_SATA_NV is not set
-# CONFIG_SCSI_PDC_ADMA is not set
-# CONFIG_SCSI_SATA_QSTOR is not set
-# CONFIG_SCSI_SATA_PROMISE is not set
-# CONFIG_SCSI_SATA_SX4 is not set
-# CONFIG_SCSI_SATA_SIL is not set
-# CONFIG_SCSI_SATA_SIL24 is not set
-# CONFIG_SCSI_SATA_SIS is not set
-# CONFIG_SCSI_SATA_ULI is not set
-# CONFIG_SCSI_SATA_VIA is not set
-CONFIG_SCSI_SATA_VITESSE=y
-# 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_SYM53C8XX_2=y
-CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=1
-CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16
-CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64
-# CONFIG_SCSI_SYM53C8XX_IOMAPPED is not set
-# CONFIG_SCSI_IPR is not set
-# CONFIG_SCSI_QLOGIC_FC is not set
-CONFIG_SCSI_QLOGIC_1280=y
-# CONFIG_SCSI_QLA_FC is not set
-# CONFIG_SCSI_LPFC is not set
-# CONFIG_SCSI_DC395x is not set
-# CONFIG_SCSI_DC390T is not set
-# CONFIG_SCSI_DEBUG is not set
-
-#
-# Multi-device support (RAID and LVM)
-#
-CONFIG_MD=y
-CONFIG_BLK_DEV_MD=m
-CONFIG_MD_LINEAR=m
-CONFIG_MD_RAID0=m
-CONFIG_MD_RAID1=m
-# CONFIG_MD_RAID10 is not set
-CONFIG_MD_RAID5=m
-CONFIG_MD_RAID6=m
-CONFIG_MD_MULTIPATH=m
-# CONFIG_MD_FAULTY is not set
-CONFIG_BLK_DEV_DM=m
+CONFIG_CHR_DEV_ST=m
+CONFIG_CIFS=m
+CONFIG_CRYPTO_MD5=y
+CONFIG_DEBUG_KERNEL=y
+CONFIG_DEBUG_MUTEXES=y
CONFIG_DM_CRYPT=m
-CONFIG_DM_SNAPSHOT=m
CONFIG_DM_MIRROR=m
-CONFIG_DM_ZERO=m
CONFIG_DM_MULTIPATH=m
-# CONFIG_DM_MULTIPATH_EMC is not set
-
-#
-# Fusion MPT device support
-#
-CONFIG_FUSION=y
-CONFIG_FUSION_SPI=y
-CONFIG_FUSION_FC=m
-# CONFIG_FUSION_SAS is not set
-CONFIG_FUSION_MAX_SGE=128
-# CONFIG_FUSION_CTL is not set
-
-#
-# IEEE 1394 (FireWire) support
-#
-# CONFIG_IEEE1394 is not set
-
-#
-# I2O device support
-#
-# CONFIG_I2O is not set
-
-#
-# Network device support
-#
-CONFIG_NETDEVICES=y
-CONFIG_DUMMY=m
-# CONFIG_BONDING 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
-# CONFIG_TULIP_MWI is not set
-# CONFIG_TULIP_MMIO is not set
-# CONFIG_TULIP_NAPI is not set
-# CONFIG_DE4X5 is not set
-# CONFIG_WINBOND_840 is not set
-# CONFIG_DM9102 is not set
-# CONFIG_ULI526X is not set
-# CONFIG_HP100 is not set
-CONFIG_NET_PCI=y
-# CONFIG_PCNET32 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=m
-CONFIG_E100=m
-# CONFIG_FEALNX is not set
-# CONFIG_NATSEMI is not set
-# CONFIG_NE2K_PCI is not set
-# CONFIG_8139CP is not set
-# CONFIG_8139TOO is not set
-# CONFIG_SIS900 is not set
-# CONFIG_EPIC100 is not set
-# CONFIG_SUNDANCE is not set
-# CONFIG_VIA_RHINE is not set
-
-#
-# Ethernet (1000 Mbit)
-#
-# CONFIG_ACENIC is not set
-# CONFIG_DL2K is not set
-CONFIG_E1000=y
-# 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 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=y
-# CONFIG_BNX2 is not set
-
-#
-# Ethernet (10000 Mbit)
-#
-# CONFIG_CHELSIO_T1 is not set
-# CONFIG_IXGB is not set
-# CONFIG_S2IO is not set
-
-#
-# Token Ring devices
-#
-# CONFIG_TR is not set
-
-#
-# Wireless LAN (non-hamradio)
-#
-# CONFIG_NET_RADIO is not set
-
-#
-# Wan interfaces
-#
-# CONFIG_WAN is not set
-# CONFIG_FDDI is not set
-# CONFIG_HIPPI is not set
-# CONFIG_PPP is not set
-# CONFIG_SLIP is not set
-# CONFIG_NET_FC is not set
-# 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
-
-#
-# Input device support
-#
-CONFIG_INPUT=y
-
-#
-# Userland interfaces
-#
-CONFIG_INPUT_MOUSEDEV=y
-CONFIG_INPUT_MOUSEDEV_PSAUX=y
-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_INPUT_MOUSE=y
-CONFIG_MOUSE_PS2=y
-# CONFIG_MOUSE_SERIAL is not set
-# CONFIG_MOUSE_VSXXXAA is not set
-# CONFIG_INPUT_JOYSTICK is not set
-# CONFIG_INPUT_TOUCHSCREEN is not set
-# CONFIG_INPUT_MISC is not set
-
-#
-# Hardware I/O ports
-#
-CONFIG_SERIO=y
-CONFIG_SERIO_I8042=y
-# CONFIG_SERIO_SERPORT is not set
-# CONFIG_SERIO_PCIPS2 is not set
-CONFIG_SERIO_LIBPS2=y
-# CONFIG_SERIO_RAW is not set
-CONFIG_GAMEPORT=m
-# CONFIG_GAMEPORT_NS558 is not set
-# CONFIG_GAMEPORT_L4 is not set
-# CONFIG_GAMEPORT_EMU10K1 is not set
-# CONFIG_GAMEPORT_FM801 is not set
-
-#
-# Character devices
-#
-CONFIG_VT=y
-CONFIG_VT_CONSOLE=y
-CONFIG_HW_CONSOLE=y
-CONFIG_SERIAL_NONSTANDARD=y
-# CONFIG_COMPUTONE is not set
-# CONFIG_ROCKETPORT is not set
-# CONFIG_CYCLADES is not set
-# CONFIG_DIGIEPCA is not set
-# CONFIG_MOXA_INTELLIO is not set
-# CONFIG_MOXA_SMARTIO is not set
-# CONFIG_ISI is not set
-# CONFIG_SYNCLINKMP is not set
-# CONFIG_SYNCLINK_GT is not set
-# CONFIG_N_HDLC is not set
-# CONFIG_SPECIALIX is not set
-# CONFIG_SX is not set
-# CONFIG_STALDRV is not set
-CONFIG_SGI_SNSC=y
-CONFIG_SGI_TIOCX=y
-CONFIG_SGI_MBCS=m
-
-#
-# Serial drivers
-#
-CONFIG_SERIAL_8250=y
-CONFIG_SERIAL_8250_CONSOLE=y
-CONFIG_SERIAL_8250_ACPI=y
-CONFIG_SERIAL_8250_NR_UARTS=6
-CONFIG_SERIAL_8250_RUNTIME_UARTS=4
-CONFIG_SERIAL_8250_EXTENDED=y
-CONFIG_SERIAL_8250_SHARE_IRQ=y
-# CONFIG_SERIAL_8250_DETECT_IRQ is not set
-# CONFIG_SERIAL_8250_RSA is not set
-
-#
-# Non-8250 serial port support
-#
-CONFIG_SERIAL_CORE=y
-CONFIG_SERIAL_CORE_CONSOLE=y
-CONFIG_SERIAL_SGI_L1_CONSOLE=y
-# CONFIG_SERIAL_JSM is not set
-CONFIG_SERIAL_SGI_IOC4=y
-CONFIG_SERIAL_SGI_IOC3=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
-
-#
-# Ftape, the floppy tape device driver
-#
-CONFIG_AGP=m
-CONFIG_AGP_I460=m
-CONFIG_AGP_HP_ZX1=m
-CONFIG_AGP_SGI_TIOCA=m
+CONFIG_DM_SNAPSHOT=m
+CONFIG_DM_ZERO=m
CONFIG_DRM=m
-CONFIG_DRM_TDFX=m
+CONFIG_DRM_MGA=m
CONFIG_DRM_R128=m
CONFIG_DRM_RADEON=m
-CONFIG_DRM_MGA=m
CONFIG_DRM_SIS=m
-# CONFIG_DRM_VIA is not set
-# CONFIG_DRM_SAVAGE is not set
-CONFIG_RAW_DRIVER=m
-CONFIG_MAX_RAW_DEVS=256
-CONFIG_HPET=y
-# CONFIG_HPET_RTC_IRQ is not set
-CONFIG_HPET_MMAP=y
-# CONFIG_HANGCHECK_TIMER is not set
-CONFIG_MMTIMER=y
-
-#
-# TPM devices
-#
-# CONFIG_TCG_TPM is not set
-# CONFIG_TELCLOCK 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_F71805F is not set
-# CONFIG_HWMON_DEBUG_CHIP is not set
-
-#
-# Misc devices
-#
-
-#
-# Multimedia Capabilities Port drivers
-#
-
-#
-# Multimedia devices
-#
-# CONFIG_VIDEO_DEV is not set
-
-#
-# Digital Video Broadcasting Devices
-#
-# CONFIG_DVB is not set
-
-#
-# Graphics support
-#
-# CONFIG_FB is not set
-
-#
-# Console display driver support
-#
-CONFIG_VGA_CONSOLE=y
-CONFIG_DUMMY_CONSOLE=y
-
-#
-# Sound
-#
-CONFIG_SOUND=m
-
-#
-# Advanced Linux Sound Architecture
-#
-CONFIG_SND=m
-CONFIG_SND_TIMER=m
-CONFIG_SND_PCM=m
-CONFIG_SND_HWDEP=m
-CONFIG_SND_RAWMIDI=m
-CONFIG_SND_SEQUENCER=m
-CONFIG_SND_SEQ_DUMMY=m
-CONFIG_SND_OSSEMUL=y
-CONFIG_SND_MIXER_OSS=m
-CONFIG_SND_PCM_OSS=m
-CONFIG_SND_SEQUENCER_OSS=y
-# CONFIG_SND_DYNAMIC_MINORS is not set
-CONFIG_SND_SUPPORT_OLD_API=y
-CONFIG_SND_VERBOSE_PRINTK=y
-# CONFIG_SND_DEBUG is not set
-
-#
-# Generic devices
-#
-CONFIG_SND_MPU401_UART=m
-CONFIG_SND_OPL3_LIB=m
-CONFIG_SND_AC97_CODEC=m
-CONFIG_SND_AC97_BUS=m
-CONFIG_SND_DUMMY=m
-CONFIG_SND_VIRMIDI=m
-CONFIG_SND_MTPAV=m
-CONFIG_SND_SERIAL_U16550=m
-CONFIG_SND_MPU401=m
-
-#
-# PCI devices
-#
-# CONFIG_SND_AD1889 is not set
-# CONFIG_SND_ALI5451 is not set
-# CONFIG_SND_ATIIXP is not set
-# CONFIG_SND_ATIIXP_MODEM is not set
-# CONFIG_SND_AU8810 is not set
-# CONFIG_SND_AU8820 is not set
-# CONFIG_SND_AU8830 is not set
-# CONFIG_SND_AZT3328 is not set
-# CONFIG_SND_BT87X is not set
-# CONFIG_SND_CA0106 is not set
-# CONFIG_SND_CMIPCI is not set
-CONFIG_SND_CS4281=m
-CONFIG_SND_CS46XX=m
-CONFIG_SND_CS46XX_NEW_DSP=y
-CONFIG_SND_EMU10K1=m
-# CONFIG_SND_EMU10K1X is not set
-# CONFIG_SND_ENS1370 is not set
-# CONFIG_SND_ENS1371 is not set
-# CONFIG_SND_ES1938 is not set
-# CONFIG_SND_ES1968 is not set
-CONFIG_SND_FM801=m
-# CONFIG_SND_FM801_TEA575X is not set
-# CONFIG_SND_HDA_INTEL is not set
-# CONFIG_SND_HDSP is not set
-# CONFIG_SND_HDSPM is not set
-# CONFIG_SND_ICE1712 is not set
-# CONFIG_SND_ICE1724 is not set
-# CONFIG_SND_INTEL8X0 is not set
-# CONFIG_SND_INTEL8X0M is not set
-# CONFIG_SND_KORG1212 is not set
-# CONFIG_SND_MAESTRO3 is not set
-# CONFIG_SND_MIXART is not set
-# CONFIG_SND_NM256 is not set
-# CONFIG_SND_PCXHR is not set
-# CONFIG_SND_RME32 is not set
-# CONFIG_SND_RME96 is not set
-# CONFIG_SND_RME9652 is not set
-# CONFIG_SND_SONICVIBES is not set
-# CONFIG_SND_TRIDENT is not set
-# CONFIG_SND_VIA82XX is not set
-# CONFIG_SND_VIA82XX_MODEM is not set
-# CONFIG_SND_VX222 is not set
-# CONFIG_SND_YMFPCI is not set
-
-#
-# USB devices
-#
-# CONFIG_SND_USB_AUDIO is not set
-
-#
-# Open Sound System
-#
-# CONFIG_SOUND_PRIME is not set
-
-#
-# USB support
-#
-CONFIG_USB_ARCH_HAS_HCD=y
-CONFIG_USB_ARCH_HAS_OHCI=y
-CONFIG_USB=m
-# CONFIG_USB_DEBUG is not set
-
-#
-# Miscellaneous USB options
-#
-CONFIG_USB_DEVICEFS=y
-# CONFIG_USB_BANDWIDTH 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_EHCI_HCD=m
-# CONFIG_USB_EHCI_SPLIT_ISO is not set
-# CONFIG_USB_EHCI_ROOT_HUB_TT is not set
-# CONFIG_USB_ISP116X_HCD is not set
-CONFIG_USB_OHCI_HCD=m
-# CONFIG_USB_OHCI_BIG_ENDIAN is not set
-CONFIG_USB_OHCI_LITTLE_ENDIAN=y
-CONFIG_USB_UHCI_HCD=m
-# CONFIG_USB_SL811_HCD is not set
-
-#
-# USB Device Class drivers
-#
-# CONFIG_OBSOLETE_OSS_USB_DRIVER is not set
-# CONFIG_USB_ACM is not set
-# CONFIG_USB_PRINTER is not set
-
-#
-# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
-#
-
-#
-# may also be needed; see USB_STORAGE Help for more information
-#
-CONFIG_USB_STORAGE=m
-# CONFIG_USB_STORAGE_DEBUG is not set
-# CONFIG_USB_STORAGE_DATAFAB is not set
-# CONFIG_USB_STORAGE_FREECOM is not set
-# CONFIG_USB_STORAGE_ISD200 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_LIBUSUAL is not set
-
-#
-# USB Input Devices
-#
-CONFIG_USB_HID=m
-CONFIG_USB_HIDINPUT=y
-# 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_MTOUCH is not set
-# CONFIG_USB_ITMTOUCH is not set
-# CONFIG_USB_EGALAX 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
-
-#
-# USB Imaging devices
-#
-# CONFIG_USB_MDC800 is not set
-# CONFIG_USB_MICROTEK is not set
-
-#
-# USB Multimedia devices
-#
-# CONFIG_USB_DABUSB is not set
-
-#
-# Video4Linux support is needed for USB Multimedia device support
-#
-
-#
-# USB Network Adapters
-#
-# CONFIG_USB_CATC is not set
-# CONFIG_USB_KAWETH is not set
-# CONFIG_USB_PEGASUS is not set
-# CONFIG_USB_RTL8150 is not set
-# CONFIG_USB_USBNET is not set
-CONFIG_USB_MON=y
-
-#
-# 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_AUERSWALD is not set
-# CONFIG_USB_RIO500 is not set
-# CONFIG_USB_LEGOTOWER is not set
-# CONFIG_USB_LCD is not set
-# CONFIG_USB_LED is not set
-# CONFIG_USB_CYTHERM is not set
-# CONFIG_USB_PHIDGETKIT is not set
-# CONFIG_USB_PHIDGETSERVO is not set
-# CONFIG_USB_IDMOUSE is not set
-# CONFIG_USB_SISUSBVGA is not set
-# CONFIG_USB_LD is not set
-# CONFIG_USB_TEST is not set
-
-#
-# USB DSL modem support
-#
-
-#
-# USB Gadget Support
-#
-# CONFIG_USB_GADGET is not set
-
-#
-# MMC/SD Card support
-#
-# CONFIG_MMC is not set
-
-#
-# InfiniBand support
-#
-CONFIG_INFINIBAND=m
-# CONFIG_INFINIBAND_USER_MAD is not set
-# CONFIG_INFINIBAND_USER_ACCESS is not set
-CONFIG_INFINIBAND_MTHCA=m
-# CONFIG_INFINIBAND_MTHCA_DEBUG is not set
-CONFIG_INFINIBAND_IPOIB=m
-# CONFIG_INFINIBAND_IPOIB_DEBUG is not set
-# CONFIG_INFINIBAND_SRP is not set
-
-#
-# SN Devices
-#
-CONFIG_SGI_IOC4=y
-CONFIG_SGI_IOC3=y
-
-#
-# EDAC - error detection and reporting (RAS)
-#
-
-#
-# File systems
-#
-CONFIG_EXT2_FS=y
-CONFIG_EXT2_FS_XATTR=y
+CONFIG_DRM_TDFX=m
+CONFIG_DUMMY=m
+CONFIG_E1000=y
+CONFIG_E100=m
+CONFIG_EFI_PARTITION=y
+CONFIG_EFI_RTC=y
+CONFIG_EFI_VARS=y
+CONFIG_EXPERIMENTAL=y
CONFIG_EXT2_FS_POSIX_ACL=y
CONFIG_EXT2_FS_SECURITY=y
-# CONFIG_EXT2_FS_XIP is not set
-CONFIG_EXT3_FS=y
-CONFIG_EXT3_FS_XATTR=y
+CONFIG_EXT2_FS_XATTR=y
+CONFIG_EXT2_FS=y
CONFIG_EXT3_FS_POSIX_ACL=y
CONFIG_EXT3_FS_SECURITY=y
-CONFIG_JBD=y
-# CONFIG_JBD_DEBUG is not set
-CONFIG_FS_MBCACHE=y
-CONFIG_REISERFS_FS=y
-# CONFIG_REISERFS_CHECK is not set
-# CONFIG_REISERFS_PROC_INFO is not set
-CONFIG_REISERFS_FS_XATTR=y
-CONFIG_REISERFS_FS_POSIX_ACL=y
-CONFIG_REISERFS_FS_SECURITY=y
-# CONFIG_JFS_FS is not set
-CONFIG_FS_POSIX_ACL=y
-CONFIG_XFS_FS=y
-CONFIG_XFS_EXPORT=y
-# CONFIG_XFS_QUOTA is not set
-# CONFIG_XFS_SECURITY is not set
-# CONFIG_XFS_POSIX_ACL is not set
-# CONFIG_XFS_RT is not set
-# CONFIG_OCFS2_FS is not set
-# CONFIG_MINIX_FS is not set
-# CONFIG_ROMFS_FS is not set
+CONFIG_EXT3_FS=y
+CONFIG_FUSION_FC=m
+CONFIG_FUSION_SPI=y
+CONFIG_FUSION=y
+CONFIG_GAMEPORT=m
+CONFIG_HOTPLUG_CPU=y
+CONFIG_HOTPLUG_PCI_ACPI=m
+CONFIG_HOTPLUG_PCI=m
+CONFIG_HPET=y
+CONFIG_HUGETLBFS=y
+# CONFIG_HW_RANDOM is not set
+CONFIG_IA64_CYCLONE=y
+CONFIG_IA64_MCA_RECOVERY=y
+CONFIG_IA64_PALINFO=y
+CONFIG_IDE_GENERIC=y
+CONFIG_IDE=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_IKCONFIG=y
+CONFIG_INET=y
+CONFIG_INFINIBAND_IPOIB=m
+CONFIG_INFINIBAND=m
+CONFIG_INFINIBAND_MTHCA=m
CONFIG_INOTIFY=y
-# CONFIG_QUOTA is not set
-CONFIG_DNOTIFY=y
-CONFIG_AUTOFS_FS=y
-CONFIG_AUTOFS4_FS=y
-# CONFIG_FUSE_FS is not set
-
-#
-# CD-ROM/DVD Filesystems
-#
+CONFIG_IP_MULTICAST=y
+# CONFIG_IPV6 is not set
CONFIG_ISO9660_FS=m
CONFIG_JOLIET=y
-# CONFIG_ZISOFS is not set
-CONFIG_UDF_FS=m
-CONFIG_UDF_NLS=y
-
-#
-# DOS/FAT/NT Filesystems
-#
-CONFIG_FAT_FS=y
-# CONFIG_MSDOS_FS is not set
-CONFIG_VFAT_FS=y
-CONFIG_FAT_DEFAULT_CODEPAGE=437
-CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
-CONFIG_NTFS_FS=m
-# CONFIG_NTFS_DEBUG is not set
-# CONFIG_NTFS_RW is not set
-
-#
-# Pseudo filesystems
-#
-CONFIG_PROC_FS=y
-CONFIG_PROC_KCORE=y
-CONFIG_SYSFS=y
-CONFIG_TMPFS=y
-CONFIG_HUGETLBFS=y
-CONFIG_HUGETLB_PAGE=y
-CONFIG_RAMFS=y
-# CONFIG_RELAYFS_FS is not set
-# CONFIG_CONFIGFS_FS is not set
-
-#
-# Miscellaneous filesystems
-#
-# CONFIG_ADFS_FS is not set
-# CONFIG_AFFS_FS is not set
-# CONFIG_HFS_FS is not set
-# CONFIG_HFSPLUS_FS is not set
-# CONFIG_BEFS_FS is not set
-# CONFIG_BFS_FS is not set
-# CONFIG_EFS_FS is not set
-# CONFIG_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_KALLSYMS_ALL=y
+CONFIG_LOG_BUF_SHIFT=20
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_MCKINLEY=y
+CONFIG_MD_LINEAR=m
+CONFIG_MD_MULTIPATH=m
+CONFIG_MD_RAID0=m
+CONFIG_MD_RAID1=m
+CONFIG_MD=y
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODVERSIONS=y
+CONFIG_NETCONSOLE=y
+CONFIG_NETDEVICES=y
+CONFIG_NET_ETHERNET=y
+CONFIG_NET_PCI=y
+CONFIG_NET_TULIP=y
+CONFIG_NFSD=m
+CONFIG_NFSD_V4=y
CONFIG_NFS_FS=m
CONFIG_NFS_V3=y
-# CONFIG_NFS_V3_ACL is not set
CONFIG_NFS_V4=y
-CONFIG_NFS_DIRECTIO=y
-CONFIG_NFSD=m
-CONFIG_NFSD_V3=y
-# CONFIG_NFSD_V3_ACL is not set
-CONFIG_NFSD_V4=y
-CONFIG_NFSD_TCP=y
-CONFIG_LOCKD=m
-CONFIG_LOCKD_V4=y
-CONFIG_EXPORTFS=y
-CONFIG_NFS_COMMON=y
-CONFIG_SUNRPC=m
-CONFIG_SUNRPC_GSS=m
-CONFIG_RPCSEC_GSS_KRB5=m
-# CONFIG_RPCSEC_GSS_SPKM3 is not set
-CONFIG_SMB_FS=m
-CONFIG_SMB_NLS_DEFAULT=y
-CONFIG_SMB_NLS_REMOTE="cp437"
-CONFIG_CIFS=m
-# CONFIG_CIFS_STATS is not set
-# CONFIG_CIFS_XATTR is not set
-# CONFIG_CIFS_EXPERIMENTAL is not set
-# CONFIG_NCP_FS is not set
-# CONFIG_CODA_FS is not set
-# CONFIG_AFS_FS is not set
-# CONFIG_9P_FS is not set
-
-#
-# Partition Types
-#
-CONFIG_PARTITION_ADVANCED=y
-# CONFIG_ACORN_PARTITION is not set
-# CONFIG_OSF_PARTITION is not set
-# CONFIG_AMIGA_PARTITION is not set
-# CONFIG_ATARI_PARTITION is not set
-# CONFIG_MAC_PARTITION is not set
-CONFIG_MSDOS_PARTITION=y
-# CONFIG_BSD_DISKLABEL is not set
-# CONFIG_MINIX_SUBPARTITION is not set
-# CONFIG_SOLARIS_X86_PARTITION is not set
-# CONFIG_UNIXWARE_DISKLABEL is not set
-# CONFIG_LDM_PARTITION is not set
-CONFIG_SGI_PARTITION=y
-# CONFIG_ULTRIX_PARTITION is not set
-# CONFIG_SUN_PARTITION is not set
-# CONFIG_KARMA_PARTITION is not set
-CONFIG_EFI_PARTITION=y
-
-#
-# Native Language Support
-#
-CONFIG_NLS=y
-CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_1250=m
+CONFIG_NLS_CODEPAGE_1251=m
CONFIG_NLS_CODEPAGE_437=y
CONFIG_NLS_CODEPAGE_737=m
CONFIG_NLS_CODEPAGE_775=m
@@ -1277,15 +120,14 @@ CONFIG_NLS_CODEPAGE_864=m
CONFIG_NLS_CODEPAGE_865=m
CONFIG_NLS_CODEPAGE_866=m
CONFIG_NLS_CODEPAGE_869=m
-CONFIG_NLS_CODEPAGE_936=m
-CONFIG_NLS_CODEPAGE_950=m
+CONFIG_NLS_CODEPAGE_874=m
CONFIG_NLS_CODEPAGE_932=m
+CONFIG_NLS_CODEPAGE_936=m
CONFIG_NLS_CODEPAGE_949=m
-CONFIG_NLS_CODEPAGE_874=m
-CONFIG_NLS_ISO8859_8=m
-CONFIG_NLS_CODEPAGE_1250=m
-CONFIG_NLS_CODEPAGE_1251=m
-# CONFIG_NLS_ASCII is not set
+CONFIG_NLS_CODEPAGE_950=m
+CONFIG_NLS_ISO8859_13=m
+CONFIG_NLS_ISO8859_14=m
+CONFIG_NLS_ISO8859_15=m
CONFIG_NLS_ISO8859_1=y
CONFIG_NLS_ISO8859_2=m
CONFIG_NLS_ISO8859_3=m
@@ -1293,100 +135,77 @@ CONFIG_NLS_ISO8859_4=m
CONFIG_NLS_ISO8859_5=m
CONFIG_NLS_ISO8859_6=m
CONFIG_NLS_ISO8859_7=m
+CONFIG_NLS_ISO8859_8=m
CONFIG_NLS_ISO8859_9=m
-CONFIG_NLS_ISO8859_13=m
-CONFIG_NLS_ISO8859_14=m
-CONFIG_NLS_ISO8859_15=m
CONFIG_NLS_KOI8_R=m
CONFIG_NLS_KOI8_U=m
CONFIG_NLS_UTF8=m
-
-#
-# Library routines
-#
-# CONFIG_CRC_CCITT is not set
-# CONFIG_CRC16 is not set
-CONFIG_CRC32=y
-# CONFIG_LIBCRC32C is not set
-CONFIG_GENERIC_HARDIRQS=y
-CONFIG_GENERIC_IRQ_PROBE=y
-CONFIG_GENERIC_PENDING_IRQ=y
-
-#
-# HP Simulator drivers
-#
-# CONFIG_HP_SIMETH is not set
-# CONFIG_HP_SIMSERIAL is not set
-# CONFIG_HP_SIMSCSI is not set
-
-#
-# Instrumentation Support
-#
-# CONFIG_PROFILING is not set
-# CONFIG_KPROBES is not set
-
-#
-# Kernel hacking
-#
-# CONFIG_PRINTK_TIME is not set
-CONFIG_MAGIC_SYSRQ=y
-CONFIG_DEBUG_KERNEL=y
-CONFIG_LOG_BUF_SHIFT=20
-CONFIG_DETECT_SOFTLOCKUP=y
-# CONFIG_SCHEDSTATS is not set
-# CONFIG_DEBUG_SLAB is not set
-CONFIG_DEBUG_MUTEXES=y
-# CONFIG_DEBUG_SPINLOCK is not set
-# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
-# CONFIG_DEBUG_KOBJECT is not set
-# CONFIG_DEBUG_INFO is not set
-# CONFIG_DEBUG_FS is not set
-# CONFIG_DEBUG_VM is not set
-CONFIG_FORCED_INLINING=y
-# CONFIG_RCU_TORTURE_TEST is not set
-CONFIG_IA64_GRANULE_16MB=y
-# CONFIG_IA64_GRANULE_64MB is not set
-# CONFIG_IA64_PRINT_HAZARDS is not set
-# 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_HMAC is not set
-# CONFIG_CRYPTO_NULL is not set
-# CONFIG_CRYPTO_MD4 is not set
-CONFIG_CRYPTO_MD5=y
-# CONFIG_CRYPTO_SHA1 is not set
-# CONFIG_CRYPTO_SHA256 is not set
-# CONFIG_CRYPTO_SHA512 is not set
-# CONFIG_CRYPTO_WP512 is not set
-# CONFIG_CRYPTO_TGR192 is not set
-CONFIG_CRYPTO_DES=m
-# CONFIG_CRYPTO_BLOWFISH is not set
-# CONFIG_CRYPTO_TWOFISH is not set
-# CONFIG_CRYPTO_SERPENT is not set
-# CONFIG_CRYPTO_AES is not set
-# CONFIG_CRYPTO_CAST5 is not set
-# CONFIG_CRYPTO_CAST6 is not set
-# CONFIG_CRYPTO_TEA is not set
-# CONFIG_CRYPTO_ARC4 is not set
-# CONFIG_CRYPTO_KHAZAD is not set
-# CONFIG_CRYPTO_ANUBIS is not set
-# CONFIG_CRYPTO_DEFLATE is not set
-# CONFIG_CRYPTO_MICHAEL_MIC is not set
-# CONFIG_CRYPTO_CRC32C is not set
-# CONFIG_CRYPTO_TEST is not set
-
-#
-# Hardware crypto devices
-#
+CONFIG_NR_CPUS=512
+CONFIG_NTFS_FS=m
+CONFIG_PACKET=y
+CONFIG_PARTITION_ADVANCED=y
+CONFIG_PERFMON=y
+CONFIG_POSIX_MQUEUE=y
+CONFIG_PROC_KCORE=y
+CONFIG_RAW_DRIVER=m
+CONFIG_REISERFS_FS_POSIX_ACL=y
+CONFIG_REISERFS_FS_SECURITY=y
+CONFIG_REISERFS_FS_XATTR=y
+CONFIG_REISERFS_FS=y
+CONFIG_SCSI_FC_ATTRS=y
+CONFIG_SCSI_QLOGIC_1280=y
+CONFIG_SCSI_SYM53C8XX_2=y
+CONFIG_SCSI=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_EXTENDED=y
+CONFIG_SERIAL_8250_NR_UARTS=6
+CONFIG_SERIAL_8250_SHARE_IRQ=y
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_NONSTANDARD=y
+CONFIG_SERIAL_SGI_IOC3=y
+CONFIG_SERIAL_SGI_IOC4=y
+CONFIG_SERIAL_SGI_L1_CONSOLE=y
+# CONFIG_SERIO_SERPORT is not set
+CONFIG_SGI_IOC3=y
+CONFIG_SGI_IOC4=y
+CONFIG_SGI_MBCS=m
+CONFIG_SGI_PARTITION=y
+CONFIG_SGI_SNSC=y
+CONFIG_SGI_TIOCX=y
+CONFIG_SMB_FS=m
+CONFIG_SMB_NLS_DEFAULT=y
+CONFIG_SMP=y
+CONFIG_SND_CS4281=m
+CONFIG_SND_CS46XX=m
+CONFIG_SND_DUMMY=m
+CONFIG_SND_EMU10K1=m
+CONFIG_SND_FM801=m
+CONFIG_SND=m
+CONFIG_SND_MIXER_OSS=m
+CONFIG_SND_MPU401=m
+CONFIG_SND_MTPAV=m
+CONFIG_SND_PCM_OSS=m
+CONFIG_SND_SEQ_DUMMY=m
+CONFIG_SND_SEQUENCER=m
+CONFIG_SND_SEQUENCER_OSS=y
+CONFIG_SND_SERIAL_U16550=m
+CONFIG_SND_VERBOSE_PRINTK=y
+CONFIG_SND_VIRMIDI=m
+CONFIG_SOUND=m
+CONFIG_SPARSEMEM_MANUAL=y
+CONFIG_SYN_COOKIES=y
+CONFIG_SYSVIPC=y
+CONFIG_TIGON3=y
+CONFIG_TMPFS=y
+CONFIG_TULIP=m
+CONFIG_UDF_FS=m
+CONFIG_UNIX=y
+CONFIG_USB_DEVICEFS=y
+CONFIG_USB_EHCI_HCD=m
+CONFIG_USB=m
+CONFIG_USB_MON=m
+CONFIG_USB_OHCI_HCD=m
+CONFIG_USB_STORAGE=m
+CONFIG_USB_UHCI_HCD=m
+CONFIG_VFAT_FS=y
+CONFIG_XFS_FS=y
diff --git a/arch/ia64/configs/sim_defconfig b/arch/ia64/configs/sim_defconfig
index 21a23cdfd41..585222b368c 100644
--- a/arch/ia64/configs/sim_defconfig
+++ b/arch/ia64/configs/sim_defconfig
@@ -1,723 +1,57 @@
-#
-# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.16-rc5
-# Mon Feb 27 16:13:41 2006
-#
-
-#
-# Code maturity level options
-#
-CONFIG_EXPERIMENTAL=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_POSIX_MQUEUE is not set
-# CONFIG_BSD_PROCESS_ACCT is not set
-CONFIG_SYSCTL=y
-# CONFIG_AUDIT is not set
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-# CONFIG_CPUSETS is not set
-CONFIG_INITRAMFS_SOURCE=""
+CONFIG_BINFMT_MISC=y
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_SD=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-# CONFIG_EMBEDDED 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=y
-CONFIG_EPOLL=y
-CONFIG_SHMEM=y
-CONFIG_CC_ALIGN_FUNCTIONS=0
-CONFIG_CC_ALIGN_LABELS=0
-CONFIG_CC_ALIGN_LOOPS=0
-CONFIG_CC_ALIGN_JUMPS=0
-CONFIG_SLUB=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=y
-CONFIG_OBSOLETE_MODPARM=y
-CONFIG_MODVERSIONS=y
-# CONFIG_MODULE_SRCVERSION_ALL is not set
-CONFIG_KMOD=y
-CONFIG_STOP_MACHINE=y
-
-#
-# Block layer
-#
-
-#
-# IO Schedulers
-#
-CONFIG_IOSCHED_NOOP=y
-CONFIG_IOSCHED_AS=y
-CONFIG_IOSCHED_DEADLINE=y
-CONFIG_IOSCHED_CFQ=y
-CONFIG_DEFAULT_AS=y
-# CONFIG_DEFAULT_DEADLINE is not set
-# CONFIG_DEFAULT_CFQ is not set
-# CONFIG_DEFAULT_NOOP is not set
-CONFIG_DEFAULT_IOSCHED="anticipatory"
-
-#
-# Processor type and features
-#
-CONFIG_IA64=y
-CONFIG_64BIT=y
-CONFIG_MMU=y
-CONFIG_SWIOTLB=y
-CONFIG_RWSEM_XCHGADD_ALGORITHM=y
-CONFIG_GENERIC_CALIBRATE_DELAY=y
-CONFIG_GENERIC_TIME=y
-CONFIG_EFI=y
-CONFIG_GENERIC_IOMAP=y
-CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y
-CONFIG_DMA_IS_DMA32=y
-# CONFIG_IA64_GENERIC is not set
-# CONFIG_IA64_DIG is not set
-# CONFIG_IA64_HP_ZX1 is not set
-# CONFIG_IA64_HP_ZX1_SWIOTLB is not set
-# CONFIG_IA64_SGI_SN2 is not set
+CONFIG_DEBUG_INFO=y
+CONFIG_DEBUG_KERNEL=y
+CONFIG_DEBUG_MUTEXES=y
+CONFIG_EFI_PARTITION=y
+CONFIG_EFI_RTC=y
+CONFIG_EFI_VARS=y
+CONFIG_EXPERIMENTAL=y
+CONFIG_EXT2_FS=y
+# CONFIG_EXT3_FS_XATTR is not set
+CONFIG_EXT3_FS=y
+CONFIG_HP_SIMETH=y
+CONFIG_HP_SIMSCSI=y
+CONFIG_HP_SIMSERIAL_CONSOLE=y
+CONFIG_HP_SIMSERIAL=y
+CONFIG_HUGETLBFS=y
CONFIG_IA64_HP_SIM=y
-# CONFIG_ITANIUM is not set
-CONFIG_MCKINLEY=y
-# CONFIG_IA64_PAGE_SIZE_4KB is not set
-# CONFIG_IA64_PAGE_SIZE_8KB 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
-CONFIG_HZ_250=y
-# CONFIG_HZ_1000 is not set
-CONFIG_HZ=250
-CONFIG_IA64_L1_CACHE_SHIFT=7
-# CONFIG_IA64_CYCLONE is not set
-CONFIG_FORCE_MAX_ZONEORDER=17
-CONFIG_SMP=y
-CONFIG_NR_CPUS=64
-# CONFIG_HOTPLUG_CPU is not set
-# CONFIG_SCHED_SMT is not set
-CONFIG_PREEMPT=y
-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_ARCH_SELECT_MEMORY_MODEL=y
-CONFIG_ARCH_DISCONTIGMEM_ENABLE=y
-CONFIG_ARCH_FLATMEM_ENABLE=y
-CONFIG_ARCH_SPARSEMEM_ENABLE=y
-# CONFIG_VIRTUAL_MEM_MAP is not set
-# CONFIG_IA64_MCA_RECOVERY is not set
-# CONFIG_PERFMON is not set
CONFIG_IA64_PALINFO=m
-
-#
-# Firmware Drivers
-#
-CONFIG_EFI_VARS=y
-CONFIG_BINFMT_ELF=y
-CONFIG_BINFMT_MISC=y
-
-#
-# Power management and ACPI
-#
-
-#
-# Networking
-#
-CONFIG_NET=y
-
-#
-# Networking options
-#
-# CONFIG_NETDEBUG is not set
-CONFIG_PACKET=y
-# CONFIG_PACKET_MMAP is not set
-# CONFIG_UNIX is not set
-# CONFIG_NET_KEY is not set
+CONFIG_IKCONFIG_PROC=y
+CONFIG_IKCONFIG=y
CONFIG_INET=y
+CONFIG_INOTIFY=y
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
CONFIG_IP_MULTICAST=y
-# CONFIG_IP_ADVANCED_ROUTER is not set
-CONFIG_IP_FIB_HASH=y
-# CONFIG_IP_PNP is not set
-# CONFIG_NET_IPIP is not set
-# CONFIG_NET_IPGRE is not set
-# CONFIG_IP_MROUTE is not set
-# CONFIG_ARPD is not set
-# CONFIG_SYN_COOKIES is not set
-# CONFIG_INET_AH is not set
-# CONFIG_INET_ESP is not set
-# CONFIG_INET_IPCOMP is not set
-# CONFIG_INET_TUNNEL is not set
-CONFIG_INET_DIAG=y
-CONFIG_INET_TCP_DIAG=y
-# CONFIG_TCP_CONG_ADVANCED is not set
-CONFIG_TCP_CONG_BIC=y
# CONFIG_IPV6 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_NET_DIVERT is not set
-# CONFIG_ECONET is not set
-# CONFIG_WAN_ROUTER is not set
-
-#
-# QoS and/or fair queueing
-#
-# CONFIG_NET_SCHED is not set
-
-#
-# 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 is not set
-CONFIG_PREVENT_FIRMWARE_BUILD=y
-# CONFIG_FW_LOADER is not set
-# CONFIG_DEBUG_DRIVER is not set
-
-#
-# Connector - unified userspace <-> kernelspace linker
-#
-# CONFIG_CONNECTOR is not set
-
-#
-# Memory Technology Devices (MTD)
-#
-# CONFIG_MTD is not set
-
-#
-# Parallel port support
-#
-# CONFIG_PARPORT is not set
-
-#
-# Plug and Play support
-#
-
-#
-# 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_RAM=y
-CONFIG_BLK_DEV_RAM_COUNT=16
-CONFIG_BLK_DEV_RAM_SIZE=4096
-# 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
-#
-# CONFIG_IDE is not set
-
-#
-# SCSI device support
-#
-# CONFIG_RAID_ATTRS is not set
-CONFIG_SCSI=y
-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=y
+# CONFIG_LEGACY_PTYS is not set
+CONFIG_LOG_BUF_SHIFT=16
+CONFIG_MCKINLEY=y
+CONFIG_MODULE_FORCE_UNLOAD=y
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODVERSIONS=y
+CONFIG_NET=y
+CONFIG_NFSD_V3=y
+CONFIG_NFSD=y
+CONFIG_NFS_FS=y
+CONFIG_NR_CPUS=64
+CONFIG_PACKET=y
+CONFIG_PARTITION_ADVANCED=y
+CONFIG_PREEMPT=y
+CONFIG_PROC_KCORE=y
CONFIG_SCSI_CONSTANTS=y
CONFIG_SCSI_LOGGING=y
-
-#
-# SCSI Transport Attributes
-#
+CONFIG_SCSI_MULTI_LUN=y
CONFIG_SCSI_SPI_ATTRS=y
-# CONFIG_SCSI_FC_ATTRS is not set
-# CONFIG_SCSI_ISCSI_ATTRS is not set
-# CONFIG_SCSI_SAS_ATTRS is not set
-
-#
-# SCSI low-level drivers
-#
-# CONFIG_ISCSI_TCP is not set
-# CONFIG_SCSI_SATA is not set
-# CONFIG_SCSI_DEBUG 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 is not set
-# CONFIG_DUMMY is not set
-# CONFIG_BONDING is not set
-# CONFIG_EQUALIZER is not set
-# CONFIG_TUN is not set
-
-#
-# PHY device support
-#
-
-#
-# Ethernet (10 or 100Mbit)
-#
-# CONFIG_NET_ETHERNET is not set
-
-#
-# Ethernet (1000 Mbit)
-#
-
-#
-# Ethernet (10000 Mbit)
-#
-# 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
-
-#
-# Userland interfaces
-#
-CONFIG_INPUT_MOUSEDEV=y
-CONFIG_INPUT_MOUSEDEV_PSAUX=y
-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 is not set
-# CONFIG_INPUT_MOUSE is not set
-# CONFIG_INPUT_JOYSTICK is not set
-# CONFIG_INPUT_TOUCHSCREEN is not set
-# CONFIG_INPUT_MISC is not set
-
-#
-# Hardware I/O ports
-#
-CONFIG_SERIO=y
+CONFIG_SCSI=y
# CONFIG_SERIO_I8042 is not set
-CONFIG_SERIO_SERPORT=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_SERIAL_NONSTANDARD is not set
-
-#
-# Serial drivers
-#
-# CONFIG_SERIAL_8250 is not set
-
-#
-# Non-8250 serial port support
-#
-CONFIG_UNIX98_PTYS=y
-# CONFIG_LEGACY_PTYS is not set
-
-#
-# IPMI
-#
-# CONFIG_IPMI_HANDLER is not set
-
-#
-# Watchdog Cards
-#
-# CONFIG_WATCHDOG is not set
-CONFIG_EFI_RTC=y
-# CONFIG_DTLK is not set
-# CONFIG_R3964 is not set
-
-#
-# Ftape, the floppy tape device driver
-#
-# CONFIG_AGP is not set
-# CONFIG_RAW_DRIVER is not set
-# CONFIG_HANGCHECK_TIMER is not set
-
-#
-# TPM devices
-#
-# CONFIG_TCG_TPM is not set
-# CONFIG_TELCLOCK 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_F71805F is not set
-# CONFIG_HWMON_DEBUG_CHIP is not set
-
-#
-# Misc devices
-#
-
-#
-# Multimedia Capabilities Port drivers
-#
-
-#
-# Multimedia devices
-#
-# CONFIG_VIDEO_DEV is not set
-
-#
-# Digital Video Broadcasting Devices
-#
-# CONFIG_DVB is not set
-
-#
-# Graphics support
-#
-# CONFIG_FB is not set
-
-#
-# Console display driver support
-#
+CONFIG_SMP=y
+# CONFIG_STANDALONE is not set
+CONFIG_SYSVIPC=y
# CONFIG_VGA_CONSOLE is not set
-CONFIG_DUMMY_CONSOLE=y
-
-#
-# Sound
-#
-# CONFIG_SOUND is not set
-
-#
-# USB support
-#
-# CONFIG_USB_ARCH_HAS_HCD is not set
-# CONFIG_USB_ARCH_HAS_OHCI 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
-
-#
-# InfiniBand support
-#
-
-#
-# EDAC - error detection and reporting (RAS)
-#
-
-#
-# 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 is not set
-CONFIG_JBD=y
-# CONFIG_JBD_DEBUG is not set
-# CONFIG_REISERFS_FS is not set
-# CONFIG_JFS_FS is not set
-# CONFIG_FS_POSIX_ACL is not set
-# CONFIG_XFS_FS is not set
-# CONFIG_OCFS2_FS is not set
-# CONFIG_MINIX_FS is not set
-# CONFIG_ROMFS_FS is not set
-CONFIG_INOTIFY=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_SYSFS=y
-# CONFIG_TMPFS is not set
-CONFIG_HUGETLBFS=y
-CONFIG_HUGETLB_PAGE=y
-CONFIG_RAMFS=y
-# CONFIG_RELAYFS_FS is not set
-# CONFIG_CONFIGFS_FS is not set
-
-#
-# Miscellaneous filesystems
-#
-# CONFIG_ADFS_FS is not set
-# CONFIG_AFFS_FS is not set
-# CONFIG_HFS_FS is not set
-# CONFIG_HFSPLUS_FS is not set
-# CONFIG_BEFS_FS is not set
-# CONFIG_BFS_FS is not set
-# CONFIG_EFS_FS is not set
-# CONFIG_CRAMFS is not set
-# CONFIG_VXFS_FS is not set
-# CONFIG_HPFS_FS is not set
-# CONFIG_QNX4FS_FS is not set
-# CONFIG_SYSV_FS is not set
-# CONFIG_UFS_FS is not set
-
-#
-# Network File Systems
-#
-CONFIG_NFS_FS=y
-# CONFIG_NFS_V3 is not set
-# CONFIG_NFS_V4 is not set
-CONFIG_NFS_DIRECTIO=y
-CONFIG_NFSD=y
-CONFIG_NFSD_V3=y
-# CONFIG_NFSD_V3_ACL is not set
-# CONFIG_NFSD_V4 is not set
-# CONFIG_NFSD_TCP is not set
-CONFIG_LOCKD=y
-CONFIG_LOCKD_V4=y
-CONFIG_EXPORTFS=y
-CONFIG_NFS_COMMON=y
-CONFIG_SUNRPC=y
-# CONFIG_RPCSEC_GSS_KRB5 is not set
-# CONFIG_RPCSEC_GSS_SPKM3 is not set
-# CONFIG_SMB_FS is not set
-# CONFIG_CIFS is not set
-# CONFIG_NCP_FS is not set
-# CONFIG_CODA_FS is not set
-# CONFIG_AFS_FS is not set
-# CONFIG_9P_FS is not set
-
-#
-# Partition Types
-#
-CONFIG_PARTITION_ADVANCED=y
-# CONFIG_ACORN_PARTITION is not set
-# CONFIG_OSF_PARTITION is not set
-# CONFIG_AMIGA_PARTITION is not set
-# CONFIG_ATARI_PARTITION is not set
-# CONFIG_MAC_PARTITION is not set
-CONFIG_MSDOS_PARTITION=y
-# CONFIG_BSD_DISKLABEL is not set
-# CONFIG_MINIX_SUBPARTITION is not set
-# CONFIG_SOLARIS_X86_PARTITION is not set
-# CONFIG_UNIXWARE_DISKLABEL is not set
-# CONFIG_LDM_PARTITION is not set
-# CONFIG_SGI_PARTITION is not set
-# CONFIG_ULTRIX_PARTITION is not set
-# CONFIG_SUN_PARTITION is not set
-# CONFIG_KARMA_PARTITION is not set
-CONFIG_EFI_PARTITION=y
-
-#
-# Native Language Support
-#
-# CONFIG_NLS is not set
-
-#
-# Library routines
-#
-# CONFIG_CRC_CCITT is not set
-# CONFIG_CRC16 is not set
-CONFIG_CRC32=y
-# CONFIG_LIBCRC32C is not set
-CONFIG_GENERIC_HARDIRQS=y
-CONFIG_GENERIC_IRQ_PROBE=y
-CONFIG_GENERIC_PENDING_IRQ=y
-
-#
-# HP Simulator drivers
-#
-CONFIG_HP_SIMETH=y
-CONFIG_HP_SIMSERIAL=y
-CONFIG_HP_SIMSERIAL_CONSOLE=y
-CONFIG_HP_SIMSCSI=y
-
-#
-# Instrumentation Support
-#
-# CONFIG_PROFILING is not set
-# CONFIG_KPROBES is not set
-
-#
-# Kernel hacking
-#
-# CONFIG_PRINTK_TIME is not set
-# CONFIG_MAGIC_SYSRQ is not set
-CONFIG_DEBUG_KERNEL=y
-CONFIG_LOG_BUF_SHIFT=16
-CONFIG_DETECT_SOFTLOCKUP=y
-# CONFIG_SCHEDSTATS is not set
-# CONFIG_DEBUG_SLAB is not set
-CONFIG_DEBUG_PREEMPT=y
-CONFIG_DEBUG_MUTEXES=y
-# CONFIG_DEBUG_SPINLOCK is not set
-# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
-# CONFIG_DEBUG_KOBJECT is not set
-CONFIG_DEBUG_INFO=y
-# CONFIG_DEBUG_FS is not set
-# CONFIG_DEBUG_VM is not set
-CONFIG_FORCED_INLINING=y
-# CONFIG_RCU_TORTURE_TEST is not set
-# CONFIG_IA64_GRANULE_16MB is not set
-CONFIG_IA64_GRANULE_64MB=y
-# CONFIG_IA64_PRINT_HAZARDS is not set
-# 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 is not set
-
-#
-# Hardware crypto devices
-#
diff --git a/arch/ia64/configs/tiger_defconfig b/arch/ia64/configs/tiger_defconfig
index c5a5ea9d54a..498618ea00e 100644
--- a/arch/ia64/configs/tiger_defconfig
+++ b/arch/ia64/configs/tiger_defconfig
@@ -1,1134 +1,113 @@
-#
-# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.22
-# Thu Jul 19 13:54:47 2007
-#
-CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
-
-#
-# Code maturity level options
-#
-CONFIG_EXPERIMENTAL=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_SYSVIPC_SYSCTL=y
-CONFIG_POSIX_MQUEUE=y
-# CONFIG_BSD_PROCESS_ACCT is not set
-# CONFIG_TASKSTATS 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
-CONFIG_BLK_DEV_INITRD=y
-CONFIG_INITRAMFS_SOURCE=""
-CONFIG_CC_OPTIMIZE_FOR_SIZE=y
-CONFIG_SYSCTL=y
-# CONFIG_EMBEDDED is not set
-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_SLUB=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_MODULES=y
-CONFIG_MODULE_UNLOAD=y
-# CONFIG_MODULE_FORCE_UNLOAD is not set
-CONFIG_MODVERSIONS=y
-CONFIG_MODULE_SRCVERSION_ALL=y
-CONFIG_KMOD=y
-CONFIG_STOP_MACHINE=y
-CONFIG_BLOCK=y
-# CONFIG_BLK_DEV_IO_TRACE is not set
-# CONFIG_BLK_DEV_BSG 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"
-
-#
-# Processor type and features
-#
-CONFIG_IA64=y
-CONFIG_64BIT=y
-CONFIG_ZONE_DMA=y
-CONFIG_QUICKLIST=y
-CONFIG_MMU=y
-CONFIG_SWIOTLB=y
-CONFIG_RWSEM_XCHGADD_ALGORITHM=y
-# CONFIG_ARCH_HAS_ILOG2_U32 is not set
-# CONFIG_ARCH_HAS_ILOG2_U64 is not set
-CONFIG_GENERIC_FIND_NEXT_BIT=y
-CONFIG_GENERIC_CALIBRATE_DELAY=y
-CONFIG_GENERIC_TIME=y
-CONFIG_DMI=y
-CONFIG_EFI=y
-CONFIG_GENERIC_IOMAP=y
-CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y
-CONFIG_AUDIT_ARCH=y
-# CONFIG_IA64_GENERIC is not set
-CONFIG_IA64_DIG=y
-# CONFIG_IA64_HP_ZX1 is not set
-# CONFIG_IA64_HP_ZX1_SWIOTLB is not set
-# CONFIG_IA64_SGI_SN2 is not set
-# CONFIG_IA64_HP_SIM is not set
-# CONFIG_ITANIUM is not set
-CONFIG_MCKINLEY=y
-# CONFIG_IA64_PAGE_SIZE_4KB is not set
-# CONFIG_IA64_PAGE_SIZE_8KB 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
-CONFIG_HZ_250=y
-# CONFIG_HZ_300 is not set
-# CONFIG_HZ_1000 is not set
-CONFIG_HZ=250
-CONFIG_IA64_L1_CACHE_SHIFT=7
-CONFIG_IA64_CYCLONE=y
-CONFIG_IOSAPIC=y
-CONFIG_FORCE_MAX_ZONEORDER=17
-CONFIG_SMP=y
-CONFIG_NR_CPUS=16
-CONFIG_HOTPLUG_CPU=y
-CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
-# CONFIG_SCHED_SMT is not set
-CONFIG_PERMIT_BSP_REMOVE=y
-CONFIG_FORCE_CPEI_RETARGET=y
-# CONFIG_PREEMPT is not set
-CONFIG_SELECT_MEMORY_MODEL=y
-CONFIG_FLATMEM_MANUAL=y
-# CONFIG_DISCONTIGMEM_MANUAL is not set
-# CONFIG_SPARSEMEM_MANUAL is not set
-CONFIG_FLATMEM=y
-CONFIG_FLAT_NODE_MEM_MAP=y
-# CONFIG_SPARSEMEM_STATIC is not set
-CONFIG_SPLIT_PTLOCK_CPUS=4
-CONFIG_RESOURCES_64BIT=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
-CONFIG_ARCH_SPARSEMEM_ENABLE=y
-CONFIG_ARCH_POPULATES_NODE_MAP=y
-CONFIG_VIRTUAL_MEM_MAP=y
-CONFIG_HOLES_IN_ZONE=y
-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
-
-#
-# Firmware Drivers
-#
-CONFIG_EFI_VARS=y
-CONFIG_EFI_PCDP=y
-CONFIG_DMIID=y
-CONFIG_BINFMT_ELF=y
-CONFIG_BINFMT_MISC=m
-
-# CONFIG_DMAR is not set
-
-#
-# Power management and ACPI
-#
-CONFIG_PM=y
-CONFIG_PM_LEGACY=y
-# CONFIG_PM_DEBUG is not set
-
-#
-# ACPI (Advanced Configuration and Power Interface) Support
-#
-CONFIG_ACPI=y
-CONFIG_ACPI_PROCFS=y
CONFIG_ACPI_BUTTON=m
+CONFIG_ACPI_CONTAINER=m
CONFIG_ACPI_FAN=m
-# CONFIG_ACPI_DOCK is not set
CONFIG_ACPI_PROCESSOR=m
-CONFIG_ACPI_HOTPLUG_CPU=y
-CONFIG_ACPI_THERMAL=m
-CONFIG_ACPI_BLACKLIST_YEAR=0
-# CONFIG_ACPI_DEBUG is not set
-CONFIG_ACPI_EC=y
-CONFIG_ACPI_POWER=y
-CONFIG_ACPI_SYSTEM=y
-CONFIG_ACPI_CONTAINER=m
-
-#
-# CPU Frequency scaling
-#
-# CONFIG_CPU_FREQ is not set
-
-#
-# Bus options (PCI, PCMCIA)
-#
-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
-CONFIG_HOTPLUG_PCI=m
-# CONFIG_HOTPLUG_PCI_FAKE is not set
-CONFIG_HOTPLUG_PCI_ACPI=m
-# CONFIG_HOTPLUG_PCI_ACPI_IBM is not set
-# CONFIG_HOTPLUG_PCI_CPCI is not set
-# CONFIG_HOTPLUG_PCI_SHPC is not set
-
-#
-# PCCARD (PCMCIA/CardBus) support
-#
-# CONFIG_PCCARD 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=y
-# CONFIG_IP_ADVANCED_ROUTER is not set
-CONFIG_IP_FIB_HASH=y
-# CONFIG_IP_PNP is not set
-# CONFIG_NET_IPIP is not set
-# CONFIG_NET_IPGRE is not set
-# CONFIG_IP_MROUTE is not set
+CONFIG_ACPI_PROCFS=y
+CONFIG_AGP_I460=m
+CONFIG_AGP=m
CONFIG_ARPD=y
-CONFIG_SYN_COOKIES=y
-# CONFIG_INET_AH is not set
-# CONFIG_INET_ESP is not set
-# CONFIG_INET_IPCOMP is not set
-# CONFIG_INET_XFRM_TUNNEL is not set
-# CONFIG_INET_TUNNEL is not set
-CONFIG_INET_XFRM_MODE_TRANSPORT=y
-CONFIG_INET_XFRM_MODE_TUNNEL=y
-CONFIG_INET_XFRM_MODE_BEET=y
-CONFIG_INET_DIAG=y
-CONFIG_INET_TCP_DIAG=y
-# CONFIG_TCP_CONG_ADVANCED is not set
-CONFIG_TCP_CONG_CUBIC=y
-CONFIG_DEFAULT_TCP_CONG="cubic"
-# CONFIG_TCP_MD5SIG is not set
-# CONFIG_IPV6 is not set
-# CONFIG_INET6_XFRM_TUNNEL is not set
-# CONFIG_INET6_TUNNEL is not set
-# CONFIG_NETWORK_SECMARK is not set
-# CONFIG_NETFILTER is not set
-# 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 is not set
-# CONFIG_AF_RXRPC is not set
-
-#
-# Wireless
-#
-# CONFIG_CFG80211 is not set
-# CONFIG_WIRELESS_EXT is not set
-# CONFIG_MAC80211 is not set
-# CONFIG_IEEE80211 is not set
-# CONFIG_RFKILL is not set
-# CONFIG_NET_9P is not set
-
-#
-# Device Drivers
-#
-
-#
-# Generic Driver Options
-#
-CONFIG_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
-# CONFIG_CONNECTOR is not set
-# CONFIG_MTD is not set
-# CONFIG_PARPORT is not set
-CONFIG_PNP=y
-# CONFIG_PNP_DEBUG is not set
-
-#
-# Protocols
-#
-CONFIG_PNPACPI=y
-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
-# CONFIG_BLK_DEV_UMEM is not set
-# CONFIG_BLK_DEV_COW_COMMON is not set
-CONFIG_BLK_DEV_LOOP=m
+CONFIG_AUTOFS4_FS=y
+CONFIG_AUTOFS_FS=y
+CONFIG_BINFMT_MISC=m
+# CONFIG_BLK_DEV_BSG is not set
+CONFIG_BLK_DEV_CMD64X=y
CONFIG_BLK_DEV_CRYPTOLOOP=m
-CONFIG_BLK_DEV_NBD=m
-# CONFIG_BLK_DEV_SX8 is not set
-# CONFIG_BLK_DEV_UB is not set
-CONFIG_BLK_DEV_RAM=y
-CONFIG_BLK_DEV_RAM_COUNT=16
-CONFIG_BLK_DEV_RAM_SIZE=4096
-CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
-# CONFIG_CDROM_PKTCDVD is not set
-# CONFIG_ATA_OVER_ETH is not set
-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_IDE=y
-CONFIG_IDE_MAX_HWIFS=4
-CONFIG_BLK_DEV_IDE=y
-
-#
-# Please see Documentation/ide.txt for help/info on IDE drives
-#
-# CONFIG_BLK_DEV_IDE_SATA is not set
-CONFIG_BLK_DEV_IDEDISK=y
-# CONFIG_IDEDISK_MULTI_MODE is not set
-CONFIG_BLK_DEV_IDECD=y
-# CONFIG_BLK_DEV_IDETAPE is not set
-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
-#
-# CONFIG_IDE_GENERIC is not set
-# 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_DM=m
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_ONLYDISK is not set
-# CONFIG_BLK_DEV_AEC62XX is not set
-# CONFIG_BLK_DEV_ALI15X3 is not set
-# CONFIG_BLK_DEV_AMD74XX is not set
-CONFIG_BLK_DEV_CMD64X=y
-# CONFIG_BLK_DEV_TRIFLEX is not set
-# CONFIG_BLK_DEV_CY82C693 is not set
-# CONFIG_BLK_DEV_CS5520 is not set
-# CONFIG_BLK_DEV_CS5530 is not set
-# CONFIG_BLK_DEV_HPT34X is not set
-# CONFIG_BLK_DEV_HPT366 is not set
-# CONFIG_BLK_DEV_JMICRON is not set
-# CONFIG_BLK_DEV_SC1200 is not set
+CONFIG_BLK_DEV_IDECD=y
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_BLK_DEV_LOOP=m
+CONFIG_BLK_DEV_MD=m
+CONFIG_BLK_DEV_NBD=m
CONFIG_BLK_DEV_PIIX=y
-# CONFIG_BLK_DEV_IT8213 is not set
-# CONFIG_BLK_DEV_IT821X is not set
-# CONFIG_BLK_DEV_NS87415 is not set
-# CONFIG_BLK_DEV_PDC202XX_OLD is not set
-# CONFIG_BLK_DEV_PDC202XX_NEW is not set
-# CONFIG_BLK_DEV_SVWKS is not set
-# CONFIG_BLK_DEV_SIIMAGE is not set
-# CONFIG_BLK_DEV_SLC90E66 is not set
-# CONFIG_BLK_DEV_TRM290 is not set
-# CONFIG_BLK_DEV_VIA82CXXX is not set
-# CONFIG_BLK_DEV_TC86C001 is not set
-# CONFIG_IDE_ARM is not set
-CONFIG_BLK_DEV_IDEDMA=y
-# CONFIG_IDEDMA_IVB is not set
-# CONFIG_BLK_DEV_HD is not set
-
-#
-# SCSI device support
-#
-# 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
-
-#
-# SCSI support type (disk, tape, CD-ROM)
-#
+CONFIG_BLK_DEV_RAM=y
CONFIG_BLK_DEV_SD=y
-CONFIG_CHR_DEV_ST=m
-# CONFIG_CHR_DEV_OSST is not set
CONFIG_BLK_DEV_SR=m
-# CONFIG_BLK_DEV_SR_VENDOR 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=y
-CONFIG_SCSI_FC_ATTRS=y
-# 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_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=y
-CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=1
-CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16
-CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64
-CONFIG_SCSI_SYM53C8XX_MMIO=y
-CONFIG_SCSI_QLOGIC_1280=y
-# 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_DEBUG is not set
-# CONFIG_SCSI_SRP is not set
-# CONFIG_ATA is not set
-CONFIG_MD=y
-CONFIG_BLK_DEV_MD=m
-CONFIG_MD_LINEAR=m
-CONFIG_MD_RAID0=m
-CONFIG_MD_RAID1=m
-# CONFIG_MD_RAID10 is not set
-# CONFIG_MD_RAID456 is not set
-CONFIG_MD_MULTIPATH=m
-# CONFIG_MD_FAULTY is not set
-CONFIG_BLK_DEV_DM=m
-# CONFIG_DM_DEBUG is not set
+CONFIG_CHR_DEV_ST=m
+CONFIG_CIFS=m
+CONFIG_CRYPTO_ECB=m
+CONFIG_CRYPTO_MD5=y
+CONFIG_CRYPTO_PCBC=m
+CONFIG_DEBUG_KERNEL=y
+CONFIG_DEBUG_MUTEXES=y
CONFIG_DM_CRYPT=m
-CONFIG_DM_SNAPSHOT=m
CONFIG_DM_MIRROR=m
+CONFIG_DM_SNAPSHOT=m
CONFIG_DM_ZERO=m
-# CONFIG_DM_MULTIPATH is not set
-# CONFIG_DM_DELAY is not set
-
-#
-# Fusion MPT device support
-#
-CONFIG_FUSION=y
-CONFIG_FUSION_SPI=y
-CONFIG_FUSION_FC=y
-# CONFIG_FUSION_SAS is not set
-CONFIG_FUSION_MAX_SGE=128
-CONFIG_FUSION_CTL=y
-
-#
-# IEEE 1394 (FireWire) support
-#
-# CONFIG_FIREWIRE is not set
-# CONFIG_IEEE1394 is not set
-# CONFIG_I2O is not set
-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
-# CONFIG_ARCNET is not set
-# CONFIG_PHYLIB is not set
-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
-CONFIG_NET_TULIP=y
-# CONFIG_DE2104X is not set
-CONFIG_TULIP=m
-# CONFIG_TULIP_MWI is not set
-# CONFIG_TULIP_MMIO is not set
-# CONFIG_TULIP_NAPI is not set
-# CONFIG_DE4X5 is not set
-# CONFIG_WINBOND_840 is not set
-# CONFIG_DM9102 is not set
-# CONFIG_ULI526X is not set
-# CONFIG_HP100 is not set
-CONFIG_NET_PCI=y
-# CONFIG_PCNET32 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=m
-CONFIG_E100=m
-# CONFIG_FEALNX is not set
-# CONFIG_NATSEMI is not set
-# CONFIG_NE2K_PCI is not set
-# CONFIG_8139CP is not set
-# CONFIG_8139TOO is not set
-# CONFIG_SIS900 is not set
-# CONFIG_EPIC100 is not set
-# CONFIG_SUNDANCE is not set
-# CONFIG_VIA_RHINE is not set
-# CONFIG_SC92031 is not set
-CONFIG_NETDEV_1000=y
-# CONFIG_ACENIC is not set
-# CONFIG_DL2K is not set
-CONFIG_E1000=y
-# 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 is not set
-# CONFIG_SIS190 is not set
-# CONFIG_SKGE is not set
-# CONFIG_SKY2 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
-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
-
-#
-# 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
-# CONFIG_PPP is not set
-# CONFIG_SLIP is not set
-# CONFIG_NET_FC is not set
-# CONFIG_SHAPER is not set
-CONFIG_NETCONSOLE=y
-CONFIG_NETPOLL=y
-# CONFIG_NETPOLL_TRAP is not set
-CONFIG_NET_POLL_CONTROLLER=y
-# CONFIG_ISDN is not set
-# CONFIG_PHONE is not set
-
-#
-# Input device support
-#
-CONFIG_INPUT=y
-# CONFIG_INPUT_FF_MEMLESS is not set
-# CONFIG_INPUT_POLLDEV is not set
-
-#
-# Userland interfaces
-#
-CONFIG_INPUT_MOUSEDEV=y
-CONFIG_INPUT_MOUSEDEV_PSAUX=y
-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=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
-
-#
-# Hardware I/O ports
-#
-CONFIG_SERIO=y
-CONFIG_SERIO_I8042=y
-# CONFIG_SERIO_SERPORT is not set
-# CONFIG_SERIO_PCIPS2 is not set
-CONFIG_SERIO_LIBPS2=y
-# CONFIG_SERIO_RAW is not set
-CONFIG_GAMEPORT=m
-# CONFIG_GAMEPORT_NS558 is not set
-# CONFIG_GAMEPORT_L4 is not set
-# CONFIG_GAMEPORT_EMU10K1 is not set
-# CONFIG_GAMEPORT_FM801 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=y
-# CONFIG_COMPUTONE is not set
-# CONFIG_ROCKETPORT is not set
-# CONFIG_CYCLADES is not set
-# CONFIG_DIGIEPCA is not set
-# CONFIG_MOXA_INTELLIO is not set
-# CONFIG_MOXA_SMARTIO is not set
-# CONFIG_MOXA_SMARTIO_NEW is not set
-# CONFIG_ISI is not set
-# CONFIG_SYNCLINKMP is not set
-# CONFIG_SYNCLINK_GT is not set
-# CONFIG_N_HDLC is not set
-# CONFIG_SPECIALIX is not set
-# CONFIG_SX is not set
-# CONFIG_RIO is not set
-# CONFIG_STALDRV is not set
-
-#
-# Serial drivers
-#
-CONFIG_SERIAL_8250=y
-CONFIG_SERIAL_8250_CONSOLE=y
-CONFIG_SERIAL_8250_PCI=y
-CONFIG_SERIAL_8250_PNP=y
-CONFIG_SERIAL_8250_NR_UARTS=6
-CONFIG_SERIAL_8250_RUNTIME_UARTS=4
-CONFIG_SERIAL_8250_EXTENDED=y
-CONFIG_SERIAL_8250_SHARE_IRQ=y
-# CONFIG_SERIAL_8250_DETECT_IRQ is not set
-# CONFIG_SERIAL_8250_RSA is not set
-
-#
-# Non-8250 serial port support
-#
-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
-# CONFIG_IPMI_HANDLER is not set
-# CONFIG_WATCHDOG is not set
-# CONFIG_HW_RANDOM is not set
-CONFIG_EFI_RTC=y
-# CONFIG_R3964 is not set
-# CONFIG_APPLICOM is not set
-CONFIG_AGP=m
-CONFIG_AGP_I460=m
CONFIG_DRM=m
-CONFIG_DRM_TDFX=m
+CONFIG_DRM_MGA=m
CONFIG_DRM_R128=m
CONFIG_DRM_RADEON=m
-CONFIG_DRM_MGA=m
CONFIG_DRM_SIS=m
-# CONFIG_DRM_VIA is not set
-# CONFIG_DRM_SAVAGE is not set
-CONFIG_RAW_DRIVER=m
-CONFIG_MAX_RAW_DEVS=256
-CONFIG_HPET=y
-# CONFIG_HPET_RTC_IRQ is not set
-CONFIG_HPET_MMAP=y
-# CONFIG_HANGCHECK_TIMER is not set
-# 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
-# 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_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
-# 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
-
-#
-# Console display driver support
-#
-CONFIG_VGA_CONSOLE=y
-# CONFIG_VGACON_SOFT_SCROLLBACK is not set
-CONFIG_DUMMY_CONSOLE=y
-
-#
-# Sound
-#
-# CONFIG_SOUND is not set
-CONFIG_HID_SUPPORT=y
-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
-CONFIG_USB_SUPPORT=y
-CONFIG_USB_ARCH_HAS_HCD=y
-CONFIG_USB_ARCH_HAS_OHCI=y
-CONFIG_USB_ARCH_HAS_EHCI=y
-CONFIG_USB=y
-# CONFIG_USB_DEBUG is not set
-
-#
-# 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
-
-#
-# USB Host Controller Drivers
-#
-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_ISP116X_HCD is not set
-CONFIG_USB_OHCI_HCD=m
-# 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_UHCI_HCD=y
-# CONFIG_USB_SL811_HCD is not set
-# CONFIG_USB_R8A66597_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=m
-# CONFIG_USB_STORAGE_DEBUG is not set
-# CONFIG_USB_STORAGE_DATAFAB is not set
-# CONFIG_USB_STORAGE_FREECOM is not set
-# CONFIG_USB_STORAGE_ISD200 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_SISUSBVGA 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 is not set
-
-#
-# LED devices
-#
-# CONFIG_NEW_LEDS is not set
-
-#
-# LED drivers
-#
-
-#
-# LED Triggers
-#
-# CONFIG_INFINIBAND is not set
-
-#
-# Real Time Clock
-#
-# CONFIG_RTC_CLASS is not set
-
-#
-# DMA Engine support
-#
-# CONFIG_DMA_ENGINE is not set
-
-#
-# DMA Clients
-#
-
-#
-# DMA Devices
-#
-
-#
-# Userspace I/O
-#
-# CONFIG_UIO is not set
-# CONFIG_MSPEC is not set
-
-#
-# File systems
-#
-CONFIG_EXT2_FS=y
-CONFIG_EXT2_FS_XATTR=y
+CONFIG_DRM_TDFX=m
+CONFIG_DUMMY=m
+CONFIG_E1000=y
+CONFIG_E100=m
+CONFIG_EFI_PARTITION=y
+CONFIG_EFI_RTC=y
+CONFIG_EFI_VARS=y
+CONFIG_EXPERIMENTAL=y
CONFIG_EXT2_FS_POSIX_ACL=y
CONFIG_EXT2_FS_SECURITY=y
-# CONFIG_EXT2_FS_XIP is not set
-CONFIG_EXT3_FS=y
-CONFIG_EXT3_FS_XATTR=y
+CONFIG_EXT2_FS_XATTR=y
+CONFIG_EXT2_FS=y
CONFIG_EXT3_FS_POSIX_ACL=y
CONFIG_EXT3_FS_SECURITY=y
-# CONFIG_EXT4DEV_FS is not set
-CONFIG_JBD=y
-# CONFIG_JBD_DEBUG is not set
-CONFIG_FS_MBCACHE=y
-CONFIG_REISERFS_FS=y
-# CONFIG_REISERFS_CHECK is not set
-# CONFIG_REISERFS_PROC_INFO is not set
-CONFIG_REISERFS_FS_XATTR=y
-CONFIG_REISERFS_FS_POSIX_ACL=y
-CONFIG_REISERFS_FS_SECURITY=y
-# CONFIG_JFS_FS is not set
-CONFIG_FS_POSIX_ACL=y
-CONFIG_XFS_FS=y
-# CONFIG_XFS_QUOTA is not set
-# CONFIG_XFS_SECURITY is not set
-# CONFIG_XFS_POSIX_ACL is not set
-# CONFIG_XFS_RT 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_EXT3_FS=y
+CONFIG_FORCE_CPEI_RETARGET=y
+CONFIG_FUSION_CTL=y
+CONFIG_FUSION_FC=y
+CONFIG_FUSION_SPI=y
+CONFIG_FUSION=y
+CONFIG_GAMEPORT=m
+CONFIG_HOTPLUG_CPU=y
+CONFIG_HOTPLUG_PCI_ACPI=m
+CONFIG_HOTPLUG_PCI=m
+CONFIG_HPET=y
+CONFIG_HUGETLBFS=y
+# CONFIG_HW_RANDOM is not set
+CONFIG_IA64_CYCLONE=y
+CONFIG_IA64_DIG=y
+CONFIG_IA64_GRANULE_16MB=y
+CONFIG_IA64_MCA_RECOVERY=y
+CONFIG_IA64_PAGE_SIZE_64KB=y
+CONFIG_IA64_PALINFO=y
+CONFIG_IDE=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_IKCONFIG=y
+CONFIG_INET=y
CONFIG_INOTIFY=y
-CONFIG_INOTIFY_USER=y
-# CONFIG_QUOTA is not set
-CONFIG_DNOTIFY=y
-CONFIG_AUTOFS_FS=y
-CONFIG_AUTOFS4_FS=y
-# CONFIG_FUSE_FS is not set
-
-#
-# CD-ROM/DVD Filesystems
-#
+CONFIG_IP_MULTICAST=y
+# CONFIG_IPV6 is not set
CONFIG_ISO9660_FS=m
CONFIG_JOLIET=y
-# CONFIG_ZISOFS is not set
-CONFIG_UDF_FS=m
-CONFIG_UDF_NLS=y
-
-#
-# DOS/FAT/NT Filesystems
-#
-CONFIG_FAT_FS=y
-# CONFIG_MSDOS_FS is not set
-CONFIG_VFAT_FS=y
-CONFIG_FAT_DEFAULT_CODEPAGE=437
-CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
-CONFIG_NTFS_FS=m
-# CONFIG_NTFS_DEBUG is not set
-# CONFIG_NTFS_RW 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
-
-#
-# Network File Systems
-#
+CONFIG_KALLSYMS_ALL=y
+CONFIG_KEXEC=y
+CONFIG_LOG_BUF_SHIFT=20
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_MCKINLEY=y
+CONFIG_MD_LINEAR=m
+CONFIG_MD_MULTIPATH=m
+CONFIG_MD_RAID0=m
+CONFIG_MD_RAID1=m
+CONFIG_MD=y
+CONFIG_MODULE_SRCVERSION_ALL=y
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODVERSIONS=y
+CONFIG_NETCONSOLE=y
+CONFIG_NETDEVICES=y
+CONFIG_NET_ETHERNET=y
+CONFIG_NET_PCI=y
+CONFIG_NET_TULIP=y
+CONFIG_NFSD=m
+CONFIG_NFSD_V4=y
CONFIG_NFS_FS=m
CONFIG_NFS_V3=y
-# CONFIG_NFS_V3_ACL is not set
CONFIG_NFS_V4=y
-CONFIG_NFS_DIRECTIO=y
-CONFIG_NFSD=m
-CONFIG_NFSD_V3=y
-# CONFIG_NFSD_V3_ACL is not set
-CONFIG_NFSD_V4=y
-CONFIG_NFSD_TCP=y
-CONFIG_LOCKD=m
-CONFIG_LOCKD_V4=y
-CONFIG_EXPORTFS=m
-CONFIG_NFS_COMMON=y
-CONFIG_SUNRPC=m
-CONFIG_SUNRPC_GSS=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
-CONFIG_SMB_NLS_REMOTE="cp437"
-CONFIG_CIFS=m
-# CONFIG_CIFS_STATS is not set
-# CONFIG_CIFS_WEAK_PW_HASH is not set
-# CONFIG_CIFS_XATTR is not set
-# CONFIG_CIFS_DEBUG2 is not set
-# CONFIG_CIFS_EXPERIMENTAL is not set
-# CONFIG_NCP_FS is not set
-# CONFIG_CODA_FS is not set
-# CONFIG_AFS_FS is not set
-
-#
-# Partition Types
-#
-CONFIG_PARTITION_ADVANCED=y
-# CONFIG_ACORN_PARTITION is not set
-# CONFIG_OSF_PARTITION is not set
-# CONFIG_AMIGA_PARTITION is not set
-# CONFIG_ATARI_PARTITION is not set
-# CONFIG_MAC_PARTITION is not set
-CONFIG_MSDOS_PARTITION=y
-# CONFIG_BSD_DISKLABEL is not set
-# CONFIG_MINIX_SUBPARTITION is not set
-# CONFIG_SOLARIS_X86_PARTITION is not set
-# CONFIG_UNIXWARE_DISKLABEL is not set
-# CONFIG_LDM_PARTITION is not set
-CONFIG_SGI_PARTITION=y
-# CONFIG_ULTRIX_PARTITION is not set
-# 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
-#
-CONFIG_NLS=y
-CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_1250=m
+CONFIG_NLS_CODEPAGE_1251=m
CONFIG_NLS_CODEPAGE_437=y
CONFIG_NLS_CODEPAGE_737=m
CONFIG_NLS_CODEPAGE_775=m
@@ -1144,15 +123,14 @@ CONFIG_NLS_CODEPAGE_864=m
CONFIG_NLS_CODEPAGE_865=m
CONFIG_NLS_CODEPAGE_866=m
CONFIG_NLS_CODEPAGE_869=m
-CONFIG_NLS_CODEPAGE_936=m
-CONFIG_NLS_CODEPAGE_950=m
+CONFIG_NLS_CODEPAGE_874=m
CONFIG_NLS_CODEPAGE_932=m
+CONFIG_NLS_CODEPAGE_936=m
CONFIG_NLS_CODEPAGE_949=m
-CONFIG_NLS_CODEPAGE_874=m
-CONFIG_NLS_ISO8859_8=m
-CONFIG_NLS_CODEPAGE_1250=m
-CONFIG_NLS_CODEPAGE_1251=m
-# CONFIG_NLS_ASCII is not set
+CONFIG_NLS_CODEPAGE_950=m
+CONFIG_NLS_ISO8859_13=m
+CONFIG_NLS_ISO8859_14=m
+CONFIG_NLS_ISO8859_15=m
CONFIG_NLS_ISO8859_1=y
CONFIG_NLS_ISO8859_2=m
CONFIG_NLS_ISO8859_3=m
@@ -1160,120 +138,50 @@ CONFIG_NLS_ISO8859_4=m
CONFIG_NLS_ISO8859_5=m
CONFIG_NLS_ISO8859_6=m
CONFIG_NLS_ISO8859_7=m
+CONFIG_NLS_ISO8859_8=m
CONFIG_NLS_ISO8859_9=m
-CONFIG_NLS_ISO8859_13=m
-CONFIG_NLS_ISO8859_14=m
-CONFIG_NLS_ISO8859_15=m
CONFIG_NLS_KOI8_R=m
CONFIG_NLS_KOI8_U=m
CONFIG_NLS_UTF8=m
-
-#
-# Distributed Lock Manager
-#
-# CONFIG_DLM 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_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
-CONFIG_IRQ_PER_CPU=y
-
-#
-# Instrumentation Support
-#
-# CONFIG_PROFILING is not set
-# CONFIG_KPROBES 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=y
-CONFIG_SCHED_DEBUG=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=y
-# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
-# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
-# CONFIG_DEBUG_KOBJECT is not set
-# CONFIG_DEBUG_INFO is not set
-# CONFIG_DEBUG_VM is not set
-# CONFIG_DEBUG_LIST is not set
-CONFIG_FORCED_INLINING=y
-# CONFIG_RCU_TORTURE_TEST is not set
-# CONFIG_FAULT_INJECTION is not set
-CONFIG_IA64_GRANULE_16MB=y
-# CONFIG_IA64_GRANULE_64MB is not set
-# CONFIG_IA64_PRINT_HAZARDS is not set
-# CONFIG_DISABLE_VHPT is not set
-# CONFIG_IA64_DEBUG_CMPXCHG is not set
-# CONFIG_IA64_DEBUG_IRQ is not set
-
-#
-# Security options
-#
-# CONFIG_KEYS is not set
-# CONFIG_SECURITY is not set
-CONFIG_CRYPTO=y
-CONFIG_CRYPTO_ALGAPI=y
-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=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=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
-# 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
-CONFIG_CRYPTO_HW=y
+CONFIG_NR_CPUS=16
+CONFIG_NTFS_FS=m
+CONFIG_PACKET=y
+CONFIG_PARTITION_ADVANCED=y
+CONFIG_PERFMON=y
+CONFIG_PERMIT_BSP_REMOVE=y
+CONFIG_POSIX_MQUEUE=y
+CONFIG_PROC_KCORE=y
+CONFIG_RAW_DRIVER=m
+CONFIG_REISERFS_FS_POSIX_ACL=y
+CONFIG_REISERFS_FS_SECURITY=y
+CONFIG_REISERFS_FS_XATTR=y
+CONFIG_REISERFS_FS=y
+CONFIG_SCSI_QLOGIC_1280=y
+CONFIG_SCSI_SYM53C8XX_2=y
+CONFIG_SCSI=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_EXTENDED=y
+CONFIG_SERIAL_8250_NR_UARTS=6
+CONFIG_SERIAL_8250_SHARE_IRQ=y
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_NONSTANDARD=y
+# CONFIG_SERIO_SERPORT is not set
+CONFIG_SGI_PARTITION=y
+CONFIG_SMB_FS=m
+CONFIG_SMB_NLS_DEFAULT=y
+CONFIG_SMP=y
+CONFIG_SYN_COOKIES=y
+CONFIG_SYSVIPC=y
+CONFIG_TIGON3=y
+CONFIG_TMPFS=y
+CONFIG_TULIP=m
+CONFIG_UDF_FS=m
+CONFIG_UNIX=y
+CONFIG_USB_DEVICEFS=y
+CONFIG_USB_EHCI_HCD=m
+CONFIG_USB_OHCI_HCD=m
+CONFIG_USB_STORAGE=m
+CONFIG_USB_UHCI_HCD=y
+CONFIG_USB=y
+CONFIG_VFAT_FS=y
+CONFIG_XFS_FS=y
diff --git a/arch/ia64/configs/xen_domu_defconfig b/arch/ia64/configs/xen_domu_defconfig
index c67eafc4bb3..5f6d284723a 100644
--- a/arch/ia64/configs/xen_domu_defconfig
+++ b/arch/ia64/configs/xen_domu_defconfig
@@ -1,1374 +1,121 @@
-#
-# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.29-rc1
-# Fri Jan 16 11:49:59 2009
-#
-CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
-
-#
-# General setup
-#
-CONFIG_EXPERIMENTAL=y
-CONFIG_LOCK_KERNEL=y
-CONFIG_INIT_ENV_ARG_LIMIT=32
-CONFIG_LOCALVERSION=""
-CONFIG_LOCALVERSION_AUTO=y
-CONFIG_SWAP=y
-CONFIG_SYSVIPC=y
-CONFIG_SYSVIPC_SYSCTL=y
-CONFIG_POSIX_MQUEUE=y
-# CONFIG_BSD_PROCESS_ACCT is not set
-# CONFIG_TASKSTATS is not set
-# CONFIG_AUDIT is not set
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_LOG_BUF_SHIFT=20
-CONFIG_HAVE_UNSTABLE_SCHED_CLOCK=y
-# CONFIG_GROUP_SCHED is not set
-
-#
-# Control Group support
-#
-# CONFIG_CGROUPS is not set
-CONFIG_SYSFS_DEPRECATED=y
-CONFIG_SYSFS_DEPRECATED_V2=y
-# CONFIG_RELAY is not set
-CONFIG_NAMESPACES=y
-# CONFIG_UTS_NS is not set
-# CONFIG_IPC_NS is not set
-# CONFIG_USER_NS is not set
-# CONFIG_PID_NS is not set
-CONFIG_BLK_DEV_INITRD=y
-CONFIG_INITRAMFS_SOURCE=""
-CONFIG_CC_OPTIMIZE_FOR_SIZE=y
-CONFIG_SYSCTL=y
-# CONFIG_EMBEDDED is not set
-CONFIG_SYSCTL_SYSCALL=y
-CONFIG_KALLSYMS=y
-CONFIG_KALLSYMS_ALL=y
-CONFIG_KALLSYMS_STRIP_GENERATED=y
-# CONFIG_KALLSYMS_EXTRA_PASS is not set
-CONFIG_HOTPLUG=y
-CONFIG_PRINTK=y
-CONFIG_BUG=y
-CONFIG_ELF_CORE=y
-CONFIG_COMPAT_BRK=y
-CONFIG_BASE_FULL=y
-CONFIG_FUTEX=y
-CONFIG_ANON_INODES=y
-CONFIG_EPOLL=y
-CONFIG_SIGNALFD=y
-CONFIG_TIMERFD=y
-CONFIG_EVENTFD=y
-CONFIG_SHMEM=y
-CONFIG_AIO=y
-CONFIG_VM_EVENT_COUNTERS=y
-CONFIG_PCI_QUIRKS=y
-CONFIG_SLUB_DEBUG=y
-# CONFIG_SLAB is not set
-CONFIG_SLUB=y
-# CONFIG_SLOB is not set
-# CONFIG_PROFILING is not set
-CONFIG_HAVE_OPROFILE=y
-# CONFIG_KPROBES is not set
-CONFIG_HAVE_KPROBES=y
-CONFIG_HAVE_KRETPROBES=y
-CONFIG_HAVE_ARCH_TRACEHOOK=y
-CONFIG_HAVE_DMA_ATTRS=y
-CONFIG_USE_GENERIC_SMP_HELPERS=y
-# CONFIG_HAVE_GENERIC_DMA_COHERENT is not set
-CONFIG_SLABINFO=y
-CONFIG_RT_MUTEXES=y
-CONFIG_BASE_SMALL=0
-CONFIG_MODULES=y
-# CONFIG_MODULE_FORCE_LOAD is not set
-CONFIG_MODULE_UNLOAD=y
-# CONFIG_MODULE_FORCE_UNLOAD is not set
-CONFIG_MODVERSIONS=y
-CONFIG_MODULE_SRCVERSION_ALL=y
-CONFIG_STOP_MACHINE=y
-CONFIG_BLOCK=y
-# CONFIG_BLK_DEV_IO_TRACE is not set
-# CONFIG_BLK_DEV_BSG is not set
-# CONFIG_BLK_DEV_INTEGRITY 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"
-CONFIG_CLASSIC_RCU=y
-# CONFIG_TREE_RCU is not set
-# CONFIG_PREEMPT_RCU is not set
-# CONFIG_TREE_RCU_TRACE is not set
-# CONFIG_PREEMPT_RCU_TRACE is not set
-CONFIG_FREEZER=y
-
-#
-# Processor type and features
-#
-CONFIG_IA64=y
-CONFIG_64BIT=y
-CONFIG_ZONE_DMA=y
-CONFIG_QUICKLIST=y
-CONFIG_MMU=y
-CONFIG_SWIOTLB=y
-CONFIG_IOMMU_HELPER=y
-CONFIG_RWSEM_XCHGADD_ALGORITHM=y
-CONFIG_HUGETLB_PAGE_SIZE_VARIABLE=y
-CONFIG_GENERIC_FIND_NEXT_BIT=y
-CONFIG_GENERIC_CALIBRATE_DELAY=y
-CONFIG_GENERIC_TIME=y
-CONFIG_GENERIC_TIME_VSYSCALL=y
-CONFIG_HAVE_SETUP_PER_CPU_AREA=y
-CONFIG_DMI=y
-CONFIG_EFI=y
-CONFIG_GENERIC_IOMAP=y
-CONFIG_SCHED_OMIT_FRAME_POINTER=y
-CONFIG_AUDIT_ARCH=y
-CONFIG_PARAVIRT_GUEST=y
-CONFIG_PARAVIRT=y
-CONFIG_XEN=y
-CONFIG_XEN_XENCOMM=y
-CONFIG_NO_IDLE_HZ=y
-# CONFIG_IA64_GENERIC is not set
-# CONFIG_IA64_DIG is not set
-# CONFIG_IA64_DIG_VTD is not set
-# CONFIG_IA64_HP_ZX1 is not set
-# CONFIG_IA64_HP_ZX1_SWIOTLB is not set
-# CONFIG_IA64_SGI_SN2 is not set
-# CONFIG_IA64_SGI_UV is not set
-# CONFIG_IA64_HP_SIM is not set
-CONFIG_IA64_XEN_GUEST=y
-# CONFIG_ITANIUM is not set
-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_PGTABLE_3=y
-# CONFIG_PGTABLE_4 is not set
-CONFIG_HZ=250
-# CONFIG_HZ_100 is not set
-CONFIG_HZ_250=y
-# CONFIG_HZ_300 is not set
-# CONFIG_HZ_1000 is not set
-# CONFIG_SCHED_HRTICK is not set
-CONFIG_IA64_L1_CACHE_SHIFT=7
-CONFIG_IA64_CYCLONE=y
-CONFIG_IOSAPIC=y
-CONFIG_FORCE_MAX_ZONEORDER=17
-# CONFIG_VIRT_CPU_ACCOUNTING is not set
-CONFIG_SMP=y
-CONFIG_NR_CPUS=16
-CONFIG_HOTPLUG_CPU=y
-CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
-CONFIG_ARCH_ENABLE_MEMORY_HOTREMOVE=y
-# CONFIG_SCHED_SMT is not set
-CONFIG_PERMIT_BSP_REMOVE=y
-CONFIG_FORCE_CPEI_RETARGET=y
-CONFIG_PREEMPT_NONE=y
-# CONFIG_PREEMPT_VOLUNTARY is not set
-# CONFIG_PREEMPT is not set
-CONFIG_SELECT_MEMORY_MODEL=y
-CONFIG_FLATMEM_MANUAL=y
-# CONFIG_DISCONTIGMEM_MANUAL is not set
-# CONFIG_SPARSEMEM_MANUAL is not set
-CONFIG_FLATMEM=y
-CONFIG_FLAT_NODE_MEM_MAP=y
-CONFIG_SPARSEMEM_VMEMMAP_ENABLE=y
-CONFIG_PAGEFLAGS_EXTENDED=y
-CONFIG_SPLIT_PTLOCK_CPUS=4
-CONFIG_MIGRATION=y
-CONFIG_PHYS_ADDR_T_64BIT=y
-CONFIG_ZONE_DMA_FLAG=1
-CONFIG_BOUNCE=y
-CONFIG_NR_QUICK=1
-CONFIG_VIRT_TO_BUS=y
-CONFIG_UNEVICTABLE_LRU=y
-CONFIG_ARCH_SELECT_MEMORY_MODEL=y
-CONFIG_ARCH_DISCONTIGMEM_ENABLE=y
-CONFIG_ARCH_FLATMEM_ENABLE=y
-CONFIG_ARCH_SPARSEMEM_ENABLE=y
-CONFIG_ARCH_POPULATES_NODE_MAP=y
-CONFIG_VIRTUAL_MEM_MAP=y
-CONFIG_HOLES_IN_ZONE=y
-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_IA64_HP_AML_NFW is not set
-CONFIG_KEXEC=y
-# CONFIG_CRASH_DUMP is not set
-
-#
-# Firmware Drivers
-#
-# CONFIG_FIRMWARE_MEMMAP is not set
-CONFIG_EFI_VARS=y
-CONFIG_EFI_PCDP=y
-CONFIG_DMIID=y
-CONFIG_BINFMT_ELF=y
-# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
-# CONFIG_HAVE_AOUT is not set
-CONFIG_BINFMT_MISC=m
-
-#
-# Power management and ACPI options
-#
-CONFIG_PM=y
-# CONFIG_PM_DEBUG is not set
-CONFIG_PM_SLEEP=y
-CONFIG_SUSPEND=y
-CONFIG_SUSPEND_FREEZER=y
-CONFIG_ACPI=y
-CONFIG_ACPI_SLEEP=y
-CONFIG_ACPI_PROCFS=y
-CONFIG_ACPI_PROCFS_POWER=y
-CONFIG_ACPI_SYSFS_POWER=y
-CONFIG_ACPI_PROC_EVENT=y
CONFIG_ACPI_BUTTON=m
+CONFIG_ACPI_CONTAINER=m
CONFIG_ACPI_FAN=m
-# CONFIG_ACPI_DOCK is not set
CONFIG_ACPI_PROCESSOR=m
-CONFIG_ACPI_HOTPLUG_CPU=y
-CONFIG_ACPI_THERMAL=m
-# CONFIG_ACPI_CUSTOM_DSDT is not set
-CONFIG_ACPI_BLACKLIST_YEAR=0
-# CONFIG_ACPI_DEBUG is not set
-# CONFIG_ACPI_PCI_SLOT is not set
-CONFIG_ACPI_SYSTEM=y
-CONFIG_ACPI_CONTAINER=m
-
-#
-# CPU Frequency scaling
-#
-# CONFIG_CPU_FREQ is not set
-
-#
-# Bus options (PCI, PCMCIA)
-#
-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_LEGACY=y
-# CONFIG_PCI_DEBUG is not set
-# CONFIG_PCI_STUB is not set
-CONFIG_HOTPLUG_PCI=m
-# CONFIG_HOTPLUG_PCI_FAKE is not set
-CONFIG_HOTPLUG_PCI_ACPI=m
-# CONFIG_HOTPLUG_PCI_ACPI_IBM is not set
-# CONFIG_HOTPLUG_PCI_CPCI is not set
-# CONFIG_HOTPLUG_PCI_SHPC is not set
-# CONFIG_PCCARD is not set
-CONFIG_NET=y
-
-#
-# Networking options
-#
-# CONFIG_NET_NS is not set
-CONFIG_COMPAT_NET_DEV_OPS=y
-CONFIG_PACKET=y
-# CONFIG_PACKET_MMAP is not set
-CONFIG_UNIX=y
-CONFIG_XFRM=y
-# CONFIG_XFRM_USER is not set
-# CONFIG_XFRM_SUB_POLICY is not set
-# CONFIG_XFRM_MIGRATE is not set
-# CONFIG_XFRM_STATISTICS is not set
-# CONFIG_NET_KEY is not set
-CONFIG_INET=y
-CONFIG_IP_MULTICAST=y
-# CONFIG_IP_ADVANCED_ROUTER is not set
-CONFIG_IP_FIB_HASH=y
-# CONFIG_IP_PNP is not set
-# CONFIG_NET_IPIP is not set
-# CONFIG_NET_IPGRE is not set
-# CONFIG_IP_MROUTE is not set
+CONFIG_ACPI_PROCFS=y
+CONFIG_AGP=m
CONFIG_ARPD=y
-CONFIG_SYN_COOKIES=y
-# CONFIG_INET_AH is not set
-# CONFIG_INET_ESP is not set
-# CONFIG_INET_IPCOMP is not set
-# CONFIG_INET_XFRM_TUNNEL is not set
-# CONFIG_INET_TUNNEL is not set
-CONFIG_INET_XFRM_MODE_TRANSPORT=y
-CONFIG_INET_XFRM_MODE_TUNNEL=y
-CONFIG_INET_XFRM_MODE_BEET=y
-# CONFIG_INET_LRO is not set
-CONFIG_INET_DIAG=y
-CONFIG_INET_TCP_DIAG=y
-# CONFIG_TCP_CONG_ADVANCED is not set
-CONFIG_TCP_CONG_CUBIC=y
-CONFIG_DEFAULT_TCP_CONG="cubic"
-# CONFIG_TCP_MD5SIG is not set
-# CONFIG_IPV6 is not set
-# CONFIG_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_NET_DSA is not set
-# CONFIG_VLAN_8021Q is not set
-# CONFIG_DECNET is not set
-# CONFIG_LLC2 is not set
-# CONFIG_IPX is not set
-# CONFIG_ATALK is not set
-# CONFIG_X25 is not set
-# CONFIG_LAPB is not set
-# CONFIG_ECONET is not set
-# CONFIG_WAN_ROUTER is not set
-# CONFIG_NET_SCHED is not set
-# CONFIG_DCB is not set
-
-#
-# Network testing
-#
-# CONFIG_NET_PKTGEN is not set
-# CONFIG_HAMRADIO is not set
-# CONFIG_CAN is not set
-# CONFIG_IRDA is not set
-# CONFIG_BT is not set
-# CONFIG_AF_RXRPC is not set
-# CONFIG_PHONET is not set
-# CONFIG_WIRELESS is not set
-# CONFIG_WIMAX is not set
-# CONFIG_RFKILL is not set
-# CONFIG_NET_9P is not set
-
-#
-# Device Drivers
-#
-
-#
-# Generic Driver Options
-#
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
-CONFIG_STANDALONE=y
-CONFIG_PREVENT_FIRMWARE_BUILD=y
-CONFIG_FW_LOADER=y
-CONFIG_FIRMWARE_IN_KERNEL=y
-CONFIG_EXTRA_FIRMWARE=""
-# CONFIG_DEBUG_DRIVER is not set
-# CONFIG_DEBUG_DEVRES is not set
-# CONFIG_SYS_HYPERVISOR is not set
-# CONFIG_CONNECTOR is not set
-# CONFIG_MTD is not set
-# CONFIG_PARPORT is not set
-CONFIG_PNP=y
-CONFIG_PNP_DEBUG_MESSAGES=y
-
-#
-# Protocols
-#
-CONFIG_PNPACPI=y
-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
-# CONFIG_BLK_DEV_UMEM is not set
-# CONFIG_BLK_DEV_COW_COMMON is not set
-CONFIG_BLK_DEV_LOOP=m
+CONFIG_AUTOFS4_FS=y
+CONFIG_AUTOFS_FS=y
+CONFIG_BINFMT_MISC=m
+# CONFIG_BLK_DEV_BSG is not set
+CONFIG_BLK_DEV_CMD64X=y
CONFIG_BLK_DEV_CRYPTOLOOP=m
-CONFIG_BLK_DEV_NBD=m
-# CONFIG_BLK_DEV_SX8 is not set
-# CONFIG_BLK_DEV_UB is not set
-CONFIG_BLK_DEV_RAM=y
-CONFIG_BLK_DEV_RAM_COUNT=16
-CONFIG_BLK_DEV_RAM_SIZE=4096
-# CONFIG_BLK_DEV_XIP is not set
-# CONFIG_CDROM_PKTCDVD is not set
-# CONFIG_ATA_OVER_ETH is not set
-CONFIG_XEN_BLKDEV_FRONTEND=y
-# CONFIG_BLK_DEV_HD is not set
-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_ICS932S401 is not set
-# CONFIG_ENCLOSURE_SERVICES is not set
-# CONFIG_HP_ILO is not set
-# CONFIG_C2PORT is not set
-CONFIG_HAVE_IDE=y
-CONFIG_IDE=y
-
-#
-# Please see Documentation/ide/ide.txt for help/info on IDE drives
-#
-CONFIG_IDE_TIMINGS=y
-CONFIG_IDE_ATAPI=y
-# CONFIG_BLK_DEV_IDE_SATA is not set
-CONFIG_IDE_GD=y
-CONFIG_IDE_GD_ATA=y
-# CONFIG_IDE_GD_ATAPI is not set
-CONFIG_BLK_DEV_IDECD=y
-CONFIG_BLK_DEV_IDECD_VERBOSE_ERRORS=y
-# CONFIG_BLK_DEV_IDETAPE is not set
-# CONFIG_BLK_DEV_IDEACPI is not set
-# CONFIG_IDE_TASK_IOCTL is not set
-CONFIG_IDE_PROC_FS=y
-
-#
-# IDE chipset support/bugfixes
-#
-# CONFIG_IDE_GENERIC is not set
-# CONFIG_BLK_DEV_PLATFORM is not set
-# CONFIG_BLK_DEV_IDEPNP is not set
-CONFIG_BLK_DEV_IDEDMA_SFF=y
-
-#
-# PCI IDE chipsets support
-#
-CONFIG_BLK_DEV_IDEPCI=y
-CONFIG_IDEPCI_PCIBUS_ORDER=y
-# CONFIG_BLK_DEV_OFFBOARD is not set
+CONFIG_BLK_DEV_DM=m
CONFIG_BLK_DEV_GENERIC=y
-# CONFIG_BLK_DEV_OPTI621 is not set
-CONFIG_BLK_DEV_IDEDMA_PCI=y
-# CONFIG_BLK_DEV_AEC62XX is not set
-# CONFIG_BLK_DEV_ALI15X3 is not set
-# CONFIG_BLK_DEV_AMD74XX is not set
-CONFIG_BLK_DEV_CMD64X=y
-# CONFIG_BLK_DEV_TRIFLEX is not set
-# CONFIG_BLK_DEV_CS5520 is not set
-# CONFIG_BLK_DEV_CS5530 is not set
-# CONFIG_BLK_DEV_HPT366 is not set
-# CONFIG_BLK_DEV_JMICRON is not set
-# CONFIG_BLK_DEV_SC1200 is not set
+CONFIG_BLK_DEV_IDECD=y
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_BLK_DEV_LOOP=m
+CONFIG_BLK_DEV_MD=m
+CONFIG_BLK_DEV_NBD=m
CONFIG_BLK_DEV_PIIX=y
-# CONFIG_BLK_DEV_IT8172 is not set
-# CONFIG_BLK_DEV_IT8213 is not set
-# CONFIG_BLK_DEV_IT821X is not set
-# CONFIG_BLK_DEV_NS87415 is not set
-# CONFIG_BLK_DEV_PDC202XX_OLD is not set
-# CONFIG_BLK_DEV_PDC202XX_NEW is not set
-# CONFIG_BLK_DEV_SVWKS is not set
-# CONFIG_BLK_DEV_SIIMAGE is not set
-# CONFIG_BLK_DEV_SLC90E66 is not set
-# CONFIG_BLK_DEV_TRM290 is not set
-# CONFIG_BLK_DEV_VIA82CXXX is not set
-# CONFIG_BLK_DEV_TC86C001 is not set
-CONFIG_BLK_DEV_IDEDMA=y
-
-#
-# SCSI device support
-#
-# 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
-
-#
-# SCSI support type (disk, tape, CD-ROM)
-#
+CONFIG_BLK_DEV_RAM=y
CONFIG_BLK_DEV_SD=y
-CONFIG_CHR_DEV_ST=m
-# CONFIG_CHR_DEV_OSST is not set
CONFIG_BLK_DEV_SR=m
-# CONFIG_BLK_DEV_SR_VENDOR 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=y
-CONFIG_SCSI_FC_ATTRS=y
-# CONFIG_SCSI_ISCSI_ATTRS is not set
-# CONFIG_SCSI_SAS_LIBSAS is not set
-# CONFIG_SCSI_SRP_ATTRS is not set
-CONFIG_SCSI_LOWLEVEL=y
-# CONFIG_ISCSI_TCP is not set
-# CONFIG_SCSI_CXGB3_ISCSI 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_ADVANSYS 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_LIBFC is not set
-# CONFIG_FCOE 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_MVSAS is not set
-# CONFIG_SCSI_STEX is not set
-CONFIG_SCSI_SYM53C8XX_2=y
-CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=1
-CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16
-CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64
-CONFIG_SCSI_SYM53C8XX_MMIO=y
-CONFIG_SCSI_QLOGIC_1280=y
-# 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_DEBUG is not set
-# CONFIG_SCSI_SRP is not set
-# CONFIG_SCSI_DH is not set
-# CONFIG_ATA is not set
-CONFIG_MD=y
-CONFIG_BLK_DEV_MD=m
-CONFIG_MD_LINEAR=m
-CONFIG_MD_RAID0=m
-CONFIG_MD_RAID1=m
-# CONFIG_MD_RAID10 is not set
-# CONFIG_MD_RAID456 is not set
-CONFIG_MD_MULTIPATH=m
-# CONFIG_MD_FAULTY is not set
-CONFIG_BLK_DEV_DM=m
-# CONFIG_DM_DEBUG is not set
+CONFIG_CHR_DEV_ST=m
+CONFIG_CIFS=m
+# CONFIG_CRYPTO_ANSI_CPRNG is not set
+CONFIG_CRYPTO_ECB=m
+CONFIG_CRYPTO_MD5=y
+CONFIG_CRYPTO_PCBC=m
+CONFIG_DEBUG_KERNEL=y
+CONFIG_DEBUG_MUTEXES=y
CONFIG_DM_CRYPT=m
-CONFIG_DM_SNAPSHOT=m
CONFIG_DM_MIRROR=m
+CONFIG_DM_SNAPSHOT=m
CONFIG_DM_ZERO=m
-# CONFIG_DM_MULTIPATH is not set
-# CONFIG_DM_DELAY is not set
-# CONFIG_DM_UEVENT is not set
-CONFIG_FUSION=y
-CONFIG_FUSION_SPI=y
-CONFIG_FUSION_FC=y
-# CONFIG_FUSION_SAS is not set
-CONFIG_FUSION_MAX_SGE=128
-CONFIG_FUSION_CTL=y
-# CONFIG_FUSION_LOGGING is not set
-
-#
-# IEEE 1394 (FireWire) support
-#
-
-#
-# Enable only one of the two stacks, unless you know what you are doing
-#
-# CONFIG_FIREWIRE is not set
-# CONFIG_IEEE1394 is not set
-# CONFIG_I2O is not set
-CONFIG_NETDEVICES=y
-CONFIG_DUMMY=m
-# CONFIG_BONDING is not set
-# CONFIG_MACVLAN is not set
-# CONFIG_EQUALIZER is not set
-# CONFIG_TUN is not set
-# CONFIG_VETH is not set
-# CONFIG_NET_SB1000 is not set
-# CONFIG_ARCNET is not set
-CONFIG_PHYLIB=y
-
-#
-# MII PHY device drivers
-#
-# CONFIG_MARVELL_PHY is not set
-# CONFIG_DAVICOM_PHY is not set
-# CONFIG_QSEMI_PHY is not set
-# CONFIG_LXT_PHY is not set
-# CONFIG_CICADA_PHY is not set
-# CONFIG_VITESSE_PHY is not set
-# CONFIG_SMSC_PHY is not set
-# CONFIG_BROADCOM_PHY is not set
-# CONFIG_ICPLUS_PHY is not set
-# CONFIG_REALTEK_PHY is not set
-# CONFIG_NATIONAL_PHY is not set
-# CONFIG_STE10XP is not set
-# CONFIG_LSI_ET1011C_PHY is not set
-# CONFIG_FIXED_PHY is not set
-# CONFIG_MDIO_BITBANG is not set
-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
-CONFIG_NET_TULIP=y
-# CONFIG_DE2104X is not set
-CONFIG_TULIP=m
-# CONFIG_TULIP_MWI is not set
-# CONFIG_TULIP_MMIO is not set
-# CONFIG_TULIP_NAPI is not set
-# CONFIG_DE4X5 is not set
-# CONFIG_WINBOND_840 is not set
-# CONFIG_DM9102 is not set
-# CONFIG_ULI526X is not set
-# CONFIG_HP100 is not set
-# CONFIG_IBM_NEW_EMAC_ZMII is not set
-# CONFIG_IBM_NEW_EMAC_RGMII is not set
-# CONFIG_IBM_NEW_EMAC_TAH is not set
-# CONFIG_IBM_NEW_EMAC_EMAC4 is not set
-# CONFIG_IBM_NEW_EMAC_NO_FLOW_CTRL is not set
-# CONFIG_IBM_NEW_EMAC_MAL_CLR_ICINTSTAT is not set
-# CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set
-CONFIG_NET_PCI=y
-# CONFIG_PCNET32 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_E100=m
-# CONFIG_FEALNX is not set
-# CONFIG_NATSEMI is not set
-# CONFIG_NE2K_PCI is not set
-# CONFIG_8139CP is not set
-# CONFIG_8139TOO is not set
-# CONFIG_R6040 is not set
-# CONFIG_SIS900 is not set
-# CONFIG_EPIC100 is not set
-# CONFIG_SMSC9420 is not set
-# CONFIG_SUNDANCE is not set
-# CONFIG_TLAN is not set
-# CONFIG_VIA_RHINE is not set
-# CONFIG_SC92031 is not set
-# CONFIG_ATL2 is not set
-CONFIG_NETDEV_1000=y
-# CONFIG_ACENIC is not set
-# CONFIG_DL2K is not set
-CONFIG_E1000=y
-# CONFIG_E1000E is not set
-# CONFIG_IP1000 is not set
-# CONFIG_IGB 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_VIA_VELOCITY is not set
-CONFIG_TIGON3=y
-# CONFIG_BNX2 is not set
-# CONFIG_QLA3XXX is not set
-# CONFIG_ATL1 is not set
-# CONFIG_ATL1E is not set
-# CONFIG_JME is not set
-CONFIG_NETDEV_10000=y
-# CONFIG_CHELSIO_T1 is not set
-CONFIG_CHELSIO_T3_DEPENDS=y
-# CONFIG_CHELSIO_T3 is not set
-# CONFIG_ENIC is not set
-# CONFIG_IXGBE 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_NIU is not set
-# CONFIG_MLX4_EN is not set
-# CONFIG_MLX4_CORE is not set
-# CONFIG_TEHUTI is not set
-# CONFIG_BNX2X is not set
-# CONFIG_QLGE is not set
-# CONFIG_SFC is not set
-# CONFIG_TR is not set
-
-#
-# Wireless LAN
-#
-# CONFIG_WLAN_PRE80211 is not set
-# CONFIG_WLAN_80211 is not set
-# CONFIG_IWLWIFI_LEDS is not set
-
-#
-# Enable WiMAX (Networking options) to see the WiMAX drivers
-#
-
-#
-# USB Network Adapters
-#
-# CONFIG_USB_CATC is not set
-# CONFIG_USB_KAWETH is not set
-# CONFIG_USB_PEGASUS is not set
-# CONFIG_USB_RTL8150 is not set
-# CONFIG_USB_USBNET is not set
-# CONFIG_WAN is not set
-CONFIG_XEN_NETDEV_FRONTEND=y
-# 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_NETCONSOLE=y
-# CONFIG_NETCONSOLE_DYNAMIC is not set
-CONFIG_NETPOLL=y
-# CONFIG_NETPOLL_TRAP is not set
-CONFIG_NET_POLL_CONTROLLER=y
-# CONFIG_ISDN is not set
-# CONFIG_PHONE is not set
-
-#
-# Input device support
-#
-CONFIG_INPUT=y
-# CONFIG_INPUT_FF_MEMLESS is not set
-# CONFIG_INPUT_POLLDEV is not set
-
-#
-# Userland interfaces
-#
-CONFIG_INPUT_MOUSEDEV=y
-CONFIG_INPUT_MOUSEDEV_PSAUX=y
-CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
-CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
-# CONFIG_INPUT_JOYDEV 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=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_ELANTECH is not set
-# CONFIG_MOUSE_PS2_TOUCHKIT is not set
-# CONFIG_MOUSE_SERIAL is not set
-# CONFIG_MOUSE_APPLETOUCH is not set
-# CONFIG_MOUSE_BCM5974 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
-
-#
-# Hardware I/O ports
-#
-CONFIG_SERIO=y
-CONFIG_SERIO_I8042=y
-# CONFIG_SERIO_SERPORT is not set
-# CONFIG_SERIO_PCIPS2 is not set
-CONFIG_SERIO_LIBPS2=y
-# CONFIG_SERIO_RAW is not set
-CONFIG_GAMEPORT=m
-# CONFIG_GAMEPORT_NS558 is not set
-# CONFIG_GAMEPORT_L4 is not set
-# CONFIG_GAMEPORT_EMU10K1 is not set
-# CONFIG_GAMEPORT_FM801 is not set
-
-#
-# Character devices
-#
-CONFIG_VT=y
-CONFIG_CONSOLE_TRANSLATIONS=y
-CONFIG_VT_CONSOLE=y
-CONFIG_HW_CONSOLE=y
-# CONFIG_VT_HW_CONSOLE_BINDING is not set
-CONFIG_DEVKMEM=y
-CONFIG_SERIAL_NONSTANDARD=y
-# CONFIG_COMPUTONE is not set
-# CONFIG_ROCKETPORT is not set
-# CONFIG_CYCLADES is not set
-# CONFIG_DIGIEPCA is not set
-# CONFIG_MOXA_INTELLIO is not set
-# CONFIG_MOXA_SMARTIO is not set
-# CONFIG_ISI is not set
-# CONFIG_SYNCLINKMP is not set
-# CONFIG_SYNCLINK_GT is not set
-# CONFIG_N_HDLC is not set
-# CONFIG_RISCOM8 is not set
-# CONFIG_SPECIALIX is not set
-# CONFIG_SX is not set
-# CONFIG_RIO is not set
-# CONFIG_STALDRV is not set
-# CONFIG_NOZOMI is not set
-
-#
-# Serial drivers
-#
-CONFIG_SERIAL_8250=y
-CONFIG_SERIAL_8250_CONSOLE=y
-CONFIG_SERIAL_8250_PCI=y
-CONFIG_SERIAL_8250_PNP=y
-CONFIG_SERIAL_8250_NR_UARTS=6
-CONFIG_SERIAL_8250_RUNTIME_UARTS=4
-CONFIG_SERIAL_8250_EXTENDED=y
-CONFIG_SERIAL_8250_SHARE_IRQ=y
-# CONFIG_SERIAL_8250_DETECT_IRQ is not set
-# CONFIG_SERIAL_8250_RSA is not set
-
-#
-# Non-8250 serial port support
-#
-CONFIG_SERIAL_CORE=y
-CONFIG_SERIAL_CORE_CONSOLE=y
-# CONFIG_SERIAL_JSM is not set
-CONFIG_UNIX98_PTYS=y
-# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
-CONFIG_LEGACY_PTYS=y
-CONFIG_LEGACY_PTY_COUNT=256
-CONFIG_HVC_DRIVER=y
-CONFIG_HVC_IRQ=y
-CONFIG_HVC_XEN=y
-# CONFIG_IPMI_HANDLER is not set
-# CONFIG_HW_RANDOM is not set
-CONFIG_EFI_RTC=y
-# CONFIG_R3964 is not set
-# CONFIG_APPLICOM is not set
-CONFIG_RAW_DRIVER=m
-CONFIG_MAX_RAW_DEVS=256
-CONFIG_HPET=y
-CONFIG_HPET_MMAP=y
-# CONFIG_HANGCHECK_TIMER is not set
-# CONFIG_TCG_TPM is not set
-CONFIG_DEVPORT=y
-CONFIG_I2C=m
-CONFIG_I2C_BOARDINFO=y
-# CONFIG_I2C_CHARDEV is not set
-CONFIG_I2C_HELPER_AUTO=y
-CONFIG_I2C_ALGOBIT=m
-
-#
-# I2C Hardware Bus support
-#
-
-#
-# PC SMBus host controller drivers
-#
-# 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_ISCH is not set
-# CONFIG_I2C_PIIX4 is not set
-# CONFIG_I2C_NFORCE2 is not set
-# CONFIG_I2C_SIS5595 is not set
-# CONFIG_I2C_SIS630 is not set
-# CONFIG_I2C_SIS96X is not set
-# CONFIG_I2C_VIA is not set
-# CONFIG_I2C_VIAPRO is not set
-
-#
-# I2C system bus drivers (mostly embedded / system-on-chip)
-#
-# CONFIG_I2C_OCORES is not set
-# CONFIG_I2C_SIMTEC is not set
-
-#
-# External I2C/SMBus adapter drivers
-#
-# CONFIG_I2C_PARPORT_LIGHT is not set
-# CONFIG_I2C_TAOS_EVM is not set
-# CONFIG_I2C_TINY_USB is not set
-
-#
-# Graphics adapter I2C/DDC channel drivers
-#
-# CONFIG_I2C_VOODOO3 is not set
-
-#
-# Other I2C/SMBus bus drivers
-#
-# CONFIG_I2C_PCA_PLATFORM is not set
-# CONFIG_I2C_STUB is not set
-
-#
-# Miscellaneous I2C Chip support
-#
-# CONFIG_DS1682 is not set
-# CONFIG_AT24 is not set
-# CONFIG_SENSORS_EEPROM is not set
-# CONFIG_SENSORS_PCF8574 is not set
-# CONFIG_PCF8575 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
-# CONFIG_I2C_DEBUG_CHIP is not set
-# CONFIG_SPI is not set
-# CONFIG_W1 is not set
-CONFIG_POWER_SUPPLY=y
-# CONFIG_POWER_SUPPLY_DEBUG is not set
-# CONFIG_PDA_POWER is not set
-# CONFIG_BATTERY_DS2760 is not set
-# CONFIG_BATTERY_BQ27x00 is not set
-CONFIG_HWMON=y
-# CONFIG_HWMON_VID is not set
-# CONFIG_SENSORS_AD7414 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_ADT7462 is not set
-# CONFIG_SENSORS_ADT7470 is not set
-# CONFIG_SENSORS_ADT7473 is not set
-# CONFIG_SENSORS_ATXP1 is not set
-# CONFIG_SENSORS_DS1621 is not set
-# CONFIG_SENSORS_I5K_AMB is not set
-# CONFIG_SENSORS_F71805F is not set
-# CONFIG_SENSORS_F71882FG is not set
-# CONFIG_SENSORS_F75375S is not set
-# CONFIG_SENSORS_GL518SM is not set
-# CONFIG_SENSORS_GL520SM is not set
-# CONFIG_SENSORS_IT87 is not set
-# CONFIG_SENSORS_LM63 is not set
-# CONFIG_SENSORS_LM75 is not set
-# CONFIG_SENSORS_LM77 is not set
-# CONFIG_SENSORS_LM78 is not set
-# CONFIG_SENSORS_LM80 is not set
-# CONFIG_SENSORS_LM83 is not set
-# CONFIG_SENSORS_LM85 is not set
-# CONFIG_SENSORS_LM87 is not set
-# CONFIG_SENSORS_LM90 is not set
-# CONFIG_SENSORS_LM92 is not set
-# CONFIG_SENSORS_LM93 is not set
-# CONFIG_SENSORS_LTC4245 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
-# CONFIG_SENSORS_ADS7828 is not set
-# CONFIG_SENSORS_THMC50 is not set
-# 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_W83L786NG is not set
-# CONFIG_SENSORS_W83627HF is not set
-# CONFIG_SENSORS_W83627EHF is not set
-# CONFIG_SENSORS_LIS3LV02D is not set
-# CONFIG_HWMON_DEBUG_CHIP is not set
-CONFIG_THERMAL=m
-# CONFIG_THERMAL_HWMON is not set
-# CONFIG_WATCHDOG is not set
-CONFIG_SSB_POSSIBLE=y
-
-#
-# Sonics Silicon Backplane
-#
-# CONFIG_SSB is not set
-
-#
-# Multifunction device drivers
-#
-# CONFIG_MFD_CORE is not set
-# CONFIG_MFD_SM501 is not set
-# CONFIG_HTC_PASIC3 is not set
-# CONFIG_MFD_TMIO is not set
-# CONFIG_MFD_WM8400 is not set
-# CONFIG_MFD_WM8350_I2C is not set
-# CONFIG_MFD_PCF50633 is not set
-# CONFIG_REGULATOR is not set
-
-#
-# Multimedia devices
-#
-
-#
-# Multimedia core support
-#
-# CONFIG_VIDEO_DEV is not set
-# CONFIG_DVB_CORE is not set
-# CONFIG_VIDEO_MEDIA is not set
-
-#
-# Multimedia drivers
-#
-CONFIG_DAB=y
-# CONFIG_USB_DABUSB is not set
-
-#
-# Graphics support
-#
-CONFIG_AGP=m
CONFIG_DRM=m
-CONFIG_DRM_TDFX=m
+CONFIG_DRM_MGA=m
CONFIG_DRM_R128=m
CONFIG_DRM_RADEON=m
-CONFIG_DRM_MGA=m
CONFIG_DRM_SIS=m
-# CONFIG_DRM_VIA is not set
-# CONFIG_DRM_SAVAGE is not set
-# CONFIG_VGASTATE is not set
-# CONFIG_VIDEO_OUTPUT_CONTROL is not set
-# CONFIG_FB is not set
-# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
-
-#
-# Display device support
-#
-# CONFIG_DISPLAY_SUPPORT is not set
-
-#
-# Console display driver support
-#
-CONFIG_VGA_CONSOLE=y
-# CONFIG_VGACON_SOFT_SCROLLBACK is not set
-CONFIG_DUMMY_CONSOLE=y
-# CONFIG_SOUND is not set
-CONFIG_HID_SUPPORT=y
-CONFIG_HID=y
-# CONFIG_HID_DEBUG is not set
-# CONFIG_HIDRAW is not set
-
-#
-# USB Input Devices
-#
-CONFIG_USB_HID=y
-# CONFIG_HID_PID is not set
-# CONFIG_USB_HIDDEV is not set
-
-#
-# Special HID drivers
-#
-CONFIG_HID_COMPAT=y
-CONFIG_HID_A4TECH=y
-CONFIG_HID_APPLE=y
-CONFIG_HID_BELKIN=y
-CONFIG_HID_CHERRY=y
-CONFIG_HID_CHICONY=y
-CONFIG_HID_CYPRESS=y
-CONFIG_HID_EZKEY=y
+CONFIG_DRM_TDFX=m
+CONFIG_DUMMY=m
+CONFIG_E1000=y
+CONFIG_E100=m
+CONFIG_EFI_PARTITION=y
+CONFIG_EFI_RTC=y
+CONFIG_EFI_VARS=y
+CONFIG_EXPERIMENTAL=y
+CONFIG_EXT2_FS_POSIX_ACL=y
+CONFIG_EXT2_FS_SECURITY=y
+CONFIG_EXT2_FS_XATTR=y
+CONFIG_EXT2_FS=y
+CONFIG_EXT3_FS_POSIX_ACL=y
+CONFIG_EXT3_FS_SECURITY=y
+CONFIG_EXT3_FS=y
+CONFIG_FORCE_CPEI_RETARGET=y
+CONFIG_FUSION_CTL=y
+CONFIG_FUSION_FC=y
+CONFIG_FUSION_SPI=y
+CONFIG_FUSION=y
+CONFIG_GAMEPORT=m
CONFIG_HID_GYRATION=y
-CONFIG_HID_LOGITECH=y
-# CONFIG_LOGITECH_FF is not set
-# CONFIG_LOGIRUMBLEPAD2_FF is not set
-CONFIG_HID_MICROSOFT=y
-CONFIG_HID_MONTEREY=y
CONFIG_HID_NTRIG=y
CONFIG_HID_PANTHERLORD=y
-# CONFIG_PANTHERLORD_FF is not set
CONFIG_HID_PETALYNX=y
CONFIG_HID_SAMSUNG=y
CONFIG_HID_SONY=y
CONFIG_HID_SUNPLUS=y
-# CONFIG_GREENASIA_FF is not set
CONFIG_HID_TOPSEED=y
-# CONFIG_THRUSTMASTER_FF is not set
-# CONFIG_ZEROPLUS_FF 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
-CONFIG_USB=y
-# CONFIG_USB_DEBUG is not set
-# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set
-
-#
-# 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_OTG is not set
-# CONFIG_USB_MON is not set
-# CONFIG_USB_WUSB is not set
-# CONFIG_USB_WUSB_CBAF is not set
-
-#
-# USB Host Controller Drivers
-#
-# CONFIG_USB_C67X00_HCD is not set
-CONFIG_USB_EHCI_HCD=m
-# CONFIG_USB_EHCI_ROOT_HUB_TT is not set
-# CONFIG_USB_EHCI_TT_NEWSCHED is not set
-# CONFIG_USB_OXU210HP_HCD is not set
-# CONFIG_USB_ISP116X_HCD is not set
-# CONFIG_USB_ISP1760_HCD is not set
-CONFIG_USB_OHCI_HCD=m
-# 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_UHCI_HCD=y
-# CONFIG_USB_SL811_HCD is not set
-# CONFIG_USB_R8A66597_HCD is not set
-# CONFIG_USB_WHCI_HCD is not set
-# CONFIG_USB_HWA_HCD is not set
-
-#
-# USB Device Class drivers
-#
-# CONFIG_USB_ACM is not set
-# CONFIG_USB_PRINTER is not set
-# CONFIG_USB_WDM is not set
-# CONFIG_USB_TMC is not set
-
-#
-# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may also be needed;
-#
-
-#
-# see USB_STORAGE Help for more information
-#
-CONFIG_USB_STORAGE=m
-# CONFIG_USB_STORAGE_DEBUG is not set
-# CONFIG_USB_STORAGE_DATAFAB is not set
-# CONFIG_USB_STORAGE_FREECOM is not set
-# CONFIG_USB_STORAGE_ISD200 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_ONETOUCH is not set
-# CONFIG_USB_STORAGE_KARMA is not set
-# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set
-# CONFIG_USB_LIBUSUAL is not set
-
-#
-# USB Imaging devices
-#
-# CONFIG_USB_MDC800 is not set
-# CONFIG_USB_MICROTEK is not set
-
-#
-# USB port drivers
-#
-# CONFIG_USB_SERIAL is not set
-
-#
-# USB Miscellaneous drivers
-#
-# CONFIG_USB_EMI62 is not set
-# CONFIG_USB_EMI26 is not set
-# CONFIG_USB_ADUTUX is not set
-# CONFIG_USB_SEVSEG is not set
-# CONFIG_USB_RIO500 is not set
-# CONFIG_USB_LEGOTOWER is not set
-# CONFIG_USB_LCD is not set
-# CONFIG_USB_BERRY_CHARGE is not set
-# CONFIG_USB_LED is not set
-# CONFIG_USB_CYPRESS_CY7C63 is not set
-# CONFIG_USB_CYTHERM is not set
-# CONFIG_USB_PHIDGET is not set
-# CONFIG_USB_IDMOUSE is not set
-# CONFIG_USB_FTDI_ELAN is not set
-# CONFIG_USB_APPLEDISPLAY is not set
-# CONFIG_USB_SISUSBVGA is not set
-# CONFIG_USB_LD is not set
-# CONFIG_USB_TRANCEVIBRATOR is not set
-# CONFIG_USB_IOWARRIOR is not set
-# CONFIG_USB_TEST is not set
-# CONFIG_USB_ISIGHTFW is not set
-# CONFIG_USB_VST is not set
-# CONFIG_USB_GADGET is not set
-
-#
-# OTG and related infrastructure
-#
-# CONFIG_UWB is not set
-# CONFIG_MMC is not set
-# CONFIG_MEMSTICK is not set
-# CONFIG_NEW_LEDS is not set
-# CONFIG_ACCESSIBILITY is not set
-# CONFIG_INFINIBAND is not set
-# CONFIG_RTC_CLASS is not set
-# CONFIG_DMADEVICES is not set
-# CONFIG_UIO is not set
-CONFIG_XEN_BALLOON=y
-CONFIG_XEN_SCRUB_PAGES=y
-CONFIG_XENFS=y
-CONFIG_XEN_COMPAT_XENFS=y
-# CONFIG_STAGING is not set
-# CONFIG_MSPEC is not set
-
-#
-# File systems
-#
-CONFIG_EXT2_FS=y
-CONFIG_EXT2_FS_XATTR=y
-CONFIG_EXT2_FS_POSIX_ACL=y
-CONFIG_EXT2_FS_SECURITY=y
-# CONFIG_EXT2_FS_XIP is not set
-CONFIG_EXT3_FS=y
-CONFIG_EXT3_FS_XATTR=y
-CONFIG_EXT3_FS_POSIX_ACL=y
-CONFIG_EXT3_FS_SECURITY=y
-# CONFIG_EXT4_FS is not set
-CONFIG_JBD=y
-CONFIG_FS_MBCACHE=y
-CONFIG_REISERFS_FS=y
-# CONFIG_REISERFS_CHECK is not set
-# CONFIG_REISERFS_PROC_INFO is not set
-CONFIG_REISERFS_FS_XATTR=y
-CONFIG_REISERFS_FS_POSIX_ACL=y
-CONFIG_REISERFS_FS_SECURITY=y
-# CONFIG_JFS_FS is not set
-CONFIG_FS_POSIX_ACL=y
-CONFIG_FILE_LOCKING=y
-CONFIG_XFS_FS=y
-# CONFIG_XFS_QUOTA is not set
-# CONFIG_XFS_POSIX_ACL is not set
-# CONFIG_XFS_RT is not set
-# CONFIG_XFS_DEBUG is not set
-# CONFIG_GFS2_FS is not set
-# CONFIG_OCFS2_FS is not set
-# CONFIG_BTRFS_FS is not set
-CONFIG_DNOTIFY=y
+CONFIG_HOTPLUG_CPU=y
+CONFIG_HOTPLUG_PCI_ACPI=m
+CONFIG_HOTPLUG_PCI=m
+CONFIG_HPET=y
+CONFIG_HUGETLBFS=y
+# CONFIG_HW_RANDOM is not set
+CONFIG_IA64_CYCLONE=y
+CONFIG_IA64_GRANULE_16MB=y
+CONFIG_IA64_MCA_RECOVERY=y
+CONFIG_IA64_PALINFO=y
+CONFIG_IA64_XEN_GUEST=y
+CONFIG_IDE=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_IKCONFIG=y
+# CONFIG_INET_LRO is not set
+CONFIG_INET=y
CONFIG_INOTIFY=y
-CONFIG_INOTIFY_USER=y
-# CONFIG_QUOTA is not set
-CONFIG_AUTOFS_FS=y
-CONFIG_AUTOFS4_FS=y
-# CONFIG_FUSE_FS is not set
-
-#
-# CD-ROM/DVD Filesystems
-#
+CONFIG_IP_MULTICAST=y
+# CONFIG_IPV6 is not set
CONFIG_ISO9660_FS=m
CONFIG_JOLIET=y
-# CONFIG_ZISOFS is not set
-CONFIG_UDF_FS=m
-CONFIG_UDF_NLS=y
-
-#
-# DOS/FAT/NT Filesystems
-#
-CONFIG_FAT_FS=y
-# CONFIG_MSDOS_FS is not set
-CONFIG_VFAT_FS=y
-CONFIG_FAT_DEFAULT_CODEPAGE=437
-CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
-CONFIG_NTFS_FS=m
-# CONFIG_NTFS_DEBUG is not set
-# CONFIG_NTFS_RW is not set
-
-#
-# Pseudo filesystems
-#
-CONFIG_PROC_FS=y
-CONFIG_PROC_KCORE=y
-CONFIG_PROC_SYSCTL=y
-CONFIG_PROC_PAGE_MONITOR=y
-CONFIG_SYSFS=y
-CONFIG_TMPFS=y
-# CONFIG_TMPFS_POSIX_ACL is not set
-CONFIG_HUGETLBFS=y
-CONFIG_HUGETLB_PAGE=y
-# CONFIG_CONFIGFS_FS is not set
-CONFIG_MISC_FILESYSTEMS=y
-# 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_SQUASHFS is not set
-# CONFIG_VXFS_FS is not set
-# CONFIG_MINIX_FS is not set
-# CONFIG_OMFS_FS is not set
-# CONFIG_HPFS_FS is not set
-# CONFIG_QNX4FS_FS is not set
-# CONFIG_ROMFS_FS is not set
-# CONFIG_SYSV_FS is not set
-# CONFIG_UFS_FS is not set
-CONFIG_NETWORK_FILESYSTEMS=y
+CONFIG_KALLSYMS_ALL=y
+CONFIG_KEXEC=y
+CONFIG_LOG_BUF_SHIFT=20
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_MCKINLEY=y
+CONFIG_MD_LINEAR=m
+CONFIG_MD_MULTIPATH=m
+CONFIG_MD_RAID0=m
+CONFIG_MD_RAID1=m
+CONFIG_MD=y
+CONFIG_MODULE_SRCVERSION_ALL=y
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODVERSIONS=y
+CONFIG_NETCONSOLE=y
+CONFIG_NETDEVICES=y
+CONFIG_NET_ETHERNET=y
+CONFIG_NET_PCI=y
+CONFIG_NET_TULIP=y
+CONFIG_NFSD=m
+CONFIG_NFSD_V4=y
CONFIG_NFS_FS=m
CONFIG_NFS_V3=y
-# CONFIG_NFS_V3_ACL is not set
CONFIG_NFS_V4=y
-CONFIG_NFSD=m
-CONFIG_NFSD_V3=y
-# CONFIG_NFSD_V3_ACL is not set
-CONFIG_NFSD_V4=y
-CONFIG_LOCKD=m
-CONFIG_LOCKD_V4=y
-CONFIG_EXPORTFS=m
-CONFIG_NFS_COMMON=y
-CONFIG_SUNRPC=m
-CONFIG_SUNRPC_GSS=m
-# CONFIG_SUNRPC_REGISTER_V4 is not set
-CONFIG_RPCSEC_GSS_KRB5=m
-# CONFIG_RPCSEC_GSS_SPKM3 is not set
-CONFIG_SMB_FS=m
-CONFIG_SMB_NLS_DEFAULT=y
-CONFIG_SMB_NLS_REMOTE="cp437"
-CONFIG_CIFS=m
-# CONFIG_CIFS_STATS is not set
-# CONFIG_CIFS_WEAK_PW_HASH is not set
-# CONFIG_CIFS_XATTR is not set
-# CONFIG_CIFS_DEBUG2 is not set
-# CONFIG_CIFS_EXPERIMENTAL is not set
-# CONFIG_NCP_FS is not set
-# CONFIG_CODA_FS is not set
-# CONFIG_AFS_FS is not set
-
-#
-# Partition Types
-#
-CONFIG_PARTITION_ADVANCED=y
-# CONFIG_ACORN_PARTITION is not set
-# CONFIG_OSF_PARTITION is not set
-# CONFIG_AMIGA_PARTITION is not set
-# CONFIG_ATARI_PARTITION is not set
-# CONFIG_MAC_PARTITION is not set
-CONFIG_MSDOS_PARTITION=y
-# CONFIG_BSD_DISKLABEL is not set
-# CONFIG_MINIX_SUBPARTITION is not set
-# CONFIG_SOLARIS_X86_PARTITION is not set
-# CONFIG_UNIXWARE_DISKLABEL is not set
-# CONFIG_LDM_PARTITION is not set
-CONFIG_SGI_PARTITION=y
-# CONFIG_ULTRIX_PARTITION is not set
-# CONFIG_SUN_PARTITION is not set
-# CONFIG_KARMA_PARTITION is not set
-CONFIG_EFI_PARTITION=y
-# CONFIG_SYSV68_PARTITION is not set
-CONFIG_NLS=y
-CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_1250=m
+CONFIG_NLS_CODEPAGE_1251=m
CONFIG_NLS_CODEPAGE_437=y
CONFIG_NLS_CODEPAGE_737=m
CONFIG_NLS_CODEPAGE_775=m
@@ -1384,15 +131,14 @@ CONFIG_NLS_CODEPAGE_864=m
CONFIG_NLS_CODEPAGE_865=m
CONFIG_NLS_CODEPAGE_866=m
CONFIG_NLS_CODEPAGE_869=m
-CONFIG_NLS_CODEPAGE_936=m
-CONFIG_NLS_CODEPAGE_950=m
+CONFIG_NLS_CODEPAGE_874=m
CONFIG_NLS_CODEPAGE_932=m
+CONFIG_NLS_CODEPAGE_936=m
CONFIG_NLS_CODEPAGE_949=m
-CONFIG_NLS_CODEPAGE_874=m
-CONFIG_NLS_ISO8859_8=m
-CONFIG_NLS_CODEPAGE_1250=m
-CONFIG_NLS_CODEPAGE_1251=m
-# CONFIG_NLS_ASCII is not set
+CONFIG_NLS_CODEPAGE_950=m
+CONFIG_NLS_ISO8859_13=m
+CONFIG_NLS_ISO8859_14=m
+CONFIG_NLS_ISO8859_15=m
CONFIG_NLS_ISO8859_1=y
CONFIG_NLS_ISO8859_2=m
CONFIG_NLS_ISO8859_3=m
@@ -1400,200 +146,54 @@ CONFIG_NLS_ISO8859_4=m
CONFIG_NLS_ISO8859_5=m
CONFIG_NLS_ISO8859_6=m
CONFIG_NLS_ISO8859_7=m
+CONFIG_NLS_ISO8859_8=m
CONFIG_NLS_ISO8859_9=m
-CONFIG_NLS_ISO8859_13=m
-CONFIG_NLS_ISO8859_14=m
-CONFIG_NLS_ISO8859_15=m
CONFIG_NLS_KOI8_R=m
CONFIG_NLS_KOI8_U=m
CONFIG_NLS_UTF8=m
-# CONFIG_DLM is not set
-
-#
-# Kernel hacking
-#
-# CONFIG_PRINTK_TIME is not set
-CONFIG_ENABLE_WARN_DEPRECATED=y
-CONFIG_ENABLE_MUST_CHECK=y
-CONFIG_FRAME_WARN=2048
-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=y
-# CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set
-CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=0
-CONFIG_SCHED_DEBUG=y
-# CONFIG_SCHEDSTATS is not set
-# CONFIG_TIMER_STATS is not set
-# CONFIG_DEBUG_OBJECTS is not set
-# CONFIG_SLUB_DEBUG_ON is not set
-# CONFIG_SLUB_STATS 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=y
-# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
-# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
-# CONFIG_DEBUG_KOBJECT is not set
-# CONFIG_DEBUG_INFO is not set
-# CONFIG_DEBUG_VM is not set
-# CONFIG_DEBUG_WRITECOUNT is not set
-CONFIG_DEBUG_MEMORY_INIT=y
-# CONFIG_DEBUG_LIST is not set
-# CONFIG_DEBUG_SG is not set
-# CONFIG_DEBUG_NOTIFIERS is not set
-# CONFIG_BOOT_PRINTK_DELAY is not set
-# CONFIG_RCU_TORTURE_TEST is not set
+CONFIG_NR_CPUS=16
+CONFIG_NTFS_FS=m
+CONFIG_PACKET=y
+CONFIG_PARAVIRT_GUEST=y
+CONFIG_PARTITION_ADVANCED=y
+CONFIG_PERFMON=y
+CONFIG_PERMIT_BSP_REMOVE=y
+CONFIG_POSIX_MQUEUE=y
+CONFIG_PROC_KCORE=y
+CONFIG_RAW_DRIVER=m
# CONFIG_RCU_CPU_STALL_DETECTOR is not set
-# CONFIG_BACKTRACE_SELF_TEST is not set
-# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
-# CONFIG_FAULT_INJECTION is not set
-# CONFIG_SYSCTL_SYSCALL_CHECK is not set
-
-#
-# Tracers
-#
-# CONFIG_SCHED_TRACER is not set
-# CONFIG_CONTEXT_SWITCH_TRACER is not set
-# CONFIG_BOOT_TRACER is not set
-# CONFIG_TRACE_BRANCH_PROFILING is not set
-# CONFIG_DYNAMIC_PRINTK_DEBUG is not set
-# CONFIG_SAMPLES is not set
-CONFIG_IA64_GRANULE_16MB=y
-# CONFIG_IA64_GRANULE_64MB is not set
-# CONFIG_IA64_PRINT_HAZARDS is not set
-# CONFIG_DISABLE_VHPT is not set
-# CONFIG_IA64_DEBUG_CMPXCHG is not set
-# CONFIG_IA64_DEBUG_IRQ is not set
-
-#
-# Security options
-#
-# CONFIG_KEYS is not set
-# CONFIG_SECURITY is not set
-# CONFIG_SECURITYFS is not set
-# CONFIG_SECURITY_FILE_CAPABILITIES is not set
-CONFIG_CRYPTO=y
-
-#
-# Crypto core or helper
-#
-# CONFIG_CRYPTO_FIPS is not set
-CONFIG_CRYPTO_ALGAPI=y
-CONFIG_CRYPTO_ALGAPI2=y
-CONFIG_CRYPTO_AEAD2=y
-CONFIG_CRYPTO_BLKCIPHER=m
-CONFIG_CRYPTO_BLKCIPHER2=y
-CONFIG_CRYPTO_HASH=y
-CONFIG_CRYPTO_HASH2=y
-CONFIG_CRYPTO_RNG2=y
-CONFIG_CRYPTO_MANAGER=m
-CONFIG_CRYPTO_MANAGER2=y
-# CONFIG_CRYPTO_GF128MUL is not set
-# CONFIG_CRYPTO_NULL is not set
-# CONFIG_CRYPTO_CRYPTD is not set
-# CONFIG_CRYPTO_AUTHENC is not set
-# CONFIG_CRYPTO_TEST is not set
-
-#
-# Authenticated Encryption with Associated Data
-#
-# CONFIG_CRYPTO_CCM is not set
-# CONFIG_CRYPTO_GCM is not set
-# CONFIG_CRYPTO_SEQIV is not set
-
-#
-# Block modes
-#
-CONFIG_CRYPTO_CBC=m
-# CONFIG_CRYPTO_CTR is not set
-# CONFIG_CRYPTO_CTS is not set
-CONFIG_CRYPTO_ECB=m
-# CONFIG_CRYPTO_LRW is not set
-CONFIG_CRYPTO_PCBC=m
-# CONFIG_CRYPTO_XTS is not set
-
-#
-# Hash modes
-#
-# CONFIG_CRYPTO_HMAC is not set
-# CONFIG_CRYPTO_XCBC is not set
-
-#
-# Digest
-#
-# CONFIG_CRYPTO_CRC32C is not set
-# CONFIG_CRYPTO_MD4 is not set
-CONFIG_CRYPTO_MD5=y
-# CONFIG_CRYPTO_MICHAEL_MIC is not set
-# CONFIG_CRYPTO_RMD128 is not set
-# CONFIG_CRYPTO_RMD160 is not set
-# CONFIG_CRYPTO_RMD256 is not set
-# CONFIG_CRYPTO_RMD320 is not set
-# CONFIG_CRYPTO_SHA1 is not set
-# CONFIG_CRYPTO_SHA256 is not set
-# CONFIG_CRYPTO_SHA512 is not set
-# CONFIG_CRYPTO_TGR192 is not set
-# CONFIG_CRYPTO_WP512 is not set
-
-#
-# Ciphers
-#
-# CONFIG_CRYPTO_AES is not set
-# CONFIG_CRYPTO_ANUBIS is not set
-# CONFIG_CRYPTO_ARC4 is not set
-# CONFIG_CRYPTO_BLOWFISH is not set
-# CONFIG_CRYPTO_CAMELLIA is not set
-# CONFIG_CRYPTO_CAST5 is not set
-# CONFIG_CRYPTO_CAST6 is not set
-CONFIG_CRYPTO_DES=m
-# CONFIG_CRYPTO_FCRYPT is not set
-# CONFIG_CRYPTO_KHAZAD is not set
-# CONFIG_CRYPTO_SALSA20 is not set
-# CONFIG_CRYPTO_SEED is not set
-# CONFIG_CRYPTO_SERPENT is not set
-# CONFIG_CRYPTO_TEA is not set
-# CONFIG_CRYPTO_TWOFISH is not set
-
-#
-# Compression
-#
-# CONFIG_CRYPTO_DEFLATE is not set
-# CONFIG_CRYPTO_LZO is not set
-
-#
-# Random Number Generation
-#
-# CONFIG_CRYPTO_ANSI_CPRNG is not set
-CONFIG_CRYPTO_HW=y
-# CONFIG_CRYPTO_DEV_HIFN_795X is not set
-CONFIG_HAVE_KVM=y
-CONFIG_VIRTUALIZATION=y
-# CONFIG_KVM is not set
-# CONFIG_VIRTIO_PCI is not set
-# CONFIG_VIRTIO_BALLOON is not set
-
-#
-# Library routines
-#
-CONFIG_BITREVERSE=y
-CONFIG_GENERIC_FIND_LAST_BIT=y
-# CONFIG_CRC_CCITT is not set
-# CONFIG_CRC16 is not set
-# CONFIG_CRC_T10DIF is not set
-CONFIG_CRC_ITU_T=m
-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
-CONFIG_IRQ_PER_CPU=y
-# CONFIG_IOMMU_API is not set
+CONFIG_REISERFS_FS_POSIX_ACL=y
+CONFIG_REISERFS_FS_SECURITY=y
+CONFIG_REISERFS_FS_XATTR=y
+CONFIG_REISERFS_FS=y
+CONFIG_SCSI_QLOGIC_1280=y
+CONFIG_SCSI_SYM53C8XX_2=y
+CONFIG_SCSI=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_EXTENDED=y
+CONFIG_SERIAL_8250_NR_UARTS=6
+CONFIG_SERIAL_8250_SHARE_IRQ=y
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_NONSTANDARD=y
+# CONFIG_SERIO_SERPORT is not set
+CONFIG_SGI_PARTITION=y
+CONFIG_SMB_FS=m
+CONFIG_SMB_NLS_DEFAULT=y
+CONFIG_SMP=y
+CONFIG_SYN_COOKIES=y
+CONFIG_SYSFS_DEPRECATED_V2=y
+CONFIG_SYSVIPC=y
+CONFIG_TIGON3=y
+CONFIG_TMPFS=y
+CONFIG_TULIP=m
+CONFIG_UDF_FS=m
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_UNIX=y
+CONFIG_USB_DEVICEFS=y
+CONFIG_USB_EHCI_HCD=m
+CONFIG_USB_OHCI_HCD=m
+CONFIG_USB_STORAGE=m
+CONFIG_USB_UHCI_HCD=y
+CONFIG_USB=y
+CONFIG_VFAT_FS=y
+CONFIG_XFS_FS=y
diff --git a/arch/ia64/configs/zx1_defconfig b/arch/ia64/configs/zx1_defconfig
index 3cec65b534c..de0b68e0d48 100644
--- a/arch/ia64/configs/zx1_defconfig
+++ b/arch/ia64/configs/zx1_defconfig
@@ -1,1460 +1,85 @@
-#
-# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.21-rc3
-# Thu Mar 8 11:04:20 2007
-#
-CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
-
-#
-# Code maturity level options
-#
-CONFIG_EXPERIMENTAL=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 is not set
-# CONFIG_CPUSETS 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=y
-CONFIG_SYSCTL=y
-# CONFIG_EMBEDDED is not set
-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_EPOLL=y
-CONFIG_SHMEM=y
-CONFIG_SLUB=y
-CONFIG_VM_EVENT_COUNTERS=y
-CONFIG_RT_MUTEXES=y
-# CONFIG_TINY_SHMEM is not set
-CONFIG_BASE_SMALL=0
-# CONFIG_SLOB is not set
-
-#
-# Loadable module support
-#
-CONFIG_MODULES=y
-# CONFIG_MODULE_UNLOAD is not set
-# CONFIG_MODVERSIONS is not set
-# 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
-
-#
-# 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"
-
-#
-# Processor type and features
-#
-CONFIG_IA64=y
-CONFIG_64BIT=y
-CONFIG_ZONE_DMA=y
-CONFIG_MMU=y
-CONFIG_RWSEM_XCHGADD_ALGORITHM=y
-# CONFIG_ARCH_HAS_ILOG2_U32 is not set
-# CONFIG_ARCH_HAS_ILOG2_U64 is not set
-CONFIG_GENERIC_FIND_NEXT_BIT=y
-CONFIG_GENERIC_CALIBRATE_DELAY=y
-CONFIG_GENERIC_TIME=y
-CONFIG_DMI=y
-CONFIG_EFI=y
-CONFIG_GENERIC_IOMAP=y
-CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y
-CONFIG_AUDIT_ARCH=y
-# CONFIG_IA64_GENERIC is not set
-# CONFIG_IA64_DIG is not set
-CONFIG_IA64_HP_ZX1=y
-# CONFIG_IA64_HP_ZX1_SWIOTLB is not set
-# CONFIG_IA64_SGI_SN2 is not set
-# CONFIG_IA64_HP_SIM is not set
-# CONFIG_ITANIUM is not set
-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_PGTABLE_3=y
-# CONFIG_PGTABLE_4 is not set
-# 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_IA64_L1_CACHE_SHIFT=7
-# CONFIG_IA64_CYCLONE is not set
-CONFIG_IOSAPIC=y
-CONFIG_FORCE_MAX_ZONEORDER=17
-CONFIG_SMP=y
-CONFIG_NR_CPUS=16
-CONFIG_HOTPLUG_CPU=y
-CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
-# CONFIG_SCHED_SMT is not set
-# CONFIG_PERMIT_BSP_REMOVE is not set
-# CONFIG_PREEMPT is not set
-CONFIG_SELECT_MEMORY_MODEL=y
-CONFIG_FLATMEM_MANUAL=y
-# CONFIG_DISCONTIGMEM_MANUAL is not set
-# CONFIG_SPARSEMEM_MANUAL is not set
-CONFIG_FLATMEM=y
-CONFIG_FLAT_NODE_MEM_MAP=y
-# CONFIG_SPARSEMEM_STATIC is not set
-CONFIG_SPLIT_PTLOCK_CPUS=4
-CONFIG_RESOURCES_64BIT=y
-CONFIG_ZONE_DMA_FLAG=1
-CONFIG_ARCH_SELECT_MEMORY_MODEL=y
-CONFIG_ARCH_DISCONTIGMEM_ENABLE=y
-CONFIG_ARCH_FLATMEM_ENABLE=y
-CONFIG_ARCH_SPARSEMEM_ENABLE=y
-CONFIG_ARCH_DISCONTIGMEM_DEFAULT=y
-CONFIG_ARCH_POPULATES_NODE_MAP=y
-CONFIG_VIRTUAL_MEM_MAP=y
-CONFIG_HOLES_IN_ZONE=y
-CONFIG_IA64_MCA_RECOVERY=y
-CONFIG_PERFMON=y
-CONFIG_IA64_PALINFO=y
-# CONFIG_IA64_ESI is not set
-# CONFIG_KEXEC is not set
-CONFIG_CRASH_DUMP=y
-
-#
-# Firmware Drivers
-#
-CONFIG_EFI_VARS=y
-CONFIG_EFI_PCDP=y
-CONFIG_BINFMT_ELF=y
-CONFIG_BINFMT_MISC=y
-
-#
-# Power management and ACPI
-#
-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
-#
-CONFIG_ACPI=y
CONFIG_ACPI_PROCFS=y
-CONFIG_ACPI_BUTTON=y
-CONFIG_ACPI_FAN=y
-# CONFIG_ACPI_DOCK is not set
-CONFIG_ACPI_PROCESSOR=y
-CONFIG_ACPI_HOTPLUG_CPU=y
-CONFIG_ACPI_THERMAL=y
-CONFIG_ACPI_BLACKLIST_YEAR=0
-# CONFIG_ACPI_DEBUG is not set
-CONFIG_ACPI_EC=y
-CONFIG_ACPI_POWER=y
-CONFIG_ACPI_SYSTEM=y
-CONFIG_ACPI_CONTAINER=y
-
-#
-# CPU Frequency scaling
-#
-# CONFIG_CPU_FREQ is not set
-
-#
-# Bus options (PCI, PCMCIA)
-#
-CONFIG_PCI=y
-CONFIG_PCI_DOMAINS=y
-# CONFIG_PCIEPORTBUS is not set
-# CONFIG_PCI_MSI is not set
-# CONFIG_PCI_DEBUG is not set
-
-#
-# PCI Hotplug Support
-#
-CONFIG_HOTPLUG_PCI=y
-# CONFIG_HOTPLUG_PCI_FAKE is not set
-CONFIG_HOTPLUG_PCI_ACPI=y
-# CONFIG_HOTPLUG_PCI_ACPI_IBM is not set
-# CONFIG_HOTPLUG_PCI_CPCI is not set
-# CONFIG_HOTPLUG_PCI_SHPC is not set
-
-#
-# PCCARD (PCMCIA/CardBus) support
-#
-# CONFIG_PCCARD 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=y
-# CONFIG_IP_ADVANCED_ROUTER is not set
-CONFIG_IP_FIB_HASH=y
-# CONFIG_IP_PNP is not set
-# CONFIG_NET_IPIP is not set
-# CONFIG_NET_IPGRE is not set
-# CONFIG_IP_MROUTE is not set
-# CONFIG_ARPD is not set
-# CONFIG_SYN_COOKIES 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
-
-#
-# IP: Virtual Server Configuration
-#
-# CONFIG_IP_VS 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=y
-# CONFIG_NETFILTER_DEBUG is not set
-
-#
-# Core Netfilter Configuration
-#
-# CONFIG_NETFILTER_NETLINK is not set
-# CONFIG_NF_CONNTRACK_ENABLED is not set
-# CONFIG_NETFILTER_XTABLES is not set
-
-#
-# IP: Netfilter Configuration
-#
-# CONFIG_IP_NF_QUEUE is not set
-# CONFIG_IP_NF_IPTABLES is not set
-# CONFIG_IP_NF_ARPTABLES 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_NET_TCPPROBE 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 is not set
-
-#
-# Parallel port support
-#
-# CONFIG_PARPORT is not set
-
-#
-# Plug and Play support
-#
-CONFIG_PNP=y
-# CONFIG_PNP_DEBUG is not set
-
-#
-# Protocols
-#
-CONFIG_PNPACPI=y
-
-#
-# 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_AGP_HP_ZX1=y
+CONFIG_AGP=y
+CONFIG_AUTOFS_FS=y
+CONFIG_BINFMT_MISC=y
+CONFIG_BLK_DEV_CMD64X=y
+CONFIG_BLK_DEV_GENERIC=y
+CONFIG_BLK_DEV_IDECD=y
+CONFIG_BLK_DEV_INITRD=y
CONFIG_BLK_DEV_LOOP=y
-# CONFIG_BLK_DEV_CRYPTOLOOP is not set
-# CONFIG_BLK_DEV_NBD is not set
-# CONFIG_BLK_DEV_SX8 is not set
-# CONFIG_BLK_DEV_UB 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_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
-
-#
-# Please see Documentation/ide.txt for help/info on IDE drives
-#
-# CONFIG_BLK_DEV_IDE_SATA is not set
-CONFIG_BLK_DEV_IDEDISK=y
-# CONFIG_IDEDISK_MULTI_MODE is not set
-CONFIG_BLK_DEV_IDECD=y
-# CONFIG_BLK_DEV_IDETAPE is not set
-# CONFIG_BLK_DEV_IDEFLOPPY is not set
-# CONFIG_BLK_DEV_IDESCSI is not set
-# CONFIG_BLK_DEV_IDEACPI is not set
-# CONFIG_IDE_TASK_IOCTL is not set
-
-#
-# IDE chipset support/bugfixes
-#
-# CONFIG_IDE_GENERIC is not set
-# CONFIG_BLK_DEV_IDEPNP is not set
-CONFIG_BLK_DEV_IDEPCI=y
-CONFIG_IDEPCI_SHARE_IRQ=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 is not set
-# CONFIG_BLK_DEV_AEC62XX is not set
-# CONFIG_BLK_DEV_ALI15X3 is not set
-# CONFIG_BLK_DEV_AMD74XX is not set
-CONFIG_BLK_DEV_CMD64X=y
-# CONFIG_BLK_DEV_TRIFLEX is not set
-# CONFIG_BLK_DEV_CY82C693 is not set
-# CONFIG_BLK_DEV_CS5520 is not set
-# CONFIG_BLK_DEV_CS5530 is not set
-# CONFIG_BLK_DEV_HPT34X is not set
-# CONFIG_BLK_DEV_HPT366 is not set
-# CONFIG_BLK_DEV_JMICRON is not set
-# CONFIG_BLK_DEV_SC1200 is not set
-# CONFIG_BLK_DEV_PIIX is not set
-# CONFIG_BLK_DEV_IT8213 is not set
-# CONFIG_BLK_DEV_IT821X is not set
-# CONFIG_BLK_DEV_NS87415 is not set
-# CONFIG_BLK_DEV_PDC202XX_OLD is not set
-# CONFIG_BLK_DEV_PDC202XX_NEW is not set
-# CONFIG_BLK_DEV_SVWKS is not set
-# CONFIG_BLK_DEV_SIIMAGE is not set
-# CONFIG_BLK_DEV_SLC90E66 is not set
-# CONFIG_BLK_DEV_TRM290 is not set
-# CONFIG_BLK_DEV_VIA82CXXX is not set
-# CONFIG_BLK_DEV_TC86C001 is not set
-# CONFIG_IDE_ARM is not set
-CONFIG_BLK_DEV_IDEDMA=y
-# CONFIG_IDEDMA_IVB is not set
-# CONFIG_IDEDMA_AUTO is not set
-# CONFIG_BLK_DEV_HD is not set
-
-#
-# SCSI device support
-#
-# CONFIG_RAID_ATTRS is not set
-CONFIG_SCSI=y
-# CONFIG_SCSI_TGT is not set
-CONFIG_SCSI_NETLINK=y
-CONFIG_SCSI_PROC_FS=y
-
-#
-# SCSI support type (disk, tape, CD-ROM)
-#
CONFIG_BLK_DEV_SD=y
-CONFIG_CHR_DEV_ST=y
-CONFIG_CHR_DEV_OSST=y
-CONFIG_BLK_DEV_SR=y
CONFIG_BLK_DEV_SR_VENDOR=y
+CONFIG_BLK_DEV_SR=y
+CONFIG_BSD_PROCESS_ACCT=y
+CONFIG_CHR_DEV_OSST=y
CONFIG_CHR_DEV_SG=y
-# CONFIG_CHR_DEV_SCH is not set
-
-#
-# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
-#
-CONFIG_SCSI_MULTI_LUN=y
-CONFIG_SCSI_CONSTANTS=y
-CONFIG_SCSI_LOGGING=y
-# CONFIG_SCSI_SCAN_ASYNC is not set
-
-#
-# SCSI Transports
-#
-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_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_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=y
-CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=1
-CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16
-CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64
-CONFIG_SCSI_SYM53C8XX_MMIO=y
-CONFIG_SCSI_QLOGIC_1280=y
-# 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_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 is not set
-
-#
-# Fusion MPT device support
-#
-CONFIG_FUSION=y
-CONFIG_FUSION_SPI=y
-CONFIG_FUSION_FC=y
-# CONFIG_FUSION_SAS is not set
-CONFIG_FUSION_MAX_SGE=128
-CONFIG_FUSION_CTL=m
-
-#
-# IEEE 1394 (FireWire) support
-#
-# CONFIG_IEEE1394 is not set
-
-#
-# I2O device support
-#
-# CONFIG_I2O is not set
-
-#
-# Network device support
-#
-CONFIG_NETDEVICES=y
+CONFIG_CHR_DEV_ST=y
+CONFIG_CRASH_DUMP=y
+CONFIG_CRYPTO_ECB=m
+CONFIG_CRYPTO_PCBC=m
+CONFIG_DEBUG_KERNEL=y
+CONFIG_DEBUG_MUTEXES=y
+CONFIG_DRM_RADEON=y
+CONFIG_DRM=y
CONFIG_DUMMY=y
-# CONFIG_BONDING 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=y
-# CONFIG_HAPPYMEAL is not set
-# CONFIG_SUNGEM is not set
-# CONFIG_CASSINI is not set
-# CONFIG_NET_VENDOR_3COM is not set
-
-#
-# Tulip family network device support
-#
-CONFIG_NET_TULIP=y
-# CONFIG_DE2104X is not set
-CONFIG_TULIP=y
-CONFIG_TULIP_MWI=y
-CONFIG_TULIP_MMIO=y
-CONFIG_TULIP_NAPI=y
-CONFIG_TULIP_NAPI_HW_MITIGATION=y
-# CONFIG_DE4X5 is not set
-# CONFIG_WINBOND_840 is not set
-# CONFIG_DM9102 is not set
-# CONFIG_ULI526X is not set
-# CONFIG_HP100 is not set
-CONFIG_NET_PCI=y
-# CONFIG_PCNET32 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=y
-# CONFIG_FEALNX is not set
-# CONFIG_NATSEMI is not set
-# CONFIG_NE2K_PCI is not set
-# CONFIG_8139CP is not set
-# CONFIG_8139TOO is not set
-# CONFIG_SIS900 is not set
-# CONFIG_EPIC100 is not set
-# CONFIG_SUNDANCE is not set
-# CONFIG_VIA_RHINE is not set
-# CONFIG_SC92031 is not set
-
-#
-# Ethernet (1000 Mbit)
-#
-# CONFIG_ACENIC is not set
-# CONFIG_DL2K is not set
CONFIG_E1000=y
-# 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 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=y
-# CONFIG_BNX2 is not set
-# CONFIG_QLA3XXX is not set
-# CONFIG_ATL1 is not set
-
-#
-# Ethernet (10000 Mbit)
-#
-# CONFIG_CHELSIO_T1 is not set
-# CONFIG_CHELSIO_T3 is not set
-# CONFIG_IXGB is not set
-# CONFIG_S2IO is not set
-# CONFIG_MYRI10GE is not set
-# CONFIG_NETXEN_NIC is not set
-
-#
-# Token Ring devices
-#
-# CONFIG_TR is not set
-
-#
-# Wireless LAN (non-hamradio)
-#
-# CONFIG_NET_RADIO is not set
-
-#
-# Wan interfaces
-#
-# CONFIG_WAN is not set
-# CONFIG_FDDI is not set
-# CONFIG_HIPPI is not set
-# CONFIG_PPP is not set
-# CONFIG_SLIP is not set
-# CONFIG_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=y
-CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
-CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
-CONFIG_INPUT_JOYDEV=y
-# CONFIG_INPUT_TSDEV is not set
-CONFIG_INPUT_EVDEV=y
-# CONFIG_INPUT_EVBUG is not set
-
-#
-# Input Device Drivers
-#
-# CONFIG_INPUT_KEYBOARD is not set
-# CONFIG_INPUT_MOUSE is not set
-# CONFIG_INPUT_JOYSTICK is not set
-# CONFIG_INPUT_TOUCHSCREEN is not set
-# CONFIG_INPUT_MISC is not set
-
-#
-# Hardware I/O ports
-#
-CONFIG_SERIO=y
-# CONFIG_SERIO_I8042 is not set
-# CONFIG_SERIO_SERPORT is not set
-# CONFIG_SERIO_PCIPS2 is not set
-# 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=y
-CONFIG_SERIAL_8250_CONSOLE=y
-CONFIG_SERIAL_8250_PCI=y
-CONFIG_SERIAL_8250_PNP=y
-CONFIG_SERIAL_8250_NR_UARTS=8
-CONFIG_SERIAL_8250_RUNTIME_UARTS=4
-CONFIG_SERIAL_8250_EXTENDED=y
-CONFIG_SERIAL_8250_SHARE_IRQ=y
-# CONFIG_SERIAL_8250_DETECT_IRQ is not set
-# CONFIG_SERIAL_8250_RSA is not set
-
-#
-# Non-8250 serial port support
-#
-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
-
-#
-# Watchdog Cards
-#
-# CONFIG_WATCHDOG is not set
-# CONFIG_HW_RANDOM is not set
+CONFIG_E100=y
+CONFIG_EFI_PARTITION=y
CONFIG_EFI_RTC=y
-# CONFIG_DTLK is not set
-# CONFIG_R3964 is not set
-# CONFIG_APPLICOM is not set
-CONFIG_AGP=y
-CONFIG_AGP_HP_ZX1=y
-CONFIG_DRM=y
-# CONFIG_DRM_TDFX is not set
-# CONFIG_DRM_R128 is not set
-CONFIG_DRM_RADEON=y
-# CONFIG_DRM_MGA is not set
-# CONFIG_DRM_SIS is not set
-# CONFIG_DRM_VIA is not set
-# CONFIG_DRM_SAVAGE is not set
-# CONFIG_RAW_DRIVER is not set
-# CONFIG_HPET is not set
-# CONFIG_HANGCHECK_TIMER is not set
-
-#
-# TPM devices
-#
-# CONFIG_TCG_TPM is not set
-
-#
-# I2C support
-#
-CONFIG_I2C=y
-CONFIG_I2C_CHARDEV=y
-
-#
-# I2C Algorithms
-#
-CONFIG_I2C_ALGOBIT=y
-CONFIG_I2C_ALGOPCF=y
-# 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_PASEMI is not set
-# CONFIG_I2C_PROSAVAGE is not set
-# CONFIG_I2C_SAVAGE4 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_VIA is not set
-# CONFIG_I2C_VIAPRO is not set
-# CONFIG_I2C_VOODOO3 is not set
-# CONFIG_I2C_PCA_ISA is not set
-
-#
-# Miscellaneous I2C Chip support
-#
-# CONFIG_SENSORS_DS1337 is not set
-# CONFIG_SENSORS_DS1374 is not set
-# CONFIG_EEPROM_LEGACY 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
-
-#
-# 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 is not set
-# CONFIG_HWMON_VID is not set
-
-#
-# Multifunction device drivers
-#
-# CONFIG_MFD_SM501 is not set
-
-#
-# Multimedia devices
-#
-CONFIG_VIDEO_DEV=y
-CONFIG_VIDEO_V4L1=y
-CONFIG_VIDEO_V4L1_COMPAT=y
-CONFIG_VIDEO_V4L2=y
-
-#
-# Video Capture Adapters
-#
-
-#
-# Video Capture Adapters
-#
-# CONFIG_VIDEO_ADV_DEBUG is not set
-CONFIG_VIDEO_HELPER_CHIPS_AUTO=y
-# CONFIG_VIDEO_VIVI is not set
-# CONFIG_VIDEO_BT848 is not set
-# CONFIG_VIDEO_CPIA is not set
-# CONFIG_VIDEO_CPIA2 is not set
-# CONFIG_VIDEO_SAA5246A is not set
-# CONFIG_VIDEO_SAA5249 is not set
-# CONFIG_TUNER_3036 is not set
-# CONFIG_VIDEO_STRADIS is not set
-# CONFIG_VIDEO_ZORAN is not set
-# CONFIG_VIDEO_SAA7134 is not set
-# CONFIG_VIDEO_MXB is not set
-# CONFIG_VIDEO_DPC is not set
-# CONFIG_VIDEO_HEXIUM_ORION is not set
-# CONFIG_VIDEO_HEXIUM_GEMINI is not set
-# CONFIG_VIDEO_CX88 is not set
-# CONFIG_VIDEO_CAFE_CCIC is not set
-
-#
-# V4L USB devices
-#
-# CONFIG_VIDEO_PVRUSB2 is not set
-# CONFIG_VIDEO_EM28XX is not set
-# CONFIG_VIDEO_USBVISION is not set
-# CONFIG_USB_VICAM is not set
-# CONFIG_USB_IBMCAM is not set
-# CONFIG_USB_KONICAWC is not set
-# CONFIG_USB_QUICKCAM_MESSENGER is not set
-# CONFIG_USB_ET61X251 is not set
-# CONFIG_VIDEO_OVCAMCHIP is not set
-# CONFIG_USB_W9968CF is not set
-# CONFIG_USB_OV511 is not set
-# CONFIG_USB_SE401 is not set
-# CONFIG_USB_SN9C102 is not set
-# CONFIG_USB_STV680 is not set
-# CONFIG_USB_ZC0301 is not set
-# CONFIG_USB_PWC is not set
-
-#
-# Radio Adapters
-#
-# CONFIG_RADIO_GEMTEK_PCI is not set
-# CONFIG_RADIO_MAXIRADIO is not set
-# CONFIG_RADIO_MAESTRO is not set
-# CONFIG_USB_DSBR is not set
-
-#
-# Digital Video Broadcasting Devices
-#
-# CONFIG_DVB is not set
-# CONFIG_USB_DABUSB is not set
-
-#
-# Graphics support
-#
-CONFIG_BACKLIGHT_LCD_SUPPORT=y
-CONFIG_BACKLIGHT_CLASS_DEVICE=y
-CONFIG_LCD_CLASS_DEVICE=m
-CONFIG_FB=y
-# CONFIG_FIRMWARE_EDID is not set
-CONFIG_FB_DDC=y
-CONFIG_FB_CFB_FILLRECT=y
-CONFIG_FB_CFB_COPYAREA=y
-CONFIG_FB_CFB_IMAGEBLIT=y
-# CONFIG_FB_SVGALIB is not set
-# CONFIG_FB_MACMODES is not set
-CONFIG_FB_BACKLIGHT=y
-CONFIG_FB_MODE_HELPERS=y
-# CONFIG_FB_TILEBLITTING is not set
-
-#
-# Frambuffer hardware drivers
-#
-# CONFIG_FB_CIRRUS is not set
-# CONFIG_FB_PM2 is not set
-# CONFIG_FB_CYBER2000 is not set
-# CONFIG_FB_ASILIANT is not set
-# CONFIG_FB_IMSTT is not set
-# CONFIG_FB_S1D13XXX is not set
-# CONFIG_FB_NVIDIA is not set
-# CONFIG_FB_RIVA is not set
-# CONFIG_FB_MATROX is not set
-CONFIG_FB_RADEON=y
-CONFIG_FB_RADEON_I2C=y
-CONFIG_FB_RADEON_BACKLIGHT=y
-CONFIG_FB_RADEON_DEBUG=y
-# 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_TRIDENT is not set
-# CONFIG_FB_VIRTUAL is not set
-
-#
-# Console display driver support
-#
-CONFIG_VGA_CONSOLE=y
-# CONFIG_VGACON_SOFT_SCROLLBACK 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
-
-#
-# Logo configuration
-#
-CONFIG_LOGO=y
-# CONFIG_LOGO_LINUX_MONO is not set
-# CONFIG_LOGO_LINUX_VGA16 is not set
-CONFIG_LOGO_LINUX_CLUT224=y
-
-#
-# Sound
-#
-CONFIG_SOUND=y
-
-#
-# Advanced Linux Sound Architecture
-#
-CONFIG_SND=y
-CONFIG_SND_TIMER=y
-CONFIG_SND_PCM=y
-CONFIG_SND_HWDEP=y
-CONFIG_SND_RAWMIDI=y
-CONFIG_SND_SEQUENCER=y
-# CONFIG_SND_SEQ_DUMMY is not set
-CONFIG_SND_OSSEMUL=y
-CONFIG_SND_MIXER_OSS=y
-CONFIG_SND_PCM_OSS=y
-CONFIG_SND_PCM_OSS_PLUGINS=y
-CONFIG_SND_SEQUENCER_OSS=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_MPU401_UART=y
-CONFIG_SND_OPL3_LIB=y
-CONFIG_SND_AC97_CODEC=y
-# CONFIG_SND_DUMMY is not set
-# CONFIG_SND_VIRMIDI is not set
-# CONFIG_SND_MTPAV is not set
-# CONFIG_SND_SERIAL_U16550 is not set
-# CONFIG_SND_MPU401 is not set
-
-#
-# PCI devices
-#
-# CONFIG_SND_AD1889 is not set
-# CONFIG_SND_ALS300 is not set
-# CONFIG_SND_ALI5451 is not set
-# CONFIG_SND_ATIIXP is not set
-# CONFIG_SND_ATIIXP_MODEM is not set
-# CONFIG_SND_AU8810 is not set
-# CONFIG_SND_AU8820 is not set
-# CONFIG_SND_AU8830 is not set
-# CONFIG_SND_AZT3328 is not set
-# CONFIG_SND_BT87X is not set
-# CONFIG_SND_CA0106 is not set
-# CONFIG_SND_CMIPCI is not set
-# CONFIG_SND_CS4281 is not set
-# CONFIG_SND_CS46XX is not set
-# CONFIG_SND_DARLA20 is not set
-# CONFIG_SND_GINA20 is not set
-# CONFIG_SND_LAYLA20 is not set
-# CONFIG_SND_DARLA24 is not set
-# CONFIG_SND_GINA24 is not set
-# CONFIG_SND_LAYLA24 is not set
-# CONFIG_SND_MONA is not set
-# CONFIG_SND_MIA is not set
-# CONFIG_SND_ECHO3G is not set
-# CONFIG_SND_INDIGO is not set
-# CONFIG_SND_INDIGOIO is not set
-# CONFIG_SND_INDIGODJ is not set
-# CONFIG_SND_EMU10K1 is not set
-# CONFIG_SND_EMU10K1X is not set
-# CONFIG_SND_ENS1370 is not set
-# CONFIG_SND_ENS1371 is not set
-# CONFIG_SND_ES1938 is not set
-# CONFIG_SND_ES1968 is not set
-CONFIG_SND_FM801=y
-# CONFIG_SND_FM801_TEA575X_BOOL is not set
-# CONFIG_SND_HDA_INTEL is not set
-# CONFIG_SND_HDSP is not set
-# CONFIG_SND_HDSPM is not set
-# CONFIG_SND_ICE1712 is not set
-# CONFIG_SND_ICE1724 is not set
-# CONFIG_SND_INTEL8X0 is not set
-# CONFIG_SND_INTEL8X0M is not set
-# CONFIG_SND_KORG1212 is not set
-# CONFIG_SND_MAESTRO3 is not set
-# CONFIG_SND_MIXART is not set
-# CONFIG_SND_NM256 is not set
-# CONFIG_SND_PCXHR is not set
-# CONFIG_SND_RIPTIDE is not set
-# CONFIG_SND_RME32 is not set
-# CONFIG_SND_RME96 is not set
-# CONFIG_SND_RME9652 is not set
-# CONFIG_SND_SONICVIBES is not set
-# CONFIG_SND_TRIDENT is not set
-# CONFIG_SND_VIA82XX is not set
-# CONFIG_SND_VIA82XX_MODEM is not set
-# CONFIG_SND_VX222 is not set
-# CONFIG_SND_YMFPCI is not set
-# CONFIG_SND_AC97_POWER_SAVE is not set
-
-#
-# USB devices
-#
-# CONFIG_SND_USB_AUDIO is not set
-
-#
-# SoC audio support
-#
-# CONFIG_SND_SOC is not set
-
-#
-# Open Sound System
-#
-# CONFIG_SOUND_PRIME is not set
-CONFIG_AC97_BUS=y
-
-#
-# 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=y
-# CONFIG_USB_DEBUG is not set
-
-#
-# Miscellaneous USB options
-#
-# CONFIG_USB_DEVICEFS 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_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
-# CONFIG_USB_OHCI_BIG_ENDIAN_MMIO is not set
-CONFIG_USB_OHCI_LITTLE_ENDIAN=y
-CONFIG_USB_UHCI_HCD=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_ISD200 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 Input Devices
-#
-CONFIG_USB_HID=y
-# CONFIG_USB_HIDINPUT_POWERBOOK is not set
-# CONFIG_HID_FF is not set
-CONFIG_USB_HIDDEV=y
-# 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
-
-#
-# 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_SISUSBVGA is not set
-# CONFIG_USB_LD is not set
-# CONFIG_USB_TRANCEVIBRATOR is not set
-# CONFIG_USB_IOWARRIOR is not set
-
-#
-# USB DSL modem support
-#
-
-#
-# USB Gadget Support
-#
-# CONFIG_USB_GADGET is not set
-
-#
-# MMC/SD Card support
-#
-# CONFIG_MMC is not set
-
-#
-# LED devices
-#
-# CONFIG_NEW_LEDS is not set
-
-#
-# LED drivers
-#
-
-#
-# LED Triggers
-#
-
-#
-# InfiniBand support
-#
-# CONFIG_INFINIBAND is not set
-
-#
-# EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
-#
-
-#
-# Real Time Clock
-#
-# CONFIG_RTC_CLASS is not set
-
-#
-# DMA Engine support
-#
-# CONFIG_DMA_ENGINE is not set
-
-#
-# DMA Clients
-#
-
-#
-# DMA Devices
-#
-
-#
-# Auxiliary Display support
-#
-
-#
-# Virtualization
-#
-# CONFIG_MSPEC is not set
-
-#
-# File systems
-#
-CONFIG_EXT2_FS=y
+CONFIG_EFI_VARS=y
+CONFIG_EXPERIMENTAL=y
CONFIG_EXT2_FS_XATTR=y
-# CONFIG_EXT2_FS_POSIX_ACL is not set
-# CONFIG_EXT2_FS_SECURITY is not set
-# CONFIG_EXT2_FS_XIP is not set
+CONFIG_EXT2_FS=y
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 is not set
-# CONFIG_QUOTA is not set
-CONFIG_DNOTIFY=y
-CONFIG_AUTOFS_FS=y
-# CONFIG_AUTOFS4_FS is not set
-# CONFIG_FUSE_FS is not set
-
-#
-# CD-ROM/DVD Filesystems
-#
+CONFIG_FB_RADEON_DEBUG=y
+CONFIG_FB_RADEON=y
+CONFIG_FLATMEM_MANUAL=y
+CONFIG_FUSION_CTL=m
+CONFIG_FUSION_FC=y
+CONFIG_FUSION_SPI=y
+CONFIG_FUSION=y
+CONFIG_HOTPLUG_CPU=y
+CONFIG_HOTPLUG_PCI_ACPI=y
+CONFIG_HOTPLUG_PCI=y
+CONFIG_HUGETLBFS=y
+# CONFIG_HWMON is not set
+# CONFIG_HW_RANDOM is not set
+CONFIG_I2C_CHARDEV=y
+CONFIG_IA64_HP_ZX1=y
+CONFIG_IA64_MCA_RECOVERY=y
+CONFIG_IA64_PALINFO=y
+CONFIG_IA64_PRINT_HAZARDS=y
+CONFIG_IDE=y
+CONFIG_INET=y
+CONFIG_INPUT_EVDEV=y
+CONFIG_INPUT_JOYDEV=y
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+CONFIG_IP_MULTICAST=y
+# CONFIG_IPV6 is not set
CONFIG_ISO9660_FS=y
CONFIG_JOLIET=y
-# CONFIG_ZISOFS is not set
-CONFIG_UDF_FS=y
-CONFIG_UDF_NLS=y
-
-#
-# DOS/FAT/NT Filesystems
-#
-CONFIG_FAT_FS=y
+CONFIG_KPROBES=y
+# CONFIG_LOGO_LINUX_MONO is not set
+# CONFIG_LOGO_LINUX_VGA16 is not set
+CONFIG_LOGO=y
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_MCKINLEY=y
+CONFIG_MODULES=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_KCORE=y
-CONFIG_PROC_VMCORE=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
-
-#
-# Network File Systems
-#
+CONFIG_NETDEVICES=y
+CONFIG_NET_ETHERNET=y
+CONFIG_NETFILTER=y
+CONFIG_NET_PCI=y
+CONFIG_NET_TULIP=y
+CONFIG_NFSD_V3=y
+CONFIG_NFSD=y
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 is not set
-# CONFIG_NFSD_TCP is not set
-CONFIG_LOCKD=y
-CONFIG_LOCKD_V4=y
-CONFIG_EXPORTFS=y
-CONFIG_NFS_COMMON=y
-CONFIG_SUNRPC=y
-CONFIG_SUNRPC_GSS=y
-CONFIG_RPCSEC_GSS_KRB5=y
-# CONFIG_RPCSEC_GSS_SPKM3 is not set
-# CONFIG_SMB_FS is not set
-# CONFIG_CIFS is not set
-# CONFIG_NCP_FS is not set
-# CONFIG_CODA_FS is not set
-# CONFIG_AFS_FS is not set
-# CONFIG_9P_FS is not set
-
-#
-# Partition Types
-#
-CONFIG_PARTITION_ADVANCED=y
-# CONFIG_ACORN_PARTITION is not set
-# CONFIG_OSF_PARTITION is not set
-# CONFIG_AMIGA_PARTITION is not set
-# CONFIG_ATARI_PARTITION is not set
-# CONFIG_MAC_PARTITION is not set
-CONFIG_MSDOS_PARTITION=y
-# CONFIG_BSD_DISKLABEL is not set
-# CONFIG_MINIX_SUBPARTITION is not set
-# CONFIG_SOLARIS_X86_PARTITION is not set
-# CONFIG_UNIXWARE_DISKLABEL is not set
-# CONFIG_LDM_PARTITION is not set
-# CONFIG_SGI_PARTITION is not set
-# CONFIG_ULTRIX_PARTITION is not set
-# CONFIG_SUN_PARTITION is not set
-# CONFIG_KARMA_PARTITION is not set
-CONFIG_EFI_PARTITION=y
-
-#
-# Native Language Support
-#
-CONFIG_NLS=y
-CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_1251=y
CONFIG_NLS_CODEPAGE_437=y
CONFIG_NLS_CODEPAGE_737=y
CONFIG_NLS_CODEPAGE_775=y
@@ -1470,15 +95,14 @@ CONFIG_NLS_CODEPAGE_864=y
CONFIG_NLS_CODEPAGE_865=y
CONFIG_NLS_CODEPAGE_866=y
CONFIG_NLS_CODEPAGE_869=y
-CONFIG_NLS_CODEPAGE_936=y
-CONFIG_NLS_CODEPAGE_950=y
+CONFIG_NLS_CODEPAGE_874=y
CONFIG_NLS_CODEPAGE_932=y
+CONFIG_NLS_CODEPAGE_936=y
CONFIG_NLS_CODEPAGE_949=y
-CONFIG_NLS_CODEPAGE_874=y
-CONFIG_NLS_ISO8859_8=y
-# CONFIG_NLS_CODEPAGE_1250 is not set
-CONFIG_NLS_CODEPAGE_1251=y
-# CONFIG_NLS_ASCII is not set
+CONFIG_NLS_CODEPAGE_950=y
+CONFIG_NLS_ISO8859_13=y
+CONFIG_NLS_ISO8859_14=y
+CONFIG_NLS_ISO8859_15=y
CONFIG_NLS_ISO8859_1=y
CONFIG_NLS_ISO8859_2=y
CONFIG_NLS_ISO8859_3=y
@@ -1486,125 +110,52 @@ CONFIG_NLS_ISO8859_4=y
CONFIG_NLS_ISO8859_5=y
CONFIG_NLS_ISO8859_6=y
CONFIG_NLS_ISO8859_7=y
+CONFIG_NLS_ISO8859_8=y
CONFIG_NLS_ISO8859_9=y
-CONFIG_NLS_ISO8859_13=y
-CONFIG_NLS_ISO8859_14=y
-CONFIG_NLS_ISO8859_15=y
CONFIG_NLS_KOI8_R=y
CONFIG_NLS_KOI8_U=y
CONFIG_NLS_UTF8=y
-
-#
-# Distributed Lock Manager
-#
-# CONFIG_DLM 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_PLIST=y
-CONFIG_HAS_IOMEM=y
-CONFIG_HAS_IOPORT=y
-CONFIG_GENERIC_HARDIRQS=y
-CONFIG_GENERIC_IRQ_PROBE=y
-CONFIG_GENERIC_PENDING_IRQ=y
-CONFIG_IRQ_PER_CPU=y
-
-#
-# Instrumentation Support
-#
-# CONFIG_PROFILING is not set
-CONFIG_KPROBES=y
-
-#
-# 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=17
-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=y
-# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
-# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
-# CONFIG_DEBUG_KOBJECT is not set
-# CONFIG_DEBUG_INFO is not set
-# CONFIG_DEBUG_VM is not set
-# CONFIG_DEBUG_LIST is not set
-CONFIG_FORCED_INLINING=y
-# CONFIG_RCU_TORTURE_TEST is not set
-# CONFIG_LKDTM is not set
-# CONFIG_FAULT_INJECTION is not set
-CONFIG_IA64_GRANULE_16MB=y
-# CONFIG_IA64_GRANULE_64MB is not set
-CONFIG_IA64_PRINT_HAZARDS=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=y
-CONFIG_CRYPTO_MANAGER=y
-# CONFIG_CRYPTO_HMAC is not set
-# CONFIG_CRYPTO_XCBC is not set
-# CONFIG_CRYPTO_NULL is not set
-# CONFIG_CRYPTO_MD4 is not set
-CONFIG_CRYPTO_MD5=y
-# CONFIG_CRYPTO_SHA1 is not set
-# CONFIG_CRYPTO_SHA256 is not set
-# CONFIG_CRYPTO_SHA512 is not set
-# CONFIG_CRYPTO_WP512 is not set
-# CONFIG_CRYPTO_TGR192 is not set
-# CONFIG_CRYPTO_GF128MUL is not set
-CONFIG_CRYPTO_ECB=m
-CONFIG_CRYPTO_CBC=y
-CONFIG_CRYPTO_PCBC=m
-# CONFIG_CRYPTO_LRW is not set
-CONFIG_CRYPTO_DES=y
-# CONFIG_CRYPTO_FCRYPT is not set
-# CONFIG_CRYPTO_BLOWFISH is not set
-# CONFIG_CRYPTO_TWOFISH is not set
-# CONFIG_CRYPTO_SERPENT is not set
-# CONFIG_CRYPTO_AES is not set
-# CONFIG_CRYPTO_CAST5 is not set
-# CONFIG_CRYPTO_CAST6 is not set
-# CONFIG_CRYPTO_TEA is not set
-# CONFIG_CRYPTO_ARC4 is not set
-# CONFIG_CRYPTO_KHAZAD is not set
-# CONFIG_CRYPTO_ANUBIS is not set
-# CONFIG_CRYPTO_DEFLATE is not set
-# CONFIG_CRYPTO_MICHAEL_MIC is not set
-# CONFIG_CRYPTO_CRC32C is not set
-# CONFIG_CRYPTO_CAMELLIA is not set
-# CONFIG_CRYPTO_TEST is not set
-
-#
-# Hardware crypto devices
-#
+CONFIG_NR_CPUS=16
+CONFIG_PACKET=y
+CONFIG_PARTITION_ADVANCED=y
+CONFIG_PERFMON=y
+CONFIG_PROC_KCORE=y
+CONFIG_SCSI_CONSTANTS=y
+CONFIG_SCSI_LOGGING=y
+CONFIG_SCSI_MULTI_LUN=y
+CONFIG_SCSI_QLOGIC_1280=y
+CONFIG_SCSI_SYM53C8XX_2=y
+CONFIG_SCSI=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_EXTENDED=y
+CONFIG_SERIAL_8250_NR_UARTS=8
+CONFIG_SERIAL_8250_SHARE_IRQ=y
+CONFIG_SERIAL_8250=y
+# CONFIG_SERIO_I8042 is not set
+# CONFIG_SERIO_SERPORT is not set
+CONFIG_SMP=y
+CONFIG_SND_FM801=y
+CONFIG_SND_MIXER_OSS=y
+CONFIG_SND_PCM_OSS=y
+CONFIG_SND_SEQUENCER_OSS=y
+CONFIG_SND_SEQUENCER=y
+CONFIG_SND=y
+CONFIG_SOUND=y
+CONFIG_SYSVIPC=y
+CONFIG_TIGON3=y
+CONFIG_TMPFS=y
+CONFIG_TULIP_MMIO=y
+CONFIG_TULIP_MWI=y
+CONFIG_TULIP_NAPI_HW_MITIGATION=y
+CONFIG_TULIP_NAPI=y
+CONFIG_TULIP=y
+CONFIG_UDF_FS=y
+CONFIG_UNIX=y
+CONFIG_USB_EHCI_HCD=y
+CONFIG_USB_HIDDEV=y
+CONFIG_USB_MON=y
+CONFIG_USB_OHCI_HCD=y
+CONFIG_USB_STORAGE=y
+CONFIG_USB_UHCI_HCD=y
+CONFIG_USB=y
+CONFIG_VFAT_FS=y
diff --git a/arch/ia64/include/asm/kvm_host.h b/arch/ia64/include/asm/kvm_host.h
index a362e67e0ca..2f229e5de49 100644
--- a/arch/ia64/include/asm/kvm_host.h
+++ b/arch/ia64/include/asm/kvm_host.h
@@ -235,6 +235,7 @@ struct kvm_vm_data {
#define KVM_REQ_PTC_G 32
#define KVM_REQ_RESUME 33
+#define KVM_HPAGE_GFN_SHIFT(x) 0
#define KVM_NR_PAGE_SIZES 1
#define KVM_PAGES_PER_HPAGE(x) 1
diff --git a/arch/ia64/include/asm/local64.h b/arch/ia64/include/asm/local64.h
new file mode 100644
index 00000000000..36c93b5cc23
--- /dev/null
+++ b/arch/ia64/include/asm/local64.h
@@ -0,0 +1 @@
+#include <asm-generic/local64.h>
diff --git a/arch/ia64/include/asm/page.h b/arch/ia64/include/asm/page.h
index 5f271bc712e..41b6d31110f 100644
--- a/arch/ia64/include/asm/page.h
+++ b/arch/ia64/include/asm/page.h
@@ -41,7 +41,7 @@
#define PAGE_SIZE (__IA64_UL_CONST(1) << PAGE_SHIFT)
#define PAGE_MASK (~(PAGE_SIZE - 1))
-#define PERCPU_PAGE_SHIFT 16 /* log2() of max. size of per-CPU area */
+#define PERCPU_PAGE_SHIFT 18 /* log2() of max. size of per-CPU area */
#define PERCPU_PAGE_SIZE (__IA64_UL_CONST(1) << PERCPU_PAGE_SHIFT)
diff --git a/arch/ia64/kernel/msi_ia64.c b/arch/ia64/kernel/msi_ia64.c
index 6c892285604..4a746ea838f 100644
--- a/arch/ia64/kernel/msi_ia64.c
+++ b/arch/ia64/kernel/msi_ia64.c
@@ -25,7 +25,7 @@ static int ia64_set_msi_irq_affinity(unsigned int irq,
if (irq_prepare_move(irq, cpu))
return -1;
- read_msi_msg(irq, &msg);
+ get_cached_msi_msg(irq, &msg);
addr = msg.address_lo;
addr &= MSI_ADDR_DEST_ID_MASK;
diff --git a/arch/ia64/kernel/perfmon.c b/arch/ia64/kernel/perfmon.c
index ab985f785c1..744329072f3 100644
--- a/arch/ia64/kernel/perfmon.c
+++ b/arch/ia64/kernel/perfmon.c
@@ -1696,8 +1696,8 @@ pfm_poll(struct file *filp, poll_table * wait)
return mask;
}
-static int
-pfm_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+static long
+pfm_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
DPRINT(("pfm_ioctl called\n"));
return -EINVAL;
@@ -2174,15 +2174,15 @@ pfm_no_open(struct inode *irrelevant, struct file *dontcare)
static const struct file_operations pfm_file_ops = {
- .llseek = no_llseek,
- .read = pfm_read,
- .write = pfm_write,
- .poll = pfm_poll,
- .ioctl = pfm_ioctl,
- .open = pfm_no_open, /* special open code to disallow open via /proc */
- .fasync = pfm_fasync,
- .release = pfm_close,
- .flush = pfm_flush
+ .llseek = no_llseek,
+ .read = pfm_read,
+ .write = pfm_write,
+ .poll = pfm_poll,
+ .unlocked_ioctl = pfm_ioctl,
+ .open = pfm_no_open, /* special open code to disallow open via /proc */
+ .fasync = pfm_fasync,
+ .release = pfm_close,
+ .flush = pfm_flush
};
static int
diff --git a/arch/ia64/kernel/smpboot.c b/arch/ia64/kernel/smpboot.c
index 6a1380e90f8..99dcc85193c 100644
--- a/arch/ia64/kernel/smpboot.c
+++ b/arch/ia64/kernel/smpboot.c
@@ -519,7 +519,7 @@ do_boot_cpu (int sapicid, int cpu)
/*
* We can't use kernel_thread since we must avoid to reschedule the child.
*/
- if (!keventd_up() || current_is_keventd())
+ if (!keventd_up())
c_idle.work.func(&c_idle.work);
else {
schedule_work(&c_idle.work);
diff --git a/arch/ia64/kernel/time.c b/arch/ia64/kernel/time.c
index 653b3c46ea8..ed6f22eb5b1 100644
--- a/arch/ia64/kernel/time.c
+++ b/arch/ia64/kernel/time.c
@@ -471,7 +471,8 @@ void update_vsyscall_tz(void)
{
}
-void update_vsyscall(struct timespec *wall, struct clocksource *c, u32 mult)
+void update_vsyscall(struct timespec *wall, struct timespec *wtm,
+ struct clocksource *c, u32 mult)
{
unsigned long flags;
@@ -487,9 +488,9 @@ void update_vsyscall(struct timespec *wall, struct clocksource *c, u32 mult)
/* 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
+ fsyscall_gtod_data.monotonic_time.tv_sec = wtm->tv_sec
+ wall->tv_sec;
- fsyscall_gtod_data.monotonic_time.tv_nsec = wall_to_monotonic.tv_nsec
+ fsyscall_gtod_data.monotonic_time.tv_nsec = wtm->tv_nsec
+ wall->tv_nsec;
/* normalize */
diff --git a/arch/ia64/kernel/vmlinux.lds.S b/arch/ia64/kernel/vmlinux.lds.S
index e07218a2577..5a4d044dcb1 100644
--- a/arch/ia64/kernel/vmlinux.lds.S
+++ b/arch/ia64/kernel/vmlinux.lds.S
@@ -6,204 +6,209 @@
#include <asm-generic/vmlinux.lds.h>
-#define IVT_TEXT \
- VMLINUX_SYMBOL(__start_ivt_text) = .; \
- *(.text..ivt) \
- VMLINUX_SYMBOL(__end_ivt_text) = .;
-
OUTPUT_FORMAT("elf64-ia64-little")
OUTPUT_ARCH(ia64)
ENTRY(phys_start)
jiffies = jiffies_64;
+
PHDRS {
- code PT_LOAD;
- percpu PT_LOAD;
- data PT_LOAD;
- note PT_NOTE;
- unwind 0x70000001; /* PT_IA_64_UNWIND, but ld doesn't match the name */
+ code PT_LOAD;
+ percpu PT_LOAD;
+ data PT_LOAD;
+ note PT_NOTE;
+ unwind 0x70000001; /* PT_IA_64_UNWIND, but ld doesn't match the name */
}
-SECTIONS
-{
- /* unwind exit sections must be discarded before the rest of the
- sections get included. */
- /DISCARD/ : {
- *(.IA_64.unwind.exit.text)
- *(.IA_64.unwind_info.exit.text)
- *(.comment)
- *(.note)
- }
-
- v = PAGE_OFFSET; /* this symbol is here to make debugging easier... */
- phys_start = _start - LOAD_OFFSET;
-
- code : { } :code
- . = KERNEL_START;
-
- _text = .;
- _stext = .;
-
- .text : AT(ADDR(.text) - LOAD_OFFSET)
- {
- IVT_TEXT
- TEXT_TEXT
- SCHED_TEXT
- LOCK_TEXT
- KPROBES_TEXT
- *(.gnu.linkonce.t*)
- }
- .text2 : AT(ADDR(.text2) - LOAD_OFFSET)
- { *(.text2) }
-#ifdef CONFIG_SMP
- .text..lock : AT(ADDR(.text..lock) - LOAD_OFFSET)
- { *(.text..lock) }
-#endif
- _etext = .;
- /* Read-only data */
+SECTIONS {
+ /*
+ * unwind exit sections must be discarded before
+ * the rest of the sections get included.
+ */
+ /DISCARD/ : {
+ *(.IA_64.unwind.exit.text)
+ *(.IA_64.unwind_info.exit.text)
+ *(.comment)
+ *(.note)
+ }
- NOTES :code :note /* put .notes in text and mark in PT_NOTE */
- code_continues : {} :code /* switch back to regular program... */
+ v = PAGE_OFFSET; /* this symbol is here to make debugging easier... */
+ phys_start = _start - LOAD_OFFSET;
+
+ code : {
+ } :code
+ . = KERNEL_START;
+
+ _text = .;
+ _stext = .;
+
+ .text : AT(ADDR(.text) - LOAD_OFFSET) {
+ __start_ivt_text = .;
+ *(.text..ivt)
+ __end_ivt_text = .;
+ TEXT_TEXT
+ SCHED_TEXT
+ LOCK_TEXT
+ KPROBES_TEXT
+ *(.gnu.linkonce.t*)
+ }
- EXCEPTION_TABLE(16)
+ .text2 : AT(ADDR(.text2) - LOAD_OFFSET) {
+ *(.text2)
+ }
- /* MCA table */
- . = ALIGN(16);
- __mca_table : AT(ADDR(__mca_table) - LOAD_OFFSET)
- {
- __start___mca_table = .;
- *(__mca_table)
- __stop___mca_table = .;
+#ifdef CONFIG_SMP
+ .text..lock : AT(ADDR(.text..lock) - LOAD_OFFSET) {
+ *(.text..lock)
+ }
+#endif
+ _etext = .;
+
+ /*
+ * Read-only data
+ */
+ NOTES :code :note /* put .notes in text and mark in PT_NOTE */
+ code_continues : {
+ } : code /* switch back to regular program... */
+
+ EXCEPTION_TABLE(16)
+
+ /* MCA table */
+ . = ALIGN(16);
+ __mca_table : AT(ADDR(__mca_table) - LOAD_OFFSET) {
+ __start___mca_table = .;
+ *(__mca_table)
+ __stop___mca_table = .;
}
- .data..patch.phys_stack_reg : AT(ADDR(.data..patch.phys_stack_reg) - LOAD_OFFSET)
- {
- __start___phys_stack_reg_patchlist = .;
- *(.data..patch.phys_stack_reg)
- __end___phys_stack_reg_patchlist = .;
+ .data..patch.phys_stack_reg : AT(ADDR(.data..patch.phys_stack_reg) - LOAD_OFFSET) {
+ __start___phys_stack_reg_patchlist = .;
+ *(.data..patch.phys_stack_reg)
+ __end___phys_stack_reg_patchlist = .;
}
- /* Global data */
- _data = .;
+ /*
+ * Global data
+ */
+ _data = .;
- /* Unwind info & table: */
- . = ALIGN(8);
- .IA_64.unwind_info : AT(ADDR(.IA_64.unwind_info) - LOAD_OFFSET)
- { *(.IA_64.unwind_info*) }
- .IA_64.unwind : AT(ADDR(.IA_64.unwind) - LOAD_OFFSET)
- {
- __start_unwind = .;
- *(.IA_64.unwind*)
- __end_unwind = .;
+ /* Unwind info & table: */
+ . = ALIGN(8);
+ .IA_64.unwind_info : AT(ADDR(.IA_64.unwind_info) - LOAD_OFFSET) {
+ *(.IA_64.unwind_info*)
+ }
+ .IA_64.unwind : AT(ADDR(.IA_64.unwind) - LOAD_OFFSET) {
+ __start_unwind = .;
+ *(.IA_64.unwind*)
+ __end_unwind = .;
} :code :unwind
- code_continues2 : {} : code
+ code_continues2 : {
+ } : code
- RODATA
+ RODATA
- .opd : AT(ADDR(.opd) - LOAD_OFFSET)
- { *(.opd) }
-
- /* Initialization code and data: */
+ .opd : AT(ADDR(.opd) - LOAD_OFFSET) {
+ *(.opd)
+ }
- . = ALIGN(PAGE_SIZE);
- __init_begin = .;
+ /*
+ * Initialization code and data:
+ */
+ . = ALIGN(PAGE_SIZE);
+ __init_begin = .;
- INIT_TEXT_SECTION(PAGE_SIZE)
- INIT_DATA_SECTION(16)
+ INIT_TEXT_SECTION(PAGE_SIZE)
+ INIT_DATA_SECTION(16)
- .data..patch.vtop : AT(ADDR(.data..patch.vtop) - LOAD_OFFSET)
- {
- __start___vtop_patchlist = .;
- *(.data..patch.vtop)
- __end___vtop_patchlist = .;
+ .data..patch.vtop : AT(ADDR(.data..patch.vtop) - LOAD_OFFSET) {
+ __start___vtop_patchlist = .;
+ *(.data..patch.vtop)
+ __end___vtop_patchlist = .;
}
- .data..patch.rse : AT(ADDR(.data..patch.rse) - LOAD_OFFSET)
- {
- __start___rse_patchlist = .;
- *(.data..patch.rse)
- __end___rse_patchlist = .;
+ .data..patch.rse : AT(ADDR(.data..patch.rse) - LOAD_OFFSET) {
+ __start___rse_patchlist = .;
+ *(.data..patch.rse)
+ __end___rse_patchlist = .;
}
- .data..patch.mckinley_e9 : AT(ADDR(.data..patch.mckinley_e9) - LOAD_OFFSET)
- {
- __start___mckinley_e9_bundles = .;
- *(.data..patch.mckinley_e9)
- __end___mckinley_e9_bundles = .;
+ .data..patch.mckinley_e9 : AT(ADDR(.data..patch.mckinley_e9) - LOAD_OFFSET) {
+ __start___mckinley_e9_bundles = .;
+ *(.data..patch.mckinley_e9)
+ __end___mckinley_e9_bundles = .;
}
#if defined(CONFIG_PARAVIRT)
- . = ALIGN(16);
- .paravirt_bundles : AT(ADDR(.paravirt_bundles) - LOAD_OFFSET)
- {
- __start_paravirt_bundles = .;
- *(.paravirt_bundles)
- __stop_paravirt_bundles = .;
- }
- . = ALIGN(16);
- .paravirt_insts : AT(ADDR(.paravirt_insts) - LOAD_OFFSET)
- {
- __start_paravirt_insts = .;
- *(.paravirt_insts)
- __stop_paravirt_insts = .;
- }
- . = ALIGN(16);
- .paravirt_branches : AT(ADDR(.paravirt_branches) - LOAD_OFFSET)
- {
- __start_paravirt_branches = .;
- *(.paravirt_branches)
- __stop_paravirt_branches = .;
+ . = ALIGN(16);
+ .paravirt_bundles : AT(ADDR(.paravirt_bundles) - LOAD_OFFSET) {
+ __start_paravirt_bundles = .;
+ *(.paravirt_bundles)
+ __stop_paravirt_bundles = .;
+ }
+ . = ALIGN(16);
+ .paravirt_insts : AT(ADDR(.paravirt_insts) - LOAD_OFFSET) {
+ __start_paravirt_insts = .;
+ *(.paravirt_insts)
+ __stop_paravirt_insts = .;
+ }
+ . = ALIGN(16);
+ .paravirt_branches : AT(ADDR(.paravirt_branches) - LOAD_OFFSET) {
+ __start_paravirt_branches = .;
+ *(.paravirt_branches)
+ __stop_paravirt_branches = .;
}
#endif
#if defined(CONFIG_IA64_GENERIC)
- /* Machine Vector */
- . = ALIGN(16);
- .machvec : AT(ADDR(.machvec) - LOAD_OFFSET)
- {
- machvec_start = .;
- *(.machvec)
- machvec_end = .;
+ /* Machine Vector */
+ . = ALIGN(16);
+ .machvec : AT(ADDR(.machvec) - LOAD_OFFSET) {
+ machvec_start = .;
+ *(.machvec)
+ machvec_end = .;
}
#endif
#ifdef CONFIG_SMP
- . = ALIGN(PERCPU_PAGE_SIZE);
- __cpu0_per_cpu = .;
- . = . + PERCPU_PAGE_SIZE; /* cpu0 per-cpu space */
+ . = ALIGN(PERCPU_PAGE_SIZE);
+ __cpu0_per_cpu = .;
+ . = . + PERCPU_PAGE_SIZE; /* cpu0 per-cpu space */
#endif
- . = ALIGN(PAGE_SIZE);
- __init_end = .;
+ . = ALIGN(PAGE_SIZE);
+ __init_end = .;
- .data..page_aligned : AT(ADDR(.data..page_aligned) - LOAD_OFFSET)
- {
- PAGE_ALIGNED_DATA(PAGE_SIZE)
- . = ALIGN(PAGE_SIZE);
- __start_gate_section = .;
- *(.data..gate)
- __stop_gate_section = .;
+ .data..page_aligned : AT(ADDR(.data..page_aligned) - LOAD_OFFSET) {
+ PAGE_ALIGNED_DATA(PAGE_SIZE)
+ . = ALIGN(PAGE_SIZE);
+ __start_gate_section = .;
+ *(.data..gate)
+ __stop_gate_section = .;
#ifdef CONFIG_XEN
- . = ALIGN(PAGE_SIZE);
- __xen_start_gate_section = .;
- *(.data..gate.xen)
- __xen_stop_gate_section = .;
+ . = ALIGN(PAGE_SIZE);
+ __xen_start_gate_section = .;
+ *(.data..gate.xen)
+ __xen_stop_gate_section = .;
#endif
}
- . = ALIGN(PAGE_SIZE); /* make sure the gate page doesn't expose
- * kernel data
- */
-
- /* Per-cpu data: */
- . = ALIGN(PERCPU_PAGE_SIZE);
- PERCPU_VADDR(PERCPU_ADDR, :percpu)
- __phys_per_cpu_start = __per_cpu_load;
- . = __phys_per_cpu_start + PERCPU_PAGE_SIZE; /* ensure percpu data fits
- * into percpu page size
- */
-
- data : { } :data
- .data : AT(ADDR(.data) - LOAD_OFFSET)
- {
+ /*
+ * make sure the gate page doesn't expose
+ * kernel data
+ */
+ . = ALIGN(PAGE_SIZE);
+
+ /* Per-cpu data: */
+ . = ALIGN(PERCPU_PAGE_SIZE);
+ PERCPU_VADDR(PERCPU_ADDR, :percpu)
+ __phys_per_cpu_start = __per_cpu_load;
+ /*
+ * ensure percpu data fits
+ * into percpu page size
+ */
+ . = __phys_per_cpu_start + PERCPU_PAGE_SIZE;
+
+ data : {
+ } :data
+ .data : AT(ADDR(.data) - LOAD_OFFSET) {
INIT_TASK_DATA(PAGE_SIZE)
CACHELINE_ALIGNED_DATA(SMP_CACHE_BYTES)
READ_MOSTLY_DATA(SMP_CACHE_BYTES)
@@ -213,26 +218,37 @@ SECTIONS
CONSTRUCTORS
}
- . = ALIGN(16); /* gp must be 16-byte aligned for exc. table */
- .got : AT(ADDR(.got) - LOAD_OFFSET)
- { *(.got.plt) *(.got) }
- __gp = ADDR(.got) + 0x200000;
- /* We want the small data sections together, so single-instruction offsets
- can access them all, and initialized data all before uninitialized, so
- we can shorten the on-disk segment size. */
- .sdata : AT(ADDR(.sdata) - LOAD_OFFSET)
- { *(.sdata) *(.sdata1) *(.srdata) }
- _edata = .;
+ . = ALIGN(16); /* gp must be 16-byte aligned for exc. table */
+ .got : AT(ADDR(.got) - LOAD_OFFSET) {
+ *(.got.plt)
+ *(.got)
+ }
+ __gp = ADDR(.got) + 0x200000;
+
+ /*
+ * We want the small data sections together,
+ * so single-instruction offsets can access
+ * them all, and initialized data all before
+ * uninitialized, so we can shorten the
+ * on-disk segment size.
+ */
+ .sdata : AT(ADDR(.sdata) - LOAD_OFFSET) {
+ *(.sdata)
+ *(.sdata1)
+ *(.srdata)
+ }
+ _edata = .;
- BSS_SECTION(0, 0, 0)
+ BSS_SECTION(0, 0, 0)
- _end = .;
+ _end = .;
- code : { } :code
+ code : {
+ } :code
- STABS_DEBUG
- DWARF_DEBUG
+ STABS_DEBUG
+ DWARF_DEBUG
- /* Default discards */
- DISCARDS
+ /* Default discards */
+ DISCARDS
}
diff --git a/arch/ia64/kvm/kvm-ia64.c b/arch/ia64/kvm/kvm-ia64.c
index 21b701374f7..f56a6316e13 100644
--- a/arch/ia64/kvm/kvm-ia64.c
+++ b/arch/ia64/kvm/kvm-ia64.c
@@ -725,8 +725,6 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
int r;
sigset_t sigsaved;
- vcpu_load(vcpu);
-
if (vcpu->sigset_active)
sigprocmask(SIG_SETMASK, &vcpu->sigset, &sigsaved);
@@ -748,7 +746,6 @@ out:
if (vcpu->sigset_active)
sigprocmask(SIG_SETMASK, &sigsaved, NULL);
- vcpu_put(vcpu);
return r;
}
@@ -883,8 +880,6 @@ int kvm_arch_vcpu_ioctl_set_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
struct vpd *vpd = to_host(vcpu->kvm, vcpu->arch.vpd);
int i;
- vcpu_load(vcpu);
-
for (i = 0; i < 16; i++) {
vpd->vgr[i] = regs->vpd.vgr[i];
vpd->vbgr[i] = regs->vpd.vbgr[i];
@@ -931,8 +926,6 @@ int kvm_arch_vcpu_ioctl_set_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
vcpu->arch.itc_offset = regs->saved_itc - kvm_get_itc(vcpu);
set_bit(KVM_REQ_RESUME, &vcpu->requests);
- vcpu_put(vcpu);
-
return 0;
}
@@ -1237,7 +1230,7 @@ int kvm_arch_vcpu_init(struct kvm_vcpu *vcpu)
p_ctx->cr[2] = (unsigned long)kvm_vmm_info->vmm_ivt;
p_ctx->cr[8] = 0x3c;
- /*Initilize region register*/
+ /*Initialize region register*/
p_ctx->rr[0] = 0x30;
p_ctx->rr[1] = 0x30;
p_ctx->rr[2] = 0x30;
@@ -1246,7 +1239,7 @@ int kvm_arch_vcpu_init(struct kvm_vcpu *vcpu)
p_ctx->rr[5] = 0x30;
p_ctx->rr[7] = 0x30;
- /*Initilize branch register 0*/
+ /*Initialize branch register 0*/
p_ctx->br[0] = *(unsigned long *)kvm_vmm_info->vmm_entry;
vcpu->arch.vmm_rr = kvm->arch.vmm_init_rr;
@@ -1707,7 +1700,7 @@ static int kvm_relocate_vmm(struct kvm_vmm_info *vmm_info,
BUG_ON(!module);
if (!kvm_vmm_base) {
- printk("kvm: kvm area hasn't been initilized yet!!\n");
+ printk("kvm: kvm area hasn't been initialized yet!!\n");
return -EFAULT;
}
@@ -1802,35 +1795,24 @@ void kvm_arch_exit(void)
kvm_vmm_info = NULL;
}
-static int kvm_ia64_sync_dirty_log(struct kvm *kvm,
- struct kvm_dirty_log *log)
+static void kvm_ia64_sync_dirty_log(struct kvm *kvm,
+ struct kvm_memory_slot *memslot)
{
- struct kvm_memory_slot *memslot;
- int r, i;
+ int i;
long base;
unsigned long n;
unsigned long *dirty_bitmap = (unsigned long *)(kvm->arch.vm_base +
offsetof(struct kvm_vm_data, kvm_mem_dirty_log));
- r = -EINVAL;
- if (log->slot >= KVM_MEMORY_SLOTS)
- goto out;
-
- memslot = &kvm->memslots->memslots[log->slot];
- r = -ENOENT;
- if (!memslot->dirty_bitmap)
- goto out;
-
n = kvm_dirty_bitmap_bytes(memslot);
base = memslot->base_gfn / BITS_PER_LONG;
+ spin_lock(&kvm->arch.dirty_log_lock);
for (i = 0; i < n/sizeof(long); ++i) {
memslot->dirty_bitmap[i] = dirty_bitmap[base + i];
dirty_bitmap[base + i] = 0;
}
- r = 0;
-out:
- return r;
+ spin_unlock(&kvm->arch.dirty_log_lock);
}
int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm,
@@ -1842,12 +1824,17 @@ int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm,
int is_dirty = 0;
mutex_lock(&kvm->slots_lock);
- spin_lock(&kvm->arch.dirty_log_lock);
- r = kvm_ia64_sync_dirty_log(kvm, log);
- if (r)
+ r = -EINVAL;
+ if (log->slot >= KVM_MEMORY_SLOTS)
+ goto out;
+
+ memslot = &kvm->memslots->memslots[log->slot];
+ r = -ENOENT;
+ if (!memslot->dirty_bitmap)
goto out;
+ kvm_ia64_sync_dirty_log(kvm, memslot);
r = kvm_get_dirty_log(kvm, log, &is_dirty);
if (r)
goto out;
@@ -1855,14 +1842,12 @@ int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm,
/* If nothing is dirty, don't bother messing with page tables. */
if (is_dirty) {
kvm_flush_remote_tlbs(kvm);
- memslot = &kvm->memslots->memslots[log->slot];
n = kvm_dirty_bitmap_bytes(memslot);
memset(memslot->dirty_bitmap, 0, n);
}
r = 0;
out:
mutex_unlock(&kvm->slots_lock);
- spin_unlock(&kvm->arch.dirty_log_lock);
return r;
}
@@ -1953,11 +1938,6 @@ int kvm_cpu_has_pending_timer(struct kvm_vcpu *vcpu)
return vcpu->arch.timer_fired;
}
-gfn_t unalias_gfn(struct kvm *kvm, gfn_t gfn)
-{
- return gfn;
-}
-
int kvm_arch_vcpu_runnable(struct kvm_vcpu *vcpu)
{
return (vcpu->arch.mp_state == KVM_MP_STATE_RUNNABLE) ||
@@ -1967,9 +1947,7 @@ int kvm_arch_vcpu_runnable(struct kvm_vcpu *vcpu)
int kvm_arch_vcpu_ioctl_get_mpstate(struct kvm_vcpu *vcpu,
struct kvm_mp_state *mp_state)
{
- vcpu_load(vcpu);
mp_state->mp_state = vcpu->arch.mp_state;
- vcpu_put(vcpu);
return 0;
}
@@ -2000,10 +1978,8 @@ int kvm_arch_vcpu_ioctl_set_mpstate(struct kvm_vcpu *vcpu,
{
int r = 0;
- vcpu_load(vcpu);
vcpu->arch.mp_state = mp_state->mp_state;
if (vcpu->arch.mp_state == KVM_MP_STATE_UNINITIALIZED)
r = vcpu_reset(vcpu);
- vcpu_put(vcpu);
return r;
}
diff --git a/arch/ia64/sn/kernel/msi_sn.c b/arch/ia64/sn/kernel/msi_sn.c
index ebfdd6a9ae1..0c72dd46383 100644
--- a/arch/ia64/sn/kernel/msi_sn.c
+++ b/arch/ia64/sn/kernel/msi_sn.c
@@ -175,7 +175,7 @@ static int sn_set_msi_irq_affinity(unsigned int irq,
* Release XIO resources for the old MSI PCI address
*/
- read_msi_msg(irq, &msg);
+ get_cached_msi_msg(irq, &msg);
sn_pdev = (struct pcidev_info *)sn_irq_info->irq_pciioinfo;
pdev = sn_pdev->pdi_linux_pcidev;
provider = SN_PCIDEV_BUSPROVIDER(pdev);
diff --git a/arch/ia64/sn/kernel/setup.c b/arch/ia64/sn/kernel/setup.c
index d00dfc18002..dbc4cbecb5e 100644
--- a/arch/ia64/sn/kernel/setup.c
+++ b/arch/ia64/sn/kernel/setup.c
@@ -507,7 +507,7 @@ static void __init sn_init_pdas(char **cmdline_p)
cnodeid_t cnode;
/*
- * Allocate & initalize the nodepda for each node.
+ * Allocate & initialize the nodepda for each node.
*/
for_each_online_node(cnode) {
nodepdaindr[cnode] =
diff --git a/arch/m32r/Kconfig b/arch/m32r/Kconfig
index 3a9319f93e8..836abbbc9c0 100644
--- a/arch/m32r/Kconfig
+++ b/arch/m32r/Kconfig
@@ -44,9 +44,6 @@ config HZ
int
default 100
-config GENERIC_TIME
- def_bool y
-
config ARCH_USES_GETTIMEOFFSET
def_bool y
diff --git a/arch/m32r/Makefile b/arch/m32r/Makefile
index 469766b24e2..8ff5ba0ea26 100644
--- a/arch/m32r/Makefile
+++ b/arch/m32r/Makefile
@@ -12,8 +12,8 @@ OBJCOPYFLAGS := -O binary -R .note -R .comment -S
LDFLAGS_vmlinux :=
KBUILD_CFLAGS += -pipe -fno-schedule-insns
-CFLAGS_KERNEL += -mmodel=medium
-CFLAGS_MODULE += -mmodel=large
+KBUILD_CFLAGS_KERNEL += -mmodel=medium
+KBUILD_CFLAGS_MODULE += -mmodel=large
ifdef CONFIG_CHIP_VDEC2
cflags-$(CONFIG_ISA_M32R2) += -DNO_FPU -Wa,-bitinst
diff --git a/arch/m32r/include/asm/local64.h b/arch/m32r/include/asm/local64.h
new file mode 100644
index 00000000000..36c93b5cc23
--- /dev/null
+++ b/arch/m32r/include/asm/local64.h
@@ -0,0 +1 @@
+#include <asm-generic/local64.h>
diff --git a/arch/m68k/Kconfig b/arch/m68k/Kconfig
index 2e3737b92ff..8030e2481d9 100644
--- a/arch/m68k/Kconfig
+++ b/arch/m68k/Kconfig
@@ -59,9 +59,6 @@ config HZ
int
default 100
-config GENERIC_TIME
- def_bool y
-
config ARCH_USES_GETTIMEOFFSET
def_bool y
diff --git a/arch/m68k/Makefile b/arch/m68k/Makefile
index 570d85c3f97..b06a7e3cbcd 100644
--- a/arch/m68k/Makefile
+++ b/arch/m68k/Makefile
@@ -18,7 +18,7 @@ KBUILD_DEFCONFIG := multi_defconfig
# override top level makefile
AS += -m68020
LDFLAGS := -m m68kelf
-LDFLAGS_MODULE += -T $(srctree)/arch/m68k/kernel/module.lds
+KBUILD_LDFLAGS_MODULE += -T $(srctree)/arch/m68k/kernel/module.lds
ifneq ($(SUBARCH),$(ARCH))
ifeq ($(CROSS_COMPILE),)
CROSS_COMPILE := $(call cc-cross-prefix, \
diff --git a/arch/m68k/include/asm/local64.h b/arch/m68k/include/asm/local64.h
new file mode 100644
index 00000000000..36c93b5cc23
--- /dev/null
+++ b/arch/m68k/include/asm/local64.h
@@ -0,0 +1 @@
+#include <asm-generic/local64.h>
diff --git a/arch/m68knommu/Kconfig b/arch/m68knommu/Kconfig
index efeb6033fc1..2609c394e1d 100644
--- a/arch/m68knommu/Kconfig
+++ b/arch/m68knommu/Kconfig
@@ -63,10 +63,6 @@ config GENERIC_CALIBRATE_DELAY
bool
default y
-config GENERIC_TIME
- bool
- default y
-
config GENERIC_CMOS_UPDATE
bool
default y
diff --git a/arch/microblaze/Kconfig b/arch/microblaze/Kconfig
index 505a0859242..692fdfce2a2 100644
--- a/arch/microblaze/Kconfig
+++ b/arch/microblaze/Kconfig
@@ -14,9 +14,12 @@ config MICROBLAZE
select USB_ARCH_HAS_EHCI
select ARCH_WANT_OPTIONAL_GPIOLIB
select HAVE_OPROFILE
+ select HAVE_ARCH_KGDB
select HAVE_DMA_ATTRS
select HAVE_DMA_API_DEBUG
select TRACING_SUPPORT
+ select OF
+ select OF_FLATTREE
config SWAP
def_bool n
@@ -48,9 +51,6 @@ config GENERIC_IRQ_PROBE
config GENERIC_CALIBRATE_DELAY
def_bool y
-config GENERIC_TIME
- def_bool y
-
config GENERIC_TIME_VSYSCALL
def_bool n
@@ -75,9 +75,6 @@ config LOCKDEP_SUPPORT
config HAVE_LATENCYTOP_SUPPORT
def_bool y
-config DTC
- def_bool y
-
source "init/Kconfig"
source "kernel/Kconfig.freezer"
@@ -124,18 +121,6 @@ config CMDLINE_FORCE
Set this to have arguments from the default kernel command string
override those passed by the boot loader.
-config OF
- def_bool y
- select OF_FLATTREE
-
-config PROC_DEVICETREE
- bool "Support for device tree in /proc"
- depends on PROC_FS
- help
- This option adds a device-tree directory under /proc which contains
- an image of the device tree that the kernel copies from Open
- Firmware or other boot firmware. If unsure, say Y here.
-
endmenu
menu "Advanced setup"
@@ -223,6 +208,36 @@ config TASK_SIZE
hex "Size of user task space" if TASK_SIZE_BOOL
default "0x80000000"
+choice
+ prompt "Page size"
+ default MICROBLAZE_4K_PAGES
+ depends on ADVANCED_OPTIONS && !MMU
+ help
+ Select the kernel logical page size. Increasing the page size
+ will reduce software overhead at each page boundary, allow
+ hardware prefetch mechanisms to be more effective, and allow
+ larger dma transfers increasing IO efficiency and reducing
+ overhead. However the utilization of memory will increase.
+ For example, each cached file will using a multiple of the
+ page size to hold its contents and the difference between the
+ end of file and the end of page is wasted.
+
+ If unsure, choose 4K_PAGES.
+
+config MICROBLAZE_4K_PAGES
+ bool "4k page size"
+
+config MICROBLAZE_8K_PAGES
+ bool "8k page size"
+
+config MICROBLAZE_16K_PAGES
+ bool "16k page size"
+
+config MICROBLAZE_32K_PAGES
+ bool "32k page size"
+
+endchoice
+
endmenu
source "mm/Kconfig"
diff --git a/arch/microblaze/Kconfig.debug b/arch/microblaze/Kconfig.debug
index 9dc708a7f70..e6e5e0da28c 100644
--- a/arch/microblaze/Kconfig.debug
+++ b/arch/microblaze/Kconfig.debug
@@ -10,6 +10,7 @@ source "lib/Kconfig.debug"
config EARLY_PRINTK
bool "Early printk function for kernel"
+ depends on SERIAL_UARTLITE_CONSOLE
default n
help
This option turns on/off early printk messages to console.
diff --git a/arch/microblaze/Makefile b/arch/microblaze/Makefile
index 72f6e858374..592c7079de8 100644
--- a/arch/microblaze/Makefile
+++ b/arch/microblaze/Makefile
@@ -25,7 +25,7 @@ ifeq (,$(findstring spartan2,$(CONFIG_XILINX_MICROBLAZE0_FAMILY)))
ifeq ($(CPU_MAJOR),3)
CPUFLAGS-1 += -mno-xl-soft-mul
else
- # USE_HW_MUL can be 0, 1, or 2, defining a heirarchy of HW Mul support.
+ # USE_HW_MUL can be 0, 1, or 2, defining a hierarchy of HW Mul support.
CPUFLAGS-$(subst 1,,$(CONFIG_XILINX_MICROBLAZE0_USE_HW_MUL)) += -mxl-multiply-high
CPUFLAGS-$(CONFIG_XILINX_MICROBLAZE0_USE_HW_MUL) += -mno-xl-soft-mul
endif
diff --git a/arch/microblaze/boot/Makefile b/arch/microblaze/boot/Makefile
index 57f50c2371c..be01d78750d 100644
--- a/arch/microblaze/boot/Makefile
+++ b/arch/microblaze/boot/Makefile
@@ -35,13 +35,14 @@ quiet_cmd_cp = CP $< $@$2
cmd_cp = cat $< >$@$2 || (rm -f $@ && echo false)
quiet_cmd_strip = STRIP $@
- cmd_strip = $(STRIP) -K _start -K _end -K __log_buf -K _fdt_start vmlinux -o $@
+ cmd_strip = $(STRIP) -K microblaze_start -K _end -K __log_buf \
+ -K _fdt_start vmlinux -o $@
quiet_cmd_uimage = UIMAGE $@.ub
- cmd_uimage = $(CONFIG_SHELL) $(MKIMAGE) -A microblaze -O linux -T kernel \
- -C none -n 'Linux-$(KERNELRELEASE)' \
- -a $(CONFIG_KERNEL_BASE_ADDR) -e $(CONFIG_KERNEL_BASE_ADDR) \
- -d $@ $@.ub
+ cmd_uimage = $(CONFIG_SHELL) $(MKIMAGE) -A microblaze -O linux -T kernel \
+ -C none -n 'Linux-$(KERNELRELEASE)' \
+ -a $(CONFIG_KERNEL_BASE_ADDR) -e $(CONFIG_KERNEL_BASE_ADDR) \
+ -d $@ $@.ub
$(obj)/simpleImage.%: vmlinux FORCE
$(call if_changed,cp,.unstrip)
diff --git a/arch/microblaze/include/asm/cacheflush.h b/arch/microblaze/include/asm/cacheflush.h
index a6edd356cd0..7ebd955460d 100644
--- a/arch/microblaze/include/asm/cacheflush.h
+++ b/arch/microblaze/include/asm/cacheflush.h
@@ -17,6 +17,7 @@
/* Somebody depends on this; sigh... */
#include <linux/mm.h>
+#include <linux/io.h>
/* Look at Documentation/cachetlb.txt */
@@ -60,7 +61,6 @@ void microblaze_cache_init(void);
#define invalidate_icache() mbc->iin();
#define invalidate_icache_range(start, end) mbc->iinr(start, end);
-
#define flush_icache_user_range(vma, pg, adr, len) flush_icache();
#define flush_icache_page(vma, pg) do { } while (0)
@@ -72,9 +72,15 @@ void microblaze_cache_init(void);
#define flush_dcache() mbc->dfl();
#define flush_dcache_range(start, end) mbc->dflr(start, end);
-#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 0
-/* D-cache aliasing problem can't happen - cache is between MMU and ram */
-#define flush_dcache_page(page) do { } while (0)
+#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 1
+/* MS: We have to implement it because of rootfs-jffs2 issue on WB */
+#define flush_dcache_page(page) \
+do { \
+ unsigned long addr = (unsigned long) page_address(page); /* virtual */ \
+ addr = (u32)virt_to_phys((void *)addr); \
+ flush_dcache_range((unsigned) (addr), (unsigned) (addr) + PAGE_SIZE); \
+} while (0);
+
#define flush_dcache_mmap_lock(mapping) do { } while (0)
#define flush_dcache_mmap_unlock(mapping) do { } while (0)
@@ -97,8 +103,10 @@ void microblaze_cache_init(void);
#define copy_to_user_page(vma, page, vaddr, dst, src, len) \
do { \
+ u32 addr = virt_to_phys(dst); \
+ invalidate_icache_range((unsigned) (addr), (unsigned) (addr) + (len));\
memcpy((dst), (src), (len)); \
- flush_icache_range((unsigned) (dst), (unsigned) (dst) + (len)); \
+ flush_dcache_range((unsigned) (addr), (unsigned) (addr) + (len));\
} while (0)
#define copy_from_user_page(vma, page, vaddr, dst, src, len) \
diff --git a/arch/microblaze/include/asm/dma-mapping.h b/arch/microblaze/include/asm/dma-mapping.h
index 18b3731c850..50738958070 100644
--- a/arch/microblaze/include/asm/dma-mapping.h
+++ b/arch/microblaze/include/asm/dma-mapping.h
@@ -79,12 +79,6 @@ static inline int dma_supported(struct device *dev, u64 mask)
return ops->dma_supported(dev, mask);
}
-#ifdef CONFIG_PCI
-/* We have our own implementation of pci_set_dma_mask() */
-#define HAVE_ARCH_PCI_SET_DMA_MASK
-
-#endif
-
static inline int dma_set_mask(struct device *dev, u64 dma_mask)
{
struct dma_map_ops *ops = get_dma_ops(dev);
diff --git a/arch/microblaze/include/asm/elf.h b/arch/microblaze/include/asm/elf.h
index 7d4acf2b278..732caf1be74 100644
--- a/arch/microblaze/include/asm/elf.h
+++ b/arch/microblaze/include/asm/elf.h
@@ -77,7 +77,7 @@ typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG];
#define ELF_DATA ELFDATA2MSB
#endif
-#define ELF_EXEC_PAGESIZE 4096
+#define ELF_EXEC_PAGESIZE PAGE_SIZE
#define ELF_CORE_COPY_REGS(_dest, _regs) \
diff --git a/arch/microblaze/include/asm/exceptions.h b/arch/microblaze/include/asm/exceptions.h
index 4c7b5d037c8..6479097b802 100644
--- a/arch/microblaze/include/asm/exceptions.h
+++ b/arch/microblaze/include/asm/exceptions.h
@@ -14,6 +14,11 @@
#define _ASM_MICROBLAZE_EXCEPTIONS_H
#ifdef __KERNEL__
+
+#ifndef CONFIG_MMU
+#define EX_HANDLER_STACK_SIZ (4*19)
+#endif
+
#ifndef __ASSEMBLY__
/* Macros to enable and disable HW exceptions in the MSR */
@@ -64,22 +69,6 @@ asmlinkage void full_exception(struct pt_regs *regs, unsigned int type,
void die(const char *str, struct pt_regs *fp, long err);
void _exception(int signr, struct pt_regs *regs, int code, unsigned long addr);
-#if defined(CONFIG_KGDB)
-void (*debugger)(struct pt_regs *regs);
-int (*debugger_bpt)(struct pt_regs *regs);
-int (*debugger_sstep)(struct pt_regs *regs);
-int (*debugger_iabr_match)(struct pt_regs *regs);
-int (*debugger_dabr_match)(struct pt_regs *regs);
-void (*debugger_fault_handler)(struct pt_regs *regs);
-#else
-#define debugger(regs) do { } while (0)
-#define debugger_bpt(regs) 0
-#define debugger_sstep(regs) 0
-#define debugger_iabr_match(regs) 0
-#define debugger_dabr_match(regs) 0
-#define debugger_fault_handler ((void (*)(struct pt_regs *))0)
-#endif
-
#endif /*__ASSEMBLY__ */
#endif /* __KERNEL__ */
#endif /* _ASM_MICROBLAZE_EXCEPTIONS_H */
diff --git a/arch/microblaze/include/asm/irq.h b/arch/microblaze/include/asm/irq.h
index 31a35c33df6..ec5583d6111 100644
--- a/arch/microblaze/include/asm/irq.h
+++ b/arch/microblaze/include/asm/irq.h
@@ -27,17 +27,6 @@ extern unsigned int nr_irq;
struct pt_regs;
extern void do_IRQ(struct pt_regs *regs);
-/**
- * irq_of_parse_and_map - Parse and Map an interrupt into linux virq space
- * @device: Device node of the device whose interrupt is to be mapped
- * @index: Index of the interrupt to map
- *
- * This function is a wrapper that chains of_irq_map_one() and
- * irq_create_of_mapping() to make things easier to callers
- */
-struct device_node;
-extern unsigned int irq_of_parse_and_map(struct device_node *dev, int index);
-
/** FIXME - not implement
* irq_dispose_mapping - Unmap an interrupt
* @virq: linux virq number of the interrupt to unmap
@@ -62,17 +51,4 @@ struct irq_host;
extern unsigned int irq_create_mapping(struct irq_host *host,
irq_hw_number_t hwirq);
-/**
- * irq_create_of_mapping - Map a hardware interrupt into linux virq space
- * @controller: Device node of the interrupt controller
- * @inspec: Interrupt specifier from the device-tree
- * @intsize: Size of the interrupt specifier from the device-tree
- *
- * This function is identical to irq_create_mapping except that it takes
- * as input informations straight from the device-tree (typically the results
- * of the of_irq_map_*() functions.
- */
-extern unsigned int irq_create_of_mapping(struct device_node *controller,
- u32 *intspec, unsigned int intsize);
-
#endif /* _ASM_MICROBLAZE_IRQ_H */
diff --git a/arch/microblaze/include/asm/kgdb.h b/arch/microblaze/include/asm/kgdb.h
new file mode 100644
index 00000000000..78b17d40b23
--- /dev/null
+++ b/arch/microblaze/include/asm/kgdb.h
@@ -0,0 +1,28 @@
+#ifdef __KERNEL__
+#ifndef __MICROBLAZE_KGDB_H__
+#define __MICROBLAZE_KGDB_H__
+
+#ifndef __ASSEMBLY__
+
+#define CACHE_FLUSH_IS_SAFE 1
+#define BUFMAX 2048
+
+/*
+ * 32 32-bit general purpose registers (r0-r31)
+ * 6 32-bit special registers (pc, msr, ear, esr, fsr, btr)
+ * 12 32-bit PVR
+ * 7 32-bit MMU Regs (redr, rpid, rzpr, rtlbx, rtlbsx, rtlblo, rtlbhi)
+ * ------
+ * 57 registers
+ */
+#define NUMREGBYTES (57 * 4)
+
+#define BREAK_INSTR_SIZE 4
+static inline void arch_kgdb_breakpoint(void)
+{
+ __asm__ __volatile__("brki r16, 0x18;");
+}
+
+#endif /* __ASSEMBLY__ */
+#endif /* __MICROBLAZE_KGDB_H__ */
+#endif /* __KERNEL__ */
diff --git a/arch/microblaze/include/asm/local64.h b/arch/microblaze/include/asm/local64.h
new file mode 100644
index 00000000000..36c93b5cc23
--- /dev/null
+++ b/arch/microblaze/include/asm/local64.h
@@ -0,0 +1 @@
+#include <asm-generic/local64.h>
diff --git a/arch/microblaze/include/asm/of_device.h b/arch/microblaze/include/asm/of_device.h
deleted file mode 100644
index 73cb9804098..00000000000
--- a/arch/microblaze/include/asm/of_device.h
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright (C) 2007-2008 Michal Simek <monstr@monstr.eu>
- *
- * based on PowerPC of_device.h
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file "COPYING" in the main directory of this archive
- * for more details.
- */
-
-#ifndef _ASM_MICROBLAZE_OF_DEVICE_H
-#define _ASM_MICROBLAZE_OF_DEVICE_H
-#ifdef __KERNEL__
-
-#include <linux/device.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.
- */
-struct of_device {
- struct device dev; /* Generic device interface */
- struct pdev_archdata archdata;
-};
-
-extern ssize_t of_device_get_modalias(struct of_device *ofdev,
- char *str, ssize_t len);
-
-extern struct of_device *of_device_alloc(struct device_node *np,
- const char *bus_id,
- struct device *parent);
-
-extern int of_device_uevent(struct device *dev,
- struct kobj_uevent_env *env);
-
-extern void of_device_make_bus_id(struct of_device *dev);
-
-/* This is just here during the transition */
-#include <linux/of_device.h>
-
-#endif /* __KERNEL__ */
-#endif /* _ASM_MICROBLAZE_OF_DEVICE_H */
diff --git a/arch/microblaze/include/asm/of_platform.h b/arch/microblaze/include/asm/of_platform.h
deleted file mode 100644
index 37491276c6c..00000000000
--- a/arch/microblaze/include/asm/of_platform.h
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * 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.
- */
-
-#ifndef _ASM_MICROBLAZE_OF_PLATFORM_H
-#define _ASM_MICROBLAZE_OF_PLATFORM_H
-
-/* This is just here during the transition */
-#include <linux/of_platform.h>
-
-/*
- * The list of OF IDs below is used for matching bus types in the
- * system whose devices are to be exposed as of_platform_devices.
- *
- * This is the default list valid for most platforms. This file provides
- * functions who can take an explicit list if necessary though
- *
- * The search is always performed recursively looking for children of
- * the provided device_node and recursively if such a children matches
- * a bus type in the list
- */
-
-static const struct of_device_id of_default_bus_ids[] = {
- { .type = "soc", },
- { .compatible = "soc", },
- { .type = "plb5", },
- { .type = "plb4", },
- { .type = "opb", },
- { .type = "simple", },
- {},
-};
-
-/* Platform devices and busses creation */
-extern struct of_device *of_platform_device_create(struct device_node *np,
- const char *bus_id,
- struct device *parent);
-/* pseudo "matches" value to not do deep probe */
-#define OF_NO_DEEP_PROBE ((struct of_device_id *)-1)
-
-extern int of_platform_bus_probe(struct device_node *root,
- const struct of_device_id *matches,
- struct device *parent);
-
-extern struct of_device *of_find_device_by_phandle(phandle ph);
-
-extern void of_instantiate_rtc(void);
-
-#endif /* _ASM_MICROBLAZE_OF_PLATFORM_H */
diff --git a/arch/microblaze/include/asm/page.h b/arch/microblaze/include/asm/page.h
index 464ff32bee3..4f268faa012 100644
--- a/arch/microblaze/include/asm/page.h
+++ b/arch/microblaze/include/asm/page.h
@@ -23,8 +23,16 @@
#ifdef __KERNEL__
/* PAGE_SHIFT determines the page size */
-#define PAGE_SHIFT (12)
-#define PAGE_SIZE (_AC(1, UL) << PAGE_SHIFT)
+#if defined(CONFIG_MICROBLAZE_32K_PAGES)
+#define PAGE_SHIFT 15
+#elif defined(CONFIG_MICROBLAZE_16K_PAGES)
+#define PAGE_SHIFT 14
+#elif defined(CONFIG_MICROBLAZE_8K_PAGES)
+#define PAGE_SHIFT 13
+#else
+#define PAGE_SHIFT 12
+#endif
+#define PAGE_SIZE (ASM_CONST(1) << PAGE_SHIFT)
#define PAGE_MASK (~(PAGE_SIZE-1))
#define LOAD_OFFSET ASM_CONST((CONFIG_KERNEL_START-CONFIG_KERNEL_BASE_ADDR))
@@ -39,13 +47,6 @@
#define PAGE_UP(addr) (((addr)+((PAGE_SIZE)-1))&(~((PAGE_SIZE)-1)))
#define PAGE_DOWN(addr) ((addr)&(~((PAGE_SIZE)-1)))
-/* align addr on a size boundary - adjust address up/down if needed */
-#define _ALIGN_UP(addr, size) (((addr)+((size)-1))&(~((size)-1)))
-#define _ALIGN_DOWN(addr, size) ((addr)&(~((size)-1)))
-
-/* align addr on a size boundary - adjust address up if needed */
-#define _ALIGN(addr, size) _ALIGN_UP(addr, size)
-
#ifndef CONFIG_MMU
/*
* PAGE_OFFSET -- the first address of the first page of memory. When not
diff --git a/arch/microblaze/include/asm/pci-bridge.h b/arch/microblaze/include/asm/pci-bridge.h
index 0c77cda9f5d..0c68764ab54 100644
--- a/arch/microblaze/include/asm/pci-bridge.h
+++ b/arch/microblaze/include/asm/pci-bridge.h
@@ -172,13 +172,8 @@ static inline int pci_has_flag(int flag)
extern struct list_head hose_list;
-extern unsigned long pci_address_to_pio(phys_addr_t address);
extern int pcibios_vaddr_is_ioport(void __iomem *address);
#else
-static inline unsigned long pci_address_to_pio(phys_addr_t address)
-{
- return (unsigned long)-1;
-}
static inline int pcibios_vaddr_is_ioport(void __iomem *address)
{
return 0;
diff --git a/arch/microblaze/include/asm/prom.h b/arch/microblaze/include/asm/prom.h
index e7d67a329bd..101fa098f62 100644
--- a/arch/microblaze/include/asm/prom.h
+++ b/arch/microblaze/include/asm/prom.h
@@ -20,9 +20,6 @@
#ifndef __ASSEMBLY__
#include <linux/types.h>
-#include <linux/of_fdt.h>
-#include <linux/proc_fs.h>
-#include <linux/platform_device.h>
#include <asm/irq.h>
#include <asm/atomic.h>
@@ -50,29 +47,10 @@ extern void pci_create_OF_bus_map(void);
* OF address retreival & translation
*/
-/* Translate an OF address block into a CPU physical address
- */
-extern u64 of_translate_address(struct device_node *np, const u32 *addr);
-
-/* Extract an address from a device, returns the region size and
- * the address space flags too. The PCI version uses a BAR number
- * instead of an absolute index
- */
-extern const u32 *of_get_address(struct device_node *dev, int index,
- u64 *size, unsigned int *flags);
-extern const u32 *of_get_pci_address(struct device_node *dev, int bar_no,
- u64 *size, unsigned int *flags);
-
-/* Get an address as a resource. Note that if your address is
- * a PIO address, the conversion will fail if the physical address
- * can't be internally converted to an IO token with
- * pci_address_to_pio(), that is because it's either called to early
- * or it can't be matched to any host bridge IO space
- */
-extern int of_address_to_resource(struct device_node *dev, int index,
- struct resource *r);
-extern int of_pci_address_to_resource(struct device_node *dev, int bar,
- struct resource *r);
+#ifdef CONFIG_PCI
+extern unsigned long pci_address_to_pio(phys_addr_t address);
+#define pci_address_to_pio pci_address_to_pio
+#endif /* CONFIG_PCI */
/* Parse the ibm,dma-window property of an OF node into the busno, phys and
* size parameters.
@@ -88,69 +66,6 @@ struct device_node *of_get_cpu_node(int cpu, unsigned int *thread);
/* Get the MAC address */
extern const void *of_get_mac_address(struct device_node *np);
-/*
- * OF interrupt mapping
- */
-
-/* This structure is returned when an interrupt is mapped. The controller
- * field needs to be put() after use
- */
-
-#define OF_MAX_IRQ_SPEC 4 /* We handle specifiers of at most 4 cells */
-
-struct of_irq {
- struct device_node *controller; /* Interrupt controller node */
- u32 size; /* Specifier size */
- u32 specifier[OF_MAX_IRQ_SPEC]; /* Specifier copy */
-};
-
-/**
- * of_irq_map_init - Initialize the irq remapper
- * @flags: flags defining workarounds to enable
- *
- * Some machines have bugs in the device-tree which require certain workarounds
- * to be applied. Call this before any interrupt mapping attempts to enable
- * those workarounds.
- */
-#define OF_IMAP_OLDWORLD_MAC 0x00000001
-#define OF_IMAP_NO_PHANDLE 0x00000002
-
-extern void of_irq_map_init(unsigned int flags);
-
-/**
- * of_irq_map_raw - Low level interrupt tree parsing
- * @parent: the device interrupt parent
- * @intspec: interrupt specifier ("interrupts" property of the device)
- * @ointsize: size of the passed in interrupt specifier
- * @addr: address specifier (start of "reg" property of the device)
- * @out_irq: structure of_irq filled by this function
- *
- * Returns 0 on success and a negative number on error
- *
- * This function is a low-level interrupt tree walking function. It
- * can be used to do a partial walk with synthetized reg and interrupts
- * properties, for example when resolving PCI interrupts when no device
- * node exist for the parent.
- *
- */
-
-extern int of_irq_map_raw(struct device_node *parent, const u32 *intspec,
- u32 ointsize, const u32 *addr,
- struct of_irq *out_irq);
-
-/**
- * of_irq_map_one - Resolve an interrupt for a device
- * @device: the device whose interrupt is to be resolved
- * @index: index of the interrupt to resolve
- * @out_irq: structure of_irq filled by this function
- *
- * This function resolves an interrupt, walking the tree, for a given
- * device-tree node. It's the high level pendant to of_irq_map_raw().
- * It also implements the workarounds for OldWolrd Macs.
- */
-extern int of_irq_map_one(struct device_node *device, int index,
- struct of_irq *out_irq);
-
/**
* of_irq_map_pci - Resolve the interrupt for a PCI device
* @pdev: the device whose interrupt is to be resolved
@@ -163,20 +78,18 @@ extern int of_irq_map_one(struct device_node *device, int index,
* resolving using the OF tree walking.
*/
struct pci_dev;
+struct of_irq;
extern int of_irq_map_pci(struct pci_dev *pdev, struct of_irq *out_irq);
-extern int of_irq_to_resource(struct device_node *dev, int index,
- struct resource *r);
-
-/**
- * of_iomap - Maps the memory mapped IO for a given device_node
- * @device: the device whose io range will be mapped
- * @index: index of the io range
- *
- * Returns a pointer to the mapped memory
- */
-extern void __iomem *of_iomap(struct device_node *device, int index);
-
#endif /* __ASSEMBLY__ */
#endif /* __KERNEL__ */
+
+/* These includes are put at the bottom because they may contain things
+ * that are overridden by this file. Ideally they shouldn't be included
+ * by this file, but there are a bunch of .c files that currently depend
+ * on it. Eventually they will be cleaned up. */
+#include <linux/of_fdt.h>
+#include <linux/of_irq.h>
+#include <linux/platform_device.h>
+
#endif /* _ASM_MICROBLAZE_PROM_H */
diff --git a/arch/microblaze/include/asm/pvr.h b/arch/microblaze/include/asm/pvr.h
index e38abc7714b..9578666e98b 100644
--- a/arch/microblaze/include/asm/pvr.h
+++ b/arch/microblaze/include/asm/pvr.h
@@ -16,7 +16,7 @@
#define PVR_MSR_BIT 0x400
struct pvr_s {
- unsigned pvr[16];
+ unsigned pvr[12];
};
/* The following taken from Xilinx's standalone BSP pvr.h */
diff --git a/arch/microblaze/include/asm/setup.h b/arch/microblaze/include/asm/setup.h
index 7f31394985e..782b5c89248 100644
--- a/arch/microblaze/include/asm/setup.h
+++ b/arch/microblaze/include/asm/setup.h
@@ -28,8 +28,6 @@ void disable_early_printk(void);
void heartbeat(void);
void setup_heartbeat(void);
-unsigned long long sched_clock(void);
-
# ifdef CONFIG_MMU
extern void mmu_reset(void);
extern void early_console_reg_tlb_alloc(unsigned int addr);
diff --git a/arch/microblaze/include/asm/system.h b/arch/microblaze/include/asm/system.h
index 48c4f0335e3..e6a2284571d 100644
--- a/arch/microblaze/include/asm/system.h
+++ b/arch/microblaze/include/asm/system.h
@@ -45,7 +45,6 @@ extern struct task_struct *_switch_to(struct thread_info *prev,
#define smp_rmb() rmb()
#define smp_wmb() wmb()
-void show_trace(struct task_struct *task, unsigned long *stack);
void __bad_xchg(volatile void *ptr, int size);
static inline unsigned long __xchg(unsigned long x, volatile void *ptr,
@@ -101,10 +100,7 @@ extern struct dentry *of_debugfs_root;
* MicroBlaze doesn't handle unaligned accesses in hardware.
*
* Based on this we force the IP header alignment in network drivers.
- * We also modify NET_SKB_PAD to be a cacheline in size, thus maintaining
- * cacheline alignment of buffers.
*/
#define NET_IP_ALIGN 2
-#define NET_SKB_PAD L1_CACHE_BYTES
#endif /* _ASM_MICROBLAZE_SYSTEM_H */
diff --git a/arch/microblaze/include/asm/topology.h b/arch/microblaze/include/asm/topology.h
index 96bcea5a992..5428f333a02 100644
--- a/arch/microblaze/include/asm/topology.h
+++ b/arch/microblaze/include/asm/topology.h
@@ -1,11 +1 @@
#include <asm-generic/topology.h>
-
-#ifndef _ASM_MICROBLAZE_TOPOLOGY_H
-#define _ASM_MICROBLAZE_TOPOLOGY_H
-
-struct device_node;
-static inline int of_node_to_nid(struct device_node *device)
-{
- return 0;
-}
-#endif /* _ASM_MICROBLAZE_TOPOLOGY_H */
diff --git a/arch/microblaze/include/asm/uaccess.h b/arch/microblaze/include/asm/uaccess.h
index 26460d15b33..d840f4a2d3c 100644
--- a/arch/microblaze/include/asm/uaccess.h
+++ b/arch/microblaze/include/asm/uaccess.h
@@ -359,7 +359,7 @@ extern long __user_bad(void);
__copy_tofrom_user((__force void __user *)(to), \
(void __user *)(from), (n))
#define __copy_from_user_inatomic(to, from, n) \
- copy_from_user((to), (from), (n))
+ __copy_from_user((to), (from), (n))
static inline long copy_from_user(void *to,
const void __user *from, unsigned long n)
@@ -373,7 +373,7 @@ static inline long copy_from_user(void *to,
#define __copy_to_user(to, from, n) \
__copy_tofrom_user((void __user *)(to), \
(__force const void __user *)(from), (n))
-#define __copy_to_user_inatomic(to, from, n) copy_to_user((to), (from), (n))
+#define __copy_to_user_inatomic(to, from, n) __copy_to_user((to), (from), (n))
static inline long copy_to_user(void __user *to,
const void *from, unsigned long n)
diff --git a/arch/microblaze/include/asm/unwind.h b/arch/microblaze/include/asm/unwind.h
new file mode 100644
index 00000000000..d248b7de4b1
--- /dev/null
+++ b/arch/microblaze/include/asm/unwind.h
@@ -0,0 +1,29 @@
+/*
+ * Backtrace support for Microblaze
+ *
+ * Copyright (C) 2010 Digital Design 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.
+ */
+
+#ifndef __MICROBLAZE_UNWIND_H
+#define __MICROBLAZE_UNWIND_H
+
+struct stack_trace;
+
+struct trap_handler_info {
+ unsigned long start_addr;
+ unsigned long end_addr;
+ const char *trap_name;
+};
+extern struct trap_handler_info microblaze_trap_handlers;
+
+extern const char _hw_exception_handler;
+extern const char ex_handler_unhandled;
+
+void microblaze_unwind(struct task_struct *task, struct stack_trace *trace);
+
+#endif /* __MICROBLAZE_UNWIND_H */
+
diff --git a/arch/microblaze/kernel/Makefile b/arch/microblaze/kernel/Makefile
index e51bc152082..f0cb5c26c81 100644
--- a/arch/microblaze/kernel/Makefile
+++ b/arch/microblaze/kernel/Makefile
@@ -15,9 +15,9 @@ endif
extra-y := head.o vmlinux.lds
obj-y += dma.o exceptions.o \
- hw_exception_handler.o init_task.o intc.o irq.o of_device.o \
- of_platform.o process.o prom.o prom_parse.o ptrace.o \
- setup.o signal.o sys_microblaze.o timer.o traps.o reset.o
+ hw_exception_handler.o init_task.o intc.o irq.o \
+ process.o prom.o prom_parse.o ptrace.o \
+ reset.o setup.o signal.o sys_microblaze.o timer.o traps.o unwind.o
obj-y += cpu/
@@ -28,5 +28,6 @@ obj-$(CONFIG_MODULES) += microblaze_ksyms.o module.o
obj-$(CONFIG_MMU) += misc.o
obj-$(CONFIG_STACKTRACE) += stacktrace.o
obj-$(CONFIG_FUNCTION_TRACER) += ftrace.o mcount.o
+obj-$(CONFIG_KGDB) += kgdb.o
obj-y += entry$(MMU).o
diff --git a/arch/microblaze/kernel/cpu/mb.c b/arch/microblaze/kernel/cpu/mb.c
index 4216eb1eaa3..7086e356428 100644
--- a/arch/microblaze/kernel/cpu/mb.c
+++ b/arch/microblaze/kernel/cpu/mb.c
@@ -126,6 +126,7 @@ static int show_cpuinfo(struct seq_file *m, void *v)
cpuinfo.pvr_user1,
cpuinfo.pvr_user2);
+ count += seq_printf(m, "Page size:\t%lu\n", PAGE_SIZE);
return 0;
}
diff --git a/arch/microblaze/kernel/entry-nommu.S b/arch/microblaze/kernel/entry-nommu.S
index 8cc18cd2cce..ca84368570b 100644
--- a/arch/microblaze/kernel/entry-nommu.S
+++ b/arch/microblaze/kernel/entry-nommu.S
@@ -588,3 +588,31 @@ sys_rt_sigsuspend_wrapper:
#include "syscall_table.S"
syscall_table_size=(.-sys_call_table)
+
+type_SYSCALL:
+ .ascii "SYSCALL\0"
+type_IRQ:
+ .ascii "IRQ\0"
+type_IRQ_PREEMPT:
+ .ascii "IRQ (PREEMPTED)\0"
+type_SYSCALL_PREEMPT:
+ .ascii " SYSCALL (PREEMPTED)\0"
+
+ /*
+ * Trap decoding for stack unwinder
+ * Tuples are (start addr, end addr, string)
+ * If return address lies on [start addr, end addr],
+ * unwinder displays 'string'
+ */
+
+ .align 4
+.global microblaze_trap_handlers
+microblaze_trap_handlers:
+ /* Exact matches come first */
+ .word ret_to_user ; .word ret_to_user ; .word type_SYSCALL
+ .word ret_from_intr; .word ret_from_intr ; .word type_IRQ
+ /* Fuzzy matches go here */
+ .word ret_from_intr; .word no_intr_resched; .word type_IRQ_PREEMPT
+ .word work_pending ; .word no_work_pending; .word type_SYSCALL_PREEMPT
+ /* End of table */
+ .word 0 ; .word 0 ; .word 0
diff --git a/arch/microblaze/kernel/entry.S b/arch/microblaze/kernel/entry.S
index c0ede25c5b9..304882e5645 100644
--- a/arch/microblaze/kernel/entry.S
+++ b/arch/microblaze/kernel/entry.S
@@ -48,128 +48,107 @@
*/
#if CONFIG_XILINX_MICROBLAZE0_USE_MSR_INSTR
.macro clear_bip
- msrclr r11, MSR_BIP
- nop
+ msrclr r0, MSR_BIP
.endm
.macro set_bip
- msrset r11, MSR_BIP
- nop
+ msrset r0, MSR_BIP
.endm
.macro clear_eip
- msrclr r11, MSR_EIP
- nop
+ msrclr r0, MSR_EIP
.endm
.macro set_ee
- msrset r11, MSR_EE
- nop
+ msrset r0, MSR_EE
.endm
.macro disable_irq
- msrclr r11, MSR_IE
- nop
+ msrclr r0, MSR_IE
.endm
.macro enable_irq
- msrset r11, MSR_IE
- nop
+ msrset r0, MSR_IE
.endm
.macro set_ums
- msrset r11, MSR_UMS
- nop
- msrclr r11, MSR_VMS
- nop
+ msrset r0, MSR_UMS
+ msrclr r0, MSR_VMS
.endm
.macro set_vms
- msrclr r11, MSR_UMS
- nop
- msrset r11, MSR_VMS
- nop
+ msrclr r0, MSR_UMS
+ msrset r0, MSR_VMS
+ .endm
+
+ .macro clear_ums
+ msrclr r0, MSR_UMS
.endm
.macro clear_vms_ums
- msrclr r11, MSR_VMS
- nop
- msrclr r11, MSR_UMS
- nop
+ msrclr r0, MSR_VMS | MSR_UMS
.endm
#else
.macro clear_bip
mfs r11, rmsr
- nop
andi r11, r11, ~MSR_BIP
mts rmsr, r11
- nop
.endm
.macro set_bip
mfs r11, rmsr
- nop
ori r11, r11, MSR_BIP
mts rmsr, r11
- nop
.endm
.macro clear_eip
mfs r11, rmsr
- nop
andi r11, r11, ~MSR_EIP
mts rmsr, r11
- nop
.endm
.macro set_ee
mfs r11, rmsr
- nop
ori r11, r11, MSR_EE
mts rmsr, r11
- nop
.endm
.macro disable_irq
mfs r11, rmsr
- nop
andi r11, r11, ~MSR_IE
mts rmsr, r11
- nop
.endm
.macro enable_irq
mfs r11, rmsr
- nop
ori r11, r11, MSR_IE
mts rmsr, r11
- nop
.endm
.macro set_ums
mfs r11, rmsr
- nop
ori r11, r11, MSR_VMS
andni r11, r11, MSR_UMS
mts rmsr, r11
- nop
.endm
.macro set_vms
mfs r11, rmsr
- nop
ori r11, r11, MSR_VMS
andni r11, r11, MSR_UMS
mts rmsr, r11
- nop
+ .endm
+
+ .macro clear_ums
+ mfs r11, rmsr
+ andni r11, r11, MSR_UMS
+ mts rmsr,r11
.endm
.macro clear_vms_ums
mfs r11, rmsr
- nop
andni r11, r11, (MSR_VMS|MSR_UMS)
mts rmsr,r11
- nop
.endm
#endif
@@ -180,18 +159,22 @@
/* turn on virtual protected mode save */
#define VM_ON \
- set_ums; \
+ set_ums; \
rted r0, 2f; \
-2: nop;
+ nop; \
+2:
/* turn off virtual protected mode save and user mode save*/
#define VM_OFF \
- clear_vms_ums; \
+ clear_vms_ums; \
rted r0, TOPHYS(1f); \
-1: nop;
+ nop; \
+1:
#define SAVE_REGS \
swi r2, r1, PTO+PT_R2; /* Save SDA */ \
+ swi r3, r1, PTO+PT_R3; \
+ swi r4, r1, PTO+PT_R4; \
swi r5, r1, PTO+PT_R5; \
swi r6, r1, PTO+PT_R6; \
swi r7, r1, PTO+PT_R7; \
@@ -218,14 +201,14 @@
swi r30, r1, PTO+PT_R30; \
swi r31, r1, PTO+PT_R31; /* Save current task reg */ \
mfs r11, rmsr; /* save MSR */ \
- nop; \
swi r11, r1, PTO+PT_MSR;
#define RESTORE_REGS \
lwi r11, r1, PTO+PT_MSR; \
mts rmsr , r11; \
- nop; \
lwi r2, r1, PTO+PT_R2; /* restore SDA */ \
+ lwi r3, r1, PTO+PT_R3; \
+ lwi r4, r1, PTO+PT_R4; \
lwi r5, r1, PTO+PT_R5; \
lwi r6, r1, PTO+PT_R6; \
lwi r7, r1, PTO+PT_R7; \
@@ -252,6 +235,39 @@
lwi r30, r1, PTO+PT_R30; \
lwi r31, r1, PTO+PT_R31; /* Restore cur task reg */
+#define SAVE_STATE \
+ swi r1, r0, TOPHYS(PER_CPU(ENTRY_SP)); /* save stack */ \
+ /* See if already in kernel mode.*/ \
+ mfs r1, rmsr; \
+ andi r1, r1, MSR_UMS; \
+ bnei r1, 1f; \
+ /* Kernel-mode state save. */ \
+ /* Reload kernel stack-ptr. */ \
+ lwi r1, r0, TOPHYS(PER_CPU(ENTRY_SP)); \
+ /* FIXME: I can add these two lines to one */ \
+ /* tophys(r1,r1); */ \
+ /* addik r1, r1, -STATE_SAVE_SIZE; */ \
+ addik r1, r1, CONFIG_KERNEL_BASE_ADDR - CONFIG_KERNEL_START - STATE_SAVE_SIZE; \
+ SAVE_REGS \
+ brid 2f; \
+ swi r1, r1, PTO+PT_MODE; \
+1: /* User-mode state save. */ \
+ lwi r1, r0, TOPHYS(PER_CPU(CURRENT_SAVE)); /* get saved current */\
+ tophys(r1,r1); \
+ lwi r1, r1, TS_THREAD_INFO; /* get the thread info */ \
+ /* MS these three instructions can be added to one */ \
+ /* addik r1, r1, THREAD_SIZE; */ \
+ /* tophys(r1,r1); */ \
+ /* addik r1, r1, -STATE_SAVE_SIZE; */ \
+ addik r1, r1, THREAD_SIZE + CONFIG_KERNEL_BASE_ADDR - CONFIG_KERNEL_START - STATE_SAVE_SIZE; \
+ SAVE_REGS \
+ lwi r11, r0, TOPHYS(PER_CPU(ENTRY_SP)); \
+ swi r11, r1, PTO+PT_R1; /* Store user SP. */ \
+ swi r0, r1, PTO + PT_MODE; /* Was in user-mode. */ \
+ /* MS: I am clearing UMS even in case when I come from kernel space */ \
+ clear_ums; \
+2: lwi CURRENT_TASK, r0, TOPHYS(PER_CPU(CURRENT_SAVE));
+
.text
/*
@@ -267,45 +283,23 @@
* are masked. This is nice, means we don't have to CLI before state save
*/
C_ENTRY(_user_exception):
- swi r1, r0, TOPHYS(PER_CPU(ENTRY_SP)) /* save stack */
addi r14, r14, 4 /* return address is 4 byte after call */
- swi r11, r0, TOPHYS(r0_ram + PTO + PT_R11); /* Save r11 */
-
- lwi r11, r0, TOPHYS(PER_CPU(KM));/* See if already in kernel mode.*/
- beqi r11, 1f; /* Jump ahead if coming from user */
-/* Kernel-mode state save. */
- lwi r11, r0, TOPHYS(PER_CPU(ENTRY_SP)); /* Reload kernel stack-ptr*/
- tophys(r1,r11);
- swi r11, r1, (PT_R1-PT_SIZE); /* Save original SP. */
- lwi r11, r0, TOPHYS(r0_ram + PTO + PT_R11); /* restore r11 */
-
- addik r1, r1, -STATE_SAVE_SIZE; /* Make room on the stack. */
- SAVE_REGS
-
- addi r11, r0, 1; /* Was in kernel-mode. */
- swi r11, r1, PTO+PT_MODE; /* pt_regs -> kernel mode */
- brid 2f;
- nop; /* Fill delay slot */
+ swi r1, r0, TOPHYS(PER_CPU(ENTRY_SP)) /* save stack */
-/* User-mode state save. */
-1:
- lwi r11, r0, TOPHYS(r0_ram + PTO + PT_R11); /* restore r11 */
lwi r1, r0, TOPHYS(PER_CPU(CURRENT_SAVE)); /* get saved current */
tophys(r1,r1);
lwi r1, r1, TS_THREAD_INFO; /* get stack from task_struct */
-/* calculate kernel stack pointer from task struct 8k */
- addik r1, r1, THREAD_SIZE;
- tophys(r1,r1);
-
- addik r1, r1, -STATE_SAVE_SIZE; /* Make room on the stack. */
+ /* MS these three instructions can be added to one */
+ /* addik r1, r1, THREAD_SIZE; */
+ /* tophys(r1,r1); */
+ /* addik r1, r1, -STATE_SAVE_SIZE; */
+ addik r1, r1, THREAD_SIZE + CONFIG_KERNEL_BASE_ADDR - CONFIG_KERNEL_START - STATE_SAVE_SIZE;
SAVE_REGS
- swi r0, r1, PTO+PT_MODE; /* Was in user-mode. */
lwi r11, r0, TOPHYS(PER_CPU(ENTRY_SP));
swi r11, r1, PTO+PT_R1; /* Store user SP. */
- addi r11, r0, 1;
- swi r11, r0, TOPHYS(PER_CPU(KM)); /* Now we're in kernel-mode. */
-2: lwi CURRENT_TASK, r0, TOPHYS(PER_CPU(CURRENT_SAVE));
+ clear_ums;
+ lwi CURRENT_TASK, r0, TOPHYS(PER_CPU(CURRENT_SAVE));
/* Save away the syscall number. */
swi r12, r1, PTO+PT_R0;
tovirt(r1,r1)
@@ -316,10 +310,8 @@ C_ENTRY(_user_exception):
* register should point to the location where
* the called function should return. [note that MAKE_SYS_CALL uses label 1] */
- # Step into virtual mode.
- set_vms;
- addik r11, r0, 3f
- rtid r11, 0
+ /* Step into virtual mode */
+ rtbd r0, 3f
nop
3:
lwi r11, CURRENT_TASK, TS_THREAD_INFO /* get thread info */
@@ -363,24 +355,17 @@ C_ENTRY(_user_exception):
# Find and jump into the syscall handler.
lwi r12, r12, sys_call_table
/* where the trap should return need -8 to adjust for rtsd r15, 8 */
- la r15, r0, ret_from_trap-8
+ addi r15, r0, ret_from_trap-8
bra r12
/* The syscall number is invalid, return an error. */
5:
+ rtsd r15, 8; /* looks like a normal subroutine return */
addi r3, r0, -ENOSYS;
- rtsd r15,8; /* looks like a normal subroutine return */
- or r0, r0, r0
-
/* Entry point used to return from a syscall/trap */
/* We re-enable BIP bit before state restore */
C_ENTRY(ret_from_trap):
- set_bip; /* Ints masked for state restore*/
- lwi r11, r1, PTO+PT_MODE;
-/* See if returning to kernel mode, if so, skip resched &c. */
- bnei r11, 2f;
-
swi r3, r1, PTO + PT_R3
swi r4, r1, PTO + PT_R4
@@ -413,32 +398,19 @@ C_ENTRY(ret_from_trap):
andi r11, r11, _TIF_SIGPENDING;
beqi r11, 1f; /* Signals to handle, handle them */
- la r5, r1, PTO; /* Arg 1: struct pt_regs *regs */
+ addik r5, r1, PTO; /* Arg 1: struct pt_regs *regs */
addi r7, r0, 1; /* Arg 3: int in_syscall */
bralid r15, do_signal; /* Handle any signals */
add r6, r0, r0; /* Arg 2: sigset_t *oldset */
/* Finally, return to user state. */
-1:
- lwi r3, r1, PTO + PT_R3; /* restore syscall result */
- lwi r4, r1, PTO + PT_R4;
-
- swi r0, r0, PER_CPU(KM); /* Now officially in user state. */
+1: set_bip; /* Ints masked for state restore */
swi CURRENT_TASK, r0, PER_CPU(CURRENT_SAVE); /* save current */
VM_OFF;
tophys(r1,r1);
RESTORE_REGS;
addik r1, r1, STATE_SAVE_SIZE /* Clean up stack space. */
lwi r1, r1, PT_R1 - PT_SIZE;/* Restore user stack pointer. */
- bri 6f;
-
-/* Return to kernel state. */
-2: VM_OFF;
- tophys(r1,r1);
- RESTORE_REGS;
- addik r1, r1, STATE_SAVE_SIZE /* Clean up stack space. */
- tovirt(r1,r1);
-6:
TRAP_return: /* Make global symbol for debugging */
rtbd r14, 0; /* Instructions to return from an IRQ */
nop;
@@ -450,12 +422,11 @@ TRAP_return: /* Make global symbol for debugging */
C_ENTRY(sys_fork_wrapper):
addi r5, r0, SIGCHLD /* Arg 0: flags */
lwi r6, r1, PTO+PT_R1 /* Arg 1: child SP (use parent's) */
- la r7, r1, PTO /* Arg 2: parent context */
+ addik r7, r1, PTO /* Arg 2: parent context */
add r8. r0, r0 /* Arg 3: (unused) */
add r9, r0, r0; /* Arg 4: (unused) */
- add r10, r0, r0; /* Arg 5: (unused) */
brid do_fork /* Do real work (tail-call) */
- nop;
+ add r10, r0, r0; /* Arg 5: (unused) */
/* This the initial entry point for a new child thread, with an appropriate
stack in place that makes it look the the child is in the middle of an
@@ -466,35 +437,31 @@ C_ENTRY(ret_from_fork):
bralid r15, schedule_tail; /* ...which is schedule_tail's arg */
add r3, r5, r0; /* switch_thread returns the prev task */
/* ( in the delay slot ) */
- add r3, r0, r0; /* Child's fork call should return 0. */
brid ret_from_trap; /* Do normal trap return */
- nop;
+ add r3, r0, r0; /* Child's fork call should return 0. */
C_ENTRY(sys_vfork):
brid microblaze_vfork /* Do real work (tail-call) */
- la r5, r1, PTO
+ addik r5, r1, PTO
C_ENTRY(sys_clone):
bnei r6, 1f; /* See if child SP arg (arg 1) is 0. */
- lwi r6, r1, PTO+PT_R1; /* If so, use paret's stack ptr */
-1: la r7, r1, PTO; /* Arg 2: parent context */
+ lwi r6, r1, PTO + PT_R1; /* If so, use paret's stack ptr */
+1: addik r7, r1, PTO; /* Arg 2: parent context */
add r8, r0, r0; /* Arg 3: (unused) */
add r9, r0, r0; /* Arg 4: (unused) */
- add r10, r0, r0; /* Arg 5: (unused) */
brid do_fork /* Do real work (tail-call) */
- nop;
+ add r10, r0, r0; /* Arg 5: (unused) */
C_ENTRY(sys_execve):
- la r8, r1, PTO; /* add user context as 4th arg */
brid microblaze_execve; /* Do real work (tail-call).*/
- nop;
+ addik r8, r1, PTO; /* add user context as 4th arg */
C_ENTRY(sys_rt_sigreturn_wrapper):
swi r3, r1, PTO+PT_R3; /* restore saved r3, r4 registers */
swi r4, r1, PTO+PT_R4;
- la r5, r1, PTO; /* add user context as 1st arg */
brlid r15, sys_rt_sigreturn /* Do real work */
- nop;
+ addik r5, r1, PTO; /* add user context as 1st arg */
lwi r3, r1, PTO+PT_R3; /* restore saved r3, r4 registers */
lwi r4, r1, PTO+PT_R4;
bri ret_from_trap /* fall through will not work here due to align */
@@ -503,83 +470,23 @@ C_ENTRY(sys_rt_sigreturn_wrapper):
/*
* HW EXCEPTION rutine start
*/
-
-#define SAVE_STATE \
- swi r11, r0, TOPHYS(r0_ram + PTO + PT_R11); /* Save r11 */ \
- set_bip; /*equalize initial state for all possible entries*/\
- clear_eip; \
- enable_irq; \
- set_ee; \
- /* See if already in kernel mode.*/ \
- lwi r11, r0, TOPHYS(PER_CPU(KM)); \
- beqi r11, 1f; /* Jump ahead if coming from user */\
- /* Kernel-mode state save. */ \
- /* Reload kernel stack-ptr. */ \
- lwi r11, r0, TOPHYS(PER_CPU(ENTRY_SP)); \
- tophys(r1,r11); \
- swi r11, r1, (PT_R1-PT_SIZE); /* Save original SP. */ \
- lwi r11, r0, TOPHYS(r0_ram + PTO + PT_R11); /* restore r11 */\
- addik r1, r1, -STATE_SAVE_SIZE; /* Make room on the stack. */\
- /* store return registers separately because \
- * this macros is use for others exceptions */ \
- swi r3, r1, PTO + PT_R3; \
- swi r4, r1, PTO + PT_R4; \
- SAVE_REGS \
- /* PC, before IRQ/trap - this is one instruction above */ \
- swi r17, r1, PTO+PT_PC; \
- \
- addi r11, r0, 1; /* Was in kernel-mode. */ \
- swi r11, r1, PTO+PT_MODE; \
- brid 2f; \
- nop; /* Fill delay slot */ \
-1: /* User-mode state save. */ \
- lwi r11, r0, TOPHYS(r0_ram + PTO + PT_R11); /* restore r11 */\
- lwi r1, r0, TOPHYS(PER_CPU(CURRENT_SAVE)); /* get saved current */\
- tophys(r1,r1); \
- lwi r1, r1, TS_THREAD_INFO; /* get the thread info */ \
- addik r1, r1, THREAD_SIZE; /* calculate kernel stack pointer */\
- tophys(r1,r1); \
- \
- addik r1, r1, -STATE_SAVE_SIZE; /* Make room on the stack. */\
- /* store return registers separately because this macros \
- * is use for others exceptions */ \
- swi r3, r1, PTO + PT_R3; \
- swi r4, r1, PTO + PT_R4; \
- SAVE_REGS \
- /* PC, before IRQ/trap - this is one instruction above FIXME*/ \
- swi r17, r1, PTO+PT_PC; \
- \
- swi r0, r1, PTO+PT_MODE; /* Was in user-mode. */ \
- lwi r11, r0, TOPHYS(PER_CPU(ENTRY_SP)); \
- swi r11, r1, PTO+PT_R1; /* Store user SP. */ \
- addi r11, r0, 1; \
- swi r11, r0, TOPHYS(PER_CPU(KM)); /* Now we're in kernel-mode.*/\
-2: lwi CURRENT_TASK, r0, TOPHYS(PER_CPU(CURRENT_SAVE)); \
- /* Save away the syscall number. */ \
- swi r0, r1, PTO+PT_R0; \
- tovirt(r1,r1)
-
C_ENTRY(full_exception_trap):
- swi r1, r0, TOPHYS(PER_CPU(ENTRY_SP)) /* save stack */
/* adjust exception address for privileged instruction
* for finding where is it */
addik r17, r17, -4
SAVE_STATE /* Save registers */
+ /* PC, before IRQ/trap - this is one instruction above */
+ swi r17, r1, PTO+PT_PC;
+ tovirt(r1,r1)
/* FIXME this can be store directly in PT_ESR reg.
* I tested it but there is a fault */
/* where the trap should return need -8 to adjust for rtsd r15, 8 */
- la r15, r0, ret_from_exc - 8
- la r5, r1, PTO /* parameter struct pt_regs * regs */
+ addik r15, r0, ret_from_exc - 8
mfs r6, resr
- nop
mfs r7, rfsr; /* save FSR */
- nop
mts rfsr, r0; /* Clear sticky fsr */
- nop
- la r12, r0, full_exception
- set_vms;
- rtbd r12, 0;
- nop;
+ rted r0, full_exception
+ addik r5, r1, PTO /* parameter struct pt_regs * regs */
/*
* Unaligned data trap.
@@ -592,19 +499,27 @@ C_ENTRY(full_exception_trap):
* The assembler routine is in "arch/microblaze/kernel/hw_exception_handler.S"
*/
C_ENTRY(unaligned_data_trap):
- swi r1, r0, TOPHYS(PER_CPU(ENTRY_SP)) /* save stack */
+ /* MS: I have to save r11 value and then restore it because
+ * set_bit, clear_eip, set_ee use r11 as temp register if MSR
+ * instructions are not used. We don't need to do if MSR instructions
+ * are used and they use r0 instead of r11.
+ * I am using ENTRY_SP which should be primary used only for stack
+ * pointer saving. */
+ swi r11, r0, TOPHYS(PER_CPU(ENTRY_SP));
+ set_bip; /* equalize initial state for all possible entries */
+ clear_eip;
+ set_ee;
+ lwi r11, r0, TOPHYS(PER_CPU(ENTRY_SP));
SAVE_STATE /* Save registers.*/
+ /* PC, before IRQ/trap - this is one instruction above */
+ swi r17, r1, PTO+PT_PC;
+ tovirt(r1,r1)
/* where the trap should return need -8 to adjust for rtsd r15, 8 */
- la r15, r0, ret_from_exc-8
+ addik r15, r0, ret_from_exc-8
mfs r3, resr /* ESR */
- nop
mfs r4, rear /* EAR */
- nop
- la r7, r1, PTO /* parameter struct pt_regs * regs */
- la r12, r0, _unaligned_data_exception
- set_vms;
- rtbd r12, 0; /* interrupts enabled */
- nop;
+ rtbd r0, _unaligned_data_exception
+ addik r7, r1, PTO /* parameter struct pt_regs * regs */
/*
* Page fault traps.
@@ -625,38 +540,32 @@ C_ENTRY(unaligned_data_trap):
*/
/* data and intruction trap - which is choose is resolved int fault.c */
C_ENTRY(page_fault_data_trap):
- swi r1, r0, TOPHYS(PER_CPU(ENTRY_SP)) /* save stack */
SAVE_STATE /* Save registers.*/
+ /* PC, before IRQ/trap - this is one instruction above */
+ swi r17, r1, PTO+PT_PC;
+ tovirt(r1,r1)
/* where the trap should return need -8 to adjust for rtsd r15, 8 */
- la r15, r0, ret_from_exc-8
- la r5, r1, PTO /* parameter struct pt_regs * regs */
+ addik r15, r0, ret_from_exc-8
mfs r6, rear /* parameter unsigned long address */
- nop
mfs r7, resr /* parameter unsigned long error_code */
- nop
- la r12, r0, do_page_fault
- set_vms;
- rtbd r12, 0; /* interrupts enabled */
- nop;
+ rted r0, do_page_fault
+ addik r5, r1, PTO /* parameter struct pt_regs * regs */
C_ENTRY(page_fault_instr_trap):
- swi r1, r0, TOPHYS(PER_CPU(ENTRY_SP)) /* save stack */
SAVE_STATE /* Save registers.*/
+ /* PC, before IRQ/trap - this is one instruction above */
+ swi r17, r1, PTO+PT_PC;
+ tovirt(r1,r1)
/* where the trap should return need -8 to adjust for rtsd r15, 8 */
- la r15, r0, ret_from_exc-8
- la r5, r1, PTO /* parameter struct pt_regs * regs */
+ addik r15, r0, ret_from_exc-8
mfs r6, rear /* parameter unsigned long address */
- nop
ori r7, r0, 0 /* parameter unsigned long error_code */
- la r12, r0, do_page_fault
- set_vms;
- rtbd r12, 0; /* interrupts enabled */
- nop;
+ rted r0, do_page_fault
+ addik r5, r1, PTO /* parameter struct pt_regs * regs */
/* Entry point used to return from an exception. */
C_ENTRY(ret_from_exc):
- set_bip; /* Ints masked for state restore*/
- lwi r11, r1, PTO+PT_MODE;
+ lwi r11, r1, PTO + PT_MODE;
bnei r11, 2f; /* See if returning to kernel mode, */
/* ... if so, skip resched &c. */
@@ -687,32 +596,27 @@ C_ENTRY(ret_from_exc):
* traps), but signal handlers may want to examine or change the
* complete register state. Here we save anything not saved by
* the normal entry sequence, so that it may be safely restored
- * (in a possibly modified form) after do_signal returns.
- * store return registers separately because this macros is use
- * for others exceptions */
- la r5, r1, PTO; /* Arg 1: struct pt_regs *regs */
+ * (in a possibly modified form) after do_signal returns. */
+ addik r5, r1, PTO; /* Arg 1: struct pt_regs *regs */
addi r7, r0, 0; /* Arg 3: int in_syscall */
bralid r15, do_signal; /* Handle any signals */
add r6, r0, r0; /* Arg 2: sigset_t *oldset */
/* Finally, return to user state. */
-1: swi r0, r0, PER_CPU(KM); /* Now officially in user state. */
+1: set_bip; /* Ints masked for state restore */
swi CURRENT_TASK, r0, PER_CPU(CURRENT_SAVE); /* save current */
VM_OFF;
tophys(r1,r1);
- lwi r3, r1, PTO+PT_R3; /* restore saved r3, r4 registers */
- lwi r4, r1, PTO+PT_R4;
RESTORE_REGS;
addik r1, r1, STATE_SAVE_SIZE /* Clean up stack space. */
lwi r1, r1, PT_R1 - PT_SIZE; /* Restore user stack pointer. */
bri 6f;
/* Return to kernel state. */
-2: VM_OFF;
+2: set_bip; /* Ints masked for state restore */
+ VM_OFF;
tophys(r1,r1);
- lwi r3, r1, PTO+PT_R3; /* restore saved r3, r4 registers */
- lwi r4, r1, PTO+PT_R4;
RESTORE_REGS;
addik r1, r1, STATE_SAVE_SIZE /* Clean up stack space. */
@@ -736,36 +640,23 @@ C_ENTRY(_interrupt):
/* MS: we are in physical address */
/* Save registers, switch to proper stack, convert SP to virtual.*/
swi r1, r0, TOPHYS(PER_CPU(ENTRY_SP))
- swi r11, r0, TOPHYS(PER_CPU(R11_SAVE));
/* MS: See if already in kernel mode. */
- lwi r11, r0, TOPHYS(PER_CPU(KM));
- beqi r11, 1f; /* MS: Jump ahead if coming from user */
+ mfs r1, rmsr
+ nop
+ andi r1, r1, MSR_UMS
+ bnei r1, 1f
/* Kernel-mode state save. */
- or r11, r1, r0
- tophys(r1,r11); /* MS: I have in r1 physical address where stack is */
-/* MS: Save original SP - position PT_R1 to next stack frame 4 *1 - 152*/
- swi r11, r1, (PT_R1 - PT_SIZE);
-/* MS: restore r11 because of saving in SAVE_REGS */
- lwi r11, r0, TOPHYS(PER_CPU(R11_SAVE));
+ lwi r1, r0, TOPHYS(PER_CPU(ENTRY_SP))
+ tophys(r1,r1); /* MS: I have in r1 physical address where stack is */
/* save registers */
/* MS: Make room on the stack -> activation record */
addik r1, r1, -STATE_SAVE_SIZE;
-/* MS: store return registers separately because
- * this macros is use for others exceptions */
- swi r3, r1, PTO + PT_R3;
- swi r4, r1, PTO + PT_R4;
SAVE_REGS
- /* MS: store mode */
- addi r11, r0, 1; /* MS: Was in kernel-mode. */
- swi r11, r1, PTO + PT_MODE; /* MS: and save it */
brid 2f;
- nop; /* MS: Fill delay slot */
-
+ swi r1, r1, PTO + PT_MODE; /* 0 - user mode, 1 - kernel mode */
1:
/* User-mode state save. */
-/* MS: restore r11 -> FIXME move before SAVE_REG */
- lwi r11, r0, TOPHYS(PER_CPU(R11_SAVE));
/* MS: get the saved current */
lwi r1, r0, TOPHYS(PER_CPU(CURRENT_SAVE));
tophys(r1,r1);
@@ -774,27 +665,18 @@ C_ENTRY(_interrupt):
tophys(r1,r1);
/* save registers */
addik r1, r1, -STATE_SAVE_SIZE;
- swi r3, r1, PTO+PT_R3;
- swi r4, r1, PTO+PT_R4;
SAVE_REGS
/* calculate mode */
swi r0, r1, PTO + PT_MODE;
lwi r11, r0, TOPHYS(PER_CPU(ENTRY_SP));
swi r11, r1, PTO+PT_R1;
- /* setup kernel mode to KM */
- addi r11, r0, 1;
- swi r11, r0, TOPHYS(PER_CPU(KM));
-
+ clear_ums;
2:
lwi CURRENT_TASK, r0, TOPHYS(PER_CPU(CURRENT_SAVE));
- swi r0, r1, PTO + PT_R0;
tovirt(r1,r1)
- la r5, r1, PTO;
- set_vms;
- la r11, r0, do_IRQ;
- la r15, r0, irq_call;
-irq_call:rtbd r11, 0;
- nop;
+ addik r15, r0, irq_call;
+irq_call:rtbd r0, do_IRQ;
+ addik r5, r1, PTO;
/* MS: we are in virtual mode */
ret_from_irq:
@@ -815,7 +697,7 @@ ret_from_irq:
beqid r11, no_intr_resched
/* Handle a signal return; Pending signals should be in r18. */
addi r7, r0, 0; /* Arg 3: int in_syscall */
- la r5, r1, PTO; /* Arg 1: struct pt_regs *regs */
+ addik r5, r1, PTO; /* Arg 1: struct pt_regs *regs */
bralid r15, do_signal; /* Handle any signals */
add r6, r0, r0; /* Arg 2: sigset_t *oldset */
@@ -823,12 +705,9 @@ ret_from_irq:
no_intr_resched:
/* Disable interrupts, we are now committed to the state restore */
disable_irq
- swi r0, r0, PER_CPU(KM); /* MS: Now officially in user state. */
swi CURRENT_TASK, r0, PER_CPU(CURRENT_SAVE);
VM_OFF;
tophys(r1,r1);
- lwi r3, r1, PTO + PT_R3; /* MS: restore saved r3, r4 registers */
- lwi r4, r1, PTO + PT_R4;
RESTORE_REGS
addik r1, r1, STATE_SAVE_SIZE /* MS: Clean up stack space. */
lwi r1, r1, PT_R1 - PT_SIZE;
@@ -857,8 +736,6 @@ restore:
#endif
VM_OFF /* MS: turn off MMU */
tophys(r1,r1)
- lwi r3, r1, PTO + PT_R3; /* MS: restore saved r3, r4 registers */
- lwi r4, r1, PTO + PT_R4;
RESTORE_REGS
addik r1, r1, STATE_SAVE_SIZE /* MS: Clean up stack space. */
tovirt(r1,r1);
@@ -868,86 +745,91 @@ IRQ_return: /* MS: Make global symbol for debugging */
nop
/*
- * `Debug' trap
- * We enter dbtrap in "BIP" (breakpoint) mode.
- * So we exit the breakpoint mode with an 'rtbd' and proceed with the
- * original dbtrap.
- * however, wait to save state first
+ * Debug trap for KGDB. Enter to _debug_exception by brki r16, 0x18
+ * and call handling function with saved pt_regs
*/
C_ENTRY(_debug_exception):
/* BIP bit is set on entry, no interrupts can occur */
swi r1, r0, TOPHYS(PER_CPU(ENTRY_SP))
- swi r11, r0, TOPHYS(r0_ram + PTO + PT_R11); /* Save r11 */
- set_bip; /*equalize initial state for all possible entries*/
- clear_eip;
- enable_irq;
- lwi r11, r0, TOPHYS(PER_CPU(KM));/* See if already in kernel mode.*/
- beqi r11, 1f; /* Jump ahead if coming from user */
- /* Kernel-mode state save. */
- lwi r11, r0, TOPHYS(PER_CPU(ENTRY_SP)); /* Reload kernel stack-ptr*/
- tophys(r1,r11);
- swi r11, r1, (PT_R1-PT_SIZE); /* Save original SP. */
- lwi r11, r0, TOPHYS(r0_ram + PTO + PT_R11); /* restore r11 */
+ mfs r1, rmsr
+ nop
+ andi r1, r1, MSR_UMS
+ bnei r1, 1f
+/* MS: Kernel-mode state save - kgdb */
+ lwi r1, r0, TOPHYS(PER_CPU(ENTRY_SP)); /* Reload kernel stack-ptr*/
- addik r1, r1, -STATE_SAVE_SIZE; /* Make room on the stack. */
- swi r3, r1, PTO + PT_R3;
- swi r4, r1, PTO + PT_R4;
+ /* BIP bit is set on entry, no interrupts can occur */
+ addik r1, r1, CONFIG_KERNEL_BASE_ADDR - CONFIG_KERNEL_START - STATE_SAVE_SIZE;
SAVE_REGS;
+ /* save all regs to pt_reg structure */
+ swi r0, r1, PTO+PT_R0; /* R0 must be saved too */
+ swi r14, r1, PTO+PT_R14 /* rewrite saved R14 value */
+ swi r16, r1, PTO+PT_R16
+ swi r16, r1, PTO+PT_PC; /* PC and r16 are the same */
+ swi r17, r1, PTO+PT_R17
+ /* save special purpose registers to pt_regs */
+ mfs r11, rear;
+ swi r11, r1, PTO+PT_EAR;
+ mfs r11, resr;
+ swi r11, r1, PTO+PT_ESR;
+ mfs r11, rfsr;
+ swi r11, r1, PTO+PT_FSR;
+
+ /* stack pointer is in physical address at it is decrease
+ * by STATE_SAVE_SIZE but we need to get correct R1 value */
+ addik r11, r1, CONFIG_KERNEL_START - CONFIG_KERNEL_BASE_ADDR + STATE_SAVE_SIZE;
+ swi r11, r1, PTO+PT_R1
+ /* MS: r31 - current pointer isn't changed */
+ tovirt(r1,r1)
+#ifdef CONFIG_KGDB
+ addi r5, r1, PTO /* pass pt_reg address as the first arg */
+ la r15, r0, dbtrap_call; /* return address */
+ rtbd r0, microblaze_kgdb_break
+ nop;
+#endif
+ /* MS: Place handler for brki from kernel space if KGDB is OFF.
+ * It is very unlikely that another brki instruction is called. */
+ bri 0
- addi r11, r0, 1; /* Was in kernel-mode. */
- swi r11, r1, PTO + PT_MODE;
- brid 2f;
- nop; /* Fill delay slot */
-1: /* User-mode state save. */
- lwi r11, r0, TOPHYS(r0_ram + PTO + PT_R11); /* restore r11 */
- lwi r1, r0, TOPHYS(PER_CPU(CURRENT_SAVE)); /* get saved current */
+/* MS: User-mode state save - gdb */
+1: lwi r1, r0, TOPHYS(PER_CPU(CURRENT_SAVE)); /* get saved current */
tophys(r1,r1);
lwi r1, r1, TS_THREAD_INFO; /* get the thread info */
addik r1, r1, THREAD_SIZE; /* calculate kernel stack pointer */
tophys(r1,r1);
addik r1, r1, -STATE_SAVE_SIZE; /* Make room on the stack. */
- swi r3, r1, PTO + PT_R3;
- swi r4, r1, PTO + PT_R4;
SAVE_REGS;
-
- swi r0, r1, PTO+PT_MODE; /* Was in user-mode. */
+ swi r17, r1, PTO+PT_R17;
+ swi r16, r1, PTO+PT_R16;
+ swi r16, r1, PTO+PT_PC; /* Save LP */
+ swi r0, r1, PTO + PT_MODE; /* Was in user-mode. */
lwi r11, r0, TOPHYS(PER_CPU(ENTRY_SP));
swi r11, r1, PTO+PT_R1; /* Store user SP. */
- addi r11, r0, 1;
- swi r11, r0, TOPHYS(PER_CPU(KM)); /* Now we're in kernel-mode. */
-2: lwi CURRENT_TASK, r0, TOPHYS(PER_CPU(CURRENT_SAVE));
- /* Save away the syscall number. */
- swi r0, r1, PTO+PT_R0;
+ lwi CURRENT_TASK, r0, TOPHYS(PER_CPU(CURRENT_SAVE));
tovirt(r1,r1)
-
- addi r5, r0, SIGTRAP /* send the trap signal */
- add r6, r0, CURRENT_TASK; /* Get current task ptr into r11 */
- addk r7, r0, r0 /* 3rd param zero */
-
set_vms;
- la r11, r0, send_sig;
- la r15, r0, dbtrap_call;
-dbtrap_call: rtbd r11, 0;
- nop;
+ addik r5, r1, PTO;
+ addik r15, r0, dbtrap_call;
+dbtrap_call: /* Return point for kernel/user entry + 8 because of rtsd r15, 8 */
+ rtbd r0, sw_exception
+ nop
- set_bip; /* Ints masked for state restore*/
- lwi r11, r1, PTO+PT_MODE;
+ /* MS: The first instruction for the second part of the gdb/kgdb */
+ set_bip; /* Ints masked for state restore */
+ lwi r11, r1, PTO + PT_MODE;
bnei r11, 2f;
-
+/* MS: Return to user space - gdb */
/* Get current task ptr into r11 */
lwi r11, CURRENT_TASK, TS_THREAD_INFO; /* get thread info */
lwi r11, r11, TI_FLAGS; /* get flags in thread info */
andi r11, r11, _TIF_NEED_RESCHED;
beqi r11, 5f;
-/* Call the scheduler before returning from a syscall/trap. */
-
+ /* Call the scheduler before returning from a syscall/trap. */
bralid r15, schedule; /* Call scheduler */
nop; /* delay slot */
- /* XXX Is PT_DTRACE handling needed here? */
- /* XXX m68knommu also checks TASK_STATE & TASK_COUNTER here. */
/* Maybe handle a signal */
5: lwi r11, CURRENT_TASK, TS_THREAD_INFO; /* get thread info */
@@ -955,54 +837,40 @@ dbtrap_call: rtbd r11, 0;
andi r11, r11, _TIF_SIGPENDING;
beqi r11, 1f; /* Signals to handle, handle them */
-/* Handle a signal return; Pending signals should be in r18. */
- /* Not all registers are saved by the normal trap/interrupt entry
- points (for instance, call-saved registers (because the normal
- C-compiler calling sequence in the kernel makes sure they're
- preserved), and call-clobbered registers in the case of
- traps), but signal handlers may want to examine or change the
- complete register state. Here we save anything not saved by
- the normal entry sequence, so that it may be safely restored
- (in a possibly modified form) after do_signal returns. */
-
- la r5, r1, PTO; /* Arg 1: struct pt_regs *regs */
+ addik r5, r1, PTO; /* Arg 1: struct pt_regs *regs */
addi r7, r0, 0; /* Arg 3: int in_syscall */
bralid r15, do_signal; /* Handle any signals */
add r6, r0, r0; /* Arg 2: sigset_t *oldset */
-
/* Finally, return to user state. */
-1: swi r0, r0, PER_CPU(KM); /* Now officially in user state. */
- swi CURRENT_TASK, r0, PER_CPU(CURRENT_SAVE); /* save current */
+1: swi CURRENT_TASK, r0, PER_CPU(CURRENT_SAVE); /* save current */
VM_OFF;
tophys(r1,r1);
-
- lwi r3, r1, PTO+PT_R3; /* restore saved r3, r4 registers */
- lwi r4, r1, PTO+PT_R4;
+ /* MS: Restore all regs */
RESTORE_REGS
- addik r1, r1, STATE_SAVE_SIZE /* Clean up stack space. */
-
-
- lwi r1, r1, PT_R1 - PT_SIZE;
- /* Restore user stack pointer. */
- bri 6f;
+ lwi r17, r1, PTO+PT_R17;
+ lwi r16, r1, PTO+PT_R16;
+ addik r1, r1, STATE_SAVE_SIZE /* Clean up stack space */
+ lwi r1, r1, PT_R1 - PT_SIZE; /* Restore user stack pointer */
+DBTRAP_return_user: /* MS: Make global symbol for debugging */
+ rtbd r16, 0; /* MS: Instructions to return from a debug trap */
+ nop;
-/* Return to kernel state. */
+/* MS: Return to kernel state - kgdb */
2: VM_OFF;
tophys(r1,r1);
- lwi r3, r1, PTO+PT_R3; /* restore saved r3, r4 registers */
- lwi r4, r1, PTO+PT_R4;
+ /* MS: Restore all regs */
RESTORE_REGS
- addik r1, r1, STATE_SAVE_SIZE /* Clean up stack space. */
-
+ lwi r14, r1, PTO+PT_R14;
+ lwi r16, r1, PTO+PT_PC;
+ lwi r17, r1, PTO+PT_R17;
+ addik r1, r1, STATE_SAVE_SIZE; /* MS: Clean up stack space */
tovirt(r1,r1);
-6:
-DBTRAP_return: /* Make global symbol for debugging */
- rtbd r14, 0; /* Instructions to return from an IRQ */
+DBTRAP_return_kernel: /* MS: Make global symbol for debugging */
+ rtbd r16, 0; /* MS: Instructions to return from a debug trap */
nop;
-
ENTRY(_switch_to)
/* prepare return value */
addk r3, r0, CURRENT_TASK
@@ -1037,16 +905,12 @@ ENTRY(_switch_to)
swi r30, r11, CC_R30
/* special purpose registers */
mfs r12, rmsr
- nop
swi r12, r11, CC_MSR
mfs r12, rear
- nop
swi r12, r11, CC_EAR
mfs r12, resr
- nop
swi r12, r11, CC_ESR
mfs r12, rfsr
- nop
swi r12, r11, CC_FSR
/* update r31, the current-give me pointer to task which will be next */
@@ -1085,10 +949,8 @@ ENTRY(_switch_to)
/* special purpose registers */
lwi r12, r11, CC_FSR
mts rfsr, r12
- nop
lwi r12, r11, CC_MSR
mts rmsr, r12
- nop
rtsd r15, 8
nop
@@ -1096,15 +958,6 @@ ENTRY(_switch_to)
ENTRY(_reset)
brai 0x70; /* Jump back to FS-boot */
-ENTRY(_break)
- mfs r5, rmsr
- nop
- swi r5, r0, 0x250 + TOPHYS(r0_ram)
- mfs r5, resr
- nop
- swi r5, r0, 0x254 + TOPHYS(r0_ram)
- bri 0
-
/* These are compiled and loaded into high memory, then
* copied into place in mach_early_setup */
.section .init.ivt, "ax"
@@ -1116,14 +969,38 @@ ENTRY(_break)
nop
brai TOPHYS(_user_exception); /* syscall handler */
brai TOPHYS(_interrupt); /* Interrupt handler */
- brai TOPHYS(_break); /* nmi trap handler */
+ brai TOPHYS(_debug_exception); /* debug trap handler */
brai TOPHYS(_hw_exception_handler); /* HW exception handler */
- .org 0x60
- brai TOPHYS(_debug_exception); /* debug trap handler*/
-
.section .rodata,"a"
#include "syscall_table.S"
syscall_table_size=(.-sys_call_table)
+type_SYSCALL:
+ .ascii "SYSCALL\0"
+type_IRQ:
+ .ascii "IRQ\0"
+type_IRQ_PREEMPT:
+ .ascii "IRQ (PREEMPTED)\0"
+type_SYSCALL_PREEMPT:
+ .ascii " SYSCALL (PREEMPTED)\0"
+
+ /*
+ * Trap decoding for stack unwinder
+ * Tuples are (start addr, end addr, string)
+ * If return address lies on [start addr, end addr],
+ * unwinder displays 'string'
+ */
+
+ .align 4
+.global microblaze_trap_handlers
+microblaze_trap_handlers:
+ /* Exact matches come first */
+ .word ret_from_trap; .word ret_from_trap ; .word type_SYSCALL
+ .word ret_from_irq ; .word ret_from_irq ; .word type_IRQ
+ /* Fuzzy matches go here */
+ .word ret_from_irq ; .word no_intr_resched ; .word type_IRQ_PREEMPT
+ .word ret_from_trap; .word TRAP_return ; .word type_SYSCALL_PREEMPT
+ /* End of table */
+ .word 0 ; .word 0 ; .word 0
diff --git a/arch/microblaze/kernel/exceptions.c b/arch/microblaze/kernel/exceptions.c
index 02cbdfe5aa8..b98ee8d0c1c 100644
--- a/arch/microblaze/kernel/exceptions.c
+++ b/arch/microblaze/kernel/exceptions.c
@@ -48,12 +48,17 @@ void die(const char *str, struct pt_regs *fp, long err)
do_exit(err);
}
+/* for user application debugging */
+void sw_exception(struct pt_regs *regs)
+{
+ _exception(SIGTRAP, regs, TRAP_BRKPT, regs->r16);
+}
+
void _exception(int signr, struct pt_regs *regs, int code, unsigned long addr)
{
siginfo_t info;
if (kernel_mode(regs)) {
- debugger(regs);
die("Exception in kernel mode", regs, signr);
}
info.si_signo = signr;
@@ -143,7 +148,7 @@ asmlinkage void full_exception(struct pt_regs *regs, unsigned int type,
#ifdef CONFIG_MMU
case MICROBLAZE_PRIVILEGED_EXCEPTION:
pr_debug(KERN_WARNING "Privileged exception\n");
- /* "brk r0,r0" - used as debug breakpoint */
+ /* "brk r0,r0" - used as debug breakpoint - old toolchain */
if (get_user(code, (unsigned long *)regs->pc) == 0
&& code == 0x980c0000) {
_exception(SIGTRAP, regs, TRAP_BRKPT, addr);
diff --git a/arch/microblaze/kernel/head.S b/arch/microblaze/kernel/head.S
index 1bf73988826..42434008209 100644
--- a/arch/microblaze/kernel/head.S
+++ b/arch/microblaze/kernel/head.S
@@ -43,10 +43,10 @@
.global empty_zero_page
.align 12
empty_zero_page:
- .space 4096
+ .space PAGE_SIZE
.global swapper_pg_dir
swapper_pg_dir:
- .space 4096
+ .space PAGE_SIZE
#endif /* CONFIG_MMU */
diff --git a/arch/microblaze/kernel/hw_exception_handler.S b/arch/microblaze/kernel/hw_exception_handler.S
index 995a2123635..781195438ee 100644
--- a/arch/microblaze/kernel/hw_exception_handler.S
+++ b/arch/microblaze/kernel/hw_exception_handler.S
@@ -78,9 +78,6 @@
#include <asm/asm-offsets.h>
/* Helpful Macros */
-#ifndef CONFIG_MMU
-#define EX_HANDLER_STACK_SIZ (4*19)
-#endif
#define NUM_TO_REG(num) r ## num
#ifdef CONFIG_MMU
@@ -988,6 +985,7 @@ ex_unaligned_fixup:
.end _unaligned_data_exception
#endif /* CONFIG_MMU */
+.global ex_handler_unhandled
ex_handler_unhandled:
/* FIXME add handle function for unhandled exception - dump register */
bri 0
diff --git a/arch/microblaze/kernel/irq.c b/arch/microblaze/kernel/irq.c
index 8f120aca123..a9345fb4906 100644
--- a/arch/microblaze/kernel/irq.c
+++ b/arch/microblaze/kernel/irq.c
@@ -17,26 +17,17 @@
#include <linux/seq_file.h>
#include <linux/kernel_stat.h>
#include <linux/irq.h>
+#include <linux/of_irq.h>
#include <asm/prom.h>
-unsigned int irq_of_parse_and_map(struct device_node *dev, int index)
-{
- struct of_irq oirq;
-
- if (of_irq_map_one(dev, index, &oirq))
- return NO_IRQ;
-
- return oirq.specifier[0];
-}
-EXPORT_SYMBOL_GPL(irq_of_parse_and_map);
-
static u32 concurrent_irq;
void __irq_entry do_IRQ(struct pt_regs *regs)
{
unsigned int irq;
struct pt_regs *old_regs = set_irq_regs(regs);
+ trace_hardirqs_off();
irq_enter();
irq = get_irq(regs);
@@ -53,6 +44,7 @@ next_irq:
irq_exit();
set_irq_regs(old_regs);
+ trace_hardirqs_on();
}
int show_interrupts(struct seq_file *p, void *v)
@@ -104,7 +96,7 @@ unsigned int irq_create_mapping(struct irq_host *host, irq_hw_number_t hwirq)
EXPORT_SYMBOL_GPL(irq_create_mapping);
unsigned int irq_create_of_mapping(struct device_node *controller,
- u32 *intspec, unsigned int intsize)
+ const u32 *intspec, unsigned int intsize)
{
return intspec[0];
}
diff --git a/arch/microblaze/kernel/kgdb.c b/arch/microblaze/kernel/kgdb.c
new file mode 100644
index 00000000000..bfc006b7f2d
--- /dev/null
+++ b/arch/microblaze/kernel/kgdb.c
@@ -0,0 +1,147 @@
+/*
+ * Microblaze KGDB support
+ *
+ * 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/kgdb.h>
+#include <linux/kdebug.h>
+#include <linux/irq.h>
+#include <linux/io.h>
+#include <asm/cacheflush.h>
+#include <asm/asm-offsets.h>
+#include <asm/pvr.h>
+
+#define GDB_REG 0
+#define GDB_PC 32
+#define GDB_MSR 33
+#define GDB_EAR 34
+#define GDB_ESR 35
+#define GDB_FSR 36
+#define GDB_BTR 37
+#define GDB_PVR 38
+#define GDB_REDR 50
+#define GDB_RPID 51
+#define GDB_RZPR 52
+#define GDB_RTLBX 53
+#define GDB_RTLBSX 54 /* mfs can't read it */
+#define GDB_RTLBLO 55
+#define GDB_RTLBHI 56
+
+/* keep pvr separately because it is unchangeble */
+struct pvr_s pvr;
+
+void pt_regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *regs)
+{
+ int i;
+ unsigned long *pt_regb = (unsigned long *)regs;
+ int temp;
+ /* registers r0 - r31, pc, msr, ear, esr, fsr + do not save pt_mode */
+ for (i = 0; i < (sizeof(struct pt_regs) / 4) - 1; i++)
+ gdb_regs[i] = pt_regb[i];
+
+ /* Branch target register can't be changed */
+ __asm__ __volatile__ ("mfs %0, rbtr;" : "=r"(temp) : );
+ gdb_regs[GDB_BTR] = temp;
+
+ /* pvr part - we have 11 pvr regs */
+ for (i = 0; i < sizeof(struct pvr_s)/4; i++)
+ gdb_regs[GDB_PVR + i] = pvr.pvr[i];
+
+ /* read special registers - can't be changed */
+ __asm__ __volatile__ ("mfs %0, redr;" : "=r"(temp) : );
+ gdb_regs[GDB_REDR] = temp;
+ __asm__ __volatile__ ("mfs %0, rpid;" : "=r"(temp) : );
+ gdb_regs[GDB_RPID] = temp;
+ __asm__ __volatile__ ("mfs %0, rzpr;" : "=r"(temp) : );
+ gdb_regs[GDB_RZPR] = temp;
+ __asm__ __volatile__ ("mfs %0, rtlbx;" : "=r"(temp) : );
+ gdb_regs[GDB_RTLBX] = temp;
+ __asm__ __volatile__ ("mfs %0, rtlblo;" : "=r"(temp) : );
+ gdb_regs[GDB_RTLBLO] = temp;
+ __asm__ __volatile__ ("mfs %0, rtlbhi;" : "=r"(temp) : );
+ gdb_regs[GDB_RTLBHI] = temp;
+}
+
+void gdb_regs_to_pt_regs(unsigned long *gdb_regs, struct pt_regs *regs)
+{
+ int i;
+ unsigned long *pt_regb = (unsigned long *)regs;
+
+ /* pt_regs and gdb_regs have the same 37 values.
+ * The rest of gdb_regs are unused and can't be changed.
+ * r0 register value can't be changed too. */
+ for (i = 1; i < (sizeof(struct pt_regs) / 4) - 1; i++)
+ pt_regb[i] = gdb_regs[i];
+}
+
+void microblaze_kgdb_break(struct pt_regs *regs)
+{
+ if (kgdb_handle_exception(1, SIGTRAP, 0, regs) != 0)
+ return 0;
+
+ /* Jump over the first arch_kgdb_breakpoint which is barrier to
+ * get kgdb work. The same solution is used for powerpc */
+ if (*(u32 *) (regs->pc) == *(u32 *) (&arch_kgdb_ops.gdb_bpt_instr))
+ regs->pc += BREAK_INSTR_SIZE;
+}
+
+/* untested */
+void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *p)
+{
+ int i;
+ unsigned long *pt_regb = (unsigned long *)(p->thread.regs);
+
+ /* registers r0 - r31, pc, msr, ear, esr, fsr + do not save pt_mode */
+ for (i = 0; i < (sizeof(struct pt_regs) / 4) - 1; i++)
+ gdb_regs[i] = pt_regb[i];
+
+ /* pvr part - we have 11 pvr regs */
+ for (i = 0; i < sizeof(struct pvr_s)/4; i++)
+ gdb_regs[GDB_PVR + i] = pvr.pvr[i];
+}
+
+void kgdb_arch_set_pc(struct pt_regs *regs, unsigned long ip)
+{
+ regs->pc = ip;
+}
+
+int kgdb_arch_handle_exception(int vector, int signo, int err_code,
+ char *remcom_in_buffer, char *remcom_out_buffer,
+ struct pt_regs *regs)
+{
+ char *ptr;
+ unsigned long address;
+ int cpu = smp_processor_id();
+
+ switch (remcom_in_buffer[0]) {
+ case 'c':
+ /* handle the optional parameter */
+ ptr = &remcom_in_buffer[1];
+ if (kgdb_hex2long(&ptr, &address))
+ regs->pc = address;
+
+ return 0;
+ }
+ return -1; /* this means that we do not want to exit from the handler */
+}
+
+int kgdb_arch_init(void)
+{
+ get_pvr(&pvr); /* Fill PVR structure */
+ return 0;
+}
+
+void kgdb_arch_exit(void)
+{
+ /* Nothing to do */
+}
+
+/*
+ * Global data
+ */
+struct kgdb_arch arch_kgdb_ops = {
+ .gdb_bpt_instr = {0xba, 0x0c, 0x00, 0x18}, /* brki r16, 0x18 */
+};
diff --git a/arch/microblaze/kernel/misc.S b/arch/microblaze/kernel/misc.S
index 0fb5fc6c1fc..206da3da361 100644
--- a/arch/microblaze/kernel/misc.S
+++ b/arch/microblaze/kernel/misc.S
@@ -76,7 +76,7 @@ early_console_reg_tlb_alloc:
* the UARTs nice and early. We use a 4k real==virtual mapping.
*/
ori r4, r0, MICROBLAZE_TLB_SIZE - 1
- mts rtlbx, r4 /* TLB slot 2 */
+ mts rtlbx, r4 /* TLB slot 63 */
or r4,r5,r0
andi r4,r4,0xfffff000
diff --git a/arch/microblaze/kernel/of_device.c b/arch/microblaze/kernel/of_device.c
deleted file mode 100644
index b372787886e..00000000000
--- a/arch/microblaze/kernel/of_device.c
+++ /dev/null
@@ -1,112 +0,0 @@
-#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 <linux/of_device.h>
-
-#include <linux/errno.h>
-
-void of_device_make_bus_id(struct of_device *dev)
-{
- static atomic_t bus_no_reg_magic;
- struct device_node *node = dev->dev.of_node;
- const u32 *reg;
- u64 addr;
- int magic;
-
- /*
- * For MMIO, get the physical address
- */
- reg = of_get_property(node, "reg", NULL);
- if (reg) {
- addr = of_translate_address(node, reg);
- if (addr != OF_BAD_ADDR) {
- dev_set_name(&dev->dev, "%llx.%s",
- (unsigned long long)addr, node->name);
- return;
- }
- }
-
- /*
- * No BusID, use the node name and add a globally incremented
- * counter (and pray...)
- */
- magic = atomic_add_return(1, &bus_no_reg_magic);
- dev_set_name(&dev->dev, "%s.%d", node->name, magic - 1);
-}
-EXPORT_SYMBOL(of_device_make_bus_id);
-
-struct of_device *of_device_alloc(struct device_node *np,
- const char *bus_id,
- struct device *parent)
-{
- struct of_device *dev;
-
- dev = kzalloc(sizeof(*dev), GFP_KERNEL);
- if (!dev)
- return NULL;
-
- dev->dev.of_node = of_node_get(np);
- dev->dev.dma_mask = &dev->archdata.dma_mask;
- dev->dev.parent = parent;
- dev->dev.release = of_release_dev;
-
- if (bus_id)
- dev_set_name(&dev->dev, bus_id);
- else
- of_device_make_bus_id(dev);
-
- return dev;
-}
-EXPORT_SYMBOL(of_device_alloc);
-
-int of_device_uevent(struct device *dev, struct kobj_uevent_env *env)
-{
- struct of_device *ofdev;
- const char *compat;
- int seen = 0, cplen, sl;
-
- if (!dev)
- return -ENODEV;
-
- ofdev = to_of_device(dev);
-
- if (add_uevent_var(env, "OF_NAME=%s", ofdev->dev.of_node->name))
- return -ENOMEM;
-
- if (add_uevent_var(env, "OF_TYPE=%s", ofdev->dev.of_node->type))
- return -ENOMEM;
-
- /* Since the compatible field can contain pretty much anything
- * it's not really legal to split it out with commas. We split it
- * up using a number of environment variables instead. */
-
- compat = of_get_property(ofdev->dev.of_node, "compatible", &cplen);
- while (compat && *compat && cplen > 0) {
- if (add_uevent_var(env, "OF_COMPATIBLE_%d=%s", seen, compat))
- return -ENOMEM;
-
- sl = strlen(compat) + 1;
- compat += sl;
- cplen -= sl;
- seen++;
- }
-
- if (add_uevent_var(env, "OF_COMPATIBLE_N=%d", seen))
- return -ENOMEM;
-
- /* modalias is trickier, we add it in 2 steps */
- if (add_uevent_var(env, "MODALIAS="))
- return -ENOMEM;
- sl = of_device_get_modalias(ofdev, &env->buf[env->buflen-1],
- sizeof(env->buf) - env->buflen);
- if (sl >= (sizeof(env->buf) - env->buflen))
- return -ENOMEM;
- env->buflen += sl;
-
- return 0;
-}
-EXPORT_SYMBOL(of_device_uevent);
diff --git a/arch/microblaze/kernel/of_platform.c b/arch/microblaze/kernel/of_platform.c
deleted file mode 100644
index ccf6f4257f4..00000000000
--- a/arch/microblaze/kernel/of_platform.c
+++ /dev/null
@@ -1,200 +0,0 @@
-/*
- * Copyright (C) 2006 Benjamin Herrenschmidt, IBM Corp.
- * <benh@kernel.crashing.org>
- * and Arnd Bergmann, 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.
- *
- */
-
-#undef DEBUG
-
-#include <linux/string.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/mod_devicetable.h>
-#include <linux/pci.h>
-#include <linux/of.h>
-#include <linux/of_device.h>
-#include <linux/of_platform.h>
-
-#include <linux/errno.h>
-#include <linux/topology.h>
-#include <asm/atomic.h>
-
-struct bus_type of_platform_bus_type = {
- .uevent = of_device_uevent,
-};
-EXPORT_SYMBOL(of_platform_bus_type);
-
-static int __init of_bus_driver_init(void)
-{
- return of_bus_type_init(&of_platform_bus_type, "of_platform");
-}
-postcore_initcall(of_bus_driver_init);
-
-struct of_device *of_platform_device_create(struct device_node *np,
- const char *bus_id,
- struct device *parent)
-{
- struct of_device *dev;
-
- dev = of_device_alloc(np, bus_id, parent);
- if (!dev)
- return NULL;
-
- dev->archdata.dma_mask = 0xffffffffUL;
- dev->dev.bus = &of_platform_bus_type;
-
- /* We do not fill the DMA ops for platform devices by default.
- * This is currently the responsibility of the platform code
- * to do such, possibly using a device notifier
- */
-
- if (of_device_register(dev) != 0) {
- of_device_free(dev);
- return NULL;
- }
-
- return dev;
-}
-EXPORT_SYMBOL(of_platform_device_create);
-
-/**
- * of_platform_bus_create - Create an OF device for a bus node and all its
- * children. Optionally recursively instanciate matching busses.
- * @bus: device node of the bus to instanciate
- * @matches: match table, NULL to use the default, OF_NO_DEEP_PROBE to
- * disallow recursive creation of child busses
- */
-static int of_platform_bus_create(const struct device_node *bus,
- const struct of_device_id *matches,
- struct device *parent)
-{
- struct device_node *child;
- struct of_device *dev;
- int rc = 0;
-
- for_each_child_of_node(bus, child) {
- pr_debug(" create child: %s\n", child->full_name);
- dev = of_platform_device_create(child, NULL, parent);
- if (dev == NULL)
- rc = -ENOMEM;
- else if (!of_match_node(matches, child))
- continue;
- if (rc == 0) {
- pr_debug(" and sub busses\n");
- rc = of_platform_bus_create(child, matches, &dev->dev);
- }
- if (rc) {
- of_node_put(child);
- break;
- }
- }
- return rc;
-}
-
-
-/**
- * of_platform_bus_probe - Probe the device-tree for platform busses
- * @root: parent of the first level to probe or NULL for the root of the tree
- * @matches: match table, NULL to use the default
- * @parent: parent to hook devices from, NULL for toplevel
- *
- * Note that children of the provided root are not instanciated as devices
- * unless the specified root itself matches the bus list and is not NULL.
- */
-
-int of_platform_bus_probe(struct device_node *root,
- const struct of_device_id *matches,
- struct device *parent)
-{
- struct device_node *child;
- struct of_device *dev;
- int rc = 0;
-
- if (matches == NULL)
- matches = of_default_bus_ids;
- if (matches == OF_NO_DEEP_PROBE)
- return -EINVAL;
- if (root == NULL)
- root = of_find_node_by_path("/");
- else
- of_node_get(root);
-
- pr_debug("of_platform_bus_probe()\n");
- pr_debug(" starting at: %s\n", root->full_name);
-
- /* Do a self check of bus type, if there's a match, create
- * children
- */
- if (of_match_node(matches, root)) {
- pr_debug(" root match, create all sub devices\n");
- dev = of_platform_device_create(root, NULL, parent);
- if (dev == NULL) {
- rc = -ENOMEM;
- goto bail;
- }
- pr_debug(" create all sub busses\n");
- rc = of_platform_bus_create(root, matches, &dev->dev);
- goto bail;
- }
- for_each_child_of_node(root, child) {
- if (!of_match_node(matches, child))
- continue;
-
- pr_debug(" match: %s\n", child->full_name);
- dev = of_platform_device_create(child, NULL, parent);
- if (dev == NULL)
- rc = -ENOMEM;
- else
- rc = of_platform_bus_create(child, matches, &dev->dev);
- if (rc) {
- of_node_put(child);
- break;
- }
- }
- bail:
- of_node_put(root);
- return rc;
-}
-EXPORT_SYMBOL(of_platform_bus_probe);
-
-static int of_dev_node_match(struct device *dev, void *data)
-{
- return to_of_device(dev)->dev.of_node == data;
-}
-
-struct of_device *of_find_device_by_node(struct device_node *np)
-{
- struct device *dev;
-
- dev = bus_find_device(&of_platform_bus_type,
- NULL, np, of_dev_node_match);
- if (dev)
- return to_of_device(dev);
- return NULL;
-}
-EXPORT_SYMBOL(of_find_device_by_node);
-
-static int of_dev_phandle_match(struct device *dev, void *data)
-{
- phandle *ph = data;
- return to_of_device(dev)->dev.of_node->phandle == *ph;
-}
-
-struct of_device *of_find_device_by_phandle(phandle ph)
-{
- struct device *dev;
-
- dev = bus_find_device(&of_platform_bus_type,
- NULL, &ph, of_dev_phandle_match);
- if (dev)
- return to_of_device(dev);
- return NULL;
-}
-EXPORT_SYMBOL(of_find_device_by_phandle);
diff --git a/arch/microblaze/kernel/process.c b/arch/microblaze/kernel/process.c
index 09bed44dfcd..ba7c4b16ed3 100644
--- a/arch/microblaze/kernel/process.c
+++ b/arch/microblaze/kernel/process.c
@@ -76,8 +76,11 @@ __setup("hlt", hlt_setup);
void default_idle(void)
{
if (likely(hlt_counter)) {
- while (!need_resched())
- cpu_relax();
+ local_irq_disable();
+ stop_critical_timings();
+ cpu_relax();
+ start_critical_timings();
+ local_irq_enable();
} else {
clear_thread_flag(TIF_POLLING_NRFLAG);
smp_mb__after_clear_bit();
diff --git a/arch/microblaze/kernel/prom_parse.c b/arch/microblaze/kernel/prom_parse.c
index bf7e6c27e31..d33ba17601f 100644
--- a/arch/microblaze/kernel/prom_parse.c
+++ b/arch/microblaze/kernel/prom_parse.c
@@ -6,219 +6,11 @@
#include <linux/module.h>
#include <linux/ioport.h>
#include <linux/etherdevice.h>
+#include <linux/of_address.h>
#include <asm/prom.h>
#include <asm/pci-bridge.h>
-#define PRu64 "%llx"
-
-/* Max address size we deal with */
-#define OF_MAX_ADDR_CELLS 4
-#define OF_CHECK_COUNTS(na, ns) ((na) > 0 && (na) <= OF_MAX_ADDR_CELLS && \
- (ns) > 0)
-
-static struct of_bus *of_match_bus(struct device_node *np);
-static int __of_address_to_resource(struct device_node *dev,
- const u32 *addrp, u64 size, unsigned int flags,
- struct resource *r);
-
-/* Debug utility */
-#ifdef DEBUG
-static void of_dump_addr(const char *s, const u32 *addr, int na)
-{
- printk(KERN_INFO "%s", s);
- while (na--)
- printk(KERN_INFO " %08x", *(addr++));
- printk(KERN_INFO "\n");
-}
-#else
-static void of_dump_addr(const char *s, const u32 *addr, int na) { }
-#endif
-
-/* Callbacks for bus specific translators */
-struct of_bus {
- const char *name;
- const char *addresses;
- int (*match)(struct device_node *parent);
- void (*count_cells)(struct device_node *child,
- int *addrc, int *sizec);
- u64 (*map)(u32 *addr, const u32 *range,
- int na, int ns, int pna);
- int (*translate)(u32 *addr, u64 offset, int na);
- unsigned int (*get_flags)(const u32 *addr);
-};
-
-/*
- * Default translator (generic bus)
- */
-
-static void of_bus_default_count_cells(struct device_node *dev,
- int *addrc, int *sizec)
-{
- if (addrc)
- *addrc = of_n_addr_cells(dev);
- if (sizec)
- *sizec = of_n_size_cells(dev);
-}
-
-static u64 of_bus_default_map(u32 *addr, const u32 *range,
- int na, int ns, int pna)
-{
- u64 cp, s, da;
-
- cp = of_read_number(range, na);
- s = of_read_number(range + na + pna, ns);
- da = of_read_number(addr, na);
-
- pr_debug("OF: default map, cp="PRu64", s="PRu64", da="PRu64"\n",
- cp, s, da);
-
- if (da < cp || da >= (cp + s))
- return OF_BAD_ADDR;
- return da - cp;
-}
-
-static int of_bus_default_translate(u32 *addr, u64 offset, int na)
-{
- u64 a = of_read_number(addr, na);
- memset(addr, 0, na * 4);
- a += offset;
- if (na > 1)
- addr[na - 2] = a >> 32;
- addr[na - 1] = a & 0xffffffffu;
-
- return 0;
-}
-
-static unsigned int of_bus_default_get_flags(const u32 *addr)
-{
- return IORESOURCE_MEM;
-}
-
#ifdef CONFIG_PCI
-/*
- * PCI bus specific translator
- */
-
-static int of_bus_pci_match(struct device_node *np)
-{
- /* "vci" is for the /chaos bridge on 1st-gen PCI powermacs */
- return !strcmp(np->type, "pci") || !strcmp(np->type, "vci");
-}
-
-static void of_bus_pci_count_cells(struct device_node *np,
- int *addrc, int *sizec)
-{
- if (addrc)
- *addrc = 3;
- if (sizec)
- *sizec = 2;
-}
-
-static u64 of_bus_pci_map(u32 *addr, const u32 *range, int na, int ns, int pna)
-{
- u64 cp, s, da;
-
- /* Check address type match */
- if ((addr[0] ^ range[0]) & 0x03000000)
- return OF_BAD_ADDR;
-
- /* Read address values, skipping high cell */
- cp = of_read_number(range + 1, na - 1);
- s = of_read_number(range + na + pna, ns);
- da = of_read_number(addr + 1, na - 1);
-
- pr_debug("OF: PCI map, cp="PRu64", s="PRu64", da="PRu64"\n", cp, s, da);
-
- if (da < cp || da >= (cp + s))
- return OF_BAD_ADDR;
- return da - cp;
-}
-
-static int of_bus_pci_translate(u32 *addr, u64 offset, int na)
-{
- return of_bus_default_translate(addr + 1, offset, na - 1);
-}
-
-static unsigned int of_bus_pci_get_flags(const u32 *addr)
-{
- unsigned int flags = 0;
- u32 w = addr[0];
-
- switch ((w >> 24) & 0x03) {
- case 0x01:
- flags |= IORESOURCE_IO;
- break;
- case 0x02: /* 32 bits */
- case 0x03: /* 64 bits */
- flags |= IORESOURCE_MEM;
- break;
- }
- if (w & 0x40000000)
- flags |= IORESOURCE_PREFETCH;
- return flags;
-}
-
-const u32 *of_get_pci_address(struct device_node *dev, int bar_no, u64 *size,
- unsigned int *flags)
-{
- const u32 *prop;
- unsigned int psize;
- struct device_node *parent;
- struct of_bus *bus;
- int onesize, i, na, ns;
-
- /* Get parent & match bus type */
- parent = of_get_parent(dev);
- if (parent == NULL)
- return NULL;
- bus = of_match_bus(parent);
- if (strcmp(bus->name, "pci")) {
- of_node_put(parent);
- return NULL;
- }
- bus->count_cells(dev, &na, &ns);
- of_node_put(parent);
- if (!OF_CHECK_COUNTS(na, ns))
- return NULL;
-
- /* Get "reg" or "assigned-addresses" property */
- prop = of_get_property(dev, bus->addresses, &psize);
- if (prop == NULL)
- return NULL;
- psize /= 4;
-
- onesize = na + ns;
- for (i = 0; psize >= onesize; psize -= onesize, prop += onesize, i++)
- if ((prop[0] & 0xff) == ((bar_no * 4) + PCI_BASE_ADDRESS_0)) {
- if (size)
- *size = of_read_number(prop + na, ns);
- if (flags)
- *flags = bus->get_flags(prop);
- return prop;
- }
- return NULL;
-}
-EXPORT_SYMBOL(of_get_pci_address);
-
-int of_pci_address_to_resource(struct device_node *dev, int bar,
- struct resource *r)
-{
- const u32 *addrp;
- u64 size;
- unsigned int flags;
-
- addrp = of_get_pci_address(dev, bar, &size, &flags);
- if (addrp == NULL)
- return -EINVAL;
- return __of_address_to_resource(dev, addrp, size, flags, r);
-}
-EXPORT_SYMBOL_GPL(of_pci_address_to_resource);
-
-static u8 of_irq_pci_swizzle(u8 slot, u8 pin)
-{
- return (((pin - 1) + slot) % 4) + 1;
-}
-
int of_irq_map_pci(struct pci_dev *pdev, struct of_irq *out_irq)
{
struct device_node *dn, *ppnode;
@@ -293,331 +85,6 @@ int of_irq_map_pci(struct pci_dev *pdev, struct of_irq *out_irq)
EXPORT_SYMBOL_GPL(of_irq_map_pci);
#endif /* CONFIG_PCI */
-/*
- * ISA bus specific translator
- */
-
-static int of_bus_isa_match(struct device_node *np)
-{
- return !strcmp(np->name, "isa");
-}
-
-static void of_bus_isa_count_cells(struct device_node *child,
- int *addrc, int *sizec)
-{
- if (addrc)
- *addrc = 2;
- if (sizec)
- *sizec = 1;
-}
-
-static u64 of_bus_isa_map(u32 *addr, const u32 *range, int na, int ns, int pna)
-{
- u64 cp, s, da;
-
- /* Check address type match */
- if ((addr[0] ^ range[0]) & 0x00000001)
- return OF_BAD_ADDR;
-
- /* Read address values, skipping high cell */
- cp = of_read_number(range + 1, na - 1);
- s = of_read_number(range + na + pna, ns);
- da = of_read_number(addr + 1, na - 1);
-
- pr_debug("OF: ISA map, cp="PRu64", s="PRu64", da="PRu64"\n", cp, s, da);
-
- if (da < cp || da >= (cp + s))
- return OF_BAD_ADDR;
- return da - cp;
-}
-
-static int of_bus_isa_translate(u32 *addr, u64 offset, int na)
-{
- return of_bus_default_translate(addr + 1, offset, na - 1);
-}
-
-static unsigned int of_bus_isa_get_flags(const u32 *addr)
-{
- unsigned int flags = 0;
- u32 w = addr[0];
-
- if (w & 1)
- flags |= IORESOURCE_IO;
- else
- flags |= IORESOURCE_MEM;
- return flags;
-}
-
-/*
- * Array of bus specific translators
- */
-
-static struct of_bus of_busses[] = {
-#ifdef CONFIG_PCI
- /* PCI */
- {
- .name = "pci",
- .addresses = "assigned-addresses",
- .match = of_bus_pci_match,
- .count_cells = of_bus_pci_count_cells,
- .map = of_bus_pci_map,
- .translate = of_bus_pci_translate,
- .get_flags = of_bus_pci_get_flags,
- },
-#endif /* CONFIG_PCI */
- /* ISA */
- {
- .name = "isa",
- .addresses = "reg",
- .match = of_bus_isa_match,
- .count_cells = of_bus_isa_count_cells,
- .map = of_bus_isa_map,
- .translate = of_bus_isa_translate,
- .get_flags = of_bus_isa_get_flags,
- },
- /* Default */
- {
- .name = "default",
- .addresses = "reg",
- .match = NULL,
- .count_cells = of_bus_default_count_cells,
- .map = of_bus_default_map,
- .translate = of_bus_default_translate,
- .get_flags = of_bus_default_get_flags,
- },
-};
-
-static struct of_bus *of_match_bus(struct device_node *np)
-{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(of_busses); i++)
- if (!of_busses[i].match || of_busses[i].match(np))
- return &of_busses[i];
- BUG();
- return NULL;
-}
-
-static int of_translate_one(struct device_node *parent, struct of_bus *bus,
- struct of_bus *pbus, u32 *addr,
- int na, int ns, int pna)
-{
- const u32 *ranges;
- unsigned int rlen;
- int rone;
- u64 offset = OF_BAD_ADDR;
-
- /* Normally, an absence of a "ranges" property means we are
- * crossing a non-translatable boundary, and thus the addresses
- * below the current not cannot be converted to CPU physical ones.
- * Unfortunately, while this is very clear in the spec, it's not
- * what Apple understood, and they do have things like /uni-n or
- * /ht nodes with no "ranges" property and a lot of perfectly
- * useable mapped devices below them. Thus we treat the absence of
- * "ranges" as equivalent to an empty "ranges" property which means
- * a 1:1 translation at that level. It's up to the caller not to try
- * to translate addresses that aren't supposed to be translated in
- * the first place. --BenH.
- */
- ranges = of_get_property(parent, "ranges", (int *) &rlen);
- if (ranges == NULL || rlen == 0) {
- offset = of_read_number(addr, na);
- memset(addr, 0, pna * 4);
- pr_debug("OF: no ranges, 1:1 translation\n");
- goto finish;
- }
-
- pr_debug("OF: walking ranges...\n");
-
- /* Now walk through the ranges */
- rlen /= 4;
- rone = na + pna + ns;
- for (; rlen >= rone; rlen -= rone, ranges += rone) {
- offset = bus->map(addr, ranges, na, ns, pna);
- if (offset != OF_BAD_ADDR)
- break;
- }
- if (offset == OF_BAD_ADDR) {
- pr_debug("OF: not found !\n");
- return 1;
- }
- memcpy(addr, ranges + na, 4 * pna);
-
- finish:
- of_dump_addr("OF: parent translation for:", addr, pna);
- pr_debug("OF: with offset: "PRu64"\n", offset);
-
- /* Translate it into parent bus space */
- return pbus->translate(addr, offset, pna);
-}
-
-/*
- * Translate an address from the device-tree into a CPU physical address,
- * this walks up the tree and applies the various bus mappings on the
- * way.
- *
- * Note: We consider that crossing any level with #size-cells == 0 to mean
- * that translation is impossible (that is we are not dealing with a value
- * that can be mapped to a cpu physical address). This is not really specified
- * that way, but this is traditionally the way IBM at least do things
- */
-u64 of_translate_address(struct device_node *dev, const u32 *in_addr)
-{
- struct device_node *parent = NULL;
- struct of_bus *bus, *pbus;
- u32 addr[OF_MAX_ADDR_CELLS];
- int na, ns, pna, pns;
- u64 result = OF_BAD_ADDR;
-
- pr_debug("OF: ** translation for device %s **\n", dev->full_name);
-
- /* Increase refcount at current level */
- of_node_get(dev);
-
- /* Get parent & match bus type */
- parent = of_get_parent(dev);
- if (parent == NULL)
- goto bail;
- bus = of_match_bus(parent);
-
- /* Cound address cells & copy address locally */
- bus->count_cells(dev, &na, &ns);
- if (!OF_CHECK_COUNTS(na, ns)) {
- printk(KERN_ERR "prom_parse: Bad cell count for %s\n",
- dev->full_name);
- goto bail;
- }
- memcpy(addr, in_addr, na * 4);
-
- pr_debug("OF: bus is %s (na=%d, ns=%d) on %s\n",
- bus->name, na, ns, parent->full_name);
- of_dump_addr("OF: translating address:", addr, na);
-
- /* Translate */
- for (;;) {
- /* Switch to parent bus */
- of_node_put(dev);
- dev = parent;
- parent = of_get_parent(dev);
-
- /* If root, we have finished */
- if (parent == NULL) {
- pr_debug("OF: reached root node\n");
- result = of_read_number(addr, na);
- break;
- }
-
- /* Get new parent bus and counts */
- pbus = of_match_bus(parent);
- pbus->count_cells(dev, &pna, &pns);
- if (!OF_CHECK_COUNTS(pna, pns)) {
- printk(KERN_ERR "prom_parse: Bad cell count for %s\n",
- dev->full_name);
- break;
- }
-
- pr_debug("OF: parent bus is %s (na=%d, ns=%d) on %s\n",
- pbus->name, pna, pns, parent->full_name);
-
- /* Apply bus translation */
- if (of_translate_one(dev, bus, pbus, addr, na, ns, pna))
- break;
-
- /* Complete the move up one level */
- na = pna;
- ns = pns;
- bus = pbus;
-
- of_dump_addr("OF: one level translation:", addr, na);
- }
- bail:
- of_node_put(parent);
- of_node_put(dev);
-
- return result;
-}
-EXPORT_SYMBOL(of_translate_address);
-
-const u32 *of_get_address(struct device_node *dev, int index, u64 *size,
- unsigned int *flags)
-{
- const u32 *prop;
- unsigned int psize;
- struct device_node *parent;
- struct of_bus *bus;
- int onesize, i, na, ns;
-
- /* Get parent & match bus type */
- parent = of_get_parent(dev);
- if (parent == NULL)
- return NULL;
- bus = of_match_bus(parent);
- bus->count_cells(dev, &na, &ns);
- of_node_put(parent);
- if (!OF_CHECK_COUNTS(na, ns))
- return NULL;
-
- /* Get "reg" or "assigned-addresses" property */
- prop = of_get_property(dev, bus->addresses, (int *) &psize);
- if (prop == NULL)
- return NULL;
- psize /= 4;
-
- onesize = na + ns;
- for (i = 0; psize >= onesize; psize -= onesize, prop += onesize, i++)
- if (i == index) {
- if (size)
- *size = of_read_number(prop + na, ns);
- if (flags)
- *flags = bus->get_flags(prop);
- return prop;
- }
- return NULL;
-}
-EXPORT_SYMBOL(of_get_address);
-
-static int __of_address_to_resource(struct device_node *dev, const u32 *addrp,
- u64 size, unsigned int flags,
- struct resource *r)
-{
- u64 taddr;
-
- if ((flags & (IORESOURCE_IO | IORESOURCE_MEM)) == 0)
- return -EINVAL;
- taddr = of_translate_address(dev, addrp);
- if (taddr == OF_BAD_ADDR)
- return -EINVAL;
- memset(r, 0, sizeof(struct resource));
- if (flags & IORESOURCE_IO) {
- unsigned long port;
- port = -1; /* pci_address_to_pio(taddr); */
- if (port == (unsigned long)-1)
- return -EINVAL;
- r->start = port;
- r->end = port + size - 1;
- } else {
- r->start = taddr;
- r->end = taddr + size - 1;
- }
- r->flags = flags;
- r->name = dev->name;
- return 0;
-}
-
-int of_address_to_resource(struct device_node *dev, int index,
- struct resource *r)
-{
- const u32 *addrp;
- u64 size;
- unsigned int flags;
-
- addrp = of_get_address(dev, index, &size, &flags);
- if (addrp == NULL)
- return -EINVAL;
- return __of_address_to_resource(dev, addrp, size, flags, r);
-}
-EXPORT_SYMBOL_GPL(of_address_to_resource);
-
void of_parse_dma_window(struct device_node *dn, const void *dma_window_prop,
unsigned long *busno, unsigned long *phys, unsigned long *size)
{
@@ -644,308 +111,6 @@ void of_parse_dma_window(struct device_node *dn, const void *dma_window_prop,
*size = of_read_number(dma_window, cells);
}
-/*
- * Interrupt remapper
- */
-
-static unsigned int of_irq_workarounds;
-static struct device_node *of_irq_dflt_pic;
-
-static struct device_node *of_irq_find_parent(struct device_node *child)
-{
- struct device_node *p;
- const phandle *parp;
-
- if (!of_node_get(child))
- return NULL;
-
- do {
- parp = of_get_property(child, "interrupt-parent", NULL);
- if (parp == NULL)
- p = of_get_parent(child);
- else {
- if (of_irq_workarounds & OF_IMAP_NO_PHANDLE)
- p = of_node_get(of_irq_dflt_pic);
- else
- p = of_find_node_by_phandle(*parp);
- }
- of_node_put(child);
- child = p;
- } while (p && of_get_property(p, "#interrupt-cells", NULL) == NULL);
-
- return p;
-}
-
-/* This doesn't need to be called if you don't have any special workaround
- * flags to pass
- */
-void of_irq_map_init(unsigned int flags)
-{
- of_irq_workarounds = flags;
-
- /* OldWorld, don't bother looking at other things */
- if (flags & OF_IMAP_OLDWORLD_MAC)
- return;
-
- /* If we don't have phandles, let's try to locate a default interrupt
- * controller (happens when booting with BootX). We do a first match
- * here, hopefully, that only ever happens on machines with one
- * controller.
- */
- if (flags & OF_IMAP_NO_PHANDLE) {
- struct device_node *np;
-
- for (np = NULL; (np = of_find_all_nodes(np)) != NULL;) {
- if (of_get_property(np, "interrupt-controller", NULL)
- == NULL)
- continue;
- /* Skip /chosen/interrupt-controller */
- if (strcmp(np->name, "chosen") == 0)
- continue;
- /* It seems like at least one person on this planet
- * wants to use BootX on a machine with an AppleKiwi
- * controller which happens to pretend to be an
- * interrupt controller too.
- */
- if (strcmp(np->name, "AppleKiwi") == 0)
- continue;
- /* I think we found one ! */
- of_irq_dflt_pic = np;
- break;
- }
- }
-
-}
-
-int of_irq_map_raw(struct device_node *parent, const u32 *intspec, u32 ointsize,
- const u32 *addr, struct of_irq *out_irq)
-{
- struct device_node *ipar, *tnode, *old = NULL, *newpar = NULL;
- const u32 *tmp, *imap, *imask;
- u32 intsize = 1, addrsize, newintsize = 0, newaddrsize = 0;
- int imaplen, match, i;
-
- pr_debug("of_irq_map_raw: par=%s,intspec=[0x%08x 0x%08x...],"
- "ointsize=%d\n",
- parent->full_name, intspec[0], intspec[1], ointsize);
-
- ipar = of_node_get(parent);
-
- /* First get the #interrupt-cells property of the current cursor
- * that tells us how to interpret the passed-in intspec. If there
- * is none, we are nice and just walk up the tree
- */
- do {
- tmp = of_get_property(ipar, "#interrupt-cells", NULL);
- if (tmp != NULL) {
- intsize = *tmp;
- break;
- }
- tnode = ipar;
- ipar = of_irq_find_parent(ipar);
- of_node_put(tnode);
- } while (ipar);
- if (ipar == NULL) {
- pr_debug(" -> no parent found !\n");
- goto fail;
- }
-
- pr_debug("of_irq_map_raw: ipar=%s, size=%d\n",
- ipar->full_name, intsize);
-
- if (ointsize != intsize)
- return -EINVAL;
-
- /* Look for this #address-cells. We have to implement the old linux
- * trick of looking for the parent here as some device-trees rely on it
- */
- old = of_node_get(ipar);
- do {
- tmp = of_get_property(old, "#address-cells", NULL);
- tnode = of_get_parent(old);
- of_node_put(old);
- old = tnode;
- } while (old && tmp == NULL);
- of_node_put(old);
- old = NULL;
- addrsize = (tmp == NULL) ? 2 : *tmp;
-
- pr_debug(" -> addrsize=%d\n", addrsize);
-
- /* Now start the actual "proper" walk of the interrupt tree */
- while (ipar != NULL) {
- /* Now check if cursor is an interrupt-controller and if it is
- * then we are done
- */
- if (of_get_property(ipar, "interrupt-controller", NULL) !=
- NULL) {
- pr_debug(" -> got it !\n");
- memcpy(out_irq->specifier, intspec,
- intsize * sizeof(u32));
- out_irq->size = intsize;
- out_irq->controller = ipar;
- of_node_put(old);
- return 0;
- }
-
- /* Now look for an interrupt-map */
- imap = of_get_property(ipar, "interrupt-map", &imaplen);
- /* No interrupt map, check for an interrupt parent */
- if (imap == NULL) {
- pr_debug(" -> no map, getting parent\n");
- newpar = of_irq_find_parent(ipar);
- goto skiplevel;
- }
- imaplen /= sizeof(u32);
-
- /* Look for a mask */
- imask = of_get_property(ipar, "interrupt-map-mask", NULL);
-
- /* If we were passed no "reg" property and we attempt to parse
- * an interrupt-map, then #address-cells must be 0.
- * Fail if it's not.
- */
- if (addr == NULL && addrsize != 0) {
- pr_debug(" -> no reg passed in when needed !\n");
- goto fail;
- }
-
- /* Parse interrupt-map */
- match = 0;
- while (imaplen > (addrsize + intsize + 1) && !match) {
- /* Compare specifiers */
- match = 1;
- for (i = 0; i < addrsize && match; ++i) {
- u32 mask = imask ? imask[i] : 0xffffffffu;
- match = ((addr[i] ^ imap[i]) & mask) == 0;
- }
- for (; i < (addrsize + intsize) && match; ++i) {
- u32 mask = imask ? imask[i] : 0xffffffffu;
- match =
- ((intspec[i-addrsize] ^ imap[i])
- & mask) == 0;
- }
- imap += addrsize + intsize;
- imaplen -= addrsize + intsize;
-
- pr_debug(" -> match=%d (imaplen=%d)\n", match, imaplen);
-
- /* Get the interrupt parent */
- if (of_irq_workarounds & OF_IMAP_NO_PHANDLE)
- newpar = of_node_get(of_irq_dflt_pic);
- else
- newpar =
- of_find_node_by_phandle((phandle)*imap);
- imap++;
- --imaplen;
-
- /* Check if not found */
- if (newpar == NULL) {
- pr_debug(" -> imap parent not found !\n");
- goto fail;
- }
-
- /* Get #interrupt-cells and #address-cells of new
- * parent
- */
- tmp = of_get_property(newpar, "#interrupt-cells", NULL);
- if (tmp == NULL) {
- pr_debug(" -> parent lacks "
- "#interrupt-cells!\n");
- goto fail;
- }
- newintsize = *tmp;
- tmp = of_get_property(newpar, "#address-cells", NULL);
- newaddrsize = (tmp == NULL) ? 0 : *tmp;
-
- pr_debug(" -> newintsize=%d, newaddrsize=%d\n",
- newintsize, newaddrsize);
-
- /* Check for malformed properties */
- if (imaplen < (newaddrsize + newintsize))
- goto fail;
-
- imap += newaddrsize + newintsize;
- imaplen -= newaddrsize + newintsize;
-
- pr_debug(" -> imaplen=%d\n", imaplen);
- }
- if (!match)
- goto fail;
-
- of_node_put(old);
- old = of_node_get(newpar);
- addrsize = newaddrsize;
- intsize = newintsize;
- intspec = imap - intsize;
- addr = intspec - addrsize;
-
-skiplevel:
- /* Iterate again with new parent */
- pr_debug(" -> new parent: %s\n",
- newpar ? newpar->full_name : "<>");
- of_node_put(ipar);
- ipar = newpar;
- newpar = NULL;
- }
-fail:
- of_node_put(ipar);
- of_node_put(old);
- of_node_put(newpar);
-
- return -EINVAL;
-}
-EXPORT_SYMBOL_GPL(of_irq_map_raw);
-
-int of_irq_map_one(struct device_node *device,
- int index, struct of_irq *out_irq)
-{
- struct device_node *p;
- const u32 *intspec, *tmp, *addr;
- u32 intsize, intlen;
- int res;
-
- pr_debug("of_irq_map_one: dev=%s, index=%d\n",
- device->full_name, index);
-
- /* Get the interrupts property */
- intspec = of_get_property(device, "interrupts", (int *) &intlen);
- if (intspec == NULL)
- return -EINVAL;
- intlen /= sizeof(u32);
-
- pr_debug(" intspec=%d intlen=%d\n", *intspec, intlen);
-
- /* Get the reg property (if any) */
- addr = of_get_property(device, "reg", NULL);
-
- /* Look for the interrupt parent. */
- p = of_irq_find_parent(device);
- if (p == NULL)
- return -EINVAL;
-
- /* Get size of interrupt specifier */
- tmp = of_get_property(p, "#interrupt-cells", NULL);
- if (tmp == NULL) {
- of_node_put(p);
- return -EINVAL;
- }
- intsize = *tmp;
-
- pr_debug(" intsize=%d intlen=%d\n", intsize, intlen);
-
- /* Check index */
- if ((index + 1) * intsize > intlen)
- return -EINVAL;
-
- /* Get new specifier and map it */
- res = of_irq_map_raw(p, intspec + index * intsize, intsize,
- addr, out_irq);
- of_node_put(p);
- return res;
-}
-EXPORT_SYMBOL_GPL(of_irq_map_one);
-
/**
* Search the device tree for the best MAC address to use. 'mac-address' is
* checked first, because that is supposed to contain to "most recent" MAC
@@ -983,43 +148,3 @@ const void *of_get_mac_address(struct device_node *np)
return NULL;
}
EXPORT_SYMBOL(of_get_mac_address);
-
-int of_irq_to_resource(struct device_node *dev, int index, struct resource *r)
-{
- struct of_irq out_irq;
- int irq;
- int res;
-
- res = of_irq_map_one(dev, index, &out_irq);
-
- /* Get irq for the device */
- if (res) {
- pr_debug("IRQ not found... code = %d", res);
- return NO_IRQ;
- }
- /* Assuming single interrupt controller... */
- irq = out_irq.specifier[0];
-
- pr_debug("IRQ found = %d", irq);
-
- /* Only dereference the resource if both the
- * resource and the irq are valid. */
- if (r && irq != NO_IRQ) {
- r->start = r->end = irq;
- r->flags = IORESOURCE_IRQ;
- }
-
- return irq;
-}
-EXPORT_SYMBOL_GPL(of_irq_to_resource);
-
-void __iomem *of_iomap(struct device_node *np, int index)
-{
- struct resource res;
-
- if (of_address_to_resource(np, index, &res))
- return NULL;
-
- return ioremap(res.start, 1 + res.end - res.start);
-}
-EXPORT_SYMBOL(of_iomap);
diff --git a/arch/microblaze/kernel/ptrace.c b/arch/microblaze/kernel/ptrace.c
index a4a7770c614..dc03ffc8174 100644
--- a/arch/microblaze/kernel/ptrace.c
+++ b/arch/microblaze/kernel/ptrace.c
@@ -38,6 +38,8 @@
#include <asm/processor.h>
#include <linux/uaccess.h>
#include <asm/asm-offsets.h>
+#include <asm/cacheflush.h>
+#include <asm/io.h>
/* Returns the address where the register at REG_OFFS in P is stashed away. */
static microblaze_reg_t *reg_save_addr(unsigned reg_offs,
@@ -101,8 +103,21 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
microblaze_reg_t *reg_addr = reg_save_addr(addr, child);
if (request == PTRACE_PEEKUSR)
val = *reg_addr;
- else
+ else {
+#if 1
*reg_addr = data;
+#else
+ /* MS potential problem on WB system
+ * Be aware that reg_addr is virtual address
+ * virt_to_phys conversion is necessary.
+ * This could be sensible solution.
+ */
+ u32 paddr = virt_to_phys((u32)reg_addr);
+ invalidate_icache_range(paddr, paddr + 4);
+ *reg_addr = data;
+ flush_dcache_range(paddr, paddr + 4);
+#endif
+ }
} else
rval = -EIO;
diff --git a/arch/microblaze/kernel/reset.c b/arch/microblaze/kernel/reset.c
index a1721a33042..bd8ccab5cef 100644
--- a/arch/microblaze/kernel/reset.c
+++ b/arch/microblaze/kernel/reset.c
@@ -24,8 +24,8 @@ static int of_reset_gpio_handle(void)
int ret; /* variable which stored handle reset gpio pin */
struct device_node *root; /* root node */
struct device_node *gpio; /* gpio node */
- struct of_gpio_chip *of_gc = NULL;
- enum of_gpio_flags flags ;
+ struct gpio_chip *gc;
+ u32 flags;
const void *gpio_spec;
/* find out root node */
@@ -39,19 +39,19 @@ static int of_reset_gpio_handle(void)
goto err0;
}
- of_gc = gpio->data;
- if (!of_gc) {
+ gc = of_node_to_gpiochip(gpio);
+ if (!gc) {
pr_debug("%s: gpio controller %s isn't registered\n",
root->full_name, gpio->full_name);
ret = -ENODEV;
goto err1;
}
- ret = of_gc->xlate(of_gc, root, gpio_spec, &flags);
+ ret = gc->of_xlate(gc, root, gpio_spec, &flags);
if (ret < 0)
goto err1;
- ret += of_gc->gc.base;
+ ret += gc->base;
err1:
of_node_put(gpio);
err0:
diff --git a/arch/microblaze/kernel/setup.c b/arch/microblaze/kernel/setup.c
index 17c98dbcec8..f5f76884235 100644
--- a/arch/microblaze/kernel/setup.c
+++ b/arch/microblaze/kernel/setup.c
@@ -213,15 +213,9 @@ static struct notifier_block dflt_plat_bus_notifier = {
.priority = INT_MAX,
};
-static struct notifier_block dflt_of_bus_notifier = {
- .notifier_call = dflt_bus_notify,
- .priority = INT_MAX,
-};
-
static int __init setup_bus_notifier(void)
{
bus_register_notifier(&platform_bus_type, &dflt_plat_bus_notifier);
- bus_register_notifier(&of_platform_bus_type, &dflt_of_bus_notifier);
return 0;
}
diff --git a/arch/microblaze/kernel/stacktrace.c b/arch/microblaze/kernel/stacktrace.c
index 123692f2264..84bc6686102 100644
--- a/arch/microblaze/kernel/stacktrace.c
+++ b/arch/microblaze/kernel/stacktrace.c
@@ -14,52 +14,18 @@
#include <linux/thread_info.h>
#include <linux/ptrace.h>
#include <linux/module.h>
+#include <asm/unwind.h>
-/* FIXME initial support */
void save_stack_trace(struct stack_trace *trace)
{
- unsigned long *sp;
- unsigned long addr;
- asm("addik %0, r1, 0" : "=r" (sp));
-
- while (!kstack_end(sp)) {
- addr = *sp++;
- if (__kernel_text_address(addr)) {
- if (trace->skip > 0)
- trace->skip--;
- else
- trace->entries[trace->nr_entries++] = addr;
-
- if (trace->nr_entries >= trace->max_entries)
- break;
- }
- }
+ /* Exclude our helper functions from the trace*/
+ trace->skip += 2;
+ microblaze_unwind(NULL, trace);
}
EXPORT_SYMBOL_GPL(save_stack_trace);
void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace)
{
- unsigned int *sp;
- unsigned long addr;
-
- struct thread_info *ti = task_thread_info(tsk);
-
- if (tsk == current)
- asm("addik %0, r1, 0" : "=r" (sp));
- else
- sp = (unsigned int *)ti->cpu_context.r1;
-
- while (!kstack_end(sp)) {
- addr = *sp++;
- if (__kernel_text_address(addr)) {
- if (trace->skip > 0)
- trace->skip--;
- else
- trace->entries[trace->nr_entries++] = addr;
-
- if (trace->nr_entries >= trace->max_entries)
- break;
- }
- }
+ microblaze_unwind(tsk, trace);
}
EXPORT_SYMBOL_GPL(save_stack_trace_tsk);
diff --git a/arch/microblaze/kernel/timer.c b/arch/microblaze/kernel/timer.c
index ed61b2f1771..b1380ae93ae 100644
--- a/arch/microblaze/kernel/timer.c
+++ b/arch/microblaze/kernel/timer.c
@@ -28,6 +28,7 @@
#include <asm/prom.h>
#include <asm/irq.h>
#include <asm/system.h>
+#include <linux/cnt32_to_63.h>
#ifdef CONFIG_SELFMOD_TIMER
#include <asm/selfmod.h>
@@ -135,7 +136,7 @@ static void microblaze_timer_set_mode(enum clock_event_mode mode,
static struct clock_event_device clockevent_microblaze_timer = {
.name = "microblaze_clockevent",
.features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_PERIODIC,
- .shift = 24,
+ .shift = 8,
.rating = 300,
.set_next_event = microblaze_timer_set_next_event,
.set_mode = microblaze_timer_set_mode,
@@ -195,7 +196,7 @@ static cycle_t microblaze_cc_read(const struct cyclecounter *cc)
static struct cyclecounter microblaze_cc = {
.read = microblaze_cc_read,
.mask = CLOCKSOURCE_MASK(32),
- .shift = 24,
+ .shift = 8,
};
int __init init_microblaze_timecounter(void)
@@ -213,7 +214,7 @@ static struct clocksource clocksource_microblaze = {
.rating = 300,
.read = microblaze_read,
.mask = CLOCKSOURCE_MASK(32),
- .shift = 24, /* I can shift it */
+ .shift = 8, /* I can shift it */
.flags = CLOCK_SOURCE_IS_CONTINUOUS,
};
@@ -235,6 +236,12 @@ static int __init microblaze_clocksource_init(void)
return 0;
}
+/*
+ * We have to protect accesses before timer initialization
+ * and return 0 for sched_clock function below.
+ */
+static int timer_initialized;
+
void __init time_init(void)
{
u32 irq, i = 0;
@@ -289,4 +296,15 @@ void __init time_init(void)
#endif
microblaze_clocksource_init();
microblaze_clockevent_init();
+ timer_initialized = 1;
+}
+
+unsigned long long notrace sched_clock(void)
+{
+ if (timer_initialized) {
+ struct clocksource *cs = &clocksource_microblaze;
+ cycle_t cyc = cnt32_to_63(cs->read(NULL));
+ return clocksource_cyc2ns(cyc, cs->mult, cs->shift);
+ }
+ return 0;
}
diff --git a/arch/microblaze/kernel/traps.c b/arch/microblaze/kernel/traps.c
index 75e49202a5e..ba034d421ec 100644
--- a/arch/microblaze/kernel/traps.c
+++ b/arch/microblaze/kernel/traps.c
@@ -16,13 +16,14 @@
#include <asm/exceptions.h>
#include <asm/system.h>
+#include <asm/unwind.h>
void trap_init(void)
{
__enable_hw_exceptions();
}
-static unsigned long kstack_depth_to_print = 24;
+static unsigned long kstack_depth_to_print; /* 0 == entire stack */
static int __init kstack_setup(char *s)
{
@@ -30,31 +31,47 @@ static int __init kstack_setup(char *s)
}
__setup("kstack=", kstack_setup);
-void show_trace(struct task_struct *task, unsigned long *stack)
+void show_stack(struct task_struct *task, unsigned long *sp)
{
- unsigned long addr;
-
- if (!stack)
- stack = (unsigned long *)&stack;
+ unsigned long words_to_show;
+ u32 fp = (u32) sp;
+
+ if (fp == 0) {
+ if (task) {
+ fp = ((struct thread_info *)
+ (task->stack))->cpu_context.r1;
+ } else {
+ /* Pick up caller of dump_stack() */
+ fp = (u32)&sp - 8;
+ }
+ }
- printk(KERN_NOTICE "Call Trace: ");
-#ifdef CONFIG_KALLSYMS
- printk(KERN_NOTICE "\n");
-#endif
- while (!kstack_end(stack)) {
- addr = *stack++;
- /*
- * If the address is either in the text segment of the
- * kernel, or in the region which contains vmalloc'ed
- * memory, it *may* be the address of a calling
- * routine; if so, print it so that someone tracing
- * down the cause of the crash will be able to figure
- * out the call path that was taken.
- */
- if (kernel_text_address(addr))
- print_ip_sym(addr);
+ words_to_show = (THREAD_SIZE - (fp & (THREAD_SIZE - 1))) >> 2;
+ if (kstack_depth_to_print && (words_to_show > kstack_depth_to_print))
+ words_to_show = kstack_depth_to_print;
+
+ pr_info("Kernel Stack:\n");
+
+ /*
+ * Make the first line an 'odd' size if necessary to get
+ * remaining lines to start at an address multiple of 0x10
+ */
+ if (fp & 0xF) {
+ unsigned long line1_words = (0x10 - (fp & 0xF)) >> 2;
+ if (line1_words < words_to_show) {
+ print_hex_dump(KERN_INFO, "", DUMP_PREFIX_ADDRESS, 32,
+ 4, (void *)fp, line1_words << 2, 0);
+ fp += line1_words << 2;
+ words_to_show -= line1_words;
+ }
}
- printk(KERN_NOTICE "\n");
+ print_hex_dump(KERN_INFO, "", DUMP_PREFIX_ADDRESS, 32, 4, (void *)fp,
+ words_to_show << 2, 0);
+ printk(KERN_INFO "\n\n");
+
+ pr_info("Call Trace:\n");
+ microblaze_unwind(task, NULL);
+ pr_info("\n");
if (!task)
task = current;
@@ -62,34 +79,6 @@ void show_trace(struct task_struct *task, unsigned long *stack)
debug_show_held_locks(task);
}
-void show_stack(struct task_struct *task, unsigned long *sp)
-{
- unsigned long *stack;
- int i;
-
- if (sp == NULL) {
- if (task)
- sp = (unsigned long *) ((struct thread_info *)
- (task->stack))->cpu_context.r1;
- else
- sp = (unsigned long *)&sp;
- }
-
- stack = sp;
-
- printk(KERN_INFO "\nStack:\n ");
-
- for (i = 0; i < kstack_depth_to_print; i++) {
- if (kstack_end(sp))
- break;
- if (i && ((i % 8) == 0))
- printk("\n ");
- printk("%08lx ", *sp++);
- }
- printk("\n");
- show_trace(task, stack);
-}
-
void dump_stack(void)
{
show_stack(NULL, NULL);
diff --git a/arch/microblaze/kernel/unwind.c b/arch/microblaze/kernel/unwind.c
new file mode 100644
index 00000000000..fefac5c3358
--- /dev/null
+++ b/arch/microblaze/kernel/unwind.c
@@ -0,0 +1,318 @@
+/*
+ * Backtrace support for Microblaze
+ *
+ * Copyright (C) 2010 Digital Design Corporation
+ *
+ * Based on arch/sh/kernel/cpu/sh5/unwind.c code which is:
+ * Copyright (C) 2004 Paul Mundt
+ * Copyright (C) 2004 Richard Curnow
+ *
+ * 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.
+ */
+
+/* #define DEBUG 1 */
+#include <linux/kallsyms.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/stacktrace.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/module.h>
+#include <linux/io.h>
+#include <asm/sections.h>
+#include <asm/exceptions.h>
+#include <asm/unwind.h>
+
+struct stack_trace;
+
+/*
+ * On Microblaze, finding the previous stack frame is a little tricky.
+ * At this writing (3/2010), Microblaze does not support CONFIG_FRAME_POINTERS,
+ * and even if it did, gcc (4.1.2) does not store the frame pointer at
+ * a consistent offset within each frame. To determine frame size, it is
+ * necessary to search for the assembly instruction that creates or reclaims
+ * the frame and extract the size from it.
+ *
+ * Microblaze stores the stack pointer in r1, and creates a frame via
+ *
+ * addik r1, r1, -FRAME_SIZE
+ *
+ * The frame is reclaimed via
+ *
+ * addik r1, r1, FRAME_SIZE
+ *
+ * Frame creation occurs at or near the top of a function.
+ * Depending on the compiler, reclaim may occur at the end, or before
+ * a mid-function return.
+ *
+ * A stack frame is usually not created in a leaf function.
+ *
+ */
+
+/**
+ * get_frame_size - Extract the stack adjustment from an
+ * "addik r1, r1, adjust" instruction
+ * @instr : Microblaze instruction
+ *
+ * Return - Number of stack bytes the instruction reserves or reclaims
+ */
+inline long get_frame_size(unsigned long instr)
+{
+ return abs((s16)(instr & 0xFFFF));
+}
+
+/**
+ * find_frame_creation - Search backward to find the instruction that creates
+ * the stack frame (hopefully, for the same function the
+ * initial PC is in).
+ * @pc : Program counter at which to begin the search
+ *
+ * Return - PC at which stack frame creation occurs
+ * NULL if this cannot be found, i.e. a leaf function
+ */
+static unsigned long *find_frame_creation(unsigned long *pc)
+{
+ int i;
+
+ /* NOTE: Distance to search is arbitrary
+ * 250 works well for most things,
+ * 750 picks up things like tcp_recvmsg(),
+ * 1000 needed for fat_fill_super()
+ */
+ for (i = 0; i < 1000; i++, pc--) {
+ unsigned long instr;
+ s16 frame_size;
+
+ if (!kernel_text_address((unsigned long) pc))
+ return NULL;
+
+ instr = *pc;
+
+ /* addik r1, r1, foo ? */
+ if ((instr & 0xFFFF0000) != 0x30210000)
+ continue; /* No */
+
+ frame_size = get_frame_size(instr);
+ if ((frame_size < 8) || (frame_size & 3)) {
+ pr_debug(" Invalid frame size %d at 0x%p\n",
+ frame_size, pc);
+ return NULL;
+ }
+
+ pr_debug(" Found frame creation at 0x%p, size %d\n", pc,
+ frame_size);
+ return pc;
+ }
+
+ return NULL;
+}
+
+/**
+ * lookup_prev_stack_frame - Find the stack frame of the previous function.
+ * @fp : Frame (stack) pointer for current function
+ * @pc : Program counter within current function
+ * @leaf_return : r15 value within current function. If the current function
+ * is a leaf, this is the caller's return address.
+ * @pprev_fp : On exit, set to frame (stack) pointer for previous function
+ * @pprev_pc : On exit, set to current function caller's return address
+ *
+ * Return - 0 on success, -EINVAL if the previous frame cannot be found
+ */
+static int lookup_prev_stack_frame(unsigned long fp, unsigned long pc,
+ unsigned long leaf_return,
+ unsigned long *pprev_fp,
+ unsigned long *pprev_pc)
+{
+ unsigned long *prologue = NULL;
+
+ /* _switch_to is a special leaf function */
+ if (pc != (unsigned long) &_switch_to)
+ prologue = find_frame_creation((unsigned long *)pc);
+
+ if (prologue) {
+ long frame_size = get_frame_size(*prologue);
+
+ *pprev_fp = fp + frame_size;
+ *pprev_pc = *(unsigned long *)fp;
+ } else {
+ if (!leaf_return)
+ return -EINVAL;
+ *pprev_pc = leaf_return;
+ *pprev_fp = fp;
+ }
+
+ /* NOTE: don't check kernel_text_address here, to allow display
+ * of userland return address
+ */
+ return (!*pprev_pc || (*pprev_pc & 3)) ? -EINVAL : 0;
+}
+
+static void microblaze_unwind_inner(struct task_struct *task,
+ unsigned long pc, unsigned long fp,
+ unsigned long leaf_return,
+ struct stack_trace *trace);
+
+/**
+ * unwind_trap - Unwind through a system trap, that stored previous state
+ * on the stack.
+ */
+#ifdef CONFIG_MMU
+static inline void unwind_trap(struct task_struct *task, unsigned long pc,
+ unsigned long fp, struct stack_trace *trace)
+{
+ /* To be implemented */
+}
+#else
+static inline void unwind_trap(struct task_struct *task, unsigned long pc,
+ unsigned long fp, struct stack_trace *trace)
+{
+ const struct pt_regs *regs = (const struct pt_regs *) fp;
+ microblaze_unwind_inner(task, regs->pc, regs->r1, regs->r15, trace);
+}
+#endif
+
+/**
+ * microblaze_unwind_inner - Unwind the stack from the specified point
+ * @task : Task whose stack we are to unwind (may be NULL)
+ * @pc : Program counter from which we start unwinding
+ * @fp : Frame (stack) pointer from which we start unwinding
+ * @leaf_return : Value of r15 at pc. If the function is a leaf, this is
+ * the caller's return address.
+ * @trace : Where to store stack backtrace (PC values).
+ * NULL == print backtrace to kernel log
+ */
+void microblaze_unwind_inner(struct task_struct *task,
+ unsigned long pc, unsigned long fp,
+ unsigned long leaf_return,
+ struct stack_trace *trace)
+{
+ int ofs = 0;
+
+ pr_debug(" Unwinding with PC=%p, FP=%p\n", (void *)pc, (void *)fp);
+ if (!pc || !fp || (pc & 3) || (fp & 3)) {
+ pr_debug(" Invalid state for unwind, aborting\n");
+ return;
+ }
+ for (; pc != 0;) {
+ unsigned long next_fp, next_pc = 0;
+ unsigned long return_to = pc + 2 * sizeof(unsigned long);
+ const struct trap_handler_info *handler =
+ &microblaze_trap_handlers;
+
+ /* Is previous function the HW exception handler? */
+ if ((return_to >= (unsigned long)&_hw_exception_handler)
+ &&(return_to < (unsigned long)&ex_handler_unhandled)) {
+ /*
+ * HW exception handler doesn't save all registers,
+ * so we open-code a special case of unwind_trap()
+ */
+#ifndef CONFIG_MMU
+ const struct pt_regs *regs =
+ (const struct pt_regs *) fp;
+#endif
+ pr_info("HW EXCEPTION\n");
+#ifndef CONFIG_MMU
+ microblaze_unwind_inner(task, regs->r17 - 4,
+ fp + EX_HANDLER_STACK_SIZ,
+ regs->r15, trace);
+#endif
+ return;
+ }
+
+ /* Is previous function a trap handler? */
+ for (; handler->start_addr; ++handler) {
+ if ((return_to >= handler->start_addr)
+ && (return_to <= handler->end_addr)) {
+ if (!trace)
+ pr_info("%s\n", handler->trap_name);
+ unwind_trap(task, pc, fp, trace);
+ return;
+ }
+ }
+ pc -= ofs;
+
+ if (trace) {
+#ifdef CONFIG_STACKTRACE
+ if (trace->skip > 0)
+ trace->skip--;
+ else
+ trace->entries[trace->nr_entries++] = pc;
+
+ if (trace->nr_entries >= trace->max_entries)
+ break;
+#endif
+ } else {
+ /* Have we reached userland? */
+ if (unlikely(pc == task_pt_regs(task)->pc)) {
+ pr_info("[<%p>] PID %lu [%s]\n",
+ (void *) pc,
+ (unsigned long) task->pid,
+ task->comm);
+ break;
+ } else
+ print_ip_sym(pc);
+ }
+
+ /* Stop when we reach anything not part of the kernel */
+ if (!kernel_text_address(pc))
+ break;
+
+ if (lookup_prev_stack_frame(fp, pc, leaf_return, &next_fp,
+ &next_pc) == 0) {
+ ofs = sizeof(unsigned long);
+ pc = next_pc & ~3;
+ fp = next_fp;
+ leaf_return = 0;
+ } else {
+ pr_debug(" Failed to find previous stack frame\n");
+ break;
+ }
+
+ pr_debug(" Next PC=%p, next FP=%p\n",
+ (void *)next_pc, (void *)next_fp);
+ }
+}
+
+/**
+ * microblaze_unwind - Stack unwinder for Microblaze (external entry point)
+ * @task : Task whose stack we are to unwind (NULL == current)
+ * @trace : Where to store stack backtrace (PC values).
+ * NULL == print backtrace to kernel log
+ */
+void microblaze_unwind(struct task_struct *task, struct stack_trace *trace)
+{
+ if (task) {
+ if (task == current) {
+ const struct pt_regs *regs = task_pt_regs(task);
+ microblaze_unwind_inner(task, regs->pc, regs->r1,
+ regs->r15, trace);
+ } else {
+ struct thread_info *thread_info =
+ (struct thread_info *)(task->stack);
+ const struct cpu_context *cpu_context =
+ &thread_info->cpu_context;
+
+ microblaze_unwind_inner(task,
+ (unsigned long) &_switch_to,
+ cpu_context->r1,
+ cpu_context->r15, trace);
+ }
+ } else {
+ unsigned long pc, fp;
+
+ __asm__ __volatile__ ("or %0, r1, r0" : "=r" (fp));
+
+ __asm__ __volatile__ (
+ "brlid %0, 0f;"
+ "nop;"
+ "0:"
+ : "=r" (pc)
+ );
+
+ /* Since we are not a leaf function, use leaf_return = 0 */
+ microblaze_unwind_inner(current, pc, fp, 0, trace);
+ }
+}
+
diff --git a/arch/microblaze/kernel/vmlinux.lds.S b/arch/microblaze/kernel/vmlinux.lds.S
index db72d712460..a09f2962fbe 100644
--- a/arch/microblaze/kernel/vmlinux.lds.S
+++ b/arch/microblaze/kernel/vmlinux.lds.S
@@ -10,7 +10,7 @@
OUTPUT_FORMAT("elf32-microblaze", "elf32-microblaze", "elf32-microblaze")
OUTPUT_ARCH(microblaze)
-ENTRY(_start)
+ENTRY(microblaze_start)
#include <asm/page.h>
#include <asm-generic/vmlinux.lds.h>
@@ -20,7 +20,7 @@ jiffies = jiffies_64 + 4;
SECTIONS {
. = CONFIG_KERNEL_START;
- _start = CONFIG_KERNEL_BASE_ADDR;
+ microblaze_start = CONFIG_KERNEL_BASE_ADDR;
.text : AT(ADDR(.text) - LOAD_OFFSET) {
_text = . ;
_stext = . ;
@@ -55,7 +55,7 @@ SECTIONS {
*/
.sdata2 : AT(ADDR(.sdata2) - LOAD_OFFSET) {
_ssrw = .;
- . = ALIGN(4096); /* page aligned when MMU used - origin 0x8 */
+ . = ALIGN(PAGE_SIZE); /* page aligned when MMU used */
*(.sdata2)
. = ALIGN(8);
_essrw = .;
@@ -70,7 +70,7 @@ SECTIONS {
/* Reserve some low RAM for r0 based memory references */
. = ALIGN(0x4) ;
r0_ram = . ;
- . = . + 4096; /* a page should be enough */
+ . = . + PAGE_SIZE; /* a page should be enough */
/* Under the microblaze ABI, .sdata and .sbss must be contiguous */
. = ALIGN(8);
@@ -120,7 +120,7 @@ SECTIONS {
__init_end_before_initramfs = .;
- .init.ramfs ALIGN(4096) : AT(ADDR(.init.ramfs) - LOAD_OFFSET) {
+ .init.ramfs ALIGN(PAGE_SIZE) : AT(ADDR(.init.ramfs) - LOAD_OFFSET) {
__initramfs_start = .;
*(.init.ramfs)
__initramfs_end = .;
@@ -132,11 +132,11 @@ SECTIONS {
* so that __init_end == __bss_start. This will make image.elf
* consistent with the image.bin
*/
- /* . = ALIGN(4096); */
+ /* . = ALIGN(PAGE_SIZE); */
}
__init_end = .;
- .bss ALIGN (4096) : AT(ADDR(.bss) - LOAD_OFFSET) {
+ .bss ALIGN (PAGE_SIZE) : AT(ADDR(.bss) - LOAD_OFFSET) {
/* page aligned when MMU used */
__bss_start = . ;
*(.bss*)
@@ -145,7 +145,7 @@ SECTIONS {
__bss_stop = . ;
_ebss = . ;
}
- . = ALIGN(4096);
+ . = ALIGN(PAGE_SIZE);
_end = .;
DISCARDS
diff --git a/arch/microblaze/mm/fault.c b/arch/microblaze/mm/fault.c
index bab92299318..57bd2a09610 100644
--- a/arch/microblaze/mm/fault.c
+++ b/arch/microblaze/mm/fault.c
@@ -37,10 +37,6 @@
#include <linux/uaccess.h>
#include <asm/exceptions.h>
-#if defined(CONFIG_KGDB)
-int debugger_kernel_faults = 1;
-#endif
-
static unsigned long pte_misses; /* updated by do_page_fault() */
static unsigned long pte_errors; /* updated by do_page_fault() */
@@ -81,10 +77,6 @@ void bad_page_fault(struct pt_regs *regs, unsigned long address, int sig)
}
/* kernel has accessed a bad area */
-#if defined(CONFIG_KGDB)
- if (debugger_kernel_faults)
- debugger(regs);
-#endif
die("kernel access of bad area", regs, sig);
}
@@ -115,13 +107,6 @@ void do_page_fault(struct pt_regs *regs, unsigned long address,
if ((error_code & 0x13) == 0x13 || (error_code & 0x11) == 0x11)
is_write = 0;
-#if defined(CONFIG_KGDB)
- if (debugger_fault_handler && regs->trap == 0x300) {
- debugger_fault_handler(regs);
- return;
- }
-#endif /* CONFIG_KGDB */
-
if (unlikely(in_atomic() || !mm)) {
if (kernel_mode(regs))
goto bad_area_nosemaphore;
@@ -226,7 +211,6 @@ good_area:
* make sure we exit gracefully rather than endlessly redo
* the fault.
*/
-survive:
fault = handle_mm_fault(mm, vma, address, is_write ? FAULT_FLAG_WRITE : 0);
if (unlikely(fault & VM_FAULT_ERROR)) {
if (fault & VM_FAULT_OOM)
diff --git a/arch/microblaze/mm/init.c b/arch/microblaze/mm/init.c
index db593498992..65eb00419d1 100644
--- a/arch/microblaze/mm/init.c
+++ b/arch/microblaze/mm/init.c
@@ -134,13 +134,8 @@ void __init setup_memory(void)
* for 4GB of memory, using 4kB pages), plus 1 page
* (in case the address isn't page-aligned).
*/
-#ifndef CONFIG_MMU
- map_size = init_bootmem_node(NODE_DATA(0), PFN_UP(TOPHYS((u32)klimit)),
- min_low_pfn, max_low_pfn);
-#else
- map_size = init_bootmem_node(&contig_page_data,
+ map_size = init_bootmem_node(NODE_DATA(0),
PFN_UP(TOPHYS((u32)klimit)), min_low_pfn, max_low_pfn);
-#endif
memblock_reserve(PFN_UP(TOPHYS((u32)klimit)) << PAGE_SHIFT, map_size);
/* free bootmem is whole main memory */
diff --git a/arch/mips/Kbuild b/arch/mips/Kbuild
new file mode 100644
index 00000000000..e322d65f33a
--- /dev/null
+++ b/arch/mips/Kbuild
@@ -0,0 +1,15 @@
+# Fail on warnings - also for files referenced in subdirs
+# -Werror can be disabled for specific files using:
+# CFLAGS_<file.o> := -Wno-error
+subdir-ccflags-y := -Werror
+
+# platform specific definitions
+include arch/mips/Kbuild.platforms
+obj-y := $(platform-y)
+
+# mips object files
+# The object files are linked as core-y files would be linked
+
+obj-y += kernel/
+obj-y += mm/
+obj-y += math-emu/
diff --git a/arch/mips/Kbuild.platforms b/arch/mips/Kbuild.platforms
new file mode 100644
index 00000000000..78439b8a83c
--- /dev/null
+++ b/arch/mips/Kbuild.platforms
@@ -0,0 +1,32 @@
+# All platforms listed in alphabetic order
+
+platforms += alchemy
+platforms += ar7
+platforms += bcm47xx
+platforms += bcm63xx
+platforms += cavium-octeon
+platforms += cobalt
+platforms += dec
+platforms += emma
+platforms += jazz
+platforms += jz4740
+platforms += lasat
+platforms += loongson
+platforms += mipssim
+platforms += mti-malta
+platforms += pmc-sierra
+platforms += pnx833x
+platforms += pnx8550
+platforms += powertv
+platforms += rb532
+platforms += sgi-ip22
+platforms += sgi-ip27
+platforms += sgi-ip32
+platforms += sibyte
+platforms += sni
+platforms += txx9
+platforms += vr41xx
+platforms += wrppmc
+
+# include the platform specific files
+include $(patsubst %, $(srctree)/arch/mips/%/Platform, $(platforms))
diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
index cdaae942623..3ad59dde485 100644
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -10,6 +10,8 @@ config MIPS
select HAVE_DYNAMIC_FTRACE
select HAVE_FTRACE_MCOUNT_RECORD
select HAVE_FUNCTION_GRAPH_TRACER
+ select HAVE_KPROBES
+ select HAVE_KRETPROBES
select RTC_LIB if !MACH_LOONGSON
mainmenu "Linux/MIPS Kernel Configuration"
@@ -23,8 +25,17 @@ choice
prompt "System type"
default SGI_IP22
-config MACH_ALCHEMY
+config MIPS_ALCHEMY
bool "Alchemy processor based machines"
+ select 64BIT_PHYS_ADDR
+ select CEVT_R4K_LIB
+ select CSRC_R4K_LIB
+ select IRQ_CPU
+ select SYS_HAS_CPU_MIPS32_R1
+ select SYS_SUPPORTS_32BIT_KERNEL
+ select SYS_SUPPORTS_APM_EMULATION
+ select GENERIC_GPIO
+ select ARCH_WANT_OPTIONAL_GPIOLIB
select SYS_SUPPORTS_ZBOOT
config AR7
@@ -62,6 +73,7 @@ config BCM47XX
select SSB_DRIVER_MIPS
select SSB_DRIVER_EXTIF
select SSB_EMBEDDED
+ select SSB_B43_PCI_BRIDGE if PCI
select SSB_PCICORE_HOSTMODE if PCI
select GENERIC_GPIO
select SYS_HAS_EARLY_PRINTK
@@ -162,6 +174,18 @@ config MACH_JAZZ
Members include the Acer PICA, MIPS Magnum 4000, MIPS Millennium and
Olivetti M700-10 workstations.
+config MACH_JZ4740
+ bool "Ingenic JZ4740 based machines"
+ select SYS_HAS_CPU_MIPS32_R1
+ select SYS_SUPPORTS_32BIT_KERNEL
+ select SYS_SUPPORTS_LITTLE_ENDIAN
+ select DMA_NONCOHERENT
+ select IRQ_CPU
+ select GENERIC_GPIO
+ select ARCH_REQUIRE_GPIOLIB
+ select SYS_HAS_EARLY_PRINTK
+ select HAVE_PWM
+
config LASAT
bool "LASAT Networks platforms"
select CEVT_R4K
@@ -686,6 +710,7 @@ endchoice
source "arch/mips/alchemy/Kconfig"
source "arch/mips/bcm63xx/Kconfig"
source "arch/mips/jazz/Kconfig"
+source "arch/mips/jz4740/Kconfig"
source "arch/mips/lasat/Kconfig"
source "arch/mips/pmc-sierra/Kconfig"
source "arch/mips/powertv/Kconfig"
@@ -733,10 +758,6 @@ config GENERIC_CLOCKEVENTS
bool
default y
-config GENERIC_TIME
- bool
- default y
-
config GENERIC_CMOS_UPDATE
bool
default y
@@ -892,6 +913,9 @@ config CPU_LITTLE_ENDIAN
endchoice
+config EXPORT_UASM
+ bool
+
config SYS_SUPPORTS_APM_EMULATION
bool
diff --git a/arch/mips/Makefile b/arch/mips/Makefile
index 0b9c01add0a..f4a4b663ebb 100644
--- a/arch/mips/Makefile
+++ b/arch/mips/Makefile
@@ -93,7 +93,8 @@ all-$(CONFIG_SYS_SUPPORTS_ZBOOT)+= vmlinuz
cflags-y += -G 0 -mno-abicalls -fno-pic -pipe
cflags-y += -msoft-float
LDFLAGS_vmlinux += -G 0 -static -n -nostdlib
-MODFLAGS += -mlong-calls
+KBUILD_AFLAGS_MODULE += -mlong-calls
+KBUILD_CFLAGS_MODULE += -mlong-calls
cflags-y += -ffreestanding
@@ -130,26 +131,6 @@ cflags-$(CONFIG_CPU_R4300) += -march=r4300 -Wa,--trap
cflags-$(CONFIG_CPU_VR41XX) += -march=r4100 -Wa,--trap
cflags-$(CONFIG_CPU_R4X00) += -march=r4600 -Wa,--trap
cflags-$(CONFIG_CPU_TX49XX) += -march=r4600 -Wa,--trap
-# only gcc >= 4.4 have the loongson-specific support
-cflags-$(CONFIG_CPU_LOONGSON2) += -Wa,--trap
-cflags-$(CONFIG_CPU_LOONGSON2E) += \
- $(call cc-option,-march=loongson2e,-march=r4600)
-cflags-$(CONFIG_CPU_LOONGSON2F) += \
- $(call cc-option,-march=loongson2f,-march=r4600)
-# enable the workarounds for loongson2f
-ifdef CONFIG_CPU_LOONGSON2F_WORKAROUNDS
- ifeq ($(call as-option,-Wa$(comma)-mfix-loongson2f-nop,),)
- $(error only binutils >= 2.20.2 have needed option -mfix-loongson2f-nop)
- else
- cflags-$(CONFIG_CPU_NOP_WORKAROUNDS) += -Wa$(comma)-mfix-loongson2f-nop
- endif
- ifeq ($(call as-option,-Wa$(comma)-mfix-loongson2f-jump,),)
- $(error only binutils >= 2.20.2 have needed option -mfix-loongson2f-jump)
- else
- cflags-$(CONFIG_CPU_JUMP_WORKAROUNDS) += -Wa$(comma)-mfix-loongson2f-jump
- endif
-endif
-
cflags-$(CONFIG_CPU_MIPS32_R1) += $(call cc-option,-march=mips32,-mips32 -U_MIPS_ISA -D_MIPS_ISA=_MIPS_ISA_MIPS32) \
-Wa,-mips32 -Wa,--trap
cflags-$(CONFIG_CPU_MIPS32_R2) += $(call cc-option,-march=mips32r2,-mips32r2 -U_MIPS_ISA -D_MIPS_ISA=_MIPS_ISA_MIPS32) \
@@ -185,7 +166,8 @@ cflags-$(CONFIG_CPU_DADDI_WORKAROUNDS) += $(call cc-option,-mno-daddi,)
ifdef CONFIG_CPU_SB1
ifdef CONFIG_SB1_PASS_1_WORKAROUNDS
-MODFLAGS += -msb1-pass1-workarounds
+KBUILD_AFLAGS_MODULE += -msb1-pass1-workarounds
+KBUILD_CFLAGS_MODULE += -msb1-pass1-workarounds
endif
endif
@@ -209,455 +191,7 @@ endif
#
# Board-dependent options and extra files
#
-
-#
-# Texas Instruments AR7
-#
-core-$(CONFIG_AR7) += arch/mips/ar7/
-cflags-$(CONFIG_AR7) += -I$(srctree)/arch/mips/include/asm/mach-ar7
-load-$(CONFIG_AR7) += 0xffffffff94100000
-
-#
-# Acer PICA 61, Mips Magnum 4000 and Olivetti M700.
-#
-core-$(CONFIG_MACH_JAZZ) += arch/mips/jazz/
-cflags-$(CONFIG_MACH_JAZZ) += -I$(srctree)/arch/mips/include/asm/mach-jazz
-load-$(CONFIG_MACH_JAZZ) += 0xffffffff80080000
-
-#
-# Common Alchemy Au1x00 stuff
-#
-core-$(CONFIG_SOC_AU1X00) += arch/mips/alchemy/common/
-
-#
-# AMD Alchemy Pb1000 eval board
-#
-core-$(CONFIG_MIPS_PB1000) += arch/mips/alchemy/devboards/
-cflags-$(CONFIG_MIPS_PB1000) += -I$(srctree)/arch/mips/include/asm/mach-pb1x00
-load-$(CONFIG_MIPS_PB1000) += 0xffffffff80100000
-
-#
-# AMD Alchemy Pb1100 eval board
-#
-core-$(CONFIG_MIPS_PB1100) += arch/mips/alchemy/devboards/
-cflags-$(CONFIG_MIPS_PB1100) += -I$(srctree)/arch/mips/include/asm/mach-pb1x00
-load-$(CONFIG_MIPS_PB1100) += 0xffffffff80100000
-
-#
-# AMD Alchemy Pb1500 eval board
-#
-core-$(CONFIG_MIPS_PB1500) += arch/mips/alchemy/devboards/
-cflags-$(CONFIG_MIPS_PB1500) += -I$(srctree)/arch/mips/include/asm/mach-pb1x00
-load-$(CONFIG_MIPS_PB1500) += 0xffffffff80100000
-
-#
-# AMD Alchemy Pb1550 eval board
-#
-core-$(CONFIG_MIPS_PB1550) += arch/mips/alchemy/devboards/
-cflags-$(CONFIG_MIPS_PB1550) += -I$(srctree)/arch/mips/include/asm/mach-pb1x00
-load-$(CONFIG_MIPS_PB1550) += 0xffffffff80100000
-
-#
-# AMD Alchemy Pb1200 eval board
-#
-core-$(CONFIG_MIPS_PB1200) += arch/mips/alchemy/devboards/
-cflags-$(CONFIG_MIPS_PB1200) += -I$(srctree)/arch/mips/include/asm/mach-pb1x00
-load-$(CONFIG_MIPS_PB1200) += 0xffffffff80100000
-
-#
-# AMD Alchemy Db1000 eval board
-#
-core-$(CONFIG_MIPS_DB1000) += arch/mips/alchemy/devboards/
-cflags-$(CONFIG_MIPS_DB1000) += -I$(srctree)/arch/mips/include/asm/mach-db1x00
-load-$(CONFIG_MIPS_DB1000) += 0xffffffff80100000
-
-#
-# AMD Alchemy Db1100 eval board
-#
-core-$(CONFIG_MIPS_DB1100) += arch/mips/alchemy/devboards/
-cflags-$(CONFIG_MIPS_DB1100) += -I$(srctree)/arch/mips/include/asm/mach-db1x00
-load-$(CONFIG_MIPS_DB1100) += 0xffffffff80100000
-
-#
-# AMD Alchemy Db1500 eval board
-#
-core-$(CONFIG_MIPS_DB1500) += arch/mips/alchemy/devboards/
-cflags-$(CONFIG_MIPS_DB1500) += -I$(srctree)/arch/mips/include/asm/mach-db1x00
-load-$(CONFIG_MIPS_DB1500) += 0xffffffff80100000
-
-#
-# AMD Alchemy Db1550 eval board
-#
-core-$(CONFIG_MIPS_DB1550) += arch/mips/alchemy/devboards/
-cflags-$(CONFIG_MIPS_DB1550) += -I$(srctree)/arch/mips/include/asm/mach-db1x00
-load-$(CONFIG_MIPS_DB1550) += 0xffffffff80100000
-
-#
-# AMD Alchemy Db1200 eval board
-#
-core-$(CONFIG_MIPS_DB1200) += arch/mips/alchemy/devboards/
-cflags-$(CONFIG_MIPS_DB1200) += -I$(srctree)/arch/mips/include/asm/mach-db1x00
-load-$(CONFIG_MIPS_DB1200) += 0xffffffff80100000
-
-#
-# AMD Alchemy Bosporus eval board
-#
-core-$(CONFIG_MIPS_BOSPORUS) += arch/mips/alchemy/devboards/
-cflags-$(CONFIG_MIPS_BOSPORUS) += -I$(srctree)/arch/mips/include/asm/mach-db1x00
-load-$(CONFIG_MIPS_BOSPORUS) += 0xffffffff80100000
-
-#
-# AMD Alchemy Mirage eval board
-#
-core-$(CONFIG_MIPS_MIRAGE) += arch/mips/alchemy/devboards/
-cflags-$(CONFIG_MIPS_MIRAGE) += -I$(srctree)/arch/mips/include/asm/mach-db1x00
-load-$(CONFIG_MIPS_MIRAGE) += 0xffffffff80100000
-
-#
-# 4G-Systems eval board
-#
-libs-$(CONFIG_MIPS_MTX1) += arch/mips/alchemy/mtx-1/
-load-$(CONFIG_MIPS_MTX1) += 0xffffffff80100000
-
-#
-# MyCable eval board
-#
-libs-$(CONFIG_MIPS_XXS1500) += arch/mips/alchemy/xxs1500/
-load-$(CONFIG_MIPS_XXS1500) += 0xffffffff80100000
-
-# must be last for Alchemy systems for GPIO to work properly
-cflags-$(CONFIG_SOC_AU1X00) += -I$(srctree)/arch/mips/include/asm/mach-au1x00
-
-
-#
-# Cobalt Server
-#
-core-$(CONFIG_MIPS_COBALT) += arch/mips/cobalt/
-cflags-$(CONFIG_MIPS_COBALT) += -I$(srctree)/arch/mips/include/asm/mach-cobalt
-load-$(CONFIG_MIPS_COBALT) += 0xffffffff80080000
-
-#
-# DECstation family
-#
-core-$(CONFIG_MACH_DECSTATION) += arch/mips/dec/
-cflags-$(CONFIG_MACH_DECSTATION)+= -I$(srctree)/arch/mips/include/asm/mach-dec
-libs-$(CONFIG_MACH_DECSTATION) += arch/mips/dec/prom/
-load-$(CONFIG_MACH_DECSTATION) += 0xffffffff80040000
-
-#
-# Wind River PPMC Board (4KC + GT64120)
-#
-core-$(CONFIG_WR_PPMC) += arch/mips/gt64120/wrppmc/
-cflags-$(CONFIG_WR_PPMC) += -I$(srctree)/arch/mips/include/asm/mach-wrppmc
-load-$(CONFIG_WR_PPMC) += 0xffffffff80100000
-
-#
-# Loongson family
-#
-core-$(CONFIG_MACH_LOONGSON) += arch/mips/loongson/
-cflags-$(CONFIG_MACH_LOONGSON) += -I$(srctree)/arch/mips/include/asm/mach-loongson \
- -mno-branch-likely
-load-$(CONFIG_LEMOTE_FULOONG2E) += 0xffffffff80100000
-load-$(CONFIG_LEMOTE_MACH2F) += 0xffffffff80200000
-
-#
-# MIPS Malta board
-#
-core-$(CONFIG_MIPS_MALTA) += arch/mips/mti-malta/
-cflags-$(CONFIG_MIPS_MALTA) += -I$(srctree)/arch/mips/include/asm/mach-malta
-load-$(CONFIG_MIPS_MALTA) += 0xffffffff80100000
-all-$(CONFIG_MIPS_MALTA) := $(COMPRESSION_FNAME).bin
-
-#
-# MIPS SIM
-#
-core-$(CONFIG_MIPS_SIM) += arch/mips/mipssim/
-cflags-$(CONFIG_MIPS_SIM) += -I$(srctree)/arch/mips/include/asm/mach-mipssim
-load-$(CONFIG_MIPS_SIM) += 0x80100000
-
-#
-# PMC-Sierra MSP SOCs
-#
-core-$(CONFIG_PMC_MSP) += arch/mips/pmc-sierra/msp71xx/
-cflags-$(CONFIG_PMC_MSP) += -I$(srctree)/arch/mips/include/asm/pmc-sierra/msp71xx \
- -mno-branch-likely
-load-$(CONFIG_PMC_MSP) += 0xffffffff80100000
-
-#
-# PMC-Sierra Yosemite
-#
-core-$(CONFIG_PMC_YOSEMITE) += arch/mips/pmc-sierra/yosemite/
-cflags-$(CONFIG_PMC_YOSEMITE) += -I$(srctree)/arch/mips/include/asm/mach-yosemite
-load-$(CONFIG_PMC_YOSEMITE) += 0xffffffff80100000
-
-#
-# LASAT platforms
-#
-core-$(CONFIG_LASAT) += arch/mips/lasat/
-cflags-$(CONFIG_LASAT) += -I$(srctree)/arch/mips/include/asm/mach-lasat
-load-$(CONFIG_LASAT) += 0xffffffff80000000
-
-#
-# Common VR41xx
-#
-core-$(CONFIG_MACH_VR41XX) += arch/mips/vr41xx/common/
-cflags-$(CONFIG_MACH_VR41XX) += -I$(srctree)/arch/mips/include/asm/mach-vr41xx
-
-#
-# ZAO Networks Capcella (VR4131)
-#
-load-$(CONFIG_ZAO_CAPCELLA) += 0xffffffff80000000
-
-#
-# Victor MP-C303/304 (VR4122)
-#
-load-$(CONFIG_VICTOR_MPC30X) += 0xffffffff80001000
-
-#
-# IBM WorkPad z50 (VR4121)
-#
-core-$(CONFIG_IBM_WORKPAD) += arch/mips/vr41xx/ibm-workpad/
-load-$(CONFIG_IBM_WORKPAD) += 0xffffffff80004000
-
-#
-# CASIO CASSIPEIA E-55/65 (VR4111)
-#
-core-$(CONFIG_CASIO_E55) += arch/mips/vr41xx/casio-e55/
-load-$(CONFIG_CASIO_E55) += 0xffffffff80004000
-
-#
-# TANBAC VR4131 multichip module(TB0225) and TANBAC VR4131DIMM(TB0229) (VR4131)
-#
-load-$(CONFIG_TANBAC_TB022X) += 0xffffffff80000000
-
-# NXP STB225
-core-$(CONFIG_SOC_PNX833X) += arch/mips/nxp/pnx833x/common/
-cflags-$(CONFIG_SOC_PNX833X) += -Iarch/mips/include/asm/mach-pnx833x
-libs-$(CONFIG_NXP_STB220) += arch/mips/nxp/pnx833x/stb22x/
-load-$(CONFIG_NXP_STB220) += 0xffffffff80001000
-libs-$(CONFIG_NXP_STB225) += arch/mips/nxp/pnx833x/stb22x/
-load-$(CONFIG_NXP_STB225) += 0xffffffff80001000
-
-#
-# Common NXP PNX8550
-#
-core-$(CONFIG_SOC_PNX8550) += arch/mips/nxp/pnx8550/common/
-cflags-$(CONFIG_SOC_PNX8550) += -I$(srctree)/arch/mips/include/asm/mach-pnx8550
-
-#
-# NXP PNX8550 JBS board
-#
-libs-$(CONFIG_PNX8550_JBS) += arch/mips/nxp/pnx8550/jbs/
-#cflags-$(CONFIG_PNX8550_JBS) += -I$(srctree)/arch/mips/include/asm/mach-pnx8550
-load-$(CONFIG_PNX8550_JBS) += 0xffffffff80060000
-
-# NXP PNX8550 STB810 board
-#
-libs-$(CONFIG_PNX8550_STB810) += arch/mips/nxp/pnx8550/stb810/
-load-$(CONFIG_PNX8550_STB810) += 0xffffffff80060000
-
-#
-# Common NEC EMMAXXX
-#
-core-$(CONFIG_SOC_EMMA2RH) += arch/mips/emma/common/
-cflags-$(CONFIG_SOC_EMMA2RH) += -I$(srctree)/arch/mips/include/asm/mach-emma2rh
-
-#
-# NEC EMMA2RH Mark-eins
-#
-core-$(CONFIG_NEC_MARKEINS) += arch/mips/emma/markeins/
-load-$(CONFIG_NEC_MARKEINS) += 0xffffffff88100000
-
-#
-# Cisco PowerTV Platform
-#
-core-$(CONFIG_POWERTV) += arch/mips/powertv/
-cflags-$(CONFIG_POWERTV) += -I$(srctree)/arch/mips/include/asm/mach-powertv
-load-$(CONFIG_POWERTV) += 0xffffffff90800000
-
-#
-# SGI IP22 (Indy/Indigo2)
-#
-# Set the load address to >= 0xffffffff88069000 if you want to leave space for
-# symmon, 0xffffffff80002000 for production kernels. Note that the value must
-# be aligned to a multiple of the kernel stack size or the handling of the
-# current variable will break so for 64-bit kernels we have to raise the start
-# address by 8kb.
-#
-core-$(CONFIG_SGI_IP22) += arch/mips/sgi-ip22/
-cflags-$(CONFIG_SGI_IP22) += -I$(srctree)/arch/mips/include/asm/mach-ip22
-ifdef CONFIG_32BIT
-load-$(CONFIG_SGI_IP22) += 0xffffffff88002000
-endif
-ifdef CONFIG_64BIT
-load-$(CONFIG_SGI_IP22) += 0xffffffff88004000
-endif
-
-#
-# SGI-IP27 (Origin200/2000)
-#
-# Set the load address to >= 0xc000000000300000 if you want to leave space for
-# symmon, 0xc00000000001c000 for production kernels. Note that the value must
-# be 16kb aligned or the handling of the current variable will break.
-#
-ifdef CONFIG_SGI_IP27
-core-$(CONFIG_SGI_IP27) += arch/mips/sgi-ip27/
-cflags-$(CONFIG_SGI_IP27) += -I$(srctree)/arch/mips/include/asm/mach-ip27
-ifdef CONFIG_MAPPED_KERNEL
-load-$(CONFIG_SGI_IP27) += 0xc00000004001c000
-OBJCOPYFLAGS := --change-addresses=0x3fffffff80000000
-dataoffset-$(CONFIG_SGI_IP27) += 0x01000000
-else
-load-$(CONFIG_SGI_IP27) += 0xa80000000001c000
-OBJCOPYFLAGS := --change-addresses=0x57ffffff80000000
-endif
-endif
-
-#
-# SGI IP28 (Indigo2 R10k)
-#
-# Set the load address to >= 0xa800000020080000 if you want to leave space for
-# symmon, 0xa800000020004000 for production kernels ? Note that the value must
-# be 16kb aligned or the handling of the current variable will break.
-# Simplified: what IP22 does at 128MB+ in ksegN, IP28 does at 512MB+ in xkphys
-#
-ifdef CONFIG_SGI_IP28
- ifeq ($(call cc-option-yn,-mr10k-cache-barrier=store), n)
- $(error gcc doesn't support needed option -mr10k-cache-barrier=store)
- endif
-endif
-core-$(CONFIG_SGI_IP28) += arch/mips/sgi-ip22/
-cflags-$(CONFIG_SGI_IP28) += -mr10k-cache-barrier=store -I$(srctree)/arch/mips/include/asm/mach-ip28
-load-$(CONFIG_SGI_IP28) += 0xa800000020004000
-
-#
-# SGI-IP32 (O2)
-#
-# Set the load address to >= 80069000 if you want to leave space for symmon,
-# 0xffffffff80004000 for production kernels. Note that the value must be aligned to
-# a multiple of the kernel stack size or the handling of the current variable
-# will break.
-#
-core-$(CONFIG_SGI_IP32) += arch/mips/sgi-ip32/
-cflags-$(CONFIG_SGI_IP32) += -I$(srctree)/arch/mips/include/asm/mach-ip32
-load-$(CONFIG_SGI_IP32) += 0xffffffff80004000
-
-#
-# Sibyte SB1250/BCM1480 SOC
-#
-# This is a LIB so that it links at the end, and initcalls are later
-# the sequence; but it is built as an object so that modules don't get
-# removed (as happens, even if they have __initcall/module_init)
-#
-core-$(CONFIG_SIBYTE_BCM112X) += arch/mips/sibyte/sb1250/
-core-$(CONFIG_SIBYTE_BCM112X) += arch/mips/sibyte/common/
-cflags-$(CONFIG_SIBYTE_BCM112X) += -I$(srctree)/arch/mips/include/asm/mach-sibyte \
- -DSIBYTE_HDR_FEATURES=SIBYTE_HDR_FMASK_1250_112x_ALL
-
-core-$(CONFIG_SIBYTE_SB1250) += arch/mips/sibyte/sb1250/
-core-$(CONFIG_SIBYTE_SB1250) += arch/mips/sibyte/common/
-cflags-$(CONFIG_SIBYTE_SB1250) += -I$(srctree)/arch/mips/include/asm/mach-sibyte \
- -DSIBYTE_HDR_FEATURES=SIBYTE_HDR_FMASK_1250_112x_ALL
-
-core-$(CONFIG_SIBYTE_BCM1x55) += arch/mips/sibyte/bcm1480/
-core-$(CONFIG_SIBYTE_BCM1x55) += arch/mips/sibyte/common/
-cflags-$(CONFIG_SIBYTE_BCM1x55) += -I$(srctree)/arch/mips/include/asm/mach-sibyte \
- -DSIBYTE_HDR_FEATURES=SIBYTE_HDR_FMASK_1480_ALL
-
-core-$(CONFIG_SIBYTE_BCM1x80) += arch/mips/sibyte/bcm1480/
-core-$(CONFIG_SIBYTE_BCM1x80) += arch/mips/sibyte/common/
-cflags-$(CONFIG_SIBYTE_BCM1x80) += -I$(srctree)/arch/mips/include/asm/mach-sibyte \
- -DSIBYTE_HDR_FEATURES=SIBYTE_HDR_FMASK_1480_ALL
-
-#
-# Sibyte BCM91120x (Carmel) board
-# Sibyte BCM91120C (CRhine) board
-# Sibyte BCM91125C (CRhone) board
-# Sibyte BCM91125E (Rhone) board
-# Sibyte SWARM board
-# Sibyte BCM91x80 (BigSur) board
-#
-core-$(CONFIG_SIBYTE_CARMEL) += arch/mips/sibyte/swarm/
-load-$(CONFIG_SIBYTE_CARMEL) := 0xffffffff80100000
-core-$(CONFIG_SIBYTE_CRHINE) += arch/mips/sibyte/swarm/
-load-$(CONFIG_SIBYTE_CRHINE) := 0xffffffff80100000
-core-$(CONFIG_SIBYTE_CRHONE) += arch/mips/sibyte/swarm/
-load-$(CONFIG_SIBYTE_CRHONE) := 0xffffffff80100000
-core-$(CONFIG_SIBYTE_RHONE) += arch/mips/sibyte/swarm/
-load-$(CONFIG_SIBYTE_RHONE) := 0xffffffff80100000
-core-$(CONFIG_SIBYTE_SENTOSA) += arch/mips/sibyte/swarm/
-load-$(CONFIG_SIBYTE_SENTOSA) := 0xffffffff80100000
-core-$(CONFIG_SIBYTE_SWARM) += arch/mips/sibyte/swarm/
-load-$(CONFIG_SIBYTE_SWARM) := 0xffffffff80100000
-core-$(CONFIG_SIBYTE_BIGSUR) += arch/mips/sibyte/swarm/
-load-$(CONFIG_SIBYTE_BIGSUR) := 0xffffffff80100000
-
-#
-# Broadcom BCM47XX boards
-#
-core-$(CONFIG_BCM47XX) += arch/mips/bcm47xx/
-cflags-$(CONFIG_BCM47XX) += -I$(srctree)/arch/mips/include/asm/mach-bcm47xx
-load-$(CONFIG_BCM47XX) := 0xffffffff80001000
-
-#
-# Broadcom BCM63XX boards
-#
-core-$(CONFIG_BCM63XX) += arch/mips/bcm63xx/
-cflags-$(CONFIG_BCM63XX) += -I$(srctree)/arch/mips/include/asm/mach-bcm63xx/
-load-$(CONFIG_BCM63XX) := 0xffffffff80010000
-
-#
-# SNI RM
-#
-core-$(CONFIG_SNI_RM) += arch/mips/sni/
-cflags-$(CONFIG_SNI_RM) += -I$(srctree)/arch/mips/include/asm/mach-rm
-ifdef CONFIG_CPU_LITTLE_ENDIAN
-load-$(CONFIG_SNI_RM) += 0xffffffff80600000
-else
-load-$(CONFIG_SNI_RM) += 0xffffffff80030000
-endif
-all-$(CONFIG_SNI_RM) := $(COMPRESSION_FNAME).ecoff
-
-#
-# Common TXx9
-#
-core-$(CONFIG_MACH_TX39XX) += arch/mips/txx9/generic/
-cflags-$(CONFIG_MACH_TX39XX) += -I$(srctree)/arch/mips/include/asm/mach-tx39xx
-load-$(CONFIG_MACH_TX39XX) += 0xffffffff80050000
-core-$(CONFIG_MACH_TX49XX) += arch/mips/txx9/generic/
-cflags-$(CONFIG_MACH_TX49XX) += -I$(srctree)/arch/mips/include/asm/mach-tx49xx
-load-$(CONFIG_MACH_TX49XX) += 0xffffffff80100000
-
-#
-# Toshiba JMR-TX3927 board
-#
-core-$(CONFIG_TOSHIBA_JMR3927) += arch/mips/txx9/jmr3927/
-
-#
-# Routerboard 532 board
-#
-core-$(CONFIG_MIKROTIK_RB532) += arch/mips/rb532/
-cflags-$(CONFIG_MIKROTIK_RB532) += -I$(srctree)/arch/mips/include/asm/mach-rc32434
-load-$(CONFIG_MIKROTIK_RB532) += 0xffffffff80101000
-
-#
-# Toshiba RBTX49XX boards
-#
-core-$(CONFIG_TOSHIBA_RBTX4927) += arch/mips/txx9/rbtx4927/
-core-$(CONFIG_TOSHIBA_RBTX4938) += arch/mips/txx9/rbtx4938/
-core-$(CONFIG_TOSHIBA_RBTX4939) += arch/mips/txx9/rbtx4939/
-
-#
-# Cavium Octeon
-#
-core-$(CONFIG_CPU_CAVIUM_OCTEON) += arch/mips/cavium-octeon/
-cflags-$(CONFIG_CPU_CAVIUM_OCTEON) += -I$(srctree)/arch/mips/include/asm/mach-cavium-octeon
-core-$(CONFIG_CPU_CAVIUM_OCTEON) += arch/mips/cavium-octeon/executive/
-ifdef CONFIG_CAVIUM_OCTEON_2ND_KERNEL
-load-$(CONFIG_CPU_CAVIUM_OCTEON) += 0xffffffff84100000
-else
-load-$(CONFIG_CPU_CAVIUM_OCTEON) += 0xffffffff81100000
-endif
+include $(srctree)/arch/mips/Kbuild.platforms
cflags-y += -I$(srctree)/arch/mips/include/asm/mach-generic
drivers-$(CONFIG_PCI) += arch/mips/pci/
@@ -706,7 +240,8 @@ head-y := arch/mips/kernel/head.o arch/mips/kernel/init_task.o
libs-y += arch/mips/lib/
-core-y += arch/mips/kernel/ arch/mips/mm/ arch/mips/math-emu/
+# See arch/mips/Kbuild for content of core part of the kernel
+core-y += arch/mips/
drivers-$(CONFIG_OPROFILE) += arch/mips/oprofile/
@@ -726,6 +261,9 @@ endif
vmlinux.32: vmlinux
$(OBJCOPY) -O $(32bit-bfd) $(OBJCOPYFLAGS) $< $@
+
+#obj-$(CONFIG_KPROBES) += kprobes.o
+
#
# The 64-bit ELF tools are pretty broken so at this time we generate 64-bit
# ELF files from 32-bit files by conversion.
@@ -733,35 +271,19 @@ vmlinux.32: vmlinux
vmlinux.64: vmlinux
$(OBJCOPY) -O $(64bit-bfd) $(OBJCOPYFLAGS) $< $@
-makeboot =$(Q)$(MAKE) $(build)=arch/mips/boot VMLINUX=$(vmlinux-32) $(1)
-makezboot =$(Q)$(MAKE) $(build)=arch/mips/boot/compressed \
- VMLINUX_LOAD_ADDRESS=$(load-y) 32bit-bfd=$(32bit-bfd) $(1)
-
all: $(all-y)
-vmlinuz: vmlinux FORCE
- +@$(call makezboot,$@)
+# boot
+vmlinux.bin vmlinux.ecoff vmlinux.srec: $(vmlinux-32) FORCE
+ $(Q)$(MAKE) $(build)=arch/mips/boot VMLINUX=$(vmlinux-32) arch/mips/boot/$@
-vmlinuz.bin: vmlinux
- +@$(call makezboot,$@)
+# boot/compressed
+vmlinuz vmlinuz.bin vmlinuz.ecoff vmlinuz.srec: $(vmlinux-32) FORCE
+ $(Q)$(MAKE) $(build)=arch/mips/boot/compressed \
+ VMLINUX_LOAD_ADDRESS=$(load-y) 32bit-bfd=$(32bit-bfd) $@
-vmlinuz.ecoff: vmlinux
- +@$(call makezboot,$@)
-vmlinuz.srec: vmlinux
- +@$(call makezboot,$@)
-
-vmlinux.bin: $(vmlinux-32)
- +@$(call makeboot,$@)
-
-vmlinux.ecoff: $(vmlinux-32)
- +@$(call makeboot,$@)
-
-vmlinux.srec: $(vmlinux-32)
- +@$(call makeboot,$@)
-
-CLEAN_FILES += vmlinux.ecoff \
- vmlinux.srec
+CLEAN_FILES += vmlinux.32 vmlinux.64
archprepare:
ifdef CONFIG_MIPS32_N32
@@ -780,9 +302,9 @@ install:
$(Q)install -D -m 644 System.map $(INSTALL_PATH)/System.map-$(KERNELRELEASE)
archclean:
- @$(MAKE) $(clean)=arch/mips/boot
- @$(MAKE) $(clean)=arch/mips/boot/compressed
- @$(MAKE) $(clean)=arch/mips/lasat
+ $(Q)$(MAKE) $(clean)=arch/mips/boot
+ $(Q)$(MAKE) $(clean)=arch/mips/boot/compressed
+ $(Q)$(MAKE) $(clean)=arch/mips/lasat
define archhelp
echo ' install - install kernel into $(INSTALL_PATH)'
@@ -796,11 +318,3 @@ define archhelp
echo
echo ' These will be default as apropriate for a configured platform.'
endef
-
-CLEAN_FILES += vmlinux.32 \
- vmlinux.64 \
- vmlinux.ecoff \
- vmlinuz \
- vmlinuz.ecoff \
- vmlinuz.bin \
- vmlinuz.srec
diff --git a/arch/mips/alchemy/Kconfig b/arch/mips/alchemy/Kconfig
index df3b1a7eb15..2ccfd4a135b 100644
--- a/arch/mips/alchemy/Kconfig
+++ b/arch/mips/alchemy/Kconfig
@@ -11,7 +11,7 @@ config ALCHEMY_GPIO_INDIRECT
choice
prompt "Machine type"
- depends on MACH_ALCHEMY
+ depends on MIPS_ALCHEMY
default MIPS_DB1000
config MIPS_MTX1
@@ -128,41 +128,33 @@ config MIPS_XXS1500
select SYS_SUPPORTS_LITTLE_ENDIAN
select SYS_HAS_EARLY_PRINTK
+config MIPS_GPR
+ bool "Trapeze ITS GPR board"
+ select SOC_AU1550
+ select HW_HAS_PCI
+ select DMA_NONCOHERENT
+ select MIPS_DISABLE_OBSOLETE_IDE
+ select SYS_SUPPORTS_LITTLE_ENDIAN
+ select SYS_HAS_EARLY_PRINTK
+
endchoice
config SOC_AU1000
bool
- select SOC_AU1X00
select ALCHEMY_GPIOINT_AU1000
config SOC_AU1100
bool
- select SOC_AU1X00
select ALCHEMY_GPIOINT_AU1000
config SOC_AU1500
bool
- select SOC_AU1X00
select ALCHEMY_GPIOINT_AU1000
config SOC_AU1550
bool
- select SOC_AU1X00
select ALCHEMY_GPIOINT_AU1000
config SOC_AU1200
bool
- select SOC_AU1X00
select ALCHEMY_GPIOINT_AU1000
-
-config SOC_AU1X00
- bool
- select 64BIT_PHYS_ADDR
- select CEVT_R4K_LIB
- select CSRC_R4K_LIB
- select IRQ_CPU
- select SYS_HAS_CPU_MIPS32_R1
- select SYS_SUPPORTS_32BIT_KERNEL
- select SYS_SUPPORTS_APM_EMULATION
- select GENERIC_GPIO
- select ARCH_WANT_OPTIONAL_GPIOLIB
diff --git a/arch/mips/alchemy/Platform b/arch/mips/alchemy/Platform
new file mode 100644
index 00000000000..96e9e41f1b2
--- /dev/null
+++ b/arch/mips/alchemy/Platform
@@ -0,0 +1,114 @@
+#
+# Core Alchemy code
+#
+platform-$(CONFIG_MIPS_ALCHEMY) += alchemy/common/
+
+
+#
+# AMD Alchemy Pb1000 eval board
+#
+platform-$(CONFIG_MIPS_PB1000) += alchemy/devboards/
+cflags-$(CONFIG_MIPS_PB1000) += -I$(srctree)/arch/mips/include/asm/mach-pb1x00
+load-$(CONFIG_MIPS_PB1000) += 0xffffffff80100000
+
+#
+# AMD Alchemy Pb1100 eval board
+#
+platform-$(CONFIG_MIPS_PB1100) += alchemy/devboards/
+cflags-$(CONFIG_MIPS_PB1100) += -I$(srctree)/arch/mips/include/asm/mach-pb1x00
+load-$(CONFIG_MIPS_PB1100) += 0xffffffff80100000
+
+#
+# AMD Alchemy Pb1500 eval board
+#
+platform-$(CONFIG_MIPS_PB1500) += alchemy/devboards/
+cflags-$(CONFIG_MIPS_PB1500) += -I$(srctree)/arch/mips/include/asm/mach-pb1x00
+load-$(CONFIG_MIPS_PB1500) += 0xffffffff80100000
+
+#
+# AMD Alchemy Pb1550 eval board
+#
+platform-$(CONFIG_MIPS_PB1550) += alchemy/devboards/
+cflags-$(CONFIG_MIPS_PB1550) += -I$(srctree)/arch/mips/include/asm/mach-pb1x00
+load-$(CONFIG_MIPS_PB1550) += 0xffffffff80100000
+
+#
+# AMD Alchemy Pb1200 eval board
+#
+platform-$(CONFIG_MIPS_PB1200) += alchemy/devboards/
+cflags-$(CONFIG_MIPS_PB1200) += -I$(srctree)/arch/mips/include/asm/mach-pb1x00
+load-$(CONFIG_MIPS_PB1200) += 0xffffffff80100000
+
+#
+# AMD Alchemy Db1000 eval board
+#
+platform-$(CONFIG_MIPS_DB1000) += alchemy/devboards/
+cflags-$(CONFIG_MIPS_DB1000) += -I$(srctree)/arch/mips/include/asm/mach-db1x00
+load-$(CONFIG_MIPS_DB1000) += 0xffffffff80100000
+
+#
+# AMD Alchemy Db1100 eval board
+#
+platform-$(CONFIG_MIPS_DB1100) += alchemy/devboards/
+cflags-$(CONFIG_MIPS_DB1100) += -I$(srctree)/arch/mips/include/asm/mach-db1x00
+load-$(CONFIG_MIPS_DB1100) += 0xffffffff80100000
+
+#
+# AMD Alchemy Db1500 eval board
+#
+platform-$(CONFIG_MIPS_DB1500) += alchemy/devboards/
+cflags-$(CONFIG_MIPS_DB1500) += -I$(srctree)/arch/mips/include/asm/mach-db1x00
+load-$(CONFIG_MIPS_DB1500) += 0xffffffff80100000
+
+#
+# AMD Alchemy Db1550 eval board
+#
+platform-$(CONFIG_MIPS_DB1550) += alchemy/devboards/
+cflags-$(CONFIG_MIPS_DB1550) += -I$(srctree)/arch/mips/include/asm/mach-db1x00
+load-$(CONFIG_MIPS_DB1550) += 0xffffffff80100000
+
+#
+# AMD Alchemy Db1200 eval board
+#
+platform-$(CONFIG_MIPS_DB1200) += alchemy/devboards/
+cflags-$(CONFIG_MIPS_DB1200) += -I$(srctree)/arch/mips/include/asm/mach-db1x00
+load-$(CONFIG_MIPS_DB1200) += 0xffffffff80100000
+
+#
+# AMD Alchemy Bosporus eval board
+#
+platform-$(CONFIG_MIPS_BOSPORUS) += alchemy/devboards/
+cflags-$(CONFIG_MIPS_BOSPORUS) += -I$(srctree)/arch/mips/include/asm/mach-db1x00
+load-$(CONFIG_MIPS_BOSPORUS) += 0xffffffff80100000
+
+#
+# AMD Alchemy Mirage eval board
+#
+platform-$(CONFIG_MIPS_MIRAGE) += alchemy/devboards/
+cflags-$(CONFIG_MIPS_MIRAGE) += -I$(srctree)/arch/mips/include/asm/mach-db1x00
+load-$(CONFIG_MIPS_MIRAGE) += 0xffffffff80100000
+
+#
+# 4G-Systems eval board
+#
+platform-$(CONFIG_MIPS_MTX1) += alchemy/mtx-1/
+load-$(CONFIG_MIPS_MTX1) += 0xffffffff80100000
+
+#
+# MyCable eval board
+#
+platform-$(CONFIG_MIPS_XXS1500) += alchemy/xxs1500/
+load-$(CONFIG_MIPS_XXS1500) += 0xffffffff80100000
+
+#
+# Trapeze ITS GRP board
+#
+platform-$(CONFIG_MIPS_GPR) += alchemy/gpr/
+load-$(CONFIG_MIPS_GPR) += 0xffffffff80100000
+
+# boards can specify their own <gpio.h> in one of their include dirs.
+# If they do, placing this line here at the end will make sure the
+# compiler picks the board one. If they don't, it will make sure
+# the alchemy generic gpio header is picked up.
+
+cflags-$(CONFIG_MIPS_ALCHEMY) += -I$(srctree)/arch/mips/include/asm/mach-au1x00
diff --git a/arch/mips/alchemy/common/Makefile b/arch/mips/alchemy/common/Makefile
index 06c0e65a54b..27811fe341d 100644
--- a/arch/mips/alchemy/common/Makefile
+++ b/arch/mips/alchemy/common/Makefile
@@ -18,5 +18,3 @@ ifeq ($(CONFIG_ALCHEMY_GPIO_INDIRECT),)
endif
obj-$(CONFIG_PCI) += pci.o
-
-EXTRA_CFLAGS += -Werror
diff --git a/arch/mips/alchemy/common/clocks.c b/arch/mips/alchemy/common/clocks.c
index 460c6285c1b..af0fe41055a 100644
--- a/arch/mips/alchemy/common/clocks.c
+++ b/arch/mips/alchemy/common/clocks.c
@@ -89,11 +89,7 @@ unsigned long au1xxx_calc_clock(void)
* over backwards trying to determine the frequency.
*/
if (au1xxx_cpu_has_pll_wo())
-#ifdef CONFIG_SOC_AU1000_FREQUENCY
- cpu_speed = CONFIG_SOC_AU1000_FREQUENCY;
-#else
cpu_speed = 396000000;
-#endif
else
cpu_speed = (au_readl(SYS_CPUPLL) & 0x0000003f) * AU1000_SRC_CLK;
diff --git a/arch/mips/alchemy/common/platform.c b/arch/mips/alchemy/common/platform.c
index f9e5622ebc9..1dc55ee2681 100644
--- a/arch/mips/alchemy/common/platform.c
+++ b/arch/mips/alchemy/common/platform.c
@@ -12,6 +12,7 @@
*/
#include <linux/dma-mapping.h>
+#include <linux/etherdevice.h>
#include <linux/platform_device.h>
#include <linux/serial_8250.h>
#include <linux/init.h>
@@ -21,6 +22,8 @@
#include <asm/mach-au1x00/au1100_mmc.h>
#include <asm/mach-au1x00/au1xxx_eth.h>
+#include <prom.h>
+
#define PORT(_base, _irq) \
{ \
.mapbase = _base, \
@@ -33,7 +36,6 @@
}
static struct plat_serial8250_port au1x00_uart_data[] = {
-#if defined(CONFIG_SERIAL_8250_AU1X00)
#if defined(CONFIG_SOC_AU1000)
PORT(UART0_PHYS_ADDR, AU1000_UART0_INT),
PORT(UART1_PHYS_ADDR, AU1000_UART1_INT),
@@ -54,7 +56,6 @@ static struct plat_serial8250_port au1x00_uart_data[] = {
PORT(UART0_PHYS_ADDR, AU1200_UART0_INT),
PORT(UART1_PHYS_ADDR, AU1200_UART1_INT),
#endif
-#endif /* CONFIG_SERIAL_8250_AU1X00 */
{ },
};
@@ -436,17 +437,27 @@ static int __init au1xxx_platform_init(void)
{
unsigned int uartclk = get_au1x00_uart_baud_base() * 16;
int err, i;
+ unsigned char ethaddr[6];
/* Fill up uartclk. */
for (i = 0; au1x00_uart_data[i].flags; i++)
au1x00_uart_data[i].uartclk = uartclk;
+ /* use firmware-provided mac addr if available and necessary */
+ i = prom_get_ethernet_addr(ethaddr);
+ if (!i && !is_valid_ether_addr(au1xxx_eth0_platform_data.mac))
+ memcpy(au1xxx_eth0_platform_data.mac, ethaddr, 6);
+
err = platform_add_devices(au1xxx_platform_devices,
ARRAY_SIZE(au1xxx_platform_devices));
#ifndef CONFIG_SOC_AU1100
+ ethaddr[5] += 1; /* next addr for 2nd MAC */
+ if (!i && !is_valid_ether_addr(au1xxx_eth1_platform_data.mac))
+ memcpy(au1xxx_eth1_platform_data.mac, ethaddr, 6);
+
/* Register second MAC if enabled in pinfunc */
if (!err && !(au_readl(SYS_PINFUNC) & (u32)SYS_PF_NI2))
- platform_device_register(&au1xxx_eth1_device);
+ err = platform_device_register(&au1xxx_eth1_device);
#endif
return err;
diff --git a/arch/mips/alchemy/devboards/Makefile b/arch/mips/alchemy/devboards/Makefile
index ecbd37f9ee8..826449c817c 100644
--- a/arch/mips/alchemy/devboards/Makefile
+++ b/arch/mips/alchemy/devboards/Makefile
@@ -16,5 +16,3 @@ obj-$(CONFIG_MIPS_DB1500) += db1x00/
obj-$(CONFIG_MIPS_DB1550) += db1x00/
obj-$(CONFIG_MIPS_BOSPORUS) += db1x00/
obj-$(CONFIG_MIPS_MIRAGE) += db1x00/
-
-EXTRA_CFLAGS += -Werror
diff --git a/arch/mips/alchemy/devboards/db1200/platform.c b/arch/mips/alchemy/devboards/db1200/platform.c
index 3cb95a98ab3..3fa34c3abc0 100644
--- a/arch/mips/alchemy/devboards/db1200/platform.c
+++ b/arch/mips/alchemy/devboards/db1200/platform.c
@@ -216,14 +216,14 @@ static struct resource db1200_ide_res[] = {
}
};
-static u64 ide_dmamask = DMA_32BIT_MASK;
+static u64 ide_dmamask = DMA_BIT_MASK(32);
static struct platform_device db1200_ide_dev = {
.name = "au1200-ide",
.id = 0,
.dev = {
.dma_mask = &ide_dmamask,
- .coherent_dma_mask = DMA_32BIT_MASK,
+ .coherent_dma_mask = DMA_BIT_MASK(32),
},
.num_resources = ARRAY_SIZE(db1200_ide_res),
.resource = db1200_ide_res,
@@ -385,12 +385,12 @@ static struct au1550_spi_info db1200_spi_platdata = {
.activate_cs = db1200_spi_cs_en,
};
-static u64 spi_dmamask = DMA_32BIT_MASK;
+static u64 spi_dmamask = DMA_BIT_MASK(32);
static struct platform_device db1200_spi_dev = {
.dev = {
.dma_mask = &spi_dmamask,
- .coherent_dma_mask = DMA_32BIT_MASK,
+ .coherent_dma_mask = DMA_BIT_MASK(32),
.platform_data = &db1200_spi_platdata,
},
.name = "au1550-spi",
diff --git a/arch/mips/alchemy/devboards/db1x00/board_setup.c b/arch/mips/alchemy/devboards/db1x00/board_setup.c
index 50c9bef99da..9e45971343e 100644
--- a/arch/mips/alchemy/devboards/db1x00/board_setup.c
+++ b/arch/mips/alchemy/devboards/db1x00/board_setup.c
@@ -79,7 +79,6 @@ static struct au1000_eth_platform_data eth0_pdata = {
static void bosporus_power_off(void)
{
- printk(KERN_INFO "It's now safe to turn off power\n");
while (1)
asm volatile (".set mips3 ; wait ; .set mips0");
}
diff --git a/arch/mips/alchemy/devboards/pb1000/board_setup.c b/arch/mips/alchemy/devboards/pb1000/board_setup.c
index 4ef50d86b18..f6540ec47a6 100644
--- a/arch/mips/alchemy/devboards/pb1000/board_setup.c
+++ b/arch/mips/alchemy/devboards/pb1000/board_setup.c
@@ -47,9 +47,11 @@ static void board_reset(char *c)
static void board_power_off(void)
{
- printk(KERN_ALERT "It's now safe to remove power\n");
while (1)
- asm volatile (".set mips3 ; wait ; .set mips1");
+ asm volatile (
+ " .set mips32 \n"
+ " wait \n"
+ " .set mips0 \n");
}
void __init board_setup(void)
diff --git a/arch/mips/alchemy/devboards/pb1200/Makefile b/arch/mips/alchemy/devboards/pb1200/Makefile
index 2ea9b02ef09..18c1bd53e4c 100644
--- a/arch/mips/alchemy/devboards/pb1200/Makefile
+++ b/arch/mips/alchemy/devboards/pb1200/Makefile
@@ -3,5 +3,3 @@
#
obj-y := board_setup.o platform.o
-
-EXTRA_CFLAGS += -Werror
diff --git a/arch/mips/alchemy/gpr/Makefile b/arch/mips/alchemy/gpr/Makefile
new file mode 100644
index 00000000000..cb73fe256dc
--- /dev/null
+++ b/arch/mips/alchemy/gpr/Makefile
@@ -0,0 +1,8 @@
+#
+# Copyright 2003 MontaVista Software Inc.
+# Author: MontaVista Software, Inc. <source@mvista.com>
+#
+# Makefile for Trapeze ITS GPR board.
+#
+
+obj-y += board_setup.o init.o platform.o
diff --git a/arch/mips/alchemy/gpr/board_setup.c b/arch/mips/alchemy/gpr/board_setup.c
new file mode 100644
index 00000000000..ad2e3f13793
--- /dev/null
+++ b/arch/mips/alchemy/gpr/board_setup.c
@@ -0,0 +1,93 @@
+/*
+ * Copyright 2010 Wolfgang Grandegger <wg@denx.de>
+ *
+ * Copyright 2000-2003, 2008 MontaVista Software Inc.
+ * Author: MontaVista Software, Inc. <source@mvista.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * 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/gpio.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+
+#include <asm/reboot.h>
+#include <asm/mach-au1x00/au1000.h>
+
+#include <prom.h>
+
+#define UART1_ADDR KSEG1ADDR(UART1_PHYS_ADDR)
+#define UART3_ADDR KSEG1ADDR(UART3_PHYS_ADDR)
+
+char irq_tab_alchemy[][5] __initdata = {
+ [0] = { -1, AU1500_PCI_INTA, AU1500_PCI_INTB, 0xff, 0xff },
+};
+
+static void gpr_reset(char *c)
+{
+ /* switch System-LED to orange (red# and green# on) */
+ alchemy_gpio_direction_output(4, 0);
+ alchemy_gpio_direction_output(5, 0);
+
+ /* trigger watchdog to reset board in 200ms */
+ printk(KERN_EMERG "Triggering watchdog soft reset...\n");
+ raw_local_irq_disable();
+ alchemy_gpio_direction_output(1, 0);
+ udelay(1);
+ alchemy_gpio_set_value(1, 1);
+ while (1)
+ cpu_wait();
+}
+
+static void gpr_power_off(void)
+{
+ while (1)
+ cpu_wait();
+}
+
+void __init board_setup(void)
+{
+ printk(KERN_INFO "Tarpeze ITS GPR board\n");
+
+ pm_power_off = gpr_power_off;
+ _machine_halt = gpr_power_off;
+ _machine_restart = gpr_reset;
+
+ /* Enable UART3 */
+ au_writel(0x1, UART3_ADDR + UART_MOD_CNTRL);/* clock enable (CE) */
+ au_writel(0x3, UART3_ADDR + UART_MOD_CNTRL); /* CE and "enable" */
+ /* Enable UART1 */
+ au_writel(0x1, UART1_ADDR + UART_MOD_CNTRL); /* clock enable (CE) */
+ au_writel(0x3, UART1_ADDR + UART_MOD_CNTRL); /* CE and "enable" */
+
+ /* Take away Reset of UMTS-card */
+ alchemy_gpio_direction_output(215, 1);
+
+#ifdef CONFIG_PCI
+#if defined(__MIPSEB__)
+ au_writel(0xf | (2 << 6) | (1 << 4), Au1500_PCI_CFG);
+#else
+ au_writel(0xf, Au1500_PCI_CFG);
+#endif
+#endif
+}
diff --git a/arch/mips/alchemy/gpr/init.c b/arch/mips/alchemy/gpr/init.c
new file mode 100644
index 00000000000..f044f4c541d
--- /dev/null
+++ b/arch/mips/alchemy/gpr/init.c
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2010 Wolfgang Grandegger <wg@denx.de>
+ *
+ * Copyright 2003, 2008 MontaVista Software Inc.
+ * Author: MontaVista Software, Inc. <source@mvista.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * 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/init.h>
+#include <linux/kernel.h>
+
+#include <asm/bootinfo.h>
+#include <asm/mach-au1x00/au1000.h>
+
+#include <prom.h>
+
+const char *get_system_type(void)
+{
+ return "GPR";
+}
+
+void __init prom_init(void)
+{
+ unsigned char *memsize_str;
+ unsigned long memsize;
+
+ prom_argc = fw_arg0;
+ prom_argv = (char **)fw_arg1;
+ prom_envp = (char **)fw_arg2;
+
+ prom_init_cmdline();
+
+ memsize_str = prom_getenv("memsize");
+ if (!memsize_str)
+ memsize = 0x04000000;
+ else
+ strict_strtoul(memsize_str, 0, &memsize);
+ add_memory_region(0, memsize, BOOT_MEM_RAM);
+}
+
+void prom_putchar(unsigned char c)
+{
+ alchemy_uart_putchar(UART0_PHYS_ADDR, c);
+}
diff --git a/arch/mips/alchemy/gpr/platform.c b/arch/mips/alchemy/gpr/platform.c
new file mode 100644
index 00000000000..14b46629cfc
--- /dev/null
+++ b/arch/mips/alchemy/gpr/platform.c
@@ -0,0 +1,183 @@
+/*
+ * GPR board platform device registration
+ *
+ * Copyright (C) 2010 Wolfgang Grandegger <wg@denx.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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/mtd/partitions.h>
+#include <linux/mtd/physmap.h>
+#include <linux/leds.h>
+#include <linux/gpio.h>
+#include <linux/i2c.h>
+#include <linux/i2c-gpio.h>
+
+#include <asm/mach-au1x00/au1000.h>
+
+/*
+ * Watchdog
+ */
+static struct resource gpr_wdt_resource[] = {
+ [0] = {
+ .start = 1,
+ .end = 1,
+ .name = "gpr-adm6320-wdt",
+ .flags = IORESOURCE_IRQ,
+ }
+};
+
+static struct platform_device gpr_wdt_device = {
+ .name = "adm6320-wdt",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(gpr_wdt_resource),
+ .resource = gpr_wdt_resource,
+};
+
+/*
+ * FLASH
+ *
+ * 0x00000000-0x00200000 : "kernel"
+ * 0x00200000-0x00a00000 : "rootfs"
+ * 0x01d00000-0x01f00000 : "config"
+ * 0x01c00000-0x01d00000 : "yamon"
+ * 0x01d00000-0x01d40000 : "yamon env vars"
+ * 0x00000000-0x00a00000 : "kernel+rootfs"
+ */
+static struct mtd_partition gpr_mtd_partitions[] = {
+ {
+ .name = "kernel",
+ .size = 0x00200000,
+ .offset = 0,
+ },
+ {
+ .name = "rootfs",
+ .size = 0x00800000,
+ .offset = MTDPART_OFS_APPEND,
+ .mask_flags = MTD_WRITEABLE,
+ },
+ {
+ .name = "config",
+ .size = 0x00200000,
+ .offset = 0x01d00000,
+ },
+ {
+ .name = "yamon",
+ .size = 0x00100000,
+ .offset = 0x01c00000,
+ },
+ {
+ .name = "yamon env vars",
+ .size = 0x00040000,
+ .offset = MTDPART_OFS_APPEND,
+ },
+ {
+ .name = "kernel+rootfs",
+ .size = 0x00a00000,
+ .offset = 0,
+ },
+};
+
+static struct physmap_flash_data gpr_flash_data = {
+ .width = 4,
+ .nr_parts = ARRAY_SIZE(gpr_mtd_partitions),
+ .parts = gpr_mtd_partitions,
+};
+
+static struct resource gpr_mtd_resource = {
+ .start = 0x1e000000,
+ .end = 0x1fffffff,
+ .flags = IORESOURCE_MEM,
+};
+
+static struct platform_device gpr_mtd_device = {
+ .name = "physmap-flash",
+ .dev = {
+ .platform_data = &gpr_flash_data,
+ },
+ .num_resources = 1,
+ .resource = &gpr_mtd_resource,
+};
+
+/*
+ * LEDs
+ */
+static struct gpio_led gpr_gpio_leds[] = {
+ { /* green */
+ .name = "gpr:green",
+ .gpio = 4,
+ .active_low = 1,
+ },
+ { /* red */
+ .name = "gpr:red",
+ .gpio = 5,
+ .active_low = 1,
+ }
+};
+
+static struct gpio_led_platform_data gpr_led_data = {
+ .num_leds = ARRAY_SIZE(gpr_gpio_leds),
+ .leds = gpr_gpio_leds,
+};
+
+static struct platform_device gpr_led_devices = {
+ .name = "leds-gpio",
+ .id = -1,
+ .dev = {
+ .platform_data = &gpr_led_data,
+ }
+};
+
+/*
+ * I2C
+ */
+static struct i2c_gpio_platform_data gpr_i2c_data = {
+ .sda_pin = 209,
+ .sda_is_open_drain = 1,
+ .scl_pin = 210,
+ .scl_is_open_drain = 1,
+ .udelay = 2, /* ~100 kHz */
+ .timeout = HZ,
+ };
+
+static struct platform_device gpr_i2c_device = {
+ .name = "i2c-gpio",
+ .id = -1,
+ .dev.platform_data = &gpr_i2c_data,
+};
+
+static struct i2c_board_info gpr_i2c_info[] __initdata = {
+ {
+ I2C_BOARD_INFO("lm83", 0x18),
+ .type = "lm83"
+ }
+};
+
+static struct platform_device *gpr_devices[] __initdata = {
+ &gpr_wdt_device,
+ &gpr_mtd_device,
+ &gpr_i2c_device,
+ &gpr_led_devices,
+};
+
+static int __init gpr_dev_init(void)
+{
+ i2c_register_board_info(0, gpr_i2c_info, ARRAY_SIZE(gpr_i2c_info));
+
+ return platform_add_devices(gpr_devices, ARRAY_SIZE(gpr_devices));
+}
+device_initcall(gpr_dev_init);
diff --git a/arch/mips/alchemy/mtx-1/Makefile b/arch/mips/alchemy/mtx-1/Makefile
index 4a53815b3c6..81b540ceaf8 100644
--- a/arch/mips/alchemy/mtx-1/Makefile
+++ b/arch/mips/alchemy/mtx-1/Makefile
@@ -6,7 +6,4 @@
# Makefile for 4G Systems MTX-1 board.
#
-lib-y := init.o board_setup.o
-obj-y := platform.o
-
-EXTRA_CFLAGS += -Werror
+obj-y += init.o board_setup.o platform.o
diff --git a/arch/mips/alchemy/mtx-1/board_setup.c b/arch/mips/alchemy/mtx-1/board_setup.c
index 52d883d37dd..6398fa95905 100644
--- a/arch/mips/alchemy/mtx-1/board_setup.c
+++ b/arch/mips/alchemy/mtx-1/board_setup.c
@@ -60,9 +60,11 @@ static void mtx1_reset(char *c)
static void mtx1_power_off(void)
{
- printk(KERN_ALERT "It's now safe to remove power\n");
while (1)
- asm volatile (".set mips3 ; wait ; .set mips1");
+ asm volatile (
+ " .set mips32 \n"
+ " wait \n"
+ " .set mips0 \n");
}
void __init board_setup(void)
@@ -105,14 +107,10 @@ void __init board_setup(void)
int
mtx1_pci_idsel(unsigned int devsel, int assert)
{
-#define MTX_IDSEL_ONLY_0_AND_3 0
-#if MTX_IDSEL_ONLY_0_AND_3
- if (devsel != 0 && devsel != 3) {
- printk(KERN_ERR "*** not 0 or 3\n");
- return 0;
- }
-#endif
-
+ /* This function is only necessary to support a proprietary Cardbus
+ * adapter on the mtx-1 "singleboard" variant. It triggers a custom
+ * logic chip connected to EXT_IO3 (GPIO1) to suppress IDSEL signals.
+ */
if (assert && devsel != 0)
/* Suppress signal to Cardbus */
alchemy_gpio_set_value(1, 0); /* set EXT_IO3 OFF */
diff --git a/arch/mips/alchemy/xxs1500/Makefile b/arch/mips/alchemy/xxs1500/Makefile
index 4dc81d794cb..91defcf4f33 100644
--- a/arch/mips/alchemy/xxs1500/Makefile
+++ b/arch/mips/alchemy/xxs1500/Makefile
@@ -5,6 +5,4 @@
# Makefile for MyCable XXS1500 board.
#
-lib-y := init.o board_setup.o platform.o
-
-EXTRA_CFLAGS += -Werror
+obj-y += init.o board_setup.o platform.o
diff --git a/arch/mips/alchemy/xxs1500/board_setup.c b/arch/mips/alchemy/xxs1500/board_setup.c
index 47b42927607..b43c918925d 100644
--- a/arch/mips/alchemy/xxs1500/board_setup.c
+++ b/arch/mips/alchemy/xxs1500/board_setup.c
@@ -42,9 +42,11 @@ static void xxs1500_reset(char *c)
static void xxs1500_power_off(void)
{
- printk(KERN_ALERT "It's now safe to remove power\n");
while (1)
- asm volatile (".set mips3 ; wait ; .set mips1");
+ asm volatile (
+ " .set mips32 \n"
+ " wait \n"
+ " .set mips0 \n");
}
void __init board_setup(void)
diff --git a/arch/mips/ar7/Makefile b/arch/mips/ar7/Makefile
index 26bc5da1899..7435e44b396 100644
--- a/arch/mips/ar7/Makefile
+++ b/arch/mips/ar7/Makefile
@@ -8,4 +8,3 @@ obj-y := \
platform.o \
gpio.o \
clock.o
-EXTRA_CFLAGS += -Werror
diff --git a/arch/mips/ar7/Platform b/arch/mips/ar7/Platform
new file mode 100644
index 00000000000..0bf85c416c6
--- /dev/null
+++ b/arch/mips/ar7/Platform
@@ -0,0 +1,6 @@
+#
+# Texas Instruments AR7
+#
+platform-$(CONFIG_AR7) += ar7/
+cflags-$(CONFIG_AR7) += -I$(srctree)/arch/mips/include/asm/mach-ar7
+load-$(CONFIG_AR7) += 0xffffffff94100000
diff --git a/arch/mips/ar7/platform.c b/arch/mips/ar7/platform.c
index 8f31d1d5968..0da5b2b8dd8 100644
--- a/arch/mips/ar7/platform.c
+++ b/arch/mips/ar7/platform.c
@@ -292,40 +292,28 @@ static struct platform_device cpmac_high = {
.num_resources = ARRAY_SIZE(cpmac_high_res),
};
-static inline unsigned char char2hex(char h)
+static void __init cpmac_get_mac(int instance, unsigned char *dev_addr)
{
- switch (h) {
- case '0': case '1': case '2': case '3': case '4':
- case '5': case '6': case '7': case '8': case '9':
- return h - '0';
- case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
- return h - 'A' + 10;
- case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
- return h - 'a' + 10;
- default:
- return 0;
- }
-}
-
-static void cpmac_get_mac(int instance, unsigned char *dev_addr)
-{
- int i;
- char name[5], default_mac[ETH_ALEN], *mac;
+ char name[5], *mac;
- mac = NULL;
sprintf(name, "mac%c", 'a' + instance);
mac = prom_getenv(name);
- if (!mac) {
+ if (!mac && instance) {
sprintf(name, "mac%c", 'a');
mac = prom_getenv(name);
}
- if (!mac) {
- random_ether_addr(default_mac);
- mac = default_mac;
- }
- for (i = 0; i < 6; i++)
- dev_addr[i] = (char2hex(mac[i * 3]) << 4) +
- char2hex(mac[i * 3 + 1]);
+
+ if (mac) {
+ if (sscanf(mac, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx",
+ &dev_addr[0], &dev_addr[1],
+ &dev_addr[2], &dev_addr[3],
+ &dev_addr[4], &dev_addr[5]) != 6) {
+ pr_warning("cannot parse mac address, "
+ "using random address\n");
+ random_ether_addr(dev_addr);
+ }
+ } else
+ random_ether_addr(dev_addr);
}
/*****************************************************************************
diff --git a/arch/mips/bcm47xx/Platform b/arch/mips/bcm47xx/Platform
new file mode 100644
index 00000000000..874b7ca4cd1
--- /dev/null
+++ b/arch/mips/bcm47xx/Platform
@@ -0,0 +1,7 @@
+#
+# Broadcom BCM47XX boards
+#
+platform-$(CONFIG_BCM47XX) += bcm47xx/
+cflags-$(CONFIG_BCM47XX) += \
+ -I$(srctree)/arch/mips/include/asm/mach-bcm47xx
+load-$(CONFIG_BCM47XX) := 0xffffffff80001000
diff --git a/arch/mips/bcm47xx/nvram.c b/arch/mips/bcm47xx/nvram.c
index 06e03b222f6..e5b6615731e 100644
--- a/arch/mips/bcm47xx/nvram.c
+++ b/arch/mips/bcm47xx/nvram.c
@@ -69,7 +69,7 @@ int nvram_getenv(char *name, char *val, size_t val_len)
char *var, *value, *end, *eq;
if (!name)
- return 1;
+ return NVRAM_ERR_INV_PARAM;
if (!nvram_buf[0])
early_nvram_init();
@@ -89,6 +89,6 @@ int nvram_getenv(char *name, char *val, size_t val_len)
return 0;
}
}
- return 1;
+ return NVRAM_ERR_ENVNOTFOUND;
}
EXPORT_SYMBOL(nvram_getenv);
diff --git a/arch/mips/bcm47xx/prom.c b/arch/mips/bcm47xx/prom.c
index 0fa646c5a84..f6e9063cc4c 100644
--- a/arch/mips/bcm47xx/prom.c
+++ b/arch/mips/bcm47xx/prom.c
@@ -126,6 +126,7 @@ static __init void prom_init_cmdline(void)
static __init void prom_init_mem(void)
{
unsigned long mem;
+ unsigned long max;
/* Figure out memory size by finding aliases.
*
@@ -134,21 +135,26 @@ static __init void prom_init_mem(void)
* want to reuse the memory used by CFE (around 4MB). That means cfe_*
* functions stop to work at some point during the boot, we should only
* call them at the beginning of the boot.
+ *
+ * BCM47XX uses 128MB for addressing the ram, if the system contains
+ * less that that amount of ram it remaps the ram more often into the
+ * available space.
+ * Accessing memory after 128MB will cause an exception.
+ * max contains the biggest possible address supported by the platform.
+ * If the method wants to try something above we assume 128MB ram.
*/
+ max = ((unsigned long)(prom_init) | ((128 << 20) - 1));
for (mem = (1 << 20); mem < (128 << 20); mem += (1 << 20)) {
+ if (((unsigned long)(prom_init) + mem) > max) {
+ mem = (128 << 20);
+ printk(KERN_DEBUG "assume 128MB RAM\n");
+ break;
+ }
if (*(unsigned long *)((unsigned long)(prom_init) + mem) ==
*(unsigned long *)(prom_init))
break;
}
- /* Ignoring the last page when ddr size is 128M. Cached
- * accesses to last page is causing the processor to prefetch
- * using address above 128M stepping out of the ddr address
- * space.
- */
- if (mem == 0x8000000)
- mem -= 0x1000;
-
add_memory_region(0, mem, BOOT_MEM_RAM);
}
diff --git a/arch/mips/bcm63xx/Makefile b/arch/mips/bcm63xx/Makefile
index 00064b66080..6dfdc69928a 100644
--- a/arch/mips/bcm63xx/Makefile
+++ b/arch/mips/bcm63xx/Makefile
@@ -3,5 +3,3 @@ obj-y += clk.o cpu.o cs.o gpio.o irq.o prom.o setup.o timer.o \
obj-$(CONFIG_EARLY_PRINTK) += early_printk.o
obj-y += boards/
-
-EXTRA_CFLAGS += -Werror
diff --git a/arch/mips/bcm63xx/Platform b/arch/mips/bcm63xx/Platform
new file mode 100644
index 00000000000..5f86b2fff6d
--- /dev/null
+++ b/arch/mips/bcm63xx/Platform
@@ -0,0 +1,7 @@
+#
+# Broadcom BCM63XX boards
+#
+platform-$(CONFIG_BCM63XX) += bcm63xx/
+cflags-$(CONFIG_BCM63XX) += \
+ -I$(srctree)/arch/mips/include/asm/mach-bcm63xx/
+load-$(CONFIG_BCM63XX) := 0xffffffff80010000
diff --git a/arch/mips/boot/.gitignore b/arch/mips/boot/.gitignore
index 4667a5f9280..f210b09ecec 100644
--- a/arch/mips/boot/.gitignore
+++ b/arch/mips/boot/.gitignore
@@ -3,3 +3,4 @@ elf2ecoff
vmlinux.*
zImage
zImage.tmp
+calc_vmlinuz_load_addr
diff --git a/arch/mips/boot/Makefile b/arch/mips/boot/Makefile
index e39a08edcaa..85bcb5adc7c 100644
--- a/arch/mips/boot/Makefile
+++ b/arch/mips/boot/Makefile
@@ -11,35 +11,32 @@
# Some DECstations need all possible sections of an ECOFF executable
#
ifdef CONFIG_MACH_DECSTATION
- E2EFLAGS = -a
-else
- E2EFLAGS =
+ e2eflag := -a
endif
#
# Drop some uninteresting sections in the kernel.
# This is only relevant for ELF kernels but doesn't hurt a.out
#
-drop-sections = .reginfo .mdebug .comment .note .pdr .options .MIPS.options
-strip-flags = $(addprefix --remove-section=,$(drop-sections))
-
-VMLINUX = vmlinux
-
-all: vmlinux.ecoff vmlinux.srec
-
-vmlinux.ecoff: $(obj)/elf2ecoff $(VMLINUX)
- $(obj)/elf2ecoff $(VMLINUX) $(obj)/vmlinux.ecoff $(E2EFLAGS)
-
-$(obj)/elf2ecoff: $(obj)/elf2ecoff.c
- $(HOSTCC) -o $@ $^
-
-vmlinux.bin: $(VMLINUX)
- $(OBJCOPY) -O binary $(strip-flags) $(VMLINUX) $(obj)/vmlinux.bin
-
-vmlinux.srec: $(VMLINUX)
- $(OBJCOPY) -S -O srec $(strip-flags) $(VMLINUX) $(obj)/vmlinux.srec
-
-clean-files += elf2ecoff \
- vmlinux.bin \
- vmlinux.ecoff \
- vmlinux.srec
+drop-sections := .reginfo .mdebug .comment .note .pdr .options .MIPS.options
+strip-flags := $(addprefix --remove-section=,$(drop-sections))
+
+hostprogs-y := elf2ecoff
+
+targets := vmlinux.ecoff
+quiet_cmd_ecoff = ECOFF $@
+ cmd_ecoff = $(obj)/elf2ecoff $(VMLINUX) $@ $(e2eflag)
+$(obj)/vmlinux.ecoff: $(obj)/elf2ecoff $(VMLINUX) FORCE
+ $(call if_changed,ecoff)
+
+targets += vmlinux.bin
+quiet_cmd_bin = OBJCOPY $@
+ cmd_bin = $(OBJCOPY) -O binary $(strip-flags) $(VMLINUX) $@
+$(obj)/vmlinux.bin: $(VMLINUX) FORCE
+ $(call if_changed,bin)
+
+targets += vmlinux.srec
+quiet_cmd_srec = OBJCOPY $@
+ cmd_srec = $(OBJCOPY) -S -O srec $(strip-flags) $(VMLINUX) $@
+$(obj)/vmlinux.srec: $(VMLINUX) FORCE
+ $(call if_changed,srec)
diff --git a/arch/mips/boot/compressed/Makefile b/arch/mips/boot/compressed/Makefile
index 790ddd39762..ed9bb709c9a 100644
--- a/arch/mips/boot/compressed/Makefile
+++ b/arch/mips/boot/compressed/Makefile
@@ -12,14 +12,6 @@
# Author: Wu Zhangjin <wuzhangjin@gmail.com>
#
-# compressed kernel load addr: VMLINUZ_LOAD_ADDRESS > VMLINUX_LOAD_ADDRESS + VMLINUX_SIZE
-VMLINUX_SIZE := $(shell wc -c $(objtree)/$(KBUILD_IMAGE) 2>/dev/null | cut -d' ' -f1)
-VMLINUX_SIZE := $(shell [ -n "$(VMLINUX_SIZE)" ] && echo -n $$(($(VMLINUX_SIZE) + (65536 - $(VMLINUX_SIZE) % 65536))))
-# VMLINUZ_LOAD_ADDRESS = concat "high32 of VMLINUX_LOAD_ADDRESS" and "(low32 of VMLINUX_LOAD_ADDRESS) + VMLINUX_SIZE"
-HIGH32 := $(shell A=$(VMLINUX_LOAD_ADDRESS); [ $${\#A} -gt 10 ] && expr substr "$(VMLINUX_LOAD_ADDRESS)" 3 $$(($${\#A} - 10)))
-LOW32 := $(shell [ -n "$(HIGH32)" ] && A=11 || A=3; expr substr "$(VMLINUX_LOAD_ADDRESS)" $${A} 8)
-VMLINUZ_LOAD_ADDRESS := 0x$(shell [ -n "$(VMLINUX_SIZE)" -a -n "$(LOW32)" ] && printf "$(HIGH32)%08x" $$(($(VMLINUX_SIZE) + 0x$(LOW32))))
-
# set the default size of the mallocing area for decompressing
BOOT_HEAP_SIZE := 0x400000
@@ -33,49 +25,61 @@ KBUILD_AFLAGS := $(LINUXINCLUDE) $(KBUILD_AFLAGS) -D__ASSEMBLY__ \
-DBOOT_HEAP_SIZE=$(BOOT_HEAP_SIZE) \
-DKERNEL_ENTRY=0x$(shell $(NM) $(objtree)/$(KBUILD_IMAGE) 2>/dev/null | grep " kernel_entry" | cut -f1 -d \ )
-obj-y := $(obj)/head.o $(obj)/decompress.o $(obj)/dbg.o
+targets := head.o decompress.o dbg.o uart-16550.o uart-alchemy.o
+
+# decompressor objects (linked with vmlinuz)
+vmlinuzobjs-y := $(obj)/head.o $(obj)/decompress.o $(obj)/dbg.o
ifdef CONFIG_DEBUG_ZBOOT
-obj-$(CONFIG_SYS_SUPPORTS_ZBOOT_UART16550) += $(obj)/uart-16550.o
-obj-$(CONFIG_MACH_ALCHEMY) += $(obj)/uart-alchemy.o
+vmlinuzobjs-$(CONFIG_SYS_SUPPORTS_ZBOOT_UART16550) += $(obj)/uart-16550.o
+vmlinuzobjs-$(CONFIG_MIPS_ALCHEMY) += $(obj)/uart-alchemy.o
endif
+targets += vmlinux.bin
OBJCOPYFLAGS_vmlinux.bin := $(OBJCOPYFLAGS) -O binary -R .comment -S
-$(obj)/vmlinux.bin: $(KBUILD_IMAGE)
+$(obj)/vmlinux.bin: $(KBUILD_IMAGE) FORCE
$(call if_changed,objcopy)
-suffix_$(CONFIG_KERNEL_GZIP) = gz
-suffix_$(CONFIG_KERNEL_BZIP2) = bz2
-suffix_$(CONFIG_KERNEL_LZMA) = lzma
-suffix_$(CONFIG_KERNEL_LZO) = lzo
tool_$(CONFIG_KERNEL_GZIP) = gzip
tool_$(CONFIG_KERNEL_BZIP2) = bzip2
tool_$(CONFIG_KERNEL_LZMA) = lzma
tool_$(CONFIG_KERNEL_LZO) = lzo
-$(obj)/vmlinux.$(suffix_y): $(obj)/vmlinux.bin
+
+targets += vmlinux.bin.z
+$(obj)/vmlinux.bin.z: $(obj)/vmlinux.bin FORCE
$(call if_changed,$(tool_y))
-$(obj)/piggy.o: $(obj)/vmlinux.$(suffix_y) $(obj)/dummy.o
- $(Q)$(OBJCOPY) $(OBJCOPYFLAGS) \
- --add-section=.image=$< \
- --set-section-flags=.image=contents,alloc,load,readonly,data \
- $(obj)/dummy.o $@
+targets += piggy.o
+OBJCOPYFLAGS_piggy.o := --add-section=.image=$(obj)/vmlinux.bin.z \
+ --set-section-flags=.image=contents,alloc,load,readonly,data
+$(obj)/piggy.o: $(obj)/dummy.o $(obj)/vmlinux.bin.z FORCE
+ $(call if_changed,objcopy)
+
+# Calculate the load address of the compressed kernel image
+hostprogs-y := calc_vmlinuz_load_addr
+
+VMLINUZ_LOAD_ADDRESS = $(shell $(obj)/calc_vmlinuz_load_addr \
+ $(objtree)/$(KBUILD_IMAGE) $(VMLINUX_LOAD_ADDRESS))
-LDFLAGS_vmlinuz := $(LDFLAGS) -Ttext $(VMLINUZ_LOAD_ADDRESS) -T
-vmlinuz: $(src)/ld.script $(obj-y) $(obj)/piggy.o
- $(call if_changed,ld)
- $(Q)$(OBJCOPY) $(OBJCOPYFLAGS) $@
+vmlinuzobjs-y += $(obj)/piggy.o
+
+quiet_cmd_zld = LD $@
+ cmd_zld = $(LD) $(LDFLAGS) -Ttext $(VMLINUZ_LOAD_ADDRESS) -T $< $(vmlinuzobjs-y) -o $@
+quiet_cmd_strip = STRIP $@
+ cmd_strip = $(STRIP) -s $@
+vmlinuz: $(src)/ld.script $(vmlinuzobjs-y) $(obj)/calc_vmlinuz_load_addr
+ $(call cmd,zld)
+ $(call cmd,strip)
#
# Some DECstations need all possible sections of an ECOFF executable
#
ifdef CONFIG_MACH_DECSTATION
- E2EFLAGS = -a
-else
- E2EFLAGS =
+ e2eflag := -a
endif
# elf2ecoff can only handle 32bit image
+hostprogs-y += ../elf2ecoff
ifdef CONFIG_32BIT
VMLINUZ = vmlinuz
@@ -83,23 +87,22 @@ else
VMLINUZ = vmlinuz.32
endif
+quiet_cmd_32 = OBJCOPY $@
+ cmd_32 = $(OBJCOPY) -O $(32bit-bfd) $(OBJCOPYFLAGS) $< $@
vmlinuz.32: vmlinuz
- $(Q)$(OBJCOPY) -O $(32bit-bfd) $(OBJCOPYFLAGS) $< $@
+ $(call cmd,32)
+quiet_cmd_ecoff = ECOFF $@
+ cmd_ecoff = $< $(VMLINUZ) $@ $(e2eflag)
vmlinuz.ecoff: $(obj)/../elf2ecoff $(VMLINUZ)
- $(Q)$(obj)/../elf2ecoff $(VMLINUZ) vmlinuz.ecoff $(E2EFLAGS)
-
-$(obj)/../elf2ecoff: $(src)/../elf2ecoff.c
- $(Q)$(HOSTCC) -o $@ $^
+ $(call cmd,ecoff)
OBJCOPYFLAGS_vmlinuz.bin := $(OBJCOPYFLAGS) -O binary
vmlinuz.bin: vmlinuz
- $(call if_changed,objcopy)
+ $(call cmd,objcopy)
OBJCOPYFLAGS_vmlinuz.srec := $(OBJCOPYFLAGS) -S -O srec
vmlinuz.srec: vmlinuz
- $(call if_changed,objcopy)
+ $(call cmd,objcopy)
-clean:
-clean-files += *.o \
- vmlinu*
+clean-files := $(objtree)/vmlinuz.*
diff --git a/arch/mips/boot/compressed/calc_vmlinuz_load_addr.c b/arch/mips/boot/compressed/calc_vmlinuz_load_addr.c
new file mode 100644
index 00000000000..88c9d963be8
--- /dev/null
+++ b/arch/mips/boot/compressed/calc_vmlinuz_load_addr.c
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2010 "Wu Zhangjin" <wuzhangjin@gmail.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 <sys/types.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+int main(int argc, char *argv[])
+{
+ struct stat sb;
+ uint64_t vmlinux_size, vmlinux_load_addr, vmlinuz_load_addr;
+
+ if (argc != 3) {
+ fprintf(stderr, "Usage: %s <pathname> <vmlinux_load_addr>\n",
+ argv[0]);
+ return EXIT_FAILURE;
+ }
+
+ if (stat(argv[1], &sb) == -1) {
+ perror("stat");
+ return EXIT_FAILURE;
+ }
+
+ /* Convert hex characters to dec number */
+ errno = 0;
+ if (sscanf(argv[2], "%llx", &vmlinux_load_addr) != 1) {
+ if (errno != 0)
+ perror("sscanf");
+ else
+ fprintf(stderr, "No matching characters\n");
+
+ return EXIT_FAILURE;
+ }
+
+ vmlinux_size = (uint64_t)sb.st_size;
+ vmlinuz_load_addr = vmlinux_load_addr + vmlinux_size;
+
+ /*
+ * Align with 16 bytes: "greater than that used for any standard data
+ * types by a MIPS compiler." -- See MIPS Run Linux (Second Edition).
+ */
+
+ vmlinuz_load_addr += (16 - vmlinux_size % 16);
+
+ printf("0x%llx\n", vmlinuz_load_addr);
+
+ return EXIT_SUCCESS;
+}
diff --git a/arch/mips/boot/compressed/decompress.c b/arch/mips/boot/compressed/decompress.c
index 5db43c58b1b..5cad0faefa1 100644
--- a/arch/mips/boot/compressed/decompress.c
+++ b/arch/mips/boot/compressed/decompress.c
@@ -1,9 +1,6 @@
/*
- * Misc. bootloader code for many machines.
- *
* Copyright 2001 MontaVista Software Inc.
- * Author: Matt Porter <mporter@mvista.com> Derived from
- * arch/ppc/boot/prep/misc.c
+ * Author: Matt Porter <mporter@mvista.com>
*
* Copyright (C) 2009 Lemote, Inc.
* Author: Wu Zhangjin <wuzhangjin@gmail.com>
@@ -19,12 +16,12 @@
#include <asm/addrspace.h>
-/* These two variables specify the free mem region
+/*
+ * These two variables specify the free mem region
* that can be used for temporary malloc area
*/
unsigned long free_mem_ptr;
unsigned long free_mem_end_ptr;
-char *zimage_start;
/* The linker tells us where the image is. */
extern unsigned char __image_begin, __image_end;
@@ -83,38 +80,31 @@ void *memset(void *s, int c, size_t n)
void decompress_kernel(unsigned long boot_heap_start)
{
- int zimage_size;
-
- /*
- * We link ourself to an arbitrary low address. When we run, we
- * relocate outself to that address. __image_beign points to
- * the part of the image where the zImage is. -- Tom
- */
- zimage_start = (char *)(unsigned long)(&__image_begin);
+ unsigned long zimage_start, zimage_size;
+
+ zimage_start = (unsigned long)(&__image_begin);
zimage_size = (unsigned long)(&__image_end) -
(unsigned long)(&__image_begin);
- /*
- * The zImage and initrd will be between start and _end, so they've
- * already been moved once. We're good to go now. -- Tom
- */
puts("zimage at: ");
- puthex((unsigned long)zimage_start);
+ puthex(zimage_start);
puts(" ");
- puthex((unsigned long)(zimage_size + zimage_start));
+ puthex(zimage_size + zimage_start);
puts("\n");
- /* this area are prepared for mallocing when decompressing */
+ /* This area are prepared for mallocing when decompressing */
free_mem_ptr = boot_heap_start;
free_mem_end_ptr = boot_heap_start + BOOT_HEAP_SIZE;
- /* Display standard Linux/MIPS boot prompt for kernel args */
+ /* Display standard Linux/MIPS boot prompt */
puts("Uncompressing Linux at load address ");
puthex(VMLINUX_LOAD_ADDRESS_ULL);
puts("\n");
+
/* Decompress the kernel with according algorithm */
- decompress(zimage_start, zimage_size, 0, 0,
+ decompress((char *)zimage_start, zimage_size, 0, 0,
(void *)VMLINUX_LOAD_ADDRESS_ULL, 0, error);
- /* FIXME: is there a need to flush cache here? */
+
+ /* FIXME: should we flush cache here? */
puts("Now, booting the kernel...\n");
}
diff --git a/arch/mips/boot/compressed/ld.script b/arch/mips/boot/compressed/ld.script
index 613a35b02f5..8e6b07ca2f5 100644
--- a/arch/mips/boot/compressed/ld.script
+++ b/arch/mips/boot/compressed/ld.script
@@ -2,61 +2,44 @@
* ld.script for compressed kernel support of MIPS
*
* Copyright (C) 2009 Lemote Inc.
- * Author: Wu Zhangjin <wuzj@lemote.com>
+ * Author: Wu Zhangjin <wuzhanjing@gmail.com>
+ * Copyright (C) 2010 "Wu Zhangjin" <wuzhanjing@gmail.com>
*/
OUTPUT_ARCH(mips)
ENTRY(start)
SECTIONS
{
- /* . = VMLINUZ_LOAD_ADDRESS */
- /* read-only */
- _text = .; /* Text and read-only data */
- .text : {
- _ftext = . ;
+ /* Text and read-only data */
+ /* . = VMLINUZ_LOAD_ADDRESS; */
+ .text : {
*(.text)
*(.rodata)
- } = 0
- _etext = .; /* End of text section */
+ }
+ /* End of text section */
- /* writable */
- .data : { /* Data */
- _fdata = . ;
+ /* Writable data */
+ .data : {
*(.data)
- /* Put the compressed image here, so bss is on the end. */
+ /* Put the compressed image here */
__image_begin = .;
*(.image)
__image_end = .;
CONSTRUCTORS
}
- .sdata : { *(.sdata) }
- . = ALIGN(4);
- _edata = .; /* End of data section */
+ . = ALIGN(16);
+ _edata = .;
+ /* End of data section */
/* BSS */
- __bss_start = .;
- _fbss = .;
- .sbss : { *(.sbss) *(.scommon) }
- .bss : {
- *(.dynbss)
+ .bss : {
*(.bss)
- *(COMMON)
}
- . = ALIGN(4);
- _end = . ;
-
- /* These are needed for ELF backends which have not yet been converted
- * to the new style linker. */
-
- .stab 0 : { *(.stab) }
- .stabstr 0 : { *(.stabstr) }
-
- /* These must appear regardless of . */
- .gptab.sdata : { *(.gptab.data) *(.gptab.sdata) }
- .gptab.sbss : { *(.gptab.bss) *(.gptab.sbss) }
+ . = ALIGN(16);
+ _end = .;
/* Sections to be discarded */
- /DISCARD/ : {
+ /DISCARD/ : {
*(.MIPS.options)
*(.options)
*(.pdr)
diff --git a/arch/mips/cavium-octeon/Makefile b/arch/mips/cavium-octeon/Makefile
index 3e9876317e6..19eb0434269 100644
--- a/arch/mips/cavium-octeon/Makefile
+++ b/arch/mips/cavium-octeon/Makefile
@@ -12,7 +12,6 @@
obj-y := cpu.o setup.o serial.o octeon-platform.o octeon-irq.o csrc-octeon.o
obj-y += dma-octeon.o flash_setup.o
obj-y += octeon-memcpy.o
+obj-y += executive/
obj-$(CONFIG_SMP) += smp.o
-
-EXTRA_CFLAGS += -Werror
diff --git a/arch/mips/cavium-octeon/Platform b/arch/mips/cavium-octeon/Platform
new file mode 100644
index 00000000000..1e43ccf1a79
--- /dev/null
+++ b/arch/mips/cavium-octeon/Platform
@@ -0,0 +1,11 @@
+#
+# Cavium Octeon
+#
+platform-$(CONFIG_CPU_CAVIUM_OCTEON) += cavium-octeon/
+cflags-$(CONFIG_CPU_CAVIUM_OCTEON) += \
+ -I$(srctree)/arch/mips/include/asm/mach-cavium-octeon
+ifdef CONFIG_CAVIUM_OCTEON_2ND_KERNEL
+load-$(CONFIG_CPU_CAVIUM_OCTEON) += 0xffffffff84100000
+else
+load-$(CONFIG_CPU_CAVIUM_OCTEON) += 0xffffffff81100000
+endif
diff --git a/arch/mips/cavium-octeon/cpu.c b/arch/mips/cavium-octeon/cpu.c
index b6df5387e85..c664c8cc2b4 100644
--- a/arch/mips/cavium-octeon/cpu.c
+++ b/arch/mips/cavium-octeon/cpu.c
@@ -41,12 +41,8 @@ static int cnmips_cu2_call(struct notifier_block *nfb, unsigned long action,
return NOTIFY_OK; /* Let default notifier send signals */
}
-static struct notifier_block cnmips_cu2_notifier = {
- .notifier_call = cnmips_cu2_call,
-};
-
static int cnmips_cu2_setup(void)
{
- return register_cu2_notifier(&cnmips_cu2_notifier);
+ return cu2_notifier(cnmips_cu2_call, 0);
}
early_initcall(cnmips_cu2_setup);
diff --git a/arch/mips/cavium-octeon/csrc-octeon.c b/arch/mips/cavium-octeon/csrc-octeon.c
index 0bf4bbe04ae..b6847c8e0dd 100644
--- a/arch/mips/cavium-octeon/csrc-octeon.c
+++ b/arch/mips/cavium-octeon/csrc-octeon.c
@@ -53,7 +53,6 @@ static struct clocksource clocksource_mips = {
unsigned long long notrace sched_clock(void)
{
/* 64-bit arithmatic can overflow, so use 128-bit. */
-#if (__GNUC__ < 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ <= 3))
u64 t1, t2, t3;
unsigned long long rv;
u64 mult = clocksource_mips.mult;
@@ -73,13 +72,6 @@ unsigned long long notrace sched_clock(void)
: [cnt] "r" (cnt), [mult] "r" (mult), [shift] "r" (shift)
: "hi", "lo");
return rv;
-#else
- /* GCC > 4.3 do it the easy way. */
- unsigned int __attribute__((mode(TI))) t;
- t = read_c0_cvmcount();
- t = t * clocksource_mips.mult;
- return (unsigned long long)(t >> clocksource_mips.shift);
-#endif
}
void __init plat_time_init(void)
@@ -88,3 +80,58 @@ void __init plat_time_init(void)
clocksource_set_clock(&clocksource_mips, mips_hpt_frequency);
clocksource_register(&clocksource_mips);
}
+
+static u64 octeon_udelay_factor;
+static u64 octeon_ndelay_factor;
+
+void __init octeon_setup_delays(void)
+{
+ octeon_udelay_factor = octeon_get_clock_rate() / 1000000;
+ /*
+ * For __ndelay we divide by 2^16, so the factor is multiplied
+ * by the same amount.
+ */
+ octeon_ndelay_factor = (octeon_udelay_factor * 0x10000ull) / 1000ull;
+
+ preset_lpj = octeon_get_clock_rate() / HZ;
+}
+
+void __udelay(unsigned long us)
+{
+ u64 cur, end, inc;
+
+ cur = read_c0_cvmcount();
+
+ inc = us * octeon_udelay_factor;
+ end = cur + inc;
+
+ while (end > cur)
+ cur = read_c0_cvmcount();
+}
+EXPORT_SYMBOL(__udelay);
+
+void __ndelay(unsigned long ns)
+{
+ u64 cur, end, inc;
+
+ cur = read_c0_cvmcount();
+
+ inc = ((ns * octeon_ndelay_factor) >> 16);
+ end = cur + inc;
+
+ while (end > cur)
+ cur = read_c0_cvmcount();
+}
+EXPORT_SYMBOL(__ndelay);
+
+void __delay(unsigned long loops)
+{
+ u64 cur, end;
+
+ cur = read_c0_cvmcount();
+ end = cur + loops;
+
+ while (end > cur)
+ cur = read_c0_cvmcount();
+}
+EXPORT_SYMBOL(__delay);
diff --git a/arch/mips/cavium-octeon/dma-octeon.c b/arch/mips/cavium-octeon/dma-octeon.c
index be531ec1f20..d22b5a2d64f 100644
--- a/arch/mips/cavium-octeon/dma-octeon.c
+++ b/arch/mips/cavium-octeon/dma-octeon.c
@@ -99,13 +99,16 @@ dma_addr_t octeon_map_dma_mem(struct device *dev, void *ptr, size_t size)
panic("dma_map_single: "
"Attempt to map illegal memory address 0x%llx\n",
physical);
- else if ((physical + size >=
- (4ull<<30) - (OCTEON_PCI_BAR1_HOLE_SIZE<<20))
- && physical < (4ull<<30))
- pr_warning("dma_map_single: Warning: "
- "Mapping memory address that might "
- "conflict with devices 0x%llx-0x%llx\n",
- physical, physical+size-1);
+ else if (physical >= CVMX_PCIE_BAR1_PHYS_BASE &&
+ physical + size < (CVMX_PCIE_BAR1_PHYS_BASE + CVMX_PCIE_BAR1_PHYS_SIZE)) {
+ result = physical - CVMX_PCIE_BAR1_PHYS_BASE + CVMX_PCIE_BAR1_RC_BASE;
+
+ if (((result+size-1) & dma_mask) != result+size-1)
+ panic("dma_map_single: Attempt to map address 0x%llx-0x%llx, which can't be accessed according to the dma mask 0x%llx\n",
+ physical, physical+size-1, dma_mask);
+ goto done;
+ }
+
/* The 2nd 256MB is mapped at 256<<20 instead of 0x410000000 */
if ((physical >= 0x410000000ull) && physical < 0x420000000ull)
result = physical - 0x400000000ull;
diff --git a/arch/mips/cavium-octeon/octeon-irq.c b/arch/mips/cavium-octeon/octeon-irq.c
index c424cd158dc..ce7500cdf5b 100644
--- a/arch/mips/cavium-octeon/octeon-irq.c
+++ b/arch/mips/cavium-octeon/octeon-irq.c
@@ -3,15 +3,13 @@
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
- * Copyright (C) 2004-2008 Cavium Networks
+ * Copyright (C) 2004-2008, 2009, 2010 Cavium Networks
*/
#include <linux/irq.h>
#include <linux/interrupt.h>
#include <linux/smp.h>
#include <asm/octeon/octeon.h>
-#include <asm/octeon/cvmx-pexp-defs.h>
-#include <asm/octeon/cvmx-npi-defs.h>
static DEFINE_RAW_SPINLOCK(octeon_irq_ciu0_lock);
static DEFINE_RAW_SPINLOCK(octeon_irq_ciu1_lock);
@@ -41,14 +39,14 @@ static void octeon_irq_core_ack(unsigned int irq)
static void octeon_irq_core_eoi(unsigned int irq)
{
- struct irq_desc *desc = irq_desc + irq;
+ struct irq_desc *desc = irq_to_desc(irq);
unsigned int bit = irq - OCTEON_IRQ_SW0;
/*
* If an IRQ is being processed while we are disabling it the
* handler will attempt to unmask the interrupt after it has
* been disabled.
*/
- if (desc->status & IRQ_DISABLED)
+ if ((unlikely(desc->status & IRQ_DISABLED)))
return;
/*
* We don't need to disable IRQs to make these atomic since
@@ -106,6 +104,29 @@ static struct irq_chip octeon_irq_chip_core = {
static void octeon_irq_ciu0_ack(unsigned int irq)
{
+ switch (irq) {
+ case OCTEON_IRQ_GMX_DRP0:
+ case OCTEON_IRQ_GMX_DRP1:
+ case OCTEON_IRQ_IPD_DRP:
+ case OCTEON_IRQ_KEY_ZERO:
+ case OCTEON_IRQ_TIMER0:
+ case OCTEON_IRQ_TIMER1:
+ case OCTEON_IRQ_TIMER2:
+ case OCTEON_IRQ_TIMER3:
+ {
+ int index = cvmx_get_core_num() * 2;
+ u64 mask = 1ull << (irq - OCTEON_IRQ_WORKQ0);
+ /*
+ * CIU timer type interrupts must be acknoleged by
+ * writing a '1' bit to their sum0 bit.
+ */
+ cvmx_write_csr(CVMX_CIU_INTX_SUM0(index), mask);
+ break;
+ }
+ default:
+ break;
+ }
+
/*
* In order to avoid any locking accessing the CIU, we
* acknowledge CIU interrupts by disabling all of them. This
@@ -130,8 +151,54 @@ static void octeon_irq_ciu0_eoi(unsigned int irq)
set_c0_status(0x100 << 2);
}
+static int next_coreid_for_irq(struct irq_desc *desc)
+{
+
+#ifdef CONFIG_SMP
+ int coreid;
+ int weight = cpumask_weight(desc->affinity);
+
+ if (weight > 1) {
+ int cpu = smp_processor_id();
+ for (;;) {
+ cpu = cpumask_next(cpu, desc->affinity);
+ if (cpu >= nr_cpu_ids) {
+ cpu = -1;
+ continue;
+ } else if (cpumask_test_cpu(cpu, cpu_online_mask)) {
+ break;
+ }
+ }
+ coreid = octeon_coreid_for_cpu(cpu);
+ } else if (weight == 1) {
+ coreid = octeon_coreid_for_cpu(cpumask_first(desc->affinity));
+ } else {
+ coreid = cvmx_get_core_num();
+ }
+ return coreid;
+#else
+ return cvmx_get_core_num();
+#endif
+}
+
static void octeon_irq_ciu0_enable(unsigned int irq)
{
+ struct irq_desc *desc = irq_to_desc(irq);
+ int coreid = next_coreid_for_irq(desc);
+ unsigned long flags;
+ uint64_t en0;
+ int bit = irq - OCTEON_IRQ_WORKQ0; /* Bit 0-63 of EN0 */
+
+ raw_spin_lock_irqsave(&octeon_irq_ciu0_lock, flags);
+ en0 = cvmx_read_csr(CVMX_CIU_INTX_EN0(coreid * 2));
+ en0 |= 1ull << bit;
+ cvmx_write_csr(CVMX_CIU_INTX_EN0(coreid * 2), en0);
+ cvmx_read_csr(CVMX_CIU_INTX_EN0(coreid * 2));
+ raw_spin_unlock_irqrestore(&octeon_irq_ciu0_lock, flags);
+}
+
+static void octeon_irq_ciu0_enable_mbox(unsigned int irq)
+{
int coreid = cvmx_get_core_num();
unsigned long flags;
uint64_t en0;
@@ -167,63 +234,76 @@ static void octeon_irq_ciu0_disable(unsigned int irq)
}
/*
- * Enable the irq on the current core for chips that have the EN*_W1{S,C}
- * registers.
+ * Enable the irq on the next core in the affinity set for chips that
+ * have the EN*_W1{S,C} registers.
*/
static void octeon_irq_ciu0_enable_v2(unsigned int irq)
{
- int index = cvmx_get_core_num() * 2;
+ int index;
u64 mask = 1ull << (irq - OCTEON_IRQ_WORKQ0);
+ struct irq_desc *desc = irq_to_desc(irq);
- cvmx_write_csr(CVMX_CIU_INTX_EN0_W1S(index), mask);
+ if ((desc->status & IRQ_DISABLED) == 0) {
+ index = next_coreid_for_irq(desc) * 2;
+ cvmx_write_csr(CVMX_CIU_INTX_EN0_W1S(index), mask);
+ }
}
/*
- * Disable the irq on the current core for chips that have the EN*_W1{S,C}
- * registers.
+ * Enable the irq on the current CPU for chips that
+ * have the EN*_W1{S,C} registers.
*/
-static void octeon_irq_ciu0_ack_v2(unsigned int irq)
+static void octeon_irq_ciu0_enable_mbox_v2(unsigned int irq)
{
- int index = cvmx_get_core_num() * 2;
+ int index;
u64 mask = 1ull << (irq - OCTEON_IRQ_WORKQ0);
- cvmx_write_csr(CVMX_CIU_INTX_EN0_W1C(index), mask);
+ index = cvmx_get_core_num() * 2;
+ cvmx_write_csr(CVMX_CIU_INTX_EN0_W1S(index), mask);
}
/*
- * CIU timer type interrupts must be acknoleged by writing a '1' bit
- * to their sum0 bit.
+ * Disable the irq on the current core for chips that have the EN*_W1{S,C}
+ * registers.
*/
-static void octeon_irq_ciu0_timer_ack(unsigned int irq)
+static void octeon_irq_ciu0_ack_v2(unsigned int irq)
{
int index = cvmx_get_core_num() * 2;
- uint64_t mask = 1ull << (irq - OCTEON_IRQ_WORKQ0);
- cvmx_write_csr(CVMX_CIU_INTX_SUM0(index), mask);
-}
+ u64 mask = 1ull << (irq - OCTEON_IRQ_WORKQ0);
-static void octeon_irq_ciu0_timer_ack_v1(unsigned int irq)
-{
- octeon_irq_ciu0_timer_ack(irq);
- octeon_irq_ciu0_ack(irq);
-}
+ switch (irq) {
+ case OCTEON_IRQ_GMX_DRP0:
+ case OCTEON_IRQ_GMX_DRP1:
+ case OCTEON_IRQ_IPD_DRP:
+ case OCTEON_IRQ_KEY_ZERO:
+ case OCTEON_IRQ_TIMER0:
+ case OCTEON_IRQ_TIMER1:
+ case OCTEON_IRQ_TIMER2:
+ case OCTEON_IRQ_TIMER3:
+ /*
+ * CIU timer type interrupts must be acknoleged by
+ * writing a '1' bit to their sum0 bit.
+ */
+ cvmx_write_csr(CVMX_CIU_INTX_SUM0(index), mask);
+ break;
+ default:
+ break;
+ }
-static void octeon_irq_ciu0_timer_ack_v2(unsigned int irq)
-{
- octeon_irq_ciu0_timer_ack(irq);
- octeon_irq_ciu0_ack_v2(irq);
+ cvmx_write_csr(CVMX_CIU_INTX_EN0_W1C(index), mask);
}
/*
* Enable the irq on the current core for chips that have the EN*_W1{S,C}
* registers.
*/
-static void octeon_irq_ciu0_eoi_v2(unsigned int irq)
+static void octeon_irq_ciu0_eoi_mbox_v2(unsigned int irq)
{
- struct irq_desc *desc = irq_desc + irq;
+ struct irq_desc *desc = irq_to_desc(irq);
int index = cvmx_get_core_num() * 2;
u64 mask = 1ull << (irq - OCTEON_IRQ_WORKQ0);
- if ((desc->status & IRQ_DISABLED) == 0)
+ if (likely((desc->status & IRQ_DISABLED) == 0))
cvmx_write_csr(CVMX_CIU_INTX_EN0_W1S(index), mask);
}
@@ -246,18 +326,30 @@ static void octeon_irq_ciu0_disable_all_v2(unsigned int irq)
static int octeon_irq_ciu0_set_affinity(unsigned int irq, const struct cpumask *dest)
{
int cpu;
+ struct irq_desc *desc = irq_to_desc(irq);
+ int enable_one = (desc->status & IRQ_DISABLED) == 0;
unsigned long flags;
int bit = irq - OCTEON_IRQ_WORKQ0; /* Bit 0-63 of EN0 */
+ /*
+ * For non-v2 CIU, we will allow only single CPU affinity.
+ * This removes the need to do locking in the .ack/.eoi
+ * functions.
+ */
+ if (cpumask_weight(dest) != 1)
+ return -EINVAL;
+
raw_spin_lock_irqsave(&octeon_irq_ciu0_lock, flags);
for_each_online_cpu(cpu) {
int coreid = octeon_coreid_for_cpu(cpu);
uint64_t en0 =
cvmx_read_csr(CVMX_CIU_INTX_EN0(coreid * 2));
- if (cpumask_test_cpu(cpu, dest))
+ if (cpumask_test_cpu(cpu, dest) && enable_one) {
+ enable_one = 0;
en0 |= 1ull << bit;
- else
+ } else {
en0 &= ~(1ull << bit);
+ }
cvmx_write_csr(CVMX_CIU_INTX_EN0(coreid * 2), en0);
}
/*
@@ -279,13 +371,18 @@ static int octeon_irq_ciu0_set_affinity_v2(unsigned int irq,
{
int cpu;
int index;
+ struct irq_desc *desc = irq_to_desc(irq);
+ int enable_one = (desc->status & IRQ_DISABLED) == 0;
u64 mask = 1ull << (irq - OCTEON_IRQ_WORKQ0);
+
for_each_online_cpu(cpu) {
index = octeon_coreid_for_cpu(cpu) * 2;
- if (cpumask_test_cpu(cpu, dest))
+ if (cpumask_test_cpu(cpu, dest) && enable_one) {
+ enable_one = 0;
cvmx_write_csr(CVMX_CIU_INTX_EN0_W1S(index), mask);
- else
+ } else {
cvmx_write_csr(CVMX_CIU_INTX_EN0_W1C(index), mask);
+ }
}
return 0;
}
@@ -298,8 +395,7 @@ static struct irq_chip octeon_irq_chip_ciu0_v2 = {
.name = "CIU0",
.enable = octeon_irq_ciu0_enable_v2,
.disable = octeon_irq_ciu0_disable_all_v2,
- .ack = octeon_irq_ciu0_ack_v2,
- .eoi = octeon_irq_ciu0_eoi_v2,
+ .eoi = octeon_irq_ciu0_enable_v2,
#ifdef CONFIG_SMP
.set_affinity = octeon_irq_ciu0_set_affinity_v2,
#endif
@@ -309,36 +405,27 @@ static struct irq_chip octeon_irq_chip_ciu0 = {
.name = "CIU0",
.enable = octeon_irq_ciu0_enable,
.disable = octeon_irq_ciu0_disable,
- .ack = octeon_irq_ciu0_ack,
.eoi = octeon_irq_ciu0_eoi,
#ifdef CONFIG_SMP
.set_affinity = octeon_irq_ciu0_set_affinity,
#endif
};
-static struct irq_chip octeon_irq_chip_ciu0_timer_v2 = {
- .name = "CIU0-T",
- .enable = octeon_irq_ciu0_enable_v2,
- .disable = octeon_irq_ciu0_disable_all_v2,
- .ack = octeon_irq_ciu0_timer_ack_v2,
- .eoi = octeon_irq_ciu0_eoi_v2,
-#ifdef CONFIG_SMP
- .set_affinity = octeon_irq_ciu0_set_affinity_v2,
-#endif
+/* The mbox versions don't do any affinity or round-robin. */
+static struct irq_chip octeon_irq_chip_ciu0_mbox_v2 = {
+ .name = "CIU0-M",
+ .enable = octeon_irq_ciu0_enable_mbox_v2,
+ .disable = octeon_irq_ciu0_disable,
+ .eoi = octeon_irq_ciu0_eoi_mbox_v2,
};
-static struct irq_chip octeon_irq_chip_ciu0_timer = {
- .name = "CIU0-T",
- .enable = octeon_irq_ciu0_enable,
+static struct irq_chip octeon_irq_chip_ciu0_mbox = {
+ .name = "CIU0-M",
+ .enable = octeon_irq_ciu0_enable_mbox,
.disable = octeon_irq_ciu0_disable,
- .ack = octeon_irq_ciu0_timer_ack_v1,
.eoi = octeon_irq_ciu0_eoi,
-#ifdef CONFIG_SMP
- .set_affinity = octeon_irq_ciu0_set_affinity,
-#endif
};
-
static void octeon_irq_ciu1_ack(unsigned int irq)
{
/*
@@ -365,10 +452,30 @@ static void octeon_irq_ciu1_eoi(unsigned int irq)
static void octeon_irq_ciu1_enable(unsigned int irq)
{
- int coreid = cvmx_get_core_num();
+ struct irq_desc *desc = irq_to_desc(irq);
+ int coreid = next_coreid_for_irq(desc);
+ unsigned long flags;
+ uint64_t en1;
+ int bit = irq - OCTEON_IRQ_WDOG0; /* Bit 0-63 of EN1 */
+
+ raw_spin_lock_irqsave(&octeon_irq_ciu1_lock, flags);
+ en1 = cvmx_read_csr(CVMX_CIU_INTX_EN1(coreid * 2 + 1));
+ en1 |= 1ull << bit;
+ cvmx_write_csr(CVMX_CIU_INTX_EN1(coreid * 2 + 1), en1);
+ cvmx_read_csr(CVMX_CIU_INTX_EN1(coreid * 2 + 1));
+ raw_spin_unlock_irqrestore(&octeon_irq_ciu1_lock, flags);
+}
+
+/*
+ * Watchdog interrupts are special. They are associated with a single
+ * core, so we hardwire the affinity to that core.
+ */
+static void octeon_irq_ciu1_wd_enable(unsigned int irq)
+{
unsigned long flags;
uint64_t en1;
int bit = irq - OCTEON_IRQ_WDOG0; /* Bit 0-63 of EN1 */
+ int coreid = bit;
raw_spin_lock_irqsave(&octeon_irq_ciu1_lock, flags);
en1 = cvmx_read_csr(CVMX_CIU_INTX_EN1(coreid * 2 + 1));
@@ -405,36 +512,43 @@ static void octeon_irq_ciu1_disable(unsigned int irq)
*/
static void octeon_irq_ciu1_enable_v2(unsigned int irq)
{
- int index = cvmx_get_core_num() * 2 + 1;
+ int index;
u64 mask = 1ull << (irq - OCTEON_IRQ_WDOG0);
+ struct irq_desc *desc = irq_to_desc(irq);
- cvmx_write_csr(CVMX_CIU_INTX_EN1_W1S(index), mask);
+ if ((desc->status & IRQ_DISABLED) == 0) {
+ index = next_coreid_for_irq(desc) * 2 + 1;
+ cvmx_write_csr(CVMX_CIU_INTX_EN1_W1S(index), mask);
+ }
}
/*
- * Disable the irq on the current core for chips that have the EN*_W1{S,C}
- * registers.
+ * Watchdog interrupts are special. They are associated with a single
+ * core, so we hardwire the affinity to that core.
*/
-static void octeon_irq_ciu1_ack_v2(unsigned int irq)
+static void octeon_irq_ciu1_wd_enable_v2(unsigned int irq)
{
- int index = cvmx_get_core_num() * 2 + 1;
+ int index;
+ int coreid = irq - OCTEON_IRQ_WDOG0;
u64 mask = 1ull << (irq - OCTEON_IRQ_WDOG0);
+ struct irq_desc *desc = irq_to_desc(irq);
- cvmx_write_csr(CVMX_CIU_INTX_EN1_W1C(index), mask);
+ if ((desc->status & IRQ_DISABLED) == 0) {
+ index = coreid * 2 + 1;
+ cvmx_write_csr(CVMX_CIU_INTX_EN1_W1S(index), mask);
+ }
}
/*
- * Enable the irq on the current core for chips that have the EN*_W1{S,C}
+ * Disable the irq on the current core for chips that have the EN*_W1{S,C}
* registers.
*/
-static void octeon_irq_ciu1_eoi_v2(unsigned int irq)
+static void octeon_irq_ciu1_ack_v2(unsigned int irq)
{
- struct irq_desc *desc = irq_desc + irq;
int index = cvmx_get_core_num() * 2 + 1;
u64 mask = 1ull << (irq - OCTEON_IRQ_WDOG0);
- if ((desc->status & IRQ_DISABLED) == 0)
- cvmx_write_csr(CVMX_CIU_INTX_EN1_W1S(index), mask);
+ cvmx_write_csr(CVMX_CIU_INTX_EN1_W1C(index), mask);
}
/*
@@ -457,19 +571,30 @@ static int octeon_irq_ciu1_set_affinity(unsigned int irq,
const struct cpumask *dest)
{
int cpu;
+ struct irq_desc *desc = irq_to_desc(irq);
+ int enable_one = (desc->status & IRQ_DISABLED) == 0;
unsigned long flags;
int bit = irq - OCTEON_IRQ_WDOG0; /* Bit 0-63 of EN1 */
+ /*
+ * For non-v2 CIU, we will allow only single CPU affinity.
+ * This removes the need to do locking in the .ack/.eoi
+ * functions.
+ */
+ if (cpumask_weight(dest) != 1)
+ return -EINVAL;
+
raw_spin_lock_irqsave(&octeon_irq_ciu1_lock, flags);
for_each_online_cpu(cpu) {
int coreid = octeon_coreid_for_cpu(cpu);
uint64_t en1 =
- cvmx_read_csr(CVMX_CIU_INTX_EN1
- (coreid * 2 + 1));
- if (cpumask_test_cpu(cpu, dest))
+ cvmx_read_csr(CVMX_CIU_INTX_EN1(coreid * 2 + 1));
+ if (cpumask_test_cpu(cpu, dest) && enable_one) {
+ enable_one = 0;
en1 |= 1ull << bit;
- else
+ } else {
en1 &= ~(1ull << bit);
+ }
cvmx_write_csr(CVMX_CIU_INTX_EN1(coreid * 2 + 1), en1);
}
/*
@@ -491,13 +616,17 @@ static int octeon_irq_ciu1_set_affinity_v2(unsigned int irq,
{
int cpu;
int index;
+ struct irq_desc *desc = irq_to_desc(irq);
+ int enable_one = (desc->status & IRQ_DISABLED) == 0;
u64 mask = 1ull << (irq - OCTEON_IRQ_WDOG0);
for_each_online_cpu(cpu) {
index = octeon_coreid_for_cpu(cpu) * 2 + 1;
- if (cpumask_test_cpu(cpu, dest))
+ if (cpumask_test_cpu(cpu, dest) && enable_one) {
+ enable_one = 0;
cvmx_write_csr(CVMX_CIU_INTX_EN1_W1S(index), mask);
- else
+ } else {
cvmx_write_csr(CVMX_CIU_INTX_EN1_W1C(index), mask);
+ }
}
return 0;
}
@@ -507,11 +636,10 @@ static int octeon_irq_ciu1_set_affinity_v2(unsigned int irq,
* Newer octeon chips have support for lockless CIU operation.
*/
static struct irq_chip octeon_irq_chip_ciu1_v2 = {
- .name = "CIU0",
+ .name = "CIU1",
.enable = octeon_irq_ciu1_enable_v2,
.disable = octeon_irq_ciu1_disable_all_v2,
- .ack = octeon_irq_ciu1_ack_v2,
- .eoi = octeon_irq_ciu1_eoi_v2,
+ .eoi = octeon_irq_ciu1_enable_v2,
#ifdef CONFIG_SMP
.set_affinity = octeon_irq_ciu1_set_affinity_v2,
#endif
@@ -521,103 +649,36 @@ static struct irq_chip octeon_irq_chip_ciu1 = {
.name = "CIU1",
.enable = octeon_irq_ciu1_enable,
.disable = octeon_irq_ciu1_disable,
- .ack = octeon_irq_ciu1_ack,
.eoi = octeon_irq_ciu1_eoi,
#ifdef CONFIG_SMP
.set_affinity = octeon_irq_ciu1_set_affinity,
#endif
};
-#ifdef CONFIG_PCI_MSI
-
-static DEFINE_RAW_SPINLOCK(octeon_irq_msi_lock);
-
-static void octeon_irq_msi_ack(unsigned int irq)
-{
- if (!octeon_has_feature(OCTEON_FEATURE_PCIE)) {
- /* These chips have PCI */
- cvmx_write_csr(CVMX_NPI_NPI_MSI_RCV,
- 1ull << (irq - OCTEON_IRQ_MSI_BIT0));
- } else {
- /*
- * These chips have PCIe. Thankfully the ACK doesn't
- * need any locking.
- */
- cvmx_write_csr(CVMX_PEXP_NPEI_MSI_RCV0,
- 1ull << (irq - OCTEON_IRQ_MSI_BIT0));
- }
-}
-
-static void octeon_irq_msi_eoi(unsigned int irq)
-{
- /* Nothing needed */
-}
-
-static void octeon_irq_msi_enable(unsigned int irq)
-{
- if (!octeon_has_feature(OCTEON_FEATURE_PCIE)) {
- /*
- * Octeon PCI doesn't have the ability to mask/unmask
- * MSI interrupts individually. Instead of
- * masking/unmasking them in groups of 16, we simple
- * assume MSI devices are well behaved. MSI
- * interrupts are always enable and the ACK is assumed
- * to be enough.
- */
- } else {
- /* These chips have PCIe. Note that we only support
- * the first 64 MSI interrupts. Unfortunately all the
- * MSI enables are in the same register. We use
- * MSI0's lock to control access to them all.
- */
- uint64_t en;
- unsigned long flags;
- raw_spin_lock_irqsave(&octeon_irq_msi_lock, flags);
- en = cvmx_read_csr(CVMX_PEXP_NPEI_MSI_ENB0);
- en |= 1ull << (irq - OCTEON_IRQ_MSI_BIT0);
- cvmx_write_csr(CVMX_PEXP_NPEI_MSI_ENB0, en);
- cvmx_read_csr(CVMX_PEXP_NPEI_MSI_ENB0);
- raw_spin_unlock_irqrestore(&octeon_irq_msi_lock, flags);
- }
-}
-
-static void octeon_irq_msi_disable(unsigned int irq)
-{
- if (!octeon_has_feature(OCTEON_FEATURE_PCIE)) {
- /* See comment in enable */
- } else {
- /*
- * These chips have PCIe. Note that we only support
- * the first 64 MSI interrupts. Unfortunately all the
- * MSI enables are in the same register. We use
- * MSI0's lock to control access to them all.
- */
- uint64_t en;
- unsigned long flags;
- raw_spin_lock_irqsave(&octeon_irq_msi_lock, flags);
- en = cvmx_read_csr(CVMX_PEXP_NPEI_MSI_ENB0);
- en &= ~(1ull << (irq - OCTEON_IRQ_MSI_BIT0));
- cvmx_write_csr(CVMX_PEXP_NPEI_MSI_ENB0, en);
- cvmx_read_csr(CVMX_PEXP_NPEI_MSI_ENB0);
- raw_spin_unlock_irqrestore(&octeon_irq_msi_lock, flags);
- }
-}
+static struct irq_chip octeon_irq_chip_ciu1_wd_v2 = {
+ .name = "CIU1-W",
+ .enable = octeon_irq_ciu1_wd_enable_v2,
+ .disable = octeon_irq_ciu1_disable_all_v2,
+ .eoi = octeon_irq_ciu1_wd_enable_v2,
+};
-static struct irq_chip octeon_irq_chip_msi = {
- .name = "MSI",
- .enable = octeon_irq_msi_enable,
- .disable = octeon_irq_msi_disable,
- .ack = octeon_irq_msi_ack,
- .eoi = octeon_irq_msi_eoi,
+static struct irq_chip octeon_irq_chip_ciu1_wd = {
+ .name = "CIU1-W",
+ .enable = octeon_irq_ciu1_wd_enable,
+ .disable = octeon_irq_ciu1_disable,
+ .eoi = octeon_irq_ciu1_eoi,
};
-#endif
+
+static void (*octeon_ciu0_ack)(unsigned int);
+static void (*octeon_ciu1_ack)(unsigned int);
void __init arch_init_irq(void)
{
- int irq;
+ unsigned int irq;
struct irq_chip *chip0;
- struct irq_chip *chip0_timer;
+ struct irq_chip *chip0_mbox;
struct irq_chip *chip1;
+ struct irq_chip *chip1_wd;
#ifdef CONFIG_SMP
/* Set the default affinity to the boot cpu. */
@@ -631,13 +692,19 @@ void __init arch_init_irq(void)
if (OCTEON_IS_MODEL(OCTEON_CN58XX_PASS2_X) ||
OCTEON_IS_MODEL(OCTEON_CN56XX_PASS2_X) ||
OCTEON_IS_MODEL(OCTEON_CN52XX_PASS2_X)) {
+ octeon_ciu0_ack = octeon_irq_ciu0_ack_v2;
+ octeon_ciu1_ack = octeon_irq_ciu1_ack_v2;
chip0 = &octeon_irq_chip_ciu0_v2;
- chip0_timer = &octeon_irq_chip_ciu0_timer_v2;
+ chip0_mbox = &octeon_irq_chip_ciu0_mbox_v2;
chip1 = &octeon_irq_chip_ciu1_v2;
+ chip1_wd = &octeon_irq_chip_ciu1_wd_v2;
} else {
+ octeon_ciu0_ack = octeon_irq_ciu0_ack;
+ octeon_ciu1_ack = octeon_irq_ciu1_ack;
chip0 = &octeon_irq_chip_ciu0;
- chip0_timer = &octeon_irq_chip_ciu0_timer;
+ chip0_mbox = &octeon_irq_chip_ciu0_mbox;
chip1 = &octeon_irq_chip_ciu1;
+ chip1_wd = &octeon_irq_chip_ciu1_wd;
}
/* 0 - 15 reserved for i8259 master and slave controller. */
@@ -651,34 +718,23 @@ void __init arch_init_irq(void)
/* 24 - 87 CIU_INT_SUM0 */
for (irq = OCTEON_IRQ_WORKQ0; irq <= OCTEON_IRQ_BOOTDMA; irq++) {
switch (irq) {
- case OCTEON_IRQ_GMX_DRP0:
- case OCTEON_IRQ_GMX_DRP1:
- case OCTEON_IRQ_IPD_DRP:
- case OCTEON_IRQ_KEY_ZERO:
- case OCTEON_IRQ_TIMER0:
- case OCTEON_IRQ_TIMER1:
- case OCTEON_IRQ_TIMER2:
- case OCTEON_IRQ_TIMER3:
- set_irq_chip_and_handler(irq, chip0_timer, handle_percpu_irq);
+ case OCTEON_IRQ_MBOX0:
+ case OCTEON_IRQ_MBOX1:
+ set_irq_chip_and_handler(irq, chip0_mbox, handle_percpu_irq);
break;
default:
- set_irq_chip_and_handler(irq, chip0, handle_percpu_irq);
+ set_irq_chip_and_handler(irq, chip0, handle_fasteoi_irq);
break;
}
}
/* 88 - 151 CIU_INT_SUM1 */
- for (irq = OCTEON_IRQ_WDOG0; irq <= OCTEON_IRQ_RESERVED151; irq++) {
- set_irq_chip_and_handler(irq, chip1, handle_percpu_irq);
- }
+ for (irq = OCTEON_IRQ_WDOG0; irq <= OCTEON_IRQ_WDOG15; irq++)
+ set_irq_chip_and_handler(irq, chip1_wd, handle_fasteoi_irq);
+
+ for (irq = OCTEON_IRQ_UART2; irq <= OCTEON_IRQ_RESERVED151; irq++)
+ set_irq_chip_and_handler(irq, chip1, handle_fasteoi_irq);
-#ifdef CONFIG_PCI_MSI
- /* 152 - 215 PCI/PCIe MSI interrupts */
- for (irq = OCTEON_IRQ_MSI_BIT0; irq <= OCTEON_IRQ_MSI_BIT63; irq++) {
- set_irq_chip_and_handler(irq, &octeon_irq_chip_msi,
- handle_percpu_irq);
- }
-#endif
set_c0_status(0x300 << 2);
}
@@ -693,6 +749,7 @@ asmlinkage void plat_irq_dispatch(void)
unsigned long cop0_status;
uint64_t ciu_en;
uint64_t ciu_sum;
+ unsigned int irq;
while (1) {
cop0_cause = read_c0_cause();
@@ -704,18 +761,24 @@ asmlinkage void plat_irq_dispatch(void)
ciu_sum = cvmx_read_csr(ciu_sum0_address);
ciu_en = cvmx_read_csr(ciu_en0_address);
ciu_sum &= ciu_en;
- if (likely(ciu_sum))
- do_IRQ(fls64(ciu_sum) + OCTEON_IRQ_WORKQ0 - 1);
- else
+ if (likely(ciu_sum)) {
+ irq = fls64(ciu_sum) + OCTEON_IRQ_WORKQ0 - 1;
+ octeon_ciu0_ack(irq);
+ do_IRQ(irq);
+ } else {
spurious_interrupt();
+ }
} else if (unlikely(cop0_cause & STATUSF_IP3)) {
ciu_sum = cvmx_read_csr(ciu_sum1_address);
ciu_en = cvmx_read_csr(ciu_en1_address);
ciu_sum &= ciu_en;
- if (likely(ciu_sum))
- do_IRQ(fls64(ciu_sum) + OCTEON_IRQ_WDOG0 - 1);
- else
+ if (likely(ciu_sum)) {
+ irq = fls64(ciu_sum) + OCTEON_IRQ_WDOG0 - 1;
+ octeon_ciu1_ack(irq);
+ do_IRQ(irq);
+ } else {
spurious_interrupt();
+ }
} else if (likely(cop0_cause)) {
do_IRQ(fls(cop0_cause) - 9 + MIPS_CPU_IRQ_BASE);
} else {
@@ -725,54 +788,84 @@ asmlinkage void plat_irq_dispatch(void)
}
#ifdef CONFIG_HOTPLUG_CPU
-static int is_irq_enabled_on_cpu(unsigned int irq, unsigned int cpu)
-{
- unsigned int isset;
- int coreid = octeon_coreid_for_cpu(cpu);
- int bit = (irq < OCTEON_IRQ_WDOG0) ?
- irq - OCTEON_IRQ_WORKQ0 : irq - OCTEON_IRQ_WDOG0;
- if (irq < 64) {
- isset = (cvmx_read_csr(CVMX_CIU_INTX_EN0(coreid * 2)) &
- (1ull << bit)) >> bit;
- } else {
- isset = (cvmx_read_csr(CVMX_CIU_INTX_EN1(coreid * 2 + 1)) &
- (1ull << bit)) >> bit;
- }
- return isset;
-}
void fixup_irqs(void)
{
- int irq;
+ int irq;
+ struct irq_desc *desc;
+ cpumask_t new_affinity;
+ unsigned long flags;
+ int do_set_affinity;
+ int cpu;
+
+ cpu = smp_processor_id();
for (irq = OCTEON_IRQ_SW0; irq <= OCTEON_IRQ_TIMER; irq++)
octeon_irq_core_disable_local(irq);
- for (irq = OCTEON_IRQ_WORKQ0; irq <= OCTEON_IRQ_GPIO15; irq++) {
- if (is_irq_enabled_on_cpu(irq, smp_processor_id())) {
- /* ciu irq migrates to next cpu */
- octeon_irq_chip_ciu0.disable(irq);
- octeon_irq_ciu0_set_affinity(irq, &cpu_online_map);
- }
- }
-
-#if 0
- for (irq = OCTEON_IRQ_MBOX0; irq <= OCTEON_IRQ_MBOX1; irq++)
- octeon_irq_mailbox_mask(irq);
-#endif
- for (irq = OCTEON_IRQ_UART0; irq <= OCTEON_IRQ_BOOTDMA; irq++) {
- if (is_irq_enabled_on_cpu(irq, smp_processor_id())) {
- /* ciu irq migrates to next cpu */
- octeon_irq_chip_ciu0.disable(irq);
- octeon_irq_ciu0_set_affinity(irq, &cpu_online_map);
- }
- }
+ for (irq = OCTEON_IRQ_WORKQ0; irq < OCTEON_IRQ_LAST; irq++) {
+ desc = irq_to_desc(irq);
+ switch (irq) {
+ case OCTEON_IRQ_MBOX0:
+ case OCTEON_IRQ_MBOX1:
+ /* The eoi function will disable them on this CPU. */
+ desc->chip->eoi(irq);
+ break;
+ case OCTEON_IRQ_WDOG0:
+ case OCTEON_IRQ_WDOG1:
+ case OCTEON_IRQ_WDOG2:
+ case OCTEON_IRQ_WDOG3:
+ case OCTEON_IRQ_WDOG4:
+ case OCTEON_IRQ_WDOG5:
+ case OCTEON_IRQ_WDOG6:
+ case OCTEON_IRQ_WDOG7:
+ case OCTEON_IRQ_WDOG8:
+ case OCTEON_IRQ_WDOG9:
+ case OCTEON_IRQ_WDOG10:
+ case OCTEON_IRQ_WDOG11:
+ case OCTEON_IRQ_WDOG12:
+ case OCTEON_IRQ_WDOG13:
+ case OCTEON_IRQ_WDOG14:
+ case OCTEON_IRQ_WDOG15:
+ /*
+ * These have special per CPU semantics and
+ * are handled in the watchdog driver.
+ */
+ break;
+ default:
+ raw_spin_lock_irqsave(&desc->lock, flags);
+ /*
+ * If this irq has an action, it is in use and
+ * must be migrated if it has affinity to this
+ * cpu.
+ */
+ if (desc->action && cpumask_test_cpu(cpu, desc->affinity)) {
+ if (cpumask_weight(desc->affinity) > 1) {
+ /*
+ * It has multi CPU affinity,
+ * just remove this CPU from
+ * the affinity set.
+ */
+ cpumask_copy(&new_affinity, desc->affinity);
+ cpumask_clear_cpu(cpu, &new_affinity);
+ } else {
+ /*
+ * Otherwise, put it on lowest
+ * numbered online CPU.
+ */
+ cpumask_clear(&new_affinity);
+ cpumask_set_cpu(cpumask_first(cpu_online_mask), &new_affinity);
+ }
+ do_set_affinity = 1;
+ } else {
+ do_set_affinity = 0;
+ }
+ raw_spin_unlock_irqrestore(&desc->lock, flags);
+
+ if (do_set_affinity)
+ irq_set_affinity(irq, &new_affinity);
- for (irq = OCTEON_IRQ_UART2; irq <= OCTEON_IRQ_RESERVED135; irq++) {
- if (is_irq_enabled_on_cpu(irq, smp_processor_id())) {
- /* ciu irq migrates to next cpu */
- octeon_irq_chip_ciu1.disable(irq);
- octeon_irq_ciu1_set_affinity(irq, &cpu_online_map);
+ break;
}
}
}
diff --git a/arch/mips/cavium-octeon/octeon_boot.h b/arch/mips/cavium-octeon/octeon_boot.h
index 0f7f84accf9..428864b2ba4 100644
--- a/arch/mips/cavium-octeon/octeon_boot.h
+++ b/arch/mips/cavium-octeon/octeon_boot.h
@@ -23,14 +23,16 @@
#include <linux/types.h>
struct boot_init_vector {
- uint32_t stack_addr;
- uint32_t code_addr;
+ /* First stage address - in ram instead of flash */
+ uint64_t code_addr;
+ /* Setup code for application, NOT application entry point */
uint32_t app_start_func_addr;
+ /* k0 is used for global data - needs to be passed to other cores */
uint32_t k0_val;
- uint32_t flags;
- uint32_t boot_info_addr;
+ /* Address of boot info block structure */
+ uint64_t boot_info_addr;
+ uint32_t flags; /* flags */
uint32_t pad;
- uint32_t pad2;
};
/* similar to bootloader's linux_app_boot_info but without global data */
@@ -40,7 +42,7 @@ struct linux_app_boot_info {
uint32_t avail_coremask;
uint32_t pci_console_active;
uint32_t icache_prefetch_disable;
- uint32_t InitTLBStart_addr;
+ uint64_t InitTLBStart_addr;
uint32_t start_app_addr;
uint32_t cur_exception_base;
uint32_t no_mark_private_data;
@@ -58,7 +60,7 @@ struct linux_app_boot_info {
#define LINUX_APP_BOOT_BLOCK_NAME "linux-app-boot"
-#define LABI_SIGNATURE 0xAABBCCDD
+#define LABI_SIGNATURE 0xAABBCC01
/* from uboot-headers/octeon_mem_map.h */
#define EXCEPTION_BASE_INCR (4 * 1024)
diff --git a/arch/mips/cavium-octeon/serial.c b/arch/mips/cavium-octeon/serial.c
index 83eac37a1ff..638adab0284 100644
--- a/arch/mips/cavium-octeon/serial.c
+++ b/arch/mips/cavium-octeon/serial.c
@@ -18,11 +18,7 @@
#include <asm/octeon/octeon.h>
-#ifdef CONFIG_GDB_CONSOLE
-#define DEBUG_UART 0
-#else
#define DEBUG_UART 1
-#endif
unsigned int octeon_serial_in(struct uart_port *up, int offset)
{
diff --git a/arch/mips/cavium-octeon/setup.c b/arch/mips/cavium-octeon/setup.c
index d1b5ffaf028..69197cb6c7e 100644
--- a/arch/mips/cavium-octeon/setup.c
+++ b/arch/mips/cavium-octeon/setup.c
@@ -32,6 +32,7 @@
#include <asm/time.h>
#include <asm/octeon/octeon.h>
+#include <asm/octeon/pci-octeon.h>
#ifdef CONFIG_CAVIUM_DECODE_RSL
extern void cvmx_interrupt_rsl_decode(void);
@@ -578,9 +579,6 @@ void __init prom_init(void)
}
if (strstr(arcs_cmdline, "console=") == NULL) {
-#ifdef CONFIG_GDB_CONSOLE
- strcat(arcs_cmdline, " console=gdb");
-#else
#ifdef CONFIG_CAVIUM_OCTEON_2ND_KERNEL
strcat(arcs_cmdline, " console=ttyS0,115200");
#else
@@ -589,7 +587,6 @@ void __init prom_init(void)
else
strcat(arcs_cmdline, " console=ttyS0,115200");
#endif
-#endif
}
if (octeon_is_simulation()) {
@@ -598,13 +595,13 @@ void __init prom_init(void)
* the filesystem. Also specify the calibration delay
* to avoid calculating it every time.
*/
- strcat(arcs_cmdline, " rw root=1f00"
- " lpj=60176 slram=root,0x40000000,+1073741824");
+ strcat(arcs_cmdline, " rw root=1f00 slram=root,0x40000000,+1073741824");
}
mips_hpt_frequency = octeon_get_clock_rate();
octeon_init_cvmcount();
+ octeon_setup_delays();
_machine_restart = octeon_restart;
_machine_halt = octeon_halt;
@@ -613,6 +610,22 @@ void __init prom_init(void)
register_smp_ops(&octeon_smp_ops);
}
+/* Exclude a single page from the regions obtained in plat_mem_setup. */
+static __init void memory_exclude_page(u64 addr, u64 *mem, u64 *size)
+{
+ if (addr > *mem && addr < *mem + *size) {
+ u64 inc = addr - *mem;
+ add_memory_region(*mem, inc, BOOT_MEM_RAM);
+ *mem += inc;
+ *size -= inc;
+ }
+
+ if (addr == *mem && *size > PAGE_SIZE) {
+ *mem += PAGE_SIZE;
+ *size -= PAGE_SIZE;
+ }
+}
+
void __init plat_mem_setup(void)
{
uint64_t mem_alloc_size;
@@ -663,12 +676,27 @@ void __init plat_mem_setup(void)
CVMX_BOOTMEM_FLAG_NO_LOCKING);
#endif
if (memory >= 0) {
+ u64 size = mem_alloc_size;
+
+ /*
+ * exclude a page at the beginning and end of
+ * the 256MB PCIe 'hole' so the kernel will not
+ * try to allocate multi-page buffers that
+ * span the discontinuity.
+ */
+ memory_exclude_page(CVMX_PCIE_BAR1_PHYS_BASE,
+ &memory, &size);
+ memory_exclude_page(CVMX_PCIE_BAR1_PHYS_BASE +
+ CVMX_PCIE_BAR1_PHYS_SIZE,
+ &memory, &size);
+
/*
* This function automatically merges address
* regions next to each other if they are
* received in incrementing order.
*/
- add_memory_region(memory, mem_alloc_size, BOOT_MEM_RAM);
+ if (size)
+ add_memory_region(memory, size, BOOT_MEM_RAM);
total += mem_alloc_size;
} else {
break;
@@ -691,7 +719,10 @@ void __init plat_mem_setup(void)
"cvmx_bootmem_phy_alloc\n");
}
-
+/*
+ * Emit one character to the boot UART. Exported for use by the
+ * watchdog timer.
+ */
int prom_putchar(char c)
{
uint64_t lsrval;
@@ -705,6 +736,7 @@ int prom_putchar(char c)
cvmx_write_csr(CVMX_MIO_UARTX_THR(octeon_uart), c & 0xffull);
return 1;
}
+EXPORT_SYMBOL(prom_putchar);
void prom_free_prom_memory(void)
{
diff --git a/arch/mips/cavium-octeon/smp.c b/arch/mips/cavium-octeon/smp.c
index 6d99b9d8887..391cefe556b 100644
--- a/arch/mips/cavium-octeon/smp.c
+++ b/arch/mips/cavium-octeon/smp.c
@@ -3,7 +3,7 @@
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
- * Copyright (C) 2004-2008 Cavium Networks
+ * Copyright (C) 2004-2008, 2009, 2010 Cavium Networks
*/
#include <linux/cpu.h>
#include <linux/init.h>
@@ -27,7 +27,8 @@ volatile unsigned long octeon_processor_sp;
volatile unsigned long octeon_processor_gp;
#ifdef CONFIG_HOTPLUG_CPU
-static unsigned int InitTLBStart_addr;
+uint64_t octeon_bootloader_entry_addr;
+EXPORT_SYMBOL(octeon_bootloader_entry_addr);
#endif
static irqreturn_t mailbox_interrupt(int irq, void *dev_id)
@@ -80,20 +81,13 @@ static inline void octeon_send_ipi_mask(const struct cpumask *mask,
static void octeon_smp_hotplug_setup(void)
{
#ifdef CONFIG_HOTPLUG_CPU
- uint32_t labi_signature;
-
- labi_signature =
- cvmx_read64_uint32(CVMX_ADD_SEG(CVMX_MIPS_SPACE_XKPHYS,
- LABI_ADDR_IN_BOOTLOADER +
- offsetof(struct linux_app_boot_info,
- labi_signature)));
- if (labi_signature != LABI_SIGNATURE)
- pr_err("The bootloader version on this board is incorrect\n");
- InitTLBStart_addr =
- cvmx_read64_uint32(CVMX_ADD_SEG(CVMX_MIPS_SPACE_XKPHYS,
- LABI_ADDR_IN_BOOTLOADER +
- offsetof(struct linux_app_boot_info,
- InitTLBStart_addr)));
+ struct linux_app_boot_info *labi;
+
+ labi = (struct linux_app_boot_info *)PHYS_TO_XKSEG_CACHED(LABI_ADDR_IN_BOOTLOADER);
+ if (labi->labi_signature != LABI_SIGNATURE)
+ panic("The bootloader version on this board is incorrect.");
+
+ octeon_bootloader_entry_addr = labi->InitTLBStart_addr;
#endif
}
@@ -102,24 +96,47 @@ static void octeon_smp_setup(void)
const int coreid = cvmx_get_core_num();
int cpus;
int id;
-
int core_mask = octeon_get_boot_coremask();
+#ifdef CONFIG_HOTPLUG_CPU
+ unsigned int num_cores = cvmx_octeon_num_cores();
+#endif
+
+ /* The present CPUs are initially just the boot cpu (CPU 0). */
+ for (id = 0; id < NR_CPUS; id++) {
+ set_cpu_possible(id, id == 0);
+ set_cpu_present(id, id == 0);
+ }
- cpus_clear(cpu_possible_map);
__cpu_number_map[coreid] = 0;
__cpu_logical_map[0] = coreid;
- cpu_set(0, cpu_possible_map);
+ /* The present CPUs get the lowest CPU numbers. */
cpus = 1;
- for (id = 0; id < 16; id++) {
+ for (id = 0; id < NR_CPUS; id++) {
if ((id != coreid) && (core_mask & (1 << id))) {
- cpu_set(cpus, cpu_possible_map);
+ set_cpu_possible(cpus, true);
+ set_cpu_present(cpus, true);
__cpu_number_map[id] = cpus;
__cpu_logical_map[cpus] = id;
cpus++;
}
}
- cpu_present_map = cpu_possible_map;
+
+#ifdef CONFIG_HOTPLUG_CPU
+ /*
+ * The possible CPUs are all those present on the chip. We
+ * will assign CPU numbers for possible cores as well. Cores
+ * are always consecutively numberd from 0.
+ */
+ for (id = 0; id < num_cores && id < NR_CPUS; id++) {
+ if (!(core_mask & (1 << id))) {
+ set_cpu_possible(cpus, true);
+ __cpu_number_map[id] = cpus;
+ __cpu_logical_map[cpus] = id;
+ cpus++;
+ }
+ }
+#endif
octeon_smp_hotplug_setup();
}
@@ -158,18 +175,21 @@ static void octeon_init_secondary(void)
{
const int coreid = cvmx_get_core_num();
union cvmx_ciu_intx_sum0 interrupt_enable;
+ unsigned int sr;
#ifdef CONFIG_HOTPLUG_CPU
- unsigned int cur_exception_base;
-
- cur_exception_base = cvmx_read64_uint32(
- CVMX_ADD_SEG(CVMX_MIPS_SPACE_XKPHYS,
- LABI_ADDR_IN_BOOTLOADER +
- offsetof(struct linux_app_boot_info,
- cur_exception_base)));
- /* cur_exception_base is incremented in bootloader after setting */
- write_c0_ebase((unsigned int)(cur_exception_base - EXCEPTION_BASE_INCR));
+ struct linux_app_boot_info *labi;
+
+ labi = (struct linux_app_boot_info *)PHYS_TO_XKSEG_CACHED(LABI_ADDR_IN_BOOTLOADER);
+
+ if (labi->labi_signature != LABI_SIGNATURE)
+ panic("The bootloader version on this board is incorrect.");
#endif
+
+ sr = set_c0_status(ST0_BEV);
+ write_c0_ebase((u32)ebase);
+ write_c0_status(sr);
+
octeon_check_cpu_bist();
octeon_init_cvmcount();
/*
@@ -276,8 +296,8 @@ static int octeon_cpu_disable(void)
static void octeon_cpu_die(unsigned int cpu)
{
int coreid = cpu_logical_map(cpu);
- uint32_t avail_coremask;
- struct cvmx_bootmem_named_block_desc *block_desc;
+ uint32_t mask, new_mask;
+ const struct cvmx_bootmem_named_block_desc *block_desc;
while (per_cpu(cpu_state, cpu) != CPU_DEAD)
cpu_relax();
@@ -286,52 +306,40 @@ static void octeon_cpu_die(unsigned int cpu)
* This is a bit complicated strategics of getting/settig available
* cores mask, copied from bootloader
*/
+
+ mask = 1 << coreid;
/* LINUX_APP_BOOT_BLOCK is initialized in bootoct binary */
block_desc = cvmx_bootmem_find_named_block(LINUX_APP_BOOT_BLOCK_NAME);
if (!block_desc) {
- avail_coremask =
- cvmx_read64_uint32(CVMX_ADD_SEG(CVMX_MIPS_SPACE_XKPHYS,
- LABI_ADDR_IN_BOOTLOADER +
- offsetof
- (struct linux_app_boot_info,
- avail_coremask)));
- } else { /* alternative, already initialized */
- avail_coremask =
- cvmx_read64_uint32(CVMX_ADD_SEG(CVMX_MIPS_SPACE_XKPHYS,
- block_desc->base_addr +
- AVAIL_COREMASK_OFFSET_IN_LINUX_APP_BOOT_BLOCK));
- }
+ struct linux_app_boot_info *labi;
- avail_coremask |= 1 << coreid;
+ labi = (struct linux_app_boot_info *)PHYS_TO_XKSEG_CACHED(LABI_ADDR_IN_BOOTLOADER);
- /* Setting avail_coremask for bootoct binary */
- if (!block_desc) {
- cvmx_write64_uint32(CVMX_ADD_SEG(CVMX_MIPS_SPACE_XKPHYS,
- LABI_ADDR_IN_BOOTLOADER +
- offsetof(struct linux_app_boot_info,
- avail_coremask)),
- avail_coremask);
- } else {
- cvmx_write64_uint32(CVMX_ADD_SEG(CVMX_MIPS_SPACE_XKPHYS,
- block_desc->base_addr +
- AVAIL_COREMASK_OFFSET_IN_LINUX_APP_BOOT_BLOCK),
- avail_coremask);
+ labi->avail_coremask |= mask;
+ new_mask = labi->avail_coremask;
+ } else { /* alternative, already initialized */
+ uint32_t *p = (uint32_t *)PHYS_TO_XKSEG_CACHED(block_desc->base_addr +
+ AVAIL_COREMASK_OFFSET_IN_LINUX_APP_BOOT_BLOCK);
+ *p |= mask;
+ new_mask = *p;
}
- pr_info("Reset core %d. Available Coremask = %x\n", coreid,
- avail_coremask);
+ pr_info("Reset core %d. Available Coremask = 0x%x \n", coreid, new_mask);
+ mb();
cvmx_write_csr(CVMX_CIU_PP_RST, 1 << coreid);
cvmx_write_csr(CVMX_CIU_PP_RST, 0);
}
void play_dead(void)
{
- int coreid = cvmx_get_core_num();
+ int cpu = cpu_number_map(cvmx_get_core_num());
idle_task_exit();
octeon_processor_boot = 0xff;
- per_cpu(cpu_state, coreid) = CPU_DEAD;
+ per_cpu(cpu_state, cpu) = CPU_DEAD;
+
+ mb();
while (1) /* core will be reset here */
;
@@ -344,29 +352,27 @@ static void start_after_reset(void)
kernel_entry(0, 0, 0); /* set a2 = 0 for secondary core */
}
-int octeon_update_boot_vector(unsigned int cpu)
+static int octeon_update_boot_vector(unsigned int cpu)
{
int coreid = cpu_logical_map(cpu);
- unsigned int avail_coremask;
- struct cvmx_bootmem_named_block_desc *block_desc;
+ uint32_t avail_coremask;
+ const struct cvmx_bootmem_named_block_desc *block_desc;
struct boot_init_vector *boot_vect =
- (struct boot_init_vector *) cvmx_phys_to_ptr(0x0 +
- BOOTLOADER_BOOT_VECTOR);
+ (struct boot_init_vector *)PHYS_TO_XKSEG_CACHED(BOOTLOADER_BOOT_VECTOR);
block_desc = cvmx_bootmem_find_named_block(LINUX_APP_BOOT_BLOCK_NAME);
if (!block_desc) {
- avail_coremask =
- cvmx_read64_uint32(CVMX_ADD_SEG(CVMX_MIPS_SPACE_XKPHYS,
- LABI_ADDR_IN_BOOTLOADER +
- offsetof(struct linux_app_boot_info,
- avail_coremask)));
+ struct linux_app_boot_info *labi;
+
+ labi = (struct linux_app_boot_info *)PHYS_TO_XKSEG_CACHED(LABI_ADDR_IN_BOOTLOADER);
+
+ avail_coremask = labi->avail_coremask;
+ labi->avail_coremask &= ~(1 << coreid);
} else { /* alternative, already initialized */
- avail_coremask =
- cvmx_read64_uint32(CVMX_ADD_SEG(CVMX_MIPS_SPACE_XKPHYS,
- block_desc->base_addr +
- AVAIL_COREMASK_OFFSET_IN_LINUX_APP_BOOT_BLOCK));
+ avail_coremask = *(uint32_t *)PHYS_TO_XKSEG_CACHED(
+ block_desc->base_addr + AVAIL_COREMASK_OFFSET_IN_LINUX_APP_BOOT_BLOCK);
}
if (!(avail_coremask & (1 << coreid))) {
@@ -377,9 +383,9 @@ int octeon_update_boot_vector(unsigned int cpu)
boot_vect[coreid].app_start_func_addr =
(uint32_t) (unsigned long) start_after_reset;
- boot_vect[coreid].code_addr = InitTLBStart_addr;
+ boot_vect[coreid].code_addr = octeon_bootloader_entry_addr;
- CVMX_SYNC;
+ mb();
cvmx_write_csr(CVMX_CIU_NMI, (1 << coreid) & avail_coremask);
@@ -405,17 +411,11 @@ static int __cpuinit octeon_cpu_callback(struct notifier_block *nfb,
return NOTIFY_OK;
}
-static struct notifier_block __cpuinitdata octeon_cpu_notifier = {
- .notifier_call = octeon_cpu_callback,
-};
-
static int __cpuinit register_cavium_notifier(void)
{
- register_hotcpu_notifier(&octeon_cpu_notifier);
-
+ hotcpu_notifier(octeon_cpu_callback, 0);
return 0;
}
-
late_initcall(register_cavium_notifier);
#endif /* CONFIG_HOTPLUG_CPU */
diff --git a/arch/mips/cobalt/Makefile b/arch/mips/cobalt/Makefile
index 237926288d6..61a334ac43a 100644
--- a/arch/mips/cobalt/Makefile
+++ b/arch/mips/cobalt/Makefile
@@ -7,5 +7,3 @@ obj-y := buttons.o irq.o lcd.o led.o reset.o rtc.o serial.o setup.o time.o
obj-$(CONFIG_PCI) += pci.o
obj-$(CONFIG_EARLY_PRINTK) += console.o
obj-$(CONFIG_MTD_PHYSMAP) += mtd.o
-
-EXTRA_CFLAGS += -Werror
diff --git a/arch/mips/cobalt/Platform b/arch/mips/cobalt/Platform
new file mode 100644
index 00000000000..34123efd6df
--- /dev/null
+++ b/arch/mips/cobalt/Platform
@@ -0,0 +1,6 @@
+#
+# Cobalt Server
+#
+platform-$(CONFIG_MIPS_COBALT) += cobalt/
+cflags-$(CONFIG_MIPS_COBALT) += -I$(srctree)/arch/mips/include/asm/mach-cobalt
+load-$(CONFIG_MIPS_COBALT) += 0xffffffff80080000
diff --git a/arch/mips/configs/db1000_defconfig b/arch/mips/configs/db1000_defconfig
index f66d406aadc..3a9ec6ccd40 100644
--- a/arch/mips/configs/db1000_defconfig
+++ b/arch/mips/configs/db1000_defconfig
@@ -8,7 +8,7 @@ CONFIG_MIPS=y
#
# Machine selection
#
-CONFIG_MACH_ALCHEMY=y
+CONFIG_MIPS_ALCHEMY=y
# CONFIG_AR7 is not set
# CONFIG_BCM47XX is not set
# CONFIG_BCM63XX is not set
@@ -64,7 +64,6 @@ CONFIG_MIPS_DB1000=y
# CONFIG_MIPS_PB1550 is not set
# CONFIG_MIPS_XXS1500 is not set
CONFIG_SOC_AU1000=y
-CONFIG_SOC_AU1X00=y
CONFIG_LOONGSON_UART_BASE=y
CONFIG_RWSEM_GENERIC_SPINLOCK=y
# CONFIG_ARCH_HAS_ILOG2_U32 is not set
diff --git a/arch/mips/configs/db1100_defconfig b/arch/mips/configs/db1100_defconfig
index abb9a5805ad..4589b84301f 100644
--- a/arch/mips/configs/db1100_defconfig
+++ b/arch/mips/configs/db1100_defconfig
@@ -8,7 +8,7 @@ CONFIG_MIPS=y
#
# Machine selection
#
-CONFIG_MACH_ALCHEMY=y
+CONFIG_MIPS_ALCHEMY=y
# CONFIG_AR7 is not set
# CONFIG_BCM47XX is not set
# CONFIG_BCM63XX is not set
@@ -64,7 +64,6 @@ CONFIG_MIPS_DB1100=y
# CONFIG_MIPS_PB1550 is not set
# CONFIG_MIPS_XXS1500 is not set
CONFIG_SOC_AU1100=y
-CONFIG_SOC_AU1X00=y
CONFIG_LOONGSON_UART_BASE=y
CONFIG_RWSEM_GENERIC_SPINLOCK=y
# CONFIG_ARCH_HAS_ILOG2_U32 is not set
diff --git a/arch/mips/configs/db1200_defconfig b/arch/mips/configs/db1200_defconfig
index 991c20adf47..9950f2aabd3 100644
--- a/arch/mips/configs/db1200_defconfig
+++ b/arch/mips/configs/db1200_defconfig
@@ -8,7 +8,7 @@ CONFIG_MIPS=y
#
# Machine selection
#
-CONFIG_MACH_ALCHEMY=y
+CONFIG_MIPS_ALCHEMY=y
# CONFIG_AR7 is not set
# CONFIG_BCM47XX is not set
# CONFIG_BCM63XX is not set
@@ -64,7 +64,6 @@ CONFIG_MIPS_DB1200=y
# CONFIG_MIPS_PB1550 is not set
# CONFIG_MIPS_XXS1500 is not set
CONFIG_SOC_AU1200=y
-CONFIG_SOC_AU1X00=y
CONFIG_LOONGSON_UART_BASE=y
CONFIG_RWSEM_GENERIC_SPINLOCK=y
# CONFIG_ARCH_HAS_ILOG2_U32 is not set
diff --git a/arch/mips/configs/db1500_defconfig b/arch/mips/configs/db1500_defconfig
index 5424c9167bf..346ae631d1e 100644
--- a/arch/mips/configs/db1500_defconfig
+++ b/arch/mips/configs/db1500_defconfig
@@ -8,7 +8,7 @@ CONFIG_MIPS=y
#
# Machine selection
#
-CONFIG_MACH_ALCHEMY=y
+CONFIG_MIPS_ALCHEMY=y
# CONFIG_AR7 is not set
# CONFIG_BCM47XX is not set
# CONFIG_BCM63XX is not set
@@ -64,7 +64,6 @@ CONFIG_MIPS_DB1500=y
# CONFIG_MIPS_PB1550 is not set
# CONFIG_MIPS_XXS1500 is not set
CONFIG_SOC_AU1500=y
-CONFIG_SOC_AU1X00=y
CONFIG_LOONGSON_UART_BASE=y
CONFIG_RWSEM_GENERIC_SPINLOCK=y
# CONFIG_ARCH_HAS_ILOG2_U32 is not set
diff --git a/arch/mips/configs/db1550_defconfig b/arch/mips/configs/db1550_defconfig
index 949b6dcf634..10eafb942af 100644
--- a/arch/mips/configs/db1550_defconfig
+++ b/arch/mips/configs/db1550_defconfig
@@ -8,7 +8,7 @@ CONFIG_MIPS=y
#
# Machine selection
#
-CONFIG_MACH_ALCHEMY=y
+CONFIG_MIPS_ALCHEMY=y
# CONFIG_AR7 is not set
# CONFIG_BCM47XX is not set
# CONFIG_BCM63XX is not set
@@ -64,7 +64,6 @@ CONFIG_MIPS_DB1550=y
# CONFIG_MIPS_PB1550 is not set
# CONFIG_MIPS_XXS1500 is not set
CONFIG_SOC_AU1550=y
-CONFIG_SOC_AU1X00=y
CONFIG_LOONGSON_UART_BASE=y
CONFIG_RWSEM_GENERIC_SPINLOCK=y
# CONFIG_ARCH_HAS_ILOG2_U32 is not set
diff --git a/arch/mips/configs/gpr_defconfig b/arch/mips/configs/gpr_defconfig
new file mode 100644
index 00000000000..17e2e624d03
--- /dev/null
+++ b/arch/mips/configs/gpr_defconfig
@@ -0,0 +1,2060 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.35-rc6
+# Fri Jul 23 19:28:52 2010
+#
+CONFIG_MIPS=y
+
+#
+# Machine selection
+#
+CONFIG_MIPS_ALCHEMY=y
+# CONFIG_AR7 is not set
+# CONFIG_BCM47XX is not set
+# CONFIG_BCM63XX is not set
+# CONFIG_MIPS_COBALT is not set
+# CONFIG_MACH_DECSTATION is not set
+# CONFIG_MACH_JAZZ is not set
+# CONFIG_LASAT is not set
+# CONFIG_MACH_LOONGSON is not set
+# CONFIG_MIPS_MALTA is not set
+# CONFIG_MIPS_SIM is not set
+# CONFIG_NEC_MARKEINS is not set
+# CONFIG_MACH_VR41XX is not set
+# CONFIG_NXP_STB220 is not set
+# CONFIG_NXP_STB225 is not set
+# CONFIG_PNX8550_JBS is not set
+# CONFIG_PNX8550_STB810 is not set
+# CONFIG_PMC_MSP is not set
+# CONFIG_PMC_YOSEMITE is not set
+# CONFIG_POWERTV is not set
+# CONFIG_SGI_IP22 is not set
+# CONFIG_SGI_IP27 is not set
+# CONFIG_SGI_IP28 is not set
+# CONFIG_SGI_IP32 is not set
+# CONFIG_SIBYTE_CRHINE is not set
+# CONFIG_SIBYTE_CARMEL is not set
+# CONFIG_SIBYTE_CRHONE is not set
+# CONFIG_SIBYTE_RHONE is not set
+# CONFIG_SIBYTE_SWARM is not set
+# CONFIG_SIBYTE_LITTLESUR is not set
+# CONFIG_SIBYTE_SENTOSA is not set
+# CONFIG_SIBYTE_BIGSUR is not set
+# CONFIG_SNI_RM is not set
+# CONFIG_MACH_TX39XX is not set
+# CONFIG_MACH_TX49XX is not set
+# CONFIG_MIKROTIK_RB532 is not set
+# CONFIG_WR_PPMC is not set
+# CONFIG_CAVIUM_OCTEON_SIMULATOR is not set
+# CONFIG_CAVIUM_OCTEON_REFERENCE_BOARD is not set
+CONFIG_ALCHEMY_GPIOINT_AU1000=y
+# CONFIG_ALCHEMY_GPIO_INDIRECT is not set
+# CONFIG_MIPS_MTX1 is not set
+# CONFIG_MIPS_BOSPORUS is not set
+# CONFIG_MIPS_DB1000 is not set
+# CONFIG_MIPS_DB1100 is not set
+# CONFIG_MIPS_DB1200 is not set
+# CONFIG_MIPS_DB1500 is not set
+# CONFIG_MIPS_DB1550 is not set
+# CONFIG_MIPS_MIRAGE is not set
+# CONFIG_MIPS_PB1000 is not set
+# CONFIG_MIPS_PB1100 is not set
+# CONFIG_MIPS_PB1200 is not set
+# CONFIG_MIPS_PB1500 is not set
+# CONFIG_MIPS_PB1550 is not set
+# CONFIG_MIPS_XXS1500 is not set
+CONFIG_MIPS_GPR=y
+CONFIG_SOC_AU1550=y
+CONFIG_LOONGSON_UART_BASE=y
+# CONFIG_LOONGSON_MC146818 is not set
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
+CONFIG_ARCH_SUPPORTS_OPROFILE=y
+CONFIG_GENERIC_FIND_NEXT_BIT=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_GENERIC_TIME=y
+CONFIG_GENERIC_CMOS_UPDATE=y
+CONFIG_SCHED_OMIT_FRAME_POINTER=y
+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
+CONFIG_CEVT_R4K_LIB=y
+CONFIG_CSRC_R4K_LIB=y
+CONFIG_DMA_NONCOHERENT=y
+CONFIG_NEED_DMA_MAP_STATE=y
+CONFIG_SYS_HAS_EARLY_PRINTK=y
+CONFIG_MIPS_DISABLE_OBSOLETE_IDE=y
+# CONFIG_NO_IOPORT is not set
+CONFIG_GENERIC_GPIO=y
+# CONFIG_CPU_BIG_ENDIAN is not set
+CONFIG_CPU_LITTLE_ENDIAN=y
+CONFIG_SYS_SUPPORTS_APM_EMULATION=y
+CONFIG_SYS_SUPPORTS_LITTLE_ENDIAN=y
+CONFIG_IRQ_CPU=y
+CONFIG_MIPS_L1_CACHE_SHIFT=5
+
+#
+# CPU selection
+#
+# CONFIG_CPU_LOONGSON2E is not set
+# CONFIG_CPU_LOONGSON2F is not set
+CONFIG_CPU_MIPS32_R1=y
+# CONFIG_CPU_MIPS32_R2 is not set
+# CONFIG_CPU_MIPS64_R1 is not set
+# CONFIG_CPU_MIPS64_R2 is not set
+# CONFIG_CPU_R3000 is not set
+# CONFIG_CPU_TX39XX is not set
+# CONFIG_CPU_VR41XX is not set
+# CONFIG_CPU_R4300 is not set
+# CONFIG_CPU_R4X00 is not set
+# CONFIG_CPU_TX49XX is not set
+# CONFIG_CPU_R5000 is not set
+# CONFIG_CPU_R5432 is not set
+# CONFIG_CPU_R5500 is not set
+# CONFIG_CPU_R6000 is not set
+# CONFIG_CPU_NEVADA is not set
+# CONFIG_CPU_R8000 is not set
+# CONFIG_CPU_R10000 is not set
+# CONFIG_CPU_RM7000 is not set
+# CONFIG_CPU_RM9000 is not set
+# CONFIG_CPU_SB1 is not set
+# CONFIG_CPU_CAVIUM_OCTEON is not set
+CONFIG_SYS_SUPPORTS_ZBOOT=y
+CONFIG_SYS_HAS_CPU_MIPS32_R1=y
+CONFIG_CPU_MIPS32=y
+CONFIG_CPU_MIPSR1=y
+CONFIG_SYS_SUPPORTS_32BIT_KERNEL=y
+CONFIG_CPU_SUPPORTS_32BIT_KERNEL=y
+CONFIG_HARDWARE_WATCHPOINTS=y
+
+#
+# Kernel type
+#
+CONFIG_32BIT=y
+# CONFIG_64BIT is not set
+CONFIG_PAGE_SIZE_4KB=y
+# CONFIG_PAGE_SIZE_8KB is not set
+# CONFIG_PAGE_SIZE_16KB is not set
+# CONFIG_PAGE_SIZE_32KB is not set
+# CONFIG_PAGE_SIZE_64KB is not set
+CONFIG_CPU_HAS_PREFETCH=y
+CONFIG_MIPS_MT_DISABLED=y
+# CONFIG_MIPS_MT_SMP is not set
+# CONFIG_MIPS_MT_SMTC is not set
+CONFIG_64BIT_PHYS_ADDR=y
+CONFIG_ARCH_PHYS_ADDR_T_64BIT=y
+CONFIG_CPU_HAS_SYNC=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_CPU_SUPPORTS_HIGHMEM=y
+CONFIG_ARCH_FLATMEM_ENABLE=y
+CONFIG_ARCH_POPULATES_NODE_MAP=y
+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_PAGEFLAGS_EXTENDED=y
+CONFIG_SPLIT_PTLOCK_CPUS=4
+CONFIG_PHYS_ADDR_T_64BIT=y
+CONFIG_ZONE_DMA_FLAG=0
+CONFIG_VIRT_TO_BUS=y
+# CONFIG_KSM is not set
+CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
+CONFIG_TICK_ONESHOT=y
+# CONFIG_NO_HZ is not set
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
+# CONFIG_HZ_48 is not set
+# CONFIG_HZ_100 is not set
+# CONFIG_HZ_128 is not set
+CONFIG_HZ_250=y
+# CONFIG_HZ_256 is not set
+# CONFIG_HZ_1000 is not set
+# CONFIG_HZ_1024 is not set
+CONFIG_SYS_SUPPORTS_ARBIT_HZ=y
+CONFIG_HZ=250
+# CONFIG_PREEMPT_NONE is not set
+CONFIG_PREEMPT_VOLUNTARY=y
+# CONFIG_PREEMPT is not set
+# CONFIG_KEXEC is not set
+CONFIG_SECCOMP=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+CONFIG_CONSTRUCTORS=y
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_CROSS_COMPILE=""
+CONFIG_LOCALVERSION=""
+# CONFIG_LOCALVERSION_AUTO is not set
+CONFIG_HAVE_KERNEL_GZIP=y
+CONFIG_HAVE_KERNEL_BZIP2=y
+CONFIG_HAVE_KERNEL_LZMA=y
+CONFIG_HAVE_KERNEL_LZO=y
+CONFIG_KERNEL_GZIP=y
+# CONFIG_KERNEL_BZIP2 is not set
+# CONFIG_KERNEL_LZMA is not set
+# CONFIG_KERNEL_LZO is not set
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+CONFIG_POSIX_MQUEUE=y
+CONFIG_POSIX_MQUEUE_SYSCTL=y
+CONFIG_BSD_PROCESS_ACCT=y
+CONFIG_BSD_PROCESS_ACCT_V3=y
+# CONFIG_TASKSTATS is not set
+# CONFIG_AUDIT is not set
+
+#
+# RCU Subsystem
+#
+CONFIG_TREE_RCU=y
+# CONFIG_TREE_PREEMPT_RCU is not set
+# CONFIG_TINY_RCU is not set
+# CONFIG_RCU_TRACE is not set
+CONFIG_RCU_FANOUT=32
+# CONFIG_RCU_FANOUT_EXACT is not set
+# CONFIG_TREE_RCU_TRACE is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_LOG_BUF_SHIFT=17
+# CONFIG_CGROUPS is not set
+# CONFIG_SYSFS_DEPRECATED_V2 is not set
+CONFIG_RELAY=y
+# CONFIG_NAMESPACES is not set
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_RD_GZIP=y
+# CONFIG_RD_BZIP2 is not set
+# CONFIG_RD_LZMA is not set
+# CONFIG_RD_LZO is not set
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SYSCTL=y
+CONFIG_ANON_INODES=y
+CONFIG_EMBEDDED=y
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_PCSPKR_PLATFORM=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
+CONFIG_SHMEM=y
+CONFIG_AIO=y
+
+#
+# Kernel Performance Events And Counters
+#
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_PCI_QUIRKS=y
+CONFIG_COMPAT_BRK=y
+CONFIG_SLAB=y
+# CONFIG_SLUB is not set
+# CONFIG_SLOB is not set
+CONFIG_PROFILING=y
+# CONFIG_OPROFILE is not set
+CONFIG_HAVE_OPROFILE=y
+
+#
+# GCOV-based kernel profiling
+#
+# CONFIG_GCOV_KERNEL is not set
+# CONFIG_SLOW_WORK is not set
+CONFIG_HAVE_GENERIC_DMA_COHERENT=y
+CONFIG_SLABINFO=y
+CONFIG_RT_MUTEXES=y
+CONFIG_BASE_SMALL=0
+CONFIG_MODULES=y
+# CONFIG_MODULE_FORCE_LOAD is not set
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+CONFIG_BLOCK=y
+CONFIG_LBDAF=y
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_BLK_DEV_INTEGRITY is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_DEFAULT_DEADLINE is not set
+CONFIG_DEFAULT_CFQ=y
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="cfq"
+# CONFIG_INLINE_SPIN_TRYLOCK is not set
+# CONFIG_INLINE_SPIN_TRYLOCK_BH is not set
+# CONFIG_INLINE_SPIN_LOCK is not set
+# CONFIG_INLINE_SPIN_LOCK_BH is not set
+# CONFIG_INLINE_SPIN_LOCK_IRQ is not set
+# CONFIG_INLINE_SPIN_LOCK_IRQSAVE is not set
+CONFIG_INLINE_SPIN_UNLOCK=y
+# CONFIG_INLINE_SPIN_UNLOCK_BH is not set
+CONFIG_INLINE_SPIN_UNLOCK_IRQ=y
+# CONFIG_INLINE_SPIN_UNLOCK_IRQRESTORE is not set
+# CONFIG_INLINE_READ_TRYLOCK is not set
+# CONFIG_INLINE_READ_LOCK is not set
+# CONFIG_INLINE_READ_LOCK_BH is not set
+# CONFIG_INLINE_READ_LOCK_IRQ is not set
+# CONFIG_INLINE_READ_LOCK_IRQSAVE is not set
+CONFIG_INLINE_READ_UNLOCK=y
+# CONFIG_INLINE_READ_UNLOCK_BH is not set
+CONFIG_INLINE_READ_UNLOCK_IRQ=y
+# CONFIG_INLINE_READ_UNLOCK_IRQRESTORE is not set
+# CONFIG_INLINE_WRITE_TRYLOCK is not set
+# CONFIG_INLINE_WRITE_LOCK is not set
+# CONFIG_INLINE_WRITE_LOCK_BH is not set
+# CONFIG_INLINE_WRITE_LOCK_IRQ is not set
+# CONFIG_INLINE_WRITE_LOCK_IRQSAVE is not set
+CONFIG_INLINE_WRITE_UNLOCK=y
+# CONFIG_INLINE_WRITE_UNLOCK_BH is not set
+CONFIG_INLINE_WRITE_UNLOCK_IRQ=y
+# CONFIG_INLINE_WRITE_UNLOCK_IRQRESTORE is not set
+# CONFIG_MUTEX_SPIN_ON_OWNER is not set
+# CONFIG_FREEZER is not set
+
+#
+# Bus options (PCI, PCMCIA, EISA, ISA, TC)
+#
+CONFIG_HW_HAS_PCI=y
+CONFIG_PCI=y
+CONFIG_PCI_DOMAINS=y
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+# CONFIG_PCI_STUB is not set
+# CONFIG_PCI_IOV is not set
+CONFIG_MMU=y
+# CONFIG_PCCARD is not set
+# CONFIG_HOTPLUG_PCI is not set
+
+#
+# Executable file formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+# CONFIG_HAVE_AOUT is not set
+CONFIG_BINFMT_MISC=m
+CONFIG_TRAD_SIGNALS=y
+
+#
+# Power management options
+#
+CONFIG_ARCH_HIBERNATION_POSSIBLE=y
+CONFIG_ARCH_SUSPEND_POSSIBLE=y
+# CONFIG_PM is not set
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+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=y
+CONFIG_IP_ROUTE_MULTIPATH=y
+CONFIG_IP_ROUTE_VERBOSE=y
+CONFIG_IP_PNP=y
+# CONFIG_IP_PNP_DHCP is not set
+CONFIG_IP_PNP_BOOTP=y
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_IP_MROUTE is not set
+# CONFIG_ARPD is not set
+CONFIG_SYN_COOKIES=y
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+# CONFIG_INET_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+CONFIG_INET_LRO=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_NETWORK_SECMARK=y
+CONFIG_NETFILTER=y
+# CONFIG_NETFILTER_DEBUG is not set
+CONFIG_NETFILTER_ADVANCED=y
+CONFIG_BRIDGE_NETFILTER=y
+
+#
+# Core Netfilter Configuration
+#
+CONFIG_NETFILTER_NETLINK=m
+CONFIG_NETFILTER_NETLINK_QUEUE=m
+CONFIG_NETFILTER_NETLINK_LOG=m
+# CONFIG_NF_CONNTRACK is not set
+# CONFIG_NETFILTER_TPROXY is not set
+CONFIG_NETFILTER_XTABLES=m
+
+#
+# Xtables combined modules
+#
+CONFIG_NETFILTER_XT_MARK=m
+
+#
+# Xtables targets
+#
+CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m
+CONFIG_NETFILTER_XT_TARGET_DSCP=m
+CONFIG_NETFILTER_XT_TARGET_HL=m
+# CONFIG_NETFILTER_XT_TARGET_LED is not set
+CONFIG_NETFILTER_XT_TARGET_MARK=m
+# CONFIG_NETFILTER_XT_TARGET_NFLOG is not set
+CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m
+# CONFIG_NETFILTER_XT_TARGET_RATEEST is not set
+# CONFIG_NETFILTER_XT_TARGET_TEE is not set
+# CONFIG_NETFILTER_XT_TARGET_TRACE is not set
+CONFIG_NETFILTER_XT_TARGET_SECMARK=m
+# CONFIG_NETFILTER_XT_TARGET_TCPMSS is not set
+# CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP is not set
+
+#
+# Xtables matches
+#
+CONFIG_NETFILTER_XT_MATCH_COMMENT=m
+CONFIG_NETFILTER_XT_MATCH_DCCP=m
+CONFIG_NETFILTER_XT_MATCH_DSCP=m
+CONFIG_NETFILTER_XT_MATCH_ESP=m
+# CONFIG_NETFILTER_XT_MATCH_HASHLIMIT is not set
+CONFIG_NETFILTER_XT_MATCH_HL=m
+# CONFIG_NETFILTER_XT_MATCH_IPRANGE is not set
+CONFIG_NETFILTER_XT_MATCH_LENGTH=m
+CONFIG_NETFILTER_XT_MATCH_LIMIT=m
+CONFIG_NETFILTER_XT_MATCH_MAC=m
+CONFIG_NETFILTER_XT_MATCH_MARK=m
+CONFIG_NETFILTER_XT_MATCH_MULTIPORT=m
+# CONFIG_NETFILTER_XT_MATCH_OSF is not set
+# CONFIG_NETFILTER_XT_MATCH_OWNER is not set
+CONFIG_NETFILTER_XT_MATCH_PHYSDEV=m
+CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m
+CONFIG_NETFILTER_XT_MATCH_QUOTA=m
+# CONFIG_NETFILTER_XT_MATCH_RATEEST is not set
+CONFIG_NETFILTER_XT_MATCH_REALM=m
+# CONFIG_NETFILTER_XT_MATCH_RECENT is not set
+CONFIG_NETFILTER_XT_MATCH_SCTP=m
+CONFIG_NETFILTER_XT_MATCH_STATISTIC=m
+CONFIG_NETFILTER_XT_MATCH_STRING=m
+CONFIG_NETFILTER_XT_MATCH_TCPMSS=m
+# CONFIG_NETFILTER_XT_MATCH_TIME is not set
+# CONFIG_NETFILTER_XT_MATCH_U32 is not set
+CONFIG_IP_VS=m
+# CONFIG_IP_VS_DEBUG is not set
+CONFIG_IP_VS_TAB_BITS=12
+
+#
+# IPVS transport protocol load balancing support
+#
+CONFIG_IP_VS_PROTO_TCP=y
+CONFIG_IP_VS_PROTO_UDP=y
+CONFIG_IP_VS_PROTO_AH_ESP=y
+CONFIG_IP_VS_PROTO_ESP=y
+CONFIG_IP_VS_PROTO_AH=y
+# CONFIG_IP_VS_PROTO_SCTP is not set
+
+#
+# IPVS scheduler
+#
+CONFIG_IP_VS_RR=m
+CONFIG_IP_VS_WRR=m
+CONFIG_IP_VS_LC=m
+CONFIG_IP_VS_WLC=m
+CONFIG_IP_VS_LBLC=m
+CONFIG_IP_VS_LBLCR=m
+CONFIG_IP_VS_DH=m
+CONFIG_IP_VS_SH=m
+CONFIG_IP_VS_SED=m
+CONFIG_IP_VS_NQ=m
+
+#
+# IPVS application helper
+#
+CONFIG_IP_VS_FTP=m
+
+#
+# IP: Netfilter Configuration
+#
+# CONFIG_NF_DEFRAG_IPV4 is not set
+CONFIG_IP_NF_QUEUE=m
+CONFIG_IP_NF_IPTABLES=m
+CONFIG_IP_NF_MATCH_ADDRTYPE=m
+CONFIG_IP_NF_MATCH_AH=m
+CONFIG_IP_NF_MATCH_ECN=m
+CONFIG_IP_NF_MATCH_TTL=m
+CONFIG_IP_NF_FILTER=m
+CONFIG_IP_NF_TARGET_REJECT=m
+CONFIG_IP_NF_TARGET_LOG=m
+CONFIG_IP_NF_TARGET_ULOG=m
+CONFIG_IP_NF_MANGLE=m
+CONFIG_IP_NF_TARGET_ECN=m
+CONFIG_IP_NF_TARGET_TTL=m
+CONFIG_IP_NF_RAW=m
+CONFIG_IP_NF_ARPTABLES=m
+CONFIG_IP_NF_ARPFILTER=m
+CONFIG_IP_NF_ARP_MANGLE=m
+
+#
+# DECnet: Netfilter Configuration
+#
+CONFIG_DECNET_NF_GRABULATOR=m
+CONFIG_BRIDGE_NF_EBTABLES=m
+CONFIG_BRIDGE_EBT_BROUTE=m
+CONFIG_BRIDGE_EBT_T_FILTER=m
+CONFIG_BRIDGE_EBT_T_NAT=m
+CONFIG_BRIDGE_EBT_802_3=m
+CONFIG_BRIDGE_EBT_AMONG=m
+CONFIG_BRIDGE_EBT_ARP=m
+CONFIG_BRIDGE_EBT_IP=m
+CONFIG_BRIDGE_EBT_LIMIT=m
+CONFIG_BRIDGE_EBT_MARK=m
+CONFIG_BRIDGE_EBT_PKTTYPE=m
+CONFIG_BRIDGE_EBT_STP=m
+CONFIG_BRIDGE_EBT_VLAN=m
+CONFIG_BRIDGE_EBT_ARPREPLY=m
+CONFIG_BRIDGE_EBT_DNAT=m
+CONFIG_BRIDGE_EBT_MARK_T=m
+CONFIG_BRIDGE_EBT_REDIRECT=m
+CONFIG_BRIDGE_EBT_SNAT=m
+CONFIG_BRIDGE_EBT_LOG=m
+CONFIG_BRIDGE_EBT_ULOG=m
+# CONFIG_BRIDGE_EBT_NFLOG is not set
+CONFIG_IP_DCCP=m
+CONFIG_INET_DCCP_DIAG=m
+
+#
+# DCCP CCIDs Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_DCCP_CCID2_DEBUG is not set
+CONFIG_IP_DCCP_CCID3=y
+# CONFIG_IP_DCCP_CCID3_DEBUG is not set
+CONFIG_IP_DCCP_CCID3_RTO=100
+CONFIG_IP_DCCP_TFRC_LIB=y
+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
+# CONFIG_RDS is not set
+CONFIG_TIPC=m
+# CONFIG_TIPC_ADVANCED is not set
+# CONFIG_TIPC_DEBUG is not set
+CONFIG_ATM=y
+CONFIG_ATM_CLIP=y
+# CONFIG_ATM_CLIP_NO_ICMP is not set
+CONFIG_ATM_LANE=m
+CONFIG_ATM_MPOA=m
+CONFIG_ATM_BR2684=m
+# CONFIG_ATM_BR2684_IPFILTER is not set
+# CONFIG_L2TP is not set
+CONFIG_STP=m
+CONFIG_BRIDGE=m
+CONFIG_BRIDGE_IGMP_SNOOPING=y
+# CONFIG_NET_DSA is not set
+CONFIG_VLAN_8021Q=m
+# CONFIG_VLAN_8021Q_GVRP is not set
+CONFIG_DECNET=m
+# CONFIG_DECNET_ROUTER is not set
+CONFIG_LLC=m
+CONFIG_LLC2=m
+CONFIG_IPX=m
+# CONFIG_IPX_INTERN is not set
+CONFIG_ATALK=m
+CONFIG_DEV_APPLETALK=m
+CONFIG_IPDDP=m
+CONFIG_IPDDP_ENCAP=y
+CONFIG_IPDDP_DECAP=y
+CONFIG_X25=m
+CONFIG_LAPB=m
+CONFIG_ECONET=m
+CONFIG_ECONET_AUNUDP=y
+CONFIG_ECONET_NATIVE=y
+CONFIG_WAN_ROUTER=m
+# CONFIG_PHONET is not set
+# CONFIG_IEEE802154 is not set
+CONFIG_NET_SCHED=y
+
+#
+# Queueing/Scheduling
+#
+CONFIG_NET_SCH_CBQ=m
+CONFIG_NET_SCH_HTB=m
+CONFIG_NET_SCH_HFSC=m
+CONFIG_NET_SCH_ATM=m
+CONFIG_NET_SCH_PRIO=m
+# CONFIG_NET_SCH_MULTIQ is not set
+CONFIG_NET_SCH_RED=m
+CONFIG_NET_SCH_SFQ=m
+CONFIG_NET_SCH_TEQL=m
+CONFIG_NET_SCH_TBF=m
+CONFIG_NET_SCH_GRED=m
+CONFIG_NET_SCH_DSMARK=m
+CONFIG_NET_SCH_NETEM=m
+# CONFIG_NET_SCH_DRR is not set
+CONFIG_NET_SCH_INGRESS=m
+
+#
+# Classification
+#
+CONFIG_NET_CLS=y
+CONFIG_NET_CLS_BASIC=m
+CONFIG_NET_CLS_TCINDEX=m
+CONFIG_NET_CLS_ROUTE4=m
+CONFIG_NET_CLS_ROUTE=y
+CONFIG_NET_CLS_FW=m
+CONFIG_NET_CLS_U32=m
+# CONFIG_CLS_U32_PERF is not set
+CONFIG_CLS_U32_MARK=y
+CONFIG_NET_CLS_RSVP=m
+CONFIG_NET_CLS_RSVP6=m
+# CONFIG_NET_CLS_FLOW is not set
+CONFIG_NET_EMATCH=y
+CONFIG_NET_EMATCH_STACK=32
+CONFIG_NET_EMATCH_CMP=m
+CONFIG_NET_EMATCH_NBYTE=m
+CONFIG_NET_EMATCH_U32=m
+CONFIG_NET_EMATCH_META=m
+CONFIG_NET_EMATCH_TEXT=m
+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_IPT is not set
+# CONFIG_NET_ACT_NAT is not set
+# CONFIG_NET_ACT_PEDIT is not set
+# CONFIG_NET_ACT_SIMP is not set
+# CONFIG_NET_ACT_SKBEDIT is not set
+# CONFIG_NET_CLS_IND is not set
+CONFIG_NET_SCH_FIFO=y
+# CONFIG_DCB is not set
+
+#
+# Network testing
+#
+CONFIG_NET_PKTGEN=m
+CONFIG_HAMRADIO=y
+
+#
+# Packet Radio protocols
+#
+CONFIG_AX25=m
+# CONFIG_AX25_DAMA_SLAVE is not set
+CONFIG_NETROM=m
+CONFIG_ROSE=m
+
+#
+# AX.25 network device drivers
+#
+CONFIG_MKISS=m
+CONFIG_6PACK=m
+CONFIG_BPQETHER=m
+CONFIG_BAYCOM_SER_FDX=m
+CONFIG_BAYCOM_SER_HDX=m
+CONFIG_YAM=m
+# CONFIG_CAN is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_AF_RXRPC is not set
+CONFIG_FIB_RULES=y
+CONFIG_WIRELESS=y
+CONFIG_WEXT_CORE=y
+CONFIG_WEXT_PROC=y
+CONFIG_CFG80211=y
+# CONFIG_NL80211_TESTMODE is not set
+# CONFIG_CFG80211_DEVELOPER_WARNINGS is not set
+# CONFIG_CFG80211_REG_DEBUG is not set
+CONFIG_CFG80211_DEFAULT_PS=y
+# CONFIG_CFG80211_DEBUGFS is not set
+# CONFIG_CFG80211_INTERNAL_REGDB is not set
+CONFIG_CFG80211_WEXT=y
+CONFIG_WIRELESS_EXT_SYSFS=y
+# CONFIG_LIB80211 is not set
+CONFIG_MAC80211=y
+CONFIG_MAC80211_HAS_RC=y
+# CONFIG_MAC80211_RC_PID is not set
+CONFIG_MAC80211_RC_MINSTREL=y
+# CONFIG_MAC80211_RC_DEFAULT_PID is not set
+CONFIG_MAC80211_RC_DEFAULT_MINSTREL=y
+CONFIG_MAC80211_RC_DEFAULT="minstrel"
+# CONFIG_MAC80211_MESH is not set
+CONFIG_MAC80211_LEDS=y
+# CONFIG_MAC80211_DEBUGFS is not set
+# CONFIG_MAC80211_DEBUG_MENU is not set
+# CONFIG_WIMAX is not set
+# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
+# CONFIG_CAIF is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_UEVENT_HELPER_PATH=""
+# CONFIG_DEVTMPFS is not set
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+CONFIG_FW_LOADER=y
+CONFIG_FIRMWARE_IN_KERNEL=y
+CONFIG_EXTRA_FIRMWARE=""
+# CONFIG_SYS_HYPERVISOR is not set
+# CONFIG_CONNECTOR is not set
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+# CONFIG_MTD_TESTS is not set
+# CONFIG_MTD_CONCAT is not set
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_REDBOOT_PARTS is not set
+# CONFIG_MTD_CMDLINE_PARTS is not set
+# CONFIG_MTD_AR7_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=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
+# CONFIG_SM_FTL is not set
+# CONFIG_MTD_OOPS is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=y
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_GEN_PROBE=y
+# CONFIG_MTD_CFI_ADV_OPTIONS is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+CONFIG_MTD_CFI_INTELEXT=y
+CONFIG_MTD_CFI_AMDSTD=y
+# CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_CFI_UTIL=y
+CONFIG_MTD_RAM=m
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+
+#
+# Mapping drivers for chip access
+#
+CONFIG_MTD_COMPLEX_MAPPINGS=y
+CONFIG_MTD_PHYSMAP=y
+# CONFIG_MTD_PHYSMAP_COMPAT is not set
+# CONFIG_MTD_PCI is not set
+# CONFIG_MTD_GPIO_ADDR is not set
+# CONFIG_MTD_INTEL_VR_NOR is not set
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_PMC551 is not set
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+# CONFIG_MTD_NAND is not set
+# CONFIG_MTD_ONENAND is not set
+
+#
+# LPDDR flash memory drivers
+#
+# CONFIG_MTD_LPDDR is not set
+
+#
+# UBI - Unsorted block images
+#
+# CONFIG_MTD_UBI is not set
+# CONFIG_PARPORT is not set
+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
+# CONFIG_BLK_DEV_UMEM is not set
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+
+#
+# DRBD disabled because PROC_FS, INET or CONNECTOR not selected
+#
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_SX8 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=65536
+# CONFIG_BLK_DEV_XIP is not set
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+# CONFIG_BLK_DEV_HD is not set
+CONFIG_MISC_DEVICES=y
+# CONFIG_AD525X_DPOT is not set
+# CONFIG_PHANTOM is not set
+# CONFIG_SGI_IOC4 is not set
+CONFIG_TIFM_CORE=m
+CONFIG_TIFM_7XX1=m
+# CONFIG_ICS932S401 is not set
+# CONFIG_ENCLOSURE_SERVICES is not set
+# CONFIG_HP_ILO is not set
+# CONFIG_ISL29003 is not set
+# CONFIG_SENSORS_TSL2550 is not set
+# CONFIG_DS1682 is not set
+# CONFIG_C2PORT is not set
+
+#
+# EEPROM support
+#
+# CONFIG_EEPROM_AT24 is not set
+# CONFIG_EEPROM_LEGACY is not set
+# CONFIG_EEPROM_MAX6875 is not set
+# CONFIG_EEPROM_93CX6 is not set
+# CONFIG_CB710_CORE is not set
+CONFIG_HAVE_IDE=y
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+CONFIG_SCSI_MOD=m
+# CONFIG_RAID_ATTRS is not set
+CONFIG_SCSI=m
+CONFIG_SCSI_DMA=y
+# CONFIG_SCSI_TGT is not set
+CONFIG_SCSI_NETLINK=y
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=m
+# 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
+CONFIG_SCSI_MULTI_LUN=y
+# CONFIG_SCSI_CONSTANTS is not set
+CONFIG_SCSI_LOGGING=y
+# CONFIG_SCSI_SCAN_ASYNC is not set
+CONFIG_SCSI_WAIT_SCAN=m
+
+#
+# SCSI Transports
+#
+CONFIG_SCSI_SPI_ATTRS=m
+CONFIG_SCSI_FC_ATTRS=m
+CONFIG_SCSI_ISCSI_ATTRS=m
+CONFIG_SCSI_SAS_ATTRS=m
+CONFIG_SCSI_SAS_LIBSAS=m
+CONFIG_SCSI_SAS_HOST_SMP=y
+# CONFIG_SCSI_SAS_LIBSAS_DEBUG is not set
+# CONFIG_SCSI_SRP_ATTRS is not set
+# CONFIG_SCSI_LOWLEVEL is not set
+# CONFIG_SCSI_DH is not set
+# CONFIG_SCSI_OSD_INITIATOR is not set
+# CONFIG_ATA is not set
+# CONFIG_MD is not set
+# CONFIG_FUSION is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+
+#
+# You can enable one or both FireWire driver stacks.
+#
+
+#
+# The newer stack is recommended.
+#
+# CONFIG_FIREWIRE is not set
+# CONFIG_IEEE1394 is not set
+# CONFIG_I2O is not set
+CONFIG_NETDEVICES=y
+# CONFIG_IFB is not set
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_MACVLAN is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+# CONFIG_VETH is not set
+# CONFIG_ARCNET is not set
+CONFIG_PHYLIB=y
+
+#
+# MII PHY device drivers
+#
+CONFIG_MARVELL_PHY=m
+CONFIG_DAVICOM_PHY=m
+CONFIG_QSEMI_PHY=m
+CONFIG_LXT_PHY=m
+CONFIG_CICADA_PHY=m
+CONFIG_VITESSE_PHY=m
+CONFIG_SMSC_PHY=m
+# CONFIG_BROADCOM_PHY is not set
+# CONFIG_ICPLUS_PHY is not set
+# CONFIG_REALTEK_PHY is not set
+# CONFIG_NATIONAL_PHY is not set
+# CONFIG_STE10XP is not set
+# CONFIG_LSI_ET1011C_PHY is not set
+# CONFIG_MICREL_PHY is not set
+# CONFIG_FIXED_PHY is not set
+# CONFIG_MDIO_BITBANG is not set
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+# CONFIG_AX88796 is not set
+CONFIG_MIPS_AU1X00_ENET=y
+# 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
+# CONFIG_DM9000 is not set
+# CONFIG_ETHOC is not set
+# CONFIG_SMSC911X is not set
+# CONFIG_DNET is not set
+# CONFIG_NET_TULIP is not set
+# CONFIG_HP100 is not set
+# CONFIG_IBM_NEW_EMAC_ZMII is not set
+# CONFIG_IBM_NEW_EMAC_RGMII is not set
+# CONFIG_IBM_NEW_EMAC_TAH is not set
+# CONFIG_IBM_NEW_EMAC_EMAC4 is not set
+# CONFIG_IBM_NEW_EMAC_NO_FLOW_CTRL is not set
+# CONFIG_IBM_NEW_EMAC_MAL_CLR_ICINTSTAT is not set
+# CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set
+# CONFIG_NET_PCI is not set
+# CONFIG_B44 is not set
+# CONFIG_KS8842 is not set
+# CONFIG_KS8851_MLL is not set
+# CONFIG_ATL2 is not set
+# CONFIG_NETDEV_1000 is not set
+# CONFIG_NETDEV_10000 is not set
+# CONFIG_TR is not set
+CONFIG_WLAN=y
+# CONFIG_LIBERTAS_THINFIRM is not set
+# CONFIG_ATMEL is not set
+# CONFIG_AT76C50X_USB is not set
+# CONFIG_PRISM54 is not set
+# CONFIG_USB_ZD1201 is not set
+# CONFIG_USB_NET_RNDIS_WLAN is not set
+# CONFIG_RTL8180 is not set
+# CONFIG_RTL8187 is not set
+# CONFIG_ADM8211 is not set
+# CONFIG_MAC80211_HWSIM is not set
+# CONFIG_MWL8K is not set
+CONFIG_ATH_COMMON=y
+CONFIG_ATH_DEBUG=y
+CONFIG_ATH5K=y
+CONFIG_ATH5K_DEBUG=y
+# CONFIG_ATH9K is not set
+# CONFIG_ATH9K_HTC is not set
+# CONFIG_AR9170_USB is not set
+# CONFIG_B43 is not set
+# CONFIG_B43LEGACY is not set
+# CONFIG_HOSTAP is not set
+# CONFIG_IPW2100 is not set
+# CONFIG_IPW2200 is not set
+# CONFIG_IWLWIFI is not set
+# CONFIG_LIBERTAS is not set
+# CONFIG_HERMES is not set
+# CONFIG_P54_COMMON is not set
+# CONFIG_RT2X00 is not set
+# CONFIG_WL12XX is not set
+# CONFIG_ZD1211RW is not set
+
+#
+# Enable WiMAX (Networking options) to see the WiMAX drivers
+#
+
+#
+# USB Network Adapters
+#
+# CONFIG_USB_CATC is not set
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_RTL8150 is not set
+# CONFIG_USB_USBNET is not set
+# CONFIG_USB_IPHETH is not set
+CONFIG_WAN=y
+CONFIG_LANMEDIA=m
+CONFIG_HDLC=m
+CONFIG_HDLC_RAW=m
+CONFIG_HDLC_RAW_ETH=m
+CONFIG_HDLC_CISCO=m
+CONFIG_HDLC_FR=m
+CONFIG_HDLC_PPP=m
+CONFIG_HDLC_X25=m
+CONFIG_PCI200SYN=m
+CONFIG_WANXL=m
+# CONFIG_PC300TOO is not set
+CONFIG_FARSYNC=m
+CONFIG_DSCC4=m
+CONFIG_DSCC4_PCISYNC=y
+CONFIG_DSCC4_PCI_RST=y
+CONFIG_DLCI=m
+CONFIG_DLCI_MAX=8
+CONFIG_WAN_ROUTER_DRIVERS=m
+CONFIG_CYCLADES_SYNC=m
+CONFIG_CYCLOMX_X25=y
+CONFIG_LAPBETHER=m
+CONFIG_X25_ASY=m
+CONFIG_ATM_DRIVERS=y
+# CONFIG_ATM_DUMMY is not set
+CONFIG_ATM_TCP=m
+CONFIG_ATM_LANAI=m
+CONFIG_ATM_ENI=m
+# CONFIG_ATM_ENI_DEBUG is not set
+# CONFIG_ATM_ENI_TUNE_BURST is not set
+CONFIG_ATM_FIRESTREAM=m
+CONFIG_ATM_ZATM=m
+# CONFIG_ATM_ZATM_DEBUG is not set
+CONFIG_ATM_NICSTAR=m
+# CONFIG_ATM_NICSTAR_USE_SUNI is not set
+# CONFIG_ATM_NICSTAR_USE_IDT77105 is not set
+CONFIG_ATM_IDT77252=m
+# CONFIG_ATM_IDT77252_DEBUG is not set
+# CONFIG_ATM_IDT77252_RCV_ALL is not set
+CONFIG_ATM_IDT77252_USE_SUNI=y
+CONFIG_ATM_AMBASSADOR=m
+# CONFIG_ATM_AMBASSADOR_DEBUG is not set
+CONFIG_ATM_HORIZON=m
+# CONFIG_ATM_HORIZON_DEBUG is not set
+CONFIG_ATM_IA=m
+# CONFIG_ATM_IA_DEBUG is not set
+CONFIG_ATM_FORE200E=m
+# CONFIG_ATM_FORE200E_USE_TASKLET is not set
+CONFIG_ATM_FORE200E_TX_RETRY=16
+CONFIG_ATM_FORE200E_DEBUG=0
+CONFIG_ATM_HE=m
+CONFIG_ATM_HE_USE_SUNI=y
+# CONFIG_ATM_SOLOS is not set
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+CONFIG_PPP=m
+CONFIG_PPP_MULTILINK=y
+CONFIG_PPP_FILTER=y
+CONFIG_PPP_ASYNC=m
+CONFIG_PPP_SYNC_TTY=m
+CONFIG_PPP_DEFLATE=m
+CONFIG_PPP_BSDCOMP=m
+CONFIG_PPP_MPPE=m
+CONFIG_PPPOE=m
+CONFIG_PPPOATM=m
+CONFIG_SLIP=m
+CONFIG_SLIP_COMPRESSED=y
+CONFIG_SLHC=m
+CONFIG_SLIP_SMART=y
+CONFIG_SLIP_MODE_SLIP6=y
+CONFIG_NET_FC=y
+CONFIG_NETCONSOLE=m
+# CONFIG_NETCONSOLE_DYNAMIC is not set
+CONFIG_NETPOLL=y
+# CONFIG_NETPOLL_TRAP is not set
+CONFIG_NET_POLL_CONTROLLER=y
+# CONFIG_VMXNET3 is not set
+# CONFIG_ISDN is not set
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
+# CONFIG_INPUT_SPARSEKMAP is not set
+
+#
+# Userland interfaces
+#
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_CONSOLE_TRANSLATIONS=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+CONFIG_VT_HW_CONSOLE_BINDING=y
+CONFIG_DEVKMEM=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+# CONFIG_N_GSM is not set
+# CONFIG_NOZOMI is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+# CONFIG_SERIAL_8250_PCI is not set
+CONFIG_SERIAL_8250_NR_UARTS=4
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
+# CONFIG_SERIAL_8250_EXTENDED is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+# CONFIG_SERIAL_JSM is not set
+# CONFIG_SERIAL_TIMBERDALE is not set
+# CONFIG_SERIAL_ALTERA_JTAGUART is not set
+# CONFIG_SERIAL_ALTERA_UART is not set
+CONFIG_UNIX98_PTYS=y
+# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
+# CONFIG_IPMI_HANDLER is not set
+CONFIG_HW_RANDOM=y
+# CONFIG_HW_RANDOM_TIMERIOMEM is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_TCG_TPM is not set
+CONFIG_DEVPORT=y
+# CONFIG_RAMOOPS is not set
+CONFIG_I2C=y
+CONFIG_I2C_BOARDINFO=y
+CONFIG_I2C_COMPAT=y
+CONFIG_I2C_CHARDEV=y
+CONFIG_I2C_HELPER_AUTO=y
+CONFIG_I2C_ALGOBIT=y
+
+#
+# I2C Hardware Bus support
+#
+
+#
+# PC SMBus host controller drivers
+#
+# 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_ISCH is not set
+# CONFIG_I2C_PIIX4 is not set
+# CONFIG_I2C_NFORCE2 is not set
+# CONFIG_I2C_SIS5595 is not set
+# CONFIG_I2C_SIS630 is not set
+# CONFIG_I2C_SIS96X is not set
+# CONFIG_I2C_VIA is not set
+# CONFIG_I2C_VIAPRO is not set
+
+#
+# I2C system bus drivers (mostly embedded / system-on-chip)
+#
+# CONFIG_I2C_AU1550 is not set
+CONFIG_I2C_GPIO=y
+# CONFIG_I2C_OCORES is not set
+# CONFIG_I2C_PCA_PLATFORM is not set
+# CONFIG_I2C_SIMTEC is not set
+# CONFIG_I2C_XILINX is not set
+
+#
+# External I2C/SMBus adapter drivers
+#
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_TAOS_EVM is not set
+# CONFIG_I2C_TINY_USB is not set
+
+#
+# Other I2C/SMBus bus drivers
+#
+# CONFIG_I2C_STUB 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_SPI is not set
+
+#
+# PPS support
+#
+# CONFIG_PPS is not set
+CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
+CONFIG_GPIOLIB=y
+CONFIG_GPIO_SYSFS=y
+
+#
+# Memory mapped GPIO expanders:
+#
+# CONFIG_GPIO_IT8761E is not set
+# CONFIG_GPIO_SCH is not set
+
+#
+# I2C GPIO expanders:
+#
+# CONFIG_GPIO_MAX7300 is not set
+# CONFIG_GPIO_MAX732X is not set
+# CONFIG_GPIO_PCA953X is not set
+# CONFIG_GPIO_PCF857X is not set
+# CONFIG_GPIO_ADP5588 is not set
+
+#
+# PCI GPIO expanders:
+#
+# CONFIG_GPIO_CS5535 is not set
+# CONFIG_GPIO_BT8XX is not set
+# CONFIG_GPIO_LANGWELL is not set
+# CONFIG_GPIO_RDC321X is not set
+
+#
+# SPI GPIO expanders:
+#
+
+#
+# AC97 GPIO expanders:
+#
+
+#
+# MODULbus GPIO expanders:
+#
+# CONFIG_W1 is not set
+# CONFIG_POWER_SUPPLY is not set
+CONFIG_HWMON=y
+# CONFIG_HWMON_VID is not set
+# CONFIG_HWMON_DEBUG_CHIP is not set
+
+#
+# Native drivers
+#
+# CONFIG_SENSORS_AD7414 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_ADT7411 is not set
+# CONFIG_SENSORS_ADT7462 is not set
+# CONFIG_SENSORS_ADT7470 is not set
+# CONFIG_SENSORS_ADT7475 is not set
+# CONFIG_SENSORS_ASC7621 is not set
+# CONFIG_SENSORS_ATXP1 is not set
+# CONFIG_SENSORS_DS1621 is not set
+# CONFIG_SENSORS_I5K_AMB is not set
+# CONFIG_SENSORS_F71805F is not set
+# CONFIG_SENSORS_F71882FG is not set
+# CONFIG_SENSORS_F75375S is not set
+# CONFIG_SENSORS_G760A is not set
+# CONFIG_SENSORS_GL518SM is not set
+# CONFIG_SENSORS_GL520SM is not set
+# CONFIG_SENSORS_IT87 is not set
+# CONFIG_SENSORS_LM63 is not set
+# CONFIG_SENSORS_LM73 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=y
+# CONFIG_SENSORS_LM85 is not set
+# CONFIG_SENSORS_LM87 is not set
+# CONFIG_SENSORS_LM90 is not set
+# CONFIG_SENSORS_LM92 is not set
+# CONFIG_SENSORS_LM93 is not set
+# CONFIG_SENSORS_LTC4215 is not set
+# CONFIG_SENSORS_LTC4245 is not set
+# CONFIG_SENSORS_LM95241 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_PCF8591 is not set
+# CONFIG_SENSORS_SHT15 is not set
+# CONFIG_SENSORS_SIS5595 is not set
+# CONFIG_SENSORS_DME1737 is not set
+# CONFIG_SENSORS_EMC1403 is not set
+# CONFIG_SENSORS_SMSC47M1 is not set
+# CONFIG_SENSORS_SMSC47M192 is not set
+# CONFIG_SENSORS_SMSC47B397 is not set
+# CONFIG_SENSORS_ADS7828 is not set
+# CONFIG_SENSORS_AMC6821 is not set
+# CONFIG_SENSORS_THMC50 is not set
+# CONFIG_SENSORS_TMP102 is not set
+# CONFIG_SENSORS_TMP401 is not set
+# CONFIG_SENSORS_TMP421 is not set
+# 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_W83L786NG is not set
+# CONFIG_SENSORS_W83627HF is not set
+# CONFIG_SENSORS_W83627EHF is not set
+# CONFIG_SENSORS_LIS3_I2C is not set
+# CONFIG_THERMAL is not set
+CONFIG_WATCHDOG=y
+CONFIG_WATCHDOG_NOWAYOUT=y
+
+#
+# Watchdog Device Drivers
+#
+# CONFIG_SOFT_WATCHDOG is not set
+# CONFIG_ALIM7101_WDT is not set
+
+#
+# PCI-based Watchdog Cards
+#
+# CONFIG_PCIPCWATCHDOG is not set
+# CONFIG_WDTPCI is not set
+
+#
+# USB-based Watchdog Cards
+#
+# CONFIG_USBPCWATCHDOG is not set
+CONFIG_SSB_POSSIBLE=y
+
+#
+# Sonics Silicon Backplane
+#
+CONFIG_SSB=m
+CONFIG_SSB_SPROM=y
+CONFIG_SSB_PCIHOST_POSSIBLE=y
+CONFIG_SSB_PCIHOST=y
+# CONFIG_SSB_B43_PCI_BRIDGE is not set
+# CONFIG_SSB_SILENT is not set
+# CONFIG_SSB_DEBUG is not set
+CONFIG_SSB_DRIVER_PCICORE_POSSIBLE=y
+CONFIG_SSB_DRIVER_PCICORE=y
+# CONFIG_SSB_DRIVER_MIPS is not set
+CONFIG_MFD_SUPPORT=y
+# CONFIG_MFD_CORE is not set
+# CONFIG_MFD_88PM860X is not set
+# CONFIG_MFD_SM501 is not set
+# CONFIG_HTC_PASIC3 is not set
+# CONFIG_HTC_I2CPLD is not set
+# CONFIG_TPS65010 is not set
+# CONFIG_TPS6507X is not set
+# CONFIG_TWL4030_CORE is not set
+# CONFIG_MFD_TC35892 is not set
+# CONFIG_MFD_TMIO is not set
+# CONFIG_PMIC_DA903X is not set
+# CONFIG_PMIC_ADP5520 is not set
+# CONFIG_MFD_MAX8925 is not set
+# CONFIG_MFD_WM8400 is not set
+# CONFIG_MFD_WM831X is not set
+# CONFIG_MFD_WM8350_I2C is not set
+# CONFIG_MFD_WM8994 is not set
+# CONFIG_MFD_PCF50633 is not set
+# CONFIG_ABX500_CORE is not set
+# CONFIG_MFD_TIMBERDALE is not set
+# CONFIG_LPC_SCH is not set
+# CONFIG_MFD_RDC321X is not set
+# CONFIG_MFD_JANZ_CMODIO is not set
+# CONFIG_REGULATOR is not set
+# CONFIG_MEDIA_SUPPORT is not set
+
+#
+# Graphics support
+#
+# CONFIG_VGA_ARB is not set
+# CONFIG_DRM is not set
+# CONFIG_VGASTATE is not set
+# CONFIG_VIDEO_OUTPUT_CONTROL is not set
+# CONFIG_FB is not set
+CONFIG_BACKLIGHT_LCD_SUPPORT=y
+# CONFIG_LCD_CLASS_DEVICE is not set
+CONFIG_BACKLIGHT_CLASS_DEVICE=y
+# CONFIG_BACKLIGHT_GENERIC is not set
+# CONFIG_BACKLIGHT_ADP8860 is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+# CONFIG_SOUND is not set
+CONFIG_HID_SUPPORT=y
+CONFIG_HID=y
+# CONFIG_HIDRAW is not set
+
+#
+# USB Input Devices
+#
+CONFIG_USB_HID=m
+# CONFIG_HID_PID is not set
+CONFIG_USB_HIDDEV=y
+
+#
+# USB HID Boot Protocol drivers
+#
+CONFIG_USB_KBD=m
+CONFIG_USB_MOUSE=m
+
+#
+# Special HID drivers
+#
+# CONFIG_HID_3M_PCT is not set
+# CONFIG_HID_A4TECH is not set
+# CONFIG_HID_APPLE is not set
+# CONFIG_HID_BELKIN is not set
+# CONFIG_HID_CANDO is not set
+# CONFIG_HID_CHERRY is not set
+# CONFIG_HID_CHICONY is not set
+# CONFIG_HID_CYPRESS is not set
+# CONFIG_HID_DRAGONRISE is not set
+# CONFIG_HID_EGALAX is not set
+# CONFIG_HID_EZKEY is not set
+# CONFIG_HID_KYE is not set
+# CONFIG_HID_GYRATION is not set
+# CONFIG_HID_TWINHAN is not set
+# CONFIG_HID_KENSINGTON is not set
+# CONFIG_HID_LOGITECH is not set
+# CONFIG_HID_MICROSOFT is not set
+# CONFIG_HID_MOSART is not set
+# CONFIG_HID_MONTEREY is not set
+# CONFIG_HID_NTRIG is not set
+# CONFIG_HID_ORTEK is not set
+# CONFIG_HID_PANTHERLORD is not set
+# CONFIG_HID_PETALYNX is not set
+# CONFIG_HID_PICOLCD is not set
+# CONFIG_HID_QUANTA is not set
+# CONFIG_HID_ROCCAT is not set
+# CONFIG_HID_ROCCAT_KONE is not set
+# CONFIG_HID_SAMSUNG is not set
+# CONFIG_HID_SONY is not set
+# CONFIG_HID_STANTUM is not set
+# CONFIG_HID_SUNPLUS is not set
+# CONFIG_HID_GREENASIA is not set
+# CONFIG_HID_SMARTJOYPLUS is not set
+# CONFIG_HID_TOPSEED is not set
+# CONFIG_HID_THRUSTMASTER is not set
+# CONFIG_HID_ZEROPLUS is not set
+# CONFIG_HID_ZYDACRON 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
+CONFIG_USB=y
+# CONFIG_USB_DEBUG is not set
+# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set
+
+#
+# Miscellaneous USB options
+#
+# CONFIG_USB_DEVICEFS is not set
+# CONFIG_USB_DEVICE_CLASS is not set
+# CONFIG_USB_DYNAMIC_MINORS is not set
+# CONFIG_USB_OTG_WHITELIST is not set
+# CONFIG_USB_OTG_BLACKLIST_HUB is not set
+CONFIG_USB_MON=y
+# CONFIG_USB_WUSB is not set
+# CONFIG_USB_WUSB_CBAF is not set
+
+#
+# USB Host Controller Drivers
+#
+# CONFIG_USB_C67X00_HCD is not set
+# CONFIG_USB_XHCI_HCD is not set
+CONFIG_USB_EHCI_HCD=y
+CONFIG_USB_EHCI_ROOT_HUB_TT=y
+CONFIG_USB_EHCI_TT_NEWSCHED=y
+# CONFIG_USB_OXU210HP_HCD is not set
+# CONFIG_USB_ISP116X_HCD is not set
+# CONFIG_USB_ISP1760_HCD is not set
+# CONFIG_USB_ISP1362_HCD is not set
+CONFIG_USB_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_UHCI_HCD is not set
+# CONFIG_USB_SL811_HCD is not set
+# CONFIG_USB_R8A66597_HCD is not set
+# CONFIG_USB_WHCI_HCD is not set
+# CONFIG_USB_HWA_HCD is not set
+
+#
+# USB Device Class drivers
+#
+# CONFIG_USB_ACM is not set
+# CONFIG_USB_PRINTER is not set
+# CONFIG_USB_WDM is not set
+# CONFIG_USB_TMC is not set
+
+#
+# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may
+#
+
+#
+# also be needed; see USB_STORAGE Help for more info
+#
+CONFIG_USB_STORAGE=m
+# CONFIG_USB_STORAGE_DEBUG is not set
+# CONFIG_USB_STORAGE_DATAFAB is not set
+# CONFIG_USB_STORAGE_FREECOM is not set
+# CONFIG_USB_STORAGE_ISD200 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_ONETOUCH is not set
+# CONFIG_USB_STORAGE_KARMA is not set
+# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set
+CONFIG_USB_LIBUSUAL=y
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_MICROTEK is not set
+
+#
+# USB port drivers
+#
+CONFIG_USB_SERIAL=y
+# CONFIG_USB_SERIAL_CONSOLE is not set
+CONFIG_USB_EZUSB=y
+CONFIG_USB_SERIAL_GENERIC=y
+# CONFIG_USB_SERIAL_AIRCABLE is not set
+# CONFIG_USB_SERIAL_ARK3116 is not set
+# CONFIG_USB_SERIAL_BELKIN is not set
+# CONFIG_USB_SERIAL_CH341 is not set
+# CONFIG_USB_SERIAL_WHITEHEAT is not set
+# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set
+# CONFIG_USB_SERIAL_CP210X is not set
+# CONFIG_USB_SERIAL_CYPRESS_M8 is not set
+# CONFIG_USB_SERIAL_EMPEG is not set
+# CONFIG_USB_SERIAL_FTDI_SIO is not set
+# CONFIG_USB_SERIAL_FUNSOFT is not set
+# CONFIG_USB_SERIAL_VISOR is not set
+# CONFIG_USB_SERIAL_IPAQ is not set
+# CONFIG_USB_SERIAL_IR is not set
+# CONFIG_USB_SERIAL_EDGEPORT is not set
+# CONFIG_USB_SERIAL_EDGEPORT_TI is not set
+# CONFIG_USB_SERIAL_GARMIN is not set
+# CONFIG_USB_SERIAL_IPW is not set
+# CONFIG_USB_SERIAL_IUU is not set
+# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
+# CONFIG_USB_SERIAL_KEYSPAN is not set
+# CONFIG_USB_SERIAL_KLSI is not set
+# CONFIG_USB_SERIAL_KOBIL_SCT is not set
+# CONFIG_USB_SERIAL_MCT_U232 is not set
+# CONFIG_USB_SERIAL_MOS7720 is not set
+# CONFIG_USB_SERIAL_MOS7840 is not set
+# CONFIG_USB_SERIAL_MOTOROLA is not set
+# CONFIG_USB_SERIAL_NAVMAN is not set
+# CONFIG_USB_SERIAL_PL2303 is not set
+# CONFIG_USB_SERIAL_OTI6858 is not set
+# CONFIG_USB_SERIAL_QCAUX is not set
+# CONFIG_USB_SERIAL_QUALCOMM is not set
+# CONFIG_USB_SERIAL_SPCP8X5 is not set
+# CONFIG_USB_SERIAL_HP4X is not set
+# CONFIG_USB_SERIAL_SAFE is not set
+# CONFIG_USB_SERIAL_SIEMENS_MPI is not set
+CONFIG_USB_SERIAL_SIERRAWIRELESS=y
+# CONFIG_USB_SERIAL_SYMBOL is not set
+# CONFIG_USB_SERIAL_TI is not set
+# CONFIG_USB_SERIAL_CYBERJACK is not set
+# CONFIG_USB_SERIAL_XIRCOM is not set
+# CONFIG_USB_SERIAL_OPTION is not set
+# CONFIG_USB_SERIAL_OMNINET is not set
+# CONFIG_USB_SERIAL_OPTICON is not set
+# CONFIG_USB_SERIAL_VIVOPAY_SERIAL is not set
+# CONFIG_USB_SERIAL_ZIO is not set
+# CONFIG_USB_SERIAL_DEBUG 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_SEVSEG is not set
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_LEGOTOWER is not set
+# CONFIG_USB_LCD is not set
+# CONFIG_USB_LED is not set
+# CONFIG_USB_CYPRESS_CY7C63 is not set
+# CONFIG_USB_CYTHERM is not set
+# CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_FTDI_ELAN is not set
+# CONFIG_USB_APPLEDISPLAY is not set
+# CONFIG_USB_SISUSBVGA is not set
+# CONFIG_USB_LD is not set
+# CONFIG_USB_TRANCEVIBRATOR is not set
+# CONFIG_USB_IOWARRIOR is not set
+# CONFIG_USB_TEST is not set
+# CONFIG_USB_ISIGHTFW is not set
+# CONFIG_USB_ATM is not set
+# CONFIG_USB_GADGET is not set
+
+#
+# OTG and related infrastructure
+#
+# CONFIG_USB_GPIO_VBUS is not set
+# CONFIG_NOP_USB_XCEIV is not set
+# CONFIG_UWB is not set
+# CONFIG_MMC is not set
+# CONFIG_MEMSTICK is not set
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=y
+
+#
+# LED drivers
+#
+# CONFIG_LEDS_PCA9532 is not set
+CONFIG_LEDS_GPIO=y
+CONFIG_LEDS_GPIO_PLATFORM=y
+# CONFIG_LEDS_LP3944 is not set
+# CONFIG_LEDS_PCA955X is not set
+# CONFIG_LEDS_BD2802 is not set
+# CONFIG_LEDS_LT3593 is not set
+CONFIG_LEDS_TRIGGERS=y
+
+#
+# LED Triggers
+#
+CONFIG_LEDS_TRIGGER_TIMER=y
+CONFIG_LEDS_TRIGGER_HEARTBEAT=y
+# CONFIG_LEDS_TRIGGER_BACKLIGHT is not set
+# CONFIG_LEDS_TRIGGER_GPIO is not set
+CONFIG_LEDS_TRIGGER_DEFAULT_ON=y
+
+#
+# iptables trigger is under Netfilter config (LED target)
+#
+# CONFIG_ACCESSIBILITY is not set
+# CONFIG_INFINIBAND is not set
+CONFIG_RTC_LIB=y
+# CONFIG_RTC_CLASS is not set
+# CONFIG_DMADEVICES is not set
+# CONFIG_AUXDISPLAY is not set
+# CONFIG_UIO is not set
+# CONFIG_STAGING is not set
+
+#
+# File systems
+#
+# CONFIG_EXT2_FS is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_EXT4_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_BTRFS_FS is not set
+# CONFIG_NILFS2_FS is not set
+CONFIG_FILE_LOCKING=y
+# CONFIG_FSNOTIFY is not set
+# CONFIG_DNOTIFY is not set
+# CONFIG_INOTIFY is not set
+# CONFIG_INOTIFY_USER is not set
+# CONFIG_QUOTA is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+
+#
+# Caches
+#
+# CONFIG_FSCACHE is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+CONFIG_ISO9660_FS=m
+CONFIG_JOLIET=y
+CONFIG_ZISOFS=y
+CONFIG_UDF_FS=m
+CONFIG_UDF_NLS=y
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=m
+CONFIG_MSDOS_FS=m
+CONFIG_VFAT_FS=m
+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_KCORE=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_PROC_PAGE_MONITOR=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
+# CONFIG_HUGETLB_PAGE is not set
+# CONFIG_CONFIGFS_FS is not set
+CONFIG_MISC_FILESYSTEMS=y
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_ECRYPT_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_FS_WBUF_VERIFY is not set
+# CONFIG_JFFS2_SUMMARY is not set
+# CONFIG_JFFS2_FS_XATTR is not set
+CONFIG_JFFS2_COMPRESSION_OPTIONS=y
+CONFIG_JFFS2_ZLIB=y
+# CONFIG_JFFS2_LZO is not set
+CONFIG_JFFS2_RTIME=y
+CONFIG_JFFS2_RUBIN=y
+# CONFIG_JFFS2_CMODE_NONE is not set
+CONFIG_JFFS2_CMODE_PRIORITY=y
+# CONFIG_JFFS2_CMODE_SIZE is not set
+# CONFIG_JFFS2_CMODE_FAVOURLZO is not set
+# CONFIG_LOGFS is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_SQUASHFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_OMFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+CONFIG_NETWORK_FILESYSTEMS=y
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
+CONFIG_NFS_V4=y
+# CONFIG_NFS_V4_1 is not set
+CONFIG_ROOT_NFS=y
+# CONFIG_NFSD is not set
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+CONFIG_SUNRPC_GSS=y
+CONFIG_RPCSEC_GSS_KRB5=y
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CEPH_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_LDM_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_KARMA_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
+# CONFIG_SYSV68_PARTITION is not set
+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=y
+# 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 is not set
+# CONFIG_DLM is not set
+
+#
+# Kernel hacking
+#
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_WARN_DEPRECATED=y
+# CONFIG_ENABLE_MUST_CHECK is not set
+CONFIG_FRAME_WARN=1024
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_STRIP_ASM_SYMS is not set
+# CONFIG_UNUSED_SYMBOLS is not set
+CONFIG_DEBUG_FS=y
+# CONFIG_HEADERS_CHECK is not set
+# CONFIG_DEBUG_KERNEL is not set
+# CONFIG_DEBUG_MEMORY_INIT is not set
+CONFIG_RCU_CPU_STALL_DETECTOR=y
+# CONFIG_LKDTM is not set
+# CONFIG_SYSCTL_SYSCALL_CHECK is not set
+CONFIG_HAVE_FUNCTION_TRACER=y
+CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
+CONFIG_HAVE_FUNCTION_TRACE_MCOUNT_TEST=y
+CONFIG_HAVE_DYNAMIC_FTRACE=y
+CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
+CONFIG_TRACING_SUPPORT=y
+# CONFIG_FTRACE is not set
+# CONFIG_DYNAMIC_DEBUG is not set
+# CONFIG_ATOMIC64_SELFTEST is not set
+# CONFIG_SAMPLES is not set
+CONFIG_HAVE_ARCH_KGDB=y
+CONFIG_EARLY_PRINTK=y
+CONFIG_CMDLINE_BOOL=y
+CONFIG_CMDLINE="console=ttyS0,115200 root=/dev/nfs rw ip=auto"
+# CONFIG_CMDLINE_OVERRIDE is not set
+# CONFIG_SPINLOCK_TEST is not set
+
+#
+# Security options
+#
+CONFIG_KEYS=y
+# CONFIG_KEYS_DEBUG_PROC_KEYS is not set
+# CONFIG_SECURITY is not set
+# CONFIG_SECURITYFS is not set
+# CONFIG_DEFAULT_SECURITY_SELINUX is not set
+# CONFIG_DEFAULT_SECURITY_SMACK is not set
+# CONFIG_DEFAULT_SECURITY_TOMOYO is not set
+CONFIG_DEFAULT_SECURITY_DAC=y
+CONFIG_DEFAULT_SECURITY=""
+CONFIG_CRYPTO=y
+
+#
+# Crypto core or helper
+#
+# CONFIG_CRYPTO_FIPS is not set
+CONFIG_CRYPTO_ALGAPI=y
+CONFIG_CRYPTO_ALGAPI2=y
+CONFIG_CRYPTO_AEAD=m
+CONFIG_CRYPTO_AEAD2=y
+CONFIG_CRYPTO_BLKCIPHER=y
+CONFIG_CRYPTO_BLKCIPHER2=y
+CONFIG_CRYPTO_HASH=y
+CONFIG_CRYPTO_HASH2=y
+CONFIG_CRYPTO_RNG=m
+CONFIG_CRYPTO_RNG2=y
+CONFIG_CRYPTO_PCOMP=y
+CONFIG_CRYPTO_MANAGER=y
+CONFIG_CRYPTO_MANAGER2=y
+# CONFIG_CRYPTO_GF128MUL is not set
+CONFIG_CRYPTO_NULL=m
+CONFIG_CRYPTO_WORKQUEUE=y
+# CONFIG_CRYPTO_CRYPTD is not set
+CONFIG_CRYPTO_AUTHENC=m
+CONFIG_CRYPTO_TEST=m
+
+#
+# Authenticated Encryption with Associated Data
+#
+# CONFIG_CRYPTO_CCM is not set
+# CONFIG_CRYPTO_GCM is not set
+# CONFIG_CRYPTO_SEQIV is not set
+
+#
+# Block modes
+#
+CONFIG_CRYPTO_CBC=y
+# CONFIG_CRYPTO_CTR is not set
+# CONFIG_CRYPTO_CTS is not set
+CONFIG_CRYPTO_ECB=y
+# CONFIG_CRYPTO_LRW is not set
+CONFIG_CRYPTO_PCBC=m
+# CONFIG_CRYPTO_XTS is not set
+
+#
+# Hash modes
+#
+CONFIG_CRYPTO_HMAC=y
+# CONFIG_CRYPTO_XCBC is not set
+# CONFIG_CRYPTO_VMAC is not set
+
+#
+# Digest
+#
+CONFIG_CRYPTO_CRC32C=m
+# CONFIG_CRYPTO_GHASH is not set
+CONFIG_CRYPTO_MD4=m
+CONFIG_CRYPTO_MD5=y
+CONFIG_CRYPTO_MICHAEL_MIC=m
+# CONFIG_CRYPTO_RMD128 is not set
+# CONFIG_CRYPTO_RMD160 is not set
+# CONFIG_CRYPTO_RMD256 is not set
+# CONFIG_CRYPTO_RMD320 is not set
+CONFIG_CRYPTO_SHA1=m
+CONFIG_CRYPTO_SHA256=m
+CONFIG_CRYPTO_SHA512=m
+CONFIG_CRYPTO_TGR192=m
+CONFIG_CRYPTO_WP512=m
+
+#
+# Ciphers
+#
+CONFIG_CRYPTO_AES=y
+CONFIG_CRYPTO_ANUBIS=m
+CONFIG_CRYPTO_ARC4=y
+CONFIG_CRYPTO_BLOWFISH=m
+# CONFIG_CRYPTO_CAMELLIA is not set
+CONFIG_CRYPTO_CAST5=m
+CONFIG_CRYPTO_CAST6=m
+CONFIG_CRYPTO_DES=y
+# CONFIG_CRYPTO_FCRYPT is not set
+CONFIG_CRYPTO_KHAZAD=m
+# CONFIG_CRYPTO_SALSA20 is not set
+# CONFIG_CRYPTO_SEED is not set
+CONFIG_CRYPTO_SERPENT=m
+CONFIG_CRYPTO_TEA=m
+CONFIG_CRYPTO_TWOFISH=m
+CONFIG_CRYPTO_TWOFISH_COMMON=m
+
+#
+# Compression
+#
+CONFIG_CRYPTO_DEFLATE=m
+# CONFIG_CRYPTO_ZLIB is not set
+# CONFIG_CRYPTO_LZO is not set
+
+#
+# Random Number Generation
+#
+CONFIG_CRYPTO_ANSI_CPRNG=m
+CONFIG_CRYPTO_HW=y
+# CONFIG_CRYPTO_DEV_HIFN_795X is not set
+# CONFIG_BINARY_PRINTF is not set
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+CONFIG_GENERIC_FIND_LAST_BIT=y
+CONFIG_CRC_CCITT=m
+CONFIG_CRC16=m
+# CONFIG_CRC_T10DIF is not set
+CONFIG_CRC_ITU_T=m
+CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
+CONFIG_LIBCRC32C=m
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+CONFIG_DECOMPRESS_GZIP=y
+CONFIG_TEXTSEARCH=y
+CONFIG_TEXTSEARCH_KMP=m
+CONFIG_TEXTSEARCH_BM=m
+CONFIG_TEXTSEARCH_FSM=m
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
+CONFIG_NLATTR=y
diff --git a/arch/mips/configs/mtx1_defconfig b/arch/mips/configs/mtx1_defconfig
index cff8f4c0e57..10d20aa731d 100644
--- a/arch/mips/configs/mtx1_defconfig
+++ b/arch/mips/configs/mtx1_defconfig
@@ -8,7 +8,7 @@ CONFIG_MIPS=y
#
# Machine selection
#
-CONFIG_MACH_ALCHEMY=y
+CONFIG_MIPS_ALCHEMY=y
# CONFIG_AR7 is not set
# CONFIG_BCM47XX is not set
# CONFIG_BCM63XX is not set
@@ -64,7 +64,6 @@ CONFIG_MIPS_MTX1=y
# CONFIG_MIPS_PB1550 is not set
# CONFIG_MIPS_XXS1500 is not set
CONFIG_SOC_AU1500=y
-CONFIG_SOC_AU1X00=y
CONFIG_LOONGSON_UART_BASE=y
CONFIG_RWSEM_GENERIC_SPINLOCK=y
# CONFIG_ARCH_HAS_ILOG2_U32 is not set
diff --git a/arch/mips/configs/pb1100_defconfig b/arch/mips/configs/pb1100_defconfig
index 97382b698b9..778f726af8e 100644
--- a/arch/mips/configs/pb1100_defconfig
+++ b/arch/mips/configs/pb1100_defconfig
@@ -8,7 +8,7 @@ CONFIG_MIPS=y
#
# Machine selection
#
-CONFIG_MACH_ALCHEMY=y
+CONFIG_MIPS_ALCHEMY=y
# CONFIG_AR7 is not set
# CONFIG_BCM47XX is not set
# CONFIG_BCM63XX is not set
@@ -64,7 +64,6 @@ CONFIG_MIPS_PB1100=y
# CONFIG_MIPS_PB1550 is not set
# CONFIG_MIPS_XXS1500 is not set
CONFIG_SOC_AU1100=y
-CONFIG_SOC_AU1X00=y
CONFIG_LOONGSON_UART_BASE=y
CONFIG_RWSEM_GENERIC_SPINLOCK=y
# CONFIG_ARCH_HAS_ILOG2_U32 is not set
diff --git a/arch/mips/configs/pb1200_defconfig b/arch/mips/configs/pb1200_defconfig
index e9ad77320f1..0f908c69211 100644
--- a/arch/mips/configs/pb1200_defconfig
+++ b/arch/mips/configs/pb1200_defconfig
@@ -8,7 +8,7 @@ CONFIG_MIPS=y
#
# Machine selection
#
-CONFIG_MACH_ALCHEMY=y
+CONFIG_MIPS_ALCHEMY=y
# CONFIG_AR7 is not set
# CONFIG_BCM47XX is not set
# CONFIG_BCM63XX is not set
@@ -64,7 +64,6 @@ CONFIG_MIPS_PB1200=y
# CONFIG_MIPS_PB1550 is not set
# CONFIG_MIPS_XXS1500 is not set
CONFIG_SOC_AU1200=y
-CONFIG_SOC_AU1X00=y
CONFIG_LOONGSON_UART_BASE=y
CONFIG_RWSEM_GENERIC_SPINLOCK=y
# CONFIG_ARCH_HAS_ILOG2_U32 is not set
diff --git a/arch/mips/configs/pb1500_defconfig b/arch/mips/configs/pb1500_defconfig
index 7497d3306b9..1c5fe6f06c0 100644
--- a/arch/mips/configs/pb1500_defconfig
+++ b/arch/mips/configs/pb1500_defconfig
@@ -8,7 +8,7 @@ CONFIG_MIPS=y
#
# Machine selection
#
-CONFIG_MACH_ALCHEMY=y
+CONFIG_MIPS_ALCHEMY=y
# CONFIG_AR7 is not set
# CONFIG_BCM47XX is not set
# CONFIG_BCM63XX is not set
@@ -64,7 +64,6 @@ CONFIG_MIPS_PB1500=y
# CONFIG_MIPS_PB1550 is not set
# CONFIG_MIPS_XXS1500 is not set
CONFIG_SOC_AU1500=y
-CONFIG_SOC_AU1X00=y
CONFIG_LOONGSON_UART_BASE=y
CONFIG_RWSEM_GENERIC_SPINLOCK=y
# CONFIG_ARCH_HAS_ILOG2_U32 is not set
diff --git a/arch/mips/configs/pb1550_defconfig b/arch/mips/configs/pb1550_defconfig
index aa526f53cb1..49494b01138 100644
--- a/arch/mips/configs/pb1550_defconfig
+++ b/arch/mips/configs/pb1550_defconfig
@@ -8,7 +8,7 @@ CONFIG_MIPS=y
#
# Machine selection
#
-CONFIG_MACH_ALCHEMY=y
+CONFIG_MIPS_ALCHEMY=y
# CONFIG_AR7 is not set
# CONFIG_BCM47XX is not set
# CONFIG_BCM63XX is not set
@@ -64,7 +64,6 @@ CONFIG_ALCHEMY_GPIOINT_AU1000=y
CONFIG_MIPS_PB1550=y
# CONFIG_MIPS_XXS1500 is not set
CONFIG_SOC_AU1550=y
-CONFIG_SOC_AU1X00=y
CONFIG_LOONGSON_UART_BASE=y
CONFIG_RWSEM_GENERIC_SPINLOCK=y
# CONFIG_ARCH_HAS_ILOG2_U32 is not set
diff --git a/arch/mips/configs/powertv_defconfig b/arch/mips/configs/powertv_defconfig
index 7291633d81c..af0ab73bfce 100644
--- a/arch/mips/configs/powertv_defconfig
+++ b/arch/mips/configs/powertv_defconfig
@@ -1,7 +1,7 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.31-rc5
-# Fri Aug 28 14:49:33 2009
+# Linux kernel version: 2.6.35-rc3
+# Thu Jul 1 11:03:28 2010
#
CONFIG_MIPS=y
@@ -11,11 +11,12 @@ CONFIG_MIPS=y
# CONFIG_MACH_ALCHEMY is not set
# CONFIG_AR7 is not set
# CONFIG_BCM47XX is not set
+# CONFIG_BCM63XX is not set
# CONFIG_MIPS_COBALT is not set
# CONFIG_MACH_DECSTATION is not set
# CONFIG_MACH_JAZZ is not set
# CONFIG_LASAT is not set
-# CONFIG_LEMOTE_FULONG is not set
+# CONFIG_MACH_LOONGSON is not set
# CONFIG_MIPS_MALTA is not set
# CONFIG_MIPS_SIM is not set
# CONFIG_NEC_MARKEINS is not set
@@ -50,7 +51,6 @@ CONFIG_POWERTV=y
# CONFIG_MIN_RUNTIME_RESOURCES is not set
# CONFIG_BOOTLOADER_DRIVER is not set
CONFIG_BOOTLOADER_FAMILY="R2"
-CONFIG_CSRC_POWERTV=y
CONFIG_RWSEM_GENERIC_SPINLOCK=y
# CONFIG_ARCH_HAS_ILOG2_U32 is not set
# CONFIG_ARCH_HAS_ILOG2_U64 is not set
@@ -65,9 +65,9 @@ CONFIG_SCHED_OMIT_FRAME_POINTER=y
CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
CONFIG_CEVT_R4K_LIB=y
CONFIG_CEVT_R4K=y
+CONFIG_CSRC_POWERTV=y
CONFIG_DMA_NONCOHERENT=y
-CONFIG_DMA_NEED_PCI_MAP_STATE=y
-# CONFIG_EARLY_PRINTK is not set
+CONFIG_NEED_DMA_MAP_STATE=y
CONFIG_SYS_HAS_EARLY_PRINTK=y
# CONFIG_NO_IOPORT is not set
CONFIG_CPU_BIG_ENDIAN=y
@@ -79,7 +79,8 @@ CONFIG_MIPS_L1_CACHE_SHIFT=5
#
# CPU selection
#
-# CONFIG_CPU_LOONGSON2 is not set
+# CONFIG_CPU_LOONGSON2E is not set
+# CONFIG_CPU_LOONGSON2F is not set
# CONFIG_CPU_MIPS32_R1 is not set
CONFIG_CPU_MIPS32_R2=y
# CONFIG_CPU_MIPS64_R1 is not set
@@ -122,7 +123,7 @@ CONFIG_CPU_HAS_PREFETCH=y
CONFIG_MIPS_MT_DISABLED=y
# CONFIG_MIPS_MT_SMP is not set
# CONFIG_MIPS_MT_SMTC is not set
-CONFIG_CPU_HAS_LLSC=y
+# CONFIG_ARCH_PHYS_ADDR_T_64BIT is not set
CONFIG_CPU_MIPSR2_IRQ_VI=y
CONFIG_CPU_MIPSR2_IRQ_EI=y
CONFIG_CPU_HAS_SYNC=y
@@ -144,8 +145,7 @@ CONFIG_SPLIT_PTLOCK_CPUS=4
# CONFIG_PHYS_ADDR_T_64BIT is not set
CONFIG_ZONE_DMA_FLAG=0
CONFIG_VIRT_TO_BUS=y
-CONFIG_HAVE_MLOCK=y
-CONFIG_HAVE_MLOCKED_PAGE_BIT=y
+# CONFIG_KSM is not set
CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
CONFIG_TICK_ONESHOT=y
CONFIG_NO_HZ=y
@@ -177,6 +177,7 @@ CONFIG_EXPERIMENTAL=y
CONFIG_BROKEN_ON_SMP=y
CONFIG_LOCK_KERNEL=y
CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_CROSS_COMPILE="mips-linux-"
CONFIG_LOCALVERSION=""
CONFIG_LOCALVERSION_AUTO=y
# CONFIG_SWAP is not set
@@ -190,19 +191,15 @@ CONFIG_SYSVIPC_SYSCTL=y
#
# RCU Subsystem
#
-CONFIG_CLASSIC_RCU=y
-# CONFIG_TREE_RCU is not set
-# CONFIG_PREEMPT_RCU is not set
+CONFIG_TREE_RCU=y
+# CONFIG_TREE_PREEMPT_RCU is not set
+# CONFIG_TINY_RCU is not set
+# CONFIG_RCU_TRACE is not set
+CONFIG_RCU_FANOUT=32
+# CONFIG_RCU_FANOUT_EXACT is not set
# CONFIG_TREE_RCU_TRACE is not set
-# CONFIG_PREEMPT_RCU_TRACE is not set
# CONFIG_IKCONFIG is not set
CONFIG_LOG_BUF_SHIFT=16
-CONFIG_GROUP_SCHED=y
-CONFIG_FAIR_GROUP_SCHED=y
-# CONFIG_RT_GROUP_SCHED is not set
-CONFIG_USER_SCHED=y
-# CONFIG_CGROUP_SCHED is not set
-# CONFIG_CGROUPS is not set
# CONFIG_SYSFS_DEPRECATED_V2 is not set
CONFIG_RELAY=y
# CONFIG_NAMESPACES is not set
@@ -211,6 +208,7 @@ CONFIG_INITRAMFS_SOURCE=""
# CONFIG_RD_GZIP is not set
# CONFIG_RD_BZIP2 is not set
# CONFIG_RD_LZMA is not set
+# CONFIG_RD_LZO is not set
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
CONFIG_SYSCTL=y
CONFIG_ANON_INODES=y
@@ -234,18 +232,16 @@ CONFIG_SHMEM=y
CONFIG_AIO=y
#
-# Performance Counters
+# Kernel Performance Events And Counters
#
# CONFIG_VM_EVENT_COUNTERS is not set
CONFIG_PCI_QUIRKS=y
# CONFIG_SLUB_DEBUG is not set
-# CONFIG_STRIP_ASM_SYMS is not set
CONFIG_COMPAT_BRK=y
# CONFIG_SLAB is not set
CONFIG_SLUB=y
# CONFIG_SLOB is not set
# CONFIG_PROFILING is not set
-# CONFIG_MARKERS is not set
CONFIG_HAVE_OPROFILE=y
#
@@ -253,7 +249,7 @@ CONFIG_HAVE_OPROFILE=y
#
# CONFIG_GCOV_KERNEL is not set
# CONFIG_SLOW_WORK is not set
-# CONFIG_HAVE_GENERIC_DMA_COHERENT is not set
+CONFIG_HAVE_GENERIC_DMA_COHERENT=y
CONFIG_RT_MUTEXES=y
CONFIG_BASE_SMALL=0
CONFIG_MODULES=y
@@ -271,15 +267,41 @@ CONFIG_LBDAF=y
# IO Schedulers
#
CONFIG_IOSCHED_NOOP=y
-# CONFIG_IOSCHED_AS is not set
# CONFIG_IOSCHED_DEADLINE is not set
# CONFIG_IOSCHED_CFQ is not set
-# CONFIG_DEFAULT_AS is not set
# CONFIG_DEFAULT_DEADLINE is not set
# CONFIG_DEFAULT_CFQ is not set
CONFIG_DEFAULT_NOOP=y
CONFIG_DEFAULT_IOSCHED="noop"
-# CONFIG_PROBE_INITRD_HEADER is not set
+# CONFIG_INLINE_SPIN_TRYLOCK is not set
+# CONFIG_INLINE_SPIN_TRYLOCK_BH is not set
+# CONFIG_INLINE_SPIN_LOCK is not set
+# CONFIG_INLINE_SPIN_LOCK_BH is not set
+# CONFIG_INLINE_SPIN_LOCK_IRQ is not set
+# CONFIG_INLINE_SPIN_LOCK_IRQSAVE is not set
+# CONFIG_INLINE_SPIN_UNLOCK is not set
+# CONFIG_INLINE_SPIN_UNLOCK_BH is not set
+# CONFIG_INLINE_SPIN_UNLOCK_IRQ is not set
+# CONFIG_INLINE_SPIN_UNLOCK_IRQRESTORE is not set
+# CONFIG_INLINE_READ_TRYLOCK is not set
+# CONFIG_INLINE_READ_LOCK is not set
+# CONFIG_INLINE_READ_LOCK_BH is not set
+# CONFIG_INLINE_READ_LOCK_IRQ is not set
+# CONFIG_INLINE_READ_LOCK_IRQSAVE is not set
+# CONFIG_INLINE_READ_UNLOCK is not set
+# CONFIG_INLINE_READ_UNLOCK_BH is not set
+# CONFIG_INLINE_READ_UNLOCK_IRQ is not set
+# CONFIG_INLINE_READ_UNLOCK_IRQRESTORE is not set
+# CONFIG_INLINE_WRITE_TRYLOCK is not set
+# CONFIG_INLINE_WRITE_LOCK is not set
+# CONFIG_INLINE_WRITE_LOCK_BH is not set
+# CONFIG_INLINE_WRITE_LOCK_IRQ is not set
+# CONFIG_INLINE_WRITE_LOCK_IRQSAVE is not set
+# CONFIG_INLINE_WRITE_UNLOCK is not set
+# CONFIG_INLINE_WRITE_UNLOCK_BH is not set
+# CONFIG_INLINE_WRITE_UNLOCK_IRQ is not set
+# CONFIG_INLINE_WRITE_UNLOCK_IRQRESTORE is not set
+# CONFIG_MUTEX_SPIN_ON_OWNER is not set
# CONFIG_FREEZER is not set
#
@@ -289,7 +311,6 @@ CONFIG_HW_HAS_PCI=y
CONFIG_PCI=y
CONFIG_PCI_DOMAINS=y
# CONFIG_ARCH_SUPPORTS_MSI is not set
-# CONFIG_PCI_LEGACY is not set
# CONFIG_PCI_DEBUG is not set
# CONFIG_PCI_STUB is not set
# CONFIG_PCI_IOV is not set
@@ -318,7 +339,6 @@ CONFIG_NET=y
# Networking options
#
CONFIG_PACKET=y
-CONFIG_PACKET_MMAP=y
CONFIG_UNIX=y
CONFIG_XFRM=y
# CONFIG_XFRM_USER is not set
@@ -390,12 +410,26 @@ CONFIG_NETFILTER_ADVANCED=y
# CONFIG_NETFILTER_NETLINK_LOG is not set
# CONFIG_NF_CONNTRACK is not set
CONFIG_NETFILTER_XTABLES=y
+
+#
+# Xtables combined modules
+#
+# CONFIG_NETFILTER_XT_MARK is not set
+
+#
+# Xtables targets
+#
# CONFIG_NETFILTER_XT_TARGET_CLASSIFY is not set
# CONFIG_NETFILTER_XT_TARGET_MARK is not set
# CONFIG_NETFILTER_XT_TARGET_NFLOG is not set
# CONFIG_NETFILTER_XT_TARGET_NFQUEUE is not set
# CONFIG_NETFILTER_XT_TARGET_RATEEST is not set
+# CONFIG_NETFILTER_XT_TARGET_TEE is not set
# CONFIG_NETFILTER_XT_TARGET_TCPMSS is not set
+
+#
+# Xtables matches
+#
# CONFIG_NETFILTER_XT_MATCH_COMMENT is not set
# CONFIG_NETFILTER_XT_MATCH_DCCP is not set
# CONFIG_NETFILTER_XT_MATCH_DSCP is not set
@@ -465,10 +499,13 @@ CONFIG_IP6_NF_FILTER=y
# CONFIG_IP6_NF_RAW is not set
# CONFIG_IP_DCCP is not set
# CONFIG_IP_SCTP is not set
+# CONFIG_RDS is not set
# CONFIG_TIPC is not set
# CONFIG_ATM is not set
+# CONFIG_L2TP is not set
CONFIG_STP=y
CONFIG_BRIDGE=y
+CONFIG_BRIDGE_IGMP_SNOOPING=y
# CONFIG_NET_DSA is not set
# CONFIG_VLAN_8021Q is not set
# CONFIG_DECNET is not set
@@ -526,10 +563,21 @@ CONFIG_NET_SCH_FIFO=y
# CONFIG_IRDA is not set
# CONFIG_BT is not set
# CONFIG_AF_RXRPC is not set
-# CONFIG_WIRELESS is not set
+CONFIG_WIRELESS=y
+# CONFIG_CFG80211 is not set
+# CONFIG_LIB80211 is not set
+
+#
+# CFG80211 needs to be enabled for MAC80211
+#
+
+#
+# Some wireless drivers require a rate control algorithm
+#
# CONFIG_WIMAX is not set
# CONFIG_RFKILL is not set
# CONFIG_NET_9P is not set
+# CONFIG_CAIF is not set
#
# Device Drivers
@@ -539,6 +587,7 @@ CONFIG_NET_SCH_FIFO=y
# Generic Driver Options
#
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+# CONFIG_DEVTMPFS is not set
CONFIG_STANDALONE=y
CONFIG_PREVENT_FIRMWARE_BUILD=y
CONFIG_FW_LOADER=y
@@ -550,9 +599,9 @@ CONFIG_EXTRA_FIRMWARE=""
# CONFIG_CONNECTOR is not set
CONFIG_MTD=y
# CONFIG_MTD_DEBUG is not set
+# CONFIG_MTD_TESTS is not set
# CONFIG_MTD_CONCAT is not set
CONFIG_MTD_PARTITIONS=y
-# CONFIG_MTD_TESTS is not set
# CONFIG_MTD_REDBOOT_PARTS is not set
CONFIG_MTD_CMDLINE_PARTS=y
# CONFIG_MTD_AR7_PARTS is not set
@@ -568,6 +617,7 @@ CONFIG_MTD_BLOCK=y
# CONFIG_INFTL is not set
# CONFIG_RFD_FTL is not set
# CONFIG_SSFDC is not set
+# CONFIG_SM_FTL is not set
# CONFIG_MTD_OOPS is not set
#
@@ -611,11 +661,16 @@ CONFIG_MTD_CFI_I2=y
# CONFIG_MTD_DOC2000 is not set
# CONFIG_MTD_DOC2001 is not set
# CONFIG_MTD_DOC2001PLUS is not set
+CONFIG_MTD_NAND_ECC=y
+# CONFIG_MTD_NAND_ECC_SMC 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_SM_COMMON is not set
# CONFIG_MTD_NAND_MUSEUM_IDS is not set
+# CONFIG_MTD_NAND_DENALI is not set
+CONFIG_MTD_NAND_DENALI_SCRATCH_REG_ADDR=0xFF108018
CONFIG_MTD_NAND_IDS=y
+# CONFIG_MTD_NAND_RICOH is not set
# CONFIG_MTD_NAND_DISKONCHIP is not set
# CONFIG_MTD_NAND_CAFE is not set
# CONFIG_MTD_NAND_NANDSIM is not set
@@ -641,6 +696,10 @@ CONFIG_BLK_DEV=y
# CONFIG_BLK_DEV_COW_COMMON is not set
CONFIG_BLK_DEV_LOOP=y
# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+
+#
+# DRBD disabled because PROC_FS, INET or CONNECTOR not selected
+#
# CONFIG_BLK_DEV_NBD is not set
# CONFIG_BLK_DEV_SX8 is not set
# CONFIG_BLK_DEV_UB is not set
@@ -658,6 +717,7 @@ CONFIG_HAVE_IDE=y
#
# SCSI device support
#
+CONFIG_SCSI_MOD=y
# CONFIG_RAID_ATTRS is not set
CONFIG_SCSI=y
CONFIG_SCSI_DMA=y
@@ -693,64 +753,95 @@ CONFIG_SCSI_WAIT_SCAN=m
# CONFIG_SCSI_OSD_INITIATOR is not set
CONFIG_ATA=y
# CONFIG_ATA_NONSTANDARD is not set
+CONFIG_ATA_VERBOSE_ERROR=y
CONFIG_SATA_PMP=y
+
+#
+# Controllers with non-SFF native interface
+#
# CONFIG_SATA_AHCI is not set
+# CONFIG_SATA_AHCI_PLATFORM is not set
+# CONFIG_SATA_INIC162X is not set
# CONFIG_SATA_SIL24 is not set
CONFIG_ATA_SFF=y
-# CONFIG_SATA_SVW is not set
+
+#
+# SFF controllers with custom DMA interface
+#
+# CONFIG_PDC_ADMA is not set
+# CONFIG_SATA_QSTOR is not set
+# CONFIG_SATA_SX4 is not set
+CONFIG_ATA_BMDMA=y
+
+#
+# SATA SFF controllers with BMDMA
+#
# 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 is not set
# CONFIG_SATA_SIS is not set
+# CONFIG_SATA_SVW 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
+
+#
+# PATA SFF controllers with BMDMA
+#
# 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_ATP867X 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_IT821X 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_NINJA32 is not set
-# CONFIG_PATA_NS87410 is not set
# CONFIG_PATA_NS87415 is not set
-# CONFIG_PATA_OPTI is not set
+# CONFIG_PATA_OLDPIIX is not set
# CONFIG_PATA_OPTIDMA is not set
+# CONFIG_PATA_PDC2027X is not set
# CONFIG_PATA_PDC_OLD is not set
# CONFIG_PATA_RADISYS is not set
-# CONFIG_PATA_RZ1000 is not set
+# CONFIG_PATA_RDC is not set
# CONFIG_PATA_SC1200 is not set
+# CONFIG_PATA_SCH 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_TOSHIBA is not set
+# CONFIG_PATA_TRIFLEX is not set
# CONFIG_PATA_VIA is not set
# CONFIG_PATA_WINBOND is not set
+
+#
+# PIO-only SFF controllers
+#
+# CONFIG_PATA_CMD640_PCI is not set
+# CONFIG_PATA_MPIIX is not set
+# CONFIG_PATA_NS87410 is not set
+# CONFIG_PATA_OPTI is not set
# CONFIG_PATA_PLATFORM is not set
-# CONFIG_PATA_SCH is not set
+# CONFIG_PATA_RZ1000 is not set
+
+#
+# Generic fallback / legacy drivers
+#
+# CONFIG_ATA_GENERIC is not set
+# CONFIG_PATA_LEGACY is not set
# CONFIG_MD is not set
# CONFIG_FUSION is not set
@@ -763,7 +854,7 @@ CONFIG_ATA_SFF=y
#
#
-# See the help texts for more information.
+# The newer stack is recommended.
#
# CONFIG_FIREWIRE is not set
# CONFIG_IEEE1394 is not set
@@ -787,6 +878,7 @@ CONFIG_MII=y
# CONFIG_SMC91X is not set
# CONFIG_DM9000 is not set
# CONFIG_ETHOC is not set
+# CONFIG_SMSC911X is not set
# CONFIG_DNET is not set
# CONFIG_NET_TULIP is not set
# CONFIG_HP100 is not set
@@ -800,6 +892,7 @@ CONFIG_MII=y
# CONFIG_NET_PCI is not set
# CONFIG_B44 is not set
# CONFIG_KS8842 is not set
+# CONFIG_KS8851_MLL is not set
# CONFIG_ATL2 is not set
CONFIG_NETDEV_1000=y
# CONFIG_ACENIC is not set
@@ -829,6 +922,8 @@ CONFIG_NETDEV_10000=y
# CONFIG_CHELSIO_T1 is not set
CONFIG_CHELSIO_T3_DEPENDS=y
# CONFIG_CHELSIO_T3 is not set
+CONFIG_CHELSIO_T4_DEPENDS=y
+# CONFIG_CHELSIO_T4 is not set
# CONFIG_ENIC is not set
# CONFIG_IXGBE is not set
# CONFIG_IXGB is not set
@@ -841,16 +936,12 @@ CONFIG_CHELSIO_T3_DEPENDS=y
# CONFIG_MLX4_CORE is not set
# CONFIG_TEHUTI is not set
# CONFIG_BNX2X is not set
+# CONFIG_QLCNIC is not set
# CONFIG_QLGE is not set
# CONFIG_SFC is not set
# CONFIG_BE2NET is not set
# CONFIG_TR is not set
-
-#
-# Wireless LAN
-#
-# CONFIG_WLAN_PRE80211 is not set
-# CONFIG_WLAN_80211 is not set
+# CONFIG_WLAN is not set
#
# Enable WiMAX (Networking options) to see the WiMAX drivers
@@ -864,6 +955,7 @@ CONFIG_CHELSIO_T3_DEPENDS=y
# CONFIG_USB_PEGASUS is not set
CONFIG_USB_RTL8150=y
# CONFIG_USB_USBNET is not set
+# CONFIG_USB_IPHETH is not set
# CONFIG_WAN is not set
# CONFIG_FDDI is not set
# CONFIG_HIPPI is not set
@@ -873,6 +965,7 @@ CONFIG_USB_RTL8150=y
# CONFIG_NETCONSOLE is not set
# CONFIG_NETPOLL is not set
# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_VMXNET3 is not set
# CONFIG_ISDN is not set
# CONFIG_PHONE is not set
@@ -882,6 +975,7 @@ CONFIG_USB_RTL8150=y
CONFIG_INPUT=y
# CONFIG_INPUT_FF_MEMLESS is not set
# CONFIG_INPUT_POLLDEV is not set
+# CONFIG_INPUT_SPARSEKMAP is not set
#
# Userland interfaces
@@ -913,6 +1007,7 @@ CONFIG_INPUT_EVDEV=y
# CONFIG_VT is not set
# CONFIG_DEVKMEM is not set
# CONFIG_SERIAL_NONSTANDARD is not set
+# CONFIG_N_GSM is not set
# CONFIG_NOZOMI is not set
#
@@ -924,6 +1019,9 @@ CONFIG_INPUT_EVDEV=y
# Non-8250 serial port support
#
# CONFIG_SERIAL_JSM is not set
+# CONFIG_SERIAL_TIMBERDALE is not set
+# CONFIG_SERIAL_ALTERA_JTAGUART is not set
+# CONFIG_SERIAL_ALTERA_UART is not set
CONFIG_UNIX98_PTYS=y
# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
# CONFIG_LEGACY_PTYS is not set
@@ -934,6 +1032,7 @@ CONFIG_UNIX98_PTYS=y
# CONFIG_RAW_DRIVER is not set
# CONFIG_TCG_TPM is not set
CONFIG_DEVPORT=y
+# CONFIG_RAMOOPS is not set
# CONFIG_I2C is not set
# CONFIG_SPI is not set
@@ -945,7 +1044,6 @@ CONFIG_DEVPORT=y
# CONFIG_POWER_SUPPLY is not set
# CONFIG_HWMON is not set
# CONFIG_THERMAL is not set
-# CONFIG_THERMAL_HWMON is not set
# CONFIG_WATCHDOG is not set
CONFIG_SSB_POSSIBLE=y
@@ -953,20 +1051,14 @@ CONFIG_SSB_POSSIBLE=y
# Sonics Silicon Backplane
#
# CONFIG_SSB is not set
-
-#
-# Multifunction device drivers
-#
-# CONFIG_MFD_CORE is not set
-# CONFIG_MFD_SM501 is not set
-# CONFIG_HTC_PASIC3 is not set
-# CONFIG_MFD_TMIO is not set
+# CONFIG_MFD_SUPPORT is not set
# CONFIG_REGULATOR is not set
# CONFIG_MEDIA_SUPPORT is not set
#
# Graphics support
#
+# CONFIG_VGA_ARB is not set
# CONFIG_DRM is not set
# CONFIG_VGASTATE is not set
# CONFIG_VIDEO_OUTPUT_CONTROL is not set
@@ -980,7 +1072,6 @@ CONFIG_SSB_POSSIBLE=y
# CONFIG_SOUND is not set
CONFIG_HID_SUPPORT=y
CONFIG_HID=y
-# CONFIG_HID_DEBUG is not set
# CONFIG_HIDRAW is not set
#
@@ -993,31 +1084,43 @@ CONFIG_USB_HIDDEV=y
#
# Special HID drivers
#
+# CONFIG_HID_3M_PCT is not set
# CONFIG_HID_A4TECH is not set
# CONFIG_HID_APPLE is not set
# CONFIG_HID_BELKIN is not set
+# CONFIG_HID_CANDO is not set
# CONFIG_HID_CHERRY is not set
# CONFIG_HID_CHICONY is not set
# CONFIG_HID_CYPRESS is not set
# CONFIG_HID_DRAGONRISE is not set
+# CONFIG_HID_EGALAX is not set
# CONFIG_HID_EZKEY is not set
# CONFIG_HID_KYE is not set
# CONFIG_HID_GYRATION is not set
+# CONFIG_HID_TWINHAN is not set
# CONFIG_HID_KENSINGTON is not set
# CONFIG_HID_LOGITECH is not set
# CONFIG_HID_MICROSOFT is not set
+# CONFIG_HID_MOSART is not set
# CONFIG_HID_MONTEREY is not set
# CONFIG_HID_NTRIG is not set
+# CONFIG_HID_ORTEK is not set
# CONFIG_HID_PANTHERLORD is not set
# CONFIG_HID_PETALYNX is not set
+# CONFIG_HID_PICOLCD is not set
+# CONFIG_HID_QUANTA is not set
+# CONFIG_HID_ROCCAT is not set
+# CONFIG_HID_ROCCAT_KONE is not set
# CONFIG_HID_SAMSUNG is not set
# CONFIG_HID_SONY is not set
+# CONFIG_HID_STANTUM is not set
# CONFIG_HID_SUNPLUS is not set
# CONFIG_HID_GREENASIA is not set
# CONFIG_HID_SMARTJOYPLUS is not set
# CONFIG_HID_TOPSEED is not set
# CONFIG_HID_THRUSTMASTER is not set
# CONFIG_HID_ZEROPLUS is not set
+# CONFIG_HID_ZYDACRON is not set
CONFIG_USB_SUPPORT=y
CONFIG_USB_ARCH_HAS_HCD=y
CONFIG_USB_ARCH_HAS_OHCI=y
@@ -1032,7 +1135,6 @@ CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
CONFIG_USB_DEVICEFS=y
# CONFIG_USB_DEVICE_CLASS is not set
# CONFIG_USB_DYNAMIC_MINORS is not set
-# CONFIG_USB_OTG is not set
# CONFIG_USB_OTG_WHITELIST is not set
# CONFIG_USB_OTG_BLACKLIST_HUB is not set
# CONFIG_USB_MON is not set
@@ -1050,6 +1152,7 @@ CONFIG_USB_EHCI_HCD=y
# CONFIG_USB_OXU210HP_HCD is not set
# CONFIG_USB_ISP116X_HCD is not set
# CONFIG_USB_ISP1760_HCD is not set
+# CONFIG_USB_ISP1362_HCD is not set
CONFIG_USB_OHCI_HCD=y
# CONFIG_USB_OHCI_BIG_ENDIAN_DESC is not set
# CONFIG_USB_OHCI_BIG_ENDIAN_MMIO is not set
@@ -1133,6 +1236,7 @@ CONFIG_USB_SERIAL_CP210X=y
# CONFIG_USB_SERIAL_NAVMAN is not set
# CONFIG_USB_SERIAL_PL2303 is not set
# CONFIG_USB_SERIAL_OTI6858 is not set
+# CONFIG_USB_SERIAL_QCAUX is not set
# CONFIG_USB_SERIAL_QUALCOMM is not set
# CONFIG_USB_SERIAL_SPCP8X5 is not set
# CONFIG_USB_SERIAL_HP4X is not set
@@ -1146,6 +1250,8 @@ CONFIG_USB_SERIAL_CP210X=y
# CONFIG_USB_SERIAL_OPTION is not set
# CONFIG_USB_SERIAL_OMNINET is not set
# CONFIG_USB_SERIAL_OPTICON is not set
+# CONFIG_USB_SERIAL_VIVOPAY_SERIAL is not set
+# CONFIG_USB_SERIAL_ZIO is not set
# CONFIG_USB_SERIAL_DEBUG is not set
#
@@ -1158,7 +1264,6 @@ CONFIG_USB_SERIAL_CP210X=y
# 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
@@ -1171,7 +1276,6 @@ CONFIG_USB_SERIAL_CP210X=y
# CONFIG_USB_IOWARRIOR is not set
# CONFIG_USB_TEST is not set
# CONFIG_USB_ISIGHTFW is not set
-# CONFIG_USB_VST is not set
# CONFIG_USB_GADGET is not set
#
@@ -1189,10 +1293,6 @@ CONFIG_RTC_LIB=y
# CONFIG_DMADEVICES is not set
# CONFIG_AUXDISPLAY is not set
# CONFIG_UIO is not set
-
-#
-# TI VLYNQ
-#
# CONFIG_STAGING is not set
#
@@ -1214,6 +1314,7 @@ CONFIG_JBD=y
# CONFIG_GFS2_FS is not set
# CONFIG_OCFS2_FS is not set
# CONFIG_BTRFS_FS is not set
+# CONFIG_NILFS2_FS is not set
CONFIG_FILE_LOCKING=y
CONFIG_FSNOTIFY=y
# CONFIG_DNOTIFY is not set
@@ -1274,6 +1375,7 @@ CONFIG_JFFS2_ZLIB=y
# CONFIG_JFFS2_LZO is not set
CONFIG_JFFS2_RTIME=y
# CONFIG_JFFS2_RUBIN is not set
+# CONFIG_LOGFS is not set
CONFIG_CRAMFS=y
# CONFIG_SQUASHFS is not set
# CONFIG_VXFS_FS is not set
@@ -1284,7 +1386,6 @@ CONFIG_CRAMFS=y
# CONFIG_ROMFS_FS is not set
# CONFIG_SYSV_FS is not set
# CONFIG_UFS_FS is not set
-# CONFIG_NILFS2_FS is not set
CONFIG_NETWORK_FILESYSTEMS=y
CONFIG_NFS_FS=y
CONFIG_NFS_V3=y
@@ -1299,6 +1400,7 @@ CONFIG_SUNRPC=y
# CONFIG_RPCSEC_GSS_KRB5 is not set
# CONFIG_RPCSEC_GSS_SPKM3 is not set
# CONFIG_SMB_FS is not set
+# CONFIG_CEPH_FS is not set
# CONFIG_CIFS is not set
# CONFIG_NCP_FS is not set
# CONFIG_CODA_FS is not set
@@ -1360,6 +1462,7 @@ CONFIG_ENABLE_WARN_DEPRECATED=y
CONFIG_ENABLE_MUST_CHECK=y
CONFIG_FRAME_WARN=1024
# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_STRIP_ASM_SYMS is not set
# CONFIG_UNUSED_SYMBOLS is not set
CONFIG_DEBUG_FS=y
# CONFIG_HEADERS_CHECK is not set
@@ -1393,15 +1496,25 @@ CONFIG_DEBUG_INFO=y
# CONFIG_DEBUG_LIST is not set
# CONFIG_DEBUG_SG is not set
# CONFIG_DEBUG_NOTIFIERS is not set
+# CONFIG_DEBUG_CREDENTIALS is not set
# CONFIG_BOOT_PRINTK_DELAY is not set
# CONFIG_RCU_TORTURE_TEST is not set
# CONFIG_RCU_CPU_STALL_DETECTOR is not set
# CONFIG_BACKTRACE_SELF_TEST is not set
# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
+# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set
+# CONFIG_LKDTM is not set
# CONFIG_FAULT_INJECTION is not set
+# CONFIG_SYSCTL_SYSCALL_CHECK is not set
# CONFIG_PAGE_POISONING is not set
+CONFIG_HAVE_FUNCTION_TRACER=y
+CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
+CONFIG_HAVE_FUNCTION_TRACE_MCOUNT_TEST=y
+CONFIG_HAVE_DYNAMIC_FTRACE=y
+CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
CONFIG_TRACING_SUPPORT=y
CONFIG_FTRACE=y
+# CONFIG_FUNCTION_TRACER is not set
# CONFIG_IRQSOFF_TRACER is not set
# CONFIG_PREEMPT_TRACER is not set
# CONFIG_SCHED_TRACER is not set
@@ -1410,19 +1523,22 @@ CONFIG_FTRACE=y
CONFIG_BRANCH_PROFILE_NONE=y
# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set
# CONFIG_PROFILE_ALL_BRANCHES is not set
+# CONFIG_STACK_TRACER is not set
# CONFIG_KMEMTRACE is not set
# CONFIG_WORKQUEUE_TRACER is not set
# CONFIG_BLK_DEV_IO_TRACE is not set
# CONFIG_DYNAMIC_DEBUG is not set
+# CONFIG_ATOMIC64_SELFTEST is not set
# CONFIG_SAMPLES is not set
CONFIG_HAVE_ARCH_KGDB=y
# CONFIG_KGDB is not set
-# CONFIG_KMEMCHECK is not set
+# CONFIG_EARLY_PRINTK is not set
CONFIG_CMDLINE_BOOL=y
-CONFIG_CMDLINE="rw dhash_entries=1024 ihash_entries=1024 ip=10.0.1.3:10.0.1.1:10.0.1.1:255.255.255.0:zeus:eth0: root=/dev/nfs nfsroot=/nfsroot/cramfs,wsize=512,rsize=512,tcp nokgdb console=ttyUSB0,115200 memsize=252M"
+CONFIG_CMDLINE=""
# CONFIG_CMDLINE_OVERRIDE is not set
# CONFIG_DEBUG_STACK_USAGE is not set
# CONFIG_RUNTIME_DEBUG is not set
+# CONFIG_SPINLOCK_TEST is not set
#
# Security options
@@ -1430,13 +1546,16 @@ CONFIG_CMDLINE="rw dhash_entries=1024 ihash_entries=1024 ip=10.0.1.3:10.0.1.1:10
# CONFIG_KEYS is not set
# CONFIG_SECURITY is not set
# CONFIG_SECURITYFS is not set
-# CONFIG_SECURITY_FILE_CAPABILITIES is not set
+# CONFIG_DEFAULT_SECURITY_SELINUX is not set
+# CONFIG_DEFAULT_SECURITY_SMACK is not set
+# CONFIG_DEFAULT_SECURITY_TOMOYO is not set
+CONFIG_DEFAULT_SECURITY_DAC=y
+CONFIG_DEFAULT_SECURITY=""
CONFIG_CRYPTO=y
#
# Crypto core or helper
#
-# CONFIG_CRYPTO_FIPS is not set
CONFIG_CRYPTO_ALGAPI=y
CONFIG_CRYPTO_ALGAPI2=y
CONFIG_CRYPTO_AEAD=y
@@ -1479,11 +1598,13 @@ CONFIG_CRYPTO_CBC=y
#
CONFIG_CRYPTO_HMAC=y
# CONFIG_CRYPTO_XCBC is not set
+# CONFIG_CRYPTO_VMAC is not set
#
# Digest
#
# CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_GHASH is not set
# CONFIG_CRYPTO_MD4 is not set
CONFIG_CRYPTO_MD5=y
# CONFIG_CRYPTO_MICHAEL_MIC is not set
diff --git a/arch/mips/dec/Makefile b/arch/mips/dec/Makefile
index c530208ee15..9eb2f9c036a 100644
--- a/arch/mips/dec/Makefile
+++ b/arch/mips/dec/Makefile
@@ -8,5 +8,3 @@ obj-y := ecc-berr.o int-handler.o ioasic-irq.o kn01-berr.o \
obj-$(CONFIG_PROM_CONSOLE) += promcon.o
obj-$(CONFIG_TC) += tc.o
obj-$(CONFIG_CPU_HAS_WB) += wbflush.o
-
-EXTRA_CFLAGS += -Werror
diff --git a/arch/mips/dec/Platform b/arch/mips/dec/Platform
new file mode 100644
index 00000000000..3adbcbd95db
--- /dev/null
+++ b/arch/mips/dec/Platform
@@ -0,0 +1,8 @@
+#
+# DECstation family
+#
+platform-$(CONFIG_MACH_DECSTATION) = dec/
+cflags-$(CONFIG_MACH_DECSTATION) += \
+ -I$(srctree)/arch/mips/include/asm/mach-dec
+libs-$(CONFIG_MACH_DECSTATION) += arch/mips/dec/prom/
+load-$(CONFIG_MACH_DECSTATION) += 0xffffffff80040000
diff --git a/arch/mips/dec/promcon.c b/arch/mips/dec/promcon.c
index 9f0972f5a70..c239c25b79f 100644
--- a/arch/mips/dec/promcon.c
+++ b/arch/mips/dec/promcon.c
@@ -33,8 +33,7 @@ static int __init prom_console_setup(struct console *co, char *options)
return 0;
}
-static struct console sercons =
-{
+static struct console sercons = {
.name = "ttyS",
.write = prom_console_write,
.setup = prom_console_setup,
diff --git a/arch/mips/emma/Makefile b/arch/mips/emma/Makefile
new file mode 100644
index 00000000000..4254a31edb0
--- /dev/null
+++ b/arch/mips/emma/Makefile
@@ -0,0 +1,6 @@
+obj-$(CONFIG_SOC_EMMA2RH) += common/
+
+#
+# NEC EMMA2RH Mark-eins
+#
+obj-$(CONFIG_NEC_MARKEINS) += markeins/
diff --git a/arch/mips/emma/Platform b/arch/mips/emma/Platform
new file mode 100644
index 00000000000..0282f7f99b8
--- /dev/null
+++ b/arch/mips/emma/Platform
@@ -0,0 +1,4 @@
+platform-$(CONFIG_SOC_EMMA2RH) += emma/
+cflags-$(CONFIG_SOC_EMMA2RH) += \
+ -I$(srctree)/arch/mips/include/asm/mach-emma2rh
+load-$(CONFIG_NEC_MARKEINS) += 0xffffffff88100000
diff --git a/arch/mips/emma/markeins/irq.c b/arch/mips/emma/markeins/irq.c
index 9504b7ee0b7..3a96799eb65 100644
--- a/arch/mips/emma/markeins/irq.c
+++ b/arch/mips/emma/markeins/irq.c
@@ -301,7 +301,7 @@ void __init arch_init_irq(void)
/* setup cascade interrupts */
setup_irq(EMMA2RH_IRQ_BASE + EMMA2RH_SW_CASCADE, &irq_cascade);
setup_irq(EMMA2RH_IRQ_BASE + EMMA2RH_GPIO_CASCADE, &irq_cascade);
- setup_irq(CPU_IRQ_BASE + CPU_EMMA2RH_CASCADE, &irq_cascade);
+ setup_irq(MIPS_CPU_IRQ_BASE + 2, &irq_cascade);
}
asmlinkage void plat_irq_dispatch(void)
@@ -309,13 +309,13 @@ asmlinkage void plat_irq_dispatch(void)
unsigned int pending = read_c0_status() & read_c0_cause() & ST0_IM;
if (pending & STATUSF_IP7)
- do_IRQ(CPU_IRQ_BASE + 7);
+ do_IRQ(MIPS_CPU_IRQ_BASE + 7);
else if (pending & STATUSF_IP2)
emma2rh_irq_dispatch();
else if (pending & STATUSF_IP1)
- do_IRQ(CPU_IRQ_BASE + 1);
+ do_IRQ(MIPS_CPU_IRQ_BASE + 1);
else if (pending & STATUSF_IP0)
- do_IRQ(CPU_IRQ_BASE + 0);
+ do_IRQ(MIPS_CPU_IRQ_BASE + 0);
else
spurious_interrupt();
}
diff --git a/arch/mips/emma/markeins/setup.c b/arch/mips/emma/markeins/setup.c
index 9b3f51e5f14..feceebcfff4 100644
--- a/arch/mips/emma/markeins/setup.c
+++ b/arch/mips/emma/markeins/setup.c
@@ -52,7 +52,6 @@ static void markeins_machine_halt(void)
static void markeins_machine_power_off(void)
{
- printk("EMMA2RH Mark-eins halted. Please turn off the power.\n");
markeins_led("poweroff.");
while (1) ;
}
diff --git a/arch/mips/include/asm/arch_hweight.h b/arch/mips/include/asm/arch_hweight.h
new file mode 100644
index 00000000000..712a7445ee9
--- /dev/null
+++ b/arch/mips/include/asm/arch_hweight.h
@@ -0,0 +1,38 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ */
+#ifndef _ASM_ARCH_HWEIGHT_H
+#define _ASM_ARCH_HWEIGHT_H
+
+#ifdef ARCH_HAS_USABLE_BUILTIN_POPCOUNT
+
+#include <asm/types.h>
+
+static inline unsigned int __arch_hweight32(unsigned int w)
+{
+ return __builtin_popcount(w);
+}
+
+static inline unsigned int __arch_hweight16(unsigned int w)
+{
+ return __builtin_popcount(w & 0xffff);
+}
+
+static inline unsigned int __arch_hweight8(unsigned int w)
+{
+ return __builtin_popcount(w & 0xff);
+}
+
+static inline unsigned long __arch_hweight64(__u64 w)
+{
+ return __builtin_popcountll(w);
+}
+
+#else
+#include <asm-generic/bitops/arch_hweight.h>
+#endif
+
+#endif /* _ASM_ARCH_HWEIGHT_H */
diff --git a/arch/mips/include/asm/bitops.h b/arch/mips/include/asm/bitops.h
index 9255cfbee45..b0ce7ca2851 100644
--- a/arch/mips/include/asm/bitops.h
+++ b/arch/mips/include/asm/bitops.h
@@ -700,7 +700,10 @@ static inline int ffs(int word)
#ifdef __KERNEL__
#include <asm-generic/bitops/sched.h>
-#include <asm-generic/bitops/hweight.h>
+
+#include <asm/arch_hweight.h>
+#include <asm-generic/bitops/const_hweight.h>
+
#include <asm-generic/bitops/ext2-non-atomic.h>
#include <asm-generic/bitops/ext2-atomic.h>
#include <asm-generic/bitops/minix.h>
diff --git a/arch/mips/include/asm/bootinfo.h b/arch/mips/include/asm/bootinfo.h
index 09eee09780f..15a8ef0707c 100644
--- a/arch/mips/include/asm/bootinfo.h
+++ b/arch/mips/include/asm/bootinfo.h
@@ -71,6 +71,12 @@
#define MACH_LEMOTE_LL2F 7
#define MACH_LOONGSON_END 8
+/*
+ * Valid machtype for group INGENIC
+ */
+#define MACH_INGENIC_JZ4730 0 /* JZ4730 SOC */
+#define MACH_INGENIC_JZ4740 1 /* JZ4740 SOC */
+
extern char *system_type;
const char *get_system_type(void);
diff --git a/arch/mips/include/asm/break.h b/arch/mips/include/asm/break.h
index 44437ed765e..9161e684cb4 100644
--- a/arch/mips/include/asm/break.h
+++ b/arch/mips/include/asm/break.h
@@ -30,6 +30,8 @@
#define BRK_BUG 512 /* Used by BUG() */
#define BRK_KDB 513 /* Used in KDB_ENTER() */
#define BRK_MEMU 514 /* Used by FPU emulator */
+#define BRK_KPROBE_BP 515 /* Kprobe break */
+#define BRK_KPROBE_SSTEPBP 516 /* Kprobe single step software implementation */
#define BRK_MULOVF 1023 /* Multiply overflow */
#endif /* __ASM_BREAK_H */
diff --git a/arch/mips/include/asm/cacheops.h b/arch/mips/include/asm/cacheops.h
index 256ad2cc6eb..8f99c11ab66 100644
--- a/arch/mips/include/asm/cacheops.h
+++ b/arch/mips/include/asm/cacheops.h
@@ -62,6 +62,8 @@
* RM7000-specific cacheops
*/
#define Page_Invalidate_T 0x16
+#define Index_Store_Tag_T 0x0a
+#define Index_Load_Tag_T 0x06
/*
* R10000-specific cacheops
diff --git a/arch/mips/include/asm/cop2.h b/arch/mips/include/asm/cop2.h
index 6b04c98b7fa..2cb2f0c2c4f 100644
--- a/arch/mips/include/asm/cop2.h
+++ b/arch/mips/include/asm/cop2.h
@@ -9,6 +9,8 @@
#ifndef __ASM_COP2_H
#define __ASM_COP2_H
+#include <linux/notifier.h>
+
enum cu2_ops {
CU2_EXCEPTION,
CU2_LWC2_OP,
@@ -20,4 +22,14 @@ enum cu2_ops {
extern int register_cu2_notifier(struct notifier_block *nb);
extern int cu2_notifier_call_chain(unsigned long val, void *v);
+#define cu2_notifier(fn, pri) \
+({ \
+ static struct notifier_block fn##_nb __cpuinitdata = { \
+ .notifier_call = fn, \
+ .priority = pri \
+ }; \
+ \
+ register_cu2_notifier(&fn##_nb); \
+})
+
#endif /* __ASM_COP2_H */
diff --git a/arch/mips/include/asm/cpu-features.h b/arch/mips/include/asm/cpu-features.h
index ac73cede3a0..ca400f7c3f5 100644
--- a/arch/mips/include/asm/cpu-features.h
+++ b/arch/mips/include/asm/cpu-features.h
@@ -159,7 +159,8 @@
/*
* MIPS32, MIPS64, VR5500, IDT32332, IDT32334 and maybe a few other
- * pre-MIPS32/MIPS53 processors have CLO, CLZ. For 64-bit kernels
+ * pre-MIPS32/MIPS53 processors have CLO, CLZ. The IDT RC64574 is 64-bit and
+ * has CLO and CLZ but not DCLO nor DCLZ. For 64-bit kernels
* cpu_has_clo_clz also indicates the availability of DCLO and DCLZ.
*/
# ifndef cpu_has_clo_clz
diff --git a/arch/mips/include/asm/cpu.h b/arch/mips/include/asm/cpu.h
index a5acda41694..b201a8f5b12 100644
--- a/arch/mips/include/asm/cpu.h
+++ b/arch/mips/include/asm/cpu.h
@@ -34,7 +34,7 @@
#define PRID_COMP_LSI 0x080000
#define PRID_COMP_LEXRA 0x0b0000
#define PRID_COMP_CAVIUM 0x0d0000
-
+#define PRID_COMP_INGENIC 0xd00000
/*
* Assigned values for the product ID register. In order to detect a
@@ -133,6 +133,12 @@
#define PRID_IMP_CAVIUM_CN52XX 0x0700
/*
+ * These are the PRID's for when 23:16 == PRID_COMP_INGENIC
+ */
+
+#define PRID_IMP_JZRISC 0x0200
+
+/*
* Definitions for 7:0 on legacy processors
*/
@@ -219,6 +225,7 @@ enum cpu_type_enum {
CPU_4KC, CPU_4KEC, CPU_4KSC, CPU_24K, CPU_34K, CPU_1004K, CPU_74K,
CPU_ALCHEMY, CPU_PR4450, CPU_BCM3302, CPU_BCM4710,
CPU_BCM6338, CPU_BCM6345, CPU_BCM6348, CPU_BCM6358,
+ CPU_JZRISC,
/*
* MIPS64 class processors
diff --git a/arch/mips/include/asm/elf.h b/arch/mips/include/asm/elf.h
index ea77a42c5f8..fd1d39eb743 100644
--- a/arch/mips/include/asm/elf.h
+++ b/arch/mips/include/asm/elf.h
@@ -372,4 +372,9 @@ extern const char *__elf_platform;
struct linux_binprm;
extern int arch_setup_additional_pages(struct linux_binprm *bprm,
int uses_interp);
+
+struct mm_struct;
+extern unsigned long arch_randomize_brk(struct mm_struct *mm);
+#define arch_randomize_brk arch_randomize_brk
+
#endif /* _ASM_ELF_H */
diff --git a/arch/mips/include/asm/emma/emma2rh.h b/arch/mips/include/asm/emma/emma2rh.h
index 2afb2fe11b3..c1449d20ef0 100644
--- a/arch/mips/include/asm/emma/emma2rh.h
+++ b/arch/mips/include/asm/emma/emma2rh.h
@@ -99,88 +99,22 @@
#define EMMA2RH_PCI_CONFIG_BASE EMMA2RH_PCI_IO_BASE
#define EMMA2RH_PCI_CONFIG_SIZE EMMA2RH_PCI_IO_SIZE
-#define NUM_CPU_IRQ 8
#define NUM_EMMA2RH_IRQ 96
-#define CPU_EMMA2RH_CASCADE 2
-#define CPU_IRQ_BASE MIPS_CPU_IRQ_BASE
-#define EMMA2RH_IRQ_BASE (CPU_IRQ_BASE + NUM_CPU_IRQ)
+#define EMMA2RH_IRQ_BASE (MIPS_CPU_IRQ_BASE + 8)
/*
* emma2rh irq defs
*/
-#define EMMA2RH_IRQ_INT0 (0 + EMMA2RH_IRQ_BASE)
-#define EMMA2RH_IRQ_INT1 (1 + EMMA2RH_IRQ_BASE)
-#define EMMA2RH_IRQ_INT2 (2 + EMMA2RH_IRQ_BASE)
-#define EMMA2RH_IRQ_INT3 (3 + EMMA2RH_IRQ_BASE)
-#define EMMA2RH_IRQ_INT4 (4 + EMMA2RH_IRQ_BASE)
-#define EMMA2RH_IRQ_INT5 (5 + EMMA2RH_IRQ_BASE)
-#define EMMA2RH_IRQ_INT6 (6 + EMMA2RH_IRQ_BASE)
-#define EMMA2RH_IRQ_INT7 (7 + EMMA2RH_IRQ_BASE)
-#define EMMA2RH_IRQ_INT8 (8 + EMMA2RH_IRQ_BASE)
-#define EMMA2RH_IRQ_INT9 (9 + EMMA2RH_IRQ_BASE)
-#define EMMA2RH_IRQ_INT10 (10 + EMMA2RH_IRQ_BASE)
-#define EMMA2RH_IRQ_INT11 (11 + EMMA2RH_IRQ_BASE)
-#define EMMA2RH_IRQ_INT12 (12 + EMMA2RH_IRQ_BASE)
-#define EMMA2RH_IRQ_INT13 (13 + EMMA2RH_IRQ_BASE)
-#define EMMA2RH_IRQ_INT14 (14 + EMMA2RH_IRQ_BASE)
-#define EMMA2RH_IRQ_INT15 (15 + EMMA2RH_IRQ_BASE)
-#define EMMA2RH_IRQ_INT16 (16 + EMMA2RH_IRQ_BASE)
-#define EMMA2RH_IRQ_INT17 (17 + EMMA2RH_IRQ_BASE)
-#define EMMA2RH_IRQ_INT18 (18 + EMMA2RH_IRQ_BASE)
-#define EMMA2RH_IRQ_INT19 (19 + EMMA2RH_IRQ_BASE)
-#define EMMA2RH_IRQ_INT20 (20 + EMMA2RH_IRQ_BASE)
-#define EMMA2RH_IRQ_INT21 (21 + EMMA2RH_IRQ_BASE)
-#define EMMA2RH_IRQ_INT22 (22 + EMMA2RH_IRQ_BASE)
-#define EMMA2RH_IRQ_INT23 (23 + EMMA2RH_IRQ_BASE)
-#define EMMA2RH_IRQ_INT24 (24 + EMMA2RH_IRQ_BASE)
-#define EMMA2RH_IRQ_INT25 (25 + EMMA2RH_IRQ_BASE)
-#define EMMA2RH_IRQ_INT26 (26 + EMMA2RH_IRQ_BASE)
-#define EMMA2RH_IRQ_INT27 (27 + EMMA2RH_IRQ_BASE)
-#define EMMA2RH_IRQ_INT28 (28 + EMMA2RH_IRQ_BASE)
-#define EMMA2RH_IRQ_INT29 (29 + EMMA2RH_IRQ_BASE)
-#define EMMA2RH_IRQ_INT30 (30 + EMMA2RH_IRQ_BASE)
-#define EMMA2RH_IRQ_INT31 (31 + EMMA2RH_IRQ_BASE)
-#define EMMA2RH_IRQ_INT32 (32 + EMMA2RH_IRQ_BASE)
-#define EMMA2RH_IRQ_INT33 (33 + EMMA2RH_IRQ_BASE)
-#define EMMA2RH_IRQ_INT34 (34 + EMMA2RH_IRQ_BASE)
-#define EMMA2RH_IRQ_INT35 (35 + EMMA2RH_IRQ_BASE)
-#define EMMA2RH_IRQ_INT36 (36 + EMMA2RH_IRQ_BASE)
-#define EMMA2RH_IRQ_INT37 (37 + EMMA2RH_IRQ_BASE)
-#define EMMA2RH_IRQ_INT38 (38 + EMMA2RH_IRQ_BASE)
-#define EMMA2RH_IRQ_INT39 (39 + EMMA2RH_IRQ_BASE)
-#define EMMA2RH_IRQ_INT40 (40 + EMMA2RH_IRQ_BASE)
-#define EMMA2RH_IRQ_INT41 (41 + EMMA2RH_IRQ_BASE)
-#define EMMA2RH_IRQ_INT42 (42 + EMMA2RH_IRQ_BASE)
-#define EMMA2RH_IRQ_INT43 (43 + EMMA2RH_IRQ_BASE)
-#define EMMA2RH_IRQ_INT44 (44 + EMMA2RH_IRQ_BASE)
-#define EMMA2RH_IRQ_INT45 (45 + EMMA2RH_IRQ_BASE)
-#define EMMA2RH_IRQ_INT46 (46 + EMMA2RH_IRQ_BASE)
-#define EMMA2RH_IRQ_INT47 (47 + EMMA2RH_IRQ_BASE)
-#define EMMA2RH_IRQ_INT48 (48 + EMMA2RH_IRQ_BASE)
-#define EMMA2RH_IRQ_INT49 (49 + EMMA2RH_IRQ_BASE)
-#define EMMA2RH_IRQ_INT50 (50 + EMMA2RH_IRQ_BASE)
-#define EMMA2RH_IRQ_INT51 (51 + EMMA2RH_IRQ_BASE)
-#define EMMA2RH_IRQ_INT52 (52 + EMMA2RH_IRQ_BASE)
-#define EMMA2RH_IRQ_INT53 (53 + EMMA2RH_IRQ_BASE)
-#define EMMA2RH_IRQ_INT54 (54 + EMMA2RH_IRQ_BASE)
-#define EMMA2RH_IRQ_INT55 (55 + EMMA2RH_IRQ_BASE)
-#define EMMA2RH_IRQ_INT56 (56 + EMMA2RH_IRQ_BASE)
-#define EMMA2RH_IRQ_INT57 (57 + EMMA2RH_IRQ_BASE)
-#define EMMA2RH_IRQ_INT58 (58 + EMMA2RH_IRQ_BASE)
-#define EMMA2RH_IRQ_INT59 (59 + EMMA2RH_IRQ_BASE)
-#define EMMA2RH_IRQ_INT60 (60 + EMMA2RH_IRQ_BASE)
-#define EMMA2RH_IRQ_INT61 (61 + EMMA2RH_IRQ_BASE)
-#define EMMA2RH_IRQ_INT62 (62 + EMMA2RH_IRQ_BASE)
-#define EMMA2RH_IRQ_INT63 (63 + EMMA2RH_IRQ_BASE)
-
-#define EMMA2RH_IRQ_PFUR0 EMMA2RH_IRQ_INT49
-#define EMMA2RH_IRQ_PFUR1 EMMA2RH_IRQ_INT50
-#define EMMA2RH_IRQ_PFUR2 EMMA2RH_IRQ_INT51
-#define EMMA2RH_IRQ_PIIC0 EMMA2RH_IRQ_INT56
-#define EMMA2RH_IRQ_PIIC1 EMMA2RH_IRQ_INT57
-#define EMMA2RH_IRQ_PIIC2 EMMA2RH_IRQ_INT58
+#define EMMA2RH_IRQ_INT(n) (EMMA2RH_IRQ_BASE + (n))
+
+#define EMMA2RH_IRQ_PFUR0 EMMA2RH_IRQ_INT(49)
+#define EMMA2RH_IRQ_PFUR1 EMMA2RH_IRQ_INT(50)
+#define EMMA2RH_IRQ_PFUR2 EMMA2RH_IRQ_INT(51)
+#define EMMA2RH_IRQ_PIIC0 EMMA2RH_IRQ_INT(56)
+#define EMMA2RH_IRQ_PIIC1 EMMA2RH_IRQ_INT(57)
+#define EMMA2RH_IRQ_PIIC2 EMMA2RH_IRQ_INT(58)
/*
* EMMA2RH Register Access
diff --git a/arch/mips/include/asm/emma/markeins.h b/arch/mips/include/asm/emma/markeins.h
index 2618bf23024..bf2d229c2da 100644
--- a/arch/mips/include/asm/emma/markeins.h
+++ b/arch/mips/include/asm/emma/markeins.h
@@ -25,44 +25,13 @@
#define NUM_EMMA2RH_IRQ_SW 32
#define NUM_EMMA2RH_IRQ_GPIO 32
-#define EMMA2RH_SW_CASCADE (EMMA2RH_IRQ_INT7 - EMMA2RH_IRQ_INT0)
-#define EMMA2RH_GPIO_CASCADE (EMMA2RH_IRQ_INT46 - EMMA2RH_IRQ_INT0)
+#define EMMA2RH_SW_CASCADE (EMMA2RH_IRQ_INT(7) - EMMA2RH_IRQ_INT(0))
+#define EMMA2RH_GPIO_CASCADE (EMMA2RH_IRQ_INT(46) - EMMA2RH_IRQ_INT(0))
#define EMMA2RH_SW_IRQ_BASE (EMMA2RH_IRQ_BASE + NUM_EMMA2RH_IRQ)
#define EMMA2RH_GPIO_IRQ_BASE (EMMA2RH_SW_IRQ_BASE + NUM_EMMA2RH_IRQ_SW)
-#define EMMA2RH_SW_IRQ_INT0 (0+EMMA2RH_SW_IRQ_BASE)
-#define EMMA2RH_SW_IRQ_INT1 (1+EMMA2RH_SW_IRQ_BASE)
-#define EMMA2RH_SW_IRQ_INT2 (2+EMMA2RH_SW_IRQ_BASE)
-#define EMMA2RH_SW_IRQ_INT3 (3+EMMA2RH_SW_IRQ_BASE)
-#define EMMA2RH_SW_IRQ_INT4 (4+EMMA2RH_SW_IRQ_BASE)
-#define EMMA2RH_SW_IRQ_INT5 (5+EMMA2RH_SW_IRQ_BASE)
-#define EMMA2RH_SW_IRQ_INT6 (6+EMMA2RH_SW_IRQ_BASE)
-#define EMMA2RH_SW_IRQ_INT7 (7+EMMA2RH_SW_IRQ_BASE)
-#define EMMA2RH_SW_IRQ_INT8 (8+EMMA2RH_SW_IRQ_BASE)
-#define EMMA2RH_SW_IRQ_INT9 (9+EMMA2RH_SW_IRQ_BASE)
-#define EMMA2RH_SW_IRQ_INT10 (10+EMMA2RH_SW_IRQ_BASE)
-#define EMMA2RH_SW_IRQ_INT11 (11+EMMA2RH_SW_IRQ_BASE)
-#define EMMA2RH_SW_IRQ_INT12 (12+EMMA2RH_SW_IRQ_BASE)
-#define EMMA2RH_SW_IRQ_INT13 (13+EMMA2RH_SW_IRQ_BASE)
-#define EMMA2RH_SW_IRQ_INT14 (14+EMMA2RH_SW_IRQ_BASE)
-#define EMMA2RH_SW_IRQ_INT15 (15+EMMA2RH_SW_IRQ_BASE)
-#define EMMA2RH_SW_IRQ_INT16 (16+EMMA2RH_SW_IRQ_BASE)
-#define EMMA2RH_SW_IRQ_INT17 (17+EMMA2RH_SW_IRQ_BASE)
-#define EMMA2RH_SW_IRQ_INT18 (18+EMMA2RH_SW_IRQ_BASE)
-#define EMMA2RH_SW_IRQ_INT19 (19+EMMA2RH_SW_IRQ_BASE)
-#define EMMA2RH_SW_IRQ_INT20 (20+EMMA2RH_SW_IRQ_BASE)
-#define EMMA2RH_SW_IRQ_INT21 (21+EMMA2RH_SW_IRQ_BASE)
-#define EMMA2RH_SW_IRQ_INT22 (22+EMMA2RH_SW_IRQ_BASE)
-#define EMMA2RH_SW_IRQ_INT23 (23+EMMA2RH_SW_IRQ_BASE)
-#define EMMA2RH_SW_IRQ_INT24 (24+EMMA2RH_SW_IRQ_BASE)
-#define EMMA2RH_SW_IRQ_INT25 (25+EMMA2RH_SW_IRQ_BASE)
-#define EMMA2RH_SW_IRQ_INT26 (26+EMMA2RH_SW_IRQ_BASE)
-#define EMMA2RH_SW_IRQ_INT27 (27+EMMA2RH_SW_IRQ_BASE)
-#define EMMA2RH_SW_IRQ_INT28 (28+EMMA2RH_SW_IRQ_BASE)
-#define EMMA2RH_SW_IRQ_INT29 (29+EMMA2RH_SW_IRQ_BASE)
-#define EMMA2RH_SW_IRQ_INT30 (30+EMMA2RH_SW_IRQ_BASE)
-#define EMMA2RH_SW_IRQ_INT31 (31+EMMA2RH_SW_IRQ_BASE)
+#define EMMA2RH_SW_IRQ_INT(n) (EMMA2RH_SW_IRQ_BASE + (n))
#define MARKEINS_PCI_IRQ_INTA EMMA2RH_GPIO_IRQ_BASE+15
#define MARKEINS_PCI_IRQ_INTB EMMA2RH_GPIO_IRQ_BASE+16
diff --git a/arch/mips/include/asm/hazards.h b/arch/mips/include/asm/hazards.h
index 0eaf77ffbc4..4e332165d7b 100644
--- a/arch/mips/include/asm/hazards.h
+++ b/arch/mips/include/asm/hazards.h
@@ -87,7 +87,7 @@ do { \
: "=r" (tmp)); \
} while (0)
-#elif defined(CONFIG_CPU_MIPSR1) && !defined(CONFIG_MACH_ALCHEMY)
+#elif defined(CONFIG_CPU_MIPSR1) && !defined(CONFIG_MIPS_ALCHEMY)
/*
* These are slightly complicated by the fact that we guarantee R1 kernels to
@@ -138,7 +138,7 @@ do { \
__instruction_hazard(); \
} while (0)
-#elif defined(CONFIG_MACH_ALCHEMY) || defined(CONFIG_CPU_CAVIUM_OCTEON) || \
+#elif defined(CONFIG_MIPS_ALCHEMY) || defined(CONFIG_CPU_CAVIUM_OCTEON) || \
defined(CONFIG_CPU_LOONGSON2) || defined(CONFIG_CPU_R10000) || \
defined(CONFIG_CPU_R5500)
diff --git a/arch/mips/include/asm/inst.h b/arch/mips/include/asm/inst.h
index 6489f00731c..444ff71aa0e 100644
--- a/arch/mips/include/asm/inst.h
+++ b/arch/mips/include/asm/inst.h
@@ -247,6 +247,12 @@ struct ma_format { /* FPU multipy and add format (MIPS IV) */
unsigned int fmt : 2;
};
+struct b_format { /* BREAK and SYSCALL */
+ unsigned int opcode:6;
+ unsigned int code:20;
+ unsigned int func:6;
+};
+
#elif defined(__MIPSEL__)
struct j_format { /* Jump format */
@@ -314,6 +320,12 @@ struct ma_format { /* FPU multipy and add format (MIPS IV) */
unsigned int opcode : 6;
};
+struct b_format { /* BREAK and SYSCALL */
+ unsigned int func:6;
+ unsigned int code:20;
+ unsigned int opcode:6;
+};
+
#else /* !defined (__MIPSEB__) && !defined (__MIPSEL__) */
#error "MIPS but neither __MIPSEL__ nor __MIPSEB__?"
#endif
@@ -328,7 +340,8 @@ union mips_instruction {
struct c_format c_format;
struct r_format r_format;
struct f_format f_format;
- struct ma_format ma_format;
+ struct ma_format ma_format;
+ struct b_format b_format;
};
/* HACHACHAHCAHC ... */
diff --git a/arch/mips/include/asm/kdebug.h b/arch/mips/include/asm/kdebug.h
index 5bf62aafc89..6a9af5fcb5d 100644
--- a/arch/mips/include/asm/kdebug.h
+++ b/arch/mips/include/asm/kdebug.h
@@ -8,6 +8,9 @@ enum die_val {
DIE_FP,
DIE_TRAP,
DIE_RI,
+ DIE_PAGE_FAULT,
+ DIE_BREAK,
+ DIE_SSTEPBP
};
#endif /* _ASM_MIPS_KDEBUG_H */
diff --git a/arch/mips/include/asm/kgdb.h b/arch/mips/include/asm/kgdb.h
index 19002d605ac..e6c0b0e14cc 100644
--- a/arch/mips/include/asm/kgdb.h
+++ b/arch/mips/include/asm/kgdb.h
@@ -8,28 +8,27 @@
#if (_MIPS_ISA == _MIPS_ISA_MIPS1) || (_MIPS_ISA == _MIPS_ISA_MIPS2) || \
(_MIPS_ISA == _MIPS_ISA_MIPS32)
-#define KGDB_GDB_REG_SIZE 32
+#define KGDB_GDB_REG_SIZE 32
+#define GDB_SIZEOF_REG sizeof(u32)
#elif (_MIPS_ISA == _MIPS_ISA_MIPS3) || (_MIPS_ISA == _MIPS_ISA_MIPS4) || \
(_MIPS_ISA == _MIPS_ISA_MIPS64)
#ifdef CONFIG_32BIT
-#define KGDB_GDB_REG_SIZE 32
+#define KGDB_GDB_REG_SIZE 32
+#define GDB_SIZEOF_REG sizeof(u32)
#else /* CONFIG_CPU_32BIT */
-#define KGDB_GDB_REG_SIZE 64
+#define KGDB_GDB_REG_SIZE 64
+#define GDB_SIZEOF_REG sizeof(u64)
#endif
#else
#error "Need to set KGDB_GDB_REG_SIZE for MIPS ISA"
#endif /* _MIPS_ISA */
#define BUFMAX 2048
-#if (KGDB_GDB_REG_SIZE == 32)
-#define NUMREGBYTES (90*sizeof(u32))
-#define NUMCRITREGBYTES (12*sizeof(u32))
-#else
-#define NUMREGBYTES (90*sizeof(u64))
-#define NUMCRITREGBYTES (12*sizeof(u64))
-#endif
+#define DBG_MAX_REG_NUM 72
+#define NUMREGBYTES (DBG_MAX_REG_NUM * sizeof(GDB_SIZEOF_REG))
+#define NUMCRITREGBYTES (12 * sizeof(GDB_SIZEOF_REG))
#define BREAK_INSTR_SIZE 4
#define CACHE_FLUSH_IS_SAFE 0
diff --git a/arch/mips/include/asm/kprobes.h b/arch/mips/include/asm/kprobes.h
new file mode 100644
index 00000000000..e6ea4d4d720
--- /dev/null
+++ b/arch/mips/include/asm/kprobes.h
@@ -0,0 +1,92 @@
+/*
+ * Kernel Probes (KProbes)
+ * include/asm-mips/kprobes.h
+ *
+ * Copyright 2006 Sony Corp.
+ * Copyright 2010 Cavium Networks
+ *
+ * This program is free software; 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
+ */
+
+#ifndef _ASM_KPROBES_H
+#define _ASM_KPROBES_H
+
+#include <linux/ptrace.h>
+#include <linux/types.h>
+
+#include <asm/cacheflush.h>
+#include <asm/kdebug.h>
+#include <asm/inst.h>
+
+#define __ARCH_WANT_KPROBES_INSN_SLOT
+
+struct kprobe;
+struct pt_regs;
+
+typedef union mips_instruction kprobe_opcode_t;
+
+#define MAX_INSN_SIZE 2
+
+#define flush_insn_slot(p) \
+do { \
+ flush_icache_range((unsigned long)p->addr, \
+ (unsigned long)p->addr + \
+ (MAX_INSN_SIZE * sizeof(kprobe_opcode_t))); \
+} while (0)
+
+
+#define kretprobe_blacklist_size 0
+
+void arch_remove_kprobe(struct kprobe *p);
+
+/* Architecture specific copy of original instruction*/
+struct arch_specific_insn {
+ /* copy of the original instruction */
+ kprobe_opcode_t *insn;
+};
+
+struct prev_kprobe {
+ struct kprobe *kp;
+ unsigned long status;
+ unsigned long old_SR;
+ unsigned long saved_SR;
+ unsigned long saved_epc;
+};
+
+#define MAX_JPROBES_STACK_SIZE 128
+#define MAX_JPROBES_STACK_ADDR \
+ (((unsigned long)current_thread_info()) + THREAD_SIZE - 32 - sizeof(struct pt_regs))
+
+#define MIN_JPROBES_STACK_SIZE(ADDR) \
+ ((((ADDR) + MAX_JPROBES_STACK_SIZE) > MAX_JPROBES_STACK_ADDR) \
+ ? MAX_JPROBES_STACK_ADDR - (ADDR) \
+ : MAX_JPROBES_STACK_SIZE)
+
+
+/* per-cpu kprobe control block */
+struct kprobe_ctlblk {
+ unsigned long kprobe_status;
+ unsigned long kprobe_old_SR;
+ unsigned long kprobe_saved_SR;
+ unsigned long kprobe_saved_epc;
+ unsigned long jprobe_saved_sp;
+ struct pt_regs jprobe_saved_regs;
+ u8 jprobes_stack[MAX_JPROBES_STACK_SIZE];
+ struct prev_kprobe prev_kprobe;
+};
+
+extern int kprobe_exceptions_notify(struct notifier_block *self,
+ unsigned long val, void *data);
+
+#endif /* _ASM_KPROBES_H */
diff --git a/arch/mips/include/asm/local64.h b/arch/mips/include/asm/local64.h
new file mode 100644
index 00000000000..36c93b5cc23
--- /dev/null
+++ b/arch/mips/include/asm/local64.h
@@ -0,0 +1 @@
+#include <asm-generic/local64.h>
diff --git a/arch/mips/include/asm/mach-au1x00/au1xxx_eth.h b/arch/mips/include/asm/mach-au1x00/au1xxx_eth.h
index bae9b758fcd..49dc8d9db18 100644
--- a/arch/mips/include/asm/mach-au1x00/au1xxx_eth.h
+++ b/arch/mips/include/asm/mach-au1x00/au1xxx_eth.h
@@ -9,6 +9,7 @@ struct au1000_eth_platform_data {
int phy_addr;
int phy_busid;
int phy_irq;
+ char mac[6];
};
void __init au1xxx_override_eth_cfg(unsigned port,
diff --git a/arch/mips/include/asm/mach-bcm47xx/nvram.h b/arch/mips/include/asm/mach-bcm47xx/nvram.h
index 0d8cc146f7a..c58ebd8bc15 100644
--- a/arch/mips/include/asm/mach-bcm47xx/nvram.h
+++ b/arch/mips/include/asm/mach-bcm47xx/nvram.h
@@ -31,6 +31,9 @@ struct nvram_header {
#define NVRAM_MAX_VALUE_LEN 255
#define NVRAM_MAX_PARAM_LEN 64
+#define NVRAM_ERR_INV_PARAM -8
+#define NVRAM_ERR_ENVNOTFOUND -9
+
extern int nvram_getenv(char *name, char *val, size_t val_len);
#endif
diff --git a/arch/mips/include/asm/mach-cavium-octeon/cpu-feature-overrides.h b/arch/mips/include/asm/mach-cavium-octeon/cpu-feature-overrides.h
index bbf05404239..b952fc7215e 100644
--- a/arch/mips/include/asm/mach-cavium-octeon/cpu-feature-overrides.h
+++ b/arch/mips/include/asm/mach-cavium-octeon/cpu-feature-overrides.h
@@ -61,21 +61,18 @@
#define kernel_uses_smartmips_rixi (cpu_data[0].cputype == CPU_CAVIUM_OCTEON_PLUS)
-#define ARCH_HAS_READ_CURRENT_TIMER 1
#define ARCH_HAS_IRQ_PER_CPU 1
#define ARCH_HAS_SPINLOCK_PREFETCH 1
#define spin_lock_prefetch(x) prefetch(x)
#define PREFETCH_STRIDE 128
-static inline int read_current_timer(unsigned long *result)
-{
- asm volatile ("rdhwr %0,$31\n"
-#ifndef CONFIG_64BIT
- "\tsll %0, 0"
+#ifdef __OCTEON__
+/*
+ * All gcc versions that have OCTEON support define __OCTEON__ and have the
+ * __builtin_popcount support.
+ */
+#define ARCH_HAS_USABLE_BUILTIN_POPCOUNT 1
#endif
- : "=r" (*result));
- return 0;
-}
static inline int octeon_has_saa(void)
{
diff --git a/arch/mips/include/asm/mach-cavium-octeon/irq.h b/arch/mips/include/asm/mach-cavium-octeon/irq.h
index d32220fbf4f..6ddab8aef64 100644
--- a/arch/mips/include/asm/mach-cavium-octeon/irq.h
+++ b/arch/mips/include/asm/mach-cavium-octeon/irq.h
@@ -172,71 +172,9 @@
#ifdef CONFIG_PCI_MSI
/* 152 - 215 represent the MSI interrupts 0-63 */
#define OCTEON_IRQ_MSI_BIT0 152
-#define OCTEON_IRQ_MSI_BIT1 153
-#define OCTEON_IRQ_MSI_BIT2 154
-#define OCTEON_IRQ_MSI_BIT3 155
-#define OCTEON_IRQ_MSI_BIT4 156
-#define OCTEON_IRQ_MSI_BIT5 157
-#define OCTEON_IRQ_MSI_BIT6 158
-#define OCTEON_IRQ_MSI_BIT7 159
-#define OCTEON_IRQ_MSI_BIT8 160
-#define OCTEON_IRQ_MSI_BIT9 161
-#define OCTEON_IRQ_MSI_BIT10 162
-#define OCTEON_IRQ_MSI_BIT11 163
-#define OCTEON_IRQ_MSI_BIT12 164
-#define OCTEON_IRQ_MSI_BIT13 165
-#define OCTEON_IRQ_MSI_BIT14 166
-#define OCTEON_IRQ_MSI_BIT15 167
-#define OCTEON_IRQ_MSI_BIT16 168
-#define OCTEON_IRQ_MSI_BIT17 169
-#define OCTEON_IRQ_MSI_BIT18 170
-#define OCTEON_IRQ_MSI_BIT19 171
-#define OCTEON_IRQ_MSI_BIT20 172
-#define OCTEON_IRQ_MSI_BIT21 173
-#define OCTEON_IRQ_MSI_BIT22 174
-#define OCTEON_IRQ_MSI_BIT23 175
-#define OCTEON_IRQ_MSI_BIT24 176
-#define OCTEON_IRQ_MSI_BIT25 177
-#define OCTEON_IRQ_MSI_BIT26 178
-#define OCTEON_IRQ_MSI_BIT27 179
-#define OCTEON_IRQ_MSI_BIT28 180
-#define OCTEON_IRQ_MSI_BIT29 181
-#define OCTEON_IRQ_MSI_BIT30 182
-#define OCTEON_IRQ_MSI_BIT31 183
-#define OCTEON_IRQ_MSI_BIT32 184
-#define OCTEON_IRQ_MSI_BIT33 185
-#define OCTEON_IRQ_MSI_BIT34 186
-#define OCTEON_IRQ_MSI_BIT35 187
-#define OCTEON_IRQ_MSI_BIT36 188
-#define OCTEON_IRQ_MSI_BIT37 189
-#define OCTEON_IRQ_MSI_BIT38 190
-#define OCTEON_IRQ_MSI_BIT39 191
-#define OCTEON_IRQ_MSI_BIT40 192
-#define OCTEON_IRQ_MSI_BIT41 193
-#define OCTEON_IRQ_MSI_BIT42 194
-#define OCTEON_IRQ_MSI_BIT43 195
-#define OCTEON_IRQ_MSI_BIT44 196
-#define OCTEON_IRQ_MSI_BIT45 197
-#define OCTEON_IRQ_MSI_BIT46 198
-#define OCTEON_IRQ_MSI_BIT47 199
-#define OCTEON_IRQ_MSI_BIT48 200
-#define OCTEON_IRQ_MSI_BIT49 201
-#define OCTEON_IRQ_MSI_BIT50 202
-#define OCTEON_IRQ_MSI_BIT51 203
-#define OCTEON_IRQ_MSI_BIT52 204
-#define OCTEON_IRQ_MSI_BIT53 205
-#define OCTEON_IRQ_MSI_BIT54 206
-#define OCTEON_IRQ_MSI_BIT55 207
-#define OCTEON_IRQ_MSI_BIT56 208
-#define OCTEON_IRQ_MSI_BIT57 209
-#define OCTEON_IRQ_MSI_BIT58 210
-#define OCTEON_IRQ_MSI_BIT59 211
-#define OCTEON_IRQ_MSI_BIT60 212
-#define OCTEON_IRQ_MSI_BIT61 213
-#define OCTEON_IRQ_MSI_BIT62 214
-#define OCTEON_IRQ_MSI_BIT63 215
+#define OCTEON_IRQ_MSI_LAST (OCTEON_IRQ_MSI_BIT0 + 255)
-#define OCTEON_IRQ_LAST 216
+#define OCTEON_IRQ_LAST (OCTEON_IRQ_MSI_LAST + 1)
#else
#define OCTEON_IRQ_LAST 152
#endif
diff --git a/arch/mips/include/asm/mach-jz4740/base.h b/arch/mips/include/asm/mach-jz4740/base.h
new file mode 100644
index 00000000000..f3731860545
--- /dev/null
+++ b/arch/mips/include/asm/mach-jz4740/base.h
@@ -0,0 +1,26 @@
+#ifndef __ASM_MACH_JZ4740_BASE_H__
+#define __ASM_MACH_JZ4740_BASE_H__
+
+#define JZ4740_CPM_BASE_ADDR 0x10000000
+#define JZ4740_INTC_BASE_ADDR 0x10001000
+#define JZ4740_WDT_BASE_ADDR 0x10002000
+#define JZ4740_TCU_BASE_ADDR 0x10002010
+#define JZ4740_RTC_BASE_ADDR 0x10003000
+#define JZ4740_GPIO_BASE_ADDR 0x10010000
+#define JZ4740_AIC_BASE_ADDR 0x10020000
+#define JZ4740_MSC_BASE_ADDR 0x10021000
+#define JZ4740_UART0_BASE_ADDR 0x10030000
+#define JZ4740_UART1_BASE_ADDR 0x10031000
+#define JZ4740_I2C_BASE_ADDR 0x10042000
+#define JZ4740_SSI_BASE_ADDR 0x10043000
+#define JZ4740_SADC_BASE_ADDR 0x10070000
+#define JZ4740_EMC_BASE_ADDR 0x13010000
+#define JZ4740_DMAC_BASE_ADDR 0x13020000
+#define JZ4740_UHC_BASE_ADDR 0x13030000
+#define JZ4740_UDC_BASE_ADDR 0x13040000
+#define JZ4740_LCD_BASE_ADDR 0x13050000
+#define JZ4740_SLCD_BASE_ADDR 0x13050000
+#define JZ4740_CIM_BASE_ADDR 0x13060000
+#define JZ4740_IPU_BASE_ADDR 0x13080000
+
+#endif
diff --git a/arch/mips/include/asm/mach-jz4740/clock.h b/arch/mips/include/asm/mach-jz4740/clock.h
new file mode 100644
index 00000000000..1b7408dd0e2
--- /dev/null
+++ b/arch/mips/include/asm/mach-jz4740/clock.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2010, Lars-Peter Clausen <lars@metafoo.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.
+ *
+ * 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 __ASM_JZ4740_CLOCK_H__
+#define __ASM_JZ4740_CLOCK_H__
+
+enum jz4740_wait_mode {
+ JZ4740_WAIT_MODE_IDLE,
+ JZ4740_WAIT_MODE_SLEEP,
+};
+
+void jz4740_clock_set_wait_mode(enum jz4740_wait_mode mode);
+
+void jz4740_clock_udc_enable_auto_suspend(void);
+void jz4740_clock_udc_disable_auto_suspend(void);
+
+#endif
diff --git a/arch/mips/include/asm/mach-jz4740/cpu-feature-overrides.h b/arch/mips/include/asm/mach-jz4740/cpu-feature-overrides.h
new file mode 100644
index 00000000000..d12e5c6477b
--- /dev/null
+++ b/arch/mips/include/asm/mach-jz4740/cpu-feature-overrides.h
@@ -0,0 +1,51 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ */
+#ifndef __ASM_MACH_JZ4740_CPU_FEATURE_OVERRIDES_H
+#define __ASM_MACH_JZ4740_CPU_FEATURE_OVERRIDES_H
+
+#define cpu_has_tlb 1
+#define cpu_has_4kex 1
+#define cpu_has_3k_cache 0
+#define cpu_has_4k_cache 1
+#define cpu_has_tx39_cache 0
+#define cpu_has_fpu 0
+#define cpu_has_32fpr 0
+#define cpu_has_counter 0
+#define cpu_has_watch 1
+#define cpu_has_divec 1
+#define cpu_has_vce 0
+#define cpu_has_cache_cdex_p 0
+#define cpu_has_cache_cdex_s 0
+#define cpu_has_prefetch 1
+#define cpu_has_mcheck 1
+#define cpu_has_ejtag 1
+#define cpu_has_llsc 1
+#define cpu_has_mips16 0
+#define cpu_has_mdmx 0
+#define cpu_has_mips3d 0
+#define cpu_has_smartmips 0
+#define kernel_uses_llsc 1
+#define cpu_has_vtag_icache 1
+#define cpu_has_dc_aliases 0
+#define cpu_has_ic_fills_f_dc 0
+#define cpu_has_pindexed_dcache 0
+#define cpu_has_mips32r1 1
+#define cpu_has_mips32r2 0
+#define cpu_has_mips64r1 0
+#define cpu_has_mips64r2 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 0
+#define cpu_has_64bit_zero_reg 0
+#define cpu_has_inclusive_pcaches 0
+
+#define cpu_dcache_line_size() 32
+#define cpu_icache_line_size() 32
+
+#endif
diff --git a/arch/mips/include/asm/mach-jz4740/dma.h b/arch/mips/include/asm/mach-jz4740/dma.h
new file mode 100644
index 00000000000..a3be1218359
--- /dev/null
+++ b/arch/mips/include/asm/mach-jz4740/dma.h
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2010, Lars-Peter Clausen <lars@metafoo.de>
+ * JZ7420/JZ4740 DMA 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.
+ *
+ * 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 __ASM_MACH_JZ4740_DMA_H__
+#define __ASM_MACH_JZ4740_DMA_H__
+
+struct jz4740_dma_chan;
+
+enum jz4740_dma_request_type {
+ JZ4740_DMA_TYPE_AUTO_REQUEST = 8,
+ JZ4740_DMA_TYPE_UART_TRANSMIT = 20,
+ JZ4740_DMA_TYPE_UART_RECEIVE = 21,
+ JZ4740_DMA_TYPE_SPI_TRANSMIT = 22,
+ JZ4740_DMA_TYPE_SPI_RECEIVE = 23,
+ JZ4740_DMA_TYPE_AIC_TRANSMIT = 24,
+ JZ4740_DMA_TYPE_AIC_RECEIVE = 25,
+ JZ4740_DMA_TYPE_MMC_TRANSMIT = 26,
+ JZ4740_DMA_TYPE_MMC_RECEIVE = 27,
+ JZ4740_DMA_TYPE_TCU = 28,
+ JZ4740_DMA_TYPE_SADC = 29,
+ JZ4740_DMA_TYPE_SLCD = 30,
+};
+
+enum jz4740_dma_width {
+ JZ4740_DMA_WIDTH_32BIT = 0,
+ JZ4740_DMA_WIDTH_8BIT = 1,
+ JZ4740_DMA_WIDTH_16BIT = 2,
+};
+
+enum jz4740_dma_transfer_size {
+ JZ4740_DMA_TRANSFER_SIZE_4BYTE = 0,
+ JZ4740_DMA_TRANSFER_SIZE_1BYTE = 1,
+ JZ4740_DMA_TRANSFER_SIZE_2BYTE = 2,
+ JZ4740_DMA_TRANSFER_SIZE_16BYTE = 3,
+ JZ4740_DMA_TRANSFER_SIZE_32BYTE = 4,
+};
+
+enum jz4740_dma_flags {
+ JZ4740_DMA_SRC_AUTOINC = 0x2,
+ JZ4740_DMA_DST_AUTOINC = 0x1,
+};
+
+enum jz4740_dma_mode {
+ JZ4740_DMA_MODE_SINGLE = 0,
+ JZ4740_DMA_MODE_BLOCK = 1,
+};
+
+struct jz4740_dma_config {
+ enum jz4740_dma_width src_width;
+ enum jz4740_dma_width dst_width;
+ enum jz4740_dma_transfer_size transfer_size;
+ enum jz4740_dma_request_type request_type;
+ enum jz4740_dma_flags flags;
+ enum jz4740_dma_mode mode;
+};
+
+typedef void (*jz4740_dma_complete_callback_t)(struct jz4740_dma_chan *, int, void *);
+
+struct jz4740_dma_chan *jz4740_dma_request(void *dev, const char *name);
+void jz4740_dma_free(struct jz4740_dma_chan *dma);
+
+void jz4740_dma_configure(struct jz4740_dma_chan *dma,
+ const struct jz4740_dma_config *config);
+
+
+void jz4740_dma_enable(struct jz4740_dma_chan *dma);
+void jz4740_dma_disable(struct jz4740_dma_chan *dma);
+
+void jz4740_dma_set_src_addr(struct jz4740_dma_chan *dma, dma_addr_t src);
+void jz4740_dma_set_dst_addr(struct jz4740_dma_chan *dma, dma_addr_t dst);
+void jz4740_dma_set_transfer_count(struct jz4740_dma_chan *dma, uint32_t count);
+
+uint32_t jz4740_dma_get_residue(const struct jz4740_dma_chan *dma);
+
+void jz4740_dma_set_complete_cb(struct jz4740_dma_chan *dma,
+ jz4740_dma_complete_callback_t cb);
+
+#endif /* __ASM_JZ4740_DMA_H__ */
diff --git a/arch/mips/include/asm/mach-jz4740/gpio.h b/arch/mips/include/asm/mach-jz4740/gpio.h
new file mode 100644
index 00000000000..7b74703745b
--- /dev/null
+++ b/arch/mips/include/asm/mach-jz4740/gpio.h
@@ -0,0 +1,398 @@
+/*
+ * Copyright (C) 2009, Lars-Peter Clausen <lars@metafoo.de>
+ * JZ4740 GPIO pin 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.
+ *
+ * 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 _JZ_GPIO_H
+#define _JZ_GPIO_H
+
+#include <linux/types.h>
+
+enum jz_gpio_function {
+ JZ_GPIO_FUNC_NONE,
+ JZ_GPIO_FUNC1,
+ JZ_GPIO_FUNC2,
+ JZ_GPIO_FUNC3,
+};
+
+
+/*
+ Usually a driver for a SoC component has to request several gpio pins and
+ configure them as funcion pins.
+ jz_gpio_bulk_request can be used to ease this process.
+ Usually one would do something like:
+
+ const static struct jz_gpio_bulk_request i2c_pins[] = {
+ JZ_GPIO_BULK_PIN(I2C_SDA),
+ JZ_GPIO_BULK_PIN(I2C_SCK),
+ };
+
+ inside the probe function:
+
+ ret = jz_gpio_bulk_request(i2c_pins, ARRAY_SIZE(i2c_pins));
+ if (ret) {
+ ...
+
+ inside the remove function:
+
+ jz_gpio_bulk_free(i2c_pins, ARRAY_SIZE(i2c_pins));
+
+
+*/
+struct jz_gpio_bulk_request {
+ int gpio;
+ const char *name;
+ enum jz_gpio_function function;
+};
+
+#define JZ_GPIO_BULK_PIN(pin) { \
+ .gpio = JZ_GPIO_ ## pin, \
+ .name = #pin, \
+ .function = JZ_GPIO_FUNC_ ## pin \
+}
+
+int jz_gpio_bulk_request(const struct jz_gpio_bulk_request *request, size_t num);
+void jz_gpio_bulk_free(const struct jz_gpio_bulk_request *request, size_t num);
+void jz_gpio_bulk_suspend(const struct jz_gpio_bulk_request *request, size_t num);
+void jz_gpio_bulk_resume(const struct jz_gpio_bulk_request *request, size_t num);
+void jz_gpio_enable_pullup(unsigned gpio);
+void jz_gpio_disable_pullup(unsigned gpio);
+int jz_gpio_set_function(int gpio, enum jz_gpio_function function);
+
+int jz_gpio_port_direction_input(int port, uint32_t mask);
+int jz_gpio_port_direction_output(int port, uint32_t mask);
+void jz_gpio_port_set_value(int port, uint32_t value, uint32_t mask);
+uint32_t jz_gpio_port_get_value(int port, uint32_t mask);
+
+#include <asm/mach-generic/gpio.h>
+
+#define JZ_GPIO_PORTA(x) ((x) + 32 * 0)
+#define JZ_GPIO_PORTB(x) ((x) + 32 * 1)
+#define JZ_GPIO_PORTC(x) ((x) + 32 * 2)
+#define JZ_GPIO_PORTD(x) ((x) + 32 * 3)
+
+/* Port A function pins */
+#define JZ_GPIO_MEM_DATA0 JZ_GPIO_PORTA(0)
+#define JZ_GPIO_MEM_DATA1 JZ_GPIO_PORTA(1)
+#define JZ_GPIO_MEM_DATA2 JZ_GPIO_PORTA(2)
+#define JZ_GPIO_MEM_DATA3 JZ_GPIO_PORTA(3)
+#define JZ_GPIO_MEM_DATA4 JZ_GPIO_PORTA(4)
+#define JZ_GPIO_MEM_DATA5 JZ_GPIO_PORTA(5)
+#define JZ_GPIO_MEM_DATA6 JZ_GPIO_PORTA(6)
+#define JZ_GPIO_MEM_DATA7 JZ_GPIO_PORTA(7)
+#define JZ_GPIO_MEM_DATA8 JZ_GPIO_PORTA(8)
+#define JZ_GPIO_MEM_DATA9 JZ_GPIO_PORTA(9)
+#define JZ_GPIO_MEM_DATA10 JZ_GPIO_PORTA(10)
+#define JZ_GPIO_MEM_DATA11 JZ_GPIO_PORTA(11)
+#define JZ_GPIO_MEM_DATA12 JZ_GPIO_PORTA(12)
+#define JZ_GPIO_MEM_DATA13 JZ_GPIO_PORTA(13)
+#define JZ_GPIO_MEM_DATA14 JZ_GPIO_PORTA(14)
+#define JZ_GPIO_MEM_DATA15 JZ_GPIO_PORTA(15)
+#define JZ_GPIO_MEM_DATA16 JZ_GPIO_PORTA(16)
+#define JZ_GPIO_MEM_DATA17 JZ_GPIO_PORTA(17)
+#define JZ_GPIO_MEM_DATA18 JZ_GPIO_PORTA(18)
+#define JZ_GPIO_MEM_DATA19 JZ_GPIO_PORTA(19)
+#define JZ_GPIO_MEM_DATA20 JZ_GPIO_PORTA(20)
+#define JZ_GPIO_MEM_DATA21 JZ_GPIO_PORTA(21)
+#define JZ_GPIO_MEM_DATA22 JZ_GPIO_PORTA(22)
+#define JZ_GPIO_MEM_DATA23 JZ_GPIO_PORTA(23)
+#define JZ_GPIO_MEM_DATA24 JZ_GPIO_PORTA(24)
+#define JZ_GPIO_MEM_DATA25 JZ_GPIO_PORTA(25)
+#define JZ_GPIO_MEM_DATA26 JZ_GPIO_PORTA(26)
+#define JZ_GPIO_MEM_DATA27 JZ_GPIO_PORTA(27)
+#define JZ_GPIO_MEM_DATA28 JZ_GPIO_PORTA(28)
+#define JZ_GPIO_MEM_DATA29 JZ_GPIO_PORTA(29)
+#define JZ_GPIO_MEM_DATA30 JZ_GPIO_PORTA(30)
+#define JZ_GPIO_MEM_DATA31 JZ_GPIO_PORTA(31)
+
+#define JZ_GPIO_FUNC_MEM_DATA0 JZ_GPIO_FUNC1
+#define JZ_GPIO_FUNC_MEM_DATA1 JZ_GPIO_FUNC1
+#define JZ_GPIO_FUNC_MEM_DATA2 JZ_GPIO_FUNC1
+#define JZ_GPIO_FUNC_MEM_DATA3 JZ_GPIO_FUNC1
+#define JZ_GPIO_FUNC_MEM_DATA4 JZ_GPIO_FUNC1
+#define JZ_GPIO_FUNC_MEM_DATA5 JZ_GPIO_FUNC1
+#define JZ_GPIO_FUNC_MEM_DATA6 JZ_GPIO_FUNC1
+#define JZ_GPIO_FUNC_MEM_DATA7 JZ_GPIO_FUNC1
+#define JZ_GPIO_FUNC_MEM_DATA8 JZ_GPIO_FUNC1
+#define JZ_GPIO_FUNC_MEM_DATA9 JZ_GPIO_FUNC1
+#define JZ_GPIO_FUNC_MEM_DATA10 JZ_GPIO_FUNC1
+#define JZ_GPIO_FUNC_MEM_DATA11 JZ_GPIO_FUNC1
+#define JZ_GPIO_FUNC_MEM_DATA12 JZ_GPIO_FUNC1
+#define JZ_GPIO_FUNC_MEM_DATA13 JZ_GPIO_FUNC1
+#define JZ_GPIO_FUNC_MEM_DATA14 JZ_GPIO_FUNC1
+#define JZ_GPIO_FUNC_MEM_DATA15 JZ_GPIO_FUNC1
+#define JZ_GPIO_FUNC_MEM_DATA16 JZ_GPIO_FUNC1
+#define JZ_GPIO_FUNC_MEM_DATA17 JZ_GPIO_FUNC1
+#define JZ_GPIO_FUNC_MEM_DATA18 JZ_GPIO_FUNC1
+#define JZ_GPIO_FUNC_MEM_DATA19 JZ_GPIO_FUNC1
+#define JZ_GPIO_FUNC_MEM_DATA20 JZ_GPIO_FUNC1
+#define JZ_GPIO_FUNC_MEM_DATA21 JZ_GPIO_FUNC1
+#define JZ_GPIO_FUNC_MEM_DATA22 JZ_GPIO_FUNC1
+#define JZ_GPIO_FUNC_MEM_DATA23 JZ_GPIO_FUNC1
+#define JZ_GPIO_FUNC_MEM_DATA24 JZ_GPIO_FUNC1
+#define JZ_GPIO_FUNC_MEM_DATA25 JZ_GPIO_FUNC1
+#define JZ_GPIO_FUNC_MEM_DATA26 JZ_GPIO_FUNC1
+#define JZ_GPIO_FUNC_MEM_DATA27 JZ_GPIO_FUNC1
+#define JZ_GPIO_FUNC_MEM_DATA28 JZ_GPIO_FUNC1
+#define JZ_GPIO_FUNC_MEM_DATA29 JZ_GPIO_FUNC1
+#define JZ_GPIO_FUNC_MEM_DATA30 JZ_GPIO_FUNC1
+#define JZ_GPIO_FUNC_MEM_DATA31 JZ_GPIO_FUNC1
+
+/* Port B function pins */
+#define JZ_GPIO_MEM_ADDR0 JZ_GPIO_PORTB(0)
+#define JZ_GPIO_MEM_ADDR1 JZ_GPIO_PORTB(1)
+#define JZ_GPIO_MEM_ADDR2 JZ_GPIO_PORTB(2)
+#define JZ_GPIO_MEM_ADDR3 JZ_GPIO_PORTB(3)
+#define JZ_GPIO_MEM_ADDR4 JZ_GPIO_PORTB(4)
+#define JZ_GPIO_MEM_ADDR5 JZ_GPIO_PORTB(5)
+#define JZ_GPIO_MEM_ADDR6 JZ_GPIO_PORTB(6)
+#define JZ_GPIO_MEM_ADDR7 JZ_GPIO_PORTB(7)
+#define JZ_GPIO_MEM_ADDR8 JZ_GPIO_PORTB(8)
+#define JZ_GPIO_MEM_ADDR9 JZ_GPIO_PORTB(9)
+#define JZ_GPIO_MEM_ADDR10 JZ_GPIO_PORTB(10)
+#define JZ_GPIO_MEM_ADDR11 JZ_GPIO_PORTB(11)
+#define JZ_GPIO_MEM_ADDR12 JZ_GPIO_PORTB(12)
+#define JZ_GPIO_MEM_ADDR13 JZ_GPIO_PORTB(13)
+#define JZ_GPIO_MEM_ADDR14 JZ_GPIO_PORTB(14)
+#define JZ_GPIO_MEM_ADDR15 JZ_GPIO_PORTB(15)
+#define JZ_GPIO_MEM_ADDR16 JZ_GPIO_PORTB(16)
+#define JZ_GPIO_LCD_CLS JZ_GPIO_PORTB(17)
+#define JZ_GPIO_LCD_SPL JZ_GPIO_PORTB(18)
+#define JZ_GPIO_MEM_DCS JZ_GPIO_PORTB(19)
+#define JZ_GPIO_MEM_RAS JZ_GPIO_PORTB(20)
+#define JZ_GPIO_MEM_CAS JZ_GPIO_PORTB(21)
+#define JZ_GPIO_MEM_SDWE JZ_GPIO_PORTB(22)
+#define JZ_GPIO_MEM_CKE JZ_GPIO_PORTB(23)
+#define JZ_GPIO_MEM_CKO JZ_GPIO_PORTB(24)
+#define JZ_GPIO_MEM_CS0 JZ_GPIO_PORTB(25)
+#define JZ_GPIO_MEM_CS1 JZ_GPIO_PORTB(26)
+#define JZ_GPIO_MEM_CS2 JZ_GPIO_PORTB(27)
+#define JZ_GPIO_MEM_CS3 JZ_GPIO_PORTB(28)
+#define JZ_GPIO_MEM_RD JZ_GPIO_PORTB(29)
+#define JZ_GPIO_MEM_WR JZ_GPIO_PORTB(30)
+#define JZ_GPIO_MEM_WE0 JZ_GPIO_PORTB(31)
+
+#define JZ_GPIO_FUNC_MEM_ADDR0 JZ_GPIO_FUNC1
+#define JZ_GPIO_FUNC_MEM_ADDR1 JZ_GPIO_FUNC1
+#define JZ_GPIO_FUNC_MEM_ADDR2 JZ_GPIO_FUNC1
+#define JZ_GPIO_FUNC_MEM_ADDR3 JZ_GPIO_FUNC1
+#define JZ_GPIO_FUNC_MEM_ADDR4 JZ_GPIO_FUNC1
+#define JZ_GPIO_FUNC_MEM_ADDR5 JZ_GPIO_FUNC1
+#define JZ_GPIO_FUNC_MEM_ADDR6 JZ_GPIO_FUNC1
+#define JZ_GPIO_FUNC_MEM_ADDR7 JZ_GPIO_FUNC1
+#define JZ_GPIO_FUNC_MEM_ADDR8 JZ_GPIO_FUNC1
+#define JZ_GPIO_FUNC_MEM_ADDR9 JZ_GPIO_FUNC1
+#define JZ_GPIO_FUNC_MEM_ADDR10 JZ_GPIO_FUNC1
+#define JZ_GPIO_FUNC_MEM_ADDR11 JZ_GPIO_FUNC1
+#define JZ_GPIO_FUNC_MEM_ADDR12 JZ_GPIO_FUNC1
+#define JZ_GPIO_FUNC_MEM_ADDR13 JZ_GPIO_FUNC1
+#define JZ_GPIO_FUNC_MEM_ADDR14 JZ_GPIO_FUNC1
+#define JZ_GPIO_FUNC_MEM_ADDR15 JZ_GPIO_FUNC1
+#define JZ_GPIO_FUNC_MEM_ADDR16 JZ_GPIO_FUNC1
+#define JZ_GPIO_FUNC_LCD_CLS JZ_GPIO_FUNC1
+#define JZ_GPIO_FUNC_LCD_SPL JZ_GPIO_FUNC1
+#define JZ_GPIO_FUNC_MEM_DCS JZ_GPIO_FUNC1
+#define JZ_GPIO_FUNC_MEM_RAS JZ_GPIO_FUNC1
+#define JZ_GPIO_FUNC_MEM_CAS JZ_GPIO_FUNC1
+#define JZ_GPIO_FUNC_MEM_SDWE JZ_GPIO_FUNC1
+#define JZ_GPIO_FUNC_MEM_CKE JZ_GPIO_FUNC1
+#define JZ_GPIO_FUNC_MEM_CKO JZ_GPIO_FUNC1
+#define JZ_GPIO_FUNC_MEM_CS0 JZ_GPIO_FUNC1
+#define JZ_GPIO_FUNC_MEM_CS1 JZ_GPIO_FUNC1
+#define JZ_GPIO_FUNC_MEM_CS2 JZ_GPIO_FUNC1
+#define JZ_GPIO_FUNC_MEM_CS3 JZ_GPIO_FUNC1
+#define JZ_GPIO_FUNC_MEM_RD JZ_GPIO_FUNC1
+#define JZ_GPIO_FUNC_MEM_WR JZ_GPIO_FUNC1
+#define JZ_GPIO_FUNC_MEM_WE0 JZ_GPIO_FUNC1
+
+
+#define JZ_GPIO_MEM_ADDR21 JZ_GPIO_PORTB(17)
+#define JZ_GPIO_MEM_ADDR22 JZ_GPIO_PORTB(18)
+
+#define JZ_GPIO_FUNC_MEM_ADDR21 JZ_GPIO_FUNC2
+#define JZ_GPIO_FUNC_MEM_ADDR22 JZ_GPIO_FUNC2
+
+/* Port C function pins */
+#define JZ_GPIO_LCD_DATA0 JZ_GPIO_PORTC(0)
+#define JZ_GPIO_LCD_DATA1 JZ_GPIO_PORTC(1)
+#define JZ_GPIO_LCD_DATA2 JZ_GPIO_PORTC(2)
+#define JZ_GPIO_LCD_DATA3 JZ_GPIO_PORTC(3)
+#define JZ_GPIO_LCD_DATA4 JZ_GPIO_PORTC(4)
+#define JZ_GPIO_LCD_DATA5 JZ_GPIO_PORTC(5)
+#define JZ_GPIO_LCD_DATA6 JZ_GPIO_PORTC(6)
+#define JZ_GPIO_LCD_DATA7 JZ_GPIO_PORTC(7)
+#define JZ_GPIO_LCD_DATA8 JZ_GPIO_PORTC(8)
+#define JZ_GPIO_LCD_DATA9 JZ_GPIO_PORTC(9)
+#define JZ_GPIO_LCD_DATA10 JZ_GPIO_PORTC(10)
+#define JZ_GPIO_LCD_DATA11 JZ_GPIO_PORTC(11)
+#define JZ_GPIO_LCD_DATA12 JZ_GPIO_PORTC(12)
+#define JZ_GPIO_LCD_DATA13 JZ_GPIO_PORTC(13)
+#define JZ_GPIO_LCD_DATA14 JZ_GPIO_PORTC(14)
+#define JZ_GPIO_LCD_DATA15 JZ_GPIO_PORTC(15)
+#define JZ_GPIO_LCD_DATA16 JZ_GPIO_PORTC(16)
+#define JZ_GPIO_LCD_DATA17 JZ_GPIO_PORTC(17)
+#define JZ_GPIO_LCD_PCLK JZ_GPIO_PORTC(18)
+#define JZ_GPIO_LCD_HSYNC JZ_GPIO_PORTC(19)
+#define JZ_GPIO_LCD_VSYNC JZ_GPIO_PORTC(20)
+#define JZ_GPIO_LCD_DE JZ_GPIO_PORTC(21)
+#define JZ_GPIO_LCD_PS JZ_GPIO_PORTC(22)
+#define JZ_GPIO_LCD_REV JZ_GPIO_PORTC(23)
+#define JZ_GPIO_MEM_WE1 JZ_GPIO_PORTC(24)
+#define JZ_GPIO_MEM_WE2 JZ_GPIO_PORTC(25)
+#define JZ_GPIO_MEM_WE3 JZ_GPIO_PORTC(26)
+#define JZ_GPIO_MEM_WAIT JZ_GPIO_PORTC(27)
+#define JZ_GPIO_MEM_FRE JZ_GPIO_PORTC(28)
+#define JZ_GPIO_MEM_FWE JZ_GPIO_PORTC(29)
+
+#define JZ_GPIO_FUNC_LCD_DATA0 JZ_GPIO_FUNC1
+#define JZ_GPIO_FUNC_LCD_DATA1 JZ_GPIO_FUNC1
+#define JZ_GPIO_FUNC_LCD_DATA2 JZ_GPIO_FUNC1
+#define JZ_GPIO_FUNC_LCD_DATA3 JZ_GPIO_FUNC1
+#define JZ_GPIO_FUNC_LCD_DATA4 JZ_GPIO_FUNC1
+#define JZ_GPIO_FUNC_LCD_DATA5 JZ_GPIO_FUNC1
+#define JZ_GPIO_FUNC_LCD_DATA6 JZ_GPIO_FUNC1
+#define JZ_GPIO_FUNC_LCD_DATA7 JZ_GPIO_FUNC1
+#define JZ_GPIO_FUNC_LCD_DATA8 JZ_GPIO_FUNC1
+#define JZ_GPIO_FUNC_LCD_DATA9 JZ_GPIO_FUNC1
+#define JZ_GPIO_FUNC_LCD_DATA10 JZ_GPIO_FUNC1
+#define JZ_GPIO_FUNC_LCD_DATA11 JZ_GPIO_FUNC1
+#define JZ_GPIO_FUNC_LCD_DATA12 JZ_GPIO_FUNC1
+#define JZ_GPIO_FUNC_LCD_DATA13 JZ_GPIO_FUNC1
+#define JZ_GPIO_FUNC_LCD_DATA14 JZ_GPIO_FUNC1
+#define JZ_GPIO_FUNC_LCD_DATA15 JZ_GPIO_FUNC1
+#define JZ_GPIO_FUNC_LCD_DATA16 JZ_GPIO_FUNC1
+#define JZ_GPIO_FUNC_LCD_DATA17 JZ_GPIO_FUNC1
+#define JZ_GPIO_FUNC_LCD_PCLK JZ_GPIO_FUNC1
+#define JZ_GPIO_FUNC_LCD_VSYNC JZ_GPIO_FUNC1
+#define JZ_GPIO_FUNC_LCD_HSYNC JZ_GPIO_FUNC1
+#define JZ_GPIO_FUNC_LCD_DE JZ_GPIO_FUNC1
+#define JZ_GPIO_FUNC_LCD_PS JZ_GPIO_FUNC1
+#define JZ_GPIO_FUNC_LCD_REV JZ_GPIO_FUNC1
+#define JZ_GPIO_FUNC_MEM_WE1 JZ_GPIO_FUNC1
+#define JZ_GPIO_FUNC_MEM_WE2 JZ_GPIO_FUNC1
+#define JZ_GPIO_FUNC_MEM_WE3 JZ_GPIO_FUNC1
+#define JZ_GPIO_FUNC_MEM_WAIT JZ_GPIO_FUNC1
+#define JZ_GPIO_FUNC_MEM_FRE JZ_GPIO_FUNC1
+#define JZ_GPIO_FUNC_MEM_FWE JZ_GPIO_FUNC1
+
+
+#define JZ_GPIO_MEM_ADDR19 JZ_GPIO_PORTB(22)
+#define JZ_GPIO_MEM_ADDR20 JZ_GPIO_PORTB(23)
+
+#define JZ_GPIO_FUNC_MEM_ADDR19 JZ_GPIO_FUNC2
+#define JZ_GPIO_FUNC_MEM_ADDR20 JZ_GPIO_FUNC2
+
+/* Port D function pins */
+#define JZ_GPIO_CIM_DATA0 JZ_GPIO_PORTD(0)
+#define JZ_GPIO_CIM_DATA1 JZ_GPIO_PORTD(1)
+#define JZ_GPIO_CIM_DATA2 JZ_GPIO_PORTD(2)
+#define JZ_GPIO_CIM_DATA3 JZ_GPIO_PORTD(3)
+#define JZ_GPIO_CIM_DATA4 JZ_GPIO_PORTD(4)
+#define JZ_GPIO_CIM_DATA5 JZ_GPIO_PORTD(5)
+#define JZ_GPIO_CIM_DATA6 JZ_GPIO_PORTD(6)
+#define JZ_GPIO_CIM_DATA7 JZ_GPIO_PORTD(7)
+#define JZ_GPIO_MSC_CMD JZ_GPIO_PORTD(8)
+#define JZ_GPIO_MSC_CLK JZ_GPIO_PORTD(9)
+#define JZ_GPIO_MSC_DATA0 JZ_GPIO_PORTD(10)
+#define JZ_GPIO_MSC_DATA1 JZ_GPIO_PORTD(11)
+#define JZ_GPIO_MSC_DATA2 JZ_GPIO_PORTD(12)
+#define JZ_GPIO_MSC_DATA3 JZ_GPIO_PORTD(13)
+#define JZ_GPIO_CIM_MCLK JZ_GPIO_PORTD(14)
+#define JZ_GPIO_CIM_PCLK JZ_GPIO_PORTD(15)
+#define JZ_GPIO_CIM_VSYNC JZ_GPIO_PORTD(16)
+#define JZ_GPIO_CIM_HSYNC JZ_GPIO_PORTD(17)
+#define JZ_GPIO_SPI_CLK JZ_GPIO_PORTD(18)
+#define JZ_GPIO_SPI_CE0 JZ_GPIO_PORTD(19)
+#define JZ_GPIO_SPI_DT JZ_GPIO_PORTD(20)
+#define JZ_GPIO_SPI_DR JZ_GPIO_PORTD(21)
+#define JZ_GPIO_SPI_CE1 JZ_GPIO_PORTD(22)
+#define JZ_GPIO_PWM0 JZ_GPIO_PORTD(23)
+#define JZ_GPIO_PWM1 JZ_GPIO_PORTD(24)
+#define JZ_GPIO_PWM2 JZ_GPIO_PORTD(25)
+#define JZ_GPIO_PWM3 JZ_GPIO_PORTD(26)
+#define JZ_GPIO_PWM4 JZ_GPIO_PORTD(27)
+#define JZ_GPIO_PWM5 JZ_GPIO_PORTD(28)
+#define JZ_GPIO_PWM6 JZ_GPIO_PORTD(30)
+#define JZ_GPIO_PWM7 JZ_GPIO_PORTD(31)
+
+#define JZ_GPIO_FUNC_CIM_DATA JZ_GPIO_FUNC1
+#define JZ_GPIO_FUNC_CIM_DATA0 JZ_GPIO_FUNC_CIM_DATA
+#define JZ_GPIO_FUNC_CIM_DATA1 JZ_GPIO_FUNC_CIM_DATA
+#define JZ_GPIO_FUNC_CIM_DATA2 JZ_GPIO_FUNC_CIM_DATA
+#define JZ_GPIO_FUNC_CIM_DATA3 JZ_GPIO_FUNC_CIM_DATA
+#define JZ_GPIO_FUNC_CIM_DATA4 JZ_GPIO_FUNC_CIM_DATA
+#define JZ_GPIO_FUNC_CIM_DATA5 JZ_GPIO_FUNC_CIM_DATA
+#define JZ_GPIO_FUNC_CIM_DATA6 JZ_GPIO_FUNC_CIM_DATA
+#define JZ_GPIO_FUNC_CIM_DATA7 JZ_GPIO_FUNC_CIM_DATA
+#define JZ_GPIO_FUNC_MSC_CMD JZ_GPIO_FUNC1
+#define JZ_GPIO_FUNC_MSC_CLK JZ_GPIO_FUNC1
+#define JZ_GPIO_FUNC_MSC_DATA JZ_GPIO_FUNC1
+#define JZ_GPIO_FUNC_MSC_DATA0 JZ_GPIO_FUNC_MSC_DATA
+#define JZ_GPIO_FUNC_MSC_DATA1 JZ_GPIO_FUNC_MSC_DATA
+#define JZ_GPIO_FUNC_MSC_DATA2 JZ_GPIO_FUNC_MSC_DATA
+#define JZ_GPIO_FUNC_MSC_DATA3 JZ_GPIO_FUNC_MSC_DATA
+#define JZ_GPIO_FUNC_CIM_MCLK JZ_GPIO_FUNC1
+#define JZ_GPIO_FUNC_CIM_PCLK JZ_GPIO_FUNC1
+#define JZ_GPIO_FUNC_CIM_VSYNC JZ_GPIO_FUNC1
+#define JZ_GPIO_FUNC_CIM_HSYNC JZ_GPIO_FUNC1
+#define JZ_GPIO_FUNC_SPI_CLK JZ_GPIO_FUNC1
+#define JZ_GPIO_FUNC_SPI_CE0 JZ_GPIO_FUNC1
+#define JZ_GPIO_FUNC_SPI_DT JZ_GPIO_FUNC1
+#define JZ_GPIO_FUNC_SPI_DR JZ_GPIO_FUNC1
+#define JZ_GPIO_FUNC_SPI_CE1 JZ_GPIO_FUNC1
+
+#define JZ_GPIO_FUNC_PWM JZ_GPIO_FUNC1
+#define JZ_GPIO_FUNC_PWM0 JZ_GPIO_FUNC_PWM
+#define JZ_GPIO_FUNC_PWM1 JZ_GPIO_FUNC_PWM
+#define JZ_GPIO_FUNC_PWM2 JZ_GPIO_FUNC_PWM
+#define JZ_GPIO_FUNC_PWM3 JZ_GPIO_FUNC_PWM
+#define JZ_GPIO_FUNC_PWM4 JZ_GPIO_FUNC_PWM
+#define JZ_GPIO_FUNC_PWM5 JZ_GPIO_FUNC_PWM
+#define JZ_GPIO_FUNC_PWM6 JZ_GPIO_FUNC_PWM
+#define JZ_GPIO_FUNC_PWM7 JZ_GPIO_FUNC_PWM
+
+#define JZ_GPIO_MEM_SCLK_RSTN JZ_GPIO_PORTD(18)
+#define JZ_GPIO_MEM_BCLK JZ_GPIO_PORTD(19)
+#define JZ_GPIO_MEM_SDATO JZ_GPIO_PORTD(20)
+#define JZ_GPIO_MEM_SDATI JZ_GPIO_PORTD(21)
+#define JZ_GPIO_MEM_SYNC JZ_GPIO_PORTD(22)
+#define JZ_GPIO_I2C_SDA JZ_GPIO_PORTD(23)
+#define JZ_GPIO_I2C_SCK JZ_GPIO_PORTD(24)
+#define JZ_GPIO_UART0_TXD JZ_GPIO_PORTD(25)
+#define JZ_GPIO_UART0_RXD JZ_GPIO_PORTD(26)
+#define JZ_GPIO_MEM_ADDR17 JZ_GPIO_PORTD(27)
+#define JZ_GPIO_MEM_ADDR18 JZ_GPIO_PORTD(28)
+#define JZ_GPIO_UART0_CTS JZ_GPIO_PORTD(30)
+#define JZ_GPIO_UART0_RTS JZ_GPIO_PORTD(31)
+
+#define JZ_GPIO_FUNC_MEM_SCLK_RSTN JZ_GPIO_FUNC2
+#define JZ_GPIO_FUNC_MEM_BCLK JZ_GPIO_FUNC2
+#define JZ_GPIO_FUNC_MEM_SDATO JZ_GPIO_FUNC2
+#define JZ_GPIO_FUNC_MEM_SDATI JZ_GPIO_FUNC2
+#define JZ_GPIO_FUNC_MEM_SYNC JZ_GPIO_FUNC2
+#define JZ_GPIO_FUNC_I2C_SDA JZ_GPIO_FUNC2
+#define JZ_GPIO_FUNC_I2C_SCK JZ_GPIO_FUNC2
+#define JZ_GPIO_FUNC_UART0_TXD JZ_GPIO_FUNC2
+#define JZ_GPIO_FUNC_UART0_RXD JZ_GPIO_FUNC2
+#define JZ_GPIO_FUNC_MEM_ADDR17 JZ_GPIO_FUNC2
+#define JZ_GPIO_FUNC_MEM_ADDR18 JZ_GPIO_FUNC2
+#define JZ_GPIO_FUNC_UART0_CTS JZ_GPIO_FUNC2
+#define JZ_GPIO_FUNC_UART0_RTS JZ_GPIO_FUNC2
+
+#define JZ_GPIO_UART1_RXD JZ_GPIO_PORTD(30)
+#define JZ_GPIO_UART1_TXD JZ_GPIO_PORTD(31)
+
+#define JZ_GPIO_FUNC_UART1_RXD JZ_GPIO_FUNC3
+#define JZ_GPIO_FUNC_UART1_TXD JZ_GPIO_FUNC3
+
+#endif
diff --git a/arch/mips/include/asm/mach-jz4740/irq.h b/arch/mips/include/asm/mach-jz4740/irq.h
new file mode 100644
index 00000000000..a865c983c70
--- /dev/null
+++ b/arch/mips/include/asm/mach-jz4740/irq.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2009-2010, Lars-Peter Clausen <lars@metafoo.de>
+ * JZ4740 IRQ 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.
+ *
+ * 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 __ASM_MACH_JZ4740_IRQ_H__
+#define __ASM_MACH_JZ4740_IRQ_H__
+
+#define MIPS_CPU_IRQ_BASE 0
+#define JZ4740_IRQ_BASE 8
+
+/* 1st-level interrupts */
+#define JZ4740_IRQ(x) (JZ4740_IRQ_BASE + (x))
+#define JZ4740_IRQ_I2C JZ4740_IRQ(1)
+#define JZ4740_IRQ_UHC JZ4740_IRQ(3)
+#define JZ4740_IRQ_UART1 JZ4740_IRQ(8)
+#define JZ4740_IRQ_UART0 JZ4740_IRQ(9)
+#define JZ4740_IRQ_SADC JZ4740_IRQ(12)
+#define JZ4740_IRQ_MSC JZ4740_IRQ(14)
+#define JZ4740_IRQ_RTC JZ4740_IRQ(15)
+#define JZ4740_IRQ_SSI JZ4740_IRQ(16)
+#define JZ4740_IRQ_CIM JZ4740_IRQ(17)
+#define JZ4740_IRQ_AIC JZ4740_IRQ(18)
+#define JZ4740_IRQ_ETH JZ4740_IRQ(19)
+#define JZ4740_IRQ_DMAC JZ4740_IRQ(20)
+#define JZ4740_IRQ_TCU2 JZ4740_IRQ(21)
+#define JZ4740_IRQ_TCU1 JZ4740_IRQ(22)
+#define JZ4740_IRQ_TCU0 JZ4740_IRQ(23)
+#define JZ4740_IRQ_UDC JZ4740_IRQ(24)
+#define JZ4740_IRQ_GPIO3 JZ4740_IRQ(25)
+#define JZ4740_IRQ_GPIO2 JZ4740_IRQ(26)
+#define JZ4740_IRQ_GPIO1 JZ4740_IRQ(27)
+#define JZ4740_IRQ_GPIO0 JZ4740_IRQ(28)
+#define JZ4740_IRQ_IPU JZ4740_IRQ(29)
+#define JZ4740_IRQ_LCD JZ4740_IRQ(30)
+
+/* 2nd-level interrupts */
+#define JZ4740_IRQ_DMA(x) (JZ4740_IRQ(32) + (X))
+
+#define JZ4740_IRQ_INTC_GPIO(x) (JZ4740_IRQ_GPIO0 - (x))
+#define JZ4740_IRQ_GPIO(x) (JZ4740_IRQ(48) + (x))
+
+#define JZ4740_IRQ_ADC_BASE JZ4740_IRQ(176)
+
+#define NR_IRQS (JZ4740_IRQ_ADC_BASE + 6)
+
+#endif
diff --git a/arch/mips/include/asm/mach-jz4740/jz4740_fb.h b/arch/mips/include/asm/mach-jz4740/jz4740_fb.h
new file mode 100644
index 00000000000..6a50e6f7a21
--- /dev/null
+++ b/arch/mips/include/asm/mach-jz4740/jz4740_fb.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2009, Lars-Peter Clausen <lars@metafoo.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.
+ *
+ * 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 __ASM_MACH_JZ4740_JZ4740_FB_H__
+#define __ASM_MACH_JZ4740_JZ4740_FB_H__
+
+#include <linux/fb.h>
+
+enum jz4740_fb_lcd_type {
+ JZ_LCD_TYPE_GENERIC_16_BIT = 0,
+ JZ_LCD_TYPE_GENERIC_18_BIT = 0 | (1 << 4),
+ JZ_LCD_TYPE_SPECIAL_TFT_1 = 1,
+ JZ_LCD_TYPE_SPECIAL_TFT_2 = 2,
+ JZ_LCD_TYPE_SPECIAL_TFT_3 = 3,
+ JZ_LCD_TYPE_NON_INTERLACED_CCIR656 = 5,
+ JZ_LCD_TYPE_INTERLACED_CCIR656 = 7,
+ JZ_LCD_TYPE_SINGLE_COLOR_STN = 8,
+ JZ_LCD_TYPE_SINGLE_MONOCHROME_STN = 9,
+ JZ_LCD_TYPE_DUAL_COLOR_STN = 10,
+ JZ_LCD_TYPE_DUAL_MONOCHROME_STN = 11,
+ JZ_LCD_TYPE_8BIT_SERIAL = 12,
+};
+
+#define JZ4740_FB_SPECIAL_TFT_CONFIG(start, stop) (((start) << 16) | (stop))
+
+/*
+* width: width of the lcd display in mm
+* height: height of the lcd display in mm
+* num_modes: size of modes
+* modes: list of valid video modes
+* bpp: bits per pixel for the lcd
+* lcd_type: lcd type
+*/
+
+struct jz4740_fb_platform_data {
+ unsigned int width;
+ unsigned int height;
+
+ size_t num_modes;
+ struct fb_videomode *modes;
+
+ unsigned int bpp;
+ enum jz4740_fb_lcd_type lcd_type;
+
+ struct {
+ uint32_t spl;
+ uint32_t cls;
+ uint32_t ps;
+ uint32_t rev;
+ } special_tft_config;
+
+ unsigned pixclk_falling_edge:1;
+ unsigned date_enable_active_low:1;
+};
+
+#endif
diff --git a/arch/mips/include/asm/mach-jz4740/jz4740_mmc.h b/arch/mips/include/asm/mach-jz4740/jz4740_mmc.h
new file mode 100644
index 00000000000..8543f432b4b
--- /dev/null
+++ b/arch/mips/include/asm/mach-jz4740/jz4740_mmc.h
@@ -0,0 +1,15 @@
+#ifndef __LINUX_MMC_JZ4740_MMC
+#define __LINUX_MMC_JZ4740_MMC
+
+struct jz4740_mmc_platform_data {
+ int gpio_power;
+ int gpio_card_detect;
+ int gpio_read_only;
+ unsigned card_detect_active_low:1;
+ unsigned read_only_active_low:1;
+ unsigned power_active_low:1;
+
+ unsigned data_1bit:1;
+};
+
+#endif
diff --git a/arch/mips/include/asm/mach-jz4740/jz4740_nand.h b/arch/mips/include/asm/mach-jz4740/jz4740_nand.h
new file mode 100644
index 00000000000..bb5b9a4e29c
--- /dev/null
+++ b/arch/mips/include/asm/mach-jz4740/jz4740_nand.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2009-2010, Lars-Peter Clausen <lars@metafoo.de>
+ * JZ4740 SoC NAND controller 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.
+ *
+ * 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 __ASM_MACH_JZ4740_JZ4740_NAND_H__
+#define __ASM_MACH_JZ4740_JZ4740_NAND_H__
+
+#include <linux/mtd/nand.h>
+#include <linux/mtd/partitions.h>
+
+struct jz_nand_platform_data {
+ int num_partitions;
+ struct mtd_partition *partitions;
+
+ struct nand_ecclayout *ecc_layout;
+
+ unsigned int busy_gpio;
+
+ void (*ident_callback)(struct platform_device *, struct nand_chip *,
+ struct mtd_partition **, int *num_partitions);
+};
+
+#endif
diff --git a/arch/mips/include/asm/mach-jz4740/platform.h b/arch/mips/include/asm/mach-jz4740/platform.h
new file mode 100644
index 00000000000..8987a76e967
--- /dev/null
+++ b/arch/mips/include/asm/mach-jz4740/platform.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2009-2010, Lars-Peter Clausen <lars@metafoo.de>
+ * JZ4740 platform device 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.
+ *
+ * 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 __JZ4740_PLATFORM_H
+#define __JZ4740_PLATFORM_H
+
+#include <linux/platform_device.h>
+
+extern struct platform_device jz4740_usb_ohci_device;
+extern struct platform_device jz4740_udc_device;
+extern struct platform_device jz4740_mmc_device;
+extern struct platform_device jz4740_rtc_device;
+extern struct platform_device jz4740_i2c_device;
+extern struct platform_device jz4740_nand_device;
+extern struct platform_device jz4740_framebuffer_device;
+extern struct platform_device jz4740_i2s_device;
+extern struct platform_device jz4740_pcm_device;
+extern struct platform_device jz4740_codec_device;
+extern struct platform_device jz4740_adc_device;
+
+void jz4740_serial_device_register(void);
+
+#endif
diff --git a/arch/mips/include/asm/mach-jz4740/timer.h b/arch/mips/include/asm/mach-jz4740/timer.h
new file mode 100644
index 00000000000..9baa03ce748
--- /dev/null
+++ b/arch/mips/include/asm/mach-jz4740/timer.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2010, Lars-Peter Clausen <lars@metafoo.de>
+ * JZ4740 platform timer 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.
+ *
+ * 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 __ASM_MACH_JZ4740_TIMER
+#define __ASM_MACH_JZ4740_TIMER
+
+void jz4740_timer_enable_watchdog(void);
+void jz4740_timer_disable_watchdog(void);
+
+#endif
diff --git a/arch/mips/include/asm/mach-jz4740/war.h b/arch/mips/include/asm/mach-jz4740/war.h
new file mode 100644
index 00000000000..3a5bc17e28f
--- /dev/null
+++ b/arch/mips/include/asm/mach-jz4740/war.h
@@ -0,0 +1,25 @@
+/*
+ * 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) 2002, 2004, 2007 by Ralf Baechle <ralf@linux-mips.org>
+ */
+#ifndef __ASM_MIPS_MACH_JZ4740_WAR_H
+#define __ASM_MIPS_MACH_JZ4740_WAR_H
+
+#define R4600_V1_INDEX_ICACHEOP_WAR 0
+#define R4600_V1_HIT_CACHEOP_WAR 0
+#define R4600_V2_HIT_CACHEOP_WAR 0
+#define R5432_CP0_INTERRUPT_WAR 0
+#define BCM1250_M3_WAR 0
+#define SIBYTE_1956_WAR 0
+#define MIPS4K_ICACHE_REFILL_WAR 0
+#define MIPS_CACHE_SYNC_WAR 0
+#define TX49XX_ICACHE_INDEX_INV_WAR 0
+#define RM9000_CDEX_SMP_WAR 0
+#define ICACHE_REFILLS_WORKAROUND_WAR 0
+#define R10000_LLSC_WAR 0
+#define MIPS34K_MISSED_ITLB_WAR 0
+
+#endif /* __ASM_MIPS_MACH_JZ4740_WAR_H */
diff --git a/arch/mips/include/asm/mach-loongson/loongson.h b/arch/mips/include/asm/mach-loongson/loongson.h
index fcdbe3a4ce1..cb6985f2430 100644
--- a/arch/mips/include/asm/mach-loongson/loongson.h
+++ b/arch/mips/include/asm/mach-loongson/loongson.h
@@ -45,7 +45,6 @@ static inline void prom_init_uart_base(void)
/* irq operation functions */
extern void bonito_irqdispatch(void);
extern void __init bonito_irq_init(void);
-extern void __init set_irq_trigger_mode(void);
extern void __init mach_init_irq(void);
extern void mach_irq_dispatch(unsigned int pending);
extern int mach_i8259_irq(void);
@@ -63,6 +62,14 @@ extern int mach_i8259_irq(void);
#define LOONGSON_IRQ_BASE 32
#define LOONGSON2_PERFCNT_IRQ (MIPS_CPU_IRQ_BASE + 6) /* cpu perf counter */
+#include <linux/interrupt.h>
+static inline void do_perfcnt_IRQ(void)
+{
+#if defined(CONFIG_OPROFILE) || defined(CONFIG_OPROFILE_MODULE)
+ do_IRQ(LOONGSON2_PERFCNT_IRQ);
+#endif
+}
+
#define LOONGSON_FLASH_BASE 0x1c000000
#define LOONGSON_FLASH_SIZE 0x02000000 /* 32M */
#define LOONGSON_FLASH_TOP (LOONGSON_FLASH_BASE+LOONGSON_FLASH_SIZE-1)
diff --git a/arch/mips/include/asm/mach-pb1x00/pb1550.h b/arch/mips/include/asm/mach-pb1x00/pb1550.h
index 58796410bd6..fc4d766641c 100644
--- a/arch/mips/include/asm/mach-pb1x00/pb1550.h
+++ b/arch/mips/include/asm/mach-pb1x00/pb1550.h
@@ -40,14 +40,6 @@
#define SMBUS_PSC_BASE PSC2_BASE_ADDR
#define I2S_PSC_BASE PSC3_BASE_ADDR
-#if defined(CONFIG_MTD_PB1550_BOOT) && defined(CONFIG_MTD_PB1550_USER)
-#define PB1550_BOTH_BANKS
-#elif defined(CONFIG_MTD_PB1550_BOOT) && !defined(CONFIG_MTD_PB1550_USER)
-#define PB1550_BOOT_ONLY
-#elif !defined(CONFIG_MTD_PB1550_BOOT) && defined(CONFIG_MTD_PB1550_USER)
-#define PB1550_USER_ONLY
-#endif
-
/*
* Timing values as described in databook, * ns value stripped of
* lower 2 bits.
diff --git a/arch/mips/include/asm/mach-powertv/asic.h b/arch/mips/include/asm/mach-powertv/asic.h
index bcad43a93eb..c7077a64b9a 100644
--- a/arch/mips/include/asm/mach-powertv/asic.h
+++ b/arch/mips/include/asm/mach-powertv/asic.h
@@ -20,6 +20,7 @@
#define _ASM_MACH_POWERTV_ASIC_H
#include <linux/ioport.h>
+#include <linux/platform_device.h>
#include <asm/mach-powertv/asic_regs.h>
#define DVR_CAPABLE (1<<0)
@@ -40,19 +41,23 @@ enum family_type {
FAMILY_8600VZB,
FAMILY_1500VZE,
FAMILY_1500VZF,
+ FAMILY_8700,
FAMILIES
};
/* Register maps for each ASIC */
extern const struct register_map calliope_register_map;
extern const struct register_map cronus_register_map;
+extern const struct register_map gaia_register_map;
extern const struct register_map zeus_register_map;
extern struct resource dvr_cronus_resources[];
+extern struct resource dvr_gaia_resources[];
extern struct resource dvr_zeus_resources[];
extern struct resource non_dvr_calliope_resources[];
extern struct resource non_dvr_cronus_resources[];
extern struct resource non_dvr_cronuslite_resources[];
+extern struct resource non_dvr_gaia_resources[];
extern struct resource non_dvr_vz_calliope_resources[];
extern struct resource non_dvr_vze_calliope_resources[];
extern struct resource non_dvr_vzf_calliope_resources[];
@@ -67,16 +72,24 @@ extern int platform_supports_ffs(void);
extern int platform_supports_pcie(void);
extern int platform_supports_display(void);
extern void configure_platform(void);
-extern void platform_configure_usb_ehci(void);
-extern void platform_unconfigure_usb_ehci(void);
-extern void platform_configure_usb_ohci(void);
-extern void platform_unconfigure_usb_ohci(void);
/* Platform Resources */
#define ASIC_RESOURCE_GET_EXISTS 1
extern struct resource *asic_resource_get(const char *name);
extern void platform_release_memory(void *baddr, int size);
+/* USB configuration */
+struct usb_hcd; /* Forward reference */
+extern void platform_configure_usb_ehci(void);
+extern void platform_unconfigure_usb_ehci(void);
+extern void platform_configure_usb_ohci(void);
+extern void platform_unconfigure_usb_ohci(void);
+
+/* Resource for ASIC registers */
+extern struct resource asic_resource;
+extern int platform_usb_devices_init(struct platform_device **echi_dev,
+ struct platform_device **ohci_dev);
+
/* Reboot Cause */
extern void set_reboot_cause(char code, unsigned int data, unsigned int data2);
extern void set_locked_reboot_cause(char code, unsigned int data,
diff --git a/arch/mips/include/asm/mach-powertv/asic_reg_map.h b/arch/mips/include/asm/mach-powertv/asic_reg_map.h
index 6f26cb09828..20348e817b0 100644
--- a/arch/mips/include/asm/mach-powertv/asic_reg_map.h
+++ b/arch/mips/include/asm/mach-powertv/asic_reg_map.h
@@ -64,7 +64,7 @@ REGISTER_MAP_ELEMENT(int_level_0_1)
REGISTER_MAP_ELEMENT(int_level_0_0)
REGISTER_MAP_ELEMENT(int_docsis_en)
REGISTER_MAP_ELEMENT(mips_pll_setup)
-REGISTER_MAP_ELEMENT(usb_fs)
+REGISTER_MAP_ELEMENT(fs432x4b4_usb_ctl)
REGISTER_MAP_ELEMENT(test_bus)
REGISTER_MAP_ELEMENT(crt_spare)
REGISTER_MAP_ELEMENT(usb2_ohci_int_mask)
diff --git a/arch/mips/include/asm/mach-powertv/asic_regs.h b/arch/mips/include/asm/mach-powertv/asic_regs.h
index 1e11236c6db..deecb26a077 100644
--- a/arch/mips/include/asm/mach-powertv/asic_regs.h
+++ b/arch/mips/include/asm/mach-powertv/asic_regs.h
@@ -27,7 +27,8 @@ enum asic_type {
ASIC_CALLIOPE,
ASIC_CRONUS,
ASIC_CRONUSLITE,
- ASICS
+ ASIC_GAIA,
+ ASICS /* Number of supported ASICs */
};
/* hardcoded values read from Chip Version registers */
@@ -37,6 +38,7 @@ enum asic_type {
#define NAND_FLASH_BASE 0x03000000
#define CALLIOPE_IO_BASE 0x08000000
+#define GAIA_IO_BASE 0x09000000
#define CRONUS_IO_BASE 0x09000000
#define ZEUS_IO_BASE 0x09000000
@@ -99,6 +101,7 @@ static inline void register_map_virtualize(struct register_map *map)
}
extern struct register_map _asic_register_map;
+extern unsigned long asic_phy_base;
/*
* Macros to interface to registers through their ioremapped address
diff --git a/arch/mips/include/asm/mach-powertv/dma-coherence.h b/arch/mips/include/asm/mach-powertv/dma-coherence.h
index 5b8d5ebeb83..f76029c2406 100644
--- a/arch/mips/include/asm/mach-powertv/dma-coherence.h
+++ b/arch/mips/include/asm/mach-powertv/dma-coherence.h
@@ -65,21 +65,21 @@ static inline dma_addr_t plat_map_dma_mem(struct device *dev, void *addr,
size_t size)
{
if (is_kseg2(addr))
- return phys_to_bus(virt_to_phys_from_pte(addr));
+ return phys_to_dma(virt_to_phys_from_pte(addr));
else
- return phys_to_bus(virt_to_phys(addr));
+ return phys_to_dma(virt_to_phys(addr));
}
static inline dma_addr_t plat_map_dma_mem_page(struct device *dev,
struct page *page)
{
- return phys_to_bus(page_to_phys(page));
+ return phys_to_dma(page_to_phys(page));
}
static inline unsigned long plat_dma_addr_to_phys(struct device *dev,
dma_addr_t dma_addr)
{
- return bus_to_phys(dma_addr);
+ return dma_to_phys(dma_addr);
}
static inline void plat_unmap_dma_mem(struct device *dev, dma_addr_t dma_addr,
diff --git a/arch/mips/include/asm/mach-powertv/ioremap.h b/arch/mips/include/asm/mach-powertv/ioremap.h
index e6276d5146e..076f2eeaa57 100644
--- a/arch/mips/include/asm/mach-powertv/ioremap.h
+++ b/arch/mips/include/asm/mach-powertv/ioremap.h
@@ -10,64 +10,101 @@
#define __ASM_MACH_POWERTV_IOREMAP_H
#include <linux/types.h>
+#include <linux/log2.h>
+#include <linux/compiler.h>
-#define LOW_MEM_BOUNDARY_PHYS 0x20000000
-#define LOW_MEM_BOUNDARY_MASK (~(LOW_MEM_BOUNDARY_PHYS - 1))
+#include <asm/pgtable-bits.h>
+#include <asm/addrspace.h>
+
+/* We're going to mess with bits, so get sizes */
+#define IOR_BPC 8 /* Bits per char */
+#define IOR_PHYS_BITS (IOR_BPC * sizeof(phys_addr_t))
+#define IOR_DMA_BITS (IOR_BPC * sizeof(dma_addr_t))
/*
- * The bus addresses are different than the physical addresses that
- * the processor sees by an offset. This offset varies by ASIC
- * version. Define a variable to hold the offset and some macros to
- * make the conversion simpler. */
-extern unsigned long phys_to_bus_offset;
-
-#ifdef CONFIG_HIGHMEM
-#define MEM_GAP_PHYS 0x60000000
+ * Define the granularity of physical/DMA mapping in terms of the number
+ * of bits that defines the offset within a grain. These will be the
+ * least significant bits of the address. The rest of a physical or DMA
+ * address will be used to index into an appropriate table to find the
+ * offset to add to the address to yield the corresponding DMA or physical
+ * address, respectively.
+ */
+#define IOR_LSBITS 22 /* Bits in a grain */
+
/*
- * TODO: We will use the hard code for conversion between physical and
- * bus until the bootloader releases their device tree to us.
+ * Compute the number of most significant address bits after removing those
+ * used for the offset within a grain and then compute the number of table
+ * entries for the conversion.
*/
-#define phys_to_bus(x) (((x) < LOW_MEM_BOUNDARY_PHYS) ? \
- ((x) + phys_to_bus_offset) : (x))
-#define bus_to_phys(x) (((x) < MEM_GAP_PHYS_ADDR) ? \
- ((x) - phys_to_bus_offset) : (x))
-#else
-#define phys_to_bus(x) ((x) + phys_to_bus_offset)
-#define bus_to_phys(x) ((x) - phys_to_bus_offset)
-#endif
+#define IOR_PHYS_MSBITS (IOR_PHYS_BITS - IOR_LSBITS)
+#define IOR_NUM_PHYS_TO_DMA ((phys_addr_t) 1 << IOR_PHYS_MSBITS)
+
+#define IOR_DMA_MSBITS (IOR_DMA_BITS - IOR_LSBITS)
+#define IOR_NUM_DMA_TO_PHYS ((dma_addr_t) 1 << IOR_DMA_MSBITS)
/*
- * Determine whether the address we are given is for an ASIC device
- * Params: addr Address to check
- * Returns: Zero if the address is not for ASIC devices, non-zero
- * if it is.
+ * Define data structures used as elements in the arrays for the conversion
+ * between physical and DMA addresses. We do some slightly fancy math to
+ * compute the width of the offset element of the conversion tables so
+ * that we can have the smallest conversion tables. Next, round up the
+ * sizes to the next higher power of two, i.e. the offset element will have
+ * 8, 16, 32, 64, etc. bits. This eliminates the need to mask off any
+ * bits. Finally, we compute a shift value that puts the most significant
+ * bits of the offset into the most significant bits of the offset element.
+ * This makes it more efficient on processors without barrel shifters and
+ * easier to see the values if the conversion table is dumped in binary.
*/
-static inline int asic_is_device_addr(phys_t addr)
+#define _IOR_OFFSET_WIDTH(n) (1 << order_base_2(n))
+#define IOR_OFFSET_WIDTH(n) \
+ (_IOR_OFFSET_WIDTH(n) < 8 ? 8 : _IOR_OFFSET_WIDTH(n))
+
+#define IOR_PHYS_OFFSET_BITS IOR_OFFSET_WIDTH(IOR_PHYS_MSBITS)
+#define IOR_PHYS_SHIFT (IOR_PHYS_BITS - IOR_PHYS_OFFSET_BITS)
+
+#define IOR_DMA_OFFSET_BITS IOR_OFFSET_WIDTH(IOR_DMA_MSBITS)
+#define IOR_DMA_SHIFT (IOR_DMA_BITS - IOR_DMA_OFFSET_BITS)
+
+struct ior_phys_to_dma {
+ dma_addr_t offset:IOR_DMA_OFFSET_BITS __packed
+ __aligned((IOR_DMA_OFFSET_BITS / IOR_BPC));
+};
+
+struct ior_dma_to_phys {
+ dma_addr_t offset:IOR_PHYS_OFFSET_BITS __packed
+ __aligned((IOR_PHYS_OFFSET_BITS / IOR_BPC));
+};
+
+extern struct ior_phys_to_dma _ior_phys_to_dma[IOR_NUM_PHYS_TO_DMA];
+extern struct ior_dma_to_phys _ior_dma_to_phys[IOR_NUM_DMA_TO_PHYS];
+
+static inline dma_addr_t _phys_to_dma_offset_raw(phys_addr_t phys)
{
- return !((phys_t)addr & (phys_t) LOW_MEM_BOUNDARY_MASK);
+ return (dma_addr_t)_ior_phys_to_dma[phys >> IOR_LSBITS].offset;
}
-/*
- * Determine whether the address we are given is external RAM mappable
- * into KSEG1.
- * Params: addr Address to check
- * Returns: Zero if the address is not for external RAM and
- */
-static inline int asic_is_lowmem_ram_addr(phys_t addr)
+static inline dma_addr_t _dma_to_phys_offset_raw(dma_addr_t dma)
{
- /*
- * The RAM always starts at the following address in the processor's
- * physical address space
- */
- static const phys_t phys_ram_base = 0x10000000;
- phys_t bus_ram_base;
+ return (dma_addr_t)_ior_dma_to_phys[dma >> IOR_LSBITS].offset;
+}
- bus_ram_base = phys_to_bus_offset + phys_ram_base;
+/* These are not portable and should not be used in drivers. Drivers should
+ * be using ioremap() and friends to map physical addreses to virtual
+ * addresses and dma_map*() and friends to map virtual addresses into DMA
+ * addresses and back.
+ */
+static inline dma_addr_t phys_to_dma(phys_addr_t phys)
+{
+ return phys + (_phys_to_dma_offset_raw(phys) << IOR_PHYS_SHIFT);
+}
- return addr >= bus_ram_base &&
- addr < (bus_ram_base + (LOW_MEM_BOUNDARY_PHYS - phys_ram_base));
+static inline phys_addr_t dma_to_phys(dma_addr_t dma)
+{
+ return dma + (_dma_to_phys_offset_raw(dma) << IOR_DMA_SHIFT);
}
+extern void ioremap_add_map(dma_addr_t phys, phys_addr_t alias,
+ dma_addr_t size);
+
/*
* Allow physical addresses to be fixed up to help peripherals located
* outside the low 32-bit range -- generic pass-through version.
@@ -77,10 +114,50 @@ static inline phys_t fixup_bigphys_addr(phys_t phys_addr, phys_t size)
return phys_addr;
}
-static inline void __iomem *plat_ioremap(phys_t offset, unsigned long size,
+/*
+ * Handle the special case of addresses the area aliased into the first
+ * 512 MiB of the processor's physical address space. These turn into either
+ * kseg0 or kseg1 addresses, depending on flags.
+ */
+static inline void __iomem *plat_ioremap(phys_t start, unsigned long size,
unsigned long flags)
{
- return NULL;
+ phys_addr_t start_offset;
+ void __iomem *result = NULL;
+
+ /* Start by checking to see whether this is an aliased address */
+ start_offset = _dma_to_phys_offset_raw(start);
+
+ /*
+ * If:
+ * o the memory is aliased into the first 512 MiB, and
+ * o the start and end are in the same RAM bank, and
+ * o we don't have a zero size or wrap around, and
+ * o we are supposed to create an uncached mapping,
+ * handle this is a kseg0 or kseg1 address
+ */
+ if (start_offset != 0) {
+ phys_addr_t last;
+ dma_addr_t dma_to_phys_offset;
+
+ last = start + size - 1;
+ dma_to_phys_offset =
+ _dma_to_phys_offset_raw(last) << IOR_DMA_SHIFT;
+
+ if (dma_to_phys_offset == start_offset &&
+ size != 0 && start <= last) {
+ phys_t adjusted_start;
+ adjusted_start = start + start_offset;
+ if (flags == _CACHE_UNCACHED)
+ result = (void __iomem *) (unsigned long)
+ CKSEG1ADDR(adjusted_start);
+ else
+ result = (void __iomem *) (unsigned long)
+ CKSEG0ADDR(adjusted_start);
+ }
+ }
+
+ return result;
}
static inline int plat_iounmap(const volatile void __iomem *addr)
diff --git a/arch/mips/include/asm/mach-tx49xx/kmalloc.h b/arch/mips/include/asm/mach-tx49xx/kmalloc.h
index 913ff196259..b74caf65482 100644
--- a/arch/mips/include/asm/mach-tx49xx/kmalloc.h
+++ b/arch/mips/include/asm/mach-tx49xx/kmalloc.h
@@ -1,8 +1,6 @@
#ifndef __ASM_MACH_TX49XX_KMALLOC_H
#define __ASM_MACH_TX49XX_KMALLOC_H
-/*
- * All happy, no need to define ARCH_KMALLOC_MINALIGN
- */
+#define ARCH_KMALLOC_MINALIGN L1_CACHE_BYTES
#endif /* __ASM_MACH_TX49XX_KMALLOC_H */
diff --git a/arch/mips/include/asm/mipsregs.h b/arch/mips/include/asm/mipsregs.h
index c6e3c93ce7c..335474c155f 100644
--- a/arch/mips/include/asm/mipsregs.h
+++ b/arch/mips/include/asm/mipsregs.h
@@ -408,6 +408,7 @@
#define STATUSB_IP15 7
#define STATUSF_IP15 (_ULCAST_(1) << 7)
#define ST0_CH 0x00040000
+#define ST0_NMI 0x00080000
#define ST0_SR 0x00100000
#define ST0_TS 0x00200000
#define ST0_BEV 0x00400000
diff --git a/arch/mips/include/asm/octeon/octeon.h b/arch/mips/include/asm/octeon/octeon.h
index ca6214b5ccb..917a6c413b1 100644
--- a/arch/mips/include/asm/octeon/octeon.h
+++ b/arch/mips/include/asm/octeon/octeon.h
@@ -50,6 +50,7 @@ extern void octeon_crypto_disable(struct octeon_cop2_state *state,
extern asmlinkage void octeon_cop2_restore(struct octeon_cop2_state *task);
extern void octeon_init_cvmcount(void);
+extern void octeon_setup_delays(void);
#define OCTEON_ARGV_MAX_ARGS 64
#define OCTOEN_SERIAL_LEN 20
@@ -253,4 +254,6 @@ static inline uint32_t octeon_npi_read32(uint64_t address)
extern struct cvmx_bootinfo *octeon_bootinfo;
+extern uint64_t octeon_bootloader_entry_addr;
+
#endif /* __ASM_OCTEON_OCTEON_H */
diff --git a/arch/mips/include/asm/octeon/pci-octeon.h b/arch/mips/include/asm/octeon/pci-octeon.h
index 6ac5d3e3398..ece78043acf 100644
--- a/arch/mips/include/asm/octeon/pci-octeon.h
+++ b/arch/mips/include/asm/octeon/pci-octeon.h
@@ -15,6 +15,19 @@
#define PCI_CONFIG_SPACE_DELAY 10000
/*
+ * The physical memory base mapped by BAR1. 256MB at the end of the
+ * first 4GB.
+ */
+#define CVMX_PCIE_BAR1_PHYS_BASE ((1ull << 32) - (1ull << 28))
+#define CVMX_PCIE_BAR1_PHYS_SIZE (1ull << 28)
+
+/*
+ * The RC base of BAR1. gen1 has a 39-bit BAR2, gen2 has 41-bit BAR2,
+ * place BAR1 so it is the same for both.
+ */
+#define CVMX_PCIE_BAR1_RC_BASE (1ull << 41)
+
+/*
* pcibios_map_irq() is defined inside pci-octeon.c. All it does is
* call the Octeon specific version pointed to by this variable. This
* function needs to change for PCI or PCIe based hosts.
diff --git a/arch/mips/include/asm/pci.h b/arch/mips/include/asm/pci.h
index 3beea1479b4..576397c6992 100644
--- a/arch/mips/include/asm/pci.h
+++ b/arch/mips/include/asm/pci.h
@@ -140,6 +140,11 @@ static inline int pci_get_legacy_ide_irq(struct pci_dev *dev, int channel)
return channel ? 15 : 14;
}
+#ifdef CONFIG_CPU_CAVIUM_OCTEON
+/* MSI arch hook for OCTEON */
+#define arch_setup_msi_irqs arch_setup_msi_irqs
+#endif
+
extern int pci_probe_only;
extern char * (*pcibios_plat_setup)(char *str);
diff --git a/arch/mips/include/asm/pmc-sierra/msp71xx/msp_prom.h b/arch/mips/include/asm/pmc-sierra/msp71xx/msp_prom.h
index 54ef1a96d7c..786d82daf8d 100644
--- a/arch/mips/include/asm/pmc-sierra/msp71xx/msp_prom.h
+++ b/arch/mips/include/asm/pmc-sierra/msp71xx/msp_prom.h
@@ -124,10 +124,6 @@ extern void prom_meminit(void);
extern void prom_fixup_mem_map(unsigned long start_mem,
unsigned long end_mem);
-#ifdef CONFIG_MTD_PMC_MSP_RAMROOT
-extern bool get_ramroot(void **start, unsigned long *size);
-#endif
-
extern int get_ethernet_addr(char *ethaddr_name, char *ethernet_addr);
extern unsigned long get_deviceid(void);
extern char identify_enet(unsigned long interface_num);
diff --git a/arch/mips/include/asm/processor.h b/arch/mips/include/asm/processor.h
index 5d33b727acf..0d629bb93cb 100644
--- a/arch/mips/include/asm/processor.h
+++ b/arch/mips/include/asm/processor.h
@@ -34,6 +34,11 @@ extern void (*cpu_wait)(void);
extern unsigned int vced_count, vcei_count;
/*
+ * MIPS does have an arch_pick_mmap_layout()
+ */
+#define HAVE_ARCH_PICK_MMAP_LAYOUT 1
+
+/*
* A special page (the vdso) is mapped into all processes at the very
* top of the virtual memory space.
*/
@@ -52,6 +57,9 @@ extern unsigned int vced_count, vcei_count;
* space during mmap's.
*/
#define TASK_UNMAPPED_BASE ((TASK_SIZE / 3) & ~(PAGE_SIZE))
+
+#define TASK_IS_32BIT_ADDR 1
+
#endif
#ifdef CONFIG_64BIT
@@ -77,6 +85,9 @@ extern unsigned int vced_count, vcei_count;
PAGE_ALIGN(TASK_SIZE32 / 3) : PAGE_ALIGN(TASK_SIZE / 3))
#define TASK_SIZE_OF(tsk) \
(test_tsk_thread_flag(tsk, TIF_32BIT_ADDR) ? TASK_SIZE32 : TASK_SIZE)
+
+#define TASK_IS_32BIT_ADDR test_thread_flag(TIF_32BIT_ADDR)
+
#endif
#ifdef __KERNEL__
@@ -218,7 +229,6 @@ struct thread_struct {
unsigned long cp0_badvaddr; /* Last user fault */
unsigned long cp0_baduaddr; /* Last kernel fault accessing USEG */
unsigned long error_code;
- unsigned long trap_no;
unsigned long irix_trampoline; /* Wheee... */
unsigned long irix_oldctx;
#ifdef CONFIG_CPU_CAVIUM_OCTEON
@@ -290,7 +300,6 @@ struct thread_struct {
.cp0_badvaddr = 0, \
.cp0_baduaddr = 0, \
.error_code = 0, \
- .trap_no = 0, \
.irix_trampoline = 0, \
.irix_oldctx = 0, \
/* \
diff --git a/arch/mips/include/asm/ptrace.h b/arch/mips/include/asm/ptrace.h
index cdc6a46efd9..9f1b8dba2c8 100644
--- a/arch/mips/include/asm/ptrace.h
+++ b/arch/mips/include/asm/ptrace.h
@@ -137,6 +137,7 @@ extern int ptrace_set_watch_regs(struct task_struct *child,
*/
#define user_mode(regs) (((regs)->cp0_status & KU_MASK) == KU_USER)
+#define regs_return_value(_regs) ((_regs)->regs[2])
#define instruction_pointer(regs) ((regs)->cp0_epc)
#define profile_pc(regs) instruction_pointer(regs)
diff --git a/arch/mips/include/asm/sn/agent.h b/arch/mips/include/asm/sn/agent.h
index ac4ea85c3a5..dc81114d474 100644
--- a/arch/mips/include/asm/sn/agent.h
+++ b/arch/mips/include/asm/sn/agent.h
@@ -11,7 +11,6 @@
#ifndef _ASM_SGI_SN_AGENT_H
#define _ASM_SGI_SN_AGENT_H
-#include <linux/topology.h>
#include <asm/sn/addrs.h>
#include <asm/sn/arch.h>
diff --git a/arch/mips/include/asm/uasm.h b/arch/mips/include/asm/uasm.h
index 697e40c0649..892062d6d74 100644
--- a/arch/mips/include/asm/uasm.h
+++ b/arch/mips/include/asm/uasm.h
@@ -10,44 +10,55 @@
#include <linux/types.h>
+#ifdef CONFIG_EXPORT_UASM
+#include <linux/module.h>
+#define __uasminit
+#define __uasminitdata
+#define UASM_EXPORT_SYMBOL(sym) EXPORT_SYMBOL(sym)
+#else
+#define __uasminit __cpuinit
+#define __uasminitdata __cpuinitdata
+#define UASM_EXPORT_SYMBOL(sym)
+#endif
+
#define Ip_u1u2u3(op) \
-void __cpuinit \
+void __uasminit \
uasm_i##op(u32 **buf, unsigned int a, unsigned int b, unsigned int c)
#define Ip_u2u1u3(op) \
-void __cpuinit \
+void __uasminit \
uasm_i##op(u32 **buf, unsigned int a, unsigned int b, unsigned int c)
#define Ip_u3u1u2(op) \
-void __cpuinit \
+void __uasminit \
uasm_i##op(u32 **buf, unsigned int a, unsigned int b, unsigned int c)
#define Ip_u1u2s3(op) \
-void __cpuinit \
+void __uasminit \
uasm_i##op(u32 **buf, unsigned int a, unsigned int b, signed int c)
#define Ip_u2s3u1(op) \
-void __cpuinit \
+void __uasminit \
uasm_i##op(u32 **buf, unsigned int a, signed int b, unsigned int c)
#define Ip_u2u1s3(op) \
-void __cpuinit \
+void __uasminit \
uasm_i##op(u32 **buf, unsigned int a, unsigned int b, signed int c)
#define Ip_u2u1msbu3(op) \
-void __cpuinit \
+void __uasminit \
uasm_i##op(u32 **buf, unsigned int a, unsigned int b, unsigned int c, \
unsigned int d)
#define Ip_u1u2(op) \
-void __cpuinit uasm_i##op(u32 **buf, unsigned int a, unsigned int b)
+void __uasminit uasm_i##op(u32 **buf, unsigned int a, unsigned int b)
#define Ip_u1s2(op) \
-void __cpuinit uasm_i##op(u32 **buf, unsigned int a, signed int b)
+void __uasminit uasm_i##op(u32 **buf, unsigned int a, signed int b)
-#define Ip_u1(op) void __cpuinit uasm_i##op(u32 **buf, unsigned int a)
+#define Ip_u1(op) void __uasminit uasm_i##op(u32 **buf, unsigned int a)
-#define Ip_0(op) void __cpuinit uasm_i##op(u32 **buf)
+#define Ip_0(op) void __uasminit uasm_i##op(u32 **buf)
Ip_u2u1s3(_addiu);
Ip_u3u1u2(_addu);
@@ -71,6 +82,7 @@ Ip_u2u1u3(_dsra);
Ip_u2u1u3(_dsrl);
Ip_u2u1u3(_dsrl32);
Ip_u2u1u3(_drotr);
+Ip_u2u1u3(_drotr32);
Ip_u3u1u2(_dsubu);
Ip_0(_eret);
Ip_u1(_j);
@@ -111,7 +123,7 @@ struct uasm_label {
int lab;
};
-void __cpuinit uasm_build_label(struct uasm_label **lab, u32 *addr, int lid);
+void __uasminit uasm_build_label(struct uasm_label **lab, u32 *addr, int lid);
#ifdef CONFIG_64BIT
int uasm_in_compat_space_p(long addr);
#endif
@@ -121,7 +133,7 @@ void UASM_i_LA_mostly(u32 **buf, unsigned int rs, long addr);
void UASM_i_LA(u32 **buf, unsigned int rs, long addr);
#define UASM_L_LA(lb) \
-static inline void __cpuinit uasm_l##lb(struct uasm_label **lab, u32 *addr) \
+static inline void __uasminit uasm_l##lb(struct uasm_label **lab, u32 *addr) \
{ \
uasm_build_label(lab, addr, label##lb); \
}
@@ -176,6 +188,15 @@ static inline void uasm_i_dsrl_safe(u32 **p, unsigned int a1,
uasm_i_dsrl32(p, a1, a2, a3 - 32);
}
+static inline void uasm_i_drotr_safe(u32 **p, unsigned int a1,
+ unsigned int a2, unsigned int a3)
+{
+ if (a3 < 32)
+ uasm_i_drotr(p, a1, a2, a3);
+ else
+ uasm_i_drotr32(p, a1, a2, a3 - 32);
+}
+
static inline void uasm_i_dsll_safe(u32 **p, unsigned int a1,
unsigned int a2, unsigned int a3)
{
@@ -213,3 +234,7 @@ void uasm_il_bne(u32 **p, struct uasm_reloc **r, unsigned int reg1,
void uasm_il_bnez(u32 **p, struct uasm_reloc **r, unsigned int reg, int lid);
void uasm_il_bgezl(u32 **p, struct uasm_reloc **r, unsigned int reg, int lid);
void uasm_il_bgez(u32 **p, struct uasm_reloc **r, unsigned int reg, int lid);
+void uasm_il_bbit0(u32 **p, struct uasm_reloc **r, unsigned int reg,
+ unsigned int bit, int lid);
+void uasm_il_bbit1(u32 **p, struct uasm_reloc **r, unsigned int reg,
+ unsigned int bit, int lid);
diff --git a/arch/mips/jazz/Makefile b/arch/mips/jazz/Makefile
index 5aee0c266d1..dd9d99bfcf7 100644
--- a/arch/mips/jazz/Makefile
+++ b/arch/mips/jazz/Makefile
@@ -3,5 +3,3 @@
#
obj-y := irq.o jazzdma.o reset.o setup.o
-
-EXTRA_CFLAGS += -Werror
diff --git a/arch/mips/jazz/Platform b/arch/mips/jazz/Platform
new file mode 100644
index 00000000000..3373788acca
--- /dev/null
+++ b/arch/mips/jazz/Platform
@@ -0,0 +1,6 @@
+#
+# Acer PICA 61, Mips Magnum 4000 and Olivetti M700.
+#
+platform-$(CONFIG_MACH_JAZZ) += jazz/
+cflags-$(CONFIG_MACH_JAZZ) += -I$(srctree)/arch/mips/include/asm/mach-jazz
+load-$(CONFIG_MACH_JAZZ) += 0xffffffff80080000
diff --git a/arch/mips/jz4740/Kconfig b/arch/mips/jz4740/Kconfig
new file mode 100644
index 00000000000..3e7141f0746
--- /dev/null
+++ b/arch/mips/jz4740/Kconfig
@@ -0,0 +1,12 @@
+choice
+ prompt "Machine type"
+ depends on MACH_JZ4740
+ default JZ4740_QI_LB60
+
+config JZ4740_QI_LB60
+ bool "Qi Hardware Ben NanoNote"
+
+endchoice
+
+config HAVE_PWM
+ bool
diff --git a/arch/mips/jz4740/Makefile b/arch/mips/jz4740/Makefile
new file mode 100644
index 00000000000..a604eaeb6c0
--- /dev/null
+++ b/arch/mips/jz4740/Makefile
@@ -0,0 +1,20 @@
+#
+# Makefile for the Ingenic JZ4740.
+#
+
+# Object file lists.
+
+obj-y += prom.o irq.o time.o reset.o setup.o dma.o \
+ gpio.o clock.o platform.o timer.o pwm.o serial.o
+
+obj-$(CONFIG_DEBUG_FS) += clock-debugfs.o
+
+# board specific support
+
+obj-$(CONFIG_JZ4740_QI_LB60) += board-qi_lb60.o
+
+# PM support
+
+obj-$(CONFIG_PM) += pm.o
+
+EXTRA_CFLAGS += -Werror -Wall
diff --git a/arch/mips/jz4740/Platform b/arch/mips/jz4740/Platform
new file mode 100644
index 00000000000..6a97230e3d0
--- /dev/null
+++ b/arch/mips/jz4740/Platform
@@ -0,0 +1,3 @@
+core-$(CONFIG_MACH_JZ4740) += arch/mips/jz4740/
+cflags-$(CONFIG_MACH_JZ4740) += -I$(srctree)/arch/mips/include/asm/mach-jz4740
+load-$(CONFIG_MACH_JZ4740) += 0xffffffff80010000
diff --git a/arch/mips/jz4740/board-qi_lb60.c b/arch/mips/jz4740/board-qi_lb60.c
new file mode 100644
index 00000000000..5742bb4d78f
--- /dev/null
+++ b/arch/mips/jz4740/board-qi_lb60.c
@@ -0,0 +1,471 @@
+/*
+ * linux/arch/mips/jz4740/board-qi_lb60.c
+ *
+ * QI_LB60 board support
+ *
+ * Copyright (c) 2009 Qi Hardware inc.,
+ * Author: Xiangfu Liu <xiangfu@qi-hardware.com>
+ * Copyright 2010, Lars-Petrer Clausen <lars@metafoo.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 or later
+ * as published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/gpio.h>
+
+#include <linux/input.h>
+#include <linux/gpio_keys.h>
+#include <linux/input/matrix_keypad.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/spi_gpio.h>
+#include <linux/power_supply.h>
+#include <linux/power/jz4740-battery.h>
+
+#include <asm/mach-jz4740/jz4740_fb.h>
+#include <asm/mach-jz4740/jz4740_mmc.h>
+#include <asm/mach-jz4740/jz4740_nand.h>
+
+#include <linux/regulator/fixed.h>
+#include <linux/regulator/machine.h>
+
+#include <linux/leds_pwm.h>
+
+#include <asm/mach-jz4740/platform.h>
+
+#include "clock.h"
+
+static bool is_avt2;
+
+/* GPIOs */
+#define QI_LB60_GPIO_SD_CD JZ_GPIO_PORTD(0)
+#define QI_LB60_GPIO_SD_VCC_EN_N JZ_GPIO_PORTD(2)
+
+#define QI_LB60_GPIO_KEYOUT(x) (JZ_GPIO_PORTC(10) + (x))
+#define QI_LB60_GPIO_KEYIN(x) (JZ_GPIO_PORTD(18) + (x))
+#define QI_LB60_GPIO_KEYIN8 JZ_GPIO_PORTD(26)
+
+/* NAND */
+static struct nand_ecclayout qi_lb60_ecclayout_1gb = {
+/* .eccbytes = 36,
+ .eccpos = {
+ 6, 7, 8, 9, 10, 11, 12, 13,
+ 14, 15, 16, 17, 18, 19, 20, 21,
+ 22, 23, 24, 25, 26, 27, 28, 29,
+ 30, 31, 32, 33, 34, 35, 36, 37,
+ 38, 39, 40, 41
+ },*/
+ .oobfree = {
+ { .offset = 2, .length = 4 },
+ { .offset = 42, .length = 22 }
+ },
+};
+
+/* Early prototypes of the QI LB60 had only 1GB of NAND.
+ * In order to support these devices aswell the partition and ecc layout is
+ * initalized depending on the NAND size */
+static struct mtd_partition qi_lb60_partitions_1gb[] = {
+ {
+ .name = "NAND BOOT partition",
+ .offset = 0 * 0x100000,
+ .size = 4 * 0x100000,
+ },
+ {
+ .name = "NAND KERNEL partition",
+ .offset = 4 * 0x100000,
+ .size = 4 * 0x100000,
+ },
+ {
+ .name = "NAND ROOTFS partition",
+ .offset = 8 * 0x100000,
+ .size = (504 + 512) * 0x100000,
+ },
+};
+
+static struct nand_ecclayout qi_lb60_ecclayout_2gb = {
+/* .eccbytes = 72,
+ .eccpos = {
+ 12, 13, 14, 15, 16, 17, 18, 19,
+ 20, 21, 22, 23, 24, 25, 26, 27,
+ 28, 29, 30, 31, 32, 33, 34, 35,
+ 36, 37, 38, 39, 40, 41, 42, 43,
+ 44, 45, 46, 47, 48, 49, 50, 51,
+ 52, 53, 54, 55, 56, 57, 58, 59,
+ 60, 61, 62, 63, 64, 65, 66, 67,
+ 68, 69, 70, 71, 72, 73, 74, 75,
+ 76, 77, 78, 79, 80, 81, 82, 83
+ },*/
+ .oobfree = {
+ { .offset = 2, .length = 10 },
+ { .offset = 84, .length = 44 },
+ },
+};
+
+static struct mtd_partition qi_lb60_partitions_2gb[] = {
+ {
+ .name = "NAND BOOT partition",
+ .offset = 0 * 0x100000,
+ .size = 4 * 0x100000,
+ },
+ {
+ .name = "NAND KERNEL partition",
+ .offset = 4 * 0x100000,
+ .size = 4 * 0x100000,
+ },
+ {
+ .name = "NAND ROOTFS partition",
+ .offset = 8 * 0x100000,
+ .size = (504 + 512 + 1024) * 0x100000,
+ },
+};
+
+static void qi_lb60_nand_ident(struct platform_device *pdev,
+ struct nand_chip *chip, struct mtd_partition **partitions,
+ int *num_partitions)
+{
+ if (chip->page_shift == 12) {
+ chip->ecc.layout = &qi_lb60_ecclayout_2gb;
+ *partitions = qi_lb60_partitions_2gb;
+ *num_partitions = ARRAY_SIZE(qi_lb60_partitions_2gb);
+ } else {
+ chip->ecc.layout = &qi_lb60_ecclayout_1gb;
+ *partitions = qi_lb60_partitions_1gb;
+ *num_partitions = ARRAY_SIZE(qi_lb60_partitions_1gb);
+ }
+}
+
+static struct jz_nand_platform_data qi_lb60_nand_pdata = {
+ .ident_callback = qi_lb60_nand_ident,
+ .busy_gpio = 94,
+};
+
+/* Keyboard*/
+
+#define KEY_QI_QI KEY_F13
+#define KEY_QI_UPRED KEY_RIGHTALT
+#define KEY_QI_VOLUP KEY_VOLUMEUP
+#define KEY_QI_VOLDOWN KEY_VOLUMEDOWN
+#define KEY_QI_FN KEY_LEFTCTRL
+
+static const uint32_t qi_lb60_keymap[] = {
+ KEY(0, 0, KEY_F1), /* S2 */
+ KEY(0, 1, KEY_F2), /* S3 */
+ KEY(0, 2, KEY_F3), /* S4 */
+ KEY(0, 3, KEY_F4), /* S5 */
+ KEY(0, 4, KEY_F5), /* S6 */
+ KEY(0, 5, KEY_F6), /* S7 */
+ KEY(0, 6, KEY_F7), /* S8 */
+
+ KEY(1, 0, KEY_Q), /* S10 */
+ KEY(1, 1, KEY_W), /* S11 */
+ KEY(1, 2, KEY_E), /* S12 */
+ KEY(1, 3, KEY_R), /* S13 */
+ KEY(1, 4, KEY_T), /* S14 */
+ KEY(1, 5, KEY_Y), /* S15 */
+ KEY(1, 6, KEY_U), /* S16 */
+ KEY(1, 7, KEY_I), /* S17 */
+ KEY(2, 0, KEY_A), /* S18 */
+ KEY(2, 1, KEY_S), /* S19 */
+ KEY(2, 2, KEY_D), /* S20 */
+ KEY(2, 3, KEY_F), /* S21 */
+ KEY(2, 4, KEY_G), /* S22 */
+ KEY(2, 5, KEY_H), /* S23 */
+ KEY(2, 6, KEY_J), /* S24 */
+ KEY(2, 7, KEY_K), /* S25 */
+ KEY(3, 0, KEY_ESC), /* S26 */
+ KEY(3, 1, KEY_Z), /* S27 */
+ KEY(3, 2, KEY_X), /* S28 */
+ KEY(3, 3, KEY_C), /* S29 */
+ KEY(3, 4, KEY_V), /* S30 */
+ KEY(3, 5, KEY_B), /* S31 */
+ KEY(3, 6, KEY_N), /* S32 */
+ KEY(3, 7, KEY_M), /* S33 */
+ KEY(4, 0, KEY_TAB), /* S34 */
+ KEY(4, 1, KEY_CAPSLOCK), /* S35 */
+ KEY(4, 2, KEY_BACKSLASH), /* S36 */
+ KEY(4, 3, KEY_APOSTROPHE), /* S37 */
+ KEY(4, 4, KEY_COMMA), /* S38 */
+ KEY(4, 5, KEY_DOT), /* S39 */
+ KEY(4, 6, KEY_SLASH), /* S40 */
+ KEY(4, 7, KEY_UP), /* S41 */
+ KEY(5, 0, KEY_O), /* S42 */
+ KEY(5, 1, KEY_L), /* S43 */
+ KEY(5, 2, KEY_EQUAL), /* S44 */
+ KEY(5, 3, KEY_QI_UPRED), /* S45 */
+ KEY(5, 4, KEY_SPACE), /* S46 */
+ KEY(5, 5, KEY_QI_QI), /* S47 */
+ KEY(5, 6, KEY_RIGHTCTRL), /* S48 */
+ KEY(5, 7, KEY_LEFT), /* S49 */
+ KEY(6, 0, KEY_F8), /* S50 */
+ KEY(6, 1, KEY_P), /* S51 */
+ KEY(6, 2, KEY_BACKSPACE),/* S52 */
+ KEY(6, 3, KEY_ENTER), /* S53 */
+ KEY(6, 4, KEY_QI_VOLUP), /* S54 */
+ KEY(6, 5, KEY_QI_VOLDOWN), /* S55 */
+ KEY(6, 6, KEY_DOWN), /* S56 */
+ KEY(6, 7, KEY_RIGHT), /* S57 */
+
+ KEY(7, 0, KEY_LEFTSHIFT), /* S58 */
+ KEY(7, 1, KEY_LEFTALT), /* S59 */
+ KEY(7, 2, KEY_QI_FN), /* S60 */
+};
+
+static const struct matrix_keymap_data qi_lb60_keymap_data = {
+ .keymap = qi_lb60_keymap,
+ .keymap_size = ARRAY_SIZE(qi_lb60_keymap),
+};
+
+static const unsigned int qi_lb60_keypad_cols[] = {
+ QI_LB60_GPIO_KEYOUT(0),
+ QI_LB60_GPIO_KEYOUT(1),
+ QI_LB60_GPIO_KEYOUT(2),
+ QI_LB60_GPIO_KEYOUT(3),
+ QI_LB60_GPIO_KEYOUT(4),
+ QI_LB60_GPIO_KEYOUT(5),
+ QI_LB60_GPIO_KEYOUT(6),
+ QI_LB60_GPIO_KEYOUT(7),
+};
+
+static const unsigned int qi_lb60_keypad_rows[] = {
+ QI_LB60_GPIO_KEYIN(0),
+ QI_LB60_GPIO_KEYIN(1),
+ QI_LB60_GPIO_KEYIN(2),
+ QI_LB60_GPIO_KEYIN(3),
+ QI_LB60_GPIO_KEYIN(4),
+ QI_LB60_GPIO_KEYIN(5),
+ QI_LB60_GPIO_KEYIN(7),
+ QI_LB60_GPIO_KEYIN8,
+};
+
+static struct matrix_keypad_platform_data qi_lb60_pdata = {
+ .keymap_data = &qi_lb60_keymap_data,
+ .col_gpios = qi_lb60_keypad_cols,
+ .row_gpios = qi_lb60_keypad_rows,
+ .num_col_gpios = ARRAY_SIZE(qi_lb60_keypad_cols),
+ .num_row_gpios = ARRAY_SIZE(qi_lb60_keypad_rows),
+ .col_scan_delay_us = 10,
+ .debounce_ms = 10,
+ .wakeup = 1,
+ .active_low = 1,
+};
+
+static struct platform_device qi_lb60_keypad = {
+ .name = "matrix-keypad",
+ .id = -1,
+ .dev = {
+ .platform_data = &qi_lb60_pdata,
+ },
+};
+
+/* Display */
+static struct fb_videomode qi_lb60_video_modes[] = {
+ {
+ .name = "320x240",
+ .xres = 320,
+ .yres = 240,
+ .refresh = 30,
+ .left_margin = 140,
+ .right_margin = 273,
+ .upper_margin = 20,
+ .lower_margin = 2,
+ .hsync_len = 1,
+ .vsync_len = 1,
+ .sync = 0,
+ .vmode = FB_VMODE_NONINTERLACED,
+ },
+};
+
+static struct jz4740_fb_platform_data qi_lb60_fb_pdata = {
+ .width = 60,
+ .height = 45,
+ .num_modes = ARRAY_SIZE(qi_lb60_video_modes),
+ .modes = qi_lb60_video_modes,
+ .bpp = 24,
+ .lcd_type = JZ_LCD_TYPE_8BIT_SERIAL,
+ .pixclk_falling_edge = 1,
+};
+
+struct spi_gpio_platform_data spigpio_platform_data = {
+ .sck = JZ_GPIO_PORTC(23),
+ .mosi = JZ_GPIO_PORTC(22),
+ .miso = -1,
+ .num_chipselect = 1,
+};
+
+static struct platform_device spigpio_device = {
+ .name = "spi_gpio",
+ .id = 1,
+ .dev = {
+ .platform_data = &spigpio_platform_data,
+ },
+};
+
+static struct spi_board_info qi_lb60_spi_board_info[] = {
+ {
+ .modalias = "ili8960",
+ .controller_data = (void *)JZ_GPIO_PORTC(21),
+ .chip_select = 0,
+ .bus_num = 1,
+ .max_speed_hz = 30 * 1000,
+ .mode = SPI_3WIRE,
+ },
+};
+
+/* Battery */
+static struct jz_battery_platform_data qi_lb60_battery_pdata = {
+ .gpio_charge = JZ_GPIO_PORTC(27),
+ .gpio_charge_active_low = 1,
+ .info = {
+ .name = "battery",
+ .technology = POWER_SUPPLY_TECHNOLOGY_LIPO,
+ .voltage_max_design = 4200000,
+ .voltage_min_design = 3600000,
+ },
+};
+
+/* GPIO Key: power */
+static struct gpio_keys_button qi_lb60_gpio_keys_buttons[] = {
+ [0] = {
+ .code = KEY_POWER,
+ .gpio = JZ_GPIO_PORTD(29),
+ .active_low = 1,
+ .desc = "Power",
+ .wakeup = 1,
+ },
+};
+
+static struct gpio_keys_platform_data qi_lb60_gpio_keys_data = {
+ .nbuttons = ARRAY_SIZE(qi_lb60_gpio_keys_buttons),
+ .buttons = qi_lb60_gpio_keys_buttons,
+};
+
+static struct platform_device qi_lb60_gpio_keys = {
+ .name = "gpio-keys",
+ .id = -1,
+ .dev = {
+ .platform_data = &qi_lb60_gpio_keys_data,
+ }
+};
+
+static struct jz4740_mmc_platform_data qi_lb60_mmc_pdata = {
+ .gpio_card_detect = QI_LB60_GPIO_SD_CD,
+ .gpio_read_only = -1,
+ .gpio_power = QI_LB60_GPIO_SD_VCC_EN_N,
+ .power_active_low = 1,
+};
+
+/* OHCI */
+static struct regulator_consumer_supply avt2_usb_regulator_consumer =
+ REGULATOR_SUPPLY("vbus", "jz4740-ohci");
+
+static struct regulator_init_data avt2_usb_regulator_init_data = {
+ .num_consumer_supplies = 1,
+ .consumer_supplies = &avt2_usb_regulator_consumer,
+ .constraints = {
+ .name = "USB power",
+ .min_uV = 5000000,
+ .max_uV = 5000000,
+ .valid_modes_mask = REGULATOR_MODE_NORMAL,
+ .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+ },
+};
+
+static struct fixed_voltage_config avt2_usb_regulator_data = {
+ .supply_name = "USB power",
+ .microvolts = 5000000,
+ .gpio = JZ_GPIO_PORTB(17),
+ .init_data = &avt2_usb_regulator_init_data,
+};
+
+static struct platform_device avt2_usb_regulator_device = {
+ .name = "reg-fixed-voltage",
+ .id = -1,
+ .dev = {
+ .platform_data = &avt2_usb_regulator_data,
+ }
+};
+
+/* beeper */
+static struct platform_device qi_lb60_pwm_beeper = {
+ .name = "pwm-beeper",
+ .id = -1,
+ .dev = {
+ .platform_data = (void *)4,
+ },
+};
+
+static struct platform_device *jz_platform_devices[] __initdata = {
+ &jz4740_udc_device,
+ &jz4740_mmc_device,
+ &jz4740_nand_device,
+ &qi_lb60_keypad,
+ &spigpio_device,
+ &jz4740_framebuffer_device,
+ &jz4740_pcm_device,
+ &jz4740_i2s_device,
+ &jz4740_codec_device,
+ &jz4740_rtc_device,
+ &jz4740_adc_device,
+ &qi_lb60_gpio_keys,
+ &qi_lb60_pwm_beeper,
+};
+
+static void __init board_gpio_setup(void)
+{
+ /* We only need to enable/disable pullup here for pins used in generic
+ * drivers. Everything else is done by the drivers themselfs. */
+ jz_gpio_disable_pullup(QI_LB60_GPIO_SD_VCC_EN_N);
+ jz_gpio_disable_pullup(QI_LB60_GPIO_SD_CD);
+}
+
+static int __init qi_lb60_init_platform_devices(void)
+{
+ jz4740_framebuffer_device.dev.platform_data = &qi_lb60_fb_pdata;
+ jz4740_nand_device.dev.platform_data = &qi_lb60_nand_pdata;
+ jz4740_adc_device.dev.platform_data = &qi_lb60_battery_pdata;
+ jz4740_mmc_device.dev.platform_data = &qi_lb60_mmc_pdata;
+
+ jz4740_serial_device_register();
+
+ spi_register_board_info(qi_lb60_spi_board_info,
+ ARRAY_SIZE(qi_lb60_spi_board_info));
+
+ if (is_avt2) {
+ platform_device_register(&avt2_usb_regulator_device);
+ platform_device_register(&jz4740_usb_ohci_device);
+ }
+
+ return platform_add_devices(jz_platform_devices,
+ ARRAY_SIZE(jz_platform_devices));
+
+}
+
+struct jz4740_clock_board_data jz4740_clock_bdata = {
+ .ext_rate = 12000000,
+ .rtc_rate = 32768,
+};
+
+static __init int board_avt2(char *str)
+{
+ qi_lb60_mmc_pdata.card_detect_active_low = 1;
+ is_avt2 = true;
+
+ return 1;
+}
+__setup("avt2", board_avt2);
+
+static int __init qi_lb60_board_setup(void)
+{
+ printk(KERN_INFO "Qi Hardware JZ4740 QI %s setup\n",
+ is_avt2 ? "AVT2" : "LB60");
+
+ board_gpio_setup();
+
+ if (qi_lb60_init_platform_devices())
+ panic("Failed to initalize platform devices\n");
+
+ return 0;
+}
+arch_initcall(qi_lb60_board_setup);
diff --git a/arch/mips/jz4740/clock-debugfs.c b/arch/mips/jz4740/clock-debugfs.c
new file mode 100644
index 00000000000..330a0f2bf17
--- /dev/null
+++ b/arch/mips/jz4740/clock-debugfs.c
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2010, Lars-Peter Clausen <lars@metafoo.de>
+ * JZ4740 SoC clock support debugfs entries
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+
+#include <linux/debugfs.h>
+#include <linux/uaccess.h>
+
+#include <asm/mach-jz4740/clock.h>
+#include "clock.h"
+
+static struct dentry *jz4740_clock_debugfs;
+
+static int jz4740_clock_debugfs_show_enabled(void *data, uint64_t *value)
+{
+ struct clk *clk = data;
+ *value = clk_is_enabled(clk);
+
+ return 0;
+}
+
+static int jz4740_clock_debugfs_set_enabled(void *data, uint64_t value)
+{
+ struct clk *clk = data;
+
+ if (value)
+ return clk_enable(clk);
+ else
+ clk_disable(clk);
+
+ return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(jz4740_clock_debugfs_ops_enabled,
+ jz4740_clock_debugfs_show_enabled,
+ jz4740_clock_debugfs_set_enabled,
+ "%llu\n");
+
+static int jz4740_clock_debugfs_show_rate(void *data, uint64_t *value)
+{
+ struct clk *clk = data;
+ *value = clk_get_rate(clk);
+
+ return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(jz4740_clock_debugfs_ops_rate,
+ jz4740_clock_debugfs_show_rate,
+ NULL,
+ "%llu\n");
+
+void jz4740_clock_debugfs_add_clk(struct clk *clk)
+{
+ if (!jz4740_clock_debugfs)
+ return;
+
+ clk->debugfs_entry = debugfs_create_dir(clk->name, jz4740_clock_debugfs);
+ debugfs_create_file("rate", S_IWUGO | S_IRUGO, clk->debugfs_entry, clk,
+ &jz4740_clock_debugfs_ops_rate);
+ debugfs_create_file("enabled", S_IRUGO, clk->debugfs_entry, clk,
+ &jz4740_clock_debugfs_ops_enabled);
+
+ if (clk->parent) {
+ char parent_path[100];
+ snprintf(parent_path, 100, "../%s", clk->parent->name);
+ clk->debugfs_parent_entry = debugfs_create_symlink("parent",
+ clk->debugfs_entry,
+ parent_path);
+ }
+}
+
+/* TODO: Locking */
+void jz4740_clock_debugfs_update_parent(struct clk *clk)
+{
+ if (clk->debugfs_parent_entry)
+ debugfs_remove(clk->debugfs_parent_entry);
+
+ if (clk->parent) {
+ char parent_path[100];
+ snprintf(parent_path, 100, "../%s", clk->parent->name);
+ clk->debugfs_parent_entry = debugfs_create_symlink("parent",
+ clk->debugfs_entry,
+ parent_path);
+ } else {
+ clk->debugfs_parent_entry = NULL;
+ }
+}
+
+void jz4740_clock_debugfs_init(void)
+{
+ jz4740_clock_debugfs = debugfs_create_dir("jz4740-clock", NULL);
+ if (IS_ERR(jz4740_clock_debugfs))
+ jz4740_clock_debugfs = NULL;
+}
diff --git a/arch/mips/jz4740/clock.c b/arch/mips/jz4740/clock.c
new file mode 100644
index 00000000000..118a8a5562d
--- /dev/null
+++ b/arch/mips/jz4740/clock.c
@@ -0,0 +1,924 @@
+/*
+ * Copyright (C) 2010, Lars-Peter Clausen <lars@metafoo.de>
+ * JZ4740 SoC clock 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.
+ *
+ * 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/errno.h>
+#include <linux/clk.h>
+#include <linux/spinlock.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/list.h>
+#include <linux/err.h>
+
+#include <asm/mach-jz4740/clock.h>
+#include <asm/mach-jz4740/base.h>
+
+#include "clock.h"
+
+#define JZ_REG_CLOCK_CTRL 0x00
+#define JZ_REG_CLOCK_LOW_POWER 0x04
+#define JZ_REG_CLOCK_PLL 0x10
+#define JZ_REG_CLOCK_GATE 0x20
+#define JZ_REG_CLOCK_SLEEP_CTRL 0x24
+#define JZ_REG_CLOCK_I2S 0x60
+#define JZ_REG_CLOCK_LCD 0x64
+#define JZ_REG_CLOCK_MMC 0x68
+#define JZ_REG_CLOCK_UHC 0x6C
+#define JZ_REG_CLOCK_SPI 0x74
+
+#define JZ_CLOCK_CTRL_I2S_SRC_PLL BIT(31)
+#define JZ_CLOCK_CTRL_KO_ENABLE BIT(30)
+#define JZ_CLOCK_CTRL_UDC_SRC_PLL BIT(29)
+#define JZ_CLOCK_CTRL_UDIV_MASK 0x1f800000
+#define JZ_CLOCK_CTRL_CHANGE_ENABLE BIT(22)
+#define JZ_CLOCK_CTRL_PLL_HALF BIT(21)
+#define JZ_CLOCK_CTRL_LDIV_MASK 0x001f0000
+#define JZ_CLOCK_CTRL_UDIV_OFFSET 23
+#define JZ_CLOCK_CTRL_LDIV_OFFSET 16
+#define JZ_CLOCK_CTRL_MDIV_OFFSET 12
+#define JZ_CLOCK_CTRL_PDIV_OFFSET 8
+#define JZ_CLOCK_CTRL_HDIV_OFFSET 4
+#define JZ_CLOCK_CTRL_CDIV_OFFSET 0
+
+#define JZ_CLOCK_GATE_UART0 BIT(0)
+#define JZ_CLOCK_GATE_TCU BIT(1)
+#define JZ_CLOCK_GATE_RTC BIT(2)
+#define JZ_CLOCK_GATE_I2C BIT(3)
+#define JZ_CLOCK_GATE_SPI BIT(4)
+#define JZ_CLOCK_GATE_AIC BIT(5)
+#define JZ_CLOCK_GATE_I2S BIT(6)
+#define JZ_CLOCK_GATE_MMC BIT(7)
+#define JZ_CLOCK_GATE_ADC BIT(8)
+#define JZ_CLOCK_GATE_CIM BIT(9)
+#define JZ_CLOCK_GATE_LCD BIT(10)
+#define JZ_CLOCK_GATE_UDC BIT(11)
+#define JZ_CLOCK_GATE_DMAC BIT(12)
+#define JZ_CLOCK_GATE_IPU BIT(13)
+#define JZ_CLOCK_GATE_UHC BIT(14)
+#define JZ_CLOCK_GATE_UART1 BIT(15)
+
+#define JZ_CLOCK_I2S_DIV_MASK 0x01ff
+
+#define JZ_CLOCK_LCD_DIV_MASK 0x01ff
+
+#define JZ_CLOCK_MMC_DIV_MASK 0x001f
+
+#define JZ_CLOCK_UHC_DIV_MASK 0x000f
+
+#define JZ_CLOCK_SPI_SRC_PLL BIT(31)
+#define JZ_CLOCK_SPI_DIV_MASK 0x000f
+
+#define JZ_CLOCK_PLL_M_MASK 0x01ff
+#define JZ_CLOCK_PLL_N_MASK 0x001f
+#define JZ_CLOCK_PLL_OD_MASK 0x0003
+#define JZ_CLOCK_PLL_STABLE BIT(10)
+#define JZ_CLOCK_PLL_BYPASS BIT(9)
+#define JZ_CLOCK_PLL_ENABLED BIT(8)
+#define JZ_CLOCK_PLL_STABLIZE_MASK 0x000f
+#define JZ_CLOCK_PLL_M_OFFSET 23
+#define JZ_CLOCK_PLL_N_OFFSET 18
+#define JZ_CLOCK_PLL_OD_OFFSET 16
+
+#define JZ_CLOCK_LOW_POWER_MODE_DOZE BIT(2)
+#define JZ_CLOCK_LOW_POWER_MODE_SLEEP BIT(0)
+
+#define JZ_CLOCK_SLEEP_CTRL_SUSPEND_UHC BIT(7)
+#define JZ_CLOCK_SLEEP_CTRL_ENABLE_UDC BIT(6)
+
+static void __iomem *jz_clock_base;
+static spinlock_t jz_clock_lock;
+static LIST_HEAD(jz_clocks);
+
+struct main_clk {
+ struct clk clk;
+ uint32_t div_offset;
+};
+
+struct divided_clk {
+ struct clk clk;
+ uint32_t reg;
+ uint32_t mask;
+};
+
+struct static_clk {
+ struct clk clk;
+ unsigned long rate;
+};
+
+static uint32_t jz_clk_reg_read(int reg)
+{
+ return readl(jz_clock_base + reg);
+}
+
+static void jz_clk_reg_write_mask(int reg, uint32_t val, uint32_t mask)
+{
+ uint32_t val2;
+
+ spin_lock(&jz_clock_lock);
+ val2 = readl(jz_clock_base + reg);
+ val2 &= ~mask;
+ val2 |= val;
+ writel(val2, jz_clock_base + reg);
+ spin_unlock(&jz_clock_lock);
+}
+
+static void jz_clk_reg_set_bits(int reg, uint32_t mask)
+{
+ uint32_t val;
+
+ spin_lock(&jz_clock_lock);
+ val = readl(jz_clock_base + reg);
+ val |= mask;
+ writel(val, jz_clock_base + reg);
+ spin_unlock(&jz_clock_lock);
+}
+
+static void jz_clk_reg_clear_bits(int reg, uint32_t mask)
+{
+ uint32_t val;
+
+ spin_lock(&jz_clock_lock);
+ val = readl(jz_clock_base + reg);
+ val &= ~mask;
+ writel(val, jz_clock_base + reg);
+ spin_unlock(&jz_clock_lock);
+}
+
+static int jz_clk_enable_gating(struct clk *clk)
+{
+ if (clk->gate_bit == JZ4740_CLK_NOT_GATED)
+ return -EINVAL;
+
+ jz_clk_reg_clear_bits(JZ_REG_CLOCK_GATE, clk->gate_bit);
+ return 0;
+}
+
+static int jz_clk_disable_gating(struct clk *clk)
+{
+ if (clk->gate_bit == JZ4740_CLK_NOT_GATED)
+ return -EINVAL;
+
+ jz_clk_reg_set_bits(JZ_REG_CLOCK_GATE, clk->gate_bit);
+ return 0;
+}
+
+static int jz_clk_is_enabled_gating(struct clk *clk)
+{
+ if (clk->gate_bit == JZ4740_CLK_NOT_GATED)
+ return 1;
+
+ return !(jz_clk_reg_read(JZ_REG_CLOCK_GATE) & clk->gate_bit);
+}
+
+static unsigned long jz_clk_static_get_rate(struct clk *clk)
+{
+ return ((struct static_clk *)clk)->rate;
+}
+
+static int jz_clk_ko_enable(struct clk *clk)
+{
+ jz_clk_reg_set_bits(JZ_REG_CLOCK_CTRL, JZ_CLOCK_CTRL_KO_ENABLE);
+ return 0;
+}
+
+static int jz_clk_ko_disable(struct clk *clk)
+{
+ jz_clk_reg_clear_bits(JZ_REG_CLOCK_CTRL, JZ_CLOCK_CTRL_KO_ENABLE);
+ return 0;
+}
+
+static int jz_clk_ko_is_enabled(struct clk *clk)
+{
+ return !!(jz_clk_reg_read(JZ_REG_CLOCK_CTRL) & JZ_CLOCK_CTRL_KO_ENABLE);
+}
+
+static const int pllno[] = {1, 2, 2, 4};
+
+static unsigned long jz_clk_pll_get_rate(struct clk *clk)
+{
+ uint32_t val;
+ int m;
+ int n;
+ int od;
+
+ val = jz_clk_reg_read(JZ_REG_CLOCK_PLL);
+
+ if (val & JZ_CLOCK_PLL_BYPASS)
+ return clk_get_rate(clk->parent);
+
+ m = ((val >> 23) & 0x1ff) + 2;
+ n = ((val >> 18) & 0x1f) + 2;
+ od = (val >> 16) & 0x3;
+
+ return ((clk_get_rate(clk->parent) / n) * m) / pllno[od];
+}
+
+static unsigned long jz_clk_pll_half_get_rate(struct clk *clk)
+{
+ uint32_t reg;
+
+ reg = jz_clk_reg_read(JZ_REG_CLOCK_CTRL);
+ if (reg & JZ_CLOCK_CTRL_PLL_HALF)
+ return jz_clk_pll_get_rate(clk->parent);
+ return jz_clk_pll_get_rate(clk->parent) >> 1;
+}
+
+static const int jz_clk_main_divs[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32};
+
+static unsigned long jz_clk_main_round_rate(struct clk *clk, unsigned long rate)
+{
+ unsigned long parent_rate = jz_clk_pll_get_rate(clk->parent);
+ int div;
+
+ div = parent_rate / rate;
+ if (div > 32)
+ return parent_rate / 32;
+ else if (div < 1)
+ return parent_rate;
+
+ div &= (0x3 << (ffs(div) - 1));
+
+ return parent_rate / div;
+}
+
+static unsigned long jz_clk_main_get_rate(struct clk *clk)
+{
+ struct main_clk *mclk = (struct main_clk *)clk;
+ uint32_t div;
+
+ div = jz_clk_reg_read(JZ_REG_CLOCK_CTRL);
+
+ div >>= mclk->div_offset;
+ div &= 0xf;
+
+ if (div >= ARRAY_SIZE(jz_clk_main_divs))
+ div = ARRAY_SIZE(jz_clk_main_divs) - 1;
+
+ return jz_clk_pll_get_rate(clk->parent) / jz_clk_main_divs[div];
+}
+
+static int jz_clk_main_set_rate(struct clk *clk, unsigned long rate)
+{
+ struct main_clk *mclk = (struct main_clk *)clk;
+ int i;
+ int div;
+ unsigned long parent_rate = jz_clk_pll_get_rate(clk->parent);
+
+ rate = jz_clk_main_round_rate(clk, rate);
+
+ div = parent_rate / rate;
+
+ i = (ffs(div) - 1) << 1;
+ if (i > 0 && !(div & BIT(i-1)))
+ i -= 1;
+
+ jz_clk_reg_write_mask(JZ_REG_CLOCK_CTRL, i << mclk->div_offset,
+ 0xf << mclk->div_offset);
+
+ return 0;
+}
+
+static struct clk_ops jz_clk_static_ops = {
+ .get_rate = jz_clk_static_get_rate,
+ .enable = jz_clk_enable_gating,
+ .disable = jz_clk_disable_gating,
+ .is_enabled = jz_clk_is_enabled_gating,
+};
+
+static struct static_clk jz_clk_ext = {
+ .clk = {
+ .name = "ext",
+ .gate_bit = JZ4740_CLK_NOT_GATED,
+ .ops = &jz_clk_static_ops,
+ },
+};
+
+static struct clk_ops jz_clk_pll_ops = {
+ .get_rate = jz_clk_pll_get_rate,
+};
+
+static struct clk jz_clk_pll = {
+ .name = "pll",
+ .parent = &jz_clk_ext.clk,
+ .ops = &jz_clk_pll_ops,
+};
+
+static struct clk_ops jz_clk_pll_half_ops = {
+ .get_rate = jz_clk_pll_half_get_rate,
+};
+
+static struct clk jz_clk_pll_half = {
+ .name = "pll half",
+ .parent = &jz_clk_pll,
+ .ops = &jz_clk_pll_half_ops,
+};
+
+static const struct clk_ops jz_clk_main_ops = {
+ .get_rate = jz_clk_main_get_rate,
+ .set_rate = jz_clk_main_set_rate,
+ .round_rate = jz_clk_main_round_rate,
+};
+
+static struct main_clk jz_clk_cpu = {
+ .clk = {
+ .name = "cclk",
+ .parent = &jz_clk_pll,
+ .ops = &jz_clk_main_ops,
+ },
+ .div_offset = JZ_CLOCK_CTRL_CDIV_OFFSET,
+};
+
+static struct main_clk jz_clk_memory = {
+ .clk = {
+ .name = "mclk",
+ .parent = &jz_clk_pll,
+ .ops = &jz_clk_main_ops,
+ },
+ .div_offset = JZ_CLOCK_CTRL_MDIV_OFFSET,
+};
+
+static struct main_clk jz_clk_high_speed_peripheral = {
+ .clk = {
+ .name = "hclk",
+ .parent = &jz_clk_pll,
+ .ops = &jz_clk_main_ops,
+ },
+ .div_offset = JZ_CLOCK_CTRL_HDIV_OFFSET,
+};
+
+
+static struct main_clk jz_clk_low_speed_peripheral = {
+ .clk = {
+ .name = "pclk",
+ .parent = &jz_clk_pll,
+ .ops = &jz_clk_main_ops,
+ },
+ .div_offset = JZ_CLOCK_CTRL_PDIV_OFFSET,
+};
+
+static const struct clk_ops jz_clk_ko_ops = {
+ .enable = jz_clk_ko_enable,
+ .disable = jz_clk_ko_disable,
+ .is_enabled = jz_clk_ko_is_enabled,
+};
+
+static struct clk jz_clk_ko = {
+ .name = "cko",
+ .parent = &jz_clk_memory.clk,
+ .ops = &jz_clk_ko_ops,
+};
+
+static int jz_clk_spi_set_parent(struct clk *clk, struct clk *parent)
+{
+ if (parent == &jz_clk_pll)
+ jz_clk_reg_set_bits(JZ_CLOCK_SPI_SRC_PLL, JZ_REG_CLOCK_SPI);
+ else if (parent == &jz_clk_ext.clk)
+ jz_clk_reg_clear_bits(JZ_CLOCK_SPI_SRC_PLL, JZ_REG_CLOCK_SPI);
+ else
+ return -EINVAL;
+
+ clk->parent = parent;
+
+ return 0;
+}
+
+static int jz_clk_i2s_set_parent(struct clk *clk, struct clk *parent)
+{
+ if (parent == &jz_clk_pll_half)
+ jz_clk_reg_set_bits(JZ_REG_CLOCK_CTRL, JZ_CLOCK_CTRL_I2S_SRC_PLL);
+ else if (parent == &jz_clk_ext.clk)
+ jz_clk_reg_clear_bits(JZ_REG_CLOCK_CTRL, JZ_CLOCK_CTRL_I2S_SRC_PLL);
+ else
+ return -EINVAL;
+
+ clk->parent = parent;
+
+ return 0;
+}
+
+static int jz_clk_udc_enable(struct clk *clk)
+{
+ jz_clk_reg_set_bits(JZ_REG_CLOCK_SLEEP_CTRL,
+ JZ_CLOCK_SLEEP_CTRL_ENABLE_UDC);
+
+ return 0;
+}
+
+static int jz_clk_udc_disable(struct clk *clk)
+{
+ jz_clk_reg_clear_bits(JZ_REG_CLOCK_SLEEP_CTRL,
+ JZ_CLOCK_SLEEP_CTRL_ENABLE_UDC);
+
+ return 0;
+}
+
+static int jz_clk_udc_is_enabled(struct clk *clk)
+{
+ return !!(jz_clk_reg_read(JZ_REG_CLOCK_SLEEP_CTRL) &
+ JZ_CLOCK_SLEEP_CTRL_ENABLE_UDC);
+}
+
+static int jz_clk_udc_set_parent(struct clk *clk, struct clk *parent)
+{
+ if (parent == &jz_clk_pll_half)
+ jz_clk_reg_set_bits(JZ_REG_CLOCK_CTRL, JZ_CLOCK_CTRL_UDC_SRC_PLL);
+ else if (parent == &jz_clk_ext.clk)
+ jz_clk_reg_clear_bits(JZ_REG_CLOCK_CTRL, JZ_CLOCK_CTRL_UDC_SRC_PLL);
+ else
+ return -EINVAL;
+
+ clk->parent = parent;
+
+ return 0;
+}
+
+static int jz_clk_udc_set_rate(struct clk *clk, unsigned long rate)
+{
+ int div;
+
+ if (clk->parent == &jz_clk_ext.clk)
+ return -EINVAL;
+
+ div = clk_get_rate(clk->parent) / rate - 1;
+
+ if (div < 0)
+ div = 0;
+ else if (div > 63)
+ div = 63;
+
+ jz_clk_reg_write_mask(JZ_REG_CLOCK_CTRL, div << JZ_CLOCK_CTRL_UDIV_OFFSET,
+ JZ_CLOCK_CTRL_UDIV_MASK);
+ return 0;
+}
+
+static unsigned long jz_clk_udc_get_rate(struct clk *clk)
+{
+ int div;
+
+ if (clk->parent == &jz_clk_ext.clk)
+ return clk_get_rate(clk->parent);
+
+ div = (jz_clk_reg_read(JZ_REG_CLOCK_CTRL) & JZ_CLOCK_CTRL_UDIV_MASK);
+ div >>= JZ_CLOCK_CTRL_UDIV_OFFSET;
+ div += 1;
+
+ return clk_get_rate(clk->parent) / div;
+}
+
+static unsigned long jz_clk_divided_get_rate(struct clk *clk)
+{
+ struct divided_clk *dclk = (struct divided_clk *)clk;
+ int div;
+
+ if (clk->parent == &jz_clk_ext.clk)
+ return clk_get_rate(clk->parent);
+
+ div = (jz_clk_reg_read(dclk->reg) & dclk->mask) + 1;
+
+ return clk_get_rate(clk->parent) / div;
+}
+
+static int jz_clk_divided_set_rate(struct clk *clk, unsigned long rate)
+{
+ struct divided_clk *dclk = (struct divided_clk *)clk;
+ int div;
+
+ if (clk->parent == &jz_clk_ext.clk)
+ return -EINVAL;
+
+ div = clk_get_rate(clk->parent) / rate - 1;
+
+ if (div < 0)
+ div = 0;
+ else if (div > dclk->mask)
+ div = dclk->mask;
+
+ jz_clk_reg_write_mask(dclk->reg, div, dclk->mask);
+
+ return 0;
+}
+
+static unsigned long jz_clk_ldclk_round_rate(struct clk *clk, unsigned long rate)
+{
+ int div;
+ unsigned long parent_rate = jz_clk_pll_half_get_rate(clk->parent);
+
+ if (rate > 150000000)
+ return 150000000;
+
+ div = parent_rate / rate;
+ if (div < 1)
+ div = 1;
+ else if (div > 32)
+ div = 32;
+
+ return parent_rate / div;
+}
+
+static int jz_clk_ldclk_set_rate(struct clk *clk, unsigned long rate)
+{
+ int div;
+
+ if (rate > 150000000)
+ return -EINVAL;
+
+ div = jz_clk_pll_half_get_rate(clk->parent) / rate - 1;
+ if (div < 0)
+ div = 0;
+ else if (div > 31)
+ div = 31;
+
+ jz_clk_reg_write_mask(JZ_REG_CLOCK_CTRL, div << JZ_CLOCK_CTRL_LDIV_OFFSET,
+ JZ_CLOCK_CTRL_LDIV_MASK);
+
+ return 0;
+}
+
+static unsigned long jz_clk_ldclk_get_rate(struct clk *clk)
+{
+ int div;
+
+ div = jz_clk_reg_read(JZ_REG_CLOCK_CTRL) & JZ_CLOCK_CTRL_LDIV_MASK;
+ div >>= JZ_CLOCK_CTRL_LDIV_OFFSET;
+
+ return jz_clk_pll_half_get_rate(clk->parent) / (div + 1);
+}
+
+static const struct clk_ops jz_clk_ops_ld = {
+ .set_rate = jz_clk_ldclk_set_rate,
+ .get_rate = jz_clk_ldclk_get_rate,
+ .round_rate = jz_clk_ldclk_round_rate,
+ .enable = jz_clk_enable_gating,
+ .disable = jz_clk_disable_gating,
+ .is_enabled = jz_clk_is_enabled_gating,
+};
+
+static struct clk jz_clk_ld = {
+ .name = "lcd",
+ .gate_bit = JZ_CLOCK_GATE_LCD,
+ .parent = &jz_clk_pll_half,
+ .ops = &jz_clk_ops_ld,
+};
+
+static const struct clk_ops jz_clk_i2s_ops = {
+ .set_rate = jz_clk_divided_set_rate,
+ .get_rate = jz_clk_divided_get_rate,
+ .enable = jz_clk_enable_gating,
+ .disable = jz_clk_disable_gating,
+ .is_enabled = jz_clk_is_enabled_gating,
+ .set_parent = jz_clk_i2s_set_parent,
+};
+
+static const struct clk_ops jz_clk_spi_ops = {
+ .set_rate = jz_clk_divided_set_rate,
+ .get_rate = jz_clk_divided_get_rate,
+ .enable = jz_clk_enable_gating,
+ .disable = jz_clk_disable_gating,
+ .is_enabled = jz_clk_is_enabled_gating,
+ .set_parent = jz_clk_spi_set_parent,
+};
+
+static const struct clk_ops jz_clk_divided_ops = {
+ .set_rate = jz_clk_divided_set_rate,
+ .get_rate = jz_clk_divided_get_rate,
+ .enable = jz_clk_enable_gating,
+ .disable = jz_clk_disable_gating,
+ .is_enabled = jz_clk_is_enabled_gating,
+};
+
+static struct divided_clk jz4740_clock_divided_clks[] = {
+ [0] = {
+ .clk = {
+ .name = "i2s",
+ .parent = &jz_clk_ext.clk,
+ .gate_bit = JZ_CLOCK_GATE_I2S,
+ .ops = &jz_clk_i2s_ops,
+ },
+ .reg = JZ_REG_CLOCK_I2S,
+ .mask = JZ_CLOCK_I2S_DIV_MASK,
+ },
+ [1] = {
+ .clk = {
+ .name = "spi",
+ .parent = &jz_clk_ext.clk,
+ .gate_bit = JZ_CLOCK_GATE_SPI,
+ .ops = &jz_clk_spi_ops,
+ },
+ .reg = JZ_REG_CLOCK_SPI,
+ .mask = JZ_CLOCK_SPI_DIV_MASK,
+ },
+ [2] = {
+ .clk = {
+ .name = "lcd_pclk",
+ .parent = &jz_clk_pll_half,
+ .gate_bit = JZ4740_CLK_NOT_GATED,
+ .ops = &jz_clk_divided_ops,
+ },
+ .reg = JZ_REG_CLOCK_LCD,
+ .mask = JZ_CLOCK_LCD_DIV_MASK,
+ },
+ [3] = {
+ .clk = {
+ .name = "mmc",
+ .parent = &jz_clk_pll_half,
+ .gate_bit = JZ_CLOCK_GATE_MMC,
+ .ops = &jz_clk_divided_ops,
+ },
+ .reg = JZ_REG_CLOCK_MMC,
+ .mask = JZ_CLOCK_MMC_DIV_MASK,
+ },
+ [4] = {
+ .clk = {
+ .name = "uhc",
+ .parent = &jz_clk_pll_half,
+ .gate_bit = JZ_CLOCK_GATE_UHC,
+ .ops = &jz_clk_divided_ops,
+ },
+ .reg = JZ_REG_CLOCK_UHC,
+ .mask = JZ_CLOCK_UHC_DIV_MASK,
+ },
+};
+
+static const struct clk_ops jz_clk_udc_ops = {
+ .set_parent = jz_clk_udc_set_parent,
+ .set_rate = jz_clk_udc_set_rate,
+ .get_rate = jz_clk_udc_get_rate,
+ .enable = jz_clk_udc_enable,
+ .disable = jz_clk_udc_disable,
+ .is_enabled = jz_clk_udc_is_enabled,
+};
+
+static const struct clk_ops jz_clk_simple_ops = {
+ .enable = jz_clk_enable_gating,
+ .disable = jz_clk_disable_gating,
+ .is_enabled = jz_clk_is_enabled_gating,
+};
+
+static struct clk jz4740_clock_simple_clks[] = {
+ [0] = {
+ .name = "udc",
+ .parent = &jz_clk_ext.clk,
+ .ops = &jz_clk_udc_ops,
+ },
+ [1] = {
+ .name = "uart0",
+ .parent = &jz_clk_ext.clk,
+ .gate_bit = JZ_CLOCK_GATE_UART0,
+ .ops = &jz_clk_simple_ops,
+ },
+ [2] = {
+ .name = "uart1",
+ .parent = &jz_clk_ext.clk,
+ .gate_bit = JZ_CLOCK_GATE_UART1,
+ .ops = &jz_clk_simple_ops,
+ },
+ [3] = {
+ .name = "dma",
+ .parent = &jz_clk_high_speed_peripheral.clk,
+ .gate_bit = JZ_CLOCK_GATE_UART0,
+ .ops = &jz_clk_simple_ops,
+ },
+ [4] = {
+ .name = "ipu",
+ .parent = &jz_clk_high_speed_peripheral.clk,
+ .gate_bit = JZ_CLOCK_GATE_IPU,
+ .ops = &jz_clk_simple_ops,
+ },
+ [5] = {
+ .name = "adc",
+ .parent = &jz_clk_ext.clk,
+ .gate_bit = JZ_CLOCK_GATE_ADC,
+ .ops = &jz_clk_simple_ops,
+ },
+ [6] = {
+ .name = "i2c",
+ .parent = &jz_clk_ext.clk,
+ .gate_bit = JZ_CLOCK_GATE_I2C,
+ .ops = &jz_clk_simple_ops,
+ },
+ [7] = {
+ .name = "aic",
+ .parent = &jz_clk_ext.clk,
+ .gate_bit = JZ_CLOCK_GATE_AIC,
+ .ops = &jz_clk_simple_ops,
+ },
+};
+
+static struct static_clk jz_clk_rtc = {
+ .clk = {
+ .name = "rtc",
+ .gate_bit = JZ_CLOCK_GATE_RTC,
+ .ops = &jz_clk_static_ops,
+ },
+ .rate = 32768,
+};
+
+int clk_enable(struct clk *clk)
+{
+ if (!clk->ops->enable)
+ return -EINVAL;
+
+ return clk->ops->enable(clk);
+}
+EXPORT_SYMBOL_GPL(clk_enable);
+
+void clk_disable(struct clk *clk)
+{
+ if (clk->ops->disable)
+ clk->ops->disable(clk);
+}
+EXPORT_SYMBOL_GPL(clk_disable);
+
+int clk_is_enabled(struct clk *clk)
+{
+ if (clk->ops->is_enabled)
+ return clk->ops->is_enabled(clk);
+
+ return 1;
+}
+
+unsigned long clk_get_rate(struct clk *clk)
+{
+ if (clk->ops->get_rate)
+ return clk->ops->get_rate(clk);
+ if (clk->parent)
+ return clk_get_rate(clk->parent);
+
+ return -EINVAL;
+}
+EXPORT_SYMBOL_GPL(clk_get_rate);
+
+int clk_set_rate(struct clk *clk, unsigned long rate)
+{
+ if (!clk->ops->set_rate)
+ return -EINVAL;
+ return clk->ops->set_rate(clk, rate);
+}
+EXPORT_SYMBOL_GPL(clk_set_rate);
+
+long clk_round_rate(struct clk *clk, unsigned long rate)
+{
+ if (clk->ops->round_rate)
+ return clk->ops->round_rate(clk, rate);
+
+ return -EINVAL;
+}
+EXPORT_SYMBOL_GPL(clk_round_rate);
+
+int clk_set_parent(struct clk *clk, struct clk *parent)
+{
+ int ret;
+ int enabled;
+
+ if (!clk->ops->set_parent)
+ return -EINVAL;
+
+ enabled = clk_is_enabled(clk);
+ if (enabled)
+ clk_disable(clk);
+ ret = clk->ops->set_parent(clk, parent);
+ if (enabled)
+ clk_enable(clk);
+
+ jz4740_clock_debugfs_update_parent(clk);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(clk_set_parent);
+
+struct clk *clk_get(struct device *dev, const char *name)
+{
+ struct clk *clk;
+
+ list_for_each_entry(clk, &jz_clocks, list) {
+ if (strcmp(clk->name, name) == 0)
+ return clk;
+ }
+ return ERR_PTR(-ENXIO);
+}
+EXPORT_SYMBOL_GPL(clk_get);
+
+void clk_put(struct clk *clk)
+{
+}
+EXPORT_SYMBOL_GPL(clk_put);
+
+static inline void clk_add(struct clk *clk)
+{
+ list_add_tail(&clk->list, &jz_clocks);
+
+ jz4740_clock_debugfs_add_clk(clk);
+}
+
+static void clk_register_clks(void)
+{
+ size_t i;
+
+ clk_add(&jz_clk_ext.clk);
+ clk_add(&jz_clk_pll);
+ clk_add(&jz_clk_pll_half);
+ clk_add(&jz_clk_cpu.clk);
+ clk_add(&jz_clk_high_speed_peripheral.clk);
+ clk_add(&jz_clk_low_speed_peripheral.clk);
+ clk_add(&jz_clk_ko);
+ clk_add(&jz_clk_ld);
+ clk_add(&jz_clk_rtc.clk);
+
+ for (i = 0; i < ARRAY_SIZE(jz4740_clock_divided_clks); ++i)
+ clk_add(&jz4740_clock_divided_clks[i].clk);
+
+ for (i = 0; i < ARRAY_SIZE(jz4740_clock_simple_clks); ++i)
+ clk_add(&jz4740_clock_simple_clks[i]);
+}
+
+void jz4740_clock_set_wait_mode(enum jz4740_wait_mode mode)
+{
+ switch (mode) {
+ case JZ4740_WAIT_MODE_IDLE:
+ jz_clk_reg_clear_bits(JZ_REG_CLOCK_LOW_POWER, JZ_CLOCK_LOW_POWER_MODE_SLEEP);
+ break;
+ case JZ4740_WAIT_MODE_SLEEP:
+ jz_clk_reg_set_bits(JZ_REG_CLOCK_LOW_POWER, JZ_CLOCK_LOW_POWER_MODE_SLEEP);
+ break;
+ }
+}
+
+void jz4740_clock_udc_disable_auto_suspend(void)
+{
+ jz_clk_reg_clear_bits(JZ_REG_CLOCK_GATE, JZ_CLOCK_GATE_UDC);
+}
+EXPORT_SYMBOL_GPL(jz4740_clock_udc_disable_auto_suspend);
+
+void jz4740_clock_udc_enable_auto_suspend(void)
+{
+ jz_clk_reg_set_bits(JZ_REG_CLOCK_GATE, JZ_CLOCK_GATE_UDC);
+}
+EXPORT_SYMBOL_GPL(jz4740_clock_udc_enable_auto_suspend);
+
+void jz4740_clock_suspend(void)
+{
+ jz_clk_reg_set_bits(JZ_REG_CLOCK_GATE,
+ JZ_CLOCK_GATE_TCU | JZ_CLOCK_GATE_DMAC | JZ_CLOCK_GATE_UART0);
+
+ jz_clk_reg_clear_bits(JZ_REG_CLOCK_PLL, JZ_CLOCK_PLL_ENABLED);
+}
+
+void jz4740_clock_resume(void)
+{
+ uint32_t pll;
+
+ jz_clk_reg_set_bits(JZ_REG_CLOCK_PLL, JZ_CLOCK_PLL_ENABLED);
+
+ do {
+ pll = jz_clk_reg_read(JZ_REG_CLOCK_PLL);
+ } while (!(pll & JZ_CLOCK_PLL_STABLE));
+
+ jz_clk_reg_clear_bits(JZ_REG_CLOCK_GATE,
+ JZ_CLOCK_GATE_TCU | JZ_CLOCK_GATE_DMAC | JZ_CLOCK_GATE_UART0);
+}
+
+static int jz4740_clock_init(void)
+{
+ uint32_t val;
+
+ jz_clock_base = ioremap(JZ4740_CPM_BASE_ADDR, 0x100);
+ if (!jz_clock_base)
+ return -EBUSY;
+
+ spin_lock_init(&jz_clock_lock);
+
+ jz_clk_ext.rate = jz4740_clock_bdata.ext_rate;
+ jz_clk_rtc.rate = jz4740_clock_bdata.rtc_rate;
+
+ val = jz_clk_reg_read(JZ_REG_CLOCK_SPI);
+
+ if (val & JZ_CLOCK_SPI_SRC_PLL)
+ jz4740_clock_divided_clks[1].clk.parent = &jz_clk_pll_half;
+
+ val = jz_clk_reg_read(JZ_REG_CLOCK_CTRL);
+
+ if (val & JZ_CLOCK_CTRL_I2S_SRC_PLL)
+ jz4740_clock_divided_clks[0].clk.parent = &jz_clk_pll_half;
+
+ if (val & JZ_CLOCK_CTRL_UDC_SRC_PLL)
+ jz4740_clock_simple_clks[0].parent = &jz_clk_pll_half;
+
+ jz4740_clock_debugfs_init();
+
+ clk_register_clks();
+
+ return 0;
+}
+arch_initcall(jz4740_clock_init);
diff --git a/arch/mips/jz4740/clock.h b/arch/mips/jz4740/clock.h
new file mode 100644
index 00000000000..5d07499d746
--- /dev/null
+++ b/arch/mips/jz4740/clock.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2010, Lars-Peter Clausen <lars@metafoo.de>
+ * JZ4740 SoC clock 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.
+ *
+ * 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 __MIPS_JZ4740_CLOCK_H__
+#define __MIPS_JZ4740_CLOCK_H__
+
+#include <linux/list.h>
+
+struct jz4740_clock_board_data {
+ unsigned long ext_rate;
+ unsigned long rtc_rate;
+};
+
+extern struct jz4740_clock_board_data jz4740_clock_bdata;
+
+void jz4740_clock_suspend(void);
+void jz4740_clock_resume(void);
+
+struct clk;
+
+struct clk_ops {
+ unsigned long (*get_rate)(struct clk *clk);
+ unsigned long (*round_rate)(struct clk *clk, unsigned long rate);
+ int (*set_rate)(struct clk *clk, unsigned long rate);
+ int (*enable)(struct clk *clk);
+ int (*disable)(struct clk *clk);
+ int (*is_enabled)(struct clk *clk);
+
+ int (*set_parent)(struct clk *clk, struct clk *parent);
+
+};
+
+struct clk {
+ const char *name;
+ struct clk *parent;
+
+ uint32_t gate_bit;
+
+ const struct clk_ops *ops;
+
+ struct list_head list;
+
+#ifdef CONFIG_DEBUG_FS
+ struct dentry *debugfs_entry;
+ struct dentry *debugfs_parent_entry;
+#endif
+
+};
+
+#define JZ4740_CLK_NOT_GATED ((uint32_t)-1)
+
+int clk_is_enabled(struct clk *clk);
+
+#ifdef CONFIG_DEBUG_FS
+void jz4740_clock_debugfs_init(void);
+void jz4740_clock_debugfs_add_clk(struct clk *clk);
+void jz4740_clock_debugfs_update_parent(struct clk *clk);
+#else
+static inline void jz4740_clock_debugfs_init(void) {};
+static inline void jz4740_clock_debugfs_add_clk(struct clk *clk) {};
+static inline void jz4740_clock_debugfs_update_parent(struct clk *clk) {};
+#endif
+
+#endif
diff --git a/arch/mips/jz4740/dma.c b/arch/mips/jz4740/dma.c
new file mode 100644
index 00000000000..5ebe75a6835
--- /dev/null
+++ b/arch/mips/jz4740/dma.c
@@ -0,0 +1,289 @@
+/*
+ * Copyright (C) 2010, Lars-Peter Clausen <lars@metafoo.de>
+ * JZ4740 SoC DMA 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.
+ *
+ * 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/spinlock.h>
+#include <linux/interrupt.h>
+
+#include <linux/dma-mapping.h>
+#include <asm/mach-jz4740/dma.h>
+#include <asm/mach-jz4740/base.h>
+
+#define JZ_REG_DMA_SRC_ADDR(x) (0x00 + (x) * 0x20)
+#define JZ_REG_DMA_DST_ADDR(x) (0x04 + (x) * 0x20)
+#define JZ_REG_DMA_TRANSFER_COUNT(x) (0x08 + (x) * 0x20)
+#define JZ_REG_DMA_REQ_TYPE(x) (0x0C + (x) * 0x20)
+#define JZ_REG_DMA_STATUS_CTRL(x) (0x10 + (x) * 0x20)
+#define JZ_REG_DMA_CMD(x) (0x14 + (x) * 0x20)
+#define JZ_REG_DMA_DESC_ADDR(x) (0x18 + (x) * 0x20)
+
+#define JZ_REG_DMA_CTRL 0x300
+#define JZ_REG_DMA_IRQ 0x304
+#define JZ_REG_DMA_DOORBELL 0x308
+#define JZ_REG_DMA_DOORBELL_SET 0x30C
+
+#define JZ_DMA_STATUS_CTRL_NO_DESC BIT(31)
+#define JZ_DMA_STATUS_CTRL_DESC_INV BIT(6)
+#define JZ_DMA_STATUS_CTRL_ADDR_ERR BIT(4)
+#define JZ_DMA_STATUS_CTRL_TRANSFER_DONE BIT(3)
+#define JZ_DMA_STATUS_CTRL_HALT BIT(2)
+#define JZ_DMA_STATUS_CTRL_COUNT_TERMINATE BIT(1)
+#define JZ_DMA_STATUS_CTRL_ENABLE BIT(0)
+
+#define JZ_DMA_CMD_SRC_INC BIT(23)
+#define JZ_DMA_CMD_DST_INC BIT(22)
+#define JZ_DMA_CMD_RDIL_MASK (0xf << 16)
+#define JZ_DMA_CMD_SRC_WIDTH_MASK (0x3 << 14)
+#define JZ_DMA_CMD_DST_WIDTH_MASK (0x3 << 12)
+#define JZ_DMA_CMD_INTERVAL_LENGTH_MASK (0x7 << 8)
+#define JZ_DMA_CMD_BLOCK_MODE BIT(7)
+#define JZ_DMA_CMD_DESC_VALID BIT(4)
+#define JZ_DMA_CMD_DESC_VALID_MODE BIT(3)
+#define JZ_DMA_CMD_VALID_IRQ_ENABLE BIT(2)
+#define JZ_DMA_CMD_TRANSFER_IRQ_ENABLE BIT(1)
+#define JZ_DMA_CMD_LINK_ENABLE BIT(0)
+
+#define JZ_DMA_CMD_FLAGS_OFFSET 22
+#define JZ_DMA_CMD_RDIL_OFFSET 16
+#define JZ_DMA_CMD_SRC_WIDTH_OFFSET 14
+#define JZ_DMA_CMD_DST_WIDTH_OFFSET 12
+#define JZ_DMA_CMD_TRANSFER_SIZE_OFFSET 8
+#define JZ_DMA_CMD_MODE_OFFSET 7
+
+#define JZ_DMA_CTRL_PRIORITY_MASK (0x3 << 8)
+#define JZ_DMA_CTRL_HALT BIT(3)
+#define JZ_DMA_CTRL_ADDRESS_ERROR BIT(2)
+#define JZ_DMA_CTRL_ENABLE BIT(0)
+
+
+static void __iomem *jz4740_dma_base;
+static spinlock_t jz4740_dma_lock;
+
+static inline uint32_t jz4740_dma_read(size_t reg)
+{
+ return readl(jz4740_dma_base + reg);
+}
+
+static inline void jz4740_dma_write(size_t reg, uint32_t val)
+{
+ writel(val, jz4740_dma_base + reg);
+}
+
+static inline void jz4740_dma_write_mask(size_t reg, uint32_t val, uint32_t mask)
+{
+ uint32_t val2;
+ val2 = jz4740_dma_read(reg);
+ val2 &= ~mask;
+ val2 |= val;
+ jz4740_dma_write(reg, val2);
+}
+
+struct jz4740_dma_chan {
+ unsigned int id;
+ void *dev;
+ const char *name;
+
+ enum jz4740_dma_flags flags;
+ uint32_t transfer_shift;
+
+ jz4740_dma_complete_callback_t complete_cb;
+
+ unsigned used:1;
+};
+
+#define JZ4740_DMA_CHANNEL(_id) { .id = _id }
+
+struct jz4740_dma_chan jz4740_dma_channels[] = {
+ JZ4740_DMA_CHANNEL(0),
+ JZ4740_DMA_CHANNEL(1),
+ JZ4740_DMA_CHANNEL(2),
+ JZ4740_DMA_CHANNEL(3),
+ JZ4740_DMA_CHANNEL(4),
+ JZ4740_DMA_CHANNEL(5),
+};
+
+struct jz4740_dma_chan *jz4740_dma_request(void *dev, const char *name)
+{
+ unsigned int i;
+ struct jz4740_dma_chan *dma = NULL;
+
+ spin_lock(&jz4740_dma_lock);
+
+ for (i = 0; i < ARRAY_SIZE(jz4740_dma_channels); ++i) {
+ if (!jz4740_dma_channels[i].used) {
+ dma = &jz4740_dma_channels[i];
+ dma->used = 1;
+ break;
+ }
+ }
+
+ spin_unlock(&jz4740_dma_lock);
+
+ if (!dma)
+ return NULL;
+
+ dma->dev = dev;
+ dma->name = name;
+
+ return dma;
+}
+EXPORT_SYMBOL_GPL(jz4740_dma_request);
+
+void jz4740_dma_configure(struct jz4740_dma_chan *dma,
+ const struct jz4740_dma_config *config)
+{
+ uint32_t cmd;
+
+ switch (config->transfer_size) {
+ case JZ4740_DMA_TRANSFER_SIZE_2BYTE:
+ dma->transfer_shift = 1;
+ break;
+ case JZ4740_DMA_TRANSFER_SIZE_4BYTE:
+ dma->transfer_shift = 2;
+ break;
+ case JZ4740_DMA_TRANSFER_SIZE_16BYTE:
+ dma->transfer_shift = 4;
+ break;
+ case JZ4740_DMA_TRANSFER_SIZE_32BYTE:
+ dma->transfer_shift = 5;
+ break;
+ default:
+ dma->transfer_shift = 0;
+ break;
+ }
+
+ cmd = config->flags << JZ_DMA_CMD_FLAGS_OFFSET;
+ cmd |= config->src_width << JZ_DMA_CMD_SRC_WIDTH_OFFSET;
+ cmd |= config->dst_width << JZ_DMA_CMD_DST_WIDTH_OFFSET;
+ cmd |= config->transfer_size << JZ_DMA_CMD_TRANSFER_SIZE_OFFSET;
+ cmd |= config->mode << JZ_DMA_CMD_MODE_OFFSET;
+ cmd |= JZ_DMA_CMD_TRANSFER_IRQ_ENABLE;
+
+ jz4740_dma_write(JZ_REG_DMA_CMD(dma->id), cmd);
+ jz4740_dma_write(JZ_REG_DMA_STATUS_CTRL(dma->id), 0);
+ jz4740_dma_write(JZ_REG_DMA_REQ_TYPE(dma->id), config->request_type);
+}
+EXPORT_SYMBOL_GPL(jz4740_dma_configure);
+
+void jz4740_dma_set_src_addr(struct jz4740_dma_chan *dma, dma_addr_t src)
+{
+ jz4740_dma_write(JZ_REG_DMA_SRC_ADDR(dma->id), src);
+}
+EXPORT_SYMBOL_GPL(jz4740_dma_set_src_addr);
+
+void jz4740_dma_set_dst_addr(struct jz4740_dma_chan *dma, dma_addr_t dst)
+{
+ jz4740_dma_write(JZ_REG_DMA_DST_ADDR(dma->id), dst);
+}
+EXPORT_SYMBOL_GPL(jz4740_dma_set_dst_addr);
+
+void jz4740_dma_set_transfer_count(struct jz4740_dma_chan *dma, uint32_t count)
+{
+ count >>= dma->transfer_shift;
+ jz4740_dma_write(JZ_REG_DMA_TRANSFER_COUNT(dma->id), count);
+}
+EXPORT_SYMBOL_GPL(jz4740_dma_set_transfer_count);
+
+void jz4740_dma_set_complete_cb(struct jz4740_dma_chan *dma,
+ jz4740_dma_complete_callback_t cb)
+{
+ dma->complete_cb = cb;
+}
+EXPORT_SYMBOL_GPL(jz4740_dma_set_complete_cb);
+
+void jz4740_dma_free(struct jz4740_dma_chan *dma)
+{
+ dma->dev = NULL;
+ dma->complete_cb = NULL;
+ dma->used = 0;
+}
+EXPORT_SYMBOL_GPL(jz4740_dma_free);
+
+void jz4740_dma_enable(struct jz4740_dma_chan *dma)
+{
+ jz4740_dma_write_mask(JZ_REG_DMA_STATUS_CTRL(dma->id),
+ JZ_DMA_STATUS_CTRL_NO_DESC | JZ_DMA_STATUS_CTRL_ENABLE,
+ JZ_DMA_STATUS_CTRL_HALT | JZ_DMA_STATUS_CTRL_NO_DESC |
+ JZ_DMA_STATUS_CTRL_ENABLE);
+
+ jz4740_dma_write_mask(JZ_REG_DMA_CTRL,
+ JZ_DMA_CTRL_ENABLE,
+ JZ_DMA_CTRL_HALT | JZ_DMA_CTRL_ENABLE);
+}
+EXPORT_SYMBOL_GPL(jz4740_dma_enable);
+
+void jz4740_dma_disable(struct jz4740_dma_chan *dma)
+{
+ jz4740_dma_write_mask(JZ_REG_DMA_STATUS_CTRL(dma->id), 0,
+ JZ_DMA_STATUS_CTRL_ENABLE);
+}
+EXPORT_SYMBOL_GPL(jz4740_dma_disable);
+
+uint32_t jz4740_dma_get_residue(const struct jz4740_dma_chan *dma)
+{
+ uint32_t residue;
+ residue = jz4740_dma_read(JZ_REG_DMA_TRANSFER_COUNT(dma->id));
+ return residue << dma->transfer_shift;
+}
+EXPORT_SYMBOL_GPL(jz4740_dma_get_residue);
+
+static void jz4740_dma_chan_irq(struct jz4740_dma_chan *dma)
+{
+ uint32_t status;
+
+ status = jz4740_dma_read(JZ_REG_DMA_STATUS_CTRL(dma->id));
+
+ jz4740_dma_write_mask(JZ_REG_DMA_STATUS_CTRL(dma->id), 0,
+ JZ_DMA_STATUS_CTRL_ENABLE | JZ_DMA_STATUS_CTRL_TRANSFER_DONE);
+
+ if (dma->complete_cb)
+ dma->complete_cb(dma, 0, dma->dev);
+}
+
+static irqreturn_t jz4740_dma_irq(int irq, void *dev_id)
+{
+ uint32_t irq_status;
+ unsigned int i;
+
+ irq_status = readl(jz4740_dma_base + JZ_REG_DMA_IRQ);
+
+ for (i = 0; i < 6; ++i) {
+ if (irq_status & (1 << i))
+ jz4740_dma_chan_irq(&jz4740_dma_channels[i]);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static int jz4740_dma_init(void)
+{
+ unsigned int ret;
+
+ jz4740_dma_base = ioremap(JZ4740_DMAC_BASE_ADDR, 0x400);
+
+ if (!jz4740_dma_base)
+ return -EBUSY;
+
+ spin_lock_init(&jz4740_dma_lock);
+
+ ret = request_irq(JZ4740_IRQ_DMAC, jz4740_dma_irq, 0, "DMA", NULL);
+
+ if (ret)
+ printk(KERN_ERR "JZ4740 DMA: Failed to request irq: %d\n", ret);
+
+ return ret;
+}
+arch_initcall(jz4740_dma_init);
diff --git a/arch/mips/jz4740/gpio.c b/arch/mips/jz4740/gpio.c
new file mode 100644
index 00000000000..38f60f35156
--- /dev/null
+++ b/arch/mips/jz4740/gpio.c
@@ -0,0 +1,604 @@
+/*
+ * Copyright (C) 2009-2010, Lars-Peter Clausen <lars@metafoo.de>
+ * JZ4740 platform GPIO 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.
+ *
+ * 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/spinlock.h>
+#include <linux/sysdev.h>
+#include <linux/io.h>
+#include <linux/gpio.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/bitops.h>
+
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+
+#include <asm/mach-jz4740/base.h>
+
+#define JZ4740_GPIO_BASE_A (32*0)
+#define JZ4740_GPIO_BASE_B (32*1)
+#define JZ4740_GPIO_BASE_C (32*2)
+#define JZ4740_GPIO_BASE_D (32*3)
+
+#define JZ4740_GPIO_NUM_A 32
+#define JZ4740_GPIO_NUM_B 32
+#define JZ4740_GPIO_NUM_C 31
+#define JZ4740_GPIO_NUM_D 32
+
+#define JZ4740_IRQ_GPIO_BASE_A (JZ4740_IRQ_GPIO(0) + JZ4740_GPIO_BASE_A)
+#define JZ4740_IRQ_GPIO_BASE_B (JZ4740_IRQ_GPIO(0) + JZ4740_GPIO_BASE_B)
+#define JZ4740_IRQ_GPIO_BASE_C (JZ4740_IRQ_GPIO(0) + JZ4740_GPIO_BASE_C)
+#define JZ4740_IRQ_GPIO_BASE_D (JZ4740_IRQ_GPIO(0) + JZ4740_GPIO_BASE_D)
+
+#define JZ_REG_GPIO_PIN 0x00
+#define JZ_REG_GPIO_DATA 0x10
+#define JZ_REG_GPIO_DATA_SET 0x14
+#define JZ_REG_GPIO_DATA_CLEAR 0x18
+#define JZ_REG_GPIO_MASK 0x20
+#define JZ_REG_GPIO_MASK_SET 0x24
+#define JZ_REG_GPIO_MASK_CLEAR 0x28
+#define JZ_REG_GPIO_PULL 0x30
+#define JZ_REG_GPIO_PULL_SET 0x34
+#define JZ_REG_GPIO_PULL_CLEAR 0x38
+#define JZ_REG_GPIO_FUNC 0x40
+#define JZ_REG_GPIO_FUNC_SET 0x44
+#define JZ_REG_GPIO_FUNC_CLEAR 0x48
+#define JZ_REG_GPIO_SELECT 0x50
+#define JZ_REG_GPIO_SELECT_SET 0x54
+#define JZ_REG_GPIO_SELECT_CLEAR 0x58
+#define JZ_REG_GPIO_DIRECTION 0x60
+#define JZ_REG_GPIO_DIRECTION_SET 0x64
+#define JZ_REG_GPIO_DIRECTION_CLEAR 0x68
+#define JZ_REG_GPIO_TRIGGER 0x70
+#define JZ_REG_GPIO_TRIGGER_SET 0x74
+#define JZ_REG_GPIO_TRIGGER_CLEAR 0x78
+#define JZ_REG_GPIO_FLAG 0x80
+#define JZ_REG_GPIO_FLAG_CLEAR 0x14
+
+#define GPIO_TO_BIT(gpio) BIT(gpio & 0x1f)
+#define GPIO_TO_REG(gpio, reg) (gpio_to_jz_gpio_chip(gpio)->base + (reg))
+#define CHIP_TO_REG(chip, reg) (gpio_chip_to_jz_gpio_chip(chip)->base + (reg))
+
+struct jz_gpio_chip {
+ unsigned int irq;
+ unsigned int irq_base;
+ uint32_t wakeup;
+ uint32_t suspend_mask;
+ uint32_t edge_trigger_both;
+
+ void __iomem *base;
+
+ spinlock_t lock;
+
+ struct gpio_chip gpio_chip;
+ struct irq_chip irq_chip;
+ struct sys_device sysdev;
+};
+
+static struct jz_gpio_chip jz4740_gpio_chips[];
+
+static inline struct jz_gpio_chip *gpio_to_jz_gpio_chip(unsigned int gpio)
+{
+ return &jz4740_gpio_chips[gpio >> 5];
+}
+
+static inline struct jz_gpio_chip *gpio_chip_to_jz_gpio_chip(struct gpio_chip *gpio_chip)
+{
+ return container_of(gpio_chip, struct jz_gpio_chip, gpio_chip);
+}
+
+static inline struct jz_gpio_chip *irq_to_jz_gpio_chip(unsigned int irq)
+{
+ return get_irq_chip_data(irq);
+}
+
+static inline void jz_gpio_write_bit(unsigned int gpio, unsigned int reg)
+{
+ writel(GPIO_TO_BIT(gpio), GPIO_TO_REG(gpio, reg));
+}
+
+int jz_gpio_set_function(int gpio, enum jz_gpio_function function)
+{
+ if (function == JZ_GPIO_FUNC_NONE) {
+ jz_gpio_write_bit(gpio, JZ_REG_GPIO_FUNC_CLEAR);
+ jz_gpio_write_bit(gpio, JZ_REG_GPIO_SELECT_CLEAR);
+ jz_gpio_write_bit(gpio, JZ_REG_GPIO_TRIGGER_CLEAR);
+ } else {
+ jz_gpio_write_bit(gpio, JZ_REG_GPIO_FUNC_SET);
+ jz_gpio_write_bit(gpio, JZ_REG_GPIO_TRIGGER_CLEAR);
+ switch (function) {
+ case JZ_GPIO_FUNC1:
+ jz_gpio_write_bit(gpio, JZ_REG_GPIO_SELECT_CLEAR);
+ break;
+ case JZ_GPIO_FUNC3:
+ jz_gpio_write_bit(gpio, JZ_REG_GPIO_TRIGGER_SET);
+ case JZ_GPIO_FUNC2: /* Falltrough */
+ jz_gpio_write_bit(gpio, JZ_REG_GPIO_SELECT_SET);
+ break;
+ default:
+ BUG();
+ break;
+ }
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(jz_gpio_set_function);
+
+int jz_gpio_bulk_request(const struct jz_gpio_bulk_request *request, size_t num)
+{
+ size_t i;
+ int ret;
+
+ for (i = 0; i < num; ++i, ++request) {
+ ret = gpio_request(request->gpio, request->name);
+ if (ret)
+ goto err;
+ jz_gpio_set_function(request->gpio, request->function);
+ }
+
+ return 0;
+
+err:
+ for (--request; i > 0; --i, --request) {
+ gpio_free(request->gpio);
+ jz_gpio_set_function(request->gpio, JZ_GPIO_FUNC_NONE);
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(jz_gpio_bulk_request);
+
+void jz_gpio_bulk_free(const struct jz_gpio_bulk_request *request, size_t num)
+{
+ size_t i;
+
+ for (i = 0; i < num; ++i, ++request) {
+ gpio_free(request->gpio);
+ jz_gpio_set_function(request->gpio, JZ_GPIO_FUNC_NONE);
+ }
+
+}
+EXPORT_SYMBOL_GPL(jz_gpio_bulk_free);
+
+void jz_gpio_bulk_suspend(const struct jz_gpio_bulk_request *request, size_t num)
+{
+ size_t i;
+
+ for (i = 0; i < num; ++i, ++request) {
+ jz_gpio_set_function(request->gpio, JZ_GPIO_FUNC_NONE);
+ jz_gpio_write_bit(request->gpio, JZ_REG_GPIO_DIRECTION_CLEAR);
+ jz_gpio_write_bit(request->gpio, JZ_REG_GPIO_PULL_SET);
+ }
+}
+EXPORT_SYMBOL_GPL(jz_gpio_bulk_suspend);
+
+void jz_gpio_bulk_resume(const struct jz_gpio_bulk_request *request, size_t num)
+{
+ size_t i;
+
+ for (i = 0; i < num; ++i, ++request)
+ jz_gpio_set_function(request->gpio, request->function);
+}
+EXPORT_SYMBOL_GPL(jz_gpio_bulk_resume);
+
+void jz_gpio_enable_pullup(unsigned gpio)
+{
+ jz_gpio_write_bit(gpio, JZ_REG_GPIO_PULL_CLEAR);
+}
+EXPORT_SYMBOL_GPL(jz_gpio_enable_pullup);
+
+void jz_gpio_disable_pullup(unsigned gpio)
+{
+ jz_gpio_write_bit(gpio, JZ_REG_GPIO_PULL_SET);
+}
+EXPORT_SYMBOL_GPL(jz_gpio_disable_pullup);
+
+static int jz_gpio_get_value(struct gpio_chip *chip, unsigned gpio)
+{
+ return !!(readl(CHIP_TO_REG(chip, JZ_REG_GPIO_PIN)) & BIT(gpio));
+}
+
+static void jz_gpio_set_value(struct gpio_chip *chip, unsigned gpio, int value)
+{
+ uint32_t __iomem *reg = CHIP_TO_REG(chip, JZ_REG_GPIO_DATA_SET);
+ reg += !value;
+ writel(BIT(gpio), reg);
+}
+
+static int jz_gpio_direction_output(struct gpio_chip *chip, unsigned gpio,
+ int value)
+{
+ writel(BIT(gpio), CHIP_TO_REG(chip, JZ_REG_GPIO_DIRECTION_SET));
+ jz_gpio_set_value(chip, gpio, value);
+
+ return 0;
+}
+
+static int jz_gpio_direction_input(struct gpio_chip *chip, unsigned gpio)
+{
+ writel(BIT(gpio), CHIP_TO_REG(chip, JZ_REG_GPIO_DIRECTION_CLEAR));
+
+ return 0;
+}
+
+int jz_gpio_port_direction_input(int port, uint32_t mask)
+{
+ writel(mask, GPIO_TO_REG(port, JZ_REG_GPIO_DIRECTION_CLEAR));
+
+ return 0;
+}
+EXPORT_SYMBOL(jz_gpio_port_direction_input);
+
+int jz_gpio_port_direction_output(int port, uint32_t mask)
+{
+ writel(mask, GPIO_TO_REG(port, JZ_REG_GPIO_DIRECTION_SET));
+
+ return 0;
+}
+EXPORT_SYMBOL(jz_gpio_port_direction_output);
+
+void jz_gpio_port_set_value(int port, uint32_t value, uint32_t mask)
+{
+ writel(~value & mask, GPIO_TO_REG(port, JZ_REG_GPIO_DATA_CLEAR));
+ writel(value & mask, GPIO_TO_REG(port, JZ_REG_GPIO_DATA_SET));
+}
+EXPORT_SYMBOL(jz_gpio_port_set_value);
+
+uint32_t jz_gpio_port_get_value(int port, uint32_t mask)
+{
+ uint32_t value = readl(GPIO_TO_REG(port, JZ_REG_GPIO_PIN));
+
+ return value & mask;
+}
+EXPORT_SYMBOL(jz_gpio_port_get_value);
+
+int gpio_to_irq(unsigned gpio)
+{
+ return JZ4740_IRQ_GPIO(0) + gpio;
+}
+EXPORT_SYMBOL_GPL(gpio_to_irq);
+
+int irq_to_gpio(unsigned irq)
+{
+ return irq - JZ4740_IRQ_GPIO(0);
+}
+EXPORT_SYMBOL_GPL(irq_to_gpio);
+
+#define IRQ_TO_BIT(irq) BIT(irq_to_gpio(irq) & 0x1f)
+
+static void jz_gpio_check_trigger_both(struct jz_gpio_chip *chip, unsigned int irq)
+{
+ uint32_t value;
+ void __iomem *reg;
+ uint32_t mask = IRQ_TO_BIT(irq);
+
+ if (!(chip->edge_trigger_both & mask))
+ return;
+
+ reg = chip->base;
+
+ value = readl(chip->base + JZ_REG_GPIO_PIN);
+ if (value & mask)
+ reg += JZ_REG_GPIO_DIRECTION_CLEAR;
+ else
+ reg += JZ_REG_GPIO_DIRECTION_SET;
+
+ writel(mask, reg);
+}
+
+static void jz_gpio_irq_demux_handler(unsigned int irq, struct irq_desc *desc)
+{
+ uint32_t flag;
+ unsigned int gpio_irq;
+ unsigned int gpio_bank;
+ struct jz_gpio_chip *chip = get_irq_desc_data(desc);
+
+ gpio_bank = JZ4740_IRQ_GPIO0 - irq;
+
+ flag = readl(chip->base + JZ_REG_GPIO_FLAG);
+
+ if (!flag)
+ return;
+
+ gpio_irq = __fls(flag);
+
+ jz_gpio_check_trigger_both(chip, irq);
+
+ gpio_irq += (gpio_bank << 5) + JZ4740_IRQ_GPIO(0);
+
+ generic_handle_irq(gpio_irq);
+};
+
+static inline void jz_gpio_set_irq_bit(unsigned int irq, unsigned int reg)
+{
+ struct jz_gpio_chip *chip = irq_to_jz_gpio_chip(irq);
+ writel(IRQ_TO_BIT(irq), chip->base + reg);
+}
+
+static void jz_gpio_irq_mask(unsigned int irq)
+{
+ jz_gpio_set_irq_bit(irq, JZ_REG_GPIO_MASK_SET);
+};
+
+static void jz_gpio_irq_unmask(unsigned int irq)
+{
+ struct jz_gpio_chip *chip = irq_to_jz_gpio_chip(irq);
+
+ jz_gpio_check_trigger_both(chip, irq);
+
+ jz_gpio_set_irq_bit(irq, JZ_REG_GPIO_MASK_CLEAR);
+};
+
+/* TODO: Check if function is gpio */
+static unsigned int jz_gpio_irq_startup(unsigned int irq)
+{
+ struct irq_desc *desc = irq_to_desc(irq);
+
+ jz_gpio_set_irq_bit(irq, JZ_REG_GPIO_SELECT_SET);
+
+ desc->status &= ~IRQ_MASKED;
+ jz_gpio_irq_unmask(irq);
+
+ return 0;
+}
+
+static void jz_gpio_irq_shutdown(unsigned int irq)
+{
+ struct irq_desc *desc = irq_to_desc(irq);
+
+ jz_gpio_irq_mask(irq);
+ desc->status |= IRQ_MASKED;
+
+ /* Set direction to input */
+ jz_gpio_set_irq_bit(irq, JZ_REG_GPIO_DIRECTION_CLEAR);
+ jz_gpio_set_irq_bit(irq, JZ_REG_GPIO_SELECT_CLEAR);
+}
+
+static void jz_gpio_irq_ack(unsigned int irq)
+{
+ jz_gpio_set_irq_bit(irq, JZ_REG_GPIO_FLAG_CLEAR);
+};
+
+static int jz_gpio_irq_set_type(unsigned int irq, unsigned int flow_type)
+{
+ struct jz_gpio_chip *chip = irq_to_jz_gpio_chip(irq);
+ struct irq_desc *desc = irq_to_desc(irq);
+
+ jz_gpio_irq_mask(irq);
+
+ if (flow_type == IRQ_TYPE_EDGE_BOTH) {
+ uint32_t value = readl(chip->base + JZ_REG_GPIO_PIN);
+ if (value & IRQ_TO_BIT(irq))
+ flow_type = IRQ_TYPE_EDGE_FALLING;
+ else
+ flow_type = IRQ_TYPE_EDGE_RISING;
+ chip->edge_trigger_both |= IRQ_TO_BIT(irq);
+ } else {
+ chip->edge_trigger_both &= ~IRQ_TO_BIT(irq);
+ }
+
+ switch (flow_type) {
+ case IRQ_TYPE_EDGE_RISING:
+ jz_gpio_set_irq_bit(irq, JZ_REG_GPIO_DIRECTION_SET);
+ jz_gpio_set_irq_bit(irq, JZ_REG_GPIO_TRIGGER_SET);
+ break;
+ case IRQ_TYPE_EDGE_FALLING:
+ jz_gpio_set_irq_bit(irq, JZ_REG_GPIO_DIRECTION_CLEAR);
+ jz_gpio_set_irq_bit(irq, JZ_REG_GPIO_TRIGGER_SET);
+ break;
+ case IRQ_TYPE_LEVEL_HIGH:
+ jz_gpio_set_irq_bit(irq, JZ_REG_GPIO_DIRECTION_SET);
+ jz_gpio_set_irq_bit(irq, JZ_REG_GPIO_TRIGGER_CLEAR);
+ break;
+ case IRQ_TYPE_LEVEL_LOW:
+ jz_gpio_set_irq_bit(irq, JZ_REG_GPIO_DIRECTION_CLEAR);
+ jz_gpio_set_irq_bit(irq, JZ_REG_GPIO_TRIGGER_CLEAR);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (!(desc->status & IRQ_MASKED))
+ jz_gpio_irq_unmask(irq);
+
+ return 0;
+}
+
+static int jz_gpio_irq_set_wake(unsigned int irq, unsigned int on)
+{
+ struct jz_gpio_chip *chip = irq_to_jz_gpio_chip(irq);
+ spin_lock(&chip->lock);
+ if (on)
+ chip->wakeup |= IRQ_TO_BIT(irq);
+ else
+ chip->wakeup &= ~IRQ_TO_BIT(irq);
+ spin_unlock(&chip->lock);
+
+ set_irq_wake(chip->irq, on);
+ return 0;
+}
+
+/*
+ * This lock class tells lockdep that GPIO irqs are in a different
+ * category than their parents, so it won't report false recursion.
+ */
+static struct lock_class_key gpio_lock_class;
+
+#define JZ4740_GPIO_CHIP(_bank) { \
+ .irq_base = JZ4740_IRQ_GPIO_BASE_ ## _bank, \
+ .gpio_chip = { \
+ .label = "Bank " # _bank, \
+ .owner = THIS_MODULE, \
+ .set = jz_gpio_set_value, \
+ .get = jz_gpio_get_value, \
+ .direction_output = jz_gpio_direction_output, \
+ .direction_input = jz_gpio_direction_input, \
+ .base = JZ4740_GPIO_BASE_ ## _bank, \
+ .ngpio = JZ4740_GPIO_NUM_ ## _bank, \
+ }, \
+ .irq_chip = { \
+ .name = "GPIO Bank " # _bank, \
+ .mask = jz_gpio_irq_mask, \
+ .unmask = jz_gpio_irq_unmask, \
+ .ack = jz_gpio_irq_ack, \
+ .startup = jz_gpio_irq_startup, \
+ .shutdown = jz_gpio_irq_shutdown, \
+ .set_type = jz_gpio_irq_set_type, \
+ .set_wake = jz_gpio_irq_set_wake, \
+ }, \
+}
+
+static struct jz_gpio_chip jz4740_gpio_chips[] = {
+ JZ4740_GPIO_CHIP(A),
+ JZ4740_GPIO_CHIP(B),
+ JZ4740_GPIO_CHIP(C),
+ JZ4740_GPIO_CHIP(D),
+};
+
+static inline struct jz_gpio_chip *sysdev_to_chip(struct sys_device *dev)
+{
+ return container_of(dev, struct jz_gpio_chip, sysdev);
+}
+
+static int jz4740_gpio_suspend(struct sys_device *dev, pm_message_t state)
+{
+ struct jz_gpio_chip *chip = sysdev_to_chip(dev);
+
+ chip->suspend_mask = readl(chip->base + JZ_REG_GPIO_MASK);
+ writel(~(chip->wakeup), chip->base + JZ_REG_GPIO_MASK_SET);
+ writel(chip->wakeup, chip->base + JZ_REG_GPIO_MASK_CLEAR);
+
+ return 0;
+}
+
+static int jz4740_gpio_resume(struct sys_device *dev)
+{
+ struct jz_gpio_chip *chip = sysdev_to_chip(dev);
+ uint32_t mask = chip->suspend_mask;
+
+ writel(~mask, chip->base + JZ_REG_GPIO_MASK_CLEAR);
+ writel(mask, chip->base + JZ_REG_GPIO_MASK_SET);
+
+ return 0;
+}
+
+static struct sysdev_class jz4740_gpio_sysdev_class = {
+ .name = "gpio",
+ .suspend = jz4740_gpio_suspend,
+ .resume = jz4740_gpio_resume,
+};
+
+static int jz4740_gpio_chip_init(struct jz_gpio_chip *chip, unsigned int id)
+{
+ int ret, irq;
+
+ chip->sysdev.id = id;
+ chip->sysdev.cls = &jz4740_gpio_sysdev_class;
+ ret = sysdev_register(&chip->sysdev);
+
+ if (ret)
+ return ret;
+
+ spin_lock_init(&chip->lock);
+
+ chip->base = ioremap(JZ4740_GPIO_BASE_ADDR + (id * 0x100), 0x100);
+
+ gpiochip_add(&chip->gpio_chip);
+
+ chip->irq = JZ4740_IRQ_INTC_GPIO(id);
+ set_irq_data(chip->irq, chip);
+ set_irq_chained_handler(chip->irq, jz_gpio_irq_demux_handler);
+
+ for (irq = chip->irq_base; irq < chip->irq_base + chip->gpio_chip.ngpio; ++irq) {
+ lockdep_set_class(&irq_desc[irq].lock, &gpio_lock_class);
+ set_irq_chip_data(irq, chip);
+ set_irq_chip_and_handler(irq, &chip->irq_chip, handle_level_irq);
+ }
+
+ return 0;
+}
+
+static int __init jz4740_gpio_init(void)
+{
+ unsigned int i;
+ int ret;
+
+ ret = sysdev_class_register(&jz4740_gpio_sysdev_class);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < ARRAY_SIZE(jz4740_gpio_chips); ++i)
+ jz4740_gpio_chip_init(&jz4740_gpio_chips[i], i);
+
+ printk(KERN_INFO "JZ4740 GPIO initalized\n");
+
+ return 0;
+}
+arch_initcall(jz4740_gpio_init);
+
+#ifdef CONFIG_DEBUG_FS
+
+static inline void gpio_seq_reg(struct seq_file *s, struct jz_gpio_chip *chip,
+ const char *name, unsigned int reg)
+{
+ seq_printf(s, "\t%s: %08x\n", name, readl(chip->base + reg));
+}
+
+static int gpio_regs_show(struct seq_file *s, void *unused)
+{
+ struct jz_gpio_chip *chip = jz4740_gpio_chips;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(jz4740_gpio_chips); ++i, ++chip) {
+ seq_printf(s, "==GPIO %d==\n", i);
+ gpio_seq_reg(s, chip, "Pin", JZ_REG_GPIO_PIN);
+ gpio_seq_reg(s, chip, "Data", JZ_REG_GPIO_DATA);
+ gpio_seq_reg(s, chip, "Mask", JZ_REG_GPIO_MASK);
+ gpio_seq_reg(s, chip, "Pull", JZ_REG_GPIO_PULL);
+ gpio_seq_reg(s, chip, "Func", JZ_REG_GPIO_FUNC);
+ gpio_seq_reg(s, chip, "Select", JZ_REG_GPIO_SELECT);
+ gpio_seq_reg(s, chip, "Direction", JZ_REG_GPIO_DIRECTION);
+ gpio_seq_reg(s, chip, "Trigger", JZ_REG_GPIO_TRIGGER);
+ gpio_seq_reg(s, chip, "Flag", JZ_REG_GPIO_FLAG);
+ }
+
+ return 0;
+}
+
+static int gpio_regs_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, gpio_regs_show, NULL);
+}
+
+static const struct file_operations gpio_regs_operations = {
+ .open = gpio_regs_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static int __init gpio_debugfs_init(void)
+{
+ (void) debugfs_create_file("jz_regs_gpio", S_IFREG | S_IRUGO,
+ NULL, NULL, &gpio_regs_operations);
+ return 0;
+}
+subsys_initcall(gpio_debugfs_init);
+
+#endif
diff --git a/arch/mips/jz4740/irq.c b/arch/mips/jz4740/irq.c
new file mode 100644
index 00000000000..7d33ff83580
--- /dev/null
+++ b/arch/mips/jz4740/irq.c
@@ -0,0 +1,167 @@
+/*
+ * Copyright (C) 2009-2010, Lars-Peter Clausen <lars@metafoo.de>
+ * JZ4740 platform IRQ 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.
+ *
+ * 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/errno.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/timex.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+
+#include <asm/io.h>
+#include <asm/mipsregs.h>
+#include <asm/irq_cpu.h>
+
+#include <asm/mach-jz4740/base.h>
+
+static void __iomem *jz_intc_base;
+static uint32_t jz_intc_wakeup;
+static uint32_t jz_intc_saved;
+
+#define JZ_REG_INTC_STATUS 0x00
+#define JZ_REG_INTC_MASK 0x04
+#define JZ_REG_INTC_SET_MASK 0x08
+#define JZ_REG_INTC_CLEAR_MASK 0x0c
+#define JZ_REG_INTC_PENDING 0x10
+
+#define IRQ_BIT(x) BIT((x) - JZ4740_IRQ_BASE)
+
+static void intc_irq_unmask(unsigned int irq)
+{
+ writel(IRQ_BIT(irq), jz_intc_base + JZ_REG_INTC_CLEAR_MASK);
+}
+
+static void intc_irq_mask(unsigned int irq)
+{
+ writel(IRQ_BIT(irq), jz_intc_base + JZ_REG_INTC_SET_MASK);
+}
+
+static int intc_irq_set_wake(unsigned int irq, unsigned int on)
+{
+ if (on)
+ jz_intc_wakeup |= IRQ_BIT(irq);
+ else
+ jz_intc_wakeup &= ~IRQ_BIT(irq);
+
+ return 0;
+}
+
+static struct irq_chip intc_irq_type = {
+ .name = "INTC",
+ .mask = intc_irq_mask,
+ .mask_ack = intc_irq_mask,
+ .unmask = intc_irq_unmask,
+ .set_wake = intc_irq_set_wake,
+};
+
+static irqreturn_t jz4740_cascade(int irq, void *data)
+{
+ uint32_t irq_reg;
+
+ irq_reg = readl(jz_intc_base + JZ_REG_INTC_PENDING);
+
+ if (irq_reg)
+ generic_handle_irq(__fls(irq_reg) + JZ4740_IRQ_BASE);
+
+ return IRQ_HANDLED;
+}
+
+static struct irqaction jz4740_cascade_action = {
+ .handler = jz4740_cascade,
+ .name = "JZ4740 cascade interrupt",
+};
+
+void __init arch_init_irq(void)
+{
+ int i;
+ mips_cpu_irq_init();
+
+ jz_intc_base = ioremap(JZ4740_INTC_BASE_ADDR, 0x14);
+
+ for (i = JZ4740_IRQ_BASE; i < JZ4740_IRQ_BASE + 32; i++) {
+ intc_irq_mask(i);
+ set_irq_chip_and_handler(i, &intc_irq_type, handle_level_irq);
+ }
+
+ setup_irq(2, &jz4740_cascade_action);
+}
+
+asmlinkage void plat_irq_dispatch(void)
+{
+ unsigned int pending = read_c0_status() & read_c0_cause() & ST0_IM;
+ if (pending & STATUSF_IP2)
+ do_IRQ(2);
+ else if (pending & STATUSF_IP3)
+ do_IRQ(3);
+ else
+ spurious_interrupt();
+}
+
+void jz4740_intc_suspend(void)
+{
+ jz_intc_saved = readl(jz_intc_base + JZ_REG_INTC_MASK);
+ writel(~jz_intc_wakeup, jz_intc_base + JZ_REG_INTC_SET_MASK);
+ writel(jz_intc_wakeup, jz_intc_base + JZ_REG_INTC_CLEAR_MASK);
+}
+
+void jz4740_intc_resume(void)
+{
+ writel(~jz_intc_saved, jz_intc_base + JZ_REG_INTC_CLEAR_MASK);
+ writel(jz_intc_saved, jz_intc_base + JZ_REG_INTC_SET_MASK);
+}
+
+#ifdef CONFIG_DEBUG_FS
+
+static inline void intc_seq_reg(struct seq_file *s, const char *name,
+ unsigned int reg)
+{
+ seq_printf(s, "%s:\t\t%08x\n", name, readl(jz_intc_base + reg));
+}
+
+static int intc_regs_show(struct seq_file *s, void *unused)
+{
+ intc_seq_reg(s, "Status", JZ_REG_INTC_STATUS);
+ intc_seq_reg(s, "Mask", JZ_REG_INTC_MASK);
+ intc_seq_reg(s, "Pending", JZ_REG_INTC_PENDING);
+
+ return 0;
+}
+
+static int intc_regs_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, intc_regs_show, NULL);
+}
+
+static const struct file_operations intc_regs_operations = {
+ .open = intc_regs_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static int __init intc_debugfs_init(void)
+{
+ (void) debugfs_create_file("jz_regs_intc", S_IFREG | S_IRUGO,
+ NULL, NULL, &intc_regs_operations);
+ return 0;
+}
+subsys_initcall(intc_debugfs_init);
+
+#endif
diff --git a/arch/mips/jz4740/irq.h b/arch/mips/jz4740/irq.h
new file mode 100644
index 00000000000..56b5eadd1fa
--- /dev/null
+++ b/arch/mips/jz4740/irq.h
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2010, Lars-Peter Clausen <lars@metafoo.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.
+ *
+ * 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 __MIPS_JZ4740_IRQ_H__
+#define __MIPS_JZ4740_IRQ_H__
+
+extern void jz4740_intc_suspend(void);
+extern void jz4740_intc_resume(void);
+
+#endif
diff --git a/arch/mips/jz4740/platform.c b/arch/mips/jz4740/platform.c
new file mode 100644
index 00000000000..95bc2b5b14f
--- /dev/null
+++ b/arch/mips/jz4740/platform.c
@@ -0,0 +1,291 @@
+/*
+ * Copyright (C) 2009-2010, Lars-Peter Clausen <lars@metafoo.de>
+ * JZ4740 platform devices
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <linux/device.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/resource.h>
+
+#include <linux/dma-mapping.h>
+
+#include <asm/mach-jz4740/platform.h>
+#include <asm/mach-jz4740/base.h>
+#include <asm/mach-jz4740/irq.h>
+
+#include <linux/serial_core.h>
+#include <linux/serial_8250.h>
+
+#include "serial.h"
+#include "clock.h"
+
+/* OHCI controller */
+static struct resource jz4740_usb_ohci_resources[] = {
+ {
+ .start = JZ4740_UHC_BASE_ADDR,
+ .end = JZ4740_UHC_BASE_ADDR + 0x1000 - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = JZ4740_IRQ_UHC,
+ .end = JZ4740_IRQ_UHC,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+struct platform_device jz4740_usb_ohci_device = {
+ .name = "jz4740-ohci",
+ .id = -1,
+ .dev = {
+ .dma_mask = &jz4740_usb_ohci_device.dev.coherent_dma_mask,
+ .coherent_dma_mask = DMA_BIT_MASK(32),
+ },
+ .num_resources = ARRAY_SIZE(jz4740_usb_ohci_resources),
+ .resource = jz4740_usb_ohci_resources,
+};
+
+/* UDC (USB gadget controller) */
+static struct resource jz4740_usb_gdt_resources[] = {
+ {
+ .start = JZ4740_UDC_BASE_ADDR,
+ .end = JZ4740_UDC_BASE_ADDR + 0x1000 - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = JZ4740_IRQ_UDC,
+ .end = JZ4740_IRQ_UDC,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+struct platform_device jz4740_udc_device = {
+ .name = "jz-udc",
+ .id = -1,
+ .dev = {
+ .dma_mask = &jz4740_udc_device.dev.coherent_dma_mask,
+ .coherent_dma_mask = DMA_BIT_MASK(32),
+ },
+ .num_resources = ARRAY_SIZE(jz4740_usb_gdt_resources),
+ .resource = jz4740_usb_gdt_resources,
+};
+
+/* MMC/SD controller */
+static struct resource jz4740_mmc_resources[] = {
+ {
+ .start = JZ4740_MSC_BASE_ADDR,
+ .end = JZ4740_MSC_BASE_ADDR + 0x1000 - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = JZ4740_IRQ_MSC,
+ .end = JZ4740_IRQ_MSC,
+ .flags = IORESOURCE_IRQ,
+ }
+};
+
+struct platform_device jz4740_mmc_device = {
+ .name = "jz4740-mmc",
+ .id = 0,
+ .dev = {
+ .dma_mask = &jz4740_mmc_device.dev.coherent_dma_mask,
+ .coherent_dma_mask = DMA_BIT_MASK(32),
+ },
+ .num_resources = ARRAY_SIZE(jz4740_mmc_resources),
+ .resource = jz4740_mmc_resources,
+};
+
+/* RTC controller */
+static struct resource jz4740_rtc_resources[] = {
+ {
+ .start = JZ4740_RTC_BASE_ADDR,
+ .end = JZ4740_RTC_BASE_ADDR + 0x38 - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = JZ4740_IRQ_RTC,
+ .end = JZ4740_IRQ_RTC,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+struct platform_device jz4740_rtc_device = {
+ .name = "jz4740-rtc",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(jz4740_rtc_resources),
+ .resource = jz4740_rtc_resources,
+};
+
+/* I2C controller */
+static struct resource jz4740_i2c_resources[] = {
+ {
+ .start = JZ4740_I2C_BASE_ADDR,
+ .end = JZ4740_I2C_BASE_ADDR + 0x1000 - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = JZ4740_IRQ_I2C,
+ .end = JZ4740_IRQ_I2C,
+ .flags = IORESOURCE_IRQ,
+ }
+};
+
+struct platform_device jz4740_i2c_device = {
+ .name = "jz4740-i2c",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(jz4740_i2c_resources),
+ .resource = jz4740_i2c_resources,
+};
+
+/* NAND controller */
+static struct resource jz4740_nand_resources[] = {
+ {
+ .name = "mmio",
+ .start = JZ4740_EMC_BASE_ADDR,
+ .end = JZ4740_EMC_BASE_ADDR + 0x1000 - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .name = "bank",
+ .start = 0x18000000,
+ .end = 0x180C0000 - 1,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+struct platform_device jz4740_nand_device = {
+ .name = "jz4740-nand",
+ .num_resources = ARRAY_SIZE(jz4740_nand_resources),
+ .resource = jz4740_nand_resources,
+};
+
+/* LCD controller */
+static struct resource jz4740_framebuffer_resources[] = {
+ {
+ .start = JZ4740_LCD_BASE_ADDR,
+ .end = JZ4740_LCD_BASE_ADDR + 0x1000 - 1,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+struct platform_device jz4740_framebuffer_device = {
+ .name = "jz4740-fb",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(jz4740_framebuffer_resources),
+ .resource = jz4740_framebuffer_resources,
+ .dev = {
+ .dma_mask = &jz4740_framebuffer_device.dev.coherent_dma_mask,
+ .coherent_dma_mask = DMA_BIT_MASK(32),
+ },
+};
+
+/* I2S controller */
+static struct resource jz4740_i2s_resources[] = {
+ {
+ .start = JZ4740_AIC_BASE_ADDR,
+ .end = JZ4740_AIC_BASE_ADDR + 0x38 - 1,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+struct platform_device jz4740_i2s_device = {
+ .name = "jz4740-i2s",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(jz4740_i2s_resources),
+ .resource = jz4740_i2s_resources,
+};
+
+/* PCM */
+struct platform_device jz4740_pcm_device = {
+ .name = "jz4740-pcm",
+ .id = -1,
+};
+
+/* Codec */
+static struct resource jz4740_codec_resources[] = {
+ {
+ .start = JZ4740_AIC_BASE_ADDR + 0x80,
+ .end = JZ4740_AIC_BASE_ADDR + 0x88 - 1,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+struct platform_device jz4740_codec_device = {
+ .name = "jz4740-codec",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(jz4740_codec_resources),
+ .resource = jz4740_codec_resources,
+};
+
+/* ADC controller */
+static struct resource jz4740_adc_resources[] = {
+ {
+ .start = JZ4740_SADC_BASE_ADDR,
+ .end = JZ4740_SADC_BASE_ADDR + 0x30,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = JZ4740_IRQ_SADC,
+ .end = JZ4740_IRQ_SADC,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .start = JZ4740_IRQ_ADC_BASE,
+ .end = JZ4740_IRQ_ADC_BASE,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+struct platform_device jz4740_adc_device = {
+ .name = "jz4740-adc",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(jz4740_adc_resources),
+ .resource = jz4740_adc_resources,
+};
+
+/* Serial */
+#define JZ4740_UART_DATA(_id) \
+ { \
+ .flags = UPF_SKIP_TEST | UPF_IOREMAP | UPF_FIXED_TYPE, \
+ .iotype = UPIO_MEM, \
+ .regshift = 2, \
+ .serial_out = jz4740_serial_out, \
+ .type = PORT_16550, \
+ .mapbase = JZ4740_UART ## _id ## _BASE_ADDR, \
+ .irq = JZ4740_IRQ_UART ## _id, \
+ }
+
+static struct plat_serial8250_port jz4740_uart_data[] = {
+ JZ4740_UART_DATA(0),
+ JZ4740_UART_DATA(1),
+ {},
+};
+
+static struct platform_device jz4740_uart_device = {
+ .name = "serial8250",
+ .id = 0,
+ .dev = {
+ .platform_data = jz4740_uart_data,
+ },
+};
+
+void jz4740_serial_device_register(void)
+{
+ struct plat_serial8250_port *p;
+
+ for (p = jz4740_uart_data; p->flags != 0; ++p)
+ p->uartclk = jz4740_clock_bdata.ext_rate;
+
+ platform_device_register(&jz4740_uart_device);
+}
diff --git a/arch/mips/jz4740/pm.c b/arch/mips/jz4740/pm.c
new file mode 100644
index 00000000000..a9994585424
--- /dev/null
+++ b/arch/mips/jz4740/pm.c
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2010, Lars-Peter Clausen <lars@metafoo.de>
+ * JZ4740 SoC power management 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.
+ *
+ * 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/pm.h>
+#include <linux/delay.h>
+#include <linux/suspend.h>
+
+#include <asm/mach-jz4740/clock.h>
+
+#include "clock.h"
+#include "irq.h"
+
+static int jz4740_pm_enter(suspend_state_t state)
+{
+ jz4740_intc_suspend();
+ jz4740_clock_suspend();
+
+ jz4740_clock_set_wait_mode(JZ4740_WAIT_MODE_SLEEP);
+
+ __asm__(".set\tmips3\n\t"
+ "wait\n\t"
+ ".set\tmips0");
+
+ jz4740_clock_set_wait_mode(JZ4740_WAIT_MODE_IDLE);
+
+ jz4740_clock_resume();
+ jz4740_intc_resume();
+
+ return 0;
+}
+
+static struct platform_suspend_ops jz4740_pm_ops = {
+ .valid = suspend_valid_only_mem,
+ .enter = jz4740_pm_enter,
+};
+
+static int __init jz4740_pm_init(void)
+{
+ suspend_set_ops(&jz4740_pm_ops);
+ return 0;
+
+}
+late_initcall(jz4740_pm_init);
diff --git a/arch/mips/jz4740/prom.c b/arch/mips/jz4740/prom.c
new file mode 100644
index 00000000000..cfeac15eb2e
--- /dev/null
+++ b/arch/mips/jz4740/prom.c
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2010, Lars-Peter Clausen <lars@metafoo.de>
+ * JZ4740 SoC prom code
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/string.h>
+
+#include <linux/serial_reg.h>
+
+#include <asm/bootinfo.h>
+#include <asm/mach-jz4740/base.h>
+
+void jz4740_init_cmdline(int argc, char *argv[])
+{
+ unsigned int count = COMMAND_LINE_SIZE - 1;
+ int i;
+ char *dst = &(arcs_cmdline[0]);
+ char *src;
+
+ for (i = 1; i < argc && count; ++i) {
+ src = argv[i];
+ while (*src && count) {
+ *dst++ = *src++;
+ --count;
+ }
+ *dst++ = ' ';
+ }
+ if (i > 1)
+ --dst;
+
+ *dst = 0;
+}
+
+void __init prom_init(void)
+{
+ jz4740_init_cmdline((int)fw_arg0, (char **)fw_arg1);
+ mips_machtype = MACH_INGENIC_JZ4740;
+}
+
+void __init prom_free_prom_memory(void)
+{
+}
+
+#define UART_REG(_reg) ((void __iomem *)CKSEG1ADDR(JZ4740_UART0_BASE_ADDR + (_reg << 2)))
+
+void prom_putchar(char c)
+{
+ uint8_t lsr;
+
+ do {
+ lsr = readb(UART_REG(UART_LSR));
+ } while ((lsr & UART_LSR_TEMT) == 0);
+
+ writeb(c, UART_REG(UART_TX));
+}
diff --git a/arch/mips/jz4740/pwm.c b/arch/mips/jz4740/pwm.c
new file mode 100644
index 00000000000..a26a6faec9a
--- /dev/null
+++ b/arch/mips/jz4740/pwm.c
@@ -0,0 +1,177 @@
+/*
+ * Copyright (C) 2010, Lars-Peter Clausen <lars@metafoo.de>
+ * JZ4740 platform PWM 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.
+ *
+ * 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/clk.h>
+#include <linux/err.h>
+#include <linux/pwm.h>
+#include <linux/gpio.h>
+
+#include <asm/mach-jz4740/gpio.h>
+#include "timer.h"
+
+static struct clk *jz4740_pwm_clk;
+
+DEFINE_MUTEX(jz4740_pwm_mutex);
+
+struct pwm_device {
+ unsigned int id;
+ unsigned int gpio;
+ bool used;
+};
+
+static struct pwm_device jz4740_pwm_list[] = {
+ { 2, JZ_GPIO_PWM2, false },
+ { 3, JZ_GPIO_PWM3, false },
+ { 4, JZ_GPIO_PWM4, false },
+ { 5, JZ_GPIO_PWM5, false },
+ { 6, JZ_GPIO_PWM6, false },
+ { 7, JZ_GPIO_PWM7, false },
+};
+
+struct pwm_device *pwm_request(int id, const char *label)
+{
+ int ret = 0;
+ struct pwm_device *pwm;
+
+ if (id < 2 || id > 7 || !jz4740_pwm_clk)
+ return ERR_PTR(-ENODEV);
+
+ mutex_lock(&jz4740_pwm_mutex);
+
+ pwm = &jz4740_pwm_list[id - 2];
+ if (pwm->used)
+ ret = -EBUSY;
+ else
+ pwm->used = true;
+
+ mutex_unlock(&jz4740_pwm_mutex);
+
+ if (ret)
+ return ERR_PTR(ret);
+
+ ret = gpio_request(pwm->gpio, label);
+
+ if (ret) {
+ printk(KERN_ERR "Failed to request pwm gpio: %d\n", ret);
+ pwm->used = false;
+ return ERR_PTR(ret);
+ }
+
+ jz_gpio_set_function(pwm->gpio, JZ_GPIO_FUNC_PWM);
+
+ jz4740_timer_start(id);
+
+ return pwm;
+}
+
+void pwm_free(struct pwm_device *pwm)
+{
+ pwm_disable(pwm);
+ jz4740_timer_set_ctrl(pwm->id, 0);
+
+ jz_gpio_set_function(pwm->gpio, JZ_GPIO_FUNC_NONE);
+ gpio_free(pwm->gpio);
+
+ jz4740_timer_stop(pwm->id);
+
+ pwm->used = false;
+}
+
+int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns)
+{
+ unsigned long long tmp;
+ unsigned long period, duty;
+ unsigned int prescaler = 0;
+ unsigned int id = pwm->id;
+ uint16_t ctrl;
+ bool is_enabled;
+
+ if (duty_ns < 0 || duty_ns > period_ns)
+ return -EINVAL;
+
+ tmp = (unsigned long long)clk_get_rate(jz4740_pwm_clk) * period_ns;
+ do_div(tmp, 1000000000);
+ period = tmp;
+
+ while (period > 0xffff && prescaler < 6) {
+ period >>= 2;
+ ++prescaler;
+ }
+
+ if (prescaler == 6)
+ return -EINVAL;
+
+ tmp = (unsigned long long)period * duty_ns;
+ do_div(tmp, period_ns);
+ duty = period - tmp;
+
+ if (duty >= period)
+ duty = period - 1;
+
+ is_enabled = jz4740_timer_is_enabled(id);
+ if (is_enabled)
+ pwm_disable(pwm);
+
+ jz4740_timer_set_count(id, 0);
+ jz4740_timer_set_duty(id, duty);
+ jz4740_timer_set_period(id, period);
+
+ ctrl = JZ_TIMER_CTRL_PRESCALER(prescaler) | JZ_TIMER_CTRL_SRC_EXT |
+ JZ_TIMER_CTRL_PWM_ABBRUPT_SHUTDOWN;
+
+ jz4740_timer_set_ctrl(id, ctrl);
+
+ if (is_enabled)
+ pwm_enable(pwm);
+
+ return 0;
+}
+
+int pwm_enable(struct pwm_device *pwm)
+{
+ uint32_t ctrl = jz4740_timer_get_ctrl(pwm->id);
+
+ ctrl |= JZ_TIMER_CTRL_PWM_ENABLE;
+ jz4740_timer_set_ctrl(pwm->id, ctrl);
+ jz4740_timer_enable(pwm->id);
+
+ return 0;
+}
+
+void pwm_disable(struct pwm_device *pwm)
+{
+ uint32_t ctrl = jz4740_timer_get_ctrl(pwm->id);
+
+ ctrl &= ~JZ_TIMER_CTRL_PWM_ENABLE;
+ jz4740_timer_disable(pwm->id);
+ jz4740_timer_set_ctrl(pwm->id, ctrl);
+}
+
+static int __init jz4740_pwm_init(void)
+{
+ int ret = 0;
+
+ jz4740_pwm_clk = clk_get(NULL, "ext");
+
+ if (IS_ERR(jz4740_pwm_clk)) {
+ ret = PTR_ERR(jz4740_pwm_clk);
+ jz4740_pwm_clk = NULL;
+ }
+
+ return ret;
+}
+subsys_initcall(jz4740_pwm_init);
diff --git a/arch/mips/jz4740/reset.c b/arch/mips/jz4740/reset.c
new file mode 100644
index 00000000000..5f1fb95c0d0
--- /dev/null
+++ b/arch/mips/jz4740/reset.c
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2010, Lars-Peter Clausen <lars@metafoo.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.
+ *
+ * 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/pm.h>
+
+#include <asm/reboot.h>
+
+#include <asm/mach-jz4740/base.h>
+#include <asm/mach-jz4740/timer.h>
+
+static void jz4740_halt(void)
+{
+ while (1) {
+ __asm__(".set push;\n"
+ ".set mips3;\n"
+ "wait;\n"
+ ".set pop;\n"
+ );
+ }
+}
+
+#define JZ_REG_WDT_DATA 0x00
+#define JZ_REG_WDT_COUNTER_ENABLE 0x04
+#define JZ_REG_WDT_COUNTER 0x08
+#define JZ_REG_WDT_CTRL 0x0c
+
+static void jz4740_restart(char *command)
+{
+ void __iomem *wdt_base = ioremap(JZ4740_WDT_BASE_ADDR, 0x0f);
+
+ jz4740_timer_enable_watchdog();
+
+ writeb(0, wdt_base + JZ_REG_WDT_COUNTER_ENABLE);
+
+ writew(0, wdt_base + JZ_REG_WDT_COUNTER);
+ writew(0, wdt_base + JZ_REG_WDT_DATA);
+ writew(BIT(2), wdt_base + JZ_REG_WDT_CTRL);
+
+ writeb(1, wdt_base + JZ_REG_WDT_COUNTER_ENABLE);
+ jz4740_halt();
+}
+
+#define JZ_REG_RTC_CTRL 0x00
+#define JZ_REG_RTC_HIBERNATE 0x20
+
+#define JZ_RTC_CTRL_WRDY BIT(7)
+
+static void jz4740_power_off(void)
+{
+ void __iomem *rtc_base = ioremap(JZ4740_RTC_BASE_ADDR, 0x24);
+ uint32_t ctrl;
+
+ do {
+ ctrl = readl(rtc_base + JZ_REG_RTC_CTRL);
+ } while (!(ctrl & JZ_RTC_CTRL_WRDY));
+
+ writel(1, rtc_base + JZ_REG_RTC_HIBERNATE);
+ jz4740_halt();
+}
+
+void jz4740_reset_init(void)
+{
+ _machine_restart = jz4740_restart;
+ _machine_halt = jz4740_halt;
+ pm_power_off = jz4740_power_off;
+}
diff --git a/arch/mips/jz4740/reset.h b/arch/mips/jz4740/reset.h
new file mode 100644
index 00000000000..5202ab4ad9d
--- /dev/null
+++ b/arch/mips/jz4740/reset.h
@@ -0,0 +1,6 @@
+#ifndef __MIPS_JZ4740_RESET_H__
+#define __MIPS_JZ4740_RESET_H__
+
+extern void jz4740_reset_init(void);
+
+#endif
diff --git a/arch/mips/jz4740/serial.c b/arch/mips/jz4740/serial.c
new file mode 100644
index 00000000000..d23de45826d
--- /dev/null
+++ b/arch/mips/jz4740/serial.c
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2010, Lars-Peter Clausen <lars@metafoo.de>
+ * JZ4740 serial 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.
+ *
+ * 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/serial_core.h>
+#include <linux/serial_reg.h>
+
+void jz4740_serial_out(struct uart_port *p, int offset, int value)
+{
+ switch (offset) {
+ case UART_FCR:
+ value |= 0x10; /* Enable uart module */
+ break;
+ case UART_IER:
+ value |= (value & 0x4) << 2;
+ break;
+ default:
+ break;
+ }
+ writeb(value, p->membase + (offset << p->regshift));
+}
diff --git a/arch/mips/jz4740/serial.h b/arch/mips/jz4740/serial.h
new file mode 100644
index 00000000000..b9fe3ade028
--- /dev/null
+++ b/arch/mips/jz4740/serial.h
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2010, Lars-Peter Clausen <lars@metafoo.de>
+ * JZ4740 serial 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.
+ *
+ * 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 __MIPS_JZ4740_SERIAL_H__
+
+void jz4740_serial_out(struct uart_port *p, int offset, int value);
+
+#endif
diff --git a/arch/mips/jz4740/setup.c b/arch/mips/jz4740/setup.c
new file mode 100644
index 00000000000..6a9e14dab91
--- /dev/null
+++ b/arch/mips/jz4740/setup.c
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2009-2010, Lars-Peter Clausen <lars@metafoo.de>
+ * JZ4740 setup code
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+
+#include "reset.h"
+
+void __init plat_mem_setup(void)
+{
+ jz4740_reset_init();
+}
+
+const char *get_system_type(void)
+{
+ return "JZ4740";
+}
diff --git a/arch/mips/jz4740/time.c b/arch/mips/jz4740/time.c
new file mode 100644
index 00000000000..fe01678d94f
--- /dev/null
+++ b/arch/mips/jz4740/time.c
@@ -0,0 +1,144 @@
+/*
+ * Copyright (C) 2010, Lars-Peter Clausen <lars@metafoo.de>
+ * JZ4740 platform time 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.
+ *
+ * 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/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/time.h>
+
+#include <linux/clockchips.h>
+
+#include <asm/mach-jz4740/irq.h>
+#include <asm/time.h>
+
+#include "clock.h"
+#include "timer.h"
+
+#define TIMER_CLOCKEVENT 0
+#define TIMER_CLOCKSOURCE 1
+
+static uint16_t jz4740_jiffies_per_tick;
+
+static cycle_t jz4740_clocksource_read(struct clocksource *cs)
+{
+ return jz4740_timer_get_count(TIMER_CLOCKSOURCE);
+}
+
+static struct clocksource jz4740_clocksource = {
+ .name = "jz4740-timer",
+ .rating = 200,
+ .read = jz4740_clocksource_read,
+ .mask = CLOCKSOURCE_MASK(16),
+ .flags = CLOCK_SOURCE_IS_CONTINUOUS,
+};
+
+static irqreturn_t jz4740_clockevent_irq(int irq, void *devid)
+{
+ struct clock_event_device *cd = devid;
+
+ jz4740_timer_ack_full(TIMER_CLOCKEVENT);
+
+ if (cd->mode != CLOCK_EVT_MODE_PERIODIC)
+ jz4740_timer_disable(TIMER_CLOCKEVENT);
+
+ cd->event_handler(cd);
+
+ return IRQ_HANDLED;
+}
+
+static void jz4740_clockevent_set_mode(enum clock_event_mode mode,
+ struct clock_event_device *cd)
+{
+ switch (mode) {
+ case CLOCK_EVT_MODE_PERIODIC:
+ jz4740_timer_set_count(TIMER_CLOCKEVENT, 0);
+ jz4740_timer_set_period(TIMER_CLOCKEVENT, jz4740_jiffies_per_tick);
+ case CLOCK_EVT_MODE_RESUME:
+ jz4740_timer_irq_full_enable(TIMER_CLOCKEVENT);
+ jz4740_timer_enable(TIMER_CLOCKEVENT);
+ break;
+ case CLOCK_EVT_MODE_ONESHOT:
+ case CLOCK_EVT_MODE_SHUTDOWN:
+ jz4740_timer_disable(TIMER_CLOCKEVENT);
+ break;
+ default:
+ break;
+ }
+}
+
+static int jz4740_clockevent_set_next(unsigned long evt,
+ struct clock_event_device *cd)
+{
+ jz4740_timer_set_count(TIMER_CLOCKEVENT, 0);
+ jz4740_timer_set_period(TIMER_CLOCKEVENT, evt);
+ jz4740_timer_enable(TIMER_CLOCKEVENT);
+
+ return 0;
+}
+
+static struct clock_event_device jz4740_clockevent = {
+ .name = "jz4740-timer",
+ .features = CLOCK_EVT_FEAT_PERIODIC,
+ .set_next_event = jz4740_clockevent_set_next,
+ .set_mode = jz4740_clockevent_set_mode,
+ .rating = 200,
+ .irq = JZ4740_IRQ_TCU0,
+};
+
+static struct irqaction timer_irqaction = {
+ .handler = jz4740_clockevent_irq,
+ .flags = IRQF_PERCPU | IRQF_TIMER,
+ .name = "jz4740-timerirq",
+ .dev_id = &jz4740_clockevent,
+};
+
+void __init plat_time_init(void)
+{
+ int ret;
+ uint32_t clk_rate;
+ uint16_t ctrl;
+
+ jz4740_timer_init();
+
+ clk_rate = jz4740_clock_bdata.ext_rate >> 4;
+ jz4740_jiffies_per_tick = DIV_ROUND_CLOSEST(clk_rate, HZ);
+
+ clockevent_set_clock(&jz4740_clockevent, clk_rate);
+ jz4740_clockevent.min_delta_ns = clockevent_delta2ns(100, &jz4740_clockevent);
+ jz4740_clockevent.max_delta_ns = clockevent_delta2ns(0xffff, &jz4740_clockevent);
+ jz4740_clockevent.cpumask = cpumask_of(0);
+
+ clockevents_register_device(&jz4740_clockevent);
+
+ clocksource_set_clock(&jz4740_clocksource, clk_rate);
+ ret = clocksource_register(&jz4740_clocksource);
+
+ if (ret)
+ printk(KERN_ERR "Failed to register clocksource: %d\n", ret);
+
+ setup_irq(JZ4740_IRQ_TCU0, &timer_irqaction);
+
+ ctrl = JZ_TIMER_CTRL_PRESCALE_16 | JZ_TIMER_CTRL_SRC_EXT;
+
+ jz4740_timer_set_ctrl(TIMER_CLOCKEVENT, ctrl);
+ jz4740_timer_set_ctrl(TIMER_CLOCKSOURCE, ctrl);
+
+ jz4740_timer_set_period(TIMER_CLOCKEVENT, jz4740_jiffies_per_tick);
+ jz4740_timer_irq_full_enable(TIMER_CLOCKEVENT);
+
+ jz4740_timer_set_period(TIMER_CLOCKSOURCE, 0xffff);
+
+ jz4740_timer_enable(TIMER_CLOCKEVENT);
+ jz4740_timer_enable(TIMER_CLOCKSOURCE);
+}
diff --git a/arch/mips/jz4740/timer.c b/arch/mips/jz4740/timer.c
new file mode 100644
index 00000000000..b2c01512905
--- /dev/null
+++ b/arch/mips/jz4740/timer.c
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2010, Lars-Peter Clausen <lars@metafoo.de>
+ * JZ4740 platform timer 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.
+ *
+ * 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/module.h>
+
+#include "timer.h"
+
+#include <asm/mach-jz4740/base.h>
+
+void __iomem *jz4740_timer_base;
+
+void jz4740_timer_enable_watchdog(void)
+{
+ writel(BIT(16), jz4740_timer_base + JZ_REG_TIMER_STOP_CLEAR);
+}
+
+void jz4740_timer_disable_watchdog(void)
+{
+ writel(BIT(16), jz4740_timer_base + JZ_REG_TIMER_STOP_SET);
+}
+
+void __init jz4740_timer_init(void)
+{
+ jz4740_timer_base = ioremap(JZ4740_TCU_BASE_ADDR, 0x100);
+
+ if (!jz4740_timer_base)
+ panic("Failed to ioremap timer registers");
+
+ /* Disable all timer clocks except for those used as system timers */
+ writel(0x000100fc, jz4740_timer_base + JZ_REG_TIMER_STOP_SET);
+
+ /* Timer irqs are unmasked by default, mask them */
+ writel(0x00ff00ff, jz4740_timer_base + JZ_REG_TIMER_MASK_SET);
+}
diff --git a/arch/mips/jz4740/timer.h b/arch/mips/jz4740/timer.h
new file mode 100644
index 00000000000..fca3994f2e6
--- /dev/null
+++ b/arch/mips/jz4740/timer.h
@@ -0,0 +1,136 @@
+/*
+ * Copyright (C) 2010, Lars-Peter Clausen <lars@metafoo.de>
+ * JZ4740 platform timer 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.
+ *
+ * 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 __MIPS_JZ4740_TIMER_H__
+#define __MIPS_JZ4740_TIMER_H__
+
+#include <linux/module.h>
+#include <linux/io.h>
+
+#define JZ_REG_TIMER_STOP 0x0C
+#define JZ_REG_TIMER_STOP_SET 0x1C
+#define JZ_REG_TIMER_STOP_CLEAR 0x2C
+#define JZ_REG_TIMER_ENABLE 0x00
+#define JZ_REG_TIMER_ENABLE_SET 0x04
+#define JZ_REG_TIMER_ENABLE_CLEAR 0x08
+#define JZ_REG_TIMER_FLAG 0x10
+#define JZ_REG_TIMER_FLAG_SET 0x14
+#define JZ_REG_TIMER_FLAG_CLEAR 0x18
+#define JZ_REG_TIMER_MASK 0x20
+#define JZ_REG_TIMER_MASK_SET 0x24
+#define JZ_REG_TIMER_MASK_CLEAR 0x28
+
+#define JZ_REG_TIMER_DFR(x) (((x) * 0x10) + 0x30)
+#define JZ_REG_TIMER_DHR(x) (((x) * 0x10) + 0x34)
+#define JZ_REG_TIMER_CNT(x) (((x) * 0x10) + 0x38)
+#define JZ_REG_TIMER_CTRL(x) (((x) * 0x10) + 0x3C)
+
+#define JZ_TIMER_IRQ_HALF(x) BIT((x) + 0x10)
+#define JZ_TIMER_IRQ_FULL(x) BIT(x)
+
+#define JZ_TIMER_CTRL_PWM_ABBRUPT_SHUTDOWN BIT(9)
+#define JZ_TIMER_CTRL_PWM_ACTIVE_LOW BIT(8)
+#define JZ_TIMER_CTRL_PWM_ENABLE BIT(7)
+#define JZ_TIMER_CTRL_PRESCALE_MASK 0x1c
+#define JZ_TIMER_CTRL_PRESCALE_OFFSET 0x3
+#define JZ_TIMER_CTRL_PRESCALE_1 (0 << 3)
+#define JZ_TIMER_CTRL_PRESCALE_4 (1 << 3)
+#define JZ_TIMER_CTRL_PRESCALE_16 (2 << 3)
+#define JZ_TIMER_CTRL_PRESCALE_64 (3 << 3)
+#define JZ_TIMER_CTRL_PRESCALE_256 (4 << 3)
+#define JZ_TIMER_CTRL_PRESCALE_1024 (5 << 3)
+
+#define JZ_TIMER_CTRL_PRESCALER(x) ((x) << JZ_TIMER_CTRL_PRESCALE_OFFSET)
+
+#define JZ_TIMER_CTRL_SRC_EXT BIT(2)
+#define JZ_TIMER_CTRL_SRC_RTC BIT(1)
+#define JZ_TIMER_CTRL_SRC_PCLK BIT(0)
+
+extern void __iomem *jz4740_timer_base;
+void __init jz4740_timer_init(void);
+
+static inline void jz4740_timer_stop(unsigned int timer)
+{
+ writel(BIT(timer), jz4740_timer_base + JZ_REG_TIMER_STOP_SET);
+}
+
+static inline void jz4740_timer_start(unsigned int timer)
+{
+ writel(BIT(timer), jz4740_timer_base + JZ_REG_TIMER_STOP_CLEAR);
+}
+
+static inline bool jz4740_timer_is_enabled(unsigned int timer)
+{
+ return readb(jz4740_timer_base + JZ_REG_TIMER_ENABLE) & BIT(timer);
+}
+
+static inline void jz4740_timer_enable(unsigned int timer)
+{
+ writeb(BIT(timer), jz4740_timer_base + JZ_REG_TIMER_ENABLE_SET);
+}
+
+static inline void jz4740_timer_disable(unsigned int timer)
+{
+ writeb(BIT(timer), jz4740_timer_base + JZ_REG_TIMER_ENABLE_CLEAR);
+}
+
+
+static inline void jz4740_timer_set_period(unsigned int timer, uint16_t period)
+{
+ writew(period, jz4740_timer_base + JZ_REG_TIMER_DFR(timer));
+}
+
+static inline void jz4740_timer_set_duty(unsigned int timer, uint16_t duty)
+{
+ writew(duty, jz4740_timer_base + JZ_REG_TIMER_DHR(timer));
+}
+
+static inline void jz4740_timer_set_count(unsigned int timer, uint16_t count)
+{
+ writew(count, jz4740_timer_base + JZ_REG_TIMER_CNT(timer));
+}
+
+static inline uint16_t jz4740_timer_get_count(unsigned int timer)
+{
+ return readw(jz4740_timer_base + JZ_REG_TIMER_CNT(timer));
+}
+
+static inline void jz4740_timer_ack_full(unsigned int timer)
+{
+ writel(JZ_TIMER_IRQ_FULL(timer), jz4740_timer_base + JZ_REG_TIMER_FLAG_CLEAR);
+}
+
+static inline void jz4740_timer_irq_full_enable(unsigned int timer)
+{
+ writel(JZ_TIMER_IRQ_FULL(timer), jz4740_timer_base + JZ_REG_TIMER_FLAG_CLEAR);
+ writel(JZ_TIMER_IRQ_FULL(timer), jz4740_timer_base + JZ_REG_TIMER_MASK_CLEAR);
+}
+
+static inline void jz4740_timer_irq_full_disable(unsigned int timer)
+{
+ writel(JZ_TIMER_IRQ_FULL(timer), jz4740_timer_base + JZ_REG_TIMER_MASK_SET);
+}
+
+static inline void jz4740_timer_set_ctrl(unsigned int timer, uint16_t ctrl)
+{
+ writew(ctrl, jz4740_timer_base + JZ_REG_TIMER_CTRL(timer));
+}
+
+static inline uint16_t jz4740_timer_get_ctrl(unsigned int timer)
+{
+ return readw(jz4740_timer_base + JZ_REG_TIMER_CTRL(timer));
+}
+
+#endif
diff --git a/arch/mips/kernel/Makefile b/arch/mips/kernel/Makefile
index 7a6ac501cbb..06f84829978 100644
--- a/arch/mips/kernel/Makefile
+++ b/arch/mips/kernel/Makefile
@@ -76,6 +76,7 @@ obj-$(CONFIG_IRQ_TXX9) += irq_txx9.o
obj-$(CONFIG_IRQ_GT641XX) += irq-gt641xx.o
obj-$(CONFIG_IRQ_GIC) += irq-gic.o
+obj-$(CONFIG_KPROBES) += kprobes.o
obj-$(CONFIG_32BIT) += scall32-o32.o
obj-$(CONFIG_64BIT) += scall64-64.o
obj-$(CONFIG_MIPS32_COMPAT) += linux32.o ptrace32.o signal32.o
@@ -101,6 +102,4 @@ obj-$(CONFIG_HAVE_STD_PC_SERIAL_PORT) += 8250-platform.o
obj-$(CONFIG_MIPS_CPUFREQ) += cpufreq/
-EXTRA_CFLAGS += -Werror
-
CPPFLAGS_vmlinux.lds := $(KBUILD_CFLAGS)
diff --git a/arch/mips/kernel/asm-offsets.c b/arch/mips/kernel/asm-offsets.c
index ca6c83218ca..6b30fb2caa6 100644
--- a/arch/mips/kernel/asm-offsets.c
+++ b/arch/mips/kernel/asm-offsets.c
@@ -126,7 +126,6 @@ void output_thread_defines(void)
thread.cp0_baduaddr);
OFFSET(THREAD_ECODE, task_struct, \
thread.error_code);
- OFFSET(THREAD_TRAPNO, task_struct, thread.trap_no);
OFFSET(THREAD_TRAMP, task_struct, \
thread.irix_trampoline);
OFFSET(THREAD_OLDCTX, task_struct, \
diff --git a/arch/mips/kernel/cevt-r4k.c b/arch/mips/kernel/cevt-r4k.c
index 0b2450ceb13..2a4d50ff5e2 100644
--- a/arch/mips/kernel/cevt-r4k.c
+++ b/arch/mips/kernel/cevt-r4k.c
@@ -163,7 +163,6 @@ int c0_compare_int_usable(void)
int __cpuinit r4k_clockevent_init(void)
{
- uint64_t mips_freq = mips_hpt_frequency;
unsigned int cpu = smp_processor_id();
struct clock_event_device *cd;
unsigned int irq;
@@ -188,9 +187,9 @@ int __cpuinit r4k_clockevent_init(void)
cd->name = "MIPS";
cd->features = CLOCK_EVT_FEAT_ONESHOT;
+ clockevent_set_clock(cd, mips_hpt_frequency);
+
/* Calculate the min / max delta */
- cd->mult = div_sc((unsigned long) mips_freq, NSEC_PER_SEC, 32);
- cd->shift = 32;
cd->max_delta_ns = clockevent_delta2ns(0x7fffffff, cd);
cd->min_delta_ns = clockevent_delta2ns(0x300, cd);
diff --git a/arch/mips/kernel/cpu-bugs64.c b/arch/mips/kernel/cpu-bugs64.c
index 408d0a07b3a..b8bb8ba6086 100644
--- a/arch/mips/kernel/cpu-bugs64.c
+++ b/arch/mips/kernel/cpu-bugs64.c
@@ -239,7 +239,7 @@ static inline void check_daddi(void)
panic(bug64hit, !DADDI_WAR ? daddiwar : nowar);
}
-int daddiu_bug __cpuinitdata = -1;
+int daddiu_bug = -1;
static inline void check_daddiu(void)
{
diff --git a/arch/mips/kernel/cpu-probe.c b/arch/mips/kernel/cpu-probe.c
index 3562b854f2c..b1b304ea212 100644
--- a/arch/mips/kernel/cpu-probe.c
+++ b/arch/mips/kernel/cpu-probe.c
@@ -187,6 +187,7 @@ void __init check_wait(void)
case CPU_BCM6358:
case CPU_CAVIUM_OCTEON:
case CPU_CAVIUM_OCTEON_PLUS:
+ case CPU_JZRISC:
cpu_wait = r4k_wait;
break;
@@ -760,6 +761,9 @@ static void __cpuinit decode_configs(struct cpuinfo_mips *c)
ok = decode_config4(c);
mips_probe_watch_registers(c);
+
+ if (cpu_has_mips_r2)
+ c->core = read_c0_ebase() & 0x3ff;
}
static inline void cpu_probe_mips(struct cpuinfo_mips *c, unsigned int cpu)
@@ -956,6 +960,22 @@ platform:
}
}
+static inline void cpu_probe_ingenic(struct cpuinfo_mips *c, unsigned int cpu)
+{
+ decode_configs(c);
+ /* JZRISC does not implement the CP0 counter. */
+ c->options &= ~MIPS_CPU_COUNTER;
+ switch (c->processor_id & 0xff00) {
+ case PRID_IMP_JZRISC:
+ c->cputype = CPU_JZRISC;
+ __cpu_name[cpu] = "Ingenic JZRISC";
+ break;
+ default:
+ panic("Unknown Ingenic Processor ID!");
+ break;
+ }
+}
+
const char *__cpu_name[NR_CPUS];
const char *__elf_platform;
@@ -994,6 +1014,9 @@ __cpuinit void cpu_probe(void)
case PRID_COMP_CAVIUM:
cpu_probe_cavium(c, cpu);
break;
+ case PRID_COMP_INGENIC:
+ cpu_probe_ingenic(c, cpu);
+ break;
}
BUG_ON(!__cpu_name[cpu]);
diff --git a/arch/mips/kernel/kgdb.c b/arch/mips/kernel/kgdb.c
index 9b78ff6e9b8..1f4e2fa6414 100644
--- a/arch/mips/kernel/kgdb.c
+++ b/arch/mips/kernel/kgdb.c
@@ -50,6 +50,151 @@ static struct hard_trap_info {
{ 0, 0} /* Must be last */
};
+struct dbg_reg_def_t dbg_reg_def[DBG_MAX_REG_NUM] =
+{
+ { "zero", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[0]) },
+ { "at", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[1]) },
+ { "v0", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[2]) },
+ { "v1", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[3]) },
+ { "a0", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[4]) },
+ { "a1", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[5]) },
+ { "a2", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[6]) },
+ { "a3", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[7]) },
+ { "t0", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[8]) },
+ { "t1", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[9]) },
+ { "t2", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[10]) },
+ { "t3", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[11]) },
+ { "t4", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[12]) },
+ { "t5", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[13]) },
+ { "t6", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[14]) },
+ { "t7", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[15]) },
+ { "s0", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[16]) },
+ { "s1", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[17]) },
+ { "s2", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[18]) },
+ { "s3", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[19]) },
+ { "s4", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[20]) },
+ { "s5", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[21]) },
+ { "s6", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[22]) },
+ { "s7", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[23]) },
+ { "t8", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[24]) },
+ { "t9", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[25]) },
+ { "k0", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[26]) },
+ { "k1", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[27]) },
+ { "gp", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[28]) },
+ { "sp", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[29]) },
+ { "s8", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[30]) },
+ { "ra", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[31]) },
+ { "sr", GDB_SIZEOF_REG, offsetof(struct pt_regs, cp0_status) },
+ { "lo", GDB_SIZEOF_REG, offsetof(struct pt_regs, lo) },
+ { "hi", GDB_SIZEOF_REG, offsetof(struct pt_regs, hi) },
+ { "bad", GDB_SIZEOF_REG, offsetof(struct pt_regs, cp0_badvaddr) },
+ { "cause", GDB_SIZEOF_REG, offsetof(struct pt_regs, cp0_cause) },
+ { "pc", GDB_SIZEOF_REG, offsetof(struct pt_regs, cp0_epc) },
+ { "f0", GDB_SIZEOF_REG, 0 },
+ { "f1", GDB_SIZEOF_REG, 1 },
+ { "f2", GDB_SIZEOF_REG, 2 },
+ { "f3", GDB_SIZEOF_REG, 3 },
+ { "f4", GDB_SIZEOF_REG, 4 },
+ { "f5", GDB_SIZEOF_REG, 5 },
+ { "f6", GDB_SIZEOF_REG, 6 },
+ { "f7", GDB_SIZEOF_REG, 7 },
+ { "f8", GDB_SIZEOF_REG, 8 },
+ { "f9", GDB_SIZEOF_REG, 9 },
+ { "f10", GDB_SIZEOF_REG, 10 },
+ { "f11", GDB_SIZEOF_REG, 11 },
+ { "f12", GDB_SIZEOF_REG, 12 },
+ { "f13", GDB_SIZEOF_REG, 13 },
+ { "f14", GDB_SIZEOF_REG, 14 },
+ { "f15", GDB_SIZEOF_REG, 15 },
+ { "f16", GDB_SIZEOF_REG, 16 },
+ { "f17", GDB_SIZEOF_REG, 17 },
+ { "f18", GDB_SIZEOF_REG, 18 },
+ { "f19", GDB_SIZEOF_REG, 19 },
+ { "f20", GDB_SIZEOF_REG, 20 },
+ { "f21", GDB_SIZEOF_REG, 21 },
+ { "f22", GDB_SIZEOF_REG, 22 },
+ { "f23", GDB_SIZEOF_REG, 23 },
+ { "f24", GDB_SIZEOF_REG, 24 },
+ { "f25", GDB_SIZEOF_REG, 25 },
+ { "f26", GDB_SIZEOF_REG, 26 },
+ { "f27", GDB_SIZEOF_REG, 27 },
+ { "f28", GDB_SIZEOF_REG, 28 },
+ { "f29", GDB_SIZEOF_REG, 29 },
+ { "f30", GDB_SIZEOF_REG, 30 },
+ { "f31", GDB_SIZEOF_REG, 31 },
+ { "fsr", GDB_SIZEOF_REG, 0 },
+ { "fir", GDB_SIZEOF_REG, 0 },
+};
+
+int dbg_set_reg(int regno, void *mem, struct pt_regs *regs)
+{
+ int fp_reg;
+
+ if (regno < 0 || regno >= DBG_MAX_REG_NUM)
+ return -EINVAL;
+
+ if (dbg_reg_def[regno].offset != -1 && regno < 38) {
+ memcpy((void *)regs + dbg_reg_def[regno].offset, mem,
+ dbg_reg_def[regno].size);
+ } else if (current && dbg_reg_def[regno].offset != -1 && regno < 72) {
+ /* FP registers 38 -> 69 */
+ if (!(regs->cp0_status & ST0_CU1))
+ return 0;
+ if (regno == 70) {
+ /* Process the fcr31/fsr (register 70) */
+ memcpy((void *)&current->thread.fpu.fcr31, mem,
+ dbg_reg_def[regno].size);
+ goto out_save;
+ } else if (regno == 71) {
+ /* Ignore the fir (register 71) */
+ goto out_save;
+ }
+ fp_reg = dbg_reg_def[regno].offset;
+ memcpy((void *)&current->thread.fpu.fpr[fp_reg], mem,
+ dbg_reg_def[regno].size);
+out_save:
+ restore_fp(current);
+ }
+
+ return 0;
+}
+
+char *dbg_get_reg(int regno, void *mem, struct pt_regs *regs)
+{
+ int fp_reg;
+
+ if (regno >= DBG_MAX_REG_NUM || regno < 0)
+ return NULL;
+
+ if (dbg_reg_def[regno].offset != -1 && regno < 38) {
+ /* First 38 registers */
+ memcpy(mem, (void *)regs + dbg_reg_def[regno].offset,
+ dbg_reg_def[regno].size);
+ } else if (current && dbg_reg_def[regno].offset != -1 && regno < 72) {
+ /* FP registers 38 -> 69 */
+ if (!(regs->cp0_status & ST0_CU1))
+ goto out;
+ save_fp(current);
+ if (regno == 70) {
+ /* Process the fcr31/fsr (register 70) */
+ memcpy(mem, (void *)&current->thread.fpu.fcr31,
+ dbg_reg_def[regno].size);
+ goto out;
+ } else if (regno == 71) {
+ /* Ignore the fir (register 71) */
+ memset(mem, 0, dbg_reg_def[regno].size);
+ goto out;
+ }
+ fp_reg = dbg_reg_def[regno].offset;
+ memcpy(mem, (void *)&current->thread.fpu.fpr[fp_reg],
+ dbg_reg_def[regno].size);
+ }
+
+out:
+ return dbg_reg_def[regno].name;
+
+}
+
void arch_kgdb_breakpoint(void)
{
__asm__ __volatile__(
@@ -84,64 +229,6 @@ static int compute_signal(int tt)
return SIGHUP; /* default for things we don't know about */
}
-void pt_regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *regs)
-{
- int reg;
-
-#if (KGDB_GDB_REG_SIZE == 32)
- u32 *ptr = (u32 *)gdb_regs;
-#else
- u64 *ptr = (u64 *)gdb_regs;
-#endif
-
- for (reg = 0; reg < 32; reg++)
- *(ptr++) = regs->regs[reg];
-
- *(ptr++) = regs->cp0_status;
- *(ptr++) = regs->lo;
- *(ptr++) = regs->hi;
- *(ptr++) = regs->cp0_badvaddr;
- *(ptr++) = regs->cp0_cause;
- *(ptr++) = regs->cp0_epc;
-
- /* FP REGS */
- if (!(current && (regs->cp0_status & ST0_CU1)))
- return;
-
- save_fp(current);
- for (reg = 0; reg < 32; reg++)
- *(ptr++) = current->thread.fpu.fpr[reg];
-}
-
-void gdb_regs_to_pt_regs(unsigned long *gdb_regs, struct pt_regs *regs)
-{
- int reg;
-
-#if (KGDB_GDB_REG_SIZE == 32)
- const u32 *ptr = (u32 *)gdb_regs;
-#else
- const u64 *ptr = (u64 *)gdb_regs;
-#endif
-
- for (reg = 0; reg < 32; reg++)
- regs->regs[reg] = *(ptr++);
-
- regs->cp0_status = *(ptr++);
- regs->lo = *(ptr++);
- regs->hi = *(ptr++);
- regs->cp0_badvaddr = *(ptr++);
- regs->cp0_cause = *(ptr++);
- regs->cp0_epc = *(ptr++);
-
- /* FP REGS from current */
- if (!(current && (regs->cp0_status & ST0_CU1)))
- return;
-
- for (reg = 0; reg < 32; reg++)
- current->thread.fpu.fpr[reg] = *(ptr++);
- restore_fp(current);
-}
-
/*
* Similar to regs_to_gdb_regs() except that process is sleeping and so
* we may not be able to get all the info.
@@ -242,7 +329,7 @@ static struct notifier_block kgdb_notifier = {
};
/*
- * Handle the 's' and 'c' commands
+ * Handle the 'c' command
*/
int kgdb_arch_handle_exception(int vector, int signo, int err_code,
char *remcom_in_buffer, char *remcom_out_buffer,
@@ -250,20 +337,14 @@ int kgdb_arch_handle_exception(int vector, int signo, int err_code,
{
char *ptr;
unsigned long address;
- int cpu = smp_processor_id();
switch (remcom_in_buffer[0]) {
- case 's':
case 'c':
/* handle the optional parameter */
ptr = &remcom_in_buffer[1];
if (kgdb_hex2long(&ptr, &address))
regs->cp0_epc = address;
- atomic_set(&kgdb_cpu_doing_single_step, -1);
- if (remcom_in_buffer[0] == 's')
- atomic_set(&kgdb_cpu_doing_single_step, cpu);
-
return 0;
}
diff --git a/arch/mips/kernel/kprobes.c b/arch/mips/kernel/kprobes.c
new file mode 100644
index 00000000000..ee28683fc2a
--- /dev/null
+++ b/arch/mips/kernel/kprobes.c
@@ -0,0 +1,557 @@
+/*
+ * Kernel Probes (KProbes)
+ * arch/mips/kernel/kprobes.c
+ *
+ * Copyright 2006 Sony Corp.
+ * Copyright 2010 Cavium Networks
+ *
+ * Some portions copied from the powerpc version.
+ *
+ * Copyright (C) IBM Corporation, 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; 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/kprobes.h>
+#include <linux/preempt.h>
+#include <linux/kdebug.h>
+#include <linux/slab.h>
+
+#include <asm/ptrace.h>
+#include <asm/break.h>
+#include <asm/inst.h>
+
+static const union mips_instruction breakpoint_insn = {
+ .b_format = {
+ .opcode = spec_op,
+ .code = BRK_KPROBE_BP,
+ .func = break_op
+ }
+};
+
+static const union mips_instruction breakpoint2_insn = {
+ .b_format = {
+ .opcode = spec_op,
+ .code = BRK_KPROBE_SSTEPBP,
+ .func = break_op
+ }
+};
+
+DEFINE_PER_CPU(struct kprobe *, current_kprobe);
+DEFINE_PER_CPU(struct kprobe_ctlblk, kprobe_ctlblk);
+
+static int __kprobes insn_has_delayslot(union mips_instruction insn)
+{
+ switch (insn.i_format.opcode) {
+
+ /*
+ * This group contains:
+ * jr and jalr are in r_format format.
+ */
+ case spec_op:
+ switch (insn.r_format.func) {
+ case jr_op:
+ case jalr_op:
+ break;
+ default:
+ goto insn_ok;
+ }
+
+ /*
+ * This group contains:
+ * bltz_op, bgez_op, bltzl_op, bgezl_op,
+ * bltzal_op, bgezal_op, bltzall_op, bgezall_op.
+ */
+ case bcond_op:
+
+ /*
+ * These are unconditional and in j_format.
+ */
+ case jal_op:
+ case j_op:
+
+ /*
+ * These are conditional and in i_format.
+ */
+ case beq_op:
+ case beql_op:
+ case bne_op:
+ case bnel_op:
+ case blez_op:
+ case blezl_op:
+ case bgtz_op:
+ case bgtzl_op:
+
+ /*
+ * These are the FPA/cp1 branch instructions.
+ */
+ case cop1_op:
+
+#ifdef CONFIG_CPU_CAVIUM_OCTEON
+ case lwc2_op: /* This is bbit0 on Octeon */
+ case ldc2_op: /* This is bbit032 on Octeon */
+ case swc2_op: /* This is bbit1 on Octeon */
+ case sdc2_op: /* This is bbit132 on Octeon */
+#endif
+ return 1;
+ default:
+ break;
+ }
+insn_ok:
+ return 0;
+}
+
+int __kprobes arch_prepare_kprobe(struct kprobe *p)
+{
+ union mips_instruction insn;
+ union mips_instruction prev_insn;
+ int ret = 0;
+
+ prev_insn = p->addr[-1];
+ insn = p->addr[0];
+
+ if (insn_has_delayslot(insn) || insn_has_delayslot(prev_insn)) {
+ pr_notice("Kprobes for branch and jump instructions are not supported\n");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ /* insn: must be on special executable page on mips. */
+ p->ainsn.insn = get_insn_slot();
+ if (!p->ainsn.insn) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ /*
+ * In the kprobe->ainsn.insn[] array we store the original
+ * instruction at index zero and a break trap instruction at
+ * index one.
+ */
+
+ memcpy(&p->ainsn.insn[0], p->addr, sizeof(kprobe_opcode_t));
+ p->ainsn.insn[1] = breakpoint2_insn;
+ p->opcode = *p->addr;
+
+out:
+ return ret;
+}
+
+void __kprobes arch_arm_kprobe(struct kprobe *p)
+{
+ *p->addr = breakpoint_insn;
+ flush_insn_slot(p);
+}
+
+void __kprobes arch_disarm_kprobe(struct kprobe *p)
+{
+ *p->addr = p->opcode;
+ flush_insn_slot(p);
+}
+
+void __kprobes arch_remove_kprobe(struct kprobe *p)
+{
+ free_insn_slot(p->ainsn.insn, 0);
+}
+
+static void save_previous_kprobe(struct kprobe_ctlblk *kcb)
+{
+ kcb->prev_kprobe.kp = kprobe_running();
+ kcb->prev_kprobe.status = kcb->kprobe_status;
+ kcb->prev_kprobe.old_SR = kcb->kprobe_old_SR;
+ kcb->prev_kprobe.saved_SR = kcb->kprobe_saved_SR;
+ kcb->prev_kprobe.saved_epc = kcb->kprobe_saved_epc;
+}
+
+static void restore_previous_kprobe(struct kprobe_ctlblk *kcb)
+{
+ __get_cpu_var(current_kprobe) = kcb->prev_kprobe.kp;
+ kcb->kprobe_status = kcb->prev_kprobe.status;
+ kcb->kprobe_old_SR = kcb->prev_kprobe.old_SR;
+ kcb->kprobe_saved_SR = kcb->prev_kprobe.saved_SR;
+ kcb->kprobe_saved_epc = kcb->prev_kprobe.saved_epc;
+}
+
+static void set_current_kprobe(struct kprobe *p, struct pt_regs *regs,
+ struct kprobe_ctlblk *kcb)
+{
+ __get_cpu_var(current_kprobe) = p;
+ kcb->kprobe_saved_SR = kcb->kprobe_old_SR = (regs->cp0_status & ST0_IE);
+ kcb->kprobe_saved_epc = regs->cp0_epc;
+}
+
+static void prepare_singlestep(struct kprobe *p, struct pt_regs *regs)
+{
+ regs->cp0_status &= ~ST0_IE;
+
+ /* single step inline if the instruction is a break */
+ if (p->opcode.word == breakpoint_insn.word ||
+ p->opcode.word == breakpoint2_insn.word)
+ regs->cp0_epc = (unsigned long)p->addr;
+ else
+ regs->cp0_epc = (unsigned long)&p->ainsn.insn[0];
+}
+
+static int __kprobes kprobe_handler(struct pt_regs *regs)
+{
+ struct kprobe *p;
+ int ret = 0;
+ kprobe_opcode_t *addr;
+ struct kprobe_ctlblk *kcb;
+
+ addr = (kprobe_opcode_t *) regs->cp0_epc;
+
+ /*
+ * We don't want to be preempted for the entire
+ * duration of kprobe processing
+ */
+ preempt_disable();
+ kcb = get_kprobe_ctlblk();
+
+ /* Check we're not actually recursing */
+ if (kprobe_running()) {
+ p = get_kprobe(addr);
+ if (p) {
+ if (kcb->kprobe_status == KPROBE_HIT_SS &&
+ p->ainsn.insn->word == breakpoint_insn.word) {
+ regs->cp0_status &= ~ST0_IE;
+ regs->cp0_status |= kcb->kprobe_saved_SR;
+ goto no_kprobe;
+ }
+ /*
+ * We have reentered the kprobe_handler(), since
+ * another probe was hit while within the handler.
+ * We here save the original kprobes variables and
+ * just single step on the instruction of the new probe
+ * without calling any user handlers.
+ */
+ save_previous_kprobe(kcb);
+ set_current_kprobe(p, regs, kcb);
+ kprobes_inc_nmissed_count(p);
+ prepare_singlestep(p, regs);
+ kcb->kprobe_status = KPROBE_REENTER;
+ return 1;
+ } else {
+ if (addr->word != breakpoint_insn.word) {
+ /*
+ * The breakpoint instruction was removed by
+ * another cpu right after we hit, no further
+ * handling of this interrupt is appropriate
+ */
+ ret = 1;
+ goto no_kprobe;
+ }
+ p = __get_cpu_var(current_kprobe);
+ if (p->break_handler && p->break_handler(p, regs))
+ goto ss_probe;
+ }
+ goto no_kprobe;
+ }
+
+ p = get_kprobe(addr);
+ if (!p) {
+ if (addr->word != breakpoint_insn.word) {
+ /*
+ * The breakpoint instruction was removed right
+ * after we hit it. Another cpu has removed
+ * either a probepoint or a debugger breakpoint
+ * at this address. In either case, no further
+ * handling of this interrupt is appropriate.
+ */
+ ret = 1;
+ }
+ /* Not one of ours: let kernel handle it */
+ goto no_kprobe;
+ }
+
+ set_current_kprobe(p, regs, kcb);
+ kcb->kprobe_status = KPROBE_HIT_ACTIVE;
+
+ if (p->pre_handler && p->pre_handler(p, regs)) {
+ /* handler has already set things up, so skip ss setup */
+ return 1;
+ }
+
+ss_probe:
+ prepare_singlestep(p, regs);
+ kcb->kprobe_status = KPROBE_HIT_SS;
+ return 1;
+
+no_kprobe:
+ preempt_enable_no_resched();
+ return ret;
+
+}
+
+/*
+ * Called after single-stepping. p->addr is the address of the
+ * instruction whose first byte has been replaced by the "break 0"
+ * instruction. To avoid the SMP problems that can occur when we
+ * temporarily put back the original opcode to single-step, we
+ * single-stepped a copy of the instruction. The address of this
+ * copy is p->ainsn.insn.
+ *
+ * This function prepares to return from the post-single-step
+ * breakpoint trap.
+ */
+static void __kprobes resume_execution(struct kprobe *p,
+ struct pt_regs *regs,
+ struct kprobe_ctlblk *kcb)
+{
+ unsigned long orig_epc = kcb->kprobe_saved_epc;
+ regs->cp0_epc = orig_epc + 4;
+}
+
+static inline int post_kprobe_handler(struct pt_regs *regs)
+{
+ struct kprobe *cur = kprobe_running();
+ struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
+
+ if (!cur)
+ return 0;
+
+ if ((kcb->kprobe_status != KPROBE_REENTER) && cur->post_handler) {
+ kcb->kprobe_status = KPROBE_HIT_SSDONE;
+ cur->post_handler(cur, regs, 0);
+ }
+
+ resume_execution(cur, regs, kcb);
+
+ regs->cp0_status |= kcb->kprobe_saved_SR;
+
+ /* Restore back the original saved kprobes variables and continue. */
+ if (kcb->kprobe_status == KPROBE_REENTER) {
+ restore_previous_kprobe(kcb);
+ goto out;
+ }
+ reset_current_kprobe();
+out:
+ preempt_enable_no_resched();
+
+ return 1;
+}
+
+static inline int kprobe_fault_handler(struct pt_regs *regs, int trapnr)
+{
+ struct kprobe *cur = kprobe_running();
+ struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
+
+ if (cur->fault_handler && cur->fault_handler(cur, regs, trapnr))
+ return 1;
+
+ if (kcb->kprobe_status & KPROBE_HIT_SS) {
+ resume_execution(cur, regs, kcb);
+ regs->cp0_status |= kcb->kprobe_old_SR;
+
+ reset_current_kprobe();
+ preempt_enable_no_resched();
+ }
+ return 0;
+}
+
+/*
+ * Wrapper routine for handling exceptions.
+ */
+int __kprobes kprobe_exceptions_notify(struct notifier_block *self,
+ unsigned long val, void *data)
+{
+
+ struct die_args *args = (struct die_args *)data;
+ int ret = NOTIFY_DONE;
+
+ switch (val) {
+ case DIE_BREAK:
+ if (kprobe_handler(args->regs))
+ ret = NOTIFY_STOP;
+ break;
+ case DIE_SSTEPBP:
+ if (post_kprobe_handler(args->regs))
+ ret = NOTIFY_STOP;
+ break;
+
+ case DIE_PAGE_FAULT:
+ /* kprobe_running() needs smp_processor_id() */
+ preempt_disable();
+
+ if (kprobe_running()
+ && kprobe_fault_handler(args->regs, args->trapnr))
+ ret = NOTIFY_STOP;
+ preempt_enable();
+ break;
+ default:
+ break;
+ }
+ return ret;
+}
+
+int __kprobes setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs)
+{
+ struct jprobe *jp = container_of(p, struct jprobe, kp);
+ struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
+
+ kcb->jprobe_saved_regs = *regs;
+ kcb->jprobe_saved_sp = regs->regs[29];
+
+ memcpy(kcb->jprobes_stack, (void *)kcb->jprobe_saved_sp,
+ MIN_JPROBES_STACK_SIZE(kcb->jprobe_saved_sp));
+
+ regs->cp0_epc = (unsigned long)(jp->entry);
+
+ return 1;
+}
+
+/* Defined in the inline asm below. */
+void jprobe_return_end(void);
+
+void __kprobes jprobe_return(void)
+{
+ /* Assembler quirk necessitates this '0,code' business. */
+ asm volatile(
+ "break 0,%0\n\t"
+ ".globl jprobe_return_end\n"
+ "jprobe_return_end:\n"
+ : : "n" (BRK_KPROBE_BP) : "memory");
+}
+
+int __kprobes longjmp_break_handler(struct kprobe *p, struct pt_regs *regs)
+{
+ struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
+
+ if (regs->cp0_epc >= (unsigned long)jprobe_return &&
+ regs->cp0_epc <= (unsigned long)jprobe_return_end) {
+ *regs = kcb->jprobe_saved_regs;
+ memcpy((void *)kcb->jprobe_saved_sp, kcb->jprobes_stack,
+ MIN_JPROBES_STACK_SIZE(kcb->jprobe_saved_sp));
+ preempt_enable_no_resched();
+
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * Function return probe trampoline:
+ * - init_kprobes() establishes a probepoint here
+ * - When the probed function returns, this probe causes the
+ * handlers to fire
+ */
+static void __used kretprobe_trampoline_holder(void)
+{
+ asm volatile(
+ ".set push\n\t"
+ /* Keep the assembler from reordering and placing JR here. */
+ ".set noreorder\n\t"
+ "nop\n\t"
+ ".global kretprobe_trampoline\n"
+ "kretprobe_trampoline:\n\t"
+ "nop\n\t"
+ ".set pop"
+ : : : "memory");
+}
+
+void kretprobe_trampoline(void);
+
+void __kprobes arch_prepare_kretprobe(struct kretprobe_instance *ri,
+ struct pt_regs *regs)
+{
+ ri->ret_addr = (kprobe_opcode_t *) regs->regs[31];
+
+ /* Replace the return addr with trampoline addr */
+ regs->regs[31] = (unsigned long)kretprobe_trampoline;
+}
+
+/*
+ * Called when the probe at kretprobe trampoline is hit
+ */
+static int __kprobes trampoline_probe_handler(struct kprobe *p,
+ struct pt_regs *regs)
+{
+ struct kretprobe_instance *ri = NULL;
+ struct hlist_head *head, empty_rp;
+ struct hlist_node *node, *tmp;
+ unsigned long flags, orig_ret_address = 0;
+ unsigned long trampoline_address = (unsigned long)kretprobe_trampoline;
+
+ INIT_HLIST_HEAD(&empty_rp);
+ kretprobe_hash_lock(current, &head, &flags);
+
+ /*
+ * It is possible to have multiple instances associated with a given
+ * task either because an multiple functions in the call path
+ * have a return probe installed on them, and/or more than one return
+ * return probe was registered for a target function.
+ *
+ * We can handle this because:
+ * - instances are always inserted at the head of the list
+ * - when multiple return probes are registered for the same
+ * function, the first instance's ret_addr will point to the
+ * real return address, and all the rest will point to
+ * kretprobe_trampoline
+ */
+ hlist_for_each_entry_safe(ri, node, tmp, head, hlist) {
+ if (ri->task != current)
+ /* another task is sharing our hash bucket */
+ continue;
+
+ if (ri->rp && ri->rp->handler)
+ ri->rp->handler(ri, regs);
+
+ orig_ret_address = (unsigned long)ri->ret_addr;
+ recycle_rp_inst(ri, &empty_rp);
+
+ if (orig_ret_address != trampoline_address)
+ /*
+ * This is the real return address. Any other
+ * instances associated with this task are for
+ * other calls deeper on the call stack
+ */
+ break;
+ }
+
+ kretprobe_assert(ri, orig_ret_address, trampoline_address);
+ instruction_pointer(regs) = orig_ret_address;
+
+ reset_current_kprobe();
+ kretprobe_hash_unlock(current, &flags);
+ preempt_enable_no_resched();
+
+ hlist_for_each_entry_safe(ri, node, tmp, &empty_rp, hlist) {
+ hlist_del(&ri->hlist);
+ kfree(ri);
+ }
+ /*
+ * By returning a non-zero value, we are telling
+ * kprobe_handler() that we don't want the post_handler
+ * to run (and have re-enabled preemption)
+ */
+ return 1;
+}
+
+int __kprobes arch_trampoline_kprobe(struct kprobe *p)
+{
+ if (p->addr == (kprobe_opcode_t *)kretprobe_trampoline)
+ return 1;
+
+ return 0;
+}
+
+static struct kprobe trampoline_p = {
+ .addr = (kprobe_opcode_t *)kretprobe_trampoline,
+ .pre_handler = trampoline_probe_handler
+};
+
+int __init arch_init_kprobes(void)
+{
+ return register_kprobe(&trampoline_p);
+}
diff --git a/arch/mips/kernel/mcount.S b/arch/mips/kernel/mcount.S
index 6bfcb7a00ec..4c968e7efb7 100644
--- a/arch/mips/kernel/mcount.S
+++ b/arch/mips/kernel/mcount.S
@@ -165,12 +165,12 @@ NESTED(ftrace_graph_caller, PT_SIZE, ra)
/* arg3: Get frame pointer of current stack */
#ifdef CONFIG_FRAME_POINTER
- move a2, fp
+ move a2, fp
#else /* ! CONFIG_FRAME_POINTER */
#ifdef CONFIG_64BIT
- PTR_LA a2, PT_SIZE(sp)
+ PTR_LA a2, PT_SIZE(sp)
#else
- PTR_LA a2, (PT_SIZE+8)(sp)
+ PTR_LA a2, (PT_SIZE+8)(sp)
#endif
#endif
diff --git a/arch/mips/kernel/scall64-n32.S b/arch/mips/kernel/scall64-n32.S
index a4faceea9d8..a3d66137731 100644
--- a/arch/mips/kernel/scall64-n32.S
+++ b/arch/mips/kernel/scall64-n32.S
@@ -400,22 +400,22 @@ EXPORT(sysn32_call_table)
PTR sys_ioprio_set
PTR sys_ioprio_get
PTR compat_sys_utimensat
- PTR compat_sys_signalfd /* 5280 */
+ PTR compat_sys_signalfd /* 6280 */
PTR sys_ni_syscall
PTR sys_eventfd
PTR sys_fallocate
PTR sys_timerfd_create
- PTR compat_sys_timerfd_gettime /* 5285 */
+ PTR compat_sys_timerfd_gettime /* 6285 */
PTR compat_sys_timerfd_settime
PTR sys_signalfd4
PTR sys_eventfd2
PTR sys_epoll_create1
- PTR sys_dup3 /* 5290 */
+ PTR sys_dup3 /* 6290 */
PTR sys_pipe2
PTR sys_inotify_init1
PTR sys_preadv
PTR sys_pwritev
- PTR compat_sys_rt_tgsigqueueinfo /* 5295 */
+ PTR compat_sys_rt_tgsigqueueinfo /* 6295 */
PTR sys_perf_event_open
PTR sys_accept4
PTR compat_sys_recvmmsg
diff --git a/arch/mips/kernel/smp.c b/arch/mips/kernel/smp.c
index 6cdca1956b7..383aeb95cb4 100644
--- a/arch/mips/kernel/smp.c
+++ b/arch/mips/kernel/smp.c
@@ -47,8 +47,12 @@
#endif /* CONFIG_MIPS_MT_SMTC */
volatile cpumask_t cpu_callin_map; /* Bitmask of started secondaries */
+
int __cpu_number_map[NR_CPUS]; /* Map physical to logical */
+EXPORT_SYMBOL(__cpu_number_map);
+
int __cpu_logical_map[NR_CPUS]; /* Map logical to physical */
+EXPORT_SYMBOL(__cpu_logical_map);
/* Number of TCs (or siblings in Intel speak) per CPU core */
int smp_num_siblings = 1;
diff --git a/arch/mips/kernel/smtc.c b/arch/mips/kernel/smtc.c
index a95dea5459c..cfeb2c15589 100644
--- a/arch/mips/kernel/smtc.c
+++ b/arch/mips/kernel/smtc.c
@@ -975,8 +975,7 @@ void ipi_decode(struct smtc_ipi *pipi)
ipi_call_interrupt();
break;
default:
- printk("Impossible SMTC IPI Argument 0x%x\n",
- (int)arg_copy);
+ printk("Impossible SMTC IPI Argument %p\n", arg_copy);
break;
}
break;
diff --git a/arch/mips/kernel/syscall.c b/arch/mips/kernel/syscall.c
index dd81b0f8751..58bab2ef257 100644
--- a/arch/mips/kernel/syscall.c
+++ b/arch/mips/kernel/syscall.c
@@ -29,6 +29,8 @@
#include <linux/ipc.h>
#include <linux/uaccess.h>
#include <linux/slab.h>
+#include <linux/random.h>
+#include <linux/elf.h>
#include <asm/asm.h>
#include <asm/branch.h>
@@ -116,7 +118,7 @@ unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr,
(!vmm || addr + len <= vmm->vm_start))
return addr;
}
- addr = TASK_UNMAPPED_BASE;
+ addr = current->mm->mmap_base;
if (do_color_align)
addr = COLOUR_ALIGN(addr, pgoff);
else
@@ -134,6 +136,51 @@ unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr,
}
}
+void arch_pick_mmap_layout(struct mm_struct *mm)
+{
+ unsigned long random_factor = 0UL;
+
+ if (current->flags & PF_RANDOMIZE) {
+ random_factor = get_random_int();
+ random_factor = random_factor << PAGE_SHIFT;
+ if (TASK_IS_32BIT_ADDR)
+ random_factor &= 0xfffffful;
+ else
+ random_factor &= 0xffffffful;
+ }
+
+ mm->mmap_base = TASK_UNMAPPED_BASE + random_factor;
+ mm->get_unmapped_area = arch_get_unmapped_area;
+ mm->unmap_area = arch_unmap_area;
+}
+
+static inline unsigned long brk_rnd(void)
+{
+ unsigned long rnd = get_random_int();
+
+ rnd = rnd << PAGE_SHIFT;
+ /* 8MB for 32bit, 256MB for 64bit */
+ if (TASK_IS_32BIT_ADDR)
+ rnd = rnd & 0x7ffffful;
+ else
+ rnd = rnd & 0xffffffful;
+
+ return rnd;
+}
+
+unsigned long arch_randomize_brk(struct mm_struct *mm)
+{
+ unsigned long base = mm->brk;
+ unsigned long ret;
+
+ ret = PAGE_ALIGN(base + brk_rnd());
+
+ if (ret < mm->brk)
+ return mm->brk;
+
+ return ret;
+}
+
SYSCALL_DEFINE6(mips_mmap, unsigned long, addr, unsigned long, len,
unsigned long, prot, unsigned long, flags, unsigned long,
fd, off_t, offset)
diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c
index 852780868fb..03ec0019032 100644
--- a/arch/mips/kernel/traps.c
+++ b/arch/mips/kernel/traps.c
@@ -25,6 +25,7 @@
#include <linux/ptrace.h>
#include <linux/kgdb.h>
#include <linux/kdebug.h>
+#include <linux/kprobes.h>
#include <linux/notifier.h>
#include <linux/kdb.h>
@@ -334,7 +335,7 @@ void show_regs(struct pt_regs *regs)
__show_regs((struct pt_regs *)regs);
}
-void show_registers(const struct pt_regs *regs)
+void show_registers(struct pt_regs *regs)
{
const int field = 2 * sizeof(unsigned long);
@@ -356,9 +357,14 @@ void show_registers(const struct pt_regs *regs)
printk("\n");
}
+static int regs_to_trapnr(struct pt_regs *regs)
+{
+ return (regs->cp0_cause >> 2) & 0x1f;
+}
+
static DEFINE_SPINLOCK(die_lock);
-void __noreturn die(const char * str, struct pt_regs * regs)
+void __noreturn die(const char *str, struct pt_regs *regs)
{
static int die_counter;
int sig = SIGSEGV;
@@ -366,7 +372,7 @@ void __noreturn die(const char * str, struct pt_regs * regs)
unsigned long dvpret = dvpe();
#endif /* CONFIG_MIPS_MT_SMTC */
- notify_die(DIE_OOPS, str, (struct pt_regs *)regs, SIGSEGV, 0, 0);
+ notify_die(DIE_OOPS, str, regs, 0, regs_to_trapnr(regs), SIGSEGV);
console_verbose();
spin_lock_irq(&die_lock);
@@ -375,7 +381,7 @@ void __noreturn die(const char * str, struct pt_regs * regs)
mips_mt_regdump(dvpret);
#endif /* CONFIG_MIPS_MT_SMTC */
- if (notify_die(DIE_OOPS, str, regs, 0, current->thread.trap_no, SIGSEGV) == NOTIFY_STOP)
+ if (notify_die(DIE_OOPS, str, regs, 0, regs_to_trapnr(regs), SIGSEGV) == NOTIFY_STOP)
sig = 0;
printk("%s[#%d]:\n", str, ++die_counter);
@@ -449,7 +455,7 @@ asmlinkage void do_be(struct pt_regs *regs)
printk(KERN_ALERT "%s bus error, epc == %0*lx, ra == %0*lx\n",
data ? "Data" : "Instruction",
field, regs->cp0_epc, field, regs->regs[31]);
- if (notify_die(DIE_OOPS, "bus error", regs, SIGBUS, 0, 0)
+ if (notify_die(DIE_OOPS, "bus error", regs, 0, regs_to_trapnr(regs), SIGBUS)
== NOTIFY_STOP)
return;
@@ -650,7 +656,7 @@ asmlinkage void do_fpe(struct pt_regs *regs, unsigned long fcr31)
{
siginfo_t info;
- if (notify_die(DIE_FP, "FP exception", regs, SIGFPE, 0, 0)
+ if (notify_die(DIE_FP, "FP exception", regs, 0, regs_to_trapnr(regs), SIGFPE)
== NOTIFY_STOP)
return;
die_if_kernel("FP exception in kernel code", regs);
@@ -713,11 +719,11 @@ static void do_trap_or_bp(struct pt_regs *regs, unsigned int code,
char b[40];
#ifdef CONFIG_KGDB_LOW_LEVEL_TRAP
- if (kgdb_ll_trap(DIE_TRAP, str, regs, code, 0, 0) == NOTIFY_STOP)
+ if (kgdb_ll_trap(DIE_TRAP, str, regs, code, regs_to_trapnr(regs), SIGTRAP) == NOTIFY_STOP)
return;
#endif /* CONFIG_KGDB_LOW_LEVEL_TRAP */
- if (notify_die(DIE_TRAP, str, regs, code, 0, 0) == NOTIFY_STOP)
+ if (notify_die(DIE_TRAP, str, regs, code, regs_to_trapnr(regs), SIGTRAP) == NOTIFY_STOP)
return;
/*
@@ -783,6 +789,25 @@ asmlinkage void do_bp(struct pt_regs *regs)
if (bcode >= (1 << 10))
bcode >>= 10;
+ /*
+ * notify the kprobe handlers, if instruction is likely to
+ * pertain to them.
+ */
+ switch (bcode) {
+ case BRK_KPROBE_BP:
+ if (notify_die(DIE_BREAK, "debug", regs, bcode, regs_to_trapnr(regs), SIGTRAP) == NOTIFY_STOP)
+ return;
+ else
+ break;
+ case BRK_KPROBE_SSTEPBP:
+ if (notify_die(DIE_SSTEPBP, "single_step", regs, bcode, regs_to_trapnr(regs), SIGTRAP) == NOTIFY_STOP)
+ return;
+ else
+ break;
+ default:
+ break;
+ }
+
do_trap_or_bp(regs, bcode, "Break");
return;
@@ -815,7 +840,7 @@ asmlinkage void do_ri(struct pt_regs *regs)
unsigned int opcode = 0;
int status = -1;
- if (notify_die(DIE_RI, "RI Fault", regs, SIGSEGV, 0, 0)
+ if (notify_die(DIE_RI, "RI Fault", regs, 0, regs_to_trapnr(regs), SIGILL)
== NOTIFY_STOP)
return;
@@ -907,11 +932,6 @@ static int default_cu2_call(struct notifier_block *nfb, unsigned long action,
return NOTIFY_OK;
}
-static struct notifier_block default_cu2_notifier = {
- .notifier_call = default_cu2_call,
- .priority = 0x80000000, /* Run last */
-};
-
asmlinkage void do_cpu(struct pt_regs *regs)
{
unsigned int __user *epc;
@@ -1734,5 +1754,5 @@ void __init trap_init(void)
sort_extable(__start___dbe_table, __stop___dbe_table);
- register_cu2_notifier(&default_cu2_notifier);
+ cu2_notifier(default_cu2_call, 0x80000000); /* Run last */
}
diff --git a/arch/mips/lasat/Makefile b/arch/mips/lasat/Makefile
index 33791609fe9..9cc4e4db8b9 100644
--- a/arch/mips/lasat/Makefile
+++ b/arch/mips/lasat/Makefile
@@ -12,5 +12,3 @@ obj-$(CONFIG_PICVUE_PROC) += picvue_proc.o
clean:
make -C image clean
-
-EXTRA_CFLAGS += -Werror
diff --git a/arch/mips/lasat/Platform b/arch/mips/lasat/Platform
new file mode 100644
index 00000000000..760252828bf
--- /dev/null
+++ b/arch/mips/lasat/Platform
@@ -0,0 +1,7 @@
+#
+# LASAT platforms
+#
+platform-$(CONFIG_LASAT) += lasat/
+cflags-$(CONFIG_LASAT) += \
+ -I$(srctree)/arch/mips/include/asm/mach-lasat
+load-$(CONFIG_LASAT) += 0xffffffff80000000
diff --git a/arch/mips/loongson/Platform b/arch/mips/loongson/Platform
new file mode 100644
index 00000000000..29692e5433b
--- /dev/null
+++ b/arch/mips/loongson/Platform
@@ -0,0 +1,32 @@
+#
+# Loongson Processors' Support
+#
+
+# Only gcc >= 4.4 have Loongson specific support
+cflags-$(CONFIG_CPU_LOONGSON2) += -Wa,--trap
+cflags-$(CONFIG_CPU_LOONGSON2E) += \
+ $(call cc-option,-march=loongson2e,-march=r4600)
+cflags-$(CONFIG_CPU_LOONGSON2F) += \
+ $(call cc-option,-march=loongson2f,-march=r4600)
+# Enable the workarounds for Loongson2f
+ifdef CONFIG_CPU_LOONGSON2F_WORKAROUNDS
+ ifeq ($(call as-option,-Wa$(comma)-mfix-loongson2f-nop,),)
+ $(error only binutils >= 2.20.2 have needed option -mfix-loongson2f-nop)
+ else
+ cflags-$(CONFIG_CPU_NOP_WORKAROUNDS) += -Wa$(comma)-mfix-loongson2f-nop
+ endif
+ ifeq ($(call as-option,-Wa$(comma)-mfix-loongson2f-jump,),)
+ $(error only binutils >= 2.20.2 have needed option -mfix-loongson2f-jump)
+ else
+ cflags-$(CONFIG_CPU_JUMP_WORKAROUNDS) += -Wa$(comma)-mfix-loongson2f-jump
+ endif
+endif
+
+#
+# Loongson Machines' Support
+#
+
+platform-$(CONFIG_MACH_LOONGSON) += loongson/
+cflags-$(CONFIG_MACH_LOONGSON) += -I$(srctree)/arch/mips/include/asm/mach-loongson -mno-branch-likely
+load-$(CONFIG_LEMOTE_FULOONG2E) += 0xffffffff80100000
+load-$(CONFIG_LEMOTE_MACH2F) += 0xffffffff80200000
diff --git a/arch/mips/loongson/common/cs5536/Makefile b/arch/mips/loongson/common/cs5536/Makefile
index 510d4cdc237..f12e6400734 100644
--- a/arch/mips/loongson/common/cs5536/Makefile
+++ b/arch/mips/loongson/common/cs5536/Makefile
@@ -9,5 +9,3 @@ obj-$(CONFIG_CS5536) += cs5536_pci.o cs5536_ide.o cs5536_acc.o cs5536_ohci.o \
# Enable cs5536 mfgpt Timer
#
obj-$(CONFIG_CS5536_MFGPT) += cs5536_mfgpt.o
-
-EXTRA_CFLAGS += -Werror
diff --git a/arch/mips/loongson/common/irq.c b/arch/mips/loongson/common/irq.c
index 20e73283197..5897471dedc 100644
--- a/arch/mips/loongson/common/irq.c
+++ b/arch/mips/loongson/common/irq.c
@@ -21,19 +21,16 @@ void bonito_irqdispatch(void)
/* workaround the IO dma problem: let cpu looping to allow DMA finish */
int_status = LOONGSON_INTISR;
- if (int_status & (1 << 10)) {
- while (int_status & (1 << 10)) {
- udelay(1);
- int_status = LOONGSON_INTISR;
- }
+ while (int_status & (1 << 10)) {
+ udelay(1);
+ int_status = LOONGSON_INTISR;
}
/* Get pending sources, masked by current enables */
int_status = LOONGSON_INTISR & LOONGSON_INTEN;
- if (int_status != 0) {
+ if (int_status) {
i = __ffs(int_status);
- int_status &= ~(1 << i);
do_IRQ(LOONGSON_IRQ_BASE + i);
}
}
@@ -56,9 +53,6 @@ void __init arch_init_irq(void)
*/
clear_c0_status(ST0_IM | ST0_BEV);
- /* setting irq trigger mode */
- set_irq_trigger_mode();
-
/* no steer */
LOONGSON_INTSTEER = 0;
diff --git a/arch/mips/loongson/fuloong-2e/Makefile b/arch/mips/loongson/fuloong-2e/Makefile
index 3aba5fcc09d..b7622720c1a 100644
--- a/arch/mips/loongson/fuloong-2e/Makefile
+++ b/arch/mips/loongson/fuloong-2e/Makefile
@@ -3,5 +3,3 @@
#
obj-y += irq.o reset.o
-
-EXTRA_CFLAGS += -Werror
diff --git a/arch/mips/loongson/fuloong-2e/irq.c b/arch/mips/loongson/fuloong-2e/irq.c
index 320e9379bdd..d61a04222b8 100644
--- a/arch/mips/loongson/fuloong-2e/irq.c
+++ b/arch/mips/loongson/fuloong-2e/irq.c
@@ -30,7 +30,7 @@ asmlinkage void mach_irq_dispatch(unsigned int pending)
if (pending & CAUSEF_IP7)
do_IRQ(MIPS_CPU_IRQ_BASE + 7);
else if (pending & CAUSEF_IP6) /* perf counter loverflow */
- do_IRQ(LOONGSON2_PERFCNT_IRQ);
+ do_perfcnt_IRQ();
else if (pending & CAUSEF_IP5)
i8259_irqdispatch();
else if (pending & CAUSEF_IP2)
@@ -44,13 +44,6 @@ static struct irqaction cascade_irqaction = {
.name = "cascade",
};
-void __init set_irq_trigger_mode(void)
-{
- /* most bonito irq should be level triggered */
- LOONGSON_INTEDGE = LOONGSON_ICU_SYSTEMERR | LOONGSON_ICU_MASTERERR |
- LOONGSON_ICU_RETRYERR | LOONGSON_ICU_MBOXES;
-}
-
void __init mach_init_irq(void)
{
/* init all controller
@@ -59,6 +52,10 @@ void __init mach_init_irq(void)
* 32-63 ------> bonito irq
*/
+ /* most bonito irq should be level triggered */
+ LOONGSON_INTEDGE = LOONGSON_ICU_SYSTEMERR | LOONGSON_ICU_MASTERERR |
+ LOONGSON_ICU_RETRYERR | LOONGSON_ICU_MBOXES;
+
/* Sets the first-level interrupt dispatcher. */
mips_cpu_irq_init();
init_i8259_irqs();
diff --git a/arch/mips/loongson/lemote-2f/irq.c b/arch/mips/loongson/lemote-2f/irq.c
index 1d8b4d28a05..081db102bb9 100644
--- a/arch/mips/loongson/lemote-2f/irq.c
+++ b/arch/mips/loongson/lemote-2f/irq.c
@@ -19,7 +19,6 @@
#include <machine.h>
#define LOONGSON_TIMER_IRQ (MIPS_CPU_IRQ_BASE + 7) /* cpu timer */
-#define LOONGSON_PERFCNT_IRQ (MIPS_CPU_IRQ_BASE + 6) /* cpu perf counter */
#define LOONGSON_NORTH_BRIDGE_IRQ (MIPS_CPU_IRQ_BASE + 6) /* bonito */
#define LOONGSON_UART_IRQ (MIPS_CPU_IRQ_BASE + 3) /* cpu serial port */
#define LOONGSON_SOUTH_BRIDGE_IRQ (MIPS_CPU_IRQ_BASE + 2) /* i8259 */
@@ -79,9 +78,7 @@ void mach_irq_dispatch(unsigned int pending)
if (pending & CAUSEF_IP7)
do_IRQ(LOONGSON_TIMER_IRQ);
else if (pending & CAUSEF_IP6) { /* North Bridge, Perf counter */
-#if defined(CONFIG_OPROFILE) || defined(CONFIG_OPROFILE_MODULE)
- do_IRQ(LOONGSON2_PERFCNT_IRQ);
-#endif
+ do_perfcnt_IRQ();
bonito_irqdispatch();
} else if (pending & CAUSEF_IP3) /* CPU UART */
do_IRQ(LOONGSON_UART_IRQ);
@@ -91,13 +88,6 @@ void mach_irq_dispatch(unsigned int pending)
spurious_interrupt();
}
-void __init set_irq_trigger_mode(void)
-{
- /* setup cs5536 as high level trigger */
- LOONGSON_INTPOL = LOONGSON_INT_BIT_INT0 | LOONGSON_INT_BIT_INT1;
- LOONGSON_INTEDGE &= ~(LOONGSON_INT_BIT_INT0 | LOONGSON_INT_BIT_INT1);
-}
-
static irqreturn_t ip6_action(int cpl, void *dev_id)
{
return IRQ_HANDLED;
@@ -122,6 +112,10 @@ void __init mach_init_irq(void)
* 32-63 ------> bonito irq
*/
+ /* setup cs5536 as high level trigger */
+ LOONGSON_INTPOL = LOONGSON_INT_BIT_INT0 | LOONGSON_INT_BIT_INT1;
+ LOONGSON_INTEDGE &= ~(LOONGSON_INT_BIT_INT0 | LOONGSON_INT_BIT_INT1);
+
/* Sets the first-level interrupt dispatcher. */
mips_cpu_irq_init();
init_i8259_irqs();
diff --git a/arch/mips/math-emu/Makefile b/arch/mips/math-emu/Makefile
index d547efdeedc..96607230d9e 100644
--- a/arch/mips/math-emu/Makefile
+++ b/arch/mips/math-emu/Makefile
@@ -10,4 +10,3 @@ obj-y := cp1emu.o ieee754m.o ieee754d.o ieee754dp.o ieee754sp.o ieee754.o \
sp_scalb.o sp_simple.o sp_tint.o sp_fint.o sp_tlong.o sp_flong.o \
dp_sqrt.o sp_sqrt.o kernel_linkage.o dsemul.o
-EXTRA_CFLAGS += -Werror
diff --git a/arch/mips/math-emu/dp_modf.c b/arch/mips/math-emu/dp_modf.c
index 25861a42c36..a8570e5c3ef 100644
--- a/arch/mips/math-emu/dp_modf.c
+++ b/arch/mips/math-emu/dp_modf.c
@@ -29,7 +29,7 @@
/* modf function is always exact for a finite number
*/
-ieee754dp ieee754dp_modf(ieee754dp x, ieee754dp * ip)
+ieee754dp ieee754dp_modf(ieee754dp x, ieee754dp *ip)
{
COMPXDP;
diff --git a/arch/mips/math-emu/dp_tint.c b/arch/mips/math-emu/dp_tint.c
index 77b2b7ccf28..24478623c11 100644
--- a/arch/mips/math-emu/dp_tint.c
+++ b/arch/mips/math-emu/dp_tint.c
@@ -69,8 +69,7 @@ int ieee754dp_tint(ieee754dp x)
round = 0;
sticky = residue != 0;
xm = 0;
- }
- else {
+ } else {
residue = xm << (64 - DP_MBITS + xe);
round = (residue >> 63) != 0;
sticky = (residue << 1) != 0;
diff --git a/arch/mips/math-emu/dp_tlong.c b/arch/mips/math-emu/dp_tlong.c
index d71113e0716..0f07ec2be3f 100644
--- a/arch/mips/math-emu/dp_tlong.c
+++ b/arch/mips/math-emu/dp_tlong.c
@@ -71,8 +71,7 @@ s64 ieee754dp_tlong(ieee754dp x)
round = 0;
sticky = residue != 0;
xm = 0;
- }
- else {
+ } else {
/* Shifting a u64 64 times does not work,
* so we do it in two steps. Be aware that xe
* may be -1 */
diff --git a/arch/mips/math-emu/sp_modf.c b/arch/mips/math-emu/sp_modf.c
index 4b1dbac796f..76568946b4c 100644
--- a/arch/mips/math-emu/sp_modf.c
+++ b/arch/mips/math-emu/sp_modf.c
@@ -29,7 +29,7 @@
/* modf function is always exact for a finite number
*/
-ieee754sp ieee754sp_modf(ieee754sp x, ieee754sp * ip)
+ieee754sp ieee754sp_modf(ieee754sp x, ieee754sp *ip)
{
COMPXSP;
diff --git a/arch/mips/math-emu/sp_tint.c b/arch/mips/math-emu/sp_tint.c
index 1d73d2abe0b..352dc3a5f1a 100644
--- a/arch/mips/math-emu/sp_tint.c
+++ b/arch/mips/math-emu/sp_tint.c
@@ -72,8 +72,7 @@ int ieee754sp_tint(ieee754sp x)
round = 0;
sticky = residue != 0;
xm = 0;
- }
- else {
+ } else {
/* Shifting a u32 32 times does not work,
* so we do it in two steps. Be aware that xe
* may be -1 */
diff --git a/arch/mips/math-emu/sp_tlong.c b/arch/mips/math-emu/sp_tlong.c
index 4be21aa81fb..92cd9c511a1 100644
--- a/arch/mips/math-emu/sp_tlong.c
+++ b/arch/mips/math-emu/sp_tlong.c
@@ -71,8 +71,7 @@ s64 ieee754sp_tlong(ieee754sp x)
round = 0;
sticky = residue != 0;
xm = 0;
- }
- else {
+ } else {
residue = xm << (32 - SP_MBITS + xe);
round = (residue >> 31) != 0;
sticky = (residue << 1) != 0;
diff --git a/arch/mips/mipssim/Makefile b/arch/mips/mipssim/Makefile
index 41b96571315..01410a3f172 100644
--- a/arch/mips/mipssim/Makefile
+++ b/arch/mips/mipssim/Makefile
@@ -21,5 +21,3 @@ obj-y := sim_platform.o sim_setup.o sim_mem.o sim_time.o sim_int.o
obj-$(CONFIG_EARLY_PRINTK) += sim_console.o
obj-$(CONFIG_MIPS_MT_SMTC) += sim_smtc.o
-
-EXTRA_CFLAGS += -Werror
diff --git a/arch/mips/mipssim/Platform b/arch/mips/mipssim/Platform
new file mode 100644
index 00000000000..3df60b8a12e
--- /dev/null
+++ b/arch/mips/mipssim/Platform
@@ -0,0 +1,6 @@
+#
+# MIPS SIM
+#
+platform-$(CONFIG_MIPS_SIM) += mipssim/
+cflags-$(CONFIG_MIPS_SIM) += -I$(srctree)/arch/mips/include/asm/mach-mipssim
+load-$(CONFIG_MIPS_SIM) += 0x80100000
diff --git a/arch/mips/mm/Makefile b/arch/mips/mm/Makefile
index f0e43559970..d679c772d08 100644
--- a/arch/mips/mm/Makefile
+++ b/arch/mips/mm/Makefile
@@ -34,5 +34,3 @@ obj-$(CONFIG_IP22_CPU_SCACHE) += sc-ip22.o
obj-$(CONFIG_R5000_CPU_SCACHE) += sc-r5k.o
obj-$(CONFIG_RM7000_CPU_SCACHE) += sc-rm7k.o
obj-$(CONFIG_MIPS_CPU_SCACHE) += sc-mips.o
-
-EXTRA_CFLAGS += -Werror
diff --git a/arch/mips/mm/fault.c b/arch/mips/mm/fault.c
index b78f7d913ca..783ad0065fd 100644
--- a/arch/mips/mm/fault.c
+++ b/arch/mips/mm/fault.c
@@ -16,8 +16,8 @@
#include <linux/mman.h>
#include <linux/mm.h>
#include <linux/smp.h>
-#include <linux/vt_kern.h> /* For unblank_screen() */
#include <linux/module.h>
+#include <linux/kprobes.h>
#include <asm/branch.h>
#include <asm/mmu_context.h>
@@ -25,13 +25,14 @@
#include <asm/uaccess.h>
#include <asm/ptrace.h>
#include <asm/highmem.h> /* For VMALLOC_END */
+#include <linux/kdebug.h>
/*
* This routine handles page faults. It determines the address,
* and the problem, and then passes it off to one of the appropriate
* routines.
*/
-asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long write,
+asmlinkage void __kprobes do_page_fault(struct pt_regs *regs, unsigned long write,
unsigned long address)
{
struct vm_area_struct * vma = NULL;
@@ -47,6 +48,17 @@ asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long write,
field, regs->cp0_epc);
#endif
+#ifdef CONFIG_KPROBES
+ /*
+ * This is to notify the fault handler of the kprobes. The
+ * exception code is redundant as it is also carried in REGS,
+ * but we pass it anyhow.
+ */
+ if (notify_die(DIE_PAGE_FAULT, "page fault", regs, -1,
+ (regs->cp0_cause >> 2) & 0x1f, SIGSEGV) == NOTIFY_STOP)
+ return;
+#endif
+
info.si_code = SEGV_MAPERR;
/*
diff --git a/arch/mips/mm/sc-rm7k.c b/arch/mips/mm/sc-rm7k.c
index de69bfbf506..1ef75cd80a0 100644
--- a/arch/mips/mm/sc-rm7k.c
+++ b/arch/mips/mm/sc-rm7k.c
@@ -16,6 +16,7 @@
#include <asm/cacheops.h>
#include <asm/mipsregs.h>
#include <asm/processor.h>
+#include <asm/sections.h>
#include <asm/cacheflush.h> /* for run_uncached() */
/* Primary cache parameters. */
@@ -25,11 +26,15 @@
/* Secondary cache parameters. */
#define scache_size (256*1024) /* Fixed to 256KiB on RM7000 */
+/* Tertiary cache parameters */
+#define tc_lsize 32
+
extern unsigned long icache_way_size, dcache_way_size;
+unsigned long tcache_size;
#include <asm/r4kcache.h>
-static int rm7k_tcache_enabled;
+static int rm7k_tcache_init;
/*
* Writeback and invalidate the primary cache dcache before DMA.
@@ -46,7 +51,7 @@ static void rm7k_sc_wback_inv(unsigned long addr, unsigned long size)
blast_scache_range(addr, addr + size);
- if (!rm7k_tcache_enabled)
+ if (!rm7k_tcache_init)
return;
a = addr & ~(tc_pagesize - 1);
@@ -70,7 +75,7 @@ static void rm7k_sc_inv(unsigned long addr, unsigned long size)
blast_inv_scache_range(addr, addr + size);
- if (!rm7k_tcache_enabled)
+ if (!rm7k_tcache_init)
return;
a = addr & ~(tc_pagesize - 1);
@@ -83,6 +88,45 @@ static void rm7k_sc_inv(unsigned long addr, unsigned long size)
}
}
+static void blast_rm7k_tcache(void)
+{
+ unsigned long start = CKSEG0ADDR(0);
+ unsigned long end = start + tcache_size;
+
+ write_c0_taglo(0);
+
+ while (start < end) {
+ cache_op(Page_Invalidate_T, start);
+ start += tc_pagesize;
+ }
+}
+
+/*
+ * This function is executed in uncached address space.
+ */
+static __cpuinit void __rm7k_tc_enable(void)
+{
+ int i;
+
+ set_c0_config(RM7K_CONF_TE);
+
+ write_c0_taglo(0);
+ write_c0_taghi(0);
+
+ for (i = 0; i < tcache_size; i += tc_lsize)
+ cache_op(Index_Store_Tag_T, CKSEG0ADDR(i));
+}
+
+static __cpuinit void rm7k_tc_enable(void)
+{
+ if (read_c0_config() & RM7K_CONF_TE)
+ return;
+
+ BUG_ON(tcache_size == 0);
+
+ run_uncached(__rm7k_tc_enable);
+}
+
/*
* This function is executed in uncached address space.
*/
@@ -95,16 +139,8 @@ static __cpuinit void __rm7k_sc_enable(void)
write_c0_taglo(0);
write_c0_taghi(0);
- for (i = 0; i < scache_size; i += sc_lsize) {
- __asm__ __volatile__ (
- ".set noreorder\n\t"
- ".set mips3\n\t"
- "cache %1, (%0)\n\t"
- ".set mips0\n\t"
- ".set reorder"
- :
- : "r" (CKSEG0ADDR(i)), "i" (Index_Store_Tag_SD));
- }
+ for (i = 0; i < scache_size; i += sc_lsize)
+ cache_op(Index_Store_Tag_SD, CKSEG0ADDR(i));
}
static __cpuinit void rm7k_sc_enable(void)
@@ -112,13 +148,29 @@ static __cpuinit void rm7k_sc_enable(void)
if (read_c0_config() & RM7K_CONF_SE)
return;
- printk(KERN_INFO "Enabling secondary cache...\n");
+ pr_info("Enabling secondary cache...\n");
run_uncached(__rm7k_sc_enable);
+
+ if (rm7k_tcache_init)
+ rm7k_tc_enable();
+}
+
+static void rm7k_tc_disable(void)
+{
+ unsigned long flags;
+
+ local_irq_save(flags);
+ blast_rm7k_tcache();
+ clear_c0_config(RM7K_CONF_TE);
+ local_irq_save(flags);
}
static void rm7k_sc_disable(void)
{
clear_c0_config(RM7K_CONF_SE);
+
+ if (rm7k_tcache_init)
+ rm7k_tc_disable();
}
static struct bcache_ops rm7k_sc_ops = {
@@ -128,6 +180,52 @@ static struct bcache_ops rm7k_sc_ops = {
.bc_inv = rm7k_sc_inv
};
+/*
+ * This is a probing function like the one found in c-r4k.c, we look for the
+ * wrap around point with different addresses.
+ */
+static __cpuinit void __probe_tcache(void)
+{
+ unsigned long flags, addr, begin, end, pow2;
+
+ begin = (unsigned long) &_stext;
+ begin &= ~((8 * 1024 * 1024) - 1);
+ end = begin + (8 * 1024 * 1024);
+
+ local_irq_save(flags);
+
+ set_c0_config(RM7K_CONF_TE);
+
+ /* Fill size-multiple lines with a valid tag */
+ pow2 = (256 * 1024);
+ for (addr = begin; addr <= end; addr = (begin + pow2)) {
+ unsigned long *p = (unsigned long *) addr;
+ __asm__ __volatile__("nop" : : "r" (*p));
+ pow2 <<= 1;
+ }
+
+ /* Load first line with a 0 tag, to check after */
+ write_c0_taglo(0);
+ write_c0_taghi(0);
+ cache_op(Index_Store_Tag_T, begin);
+
+ /* Look for the wrap-around */
+ pow2 = (512 * 1024);
+ for (addr = begin + (512 * 1024); addr <= end; addr = begin + pow2) {
+ cache_op(Index_Load_Tag_T, addr);
+ if (!read_c0_taglo())
+ break;
+ pow2 <<= 1;
+ }
+
+ addr -= begin;
+ tcache_size = addr;
+
+ clear_c0_config(RM7K_CONF_TE);
+
+ local_irq_restore(flags);
+}
+
void __cpuinit rm7k_sc_init(void)
{
struct cpuinfo_mips *c = &current_cpu_data;
@@ -147,27 +245,26 @@ void __cpuinit rm7k_sc_init(void)
if (!(config & RM7K_CONF_SE))
rm7k_sc_enable();
+ bcops = &rm7k_sc_ops;
+
/*
* While we're at it let's deal with the tertiary cache.
*/
- if (!(config & RM7K_CONF_TC)) {
-
- /*
- * We can't enable the L3 cache yet. There may be board-specific
- * magic necessary to turn it on, and blindly asking the CPU to
- * start using it would may give cache errors.
- *
- * Also, board-specific knowledge may allow us to use the
- * CACHE Flash_Invalidate_T instruction if the tag RAM supports
- * it, and may specify the size of the L3 cache so we don't have
- * to probe it.
- */
- printk(KERN_INFO "Tertiary cache present, %s enabled\n",
- (config & RM7K_CONF_TE) ? "already" : "not (yet)");
-
- if ((config & RM7K_CONF_TE))
- rm7k_tcache_enabled = 1;
- }
- bcops = &rm7k_sc_ops;
+ rm7k_tcache_init = 0;
+ tcache_size = 0;
+
+ if (config & RM7K_CONF_TC)
+ return;
+
+ /*
+ * No efficient way to ask the hardware for the size of the tcache,
+ * so must probe for it.
+ */
+ run_uncached(__probe_tcache);
+ rm7k_tc_enable();
+ rm7k_tcache_init = 1;
+ c->tcache.linesz = tc_lsize;
+ c->tcache.ways = 1;
+ pr_info("Tertiary cache size %ldK.\n", (tcache_size >> 10));
}
diff --git a/arch/mips/mm/tlbex.c b/arch/mips/mm/tlbex.c
index 86f004dc835..4510e61883e 100644
--- a/arch/mips/mm/tlbex.c
+++ b/arch/mips/mm/tlbex.c
@@ -409,6 +409,11 @@ static void __cpuinit build_tlb_write_entry(u32 **p, struct uasm_label **l,
tlbw(p);
break;
+ case CPU_JZRISC:
+ tlbw(p);
+ uasm_i_nop(p);
+ break;
+
default:
panic("No TLB refill handler yet (CPU type: %d)",
current_cpu_data.cputype);
diff --git a/arch/mips/mm/uasm.c b/arch/mips/mm/uasm.c
index 611d564fdcf..d2647a4e012 100644
--- a/arch/mips/mm/uasm.c
+++ b/arch/mips/mm/uasm.c
@@ -62,12 +62,13 @@ enum opcode {
insn_beql, insn_bgez, insn_bgezl, insn_bltz, insn_bltzl,
insn_bne, insn_cache, insn_daddu, insn_daddiu, insn_dmfc0,
insn_dmtc0, insn_dsll, insn_dsll32, insn_dsra, insn_dsrl,
- insn_dsrl32, insn_drotr, insn_dsubu, insn_eret, insn_j, insn_jal,
- insn_jr, insn_ld, insn_ll, insn_lld, insn_lui, insn_lw, insn_mfc0,
- insn_mtc0, insn_or, insn_ori, insn_pref, insn_rfe, insn_sc, insn_scd,
- insn_sd, insn_sll, insn_sra, insn_srl, insn_rotr, insn_subu, insn_sw,
- insn_tlbp, insn_tlbr, insn_tlbwi, insn_tlbwr, insn_xor, insn_xori,
- insn_dins, insn_syscall
+ insn_dsrl32, insn_drotr, insn_drotr32, insn_dsubu, insn_eret,
+ insn_j, insn_jal, insn_jr, insn_ld, insn_ll, insn_lld,
+ insn_lui, insn_lw, insn_mfc0, insn_mtc0, insn_or, insn_ori,
+ insn_pref, insn_rfe, insn_sc, insn_scd, insn_sd, insn_sll,
+ insn_sra, insn_srl, insn_rotr, insn_subu, insn_sw, insn_tlbp,
+ insn_tlbr, insn_tlbwi, insn_tlbwr, insn_xor, insn_xori,
+ insn_dins, insn_syscall, insn_bbit0, insn_bbit1
};
struct insn {
@@ -85,7 +86,7 @@ struct insn {
| (e) << RE_SH \
| (f) << FUNC_SH)
-static struct insn insn_table[] __cpuinitdata = {
+static struct insn insn_table[] __uasminitdata = {
{ insn_addiu, M(addiu_op, 0, 0, 0, 0, 0), RS | RT | SIMM },
{ insn_addu, M(spec_op, 0, 0, 0, 0, addu_op), RS | RT | RD },
{ insn_and, M(spec_op, 0, 0, 0, 0, and_op), RS | RT | RD },
@@ -108,6 +109,7 @@ static struct insn insn_table[] __cpuinitdata = {
{ insn_dsrl, M(spec_op, 0, 0, 0, 0, dsrl_op), RT | RD | RE },
{ insn_dsrl32, M(spec_op, 0, 0, 0, 0, dsrl32_op), RT | RD | RE },
{ insn_drotr, M(spec_op, 1, 0, 0, 0, dsrl_op), RT | RD | RE },
+ { insn_drotr32, M(spec_op, 1, 0, 0, 0, dsrl32_op), RT | RD | RE },
{ insn_dsubu, M(spec_op, 0, 0, 0, 0, dsubu_op), RS | RT | RD },
{ insn_eret, M(cop0_op, cop_op, 0, 0, 0, eret_op), 0 },
{ insn_j, M(j_op, 0, 0, 0, 0, 0), JIMM },
@@ -141,12 +143,14 @@ static struct insn insn_table[] __cpuinitdata = {
{ insn_xori, M(xori_op, 0, 0, 0, 0, 0), RS | RT | UIMM },
{ insn_dins, M(spec3_op, 0, 0, 0, 0, dins_op), RS | RT | RD | RE },
{ insn_syscall, M(spec_op, 0, 0, 0, 0, syscall_op), SCIMM},
+ { insn_bbit0, M(lwc2_op, 0, 0, 0, 0, 0), RS | RT | BIMM },
+ { insn_bbit1, M(swc2_op, 0, 0, 0, 0, 0), RS | RT | BIMM },
{ insn_invalid, 0, 0 }
};
#undef M
-static inline __cpuinit u32 build_rs(u32 arg)
+static inline __uasminit u32 build_rs(u32 arg)
{
if (arg & ~RS_MASK)
printk(KERN_WARNING "Micro-assembler field overflow\n");
@@ -154,7 +158,7 @@ static inline __cpuinit u32 build_rs(u32 arg)
return (arg & RS_MASK) << RS_SH;
}
-static inline __cpuinit u32 build_rt(u32 arg)
+static inline __uasminit u32 build_rt(u32 arg)
{
if (arg & ~RT_MASK)
printk(KERN_WARNING "Micro-assembler field overflow\n");
@@ -162,7 +166,7 @@ static inline __cpuinit u32 build_rt(u32 arg)
return (arg & RT_MASK) << RT_SH;
}
-static inline __cpuinit u32 build_rd(u32 arg)
+static inline __uasminit u32 build_rd(u32 arg)
{
if (arg & ~RD_MASK)
printk(KERN_WARNING "Micro-assembler field overflow\n");
@@ -170,7 +174,7 @@ static inline __cpuinit u32 build_rd(u32 arg)
return (arg & RD_MASK) << RD_SH;
}
-static inline __cpuinit u32 build_re(u32 arg)
+static inline __uasminit u32 build_re(u32 arg)
{
if (arg & ~RE_MASK)
printk(KERN_WARNING "Micro-assembler field overflow\n");
@@ -178,7 +182,7 @@ static inline __cpuinit u32 build_re(u32 arg)
return (arg & RE_MASK) << RE_SH;
}
-static inline __cpuinit u32 build_simm(s32 arg)
+static inline __uasminit u32 build_simm(s32 arg)
{
if (arg > 0x7fff || arg < -0x8000)
printk(KERN_WARNING "Micro-assembler field overflow\n");
@@ -186,7 +190,7 @@ static inline __cpuinit u32 build_simm(s32 arg)
return arg & 0xffff;
}
-static inline __cpuinit u32 build_uimm(u32 arg)
+static inline __uasminit u32 build_uimm(u32 arg)
{
if (arg & ~IMM_MASK)
printk(KERN_WARNING "Micro-assembler field overflow\n");
@@ -194,7 +198,7 @@ static inline __cpuinit u32 build_uimm(u32 arg)
return arg & IMM_MASK;
}
-static inline __cpuinit u32 build_bimm(s32 arg)
+static inline __uasminit u32 build_bimm(s32 arg)
{
if (arg > 0x1ffff || arg < -0x20000)
printk(KERN_WARNING "Micro-assembler field overflow\n");
@@ -205,7 +209,7 @@ static inline __cpuinit u32 build_bimm(s32 arg)
return ((arg < 0) ? (1 << 15) : 0) | ((arg >> 2) & 0x7fff);
}
-static inline __cpuinit u32 build_jimm(u32 arg)
+static inline __uasminit u32 build_jimm(u32 arg)
{
if (arg & ~((JIMM_MASK) << 2))
printk(KERN_WARNING "Micro-assembler field overflow\n");
@@ -213,7 +217,7 @@ static inline __cpuinit u32 build_jimm(u32 arg)
return (arg >> 2) & JIMM_MASK;
}
-static inline __cpuinit u32 build_scimm(u32 arg)
+static inline __uasminit u32 build_scimm(u32 arg)
{
if (arg & ~SCIMM_MASK)
printk(KERN_WARNING "Micro-assembler field overflow\n");
@@ -221,7 +225,7 @@ static inline __cpuinit u32 build_scimm(u32 arg)
return (arg & SCIMM_MASK) << SCIMM_SH;
}
-static inline __cpuinit u32 build_func(u32 arg)
+static inline __uasminit u32 build_func(u32 arg)
{
if (arg & ~FUNC_MASK)
printk(KERN_WARNING "Micro-assembler field overflow\n");
@@ -229,7 +233,7 @@ static inline __cpuinit u32 build_func(u32 arg)
return arg & FUNC_MASK;
}
-static inline __cpuinit u32 build_set(u32 arg)
+static inline __uasminit u32 build_set(u32 arg)
{
if (arg & ~SET_MASK)
printk(KERN_WARNING "Micro-assembler field overflow\n");
@@ -241,7 +245,7 @@ static inline __cpuinit u32 build_set(u32 arg)
* The order of opcode arguments is implicitly left to right,
* starting with RS and ending with FUNC or IMM.
*/
-static void __cpuinit build_insn(u32 **buf, enum opcode opc, ...)
+static void __uasminit build_insn(u32 **buf, enum opcode opc, ...)
{
struct insn *ip = NULL;
unsigned int i;
@@ -291,67 +295,78 @@ static void __cpuinit build_insn(u32 **buf, enum opcode opc, ...)
Ip_u1u2u3(op) \
{ \
build_insn(buf, insn##op, a, b, c); \
-}
+} \
+UASM_EXPORT_SYMBOL(uasm_i##op);
#define I_u2u1u3(op) \
Ip_u2u1u3(op) \
{ \
build_insn(buf, insn##op, b, a, c); \
-}
+} \
+UASM_EXPORT_SYMBOL(uasm_i##op);
#define I_u3u1u2(op) \
Ip_u3u1u2(op) \
{ \
build_insn(buf, insn##op, b, c, a); \
-}
+} \
+UASM_EXPORT_SYMBOL(uasm_i##op);
#define I_u1u2s3(op) \
Ip_u1u2s3(op) \
{ \
build_insn(buf, insn##op, a, b, c); \
-}
+} \
+UASM_EXPORT_SYMBOL(uasm_i##op);
#define I_u2s3u1(op) \
Ip_u2s3u1(op) \
{ \
build_insn(buf, insn##op, c, a, b); \
-}
+} \
+UASM_EXPORT_SYMBOL(uasm_i##op);
#define I_u2u1s3(op) \
Ip_u2u1s3(op) \
{ \
build_insn(buf, insn##op, b, a, c); \
-}
+} \
+UASM_EXPORT_SYMBOL(uasm_i##op);
#define I_u2u1msbu3(op) \
Ip_u2u1msbu3(op) \
{ \
build_insn(buf, insn##op, b, a, c+d-1, c); \
-}
+} \
+UASM_EXPORT_SYMBOL(uasm_i##op);
#define I_u1u2(op) \
Ip_u1u2(op) \
{ \
build_insn(buf, insn##op, a, b); \
-}
+} \
+UASM_EXPORT_SYMBOL(uasm_i##op);
#define I_u1s2(op) \
Ip_u1s2(op) \
{ \
build_insn(buf, insn##op, a, b); \
-}
+} \
+UASM_EXPORT_SYMBOL(uasm_i##op);
#define I_u1(op) \
Ip_u1(op) \
{ \
build_insn(buf, insn##op, a); \
-}
+} \
+UASM_EXPORT_SYMBOL(uasm_i##op);
#define I_0(op) \
Ip_0(op) \
{ \
build_insn(buf, insn##op); \
-}
+} \
+UASM_EXPORT_SYMBOL(uasm_i##op);
I_u2u1s3(_addiu)
I_u3u1u2(_addu)
@@ -375,6 +390,7 @@ I_u2u1u3(_dsra)
I_u2u1u3(_dsrl)
I_u2u1u3(_dsrl32)
I_u2u1u3(_drotr)
+I_u2u1u3(_drotr32)
I_u3u1u2(_dsubu)
I_0(_eret)
I_u1(_j)
@@ -408,16 +424,19 @@ I_u3u1u2(_xor)
I_u2u1u3(_xori)
I_u2u1msbu3(_dins);
I_u1(_syscall);
+I_u1u2s3(_bbit0);
+I_u1u2s3(_bbit1);
/* Handle labels. */
-void __cpuinit uasm_build_label(struct uasm_label **lab, u32 *addr, int lid)
+void __uasminit uasm_build_label(struct uasm_label **lab, u32 *addr, int lid)
{
(*lab)->addr = addr;
(*lab)->lab = lid;
(*lab)++;
}
+UASM_EXPORT_SYMBOL(uasm_build_label);
-int __cpuinit uasm_in_compat_space_p(long addr)
+int __uasminit uasm_in_compat_space_p(long addr)
{
/* Is this address in 32bit compat space? */
#ifdef CONFIG_64BIT
@@ -426,8 +445,9 @@ int __cpuinit uasm_in_compat_space_p(long addr)
return 1;
#endif
}
+UASM_EXPORT_SYMBOL(uasm_in_compat_space_p);
-static int __cpuinit uasm_rel_highest(long val)
+static int __uasminit uasm_rel_highest(long val)
{
#ifdef CONFIG_64BIT
return ((((val + 0x800080008000L) >> 48) & 0xffff) ^ 0x8000) - 0x8000;
@@ -436,7 +456,7 @@ static int __cpuinit uasm_rel_highest(long val)
#endif
}
-static int __cpuinit uasm_rel_higher(long val)
+static int __uasminit uasm_rel_higher(long val)
{
#ifdef CONFIG_64BIT
return ((((val + 0x80008000L) >> 32) & 0xffff) ^ 0x8000) - 0x8000;
@@ -445,17 +465,19 @@ static int __cpuinit uasm_rel_higher(long val)
#endif
}
-int __cpuinit uasm_rel_hi(long val)
+int __uasminit uasm_rel_hi(long val)
{
return ((((val + 0x8000L) >> 16) & 0xffff) ^ 0x8000) - 0x8000;
}
+UASM_EXPORT_SYMBOL(uasm_rel_hi);
-int __cpuinit uasm_rel_lo(long val)
+int __uasminit uasm_rel_lo(long val)
{
return ((val & 0xffff) ^ 0x8000) - 0x8000;
}
+UASM_EXPORT_SYMBOL(uasm_rel_lo);
-void __cpuinit UASM_i_LA_mostly(u32 **buf, unsigned int rs, long addr)
+void __uasminit UASM_i_LA_mostly(u32 **buf, unsigned int rs, long addr)
{
if (!uasm_in_compat_space_p(addr)) {
uasm_i_lui(buf, rs, uasm_rel_highest(addr));
@@ -470,8 +492,9 @@ void __cpuinit UASM_i_LA_mostly(u32 **buf, unsigned int rs, long addr)
} else
uasm_i_lui(buf, rs, uasm_rel_hi(addr));
}
+UASM_EXPORT_SYMBOL(UASM_i_LA_mostly);
-void __cpuinit UASM_i_LA(u32 **buf, unsigned int rs, long addr)
+void __uasminit UASM_i_LA(u32 **buf, unsigned int rs, long addr)
{
UASM_i_LA_mostly(buf, rs, addr);
if (uasm_rel_lo(addr)) {
@@ -481,9 +504,10 @@ void __cpuinit UASM_i_LA(u32 **buf, unsigned int rs, long addr)
uasm_i_addiu(buf, rs, rs, uasm_rel_lo(addr));
}
}
+UASM_EXPORT_SYMBOL(UASM_i_LA);
/* Handle relocations. */
-void __cpuinit
+void __uasminit
uasm_r_mips_pc16(struct uasm_reloc **rel, u32 *addr, int lid)
{
(*rel)->addr = addr;
@@ -491,8 +515,9 @@ uasm_r_mips_pc16(struct uasm_reloc **rel, u32 *addr, int lid)
(*rel)->lab = lid;
(*rel)++;
}
+UASM_EXPORT_SYMBOL(uasm_r_mips_pc16);
-static inline void __cpuinit
+static inline void __uasminit
__resolve_relocs(struct uasm_reloc *rel, struct uasm_label *lab)
{
long laddr = (long)lab->addr;
@@ -509,7 +534,7 @@ __resolve_relocs(struct uasm_reloc *rel, struct uasm_label *lab)
}
}
-void __cpuinit
+void __uasminit
uasm_resolve_relocs(struct uasm_reloc *rel, struct uasm_label *lab)
{
struct uasm_label *l;
@@ -519,24 +544,27 @@ uasm_resolve_relocs(struct uasm_reloc *rel, struct uasm_label *lab)
if (rel->lab == l->lab)
__resolve_relocs(rel, l);
}
+UASM_EXPORT_SYMBOL(uasm_resolve_relocs);
-void __cpuinit
+void __uasminit
uasm_move_relocs(struct uasm_reloc *rel, u32 *first, u32 *end, long off)
{
for (; rel->lab != UASM_LABEL_INVALID; rel++)
if (rel->addr >= first && rel->addr < end)
rel->addr += off;
}
+UASM_EXPORT_SYMBOL(uasm_move_relocs);
-void __cpuinit
+void __uasminit
uasm_move_labels(struct uasm_label *lab, u32 *first, u32 *end, long off)
{
for (; lab->lab != UASM_LABEL_INVALID; lab++)
if (lab->addr >= first && lab->addr < end)
lab->addr += off;
}
+UASM_EXPORT_SYMBOL(uasm_move_labels);
-void __cpuinit
+void __uasminit
uasm_copy_handler(struct uasm_reloc *rel, struct uasm_label *lab, u32 *first,
u32 *end, u32 *target)
{
@@ -547,8 +575,9 @@ uasm_copy_handler(struct uasm_reloc *rel, struct uasm_label *lab, u32 *first,
uasm_move_relocs(rel, first, end, off);
uasm_move_labels(lab, first, end, off);
}
+UASM_EXPORT_SYMBOL(uasm_copy_handler);
-int __cpuinit uasm_insn_has_bdelay(struct uasm_reloc *rel, u32 *addr)
+int __uasminit uasm_insn_has_bdelay(struct uasm_reloc *rel, u32 *addr)
{
for (; rel->lab != UASM_LABEL_INVALID; rel++) {
if (rel->addr == addr
@@ -559,61 +588,88 @@ int __cpuinit uasm_insn_has_bdelay(struct uasm_reloc *rel, u32 *addr)
return 0;
}
+UASM_EXPORT_SYMBOL(uasm_insn_has_bdelay);
/* Convenience functions for labeled branches. */
-void __cpuinit
+void __uasminit
uasm_il_bltz(u32 **p, struct uasm_reloc **r, unsigned int reg, int lid)
{
uasm_r_mips_pc16(r, *p, lid);
uasm_i_bltz(p, reg, 0);
}
+UASM_EXPORT_SYMBOL(uasm_il_bltz);
-void __cpuinit
+void __uasminit
uasm_il_b(u32 **p, struct uasm_reloc **r, int lid)
{
uasm_r_mips_pc16(r, *p, lid);
uasm_i_b(p, 0);
}
+UASM_EXPORT_SYMBOL(uasm_il_b);
-void __cpuinit
+void __uasminit
uasm_il_beqz(u32 **p, struct uasm_reloc **r, unsigned int reg, int lid)
{
uasm_r_mips_pc16(r, *p, lid);
uasm_i_beqz(p, reg, 0);
}
+UASM_EXPORT_SYMBOL(uasm_il_beqz);
-void __cpuinit
+void __uasminit
uasm_il_beqzl(u32 **p, struct uasm_reloc **r, unsigned int reg, int lid)
{
uasm_r_mips_pc16(r, *p, lid);
uasm_i_beqzl(p, reg, 0);
}
+UASM_EXPORT_SYMBOL(uasm_il_beqzl);
-void __cpuinit
+void __uasminit
uasm_il_bne(u32 **p, struct uasm_reloc **r, unsigned int reg1,
unsigned int reg2, int lid)
{
uasm_r_mips_pc16(r, *p, lid);
uasm_i_bne(p, reg1, reg2, 0);
}
+UASM_EXPORT_SYMBOL(uasm_il_bne);
-void __cpuinit
+void __uasminit
uasm_il_bnez(u32 **p, struct uasm_reloc **r, unsigned int reg, int lid)
{
uasm_r_mips_pc16(r, *p, lid);
uasm_i_bnez(p, reg, 0);
}
+UASM_EXPORT_SYMBOL(uasm_il_bnez);
-void __cpuinit
+void __uasminit
uasm_il_bgezl(u32 **p, struct uasm_reloc **r, unsigned int reg, int lid)
{
uasm_r_mips_pc16(r, *p, lid);
uasm_i_bgezl(p, reg, 0);
}
+UASM_EXPORT_SYMBOL(uasm_il_bgezl);
-void __cpuinit
+void __uasminit
uasm_il_bgez(u32 **p, struct uasm_reloc **r, unsigned int reg, int lid)
{
uasm_r_mips_pc16(r, *p, lid);
uasm_i_bgez(p, reg, 0);
}
+UASM_EXPORT_SYMBOL(uasm_il_bgez);
+
+void __uasminit
+uasm_il_bbit0(u32 **p, struct uasm_reloc **r, unsigned int reg,
+ unsigned int bit, int lid)
+{
+ uasm_r_mips_pc16(r, *p, lid);
+ uasm_i_bbit0(p, reg, bit, 0);
+}
+UASM_EXPORT_SYMBOL(uasm_il_bbit0);
+
+void __uasminit
+uasm_il_bbit1(u32 **p, struct uasm_reloc **r, unsigned int reg,
+ unsigned int bit, int lid)
+{
+ uasm_r_mips_pc16(r, *p, lid);
+ uasm_i_bbit1(p, reg, bit, 0);
+}
+UASM_EXPORT_SYMBOL(uasm_il_bbit1);
diff --git a/arch/mips/mti-malta/Makefile b/arch/mips/mti-malta/Makefile
index 32e847808df..6079ef33b5f 100644
--- a/arch/mips/mti-malta/Makefile
+++ b/arch/mips/mti-malta/Makefile
@@ -15,5 +15,3 @@ obj-$(CONFIG_PCI) += malta-pci.o
# FIXME FIXME FIXME
obj-$(CONFIG_MIPS_MT_SMTC) += malta-smtc.o
-
-EXTRA_CFLAGS += -Werror
diff --git a/arch/mips/mti-malta/Platform b/arch/mips/mti-malta/Platform
new file mode 100644
index 00000000000..5b548b5a4fc
--- /dev/null
+++ b/arch/mips/mti-malta/Platform
@@ -0,0 +1,7 @@
+#
+# MIPS Malta board
+#
+platform-$(CONFIG_MIPS_MALTA) += mti-malta/
+cflags-$(CONFIG_MIPS_MALTA) += -I$(srctree)/arch/mips/include/asm/mach-malta
+load-$(CONFIG_MIPS_MALTA) += 0xffffffff80100000
+all-$(CONFIG_MIPS_MALTA) := $(COMPRESSION_FNAME).bin
diff --git a/arch/mips/nxp/pnx833x/stb22x/Makefile b/arch/mips/nxp/pnx833x/stb22x/Makefile
deleted file mode 100644
index f81c5801f45..00000000000
--- a/arch/mips/nxp/pnx833x/stb22x/Makefile
+++ /dev/null
@@ -1,3 +0,0 @@
-lib-y := board.o
-
-EXTRA_CFLAGS += -Werror
diff --git a/arch/mips/nxp/pnx8550/jbs/Makefile b/arch/mips/nxp/pnx8550/jbs/Makefile
deleted file mode 100644
index ad6a8ca7d8c..00000000000
--- a/arch/mips/nxp/pnx8550/jbs/Makefile
+++ /dev/null
@@ -1,4 +0,0 @@
-
-# Makefile for the NXP JBS Board.
-
-lib-y := init.o board_setup.o irqmap.o
diff --git a/arch/mips/nxp/pnx8550/stb810/Makefile b/arch/mips/nxp/pnx8550/stb810/Makefile
deleted file mode 100644
index ab91d72c566..00000000000
--- a/arch/mips/nxp/pnx8550/stb810/Makefile
+++ /dev/null
@@ -1,4 +0,0 @@
-
-# Makefile for the NXP STB810 Board.
-
-lib-y := prom_init.o board_setup.o irqmap.o
diff --git a/arch/mips/pci/msi-octeon.c b/arch/mips/pci/msi-octeon.c
index 03742e64765..d8080499872 100644
--- a/arch/mips/pci/msi-octeon.c
+++ b/arch/mips/pci/msi-octeon.c
@@ -3,7 +3,7 @@
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
- * Copyright (C) 2005-2009 Cavium Networks
+ * Copyright (C) 2005-2009, 2010 Cavium Networks
*/
#include <linux/kernel.h>
#include <linux/init.h>
@@ -22,7 +22,7 @@
* Each bit in msi_free_irq_bitmask represents a MSI interrupt that is
* in use.
*/
-static uint64_t msi_free_irq_bitmask;
+static u64 msi_free_irq_bitmask[4];
/*
* Each bit in msi_multiple_irq_bitmask tells that the device using
@@ -30,7 +30,7 @@ static uint64_t msi_free_irq_bitmask;
* is used so we can disable all of the MSI interrupts when a device
* uses multiple.
*/
-static uint64_t msi_multiple_irq_bitmask;
+static u64 msi_multiple_irq_bitmask[4];
/*
* This lock controls updates to msi_free_irq_bitmask and
@@ -38,6 +38,11 @@ static uint64_t msi_multiple_irq_bitmask;
*/
static DEFINE_SPINLOCK(msi_free_irq_bitmask_lock);
+/*
+ * Number of MSI IRQs used. This variable is set up in
+ * the module init time.
+ */
+static int msi_irq_size;
/**
* Called when a driver request MSI interrupts instead of the
@@ -54,12 +59,13 @@ static DEFINE_SPINLOCK(msi_free_irq_bitmask_lock);
int arch_setup_msi_irq(struct pci_dev *dev, struct msi_desc *desc)
{
struct msi_msg msg;
- uint16_t control;
+ u16 control;
int configured_private_bits;
int request_private_bits;
- int irq;
+ int irq = 0;
int irq_step;
- uint64_t search_mask;
+ u64 search_mask;
+ int index;
/*
* Read the MSI config to figure out how many IRQs this device
@@ -111,29 +117,31 @@ try_only_one:
* use.
*/
spin_lock(&msi_free_irq_bitmask_lock);
- for (irq = 0; irq < 64; irq += irq_step) {
- if ((msi_free_irq_bitmask & (search_mask << irq)) == 0) {
- msi_free_irq_bitmask |= search_mask << irq;
- msi_multiple_irq_bitmask |= (search_mask >> 1) << irq;
- break;
+ for (index = 0; index < msi_irq_size/64; index++) {
+ for (irq = 0; irq < 64; irq += irq_step) {
+ if ((msi_free_irq_bitmask[index] & (search_mask << irq)) == 0) {
+ msi_free_irq_bitmask[index] |= search_mask << irq;
+ msi_multiple_irq_bitmask[index] |= (search_mask >> 1) << irq;
+ goto msi_irq_allocated;
+ }
}
}
+msi_irq_allocated:
spin_unlock(&msi_free_irq_bitmask_lock);
/* Make sure the search for available interrupts didn't fail */
if (irq >= 64) {
if (request_private_bits) {
- pr_err("arch_setup_msi_irq: Unable to find %d free "
- "interrupts, trying just one",
+ pr_err("arch_setup_msi_irq: Unable to find %d free interrupts, trying just one",
1 << request_private_bits);
request_private_bits = 0;
goto try_only_one;
} else
- panic("arch_setup_msi_irq: Unable to find a free MSI "
- "interrupt");
+ panic("arch_setup_msi_irq: Unable to find a free MSI interrupt");
}
/* MSI interrupts start at logical IRQ OCTEON_IRQ_MSI_BIT0 */
+ irq += index*64;
irq += OCTEON_IRQ_MSI_BIT0;
switch (octeon_dma_bar_type) {
@@ -169,6 +177,34 @@ try_only_one:
return 0;
}
+int arch_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
+{
+ struct msi_desc *entry;
+ int ret;
+
+ /*
+ * MSI-X is not supported.
+ */
+ if (type == PCI_CAP_ID_MSIX)
+ return -EINVAL;
+
+ /*
+ * If an architecture wants to support multiple MSI, it needs to
+ * override arch_setup_msi_irqs()
+ */
+ if (type == PCI_CAP_ID_MSI && nvec > 1)
+ return 1;
+
+ list_for_each_entry(entry, &dev->msi_list, list) {
+ ret = arch_setup_msi_irq(dev, entry);
+ if (ret < 0)
+ return ret;
+ if (ret > 0)
+ return -ENOSPC;
+ }
+
+ return 0;
+}
/**
* Called when a device no longer needs its MSI interrupts. All
@@ -179,12 +215,18 @@ try_only_one:
void arch_teardown_msi_irq(unsigned int irq)
{
int number_irqs;
- uint64_t bitmask;
+ u64 bitmask;
+ int index = 0;
+ int irq0;
- if ((irq < OCTEON_IRQ_MSI_BIT0) || (irq > OCTEON_IRQ_MSI_BIT63))
+ if ((irq < OCTEON_IRQ_MSI_BIT0)
+ || (irq > msi_irq_size + OCTEON_IRQ_MSI_BIT0))
panic("arch_teardown_msi_irq: Attempted to teardown illegal "
"MSI interrupt (%d)", irq);
+
irq -= OCTEON_IRQ_MSI_BIT0;
+ index = irq / 64;
+ irq0 = irq % 64;
/*
* Count the number of IRQs we need to free by looking at the
@@ -192,97 +234,198 @@ void arch_teardown_msi_irq(unsigned int irq)
* IRQ is also owned by this device.
*/
number_irqs = 0;
- while ((irq+number_irqs < 64) &&
- (msi_multiple_irq_bitmask & (1ull << (irq + number_irqs))))
+ while ((irq0 + number_irqs < 64) &&
+ (msi_multiple_irq_bitmask[index]
+ & (1ull << (irq0 + number_irqs))))
number_irqs++;
number_irqs++;
/* Mask with one bit for each IRQ */
bitmask = (1 << number_irqs) - 1;
/* Shift the mask to the correct bit location */
- bitmask <<= irq;
- if ((msi_free_irq_bitmask & bitmask) != bitmask)
+ bitmask <<= irq0;
+ if ((msi_free_irq_bitmask[index] & bitmask) != bitmask)
panic("arch_teardown_msi_irq: Attempted to teardown MSI "
"interrupt (%d) not in use", irq);
/* Checks are done, update the in use bitmask */
spin_lock(&msi_free_irq_bitmask_lock);
- msi_free_irq_bitmask &= ~bitmask;
- msi_multiple_irq_bitmask &= ~bitmask;
+ msi_free_irq_bitmask[index] &= ~bitmask;
+ msi_multiple_irq_bitmask[index] &= ~bitmask;
spin_unlock(&msi_free_irq_bitmask_lock);
}
+static DEFINE_RAW_SPINLOCK(octeon_irq_msi_lock);
+
+static u64 msi_rcv_reg[4];
+static u64 mis_ena_reg[4];
+
+static void octeon_irq_msi_enable_pcie(unsigned int irq)
+{
+ u64 en;
+ unsigned long flags;
+ int msi_number = irq - OCTEON_IRQ_MSI_BIT0;
+ int irq_index = msi_number >> 6;
+ int irq_bit = msi_number & 0x3f;
+
+ raw_spin_lock_irqsave(&octeon_irq_msi_lock, flags);
+ en = cvmx_read_csr(mis_ena_reg[irq_index]);
+ en |= 1ull << irq_bit;
+ cvmx_write_csr(mis_ena_reg[irq_index], en);
+ cvmx_read_csr(mis_ena_reg[irq_index]);
+ raw_spin_unlock_irqrestore(&octeon_irq_msi_lock, flags);
+}
+
+static void octeon_irq_msi_disable_pcie(unsigned int irq)
+{
+ u64 en;
+ unsigned long flags;
+ int msi_number = irq - OCTEON_IRQ_MSI_BIT0;
+ int irq_index = msi_number >> 6;
+ int irq_bit = msi_number & 0x3f;
+
+ raw_spin_lock_irqsave(&octeon_irq_msi_lock, flags);
+ en = cvmx_read_csr(mis_ena_reg[irq_index]);
+ en &= ~(1ull << irq_bit);
+ cvmx_write_csr(mis_ena_reg[irq_index], en);
+ cvmx_read_csr(mis_ena_reg[irq_index]);
+ raw_spin_unlock_irqrestore(&octeon_irq_msi_lock, flags);
+}
+
+static struct irq_chip octeon_irq_chip_msi_pcie = {
+ .name = "MSI",
+ .enable = octeon_irq_msi_enable_pcie,
+ .disable = octeon_irq_msi_disable_pcie,
+};
+
+static void octeon_irq_msi_enable_pci(unsigned int irq)
+{
+ /*
+ * Octeon PCI doesn't have the ability to mask/unmask MSI
+ * interrupts individually. Instead of masking/unmasking them
+ * in groups of 16, we simple assume MSI devices are well
+ * behaved. MSI interrupts are always enable and the ACK is
+ * assumed to be enough
+ */
+}
+
+static void octeon_irq_msi_disable_pci(unsigned int irq)
+{
+ /* See comment in enable */
+}
+
+static struct irq_chip octeon_irq_chip_msi_pci = {
+ .name = "MSI",
+ .enable = octeon_irq_msi_enable_pci,
+ .disable = octeon_irq_msi_disable_pci,
+};
/*
* Called by the interrupt handling code when an MSI interrupt
* occurs.
*/
-static irqreturn_t octeon_msi_interrupt(int cpl, void *dev_id)
+static irqreturn_t __octeon_msi_do_interrupt(int index, u64 msi_bits)
{
- uint64_t msi_bits;
int irq;
+ int bit;
- if (octeon_dma_bar_type == OCTEON_DMA_BAR_TYPE_PCIE)
- msi_bits = cvmx_read_csr(CVMX_PEXP_NPEI_MSI_RCV0);
- else
- msi_bits = cvmx_read_csr(CVMX_NPI_NPI_MSI_RCV);
- irq = fls64(msi_bits);
- if (irq) {
- irq += OCTEON_IRQ_MSI_BIT0 - 1;
- if (irq_desc[irq].action) {
- do_IRQ(irq);
- return IRQ_HANDLED;
- } else {
- pr_err("Spurious MSI interrupt %d\n", irq);
- if (octeon_has_feature(OCTEON_FEATURE_PCIE)) {
- /* These chips have PCIe */
- cvmx_write_csr(CVMX_PEXP_NPEI_MSI_RCV0,
- 1ull << (irq -
- OCTEON_IRQ_MSI_BIT0));
- } else {
- /* These chips have PCI */
- cvmx_write_csr(CVMX_NPI_NPI_MSI_RCV,
- 1ull << (irq -
- OCTEON_IRQ_MSI_BIT0));
- }
- }
+ bit = fls64(msi_bits);
+ if (bit) {
+ bit--;
+ /* Acknowledge it first. */
+ cvmx_write_csr(msi_rcv_reg[index], 1ull << bit);
+
+ irq = bit + OCTEON_IRQ_MSI_BIT0 + 64 * index;
+ do_IRQ(irq);
+ return IRQ_HANDLED;
}
return IRQ_NONE;
}
+#define OCTEON_MSI_INT_HANDLER_X(x) \
+static irqreturn_t octeon_msi_interrupt##x(int cpl, void *dev_id) \
+{ \
+ u64 msi_bits = cvmx_read_csr(msi_rcv_reg[(x)]); \
+ return __octeon_msi_do_interrupt((x), msi_bits); \
+}
+
+/*
+ * Create octeon_msi_interrupt{0-3} function body
+ */
+OCTEON_MSI_INT_HANDLER_X(0);
+OCTEON_MSI_INT_HANDLER_X(1);
+OCTEON_MSI_INT_HANDLER_X(2);
+OCTEON_MSI_INT_HANDLER_X(3);
/*
* Initializes the MSI interrupt handling code
*/
-int octeon_msi_initialize(void)
+int __init octeon_msi_initialize(void)
{
+ int irq;
+ struct irq_chip *msi;
+
+ if (octeon_dma_bar_type == OCTEON_DMA_BAR_TYPE_PCIE) {
+ msi_rcv_reg[0] = CVMX_PEXP_NPEI_MSI_RCV0;
+ msi_rcv_reg[1] = CVMX_PEXP_NPEI_MSI_RCV1;
+ msi_rcv_reg[2] = CVMX_PEXP_NPEI_MSI_RCV2;
+ msi_rcv_reg[3] = CVMX_PEXP_NPEI_MSI_RCV3;
+ mis_ena_reg[0] = CVMX_PEXP_NPEI_MSI_ENB0;
+ mis_ena_reg[1] = CVMX_PEXP_NPEI_MSI_ENB1;
+ mis_ena_reg[2] = CVMX_PEXP_NPEI_MSI_ENB2;
+ mis_ena_reg[3] = CVMX_PEXP_NPEI_MSI_ENB3;
+ msi = &octeon_irq_chip_msi_pcie;
+ } else {
+ msi_rcv_reg[0] = CVMX_NPI_NPI_MSI_RCV;
+#define INVALID_GENERATE_ADE 0x8700000000000000ULL;
+ msi_rcv_reg[1] = INVALID_GENERATE_ADE;
+ msi_rcv_reg[2] = INVALID_GENERATE_ADE;
+ msi_rcv_reg[3] = INVALID_GENERATE_ADE;
+ mis_ena_reg[0] = INVALID_GENERATE_ADE;
+ mis_ena_reg[1] = INVALID_GENERATE_ADE;
+ mis_ena_reg[2] = INVALID_GENERATE_ADE;
+ mis_ena_reg[3] = INVALID_GENERATE_ADE;
+ msi = &octeon_irq_chip_msi_pci;
+ }
+
+ for (irq = OCTEON_IRQ_MSI_BIT0; irq <= OCTEON_IRQ_MSI_LAST; irq++)
+ set_irq_chip_and_handler(irq, msi, handle_simple_irq);
+
if (octeon_has_feature(OCTEON_FEATURE_PCIE)) {
- if (request_irq(OCTEON_IRQ_PCI_MSI0, octeon_msi_interrupt,
- IRQF_SHARED,
- "MSI[0:63]", octeon_msi_interrupt))
+ if (request_irq(OCTEON_IRQ_PCI_MSI0, octeon_msi_interrupt0,
+ 0, "MSI[0:63]", octeon_msi_interrupt0))
panic("request_irq(OCTEON_IRQ_PCI_MSI0) failed");
+
+ if (request_irq(OCTEON_IRQ_PCI_MSI1, octeon_msi_interrupt1,
+ 0, "MSI[64:127]", octeon_msi_interrupt1))
+ panic("request_irq(OCTEON_IRQ_PCI_MSI1) failed");
+
+ if (request_irq(OCTEON_IRQ_PCI_MSI2, octeon_msi_interrupt2,
+ 0, "MSI[127:191]", octeon_msi_interrupt2))
+ panic("request_irq(OCTEON_IRQ_PCI_MSI2) failed");
+
+ if (request_irq(OCTEON_IRQ_PCI_MSI3, octeon_msi_interrupt3,
+ 0, "MSI[192:255]", octeon_msi_interrupt3))
+ panic("request_irq(OCTEON_IRQ_PCI_MSI3) failed");
+
+ msi_irq_size = 256;
} else if (octeon_is_pci_host()) {
- if (request_irq(OCTEON_IRQ_PCI_MSI0, octeon_msi_interrupt,
- IRQF_SHARED,
- "MSI[0:15]", octeon_msi_interrupt))
+ if (request_irq(OCTEON_IRQ_PCI_MSI0, octeon_msi_interrupt0,
+ 0, "MSI[0:15]", octeon_msi_interrupt0))
panic("request_irq(OCTEON_IRQ_PCI_MSI0) failed");
- if (request_irq(OCTEON_IRQ_PCI_MSI1, octeon_msi_interrupt,
- IRQF_SHARED,
- "MSI[16:31]", octeon_msi_interrupt))
+ if (request_irq(OCTEON_IRQ_PCI_MSI1, octeon_msi_interrupt0,
+ 0, "MSI[16:31]", octeon_msi_interrupt0))
panic("request_irq(OCTEON_IRQ_PCI_MSI1) failed");
- if (request_irq(OCTEON_IRQ_PCI_MSI2, octeon_msi_interrupt,
- IRQF_SHARED,
- "MSI[32:47]", octeon_msi_interrupt))
+ if (request_irq(OCTEON_IRQ_PCI_MSI2, octeon_msi_interrupt0,
+ 0, "MSI[32:47]", octeon_msi_interrupt0))
panic("request_irq(OCTEON_IRQ_PCI_MSI2) failed");
- if (request_irq(OCTEON_IRQ_PCI_MSI3, octeon_msi_interrupt,
- IRQF_SHARED,
- "MSI[48:63]", octeon_msi_interrupt))
+ if (request_irq(OCTEON_IRQ_PCI_MSI3, octeon_msi_interrupt0,
+ 0, "MSI[48:63]", octeon_msi_interrupt0))
panic("request_irq(OCTEON_IRQ_PCI_MSI3) failed");
-
+ msi_irq_size = 64;
}
return 0;
}
-
subsys_initcall(octeon_msi_initialize);
diff --git a/arch/mips/pci/ops-titan-ht.c b/arch/mips/pci/ops-titan-ht.c
index 749c1922d42..57d54adc9e2 100644
--- a/arch/mips/pci/ops-titan-ht.c
+++ b/arch/mips/pci/ops-titan-ht.c
@@ -32,7 +32,7 @@
#include <asm/titan_dep.h>
static int titan_ht_config_read_dword(struct pci_bus *bus, unsigned int devfn,
- int offset, u32 * val)
+ int offset, u32 *val)
{
volatile uint32_t address;
int busno;
@@ -64,7 +64,7 @@ static int titan_ht_config_read_dword(struct pci_bus *bus, unsigned int devfn,
}
static int titan_ht_config_read(struct pci_bus *bus, unsigned int devfn,
- int offset, int size, u32 * val)
+ int offset, int size, u32 *val)
{
uint32_t dword;
diff --git a/arch/mips/pci/pcie-octeon.c b/arch/mips/pci/pcie-octeon.c
index 6aa5c542d52..861361e0c9a 100644
--- a/arch/mips/pci/pcie-octeon.c
+++ b/arch/mips/pci/pcie-octeon.c
@@ -402,6 +402,10 @@ static void __cvmx_pcie_rc_initialize_config_space(int pcie_port)
npei_ctl_status2.s.mps = 0;
/* Max read request size = 128 bytes for best Octeon DMA performance */
npei_ctl_status2.s.mrrs = 0;
+ if (pcie_port)
+ npei_ctl_status2.s.c1_b1_s = 3; /* Port1 BAR1 Size 256MB */
+ else
+ npei_ctl_status2.s.c0_b1_s = 3; /* Port0 BAR1 Size 256MB */
cvmx_write_csr(CVMX_PEXP_NPEI_CTL_STATUS2, npei_ctl_status2.u64);
/* ECRC Generation (PCIE*_CFG070[GE,CE]) */
@@ -666,6 +670,8 @@ static int __cvmx_pcie_rc_initialize_link(int pcie_port)
static int cvmx_pcie_rc_initialize(int pcie_port)
{
int i;
+ int base;
+ u64 addr_swizzle;
union cvmx_ciu_soft_prst ciu_soft_prst;
union cvmx_pescx_bist_status pescx_bist_status;
union cvmx_pescx_bist_status2 pescx_bist_status2;
@@ -674,6 +680,7 @@ static int cvmx_pcie_rc_initialize(int pcie_port)
union cvmx_npei_mem_access_subidx mem_access_subid;
union cvmx_npei_dbg_data npei_dbg_data;
union cvmx_pescx_ctl_status2 pescx_ctl_status2;
+ union cvmx_npei_bar1_indexx bar1_index;
/*
* Make sure we aren't trying to setup a target mode interface
@@ -918,12 +925,30 @@ static int cvmx_pcie_rc_initialize(int pcie_port)
/* Set Octeon's BAR0 to decode 0-16KB. It overlaps with Bar2 */
cvmx_write_csr(CVMX_PESCX_P2N_BAR0_START(pcie_port), 0);
- /*
- * Disable Octeon's BAR1. It isn't needed in RC mode since
- * BAR2 maps all of memory. BAR2 also maps 256MB-512MB into
- * the 2nd 256MB of memory.
- */
- cvmx_write_csr(CVMX_PESCX_P2N_BAR1_START(pcie_port), -1);
+ /* BAR1 follows BAR2 with a gap. */
+ cvmx_write_csr(CVMX_PESCX_P2N_BAR1_START(pcie_port), CVMX_PCIE_BAR1_RC_BASE);
+
+ bar1_index.u32 = 0;
+ bar1_index.s.addr_idx = (CVMX_PCIE_BAR1_PHYS_BASE >> 22);
+ bar1_index.s.ca = 1; /* Not Cached */
+ bar1_index.s.end_swp = 1; /* Endian Swap mode */
+ bar1_index.s.addr_v = 1; /* Valid entry */
+
+ base = pcie_port ? 16 : 0;
+
+ /* Big endian swizzle for 32-bit PEXP_NCB register. */
+#ifdef __MIPSEB__
+ addr_swizzle = 4;
+#else
+ addr_swizzle = 0;
+#endif
+ for (i = 0; i < 16; i++) {
+ cvmx_write64_uint32((CVMX_PEXP_NPEI_BAR1_INDEXX(base) ^ addr_swizzle),
+ bar1_index.u32);
+ base++;
+ /* 256MB / 16 >> 22 == 4 */
+ bar1_index.s.addr_idx += (((1ull << 28) / 16ull) >> 22);
+ }
/*
* Set Octeon's BAR2 to decode 0-2^39. Bar0 and Bar1 take
diff --git a/arch/mips/pmc-sierra/Platform b/arch/mips/pmc-sierra/Platform
new file mode 100644
index 00000000000..f092f2524c5
--- /dev/null
+++ b/arch/mips/pmc-sierra/Platform
@@ -0,0 +1,14 @@
+#
+# PMC-Sierra MSP SOCs
+#
+platform-$(CONFIG_PMC_MSP) += pmc-sierra/msp71xx/
+cflags-$(CONFIG_PMC_MSP) += -I$(srctree)/arch/mips/include/asm/pmc-sierra/msp71xx \
+ -mno-branch-likely
+load-$(CONFIG_PMC_MSP) += 0xffffffff80100000
+
+#
+# PMC-Sierra Yosemite
+#
+platform-$(CONFIG_PMC_YOSEMITE) += pmc-sierra/yosemite/
+cflags-$(CONFIG_PMC_YOSEMITE) += -I$(srctree)/arch/mips/include/asm/mach-yosemite
+load-$(CONFIG_PMC_YOSEMITE) += 0xffffffff80100000
diff --git a/arch/mips/pmc-sierra/msp71xx/msp_hwbutton.c b/arch/mips/pmc-sierra/msp71xx/msp_hwbutton.c
index 11769b55438..c841f083a7f 100644
--- a/arch/mips/pmc-sierra/msp71xx/msp_hwbutton.c
+++ b/arch/mips/pmc-sierra/msp71xx/msp_hwbutton.c
@@ -32,9 +32,6 @@
#include <msp_int.h>
#include <msp_regs.h>
#include <msp_regops.h>
-#ifdef CONFIG_PMCTWILED
-#include <msp_led_macros.h>
-#endif
/* For hwbutton_interrupt->initial_state */
#define HWBUTTON_HI 0x1
@@ -82,10 +79,6 @@ static void standby_on(void *data)
printk(KERN_WARNING "STANDBY switch was set to ON (not implemented)\n");
/* TODO: Put board in standby mode */
-#ifdef CONFIG_PMCTWILED
- msp_led_turn_off(MSP_LED_PWRSTANDBY_GREEN);
- msp_led_turn_on(MSP_LED_PWRSTANDBY_RED);
-#endif
}
static void standby_off(void *data)
@@ -94,10 +87,6 @@ static void standby_off(void *data)
"STANDBY switch was set to OFF (not implemented)\n");
/* TODO: Take out of standby mode */
-#ifdef CONFIG_PMCTWILED
- msp_led_turn_on(MSP_LED_PWRSTANDBY_GREEN);
- msp_led_turn_off(MSP_LED_PWRSTANDBY_RED);
-#endif
}
static struct hwbutton_interrupt softreset_sw = {
diff --git a/arch/mips/pmc-sierra/yosemite/ht-irq.c b/arch/mips/pmc-sierra/yosemite/ht-irq.c
index 5aec4057314..86b98e98fb4 100644
--- a/arch/mips/pmc-sierra/yosemite/ht-irq.c
+++ b/arch/mips/pmc-sierra/yosemite/ht-irq.c
@@ -35,18 +35,17 @@
*/
void __init titan_ht_pcibios_fixup_bus(struct pci_bus *bus)
{
- struct pci_bus *current_bus = bus;
- struct pci_dev *devices;
- struct list_head *devices_link;
+ struct pci_bus *current_bus = bus;
+ struct pci_dev *devices;
+ struct list_head *devices_link;
list_for_each(devices_link, &(current_bus->devices)) {
- devices = pci_dev_b(devices_link);
- if (devices == NULL)
- continue;
+ devices = pci_dev_b(devices_link);
+ if (devices == NULL)
+ continue;
}
/*
* PLX and SPKT related changes go here
*/
-
}
diff --git a/arch/mips/pmc-sierra/yosemite/irq.c b/arch/mips/pmc-sierra/yosemite/irq.c
index 51021cfd04b..25bbbf428be 100644
--- a/arch/mips/pmc-sierra/yosemite/irq.c
+++ b/arch/mips/pmc-sierra/yosemite/irq.c
@@ -150,8 +150,4 @@ void __init arch_init_irq(void)
mips_cpu_irq_init();
rm7k_cpu_irq_init();
rm9k_cpu_irq_init();
-
-#ifdef CONFIG_GDB_CONSOLE
- register_gdb_console();
-#endif
}
diff --git a/arch/mips/pnx833x/Makefile b/arch/mips/pnx833x/Makefile
new file mode 100644
index 00000000000..02c4698cab0
--- /dev/null
+++ b/arch/mips/pnx833x/Makefile
@@ -0,0 +1,3 @@
+obj-$(CONFIG_SOC_PNX833X) += common/
+obj-$(CONFIG_NXP_STB220) += stb22x/
+obj-$(CONFIG_NXP_STB225) += stb22x/
diff --git a/arch/mips/pnx833x/Platform b/arch/mips/pnx833x/Platform
new file mode 100644
index 00000000000..7e6ec4dbc8d
--- /dev/null
+++ b/arch/mips/pnx833x/Platform
@@ -0,0 +1,5 @@
+# NXP STB225
+platform-$(CONFIG_SOC_PNX833X) += pnx833x/
+cflags-$(CONFIG_SOC_PNX833X) += -Iarch/mips/include/asm/mach-pnx833x
+load-$(CONFIG_NXP_STB220) += 0xffffffff80001000
+load-$(CONFIG_NXP_STB225) += 0xffffffff80001000
diff --git a/arch/mips/nxp/pnx833x/common/Makefile b/arch/mips/pnx833x/common/Makefile
index 4a16f3b503b..1a46dd291b1 100644
--- a/arch/mips/nxp/pnx833x/common/Makefile
+++ b/arch/mips/pnx833x/common/Makefile
@@ -1,3 +1 @@
obj-y := interrupts.o platform.o prom.o setup.o reset.o
-
-EXTRA_CFLAGS += -Werror
diff --git a/arch/mips/nxp/pnx833x/common/interrupts.c b/arch/mips/pnx833x/common/interrupts.c
index 941916f8aaf..941916f8aaf 100644
--- a/arch/mips/nxp/pnx833x/common/interrupts.c
+++ b/arch/mips/pnx833x/common/interrupts.c
diff --git a/arch/mips/nxp/pnx833x/common/platform.c b/arch/mips/pnx833x/common/platform.c
index 01f8345a206..01f8345a206 100644
--- a/arch/mips/nxp/pnx833x/common/platform.c
+++ b/arch/mips/pnx833x/common/platform.c
diff --git a/arch/mips/nxp/pnx833x/common/prom.c b/arch/mips/pnx833x/common/prom.c
index 29969f90a6b..29969f90a6b 100644
--- a/arch/mips/nxp/pnx833x/common/prom.c
+++ b/arch/mips/pnx833x/common/prom.c
diff --git a/arch/mips/nxp/pnx833x/common/reset.c b/arch/mips/pnx833x/common/reset.c
index e0ea96d29fd..e0ea96d29fd 100644
--- a/arch/mips/nxp/pnx833x/common/reset.c
+++ b/arch/mips/pnx833x/common/reset.c
diff --git a/arch/mips/nxp/pnx833x/common/setup.c b/arch/mips/pnx833x/common/setup.c
index e51fbc4b644..e51fbc4b644 100644
--- a/arch/mips/nxp/pnx833x/common/setup.c
+++ b/arch/mips/pnx833x/common/setup.c
diff --git a/arch/mips/pnx833x/stb22x/Makefile b/arch/mips/pnx833x/stb22x/Makefile
new file mode 100644
index 00000000000..7b580060de5
--- /dev/null
+++ b/arch/mips/pnx833x/stb22x/Makefile
@@ -0,0 +1 @@
+obj-y := board.o
diff --git a/arch/mips/nxp/pnx833x/stb22x/board.c b/arch/mips/pnx833x/stb22x/board.c
index 644eb7c3210..644eb7c3210 100644
--- a/arch/mips/nxp/pnx833x/stb22x/board.c
+++ b/arch/mips/pnx833x/stb22x/board.c
diff --git a/arch/mips/pnx8550/Makefile b/arch/mips/pnx8550/Makefile
new file mode 100644
index 00000000000..3f7e8561437
--- /dev/null
+++ b/arch/mips/pnx8550/Makefile
@@ -0,0 +1,3 @@
+obj-$(CONFIG_SOC_PNX8550) += common/
+obj-$(CONFIG_PNX8550_JBS) += jbs/
+obj-$(CONFIG_PNX8550_STB810) += stb810/
diff --git a/arch/mips/pnx8550/Platform b/arch/mips/pnx8550/Platform
new file mode 100644
index 00000000000..0e7fbde768d
--- /dev/null
+++ b/arch/mips/pnx8550/Platform
@@ -0,0 +1,7 @@
+platform-$(CONFIG_SOC_PNX8550) += pnx8550/
+
+cflags-$(CONFIG_SOC_PNX8550) += \
+ -I$(srctree)/arch/mips/include/asm/mach-pnx8550
+
+load-$(CONFIG_PNX8550_JBS) += 0xffffffff80060000
+load-$(CONFIG_PNX8550_STB810) += 0xffffffff80060000
diff --git a/arch/mips/nxp/pnx8550/common/Makefile b/arch/mips/pnx8550/common/Makefile
index dd9e7b1f7fd..f8ce695dc54 100644
--- a/arch/mips/nxp/pnx8550/common/Makefile
+++ b/arch/mips/pnx8550/common/Makefile
@@ -24,5 +24,3 @@
obj-y := setup.o prom.o int.o reset.o time.o proc.o platform.o
obj-$(CONFIG_PCI) += pci.o
-
-EXTRA_CFLAGS += -Werror
diff --git a/arch/mips/nxp/pnx8550/common/int.c b/arch/mips/pnx8550/common/int.c
index cfed5051dc6..cfed5051dc6 100644
--- a/arch/mips/nxp/pnx8550/common/int.c
+++ b/arch/mips/pnx8550/common/int.c
diff --git a/arch/mips/pnx8550/common/pci.c b/arch/mips/pnx8550/common/pci.c
new file mode 100644
index 00000000000..98e86ddb86c
--- /dev/null
+++ b/arch/mips/pnx8550/common/pci.c
@@ -0,0 +1,134 @@
+/*
+ *
+ * BRIEF MODULE DESCRIPTION
+ *
+ * Author: source@mvista.com
+ *
+ * This program is free software; you can distribute it and/or modify it
+ * under the terms of the GNU General Public License (Version 2) as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ */
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+
+#include <pci.h>
+#include <glb.h>
+#include <nand.h>
+
+static struct resource pci_io_resource = {
+ .start = PNX8550_PCIIO + 0x1000, /* reserve regacy I/O space */
+ .end = PNX8550_PCIIO + PNX8550_PCIIO_SIZE,
+ .name = "pci IO space",
+ .flags = IORESOURCE_IO
+};
+
+static struct resource pci_mem_resource = {
+ .start = PNX8550_PCIMEM,
+ .end = PNX8550_PCIMEM + PNX8550_PCIMEM_SIZE - 1,
+ .name = "pci memory space",
+ .flags = IORESOURCE_MEM
+};
+
+extern struct pci_ops pnx8550_pci_ops;
+
+static struct pci_controller pnx8550_controller = {
+ .pci_ops = &pnx8550_pci_ops,
+ .io_map_base = PNX8550_PORT_BASE,
+ .io_resource = &pci_io_resource,
+ .mem_resource = &pci_mem_resource,
+};
+
+/* Return the total size of DRAM-memory, (RANK0 + RANK1) */
+static inline unsigned long get_system_mem_size(void)
+{
+ /* Read IP2031_RANK0_ADDR_LO */
+ unsigned long dram_r0_lo = inl(PCI_BASE | 0x65010);
+ /* Read IP2031_RANK1_ADDR_HI */
+ unsigned long dram_r1_hi = inl(PCI_BASE | 0x65018);
+
+ return dram_r1_hi - dram_r0_lo + 1;
+}
+
+static int __init pnx8550_pci_setup(void)
+{
+ int pci_mem_code;
+ int mem_size = get_system_mem_size() >> 20;
+
+ /* Clear the Global 2 Register, PCI Inta Output Enable Registers
+ Bit 1:Enable DAC Powerdown
+ -> 0:DACs are enabled and are working normally
+ 1:DACs are powerdown
+ Bit 0:Enable of PCI inta output
+ -> 0 = Disable PCI inta output
+ 1 = Enable PCI inta output
+ */
+ PNX8550_GLB2_ENAB_INTA_O = 0;
+
+ /* Calc the PCI mem size code */
+ if (mem_size >= 128)
+ pci_mem_code = SIZE_128M;
+ else if (mem_size >= 64)
+ pci_mem_code = SIZE_64M;
+ else if (mem_size >= 32)
+ pci_mem_code = SIZE_32M;
+ else
+ pci_mem_code = SIZE_16M;
+
+ /* Set PCI_XIO registers */
+ outl(pci_mem_resource.start, PCI_BASE | PCI_BASE1_LO);
+ outl(pci_mem_resource.end + 1, PCI_BASE | PCI_BASE1_HI);
+ outl(pci_io_resource.start, PCI_BASE | PCI_BASE2_LO);
+ outl(pci_io_resource.end, PCI_BASE | PCI_BASE2_HI);
+
+ /* Send memory transaction via PCI_BASE2 */
+ outl(0x00000001, PCI_BASE | PCI_IO);
+
+ /* Unlock the setup register */
+ outl(0xca, PCI_BASE | PCI_UNLOCKREG);
+
+ /*
+ * BAR0 of PNX8550 (pci base 10) must be zero in order for ide
+ * to work, and in order for bus_to_baddr to work without any
+ * hacks.
+ */
+ outl(0x00000000, PCI_BASE | PCI_BASE10);
+
+ /*
+ *These two bars are set by default or the boot code.
+ * However, it's safer to set them here so we're not boot
+ * code dependent.
+ */
+ outl(0x1be00000, PCI_BASE | PCI_BASE14); /* PNX MMIO */
+ outl(PNX8550_NAND_BASE_ADDR, PCI_BASE | PCI_BASE18); /* XIO */
+
+ outl(PCI_EN_TA |
+ PCI_EN_PCI2MMI |
+ PCI_EN_XIO |
+ PCI_SETUP_BASE18_SIZE(SIZE_32M) |
+ PCI_SETUP_BASE18_EN |
+ PCI_SETUP_BASE14_EN |
+ PCI_SETUP_BASE10_PREF |
+ PCI_SETUP_BASE10_SIZE(pci_mem_code) |
+ PCI_SETUP_CFGMANAGE_EN |
+ PCI_SETUP_PCIARB_EN,
+ PCI_BASE |
+ PCI_SETUP); /* PCI_SETUP */
+ outl(0x00000000, PCI_BASE | PCI_CTRL); /* PCI_CONTROL */
+
+ register_pci_controller(&pnx8550_controller);
+
+ return 0;
+}
+
+arch_initcall(pnx8550_pci_setup);
diff --git a/arch/mips/nxp/pnx8550/common/platform.c b/arch/mips/pnx8550/common/platform.c
index 5264cc09a27..5264cc09a27 100644
--- a/arch/mips/nxp/pnx8550/common/platform.c
+++ b/arch/mips/pnx8550/common/platform.c
diff --git a/arch/mips/nxp/pnx8550/common/proc.c b/arch/mips/pnx8550/common/proc.c
index 3bba5ec828e..3bba5ec828e 100644
--- a/arch/mips/nxp/pnx8550/common/proc.c
+++ b/arch/mips/pnx8550/common/proc.c
diff --git a/arch/mips/nxp/pnx8550/common/prom.c b/arch/mips/pnx8550/common/prom.c
index 32f70097c3c..32f70097c3c 100644
--- a/arch/mips/nxp/pnx8550/common/prom.c
+++ b/arch/mips/pnx8550/common/prom.c
diff --git a/arch/mips/nxp/pnx8550/common/reset.c b/arch/mips/pnx8550/common/reset.c
index fadd8744a6b..fadd8744a6b 100644
--- a/arch/mips/nxp/pnx8550/common/reset.c
+++ b/arch/mips/pnx8550/common/reset.c
diff --git a/arch/mips/pnx8550/common/setup.c b/arch/mips/pnx8550/common/setup.c
new file mode 100644
index 00000000000..64246c9c875
--- /dev/null
+++ b/arch/mips/pnx8550/common/setup.c
@@ -0,0 +1,145 @@
+/*
+ *
+ * 2.6 port, Embedded Alley Solutions, Inc
+ *
+ * Based on Per Hallsmark, per.hallsmark@mvista.com
+ *
+ * This program is free software; you can distribute it and/or modify it
+ * under the terms of the GNU General Public License (Version 2) as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ */
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/ioport.h>
+#include <linux/irq.h>
+#include <linux/mm.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/serial_pnx8xxx.h>
+#include <linux/pm.h>
+
+#include <asm/cpu.h>
+#include <asm/bootinfo.h>
+#include <asm/irq.h>
+#include <asm/mipsregs.h>
+#include <asm/reboot.h>
+#include <asm/pgtable.h>
+#include <asm/time.h>
+
+#include <glb.h>
+#include <int.h>
+#include <pci.h>
+#include <uart.h>
+#include <nand.h>
+
+extern void __init board_setup(void);
+extern void pnx8550_machine_restart(char *);
+extern void pnx8550_machine_halt(void);
+extern void pnx8550_machine_power_off(void);
+extern struct resource ioport_resource;
+extern struct resource iomem_resource;
+extern char *prom_getcmdline(void);
+
+struct resource standard_io_resources[] = {
+ {
+ .start = 0x00,
+ .end = 0x1f,
+ .name = "dma1",
+ .flags = IORESOURCE_BUSY
+ }, {
+ .start = 0x40,
+ .end = 0x5f,
+ .name = "timer",
+ .flags = IORESOURCE_BUSY
+ }, {
+ .start = 0x80,
+ .end = 0x8f,
+ .name = "dma page reg",
+ .flags = IORESOURCE_BUSY
+ }, {
+ .start = 0xc0,
+ .end = 0xdf,
+ .name = "dma2",
+ .flags = IORESOURCE_BUSY
+ },
+};
+
+#define STANDARD_IO_RESOURCES ARRAY_SIZE(standard_io_resources)
+
+extern struct resource pci_io_resource;
+extern struct resource pci_mem_resource;
+
+/* Return the total size of DRAM-memory, (RANK0 + RANK1) */
+unsigned long get_system_mem_size(void)
+{
+ /* Read IP2031_RANK0_ADDR_LO */
+ unsigned long dram_r0_lo = inl(PCI_BASE | 0x65010);
+ /* Read IP2031_RANK1_ADDR_HI */
+ unsigned long dram_r1_hi = inl(PCI_BASE | 0x65018);
+
+ return dram_r1_hi - dram_r0_lo + 1;
+}
+
+int pnx8550_console_port = -1;
+
+void __init plat_mem_setup(void)
+{
+ int i;
+ char* argptr;
+
+ board_setup(); /* board specific setup */
+
+ _machine_restart = pnx8550_machine_restart;
+ _machine_halt = pnx8550_machine_halt;
+ pm_power_off = pnx8550_machine_power_off;
+
+ /* Clear the Global 2 Register, PCI Inta Output Enable Registers
+ Bit 1:Enable DAC Powerdown
+ -> 0:DACs are enabled and are working normally
+ 1:DACs are powerdown
+ Bit 0:Enable of PCI inta output
+ -> 0 = Disable PCI inta output
+ 1 = Enable PCI inta output
+ */
+ PNX8550_GLB2_ENAB_INTA_O = 0;
+
+ /* IO/MEM resources. */
+ set_io_port_base(PNX8550_PORT_BASE);
+ ioport_resource.start = 0;
+ ioport_resource.end = ~0;
+ iomem_resource.start = 0;
+ iomem_resource.end = ~0;
+
+ /* Request I/O space for devices on this board */
+ for (i = 0; i < STANDARD_IO_RESOURCES; i++)
+ request_resource(&ioport_resource, standard_io_resources + i);
+
+ /* Place the Mode Control bit for GPIO pin 16 in primary function */
+ /* Pin 16 is used by UART1, UA1_TX */
+ outl((PNX8550_GPIO_MODE_PRIMOP << PNX8550_GPIO_MC_16_BIT) |
+ (PNX8550_GPIO_MODE_PRIMOP << PNX8550_GPIO_MC_17_BIT),
+ PNX8550_GPIO_MC1);
+
+ argptr = prom_getcmdline();
+ if ((argptr = strstr(argptr, "console=ttyS")) != NULL) {
+ argptr += strlen("console=ttyS");
+ pnx8550_console_port = *argptr == '0' ? 0 : 1;
+
+ /* We must initialize the UART (console) before early printk */
+ /* Set LCR to 8-bit and BAUD to 38400 (no 5) */
+ ip3106_lcr(UART_BASE, pnx8550_console_port) =
+ PNX8XXX_UART_LCR_8BIT;
+ ip3106_baud(UART_BASE, pnx8550_console_port) = 5;
+ }
+
+ return;
+}
diff --git a/arch/mips/nxp/pnx8550/common/time.c b/arch/mips/pnx8550/common/time.c
index 8836c6203df..8836c6203df 100644
--- a/arch/mips/nxp/pnx8550/common/time.c
+++ b/arch/mips/pnx8550/common/time.c
diff --git a/arch/mips/pnx8550/jbs/Makefile b/arch/mips/pnx8550/jbs/Makefile
new file mode 100644
index 00000000000..c4dc3d53eb5
--- /dev/null
+++ b/arch/mips/pnx8550/jbs/Makefile
@@ -0,0 +1,4 @@
+
+# Makefile for the NXP JBS Board.
+
+obj-y := init.o board_setup.o irqmap.o
diff --git a/arch/mips/nxp/pnx8550/jbs/board_setup.c b/arch/mips/pnx8550/jbs/board_setup.c
index 57dd903ca40..57dd903ca40 100644
--- a/arch/mips/nxp/pnx8550/jbs/board_setup.c
+++ b/arch/mips/pnx8550/jbs/board_setup.c
diff --git a/arch/mips/nxp/pnx8550/jbs/init.c b/arch/mips/pnx8550/jbs/init.c
index d59b4a4e5e8..d59b4a4e5e8 100644
--- a/arch/mips/nxp/pnx8550/jbs/init.c
+++ b/arch/mips/pnx8550/jbs/init.c
diff --git a/arch/mips/nxp/pnx8550/jbs/irqmap.c b/arch/mips/pnx8550/jbs/irqmap.c
index 7fc89842002..7fc89842002 100644
--- a/arch/mips/nxp/pnx8550/jbs/irqmap.c
+++ b/arch/mips/pnx8550/jbs/irqmap.c
diff --git a/arch/mips/pnx8550/stb810/Makefile b/arch/mips/pnx8550/stb810/Makefile
new file mode 100644
index 00000000000..cb4ff022f1f
--- /dev/null
+++ b/arch/mips/pnx8550/stb810/Makefile
@@ -0,0 +1,4 @@
+
+# Makefile for the NXP STB810 Board.
+
+obj-y := prom_init.o board_setup.o irqmap.o
diff --git a/arch/mips/nxp/pnx8550/stb810/board_setup.c b/arch/mips/pnx8550/stb810/board_setup.c
index af2a55e0b4e..af2a55e0b4e 100644
--- a/arch/mips/nxp/pnx8550/stb810/board_setup.c
+++ b/arch/mips/pnx8550/stb810/board_setup.c
diff --git a/arch/mips/nxp/pnx8550/stb810/irqmap.c b/arch/mips/pnx8550/stb810/irqmap.c
index 8c034963ddc..8c034963ddc 100644
--- a/arch/mips/nxp/pnx8550/stb810/irqmap.c
+++ b/arch/mips/pnx8550/stb810/irqmap.c
diff --git a/arch/mips/nxp/pnx8550/stb810/prom_init.c b/arch/mips/pnx8550/stb810/prom_init.c
index ca7f4ada064..ca7f4ada064 100644
--- a/arch/mips/nxp/pnx8550/stb810/prom_init.c
+++ b/arch/mips/pnx8550/stb810/prom_init.c
diff --git a/arch/mips/powertv/Makefile b/arch/mips/powertv/Makefile
index 0a0d73c0564..baf6e9092a9 100644
--- a/arch/mips/powertv/Makefile
+++ b/arch/mips/powertv/Makefile
@@ -23,6 +23,9 @@
# under Linux.
#
-obj-y += init.o memory.o reset.o time.o powertv_setup.o asic/ pci/
+obj-y += init.o ioremap.o memory.o powertv_setup.o reset.o time.o \
+ asic/ pci/
-EXTRA_CFLAGS += -Wall -Werror
+obj-$(CONFIG_USB) += powertv-usb.o
+
+EXTRA_CFLAGS += -Wall
diff --git a/arch/mips/powertv/Platform b/arch/mips/powertv/Platform
new file mode 100644
index 00000000000..4eb5af1d8ee
--- /dev/null
+++ b/arch/mips/powertv/Platform
@@ -0,0 +1,7 @@
+#
+# Cisco PowerTV Platform
+#
+platform-$(CONFIG_POWERTV) += powertv/
+cflags-$(CONFIG_POWERTV) += \
+ -I$(srctree)/arch/mips/include/asm/mach-powertv
+load-$(CONFIG_POWERTV) += 0xffffffff90800000
diff --git a/arch/mips/powertv/asic/Makefile b/arch/mips/powertv/asic/Makefile
index bebfdcff044..f0e95dc0ac9 100644
--- a/arch/mips/powertv/asic/Makefile
+++ b/arch/mips/powertv/asic/Makefile
@@ -16,8 +16,8 @@
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
-obj-y += asic-calliope.o asic-cronus.o asic-zeus.o asic_devices.o asic_int.o \
- irq_asic.o prealloc-calliope.o prealloc-cronus.o \
- prealloc-cronuslite.o prealloc-zeus.o
+obj-y += asic-calliope.o asic-cronus.o asic-gaia.o asic-zeus.o \
+ asic_devices.o asic_int.o irq_asic.o prealloc-calliope.o \
+ prealloc-cronus.o prealloc-cronuslite.o prealloc-gaia.o prealloc-zeus.o
EXTRA_CFLAGS += -Wall -Werror
diff --git a/arch/mips/powertv/asic/asic-calliope.c b/arch/mips/powertv/asic/asic-calliope.c
index 1ae6623444b..0a170e0ffea 100644
--- a/arch/mips/powertv/asic/asic-calliope.c
+++ b/arch/mips/powertv/asic/asic-calliope.c
@@ -77,7 +77,7 @@ const struct register_map calliope_register_map __initdata = {
.int_docsis_en = {.phys = CALLIOPE_ADDR(0xA028F4)},
.mips_pll_setup = {.phys = CALLIOPE_ADDR(0x980000)},
- .usb_fs = {.phys = CALLIOPE_ADDR(0x980030)},
+ .fs432x4b4_usb_ctl = {.phys = CALLIOPE_ADDR(0x980030)},
.test_bus = {.phys = CALLIOPE_ADDR(0x9800CC)},
.crt_spare = {.phys = CALLIOPE_ADDR(0x9800d4)},
.usb2_ohci_int_mask = {.phys = CALLIOPE_ADDR(0x9A000c)},
diff --git a/arch/mips/powertv/asic/asic-cronus.c b/arch/mips/powertv/asic/asic-cronus.c
index 5bb64bfb508..bbc0c122be5 100644
--- a/arch/mips/powertv/asic/asic-cronus.c
+++ b/arch/mips/powertv/asic/asic-cronus.c
@@ -77,13 +77,13 @@ const struct register_map cronus_register_map __initdata = {
.int_docsis_en = {.phys = CRONUS_ADDR(0x2A28F4)},
.mips_pll_setup = {.phys = CRONUS_ADDR(0x1C0000)},
- .usb_fs = {.phys = CRONUS_ADDR(0x1C0018)},
+ .fs432x4b4_usb_ctl = {.phys = CRONUS_ADDR(0x1C0028)},
.test_bus = {.phys = CRONUS_ADDR(0x1C00CC)},
.crt_spare = {.phys = CRONUS_ADDR(0x1c00d4)},
.usb2_ohci_int_mask = {.phys = CRONUS_ADDR(0x20000C)},
.usb2_strap = {.phys = CRONUS_ADDR(0x200014)},
.ehci_hcapbase = {.phys = CRONUS_ADDR(0x21FE00)},
- .ohci_hc_revision = {.phys = CRONUS_ADDR(0x1E0000)},
+ .ohci_hc_revision = {.phys = CRONUS_ADDR(0x21fc00)},
.bcm1_bs_lmi_steer = {.phys = CRONUS_ADDR(0x2E0008)},
.usb2_control = {.phys = CRONUS_ADDR(0x2E004C)},
.usb2_stbus_obc = {.phys = CRONUS_ADDR(0x21FF00)},
diff --git a/arch/mips/powertv/asic/asic-gaia.c b/arch/mips/powertv/asic/asic-gaia.c
new file mode 100644
index 00000000000..91dda682752
--- /dev/null
+++ b/arch/mips/powertv/asic/asic-gaia.c
@@ -0,0 +1,96 @@
+/*
+ * Locations of devices in the Gaia ASIC
+ *
+ * Copyright (C) 2005-2009 Scientific-Atlanta, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Author: David VomLehn
+ */
+
+#include <linux/init.h>
+#include <asm/mach-powertv/asic.h>
+
+const struct register_map gaia_register_map __initdata = {
+ .eic_slow0_strt_add = {.phys = GAIA_IO_BASE + 0x000000},
+ .eic_cfg_bits = {.phys = GAIA_IO_BASE + 0x000038},
+ .eic_ready_status = {.phys = GAIA_IO_BASE + 0x00004C},
+
+ .chipver3 = {.phys = GAIA_IO_BASE + 0x2A0800},
+ .chipver2 = {.phys = GAIA_IO_BASE + 0x2A0804},
+ .chipver1 = {.phys = GAIA_IO_BASE + 0x2A0808},
+ .chipver0 = {.phys = GAIA_IO_BASE + 0x2A080C},
+
+ /* The registers of IRBlaster */
+ .uart1_intstat = {.phys = GAIA_IO_BASE + 0x2A1800},
+ .uart1_inten = {.phys = GAIA_IO_BASE + 0x2A1804},
+ .uart1_config1 = {.phys = GAIA_IO_BASE + 0x2A1808},
+ .uart1_config2 = {.phys = GAIA_IO_BASE + 0x2A180C},
+ .uart1_divisorhi = {.phys = GAIA_IO_BASE + 0x2A1810},
+ .uart1_divisorlo = {.phys = GAIA_IO_BASE + 0x2A1814},
+ .uart1_data = {.phys = GAIA_IO_BASE + 0x2A1818},
+ .uart1_status = {.phys = GAIA_IO_BASE + 0x2A181C},
+
+ .int_stat_3 = {.phys = GAIA_IO_BASE + 0x2A2800},
+ .int_stat_2 = {.phys = GAIA_IO_BASE + 0x2A2804},
+ .int_stat_1 = {.phys = GAIA_IO_BASE + 0x2A2808},
+ .int_stat_0 = {.phys = GAIA_IO_BASE + 0x2A280C},
+ .int_config = {.phys = GAIA_IO_BASE + 0x2A2810},
+ .int_int_scan = {.phys = GAIA_IO_BASE + 0x2A2818},
+ .ien_int_3 = {.phys = GAIA_IO_BASE + 0x2A2830},
+ .ien_int_2 = {.phys = GAIA_IO_BASE + 0x2A2834},
+ .ien_int_1 = {.phys = GAIA_IO_BASE + 0x2A2838},
+ .ien_int_0 = {.phys = GAIA_IO_BASE + 0x2A283C},
+ .int_level_3_3 = {.phys = GAIA_IO_BASE + 0x2A2880},
+ .int_level_3_2 = {.phys = GAIA_IO_BASE + 0x2A2884},
+ .int_level_3_1 = {.phys = GAIA_IO_BASE + 0x2A2888},
+ .int_level_3_0 = {.phys = GAIA_IO_BASE + 0x2A288C},
+ .int_level_2_3 = {.phys = GAIA_IO_BASE + 0x2A2890},
+ .int_level_2_2 = {.phys = GAIA_IO_BASE + 0x2A2894},
+ .int_level_2_1 = {.phys = GAIA_IO_BASE + 0x2A2898},
+ .int_level_2_0 = {.phys = GAIA_IO_BASE + 0x2A289C},
+ .int_level_1_3 = {.phys = GAIA_IO_BASE + 0x2A28A0},
+ .int_level_1_2 = {.phys = GAIA_IO_BASE + 0x2A28A4},
+ .int_level_1_1 = {.phys = GAIA_IO_BASE + 0x2A28A8},
+ .int_level_1_0 = {.phys = GAIA_IO_BASE + 0x2A28AC},
+ .int_level_0_3 = {.phys = GAIA_IO_BASE + 0x2A28B0},
+ .int_level_0_2 = {.phys = GAIA_IO_BASE + 0x2A28B4},
+ .int_level_0_1 = {.phys = GAIA_IO_BASE + 0x2A28B8},
+ .int_level_0_0 = {.phys = GAIA_IO_BASE + 0x2A28BC},
+ .int_docsis_en = {.phys = GAIA_IO_BASE + 0x2A28F4},
+
+ .mips_pll_setup = {.phys = GAIA_IO_BASE + 0x1C0000},
+ .fs432x4b4_usb_ctl = {.phys = GAIA_IO_BASE + 0x1C0024},
+ .test_bus = {.phys = GAIA_IO_BASE + 0x1C00CC},
+ .crt_spare = {.phys = GAIA_IO_BASE + 0x1c0108},
+ .usb2_ohci_int_mask = {.phys = GAIA_IO_BASE + 0x20000C},
+ .usb2_strap = {.phys = GAIA_IO_BASE + 0x200014},
+ .ehci_hcapbase = {.phys = GAIA_IO_BASE + 0x21FE00},
+ .ohci_hc_revision = {.phys = GAIA_IO_BASE + 0x21fc00},
+ .bcm1_bs_lmi_steer = {.phys = GAIA_IO_BASE + 0x2E0004},
+ .usb2_control = {.phys = GAIA_IO_BASE + 0x2E004C},
+ .usb2_stbus_obc = {.phys = GAIA_IO_BASE + 0x21FF00},
+ .usb2_stbus_mess_size = {.phys = GAIA_IO_BASE + 0x21FF04},
+ .usb2_stbus_chunk_size = {.phys = GAIA_IO_BASE + 0x21FF08},
+
+ .pcie_regs = {.phys = GAIA_IO_BASE + 0x220000},
+ .tim_ch = {.phys = GAIA_IO_BASE + 0x2A2C10},
+ .tim_cl = {.phys = GAIA_IO_BASE + 0x2A2C14},
+ .gpio_dout = {.phys = GAIA_IO_BASE + 0x2A2C20},
+ .gpio_din = {.phys = GAIA_IO_BASE + 0x2A2C24},
+ .gpio_dir = {.phys = GAIA_IO_BASE + 0x2A2C2C},
+ .watchdog = {.phys = GAIA_IO_BASE + 0x2A2C30},
+ .front_panel = {.phys = GAIA_IO_BASE + 0x2A3800},
+};
diff --git a/arch/mips/powertv/asic/asic-zeus.c b/arch/mips/powertv/asic/asic-zeus.c
index 095cbe10ebb..4a05bb09647 100644
--- a/arch/mips/powertv/asic/asic-zeus.c
+++ b/arch/mips/powertv/asic/asic-zeus.c
@@ -77,7 +77,7 @@ const struct register_map zeus_register_map __initdata = {
.int_docsis_en = {.phys = ZEUS_ADDR(0x2828F4)},
.mips_pll_setup = {.phys = ZEUS_ADDR(0x1a0000)},
- .usb_fs = {.phys = ZEUS_ADDR(0x1a0018)},
+ .fs432x4b4_usb_ctl = {.phys = ZEUS_ADDR(0x1a0018)},
.test_bus = {.phys = ZEUS_ADDR(0x1a0238)},
.crt_spare = {.phys = ZEUS_ADDR(0x1a0090)},
.usb2_ohci_int_mask = {.phys = ZEUS_ADDR(0x1e000c)},
diff --git a/arch/mips/powertv/asic/asic_devices.c b/arch/mips/powertv/asic/asic_devices.c
index 9ec523e4dd0..e56fa61b399 100644
--- a/arch/mips/powertv/asic/asic_devices.c
+++ b/arch/mips/powertv/asic/asic_devices.c
@@ -1,7 +1,6 @@
/*
- * ASIC Device List Intialization
*
- * Description: Defines the platform resources for the SA settop.
+ * Description: Defines the platform resources for Gaia-based settops.
*
* Copyright (C) 2005-2009 Scientific-Atlanta, Inc.
*
@@ -19,11 +18,6 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
- * Author: Ken Eppinett
- * David Schleef <ds@schleef.org>
- *
- * Description: Defines the platform resources for the SA settop.
- *
* NOTE: The bootloader allocates persistent memory at an address which is
* 16 MiB below the end of the highest address in KSEG0. All fixed
* address memory reservations must avoid this region.
@@ -39,7 +33,6 @@
#include <linux/mm.h>
#include <linux/platform_device.h>
#include <linux/module.h>
-#include <linux/gfp.h>
#include <asm/page.h>
#include <linux/swap.h>
#include <linux/highmem.h>
@@ -74,14 +67,13 @@ unsigned long asic_phy_base;
unsigned long asic_base;
EXPORT_SYMBOL(asic_base); /* Exported for testing */
struct resource *gp_resources;
-static bool usb_configured;
/*
* Don't recommend to use it directly, it is usually used by kernel internally.
* Portable code should be using interfaces such as ioremp, dma_map_single, etc.
*/
-unsigned long phys_to_bus_offset;
-EXPORT_SYMBOL(phys_to_bus_offset);
+unsigned long phys_to_dma_offset;
+EXPORT_SYMBOL(phys_to_dma_offset);
/*
*
@@ -97,101 +89,19 @@ struct resource asic_resource = {
};
/*
- *
- * USB Host Resource Definition
- *
- */
-
-static struct resource ehci_resources[] = {
- {
- .parent = &asic_resource,
- .start = 0,
- .end = 0xff,
- .flags = IORESOURCE_MEM,
- },
- {
- .start = irq_usbehci,
- .end = irq_usbehci,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static u64 ehci_dmamask = DMA_BIT_MASK(32);
-
-static struct platform_device ehci_device = {
- .name = "powertv-ehci",
- .id = 0,
- .num_resources = 2,
- .resource = ehci_resources,
- .dev = {
- .dma_mask = &ehci_dmamask,
- .coherent_dma_mask = DMA_BIT_MASK(32),
- },
-};
-
-static struct resource ohci_resources[] = {
- {
- .parent = &asic_resource,
- .start = 0,
- .end = 0xff,
- .flags = IORESOURCE_MEM,
- },
- {
- .start = irq_usbohci,
- .end = irq_usbohci,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static u64 ohci_dmamask = DMA_BIT_MASK(32);
-
-static struct platform_device ohci_device = {
- .name = "powertv-ohci",
- .id = 0,
- .num_resources = 2,
- .resource = ohci_resources,
- .dev = {
- .dma_mask = &ohci_dmamask,
- .coherent_dma_mask = DMA_BIT_MASK(32),
- },
-};
-
-static struct platform_device *platform_devices[] = {
- &ehci_device,
- &ohci_device,
-};
-
-/*
- *
- * Platform Configuration and Device Initialization
- *
- */
-static void __init fs_update(int pe, int md, int sdiv, int disable_div_by_3)
-{
- int en_prg, byp, pwr, nsb, val;
- int sout;
-
- sout = 1;
- en_prg = 1;
- byp = 0;
- nsb = 1;
- pwr = 1;
-
- val = ((sdiv << 29) | (md << 24) | (pe<<8) | (sout<<3) | (byp<<2) |
- (nsb<<1) | (disable_div_by_3<<5));
-
- asic_write(val, usb_fs);
- asic_write(val | (en_prg<<4), usb_fs);
- asic_write(val | (en_prg<<4) | pwr, usb_fs);
-}
-
-/*
* Allow override of bootloader-specified model
+ * Returns zero on success, a negative errno value on failure. This parameter
+ * allows overriding of the bootloader-specified model.
*/
static char __initdata cmdline[COMMAND_LINE_SIZE];
#define FORCEFAMILY_PARAM "forcefamily"
+/*
+ * check_forcefamily - check for, and parse, forcefamily command line parameter
+ * @forced_family: Pointer to two-character array in which to store the
+ * value of the forcedfamily parameter, if any.
+ */
static __init int check_forcefamily(unsigned char forced_family[2])
{
const char *p;
@@ -231,14 +141,10 @@ static __init int check_forcefamily(unsigned char forced_family[2])
*/
static __init noinline void platform_set_family(void)
{
-#define BOOTLDRFAMILY(byte1, byte0) (((byte1) << 8) | (byte0))
-
unsigned char forced_family[2];
unsigned short bootldr_family;
- check_forcefamily(forced_family);
-
- if (forced_family[0] != '\0' && forced_family[1] != '\0')
+ if (check_forcefamily(forced_family) == 0)
bootldr_family = BOOTLDRFAMILY(forced_family[0],
forced_family[1]);
else {
@@ -289,6 +195,9 @@ static __init noinline void platform_set_family(void)
case BOOTLDRFAMILY('F', '1'):
platform_family = FAMILY_1500VZF;
break;
+ case BOOTLDRFAMILY('8', '7'):
+ platform_family = FAMILY_8700;
+ break;
default:
platform_family = -1;
}
@@ -301,24 +210,9 @@ unsigned int platform_get_family(void)
EXPORT_SYMBOL(platform_get_family);
/*
- * \brief usb_eye_configure() for optimizing the USB eye on Calliope.
- *
- * \param unsigned int value saved to the register.
- *
- * \return none
- *
- */
-static void __init usb_eye_configure(unsigned int value)
-{
- asic_write(asic_read(crt_spare) | value, crt_spare);
-}
-
-/*
* platform_get_asic - determine the ASIC type.
*
- * \param none
- *
- * \return ASIC type; ASIC_UNKNOWN if none
+ * Returns the ASIC type, or ASIC_UNKNOWN if unknown
*
*/
enum asic_type platform_get_asic(void)
@@ -328,93 +222,10 @@ enum asic_type platform_get_asic(void)
EXPORT_SYMBOL(platform_get_asic);
/*
- * platform_configure_usb - usb configuration based on platform type.
- * @bcm1_usb2_ctl: value for the BCM1_USB2_CTL register, which is
- * quirky
- */
-static void __init platform_configure_usb(void)
-{
- u32 bcm1_usb2_ctl;
-
- if (usb_configured)
- return;
-
- switch (asic) {
- case ASIC_ZEUS:
- case ASIC_CRONUS:
- case ASIC_CRONUSLITE:
- fs_update(0x0000, 0x11, 0x02, 0);
- bcm1_usb2_ctl = 0x803;
- break;
-
- case ASIC_CALLIOPE:
- fs_update(0x0000, 0x11, 0x02, 1);
-
- switch (platform_family) {
- case FAMILY_1500VZE:
- break;
-
- case FAMILY_1500VZF:
- usb_eye_configure(0x003c0000);
- break;
-
- default:
- usb_eye_configure(0x00300000);
- break;
- }
-
- bcm1_usb2_ctl = 0x803;
- break;
-
- default:
- pr_err("Unknown ASIC type: %d\n", asic);
- break;
- }
-
- /* turn on USB power */
- asic_write(0, usb2_strap);
- /* Enable all OHCI interrupts */
- asic_write(bcm1_usb2_ctl, usb2_control);
- /* USB2_STBUS_OBC store32/load32 */
- asic_write(3, usb2_stbus_obc);
- /* USB2_STBUS_MESS_SIZE 2 packets */
- asic_write(1, usb2_stbus_mess_size);
- /* USB2_STBUS_CHUNK_SIZE 2 packets */
- asic_write(1, usb2_stbus_chunk_size);
-
- usb_configured = true;
-}
-
-/*
- * Set up the USB EHCI interface
+ * set_register_map - set ASIC register configuration
+ * @phys_base: Physical address of the base of the ASIC registers
+ * @map: Description of key ASIC registers
*/
-void platform_configure_usb_ehci()
-{
- platform_configure_usb();
-}
-
-/*
- * Set up the USB OHCI interface
- */
-void platform_configure_usb_ohci()
-{
- platform_configure_usb();
-}
-
-/*
- * Shut the USB EHCI interface down--currently a NOP
- */
-void platform_unconfigure_usb_ehci()
-{
-}
-
-/*
- * Shut the USB OHCI interface down--currently a NOP
- */
-void platform_unconfigure_usb_ohci()
-{
-}
-
static void __init set_register_map(unsigned long phys_base,
const struct register_map *map)
{
@@ -526,6 +337,15 @@ void __init configure_platform(void)
"DVR_CAPABLE\n");
break;
+ case FAMILY_8700:
+ platform_features = FFS_CAPABLE | PCIE_CAPABLE;
+ asic = ASIC_GAIA;
+ set_register_map(GAIA_IO_BASE, &gaia_register_map);
+ gp_resources = dvr_gaia_resources;
+
+ pr_info("Platform: 8700 - GAIA, DVR_CAPABLE\n");
+ break;
+
default:
pr_crit("Platform: UNKNOWN PLATFORM\n");
break;
@@ -533,10 +353,10 @@ void __init configure_platform(void)
switch (asic) {
case ASIC_ZEUS:
- phys_to_bus_offset = 0x30000000;
+ phys_to_dma_offset = 0x30000000;
break;
case ASIC_CALLIOPE:
- phys_to_bus_offset = 0x10000000;
+ phys_to_dma_offset = 0x10000000;
break;
case ASIC_CRONUSLITE:
/* Fall through */
@@ -546,42 +366,16 @@ void __init configure_platform(void)
* 0x2XXXXXXX. If 0x10000000 aliases into 0x60000000-
* 0x6XXXXXXX, the offset should be 0x50000000, not 0x10000000.
*/
- phys_to_bus_offset = 0x10000000;
+ phys_to_dma_offset = 0x10000000;
break;
default:
- phys_to_bus_offset = 0x00000000;
+ phys_to_dma_offset = 0x00000000;
break;
}
}
-/**
- * platform_devices_init - sets up USB device resourse.
- */
-static int __init platform_devices_init(void)
-{
- pr_notice("%s: ----- Initializing USB resources -----\n", __func__);
-
- asic_resource.start = asic_phy_base;
- asic_resource.end += asic_resource.start;
-
- ehci_resources[0].start = asic_reg_phys_addr(ehci_hcapbase);
- ehci_resources[0].end += ehci_resources[0].start;
-
- ohci_resources[0].start = asic_reg_phys_addr(ohci_hc_revision);
- ohci_resources[0].end += ohci_resources[0].start;
-
- set_io_port_base(0);
-
- platform_add_devices(platform_devices, ARRAY_SIZE(platform_devices));
-
- return 0;
-}
-
-arch_initcall(platform_devices_init);
-
/*
- *
- * BOOTMEM ALLOCATION
+ * RESOURCE ALLOCATION
*
*/
/*
@@ -603,7 +397,7 @@ void __init platform_alloc_bootmem(void)
int size = gp_resources[i].end - gp_resources[i].start + 1;
if ((gp_resources[i].start != 0) &&
((gp_resources[i].flags & IORESOURCE_MEM) != 0)) {
- reserve_bootmem(bus_to_phys(gp_resources[i].start),
+ reserve_bootmem(dma_to_phys(gp_resources[i].start),
size, 0);
total += gp_resources[i].end -
gp_resources[i].start + 1;
@@ -627,7 +421,7 @@ void __init platform_alloc_bootmem(void)
else {
gp_resources[i].start =
- phys_to_bus(virt_to_phys(mem));
+ phys_to_dma(virt_to_phys(mem));
gp_resources[i].end =
gp_resources[i].start + size - 1;
total += size;
@@ -691,7 +485,7 @@ static void __init pmem_setup_resource(void)
if (resource && pmemaddr && pmemlen) {
/* The address provided by bootloader is in kseg0. Convert to
* a bus address. */
- resource->start = phys_to_bus(pmemaddr - 0x80000000);
+ resource->start = phys_to_dma(pmemaddr - 0x80000000);
resource->end = resource->start + pmemlen - 1;
pr_info("persistent memory: start=0x%x end=0x%x\n",
diff --git a/arch/mips/powertv/asic/prealloc-gaia.c b/arch/mips/powertv/asic/prealloc-gaia.c
new file mode 100644
index 00000000000..8ac8c7aeb98
--- /dev/null
+++ b/arch/mips/powertv/asic/prealloc-gaia.c
@@ -0,0 +1,589 @@
+/*
+ * Memory pre-allocations for Gaia boxes.
+ *
+ * Copyright (C) 2005-2009 Scientific-Atlanta, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Author: David VomLehn
+ */
+
+#include <linux/init.h>
+#include <asm/mach-powertv/asic.h>
+
+/*
+ * DVR_CAPABLE GAIA RESOURCES
+ */
+struct resource dvr_gaia_resources[] __initdata = {
+ /*
+ *
+ * VIDEO1 / LX1
+ *
+ */
+ {
+ .name = "ST231aImage", /* Delta-Mu 1 image and ram */
+ .start = 0x24000000,
+ .end = 0x241FFFFF, /* 2MiB */
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .name = "ST231aMonitor", /* 8KiB block ST231a monitor */
+ .start = 0x24200000,
+ .end = 0x24201FFF,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .name = "MediaMemory1",
+ .start = 0x24202000,
+ .end = 0x25FFFFFF, /*~29.9MiB (32MiB - (2MiB + 8KiB)) */
+ .flags = IORESOURCE_MEM,
+ },
+ /*
+ *
+ * VIDEO2 / LX2
+ *
+ */
+ {
+ .name = "ST231bImage", /* Delta-Mu 2 image and ram */
+ .start = 0x60000000,
+ .end = 0x601FFFFF, /* 2MiB */
+ .flags = IORESOURCE_IO,
+ },
+ {
+ .name = "ST231bMonitor", /* 8KiB block ST231b monitor */
+ .start = 0x60200000,
+ .end = 0x60201FFF,
+ .flags = IORESOURCE_IO,
+ },
+ {
+ .name = "MediaMemory2",
+ .start = 0x60202000,
+ .end = 0x61FFFFFF, /*~29.9MiB (32MiB - (2MiB + 8KiB)) */
+ .flags = IORESOURCE_IO,
+ },
+ /*
+ *
+ * Sysaudio Driver
+ *
+ * This driver requires:
+ *
+ * Arbitrary Based Buffers:
+ * DSP_Image_Buff - DSP code and data images (1MB)
+ * ADSC_CPU_PCM_Buff - ADSC CPU PCM buffer (40KB)
+ * ADSC_AUX_Buff - ADSC AUX buffer (16KB)
+ * ADSC_Main_Buff - ADSC Main buffer (16KB)
+ *
+ */
+ {
+ .name = "DSP_Image_Buff",
+ .start = 0x00000000,
+ .end = 0x000FFFFF,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .name = "ADSC_CPU_PCM_Buff",
+ .start = 0x00000000,
+ .end = 0x00009FFF,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .name = "ADSC_AUX_Buff",
+ .start = 0x00000000,
+ .end = 0x00003FFF,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .name = "ADSC_Main_Buff",
+ .start = 0x00000000,
+ .end = 0x00003FFF,
+ .flags = IORESOURCE_MEM,
+ },
+ /*
+ *
+ * STAVEM driver/STAPI
+ *
+ * This driver requires:
+ *
+ * Arbitrary Based Buffers:
+ * This memory area is used for allocating buffers for Video decoding
+ * purposes. Allocation/De-allocation within this buffer is managed
+ * by the STAVMEM driver of the STAPI. They could be Decimated
+ * Picture Buffers, Intermediate Buffers, as deemed necessary for
+ * video decoding purposes, for any video decoders on Zeus.
+ *
+ */
+ {
+ .name = "AVMEMPartition0",
+ .start = 0x63580000,
+ .end = 0x64180000 - 1, /* 12 MB total */
+ .flags = IORESOURCE_IO,
+ },
+ /*
+ *
+ * DOCSIS Subsystem
+ *
+ * This driver requires:
+ *
+ * Arbitrary Based Buffers:
+ * Docsis -
+ *
+ */
+ {
+ .name = "Docsis",
+ .start = 0x62000000,
+ .end = 0x62700000 - 1, /* 7 MB total */
+ .flags = IORESOURCE_IO,
+ },
+ /*
+ *
+ * GHW HAL Driver
+ *
+ * This driver requires:
+ *
+ * Arbitrary Based Buffers:
+ * GraphicsHeap - PowerTV Graphics Heap
+ *
+ */
+ {
+ .name = "GraphicsHeap",
+ .start = 0x62700000,
+ .end = 0x63500000 - 1, /* 14 MB total */
+ .flags = IORESOURCE_IO,
+ },
+ /*
+ *
+ * multi com buffer area
+ *
+ * This driver requires:
+ *
+ * Arbitrary Based Buffers:
+ * Docsis -
+ *
+ */
+ {
+ .name = "MulticomSHM",
+ .start = 0x26000000,
+ .end = 0x26020000 - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ /*
+ *
+ * DMA Ring buffer
+ *
+ * This driver requires:
+ *
+ * Arbitrary Based Buffers:
+ * Docsis -
+ *
+ */
+ {
+ .name = "BMM_Buffer",
+ .start = 0x00000000,
+ .end = 0x00280000 - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ /*
+ *
+ * Display bins buffer for unit0
+ *
+ * This driver requires:
+ *
+ * Arbitrary Based Buffers:
+ * Display Bins for unit0
+ *
+ */
+ {
+ .name = "DisplayBins0",
+ .start = 0x00000000,
+ .end = 0x00000FFF, /* 4 KB total */
+ .flags = IORESOURCE_MEM,
+ },
+ /*
+ *
+ * Display bins buffer
+ *
+ * This driver requires:
+ *
+ * Arbitrary Based Buffers:
+ * Display Bins for unit1
+ *
+ */
+ {
+ .name = "DisplayBins1",
+ .start = 0x64AD4000,
+ .end = 0x64AD5000 - 1, /* 4 KB total */
+ .flags = IORESOURCE_IO,
+ },
+ /*
+ *
+ * ITFS
+ *
+ * This driver requires:
+ *
+ * Arbitrary Based Buffers:
+ * Docsis -
+ *
+ */
+ {
+ .name = "ITFS",
+ .start = 0x64180000,
+ /* 815,104 bytes each for 2 ITFS partitions. */
+ .end = 0x6430DFFF,
+ .flags = IORESOURCE_IO,
+ },
+ /*
+ *
+ * AVFS
+ *
+ * This driver requires:
+ *
+ * Arbitrary Based Buffers:
+ * Docsis -
+ *
+ */
+ {
+ .name = "AvfsDmaMem",
+ .start = 0x6430E000,
+ /* (945K * 8) = (128K *3) 5 playbacks / 3 server */
+ .end = 0x64AD0000 - 1,
+ .flags = IORESOURCE_IO,
+ },
+ {
+ .name = "AvfsFileSys",
+ .start = 0x64AD0000,
+ .end = 0x64AD1000 - 1, /* 4K */
+ .flags = IORESOURCE_IO,
+ },
+ /*
+ *
+ * Smartcard
+ *
+ * This driver requires:
+ *
+ * Arbitrary Based Buffers:
+ * Read and write buffers for Internal/External cards
+ *
+ */
+ {
+ .name = "SmartCardInfo",
+ .start = 0x64AD1000,
+ .end = 0x64AD3800 - 1,
+ .flags = IORESOURCE_IO,
+ },
+ /*
+ *
+ * KAVNET
+ * NP Reset Vector - must be of the form xxCxxxxx
+ * NP Image - must be video bank 1
+ * NP IPC - must be video bank 2
+ */
+ {
+ .name = "NP_Reset_Vector",
+ .start = 0x27c00000,
+ .end = 0x27c01000 - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .name = "NP_Image",
+ .start = 0x27020000,
+ .end = 0x27060000 - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .name = "NP_IPC",
+ .start = 0x63500000,
+ .end = 0x63580000 - 1,
+ .flags = IORESOURCE_IO,
+ },
+ /*
+ * Add other resources here
+ */
+ { },
+};
+
+/*
+ * NON_DVR_CAPABLE GAIA RESOURCES
+ */
+struct resource non_dvr_gaia_resources[] __initdata = {
+ /*
+ *
+ * VIDEO1 / LX1
+ *
+ */
+ {
+ .name = "ST231aImage", /* Delta-Mu 1 image and ram */
+ .start = 0x24000000,
+ .end = 0x241FFFFF, /* 2MiB */
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .name = "ST231aMonitor", /* 8KiB block ST231a monitor */
+ .start = 0x24200000,
+ .end = 0x24201FFF,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .name = "MediaMemory1",
+ .start = 0x24202000,
+ .end = 0x25FFFFFF, /*~29.9MiB (32MiB - (2MiB + 8KiB)) */
+ .flags = IORESOURCE_MEM,
+ },
+ /*
+ *
+ * VIDEO2 / LX2
+ *
+ */
+ {
+ .name = "ST231bImage", /* Delta-Mu 2 image and ram */
+ .start = 0x60000000,
+ .end = 0x601FFFFF, /* 2MiB */
+ .flags = IORESOURCE_IO,
+ },
+ {
+ .name = "ST231bMonitor", /* 8KiB block ST231b monitor */
+ .start = 0x60200000,
+ .end = 0x60201FFF,
+ .flags = IORESOURCE_IO,
+ },
+ {
+ .name = "MediaMemory2",
+ .start = 0x60202000,
+ .end = 0x61FFFFFF, /*~29.9MiB (32MiB - (2MiB + 8KiB)) */
+ .flags = IORESOURCE_IO,
+ },
+ /*
+ *
+ * Sysaudio Driver
+ *
+ * This driver requires:
+ *
+ * Arbitrary Based Buffers:
+ * DSP_Image_Buff - DSP code and data images (1MB)
+ * ADSC_CPU_PCM_Buff - ADSC CPU PCM buffer (40KB)
+ * ADSC_AUX_Buff - ADSC AUX buffer (16KB)
+ * ADSC_Main_Buff - ADSC Main buffer (16KB)
+ *
+ */
+ {
+ .name = "DSP_Image_Buff",
+ .start = 0x00000000,
+ .end = 0x000FFFFF,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .name = "ADSC_CPU_PCM_Buff",
+ .start = 0x00000000,
+ .end = 0x00009FFF,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .name = "ADSC_AUX_Buff",
+ .start = 0x00000000,
+ .end = 0x00003FFF,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .name = "ADSC_Main_Buff",
+ .start = 0x00000000,
+ .end = 0x00003FFF,
+ .flags = IORESOURCE_MEM,
+ },
+ /*
+ *
+ * STAVEM driver/STAPI
+ *
+ * This driver requires:
+ *
+ * Arbitrary Based Buffers:
+ * This memory area is used for allocating buffers for Video decoding
+ * purposes. Allocation/De-allocation within this buffer is managed
+ * by the STAVMEM driver of the STAPI. They could be Decimated
+ * Picture Buffers, Intermediate Buffers, as deemed necessary for
+ * video decoding purposes, for any video decoders on Zeus.
+ *
+ */
+ {
+ .name = "AVMEMPartition0",
+ .start = 0x63580000,
+ .end = 0x64180000 - 1, /* 12 MB total */
+ .flags = IORESOURCE_IO,
+ },
+ /*
+ *
+ * DOCSIS Subsystem
+ *
+ * This driver requires:
+ *
+ * Arbitrary Based Buffers:
+ * Docsis -
+ *
+ */
+ {
+ .name = "Docsis",
+ .start = 0x62000000,
+ .end = 0x62700000 - 1, /* 7 MB total */
+ .flags = IORESOURCE_IO,
+ },
+ /*
+ *
+ * GHW HAL Driver
+ *
+ * This driver requires:
+ *
+ * Arbitrary Based Buffers:
+ * GraphicsHeap - PowerTV Graphics Heap
+ *
+ */
+ {
+ .name = "GraphicsHeap",
+ .start = 0x62700000,
+ .end = 0x63500000 - 1, /* 14 MB total */
+ .flags = IORESOURCE_IO,
+ },
+ /*
+ *
+ * multi com buffer area
+ *
+ * This driver requires:
+ *
+ * Arbitrary Based Buffers:
+ * Docsis -
+ *
+ */
+ {
+ .name = "MulticomSHM",
+ .start = 0x26000000,
+ .end = 0x26020000 - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ /*
+ *
+ * DMA Ring buffer
+ *
+ * This driver requires:
+ *
+ * Arbitrary Based Buffers:
+ * Docsis -
+ *
+ */
+ {
+ .name = "BMM_Buffer",
+ .start = 0x00000000,
+ .end = 0x000AA000 - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ /*
+ *
+ * Display bins buffer for unit0
+ *
+ * This driver requires:
+ *
+ * Arbitrary Based Buffers:
+ * Display Bins for unit0
+ *
+ */
+ {
+ .name = "DisplayBins0",
+ .start = 0x00000000,
+ .end = 0x00000FFF, /* 4 KB total */
+ .flags = IORESOURCE_MEM,
+ },
+ /*
+ *
+ * Display bins buffer
+ *
+ * This driver requires:
+ *
+ * Arbitrary Based Buffers:
+ * Display Bins for unit1
+ *
+ */
+ {
+ .name = "DisplayBins1",
+ .start = 0x64AD4000,
+ .end = 0x64AD5000 - 1, /* 4 KB total */
+ .flags = IORESOURCE_IO,
+ },
+ /*
+ *
+ * AVFS: player HAL memory
+ *
+ *
+ */
+ {
+ .name = "AvfsDmaMem",
+ .start = 0x6430E000,
+ .end = 0x645D2C00 - 1, /* 945K * 3 for playback */
+ .flags = IORESOURCE_IO,
+ },
+ /*
+ *
+ * PMEM
+ *
+ * This driver requires:
+ *
+ * Arbitrary Based Buffers:
+ * Persistent memory for diagnostics.
+ *
+ */
+ {
+ .name = "DiagPersistentMemory",
+ .start = 0x00000000,
+ .end = 0x10000 - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ /*
+ *
+ * Smartcard
+ *
+ * This driver requires:
+ *
+ * Arbitrary Based Buffers:
+ * Read and write buffers for Internal/External cards
+ *
+ */
+ {
+ .name = "SmartCardInfo",
+ .start = 0x64AD1000,
+ .end = 0x64AD3800 - 1,
+ .flags = IORESOURCE_IO,
+ },
+ /*
+ *
+ * KAVNET
+ * NP Reset Vector - must be of the form xxCxxxxx
+ * NP Image - must be video bank 1
+ * NP IPC - must be video bank 2
+ */
+ {
+ .name = "NP_Reset_Vector",
+ .start = 0x27c00000,
+ .end = 0x27c01000 - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .name = "NP_Image",
+ .start = 0x27020000,
+ .end = 0x27060000 - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .name = "NP_IPC",
+ .start = 0x63500000,
+ .end = 0x63580000 - 1,
+ .flags = IORESOURCE_IO,
+ },
+ { },
+};
diff --git a/arch/mips/powertv/init.c b/arch/mips/powertv/init.c
index 0afe227f1d0..83552288e80 100644
--- a/arch/mips/powertv/init.c
+++ b/arch/mips/powertv/init.c
@@ -117,8 +117,10 @@ void __init prom_init(void)
board_nmi_handler_setup = mips_nmi_setup;
board_ejtag_handler_setup = mips_ejtag_setup;
- if (prom_argc == 1)
+ if (prom_argc == 1) {
+ strlcat(arcs_cmdline, " ", COMMAND_LINE_SIZE);
strlcat(arcs_cmdline, prom_argv, COMMAND_LINE_SIZE);
+ }
configure_platform();
prom_meminit();
diff --git a/arch/mips/powertv/ioremap.c b/arch/mips/powertv/ioremap.c
new file mode 100644
index 00000000000..a77c6f62fe2
--- /dev/null
+++ b/arch/mips/powertv/ioremap.c
@@ -0,0 +1,136 @@
+/*
+ * ioremap.c
+ *
+ * Support for mapping between dma_addr_t values a phys_addr_t values.
+ *
+ * Copyright (C) 2005-2009 Scientific-Atlanta, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Author: David VomLehn <dvomlehn@cisco.com>
+ *
+ * Description: Defines the platform resources for the SA settop.
+ *
+ * NOTE: The bootloader allocates persistent memory at an address which is
+ * 16 MiB below the end of the highest address in KSEG0. All fixed
+ * address memory reservations must avoid this region.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+
+#include <asm/mach-powertv/ioremap.h>
+
+/*
+ * Define the sizes of and masks for grains in physical and DMA space. The
+ * values are the same but the types are not.
+ */
+#define IOR_PHYS_GRAIN ((phys_addr_t) 1 << IOR_LSBITS)
+#define IOR_PHYS_GRAIN_MASK (IOR_PHYS_GRAIN - 1)
+
+#define IOR_DMA_GRAIN ((dma_addr_t) 1 << IOR_LSBITS)
+#define IOR_DMA_GRAIN_MASK (IOR_DMA_GRAIN - 1)
+
+/*
+ * Values that, when accessed by an index derived from a phys_addr_t and
+ * added to phys_addr_t value, yield a DMA address
+ */
+struct ior_phys_to_dma _ior_phys_to_dma[IOR_NUM_PHYS_TO_DMA];
+EXPORT_SYMBOL(_ior_phys_to_dma);
+
+/*
+ * Values that, when accessed by an index derived from a dma_addr_t and
+ * added to that dma_addr_t value, yield a physical address
+ */
+struct ior_dma_to_phys _ior_dma_to_phys[IOR_NUM_DMA_TO_PHYS];
+EXPORT_SYMBOL(_ior_dma_to_phys);
+
+/**
+ * setup_dma_to_phys - set up conversion from DMA to physical addresses
+ * @dma_idx: Top IOR_LSBITS bits of the DMA address, i.e. an index
+ * into the array _dma_to_phys.
+ * @delta: Value that, when added to the DMA address, will yield the
+ * physical address
+ * @s: Number of bytes in the section of memory with the given delta
+ * between DMA and physical addresses.
+ */
+static void setup_dma_to_phys(dma_addr_t dma, phys_addr_t delta, dma_addr_t s)
+{
+ int dma_idx, first_idx, last_idx;
+ phys_addr_t first, last;
+
+ /*
+ * Calculate the first and last indices, rounding the first up and
+ * the second down.
+ */
+ first = dma & ~IOR_DMA_GRAIN_MASK;
+ last = (dma + s - 1) & ~IOR_DMA_GRAIN_MASK;
+ first_idx = first >> IOR_LSBITS; /* Convert to indices */
+ last_idx = last >> IOR_LSBITS;
+
+ for (dma_idx = first_idx; dma_idx <= last_idx; dma_idx++)
+ _ior_dma_to_phys[dma_idx].offset = delta >> IOR_DMA_SHIFT;
+}
+
+/**
+ * setup_phys_to_dma - set up conversion from DMA to physical addresses
+ * @phys_idx: Top IOR_LSBITS bits of the DMA address, i.e. an index
+ * into the array _phys_to_dma.
+ * @delta: Value that, when added to the DMA address, will yield the
+ * physical address
+ * @s: Number of bytes in the section of memory with the given delta
+ * between DMA and physical addresses.
+ */
+static void setup_phys_to_dma(phys_addr_t phys, dma_addr_t delta, phys_addr_t s)
+{
+ int phys_idx, first_idx, last_idx;
+ phys_addr_t first, last;
+
+ /*
+ * Calculate the first and last indices, rounding the first up and
+ * the second down.
+ */
+ first = phys & ~IOR_PHYS_GRAIN_MASK;
+ last = (phys + s - 1) & ~IOR_PHYS_GRAIN_MASK;
+ first_idx = first >> IOR_LSBITS; /* Convert to indices */
+ last_idx = last >> IOR_LSBITS;
+
+ for (phys_idx = first_idx; phys_idx <= last_idx; phys_idx++)
+ _ior_phys_to_dma[phys_idx].offset = delta >> IOR_PHYS_SHIFT;
+}
+
+/**
+ * ioremap_add_map - add to the physical and DMA address conversion arrays
+ * @phys: Process's view of the address of the start of the memory chunk
+ * @dma: DMA address of the start of the memory chunk
+ * @size: Size, in bytes, of the chunk of memory
+ *
+ * NOTE: It might be obvious, but the assumption is that all @size bytes have
+ * the same offset between the physical address and the DMA address.
+ */
+void ioremap_add_map(phys_addr_t phys, phys_addr_t dma, phys_addr_t size)
+{
+ if (size == 0)
+ return;
+
+ if ((dma & IOR_DMA_GRAIN_MASK) != 0 ||
+ (phys & IOR_PHYS_GRAIN_MASK) != 0 ||
+ (size & IOR_PHYS_GRAIN_MASK) != 0)
+ pr_crit("Memory allocation must be in chunks of 0x%x bytes\n",
+ IOR_PHYS_GRAIN);
+
+ setup_dma_to_phys(dma, phys - dma, size);
+ setup_phys_to_dma(phys, dma - phys, size);
+}
diff --git a/arch/mips/powertv/memory.c b/arch/mips/powertv/memory.c
index f49eb3d0358..73880ad29bc 100644
--- a/arch/mips/powertv/memory.c
+++ b/arch/mips/powertv/memory.c
@@ -30,28 +30,141 @@
#include <asm/sections.h>
#include <asm/mips-boards/prom.h>
+#include <asm/mach-powertv/asic.h>
+#include <asm/mach-powertv/ioremap.h>
#include "init.h"
/* Memory constants */
#define KIBIBYTE(n) ((n) * 1024) /* Number of kibibytes */
#define MEBIBYTE(n) ((n) * KIBIBYTE(1024)) /* Number of mebibytes */
-#define DEFAULT_MEMSIZE MEBIBYTE(256) /* If no memsize provided */
-#define LOW_MEM_MAX MEBIBYTE(252) /* Max usable low mem */
-#define RES_BOOTLDR_MEMSIZE MEBIBYTE(1) /* Memory reserved for bldr */
-#define BOOT_MEM_SIZE KIBIBYTE(256) /* Memory reserved for bldr */
-#define PHYS_MEM_START 0x10000000 /* Start of physical memory */
+#define DEFAULT_MEMSIZE MEBIBYTE(128) /* If no memsize provided */
-char __initdata cmdline[COMMAND_LINE_SIZE];
+#define BLDR_SIZE KIBIBYTE(256) /* Memory reserved for bldr */
+#define RV_SIZE MEBIBYTE(4) /* Size of reset vector */
-void __init prom_meminit(void)
+#define LOW_MEM_END 0x20000000 /* Highest low memory address */
+#define BLDR_ALIAS 0x10000000 /* Bootloader address */
+#define RV_PHYS 0x1fc00000 /* Reset vector address */
+#define LOW_RAM_END RV_PHYS /* End of real RAM in low mem */
+
+/*
+ * Very low-level conversion from processor physical address to device
+ * DMA address for the first bank of memory.
+ */
+#define PHYS_TO_DMA(paddr) ((paddr) + (CONFIG_LOW_RAM_DMA - LOW_RAM_ALIAS))
+
+unsigned long ptv_memsize;
+
+/*
+ * struct low_mem_reserved - Items in low memmory that are reserved
+ * @start: Physical address of item
+ * @size: Size, in bytes, of this item
+ * @is_aliased: True if this is RAM aliased from another location. If false,
+ * it is something other than aliased RAM and the RAM in the
+ * unaliased address is still visible outside of low memory.
+ */
+struct low_mem_reserved {
+ phys_addr_t start;
+ phys_addr_t size;
+ bool is_aliased;
+};
+
+/*
+ * Must be in ascending address order
+ */
+struct low_mem_reserved low_mem_reserved[] = {
+ {BLDR_ALIAS, BLDR_SIZE, true}, /* Bootloader RAM */
+ {RV_PHYS, RV_SIZE, false}, /* Reset vector */
+};
+
+/*
+ * struct mem_layout - layout of a piece of the system RAM
+ * @phys: Physical address of the start of this piece of RAM. This is the
+ * address at which both the processor and I/O devices see the
+ * RAM.
+ * @alias: Alias of this piece of memory in order to make it appear in
+ * the low memory part of the processor's address space. I/O
+ * devices don't see anything here.
+ * @size: Size, in bytes, of this piece of RAM
+ */
+struct mem_layout {
+ phys_addr_t phys;
+ phys_addr_t alias;
+ phys_addr_t size;
+};
+
+/*
+ * struct mem_layout_list - list descriptor for layouts of system RAM pieces
+ * @family: Specifies the family being described
+ * @n: Number of &struct mem_layout elements
+ * @layout: Pointer to the list of &mem_layout structures
+ */
+struct mem_layout_list {
+ enum family_type family;
+ size_t n;
+ struct mem_layout *layout;
+};
+
+static struct mem_layout f1500_layout[] = {
+ {0x20000000, 0x10000000, MEBIBYTE(256)},
+};
+
+static struct mem_layout f4500_layout[] = {
+ {0x40000000, 0x10000000, MEBIBYTE(256)},
+ {0x20000000, 0x20000000, MEBIBYTE(32)},
+};
+
+static struct mem_layout f8500_layout[] = {
+ {0x40000000, 0x10000000, MEBIBYTE(256)},
+ {0x20000000, 0x20000000, MEBIBYTE(32)},
+ {0x30000000, 0x30000000, MEBIBYTE(32)},
+};
+
+static struct mem_layout fx600_layout[] = {
+ {0x20000000, 0x10000000, MEBIBYTE(256)},
+ {0x60000000, 0x60000000, MEBIBYTE(128)},
+};
+
+static struct mem_layout_list layout_list[] = {
+ {FAMILY_1500, ARRAY_SIZE(f1500_layout), f1500_layout},
+ {FAMILY_1500VZE, ARRAY_SIZE(f1500_layout), f1500_layout},
+ {FAMILY_1500VZF, ARRAY_SIZE(f1500_layout), f1500_layout},
+ {FAMILY_4500, ARRAY_SIZE(f4500_layout), f4500_layout},
+ {FAMILY_8500, ARRAY_SIZE(f8500_layout), f8500_layout},
+ {FAMILY_8500RNG, ARRAY_SIZE(f8500_layout), f8500_layout},
+ {FAMILY_4600, ARRAY_SIZE(fx600_layout), fx600_layout},
+ {FAMILY_4600VZA, ARRAY_SIZE(fx600_layout), fx600_layout},
+ {FAMILY_8600, ARRAY_SIZE(fx600_layout), fx600_layout},
+ {FAMILY_8600VZB, ARRAY_SIZE(fx600_layout), fx600_layout},
+};
+
+/* If we can't determine the layout, use this */
+static struct mem_layout default_layout[] = {
+ {0x20000000, 0x10000000, MEBIBYTE(128)},
+};
+
+/**
+ * register_non_ram - register low memory not available for RAM usage
+ */
+static __init void register_non_ram(void)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(low_mem_reserved); i++)
+ add_memory_region(low_mem_reserved[i].start,
+ low_mem_reserved[i].size, BOOT_MEM_RESERVED);
+}
+
+/**
+ * get_memsize - get the size of memory as a single bank
+ */
+static phys_addr_t get_memsize(void)
{
+ static char cmdline[COMMAND_LINE_SIZE] __initdata;
+ phys_addr_t memsize = 0;
char *memsize_str;
- unsigned long memsize = 0;
- unsigned int physend;
char *ptr;
- int low_mem;
- int high_mem;
/* Check the command line first for a memsize directive */
strcpy(cmdline, arcs_cmdline);
@@ -73,96 +186,156 @@ void __init prom_meminit(void)
if (memsize == 0) {
if (_prom_memsize != 0) {
memsize = _prom_memsize;
- pr_info("_prom_memsize = 0x%lx\n", memsize);
+ pr_info("_prom_memsize = 0x%x\n", memsize);
/* add in memory that the bootloader doesn't
* report */
- memsize += BOOT_MEM_SIZE;
+ memsize += BLDR_SIZE;
} else {
memsize = DEFAULT_MEMSIZE;
pr_info("Memsize not passed by bootloader, "
- "defaulting to 0x%lx\n", memsize);
+ "defaulting to 0x%x\n", memsize);
}
}
}
- physend = PFN_ALIGN(&_end) - 0x80000000;
- if (memsize > LOW_MEM_MAX) {
- low_mem = LOW_MEM_MAX;
- high_mem = memsize - low_mem;
- } else {
- low_mem = memsize;
- high_mem = 0;
+ return memsize;
+}
+
+/**
+ * register_low_ram - register an aliased section of RAM
+ * @p: Alias address of memory
+ * @n: Number of bytes in this section of memory
+ *
+ * Returns the number of bytes registered
+ *
+ */
+static __init phys_addr_t register_low_ram(phys_addr_t p, phys_addr_t n)
+{
+ phys_addr_t s;
+ int i;
+ phys_addr_t orig_n;
+
+ orig_n = n;
+
+ BUG_ON(p + n > RV_PHYS);
+
+ for (i = 0; n != 0 && i < ARRAY_SIZE(low_mem_reserved); i++) {
+ phys_addr_t start;
+ phys_addr_t size;
+
+ start = low_mem_reserved[i].start;
+ size = low_mem_reserved[i].size;
+
+ /* Handle memory before this low memory section */
+ if (p < start) {
+ phys_addr_t s;
+ s = min(n, start - p);
+ add_memory_region(p, s, BOOT_MEM_RAM);
+ p += s;
+ n -= s;
+ }
+
+ /* Handle the low memory section itself. If it's aliased,
+ * we reduce the number of byes left, but if not, the RAM
+ * is available elsewhere and we don't reduce the number of
+ * bytes remaining. */
+ if (p == start) {
+ if (low_mem_reserved[i].is_aliased) {
+ s = min(n, size);
+ n -= s;
+ p += s;
+ } else
+ p += n;
+ }
}
+ return orig_n - n;
+}
+
/*
- * TODO: We will use the hard code for memory configuration until
- * the bootloader releases their device tree to us.
+ * register_ram - register real RAM
+ * @p: Address of memory as seen by devices
+ * @alias: If the memory is seen at an additional address by the processor,
+ * this will be the address, otherwise it is the same as @p.
+ * @n: Number of bytes in this section of memory
*/
+static __init void register_ram(phys_addr_t p, phys_addr_t alias,
+ phys_addr_t n)
+{
/*
- * Add the memory reserved for use by the bootloader to the
- * memory map.
- */
- add_memory_region(PHYS_MEM_START, RES_BOOTLDR_MEMSIZE,
- BOOT_MEM_RESERVED);
-#ifdef CONFIG_HIGHMEM_256_128
- /*
- * Add memory in low for general use by the kernel and its friends
- * (like drivers, applications, etc).
- */
- add_memory_region(PHYS_MEM_START + RES_BOOTLDR_MEMSIZE,
- LOW_MEM_MAX - RES_BOOTLDR_MEMSIZE, BOOT_MEM_RAM);
- /*
- * Add the memory reserved for reset vector.
- */
- add_memory_region(0x1fc00000, MEBIBYTE(4), BOOT_MEM_RESERVED);
- /*
- * Add the memory reserved.
- */
- add_memory_region(0x20000000, MEBIBYTE(1024 + 75), BOOT_MEM_RESERVED);
- /*
- * Add memory in high for general use by the kernel and its friends
- * (like drivers, applications, etc).
- *
- * 75MB is reserved for devices which are using the memory in high.
- */
- add_memory_region(0x60000000 + MEBIBYTE(75), MEBIBYTE(128 - 75),
- BOOT_MEM_RAM);
-#elif defined CONFIG_HIGHMEM_128_128
- /*
- * Add memory in low for general use by the kernel and its friends
- * (like drivers, applications, etc).
- */
- add_memory_region(PHYS_MEM_START + RES_BOOTLDR_MEMSIZE,
- MEBIBYTE(128) - RES_BOOTLDR_MEMSIZE, BOOT_MEM_RAM);
- /*
- * Add the memory reserved.
- */
- add_memory_region(PHYS_MEM_START + MEBIBYTE(128),
- MEBIBYTE(128 + 1024 + 75), BOOT_MEM_RESERVED);
- /*
- * Add memory in high for general use by the kernel and its friends
- * (like drivers, applications, etc).
- *
- * 75MB is reserved for devices which are using the memory in high.
- */
- add_memory_region(0x60000000 + MEBIBYTE(75), MEBIBYTE(128 - 75),
- BOOT_MEM_RAM);
-#else
- /* Add low memory regions for either:
- * - no-highmemory configuration case -OR-
- * - highmemory "HIGHMEM_LOWBANK_ONLY" case
- */
- /*
- * Add memory for general use by the kernel and its friends
- * (like drivers, applications, etc).
+ * If some or all of this memory has an alias, break it into the
+ * aliased and non-aliased portion.
*/
- add_memory_region(PHYS_MEM_START + RES_BOOTLDR_MEMSIZE,
- low_mem - RES_BOOTLDR_MEMSIZE, BOOT_MEM_RAM);
+ if (p != alias) {
+ phys_addr_t alias_size;
+ phys_addr_t registered;
+
+ alias_size = min(n, LOW_RAM_END - alias);
+ registered = register_low_ram(alias, alias_size);
+ ioremap_add_map(alias, p, n);
+ n -= registered;
+ p += registered;
+ }
+
+#ifdef CONFIG_HIGHMEM
+ if (n != 0) {
+ add_memory_region(p, n, BOOT_MEM_RAM);
+ ioremap_add_map(p, p, n);
+ }
+#endif
+}
+
+/**
+ * register_address_space - register things in the address space
+ * @memsize: Number of bytes of RAM installed
+ *
+ * Takes the given number of bytes of RAM and registers as many of the regions,
+ * or partial regions, as it can. So, the default configuration might have
+ * two regions with 256 MiB each. If the memsize passed in on the command line
+ * is 384 MiB, it will register the first region with 256 MiB and the second
+ * with 128 MiB.
+ */
+static __init void register_address_space(phys_addr_t memsize)
+{
+ int i;
+ phys_addr_t size;
+ size_t n;
+ struct mem_layout *layout;
+ enum family_type family;
+
/*
- * Add the memory reserved for reset vector.
+ * Register all of the things that aren't available to the kernel as
+ * memory.
*/
- add_memory_region(0x1fc00000, MEBIBYTE(4), BOOT_MEM_RESERVED);
-#endif
+ register_non_ram();
+
+ /* Find the appropriate memory description */
+ family = platform_get_family();
+
+ for (i = 0; i < ARRAY_SIZE(layout_list); i++) {
+ if (layout_list[i].family == family)
+ break;
+ }
+
+ if (i == ARRAY_SIZE(layout_list)) {
+ n = ARRAY_SIZE(default_layout);
+ layout = default_layout;
+ } else {
+ n = layout_list[i].n;
+ layout = layout_list[i].layout;
+ }
+
+ for (i = 0; memsize != 0 && i < n; i++) {
+ size = min(memsize, layout[i].size);
+ register_ram(layout[i].phys, layout[i].alias, size);
+ memsize -= size;
+ }
+}
+
+void __init prom_meminit(void)
+{
+ ptv_memsize = get_memsize();
+ register_address_space(ptv_memsize);
}
void __init prom_free_prom_memory(void)
diff --git a/arch/mips/powertv/powertv-usb.c b/arch/mips/powertv/powertv-usb.c
new file mode 100644
index 00000000000..6ac85cf7aa2
--- /dev/null
+++ b/arch/mips/powertv/powertv-usb.c
@@ -0,0 +1,403 @@
+/*
+ * powertv-usb.c
+ *
+ * Description: ASIC-specific USB device setup and shutdown
+ *
+ * Copyright (C) 2005-2009 Scientific-Atlanta, Inc.
+ * Copyright (C) 2009 Cisco Systems, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Author: Ken Eppinett
+ * David Schleef <ds@schleef.org>
+ *
+ * NOTE: The bootloader allocates persistent memory at an address which is
+ * 16 MiB below the end of the highest address in KSEG0. All fixed
+ * address memory reservations must avoid this region.
+ */
+
+#include <linux/kernel.h>
+#include <linux/ioport.h>
+#include <linux/platform_device.h>
+#include <asm/mach-powertv/asic.h>
+#include <asm/mach-powertv/interrupts.h>
+
+/* misc_clk_ctl1 values */
+#define MCC1_30MHZ_POWERUP_SELECT (1 << 14)
+#define MCC1_DIV9 (1 << 13)
+#define MCC1_ETHMIPS_POWERUP_SELECT (1 << 11)
+#define MCC1_USB_POWERUP_SELECT (1 << 1)
+#define MCC1_CLOCK108_POWERUP_SELECT (1 << 0)
+
+/* Possible values for clock select */
+#define MCC1_USB_CLOCK_HIGH_Z (0 << 4)
+#define MCC1_USB_CLOCK_48MHZ (1 << 4)
+#define MCC1_USB_CLOCK_24MHZ (2 << 4)
+#define MCC1_USB_CLOCK_6MHZ (3 << 4)
+
+#define MCC1_CONFIG (MCC1_30MHZ_POWERUP_SELECT | \
+ MCC1_DIV9 | \
+ MCC1_ETHMIPS_POWERUP_SELECT | \
+ MCC1_USB_POWERUP_SELECT | \
+ MCC1_CLOCK108_POWERUP_SELECT)
+
+/* misc_clk_ctl2 values */
+#define MCC2_GMII_GCLK_TO_PAD (1 << 31)
+#define MCC2_ETHER125_0_CLOCK_SELECT (1 << 29)
+#define MCC2_RMII_0_CLOCK_SELECT (1 << 28)
+#define MCC2_GMII_TX0_CLOCK_SELECT (1 << 27)
+#define MCC2_GMII_RX0_CLOCK_SELECT (1 << 26)
+#define MCC2_ETHER125_1_CLOCK_SELECT (1 << 24)
+#define MCC2_RMII_1_CLOCK_SELECT (1 << 23)
+#define MCC2_GMII_TX1_CLOCK_SELECT (1 << 22)
+#define MCC2_GMII_RX1_CLOCK_SELECT (1 << 21)
+#define MCC2_ETHER125_2_CLOCK_SELECT (1 << 19)
+#define MCC2_RMII_2_CLOCK_SELECT (1 << 18)
+#define MCC2_GMII_TX2_CLOCK_SELECT (1 << 17)
+#define MCC2_GMII_RX2_CLOCK_SELECT (1 << 16)
+
+#define ETHER_CLK_CONFIG (MCC2_GMII_GCLK_TO_PAD | \
+ MCC2_ETHER125_0_CLOCK_SELECT | \
+ MCC2_RMII_0_CLOCK_SELECT | \
+ MCC2_GMII_TX0_CLOCK_SELECT | \
+ MCC2_GMII_RX0_CLOCK_SELECT | \
+ MCC2_ETHER125_1_CLOCK_SELECT | \
+ MCC2_RMII_1_CLOCK_SELECT | \
+ MCC2_GMII_TX1_CLOCK_SELECT | \
+ MCC2_GMII_RX1_CLOCK_SELECT | \
+ MCC2_ETHER125_2_CLOCK_SELECT | \
+ MCC2_RMII_2_CLOCK_SELECT | \
+ MCC2_GMII_TX2_CLOCK_SELECT | \
+ MCC2_GMII_RX2_CLOCK_SELECT)
+
+/* misc_clk_ctl2 definitions for Gaia */
+#define FSX4A_REF_SELECT (1 << 16)
+#define FSX4B_REF_SELECT (1 << 17)
+#define FSX4C_REF_SELECT (1 << 18)
+#define DDR_PLL_REF_SELECT (1 << 19)
+#define MIPS_PLL_REF_SELECT (1 << 20)
+
+/* Definitions for the QAM frequency select register FS432X4A4_QAM_CTL */
+#define QAM_FS_SDIV_SHIFT 29
+#define QAM_FS_MD_SHIFT 24
+#define QAM_FS_MD_MASK 0x1f /* Cut down to 5 bits */
+#define QAM_FS_PE_SHIFT 8
+
+#define QAM_FS_DISABLE_DIVIDE_BY_3 (1 << 5)
+#define QAM_FS_ENABLE_PROGRAM (1 << 4)
+#define QAM_FS_ENABLE_OUTPUT (1 << 3)
+#define QAM_FS_SELECT_TEST_BYPASS (1 << 2)
+#define QAM_FS_DISABLE_DIGITAL_STANDBY (1 << 1)
+#define QAM_FS_CHOOSE_FS (1 << 0)
+
+/* Definitions for fs432x4a_ctl register */
+#define QAM_FS_NSDIV_54MHZ (1 << 2)
+
+/* Definitions for bcm1_usb2_ctl register */
+#define BCM1_USB2_CTL_BISTOK (1 << 11)
+#define BCM1_USB2_CTL_PORT2_SHIFT_JK (1 << 7)
+#define BCM1_USB2_CTL_PORT1_SHIFT_JK (1 << 6)
+#define BCM1_USB2_CTL_PORT2_FAST_EDGE (1 << 5)
+#define BCM1_USB2_CTL_PORT1_FAST_EDGE (1 << 4)
+#define BCM1_USB2_CTL_EHCI_PRT_PWR_ACTIVE_HIGH (1 << 1)
+#define BCM1_USB2_CTL_APP_PRT_OVRCUR_IN_ACTIVE_HIGH (1 << 0)
+
+/* Definitions for crt_spare register */
+#define CRT_SPARE_PORT2_SHIFT_JK (1 << 21)
+#define CRT_SPARE_PORT1_SHIFT_JK (1 << 20)
+#define CRT_SPARE_PORT2_FAST_EDGE (1 << 19)
+#define CRT_SPARE_PORT1_FAST_EDGE (1 << 18)
+#define CRT_SPARE_DIVIDE_BY_9_FROM_432 (1 << 17)
+#define CRT_SPARE_USB_DIVIDE_BY_9 (1 << 16)
+
+/* Definitions for usb2_stbus_obc register */
+#define USB_STBUS_OBC_STORE32_LOAD32 0x3
+
+/* Definitions for usb2_stbus_mess_size register */
+#define USB2_STBUS_MESS_SIZE_2 0x1 /* 2 packets */
+
+/* Definitions for usb2_stbus_chunk_size register */
+#define USB2_STBUS_CHUNK_SIZE_2 0x1 /* 2 packets */
+
+/* Definitions for usb2_strap register */
+#define USB2_STRAP_HFREQ_SELECT 0x1
+
+/*
+ * USB Host Resource Definition
+ */
+
+static struct resource ehci_resources[] = {
+ {
+ .parent = &asic_resource,
+ .start = 0,
+ .end = 0xff,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = irq_usbehci,
+ .end = irq_usbehci,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static u64 ehci_dmamask = 0xffffffffULL;
+
+static struct platform_device ehci_device = {
+ .name = "powertv-ehci",
+ .id = 0,
+ .num_resources = 2,
+ .resource = ehci_resources,
+ .dev = {
+ .dma_mask = &ehci_dmamask,
+ .coherent_dma_mask = 0xffffffff,
+ },
+};
+
+static struct resource ohci_resources[] = {
+ {
+ .parent = &asic_resource,
+ .start = 0,
+ .end = 0xff,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = irq_usbohci,
+ .end = irq_usbohci,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static u64 ohci_dmamask = 0xffffffffULL;
+
+static struct platform_device ohci_device = {
+ .name = "powertv-ohci",
+ .id = 0,
+ .num_resources = 2,
+ .resource = ohci_resources,
+ .dev = {
+ .dma_mask = &ohci_dmamask,
+ .coherent_dma_mask = 0xffffffff,
+ },
+};
+
+static unsigned usb_users;
+static DEFINE_SPINLOCK(usb_regs_lock);
+
+/*
+ *
+ * fs_update - set frequency synthesizer for USB
+ * @pe_bits Phase tap setting
+ * @md_bits Coarse selector bus for algorithm of phase tap
+ * @sdiv_bits Output divider setting
+ * @disable_div_by_3 Either QAM_FS_DISABLE_DIVIDE_BY_3 or zero
+ * @standby Either QAM_FS_DISABLE_DIGITAL_STANDBY or zero
+ *
+ * QAM frequency selection code, which affects the frequency at which USB
+ * runs. The frequency is calculated as:
+ * 2^15 * ndiv * Fin
+ * Fout = ------------------------------------------------------------
+ * (sdiv * (ipe * (1 + md/32) - (ipe - 2^15)*(1 + (md + 1)/32)))
+ * where:
+ * Fin 54 MHz
+ * ndiv QAM_FS_NSDIV_54MHZ ? 8 : 16
+ * sdiv 1 << (sdiv_bits + 1)
+ * ipe Same as pe_bits
+ * md A five-bit, two's-complement integer (range [-16, 15]), which
+ * is the lower 5 bits of md_bits.
+ */
+static void fs_update(u32 pe_bits, int md_bits, u32 sdiv_bits,
+ u32 disable_div_by_3, u32 standby)
+{
+ u32 val;
+
+ val = ((sdiv_bits << QAM_FS_SDIV_SHIFT) |
+ ((md_bits & QAM_FS_MD_MASK) << QAM_FS_MD_SHIFT) |
+ (pe_bits << QAM_FS_PE_SHIFT) |
+ QAM_FS_ENABLE_OUTPUT |
+ standby |
+ disable_div_by_3);
+ asic_write(val, fs432x4b4_usb_ctl);
+ asic_write(val | QAM_FS_ENABLE_PROGRAM, fs432x4b4_usb_ctl);
+ asic_write(val | QAM_FS_ENABLE_PROGRAM | QAM_FS_CHOOSE_FS,
+ fs432x4b4_usb_ctl);
+}
+
+/*
+ * usb_eye_configure - for optimizing the shape USB eye waveform
+ * @set: Bits to set in the register
+ * @clear: Bits to clear in the register; each bit with a one will
+ * be set in the register, zero bits will not be modified
+ */
+static void usb_eye_configure(u32 set, u32 clear)
+{
+ u32 old;
+
+ old = asic_read(crt_spare);
+ old |= set;
+ old &= ~clear;
+ asic_write(old, crt_spare);
+}
+
+/*
+ * platform_configure_usb - usb configuration based on platform type.
+ */
+static void platform_configure_usb(void)
+{
+ u32 bcm1_usb2_ctl_value;
+ enum asic_type asic_type;
+ unsigned long flags;
+
+ spin_lock_irqsave(&usb_regs_lock, flags);
+ usb_users++;
+
+ if (usb_users != 1) {
+ spin_unlock_irqrestore(&usb_regs_lock, flags);
+ return;
+ }
+
+ asic_type = platform_get_asic();
+
+ switch (asic_type) {
+ case ASIC_ZEUS:
+ fs_update(0x0000, -15, 0x02, 0, 0);
+ bcm1_usb2_ctl_value = BCM1_USB2_CTL_EHCI_PRT_PWR_ACTIVE_HIGH |
+ BCM1_USB2_CTL_APP_PRT_OVRCUR_IN_ACTIVE_HIGH;
+ break;
+
+ case ASIC_CRONUS:
+ case ASIC_CRONUSLITE:
+ usb_eye_configure(0, CRT_SPARE_USB_DIVIDE_BY_9);
+ fs_update(0x8000, -14, 0x03, QAM_FS_DISABLE_DIVIDE_BY_3,
+ QAM_FS_DISABLE_DIGITAL_STANDBY);
+ bcm1_usb2_ctl_value = BCM1_USB2_CTL_EHCI_PRT_PWR_ACTIVE_HIGH |
+ BCM1_USB2_CTL_APP_PRT_OVRCUR_IN_ACTIVE_HIGH;
+ break;
+
+ case ASIC_CALLIOPE:
+ fs_update(0x0000, -15, 0x02, QAM_FS_DISABLE_DIVIDE_BY_3,
+ QAM_FS_DISABLE_DIGITAL_STANDBY);
+
+ switch (platform_get_family()) {
+ case FAMILY_1500VZE:
+ break;
+
+ case FAMILY_1500VZF:
+ usb_eye_configure(CRT_SPARE_PORT2_SHIFT_JK |
+ CRT_SPARE_PORT1_SHIFT_JK |
+ CRT_SPARE_PORT2_FAST_EDGE |
+ CRT_SPARE_PORT1_FAST_EDGE, 0);
+ break;
+
+ default:
+ usb_eye_configure(CRT_SPARE_PORT2_SHIFT_JK |
+ CRT_SPARE_PORT1_SHIFT_JK, 0);
+ break;
+ }
+
+ bcm1_usb2_ctl_value = BCM1_USB2_CTL_BISTOK |
+ BCM1_USB2_CTL_EHCI_PRT_PWR_ACTIVE_HIGH |
+ BCM1_USB2_CTL_APP_PRT_OVRCUR_IN_ACTIVE_HIGH;
+ break;
+
+ case ASIC_GAIA:
+ fs_update(0x8000, -14, 0x03, QAM_FS_DISABLE_DIVIDE_BY_3,
+ QAM_FS_DISABLE_DIGITAL_STANDBY);
+ bcm1_usb2_ctl_value = BCM1_USB2_CTL_BISTOK |
+ BCM1_USB2_CTL_EHCI_PRT_PWR_ACTIVE_HIGH |
+ BCM1_USB2_CTL_APP_PRT_OVRCUR_IN_ACTIVE_HIGH;
+ break;
+
+ default:
+ pr_err("Unknown ASIC type: %d\n", asic_type);
+ bcm1_usb2_ctl_value = 0;
+ break;
+ }
+
+ /* turn on USB power */
+ asic_write(0, usb2_strap);
+ /* Enable all OHCI interrupts */
+ asic_write(bcm1_usb2_ctl_value, usb2_control);
+ /* usb2_stbus_obc store32/load32 */
+ asic_write(USB_STBUS_OBC_STORE32_LOAD32, usb2_stbus_obc);
+ /* usb2_stbus_mess_size 2 packets */
+ asic_write(USB2_STBUS_MESS_SIZE_2, usb2_stbus_mess_size);
+ /* usb2_stbus_chunk_size 2 packets */
+ asic_write(USB2_STBUS_CHUNK_SIZE_2, usb2_stbus_chunk_size);
+ spin_unlock_irqrestore(&usb_regs_lock, flags);
+}
+
+static void platform_unconfigure_usb(void)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&usb_regs_lock, flags);
+ usb_users--;
+ if (usb_users == 0)
+ asic_write(USB2_STRAP_HFREQ_SELECT, usb2_strap);
+ spin_unlock_irqrestore(&usb_regs_lock, flags);
+}
+
+/*
+ * Set up the USB EHCI interface
+ */
+void platform_configure_usb_ehci()
+{
+ platform_configure_usb();
+}
+EXPORT_SYMBOL(platform_configure_usb_ehci);
+
+/*
+ * Set up the USB OHCI interface
+ */
+void platform_configure_usb_ohci()
+{
+ platform_configure_usb();
+}
+EXPORT_SYMBOL(platform_configure_usb_ohci);
+
+/*
+ * Shut the USB EHCI interface down
+ */
+void platform_unconfigure_usb_ehci()
+{
+ platform_unconfigure_usb();
+}
+EXPORT_SYMBOL(platform_unconfigure_usb_ehci);
+
+/*
+ * Shut the USB OHCI interface down
+ */
+void platform_unconfigure_usb_ohci()
+{
+ platform_unconfigure_usb();
+}
+EXPORT_SYMBOL(platform_unconfigure_usb_ohci);
+
+/**
+ * platform_devices_init - sets up USB device resourse.
+ */
+int __init platform_usb_devices_init(struct platform_device **ehci_dev,
+ struct platform_device **ohci_dev)
+{
+ *ehci_dev = &ehci_device;
+ ehci_resources[0].start = asic_reg_phys_addr(ehci_hcapbase);
+ ehci_resources[0].end += ehci_resources[0].start;
+
+ *ohci_dev = &ohci_device;
+ ohci_resources[0].start = asic_reg_phys_addr(ohci_hc_revision);
+ ohci_resources[0].end += ohci_resources[0].start;
+
+ return 0;
+}
diff --git a/arch/mips/powertv/powertv_setup.c b/arch/mips/powertv/powertv_setup.c
index af2cae0a5ab..3933c373a43 100644
--- a/arch/mips/powertv/powertv_setup.c
+++ b/arch/mips/powertv/powertv_setup.c
@@ -199,14 +199,8 @@ static int panic_handler(struct notifier_block *notifier_block,
my_regs.cp0_status = read_c0_status();
}
-#ifdef CONFIG_DIAGNOSTICS
- failure_report((char *) cause_string,
- have_die_regs ? &die_regs : &my_regs);
- have_die_regs = false;
-#else
pr_crit("I'm feeling a bit sleepy. hmmmmm... perhaps a nap would... "
"zzzz... \n");
-#endif
return NOTIFY_DONE;
}
diff --git a/arch/mips/rb532/Makefile b/arch/mips/rb532/Makefile
index 8f0b6b6a162..efdecdb6e3e 100644
--- a/arch/mips/rb532/Makefile
+++ b/arch/mips/rb532/Makefile
@@ -3,5 +3,3 @@
#
obj-y += irq.o time.o setup.o serial.o prom.o gpio.o devices.o
-
-EXTRA_CFLAGS += -Werror
diff --git a/arch/mips/rb532/Platform b/arch/mips/rb532/Platform
new file mode 100644
index 00000000000..aeec45a7cbb
--- /dev/null
+++ b/arch/mips/rb532/Platform
@@ -0,0 +1,7 @@
+#
+# Routerboard 532
+#
+platform-$(CONFIG_MIKROTIK_RB532) += rb532/
+cflags-$(CONFIG_MIKROTIK_RB532) += \
+ -I$(srctree)/arch/mips/include/asm/mach-rc32434
+load-$(CONFIG_MIKROTIK_RB532) += 0xffffffff80101000
diff --git a/arch/mips/sgi-ip22/Makefile b/arch/mips/sgi-ip22/Makefile
index 416b18f9fa7..cc538493cae 100644
--- a/arch/mips/sgi-ip22/Makefile
+++ b/arch/mips/sgi-ip22/Makefile
@@ -9,5 +9,3 @@ obj-y += ip22-mc.o ip22-hpc.o ip22-int.o ip22-time.o ip22-nvram.o \
obj-$(CONFIG_SGI_IP22) += ip22-berr.o
obj-$(CONFIG_SGI_IP28) += ip28-berr.o
obj-$(CONFIG_EISA) += ip22-eisa.o
-
-EXTRA_CFLAGS += -Werror
diff --git a/arch/mips/sgi-ip22/Platform b/arch/mips/sgi-ip22/Platform
new file mode 100644
index 00000000000..b7a4b7e04c3
--- /dev/null
+++ b/arch/mips/sgi-ip22/Platform
@@ -0,0 +1,34 @@
+#
+# SGI IP22 (Indy/Indigo2)
+#
+# Set the load address to >= 0xffffffff88069000 if you want to leave space for
+# symmon, 0xffffffff80002000 for production kernels. Note that the value must
+# be aligned to a multiple of the kernel stack size or the handling of the
+# current variable will break so for 64-bit kernels we have to raise the start
+# address by 8kb.
+#
+platform-$(CONFIG_SGI_IP22) += sgi-ip22/
+cflags-$(CONFIG_SGI_IP22) += -I$(srctree)/arch/mips/include/asm/mach-ip22
+ifdef CONFIG_32BIT
+load-$(CONFIG_SGI_IP22) += 0xffffffff88002000
+endif
+ifdef CONFIG_64BIT
+load-$(CONFIG_SGI_IP22) += 0xffffffff88004000
+endif
+
+#
+# SGI IP28 (Indigo2 R10k)
+#
+# Set the load address to >= 0xa800000020080000 if you want to leave space for
+# symmon, 0xa800000020004000 for production kernels ? Note that the value must
+# be 16kb aligned or the handling of the current variable will break.
+# Simplified: what IP22 does at 128MB+ in ksegN, IP28 does at 512MB+ in xkphys
+#
+ifdef CONFIG_SGI_IP28
+ ifeq ($(call cc-option-yn,-mr10k-cache-barrier=store), n)
+ $(error gcc doesn't support needed option -mr10k-cache-barrier=store)
+ endif
+endif
+platform-$(CONFIG_SGI_IP28) += sgi-ip22/
+cflags-$(CONFIG_SGI_IP28) += -mr10k-cache-barrier=store -I$(srctree)/arch/mips/include/asm/mach-ip28
+load-$(CONFIG_SGI_IP28) += 0xa800000020004000
diff --git a/arch/mips/sgi-ip27/Makefile b/arch/mips/sgi-ip27/Makefile
index 31f4931b848..1f29e761d69 100644
--- a/arch/mips/sgi-ip27/Makefile
+++ b/arch/mips/sgi-ip27/Makefile
@@ -8,5 +8,3 @@ obj-y := ip27-berr.o ip27-irq.o ip27-init.o ip27-klconfig.o ip27-klnuma.o \
obj-$(CONFIG_EARLY_PRINTK) += ip27-console.o
obj-$(CONFIG_SMP) += ip27-smp.o
-
-EXTRA_CFLAGS += -Werror
diff --git a/arch/mips/sgi-ip27/Platform b/arch/mips/sgi-ip27/Platform
new file mode 100644
index 00000000000..1fb9c2ea7c8
--- /dev/null
+++ b/arch/mips/sgi-ip27/Platform
@@ -0,0 +1,19 @@
+#
+# SGI-IP27 (Origin200/2000)
+#
+# Set the load address to >= 0xc000000000300000 if you want to leave space for
+# symmon, 0xc00000000001c000 for production kernels. Note that the value must
+# be 16kb aligned or the handling of the current variable will break.
+#
+ifdef CONFIG_SGI_IP27
+platform-$(CONFIG_SGI_IP27) += sgi-ip27/
+cflags-$(CONFIG_SGI_IP27) += -I$(srctree)/arch/mips/include/asm/mach-ip27
+ifdef CONFIG_MAPPED_KERNEL
+load-$(CONFIG_SGI_IP27) += 0xc00000004001c000
+OBJCOPYFLAGS := --change-addresses=0x3fffffff80000000
+dataoffset-$(CONFIG_SGI_IP27) += 0x01000000
+else
+load-$(CONFIG_SGI_IP27) += 0xa80000000001c000
+OBJCOPYFLAGS := --change-addresses=0x57ffffff80000000
+endif
+endif
diff --git a/arch/mips/sgi-ip27/ip27-klconfig.c b/arch/mips/sgi-ip27/ip27-klconfig.c
index dd830b3670d..7afe1468800 100644
--- a/arch/mips/sgi-ip27/ip27-klconfig.c
+++ b/arch/mips/sgi-ip27/ip27-klconfig.c
@@ -48,7 +48,7 @@ klinfo_t *find_first_component(lboard_t *brd, unsigned char struct_type)
return find_component(brd, (klinfo_t *)NULL, struct_type);
}
-lboard_t * find_lboard(lboard_t *start, unsigned char brd_type)
+lboard_t *find_lboard(lboard_t *start, unsigned char brd_type)
{
/* Search all boards stored on this node. */
while (start) {
@@ -60,7 +60,7 @@ lboard_t * find_lboard(lboard_t *start, unsigned char brd_type)
return (lboard_t *)NULL;
}
-lboard_t * find_lboard_class(lboard_t *start, unsigned char brd_type)
+lboard_t *find_lboard_class(lboard_t *start, unsigned char brd_type)
{
/* Search all boards stored on this node. */
while (start) {
@@ -78,7 +78,7 @@ cnodeid_t get_cpu_cnode(cpuid_t cpu)
return CPUID_TO_COMPACT_NODEID(cpu);
}
-klcpu_t * nasid_slice_to_cpuinfo(nasid_t nasid, int slice)
+klcpu_t *nasid_slice_to_cpuinfo(nasid_t nasid, int slice)
{
lboard_t *brd;
klcpu_t *acpu;
@@ -97,7 +97,7 @@ klcpu_t * nasid_slice_to_cpuinfo(nasid_t nasid, int slice)
return (klcpu_t *)NULL;
}
-klcpu_t * sn_get_cpuinfo(cpuid_t cpu)
+klcpu_t *sn_get_cpuinfo(cpuid_t cpu)
{
nasid_t nasid;
int slice;
diff --git a/arch/mips/sgi-ip32/Makefile b/arch/mips/sgi-ip32/Makefile
index 31c9aa1bcb4..60f0227425e 100644
--- a/arch/mips/sgi-ip32/Makefile
+++ b/arch/mips/sgi-ip32/Makefile
@@ -5,5 +5,3 @@
obj-y += ip32-berr.o ip32-irq.o ip32-platform.o ip32-setup.o ip32-reset.o \
crime.o ip32-memory.o
-
-EXTRA_CFLAGS += -Werror
diff --git a/arch/mips/sgi-ip32/Platform b/arch/mips/sgi-ip32/Platform
new file mode 100644
index 00000000000..0fea556f364
--- /dev/null
+++ b/arch/mips/sgi-ip32/Platform
@@ -0,0 +1,11 @@
+#
+# SGI-IP32 (O2)
+#
+# Set the load address to >= 80069000 if you want to leave space for symmon,
+# 0xffffffff80004000 for production kernels. Note that the value must be aligned to
+# a multiple of the kernel stack size or the handling of the current variable
+# will break.
+#
+platform-$(CONFIG_SGI_IP32) += sgi-ip32/
+cflags-$(CONFIG_SGI_IP32) += -I$(srctree)/arch/mips/include/asm/mach-ip32
+load-$(CONFIG_SGI_IP32) += 0xffffffff80004000
diff --git a/arch/mips/sibyte/Makefile b/arch/mips/sibyte/Makefile
new file mode 100644
index 00000000000..c8ed2c807e6
--- /dev/null
+++ b/arch/mips/sibyte/Makefile
@@ -0,0 +1,27 @@
+#
+# Sibyte SB1250 / BCM1480 family of SOCs
+#
+obj-$(CONFIG_SIBYTE_BCM112X) += sb1250/
+obj-$(CONFIG_SIBYTE_BCM112X) += common/
+obj-$(CONFIG_SIBYTE_SB1250) += sb1250/
+obj-$(CONFIG_SIBYTE_SB1250) += common/
+obj-$(CONFIG_SIBYTE_BCM1x55) += bcm1480/
+obj-$(CONFIG_SIBYTE_BCM1x55) += common/
+obj-$(CONFIG_SIBYTE_BCM1x80) += bcm1480/
+obj-$(CONFIG_SIBYTE_BCM1x80) += common/
+
+#
+# Sibyte BCM91120x (Carmel) board
+# Sibyte BCM91120C (CRhine) board
+# Sibyte BCM91125C (CRhone) board
+# Sibyte BCM91125E (Rhone) board
+# Sibyte SWARM board
+# Sibyte BCM91x80 (BigSur) board
+#
+obj-$(CONFIG_SIBYTE_CARMEL) += swarm/
+obj-$(CONFIG_SIBYTE_CRHINE) += swarm/
+obj-$(CONFIG_SIBYTE_CRHONE) += swarm/
+obj-$(CONFIG_SIBYTE_RHONE) += swarm/
+obj-$(CONFIG_SIBYTE_SENTOSA) += swarm/
+obj-$(CONFIG_SIBYTE_SWARM) += swarm/
+obj-$(CONFIG_SIBYTE_BIGSUR) += swarm/
diff --git a/arch/mips/sibyte/Platform b/arch/mips/sibyte/Platform
new file mode 100644
index 00000000000..911dfe39c63
--- /dev/null
+++ b/arch/mips/sibyte/Platform
@@ -0,0 +1,43 @@
+#
+# These are all rather similar so we consider them a single platform
+#
+platform-$(CONFIG_SIBYTE_BCM112X) += sibyte/
+platform-$(CONFIG_SIBYTE_SB1250) += sibyte/
+platform-$(CONFIG_SIBYTE_BCM1x55) += sibyte/
+platform-$(CONFIG_SIBYTE_BCM1x80) += sibyte/
+
+#
+# Sibyte SB1250 / BCM1480 family of SOCs
+#
+cflags-$(CONFIG_SIBYTE_BCM112X) += \
+ -I$(srctree)/arch/mips/include/asm/mach-sibyte \
+ -DSIBYTE_HDR_FEATURES=SIBYTE_HDR_FMASK_1250_112x_ALL
+
+platform-$(CONFIG_SIBYTE_SB1250) += sibyte/
+cflags-$(CONFIG_SIBYTE_SB1250) += \
+ -I$(srctree)/arch/mips/include/asm/mach-sibyte \
+ -DSIBYTE_HDR_FEATURES=SIBYTE_HDR_FMASK_1250_112x_ALL
+
+cflags-$(CONFIG_SIBYTE_BCM1x55) += \
+ -I$(srctree)/arch/mips/include/asm/mach-sibyte \
+ -DSIBYTE_HDR_FEATURES=SIBYTE_HDR_FMASK_1480_ALL
+
+cflags-$(CONFIG_SIBYTE_BCM1x80) += \
+ -I$(srctree)/arch/mips/include/asm/mach-sibyte \
+ -DSIBYTE_HDR_FEATURES=SIBYTE_HDR_FMASK_1480_ALL
+
+#
+# Sibyte BCM91120x (Carmel) board
+# Sibyte BCM91120C (CRhine) board
+# Sibyte BCM91125C (CRhone) board
+# Sibyte BCM91125E (Rhone) board
+# Sibyte SWARM board
+# Sibyte BCM91x80 (BigSur) board
+#
+load-$(CONFIG_SIBYTE_CARMEL) := 0xffffffff80100000
+load-$(CONFIG_SIBYTE_CRHINE) := 0xffffffff80100000
+load-$(CONFIG_SIBYTE_CRHONE) := 0xffffffff80100000
+load-$(CONFIG_SIBYTE_RHONE) := 0xffffffff80100000
+load-$(CONFIG_SIBYTE_SENTOSA) := 0xffffffff80100000
+load-$(CONFIG_SIBYTE_SWARM) := 0xffffffff80100000
+load-$(CONFIG_SIBYTE_BIGSUR) := 0xffffffff80100000
diff --git a/arch/mips/sibyte/bcm1480/Makefile b/arch/mips/sibyte/bcm1480/Makefile
index f292f7df0cf..cdc4c56c3e2 100644
--- a/arch/mips/sibyte/bcm1480/Makefile
+++ b/arch/mips/sibyte/bcm1480/Makefile
@@ -1,5 +1,3 @@
obj-y := setup.o irq.o time.o
obj-$(CONFIG_SMP) += smp.o
-
-EXTRA_CFLAGS += -Werror
diff --git a/arch/mips/sibyte/common/Makefile b/arch/mips/sibyte/common/Makefile
index 4f659837c7c..36aa700cc40 100644
--- a/arch/mips/sibyte/common/Makefile
+++ b/arch/mips/sibyte/common/Makefile
@@ -1,5 +1,3 @@
obj-y := cfe.o
obj-$(CONFIG_SIBYTE_CFE_CONSOLE) += cfe_console.o
obj-$(CONFIG_SIBYTE_TBPROF) += sb_tbprof.o
-
-EXTRA_CFLAGS += -Werror
diff --git a/arch/mips/sibyte/sb1250/Makefile b/arch/mips/sibyte/sb1250/Makefile
index 1896f4e77a3..d3d969de407 100644
--- a/arch/mips/sibyte/sb1250/Makefile
+++ b/arch/mips/sibyte/sb1250/Makefile
@@ -2,5 +2,3 @@ obj-y := setup.o irq.o time.o
obj-$(CONFIG_SMP) += smp.o
obj-$(CONFIG_SIBYTE_BUS_WATCHER) += bus_watcher.o
-
-EXTRA_CFLAGS += -Werror
diff --git a/arch/mips/sni/Makefile b/arch/mips/sni/Makefile
index a7dbeebe7fe..9d3bad3200c 100644
--- a/arch/mips/sni/Makefile
+++ b/arch/mips/sni/Makefile
@@ -4,5 +4,3 @@
obj-y += irq.o reset.o setup.o a20r.o rm200.o pcimt.o pcit.o time.o
obj-$(CONFIG_EISA) += eisa.o
-
-EXTRA_CFLAGS += -Werror
diff --git a/arch/mips/sni/Platform b/arch/mips/sni/Platform
new file mode 100644
index 00000000000..2644a9d63c0
--- /dev/null
+++ b/arch/mips/sni/Platform
@@ -0,0 +1,11 @@
+#
+# SNI RM
+#
+platform-$(CONFIG_SNI_RM) += sni/
+cflags-$(CONFIG_SNI_RM) += -I$(srctree)/arch/mips/include/asm/mach-rm
+ifdef CONFIG_CPU_LITTLE_ENDIAN
+load-$(CONFIG_SNI_RM) += 0xffffffff80600000
+else
+load-$(CONFIG_SNI_RM) += 0xffffffff80030000
+endif
+all-$(CONFIG_SNI_RM) := $(COMPRESSION_FNAME).ecoff
diff --git a/arch/mips/txx9/Makefile b/arch/mips/txx9/Makefile
new file mode 100644
index 00000000000..34787dabff0
--- /dev/null
+++ b/arch/mips/txx9/Makefile
@@ -0,0 +1,17 @@
+#
+# Common TXx9
+#
+obj-$(CONFIG_MACH_TX39XX) += generic/
+obj-$(CONFIG_MACH_TX49XX) += generic/
+
+#
+# Toshiba JMR-TX3927 board
+#
+obj-$(CONFIG_TOSHIBA_JMR3927) += jmr3927/
+
+#
+# Toshiba RBTX49XX boards
+#
+obj-$(CONFIG_TOSHIBA_RBTX4927) += rbtx4927/
+obj-$(CONFIG_TOSHIBA_RBTX4938) += rbtx4938/
+obj-$(CONFIG_TOSHIBA_RBTX4939) += rbtx4939/
diff --git a/arch/mips/txx9/Platform b/arch/mips/txx9/Platform
new file mode 100644
index 00000000000..a801abbe138
--- /dev/null
+++ b/arch/mips/txx9/Platform
@@ -0,0 +1,10 @@
+platform-$(CONFIG_MACH_TX39XX) += txx9/
+platform-$(CONFIG_MACH_TX49XX) += txx9/
+
+cflags-$(CONFIG_MACH_TX39XX) += \
+ -I$(srctree)/arch/mips/include/asm/mach-tx39xx
+cflags-$(CONFIG_MACH_TX49XX) += \
+ -I$(srctree)/arch/mips/include/asm/mach-tx49xx
+
+load-$(CONFIG_MACH_TX39XX) += 0xffffffff80050000
+load-$(CONFIG_MACH_TX49XX) += 0xffffffff80100000
diff --git a/arch/mips/txx9/generic/Makefile b/arch/mips/txx9/generic/Makefile
index f2579ce054a..1863c167e66 100644
--- a/arch/mips/txx9/generic/Makefile
+++ b/arch/mips/txx9/generic/Makefile
@@ -11,5 +11,3 @@ obj-$(CONFIG_SOC_TX4939) += setup_tx4939.o irq_tx4939.o
obj-$(CONFIG_TOSHIBA_FPCIB0) += smsc_fdc37m81x.o
obj-$(CONFIG_SPI) += spi_eeprom.o
obj-$(CONFIG_TXX9_7SEGLED) += 7segled.o
-
-EXTRA_CFLAGS += -Werror
diff --git a/arch/mips/txx9/jmr3927/Makefile b/arch/mips/txx9/jmr3927/Makefile
index 20d61ac543e..9f5d5b62383 100644
--- a/arch/mips/txx9/jmr3927/Makefile
+++ b/arch/mips/txx9/jmr3927/Makefile
@@ -3,5 +3,3 @@
#
obj-y += prom.o irq.o setup.o
-
-EXTRA_CFLAGS += -Werror
diff --git a/arch/mips/txx9/rbtx4927/Makefile b/arch/mips/txx9/rbtx4927/Makefile
index f3e1f597b4f..60b24c8f7e6 100644
--- a/arch/mips/txx9/rbtx4927/Makefile
+++ b/arch/mips/txx9/rbtx4927/Makefile
@@ -1,3 +1 @@
obj-y += prom.o setup.o irq.o
-
-EXTRA_CFLAGS += -Werror
diff --git a/arch/mips/txx9/rbtx4938/Makefile b/arch/mips/txx9/rbtx4938/Makefile
index f3e1f597b4f..60b24c8f7e6 100644
--- a/arch/mips/txx9/rbtx4938/Makefile
+++ b/arch/mips/txx9/rbtx4938/Makefile
@@ -1,3 +1 @@
obj-y += prom.o setup.o irq.o
-
-EXTRA_CFLAGS += -Werror
diff --git a/arch/mips/txx9/rbtx4939/Makefile b/arch/mips/txx9/rbtx4939/Makefile
index 3232cd03a7d..5c84625a3f1 100644
--- a/arch/mips/txx9/rbtx4939/Makefile
+++ b/arch/mips/txx9/rbtx4939/Makefile
@@ -1,3 +1 @@
obj-y += irq.o setup.o prom.o
-
-EXTRA_CFLAGS += -Werror
diff --git a/arch/mips/vr41xx/Platform b/arch/mips/vr41xx/Platform
new file mode 100644
index 00000000000..b6c8d5c08dd
--- /dev/null
+++ b/arch/mips/vr41xx/Platform
@@ -0,0 +1,32 @@
+#
+# NEC VR4100 series based machines
+#
+platform-$(CONFIG_MACH_VR41XX) += vr41xx/common/
+cflags-$(CONFIG_MACH_VR41XX) += -I$(srctree)/arch/mips/include/asm/mach-vr41xx
+
+#
+# CASIO CASSIPEIA E-55/65 (VR4111)
+#
+platform-$(CONFIG_CASIO_E55) += vr41xx/casio-e55/
+load-$(CONFIG_CASIO_E55) += 0xffffffff80004000
+
+#
+# IBM WorkPad z50 (VR4121)
+#
+platform-$(CONFIG_IBM_WORKPAD) += vr41xx/ibm-workpad/
+load-$(CONFIG_IBM_WORKPAD) += 0xffffffff80004000
+
+#
+# TANBAC VR4131 multichip module(TB0225) and TANBAC VR4131DIMM(TB0229) (VR4131)
+#
+load-$(CONFIG_TANBAC_TB022X) += 0xffffffff80000000
+
+#
+# Victor MP-C303/304 (VR4122)
+#
+load-$(CONFIG_VICTOR_MPC30X) += 0xffffffff80001000
+
+#
+# ZAO Networks Capcella (VR4131)
+#
+load-$(CONFIG_ZAO_CAPCELLA) += 0xffffffff80000000
diff --git a/arch/mips/vr41xx/common/Makefile b/arch/mips/vr41xx/common/Makefile
index 7d5d83b8c58..d0d84ec8d63 100644
--- a/arch/mips/vr41xx/common/Makefile
+++ b/arch/mips/vr41xx/common/Makefile
@@ -3,5 +3,3 @@
#
obj-y += bcu.o cmu.o giu.o icu.o init.o irq.o pmu.o rtc.o siu.o type.o
-
-EXTRA_CFLAGS += -Werror
diff --git a/arch/mips/gt64120/wrppmc/Makefile b/arch/mips/wrppmc/Makefile
index b49d282bee8..307cc6920ce 100644
--- a/arch/mips/gt64120/wrppmc/Makefile
+++ b/arch/mips/wrppmc/Makefile
@@ -6,9 +6,7 @@
# Copyright 2006 Wind River System, Inc.
# Author: Rongkai.Zhan <rongkai.zhan@windriver.com>
#
-# Makefile for the Wind River MIPS 4KC PPMC Eval Board
+# Makefile for the Wind River MIPS 4Kc PPMC Eval Board
#
obj-y += irq.o pci.o reset.o serial.o setup.o time.o
-
-EXTRA_CFLAGS += -Werror
diff --git a/arch/mips/wrppmc/Platform b/arch/mips/wrppmc/Platform
new file mode 100644
index 00000000000..e758645e968
--- /dev/null
+++ b/arch/mips/wrppmc/Platform
@@ -0,0 +1,7 @@
+#
+# Wind River PPMC Board (4KC + GT64120)
+#
+platform-$(CONFIG_WR_PPMC) += wrppmc/
+cflags-$(CONFIG_WR_PPMC) += \
+ -I$(srctree)/arch/mips/include/asm/mach-wrppmc
+load-$(CONFIG_WR_PPMC) += 0xffffffff80100000
diff --git a/arch/mips/gt64120/wrppmc/irq.c b/arch/mips/wrppmc/irq.c
index c6e706274db..c6e706274db 100644
--- a/arch/mips/gt64120/wrppmc/irq.c
+++ b/arch/mips/wrppmc/irq.c
diff --git a/arch/mips/gt64120/wrppmc/pci.c b/arch/mips/wrppmc/pci.c
index d06192faeb7..d06192faeb7 100644
--- a/arch/mips/gt64120/wrppmc/pci.c
+++ b/arch/mips/wrppmc/pci.c
diff --git a/arch/mips/gt64120/wrppmc/reset.c b/arch/mips/wrppmc/reset.c
index cc5474b24f0..cc5474b24f0 100644
--- a/arch/mips/gt64120/wrppmc/reset.c
+++ b/arch/mips/wrppmc/reset.c
diff --git a/arch/mips/gt64120/wrppmc/serial.c b/arch/mips/wrppmc/serial.c
index 6f9d0858f59..6f9d0858f59 100644
--- a/arch/mips/gt64120/wrppmc/serial.c
+++ b/arch/mips/wrppmc/serial.c
diff --git a/arch/mips/gt64120/wrppmc/setup.c b/arch/mips/wrppmc/setup.c
index ca65c84031a..ca65c84031a 100644
--- a/arch/mips/gt64120/wrppmc/setup.c
+++ b/arch/mips/wrppmc/setup.c
diff --git a/arch/mips/gt64120/wrppmc/time.c b/arch/mips/wrppmc/time.c
index 668dbd5f12c..668dbd5f12c 100644
--- a/arch/mips/gt64120/wrppmc/time.c
+++ b/arch/mips/wrppmc/time.c
diff --git a/arch/mn10300/Kconfig b/arch/mn10300/Kconfig
index 1c4565a9102..444b9f918fd 100644
--- a/arch/mn10300/Kconfig
+++ b/arch/mn10300/Kconfig
@@ -46,9 +46,6 @@ config GENERIC_FIND_NEXT_BIT
config GENERIC_HWEIGHT
def_bool y
-config GENERIC_TIME
- def_bool y
-
config GENERIC_BUG
def_bool y
diff --git a/arch/mn10300/include/asm/local64.h b/arch/mn10300/include/asm/local64.h
new file mode 100644
index 00000000000..36c93b5cc23
--- /dev/null
+++ b/arch/mn10300/include/asm/local64.h
@@ -0,0 +1 @@
+#include <asm-generic/local64.h>
diff --git a/arch/parisc/Kconfig b/arch/parisc/Kconfig
index 05a366a5c4d..907417d187e 100644
--- a/arch/parisc/Kconfig
+++ b/arch/parisc/Kconfig
@@ -66,10 +66,6 @@ config GENERIC_CALIBRATE_DELAY
bool
default y
-config GENERIC_TIME
- bool
- default y
-
config TIME_LOW_RES
bool
depends on SMP
diff --git a/arch/parisc/include/asm/local64.h b/arch/parisc/include/asm/local64.h
new file mode 100644
index 00000000000..36c93b5cc23
--- /dev/null
+++ b/arch/parisc/include/asm/local64.h
@@ -0,0 +1 @@
+#include <asm-generic/local64.h>
diff --git a/arch/parisc/kernel/firmware.c b/arch/parisc/kernel/firmware.c
index 4c247e02d9b..df971fa0c32 100644
--- a/arch/parisc/kernel/firmware.c
+++ b/arch/parisc/kernel/firmware.c
@@ -1123,7 +1123,6 @@ static char __attribute__((aligned(64))) iodc_dbuf[4096];
*/
int pdc_iodc_print(const unsigned char *str, unsigned count)
{
- static int posx; /* for simple TAB-Simulation... */
unsigned int i;
unsigned long flags;
@@ -1133,19 +1132,12 @@ int pdc_iodc_print(const unsigned char *str, unsigned count)
iodc_dbuf[i+0] = '\r';
iodc_dbuf[i+1] = '\n';
i += 2;
- posx = 0;
goto print;
- case '\t':
- while (posx & 7) {
- iodc_dbuf[i] = ' ';
- i++, posx++;
- }
- break;
case '\b': /* BS */
- posx -= 2;
+ i--; /* overwrite last */
default:
iodc_dbuf[i] = str[i];
- i++, posx++;
+ i++;
break;
}
}
diff --git a/arch/parisc/kernel/ftrace.c b/arch/parisc/kernel/ftrace.c
index 9877372ffdb..5beb97bafbb 100644
--- a/arch/parisc/kernel/ftrace.c
+++ b/arch/parisc/kernel/ftrace.c
@@ -82,7 +82,7 @@ unsigned long ftrace_return_to_handler(unsigned long retval0,
unsigned long ret;
pop_return_trace(&trace, &ret);
- trace.rettime = cpu_clock(raw_smp_processor_id());
+ trace.rettime = local_clock();
ftrace_graph_return(&trace);
if (unlikely(!ret)) {
@@ -126,7 +126,7 @@ void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr)
return;
}
- calltime = cpu_clock(raw_smp_processor_id());
+ calltime = local_clock();
if (push_return_trace(old, calltime,
self_addr, &trace.depth) == -EBUSY) {
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index 2031a284686..631e5a0fb6a 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -29,9 +29,6 @@ config MMU
config GENERIC_CMOS_UPDATE
def_bool y
-config GENERIC_TIME
- def_bool y
-
config GENERIC_TIME_VSYSCALL
def_bool y
@@ -120,6 +117,8 @@ config ARCH_NO_VIRT_TO_BUS
config PPC
bool
default y
+ select OF
+ select OF_FLATTREE
select HAVE_FTRACE_MCOUNT_RECORD
select HAVE_DYNAMIC_FTRACE
select HAVE_FUNCTION_TRACER
@@ -141,6 +140,7 @@ config PPC
select GENERIC_ATOMIC64 if PPC32
select HAVE_PERF_EVENTS
select HAVE_REGS_AND_STACK_ACCESS_API
+ select HAVE_HW_BREAKPOINT if PERF_EVENTS && PPC_BOOK3S_64
config EARLY_PRINTK
bool
@@ -172,10 +172,6 @@ config ARCH_MAY_HAVE_PC_FDC
config PPC_OF
def_bool y
-config OF
- def_bool y
- select OF_FLATTREE
-
config PPC_UDBG_16550
bool
default n
@@ -198,10 +194,6 @@ config SYS_SUPPORTS_APM_EMULATION
default y if PMAC_APM_EMU
bool
-config DTC
- bool
- default y
-
config DEFAULT_UIMAGE
bool
help
@@ -218,7 +210,7 @@ config ARCH_HIBERNATION_POSSIBLE
config ARCH_SUSPEND_POSSIBLE
def_bool y
depends on ADB_PMU || PPC_EFIKA || PPC_LITE5200 || PPC_83xx || \
- PPC_85xx || PPC_86xx
+ PPC_85xx || PPC_86xx || PPC_PSERIES
config PPC_DCR_NATIVE
bool
@@ -351,7 +343,7 @@ config ARCH_ENABLE_MEMORY_HOTREMOVE
config KEXEC
bool "kexec system call (EXPERIMENTAL)"
- depends on (PPC_BOOK3S || (FSL_BOOKE && !SMP)) && EXPERIMENTAL
+ depends on (PPC_BOOK3S || FSL_BOOKE) && EXPERIMENTAL
help
kexec is a system call that implements the ability to shutdown your
current kernel, and to start another kernel. It is like a reboot
@@ -368,8 +360,8 @@ config KEXEC
config CRASH_DUMP
bool "Build a kdump crash kernel"
- depends on PPC64 || 6xx
- select RELOCATABLE if PPC64
+ depends on PPC64 || 6xx || FSL_BOOKE
+ select RELOCATABLE if PPC64 || FSL_BOOKE
help
Build a kernel suitable for use as a kdump capture kernel.
The same kernel binary can be used as production kernel and dump
@@ -578,14 +570,6 @@ config SCHED_SMT
when dealing with POWER5 cpus at a cost of slightly increased
overhead in some places. If unsure say N here.
-config PROC_DEVICETREE
- bool "Support for device tree in /proc"
- depends on PROC_FS
- help
- This option adds a device-tree directory under /proc which contains
- an image of the device tree that the kernel copies from Open
- Firmware or other boot firmware. If unsure, say Y here.
-
config CMDLINE_BOOL
bool "Default bootloader kernel arguments"
@@ -668,7 +652,7 @@ config NEED_SG_DMA_LENGTH
config GENERIC_ISA_DMA
bool
- depends on PPC64 || POWER4 || 6xx && !CPM2
+ depends on ISA_DMA_API
default y
config PPC_INDIRECT_PCI
@@ -897,7 +881,7 @@ config KERNEL_START_BOOL
config KERNEL_START
hex "Virtual address of kernel base" if KERNEL_START_BOOL
default PAGE_OFFSET if PAGE_OFFSET_BOOL
- default "0xc2000000" if CRASH_DUMP
+ default "0xc2000000" if CRASH_DUMP && !RELOCATABLE
default "0xc0000000"
config PHYSICAL_START_BOOL
@@ -910,7 +894,7 @@ config PHYSICAL_START_BOOL
config PHYSICAL_START
hex "Physical address where the kernel is loaded" if PHYSICAL_START_BOOL
- default "0x02000000" if PPC_STD_MMU && CRASH_DUMP
+ default "0x02000000" if PPC_STD_MMU && CRASH_DUMP && !RELOCATABLE
default "0x00000000"
config PHYSICAL_ALIGN
diff --git a/arch/powerpc/Makefile b/arch/powerpc/Makefile
index 77cfe7a29e2..5d42f5eae70 100644
--- a/arch/powerpc/Makefile
+++ b/arch/powerpc/Makefile
@@ -94,7 +94,7 @@ else
endif
endif
-LDFLAGS_MODULE += arch/powerpc/lib/crtsavres.o
+KBUILD_LDFLAGS_MODULE += arch/powerpc/lib/crtsavres.o
ifeq ($(CONFIG_TUNE_CELL),y)
KBUILD_CFLAGS += $(call cc-option,-mtune=cell)
diff --git a/arch/powerpc/boot/dts/canyonlands.dts b/arch/powerpc/boot/dts/canyonlands.dts
index cd56bb5b347..5806ef0b860 100644
--- a/arch/powerpc/boot/dts/canyonlands.dts
+++ b/arch/powerpc/boot/dts/canyonlands.dts
@@ -270,7 +270,7 @@
clock-frequency = <0>; /* Filled in by U-Boot */
current-speed = <0>; /* Filled in by U-Boot */
interrupt-parent = <&UIC1>;
- interrupts = <0x1d 0x4>;
+ interrupts = <28 0x4>;
};
UART3: serial@ef600600 {
@@ -281,7 +281,7 @@
clock-frequency = <0>; /* Filled in by U-Boot */
current-speed = <0>; /* Filled in by U-Boot */
interrupt-parent = <&UIC1>;
- interrupts = <0x1e 0x4>;
+ interrupts = <29 0x4>;
};
IIC0: i2c@ef600700 {
diff --git a/arch/powerpc/boot/dts/glacier.dts b/arch/powerpc/boot/dts/glacier.dts
index d62a4fb6f93..e618fc4cbc9 100644
--- a/arch/powerpc/boot/dts/glacier.dts
+++ b/arch/powerpc/boot/dts/glacier.dts
@@ -259,7 +259,7 @@
clock-frequency = <0>; /* Filled in by U-Boot */
current-speed = <0>; /* Filled in by U-Boot */
interrupt-parent = <&UIC1>;
- interrupts = <0x1d 0x4>;
+ interrupts = <28 0x4>;
};
UART3: serial@ef600600 {
@@ -270,7 +270,7 @@
clock-frequency = <0>; /* Filled in by U-Boot */
current-speed = <0>; /* Filled in by U-Boot */
interrupt-parent = <&UIC1>;
- interrupts = <0x1e 0x4>;
+ interrupts = <29 0x4>;
};
IIC0: i2c@ef600700 {
diff --git a/arch/powerpc/boot/dts/mpc8308rdb.dts b/arch/powerpc/boot/dts/mpc8308rdb.dts
new file mode 100644
index 00000000000..a97eb2db5a1
--- /dev/null
+++ b/arch/powerpc/boot/dts/mpc8308rdb.dts
@@ -0,0 +1,303 @@
+/*
+ * MPC8308RDB Device Tree Source
+ *
+ * Copyright 2009 Freescale Semiconductor Inc.
+ * Copyright 2010 Ilya Yanok, Emcraft Systems, yanok@emcraft.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.
+ */
+
+/dts-v1/;
+
+/ {
+ compatible = "fsl,mpc8308rdb";
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ aliases {
+ ethernet0 = &enet0;
+ ethernet1 = &enet1;
+ serial0 = &serial0;
+ serial1 = &serial1;
+ pci0 = &pci0;
+ };
+
+ cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ PowerPC,8308@0 {
+ device_type = "cpu";
+ reg = <0x0>;
+ d-cache-line-size = <32>;
+ i-cache-line-size = <32>;
+ d-cache-size = <16384>;
+ i-cache-size = <16384>;
+ timebase-frequency = <0>; // from bootloader
+ bus-frequency = <0>; // from bootloader
+ clock-frequency = <0>; // from bootloader
+ };
+ };
+
+ memory {
+ device_type = "memory";
+ reg = <0x00000000 0x08000000>; // 128MB at 0
+ };
+
+ localbus@e0005000 {
+ #address-cells = <2>;
+ #size-cells = <1>;
+ compatible = "fsl,mpc8315-elbc", "fsl,elbc", "simple-bus";
+ reg = <0xe0005000 0x1000>;
+ interrupts = <77 0x8>;
+ interrupt-parent = <&ipic>;
+
+ // CS0 and CS1 are swapped when
+ // booting from nand, but the
+ // addresses are the same.
+ ranges = <0x0 0x0 0xfe000000 0x00800000
+ 0x1 0x0 0xe0600000 0x00002000
+ 0x2 0x0 0xf0000000 0x00020000
+ 0x3 0x0 0xfa000000 0x00008000>;
+
+ flash@0,0 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "cfi-flash";
+ reg = <0x0 0x0 0x800000>;
+ bank-width = <2>;
+ device-width = <1>;
+
+ u-boot@0 {
+ reg = <0x0 0x60000>;
+ read-only;
+ };
+ env@60000 {
+ reg = <0x60000 0x10000>;
+ };
+ env1@70000 {
+ reg = <0x70000 0x10000>;
+ };
+ kernel@80000 {
+ reg = <0x80000 0x200000>;
+ };
+ dtb@280000 {
+ reg = <0x280000 0x10000>;
+ };
+ ramdisk@290000 {
+ reg = <0x290000 0x570000>;
+ };
+ };
+
+ nand@1,0 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "fsl,mpc8315-fcm-nand",
+ "fsl,elbc-fcm-nand";
+ reg = <0x1 0x0 0x2000>;
+
+ jffs2@0 {
+ reg = <0x0 0x2000000>;
+ };
+ };
+ };
+
+ immr@e0000000 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ device_type = "soc";
+ compatible = "fsl,mpc8315-immr", "simple-bus";
+ ranges = <0 0xe0000000 0x00100000>;
+ reg = <0xe0000000 0x00000200>;
+ bus-frequency = <0>;
+
+ i2c@3000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ cell-index = <0>;
+ compatible = "fsl-i2c";
+ reg = <0x3000 0x100>;
+ interrupts = <14 0x8>;
+ interrupt-parent = <&ipic>;
+ dfsrr;
+ rtc@68 {
+ compatible = "dallas,ds1339";
+ reg = <0x68>;
+ };
+ };
+
+ usb@23000 {
+ compatible = "fsl-usb2-dr";
+ reg = <0x23000 0x1000>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ interrupt-parent = <&ipic>;
+ interrupts = <38 0x8>;
+ dr_mode = "peripheral";
+ phy_type = "ulpi";
+ };
+
+ enet0: ethernet@24000 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges = <0x0 0x24000 0x1000>;
+
+ cell-index = <0>;
+ device_type = "network";
+ model = "eTSEC";
+ compatible = "gianfar";
+ reg = <0x24000 0x1000>;
+ local-mac-address = [ 00 00 00 00 00 00 ];
+ interrupts = <32 0x8 33 0x8 34 0x8>;
+ interrupt-parent = <&ipic>;
+ tbi-handle = < &tbi0 >;
+ phy-handle = < &phy2 >;
+ fsl,magic-packet;
+
+ mdio@520 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "fsl,gianfar-mdio";
+ reg = <0x520 0x20>;
+ phy2: ethernet-phy@2 {
+ interrupt-parent = <&ipic>;
+ interrupts = <17 0x8>;
+ reg = <0x2>;
+ device_type = "ethernet-phy";
+ };
+ tbi0: tbi-phy@11 {
+ reg = <0x11>;
+ device_type = "tbi-phy";
+ };
+ };
+ };
+
+ enet1: ethernet@25000 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ cell-index = <1>;
+ device_type = "network";
+ model = "eTSEC";
+ compatible = "gianfar";
+ reg = <0x25000 0x1000>;
+ ranges = <0x0 0x25000 0x1000>;
+ local-mac-address = [ 00 00 00 00 00 00 ];
+ interrupts = <35 0x8 36 0x8 37 0x8>;
+ interrupt-parent = <&ipic>;
+ tbi-handle = < &tbi1 >;
+ /* Vitesse 7385 isn't on the MDIO bus */
+ fixed-link = <1 1 1000 0 0>;
+ fsl,magic-packet;
+
+ mdio@520 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "fsl,gianfar-tbi";
+ reg = <0x520 0x20>;
+
+ tbi1: tbi-phy@11 {
+ reg = <0x11>;
+ device_type = "tbi-phy";
+ };
+ };
+ };
+
+ serial0: serial@4500 {
+ cell-index = <0>;
+ device_type = "serial";
+ compatible = "ns16550";
+ reg = <0x4500 0x100>;
+ clock-frequency = <133333333>;
+ interrupts = <9 0x8>;
+ interrupt-parent = <&ipic>;
+ };
+
+ serial1: serial@4600 {
+ cell-index = <1>;
+ device_type = "serial";
+ compatible = "ns16550";
+ reg = <0x4600 0x100>;
+ clock-frequency = <133333333>;
+ interrupts = <10 0x8>;
+ interrupt-parent = <&ipic>;
+ };
+
+ gpio@c00 {
+ #gpio-cells = <2>;
+ device_type = "gpio";
+ compatible = "fsl,mpc8308-gpio", "fsl,mpc8349-gpio";
+ reg = <0xc00 0x18>;
+ interrupts = <74 0x8>;
+ interrupt-parent = <&ipic>;
+ gpio-controller;
+ };
+
+ /* IPIC
+ * interrupts cell = <intr #, sense>
+ * sense values match linux IORESOURCE_IRQ_* defines:
+ * sense == 8: Level, low assertion
+ * sense == 2: Edge, high-to-low change
+ */
+ ipic: interrupt-controller@700 {
+ compatible = "fsl,ipic";
+ interrupt-controller;
+ #address-cells = <0>;
+ #interrupt-cells = <2>;
+ reg = <0x700 0x100>;
+ device_type = "ipic";
+ };
+
+ ipic-msi@7c0 {
+ compatible = "fsl,ipic-msi";
+ reg = <0x7c0 0x40>;
+ msi-available-ranges = <0x0 0x100>;
+ interrupts = < 0x43 0x8
+ 0x4 0x8
+ 0x51 0x8
+ 0x52 0x8
+ 0x56 0x8
+ 0x57 0x8
+ 0x58 0x8
+ 0x59 0x8 >;
+ interrupt-parent = < &ipic >;
+ };
+
+ };
+
+ pci0: pcie@e0009000 {
+ #address-cells = <3>;
+ #size-cells = <2>;
+ #interrupt-cells = <1>;
+ device_type = "pci";
+ compatible = "fsl,mpc8308-pcie", "fsl,mpc8314-pcie";
+ reg = <0xe0009000 0x00001000
+ 0xb0000000 0x01000000>;
+ ranges = <0x02000000 0 0xa0000000 0xa0000000 0 0x10000000
+ 0x01000000 0 0x00000000 0xb1000000 0 0x00800000>;
+ bus-range = <0 0>;
+ interrupt-map-mask = <0xf800 0 0 7>;
+ interrupt-map = <0 0 0 1 &ipic 1 8
+ 0 0 0 2 &ipic 1 8
+ 0 0 0 3 &ipic 1 8
+ 0 0 0 4 &ipic 1 8>;
+ interrupts = <0x1 0x8>;
+ interrupt-parent = <&ipic>;
+ clock-frequency = <0>;
+
+ pcie@0 {
+ #address-cells = <3>;
+ #size-cells = <2>;
+ device_type = "pci";
+ reg = <0 0 0 0 0>;
+ ranges = <0x02000000 0 0xa0000000
+ 0x02000000 0 0xa0000000
+ 0 0x10000000
+ 0x01000000 0 0x00000000
+ 0x01000000 0 0x00000000
+ 0 0x00800000>;
+ };
+ };
+};
diff --git a/arch/powerpc/boot/dts/mpc8540ads.dts b/arch/powerpc/boot/dts/mpc8540ads.dts
index 9dc292962a9..8d1bf0fd926 100644
--- a/arch/powerpc/boot/dts/mpc8540ads.dts
+++ b/arch/powerpc/boot/dts/mpc8540ads.dts
@@ -71,14 +71,14 @@
};
memory-controller@2000 {
- compatible = "fsl,8540-memory-controller";
+ compatible = "fsl,mpc8540-memory-controller";
reg = <0x2000 0x1000>;
interrupt-parent = <&mpic>;
interrupts = <18 2>;
};
L2: l2-cache-controller@20000 {
- compatible = "fsl,8540-l2-cache-controller";
+ compatible = "fsl,mpc8540-l2-cache-controller";
reg = <0x20000 0x1000>;
cache-line-size = <32>; // 32 bytes
cache-size = <0x40000>; // L2, 256K
diff --git a/arch/powerpc/boot/dts/mpc8541cds.dts b/arch/powerpc/boot/dts/mpc8541cds.dts
index 9a3ad311aed..87ff96549fa 100644
--- a/arch/powerpc/boot/dts/mpc8541cds.dts
+++ b/arch/powerpc/boot/dts/mpc8541cds.dts
@@ -71,14 +71,14 @@
};
memory-controller@2000 {
- compatible = "fsl,8541-memory-controller";
+ compatible = "fsl,mpc8541-memory-controller";
reg = <0x2000 0x1000>;
interrupt-parent = <&mpic>;
interrupts = <18 2>;
};
L2: l2-cache-controller@20000 {
- compatible = "fsl,8541-l2-cache-controller";
+ compatible = "fsl,mpc8541-l2-cache-controller";
reg = <0x20000 0x1000>;
cache-line-size = <32>; // 32 bytes
cache-size = <0x40000>; // L2, 256K
diff --git a/arch/powerpc/boot/dts/mpc8544ds.dts b/arch/powerpc/boot/dts/mpc8544ds.dts
index 98e94b46566..d793968743c 100644
--- a/arch/powerpc/boot/dts/mpc8544ds.dts
+++ b/arch/powerpc/boot/dts/mpc8544ds.dts
@@ -73,14 +73,14 @@
};
memory-controller@2000 {
- compatible = "fsl,8544-memory-controller";
+ compatible = "fsl,mpc8544-memory-controller";
reg = <0x2000 0x1000>;
interrupt-parent = <&mpic>;
interrupts = <18 2>;
};
L2: l2-cache-controller@20000 {
- compatible = "fsl,8544-l2-cache-controller";
+ compatible = "fsl,mpc8544-l2-cache-controller";
reg = <0x20000 0x1000>;
cache-line-size = <32>; // 32 bytes
cache-size = <0x40000>; // L2, 256K
diff --git a/arch/powerpc/boot/dts/mpc8548cds.dts b/arch/powerpc/boot/dts/mpc8548cds.dts
index 0f526245268..a17a5572fb7 100644
--- a/arch/powerpc/boot/dts/mpc8548cds.dts
+++ b/arch/powerpc/boot/dts/mpc8548cds.dts
@@ -74,14 +74,14 @@
};
memory-controller@2000 {
- compatible = "fsl,8548-memory-controller";
+ compatible = "fsl,mpc8548-memory-controller";
reg = <0x2000 0x1000>;
interrupt-parent = <&mpic>;
interrupts = <18 2>;
};
L2: l2-cache-controller@20000 {
- compatible = "fsl,8548-l2-cache-controller";
+ compatible = "fsl,mpc8548-l2-cache-controller";
reg = <0x20000 0x1000>;
cache-line-size = <32>; // 32 bytes
cache-size = <0x80000>; // L2, 512K
diff --git a/arch/powerpc/boot/dts/mpc8555cds.dts b/arch/powerpc/boot/dts/mpc8555cds.dts
index 065b2f093de..5c5614f9eb1 100644
--- a/arch/powerpc/boot/dts/mpc8555cds.dts
+++ b/arch/powerpc/boot/dts/mpc8555cds.dts
@@ -71,14 +71,14 @@
};
memory-controller@2000 {
- compatible = "fsl,8555-memory-controller";
+ compatible = "fsl,mpc8555-memory-controller";
reg = <0x2000 0x1000>;
interrupt-parent = <&mpic>;
interrupts = <18 2>;
};
L2: l2-cache-controller@20000 {
- compatible = "fsl,8555-l2-cache-controller";
+ compatible = "fsl,mpc8555-l2-cache-controller";
reg = <0x20000 0x1000>;
cache-line-size = <32>; // 32 bytes
cache-size = <0x40000>; // L2, 256K
diff --git a/arch/powerpc/boot/dts/mpc8560ads.dts b/arch/powerpc/boot/dts/mpc8560ads.dts
index a5bb1ec70a5..6e85e1ba085 100644
--- a/arch/powerpc/boot/dts/mpc8560ads.dts
+++ b/arch/powerpc/boot/dts/mpc8560ads.dts
@@ -71,14 +71,14 @@
};
memory-controller@2000 {
- compatible = "fsl,8540-memory-controller";
+ compatible = "fsl,mpc8540-memory-controller";
reg = <0x2000 0x1000>;
interrupt-parent = <&mpic>;
interrupts = <18 2>;
};
L2: l2-cache-controller@20000 {
- compatible = "fsl,8540-l2-cache-controller";
+ compatible = "fsl,mpc8540-l2-cache-controller";
reg = <0x20000 0x1000>;
cache-line-size = <32>; // 32 bytes
cache-size = <0x40000>; // L2, 256K
diff --git a/arch/powerpc/boot/dts/mpc8568mds.dts b/arch/powerpc/boot/dts/mpc8568mds.dts
index 92fb17876e7..30cf0e098bb 100644
--- a/arch/powerpc/boot/dts/mpc8568mds.dts
+++ b/arch/powerpc/boot/dts/mpc8568mds.dts
@@ -124,14 +124,14 @@
};
memory-controller@2000 {
- compatible = "fsl,8568-memory-controller";
+ compatible = "fsl,mpc8568-memory-controller";
reg = <0x2000 0x1000>;
interrupt-parent = <&mpic>;
interrupts = <18 2>;
};
L2: l2-cache-controller@20000 {
- compatible = "fsl,8568-l2-cache-controller";
+ compatible = "fsl,mpc8568-l2-cache-controller";
reg = <0x20000 0x1000>;
cache-line-size = <32>; // 32 bytes
cache-size = <0x80000>; // L2, 512K
diff --git a/arch/powerpc/boot/dts/p1021mds.dts b/arch/powerpc/boot/dts/p1021mds.dts
index 7fad2df2598..ad5b8526900 100644
--- a/arch/powerpc/boot/dts/p1021mds.dts
+++ b/arch/powerpc/boot/dts/p1021mds.dts
@@ -617,6 +617,7 @@
bus-frequency = <0>;
fsl,qe-num-riscs = <1>;
fsl,qe-num-snums = <28>;
+ status = "disabled"; /* no firmware loaded */
qeic: interrupt-controller@80 {
interrupt-controller;
diff --git a/arch/powerpc/boot/dts/p1022ds.dts b/arch/powerpc/boot/dts/p1022ds.dts
new file mode 100644
index 00000000000..8bcb10b9267
--- /dev/null
+++ b/arch/powerpc/boot/dts/p1022ds.dts
@@ -0,0 +1,633 @@
+/*
+ * P1022 DS 36Bit Physical Address Map Device Tree Source
+ *
+ * Copyright 2010 Freescale Semiconductor, 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.
+ */
+
+/dts-v1/;
+/ {
+ model = "fsl,P1022";
+ compatible = "fsl,P1022DS";
+ #address-cells = <2>;
+ #size-cells = <2>;
+ interrupt-parent = <&mpic>;
+
+ aliases {
+ ethernet0 = &enet0;
+ ethernet1 = &enet1;
+ serial0 = &serial0;
+ serial1 = &serial1;
+ pci0 = &pci0;
+ pci1 = &pci1;
+ pci2 = &pci2;
+ };
+
+ cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ PowerPC,P1022@0 {
+ device_type = "cpu";
+ reg = <0x0>;
+ next-level-cache = <&L2>;
+ };
+
+ PowerPC,P1022@1 {
+ device_type = "cpu";
+ reg = <0x1>;
+ next-level-cache = <&L2>;
+ };
+ };
+
+ memory {
+ device_type = "memory";
+ };
+
+ localbus@fffe05000 {
+ #address-cells = <2>;
+ #size-cells = <1>;
+ compatible = "fsl,p1022-elbc", "fsl,elbc", "simple-bus";
+ reg = <0 0xffe05000 0 0x1000>;
+ interrupts = <19 2>;
+
+ ranges = <0x0 0x0 0xf 0xe8000000 0x08000000
+ 0x1 0x0 0xf 0xe0000000 0x08000000
+ 0x2 0x0 0x0 0xffa00000 0x00040000
+ 0x3 0x0 0xf 0xffdf0000 0x00008000>;
+
+ nor@0,0 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "cfi-flash";
+ reg = <0x0 0x0 0x8000000>;
+ bank-width = <2>;
+ device-width = <1>;
+
+ partition@0 {
+ reg = <0x0 0x03000000>;
+ label = "ramdisk-nor";
+ read-only;
+ };
+
+ partition@3000000 {
+ reg = <0x03000000 0x00e00000>;
+ label = "diagnostic-nor";
+ read-only;
+ };
+
+ partition@3e00000 {
+ reg = <0x03e00000 0x00200000>;
+ label = "dink-nor";
+ read-only;
+ };
+
+ partition@4000000 {
+ reg = <0x04000000 0x00400000>;
+ label = "kernel-nor";
+ read-only;
+ };
+
+ partition@4400000 {
+ reg = <0x04400000 0x03b00000>;
+ label = "jffs2-nor";
+ };
+
+ partition@7f00000 {
+ reg = <0x07f00000 0x00080000>;
+ label = "dtb-nor";
+ read-only;
+ };
+
+ partition@7f80000 {
+ reg = <0x07f80000 0x00080000>;
+ label = "u-boot-nor";
+ read-only;
+ };
+ };
+
+ nand@2,0 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "fsl,elbc-fcm-nand";
+ reg = <0x2 0x0 0x40000>;
+
+ partition@0 {
+ reg = <0x0 0x02000000>;
+ label = "u-boot-nand";
+ read-only;
+ };
+
+ partition@2000000 {
+ reg = <0x02000000 0x10000000>;
+ label = "jffs2-nand";
+ };
+
+ partition@12000000 {
+ reg = <0x12000000 0x10000000>;
+ label = "ramdisk-nand";
+ read-only;
+ };
+
+ partition@22000000 {
+ reg = <0x22000000 0x04000000>;
+ label = "kernel-nand";
+ };
+
+ partition@26000000 {
+ reg = <0x26000000 0x01000000>;
+ label = "dtb-nand";
+ read-only;
+ };
+
+ partition@27000000 {
+ reg = <0x27000000 0x19000000>;
+ label = "reserved-nand";
+ };
+ };
+ };
+
+ soc@fffe00000 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ device_type = "soc";
+ compatible = "fsl,p1022-immr", "simple-bus";
+ ranges = <0x0 0xf 0xffe00000 0x100000>;
+ bus-frequency = <0>; // Filled out by uboot.
+
+ ecm-law@0 {
+ compatible = "fsl,ecm-law";
+ reg = <0x0 0x1000>;
+ fsl,num-laws = <12>;
+ };
+
+ ecm@1000 {
+ compatible = "fsl,p1022-ecm", "fsl,ecm";
+ reg = <0x1000 0x1000>;
+ interrupts = <16 2>;
+ };
+
+ memory-controller@2000 {
+ compatible = "fsl,p1022-memory-controller";
+ reg = <0x2000 0x1000>;
+ interrupts = <16 2>;
+ };
+
+ i2c@3000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ cell-index = <0>;
+ compatible = "fsl-i2c";
+ reg = <0x3000 0x100>;
+ interrupts = <43 2>;
+ dfsrr;
+ };
+
+ i2c@3100 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ cell-index = <1>;
+ compatible = "fsl-i2c";
+ reg = <0x3100 0x100>;
+ interrupts = <43 2>;
+ dfsrr;
+
+ wm8776:codec@1a {
+ compatible = "wlf,wm8776";
+ reg = <0x1a>;
+ /* MCLK source is a stand-alone oscillator */
+ clock-frequency = <12288000>;
+ };
+ };
+
+ serial0: serial@4500 {
+ cell-index = <0>;
+ device_type = "serial";
+ compatible = "ns16550";
+ reg = <0x4500 0x100>;
+ clock-frequency = <0>;
+ interrupts = <42 2>;
+ };
+
+ serial1: serial@4600 {
+ cell-index = <1>;
+ device_type = "serial";
+ compatible = "ns16550";
+ reg = <0x4600 0x100>;
+ clock-frequency = <0>;
+ interrupts = <42 2>;
+ };
+
+ spi@7000 {
+ cell-index = <0>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "fsl,espi";
+ reg = <0x7000 0x1000>;
+ interrupts = <59 0x2>;
+ espi,num-ss-bits = <4>;
+ mode = "cpu";
+
+ fsl_m25p80@0 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "fsl,espi-flash";
+ reg = <0>;
+ linux,modalias = "fsl_m25p80";
+ spi-max-frequency = <40000000>; /* input clock */
+ partition@0 {
+ label = "u-boot-spi";
+ reg = <0x00000000 0x00100000>;
+ read-only;
+ };
+ partition@100000 {
+ label = "kernel-spi";
+ reg = <0x00100000 0x00500000>;
+ read-only;
+ };
+ partition@600000 {
+ label = "dtb-spi";
+ reg = <0x00600000 0x00100000>;
+ read-only;
+ };
+ partition@700000 {
+ label = "file system-spi";
+ reg = <0x00700000 0x00900000>;
+ };
+ };
+ };
+
+ ssi@15000 {
+ compatible = "fsl,mpc8610-ssi";
+ cell-index = <0>;
+ reg = <0x15000 0x100>;
+ interrupts = <75 2>;
+ fsl,mode = "i2s-slave";
+ codec-handle = <&wm8776>;
+ fsl,playback-dma = <&dma00>;
+ fsl,capture-dma = <&dma01>;
+ fsl,fifo-depth = <16>;
+ };
+
+ dma@c300 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "fsl,eloplus-dma";
+ reg = <0xc300 0x4>;
+ ranges = <0x0 0xc100 0x200>;
+ cell-index = <1>;
+ dma00: dma-channel@0 {
+ compatible = "fsl,eloplus-dma-channel";
+ reg = <0x0 0x80>;
+ cell-index = <0>;
+ interrupts = <76 2>;
+ };
+ dma01: dma-channel@80 {
+ compatible = "fsl,eloplus-dma-channel";
+ reg = <0x80 0x80>;
+ cell-index = <1>;
+ interrupts = <77 2>;
+ };
+ dma-channel@100 {
+ compatible = "fsl,eloplus-dma-channel";
+ reg = <0x100 0x80>;
+ cell-index = <2>;
+ interrupts = <78 2>;
+ };
+ dma-channel@180 {
+ compatible = "fsl,eloplus-dma-channel";
+ reg = <0x180 0x80>;
+ cell-index = <3>;
+ interrupts = <79 2>;
+ };
+ };
+
+ gpio: gpio-controller@f000 {
+ #gpio-cells = <2>;
+ compatible = "fsl,mpc8572-gpio";
+ reg = <0xf000 0x100>;
+ interrupts = <47 0x2>;
+ gpio-controller;
+ };
+
+ L2: l2-cache-controller@20000 {
+ compatible = "fsl,p1022-l2-cache-controller";
+ reg = <0x20000 0x1000>;
+ cache-line-size = <32>; // 32 bytes
+ cache-size = <0x40000>; // L2, 256K
+ interrupts = <16 2>;
+ };
+
+ dma@21300 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "fsl,eloplus-dma";
+ reg = <0x21300 0x4>;
+ ranges = <0x0 0x21100 0x200>;
+ cell-index = <0>;
+ dma-channel@0 {
+ compatible = "fsl,eloplus-dma-channel";
+ reg = <0x0 0x80>;
+ cell-index = <0>;
+ interrupts = <20 2>;
+ };
+ dma-channel@80 {
+ compatible = "fsl,eloplus-dma-channel";
+ reg = <0x80 0x80>;
+ cell-index = <1>;
+ interrupts = <21 2>;
+ };
+ dma-channel@100 {
+ compatible = "fsl,eloplus-dma-channel";
+ reg = <0x100 0x80>;
+ cell-index = <2>;
+ interrupts = <22 2>;
+ };
+ dma-channel@180 {
+ compatible = "fsl,eloplus-dma-channel";
+ reg = <0x180 0x80>;
+ cell-index = <3>;
+ interrupts = <23 2>;
+ };
+ };
+
+ usb@22000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "fsl-usb2-dr";
+ reg = <0x22000 0x1000>;
+ interrupts = <28 0x2>;
+ phy_type = "ulpi";
+ };
+
+ mdio@24000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "fsl,etsec2-mdio";
+ reg = <0x24000 0x1000 0xb0030 0x4>;
+
+ phy0: ethernet-phy@0 {
+ interrupts = <3 1>;
+ reg = <0x1>;
+ };
+ phy1: ethernet-phy@1 {
+ interrupts = <9 1>;
+ reg = <0x2>;
+ };
+ };
+
+ mdio@25000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "fsl,etsec2-mdio";
+ reg = <0x25000 0x1000 0xb1030 0x4>;
+ };
+
+ enet0: ethernet@B0000 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ cell-index = <0>;
+ device_type = "network";
+ model = "eTSEC";
+ compatible = "fsl,etsec2";
+ fsl,num_rx_queues = <0x8>;
+ fsl,num_tx_queues = <0x8>;
+ fsl,magic-packet;
+ fsl,wake-on-filer;
+ local-mac-address = [ 00 00 00 00 00 00 ];
+ fixed-link = <1 1 1000 0 0>;
+ phy-handle = <&phy0>;
+ phy-connection-type = "rgmii-id";
+ queue-group@0{
+ #address-cells = <1>;
+ #size-cells = <1>;
+ reg = <0xB0000 0x1000>;
+ interrupts = <29 2 30 2 34 2>;
+ };
+ queue-group@1{
+ #address-cells = <1>;
+ #size-cells = <1>;
+ reg = <0xB4000 0x1000>;
+ interrupts = <17 2 18 2 24 2>;
+ };
+ };
+
+ enet1: ethernet@B1000 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ cell-index = <0>;
+ device_type = "network";
+ model = "eTSEC";
+ compatible = "fsl,etsec2";
+ fsl,num_rx_queues = <0x8>;
+ fsl,num_tx_queues = <0x8>;
+ local-mac-address = [ 00 00 00 00 00 00 ];
+ fixed-link = <1 1 1000 0 0>;
+ phy-handle = <&phy1>;
+ phy-connection-type = "rgmii-id";
+ queue-group@0{
+ #address-cells = <1>;
+ #size-cells = <1>;
+ reg = <0xB1000 0x1000>;
+ interrupts = <35 2 36 2 40 2>;
+ };
+ queue-group@1{
+ #address-cells = <1>;
+ #size-cells = <1>;
+ reg = <0xB5000 0x1000>;
+ interrupts = <51 2 52 2 67 2>;
+ };
+ };
+
+ sdhci@2e000 {
+ compatible = "fsl,p1022-esdhc", "fsl,esdhc";
+ reg = <0x2e000 0x1000>;
+ interrupts = <72 0x2>;
+ fsl,sdhci-auto-cmd12;
+ /* Filled in by U-Boot */
+ clock-frequency = <0>;
+ };
+
+ crypto@30000 {
+ compatible = "fsl,sec3.3", "fsl,sec3.1", "fsl,sec3.0",
+ "fsl,sec2.4", "fsl,sec2.2", "fsl,sec2.1",
+ "fsl,sec2.0";
+ reg = <0x30000 0x10000>;
+ interrupts = <45 2 58 2>;
+ fsl,num-channels = <4>;
+ fsl,channel-fifo-len = <24>;
+ fsl,exec-units-mask = <0x97c>;
+ fsl,descriptor-types-mask = <0x3a30abf>;
+ };
+
+ sata@18000 {
+ compatible = "fsl,mpc8536-sata", "fsl,pq-sata";
+ reg = <0x18000 0x1000>;
+ cell-index = <1>;
+ interrupts = <74 0x2>;
+ };
+
+ sata@19000 {
+ compatible = "fsl,mpc8536-sata", "fsl,pq-sata";
+ reg = <0x19000 0x1000>;
+ cell-index = <2>;
+ interrupts = <41 0x2>;
+ };
+
+ power@e0070{
+ compatible = "fsl,mpc8536-pmc", "fsl,mpc8548-pmc";
+ reg = <0xe0070 0x20>;
+ };
+
+ display@10000 {
+ compatible = "fsl,diu", "fsl,p1022-diu";
+ reg = <0x10000 1000>;
+ interrupts = <64 2>;
+ };
+
+ timer@41100 {
+ compatible = "fsl,mpic-global-timer";
+ reg = <0x41100 0x204>;
+ interrupts = <0xf7 0x2>;
+ };
+
+ mpic: pic@40000 {
+ interrupt-controller;
+ #address-cells = <0>;
+ #interrupt-cells = <2>;
+ reg = <0x40000 0x40000>;
+ compatible = "chrp,open-pic";
+ device_type = "open-pic";
+ };
+
+ msi@41600 {
+ compatible = "fsl,p1022-msi", "fsl,mpic-msi";
+ reg = <0x41600 0x80>;
+ msi-available-ranges = <0 0x100>;
+ interrupts = <
+ 0xe0 0
+ 0xe1 0
+ 0xe2 0
+ 0xe3 0
+ 0xe4 0
+ 0xe5 0
+ 0xe6 0
+ 0xe7 0>;
+ };
+
+ global-utilities@e0000 { //global utilities block
+ compatible = "fsl,p1022-guts";
+ reg = <0xe0000 0x1000>;
+ fsl,has-rstcr;
+ };
+ };
+
+ pci0: pcie@fffe09000 {
+ compatible = "fsl,p1022-pcie";
+ device_type = "pci";
+ #interrupt-cells = <1>;
+ #size-cells = <2>;
+ #address-cells = <3>;
+ reg = <0xf 0xffe09000 0 0x1000>;
+ bus-range = <0 255>;
+ ranges = <0x2000000 0x0 0xa0000000 0xc 0x20000000 0x0 0x20000000
+ 0x1000000 0x0 0x00000000 0xf 0xffc10000 0x0 0x10000>;
+ clock-frequency = <33333333>;
+ interrupts = <16 2>;
+ interrupt-map-mask = <0xf800 0 0 7>;
+ interrupt-map = <
+ /* IDSEL 0x0 */
+ 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
+ >;
+ pcie@0 {
+ reg = <0x0 0x0 0x0 0x0 0x0>;
+ #size-cells = <2>;
+ #address-cells = <3>;
+ device_type = "pci";
+ ranges = <0x2000000 0x0 0xe0000000
+ 0x2000000 0x0 0xe0000000
+ 0x0 0x20000000
+
+ 0x1000000 0x0 0x0
+ 0x1000000 0x0 0x0
+ 0x0 0x100000>;
+ };
+ };
+
+ pci1: pcie@fffe0a000 {
+ compatible = "fsl,p1022-pcie";
+ device_type = "pci";
+ #interrupt-cells = <1>;
+ #size-cells = <2>;
+ #address-cells = <3>;
+ reg = <0xf 0xffe0a000 0 0x1000>;
+ bus-range = <0 255>;
+ ranges = <0x2000000 0x0 0xc0000000 0xc 0x40000000 0x0 0x20000000
+ 0x1000000 0x0 0x00000000 0xf 0xffc20000 0x0 0x10000>;
+ clock-frequency = <33333333>;
+ interrupts = <16 2>;
+ interrupt-map-mask = <0xf800 0 0 7>;
+ interrupt-map = <
+ /* IDSEL 0x0 */
+ 0000 0 0 1 &mpic 0 1
+ 0000 0 0 2 &mpic 1 1
+ 0000 0 0 3 &mpic 2 1
+ 0000 0 0 4 &mpic 3 1
+ >;
+ pcie@0 {
+ reg = <0x0 0x0 0x0 0x0 0x0>;
+ #size-cells = <2>;
+ #address-cells = <3>;
+ device_type = "pci";
+ ranges = <0x2000000 0x0 0xe0000000
+ 0x2000000 0x0 0xe0000000
+ 0x0 0x20000000
+
+ 0x1000000 0x0 0x0
+ 0x1000000 0x0 0x0
+ 0x0 0x100000>;
+ };
+ };
+
+
+ pci2: pcie@fffe0b000 {
+ compatible = "fsl,p1022-pcie";
+ device_type = "pci";
+ #interrupt-cells = <1>;
+ #size-cells = <2>;
+ #address-cells = <3>;
+ reg = <0xf 0xffe0b000 0 0x1000>;
+ bus-range = <0 255>;
+ ranges = <0x2000000 0x0 0x80000000 0xc 0x00000000 0x0 0x20000000
+ 0x1000000 0x0 0x00000000 0xf 0xffc00000 0x0 0x10000>;
+ clock-frequency = <33333333>;
+ interrupts = <16 2>;
+ interrupt-map-mask = <0xf800 0 0 7>;
+ interrupt-map = <
+ /* IDSEL 0x0 */
+ 0000 0 0 1 &mpic 8 1
+ 0000 0 0 2 &mpic 9 1
+ 0000 0 0 3 &mpic 10 1
+ 0000 0 0 4 &mpic 11 1
+ >;
+ pcie@0 {
+ reg = <0x0 0x0 0x0 0x0 0x0>;
+ #size-cells = <2>;
+ #address-cells = <3>;
+ device_type = "pci";
+ ranges = <0x2000000 0x0 0xe0000000
+ 0x2000000 0x0 0xe0000000
+ 0x0 0x20000000
+
+ 0x1000000 0x0 0x0
+ 0x1000000 0x0 0x0
+ 0x0 0x100000>;
+ };
+ };
+};
diff --git a/arch/powerpc/boot/dts/pdm360ng.dts b/arch/powerpc/boot/dts/pdm360ng.dts
new file mode 100644
index 00000000000..94dfa5c9a7f
--- /dev/null
+++ b/arch/powerpc/boot/dts/pdm360ng.dts
@@ -0,0 +1,410 @@
+/*
+ * Device Tree Source for IFM PDM360NG.
+ *
+ * Copyright 2009 - 2010 DENX Software Engineering.
+ * Anatolij Gustschin <agust@denx.de>
+ *
+ * Based on MPC5121E ADS dts.
+ * Copyright 2008 Freescale Semiconductor Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+/dts-v1/;
+
+/ {
+ model = "pdm360ng";
+ compatible = "ifm,pdm360ng";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ interrupt-parent = <&ipic>;
+
+ aliases {
+ ethernet0 = &eth0;
+ };
+
+ cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ PowerPC,5121@0 {
+ device_type = "cpu";
+ reg = <0>;
+ d-cache-line-size = <0x20>; // 32 bytes
+ i-cache-line-size = <0x20>; // 32 bytes
+ d-cache-size = <0x8000>; // L1, 32K
+ i-cache-size = <0x8000>; // L1, 32K
+ timebase-frequency = <49500000>;// 49.5 MHz (csb/4)
+ bus-frequency = <198000000>; // 198 MHz csb bus
+ clock-frequency = <396000000>; // 396 MHz ppc core
+ };
+ };
+
+ memory {
+ device_type = "memory";
+ reg = <0x00000000 0x20000000>; // 512MB at 0
+ };
+
+ nfc@40000000 {
+ compatible = "fsl,mpc5121-nfc";
+ reg = <0x40000000 0x100000>;
+ interrupts = <0x6 0x8>;
+ #address-cells = <0x1>;
+ #size-cells = <0x1>;
+ bank-width = <0x1>;
+ chips = <0x1>;
+
+ partition@0 {
+ label = "nand0";
+ reg = <0x0 0x40000000>;
+ };
+ };
+
+ sram@50000000 {
+ compatible = "fsl,mpc5121-sram";
+ reg = <0x50000000 0x20000>; // 128K at 0x50000000
+ };
+
+ localbus@80000020 {
+ compatible = "fsl,mpc5121-localbus";
+ #address-cells = <2>;
+ #size-cells = <1>;
+ reg = <0x80000020 0x40>;
+
+ ranges = <0x0 0x0 0xf0000000 0x10000000 /* Flash */
+ 0x2 0x0 0x50040000 0x00020000>; /* CS2: MRAM */
+
+ flash@0,0 {
+ compatible = "amd,s29gl01gp", "cfi-flash";
+ reg = <0 0x00000000 0x08000000
+ 0 0x08000000 0x08000000>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ bank-width = <4>;
+ device-width = <2>;
+
+ partition@0 {
+ label = "u-boot";
+ reg = <0x00000000 0x00080000>;
+ read-only;
+ };
+ partition@80000 {
+ label = "environment";
+ reg = <0x00080000 0x00080000>;
+ read-only;
+ };
+ partition@100000 {
+ label = "splash-image";
+ reg = <0x00100000 0x00080000>;
+ read-only;
+ };
+ partition@180000 {
+ label = "device-tree";
+ reg = <0x00180000 0x00040000>;
+ };
+ partition@1c0000 {
+ label = "kernel";
+ reg = <0x001c0000 0x00500000>;
+ };
+ partition@6c0000 {
+ label = "filesystem";
+ reg = <0x006c0000 0x07940000>;
+ };
+ };
+
+ mram0@2,0 {
+ compatible = "mtd-ram";
+ reg = <2 0x00000 0x10000>;
+ bank-width = <2>;
+ };
+
+ mram1@2,10000 {
+ compatible = "mtd-ram";
+ reg = <2 0x010000 0x10000>;
+ bank-width = <2>;
+ };
+ };
+
+ soc@80000000 {
+ compatible = "fsl,mpc5121-immr";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ #interrupt-cells = <2>;
+ ranges = <0x0 0x80000000 0x400000>;
+ reg = <0x80000000 0x400000>;
+ bus-frequency = <66000000>; // 66 MHz ips bus
+
+ // IPIC
+ // interrupts cell = <intr #, sense>
+ // sense values match linux IORESOURCE_IRQ_* defines:
+ // sense == 8: Level, low assertion
+ // sense == 2: Edge, high-to-low change
+ //
+ ipic: interrupt-controller@c00 {
+ compatible = "fsl,mpc5121-ipic", "fsl,ipic";
+ interrupt-controller;
+ #address-cells = <0>;
+ #interrupt-cells = <2>;
+ reg = <0xc00 0x100>;
+ };
+
+ rtc@a00 { // Real time clock
+ compatible = "fsl,mpc5121-rtc";
+ reg = <0xa00 0x100>;
+ interrupts = <79 0x8 80 0x8>;
+ };
+
+ reset@e00 { // Reset module
+ compatible = "fsl,mpc5121-reset";
+ reg = <0xe00 0x100>;
+ };
+
+ clock@f00 { // Clock control
+ compatible = "fsl,mpc5121-clock";
+ reg = <0xf00 0x100>;
+ };
+
+ pmc@1000{ //Power Management Controller
+ compatible = "fsl,mpc5121-pmc";
+ reg = <0x1000 0x100>;
+ interrupts = <83 0x2>;
+ };
+
+ gpio@1100 {
+ compatible = "fsl,mpc5121-gpio";
+ reg = <0x1100 0x100>;
+ interrupts = <78 0x8>;
+ };
+
+ can@1300 {
+ compatible = "fsl,mpc5121-mscan";
+ interrupts = <12 0x8>;
+ reg = <0x1300 0x80>;
+ };
+
+ can@1380 {
+ compatible = "fsl,mpc5121-mscan";
+ interrupts = <13 0x8>;
+ reg = <0x1380 0x80>;
+ };
+
+ i2c@1700 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "fsl,mpc5121-i2c";
+ reg = <0x1700 0x20>;
+ interrupts = <0x9 0x8>;
+ fsl,preserve-clocking;
+
+ eeprom@50 {
+ compatible = "at,24c01";
+ reg = <0x50>;
+ };
+
+ rtc@68 {
+ compatible = "stm,m41t00";
+ reg = <0x68>;
+ };
+ };
+
+ i2c@1740 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "fsl,mpc5121-i2c";
+ reg = <0x1740 0x20>;
+ interrupts = <0xb 0x8>;
+ fsl,preserve-clocking;
+ };
+
+ i2ccontrol@1760 {
+ compatible = "fsl,mpc5121-i2c-ctrl";
+ reg = <0x1760 0x8>;
+ };
+
+ axe@2000 {
+ compatible = "fsl,mpc5121-axe";
+ reg = <0x2000 0x100>;
+ interrupts = <42 0x8>;
+ };
+
+ display@2100 {
+ compatible = "fsl,mpc5121-diu";
+ reg = <0x2100 0x100>;
+ interrupts = <64 0x8>;
+ };
+
+ can@2300 {
+ compatible = "fsl,mpc5121-mscan";
+ interrupts = <90 0x8>;
+ reg = <0x2300 0x80>;
+ };
+
+ can@2380 {
+ compatible = "fsl,mpc5121-mscan";
+ interrupts = <91 0x8>;
+ reg = <0x2380 0x80>;
+ };
+
+ viu@2400 {
+ compatible = "fsl,mpc5121-viu";
+ reg = <0x2400 0x400>;
+ interrupts = <67 0x8>;
+ };
+
+ mdio@2800 {
+ compatible = "fsl,mpc5121-fec-mdio";
+ reg = <0x2800 0x200>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ phy: ethernet-phy@0 {
+ compatible = "smsc,lan8700";
+ reg = <0x1f>;
+ };
+ };
+
+ eth0: ethernet@2800 {
+ compatible = "fsl,mpc5121-fec";
+ reg = <0x2800 0x200>;
+ local-mac-address = [ 00 00 00 00 00 00 ];
+ interrupts = <4 0x8>;
+ phy-handle = < &phy >;
+ };
+
+ // USB1 using external ULPI PHY
+ usb@3000 {
+ compatible = "fsl,mpc5121-usb2-dr";
+ reg = <0x3000 0x600>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ interrupts = <43 0x8>;
+ dr_mode = "host";
+ phy_type = "ulpi";
+ };
+
+ // USB0 using internal UTMI PHY
+ usb@4000 {
+ compatible = "fsl,mpc5121-usb2-dr";
+ reg = <0x4000 0x600>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ interrupts = <44 0x8>;
+ dr_mode = "otg";
+ phy_type = "utmi_wide";
+ fsl,invert-pwr-fault;
+ };
+
+ // IO control
+ ioctl@a000 {
+ compatible = "fsl,mpc5121-ioctl";
+ reg = <0xA000 0x1000>;
+ };
+
+ // 512x PSCs are not 52xx PSCs compatible
+ serial@11000 {
+ compatible = "fsl,mpc5121-psc-uart", "fsl,mpc5121-psc";
+ cell-index = <0>;
+ reg = <0x11000 0x100>;
+ interrupts = <40 0x8>;
+ fsl,rx-fifo-size = <16>;
+ fsl,tx-fifo-size = <16>;
+ };
+
+ serial@11100 {
+ compatible = "fsl,mpc5121-psc-uart", "fsl,mpc5121-psc";
+ cell-index = <1>;
+ reg = <0x11100 0x100>;
+ interrupts = <40 0x8>;
+ fsl,rx-fifo-size = <16>;
+ fsl,tx-fifo-size = <16>;
+ };
+
+ serial@11200 {
+ compatible = "fsl,mpc5121-psc-uart", "fsl,mpc5121-psc";
+ cell-index = <2>;
+ reg = <0x11200 0x100>;
+ interrupts = <40 0x8>;
+ fsl,rx-fifo-size = <16>;
+ fsl,tx-fifo-size = <16>;
+ };
+
+ serial@11300 {
+ compatible = "fsl,mpc5121-psc-uart", "fsl,mpc5121-psc";
+ cell-index = <3>;
+ reg = <0x11300 0x100>;
+ interrupts = <40 0x8>;
+ fsl,rx-fifo-size = <16>;
+ fsl,tx-fifo-size = <16>;
+ };
+
+ serial@11400 {
+ compatible = "fsl,mpc5121-psc-uart", "fsl,mpc5121-psc";
+ cell-index = <4>;
+ reg = <0x11400 0x100>;
+ interrupts = <40 0x8>;
+ fsl,rx-fifo-size = <16>;
+ fsl,tx-fifo-size = <16>;
+ };
+
+ serial@11600 {
+ compatible = "fsl,mpc5121-psc-uart", "fsl,mpc5121-psc";
+ cell-index = <6>;
+ reg = <0x11600 0x100>;
+ interrupts = <40 0x8>;
+ fsl,rx-fifo-size = <16>;
+ fsl,tx-fifo-size = <16>;
+ };
+
+ serial@11800 {
+ compatible = "fsl,mpc5121-psc-uart", "fsl,mpc5121-psc";
+ cell-index = <8>;
+ reg = <0x11800 0x100>;
+ interrupts = <40 0x8>;
+ fsl,rx-fifo-size = <16>;
+ fsl,tx-fifo-size = <16>;
+ };
+
+ serial@11B00 {
+ compatible = "fsl,mpc5121-psc-uart", "fsl,mpc5121-psc";
+ cell-index = <11>;
+ reg = <0x11B00 0x100>;
+ interrupts = <40 0x8>;
+ fsl,rx-fifo-size = <16>;
+ fsl,tx-fifo-size = <16>;
+ };
+
+ pscfifo@11f00 {
+ compatible = "fsl,mpc5121-psc-fifo";
+ reg = <0x11f00 0x100>;
+ interrupts = <40 0x8>;
+ };
+
+ spi@11900 {
+ compatible = "fsl,mpc5121-psc-spi", "fsl,mpc5121-psc";
+ cell-index = <9>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0x11900 0x100>;
+ interrupts = <40 0x8>;
+ fsl,rx-fifo-size = <16>;
+ fsl,tx-fifo-size = <16>;
+
+ // 7845 touch screen controller
+ ts@0 {
+ compatible = "ti,ads7846";
+ reg = <0x0>;
+ spi-max-frequency = <3000000>;
+ // pen irq is GPIO25
+ interrupts = <78 0x8>;
+ };
+ };
+
+ dma@14000 {
+ compatible = "fsl,mpc5121-dma";
+ reg = <0x14000 0x1800>;
+ interrupts = <65 0x8>;
+ };
+ };
+};
diff --git a/arch/powerpc/boot/dts/stxssa8555.dts b/arch/powerpc/boot/dts/stxssa8555.dts
new file mode 100644
index 00000000000..49efd44057d
--- /dev/null
+++ b/arch/powerpc/boot/dts/stxssa8555.dts
@@ -0,0 +1,380 @@
+/*
+ * MPC8555-based STx GP3 Device Tree Source
+ *
+ * Copyright 2006, 2008 Freescale Semiconductor Inc.
+ *
+ * Copyright 2010 Silicon Turnkey Express LLC.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+/dts-v1/;
+
+/ {
+ model = "stx,gp3";
+ compatible = "stx,gp3-8560", "stx,gp3";
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ aliases {
+ ethernet0 = &enet0;
+ ethernet1 = &enet1;
+ serial0 = &serial0;
+ serial1 = &serial1;
+ pci0 = &pci0;
+ };
+
+ cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ PowerPC,8555@0 {
+ device_type = "cpu";
+ reg = <0x0>;
+ d-cache-line-size = <32>; // 32 bytes
+ i-cache-line-size = <32>; // 32 bytes
+ d-cache-size = <0x8000>; // L1, 32K
+ i-cache-size = <0x8000>; // L1, 32K
+ timebase-frequency = <0>; // 33 MHz, from uboot
+ bus-frequency = <0>; // 166 MHz
+ clock-frequency = <0>; // 825 MHz, from uboot
+ next-level-cache = <&L2>;
+ };
+ };
+
+ memory {
+ device_type = "memory";
+ reg = <0x00000000 0x10000000>;
+ };
+
+ soc8555@e0000000 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ device_type = "soc";
+ compatible = "simple-bus";
+ ranges = <0x0 0xe0000000 0x100000>;
+ bus-frequency = <0>;
+
+ ecm-law@0 {
+ compatible = "fsl,ecm-law";
+ reg = <0x0 0x1000>;
+ fsl,num-laws = <8>;
+ };
+
+ ecm@1000 {
+ compatible = "fsl,mpc8555-ecm", "fsl,ecm";
+ reg = <0x1000 0x1000>;
+ interrupts = <17 2>;
+ interrupt-parent = <&mpic>;
+ };
+
+ memory-controller@2000 {
+ compatible = "fsl,mpc8555-memory-controller";
+ reg = <0x2000 0x1000>;
+ interrupt-parent = <&mpic>;
+ interrupts = <18 2>;
+ };
+
+ L2: l2-cache-controller@20000 {
+ compatible = "fsl,mpc8555-l2-cache-controller";
+ reg = <0x20000 0x1000>;
+ cache-line-size = <32>; // 32 bytes
+ cache-size = <0x40000>; // L2, 256K
+ interrupt-parent = <&mpic>;
+ interrupts = <16 2>;
+ };
+
+ i2c@3000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ cell-index = <0>;
+ compatible = "fsl-i2c";
+ reg = <0x3000 0x100>;
+ interrupts = <43 2>;
+ interrupt-parent = <&mpic>;
+ dfsrr;
+ };
+
+ dma@21300 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "fsl,mpc8555-dma", "fsl,eloplus-dma";
+ reg = <0x21300 0x4>;
+ ranges = <0x0 0x21100 0x200>;
+ cell-index = <0>;
+ dma-channel@0 {
+ compatible = "fsl,mpc8555-dma-channel",
+ "fsl,eloplus-dma-channel";
+ reg = <0x0 0x80>;
+ cell-index = <0>;
+ interrupt-parent = <&mpic>;
+ interrupts = <20 2>;
+ };
+ dma-channel@80 {
+ compatible = "fsl,mpc8555-dma-channel",
+ "fsl,eloplus-dma-channel";
+ reg = <0x80 0x80>;
+ cell-index = <1>;
+ interrupt-parent = <&mpic>;
+ interrupts = <21 2>;
+ };
+ dma-channel@100 {
+ compatible = "fsl,mpc8555-dma-channel",
+ "fsl,eloplus-dma-channel";
+ reg = <0x100 0x80>;
+ cell-index = <2>;
+ interrupt-parent = <&mpic>;
+ interrupts = <22 2>;
+ };
+ dma-channel@180 {
+ compatible = "fsl,mpc8555-dma-channel",
+ "fsl,eloplus-dma-channel";
+ reg = <0x180 0x80>;
+ cell-index = <3>;
+ interrupt-parent = <&mpic>;
+ interrupts = <23 2>;
+ };
+ };
+
+ enet0: ethernet@24000 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ cell-index = <0>;
+ device_type = "network";
+ model = "TSEC";
+ compatible = "gianfar";
+ reg = <0x24000 0x1000>;
+ ranges = <0x0 0x24000 0x1000>;
+ local-mac-address = [ 00 00 00 00 00 00 ];
+ interrupts = <29 2 30 2 34 2>;
+ interrupt-parent = <&mpic>;
+ tbi-handle = <&tbi0>;
+ phy-handle = <&phy0>;
+
+ mdio@520 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "fsl,gianfar-mdio";
+ reg = <0x520 0x20>;
+
+ phy0: ethernet-phy@2 {
+ interrupt-parent = <&mpic>;
+ interrupts = <5 1>;
+ reg = <0x2>;
+ device_type = "ethernet-phy";
+ };
+ phy1: ethernet-phy@4 {
+ interrupt-parent = <&mpic>;
+ interrupts = <5 1>;
+ reg = <0x4>;
+ device_type = "ethernet-phy";
+ };
+ tbi0: tbi-phy@11 {
+ reg = <0x11>;
+ device_type = "tbi-phy";
+ };
+ };
+ };
+
+ enet1: ethernet@25000 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ cell-index = <1>;
+ device_type = "network";
+ model = "TSEC";
+ compatible = "gianfar";
+ reg = <0x25000 0x1000>;
+ ranges = <0x0 0x25000 0x1000>;
+ local-mac-address = [ 00 00 00 00 00 00 ];
+ interrupts = <35 2 36 2 40 2>;
+ interrupt-parent = <&mpic>;
+ tbi-handle = <&tbi1>;
+ phy-handle = <&phy1>;
+
+ mdio@520 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "fsl,gianfar-tbi";
+ reg = <0x520 0x20>;
+
+ tbi1: tbi-phy@11 {
+ reg = <0x11>;
+ device_type = "tbi-phy";
+ };
+ };
+ };
+
+ serial0: serial@4500 {
+ cell-index = <0>;
+ device_type = "serial";
+ compatible = "ns16550";
+ reg = <0x4500 0x100>; // reg base, size
+ clock-frequency = <0>; // should we fill in in uboot?
+ interrupts = <42 2>;
+ interrupt-parent = <&mpic>;
+ };
+
+ serial1: serial@4600 {
+ cell-index = <1>;
+ device_type = "serial";
+ compatible = "ns16550";
+ reg = <0x4600 0x100>; // reg base, size
+ clock-frequency = <0>; // should we fill in in uboot?
+ interrupts = <42 2>;
+ interrupt-parent = <&mpic>;
+ };
+
+ crypto@30000 {
+ compatible = "fsl,sec2.0";
+ reg = <0x30000 0x10000>;
+ interrupts = <45 2>;
+ interrupt-parent = <&mpic>;
+ fsl,num-channels = <4>;
+ fsl,channel-fifo-len = <24>;
+ fsl,exec-units-mask = <0x7e>;
+ fsl,descriptor-types-mask = <0x01010ebf>;
+ };
+
+ mpic: pic@40000 {
+ interrupt-controller;
+ #address-cells = <0>;
+ #interrupt-cells = <2>;
+ reg = <0x40000 0x40000>;
+ compatible = "chrp,open-pic";
+ device_type = "open-pic";
+ };
+
+ cpm@919c0 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "fsl,mpc8555-cpm", "fsl,cpm2";
+ reg = <0x919c0 0x30>;
+ ranges;
+
+ muram@80000 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges = <0x0 0x80000 0x10000>;
+
+ data@0 {
+ compatible = "fsl,cpm-muram-data";
+ reg = <0x0 0x2000 0x9000 0x1000>;
+ };
+ };
+
+ brg@919f0 {
+ compatible = "fsl,mpc8555-brg",
+ "fsl,cpm2-brg",
+ "fsl,cpm-brg";
+ reg = <0x919f0 0x10 0x915f0 0x10>;
+ };
+
+ cpmpic: pic@90c00 {
+ interrupt-controller;
+ #address-cells = <0>;
+ #interrupt-cells = <2>;
+ interrupts = <46 2>;
+ interrupt-parent = <&mpic>;
+ reg = <0x90c00 0x80>;
+ compatible = "fsl,mpc8555-cpm-pic", "fsl,cpm2-pic";
+ };
+ };
+ };
+
+ pci0: pci@e0008000 {
+ interrupt-map-mask = <0x1f800 0x0 0x0 0x7>;
+ interrupt-map = <
+
+ /* IDSEL 0x10 */
+ 0x8000 0x0 0x0 0x1 &mpic 0x0 0x1
+ 0x8000 0x0 0x0 0x2 &mpic 0x1 0x1
+ 0x8000 0x0 0x0 0x3 &mpic 0x2 0x1
+ 0x8000 0x0 0x0 0x4 &mpic 0x3 0x1
+
+ /* IDSEL 0x11 */
+ 0x8800 0x0 0x0 0x1 &mpic 0x0 0x1
+ 0x8800 0x0 0x0 0x2 &mpic 0x1 0x1
+ 0x8800 0x0 0x0 0x3 &mpic 0x2 0x1
+ 0x8800 0x0 0x0 0x4 &mpic 0x3 0x1
+
+ /* IDSEL 0x12 (Slot 1) */
+ 0x9000 0x0 0x0 0x1 &mpic 0x0 0x1
+ 0x9000 0x0 0x0 0x2 &mpic 0x1 0x1
+ 0x9000 0x0 0x0 0x3 &mpic 0x2 0x1
+ 0x9000 0x0 0x0 0x4 &mpic 0x3 0x1
+
+ /* IDSEL 0x13 (Slot 2) */
+ 0x9800 0x0 0x0 0x1 &mpic 0x1 0x1
+ 0x9800 0x0 0x0 0x2 &mpic 0x2 0x1
+ 0x9800 0x0 0x0 0x3 &mpic 0x3 0x1
+ 0x9800 0x0 0x0 0x4 &mpic 0x0 0x1
+
+ /* IDSEL 0x14 (Slot 3) */
+ 0xa000 0x0 0x0 0x1 &mpic 0x2 0x1
+ 0xa000 0x0 0x0 0x2 &mpic 0x3 0x1
+ 0xa000 0x0 0x0 0x3 &mpic 0x0 0x1
+ 0xa000 0x0 0x0 0x4 &mpic 0x1 0x1
+
+ /* IDSEL 0x15 (Slot 4) */
+ 0xa800 0x0 0x0 0x1 &mpic 0x3 0x1
+ 0xa800 0x0 0x0 0x2 &mpic 0x0 0x1
+ 0xa800 0x0 0x0 0x3 &mpic 0x1 0x1
+ 0xa800 0x0 0x0 0x4 &mpic 0x2 0x1
+
+ /* Bus 1 (Tundra Bridge) */
+ /* IDSEL 0x12 (ISA bridge) */
+ 0x19000 0x0 0x0 0x1 &mpic 0x0 0x1
+ 0x19000 0x0 0x0 0x2 &mpic 0x1 0x1
+ 0x19000 0x0 0x0 0x3 &mpic 0x2 0x1
+ 0x19000 0x0 0x0 0x4 &mpic 0x3 0x1>;
+ interrupt-parent = <&mpic>;
+ interrupts = <24 2>;
+ bus-range = <0 0>;
+ ranges = <0x2000000 0x0 0x80000000 0x80000000 0x0 0x20000000
+ 0x1000000 0x0 0x0 0xe2000000 0x0 0x100000>;
+ clock-frequency = <66666666>;
+ #interrupt-cells = <1>;
+ #size-cells = <2>;
+ #address-cells = <3>;
+ reg = <0xe0008000 0x1000>;
+ compatible = "fsl,mpc8540-pci";
+ device_type = "pci";
+
+ i8259@19000 {
+ interrupt-controller;
+ device_type = "interrupt-controller";
+ reg = <0x19000 0x0 0x0 0x0 0x1>;
+ #address-cells = <0>;
+ #interrupt-cells = <2>;
+ compatible = "chrp,iic";
+ interrupts = <1>;
+ interrupt-parent = <&pci0>;
+ };
+ };
+
+ pci1: pci@e0009000 {
+ interrupt-map-mask = <0xf800 0x0 0x0 0x7>;
+ interrupt-map = <
+
+ /* IDSEL 0x15 */
+ 0xa800 0x0 0x0 0x1 &mpic 0xb 0x1
+ 0xa800 0x0 0x0 0x2 &mpic 0xb 0x1
+ 0xa800 0x0 0x0 0x3 &mpic 0xb 0x1
+ 0xa800 0x0 0x0 0x4 &mpic 0xb 0x1>;
+ interrupt-parent = <&mpic>;
+ interrupts = <25 2>;
+ bus-range = <0 0>;
+ ranges = <0x2000000 0x0 0xa0000000 0xa0000000 0x0 0x20000000
+ 0x1000000 0x0 0x0 0xe3000000 0x0 0x100000>;
+ clock-frequency = <66666666>;
+ #interrupt-cells = <1>;
+ #size-cells = <2>;
+ #address-cells = <3>;
+ reg = <0xe0009000 0x1000>;
+ compatible = "fsl,mpc8540-pci";
+ device_type = "pci";
+ };
+};
diff --git a/arch/powerpc/boot/dts/tqm8540.dts b/arch/powerpc/boot/dts/tqm8540.dts
index 71347537b83..15ca731bc24 100644
--- a/arch/powerpc/boot/dts/tqm8540.dts
+++ b/arch/powerpc/boot/dts/tqm8540.dts
@@ -289,7 +289,14 @@
interrupt-map = <
/* IDSEL 28 */
0xe000 0 0 1 &mpic 2 1
- 0xe000 0 0 2 &mpic 3 1>;
+ 0xe000 0 0 2 &mpic 3 1
+ 0xe000 0 0 3 &mpic 6 1
+ 0xe000 0 0 4 &mpic 5 1
+
+ /* IDSEL 11 */
+ 0x5800 0 0 1 &mpic 6 1
+ 0x5800 0 0 2 &mpic 5 1
+ >;
interrupt-parent = <&mpic>;
interrupts = <24 2>;
diff --git a/arch/powerpc/boot/dts/tqm8541.dts b/arch/powerpc/boot/dts/tqm8541.dts
index b30f63753d4..f49d0918131 100644
--- a/arch/powerpc/boot/dts/tqm8541.dts
+++ b/arch/powerpc/boot/dts/tqm8541.dts
@@ -311,7 +311,14 @@
interrupt-map = <
/* IDSEL 28 */
0xe000 0 0 1 &mpic 2 1
- 0xe000 0 0 2 &mpic 3 1>;
+ 0xe000 0 0 2 &mpic 3 1
+ 0xe000 0 0 3 &mpic 6 1
+ 0xe000 0 0 4 &mpic 5 1
+
+ /* IDSEL 11 */
+ 0x5800 0 0 1 &mpic 6 1
+ 0x5800 0 0 2 &mpic 5 1
+ >;
interrupt-parent = <&mpic>;
interrupts = <24 2>;
diff --git a/arch/powerpc/boot/dts/tqm8548-bigflash.dts b/arch/powerpc/boot/dts/tqm8548-bigflash.dts
index 61f25e15fd6..5dbb36edb03 100644
--- a/arch/powerpc/boot/dts/tqm8548-bigflash.dts
+++ b/arch/powerpc/boot/dts/tqm8548-bigflash.dts
@@ -442,7 +442,14 @@
interrupt-map = <
/* IDSEL 28 */
0xe000 0 0 1 &mpic 2 1
- 0xe000 0 0 2 &mpic 3 1>;
+ 0xe000 0 0 2 &mpic 3 1
+ 0xe000 0 0 3 &mpic 6 1
+ 0xe000 0 0 4 &mpic 5 1
+
+ /* IDSEL 11 */
+ 0x5800 0 0 1 &mpic 6 1
+ 0x5800 0 0 2 &mpic 5 1
+ >;
interrupt-parent = <&mpic>;
interrupts = <24 2>;
diff --git a/arch/powerpc/boot/dts/tqm8548.dts b/arch/powerpc/boot/dts/tqm8548.dts
index 025759c7c95..a050ae42710 100644
--- a/arch/powerpc/boot/dts/tqm8548.dts
+++ b/arch/powerpc/boot/dts/tqm8548.dts
@@ -442,7 +442,14 @@
interrupt-map = <
/* IDSEL 28 */
0xe000 0 0 1 &mpic 2 1
- 0xe000 0 0 2 &mpic 3 1>;
+ 0xe000 0 0 2 &mpic 3 1
+ 0xe000 0 0 3 &mpic 6 1
+ 0xe000 0 0 4 &mpic 5 1
+
+ /* IDSEL 11 */
+ 0x5800 0 0 1 &mpic 6 1
+ 0x5800 0 0 2 &mpic 5 1
+ >;
interrupt-parent = <&mpic>;
interrupts = <24 2>;
diff --git a/arch/powerpc/boot/dts/tqm8555.dts b/arch/powerpc/boot/dts/tqm8555.dts
index 95e28738183..81bad8cd375 100644
--- a/arch/powerpc/boot/dts/tqm8555.dts
+++ b/arch/powerpc/boot/dts/tqm8555.dts
@@ -311,7 +311,14 @@
interrupt-map = <
/* IDSEL 28 */
0xe000 0 0 1 &mpic 2 1
- 0xe000 0 0 2 &mpic 3 1>;
+ 0xe000 0 0 2 &mpic 3 1
+ 0xe000 0 0 3 &mpic 6 1
+ 0xe000 0 0 4 &mpic 5 1
+
+ /* IDSEL 11 */
+ 0x5800 0 0 1 &mpic 6 1
+ 0x5800 0 0 2 &mpic 5 1
+ >;
interrupt-parent = <&mpic>;
interrupts = <24 2>;
diff --git a/arch/powerpc/boot/dts/tqm8560.dts b/arch/powerpc/boot/dts/tqm8560.dts
index ff70580a8f4..22ec39b5bee 100644
--- a/arch/powerpc/boot/dts/tqm8560.dts
+++ b/arch/powerpc/boot/dts/tqm8560.dts
@@ -382,7 +382,14 @@
interrupt-map = <
/* IDSEL 28 */
0xe000 0 0 1 &mpic 2 1
- 0xe000 0 0 2 &mpic 3 1>;
+ 0xe000 0 0 2 &mpic 3 1
+ 0xe000 0 0 3 &mpic 6 1
+ 0xe000 0 0 4 &mpic 5 1
+
+ /* IDSEL 11 */
+ 0x5800 0 0 1 &mpic 6 1
+ 0x5800 0 0 2 &mpic 5 1
+ >;
interrupt-parent = <&mpic>;
interrupts = <24 2>;
diff --git a/arch/powerpc/boot/dts/tqm8xx.dts b/arch/powerpc/boot/dts/tqm8xx.dts
new file mode 100644
index 00000000000..f6da7ec49a8
--- /dev/null
+++ b/arch/powerpc/boot/dts/tqm8xx.dts
@@ -0,0 +1,172 @@
+/*
+ * TQM8XX Device Tree Source
+ *
+ * Heiko Schocher <hs@denx.de>
+ * 2010 DENX Software Engineering 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.
+ */
+
+/dts-v1/;
+
+/ {
+ model = "TQM8xx";
+ compatible = "tqc,tqm8xx";
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ aliases {
+ ethernet0 = &eth0;
+ ethernet1 = &eth1;
+ mdio1 = &phy1;
+ serial0 = &smc1;
+ };
+
+ cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ PowerPC,860@0 {
+ device_type = "cpu";
+ reg = <0x0>;
+ d-cache-line-size = <16>; // 16 bytes
+ i-cache-line-size = <16>; // 16 bytes
+ d-cache-size = <0x1000>; // L1, 4K
+ i-cache-size = <0x1000>; // L1, 4K
+ timebase-frequency = <0>;
+ bus-frequency = <0>;
+ clock-frequency = <0>;
+ interrupts = <15 2>; // decrementer interrupt
+ interrupt-parent = <&PIC>;
+ };
+ };
+
+ memory {
+ device_type = "memory";
+ reg = <0x0 0x2000000>;
+ };
+
+ localbus@fff00100 {
+ compatible = "fsl,mpc860-localbus", "fsl,pq1-localbus";
+ #address-cells = <2>;
+ #size-cells = <1>;
+ reg = <0xfff00100 0x40>;
+
+ ranges = <
+ 0x0 0x0 0x40000000 0x800000
+ >;
+
+ flash@0,0 {
+ compatible = "cfi-flash";
+ reg = <0 0 0x800000>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ bank-width = <4>;
+ device-width = <2>;
+ };
+ };
+
+ soc@fff00000 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ device_type = "soc";
+ ranges = <0x0 0xfff00000 0x00004000>;
+
+ phy1: mdio@e00 {
+ compatible = "fsl,mpc866-fec-mdio", "fsl,pq1-fec-mdio";
+ reg = <0xe00 0x188>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ PHY: ethernet-phy@f {
+ reg = <0xf>;
+ device_type = "ethernet-phy";
+ };
+ };
+
+ eth1: ethernet@e00 {
+ device_type = "network";
+ compatible = "fsl,mpc866-fec-enet",
+ "fsl,pq1-fec-enet";
+ reg = <0xe00 0x188>;
+ interrupts = <3 1>;
+ interrupt-parent = <&PIC>;
+ phy-handle = <&PHY>;
+ linux,network-index = <1>;
+ };
+
+ PIC: pic@0 {
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ reg = <0x0 0x24>;
+ compatible = "fsl,mpc860-pic", "fsl,pq1-pic";
+ };
+
+ cpm@9c0 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "fsl,mpc860-cpm", "fsl,cpm1";
+ ranges;
+ reg = <0x9c0 0x40>;
+ brg-frequency = <0>;
+ interrupts = <0 2>; // cpm error interrupt
+ interrupt-parent = <&CPM_PIC>;
+
+ muram@2000 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges = <0x0 0x2000 0x2000>;
+
+ data@0 {
+ compatible = "fsl,cpm-muram-data";
+ reg = <0x0 0x2000>;
+ };
+ };
+
+ brg@9f0 {
+ compatible = "fsl,mpc860-brg",
+ "fsl,cpm1-brg",
+ "fsl,cpm-brg";
+ reg = <0x9f0 0x10>;
+ clock-frequency = <0>;
+ };
+
+ CPM_PIC: pic@930 {
+ interrupt-controller;
+ #address-cells = <0>;
+ #interrupt-cells = <1>;
+ interrupts = <5 2 0 2>;
+ interrupt-parent = <&PIC>;
+ reg = <0x930 0x20>;
+ compatible = "fsl,mpc860-cpm-pic",
+ "fsl,cpm1-pic";
+ };
+
+
+ smc1: serial@a80 {
+ device_type = "serial";
+ compatible = "fsl,mpc860-smc-uart",
+ "fsl,cpm1-smc-uart";
+ reg = <0xa80 0x10 0x3e80 0x40>;
+ interrupts = <4>;
+ interrupt-parent = <&CPM_PIC>;
+ fsl,cpm-brg = <1>;
+ fsl,cpm-command = <0x90>;
+ };
+
+ eth0: ethernet@a00 {
+ device_type = "network";
+ compatible = "fsl,mpc860-scc-enet",
+ "fsl,cpm1-scc-enet";
+ reg = <0xa00 0x18 0x3c00 0x100>;
+ interrupts = <30>;
+ interrupt-parent = <&CPM_PIC>;
+ fsl,cpm-command = <0000>;
+ linux,network-index = <0>;
+ fixed-link = <0 0 10 0 0>;
+ };
+ };
+ };
+};
diff --git a/arch/powerpc/configs/mpc85xx_defconfig b/arch/powerpc/configs/mpc85xx_defconfig
index cfebef9f912..d32f31a03f5 100644
--- a/arch/powerpc/configs/mpc85xx_defconfig
+++ b/arch/powerpc/configs/mpc85xx_defconfig
@@ -19,7 +19,8 @@ CONFIG_E500=y
CONFIG_FSL_EMB_PERFMON=y
CONFIG_BOOKE=y
CONFIG_FSL_BOOKE=y
-# CONFIG_PHYS_64BIT is not set
+CONFIG_PTE_64BIT=y
+CONFIG_PHYS_64BIT=y
CONFIG_SPE=y
CONFIG_PPC_MMU_NOHASH=y
CONFIG_PPC_MMU_NOHASH_32=y
@@ -28,7 +29,7 @@ CONFIG_PPC_BOOK3E_MMU=y
# CONFIG_SMP is not set
CONFIG_PPC32=y
CONFIG_WORD_SIZE=32
-# CONFIG_ARCH_PHYS_ADDR_T_64BIT is not set
+CONFIG_ARCH_PHYS_ADDR_T_64BIT=y
CONFIG_MMU=y
CONFIG_GENERIC_CMOS_UPDATE=y
CONFIG_GENERIC_TIME=y
@@ -239,6 +240,7 @@ CONFIG_MPC85xx_MDS=y
CONFIG_MPC8536_DS=y
CONFIG_MPC85xx_DS=y
CONFIG_MPC85xx_RDB=y
+CONFIG_P1022_DS=y
CONFIG_SOCRATES=y
CONFIG_KSI8560=y
CONFIG_XES_MPC85xx=y
@@ -311,7 +313,7 @@ CONFIG_FLAT_NODE_MEM_MAP=y
CONFIG_PAGEFLAGS_EXTENDED=y
CONFIG_SPLIT_PTLOCK_CPUS=4
CONFIG_MIGRATION=y
-# CONFIG_PHYS_ADDR_T_64BIT is not set
+CONFIG_PHYS_ADDR_T_64BIT=y
CONFIG_ZONE_DMA_FLAG=1
CONFIG_BOUNCE=y
CONFIG_VIRT_TO_BUS=y
@@ -321,7 +323,7 @@ CONFIG_PPC_4K_PAGES=y
# CONFIG_PPC_16K_PAGES is not set
# CONFIG_PPC_64K_PAGES is not set
# CONFIG_PPC_256K_PAGES is not set
-CONFIG_FORCE_MAX_ZONEORDER=11
+CONFIG_FORCE_MAX_ZONEORDER=12
CONFIG_PROC_DEVICETREE=y
# CONFIG_CMDLINE_BOOL is not set
CONFIG_EXTRA_TARGETS=""
@@ -1122,16 +1124,13 @@ CONFIG_VGA_CONSOLE=y
# CONFIG_VGACON_SOFT_SCROLLBACK is not set
CONFIG_DUMMY_CONSOLE=y
CONFIG_SOUND=y
-CONFIG_SOUND_OSS_CORE=y
-CONFIG_SOUND_OSS_CORE_PRECLAIM=y
+# CONFIG_SOUND_OSS_CORE is not set
CONFIG_SND=y
CONFIG_SND_TIMER=y
CONFIG_SND_PCM=y
# CONFIG_SND_SEQUENCER is not set
-CONFIG_SND_OSSEMUL=y
-CONFIG_SND_MIXER_OSS=y
-CONFIG_SND_PCM_OSS=y
-CONFIG_SND_PCM_OSS_PLUGINS=y
+# CONFIG_SND_MIXER_OSS is not set
+# CONFIG_SND_PCM_OSS is not set
# CONFIG_SND_HRTIMER is not set
# CONFIG_SND_DYNAMIC_MINORS is not set
# CONFIG_SND_SUPPORT_OLD_API is not set
@@ -1145,12 +1144,7 @@ CONFIG_SND_VMASTER=y
# CONFIG_SND_SBAWE_SEQ is not set
# CONFIG_SND_EMU10K1_SEQ is not set
CONFIG_SND_AC97_CODEC=y
-CONFIG_SND_DRIVERS=y
-# 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
-# CONFIG_SND_AC97_POWER_SAVE is not set
+# CONFIG_SND_DRIVERS is not set
CONFIG_SND_PCI=y
# CONFIG_SND_AD1889 is not set
# CONFIG_SND_ALS300 is not set
@@ -1218,12 +1212,8 @@ CONFIG_SND_INTEL8X0=y
# CONFIG_SND_VIRTUOSO is not set
# CONFIG_SND_VX222 is not set
# CONFIG_SND_YMFPCI is not set
-CONFIG_SND_PPC=y
-CONFIG_SND_USB=y
-# CONFIG_SND_USB_AUDIO is not set
-# CONFIG_SND_USB_UA101 is not set
-# CONFIG_SND_USB_USX2Y is not set
-# CONFIG_SND_USB_CAIAQ is not set
+# CONFIG_SND_PPC is not set
+# CONFIG_SND_USB is not set
# CONFIG_SND_SOC is not set
# CONFIG_SOUND_PRIME is not set
CONFIG_AC97_BUS=y
diff --git a/arch/powerpc/configs/mpc85xx_smp_defconfig b/arch/powerpc/configs/mpc85xx_smp_defconfig
index f5451d80f19..f93de10adcd 100644
--- a/arch/powerpc/configs/mpc85xx_smp_defconfig
+++ b/arch/powerpc/configs/mpc85xx_smp_defconfig
@@ -19,7 +19,8 @@ CONFIG_E500=y
CONFIG_FSL_EMB_PERFMON=y
CONFIG_BOOKE=y
CONFIG_FSL_BOOKE=y
-# CONFIG_PHYS_64BIT is not set
+CONFIG_PTE_64BIT=y
+CONFIG_PHYS_64BIT=y
CONFIG_SPE=y
CONFIG_PPC_MMU_NOHASH=y
CONFIG_PPC_MMU_NOHASH_32=y
@@ -29,7 +30,7 @@ CONFIG_SMP=y
CONFIG_NR_CPUS=8
CONFIG_PPC32=y
CONFIG_WORD_SIZE=32
-# CONFIG_ARCH_PHYS_ADDR_T_64BIT is not set
+CONFIG_ARCH_PHYS_ADDR_T_64BIT=y
CONFIG_MMU=y
CONFIG_GENERIC_CMOS_UPDATE=y
CONFIG_GENERIC_TIME=y
@@ -243,6 +244,7 @@ CONFIG_MPC85xx_MDS=y
CONFIG_MPC8536_DS=y
CONFIG_MPC85xx_DS=y
CONFIG_MPC85xx_RDB=y
+CONFIG_P1022_DS=y
CONFIG_SOCRATES=y
CONFIG_KSI8560=y
CONFIG_XES_MPC85xx=y
@@ -316,7 +318,7 @@ CONFIG_FLAT_NODE_MEM_MAP=y
CONFIG_PAGEFLAGS_EXTENDED=y
CONFIG_SPLIT_PTLOCK_CPUS=4
CONFIG_MIGRATION=y
-# CONFIG_PHYS_ADDR_T_64BIT is not set
+CONFIG_PHYS_ADDR_T_64BIT=y
CONFIG_ZONE_DMA_FLAG=1
CONFIG_BOUNCE=y
CONFIG_VIRT_TO_BUS=y
@@ -326,7 +328,7 @@ CONFIG_PPC_4K_PAGES=y
# CONFIG_PPC_16K_PAGES is not set
# CONFIG_PPC_64K_PAGES is not set
# CONFIG_PPC_256K_PAGES is not set
-CONFIG_FORCE_MAX_ZONEORDER=11
+CONFIG_FORCE_MAX_ZONEORDER=12
CONFIG_PROC_DEVICETREE=y
# CONFIG_CMDLINE_BOOL is not set
CONFIG_EXTRA_TARGETS=""
@@ -1127,16 +1129,13 @@ CONFIG_VGA_CONSOLE=y
# CONFIG_VGACON_SOFT_SCROLLBACK is not set
CONFIG_DUMMY_CONSOLE=y
CONFIG_SOUND=y
-CONFIG_SOUND_OSS_CORE=y
-CONFIG_SOUND_OSS_CORE_PRECLAIM=y
+# CONFIG_SOUND_OSS_CORE is not set
CONFIG_SND=y
CONFIG_SND_TIMER=y
CONFIG_SND_PCM=y
# CONFIG_SND_SEQUENCER is not set
-CONFIG_SND_OSSEMUL=y
-CONFIG_SND_MIXER_OSS=y
-CONFIG_SND_PCM_OSS=y
-CONFIG_SND_PCM_OSS_PLUGINS=y
+# CONFIG_SND_MIXER_OSS is not set
+# CONFIG_SND_PCM_OSS is not set
# CONFIG_SND_HRTIMER is not set
# CONFIG_SND_DYNAMIC_MINORS is not set
# CONFIG_SND_SUPPORT_OLD_API is not set
@@ -1150,12 +1149,7 @@ CONFIG_SND_VMASTER=y
# CONFIG_SND_SBAWE_SEQ is not set
# CONFIG_SND_EMU10K1_SEQ is not set
CONFIG_SND_AC97_CODEC=y
-CONFIG_SND_DRIVERS=y
-# 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
-# CONFIG_SND_AC97_POWER_SAVE is not set
+# CONFIG_SND_DRIVERS is not set
CONFIG_SND_PCI=y
# CONFIG_SND_AD1889 is not set
# CONFIG_SND_ALS300 is not set
@@ -1223,12 +1217,8 @@ CONFIG_SND_INTEL8X0=y
# CONFIG_SND_VIRTUOSO is not set
# CONFIG_SND_VX222 is not set
# CONFIG_SND_YMFPCI is not set
-CONFIG_SND_PPC=y
-CONFIG_SND_USB=y
-# CONFIG_SND_USB_AUDIO is not set
-# CONFIG_SND_USB_UA101 is not set
-# CONFIG_SND_USB_USX2Y is not set
-# CONFIG_SND_USB_CAIAQ is not set
+# CONFIG_SND_PPC is not set
+# CONFIG_SND_USB is not set
# CONFIG_SND_SOC is not set
# CONFIG_SOUND_PRIME is not set
CONFIG_AC97_BUS=y
diff --git a/arch/powerpc/configs/tqm8xx_defconfig b/arch/powerpc/configs/tqm8xx_defconfig
new file mode 100644
index 00000000000..85e654b6487
--- /dev/null
+++ b/arch/powerpc/configs/tqm8xx_defconfig
@@ -0,0 +1,934 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.34-rc1
+# Tue Mar 23 08:22:15 2010
+#
+# CONFIG_PPC64 is not set
+
+#
+# Processor support
+#
+# CONFIG_PPC_BOOK3S_32 is not set
+# CONFIG_PPC_85xx is not set
+CONFIG_PPC_8xx=y
+# CONFIG_40x is not set
+# CONFIG_44x is not set
+# CONFIG_E200 is not set
+CONFIG_8xx=y
+CONFIG_PPC_MMU_NOHASH=y
+CONFIG_PPC_MMU_NOHASH_32=y
+# CONFIG_PPC_MM_SLICES is not set
+CONFIG_NOT_COHERENT_CACHE=y
+CONFIG_PPC32=y
+CONFIG_WORD_SIZE=32
+# CONFIG_ARCH_PHYS_ADDR_T_64BIT is not set
+CONFIG_MMU=y
+CONFIG_GENERIC_CMOS_UPDATE=y
+CONFIG_GENERIC_TIME=y
+CONFIG_GENERIC_TIME_VSYSCALL=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
+# CONFIG_HAVE_SETUP_PER_CPU_AREA is not set
+# CONFIG_NEED_PER_CPU_EMBED_FIRST_CHUNK is not set
+CONFIG_IRQ_PER_CPU=y
+CONFIG_NR_IRQS=512
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_HAVE_LATENCYTOP_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_ARCH_HAS_ILOG2_U32=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_FIND_NEXT_BIT=y
+# CONFIG_ARCH_NO_VIRT_TO_BUS is not set
+CONFIG_PPC=y
+CONFIG_EARLY_PRINTK=y
+CONFIG_GENERIC_NVRAM=y
+CONFIG_SCHED_OMIT_FRAME_POINTER=y
+CONFIG_ARCH_MAY_HAVE_PC_FDC=y
+CONFIG_PPC_OF=y
+CONFIG_OF=y
+# CONFIG_PPC_UDBG_16550 is not set
+# CONFIG_GENERIC_TBSYNC is not set
+CONFIG_AUDIT_ARCH=y
+CONFIG_GENERIC_BUG=y
+CONFIG_DTC=y
+# CONFIG_DEFAULT_UIMAGE is not set
+CONFIG_ARCH_HIBERNATION_POSSIBLE=y
+# CONFIG_PPC_DCR_NATIVE is not set
+# CONFIG_PPC_DCR_MMIO is not set
+CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC=y
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+CONFIG_CONSTRUCTORS=y
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+# CONFIG_SWAP is not set
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+# CONFIG_POSIX_MQUEUE is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_AUDIT is not set
+
+#
+# RCU Subsystem
+#
+CONFIG_TREE_RCU=y
+# CONFIG_TREE_PREEMPT_RCU is not set
+# CONFIG_TINY_RCU is not set
+# CONFIG_RCU_TRACE is not set
+CONFIG_RCU_FANOUT=32
+# CONFIG_RCU_FANOUT_EXACT is not set
+# CONFIG_TREE_RCU_TRACE is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_CGROUPS is not set
+CONFIG_SYSFS_DEPRECATED=y
+CONFIG_SYSFS_DEPRECATED_V2=y
+# CONFIG_RELAY is not set
+# CONFIG_NAMESPACES is not set
+# CONFIG_BLK_DEV_INITRD is not set
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SYSCTL=y
+CONFIG_ANON_INODES=y
+CONFIG_EMBEDDED=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 is not set
+# CONFIG_BASE_FULL is not set
+# CONFIG_FUTEX is not set
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
+CONFIG_SHMEM=y
+CONFIG_AIO=y
+CONFIG_HAVE_PERF_EVENTS=y
+
+#
+# Kernel Performance Events And Counters
+#
+# CONFIG_PERF_EVENTS is not set
+# CONFIG_PERF_COUNTERS is not set
+# CONFIG_VM_EVENT_COUNTERS is not set
+CONFIG_SLUB_DEBUG=y
+CONFIG_COMPAT_BRK=y
+# CONFIG_SLAB is not set
+CONFIG_SLUB=y
+# CONFIG_SLOB is not set
+# CONFIG_PROFILING is not set
+CONFIG_HAVE_OPROFILE=y
+# CONFIG_KPROBES is not set
+CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS=y
+CONFIG_HAVE_IOREMAP_PROT=y
+CONFIG_HAVE_KPROBES=y
+CONFIG_HAVE_KRETPROBES=y
+CONFIG_HAVE_ARCH_TRACEHOOK=y
+CONFIG_HAVE_DMA_ATTRS=y
+CONFIG_HAVE_CLK=y
+CONFIG_HAVE_DMA_API_DEBUG=y
+
+#
+# GCOV-based kernel profiling
+#
+# CONFIG_SLOW_WORK is not set
+# CONFIG_HAVE_GENERIC_DMA_COHERENT is not set
+CONFIG_SLABINFO=y
+CONFIG_BASE_SMALL=1
+CONFIG_MODULES=y
+# CONFIG_MODULE_FORCE_LOAD is not set
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+# CONFIG_MODVERSIONS is not set
+CONFIG_MODULE_SRCVERSION_ALL=y
+CONFIG_BLOCK=y
+CONFIG_LBDAF=y
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_BLK_DEV_INTEGRITY is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_DEADLINE=y
+# CONFIG_IOSCHED_CFQ is not set
+CONFIG_DEFAULT_DEADLINE=y
+# CONFIG_DEFAULT_CFQ is not set
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="deadline"
+# CONFIG_INLINE_SPIN_TRYLOCK is not set
+# CONFIG_INLINE_SPIN_TRYLOCK_BH is not set
+# CONFIG_INLINE_SPIN_LOCK is not set
+# CONFIG_INLINE_SPIN_LOCK_BH is not set
+# CONFIG_INLINE_SPIN_LOCK_IRQ is not set
+# CONFIG_INLINE_SPIN_LOCK_IRQSAVE is not set
+CONFIG_INLINE_SPIN_UNLOCK=y
+# CONFIG_INLINE_SPIN_UNLOCK_BH is not set
+CONFIG_INLINE_SPIN_UNLOCK_IRQ=y
+# CONFIG_INLINE_SPIN_UNLOCK_IRQRESTORE is not set
+# CONFIG_INLINE_READ_TRYLOCK is not set
+# CONFIG_INLINE_READ_LOCK is not set
+# CONFIG_INLINE_READ_LOCK_BH is not set
+# CONFIG_INLINE_READ_LOCK_IRQ is not set
+# CONFIG_INLINE_READ_LOCK_IRQSAVE is not set
+CONFIG_INLINE_READ_UNLOCK=y
+# CONFIG_INLINE_READ_UNLOCK_BH is not set
+CONFIG_INLINE_READ_UNLOCK_IRQ=y
+# CONFIG_INLINE_READ_UNLOCK_IRQRESTORE is not set
+# CONFIG_INLINE_WRITE_TRYLOCK is not set
+# CONFIG_INLINE_WRITE_LOCK is not set
+# CONFIG_INLINE_WRITE_LOCK_BH is not set
+# CONFIG_INLINE_WRITE_LOCK_IRQ is not set
+# CONFIG_INLINE_WRITE_LOCK_IRQSAVE is not set
+CONFIG_INLINE_WRITE_UNLOCK=y
+# CONFIG_INLINE_WRITE_UNLOCK_BH is not set
+CONFIG_INLINE_WRITE_UNLOCK_IRQ=y
+# CONFIG_INLINE_WRITE_UNLOCK_IRQRESTORE is not set
+# CONFIG_MUTEX_SPIN_ON_OWNER is not set
+# CONFIG_FREEZER is not set
+
+#
+# Platform support
+#
+# CONFIG_PPC_CELL is not set
+# CONFIG_PPC_CELL_NATIVE is not set
+CONFIG_CPM1=y
+# CONFIG_MPC8XXFADS is not set
+# CONFIG_MPC86XADS is not set
+# CONFIG_MPC885ADS is not set
+# CONFIG_PPC_EP88XC is not set
+# CONFIG_PPC_ADDER875 is not set
+# CONFIG_PPC_MGSUVD is not set
+CONFIG_TQM8XX=y
+
+#
+# MPC8xx CPM Options
+#
+
+#
+# Generic MPC8xx Options
+#
+CONFIG_8xx_COPYBACK=y
+# CONFIG_8xx_GPIO is not set
+# CONFIG_8xx_CPU6 is not set
+# CONFIG_8xx_CPU15 is not set
+CONFIG_NO_UCODE_PATCH=y
+# CONFIG_USB_SOF_UCODE_PATCH is not set
+# CONFIG_I2C_SPI_UCODE_PATCH is not set
+# CONFIG_I2C_SPI_SMC1_UCODE_PATCH is not set
+# CONFIG_PQ2ADS is not set
+# CONFIG_IPIC is not set
+# CONFIG_MPIC is not set
+# CONFIG_MPIC_WEIRD is not set
+# CONFIG_PPC_I8259 is not set
+# CONFIG_PPC_RTAS is not set
+# CONFIG_MMIO_NVRAM is not set
+# CONFIG_PPC_MPC106 is not set
+# CONFIG_PPC_970_NAP is not set
+# CONFIG_PPC_INDIRECT_IO is not set
+# CONFIG_GENERIC_IOMAP is not set
+# CONFIG_CPU_FREQ is not set
+# CONFIG_QUICC_ENGINE is not set
+# CONFIG_FSL_ULI1575 is not set
+CONFIG_CPM=y
+# CONFIG_SIMPLE_GPIO is not set
+
+#
+# Kernel options
+#
+# CONFIG_HIGHMEM is not set
+CONFIG_TICK_ONESHOT=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
+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_SCHED_HRTICK=y
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
+# CONFIG_PREEMPT is not set
+CONFIG_BINFMT_ELF=y
+# CONFIG_HAVE_AOUT is not set
+# CONFIG_BINFMT_MISC is not set
+# CONFIG_MATH_EMULATION is not set
+CONFIG_8XX_MINIMAL_FPEMU=y
+# CONFIG_IOMMU_HELPER is not set
+# CONFIG_SWIOTLB is not set
+CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
+CONFIG_ARCH_HAS_WALK_MEMORY=y
+CONFIG_ARCH_ENABLE_MEMORY_HOTREMOVE=y
+CONFIG_SPARSE_IRQ=y
+CONFIG_MAX_ACTIVE_REGIONS=32
+CONFIG_ARCH_FLATMEM_ENABLE=y
+CONFIG_ARCH_POPULATES_NODE_MAP=y
+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_PAGEFLAGS_EXTENDED=y
+CONFIG_SPLIT_PTLOCK_CPUS=4
+CONFIG_MIGRATION=y
+# CONFIG_PHYS_ADDR_T_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=1
+CONFIG_BOUNCE=y
+CONFIG_VIRT_TO_BUS=y
+# CONFIG_KSM is not set
+CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
+CONFIG_PPC_4K_PAGES=y
+# CONFIG_PPC_16K_PAGES is not set
+# CONFIG_PPC_64K_PAGES is not set
+# CONFIG_PPC_256K_PAGES is not set
+CONFIG_FORCE_MAX_ZONEORDER=11
+CONFIG_PROC_DEVICETREE=y
+# CONFIG_CMDLINE_BOOL is not set
+CONFIG_EXTRA_TARGETS=""
+# CONFIG_PM is not set
+# CONFIG_SECCOMP is not set
+CONFIG_ISA_DMA_API=y
+
+#
+# Bus options
+#
+CONFIG_ZONE_DMA=y
+CONFIG_NEED_DMA_MAP_STATE=y
+CONFIG_FSL_SOC=y
+# CONFIG_PCI is not set
+# CONFIG_PCI_DOMAINS is not set
+# CONFIG_PCI_SYSCALL is not set
+# CONFIG_PCI_QSPAN is not set
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+# CONFIG_PCCARD is not set
+# CONFIG_HAS_RAPIDIO is not set
+
+#
+# Advanced setup
+#
+# CONFIG_ADVANCED_OPTIONS is not set
+
+#
+# Default settings for advanced configuration options are used
+#
+CONFIG_LOWMEM_SIZE=0x30000000
+CONFIG_PAGE_OFFSET=0xc0000000
+CONFIG_KERNEL_START=0xc0000000
+CONFIG_PHYSICAL_START=0x00000000
+CONFIG_TASK_SIZE=0x80000000
+CONFIG_CONSISTENT_SIZE=0x00200000
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_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 is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_LRO is not set
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+# CONFIG_IPV6 is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_IP_DCCP is not set
+# CONFIG_IP_SCTP is not set
+# CONFIG_RDS is not set
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_NET_DSA is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_PHONET is not set
+# CONFIG_IEEE802154 is not set
+# CONFIG_NET_SCHED is not set
+# CONFIG_DCB is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_CAN is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_AF_RXRPC is not set
+# CONFIG_WIRELESS is not set
+# CONFIG_WIMAX is not set
+# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+# CONFIG_DEVTMPFS is not set
+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
+# CONFIG_CONNECTOR is not set
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+# CONFIG_MTD_TESTS is not set
+CONFIG_MTD_CONCAT=y
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_REDBOOT_PARTS is not set
+CONFIG_MTD_CMDLINE_PARTS=y
+CONFIG_MTD_OF_PARTS=y
+# CONFIG_MTD_AR7_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
+# CONFIG_MTD_OOPS is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=y
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_GEN_PROBE=y
+# CONFIG_MTD_CFI_ADV_OPTIONS is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+CONFIG_MTD_CFI_INTELEXT=y
+CONFIG_MTD_CFI_AMDSTD=y
+# CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_CFI_UTIL=y
+# 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_PHYSMAP is not set
+CONFIG_MTD_PHYSMAP_OF=y
+# CONFIG_MTD_CFI_FLAGADM 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 is not set
+# CONFIG_MTD_ONENAND is not set
+
+#
+# LPDDR flash memory drivers
+#
+# CONFIG_MTD_LPDDR is not set
+
+#
+# UBI - Unsorted block images
+#
+# CONFIG_MTD_UBI is not set
+CONFIG_OF_FLATTREE=y
+CONFIG_OF_DYNAMIC=y
+CONFIG_OF_DEVICE=y
+CONFIG_OF_MDIO=y
+# CONFIG_PARPORT is not set
+# CONFIG_BLK_DEV is not set
+# CONFIG_MISC_DEVICES is not set
+CONFIG_HAVE_IDE=y
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+# CONFIG_SCSI is not set
+# CONFIG_SCSI_DMA is not set
+# CONFIG_SCSI_NETLINK is not set
+# CONFIG_ATA is not set
+# CONFIG_MD is not set
+# CONFIG_MACINTOSH_DRIVERS is not set
+CONFIG_NETDEVICES=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_VETH is not set
+CONFIG_PHYLIB=y
+
+#
+# MII PHY device drivers
+#
+# CONFIG_MARVELL_PHY is not set
+CONFIG_DAVICOM_PHY=y
+# CONFIG_QSEMI_PHY is not set
+# CONFIG_LXT_PHY is not set
+# CONFIG_CICADA_PHY is not set
+# CONFIG_VITESSE_PHY is not set
+# CONFIG_SMSC_PHY is not set
+# CONFIG_BROADCOM_PHY is not set
+# CONFIG_ICPLUS_PHY is not set
+# CONFIG_REALTEK_PHY is not set
+# CONFIG_NATIONAL_PHY is not set
+# CONFIG_STE10XP is not set
+# CONFIG_LSI_ET1011C_PHY is not set
+CONFIG_FIXED_PHY=y
+# CONFIG_MDIO_BITBANG is not set
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+# CONFIG_ETHOC is not set
+# CONFIG_DNET is not set
+# CONFIG_IBM_NEW_EMAC_ZMII is not set
+# CONFIG_IBM_NEW_EMAC_RGMII is not set
+# CONFIG_IBM_NEW_EMAC_TAH is not set
+# CONFIG_IBM_NEW_EMAC_EMAC4 is not set
+# CONFIG_IBM_NEW_EMAC_NO_FLOW_CTRL is not set
+# CONFIG_IBM_NEW_EMAC_MAL_CLR_ICINTSTAT is not set
+# CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set
+# CONFIG_B44 is not set
+# CONFIG_KS8842 is not set
+# CONFIG_KS8851_MLL is not set
+# CONFIG_XILINX_EMACLITE is not set
+CONFIG_FS_ENET=y
+CONFIG_FS_ENET_HAS_SCC=y
+CONFIG_FS_ENET_HAS_FEC=y
+CONFIG_FS_ENET_MDIO_FEC=y
+# CONFIG_NETDEV_1000 is not set
+# CONFIG_NETDEV_10000 is not set
+# CONFIG_WLAN is not set
+
+#
+# Enable WiMAX (Networking options) to see the WiMAX drivers
+#
+# CONFIG_WAN is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_ISDN is not set
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+# CONFIG_INPUT is not set
+
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+# CONFIG_VT is not set
+CONFIG_DEVKMEM=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_8250 is not set
+
+#
+# Non-8250 serial port support
+#
+# CONFIG_SERIAL_UARTLITE is not set
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_SERIAL_CPM=y
+CONFIG_SERIAL_CPM_CONSOLE=y
+# CONFIG_SERIAL_TIMBERDALE is not set
+# CONFIG_SERIAL_GRLIB_GAISLER_APBUART is not set
+CONFIG_UNIX98_PTYS=y
+# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_HVC_UDBG is not set
+# CONFIG_IPMI_HANDLER is not set
+CONFIG_HW_RANDOM=y
+# CONFIG_HW_RANDOM_TIMERIOMEM is not set
+# CONFIG_NVRAM is not set
+CONFIG_GEN_RTC=y
+# CONFIG_GEN_RTC_X is not set
+# CONFIG_R3964 is not set
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_TCG_TPM is not set
+# CONFIG_I2C is not set
+# CONFIG_SPI is not set
+
+#
+# PPS support
+#
+# CONFIG_PPS is not set
+CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
+# CONFIG_GPIOLIB is not set
+# CONFIG_W1 is not set
+# CONFIG_POWER_SUPPLY is not set
+# CONFIG_HWMON is not set
+# CONFIG_THERMAL is not set
+# CONFIG_WATCHDOG is not set
+CONFIG_SSB_POSSIBLE=y
+
+#
+# Sonics Silicon Backplane
+#
+# CONFIG_SSB is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_CORE is not set
+# CONFIG_MFD_SM501 is not set
+# CONFIG_HTC_PASIC3 is not set
+# CONFIG_MFD_TMIO is not set
+# CONFIG_REGULATOR is not set
+# CONFIG_MEDIA_SUPPORT is not set
+
+#
+# Graphics support
+#
+# CONFIG_VGASTATE is not set
+# CONFIG_VIDEO_OUTPUT_CONTROL is not set
+# CONFIG_FB is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+# CONFIG_SOUND is not set
+# CONFIG_USB_SUPPORT is not set
+# CONFIG_MMC is not set
+# CONFIG_MEMSTICK is not set
+# CONFIG_NEW_LEDS is not set
+# CONFIG_ACCESSIBILITY is not set
+# CONFIG_EDAC is not set
+# CONFIG_RTC_CLASS is not set
+# CONFIG_DMADEVICES is not set
+# CONFIG_AUXDISPLAY is not set
+# CONFIG_UIO is not set
+
+#
+# TI VLYNQ
+#
+# CONFIG_STAGING is not set
+
+#
+# File systems
+#
+# CONFIG_EXT2_FS is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_EXT4_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_BTRFS_FS is not set
+# CONFIG_NILFS2_FS is not set
+CONFIG_FILE_LOCKING=y
+CONFIG_FSNOTIFY=y
+# CONFIG_DNOTIFY is not set
+# CONFIG_INOTIFY is not set
+CONFIG_INOTIFY_USER=y
+# CONFIG_QUOTA is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+
+#
+# Caches
+#
+# CONFIG_FSCACHE is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+# CONFIG_MSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+# CONFIG_PROC_KCORE is not set
+CONFIG_PROC_SYSCTL=y
+CONFIG_PROC_PAGE_MONITOR=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
+# CONFIG_HUGETLB_PAGE is not set
+# CONFIG_CONFIGFS_FS is not set
+CONFIG_MISC_FILESYSTEMS=y
+# 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 is not set
+# CONFIG_LOGFS is not set
+CONFIG_CRAMFS=y
+# CONFIG_SQUASHFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_OMFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+CONFIG_NETWORK_FILESYSTEMS=y
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
+# CONFIG_NFS_V4 is not set
+CONFIG_ROOT_NFS=y
+# CONFIG_NFSD is not set
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_LDM_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_KARMA_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
+# CONFIG_SYSV68_PARTITION is not set
+# CONFIG_NLS is not set
+# CONFIG_DLM is not set
+# CONFIG_BINARY_PRINTF is not set
+
+#
+# Library routines
+#
+CONFIG_GENERIC_FIND_LAST_BIT=y
+# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC16 is not set
+# CONFIG_CRC_T10DIF is not set
+# CONFIG_CRC_ITU_T is not set
+# CONFIG_CRC32 is not set
+# CONFIG_CRC7 is not set
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
+CONFIG_HAVE_LMB=y
+CONFIG_NLATTR=y
+CONFIG_GENERIC_ATOMIC64=y
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_WARN_DEPRECATED=y
+CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_FRAME_WARN=1024
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_STRIP_ASM_SYMS is not set
+# 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=y
+# CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set
+CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=0
+CONFIG_DETECT_HUNG_TASK=y
+# CONFIG_BOOTPARAM_HUNG_TASK_PANIC is not set
+CONFIG_BOOTPARAM_HUNG_TASK_PANIC_VALUE=0
+CONFIG_SCHED_DEBUG=y
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_TIMER_STATS is not set
+# CONFIG_DEBUG_OBJECTS is not set
+# CONFIG_SLUB_DEBUG_ON is not set
+# CONFIG_SLUB_STATS is not set
+# CONFIG_DEBUG_KMEMLEAK 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
+CONFIG_DEBUG_BUGVERBOSE=y
+CONFIG_DEBUG_INFO=y
+# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_WRITECOUNT is not set
+# CONFIG_DEBUG_MEMORY_INIT is not set
+# CONFIG_DEBUG_LIST is not set
+# CONFIG_DEBUG_SG is not set
+# CONFIG_DEBUG_NOTIFIERS is not set
+# CONFIG_DEBUG_CREDENTIALS is not set
+# CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_RCU_CPU_STALL_DETECTOR is not set
+# CONFIG_BACKTRACE_SELF_TEST is not set
+# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
+# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set
+# CONFIG_FAULT_INJECTION is not set
+# CONFIG_LATENCYTOP is not set
+# CONFIG_SYSCTL_SYSCALL_CHECK is not set
+# CONFIG_DEBUG_PAGEALLOC is not set
+CONFIG_HAVE_FUNCTION_TRACER=y
+CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
+CONFIG_HAVE_DYNAMIC_FTRACE=y
+CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
+CONFIG_TRACING_SUPPORT=y
+CONFIG_FTRACE=y
+# CONFIG_FUNCTION_TRACER is not set
+# CONFIG_IRQSOFF_TRACER is not set
+# CONFIG_SCHED_TRACER is not set
+# CONFIG_ENABLE_DEFAULT_TRACERS is not set
+# CONFIG_BOOT_TRACER is not set
+CONFIG_BRANCH_PROFILE_NONE=y
+# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set
+# CONFIG_PROFILE_ALL_BRANCHES is not set
+# CONFIG_STACK_TRACER is not set
+# CONFIG_KMEMTRACE is not set
+# CONFIG_WORKQUEUE_TRACER is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_DMA_API_DEBUG is not set
+# CONFIG_SAMPLES is not set
+CONFIG_HAVE_ARCH_KGDB=y
+# CONFIG_KGDB is not set
+# CONFIG_PPC_DISABLE_WERROR is not set
+CONFIG_PPC_WERROR=y
+CONFIG_PRINT_STACK_DEPTH=64
+# CONFIG_DEBUG_STACKOVERFLOW is not set
+# CONFIG_DEBUG_STACK_USAGE is not set
+# CONFIG_CODE_PATCHING_SELFTEST is not set
+# CONFIG_FTR_FIXUP_SELFTEST is not set
+# CONFIG_MSI_BITMAP_SELFTEST is not set
+# CONFIG_XMON is not set
+# CONFIG_IRQSTACKS is not set
+# CONFIG_BDI_SWITCH is not set
+# CONFIG_PPC_EARLY_DEBUG is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+# CONFIG_SECURITYFS is not set
+# CONFIG_DEFAULT_SECURITY_SELINUX is not set
+# CONFIG_DEFAULT_SECURITY_SMACK is not set
+# CONFIG_DEFAULT_SECURITY_TOMOYO is not set
+CONFIG_DEFAULT_SECURITY_DAC=y
+CONFIG_DEFAULT_SECURITY=""
+# CONFIG_CRYPTO is not set
+CONFIG_PPC_CLOCK=y
+CONFIG_PPC_LIB_RHEAP=y
+# CONFIG_VIRTUALIZATION is not set
diff --git a/arch/powerpc/include/asm/abs_addr.h b/arch/powerpc/include/asm/abs_addr.h
index 9a846efe638..5ab0b71531b 100644
--- a/arch/powerpc/include/asm/abs_addr.h
+++ b/arch/powerpc/include/asm/abs_addr.h
@@ -69,7 +69,7 @@ static inline unsigned long phys_to_abs(unsigned long pa)
* Legacy iSeries Hypervisor calls
*/
#define iseries_hv_addr(virtaddr) \
- (0x8000000000000000 | virt_to_abs(virtaddr))
+ (0x8000000000000000UL | virt_to_abs(virtaddr))
#endif /* __KERNEL__ */
#endif /* _ASM_POWERPC_ABS_ADDR_H */
diff --git a/arch/powerpc/include/asm/asm-compat.h b/arch/powerpc/include/asm/asm-compat.h
index 2048a6aeea9..decad950f11 100644
--- a/arch/powerpc/include/asm/asm-compat.h
+++ b/arch/powerpc/include/asm/asm-compat.h
@@ -30,6 +30,7 @@
#define PPC_STLCX stringify_in_c(stdcx.)
#define PPC_CNTLZL stringify_in_c(cntlzd)
#define PPC_LR_STKOFF 16
+#define PPC_MIN_STKFRM 112
/* Move to CR, single-entry optimized version. Only available
* on POWER4 and later.
@@ -55,6 +56,7 @@
#define PPC_CNTLZL stringify_in_c(cntlzw)
#define PPC_MTOCRF stringify_in_c(mtcrf)
#define PPC_LR_STKOFF 4
+#define PPC_MIN_STKFRM 16
#endif
diff --git a/arch/powerpc/include/asm/cputable.h b/arch/powerpc/include/asm/cputable.h
index b0b21134f61..3a40a992e59 100644
--- a/arch/powerpc/include/asm/cputable.h
+++ b/arch/powerpc/include/asm/cputable.h
@@ -197,6 +197,7 @@ extern const char *powerpc_base_platform;
#define CPU_FTR_SAO LONG_ASM_CONST(0x0020000000000000)
#define CPU_FTR_CP_USE_DCBTZ LONG_ASM_CONST(0x0040000000000000)
#define CPU_FTR_UNALIGNED_LD_STD LONG_ASM_CONST(0x0080000000000000)
+#define CPU_FTR_ASYM_SMT LONG_ASM_CONST(0x0100000000000000)
#ifndef __ASSEMBLY__
@@ -412,7 +413,7 @@ extern const char *powerpc_base_platform;
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 | CPU_FTR_SAO)
+ CPU_FTR_DSCR | CPU_FTR_SAO | CPU_FTR_ASYM_SMT)
#define CPU_FTRS_CELL (CPU_FTR_USE_TB | CPU_FTR_LWSYNC | \
CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_CTRL | \
CPU_FTR_ALTIVEC_COMP | CPU_FTR_MMCRA | CPU_FTR_SMT | \
@@ -517,6 +518,10 @@ static inline int cpu_has_feature(unsigned long feature)
& feature);
}
+#ifdef CONFIG_HAVE_HW_BREAKPOINT
+#define HBP_NUM 1
+#endif /* CONFIG_HAVE_HW_BREAKPOINT */
+
#endif /* !__ASSEMBLY__ */
#endif /* __KERNEL__ */
diff --git a/arch/powerpc/include/asm/dbell.h b/arch/powerpc/include/asm/dbell.h
index 501189a543d..0893ab9343a 100644
--- a/arch/powerpc/include/asm/dbell.h
+++ b/arch/powerpc/include/asm/dbell.h
@@ -27,10 +27,10 @@ enum ppc_dbell {
PPC_G_DBELL_MC = 4, /* guest mcheck doorbell */
};
-#ifdef CONFIG_SMP
-extern unsigned long dbell_smp_message[NR_CPUS];
-extern void smp_dbell_message_pass(int target, int msg);
-#endif
+extern void doorbell_message_pass(int target, int msg);
+extern void doorbell_exception(struct pt_regs *regs);
+extern void doorbell_check_self(void);
+extern void doorbell_setup_this_cpu(void);
static inline void ppc_msgsnd(enum ppc_dbell type, u32 flags, u32 tag)
{
diff --git a/arch/powerpc/include/asm/hvcall.h b/arch/powerpc/include/asm/hvcall.h
index 5119b7db314..de03ca58db5 100644
--- a/arch/powerpc/include/asm/hvcall.h
+++ b/arch/powerpc/include/asm/hvcall.h
@@ -74,6 +74,7 @@
#define H_NOT_ENOUGH_RESOURCES -44
#define H_R_STATE -45
#define H_RESCINDEND -46
+#define H_MULTI_THREADS_ACTIVE -9005
/* Long Busy is a condition that can be returned by the firmware
diff --git a/arch/powerpc/include/asm/hw_breakpoint.h b/arch/powerpc/include/asm/hw_breakpoint.h
new file mode 100644
index 00000000000..1c33ec17ca3
--- /dev/null
+++ b/arch/powerpc/include/asm/hw_breakpoint.h
@@ -0,0 +1,74 @@
+/*
+ * PowerPC BookIII S hardware breakpoint 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.
+ *
+ * Copyright 2010, IBM Corporation.
+ * Author: K.Prasad <prasad@linux.vnet.ibm.com>
+ *
+ */
+
+#ifndef _PPC_BOOK3S_64_HW_BREAKPOINT_H
+#define _PPC_BOOK3S_64_HW_BREAKPOINT_H
+
+#ifdef __KERNEL__
+#ifdef CONFIG_HAVE_HW_BREAKPOINT
+
+struct arch_hw_breakpoint {
+ bool extraneous_interrupt;
+ u8 len; /* length of the target data symbol */
+ int type;
+ unsigned long address;
+};
+
+#include <linux/kdebug.h>
+#include <asm/reg.h>
+#include <asm/system.h>
+
+struct perf_event;
+struct pmu;
+struct perf_sample_data;
+
+#define HW_BREAKPOINT_ALIGN 0x7
+/* Maximum permissible length of any HW Breakpoint */
+#define HW_BREAKPOINT_LEN 0x8
+
+extern int hw_breakpoint_slots(int type);
+extern int arch_bp_generic_fields(int type, int *gen_bp_type);
+extern int arch_check_bp_in_kernelspace(struct perf_event *bp);
+extern int arch_validate_hwbkpt_settings(struct perf_event *bp);
+extern int hw_breakpoint_exceptions_notify(struct notifier_block *unused,
+ unsigned long val, void *data);
+int arch_install_hw_breakpoint(struct perf_event *bp);
+void arch_uninstall_hw_breakpoint(struct perf_event *bp);
+void hw_breakpoint_pmu_read(struct perf_event *bp);
+extern void flush_ptrace_hw_breakpoint(struct task_struct *tsk);
+
+extern struct pmu perf_ops_bp;
+extern void ptrace_triggered(struct perf_event *bp, int nmi,
+ struct perf_sample_data *data, struct pt_regs *regs);
+static inline void hw_breakpoint_disable(void)
+{
+ set_dabr(0);
+}
+extern void thread_change_pc(struct task_struct *tsk, struct pt_regs *regs);
+
+#else /* CONFIG_HAVE_HW_BREAKPOINT */
+static inline void hw_breakpoint_disable(void) { }
+static inline void thread_change_pc(struct task_struct *tsk,
+ struct pt_regs *regs) { }
+#endif /* CONFIG_HAVE_HW_BREAKPOINT */
+#endif /* __KERNEL__ */
+#endif /* _PPC_BOOK3S_64_HW_BREAKPOINT_H */
diff --git a/arch/powerpc/include/asm/irq.h b/arch/powerpc/include/asm/irq.h
index ecba37a9174..67ab5fb7d15 100644
--- a/arch/powerpc/include/asm/irq.h
+++ b/arch/powerpc/include/asm/irq.h
@@ -300,34 +300,6 @@ extern unsigned int irq_alloc_virt(struct irq_host *host,
*/
extern void irq_free_virt(unsigned int virq, unsigned int count);
-
-/* -- OF helpers -- */
-
-/**
- * irq_create_of_mapping - Map a hardware interrupt into linux virq space
- * @controller: Device node of the interrupt controller
- * @inspec: Interrupt specifier from the device-tree
- * @intsize: Size of the interrupt specifier from the device-tree
- *
- * This function is identical to irq_create_mapping except that it takes
- * as input informations straight from the device-tree (typically the results
- * of the of_irq_map_*() functions.
- */
-extern unsigned int irq_create_of_mapping(struct device_node *controller,
- const u32 *intspec, unsigned int intsize);
-
-/**
- * irq_of_parse_and_map - Parse and Map an interrupt into linux virq space
- * @device: Device node of the device whose interrupt is to be mapped
- * @index: Index of the interrupt to map
- *
- * This function is a wrapper that chains of_irq_map_one() and
- * irq_create_of_mapping() to make things easier to callers
- */
-extern unsigned int irq_of_parse_and_map(struct device_node *dev, int index);
-
-/* -- End OF helpers -- */
-
/**
* irq_early_init - Init irq remapping subsystem
*/
diff --git a/arch/powerpc/include/asm/kvm_book3s.h b/arch/powerpc/include/asm/kvm_book3s.h
index 6f74d93725a..8274a2d4392 100644
--- a/arch/powerpc/include/asm/kvm_book3s.h
+++ b/arch/powerpc/include/asm/kvm_book3s.h
@@ -115,7 +115,15 @@ extern void kvmppc_mmu_book3s_32_init(struct kvm_vcpu *vcpu);
extern int kvmppc_mmu_map_page(struct kvm_vcpu *vcpu, struct kvmppc_pte *pte);
extern int kvmppc_mmu_map_segment(struct kvm_vcpu *vcpu, ulong eaddr);
extern void kvmppc_mmu_flush_segments(struct kvm_vcpu *vcpu);
-extern struct kvmppc_pte *kvmppc_mmu_find_pte(struct kvm_vcpu *vcpu, u64 ea, bool data);
+
+extern void kvmppc_mmu_hpte_cache_map(struct kvm_vcpu *vcpu, struct hpte_cache *pte);
+extern struct hpte_cache *kvmppc_mmu_hpte_cache_next(struct kvm_vcpu *vcpu);
+extern void kvmppc_mmu_hpte_destroy(struct kvm_vcpu *vcpu);
+extern int kvmppc_mmu_hpte_init(struct kvm_vcpu *vcpu);
+extern void kvmppc_mmu_invalidate_pte(struct kvm_vcpu *vcpu, struct hpte_cache *pte);
+extern int kvmppc_mmu_hpte_sysinit(void);
+extern void kvmppc_mmu_hpte_sysexit(void);
+
extern int kvmppc_ld(struct kvm_vcpu *vcpu, ulong *eaddr, int size, void *ptr, bool data);
extern int kvmppc_st(struct kvm_vcpu *vcpu, ulong *eaddr, int size, void *ptr, bool data);
extern void kvmppc_book3s_queue_irqprio(struct kvm_vcpu *vcpu, unsigned int vec);
diff --git a/arch/powerpc/include/asm/kvm_fpu.h b/arch/powerpc/include/asm/kvm_fpu.h
index 94f05de9ad0..c3d4f0518a6 100644
--- a/arch/powerpc/include/asm/kvm_fpu.h
+++ b/arch/powerpc/include/asm/kvm_fpu.h
@@ -22,24 +22,24 @@
#include <linux/types.h>
-extern void fps_fres(struct thread_struct *t, u32 *dst, u32 *src1);
-extern void fps_frsqrte(struct thread_struct *t, u32 *dst, u32 *src1);
-extern void fps_fsqrts(struct thread_struct *t, u32 *dst, u32 *src1);
+extern void fps_fres(u64 *fpscr, u32 *dst, u32 *src1);
+extern void fps_frsqrte(u64 *fpscr, u32 *dst, u32 *src1);
+extern void fps_fsqrts(u64 *fpscr, u32 *dst, u32 *src1);
-extern void fps_fadds(struct thread_struct *t, u32 *dst, u32 *src1, u32 *src2);
-extern void fps_fdivs(struct thread_struct *t, u32 *dst, u32 *src1, u32 *src2);
-extern void fps_fmuls(struct thread_struct *t, u32 *dst, u32 *src1, u32 *src2);
-extern void fps_fsubs(struct thread_struct *t, u32 *dst, u32 *src1, u32 *src2);
+extern void fps_fadds(u64 *fpscr, u32 *dst, u32 *src1, u32 *src2);
+extern void fps_fdivs(u64 *fpscr, u32 *dst, u32 *src1, u32 *src2);
+extern void fps_fmuls(u64 *fpscr, u32 *dst, u32 *src1, u32 *src2);
+extern void fps_fsubs(u64 *fpscr, u32 *dst, u32 *src1, u32 *src2);
-extern void fps_fmadds(struct thread_struct *t, u32 *dst, u32 *src1, u32 *src2,
+extern void fps_fmadds(u64 *fpscr, u32 *dst, u32 *src1, u32 *src2,
u32 *src3);
-extern void fps_fmsubs(struct thread_struct *t, u32 *dst, u32 *src1, u32 *src2,
+extern void fps_fmsubs(u64 *fpscr, u32 *dst, u32 *src1, u32 *src2,
u32 *src3);
-extern void fps_fnmadds(struct thread_struct *t, u32 *dst, u32 *src1, u32 *src2,
+extern void fps_fnmadds(u64 *fpscr, u32 *dst, u32 *src1, u32 *src2,
u32 *src3);
-extern void fps_fnmsubs(struct thread_struct *t, u32 *dst, u32 *src1, u32 *src2,
+extern void fps_fnmsubs(u64 *fpscr, u32 *dst, u32 *src1, u32 *src2,
u32 *src3);
-extern void fps_fsel(struct thread_struct *t, u32 *dst, u32 *src1, u32 *src2,
+extern void fps_fsel(u64 *fpscr, u32 *dst, u32 *src1, u32 *src2,
u32 *src3);
#define FPD_ONE_IN(name) extern void fpd_ ## name(u64 *fpscr, u32 *cr, \
@@ -82,4 +82,7 @@ FPD_THREE_IN(fmadd)
FPD_THREE_IN(fnmsub)
FPD_THREE_IN(fnmadd)
+extern void kvm_cvt_fd(u32 *from, u64 *to, u64 *fpscr);
+extern void kvm_cvt_df(u64 *from, u32 *to, u64 *fpscr);
+
#endif
diff --git a/arch/powerpc/include/asm/kvm_host.h b/arch/powerpc/include/asm/kvm_host.h
index 0c9ad869dec..b0b23c007d6 100644
--- a/arch/powerpc/include/asm/kvm_host.h
+++ b/arch/powerpc/include/asm/kvm_host.h
@@ -35,10 +35,17 @@
#define KVM_COALESCED_MMIO_PAGE_OFFSET 1
/* We don't currently support large pages. */
+#define KVM_HPAGE_GFN_SHIFT(x) 0
#define KVM_NR_PAGE_SIZES 1
#define KVM_PAGES_PER_HPAGE(x) (1UL<<31)
-#define HPTEG_CACHE_NUM 1024
+#define HPTEG_CACHE_NUM (1 << 15)
+#define HPTEG_HASH_BITS_PTE 13
+#define HPTEG_HASH_BITS_VPTE 13
+#define HPTEG_HASH_BITS_VPTE_LONG 5
+#define HPTEG_HASH_NUM_PTE (1 << HPTEG_HASH_BITS_PTE)
+#define HPTEG_HASH_NUM_VPTE (1 << HPTEG_HASH_BITS_VPTE)
+#define HPTEG_HASH_NUM_VPTE_LONG (1 << HPTEG_HASH_BITS_VPTE_LONG)
struct kvm;
struct kvm_run;
@@ -151,6 +158,9 @@ struct kvmppc_mmu {
};
struct hpte_cache {
+ struct hlist_node list_pte;
+ struct hlist_node list_vpte;
+ struct hlist_node list_vpte_long;
u64 host_va;
u64 pfn;
ulong slot;
@@ -282,8 +292,10 @@ struct kvm_vcpu_arch {
unsigned long pending_exceptions;
#ifdef CONFIG_PPC_BOOK3S
- struct hpte_cache hpte_cache[HPTEG_CACHE_NUM];
- int hpte_cache_offset;
+ struct hlist_head hpte_hash_pte[HPTEG_HASH_NUM_PTE];
+ struct hlist_head hpte_hash_vpte[HPTEG_HASH_NUM_VPTE];
+ struct hlist_head hpte_hash_vpte_long[HPTEG_HASH_NUM_VPTE_LONG];
+ int hpte_cache_count;
#endif
};
diff --git a/arch/powerpc/include/asm/local64.h b/arch/powerpc/include/asm/local64.h
new file mode 100644
index 00000000000..36c93b5cc23
--- /dev/null
+++ b/arch/powerpc/include/asm/local64.h
@@ -0,0 +1 @@
+#include <asm-generic/local64.h>
diff --git a/arch/powerpc/include/asm/machdep.h b/arch/powerpc/include/asm/machdep.h
index 9f0fc9e6ce0..adc8e6cdf33 100644
--- a/arch/powerpc/include/asm/machdep.h
+++ b/arch/powerpc/include/asm/machdep.h
@@ -266,6 +266,7 @@ struct machdep_calls {
void (*suspend_disable_irqs)(void);
void (*suspend_enable_irqs)(void);
#endif
+ int (*suspend_disable_cpu)(void);
#ifdef CONFIG_ARCH_CPU_PROBE_RELEASE
ssize_t (*cpu_probe)(const char *, size_t);
@@ -277,6 +278,7 @@ extern void e500_idle(void);
extern void power4_idle(void);
extern void power4_cpu_offline_powersave(void);
extern void ppc6xx_idle(void);
+extern void book3e_idle(void);
/*
* ppc_md contains a copy of the machine description structure for the
@@ -366,8 +368,5 @@ static inline void log_error(char *buf, unsigned int err_type, int fatal)
#define machine_late_initcall(mach,fn) __define_machine_initcall(mach,"7",fn,7)
#define machine_late_initcall_sync(mach,fn) __define_machine_initcall(mach,"7s",fn,7s)
-void generic_suspend_disable_irqs(void);
-void generic_suspend_enable_irqs(void);
-
#endif /* __KERNEL__ */
#endif /* _ASM_POWERPC_MACHDEP_H */
diff --git a/arch/powerpc/include/asm/macio.h b/arch/powerpc/include/asm/macio.h
index 675e159b5ef..7ab82c825a0 100644
--- a/arch/powerpc/include/asm/macio.h
+++ b/arch/powerpc/include/asm/macio.h
@@ -38,7 +38,7 @@ struct macio_dev
{
struct macio_bus *bus; /* macio bus this device is on */
struct macio_dev *media_bay; /* Device is part of a media bay */
- struct of_device ofdev;
+ struct platform_device ofdev;
struct device_dma_parameters dma_parms; /* ide needs that */
int n_resources;
struct resource resource[MACIO_DEV_COUNT_RESOURCES];
diff --git a/arch/powerpc/include/asm/mmu-book3e.h b/arch/powerpc/include/asm/mmu-book3e.h
index 74695816205..87a1d787c5b 100644
--- a/arch/powerpc/include/asm/mmu-book3e.h
+++ b/arch/powerpc/include/asm/mmu-book3e.h
@@ -193,6 +193,10 @@ struct mmu_psize_def
{
unsigned int shift; /* number of bits */
unsigned int enc; /* PTE encoding */
+ unsigned int ind; /* Corresponding indirect page size shift */
+ unsigned int flags;
+#define MMU_PAGE_SIZE_DIRECT 0x1 /* Supported as a direct size */
+#define MMU_PAGE_SIZE_INDIRECT 0x2 /* Supported as an indirect size */
};
extern struct mmu_psize_def mmu_psize_defs[MMU_PAGE_COUNT];
diff --git a/arch/powerpc/include/asm/mpc5121.h b/arch/powerpc/include/asm/mpc5121.h
index e6a30bb1d16..8c0ab2ca689 100644
--- a/arch/powerpc/include/asm/mpc5121.h
+++ b/arch/powerpc/include/asm/mpc5121.h
@@ -21,4 +21,36 @@ struct mpc512x_reset_module {
u32 rcer; /* Reset Control Enable Register */
};
+/*
+ * Clock Control Module
+ */
+struct mpc512x_ccm {
+ u32 spmr; /* System PLL Mode Register */
+ u32 sccr1; /* System Clock Control Register 1 */
+ u32 sccr2; /* System Clock Control Register 2 */
+ u32 scfr1; /* System Clock Frequency Register 1 */
+ u32 scfr2; /* System Clock Frequency Register 2 */
+ u32 scfr2s; /* System Clock Frequency Shadow Register 2 */
+ u32 bcr; /* Bread Crumb Register */
+ u32 p0ccr; /* PSC0 Clock Control Register */
+ u32 p1ccr; /* PSC1 CCR */
+ u32 p2ccr; /* PSC2 CCR */
+ u32 p3ccr; /* PSC3 CCR */
+ u32 p4ccr; /* PSC4 CCR */
+ u32 p5ccr; /* PSC5 CCR */
+ u32 p6ccr; /* PSC6 CCR */
+ u32 p7ccr; /* PSC7 CCR */
+ u32 p8ccr; /* PSC8 CCR */
+ u32 p9ccr; /* PSC9 CCR */
+ u32 p10ccr; /* PSC10 CCR */
+ u32 p11ccr; /* PSC11 CCR */
+ u32 spccr; /* SPDIF Clock Control Register */
+ u32 cccr; /* CFM Clock Control Register */
+ u32 dccr; /* DIU Clock Control Register */
+ u32 m1ccr; /* MSCAN1 CCR */
+ u32 m2ccr; /* MSCAN2 CCR */
+ u32 m3ccr; /* MSCAN3 CCR */
+ u32 m4ccr; /* MSCAN4 CCR */
+ u8 res[0x98]; /* Reserved */
+};
#endif /* __ASM_POWERPC_MPC5121_H__ */
diff --git a/arch/powerpc/include/asm/of_device.h b/arch/powerpc/include/asm/of_device.h
deleted file mode 100644
index 444e97e2982..00000000000
--- a/arch/powerpc/include/asm/of_device.h
+++ /dev/null
@@ -1,27 +0,0 @@
-#ifndef _ASM_POWERPC_OF_DEVICE_H
-#define _ASM_POWERPC_OF_DEVICE_H
-#ifdef __KERNEL__
-
-#include <linux/device.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.
- */
-struct of_device
-{
- struct device dev; /* Generic device interface */
- struct pdev_archdata archdata;
-};
-
-extern struct of_device *of_device_alloc(struct device_node *np,
- const char *bus_id,
- struct device *parent);
-
-extern int of_device_uevent(struct device *dev,
- struct kobj_uevent_env *env);
-
-#endif /* __KERNEL__ */
-#endif /* _ASM_POWERPC_OF_DEVICE_H */
diff --git a/arch/powerpc/include/asm/of_platform.h b/arch/powerpc/include/asm/of_platform.h
deleted file mode 100644
index d4aaa348944..00000000000
--- a/arch/powerpc/include/asm/of_platform.h
+++ /dev/null
@@ -1,29 +0,0 @@
-#ifndef _ASM_POWERPC_OF_PLATFORM_H
-#define _ASM_POWERPC_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.
- *
- */
-
-/* Platform devices and busses creation */
-extern struct of_device *of_platform_device_create(struct device_node *np,
- const char *bus_id,
- struct device *parent);
-/* pseudo "matches" value to not do deep probe */
-#define OF_NO_DEEP_PROBE ((struct of_device_id *)-1)
-
-extern int of_platform_bus_probe(struct device_node *root,
- const struct of_device_id *matches,
- struct device *parent);
-
-extern struct of_device *of_find_device_by_phandle(phandle ph);
-
-extern void of_instantiate_rtc(void);
-
-#endif /* _ASM_POWERPC_OF_PLATFORM_H */
diff --git a/arch/powerpc/include/asm/paca.h b/arch/powerpc/include/asm/paca.h
index 8ce7963ad41..1ff6662f7fa 100644
--- a/arch/powerpc/include/asm/paca.h
+++ b/arch/powerpc/include/asm/paca.h
@@ -146,7 +146,7 @@ struct paca_struct {
extern struct paca_struct *paca;
extern __initdata struct paca_struct boot_paca;
extern void initialise_paca(struct paca_struct *new_paca, int cpu);
-
+extern void setup_paca(struct paca_struct *new_paca);
extern void allocate_pacas(void);
extern void free_unused_pacas(void);
diff --git a/arch/powerpc/include/asm/pci-bridge.h b/arch/powerpc/include/asm/pci-bridge.h
index 76e1f313a58..51e9e6f90d1 100644
--- a/arch/powerpc/include/asm/pci-bridge.h
+++ b/arch/powerpc/include/asm/pci-bridge.h
@@ -303,13 +303,8 @@ extern void pcibios_free_controller(struct pci_controller *phb);
extern void pcibios_setup_phb_resources(struct pci_controller *hose);
#ifdef CONFIG_PCI
-extern unsigned long pci_address_to_pio(phys_addr_t address);
extern int pcibios_vaddr_is_ioport(void __iomem *address);
#else
-static inline unsigned long pci_address_to_pio(phys_addr_t address)
-{
- return (unsigned long)-1;
-}
static inline int pcibios_vaddr_is_ioport(void __iomem *address)
{
return 0;
diff --git a/arch/powerpc/include/asm/percpu.h b/arch/powerpc/include/asm/percpu.h
index f879252b7ea..2cedefddba3 100644
--- a/arch/powerpc/include/asm/percpu.h
+++ b/arch/powerpc/include/asm/percpu.h
@@ -1,7 +1,6 @@
#ifndef _ASM_POWERPC_PERCPU_H_
#define _ASM_POWERPC_PERCPU_H_
#ifdef __powerpc64__
-#include <linux/compiler.h>
/*
* Same as asm-generic/percpu.h, except that we store the per cpu offset
@@ -12,9 +11,7 @@
#include <asm/paca.h>
-#define __per_cpu_offset(cpu) (paca[cpu].data_offset)
#define __my_cpu_offset local_paca->data_offset
-#define per_cpu_offset(x) (__per_cpu_offset(x))
#endif /* CONFIG_SMP */
#endif /* __powerpc64__ */
diff --git a/arch/powerpc/include/asm/perf_event.h b/arch/powerpc/include/asm/perf_event.h
index e6d4ce69b12..5c16b891d50 100644
--- a/arch/powerpc/include/asm/perf_event.h
+++ b/arch/powerpc/include/asm/perf_event.h
@@ -21,3 +21,15 @@
#ifdef CONFIG_FSL_EMB_PERF_EVENT
#include <asm/perf_event_fsl_emb.h>
#endif
+
+#ifdef CONFIG_PERF_EVENTS
+#include <asm/ptrace.h>
+#include <asm/reg.h>
+
+#define perf_arch_fetch_caller_regs(regs, __ip) \
+ do { \
+ (regs)->nip = __ip; \
+ (regs)->gpr[1] = *(unsigned long *)__get_SP(); \
+ asm volatile("mfmsr %0" : "=r" ((regs)->msr)); \
+ } while (0)
+#endif
diff --git a/arch/powerpc/include/asm/ppc-opcode.h b/arch/powerpc/include/asm/ppc-opcode.h
index d553bbeb726..43adc8b819e 100644
--- a/arch/powerpc/include/asm/ppc-opcode.h
+++ b/arch/powerpc/include/asm/ppc-opcode.h
@@ -52,13 +52,17 @@
#define PPC_INST_WAIT 0x7c00007c
#define PPC_INST_TLBIVAX 0x7c000624
#define PPC_INST_TLBSRX_DOT 0x7c0006a5
+#define PPC_INST_XXLOR 0xf0000510
/* macros to insert fields into opcodes */
#define __PPC_RA(a) (((a) & 0x1f) << 16)
#define __PPC_RB(b) (((b) & 0x1f) << 11)
#define __PPC_RS(s) (((s) & 0x1f) << 21)
#define __PPC_RT(s) __PPC_RS(s)
+#define __PPC_XA(a) ((((a) & 0x1f) << 16) | (((a) & 0x20) >> 3))
+#define __PPC_XB(b) ((((b) & 0x1f) << 11) | (((b) & 0x20) >> 4))
#define __PPC_XS(s) ((((s) & 0x1f) << 21) | (((s) & 0x20) >> 5))
+#define __PPC_XT(s) __PPC_XS(s)
#define __PPC_T_TLB(t) (((t) & 0x3) << 21)
#define __PPC_WC(w) (((w) & 0x3) << 21)
/*
@@ -106,9 +110,12 @@
* the 128 bit load store instructions based on that.
*/
#define VSX_XX1(s, a, b) (__PPC_XS(s) | __PPC_RA(a) | __PPC_RB(b))
+#define VSX_XX3(t, a, b) (__PPC_XT(t) | __PPC_XA(a) | __PPC_XB(b))
#define STXVD2X(s, a, b) stringify_in_c(.long PPC_INST_STXVD2X | \
VSX_XX1((s), (a), (b)))
#define LXVD2X(s, a, b) stringify_in_c(.long PPC_INST_LXVD2X | \
VSX_XX1((s), (a), (b)))
+#define XXLOR(t, a, b) stringify_in_c(.long PPC_INST_XXLOR | \
+ VSX_XX3((t), (a), (b)))
#endif /* _ASM_POWERPC_PPC_OPCODE_H */
diff --git a/arch/powerpc/include/asm/processor.h b/arch/powerpc/include/asm/processor.h
index 7492fe8ad6e..19c05b0f74b 100644
--- a/arch/powerpc/include/asm/processor.h
+++ b/arch/powerpc/include/asm/processor.h
@@ -209,6 +209,14 @@ struct thread_struct {
#ifdef CONFIG_PPC64
unsigned long start_tb; /* Start purr when proc switched in */
unsigned long accum_tb; /* Total accumilated purr for process */
+#ifdef CONFIG_HAVE_HW_BREAKPOINT
+ struct perf_event *ptrace_bps[HBP_NUM];
+ /*
+ * Helps identify source of single-step exception and subsequent
+ * hw-breakpoint enablement
+ */
+ struct perf_event *last_hit_ubp;
+#endif /* CONFIG_HAVE_HW_BREAKPOINT */
#endif
unsigned long dabr; /* Data address breakpoint register */
#ifdef CONFIG_ALTIVEC
diff --git a/arch/powerpc/include/asm/prom.h b/arch/powerpc/include/asm/prom.h
index ddd408a93b5..ae26f2efd08 100644
--- a/arch/powerpc/include/asm/prom.h
+++ b/arch/powerpc/include/asm/prom.h
@@ -17,9 +17,6 @@
* 2 of the License, or (at your option) any later version.
*/
#include <linux/types.h>
-#include <linux/of_fdt.h>
-#include <linux/proc_fs.h>
-#include <linux/platform_device.h>
#include <asm/irq.h>
#include <asm/atomic.h>
@@ -43,49 +40,14 @@ extern void pci_create_OF_bus_map(void);
* OF address retreival & translation
*/
-/* Translate an OF address block into a CPU physical address
- */
-extern u64 of_translate_address(struct device_node *np, const u32 *addr);
-
/* Translate a DMA address from device space to CPU space */
extern u64 of_translate_dma_address(struct device_node *dev,
const u32 *in_addr);
-/* Extract an address from a device, returns the region size and
- * the address space flags too. The PCI version uses a BAR number
- * instead of an absolute index
- */
-extern const u32 *of_get_address(struct device_node *dev, int index,
- u64 *size, unsigned int *flags);
#ifdef CONFIG_PCI
-extern const u32 *of_get_pci_address(struct device_node *dev, int bar_no,
- u64 *size, unsigned int *flags);
-#else
-static inline const u32 *of_get_pci_address(struct device_node *dev,
- int bar_no, u64 *size, unsigned int *flags)
-{
- return NULL;
-}
-#endif /* CONFIG_PCI */
-
-/* Get an address as a resource. Note that if your address is
- * a PIO address, the conversion will fail if the physical address
- * can't be internally converted to an IO token with
- * pci_address_to_pio(), that is because it's either called to early
- * or it can't be matched to any host bridge IO space
- */
-extern int of_address_to_resource(struct device_node *dev, int index,
- struct resource *r);
-#ifdef CONFIG_PCI
-extern int of_pci_address_to_resource(struct device_node *dev, int bar,
- struct resource *r);
-#else
-static inline int of_pci_address_to_resource(struct device_node *dev, int bar,
- struct resource *r)
-{
- return -ENOSYS;
-}
-#endif /* CONFIG_PCI */
+extern unsigned long pci_address_to_pio(phys_addr_t address);
+#define pci_address_to_pio pci_address_to_pio
+#endif /* CONFIG_PCI */
/* Parse the ibm,dma-window property of an OF node into the busno, phys and
* size parameters.
@@ -104,69 +66,12 @@ struct device_node *of_find_next_cache_node(struct device_node *np);
/* Get the MAC address */
extern const void *of_get_mac_address(struct device_node *np);
-/*
- * OF interrupt mapping
- */
-
-/* This structure is returned when an interrupt is mapped. The controller
- * field needs to be put() after use
- */
-
-#define OF_MAX_IRQ_SPEC 4 /* We handle specifiers of at most 4 cells */
-
-struct of_irq {
- struct device_node *controller; /* Interrupt controller node */
- u32 size; /* Specifier size */
- u32 specifier[OF_MAX_IRQ_SPEC]; /* Specifier copy */
-};
-
-/**
- * of_irq_map_init - Initialize the irq remapper
- * @flags: flags defining workarounds to enable
- *
- * Some machines have bugs in the device-tree which require certain workarounds
- * to be applied. Call this before any interrupt mapping attempts to enable
- * those workarounds.
- */
-#define OF_IMAP_OLDWORLD_MAC 0x00000001
-#define OF_IMAP_NO_PHANDLE 0x00000002
-
-extern void of_irq_map_init(unsigned int flags);
-
-/**
- * of_irq_map_raw - Low level interrupt tree parsing
- * @parent: the device interrupt parent
- * @intspec: interrupt specifier ("interrupts" property of the device)
- * @ointsize: size of the passed in interrupt specifier
- * @addr: address specifier (start of "reg" property of the device)
- * @out_irq: structure of_irq filled by this function
- *
- * Returns 0 on success and a negative number on error
- *
- * This function is a low-level interrupt tree walking function. It
- * can be used to do a partial walk with synthetized reg and interrupts
- * properties, for example when resolving PCI interrupts when no device
- * node exist for the parent.
- *
- */
-
-extern int of_irq_map_raw(struct device_node *parent, const u32 *intspec,
- u32 ointsize, const u32 *addr,
- struct of_irq *out_irq);
-
-
-/**
- * of_irq_map_one - Resolve an interrupt for a device
- * @device: the device whose interrupt is to be resolved
- * @index: index of the interrupt to resolve
- * @out_irq: structure of_irq filled by this function
- *
- * This function resolves an interrupt, walking the tree, for a given
- * device-tree node. It's the high level pendant to of_irq_map_raw().
- * It also implements the workarounds for OldWolrd Macs.
- */
-extern int of_irq_map_one(struct device_node *device, int index,
- struct of_irq *out_irq);
+#ifdef CONFIG_NUMA
+extern int of_node_to_nid(struct device_node *device);
+#else
+static inline int of_node_to_nid(struct device_node *device) { return 0; }
+#endif
+#define of_node_to_nid of_node_to_nid
/**
* of_irq_map_pci - Resolve the interrupt for a PCI device
@@ -180,19 +85,19 @@ extern int of_irq_map_one(struct device_node *device, int index,
* resolving using the OF tree walking.
*/
struct pci_dev;
+struct of_irq;
extern int of_irq_map_pci(struct pci_dev *pdev, struct of_irq *out_irq);
-extern int of_irq_to_resource(struct device_node *dev, int index,
- struct resource *r);
+extern void of_instantiate_rtc(void);
-/**
- * of_iomap - Maps the memory mapped IO for a given device_node
- * @device: the device whose io range will be mapped
- * @index: index of the io range
- *
- * Returns a pointer to the mapped memory
- */
-extern void __iomem *of_iomap(struct device_node *device, int index);
+/* These includes are put at the bottom because they may contain things
+ * that are overridden by this file. Ideally they shouldn't be included
+ * by this file, but there are a bunch of .c files that currently depend
+ * on it. Eventually they will be cleaned up. */
+#include <linux/of_fdt.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/platform_device.h>
#endif /* __KERNEL__ */
#endif /* _POWERPC_PROM_H */
diff --git a/arch/powerpc/include/asm/reg.h b/arch/powerpc/include/asm/reg.h
index d62fdf4e504..d8be016d2ed 100644
--- a/arch/powerpc/include/asm/reg.h
+++ b/arch/powerpc/include/asm/reg.h
@@ -890,7 +890,7 @@
#ifndef __ASSEMBLY__
#define mfmsr() ({unsigned long rval; \
asm volatile("mfmsr %0" : "=r" (rval)); rval;})
-#ifdef CONFIG_PPC64
+#ifdef CONFIG_PPC_BOOK3S_64
#define __mtmsrd(v, l) asm volatile("mtmsrd %0," __stringify(l) \
: : "r" (v) : "memory")
#define mtmsrd(v) __mtmsrd((v), 0)
diff --git a/arch/powerpc/include/asm/reg_booke.h b/arch/powerpc/include/asm/reg_booke.h
index 2360317179a..667a498eaee 100644
--- a/arch/powerpc/include/asm/reg_booke.h
+++ b/arch/powerpc/include/asm/reg_booke.h
@@ -29,8 +29,8 @@
#if defined(CONFIG_PPC_BOOK3E_64)
#define MSR_ MSR_ME | MSR_CE
#define MSR_KERNEL MSR_ | MSR_CM
-#define MSR_USER32 MSR_ | MSR_PR | MSR_EE
-#define MSR_USER64 MSR_USER32 | MSR_CM
+#define MSR_USER32 MSR_ | MSR_PR | MSR_EE | MSR_DE
+#define MSR_USER64 MSR_USER32 | MSR_CM | MSR_DE
#elif defined (CONFIG_40x)
#define MSR_KERNEL (MSR_ME|MSR_RI|MSR_IR|MSR_DR|MSR_CE)
#define MSR_USER (MSR_KERNEL|MSR_PR|MSR_EE)
@@ -62,6 +62,7 @@
#define SPRN_TLB0PS 0x158 /* TLB 0 Page Size Register */
#define SPRN_MAS5_MAS6 0x15c /* MMU Assist Register 5 || 6 */
#define SPRN_MAS8_MAS1 0x15d /* MMU Assist Register 8 || 1 */
+#define SPRN_EPTCFG 0x15e /* Embedded Page Table Config */
#define SPRN_MAS7_MAS3 0x174 /* MMU Assist Register 7 || 3 */
#define SPRN_MAS0_MAS1 0x175 /* MMU Assist Register 0 || 1 */
#define SPRN_IVOR0 0x190 /* Interrupt Vector Offset Register 0 */
diff --git a/arch/powerpc/include/asm/rtas.h b/arch/powerpc/include/asm/rtas.h
index 20de73c3668..3d35f8ae377 100644
--- a/arch/powerpc/include/asm/rtas.h
+++ b/arch/powerpc/include/asm/rtas.h
@@ -63,6 +63,14 @@ struct rtas_t {
struct device_node *dev; /* virtual address pointer */
};
+struct rtas_suspend_me_data {
+ atomic_t working; /* number of cpus accessing this struct */
+ atomic_t done;
+ int token; /* ibm,suspend-me */
+ atomic_t error;
+ struct completion *complete; /* wait on this until working == 0 */
+};
+
/* RTAS event classes */
#define RTAS_INTERNAL_ERROR 0x80000000 /* set bit 0 */
#define RTAS_EPOW_WARNING 0x40000000 /* set bit 1 */
@@ -137,6 +145,9 @@ struct rtas_t {
#define RTAS_TYPE_PMGM_CONFIG_CHANGE 0x70
#define RTAS_TYPE_PMGM_SERVICE_PROC 0x71
+/* RTAS check-exception vector offset */
+#define RTAS_VECTOR_EXTERNAL_INTERRUPT 0x500
+
struct rtas_error_log {
unsigned long version:8; /* Architectural version */
unsigned long severity:3; /* Severity level of error */
@@ -174,6 +185,8 @@ extern int rtas_set_indicator(int indicator, int index, int new_value);
extern int rtas_set_indicator_fast(int indicator, int index, int new_value);
extern void rtas_progress(char *s, unsigned short hex);
extern void rtas_initialize(void);
+extern int rtas_suspend_cpu(struct rtas_suspend_me_data *data);
+extern int rtas_suspend_last_cpu(struct rtas_suspend_me_data *data);
struct rtc_time;
extern unsigned long rtas_get_boot_time(void);
diff --git a/arch/powerpc/include/asm/smu.h b/arch/powerpc/include/asm/smu.h
index 7ae2753da56..e3bdada8c54 100644
--- a/arch/powerpc/include/asm/smu.h
+++ b/arch/powerpc/include/asm/smu.h
@@ -457,8 +457,8 @@ extern void smu_poll(void);
*/
extern int smu_init(void);
extern int smu_present(void);
-struct of_device;
-extern struct of_device *smu_get_ofdev(void);
+struct platform_device;
+extern struct platform_device *smu_get_ofdev(void);
/*
diff --git a/arch/powerpc/include/asm/system.h b/arch/powerpc/include/asm/system.h
index a6297c67c3d..6c294acac84 100644
--- a/arch/powerpc/include/asm/system.h
+++ b/arch/powerpc/include/asm/system.h
@@ -515,11 +515,8 @@ __cmpxchg_local(volatile void *ptr, unsigned long old, unsigned long new,
* powers of 2 writes until it reaches sufficient alignment).
*
* Based on this we disable the IP header alignment in network drivers.
- * We also modify NET_SKB_PAD to be a cacheline in size, thus maintaining
- * cacheline alignment of buffers.
*/
#define NET_IP_ALIGN 0
-#define NET_SKB_PAD L1_CACHE_BYTES
#define cmpxchg64(ptr, o, n) \
({ \
diff --git a/arch/powerpc/include/asm/time.h b/arch/powerpc/include/asm/time.h
index 27ccb764fda..dc779dfcf25 100644
--- a/arch/powerpc/include/asm/time.h
+++ b/arch/powerpc/include/asm/time.h
@@ -28,16 +28,12 @@
extern unsigned long tb_ticks_per_jiffy;
extern unsigned long tb_ticks_per_usec;
extern unsigned long tb_ticks_per_sec;
-extern u64 tb_to_xs;
-extern unsigned tb_to_us;
struct rtc_time;
extern void to_tm(int tim, struct rtc_time * tm);
extern void GregorianDay(struct rtc_time *tm);
-extern time_t last_rtc_update;
extern void generic_calibrate_decr(void);
-extern void wakeup_decrementer(void);
extern void snapshot_timebase(void);
extern void set_dec_cpu6(unsigned int val);
@@ -204,9 +200,6 @@ static inline unsigned long tb_ticks_since(unsigned long tstamp)
extern u64 mulhdu(u64, u64);
#endif
-extern void smp_space_timers(unsigned int);
-
-extern unsigned mulhwu_scale_factor(unsigned, unsigned);
extern void div128_by_32(u64 dividend_high, u64 dividend_low,
unsigned divisor, struct div_result *dr);
diff --git a/arch/powerpc/include/asm/topology.h b/arch/powerpc/include/asm/topology.h
index 32adf728072..afe4aaa65c3 100644
--- a/arch/powerpc/include/asm/topology.h
+++ b/arch/powerpc/include/asm/topology.h
@@ -41,8 +41,6 @@ static inline int cpu_to_node(int cpu)
cpu_all_mask : \
node_to_cpumask_map[node])
-int of_node_to_nid(struct device_node *device);
-
struct pci_bus;
#ifdef CONFIG_PCI
extern int pcibus_to_node(struct pci_bus *bus);
@@ -87,6 +85,9 @@ static inline int pcibus_to_node(struct pci_bus *bus)
.balance_interval = 1, \
}
+extern int __node_distance(int, int);
+#define node_distance(a, b) __node_distance(a, b)
+
extern void __init dump_numa_cpu_topology(void);
extern int sysfs_add_device_to_node(struct sys_device *dev, int nid);
@@ -94,11 +95,6 @@ extern void sysfs_remove_device_from_node(struct sys_device *dev, int nid);
#else
-static inline int of_node_to_nid(struct device_node *device)
-{
- return 0;
-}
-
static inline void dump_numa_cpu_topology(void) {}
static inline int sysfs_add_device_to_node(struct sys_device *dev, int nid)
diff --git a/arch/powerpc/include/asm/vdso_datapage.h b/arch/powerpc/include/asm/vdso_datapage.h
index 13c2c283e17..08679c5319b 100644
--- a/arch/powerpc/include/asm/vdso_datapage.h
+++ b/arch/powerpc/include/asm/vdso_datapage.h
@@ -85,6 +85,7 @@ struct vdso_data {
__s32 wtom_clock_sec; /* Wall to monotonic clock */
__s32 wtom_clock_nsec;
struct timespec stamp_xtime; /* xtime as at tb_orig_stamp */
+ __u32 stamp_sec_fraction; /* fractional seconds of stamp_xtime */
__u32 syscall_map_64[SYSCALL_MAP_SIZE]; /* map of syscalls */
__u32 syscall_map_32[SYSCALL_MAP_SIZE]; /* map of syscalls */
};
@@ -105,6 +106,7 @@ struct vdso_data {
__s32 wtom_clock_sec; /* Wall to monotonic clock */
__s32 wtom_clock_nsec;
struct timespec stamp_xtime; /* xtime as at tb_orig_stamp */
+ __u32 stamp_sec_fraction; /* fractional seconds of stamp_xtime */
__u32 syscall_map_32[SYSCALL_MAP_SIZE]; /* map of syscalls */
__u32 dcache_block_size; /* L1 d-cache block size */
__u32 icache_block_size; /* L1 i-cache block size */
diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile
index 58d0572de6f..1dda7012914 100644
--- a/arch/powerpc/kernel/Makefile
+++ b/arch/powerpc/kernel/Makefile
@@ -34,13 +34,14 @@ obj-y += vdso32/
obj-$(CONFIG_PPC64) += setup_64.o sys_ppc32.o \
signal_64.o ptrace32.o \
paca.o nvram_64.o firmware.o
+obj-$(CONFIG_HAVE_HW_BREAKPOINT) += hw_breakpoint.o
obj-$(CONFIG_PPC_BOOK3S_64) += cpu_setup_ppc970.o cpu_setup_pa6t.o
obj64-$(CONFIG_RELOCATABLE) += reloc_64.o
-obj-$(CONFIG_PPC_BOOK3E_64) += exceptions-64e.o
+obj-$(CONFIG_PPC_BOOK3E_64) += exceptions-64e.o idle_book3e.o
obj-$(CONFIG_PPC64) += vdso64/
obj-$(CONFIG_ALTIVEC) += vecemu.o
obj-$(CONFIG_PPC_970_NAP) += idle_power4.o
-obj-$(CONFIG_PPC_OF) += of_device.o of_platform.o prom_parse.o
+obj-$(CONFIG_PPC_OF) += of_platform.o prom_parse.o
obj-$(CONFIG_PPC_CLOCK) += clock.o
procfs-y := proc_powerpc.o
obj-$(CONFIG_PROC_FS) += $(procfs-y)
@@ -67,6 +68,7 @@ obj64-$(CONFIG_HIBERNATION) += swsusp_asm64.o
obj-$(CONFIG_MODULES) += module.o module_$(CONFIG_WORD_SIZE).o
obj-$(CONFIG_44x) += cpu_setup_44x.o
obj-$(CONFIG_FSL_BOOKE) += cpu_setup_fsl_booke.o dbell.o
+obj-$(CONFIG_PPC_BOOK3E_64) += dbell.o
extra-y := head_$(CONFIG_WORD_SIZE).o
extra-$(CONFIG_PPC_BOOK3E_32) := head_new_booke.o
diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c
index 496cc5b3984..1c0607ddccc 100644
--- a/arch/powerpc/kernel/asm-offsets.c
+++ b/arch/powerpc/kernel/asm-offsets.c
@@ -194,7 +194,6 @@ int main(void)
DEFINE(PACA_STARTSPURR, offsetof(struct paca_struct, startspurr));
DEFINE(PACA_USER_TIME, offsetof(struct paca_struct, user_time));
DEFINE(PACA_SYSTEM_TIME, offsetof(struct paca_struct, system_time));
- DEFINE(PACA_DATA_OFFSET, offsetof(struct paca_struct, data_offset));
DEFINE(PACA_TRAP_SAVE, offsetof(struct paca_struct, trap_save));
#ifdef CONFIG_KVM_BOOK3S_64_HANDLER
DEFINE(PACA_KVM_SVCPU, offsetof(struct paca_struct, shadow_vcpu));
@@ -342,6 +341,7 @@ int main(void)
DEFINE(WTOM_CLOCK_SEC, offsetof(struct vdso_data, wtom_clock_sec));
DEFINE(WTOM_CLOCK_NSEC, offsetof(struct vdso_data, wtom_clock_nsec));
DEFINE(STAMP_XTIME, offsetof(struct vdso_data, stamp_xtime));
+ DEFINE(STAMP_SEC_FRAC, offsetof(struct vdso_data, stamp_sec_fraction));
DEFINE(CFG_ICACHE_BLOCKSZ, offsetof(struct vdso_data, icache_block_size));
DEFINE(CFG_DCACHE_BLOCKSZ, offsetof(struct vdso_data, dcache_block_size));
DEFINE(CFG_ICACHE_LOGBLOCKSZ, offsetof(struct vdso_data, icache_log_block_size));
diff --git a/arch/powerpc/kernel/cputable.c b/arch/powerpc/kernel/cputable.c
index 87aa0f3c604..65e2b4e10f9 100644
--- a/arch/powerpc/kernel/cputable.c
+++ b/arch/powerpc/kernel/cputable.c
@@ -1364,10 +1364,10 @@ static struct cpu_spec __initdata cpu_specs[] = {
.machine_check = machine_check_4xx,
.platform = "ppc405",
},
- { /* 405EX */
- .pvr_mask = 0xffff0004,
- .pvr_value = 0x12910004,
- .cpu_name = "405EX",
+ { /* 405EX Rev. A/B with Security */
+ .pvr_mask = 0xffff000f,
+ .pvr_value = 0x12910007,
+ .cpu_name = "405EX Rev. A/B",
.cpu_features = CPU_FTRS_40X,
.cpu_user_features = PPC_FEATURE_32 |
PPC_FEATURE_HAS_MMU | PPC_FEATURE_HAS_4xxMAC,
@@ -1377,10 +1377,114 @@ static struct cpu_spec __initdata cpu_specs[] = {
.machine_check = machine_check_4xx,
.platform = "ppc405",
},
- { /* 405EXr */
- .pvr_mask = 0xffff0004,
+ { /* 405EX Rev. C without Security */
+ .pvr_mask = 0xffff000f,
+ .pvr_value = 0x1291000d,
+ .cpu_name = "405EX Rev. C",
+ .cpu_features = CPU_FTRS_40X,
+ .cpu_user_features = PPC_FEATURE_32 |
+ PPC_FEATURE_HAS_MMU | PPC_FEATURE_HAS_4xxMAC,
+ .mmu_features = MMU_FTR_TYPE_40x,
+ .icache_bsize = 32,
+ .dcache_bsize = 32,
+ .machine_check = machine_check_4xx,
+ .platform = "ppc405",
+ },
+ { /* 405EX Rev. C with Security */
+ .pvr_mask = 0xffff000f,
+ .pvr_value = 0x1291000f,
+ .cpu_name = "405EX Rev. C",
+ .cpu_features = CPU_FTRS_40X,
+ .cpu_user_features = PPC_FEATURE_32 |
+ PPC_FEATURE_HAS_MMU | PPC_FEATURE_HAS_4xxMAC,
+ .mmu_features = MMU_FTR_TYPE_40x,
+ .icache_bsize = 32,
+ .dcache_bsize = 32,
+ .machine_check = machine_check_4xx,
+ .platform = "ppc405",
+ },
+ { /* 405EX Rev. D without Security */
+ .pvr_mask = 0xffff000f,
+ .pvr_value = 0x12910003,
+ .cpu_name = "405EX Rev. D",
+ .cpu_features = CPU_FTRS_40X,
+ .cpu_user_features = PPC_FEATURE_32 |
+ PPC_FEATURE_HAS_MMU | PPC_FEATURE_HAS_4xxMAC,
+ .mmu_features = MMU_FTR_TYPE_40x,
+ .icache_bsize = 32,
+ .dcache_bsize = 32,
+ .machine_check = machine_check_4xx,
+ .platform = "ppc405",
+ },
+ { /* 405EX Rev. D with Security */
+ .pvr_mask = 0xffff000f,
+ .pvr_value = 0x12910005,
+ .cpu_name = "405EX Rev. D",
+ .cpu_features = CPU_FTRS_40X,
+ .cpu_user_features = PPC_FEATURE_32 |
+ PPC_FEATURE_HAS_MMU | PPC_FEATURE_HAS_4xxMAC,
+ .mmu_features = MMU_FTR_TYPE_40x,
+ .icache_bsize = 32,
+ .dcache_bsize = 32,
+ .machine_check = machine_check_4xx,
+ .platform = "ppc405",
+ },
+ { /* 405EXr Rev. A/B without Security */
+ .pvr_mask = 0xffff000f,
+ .pvr_value = 0x12910001,
+ .cpu_name = "405EXr Rev. A/B",
+ .cpu_features = CPU_FTRS_40X,
+ .cpu_user_features = PPC_FEATURE_32 |
+ PPC_FEATURE_HAS_MMU | PPC_FEATURE_HAS_4xxMAC,
+ .mmu_features = MMU_FTR_TYPE_40x,
+ .icache_bsize = 32,
+ .dcache_bsize = 32,
+ .machine_check = machine_check_4xx,
+ .platform = "ppc405",
+ },
+ { /* 405EXr Rev. C without Security */
+ .pvr_mask = 0xffff000f,
+ .pvr_value = 0x12910009,
+ .cpu_name = "405EXr Rev. C",
+ .cpu_features = CPU_FTRS_40X,
+ .cpu_user_features = PPC_FEATURE_32 |
+ PPC_FEATURE_HAS_MMU | PPC_FEATURE_HAS_4xxMAC,
+ .mmu_features = MMU_FTR_TYPE_40x,
+ .icache_bsize = 32,
+ .dcache_bsize = 32,
+ .machine_check = machine_check_4xx,
+ .platform = "ppc405",
+ },
+ { /* 405EXr Rev. C with Security */
+ .pvr_mask = 0xffff000f,
+ .pvr_value = 0x1291000b,
+ .cpu_name = "405EXr Rev. C",
+ .cpu_features = CPU_FTRS_40X,
+ .cpu_user_features = PPC_FEATURE_32 |
+ PPC_FEATURE_HAS_MMU | PPC_FEATURE_HAS_4xxMAC,
+ .mmu_features = MMU_FTR_TYPE_40x,
+ .icache_bsize = 32,
+ .dcache_bsize = 32,
+ .machine_check = machine_check_4xx,
+ .platform = "ppc405",
+ },
+ { /* 405EXr Rev. D without Security */
+ .pvr_mask = 0xffff000f,
.pvr_value = 0x12910000,
- .cpu_name = "405EXr",
+ .cpu_name = "405EXr Rev. D",
+ .cpu_features = CPU_FTRS_40X,
+ .cpu_user_features = PPC_FEATURE_32 |
+ PPC_FEATURE_HAS_MMU | PPC_FEATURE_HAS_4xxMAC,
+ .mmu_features = MMU_FTR_TYPE_40x,
+ .icache_bsize = 32,
+ .dcache_bsize = 32,
+ .machine_check = machine_check_4xx,
+ .platform = "ppc405",
+ },
+ { /* 405EXr Rev. D with Security */
+ .pvr_mask = 0xffff000f,
+ .pvr_value = 0x12910002,
+ .cpu_name = "405EXr Rev. D",
.cpu_features = CPU_FTRS_40X,
.cpu_user_features = PPC_FEATURE_32 |
PPC_FEATURE_HAS_MMU | PPC_FEATURE_HAS_4xxMAC,
diff --git a/arch/powerpc/kernel/crash_dump.c b/arch/powerpc/kernel/crash_dump.c
index 40f524643ba..8e05c16344e 100644
--- a/arch/powerpc/kernel/crash_dump.c
+++ b/arch/powerpc/kernel/crash_dump.c
@@ -128,9 +128,9 @@ ssize_t copy_oldmem_page(unsigned long pfn, char *buf,
if (!csize)
return 0;
- csize = min(csize, PAGE_SIZE);
+ csize = min_t(size_t, csize, PAGE_SIZE);
- if (pfn < max_pfn) {
+ if ((min_low_pfn < pfn) && (pfn < max_pfn)) {
vaddr = __va(pfn << PAGE_SHIFT);
csize = copy_oldmem_vaddr(vaddr, buf, csize, offset, userbuf);
} else {
diff --git a/arch/powerpc/kernel/dbell.c b/arch/powerpc/kernel/dbell.c
index 1493734cd87..3307a52d797 100644
--- a/arch/powerpc/kernel/dbell.c
+++ b/arch/powerpc/kernel/dbell.c
@@ -13,32 +13,88 @@
#include <linux/kernel.h>
#include <linux/smp.h>
#include <linux/threads.h>
+#include <linux/percpu.h>
#include <asm/dbell.h>
+#include <asm/irq_regs.h>
#ifdef CONFIG_SMP
-unsigned long dbell_smp_message[NR_CPUS];
+struct doorbell_cpu_info {
+ unsigned long messages; /* current messages bits */
+ unsigned int tag; /* tag value */
+};
-void smp_dbell_message_pass(int target, int msg)
+static DEFINE_PER_CPU(struct doorbell_cpu_info, doorbell_cpu_info);
+
+void doorbell_setup_this_cpu(void)
+{
+ struct doorbell_cpu_info *info = &__get_cpu_var(doorbell_cpu_info);
+
+ info->messages = 0;
+ info->tag = mfspr(SPRN_PIR) & 0x3fff;
+}
+
+void doorbell_message_pass(int target, int msg)
{
+ struct doorbell_cpu_info *info;
int i;
- if(target < NR_CPUS) {
- set_bit(msg, &dbell_smp_message[target]);
- ppc_msgsnd(PPC_DBELL, 0, target);
+ if (target < NR_CPUS) {
+ info = &per_cpu(doorbell_cpu_info, target);
+ set_bit(msg, &info->messages);
+ ppc_msgsnd(PPC_DBELL, 0, info->tag);
}
- else if(target == MSG_ALL_BUT_SELF) {
+ else if (target == MSG_ALL_BUT_SELF) {
for_each_online_cpu(i) {
if (i == smp_processor_id())
continue;
- set_bit(msg, &dbell_smp_message[i]);
- ppc_msgsnd(PPC_DBELL, 0, i);
+ info = &per_cpu(doorbell_cpu_info, i);
+ set_bit(msg, &info->messages);
+ ppc_msgsnd(PPC_DBELL, 0, info->tag);
}
}
else { /* target == MSG_ALL */
- for_each_online_cpu(i)
- set_bit(msg, &dbell_smp_message[i]);
+ for_each_online_cpu(i) {
+ info = &per_cpu(doorbell_cpu_info, i);
+ set_bit(msg, &info->messages);
+ }
ppc_msgsnd(PPC_DBELL, PPC_DBELL_MSG_BRDCAST, 0);
}
}
-#endif
+
+void doorbell_exception(struct pt_regs *regs)
+{
+ struct pt_regs *old_regs = set_irq_regs(regs);
+ struct doorbell_cpu_info *info = &__get_cpu_var(doorbell_cpu_info);
+ int msg;
+
+ /* Warning: regs can be NULL when called from irq enable */
+
+ if (!info->messages || (num_online_cpus() < 2))
+ goto out;
+
+ for (msg = 0; msg < 4; msg++)
+ if (test_and_clear_bit(msg, &info->messages))
+ smp_message_recv(msg);
+
+out:
+ set_irq_regs(old_regs);
+}
+
+void doorbell_check_self(void)
+{
+ struct doorbell_cpu_info *info = &__get_cpu_var(doorbell_cpu_info);
+
+ if (!info->messages)
+ return;
+
+ ppc_msgsnd(PPC_DBELL, 0, info->tag);
+}
+
+#else /* CONFIG_SMP */
+void doorbell_exception(struct pt_regs *regs)
+{
+ printk(KERN_WARNING "Received doorbell on non-smp system\n");
+}
+#endif /* CONFIG_SMP */
+
diff --git a/arch/powerpc/kernel/dma-swiotlb.c b/arch/powerpc/kernel/dma-swiotlb.c
index 02f724f3675..4295e0b94b2 100644
--- a/arch/powerpc/kernel/dma-swiotlb.c
+++ b/arch/powerpc/kernel/dma-swiotlb.c
@@ -82,17 +82,9 @@ static struct notifier_block ppc_swiotlb_plat_bus_notifier = {
.priority = 0,
};
-static struct notifier_block ppc_swiotlb_of_bus_notifier = {
- .notifier_call = ppc_swiotlb_bus_notify,
- .priority = 0,
-};
-
int __init swiotlb_setup_bus_notifier(void)
{
bus_register_notifier(&platform_bus_type,
&ppc_swiotlb_plat_bus_notifier);
- bus_register_notifier(&of_platform_bus_type,
- &ppc_swiotlb_of_bus_notifier);
-
return 0;
}
diff --git a/arch/powerpc/kernel/exceptions-64e.S b/arch/powerpc/kernel/exceptions-64e.S
index 24dcc0ecf24..5c43063d250 100644
--- a/arch/powerpc/kernel/exceptions-64e.S
+++ b/arch/powerpc/kernel/exceptions-64e.S
@@ -191,6 +191,12 @@ exc_##n##_bad_stack: \
sth r1,PACA_TRAP_SAVE(r13); /* store trap */ \
b bad_stack_book3e; /* bad stack error */
+/* WARNING: If you change the layout of this stub, make sure you chcek
+ * the debug exception handler which handles single stepping
+ * into exceptions from userspace, and the MM code in
+ * arch/powerpc/mm/tlb_nohash.c which patches the branch here
+ * and would need to be updated if that branch is moved
+ */
#define EXCEPTION_STUB(loc, label) \
. = interrupt_base_book3e + loc; \
nop; /* To make debug interrupts happy */ \
@@ -204,11 +210,30 @@ exc_##n##_bad_stack: \
lis r,TSR_FIS@h; \
mtspr SPRN_TSR,r
+/* Used by asynchronous interrupt that may happen in the idle loop.
+ *
+ * This check if the thread was in the idle loop, and if yes, returns
+ * to the caller rather than the PC. This is to avoid a race if
+ * interrupts happen before the wait instruction.
+ */
+#define CHECK_NAPPING() \
+ clrrdi r11,r1,THREAD_SHIFT; \
+ ld r10,TI_LOCAL_FLAGS(r11); \
+ andi. r9,r10,_TLF_NAPPING; \
+ beq+ 1f; \
+ ld r8,_LINK(r1); \
+ rlwinm r7,r10,0,~_TLF_NAPPING; \
+ std r8,_NIP(r1); \
+ std r7,TI_LOCAL_FLAGS(r11); \
+1:
+
+
#define MASKABLE_EXCEPTION(trapnum, label, hdlr, ack) \
START_EXCEPTION(label); \
NORMAL_EXCEPTION_PROLOG(trapnum, PROLOG_ADDITION_MASKABLE) \
EXCEPTION_COMMON(trapnum, PACA_EXGEN, INTS_DISABLE_ALL) \
ack(r8); \
+ CHECK_NAPPING(); \
addi r3,r1,STACK_FRAME_OVERHEAD; \
bl hdlr; \
b .ret_from_except_lite;
@@ -246,11 +271,9 @@ interrupt_base_book3e: /* fake trap */
EXCEPTION_STUB(0x1a0, watchdog) /* 0x09f0 */
EXCEPTION_STUB(0x1c0, data_tlb_miss)
EXCEPTION_STUB(0x1e0, instruction_tlb_miss)
+ EXCEPTION_STUB(0x280, doorbell)
+ EXCEPTION_STUB(0x2a0, doorbell_crit)
-#if 0
- EXCEPTION_STUB(0x280, processor_doorbell)
- EXCEPTION_STUB(0x220, processor_doorbell_crit)
-#endif
.globl interrupt_end_book3e
interrupt_end_book3e:
@@ -259,6 +282,7 @@ interrupt_end_book3e:
CRIT_EXCEPTION_PROLOG(0x100, PROLOG_ADDITION_NONE)
// EXCEPTION_COMMON(0x100, PACA_EXCRIT, INTS_DISABLE_ALL)
// bl special_reg_save_crit
+// CHECK_NAPPING();
// addi r3,r1,STACK_FRAME_OVERHEAD
// bl .critical_exception
// b ret_from_crit_except
@@ -270,6 +294,7 @@ interrupt_end_book3e:
// EXCEPTION_COMMON(0x200, PACA_EXMC, INTS_DISABLE_ALL)
// bl special_reg_save_mc
// addi r3,r1,STACK_FRAME_OVERHEAD
+// CHECK_NAPPING();
// bl .machine_check_exception
// b ret_from_mc_except
b .
@@ -340,6 +365,7 @@ interrupt_end_book3e:
CRIT_EXCEPTION_PROLOG(0x9f0, PROLOG_ADDITION_NONE)
// EXCEPTION_COMMON(0x9f0, PACA_EXCRIT, INTS_DISABLE_ALL)
// bl special_reg_save_crit
+// CHECK_NAPPING();
// addi r3,r1,STACK_FRAME_OVERHEAD
// bl .unknown_exception
// b ret_from_crit_except
@@ -428,6 +454,20 @@ interrupt_end_book3e:
kernel_dbg_exc:
b . /* NYI */
+/* Doorbell interrupt */
+ MASKABLE_EXCEPTION(0x2070, doorbell, .doorbell_exception, ACK_NONE)
+
+/* Doorbell critical Interrupt */
+ START_EXCEPTION(doorbell_crit);
+ CRIT_EXCEPTION_PROLOG(0x2080, PROLOG_ADDITION_NONE)
+// EXCEPTION_COMMON(0x2080, PACA_EXCRIT, INTS_DISABLE_ALL)
+// bl special_reg_save_crit
+// CHECK_NAPPING();
+// addi r3,r1,STACK_FRAME_OVERHEAD
+// bl .doorbell_critical_exception
+// b ret_from_crit_except
+ b .
+
/*
* An interrupt came in while soft-disabled; clear EE in SRR1,
@@ -563,6 +603,8 @@ BAD_STACK_TRAMPOLINE(0xd00)
BAD_STACK_TRAMPOLINE(0xe00)
BAD_STACK_TRAMPOLINE(0xf00)
BAD_STACK_TRAMPOLINE(0xf20)
+BAD_STACK_TRAMPOLINE(0x2070)
+BAD_STACK_TRAMPOLINE(0x2080)
.globl bad_stack_book3e
bad_stack_book3e:
diff --git a/arch/powerpc/kernel/exceptions-64s.S b/arch/powerpc/kernel/exceptions-64s.S
index 3e423fbad6b..f53029a0155 100644
--- a/arch/powerpc/kernel/exceptions-64s.S
+++ b/arch/powerpc/kernel/exceptions-64s.S
@@ -828,6 +828,7 @@ END_FW_FTR_SECTION_IFCLR(FW_FEATURE_ISERIES)
/* We have a data breakpoint exception - handle it */
handle_dabr_fault:
+ bl .save_nvgprs
ld r4,_DAR(r1)
ld r5,_DSISR(r1)
addi r3,r1,STACK_FRAME_OVERHEAD
diff --git a/arch/powerpc/kernel/hw_breakpoint.c b/arch/powerpc/kernel/hw_breakpoint.c
new file mode 100644
index 00000000000..5ecd0401cdb
--- /dev/null
+++ b/arch/powerpc/kernel/hw_breakpoint.c
@@ -0,0 +1,364 @@
+/*
+ * HW_breakpoint: a unified kernel/user-space hardware breakpoint facility,
+ * using the CPU's debug registers. Derived from
+ * "arch/x86/kernel/hw_breakpoint.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.
+ *
+ * Copyright 2010 IBM Corporation
+ * Author: K.Prasad <prasad@linux.vnet.ibm.com>
+ *
+ */
+
+#include <linux/hw_breakpoint.h>
+#include <linux/notifier.h>
+#include <linux/kprobes.h>
+#include <linux/percpu.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/smp.h>
+
+#include <asm/hw_breakpoint.h>
+#include <asm/processor.h>
+#include <asm/sstep.h>
+#include <asm/uaccess.h>
+
+/*
+ * Stores the breakpoints currently in use on each breakpoint address
+ * register for every cpu
+ */
+static DEFINE_PER_CPU(struct perf_event *, bp_per_reg);
+
+/*
+ * Returns total number of data or instruction breakpoints available.
+ */
+int hw_breakpoint_slots(int type)
+{
+ if (type == TYPE_DATA)
+ return HBP_NUM;
+ return 0; /* no instruction breakpoints available */
+}
+
+/*
+ * Install a perf counter breakpoint.
+ *
+ * We seek a free debug address register and use it for this
+ * breakpoint.
+ *
+ * Atomic: we hold the counter->ctx->lock and we only handle variables
+ * and registers local to this cpu.
+ */
+int arch_install_hw_breakpoint(struct perf_event *bp)
+{
+ struct arch_hw_breakpoint *info = counter_arch_bp(bp);
+ struct perf_event **slot = &__get_cpu_var(bp_per_reg);
+
+ *slot = bp;
+
+ /*
+ * Do not install DABR values if the instruction must be single-stepped.
+ * If so, DABR will be populated in single_step_dabr_instruction().
+ */
+ if (current->thread.last_hit_ubp != bp)
+ set_dabr(info->address | info->type | DABR_TRANSLATION);
+
+ return 0;
+}
+
+/*
+ * Uninstall the breakpoint contained in the given counter.
+ *
+ * First we search the debug address register it uses and then we disable
+ * it.
+ *
+ * Atomic: we hold the counter->ctx->lock and we only handle variables
+ * and registers local to this cpu.
+ */
+void arch_uninstall_hw_breakpoint(struct perf_event *bp)
+{
+ struct perf_event **slot = &__get_cpu_var(bp_per_reg);
+
+ if (*slot != bp) {
+ WARN_ONCE(1, "Can't find the breakpoint");
+ return;
+ }
+
+ *slot = NULL;
+ set_dabr(0);
+}
+
+/*
+ * Perform cleanup of arch-specific counters during unregistration
+ * of the perf-event
+ */
+void arch_unregister_hw_breakpoint(struct perf_event *bp)
+{
+ /*
+ * If the breakpoint is unregistered between a hw_breakpoint_handler()
+ * and the single_step_dabr_instruction(), then cleanup the breakpoint
+ * restoration variables to prevent dangling pointers.
+ */
+ if (bp->ctx->task)
+ bp->ctx->task->thread.last_hit_ubp = NULL;
+}
+
+/*
+ * Check for virtual address in kernel space.
+ */
+int arch_check_bp_in_kernelspace(struct perf_event *bp)
+{
+ struct arch_hw_breakpoint *info = counter_arch_bp(bp);
+
+ return is_kernel_addr(info->address);
+}
+
+int arch_bp_generic_fields(int type, int *gen_bp_type)
+{
+ switch (type) {
+ case DABR_DATA_READ:
+ *gen_bp_type = HW_BREAKPOINT_R;
+ break;
+ case DABR_DATA_WRITE:
+ *gen_bp_type = HW_BREAKPOINT_W;
+ break;
+ case (DABR_DATA_WRITE | DABR_DATA_READ):
+ *gen_bp_type = (HW_BREAKPOINT_W | HW_BREAKPOINT_R);
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+/*
+ * Validate the arch-specific HW Breakpoint register settings
+ */
+int arch_validate_hwbkpt_settings(struct perf_event *bp)
+{
+ int ret = -EINVAL;
+ struct arch_hw_breakpoint *info = counter_arch_bp(bp);
+
+ if (!bp)
+ return ret;
+
+ switch (bp->attr.bp_type) {
+ case HW_BREAKPOINT_R:
+ info->type = DABR_DATA_READ;
+ break;
+ case HW_BREAKPOINT_W:
+ info->type = DABR_DATA_WRITE;
+ break;
+ case HW_BREAKPOINT_R | HW_BREAKPOINT_W:
+ info->type = (DABR_DATA_READ | DABR_DATA_WRITE);
+ break;
+ default:
+ return ret;
+ }
+
+ info->address = bp->attr.bp_addr;
+ info->len = bp->attr.bp_len;
+
+ /*
+ * Since breakpoint length can be a maximum of HW_BREAKPOINT_LEN(8)
+ * and breakpoint addresses are aligned to nearest double-word
+ * HW_BREAKPOINT_ALIGN by rounding off to the lower address, the
+ * 'symbolsize' should satisfy the check below.
+ */
+ if (info->len >
+ (HW_BREAKPOINT_LEN - (info->address & HW_BREAKPOINT_ALIGN)))
+ return -EINVAL;
+ return 0;
+}
+
+/*
+ * Restores the breakpoint on the debug registers.
+ * Invoke this function if it is known that the execution context is
+ * about to change to cause loss of MSR_SE settings.
+ */
+void thread_change_pc(struct task_struct *tsk, struct pt_regs *regs)
+{
+ struct arch_hw_breakpoint *info;
+
+ if (likely(!tsk->thread.last_hit_ubp))
+ return;
+
+ info = counter_arch_bp(tsk->thread.last_hit_ubp);
+ regs->msr &= ~MSR_SE;
+ set_dabr(info->address | info->type | DABR_TRANSLATION);
+ tsk->thread.last_hit_ubp = NULL;
+}
+
+/*
+ * Handle debug exception notifications.
+ */
+int __kprobes hw_breakpoint_handler(struct die_args *args)
+{
+ int rc = NOTIFY_STOP;
+ struct perf_event *bp;
+ struct pt_regs *regs = args->regs;
+ int stepped = 1;
+ struct arch_hw_breakpoint *info;
+ unsigned int instr;
+ unsigned long dar = regs->dar;
+
+ /* Disable breakpoints during exception handling */
+ set_dabr(0);
+
+ /*
+ * The counter may be concurrently released but that can only
+ * occur from a call_rcu() path. We can then safely fetch
+ * the breakpoint, use its callback, touch its counter
+ * while we are in an rcu_read_lock() path.
+ */
+ rcu_read_lock();
+
+ bp = __get_cpu_var(bp_per_reg);
+ if (!bp)
+ goto out;
+ info = counter_arch_bp(bp);
+
+ /*
+ * Return early after invoking user-callback function without restoring
+ * DABR if the breakpoint is from ptrace which always operates in
+ * one-shot mode. The ptrace-ed process will receive the SIGTRAP signal
+ * generated in do_dabr().
+ */
+ if (bp->overflow_handler == ptrace_triggered) {
+ perf_bp_event(bp, regs);
+ rc = NOTIFY_DONE;
+ goto out;
+ }
+
+ /*
+ * Verify if dar lies within the address range occupied by the symbol
+ * being watched to filter extraneous exceptions. If it doesn't,
+ * we still need to single-step the instruction, but we don't
+ * generate an event.
+ */
+ info->extraneous_interrupt = !((bp->attr.bp_addr <= dar) &&
+ (dar - bp->attr.bp_addr < bp->attr.bp_len));
+
+ /* Do not emulate user-space instructions, instead single-step them */
+ if (user_mode(regs)) {
+ bp->ctx->task->thread.last_hit_ubp = bp;
+ regs->msr |= MSR_SE;
+ goto out;
+ }
+
+ stepped = 0;
+ instr = 0;
+ if (!__get_user_inatomic(instr, (unsigned int *) regs->nip))
+ stepped = emulate_step(regs, instr);
+
+ /*
+ * emulate_step() could not execute it. We've failed in reliably
+ * handling the hw-breakpoint. Unregister it and throw a warning
+ * message to let the user know about it.
+ */
+ if (!stepped) {
+ WARN(1, "Unable to handle hardware breakpoint. Breakpoint at "
+ "0x%lx will be disabled.", info->address);
+ perf_event_disable(bp);
+ goto out;
+ }
+ /*
+ * As a policy, the callback is invoked in a 'trigger-after-execute'
+ * fashion
+ */
+ if (!info->extraneous_interrupt)
+ perf_bp_event(bp, regs);
+
+ set_dabr(info->address | info->type | DABR_TRANSLATION);
+out:
+ rcu_read_unlock();
+ return rc;
+}
+
+/*
+ * Handle single-step exceptions following a DABR hit.
+ */
+int __kprobes single_step_dabr_instruction(struct die_args *args)
+{
+ struct pt_regs *regs = args->regs;
+ struct perf_event *bp = NULL;
+ struct arch_hw_breakpoint *bp_info;
+
+ bp = current->thread.last_hit_ubp;
+ /*
+ * Check if we are single-stepping as a result of a
+ * previous HW Breakpoint exception
+ */
+ if (!bp)
+ return NOTIFY_DONE;
+
+ bp_info = counter_arch_bp(bp);
+
+ /*
+ * We shall invoke the user-defined callback function in the single
+ * stepping handler to confirm to 'trigger-after-execute' semantics
+ */
+ if (!bp_info->extraneous_interrupt)
+ perf_bp_event(bp, regs);
+
+ set_dabr(bp_info->address | bp_info->type | DABR_TRANSLATION);
+ current->thread.last_hit_ubp = NULL;
+
+ /*
+ * If the process was being single-stepped by ptrace, let the
+ * other single-step actions occur (e.g. generate SIGTRAP).
+ */
+ if (test_thread_flag(TIF_SINGLESTEP))
+ return NOTIFY_DONE;
+
+ return NOTIFY_STOP;
+}
+
+/*
+ * Handle debug exception notifications.
+ */
+int __kprobes hw_breakpoint_exceptions_notify(
+ struct notifier_block *unused, unsigned long val, void *data)
+{
+ int ret = NOTIFY_DONE;
+
+ switch (val) {
+ case DIE_DABR_MATCH:
+ ret = hw_breakpoint_handler(data);
+ break;
+ case DIE_SSTEP:
+ ret = single_step_dabr_instruction(data);
+ break;
+ }
+
+ return ret;
+}
+
+/*
+ * Release the user breakpoints used by ptrace
+ */
+void flush_ptrace_hw_breakpoint(struct task_struct *tsk)
+{
+ struct thread_struct *t = &tsk->thread;
+
+ unregister_hw_breakpoint(t->ptrace_bps[0]);
+ t->ptrace_bps[0] = NULL;
+}
+
+void hw_breakpoint_pmu_read(struct perf_event *bp)
+{
+ /* TODO */
+}
diff --git a/arch/powerpc/kernel/ibmebus.c b/arch/powerpc/kernel/ibmebus.c
index 21266abfbda..9b626cfffce 100644
--- a/arch/powerpc/kernel/ibmebus.c
+++ b/arch/powerpc/kernel/ibmebus.c
@@ -140,19 +140,19 @@ static struct dma_map_ops ibmebus_dma_ops = {
static int ibmebus_match_path(struct device *dev, void *data)
{
- struct device_node *dn = to_of_device(dev)->dev.of_node;
+ struct device_node *dn = to_platform_device(dev)->dev.of_node;
return (dn->full_name &&
(strcasecmp((char *)data, dn->full_name) == 0));
}
static int ibmebus_match_node(struct device *dev, void *data)
{
- return to_of_device(dev)->dev.of_node == data;
+ return to_platform_device(dev)->dev.of_node == data;
}
static int ibmebus_create_device(struct device_node *dn)
{
- struct of_device *dev;
+ struct platform_device *dev;
int ret;
dev = of_device_alloc(dn, NULL, &ibmebus_bus_device);
@@ -298,7 +298,7 @@ static ssize_t ibmebus_store_remove(struct bus_type *bus,
if ((dev = bus_find_device(&ibmebus_bus_type, NULL, path,
ibmebus_match_path))) {
- of_device_unregister(to_of_device(dev));
+ of_device_unregister(to_platform_device(dev));
kfree(path);
return count;
diff --git a/arch/powerpc/kernel/idle_book3e.S b/arch/powerpc/kernel/idle_book3e.S
new file mode 100644
index 00000000000..16c002d6bdf
--- /dev/null
+++ b/arch/powerpc/kernel/idle_book3e.S
@@ -0,0 +1,86 @@
+/*
+ * Copyright 2010 IBM Corp, Benjamin Herrenschmidt <benh@kernel.crashing.org>
+ *
+ * Generic idle routine for Book3E processors
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify 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/threads.h>
+#include <asm/reg.h>
+#include <asm/ppc_asm.h>
+#include <asm/asm-offsets.h>
+#include <asm/ppc-opcode.h>
+#include <asm/processor.h>
+#include <asm/thread_info.h>
+
+/* 64-bit version only for now */
+#ifdef CONFIG_PPC64
+
+_GLOBAL(book3e_idle)
+ /* Save LR for later */
+ mflr r0
+ std r0,16(r1)
+
+ /* Hard disable interrupts */
+ wrteei 0
+
+ /* Now check if an interrupt came in while we were soft disabled
+ * since we may otherwise lose it (doorbells etc...). We know
+ * that since PACAHARDIRQEN will have been cleared in that case.
+ */
+ lbz r3,PACAHARDIRQEN(r13)
+ cmpwi cr0,r3,0
+ beqlr
+
+ /* Now we are going to mark ourselves as soft and hard enables in
+ * order to be able to take interrupts while asleep. We inform lockdep
+ * of that. We don't actually turn interrupts on just yet tho.
+ */
+#ifdef CONFIG_TRACE_IRQFLAGS
+ stdu r1,-128(r1)
+ bl .trace_hardirqs_on
+#endif
+ li r0,1
+ stb r0,PACASOFTIRQEN(r13)
+ stb r0,PACAHARDIRQEN(r13)
+
+ /* Interrupts will make use return to LR, so get something we want
+ * in there
+ */
+ bl 1f
+
+ /* Hard disable interrupts again */
+ wrteei 0
+
+ /* Mark them off again in the PACA as well */
+ li r0,0
+ stb r0,PACASOFTIRQEN(r13)
+ stb r0,PACAHARDIRQEN(r13)
+
+ /* Tell lockdep about it */
+#ifdef CONFIG_TRACE_IRQFLAGS
+ bl .trace_hardirqs_off
+ addi r1,r1,128
+#endif
+ ld r0,16(r1)
+ mtlr r0
+ blr
+
+1: /* Let's set the _TLF_NAPPING flag so interrupts make us return
+ * to the right spot
+ */
+ clrrdi r11,r1,THREAD_SHIFT
+ ld r10,TI_LOCAL_FLAGS(r11)
+ ori r10,r10,_TLF_NAPPING
+ std r10,TI_LOCAL_FLAGS(r11)
+
+ /* We can now re-enable hard interrupts and go to sleep */
+ wrteei 1
+1: PPC_WAIT(0)
+ b 1b
+
+#endif /* CONFIG_PPC64 */
diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c
index 77be3d058a6..d3ce67cf03b 100644
--- a/arch/powerpc/kernel/irq.c
+++ b/arch/powerpc/kernel/irq.c
@@ -53,6 +53,8 @@
#include <linux/bootmem.h>
#include <linux/pci.h>
#include <linux/debugfs.h>
+#include <linux/of.h>
+#include <linux/of_irq.h>
#include <asm/uaccess.h>
#include <asm/system.h>
@@ -64,6 +66,8 @@
#include <asm/ptrace.h>
#include <asm/machdep.h>
#include <asm/udbg.h>
+#include <asm/dbell.h>
+
#ifdef CONFIG_PPC64
#include <asm/paca.h>
#include <asm/firmware.h>
@@ -153,14 +157,28 @@ notrace void raw_local_irq_restore(unsigned long en)
if (get_hard_enabled())
return;
+#if defined(CONFIG_BOOKE) && defined(CONFIG_SMP)
+ /* Check for pending doorbell interrupts and resend to ourself */
+ doorbell_check_self();
+#endif
+
/*
* Need to hard-enable interrupts here. Since currently disabled,
* no need to take further asm precautions against preemption; but
* use local_paca instead of get_paca() to avoid preemption checking.
*/
local_paca->hard_enabled = en;
+
+#ifndef CONFIG_BOOKE
+ /* On server, re-trigger the decrementer if it went negative since
+ * some processors only trigger on edge transitions of the sign bit.
+ *
+ * BookE has a level sensitive decrementer (latches in TSR) so we
+ * don't need that
+ */
if ((int)mfspr(SPRN_DEC) < 0)
mtspr(SPRN_DEC, 1);
+#endif /* CONFIG_BOOKE */
/*
* Force the delivery of pending soft-disabled interrupts on PS3.
@@ -804,18 +822,6 @@ unsigned int irq_create_of_mapping(struct device_node *controller,
}
EXPORT_SYMBOL_GPL(irq_create_of_mapping);
-unsigned int irq_of_parse_and_map(struct device_node *dev, int index)
-{
- struct of_irq oirq;
-
- if (of_irq_map_one(dev, index, &oirq))
- return NO_IRQ;
-
- return irq_create_of_mapping(oirq.controller, oirq.specifier,
- oirq.size);
-}
-EXPORT_SYMBOL_GPL(irq_of_parse_and_map);
-
void irq_dispose_mapping(unsigned int virq)
{
struct irq_host *host;
diff --git a/arch/powerpc/kernel/kgdb.c b/arch/powerpc/kernel/kgdb.c
index 82a7b228c81..7f61a3ac787 100644
--- a/arch/powerpc/kernel/kgdb.c
+++ b/arch/powerpc/kernel/kgdb.c
@@ -129,7 +129,7 @@ static int kgdb_handle_breakpoint(struct pt_regs *regs)
return 0;
if (*(u32 *) (regs->nip) == *(u32 *) (&arch_kgdb_ops.gdb_bpt_instr))
- regs->nip += 4;
+ regs->nip += BREAK_INSTR_SIZE;
return 1;
}
diff --git a/arch/powerpc/kernel/legacy_serial.c b/arch/powerpc/kernel/legacy_serial.c
index 035ada5443e..c1fd0f9658f 100644
--- a/arch/powerpc/kernel/legacy_serial.c
+++ b/arch/powerpc/kernel/legacy_serial.c
@@ -4,6 +4,7 @@
#include <linux/serial_core.h>
#include <linux/console.h>
#include <linux/pci.h>
+#include <linux/of_address.h>
#include <linux/of_device.h>
#include <asm/io.h>
#include <asm/mmu.h>
diff --git a/arch/powerpc/kernel/machine_kexec.c b/arch/powerpc/kernel/machine_kexec.c
index 89f005116aa..dd6c141f166 100644
--- a/arch/powerpc/kernel/machine_kexec.c
+++ b/arch/powerpc/kernel/machine_kexec.c
@@ -45,6 +45,18 @@ void machine_kexec_cleanup(struct kimage *image)
ppc_md.machine_kexec_cleanup(image);
}
+void arch_crash_save_vmcoreinfo(void)
+{
+
+#ifdef CONFIG_NEED_MULTIPLE_NODES
+ VMCOREINFO_SYMBOL(node_data);
+ VMCOREINFO_LENGTH(node_data, MAX_NUMNODES);
+#endif
+#ifndef CONFIG_NEED_MULTIPLE_NODES
+ VMCOREINFO_SYMBOL(contig_page_data);
+#endif
+}
+
/*
* Do not allocate memory (or fail in any way) in machine_kexec().
* We are past the point of no return, committed to rebooting now.
@@ -144,24 +156,24 @@ int overlaps_crashkernel(unsigned long start, unsigned long size)
}
/* Values we need to export to the second kernel via the device tree. */
-static unsigned long kernel_end;
-static unsigned long crashk_size;
+static phys_addr_t kernel_end;
+static phys_addr_t crashk_size;
static struct property kernel_end_prop = {
.name = "linux,kernel-end",
- .length = sizeof(unsigned long),
+ .length = sizeof(phys_addr_t),
.value = &kernel_end,
};
static struct property crashk_base_prop = {
.name = "linux,crashkernel-base",
- .length = sizeof(unsigned long),
+ .length = sizeof(phys_addr_t),
.value = &crashk_res.start,
};
static struct property crashk_size_prop = {
.name = "linux,crashkernel-size",
- .length = sizeof(unsigned long),
+ .length = sizeof(phys_addr_t),
.value = &crashk_size,
};
diff --git a/arch/powerpc/kernel/machine_kexec_64.c b/arch/powerpc/kernel/machine_kexec_64.c
index ed31a29c4ff..583af70c4b1 100644
--- a/arch/powerpc/kernel/machine_kexec_64.c
+++ b/arch/powerpc/kernel/machine_kexec_64.c
@@ -15,6 +15,8 @@
#include <linux/thread_info.h>
#include <linux/init_task.h>
#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/cpu.h>
#include <asm/page.h>
#include <asm/current.h>
@@ -25,6 +27,7 @@
#include <asm/sections.h> /* _end */
#include <asm/prom.h>
#include <asm/smp.h>
+#include <asm/hw_breakpoint.h>
int default_machine_kexec_prepare(struct kimage *image)
{
@@ -165,6 +168,7 @@ static void kexec_smp_down(void *arg)
while(kexec_all_irq_disabled == 0)
cpu_relax();
mb(); /* make sure all irqs are disabled before this */
+ hw_breakpoint_disable();
/*
* Now every CPU has IRQs off, we can clear out any pending
* IPIs and be sure that no more will come in after this.
@@ -180,8 +184,22 @@ static void kexec_prepare_cpus_wait(int wait_state)
{
int my_cpu, i, notified=-1;
+ hw_breakpoint_disable();
my_cpu = get_cpu();
- /* Make sure each CPU has atleast made it to the state we need */
+ /* Make sure each CPU has at least made it to the state we need.
+ *
+ * FIXME: There is a (slim) chance of a problem if not all of the CPUs
+ * are correctly onlined. If somehow we start a CPU on boot with RTAS
+ * start-cpu, but somehow that CPU doesn't write callin_cpu_map[] in
+ * time, the boot CPU will timeout. If it does eventually execute
+ * stuff, the secondary will start up (paca[].cpu_start was written) and
+ * get into a peculiar state. If the platform supports
+ * smp_ops->take_timebase(), the secondary CPU will probably be spinning
+ * in there. If not (i.e. pseries), the secondary will continue on and
+ * try to online itself/idle/etc. If it survives that, we need to find
+ * these possible-but-not-online-but-should-be CPUs and chaperone them
+ * into kexec_smp_wait().
+ */
for_each_online_cpu(i) {
if (i == my_cpu)
continue;
@@ -189,9 +207,9 @@ static void kexec_prepare_cpus_wait(int wait_state)
while (paca[i].kexec_state < wait_state) {
barrier();
if (i != notified) {
- printk( "kexec: waiting for cpu %d (physical"
- " %d) to enter %i state\n",
- i, paca[i].hw_cpu_id, wait_state);
+ printk(KERN_INFO "kexec: waiting for cpu %d "
+ "(physical %d) to enter %i state\n",
+ i, paca[i].hw_cpu_id, wait_state);
notified = i;
}
}
@@ -199,9 +217,32 @@ static void kexec_prepare_cpus_wait(int wait_state)
mb();
}
-static void kexec_prepare_cpus(void)
+/*
+ * We need to make sure each present CPU is online. The next kernel will scan
+ * the device tree and assume primary threads are online and query secondary
+ * threads via RTAS to online them if required. If we don't online primary
+ * threads, they will be stuck. However, we also online secondary threads as we
+ * may be using 'cede offline'. In this case RTAS doesn't see the secondary
+ * threads as offline -- and again, these CPUs will be stuck.
+ *
+ * So, we online all CPUs that should be running, including secondary threads.
+ */
+static void wake_offline_cpus(void)
{
+ int cpu = 0;
+ for_each_present_cpu(cpu) {
+ if (!cpu_online(cpu)) {
+ printk(KERN_INFO "kexec: Waking offline cpu %d.\n",
+ cpu);
+ cpu_up(cpu);
+ }
+ }
+}
+
+static void kexec_prepare_cpus(void)
+{
+ wake_offline_cpus();
smp_call_function(kexec_smp_down, NULL, /* wait */0);
local_irq_disable();
mb(); /* make sure IRQs are disabled before we say they are */
@@ -215,7 +256,10 @@ static void kexec_prepare_cpus(void)
if (ppc_md.kexec_cpu_down)
ppc_md.kexec_cpu_down(0, 0);
- /* Before removing MMU mapings make sure all CPUs have entered real mode */
+ /*
+ * Before removing MMU mappings make sure all CPUs have entered real
+ * mode:
+ */
kexec_prepare_cpus_wait(KEXEC_STATE_REAL_MODE);
put_cpu();
@@ -257,6 +301,12 @@ static void kexec_prepare_cpus(void)
static union thread_union kexec_stack __init_task_data =
{ };
+/*
+ * For similar reasons to the stack above, the kexecing CPU needs to be on a
+ * static PACA; we switch to kexec_paca.
+ */
+struct paca_struct kexec_paca;
+
/* Our assembly helper, in kexec_stub.S */
extern NORET_TYPE void kexec_sequence(void *newstack, unsigned long start,
void *image, void *control,
@@ -278,12 +328,28 @@ void default_machine_kexec(struct kimage *image)
if (crashing_cpu == -1)
kexec_prepare_cpus();
+ pr_debug("kexec: Starting switchover sequence.\n");
+
/* switch to a staticly allocated stack. Based on irq stack code.
* XXX: the task struct will likely be invalid once we do the copy!
*/
kexec_stack.thread_info.task = current_thread_info()->task;
kexec_stack.thread_info.flags = 0;
+ /* We need a static PACA, too; copy this CPU's PACA over and switch to
+ * it. Also poison per_cpu_offset to catch anyone using non-static
+ * data.
+ */
+ memcpy(&kexec_paca, get_paca(), sizeof(struct paca_struct));
+ kexec_paca.data_offset = 0xedeaddeadeeeeeeeUL;
+ paca = (struct paca_struct *)RELOC_HIDE(&kexec_paca, 0) -
+ kexec_paca.paca_index;
+ setup_paca(&kexec_paca);
+
+ /* XXX: If anyone does 'dynamic lppacas' this will also need to be
+ * switched to a static version!
+ */
+
/* Some things are best done in assembly. Finding globals with
* a toc is easier in C, so pass in what we can.
*/
diff --git a/arch/powerpc/kernel/misc.S b/arch/powerpc/kernel/misc.S
index 22e507c8a55..2d29752cbe1 100644
--- a/arch/powerpc/kernel/misc.S
+++ b/arch/powerpc/kernel/misc.S
@@ -127,29 +127,3 @@ _GLOBAL(__setup_cpu_power7)
_GLOBAL(__restore_cpu_power7)
/* place holder */
blr
-
-/*
- * Get a minimal set of registers for our caller's nth caller.
- * r3 = regs pointer, r5 = n.
- *
- * We only get R1 (stack pointer), NIP (next instruction pointer)
- * and LR (link register). These are all we can get in the
- * general case without doing complicated stack unwinding, but
- * fortunately they are enough to do a stack backtrace, which
- * is all we need them for.
- */
-_GLOBAL(perf_arch_fetch_caller_regs)
- mr r6,r1
- cmpwi r5,0
- mflr r4
- ble 2f
- mtctr r5
-1: PPC_LL r6,0(r6)
- bdnz 1b
- PPC_LL r4,PPC_LR_STKOFF(r6)
-2: PPC_LL r7,0(r6)
- PPC_LL r7,PPC_LR_STKOFF(r7)
- PPC_STL r6,GPR1-STACK_FRAME_OVERHEAD(r3)
- PPC_STL r4,_NIP-STACK_FRAME_OVERHEAD(r3)
- PPC_STL r7,_LINK-STACK_FRAME_OVERHEAD(r3)
- blr
diff --git a/arch/powerpc/kernel/of_device.c b/arch/powerpc/kernel/of_device.c
deleted file mode 100644
index df78e0236a0..00000000000
--- a/arch/powerpc/kernel/of_device.c
+++ /dev/null
@@ -1,133 +0,0 @@
-#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 <linux/of_device.h>
-
-#include <asm/errno.h>
-#include <asm/dcr.h>
-
-static void of_device_make_bus_id(struct of_device *dev)
-{
- static atomic_t bus_no_reg_magic;
- struct device_node *node = dev->dev.of_node;
- const u32 *reg;
- u64 addr;
- int magic;
-
- /*
- * If it's a DCR based device, use 'd' for native DCRs
- * and 'D' for MMIO DCRs.
- */
-#ifdef CONFIG_PPC_DCR
- reg = of_get_property(node, "dcr-reg", NULL);
- if (reg) {
-#ifdef CONFIG_PPC_DCR_NATIVE
- dev_set_name(&dev->dev, "d%x.%s", *reg, node->name);
-#else /* CONFIG_PPC_DCR_NATIVE */
- addr = of_translate_dcr_address(node, *reg, NULL);
- if (addr != OF_BAD_ADDR) {
- dev_set_name(&dev->dev, "D%llx.%s",
- (unsigned long long)addr, node->name);
- return;
- }
-#endif /* !CONFIG_PPC_DCR_NATIVE */
- }
-#endif /* CONFIG_PPC_DCR */
-
- /*
- * For MMIO, get the physical address
- */
- reg = of_get_property(node, "reg", NULL);
- if (reg) {
- addr = of_translate_address(node, reg);
- if (addr != OF_BAD_ADDR) {
- dev_set_name(&dev->dev, "%llx.%s",
- (unsigned long long)addr, node->name);
- return;
- }
- }
-
- /*
- * No BusID, use the node name and add a globally incremented
- * counter (and pray...)
- */
- magic = atomic_add_return(1, &bus_no_reg_magic);
- dev_set_name(&dev->dev, "%s.%d", node->name, magic - 1);
-}
-
-struct of_device *of_device_alloc(struct device_node *np,
- const char *bus_id,
- struct device *parent)
-{
- struct of_device *dev;
-
- dev = kzalloc(sizeof(*dev), GFP_KERNEL);
- if (!dev)
- return NULL;
-
- dev->dev.of_node = of_node_get(np);
- dev->dev.dma_mask = &dev->archdata.dma_mask;
- dev->dev.parent = parent;
- dev->dev.release = of_release_dev;
-
- if (bus_id)
- dev_set_name(&dev->dev, "%s", bus_id);
- else
- of_device_make_bus_id(dev);
-
- return dev;
-}
-EXPORT_SYMBOL(of_device_alloc);
-
-int of_device_uevent(struct device *dev, struct kobj_uevent_env *env)
-{
- struct of_device *ofdev;
- const char *compat;
- int seen = 0, cplen, sl;
-
- if (!dev)
- return -ENODEV;
-
- ofdev = to_of_device(dev);
-
- if (add_uevent_var(env, "OF_NAME=%s", ofdev->dev.of_node->name))
- return -ENOMEM;
-
- if (add_uevent_var(env, "OF_TYPE=%s", ofdev->dev.of_node->type))
- return -ENOMEM;
-
- /* Since the compatible field can contain pretty much anything
- * it's not really legal to split it out with commas. We split it
- * up using a number of environment variables instead. */
-
- compat = of_get_property(ofdev->dev.of_node, "compatible", &cplen);
- while (compat && *compat && cplen > 0) {
- if (add_uevent_var(env, "OF_COMPATIBLE_%d=%s", seen, compat))
- return -ENOMEM;
-
- sl = strlen (compat) + 1;
- compat += sl;
- cplen -= sl;
- seen++;
- }
-
- if (add_uevent_var(env, "OF_COMPATIBLE_N=%d", seen))
- return -ENOMEM;
-
- /* modalias is trickier, we add it in 2 steps */
- if (add_uevent_var(env, "MODALIAS="))
- return -ENOMEM;
- sl = of_device_get_modalias(ofdev, &env->buf[env->buflen-1],
- sizeof(env->buf) - env->buflen);
- if (sl >= (sizeof(env->buf) - env->buflen))
- return -ENOMEM;
- env->buflen += sl;
-
- return 0;
-}
-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 487a98851ba..b2c363ef38a 100644
--- a/arch/powerpc/kernel/of_platform.c
+++ b/arch/powerpc/kernel/of_platform.c
@@ -28,207 +28,6 @@
#include <asm/ppc-pci.h>
#include <asm/atomic.h>
-/*
- * The list of OF IDs below is used for matching bus types in the
- * system whose devices are to be exposed as of_platform_devices.
- *
- * This is the default list valid for most platforms. This file provides
- * functions who can take an explicit list if necessary though
- *
- * The search is always performed recursively looking for children of
- * the provided device_node and recursively if such a children matches
- * a bus type in the list
- */
-
-static const struct of_device_id of_default_bus_ids[] = {
- { .type = "soc", },
- { .compatible = "soc", },
- { .type = "spider", },
- { .type = "axon", },
- { .type = "plb5", },
- { .type = "plb4", },
- { .type = "opb", },
- { .type = "ebc", },
- {},
-};
-
-struct bus_type of_platform_bus_type = {
- .uevent = of_device_uevent,
-};
-EXPORT_SYMBOL(of_platform_bus_type);
-
-static int __init of_bus_driver_init(void)
-{
- return of_bus_type_init(&of_platform_bus_type, "of_platform");
-}
-
-postcore_initcall(of_bus_driver_init);
-
-struct of_device* of_platform_device_create(struct device_node *np,
- const char *bus_id,
- struct device *parent)
-{
- struct of_device *dev;
-
- dev = of_device_alloc(np, bus_id, parent);
- if (!dev)
- return NULL;
-
- dev->archdata.dma_mask = 0xffffffffUL;
- dev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
-
- dev->dev.bus = &of_platform_bus_type;
-
- /* We do not fill the DMA ops for platform devices by default.
- * This is currently the responsibility of the platform code
- * to do such, possibly using a device notifier
- */
-
- if (of_device_register(dev) != 0) {
- of_device_free(dev);
- return NULL;
- }
-
- return dev;
-}
-EXPORT_SYMBOL(of_platform_device_create);
-
-
-
-/**
- * of_platform_bus_create - Create an OF device for a bus node and all its
- * children. Optionally recursively instanciate matching busses.
- * @bus: device node of the bus to instanciate
- * @matches: match table, NULL to use the default, OF_NO_DEEP_PROBE to
- * disallow recursive creation of child busses
- */
-static int of_platform_bus_create(const struct device_node *bus,
- const struct of_device_id *matches,
- struct device *parent)
-{
- struct device_node *child;
- struct of_device *dev;
- int rc = 0;
-
- for_each_child_of_node(bus, child) {
- pr_debug(" create child: %s\n", child->full_name);
- dev = of_platform_device_create(child, NULL, parent);
- if (dev == NULL)
- rc = -ENOMEM;
- else if (!of_match_node(matches, child))
- continue;
- if (rc == 0) {
- pr_debug(" and sub busses\n");
- rc = of_platform_bus_create(child, matches, &dev->dev);
- } if (rc) {
- of_node_put(child);
- break;
- }
- }
- return rc;
-}
-
-/**
- * of_platform_bus_probe - Probe the device-tree for platform busses
- * @root: parent of the first level to probe or NULL for the root of the tree
- * @matches: match table, NULL to use the default
- * @parent: parent to hook devices from, NULL for toplevel
- *
- * Note that children of the provided root are not instanciated as devices
- * unless the specified root itself matches the bus list and is not NULL.
- */
-
-int of_platform_bus_probe(struct device_node *root,
- const struct of_device_id *matches,
- struct device *parent)
-{
- struct device_node *child;
- struct of_device *dev;
- int rc = 0;
-
- if (matches == NULL)
- matches = of_default_bus_ids;
- if (matches == OF_NO_DEEP_PROBE)
- return -EINVAL;
- if (root == NULL)
- root = of_find_node_by_path("/");
- else
- of_node_get(root);
-
- pr_debug("of_platform_bus_probe()\n");
- pr_debug(" starting at: %s\n", root->full_name);
-
- /* Do a self check of bus type, if there's a match, create
- * children
- */
- if (of_match_node(matches, root)) {
- pr_debug(" root match, create all sub devices\n");
- dev = of_platform_device_create(root, NULL, parent);
- if (dev == NULL) {
- rc = -ENOMEM;
- goto bail;
- }
- pr_debug(" create all sub busses\n");
- rc = of_platform_bus_create(root, matches, &dev->dev);
- goto bail;
- }
- for_each_child_of_node(root, child) {
- if (!of_match_node(matches, child))
- continue;
-
- pr_debug(" match: %s\n", child->full_name);
- dev = of_platform_device_create(child, NULL, parent);
- if (dev == NULL)
- rc = -ENOMEM;
- else
- rc = of_platform_bus_create(child, matches, &dev->dev);
- if (rc) {
- of_node_put(child);
- break;
- }
- }
- bail:
- of_node_put(root);
- return rc;
-}
-EXPORT_SYMBOL(of_platform_bus_probe);
-
-static int of_dev_node_match(struct device *dev, void *data)
-{
- return to_of_device(dev)->dev.of_node == data;
-}
-
-struct of_device *of_find_device_by_node(struct device_node *np)
-{
- struct device *dev;
-
- dev = bus_find_device(&of_platform_bus_type,
- NULL, np, of_dev_node_match);
- if (dev)
- return to_of_device(dev);
- return NULL;
-}
-EXPORT_SYMBOL(of_find_device_by_node);
-
-static int of_dev_phandle_match(struct device *dev, void *data)
-{
- phandle *ph = data;
- return to_of_device(dev)->dev.of_node->phandle == *ph;
-}
-
-struct of_device *of_find_device_by_phandle(phandle ph)
-{
- struct device *dev;
-
- dev = bus_find_device(&of_platform_bus_type,
- NULL, &ph, of_dev_phandle_match);
- if (dev)
- return to_of_device(dev);
- return NULL;
-}
-EXPORT_SYMBOL(of_find_device_by_phandle);
-
-
#ifdef CONFIG_PPC_OF_PLATFORM_PCI
/* The probing of PCI controllers from of_platform is currently
@@ -237,7 +36,7 @@ EXPORT_SYMBOL(of_find_device_by_phandle);
* lacking some bits needed here.
*/
-static int __devinit of_pci_phb_probe(struct of_device *dev,
+static int __devinit of_pci_phb_probe(struct platform_device *dev,
const struct of_device_id *match)
{
struct pci_controller *phb;
diff --git a/arch/powerpc/kernel/paca.c b/arch/powerpc/kernel/paca.c
index 139a773853f..d0a26f1770f 100644
--- a/arch/powerpc/kernel/paca.c
+++ b/arch/powerpc/kernel/paca.c
@@ -105,6 +105,16 @@ void __init initialise_paca(struct paca_struct *new_paca, int cpu)
#endif /* CONFIG_PPC_STD_MMU_64 */
}
+/* Put the paca pointer into r13 and SPRG_PACA */
+void setup_paca(struct paca_struct *new_paca)
+{
+ local_paca = new_paca;
+ mtspr(SPRN_SPRG_PACA, local_paca);
+#ifdef CONFIG_PPC_BOOK3E
+ mtspr(SPRN_SPRG_TLB_EXFRAME, local_paca->extlb);
+#endif
+}
+
static int __initdata paca_size;
void __init allocate_pacas(void)
diff --git a/arch/powerpc/kernel/pci-common.c b/arch/powerpc/kernel/pci-common.c
index 5b38f6ae2b2..9021c4ad4bb 100644
--- a/arch/powerpc/kernel/pci-common.c
+++ b/arch/powerpc/kernel/pci-common.c
@@ -21,6 +21,7 @@
#include <linux/string.h>
#include <linux/init.h>
#include <linux/bootmem.h>
+#include <linux/of_address.h>
#include <linux/mm.h>
#include <linux/list.h>
#include <linux/syscalls.h>
diff --git a/arch/powerpc/kernel/perf_event.c b/arch/powerpc/kernel/perf_event.c
index 5c14ffe5125..d301a30445e 100644
--- a/arch/powerpc/kernel/perf_event.c
+++ b/arch/powerpc/kernel/perf_event.c
@@ -410,15 +410,15 @@ static void power_pmu_read(struct perf_event *event)
* Therefore we treat them like NMIs.
*/
do {
- prev = atomic64_read(&event->hw.prev_count);
+ prev = local64_read(&event->hw.prev_count);
barrier();
val = read_pmc(event->hw.idx);
- } while (atomic64_cmpxchg(&event->hw.prev_count, prev, val) != prev);
+ } while (local64_cmpxchg(&event->hw.prev_count, prev, val) != prev);
/* The counters are only 32 bits wide */
delta = (val - prev) & 0xfffffffful;
- atomic64_add(delta, &event->count);
- atomic64_sub(delta, &event->hw.period_left);
+ local64_add(delta, &event->count);
+ local64_sub(delta, &event->hw.period_left);
}
/*
@@ -444,10 +444,10 @@ static void freeze_limited_counters(struct cpu_hw_events *cpuhw,
if (!event->hw.idx)
continue;
val = (event->hw.idx == 5) ? pmc5 : pmc6;
- prev = atomic64_read(&event->hw.prev_count);
+ prev = local64_read(&event->hw.prev_count);
event->hw.idx = 0;
delta = (val - prev) & 0xfffffffful;
- atomic64_add(delta, &event->count);
+ local64_add(delta, &event->count);
}
}
@@ -462,7 +462,7 @@ static void thaw_limited_counters(struct cpu_hw_events *cpuhw,
event = cpuhw->limited_counter[i];
event->hw.idx = cpuhw->limited_hwidx[i];
val = (event->hw.idx == 5) ? pmc5 : pmc6;
- atomic64_set(&event->hw.prev_count, val);
+ local64_set(&event->hw.prev_count, val);
perf_event_update_userpage(event);
}
}
@@ -666,11 +666,11 @@ void hw_perf_enable(void)
}
val = 0;
if (event->hw.sample_period) {
- left = atomic64_read(&event->hw.period_left);
+ left = local64_read(&event->hw.period_left);
if (left < 0x80000000L)
val = 0x80000000L - left;
}
- atomic64_set(&event->hw.prev_count, val);
+ local64_set(&event->hw.prev_count, val);
event->hw.idx = idx;
write_pmc(idx, val);
perf_event_update_userpage(event);
@@ -754,7 +754,7 @@ static int power_pmu_enable(struct perf_event *event)
* skip the schedulability test here, it will be peformed
* at commit time(->commit_txn) as a whole
*/
- if (cpuhw->group_flag & PERF_EVENT_TXN_STARTED)
+ if (cpuhw->group_flag & PERF_EVENT_TXN)
goto nocheck;
if (check_excludes(cpuhw->event, cpuhw->flags, n0, 1))
@@ -845,8 +845,8 @@ static void power_pmu_unthrottle(struct perf_event *event)
if (left < 0x80000000L)
val = 0x80000000L - left;
write_pmc(event->hw.idx, val);
- atomic64_set(&event->hw.prev_count, val);
- atomic64_set(&event->hw.period_left, left);
+ local64_set(&event->hw.prev_count, val);
+ local64_set(&event->hw.period_left, left);
perf_event_update_userpage(event);
perf_enable();
local_irq_restore(flags);
@@ -861,7 +861,7 @@ void power_pmu_start_txn(const struct pmu *pmu)
{
struct cpu_hw_events *cpuhw = &__get_cpu_var(cpu_hw_events);
- cpuhw->group_flag |= PERF_EVENT_TXN_STARTED;
+ cpuhw->group_flag |= PERF_EVENT_TXN;
cpuhw->n_txn_start = cpuhw->n_events;
}
@@ -874,7 +874,7 @@ void power_pmu_cancel_txn(const struct pmu *pmu)
{
struct cpu_hw_events *cpuhw = &__get_cpu_var(cpu_hw_events);
- cpuhw->group_flag &= ~PERF_EVENT_TXN_STARTED;
+ cpuhw->group_flag &= ~PERF_EVENT_TXN;
}
/*
@@ -900,6 +900,7 @@ int power_pmu_commit_txn(const struct pmu *pmu)
for (i = cpuhw->n_txn_start; i < n; ++i)
cpuhw->event[i]->hw.config = cpuhw->events[i];
+ cpuhw->group_flag &= ~PERF_EVENT_TXN;
return 0;
}
@@ -1111,7 +1112,7 @@ const struct pmu *hw_perf_event_init(struct perf_event *event)
event->hw.config = events[n];
event->hw.event_base = cflags[n];
event->hw.last_period = event->hw.sample_period;
- atomic64_set(&event->hw.period_left, event->hw.last_period);
+ local64_set(&event->hw.period_left, event->hw.last_period);
/*
* See if we need to reserve the PMU.
@@ -1149,16 +1150,16 @@ static void record_and_restart(struct perf_event *event, unsigned long val,
int record = 0;
/* we don't have to worry about interrupts here */
- prev = atomic64_read(&event->hw.prev_count);
+ prev = local64_read(&event->hw.prev_count);
delta = (val - prev) & 0xfffffffful;
- atomic64_add(delta, &event->count);
+ local64_add(delta, &event->count);
/*
* See if the total period for this event has expired,
* and update for the next period.
*/
val = 0;
- left = atomic64_read(&event->hw.period_left) - delta;
+ left = local64_read(&event->hw.period_left) - delta;
if (period) {
if (left <= 0) {
left += period;
@@ -1196,8 +1197,8 @@ static void record_and_restart(struct perf_event *event, unsigned long val,
}
write_pmc(event->hw.idx, val);
- atomic64_set(&event->hw.prev_count, val);
- atomic64_set(&event->hw.period_left, left);
+ local64_set(&event->hw.prev_count, val);
+ local64_set(&event->hw.period_left, left);
perf_event_update_userpage(event);
}
diff --git a/arch/powerpc/kernel/perf_event_fsl_emb.c b/arch/powerpc/kernel/perf_event_fsl_emb.c
index babcceecd2e..1ba45471ae4 100644
--- a/arch/powerpc/kernel/perf_event_fsl_emb.c
+++ b/arch/powerpc/kernel/perf_event_fsl_emb.c
@@ -162,15 +162,15 @@ static void fsl_emb_pmu_read(struct perf_event *event)
* Therefore we treat them like NMIs.
*/
do {
- prev = atomic64_read(&event->hw.prev_count);
+ prev = local64_read(&event->hw.prev_count);
barrier();
val = read_pmc(event->hw.idx);
- } while (atomic64_cmpxchg(&event->hw.prev_count, prev, val) != prev);
+ } while (local64_cmpxchg(&event->hw.prev_count, prev, val) != prev);
/* The counters are only 32 bits wide */
delta = (val - prev) & 0xfffffffful;
- atomic64_add(delta, &event->count);
- atomic64_sub(delta, &event->hw.period_left);
+ local64_add(delta, &event->count);
+ local64_sub(delta, &event->hw.period_left);
}
/*
@@ -296,11 +296,11 @@ static int fsl_emb_pmu_enable(struct perf_event *event)
val = 0;
if (event->hw.sample_period) {
- s64 left = atomic64_read(&event->hw.period_left);
+ s64 left = local64_read(&event->hw.period_left);
if (left < 0x80000000L)
val = 0x80000000L - left;
}
- atomic64_set(&event->hw.prev_count, val);
+ local64_set(&event->hw.prev_count, val);
write_pmc(i, val);
perf_event_update_userpage(event);
@@ -371,8 +371,8 @@ static void fsl_emb_pmu_unthrottle(struct perf_event *event)
if (left < 0x80000000L)
val = 0x80000000L - left;
write_pmc(event->hw.idx, val);
- atomic64_set(&event->hw.prev_count, val);
- atomic64_set(&event->hw.period_left, left);
+ local64_set(&event->hw.prev_count, val);
+ local64_set(&event->hw.period_left, left);
perf_event_update_userpage(event);
perf_enable();
local_irq_restore(flags);
@@ -500,7 +500,7 @@ const struct pmu *hw_perf_event_init(struct perf_event *event)
return ERR_PTR(-ENOTSUPP);
event->hw.last_period = event->hw.sample_period;
- atomic64_set(&event->hw.period_left, event->hw.last_period);
+ local64_set(&event->hw.period_left, event->hw.last_period);
/*
* See if we need to reserve the PMU.
@@ -541,16 +541,16 @@ static void record_and_restart(struct perf_event *event, unsigned long val,
int record = 0;
/* we don't have to worry about interrupts here */
- prev = atomic64_read(&event->hw.prev_count);
+ prev = local64_read(&event->hw.prev_count);
delta = (val - prev) & 0xfffffffful;
- atomic64_add(delta, &event->count);
+ local64_add(delta, &event->count);
/*
* See if the total period for this event has expired,
* and update for the next period.
*/
val = 0;
- left = atomic64_read(&event->hw.period_left) - delta;
+ left = local64_read(&event->hw.period_left) - delta;
if (period) {
if (left <= 0) {
left += period;
@@ -569,6 +569,7 @@ static void record_and_restart(struct perf_event *event, unsigned long val,
struct perf_sample_data data;
perf_sample_data_init(&data, 0);
+ data.period = event->hw.last_period;
if (perf_event_overflow(event, nmi, &data, regs)) {
/*
@@ -584,8 +585,8 @@ static void record_and_restart(struct perf_event *event, unsigned long val,
}
write_pmc(event->hw.idx, val);
- atomic64_set(&event->hw.prev_count, val);
- atomic64_set(&event->hw.period_left, left);
+ local64_set(&event->hw.prev_count, val);
+ local64_set(&event->hw.period_left, left);
perf_event_update_userpage(event);
}
diff --git a/arch/powerpc/kernel/ppc_ksyms.c b/arch/powerpc/kernel/ppc_ksyms.c
index 3b4dcc82a4c..ab3e392ac63 100644
--- a/arch/powerpc/kernel/ppc_ksyms.c
+++ b/arch/powerpc/kernel/ppc_ksyms.c
@@ -101,10 +101,6 @@ EXPORT_SYMBOL(pci_dram_offset);
EXPORT_SYMBOL(start_thread);
EXPORT_SYMBOL(kernel_thread);
-#ifdef CONFIG_PPC_FPU
-EXPORT_SYMBOL_GPL(cvt_df);
-EXPORT_SYMBOL_GPL(cvt_fd);
-#endif
EXPORT_SYMBOL(giveup_fpu);
#ifdef CONFIG_ALTIVEC
EXPORT_SYMBOL(giveup_altivec);
diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c
index 773424df828..e78a5add7f1 100644
--- a/arch/powerpc/kernel/process.c
+++ b/arch/powerpc/kernel/process.c
@@ -37,6 +37,7 @@
#include <linux/kernel_stat.h>
#include <linux/personality.h>
#include <linux/random.h>
+#include <linux/hw_breakpoint.h>
#include <asm/pgtable.h>
#include <asm/uaccess.h>
@@ -462,14 +463,42 @@ struct task_struct *__switch_to(struct task_struct *prev,
#ifdef CONFIG_PPC_ADV_DEBUG_REGS
switch_booke_debug_regs(&new->thread);
#else
+/*
+ * For PPC_BOOK3S_64, we use the hw-breakpoint interfaces that would
+ * schedule DABR
+ */
+#ifndef CONFIG_HAVE_HW_BREAKPOINT
if (unlikely(__get_cpu_var(current_dabr) != new->thread.dabr))
set_dabr(new->thread.dabr);
+#endif /* CONFIG_HAVE_HW_BREAKPOINT */
#endif
new_thread = &new->thread;
old_thread = &current->thread;
+#if defined(CONFIG_PPC_BOOK3E_64)
+ /* XXX Current Book3E code doesn't deal with kernel side DBCR0,
+ * we always hold the user values, so we set it now.
+ *
+ * However, we ensure the kernel MSR:DE is appropriately cleared too
+ * to avoid spurrious single step exceptions in the kernel.
+ *
+ * This will have to change to merge with the ppc32 code at some point,
+ * but I don't like much what ppc32 is doing today so there's some
+ * thinking needed there
+ */
+ if ((new_thread->dbcr0 | old_thread->dbcr0) & DBCR0_IDM) {
+ u32 dbcr0;
+
+ mtmsr(mfmsr() & ~MSR_DE);
+ isync();
+ dbcr0 = mfspr(SPRN_DBCR0);
+ dbcr0 = (dbcr0 & DBCR0_EDM) | new_thread->dbcr0;
+ mtspr(SPRN_DBCR0, dbcr0);
+ }
+#endif /* CONFIG_PPC64_BOOK3E */
+
#ifdef CONFIG_PPC64
/*
* Collect processor utilization data per process
@@ -642,7 +671,11 @@ void flush_thread(void)
{
discard_lazy_cpu_state();
+#ifdef CONFIG_HAVE_HW_BREAKPOINTS
+ flush_ptrace_hw_breakpoint(current);
+#else /* CONFIG_HAVE_HW_BREAKPOINTS */
set_debug_reg_defaults(&current->thread);
+#endif /* CONFIG_HAVE_HW_BREAKPOINTS */
}
void
@@ -660,6 +693,9 @@ void prepare_to_copy(struct task_struct *tsk)
flush_altivec_to_thread(current);
flush_vsx_to_thread(current);
flush_spe_to_thread(current);
+#ifdef CONFIG_HAVE_HW_BREAKPOINT
+ flush_ptrace_hw_breakpoint(tsk);
+#endif /* CONFIG_HAVE_HW_BREAKPOINT */
}
/*
@@ -1263,3 +1299,14 @@ unsigned long randomize_et_dyn(unsigned long base)
return ret;
}
+
+#ifdef CONFIG_SMP
+int arch_sd_sibling_asym_packing(void)
+{
+ if (cpu_has_feature(CPU_FTR_ASYM_SMT)) {
+ printk_once(KERN_INFO "Enabling Asymmetric SMT scheduling\n");
+ return SD_ASYM_PACKING;
+ }
+ return 0;
+}
+#endif
diff --git a/arch/powerpc/kernel/prom_init.c b/arch/powerpc/kernel/prom_init.c
index 3b6f8ae9b8c..941ff4dbc56 100644
--- a/arch/powerpc/kernel/prom_init.c
+++ b/arch/powerpc/kernel/prom_init.c
@@ -311,6 +311,24 @@ static void __init prom_print_hex(unsigned long val)
call_prom("write", 3, 1, _prom->stdout, buf, nibbles);
}
+/* max number of decimal digits in an unsigned long */
+#define UL_DIGITS 21
+static void __init prom_print_dec(unsigned long val)
+{
+ int i, size;
+ char buf[UL_DIGITS+1];
+ struct prom_t *_prom = &RELOC(prom);
+
+ for (i = UL_DIGITS-1; i >= 0; i--) {
+ buf[i] = (val % 10) + '0';
+ val = val/10;
+ if (val == 0)
+ break;
+ }
+ /* shift stuff down */
+ size = UL_DIGITS - i;
+ call_prom("write", 3, 1, _prom->stdout, buf+i, size);
+}
static void __init prom_printf(const char *format, ...)
{
@@ -350,6 +368,14 @@ static void __init prom_printf(const char *format, ...)
v = va_arg(args, unsigned long);
prom_print_hex(v);
break;
+ case 'l':
+ ++q;
+ if (*q == 'u') { /* '%lu' */
+ ++q;
+ v = va_arg(args, unsigned long);
+ prom_print_dec(v);
+ }
+ break;
}
}
}
@@ -835,11 +861,11 @@ static int __init prom_count_smt_threads(void)
if (plen == PROM_ERROR)
break;
plen >>= 2;
- prom_debug("Found 0x%x smt threads per core\n", (unsigned long)plen);
+ prom_debug("Found %lu smt threads per core\n", (unsigned long)plen);
/* Sanity check */
if (plen < 1 || plen > 64) {
- prom_printf("Threads per core 0x%x out of bounds, assuming 1\n",
+ prom_printf("Threads per core %lu out of bounds, assuming 1\n",
(unsigned long)plen);
return 1;
}
@@ -869,12 +895,12 @@ static void __init prom_send_capabilities(void)
cores = (u32 *)PTRRELOC(&ibm_architecture_vec[IBM_ARCH_VEC_NRCORES_OFFSET]);
if (*cores != NR_CPUS) {
prom_printf("WARNING ! "
- "ibm_architecture_vec structure inconsistent: 0x%x !\n",
+ "ibm_architecture_vec structure inconsistent: %lu!\n",
*cores);
} else {
*cores = DIV_ROUND_UP(NR_CPUS, prom_count_smt_threads());
- prom_printf("Max number of cores passed to firmware: 0x%x\n",
- (unsigned long)*cores);
+ prom_printf("Max number of cores passed to firmware: %lu (NR_CPUS = %lu)\n",
+ *cores, NR_CPUS);
}
/* try calling the ibm,client-architecture-support method */
@@ -1482,7 +1508,7 @@ static void __init prom_hold_cpus(void)
reg = -1;
prom_getprop(node, "reg", &reg, sizeof(reg));
- prom_debug("cpu hw idx = 0x%x\n", reg);
+ prom_debug("cpu hw idx = %lu\n", reg);
/* Init the acknowledge var which will be reset by
* the secondary cpu when it awakens from its OF
@@ -1492,7 +1518,7 @@ static void __init prom_hold_cpus(void)
if (reg != _prom->cpu) {
/* Primary Thread of non-boot cpu */
- prom_printf("starting cpu hw idx %x... ", reg);
+ prom_printf("starting cpu hw idx %lu... ", reg);
call_prom("start-cpu", 3, 0, node,
secondary_hold, reg);
@@ -1507,7 +1533,7 @@ static void __init prom_hold_cpus(void)
}
#ifdef CONFIG_SMP
else
- prom_printf("boot cpu hw idx %x\n", reg);
+ prom_printf("boot cpu hw idx %lu\n", reg);
#endif /* CONFIG_SMP */
}
@@ -2420,7 +2446,7 @@ static void __init prom_find_boot_cpu(void)
prom_getprop(cpu_pkg, "reg", &getprop_rval, sizeof(getprop_rval));
_prom->cpu = getprop_rval;
- prom_debug("Booting CPU hw index = 0x%x\n", _prom->cpu);
+ prom_debug("Booting CPU hw index = %lu\n", _prom->cpu);
}
static void __init prom_check_initrd(unsigned long r3, unsigned long r4)
diff --git a/arch/powerpc/kernel/prom_parse.c b/arch/powerpc/kernel/prom_parse.c
index 8362620c9e6..88334af038e 100644
--- a/arch/powerpc/kernel/prom_parse.c
+++ b/arch/powerpc/kernel/prom_parse.c
@@ -6,232 +6,11 @@
#include <linux/module.h>
#include <linux/ioport.h>
#include <linux/etherdevice.h>
+#include <linux/of_address.h>
#include <asm/prom.h>
#include <asm/pci-bridge.h>
-#ifdef DEBUG
-#define DBG(fmt...) do { printk(fmt); } while(0)
-#else
-#define DBG(fmt...) do { } while(0)
-#endif
-
-#ifdef CONFIG_PPC64
-#define PRu64 "%lx"
-#else
-#define PRu64 "%llx"
-#endif
-
-/* Max address size we deal with */
-#define OF_MAX_ADDR_CELLS 4
-#define OF_CHECK_COUNTS(na, ns) ((na) > 0 && (na) <= OF_MAX_ADDR_CELLS && \
- (ns) > 0)
-
-static struct of_bus *of_match_bus(struct device_node *np);
-static int __of_address_to_resource(struct device_node *dev,
- const u32 *addrp, u64 size, unsigned int flags,
- struct resource *r);
-
-
-/* Debug utility */
-#ifdef DEBUG
-static void of_dump_addr(const char *s, const u32 *addr, int na)
-{
- printk("%s", s);
- while(na--)
- printk(" %08x", *(addr++));
- printk("\n");
-}
-#else
-static void of_dump_addr(const char *s, const u32 *addr, int na) { }
-#endif
-
-
-/* Callbacks for bus specific translators */
-struct of_bus {
- const char *name;
- const char *addresses;
- int (*match)(struct device_node *parent);
- void (*count_cells)(struct device_node *child,
- int *addrc, int *sizec);
- u64 (*map)(u32 *addr, const u32 *range,
- int na, int ns, int pna);
- int (*translate)(u32 *addr, u64 offset, int na);
- unsigned int (*get_flags)(const u32 *addr);
-};
-
-
-/*
- * Default translator (generic bus)
- */
-
-static void of_bus_default_count_cells(struct device_node *dev,
- int *addrc, int *sizec)
-{
- if (addrc)
- *addrc = of_n_addr_cells(dev);
- if (sizec)
- *sizec = of_n_size_cells(dev);
-}
-
-static u64 of_bus_default_map(u32 *addr, const u32 *range,
- int na, int ns, int pna)
-{
- u64 cp, s, da;
-
- cp = of_read_number(range, na);
- s = of_read_number(range + na + pna, ns);
- da = of_read_number(addr, na);
-
- DBG("OF: default map, cp="PRu64", s="PRu64", da="PRu64"\n",
- cp, s, da);
-
- if (da < cp || da >= (cp + s))
- return OF_BAD_ADDR;
- return da - cp;
-}
-
-static int of_bus_default_translate(u32 *addr, u64 offset, int na)
-{
- u64 a = of_read_number(addr, na);
- memset(addr, 0, na * 4);
- a += offset;
- if (na > 1)
- addr[na - 2] = a >> 32;
- addr[na - 1] = a & 0xffffffffu;
-
- return 0;
-}
-
-static unsigned int of_bus_default_get_flags(const u32 *addr)
-{
- return IORESOURCE_MEM;
-}
-
-
#ifdef CONFIG_PCI
-/*
- * PCI bus specific translator
- */
-
-static int of_bus_pci_match(struct device_node *np)
-{
- /* "vci" is for the /chaos bridge on 1st-gen PCI powermacs */
- return !strcmp(np->type, "pci") || !strcmp(np->type, "vci");
-}
-
-static void of_bus_pci_count_cells(struct device_node *np,
- int *addrc, int *sizec)
-{
- if (addrc)
- *addrc = 3;
- if (sizec)
- *sizec = 2;
-}
-
-static unsigned int of_bus_pci_get_flags(const u32 *addr)
-{
- unsigned int flags = 0;
- u32 w = addr[0];
-
- switch((w >> 24) & 0x03) {
- case 0x01:
- flags |= IORESOURCE_IO;
- break;
- case 0x02: /* 32 bits */
- case 0x03: /* 64 bits */
- flags |= IORESOURCE_MEM;
- break;
- }
- if (w & 0x40000000)
- flags |= IORESOURCE_PREFETCH;
- return flags;
-}
-
-static u64 of_bus_pci_map(u32 *addr, const u32 *range, int na, int ns, int pna)
-{
- u64 cp, s, da;
- unsigned int af, rf;
-
- af = of_bus_pci_get_flags(addr);
- rf = of_bus_pci_get_flags(range);
-
- /* Check address type match */
- if ((af ^ rf) & (IORESOURCE_MEM | IORESOURCE_IO))
- return OF_BAD_ADDR;
-
- /* Read address values, skipping high cell */
- cp = of_read_number(range + 1, na - 1);
- s = of_read_number(range + na + pna, ns);
- da = of_read_number(addr + 1, na - 1);
-
- DBG("OF: PCI map, cp="PRu64", s="PRu64", da="PRu64"\n", cp, s, da);
-
- if (da < cp || da >= (cp + s))
- return OF_BAD_ADDR;
- return da - cp;
-}
-
-static int of_bus_pci_translate(u32 *addr, u64 offset, int na)
-{
- return of_bus_default_translate(addr + 1, offset, na - 1);
-}
-
-const u32 *of_get_pci_address(struct device_node *dev, int bar_no, u64 *size,
- unsigned int *flags)
-{
- const u32 *prop;
- unsigned int psize;
- struct device_node *parent;
- struct of_bus *bus;
- int onesize, i, na, ns;
-
- /* Get parent & match bus type */
- parent = of_get_parent(dev);
- if (parent == NULL)
- return NULL;
- bus = of_match_bus(parent);
- if (strcmp(bus->name, "pci")) {
- of_node_put(parent);
- return NULL;
- }
- bus->count_cells(dev, &na, &ns);
- of_node_put(parent);
- if (!OF_CHECK_COUNTS(na, ns))
- return NULL;
-
- /* Get "reg" or "assigned-addresses" property */
- prop = of_get_property(dev, bus->addresses, &psize);
- if (prop == NULL)
- return NULL;
- psize /= 4;
-
- onesize = na + ns;
- for (i = 0; psize >= onesize; psize -= onesize, prop += onesize, i++)
- if ((prop[0] & 0xff) == ((bar_no * 4) + PCI_BASE_ADDRESS_0)) {
- if (size)
- *size = of_read_number(prop + na, ns);
- if (flags)
- *flags = bus->get_flags(prop);
- return prop;
- }
- return NULL;
-}
-EXPORT_SYMBOL(of_get_pci_address);
-
-int of_pci_address_to_resource(struct device_node *dev, int bar,
- struct resource *r)
-{
- const u32 *addrp;
- u64 size;
- unsigned int flags;
-
- addrp = of_get_pci_address(dev, bar, &size, &flags);
- if (addrp == NULL)
- return -EINVAL;
- return __of_address_to_resource(dev, addrp, size, flags, r);
-}
-EXPORT_SYMBOL_GPL(of_pci_address_to_resource);
-
int of_irq_map_pci(struct pci_dev *pdev, struct of_irq *out_irq)
{
struct device_node *dn, *ppnode;
@@ -313,345 +92,6 @@ int of_irq_map_pci(struct pci_dev *pdev, struct of_irq *out_irq)
EXPORT_SYMBOL_GPL(of_irq_map_pci);
#endif /* CONFIG_PCI */
-/*
- * ISA bus specific translator
- */
-
-static int of_bus_isa_match(struct device_node *np)
-{
- return !strcmp(np->name, "isa");
-}
-
-static void of_bus_isa_count_cells(struct device_node *child,
- int *addrc, int *sizec)
-{
- if (addrc)
- *addrc = 2;
- if (sizec)
- *sizec = 1;
-}
-
-static u64 of_bus_isa_map(u32 *addr, const u32 *range, int na, int ns, int pna)
-{
- u64 cp, s, da;
-
- /* Check address type match */
- if ((addr[0] ^ range[0]) & 0x00000001)
- return OF_BAD_ADDR;
-
- /* Read address values, skipping high cell */
- cp = of_read_number(range + 1, na - 1);
- s = of_read_number(range + na + pna, ns);
- da = of_read_number(addr + 1, na - 1);
-
- DBG("OF: ISA map, cp="PRu64", s="PRu64", da="PRu64"\n", cp, s, da);
-
- if (da < cp || da >= (cp + s))
- return OF_BAD_ADDR;
- return da - cp;
-}
-
-static int of_bus_isa_translate(u32 *addr, u64 offset, int na)
-{
- return of_bus_default_translate(addr + 1, offset, na - 1);
-}
-
-static unsigned int of_bus_isa_get_flags(const u32 *addr)
-{
- unsigned int flags = 0;
- u32 w = addr[0];
-
- if (w & 1)
- flags |= IORESOURCE_IO;
- else
- flags |= IORESOURCE_MEM;
- return flags;
-}
-
-
-/*
- * Array of bus specific translators
- */
-
-static struct of_bus of_busses[] = {
-#ifdef CONFIG_PCI
- /* PCI */
- {
- .name = "pci",
- .addresses = "assigned-addresses",
- .match = of_bus_pci_match,
- .count_cells = of_bus_pci_count_cells,
- .map = of_bus_pci_map,
- .translate = of_bus_pci_translate,
- .get_flags = of_bus_pci_get_flags,
- },
-#endif /* CONFIG_PCI */
- /* ISA */
- {
- .name = "isa",
- .addresses = "reg",
- .match = of_bus_isa_match,
- .count_cells = of_bus_isa_count_cells,
- .map = of_bus_isa_map,
- .translate = of_bus_isa_translate,
- .get_flags = of_bus_isa_get_flags,
- },
- /* Default */
- {
- .name = "default",
- .addresses = "reg",
- .match = NULL,
- .count_cells = of_bus_default_count_cells,
- .map = of_bus_default_map,
- .translate = of_bus_default_translate,
- .get_flags = of_bus_default_get_flags,
- },
-};
-
-static struct of_bus *of_match_bus(struct device_node *np)
-{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(of_busses); i ++)
- if (!of_busses[i].match || of_busses[i].match(np))
- return &of_busses[i];
- BUG();
- return NULL;
-}
-
-static int of_translate_one(struct device_node *parent, struct of_bus *bus,
- struct of_bus *pbus, u32 *addr,
- int na, int ns, int pna, const char *rprop)
-{
- const u32 *ranges;
- unsigned int rlen;
- int rone;
- u64 offset = OF_BAD_ADDR;
-
- /* Normally, an absence of a "ranges" property means we are
- * crossing a non-translatable boundary, and thus the addresses
- * below the current not cannot be converted to CPU physical ones.
- * Unfortunately, while this is very clear in the spec, it's not
- * what Apple understood, and they do have things like /uni-n or
- * /ht nodes with no "ranges" property and a lot of perfectly
- * useable mapped devices below them. Thus we treat the absence of
- * "ranges" as equivalent to an empty "ranges" property which means
- * a 1:1 translation at that level. It's up to the caller not to try
- * to translate addresses that aren't supposed to be translated in
- * the first place. --BenH.
- */
- ranges = of_get_property(parent, rprop, &rlen);
- if (ranges == NULL || rlen == 0) {
- offset = of_read_number(addr, na);
- memset(addr, 0, pna * 4);
- DBG("OF: no ranges, 1:1 translation\n");
- goto finish;
- }
-
- DBG("OF: walking ranges...\n");
-
- /* Now walk through the ranges */
- rlen /= 4;
- rone = na + pna + ns;
- for (; rlen >= rone; rlen -= rone, ranges += rone) {
- offset = bus->map(addr, ranges, na, ns, pna);
- if (offset != OF_BAD_ADDR)
- break;
- }
- if (offset == OF_BAD_ADDR) {
- DBG("OF: not found !\n");
- return 1;
- }
- memcpy(addr, ranges + na, 4 * pna);
-
- finish:
- of_dump_addr("OF: parent translation for:", addr, pna);
- DBG("OF: with offset: "PRu64"\n", offset);
-
- /* Translate it into parent bus space */
- return pbus->translate(addr, offset, pna);
-}
-
-
-/*
- * Translate an address from the device-tree into a CPU physical address,
- * this walks up the tree and applies the various bus mappings on the
- * way.
- *
- * Note: We consider that crossing any level with #size-cells == 0 to mean
- * that translation is impossible (that is we are not dealing with a value
- * that can be mapped to a cpu physical address). This is not really specified
- * that way, but this is traditionally the way IBM at least do things
- */
-u64 __of_translate_address(struct device_node *dev, const u32 *in_addr,
- const char *rprop)
-{
- struct device_node *parent = NULL;
- struct of_bus *bus, *pbus;
- u32 addr[OF_MAX_ADDR_CELLS];
- int na, ns, pna, pns;
- u64 result = OF_BAD_ADDR;
-
- DBG("OF: ** translation for device %s **\n", dev->full_name);
-
- /* Increase refcount at current level */
- of_node_get(dev);
-
- /* Get parent & match bus type */
- parent = of_get_parent(dev);
- if (parent == NULL)
- goto bail;
- bus = of_match_bus(parent);
-
- /* Cound address cells & copy address locally */
- bus->count_cells(dev, &na, &ns);
- if (!OF_CHECK_COUNTS(na, ns)) {
- printk(KERN_ERR "prom_parse: Bad cell count for %s\n",
- dev->full_name);
- goto bail;
- }
- memcpy(addr, in_addr, na * 4);
-
- DBG("OF: bus is %s (na=%d, ns=%d) on %s\n",
- bus->name, na, ns, parent->full_name);
- of_dump_addr("OF: translating address:", addr, na);
-
- /* Translate */
- for (;;) {
- /* Switch to parent bus */
- of_node_put(dev);
- dev = parent;
- parent = of_get_parent(dev);
-
- /* If root, we have finished */
- if (parent == NULL) {
- DBG("OF: reached root node\n");
- result = of_read_number(addr, na);
- break;
- }
-
- /* Get new parent bus and counts */
- pbus = of_match_bus(parent);
- pbus->count_cells(dev, &pna, &pns);
- if (!OF_CHECK_COUNTS(pna, pns)) {
- printk(KERN_ERR "prom_parse: Bad cell count for %s\n",
- dev->full_name);
- break;
- }
-
- DBG("OF: parent bus is %s (na=%d, ns=%d) on %s\n",
- pbus->name, pna, pns, parent->full_name);
-
- /* Apply bus translation */
- if (of_translate_one(dev, bus, pbus, addr, na, ns, pna, rprop))
- break;
-
- /* Complete the move up one level */
- na = pna;
- ns = pns;
- bus = pbus;
-
- of_dump_addr("OF: one level translation:", addr, na);
- }
- bail:
- of_node_put(parent);
- of_node_put(dev);
-
- return result;
-}
-
-u64 of_translate_address(struct device_node *dev, const u32 *in_addr)
-{
- return __of_translate_address(dev, in_addr, "ranges");
-}
-EXPORT_SYMBOL(of_translate_address);
-
-u64 of_translate_dma_address(struct device_node *dev, const u32 *in_addr)
-{
- return __of_translate_address(dev, in_addr, "dma-ranges");
-}
-EXPORT_SYMBOL(of_translate_dma_address);
-
-const u32 *of_get_address(struct device_node *dev, int index, u64 *size,
- unsigned int *flags)
-{
- const u32 *prop;
- unsigned int psize;
- struct device_node *parent;
- struct of_bus *bus;
- int onesize, i, na, ns;
-
- /* Get parent & match bus type */
- parent = of_get_parent(dev);
- if (parent == NULL)
- return NULL;
- bus = of_match_bus(parent);
- bus->count_cells(dev, &na, &ns);
- of_node_put(parent);
- if (!OF_CHECK_COUNTS(na, ns))
- return NULL;
-
- /* Get "reg" or "assigned-addresses" property */
- prop = of_get_property(dev, bus->addresses, &psize);
- if (prop == NULL)
- return NULL;
- psize /= 4;
-
- onesize = na + ns;
- for (i = 0; psize >= onesize; psize -= onesize, prop += onesize, i++)
- if (i == index) {
- if (size)
- *size = of_read_number(prop + na, ns);
- if (flags)
- *flags = bus->get_flags(prop);
- return prop;
- }
- return NULL;
-}
-EXPORT_SYMBOL(of_get_address);
-
-static int __of_address_to_resource(struct device_node *dev, const u32 *addrp,
- u64 size, unsigned int flags,
- struct resource *r)
-{
- u64 taddr;
-
- if ((flags & (IORESOURCE_IO | IORESOURCE_MEM)) == 0)
- return -EINVAL;
- taddr = of_translate_address(dev, addrp);
- if (taddr == OF_BAD_ADDR)
- return -EINVAL;
- memset(r, 0, sizeof(struct resource));
- if (flags & IORESOURCE_IO) {
- unsigned long port;
- port = pci_address_to_pio(taddr);
- if (port == (unsigned long)-1)
- return -EINVAL;
- r->start = port;
- r->end = port + size - 1;
- } else {
- r->start = taddr;
- r->end = taddr + size - 1;
- }
- r->flags = flags;
- r->name = dev->name;
- return 0;
-}
-
-int of_address_to_resource(struct device_node *dev, int index,
- struct resource *r)
-{
- const u32 *addrp;
- u64 size;
- unsigned int flags;
-
- addrp = of_get_address(dev, index, &size, &flags);
- if (addrp == NULL)
- return -EINVAL;
- return __of_address_to_resource(dev, addrp, size, flags, r);
-}
-EXPORT_SYMBOL_GPL(of_address_to_resource);
-
void of_parse_dma_window(struct device_node *dn, const void *dma_window_prop,
unsigned long *busno, unsigned long *phys, unsigned long *size)
{
@@ -678,342 +118,6 @@ void of_parse_dma_window(struct device_node *dn, const void *dma_window_prop,
*size = of_read_number(dma_window, cells);
}
-/*
- * Interrupt remapper
- */
-
-static unsigned int of_irq_workarounds;
-static struct device_node *of_irq_dflt_pic;
-
-static struct device_node *of_irq_find_parent(struct device_node *child)
-{
- struct device_node *p;
- const phandle *parp;
-
- if (!of_node_get(child))
- return NULL;
-
- do {
- parp = of_get_property(child, "interrupt-parent", NULL);
- if (parp == NULL)
- p = of_get_parent(child);
- else {
- if (of_irq_workarounds & OF_IMAP_NO_PHANDLE)
- p = of_node_get(of_irq_dflt_pic);
- else
- p = of_find_node_by_phandle(*parp);
- }
- of_node_put(child);
- child = p;
- } while (p && of_get_property(p, "#interrupt-cells", NULL) == NULL);
-
- return p;
-}
-
-/* This doesn't need to be called if you don't have any special workaround
- * flags to pass
- */
-void of_irq_map_init(unsigned int flags)
-{
- of_irq_workarounds = flags;
-
- /* OldWorld, don't bother looking at other things */
- if (flags & OF_IMAP_OLDWORLD_MAC)
- return;
-
- /* If we don't have phandles, let's try to locate a default interrupt
- * controller (happens when booting with BootX). We do a first match
- * here, hopefully, that only ever happens on machines with one
- * controller.
- */
- if (flags & OF_IMAP_NO_PHANDLE) {
- struct device_node *np;
-
- for_each_node_with_property(np, "interrupt-controller") {
- /* Skip /chosen/interrupt-controller */
- if (strcmp(np->name, "chosen") == 0)
- continue;
- /* It seems like at least one person on this planet wants
- * to use BootX on a machine with an AppleKiwi controller
- * which happens to pretend to be an interrupt
- * controller too.
- */
- if (strcmp(np->name, "AppleKiwi") == 0)
- continue;
- /* I think we found one ! */
- of_irq_dflt_pic = np;
- break;
- }
- }
-
-}
-
-int of_irq_map_raw(struct device_node *parent, const u32 *intspec, u32 ointsize,
- const u32 *addr, struct of_irq *out_irq)
-{
- struct device_node *ipar, *tnode, *old = NULL, *newpar = NULL;
- const u32 *tmp, *imap, *imask;
- u32 intsize = 1, addrsize, newintsize = 0, newaddrsize = 0;
- int imaplen, match, i;
-
- DBG("of_irq_map_raw: par=%s,intspec=[0x%08x 0x%08x...],ointsize=%d\n",
- parent->full_name, intspec[0], intspec[1], ointsize);
-
- ipar = of_node_get(parent);
-
- /* First get the #interrupt-cells property of the current cursor
- * that tells us how to interpret the passed-in intspec. If there
- * is none, we are nice and just walk up the tree
- */
- do {
- tmp = of_get_property(ipar, "#interrupt-cells", NULL);
- if (tmp != NULL) {
- intsize = *tmp;
- break;
- }
- tnode = ipar;
- ipar = of_irq_find_parent(ipar);
- of_node_put(tnode);
- } while (ipar);
- if (ipar == NULL) {
- DBG(" -> no parent found !\n");
- goto fail;
- }
-
- DBG("of_irq_map_raw: ipar=%s, size=%d\n", ipar->full_name, intsize);
-
- if (ointsize != intsize)
- return -EINVAL;
-
- /* Look for this #address-cells. We have to implement the old linux
- * trick of looking for the parent here as some device-trees rely on it
- */
- old = of_node_get(ipar);
- do {
- tmp = of_get_property(old, "#address-cells", NULL);
- tnode = of_get_parent(old);
- of_node_put(old);
- old = tnode;
- } while(old && tmp == NULL);
- of_node_put(old);
- old = NULL;
- addrsize = (tmp == NULL) ? 2 : *tmp;
-
- DBG(" -> addrsize=%d\n", addrsize);
-
- /* Now start the actual "proper" walk of the interrupt tree */
- while (ipar != NULL) {
- /* Now check if cursor is an interrupt-controller and if it is
- * then we are done
- */
- if (of_get_property(ipar, "interrupt-controller", NULL) !=
- NULL) {
- DBG(" -> got it !\n");
- memcpy(out_irq->specifier, intspec,
- intsize * sizeof(u32));
- out_irq->size = intsize;
- out_irq->controller = ipar;
- of_node_put(old);
- return 0;
- }
-
- /* Now look for an interrupt-map */
- imap = of_get_property(ipar, "interrupt-map", &imaplen);
- /* No interrupt map, check for an interrupt parent */
- if (imap == NULL) {
- DBG(" -> no map, getting parent\n");
- newpar = of_irq_find_parent(ipar);
- goto skiplevel;
- }
- imaplen /= sizeof(u32);
-
- /* Look for a mask */
- imask = of_get_property(ipar, "interrupt-map-mask", NULL);
-
- /* If we were passed no "reg" property and we attempt to parse
- * an interrupt-map, then #address-cells must be 0.
- * Fail if it's not.
- */
- if (addr == NULL && addrsize != 0) {
- DBG(" -> no reg passed in when needed !\n");
- goto fail;
- }
-
- /* Parse interrupt-map */
- match = 0;
- while (imaplen > (addrsize + intsize + 1) && !match) {
- /* Compare specifiers */
- match = 1;
- for (i = 0; i < addrsize && match; ++i) {
- u32 mask = imask ? imask[i] : 0xffffffffu;
- match = ((addr[i] ^ imap[i]) & mask) == 0;
- }
- for (; i < (addrsize + intsize) && match; ++i) {
- u32 mask = imask ? imask[i] : 0xffffffffu;
- match =
- ((intspec[i-addrsize] ^ imap[i]) & mask) == 0;
- }
- imap += addrsize + intsize;
- imaplen -= addrsize + intsize;
-
- DBG(" -> match=%d (imaplen=%d)\n", match, imaplen);
-
- /* Get the interrupt parent */
- if (of_irq_workarounds & OF_IMAP_NO_PHANDLE)
- newpar = of_node_get(of_irq_dflt_pic);
- else
- newpar = of_find_node_by_phandle((phandle)*imap);
- imap++;
- --imaplen;
-
- /* Check if not found */
- if (newpar == NULL) {
- DBG(" -> imap parent not found !\n");
- goto fail;
- }
-
- /* Get #interrupt-cells and #address-cells of new
- * parent
- */
- tmp = of_get_property(newpar, "#interrupt-cells", NULL);
- if (tmp == NULL) {
- DBG(" -> parent lacks #interrupt-cells !\n");
- goto fail;
- }
- newintsize = *tmp;
- tmp = of_get_property(newpar, "#address-cells", NULL);
- newaddrsize = (tmp == NULL) ? 0 : *tmp;
-
- DBG(" -> newintsize=%d, newaddrsize=%d\n",
- newintsize, newaddrsize);
-
- /* Check for malformed properties */
- if (imaplen < (newaddrsize + newintsize))
- goto fail;
-
- imap += newaddrsize + newintsize;
- imaplen -= newaddrsize + newintsize;
-
- DBG(" -> imaplen=%d\n", imaplen);
- }
- if (!match)
- goto fail;
-
- of_node_put(old);
- old = of_node_get(newpar);
- addrsize = newaddrsize;
- intsize = newintsize;
- intspec = imap - intsize;
- addr = intspec - addrsize;
-
- skiplevel:
- /* Iterate again with new parent */
- DBG(" -> new parent: %s\n", newpar ? newpar->full_name : "<>");
- of_node_put(ipar);
- ipar = newpar;
- newpar = NULL;
- }
- fail:
- of_node_put(ipar);
- of_node_put(old);
- of_node_put(newpar);
-
- return -EINVAL;
-}
-EXPORT_SYMBOL_GPL(of_irq_map_raw);
-
-#if defined(CONFIG_PPC_PMAC) && defined(CONFIG_PPC32)
-static int of_irq_map_oldworld(struct device_node *device, int index,
- struct of_irq *out_irq)
-{
- const u32 *ints = NULL;
- int intlen;
-
- /*
- * Old machines just have a list of interrupt numbers
- * and no interrupt-controller nodes. We also have dodgy
- * cases where the APPL,interrupts property is completely
- * missing behind pci-pci bridges and we have to get it
- * from the parent (the bridge itself, as apple just wired
- * everything together on these)
- */
- while (device) {
- ints = of_get_property(device, "AAPL,interrupts", &intlen);
- if (ints != NULL)
- break;
- device = device->parent;
- if (device && strcmp(device->type, "pci") != 0)
- break;
- }
- if (ints == NULL)
- return -EINVAL;
- intlen /= sizeof(u32);
-
- if (index >= intlen)
- return -EINVAL;
-
- out_irq->controller = NULL;
- out_irq->specifier[0] = ints[index];
- out_irq->size = 1;
-
- return 0;
-}
-#else /* defined(CONFIG_PPC_PMAC) && defined(CONFIG_PPC32) */
-static int of_irq_map_oldworld(struct device_node *device, int index,
- struct of_irq *out_irq)
-{
- return -EINVAL;
-}
-#endif /* !(defined(CONFIG_PPC_PMAC) && defined(CONFIG_PPC32)) */
-
-int of_irq_map_one(struct device_node *device, int index, struct of_irq *out_irq)
-{
- struct device_node *p;
- const u32 *intspec, *tmp, *addr;
- u32 intsize, intlen;
- int res = -EINVAL;
-
- DBG("of_irq_map_one: dev=%s, index=%d\n", device->full_name, index);
-
- /* OldWorld mac stuff is "special", handle out of line */
- if (of_irq_workarounds & OF_IMAP_OLDWORLD_MAC)
- return of_irq_map_oldworld(device, index, out_irq);
-
- /* Get the interrupts property */
- intspec = of_get_property(device, "interrupts", &intlen);
- if (intspec == NULL)
- return -EINVAL;
- intlen /= sizeof(u32);
-
- /* Get the reg property (if any) */
- addr = of_get_property(device, "reg", NULL);
-
- /* Look for the interrupt parent. */
- p = of_irq_find_parent(device);
- if (p == NULL)
- return -EINVAL;
-
- /* Get size of interrupt specifier */
- tmp = of_get_property(p, "#interrupt-cells", NULL);
- if (tmp == NULL)
- goto out;
- intsize = *tmp;
-
- DBG(" intsize=%d intlen=%d\n", intsize, intlen);
-
- /* Check index */
- if ((index + 1) * intsize > intlen)
- goto out;
-
- /* Get new specifier and map it */
- res = of_irq_map_raw(p, intspec + index * intsize, intsize,
- addr, out_irq);
-out:
- of_node_put(p);
- return res;
-}
-EXPORT_SYMBOL_GPL(of_irq_map_one);
-
/**
* Search the device tree for the best MAC address to use. 'mac-address' is
* checked first, because that is supposed to contain to "most recent" MAC
@@ -1051,29 +155,3 @@ const void *of_get_mac_address(struct device_node *np)
return NULL;
}
EXPORT_SYMBOL(of_get_mac_address);
-
-int of_irq_to_resource(struct device_node *dev, int index, struct resource *r)
-{
- int irq = irq_of_parse_and_map(dev, index);
-
- /* Only dereference the resource if both the
- * resource and the irq are valid. */
- if (r && irq != NO_IRQ) {
- r->start = r->end = irq;
- r->flags = IORESOURCE_IRQ;
- }
-
- return irq;
-}
-EXPORT_SYMBOL_GPL(of_irq_to_resource);
-
-void __iomem *of_iomap(struct device_node *np, int index)
-{
- struct resource res;
-
- if (of_address_to_resource(np, index, &res))
- return NULL;
-
- return ioremap(res.start, 1 + res.end - res.start);
-}
-EXPORT_SYMBOL(of_iomap);
diff --git a/arch/powerpc/kernel/ptrace.c b/arch/powerpc/kernel/ptrace.c
index 7a0c0199ea2..11f3cd9c832 100644
--- a/arch/powerpc/kernel/ptrace.c
+++ b/arch/powerpc/kernel/ptrace.c
@@ -32,6 +32,8 @@
#ifdef CONFIG_PPC32
#include <linux/module.h>
#endif
+#include <linux/hw_breakpoint.h>
+#include <linux/perf_event.h>
#include <asm/uaccess.h>
#include <asm/page.h>
@@ -866,9 +868,34 @@ void user_disable_single_step(struct task_struct *task)
clear_tsk_thread_flag(task, TIF_SINGLESTEP);
}
+#ifdef CONFIG_HAVE_HW_BREAKPOINT
+void ptrace_triggered(struct perf_event *bp, int nmi,
+ struct perf_sample_data *data, struct pt_regs *regs)
+{
+ struct perf_event_attr attr;
+
+ /*
+ * Disable the breakpoint request here since ptrace has defined a
+ * one-shot behaviour for breakpoint exceptions in PPC64.
+ * The SIGTRAP signal is generated automatically for us in do_dabr().
+ * We don't have to do anything about that here
+ */
+ attr = bp->attr;
+ attr.disabled = true;
+ modify_user_hw_breakpoint(bp, &attr);
+}
+#endif /* CONFIG_HAVE_HW_BREAKPOINT */
+
int ptrace_set_debugreg(struct task_struct *task, unsigned long addr,
unsigned long data)
{
+#ifdef CONFIG_HAVE_HW_BREAKPOINT
+ int ret;
+ struct thread_struct *thread = &(task->thread);
+ struct perf_event *bp;
+ struct perf_event_attr attr;
+#endif /* CONFIG_HAVE_HW_BREAKPOINT */
+
/* For ppc64 we support one DABR and no IABR's at the moment (ppc64).
* For embedded processors we support one DAC and no IAC's at the
* moment.
@@ -896,6 +923,43 @@ int ptrace_set_debugreg(struct task_struct *task, unsigned long addr,
/* Ensure breakpoint translation bit is set */
if (data && !(data & DABR_TRANSLATION))
return -EIO;
+#ifdef CONFIG_HAVE_HW_BREAKPOINT
+ bp = thread->ptrace_bps[0];
+ if ((!data) || !(data & (DABR_DATA_WRITE | DABR_DATA_READ))) {
+ if (bp) {
+ unregister_hw_breakpoint(bp);
+ thread->ptrace_bps[0] = NULL;
+ }
+ return 0;
+ }
+ if (bp) {
+ attr = bp->attr;
+ attr.bp_addr = data & ~HW_BREAKPOINT_ALIGN;
+ arch_bp_generic_fields(data &
+ (DABR_DATA_WRITE | DABR_DATA_READ),
+ &attr.bp_type);
+ ret = modify_user_hw_breakpoint(bp, &attr);
+ if (ret)
+ return ret;
+ thread->ptrace_bps[0] = bp;
+ thread->dabr = data;
+ return 0;
+ }
+
+ /* Create a new breakpoint request if one doesn't exist already */
+ hw_breakpoint_init(&attr);
+ attr.bp_addr = data & ~HW_BREAKPOINT_ALIGN;
+ arch_bp_generic_fields(data & (DABR_DATA_WRITE | DABR_DATA_READ),
+ &attr.bp_type);
+
+ thread->ptrace_bps[0] = bp = register_user_hw_breakpoint(&attr,
+ ptrace_triggered, task);
+ if (IS_ERR(bp)) {
+ thread->ptrace_bps[0] = NULL;
+ return PTR_ERR(bp);
+ }
+
+#endif /* CONFIG_HAVE_HW_BREAKPOINT */
/* Move contents to the DABR register */
task->thread.dabr = data;
diff --git a/arch/powerpc/kernel/rtas.c b/arch/powerpc/kernel/rtas.c
index d0516dbee76..41048de3c6c 100644
--- a/arch/powerpc/kernel/rtas.c
+++ b/arch/powerpc/kernel/rtas.c
@@ -47,14 +47,6 @@ struct rtas_t rtas = {
};
EXPORT_SYMBOL(rtas);
-struct rtas_suspend_me_data {
- atomic_t working; /* number of cpus accessing this struct */
- atomic_t done;
- int token; /* ibm,suspend-me */
- int error;
- struct completion *complete; /* wait on this until working == 0 */
-};
-
DEFINE_SPINLOCK(rtas_data_buf_lock);
EXPORT_SYMBOL(rtas_data_buf_lock);
@@ -714,14 +706,53 @@ void rtas_os_term(char *str)
static int ibm_suspend_me_token = RTAS_UNKNOWN_SERVICE;
#ifdef CONFIG_PPC_PSERIES
-static void rtas_percpu_suspend_me(void *info)
+static int __rtas_suspend_last_cpu(struct rtas_suspend_me_data *data, int wake_when_done)
+{
+ u16 slb_size = mmu_slb_size;
+ int rc = H_MULTI_THREADS_ACTIVE;
+ int cpu;
+
+ slb_set_size(SLB_MIN_SIZE);
+ printk(KERN_DEBUG "calling ibm,suspend-me on cpu %i\n", smp_processor_id());
+
+ while (rc == H_MULTI_THREADS_ACTIVE && !atomic_read(&data->done) &&
+ !atomic_read(&data->error))
+ rc = rtas_call(data->token, 0, 1, NULL);
+
+ if (rc || atomic_read(&data->error)) {
+ printk(KERN_DEBUG "ibm,suspend-me returned %d\n", rc);
+ slb_set_size(slb_size);
+ }
+
+ if (atomic_read(&data->error))
+ rc = atomic_read(&data->error);
+
+ atomic_set(&data->error, rc);
+
+ if (wake_when_done) {
+ atomic_set(&data->done, 1);
+
+ for_each_online_cpu(cpu)
+ plpar_hcall_norets(H_PROD, get_hard_smp_processor_id(cpu));
+ }
+
+ if (atomic_dec_return(&data->working) == 0)
+ complete(data->complete);
+
+ return rc;
+}
+
+int rtas_suspend_last_cpu(struct rtas_suspend_me_data *data)
+{
+ atomic_inc(&data->working);
+ return __rtas_suspend_last_cpu(data, 0);
+}
+
+static int __rtas_suspend_cpu(struct rtas_suspend_me_data *data, int wake_when_done)
{
long rc = H_SUCCESS;
unsigned long msr_save;
- u16 slb_size = mmu_slb_size;
int cpu;
- struct rtas_suspend_me_data *data =
- (struct rtas_suspend_me_data *)info;
atomic_inc(&data->working);
@@ -729,7 +760,7 @@ static void rtas_percpu_suspend_me(void *info)
msr_save = mfmsr();
mtmsr(msr_save & ~(MSR_EE));
- while (rc == H_SUCCESS && !atomic_read(&data->done))
+ while (rc == H_SUCCESS && !atomic_read(&data->done) && !atomic_read(&data->error))
rc = plpar_hcall_norets(H_JOIN);
mtmsr(msr_save);
@@ -741,33 +772,37 @@ static void rtas_percpu_suspend_me(void *info)
/* All other cpus are in H_JOIN, this cpu does
* the suspend.
*/
- slb_set_size(SLB_MIN_SIZE);
- printk(KERN_DEBUG "calling ibm,suspend-me on cpu %i\n",
- smp_processor_id());
- data->error = rtas_call(data->token, 0, 1, NULL);
-
- if (data->error) {
- printk(KERN_DEBUG "ibm,suspend-me returned %d\n",
- data->error);
- slb_set_size(slb_size);
- }
+ return __rtas_suspend_last_cpu(data, wake_when_done);
} else {
printk(KERN_ERR "H_JOIN on cpu %i failed with rc = %ld\n",
smp_processor_id(), rc);
- data->error = rc;
+ atomic_set(&data->error, rc);
}
- atomic_set(&data->done, 1);
+ if (wake_when_done) {
+ atomic_set(&data->done, 1);
- /* This cpu did the suspend or got an error; in either case,
- * we need to prod all other other cpus out of join state.
- * Extra prods are harmless.
- */
- for_each_online_cpu(cpu)
- plpar_hcall_norets(H_PROD, get_hard_smp_processor_id(cpu));
+ /* This cpu did the suspend or got an error; in either case,
+ * we need to prod all other other cpus out of join state.
+ * Extra prods are harmless.
+ */
+ for_each_online_cpu(cpu)
+ plpar_hcall_norets(H_PROD, get_hard_smp_processor_id(cpu));
+ }
out:
if (atomic_dec_return(&data->working) == 0)
complete(data->complete);
+ return rc;
+}
+
+int rtas_suspend_cpu(struct rtas_suspend_me_data *data)
+{
+ return __rtas_suspend_cpu(data, 0);
+}
+
+static void rtas_percpu_suspend_me(void *info)
+{
+ __rtas_suspend_cpu((struct rtas_suspend_me_data *)info, 1);
}
static int rtas_ibm_suspend_me(struct rtas_args *args)
@@ -802,22 +837,22 @@ static int rtas_ibm_suspend_me(struct rtas_args *args)
atomic_set(&data.working, 0);
atomic_set(&data.done, 0);
+ atomic_set(&data.error, 0);
data.token = rtas_token("ibm,suspend-me");
- data.error = 0;
data.complete = &done;
/* Call function on all CPUs. One of us will make the
* rtas call
*/
if (on_each_cpu(rtas_percpu_suspend_me, &data, 0))
- data.error = -EINVAL;
+ atomic_set(&data.error, -EINVAL);
wait_for_completion(&done);
- if (data.error != 0)
+ if (atomic_read(&data.error) != 0)
printk(KERN_ERR "Error doing global join\n");
- return data.error;
+ return atomic_read(&data.error);
}
#else /* CONFIG_PPC_PSERIES */
static int rtas_ibm_suspend_me(struct rtas_args *args)
diff --git a/arch/powerpc/kernel/setup-common.c b/arch/powerpc/kernel/setup-common.c
index b7e6c7e193a..15ade0d7bbb 100644
--- a/arch/powerpc/kernel/setup-common.c
+++ b/arch/powerpc/kernel/setup-common.c
@@ -94,6 +94,10 @@ struct screen_info screen_info = {
.orig_video_points = 16
};
+/* Variables required to store legacy IO irq routing */
+int of_i8042_kbd_irq;
+int of_i8042_aux_irq;
+
#ifdef __DO_IRQ_CANON
/* XXX should go elsewhere eventually */
int ppc_do_canonicalize_irqs;
@@ -575,6 +579,15 @@ int check_legacy_ioport(unsigned long base_port)
np = of_find_compatible_node(NULL, NULL, "pnpPNP,f03");
if (np) {
parent = of_get_parent(np);
+
+ of_i8042_kbd_irq = irq_of_parse_and_map(parent, 0);
+ if (!of_i8042_kbd_irq)
+ of_i8042_kbd_irq = 1;
+
+ of_i8042_aux_irq = irq_of_parse_and_map(parent, 1);
+ if (!of_i8042_aux_irq)
+ of_i8042_aux_irq = 12;
+
of_node_put(np);
np = parent;
break;
@@ -701,16 +714,9 @@ static struct notifier_block ppc_dflt_plat_bus_notifier = {
.priority = INT_MAX,
};
-static struct notifier_block ppc_dflt_of_bus_notifier = {
- .notifier_call = ppc_dflt_bus_notify,
- .priority = INT_MAX,
-};
-
static int __init setup_bus_notifier(void)
{
bus_register_notifier(&platform_bus_type, &ppc_dflt_plat_bus_notifier);
- bus_register_notifier(&of_platform_bus_type, &ppc_dflt_of_bus_notifier);
-
return 0;
}
diff --git a/arch/powerpc/kernel/setup_64.c b/arch/powerpc/kernel/setup_64.c
index d135f93cb0f..1bee4b68fa4 100644
--- a/arch/powerpc/kernel/setup_64.c
+++ b/arch/powerpc/kernel/setup_64.c
@@ -142,16 +142,6 @@ early_param("smt-enabled", early_smt_enabled);
#define check_smt_enabled()
#endif /* CONFIG_SMP */
-/* Put the paca pointer into r13 and SPRG_PACA */
-static void __init setup_paca(struct paca_struct *new_paca)
-{
- local_paca = new_paca;
- mtspr(SPRN_SPRG_PACA, local_paca);
-#ifdef CONFIG_PPC_BOOK3E
- mtspr(SPRN_SPRG_TLB_EXFRAME, local_paca->extlb);
-#endif
-}
-
/*
* Early initialization entry point. This is called by head.S
* with MMU translation disabled. We rely on the "feature" of
@@ -600,6 +590,9 @@ static int pcpu_cpu_distance(unsigned int from, unsigned int to)
return REMOTE_DISTANCE;
}
+unsigned long __per_cpu_offset[NR_CPUS] __read_mostly;
+EXPORT_SYMBOL(__per_cpu_offset);
+
void __init setup_per_cpu_areas(void)
{
const size_t dyn_size = PERCPU_MODULE_RESERVE + PERCPU_DYNAMIC_RESERVE;
@@ -624,8 +617,10 @@ void __init setup_per_cpu_areas(void)
panic("cannot initialize percpu area (err=%d)", rc);
delta = (unsigned long)pcpu_base_addr - (unsigned long)__per_cpu_start;
- for_each_possible_cpu(cpu)
- paca[cpu].data_offset = delta + pcpu_unit_offsets[cpu];
+ for_each_possible_cpu(cpu) {
+ __per_cpu_offset[cpu] = delta + pcpu_unit_offsets[cpu];
+ paca[cpu].data_offset = __per_cpu_offset[cpu];
+ }
}
#endif
diff --git a/arch/powerpc/kernel/signal.c b/arch/powerpc/kernel/signal.c
index a0afb555a7c..7109f5b1baa 100644
--- a/arch/powerpc/kernel/signal.c
+++ b/arch/powerpc/kernel/signal.c
@@ -11,6 +11,7 @@
#include <linux/tracehook.h>
#include <linux/signal.h>
+#include <asm/hw_breakpoint.h>
#include <asm/uaccess.h>
#include <asm/unistd.h>
@@ -149,6 +150,8 @@ static int do_signal_pending(sigset_t *oldset, struct pt_regs *regs)
if (current->thread.dabr)
set_dabr(current->thread.dabr);
#endif
+ /* Re-enable the breakpoints for the signal stack */
+ thread_change_pc(current, regs);
if (is32) {
if (ka.sa.sa_flags & SA_SIGINFO)
diff --git a/arch/powerpc/kernel/smp.c b/arch/powerpc/kernel/smp.c
index 5c196d1086d..a61b3ddd7bb 100644
--- a/arch/powerpc/kernel/smp.c
+++ b/arch/powerpc/kernel/smp.c
@@ -288,8 +288,6 @@ void __init smp_prepare_cpus(unsigned int max_cpus)
max_cpus = NR_CPUS;
else
max_cpus = 1;
-
- smp_space_timers(max_cpus);
for_each_possible_cpu(cpu)
if (cpu != boot_cpuid)
@@ -501,14 +499,6 @@ int __devinit start_secondary(void *unused)
current->active_mm = &init_mm;
smp_store_cpu_info(cpu);
-
-#if defined(CONFIG_BOOKE) || defined(CONFIG_40x)
- /* Clear any pending timer interrupts */
- mtspr(SPRN_TSR, TSR_ENW | TSR_WIS | TSR_DIS | TSR_FIS);
-
- /* Enable decrementer interrupt */
- mtspr(SPRN_TCR, TCR_DIE);
-#endif
set_dec(tb_ticks_per_jiffy);
preempt_disable();
cpu_callin_map[cpu] = 1;
diff --git a/arch/powerpc/kernel/suspend.c b/arch/powerpc/kernel/suspend.c
index 6fc6328dc62..0167d53da30 100644
--- a/arch/powerpc/kernel/suspend.c
+++ b/arch/powerpc/kernel/suspend.c
@@ -3,7 +3,7 @@
*
* Distribute under GPLv2
*
- * Copyright (c) 2002 Pavel Machek <pavel@suse.cz>
+ * Copyright (c) 2002 Pavel Machek <pavel@ucw.cz>
* Copyright (c) 2001 Patrick Mochel <mochel@osdl.org>
*/
diff --git a/arch/powerpc/kernel/time.c b/arch/powerpc/kernel/time.c
index 0441bbdadbd..ce53dfa7130 100644
--- a/arch/powerpc/kernel/time.c
+++ b/arch/powerpc/kernel/time.c
@@ -149,16 +149,6 @@ unsigned long tb_ticks_per_usec = 100; /* sane default */
EXPORT_SYMBOL(tb_ticks_per_usec);
unsigned long tb_ticks_per_sec;
EXPORT_SYMBOL(tb_ticks_per_sec); /* for cputime_t conversions */
-u64 tb_to_xs;
-unsigned tb_to_us;
-
-#define TICKLEN_SCALE NTP_SCALE_SHIFT
-static u64 last_tick_len; /* units are ns / 2^TICKLEN_SCALE */
-static u64 ticklen_to_xs; /* 0.64 fraction */
-
-/* If last_tick_len corresponds to about 1/HZ seconds, then
- last_tick_len << TICKLEN_SHIFT will be about 2^63. */
-#define TICKLEN_SHIFT (63 - 30 - TICKLEN_SCALE + SHIFT_HZ)
DEFINE_SPINLOCK(rtc_lock);
EXPORT_SYMBOL_GPL(rtc_lock);
@@ -174,7 +164,6 @@ unsigned long ppc_proc_freq;
EXPORT_SYMBOL(ppc_proc_freq);
unsigned long ppc_tb_freq;
-static u64 tb_last_jiffy __cacheline_aligned_in_smp;
static DEFINE_PER_CPU(u64, last_jiffy);
#ifdef CONFIG_VIRT_CPU_ACCOUNTING
@@ -423,30 +412,6 @@ void udelay(unsigned long usecs)
}
EXPORT_SYMBOL(udelay);
-static inline void update_gtod(u64 new_tb_stamp, u64 new_stamp_xsec,
- u64 new_tb_to_xs)
-{
- /*
- * tb_update_count is used to allow the userspace gettimeofday code
- * to assure itself that it sees a consistent view of the tb_to_xs and
- * stamp_xsec variables. It reads the tb_update_count, then reads
- * tb_to_xs and stamp_xsec and then reads tb_update_count again. If
- * the two values of tb_update_count match and are even then the
- * tb_to_xs and stamp_xsec values are consistent. If not, then it
- * loops back and reads them again until this criteria is met.
- * We expect the caller to have done the first increment of
- * vdso_data->tb_update_count already.
- */
- vdso_data->tb_orig_stamp = new_tb_stamp;
- vdso_data->stamp_xsec = new_stamp_xsec;
- vdso_data->tb_to_xs = new_tb_to_xs;
- vdso_data->wtom_clock_sec = wall_to_monotonic.tv_sec;
- vdso_data->wtom_clock_nsec = wall_to_monotonic.tv_nsec;
- vdso_data->stamp_xtime = xtime;
- smp_wmb();
- ++(vdso_data->tb_update_count);
-}
-
#ifdef CONFIG_SMP
unsigned long profile_pc(struct pt_regs *regs)
{
@@ -470,7 +435,6 @@ EXPORT_SYMBOL(profile_pc);
static int __init iSeries_tb_recal(void)
{
- struct div_result divres;
unsigned long titan, tb;
/* Make sure we only run on iSeries */
@@ -501,10 +465,7 @@ static int __init iSeries_tb_recal(void)
tb_ticks_per_jiffy = new_tb_ticks_per_jiffy;
tb_ticks_per_sec = new_tb_ticks_per_sec;
calc_cputime_factors();
- div128_by_32( XSEC_PER_SEC, 0, tb_ticks_per_sec, &divres );
- tb_to_xs = divres.result_low;
vdso_data->tb_ticks_per_sec = tb_ticks_per_sec;
- vdso_data->tb_to_xs = tb_to_xs;
setup_cputime_one_jiffy();
}
else {
@@ -667,27 +628,9 @@ void timer_interrupt(struct pt_regs * regs)
trace_timer_interrupt_exit(regs);
}
-void wakeup_decrementer(void)
-{
- unsigned long ticks;
-
- /*
- * The timebase gets saved on sleep and restored on wakeup,
- * so all we need to do is to reset the decrementer.
- */
- ticks = tb_ticks_since(__get_cpu_var(last_jiffy));
- if (ticks < tb_ticks_per_jiffy)
- ticks = tb_ticks_per_jiffy - ticks;
- else
- ticks = 1;
- set_dec(ticks);
-}
-
#ifdef CONFIG_SUSPEND
-void generic_suspend_disable_irqs(void)
+static void generic_suspend_disable_irqs(void)
{
- preempt_disable();
-
/* Disable the decrementer, so that it doesn't interfere
* with suspending.
*/
@@ -697,12 +640,9 @@ void generic_suspend_disable_irqs(void)
set_dec(0x7fffffff);
}
-void generic_suspend_enable_irqs(void)
+static void generic_suspend_enable_irqs(void)
{
- wakeup_decrementer();
-
local_irq_enable();
- preempt_enable();
}
/* Overrides the weak version in kernel/power/main.c */
@@ -722,23 +662,6 @@ void arch_suspend_enable_irqs(void)
}
#endif
-#ifdef CONFIG_SMP
-void __init smp_space_timers(unsigned int max_cpus)
-{
- int i;
- u64 previous_tb = per_cpu(last_jiffy, boot_cpuid);
-
- /* make sure tb > per_cpu(last_jiffy, cpu) for all cpus always */
- previous_tb -= tb_ticks_per_jiffy;
-
- for_each_possible_cpu(i) {
- if (i == boot_cpuid)
- continue;
- per_cpu(last_jiffy, i) = previous_tb;
- }
-}
-#endif
-
/*
* Scheduler clock - returns current time in nanosec units.
*
@@ -873,10 +796,11 @@ static cycle_t timebase_read(struct clocksource *cs)
return (cycle_t)get_tb();
}
-void update_vsyscall(struct timespec *wall_time, struct clocksource *clock,
- u32 mult)
+void update_vsyscall(struct timespec *wall_time, struct timespec *wtm,
+ struct clocksource *clock, u32 mult)
{
- u64 t2x, stamp_xsec;
+ u64 new_tb_to_xs, new_stamp_xsec;
+ u32 frac_sec;
if (clock != &clocksource_timebase)
return;
@@ -887,11 +811,35 @@ void update_vsyscall(struct timespec *wall_time, struct clocksource *clock,
/* XXX this assumes clock->shift == 22 */
/* 4611686018 ~= 2^(20+64-22) / 1e9 */
- t2x = (u64) mult * 4611686018ULL;
- stamp_xsec = (u64) xtime.tv_nsec * XSEC_PER_SEC;
- do_div(stamp_xsec, 1000000000);
- stamp_xsec += (u64) xtime.tv_sec * XSEC_PER_SEC;
- update_gtod(clock->cycle_last, stamp_xsec, t2x);
+ new_tb_to_xs = (u64) mult * 4611686018ULL;
+ new_stamp_xsec = (u64) wall_time->tv_nsec * XSEC_PER_SEC;
+ do_div(new_stamp_xsec, 1000000000);
+ new_stamp_xsec += (u64) wall_time->tv_sec * XSEC_PER_SEC;
+
+ BUG_ON(wall_time->tv_nsec >= NSEC_PER_SEC);
+ /* this is tv_nsec / 1e9 as a 0.32 fraction */
+ frac_sec = ((u64) wall_time->tv_nsec * 18446744073ULL) >> 32;
+
+ /*
+ * tb_update_count is used to allow the userspace gettimeofday code
+ * to assure itself that it sees a consistent view of the tb_to_xs and
+ * stamp_xsec variables. It reads the tb_update_count, then reads
+ * tb_to_xs and stamp_xsec and then reads tb_update_count again. If
+ * the two values of tb_update_count match and are even then the
+ * tb_to_xs and stamp_xsec values are consistent. If not, then it
+ * loops back and reads them again until this criteria is met.
+ * We expect the caller to have done the first increment of
+ * vdso_data->tb_update_count already.
+ */
+ vdso_data->tb_orig_stamp = clock->cycle_last;
+ vdso_data->stamp_xsec = new_stamp_xsec;
+ vdso_data->tb_to_xs = new_tb_to_xs;
+ vdso_data->wtom_clock_sec = wtm->tv_sec;
+ vdso_data->wtom_clock_nsec = wtm->tv_nsec;
+ vdso_data->stamp_xtime = *wall_time;
+ vdso_data->stamp_sec_fraction = frac_sec;
+ smp_wmb();
+ ++(vdso_data->tb_update_count);
}
void update_vsyscall_tz(void)
@@ -1007,15 +955,13 @@ void secondary_cpu_time_init(void)
/* This function is only called on the boot processor */
void __init time_init(void)
{
- unsigned long flags;
struct div_result res;
- u64 scale, x;
+ u64 scale;
unsigned shift;
if (__USE_RTC()) {
/* 601 processor: dec counts down by 128 every 128ns */
ppc_tb_freq = 1000000000;
- tb_last_jiffy = get_rtcl();
} else {
/* Normal PowerPC with timebase register */
ppc_md.calibrate_decr();
@@ -1023,50 +969,15 @@ void __init time_init(void)
ppc_tb_freq / 1000000, ppc_tb_freq % 1000000);
printk(KERN_DEBUG "time_init: processor frequency = %lu.%.6lu MHz\n",
ppc_proc_freq / 1000000, ppc_proc_freq % 1000000);
- tb_last_jiffy = get_tb();
}
tb_ticks_per_jiffy = ppc_tb_freq / HZ;
tb_ticks_per_sec = ppc_tb_freq;
tb_ticks_per_usec = ppc_tb_freq / 1000000;
- tb_to_us = mulhwu_scale_factor(ppc_tb_freq, 1000000);
calc_cputime_factors();
setup_cputime_one_jiffy();
/*
- * Calculate the length of each tick in ns. It will not be
- * exactly 1e9/HZ unless ppc_tb_freq is divisible by HZ.
- * We compute 1e9 * tb_ticks_per_jiffy / ppc_tb_freq,
- * rounded up.
- */
- x = (u64) NSEC_PER_SEC * tb_ticks_per_jiffy + ppc_tb_freq - 1;
- do_div(x, ppc_tb_freq);
- tick_nsec = x;
- last_tick_len = x << TICKLEN_SCALE;
-
- /*
- * Compute ticklen_to_xs, which is a factor which gets multiplied
- * by (last_tick_len << TICKLEN_SHIFT) to get a tb_to_xs value.
- * It is computed as:
- * ticklen_to_xs = 2^N / (tb_ticks_per_jiffy * 1e9)
- * where N = 64 + 20 - TICKLEN_SCALE - TICKLEN_SHIFT
- * which turns out to be N = 51 - SHIFT_HZ.
- * This gives the result as a 0.64 fixed-point fraction.
- * That value is reduced by an offset amounting to 1 xsec per
- * 2^31 timebase ticks to avoid problems with time going backwards
- * by 1 xsec when we do timer_recalc_offset due to losing the
- * fractional xsec. That offset is equal to ppc_tb_freq/2^51
- * since there are 2^20 xsec in a second.
- */
- div128_by_32((1ULL << 51) - ppc_tb_freq, 0,
- tb_ticks_per_jiffy << SHIFT_HZ, &res);
- div128_by_32(res.result_high, res.result_low, NSEC_PER_SEC, &res);
- ticklen_to_xs = res.result_low;
-
- /* Compute tb_to_xs from tick_nsec */
- tb_to_xs = mulhdu(last_tick_len << TICKLEN_SHIFT, ticklen_to_xs);
-
- /*
* Compute scale factor for sched_clock.
* The calibrate_decr() function has set tb_ticks_per_sec,
* which is the timebase frequency.
@@ -1087,21 +998,14 @@ void __init time_init(void)
/* Save the current timebase to pretty up CONFIG_PRINTK_TIME */
boot_tb = get_tb_or_rtc();
- write_seqlock_irqsave(&xtime_lock, flags);
-
/* If platform provided a timezone (pmac), we correct the time */
if (timezone_offset) {
sys_tz.tz_minuteswest = -timezone_offset / 60;
sys_tz.tz_dsttime = 0;
}
- vdso_data->tb_orig_stamp = tb_last_jiffy;
vdso_data->tb_update_count = 0;
vdso_data->tb_ticks_per_sec = tb_ticks_per_sec;
- vdso_data->stamp_xsec = (u64) xtime.tv_sec * XSEC_PER_SEC;
- vdso_data->tb_to_xs = tb_to_xs;
-
- write_sequnlock_irqrestore(&xtime_lock, flags);
/* Start the decrementer on CPUs that have manual control
* such as BookE
@@ -1195,39 +1099,6 @@ void to_tm(int tim, struct rtc_time * tm)
GregorianDay(tm);
}
-/* Auxiliary function to compute scaling factors */
-/* Actually the choice of a timebase running at 1/4 the of the bus
- * frequency giving resolution of a few tens of nanoseconds is quite nice.
- * It makes this computation very precise (27-28 bits typically) which
- * is optimistic considering the stability of most processor clock
- * oscillators and the precision with which the timebase frequency
- * is measured but does not harm.
- */
-unsigned mulhwu_scale_factor(unsigned inscale, unsigned outscale)
-{
- unsigned mlt=0, tmp, err;
- /* No concern for performance, it's done once: use a stupid
- * but safe and compact method to find the multiplier.
- */
-
- for (tmp = 1U<<31; tmp != 0; tmp >>= 1) {
- if (mulhwu(inscale, mlt|tmp) < outscale)
- mlt |= tmp;
- }
-
- /* We might still be off by 1 for the best approximation.
- * A side effect of this is that if outscale is too large
- * the returned value will be zero.
- * Many corner cases have been checked and seem to work,
- * some might have been forgotten in the test however.
- */
-
- err = inscale * (mlt+1);
- if (err <= inscale/2)
- mlt++;
- return mlt;
-}
-
/*
* Divide a 128-bit dividend by a 32-bit divisor, leaving a 128 bit
* result.
diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c
index 25fc33984c2..a45a63c3a0c 100644
--- a/arch/powerpc/kernel/traps.c
+++ b/arch/powerpc/kernel/traps.c
@@ -55,9 +55,6 @@
#endif
#include <asm/kexec.h>
#include <asm/ppc-opcode.h>
-#ifdef CONFIG_FSL_BOOKE
-#include <asm/dbell.h>
-#endif
#if defined(CONFIG_DEBUGGER) || defined(CONFIG_KEXEC)
int (*__debugger)(struct pt_regs *regs) __read_mostly;
@@ -688,7 +685,7 @@ void RunModeException(struct pt_regs *regs)
void __kprobes single_step_exception(struct pt_regs *regs)
{
- regs->msr &= ~(MSR_SE | MSR_BE); /* Turn off 'trace' bits */
+ clear_single_step(regs);
if (notify_die(DIE_SSTEP, "single_step", regs, 5,
5, SIGTRAP) == NOTIFY_STOP)
@@ -707,10 +704,8 @@ void __kprobes single_step_exception(struct pt_regs *regs)
*/
static void emulate_single_step(struct pt_regs *regs)
{
- if (single_stepping(regs)) {
- clear_single_step(regs);
- _exception(SIGTRAP, regs, TRAP_TRACE, 0);
- }
+ if (single_stepping(regs))
+ single_step_exception(regs);
}
static inline int __parse_fpscr(unsigned long fpscr)
@@ -1344,24 +1339,6 @@ void vsx_assist_exception(struct pt_regs *regs)
#endif /* CONFIG_VSX */
#ifdef CONFIG_FSL_BOOKE
-
-void doorbell_exception(struct pt_regs *regs)
-{
-#ifdef CONFIG_SMP
- int cpu = smp_processor_id();
- int msg;
-
- if (num_online_cpus() < 2)
- return;
-
- for (msg = 0; msg < 4; msg++)
- if (test_and_clear_bit(msg, &dbell_smp_message[cpu]))
- smp_message_recv(msg);
-#else
- printk(KERN_WARNING "Received doorbell on non-smp system\n");
-#endif
-}
-
void CacheLockingException(struct pt_regs *regs, unsigned long address,
unsigned long error_code)
{
diff --git a/arch/powerpc/kernel/vdso32/gettimeofday.S b/arch/powerpc/kernel/vdso32/gettimeofday.S
index ee038d4bf25..4ee09ee2e83 100644
--- a/arch/powerpc/kernel/vdso32/gettimeofday.S
+++ b/arch/powerpc/kernel/vdso32/gettimeofday.S
@@ -19,8 +19,10 @@
/* Offset for the low 32-bit part of a field of long type */
#ifdef CONFIG_PPC64
#define LOPART 4
+#define TSPEC_TV_SEC TSPC64_TV_SEC+LOPART
#else
#define LOPART 0
+#define TSPEC_TV_SEC TSPC32_TV_SEC
#endif
.text
@@ -41,23 +43,11 @@ V_FUNCTION_BEGIN(__kernel_gettimeofday)
mr r9, r3 /* datapage ptr in r9 */
cmplwi r10,0 /* check if tv is NULL */
beq 3f
- bl __do_get_xsec@local /* get xsec from tb & kernel */
- bne- 2f /* out of line -> do syscall */
-
- /* seconds are xsec >> 20 */
- rlwinm r5,r4,12,20,31
- rlwimi r5,r3,12,0,19
- stw r5,TVAL32_TV_SEC(r10)
-
- /* get remaining xsec and convert to usec. we scale
- * up remaining xsec by 12 bits and get the top 32 bits
- * of the multiplication
- */
- rlwinm r5,r4,12,0,19
- lis r6,1000000@h
- ori r6,r6,1000000@l
- mulhwu r5,r5,r6
- stw r5,TVAL32_TV_USEC(r10)
+ lis r7,1000000@ha /* load up USEC_PER_SEC */
+ addi r7,r7,1000000@l /* so we get microseconds in r4 */
+ bl __do_get_tspec@local /* get sec/usec from tb & kernel */
+ stw r3,TVAL32_TV_SEC(r10)
+ stw r4,TVAL32_TV_USEC(r10)
3: cmplwi r11,0 /* check if tz is NULL */
beq 1f
@@ -70,14 +60,6 @@ V_FUNCTION_BEGIN(__kernel_gettimeofday)
crclr cr0*4+so
li r3,0
blr
-
-2:
- mtlr r12
- mr r3,r10
- mr r4,r11
- li r0,__NR_gettimeofday
- sc
- blr
.cfi_endproc
V_FUNCTION_END(__kernel_gettimeofday)
@@ -100,7 +82,8 @@ V_FUNCTION_BEGIN(__kernel_clock_gettime)
mr r11,r4 /* r11 saves tp */
bl __get_datapage@local /* get data page */
mr r9,r3 /* datapage ptr in r9 */
-
+ lis r7,NSEC_PER_SEC@h /* want nanoseconds */
+ ori r7,r7,NSEC_PER_SEC@l
50: bl __do_get_tspec@local /* get sec/nsec from tb & kernel */
bne cr1,80f /* not monotonic -> all done */
@@ -198,83 +181,12 @@ V_FUNCTION_END(__kernel_clock_getres)
/*
- * This is the core of gettimeofday() & friends, it returns the xsec
- * value in r3 & r4 and expects the datapage ptr (non clobbered)
- * in r9. clobbers r0,r4,r5,r6,r7,r8.
- * When returning, r8 contains the counter value that can be reused
- * by the monotonic clock implementation
- */
-__do_get_xsec:
- .cfi_startproc
- /* Check for update count & load values. We use the low
- * order 32 bits of the update count
- */
-1: lwz r8,(CFG_TB_UPDATE_COUNT+LOPART)(r9)
- andi. r0,r8,1 /* pending update ? loop */
- bne- 1b
- xor r0,r8,r8 /* create dependency */
- add r9,r9,r0
-
- /* Load orig stamp (offset to TB) */
- lwz r5,CFG_TB_ORIG_STAMP(r9)
- lwz r6,(CFG_TB_ORIG_STAMP+4)(r9)
-
- /* Get a stable TB value */
-2: mftbu r3
- mftbl r4
- mftbu r0
- cmpl cr0,r3,r0
- bne- 2b
-
- /* Substract tb orig stamp. If the high part is non-zero, we jump to
- * the slow path which call the syscall.
- * If it's ok, then we have our 32 bits tb_ticks value in r7
- */
- subfc r7,r6,r4
- subfe. r0,r5,r3
- bne- 3f
-
- /* Load scale factor & do multiplication */
- lwz r5,CFG_TB_TO_XS(r9) /* load values */
- lwz r6,(CFG_TB_TO_XS+4)(r9)
- mulhwu r4,r7,r5
- mulhwu r6,r7,r6
- mullw r0,r7,r5
- addc r6,r6,r0
-
- /* At this point, we have the scaled xsec value in r4 + XER:CA
- * we load & add the stamp since epoch
- */
- lwz r5,CFG_STAMP_XSEC(r9)
- lwz r6,(CFG_STAMP_XSEC+4)(r9)
- adde r4,r4,r6
- addze r3,r5
-
- /* We now have our result in r3,r4. We create a fake dependency
- * on that result and re-check the counter
- */
- or r6,r4,r3
- xor r0,r6,r6
- add r9,r9,r0
- lwz r0,(CFG_TB_UPDATE_COUNT+LOPART)(r9)
- cmpl cr0,r8,r0 /* check if updated */
- bne- 1b
-
- /* Warning ! The caller expects CR:EQ to be set to indicate a
- * successful calculation (so it won't fallback to the syscall
- * method). We have overriden that CR bit in the counter check,
- * but fortunately, the loop exit condition _is_ CR:EQ set, so
- * we can exit safely here. If you change this code, be careful
- * of that side effect.
- */
-3: blr
- .cfi_endproc
-
-/*
- * This is the core of clock_gettime(), it returns the current
- * time in seconds and nanoseconds in r3 and r4.
+ * This is the core of clock_gettime() and gettimeofday(),
+ * it returns the current time in r3 (seconds) and r4.
+ * On entry, r7 gives the resolution of r4, either USEC_PER_SEC
+ * or NSEC_PER_SEC, giving r4 in microseconds or nanoseconds.
* It expects the datapage ptr in r9 and doesn't clobber it.
- * It clobbers r0, r5, r6, r10 and returns NSEC_PER_SEC in r7.
+ * It clobbers r0, r5 and r6.
* On return, r8 contains the counter value that can be reused.
* This clobbers cr0 but not any other cr field.
*/
@@ -297,70 +209,58 @@ __do_get_tspec:
2: mftbu r3
mftbl r4
mftbu r0
- cmpl cr0,r3,r0
+ cmplw cr0,r3,r0
bne- 2b
/* Subtract tb orig stamp and shift left 12 bits.
*/
- subfc r7,r6,r4
+ subfc r4,r6,r4
subfe r0,r5,r3
slwi r0,r0,12
- rlwimi. r0,r7,12,20,31
- slwi r7,r7,12
+ rlwimi. r0,r4,12,20,31
+ slwi r4,r4,12
- /* Load scale factor & do multiplication */
+ /*
+ * Load scale factor & do multiplication.
+ * We only use the high 32 bits of the tb_to_xs value.
+ * Even with a 1GHz timebase clock, the high 32 bits of
+ * tb_to_xs will be at least 4 million, so the error from
+ * ignoring the low 32 bits will be no more than 0.25ppm.
+ * The error will just make the clock run very very slightly
+ * slow until the next time the kernel updates the VDSO data,
+ * at which point the clock will catch up to the kernel's value,
+ * so there is no long-term error accumulation.
+ */
lwz r5,CFG_TB_TO_XS(r9) /* load values */
- lwz r6,(CFG_TB_TO_XS+4)(r9)
- mulhwu r3,r7,r6
- mullw r10,r7,r5
- mulhwu r4,r7,r5
- addc r10,r3,r10
+ mulhwu r4,r4,r5
li r3,0
beq+ 4f /* skip high part computation if 0 */
mulhwu r3,r0,r5
- mullw r7,r0,r5
- mulhwu r5,r0,r6
- mullw r6,r0,r6
- adde r4,r4,r7
- addze r3,r3
+ mullw r5,r0,r5
addc r4,r4,r5
addze r3,r3
- addc r10,r10,r6
-
-4: addze r4,r4 /* add in carry */
- lis r7,NSEC_PER_SEC@h
- ori r7,r7,NSEC_PER_SEC@l
- mulhwu r4,r4,r7 /* convert to nanoseconds */
-
- /* At this point, we have seconds & nanoseconds since the xtime
- * stamp in r3+CA and r4. Load & add the xtime stamp.
+4:
+ /* At this point, we have seconds since the xtime stamp
+ * as a 32.32 fixed-point number in r3 and r4.
+ * Load & add the xtime stamp.
*/
-#ifdef CONFIG_PPC64
- lwz r5,STAMP_XTIME+TSPC64_TV_SEC+LOPART(r9)
- lwz r6,STAMP_XTIME+TSPC64_TV_NSEC+LOPART(r9)
-#else
- lwz r5,STAMP_XTIME+TSPC32_TV_SEC(r9)
- lwz r6,STAMP_XTIME+TSPC32_TV_NSEC(r9)
-#endif
- add r4,r4,r6
+ lwz r5,STAMP_XTIME+TSPEC_TV_SEC(r9)
+ lwz r6,STAMP_SEC_FRAC(r9)
+ addc r4,r4,r6
adde r3,r3,r5
- /* We now have our result in r3,r4. We create a fake dependency
- * on that result and re-check the counter
+ /* We create a fake dependency on the result in r3/r4
+ * and re-check the counter
*/
or r6,r4,r3
xor r0,r6,r6
add r9,r9,r0
lwz r0,(CFG_TB_UPDATE_COUNT+LOPART)(r9)
- cmpl cr0,r8,r0 /* check if updated */
+ cmplw cr0,r8,r0 /* check if updated */
bne- 1b
- /* check for nanosecond overflow and adjust if necessary */
- cmpw r4,r7
- bltlr /* all done if no overflow */
- subf r4,r7,r4 /* adjust if overflow */
- addi r3,r3,1
+ mulhwu r4,r4,r7 /* convert to micro or nanoseconds */
blr
.cfi_endproc
diff --git a/arch/powerpc/kernel/vdso64/gettimeofday.S b/arch/powerpc/kernel/vdso64/gettimeofday.S
index 262cd5857a5..e97a9a0dc4a 100644
--- a/arch/powerpc/kernel/vdso64/gettimeofday.S
+++ b/arch/powerpc/kernel/vdso64/gettimeofday.S
@@ -33,18 +33,11 @@ V_FUNCTION_BEGIN(__kernel_gettimeofday)
bl V_LOCAL_FUNC(__get_datapage) /* get data page */
cmpldi r11,0 /* check if tv is NULL */
beq 2f
- bl V_LOCAL_FUNC(__do_get_xsec) /* get xsec from tb & kernel */
- lis r7,15 /* r7 = 1000000 = USEC_PER_SEC */
- ori r7,r7,16960
- rldicl r5,r4,44,20 /* r5 = sec = xsec / XSEC_PER_SEC */
- rldicr r6,r5,20,43 /* r6 = sec * XSEC_PER_SEC */
- std r5,TVAL64_TV_SEC(r11) /* store sec in tv */
- subf r0,r6,r4 /* r0 = xsec = (xsec - r6) */
- mulld r0,r0,r7 /* usec = (xsec * USEC_PER_SEC) /
- * XSEC_PER_SEC
- */
- rldicl r0,r0,44,20
- std r0,TVAL64_TV_USEC(r11) /* store usec in tv */
+ lis r7,1000000@ha /* load up USEC_PER_SEC */
+ addi r7,r7,1000000@l
+ bl V_LOCAL_FUNC(__do_get_tspec) /* get sec/us from tb & kernel */
+ std r4,TVAL64_TV_SEC(r11) /* store sec in tv */
+ std r5,TVAL64_TV_USEC(r11) /* store usec in tv */
2: cmpldi r10,0 /* check if tz is NULL */
beq 1f
lwz r4,CFG_TZ_MINUTEWEST(r3)/* fill tz */
@@ -77,6 +70,8 @@ V_FUNCTION_BEGIN(__kernel_clock_gettime)
.cfi_register lr,r12
mr r11,r4 /* r11 saves tp */
bl V_LOCAL_FUNC(__get_datapage) /* get data page */
+ lis r7,NSEC_PER_SEC@h /* want nanoseconds */
+ ori r7,r7,NSEC_PER_SEC@l
50: bl V_LOCAL_FUNC(__do_get_tspec) /* get time from tb & kernel */
bne cr1,80f /* if not monotonic, all done */
@@ -171,49 +166,12 @@ V_FUNCTION_END(__kernel_clock_getres)
/*
- * This is the core of gettimeofday(), it returns the xsec
- * value in r4 and expects the datapage ptr (non clobbered)
- * in r3. clobbers r0,r4,r5,r6,r7,r8
- * When returning, r8 contains the counter value that can be reused
- */
-V_FUNCTION_BEGIN(__do_get_xsec)
- .cfi_startproc
- /* check for update count & load values */
-1: ld r8,CFG_TB_UPDATE_COUNT(r3)
- andi. r0,r8,1 /* pending update ? loop */
- bne- 1b
- xor r0,r8,r8 /* create dependency */
- add r3,r3,r0
-
- /* Get TB & offset it. We use the MFTB macro which will generate
- * workaround code for Cell.
- */
- MFTB(r7)
- ld r9,CFG_TB_ORIG_STAMP(r3)
- subf r7,r9,r7
-
- /* Scale result */
- ld r5,CFG_TB_TO_XS(r3)
- mulhdu r7,r7,r5
-
- /* Add stamp since epoch */
- ld r6,CFG_STAMP_XSEC(r3)
- add r4,r6,r7
-
- xor r0,r4,r4
- add r3,r3,r0
- ld r0,CFG_TB_UPDATE_COUNT(r3)
- cmpld cr0,r0,r8 /* check if updated */
- bne- 1b
- blr
- .cfi_endproc
-V_FUNCTION_END(__do_get_xsec)
-
-/*
- * This is the core of clock_gettime(), it returns the current
- * time in seconds and nanoseconds in r4 and r5.
+ * This is the core of clock_gettime() and gettimeofday(),
+ * it returns the current time in r4 (seconds) and r5.
+ * On entry, r7 gives the resolution of r5, either USEC_PER_SEC
+ * or NSEC_PER_SEC, giving r5 in microseconds or nanoseconds.
* It expects the datapage ptr in r3 and doesn't clobber it.
- * It clobbers r0 and r6 and returns NSEC_PER_SEC in r7.
+ * It clobbers r0, r6 and r9.
* On return, r8 contains the counter value that can be reused.
* This clobbers cr0 but not any other cr field.
*/
@@ -229,18 +187,18 @@ V_FUNCTION_BEGIN(__do_get_tspec)
/* Get TB & offset it. We use the MFTB macro which will generate
* workaround code for Cell.
*/
- MFTB(r7)
+ MFTB(r6)
ld r9,CFG_TB_ORIG_STAMP(r3)
- subf r7,r9,r7
+ subf r6,r9,r6
/* Scale result */
ld r5,CFG_TB_TO_XS(r3)
- sldi r7,r7,12 /* compute time since stamp_xtime */
- mulhdu r6,r7,r5 /* in units of 2^-32 seconds */
+ sldi r6,r6,12 /* compute time since stamp_xtime */
+ mulhdu r6,r6,r5 /* in units of 2^-32 seconds */
/* Add stamp since epoch */
ld r4,STAMP_XTIME+TSPC64_TV_SEC(r3)
- ld r5,STAMP_XTIME+TSPC64_TV_NSEC(r3)
+ lwz r5,STAMP_SEC_FRAC(r3)
or r0,r4,r5
or r0,r0,r6
xor r0,r0,r0
@@ -250,17 +208,11 @@ V_FUNCTION_BEGIN(__do_get_tspec)
bne- 1b /* reload if so */
/* convert to seconds & nanoseconds and add to stamp */
- lis r7,NSEC_PER_SEC@h
- ori r7,r7,NSEC_PER_SEC@l
- mulhwu r0,r6,r7 /* compute nanoseconds and */
+ add r6,r6,r5 /* add on fractional seconds of xtime */
+ mulhwu r5,r6,r7 /* compute micro or nanoseconds and */
srdi r6,r6,32 /* seconds since stamp_xtime */
- clrldi r0,r0,32
- add r5,r5,r0 /* add nanoseconds together */
- cmpd r5,r7 /* overflow? */
+ clrldi r5,r5,32
add r4,r4,r6
- bltlr /* all done if no overflow */
- subf r5,r7,r5 /* if overflow, adjust */
- addi r4,r4,1
blr
.cfi_endproc
V_FUNCTION_END(__do_get_tspec)
diff --git a/arch/powerpc/kvm/44x_tlb.c b/arch/powerpc/kvm/44x_tlb.c
index 812312542e5..9b9b5cdea84 100644
--- a/arch/powerpc/kvm/44x_tlb.c
+++ b/arch/powerpc/kvm/44x_tlb.c
@@ -316,7 +316,8 @@ void kvmppc_mmu_map(struct kvm_vcpu *vcpu, u64 gvaddr, gpa_t gpaddr,
gfn = gpaddr >> PAGE_SHIFT;
new_page = gfn_to_page(vcpu->kvm, gfn);
if (is_error_page(new_page)) {
- printk(KERN_ERR "Couldn't get guest page for gfn %lx!\n", gfn);
+ printk(KERN_ERR "Couldn't get guest page for gfn %llx!\n",
+ (unsigned long long)gfn);
kvm_release_page_clean(new_page);
return;
}
diff --git a/arch/powerpc/kvm/Makefile b/arch/powerpc/kvm/Makefile
index ff436066bf7..d45c818a384 100644
--- a/arch/powerpc/kvm/Makefile
+++ b/arch/powerpc/kvm/Makefile
@@ -45,6 +45,7 @@ kvm-book3s_64-objs := \
book3s.o \
book3s_emulate.o \
book3s_interrupts.o \
+ book3s_mmu_hpte.o \
book3s_64_mmu_host.o \
book3s_64_mmu.o \
book3s_32_mmu.o
@@ -57,6 +58,7 @@ kvm-book3s_32-objs := \
book3s.o \
book3s_emulate.o \
book3s_interrupts.o \
+ book3s_mmu_hpte.o \
book3s_32_mmu_host.o \
book3s_32_mmu.o
kvm-objs-$(CONFIG_KVM_BOOK3S_32) := $(kvm-book3s_32-objs)
diff --git a/arch/powerpc/kvm/book3s.c b/arch/powerpc/kvm/book3s.c
index b998abf1a63..a3cef30d1d4 100644
--- a/arch/powerpc/kvm/book3s.c
+++ b/arch/powerpc/kvm/book3s.c
@@ -1047,8 +1047,6 @@ int kvm_arch_vcpu_ioctl_get_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
{
int i;
- vcpu_load(vcpu);
-
regs->pc = kvmppc_get_pc(vcpu);
regs->cr = kvmppc_get_cr(vcpu);
regs->ctr = kvmppc_get_ctr(vcpu);
@@ -1069,8 +1067,6 @@ int kvm_arch_vcpu_ioctl_get_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
for (i = 0; i < ARRAY_SIZE(regs->gpr); i++)
regs->gpr[i] = kvmppc_get_gpr(vcpu, i);
- vcpu_put(vcpu);
-
return 0;
}
@@ -1078,8 +1074,6 @@ int kvm_arch_vcpu_ioctl_set_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
{
int i;
- vcpu_load(vcpu);
-
kvmppc_set_pc(vcpu, regs->pc);
kvmppc_set_cr(vcpu, regs->cr);
kvmppc_set_ctr(vcpu, regs->ctr);
@@ -1099,8 +1093,6 @@ int kvm_arch_vcpu_ioctl_set_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
for (i = 0; i < ARRAY_SIZE(regs->gpr); i++)
kvmppc_set_gpr(vcpu, i, regs->gpr[i]);
- vcpu_put(vcpu);
-
return 0;
}
@@ -1110,8 +1102,6 @@ int kvm_arch_vcpu_ioctl_get_sregs(struct kvm_vcpu *vcpu,
struct kvmppc_vcpu_book3s *vcpu3s = to_book3s(vcpu);
int i;
- vcpu_load(vcpu);
-
sregs->pvr = vcpu->arch.pvr;
sregs->u.s.sdr1 = to_book3s(vcpu)->sdr1;
@@ -1131,8 +1121,6 @@ int kvm_arch_vcpu_ioctl_get_sregs(struct kvm_vcpu *vcpu,
}
}
- vcpu_put(vcpu);
-
return 0;
}
@@ -1142,8 +1130,6 @@ int kvm_arch_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu,
struct kvmppc_vcpu_book3s *vcpu3s = to_book3s(vcpu);
int i;
- vcpu_load(vcpu);
-
kvmppc_set_pvr(vcpu, sregs->pvr);
vcpu3s->sdr1 = sregs->u.s.sdr1;
@@ -1171,8 +1157,6 @@ int kvm_arch_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu,
/* Flush the MMU after messing with the segments */
kvmppc_mmu_pte_flush(vcpu, 0, 0);
- vcpu_put(vcpu);
-
return 0;
}
@@ -1309,12 +1293,17 @@ extern int __kvmppc_vcpu_entry(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu);
int __kvmppc_vcpu_run(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu)
{
int ret;
- struct thread_struct ext_bkp;
+ double fpr[32][TS_FPRWIDTH];
+ unsigned int fpscr;
+ int fpexc_mode;
#ifdef CONFIG_ALTIVEC
- bool save_vec = current->thread.used_vr;
+ vector128 vr[32];
+ vector128 vscr;
+ unsigned long uninitialized_var(vrsave);
+ int used_vr;
#endif
#ifdef CONFIG_VSX
- bool save_vsx = current->thread.used_vsr;
+ int used_vsr;
#endif
ulong ext_msr;
@@ -1327,27 +1316,27 @@ int __kvmppc_vcpu_run(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu)
/* Save FPU state in stack */
if (current->thread.regs->msr & MSR_FP)
giveup_fpu(current);
- memcpy(ext_bkp.fpr, current->thread.fpr, sizeof(current->thread.fpr));
- ext_bkp.fpscr = current->thread.fpscr;
- ext_bkp.fpexc_mode = current->thread.fpexc_mode;
+ memcpy(fpr, current->thread.fpr, sizeof(current->thread.fpr));
+ fpscr = current->thread.fpscr.val;
+ fpexc_mode = current->thread.fpexc_mode;
#ifdef CONFIG_ALTIVEC
/* Save Altivec state in stack */
- if (save_vec) {
+ used_vr = current->thread.used_vr;
+ if (used_vr) {
if (current->thread.regs->msr & MSR_VEC)
giveup_altivec(current);
- memcpy(ext_bkp.vr, current->thread.vr, sizeof(ext_bkp.vr));
- ext_bkp.vscr = current->thread.vscr;
- ext_bkp.vrsave = current->thread.vrsave;
+ memcpy(vr, current->thread.vr, sizeof(current->thread.vr));
+ vscr = current->thread.vscr;
+ vrsave = current->thread.vrsave;
}
- ext_bkp.used_vr = current->thread.used_vr;
#endif
#ifdef CONFIG_VSX
/* Save VSX state in stack */
- if (save_vsx && (current->thread.regs->msr & MSR_VSX))
+ used_vsr = current->thread.used_vsr;
+ if (used_vsr && (current->thread.regs->msr & MSR_VSX))
__giveup_vsx(current);
- ext_bkp.used_vsr = current->thread.used_vsr;
#endif
/* Remember the MSR with disabled extensions */
@@ -1372,22 +1361,22 @@ int __kvmppc_vcpu_run(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu)
kvmppc_giveup_ext(vcpu, MSR_VSX);
/* Restore FPU state from stack */
- memcpy(current->thread.fpr, ext_bkp.fpr, sizeof(ext_bkp.fpr));
- current->thread.fpscr = ext_bkp.fpscr;
- current->thread.fpexc_mode = ext_bkp.fpexc_mode;
+ memcpy(current->thread.fpr, fpr, sizeof(current->thread.fpr));
+ current->thread.fpscr.val = fpscr;
+ current->thread.fpexc_mode = fpexc_mode;
#ifdef CONFIG_ALTIVEC
/* Restore Altivec state from stack */
- if (save_vec && current->thread.used_vr) {
- memcpy(current->thread.vr, ext_bkp.vr, sizeof(ext_bkp.vr));
- current->thread.vscr = ext_bkp.vscr;
- current->thread.vrsave= ext_bkp.vrsave;
+ if (used_vr && current->thread.used_vr) {
+ memcpy(current->thread.vr, vr, sizeof(current->thread.vr));
+ current->thread.vscr = vscr;
+ current->thread.vrsave = vrsave;
}
- current->thread.used_vr = ext_bkp.used_vr;
+ current->thread.used_vr = used_vr;
#endif
#ifdef CONFIG_VSX
- current->thread.used_vsr = ext_bkp.used_vsr;
+ current->thread.used_vsr = used_vsr;
#endif
return ret;
@@ -1395,12 +1384,22 @@ int __kvmppc_vcpu_run(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu)
static int kvmppc_book3s_init(void)
{
- return kvm_init(NULL, sizeof(struct kvmppc_vcpu_book3s), 0,
- THIS_MODULE);
+ int r;
+
+ r = kvm_init(NULL, sizeof(struct kvmppc_vcpu_book3s), 0,
+ THIS_MODULE);
+
+ if (r)
+ return r;
+
+ r = kvmppc_mmu_hpte_sysinit();
+
+ return r;
}
static void kvmppc_book3s_exit(void)
{
+ kvmppc_mmu_hpte_sysexit();
kvm_exit();
}
diff --git a/arch/powerpc/kvm/book3s_32_mmu.c b/arch/powerpc/kvm/book3s_32_mmu.c
index 0b10503c8a4..3292d76101d 100644
--- a/arch/powerpc/kvm/book3s_32_mmu.c
+++ b/arch/powerpc/kvm/book3s_32_mmu.c
@@ -354,10 +354,10 @@ static int kvmppc_mmu_book3s_32_esid_to_vsid(struct kvm_vcpu *vcpu, ulong esid,
*vsid = VSID_REAL_DR | gvsid;
break;
case MSR_DR|MSR_IR:
- if (!sr->valid)
- return -1;
-
- *vsid = sr->vsid;
+ if (sr->valid)
+ *vsid = sr->vsid;
+ else
+ *vsid = VSID_BAT | gvsid;
break;
default:
BUG();
diff --git a/arch/powerpc/kvm/book3s_32_mmu_host.c b/arch/powerpc/kvm/book3s_32_mmu_host.c
index 0bb66005338..0b51ef872c1 100644
--- a/arch/powerpc/kvm/book3s_32_mmu_host.c
+++ b/arch/powerpc/kvm/book3s_32_mmu_host.c
@@ -19,6 +19,7 @@
*/
#include <linux/kvm_host.h>
+#include <linux/hash.h>
#include <asm/kvm_ppc.h>
#include <asm/kvm_book3s.h>
@@ -57,139 +58,26 @@
static ulong htab;
static u32 htabmask;
-static void invalidate_pte(struct kvm_vcpu *vcpu, struct hpte_cache *pte)
+void kvmppc_mmu_invalidate_pte(struct kvm_vcpu *vcpu, struct hpte_cache *pte)
{
volatile u32 *pteg;
- dprintk_mmu("KVM: Flushing SPTE: 0x%llx (0x%llx) -> 0x%llx\n",
- pte->pte.eaddr, pte->pte.vpage, pte->host_va);
-
+ /* Remove from host HTAB */
pteg = (u32*)pte->slot;
-
pteg[0] = 0;
+
+ /* And make sure it's gone from the TLB too */
asm volatile ("sync");
asm volatile ("tlbie %0" : : "r" (pte->pte.eaddr) : "memory");
asm volatile ("sync");
asm volatile ("tlbsync");
-
- pte->host_va = 0;
-
- if (pte->pte.may_write)
- kvm_release_pfn_dirty(pte->pfn);
- else
- kvm_release_pfn_clean(pte->pfn);
-}
-
-void kvmppc_mmu_pte_flush(struct kvm_vcpu *vcpu, ulong guest_ea, ulong ea_mask)
-{
- int i;
-
- dprintk_mmu("KVM: Flushing %d Shadow PTEs: 0x%x & 0x%x\n",
- vcpu->arch.hpte_cache_offset, guest_ea, ea_mask);
- BUG_ON(vcpu->arch.hpte_cache_offset > HPTEG_CACHE_NUM);
-
- guest_ea &= ea_mask;
- for (i = 0; i < vcpu->arch.hpte_cache_offset; i++) {
- struct hpte_cache *pte;
-
- pte = &vcpu->arch.hpte_cache[i];
- if (!pte->host_va)
- continue;
-
- if ((pte->pte.eaddr & ea_mask) == guest_ea) {
- invalidate_pte(vcpu, pte);
- }
- }
-
- /* Doing a complete flush -> start from scratch */
- if (!ea_mask)
- vcpu->arch.hpte_cache_offset = 0;
-}
-
-void kvmppc_mmu_pte_vflush(struct kvm_vcpu *vcpu, u64 guest_vp, u64 vp_mask)
-{
- int i;
-
- dprintk_mmu("KVM: Flushing %d Shadow vPTEs: 0x%llx & 0x%llx\n",
- vcpu->arch.hpte_cache_offset, guest_vp, vp_mask);
- BUG_ON(vcpu->arch.hpte_cache_offset > HPTEG_CACHE_NUM);
-
- guest_vp &= vp_mask;
- for (i = 0; i < vcpu->arch.hpte_cache_offset; i++) {
- struct hpte_cache *pte;
-
- pte = &vcpu->arch.hpte_cache[i];
- if (!pte->host_va)
- continue;
-
- if ((pte->pte.vpage & vp_mask) == guest_vp) {
- invalidate_pte(vcpu, pte);
- }
- }
-}
-
-void kvmppc_mmu_pte_pflush(struct kvm_vcpu *vcpu, ulong pa_start, ulong pa_end)
-{
- int i;
-
- dprintk_mmu("KVM: Flushing %d Shadow pPTEs: 0x%llx & 0x%llx\n",
- vcpu->arch.hpte_cache_offset, pa_start, pa_end);
- BUG_ON(vcpu->arch.hpte_cache_offset > HPTEG_CACHE_NUM);
-
- for (i = 0; i < vcpu->arch.hpte_cache_offset; i++) {
- struct hpte_cache *pte;
-
- pte = &vcpu->arch.hpte_cache[i];
- if (!pte->host_va)
- continue;
-
- if ((pte->pte.raddr >= pa_start) &&
- (pte->pte.raddr < pa_end)) {
- invalidate_pte(vcpu, pte);
- }
- }
-}
-
-struct kvmppc_pte *kvmppc_mmu_find_pte(struct kvm_vcpu *vcpu, u64 ea, bool data)
-{
- int i;
- u64 guest_vp;
-
- guest_vp = vcpu->arch.mmu.ea_to_vp(vcpu, ea, false);
- for (i=0; i<vcpu->arch.hpte_cache_offset; i++) {
- struct hpte_cache *pte;
-
- pte = &vcpu->arch.hpte_cache[i];
- if (!pte->host_va)
- continue;
-
- if (pte->pte.vpage == guest_vp)
- return &pte->pte;
- }
-
- return NULL;
-}
-
-static int kvmppc_mmu_hpte_cache_next(struct kvm_vcpu *vcpu)
-{
- if (vcpu->arch.hpte_cache_offset == HPTEG_CACHE_NUM)
- kvmppc_mmu_pte_flush(vcpu, 0, 0);
-
- return vcpu->arch.hpte_cache_offset++;
}
/* We keep 512 gvsid->hvsid entries, mapping the guest ones to the array using
* a hash, so we don't waste cycles on looping */
static u16 kvmppc_sid_hash(struct kvm_vcpu *vcpu, u64 gvsid)
{
- return (u16)(((gvsid >> (SID_MAP_BITS * 7)) & SID_MAP_MASK) ^
- ((gvsid >> (SID_MAP_BITS * 6)) & SID_MAP_MASK) ^
- ((gvsid >> (SID_MAP_BITS * 5)) & SID_MAP_MASK) ^
- ((gvsid >> (SID_MAP_BITS * 4)) & SID_MAP_MASK) ^
- ((gvsid >> (SID_MAP_BITS * 3)) & SID_MAP_MASK) ^
- ((gvsid >> (SID_MAP_BITS * 2)) & SID_MAP_MASK) ^
- ((gvsid >> (SID_MAP_BITS * 1)) & SID_MAP_MASK) ^
- ((gvsid >> (SID_MAP_BITS * 0)) & SID_MAP_MASK));
+ return hash_64(gvsid, SID_MAP_BITS);
}
@@ -256,7 +144,6 @@ int kvmppc_mmu_map_page(struct kvm_vcpu *vcpu, struct kvmppc_pte *orig_pte)
register int rr = 0;
bool primary = false;
bool evict = false;
- int hpte_id;
struct hpte_cache *pte;
/* Get host physical address for gpa */
@@ -341,8 +228,7 @@ next_pteg:
/* Now tell our Shadow PTE code about the new page */
- hpte_id = kvmppc_mmu_hpte_cache_next(vcpu);
- pte = &vcpu->arch.hpte_cache[hpte_id];
+ pte = kvmppc_mmu_hpte_cache_next(vcpu);
dprintk_mmu("KVM: %c%c Map 0x%llx: [%lx] 0x%llx (0x%llx) -> %lx\n",
orig_pte->may_write ? 'w' : '-',
@@ -355,6 +241,8 @@ next_pteg:
pte->pte = *orig_pte;
pte->pfn = hpaddr >> PAGE_SHIFT;
+ kvmppc_mmu_hpte_cache_map(vcpu, pte);
+
return 0;
}
@@ -439,7 +327,7 @@ void kvmppc_mmu_flush_segments(struct kvm_vcpu *vcpu)
void kvmppc_mmu_destroy(struct kvm_vcpu *vcpu)
{
- kvmppc_mmu_pte_flush(vcpu, 0, 0);
+ kvmppc_mmu_hpte_destroy(vcpu);
preempt_disable();
__destroy_context(to_book3s(vcpu)->context_id);
preempt_enable();
@@ -479,5 +367,7 @@ int kvmppc_mmu_init(struct kvm_vcpu *vcpu)
htabmask = ((sdr1 & 0x1FF) << 16) | 0xFFC0;
htab = (ulong)__va(sdr1 & 0xffff0000);
+ kvmppc_mmu_hpte_init(vcpu);
+
return 0;
}
diff --git a/arch/powerpc/kvm/book3s_64_mmu_host.c b/arch/powerpc/kvm/book3s_64_mmu_host.c
index e4b5744977f..384179a5002 100644
--- a/arch/powerpc/kvm/book3s_64_mmu_host.c
+++ b/arch/powerpc/kvm/book3s_64_mmu_host.c
@@ -20,6 +20,7 @@
*/
#include <linux/kvm_host.h>
+#include <linux/hash.h>
#include <asm/kvm_ppc.h>
#include <asm/kvm_book3s.h>
@@ -46,135 +47,20 @@
#define dprintk_slb(a, ...) do { } while(0)
#endif
-static void invalidate_pte(struct hpte_cache *pte)
+void kvmppc_mmu_invalidate_pte(struct kvm_vcpu *vcpu, struct hpte_cache *pte)
{
- dprintk_mmu("KVM: Flushing SPT: 0x%lx (0x%llx) -> 0x%llx\n",
- pte->pte.eaddr, pte->pte.vpage, pte->host_va);
-
ppc_md.hpte_invalidate(pte->slot, pte->host_va,
MMU_PAGE_4K, MMU_SEGSIZE_256M,
false);
- pte->host_va = 0;
-
- if (pte->pte.may_write)
- kvm_release_pfn_dirty(pte->pfn);
- else
- kvm_release_pfn_clean(pte->pfn);
-}
-
-void kvmppc_mmu_pte_flush(struct kvm_vcpu *vcpu, ulong guest_ea, ulong ea_mask)
-{
- int i;
-
- dprintk_mmu("KVM: Flushing %d Shadow PTEs: 0x%lx & 0x%lx\n",
- vcpu->arch.hpte_cache_offset, guest_ea, ea_mask);
- BUG_ON(vcpu->arch.hpte_cache_offset > HPTEG_CACHE_NUM);
-
- guest_ea &= ea_mask;
- for (i = 0; i < vcpu->arch.hpte_cache_offset; i++) {
- struct hpte_cache *pte;
-
- pte = &vcpu->arch.hpte_cache[i];
- if (!pte->host_va)
- continue;
-
- if ((pte->pte.eaddr & ea_mask) == guest_ea) {
- invalidate_pte(pte);
- }
- }
-
- /* Doing a complete flush -> start from scratch */
- if (!ea_mask)
- vcpu->arch.hpte_cache_offset = 0;
-}
-
-void kvmppc_mmu_pte_vflush(struct kvm_vcpu *vcpu, u64 guest_vp, u64 vp_mask)
-{
- int i;
-
- dprintk_mmu("KVM: Flushing %d Shadow vPTEs: 0x%llx & 0x%llx\n",
- vcpu->arch.hpte_cache_offset, guest_vp, vp_mask);
- BUG_ON(vcpu->arch.hpte_cache_offset > HPTEG_CACHE_NUM);
-
- guest_vp &= vp_mask;
- for (i = 0; i < vcpu->arch.hpte_cache_offset; i++) {
- struct hpte_cache *pte;
-
- pte = &vcpu->arch.hpte_cache[i];
- if (!pte->host_va)
- continue;
-
- if ((pte->pte.vpage & vp_mask) == guest_vp) {
- invalidate_pte(pte);
- }
- }
-}
-
-void kvmppc_mmu_pte_pflush(struct kvm_vcpu *vcpu, ulong pa_start, ulong pa_end)
-{
- int i;
-
- dprintk_mmu("KVM: Flushing %d Shadow pPTEs: 0x%lx & 0x%lx\n",
- vcpu->arch.hpte_cache_offset, pa_start, pa_end);
- BUG_ON(vcpu->arch.hpte_cache_offset > HPTEG_CACHE_NUM);
-
- for (i = 0; i < vcpu->arch.hpte_cache_offset; i++) {
- struct hpte_cache *pte;
-
- pte = &vcpu->arch.hpte_cache[i];
- if (!pte->host_va)
- continue;
-
- if ((pte->pte.raddr >= pa_start) &&
- (pte->pte.raddr < pa_end)) {
- invalidate_pte(pte);
- }
- }
-}
-
-struct kvmppc_pte *kvmppc_mmu_find_pte(struct kvm_vcpu *vcpu, u64 ea, bool data)
-{
- int i;
- u64 guest_vp;
-
- guest_vp = vcpu->arch.mmu.ea_to_vp(vcpu, ea, false);
- for (i=0; i<vcpu->arch.hpte_cache_offset; i++) {
- struct hpte_cache *pte;
-
- pte = &vcpu->arch.hpte_cache[i];
- if (!pte->host_va)
- continue;
-
- if (pte->pte.vpage == guest_vp)
- return &pte->pte;
- }
-
- return NULL;
-}
-
-static int kvmppc_mmu_hpte_cache_next(struct kvm_vcpu *vcpu)
-{
- if (vcpu->arch.hpte_cache_offset == HPTEG_CACHE_NUM)
- kvmppc_mmu_pte_flush(vcpu, 0, 0);
-
- return vcpu->arch.hpte_cache_offset++;
}
/* We keep 512 gvsid->hvsid entries, mapping the guest ones to the array using
* a hash, so we don't waste cycles on looping */
static u16 kvmppc_sid_hash(struct kvm_vcpu *vcpu, u64 gvsid)
{
- return (u16)(((gvsid >> (SID_MAP_BITS * 7)) & SID_MAP_MASK) ^
- ((gvsid >> (SID_MAP_BITS * 6)) & SID_MAP_MASK) ^
- ((gvsid >> (SID_MAP_BITS * 5)) & SID_MAP_MASK) ^
- ((gvsid >> (SID_MAP_BITS * 4)) & SID_MAP_MASK) ^
- ((gvsid >> (SID_MAP_BITS * 3)) & SID_MAP_MASK) ^
- ((gvsid >> (SID_MAP_BITS * 2)) & SID_MAP_MASK) ^
- ((gvsid >> (SID_MAP_BITS * 1)) & SID_MAP_MASK) ^
- ((gvsid >> (SID_MAP_BITS * 0)) & SID_MAP_MASK));
+ return hash_64(gvsid, SID_MAP_BITS);
}
-
static struct kvmppc_sid_map *find_sid_vsid(struct kvm_vcpu *vcpu, u64 gvsid)
{
struct kvmppc_sid_map *map;
@@ -273,8 +159,7 @@ map_again:
attempt++;
goto map_again;
} else {
- int hpte_id = kvmppc_mmu_hpte_cache_next(vcpu);
- struct hpte_cache *pte = &vcpu->arch.hpte_cache[hpte_id];
+ struct hpte_cache *pte = kvmppc_mmu_hpte_cache_next(vcpu);
dprintk_mmu("KVM: %c%c Map 0x%lx: [%lx] 0x%lx (0x%llx) -> %lx\n",
((rflags & HPTE_R_PP) == 3) ? '-' : 'w',
@@ -292,6 +177,8 @@ map_again:
pte->host_va = va;
pte->pte = *orig_pte;
pte->pfn = hpaddr >> PAGE_SHIFT;
+
+ kvmppc_mmu_hpte_cache_map(vcpu, pte);
}
return 0;
@@ -418,7 +305,7 @@ void kvmppc_mmu_flush_segments(struct kvm_vcpu *vcpu)
void kvmppc_mmu_destroy(struct kvm_vcpu *vcpu)
{
- kvmppc_mmu_pte_flush(vcpu, 0, 0);
+ kvmppc_mmu_hpte_destroy(vcpu);
__destroy_context(to_book3s(vcpu)->context_id);
}
@@ -436,5 +323,7 @@ int kvmppc_mmu_init(struct kvm_vcpu *vcpu)
vcpu3s->vsid_first = vcpu3s->context_id << USER_ESID_BITS;
vcpu3s->vsid_next = vcpu3s->vsid_first;
+ kvmppc_mmu_hpte_init(vcpu);
+
return 0;
}
diff --git a/arch/powerpc/kvm/book3s_mmu_hpte.c b/arch/powerpc/kvm/book3s_mmu_hpte.c
new file mode 100644
index 00000000000..4868d4a7ebc
--- /dev/null
+++ b/arch/powerpc/kvm/book3s_mmu_hpte.c
@@ -0,0 +1,277 @@
+/*
+ * Copyright (C) 2010 SUSE Linux Products GmbH. All rights reserved.
+ *
+ * Authors:
+ * Alexander Graf <agraf@suse.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include <linux/kvm_host.h>
+#include <linux/hash.h>
+#include <linux/slab.h>
+
+#include <asm/kvm_ppc.h>
+#include <asm/kvm_book3s.h>
+#include <asm/machdep.h>
+#include <asm/mmu_context.h>
+#include <asm/hw_irq.h>
+
+#define PTE_SIZE 12
+
+/* #define DEBUG_MMU */
+
+#ifdef DEBUG_MMU
+#define dprintk_mmu(a, ...) printk(KERN_INFO a, __VA_ARGS__)
+#else
+#define dprintk_mmu(a, ...) do { } while(0)
+#endif
+
+static struct kmem_cache *hpte_cache;
+
+static inline u64 kvmppc_mmu_hash_pte(u64 eaddr)
+{
+ return hash_64(eaddr >> PTE_SIZE, HPTEG_HASH_BITS_PTE);
+}
+
+static inline u64 kvmppc_mmu_hash_vpte(u64 vpage)
+{
+ return hash_64(vpage & 0xfffffffffULL, HPTEG_HASH_BITS_VPTE);
+}
+
+static inline u64 kvmppc_mmu_hash_vpte_long(u64 vpage)
+{
+ return hash_64((vpage & 0xffffff000ULL) >> 12,
+ HPTEG_HASH_BITS_VPTE_LONG);
+}
+
+void kvmppc_mmu_hpte_cache_map(struct kvm_vcpu *vcpu, struct hpte_cache *pte)
+{
+ u64 index;
+
+ /* Add to ePTE list */
+ index = kvmppc_mmu_hash_pte(pte->pte.eaddr);
+ hlist_add_head(&pte->list_pte, &vcpu->arch.hpte_hash_pte[index]);
+
+ /* Add to vPTE list */
+ index = kvmppc_mmu_hash_vpte(pte->pte.vpage);
+ hlist_add_head(&pte->list_vpte, &vcpu->arch.hpte_hash_vpte[index]);
+
+ /* Add to vPTE_long list */
+ index = kvmppc_mmu_hash_vpte_long(pte->pte.vpage);
+ hlist_add_head(&pte->list_vpte_long,
+ &vcpu->arch.hpte_hash_vpte_long[index]);
+}
+
+static void invalidate_pte(struct kvm_vcpu *vcpu, struct hpte_cache *pte)
+{
+ dprintk_mmu("KVM: Flushing SPT: 0x%lx (0x%llx) -> 0x%llx\n",
+ pte->pte.eaddr, pte->pte.vpage, pte->host_va);
+
+ /* Different for 32 and 64 bit */
+ kvmppc_mmu_invalidate_pte(vcpu, pte);
+
+ if (pte->pte.may_write)
+ kvm_release_pfn_dirty(pte->pfn);
+ else
+ kvm_release_pfn_clean(pte->pfn);
+
+ hlist_del(&pte->list_pte);
+ hlist_del(&pte->list_vpte);
+ hlist_del(&pte->list_vpte_long);
+
+ vcpu->arch.hpte_cache_count--;
+ kmem_cache_free(hpte_cache, pte);
+}
+
+static void kvmppc_mmu_pte_flush_all(struct kvm_vcpu *vcpu)
+{
+ struct hpte_cache *pte;
+ struct hlist_node *node, *tmp;
+ int i;
+
+ for (i = 0; i < HPTEG_HASH_NUM_VPTE_LONG; i++) {
+ struct hlist_head *list = &vcpu->arch.hpte_hash_vpte_long[i];
+
+ hlist_for_each_entry_safe(pte, node, tmp, list, list_vpte_long)
+ invalidate_pte(vcpu, pte);
+ }
+}
+
+static void kvmppc_mmu_pte_flush_page(struct kvm_vcpu *vcpu, ulong guest_ea)
+{
+ struct hlist_head *list;
+ struct hlist_node *node, *tmp;
+ struct hpte_cache *pte;
+
+ /* Find the list of entries in the map */
+ list = &vcpu->arch.hpte_hash_pte[kvmppc_mmu_hash_pte(guest_ea)];
+
+ /* Check the list for matching entries and invalidate */
+ hlist_for_each_entry_safe(pte, node, tmp, list, list_pte)
+ if ((pte->pte.eaddr & ~0xfffUL) == guest_ea)
+ invalidate_pte(vcpu, pte);
+}
+
+void kvmppc_mmu_pte_flush(struct kvm_vcpu *vcpu, ulong guest_ea, ulong ea_mask)
+{
+ u64 i;
+
+ dprintk_mmu("KVM: Flushing %d Shadow PTEs: 0x%lx & 0x%lx\n",
+ vcpu->arch.hpte_cache_count, guest_ea, ea_mask);
+
+ guest_ea &= ea_mask;
+
+ switch (ea_mask) {
+ case ~0xfffUL:
+ kvmppc_mmu_pte_flush_page(vcpu, guest_ea);
+ break;
+ case 0x0ffff000:
+ /* 32-bit flush w/o segment, go through all possible segments */
+ for (i = 0; i < 0x100000000ULL; i += 0x10000000ULL)
+ kvmppc_mmu_pte_flush(vcpu, guest_ea | i, ~0xfffUL);
+ break;
+ case 0:
+ /* Doing a complete flush -> start from scratch */
+ kvmppc_mmu_pte_flush_all(vcpu);
+ break;
+ default:
+ WARN_ON(1);
+ break;
+ }
+}
+
+/* Flush with mask 0xfffffffff */
+static void kvmppc_mmu_pte_vflush_short(struct kvm_vcpu *vcpu, u64 guest_vp)
+{
+ struct hlist_head *list;
+ struct hlist_node *node, *tmp;
+ struct hpte_cache *pte;
+ u64 vp_mask = 0xfffffffffULL;
+
+ list = &vcpu->arch.hpte_hash_vpte[kvmppc_mmu_hash_vpte(guest_vp)];
+
+ /* Check the list for matching entries and invalidate */
+ hlist_for_each_entry_safe(pte, node, tmp, list, list_vpte)
+ if ((pte->pte.vpage & vp_mask) == guest_vp)
+ invalidate_pte(vcpu, pte);
+}
+
+/* Flush with mask 0xffffff000 */
+static void kvmppc_mmu_pte_vflush_long(struct kvm_vcpu *vcpu, u64 guest_vp)
+{
+ struct hlist_head *list;
+ struct hlist_node *node, *tmp;
+ struct hpte_cache *pte;
+ u64 vp_mask = 0xffffff000ULL;
+
+ list = &vcpu->arch.hpte_hash_vpte_long[
+ kvmppc_mmu_hash_vpte_long(guest_vp)];
+
+ /* Check the list for matching entries and invalidate */
+ hlist_for_each_entry_safe(pte, node, tmp, list, list_vpte_long)
+ if ((pte->pte.vpage & vp_mask) == guest_vp)
+ invalidate_pte(vcpu, pte);
+}
+
+void kvmppc_mmu_pte_vflush(struct kvm_vcpu *vcpu, u64 guest_vp, u64 vp_mask)
+{
+ dprintk_mmu("KVM: Flushing %d Shadow vPTEs: 0x%llx & 0x%llx\n",
+ vcpu->arch.hpte_cache_count, guest_vp, vp_mask);
+ guest_vp &= vp_mask;
+
+ switch(vp_mask) {
+ case 0xfffffffffULL:
+ kvmppc_mmu_pte_vflush_short(vcpu, guest_vp);
+ break;
+ case 0xffffff000ULL:
+ kvmppc_mmu_pte_vflush_long(vcpu, guest_vp);
+ break;
+ default:
+ WARN_ON(1);
+ return;
+ }
+}
+
+void kvmppc_mmu_pte_pflush(struct kvm_vcpu *vcpu, ulong pa_start, ulong pa_end)
+{
+ struct hlist_node *node, *tmp;
+ struct hpte_cache *pte;
+ int i;
+
+ dprintk_mmu("KVM: Flushing %d Shadow pPTEs: 0x%lx - 0x%lx\n",
+ vcpu->arch.hpte_cache_count, pa_start, pa_end);
+
+ for (i = 0; i < HPTEG_HASH_NUM_VPTE_LONG; i++) {
+ struct hlist_head *list = &vcpu->arch.hpte_hash_vpte_long[i];
+
+ hlist_for_each_entry_safe(pte, node, tmp, list, list_vpte_long)
+ if ((pte->pte.raddr >= pa_start) &&
+ (pte->pte.raddr < pa_end))
+ invalidate_pte(vcpu, pte);
+ }
+}
+
+struct hpte_cache *kvmppc_mmu_hpte_cache_next(struct kvm_vcpu *vcpu)
+{
+ struct hpte_cache *pte;
+
+ pte = kmem_cache_zalloc(hpte_cache, GFP_KERNEL);
+ vcpu->arch.hpte_cache_count++;
+
+ if (vcpu->arch.hpte_cache_count == HPTEG_CACHE_NUM)
+ kvmppc_mmu_pte_flush_all(vcpu);
+
+ return pte;
+}
+
+void kvmppc_mmu_hpte_destroy(struct kvm_vcpu *vcpu)
+{
+ kvmppc_mmu_pte_flush(vcpu, 0, 0);
+}
+
+static void kvmppc_mmu_hpte_init_hash(struct hlist_head *hash_list, int len)
+{
+ int i;
+
+ for (i = 0; i < len; i++)
+ INIT_HLIST_HEAD(&hash_list[i]);
+}
+
+int kvmppc_mmu_hpte_init(struct kvm_vcpu *vcpu)
+{
+ /* init hpte lookup hashes */
+ kvmppc_mmu_hpte_init_hash(vcpu->arch.hpte_hash_pte,
+ ARRAY_SIZE(vcpu->arch.hpte_hash_pte));
+ kvmppc_mmu_hpte_init_hash(vcpu->arch.hpte_hash_vpte,
+ ARRAY_SIZE(vcpu->arch.hpte_hash_vpte));
+ kvmppc_mmu_hpte_init_hash(vcpu->arch.hpte_hash_vpte_long,
+ ARRAY_SIZE(vcpu->arch.hpte_hash_vpte_long));
+
+ return 0;
+}
+
+int kvmppc_mmu_hpte_sysinit(void)
+{
+ /* init hpte slab cache */
+ hpte_cache = kmem_cache_create("kvm-spt", sizeof(struct hpte_cache),
+ sizeof(struct hpte_cache), 0, NULL);
+
+ return 0;
+}
+
+void kvmppc_mmu_hpte_sysexit(void)
+{
+ kmem_cache_destroy(hpte_cache);
+}
diff --git a/arch/powerpc/kvm/book3s_paired_singles.c b/arch/powerpc/kvm/book3s_paired_singles.c
index a9f66abafcb..474f2e24050 100644
--- a/arch/powerpc/kvm/book3s_paired_singles.c
+++ b/arch/powerpc/kvm/book3s_paired_singles.c
@@ -159,10 +159,7 @@
static inline void kvmppc_sync_qpr(struct kvm_vcpu *vcpu, int rt)
{
- struct thread_struct t;
-
- t.fpscr.val = vcpu->arch.fpscr;
- cvt_df((double*)&vcpu->arch.fpr[rt], (float*)&vcpu->arch.qpr[rt], &t);
+ kvm_cvt_df(&vcpu->arch.fpr[rt], &vcpu->arch.qpr[rt], &vcpu->arch.fpscr);
}
static void kvmppc_inject_pf(struct kvm_vcpu *vcpu, ulong eaddr, bool is_store)
@@ -183,7 +180,6 @@ static int kvmppc_emulate_fpr_load(struct kvm_run *run, struct kvm_vcpu *vcpu,
int rs, ulong addr, int ls_type)
{
int emulated = EMULATE_FAIL;
- struct thread_struct t;
int r;
char tmp[8];
int len = sizeof(u32);
@@ -191,8 +187,6 @@ static int kvmppc_emulate_fpr_load(struct kvm_run *run, struct kvm_vcpu *vcpu,
if (ls_type == FPU_LS_DOUBLE)
len = sizeof(u64);
- t.fpscr.val = vcpu->arch.fpscr;
-
/* read from memory */
r = kvmppc_ld(vcpu, &addr, len, tmp, true);
vcpu->arch.paddr_accessed = addr;
@@ -210,7 +204,7 @@ static int kvmppc_emulate_fpr_load(struct kvm_run *run, struct kvm_vcpu *vcpu,
/* put in registers */
switch (ls_type) {
case FPU_LS_SINGLE:
- cvt_fd((float*)tmp, (double*)&vcpu->arch.fpr[rs], &t);
+ kvm_cvt_fd((u32*)tmp, &vcpu->arch.fpr[rs], &vcpu->arch.fpscr);
vcpu->arch.qpr[rs] = *((u32*)tmp);
break;
case FPU_LS_DOUBLE:
@@ -229,17 +223,14 @@ static int kvmppc_emulate_fpr_store(struct kvm_run *run, struct kvm_vcpu *vcpu,
int rs, ulong addr, int ls_type)
{
int emulated = EMULATE_FAIL;
- struct thread_struct t;
int r;
char tmp[8];
u64 val;
int len;
- t.fpscr.val = vcpu->arch.fpscr;
-
switch (ls_type) {
case FPU_LS_SINGLE:
- cvt_df((double*)&vcpu->arch.fpr[rs], (float*)tmp, &t);
+ kvm_cvt_df(&vcpu->arch.fpr[rs], (u32*)tmp, &vcpu->arch.fpscr);
val = *((u32*)tmp);
len = sizeof(u32);
break;
@@ -278,13 +269,10 @@ static int kvmppc_emulate_psq_load(struct kvm_run *run, struct kvm_vcpu *vcpu,
int rs, ulong addr, bool w, int i)
{
int emulated = EMULATE_FAIL;
- struct thread_struct t;
int r;
float one = 1.0;
u32 tmp[2];
- t.fpscr.val = vcpu->arch.fpscr;
-
/* read from memory */
if (w) {
r = kvmppc_ld(vcpu, &addr, sizeof(u32), tmp, true);
@@ -308,7 +296,7 @@ static int kvmppc_emulate_psq_load(struct kvm_run *run, struct kvm_vcpu *vcpu,
emulated = EMULATE_DONE;
/* put in registers */
- cvt_fd((float*)&tmp[0], (double*)&vcpu->arch.fpr[rs], &t);
+ kvm_cvt_fd(&tmp[0], &vcpu->arch.fpr[rs], &vcpu->arch.fpscr);
vcpu->arch.qpr[rs] = tmp[1];
dprintk(KERN_INFO "KVM: PSQ_LD [0x%x, 0x%x] at 0x%lx (%d)\n", tmp[0],
@@ -322,14 +310,11 @@ static int kvmppc_emulate_psq_store(struct kvm_run *run, struct kvm_vcpu *vcpu,
int rs, ulong addr, bool w, int i)
{
int emulated = EMULATE_FAIL;
- struct thread_struct t;
int r;
u32 tmp[2];
int len = w ? sizeof(u32) : sizeof(u64);
- t.fpscr.val = vcpu->arch.fpscr;
-
- cvt_df((double*)&vcpu->arch.fpr[rs], (float*)&tmp[0], &t);
+ kvm_cvt_df(&vcpu->arch.fpr[rs], &tmp[0], &vcpu->arch.fpscr);
tmp[1] = vcpu->arch.qpr[rs];
r = kvmppc_st(vcpu, &addr, len, tmp, true);
@@ -517,7 +502,7 @@ static int get_d_signext(u32 inst)
static int kvmppc_ps_three_in(struct kvm_vcpu *vcpu, bool rc,
int reg_out, int reg_in1, int reg_in2,
int reg_in3, int scalar,
- void (*func)(struct thread_struct *t,
+ void (*func)(u64 *fpscr,
u32 *dst, u32 *src1,
u32 *src2, u32 *src3))
{
@@ -526,27 +511,25 @@ static int kvmppc_ps_three_in(struct kvm_vcpu *vcpu, bool rc,
u32 ps0_out;
u32 ps0_in1, ps0_in2, ps0_in3;
u32 ps1_in1, ps1_in2, ps1_in3;
- struct thread_struct t;
- t.fpscr.val = vcpu->arch.fpscr;
/* RC */
WARN_ON(rc);
/* PS0 */
- cvt_df((double*)&fpr[reg_in1], (float*)&ps0_in1, &t);
- cvt_df((double*)&fpr[reg_in2], (float*)&ps0_in2, &t);
- cvt_df((double*)&fpr[reg_in3], (float*)&ps0_in3, &t);
+ kvm_cvt_df(&fpr[reg_in1], &ps0_in1, &vcpu->arch.fpscr);
+ kvm_cvt_df(&fpr[reg_in2], &ps0_in2, &vcpu->arch.fpscr);
+ kvm_cvt_df(&fpr[reg_in3], &ps0_in3, &vcpu->arch.fpscr);
if (scalar & SCALAR_LOW)
ps0_in2 = qpr[reg_in2];
- func(&t, &ps0_out, &ps0_in1, &ps0_in2, &ps0_in3);
+ func(&vcpu->arch.fpscr, &ps0_out, &ps0_in1, &ps0_in2, &ps0_in3);
dprintk(KERN_INFO "PS3 ps0 -> f(0x%x, 0x%x, 0x%x) = 0x%x\n",
ps0_in1, ps0_in2, ps0_in3, ps0_out);
if (!(scalar & SCALAR_NO_PS0))
- cvt_fd((float*)&ps0_out, (double*)&fpr[reg_out], &t);
+ kvm_cvt_fd(&ps0_out, &fpr[reg_out], &vcpu->arch.fpscr);
/* PS1 */
ps1_in1 = qpr[reg_in1];
@@ -557,7 +540,7 @@ static int kvmppc_ps_three_in(struct kvm_vcpu *vcpu, bool rc,
ps1_in2 = ps0_in2;
if (!(scalar & SCALAR_NO_PS1))
- func(&t, &qpr[reg_out], &ps1_in1, &ps1_in2, &ps1_in3);
+ func(&vcpu->arch.fpscr, &qpr[reg_out], &ps1_in1, &ps1_in2, &ps1_in3);
dprintk(KERN_INFO "PS3 ps1 -> f(0x%x, 0x%x, 0x%x) = 0x%x\n",
ps1_in1, ps1_in2, ps1_in3, qpr[reg_out]);
@@ -568,7 +551,7 @@ static int kvmppc_ps_three_in(struct kvm_vcpu *vcpu, bool rc,
static int kvmppc_ps_two_in(struct kvm_vcpu *vcpu, bool rc,
int reg_out, int reg_in1, int reg_in2,
int scalar,
- void (*func)(struct thread_struct *t,
+ void (*func)(u64 *fpscr,
u32 *dst, u32 *src1,
u32 *src2))
{
@@ -578,27 +561,25 @@ static int kvmppc_ps_two_in(struct kvm_vcpu *vcpu, bool rc,
u32 ps0_in1, ps0_in2;
u32 ps1_out;
u32 ps1_in1, ps1_in2;
- struct thread_struct t;
- t.fpscr.val = vcpu->arch.fpscr;
/* RC */
WARN_ON(rc);
/* PS0 */
- cvt_df((double*)&fpr[reg_in1], (float*)&ps0_in1, &t);
+ kvm_cvt_df(&fpr[reg_in1], &ps0_in1, &vcpu->arch.fpscr);
if (scalar & SCALAR_LOW)
ps0_in2 = qpr[reg_in2];
else
- cvt_df((double*)&fpr[reg_in2], (float*)&ps0_in2, &t);
+ kvm_cvt_df(&fpr[reg_in2], &ps0_in2, &vcpu->arch.fpscr);
- func(&t, &ps0_out, &ps0_in1, &ps0_in2);
+ func(&vcpu->arch.fpscr, &ps0_out, &ps0_in1, &ps0_in2);
if (!(scalar & SCALAR_NO_PS0)) {
dprintk(KERN_INFO "PS2 ps0 -> f(0x%x, 0x%x) = 0x%x\n",
ps0_in1, ps0_in2, ps0_out);
- cvt_fd((float*)&ps0_out, (double*)&fpr[reg_out], &t);
+ kvm_cvt_fd(&ps0_out, &fpr[reg_out], &vcpu->arch.fpscr);
}
/* PS1 */
@@ -608,7 +589,7 @@ static int kvmppc_ps_two_in(struct kvm_vcpu *vcpu, bool rc,
if (scalar & SCALAR_HIGH)
ps1_in2 = ps0_in2;
- func(&t, &ps1_out, &ps1_in1, &ps1_in2);
+ func(&vcpu->arch.fpscr, &ps1_out, &ps1_in1, &ps1_in2);
if (!(scalar & SCALAR_NO_PS1)) {
qpr[reg_out] = ps1_out;
@@ -622,31 +603,29 @@ static int kvmppc_ps_two_in(struct kvm_vcpu *vcpu, bool rc,
static int kvmppc_ps_one_in(struct kvm_vcpu *vcpu, bool rc,
int reg_out, int reg_in,
- void (*func)(struct thread_struct *t,
+ void (*func)(u64 *t,
u32 *dst, u32 *src1))
{
u32 *qpr = vcpu->arch.qpr;
u64 *fpr = vcpu->arch.fpr;
u32 ps0_out, ps0_in;
u32 ps1_in;
- struct thread_struct t;
- t.fpscr.val = vcpu->arch.fpscr;
/* RC */
WARN_ON(rc);
/* PS0 */
- cvt_df((double*)&fpr[reg_in], (float*)&ps0_in, &t);
- func(&t, &ps0_out, &ps0_in);
+ kvm_cvt_df(&fpr[reg_in], &ps0_in, &vcpu->arch.fpscr);
+ func(&vcpu->arch.fpscr, &ps0_out, &ps0_in);
dprintk(KERN_INFO "PS1 ps0 -> f(0x%x) = 0x%x\n",
ps0_in, ps0_out);
- cvt_fd((float*)&ps0_out, (double*)&fpr[reg_out], &t);
+ kvm_cvt_fd(&ps0_out, &fpr[reg_out], &vcpu->arch.fpscr);
/* PS1 */
ps1_in = qpr[reg_in];
- func(&t, &qpr[reg_out], &ps1_in);
+ func(&vcpu->arch.fpscr, &qpr[reg_out], &ps1_in);
dprintk(KERN_INFO "PS1 ps1 -> f(0x%x) = 0x%x\n",
ps1_in, qpr[reg_out]);
@@ -672,13 +651,10 @@ int kvmppc_emulate_paired_single(struct kvm_run *run, struct kvm_vcpu *vcpu)
bool rcomp = (inst & 1) ? true : false;
u32 cr = kvmppc_get_cr(vcpu);
- struct thread_struct t;
#ifdef DEBUG
int i;
#endif
- t.fpscr.val = vcpu->arch.fpscr;
-
if (!kvmppc_inst_is_paired_single(vcpu, inst))
return EMULATE_FAIL;
@@ -695,7 +671,7 @@ int kvmppc_emulate_paired_single(struct kvm_run *run, struct kvm_vcpu *vcpu)
#ifdef DEBUG
for (i = 0; i < ARRAY_SIZE(vcpu->arch.fpr); i++) {
u32 f;
- cvt_df((double*)&vcpu->arch.fpr[i], (float*)&f, &t);
+ kvm_cvt_df(&vcpu->arch.fpr[i], &f, &vcpu->arch.fpscr);
dprintk(KERN_INFO "FPR[%d] = 0x%x / 0x%llx QPR[%d] = 0x%x\n",
i, f, vcpu->arch.fpr[i], i, vcpu->arch.qpr[i]);
}
@@ -819,8 +795,9 @@ int kvmppc_emulate_paired_single(struct kvm_run *run, struct kvm_vcpu *vcpu)
WARN_ON(rcomp);
vcpu->arch.fpr[ax_rd] = vcpu->arch.fpr[ax_ra];
/* vcpu->arch.qpr[ax_rd] = vcpu->arch.fpr[ax_rb]; */
- cvt_df((double*)&vcpu->arch.fpr[ax_rb],
- (float*)&vcpu->arch.qpr[ax_rd], &t);
+ kvm_cvt_df(&vcpu->arch.fpr[ax_rb],
+ &vcpu->arch.qpr[ax_rd],
+ &vcpu->arch.fpscr);
break;
case OP_4X_PS_MERGE01:
WARN_ON(rcomp);
@@ -830,17 +807,20 @@ int kvmppc_emulate_paired_single(struct kvm_run *run, struct kvm_vcpu *vcpu)
case OP_4X_PS_MERGE10:
WARN_ON(rcomp);
/* vcpu->arch.fpr[ax_rd] = vcpu->arch.qpr[ax_ra]; */
- cvt_fd((float*)&vcpu->arch.qpr[ax_ra],
- (double*)&vcpu->arch.fpr[ax_rd], &t);
+ kvm_cvt_fd(&vcpu->arch.qpr[ax_ra],
+ &vcpu->arch.fpr[ax_rd],
+ &vcpu->arch.fpscr);
/* vcpu->arch.qpr[ax_rd] = vcpu->arch.fpr[ax_rb]; */
- cvt_df((double*)&vcpu->arch.fpr[ax_rb],
- (float*)&vcpu->arch.qpr[ax_rd], &t);
+ kvm_cvt_df(&vcpu->arch.fpr[ax_rb],
+ &vcpu->arch.qpr[ax_rd],
+ &vcpu->arch.fpscr);
break;
case OP_4X_PS_MERGE11:
WARN_ON(rcomp);
/* vcpu->arch.fpr[ax_rd] = vcpu->arch.qpr[ax_ra]; */
- cvt_fd((float*)&vcpu->arch.qpr[ax_ra],
- (double*)&vcpu->arch.fpr[ax_rd], &t);
+ kvm_cvt_fd(&vcpu->arch.qpr[ax_ra],
+ &vcpu->arch.fpr[ax_rd],
+ &vcpu->arch.fpscr);
vcpu->arch.qpr[ax_rd] = vcpu->arch.qpr[ax_rb];
break;
}
@@ -1275,7 +1255,7 @@ int kvmppc_emulate_paired_single(struct kvm_run *run, struct kvm_vcpu *vcpu)
#ifdef DEBUG
for (i = 0; i < ARRAY_SIZE(vcpu->arch.fpr); i++) {
u32 f;
- cvt_df((double*)&vcpu->arch.fpr[i], (float*)&f, &t);
+ kvm_cvt_df(&vcpu->arch.fpr[i], &f, &vcpu->arch.fpscr);
dprintk(KERN_INFO "FPR[%d] = 0x%x\n", i, f);
}
#endif
diff --git a/arch/powerpc/kvm/booke.c b/arch/powerpc/kvm/booke.c
index a33ab8cc2cc..8d4e35f5372 100644
--- a/arch/powerpc/kvm/booke.c
+++ b/arch/powerpc/kvm/booke.c
@@ -144,7 +144,7 @@ static int kvmppc_booke_irqprio_deliver(struct kvm_vcpu *vcpu,
unsigned int priority)
{
int allowed = 0;
- ulong msr_mask;
+ ulong uninitialized_var(msr_mask);
bool update_esr = false, update_dear = false;
switch (priority) {
@@ -485,8 +485,6 @@ int kvm_arch_vcpu_ioctl_get_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
{
int i;
- vcpu_load(vcpu);
-
regs->pc = vcpu->arch.pc;
regs->cr = kvmppc_get_cr(vcpu);
regs->ctr = vcpu->arch.ctr;
@@ -507,8 +505,6 @@ int kvm_arch_vcpu_ioctl_get_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
for (i = 0; i < ARRAY_SIZE(regs->gpr); i++)
regs->gpr[i] = kvmppc_get_gpr(vcpu, i);
- vcpu_put(vcpu);
-
return 0;
}
@@ -516,8 +512,6 @@ int kvm_arch_vcpu_ioctl_set_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
{
int i;
- vcpu_load(vcpu);
-
vcpu->arch.pc = regs->pc;
kvmppc_set_cr(vcpu, regs->cr);
vcpu->arch.ctr = regs->ctr;
@@ -537,8 +531,6 @@ int kvm_arch_vcpu_ioctl_set_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
for (i = 0; i < ARRAY_SIZE(regs->gpr); i++)
kvmppc_set_gpr(vcpu, i, regs->gpr[i]);
- vcpu_put(vcpu);
-
return 0;
}
@@ -569,9 +561,7 @@ int kvm_arch_vcpu_ioctl_translate(struct kvm_vcpu *vcpu,
{
int r;
- vcpu_load(vcpu);
r = kvmppc_core_vcpu_translate(vcpu, tr);
- vcpu_put(vcpu);
return r;
}
diff --git a/arch/powerpc/kvm/fpu.S b/arch/powerpc/kvm/fpu.S
index 2b340a3eee9..cb34bbe1611 100644
--- a/arch/powerpc/kvm/fpu.S
+++ b/arch/powerpc/kvm/fpu.S
@@ -271,3 +271,21 @@ FPD_THREE_IN(fmsub)
FPD_THREE_IN(fmadd)
FPD_THREE_IN(fnmsub)
FPD_THREE_IN(fnmadd)
+
+_GLOBAL(kvm_cvt_fd)
+ lfd 0,0(r5) /* load up fpscr value */
+ MTFSF_L(0)
+ lfs 0,0(r3)
+ stfd 0,0(r4)
+ mffs 0
+ stfd 0,0(r5) /* save new fpscr value */
+ blr
+
+_GLOBAL(kvm_cvt_df)
+ lfd 0,0(r5) /* load up fpscr value */
+ MTFSF_L(0)
+ lfd 0,0(r3)
+ stfs 0,0(r4)
+ mffs 0
+ stfd 0,0(r5) /* save new fpscr value */
+ blr
diff --git a/arch/powerpc/kvm/powerpc.c b/arch/powerpc/kvm/powerpc.c
index 9b8683f39e0..72a4ad86ee9 100644
--- a/arch/powerpc/kvm/powerpc.c
+++ b/arch/powerpc/kvm/powerpc.c
@@ -36,11 +36,6 @@
#define CREATE_TRACE_POINTS
#include "trace.h"
-gfn_t unalias_gfn(struct kvm *kvm, gfn_t gfn)
-{
- return gfn;
-}
-
int kvm_arch_vcpu_runnable(struct kvm_vcpu *v)
{
return !(v->arch.msr & MSR_WE) || !!(v->arch.pending_exceptions);
@@ -287,7 +282,7 @@ static void kvmppc_complete_dcr_load(struct kvm_vcpu *vcpu,
static void kvmppc_complete_mmio_load(struct kvm_vcpu *vcpu,
struct kvm_run *run)
{
- u64 gpr;
+ u64 uninitialized_var(gpr);
if (run->mmio.len > sizeof(gpr)) {
printk(KERN_ERR "bad MMIO length: %d\n", run->mmio.len);
@@ -423,8 +418,6 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run)
int r;
sigset_t sigsaved;
- vcpu_load(vcpu);
-
if (vcpu->sigset_active)
sigprocmask(SIG_SETMASK, &vcpu->sigset, &sigsaved);
@@ -456,8 +449,6 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run)
if (vcpu->sigset_active)
sigprocmask(SIG_SETMASK, &sigsaved, NULL);
- vcpu_put(vcpu);
-
return r;
}
@@ -523,8 +514,9 @@ long kvm_arch_vcpu_ioctl(struct file *filp,
if (copy_from_user(&irq, argp, sizeof(irq)))
goto out;
r = kvm_vcpu_ioctl_interrupt(vcpu, &irq);
- break;
+ goto out;
}
+
case KVM_ENABLE_CAP:
{
struct kvm_enable_cap cap;
diff --git a/arch/powerpc/kvm/timing.c b/arch/powerpc/kvm/timing.c
index 70378551c0c..46fa04f12a9 100644
--- a/arch/powerpc/kvm/timing.c
+++ b/arch/powerpc/kvm/timing.c
@@ -182,7 +182,7 @@ static ssize_t kvmppc_exit_timing_write(struct file *file,
}
if (c == 'c') {
- struct seq_file *seqf = (struct seq_file *)file->private_data;
+ struct seq_file *seqf = file->private_data;
struct kvm_vcpu *vcpu = seqf->private;
/* Write does not affect our buffers previously generated with
* show. seq_file is locked here to prevent races of init with
diff --git a/arch/powerpc/lib/Makefile b/arch/powerpc/lib/Makefile
index 111da1c03a1..5bb89c82807 100644
--- a/arch/powerpc/lib/Makefile
+++ b/arch/powerpc/lib/Makefile
@@ -18,8 +18,9 @@ obj-$(CONFIG_HAS_IOMEM) += devres.o
obj-$(CONFIG_PPC64) += copypage_64.o copyuser_64.o \
memcpy_64.o usercopy_64.o mem_64.o string.o
-obj-$(CONFIG_XMON) += sstep.o
-obj-$(CONFIG_KPROBES) += sstep.o
+obj-$(CONFIG_XMON) += sstep.o ldstfp.o
+obj-$(CONFIG_KPROBES) += sstep.o ldstfp.o
+obj-$(CONFIG_HAVE_HW_BREAKPOINT) += sstep.o ldstfp.o
ifeq ($(CONFIG_PPC64),y)
obj-$(CONFIG_SMP) += locks.o
diff --git a/arch/powerpc/lib/ldstfp.S b/arch/powerpc/lib/ldstfp.S
new file mode 100644
index 00000000000..f6448636baf
--- /dev/null
+++ b/arch/powerpc/lib/ldstfp.S
@@ -0,0 +1,375 @@
+/*
+ * Floating-point, VMX/Altivec and VSX loads and stores
+ * for use in instruction emulation.
+ *
+ * Copyright 2010 Paul Mackerras, IBM Corp. <paulus@au1.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 <asm/processor.h>
+#include <asm/ppc_asm.h>
+#include <asm/ppc-opcode.h>
+#include <asm/reg.h>
+#include <asm/asm-offsets.h>
+#include <linux/errno.h>
+
+#define STKFRM (PPC_MIN_STKFRM + 16)
+
+ .macro extab instr,handler
+ .section __ex_table,"a"
+ PPC_LONG \instr,\handler
+ .previous
+ .endm
+
+ .macro inst32 op
+reg = 0
+ .rept 32
+20: \op reg,0,r4
+ b 3f
+ extab 20b,99f
+reg = reg + 1
+ .endr
+ .endm
+
+/* Get the contents of frN into fr0; N is in r3. */
+_GLOBAL(get_fpr)
+ mflr r0
+ rlwinm r3,r3,3,0xf8
+ bcl 20,31,1f
+ blr /* fr0 is already in fr0 */
+ nop
+reg = 1
+ .rept 31
+ fmr fr0,reg
+ blr
+reg = reg + 1
+ .endr
+1: mflr r5
+ add r5,r3,r5
+ mtctr r5
+ mtlr r0
+ bctr
+
+/* Put the contents of fr0 into frN; N is in r3. */
+_GLOBAL(put_fpr)
+ mflr r0
+ rlwinm r3,r3,3,0xf8
+ bcl 20,31,1f
+ blr /* fr0 is already in fr0 */
+ nop
+reg = 1
+ .rept 31
+ fmr reg,fr0
+ blr
+reg = reg + 1
+ .endr
+1: mflr r5
+ add r5,r3,r5
+ mtctr r5
+ mtlr r0
+ bctr
+
+/* Load FP reg N from float at *p. N is in r3, p in r4. */
+_GLOBAL(do_lfs)
+ PPC_STLU r1,-STKFRM(r1)
+ mflr r0
+ PPC_STL r0,STKFRM+PPC_LR_STKOFF(r1)
+ mfmsr r6
+ ori r7,r6,MSR_FP
+ cmpwi cr7,r3,0
+ mtmsrd r7
+ isync
+ beq cr7,1f
+ stfd fr0,STKFRM-16(r1)
+1: li r9,-EFAULT
+2: lfs fr0,0(r4)
+ li r9,0
+3: bl put_fpr
+ beq cr7,4f
+ lfd fr0,STKFRM-16(r1)
+4: PPC_LL r0,STKFRM+PPC_LR_STKOFF(r1)
+ mtlr r0
+ mtmsrd r6
+ isync
+ mr r3,r9
+ addi r1,r1,STKFRM
+ blr
+ extab 2b,3b
+
+/* Load FP reg N from double at *p. N is in r3, p in r4. */
+_GLOBAL(do_lfd)
+ PPC_STLU r1,-STKFRM(r1)
+ mflr r0
+ PPC_STL r0,STKFRM+PPC_LR_STKOFF(r1)
+ mfmsr r6
+ ori r7,r6,MSR_FP
+ cmpwi cr7,r3,0
+ mtmsrd r7
+ isync
+ beq cr7,1f
+ stfd fr0,STKFRM-16(r1)
+1: li r9,-EFAULT
+2: lfd fr0,0(r4)
+ li r9,0
+3: beq cr7,4f
+ bl put_fpr
+ lfd fr0,STKFRM-16(r1)
+4: PPC_LL r0,STKFRM+PPC_LR_STKOFF(r1)
+ mtlr r0
+ mtmsrd r6
+ isync
+ mr r3,r9
+ addi r1,r1,STKFRM
+ blr
+ extab 2b,3b
+
+/* Store FP reg N to float at *p. N is in r3, p in r4. */
+_GLOBAL(do_stfs)
+ PPC_STLU r1,-STKFRM(r1)
+ mflr r0
+ PPC_STL r0,STKFRM+PPC_LR_STKOFF(r1)
+ mfmsr r6
+ ori r7,r6,MSR_FP
+ cmpwi cr7,r3,0
+ mtmsrd r7
+ isync
+ beq cr7,1f
+ stfd fr0,STKFRM-16(r1)
+ bl get_fpr
+1: li r9,-EFAULT
+2: stfs fr0,0(r4)
+ li r9,0
+3: beq cr7,4f
+ lfd fr0,STKFRM-16(r1)
+4: PPC_LL r0,STKFRM+PPC_LR_STKOFF(r1)
+ mtlr r0
+ mtmsrd r6
+ isync
+ mr r3,r9
+ addi r1,r1,STKFRM
+ blr
+ extab 2b,3b
+
+/* Store FP reg N to double at *p. N is in r3, p in r4. */
+_GLOBAL(do_stfd)
+ PPC_STLU r1,-STKFRM(r1)
+ mflr r0
+ PPC_STL r0,STKFRM+PPC_LR_STKOFF(r1)
+ mfmsr r6
+ ori r7,r6,MSR_FP
+ cmpwi cr7,r3,0
+ mtmsrd r7
+ isync
+ beq cr7,1f
+ stfd fr0,STKFRM-16(r1)
+ bl get_fpr
+1: li r9,-EFAULT
+2: stfd fr0,0(r4)
+ li r9,0
+3: beq cr7,4f
+ lfd fr0,STKFRM-16(r1)
+4: PPC_LL r0,STKFRM+PPC_LR_STKOFF(r1)
+ mtlr r0
+ mtmsrd r6
+ isync
+ mr r3,r9
+ addi r1,r1,STKFRM
+ blr
+ extab 2b,3b
+
+#ifdef CONFIG_ALTIVEC
+/* Get the contents of vrN into vr0; N is in r3. */
+_GLOBAL(get_vr)
+ mflr r0
+ rlwinm r3,r3,3,0xf8
+ bcl 20,31,1f
+ blr /* vr0 is already in vr0 */
+ nop
+reg = 1
+ .rept 31
+ vor vr0,reg,reg /* assembler doesn't know vmr? */
+ blr
+reg = reg + 1
+ .endr
+1: mflr r5
+ add r5,r3,r5
+ mtctr r5
+ mtlr r0
+ bctr
+
+/* Put the contents of vr0 into vrN; N is in r3. */
+_GLOBAL(put_vr)
+ mflr r0
+ rlwinm r3,r3,3,0xf8
+ bcl 20,31,1f
+ blr /* vr0 is already in vr0 */
+ nop
+reg = 1
+ .rept 31
+ vor reg,vr0,vr0
+ blr
+reg = reg + 1
+ .endr
+1: mflr r5
+ add r5,r3,r5
+ mtctr r5
+ mtlr r0
+ bctr
+
+/* Load vector reg N from *p. N is in r3, p in r4. */
+_GLOBAL(do_lvx)
+ PPC_STLU r1,-STKFRM(r1)
+ mflr r0
+ PPC_STL r0,STKFRM+PPC_LR_STKOFF(r1)
+ mfmsr r6
+ oris r7,r6,MSR_VEC@h
+ cmpwi cr7,r3,0
+ li r8,STKFRM-16
+ mtmsrd r7
+ isync
+ beq cr7,1f
+ stvx vr0,r1,r8
+1: li r9,-EFAULT
+2: lvx vr0,0,r4
+ li r9,0
+3: beq cr7,4f
+ bl put_vr
+ lvx vr0,r1,r8
+4: PPC_LL r0,STKFRM+PPC_LR_STKOFF(r1)
+ mtlr r0
+ mtmsrd r6
+ isync
+ mr r3,r9
+ addi r1,r1,STKFRM
+ blr
+ extab 2b,3b
+
+/* Store vector reg N to *p. N is in r3, p in r4. */
+_GLOBAL(do_stvx)
+ PPC_STLU r1,-STKFRM(r1)
+ mflr r0
+ PPC_STL r0,STKFRM+PPC_LR_STKOFF(r1)
+ mfmsr r6
+ oris r7,r6,MSR_VEC@h
+ cmpwi cr7,r3,0
+ li r8,STKFRM-16
+ mtmsrd r7
+ isync
+ beq cr7,1f
+ stvx vr0,r1,r8
+ bl get_vr
+1: li r9,-EFAULT
+2: stvx vr0,0,r4
+ li r9,0
+3: beq cr7,4f
+ lvx vr0,r1,r8
+4: PPC_LL r0,STKFRM+PPC_LR_STKOFF(r1)
+ mtlr r0
+ mtmsrd r6
+ isync
+ mr r3,r9
+ addi r1,r1,STKFRM
+ blr
+ extab 2b,3b
+#endif /* CONFIG_ALTIVEC */
+
+#ifdef CONFIG_VSX
+/* Get the contents of vsrN into vsr0; N is in r3. */
+_GLOBAL(get_vsr)
+ mflr r0
+ rlwinm r3,r3,3,0x1f8
+ bcl 20,31,1f
+ blr /* vsr0 is already in vsr0 */
+ nop
+reg = 1
+ .rept 63
+ XXLOR(0,reg,reg)
+ blr
+reg = reg + 1
+ .endr
+1: mflr r5
+ add r5,r3,r5
+ mtctr r5
+ mtlr r0
+ bctr
+
+/* Put the contents of vsr0 into vsrN; N is in r3. */
+_GLOBAL(put_vsr)
+ mflr r0
+ rlwinm r3,r3,3,0x1f8
+ bcl 20,31,1f
+ blr /* vr0 is already in vr0 */
+ nop
+reg = 1
+ .rept 63
+ XXLOR(reg,0,0)
+ blr
+reg = reg + 1
+ .endr
+1: mflr r5
+ add r5,r3,r5
+ mtctr r5
+ mtlr r0
+ bctr
+
+/* Load VSX reg N from vector doubleword *p. N is in r3, p in r4. */
+_GLOBAL(do_lxvd2x)
+ PPC_STLU r1,-STKFRM(r1)
+ mflr r0
+ PPC_STL r0,STKFRM+PPC_LR_STKOFF(r1)
+ mfmsr r6
+ oris r7,r6,MSR_VSX@h
+ cmpwi cr7,r3,0
+ li r8,STKFRM-16
+ mtmsrd r7
+ isync
+ beq cr7,1f
+ STXVD2X(0,r1,r8)
+1: li r9,-EFAULT
+2: LXVD2X(0,0,r4)
+ li r9,0
+3: beq cr7,4f
+ bl put_vsr
+ LXVD2X(0,r1,r8)
+4: PPC_LL r0,STKFRM+PPC_LR_STKOFF(r1)
+ mtlr r0
+ mtmsrd r6
+ isync
+ mr r3,r9
+ addi r1,r1,STKFRM
+ blr
+ extab 2b,3b
+
+/* Store VSX reg N to vector doubleword *p. N is in r3, p in r4. */
+_GLOBAL(do_stxvd2x)
+ PPC_STLU r1,-STKFRM(r1)
+ mflr r0
+ PPC_STL r0,STKFRM+PPC_LR_STKOFF(r1)
+ mfmsr r6
+ oris r7,r6,MSR_VSX@h
+ cmpwi cr7,r3,0
+ li r8,STKFRM-16
+ mtmsrd r7
+ isync
+ beq cr7,1f
+ STXVD2X(0,r1,r8)
+ bl get_vsr
+1: li r9,-EFAULT
+2: STXVD2X(0,0,r4)
+ li r9,0
+3: beq cr7,4f
+ LXVD2X(0,r1,r8)
+4: PPC_LL r0,STKFRM+PPC_LR_STKOFF(r1)
+ mtlr r0
+ mtmsrd r6
+ isync
+ mr r3,r9
+ addi r1,r1,STKFRM
+ blr
+ extab 2b,3b
+
+#endif /* CONFIG_VSX */
diff --git a/arch/powerpc/lib/sstep.c b/arch/powerpc/lib/sstep.c
index 13b7d54f185..e0a9858d537 100644
--- a/arch/powerpc/lib/sstep.c
+++ b/arch/powerpc/lib/sstep.c
@@ -13,6 +13,8 @@
#include <linux/ptrace.h>
#include <asm/sstep.h>
#include <asm/processor.h>
+#include <asm/uaccess.h>
+#include <asm/cputable.h>
extern char system_call_common[];
@@ -23,6 +25,23 @@ extern char system_call_common[];
#define MSR_MASK 0x87c0ffff
#endif
+/* Bits in XER */
+#define XER_SO 0x80000000U
+#define XER_OV 0x40000000U
+#define XER_CA 0x20000000U
+
+/*
+ * Functions in ldstfp.S
+ */
+extern int do_lfs(int rn, unsigned long ea);
+extern int do_lfd(int rn, unsigned long ea);
+extern int do_stfs(int rn, unsigned long ea);
+extern int do_stfd(int rn, unsigned long ea);
+extern int do_lvx(int rn, unsigned long ea);
+extern int do_stvx(int rn, unsigned long ea);
+extern int do_lxvd2x(int rn, unsigned long ea);
+extern int do_stxvd2x(int rn, unsigned long ea);
+
/*
* Determine whether a conditional branch instruction would branch.
*/
@@ -46,16 +65,499 @@ static int __kprobes branch_taken(unsigned int instr, struct pt_regs *regs)
return 1;
}
+
+static long __kprobes address_ok(struct pt_regs *regs, unsigned long ea, int nb)
+{
+ if (!user_mode(regs))
+ return 1;
+ return __access_ok(ea, nb, USER_DS);
+}
+
+/*
+ * Calculate effective address for a D-form instruction
+ */
+static unsigned long __kprobes dform_ea(unsigned int instr, struct pt_regs *regs)
+{
+ int ra;
+ unsigned long ea;
+
+ ra = (instr >> 16) & 0x1f;
+ ea = (signed short) instr; /* sign-extend */
+ if (ra) {
+ ea += regs->gpr[ra];
+ if (instr & 0x04000000) /* update forms */
+ regs->gpr[ra] = ea;
+ }
+#ifdef __powerpc64__
+ if (!(regs->msr & MSR_SF))
+ ea &= 0xffffffffUL;
+#endif
+ return ea;
+}
+
+#ifdef __powerpc64__
+/*
+ * Calculate effective address for a DS-form instruction
+ */
+static unsigned long __kprobes dsform_ea(unsigned int instr, struct pt_regs *regs)
+{
+ int ra;
+ unsigned long ea;
+
+ ra = (instr >> 16) & 0x1f;
+ ea = (signed short) (instr & ~3); /* sign-extend */
+ if (ra) {
+ ea += regs->gpr[ra];
+ if ((instr & 3) == 1) /* update forms */
+ regs->gpr[ra] = ea;
+ }
+ if (!(regs->msr & MSR_SF))
+ ea &= 0xffffffffUL;
+ return ea;
+}
+#endif /* __powerpc64 */
+
+/*
+ * Calculate effective address for an X-form instruction
+ */
+static unsigned long __kprobes xform_ea(unsigned int instr, struct pt_regs *regs,
+ int do_update)
+{
+ int ra, rb;
+ unsigned long ea;
+
+ ra = (instr >> 16) & 0x1f;
+ rb = (instr >> 11) & 0x1f;
+ ea = regs->gpr[rb];
+ if (ra) {
+ ea += regs->gpr[ra];
+ if (do_update) /* update forms */
+ regs->gpr[ra] = ea;
+ }
+#ifdef __powerpc64__
+ if (!(regs->msr & MSR_SF))
+ ea &= 0xffffffffUL;
+#endif
+ return ea;
+}
+
+/*
+ * Return the largest power of 2, not greater than sizeof(unsigned long),
+ * such that x is a multiple of it.
+ */
+static inline unsigned long max_align(unsigned long x)
+{
+ x |= sizeof(unsigned long);
+ return x & -x; /* isolates rightmost bit */
+}
+
+
+static inline unsigned long byterev_2(unsigned long x)
+{
+ return ((x >> 8) & 0xff) | ((x & 0xff) << 8);
+}
+
+static inline unsigned long byterev_4(unsigned long x)
+{
+ return ((x >> 24) & 0xff) | ((x >> 8) & 0xff00) |
+ ((x & 0xff00) << 8) | ((x & 0xff) << 24);
+}
+
+#ifdef __powerpc64__
+static inline unsigned long byterev_8(unsigned long x)
+{
+ return (byterev_4(x) << 32) | byterev_4(x >> 32);
+}
+#endif
+
+static int __kprobes read_mem_aligned(unsigned long *dest, unsigned long ea,
+ int nb)
+{
+ int err = 0;
+ unsigned long x = 0;
+
+ switch (nb) {
+ case 1:
+ err = __get_user(x, (unsigned char __user *) ea);
+ break;
+ case 2:
+ err = __get_user(x, (unsigned short __user *) ea);
+ break;
+ case 4:
+ err = __get_user(x, (unsigned int __user *) ea);
+ break;
+#ifdef __powerpc64__
+ case 8:
+ err = __get_user(x, (unsigned long __user *) ea);
+ break;
+#endif
+ }
+ if (!err)
+ *dest = x;
+ return err;
+}
+
+static int __kprobes read_mem_unaligned(unsigned long *dest, unsigned long ea,
+ int nb, struct pt_regs *regs)
+{
+ int err;
+ unsigned long x, b, c;
+
+ /* unaligned, do this in pieces */
+ x = 0;
+ for (; nb > 0; nb -= c) {
+ c = max_align(ea);
+ if (c > nb)
+ c = max_align(nb);
+ err = read_mem_aligned(&b, ea, c);
+ if (err)
+ return err;
+ x = (x << (8 * c)) + b;
+ ea += c;
+ }
+ *dest = x;
+ return 0;
+}
+
+/*
+ * Read memory at address ea for nb bytes, return 0 for success
+ * or -EFAULT if an error occurred.
+ */
+static int __kprobes read_mem(unsigned long *dest, unsigned long ea, int nb,
+ struct pt_regs *regs)
+{
+ if (!address_ok(regs, ea, nb))
+ return -EFAULT;
+ if ((ea & (nb - 1)) == 0)
+ return read_mem_aligned(dest, ea, nb);
+ return read_mem_unaligned(dest, ea, nb, regs);
+}
+
+static int __kprobes write_mem_aligned(unsigned long val, unsigned long ea,
+ int nb)
+{
+ int err = 0;
+
+ switch (nb) {
+ case 1:
+ err = __put_user(val, (unsigned char __user *) ea);
+ break;
+ case 2:
+ err = __put_user(val, (unsigned short __user *) ea);
+ break;
+ case 4:
+ err = __put_user(val, (unsigned int __user *) ea);
+ break;
+#ifdef __powerpc64__
+ case 8:
+ err = __put_user(val, (unsigned long __user *) ea);
+ break;
+#endif
+ }
+ return err;
+}
+
+static int __kprobes write_mem_unaligned(unsigned long val, unsigned long ea,
+ int nb, struct pt_regs *regs)
+{
+ int err;
+ unsigned long c;
+
+ /* unaligned or little-endian, do this in pieces */
+ for (; nb > 0; nb -= c) {
+ c = max_align(ea);
+ if (c > nb)
+ c = max_align(nb);
+ err = write_mem_aligned(val >> (nb - c) * 8, ea, c);
+ if (err)
+ return err;
+ ++ea;
+ }
+ return 0;
+}
+
+/*
+ * Write memory at address ea for nb bytes, return 0 for success
+ * or -EFAULT if an error occurred.
+ */
+static int __kprobes write_mem(unsigned long val, unsigned long ea, int nb,
+ struct pt_regs *regs)
+{
+ if (!address_ok(regs, ea, nb))
+ return -EFAULT;
+ if ((ea & (nb - 1)) == 0)
+ return write_mem_aligned(val, ea, nb);
+ return write_mem_unaligned(val, ea, nb, regs);
+}
+
/*
- * Emulate instructions that cause a transfer of control.
+ * Check the address and alignment, and call func to do the actual
+ * load or store.
+ */
+static int __kprobes do_fp_load(int rn, int (*func)(int, unsigned long),
+ unsigned long ea, int nb,
+ struct pt_regs *regs)
+{
+ int err;
+ unsigned long val[sizeof(double) / sizeof(long)];
+ unsigned long ptr;
+
+ if (!address_ok(regs, ea, nb))
+ return -EFAULT;
+ if ((ea & 3) == 0)
+ return (*func)(rn, ea);
+ ptr = (unsigned long) &val[0];
+ if (sizeof(unsigned long) == 8 || nb == 4) {
+ err = read_mem_unaligned(&val[0], ea, nb, regs);
+ ptr += sizeof(unsigned long) - nb;
+ } else {
+ /* reading a double on 32-bit */
+ err = read_mem_unaligned(&val[0], ea, 4, regs);
+ if (!err)
+ err = read_mem_unaligned(&val[1], ea + 4, 4, regs);
+ }
+ if (err)
+ return err;
+ return (*func)(rn, ptr);
+}
+
+static int __kprobes do_fp_store(int rn, int (*func)(int, unsigned long),
+ unsigned long ea, int nb,
+ struct pt_regs *regs)
+{
+ int err;
+ unsigned long val[sizeof(double) / sizeof(long)];
+ unsigned long ptr;
+
+ if (!address_ok(regs, ea, nb))
+ return -EFAULT;
+ if ((ea & 3) == 0)
+ return (*func)(rn, ea);
+ ptr = (unsigned long) &val[0];
+ if (sizeof(unsigned long) == 8 || nb == 4) {
+ ptr += sizeof(unsigned long) - nb;
+ err = (*func)(rn, ptr);
+ if (err)
+ return err;
+ err = write_mem_unaligned(val[0], ea, nb, regs);
+ } else {
+ /* writing a double on 32-bit */
+ err = (*func)(rn, ptr);
+ if (err)
+ return err;
+ err = write_mem_unaligned(val[0], ea, 4, regs);
+ if (!err)
+ err = write_mem_unaligned(val[1], ea + 4, 4, regs);
+ }
+ return err;
+}
+
+#ifdef CONFIG_ALTIVEC
+/* For Altivec/VMX, no need to worry about alignment */
+static int __kprobes do_vec_load(int rn, int (*func)(int, unsigned long),
+ unsigned long ea, struct pt_regs *regs)
+{
+ if (!address_ok(regs, ea & ~0xfUL, 16))
+ return -EFAULT;
+ return (*func)(rn, ea);
+}
+
+static int __kprobes do_vec_store(int rn, int (*func)(int, unsigned long),
+ unsigned long ea, struct pt_regs *regs)
+{
+ if (!address_ok(regs, ea & ~0xfUL, 16))
+ return -EFAULT;
+ return (*func)(rn, ea);
+}
+#endif /* CONFIG_ALTIVEC */
+
+#ifdef CONFIG_VSX
+static int __kprobes do_vsx_load(int rn, int (*func)(int, unsigned long),
+ unsigned long ea, struct pt_regs *regs)
+{
+ int err;
+ unsigned long val[2];
+
+ if (!address_ok(regs, ea, 16))
+ return -EFAULT;
+ if ((ea & 3) == 0)
+ return (*func)(rn, ea);
+ err = read_mem_unaligned(&val[0], ea, 8, regs);
+ if (!err)
+ err = read_mem_unaligned(&val[1], ea + 8, 8, regs);
+ if (!err)
+ err = (*func)(rn, (unsigned long) &val[0]);
+ return err;
+}
+
+static int __kprobes do_vsx_store(int rn, int (*func)(int, unsigned long),
+ unsigned long ea, struct pt_regs *regs)
+{
+ int err;
+ unsigned long val[2];
+
+ if (!address_ok(regs, ea, 16))
+ return -EFAULT;
+ if ((ea & 3) == 0)
+ return (*func)(rn, ea);
+ err = (*func)(rn, (unsigned long) &val[0]);
+ if (err)
+ return err;
+ err = write_mem_unaligned(val[0], ea, 8, regs);
+ if (!err)
+ err = write_mem_unaligned(val[1], ea + 8, 8, regs);
+ return err;
+}
+#endif /* CONFIG_VSX */
+
+#define __put_user_asmx(x, addr, err, op, cr) \
+ __asm__ __volatile__( \
+ "1: " op " %2,0,%3\n" \
+ " mfcr %1\n" \
+ "2:\n" \
+ ".section .fixup,\"ax\"\n" \
+ "3: li %0,%4\n" \
+ " b 2b\n" \
+ ".previous\n" \
+ ".section __ex_table,\"a\"\n" \
+ PPC_LONG_ALIGN "\n" \
+ PPC_LONG "1b,3b\n" \
+ ".previous" \
+ : "=r" (err), "=r" (cr) \
+ : "r" (x), "r" (addr), "i" (-EFAULT), "0" (err))
+
+#define __get_user_asmx(x, addr, err, op) \
+ __asm__ __volatile__( \
+ "1: "op" %1,0,%2\n" \
+ "2:\n" \
+ ".section .fixup,\"ax\"\n" \
+ "3: li %0,%3\n" \
+ " b 2b\n" \
+ ".previous\n" \
+ ".section __ex_table,\"a\"\n" \
+ PPC_LONG_ALIGN "\n" \
+ PPC_LONG "1b,3b\n" \
+ ".previous" \
+ : "=r" (err), "=r" (x) \
+ : "r" (addr), "i" (-EFAULT), "0" (err))
+
+#define __cacheop_user_asmx(addr, err, op) \
+ __asm__ __volatile__( \
+ "1: "op" 0,%1\n" \
+ "2:\n" \
+ ".section .fixup,\"ax\"\n" \
+ "3: li %0,%3\n" \
+ " b 2b\n" \
+ ".previous\n" \
+ ".section __ex_table,\"a\"\n" \
+ PPC_LONG_ALIGN "\n" \
+ PPC_LONG "1b,3b\n" \
+ ".previous" \
+ : "=r" (err) \
+ : "r" (addr), "i" (-EFAULT), "0" (err))
+
+static void __kprobes set_cr0(struct pt_regs *regs, int rd)
+{
+ long val = regs->gpr[rd];
+
+ regs->ccr = (regs->ccr & 0x0fffffff) | ((regs->xer >> 3) & 0x10000000);
+#ifdef __powerpc64__
+ if (!(regs->msr & MSR_SF))
+ val = (int) val;
+#endif
+ if (val < 0)
+ regs->ccr |= 0x80000000;
+ else if (val > 0)
+ regs->ccr |= 0x40000000;
+ else
+ regs->ccr |= 0x20000000;
+}
+
+static void __kprobes add_with_carry(struct pt_regs *regs, int rd,
+ unsigned long val1, unsigned long val2,
+ unsigned long carry_in)
+{
+ unsigned long val = val1 + val2;
+
+ if (carry_in)
+ ++val;
+ regs->gpr[rd] = val;
+#ifdef __powerpc64__
+ if (!(regs->msr & MSR_SF)) {
+ val = (unsigned int) val;
+ val1 = (unsigned int) val1;
+ }
+#endif
+ if (val < val1 || (carry_in && val == val1))
+ regs->xer |= XER_CA;
+ else
+ regs->xer &= ~XER_CA;
+}
+
+static void __kprobes do_cmp_signed(struct pt_regs *regs, long v1, long v2,
+ int crfld)
+{
+ unsigned int crval, shift;
+
+ crval = (regs->xer >> 31) & 1; /* get SO bit */
+ if (v1 < v2)
+ crval |= 8;
+ else if (v1 > v2)
+ crval |= 4;
+ else
+ crval |= 2;
+ shift = (7 - crfld) * 4;
+ regs->ccr = (regs->ccr & ~(0xf << shift)) | (crval << shift);
+}
+
+static void __kprobes do_cmp_unsigned(struct pt_regs *regs, unsigned long v1,
+ unsigned long v2, int crfld)
+{
+ unsigned int crval, shift;
+
+ crval = (regs->xer >> 31) & 1; /* get SO bit */
+ if (v1 < v2)
+ crval |= 8;
+ else if (v1 > v2)
+ crval |= 4;
+ else
+ crval |= 2;
+ shift = (7 - crfld) * 4;
+ regs->ccr = (regs->ccr & ~(0xf << shift)) | (crval << shift);
+}
+
+/*
+ * Elements of 32-bit rotate and mask instructions.
+ */
+#define MASK32(mb, me) ((0xffffffffUL >> (mb)) + \
+ ((signed long)-0x80000000L >> (me)) + ((me) >= (mb)))
+#ifdef __powerpc64__
+#define MASK64_L(mb) (~0UL >> (mb))
+#define MASK64_R(me) ((signed long)-0x8000000000000000L >> (me))
+#define MASK64(mb, me) (MASK64_L(mb) + MASK64_R(me) + ((me) >= (mb)))
+#define DATA32(x) (((x) & 0xffffffffUL) | (((x) & 0xffffffffUL) << 32))
+#else
+#define DATA32(x) (x)
+#endif
+#define ROTATE(x, n) ((n) ? (((x) << (n)) | ((x) >> (8 * sizeof(long) - (n)))) : (x))
+
+/*
+ * Emulate instructions that cause a transfer of control,
+ * loads and stores, and a few other instructions.
* Returns 1 if the step was emulated, 0 if not,
* or -1 if the instruction is one that should not be stepped,
* such as an rfid, or a mtmsrd that would clear MSR_RI.
*/
int __kprobes emulate_step(struct pt_regs *regs, unsigned int instr)
{
- unsigned int opcode, rs, rb, rd, spr;
+ unsigned int opcode, ra, rb, rd, spr, u;
unsigned long int imm;
+ unsigned long int val, val2;
+ unsigned long int ea;
+ unsigned int cr, mb, me, sh;
+ int err;
+ unsigned long old_ra;
+ long ival;
opcode = instr >> 26;
switch (opcode) {
@@ -78,7 +580,13 @@ int __kprobes emulate_step(struct pt_regs *regs, unsigned int instr)
* entry code works. If that is changed, this will
* need to be changed also.
*/
+ if (regs->gpr[0] == 0x1ebe &&
+ cpu_has_feature(CPU_FTR_REAL_LE)) {
+ regs->msr ^= MSR_LE;
+ goto instr_done;
+ }
regs->gpr[9] = regs->gpr[13];
+ regs->gpr[10] = MSR_KERNEL;
regs->gpr[11] = regs->nip + 4;
regs->gpr[12] = regs->msr & MSR_MASK;
regs->gpr[13] = (unsigned long) get_paca();
@@ -102,9 +610,9 @@ int __kprobes emulate_step(struct pt_regs *regs, unsigned int instr)
regs->nip = imm;
return 1;
case 19:
- switch (instr & 0x7fe) {
- case 0x20: /* bclr */
- case 0x420: /* bcctr */
+ switch ((instr >> 1) & 0x3ff) {
+ case 16: /* bclr */
+ case 528: /* bcctr */
imm = (instr & 0x400)? regs->ctr: regs->link;
regs->nip += 4;
if ((regs->msr & MSR_SF) == 0) {
@@ -116,30 +624,233 @@ int __kprobes emulate_step(struct pt_regs *regs, unsigned int instr)
if (branch_taken(instr, regs))
regs->nip = imm;
return 1;
- case 0x24: /* rfid, scary */
+
+ case 18: /* rfid, scary */
return -1;
+
+ case 150: /* isync */
+ isync();
+ goto instr_done;
+
+ case 33: /* crnor */
+ case 129: /* crandc */
+ case 193: /* crxor */
+ case 225: /* crnand */
+ case 257: /* crand */
+ case 289: /* creqv */
+ case 417: /* crorc */
+ case 449: /* cror */
+ ra = (instr >> 16) & 0x1f;
+ rb = (instr >> 11) & 0x1f;
+ rd = (instr >> 21) & 0x1f;
+ ra = (regs->ccr >> (31 - ra)) & 1;
+ rb = (regs->ccr >> (31 - rb)) & 1;
+ val = (instr >> (6 + ra * 2 + rb)) & 1;
+ regs->ccr = (regs->ccr & ~(1UL << (31 - rd))) |
+ (val << (31 - rd));
+ goto instr_done;
+ }
+ break;
+ case 31:
+ switch ((instr >> 1) & 0x3ff) {
+ case 598: /* sync */
+#ifdef __powerpc64__
+ switch ((instr >> 21) & 3) {
+ case 1: /* lwsync */
+ asm volatile("lwsync" : : : "memory");
+ goto instr_done;
+ case 2: /* ptesync */
+ asm volatile("ptesync" : : : "memory");
+ goto instr_done;
+ }
+#endif
+ mb();
+ goto instr_done;
+
+ case 854: /* eieio */
+ eieio();
+ goto instr_done;
+ }
+ break;
+ }
+
+ /* Following cases refer to regs->gpr[], so we need all regs */
+ if (!FULL_REGS(regs))
+ return 0;
+
+ rd = (instr >> 21) & 0x1f;
+ ra = (instr >> 16) & 0x1f;
+ rb = (instr >> 11) & 0x1f;
+
+ switch (opcode) {
+ case 7: /* mulli */
+ regs->gpr[rd] = regs->gpr[ra] * (short) instr;
+ goto instr_done;
+
+ case 8: /* subfic */
+ imm = (short) instr;
+ add_with_carry(regs, rd, ~regs->gpr[ra], imm, 1);
+ goto instr_done;
+
+ case 10: /* cmpli */
+ imm = (unsigned short) instr;
+ val = regs->gpr[ra];
+#ifdef __powerpc64__
+ if ((rd & 1) == 0)
+ val = (unsigned int) val;
+#endif
+ do_cmp_unsigned(regs, val, imm, rd >> 2);
+ goto instr_done;
+
+ case 11: /* cmpi */
+ imm = (short) instr;
+ val = regs->gpr[ra];
+#ifdef __powerpc64__
+ if ((rd & 1) == 0)
+ val = (int) val;
+#endif
+ do_cmp_signed(regs, val, imm, rd >> 2);
+ goto instr_done;
+
+ case 12: /* addic */
+ imm = (short) instr;
+ add_with_carry(regs, rd, regs->gpr[ra], imm, 0);
+ goto instr_done;
+
+ case 13: /* addic. */
+ imm = (short) instr;
+ add_with_carry(regs, rd, regs->gpr[ra], imm, 0);
+ set_cr0(regs, rd);
+ goto instr_done;
+
+ case 14: /* addi */
+ imm = (short) instr;
+ if (ra)
+ imm += regs->gpr[ra];
+ regs->gpr[rd] = imm;
+ goto instr_done;
+
+ case 15: /* addis */
+ imm = ((short) instr) << 16;
+ if (ra)
+ imm += regs->gpr[ra];
+ regs->gpr[rd] = imm;
+ goto instr_done;
+
+ case 20: /* rlwimi */
+ mb = (instr >> 6) & 0x1f;
+ me = (instr >> 1) & 0x1f;
+ val = DATA32(regs->gpr[rd]);
+ imm = MASK32(mb, me);
+ regs->gpr[ra] = (regs->gpr[ra] & ~imm) | (ROTATE(val, rb) & imm);
+ goto logical_done;
+
+ case 21: /* rlwinm */
+ mb = (instr >> 6) & 0x1f;
+ me = (instr >> 1) & 0x1f;
+ val = DATA32(regs->gpr[rd]);
+ regs->gpr[ra] = ROTATE(val, rb) & MASK32(mb, me);
+ goto logical_done;
+
+ case 23: /* rlwnm */
+ mb = (instr >> 6) & 0x1f;
+ me = (instr >> 1) & 0x1f;
+ rb = regs->gpr[rb] & 0x1f;
+ val = DATA32(regs->gpr[rd]);
+ regs->gpr[ra] = ROTATE(val, rb) & MASK32(mb, me);
+ goto logical_done;
+
+ case 24: /* ori */
+ imm = (unsigned short) instr;
+ regs->gpr[ra] = regs->gpr[rd] | imm;
+ goto instr_done;
+
+ case 25: /* oris */
+ imm = (unsigned short) instr;
+ regs->gpr[ra] = regs->gpr[rd] | (imm << 16);
+ goto instr_done;
+
+ case 26: /* xori */
+ imm = (unsigned short) instr;
+ regs->gpr[ra] = regs->gpr[rd] ^ imm;
+ goto instr_done;
+
+ case 27: /* xoris */
+ imm = (unsigned short) instr;
+ regs->gpr[ra] = regs->gpr[rd] ^ (imm << 16);
+ goto instr_done;
+
+ case 28: /* andi. */
+ imm = (unsigned short) instr;
+ regs->gpr[ra] = regs->gpr[rd] & imm;
+ set_cr0(regs, ra);
+ goto instr_done;
+
+ case 29: /* andis. */
+ imm = (unsigned short) instr;
+ regs->gpr[ra] = regs->gpr[rd] & (imm << 16);
+ set_cr0(regs, ra);
+ goto instr_done;
+
+#ifdef __powerpc64__
+ case 30: /* rld* */
+ mb = ((instr >> 6) & 0x1f) | (instr & 0x20);
+ val = regs->gpr[rd];
+ if ((instr & 0x10) == 0) {
+ sh = rb | ((instr & 2) << 4);
+ val = ROTATE(val, sh);
+ switch ((instr >> 2) & 3) {
+ case 0: /* rldicl */
+ regs->gpr[ra] = val & MASK64_L(mb);
+ goto logical_done;
+ case 1: /* rldicr */
+ regs->gpr[ra] = val & MASK64_R(mb);
+ goto logical_done;
+ case 2: /* rldic */
+ regs->gpr[ra] = val & MASK64(mb, 63 - sh);
+ goto logical_done;
+ case 3: /* rldimi */
+ imm = MASK64(mb, 63 - sh);
+ regs->gpr[ra] = (regs->gpr[ra] & ~imm) |
+ (val & imm);
+ goto logical_done;
+ }
+ } else {
+ sh = regs->gpr[rb] & 0x3f;
+ val = ROTATE(val, sh);
+ switch ((instr >> 1) & 7) {
+ case 0: /* rldcl */
+ regs->gpr[ra] = val & MASK64_L(mb);
+ goto logical_done;
+ case 1: /* rldcr */
+ regs->gpr[ra] = val & MASK64_R(mb);
+ goto logical_done;
+ }
}
+#endif
+
case 31:
- rd = (instr >> 21) & 0x1f;
- switch (instr & 0x7fe) {
- case 0xa6: /* mfmsr */
+ switch ((instr >> 1) & 0x3ff) {
+ case 83: /* mfmsr */
+ if (regs->msr & MSR_PR)
+ break;
regs->gpr[rd] = regs->msr & MSR_MASK;
- regs->nip += 4;
- if ((regs->msr & MSR_SF) == 0)
- regs->nip &= 0xffffffffUL;
- return 1;
- case 0x124: /* mtmsr */
+ goto instr_done;
+ case 146: /* mtmsr */
+ if (regs->msr & MSR_PR)
+ break;
imm = regs->gpr[rd];
if ((imm & MSR_RI) == 0)
/* can't step mtmsr that would clear MSR_RI */
return -1;
regs->msr = imm;
- regs->nip += 4;
- return 1;
+ goto instr_done;
#ifdef CONFIG_PPC64
- case 0x164: /* mtmsrd */
+ case 178: /* mtmsrd */
/* only MSR_EE and MSR_RI get changed if bit 15 set */
/* mtmsrd doesn't change MSR_HV and MSR_ME */
+ if (regs->msr & MSR_PR)
+ break;
imm = (instr & 0x10000)? 0x8002: 0xefffffffffffefffUL;
imm = (regs->msr & MSR_MASK & ~imm)
| (regs->gpr[rd] & imm);
@@ -147,57 +858,770 @@ int __kprobes emulate_step(struct pt_regs *regs, unsigned int instr)
/* can't step mtmsrd that would clear MSR_RI */
return -1;
regs->msr = imm;
- regs->nip += 4;
- if ((imm & MSR_SF) == 0)
- regs->nip &= 0xffffffffUL;
- return 1;
+ goto instr_done;
#endif
- case 0x26: /* mfcr */
+ case 19: /* mfcr */
regs->gpr[rd] = regs->ccr;
regs->gpr[rd] &= 0xffffffffUL;
- goto mtspr_out;
- case 0x2a6: /* mfspr */
+ goto instr_done;
+
+ case 144: /* mtcrf */
+ imm = 0xf0000000UL;
+ val = regs->gpr[rd];
+ for (sh = 0; sh < 8; ++sh) {
+ if (instr & (0x80000 >> sh))
+ regs->ccr = (regs->ccr & ~imm) |
+ (val & imm);
+ imm >>= 4;
+ }
+ goto instr_done;
+
+ case 339: /* mfspr */
spr = (instr >> 11) & 0x3ff;
switch (spr) {
case 0x20: /* mfxer */
regs->gpr[rd] = regs->xer;
regs->gpr[rd] &= 0xffffffffUL;
- goto mtspr_out;
+ goto instr_done;
case 0x100: /* mflr */
regs->gpr[rd] = regs->link;
- goto mtspr_out;
+ goto instr_done;
case 0x120: /* mfctr */
regs->gpr[rd] = regs->ctr;
- goto mtspr_out;
- }
- break;
- case 0x378: /* orx */
- if (instr & 1)
- break;
- rs = (instr >> 21) & 0x1f;
- rb = (instr >> 11) & 0x1f;
- if (rs == rb) { /* mr */
- rd = (instr >> 16) & 0x1f;
- regs->gpr[rd] = regs->gpr[rs];
- goto mtspr_out;
+ goto instr_done;
}
break;
- case 0x3a6: /* mtspr */
+
+ case 467: /* mtspr */
spr = (instr >> 11) & 0x3ff;
switch (spr) {
case 0x20: /* mtxer */
regs->xer = (regs->gpr[rd] & 0xffffffffUL);
- goto mtspr_out;
+ goto instr_done;
case 0x100: /* mtlr */
regs->link = regs->gpr[rd];
- goto mtspr_out;
+ goto instr_done;
case 0x120: /* mtctr */
regs->ctr = regs->gpr[rd];
-mtspr_out:
- regs->nip += 4;
- return 1;
+ goto instr_done;
}
+ break;
+
+/*
+ * Compare instructions
+ */
+ case 0: /* cmp */
+ val = regs->gpr[ra];
+ val2 = regs->gpr[rb];
+#ifdef __powerpc64__
+ if ((rd & 1) == 0) {
+ /* word (32-bit) compare */
+ val = (int) val;
+ val2 = (int) val2;
+ }
+#endif
+ do_cmp_signed(regs, val, val2, rd >> 2);
+ goto instr_done;
+
+ case 32: /* cmpl */
+ val = regs->gpr[ra];
+ val2 = regs->gpr[rb];
+#ifdef __powerpc64__
+ if ((rd & 1) == 0) {
+ /* word (32-bit) compare */
+ val = (unsigned int) val;
+ val2 = (unsigned int) val2;
+ }
+#endif
+ do_cmp_unsigned(regs, val, val2, rd >> 2);
+ goto instr_done;
+
+/*
+ * Arithmetic instructions
+ */
+ case 8: /* subfc */
+ add_with_carry(regs, rd, ~regs->gpr[ra],
+ regs->gpr[rb], 1);
+ goto arith_done;
+#ifdef __powerpc64__
+ case 9: /* mulhdu */
+ asm("mulhdu %0,%1,%2" : "=r" (regs->gpr[rd]) :
+ "r" (regs->gpr[ra]), "r" (regs->gpr[rb]));
+ goto arith_done;
+#endif
+ case 10: /* addc */
+ add_with_carry(regs, rd, regs->gpr[ra],
+ regs->gpr[rb], 0);
+ goto arith_done;
+
+ case 11: /* mulhwu */
+ asm("mulhwu %0,%1,%2" : "=r" (regs->gpr[rd]) :
+ "r" (regs->gpr[ra]), "r" (regs->gpr[rb]));
+ goto arith_done;
+
+ case 40: /* subf */
+ regs->gpr[rd] = regs->gpr[rb] - regs->gpr[ra];
+ goto arith_done;
+#ifdef __powerpc64__
+ case 73: /* mulhd */
+ asm("mulhd %0,%1,%2" : "=r" (regs->gpr[rd]) :
+ "r" (regs->gpr[ra]), "r" (regs->gpr[rb]));
+ goto arith_done;
+#endif
+ case 75: /* mulhw */
+ asm("mulhw %0,%1,%2" : "=r" (regs->gpr[rd]) :
+ "r" (regs->gpr[ra]), "r" (regs->gpr[rb]));
+ goto arith_done;
+
+ case 104: /* neg */
+ regs->gpr[rd] = -regs->gpr[ra];
+ goto arith_done;
+
+ case 136: /* subfe */
+ add_with_carry(regs, rd, ~regs->gpr[ra], regs->gpr[rb],
+ regs->xer & XER_CA);
+ goto arith_done;
+
+ case 138: /* adde */
+ add_with_carry(regs, rd, regs->gpr[ra], regs->gpr[rb],
+ regs->xer & XER_CA);
+ goto arith_done;
+
+ case 200: /* subfze */
+ add_with_carry(regs, rd, ~regs->gpr[ra], 0L,
+ regs->xer & XER_CA);
+ goto arith_done;
+
+ case 202: /* addze */
+ add_with_carry(regs, rd, regs->gpr[ra], 0L,
+ regs->xer & XER_CA);
+ goto arith_done;
+
+ case 232: /* subfme */
+ add_with_carry(regs, rd, ~regs->gpr[ra], -1L,
+ regs->xer & XER_CA);
+ goto arith_done;
+#ifdef __powerpc64__
+ case 233: /* mulld */
+ regs->gpr[rd] = regs->gpr[ra] * regs->gpr[rb];
+ goto arith_done;
+#endif
+ case 234: /* addme */
+ add_with_carry(regs, rd, regs->gpr[ra], -1L,
+ regs->xer & XER_CA);
+ goto arith_done;
+
+ case 235: /* mullw */
+ regs->gpr[rd] = (unsigned int) regs->gpr[ra] *
+ (unsigned int) regs->gpr[rb];
+ goto arith_done;
+
+ case 266: /* add */
+ regs->gpr[rd] = regs->gpr[ra] + regs->gpr[rb];
+ goto arith_done;
+#ifdef __powerpc64__
+ case 457: /* divdu */
+ regs->gpr[rd] = regs->gpr[ra] / regs->gpr[rb];
+ goto arith_done;
+#endif
+ case 459: /* divwu */
+ regs->gpr[rd] = (unsigned int) regs->gpr[ra] /
+ (unsigned int) regs->gpr[rb];
+ goto arith_done;
+#ifdef __powerpc64__
+ case 489: /* divd */
+ regs->gpr[rd] = (long int) regs->gpr[ra] /
+ (long int) regs->gpr[rb];
+ goto arith_done;
+#endif
+ case 491: /* divw */
+ regs->gpr[rd] = (int) regs->gpr[ra] /
+ (int) regs->gpr[rb];
+ goto arith_done;
+
+
+/*
+ * Logical instructions
+ */
+ case 26: /* cntlzw */
+ asm("cntlzw %0,%1" : "=r" (regs->gpr[ra]) :
+ "r" (regs->gpr[rd]));
+ goto logical_done;
+#ifdef __powerpc64__
+ case 58: /* cntlzd */
+ asm("cntlzd %0,%1" : "=r" (regs->gpr[ra]) :
+ "r" (regs->gpr[rd]));
+ goto logical_done;
+#endif
+ case 28: /* and */
+ regs->gpr[ra] = regs->gpr[rd] & regs->gpr[rb];
+ goto logical_done;
+
+ case 60: /* andc */
+ regs->gpr[ra] = regs->gpr[rd] & ~regs->gpr[rb];
+ goto logical_done;
+
+ case 124: /* nor */
+ regs->gpr[ra] = ~(regs->gpr[rd] | regs->gpr[rb]);
+ goto logical_done;
+
+ case 284: /* xor */
+ regs->gpr[ra] = ~(regs->gpr[rd] ^ regs->gpr[rb]);
+ goto logical_done;
+
+ case 316: /* xor */
+ regs->gpr[ra] = regs->gpr[rd] ^ regs->gpr[rb];
+ goto logical_done;
+
+ case 412: /* orc */
+ regs->gpr[ra] = regs->gpr[rd] | ~regs->gpr[rb];
+ goto logical_done;
+
+ case 444: /* or */
+ regs->gpr[ra] = regs->gpr[rd] | regs->gpr[rb];
+ goto logical_done;
+
+ case 476: /* nand */
+ regs->gpr[ra] = ~(regs->gpr[rd] & regs->gpr[rb]);
+ goto logical_done;
+
+ case 922: /* extsh */
+ regs->gpr[ra] = (signed short) regs->gpr[rd];
+ goto logical_done;
+
+ case 954: /* extsb */
+ regs->gpr[ra] = (signed char) regs->gpr[rd];
+ goto logical_done;
+#ifdef __powerpc64__
+ case 986: /* extsw */
+ regs->gpr[ra] = (signed int) regs->gpr[rd];
+ goto logical_done;
+#endif
+
+/*
+ * Shift instructions
+ */
+ case 24: /* slw */
+ sh = regs->gpr[rb] & 0x3f;
+ if (sh < 32)
+ regs->gpr[ra] = (regs->gpr[rd] << sh) & 0xffffffffUL;
+ else
+ regs->gpr[ra] = 0;
+ goto logical_done;
+
+ case 536: /* srw */
+ sh = regs->gpr[rb] & 0x3f;
+ if (sh < 32)
+ regs->gpr[ra] = (regs->gpr[rd] & 0xffffffffUL) >> sh;
+ else
+ regs->gpr[ra] = 0;
+ goto logical_done;
+
+ case 792: /* sraw */
+ sh = regs->gpr[rb] & 0x3f;
+ ival = (signed int) regs->gpr[rd];
+ regs->gpr[ra] = ival >> (sh < 32 ? sh : 31);
+ if (ival < 0 && (sh >= 32 || (ival & ((1 << sh) - 1)) != 0))
+ regs->xer |= XER_CA;
+ else
+ regs->xer &= ~XER_CA;
+ goto logical_done;
+
+ case 824: /* srawi */
+ sh = rb;
+ ival = (signed int) regs->gpr[rd];
+ regs->gpr[ra] = ival >> sh;
+ if (ival < 0 && (ival & ((1 << sh) - 1)) != 0)
+ regs->xer |= XER_CA;
+ else
+ regs->xer &= ~XER_CA;
+ goto logical_done;
+
+#ifdef __powerpc64__
+ case 27: /* sld */
+ sh = regs->gpr[rd] & 0x7f;
+ if (sh < 64)
+ regs->gpr[ra] = regs->gpr[rd] << sh;
+ else
+ regs->gpr[ra] = 0;
+ goto logical_done;
+
+ case 539: /* srd */
+ sh = regs->gpr[rb] & 0x7f;
+ if (sh < 64)
+ regs->gpr[ra] = regs->gpr[rd] >> sh;
+ else
+ regs->gpr[ra] = 0;
+ goto logical_done;
+
+ case 794: /* srad */
+ sh = regs->gpr[rb] & 0x7f;
+ ival = (signed long int) regs->gpr[rd];
+ regs->gpr[ra] = ival >> (sh < 64 ? sh : 63);
+ if (ival < 0 && (sh >= 64 || (ival & ((1 << sh) - 1)) != 0))
+ regs->xer |= XER_CA;
+ else
+ regs->xer &= ~XER_CA;
+ goto logical_done;
+
+ case 826: /* sradi with sh_5 = 0 */
+ case 827: /* sradi with sh_5 = 1 */
+ sh = rb | ((instr & 2) << 4);
+ ival = (signed long int) regs->gpr[rd];
+ regs->gpr[ra] = ival >> sh;
+ if (ival < 0 && (ival & ((1 << sh) - 1)) != 0)
+ regs->xer |= XER_CA;
+ else
+ regs->xer &= ~XER_CA;
+ goto logical_done;
+#endif /* __powerpc64__ */
+
+/*
+ * Cache instructions
+ */
+ case 54: /* dcbst */
+ ea = xform_ea(instr, regs, 0);
+ if (!address_ok(regs, ea, 8))
+ return 0;
+ err = 0;
+ __cacheop_user_asmx(ea, err, "dcbst");
+ if (err)
+ return 0;
+ goto instr_done;
+
+ case 86: /* dcbf */
+ ea = xform_ea(instr, regs, 0);
+ if (!address_ok(regs, ea, 8))
+ return 0;
+ err = 0;
+ __cacheop_user_asmx(ea, err, "dcbf");
+ if (err)
+ return 0;
+ goto instr_done;
+
+ case 246: /* dcbtst */
+ if (rd == 0) {
+ ea = xform_ea(instr, regs, 0);
+ prefetchw((void *) ea);
+ }
+ goto instr_done;
+
+ case 278: /* dcbt */
+ if (rd == 0) {
+ ea = xform_ea(instr, regs, 0);
+ prefetch((void *) ea);
+ }
+ goto instr_done;
+
}
+ break;
}
- return 0;
+
+ /*
+ * Following cases are for loads and stores, so bail out
+ * if we're in little-endian mode.
+ */
+ if (regs->msr & MSR_LE)
+ return 0;
+
+ /*
+ * Save register RA in case it's an update form load or store
+ * and the access faults.
+ */
+ old_ra = regs->gpr[ra];
+
+ switch (opcode) {
+ case 31:
+ u = instr & 0x40;
+ switch ((instr >> 1) & 0x3ff) {
+ case 20: /* lwarx */
+ ea = xform_ea(instr, regs, 0);
+ if (ea & 3)
+ break; /* can't handle misaligned */
+ err = -EFAULT;
+ if (!address_ok(regs, ea, 4))
+ goto ldst_done;
+ err = 0;
+ __get_user_asmx(val, ea, err, "lwarx");
+ if (!err)
+ regs->gpr[rd] = val;
+ goto ldst_done;
+
+ case 150: /* stwcx. */
+ ea = xform_ea(instr, regs, 0);
+ if (ea & 3)
+ break; /* can't handle misaligned */
+ err = -EFAULT;
+ if (!address_ok(regs, ea, 4))
+ goto ldst_done;
+ err = 0;
+ __put_user_asmx(regs->gpr[rd], ea, err, "stwcx.", cr);
+ if (!err)
+ regs->ccr = (regs->ccr & 0x0fffffff) |
+ (cr & 0xe0000000) |
+ ((regs->xer >> 3) & 0x10000000);
+ goto ldst_done;
+
+#ifdef __powerpc64__
+ case 84: /* ldarx */
+ ea = xform_ea(instr, regs, 0);
+ if (ea & 7)
+ break; /* can't handle misaligned */
+ err = -EFAULT;
+ if (!address_ok(regs, ea, 8))
+ goto ldst_done;
+ err = 0;
+ __get_user_asmx(val, ea, err, "ldarx");
+ if (!err)
+ regs->gpr[rd] = val;
+ goto ldst_done;
+
+ case 214: /* stdcx. */
+ ea = xform_ea(instr, regs, 0);
+ if (ea & 7)
+ break; /* can't handle misaligned */
+ err = -EFAULT;
+ if (!address_ok(regs, ea, 8))
+ goto ldst_done;
+ err = 0;
+ __put_user_asmx(regs->gpr[rd], ea, err, "stdcx.", cr);
+ if (!err)
+ regs->ccr = (regs->ccr & 0x0fffffff) |
+ (cr & 0xe0000000) |
+ ((regs->xer >> 3) & 0x10000000);
+ goto ldst_done;
+
+ case 21: /* ldx */
+ case 53: /* ldux */
+ err = read_mem(&regs->gpr[rd], xform_ea(instr, regs, u),
+ 8, regs);
+ goto ldst_done;
+#endif
+
+ case 23: /* lwzx */
+ case 55: /* lwzux */
+ err = read_mem(&regs->gpr[rd], xform_ea(instr, regs, u),
+ 4, regs);
+ goto ldst_done;
+
+ case 87: /* lbzx */
+ case 119: /* lbzux */
+ err = read_mem(&regs->gpr[rd], xform_ea(instr, regs, u),
+ 1, regs);
+ goto ldst_done;
+
+#ifdef CONFIG_ALTIVEC
+ case 103: /* lvx */
+ case 359: /* lvxl */
+ if (!(regs->msr & MSR_VEC))
+ break;
+ ea = xform_ea(instr, regs, 0);
+ err = do_vec_load(rd, do_lvx, ea, regs);
+ goto ldst_done;
+
+ case 231: /* stvx */
+ case 487: /* stvxl */
+ if (!(regs->msr & MSR_VEC))
+ break;
+ ea = xform_ea(instr, regs, 0);
+ err = do_vec_store(rd, do_stvx, ea, regs);
+ goto ldst_done;
+#endif /* CONFIG_ALTIVEC */
+
+#ifdef __powerpc64__
+ case 149: /* stdx */
+ case 181: /* stdux */
+ val = regs->gpr[rd];
+ err = write_mem(val, xform_ea(instr, regs, u), 8, regs);
+ goto ldst_done;
+#endif
+
+ case 151: /* stwx */
+ case 183: /* stwux */
+ val = regs->gpr[rd];
+ err = write_mem(val, xform_ea(instr, regs, u), 4, regs);
+ goto ldst_done;
+
+ case 215: /* stbx */
+ case 247: /* stbux */
+ val = regs->gpr[rd];
+ err = write_mem(val, xform_ea(instr, regs, u), 1, regs);
+ goto ldst_done;
+
+ case 279: /* lhzx */
+ case 311: /* lhzux */
+ err = read_mem(&regs->gpr[rd], xform_ea(instr, regs, u),
+ 2, regs);
+ goto ldst_done;
+
+#ifdef __powerpc64__
+ case 341: /* lwax */
+ case 373: /* lwaux */
+ err = read_mem(&regs->gpr[rd], xform_ea(instr, regs, u),
+ 4, regs);
+ if (!err)
+ regs->gpr[rd] = (signed int) regs->gpr[rd];
+ goto ldst_done;
+#endif
+
+ case 343: /* lhax */
+ case 375: /* lhaux */
+ err = read_mem(&regs->gpr[rd], xform_ea(instr, regs, u),
+ 2, regs);
+ if (!err)
+ regs->gpr[rd] = (signed short) regs->gpr[rd];
+ goto ldst_done;
+
+ case 407: /* sthx */
+ case 439: /* sthux */
+ val = regs->gpr[rd];
+ err = write_mem(val, xform_ea(instr, regs, u), 2, regs);
+ goto ldst_done;
+
+#ifdef __powerpc64__
+ case 532: /* ldbrx */
+ err = read_mem(&val, xform_ea(instr, regs, 0), 8, regs);
+ if (!err)
+ regs->gpr[rd] = byterev_8(val);
+ goto ldst_done;
+
+#endif
+
+ case 534: /* lwbrx */
+ err = read_mem(&val, xform_ea(instr, regs, 0), 4, regs);
+ if (!err)
+ regs->gpr[rd] = byterev_4(val);
+ goto ldst_done;
+
+ case 535: /* lfsx */
+ case 567: /* lfsux */
+ if (!(regs->msr & MSR_FP))
+ break;
+ ea = xform_ea(instr, regs, u);
+ err = do_fp_load(rd, do_lfs, ea, 4, regs);
+ goto ldst_done;
+
+ case 599: /* lfdx */
+ case 631: /* lfdux */
+ if (!(regs->msr & MSR_FP))
+ break;
+ ea = xform_ea(instr, regs, u);
+ err = do_fp_load(rd, do_lfd, ea, 8, regs);
+ goto ldst_done;
+
+ case 663: /* stfsx */
+ case 695: /* stfsux */
+ if (!(regs->msr & MSR_FP))
+ break;
+ ea = xform_ea(instr, regs, u);
+ err = do_fp_store(rd, do_stfs, ea, 4, regs);
+ goto ldst_done;
+
+ case 727: /* stfdx */
+ case 759: /* stfdux */
+ if (!(regs->msr & MSR_FP))
+ break;
+ ea = xform_ea(instr, regs, u);
+ err = do_fp_store(rd, do_stfd, ea, 8, regs);
+ goto ldst_done;
+
+#ifdef __powerpc64__
+ case 660: /* stdbrx */
+ val = byterev_8(regs->gpr[rd]);
+ err = write_mem(val, xform_ea(instr, regs, 0), 8, regs);
+ goto ldst_done;
+
+#endif
+ case 662: /* stwbrx */
+ val = byterev_4(regs->gpr[rd]);
+ err = write_mem(val, xform_ea(instr, regs, 0), 4, regs);
+ goto ldst_done;
+
+ case 790: /* lhbrx */
+ err = read_mem(&val, xform_ea(instr, regs, 0), 2, regs);
+ if (!err)
+ regs->gpr[rd] = byterev_2(val);
+ goto ldst_done;
+
+ case 918: /* sthbrx */
+ val = byterev_2(regs->gpr[rd]);
+ err = write_mem(val, xform_ea(instr, regs, 0), 2, regs);
+ goto ldst_done;
+
+#ifdef CONFIG_VSX
+ case 844: /* lxvd2x */
+ case 876: /* lxvd2ux */
+ if (!(regs->msr & MSR_VSX))
+ break;
+ rd |= (instr & 1) << 5;
+ ea = xform_ea(instr, regs, u);
+ err = do_vsx_load(rd, do_lxvd2x, ea, regs);
+ goto ldst_done;
+
+ case 972: /* stxvd2x */
+ case 1004: /* stxvd2ux */
+ if (!(regs->msr & MSR_VSX))
+ break;
+ rd |= (instr & 1) << 5;
+ ea = xform_ea(instr, regs, u);
+ err = do_vsx_store(rd, do_stxvd2x, ea, regs);
+ goto ldst_done;
+
+#endif /* CONFIG_VSX */
+ }
+ break;
+
+ case 32: /* lwz */
+ case 33: /* lwzu */
+ err = read_mem(&regs->gpr[rd], dform_ea(instr, regs), 4, regs);
+ goto ldst_done;
+
+ case 34: /* lbz */
+ case 35: /* lbzu */
+ err = read_mem(&regs->gpr[rd], dform_ea(instr, regs), 1, regs);
+ goto ldst_done;
+
+ case 36: /* stw */
+ case 37: /* stwu */
+ val = regs->gpr[rd];
+ err = write_mem(val, dform_ea(instr, regs), 4, regs);
+ goto ldst_done;
+
+ case 38: /* stb */
+ case 39: /* stbu */
+ val = regs->gpr[rd];
+ err = write_mem(val, dform_ea(instr, regs), 1, regs);
+ goto ldst_done;
+
+ case 40: /* lhz */
+ case 41: /* lhzu */
+ err = read_mem(&regs->gpr[rd], dform_ea(instr, regs), 2, regs);
+ goto ldst_done;
+
+ case 42: /* lha */
+ case 43: /* lhau */
+ err = read_mem(&regs->gpr[rd], dform_ea(instr, regs), 2, regs);
+ if (!err)
+ regs->gpr[rd] = (signed short) regs->gpr[rd];
+ goto ldst_done;
+
+ case 44: /* sth */
+ case 45: /* sthu */
+ val = regs->gpr[rd];
+ err = write_mem(val, dform_ea(instr, regs), 2, regs);
+ goto ldst_done;
+
+ case 46: /* lmw */
+ ra = (instr >> 16) & 0x1f;
+ if (ra >= rd)
+ break; /* invalid form, ra in range to load */
+ ea = dform_ea(instr, regs);
+ do {
+ err = read_mem(&regs->gpr[rd], ea, 4, regs);
+ if (err)
+ return 0;
+ ea += 4;
+ } while (++rd < 32);
+ goto instr_done;
+
+ case 47: /* stmw */
+ ea = dform_ea(instr, regs);
+ do {
+ err = write_mem(regs->gpr[rd], ea, 4, regs);
+ if (err)
+ return 0;
+ ea += 4;
+ } while (++rd < 32);
+ goto instr_done;
+
+ case 48: /* lfs */
+ case 49: /* lfsu */
+ if (!(regs->msr & MSR_FP))
+ break;
+ ea = dform_ea(instr, regs);
+ err = do_fp_load(rd, do_lfs, ea, 4, regs);
+ goto ldst_done;
+
+ case 50: /* lfd */
+ case 51: /* lfdu */
+ if (!(regs->msr & MSR_FP))
+ break;
+ ea = dform_ea(instr, regs);
+ err = do_fp_load(rd, do_lfd, ea, 8, regs);
+ goto ldst_done;
+
+ case 52: /* stfs */
+ case 53: /* stfsu */
+ if (!(regs->msr & MSR_FP))
+ break;
+ ea = dform_ea(instr, regs);
+ err = do_fp_store(rd, do_stfs, ea, 4, regs);
+ goto ldst_done;
+
+ case 54: /* stfd */
+ case 55: /* stfdu */
+ if (!(regs->msr & MSR_FP))
+ break;
+ ea = dform_ea(instr, regs);
+ err = do_fp_store(rd, do_stfd, ea, 8, regs);
+ goto ldst_done;
+
+#ifdef __powerpc64__
+ case 58: /* ld[u], lwa */
+ switch (instr & 3) {
+ case 0: /* ld */
+ err = read_mem(&regs->gpr[rd], dsform_ea(instr, regs),
+ 8, regs);
+ goto ldst_done;
+ case 1: /* ldu */
+ err = read_mem(&regs->gpr[rd], dsform_ea(instr, regs),
+ 8, regs);
+ goto ldst_done;
+ case 2: /* lwa */
+ err = read_mem(&regs->gpr[rd], dsform_ea(instr, regs),
+ 4, regs);
+ if (!err)
+ regs->gpr[rd] = (signed int) regs->gpr[rd];
+ goto ldst_done;
+ }
+ break;
+
+ case 62: /* std[u] */
+ val = regs->gpr[rd];
+ switch (instr & 3) {
+ case 0: /* std */
+ err = write_mem(val, dsform_ea(instr, regs), 8, regs);
+ goto ldst_done;
+ case 1: /* stdu */
+ err = write_mem(val, dsform_ea(instr, regs), 8, regs);
+ goto ldst_done;
+ }
+ break;
+#endif /* __powerpc64__ */
+
+ }
+ err = -EINVAL;
+
+ ldst_done:
+ if (err) {
+ regs->gpr[ra] = old_ra;
+ return 0; /* invoke DSI if -EFAULT? */
+ }
+ instr_done:
+ regs->nip += 4;
+#ifdef __powerpc64__
+ if ((regs->msr & MSR_SF) == 0)
+ regs->nip &= 0xffffffffUL;
+#endif
+ return 1;
+
+ logical_done:
+ if (instr & 1)
+ set_cr0(regs, ra);
+ goto instr_done;
+
+ arith_done:
+ if (instr & 1)
+ set_cr0(regs, rd);
+ goto instr_done;
}
diff --git a/arch/powerpc/mm/fsl_booke_mmu.c b/arch/powerpc/mm/fsl_booke_mmu.c
index cdc7526e9c9..4b66a1ece6d 100644
--- a/arch/powerpc/mm/fsl_booke_mmu.c
+++ b/arch/powerpc/mm/fsl_booke_mmu.c
@@ -104,9 +104,10 @@ unsigned long p_mapped_by_tlbcam(phys_addr_t pa)
}
/*
- * Set up one of the I/D BAT (block address translation) register pairs.
- * The parameters are not checked; in particular size must be a power
- * of 4 between 4k and 256M.
+ * Set up a variable-size TLB entry (tlbcam). The parameters are not checked;
+ * in particular size must be a power of 4 between 4k and 256M (or 1G, for cpus
+ * that support extended page sizes). Note that while some cpus support a
+ * page size of 4G, we don't allow its use here.
*/
static void settlbcam(int index, unsigned long virt, phys_addr_t phys,
unsigned long size, unsigned long flags, unsigned int pid)
diff --git a/arch/powerpc/mm/numa.c b/arch/powerpc/mm/numa.c
index aa731af720c..002878ccf90 100644
--- a/arch/powerpc/mm/numa.c
+++ b/arch/powerpc/mm/numa.c
@@ -42,6 +42,12 @@ EXPORT_SYMBOL(node_data);
static int min_common_depth;
static int n_mem_addr_cells, n_mem_size_cells;
+static int form1_affinity;
+
+#define MAX_DISTANCE_REF_POINTS 4
+static int distance_ref_points_depth;
+static const unsigned int *distance_ref_points;
+static int distance_lookup_table[MAX_NUMNODES][MAX_DISTANCE_REF_POINTS];
/*
* Allocate node_to_cpumask_map based on number of available nodes
@@ -204,6 +210,39 @@ static const u32 *of_get_usable_memory(struct device_node *memory)
return prop;
}
+int __node_distance(int a, int b)
+{
+ int i;
+ int distance = LOCAL_DISTANCE;
+
+ if (!form1_affinity)
+ return distance;
+
+ for (i = 0; i < distance_ref_points_depth; i++) {
+ if (distance_lookup_table[a][i] == distance_lookup_table[b][i])
+ break;
+
+ /* Double the distance for each NUMA level */
+ distance *= 2;
+ }
+
+ return distance;
+}
+
+static void initialize_distance_lookup_table(int nid,
+ const unsigned int *associativity)
+{
+ int i;
+
+ if (!form1_affinity)
+ return;
+
+ for (i = 0; i < distance_ref_points_depth; i++) {
+ distance_lookup_table[nid][i] =
+ associativity[distance_ref_points[i]];
+ }
+}
+
/* Returns nid in the range [0..MAX_NUMNODES-1], or -1 if no useful numa
* info is found.
*/
@@ -225,6 +264,10 @@ static int of_node_to_nid_single(struct device_node *device)
/* POWER4 LPAR uses 0xffff as invalid node */
if (nid == 0xffff || nid >= MAX_NUMNODES)
nid = -1;
+
+ if (nid > 0 && tmp[0] >= distance_ref_points_depth)
+ initialize_distance_lookup_table(nid, tmp);
+
out:
return nid;
}
@@ -251,26 +294,10 @@ int of_node_to_nid(struct device_node *device)
}
EXPORT_SYMBOL_GPL(of_node_to_nid);
-/*
- * In theory, the "ibm,associativity" property may contain multiple
- * associativity lists because a resource may be multiply connected
- * into the machine. This resource then has different associativity
- * characteristics relative to its multiple connections. We ignore
- * this for now. We also assume that all cpu and memory sets have
- * their distances represented at a common level. This won't be
- * true for hierarchical NUMA.
- *
- * In any case the ibm,associativity-reference-points should give
- * the correct depth for a normal NUMA system.
- *
- * - Dave Hansen <haveblue@us.ibm.com>
- */
static int __init find_min_common_depth(void)
{
- int depth, index;
- const unsigned int *ref_points;
+ int depth;
struct device_node *rtas_root;
- unsigned int len;
struct device_node *chosen;
const char *vec5;
@@ -280,18 +307,28 @@ static int __init find_min_common_depth(void)
return -1;
/*
- * this property is 2 32-bit integers, each representing a level of
- * depth in the associativity nodes. The first is for an SMP
- * configuration (should be all 0's) and the second is for a normal
- * NUMA configuration.
+ * This property is a set of 32-bit integers, each representing
+ * an index into the ibm,associativity nodes.
+ *
+ * With form 0 affinity the first integer is for an SMP configuration
+ * (should be all 0's) and the second is for a normal NUMA
+ * configuration. We have only one level of NUMA.
+ *
+ * With form 1 affinity the first integer is the most significant
+ * NUMA boundary and the following are progressively less significant
+ * boundaries. There can be more than one level of NUMA.
*/
- index = 1;
- ref_points = of_get_property(rtas_root,
- "ibm,associativity-reference-points", &len);
+ distance_ref_points = of_get_property(rtas_root,
+ "ibm,associativity-reference-points",
+ &distance_ref_points_depth);
+
+ if (!distance_ref_points) {
+ dbg("NUMA: ibm,associativity-reference-points not found.\n");
+ goto err;
+ }
+
+ distance_ref_points_depth /= sizeof(int);
- /*
- * For form 1 affinity information we want the first field
- */
#define VEC5_AFFINITY_BYTE 5
#define VEC5_AFFINITY 0x80
chosen = of_find_node_by_path("/chosen");
@@ -299,19 +336,38 @@ static int __init find_min_common_depth(void)
vec5 = of_get_property(chosen, "ibm,architecture-vec-5", NULL);
if (vec5 && (vec5[VEC5_AFFINITY_BYTE] & VEC5_AFFINITY)) {
dbg("Using form 1 affinity\n");
- index = 0;
+ form1_affinity = 1;
}
}
- if ((len >= 2 * sizeof(unsigned int)) && ref_points) {
- depth = ref_points[index];
+ if (form1_affinity) {
+ depth = distance_ref_points[0];
} else {
- dbg("NUMA: ibm,associativity-reference-points not found.\n");
- depth = -1;
+ if (distance_ref_points_depth < 2) {
+ printk(KERN_WARNING "NUMA: "
+ "short ibm,associativity-reference-points\n");
+ goto err;
+ }
+
+ depth = distance_ref_points[1];
}
- of_node_put(rtas_root);
+ /*
+ * Warn and cap if the hardware supports more than
+ * MAX_DISTANCE_REF_POINTS domains.
+ */
+ if (distance_ref_points_depth > MAX_DISTANCE_REF_POINTS) {
+ printk(KERN_WARNING "NUMA: distance array capped at "
+ "%d entries\n", MAX_DISTANCE_REF_POINTS);
+ distance_ref_points_depth = MAX_DISTANCE_REF_POINTS;
+ }
+
+ of_node_put(rtas_root);
return depth;
+
+err:
+ of_node_put(rtas_root);
+ return -1;
}
static void __init get_n_mem_cells(int *n_addr_cells, int *n_size_cells)
diff --git a/arch/powerpc/mm/pgtable.c b/arch/powerpc/mm/pgtable.c
index ebc2f38eb38..2c7e801ab20 100644
--- a/arch/powerpc/mm/pgtable.c
+++ b/arch/powerpc/mm/pgtable.c
@@ -92,7 +92,6 @@ static void pte_free_rcu_callback(struct rcu_head *head)
static void pte_free_submit(struct pte_freelist_batch *batch)
{
- INIT_RCU_HEAD(&batch->rcu);
call_rcu(&batch->rcu, pte_free_rcu_callback);
}
diff --git a/arch/powerpc/mm/tlb_hash32.c b/arch/powerpc/mm/tlb_hash32.c
index 8aaa8b7eb32..690566b66e8 100644
--- a/arch/powerpc/mm/tlb_hash32.c
+++ b/arch/powerpc/mm/tlb_hash32.c
@@ -89,17 +89,6 @@ void tlb_flush(struct mmu_gather *tlb)
* -- Cort
*/
-/*
- * 750 SMP is a Bad Idea because the 750 doesn't broadcast all
- * the cache operations on the bus. Hence we need to use an IPI
- * to get the other CPU(s) to invalidate their TLBs.
- */
-#ifdef CONFIG_SMP_750
-#define FINISH_FLUSH smp_send_tlb_invalidate(0)
-#else
-#define FINISH_FLUSH do { } while (0)
-#endif
-
static void flush_range(struct mm_struct *mm, unsigned long start,
unsigned long end)
{
@@ -138,7 +127,6 @@ static void flush_range(struct mm_struct *mm, unsigned long start,
void flush_tlb_kernel_range(unsigned long start, unsigned long end)
{
flush_range(&init_mm, start, end);
- FINISH_FLUSH;
}
EXPORT_SYMBOL(flush_tlb_kernel_range);
@@ -162,7 +150,6 @@ void flush_tlb_mm(struct mm_struct *mm)
*/
for (mp = mm->mmap; mp != NULL; mp = mp->vm_next)
flush_range(mp->vm_mm, mp->vm_start, mp->vm_end);
- FINISH_FLUSH;
}
EXPORT_SYMBOL(flush_tlb_mm);
@@ -179,7 +166,6 @@ void flush_tlb_page(struct vm_area_struct *vma, unsigned long vmaddr)
pmd = pmd_offset(pud_offset(pgd_offset(mm, vmaddr), vmaddr), vmaddr);
if (!pmd_none(*pmd))
flush_hash_pages(mm->context.id, vmaddr, pmd_val(*pmd), 1);
- FINISH_FLUSH;
}
EXPORT_SYMBOL(flush_tlb_page);
@@ -192,6 +178,5 @@ void flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
unsigned long end)
{
flush_range(vma->vm_mm, start, end);
- FINISH_FLUSH;
}
EXPORT_SYMBOL(flush_tlb_range);
diff --git a/arch/powerpc/mm/tlb_nohash.c b/arch/powerpc/mm/tlb_nohash.c
index d8695b02a96..fe391e94252 100644
--- a/arch/powerpc/mm/tlb_nohash.c
+++ b/arch/powerpc/mm/tlb_nohash.c
@@ -46,6 +46,7 @@
struct mmu_psize_def mmu_psize_defs[MMU_PAGE_COUNT] = {
[MMU_PAGE_4K] = {
.shift = 12,
+ .ind = 20,
.enc = BOOK3E_PAGESZ_4K,
},
[MMU_PAGE_16K] = {
@@ -54,6 +55,7 @@ struct mmu_psize_def mmu_psize_defs[MMU_PAGE_COUNT] = {
},
[MMU_PAGE_64K] = {
.shift = 16,
+ .ind = 28,
.enc = BOOK3E_PAGESZ_64K,
},
[MMU_PAGE_1M] = {
@@ -62,6 +64,7 @@ struct mmu_psize_def mmu_psize_defs[MMU_PAGE_COUNT] = {
},
[MMU_PAGE_16M] = {
.shift = 24,
+ .ind = 36,
.enc = BOOK3E_PAGESZ_16M,
},
[MMU_PAGE_256M] = {
@@ -344,16 +347,108 @@ void tlb_flush_pgtable(struct mmu_gather *tlb, unsigned long address)
}
}
-/*
- * Early initialization of the MMU TLB code
- */
-static void __early_init_mmu(int boot_cpu)
+static void setup_page_sizes(void)
+{
+ unsigned int tlb0cfg = mfspr(SPRN_TLB0CFG);
+ unsigned int tlb0ps = mfspr(SPRN_TLB0PS);
+ unsigned int eptcfg = mfspr(SPRN_EPTCFG);
+ int i, psize;
+
+ /* Look for supported direct sizes */
+ for (psize = 0; psize < MMU_PAGE_COUNT; ++psize) {
+ struct mmu_psize_def *def = &mmu_psize_defs[psize];
+
+ if (tlb0ps & (1U << (def->shift - 10)))
+ def->flags |= MMU_PAGE_SIZE_DIRECT;
+ }
+
+ /* Indirect page sizes supported ? */
+ if ((tlb0cfg & TLBnCFG_IND) == 0)
+ goto no_indirect;
+
+ /* Now, we only deal with one IND page size for each
+ * direct size. Hopefully all implementations today are
+ * unambiguous, but we might want to be careful in the
+ * future.
+ */
+ for (i = 0; i < 3; i++) {
+ unsigned int ps, sps;
+
+ sps = eptcfg & 0x1f;
+ eptcfg >>= 5;
+ ps = eptcfg & 0x1f;
+ eptcfg >>= 5;
+ if (!ps || !sps)
+ continue;
+ for (psize = 0; psize < MMU_PAGE_COUNT; psize++) {
+ struct mmu_psize_def *def = &mmu_psize_defs[psize];
+
+ if (ps == (def->shift - 10))
+ def->flags |= MMU_PAGE_SIZE_INDIRECT;
+ if (sps == (def->shift - 10))
+ def->ind = ps + 10;
+ }
+ }
+ no_indirect:
+
+ /* Cleanup array and print summary */
+ pr_info("MMU: Supported page sizes\n");
+ for (psize = 0; psize < MMU_PAGE_COUNT; ++psize) {
+ struct mmu_psize_def *def = &mmu_psize_defs[psize];
+ const char *__page_type_names[] = {
+ "unsupported",
+ "direct",
+ "indirect",
+ "direct & indirect"
+ };
+ if (def->flags == 0) {
+ def->shift = 0;
+ continue;
+ }
+ pr_info(" %8ld KB as %s\n", 1ul << (def->shift - 10),
+ __page_type_names[def->flags & 0x3]);
+ }
+}
+
+static void setup_mmu_htw(void)
{
extern unsigned int interrupt_base_book3e;
extern unsigned int exc_data_tlb_miss_htw_book3e;
extern unsigned int exc_instruction_tlb_miss_htw_book3e;
unsigned int *ibase = &interrupt_base_book3e;
+
+ /* Check if HW tablewalk is present, and if yes, enable it by:
+ *
+ * - patching the TLB miss handlers to branch to the
+ * one dedicates to it
+ *
+ * - setting the global book3e_htw_enabled
+ */
+ unsigned int tlb0cfg = mfspr(SPRN_TLB0CFG);
+
+ if ((tlb0cfg & TLBnCFG_IND) &&
+ (tlb0cfg & TLBnCFG_PT)) {
+ /* Our exceptions vectors start with a NOP and -then- a branch
+ * to deal with single stepping from userspace which stops on
+ * the second instruction. Thus we need to patch the second
+ * instruction of the exception, not the first one
+ */
+ patch_branch(ibase + (0x1c0 / 4) + 1,
+ (unsigned long)&exc_data_tlb_miss_htw_book3e, 0);
+ patch_branch(ibase + (0x1e0 / 4) + 1,
+ (unsigned long)&exc_instruction_tlb_miss_htw_book3e, 0);
+ book3e_htw_enabled = 1;
+ }
+ pr_info("MMU: Book3E Page Tables %s\n",
+ book3e_htw_enabled ? "Enabled" : "Disabled");
+}
+
+/*
+ * Early initialization of the MMU TLB code
+ */
+static void __early_init_mmu(int boot_cpu)
+{
unsigned int mas4;
/* XXX This will have to be decided at runtime, but right
@@ -370,35 +465,17 @@ static void __early_init_mmu(int boot_cpu)
*/
mmu_vmemmap_psize = MMU_PAGE_16M;
- /* Check if HW tablewalk is present, and if yes, enable it by:
- *
- * - patching the TLB miss handlers to branch to the
- * one dedicates to it
- *
- * - setting the global book3e_htw_enabled
- *
- * - Set MAS4:INDD and default page size
- */
-
/* XXX This code only checks for TLB 0 capabilities and doesn't
* check what page size combos are supported by the HW. It
* also doesn't handle the case where a separate array holds
* the IND entries from the array loaded by the PT.
*/
if (boot_cpu) {
- unsigned int tlb0cfg = mfspr(SPRN_TLB0CFG);
+ /* Look for supported page sizes */
+ setup_page_sizes();
- /* Check if HW loader is supported */
- if ((tlb0cfg & TLBnCFG_IND) &&
- (tlb0cfg & TLBnCFG_PT)) {
- patch_branch(ibase + (0x1c0 / 4),
- (unsigned long)&exc_data_tlb_miss_htw_book3e, 0);
- patch_branch(ibase + (0x1e0 / 4),
- (unsigned long)&exc_instruction_tlb_miss_htw_book3e, 0);
- book3e_htw_enabled = 1;
- }
- pr_info("MMU: Book3E Page Tables %s\n",
- book3e_htw_enabled ? "Enabled" : "Disabled");
+ /* Look for HW tablewalk support */
+ setup_mmu_htw();
}
/* Set MAS4 based on page table setting */
diff --git a/arch/powerpc/oprofile/Makefile b/arch/powerpc/oprofile/Makefile
index 73e1c2ca055..e219ca43962 100644
--- a/arch/powerpc/oprofile/Makefile
+++ b/arch/powerpc/oprofile/Makefile
@@ -16,6 +16,6 @@ oprofile-y := $(DRIVER_OBJS) common.o backtrace.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_PPC_BOOK3S_64) += op_model_rs64.o op_model_power4.o op_model_pa6t.o
oprofile-$(CONFIG_FSL_EMB_PERFMON) += op_model_fsl_emb.o
oprofile-$(CONFIG_6xx) += op_model_7450.o
diff --git a/arch/powerpc/oprofile/common.c b/arch/powerpc/oprofile/common.c
index 21f16edf6c8..d65e68f3cb2 100644
--- a/arch/powerpc/oprofile/common.c
+++ b/arch/powerpc/oprofile/common.c
@@ -199,7 +199,7 @@ int __init oprofile_arch_init(struct oprofile_operations *ops)
return -ENODEV;
switch (cur_cpu_spec->oprofile_type) {
-#ifdef CONFIG_PPC64
+#ifdef CONFIG_PPC_BOOK3S_64
#ifdef CONFIG_OPROFILE_CELL
case PPC_OPROFILE_CELL:
if (firmware_has_feature(FW_FEATURE_LPAR))
diff --git a/arch/powerpc/platforms/40x/Kconfig b/arch/powerpc/platforms/40x/Kconfig
index ec64264f7a5..b72176434eb 100644
--- a/arch/powerpc/platforms/40x/Kconfig
+++ b/arch/powerpc/platforms/40x/Kconfig
@@ -71,22 +71,6 @@ config MAKALU
help
This option enables support for the AMCC PPC405EX board.
-#config REDWOOD_5
-# bool "Redwood-5"
-# depends on 40x
-# default n
-# select STB03xxx
-# help
-# This option enables support for the IBM STB04 evaluation board.
-
-#config REDWOOD_6
-# bool "Redwood-6"
-# depends on 40x
-# default n
-# select STB03xxx
-# help
-# This option enables support for the IBM STBx25xx evaluation board.
-
#config SYCAMORE
# bool "Sycamore"
# depends on 40x
diff --git a/arch/powerpc/platforms/512x/Kconfig b/arch/powerpc/platforms/512x/Kconfig
index 4dac9b0525a..27b0651221d 100644
--- a/arch/powerpc/platforms/512x/Kconfig
+++ b/arch/powerpc/platforms/512x/Kconfig
@@ -1,32 +1,34 @@
config PPC_MPC512x
- bool
+ bool "512x-based boards"
+ depends on 6xx
select FSL_SOC
select IPIC
select PPC_CLOCK
select PPC_PCI_CHOICE
select FSL_PCI if PCI
-config PPC_MPC5121
- bool
- select PPC_MPC512x
-
config MPC5121_ADS
bool "Freescale MPC5121E ADS"
- depends on 6xx
+ depends on PPC_MPC512x
select DEFAULT_UIMAGE
- select PPC_MPC5121
select MPC5121_ADS_CPLD
help
This option enables support for the MPC5121E ADS board.
config MPC5121_GENERIC
bool "Generic support for simple MPC5121 based boards"
- depends on 6xx
+ depends on PPC_MPC512x
select DEFAULT_UIMAGE
- select PPC_MPC5121
help
This option enables support for simple MPC5121 based boards
which do not need custom platform specific setup.
Compatible boards include: Protonic LVT base boards (ZANMCU
and VICVT2).
+
+config PDM360NG
+ bool "ifm PDM360NG board"
+ depends on PPC_MPC512x
+ select DEFAULT_UIMAGE
+ help
+ This option enables support for the PDM360NG board.
diff --git a/arch/powerpc/platforms/512x/Makefile b/arch/powerpc/platforms/512x/Makefile
index 90be2f5717e..4efc1c4b6fb 100644
--- a/arch/powerpc/platforms/512x/Makefile
+++ b/arch/powerpc/platforms/512x/Makefile
@@ -4,3 +4,4 @@
obj-y += clock.o mpc512x_shared.o
obj-$(CONFIG_MPC5121_ADS) += mpc5121_ads.o mpc5121_ads_cpld.o
obj-$(CONFIG_MPC5121_GENERIC) += mpc5121_generic.o
+obj-$(CONFIG_PDM360NG) += pdm360ng.o
diff --git a/arch/powerpc/platforms/512x/clock.c b/arch/powerpc/platforms/512x/clock.c
index 4c42246b86a..5b243bd3eb3 100644
--- a/arch/powerpc/platforms/512x/clock.c
+++ b/arch/powerpc/platforms/512x/clock.c
@@ -292,6 +292,15 @@ static void diu_clk_calc(struct clk *clk)
clk->rate = rate;
}
+static void viu_clk_calc(struct clk *clk)
+{
+ unsigned long rate;
+
+ rate = sys_clk.rate;
+ rate /= 2;
+ clk->rate = rate;
+}
+
static void half_clk_calc(struct clk *clk)
{
clk->rate = clk->parent->rate / 2;
@@ -412,6 +421,14 @@ static struct clk diu_clk = {
.calc = diu_clk_calc,
};
+static struct clk viu_clk = {
+ .name = "viu_clk",
+ .flags = CLK_HAS_CTRL,
+ .reg = 1,
+ .bit = 18,
+ .calc = viu_clk_calc,
+};
+
static struct clk axe_clk = {
.name = "axe_clk",
.flags = CLK_HAS_CTRL,
@@ -535,6 +552,7 @@ struct clk *rate_clks[] = {
&ref_clk,
&sys_clk,
&diu_clk,
+ &viu_clk,
&csb_clk,
&e300_clk,
&ips_clk,
@@ -660,7 +678,7 @@ static void psc_clks_init(void)
{
struct device_node *np;
const u32 *cell_index;
- struct of_device *ofdev;
+ struct platform_device *ofdev;
for_each_compatible_node(np, NULL, "fsl,mpc5121-psc") {
cell_index = of_get_property(np, "cell-index", NULL);
diff --git a/arch/powerpc/platforms/512x/mpc5121_ads.c b/arch/powerpc/platforms/512x/mpc5121_ads.c
index ee6ae129c25..dcef6ade48e 100644
--- a/arch/powerpc/platforms/512x/mpc5121_ads.c
+++ b/arch/powerpc/platforms/512x/mpc5121_ads.c
@@ -42,6 +42,7 @@ static void __init mpc5121_ads_setup_arch(void)
for_each_compatible_node(np, "pci", "fsl,mpc5121-pci")
mpc83xx_add_bridge(np);
#endif
+ mpc512x_setup_diu();
}
static void __init mpc5121_ads_init_IRQ(void)
@@ -65,6 +66,7 @@ define_machine(mpc5121_ads) {
.probe = mpc5121_ads_probe,
.setup_arch = mpc5121_ads_setup_arch,
.init = mpc512x_init,
+ .init_early = mpc512x_init_diu,
.init_IRQ = mpc5121_ads_init_IRQ,
.get_irq = ipic_get_irq,
.calibrate_decr = generic_calibrate_decr,
diff --git a/arch/powerpc/platforms/512x/mpc5121_generic.c b/arch/powerpc/platforms/512x/mpc5121_generic.c
index a6c0e3a2615..e487eb06ec6 100644
--- a/arch/powerpc/platforms/512x/mpc5121_generic.c
+++ b/arch/powerpc/platforms/512x/mpc5121_generic.c
@@ -52,6 +52,8 @@ define_machine(mpc5121_generic) {
.name = "MPC5121 generic",
.probe = mpc5121_generic_probe,
.init = mpc512x_init,
+ .init_early = mpc512x_init_diu,
+ .setup_arch = mpc512x_setup_diu,
.init_IRQ = mpc512x_init_IRQ,
.get_irq = ipic_get_irq,
.calibrate_decr = generic_calibrate_decr,
diff --git a/arch/powerpc/platforms/512x/mpc512x.h b/arch/powerpc/platforms/512x/mpc512x.h
index b2daca0d148..1ab6d11d0b1 100644
--- a/arch/powerpc/platforms/512x/mpc512x.h
+++ b/arch/powerpc/platforms/512x/mpc512x.h
@@ -16,4 +16,6 @@ extern void __init mpc512x_init(void);
extern int __init mpc5121_clk_init(void);
void __init mpc512x_declare_of_platform_devices(void);
extern void mpc512x_restart(char *cmd);
+extern void mpc512x_init_diu(void);
+extern void mpc512x_setup_diu(void);
#endif /* __MPC512X_H__ */
diff --git a/arch/powerpc/platforms/512x/mpc512x_shared.c b/arch/powerpc/platforms/512x/mpc512x_shared.c
index 707e572b7c4..e41ebbdb3e1 100644
--- a/arch/powerpc/platforms/512x/mpc512x_shared.c
+++ b/arch/powerpc/platforms/512x/mpc512x_shared.c
@@ -16,7 +16,11 @@
#include <linux/io.h>
#include <linux/irq.h>
#include <linux/of_platform.h>
+#include <linux/fsl-diu-fb.h>
+#include <linux/bootmem.h>
+#include <sysdev/fsl_soc.h>
+#include <asm/cacheflush.h>
#include <asm/machdep.h>
#include <asm/ipic.h>
#include <asm/prom.h>
@@ -54,6 +58,286 @@ void mpc512x_restart(char *cmd)
;
}
+struct fsl_diu_shared_fb {
+ u8 gamma[0x300]; /* 32-bit aligned! */
+ struct diu_ad ad0; /* 32-bit aligned! */
+ phys_addr_t fb_phys;
+ size_t fb_len;
+ bool in_use;
+};
+
+unsigned int mpc512x_get_pixel_format(unsigned int bits_per_pixel,
+ int monitor_port)
+{
+ switch (bits_per_pixel) {
+ case 32:
+ return 0x88883316;
+ case 24:
+ return 0x88082219;
+ case 16:
+ return 0x65053118;
+ }
+ return 0x00000400;
+}
+
+void mpc512x_set_gamma_table(int monitor_port, char *gamma_table_base)
+{
+}
+
+void mpc512x_set_monitor_port(int monitor_port)
+{
+}
+
+#define DIU_DIV_MASK 0x000000ff
+void mpc512x_set_pixel_clock(unsigned int pixclock)
+{
+ unsigned long bestval, bestfreq, speed, busfreq;
+ unsigned long minpixclock, maxpixclock, pixval;
+ struct mpc512x_ccm __iomem *ccm;
+ struct device_node *np;
+ u32 temp;
+ long err;
+ int i;
+
+ np = of_find_compatible_node(NULL, NULL, "fsl,mpc5121-clock");
+ if (!np) {
+ pr_err("Can't find clock control module.\n");
+ return;
+ }
+
+ ccm = of_iomap(np, 0);
+ of_node_put(np);
+ if (!ccm) {
+ pr_err("Can't map clock control module reg.\n");
+ return;
+ }
+
+ np = of_find_node_by_type(NULL, "cpu");
+ if (np) {
+ const unsigned int *prop =
+ of_get_property(np, "bus-frequency", NULL);
+
+ of_node_put(np);
+ if (prop) {
+ busfreq = *prop;
+ } else {
+ pr_err("Can't get bus-frequency property\n");
+ return;
+ }
+ } else {
+ pr_err("Can't find 'cpu' node.\n");
+ return;
+ }
+
+ /* Pixel Clock configuration */
+ pr_debug("DIU: Bus Frequency = %lu\n", busfreq);
+ speed = busfreq * 4; /* DIU_DIV ratio is 4 * CSB_CLK / DIU_CLK */
+
+ /* Calculate the pixel clock with the smallest error */
+ /* calculate the following in steps to avoid overflow */
+ pr_debug("DIU pixclock in ps - %d\n", pixclock);
+ temp = (1000000000 / pixclock) * 1000;
+ pixclock = temp;
+ pr_debug("DIU pixclock freq - %u\n", pixclock);
+
+ temp = temp / 20; /* pixclock * 0.05 */
+ pr_debug("deviation = %d\n", temp);
+ minpixclock = pixclock - temp;
+ maxpixclock = pixclock + temp;
+ pr_debug("DIU minpixclock - %lu\n", minpixclock);
+ pr_debug("DIU maxpixclock - %lu\n", maxpixclock);
+ pixval = speed/pixclock;
+ pr_debug("DIU pixval = %lu\n", pixval);
+
+ err = LONG_MAX;
+ bestval = pixval;
+ pr_debug("DIU bestval = %lu\n", bestval);
+
+ bestfreq = 0;
+ for (i = -1; i <= 1; i++) {
+ temp = speed / (pixval+i);
+ pr_debug("DIU test pixval i=%d, pixval=%lu, temp freq. = %u\n",
+ i, pixval, temp);
+ if ((temp < minpixclock) || (temp > maxpixclock))
+ pr_debug("DIU exceeds monitor range (%lu to %lu)\n",
+ minpixclock, maxpixclock);
+ else if (abs(temp - pixclock) < err) {
+ pr_debug("Entered the else if block %d\n", i);
+ err = abs(temp - pixclock);
+ bestval = pixval + i;
+ bestfreq = temp;
+ }
+ }
+
+ pr_debug("DIU chose = %lx\n", bestval);
+ pr_debug("DIU error = %ld\n NomPixClk ", err);
+ pr_debug("DIU: Best Freq = %lx\n", bestfreq);
+ /* Modify DIU_DIV in CCM SCFR1 */
+ temp = in_be32(&ccm->scfr1);
+ pr_debug("DIU: Current value of SCFR1: 0x%08x\n", temp);
+ temp &= ~DIU_DIV_MASK;
+ temp |= (bestval & DIU_DIV_MASK);
+ out_be32(&ccm->scfr1, temp);
+ pr_debug("DIU: Modified value of SCFR1: 0x%08x\n", temp);
+ iounmap(ccm);
+}
+
+ssize_t mpc512x_show_monitor_port(int monitor_port, char *buf)
+{
+ return sprintf(buf, "0 - 5121 LCD\n");
+}
+
+int mpc512x_set_sysfs_monitor_port(int val)
+{
+ return 0;
+}
+
+static struct fsl_diu_shared_fb __attribute__ ((__aligned__(8))) diu_shared_fb;
+
+#if defined(CONFIG_FB_FSL_DIU) || \
+ defined(CONFIG_FB_FSL_DIU_MODULE)
+static inline void mpc512x_free_bootmem(struct page *page)
+{
+ __ClearPageReserved(page);
+ BUG_ON(PageTail(page));
+ BUG_ON(atomic_read(&page->_count) > 1);
+ atomic_set(&page->_count, 1);
+ __free_page(page);
+ totalram_pages++;
+}
+
+void mpc512x_release_bootmem(void)
+{
+ unsigned long addr = diu_shared_fb.fb_phys & PAGE_MASK;
+ unsigned long size = diu_shared_fb.fb_len;
+ unsigned long start, end;
+
+ if (diu_shared_fb.in_use) {
+ start = PFN_UP(addr);
+ end = PFN_DOWN(addr + size);
+
+ for (; start < end; start++)
+ mpc512x_free_bootmem(pfn_to_page(start));
+
+ diu_shared_fb.in_use = false;
+ }
+ diu_ops.release_bootmem = NULL;
+}
+#endif
+
+/*
+ * Check if DIU was pre-initialized. If so, perform steps
+ * needed to continue displaying through the whole boot process.
+ * Move area descriptor and gamma table elsewhere, they are
+ * destroyed by bootmem allocator otherwise. The frame buffer
+ * address range will be reserved in setup_arch() after bootmem
+ * allocator is up.
+ */
+void __init mpc512x_init_diu(void)
+{
+ struct device_node *np;
+ struct diu __iomem *diu_reg;
+ phys_addr_t desc;
+ void __iomem *vaddr;
+ unsigned long mode, pix_fmt, res, bpp;
+ unsigned long dst;
+
+ np = of_find_compatible_node(NULL, NULL, "fsl,mpc5121-diu");
+ if (!np) {
+ pr_err("No DIU node\n");
+ return;
+ }
+
+ diu_reg = of_iomap(np, 0);
+ of_node_put(np);
+ if (!diu_reg) {
+ pr_err("Can't map DIU\n");
+ return;
+ }
+
+ mode = in_be32(&diu_reg->diu_mode);
+ if (mode != MFB_MODE1) {
+ pr_info("%s: DIU OFF\n", __func__);
+ goto out;
+ }
+
+ desc = in_be32(&diu_reg->desc[0]);
+ vaddr = ioremap(desc, sizeof(struct diu_ad));
+ if (!vaddr) {
+ pr_err("Can't map DIU area desc.\n");
+ goto out;
+ }
+ memcpy(&diu_shared_fb.ad0, vaddr, sizeof(struct diu_ad));
+ /* flush fb area descriptor */
+ dst = (unsigned long)&diu_shared_fb.ad0;
+ flush_dcache_range(dst, dst + sizeof(struct diu_ad) - 1);
+
+ res = in_be32(&diu_reg->disp_size);
+ pix_fmt = in_le32(vaddr);
+ bpp = ((pix_fmt >> 16) & 0x3) + 1;
+ diu_shared_fb.fb_phys = in_le32(vaddr + 4);
+ diu_shared_fb.fb_len = ((res & 0xfff0000) >> 16) * (res & 0xfff) * bpp;
+ diu_shared_fb.in_use = true;
+ iounmap(vaddr);
+
+ desc = in_be32(&diu_reg->gamma);
+ vaddr = ioremap(desc, sizeof(diu_shared_fb.gamma));
+ if (!vaddr) {
+ pr_err("Can't map DIU area desc.\n");
+ diu_shared_fb.in_use = false;
+ goto out;
+ }
+ memcpy(&diu_shared_fb.gamma, vaddr, sizeof(diu_shared_fb.gamma));
+ /* flush gamma table */
+ dst = (unsigned long)&diu_shared_fb.gamma;
+ flush_dcache_range(dst, dst + sizeof(diu_shared_fb.gamma) - 1);
+
+ iounmap(vaddr);
+ out_be32(&diu_reg->gamma, virt_to_phys(&diu_shared_fb.gamma));
+ out_be32(&diu_reg->desc[1], 0);
+ out_be32(&diu_reg->desc[2], 0);
+ out_be32(&diu_reg->desc[0], virt_to_phys(&diu_shared_fb.ad0));
+
+out:
+ iounmap(diu_reg);
+}
+
+void __init mpc512x_setup_diu(void)
+{
+ int ret;
+
+ /*
+ * We do not allocate and configure new area for bitmap buffer
+ * because it would requere copying bitmap data (splash image)
+ * and so negatively affect boot time. Instead we reserve the
+ * already configured frame buffer area so that it won't be
+ * destroyed. The starting address of the area to reserve and
+ * also it's length is passed to reserve_bootmem(). It will be
+ * freed later on first open of fbdev, when splash image is not
+ * needed any more.
+ */
+ if (diu_shared_fb.in_use) {
+ ret = reserve_bootmem(diu_shared_fb.fb_phys,
+ diu_shared_fb.fb_len,
+ BOOTMEM_EXCLUSIVE);
+ if (ret) {
+ pr_err("%s: reserve bootmem failed\n", __func__);
+ diu_shared_fb.in_use = false;
+ }
+ }
+
+#if defined(CONFIG_FB_FSL_DIU) || \
+ defined(CONFIG_FB_FSL_DIU_MODULE)
+ diu_ops.get_pixel_format = mpc512x_get_pixel_format;
+ diu_ops.set_gamma_table = mpc512x_set_gamma_table;
+ diu_ops.set_monitor_port = mpc512x_set_monitor_port;
+ diu_ops.set_pixel_clock = mpc512x_set_pixel_clock;
+ diu_ops.show_monitor_port = mpc512x_show_monitor_port;
+ diu_ops.set_sysfs_monitor_port = mpc512x_set_sysfs_monitor_port;
+ diu_ops.release_bootmem = mpc512x_release_bootmem;
+#endif
+}
+
void __init mpc512x_init_IRQ(void)
{
struct device_node *np;
diff --git a/arch/powerpc/platforms/512x/pdm360ng.c b/arch/powerpc/platforms/512x/pdm360ng.c
new file mode 100644
index 00000000000..0575e858291
--- /dev/null
+++ b/arch/powerpc/platforms/512x/pdm360ng.c
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2010 DENX Software Engineering
+ *
+ * Anatolij Gustschin, <agust@denx.de>
+ *
+ * PDM360NG board setup
+ *
+ * This is free software; you can redistribute it and/or modify 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/io.h>
+#include <linux/of_platform.h>
+
+#include <asm/machdep.h>
+#include <asm/ipic.h>
+
+#include "mpc512x.h"
+
+#if defined(CONFIG_TOUCHSCREEN_ADS7846) || \
+ defined(CONFIG_TOUCHSCREEN_ADS7846_MODULE)
+#include <linux/interrupt.h>
+#include <linux/spi/ads7846.h>
+#include <linux/spi/spi.h>
+#include <linux/notifier.h>
+
+static void *pdm360ng_gpio_base;
+
+static int pdm360ng_get_pendown_state(void)
+{
+ u32 reg;
+
+ reg = in_be32(pdm360ng_gpio_base + 0xc);
+ if (reg & 0x40)
+ setbits32(pdm360ng_gpio_base + 0xc, 0x40);
+
+ reg = in_be32(pdm360ng_gpio_base + 0x8);
+
+ /* return 1 if pen is down */
+ return (reg & 0x40) == 0;
+}
+
+static struct ads7846_platform_data pdm360ng_ads7846_pdata = {
+ .model = 7845,
+ .get_pendown_state = pdm360ng_get_pendown_state,
+ .irq_flags = IRQF_TRIGGER_LOW,
+};
+
+static int __init pdm360ng_penirq_init(void)
+{
+ struct device_node *np;
+
+ np = of_find_compatible_node(NULL, NULL, "fsl,mpc5121-gpio");
+ if (!np) {
+ pr_err("%s: Can't find 'mpc5121-gpio' node\n", __func__);
+ return -ENODEV;
+ }
+
+ pdm360ng_gpio_base = of_iomap(np, 0);
+ of_node_put(np);
+ if (!pdm360ng_gpio_base) {
+ pr_err("%s: Can't map gpio regs.\n", __func__);
+ return -ENODEV;
+ }
+ out_be32(pdm360ng_gpio_base + 0xc, 0xffffffff);
+ setbits32(pdm360ng_gpio_base + 0x18, 0x2000);
+ setbits32(pdm360ng_gpio_base + 0x10, 0x40);
+
+ return 0;
+}
+
+static int pdm360ng_touchscreen_notifier_call(struct notifier_block *nb,
+ unsigned long event, void *__dev)
+{
+ struct device *dev = __dev;
+
+ if ((event == BUS_NOTIFY_ADD_DEVICE) &&
+ of_device_is_compatible(dev->of_node, "ti,ads7846")) {
+ dev->platform_data = &pdm360ng_ads7846_pdata;
+ return NOTIFY_OK;
+ }
+ return NOTIFY_DONE;
+}
+
+static struct notifier_block pdm360ng_touchscreen_nb = {
+ .notifier_call = pdm360ng_touchscreen_notifier_call,
+};
+
+static void __init pdm360ng_touchscreen_init(void)
+{
+ if (pdm360ng_penirq_init())
+ return;
+
+ bus_register_notifier(&spi_bus_type, &pdm360ng_touchscreen_nb);
+}
+#else
+static inline void __init pdm360ng_touchscreen_init(void)
+{
+}
+#endif /* CONFIG_TOUCHSCREEN_ADS7846 */
+
+void __init pdm360ng_init(void)
+{
+ mpc512x_init();
+ pdm360ng_touchscreen_init();
+}
+
+static int __init pdm360ng_probe(void)
+{
+ unsigned long root = of_get_flat_dt_root();
+
+ return of_flat_dt_is_compatible(root, "ifm,pdm360ng");
+}
+
+define_machine(pdm360ng) {
+ .name = "PDM360NG",
+ .probe = pdm360ng_probe,
+ .setup_arch = mpc512x_setup_diu,
+ .init = pdm360ng_init,
+ .init_early = mpc512x_init_diu,
+ .init_IRQ = mpc512x_init_IRQ,
+ .get_irq = ipic_get_irq,
+ .calibrate_decr = generic_calibrate_decr,
+ .restart = mpc512x_restart,
+};
diff --git a/arch/powerpc/platforms/52xx/lite5200.c b/arch/powerpc/platforms/52xx/lite5200.c
index 6d584f4e3c9..de55bc0584b 100644
--- a/arch/powerpc/platforms/52xx/lite5200.c
+++ b/arch/powerpc/platforms/52xx/lite5200.c
@@ -18,6 +18,7 @@
#include <linux/init.h>
#include <linux/pci.h>
#include <linux/of.h>
+#include <linux/of_address.h>
#include <linux/root_dev.h>
#include <linux/initrd.h>
#include <asm/time.h>
diff --git a/arch/powerpc/platforms/52xx/lite5200_pm.c b/arch/powerpc/platforms/52xx/lite5200_pm.c
index b5c753db125..80234e5921f 100644
--- a/arch/powerpc/platforms/52xx/lite5200_pm.c
+++ b/arch/powerpc/platforms/52xx/lite5200_pm.c
@@ -216,9 +216,6 @@ static int lite5200_pm_enter(suspend_state_t state)
lite5200_restore_regs();
- /* restart jiffies */
- wakeup_decrementer();
-
iounmap(mbar);
return 0;
}
diff --git a/arch/powerpc/platforms/52xx/mpc52xx_gpio.c b/arch/powerpc/platforms/52xx/mpc52xx_gpio.c
index ca5305a5bd6..0dad9a935eb 100644
--- a/arch/powerpc/platforms/52xx/mpc52xx_gpio.c
+++ b/arch/powerpc/platforms/52xx/mpc52xx_gpio.c
@@ -147,26 +147,25 @@ mpc52xx_wkup_gpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val)
return 0;
}
-static int __devinit mpc52xx_wkup_gpiochip_probe(struct of_device *ofdev,
+static int __devinit mpc52xx_wkup_gpiochip_probe(struct platform_device *ofdev,
const struct of_device_id *match)
{
struct mpc52xx_gpiochip *chip;
struct mpc52xx_gpio_wkup __iomem *regs;
- struct of_gpio_chip *ofchip;
+ struct gpio_chip *gc;
int ret;
chip = kzalloc(sizeof(*chip), GFP_KERNEL);
if (!chip)
return -ENOMEM;
- ofchip = &chip->mmchip.of_gc;
+ gc = &chip->mmchip.gc;
- ofchip->gpio_cells = 2;
- ofchip->gc.ngpio = 8;
- ofchip->gc.direction_input = mpc52xx_wkup_gpio_dir_in;
- ofchip->gc.direction_output = mpc52xx_wkup_gpio_dir_out;
- ofchip->gc.get = mpc52xx_wkup_gpio_get;
- ofchip->gc.set = mpc52xx_wkup_gpio_set;
+ gc->ngpio = 8;
+ gc->direction_input = mpc52xx_wkup_gpio_dir_in;
+ gc->direction_output = mpc52xx_wkup_gpio_dir_out;
+ gc->get = mpc52xx_wkup_gpio_get;
+ gc->set = mpc52xx_wkup_gpio_set;
ret = of_mm_gpiochip_add(ofdev->dev.of_node, &chip->mmchip);
if (ret)
@@ -180,7 +179,7 @@ static int __devinit mpc52xx_wkup_gpiochip_probe(struct of_device *ofdev,
return 0;
}
-static int mpc52xx_gpiochip_remove(struct of_device *ofdev)
+static int mpc52xx_gpiochip_remove(struct platform_device *ofdev)
{
return -EBUSY;
}
@@ -311,11 +310,11 @@ mpc52xx_simple_gpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val)
return 0;
}
-static int __devinit mpc52xx_simple_gpiochip_probe(struct of_device *ofdev,
+static int __devinit mpc52xx_simple_gpiochip_probe(struct platform_device *ofdev,
const struct of_device_id *match)
{
struct mpc52xx_gpiochip *chip;
- struct of_gpio_chip *ofchip;
+ struct gpio_chip *gc;
struct mpc52xx_gpio __iomem *regs;
int ret;
@@ -323,14 +322,13 @@ static int __devinit mpc52xx_simple_gpiochip_probe(struct of_device *ofdev,
if (!chip)
return -ENOMEM;
- ofchip = &chip->mmchip.of_gc;
+ gc = &chip->mmchip.gc;
- ofchip->gpio_cells = 2;
- ofchip->gc.ngpio = 32;
- ofchip->gc.direction_input = mpc52xx_simple_gpio_dir_in;
- ofchip->gc.direction_output = mpc52xx_simple_gpio_dir_out;
- ofchip->gc.get = mpc52xx_simple_gpio_get;
- ofchip->gc.set = mpc52xx_simple_gpio_set;
+ gc->ngpio = 32;
+ gc->direction_input = mpc52xx_simple_gpio_dir_in;
+ gc->direction_output = mpc52xx_simple_gpio_dir_out;
+ gc->get = mpc52xx_simple_gpio_get;
+ gc->set = mpc52xx_simple_gpio_set;
ret = of_mm_gpiochip_add(ofdev->dev.of_node, &chip->mmchip);
if (ret)
diff --git a/arch/powerpc/platforms/52xx/mpc52xx_gpt.c b/arch/powerpc/platforms/52xx/mpc52xx_gpt.c
index 46c93578cbf..fea833e18ad 100644
--- a/arch/powerpc/platforms/52xx/mpc52xx_gpt.c
+++ b/arch/powerpc/platforms/52xx/mpc52xx_gpt.c
@@ -78,7 +78,7 @@ MODULE_LICENSE("GPL");
* @dev: pointer to device structure
* @regs: virtual address of GPT registers
* @lock: spinlock to coordinate between different functions.
- * @of_gc: of_gpio_chip instance structure; used when GPIO is enabled
+ * @gc: gpio_chip instance structure; used when GPIO is enabled
* @irqhost: Pointer to irq_host instance; used when IRQ mode is supported
* @wdt_mode: only relevant for gpt0: bit 0 (MPC52xx_GPT_CAN_WDT) indicates
* if the gpt may be used as wdt, bit 1 (MPC52xx_GPT_IS_WDT) indicates
@@ -94,7 +94,7 @@ struct mpc52xx_gpt_priv {
u8 wdt_mode;
#if defined(CONFIG_GPIOLIB)
- struct of_gpio_chip of_gc;
+ struct gpio_chip gc;
#endif
};
@@ -280,7 +280,7 @@ mpc52xx_gpt_irq_setup(struct mpc52xx_gpt_priv *gpt, struct device_node *node)
#if defined(CONFIG_GPIOLIB)
static inline struct mpc52xx_gpt_priv *gc_to_mpc52xx_gpt(struct gpio_chip *gc)
{
- return container_of(to_of_gpio_chip(gc), struct mpc52xx_gpt_priv,of_gc);
+ return container_of(gc, struct mpc52xx_gpt_priv, gc);
}
static int mpc52xx_gpt_gpio_get(struct gpio_chip *gc, unsigned int gpio)
@@ -336,28 +336,25 @@ mpc52xx_gpt_gpio_setup(struct mpc52xx_gpt_priv *gpt, struct device_node *node)
if (!of_find_property(node, "gpio-controller", NULL))
return;
- gpt->of_gc.gc.label = kstrdup(node->full_name, GFP_KERNEL);
- if (!gpt->of_gc.gc.label) {
+ gpt->gc.label = kstrdup(node->full_name, GFP_KERNEL);
+ if (!gpt->gc.label) {
dev_err(gpt->dev, "out of memory\n");
return;
}
- gpt->of_gc.gpio_cells = 2;
- gpt->of_gc.gc.ngpio = 1;
- gpt->of_gc.gc.direction_input = mpc52xx_gpt_gpio_dir_in;
- gpt->of_gc.gc.direction_output = mpc52xx_gpt_gpio_dir_out;
- gpt->of_gc.gc.get = mpc52xx_gpt_gpio_get;
- gpt->of_gc.gc.set = mpc52xx_gpt_gpio_set;
- gpt->of_gc.gc.base = -1;
- gpt->of_gc.xlate = of_gpio_simple_xlate;
- node->data = &gpt->of_gc;
- of_node_get(node);
+ gpt->gc.ngpio = 1;
+ gpt->gc.direction_input = mpc52xx_gpt_gpio_dir_in;
+ gpt->gc.direction_output = mpc52xx_gpt_gpio_dir_out;
+ gpt->gc.get = mpc52xx_gpt_gpio_get;
+ gpt->gc.set = mpc52xx_gpt_gpio_set;
+ gpt->gc.base = -1;
+ gpt->gc.of_node = node;
/* Setup external pin in GPIO mode */
clrsetbits_be32(&gpt->regs->mode, MPC52xx_GPT_MODE_MS_MASK,
MPC52xx_GPT_MODE_MS_GPIO);
- rc = gpiochip_add(&gpt->of_gc.gc);
+ rc = gpiochip_add(&gpt->gc);
if (rc)
dev_err(gpt->dev, "gpiochip_add() failed; rc=%i\n", rc);
@@ -723,7 +720,7 @@ static inline int mpc52xx_gpt_wdt_setup(struct mpc52xx_gpt_priv *gpt,
/* ---------------------------------------------------------------------
* of_platform bus binding code
*/
-static int __devinit mpc52xx_gpt_probe(struct of_device *ofdev,
+static int __devinit mpc52xx_gpt_probe(struct platform_device *ofdev,
const struct of_device_id *match)
{
struct mpc52xx_gpt_priv *gpt;
@@ -769,7 +766,7 @@ static int __devinit mpc52xx_gpt_probe(struct of_device *ofdev,
return 0;
}
-static int mpc52xx_gpt_remove(struct of_device *ofdev)
+static int mpc52xx_gpt_remove(struct platform_device *ofdev)
{
return -EBUSY;
}
diff --git a/arch/powerpc/platforms/52xx/mpc52xx_lpbfifo.c b/arch/powerpc/platforms/52xx/mpc52xx_lpbfifo.c
index e86aec64450..f4ac213c89c 100644
--- a/arch/powerpc/platforms/52xx/mpc52xx_lpbfifo.c
+++ b/arch/powerpc/platforms/52xx/mpc52xx_lpbfifo.c
@@ -436,8 +436,8 @@ void mpc52xx_lpbfifo_abort(struct mpc52xx_lpbfifo_request *req)
}
EXPORT_SYMBOL(mpc52xx_lpbfifo_abort);
-static int __devinit
-mpc52xx_lpbfifo_probe(struct of_device *op, const struct of_device_id *match)
+static int __devinit mpc52xx_lpbfifo_probe(struct platform_device *op,
+ const struct of_device_id *match)
{
struct resource res;
int rc = -ENOMEM;
@@ -507,7 +507,7 @@ mpc52xx_lpbfifo_probe(struct of_device *op, const struct of_device_id *match)
}
-static int __devexit mpc52xx_lpbfifo_remove(struct of_device *op)
+static int __devexit mpc52xx_lpbfifo_remove(struct platform_device *op)
{
if (lpbfifo.dev != &op->dev)
return 0;
diff --git a/arch/powerpc/platforms/52xx/mpc52xx_pm.c b/arch/powerpc/platforms/52xx/mpc52xx_pm.c
index 76722532bd9..568cef63627 100644
--- a/arch/powerpc/platforms/52xx/mpc52xx_pm.c
+++ b/arch/powerpc/platforms/52xx/mpc52xx_pm.c
@@ -171,9 +171,6 @@ int mpc52xx_pm_enter(suspend_state_t state)
/* restore SRAM */
memcpy(sram, saved_sram, sram_size);
- /* restart jiffies */
- wakeup_decrementer();
-
/* reenable interrupts in PIC */
out_be32(&intr->main_mask, intr_main_mask);
diff --git a/arch/powerpc/platforms/82xx/ep8248e.c b/arch/powerpc/platforms/82xx/ep8248e.c
index 9f2e52b36f9..1565e0446dc 100644
--- a/arch/powerpc/platforms/82xx/ep8248e.c
+++ b/arch/powerpc/platforms/82xx/ep8248e.c
@@ -111,7 +111,7 @@ static struct mdiobb_ctrl ep8248e_mdio_ctrl = {
.ops = &ep8248e_mdio_ops,
};
-static int __devinit ep8248e_mdio_probe(struct of_device *ofdev,
+static int __devinit ep8248e_mdio_probe(struct platform_device *ofdev,
const struct of_device_id *match)
{
struct mii_bus *bus;
@@ -154,7 +154,7 @@ err_free_bus:
return ret;
}
-static int ep8248e_mdio_remove(struct of_device *ofdev)
+static int ep8248e_mdio_remove(struct platform_device *ofdev)
{
BUG();
return 0;
diff --git a/arch/powerpc/platforms/83xx/Kconfig b/arch/powerpc/platforms/83xx/Kconfig
index f49a2548c5f..021763a32c2 100644
--- a/arch/powerpc/platforms/83xx/Kconfig
+++ b/arch/powerpc/platforms/83xx/Kconfig
@@ -9,6 +9,14 @@ menuconfig PPC_83xx
if PPC_83xx
+config MPC830x_RDB
+ bool "Freescale MPC830x RDB"
+ select DEFAULT_UIMAGE
+ select PPC_MPC831x
+ select FSL_GTM
+ help
+ This option enables support for the MPC8308 RDB board.
+
config MPC831x_RDB
bool "Freescale MPC831x RDB"
select DEFAULT_UIMAGE
diff --git a/arch/powerpc/platforms/83xx/Makefile b/arch/powerpc/platforms/83xx/Makefile
index e139c36572e..6e8bbbbcfdf 100644
--- a/arch/powerpc/platforms/83xx/Makefile
+++ b/arch/powerpc/platforms/83xx/Makefile
@@ -4,6 +4,7 @@
obj-y := misc.o usb.o
obj-$(CONFIG_SUSPEND) += suspend.o suspend-asm.o
obj-$(CONFIG_MCU_MPC8349EMITX) += mcu_mpc8349emitx.o
+obj-$(CONFIG_MPC830x_RDB) += mpc830x_rdb.o
obj-$(CONFIG_MPC831x_RDB) += mpc831x_rdb.o
obj-$(CONFIG_MPC832x_RDB) += mpc832x_rdb.o
obj-$(CONFIG_MPC834x_MDS) += mpc834x_mds.o
diff --git a/arch/powerpc/platforms/83xx/mcu_mpc8349emitx.c b/arch/powerpc/platforms/83xx/mcu_mpc8349emitx.c
index d119a7c1c17..70798ac911e 100644
--- a/arch/powerpc/platforms/83xx/mcu_mpc8349emitx.c
+++ b/arch/powerpc/platforms/83xx/mcu_mpc8349emitx.c
@@ -35,9 +35,8 @@
struct mcu {
struct mutex lock;
- struct device_node *np;
struct i2c_client *client;
- struct of_gpio_chip of_gc;
+ struct gpio_chip gc;
u8 reg_ctrl;
};
@@ -56,8 +55,7 @@ static void mcu_power_off(void)
static void mcu_gpio_set(struct gpio_chip *gc, unsigned int gpio, int val)
{
- struct of_gpio_chip *of_gc = to_of_gpio_chip(gc);
- struct mcu *mcu = container_of(of_gc, struct mcu, of_gc);
+ struct mcu *mcu = container_of(gc, struct mcu, gc);
u8 bit = 1 << (4 + gpio);
mutex_lock(&mcu->lock);
@@ -79,9 +77,7 @@ static int mcu_gpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val)
static int mcu_gpiochip_add(struct mcu *mcu)
{
struct device_node *np;
- struct of_gpio_chip *of_gc = &mcu->of_gc;
- struct gpio_chip *gc = &of_gc->gc;
- int ret;
+ struct gpio_chip *gc = &mcu->gc;
np = of_find_compatible_node(NULL, NULL, "fsl,mcu-mpc8349emitx");
if (!np)
@@ -94,32 +90,14 @@ static int mcu_gpiochip_add(struct mcu *mcu)
gc->base = -1;
gc->set = mcu_gpio_set;
gc->direction_output = mcu_gpio_dir_out;
- of_gc->gpio_cells = 2;
- of_gc->xlate = of_gpio_simple_xlate;
+ gc->of_node = np;
- np->data = of_gc;
- mcu->np = np;
-
- /*
- * We don't want to lose the node, its ->data and ->full_name...
- * So, if succeeded, we don't put the node here.
- */
- ret = gpiochip_add(gc);
- if (ret)
- of_node_put(np);
- return ret;
+ return gpiochip_add(gc);
}
static int mcu_gpiochip_remove(struct mcu *mcu)
{
- int ret;
-
- ret = gpiochip_remove(&mcu->of_gc.gc);
- if (ret)
- return ret;
- of_node_put(mcu->np);
-
- return 0;
+ return gpiochip_remove(&mcu->gc);
}
static int __devinit mcu_probe(struct i2c_client *client,
@@ -182,10 +160,16 @@ static const struct i2c_device_id mcu_ids[] = {
};
MODULE_DEVICE_TABLE(i2c, mcu_ids);
+static struct of_device_id mcu_of_match_table[] __devinitdata = {
+ { .compatible = "fsl,mcu-mpc8349emitx", },
+ { },
+};
+
static struct i2c_driver mcu_driver = {
.driver = {
.name = "mcu-mpc8349emitx",
.owner = THIS_MODULE,
+ .of_match_table = mcu_of_match_table,
},
.probe = mcu_probe,
.remove = __devexit_p(mcu_remove),
diff --git a/arch/powerpc/platforms/83xx/mpc830x_rdb.c b/arch/powerpc/platforms/83xx/mpc830x_rdb.c
new file mode 100644
index 00000000000..ac102ee9abe
--- /dev/null
+++ b/arch/powerpc/platforms/83xx/mpc830x_rdb.c
@@ -0,0 +1,94 @@
+/*
+ * arch/powerpc/platforms/83xx/mpc830x_rdb.c
+ *
+ * Description: MPC830x RDB board specific routines.
+ * This file is based on mpc831x_rdb.c
+ *
+ * Copyright (C) Freescale Semiconductor, Inc. 2009. All rights reserved.
+ * Copyright (C) 2010. Ilya Yanok, Emcraft Systems, yanok@emcraft.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/pci.h>
+#include <linux/of_platform.h>
+#include <asm/time.h>
+#include <asm/ipic.h>
+#include <asm/udbg.h>
+#include <sysdev/fsl_pci.h>
+#include <sysdev/fsl_soc.h>
+#include "mpc83xx.h"
+
+/*
+ * Setup the architecture
+ */
+static void __init mpc830x_rdb_setup_arch(void)
+{
+#ifdef CONFIG_PCI
+ struct device_node *np;
+#endif
+
+ if (ppc_md.progress)
+ ppc_md.progress("mpc830x_rdb_setup_arch()", 0);
+
+#ifdef CONFIG_PCI
+ for_each_compatible_node(np, "pci", "fsl,mpc8308-pcie")
+ mpc83xx_add_bridge(np);
+#endif
+ mpc831x_usb_cfg();
+}
+
+static void __init mpc830x_rdb_init_IRQ(void)
+{
+ struct device_node *np;
+
+ np = of_find_node_by_type(NULL, "ipic");
+ if (!np)
+ return;
+
+ ipic_init(np, 0);
+
+ /* Initialize the default interrupt mapping priorities,
+ * in case the boot rom changed something on us.
+ */
+ ipic_set_default_priority();
+}
+
+/*
+ * Called very early, MMU is off, device-tree isn't unflattened
+ */
+static int __init mpc830x_rdb_probe(void)
+{
+ unsigned long root = of_get_flat_dt_root();
+
+ return of_flat_dt_is_compatible(root, "MPC8308RDB") ||
+ of_flat_dt_is_compatible(root, "fsl,mpc8308rdb");
+}
+
+static struct of_device_id __initdata of_bus_ids[] = {
+ { .compatible = "simple-bus" },
+ { .compatible = "gianfar" },
+ {},
+};
+
+static int __init declare_of_platform_devices(void)
+{
+ of_platform_bus_probe(NULL, of_bus_ids, NULL);
+ return 0;
+}
+machine_device_initcall(mpc830x_rdb, declare_of_platform_devices);
+
+define_machine(mpc830x_rdb) {
+ .name = "MPC830x RDB",
+ .probe = mpc830x_rdb_probe,
+ .setup_arch = mpc830x_rdb_setup_arch,
+ .init_IRQ = mpc830x_rdb_init_IRQ,
+ .get_irq = ipic_get_irq,
+ .restart = mpc83xx_restart,
+ .time_init = mpc83xx_time_init,
+ .calibrate_decr = generic_calibrate_decr,
+ .progress = udbg_progress,
+};
diff --git a/arch/powerpc/platforms/83xx/suspend.c b/arch/powerpc/platforms/83xx/suspend.c
index ebe6c353720..75ae77f1af6 100644
--- a/arch/powerpc/platforms/83xx/suspend.c
+++ b/arch/powerpc/platforms/83xx/suspend.c
@@ -99,7 +99,7 @@ struct pmc_type {
int has_deep_sleep;
};
-static struct of_device *pmc_dev;
+static struct platform_device *pmc_dev;
static int has_deep_sleep, deep_sleeping;
static int pmc_irq;
static struct mpc83xx_pmc __iomem *pmc_regs;
@@ -318,7 +318,7 @@ static struct platform_suspend_ops mpc83xx_suspend_ops = {
.end = mpc83xx_suspend_end,
};
-static int pmc_probe(struct of_device *ofdev,
+static int pmc_probe(struct platform_device *ofdev,
const struct of_device_id *match)
{
struct device_node *np = ofdev->dev.of_node;
@@ -396,7 +396,7 @@ out:
return ret;
}
-static int pmc_remove(struct of_device *ofdev)
+static int pmc_remove(struct platform_device *ofdev)
{
return -EPERM;
};
diff --git a/arch/powerpc/platforms/85xx/Kconfig b/arch/powerpc/platforms/85xx/Kconfig
index 3a2ade2e443..bea1f5905ad 100644
--- a/arch/powerpc/platforms/85xx/Kconfig
+++ b/arch/powerpc/platforms/85xx/Kconfig
@@ -65,6 +65,14 @@ config MPC85xx_RDB
help
This option enables support for the MPC85xx RDB (P2020 RDB) board
+config P1022_DS
+ bool "Freescale P1022 DS"
+ select DEFAULT_UIMAGE
+ select CONFIG_PHYS_64BIT # The DTS has 36-bit addresses
+ select SWIOTLB
+ help
+ This option enables support for the Freescale P1022DS reference board.
+
config SOCRATES
bool "Socrates"
select DEFAULT_UIMAGE
diff --git a/arch/powerpc/platforms/85xx/Makefile b/arch/powerpc/platforms/85xx/Makefile
index 387c128f2c8..a2ec3f8f4d0 100644
--- a/arch/powerpc/platforms/85xx/Makefile
+++ b/arch/powerpc/platforms/85xx/Makefile
@@ -10,6 +10,7 @@ obj-$(CONFIG_MPC8536_DS) += mpc8536_ds.o
obj-$(CONFIG_MPC85xx_DS) += mpc85xx_ds.o
obj-$(CONFIG_MPC85xx_MDS) += mpc85xx_mds.o
obj-$(CONFIG_MPC85xx_RDB) += mpc85xx_rdb.o
+obj-$(CONFIG_P1022_DS) += p1022_ds.o
obj-$(CONFIG_P4080_DS) += p4080_ds.o corenet_ds.o
obj-$(CONFIG_STX_GP3) += stx_gp3.o
obj-$(CONFIG_TQM85xx) += tqm85xx.o
diff --git a/arch/powerpc/platforms/85xx/mpc85xx_mds.c b/arch/powerpc/platforms/85xx/mpc85xx_mds.c
index 494513682d7..da64be19d09 100644
--- a/arch/powerpc/platforms/85xx/mpc85xx_mds.c
+++ b/arch/powerpc/platforms/85xx/mpc85xx_mds.c
@@ -158,51 +158,108 @@ static int mpc8568_mds_phy_fixups(struct phy_device *phydev)
extern void __init mpc85xx_smp_init(void);
#endif
-static void __init mpc85xx_mds_setup_arch(void)
+#ifdef CONFIG_QUICC_ENGINE
+static struct of_device_id mpc85xx_qe_ids[] __initdata = {
+ { .type = "qe", },
+ { .compatible = "fsl,qe", },
+ { },
+};
+
+static void __init mpc85xx_publish_qe_devices(void)
{
struct device_node *np;
- static u8 __iomem *bcsr_regs = NULL;
-#ifdef CONFIG_PCI
- struct pci_controller *hose;
-#endif
- dma_addr_t max = 0xffffffff;
- if (ppc_md.progress)
- ppc_md.progress("mpc85xx_mds_setup_arch()", 0);
+ np = of_find_compatible_node(NULL, NULL, "fsl,qe");
+ if (!of_device_is_available(np)) {
+ of_node_put(np);
+ return;
+ }
+
+ of_platform_bus_probe(NULL, mpc85xx_qe_ids, NULL);
+}
+
+static void __init mpc85xx_mds_reset_ucc_phys(void)
+{
+ struct device_node *np;
+ static u8 __iomem *bcsr_regs;
/* Map BCSR area */
np = of_find_node_by_name(NULL, "bcsr");
- if (np != NULL) {
- struct resource res;
+ if (!np)
+ return;
- of_address_to_resource(np, 0, &res);
- bcsr_regs = ioremap(res.start, res.end - res.start +1);
- of_node_put(np);
- }
+ bcsr_regs = of_iomap(np, 0);
+ of_node_put(np);
+ if (!bcsr_regs)
+ return;
-#ifdef CONFIG_PCI
- for_each_node_by_type(np, "pci") {
- if (of_device_is_compatible(np, "fsl,mpc8540-pci") ||
- of_device_is_compatible(np, "fsl,mpc8548-pcie")) {
- struct resource rsrc;
- of_address_to_resource(np, 0, &rsrc);
- if ((rsrc.start & 0xfffff) == 0x8000)
- fsl_add_bridge(np, 1);
- else
- fsl_add_bridge(np, 0);
+ if (machine_is(mpc8568_mds)) {
+#define BCSR_UCC1_GETH_EN (0x1 << 7)
+#define BCSR_UCC2_GETH_EN (0x1 << 7)
+#define BCSR_UCC1_MODE_MSK (0x3 << 4)
+#define BCSR_UCC2_MODE_MSK (0x3 << 0)
- hose = pci_find_hose_for_OF_device(np);
- max = min(max, hose->dma_window_base_cur +
- hose->dma_window_size);
+ /* Turn off UCC1 & UCC2 */
+ clrbits8(&bcsr_regs[8], BCSR_UCC1_GETH_EN);
+ clrbits8(&bcsr_regs[9], BCSR_UCC2_GETH_EN);
+
+ /* Mode is RGMII, all bits clear */
+ clrbits8(&bcsr_regs[11], BCSR_UCC1_MODE_MSK |
+ BCSR_UCC2_MODE_MSK);
+
+ /* Turn UCC1 & UCC2 on */
+ setbits8(&bcsr_regs[8], BCSR_UCC1_GETH_EN);
+ setbits8(&bcsr_regs[9], BCSR_UCC2_GETH_EN);
+ } else if (machine_is(mpc8569_mds)) {
+#define BCSR7_UCC12_GETHnRST (0x1 << 2)
+#define BCSR8_UEM_MARVELL_RST (0x1 << 1)
+#define BCSR_UCC_RGMII (0x1 << 6)
+#define BCSR_UCC_RTBI (0x1 << 5)
+ /*
+ * U-Boot mangles interrupt polarity for Marvell PHYs,
+ * so reset built-in and UEM Marvell PHYs, this puts
+ * the PHYs into their normal state.
+ */
+ clrbits8(&bcsr_regs[7], BCSR7_UCC12_GETHnRST);
+ setbits8(&bcsr_regs[8], BCSR8_UEM_MARVELL_RST);
+
+ setbits8(&bcsr_regs[7], BCSR7_UCC12_GETHnRST);
+ clrbits8(&bcsr_regs[8], BCSR8_UEM_MARVELL_RST);
+
+ for (np = NULL; (np = of_find_compatible_node(np,
+ "network",
+ "ucc_geth")) != NULL;) {
+ const unsigned int *prop;
+ int ucc_num;
+
+ prop = of_get_property(np, "cell-index", NULL);
+ if (prop == NULL)
+ continue;
+
+ ucc_num = *prop - 1;
+
+ prop = of_get_property(np, "phy-connection-type", NULL);
+ if (prop == NULL)
+ continue;
+
+ if (strcmp("rtbi", (const char *)prop) == 0)
+ clrsetbits_8(&bcsr_regs[7 + ucc_num],
+ BCSR_UCC_RGMII, BCSR_UCC_RTBI);
}
+ } else if (machine_is(p1021_mds)) {
+#define BCSR11_ENET_MICRST (0x1 << 5)
+ /* Reset Micrel PHY */
+ clrbits8(&bcsr_regs[11], BCSR11_ENET_MICRST);
+ setbits8(&bcsr_regs[11], BCSR11_ENET_MICRST);
}
-#endif
-#ifdef CONFIG_SMP
- mpc85xx_smp_init();
-#endif
+ iounmap(bcsr_regs);
+}
+
+static void __init mpc85xx_mds_qe_init(void)
+{
+ struct device_node *np;
-#ifdef CONFIG_QUICC_ENGINE
np = of_find_compatible_node(NULL, NULL, "fsl,qe");
if (!np) {
np = of_find_node_by_name(NULL, "qe");
@@ -210,6 +267,11 @@ static void __init mpc85xx_mds_setup_arch(void)
return;
}
+ if (!of_device_is_available(np)) {
+ of_node_put(np);
+ return;
+ }
+
qe_reset();
of_node_put(np);
@@ -224,70 +286,7 @@ static void __init mpc85xx_mds_setup_arch(void)
par_io_of_config(ucc);
}
- if (bcsr_regs) {
- if (machine_is(mpc8568_mds)) {
-#define BCSR_UCC1_GETH_EN (0x1 << 7)
-#define BCSR_UCC2_GETH_EN (0x1 << 7)
-#define BCSR_UCC1_MODE_MSK (0x3 << 4)
-#define BCSR_UCC2_MODE_MSK (0x3 << 0)
-
- /* Turn off UCC1 & UCC2 */
- clrbits8(&bcsr_regs[8], BCSR_UCC1_GETH_EN);
- clrbits8(&bcsr_regs[9], BCSR_UCC2_GETH_EN);
-
- /* Mode is RGMII, all bits clear */
- clrbits8(&bcsr_regs[11], BCSR_UCC1_MODE_MSK |
- BCSR_UCC2_MODE_MSK);
-
- /* Turn UCC1 & UCC2 on */
- setbits8(&bcsr_regs[8], BCSR_UCC1_GETH_EN);
- setbits8(&bcsr_regs[9], BCSR_UCC2_GETH_EN);
- } else if (machine_is(mpc8569_mds)) {
-#define BCSR7_UCC12_GETHnRST (0x1 << 2)
-#define BCSR8_UEM_MARVELL_RST (0x1 << 1)
-#define BCSR_UCC_RGMII (0x1 << 6)
-#define BCSR_UCC_RTBI (0x1 << 5)
- /*
- * U-Boot mangles interrupt polarity for Marvell PHYs,
- * so reset built-in and UEM Marvell PHYs, this puts
- * the PHYs into their normal state.
- */
- clrbits8(&bcsr_regs[7], BCSR7_UCC12_GETHnRST);
- setbits8(&bcsr_regs[8], BCSR8_UEM_MARVELL_RST);
-
- setbits8(&bcsr_regs[7], BCSR7_UCC12_GETHnRST);
- clrbits8(&bcsr_regs[8], BCSR8_UEM_MARVELL_RST);
-
- for (np = NULL; (np = of_find_compatible_node(np,
- "network",
- "ucc_geth")) != NULL;) {
- const unsigned int *prop;
- int ucc_num;
-
- prop = of_get_property(np, "cell-index", NULL);
- if (prop == NULL)
- continue;
-
- ucc_num = *prop - 1;
-
- prop = of_get_property(np, "phy-connection-type", NULL);
- if (prop == NULL)
- continue;
-
- if (strcmp("rtbi", (const char *)prop) == 0)
- clrsetbits_8(&bcsr_regs[7 + ucc_num],
- BCSR_UCC_RGMII, BCSR_UCC_RTBI);
- }
-
- } else if (machine_is(p1021_mds)) {
-#define BCSR11_ENET_MICRST (0x1 << 5)
- /* Reset Micrel PHY */
- clrbits8(&bcsr_regs[11], BCSR11_ENET_MICRST);
- setbits8(&bcsr_regs[11], BCSR11_ENET_MICRST);
- }
-
- iounmap(bcsr_regs);
- }
+ mpc85xx_mds_reset_ucc_phys();
if (machine_is(p1021_mds)) {
#define MPC85xx_PMUXCR_OFFSET 0x60
@@ -322,8 +321,72 @@ static void __init mpc85xx_mds_setup_arch(void)
}
}
+}
+
+static void __init mpc85xx_mds_qeic_init(void)
+{
+ struct device_node *np;
+
+ np = of_find_compatible_node(NULL, NULL, "fsl,qe");
+ if (!of_device_is_available(np)) {
+ of_node_put(np);
+ return;
+ }
+
+ np = of_find_compatible_node(NULL, NULL, "fsl,qe-ic");
+ if (!np) {
+ np = of_find_node_by_type(NULL, "qeic");
+ if (!np)
+ return;
+ }
+
+ if (machine_is(p1021_mds))
+ qe_ic_init(np, 0, qe_ic_cascade_low_mpic,
+ qe_ic_cascade_high_mpic);
+ else
+ qe_ic_init(np, 0, qe_ic_cascade_muxed_mpic, NULL);
+ of_node_put(np);
+}
+#else
+static void __init mpc85xx_publish_qe_devices(void) { }
+static void __init mpc85xx_mds_qe_init(void) { }
+static void __init mpc85xx_mds_qeic_init(void) { }
#endif /* CONFIG_QUICC_ENGINE */
+static void __init mpc85xx_mds_setup_arch(void)
+{
+#ifdef CONFIG_PCI
+ struct pci_controller *hose;
+#endif
+ dma_addr_t max = 0xffffffff;
+
+ if (ppc_md.progress)
+ ppc_md.progress("mpc85xx_mds_setup_arch()", 0);
+
+#ifdef CONFIG_PCI
+ for_each_node_by_type(np, "pci") {
+ if (of_device_is_compatible(np, "fsl,mpc8540-pci") ||
+ of_device_is_compatible(np, "fsl,mpc8548-pcie")) {
+ struct resource rsrc;
+ of_address_to_resource(np, 0, &rsrc);
+ if ((rsrc.start & 0xfffff) == 0x8000)
+ fsl_add_bridge(np, 1);
+ else
+ fsl_add_bridge(np, 0);
+
+ hose = pci_find_hose_for_OF_device(np);
+ max = min(max, hose->dma_window_base_cur +
+ hose->dma_window_size);
+ }
+ }
+#endif
+
+#ifdef CONFIG_SMP
+ mpc85xx_smp_init();
+#endif
+
+ mpc85xx_mds_qe_init();
+
#ifdef CONFIG_SWIOTLB
if (memblock_end_of_DRAM() > max) {
ppc_swiotlb_enable = 1;
@@ -369,8 +432,6 @@ static struct of_device_id mpc85xx_ids[] = {
{ .type = "soc", },
{ .compatible = "soc", },
{ .compatible = "simple-bus", },
- { .type = "qe", },
- { .compatible = "fsl,qe", },
{ .compatible = "gianfar", },
{ .compatible = "fsl,rapidio-delta", },
{ .compatible = "fsl,mpc8548-guts", },
@@ -382,8 +443,6 @@ static struct of_device_id p1021_ids[] = {
{ .type = "soc", },
{ .compatible = "soc", },
{ .compatible = "simple-bus", },
- { .type = "qe", },
- { .compatible = "fsl,qe", },
{ .compatible = "gianfar", },
{},
};
@@ -395,16 +454,16 @@ static int __init mpc85xx_publish_devices(void)
if (machine_is(mpc8569_mds))
simple_gpiochip_init("fsl,mpc8569mds-bcsr-gpio");
- /* Publish the QE devices */
of_platform_bus_probe(NULL, mpc85xx_ids, NULL);
+ mpc85xx_publish_qe_devices();
return 0;
}
static int __init p1021_publish_devices(void)
{
- /* Publish the QE devices */
of_platform_bus_probe(NULL, p1021_ids, NULL);
+ mpc85xx_publish_qe_devices();
return 0;
}
@@ -441,21 +500,7 @@ static void __init mpc85xx_mds_pic_init(void)
of_node_put(np);
mpic_init(mpic);
-
-#ifdef CONFIG_QUICC_ENGINE
- np = of_find_compatible_node(NULL, NULL, "fsl,qe-ic");
- if (!np) {
- np = of_find_node_by_type(NULL, "qeic");
- if (!np)
- return;
- }
- if (machine_is(p1021_mds))
- qe_ic_init(np, 0, qe_ic_cascade_low_mpic,
- qe_ic_cascade_high_mpic);
- else
- qe_ic_init(np, 0, qe_ic_cascade_muxed_mpic, NULL);
- of_node_put(np);
-#endif /* CONFIG_QUICC_ENGINE */
+ mpc85xx_mds_qeic_init();
}
static int __init mpc85xx_mds_probe(void)
diff --git a/arch/powerpc/platforms/85xx/p1022_ds.c b/arch/powerpc/platforms/85xx/p1022_ds.c
new file mode 100644
index 00000000000..e1467c93745
--- /dev/null
+++ b/arch/powerpc/platforms/85xx/p1022_ds.c
@@ -0,0 +1,148 @@
+/*
+ * P1022DS board specific routines
+ *
+ * Authors: Travis Wheatley <travis.wheatley@freescale.com>
+ * Dave Liu <daveliu@freescale.com>
+ * Timur Tabi <timur@freescale.com>
+ *
+ * Copyright 2010 Freescale Semiconductor, Inc.
+ *
+ * This file is taken from the Freescale P1022DS BSP, with modifications:
+ * 1) No DIU support (pending rewrite of DIU code)
+ * 2) No AMP support
+ * 3) No PCI endpoint support
+ *
+ * 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/pci.h>
+#include <linux/of_platform.h>
+#include <linux/lmb.h>
+
+#include <asm/mpic.h>
+#include <asm/swiotlb.h>
+
+#include <sysdev/fsl_soc.h>
+#include <sysdev/fsl_pci.h>
+
+void __init p1022_ds_pic_init(void)
+{
+ struct mpic *mpic;
+ struct resource r;
+ struct device_node *np;
+
+ np = of_find_node_by_type(NULL, "open-pic");
+ if (!np) {
+ pr_err("Could not find open-pic node\n");
+ return;
+ }
+
+ if (of_address_to_resource(np, 0, &r)) {
+ pr_err("Failed to map mpic register space\n");
+ of_node_put(np);
+ return;
+ }
+
+ mpic = mpic_alloc(np, r.start,
+ MPIC_PRIMARY | MPIC_WANTS_RESET |
+ MPIC_BIG_ENDIAN | MPIC_BROKEN_FRR_NIRQS |
+ MPIC_SINGLE_DEST_CPU,
+ 0, 256, " OpenPIC ");
+
+ BUG_ON(mpic == NULL);
+ of_node_put(np);
+
+ mpic_init(mpic);
+}
+
+#ifdef CONFIG_SMP
+void __init mpc85xx_smp_init(void);
+#endif
+
+/*
+ * Setup the architecture
+ */
+static void __init p1022_ds_setup_arch(void)
+{
+#ifdef CONFIG_PCI
+ struct device_node *np;
+#endif
+ dma_addr_t max = 0xffffffff;
+
+ if (ppc_md.progress)
+ ppc_md.progress("p1022_ds_setup_arch()", 0);
+
+#ifdef CONFIG_PCI
+ for_each_compatible_node(np, "pci", "fsl,p1022-pcie") {
+ struct resource rsrc;
+ struct pci_controller *hose;
+
+ of_address_to_resource(np, 0, &rsrc);
+
+ if ((rsrc.start & 0xfffff) == 0x8000)
+ fsl_add_bridge(np, 1);
+ else
+ fsl_add_bridge(np, 0);
+
+ hose = pci_find_hose_for_OF_device(np);
+ max = min(max, hose->dma_window_base_cur +
+ hose->dma_window_size);
+ }
+#endif
+
+#ifdef CONFIG_SMP
+ mpc85xx_smp_init();
+#endif
+
+#ifdef CONFIG_SWIOTLB
+ if (lmb_end_of_DRAM() > max) {
+ ppc_swiotlb_enable = 1;
+ set_pci_dma_ops(&swiotlb_dma_ops);
+ ppc_md.pci_dma_dev_setup = pci_dma_dev_setup_swiotlb;
+ }
+#endif
+
+ pr_info("Freescale P1022 DS reference board\n");
+}
+
+static struct of_device_id __initdata p1022_ds_ids[] = {
+ { .type = "soc", },
+ { .compatible = "soc", },
+ { .compatible = "simple-bus", },
+ { .compatible = "gianfar", },
+ {},
+};
+
+static int __init p1022_ds_publish_devices(void)
+{
+ return of_platform_bus_probe(NULL, p1022_ds_ids, NULL);
+}
+machine_device_initcall(p1022_ds, p1022_ds_publish_devices);
+
+machine_arch_initcall(p1022_ds, swiotlb_setup_bus_notifier);
+
+/*
+ * Called very early, device-tree isn't unflattened
+ */
+static int __init p1022_ds_probe(void)
+{
+ unsigned long root = of_get_flat_dt_root();
+
+ return of_flat_dt_is_compatible(root, "fsl,p1022ds");
+}
+
+define_machine(p1022_ds) {
+ .name = "P1022 DS",
+ .probe = p1022_ds_probe,
+ .setup_arch = p1022_ds_setup_arch,
+ .init_IRQ = p1022_ds_pic_init,
+#ifdef CONFIG_PCI
+ .pcibios_fixup_bus = fsl_pcibios_fixup_bus,
+#endif
+ .get_irq = mpic_get_irq,
+ .restart = fsl_rstcr_restart,
+ .calibrate_decr = generic_calibrate_decr,
+ .progress = udbg_progress,
+};
diff --git a/arch/powerpc/platforms/85xx/smp.c b/arch/powerpc/platforms/85xx/smp.c
index a15f582300d..a6b106557be 100644
--- a/arch/powerpc/platforms/85xx/smp.c
+++ b/arch/powerpc/platforms/85xx/smp.c
@@ -15,6 +15,7 @@
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/of.h>
+#include <linux/kexec.h>
#include <asm/machdep.h>
#include <asm/pgtable.h>
@@ -24,6 +25,7 @@
#include <asm/dbell.h>
#include <sysdev/fsl_soc.h>
+#include <sysdev/mpic.h>
extern void __early_start(void);
@@ -99,12 +101,70 @@ static void __init
smp_85xx_setup_cpu(int cpu_nr)
{
mpic_setup_this_cpu();
+ if (cpu_has_feature(CPU_FTR_DBELL))
+ doorbell_setup_this_cpu();
}
struct smp_ops_t smp_85xx_ops = {
.kick_cpu = smp_85xx_kick_cpu,
+#ifdef CONFIG_KEXEC
+ .give_timebase = smp_generic_give_timebase,
+ .take_timebase = smp_generic_take_timebase,
+#endif
};
+#ifdef CONFIG_KEXEC
+static int kexec_down_cpus = 0;
+
+void mpc85xx_smp_kexec_cpu_down(int crash_shutdown, int secondary)
+{
+ mpic_teardown_this_cpu(1);
+
+ /* When crashing, this gets called on all CPU's we only
+ * take down the non-boot cpus */
+ if (smp_processor_id() != boot_cpuid)
+ {
+ local_irq_disable();
+ kexec_down_cpus++;
+
+ while (1);
+ }
+}
+
+static void mpc85xx_smp_kexec_down(void *arg)
+{
+ if (ppc_md.kexec_cpu_down)
+ ppc_md.kexec_cpu_down(0,1);
+}
+
+static void mpc85xx_smp_machine_kexec(struct kimage *image)
+{
+ int timeout = 2000;
+ int i;
+
+ set_cpus_allowed(current, cpumask_of_cpu(boot_cpuid));
+
+ smp_call_function(mpc85xx_smp_kexec_down, NULL, 0);
+
+ while ( (kexec_down_cpus != (num_online_cpus() - 1)) &&
+ ( timeout > 0 ) )
+ {
+ timeout--;
+ }
+
+ if ( !timeout )
+ printk(KERN_ERR "Unable to bring down secondary cpu(s)");
+
+ for (i = 0; i < num_present_cpus(); i++)
+ {
+ if ( i == smp_processor_id() ) continue;
+ mpic_reset_core(i);
+ }
+
+ default_machine_kexec(image);
+}
+#endif /* CONFIG_KEXEC */
+
void __init mpc85xx_smp_init(void)
{
struct device_node *np;
@@ -117,9 +177,14 @@ void __init mpc85xx_smp_init(void)
}
if (cpu_has_feature(CPU_FTR_DBELL))
- smp_85xx_ops.message_pass = smp_dbell_message_pass;
+ smp_85xx_ops.message_pass = doorbell_message_pass;
BUG_ON(!smp_85xx_ops.message_pass);
smp_ops = &smp_85xx_ops;
+
+#ifdef CONFIG_KEXEC
+ ppc_md.kexec_cpu_down = mpc85xx_smp_kexec_cpu_down;
+ ppc_md.machine_kexec = mpc85xx_smp_machine_kexec;
+#endif
}
diff --git a/arch/powerpc/platforms/85xx/tqm85xx.c b/arch/powerpc/platforms/85xx/tqm85xx.c
index 5b0ab9966e9..8f29bbce536 100644
--- a/arch/powerpc/platforms/85xx/tqm85xx.c
+++ b/arch/powerpc/platforms/85xx/tqm85xx.c
@@ -151,6 +151,27 @@ static void tqm85xx_show_cpuinfo(struct seq_file *m)
seq_printf(m, "PLL setting\t: 0x%x\n", ((phid1 >> 24) & 0x3f));
}
+static void __init tqm85xx_ti1520_fixup(struct pci_dev *pdev)
+{
+ unsigned int val;
+
+ /* Do not do the fixup on other platforms! */
+ if (!machine_is(tqm85xx))
+ return;
+
+ dev_info(&pdev->dev, "Using TI 1520 fixup on TQM85xx\n");
+
+ /*
+ * Enable P2CCLK bit in system control register
+ * to enable CLOCK output to power chip
+ */
+ pci_read_config_dword(pdev, 0x80, &val);
+ pci_write_config_dword(pdev, 0x80, val | (1 << 27));
+
+}
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1520,
+ tqm85xx_ti1520_fixup);
+
static struct of_device_id __initdata of_bus_ids[] = {
{ .compatible = "simple-bus", },
{ .compatible = "gianfar", },
diff --git a/arch/powerpc/platforms/86xx/gef_gpio.c b/arch/powerpc/platforms/86xx/gef_gpio.c
index b8cb08dbd89..4ff7b1e7bba 100644
--- a/arch/powerpc/platforms/86xx/gef_gpio.c
+++ b/arch/powerpc/platforms/86xx/gef_gpio.c
@@ -118,12 +118,12 @@ static int __init gef_gpio_init(void)
}
/* Setup pointers to chip functions */
- gef_gpio_chip->of_gc.gpio_cells = 2;
- gef_gpio_chip->of_gc.gc.ngpio = 19;
- gef_gpio_chip->of_gc.gc.direction_input = gef_gpio_dir_in;
- gef_gpio_chip->of_gc.gc.direction_output = gef_gpio_dir_out;
- gef_gpio_chip->of_gc.gc.get = gef_gpio_get;
- gef_gpio_chip->of_gc.gc.set = gef_gpio_set;
+ gef_gpio_chip->gc.of_gpio_n_cells = 2;
+ gef_gpio_chip->gc.ngpio = 19;
+ gef_gpio_chip->gc.direction_input = gef_gpio_dir_in;
+ gef_gpio_chip->gc.direction_output = gef_gpio_dir_out;
+ gef_gpio_chip->gc.get = gef_gpio_get;
+ gef_gpio_chip->gc.set = gef_gpio_set;
/* This function adds a memory mapped GPIO chip */
retval = of_mm_gpiochip_add(np, gef_gpio_chip);
@@ -146,12 +146,12 @@ static int __init gef_gpio_init(void)
}
/* Setup pointers to chip functions */
- gef_gpio_chip->of_gc.gpio_cells = 2;
- gef_gpio_chip->of_gc.gc.ngpio = 6;
- gef_gpio_chip->of_gc.gc.direction_input = gef_gpio_dir_in;
- gef_gpio_chip->of_gc.gc.direction_output = gef_gpio_dir_out;
- gef_gpio_chip->of_gc.gc.get = gef_gpio_get;
- gef_gpio_chip->of_gc.gc.set = gef_gpio_set;
+ gef_gpio_chip->gc.of_gpio_n_cells = 2;
+ gef_gpio_chip->gc.ngpio = 6;
+ gef_gpio_chip->gc.direction_input = gef_gpio_dir_in;
+ gef_gpio_chip->gc.direction_output = gef_gpio_dir_out;
+ gef_gpio_chip->gc.get = gef_gpio_get;
+ gef_gpio_chip->gc.set = gef_gpio_set;
/* This function adds a memory mapped GPIO chip */
retval = of_mm_gpiochip_add(np, gef_gpio_chip);
diff --git a/arch/powerpc/platforms/8xx/Kconfig b/arch/powerpc/platforms/8xx/Kconfig
index 48a920a98e7..dd35ce081cf 100644
--- a/arch/powerpc/platforms/8xx/Kconfig
+++ b/arch/powerpc/platforms/8xx/Kconfig
@@ -55,6 +55,12 @@ config PPC_MGSUVD
help
This enables support for the Keymile MGSUVD board.
+config TQM8XX
+ bool "TQM8XX"
+ select CPM1
+ help
+ support for the mpc8xx based boards from TQM.
+
endchoice
menu "Freescale Ethernet driver platform-specific options"
diff --git a/arch/powerpc/platforms/8xx/Makefile b/arch/powerpc/platforms/8xx/Makefile
index bdbfd749601..a491fe6b94f 100644
--- a/arch/powerpc/platforms/8xx/Makefile
+++ b/arch/powerpc/platforms/8xx/Makefile
@@ -7,3 +7,4 @@ obj-$(CONFIG_MPC86XADS) += mpc86xads_setup.o
obj-$(CONFIG_PPC_EP88XC) += ep88xc.o
obj-$(CONFIG_PPC_ADDER875) += adder875.o
obj-$(CONFIG_PPC_MGSUVD) += mgsuvd.o
+obj-$(CONFIG_TQM8XX) += tqm8xx_setup.o
diff --git a/arch/powerpc/platforms/8xx/tqm8xx_setup.c b/arch/powerpc/platforms/8xx/tqm8xx_setup.c
new file mode 100644
index 00000000000..b71c650fbb1
--- /dev/null
+++ b/arch/powerpc/platforms/8xx/tqm8xx_setup.c
@@ -0,0 +1,156 @@
+/*
+ * Platform setup for the MPC8xx based boards from TQM.
+ *
+ * Heiko Schocher <hs@denx.de>
+ * Copyright 2010 DENX Software Engineering GmbH
+ *
+ * based on:
+ * Vitaly Bordug <vbordug@ru.mvista.com>
+ *
+ * Copyright 2005 MontaVista Software Inc.
+ *
+ * Heavily modified by Scott Wood <scottwood@freescale.com>
+ * Copyright 2007 Freescale Semiconductor, Inc.
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/param.h>
+#include <linux/string.h>
+#include <linux/ioport.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+
+#include <linux/fs_enet_pd.h>
+#include <linux/fs_uart_pd.h>
+#include <linux/fsl_devices.h>
+#include <linux/mii.h>
+#include <linux/of_platform.h>
+
+#include <asm/delay.h>
+#include <asm/io.h>
+#include <asm/machdep.h>
+#include <asm/page.h>
+#include <asm/processor.h>
+#include <asm/system.h>
+#include <asm/time.h>
+#include <asm/mpc8xx.h>
+#include <asm/8xx_immap.h>
+#include <asm/cpm1.h>
+#include <asm/fs_pd.h>
+#include <asm/udbg.h>
+
+#include "mpc8xx.h"
+
+struct cpm_pin {
+ int port, pin, flags;
+};
+
+static struct __initdata cpm_pin tqm8xx_pins[] = {
+ /* SMC1 */
+ {CPM_PORTB, 24, CPM_PIN_INPUT}, /* RX */
+ {CPM_PORTB, 25, CPM_PIN_INPUT | CPM_PIN_SECONDARY}, /* TX */
+
+ /* SCC1 */
+ {CPM_PORTA, 5, CPM_PIN_INPUT}, /* CLK1 */
+ {CPM_PORTA, 7, CPM_PIN_INPUT}, /* CLK2 */
+ {CPM_PORTA, 14, CPM_PIN_INPUT}, /* TX */
+ {CPM_PORTA, 15, CPM_PIN_INPUT}, /* RX */
+ {CPM_PORTC, 15, CPM_PIN_INPUT | CPM_PIN_SECONDARY}, /* TENA */
+ {CPM_PORTC, 10, CPM_PIN_INPUT | CPM_PIN_SECONDARY | CPM_PIN_GPIO},
+ {CPM_PORTC, 11, CPM_PIN_INPUT | CPM_PIN_SECONDARY | CPM_PIN_GPIO},
+};
+
+static struct __initdata cpm_pin tqm8xx_fec_pins[] = {
+ /* MII */
+ {CPM_PORTD, 3, CPM_PIN_OUTPUT},
+ {CPM_PORTD, 4, CPM_PIN_OUTPUT},
+ {CPM_PORTD, 5, CPM_PIN_OUTPUT},
+ {CPM_PORTD, 6, CPM_PIN_OUTPUT},
+ {CPM_PORTD, 7, CPM_PIN_OUTPUT},
+ {CPM_PORTD, 8, CPM_PIN_OUTPUT},
+ {CPM_PORTD, 9, CPM_PIN_OUTPUT},
+ {CPM_PORTD, 10, CPM_PIN_OUTPUT},
+ {CPM_PORTD, 11, CPM_PIN_OUTPUT},
+ {CPM_PORTD, 12, CPM_PIN_OUTPUT},
+ {CPM_PORTD, 13, CPM_PIN_OUTPUT},
+ {CPM_PORTD, 14, CPM_PIN_OUTPUT},
+ {CPM_PORTD, 15, CPM_PIN_OUTPUT},
+};
+
+static void __init init_pins(int n, struct cpm_pin *pin)
+{
+ int i;
+
+ for (i = 0; i < n; i++) {
+ cpm1_set_pin(pin->port, pin->pin, pin->flags);
+ pin++;
+ }
+}
+
+static void __init init_ioports(void)
+{
+ struct device_node *dnode;
+ struct property *prop;
+ int len;
+
+ init_pins(ARRAY_SIZE(tqm8xx_pins), &tqm8xx_pins[0]);
+
+ cpm1_clk_setup(CPM_CLK_SMC1, CPM_BRG1, CPM_CLK_RTX);
+
+ dnode = of_find_node_by_name(NULL, "aliases");
+ if (dnode == NULL)
+ return;
+ prop = of_find_property(dnode, "ethernet1", &len);
+ if (prop == NULL)
+ return;
+
+ /* init FEC pins */
+ init_pins(ARRAY_SIZE(tqm8xx_fec_pins), &tqm8xx_fec_pins[0]);
+}
+
+static void __init tqm8xx_setup_arch(void)
+{
+ cpm_reset();
+ init_ioports();
+}
+
+static int __init tqm8xx_probe(void)
+{
+ unsigned long node = of_get_flat_dt_root();
+
+ return of_flat_dt_is_compatible(node, "tqc,tqm8xx");
+}
+
+static struct of_device_id __initdata of_bus_ids[] = {
+ { .name = "soc", },
+ { .name = "cpm", },
+ { .name = "localbus", },
+ { .compatible = "simple-bus" },
+ {},
+};
+
+static int __init declare_of_platform_devices(void)
+{
+ of_platform_bus_probe(NULL, of_bus_ids, NULL);
+
+ return 0;
+}
+machine_device_initcall(tqm8xx, declare_of_platform_devices);
+
+define_machine(tqm8xx) {
+ .name = "TQM8xx",
+ .probe = tqm8xx_probe,
+ .setup_arch = tqm8xx_setup_arch,
+ .init_IRQ = mpc8xx_pics_init,
+ .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,
+ .progress = udbg_progress,
+};
diff --git a/arch/powerpc/platforms/amigaone/setup.c b/arch/powerpc/platforms/amigaone/setup.c
index fb4eb0df054..03aabc0e16a 100644
--- a/arch/powerpc/platforms/amigaone/setup.c
+++ b/arch/powerpc/platforms/amigaone/setup.c
@@ -13,12 +13,13 @@
*/
#include <linux/kernel.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
#include <linux/seq_file.h>
#include <generated/utsrelease.h>
#include <asm/machdep.h>
#include <asm/cputable.h>
-#include <asm/prom.h>
#include <asm/pci-bridge.h>
#include <asm/i8259.h>
#include <asm/time.h>
diff --git a/arch/powerpc/platforms/cell/axon_msi.c b/arch/powerpc/platforms/cell/axon_msi.c
index 6257e537861..97085530aa6 100644
--- a/arch/powerpc/platforms/cell/axon_msi.c
+++ b/arch/powerpc/platforms/cell/axon_msi.c
@@ -328,7 +328,7 @@ static struct irq_host_ops msic_host_ops = {
.map = msic_host_map,
};
-static int axon_msi_shutdown(struct of_device *device)
+static int axon_msi_shutdown(struct platform_device *device)
{
struct axon_msic *msic = dev_get_drvdata(&device->dev);
u32 tmp;
@@ -342,7 +342,7 @@ static int axon_msi_shutdown(struct of_device *device)
return 0;
}
-static int axon_msi_probe(struct of_device *device,
+static int axon_msi_probe(struct platform_device *device,
const struct of_device_id *device_id)
{
struct device_node *dn = device->dev.of_node;
diff --git a/arch/powerpc/platforms/cell/beat_iommu.c b/arch/powerpc/platforms/cell/beat_iommu.c
index 39d361c5c6d..beec405eb6f 100644
--- a/arch/powerpc/platforms/cell/beat_iommu.c
+++ b/arch/powerpc/platforms/cell/beat_iommu.c
@@ -108,7 +108,7 @@ static int __init celleb_init_iommu(void)
celleb_init_direct_mapping();
set_pci_dma_ops(&dma_direct_ops);
ppc_md.pci_dma_dev_setup = celleb_pci_dma_dev_setup;
- bus_register_notifier(&of_platform_bus_type, &celleb_of_bus_notifier);
+ bus_register_notifier(&platform_bus_type, &celleb_of_bus_notifier);
return 0;
}
diff --git a/arch/powerpc/platforms/cell/iommu.c b/arch/powerpc/platforms/cell/iommu.c
index 3712900471b..58b13ce3847 100644
--- a/arch/powerpc/platforms/cell/iommu.c
+++ b/arch/powerpc/platforms/cell/iommu.c
@@ -1204,7 +1204,7 @@ static int __init cell_iommu_init(void)
/* Register callbacks on OF platform device addition/removal
* to handle linking them to the right DMA operations
*/
- bus_register_notifier(&of_platform_bus_type, &cell_of_bus_notifier);
+ bus_register_notifier(&platform_bus_type, &cell_of_bus_notifier);
return 0;
}
diff --git a/arch/powerpc/platforms/cell/qpace_setup.c b/arch/powerpc/platforms/cell/qpace_setup.c
index c5ce02e84c8..1b574904275 100644
--- a/arch/powerpc/platforms/cell/qpace_setup.c
+++ b/arch/powerpc/platforms/cell/qpace_setup.c
@@ -61,12 +61,24 @@ static void qpace_progress(char *s, unsigned short hex)
printk("*** %04x : %s\n", hex, s ? s : "");
}
+static const struct of_device_id qpace_bus_ids[] __initdata = {
+ { .type = "soc", },
+ { .compatible = "soc", },
+ { .type = "spider", },
+ { .type = "axon", },
+ { .type = "plb5", },
+ { .type = "plb4", },
+ { .type = "opb", },
+ { .type = "ebc", },
+ {},
+};
+
static int __init qpace_publish_devices(void)
{
int node;
/* Publish OF platform devices for southbridge IOs */
- of_platform_bus_probe(NULL, NULL, NULL);
+ of_platform_bus_probe(NULL, qpace_bus_ids, NULL);
/* There is no device for the MIC memory controller, thus we create
* a platform device for it to attach the EDAC driver to.
diff --git a/arch/powerpc/platforms/cell/setup.c b/arch/powerpc/platforms/cell/setup.c
index 50385db586b..691995761b3 100644
--- a/arch/powerpc/platforms/cell/setup.c
+++ b/arch/powerpc/platforms/cell/setup.c
@@ -141,6 +141,18 @@ static int __devinit cell_setup_phb(struct pci_controller *phb)
return 0;
}
+static const struct of_device_id cell_bus_ids[] __initdata = {
+ { .type = "soc", },
+ { .compatible = "soc", },
+ { .type = "spider", },
+ { .type = "axon", },
+ { .type = "plb5", },
+ { .type = "plb4", },
+ { .type = "opb", },
+ { .type = "ebc", },
+ {},
+};
+
static int __init cell_publish_devices(void)
{
struct device_node *root = of_find_node_by_path("/");
@@ -148,7 +160,7 @@ static int __init cell_publish_devices(void)
int node;
/* Publish OF platform devices for southbridge IOs */
- of_platform_bus_probe(NULL, NULL, NULL);
+ of_platform_bus_probe(NULL, cell_bus_ids, NULL);
/* On spider based blades, we need to manually create the OF
* platform devices for the PCI host bridges
diff --git a/arch/powerpc/platforms/iseries/mf.c b/arch/powerpc/platforms/iseries/mf.c
index d2c1d497846..33e5fc7334f 100644
--- a/arch/powerpc/platforms/iseries/mf.c
+++ b/arch/powerpc/platforms/iseries/mf.c
@@ -30,6 +30,7 @@
#include <linux/init.h>
#include <linux/completion.h>
#include <linux/delay.h>
+#include <linux/proc_fs.h>
#include <linux/dma-mapping.h>
#include <linux/bcd.h>
#include <linux/rtc.h>
diff --git a/arch/powerpc/platforms/iseries/vio.c b/arch/powerpc/platforms/iseries/vio.c
index 00b6730bc48..b6db7cef83b 100644
--- a/arch/powerpc/platforms/iseries/vio.c
+++ b/arch/powerpc/platforms/iseries/vio.c
@@ -87,12 +87,11 @@ static struct device_node *new_node(const char *path,
if (!np)
return NULL;
- np->full_name = kmalloc(strlen(path) + 1, GFP_KERNEL);
+ np->full_name = kstrdup(path, GFP_KERNEL);
if (!np->full_name) {
kfree(np);
return NULL;
}
- strcpy(np->full_name, path);
of_node_set_flag(np, OF_DYNAMIC);
kref_init(&np->kref);
np->parent = of_node_get(parent);
diff --git a/arch/powerpc/platforms/pasemi/gpio_mdio.c b/arch/powerpc/platforms/pasemi/gpio_mdio.c
index 627ee089e75..a5d907b5a4c 100644
--- a/arch/powerpc/platforms/pasemi/gpio_mdio.c
+++ b/arch/powerpc/platforms/pasemi/gpio_mdio.c
@@ -216,7 +216,7 @@ static int gpio_mdio_reset(struct mii_bus *bus)
}
-static int __devinit gpio_mdio_probe(struct of_device *ofdev,
+static int __devinit gpio_mdio_probe(struct platform_device *ofdev,
const struct of_device_id *match)
{
struct device *dev = &ofdev->dev;
@@ -275,7 +275,7 @@ out:
}
-static int gpio_mdio_remove(struct of_device *dev)
+static int gpio_mdio_remove(struct platform_device *dev)
{
struct mii_bus *bus = dev_get_drvdata(&dev->dev);
diff --git a/arch/powerpc/platforms/powermac/cpufreq_32.c b/arch/powerpc/platforms/powermac/cpufreq_32.c
index 1e9eba175ff..415ca6d6b27 100644
--- a/arch/powerpc/platforms/powermac/cpufreq_32.c
+++ b/arch/powerpc/platforms/powermac/cpufreq_32.c
@@ -310,8 +310,12 @@ static int pmu_set_cpu_speed(int low_speed)
/* Restore low level PMU operations */
pmu_unlock();
- /* Restore decrementer */
- wakeup_decrementer();
+ /*
+ * Restore decrementer; we'll take a decrementer interrupt
+ * as soon as interrupts are re-enabled and the generic
+ * clockevents code will reprogram it with the right value.
+ */
+ set_dec(1);
/* Restore interrupts */
mpic_cpu_set_priority(pic_prio);
diff --git a/arch/powerpc/platforms/powermac/feature.c b/arch/powerpc/platforms/powermac/feature.c
index 9e1b9fd7520..39df6ab1735 100644
--- a/arch/powerpc/platforms/powermac/feature.c
+++ b/arch/powerpc/platforms/powermac/feature.c
@@ -21,6 +21,8 @@
#include <linux/delay.h>
#include <linux/kernel.h>
#include <linux/sched.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
#include <linux/spinlock.h>
#include <linux/adb.h>
#include <linux/pmu.h>
@@ -2191,7 +2193,11 @@ static struct pmac_mb_def pmac_mb_defs[] = {
PMAC_TYPE_UNKNOWN_INTREPID, intrepid_features,
PMAC_MB_MAY_SLEEP,
},
- { "iMac,1", "iMac (first generation)",
+ { "PowerMac10,2", "Mac mini (Late 2005)",
+ PMAC_TYPE_UNKNOWN_INTREPID, intrepid_features,
+ PMAC_MB_MAY_SLEEP,
+ },
+ { "iMac,1", "iMac (first generation)",
PMAC_TYPE_ORIG_IMAC, paddington_features,
0
},
diff --git a/arch/powerpc/platforms/powermac/low_i2c.c b/arch/powerpc/platforms/powermac/low_i2c.c
index 06a137c5b8b..480567e5fa9 100644
--- a/arch/powerpc/platforms/powermac/low_i2c.c
+++ b/arch/powerpc/platforms/powermac/low_i2c.c
@@ -542,11 +542,12 @@ static struct pmac_i2c_host_kw *__init kw_i2c_host_init(struct device_node *np)
/* Make sure IRQ is disabled */
kw_write_reg(reg_ier, 0);
- /* Request chip interrupt. We set IRQF_TIMER because we don't
+ /* Request chip interrupt. We set IRQF_NO_SUSPEND because we don't
* want that interrupt disabled between the 2 passes of driver
* suspend or we'll have issues running the pfuncs
*/
- if (request_irq(host->irq, kw_i2c_irq, IRQF_TIMER, "keywest i2c", host))
+ if (request_irq(host->irq, kw_i2c_irq, IRQF_NO_SUSPEND,
+ "keywest i2c", host))
host->irq = NO_IRQ;
printk(KERN_INFO "KeyWest i2c @0x%08x irq %d %s\n",
diff --git a/arch/powerpc/platforms/powermac/pic.c b/arch/powerpc/platforms/powermac/pic.c
index 630a533d0e5..890d5f72b19 100644
--- a/arch/powerpc/platforms/powermac/pic.c
+++ b/arch/powerpc/platforms/powermac/pic.c
@@ -46,6 +46,10 @@ struct pmac_irq_hw {
unsigned int level;
};
+/* Workaround flags for 32bit powermac machines */
+unsigned int of_irq_workarounds;
+struct device_node *of_irq_dflt_pic;
+
/* Default addresses */
static volatile struct pmac_irq_hw __iomem *pmac_irq_hw[4];
@@ -428,6 +432,42 @@ static void __init pmac_pic_probe_oldstyle(void)
setup_irq(irq_create_mapping(NULL, 20), &xmon_action);
#endif
}
+
+int of_irq_map_oldworld(struct device_node *device, int index,
+ struct of_irq *out_irq)
+{
+ const u32 *ints = NULL;
+ int intlen;
+
+ /*
+ * Old machines just have a list of interrupt numbers
+ * and no interrupt-controller nodes. We also have dodgy
+ * cases where the APPL,interrupts property is completely
+ * missing behind pci-pci bridges and we have to get it
+ * from the parent (the bridge itself, as apple just wired
+ * everything together on these)
+ */
+ while (device) {
+ ints = of_get_property(device, "AAPL,interrupts", &intlen);
+ if (ints != NULL)
+ break;
+ device = device->parent;
+ if (device && strcmp(device->type, "pci") != 0)
+ break;
+ }
+ if (ints == NULL)
+ return -EINVAL;
+ intlen /= sizeof(u32);
+
+ if (index >= intlen)
+ return -EINVAL;
+
+ out_irq->controller = NULL;
+ out_irq->specifier[0] = ints[index];
+ out_irq->size = 1;
+
+ return 0;
+}
#endif /* CONFIG_PPC32 */
static void pmac_u3_cascade(unsigned int irq, struct irq_desc *desc)
@@ -559,19 +599,39 @@ static int __init pmac_pic_probe_mpic(void)
void __init pmac_pic_init(void)
{
- unsigned int flags = 0;
-
/* We configure the OF parsing based on our oldworld vs. newworld
* platform type and wether we were booted by BootX.
*/
#ifdef CONFIG_PPC32
if (!pmac_newworld)
- flags |= OF_IMAP_OLDWORLD_MAC;
+ of_irq_workarounds |= OF_IMAP_OLDWORLD_MAC;
if (of_get_property(of_chosen, "linux,bootx", NULL) != NULL)
- flags |= OF_IMAP_NO_PHANDLE;
-#endif /* CONFIG_PPC_32 */
+ of_irq_workarounds |= OF_IMAP_NO_PHANDLE;
- of_irq_map_init(flags);
+ /* If we don't have phandles on a newworld, then try to locate a
+ * default interrupt controller (happens when booting with BootX).
+ * We do a first match here, hopefully, that only ever happens on
+ * machines with one controller.
+ */
+ if (pmac_newworld && (of_irq_workarounds & OF_IMAP_NO_PHANDLE)) {
+ struct device_node *np;
+
+ for_each_node_with_property(np, "interrupt-controller") {
+ /* Skip /chosen/interrupt-controller */
+ if (strcmp(np->name, "chosen") == 0)
+ continue;
+ /* It seems like at least one person wants
+ * to use BootX on a machine with an AppleKiwi
+ * controller which happens to pretend to be an
+ * interrupt controller too. */
+ if (strcmp(np->name, "AppleKiwi") == 0)
+ continue;
+ /* I think we found one ! */
+ of_irq_dflt_pic = np;
+ break;
+ }
+ }
+#endif /* CONFIG_PPC32 */
/* We first try to detect Apple's new Core99 chipset, since mac-io
* is quite different on those machines and contains an IBM MPIC2.
diff --git a/arch/powerpc/platforms/ps3/htab.c b/arch/powerpc/platforms/ps3/htab.c
index 2c0ed87f202..3124cf791eb 100644
--- a/arch/powerpc/platforms/ps3/htab.c
+++ b/arch/powerpc/platforms/ps3/htab.c
@@ -136,7 +136,7 @@ static long ps3_hpte_updatepp(unsigned long slot, unsigned long newpp,
* As lv1_read_htab_entries() does not give us the RPN, we can
* not synthesize the new hpte_r value here, and therefore can
* not update the hpte with lv1_insert_htab_entry(), so we
- * insted invalidate it and ask the caller to update it via
+ * instead invalidate it and ask the caller to update it via
* ps3_hpte_insert() by returning a -1 value.
*/
if (!HPTE_V_COMPARE(hpte_v, want_v) || !(hpte_v & HPTE_V_VALID)) {
diff --git a/arch/powerpc/platforms/pseries/Makefile b/arch/powerpc/platforms/pseries/Makefile
index 3dbef309bc8..046ace9c438 100644
--- a/arch/powerpc/platforms/pseries/Makefile
+++ b/arch/powerpc/platforms/pseries/Makefile
@@ -26,3 +26,7 @@ obj-$(CONFIG_HCALL_STATS) += hvCall_inst.o
obj-$(CONFIG_PHYP_DUMP) += phyp_dump.o
obj-$(CONFIG_CMM) += cmm.o
obj-$(CONFIG_DTL) += dtl.o
+
+ifeq ($(CONFIG_PPC_PSERIES),y)
+obj-$(CONFIG_SUSPEND) += suspend.o
+endif
diff --git a/arch/powerpc/platforms/pseries/dlpar.c b/arch/powerpc/platforms/pseries/dlpar.c
index d71e5858408..227c1c3d585 100644
--- a/arch/powerpc/platforms/pseries/dlpar.c
+++ b/arch/powerpc/platforms/pseries/dlpar.c
@@ -463,6 +463,7 @@ static int dlpar_offline_cpu(struct device_node *dn)
break;
if (get_cpu_current_state(cpu) == CPU_STATE_ONLINE) {
+ set_preferred_offline_state(cpu, CPU_STATE_OFFLINE);
cpu_maps_update_done();
rc = cpu_down(cpu);
if (rc)
diff --git a/arch/powerpc/platforms/pseries/eeh_cache.c b/arch/powerpc/platforms/pseries/eeh_cache.c
index 30b987b73c2..8ed0d2d0e1b 100644
--- a/arch/powerpc/platforms/pseries/eeh_cache.c
+++ b/arch/powerpc/platforms/pseries/eeh_cache.c
@@ -288,8 +288,7 @@ void __init pci_addr_cache_build(void)
spin_lock_init(&pci_io_addr_cache_root.piar_lock);
- while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {
-
+ for_each_pci_dev(dev) {
pci_addr_cache_insert_device(dev);
dn = pci_device_to_OF_node(dev);
diff --git a/arch/powerpc/platforms/pseries/event_sources.c b/arch/powerpc/platforms/pseries/event_sources.c
index e889c9d9586..2605c310166 100644
--- a/arch/powerpc/platforms/pseries/event_sources.c
+++ b/arch/powerpc/platforms/pseries/event_sources.c
@@ -41,9 +41,12 @@ void request_event_sources_irqs(struct device_node *np,
if (count > 15)
break;
virqs[count] = irq_create_mapping(NULL, *(opicprop++));
- if (virqs[count] == NO_IRQ)
- printk(KERN_ERR "Unable to allocate interrupt "
- "number for %s\n", np->full_name);
+ if (virqs[count] == NO_IRQ) {
+ pr_err("event-sources: Unable to allocate "
+ "interrupt number for %s\n",
+ np->full_name);
+ WARN_ON(1);
+ }
else
count++;
@@ -59,9 +62,12 @@ void request_event_sources_irqs(struct device_node *np,
virqs[count] = irq_create_of_mapping(oirq.controller,
oirq.specifier,
oirq.size);
- if (virqs[count] == NO_IRQ)
- printk(KERN_ERR "Unable to allocate interrupt "
- "number for %s\n", np->full_name);
+ if (virqs[count] == NO_IRQ) {
+ pr_err("event-sources: Unable to allocate "
+ "interrupt number for %s\n",
+ np->full_name);
+ WARN_ON(1);
+ }
else
count++;
}
@@ -70,8 +76,9 @@ void request_event_sources_irqs(struct device_node *np,
/* Now request them */
for (i = 0; i < count; i++) {
if (request_irq(virqs[i], handler, 0, name, NULL)) {
- printk(KERN_ERR "Unable to request interrupt %d for "
- "%s\n", virqs[i], np->full_name);
+ pr_err("event-sources: Unable to request interrupt "
+ "%d for %s\n", virqs[i], np->full_name);
+ WARN_ON(1);
return;
}
}
diff --git a/arch/powerpc/platforms/pseries/hotplug-cpu.c b/arch/powerpc/platforms/pseries/hotplug-cpu.c
index 8f85f399ab9..fd50ccd4bac 100644
--- a/arch/powerpc/platforms/pseries/hotplug-cpu.c
+++ b/arch/powerpc/platforms/pseries/hotplug-cpu.c
@@ -116,6 +116,9 @@ static void pseries_mach_cpu_die(void)
if (get_preferred_offline_state(cpu) == CPU_STATE_INACTIVE) {
set_cpu_current_state(cpu, CPU_STATE_INACTIVE);
+ if (ppc_md.suspend_disable_cpu)
+ ppc_md.suspend_disable_cpu();
+
cede_latency_hint = 2;
get_lppaca()->idle = 1;
@@ -190,12 +193,12 @@ static void pseries_cpu_die(unsigned int cpu)
if (get_preferred_offline_state(cpu) == CPU_STATE_INACTIVE) {
cpu_status = 1;
- for (tries = 0; tries < 1000; tries++) {
+ for (tries = 0; tries < 5000; tries++) {
if (get_cpu_current_state(cpu) == CPU_STATE_INACTIVE) {
cpu_status = 0;
break;
}
- cpu_relax();
+ msleep(1);
}
} else if (get_preferred_offline_state(cpu) == CPU_STATE_OFFLINE) {
diff --git a/arch/powerpc/platforms/pseries/ras.c b/arch/powerpc/platforms/pseries/ras.c
index 41a3e9a039e..a4fc6da87c2 100644
--- a/arch/powerpc/platforms/pseries/ras.c
+++ b/arch/powerpc/platforms/pseries/ras.c
@@ -61,7 +61,6 @@ static int ras_check_exception_token;
#define EPOW_SENSOR_TOKEN 9
#define EPOW_SENSOR_INDEX 0
-#define RAS_VECTOR_OFFSET 0x500
static irqreturn_t ras_epow_interrupt(int irq, void *dev_id);
static irqreturn_t ras_error_interrupt(int irq, void *dev_id);
@@ -121,7 +120,7 @@ static irqreturn_t ras_epow_interrupt(int irq, void *dev_id)
spin_lock(&ras_log_buf_lock);
status = rtas_call(ras_check_exception_token, 6, 1, NULL,
- RAS_VECTOR_OFFSET,
+ RTAS_VECTOR_EXTERNAL_INTERRUPT,
irq_map[irq].hwirq,
RTAS_EPOW_WARNING | RTAS_POWERMGM_EVENTS,
critical, __pa(&ras_log_buf),
@@ -156,7 +155,7 @@ static irqreturn_t ras_error_interrupt(int irq, void *dev_id)
spin_lock(&ras_log_buf_lock);
status = rtas_call(ras_check_exception_token, 6, 1, NULL,
- RAS_VECTOR_OFFSET,
+ RTAS_VECTOR_EXTERNAL_INTERRUPT,
irq_map[irq].hwirq,
RTAS_INTERNAL_ERROR, 1 /*Time Critical */,
__pa(&ras_log_buf),
diff --git a/arch/powerpc/platforms/pseries/reconfig.c b/arch/powerpc/platforms/pseries/reconfig.c
index 1a58637bcea..57ddbb43b33 100644
--- a/arch/powerpc/platforms/pseries/reconfig.c
+++ b/arch/powerpc/platforms/pseries/reconfig.c
@@ -118,12 +118,10 @@ static int pSeries_reconfig_add_node(const char *path, struct property *proplist
if (!np)
goto out_err;
- np->full_name = kmalloc(strlen(path) + 1, GFP_KERNEL);
+ np->full_name = kstrdup(path, GFP_KERNEL);
if (!np->full_name)
goto out_err;
- strcpy(np->full_name, path);
-
np->properties = proplist;
of_node_set_flag(np, OF_DYNAMIC);
kref_init(&np->kref);
diff --git a/arch/powerpc/platforms/pseries/suspend.c b/arch/powerpc/platforms/pseries/suspend.c
new file mode 100644
index 00000000000..ed72098bb4e
--- /dev/null
+++ b/arch/powerpc/platforms/pseries/suspend.c
@@ -0,0 +1,214 @@
+/*
+ * Copyright (C) 2010 Brian King 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/delay.h>
+#include <linux/suspend.h>
+#include <asm/firmware.h>
+#include <asm/hvcall.h>
+#include <asm/machdep.h>
+#include <asm/mmu.h>
+#include <asm/rtas.h>
+
+static u64 stream_id;
+static struct sys_device suspend_sysdev;
+static DECLARE_COMPLETION(suspend_work);
+static struct rtas_suspend_me_data suspend_data;
+static atomic_t suspending;
+
+/**
+ * pseries_suspend_begin - First phase of hibernation
+ *
+ * Check to ensure we are in a valid state to hibernate
+ *
+ * Return value:
+ * 0 on success / other on failure
+ **/
+static int pseries_suspend_begin(suspend_state_t state)
+{
+ long vasi_state, rc;
+ unsigned long retbuf[PLPAR_HCALL_BUFSIZE];
+
+ /* Make sure the state is valid */
+ rc = plpar_hcall(H_VASI_STATE, retbuf, stream_id);
+
+ vasi_state = retbuf[0];
+
+ if (rc) {
+ pr_err("pseries_suspend_begin: vasi_state returned %ld\n",rc);
+ return rc;
+ } else if (vasi_state == H_VASI_ENABLED) {
+ return -EAGAIN;
+ } else if (vasi_state != H_VASI_SUSPENDING) {
+ pr_err("pseries_suspend_begin: vasi_state returned state %ld\n",
+ vasi_state);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+/**
+ * pseries_suspend_cpu - Suspend a single CPU
+ *
+ * Makes the H_JOIN call to suspend the CPU
+ *
+ **/
+static int pseries_suspend_cpu(void)
+{
+ if (atomic_read(&suspending))
+ return rtas_suspend_cpu(&suspend_data);
+ return 0;
+}
+
+/**
+ * pseries_suspend_enter - Final phase of hibernation
+ *
+ * Return value:
+ * 0 on success / other on failure
+ **/
+static int pseries_suspend_enter(suspend_state_t state)
+{
+ int rc = rtas_suspend_last_cpu(&suspend_data);
+
+ atomic_set(&suspending, 0);
+ atomic_set(&suspend_data.done, 1);
+ return rc;
+}
+
+/**
+ * pseries_prepare_late - Prepare to suspend all other CPUs
+ *
+ * Return value:
+ * 0 on success / other on failure
+ **/
+static int pseries_prepare_late(void)
+{
+ atomic_set(&suspending, 1);
+ atomic_set(&suspend_data.working, 0);
+ atomic_set(&suspend_data.done, 0);
+ atomic_set(&suspend_data.error, 0);
+ suspend_data.complete = &suspend_work;
+ INIT_COMPLETION(suspend_work);
+ return 0;
+}
+
+/**
+ * store_hibernate - Initiate partition hibernation
+ * @classdev: sysdev class struct
+ * @attr: class device attribute struct
+ * @buf: buffer
+ * @count: buffer size
+ *
+ * Write the stream ID received from the HMC to this file
+ * to trigger hibernating the partition
+ *
+ * Return value:
+ * number of bytes printed to buffer / other on failure
+ **/
+static ssize_t store_hibernate(struct sysdev_class *classdev,
+ struct sysdev_class_attribute *attr,
+ const char *buf, size_t count)
+{
+ int rc;
+
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+
+ stream_id = simple_strtoul(buf, NULL, 16);
+
+ do {
+ rc = pseries_suspend_begin(PM_SUSPEND_MEM);
+ if (rc == -EAGAIN)
+ ssleep(1);
+ } while (rc == -EAGAIN);
+
+ if (!rc)
+ rc = pm_suspend(PM_SUSPEND_MEM);
+
+ stream_id = 0;
+
+ if (!rc)
+ rc = count;
+ return rc;
+}
+
+static SYSDEV_CLASS_ATTR(hibernate, S_IWUSR, NULL, store_hibernate);
+
+static struct sysdev_class suspend_sysdev_class = {
+ .name = "power",
+};
+
+static struct platform_suspend_ops pseries_suspend_ops = {
+ .valid = suspend_valid_only_mem,
+ .begin = pseries_suspend_begin,
+ .prepare_late = pseries_prepare_late,
+ .enter = pseries_suspend_enter,
+};
+
+/**
+ * pseries_suspend_sysfs_register - Register with sysfs
+ *
+ * Return value:
+ * 0 on success / other on failure
+ **/
+static int pseries_suspend_sysfs_register(struct sys_device *sysdev)
+{
+ int rc;
+
+ if ((rc = sysdev_class_register(&suspend_sysdev_class)))
+ return rc;
+
+ sysdev->id = 0;
+ sysdev->cls = &suspend_sysdev_class;
+
+ if ((rc = sysdev_class_create_file(&suspend_sysdev_class, &attr_hibernate)))
+ goto class_unregister;
+
+ return 0;
+
+class_unregister:
+ sysdev_class_unregister(&suspend_sysdev_class);
+ return rc;
+}
+
+/**
+ * pseries_suspend_init - initcall for pSeries suspend
+ *
+ * Return value:
+ * 0 on success / other on failure
+ **/
+static int __init pseries_suspend_init(void)
+{
+ int rc;
+
+ if (!machine_is(pseries) || !firmware_has_feature(FW_FEATURE_LPAR))
+ return 0;
+
+ suspend_data.token = rtas_token("ibm,suspend-me");
+ if (suspend_data.token == RTAS_UNKNOWN_SERVICE)
+ return 0;
+
+ if ((rc = pseries_suspend_sysfs_register(&suspend_sysdev)))
+ return rc;
+
+ ppc_md.suspend_disable_cpu = pseries_suspend_cpu;
+ suspend_set_ops(&pseries_suspend_ops);
+ return 0;
+}
+
+__initcall(pseries_suspend_init);
diff --git a/arch/powerpc/platforms/pseries/xics.c b/arch/powerpc/platforms/pseries/xics.c
index f19d1946839..5b22b07c8f6 100644
--- a/arch/powerpc/platforms/pseries/xics.c
+++ b/arch/powerpc/platforms/pseries/xics.c
@@ -549,8 +549,6 @@ static irqreturn_t xics_ipi_dispatch(int cpu)
{
unsigned long *tgt = &per_cpu(xics_ipi_message, cpu);
- WARN_ON(cpu_is_offline(cpu));
-
mb(); /* order mmio clearing qirr */
while (*tgt) {
if (test_and_clear_bit(PPC_MSG_CALL_FUNCTION, tgt)) {
diff --git a/arch/powerpc/sysdev/axonram.c b/arch/powerpc/sysdev/axonram.c
index 402d2212162..2659a60bd7b 100644
--- a/arch/powerpc/sysdev/axonram.c
+++ b/arch/powerpc/sysdev/axonram.c
@@ -60,7 +60,7 @@
static int azfs_major, azfs_minor;
struct axon_ram_bank {
- struct of_device *device;
+ struct platform_device *device;
struct gendisk *disk;
unsigned int irq_id;
unsigned long ph_addr;
@@ -72,7 +72,7 @@ struct axon_ram_bank {
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 platform_device *device = to_platform_device(dev);
struct axon_ram_bank *bank = device->dev.platform_data;
BUG_ON(!bank);
@@ -90,7 +90,7 @@ static DEVICE_ATTR(ecc, S_IRUGO, axon_ram_sysfs_ecc, NULL);
static irqreturn_t
axon_ram_irq_handler(int irq, void *dev)
{
- struct of_device *device = dev;
+ struct platform_device *device = dev;
struct axon_ram_bank *bank = device->dev.platform_data;
BUG_ON(!bank);
@@ -174,8 +174,8 @@ static const struct block_device_operations axon_ram_devops = {
* 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_probe(struct platform_device *device,
+ const struct of_device_id *device_id)
{
static int axon_ram_bank_id = -1;
struct axon_ram_bank *bank;
@@ -304,7 +304,7 @@ failed:
* @device: see of_platform_driver method
*/
static int
-axon_ram_remove(struct of_device *device)
+axon_ram_remove(struct platform_device *device)
{
struct axon_ram_bank *bank = device->dev.platform_data;
diff --git a/arch/powerpc/sysdev/bestcomm/bestcomm.c b/arch/powerpc/sysdev/bestcomm/bestcomm.c
index a7c5c470af1..65025611506 100644
--- a/arch/powerpc/sysdev/bestcomm/bestcomm.c
+++ b/arch/powerpc/sysdev/bestcomm/bestcomm.c
@@ -365,8 +365,8 @@ bcom_engine_cleanup(void)
/* OF platform driver */
/* ======================================================================== */
-static int __devinit
-mpc52xx_bcom_probe(struct of_device *op, const struct of_device_id *match)
+static int __devinit mpc52xx_bcom_probe(struct platform_device *op,
+ const struct of_device_id *match)
{
struct device_node *ofn_sram;
struct resource res_bcom;
@@ -461,8 +461,7 @@ error_ofput:
}
-static int
-mpc52xx_bcom_remove(struct of_device *op)
+static int mpc52xx_bcom_remove(struct platform_device *op)
{
/* Clean up the engine */
bcom_engine_cleanup();
diff --git a/arch/powerpc/sysdev/bestcomm/sram.c b/arch/powerpc/sysdev/bestcomm/sram.c
index 5d74ef7a651..1225012a681 100644
--- a/arch/powerpc/sysdev/bestcomm/sram.c
+++ b/arch/powerpc/sysdev/bestcomm/sram.c
@@ -11,6 +11,7 @@
* kind, whether express or implied.
*/
+#include <linux/err.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
diff --git a/arch/powerpc/sysdev/cpm1.c b/arch/powerpc/sysdev/cpm1.c
index 8d103ca6d6a..00852124ff4 100644
--- a/arch/powerpc/sysdev/cpm1.c
+++ b/arch/powerpc/sysdev/cpm1.c
@@ -621,7 +621,6 @@ int cpm1_gpiochip_add16(struct device_node *np)
{
struct cpm1_gpio16_chip *cpm1_gc;
struct of_mm_gpio_chip *mm_gc;
- struct of_gpio_chip *of_gc;
struct gpio_chip *gc;
cpm1_gc = kzalloc(sizeof(*cpm1_gc), GFP_KERNEL);
@@ -631,11 +630,9 @@ int cpm1_gpiochip_add16(struct device_node *np)
spin_lock_init(&cpm1_gc->lock);
mm_gc = &cpm1_gc->mm_gc;
- of_gc = &mm_gc->of_gc;
- gc = &of_gc->gc;
+ gc = &mm_gc->gc;
mm_gc->save_regs = cpm1_gpio16_save_regs;
- of_gc->gpio_cells = 2;
gc->ngpio = 16;
gc->direction_input = cpm1_gpio16_dir_in;
gc->direction_output = cpm1_gpio16_dir_out;
@@ -745,7 +742,6 @@ int cpm1_gpiochip_add32(struct device_node *np)
{
struct cpm1_gpio32_chip *cpm1_gc;
struct of_mm_gpio_chip *mm_gc;
- struct of_gpio_chip *of_gc;
struct gpio_chip *gc;
cpm1_gc = kzalloc(sizeof(*cpm1_gc), GFP_KERNEL);
@@ -755,11 +751,9 @@ int cpm1_gpiochip_add32(struct device_node *np)
spin_lock_init(&cpm1_gc->lock);
mm_gc = &cpm1_gc->mm_gc;
- of_gc = &mm_gc->of_gc;
- gc = &of_gc->gc;
+ gc = &mm_gc->gc;
mm_gc->save_regs = cpm1_gpio32_save_regs;
- of_gc->gpio_cells = 2;
gc->ngpio = 32;
gc->direction_input = cpm1_gpio32_dir_in;
gc->direction_output = cpm1_gpio32_dir_out;
diff --git a/arch/powerpc/sysdev/cpm_common.c b/arch/powerpc/sysdev/cpm_common.c
index 88b9812c854..2b69aa0315b 100644
--- a/arch/powerpc/sysdev/cpm_common.c
+++ b/arch/powerpc/sysdev/cpm_common.c
@@ -325,7 +325,6 @@ int cpm2_gpiochip_add32(struct device_node *np)
{
struct cpm2_gpio32_chip *cpm2_gc;
struct of_mm_gpio_chip *mm_gc;
- struct of_gpio_chip *of_gc;
struct gpio_chip *gc;
cpm2_gc = kzalloc(sizeof(*cpm2_gc), GFP_KERNEL);
@@ -335,11 +334,9 @@ int cpm2_gpiochip_add32(struct device_node *np)
spin_lock_init(&cpm2_gc->lock);
mm_gc = &cpm2_gc->mm_gc;
- of_gc = &mm_gc->of_gc;
- gc = &of_gc->gc;
+ gc = &mm_gc->gc;
mm_gc->save_regs = cpm2_gpio32_save_regs;
- of_gc->gpio_cells = 2;
gc->ngpio = 32;
gc->direction_input = cpm2_gpio32_dir_in;
gc->direction_output = cpm2_gpio32_dir_out;
diff --git a/arch/powerpc/sysdev/fsl_gtm.c b/arch/powerpc/sysdev/fsl_gtm.c
index eca4545dd52..7dd2885321a 100644
--- a/arch/powerpc/sysdev/fsl_gtm.c
+++ b/arch/powerpc/sysdev/fsl_gtm.c
@@ -14,6 +14,7 @@
*/
#include <linux/kernel.h>
+#include <linux/err.h>
#include <linux/errno.h>
#include <linux/list.h>
#include <linux/io.h>
diff --git a/arch/powerpc/sysdev/fsl_msi.c b/arch/powerpc/sysdev/fsl_msi.c
index 962c2d8dd8d..87991d3abba 100644
--- a/arch/powerpc/sysdev/fsl_msi.c
+++ b/arch/powerpc/sysdev/fsl_msi.c
@@ -250,7 +250,7 @@ unlock:
raw_spin_unlock(&desc->lock);
}
-static int fsl_of_msi_remove(struct of_device *ofdev)
+static int fsl_of_msi_remove(struct platform_device *ofdev)
{
struct fsl_msi *msi = ofdev->dev.platform_data;
int virq, i;
@@ -274,7 +274,7 @@ static int fsl_of_msi_remove(struct of_device *ofdev)
return 0;
}
-static int __devinit fsl_of_msi_probe(struct of_device *dev,
+static int __devinit fsl_of_msi_probe(struct platform_device *dev,
const struct of_device_id *match)
{
struct fsl_msi *msi;
diff --git a/arch/powerpc/sysdev/fsl_pci.c b/arch/powerpc/sysdev/fsl_pci.c
index 356c6a0e1b2..209384b6e03 100644
--- a/arch/powerpc/sysdev/fsl_pci.c
+++ b/arch/powerpc/sysdev/fsl_pci.c
@@ -412,6 +412,7 @@ DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_P4080, quirk_fsl_pcie_header);
#endif /* CONFIG_FSL_SOC_BOOKE || CONFIG_PPC_86xx */
#if defined(CONFIG_PPC_83xx) || defined(CONFIG_PPC_MPC512x)
+DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_MPC8308, quirk_fsl_pcie_header);
DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_MPC8314E, quirk_fsl_pcie_header);
DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_MPC8314, quirk_fsl_pcie_header);
DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_MPC8315E, quirk_fsl_pcie_header);
diff --git a/arch/powerpc/sysdev/fsl_pmc.c b/arch/powerpc/sysdev/fsl_pmc.c
index 9082eb921ad..44de8559c97 100644
--- a/arch/powerpc/sysdev/fsl_pmc.c
+++ b/arch/powerpc/sysdev/fsl_pmc.c
@@ -58,7 +58,8 @@ static struct platform_suspend_ops pmc_suspend_ops = {
.enter = pmc_suspend_enter,
};
-static int pmc_probe(struct of_device *ofdev, const struct of_device_id *id)
+static int pmc_probe(struct platform_device *ofdev,
+ const struct of_device_id *id)
{
pmc_regs = of_iomap(ofdev->dev.of_node, 0);
if (!pmc_regs)
diff --git a/arch/powerpc/sysdev/fsl_rio.c b/arch/powerpc/sysdev/fsl_rio.c
index 30e1626b2e8..8bd86530ee2 100644
--- a/arch/powerpc/sysdev/fsl_rio.c
+++ b/arch/powerpc/sysdev/fsl_rio.c
@@ -1338,7 +1338,7 @@ static inline void fsl_rio_info(struct device *dev, u32 ccsr)
* master port with system-specific info, and registers the
* master port with the RapidIO subsystem.
*/
-int fsl_rio_setup(struct of_device *dev)
+int fsl_rio_setup(struct platform_device *dev)
{
struct rio_ops *ops;
struct rio_mport *port;
@@ -1536,7 +1536,7 @@ err_ops:
/* The probe function for RapidIO peer-to-peer network.
*/
-static int __devinit fsl_of_rio_rpn_probe(struct of_device *dev,
+static int __devinit fsl_of_rio_rpn_probe(struct platform_device *dev,
const struct of_device_id *match)
{
int rc;
diff --git a/arch/powerpc/sysdev/fsl_soc.h b/arch/powerpc/sysdev/fsl_soc.h
index 42381bb6cd5..53609489a62 100644
--- a/arch/powerpc/sysdev/fsl_soc.h
+++ b/arch/powerpc/sysdev/fsl_soc.h
@@ -30,6 +30,7 @@ struct platform_diu_data_ops {
void (*set_pixel_clock) (unsigned int pixclock);
ssize_t (*show_monitor_port) (int monitor_port, char *buf);
int (*set_sysfs_monitor_port) (int val);
+ void (*release_bootmem) (void);
};
extern struct platform_diu_data_ops diu_ops;
diff --git a/arch/powerpc/sysdev/mpc8xxx_gpio.c b/arch/powerpc/sysdev/mpc8xxx_gpio.c
index 83f519655fa..2b69084d0f0 100644
--- a/arch/powerpc/sysdev/mpc8xxx_gpio.c
+++ b/arch/powerpc/sysdev/mpc8xxx_gpio.c
@@ -257,7 +257,6 @@ static void __init mpc8xxx_add_controller(struct device_node *np)
{
struct mpc8xxx_gpio_chip *mpc8xxx_gc;
struct of_mm_gpio_chip *mm_gc;
- struct of_gpio_chip *of_gc;
struct gpio_chip *gc;
unsigned hwirq;
int ret;
@@ -271,11 +270,9 @@ static void __init mpc8xxx_add_controller(struct device_node *np)
spin_lock_init(&mpc8xxx_gc->lock);
mm_gc = &mpc8xxx_gc->mm_gc;
- of_gc = &mm_gc->of_gc;
- gc = &of_gc->gc;
+ gc = &mm_gc->gc;
mm_gc->save_regs = mpc8xxx_gpio_save_regs;
- of_gc->gpio_cells = 2;
gc->ngpio = MPC8XXX_GPIO_PINS;
gc->direction_input = mpc8xxx_gpio_dir_in;
gc->direction_output = mpc8xxx_gpio_dir_out;
diff --git a/arch/powerpc/sysdev/mpic.c b/arch/powerpc/sysdev/mpic.c
index 20b73c025a4..7c1342618a3 100644
--- a/arch/powerpc/sysdev/mpic.c
+++ b/arch/powerpc/sysdev/mpic.c
@@ -1636,6 +1636,24 @@ void __devinit smp_mpic_setup_cpu(int cpu)
{
mpic_setup_this_cpu();
}
+
+void mpic_reset_core(int cpu)
+{
+ struct mpic *mpic = mpic_primary;
+ u32 pir;
+ int cpuid = get_hard_smp_processor_id(cpu);
+
+ /* Set target bit for core reset */
+ pir = mpic_read(mpic->gregs, MPIC_INFO(GREG_PROCESSOR_INIT));
+ pir |= (1 << cpuid);
+ mpic_write(mpic->gregs, MPIC_INFO(GREG_PROCESSOR_INIT), pir);
+ mpic_read(mpic->gregs, MPIC_INFO(GREG_PROCESSOR_INIT));
+
+ /* Restore target bit after reset complete */
+ pir &= ~(1 << cpuid);
+ mpic_write(mpic->gregs, MPIC_INFO(GREG_PROCESSOR_INIT), pir);
+ mpic_read(mpic->gregs, MPIC_INFO(GREG_PROCESSOR_INIT));
+}
#endif /* CONFIG_SMP */
#ifdef CONFIG_PM
diff --git a/arch/powerpc/sysdev/mpic.h b/arch/powerpc/sysdev/mpic.h
index eff433c322a..e4a6df77b8d 100644
--- a/arch/powerpc/sysdev/mpic.h
+++ b/arch/powerpc/sysdev/mpic.h
@@ -37,5 +37,6 @@ static inline int mpic_pasemi_msi_init(struct mpic *mpic)
extern int mpic_set_irq_type(unsigned int virq, unsigned int flow_type);
extern void mpic_set_vector(unsigned int virq, unsigned int vector);
extern int mpic_set_affinity(unsigned int irq, const struct cpumask *cpumask);
+extern void mpic_reset_core(int cpu);
#endif /* _POWERPC_SYSDEV_MPIC_H */
diff --git a/arch/powerpc/sysdev/mv64x60_dev.c b/arch/powerpc/sysdev/mv64x60_dev.c
index 31acd3b1718..1398bc45499 100644
--- a/arch/powerpc/sysdev/mv64x60_dev.c
+++ b/arch/powerpc/sysdev/mv64x60_dev.c
@@ -20,12 +20,7 @@
#include <asm/prom.h>
-/*
- * These functions provide the necessary setup for the mv64x60 drivers.
- * These drivers are unusual in that they work on both the MIPS and PowerPC
- * architectures. Because of that, the drivers do not support the normal
- * PowerPC of_platform_bus_type. They support platform_bus_type instead.
- */
+/* These functions provide the necessary setup for the mv64x60 drivers. */
static struct of_device_id __initdata of_mv64x60_devices[] = {
{ .compatible = "marvell,mv64306-devctrl", },
diff --git a/arch/powerpc/sysdev/mv64x60_pci.c b/arch/powerpc/sysdev/mv64x60_pci.c
index 198f288570c..77bb3f4d530 100644
--- a/arch/powerpc/sysdev/mv64x60_pci.c
+++ b/arch/powerpc/sysdev/mv64x60_pci.c
@@ -73,7 +73,6 @@ static struct bin_attribute mv64x60_hs_reg_attr = { /* Hotswap register */
.attr = {
.name = "hs_reg",
.mode = S_IRUGO | S_IWUSR,
- .owner = THIS_MODULE,
},
.size = MV64X60_VAL_LEN_MAX,
.read = mv64x60_hs_reg_read,
diff --git a/arch/powerpc/sysdev/pmi.c b/arch/powerpc/sysdev/pmi.c
index d07137a07d7..24a0bb955b1 100644
--- a/arch/powerpc/sysdev/pmi.c
+++ b/arch/powerpc/sysdev/pmi.c
@@ -43,7 +43,7 @@ struct pmi_data {
struct mutex msg_mutex;
pmi_message_t msg;
struct completion *completion;
- struct of_device *dev;
+ struct platform_device *dev;
int irq;
u8 __iomem *pmi_reg;
struct work_struct work;
@@ -121,7 +121,7 @@ static void pmi_notify_handlers(struct work_struct *work)
spin_unlock(&data->handler_spinlock);
}
-static int pmi_of_probe(struct of_device *dev,
+static int pmi_of_probe(struct platform_device *dev,
const struct of_device_id *match)
{
struct device_node *np = dev->dev.of_node;
@@ -185,7 +185,7 @@ out:
return rc;
}
-static int pmi_of_remove(struct of_device *dev)
+static int pmi_of_remove(struct platform_device *dev)
{
struct pmi_handler *handler, *tmp;
diff --git a/arch/powerpc/sysdev/ppc4xx_gpio.c b/arch/powerpc/sysdev/ppc4xx_gpio.c
index 3812fc366be..fc65ad1b329 100644
--- a/arch/powerpc/sysdev/ppc4xx_gpio.c
+++ b/arch/powerpc/sysdev/ppc4xx_gpio.c
@@ -181,7 +181,6 @@ static int __init ppc4xx_add_gpiochips(void)
int ret;
struct ppc4xx_gpio_chip *ppc4xx_gc;
struct of_mm_gpio_chip *mm_gc;
- struct of_gpio_chip *of_gc;
struct gpio_chip *gc;
ppc4xx_gc = kzalloc(sizeof(*ppc4xx_gc), GFP_KERNEL);
@@ -193,10 +192,8 @@ static int __init ppc4xx_add_gpiochips(void)
spin_lock_init(&ppc4xx_gc->lock);
mm_gc = &ppc4xx_gc->mm_gc;
- of_gc = &mm_gc->of_gc;
- gc = &of_gc->gc;
+ gc = &mm_gc->gc;
- of_gc->gpio_cells = 2;
gc->ngpio = 32;
gc->direction_input = ppc4xx_gpio_dir_in;
gc->direction_output = ppc4xx_gpio_dir_out;
diff --git a/arch/powerpc/sysdev/qe_lib/gpio.c b/arch/powerpc/sysdev/qe_lib/gpio.c
index dc8f8d61807..36bf845df12 100644
--- a/arch/powerpc/sysdev/qe_lib/gpio.c
+++ b/arch/powerpc/sysdev/qe_lib/gpio.c
@@ -138,8 +138,8 @@ struct qe_pin {
struct qe_pin *qe_pin_request(struct device_node *np, int index)
{
struct qe_pin *qe_pin;
- struct device_node *gc;
- struct of_gpio_chip *of_gc = NULL;
+ struct device_node *gpio_np;
+ struct gpio_chip *gc;
struct of_mm_gpio_chip *mm_gc;
struct qe_gpio_chip *qe_gc;
int err;
@@ -155,40 +155,40 @@ struct qe_pin *qe_pin_request(struct device_node *np, int index)
}
err = of_parse_phandles_with_args(np, "gpios", "#gpio-cells", index,
- &gc, &gpio_spec);
+ &gpio_np, &gpio_spec);
if (err) {
pr_debug("%s: can't parse gpios property\n", __func__);
goto err0;
}
- if (!of_device_is_compatible(gc, "fsl,mpc8323-qe-pario-bank")) {
+ if (!of_device_is_compatible(gpio_np, "fsl,mpc8323-qe-pario-bank")) {
pr_debug("%s: tried to get a non-qe pin\n", __func__);
err = -EINVAL;
goto err1;
}
- of_gc = gc->data;
- if (!of_gc) {
+ gc = of_node_to_gpiochip(gpio_np);
+ if (!gc) {
pr_debug("%s: gpio controller %s isn't registered\n",
- np->full_name, gc->full_name);
+ np->full_name, gpio_np->full_name);
err = -ENODEV;
goto err1;
}
- gpio_cells = of_get_property(gc, "#gpio-cells", &size);
+ gpio_cells = of_get_property(gpio_np, "#gpio-cells", &size);
if (!gpio_cells || size != sizeof(*gpio_cells) ||
- *gpio_cells != of_gc->gpio_cells) {
+ *gpio_cells != gc->of_gpio_n_cells) {
pr_debug("%s: wrong #gpio-cells for %s\n",
- np->full_name, gc->full_name);
+ np->full_name, gpio_np->full_name);
err = -EINVAL;
goto err1;
}
- err = of_gc->xlate(of_gc, np, gpio_spec, NULL);
+ err = gc->of_xlate(gc, np, gpio_spec, NULL);
if (err < 0)
goto err1;
- mm_gc = to_of_mm_gpio_chip(&of_gc->gc);
+ mm_gc = to_of_mm_gpio_chip(gc);
qe_gc = to_qe_gpio_chip(mm_gc);
spin_lock_irqsave(&qe_gc->lock, flags);
@@ -206,7 +206,7 @@ struct qe_pin *qe_pin_request(struct device_node *np, int index)
if (!err)
return qe_pin;
err1:
- of_node_put(gc);
+ of_node_put(gpio_np);
err0:
kfree(qe_pin);
pr_debug("%s failed with status %d\n", __func__, err);
@@ -307,7 +307,6 @@ static int __init qe_add_gpiochips(void)
int ret;
struct qe_gpio_chip *qe_gc;
struct of_mm_gpio_chip *mm_gc;
- struct of_gpio_chip *of_gc;
struct gpio_chip *gc;
qe_gc = kzalloc(sizeof(*qe_gc), GFP_KERNEL);
@@ -319,11 +318,9 @@ static int __init qe_add_gpiochips(void)
spin_lock_init(&qe_gc->lock);
mm_gc = &qe_gc->mm_gc;
- of_gc = &mm_gc->of_gc;
- gc = &of_gc->gc;
+ gc = &mm_gc->gc;
mm_gc->save_regs = qe_gpio_save_regs;
- of_gc->gpio_cells = 2;
gc->ngpio = QE_PIO_PINS;
gc->direction_input = qe_gpio_dir_in;
gc->direction_output = qe_gpio_dir_out;
diff --git a/arch/powerpc/sysdev/qe_lib/qe.c b/arch/powerpc/sysdev/qe_lib/qe.c
index 093e0ae1a94..3da8014931c 100644
--- a/arch/powerpc/sysdev/qe_lib/qe.c
+++ b/arch/powerpc/sysdev/qe_lib/qe.c
@@ -651,14 +651,15 @@ unsigned int qe_get_num_of_snums(void)
EXPORT_SYMBOL(qe_get_num_of_snums);
#if defined(CONFIG_SUSPEND) && defined(CONFIG_PPC_85xx)
-static int qe_resume(struct of_device *ofdev)
+static int qe_resume(struct platform_device *ofdev)
{
if (!qe_alive_during_sleep())
qe_reset();
return 0;
}
-static int qe_probe(struct of_device *ofdev, const struct of_device_id *id)
+static int qe_probe(struct platform_device *ofdev,
+ const struct of_device_id *id)
{
return 0;
}
diff --git a/arch/powerpc/sysdev/simple_gpio.c b/arch/powerpc/sysdev/simple_gpio.c
index d5fb173e588..b6defda5ccc 100644
--- a/arch/powerpc/sysdev/simple_gpio.c
+++ b/arch/powerpc/sysdev/simple_gpio.c
@@ -91,7 +91,6 @@ static int __init u8_simple_gpiochip_add(struct device_node *np)
int ret;
struct u8_gpio_chip *u8_gc;
struct of_mm_gpio_chip *mm_gc;
- struct of_gpio_chip *of_gc;
struct gpio_chip *gc;
u8_gc = kzalloc(sizeof(*u8_gc), GFP_KERNEL);
@@ -101,11 +100,9 @@ static int __init u8_simple_gpiochip_add(struct device_node *np)
spin_lock_init(&u8_gc->lock);
mm_gc = &u8_gc->mm_gc;
- of_gc = &mm_gc->of_gc;
- gc = &of_gc->gc;
+ gc = &mm_gc->gc;
mm_gc->save_regs = u8_gpio_save_regs;
- of_gc->gpio_cells = 2;
gc->ngpio = 8;
gc->direction_input = u8_gpio_dir_in;
gc->direction_output = u8_gpio_dir_out;
diff --git a/arch/powerpc/xmon/xmon.c b/arch/powerpc/xmon/xmon.c
index 8bad7d5f32a..0554445200b 100644
--- a/arch/powerpc/xmon/xmon.c
+++ b/arch/powerpc/xmon/xmon.c
@@ -155,6 +155,9 @@ static int do_spu_cmd(void);
#ifdef CONFIG_44x
static void dump_tlb_44x(void);
#endif
+#ifdef CONFIG_PPC_BOOK3E
+static void dump_tlb_book3e(void);
+#endif
static int xmon_no_auto_backtrace;
@@ -888,6 +891,11 @@ cmds(struct pt_regs *excp)
dump_tlb_44x();
break;
#endif
+#ifdef CONFIG_PPC_BOOK3E
+ case 'u':
+ dump_tlb_book3e();
+ break;
+#endif
default:
printf("Unrecognized command: ");
do {
@@ -2701,6 +2709,150 @@ static void dump_tlb_44x(void)
}
#endif /* CONFIG_44x */
+#ifdef CONFIG_PPC_BOOK3E
+static void dump_tlb_book3e(void)
+{
+ u32 mmucfg, pidmask, lpidmask;
+ u64 ramask;
+ int i, tlb, ntlbs, pidsz, lpidsz, rasz, lrat = 0;
+ int mmu_version;
+ static const char *pgsz_names[] = {
+ " 1K",
+ " 2K",
+ " 4K",
+ " 8K",
+ " 16K",
+ " 32K",
+ " 64K",
+ "128K",
+ "256K",
+ "512K",
+ " 1M",
+ " 2M",
+ " 4M",
+ " 8M",
+ " 16M",
+ " 32M",
+ " 64M",
+ "128M",
+ "256M",
+ "512M",
+ " 1G",
+ " 2G",
+ " 4G",
+ " 8G",
+ " 16G",
+ " 32G",
+ " 64G",
+ "128G",
+ "256G",
+ "512G",
+ " 1T",
+ " 2T",
+ };
+
+ /* Gather some infos about the MMU */
+ mmucfg = mfspr(SPRN_MMUCFG);
+ mmu_version = (mmucfg & 3) + 1;
+ ntlbs = ((mmucfg >> 2) & 3) + 1;
+ pidsz = ((mmucfg >> 6) & 0x1f) + 1;
+ lpidsz = (mmucfg >> 24) & 0xf;
+ rasz = (mmucfg >> 16) & 0x7f;
+ if ((mmu_version > 1) && (mmucfg & 0x10000))
+ lrat = 1;
+ printf("Book3E MMU MAV=%d.0,%d TLBs,%d-bit PID,%d-bit LPID,%d-bit RA\n",
+ mmu_version, ntlbs, pidsz, lpidsz, rasz);
+ pidmask = (1ul << pidsz) - 1;
+ lpidmask = (1ul << lpidsz) - 1;
+ ramask = (1ull << rasz) - 1;
+
+ for (tlb = 0; tlb < ntlbs; tlb++) {
+ u32 tlbcfg;
+ int nent, assoc, new_cc = 1;
+ printf("TLB %d:\n------\n", tlb);
+ switch(tlb) {
+ case 0:
+ tlbcfg = mfspr(SPRN_TLB0CFG);
+ break;
+ case 1:
+ tlbcfg = mfspr(SPRN_TLB1CFG);
+ break;
+ case 2:
+ tlbcfg = mfspr(SPRN_TLB2CFG);
+ break;
+ case 3:
+ tlbcfg = mfspr(SPRN_TLB3CFG);
+ break;
+ default:
+ printf("Unsupported TLB number !\n");
+ continue;
+ }
+ nent = tlbcfg & 0xfff;
+ assoc = (tlbcfg >> 24) & 0xff;
+ for (i = 0; i < nent; i++) {
+ u32 mas0 = MAS0_TLBSEL(tlb);
+ u32 mas1 = MAS1_TSIZE(BOOK3E_PAGESZ_4K);
+ u64 mas2 = 0;
+ u64 mas7_mas3;
+ int esel = i, cc = i;
+
+ if (assoc != 0) {
+ cc = i / assoc;
+ esel = i % assoc;
+ mas2 = cc * 0x1000;
+ }
+
+ mas0 |= MAS0_ESEL(esel);
+ mtspr(SPRN_MAS0, mas0);
+ mtspr(SPRN_MAS1, mas1);
+ mtspr(SPRN_MAS2, mas2);
+ asm volatile("tlbre 0,0,0" : : : "memory");
+ mas1 = mfspr(SPRN_MAS1);
+ mas2 = mfspr(SPRN_MAS2);
+ mas7_mas3 = mfspr(SPRN_MAS7_MAS3);
+ if (assoc && (i % assoc) == 0)
+ new_cc = 1;
+ if (!(mas1 & MAS1_VALID))
+ continue;
+ if (assoc == 0)
+ printf("%04x- ", i);
+ else if (new_cc)
+ printf("%04x-%c", cc, 'A' + esel);
+ else
+ printf(" |%c", 'A' + esel);
+ new_cc = 0;
+ printf(" %016llx %04x %s %c%c AS%c",
+ mas2 & ~0x3ffull,
+ (mas1 >> 16) & 0x3fff,
+ pgsz_names[(mas1 >> 7) & 0x1f],
+ mas1 & MAS1_IND ? 'I' : ' ',
+ mas1 & MAS1_IPROT ? 'P' : ' ',
+ mas1 & MAS1_TS ? '1' : '0');
+ printf(" %c%c%c%c%c%c%c",
+ mas2 & MAS2_X0 ? 'a' : ' ',
+ mas2 & MAS2_X1 ? 'v' : ' ',
+ mas2 & MAS2_W ? 'w' : ' ',
+ mas2 & MAS2_I ? 'i' : ' ',
+ mas2 & MAS2_M ? 'm' : ' ',
+ mas2 & MAS2_G ? 'g' : ' ',
+ mas2 & MAS2_E ? 'e' : ' ');
+ printf(" %016llx", mas7_mas3 & ramask & ~0x7ffull);
+ if (mas1 & MAS1_IND)
+ printf(" %s\n",
+ pgsz_names[(mas7_mas3 >> 1) & 0x1f]);
+ else
+ printf(" U%c%c%c S%c%c%c\n",
+ mas7_mas3 & MAS3_UX ? 'x' : ' ',
+ mas7_mas3 & MAS3_UW ? 'w' : ' ',
+ mas7_mas3 & MAS3_UR ? 'r' : ' ',
+ mas7_mas3 & MAS3_SX ? 'x' : ' ',
+ mas7_mas3 & MAS3_SW ? 'w' : ' ',
+ mas7_mas3 & MAS3_SR ? 'r' : ' ');
+ }
+ }
+}
+#endif /* CONFIG_PPC_BOOK3E */
+
static void xmon_init(int enable)
{
#ifdef CONFIG_PPC_ISERIES
diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig
index bee1c0f794c..f0777a47e3a 100644
--- a/arch/s390/Kconfig
+++ b/arch/s390/Kconfig
@@ -40,9 +40,6 @@ config ARCH_HAS_ILOG2_U64
config GENERIC_HWEIGHT
def_bool y
-config GENERIC_TIME
- def_bool y
-
config GENERIC_TIME_VSYSCALL
def_bool y
diff --git a/arch/s390/Makefile b/arch/s390/Makefile
index 30c5f01f93b..0c9e6c6d2a6 100644
--- a/arch/s390/Makefile
+++ b/arch/s390/Makefile
@@ -24,7 +24,8 @@ CHECKFLAGS += -D__s390__ -msize-long
else
LD_BFD := elf64-s390
LDFLAGS := -m elf64_s390
-MODFLAGS += -fpic -D__PIC__
+KBUILD_AFLAGS_MODULE += -fpic -D__PIC__
+KBUILD_CFLAGS_MODULE += -fpic -D__PIC__
KBUILD_CFLAGS += -m64
KBUILD_AFLAGS += -m64
UTS_MACHINE := s390x
diff --git a/arch/s390/appldata/appldata_net_sum.c b/arch/s390/appldata/appldata_net_sum.c
index 9a9586f4103..f02e89ce4df 100644
--- a/arch/s390/appldata/appldata_net_sum.c
+++ b/arch/s390/appldata/appldata_net_sum.c
@@ -85,7 +85,8 @@ static void appldata_get_net_sum_data(void *data)
rcu_read_lock();
for_each_netdev_rcu(&init_net, dev) {
- const struct net_device_stats *stats = dev_get_stats(dev);
+ struct rtnl_link_stats64 temp;
+ const struct net_device_stats *stats = dev_get_stats(dev, &temp);
rx_packets += stats->rx_packets;
tx_packets += stats->tx_packets;
diff --git a/arch/s390/crypto/Makefile b/arch/s390/crypto/Makefile
index 6a1157fa4f9..1cf81d77c5a 100644
--- a/arch/s390/crypto/Makefile
+++ b/arch/s390/crypto/Makefile
@@ -5,6 +5,6 @@
obj-$(CONFIG_CRYPTO_SHA1_S390) += sha1_s390.o sha_common.o
obj-$(CONFIG_CRYPTO_SHA256_S390) += sha256_s390.o sha_common.o
obj-$(CONFIG_CRYPTO_SHA512_S390) += sha512_s390.o sha_common.o
-obj-$(CONFIG_CRYPTO_DES_S390) += des_s390.o des_check_key.o
+obj-$(CONFIG_CRYPTO_DES_S390) += des_s390.o
obj-$(CONFIG_CRYPTO_AES_S390) += aes_s390.o
obj-$(CONFIG_S390_PRNG) += prng.o
diff --git a/arch/s390/crypto/crypto_des.h b/arch/s390/crypto/crypto_des.h
index c964b64111d..6210457ceeb 100644
--- a/arch/s390/crypto/crypto_des.h
+++ b/arch/s390/crypto/crypto_des.h
@@ -15,4 +15,4 @@
extern int crypto_des_check_key(const u8*, unsigned int, u32*);
-#endif //__CRYPTO_DES_H__
+#endif /*__CRYPTO_DES_H__*/
diff --git a/arch/s390/crypto/des_s390.c b/arch/s390/crypto/des_s390.c
index 2bc479ab3a6..cc542011839 100644
--- a/arch/s390/crypto/des_s390.c
+++ b/arch/s390/crypto/des_s390.c
@@ -14,32 +14,21 @@
*
*/
-#include <crypto/algapi.h>
#include <linux/init.h>
#include <linux/module.h>
+#include <linux/crypto.h>
+#include <crypto/algapi.h>
+#include <crypto/des.h>
#include "crypt_s390.h"
-#include "crypto_des.h"
-
-#define DES_BLOCK_SIZE 8
-#define DES_KEY_SIZE 8
-
-#define DES3_128_KEY_SIZE (2 * DES_KEY_SIZE)
-#define DES3_128_BLOCK_SIZE DES_BLOCK_SIZE
#define DES3_192_KEY_SIZE (3 * DES_KEY_SIZE)
-#define DES3_192_BLOCK_SIZE DES_BLOCK_SIZE
struct crypt_s390_des_ctx {
u8 iv[DES_BLOCK_SIZE];
u8 key[DES_KEY_SIZE];
};
-struct crypt_s390_des3_128_ctx {
- u8 iv[DES_BLOCK_SIZE];
- u8 key[DES3_128_KEY_SIZE];
-};
-
struct crypt_s390_des3_192_ctx {
u8 iv[DES_BLOCK_SIZE];
u8 key[DES3_192_KEY_SIZE];
@@ -50,13 +39,16 @@ static int des_setkey(struct crypto_tfm *tfm, const u8 *key,
{
struct crypt_s390_des_ctx *dctx = crypto_tfm_ctx(tfm);
u32 *flags = &tfm->crt_flags;
- int ret;
+ u32 tmp[DES_EXPKEY_WORDS];
- /* test if key is valid (not a weak key) */
- ret = crypto_des_check_key(key, keylen, flags);
- if (ret == 0)
- memcpy(dctx->key, key, keylen);
- return ret;
+ /* check for weak keys */
+ if (!des_ekey(tmp, key) && (*flags & CRYPTO_TFM_REQ_WEAK_KEY)) {
+ *flags |= CRYPTO_TFM_RES_WEAK_KEY;
+ return -EINVAL;
+ }
+
+ memcpy(dctx->key, key, keylen);
+ return 0;
}
static void des_encrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in)
@@ -237,165 +229,6 @@ static struct crypto_alg cbc_des_alg = {
* complementation keys. Any weakness is obviated by the use of
* multiple keys.
*
- * However, if the two independent 64-bit keys are equal,
- * then the DES3 operation is simply the same as DES.
- * Implementers MUST reject keys that exhibit this property.
- *
- */
-static int des3_128_setkey(struct crypto_tfm *tfm, const u8 *key,
- unsigned int keylen)
-{
- int i, ret;
- struct crypt_s390_des3_128_ctx *dctx = crypto_tfm_ctx(tfm);
- const u8 *temp_key = key;
- u32 *flags = &tfm->crt_flags;
-
- if (!(memcmp(key, &key[DES_KEY_SIZE], DES_KEY_SIZE)) &&
- (*flags & CRYPTO_TFM_REQ_WEAK_KEY)) {
- *flags |= CRYPTO_TFM_RES_WEAK_KEY;
- return -EINVAL;
- }
- for (i = 0; i < 2; i++, temp_key += DES_KEY_SIZE) {
- ret = crypto_des_check_key(temp_key, DES_KEY_SIZE, flags);
- if (ret < 0)
- return ret;
- }
- memcpy(dctx->key, key, keylen);
- return 0;
-}
-
-static void des3_128_encrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
-{
- struct crypt_s390_des3_128_ctx *dctx = crypto_tfm_ctx(tfm);
-
- crypt_s390_km(KM_TDEA_128_ENCRYPT, dctx->key, dst, (void*)src,
- DES3_128_BLOCK_SIZE);
-}
-
-static void des3_128_decrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
-{
- struct crypt_s390_des3_128_ctx *dctx = crypto_tfm_ctx(tfm);
-
- crypt_s390_km(KM_TDEA_128_DECRYPT, dctx->key, dst, (void*)src,
- DES3_128_BLOCK_SIZE);
-}
-
-static struct crypto_alg des3_128_alg = {
- .cra_name = "des3_ede128",
- .cra_driver_name = "des3_ede128-s390",
- .cra_priority = CRYPT_S390_PRIORITY,
- .cra_flags = CRYPTO_ALG_TYPE_CIPHER,
- .cra_blocksize = DES3_128_BLOCK_SIZE,
- .cra_ctxsize = sizeof(struct crypt_s390_des3_128_ctx),
- .cra_module = THIS_MODULE,
- .cra_list = LIST_HEAD_INIT(des3_128_alg.cra_list),
- .cra_u = {
- .cipher = {
- .cia_min_keysize = DES3_128_KEY_SIZE,
- .cia_max_keysize = DES3_128_KEY_SIZE,
- .cia_setkey = des3_128_setkey,
- .cia_encrypt = des3_128_encrypt,
- .cia_decrypt = des3_128_decrypt,
- }
- }
-};
-
-static int ecb_des3_128_encrypt(struct blkcipher_desc *desc,
- struct scatterlist *dst,
- struct scatterlist *src, unsigned int nbytes)
-{
- struct crypt_s390_des3_128_ctx *sctx = crypto_blkcipher_ctx(desc->tfm);
- struct blkcipher_walk walk;
-
- blkcipher_walk_init(&walk, dst, src, nbytes);
- return ecb_desall_crypt(desc, KM_TDEA_128_ENCRYPT, sctx->key, &walk);
-}
-
-static int ecb_des3_128_decrypt(struct blkcipher_desc *desc,
- struct scatterlist *dst,
- struct scatterlist *src, unsigned int nbytes)
-{
- struct crypt_s390_des3_128_ctx *sctx = crypto_blkcipher_ctx(desc->tfm);
- struct blkcipher_walk walk;
-
- blkcipher_walk_init(&walk, dst, src, nbytes);
- return ecb_desall_crypt(desc, KM_TDEA_128_DECRYPT, sctx->key, &walk);
-}
-
-static struct crypto_alg ecb_des3_128_alg = {
- .cra_name = "ecb(des3_ede128)",
- .cra_driver_name = "ecb-des3_ede128-s390",
- .cra_priority = CRYPT_S390_COMPOSITE_PRIORITY,
- .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER,
- .cra_blocksize = DES3_128_BLOCK_SIZE,
- .cra_ctxsize = sizeof(struct crypt_s390_des3_128_ctx),
- .cra_type = &crypto_blkcipher_type,
- .cra_module = THIS_MODULE,
- .cra_list = LIST_HEAD_INIT(
- ecb_des3_128_alg.cra_list),
- .cra_u = {
- .blkcipher = {
- .min_keysize = DES3_128_KEY_SIZE,
- .max_keysize = DES3_128_KEY_SIZE,
- .setkey = des3_128_setkey,
- .encrypt = ecb_des3_128_encrypt,
- .decrypt = ecb_des3_128_decrypt,
- }
- }
-};
-
-static int cbc_des3_128_encrypt(struct blkcipher_desc *desc,
- struct scatterlist *dst,
- struct scatterlist *src, unsigned int nbytes)
-{
- struct crypt_s390_des3_128_ctx *sctx = crypto_blkcipher_ctx(desc->tfm);
- struct blkcipher_walk walk;
-
- blkcipher_walk_init(&walk, dst, src, nbytes);
- return cbc_desall_crypt(desc, KMC_TDEA_128_ENCRYPT, sctx->iv, &walk);
-}
-
-static int cbc_des3_128_decrypt(struct blkcipher_desc *desc,
- struct scatterlist *dst,
- struct scatterlist *src, unsigned int nbytes)
-{
- struct crypt_s390_des3_128_ctx *sctx = crypto_blkcipher_ctx(desc->tfm);
- struct blkcipher_walk walk;
-
- blkcipher_walk_init(&walk, dst, src, nbytes);
- return cbc_desall_crypt(desc, KMC_TDEA_128_DECRYPT, sctx->iv, &walk);
-}
-
-static struct crypto_alg cbc_des3_128_alg = {
- .cra_name = "cbc(des3_ede128)",
- .cra_driver_name = "cbc-des3_ede128-s390",
- .cra_priority = CRYPT_S390_COMPOSITE_PRIORITY,
- .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER,
- .cra_blocksize = DES3_128_BLOCK_SIZE,
- .cra_ctxsize = sizeof(struct crypt_s390_des3_128_ctx),
- .cra_type = &crypto_blkcipher_type,
- .cra_module = THIS_MODULE,
- .cra_list = LIST_HEAD_INIT(
- cbc_des3_128_alg.cra_list),
- .cra_u = {
- .blkcipher = {
- .min_keysize = DES3_128_KEY_SIZE,
- .max_keysize = DES3_128_KEY_SIZE,
- .ivsize = DES3_128_BLOCK_SIZE,
- .setkey = des3_128_setkey,
- .encrypt = cbc_des3_128_encrypt,
- .decrypt = cbc_des3_128_decrypt,
- }
- }
-};
-
-/*
- * RFC2451:
- *
- * For DES-EDE3, there is no known need to reject weak or
- * complementation keys. Any weakness is obviated by the use of
- * multiple keys.
- *
* However, if the first two or last two independent 64-bit keys are
* equal (k1 == k2 or k2 == k3), then the DES3 operation is simply the
* same as DES. Implementers MUST reject keys that exhibit this
@@ -405,9 +238,7 @@ static struct crypto_alg cbc_des3_128_alg = {
static int des3_192_setkey(struct crypto_tfm *tfm, const u8 *key,
unsigned int keylen)
{
- int i, ret;
struct crypt_s390_des3_192_ctx *dctx = crypto_tfm_ctx(tfm);
- const u8 *temp_key = key;
u32 *flags = &tfm->crt_flags;
if (!(memcmp(key, &key[DES_KEY_SIZE], DES_KEY_SIZE) &&
@@ -417,11 +248,6 @@ static int des3_192_setkey(struct crypto_tfm *tfm, const u8 *key,
*flags |= CRYPTO_TFM_RES_WEAK_KEY;
return -EINVAL;
}
- for (i = 0; i < 3; i++, temp_key += DES_KEY_SIZE) {
- ret = crypto_des_check_key(temp_key, DES_KEY_SIZE, flags);
- if (ret < 0)
- return ret;
- }
memcpy(dctx->key, key, keylen);
return 0;
}
@@ -431,7 +257,7 @@ static void des3_192_encrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
struct crypt_s390_des3_192_ctx *dctx = crypto_tfm_ctx(tfm);
crypt_s390_km(KM_TDEA_192_ENCRYPT, dctx->key, dst, (void*)src,
- DES3_192_BLOCK_SIZE);
+ DES_BLOCK_SIZE);
}
static void des3_192_decrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
@@ -439,7 +265,7 @@ static void des3_192_decrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
struct crypt_s390_des3_192_ctx *dctx = crypto_tfm_ctx(tfm);
crypt_s390_km(KM_TDEA_192_DECRYPT, dctx->key, dst, (void*)src,
- DES3_192_BLOCK_SIZE);
+ DES_BLOCK_SIZE);
}
static struct crypto_alg des3_192_alg = {
@@ -447,7 +273,7 @@ static struct crypto_alg des3_192_alg = {
.cra_driver_name = "des3_ede-s390",
.cra_priority = CRYPT_S390_PRIORITY,
.cra_flags = CRYPTO_ALG_TYPE_CIPHER,
- .cra_blocksize = DES3_192_BLOCK_SIZE,
+ .cra_blocksize = DES_BLOCK_SIZE,
.cra_ctxsize = sizeof(struct crypt_s390_des3_192_ctx),
.cra_module = THIS_MODULE,
.cra_list = LIST_HEAD_INIT(des3_192_alg.cra_list),
@@ -489,7 +315,7 @@ static struct crypto_alg ecb_des3_192_alg = {
.cra_driver_name = "ecb-des3_ede-s390",
.cra_priority = CRYPT_S390_COMPOSITE_PRIORITY,
.cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER,
- .cra_blocksize = DES3_192_BLOCK_SIZE,
+ .cra_blocksize = DES_BLOCK_SIZE,
.cra_ctxsize = sizeof(struct crypt_s390_des3_192_ctx),
.cra_type = &crypto_blkcipher_type,
.cra_module = THIS_MODULE,
@@ -533,7 +359,7 @@ static struct crypto_alg cbc_des3_192_alg = {
.cra_driver_name = "cbc-des3_ede-s390",
.cra_priority = CRYPT_S390_COMPOSITE_PRIORITY,
.cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER,
- .cra_blocksize = DES3_192_BLOCK_SIZE,
+ .cra_blocksize = DES_BLOCK_SIZE,
.cra_ctxsize = sizeof(struct crypt_s390_des3_192_ctx),
.cra_type = &crypto_blkcipher_type,
.cra_module = THIS_MODULE,
@@ -543,7 +369,7 @@ static struct crypto_alg cbc_des3_192_alg = {
.blkcipher = {
.min_keysize = DES3_192_KEY_SIZE,
.max_keysize = DES3_192_KEY_SIZE,
- .ivsize = DES3_192_BLOCK_SIZE,
+ .ivsize = DES_BLOCK_SIZE,
.setkey = des3_192_setkey,
.encrypt = cbc_des3_192_encrypt,
.decrypt = cbc_des3_192_decrypt,
@@ -553,10 +379,9 @@ static struct crypto_alg cbc_des3_192_alg = {
static int des_s390_init(void)
{
- int ret = 0;
+ int ret;
if (!crypt_s390_func_available(KM_DEA_ENCRYPT) ||
- !crypt_s390_func_available(KM_TDEA_128_ENCRYPT) ||
!crypt_s390_func_available(KM_TDEA_192_ENCRYPT))
return -EOPNOTSUPP;
@@ -569,17 +394,6 @@ static int des_s390_init(void)
ret = crypto_register_alg(&cbc_des_alg);
if (ret)
goto cbc_des_err;
-
- ret = crypto_register_alg(&des3_128_alg);
- if (ret)
- goto des3_128_err;
- ret = crypto_register_alg(&ecb_des3_128_alg);
- if (ret)
- goto ecb_des3_128_err;
- ret = crypto_register_alg(&cbc_des3_128_alg);
- if (ret)
- goto cbc_des3_128_err;
-
ret = crypto_register_alg(&des3_192_alg);
if (ret)
goto des3_192_err;
@@ -589,7 +403,6 @@ static int des_s390_init(void)
ret = crypto_register_alg(&cbc_des3_192_alg);
if (ret)
goto cbc_des3_192_err;
-
out:
return ret;
@@ -598,12 +411,6 @@ cbc_des3_192_err:
ecb_des3_192_err:
crypto_unregister_alg(&des3_192_alg);
des3_192_err:
- crypto_unregister_alg(&cbc_des3_128_alg);
-cbc_des3_128_err:
- crypto_unregister_alg(&ecb_des3_128_alg);
-ecb_des3_128_err:
- crypto_unregister_alg(&des3_128_alg);
-des3_128_err:
crypto_unregister_alg(&cbc_des_alg);
cbc_des_err:
crypto_unregister_alg(&ecb_des_alg);
@@ -613,21 +420,18 @@ des_err:
goto out;
}
-static void __exit des_s390_fini(void)
+static void __exit des_s390_exit(void)
{
crypto_unregister_alg(&cbc_des3_192_alg);
crypto_unregister_alg(&ecb_des3_192_alg);
crypto_unregister_alg(&des3_192_alg);
- crypto_unregister_alg(&cbc_des3_128_alg);
- crypto_unregister_alg(&ecb_des3_128_alg);
- crypto_unregister_alg(&des3_128_alg);
crypto_unregister_alg(&cbc_des_alg);
crypto_unregister_alg(&ecb_des_alg);
crypto_unregister_alg(&des_alg);
}
module_init(des_s390_init);
-module_exit(des_s390_fini);
+module_exit(des_s390_exit);
MODULE_ALIAS("des");
MODULE_ALIAS("des3_ede");
diff --git a/arch/s390/include/asm/kvm_host.h b/arch/s390/include/asm/kvm_host.h
index 27605b62b98..cef7dbf69df 100644
--- a/arch/s390/include/asm/kvm_host.h
+++ b/arch/s390/include/asm/kvm_host.h
@@ -26,7 +26,7 @@
struct sca_entry {
atomic_t scn;
- __u64 reserved;
+ __u32 reserved;
__u64 sda;
__u64 reserved2[2];
} __attribute__((packed));
@@ -41,7 +41,8 @@ struct sca_block {
} __attribute__((packed));
#define KVM_NR_PAGE_SIZES 2
-#define KVM_HPAGE_SHIFT(x) (PAGE_SHIFT + ((x) - 1) * 8)
+#define KVM_HPAGE_GFN_SHIFT(x) (((x) - 1) * 8)
+#define KVM_HPAGE_SHIFT(x) (PAGE_SHIFT + KVM_HPAGE_GFN_SHIFT(x))
#define KVM_HPAGE_SIZE(x) (1UL << KVM_HPAGE_SHIFT(x))
#define KVM_HPAGE_MASK(x) (~(KVM_HPAGE_SIZE(x) - 1))
#define KVM_PAGES_PER_HPAGE(x) (KVM_HPAGE_SIZE(x) / PAGE_SIZE)
diff --git a/arch/s390/include/asm/local64.h b/arch/s390/include/asm/local64.h
new file mode 100644
index 00000000000..36c93b5cc23
--- /dev/null
+++ b/arch/s390/include/asm/local64.h
@@ -0,0 +1 @@
+#include <asm-generic/local64.h>
diff --git a/arch/s390/include/asm/qdio.h b/arch/s390/include/asm/qdio.h
index 0eaae626027..2ba63027629 100644
--- a/arch/s390/include/asm/qdio.h
+++ b/arch/s390/include/asm/qdio.h
@@ -84,6 +84,7 @@ struct qdr {
#define QIB_AC_OUTBOUND_PCI_SUPPORTED 0x40
#define QIB_RFLAGS_ENABLE_QEBSM 0x80
+#define QIB_RFLAGS_ENABLE_DATA_DIV 0x02
/**
* struct qib - queue information block (QIB)
@@ -284,6 +285,9 @@ struct slsb {
u8 val[QDIO_MAX_BUFFERS_PER_Q];
} __attribute__ ((packed, aligned(256)));
+#define CHSC_AC2_DATA_DIV_AVAILABLE 0x0010
+#define CHSC_AC2_DATA_DIV_ENABLED 0x0002
+
struct qdio_ssqd_desc {
u8 flags;
u8:8;
@@ -332,6 +336,7 @@ typedef void qdio_handler_t(struct ccw_device *, unsigned int, int,
* @adapter_name: name for the adapter
* @qib_param_field_format: format for qib_parm_field
* @qib_param_field: pointer to 128 bytes or NULL, if no param field
+ * @qib_rflags: rflags to set
* @input_slib_elements: pointer to no_input_qs * 128 words of data or NULL
* @output_slib_elements: pointer to no_output_qs * 128 words of data or NULL
* @no_input_qs: number of input queues
@@ -348,6 +353,7 @@ struct qdio_initialize {
unsigned char adapter_name[8];
unsigned int qib_param_field_format;
unsigned char *qib_param_field;
+ unsigned char qib_rflags;
unsigned long *input_slib_elements;
unsigned long *output_slib_elements;
unsigned int no_input_qs;
diff --git a/arch/s390/kernel/time.c b/arch/s390/kernel/time.c
index 15a7536452d..2896cac9c14 100644
--- a/arch/s390/kernel/time.c
+++ b/arch/s390/kernel/time.c
@@ -207,8 +207,8 @@ struct clocksource * __init clocksource_default_clock(void)
return &clocksource_tod;
}
-void update_vsyscall(struct timespec *wall_time, struct clocksource *clock,
- u32 mult)
+void update_vsyscall(struct timespec *wall_time, struct timespec *wtm,
+ struct clocksource *clock, u32 mult)
{
if (clock != &clocksource_tod)
return;
@@ -219,8 +219,8 @@ void update_vsyscall(struct timespec *wall_time, struct clocksource *clock,
vdso_data->xtime_tod_stamp = clock->cycle_last;
vdso_data->xtime_clock_sec = wall_time->tv_sec;
vdso_data->xtime_clock_nsec = wall_time->tv_nsec;
- vdso_data->wtom_clock_sec = wall_to_monotonic.tv_sec;
- vdso_data->wtom_clock_nsec = wall_to_monotonic.tv_nsec;
+ vdso_data->wtom_clock_sec = wtm->tv_sec;
+ vdso_data->wtom_clock_nsec = wtm->tv_nsec;
vdso_data->ntp_mult = mult;
smp_wmb();
++vdso_data->tb_update_count;
diff --git a/arch/s390/kvm/intercept.c b/arch/s390/kvm/intercept.c
index 3ddc30895e3..f7b6df45d8b 100644
--- a/arch/s390/kvm/intercept.c
+++ b/arch/s390/kvm/intercept.c
@@ -135,7 +135,7 @@ static int handle_stop(struct kvm_vcpu *vcpu)
spin_lock_bh(&vcpu->arch.local_int.lock);
if (vcpu->arch.local_int.action_bits & ACTION_STORE_ON_STOP) {
vcpu->arch.local_int.action_bits &= ~ACTION_STORE_ON_STOP;
- rc = __kvm_s390_vcpu_store_status(vcpu,
+ rc = kvm_s390_vcpu_store_status(vcpu,
KVM_S390_STORE_STATUS_NOADDR);
if (rc >= 0)
rc = -EOPNOTSUPP;
diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c
index ae370581687..4fe68650535 100644
--- a/arch/s390/kvm/kvm-s390.c
+++ b/arch/s390/kvm/kvm-s390.c
@@ -207,6 +207,7 @@ out_nokvm:
void kvm_arch_vcpu_destroy(struct kvm_vcpu *vcpu)
{
VCPU_EVENT(vcpu, 3, "%s", "free cpu");
+ clear_bit(63 - vcpu->vcpu_id, (unsigned long *) &vcpu->kvm->arch.sca->mcn);
if (vcpu->kvm->arch.sca->cpu[vcpu->vcpu_id].sda ==
(__u64) vcpu->arch.sie_block)
vcpu->kvm->arch.sca->cpu[vcpu->vcpu_id].sda = 0;
@@ -296,7 +297,7 @@ int kvm_arch_vcpu_setup(struct kvm_vcpu *vcpu)
{
atomic_set(&vcpu->arch.sie_block->cpuflags, CPUSTAT_ZARCH);
set_bit(KVM_REQ_MMU_RELOAD, &vcpu->requests);
- vcpu->arch.sie_block->ecb = 2;
+ vcpu->arch.sie_block->ecb = 6;
vcpu->arch.sie_block->eca = 0xC1002001U;
vcpu->arch.sie_block->fac = (int) (long) facilities;
hrtimer_init(&vcpu->arch.ckc_timer, CLOCK_REALTIME, HRTIMER_MODE_ABS);
@@ -329,6 +330,7 @@ struct kvm_vcpu *kvm_arch_vcpu_create(struct kvm *kvm,
kvm->arch.sca->cpu[id].sda = (__u64) vcpu->arch.sie_block;
vcpu->arch.sie_block->scaoh = (__u32)(((__u64)kvm->arch.sca) >> 32);
vcpu->arch.sie_block->scaol = (__u32)(__u64)kvm->arch.sca;
+ set_bit(63 - id, (unsigned long *) &kvm->arch.sca->mcn);
spin_lock_init(&vcpu->arch.local_int.lock);
INIT_LIST_HEAD(&vcpu->arch.local_int.list);
@@ -363,63 +365,49 @@ int kvm_arch_vcpu_runnable(struct kvm_vcpu *vcpu)
static int kvm_arch_vcpu_ioctl_initial_reset(struct kvm_vcpu *vcpu)
{
- vcpu_load(vcpu);
kvm_s390_vcpu_initial_reset(vcpu);
- vcpu_put(vcpu);
return 0;
}
int kvm_arch_vcpu_ioctl_set_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
{
- vcpu_load(vcpu);
memcpy(&vcpu->arch.guest_gprs, &regs->gprs, sizeof(regs->gprs));
- vcpu_put(vcpu);
return 0;
}
int kvm_arch_vcpu_ioctl_get_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
{
- vcpu_load(vcpu);
memcpy(&regs->gprs, &vcpu->arch.guest_gprs, sizeof(regs->gprs));
- vcpu_put(vcpu);
return 0;
}
int kvm_arch_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu,
struct kvm_sregs *sregs)
{
- vcpu_load(vcpu);
memcpy(&vcpu->arch.guest_acrs, &sregs->acrs, sizeof(sregs->acrs));
memcpy(&vcpu->arch.sie_block->gcr, &sregs->crs, sizeof(sregs->crs));
- vcpu_put(vcpu);
return 0;
}
int kvm_arch_vcpu_ioctl_get_sregs(struct kvm_vcpu *vcpu,
struct kvm_sregs *sregs)
{
- vcpu_load(vcpu);
memcpy(&sregs->acrs, &vcpu->arch.guest_acrs, sizeof(sregs->acrs));
memcpy(&sregs->crs, &vcpu->arch.sie_block->gcr, sizeof(sregs->crs));
- vcpu_put(vcpu);
return 0;
}
int kvm_arch_vcpu_ioctl_set_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu)
{
- vcpu_load(vcpu);
memcpy(&vcpu->arch.guest_fpregs.fprs, &fpu->fprs, sizeof(fpu->fprs));
vcpu->arch.guest_fpregs.fpc = fpu->fpc;
- vcpu_put(vcpu);
return 0;
}
int kvm_arch_vcpu_ioctl_get_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu)
{
- vcpu_load(vcpu);
memcpy(&fpu->fprs, &vcpu->arch.guest_fpregs.fprs, sizeof(fpu->fprs));
fpu->fpc = vcpu->arch.guest_fpregs.fpc;
- vcpu_put(vcpu);
return 0;
}
@@ -427,14 +415,12 @@ static int kvm_arch_vcpu_ioctl_set_initial_psw(struct kvm_vcpu *vcpu, psw_t psw)
{
int rc = 0;
- vcpu_load(vcpu);
if (atomic_read(&vcpu->arch.sie_block->cpuflags) & CPUSTAT_RUNNING)
rc = -EBUSY;
else {
vcpu->run->psw_mask = psw.mask;
vcpu->run->psw_addr = psw.addr;
}
- vcpu_put(vcpu);
return rc;
}
@@ -498,8 +484,6 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
int rc;
sigset_t sigsaved;
- vcpu_load(vcpu);
-
rerun_vcpu:
if (vcpu->requests)
if (test_and_clear_bit(KVM_REQ_MMU_RELOAD, &vcpu->requests))
@@ -568,8 +552,6 @@ rerun_vcpu:
if (vcpu->sigset_active)
sigprocmask(SIG_SETMASK, &sigsaved, NULL);
- vcpu_put(vcpu);
-
vcpu->stat.exit_userspace++;
return rc;
}
@@ -589,7 +571,7 @@ static int __guestcopy(struct kvm_vcpu *vcpu, u64 guestdest, const void *from,
* KVM_S390_STORE_STATUS_NOADDR: -> 0x1200 on 64 bit
* KVM_S390_STORE_STATUS_PREFIXED: -> prefix
*/
-int __kvm_s390_vcpu_store_status(struct kvm_vcpu *vcpu, unsigned long addr)
+int kvm_s390_vcpu_store_status(struct kvm_vcpu *vcpu, unsigned long addr)
{
const unsigned char archmode = 1;
int prefix;
@@ -651,45 +633,42 @@ int __kvm_s390_vcpu_store_status(struct kvm_vcpu *vcpu, unsigned long addr)
return 0;
}
-static int kvm_s390_vcpu_store_status(struct kvm_vcpu *vcpu, unsigned long addr)
-{
- int rc;
-
- vcpu_load(vcpu);
- rc = __kvm_s390_vcpu_store_status(vcpu, addr);
- vcpu_put(vcpu);
- return rc;
-}
-
long kvm_arch_vcpu_ioctl(struct file *filp,
unsigned int ioctl, unsigned long arg)
{
struct kvm_vcpu *vcpu = filp->private_data;
void __user *argp = (void __user *)arg;
+ long r;
switch (ioctl) {
case KVM_S390_INTERRUPT: {
struct kvm_s390_interrupt s390int;
+ r = -EFAULT;
if (copy_from_user(&s390int, argp, sizeof(s390int)))
- return -EFAULT;
- return kvm_s390_inject_vcpu(vcpu, &s390int);
+ break;
+ r = kvm_s390_inject_vcpu(vcpu, &s390int);
+ break;
}
case KVM_S390_STORE_STATUS:
- return kvm_s390_vcpu_store_status(vcpu, arg);
+ r = kvm_s390_vcpu_store_status(vcpu, arg);
+ break;
case KVM_S390_SET_INITIAL_PSW: {
psw_t psw;
+ r = -EFAULT;
if (copy_from_user(&psw, argp, sizeof(psw)))
- return -EFAULT;
- return kvm_arch_vcpu_ioctl_set_initial_psw(vcpu, psw);
+ break;
+ r = kvm_arch_vcpu_ioctl_set_initial_psw(vcpu, psw);
+ break;
}
case KVM_S390_INITIAL_RESET:
- return kvm_arch_vcpu_ioctl_initial_reset(vcpu);
+ r = kvm_arch_vcpu_ioctl_initial_reset(vcpu);
+ break;
default:
- ;
+ r = -EINVAL;
}
- return -EINVAL;
+ return r;
}
/* Section: memory related */
@@ -744,11 +723,6 @@ void kvm_arch_flush_shadow(struct kvm *kvm)
{
}
-gfn_t unalias_gfn(struct kvm *kvm, gfn_t gfn)
-{
- return gfn;
-}
-
static int __init kvm_s390_init(void)
{
int ret;
diff --git a/arch/s390/kvm/kvm-s390.h b/arch/s390/kvm/kvm-s390.h
index cfa9d177745..a7b7586626d 100644
--- a/arch/s390/kvm/kvm-s390.h
+++ b/arch/s390/kvm/kvm-s390.h
@@ -92,7 +92,7 @@ int kvm_s390_handle_b2(struct kvm_vcpu *vcpu);
int kvm_s390_handle_sigp(struct kvm_vcpu *vcpu);
/* implemented in kvm-s390.c */
-int __kvm_s390_vcpu_store_status(struct kvm_vcpu *vcpu,
+int kvm_s390_vcpu_store_status(struct kvm_vcpu *vcpu,
unsigned long addr);
/* implemented in diag.c */
int kvm_s390_handle_diag(struct kvm_vcpu *vcpu);
diff --git a/arch/score/Kconfig b/arch/score/Kconfig
index 55d413e6dcf..be4a1558475 100644
--- a/arch/score/Kconfig
+++ b/arch/score/Kconfig
@@ -55,9 +55,6 @@ config GENERIC_CALIBRATE_DELAY
config GENERIC_CLOCKEVENTS
def_bool y
-config GENERIC_TIME
- def_bool y
-
config SCHED_NO_NO_OMIT_FRAME_POINTER
def_bool y
diff --git a/arch/score/Makefile b/arch/score/Makefile
index 68e0cd06d5c..d77dc639d8e 100644
--- a/arch/score/Makefile
+++ b/arch/score/Makefile
@@ -20,7 +20,8 @@ cflags-y += -G0 -pipe -mel -mnhwloop -D__SCOREEL__ \
#
KBUILD_AFLAGS += $(cflags-y)
KBUILD_CFLAGS += $(cflags-y)
-MODFLAGS += -mlong-calls
+KBUILD_AFLAGS_MODULE += -mlong-calls
+KBUILD_CFLAGS_MODULE += -mlong-calls
LDFLAGS += --oformat elf32-littlescore
LDFLAGS_vmlinux += -G0 -static -nostdlib
diff --git a/arch/score/include/asm/local64.h b/arch/score/include/asm/local64.h
new file mode 100644
index 00000000000..36c93b5cc23
--- /dev/null
+++ b/arch/score/include/asm/local64.h
@@ -0,0 +1 @@
+#include <asm-generic/local64.h>
diff --git a/arch/sh/Kconfig b/arch/sh/Kconfig
index 82868fee21f..33990fa95af 100644
--- a/arch/sh/Kconfig
+++ b/arch/sh/Kconfig
@@ -98,9 +98,6 @@ config GENERIC_CALIBRATE_DELAY
config GENERIC_IOMAP
bool
-config GENERIC_TIME
- def_bool y
-
config GENERIC_CLOCKEVENTS
def_bool y
diff --git a/arch/sh/boards/mach-ap325rxa/setup.c b/arch/sh/boards/mach-ap325rxa/setup.c
index 3a170bd3f3d..de375b64e41 100644
--- a/arch/sh/boards/mach-ap325rxa/setup.c
+++ b/arch/sh/boards/mach-ap325rxa/setup.c
@@ -316,7 +316,7 @@ static struct soc_camera_platform_info camera_info = {
.format_name = "UYVY",
.format_depth = 16,
.format = {
- .code = V4L2_MBUS_FMT_YUYV8_2X8_BE,
+ .code = V4L2_MBUS_FMT_UYVY8_2X8,
.colorspace = V4L2_COLORSPACE_SMPTE170M,
.field = V4L2_FIELD_NONE,
.width = 640,
diff --git a/arch/sh/include/asm/local64.h b/arch/sh/include/asm/local64.h
new file mode 100644
index 00000000000..36c93b5cc23
--- /dev/null
+++ b/arch/sh/include/asm/local64.h
@@ -0,0 +1 @@
+#include <asm-generic/local64.h>
diff --git a/arch/sh/kernel/clkdev.c b/arch/sh/kernel/clkdev.c
index defdd6e3090..befc255830a 100644
--- a/arch/sh/kernel/clkdev.c
+++ b/arch/sh/kernel/clkdev.c
@@ -36,7 +36,7 @@ static DEFINE_MUTEX(clocks_mutex);
* If an entry has a device ID, it must match
* If an entry has a connection ID, it must match
* Then we take the most specific entry - with the following
- * order of precidence: dev+con > dev only > con only.
+ * order of precedence: dev+con > dev only > con only.
*/
static struct clk *clk_find(const char *dev_id, const char *con_id)
{
diff --git a/arch/sh/kernel/perf_event.c b/arch/sh/kernel/perf_event.c
index 81b6de41ae5..7a3dc356725 100644
--- a/arch/sh/kernel/perf_event.c
+++ b/arch/sh/kernel/perf_event.c
@@ -185,10 +185,10 @@ static void sh_perf_event_update(struct perf_event *event,
* this is the simplest approach for maintaining consistency.
*/
again:
- prev_raw_count = atomic64_read(&hwc->prev_count);
+ prev_raw_count = local64_read(&hwc->prev_count);
new_raw_count = sh_pmu->read(idx);
- if (atomic64_cmpxchg(&hwc->prev_count, prev_raw_count,
+ if (local64_cmpxchg(&hwc->prev_count, prev_raw_count,
new_raw_count) != prev_raw_count)
goto again;
@@ -203,7 +203,7 @@ again:
delta = (new_raw_count << shift) - (prev_raw_count << shift);
delta >>= shift;
- atomic64_add(delta, &event->count);
+ local64_add(delta, &event->count);
}
static void sh_pmu_disable(struct perf_event *event)
diff --git a/arch/sparc/Kconfig b/arch/sparc/Kconfig
index c0015db247b..491e9d6de19 100644
--- a/arch/sparc/Kconfig
+++ b/arch/sparc/Kconfig
@@ -18,6 +18,7 @@ config 64BIT
config SPARC
bool
default y
+ select OF
select HAVE_IDE
select HAVE_OPROFILE
select HAVE_ARCH_KGDB if !SMP || SPARC64
@@ -66,9 +67,6 @@ config BITS
default 32 if SPARC32
default 64 if SPARC64
-config GENERIC_TIME
- def_bool y
-
config ARCH_USES_GETTIMEOFFSET
bool
default y if SPARC32
@@ -148,9 +146,6 @@ config GENERIC_GPIO
config ARCH_NO_VIRT_TO_BUS
def_bool y
-config OF
- def_bool y
-
config ARCH_SUPPORTS_DEBUG_PAGEALLOC
def_bool y if SPARC64
diff --git a/arch/sparc/boot/btfixupprep.c b/arch/sparc/boot/btfixupprep.c
index e7f2940bd27..da031159e2b 100644
--- a/arch/sparc/boot/btfixupprep.c
+++ b/arch/sparc/boot/btfixupprep.c
@@ -216,7 +216,7 @@ main1:
switch (buffer[nbase+3]) {
case 'f':
if (initval) {
- fprintf(stderr, "Cannot use pre-initalized fixups for calls\n%s\n", buffer);
+ fprintf(stderr, "Cannot use pre-initialized fixups for calls\n%s\n", buffer);
exit(1);
}
if (!strcmp (sect, "__ksymtab")) {
@@ -273,7 +273,7 @@ main1:
break;
case 'i':
if (initval) {
- fprintf(stderr, "Cannot use pre-initalized fixups for INT\n%s\n", buffer);
+ fprintf(stderr, "Cannot use pre-initialized fixups for INT\n%s\n", buffer);
exit(1);
}
if (strncmp (buffer + mode+9, "HI22 ", 10) && strncmp (buffer + mode+9, "LO10 ", 10)) {
diff --git a/arch/sparc/include/asm/device.h b/arch/sparc/include/asm/device.h
index d4c45214741..daa6a8a5e9c 100644
--- a/arch/sparc/include/asm/device.h
+++ b/arch/sparc/include/asm/device.h
@@ -6,18 +6,25 @@
#ifndef _ASM_SPARC_DEVICE_H
#define _ASM_SPARC_DEVICE_H
+#include <asm/openprom.h>
+
struct device_node;
-struct of_device;
+struct platform_device;
struct dev_archdata {
void *iommu;
void *stc;
void *host_controller;
- struct of_device *op;
+ struct platform_device *op;
int numa_node;
};
+extern void of_propagate_archdata(struct platform_device *bus);
+
struct pdev_archdata {
+ struct resource resource[PROMREG_MAX];
+ unsigned int irqs[PROMINTR_MAX];
+ int num_irqs;
};
#endif /* _ASM_SPARC_DEVICE_H */
diff --git a/arch/sparc/include/asm/floppy_64.h b/arch/sparc/include/asm/floppy_64.h
index 8fac3ab22f3..6597ce874d7 100644
--- a/arch/sparc/include/asm/floppy_64.h
+++ b/arch/sparc/include/asm/floppy_64.h
@@ -43,7 +43,7 @@ struct sun_flpy_controller {
/* You'll only ever find one controller on an Ultra anyways. */
static struct sun_flpy_controller *sun_fdc = (struct sun_flpy_controller *)-1;
unsigned long fdc_status;
-static struct of_device *floppy_op = NULL;
+static struct platform_device *floppy_op = NULL;
struct sun_floppy_ops {
unsigned char (*fd_inb) (unsigned long port);
@@ -548,7 +548,7 @@ static unsigned long __init sun_floppy_init(void)
{
static int initialized = 0;
struct device_node *dp;
- struct of_device *op;
+ struct platform_device *op;
const char *prop;
char state[128];
@@ -567,7 +567,7 @@ static unsigned long __init sun_floppy_init(void)
}
if (op) {
floppy_op = op;
- FLOPPY_IRQ = op->irqs[0];
+ FLOPPY_IRQ = op->archdata.irqs[0];
} else {
struct device_node *ebus_dp;
void __iomem *auxio_reg;
@@ -593,7 +593,7 @@ static unsigned long __init sun_floppy_init(void)
if (state_prop && !strncmp(state_prop, "disabled", 8))
return 0;
- FLOPPY_IRQ = op->irqs[0];
+ FLOPPY_IRQ = op->archdata.irqs[0];
/* Make sure the high density bit is set, some systems
* (most notably Ultra5/Ultra10) come up with it clear.
@@ -661,7 +661,7 @@ static unsigned long __init sun_floppy_init(void)
config = 0;
for (dp = ebus_dp->child; dp; dp = dp->sibling) {
if (!strcmp(dp->name, "ecpp")) {
- struct of_device *ecpp_op;
+ struct platform_device *ecpp_op;
ecpp_op = of_find_device_by_node(dp);
if (ecpp_op)
diff --git a/arch/sparc/include/asm/local64.h b/arch/sparc/include/asm/local64.h
new file mode 100644
index 00000000000..36c93b5cc23
--- /dev/null
+++ b/arch/sparc/include/asm/local64.h
@@ -0,0 +1 @@
+#include <asm-generic/local64.h>
diff --git a/arch/sparc/include/asm/of_device.h b/arch/sparc/include/asm/of_device.h
deleted file mode 100644
index f320246a058..00000000000
--- a/arch/sparc/include/asm/of_device.h
+++ /dev/null
@@ -1,38 +0,0 @@
-#ifndef _ASM_SPARC_OF_DEVICE_H
-#define _ASM_SPARC_OF_DEVICE_H
-#ifdef __KERNEL__
-
-#include <linux/device.h>
-#include <linux/of.h>
-#include <linux/mod_devicetable.h>
-#include <asm/openprom.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.
- */
-struct of_device
-{
- struct device dev;
- struct resource resource[PROMREG_MAX];
- unsigned int irqs[PROMINTR_MAX];
- int num_irqs;
-
- void *sysdata;
-
- int slot;
- int portid;
- int clock_freq;
-};
-
-extern void __iomem *of_ioremap(struct resource *res, unsigned long offset, unsigned long size, char *name);
-extern void of_iounmap(struct resource *res, void __iomem *base, unsigned long size);
-
-extern void of_propagate_archdata(struct of_device *bus);
-
-/* This is just here during the transition */
-#include <linux/of_platform.h>
-
-#endif /* __KERNEL__ */
-#endif /* _ASM_SPARC_OF_DEVICE_H */
diff --git a/arch/sparc/include/asm/of_platform.h b/arch/sparc/include/asm/of_platform.h
deleted file mode 100644
index 90da99059f8..00000000000
--- a/arch/sparc/include/asm/of_platform.h
+++ /dev/null
@@ -1,18 +0,0 @@
-#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/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.
- *
- */
-
-#define of_bus_type of_platform_bus_type /* for compatibility */
-
-#endif
diff --git a/arch/sparc/include/asm/parport.h b/arch/sparc/include/asm/parport.h
index c333b8d0949..4f7afa01b2a 100644
--- a/arch/sparc/include/asm/parport.h
+++ b/arch/sparc/include/asm/parport.h
@@ -103,7 +103,7 @@ static inline unsigned int get_dma_residue(unsigned int dmanr)
return ebus_dma_residue(&sparc_ebus_dmas[dmanr].info);
}
-static int __devinit ecpp_probe(struct of_device *op, const struct of_device_id *match)
+static int __devinit ecpp_probe(struct platform_device *op, const struct of_device_id *match)
{
unsigned long base = op->resource[0].start;
unsigned long config = op->resource[1].start;
@@ -116,7 +116,7 @@ static int __devinit ecpp_probe(struct of_device *op, const struct of_device_id
parent = op->dev.of_node->parent;
if (!strcmp(parent->name, "dma")) {
p = parport_pc_probe_port(base, base + 0x400,
- op->irqs[0], PARPORT_DMA_NOFIFO,
+ op->archdata.irqs[0], PARPORT_DMA_NOFIFO,
op->dev.parent->parent, 0);
if (!p)
return -ENOMEM;
@@ -166,7 +166,7 @@ static int __devinit ecpp_probe(struct of_device *op, const struct of_device_id
0, PTR_LPT_REG_DIR);
p = parport_pc_probe_port(base, base + 0x400,
- op->irqs[0],
+ op->archdata.irqs[0],
slot,
op->dev.parent,
0);
@@ -192,7 +192,7 @@ out_err:
return err;
}
-static int __devexit ecpp_remove(struct of_device *op)
+static int __devexit ecpp_remove(struct platform_device *op)
{
struct parport *p = dev_get_drvdata(&op->dev);
int slot = p->dma;
@@ -243,9 +243,7 @@ static struct of_platform_driver ecpp_driver = {
static int parport_pc_find_nonpci_ports(int autoirq, int autodma)
{
- of_register_driver(&ecpp_driver, &of_bus_type);
-
- return 0;
+ return of_register_platform_driver(&ecpp_driver);
}
#endif /* !(_ASM_SPARC64_PARPORT_H */
diff --git a/arch/sparc/include/asm/perf_event.h b/arch/sparc/include/asm/perf_event.h
index 7e2669894ce..74c4e0cd889 100644
--- a/arch/sparc/include/asm/perf_event.h
+++ b/arch/sparc/include/asm/perf_event.h
@@ -6,7 +6,15 @@ extern void set_perf_event_pending(void);
#define PERF_EVENT_INDEX_OFFSET 0
#ifdef CONFIG_PERF_EVENTS
+#include <asm/ptrace.h>
+
extern void init_hw_perf_events(void);
+
+extern void
+__perf_arch_fetch_caller_regs(struct pt_regs *regs, unsigned long ip, int skip);
+
+#define perf_arch_fetch_caller_regs(pt_regs, ip) \
+ __perf_arch_fetch_caller_regs(pt_regs, ip, 1);
#else
static inline void init_hw_perf_events(void) { }
#endif
diff --git a/arch/sparc/include/asm/prom.h b/arch/sparc/include/asm/prom.h
index f845828ca4c..291f12575ed 100644
--- a/arch/sparc/include/asm/prom.h
+++ b/arch/sparc/include/asm/prom.h
@@ -43,20 +43,22 @@ extern int of_getintprop_default(struct device_node *np,
extern int of_find_in_proplist(const char *list, const char *match, int len);
#ifdef CONFIG_NUMA
extern int of_node_to_nid(struct device_node *dp);
-#else
-#define of_node_to_nid(dp) (-1)
+#define of_node_to_nid of_node_to_nid
#endif
extern void prom_build_devicetree(void);
extern void of_populate_present_mask(void);
extern void of_fill_in_cpu_data(void);
+struct resource;
+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);
+
/* These routines are here to provide compatibility with how powerpc
* handles IRQ mapping for OF device nodes. We precompute and permanently
- * register them in the of_device objects, whereas powerpc computes them
+ * register them in the platform_device objects, whereas powerpc computes them
* on request.
*/
-extern unsigned int irq_of_parse_and_map(struct device_node *node, int index);
static inline void irq_dispose_mapping(unsigned int virq)
{
}
diff --git a/arch/sparc/kernel/apc.c b/arch/sparc/kernel/apc.c
index b27476caa13..2c0046ecc71 100644
--- a/arch/sparc/kernel/apc.c
+++ b/arch/sparc/kernel/apc.c
@@ -68,7 +68,7 @@ static void apc_swift_idle(void)
#endif
}
-static inline void apc_free(struct of_device *op)
+static inline void apc_free(struct platform_device *op)
{
of_iounmap(&op->resource[0], regs, resource_size(&op->resource[0]));
}
@@ -136,7 +136,7 @@ static const struct file_operations apc_fops = {
static struct miscdevice apc_miscdev = { APC_MINOR, APC_DEVNAME, &apc_fops };
-static int __devinit apc_probe(struct of_device *op,
+static int __devinit apc_probe(struct platform_device *op,
const struct of_device_id *match)
{
int err;
@@ -184,7 +184,7 @@ static struct of_platform_driver apc_driver = {
static int __init apc_init(void)
{
- return of_register_driver(&apc_driver, &of_bus_type);
+ return of_register_platform_driver(&apc_driver);
}
/* This driver is not critical to the boot process
diff --git a/arch/sparc/kernel/auxio_64.c b/arch/sparc/kernel/auxio_64.c
index ddc84128b3c..3efd3c5af6a 100644
--- a/arch/sparc/kernel/auxio_64.c
+++ b/arch/sparc/kernel/auxio_64.c
@@ -102,7 +102,8 @@ static struct of_device_id __initdata auxio_match[] = {
MODULE_DEVICE_TABLE(of, auxio_match);
-static int __devinit auxio_probe(struct of_device *dev, const struct of_device_id *match)
+static int __devinit auxio_probe(struct platform_device *dev,
+ const struct of_device_id *match)
{
struct device_node *dp = dev->dev.of_node;
unsigned long size;
@@ -142,7 +143,7 @@ static struct of_platform_driver auxio_driver = {
static int __init auxio_init(void)
{
- return of_register_driver(&auxio_driver, &of_platform_bus_type);
+ return of_register_platform_driver(&auxio_driver);
}
/* Must be after subsys_initcall() so that busses are probed. Must
diff --git a/arch/sparc/kernel/central.c b/arch/sparc/kernel/central.c
index 434335f6582..cfa2624c533 100644
--- a/arch/sparc/kernel/central.c
+++ b/arch/sparc/kernel/central.c
@@ -59,7 +59,7 @@ static int __devinit clock_board_calc_nslots(struct clock_board *p)
}
}
-static int __devinit clock_board_probe(struct of_device *op,
+static int __devinit clock_board_probe(struct platform_device *op,
const struct of_device_id *match)
{
struct clock_board *p = kzalloc(sizeof(*p), GFP_KERNEL);
@@ -157,7 +157,7 @@ static struct of_platform_driver clock_board_driver = {
},
};
-static int __devinit fhc_probe(struct of_device *op,
+static int __devinit fhc_probe(struct platform_device *op,
const struct of_device_id *match)
{
struct fhc *p = kzalloc(sizeof(*p), GFP_KERNEL);
@@ -265,8 +265,8 @@ static struct of_platform_driver fhc_driver = {
static int __init sunfire_init(void)
{
- (void) of_register_driver(&fhc_driver, &of_platform_bus_type);
- (void) of_register_driver(&clock_board_driver, &of_platform_bus_type);
+ (void) of_register_platform_driver(&fhc_driver);
+ (void) of_register_platform_driver(&clock_board_driver);
return 0;
}
diff --git a/arch/sparc/kernel/chmc.c b/arch/sparc/kernel/chmc.c
index 870cb65b3f2..08c466ebb32 100644
--- a/arch/sparc/kernel/chmc.c
+++ b/arch/sparc/kernel/chmc.c
@@ -392,7 +392,7 @@ static void __devinit jbusmc_construct_dimm_groups(struct jbusmc *p,
}
}
-static int __devinit jbusmc_probe(struct of_device *op,
+static int __devinit jbusmc_probe(struct platform_device *op,
const struct of_device_id *match)
{
const struct linux_prom64_registers *mem_regs;
@@ -690,7 +690,7 @@ static void chmc_fetch_decode_regs(struct chmc *p)
chmc_read_mcreg(p, CHMCTRL_DECODE4));
}
-static int __devinit chmc_probe(struct of_device *op,
+static int __devinit chmc_probe(struct platform_device *op,
const struct of_device_id *match)
{
struct device_node *dp = op->dev.of_node;
@@ -765,7 +765,7 @@ out_free:
goto out;
}
-static int __devinit us3mc_probe(struct of_device *op,
+static int __devinit us3mc_probe(struct platform_device *op,
const struct of_device_id *match)
{
if (mc_type == MC_TYPE_SAFARI)
@@ -775,21 +775,21 @@ static int __devinit us3mc_probe(struct of_device *op,
return -ENODEV;
}
-static void __devexit chmc_destroy(struct of_device *op, struct chmc *p)
+static void __devexit chmc_destroy(struct platform_device *op, struct chmc *p)
{
list_del(&p->list);
of_iounmap(&op->resource[0], p->regs, 0x48);
kfree(p);
}
-static void __devexit jbusmc_destroy(struct of_device *op, struct jbusmc *p)
+static void __devexit jbusmc_destroy(struct platform_device *op, struct jbusmc *p)
{
mc_list_del(&p->list);
of_iounmap(&op->resource[0], p->regs, JBUSMC_REGS_SIZE);
kfree(p);
}
-static int __devexit us3mc_remove(struct of_device *op)
+static int __devexit us3mc_remove(struct platform_device *op)
{
void *p = dev_get_drvdata(&op->dev);
@@ -848,7 +848,7 @@ static int __init us3mc_init(void)
ret = register_dimm_printer(us3mc_dimm_printer);
if (!ret) {
- ret = of_register_driver(&us3mc_driver, &of_bus_type);
+ ret = of_register_platform_driver(&us3mc_driver);
if (ret)
unregister_dimm_printer(us3mc_dimm_printer);
}
@@ -859,7 +859,7 @@ static void __exit us3mc_cleanup(void)
{
if (us3mc_platform()) {
unregister_dimm_printer(us3mc_dimm_printer);
- of_unregister_driver(&us3mc_driver);
+ of_unregister_platform_driver(&us3mc_driver);
}
}
diff --git a/arch/sparc/kernel/helpers.S b/arch/sparc/kernel/helpers.S
index 92090cc9e82..682fee06a16 100644
--- a/arch/sparc/kernel/helpers.S
+++ b/arch/sparc/kernel/helpers.S
@@ -47,9 +47,9 @@ stack_trace_flush:
.size stack_trace_flush,.-stack_trace_flush
#ifdef CONFIG_PERF_EVENTS
- .globl perf_arch_fetch_caller_regs
- .type perf_arch_fetch_caller_regs,#function
-perf_arch_fetch_caller_regs:
+ .globl __perf_arch_fetch_caller_regs
+ .type __perf_arch_fetch_caller_regs,#function
+__perf_arch_fetch_caller_regs:
/* We always read the %pstate into %o5 since we will use
* that to construct a fake %tstate to store into the regs.
*/
diff --git a/arch/sparc/kernel/ioport.c b/arch/sparc/kernel/ioport.c
index 703e4aa9bc3..41f7e4e0f72 100644
--- a/arch/sparc/kernel/ioport.c
+++ b/arch/sparc/kernel/ioport.c
@@ -253,7 +253,7 @@ EXPORT_SYMBOL(sbus_set_sbus64);
static void *sbus_alloc_coherent(struct device *dev, size_t len,
dma_addr_t *dma_addrp, gfp_t gfp)
{
- struct of_device *op = to_of_device(dev);
+ struct platform_device *op = to_platform_device(dev);
unsigned long len_total = (len + PAGE_SIZE-1) & PAGE_MASK;
unsigned long va;
struct resource *res;
diff --git a/arch/sparc/kernel/of_device_32.c b/arch/sparc/kernel/of_device_32.c
index 47e63f1e719..2d055a1e9cc 100644
--- a/arch/sparc/kernel/of_device_32.c
+++ b/arch/sparc/kernel/of_device_32.c
@@ -241,10 +241,10 @@ static int __init use_1to1_mapping(struct device_node *pp)
static int of_resource_verbose;
-static void __init build_device_resources(struct of_device *op,
+static void __init build_device_resources(struct platform_device *op,
struct device *parent)
{
- struct of_device *p_op;
+ struct platform_device *p_op;
struct of_bus *bus;
int na, ns;
int index, num_reg;
@@ -253,7 +253,7 @@ static void __init build_device_resources(struct of_device *op,
if (!parent)
return;
- p_op = to_of_device(parent);
+ p_op = to_platform_device(parent);
bus = of_match_bus(p_op->dev.of_node);
bus->count_cells(op->dev.of_node, &na, &ns);
@@ -267,6 +267,8 @@ static void __init build_device_resources(struct of_device *op,
/* Conver to num-entries. */
num_reg /= na + ns;
+ op->resource = op->archdata.resource;
+ op->num_resources = num_reg;
for (index = 0; index < num_reg; index++) {
struct resource *r = &op->resource[index];
u32 addr[OF_MAX_ADDR_CELLS];
@@ -333,10 +335,10 @@ static void __init build_device_resources(struct of_device *op,
}
}
-static struct of_device * __init scan_one_device(struct device_node *dp,
+static struct platform_device * __init scan_one_device(struct device_node *dp,
struct device *parent)
{
- struct of_device *op = kzalloc(sizeof(*op), GFP_KERNEL);
+ struct platform_device *op = kzalloc(sizeof(*op), GFP_KERNEL);
const struct linux_prom_irqs *intr;
struct dev_archdata *sd;
int len, i;
@@ -349,27 +351,21 @@ static struct of_device * __init scan_one_device(struct device_node *dp,
op->dev.of_node = dp;
- op->clock_freq = of_getintprop_default(dp, "clock-frequency",
- (25*1000*1000));
- op->portid = of_getintprop_default(dp, "upa-portid", -1);
- if (op->portid == -1)
- op->portid = of_getintprop_default(dp, "portid", -1);
-
intr = of_get_property(dp, "intr", &len);
if (intr) {
- op->num_irqs = len / sizeof(struct linux_prom_irqs);
- for (i = 0; i < op->num_irqs; i++)
- op->irqs[i] = intr[i].pri;
+ op->archdata.num_irqs = len / sizeof(struct linux_prom_irqs);
+ for (i = 0; i < op->archdata.num_irqs; i++)
+ op->archdata.irqs[i] = intr[i].pri;
} else {
const unsigned int *irq =
of_get_property(dp, "interrupts", &len);
if (irq) {
- op->num_irqs = len / sizeof(unsigned int);
- for (i = 0; i < op->num_irqs; i++)
- op->irqs[i] = irq[i];
+ op->archdata.num_irqs = len / sizeof(unsigned int);
+ for (i = 0; i < op->archdata.num_irqs; i++)
+ op->archdata.irqs[i] = irq[i];
} else {
- op->num_irqs = 0;
+ op->archdata.num_irqs = 0;
}
}
if (sparc_cpu_model == sun4d) {
@@ -411,8 +407,8 @@ static struct of_device * __init scan_one_device(struct device_node *dp,
goto build_resources;
}
- for (i = 0; i < op->num_irqs; i++) {
- int this_irq = op->irqs[i];
+ for (i = 0; i < op->archdata.num_irqs; i++) {
+ int this_irq = op->archdata.irqs[i];
int sbusl = pil_to_sbus[this_irq];
if (sbusl)
@@ -420,7 +416,7 @@ static struct of_device * __init scan_one_device(struct device_node *dp,
(sbusl << 2) +
slot);
- op->irqs[i] = this_irq;
+ op->archdata.irqs[i] = this_irq;
}
}
@@ -428,7 +424,7 @@ build_resources:
build_device_resources(op, parent);
op->dev.parent = parent;
- op->dev.bus = &of_platform_bus_type;
+ op->dev.bus = &platform_bus_type;
if (!parent)
dev_set_name(&op->dev, "root");
else
@@ -447,7 +443,7 @@ build_resources:
static void __init scan_tree(struct device_node *dp, struct device *parent)
{
while (dp) {
- struct of_device *op = scan_one_device(dp, parent);
+ struct platform_device *op = scan_one_device(dp, parent);
if (op)
scan_tree(dp->child, &op->dev);
@@ -456,30 +452,19 @@ static void __init scan_tree(struct device_node *dp, struct device *parent)
}
}
-static void __init scan_of_devices(void)
+static int __init scan_of_devices(void)
{
struct device_node *root = of_find_node_by_path("/");
- struct of_device *parent;
+ struct platform_device *parent;
parent = scan_one_device(root, NULL);
if (!parent)
- return;
+ return 0;
scan_tree(root->child, &parent->dev);
+ return 0;
}
-
-static int __init of_bus_driver_init(void)
-{
- int err;
-
- err = of_bus_type_init(&of_platform_bus_type, "of");
- if (!err)
- scan_of_devices();
-
- return err;
-}
-
-postcore_initcall(of_bus_driver_init);
+postcore_initcall(scan_of_devices);
static int __init of_debug(char *str)
{
diff --git a/arch/sparc/kernel/of_device_64.c b/arch/sparc/kernel/of_device_64.c
index 1dae8079f72..63cd4e5d47c 100644
--- a/arch/sparc/kernel/of_device_64.c
+++ b/arch/sparc/kernel/of_device_64.c
@@ -310,10 +310,10 @@ static int __init use_1to1_mapping(struct device_node *pp)
static int of_resource_verbose;
-static void __init build_device_resources(struct of_device *op,
+static void __init build_device_resources(struct platform_device *op,
struct device *parent)
{
- struct of_device *p_op;
+ struct platform_device *p_op;
struct of_bus *bus;
int na, ns;
int index, num_reg;
@@ -322,7 +322,7 @@ static void __init build_device_resources(struct of_device *op,
if (!parent)
return;
- p_op = to_of_device(parent);
+ p_op = to_platform_device(parent);
bus = of_match_bus(p_op->dev.of_node);
bus->count_cells(op->dev.of_node, &na, &ns);
@@ -344,6 +344,8 @@ static void __init build_device_resources(struct of_device *op,
num_reg = PROMREG_MAX;
}
+ op->resource = op->archdata.resource;
+ op->num_resources = num_reg;
for (index = 0; index < num_reg; index++) {
struct resource *r = &op->resource[index];
u32 addr[OF_MAX_ADDR_CELLS];
@@ -526,7 +528,7 @@ static unsigned int __init pci_irq_swizzle(struct device_node *dp,
static int of_irq_verbose;
-static unsigned int __init build_one_device_irq(struct of_device *op,
+static unsigned int __init build_one_device_irq(struct platform_device *op,
struct device *parent,
unsigned int irq)
{
@@ -628,10 +630,10 @@ out:
return irq;
}
-static struct of_device * __init scan_one_device(struct device_node *dp,
+static struct platform_device * __init scan_one_device(struct device_node *dp,
struct device *parent)
{
- struct of_device *op = kzalloc(sizeof(*op), GFP_KERNEL);
+ struct platform_device *op = kzalloc(sizeof(*op), GFP_KERNEL);
const unsigned int *irq;
struct dev_archdata *sd;
int len, i;
@@ -644,34 +646,28 @@ static struct of_device * __init scan_one_device(struct device_node *dp,
op->dev.of_node = dp;
- op->clock_freq = of_getintprop_default(dp, "clock-frequency",
- (25*1000*1000));
- op->portid = of_getintprop_default(dp, "upa-portid", -1);
- if (op->portid == -1)
- op->portid = of_getintprop_default(dp, "portid", -1);
-
irq = of_get_property(dp, "interrupts", &len);
if (irq) {
- op->num_irqs = len / 4;
+ op->archdata.num_irqs = len / 4;
/* Prevent overrunning the op->irqs[] array. */
- if (op->num_irqs > PROMINTR_MAX) {
+ if (op->archdata.num_irqs > PROMINTR_MAX) {
printk(KERN_WARNING "%s: Too many irqs (%d), "
"limiting to %d.\n",
- dp->full_name, op->num_irqs, PROMINTR_MAX);
- op->num_irqs = PROMINTR_MAX;
+ dp->full_name, op->archdata.num_irqs, PROMINTR_MAX);
+ op->archdata.num_irqs = PROMINTR_MAX;
}
- memcpy(op->irqs, irq, op->num_irqs * 4);
+ memcpy(op->archdata.irqs, irq, op->archdata.num_irqs * 4);
} else {
- op->num_irqs = 0;
+ op->archdata.num_irqs = 0;
}
build_device_resources(op, parent);
- for (i = 0; i < op->num_irqs; i++)
- op->irqs[i] = build_one_device_irq(op, parent, op->irqs[i]);
+ for (i = 0; i < op->archdata.num_irqs; i++)
+ op->archdata.irqs[i] = build_one_device_irq(op, parent, op->archdata.irqs[i]);
op->dev.parent = parent;
- op->dev.bus = &of_platform_bus_type;
+ op->dev.bus = &platform_bus_type;
if (!parent)
dev_set_name(&op->dev, "root");
else
@@ -690,7 +686,7 @@ static struct of_device * __init scan_one_device(struct device_node *dp,
static void __init scan_tree(struct device_node *dp, struct device *parent)
{
while (dp) {
- struct of_device *op = scan_one_device(dp, parent);
+ struct platform_device *op = scan_one_device(dp, parent);
if (op)
scan_tree(dp->child, &op->dev);
@@ -699,30 +695,19 @@ static void __init scan_tree(struct device_node *dp, struct device *parent)
}
}
-static void __init scan_of_devices(void)
+static int __init scan_of_devices(void)
{
struct device_node *root = of_find_node_by_path("/");
- struct of_device *parent;
+ struct platform_device *parent;
parent = scan_one_device(root, NULL);
if (!parent)
- return;
+ return 0;
scan_tree(root->child, &parent->dev);
+ return 0;
}
-
-static int __init of_bus_driver_init(void)
-{
- int err;
-
- err = of_bus_type_init(&of_platform_bus_type, "of");
- if (!err)
- scan_of_devices();
-
- return err;
-}
-
-postcore_initcall(of_bus_driver_init);
+postcore_initcall(scan_of_devices);
static int __init of_debug(char *str)
{
diff --git a/arch/sparc/kernel/of_device_common.c b/arch/sparc/kernel/of_device_common.c
index 10c6c36a6e7..49ddff56cb0 100644
--- a/arch/sparc/kernel/of_device_common.c
+++ b/arch/sparc/kernel/of_device_common.c
@@ -11,48 +11,28 @@
#include "of_device_common.h"
-static int node_match(struct device *dev, void *data)
-{
- struct of_device *op = to_of_device(dev);
- struct device_node *dp = data;
-
- return (op->dev.of_node == dp);
-}
-
-struct of_device *of_find_device_by_node(struct device_node *dp)
-{
- struct device *dev = bus_find_device(&of_platform_bus_type, NULL,
- dp, node_match);
-
- if (dev)
- return to_of_device(dev);
-
- return NULL;
-}
-EXPORT_SYMBOL(of_find_device_by_node);
-
unsigned int irq_of_parse_and_map(struct device_node *node, int index)
{
- struct of_device *op = of_find_device_by_node(node);
+ struct platform_device *op = of_find_device_by_node(node);
- if (!op || index >= op->num_irqs)
+ if (!op || index >= op->archdata.num_irqs)
return 0;
- return op->irqs[index];
+ return op->archdata.irqs[index];
}
EXPORT_SYMBOL(irq_of_parse_and_map);
/* Take the archdata values for IOMMU, STC, and HOSTDATA found in
- * BUS and propagate to all child of_device objects.
+ * BUS and propagate to all child platform_device objects.
*/
-void of_propagate_archdata(struct of_device *bus)
+void of_propagate_archdata(struct platform_device *bus)
{
struct dev_archdata *bus_sd = &bus->dev.archdata;
struct device_node *bus_dp = bus->dev.of_node;
struct device_node *dp;
for (dp = bus_dp->child; dp; dp = dp->sibling) {
- struct of_device *op = of_find_device_by_node(dp);
+ struct platform_device *op = of_find_device_by_node(dp);
op->dev.archdata.iommu = bus_sd->iommu;
op->dev.archdata.stc = bus_sd->stc;
@@ -64,9 +44,6 @@ void of_propagate_archdata(struct of_device *bus)
}
}
-struct bus_type of_platform_bus_type;
-EXPORT_SYMBOL(of_platform_bus_type);
-
static void get_cells(struct device_node *dp, int *addrc, int *sizec)
{
if (addrc)
diff --git a/arch/sparc/kernel/pci.c b/arch/sparc/kernel/pci.c
index 8a8363adb8b..4137579d9ad 100644
--- a/arch/sparc/kernel/pci.c
+++ b/arch/sparc/kernel/pci.c
@@ -198,7 +198,7 @@ static unsigned long pci_parse_of_flags(u32 addr0)
* into physical address resources, we only have to figure out the register
* mapping.
*/
-static void pci_parse_of_addrs(struct of_device *op,
+static void pci_parse_of_addrs(struct platform_device *op,
struct device_node *node,
struct pci_dev *dev)
{
@@ -248,7 +248,7 @@ static struct pci_dev *of_create_pci_dev(struct pci_pbm_info *pbm,
{
struct dev_archdata *sd;
struct pci_slot *slot;
- struct of_device *op;
+ struct platform_device *op;
struct pci_dev *dev;
const char *type;
u32 class;
@@ -340,7 +340,7 @@ static struct pci_dev *of_create_pci_dev(struct pci_pbm_info *pbm,
dev->hdr_type = PCI_HEADER_TYPE_NORMAL;
dev->rom_base_reg = PCI_ROM_ADDRESS;
- dev->irq = sd->op->irqs[0];
+ dev->irq = sd->op->archdata.irqs[0];
if (dev->irq == 0xffffffff)
dev->irq = PCI_IRQ_NONE;
}
diff --git a/arch/sparc/kernel/pci_fire.c b/arch/sparc/kernel/pci_fire.c
index 51cfa09e392..efb896d6875 100644
--- a/arch/sparc/kernel/pci_fire.c
+++ b/arch/sparc/kernel/pci_fire.c
@@ -410,7 +410,7 @@ static void pci_fire_hw_init(struct pci_pbm_info *pbm)
}
static int __devinit pci_fire_pbm_init(struct pci_pbm_info *pbm,
- struct of_device *op, u32 portid)
+ struct platform_device *op, u32 portid)
{
const struct linux_prom64_registers *regs;
struct device_node *dp = op->dev.of_node;
@@ -455,7 +455,7 @@ static int __devinit pci_fire_pbm_init(struct pci_pbm_info *pbm,
return 0;
}
-static int __devinit fire_probe(struct of_device *op,
+static int __devinit fire_probe(struct platform_device *op,
const struct of_device_id *match)
{
struct device_node *dp = op->dev.of_node;
@@ -518,7 +518,7 @@ static struct of_platform_driver fire_driver = {
static int __init fire_init(void)
{
- return of_register_driver(&fire_driver, &of_bus_type);
+ return of_register_platform_driver(&fire_driver);
}
subsys_initcall(fire_init);
diff --git a/arch/sparc/kernel/pci_impl.h b/arch/sparc/kernel/pci_impl.h
index 03186824327..e20ed5f06e9 100644
--- a/arch/sparc/kernel/pci_impl.h
+++ b/arch/sparc/kernel/pci_impl.h
@@ -91,7 +91,7 @@ struct pci_pbm_info {
char *name;
/* OBP specific information. */
- struct of_device *op;
+ struct platform_device *op;
u64 ino_bitmap;
/* PBM I/O and Memory space resources. */
diff --git a/arch/sparc/kernel/pci_psycho.c b/arch/sparc/kernel/pci_psycho.c
index 558a7051282..22eab7cf3b1 100644
--- a/arch/sparc/kernel/pci_psycho.c
+++ b/arch/sparc/kernel/pci_psycho.c
@@ -285,7 +285,7 @@ static irqreturn_t psycho_ce_intr(int irq, void *dev_id)
#define PSYCHO_ECCCTRL_CE 0x2000000000000000UL /* Enable CE INterrupts */
static void psycho_register_error_handlers(struct pci_pbm_info *pbm)
{
- struct of_device *op = of_find_device_by_node(pbm->op->dev.of_node);
+ struct platform_device *op = of_find_device_by_node(pbm->op->dev.of_node);
unsigned long base = pbm->controller_regs;
u64 tmp;
int err;
@@ -302,23 +302,23 @@ static void psycho_register_error_handlers(struct pci_pbm_info *pbm)
* 5: POWER MANAGEMENT
*/
- if (op->num_irqs < 6)
+ if (op->archdata.num_irqs < 6)
return;
/* We really mean to ignore the return result here. Two
* PCI controller share the same interrupt numbers and
* drive the same front-end hardware.
*/
- err = request_irq(op->irqs[1], psycho_ue_intr, IRQF_SHARED,
+ err = request_irq(op->archdata.irqs[1], psycho_ue_intr, IRQF_SHARED,
"PSYCHO_UE", pbm);
- err = request_irq(op->irqs[2], psycho_ce_intr, IRQF_SHARED,
+ err = request_irq(op->archdata.irqs[2], psycho_ce_intr, IRQF_SHARED,
"PSYCHO_CE", pbm);
/* This one, however, ought not to fail. We can just warn
* about it since the system can still operate properly even
* if this fails.
*/
- err = request_irq(op->irqs[0], psycho_pcierr_intr, IRQF_SHARED,
+ err = request_irq(op->archdata.irqs[0], psycho_pcierr_intr, IRQF_SHARED,
"PSYCHO_PCIERR", pbm);
if (err)
printk(KERN_WARNING "%s: Could not register PCIERR, "
@@ -483,7 +483,7 @@ static void psycho_pbm_strbuf_init(struct pci_pbm_info *pbm,
#define PSYCHO_MEMSPACE_SIZE 0x07fffffffUL
static void __devinit psycho_pbm_init(struct pci_pbm_info *pbm,
- struct of_device *op, int is_pbm_a)
+ struct platform_device *op, int is_pbm_a)
{
psycho_pbm_init_common(pbm, op, "PSYCHO", PBM_CHIP_TYPE_PSYCHO);
psycho_pbm_strbuf_init(pbm, is_pbm_a);
@@ -503,7 +503,7 @@ static struct pci_pbm_info * __devinit psycho_find_sibling(u32 upa_portid)
#define PSYCHO_CONFIGSPACE 0x001000000UL
-static int __devinit psycho_probe(struct of_device *op,
+static int __devinit psycho_probe(struct platform_device *op,
const struct of_device_id *match)
{
const struct linux_prom64_registers *pr_regs;
@@ -612,7 +612,7 @@ static struct of_platform_driver psycho_driver = {
static int __init psycho_init(void)
{
- return of_register_driver(&psycho_driver, &of_bus_type);
+ return of_register_platform_driver(&psycho_driver);
}
subsys_initcall(psycho_init);
diff --git a/arch/sparc/kernel/pci_sabre.c b/arch/sparc/kernel/pci_sabre.c
index 6dad8e3b750..5c3f5ec4cab 100644
--- a/arch/sparc/kernel/pci_sabre.c
+++ b/arch/sparc/kernel/pci_sabre.c
@@ -311,7 +311,7 @@ static irqreturn_t sabre_ce_intr(int irq, void *dev_id)
static void sabre_register_error_handlers(struct pci_pbm_info *pbm)
{
struct device_node *dp = pbm->op->dev.of_node;
- struct of_device *op;
+ struct platform_device *op;
unsigned long base = pbm->controller_regs;
u64 tmp;
int err;
@@ -329,7 +329,7 @@ static void sabre_register_error_handlers(struct pci_pbm_info *pbm)
* 2: CE ERR
* 3: POWER FAIL
*/
- if (op->num_irqs < 4)
+ if (op->archdata.num_irqs < 4)
return;
/* We clear the error bits in the appropriate AFSR before
@@ -341,7 +341,7 @@ static void sabre_register_error_handlers(struct pci_pbm_info *pbm)
SABRE_UEAFSR_SDTE | SABRE_UEAFSR_PDTE),
base + SABRE_UE_AFSR);
- err = request_irq(op->irqs[1], sabre_ue_intr, 0, "SABRE_UE", pbm);
+ err = request_irq(op->archdata.irqs[1], sabre_ue_intr, 0, "SABRE_UE", pbm);
if (err)
printk(KERN_WARNING "%s: Couldn't register UE, err=%d.\n",
pbm->name, err);
@@ -351,11 +351,11 @@ static void sabre_register_error_handlers(struct pci_pbm_info *pbm)
base + SABRE_CE_AFSR);
- err = request_irq(op->irqs[2], sabre_ce_intr, 0, "SABRE_CE", pbm);
+ err = request_irq(op->archdata.irqs[2], sabre_ce_intr, 0, "SABRE_CE", pbm);
if (err)
printk(KERN_WARNING "%s: Couldn't register CE, err=%d.\n",
pbm->name, err);
- err = request_irq(op->irqs[0], psycho_pcierr_intr, 0,
+ err = request_irq(op->archdata.irqs[0], psycho_pcierr_intr, 0,
"SABRE_PCIERR", pbm);
if (err)
printk(KERN_WARNING "%s: Couldn't register PCIERR, err=%d.\n",
@@ -443,7 +443,7 @@ static void __devinit sabre_scan_bus(struct pci_pbm_info *pbm,
}
static void __devinit sabre_pbm_init(struct pci_pbm_info *pbm,
- struct of_device *op)
+ struct platform_device *op)
{
psycho_pbm_init_common(pbm, op, "SABRE", PBM_CHIP_TYPE_SABRE);
pbm->pci_afsr = pbm->controller_regs + SABRE_PIOAFSR;
@@ -452,7 +452,7 @@ static void __devinit sabre_pbm_init(struct pci_pbm_info *pbm,
sabre_scan_bus(pbm, &op->dev);
}
-static int __devinit sabre_probe(struct of_device *op,
+static int __devinit sabre_probe(struct platform_device *op,
const struct of_device_id *match)
{
const struct linux_prom64_registers *pr_regs;
@@ -606,7 +606,7 @@ static struct of_platform_driver sabre_driver = {
static int __init sabre_init(void)
{
- return of_register_driver(&sabre_driver, &of_bus_type);
+ return of_register_platform_driver(&sabre_driver);
}
subsys_initcall(sabre_init);
diff --git a/arch/sparc/kernel/pci_schizo.c b/arch/sparc/kernel/pci_schizo.c
index 97a1ae2e1c0..445a47a2fb3 100644
--- a/arch/sparc/kernel/pci_schizo.c
+++ b/arch/sparc/kernel/pci_schizo.c
@@ -844,7 +844,7 @@ static int pbm_routes_this_ino(struct pci_pbm_info *pbm, u32 ino)
*/
static void tomatillo_register_error_handlers(struct pci_pbm_info *pbm)
{
- struct of_device *op = of_find_device_by_node(pbm->op->dev.of_node);
+ struct platform_device *op = of_find_device_by_node(pbm->op->dev.of_node);
u64 tmp, err_mask, err_no_mask;
int err;
@@ -857,14 +857,14 @@ static void tomatillo_register_error_handlers(struct pci_pbm_info *pbm)
*/
if (pbm_routes_this_ino(pbm, SCHIZO_UE_INO)) {
- err = request_irq(op->irqs[1], schizo_ue_intr, 0,
+ err = request_irq(op->archdata.irqs[1], schizo_ue_intr, 0,
"TOMATILLO_UE", pbm);
if (err)
printk(KERN_WARNING "%s: Could not register UE, "
"err=%d\n", pbm->name, err);
}
if (pbm_routes_this_ino(pbm, SCHIZO_CE_INO)) {
- err = request_irq(op->irqs[2], schizo_ce_intr, 0,
+ err = request_irq(op->archdata.irqs[2], schizo_ce_intr, 0,
"TOMATILLO_CE", pbm);
if (err)
printk(KERN_WARNING "%s: Could not register CE, "
@@ -872,10 +872,10 @@ static void tomatillo_register_error_handlers(struct pci_pbm_info *pbm)
}
err = 0;
if (pbm_routes_this_ino(pbm, SCHIZO_PCIERR_A_INO)) {
- err = request_irq(op->irqs[0], schizo_pcierr_intr, 0,
+ err = request_irq(op->archdata.irqs[0], schizo_pcierr_intr, 0,
"TOMATILLO_PCIERR", pbm);
} else if (pbm_routes_this_ino(pbm, SCHIZO_PCIERR_B_INO)) {
- err = request_irq(op->irqs[0], schizo_pcierr_intr, 0,
+ err = request_irq(op->archdata.irqs[0], schizo_pcierr_intr, 0,
"TOMATILLO_PCIERR", pbm);
}
if (err)
@@ -883,7 +883,7 @@ static void tomatillo_register_error_handlers(struct pci_pbm_info *pbm)
"err=%d\n", pbm->name, err);
if (pbm_routes_this_ino(pbm, SCHIZO_SERR_INO)) {
- err = request_irq(op->irqs[3], schizo_safarierr_intr, 0,
+ err = request_irq(op->archdata.irqs[3], schizo_safarierr_intr, 0,
"TOMATILLO_SERR", pbm);
if (err)
printk(KERN_WARNING "%s: Could not register SERR, "
@@ -939,7 +939,7 @@ static void tomatillo_register_error_handlers(struct pci_pbm_info *pbm)
static void schizo_register_error_handlers(struct pci_pbm_info *pbm)
{
- struct of_device *op = of_find_device_by_node(pbm->op->dev.of_node);
+ struct platform_device *op = of_find_device_by_node(pbm->op->dev.of_node);
u64 tmp, err_mask, err_no_mask;
int err;
@@ -952,14 +952,14 @@ static void schizo_register_error_handlers(struct pci_pbm_info *pbm)
*/
if (pbm_routes_this_ino(pbm, SCHIZO_UE_INO)) {
- err = request_irq(op->irqs[1], schizo_ue_intr, 0,
+ err = request_irq(op->archdata.irqs[1], schizo_ue_intr, 0,
"SCHIZO_UE", pbm);
if (err)
printk(KERN_WARNING "%s: Could not register UE, "
"err=%d\n", pbm->name, err);
}
if (pbm_routes_this_ino(pbm, SCHIZO_CE_INO)) {
- err = request_irq(op->irqs[2], schizo_ce_intr, 0,
+ err = request_irq(op->archdata.irqs[2], schizo_ce_intr, 0,
"SCHIZO_CE", pbm);
if (err)
printk(KERN_WARNING "%s: Could not register CE, "
@@ -967,10 +967,10 @@ static void schizo_register_error_handlers(struct pci_pbm_info *pbm)
}
err = 0;
if (pbm_routes_this_ino(pbm, SCHIZO_PCIERR_A_INO)) {
- err = request_irq(op->irqs[0], schizo_pcierr_intr, 0,
+ err = request_irq(op->archdata.irqs[0], schizo_pcierr_intr, 0,
"SCHIZO_PCIERR", pbm);
} else if (pbm_routes_this_ino(pbm, SCHIZO_PCIERR_B_INO)) {
- err = request_irq(op->irqs[0], schizo_pcierr_intr, 0,
+ err = request_irq(op->archdata.irqs[0], schizo_pcierr_intr, 0,
"SCHIZO_PCIERR", pbm);
}
if (err)
@@ -978,7 +978,7 @@ static void schizo_register_error_handlers(struct pci_pbm_info *pbm)
"err=%d\n", pbm->name, err);
if (pbm_routes_this_ino(pbm, SCHIZO_SERR_INO)) {
- err = request_irq(op->irqs[3], schizo_safarierr_intr, 0,
+ err = request_irq(op->archdata.irqs[3], schizo_safarierr_intr, 0,
"SCHIZO_SERR", pbm);
if (err)
printk(KERN_WARNING "%s: Could not register SERR, "
@@ -1307,7 +1307,7 @@ static void schizo_pbm_hw_init(struct pci_pbm_info *pbm)
}
static int __devinit schizo_pbm_init(struct pci_pbm_info *pbm,
- struct of_device *op, u32 portid,
+ struct platform_device *op, u32 portid,
int chip_type)
{
const struct linux_prom64_registers *regs;
@@ -1413,7 +1413,7 @@ static struct pci_pbm_info * __devinit schizo_find_sibling(u32 portid,
return NULL;
}
-static int __devinit __schizo_init(struct of_device *op, unsigned long chip_type)
+static int __devinit __schizo_init(struct platform_device *op, unsigned long chip_type)
{
struct device_node *dp = op->dev.of_node;
struct pci_pbm_info *pbm;
@@ -1460,7 +1460,7 @@ out_err:
return err;
}
-static int __devinit schizo_probe(struct of_device *op,
+static int __devinit schizo_probe(struct platform_device *op,
const struct of_device_id *match)
{
return __schizo_init(op, (unsigned long) match->data);
@@ -1501,7 +1501,7 @@ static struct of_platform_driver schizo_driver = {
static int __init schizo_init(void)
{
- return of_register_driver(&schizo_driver, &of_bus_type);
+ return of_register_platform_driver(&schizo_driver);
}
subsys_initcall(schizo_init);
diff --git a/arch/sparc/kernel/pci_sun4v.c b/arch/sparc/kernel/pci_sun4v.c
index a24af6f7e17..743344aa6d8 100644
--- a/arch/sparc/kernel/pci_sun4v.c
+++ b/arch/sparc/kernel/pci_sun4v.c
@@ -879,7 +879,7 @@ static void pci_sun4v_msi_init(struct pci_pbm_info *pbm)
#endif /* !(CONFIG_PCI_MSI) */
static int __devinit pci_sun4v_pbm_init(struct pci_pbm_info *pbm,
- struct of_device *op, u32 devhandle)
+ struct platform_device *op, u32 devhandle)
{
struct device_node *dp = op->dev.of_node;
int err;
@@ -918,7 +918,7 @@ static int __devinit pci_sun4v_pbm_init(struct pci_pbm_info *pbm,
return 0;
}
-static int __devinit pci_sun4v_probe(struct of_device *op,
+static int __devinit pci_sun4v_probe(struct platform_device *op,
const struct of_device_id *match)
{
const struct linux_prom64_registers *regs;
@@ -1019,7 +1019,7 @@ static struct of_platform_driver pci_sun4v_driver = {
static int __init pci_sun4v_init(void)
{
- return of_register_driver(&pci_sun4v_driver, &of_bus_type);
+ return of_register_platform_driver(&pci_sun4v_driver);
}
subsys_initcall(pci_sun4v_init);
diff --git a/arch/sparc/kernel/perf_event.c b/arch/sparc/kernel/perf_event.c
index 44faabc3c02..357ced3c33f 100644
--- a/arch/sparc/kernel/perf_event.c
+++ b/arch/sparc/kernel/perf_event.c
@@ -572,18 +572,18 @@ static u64 sparc_perf_event_update(struct perf_event *event,
s64 delta;
again:
- prev_raw_count = atomic64_read(&hwc->prev_count);
+ prev_raw_count = local64_read(&hwc->prev_count);
new_raw_count = read_pmc(idx);
- if (atomic64_cmpxchg(&hwc->prev_count, prev_raw_count,
+ if (local64_cmpxchg(&hwc->prev_count, prev_raw_count,
new_raw_count) != prev_raw_count)
goto again;
delta = (new_raw_count << shift) - (prev_raw_count << shift);
delta >>= shift;
- atomic64_add(delta, &event->count);
- atomic64_sub(delta, &hwc->period_left);
+ local64_add(delta, &event->count);
+ local64_sub(delta, &hwc->period_left);
return new_raw_count;
}
@@ -591,27 +591,27 @@ again:
static int sparc_perf_event_set_period(struct perf_event *event,
struct hw_perf_event *hwc, int idx)
{
- s64 left = atomic64_read(&hwc->period_left);
+ s64 left = local64_read(&hwc->period_left);
s64 period = hwc->sample_period;
int ret = 0;
if (unlikely(left <= -period)) {
left = period;
- atomic64_set(&hwc->period_left, left);
+ local64_set(&hwc->period_left, left);
hwc->last_period = period;
ret = 1;
}
if (unlikely(left <= 0)) {
left += period;
- atomic64_set(&hwc->period_left, left);
+ local64_set(&hwc->period_left, left);
hwc->last_period = period;
ret = 1;
}
if (left > MAX_PERIOD)
left = MAX_PERIOD;
- atomic64_set(&hwc->prev_count, (u64)-left);
+ local64_set(&hwc->prev_count, (u64)-left);
write_pmc(idx, (u64)(-left) & 0xffffffff);
@@ -1006,7 +1006,7 @@ static int sparc_pmu_enable(struct perf_event *event)
* skip the schedulability test here, it will be peformed
* at commit time(->commit_txn) as a whole
*/
- if (cpuc->group_flag & PERF_EVENT_TXN_STARTED)
+ if (cpuc->group_flag & PERF_EVENT_TXN)
goto nocheck;
if (check_excludes(cpuc->event, n0, 1))
@@ -1088,7 +1088,7 @@ static int __hw_perf_event_init(struct perf_event *event)
if (!hwc->sample_period) {
hwc->sample_period = MAX_PERIOD;
hwc->last_period = hwc->sample_period;
- atomic64_set(&hwc->period_left, hwc->sample_period);
+ local64_set(&hwc->period_left, hwc->sample_period);
}
return 0;
@@ -1103,7 +1103,7 @@ static void sparc_pmu_start_txn(const struct pmu *pmu)
{
struct cpu_hw_events *cpuhw = &__get_cpu_var(cpu_hw_events);
- cpuhw->group_flag |= PERF_EVENT_TXN_STARTED;
+ cpuhw->group_flag |= PERF_EVENT_TXN;
}
/*
@@ -1115,7 +1115,7 @@ static void sparc_pmu_cancel_txn(const struct pmu *pmu)
{
struct cpu_hw_events *cpuhw = &__get_cpu_var(cpu_hw_events);
- cpuhw->group_flag &= ~PERF_EVENT_TXN_STARTED;
+ cpuhw->group_flag &= ~PERF_EVENT_TXN;
}
/*
@@ -1138,6 +1138,7 @@ static int sparc_pmu_commit_txn(const struct pmu *pmu)
if (sparc_check_constraints(cpuc->event, cpuc->events, n))
return -EAGAIN;
+ cpuc->group_flag &= ~PERF_EVENT_TXN;
return 0;
}
diff --git a/arch/sparc/kernel/pmc.c b/arch/sparc/kernel/pmc.c
index 9589d8b9b0c..94536a85f16 100644
--- a/arch/sparc/kernel/pmc.c
+++ b/arch/sparc/kernel/pmc.c
@@ -51,7 +51,7 @@ static void pmc_swift_idle(void)
#endif
}
-static int __devinit pmc_probe(struct of_device *op,
+static int __devinit pmc_probe(struct platform_device *op,
const struct of_device_id *match)
{
regs = of_ioremap(&op->resource[0], 0,
@@ -89,7 +89,7 @@ static struct of_platform_driver pmc_driver = {
static int __init pmc_init(void)
{
- return of_register_driver(&pmc_driver, &of_bus_type);
+ return of_register_platform_driver(&pmc_driver);
}
/* This driver is not critical to the boot process
diff --git a/arch/sparc/kernel/power.c b/arch/sparc/kernel/power.c
index 168d4cb63f5..2c59f4d387d 100644
--- a/arch/sparc/kernel/power.c
+++ b/arch/sparc/kernel/power.c
@@ -33,10 +33,10 @@ static int __devinit has_button_interrupt(unsigned int irq, struct device_node *
return 1;
}
-static int __devinit power_probe(struct of_device *op, const struct of_device_id *match)
+static int __devinit power_probe(struct platform_device *op, const struct of_device_id *match)
{
struct resource *res = &op->resource[0];
- unsigned int irq= op->irqs[0];
+ unsigned int irq = op->archdata.irqs[0];
power_reg = of_ioremap(res, 0, 0x4, "power");
@@ -70,7 +70,7 @@ static struct of_platform_driver power_driver = {
static int __init power_init(void)
{
- return of_register_driver(&power_driver, &of_platform_bus_type);
+ return of_register_platform_driver(&power_driver);
}
device_initcall(power_init);
diff --git a/arch/sparc/kernel/prom.h b/arch/sparc/kernel/prom.h
index a8591ef2636..eeb04a782ec 100644
--- a/arch/sparc/kernel/prom.h
+++ b/arch/sparc/kernel/prom.h
@@ -9,14 +9,6 @@ extern void irq_trans_init(struct device_node *dp);
extern unsigned int prom_unique_id;
-static inline int is_root_node(const struct device_node *dp)
-{
- if (!dp)
- return 0;
-
- return (dp->parent == NULL);
-}
-
extern char *build_path_component(struct device_node *dp);
extern void of_console_init(void);
diff --git a/arch/sparc/kernel/prom_64.c b/arch/sparc/kernel/prom_64.c
index 466a32763ea..86597d9867f 100644
--- a/arch/sparc/kernel/prom_64.c
+++ b/arch/sparc/kernel/prom_64.c
@@ -21,7 +21,7 @@
#include <linux/mm.h>
#include <linux/module.h>
#include <linux/memblock.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
#include <asm/prom.h>
#include <asm/oplib.h>
@@ -81,7 +81,7 @@ static void __init sun4v_path_component(struct device_node *dp, char *tmp_buf)
return;
regs = rprop->value;
- if (!is_root_node(dp->parent)) {
+ if (!of_node_is_root(dp->parent)) {
sprintf(tmp_buf, "%s@%x,%x",
dp->name,
(unsigned int) (regs->phys_addr >> 32UL),
@@ -121,7 +121,7 @@ static void __init sun4u_path_component(struct device_node *dp, char *tmp_buf)
return;
regs = prop->value;
- if (!is_root_node(dp->parent)) {
+ if (!of_node_is_root(dp->parent)) {
sprintf(tmp_buf, "%s@%x,%x",
dp->name,
(unsigned int) (regs->phys_addr >> 32UL),
diff --git a/arch/sparc/kernel/prom_common.c b/arch/sparc/kernel/prom_common.c
index 57ac9e28be0..1f830da2ddf 100644
--- a/arch/sparc/kernel/prom_common.c
+++ b/arch/sparc/kernel/prom_common.c
@@ -244,7 +244,7 @@ char * __init build_full_name(struct device_node *dp)
n = prom_early_alloc(len);
strcpy(n, dp->parent->full_name);
- if (!is_root_node(dp->parent)) {
+ if (!of_node_is_root(dp->parent)) {
strcpy(n + plen, "/");
plen++;
}
diff --git a/arch/sparc/kernel/prom_irqtrans.c b/arch/sparc/kernel/prom_irqtrans.c
index 5702ad4710c..ce651147fab 100644
--- a/arch/sparc/kernel/prom_irqtrans.c
+++ b/arch/sparc/kernel/prom_irqtrans.c
@@ -719,7 +719,7 @@ static unsigned int central_build_irq(struct device_node *dp,
void *_data)
{
struct device_node *central_dp = _data;
- struct of_device *central_op = of_find_device_by_node(central_dp);
+ struct platform_device *central_op = of_find_device_by_node(central_dp);
struct resource *res;
unsigned long imap, iclr;
u32 tmp;
diff --git a/arch/sparc/kernel/psycho_common.c b/arch/sparc/kernel/psycho_common.c
index 3f34ac85393..fe2af66bb19 100644
--- a/arch/sparc/kernel/psycho_common.c
+++ b/arch/sparc/kernel/psycho_common.c
@@ -447,7 +447,7 @@ int psycho_iommu_init(struct pci_pbm_info *pbm, int tsbsize,
}
-void psycho_pbm_init_common(struct pci_pbm_info *pbm, struct of_device *op,
+void psycho_pbm_init_common(struct pci_pbm_info *pbm, struct platform_device *op,
const char *chip_name, int chip_type)
{
struct device_node *dp = op->dev.of_node;
diff --git a/arch/sparc/kernel/psycho_common.h b/arch/sparc/kernel/psycho_common.h
index 092c278ef28..590b4ed8ab5 100644
--- a/arch/sparc/kernel/psycho_common.h
+++ b/arch/sparc/kernel/psycho_common.h
@@ -42,7 +42,7 @@ extern int psycho_iommu_init(struct pci_pbm_info *pbm, int tsbsize,
unsigned long write_complete_offset);
extern void psycho_pbm_init_common(struct pci_pbm_info *pbm,
- struct of_device *op,
+ struct platform_device *op,
const char *chip_name, int chip_type);
#endif /* _PSYCHO_COMMON_H */
diff --git a/arch/sparc/kernel/sbus.c b/arch/sparc/kernel/sbus.c
index cfeaf04b9cd..2ca32d13abc 100644
--- a/arch/sparc/kernel/sbus.c
+++ b/arch/sparc/kernel/sbus.c
@@ -57,7 +57,7 @@
void sbus_set_sbus64(struct device *dev, int bursts)
{
struct iommu *iommu = dev->archdata.iommu;
- struct of_device *op = to_of_device(dev);
+ struct platform_device *op = to_platform_device(dev);
const struct linux_prom_registers *regs;
unsigned long cfg_reg;
int slot;
@@ -204,7 +204,7 @@ static unsigned long sysio_imap_to_iclr(unsigned long imap)
return imap + diff;
}
-static unsigned int sbus_build_irq(struct of_device *op, unsigned int ino)
+static unsigned int sbus_build_irq(struct platform_device *op, unsigned int ino)
{
struct iommu *iommu = op->dev.archdata.iommu;
unsigned long reg_base = iommu->write_complete_reg - 0x2000UL;
@@ -267,7 +267,7 @@ static unsigned int sbus_build_irq(struct of_device *op, unsigned int ino)
#define SYSIO_UEAFSR_RESV2 0x0000001fffffffffUL /* Reserved */
static irqreturn_t sysio_ue_handler(int irq, void *dev_id)
{
- struct of_device *op = dev_id;
+ struct platform_device *op = dev_id;
struct iommu *iommu = op->dev.archdata.iommu;
unsigned long reg_base = iommu->write_complete_reg - 0x2000UL;
unsigned long afsr_reg, afar_reg;
@@ -341,7 +341,7 @@ static irqreturn_t sysio_ue_handler(int irq, void *dev_id)
#define SYSIO_CEAFSR_RESV2 0x0000001fffffffffUL /* Reserved */
static irqreturn_t sysio_ce_handler(int irq, void *dev_id)
{
- struct of_device *op = dev_id;
+ struct platform_device *op = dev_id;
struct iommu *iommu = op->dev.archdata.iommu;
unsigned long reg_base = iommu->write_complete_reg - 0x2000UL;
unsigned long afsr_reg, afar_reg;
@@ -420,7 +420,7 @@ static irqreturn_t sysio_ce_handler(int irq, void *dev_id)
#define SYSIO_SBAFSR_RESV3 0x0000001fffffffffUL /* Reserved */
static irqreturn_t sysio_sbus_error_handler(int irq, void *dev_id)
{
- struct of_device *op = dev_id;
+ struct platform_device *op = dev_id;
struct iommu *iommu = op->dev.archdata.iommu;
unsigned long afsr_reg, afar_reg, reg_base;
unsigned long afsr, afar, error_bits;
@@ -488,7 +488,7 @@ static irqreturn_t sysio_sbus_error_handler(int irq, void *dev_id)
#define SYSIO_CE_INO 0x35
#define SYSIO_SBUSERR_INO 0x36
-static void __init sysio_register_error_handlers(struct of_device *op)
+static void __init sysio_register_error_handlers(struct platform_device *op)
{
struct iommu *iommu = op->dev.archdata.iommu;
unsigned long reg_base = iommu->write_complete_reg - 0x2000UL;
@@ -534,7 +534,7 @@ static void __init sysio_register_error_handlers(struct of_device *op)
}
/* Boot time initialization. */
-static void __init sbus_iommu_init(struct of_device *op)
+static void __init sbus_iommu_init(struct platform_device *op)
{
const struct linux_prom64_registers *pr;
struct device_node *dp = op->dev.of_node;
@@ -663,7 +663,7 @@ static int __init sbus_init(void)
struct device_node *dp;
for_each_node_by_name(dp, "sbus") {
- struct of_device *op = of_find_device_by_node(dp);
+ struct platform_device *op = of_find_device_by_node(dp);
sbus_iommu_init(op);
of_propagate_archdata(op);
diff --git a/arch/sparc/kernel/time_32.c b/arch/sparc/kernel/time_32.c
index e404b063be2..9c743b1886f 100644
--- a/arch/sparc/kernel/time_32.c
+++ b/arch/sparc/kernel/time_32.c
@@ -142,7 +142,7 @@ static struct platform_device m48t59_rtc = {
},
};
-static int __devinit clock_probe(struct of_device *op, const struct of_device_id *match)
+static int __devinit clock_probe(struct platform_device *op, const struct of_device_id *match)
{
struct device_node *dp = op->dev.of_node;
const char *model = of_get_property(dp, "model", NULL);
@@ -189,7 +189,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_platform_bus_type);
+ return of_register_platform_driver(&clock_driver);
}
/* Must be after subsys_initcall() so that busses are probed. Must
* be before device_initcall() because things like the RTC driver
diff --git a/arch/sparc/kernel/time_64.c b/arch/sparc/kernel/time_64.c
index 21e9fcae066..3bc9c9979b9 100644
--- a/arch/sparc/kernel/time_64.c
+++ b/arch/sparc/kernel/time_64.c
@@ -419,7 +419,7 @@ static struct platform_device rtc_cmos_device = {
.num_resources = 1,
};
-static int __devinit rtc_probe(struct of_device *op, const struct of_device_id *match)
+static int __devinit rtc_probe(struct platform_device *op, const struct of_device_id *match)
{
struct resource *r;
@@ -477,7 +477,7 @@ static struct platform_device rtc_bq4802_device = {
.num_resources = 1,
};
-static int __devinit bq4802_probe(struct of_device *op, const struct of_device_id *match)
+static int __devinit bq4802_probe(struct platform_device *op, const struct of_device_id *match)
{
printk(KERN_INFO "%s: BQ4802 regs at 0x%llx\n",
@@ -534,7 +534,7 @@ static struct platform_device m48t59_rtc = {
},
};
-static int __devinit mostek_probe(struct of_device *op, const struct of_device_id *match)
+static int __devinit mostek_probe(struct platform_device *op, const struct of_device_id *match)
{
struct device_node *dp = op->dev.of_node;
@@ -586,9 +586,9 @@ static int __init clock_init(void)
if (tlb_type == hypervisor)
return platform_device_register(&rtc_sun4v_device);
- (void) of_register_driver(&rtc_driver, &of_platform_bus_type);
- (void) of_register_driver(&mostek_driver, &of_platform_bus_type);
- (void) of_register_driver(&bq4802_driver, &of_platform_bus_type);
+ (void) of_register_platform_driver(&rtc_driver);
+ (void) of_register_platform_driver(&mostek_driver);
+ (void) of_register_platform_driver(&bq4802_driver);
return 0;
}
diff --git a/arch/sparc/mm/io-unit.c b/arch/sparc/mm/io-unit.c
index 005e758a4db..fc58c3e917d 100644
--- a/arch/sparc/mm/io-unit.c
+++ b/arch/sparc/mm/io-unit.c
@@ -35,7 +35,7 @@
#define IOPERM (IOUPTE_CACHE | IOUPTE_WRITE | IOUPTE_VALID)
#define MKIOPTE(phys) __iopte((((phys)>>4) & IOUPTE_PAGE) | IOPERM)
-static void __init iounit_iommu_init(struct of_device *op)
+static void __init iounit_iommu_init(struct platform_device *op)
{
struct iounit_struct *iounit;
iopte_t *xpt, *xptend;
@@ -74,7 +74,7 @@ static int __init iounit_init(void)
struct device_node *dp;
for_each_node_by_name(dp, "sbi") {
- struct of_device *op = of_find_device_by_node(dp);
+ struct platform_device *op = of_find_device_by_node(dp);
iounit_iommu_init(op);
of_propagate_archdata(op);
diff --git a/arch/sparc/mm/iommu.c b/arch/sparc/mm/iommu.c
index b2e6e73888b..07fc6a65d9b 100644
--- a/arch/sparc/mm/iommu.c
+++ b/arch/sparc/mm/iommu.c
@@ -56,14 +56,14 @@ static pgprot_t dvma_prot; /* Consistent mapping pte flags */
#define IOPERM (IOPTE_CACHE | IOPTE_WRITE | IOPTE_VALID)
#define MKIOPTE(pfn, perm) (((((pfn)<<8) & IOPTE_PAGE) | (perm)) & ~IOPTE_WAZ)
-static void __init sbus_iommu_init(struct of_device *op)
+static void __init sbus_iommu_init(struct platform_device *op)
{
struct iommu_struct *iommu;
unsigned int impl, vers;
unsigned long *bitmap;
unsigned long tmp;
- iommu = kmalloc(sizeof(struct iommu_struct), GFP_ATOMIC);
+ iommu = kmalloc(sizeof(struct iommu_struct), GFP_KERNEL);
if (!iommu) {
prom_printf("Unable to allocate iommu structure\n");
prom_halt();
@@ -132,7 +132,7 @@ static int __init iommu_init(void)
struct device_node *dp;
for_each_node_by_name(dp, "iommu") {
- struct of_device *op = of_find_device_by_node(dp);
+ struct platform_device *op = of_find_device_by_node(dp);
sbus_iommu_init(op);
of_propagate_archdata(op);
diff --git a/arch/um/Kconfig.common b/arch/um/Kconfig.common
index 0d207e73a75..7c8e277f6d3 100644
--- a/arch/um/Kconfig.common
+++ b/arch/um/Kconfig.common
@@ -55,10 +55,6 @@ config GENERIC_BUG
default y
depends on BUG
-config GENERIC_TIME
- bool
- default y
-
config GENERIC_CLOCKEVENTS
bool
default y
diff --git a/arch/um/drivers/hostaudio_kern.c b/arch/um/drivers/hostaudio_kern.c
index ae42695c359..68142df7660 100644
--- a/arch/um/drivers/hostaudio_kern.c
+++ b/arch/um/drivers/hostaudio_kern.c
@@ -8,6 +8,7 @@
#include "linux/slab.h"
#include "linux/sound.h"
#include "linux/soundcard.h"
+#include "linux/smp_lock.h"
#include "asm/uaccess.h"
#include "init.h"
#include "os.h"
@@ -198,7 +199,10 @@ static int hostaudio_open(struct inode *inode, struct file *file)
if (file->f_mode & FMODE_WRITE)
w = 1;
+ lock_kernel();
ret = os_open_file(dsp, of_set_rw(OPENFLAGS(), r, w), 0);
+ unlock_kernel();
+
if (ret < 0) {
kfree(state);
return ret;
@@ -254,7 +258,9 @@ static int hostmixer_open_mixdev(struct inode *inode, struct file *file)
if (file->f_mode & FMODE_WRITE)
w = 1;
+ lock_kernel();
ret = os_open_file(mixer, of_set_rw(OPENFLAGS(), r, w), 0);
+ unlock_kernel();
if (ret < 0) {
printk(KERN_ERR "hostaudio_open_mixdev failed to open '%s', "
diff --git a/arch/um/drivers/net_kern.c b/arch/um/drivers/net_kern.c
index f0537269423..2ab233ba32c 100644
--- a/arch/um/drivers/net_kern.c
+++ b/arch/um/drivers/net_kern.c
@@ -25,11 +25,6 @@
#include "net_kern.h"
#include "net_user.h"
-static inline void set_ether_mac(struct net_device *dev, unsigned char *addr)
-{
- memcpy(dev->dev_addr, addr, ETH_ALEN);
-}
-
#define DRIVER_NAME "uml-netdev"
static DEFINE_SPINLOCK(opened_lock);
@@ -266,7 +261,7 @@ static int uml_net_set_mac(struct net_device *dev, void *addr)
struct sockaddr *hwaddr = addr;
spin_lock_irq(&lp->lock);
- set_ether_mac(dev, hwaddr->sa_data);
+ eth_mac_addr(dev, hwaddr->sa_data);
spin_unlock_irq(&lp->lock);
return 0;
@@ -380,7 +375,6 @@ static const struct net_device_ops uml_netdev_ops = {
.ndo_tx_timeout = uml_net_tx_timeout,
.ndo_set_mac_address = uml_net_set_mac,
.ndo_change_mtu = uml_net_change_mtu,
- .ndo_set_mac_address = eth_mac_addr,
.ndo_validate_addr = eth_validate_addr,
};
@@ -478,7 +472,7 @@ static void eth_configure(int n, void *init, char *mac,
((*transport->user->init)(&lp->user, dev) != 0))
goto out_unregister;
- set_ether_mac(dev, device->mac);
+ eth_mac_addr(dev, device->mac);
dev->mtu = transport->user->mtu;
dev->netdev_ops = &uml_netdev_ops;
dev->ethtool_ops = &uml_net_ethtool_ops;
diff --git a/arch/um/include/asm/pgtable-3level.h b/arch/um/include/asm/pgtable-3level.h
index 084de4a9fc7..0032f9212e7 100644
--- a/arch/um/include/asm/pgtable-3level.h
+++ b/arch/um/include/asm/pgtable-3level.h
@@ -60,7 +60,7 @@
set_pud(pud, __pud(_PAGE_TABLE + __pa(pmd)))
#ifdef CONFIG_64BIT
-#define set_pud(pudptr, pudval) set_64bit((phys_t *) (pudptr), pud_val(pudval))
+#define set_pud(pudptr, pudval) set_64bit((u64 *) (pudptr), pud_val(pudval))
#else
#define set_pud(pudptr, pudval) (*(pudptr) = (pudval))
#endif
@@ -73,7 +73,7 @@ static inline int pgd_newpage(pgd_t pgd)
static inline void pgd_mkuptodate(pgd_t pgd) { pgd_val(pgd) &= ~_PAGE_NEWPAGE; }
#ifdef CONFIG_64BIT
-#define set_pmd(pmdptr, pmdval) set_64bit((phys_t *) (pmdptr), pmd_val(pmdval))
+#define set_pmd(pmdptr, pmdval) set_64bit((u64 *) (pmdptr), pmd_val(pmdval))
#else
#define set_pmd(pmdptr, pmdval) (*(pmdptr) = (pmdval))
#endif
diff --git a/arch/um/kernel/time.c b/arch/um/kernel/time.c
index c8b9c469fcd..a08d9fab81f 100644
--- a/arch/um/kernel/time.c
+++ b/arch/um/kernel/time.c
@@ -102,16 +102,16 @@ static void __init setup_itimer(void)
clockevents_register_device(&itimer_clockevent);
}
-void __init time_init(void)
+void read_persistent_clock(struct timespec *ts)
{
- long long nsecs;
-
- timer_init();
+ long long nsecs = os_nsecs();
- nsecs = os_nsecs();
- set_normalized_timespec(&wall_to_monotonic, -nsecs / NSEC_PER_SEC,
- -nsecs % NSEC_PER_SEC);
- set_normalized_timespec(&xtime, nsecs / NSEC_PER_SEC,
+ set_normalized_timespec(ts, nsecs / NSEC_PER_SEC,
nsecs % NSEC_PER_SEC);
+}
+
+void __init time_init(void)
+{
+ timer_init();
late_time_init = setup_itimer;
}
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index dcb0593b4a6..a84fc34c8f7 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -55,6 +55,7 @@ config X86
select HAVE_HW_BREAKPOINT
select HAVE_MIXED_BREAKPOINTS_REGS
select PERF_EVENTS
+ select HAVE_PERF_EVENTS_NMI
select ANON_INODES
select HAVE_ARCH_KMEMCHECK
select HAVE_USER_RETURN_NOTIFIER
@@ -72,9 +73,6 @@ config ARCH_DEFCONFIG
default "arch/x86/configs/i386_defconfig" if X86_32
default "arch/x86/configs/x86_64_defconfig" if X86_64
-config GENERIC_TIME
- def_bool y
-
config GENERIC_CMOS_UPDATE
def_bool y
@@ -2046,7 +2044,7 @@ config SCx200
config SCx200HR_TIMER
tristate "NatSemi SCx200 27MHz High-Resolution Timer Support"
- depends on SCx200 && GENERIC_TIME
+ depends on SCx200
default y
---help---
This driver provides a clocksource built upon the on-chip
@@ -2062,6 +2060,15 @@ config OLPC
Add support for detecting the unique features of the OLPC
XO hardware.
+config OLPC_OPENFIRMWARE
+ bool "Support for OLPC's Open Firmware"
+ depends on !X86_64 && !X86_PAE
+ default y if OLPC
+ help
+ This option adds support for the implementation of Open Firmware
+ that is used on the OLPC XO-1 Children's Machine.
+ If unsure, say N here.
+
endif # X86_32
config K8_NB
diff --git a/arch/x86/boot/Makefile b/arch/x86/boot/Makefile
index ec749c2bfdd..f7cb086b4ad 100644
--- a/arch/x86/boot/Makefile
+++ b/arch/x86/boot/Makefile
@@ -26,10 +26,10 @@ targets := vmlinux.bin setup.bin setup.elf bzImage
targets += fdimage fdimage144 fdimage288 image.iso mtools.conf
subdir- := compressed
-setup-y += a20.o bioscall.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 regs.o string.o tty.o video.o video-mode.o
-setup-y += version.o
+setup-y += a20.o bioscall.o cmdline.o copy.o cpu.o cpucheck.o
+setup-y += early_serial_console.o edd.o header.o main.o mca.o memory.o
+setup-y += pm.o pmjump.o printf.o regs.o string.o tty.o video.o
+setup-y += video-mode.o version.o
setup-$(CONFIG_X86_APM_BOOT) += apm.o
# The link order of the video-*.o modules can matter. In particular,
diff --git a/arch/x86/boot/boot.h b/arch/x86/boot/boot.h
index 98239d2658f..c7093bd9f2d 100644
--- a/arch/x86/boot/boot.h
+++ b/arch/x86/boot/boot.h
@@ -28,6 +28,7 @@
#include "bitops.h"
#include <asm/cpufeature.h>
#include <asm/processor-flags.h>
+#include "ctype.h"
/* Useful macros */
#define BUILD_BUG_ON(condition) ((void)sizeof(char[1 - 2*!!(condition)]))
@@ -37,6 +38,8 @@
extern struct setup_header hdr;
extern struct boot_params boot_params;
+#define cpu_relax() asm volatile("rep; nop")
+
/* Basic port I/O */
static inline void outb(u8 v, u16 port)
{
@@ -198,11 +201,6 @@ static inline int memcmp_gs(const void *s1, addr_t s2, size_t len)
return diff;
}
-static inline int isdigit(int ch)
-{
- return (ch >= '0') && (ch <= '9');
-}
-
/* Heap -- available for dynamic lists. */
extern char _end[];
extern char *HEAP;
@@ -287,8 +285,18 @@ struct biosregs {
void intcall(u8 int_no, const struct biosregs *ireg, struct biosregs *oreg);
/* cmdline.c */
-int cmdline_find_option(const char *option, char *buffer, int bufsize);
-int cmdline_find_option_bool(const char *option);
+int __cmdline_find_option(u32 cmdline_ptr, const char *option, char *buffer, int bufsize);
+int __cmdline_find_option_bool(u32 cmdline_ptr, const char *option);
+static inline int cmdline_find_option(const char *option, char *buffer, int bufsize)
+{
+ return __cmdline_find_option(boot_params.hdr.cmd_line_ptr, option, buffer, bufsize);
+}
+
+static inline int cmdline_find_option_bool(const char *option)
+{
+ return __cmdline_find_option_bool(boot_params.hdr.cmd_line_ptr, option);
+}
+
/* cpu.c, cpucheck.c */
struct cpu_features {
@@ -300,6 +308,10 @@ extern struct cpu_features cpu;
int check_cpu(int *cpu_level_ptr, int *req_level_ptr, u32 **err_flags_ptr);
int validate_cpu(void);
+/* early_serial_console.c */
+extern int early_serial_base;
+void console_init(void);
+
/* edd.c */
void query_edd(void);
@@ -329,8 +341,10 @@ void initregs(struct biosregs *regs);
/* string.c */
int strcmp(const char *str1, const char *str2);
+int strncmp(const char *cs, const char *ct, size_t count);
size_t strnlen(const char *s, size_t maxlen);
unsigned int atou(const char *s);
+unsigned long long simple_strtoull(const char *cp, char **endp, unsigned int base);
/* tty.c */
void puts(const char *);
diff --git a/arch/x86/boot/cmdline.c b/arch/x86/boot/cmdline.c
index a1d35634bce..6b3b6f708c0 100644
--- a/arch/x86/boot/cmdline.c
+++ b/arch/x86/boot/cmdline.c
@@ -27,9 +27,8 @@ static inline int myisspace(u8 c)
* 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)
+int __cmdline_find_option(u32 cmdline_ptr, const char *option, char *buffer, int bufsize)
{
- u32 cmdline_ptr = boot_params.hdr.cmd_line_ptr;
addr_t cptr;
char c;
int len = -1;
@@ -100,9 +99,8 @@ int cmdline_find_option(const char *option, char *buffer, int bufsize)
* Returns the position of that option (starts counting with 1)
* or 0 on not found
*/
-int cmdline_find_option_bool(const char *option)
+int __cmdline_find_option_bool(u32 cmdline_ptr, const char *option)
{
- u32 cmdline_ptr = boot_params.hdr.cmd_line_ptr;
addr_t cptr;
char c;
int pos = 0, wstart = 0;
diff --git a/arch/x86/boot/compressed/Makefile b/arch/x86/boot/compressed/Makefile
index fbb47daf245..0c229551eea 100644
--- a/arch/x86/boot/compressed/Makefile
+++ b/arch/x86/boot/compressed/Makefile
@@ -4,7 +4,7 @@
# create a compressed vmlinux image from the original vmlinux
#
-targets := vmlinux.lds vmlinux vmlinux.bin vmlinux.bin.gz vmlinux.bin.bz2 vmlinux.bin.lzma vmlinux.bin.lzo head_$(BITS).o misc.o piggy.o
+targets := vmlinux.lds vmlinux vmlinux.bin vmlinux.bin.gz vmlinux.bin.bz2 vmlinux.bin.lzma vmlinux.bin.lzo head_$(BITS).o misc.o string.o cmdline.o early_serial_console.o piggy.o
KBUILD_CFLAGS := -m$(BITS) -D__KERNEL__ $(LINUX_INCLUDE) -O2
KBUILD_CFLAGS += -fno-strict-aliasing -fPIC
@@ -23,7 +23,7 @@ LDFLAGS_vmlinux := -T
hostprogs-y := mkpiggy
-$(obj)/vmlinux: $(obj)/vmlinux.lds $(obj)/head_$(BITS).o $(obj)/misc.o $(obj)/piggy.o FORCE
+$(obj)/vmlinux: $(obj)/vmlinux.lds $(obj)/head_$(BITS).o $(obj)/misc.o $(obj)/string.o $(obj)/cmdline.o $(obj)/early_serial_console.o $(obj)/piggy.o FORCE
$(call if_changed,ld)
@:
diff --git a/arch/x86/boot/compressed/cmdline.c b/arch/x86/boot/compressed/cmdline.c
new file mode 100644
index 00000000000..cb62f786990
--- /dev/null
+++ b/arch/x86/boot/compressed/cmdline.c
@@ -0,0 +1,21 @@
+#include "misc.h"
+
+static unsigned long fs;
+static inline void set_fs(unsigned long seg)
+{
+ fs = seg << 4; /* shift it back */
+}
+typedef unsigned long addr_t;
+static inline char rdfs8(addr_t addr)
+{
+ return *((char *)(fs + addr));
+}
+#include "../cmdline.c"
+int cmdline_find_option(const char *option, char *buffer, int bufsize)
+{
+ return __cmdline_find_option(real_mode->hdr.cmd_line_ptr, option, buffer, bufsize);
+}
+int cmdline_find_option_bool(const char *option)
+{
+ return __cmdline_find_option_bool(real_mode->hdr.cmd_line_ptr, option);
+}
diff --git a/arch/x86/boot/compressed/early_serial_console.c b/arch/x86/boot/compressed/early_serial_console.c
new file mode 100644
index 00000000000..261e81fb958
--- /dev/null
+++ b/arch/x86/boot/compressed/early_serial_console.c
@@ -0,0 +1,5 @@
+#include "misc.h"
+
+int early_serial_base;
+
+#include "../early_serial_console.c"
diff --git a/arch/x86/boot/compressed/head_32.S b/arch/x86/boot/compressed/head_32.S
index f543b70ffae..67a655a39ce 100644
--- a/arch/x86/boot/compressed/head_32.S
+++ b/arch/x86/boot/compressed/head_32.S
@@ -124,6 +124,19 @@ relocated:
rep stosl
/*
+ * Adjust our own GOT
+ */
+ leal _got(%ebx), %edx
+ leal _egot(%ebx), %ecx
+1:
+ cmpl %ecx, %edx
+ jae 2f
+ addl %ebx, (%edx)
+ addl $4, %edx
+ jmp 1b
+2:
+
+/*
* Do the decompression, and jump to the new kernel..
*/
leal z_extract_offset_negative(%ebx), %ebp
diff --git a/arch/x86/boot/compressed/head_64.S b/arch/x86/boot/compressed/head_64.S
index faff0dc9c06..52f85a196fa 100644
--- a/arch/x86/boot/compressed/head_64.S
+++ b/arch/x86/boot/compressed/head_64.S
@@ -280,6 +280,19 @@ relocated:
rep stosq
/*
+ * Adjust our own GOT
+ */
+ leaq _got(%rip), %rdx
+ leaq _egot(%rip), %rcx
+1:
+ cmpq %rcx, %rdx
+ jae 2f
+ addq %rbx, (%rdx)
+ addq $8, %rdx
+ jmp 1b
+2:
+
+/*
* Do the decompression, and jump to the new kernel..
*/
pushq %rsi /* Save the real mode argument */
diff --git a/arch/x86/boot/compressed/misc.c b/arch/x86/boot/compressed/misc.c
index 51e240779a4..8f7bef8e9ff 100644
--- a/arch/x86/boot/compressed/misc.c
+++ b/arch/x86/boot/compressed/misc.c
@@ -9,23 +9,7 @@
* High loaded stuff by Hans Lermen & Werner Almesberger, Feb. 1996
*/
-/*
- * we have to be careful, because no indirections are allowed here, and
- * paravirt_ops is a kind of one. As it will only run in baremetal anyway,
- * we just keep it from happening
- */
-#undef CONFIG_PARAVIRT
-#ifdef CONFIG_X86_32
-#define _ASM_X86_DESC_H 1
-#endif
-
-#include <linux/linkage.h>
-#include <linux/screen_info.h>
-#include <linux/elf.h>
-#include <linux/io.h>
-#include <asm/page.h>
-#include <asm/boot.h>
-#include <asm/bootparam.h>
+#include "misc.h"
/* WARNING!!
* This code is compiled with -fPIC and it is relocated dynamically
@@ -123,15 +107,13 @@ static void error(char *m);
/*
* This is set up by the setup-routine at boot-time
*/
-static struct boot_params *real_mode; /* Pointer to real-mode data */
+struct boot_params *real_mode; /* Pointer to real-mode data */
static int quiet;
+static int debug;
void *memset(void *s, int c, size_t n);
void *memcpy(void *dest, const void *src, size_t n);
-static void __putstr(int, const char *);
-#define putstr(__x) __putstr(0, __x)
-
#ifdef CONFIG_X86_64
#define memptr long
#else
@@ -170,7 +152,21 @@ static void scroll(void)
vidmem[i] = ' ';
}
-static void __putstr(int error, const char *s)
+#define XMTRDY 0x20
+
+#define TXR 0 /* Transmit register (WRITE) */
+#define LSR 5 /* Line Status */
+static void serial_putchar(int ch)
+{
+ unsigned timeout = 0xffff;
+
+ while ((inb(early_serial_base + LSR) & XMTRDY) == 0 && --timeout)
+ cpu_relax();
+
+ outb(ch, early_serial_base + TXR);
+}
+
+void __putstr(int error, const char *s)
{
int x, y, pos;
char c;
@@ -179,6 +175,14 @@ static void __putstr(int error, const char *s)
if (!error)
return;
#endif
+ if (early_serial_base) {
+ const char *str = s;
+ while (*str) {
+ if (*str == '\n')
+ serial_putchar('\r');
+ serial_putchar(*str++);
+ }
+ }
if (real_mode->screen_info.orig_video_mode == 0 &&
lines == 0 && cols == 0)
@@ -305,8 +309,10 @@ asmlinkage void decompress_kernel(void *rmode, memptr heap,
{
real_mode = rmode;
- if (real_mode->hdr.loadflags & QUIET_FLAG)
+ if (cmdline_find_option_bool("quiet"))
quiet = 1;
+ if (cmdline_find_option_bool("debug"))
+ debug = 1;
if (real_mode->screen_info.orig_video_mode == 7) {
vidmem = (char *) 0xb0000;
@@ -319,6 +325,10 @@ asmlinkage void decompress_kernel(void *rmode, memptr heap,
lines = real_mode->screen_info.orig_video_lines;
cols = real_mode->screen_info.orig_video_cols;
+ console_init();
+ if (debug)
+ putstr("early console in decompress_kernel\n");
+
free_mem_ptr = heap; /* Heap */
free_mem_end_ptr = heap + BOOT_HEAP_SIZE;
diff --git a/arch/x86/boot/compressed/misc.h b/arch/x86/boot/compressed/misc.h
new file mode 100644
index 00000000000..3f19c81a620
--- /dev/null
+++ b/arch/x86/boot/compressed/misc.h
@@ -0,0 +1,39 @@
+#ifndef BOOT_COMPRESSED_MISC_H
+#define BOOT_COMPRESSED_MISC_H
+
+/*
+ * we have to be careful, because no indirections are allowed here, and
+ * paravirt_ops is a kind of one. As it will only run in baremetal anyway,
+ * we just keep it from happening
+ */
+#undef CONFIG_PARAVIRT
+#ifdef CONFIG_X86_32
+#define _ASM_X86_DESC_H 1
+#endif
+
+#include <linux/linkage.h>
+#include <linux/screen_info.h>
+#include <linux/elf.h>
+#include <linux/io.h>
+#include <asm/page.h>
+#include <asm/boot.h>
+#include <asm/bootparam.h>
+
+#define BOOT_BOOT_H
+#include "../ctype.h"
+
+/* misc.c */
+extern struct boot_params *real_mode; /* Pointer to real-mode data */
+void __putstr(int error, const char *s);
+#define putstr(__x) __putstr(0, __x)
+#define puts(__x) __putstr(0, __x)
+
+/* cmdline.c */
+int cmdline_find_option(const char *option, char *buffer, int bufsize);
+int cmdline_find_option_bool(const char *option);
+
+/* early_serial_console.c */
+extern int early_serial_base;
+void console_init(void);
+
+#endif
diff --git a/arch/x86/boot/compressed/string.c b/arch/x86/boot/compressed/string.c
new file mode 100644
index 00000000000..19b3e693cd7
--- /dev/null
+++ b/arch/x86/boot/compressed/string.c
@@ -0,0 +1,2 @@
+#include "misc.h"
+#include "../string.c"
diff --git a/arch/x86/boot/compressed/vmlinux.lds.S b/arch/x86/boot/compressed/vmlinux.lds.S
index 5ddabceee12..34d047c9828 100644
--- a/arch/x86/boot/compressed/vmlinux.lds.S
+++ b/arch/x86/boot/compressed/vmlinux.lds.S
@@ -41,6 +41,12 @@ SECTIONS
*(.rodata.*)
_erodata = . ;
}
+ .got : {
+ _got = .;
+ KEEP(*(.got.plt))
+ KEEP(*(.got))
+ _egot = .;
+ }
.data : {
_data = . ;
*(.data)
diff --git a/arch/x86/boot/ctype.h b/arch/x86/boot/ctype.h
new file mode 100644
index 00000000000..25e13403193
--- /dev/null
+++ b/arch/x86/boot/ctype.h
@@ -0,0 +1,21 @@
+#ifndef BOOT_ISDIGIT_H
+
+#define BOOT_ISDIGIT_H
+
+static inline int isdigit(int ch)
+{
+ return (ch >= '0') && (ch <= '9');
+}
+
+static inline int isxdigit(int ch)
+{
+ if (isdigit(ch))
+ return true;
+
+ if ((ch >= 'a') && (ch <= 'f'))
+ return true;
+
+ return (ch >= 'A') && (ch <= 'F');
+}
+
+#endif
diff --git a/arch/x86/boot/early_serial_console.c b/arch/x86/boot/early_serial_console.c
new file mode 100644
index 00000000000..030f4b93e25
--- /dev/null
+++ b/arch/x86/boot/early_serial_console.c
@@ -0,0 +1,139 @@
+#include "boot.h"
+
+#define DEFAULT_SERIAL_PORT 0x3f8 /* ttyS0 */
+
+#define XMTRDY 0x20
+
+#define DLAB 0x80
+
+#define TXR 0 /* Transmit register (WRITE) */
+#define RXR 0 /* Receive register (READ) */
+#define IER 1 /* Interrupt Enable */
+#define IIR 2 /* Interrupt ID */
+#define FCR 2 /* FIFO control */
+#define LCR 3 /* Line control */
+#define MCR 4 /* Modem control */
+#define LSR 5 /* Line Status */
+#define MSR 6 /* Modem Status */
+#define DLL 0 /* Divisor Latch Low */
+#define DLH 1 /* Divisor latch High */
+
+#define DEFAULT_BAUD 9600
+
+static void early_serial_init(int port, int baud)
+{
+ unsigned char c;
+ unsigned divisor;
+
+ outb(0x3, port + LCR); /* 8n1 */
+ outb(0, port + IER); /* no interrupt */
+ outb(0, port + FCR); /* no fifo */
+ outb(0x3, port + MCR); /* DTR + RTS */
+
+ divisor = 115200 / baud;
+ c = inb(port + LCR);
+ outb(c | DLAB, port + LCR);
+ outb(divisor & 0xff, port + DLL);
+ outb((divisor >> 8) & 0xff, port + DLH);
+ outb(c & ~DLAB, port + LCR);
+
+ early_serial_base = port;
+}
+
+static void parse_earlyprintk(void)
+{
+ int baud = DEFAULT_BAUD;
+ char arg[32];
+ int pos = 0;
+ int port = 0;
+
+ if (cmdline_find_option("earlyprintk", arg, sizeof arg) > 0) {
+ char *e;
+
+ if (!strncmp(arg, "serial", 6)) {
+ port = DEFAULT_SERIAL_PORT;
+ pos += 6;
+ }
+
+ if (arg[pos] == ',')
+ pos++;
+
+ if (!strncmp(arg, "ttyS", 4)) {
+ static const int bases[] = { 0x3f8, 0x2f8 };
+ int idx = 0;
+
+ if (!strncmp(arg + pos, "ttyS", 4))
+ pos += 4;
+
+ if (arg[pos++] == '1')
+ idx = 1;
+
+ port = bases[idx];
+ }
+
+ if (arg[pos] == ',')
+ pos++;
+
+ baud = simple_strtoull(arg + pos, &e, 0);
+ if (baud == 0 || arg + pos == e)
+ baud = DEFAULT_BAUD;
+ }
+
+ if (port)
+ early_serial_init(port, baud);
+}
+
+#define BASE_BAUD (1843200/16)
+static unsigned int probe_baud(int port)
+{
+ unsigned char lcr, dll, dlh;
+ unsigned int quot;
+
+ lcr = inb(port + LCR);
+ outb(lcr | DLAB, port + LCR);
+ dll = inb(port + DLL);
+ dlh = inb(port + DLH);
+ outb(lcr, port + LCR);
+ quot = (dlh << 8) | dll;
+
+ return BASE_BAUD / quot;
+}
+
+static void parse_console_uart8250(void)
+{
+ char optstr[64], *options;
+ int baud = DEFAULT_BAUD;
+ int port = 0;
+
+ /*
+ * console=uart8250,io,0x3f8,115200n8
+ * need to make sure it is last one console !
+ */
+ if (cmdline_find_option("console", optstr, sizeof optstr) <= 0)
+ return;
+
+ options = optstr;
+
+ if (!strncmp(options, "uart8250,io,", 12))
+ port = simple_strtoull(options + 12, &options, 0);
+ else if (!strncmp(options, "uart,io,", 8))
+ port = simple_strtoull(options + 8, &options, 0);
+ else
+ return;
+
+ if (options && (options[0] == ','))
+ baud = simple_strtoull(options + 1, &options, 0);
+ else
+ baud = probe_baud(port);
+
+ if (port)
+ early_serial_init(port, baud);
+}
+
+void console_init(void)
+{
+ parse_earlyprintk();
+
+ if (!early_serial_base)
+ parse_console_uart8250();
+}
diff --git a/arch/x86/boot/main.c b/arch/x86/boot/main.c
index 140172b895b..40358c8905b 100644
--- a/arch/x86/boot/main.c
+++ b/arch/x86/boot/main.c
@@ -130,6 +130,11 @@ void main(void)
/* First, copy the boot header into the "zeropage" */
copy_boot_params();
+ /* Initialize the early-boot console */
+ console_init();
+ if (cmdline_find_option_bool("debug"))
+ puts("early console in setup code\n");
+
/* End of heap check */
init_heap();
@@ -168,10 +173,6 @@ void main(void)
/* Set the video mode */
set_video();
- /* Parse command line for 'quiet' and pass it to decompressor. */
- if (cmdline_find_option_bool("quiet"))
- boot_params.hdr.loadflags |= QUIET_FLAG;
-
/* Do the last things and invoke protected mode */
go_to_protected_mode();
}
diff --git a/arch/x86/boot/printf.c b/arch/x86/boot/printf.c
index 50e47cdbddd..cdac91ca55d 100644
--- a/arch/x86/boot/printf.c
+++ b/arch/x86/boot/printf.c
@@ -34,7 +34,7 @@ static int skip_atoi(const char **s)
#define SMALL 32 /* Must be 32 == 0x20 */
#define SPECIAL 64 /* 0x */
-#define do_div(n,base) ({ \
+#define __do_div(n, base) ({ \
int __res; \
__res = ((unsigned long) n) % (unsigned) base; \
n = ((unsigned long) n) / (unsigned) base; \
@@ -83,7 +83,7 @@ static char *number(char *str, long num, int base, int size, int precision,
tmp[i++] = '0';
else
while (num != 0)
- tmp[i++] = (digits[do_div(num, base)] | locase);
+ tmp[i++] = (digits[__do_div(num, base)] | locase);
if (i > precision)
precision = i;
size -= precision;
diff --git a/arch/x86/boot/string.c b/arch/x86/boot/string.c
index f94b7a0c2ab..3cbc4058dd2 100644
--- a/arch/x86/boot/string.c
+++ b/arch/x86/boot/string.c
@@ -30,6 +30,22 @@ int strcmp(const char *str1, const char *str2)
return 0;
}
+int strncmp(const char *cs, const char *ct, size_t count)
+{
+ unsigned char c1, c2;
+
+ while (count) {
+ c1 = *cs++;
+ c2 = *ct++;
+ if (c1 != c2)
+ return c1 < c2 ? -1 : 1;
+ if (!c1)
+ break;
+ count--;
+ }
+ return 0;
+}
+
size_t strnlen(const char *s, size_t maxlen)
{
const char *es = s;
@@ -48,3 +64,50 @@ unsigned int atou(const char *s)
i = i * 10 + (*s++ - '0');
return i;
}
+
+/* Works only for digits and letters, but small and fast */
+#define TOLOWER(x) ((x) | 0x20)
+
+static unsigned int simple_guess_base(const char *cp)
+{
+ if (cp[0] == '0') {
+ if (TOLOWER(cp[1]) == 'x' && isxdigit(cp[2]))
+ return 16;
+ else
+ return 8;
+ } else {
+ return 10;
+ }
+}
+
+/**
+ * simple_strtoull - convert a string to an unsigned long long
+ * @cp: The start of the string
+ * @endp: A pointer to the end of the parsed string will be placed here
+ * @base: The number base to use
+ */
+
+unsigned long long simple_strtoull(const char *cp, char **endp, unsigned int base)
+{
+ unsigned long long result = 0;
+
+ if (!base)
+ base = simple_guess_base(cp);
+
+ if (base == 16 && cp[0] == '0' && TOLOWER(cp[1]) == 'x')
+ cp += 2;
+
+ while (isxdigit(*cp)) {
+ unsigned int value;
+
+ value = isdigit(*cp) ? *cp - '0' : TOLOWER(*cp) - 'a' + 10;
+ if (value >= base)
+ break;
+ result = result * base + value;
+ cp++;
+ }
+ if (endp)
+ *endp = (char *)cp;
+
+ return result;
+}
diff --git a/arch/x86/boot/tty.c b/arch/x86/boot/tty.c
index 01ec69c901c..def2451f46a 100644
--- a/arch/x86/boot/tty.c
+++ b/arch/x86/boot/tty.c
@@ -10,23 +10,36 @@
* ----------------------------------------------------------------------- */
/*
- * Very simple screen I/O
- * XXX: Probably should add very simple serial I/O?
+ * Very simple screen and serial I/O
*/
#include "boot.h"
+int early_serial_base;
+
+#define XMTRDY 0x20
+
+#define TXR 0 /* Transmit register (WRITE) */
+#define LSR 5 /* Line Status */
+
/*
* These functions are in .inittext so they can be used to signal
* error during initialization.
*/
-void __attribute__((section(".inittext"))) putchar(int ch)
+static void __attribute__((section(".inittext"))) serial_putchar(int ch)
{
- struct biosregs ireg;
+ unsigned timeout = 0xffff;
- if (ch == '\n')
- putchar('\r'); /* \n -> \r\n */
+ while ((inb(early_serial_base + LSR) & XMTRDY) == 0 && --timeout)
+ cpu_relax();
+
+ outb(ch, early_serial_base + TXR);
+}
+
+static void __attribute__((section(".inittext"))) bios_putchar(int ch)
+{
+ struct biosregs ireg;
initregs(&ireg);
ireg.bx = 0x0007;
@@ -36,6 +49,17 @@ void __attribute__((section(".inittext"))) putchar(int ch)
intcall(0x10, &ireg, NULL);
}
+void __attribute__((section(".inittext"))) putchar(int ch)
+{
+ if (ch == '\n')
+ putchar('\r'); /* \n -> \r\n */
+
+ bios_putchar(ch);
+
+ if (early_serial_base != 0)
+ serial_putchar(ch);
+}
+
void __attribute__((section(".inittext"))) puts(const char *str)
{
while (*str)
@@ -112,3 +136,4 @@ int getchar_timeout(void)
return 0; /* Timeout! */
}
+
diff --git a/arch/x86/configs/i386_defconfig b/arch/x86/configs/i386_defconfig
index d28fad19654..e3a32431ca1 100644
--- a/arch/x86/configs/i386_defconfig
+++ b/arch/x86/configs/i386_defconfig
@@ -1471,6 +1471,7 @@ CONFIG_HWMON=y
# CONFIG_SENSORS_GL518SM is not set
# CONFIG_SENSORS_GL520SM is not set
# CONFIG_SENSORS_CORETEMP is not set
+# CONFIG_SENSORS_PKGTEMP is not set
# CONFIG_SENSORS_IT87 is not set
# CONFIG_SENSORS_LM63 is not set
# CONFIG_SENSORS_LM75 is not set
diff --git a/arch/x86/configs/x86_64_defconfig b/arch/x86/configs/x86_64_defconfig
index 6c86acd847a..4251f837205 100644
--- a/arch/x86/configs/x86_64_defconfig
+++ b/arch/x86/configs/x86_64_defconfig
@@ -1456,6 +1456,7 @@ CONFIG_HWMON=y
# CONFIG_SENSORS_GL518SM is not set
# CONFIG_SENSORS_GL520SM is not set
# CONFIG_SENSORS_CORETEMP is not set
+# CONFIG_SENSORS_PKGTEMP is not set
# CONFIG_SENSORS_IT87 is not set
# CONFIG_SENSORS_LM63 is not set
# CONFIG_SENSORS_LM75 is not set
diff --git a/arch/x86/include/asm/acpi.h b/arch/x86/include/asm/acpi.h
index aa2c39d968f..92091de1111 100644
--- a/arch/x86/include/asm/acpi.h
+++ b/arch/x86/include/asm/acpi.h
@@ -134,7 +134,7 @@ static inline unsigned int acpi_processor_cstate_check(unsigned int max_cstate)
boot_cpu_data.x86_model <= 0x05 &&
boot_cpu_data.x86_mask < 0x0A)
return 1;
- else if (boot_cpu_has(X86_FEATURE_AMDC1E))
+ else if (c1e_detected)
return 1;
else
return max_cstate;
diff --git a/arch/x86/include/asm/alternative.h b/arch/x86/include/asm/alternative.h
index 03b6bb5394a..bc6abb7bc7e 100644
--- a/arch/x86/include/asm/alternative.h
+++ b/arch/x86/include/asm/alternative.h
@@ -45,10 +45,9 @@
struct alt_instr {
u8 *instr; /* original instruction */
u8 *replacement;
- u8 cpuid; /* cpuid bit set for replacement */
+ u16 cpuid; /* cpuid bit set for replacement */
u8 instrlen; /* length of original instruction */
u8 replacementlen; /* length of new instruction, <= instrlen */
- u8 pad1;
#ifdef CONFIG_X86_64
u32 pad2;
#endif
@@ -86,9 +85,11 @@ static inline int alternatives_text_reserved(void *start, void *end)
_ASM_ALIGN "\n" \
_ASM_PTR "661b\n" /* label */ \
_ASM_PTR "663f\n" /* new instruction */ \
- " .byte " __stringify(feature) "\n" /* feature bit */ \
+ " .word " __stringify(feature) "\n" /* feature bit */ \
" .byte 662b-661b\n" /* sourcelen */ \
" .byte 664f-663f\n" /* replacementlen */ \
+ ".previous\n" \
+ ".section .discard,\"aw\",@progbits\n" \
" .byte 0xff + (664f-663f) - (662b-661b)\n" /* rlen <= slen */ \
".previous\n" \
".section .altinstr_replacement, \"ax\"\n" \
diff --git a/arch/x86/include/asm/apb_timer.h b/arch/x86/include/asm/apb_timer.h
index c74a2eebe57..a69b1ac9eaf 100644
--- a/arch/x86/include/asm/apb_timer.h
+++ b/arch/x86/include/asm/apb_timer.h
@@ -55,7 +55,6 @@ extern unsigned long apbt_quick_calibrate(void);
extern int arch_setup_apbt_irqs(int irq, int trigger, int mask, int cpu);
extern void apbt_setup_secondary_clock(void);
extern unsigned int boot_cpu_id;
-extern int disable_apbt_percpu;
extern struct sfi_timer_table_entry *sfi_get_mtmr(int hint);
extern void sfi_free_mtmr(struct sfi_timer_table_entry *mtmr);
diff --git a/arch/x86/include/asm/bootparam.h b/arch/x86/include/asm/bootparam.h
index 6be33d83c71..8e6218550e7 100644
--- a/arch/x86/include/asm/bootparam.h
+++ b/arch/x86/include/asm/bootparam.h
@@ -70,6 +70,14 @@ struct sys_desc_table {
__u8 table[14];
};
+/* Gleaned from OFW's set-parameters in cpu/x86/pc/linux.fth */
+struct olpc_ofw_header {
+ __u32 ofw_magic; /* OFW signature */
+ __u32 ofw_version;
+ __u32 cif_handler; /* callback into OFW */
+ __u32 irq_desc_table;
+} __attribute__((packed));
+
struct efi_info {
__u32 efi_loader_signature;
__u32 efi_systab;
@@ -92,7 +100,8 @@ struct boot_params {
__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 olpc_ofw_header olpc_ofw_header; /* 0x0b0 */
+ __u8 _pad4[128]; /* 0x0c0 */
struct edid_info edid_info; /* 0x140 */
struct efi_info efi_info; /* 0x1c0 */
__u32 alt_mem_k; /* 0x1e0 */
diff --git a/arch/x86/include/asm/cmpxchg_32.h b/arch/x86/include/asm/cmpxchg_32.h
index 8859e12dd3c..284a6e8f7ce 100644
--- a/arch/x86/include/asm/cmpxchg_32.h
+++ b/arch/x86/include/asm/cmpxchg_32.h
@@ -11,38 +11,42 @@
extern void __xchg_wrong_size(void);
/*
- * Note: no "lock" prefix even on SMP: xchg always implies lock anyway
- * Note 2: xchg has side effect, so that attribute volatile is necessary,
- * but generally the primitive is invalid, *ptr is output argument. --ANK
+ * Note: no "lock" prefix even on SMP: xchg always implies lock anyway.
+ * Since this is generally used to protect other memory information, we
+ * use "asm volatile" and "memory" clobbers to prevent gcc from moving
+ * information around.
*/
-
-struct __xchg_dummy {
- unsigned long a[100];
-};
-#define __xg(x) ((struct __xchg_dummy *)(x))
-
#define __xchg(x, ptr, size) \
({ \
__typeof(*(ptr)) __x = (x); \
switch (size) { \
case 1: \
- asm volatile("xchgb %b0,%1" \
- : "=q" (__x) \
- : "m" (*__xg(ptr)), "0" (__x) \
+ { \
+ volatile u8 *__ptr = (volatile u8 *)(ptr); \
+ asm volatile("xchgb %0,%1" \
+ : "=q" (__x), "+m" (*__ptr) \
+ : "0" (__x) \
: "memory"); \
break; \
+ } \
case 2: \
- asm volatile("xchgw %w0,%1" \
- : "=r" (__x) \
- : "m" (*__xg(ptr)), "0" (__x) \
+ { \
+ volatile u16 *__ptr = (volatile u16 *)(ptr); \
+ asm volatile("xchgw %0,%1" \
+ : "=r" (__x), "+m" (*__ptr) \
+ : "0" (__x) \
: "memory"); \
break; \
+ } \
case 4: \
+ { \
+ volatile u32 *__ptr = (volatile u32 *)(ptr); \
asm volatile("xchgl %0,%1" \
- : "=r" (__x) \
- : "m" (*__xg(ptr)), "0" (__x) \
+ : "=r" (__x), "+m" (*__ptr) \
+ : "0" (__x) \
: "memory"); \
break; \
+ } \
default: \
__xchg_wrong_size(); \
} \
@@ -53,60 +57,33 @@ struct __xchg_dummy {
__xchg((v), (ptr), sizeof(*ptr))
/*
- * The semantics of XCHGCMP8B are a bit strange, this is why
- * there is a loop and the loading of %%eax and %%edx has to
- * be inside. This inlines well in most cases, the cached
- * cost is around ~38 cycles. (in the future we might want
- * to do an SIMD/3DNOW!/MMX/FPU 64-bit store here, but that
- * might have an implicit FPU-save as a cost, so it's not
- * clear which path to go.)
+ * CMPXCHG8B only writes to the target if we had the previous
+ * value in registers, otherwise it acts as a read and gives us the
+ * "new previous" value. That is why there is a loop. Preloading
+ * EDX:EAX is a performance optimization: in the common case it means
+ * we need only one locked operation.
*
- * cmpxchg8b must be used with the lock prefix here to allow
- * the instruction to be executed atomically, see page 3-102
- * of the instruction set reference 24319102.pdf. We need
- * the reader side to see the coherent 64bit value.
+ * A SIMD/3DNOW!/MMX/FPU 64-bit store here would require at the very
+ * least an FPU save and/or %cr0.ts manipulation.
+ *
+ * cmpxchg8b must be used with the lock prefix here to allow the
+ * instruction to be executed atomically. We need to have the reader
+ * side to see the coherent 64bit value.
*/
-static inline void __set_64bit(unsigned long long *ptr,
- unsigned int low, unsigned int high)
+static inline void set_64bit(volatile u64 *ptr, u64 value)
{
+ u32 low = value;
+ u32 high = value >> 32;
+ u64 prev = *ptr;
+
asm volatile("\n1:\t"
- "movl (%0), %%eax\n\t"
- "movl 4(%0), %%edx\n\t"
- LOCK_PREFIX "cmpxchg8b (%0)\n\t"
+ LOCK_PREFIX "cmpxchg8b %0\n\t"
"jnz 1b"
- : /* no outputs */
- : "D"(ptr),
- "b"(low),
- "c"(high)
- : "ax", "dx", "memory");
-}
-
-static inline void __set_64bit_constant(unsigned long long *ptr,
- unsigned long long value)
-{
- __set_64bit(ptr, (unsigned int)value, (unsigned int)(value >> 32));
-}
-
-#define ll_low(x) *(((unsigned int *)&(x)) + 0)
-#define ll_high(x) *(((unsigned int *)&(x)) + 1)
-
-static inline void __set_64bit_var(unsigned long long *ptr,
- unsigned long long value)
-{
- __set_64bit(ptr, ll_low(value), ll_high(value));
+ : "=m" (*ptr), "+A" (prev)
+ : "b" (low), "c" (high)
+ : "memory");
}
-#define set_64bit(ptr, value) \
- (__builtin_constant_p((value)) \
- ? __set_64bit_constant((ptr), (value)) \
- : __set_64bit_var((ptr), (value)))
-
-#define _set_64bit(ptr, value) \
- (__builtin_constant_p(value) \
- ? __set_64bit(ptr, (unsigned int)(value), \
- (unsigned int)((value) >> 32)) \
- : __set_64bit(ptr, ll_low((value)), ll_high((value))))
-
extern void __cmpxchg_wrong_size(void);
/*
@@ -121,23 +98,32 @@ extern void __cmpxchg_wrong_size(void);
__typeof__(*(ptr)) __new = (new); \
switch (size) { \
case 1: \
- asm volatile(lock "cmpxchgb %b1,%2" \
- : "=a"(__ret) \
- : "q"(__new), "m"(*__xg(ptr)), "0"(__old) \
+ { \
+ volatile u8 *__ptr = (volatile u8 *)(ptr); \
+ asm volatile(lock "cmpxchgb %2,%1" \
+ : "=a" (__ret), "+m" (*__ptr) \
+ : "q" (__new), "0" (__old) \
: "memory"); \
break; \
+ } \
case 2: \
- asm volatile(lock "cmpxchgw %w1,%2" \
- : "=a"(__ret) \
- : "r"(__new), "m"(*__xg(ptr)), "0"(__old) \
+ { \
+ volatile u16 *__ptr = (volatile u16 *)(ptr); \
+ asm volatile(lock "cmpxchgw %2,%1" \
+ : "=a" (__ret), "+m" (*__ptr) \
+ : "r" (__new), "0" (__old) \
: "memory"); \
break; \
+ } \
case 4: \
- asm volatile(lock "cmpxchgl %1,%2" \
- : "=a"(__ret) \
- : "r"(__new), "m"(*__xg(ptr)), "0"(__old) \
+ { \
+ volatile u32 *__ptr = (volatile u32 *)(ptr); \
+ asm volatile(lock "cmpxchgl %2,%1" \
+ : "=a" (__ret), "+m" (*__ptr) \
+ : "r" (__new), "0" (__old) \
: "memory"); \
break; \
+ } \
default: \
__cmpxchg_wrong_size(); \
} \
@@ -175,32 +161,28 @@ extern void __cmpxchg_wrong_size(void);
(unsigned long long)(n)))
#endif
-static inline unsigned long long __cmpxchg64(volatile void *ptr,
- unsigned long long old,
- unsigned long long new)
+static inline u64 __cmpxchg64(volatile u64 *ptr, u64 old, u64 new)
{
- unsigned long long prev;
- asm volatile(LOCK_PREFIX "cmpxchg8b %3"
- : "=A"(prev)
- : "b"((unsigned long)new),
- "c"((unsigned long)(new >> 32)),
- "m"(*__xg(ptr)),
- "0"(old)
+ u64 prev;
+ asm volatile(LOCK_PREFIX "cmpxchg8b %1"
+ : "=A" (prev),
+ "+m" (*ptr)
+ : "b" ((u32)new),
+ "c" ((u32)(new >> 32)),
+ "0" (old)
: "memory");
return prev;
}
-static inline unsigned long long __cmpxchg64_local(volatile void *ptr,
- unsigned long long old,
- unsigned long long new)
+static inline u64 __cmpxchg64_local(volatile u64 *ptr, u64 old, u64 new)
{
- unsigned long long prev;
- asm volatile("cmpxchg8b %3"
- : "=A"(prev)
- : "b"((unsigned long)new),
- "c"((unsigned long)(new >> 32)),
- "m"(*__xg(ptr)),
- "0"(old)
+ u64 prev;
+ asm volatile("cmpxchg8b %1"
+ : "=A" (prev),
+ "+m" (*ptr)
+ : "b" ((u32)new),
+ "c" ((u32)(new >> 32)),
+ "0" (old)
: "memory");
return prev;
}
@@ -264,8 +246,6 @@ static inline unsigned long cmpxchg_386(volatile void *ptr, unsigned long old,
* to simulate the cmpxchg8b on the 80386 and 80486 CPU.
*/
-extern unsigned long long cmpxchg_486_u64(volatile void *, u64, u64);
-
#define cmpxchg64(ptr, o, n) \
({ \
__typeof__(*(ptr)) __ret; \
@@ -283,20 +263,20 @@ extern unsigned long long cmpxchg_486_u64(volatile void *, u64, u64);
__ret; })
-
-#define cmpxchg64_local(ptr, o, n) \
-({ \
- __typeof__(*(ptr)) __ret; \
- if (likely(boot_cpu_data.x86 > 4)) \
- __ret = (__typeof__(*(ptr)))__cmpxchg64_local((ptr), \
- (unsigned long long)(o), \
- (unsigned long long)(n)); \
- else \
- __ret = (__typeof__(*(ptr)))cmpxchg_486_u64((ptr), \
- (unsigned long long)(o), \
- (unsigned long long)(n)); \
- __ret; \
-})
+#define cmpxchg64_local(ptr, o, n) \
+({ \
+ __typeof__(*(ptr)) __ret; \
+ __typeof__(*(ptr)) __old = (o); \
+ __typeof__(*(ptr)) __new = (n); \
+ alternative_io("call cmpxchg8b_emu", \
+ "cmpxchg8b (%%esi)" , \
+ X86_FEATURE_CX8, \
+ "=A" (__ret), \
+ "S" ((ptr)), "0" (__old), \
+ "b" ((unsigned int)__new), \
+ "c" ((unsigned int)(__new>>32)) \
+ : "memory"); \
+ __ret; })
#endif
diff --git a/arch/x86/include/asm/cmpxchg_64.h b/arch/x86/include/asm/cmpxchg_64.h
index 485ae415fae..423ae58aa02 100644
--- a/arch/x86/include/asm/cmpxchg_64.h
+++ b/arch/x86/include/asm/cmpxchg_64.h
@@ -3,51 +3,60 @@
#include <asm/alternative.h> /* Provides LOCK_PREFIX */
-#define __xg(x) ((volatile long *)(x))
-
-static inline void set_64bit(volatile unsigned long *ptr, unsigned long val)
+static inline void set_64bit(volatile u64 *ptr, u64 val)
{
*ptr = val;
}
-#define _set_64bit set_64bit
-
extern void __xchg_wrong_size(void);
extern void __cmpxchg_wrong_size(void);
/*
- * Note: no "lock" prefix even on SMP: xchg always implies lock anyway
- * Note 2: xchg has side effect, so that attribute volatile is necessary,
- * but generally the primitive is invalid, *ptr is output argument. --ANK
+ * Note: no "lock" prefix even on SMP: xchg always implies lock anyway.
+ * Since this is generally used to protect other memory information, we
+ * use "asm volatile" and "memory" clobbers to prevent gcc from moving
+ * information around.
*/
#define __xchg(x, ptr, size) \
({ \
__typeof(*(ptr)) __x = (x); \
switch (size) { \
case 1: \
- asm volatile("xchgb %b0,%1" \
- : "=q" (__x) \
- : "m" (*__xg(ptr)), "0" (__x) \
+ { \
+ volatile u8 *__ptr = (volatile u8 *)(ptr); \
+ asm volatile("xchgb %0,%1" \
+ : "=q" (__x), "+m" (*__ptr) \
+ : "0" (__x) \
: "memory"); \
break; \
+ } \
case 2: \
- asm volatile("xchgw %w0,%1" \
- : "=r" (__x) \
- : "m" (*__xg(ptr)), "0" (__x) \
+ { \
+ volatile u16 *__ptr = (volatile u16 *)(ptr); \
+ asm volatile("xchgw %0,%1" \
+ : "=r" (__x), "+m" (*__ptr) \
+ : "0" (__x) \
: "memory"); \
break; \
+ } \
case 4: \
- asm volatile("xchgl %k0,%1" \
- : "=r" (__x) \
- : "m" (*__xg(ptr)), "0" (__x) \
+ { \
+ volatile u32 *__ptr = (volatile u32 *)(ptr); \
+ asm volatile("xchgl %0,%1" \
+ : "=r" (__x), "+m" (*__ptr) \
+ : "0" (__x) \
: "memory"); \
break; \
+ } \
case 8: \
+ { \
+ volatile u64 *__ptr = (volatile u64 *)(ptr); \
asm volatile("xchgq %0,%1" \
- : "=r" (__x) \
- : "m" (*__xg(ptr)), "0" (__x) \
+ : "=r" (__x), "+m" (*__ptr) \
+ : "0" (__x) \
: "memory"); \
break; \
+ } \
default: \
__xchg_wrong_size(); \
} \
@@ -71,29 +80,41 @@ extern void __cmpxchg_wrong_size(void);
__typeof__(*(ptr)) __new = (new); \
switch (size) { \
case 1: \
- asm volatile(lock "cmpxchgb %b1,%2" \
- : "=a"(__ret) \
- : "q"(__new), "m"(*__xg(ptr)), "0"(__old) \
+ { \
+ volatile u8 *__ptr = (volatile u8 *)(ptr); \
+ asm volatile(lock "cmpxchgb %2,%1" \
+ : "=a" (__ret), "+m" (*__ptr) \
+ : "q" (__new), "0" (__old) \
: "memory"); \
break; \
+ } \
case 2: \
- asm volatile(lock "cmpxchgw %w1,%2" \
- : "=a"(__ret) \
- : "r"(__new), "m"(*__xg(ptr)), "0"(__old) \
+ { \
+ volatile u16 *__ptr = (volatile u16 *)(ptr); \
+ asm volatile(lock "cmpxchgw %2,%1" \
+ : "=a" (__ret), "+m" (*__ptr) \
+ : "r" (__new), "0" (__old) \
: "memory"); \
break; \
+ } \
case 4: \
- asm volatile(lock "cmpxchgl %k1,%2" \
- : "=a"(__ret) \
- : "r"(__new), "m"(*__xg(ptr)), "0"(__old) \
+ { \
+ volatile u32 *__ptr = (volatile u32 *)(ptr); \
+ asm volatile(lock "cmpxchgl %2,%1" \
+ : "=a" (__ret), "+m" (*__ptr) \
+ : "r" (__new), "0" (__old) \
: "memory"); \
break; \
+ } \
case 8: \
- asm volatile(lock "cmpxchgq %1,%2" \
- : "=a"(__ret) \
- : "r"(__new), "m"(*__xg(ptr)), "0"(__old) \
+ { \
+ volatile u64 *__ptr = (volatile u64 *)(ptr); \
+ asm volatile(lock "cmpxchgq %2,%1" \
+ : "=a" (__ret), "+m" (*__ptr) \
+ : "r" (__new), "0" (__old) \
: "memory"); \
break; \
+ } \
default: \
__cmpxchg_wrong_size(); \
} \
diff --git a/arch/x86/include/asm/cpufeature.h b/arch/x86/include/asm/cpufeature.h
index 46814591438..781a50b29a4 100644
--- a/arch/x86/include/asm/cpufeature.h
+++ b/arch/x86/include/asm/cpufeature.h
@@ -6,7 +6,7 @@
#include <asm/required-features.h>
-#define NCAPINTS 9 /* N 32-bit words worth of info */
+#define NCAPINTS 10 /* N 32-bit words worth of info */
/*
* Note: If the comment begins with a quoted string, that string is used
@@ -89,7 +89,7 @@
#define X86_FEATURE_LFENCE_RDTSC (3*32+18) /* "" Lfence synchronizes RDTSC */
#define X86_FEATURE_11AP (3*32+19) /* "" Bad local APIC aka 11AP */
#define X86_FEATURE_NOPL (3*32+20) /* The NOPL (0F 1F) instructions */
-#define X86_FEATURE_AMDC1E (3*32+21) /* AMD C1E detected */
+ /* 21 available, was AMD_C1E */
#define X86_FEATURE_XTOPOLOGY (3*32+22) /* cpu topology enum extensions */
#define X86_FEATURE_TSC_RELIABLE (3*32+23) /* TSC is known to be reliable */
#define X86_FEATURE_NONSTOP_TSC (3*32+24) /* TSC does not stop in C states */
@@ -124,6 +124,8 @@
#define X86_FEATURE_XSAVE (4*32+26) /* XSAVE/XRSTOR/XSETBV/XGETBV */
#define X86_FEATURE_OSXSAVE (4*32+27) /* "" XSAVE enabled in the OS */
#define X86_FEATURE_AVX (4*32+28) /* Advanced Vector Extensions */
+#define X86_FEATURE_F16C (4*32+29) /* 16-bit fp conversions */
+#define X86_FEATURE_RDRND (4*32+30) /* The RDRAND instruction */
#define X86_FEATURE_HYPERVISOR (4*32+31) /* Running on a hypervisor */
/* VIA/Cyrix/Centaur-defined CPU features, CPUID level 0xC0000001, word 5 */
@@ -157,22 +159,29 @@
/*
* Auxiliary flags: Linux defined - For features scattered in various
- * CPUID levels like 0x6, 0xA etc
+ * CPUID levels like 0x6, 0xA etc, word 7
*/
#define X86_FEATURE_IDA (7*32+ 0) /* Intel Dynamic Acceleration */
#define X86_FEATURE_ARAT (7*32+ 1) /* Always Running APIC Timer */
#define X86_FEATURE_CPB (7*32+ 2) /* AMD Core Performance Boost */
+#define X86_FEATURE_EPB (7*32+ 3) /* IA32_ENERGY_PERF_BIAS support */
+#define X86_FEATURE_XSAVEOPT (7*32+ 4) /* Optimized Xsave */
+#define X86_FEATURE_PLN (7*32+ 5) /* Intel Power Limit Notification */
+#define X86_FEATURE_PTS (7*32+ 6) /* Intel Package Thermal Status */
-/* Virtualization flags: Linux defined */
+/* Virtualization flags: Linux defined, word 8 */
#define X86_FEATURE_TPR_SHADOW (8*32+ 0) /* Intel TPR Shadow */
#define X86_FEATURE_VNMI (8*32+ 1) /* Intel Virtual NMI */
#define X86_FEATURE_FLEXPRIORITY (8*32+ 2) /* Intel FlexPriority */
#define X86_FEATURE_EPT (8*32+ 3) /* Intel Extended Page Table */
#define X86_FEATURE_VPID (8*32+ 4) /* Intel Virtual Processor ID */
-#define X86_FEATURE_NPT (8*32+5) /* AMD Nested Page Table support */
-#define X86_FEATURE_LBRV (8*32+6) /* AMD LBR Virtualization support */
-#define X86_FEATURE_SVML (8*32+7) /* "svm_lock" AMD SVM locking MSR */
-#define X86_FEATURE_NRIPS (8*32+8) /* "nrip_save" AMD SVM next_rip save */
+#define X86_FEATURE_NPT (8*32+ 5) /* AMD Nested Page Table support */
+#define X86_FEATURE_LBRV (8*32+ 6) /* AMD LBR Virtualization support */
+#define X86_FEATURE_SVML (8*32+ 7) /* "svm_lock" AMD SVM locking MSR */
+#define X86_FEATURE_NRIPS (8*32+ 8) /* "nrip_save" AMD SVM next_rip save */
+
+/* Intel-defined CPU features, CPUID level 0x00000007:0 (ebx), word 9 */
+#define X86_FEATURE_FSGSBASE (9*32+ 0) /* {RD/WR}{FS/GS}BASE instructions*/
#if defined(__KERNEL__) && !defined(__ASSEMBLY__)
@@ -194,7 +203,9 @@ extern const char * const x86_power_flags[32];
(((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)) ) \
+ (((bit)>>5)==7 && (1UL<<((bit)&31) & REQUIRED_MASK7)) || \
+ (((bit)>>5)==8 && (1UL<<((bit)&31) & REQUIRED_MASK8)) || \
+ (((bit)>>5)==9 && (1UL<<((bit)&31) & REQUIRED_MASK9)) ) \
? 1 : \
test_cpu_cap(c, bit))
@@ -291,7 +302,7 @@ extern const char * const x86_power_flags[32];
* patch the target code for additional performance.
*
*/
-static __always_inline __pure bool __static_cpu_has(u8 bit)
+static __always_inline __pure bool __static_cpu_has(u16 bit)
{
#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5)
asm goto("1: jmp %l[t_no]\n"
@@ -300,11 +311,11 @@ static __always_inline __pure bool __static_cpu_has(u8 bit)
_ASM_ALIGN "\n"
_ASM_PTR "1b\n"
_ASM_PTR "0\n" /* no replacement */
- " .byte %P0\n" /* feature bit */
+ " .word %P0\n" /* feature bit */
" .byte 2b - 1b\n" /* source len */
" .byte 0\n" /* replacement len */
- " .byte 0xff + 0 - (2b-1b)\n" /* padding */
".previous\n"
+ /* skipping size check since replacement size = 0 */
: : "i" (bit) : : t_no);
return true;
t_no:
@@ -318,10 +329,12 @@ static __always_inline __pure bool __static_cpu_has(u8 bit)
_ASM_ALIGN "\n"
_ASM_PTR "1b\n"
_ASM_PTR "3f\n"
- " .byte %P1\n" /* feature bit */
+ " .word %P1\n" /* feature bit */
" .byte 2b - 1b\n" /* source len */
" .byte 4f - 3f\n" /* replacement len */
- " .byte 0xff + (4f-3f) - (2b-1b)\n" /* padding */
+ ".previous\n"
+ ".section .discard,\"aw\",@progbits\n"
+ " .byte 0xff + (4f-3f) - (2b-1b)\n" /* size check */
".previous\n"
".section .altinstr_replacement,\"ax\"\n"
"3: movb $1,%0\n"
@@ -337,7 +350,7 @@ static __always_inline __pure bool __static_cpu_has(u8 bit)
( \
__builtin_constant_p(boot_cpu_has(bit)) ? \
boot_cpu_has(bit) : \
- (__builtin_constant_p(bit) && !((bit) & ~0xff)) ? \
+ __builtin_constant_p(bit) ? \
__static_cpu_has(bit) : \
boot_cpu_has(bit) \
)
diff --git a/arch/x86/include/asm/hw_breakpoint.h b/arch/x86/include/asm/hw_breakpoint.h
index 942255310e6..528a11e8d3e 100644
--- a/arch/x86/include/asm/hw_breakpoint.h
+++ b/arch/x86/include/asm/hw_breakpoint.h
@@ -20,10 +20,10 @@ struct arch_hw_breakpoint {
#include <linux/list.h>
/* Available HW breakpoint length encodings */
+#define X86_BREAKPOINT_LEN_X 0x00
#define X86_BREAKPOINT_LEN_1 0x40
#define X86_BREAKPOINT_LEN_2 0x44
#define X86_BREAKPOINT_LEN_4 0x4c
-#define X86_BREAKPOINT_LEN_EXECUTE 0x40
#ifdef CONFIG_X86_64
#define X86_BREAKPOINT_LEN_8 0x48
diff --git a/arch/x86/include/asm/hypervisor.h b/arch/x86/include/asm/hypervisor.h
index 70abda7058c..ff2546ce717 100644
--- a/arch/x86/include/asm/hypervisor.h
+++ b/arch/x86/include/asm/hypervisor.h
@@ -45,5 +45,6 @@ extern const struct hypervisor_x86 *x86_hyper;
/* Recognized hypervisors */
extern const struct hypervisor_x86 x86_hyper_vmware;
extern const struct hypervisor_x86 x86_hyper_ms_hyperv;
+extern const struct hypervisor_x86 x86_hyper_xen_hvm;
#endif
diff --git a/arch/x86/include/asm/i387.h b/arch/x86/include/asm/i387.h
index c991b3a7b90..a73a8d5a5e6 100644
--- a/arch/x86/include/asm/i387.h
+++ b/arch/x86/include/asm/i387.h
@@ -31,7 +31,6 @@ extern void mxcsr_feature_mask_init(void);
extern int init_fpu(struct task_struct *child);
extern asmlinkage void math_state_restore(void);
extern void __math_state_restore(void);
-extern void init_thread_xstate(void);
extern int dump_fpu(struct pt_regs *, struct user_i387_struct *);
extern user_regset_active_fn fpregs_active, xfpregs_active;
@@ -58,11 +57,25 @@ extern int restore_i387_xstate_ia32(void __user *buf);
#define X87_FSW_ES (1 << 7) /* Exception Summary */
+static __always_inline __pure bool use_xsaveopt(void)
+{
+ return static_cpu_has(X86_FEATURE_XSAVEOPT);
+}
+
static __always_inline __pure bool use_xsave(void)
{
return static_cpu_has(X86_FEATURE_XSAVE);
}
+extern void __sanitize_i387_state(struct task_struct *);
+
+static inline void sanitize_i387_state(struct task_struct *tsk)
+{
+ if (!use_xsaveopt())
+ return;
+ __sanitize_i387_state(tsk);
+}
+
#ifdef CONFIG_X86_64
/* Ignore delayed exceptions from user space */
@@ -127,6 +140,15 @@ static inline int fxsave_user(struct i387_fxsave_struct __user *fx)
{
int err;
+ /*
+ * Clear the bytes not touched by the fxsave and reserved
+ * for the SW usage.
+ */
+ err = __clear_user(&fx->sw_reserved,
+ sizeof(struct _fpx_sw_bytes));
+ if (unlikely(err))
+ return -EFAULT;
+
asm volatile("1: rex64/fxsave (%[fx])\n\t"
"2:\n"
".section .fixup,\"ax\"\n"
@@ -482,6 +504,8 @@ static inline void fpu_copy(struct fpu *dst, struct fpu *src)
memcpy(dst->state, src->state, xstate_size);
}
+extern void fpu_finit(struct fpu *fpu);
+
#endif /* __ASSEMBLY__ */
#define PSHUFB_XMM5_XMM0 .byte 0x66, 0x0f, 0x38, 0x00, 0xc5
diff --git a/arch/x86/include/asm/intel_scu_ipc.h b/arch/x86/include/asm/intel_scu_ipc.h
index 4470c9ad4a3..29f66793cc5 100644
--- a/arch/x86/include/asm/intel_scu_ipc.h
+++ b/arch/x86/include/asm/intel_scu_ipc.h
@@ -1,6 +1,12 @@
#ifndef _ASM_X86_INTEL_SCU_IPC_H_
#define _ASM_X86_INTEL_SCU_IPC_H_
+#define IPCMSG_VRTC 0xFA /* Set vRTC device */
+
+/* Command id associated with message IPCMSG_VRTC */
+#define IPC_CMD_VRTC_SETTIME 1 /* Set time */
+#define IPC_CMD_VRTC_SETALARM 2 /* Set alarm */
+
/* Read single register */
int intel_scu_ipc_ioread8(u16 addr, u8 *data);
@@ -28,20 +34,6 @@ int intel_scu_ipc_writev(u16 *addr, u8 *data, int len);
/* Update single register based on the mask */
int intel_scu_ipc_update_register(u16 addr, u8 data, u8 mask);
-/*
- * Indirect register read
- * Can be used when SCCB(System Controller Configuration Block) register
- * HRIM(Honor Restricted IPC Messages) is set (bit 23)
- */
-int intel_scu_ipc_register_read(u32 addr, u32 *data);
-
-/*
- * Indirect register write
- * Can be used when SCCB(System Controller Configuration Block) register
- * HRIM(Honor Restricted IPC Messages) is set (bit 23)
- */
-int intel_scu_ipc_register_write(u32 addr, u32 data);
-
/* Issue commands to the SCU with or without data */
int intel_scu_ipc_simple_command(int cmd, int sub);
int intel_scu_ipc_command(int cmd, int sub, u32 *in, int inlen,
diff --git a/arch/x86/include/asm/irq_vectors.h b/arch/x86/include/asm/irq_vectors.h
index 8767d99c4f6..e2ca3009255 100644
--- a/arch/x86/include/asm/irq_vectors.h
+++ b/arch/x86/include/asm/irq_vectors.h
@@ -125,6 +125,9 @@
*/
#define MCE_SELF_VECTOR 0xeb
+/* Xen vector callback to receive events in a HVM domain */
+#define XEN_HVM_EVTCHN_CALLBACK 0xe9
+
#define NR_VECTORS 256
#define FPU_IRQ 13
diff --git a/arch/x86/include/asm/kgdb.h b/arch/x86/include/asm/kgdb.h
index 006da3687cd..396f5b5fc4d 100644
--- a/arch/x86/include/asm/kgdb.h
+++ b/arch/x86/include/asm/kgdb.h
@@ -39,9 +39,11 @@ enum regnames {
GDB_FS, /* 14 */
GDB_GS, /* 15 */
};
+#define GDB_ORIG_AX 41
+#define DBG_MAX_REG_NUM 16
#define NUMREGBYTES ((GDB_GS+1)*4)
#else /* ! CONFIG_X86_32 */
-enum regnames64 {
+enum regnames {
GDB_AX, /* 0 */
GDB_BX, /* 1 */
GDB_CX, /* 2 */
@@ -59,15 +61,15 @@ enum regnames64 {
GDB_R14, /* 14 */
GDB_R15, /* 15 */
GDB_PC, /* 16 */
+ GDB_PS, /* 17 */
+ GDB_CS, /* 18 */
+ GDB_SS, /* 19 */
};
-
-enum regnames32 {
- GDB_PS = 34,
- GDB_CS,
- GDB_SS,
-};
-#define NUMREGBYTES ((GDB_SS+1)*4)
-#endif /* CONFIG_X86_32 */
+#define GDB_ORIG_AX 57
+#define DBG_MAX_REG_NUM 20
+/* 17 64 bit regs and 3 32 bit regs */
+#define NUMREGBYTES ((17 * 8) + (3 * 4))
+#endif /* ! CONFIG_X86_32 */
static inline void arch_kgdb_breakpoint(void)
{
diff --git a/arch/x86/include/asm/kvm.h b/arch/x86/include/asm/kvm.h
index ff90055c7f0..4d8dcbdfc12 100644
--- a/arch/x86/include/asm/kvm.h
+++ b/arch/x86/include/asm/kvm.h
@@ -22,6 +22,8 @@
#define __KVM_HAVE_XEN_HVM
#define __KVM_HAVE_VCPU_EVENTS
#define __KVM_HAVE_DEBUGREGS
+#define __KVM_HAVE_XSAVE
+#define __KVM_HAVE_XCRS
/* Architectural interrupt line count. */
#define KVM_NR_INTERRUPTS 256
@@ -299,4 +301,24 @@ struct kvm_debugregs {
__u64 reserved[9];
};
+/* for KVM_CAP_XSAVE */
+struct kvm_xsave {
+ __u32 region[1024];
+};
+
+#define KVM_MAX_XCRS 16
+
+struct kvm_xcr {
+ __u32 xcr;
+ __u32 reserved;
+ __u64 value;
+};
+
+struct kvm_xcrs {
+ __u32 nr_xcrs;
+ __u32 flags;
+ struct kvm_xcr xcrs[KVM_MAX_XCRS];
+ __u64 padding[16];
+};
+
#endif /* _ASM_X86_KVM_H */
diff --git a/arch/x86/include/asm/kvm_emulate.h b/arch/x86/include/asm/kvm_emulate.h
index 0b2729bf207..51cfd730ac5 100644
--- a/arch/x86/include/asm/kvm_emulate.h
+++ b/arch/x86/include/asm/kvm_emulate.h
@@ -51,8 +51,10 @@ struct x86_emulate_ctxt;
#define X86EMUL_UNHANDLEABLE 1
/* Terminate emulation but return success to the caller. */
#define X86EMUL_PROPAGATE_FAULT 2 /* propagate a generated fault to guest */
-#define X86EMUL_RETRY_INSTR 2 /* retry the instruction for some reason */
-#define X86EMUL_CMPXCHG_FAILED 2 /* cmpxchg did not see expected value */
+#define X86EMUL_RETRY_INSTR 3 /* retry the instruction for some reason */
+#define X86EMUL_CMPXCHG_FAILED 4 /* cmpxchg did not see expected value */
+#define X86EMUL_IO_NEEDED 5 /* IO is needed to complete emulation */
+
struct x86_emulate_ops {
/*
* read_std: Read bytes of standard (non-emulated/special) memory.
@@ -92,6 +94,7 @@ struct x86_emulate_ops {
int (*read_emulated)(unsigned long addr,
void *val,
unsigned int bytes,
+ unsigned int *error,
struct kvm_vcpu *vcpu);
/*
@@ -104,6 +107,7 @@ struct x86_emulate_ops {
int (*write_emulated)(unsigned long addr,
const void *val,
unsigned int bytes,
+ unsigned int *error,
struct kvm_vcpu *vcpu);
/*
@@ -118,6 +122,7 @@ struct x86_emulate_ops {
const void *old,
const void *new,
unsigned int bytes,
+ unsigned int *error,
struct kvm_vcpu *vcpu);
int (*pio_in_emulated)(int size, unsigned short port, void *val,
@@ -132,18 +137,26 @@ struct x86_emulate_ops {
int seg, struct kvm_vcpu *vcpu);
u16 (*get_segment_selector)(int seg, struct kvm_vcpu *vcpu);
void (*set_segment_selector)(u16 sel, int seg, struct kvm_vcpu *vcpu);
+ unsigned long (*get_cached_segment_base)(int seg, struct kvm_vcpu *vcpu);
void (*get_gdt)(struct desc_ptr *dt, struct kvm_vcpu *vcpu);
ulong (*get_cr)(int cr, struct kvm_vcpu *vcpu);
- void (*set_cr)(int cr, ulong val, struct kvm_vcpu *vcpu);
+ int (*set_cr)(int cr, ulong val, struct kvm_vcpu *vcpu);
int (*cpl)(struct kvm_vcpu *vcpu);
- void (*set_rflags)(struct kvm_vcpu *vcpu, unsigned long rflags);
+ int (*get_dr)(int dr, unsigned long *dest, struct kvm_vcpu *vcpu);
+ int (*set_dr)(int dr, unsigned long value, struct kvm_vcpu *vcpu);
+ int (*set_msr)(struct kvm_vcpu *vcpu, u32 msr_index, u64 data);
+ int (*get_msr)(struct kvm_vcpu *vcpu, u32 msr_index, u64 *pdata);
};
/* Type, address-of, and value of an instruction's operand. */
struct operand {
enum { OP_REG, OP_MEM, OP_IMM, OP_NONE } type;
unsigned int bytes;
- unsigned long val, orig_val, *ptr;
+ unsigned long orig_val, *ptr;
+ union {
+ unsigned long val;
+ char valptr[sizeof(unsigned long) + 2];
+ };
};
struct fetch_cache {
@@ -186,6 +199,7 @@ struct decode_cache {
unsigned long modrm_val;
struct fetch_cache fetch;
struct read_cache io_read;
+ struct read_cache mem_read;
};
struct x86_emulate_ctxt {
@@ -202,6 +216,12 @@ struct x86_emulate_ctxt {
int interruptibility;
bool restart; /* restart string instruction after writeback */
+
+ int exception; /* exception that happens during emulation or -1 */
+ u32 error_code; /* error code for exception */
+ bool error_code_valid;
+ unsigned long cr2; /* faulted address in case of #PF */
+
/* decode cache */
struct decode_cache decode;
};
diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
index 76f5483cffe..502e53f999c 100644
--- a/arch/x86/include/asm/kvm_host.h
+++ b/arch/x86/include/asm/kvm_host.h
@@ -15,6 +15,7 @@
#include <linux/mm.h>
#include <linux/mmu_notifier.h>
#include <linux/tracepoint.h>
+#include <linux/cpumask.h>
#include <linux/kvm.h>
#include <linux/kvm_para.h>
@@ -39,11 +40,14 @@
0xFFFFFF0000000000ULL)
#define INVALID_PAGE (~(hpa_t)0)
+#define VALID_PAGE(x) ((x) != INVALID_PAGE)
+
#define UNMAPPED_GVA (~(gpa_t)0)
/* KVM Hugepage definitions for x86 */
#define KVM_NR_PAGE_SIZES 3
-#define KVM_HPAGE_SHIFT(x) (PAGE_SHIFT + (((x) - 1) * 9))
+#define KVM_HPAGE_GFN_SHIFT(x) (((x) - 1) * 9)
+#define KVM_HPAGE_SHIFT(x) (PAGE_SHIFT + KVM_HPAGE_GFN_SHIFT(x))
#define KVM_HPAGE_SIZE(x) (1UL << KVM_HPAGE_SHIFT(x))
#define KVM_HPAGE_MASK(x) (~(KVM_HPAGE_SIZE(x) - 1))
#define KVM_PAGES_PER_HPAGE(x) (KVM_HPAGE_SIZE(x) / PAGE_SIZE)
@@ -69,8 +73,6 @@
#define IOPL_SHIFT 12
-#define KVM_ALIAS_SLOTS 4
-
#define KVM_PERMILLE_MMU_PAGES 20
#define KVM_MIN_ALLOC_MMU_PAGES 64
#define KVM_MMU_HASH_SHIFT 10
@@ -241,7 +243,7 @@ struct kvm_mmu {
void (*prefetch_page)(struct kvm_vcpu *vcpu,
struct kvm_mmu_page *page);
int (*sync_page)(struct kvm_vcpu *vcpu,
- struct kvm_mmu_page *sp);
+ struct kvm_mmu_page *sp, bool clear_unsync);
void (*invlpg)(struct kvm_vcpu *vcpu, gva_t gva);
hpa_t root_hpa;
int root_level;
@@ -301,8 +303,8 @@ struct kvm_vcpu_arch {
unsigned long mmu_seq;
} update_pte;
- struct i387_fxsave_struct host_fx_image;
- struct i387_fxsave_struct guest_fx_image;
+ struct fpu guest_fpu;
+ u64 xcr0;
gva_t mmio_fault_cr2;
struct kvm_pio_request pio;
@@ -360,26 +362,11 @@ struct kvm_vcpu_arch {
/* fields used by HYPER-V emulation */
u64 hv_vapic;
-};
-
-struct kvm_mem_alias {
- gfn_t base_gfn;
- unsigned long npages;
- gfn_t target_gfn;
-#define KVM_ALIAS_INVALID 1UL
- unsigned long flags;
-};
-#define KVM_ARCH_HAS_UNALIAS_INSTANTIATION
-
-struct kvm_mem_aliases {
- struct kvm_mem_alias aliases[KVM_ALIAS_SLOTS];
- int naliases;
+ cpumask_var_t wbinvd_dirty_mask;
};
struct kvm_arch {
- struct kvm_mem_aliases *aliases;
-
unsigned int n_free_mmu_pages;
unsigned int n_requested_mmu_pages;
unsigned int n_alloc_mmu_pages;
@@ -533,6 +520,8 @@ struct kvm_x86_ops {
void (*set_supported_cpuid)(u32 func, struct kvm_cpuid_entry2 *entry);
+ bool (*has_wbinvd_exit)(void);
+
const struct trace_print_flags *exit_reasons_str;
};
@@ -576,7 +565,6 @@ enum emulation_result {
#define EMULTYPE_SKIP (1 << 2)
int emulate_instruction(struct kvm_vcpu *vcpu,
unsigned long cr2, u16 error_code, int emulation_type);
-void kvm_report_emulation_failure(struct kvm_vcpu *cvpu, const char *context);
void realmode_lgdt(struct kvm_vcpu *vcpu, u16 size, unsigned long address);
void realmode_lidt(struct kvm_vcpu *vcpu, u16 size, unsigned long address);
@@ -591,10 +579,7 @@ 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,
- unsigned long *dest);
-int emulator_set_dr(struct x86_emulate_ctxt *ctxt, int dr,
- unsigned long value);
+int kvm_emulate_wbinvd(struct kvm_vcpu *vcpu);
void kvm_get_segment(struct kvm_vcpu *vcpu, struct kvm_segment *var, int seg);
int kvm_load_segment_descriptor(struct kvm_vcpu *vcpu, u16 selector, int seg);
@@ -602,15 +587,16 @@ int kvm_load_segment_descriptor(struct kvm_vcpu *vcpu, u16 selector, int seg);
int kvm_task_switch(struct kvm_vcpu *vcpu, u16 tss_selector, int reason,
bool has_error_code, u32 error_code);
-void kvm_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0);
-void kvm_set_cr3(struct kvm_vcpu *vcpu, unsigned long cr3);
-void kvm_set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4);
+int kvm_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0);
+int kvm_set_cr3(struct kvm_vcpu *vcpu, unsigned long cr3);
+int kvm_set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4);
void kvm_set_cr8(struct kvm_vcpu *vcpu, unsigned long cr8);
int kvm_set_dr(struct kvm_vcpu *vcpu, int dr, unsigned long val);
int kvm_get_dr(struct kvm_vcpu *vcpu, int dr, unsigned long *val);
unsigned long kvm_get_cr8(struct kvm_vcpu *vcpu);
void kvm_lmsw(struct kvm_vcpu *vcpu, unsigned long msw);
void kvm_get_cs_db_l_bits(struct kvm_vcpu *vcpu, int *db, int *l);
+int kvm_set_xcr(struct kvm_vcpu *vcpu, u32 index, u64 xcr);
int kvm_get_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata);
int kvm_set_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 data);
@@ -630,12 +616,7 @@ int kvm_pic_set_irq(void *opaque, int irq, int level);
void kvm_inject_nmi(struct kvm_vcpu *vcpu);
-void fx_init(struct kvm_vcpu *vcpu);
-
-int emulator_write_emulated(unsigned long addr,
- const void *val,
- unsigned int bytes,
- struct kvm_vcpu *vcpu);
+int fx_init(struct kvm_vcpu *vcpu);
void kvm_mmu_flush_tlb(struct kvm_vcpu *vcpu);
void kvm_mmu_pte_write(struct kvm_vcpu *vcpu, gpa_t gpa,
@@ -664,8 +645,6 @@ void kvm_disable_tdp(void);
int complete_pio(struct kvm_vcpu *vcpu);
bool kvm_check_iopl(struct kvm_vcpu *vcpu);
-struct kvm_memory_slot *gfn_to_memslot_unaliased(struct kvm *kvm, gfn_t gfn);
-
static inline struct kvm_mmu_page *page_header(hpa_t shadow_page)
{
struct page *page = pfn_to_page(shadow_page >> PAGE_SHIFT);
@@ -719,21 +698,6 @@ static inline unsigned long read_msr(unsigned long msr)
}
#endif
-static inline void kvm_fx_save(struct i387_fxsave_struct *image)
-{
- asm("fxsave (%0)":: "r" (image));
-}
-
-static inline void kvm_fx_restore(struct i387_fxsave_struct *image)
-{
- asm("fxrstor (%0)":: "r" (image));
-}
-
-static inline void kvm_fx_finit(void)
-{
- asm("finit");
-}
-
static inline u32 get_rdx_init_val(void)
{
return 0x600; /* P6 family */
diff --git a/arch/x86/include/asm/local64.h b/arch/x86/include/asm/local64.h
new file mode 100644
index 00000000000..36c93b5cc23
--- /dev/null
+++ b/arch/x86/include/asm/local64.h
@@ -0,0 +1 @@
+#include <asm-generic/local64.h>
diff --git a/arch/x86/include/asm/mce.h b/arch/x86/include/asm/mce.h
index f32a4301c4d..c62c13cb978 100644
--- a/arch/x86/include/asm/mce.h
+++ b/arch/x86/include/asm/mce.h
@@ -38,6 +38,10 @@
#define MCM_ADDR_MEM 3 /* memory address */
#define MCM_ADDR_GENERIC 7 /* generic */
+/* CTL2 register defines */
+#define MCI_CTL2_CMCI_EN (1ULL << 30)
+#define MCI_CTL2_CMCI_THRESHOLD_MASK 0x7fffULL
+
#define MCJ_CTX_MASK 3
#define MCJ_CTX(flags) ((flags) & MCJ_CTX_MASK)
#define MCJ_CTX_RANDOM 0 /* inject context: random */
diff --git a/arch/x86/include/asm/mrst.h b/arch/x86/include/asm/mrst.h
index 451d30e7f62..16350740edf 100644
--- a/arch/x86/include/asm/mrst.h
+++ b/arch/x86/include/asm/mrst.h
@@ -13,6 +13,32 @@
extern int pci_mrst_init(void);
int __init sfi_parse_mrtc(struct sfi_table_header *table);
+/*
+ * Medfield is the follow-up of Moorestown, it combines two chip solution into
+ * one. Other than that it also added always-on and constant tsc and lapic
+ * timers. Medfield is the platform name, and the chip name is called Penwell
+ * we treat Medfield/Penwell as a variant of Moorestown. Penwell can be
+ * identified via MSRs.
+ */
+enum mrst_cpu_type {
+ MRST_CPU_CHIP_LINCROFT = 1,
+ MRST_CPU_CHIP_PENWELL,
+};
+
+extern enum mrst_cpu_type __mrst_cpu_chip;
+static enum mrst_cpu_type mrst_identify_cpu(void)
+{
+ return __mrst_cpu_chip;
+}
+
+enum mrst_timer_options {
+ MRST_TIMER_DEFAULT,
+ MRST_TIMER_APBT_ONLY,
+ MRST_TIMER_LAPIC_APBT,
+};
+
+extern enum mrst_timer_options mrst_timer_options;
+
#define SFI_MTMR_MAX_NUM 8
#define SFI_MRTC_MAX 8
diff --git a/arch/x86/include/asm/msr-index.h b/arch/x86/include/asm/msr-index.h
index 8c7ae431862..986f7790fdb 100644
--- a/arch/x86/include/asm/msr-index.h
+++ b/arch/x86/include/asm/msr-index.h
@@ -20,6 +20,7 @@
#define _EFER_LMA 10 /* Long mode active (read-only) */
#define _EFER_NX 11 /* No execute enable */
#define _EFER_SVME 12 /* Enable virtualization */
+#define _EFER_LMSLE 13 /* Long Mode Segment Limit Enable */
#define _EFER_FFXSR 14 /* Enable Fast FXSAVE/FXRSTOR */
#define EFER_SCE (1<<_EFER_SCE)
@@ -27,6 +28,7 @@
#define EFER_LMA (1<<_EFER_LMA)
#define EFER_NX (1<<_EFER_NX)
#define EFER_SVME (1<<_EFER_SVME)
+#define EFER_LMSLE (1<<_EFER_LMSLE)
#define EFER_FFXSR (1<<_EFER_FFXSR)
/* Intel MSRs. Some also available on other CPUs */
@@ -94,9 +96,6 @@
#define MSR_IA32_MC0_CTL2 0x00000280
#define MSR_IA32_MCx_CTL2(x) (MSR_IA32_MC0_CTL2 + (x))
-#define CMCI_EN (1ULL << 30)
-#define CMCI_THRESHOLD_MASK 0xffffULL
-
#define MSR_P6_PERFCTR0 0x000000c1
#define MSR_P6_PERFCTR1 0x000000c2
#define MSR_P6_EVNTSEL0 0x00000186
@@ -159,8 +158,6 @@
#define MSR_K7_FID_VID_STATUS 0xc0010042
/* K6 MSRs */
-#define MSR_K6_EFER 0xc0000080
-#define MSR_K6_STAR 0xc0000081
#define MSR_K6_WHCR 0xc0000082
#define MSR_K6_UWCCR 0xc0000085
#define MSR_K6_EPMR 0xc0000086
@@ -224,12 +221,14 @@
#define MSR_IA32_THERM_CONTROL 0x0000019a
#define MSR_IA32_THERM_INTERRUPT 0x0000019b
-#define THERM_INT_LOW_ENABLE (1 << 0)
-#define THERM_INT_HIGH_ENABLE (1 << 1)
+#define THERM_INT_HIGH_ENABLE (1 << 0)
+#define THERM_INT_LOW_ENABLE (1 << 1)
+#define THERM_INT_PLN_ENABLE (1 << 24)
#define MSR_IA32_THERM_STATUS 0x0000019c
#define THERM_STATUS_PROCHOT (1 << 0)
+#define THERM_STATUS_POWER_LIMIT (1 << 10)
#define MSR_THERM2_CTL 0x0000019d
@@ -239,6 +238,19 @@
#define MSR_IA32_TEMPERATURE_TARGET 0x000001a2
+#define MSR_IA32_ENERGY_PERF_BIAS 0x000001b0
+
+#define MSR_IA32_PACKAGE_THERM_STATUS 0x000001b1
+
+#define PACKAGE_THERM_STATUS_PROCHOT (1 << 0)
+#define PACKAGE_THERM_STATUS_POWER_LIMIT (1 << 10)
+
+#define MSR_IA32_PACKAGE_THERM_INTERRUPT 0x000001b2
+
+#define PACKAGE_THERM_INT_HIGH_ENABLE (1 << 0)
+#define PACKAGE_THERM_INT_LOW_ENABLE (1 << 1)
+#define PACKAGE_THERM_INT_PLN_ENABLE (1 << 24)
+
/* MISC_ENABLE bits: architectural */
#define MSR_IA32_MISC_ENABLE_FAST_STRING (1ULL << 0)
#define MSR_IA32_MISC_ENABLE_TCC (1ULL << 1)
diff --git a/arch/x86/include/asm/msr.h b/arch/x86/include/asm/msr.h
index c5bc4c2d33f..084ef95274c 100644
--- a/arch/x86/include/asm/msr.h
+++ b/arch/x86/include/asm/msr.h
@@ -148,8 +148,8 @@ static inline unsigned long long native_read_pmc(int counter)
#define rdmsr(msr, val1, val2) \
do { \
u64 __val = native_read_msr((msr)); \
- (val1) = (u32)__val; \
- (val2) = (u32)(__val >> 32); \
+ (void)((val1) = (u32)__val); \
+ (void)((val2) = (u32)(__val >> 32)); \
} while (0)
static inline void wrmsr(unsigned msr, unsigned low, unsigned high)
diff --git a/arch/x86/include/asm/nmi.h b/arch/x86/include/asm/nmi.h
index 93da9c3f334..932f0f86b4b 100644
--- a/arch/x86/include/asm/nmi.h
+++ b/arch/x86/include/asm/nmi.h
@@ -17,7 +17,9 @@ int do_nmi_callback(struct pt_regs *regs, int cpu);
extern void die_nmi(char *str, struct pt_regs *regs, int do_panic);
extern int check_nmi_watchdog(void);
+#if !defined(CONFIG_LOCKUP_DETECTOR)
extern int nmi_watchdog_enabled;
+#endif
extern int avail_to_resrv_perfctr_nmi_bit(unsigned int);
extern int reserve_perfctr_nmi(unsigned int);
extern void release_perfctr_nmi(unsigned int);
diff --git a/arch/x86/include/asm/olpc_ofw.h b/arch/x86/include/asm/olpc_ofw.h
new file mode 100644
index 00000000000..08fde475cb3
--- /dev/null
+++ b/arch/x86/include/asm/olpc_ofw.h
@@ -0,0 +1,31 @@
+#ifndef _ASM_X86_OLPC_OFW_H
+#define _ASM_X86_OLPC_OFW_H
+
+/* index into the page table containing the entry OFW occupies */
+#define OLPC_OFW_PDE_NR 1022
+
+#define OLPC_OFW_SIG 0x2057464F /* aka "OFW " */
+
+#ifdef CONFIG_OLPC_OPENFIRMWARE
+
+/* run an OFW command by calling into the firmware */
+#define olpc_ofw(name, args, res) \
+ __olpc_ofw((name), ARRAY_SIZE(args), args, ARRAY_SIZE(res), res)
+
+extern int __olpc_ofw(const char *name, int nr_args, const void **args, int nr_res,
+ void **res);
+
+/* determine whether OFW is available and lives in the proper memory */
+extern void olpc_ofw_detect(void);
+
+/* install OFW's pde permanently into the kernel's pgtable */
+extern void setup_olpc_ofw_pgd(void);
+
+#else /* !CONFIG_OLPC_OPENFIRMWARE */
+
+static inline void olpc_ofw_detect(void) { }
+static inline void setup_olpc_ofw_pgd(void) { }
+
+#endif /* !CONFIG_OLPC_OPENFIRMWARE */
+
+#endif /* _ASM_X86_OLPC_OFW_H */
diff --git a/arch/x86/include/asm/pci_x86.h b/arch/x86/include/asm/pci_x86.h
index cd2a31dc5fb..49c7219826f 100644
--- a/arch/x86/include/asm/pci_x86.h
+++ b/arch/x86/include/asm/pci_x86.h
@@ -30,6 +30,7 @@
#define PCI_HAS_IO_ECS 0x40000
#define PCI_NOASSIGN_ROMS 0x80000
#define PCI_ROOT_NO_CRS 0x100000
+#define PCI_NOASSIGN_BARS 0x200000
extern unsigned int pci_probe;
extern unsigned long pirq_table_addr;
diff --git a/arch/x86/include/asm/perf_event.h b/arch/x86/include/asm/perf_event.h
index 254883d0c7e..6e742cc4251 100644
--- a/arch/x86/include/asm/perf_event.h
+++ b/arch/x86/include/asm/perf_event.h
@@ -68,8 +68,9 @@ union cpuid10_eax {
union cpuid10_edx {
struct {
- unsigned int num_counters_fixed:4;
- unsigned int reserved:28;
+ unsigned int num_counters_fixed:5;
+ unsigned int bit_width_fixed:8;
+ unsigned int reserved:19;
} split;
unsigned int full;
};
@@ -140,6 +141,19 @@ extern unsigned long perf_instruction_pointer(struct pt_regs *regs);
extern unsigned long perf_misc_flags(struct pt_regs *regs);
#define perf_misc_flags(regs) perf_misc_flags(regs)
+#include <asm/stacktrace.h>
+
+/*
+ * We abuse bit 3 from flags to pass exact information, see perf_misc_flags
+ * and the comment with PERF_EFLAGS_EXACT.
+ */
+#define perf_arch_fetch_caller_regs(regs, __ip) { \
+ (regs)->ip = (__ip); \
+ (regs)->bp = caller_frame_pointer(); \
+ (regs)->cs = __KERNEL_CS; \
+ regs->flags = 0; \
+}
+
#else
static inline void init_hw_perf_events(void) { }
static inline void perf_events_lapic_init(void) { }
diff --git a/arch/x86/include/asm/perf_event_p4.h b/arch/x86/include/asm/perf_event_p4.h
index 64a8ebff06f..def500776b1 100644
--- a/arch/x86/include/asm/perf_event_p4.h
+++ b/arch/x86/include/asm/perf_event_p4.h
@@ -19,7 +19,6 @@
#define ARCH_P4_RESERVED_ESCR (2) /* IQ_ESCR(0,1) not always present */
#define ARCH_P4_MAX_ESCR (ARCH_P4_TOTAL_ESCR - ARCH_P4_RESERVED_ESCR)
#define ARCH_P4_MAX_CCCR (18)
-#define ARCH_P4_MAX_COUNTER (ARCH_P4_MAX_CCCR / 2)
#define P4_ESCR_EVENT_MASK 0x7e000000U
#define P4_ESCR_EVENT_SHIFT 25
@@ -71,10 +70,6 @@
#define P4_CCCR_THRESHOLD(v) ((v) << P4_CCCR_THRESHOLD_SHIFT)
#define P4_CCCR_ESEL(v) ((v) << P4_CCCR_ESCR_SELECT_SHIFT)
-/* Custom bits in reerved CCCR area */
-#define P4_CCCR_CACHE_OPS_MASK 0x0000003fU
-
-
/* Non HT mask */
#define P4_CCCR_MASK \
(P4_CCCR_OVF | \
@@ -106,8 +101,7 @@
* ESCR and CCCR but rather an only packed value should
* be unpacked and written to a proper addresses
*
- * the base idea is to pack as much info as
- * possible
+ * the base idea is to pack as much info as possible
*/
#define p4_config_pack_escr(v) (((u64)(v)) << 32)
#define p4_config_pack_cccr(v) (((u64)(v)) & 0xffffffffULL)
@@ -130,8 +124,6 @@
t; \
})
-#define p4_config_unpack_cache_event(v) (((u64)(v)) & P4_CCCR_CACHE_OPS_MASK)
-
#define P4_CONFIG_HT_SHIFT 63
#define P4_CONFIG_HT (1ULL << P4_CONFIG_HT_SHIFT)
@@ -214,6 +206,12 @@ static inline u32 p4_default_escr_conf(int cpu, int exclude_os, int exclude_usr)
return escr;
}
+/*
+ * This are the events which should be used in "Event Select"
+ * field of ESCR register, they are like unique keys which allow
+ * the kernel to determinate which CCCR and COUNTER should be
+ * used to track an event
+ */
enum P4_EVENTS {
P4_EVENT_TC_DELIVER_MODE,
P4_EVENT_BPU_FETCH_REQUEST,
@@ -561,7 +559,7 @@ enum P4_EVENT_OPCODES {
* a caller should use P4_ESCR_EMASK_NAME helper to
* pick the EventMask needed, for example
*
- * P4_ESCR_EMASK_NAME(P4_EVENT_TC_DELIVER_MODE, DD)
+ * P4_ESCR_EMASK_BIT(P4_EVENT_TC_DELIVER_MODE, DD)
*/
enum P4_ESCR_EMASKS {
P4_GEN_ESCR_EMASK(P4_EVENT_TC_DELIVER_MODE, DD, 0),
@@ -753,43 +751,50 @@ enum P4_ESCR_EMASKS {
P4_GEN_ESCR_EMASK(P4_EVENT_INSTR_COMPLETED, BOGUS, 1),
};
-/* P4 PEBS: stale for a while */
-#define P4_PEBS_METRIC_MASK 0x00001fffU
-#define P4_PEBS_UOB_TAG 0x01000000U
-#define P4_PEBS_ENABLE 0x02000000U
-
-/* Replay metrics for MSR_IA32_PEBS_ENABLE and MSR_P4_PEBS_MATRIX_VERT */
-#define P4_PEBS__1stl_cache_load_miss_retired 0x3000001
-#define P4_PEBS__2ndl_cache_load_miss_retired 0x3000002
-#define P4_PEBS__dtlb_load_miss_retired 0x3000004
-#define P4_PEBS__dtlb_store_miss_retired 0x3000004
-#define P4_PEBS__dtlb_all_miss_retired 0x3000004
-#define P4_PEBS__tagged_mispred_branch 0x3018000
-#define P4_PEBS__mob_load_replay_retired 0x3000200
-#define P4_PEBS__split_load_retired 0x3000400
-#define P4_PEBS__split_store_retired 0x3000400
-
-#define P4_VERT__1stl_cache_load_miss_retired 0x0000001
-#define P4_VERT__2ndl_cache_load_miss_retired 0x0000001
-#define P4_VERT__dtlb_load_miss_retired 0x0000001
-#define P4_VERT__dtlb_store_miss_retired 0x0000002
-#define P4_VERT__dtlb_all_miss_retired 0x0000003
-#define P4_VERT__tagged_mispred_branch 0x0000010
-#define P4_VERT__mob_load_replay_retired 0x0000001
-#define P4_VERT__split_load_retired 0x0000001
-#define P4_VERT__split_store_retired 0x0000002
-
-enum P4_CACHE_EVENTS {
- P4_CACHE__NONE,
-
- P4_CACHE__1stl_cache_load_miss_retired,
- P4_CACHE__2ndl_cache_load_miss_retired,
- P4_CACHE__dtlb_load_miss_retired,
- P4_CACHE__dtlb_store_miss_retired,
- P4_CACHE__itlb_reference_hit,
- P4_CACHE__itlb_reference_miss,
-
- P4_CACHE__MAX
+/*
+ * P4 PEBS specifics (Replay Event only)
+ *
+ * Format (bits):
+ * 0-6: metric from P4_PEBS_METRIC enum
+ * 7 : reserved
+ * 8 : reserved
+ * 9-11 : reserved
+ *
+ * Note we have UOP and PEBS bits reserved for now
+ * just in case if we will need them once
+ */
+#define P4_PEBS_CONFIG_ENABLE (1 << 7)
+#define P4_PEBS_CONFIG_UOP_TAG (1 << 8)
+#define P4_PEBS_CONFIG_METRIC_MASK 0x3f
+#define P4_PEBS_CONFIG_MASK 0xff
+
+/*
+ * mem: Only counters MSR_IQ_COUNTER4 (16) and
+ * MSR_IQ_COUNTER5 (17) are allowed for PEBS sampling
+ */
+#define P4_PEBS_ENABLE 0x02000000U
+#define P4_PEBS_ENABLE_UOP_TAG 0x01000000U
+
+#define p4_config_unpack_metric(v) (((u64)(v)) & P4_PEBS_CONFIG_METRIC_MASK)
+#define p4_config_unpack_pebs(v) (((u64)(v)) & P4_PEBS_CONFIG_MASK)
+
+#define p4_config_pebs_has(v, mask) (p4_config_unpack_pebs(v) & (mask))
+
+enum P4_PEBS_METRIC {
+ P4_PEBS_METRIC__none,
+
+ P4_PEBS_METRIC__1stl_cache_load_miss_retired,
+ P4_PEBS_METRIC__2ndl_cache_load_miss_retired,
+ P4_PEBS_METRIC__dtlb_load_miss_retired,
+ P4_PEBS_METRIC__dtlb_store_miss_retired,
+ P4_PEBS_METRIC__dtlb_all_miss_retired,
+ P4_PEBS_METRIC__tagged_mispred_branch,
+ P4_PEBS_METRIC__mob_load_replay_retired,
+ P4_PEBS_METRIC__split_load_retired,
+ P4_PEBS_METRIC__split_store_retired,
+
+ P4_PEBS_METRIC__max
};
#endif /* PERF_EVENT_P4_H */
+
diff --git a/arch/x86/include/asm/processor.h b/arch/x86/include/asm/processor.h
index 7e5c6a60b8e..325b7bdbeba 100644
--- a/arch/x86/include/asm/processor.h
+++ b/arch/x86/include/asm/processor.h
@@ -762,6 +762,7 @@ extern void init_c1e_mask(void);
extern unsigned long boot_option_idle_override;
extern unsigned long idle_halt;
extern unsigned long idle_nomwait;
+extern bool c1e_detected;
/*
* on systems with caches, caches must be flashed as the absolute
@@ -1025,4 +1026,24 @@ unsigned long calc_aperfmperf_ratio(struct aperfmperf *old,
return ratio;
}
+/*
+ * AMD errata checking
+ */
+#ifdef CONFIG_CPU_SUP_AMD
+extern const int amd_erratum_383[];
+extern const int amd_erratum_400[];
+extern bool cpu_has_amd_erratum(const int *);
+
+#define AMD_LEGACY_ERRATUM(...) { -1, __VA_ARGS__, 0 }
+#define AMD_OSVW_ERRATUM(osvw_id, ...) { osvw_id, __VA_ARGS__, 0 }
+#define AMD_MODEL_RANGE(f, m_start, s_start, m_end, s_end) \
+ ((f << 24) | (m_start << 16) | (s_start << 12) | (m_end << 4) | (s_end))
+#define AMD_MODEL_RANGE_FAMILY(range) (((range) >> 24) & 0xff)
+#define AMD_MODEL_RANGE_START(range) (((range) >> 12) & 0xfff)
+#define AMD_MODEL_RANGE_END(range) ((range) & 0xfff)
+
+#else
+#define cpu_has_amd_erratum(x) (false)
+#endif /* CONFIG_CPU_SUP_AMD */
+
#endif /* _ASM_X86_PROCESSOR_H */
diff --git a/arch/x86/include/asm/required-features.h b/arch/x86/include/asm/required-features.h
index 64cf2d24fad..6c7fc25f2c3 100644
--- a/arch/x86/include/asm/required-features.h
+++ b/arch/x86/include/asm/required-features.h
@@ -84,5 +84,7 @@
#define REQUIRED_MASK5 0
#define REQUIRED_MASK6 0
#define REQUIRED_MASK7 0
+#define REQUIRED_MASK8 0
+#define REQUIRED_MASK9 0
#endif /* _ASM_X86_REQUIRED_FEATURES_H */
diff --git a/arch/x86/include/asm/rwsem.h b/arch/x86/include/asm/rwsem.h
index 606ede12697..d1e41b0f9b6 100644
--- a/arch/x86/include/asm/rwsem.h
+++ b/arch/x86/include/asm/rwsem.h
@@ -118,7 +118,7 @@ static inline void __down_read(struct rw_semaphore *sem)
{
asm volatile("# beginning down_read\n\t"
LOCK_PREFIX _ASM_INC "(%1)\n\t"
- /* adds 0x00000001, returns the old value */
+ /* adds 0x00000001 */
" jns 1f\n"
" call call_rwsem_down_read_failed\n"
"1:\n\t"
@@ -156,11 +156,9 @@ static inline int __down_read_trylock(struct rw_semaphore *sem)
static inline void __down_write_nested(struct rw_semaphore *sem, int subclass)
{
rwsem_count_t tmp;
-
- tmp = RWSEM_ACTIVE_WRITE_BIAS;
asm volatile("# beginning down_write\n\t"
LOCK_PREFIX " xadd %1,(%2)\n\t"
- /* subtract 0x0000ffff, returns the old value */
+ /* adds 0xffff0001, returns the old value */
" test %1,%1\n\t"
/* was the count 0 before? */
" jz 1f\n"
@@ -168,7 +166,7 @@ static inline void __down_write_nested(struct rw_semaphore *sem, int subclass)
"1:\n"
"# ending down_write"
: "+m" (sem->count), "=d" (tmp)
- : "a" (sem), "1" (tmp)
+ : "a" (sem), "1" (RWSEM_ACTIVE_WRITE_BIAS)
: "memory", "cc");
}
@@ -195,16 +193,16 @@ static inline int __down_write_trylock(struct rw_semaphore *sem)
*/
static inline void __up_read(struct rw_semaphore *sem)
{
- rwsem_count_t tmp = -RWSEM_ACTIVE_READ_BIAS;
+ rwsem_count_t tmp;
asm volatile("# beginning __up_read\n\t"
LOCK_PREFIX " xadd %1,(%2)\n\t"
/* subtracts 1, returns the old value */
" jns 1f\n\t"
- " call call_rwsem_wake\n"
+ " call call_rwsem_wake\n" /* expects old value in %edx */
"1:\n"
"# ending __up_read\n"
: "+m" (sem->count), "=d" (tmp)
- : "a" (sem), "1" (tmp)
+ : "a" (sem), "1" (-RWSEM_ACTIVE_READ_BIAS)
: "memory", "cc");
}
@@ -216,10 +214,9 @@ static inline void __up_write(struct rw_semaphore *sem)
rwsem_count_t tmp;
asm volatile("# beginning __up_write\n\t"
LOCK_PREFIX " xadd %1,(%2)\n\t"
- /* tries to transition
- 0xffff0001 -> 0x00000000 */
- " jz 1f\n"
- " call call_rwsem_wake\n"
+ /* subtracts 0xffff0001, returns the old value */
+ " jns 1f\n\t"
+ " call call_rwsem_wake\n" /* expects old value in %edx */
"1:\n\t"
"# ending __up_write\n"
: "+m" (sem->count), "=d" (tmp)
diff --git a/arch/x86/include/asm/setup.h b/arch/x86/include/asm/setup.h
index 86b1506f417..ef292c792d7 100644
--- a/arch/x86/include/asm/setup.h
+++ b/arch/x86/include/asm/setup.h
@@ -82,7 +82,7 @@ void *extend_brk(size_t size, size_t align);
* executable.)
*/
#define RESERVE_BRK(name,sz) \
- static void __section(.discard) __used \
+ static void __section(.discard.text) __used \
__brk_reservation_fn_##name##__(void) { \
asm volatile ( \
".pushsection .brk_reservation,\"aw\",@nobits;" \
diff --git a/arch/x86/include/asm/stacktrace.h b/arch/x86/include/asm/stacktrace.h
index 4dab78edbad..2b16a2ad23d 100644
--- a/arch/x86/include/asm/stacktrace.h
+++ b/arch/x86/include/asm/stacktrace.h
@@ -1,6 +1,13 @@
+/*
+ * Copyright (C) 1991, 1992 Linus Torvalds
+ * Copyright (C) 2000, 2001, 2002 Andi Kleen, SuSE Labs
+ */
+
#ifndef _ASM_X86_STACKTRACE_H
#define _ASM_X86_STACKTRACE_H
+#include <linux/uaccess.h>
+
extern int kstack_depth_to_print;
struct thread_info;
@@ -42,4 +49,46 @@ void dump_trace(struct task_struct *tsk, struct pt_regs *regs,
unsigned long *stack, unsigned long bp,
const struct stacktrace_ops *ops, void *data);
+#ifdef CONFIG_X86_32
+#define STACKSLOTS_PER_LINE 8
+#define get_bp(bp) asm("movl %%ebp, %0" : "=r" (bp) :)
+#else
+#define STACKSLOTS_PER_LINE 4
+#define get_bp(bp) asm("movq %%rbp, %0" : "=r" (bp) :)
+#endif
+
+extern void
+show_trace_log_lvl(struct task_struct *task, struct pt_regs *regs,
+ unsigned long *stack, unsigned long bp, char *log_lvl);
+
+extern void
+show_stack_log_lvl(struct task_struct *task, struct pt_regs *regs,
+ unsigned long *sp, unsigned long bp, char *log_lvl);
+
+extern unsigned int code_bytes;
+
+/* The form of the top of the frame on the stack */
+struct stack_frame {
+ struct stack_frame *next_frame;
+ unsigned long return_address;
+};
+
+struct stack_frame_ia32 {
+ u32 next_frame;
+ u32 return_address;
+};
+
+static inline unsigned long caller_frame_pointer(void)
+{
+ struct stack_frame *frame;
+
+ get_bp(frame);
+
+#ifdef CONFIG_FRAME_POINTER
+ frame = frame->next_frame;
+#endif
+
+ return (unsigned long)frame;
+}
+
#endif /* _ASM_X86_STACKTRACE_H */
diff --git a/arch/x86/include/asm/system.h b/arch/x86/include/asm/system.h
index e7f4d33c55e..33ecc3ea878 100644
--- a/arch/x86/include/asm/system.h
+++ b/arch/x86/include/asm/system.h
@@ -457,4 +457,11 @@ static __always_inline void rdtsc_barrier(void)
alternative(ASM_NOP3, "lfence", X86_FEATURE_LFENCE_RDTSC);
}
+/*
+ * We handle most unaligned accesses in hardware. On the other hand
+ * unaligned DMA can be quite expensive on some Nehalem processors.
+ *
+ * Based on this we disable the IP header alignment in network drivers.
+ */
+#define NET_IP_ALIGN 0
#endif /* _ASM_X86_SYSTEM_H */
diff --git a/arch/x86/include/asm/vmx.h b/arch/x86/include/asm/vmx.h
index 9e6779f7cf2..9f0cbd987d5 100644
--- a/arch/x86/include/asm/vmx.h
+++ b/arch/x86/include/asm/vmx.h
@@ -257,6 +257,7 @@ enum vmcs_field {
#define EXIT_REASON_IO_INSTRUCTION 30
#define EXIT_REASON_MSR_READ 31
#define EXIT_REASON_MSR_WRITE 32
+#define EXIT_REASON_INVALID_STATE 33
#define EXIT_REASON_MWAIT_INSTRUCTION 36
#define EXIT_REASON_MONITOR_INSTRUCTION 39
#define EXIT_REASON_PAUSE_INSTRUCTION 40
@@ -266,6 +267,7 @@ enum vmcs_field {
#define EXIT_REASON_EPT_VIOLATION 48
#define EXIT_REASON_EPT_MISCONFIG 49
#define EXIT_REASON_WBINVD 54
+#define EXIT_REASON_XSETBV 55
/*
* Interruption-information format
@@ -375,6 +377,9 @@ enum vmcs_field {
#define VMX_EPT_EXTENT_CONTEXT_BIT (1ull << 25)
#define VMX_EPT_EXTENT_GLOBAL_BIT (1ull << 26)
+#define VMX_VPID_EXTENT_SINGLE_CONTEXT_BIT (1ull << 9) /* (41 - 32) */
+#define VMX_VPID_EXTENT_GLOBAL_CONTEXT_BIT (1ull << 10) /* (42 - 32) */
+
#define VMX_EPT_DEFAULT_GAW 3
#define VMX_EPT_MAX_GAW 0x4
#define VMX_EPT_MT_EPTE_SHIFT 3
diff --git a/arch/x86/include/asm/xen/hypercall.h b/arch/x86/include/asm/xen/hypercall.h
index 9c371e4a9fa..7fda040a76c 100644
--- a/arch/x86/include/asm/xen/hypercall.h
+++ b/arch/x86/include/asm/xen/hypercall.h
@@ -417,6 +417,12 @@ HYPERVISOR_nmi_op(unsigned long op, unsigned long arg)
return _hypercall2(int, nmi_op, op, arg);
}
+static inline unsigned long __must_check
+HYPERVISOR_hvm_op(int op, void *arg)
+{
+ return _hypercall2(unsigned long, hvm_op, op, arg);
+}
+
static inline void
MULTI_fpu_taskswitch(struct multicall_entry *mcl, int set)
{
diff --git a/arch/x86/include/asm/xsave.h b/arch/x86/include/asm/xsave.h
index 2c4390cae22..c6ce2452f10 100644
--- a/arch/x86/include/asm/xsave.h
+++ b/arch/x86/include/asm/xsave.h
@@ -3,7 +3,8 @@
#include <linux/types.h>
#include <asm/processor.h>
-#include <asm/i387.h>
+
+#define XSTATE_CPUID 0x0000000d
#define XSTATE_FP 0x1
#define XSTATE_SSE 0x2
@@ -13,6 +14,12 @@
#define FXSAVE_SIZE 512
+#define XSAVE_HDR_SIZE 64
+#define XSAVE_HDR_OFFSET FXSAVE_SIZE
+
+#define XSAVE_YMM_SIZE 256
+#define XSAVE_YMM_OFFSET (XSAVE_HDR_SIZE + XSAVE_HDR_OFFSET)
+
/*
* These are the features that the OS can handle currently.
*/
@@ -26,10 +33,8 @@
extern unsigned int xstate_size;
extern u64 pcntxt_mask;
-extern struct xsave_struct *init_xstate_buf;
extern u64 xstate_fx_sw_bytes[USER_XSTATE_FX_SW_WORDS];
-extern void xsave_cntxt_init(void);
extern void xsave_init(void);
extern void update_regset_xstate_info(unsigned int size, u64 xstate_mask);
extern int init_fpu(struct task_struct *child);
@@ -59,6 +64,16 @@ static inline int fpu_xrstor_checking(struct fpu *fpu)
static inline int xsave_user(struct xsave_struct __user *buf)
{
int err;
+
+ /*
+ * Clear the xsave header first, so that reserved fields are
+ * initialized to zero.
+ */
+ err = __clear_user(&buf->xsave_hdr,
+ sizeof(struct xsave_hdr_struct));
+ if (unlikely(err))
+ return -EFAULT;
+
__asm__ __volatile__("1: .byte " REX_PREFIX "0x0f,0xae,0x27\n"
"2:\n"
".section .fixup,\"ax\"\n"
@@ -111,12 +126,25 @@ static inline void xrstor_state(struct xsave_struct *fx, u64 mask)
: "memory");
}
+static inline void xsave_state(struct xsave_struct *fx, u64 mask)
+{
+ u32 lmask = mask;
+ u32 hmask = mask >> 32;
+
+ asm volatile(".byte " REX_PREFIX "0x0f,0xae,0x27\n\t"
+ : : "D" (fx), "m" (*fx), "a" (lmask), "d" (hmask)
+ : "memory");
+}
+
static inline void fpu_xsave(struct fpu *fpu)
{
/* This, however, we can work around by forcing the compiler to select
an addressing mode that doesn't require extended registers. */
- __asm__ __volatile__(".byte " REX_PREFIX "0x0f,0xae,0x27"
- : : "D" (&(fpu->state->xsave)),
- "a" (-1), "d"(-1) : "memory");
+ alternative_input(
+ ".byte " REX_PREFIX "0x0f,0xae,0x27",
+ ".byte " REX_PREFIX "0x0f,0xae,0x37",
+ X86_FEATURE_XSAVEOPT,
+ [fx] "D" (&fpu->state->xsave), "a" (-1), "d" (-1) :
+ "memory");
}
#endif
diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile
index e77b2208372..0925676266b 100644
--- a/arch/x86/kernel/Makefile
+++ b/arch/x86/kernel/Makefile
@@ -104,6 +104,7 @@ obj-$(CONFIG_SCx200) += scx200.o
scx200-y += scx200_32.o
obj-$(CONFIG_OLPC) += olpc.o
+obj-$(CONFIG_OLPC_OPENFIRMWARE) += olpc_ofw.o
obj-$(CONFIG_X86_MRST) += mrst.o
microcode-y := microcode_core.o
diff --git a/arch/x86/kernel/acpi/realmode/wakeup.S b/arch/x86/kernel/acpi/realmode/wakeup.S
index 580b4e29601..28595d6df47 100644
--- a/arch/x86/kernel/acpi/realmode/wakeup.S
+++ b/arch/x86/kernel/acpi/realmode/wakeup.S
@@ -104,7 +104,7 @@ _start:
movl %eax, %ecx
orl %edx, %ecx
jz 1f
- movl $0xc0000080, %ecx
+ movl $MSR_EFER, %ecx
wrmsr
1:
diff --git a/arch/x86/kernel/acpi/sleep.c b/arch/x86/kernel/acpi/sleep.c
index fcc3c61fdec..33cec152070 100644
--- a/arch/x86/kernel/acpi/sleep.c
+++ b/arch/x86/kernel/acpi/sleep.c
@@ -2,7 +2,7 @@
* sleep.c - x86-specific ACPI sleep support.
*
* Copyright (C) 2001-2003 Patrick Mochel
- * Copyright (C) 2001-2003 Pavel Machek <pavel@suse.cz>
+ * Copyright (C) 2001-2003 Pavel Machek <pavel@ucw.cz>
*/
#include <linux/acpi.h>
diff --git a/arch/x86/kernel/alternative.c b/arch/x86/kernel/alternative.c
index 70237732a6c..f65ab8b014c 100644
--- a/arch/x86/kernel/alternative.c
+++ b/arch/x86/kernel/alternative.c
@@ -214,6 +214,7 @@ void __init_or_module apply_alternatives(struct alt_instr *start,
u8 *instr = a->instr;
BUG_ON(a->replacementlen > a->instrlen);
BUG_ON(a->instrlen > sizeof(insnbuf));
+ BUG_ON(a->cpuid >= NCAPINTS*32);
if (!boot_cpu_has(a->cpuid))
continue;
#ifdef CONFIG_X86_64
diff --git a/arch/x86/kernel/amd_iommu.c b/arch/x86/kernel/amd_iommu.c
index 0d20286d78c..fa044e1e30a 100644
--- a/arch/x86/kernel/amd_iommu.c
+++ b/arch/x86/kernel/amd_iommu.c
@@ -2572,6 +2572,11 @@ static phys_addr_t amd_iommu_iova_to_phys(struct iommu_domain *dom,
static int amd_iommu_domain_has_cap(struct iommu_domain *domain,
unsigned long cap)
{
+ switch (cap) {
+ case IOMMU_CAP_CACHE_COHERENCY:
+ return 1;
+ }
+
return 0;
}
@@ -2609,8 +2614,7 @@ int __init amd_iommu_init_passthrough(void)
pt_domain->mode |= PAGE_MODE_NONE;
- while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {
-
+ for_each_pci_dev(dev) {
if (!check_device(&dev->dev))
continue;
diff --git a/arch/x86/kernel/apb_timer.c b/arch/x86/kernel/apb_timer.c
index a35347501d3..8dd77800ff5 100644
--- a/arch/x86/kernel/apb_timer.c
+++ b/arch/x86/kernel/apb_timer.c
@@ -43,10 +43,11 @@
#include <asm/fixmap.h>
#include <asm/apb_timer.h>
+#include <asm/mrst.h>
#define APBT_MASK CLOCKSOURCE_MASK(32)
#define APBT_SHIFT 22
-#define APBT_CLOCKEVENT_RATING 150
+#define APBT_CLOCKEVENT_RATING 110
#define APBT_CLOCKSOURCE_RATING 250
#define APBT_MIN_DELTA_USEC 200
@@ -83,8 +84,6 @@ struct apbt_dev {
char name[10];
};
-int disable_apbt_percpu __cpuinitdata;
-
static DEFINE_PER_CPU(struct apbt_dev, cpu_apbt_dev);
#ifdef CONFIG_SMP
@@ -195,29 +194,6 @@ static struct clock_event_device apbt_clockevent = {
};
/*
- * if user does not want to use per CPU apb timer, just give it a lower rating
- * than local apic timer and skip the late per cpu timer init.
- */
-static inline int __init setup_x86_mrst_timer(char *arg)
-{
- if (!arg)
- return -EINVAL;
-
- if (strcmp("apbt_only", arg) == 0)
- disable_apbt_percpu = 0;
- else if (strcmp("lapic_and_apbt", arg) == 0)
- disable_apbt_percpu = 1;
- else {
- pr_warning("X86 MRST timer option %s not recognised"
- " use x86_mrst_timer=apbt_only or lapic_and_apbt\n",
- arg);
- return -EINVAL;
- }
- return 0;
-}
-__setup("x86_mrst_timer=", setup_x86_mrst_timer);
-
-/*
* start count down from 0xffff_ffff. this is done by toggling the enable bit
* then load initial load count to ~0.
*/
@@ -335,7 +311,7 @@ static int __init apbt_clockevent_register(void)
adev->num = smp_processor_id();
memcpy(&adev->evt, &apbt_clockevent, sizeof(struct clock_event_device));
- if (disable_apbt_percpu) {
+ if (mrst_timer_options == MRST_TIMER_LAPIC_APBT) {
apbt_clockevent.rating = APBT_CLOCKEVENT_RATING - 100;
global_clock_event = &adev->evt;
printk(KERN_DEBUG "%s clockevent registered as global\n",
@@ -429,7 +405,8 @@ static int apbt_cpuhp_notify(struct notifier_block *n,
static __init int apbt_late_init(void)
{
- if (disable_apbt_percpu || !apb_timer_block_enabled)
+ if (mrst_timer_options == MRST_TIMER_LAPIC_APBT ||
+ !apb_timer_block_enabled)
return 0;
/* This notifier should be called after workqueue is ready */
hotcpu_notifier(apbt_cpuhp_notify, -20);
@@ -450,6 +427,8 @@ static void apbt_set_mode(enum clock_event_mode mode,
int timer_num;
struct apbt_dev *adev = EVT_TO_APBT_DEV(evt);
+ BUG_ON(!apbt_virt_address);
+
timer_num = adev->num;
pr_debug("%s CPU %d timer %d mode=%d\n",
__func__, first_cpu(*evt->cpumask), timer_num, mode);
@@ -676,7 +655,7 @@ void __init apbt_time_init(void)
}
#ifdef CONFIG_SMP
/* kernel cmdline disable apb timer, so we will use lapic timers */
- if (disable_apbt_percpu) {
+ if (mrst_timer_options == MRST_TIMER_LAPIC_APBT) {
printk(KERN_INFO "apbt: disabled per cpu timer\n");
return;
}
diff --git a/arch/x86/kernel/aperture_64.c b/arch/x86/kernel/aperture_64.c
index b5d8b0bcf23..a2e0caf26e1 100644
--- a/arch/x86/kernel/aperture_64.c
+++ b/arch/x86/kernel/aperture_64.c
@@ -280,7 +280,7 @@ void __init early_gart_iommu_check(void)
* or BIOS forget to put that in reserved.
* try to update e820 to make that region as reserved.
*/
- u32 agp_aper_base = 0, agp_aper_order = 0;
+ u32 agp_aper_order = 0;
int i, fix, slot, valid_agp = 0;
u32 ctl;
u32 aper_size = 0, aper_order = 0, last_aper_order = 0;
@@ -291,7 +291,7 @@ void __init early_gart_iommu_check(void)
return;
/* This is mostly duplicate of iommu_hole_init */
- agp_aper_base = search_agp_bridge(&agp_aper_order, &valid_agp);
+ search_agp_bridge(&agp_aper_order, &valid_agp);
fix = 0;
for (i = 0; i < ARRAY_SIZE(bus_dev_ranges); i++) {
diff --git a/arch/x86/kernel/apic/Makefile b/arch/x86/kernel/apic/Makefile
index 565c1bfc507..910f20b457c 100644
--- a/arch/x86/kernel/apic/Makefile
+++ b/arch/x86/kernel/apic/Makefile
@@ -2,7 +2,12 @@
# Makefile for local APIC drivers and for the IO-APIC code
#
-obj-$(CONFIG_X86_LOCAL_APIC) += apic.o apic_noop.o probe_$(BITS).o ipi.o nmi.o
+obj-$(CONFIG_X86_LOCAL_APIC) += apic.o apic_noop.o probe_$(BITS).o ipi.o
+ifneq ($(CONFIG_HARDLOCKUP_DETECTOR),y)
+obj-$(CONFIG_X86_LOCAL_APIC) += nmi.o
+endif
+obj-$(CONFIG_HARDLOCKUP_DETECTOR) += hw_nmi.o
+
obj-$(CONFIG_X86_IO_APIC) += io_apic.o
obj-$(CONFIG_SMP) += ipi.o
diff --git a/arch/x86/kernel/apic/apic.c b/arch/x86/kernel/apic/apic.c
index a96489ee6ca..980508c7908 100644
--- a/arch/x86/kernel/apic/apic.c
+++ b/arch/x86/kernel/apic/apic.c
@@ -460,7 +460,7 @@ static void lapic_timer_broadcast(const struct cpumask *mask)
}
/*
- * Setup the local APIC timer for this CPU. Copy the initilized values
+ * Setup the local APIC timer for this CPU. Copy the initialized values
* of the boot CPU and register the clock event in the framework.
*/
static void __cpuinit setup_APIC_timer(void)
diff --git a/arch/x86/kernel/apic/es7000_32.c b/arch/x86/kernel/apic/es7000_32.c
index 425e53a87fe..8593582d802 100644
--- a/arch/x86/kernel/apic/es7000_32.c
+++ b/arch/x86/kernel/apic/es7000_32.c
@@ -129,7 +129,6 @@ int es7000_plat;
* GSI override for ES7000 platforms.
*/
-static unsigned int base;
static int __cpuinit wakeup_secondary_cpu_via_mip(int cpu, unsigned long eip)
{
diff --git a/arch/x86/kernel/apic/hw_nmi.c b/arch/x86/kernel/apic/hw_nmi.c
new file mode 100644
index 00000000000..cefd6942f0e
--- /dev/null
+++ b/arch/x86/kernel/apic/hw_nmi.c
@@ -0,0 +1,107 @@
+/*
+ * HW NMI watchdog support
+ *
+ * started by Don Zickus, Copyright (C) 2010 Red Hat, Inc.
+ *
+ * Arch specific calls to support NMI watchdog
+ *
+ * Bits copied from original nmi.c file
+ *
+ */
+#include <asm/apic.h>
+
+#include <linux/cpumask.h>
+#include <linux/kdebug.h>
+#include <linux/notifier.h>
+#include <linux/kprobes.h>
+#include <linux/nmi.h>
+#include <linux/module.h>
+
+/* For reliability, we're prepared to waste bits here. */
+static DECLARE_BITMAP(backtrace_mask, NR_CPUS) __read_mostly;
+
+u64 hw_nmi_get_sample_period(void)
+{
+ return (u64)(cpu_khz) * 1000 * 60;
+}
+
+#ifdef ARCH_HAS_NMI_WATCHDOG
+void arch_trigger_all_cpu_backtrace(void)
+{
+ int i;
+
+ cpumask_copy(to_cpumask(backtrace_mask), cpu_online_mask);
+
+ printk(KERN_INFO "sending NMI to all CPUs:\n");
+ apic->send_IPI_all(NMI_VECTOR);
+
+ /* Wait for up to 10 seconds for all CPUs to do the backtrace */
+ for (i = 0; i < 10 * 1000; i++) {
+ if (cpumask_empty(to_cpumask(backtrace_mask)))
+ break;
+ mdelay(1);
+ }
+}
+
+static int __kprobes
+arch_trigger_all_cpu_backtrace_handler(struct notifier_block *self,
+ unsigned long cmd, void *__args)
+{
+ struct die_args *args = __args;
+ struct pt_regs *regs;
+ int cpu = smp_processor_id();
+
+ switch (cmd) {
+ case DIE_NMI:
+ case DIE_NMI_IPI:
+ break;
+
+ default:
+ return NOTIFY_DONE;
+ }
+
+ regs = args->regs;
+
+ if (cpumask_test_cpu(cpu, to_cpumask(backtrace_mask))) {
+ static arch_spinlock_t lock = __ARCH_SPIN_LOCK_UNLOCKED;
+
+ arch_spin_lock(&lock);
+ printk(KERN_WARNING "NMI backtrace for cpu %d\n", cpu);
+ show_regs(regs);
+ dump_stack();
+ arch_spin_unlock(&lock);
+ cpumask_clear_cpu(cpu, to_cpumask(backtrace_mask));
+ return NOTIFY_STOP;
+ }
+
+ return NOTIFY_DONE;
+}
+
+static __read_mostly struct notifier_block backtrace_notifier = {
+ .notifier_call = arch_trigger_all_cpu_backtrace_handler,
+ .next = NULL,
+ .priority = 1
+};
+
+static int __init register_trigger_all_cpu_backtrace(void)
+{
+ register_die_notifier(&backtrace_notifier);
+ return 0;
+}
+early_initcall(register_trigger_all_cpu_backtrace);
+#endif
+
+/* STUB calls to mimic old nmi_watchdog behaviour */
+#if defined(CONFIG_X86_LOCAL_APIC)
+unsigned int nmi_watchdog = NMI_NONE;
+EXPORT_SYMBOL(nmi_watchdog);
+void acpi_nmi_enable(void) { return; }
+void acpi_nmi_disable(void) { return; }
+#endif
+atomic_t nmi_active = ATOMIC_INIT(0); /* oprofile uses this */
+EXPORT_SYMBOL(nmi_active);
+int unknown_nmi_panic;
+void cpu_nmi_set_wd_enabled(void) { return; }
+void stop_apic_nmi_watchdog(void *unused) { return; }
+void setup_apic_nmi_watchdog(void *unused) { return; }
+int __init check_nmi_watchdog(void) { return 0; }
diff --git a/arch/x86/kernel/apic/io_apic.c b/arch/x86/kernel/apic/io_apic.c
index e41ed24ab26..4dc0084ec1b 100644
--- a/arch/x86/kernel/apic/io_apic.c
+++ b/arch/x86/kernel/apic/io_apic.c
@@ -3397,7 +3397,7 @@ static int set_msi_irq_affinity(unsigned int irq, const struct cpumask *mask)
cfg = desc->chip_data;
- read_msi_msg_desc(desc, &msg);
+ get_cached_msi_msg_desc(desc, &msg);
msg.data &= ~MSI_DATA_VECTOR_MASK;
msg.data |= MSI_DATA_VECTOR(cfg->vector);
diff --git a/arch/x86/kernel/apic/nmi.c b/arch/x86/kernel/apic/nmi.c
index 1edaf15c0b8..a43f71cb30f 100644
--- a/arch/x86/kernel/apic/nmi.c
+++ b/arch/x86/kernel/apic/nmi.c
@@ -401,13 +401,6 @@ nmi_watchdog_tick(struct pt_regs *regs, unsigned reason)
int cpu = smp_processor_id();
int rc = 0;
- /* check for other users first */
- if (notify_die(DIE_NMI, "nmi", regs, reason, 2, SIGINT)
- == NOTIFY_STOP) {
- rc = 1;
- touched = 1;
- }
-
sum = get_timer_irqs(cpu);
if (__get_cpu_var(nmi_touch)) {
diff --git a/arch/x86/kernel/apm_32.c b/arch/x86/kernel/apm_32.c
index c4f9182ca3a..4c9c67bf09b 100644
--- a/arch/x86/kernel/apm_32.c
+++ b/arch/x86/kernel/apm_32.c
@@ -140,7 +140,7 @@
* is now the way life works).
* Fix thinko in suspend() (wrong return).
* Notify drivers on critical suspend.
- * Make kapmd absorb more idle time (Pavel Machek <pavel@suse.cz>
+ * Make kapmd absorb more idle time (Pavel Machek <pavel@ucw.cz>
* modified by sfr).
* Disable interrupts while we are suspended (Andy Henroid
* <andy_henroid@yahoo.com> fixed by sfr).
diff --git a/arch/x86/kernel/cpu/Makefile b/arch/x86/kernel/cpu/Makefile
index 3a785da34b6..3f0ebe429a0 100644
--- a/arch/x86/kernel/cpu/Makefile
+++ b/arch/x86/kernel/cpu/Makefile
@@ -12,11 +12,11 @@ endif
nostackp := $(call cc-option, -fno-stack-protector)
CFLAGS_common.o := $(nostackp)
-obj-y := intel_cacheinfo.o addon_cpuid_features.o
+obj-y := intel_cacheinfo.o scattered.o topology.o
obj-y += proc.o capflags.o powerflags.o common.o
obj-y += vmware.o hypervisor.o sched.o mshyperv.o
-obj-$(CONFIG_X86_32) += bugs.o cmpxchg.o
+obj-$(CONFIG_X86_32) += bugs.o
obj-$(CONFIG_X86_64) += bugs_64.o
obj-$(CONFIG_CPU_SUP_INTEL) += intel.o
diff --git a/arch/x86/kernel/cpu/amd.c b/arch/x86/kernel/cpu/amd.c
index e485825130d..60a57b13082 100644
--- a/arch/x86/kernel/cpu/amd.c
+++ b/arch/x86/kernel/cpu/amd.c
@@ -466,7 +466,7 @@ static void __cpuinit init_amd(struct cpuinfo_x86 *c)
}
}
- if (c->x86 == 0x10 || c->x86 == 0x11)
+ if (c->x86 >= 0x10)
set_cpu_cap(c, X86_FEATURE_REP_GOOD);
/* get apicid instead of initial apic id from cpuid */
@@ -529,7 +529,7 @@ static void __cpuinit init_amd(struct cpuinfo_x86 *c)
num_cache_leaves = 3;
}
- if (c->x86 >= 0xf && c->x86 <= 0x11)
+ if (c->x86 >= 0xf)
set_cpu_cap(c, X86_FEATURE_K8);
if (cpu_has_xmm2) {
@@ -546,7 +546,7 @@ static void __cpuinit init_amd(struct cpuinfo_x86 *c)
fam10h_check_enable_mmcfg();
}
- if (c == &boot_cpu_data && c->x86 >= 0xf && c->x86 <= 0x11) {
+ if (c == &boot_cpu_data && c->x86 >= 0xf) {
unsigned long long tseg;
/*
@@ -609,3 +609,74 @@ static const struct cpu_dev __cpuinitconst amd_cpu_dev = {
};
cpu_dev_register(amd_cpu_dev);
+
+/*
+ * AMD errata checking
+ *
+ * Errata are defined as arrays of ints using the AMD_LEGACY_ERRATUM() or
+ * AMD_OSVW_ERRATUM() macros. The latter is intended for newer errata that
+ * have an OSVW id assigned, which it takes as first argument. Both take a
+ * variable number of family-specific model-stepping ranges created by
+ * AMD_MODEL_RANGE(). Each erratum also has to be declared as extern const
+ * int[] in arch/x86/include/asm/processor.h.
+ *
+ * Example:
+ *
+ * const int amd_erratum_319[] =
+ * AMD_LEGACY_ERRATUM(AMD_MODEL_RANGE(0x10, 0x2, 0x1, 0x4, 0x2),
+ * AMD_MODEL_RANGE(0x10, 0x8, 0x0, 0x8, 0x0),
+ * AMD_MODEL_RANGE(0x10, 0x9, 0x0, 0x9, 0x0));
+ */
+
+const int amd_erratum_400[] =
+ AMD_OSVW_ERRATUM(1, AMD_MODEL_RANGE(0xf, 0x41, 0x2, 0xff, 0xf),
+ AMD_MODEL_RANGE(0x10, 0x2, 0x1, 0xff, 0xf));
+EXPORT_SYMBOL_GPL(amd_erratum_400);
+
+const int amd_erratum_383[] =
+ AMD_OSVW_ERRATUM(3, AMD_MODEL_RANGE(0x10, 0, 0, 0xff, 0xf));
+EXPORT_SYMBOL_GPL(amd_erratum_383);
+
+bool cpu_has_amd_erratum(const int *erratum)
+{
+ struct cpuinfo_x86 *cpu = &current_cpu_data;
+ int osvw_id = *erratum++;
+ u32 range;
+ u32 ms;
+
+ /*
+ * If called early enough that current_cpu_data hasn't been initialized
+ * yet, fall back to boot_cpu_data.
+ */
+ if (cpu->x86 == 0)
+ cpu = &boot_cpu_data;
+
+ if (cpu->x86_vendor != X86_VENDOR_AMD)
+ return false;
+
+ if (osvw_id >= 0 && osvw_id < 65536 &&
+ cpu_has(cpu, X86_FEATURE_OSVW)) {
+ u64 osvw_len;
+
+ rdmsrl(MSR_AMD64_OSVW_ID_LENGTH, osvw_len);
+ if (osvw_id < osvw_len) {
+ u64 osvw_bits;
+
+ rdmsrl(MSR_AMD64_OSVW_STATUS + (osvw_id >> 6),
+ osvw_bits);
+ return osvw_bits & (1ULL << (osvw_id & 0x3f));
+ }
+ }
+
+ /* OSVW unavailable or ID unknown, match family-model-stepping range */
+ ms = (cpu->x86_model << 8) | cpu->x86_mask;
+ while ((range = *erratum++))
+ if ((cpu->x86 == AMD_MODEL_RANGE_FAMILY(range)) &&
+ (ms >= AMD_MODEL_RANGE_START(range)) &&
+ (ms <= AMD_MODEL_RANGE_END(range)))
+ return true;
+
+ return false;
+}
+
+EXPORT_SYMBOL_GPL(cpu_has_amd_erratum);
diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c
index 68e4a6f2211..490dac63c2d 100644
--- a/arch/x86/kernel/cpu/common.c
+++ b/arch/x86/kernel/cpu/common.c
@@ -140,10 +140,18 @@ EXPORT_PER_CPU_SYMBOL_GPL(gdt_page);
static int __init x86_xsave_setup(char *s)
{
setup_clear_cpu_cap(X86_FEATURE_XSAVE);
+ setup_clear_cpu_cap(X86_FEATURE_XSAVEOPT);
return 1;
}
__setup("noxsave", x86_xsave_setup);
+static int __init x86_xsaveopt_setup(char *s)
+{
+ setup_clear_cpu_cap(X86_FEATURE_XSAVEOPT);
+ return 1;
+}
+__setup("noxsaveopt", x86_xsaveopt_setup);
+
#ifdef CONFIG_X86_32
static int cachesize_override __cpuinitdata = -1;
static int disable_x86_serial_nr __cpuinitdata = 1;
@@ -551,6 +559,16 @@ static void __cpuinit get_cpu_cap(struct cpuinfo_x86 *c)
c->x86_capability[4] = excap;
}
+ /* Additional Intel-defined flags: level 0x00000007 */
+ if (c->cpuid_level >= 0x00000007) {
+ u32 eax, ebx, ecx, edx;
+
+ cpuid_count(0x00000007, 0, &eax, &ebx, &ecx, &edx);
+
+ if (eax > 0)
+ c->x86_capability[9] = ebx;
+ }
+
/* AMD-defined flags: level 0x80000001 */
xlvl = cpuid_eax(0x80000000);
c->extended_cpuid_level = xlvl;
@@ -576,6 +594,7 @@ static void __cpuinit get_cpu_cap(struct cpuinfo_x86 *c)
if (c->extended_cpuid_level >= 0x80000007)
c->x86_power = cpuid_edx(0x80000007);
+ init_scattered_cpuid_features(c);
}
static void __cpuinit identify_cpu_without_cpuid(struct cpuinfo_x86 *c)
@@ -731,7 +750,6 @@ static void __cpuinit generic_identify(struct cpuinfo_x86 *c)
get_model_name(c); /* Default name */
- init_scattered_cpuid_features(c);
detect_nopl(c);
}
@@ -1192,6 +1210,7 @@ void __cpuinit cpu_init(void)
dbg_restore_debug_regs();
fpu_init();
+ xsave_init();
raw_local_save_flags(kernel_eflags);
@@ -1252,12 +1271,7 @@ void __cpuinit cpu_init(void)
clear_used_math();
mxcsr_feature_mask_init();
- /*
- * Boot processor to setup the FP and extended state context info.
- */
- if (smp_processor_id() == boot_cpu_id)
- init_thread_xstate();
-
+ fpu_init();
xsave_init();
}
#endif
diff --git a/arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c b/arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c
index 1d3cddaa40e..246cd3afbb5 100644
--- a/arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c
+++ b/arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c
@@ -34,7 +34,6 @@
#include <linux/compiler.h>
#include <linux/dmi.h>
#include <linux/slab.h>
-#include <trace/events/power.h>
#include <linux/acpi.h>
#include <linux/io.h>
@@ -324,8 +323,6 @@ static int acpi_cpufreq_target(struct cpufreq_policy *policy,
}
}
- trace_power_frequency(POWER_PSTATE, data->freq_table[next_state].frequency);
-
switch (data->cpu_feature) {
case SYSTEM_INTEL_MSR_CAPABLE:
cmd.type = SYSTEM_INTEL_MSR_CAPABLE;
@@ -351,7 +348,7 @@ static int acpi_cpufreq_target(struct cpufreq_policy *policy,
freqs.old = perf->states[perf->state].core_frequency * 1000;
freqs.new = data->freq_table[next_state].frequency;
- for_each_cpu(i, cmd.mask) {
+ for_each_cpu(i, policy->cpus) {
freqs.cpu = i;
cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
}
@@ -367,7 +364,7 @@ static int acpi_cpufreq_target(struct cpufreq_policy *policy,
}
}
- for_each_cpu(i, cmd.mask) {
+ for_each_cpu(i, policy->cpus) {
freqs.cpu = i;
cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
}
diff --git a/arch/x86/kernel/cpu/cpufreq/gx-suspmod.c b/arch/x86/kernel/cpu/cpufreq/gx-suspmod.c
index 16e3483be9e..32974cf8423 100644
--- a/arch/x86/kernel/cpu/cpufreq/gx-suspmod.c
+++ b/arch/x86/kernel/cpu/cpufreq/gx-suspmod.c
@@ -169,12 +169,9 @@ static int gx_freq_mult[16] = {
* Low Level chipset interface *
****************************************************************/
static struct pci_device_id gx_chipset_tbl[] __initdata = {
- { PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5530_LEGACY,
- PCI_ANY_ID, PCI_ANY_ID },
- { PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5520,
- PCI_ANY_ID, PCI_ANY_ID },
- { PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5510,
- PCI_ANY_ID, PCI_ANY_ID },
+ { PCI_VDEVICE(CYRIX, PCI_DEVICE_ID_CYRIX_5530_LEGACY), },
+ { PCI_VDEVICE(CYRIX, PCI_DEVICE_ID_CYRIX_5520), },
+ { PCI_VDEVICE(CYRIX, PCI_DEVICE_ID_CYRIX_5510), },
{ 0, },
};
@@ -199,7 +196,7 @@ static __init struct pci_dev *gx_detect_chipset(void)
}
/* detect which companion chip is used */
- while ((gx_pci = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, gx_pci)) != NULL) {
+ for_each_pci_dev(gx_pci) {
if ((pci_match_id(gx_chipset_tbl, gx_pci)) != NULL)
return gx_pci;
}
diff --git a/arch/x86/kernel/cpu/cpufreq/longhaul.c b/arch/x86/kernel/cpu/cpufreq/longhaul.c
index 7e7eea4f826..03162dac627 100644
--- a/arch/x86/kernel/cpu/cpufreq/longhaul.c
+++ b/arch/x86/kernel/cpu/cpufreq/longhaul.c
@@ -426,7 +426,7 @@ static int guess_fsb(int mult)
}
-static int __init longhaul_get_ranges(void)
+static int __cpuinit longhaul_get_ranges(void)
{
unsigned int i, j, k = 0;
unsigned int ratio;
@@ -530,7 +530,7 @@ static int __init longhaul_get_ranges(void)
}
-static void __init longhaul_setup_voltagescaling(void)
+static void __cpuinit longhaul_setup_voltagescaling(void)
{
union msr_longhaul longhaul;
struct mV_pos minvid, maxvid, vid;
@@ -784,7 +784,7 @@ static int longhaul_setup_southbridge(void)
return 0;
}
-static int __init longhaul_cpu_init(struct cpufreq_policy *policy)
+static int __cpuinit longhaul_cpu_init(struct cpufreq_policy *policy)
{
struct cpuinfo_x86 *c = &cpu_data(0);
char *cpuname = NULL;
diff --git a/arch/x86/kernel/cpu/cpufreq/longhaul.h b/arch/x86/kernel/cpu/cpufreq/longhaul.h
index e2360a469f7..cbf48fbca88 100644
--- a/arch/x86/kernel/cpu/cpufreq/longhaul.h
+++ b/arch/x86/kernel/cpu/cpufreq/longhaul.h
@@ -56,7 +56,7 @@ union msr_longhaul {
/*
* VIA C3 Samuel 1 & Samuel 2 (stepping 0)
*/
-static const int __initdata samuel1_mults[16] = {
+static const int __cpuinitdata samuel1_mults[16] = {
-1, /* 0000 -> RESERVED */
30, /* 0001 -> 3.0x */
40, /* 0010 -> 4.0x */
@@ -75,7 +75,7 @@ static const int __initdata samuel1_mults[16] = {
-1, /* 1111 -> RESERVED */
};
-static const int __initdata samuel1_eblcr[16] = {
+static const int __cpuinitdata samuel1_eblcr[16] = {
50, /* 0000 -> RESERVED */
30, /* 0001 -> 3.0x */
40, /* 0010 -> 4.0x */
@@ -97,7 +97,7 @@ static const int __initdata samuel1_eblcr[16] = {
/*
* VIA C3 Samuel2 Stepping 1->15
*/
-static const int __initdata samuel2_eblcr[16] = {
+static const int __cpuinitdata samuel2_eblcr[16] = {
50, /* 0000 -> 5.0x */
30, /* 0001 -> 3.0x */
40, /* 0010 -> 4.0x */
@@ -119,7 +119,7 @@ static const int __initdata samuel2_eblcr[16] = {
/*
* VIA C3 Ezra
*/
-static const int __initdata ezra_mults[16] = {
+static const int __cpuinitdata ezra_mults[16] = {
100, /* 0000 -> 10.0x */
30, /* 0001 -> 3.0x */
40, /* 0010 -> 4.0x */
@@ -138,7 +138,7 @@ static const int __initdata ezra_mults[16] = {
120, /* 1111 -> 12.0x */
};
-static const int __initdata ezra_eblcr[16] = {
+static const int __cpuinitdata ezra_eblcr[16] = {
50, /* 0000 -> 5.0x */
30, /* 0001 -> 3.0x */
40, /* 0010 -> 4.0x */
@@ -160,7 +160,7 @@ static const int __initdata ezra_eblcr[16] = {
/*
* VIA C3 (Ezra-T) [C5M].
*/
-static const int __initdata ezrat_mults[32] = {
+static const int __cpuinitdata ezrat_mults[32] = {
100, /* 0000 -> 10.0x */
30, /* 0001 -> 3.0x */
40, /* 0010 -> 4.0x */
@@ -196,7 +196,7 @@ static const int __initdata ezrat_mults[32] = {
-1, /* 1111 -> RESERVED (12.0x) */
};
-static const int __initdata ezrat_eblcr[32] = {
+static const int __cpuinitdata ezrat_eblcr[32] = {
50, /* 0000 -> 5.0x */
30, /* 0001 -> 3.0x */
40, /* 0010 -> 4.0x */
@@ -235,7 +235,7 @@ static const int __initdata ezrat_eblcr[32] = {
/*
* VIA C3 Nehemiah */
-static const int __initdata nehemiah_mults[32] = {
+static const int __cpuinitdata nehemiah_mults[32] = {
100, /* 0000 -> 10.0x */
-1, /* 0001 -> 16.0x */
40, /* 0010 -> 4.0x */
@@ -270,7 +270,7 @@ static const int __initdata nehemiah_mults[32] = {
-1, /* 1111 -> 12.0x */
};
-static const int __initdata nehemiah_eblcr[32] = {
+static const int __cpuinitdata nehemiah_eblcr[32] = {
50, /* 0000 -> 5.0x */
160, /* 0001 -> 16.0x */
40, /* 0010 -> 4.0x */
@@ -315,7 +315,7 @@ struct mV_pos {
unsigned short pos;
};
-static const struct mV_pos __initdata vrm85_mV[32] = {
+static const struct mV_pos __cpuinitdata vrm85_mV[32] = {
{1250, 8}, {1200, 6}, {1150, 4}, {1100, 2},
{1050, 0}, {1800, 30}, {1750, 28}, {1700, 26},
{1650, 24}, {1600, 22}, {1550, 20}, {1500, 18},
@@ -326,14 +326,14 @@ static const struct mV_pos __initdata vrm85_mV[32] = {
{1475, 17}, {1425, 15}, {1375, 13}, {1325, 11}
};
-static const unsigned char __initdata mV_vrm85[32] = {
+static const unsigned char __cpuinitdata mV_vrm85[32] = {
0x04, 0x14, 0x03, 0x13, 0x02, 0x12, 0x01, 0x11,
0x00, 0x10, 0x0f, 0x1f, 0x0e, 0x1e, 0x0d, 0x1d,
0x0c, 0x1c, 0x0b, 0x1b, 0x0a, 0x1a, 0x09, 0x19,
0x08, 0x18, 0x07, 0x17, 0x06, 0x16, 0x05, 0x15
};
-static const struct mV_pos __initdata mobilevrm_mV[32] = {
+static const struct mV_pos __cpuinitdata mobilevrm_mV[32] = {
{1750, 31}, {1700, 30}, {1650, 29}, {1600, 28},
{1550, 27}, {1500, 26}, {1450, 25}, {1400, 24},
{1350, 23}, {1300, 22}, {1250, 21}, {1200, 20},
@@ -344,7 +344,7 @@ static const struct mV_pos __initdata mobilevrm_mV[32] = {
{675, 3}, {650, 2}, {625, 1}, {600, 0}
};
-static const unsigned char __initdata mV_mobilevrm[32] = {
+static const unsigned char __cpuinitdata mV_mobilevrm[32] = {
0x1f, 0x1e, 0x1d, 0x1c, 0x1b, 0x1a, 0x19, 0x18,
0x17, 0x16, 0x15, 0x14, 0x13, 0x12, 0x11, 0x10,
0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08,
diff --git a/arch/x86/kernel/cpu/cpufreq/longrun.c b/arch/x86/kernel/cpu/cpufreq/longrun.c
index e7b559d74c5..fc09f142d94 100644
--- a/arch/x86/kernel/cpu/cpufreq/longrun.c
+++ b/arch/x86/kernel/cpu/cpufreq/longrun.c
@@ -165,8 +165,8 @@ static unsigned int longrun_get(unsigned int cpu)
* TMTA rules:
* performance_pctg = (target_freq - low_freq)/(high_freq - low_freq)
*/
-static unsigned int __init longrun_determine_freqs(unsigned int *low_freq,
- unsigned int *high_freq)
+static unsigned int __cpuinit longrun_determine_freqs(unsigned int *low_freq,
+ unsigned int *high_freq)
{
u32 msr_lo, msr_hi;
u32 save_lo, save_hi;
@@ -258,7 +258,7 @@ static unsigned int __init longrun_determine_freqs(unsigned int *low_freq,
}
-static int __init longrun_cpu_init(struct cpufreq_policy *policy)
+static int __cpuinit longrun_cpu_init(struct cpufreq_policy *policy)
{
int result = 0;
diff --git a/arch/x86/kernel/cpu/cpufreq/p4-clockmod.c b/arch/x86/kernel/cpu/cpufreq/p4-clockmod.c
index 7b8a8ba67b0..bd1cac747f6 100644
--- a/arch/x86/kernel/cpu/cpufreq/p4-clockmod.c
+++ b/arch/x86/kernel/cpu/cpufreq/p4-clockmod.c
@@ -178,13 +178,8 @@ static unsigned int cpufreq_p4_get_frequency(struct cpuinfo_x86 *c)
}
}
- if (c->x86 != 0xF) {
- if (!cpu_has(c, X86_FEATURE_EST))
- printk(KERN_WARNING PFX "Unknown CPU. "
- "Please send an e-mail to "
- "<cpufreq@vger.kernel.org>\n");
+ if (c->x86 != 0xF)
return 0;
- }
/* on P-4s, the TSC runs with constant frequency independent whether
* throttling is active or not. */
diff --git a/arch/x86/kernel/cpu/cpufreq/powernow-k7.c b/arch/x86/kernel/cpu/cpufreq/powernow-k7.c
index 9a97116f89e..4a45fd6e41b 100644
--- a/arch/x86/kernel/cpu/cpufreq/powernow-k7.c
+++ b/arch/x86/kernel/cpu/cpufreq/powernow-k7.c
@@ -569,7 +569,7 @@ static int powernow_verify(struct cpufreq_policy *policy)
* We will then get the same kind of behaviour already tested under
* the "well-known" other OS.
*/
-static int __init fixup_sgtc(void)
+static int __cpuinit fixup_sgtc(void)
{
unsigned int sgtc;
unsigned int m;
@@ -603,7 +603,7 @@ static unsigned int powernow_get(unsigned int cpu)
}
-static int __init acer_cpufreq_pst(const struct dmi_system_id *d)
+static int __cpuinit acer_cpufreq_pst(const struct dmi_system_id *d)
{
printk(KERN_WARNING PFX
"%s laptop with broken PST tables in BIOS detected.\n",
@@ -621,7 +621,7 @@ static int __init acer_cpufreq_pst(const struct dmi_system_id *d)
* A BIOS update is all that can save them.
* Mention this, and disable cpufreq.
*/
-static struct dmi_system_id __initdata powernow_dmi_table[] = {
+static struct dmi_system_id __cpuinitdata powernow_dmi_table[] = {
{
.callback = acer_cpufreq_pst,
.ident = "Acer Aspire",
@@ -633,7 +633,7 @@ static struct dmi_system_id __initdata powernow_dmi_table[] = {
{ }
};
-static int __init powernow_cpu_init(struct cpufreq_policy *policy)
+static int __cpuinit powernow_cpu_init(struct cpufreq_policy *policy)
{
union msr_fidvidstatus fidvidstatus;
int result;
diff --git a/arch/x86/kernel/cpu/cpufreq/powernow-k8.c b/arch/x86/kernel/cpu/cpufreq/powernow-k8.c
index 3e90cce3dc8..491977baf6c 100644
--- a/arch/x86/kernel/cpu/cpufreq/powernow-k8.c
+++ b/arch/x86/kernel/cpu/cpufreq/powernow-k8.c
@@ -9,7 +9,7 @@
* Based on the powernow-k7.c module written by Dave Jones.
* (C) 2003 Dave Jones on behalf of SuSE Labs
* (C) 2004 Dominik Brodowski <linux@brodo.de>
- * (C) 2004 Pavel Machek <pavel@suse.cz>
+ * (C) 2004 Pavel Machek <pavel@ucw.cz>
* Licensed under the terms of the GNU GPL License version 2.
* Based upon datasheets & sample CPUs kindly provided by AMD.
*
@@ -806,6 +806,8 @@ static int find_psb_table(struct powernow_k8_data *data)
* www.amd.com
*/
printk(KERN_ERR FW_BUG PFX "No PSB or ACPI _PSS objects\n");
+ printk(KERN_ERR PFX "Make sure that your BIOS is up to date"
+ " and Cool'N'Quiet support is enabled in BIOS setup\n");
return -ENODEV;
}
@@ -910,8 +912,8 @@ static int fill_powernow_table_pstate(struct powernow_k8_data *data,
{
int i;
u32 hi = 0, lo = 0;
- rdmsr(MSR_PSTATE_CUR_LIMIT, hi, lo);
- data->max_hw_pstate = (hi & HW_PSTATE_MAX_MASK) >> HW_PSTATE_MAX_SHIFT;
+ rdmsr(MSR_PSTATE_CUR_LIMIT, lo, hi);
+ data->max_hw_pstate = (lo & HW_PSTATE_MAX_MASK) >> HW_PSTATE_MAX_SHIFT;
for (i = 0; i < data->acpi_data.state_count; i++) {
u32 index;
diff --git a/arch/x86/kernel/cpu/hypervisor.c b/arch/x86/kernel/cpu/hypervisor.c
index dd531cc56a8..8095f8611f8 100644
--- a/arch/x86/kernel/cpu/hypervisor.c
+++ b/arch/x86/kernel/cpu/hypervisor.c
@@ -34,6 +34,9 @@ static const __initconst struct hypervisor_x86 * const hypervisors[] =
{
&x86_hyper_vmware,
&x86_hyper_ms_hyperv,
+#ifdef CONFIG_XEN_PVHVM
+ &x86_hyper_xen_hvm,
+#endif
};
const struct hypervisor_x86 *x86_hyper;
diff --git a/arch/x86/kernel/cpu/intel_cacheinfo.c b/arch/x86/kernel/cpu/intel_cacheinfo.c
index 33eae2062cf..898c2f4eab8 100644
--- a/arch/x86/kernel/cpu/intel_cacheinfo.c
+++ b/arch/x86/kernel/cpu/intel_cacheinfo.c
@@ -347,8 +347,8 @@ static struct amd_l3_cache * __cpuinit amd_init_l3_cache(int node)
return l3;
}
-static void __cpuinit
-amd_check_l3_disable(int index, struct _cpuid4_info_regs *this_leaf)
+static void __cpuinit amd_check_l3_disable(struct _cpuid4_info_regs *this_leaf,
+ int index)
{
int node;
@@ -396,20 +396,39 @@ amd_check_l3_disable(int index, struct _cpuid4_info_regs *this_leaf)
this_leaf->l3 = l3_caches[node];
}
+/*
+ * check whether a slot used for disabling an L3 index is occupied.
+ * @l3: L3 cache descriptor
+ * @slot: slot number (0..1)
+ *
+ * @returns: the disabled index if used or negative value if slot free.
+ */
+int amd_get_l3_disable_slot(struct amd_l3_cache *l3, unsigned slot)
+{
+ unsigned int reg = 0;
+
+ pci_read_config_dword(l3->dev, 0x1BC + slot * 4, &reg);
+
+ /* check whether this slot is activated already */
+ if (reg & (3UL << 30))
+ return reg & 0xfff;
+
+ return -1;
+}
+
static ssize_t show_cache_disable(struct _cpuid4_info *this_leaf, char *buf,
unsigned int slot)
{
- struct pci_dev *dev = this_leaf->l3->dev;
- unsigned int reg = 0;
+ int index;
if (!this_leaf->l3 || !this_leaf->l3->can_disable)
return -EINVAL;
- if (!dev)
- return -EINVAL;
+ index = amd_get_l3_disable_slot(this_leaf->l3, slot);
+ if (index >= 0)
+ return sprintf(buf, "%d\n", index);
- pci_read_config_dword(dev, 0x1BC + slot * 4, &reg);
- return sprintf(buf, "0x%08x\n", reg);
+ return sprintf(buf, "FREE\n");
}
#define SHOW_CACHE_DISABLE(slot) \
@@ -451,37 +470,74 @@ static void amd_l3_disable_index(struct amd_l3_cache *l3, int cpu,
}
}
-
-static ssize_t store_cache_disable(struct _cpuid4_info *this_leaf,
- const char *buf, size_t count,
- unsigned int slot)
+/*
+ * disable a L3 cache index by using a disable-slot
+ *
+ * @l3: L3 cache descriptor
+ * @cpu: A CPU on the node containing the L3 cache
+ * @slot: slot number (0..1)
+ * @index: index to disable
+ *
+ * @return: 0 on success, error status on failure
+ */
+int amd_set_l3_disable_slot(struct amd_l3_cache *l3, int cpu, unsigned slot,
+ unsigned long index)
{
- struct pci_dev *dev = this_leaf->l3->dev;
- int cpu = cpumask_first(to_cpumask(this_leaf->shared_cpu_map));
- unsigned long val = 0;
+ int ret = 0;
#define SUBCACHE_MASK (3UL << 20)
#define SUBCACHE_INDEX 0xfff
- if (!this_leaf->l3 || !this_leaf->l3->can_disable)
+ /*
+ * check whether this slot is already used or
+ * the index is already disabled
+ */
+ ret = amd_get_l3_disable_slot(l3, slot);
+ if (ret >= 0)
return -EINVAL;
+ /*
+ * check whether the other slot has disabled the
+ * same index already
+ */
+ if (index == amd_get_l3_disable_slot(l3, !slot))
+ return -EINVAL;
+
+ /* do not allow writes outside of allowed bits */
+ if ((index & ~(SUBCACHE_MASK | SUBCACHE_INDEX)) ||
+ ((index & SUBCACHE_INDEX) > l3->indices))
+ return -EINVAL;
+
+ amd_l3_disable_index(l3, cpu, slot, index);
+
+ return 0;
+}
+
+static ssize_t store_cache_disable(struct _cpuid4_info *this_leaf,
+ const char *buf, size_t count,
+ unsigned int slot)
+{
+ unsigned long val = 0;
+ int cpu, err = 0;
+
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
- if (!dev)
+ if (!this_leaf->l3 || !this_leaf->l3->can_disable)
return -EINVAL;
- if (strict_strtoul(buf, 10, &val) < 0)
- return -EINVAL;
+ cpu = cpumask_first(to_cpumask(this_leaf->shared_cpu_map));
- /* do not allow writes outside of allowed bits */
- if ((val & ~(SUBCACHE_MASK | SUBCACHE_INDEX)) ||
- ((val & SUBCACHE_INDEX) > this_leaf->l3->indices))
+ if (strict_strtoul(buf, 10, &val) < 0)
return -EINVAL;
- amd_l3_disable_index(this_leaf->l3, cpu, slot, val);
-
+ err = amd_set_l3_disable_slot(this_leaf->l3, cpu, slot, val);
+ if (err) {
+ if (err == -EEXIST)
+ printk(KERN_WARNING "L3 disable slot %d in use!\n",
+ slot);
+ return err;
+ }
return count;
}
@@ -502,7 +558,7 @@ static struct _cache_attr cache_disable_1 = __ATTR(cache_disable_1, 0644,
#else /* CONFIG_CPU_SUP_AMD */
static void __cpuinit
-amd_check_l3_disable(int index, struct _cpuid4_info_regs *this_leaf)
+amd_check_l3_disable(struct _cpuid4_info_regs *this_leaf, int index)
{
};
#endif /* CONFIG_CPU_SUP_AMD */
@@ -518,7 +574,7 @@ __cpuinit cpuid4_cache_lookup_regs(int index,
if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD) {
amd_cpuid4(index, &eax, &ebx, &ecx);
- amd_check_l3_disable(index, this_leaf);
+ amd_check_l3_disable(this_leaf, index);
} else {
cpuid_count(4, index, &eax.full, &ebx.full, &ecx.full, &edx);
}
diff --git a/arch/x86/kernel/cpu/mcheck/mce.c b/arch/x86/kernel/cpu/mcheck/mce.c
index 18cc4256225..ed41562909f 100644
--- a/arch/x86/kernel/cpu/mcheck/mce.c
+++ b/arch/x86/kernel/cpu/mcheck/mce.c
@@ -51,7 +51,7 @@
static DEFINE_MUTEX(mce_read_mutex);
#define rcu_dereference_check_mce(p) \
- rcu_dereference_check((p), \
+ rcu_dereference_index_check((p), \
rcu_read_lock_sched_held() || \
lockdep_is_held(&mce_read_mutex))
@@ -107,8 +107,8 @@ EXPORT_SYMBOL_GPL(x86_mce_decoder_chain);
static int default_decode_mce(struct notifier_block *nb, unsigned long val,
void *data)
{
- pr_emerg("No human readable MCE decoding support on this CPU type.\n");
- pr_emerg("Run the message through 'mcelog --ascii' to decode.\n");
+ pr_emerg(HW_ERR "No human readable MCE decoding support on this CPU type.\n");
+ pr_emerg(HW_ERR "Run the message through 'mcelog --ascii' to decode.\n");
return NOTIFY_STOP;
}
@@ -211,11 +211,11 @@ void mce_log(struct mce *mce)
static void print_mce(struct mce *m)
{
- pr_emerg("CPU %d: Machine Check Exception: %16Lx Bank %d: %016Lx\n",
+ pr_emerg(HW_ERR "CPU %d: Machine Check Exception: %Lx Bank %d: %016Lx\n",
m->extcpu, m->mcgstatus, m->bank, m->status);
if (m->ip) {
- pr_emerg("RIP%s %02x:<%016Lx> ",
+ pr_emerg(HW_ERR "RIP%s %02x:<%016Lx> ",
!(m->mcgstatus & MCG_STATUS_EIPV) ? " !INEXACT!" : "",
m->cs, m->ip);
@@ -224,14 +224,14 @@ static void print_mce(struct mce *m)
pr_cont("\n");
}
- pr_emerg("TSC %llx ", m->tsc);
+ pr_emerg(HW_ERR "TSC %llx ", m->tsc);
if (m->addr)
pr_cont("ADDR %llx ", m->addr);
if (m->misc)
pr_cont("MISC %llx ", m->misc);
pr_cont("\n");
- pr_emerg("PROCESSOR %u:%x TIME %llu SOCKET %u APIC %x\n",
+ pr_emerg(HW_ERR "PROCESSOR %u:%x TIME %llu SOCKET %u APIC %x\n",
m->cpuvendor, m->cpuid, m->time, m->socketid, m->apicid);
/*
@@ -241,16 +241,6 @@ static void print_mce(struct mce *m)
atomic_notifier_call_chain(&x86_mce_decoder_chain, 0, m);
}
-static void print_mce_head(void)
-{
- pr_emerg("\nHARDWARE ERROR\n");
-}
-
-static void print_mce_tail(void)
-{
- pr_emerg("This is not a software problem!\n");
-}
-
#define PANIC_TIMEOUT 5 /* 5 seconds */
static atomic_t mce_paniced;
@@ -291,7 +281,6 @@ static void mce_panic(char *msg, struct mce *final, char *exp)
if (atomic_inc_return(&mce_fake_paniced) > 1)
return;
}
- print_mce_head();
/* First print corrected ones that are still unlogged */
for (i = 0; i < MCE_LOG_LEN; i++) {
struct mce *m = &mcelog.entry[i];
@@ -322,16 +311,15 @@ static void mce_panic(char *msg, struct mce *final, char *exp)
apei_err = apei_write_mce(final);
}
if (cpu_missing)
- printk(KERN_EMERG "Some CPUs didn't answer in synchronization\n");
- print_mce_tail();
+ pr_emerg(HW_ERR "Some CPUs didn't answer in synchronization\n");
if (exp)
- printk(KERN_EMERG "Machine check: %s\n", exp);
+ pr_emerg(HW_ERR "Machine check: %s\n", exp);
if (!fake_panic) {
if (panic_timeout == 0)
panic_timeout = mce_panic_timeout;
panic(msg);
} else
- printk(KERN_EMERG "Fake kernel panic: %s\n", msg);
+ pr_emerg(HW_ERR "Fake kernel panic: %s\n", msg);
}
/* Support code for software error injection */
@@ -600,6 +588,7 @@ void machine_check_poll(enum mcp_flags flags, mce_banks_t *b)
*/
if (!(flags & MCP_DONTLOG) && !mce_dont_log_ce) {
mce_log(&m);
+ atomic_notifier_call_chain(&x86_mce_decoder_chain, 0, &m);
add_taint(TAINT_MACHINE_CHECK);
}
@@ -1220,7 +1209,7 @@ int mce_notify_irq(void)
schedule_work(&mce_trigger_work);
if (__ratelimit(&ratelimit))
- printk(KERN_INFO "Machine check events logged\n");
+ pr_info(HW_ERR "Machine check events logged\n");
return 1;
}
diff --git a/arch/x86/kernel/cpu/mcheck/mce_intel.c b/arch/x86/kernel/cpu/mcheck/mce_intel.c
index 62b48e40920..6fcd0936194 100644
--- a/arch/x86/kernel/cpu/mcheck/mce_intel.c
+++ b/arch/x86/kernel/cpu/mcheck/mce_intel.c
@@ -95,19 +95,20 @@ static void cmci_discover(int banks, int boot)
rdmsrl(MSR_IA32_MCx_CTL2(i), val);
/* Already owned by someone else? */
- if (val & CMCI_EN) {
+ if (val & MCI_CTL2_CMCI_EN) {
if (test_and_clear_bit(i, owned) && !boot)
print_update("SHD", &hdr, i);
__clear_bit(i, __get_cpu_var(mce_poll_banks));
continue;
}
- val |= CMCI_EN | CMCI_THRESHOLD;
+ val &= ~MCI_CTL2_CMCI_THRESHOLD_MASK;
+ val |= MCI_CTL2_CMCI_EN | CMCI_THRESHOLD;
wrmsrl(MSR_IA32_MCx_CTL2(i), val);
rdmsrl(MSR_IA32_MCx_CTL2(i), val);
/* Did the enable bit stick? -- the bank supports CMCI */
- if (val & CMCI_EN) {
+ if (val & MCI_CTL2_CMCI_EN) {
if (!test_and_set_bit(i, owned) && !boot)
print_update("CMCI", &hdr, i);
__clear_bit(i, __get_cpu_var(mce_poll_banks));
@@ -155,7 +156,7 @@ void cmci_clear(void)
continue;
/* Disable CMCI */
rdmsrl(MSR_IA32_MCx_CTL2(i), val);
- val &= ~(CMCI_EN|CMCI_THRESHOLD_MASK);
+ val &= ~(MCI_CTL2_CMCI_EN|MCI_CTL2_CMCI_THRESHOLD_MASK);
wrmsrl(MSR_IA32_MCx_CTL2(i), val);
__clear_bit(i, __get_cpu_var(mce_banks_owned));
}
diff --git a/arch/x86/kernel/cpu/mcheck/therm_throt.c b/arch/x86/kernel/cpu/mcheck/therm_throt.c
index e1a0a3bf971..c2a8b26d4fe 100644
--- a/arch/x86/kernel/cpu/mcheck/therm_throt.c
+++ b/arch/x86/kernel/cpu/mcheck/therm_throt.c
@@ -34,15 +34,25 @@
/* How long to wait between reporting thermal events */
#define CHECK_INTERVAL (300 * HZ)
+#define THERMAL_THROTTLING_EVENT 0
+#define POWER_LIMIT_EVENT 1
+
/*
- * Current thermal throttling state:
+ * Current thermal event state:
*/
-struct thermal_state {
- bool is_throttled;
-
+struct _thermal_state {
+ bool new_event;
+ int event;
u64 next_check;
- unsigned long throttle_count;
- unsigned long last_throttle_count;
+ unsigned long count;
+ unsigned long last_count;
+};
+
+struct thermal_state {
+ struct _thermal_state core_throttle;
+ struct _thermal_state core_power_limit;
+ struct _thermal_state package_throttle;
+ struct _thermal_state package_power_limit;
};
static DEFINE_PER_CPU(struct thermal_state, thermal_state);
@@ -53,11 +63,13 @@ static u32 lvtthmr_init __read_mostly;
#ifdef CONFIG_SYSFS
#define define_therm_throt_sysdev_one_ro(_name) \
- static SYSDEV_ATTR(_name, 0444, therm_throt_sysdev_show_##_name, NULL)
+ static SYSDEV_ATTR(_name, 0444, \
+ therm_throt_sysdev_show_##_name, \
+ NULL) \
-#define define_therm_throt_sysdev_show_func(name) \
+#define define_therm_throt_sysdev_show_func(event, name) \
\
-static ssize_t therm_throt_sysdev_show_##name( \
+static ssize_t therm_throt_sysdev_show_##event##_##name( \
struct sys_device *dev, \
struct sysdev_attribute *attr, \
char *buf) \
@@ -66,30 +78,42 @@ static ssize_t therm_throt_sysdev_show_##name( \
ssize_t ret; \
\
preempt_disable(); /* CPU hotplug */ \
- if (cpu_online(cpu)) \
+ if (cpu_online(cpu)) { \
ret = sprintf(buf, "%lu\n", \
- per_cpu(thermal_state, cpu).name); \
- else \
+ per_cpu(thermal_state, cpu).event.name); \
+ } else \
ret = 0; \
preempt_enable(); \
\
return ret; \
}
-define_therm_throt_sysdev_show_func(throttle_count);
-define_therm_throt_sysdev_one_ro(throttle_count);
+define_therm_throt_sysdev_show_func(core_throttle, count);
+define_therm_throt_sysdev_one_ro(core_throttle_count);
+
+define_therm_throt_sysdev_show_func(core_power_limit, count);
+define_therm_throt_sysdev_one_ro(core_power_limit_count);
+
+define_therm_throt_sysdev_show_func(package_throttle, count);
+define_therm_throt_sysdev_one_ro(package_throttle_count);
+
+define_therm_throt_sysdev_show_func(package_power_limit, count);
+define_therm_throt_sysdev_one_ro(package_power_limit_count);
static struct attribute *thermal_throttle_attrs[] = {
- &attr_throttle_count.attr,
+ &attr_core_throttle_count.attr,
NULL
};
-static struct attribute_group thermal_throttle_attr_group = {
+static struct attribute_group thermal_attr_group = {
.attrs = thermal_throttle_attrs,
.name = "thermal_throttle"
};
#endif /* CONFIG_SYSFS */
+#define CORE_LEVEL 0
+#define PACKAGE_LEVEL 1
+
/***
* therm_throt_process - Process thermal throttling event from interrupt
* @curr: Whether the condition is current or not (boolean), since the
@@ -106,39 +130,70 @@ static struct attribute_group thermal_throttle_attr_group = {
* 1 : Event should be logged further, and a message has been
* printed to the syslog.
*/
-static int therm_throt_process(bool is_throttled)
+static int therm_throt_process(bool new_event, int event, int level)
{
- struct thermal_state *state;
- unsigned int this_cpu;
- bool was_throttled;
+ struct _thermal_state *state;
+ unsigned int this_cpu = smp_processor_id();
+ bool old_event;
u64 now;
+ struct thermal_state *pstate = &per_cpu(thermal_state, this_cpu);
- this_cpu = smp_processor_id();
now = get_jiffies_64();
- state = &per_cpu(thermal_state, this_cpu);
+ if (level == CORE_LEVEL) {
+ if (event == THERMAL_THROTTLING_EVENT)
+ state = &pstate->core_throttle;
+ else if (event == POWER_LIMIT_EVENT)
+ state = &pstate->core_power_limit;
+ else
+ return 0;
+ } else if (level == PACKAGE_LEVEL) {
+ if (event == THERMAL_THROTTLING_EVENT)
+ state = &pstate->package_throttle;
+ else if (event == POWER_LIMIT_EVENT)
+ state = &pstate->package_power_limit;
+ else
+ return 0;
+ } else
+ return 0;
- was_throttled = state->is_throttled;
- state->is_throttled = is_throttled;
+ old_event = state->new_event;
+ state->new_event = new_event;
- if (is_throttled)
- state->throttle_count++;
+ if (new_event)
+ state->count++;
if (time_before64(now, state->next_check) &&
- state->throttle_count != state->last_throttle_count)
+ state->count != state->last_count)
return 0;
state->next_check = now + CHECK_INTERVAL;
- state->last_throttle_count = state->throttle_count;
+ state->last_count = state->count;
/* if we just entered the thermal event */
- if (is_throttled) {
- printk(KERN_CRIT "CPU%d: Temperature above threshold, cpu clock throttled (total events = %lu)\n", this_cpu, state->throttle_count);
+ if (new_event) {
+ if (event == THERMAL_THROTTLING_EVENT)
+ printk(KERN_CRIT "CPU%d: %s temperature above threshold, cpu clock throttled (total events = %lu)\n",
+ this_cpu,
+ level == CORE_LEVEL ? "Core" : "Package",
+ state->count);
+ else
+ printk(KERN_CRIT "CPU%d: %s power limit notification (total events = %lu)\n",
+ this_cpu,
+ level == CORE_LEVEL ? "Core" : "Package",
+ state->count);
add_taint(TAINT_MACHINE_CHECK);
return 1;
}
- if (was_throttled) {
- printk(KERN_INFO "CPU%d: Temperature/speed normal\n", this_cpu);
+ if (old_event) {
+ if (event == THERMAL_THROTTLING_EVENT)
+ printk(KERN_INFO "CPU%d: %s temperature/speed normal\n",
+ this_cpu,
+ level == CORE_LEVEL ? "Core" : "Package");
+ else
+ printk(KERN_INFO "CPU%d: %s power limit normal\n",
+ this_cpu,
+ level == CORE_LEVEL ? "Core" : "Package");
return 1;
}
@@ -149,13 +204,32 @@ static int therm_throt_process(bool is_throttled)
/* Add/Remove thermal_throttle interface for CPU device: */
static __cpuinit int thermal_throttle_add_dev(struct sys_device *sys_dev)
{
- return sysfs_create_group(&sys_dev->kobj,
- &thermal_throttle_attr_group);
+ int err;
+ struct cpuinfo_x86 *c = &cpu_data(smp_processor_id());
+
+ err = sysfs_create_group(&sys_dev->kobj, &thermal_attr_group);
+ if (err)
+ return err;
+
+ if (cpu_has(c, X86_FEATURE_PLN))
+ err = sysfs_add_file_to_group(&sys_dev->kobj,
+ &attr_core_power_limit_count.attr,
+ thermal_attr_group.name);
+ if (cpu_has(c, X86_FEATURE_PTS))
+ err = sysfs_add_file_to_group(&sys_dev->kobj,
+ &attr_package_throttle_count.attr,
+ thermal_attr_group.name);
+ if (cpu_has(c, X86_FEATURE_PLN))
+ err = sysfs_add_file_to_group(&sys_dev->kobj,
+ &attr_package_power_limit_count.attr,
+ thermal_attr_group.name);
+
+ return err;
}
static __cpuinit void thermal_throttle_remove_dev(struct sys_device *sys_dev)
{
- sysfs_remove_group(&sys_dev->kobj, &thermal_throttle_attr_group);
+ sysfs_remove_group(&sys_dev->kobj, &thermal_attr_group);
}
/* Mutex protecting device creation against CPU hotplug: */
@@ -226,14 +300,50 @@ device_initcall(thermal_throttle_init_device);
#endif /* CONFIG_SYSFS */
+/*
+ * Set up the most two significant bit to notify mce log that this thermal
+ * event type.
+ * This is a temp solution. May be changed in the future with mce log
+ * infrasture.
+ */
+#define CORE_THROTTLED (0)
+#define CORE_POWER_LIMIT ((__u64)1 << 62)
+#define PACKAGE_THROTTLED ((__u64)2 << 62)
+#define PACKAGE_POWER_LIMIT ((__u64)3 << 62)
+
/* Thermal transition interrupt handler */
static void intel_thermal_interrupt(void)
{
__u64 msr_val;
+ struct cpuinfo_x86 *c = &cpu_data(smp_processor_id());
rdmsrl(MSR_IA32_THERM_STATUS, msr_val);
- if (therm_throt_process((msr_val & THERM_STATUS_PROCHOT) != 0))
- mce_log_therm_throt_event(msr_val);
+
+ if (therm_throt_process(msr_val & THERM_STATUS_PROCHOT,
+ THERMAL_THROTTLING_EVENT,
+ CORE_LEVEL) != 0)
+ mce_log_therm_throt_event(CORE_THROTTLED | msr_val);
+
+ if (cpu_has(c, X86_FEATURE_PLN))
+ if (therm_throt_process(msr_val & THERM_STATUS_POWER_LIMIT,
+ POWER_LIMIT_EVENT,
+ CORE_LEVEL) != 0)
+ mce_log_therm_throt_event(CORE_POWER_LIMIT | msr_val);
+
+ if (cpu_has(c, X86_FEATURE_PTS)) {
+ rdmsrl(MSR_IA32_PACKAGE_THERM_STATUS, msr_val);
+ if (therm_throt_process(msr_val & PACKAGE_THERM_STATUS_PROCHOT,
+ THERMAL_THROTTLING_EVENT,
+ PACKAGE_LEVEL) != 0)
+ mce_log_therm_throt_event(PACKAGE_THROTTLED | msr_val);
+ if (cpu_has(c, X86_FEATURE_PLN))
+ if (therm_throt_process(msr_val &
+ PACKAGE_THERM_STATUS_POWER_LIMIT,
+ POWER_LIMIT_EVENT,
+ PACKAGE_LEVEL) != 0)
+ mce_log_therm_throt_event(PACKAGE_POWER_LIMIT
+ | msr_val);
+ }
}
static void unexpected_thermal_interrupt(void)
@@ -335,8 +445,26 @@ void intel_init_thermal(struct cpuinfo_x86 *c)
apic_write(APIC_LVTTHMR, h);
rdmsr(MSR_IA32_THERM_INTERRUPT, l, h);
- wrmsr(MSR_IA32_THERM_INTERRUPT,
- l | (THERM_INT_LOW_ENABLE | THERM_INT_HIGH_ENABLE), h);
+ if (cpu_has(c, X86_FEATURE_PLN))
+ wrmsr(MSR_IA32_THERM_INTERRUPT,
+ l | (THERM_INT_LOW_ENABLE
+ | THERM_INT_HIGH_ENABLE | THERM_INT_PLN_ENABLE), h);
+ else
+ wrmsr(MSR_IA32_THERM_INTERRUPT,
+ l | (THERM_INT_LOW_ENABLE | THERM_INT_HIGH_ENABLE), h);
+
+ if (cpu_has(c, X86_FEATURE_PTS)) {
+ rdmsr(MSR_IA32_PACKAGE_THERM_INTERRUPT, l, h);
+ if (cpu_has(c, X86_FEATURE_PLN))
+ wrmsr(MSR_IA32_PACKAGE_THERM_INTERRUPT,
+ l | (PACKAGE_THERM_INT_LOW_ENABLE
+ | PACKAGE_THERM_INT_HIGH_ENABLE
+ | PACKAGE_THERM_INT_PLN_ENABLE), h);
+ else
+ wrmsr(MSR_IA32_PACKAGE_THERM_INTERRUPT,
+ l | (PACKAGE_THERM_INT_LOW_ENABLE
+ | PACKAGE_THERM_INT_HIGH_ENABLE), h);
+ }
smp_thermal_vector = intel_thermal_interrupt;
diff --git a/arch/x86/kernel/cpu/mshyperv.c b/arch/x86/kernel/cpu/mshyperv.c
index 16f41bbe46b..d944bf6c50e 100644
--- a/arch/x86/kernel/cpu/mshyperv.c
+++ b/arch/x86/kernel/cpu/mshyperv.c
@@ -18,6 +18,7 @@
#include <asm/mshyperv.h>
struct ms_hyperv_info ms_hyperv;
+EXPORT_SYMBOL_GPL(ms_hyperv);
static bool __init ms_hyperv_platform(void)
{
diff --git a/arch/x86/kernel/cpu/mtrr/cleanup.c b/arch/x86/kernel/cpu/mtrr/cleanup.c
index 06130b52f01..c5f59d07142 100644
--- a/arch/x86/kernel/cpu/mtrr/cleanup.c
+++ b/arch/x86/kernel/cpu/mtrr/cleanup.c
@@ -632,9 +632,9 @@ static void __init mtrr_print_out_one_result(int i)
unsigned long gran_base, chunk_base, lose_base;
char gran_factor, chunk_factor, lose_factor;
- gran_base = to_size_factor(result[i].gran_sizek, &gran_factor),
- chunk_base = to_size_factor(result[i].chunk_sizek, &chunk_factor),
- lose_base = to_size_factor(result[i].lose_cover_sizek, &lose_factor),
+ gran_base = to_size_factor(result[i].gran_sizek, &gran_factor);
+ chunk_base = to_size_factor(result[i].chunk_sizek, &chunk_factor);
+ lose_base = to_size_factor(result[i].lose_cover_sizek, &lose_factor);
pr_info("%sgran_size: %ld%c \tchunk_size: %ld%c \t",
result[i].bad ? "*BAD*" : " ",
diff --git a/arch/x86/kernel/cpu/mtrr/generic.c b/arch/x86/kernel/cpu/mtrr/generic.c
index fd31a441c61..7d28d7d0388 100644
--- a/arch/x86/kernel/cpu/mtrr/generic.c
+++ b/arch/x86/kernel/cpu/mtrr/generic.c
@@ -433,13 +433,12 @@ static void generic_get_mtrr(unsigned int reg, unsigned long *base,
{
unsigned int mask_lo, mask_hi, base_lo, base_hi;
unsigned int tmp, hi;
- int cpu;
/*
* get_mtrr doesn't need to update mtrr_state, also it could be called
* from any cpu, so try to print it out directly.
*/
- cpu = get_cpu();
+ get_cpu();
rdmsr(MTRRphysMask_MSR(reg), mask_lo, mask_hi);
diff --git a/arch/x86/kernel/cpu/mtrr/main.c b/arch/x86/kernel/cpu/mtrr/main.c
index 79556bd9b60..01c0f3ee6cc 100644
--- a/arch/x86/kernel/cpu/mtrr/main.c
+++ b/arch/x86/kernel/cpu/mtrr/main.c
@@ -35,6 +35,7 @@
#include <linux/types.h> /* FIXME: kvm_para.h needs this */
+#include <linux/stop_machine.h>
#include <linux/kvm_para.h>
#include <linux/uaccess.h>
#include <linux/module.h>
@@ -143,22 +144,28 @@ struct set_mtrr_data {
mtrr_type smp_type;
};
+static DEFINE_PER_CPU(struct cpu_stop_work, mtrr_work);
+
/**
- * ipi_handler - Synchronisation handler. Executed by "other" CPUs.
+ * mtrr_work_handler - Synchronisation handler. Executed by "other" CPUs.
* @info: pointer to mtrr configuration data
*
* Returns nothing.
*/
-static void ipi_handler(void *info)
+static int mtrr_work_handler(void *info)
{
#ifdef CONFIG_SMP
struct set_mtrr_data *data = info;
unsigned long flags;
+ atomic_dec(&data->count);
+ while (!atomic_read(&data->gate))
+ cpu_relax();
+
local_irq_save(flags);
atomic_dec(&data->count);
- while (!atomic_read(&data->gate))
+ while (atomic_read(&data->gate))
cpu_relax();
/* The master has cleared me to execute */
@@ -173,12 +180,13 @@ static void ipi_handler(void *info)
}
atomic_dec(&data->count);
- while (atomic_read(&data->gate))
+ while (!atomic_read(&data->gate))
cpu_relax();
atomic_dec(&data->count);
local_irq_restore(flags);
#endif
+ return 0;
}
static inline int types_compatible(mtrr_type type1, mtrr_type type2)
@@ -198,7 +206,7 @@ static inline int types_compatible(mtrr_type type1, mtrr_type type2)
*
* This is kinda tricky, but fortunately, Intel spelled it out for us cleanly:
*
- * 1. Send IPI to do the following:
+ * 1. Queue work to do the following on all processors:
* 2. Disable Interrupts
* 3. Wait for all procs to do so
* 4. Enter no-fill cache mode
@@ -215,14 +223,17 @@ static inline int types_compatible(mtrr_type type1, mtrr_type type2)
* 15. Enable interrupts.
*
* What does that mean for us? Well, first we set data.count to the number
- * of CPUs. As each CPU disables interrupts, it'll decrement it once. We wait
- * until it hits 0 and proceed. We set the data.gate flag and reset data.count.
- * Meanwhile, they are waiting for that flag to be set. Once it's set, each
+ * of CPUs. As each CPU announces that it started the rendezvous handler by
+ * decrementing the count, We reset data.count and set the data.gate flag
+ * allowing all the cpu's to proceed with the work. As each cpu disables
+ * interrupts, it'll decrement data.count once. We wait until it hits 0 and
+ * proceed. We clear the data.gate flag and reset data.count. Meanwhile, they
+ * are waiting for that flag to be cleared. Once it's cleared, each
* CPU goes through the transition of updating MTRRs.
* The CPU vendors may each do it differently,
* so we call mtrr_if->set() callback and let them take care of it.
* When they're done, they again decrement data->count and wait for data.gate
- * to be reset.
+ * to be set.
* When we finish, we wait for data.count to hit 0 and toggle the data.gate flag
* Everyone then enables interrupts and we all continue on.
*
@@ -234,6 +245,9 @@ set_mtrr(unsigned int reg, unsigned long base, unsigned long size, mtrr_type typ
{
struct set_mtrr_data data;
unsigned long flags;
+ int cpu;
+
+ preempt_disable();
data.smp_reg = reg;
data.smp_base = base;
@@ -246,10 +260,15 @@ set_mtrr(unsigned int reg, unsigned long base, unsigned long size, mtrr_type typ
atomic_set(&data.gate, 0);
/* Start the ball rolling on other CPUs */
- if (smp_call_function(ipi_handler, &data, 0) != 0)
- panic("mtrr: timed out waiting for other CPUs\n");
+ for_each_online_cpu(cpu) {
+ struct cpu_stop_work *work = &per_cpu(mtrr_work, cpu);
+
+ if (cpu == smp_processor_id())
+ continue;
+
+ stop_one_cpu_nowait(cpu, mtrr_work_handler, &data, work);
+ }
- local_irq_save(flags);
while (atomic_read(&data.count))
cpu_relax();
@@ -259,6 +278,16 @@ set_mtrr(unsigned int reg, unsigned long base, unsigned long size, mtrr_type typ
smp_wmb();
atomic_set(&data.gate, 1);
+ local_irq_save(flags);
+
+ while (atomic_read(&data.count))
+ cpu_relax();
+
+ /* Ok, reset count and toggle gate */
+ atomic_set(&data.count, num_booting_cpus() - 1);
+ smp_wmb();
+ atomic_set(&data.gate, 0);
+
/* Do our MTRR business */
/*
@@ -279,7 +308,7 @@ set_mtrr(unsigned int reg, unsigned long base, unsigned long size, mtrr_type typ
atomic_set(&data.count, num_booting_cpus() - 1);
smp_wmb();
- atomic_set(&data.gate, 0);
+ atomic_set(&data.gate, 1);
/*
* Wait here for everyone to have seen the gate change
@@ -289,6 +318,7 @@ set_mtrr(unsigned int reg, unsigned long base, unsigned long size, mtrr_type typ
cpu_relax();
local_irq_restore(flags);
+ preempt_enable();
}
/**
diff --git a/arch/x86/kernel/cpu/perf_event.c b/arch/x86/kernel/cpu/perf_event.c
index 5db5b7d65a1..f2da20fda02 100644
--- a/arch/x86/kernel/cpu/perf_event.c
+++ b/arch/x86/kernel/cpu/perf_event.c
@@ -220,6 +220,7 @@ struct x86_pmu {
struct perf_event *event);
struct event_constraint *event_constraints;
void (*quirks)(void);
+ int perfctr_second_write;
int (*cpu_prepare)(int cpu);
void (*cpu_starting)(int cpu);
@@ -295,10 +296,10 @@ x86_perf_event_update(struct perf_event *event)
* count to the generic event atomically:
*/
again:
- prev_raw_count = atomic64_read(&hwc->prev_count);
+ prev_raw_count = local64_read(&hwc->prev_count);
rdmsrl(hwc->event_base + idx, new_raw_count);
- if (atomic64_cmpxchg(&hwc->prev_count, prev_raw_count,
+ if (local64_cmpxchg(&hwc->prev_count, prev_raw_count,
new_raw_count) != prev_raw_count)
goto again;
@@ -313,8 +314,8 @@ again:
delta = (new_raw_count << shift) - (prev_raw_count << shift);
delta >>= shift;
- atomic64_add(delta, &event->count);
- atomic64_sub(delta, &hwc->period_left);
+ local64_add(delta, &event->count);
+ local64_sub(delta, &hwc->period_left);
return new_raw_count;
}
@@ -438,7 +439,7 @@ static int x86_setup_perfctr(struct perf_event *event)
if (!hwc->sample_period) {
hwc->sample_period = x86_pmu.max_period;
hwc->last_period = hwc->sample_period;
- atomic64_set(&hwc->period_left, hwc->sample_period);
+ local64_set(&hwc->period_left, hwc->sample_period);
} else {
/*
* If we have a PMU initialized but no APIC
@@ -885,7 +886,7 @@ static int
x86_perf_event_set_period(struct perf_event *event)
{
struct hw_perf_event *hwc = &event->hw;
- s64 left = atomic64_read(&hwc->period_left);
+ s64 left = local64_read(&hwc->period_left);
s64 period = hwc->sample_period;
int ret = 0, idx = hwc->idx;
@@ -897,14 +898,14 @@ x86_perf_event_set_period(struct perf_event *event)
*/
if (unlikely(left <= -period)) {
left = period;
- atomic64_set(&hwc->period_left, left);
+ local64_set(&hwc->period_left, left);
hwc->last_period = period;
ret = 1;
}
if (unlikely(left <= 0)) {
left += period;
- atomic64_set(&hwc->period_left, left);
+ local64_set(&hwc->period_left, left);
hwc->last_period = period;
ret = 1;
}
@@ -923,10 +924,19 @@ x86_perf_event_set_period(struct perf_event *event)
* The hw event starts counting from this event offset,
* mark it to be able to extra future deltas:
*/
- atomic64_set(&hwc->prev_count, (u64)-left);
+ local64_set(&hwc->prev_count, (u64)-left);
- wrmsrl(hwc->event_base + idx,
+ wrmsrl(hwc->event_base + idx, (u64)(-left) & x86_pmu.cntval_mask);
+
+ /*
+ * Due to erratum on certan cpu we need
+ * a second write to be sure the register
+ * is updated properly
+ */
+ if (x86_pmu.perfctr_second_write) {
+ wrmsrl(hwc->event_base + idx,
(u64)(-left) & x86_pmu.cntval_mask);
+ }
perf_event_update_userpage(event);
@@ -969,7 +979,7 @@ static int x86_pmu_enable(struct perf_event *event)
* skip the schedulability test here, it will be peformed
* at commit time(->commit_txn) as a whole
*/
- if (cpuc->group_flag & PERF_EVENT_TXN_STARTED)
+ if (cpuc->group_flag & PERF_EVENT_TXN)
goto out;
ret = x86_pmu.schedule_events(cpuc, n, assign);
@@ -1096,7 +1106,7 @@ static void x86_pmu_disable(struct perf_event *event)
* The events never got scheduled and ->cancel_txn will truncate
* the event_list.
*/
- if (cpuc->group_flag & PERF_EVENT_TXN_STARTED)
+ if (cpuc->group_flag & PERF_EVENT_TXN)
return;
x86_pmu_stop(event);
@@ -1388,7 +1398,7 @@ static void x86_pmu_start_txn(const struct pmu *pmu)
{
struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
- cpuc->group_flag |= PERF_EVENT_TXN_STARTED;
+ cpuc->group_flag |= PERF_EVENT_TXN;
cpuc->n_txn = 0;
}
@@ -1401,7 +1411,7 @@ static void x86_pmu_cancel_txn(const struct pmu *pmu)
{
struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
- cpuc->group_flag &= ~PERF_EVENT_TXN_STARTED;
+ cpuc->group_flag &= ~PERF_EVENT_TXN;
/*
* Truncate the collected events.
*/
@@ -1435,11 +1445,7 @@ static int x86_pmu_commit_txn(const struct pmu *pmu)
*/
memcpy(cpuc->assign, assign, n*sizeof(int));
- /*
- * Clear out the txn count so that ->cancel_txn() which gets
- * run after ->commit_txn() doesn't undo things.
- */
- cpuc->n_txn = 0;
+ cpuc->group_flag &= ~PERF_EVENT_TXN;
return 0;
}
@@ -1607,8 +1613,6 @@ static const struct stacktrace_ops backtrace_ops = {
.walk_stack = print_context_stack_bp,
};
-#include "../dumpstack.h"
-
static void
perf_callchain_kernel(struct pt_regs *regs, struct perf_callchain_entry *entry)
{
@@ -1730,22 +1734,6 @@ struct perf_callchain_entry *perf_callchain(struct pt_regs *regs)
return entry;
}
-void perf_arch_fetch_caller_regs(struct pt_regs *regs, unsigned long ip, int skip)
-{
- regs->ip = ip;
- /*
- * perf_arch_fetch_caller_regs adds another call, we need to increment
- * the skip level
- */
- regs->bp = rewind_frame_pointer(skip + 1);
- regs->cs = __KERNEL_CS;
- /*
- * We abuse bit 3 to pass exact information, see perf_misc_flags
- * and the comment with PERF_EFLAGS_EXACT.
- */
- regs->flags = 0;
-}
-
unsigned long perf_instruction_pointer(struct pt_regs *regs)
{
unsigned long ip;
diff --git a/arch/x86/kernel/cpu/perf_event_p4.c b/arch/x86/kernel/cpu/perf_event_p4.c
index ae85d69644d..107711bf0ee 100644
--- a/arch/x86/kernel/cpu/perf_event_p4.c
+++ b/arch/x86/kernel/cpu/perf_event_p4.c
@@ -21,22 +21,36 @@ struct p4_event_bind {
char cntr[2][P4_CNTR_LIMIT]; /* counter index (offset), -1 on abscence */
};
-struct p4_cache_event_bind {
+struct p4_pebs_bind {
unsigned int metric_pebs;
unsigned int metric_vert;
};
-#define P4_GEN_CACHE_EVENT_BIND(name) \
- [P4_CACHE__##name] = { \
- .metric_pebs = P4_PEBS__##name, \
- .metric_vert = P4_VERT__##name, \
+/* it sets P4_PEBS_ENABLE_UOP_TAG as well */
+#define P4_GEN_PEBS_BIND(name, pebs, vert) \
+ [P4_PEBS_METRIC__##name] = { \
+ .metric_pebs = pebs | P4_PEBS_ENABLE_UOP_TAG, \
+ .metric_vert = vert, \
}
-static struct p4_cache_event_bind p4_cache_event_bind_map[] = {
- P4_GEN_CACHE_EVENT_BIND(1stl_cache_load_miss_retired),
- P4_GEN_CACHE_EVENT_BIND(2ndl_cache_load_miss_retired),
- P4_GEN_CACHE_EVENT_BIND(dtlb_load_miss_retired),
- P4_GEN_CACHE_EVENT_BIND(dtlb_store_miss_retired),
+/*
+ * note we have P4_PEBS_ENABLE_UOP_TAG always set here
+ *
+ * it's needed for mapping P4_PEBS_CONFIG_METRIC_MASK bits of
+ * event configuration to find out which values are to be
+ * written into MSR_IA32_PEBS_ENABLE and MSR_P4_PEBS_MATRIX_VERT
+ * resgisters
+ */
+static struct p4_pebs_bind p4_pebs_bind_map[] = {
+ P4_GEN_PEBS_BIND(1stl_cache_load_miss_retired, 0x0000001, 0x0000001),
+ P4_GEN_PEBS_BIND(2ndl_cache_load_miss_retired, 0x0000002, 0x0000001),
+ P4_GEN_PEBS_BIND(dtlb_load_miss_retired, 0x0000004, 0x0000001),
+ P4_GEN_PEBS_BIND(dtlb_store_miss_retired, 0x0000004, 0x0000002),
+ P4_GEN_PEBS_BIND(dtlb_all_miss_retired, 0x0000004, 0x0000003),
+ P4_GEN_PEBS_BIND(tagged_mispred_branch, 0x0018000, 0x0000010),
+ P4_GEN_PEBS_BIND(mob_load_replay_retired, 0x0000200, 0x0000001),
+ P4_GEN_PEBS_BIND(split_load_retired, 0x0000400, 0x0000001),
+ P4_GEN_PEBS_BIND(split_store_retired, 0x0000400, 0x0000002),
};
/*
@@ -281,10 +295,10 @@ static struct p4_event_bind p4_event_bind_map[] = {
},
};
-#define P4_GEN_CACHE_EVENT(event, bit, cache_event) \
+#define P4_GEN_CACHE_EVENT(event, bit, metric) \
p4_config_pack_escr(P4_ESCR_EVENT(event) | \
P4_ESCR_EMASK_BIT(event, bit)) | \
- p4_config_pack_cccr(cache_event | \
+ p4_config_pack_cccr(metric | \
P4_CCCR_ESEL(P4_OPCODE_ESEL(P4_OPCODE(event))))
static __initconst const u64 p4_hw_cache_event_ids
@@ -296,34 +310,34 @@ static __initconst const u64 p4_hw_cache_event_ids
[ C(OP_READ) ] = {
[ C(RESULT_ACCESS) ] = 0x0,
[ C(RESULT_MISS) ] = P4_GEN_CACHE_EVENT(P4_EVENT_REPLAY_EVENT, NBOGUS,
- P4_CACHE__1stl_cache_load_miss_retired),
+ P4_PEBS_METRIC__1stl_cache_load_miss_retired),
},
},
[ C(LL ) ] = {
[ C(OP_READ) ] = {
[ C(RESULT_ACCESS) ] = 0x0,
[ C(RESULT_MISS) ] = P4_GEN_CACHE_EVENT(P4_EVENT_REPLAY_EVENT, NBOGUS,
- P4_CACHE__2ndl_cache_load_miss_retired),
+ P4_PEBS_METRIC__2ndl_cache_load_miss_retired),
},
},
[ C(DTLB) ] = {
[ C(OP_READ) ] = {
[ C(RESULT_ACCESS) ] = 0x0,
[ C(RESULT_MISS) ] = P4_GEN_CACHE_EVENT(P4_EVENT_REPLAY_EVENT, NBOGUS,
- P4_CACHE__dtlb_load_miss_retired),
+ P4_PEBS_METRIC__dtlb_load_miss_retired),
},
[ C(OP_WRITE) ] = {
[ C(RESULT_ACCESS) ] = 0x0,
[ C(RESULT_MISS) ] = P4_GEN_CACHE_EVENT(P4_EVENT_REPLAY_EVENT, NBOGUS,
- P4_CACHE__dtlb_store_miss_retired),
+ P4_PEBS_METRIC__dtlb_store_miss_retired),
},
},
[ C(ITLB) ] = {
[ C(OP_READ) ] = {
[ C(RESULT_ACCESS) ] = P4_GEN_CACHE_EVENT(P4_EVENT_ITLB_REFERENCE, HIT,
- P4_CACHE__itlb_reference_hit),
+ P4_PEBS_METRIC__none),
[ C(RESULT_MISS) ] = P4_GEN_CACHE_EVENT(P4_EVENT_ITLB_REFERENCE, MISS,
- P4_CACHE__itlb_reference_miss),
+ P4_PEBS_METRIC__none),
},
[ C(OP_WRITE) ] = {
[ C(RESULT_ACCESS) ] = -1,
@@ -414,11 +428,37 @@ static u64 p4_pmu_event_map(int hw_event)
return config;
}
+static int p4_validate_raw_event(struct perf_event *event)
+{
+ unsigned int v;
+
+ /* user data may have out-of-bound event index */
+ v = p4_config_unpack_event(event->attr.config);
+ if (v >= ARRAY_SIZE(p4_event_bind_map)) {
+ pr_warning("P4 PMU: Unknown event code: %d\n", v);
+ return -EINVAL;
+ }
+
+ /*
+ * it may have some screwed PEBS bits
+ */
+ if (p4_config_pebs_has(event->attr.config, P4_PEBS_CONFIG_ENABLE)) {
+ pr_warning("P4 PMU: PEBS are not supported yet\n");
+ return -EINVAL;
+ }
+ v = p4_config_unpack_metric(event->attr.config);
+ if (v >= ARRAY_SIZE(p4_pebs_bind_map)) {
+ pr_warning("P4 PMU: Unknown metric code: %d\n", v);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
static int p4_hw_config(struct perf_event *event)
{
int cpu = get_cpu();
int rc = 0;
- unsigned int evnt;
u32 escr, cccr;
/*
@@ -438,12 +478,9 @@ static int p4_hw_config(struct perf_event *event)
if (event->attr.type == PERF_TYPE_RAW) {
- /* user data may have out-of-bound event index */
- evnt = p4_config_unpack_event(event->attr.config);
- if (evnt >= ARRAY_SIZE(p4_event_bind_map)) {
- rc = -EINVAL;
+ rc = p4_validate_raw_event(event);
+ if (rc)
goto out;
- }
/*
* We don't control raw events so it's up to the caller
@@ -451,12 +488,15 @@ static int p4_hw_config(struct perf_event *event)
* on HT machine but allow HT-compatible specifics to be
* passed on)
*
+ * Note that for RAW events we allow user to use P4_CCCR_RESERVED
+ * bits since we keep additional info here (for cache events and etc)
+ *
* XXX: HT wide things should check perf_paranoid_cpu() &&
* CAP_SYS_ADMIN
*/
event->hw.config |= event->attr.config &
(p4_config_pack_escr(P4_ESCR_MASK_HT) |
- p4_config_pack_cccr(P4_CCCR_MASK_HT));
+ p4_config_pack_cccr(P4_CCCR_MASK_HT | P4_CCCR_RESERVED));
}
rc = x86_setup_perfctr(event);
@@ -482,6 +522,29 @@ static inline int p4_pmu_clear_cccr_ovf(struct hw_perf_event *hwc)
return overflow;
}
+static void p4_pmu_disable_pebs(void)
+{
+ /*
+ * FIXME
+ *
+ * It's still allowed that two threads setup same cache
+ * events so we can't simply clear metrics until we knew
+ * noone is depending on us, so we need kind of counter
+ * for "ReplayEvent" users.
+ *
+ * What is more complex -- RAW events, if user (for some
+ * reason) will pass some cache event metric with improper
+ * event opcode -- it's fine from hardware point of view
+ * but completely nonsence from "meaning" of such action.
+ *
+ * So at moment let leave metrics turned on forever -- it's
+ * ok for now but need to be revisited!
+ *
+ * (void)checking_wrmsrl(MSR_IA32_PEBS_ENABLE, (u64)0);
+ * (void)checking_wrmsrl(MSR_P4_PEBS_MATRIX_VERT, (u64)0);
+ */
+}
+
static inline void p4_pmu_disable_event(struct perf_event *event)
{
struct hw_perf_event *hwc = &event->hw;
@@ -507,6 +570,26 @@ static void p4_pmu_disable_all(void)
continue;
p4_pmu_disable_event(event);
}
+
+ p4_pmu_disable_pebs();
+}
+
+/* configuration must be valid */
+static void p4_pmu_enable_pebs(u64 config)
+{
+ struct p4_pebs_bind *bind;
+ unsigned int idx;
+
+ BUILD_BUG_ON(P4_PEBS_METRIC__max > P4_PEBS_CONFIG_METRIC_MASK);
+
+ idx = p4_config_unpack_metric(config);
+ if (idx == P4_PEBS_METRIC__none)
+ return;
+
+ bind = &p4_pebs_bind_map[idx];
+
+ (void)checking_wrmsrl(MSR_IA32_PEBS_ENABLE, (u64)bind->metric_pebs);
+ (void)checking_wrmsrl(MSR_P4_PEBS_MATRIX_VERT, (u64)bind->metric_vert);
}
static void p4_pmu_enable_event(struct perf_event *event)
@@ -515,9 +598,7 @@ static void p4_pmu_enable_event(struct perf_event *event)
int thread = p4_ht_config_thread(hwc->config);
u64 escr_conf = p4_config_unpack_escr(p4_clear_ht_bit(hwc->config));
unsigned int idx = p4_config_unpack_event(hwc->config);
- unsigned int idx_cache = p4_config_unpack_cache_event(hwc->config);
struct p4_event_bind *bind;
- struct p4_cache_event_bind *bind_cache;
u64 escr_addr, cccr;
bind = &p4_event_bind_map[idx];
@@ -537,16 +618,10 @@ static void p4_pmu_enable_event(struct perf_event *event)
cccr = p4_config_unpack_cccr(hwc->config);
/*
- * it could be Cache event so that we need to
- * set metrics into additional MSRs
+ * it could be Cache event so we need to write metrics
+ * into additional MSRs
*/
- BUILD_BUG_ON(P4_CACHE__MAX > P4_CCCR_CACHE_OPS_MASK);
- if (idx_cache > P4_CACHE__NONE &&
- idx_cache < ARRAY_SIZE(p4_cache_event_bind_map)) {
- bind_cache = &p4_cache_event_bind_map[idx_cache];
- (void)checking_wrmsrl(MSR_IA32_PEBS_ENABLE, (u64)bind_cache->metric_pebs);
- (void)checking_wrmsrl(MSR_P4_PEBS_MATRIX_VERT, (u64)bind_cache->metric_vert);
- }
+ p4_pmu_enable_pebs(hwc->config);
(void)checking_wrmsrl(escr_addr, escr_conf);
(void)checking_wrmsrl(hwc->config_base + hwc->idx,
@@ -829,6 +904,15 @@ static __initconst const struct x86_pmu p4_pmu = {
.max_period = (1ULL << 39) - 1,
.hw_config = p4_hw_config,
.schedule_events = p4_pmu_schedule_events,
+ /*
+ * This handles erratum N15 in intel doc 249199-029,
+ * the counter may not be updated correctly on write
+ * so we need a second write operation to do the trick
+ * (the official workaround didn't work)
+ *
+ * the former idea is taken from OProfile code
+ */
+ .perfctr_second_write = 1,
};
static __init int p4_pmu_init(void)
diff --git a/arch/x86/kernel/cpu/scattered.c b/arch/x86/kernel/cpu/scattered.c
new file mode 100644
index 00000000000..34b4dad6f0b
--- /dev/null
+++ b/arch/x86/kernel/cpu/scattered.c
@@ -0,0 +1,63 @@
+/*
+ * Routines to indentify additional cpu features that are scattered in
+ * cpuid space.
+ */
+#include <linux/cpu.h>
+
+#include <asm/pat.h>
+#include <asm/processor.h>
+
+#include <asm/apic.h>
+
+struct cpuid_bit {
+ u16 feature;
+ u8 reg;
+ u8 bit;
+ u32 level;
+ u32 sub_leaf;
+};
+
+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 __cpuinitconst cpuid_bits[] = {
+ { X86_FEATURE_IDA, CR_EAX, 1, 0x00000006, 0 },
+ { X86_FEATURE_ARAT, CR_EAX, 2, 0x00000006, 0 },
+ { X86_FEATURE_PLN, CR_EAX, 4, 0x00000006, 0 },
+ { X86_FEATURE_PTS, CR_EAX, 6, 0x00000006, 0 },
+ { X86_FEATURE_APERFMPERF, CR_ECX, 0, 0x00000006, 0 },
+ { X86_FEATURE_EPB, CR_ECX, 3, 0x00000006, 0 },
+ { X86_FEATURE_XSAVEOPT, CR_EAX, 0, 0x0000000d, 1 },
+ { X86_FEATURE_CPB, CR_EDX, 9, 0x80000007, 0 },
+ { X86_FEATURE_NPT, CR_EDX, 0, 0x8000000a, 0 },
+ { X86_FEATURE_LBRV, CR_EDX, 1, 0x8000000a, 0 },
+ { X86_FEATURE_SVML, CR_EDX, 2, 0x8000000a, 0 },
+ { X86_FEATURE_NRIPS, CR_EDX, 3, 0x8000000a, 0 },
+ { 0, 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_count(cb->level, cb->sub_leaf, &regs[CR_EAX],
+ &regs[CR_EBX], &regs[CR_ECX], &regs[CR_EDX]);
+
+ if (regs[cb->reg] & (1 << cb->bit))
+ set_cpu_cap(c, cb->feature);
+ }
+}
diff --git a/arch/x86/kernel/cpu/addon_cpuid_features.c b/arch/x86/kernel/cpu/topology.c
index 10fa5684a66..4397e987a1c 100644
--- a/arch/x86/kernel/cpu/addon_cpuid_features.c
+++ b/arch/x86/kernel/cpu/topology.c
@@ -1,62 +1,14 @@
/*
- * Routines to indentify additional cpu features that are scattered in
- * cpuid space.
+ * Check for extended topology enumeration cpuid leaf 0xb and if it
+ * exists, use it for populating initial_apicid and cpu topology
+ * detection.
*/
-#include <linux/cpu.h>
+#include <linux/cpu.h>
+#include <asm/apic.h>
#include <asm/pat.h>
#include <asm/processor.h>
-#include <asm/apic.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 __cpuinitconst cpuid_bits[] = {
- { X86_FEATURE_IDA, CR_EAX, 1, 0x00000006 },
- { X86_FEATURE_ARAT, CR_EAX, 2, 0x00000006 },
- { X86_FEATURE_APERFMPERF, CR_ECX, 0, 0x00000006 },
- { X86_FEATURE_CPB, CR_EDX, 9, 0x80000007 },
- { X86_FEATURE_NPT, CR_EDX, 0, 0x8000000a },
- { X86_FEATURE_LBRV, CR_EDX, 1, 0x8000000a },
- { X86_FEATURE_SVML, CR_EDX, 2, 0x8000000a },
- { X86_FEATURE_NRIPS, CR_EDX, 3, 0x8000000a },
- { 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_cpu_cap(c, cb->feature);
- }
-}
-
/* leaf 0xb SMT level */
#define SMT_LEVEL 0
diff --git a/arch/x86/kernel/cpu/vmware.c b/arch/x86/kernel/cpu/vmware.c
index b9d1ff58844..227b0448960 100644
--- a/arch/x86/kernel/cpu/vmware.c
+++ b/arch/x86/kernel/cpu/vmware.c
@@ -51,7 +51,7 @@ static inline int __vmware_platform(void)
static unsigned long vmware_get_tsc_khz(void)
{
- uint64_t tsc_hz;
+ uint64_t tsc_hz, lpj;
uint32_t eax, ebx, ecx, edx;
VMWARE_PORT(GETHZ, eax, ebx, ecx, edx);
@@ -62,6 +62,13 @@ static unsigned long vmware_get_tsc_khz(void)
printk(KERN_INFO "TSC freq read from hypervisor : %lu.%03lu MHz\n",
(unsigned long) tsc_hz / 1000,
(unsigned long) tsc_hz % 1000);
+
+ if (!preset_lpj) {
+ lpj = ((u64)tsc_hz * 1000);
+ do_div(lpj, HZ);
+ preset_lpj = lpj;
+ }
+
return tsc_hz;
}
diff --git a/arch/x86/kernel/dumpstack.c b/arch/x86/kernel/dumpstack.c
index c89a386930b..6e8752c1bd5 100644
--- a/arch/x86/kernel/dumpstack.c
+++ b/arch/x86/kernel/dumpstack.c
@@ -18,7 +18,6 @@
#include <asm/stacktrace.h>
-#include "dumpstack.h"
int panic_on_unrecovered_nmi;
int panic_on_io_nmi;
diff --git a/arch/x86/kernel/dumpstack.h b/arch/x86/kernel/dumpstack.h
deleted file mode 100644
index e1a93be4fd4..00000000000
--- a/arch/x86/kernel/dumpstack.h
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright (C) 1991, 1992 Linus Torvalds
- * Copyright (C) 2000, 2001, 2002 Andi Kleen, SuSE Labs
- */
-
-#ifndef DUMPSTACK_H
-#define DUMPSTACK_H
-
-#ifdef CONFIG_X86_32
-#define STACKSLOTS_PER_LINE 8
-#define get_bp(bp) asm("movl %%ebp, %0" : "=r" (bp) :)
-#else
-#define STACKSLOTS_PER_LINE 4
-#define get_bp(bp) asm("movq %%rbp, %0" : "=r" (bp) :)
-#endif
-
-#include <linux/uaccess.h>
-
-extern void
-show_trace_log_lvl(struct task_struct *task, struct pt_regs *regs,
- unsigned long *stack, unsigned long bp, char *log_lvl);
-
-extern void
-show_stack_log_lvl(struct task_struct *task, struct pt_regs *regs,
- unsigned long *sp, unsigned long bp, char *log_lvl);
-
-extern unsigned int code_bytes;
-
-/* The form of the top of the frame on the stack */
-struct stack_frame {
- struct stack_frame *next_frame;
- unsigned long return_address;
-};
-
-struct stack_frame_ia32 {
- u32 next_frame;
- u32 return_address;
-};
-
-static inline unsigned long rewind_frame_pointer(int n)
-{
- struct stack_frame *frame;
-
- get_bp(frame);
-
-#ifdef CONFIG_FRAME_POINTER
- while (n--) {
- if (probe_kernel_address(&frame->next_frame, frame))
- break;
- }
-#endif
-
- return (unsigned long)frame;
-}
-
-#endif /* DUMPSTACK_H */
diff --git a/arch/x86/kernel/dumpstack_32.c b/arch/x86/kernel/dumpstack_32.c
index 11540a189d9..0f6376ffa2d 100644
--- a/arch/x86/kernel/dumpstack_32.c
+++ b/arch/x86/kernel/dumpstack_32.c
@@ -16,8 +16,6 @@
#include <asm/stacktrace.h>
-#include "dumpstack.h"
-
void dump_trace(struct task_struct *task, struct pt_regs *regs,
unsigned long *stack, unsigned long bp,
diff --git a/arch/x86/kernel/dumpstack_64.c b/arch/x86/kernel/dumpstack_64.c
index 272c9f1f05f..57a21f11c79 100644
--- a/arch/x86/kernel/dumpstack_64.c
+++ b/arch/x86/kernel/dumpstack_64.c
@@ -16,7 +16,6 @@
#include <asm/stacktrace.h>
-#include "dumpstack.h"
#define N_EXCEPTION_STACKS_END \
(N_EXCEPTION_STACKS + DEBUG_STKSZ/EXCEPTION_STKSZ - 2)
diff --git a/arch/x86/kernel/entry_32.S b/arch/x86/kernel/entry_32.S
index cd49141cf15..227d00920d2 100644
--- a/arch/x86/kernel/entry_32.S
+++ b/arch/x86/kernel/entry_32.S
@@ -611,14 +611,14 @@ ldt_ss:
* compensating for the offset by changing to the ESPFIX segment with
* a base address that matches for the difference.
*/
+#define GDT_ESPFIX_SS PER_CPU_VAR(gdt_page) + (GDT_ENTRY_ESPFIX_SS * 8)
mov %esp, %edx /* load kernel esp */
mov PT_OLDESP(%esp), %eax /* load userspace esp */
mov %dx, %ax /* eax: new kernel esp */
sub %eax, %edx /* offset (low word is 0) */
- PER_CPU(gdt_page, %ebx)
shr $16, %edx
- mov %dl, GDT_ENTRY_ESPFIX_SS * 8 + 4(%ebx) /* bits 16..23 */
- mov %dh, GDT_ENTRY_ESPFIX_SS * 8 + 7(%ebx) /* bits 24..31 */
+ mov %dl, GDT_ESPFIX_SS + 4 /* bits 16..23 */
+ mov %dh, GDT_ESPFIX_SS + 7 /* bits 24..31 */
pushl $__ESPFIX_SS
CFI_ADJUST_CFA_OFFSET 4
push %eax /* new kernel esp */
@@ -791,9 +791,8 @@ ptregs_clone:
* normal stack and adjusts ESP with the matching offset.
*/
/* fixup the stack */
- PER_CPU(gdt_page, %ebx)
- mov GDT_ENTRY_ESPFIX_SS * 8 + 4(%ebx), %al /* bits 16..23 */
- mov GDT_ENTRY_ESPFIX_SS * 8 + 7(%ebx), %ah /* bits 24..31 */
+ mov GDT_ESPFIX_SS + 4, %al /* bits 16..23 */
+ mov GDT_ESPFIX_SS + 7, %ah /* bits 24..31 */
shl $16, %eax
addl %esp, %eax /* the adjusted stack pointer */
pushl $__KERNEL_DS
@@ -914,7 +913,7 @@ ENTRY(simd_coprocessor_error)
.balign 4
.long 661b
.long 663f
- .byte X86_FEATURE_XMM
+ .word X86_FEATURE_XMM
.byte 662b-661b
.byte 664f-663f
.previous
@@ -1166,6 +1165,9 @@ ENTRY(xen_failsafe_callback)
.previous
ENDPROC(xen_failsafe_callback)
+BUILD_INTERRUPT3(xen_hvm_callback_vector, XEN_HVM_EVTCHN_CALLBACK,
+ xen_evtchn_do_upcall)
+
#endif /* CONFIG_XEN */
#ifdef CONFIG_FUNCTION_TRACER
diff --git a/arch/x86/kernel/entry_64.S b/arch/x86/kernel/entry_64.S
index 4db7c4d12ff..c5ea5cdbe7b 100644
--- a/arch/x86/kernel/entry_64.S
+++ b/arch/x86/kernel/entry_64.S
@@ -1065,6 +1065,7 @@ ENTRY(\sym)
END(\sym)
.endm
+#define INIT_TSS_IST(x) PER_CPU_VAR(init_tss) + (TSS_ist + ((x) - 1) * 8)
.macro paranoidzeroentry_ist sym do_sym ist
ENTRY(\sym)
INTR_FRAME
@@ -1076,10 +1077,9 @@ ENTRY(\sym)
TRACE_IRQS_OFF
movq %rsp,%rdi /* pt_regs pointer */
xorl %esi,%esi /* no error code */
- PER_CPU(init_tss, %r12)
- subq $EXCEPTION_STKSZ, TSS_ist + (\ist - 1) * 8(%r12)
+ subq $EXCEPTION_STKSZ, INIT_TSS_IST(\ist)
call \do_sym
- addq $EXCEPTION_STKSZ, TSS_ist + (\ist - 1) * 8(%r12)
+ addq $EXCEPTION_STKSZ, INIT_TSS_IST(\ist)
jmp paranoid_exit /* %ebx: no swapgs flag */
CFI_ENDPROC
END(\sym)
@@ -1329,6 +1329,9 @@ ENTRY(xen_failsafe_callback)
CFI_ENDPROC
END(xen_failsafe_callback)
+apicinterrupt XEN_HVM_EVTCHN_CALLBACK \
+ xen_hvm_callback_vector xen_evtchn_do_upcall
+
#endif /* CONFIG_XEN */
/*
diff --git a/arch/x86/kernel/head32.c b/arch/x86/kernel/head32.c
index b2e24603739..784360c0625 100644
--- a/arch/x86/kernel/head32.c
+++ b/arch/x86/kernel/head32.c
@@ -20,7 +20,7 @@
static void __init i386_default_early_setup(void)
{
- /* Initilize 32bit specific setup functions */
+ /* Initialize 32bit specific setup functions */
x86_init.resources.probe_roms = probe_roms;
x86_init.resources.reserve_resources = i386_reserve_resources;
x86_init.mpparse.setup_ioapic_ids = setup_ioapic_ids_from_mpc;
diff --git a/arch/x86/kernel/head_32.S b/arch/x86/kernel/head_32.S
index 37c3d4b17d8..ff4c453e13f 100644
--- a/arch/x86/kernel/head_32.S
+++ b/arch/x86/kernel/head_32.S
@@ -131,6 +131,12 @@ ENTRY(startup_32)
movsl
1:
+#ifdef CONFIG_OLPC_OPENFIRMWARE
+ /* save OFW's pgdir table for later use when calling into OFW */
+ movl %cr3, %eax
+ movl %eax, pa(olpc_ofw_pgd)
+#endif
+
#ifdef CONFIG_PARAVIRT
/* This is can only trip for a broken bootloader... */
cmpw $0x207, pa(boot_params + BP_version)
diff --git a/arch/x86/kernel/head_64.S b/arch/x86/kernel/head_64.S
index 3d1e6f16b7a..239046bd447 100644
--- a/arch/x86/kernel/head_64.S
+++ b/arch/x86/kernel/head_64.S
@@ -234,9 +234,8 @@ ENTRY(secondary_startup_64)
* init data section till per cpu areas are set up.
*/
movl $MSR_GS_BASE,%ecx
- movq initial_gs(%rip),%rax
- movq %rax,%rdx
- shrq $32,%rdx
+ movl initial_gs(%rip),%eax
+ movl initial_gs+4(%rip),%edx
wrmsr
/* esi is pointer to real mode structure with interesting info.
diff --git a/arch/x86/kernel/hpet.c b/arch/x86/kernel/hpet.c
index ba390d73117..33dbcc4ec5f 100644
--- a/arch/x86/kernel/hpet.c
+++ b/arch/x86/kernel/hpet.c
@@ -16,7 +16,6 @@
#include <asm/hpet.h>
#define HPET_MASK CLOCKSOURCE_MASK(32)
-#define HPET_SHIFT 22
/* FSEC = 10^-15
NSEC = 10^-9 */
@@ -787,7 +786,6 @@ static struct clocksource clocksource_hpet = {
.rating = 250,
.read = read_hpet,
.mask = HPET_MASK,
- .shift = HPET_SHIFT,
.flags = CLOCK_SOURCE_IS_CONTINUOUS,
.resume = hpet_resume_counter,
#ifdef CONFIG_X86_64
@@ -798,6 +796,7 @@ static struct clocksource clocksource_hpet = {
static int hpet_clocksource_register(void)
{
u64 start, now;
+ u64 hpet_freq;
cycle_t t1;
/* Start the counter */
@@ -832,9 +831,15 @@ static int hpet_clocksource_register(void)
* mult = (hpet_period * 2^shift)/10^6
* mult = (hpet_period << shift)/FSEC_PER_NSEC
*/
- clocksource_hpet.mult = div_sc(hpet_period, FSEC_PER_NSEC, HPET_SHIFT);
- clocksource_register(&clocksource_hpet);
+ /* Need to convert hpet_period (fsec/cyc) to cyc/sec:
+ *
+ * cyc/sec = FSEC_PER_SEC/hpet_period(fsec/cyc)
+ * cyc/sec = (FSEC_PER_NSEC * NSEC_PER_SEC)/hpet_period
+ */
+ hpet_freq = FSEC_PER_NSEC * NSEC_PER_SEC;
+ do_div(hpet_freq, hpet_period);
+ clocksource_register_hz(&clocksource_hpet, (u32)hpet_freq);
return 0;
}
diff --git a/arch/x86/kernel/hw_breakpoint.c b/arch/x86/kernel/hw_breakpoint.c
index a8f1b803d2f..a474ec37c32 100644
--- a/arch/x86/kernel/hw_breakpoint.c
+++ b/arch/x86/kernel/hw_breakpoint.c
@@ -208,6 +208,9 @@ int arch_bp_generic_fields(int x86_len, int x86_type,
{
/* Len */
switch (x86_len) {
+ case X86_BREAKPOINT_LEN_X:
+ *gen_len = sizeof(long);
+ break;
case X86_BREAKPOINT_LEN_1:
*gen_len = HW_BREAKPOINT_LEN_1;
break;
@@ -251,6 +254,29 @@ static int arch_build_bp_info(struct perf_event *bp)
info->address = bp->attr.bp_addr;
+ /* Type */
+ switch (bp->attr.bp_type) {
+ case HW_BREAKPOINT_W:
+ info->type = X86_BREAKPOINT_WRITE;
+ break;
+ case HW_BREAKPOINT_W | HW_BREAKPOINT_R:
+ info->type = X86_BREAKPOINT_RW;
+ break;
+ case HW_BREAKPOINT_X:
+ info->type = X86_BREAKPOINT_EXECUTE;
+ /*
+ * x86 inst breakpoints need to have a specific undefined len.
+ * But we still need to check userspace is not trying to setup
+ * an unsupported length, to get a range breakpoint for example.
+ */
+ if (bp->attr.bp_len == sizeof(long)) {
+ info->len = X86_BREAKPOINT_LEN_X;
+ return 0;
+ }
+ default:
+ return -EINVAL;
+ }
+
/* Len */
switch (bp->attr.bp_len) {
case HW_BREAKPOINT_LEN_1:
@@ -271,21 +297,6 @@ static int arch_build_bp_info(struct perf_event *bp)
return -EINVAL;
}
- /* Type */
- switch (bp->attr.bp_type) {
- case HW_BREAKPOINT_W:
- info->type = X86_BREAKPOINT_WRITE;
- break;
- case HW_BREAKPOINT_W | HW_BREAKPOINT_R:
- info->type = X86_BREAKPOINT_RW;
- break;
- case HW_BREAKPOINT_X:
- info->type = X86_BREAKPOINT_EXECUTE;
- break;
- default:
- return -EINVAL;
- }
-
return 0;
}
/*
@@ -305,6 +316,9 @@ int arch_validate_hwbkpt_settings(struct perf_event *bp)
ret = -EINVAL;
switch (info->len) {
+ case X86_BREAKPOINT_LEN_X:
+ align = sizeof(long) -1;
+ break;
case X86_BREAKPOINT_LEN_1:
align = 0;
break;
@@ -466,6 +480,13 @@ static int __kprobes hw_breakpoint_handler(struct die_args *args)
perf_bp_event(bp, args->regs);
+ /*
+ * Set up resume flag to avoid breakpoint recursion when
+ * returning back to origin.
+ */
+ if (bp->hw.info.type == X86_BREAKPOINT_EXECUTE)
+ args->regs->flags |= X86_EFLAGS_RF;
+
rcu_read_unlock();
}
/*
diff --git a/arch/x86/kernel/i387.c b/arch/x86/kernel/i387.c
index 86cef6b3225..1f11f5ce668 100644
--- a/arch/x86/kernel/i387.c
+++ b/arch/x86/kernel/i387.c
@@ -59,18 +59,18 @@ void __cpuinit mxcsr_feature_mask_init(void)
stts();
}
-void __cpuinit init_thread_xstate(void)
+static void __cpuinit init_thread_xstate(void)
{
+ /*
+ * Note that xstate_size might be overwriten later during
+ * xsave_init().
+ */
+
if (!HAVE_HWFP) {
xstate_size = sizeof(struct i387_soft_struct);
return;
}
- if (cpu_has_xsave) {
- xsave_cntxt_init();
- return;
- }
-
if (cpu_has_fxsr)
xstate_size = sizeof(struct i387_fxsave_struct);
#ifdef CONFIG_X86_32
@@ -84,6 +84,7 @@ void __cpuinit init_thread_xstate(void)
* Called at bootup to set up the initial FPU state that is later cloned
* into all processes.
*/
+
void __cpuinit fpu_init(void)
{
unsigned long oldcr0 = read_cr0();
@@ -93,21 +94,26 @@ void __cpuinit fpu_init(void)
write_cr0(oldcr0 & ~(X86_CR0_TS|X86_CR0_EM)); /* clear TS and EM */
- /*
- * Boot processor to setup the FP and extended state context info.
- */
if (!smp_processor_id())
init_thread_xstate();
- xsave_init();
mxcsr_feature_mask_init();
/* clean state in init */
current_thread_info()->status = 0;
clear_used_math();
}
-#endif /* CONFIG_X86_64 */
-static void fpu_finit(struct fpu *fpu)
+#else /* CONFIG_X86_64 */
+
+void __cpuinit fpu_init(void)
+{
+ if (!smp_processor_id())
+ init_thread_xstate();
+}
+
+#endif /* CONFIG_X86_32 */
+
+void fpu_finit(struct fpu *fpu)
{
#ifdef CONFIG_X86_32
if (!HAVE_HWFP) {
@@ -132,6 +138,7 @@ static void fpu_finit(struct fpu *fpu)
fp->fos = 0xffff0000u;
}
}
+EXPORT_SYMBOL_GPL(fpu_finit);
/*
* The _current_ task is using the FPU for the first time
@@ -190,6 +197,8 @@ int xfpregs_get(struct task_struct *target, const struct user_regset *regset,
if (ret)
return ret;
+ sanitize_i387_state(target);
+
return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
&target->thread.fpu.state->fxsave, 0, -1);
}
@@ -207,6 +216,8 @@ int xfpregs_set(struct task_struct *target, const struct user_regset *regset,
if (ret)
return ret;
+ sanitize_i387_state(target);
+
ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
&target->thread.fpu.state->fxsave, 0, -1);
@@ -446,6 +457,8 @@ int fpregs_get(struct task_struct *target, const struct user_regset *regset,
-1);
}
+ sanitize_i387_state(target);
+
if (kbuf && pos == 0 && count == sizeof(env)) {
convert_from_fxsr(kbuf, target);
return 0;
@@ -467,6 +480,8 @@ int fpregs_set(struct task_struct *target, const struct user_regset *regset,
if (ret)
return ret;
+ sanitize_i387_state(target);
+
if (!HAVE_HWFP)
return fpregs_soft_set(target, regset, pos, count, kbuf, ubuf);
@@ -533,6 +548,9 @@ static int save_i387_xsave(void __user *buf)
struct _fpstate_ia32 __user *fx = buf;
int err = 0;
+
+ sanitize_i387_state(tsk);
+
/*
* For legacy compatible, we always set FP/SSE bits in the bit
* vector while saving the state to the user context.
diff --git a/arch/x86/kernel/kgdb.c b/arch/x86/kernel/kgdb.c
index 01ab17ae2ae..ef10940e1af 100644
--- a/arch/x86/kernel/kgdb.c
+++ b/arch/x86/kernel/kgdb.c
@@ -49,55 +49,94 @@
#include <asm/system.h>
#include <asm/apic.h>
-/**
- * pt_regs_to_gdb_regs - Convert ptrace regs to GDB regs
- * @gdb_regs: A pointer to hold the registers in the order GDB wants.
- * @regs: The &struct pt_regs of the current process.
- *
- * Convert the pt_regs in @regs into the format for registers that
- * GDB expects, stored in @gdb_regs.
- */
-void pt_regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *regs)
+struct dbg_reg_def_t dbg_reg_def[DBG_MAX_REG_NUM] =
{
-#ifndef CONFIG_X86_32
- u32 *gdb_regs32 = (u32 *)gdb_regs;
+#ifdef CONFIG_X86_32
+ { "ax", 4, offsetof(struct pt_regs, ax) },
+ { "cx", 4, offsetof(struct pt_regs, cx) },
+ { "dx", 4, offsetof(struct pt_regs, dx) },
+ { "bx", 4, offsetof(struct pt_regs, bx) },
+ { "sp", 4, offsetof(struct pt_regs, sp) },
+ { "bp", 4, offsetof(struct pt_regs, bp) },
+ { "si", 4, offsetof(struct pt_regs, si) },
+ { "di", 4, offsetof(struct pt_regs, di) },
+ { "ip", 4, offsetof(struct pt_regs, ip) },
+ { "flags", 4, offsetof(struct pt_regs, flags) },
+ { "cs", 4, offsetof(struct pt_regs, cs) },
+ { "ss", 4, offsetof(struct pt_regs, ss) },
+ { "ds", 4, offsetof(struct pt_regs, ds) },
+ { "es", 4, offsetof(struct pt_regs, es) },
+ { "fs", 4, -1 },
+ { "gs", 4, -1 },
+#else
+ { "ax", 8, offsetof(struct pt_regs, ax) },
+ { "bx", 8, offsetof(struct pt_regs, bx) },
+ { "cx", 8, offsetof(struct pt_regs, cx) },
+ { "dx", 8, offsetof(struct pt_regs, dx) },
+ { "si", 8, offsetof(struct pt_regs, dx) },
+ { "di", 8, offsetof(struct pt_regs, di) },
+ { "bp", 8, offsetof(struct pt_regs, bp) },
+ { "sp", 8, offsetof(struct pt_regs, sp) },
+ { "r8", 8, offsetof(struct pt_regs, r8) },
+ { "r9", 8, offsetof(struct pt_regs, r9) },
+ { "r10", 8, offsetof(struct pt_regs, r10) },
+ { "r11", 8, offsetof(struct pt_regs, r11) },
+ { "r12", 8, offsetof(struct pt_regs, r12) },
+ { "r13", 8, offsetof(struct pt_regs, r13) },
+ { "r14", 8, offsetof(struct pt_regs, r14) },
+ { "r15", 8, offsetof(struct pt_regs, r15) },
+ { "ip", 8, offsetof(struct pt_regs, ip) },
+ { "flags", 4, offsetof(struct pt_regs, flags) },
+ { "cs", 4, offsetof(struct pt_regs, cs) },
+ { "ss", 4, offsetof(struct pt_regs, ss) },
#endif
- gdb_regs[GDB_AX] = regs->ax;
- gdb_regs[GDB_BX] = regs->bx;
- gdb_regs[GDB_CX] = regs->cx;
- gdb_regs[GDB_DX] = regs->dx;
- gdb_regs[GDB_SI] = regs->si;
- gdb_regs[GDB_DI] = regs->di;
- gdb_regs[GDB_BP] = regs->bp;
- gdb_regs[GDB_PC] = regs->ip;
+};
+
+int dbg_set_reg(int regno, void *mem, struct pt_regs *regs)
+{
+ if (
#ifdef CONFIG_X86_32
- gdb_regs[GDB_PS] = regs->flags;
- gdb_regs[GDB_DS] = regs->ds;
- gdb_regs[GDB_ES] = regs->es;
- gdb_regs[GDB_CS] = regs->cs;
- gdb_regs[GDB_FS] = 0xFFFF;
- gdb_regs[GDB_GS] = 0xFFFF;
- if (user_mode_vm(regs)) {
- gdb_regs[GDB_SS] = regs->ss;
- gdb_regs[GDB_SP] = regs->sp;
- } else {
- gdb_regs[GDB_SS] = __KERNEL_DS;
- gdb_regs[GDB_SP] = kernel_stack_pointer(regs);
+ regno == GDB_SS || regno == GDB_FS || regno == GDB_GS ||
+#endif
+ regno == GDB_SP || regno == GDB_ORIG_AX)
+ return 0;
+
+ if (dbg_reg_def[regno].offset != -1)
+ memcpy((void *)regs + dbg_reg_def[regno].offset, mem,
+ dbg_reg_def[regno].size);
+ return 0;
+}
+
+char *dbg_get_reg(int regno, void *mem, struct pt_regs *regs)
+{
+ if (regno == GDB_ORIG_AX) {
+ memcpy(mem, &regs->orig_ax, sizeof(regs->orig_ax));
+ return "orig_ax";
}
-#else
- gdb_regs[GDB_R8] = regs->r8;
- gdb_regs[GDB_R9] = regs->r9;
- gdb_regs[GDB_R10] = regs->r10;
- gdb_regs[GDB_R11] = regs->r11;
- gdb_regs[GDB_R12] = regs->r12;
- gdb_regs[GDB_R13] = regs->r13;
- gdb_regs[GDB_R14] = regs->r14;
- gdb_regs[GDB_R15] = regs->r15;
- gdb_regs32[GDB_PS] = regs->flags;
- gdb_regs32[GDB_CS] = regs->cs;
- gdb_regs32[GDB_SS] = regs->ss;
- gdb_regs[GDB_SP] = kernel_stack_pointer(regs);
+ if (regno >= DBG_MAX_REG_NUM || regno < 0)
+ return NULL;
+
+ if (dbg_reg_def[regno].offset != -1)
+ memcpy(mem, (void *)regs + dbg_reg_def[regno].offset,
+ dbg_reg_def[regno].size);
+
+ switch (regno) {
+#ifdef CONFIG_X86_32
+ case GDB_SS:
+ if (!user_mode_vm(regs))
+ *(unsigned long *)mem = __KERNEL_DS;
+ break;
+ case GDB_SP:
+ if (!user_mode_vm(regs))
+ *(unsigned long *)mem = kernel_stack_pointer(regs);
+ break;
+ case GDB_GS:
+ case GDB_FS:
+ *(unsigned long *)mem = 0xFFFF;
+ break;
#endif
+ }
+ return dbg_reg_def[regno].name;
}
/**
@@ -150,54 +189,13 @@ void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *p)
gdb_regs[GDB_SP] = p->thread.sp;
}
-/**
- * gdb_regs_to_pt_regs - Convert GDB regs to ptrace regs.
- * @gdb_regs: A pointer to hold the registers we've received from GDB.
- * @regs: A pointer to a &struct pt_regs to hold these values in.
- *
- * Convert the GDB regs in @gdb_regs into the pt_regs, and store them
- * in @regs.
- */
-void gdb_regs_to_pt_regs(unsigned long *gdb_regs, struct pt_regs *regs)
-{
-#ifndef CONFIG_X86_32
- u32 *gdb_regs32 = (u32 *)gdb_regs;
-#endif
- regs->ax = gdb_regs[GDB_AX];
- regs->bx = gdb_regs[GDB_BX];
- regs->cx = gdb_regs[GDB_CX];
- regs->dx = gdb_regs[GDB_DX];
- regs->si = gdb_regs[GDB_SI];
- regs->di = gdb_regs[GDB_DI];
- regs->bp = gdb_regs[GDB_BP];
- regs->ip = gdb_regs[GDB_PC];
-#ifdef CONFIG_X86_32
- regs->flags = gdb_regs[GDB_PS];
- regs->ds = gdb_regs[GDB_DS];
- regs->es = gdb_regs[GDB_ES];
- regs->cs = gdb_regs[GDB_CS];
-#else
- regs->r8 = gdb_regs[GDB_R8];
- regs->r9 = gdb_regs[GDB_R9];
- regs->r10 = gdb_regs[GDB_R10];
- regs->r11 = gdb_regs[GDB_R11];
- regs->r12 = gdb_regs[GDB_R12];
- regs->r13 = gdb_regs[GDB_R13];
- regs->r14 = gdb_regs[GDB_R14];
- regs->r15 = gdb_regs[GDB_R15];
- regs->flags = gdb_regs32[GDB_PS];
- regs->cs = gdb_regs32[GDB_CS];
- regs->ss = gdb_regs32[GDB_SS];
-#endif
-}
-
static struct hw_breakpoint {
unsigned enabled;
unsigned long addr;
int len;
int type;
struct perf_event **pev;
-} breakinfo[4];
+} breakinfo[HBP_NUM];
static unsigned long early_dr7;
@@ -205,7 +203,7 @@ static void kgdb_correct_hw_break(void)
{
int breakno;
- for (breakno = 0; breakno < 4; breakno++) {
+ for (breakno = 0; breakno < HBP_NUM; breakno++) {
struct perf_event *bp;
struct arch_hw_breakpoint *info;
int val;
@@ -292,10 +290,10 @@ kgdb_remove_hw_break(unsigned long addr, int len, enum kgdb_bptype bptype)
{
int i;
- for (i = 0; i < 4; i++)
+ for (i = 0; i < HBP_NUM; i++)
if (breakinfo[i].addr == addr && breakinfo[i].enabled)
break;
- if (i == 4)
+ if (i == HBP_NUM)
return -1;
if (hw_break_release_slot(i)) {
@@ -313,7 +311,7 @@ static void kgdb_remove_all_hw_break(void)
int cpu = raw_smp_processor_id();
struct perf_event *bp;
- for (i = 0; i < 4; i++) {
+ for (i = 0; i < HBP_NUM; i++) {
if (!breakinfo[i].enabled)
continue;
bp = *per_cpu_ptr(breakinfo[i].pev, cpu);
@@ -333,10 +331,10 @@ kgdb_set_hw_break(unsigned long addr, int len, enum kgdb_bptype bptype)
{
int i;
- for (i = 0; i < 4; i++)
+ for (i = 0; i < HBP_NUM; i++)
if (!breakinfo[i].enabled)
break;
- if (i == 4)
+ if (i == HBP_NUM)
return -1;
switch (bptype) {
@@ -397,7 +395,7 @@ void kgdb_disable_hw_debug(struct pt_regs *regs)
/* Disable hardware debugging while we are in kgdb: */
set_debugreg(0UL, 7);
- for (i = 0; i < 4; i++) {
+ for (i = 0; i < HBP_NUM; i++) {
if (!breakinfo[i].enabled)
continue;
if (dbg_is_early) {
@@ -458,7 +456,6 @@ int kgdb_arch_handle_exception(int e_vector, int signo, int err_code,
{
unsigned long addr;
char *ptr;
- int newPC;
switch (remcomInBuffer[0]) {
case 'c':
@@ -469,8 +466,6 @@ int kgdb_arch_handle_exception(int e_vector, int signo, int err_code,
linux_regs->ip = addr;
case 'D':
case 'k':
- newPC = linux_regs->ip;
-
/* clear the trace bit */
linux_regs->flags &= ~X86_EFLAGS_TF;
atomic_set(&kgdb_cpu_doing_single_step, -1);
@@ -645,7 +640,7 @@ void kgdb_arch_late(void)
attr.bp_len = HW_BREAKPOINT_LEN_1;
attr.bp_type = HW_BREAKPOINT_W;
attr.disabled = 1;
- for (i = 0; i < 4; i++) {
+ for (i = 0; i < HBP_NUM; i++) {
if (breakinfo[i].pev)
continue;
breakinfo[i].pev = register_wide_hw_breakpoint(&attr, NULL);
diff --git a/arch/x86/kernel/kprobes.c b/arch/x86/kernel/kprobes.c
index 675879b65ce..1bfb6cf4dd5 100644
--- a/arch/x86/kernel/kprobes.c
+++ b/arch/x86/kernel/kprobes.c
@@ -126,16 +126,22 @@ static void __kprobes synthesize_reljump(void *from, void *to)
}
/*
- * Check for the REX prefix which can only exist on X86_64
- * X86_32 always returns 0
+ * Skip the prefixes of the instruction.
*/
-static int __kprobes is_REX_prefix(kprobe_opcode_t *insn)
+static kprobe_opcode_t *__kprobes skip_prefixes(kprobe_opcode_t *insn)
{
+ insn_attr_t attr;
+
+ attr = inat_get_opcode_attribute((insn_byte_t)*insn);
+ while (inat_is_legacy_prefix(attr)) {
+ insn++;
+ attr = inat_get_opcode_attribute((insn_byte_t)*insn);
+ }
#ifdef CONFIG_X86_64
- if ((*insn & 0xf0) == 0x40)
- return 1;
+ if (inat_is_rex_prefix(attr))
+ insn++;
#endif
- return 0;
+ return insn;
}
/*
@@ -272,6 +278,9 @@ static int __kprobes can_probe(unsigned long paddr)
*/
static int __kprobes is_IF_modifier(kprobe_opcode_t *insn)
{
+ /* Skip prefixes */
+ insn = skip_prefixes(insn);
+
switch (*insn) {
case 0xfa: /* cli */
case 0xfb: /* sti */
@@ -280,13 +289,6 @@ static int __kprobes is_IF_modifier(kprobe_opcode_t *insn)
return 1;
}
- /*
- * on X86_64, 0x40-0x4f are REX prefixes so we need to look
- * at the next byte instead.. but of course not recurse infinitely
- */
- if (is_REX_prefix(insn))
- return is_IF_modifier(++insn);
-
return 0;
}
@@ -803,9 +805,8 @@ static void __kprobes resume_execution(struct kprobe *p,
unsigned long orig_ip = (unsigned long)p->addr;
kprobe_opcode_t *insn = p->ainsn.insn;
- /*skip the REX prefix*/
- if (is_REX_prefix(insn))
- insn++;
+ /* Skip prefixes */
+ insn = skip_prefixes(insn);
regs->flags &= ~X86_EFLAGS_TF;
switch (*insn) {
diff --git a/arch/x86/kernel/mrst.c b/arch/x86/kernel/mrst.c
index 5915e0b3330..79ae68154e8 100644
--- a/arch/x86/kernel/mrst.c
+++ b/arch/x86/kernel/mrst.c
@@ -25,8 +25,34 @@
#include <asm/i8259.h>
#include <asm/apb_timer.h>
+/*
+ * the clockevent devices on Moorestown/Medfield can be APBT or LAPIC clock,
+ * cmdline option x86_mrst_timer can be used to override the configuration
+ * to prefer one or the other.
+ * at runtime, there are basically three timer configurations:
+ * 1. per cpu apbt clock only
+ * 2. per cpu always-on lapic clocks only, this is Penwell/Medfield only
+ * 3. per cpu lapic clock (C3STOP) and one apbt clock, with broadcast.
+ *
+ * by default (without cmdline option), platform code first detects cpu type
+ * to see if we are on lincroft or penwell, then set up both lapic or apbt
+ * clocks accordingly.
+ * i.e. by default, medfield uses configuration #2, moorestown uses #1.
+ * config #3 is supported but not recommended on medfield.
+ *
+ * rating and feature summary:
+ * lapic (with C3STOP) --------- 100
+ * apbt (always-on) ------------ 110
+ * lapic (always-on,ARAT) ------ 150
+ */
+
+__cpuinitdata enum mrst_timer_options mrst_timer_options;
+
static u32 sfi_mtimer_usage[SFI_MTMR_MAX_NUM];
static struct sfi_timer_table_entry sfi_mtimer_array[SFI_MTMR_MAX_NUM];
+enum mrst_cpu_type __mrst_cpu_chip;
+EXPORT_SYMBOL_GPL(__mrst_cpu_chip);
+
int sfi_mtimer_num;
struct sfi_rtc_table_entry sfi_mrtc_array[SFI_MRTC_MAX];
@@ -167,18 +193,6 @@ int __init sfi_parse_mrtc(struct sfi_table_header *table)
return 0;
}
-/*
- * the secondary clock in Moorestown can be APBT or LAPIC clock, default to
- * APBT but cmdline option can also override it.
- */
-static void __cpuinit mrst_setup_secondary_clock(void)
-{
- /* restore default lapic clock if disabled by cmdline */
- if (disable_apbt_percpu)
- return setup_secondary_APIC_clock();
- apbt_setup_secondary_clock();
-}
-
static unsigned long __init mrst_calibrate_tsc(void)
{
unsigned long flags, fast_calibrate;
@@ -195,6 +209,21 @@ static unsigned long __init mrst_calibrate_tsc(void)
void __init mrst_time_init(void)
{
+ switch (mrst_timer_options) {
+ case MRST_TIMER_APBT_ONLY:
+ break;
+ case MRST_TIMER_LAPIC_APBT:
+ x86_init.timers.setup_percpu_clockev = setup_boot_APIC_clock;
+ x86_cpuinit.setup_percpu_clockev = setup_secondary_APIC_clock;
+ break;
+ default:
+ if (!boot_cpu_has(X86_FEATURE_ARAT))
+ break;
+ x86_init.timers.setup_percpu_clockev = setup_boot_APIC_clock;
+ x86_cpuinit.setup_percpu_clockev = setup_secondary_APIC_clock;
+ return;
+ }
+ /* we need at least one APB timer */
sfi_table_parse(SFI_SIG_MTMR, NULL, NULL, sfi_parse_mtmr);
pre_init_apic_IRQ0();
apbt_time_init();
@@ -205,16 +234,21 @@ void __init mrst_rtc_init(void)
sfi_table_parse(SFI_SIG_MRTC, NULL, NULL, sfi_parse_mrtc);
}
-/*
- * if we use per cpu apb timer, the bootclock already setup. if we use lapic
- * timer and one apbt timer for broadcast, we need to set up lapic boot clock.
- */
-static void __init mrst_setup_boot_clock(void)
+void __cpuinit mrst_arch_setup(void)
{
- pr_info("%s: per cpu apbt flag %d \n", __func__, disable_apbt_percpu);
- if (disable_apbt_percpu)
- setup_boot_APIC_clock();
-};
+ if (boot_cpu_data.x86 == 6 && boot_cpu_data.x86_model == 0x27)
+ __mrst_cpu_chip = MRST_CPU_CHIP_PENWELL;
+ else if (boot_cpu_data.x86 == 6 && boot_cpu_data.x86_model == 0x26)
+ __mrst_cpu_chip = MRST_CPU_CHIP_LINCROFT;
+ else {
+ pr_err("Unknown Moorestown CPU (%d:%d), default to Lincroft\n",
+ boot_cpu_data.x86, boot_cpu_data.x86_model);
+ __mrst_cpu_chip = MRST_CPU_CHIP_LINCROFT;
+ }
+ pr_debug("Moorestown CPU %s identified\n",
+ (__mrst_cpu_chip == MRST_CPU_CHIP_LINCROFT) ?
+ "Lincroft" : "Penwell");
+}
/* MID systems don't have i8042 controller */
static int mrst_i8042_detect(void)
@@ -232,11 +266,13 @@ void __init x86_mrst_early_setup(void)
x86_init.resources.reserve_resources = x86_init_noop;
x86_init.timers.timer_init = mrst_time_init;
- x86_init.timers.setup_percpu_clockev = mrst_setup_boot_clock;
+ x86_init.timers.setup_percpu_clockev = x86_init_noop;
x86_init.irqs.pre_vector_init = x86_init_noop;
- x86_cpuinit.setup_percpu_clockev = mrst_setup_secondary_clock;
+ x86_init.oem.arch_setup = mrst_arch_setup;
+
+ x86_cpuinit.setup_percpu_clockev = apbt_setup_secondary_clock;
x86_platform.calibrate_tsc = mrst_calibrate_tsc;
x86_platform.i8042_detect = mrst_i8042_detect;
@@ -250,3 +286,26 @@ void __init x86_mrst_early_setup(void)
x86_init.mpparse.get_smp_config = x86_init_uint_noop;
}
+
+/*
+ * if user does not want to use per CPU apb timer, just give it a lower rating
+ * than local apic timer and skip the late per cpu timer init.
+ */
+static inline int __init setup_x86_mrst_timer(char *arg)
+{
+ if (!arg)
+ return -EINVAL;
+
+ if (strcmp("apbt_only", arg) == 0)
+ mrst_timer_options = MRST_TIMER_APBT_ONLY;
+ else if (strcmp("lapic_and_apbt", arg) == 0)
+ mrst_timer_options = MRST_TIMER_LAPIC_APBT;
+ else {
+ pr_warning("X86 MRST timer option %s not recognised"
+ " use x86_mrst_timer=apbt_only or lapic_and_apbt\n",
+ arg);
+ return -EINVAL;
+ }
+ return 0;
+}
+__setup("x86_mrst_timer=", setup_x86_mrst_timer);
diff --git a/arch/x86/kernel/olpc.c b/arch/x86/kernel/olpc.c
index 8297160c41b..0e0cdde519b 100644
--- a/arch/x86/kernel/olpc.c
+++ b/arch/x86/kernel/olpc.c
@@ -21,10 +21,7 @@
#include <asm/geode.h>
#include <asm/setup.h>
#include <asm/olpc.h>
-
-#ifdef CONFIG_OPEN_FIRMWARE
-#include <asm/ofw.h>
-#endif
+#include <asm/olpc_ofw.h>
struct olpc_platform_t olpc_platform_info;
EXPORT_SYMBOL_GPL(olpc_platform_info);
@@ -145,7 +142,7 @@ restart:
* The OBF flag will sometimes misbehave due to what we believe
* is a hardware quirk..
*/
- printk(KERN_DEBUG "olpc-ec: running cmd 0x%x\n", cmd);
+ pr_devel("olpc-ec: running cmd 0x%x\n", cmd);
outb(cmd, 0x6c);
if (wait_on_ibf(0x6c, 0)) {
@@ -162,8 +159,7 @@ restart:
" EC accept data!\n");
goto err;
}
- printk(KERN_DEBUG "olpc-ec: sending cmd arg 0x%x\n",
- inbuf[i]);
+ pr_devel("olpc-ec: sending cmd arg 0x%x\n", inbuf[i]);
outb(inbuf[i], 0x68);
}
}
@@ -176,8 +172,7 @@ restart:
goto restart;
}
outbuf[i] = inb(0x68);
- printk(KERN_DEBUG "olpc-ec: received 0x%x\n",
- outbuf[i]);
+ pr_devel("olpc-ec: received 0x%x\n", outbuf[i]);
}
}
@@ -188,14 +183,15 @@ err:
}
EXPORT_SYMBOL_GPL(olpc_ec_cmd);
-#ifdef CONFIG_OPEN_FIRMWARE
+#ifdef CONFIG_OLPC_OPENFIRMWARE
static void __init platform_detect(void)
{
size_t propsize;
__be32 rev;
+ const void *args[] = { NULL, "board-revision-int", &rev, (void *)4 };
+ void *res[] = { &propsize };
- if (ofw("getprop", 4, 1, NULL, "board-revision-int", &rev, 4,
- &propsize) || propsize != 4) {
+ if (olpc_ofw("getprop", args, res) || propsize != 4) {
printk(KERN_ERR "ofw: getprop call failed!\n");
rev = cpu_to_be32(0);
}
diff --git a/arch/x86/kernel/olpc_ofw.c b/arch/x86/kernel/olpc_ofw.c
new file mode 100644
index 00000000000..3218aa71ab5
--- /dev/null
+++ b/arch/x86/kernel/olpc_ofw.c
@@ -0,0 +1,106 @@
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <asm/page.h>
+#include <asm/setup.h>
+#include <asm/io.h>
+#include <asm/pgtable.h>
+#include <asm/olpc_ofw.h>
+
+/* address of OFW callback interface; will be NULL if OFW isn't found */
+static int (*olpc_ofw_cif)(int *);
+
+/* page dir entry containing OFW's pgdir table; filled in by head_32.S */
+u32 olpc_ofw_pgd __initdata;
+
+static DEFINE_SPINLOCK(ofw_lock);
+
+#define MAXARGS 10
+
+void __init setup_olpc_ofw_pgd(void)
+{
+ pgd_t *base, *ofw_pde;
+
+ if (!olpc_ofw_cif)
+ return;
+
+ /* fetch OFW's PDE */
+ base = early_ioremap(olpc_ofw_pgd, sizeof(olpc_ofw_pgd) * PTRS_PER_PGD);
+ if (!base) {
+ printk(KERN_ERR "failed to remap OFW's pgd - disabling OFW!\n");
+ olpc_ofw_cif = NULL;
+ return;
+ }
+ ofw_pde = &base[OLPC_OFW_PDE_NR];
+
+ /* install OFW's PDE permanently into the kernel's pgtable */
+ set_pgd(&swapper_pg_dir[OLPC_OFW_PDE_NR], *ofw_pde);
+ /* implicit optimization barrier here due to uninline function return */
+
+ early_iounmap(base, sizeof(olpc_ofw_pgd) * PTRS_PER_PGD);
+}
+
+int __olpc_ofw(const char *name, int nr_args, const void **args, int nr_res,
+ void **res)
+{
+ int ofw_args[MAXARGS + 3];
+ unsigned long flags;
+ int ret, i, *p;
+
+ BUG_ON(nr_args + nr_res > MAXARGS);
+
+ if (!olpc_ofw_cif)
+ return -EIO;
+
+ ofw_args[0] = (int)name;
+ ofw_args[1] = nr_args;
+ ofw_args[2] = nr_res;
+
+ p = &ofw_args[3];
+ for (i = 0; i < nr_args; i++, p++)
+ *p = (int)args[i];
+
+ /* call into ofw */
+ spin_lock_irqsave(&ofw_lock, flags);
+ ret = olpc_ofw_cif(ofw_args);
+ spin_unlock_irqrestore(&ofw_lock, flags);
+
+ if (!ret) {
+ for (i = 0; i < nr_res; i++, p++)
+ *((int *)res[i]) = *p;
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(__olpc_ofw);
+
+/* OFW cif _should_ be above this address */
+#define OFW_MIN 0xff000000
+
+/* OFW starts on a 1MB boundary */
+#define OFW_BOUND (1<<20)
+
+void __init olpc_ofw_detect(void)
+{
+ struct olpc_ofw_header *hdr = &boot_params.olpc_ofw_header;
+ unsigned long start;
+
+ /* ensure OFW booted us by checking for "OFW " string */
+ if (hdr->ofw_magic != OLPC_OFW_SIG)
+ return;
+
+ olpc_ofw_cif = (int (*)(int *))hdr->cif_handler;
+
+ if ((unsigned long)olpc_ofw_cif < OFW_MIN) {
+ printk(KERN_ERR "OFW detected, but cif has invalid address 0x%lx - disabling.\n",
+ (unsigned long)olpc_ofw_cif);
+ olpc_ofw_cif = NULL;
+ return;
+ }
+
+ /* determine where OFW starts in memory */
+ start = round_down((unsigned long)olpc_ofw_cif, OFW_BOUND);
+ printk(KERN_INFO "OFW detected in memory, cif @ 0x%lx (reserving top %ldMB)\n",
+ (unsigned long)olpc_ofw_cif, (-start) >> 20);
+ reserve_top_address(-start);
+}
diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c
index e7e35219b32..d401f1d2d06 100644
--- a/arch/x86/kernel/process.c
+++ b/arch/x86/kernel/process.c
@@ -28,6 +28,7 @@ unsigned long idle_nomwait;
EXPORT_SYMBOL(idle_nomwait);
struct kmem_cache *task_xstate_cachep;
+EXPORT_SYMBOL_GPL(task_xstate_cachep);
int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src)
{
@@ -371,7 +372,7 @@ static inline int hlt_use_halt(void)
void default_idle(void)
{
if (hlt_use_halt()) {
- trace_power_start(POWER_CSTATE, 1);
+ trace_power_start(POWER_CSTATE, 1, smp_processor_id());
current_thread_info()->status &= ~TS_POLLING;
/*
* TS_POLLING-cleared state must be visible before we
@@ -441,7 +442,7 @@ EXPORT_SYMBOL_GPL(cpu_idle_wait);
*/
void mwait_idle_with_hints(unsigned long ax, unsigned long cx)
{
- trace_power_start(POWER_CSTATE, (ax>>4)+1);
+ trace_power_start(POWER_CSTATE, (ax>>4)+1, smp_processor_id());
if (!need_resched()) {
if (cpu_has(&current_cpu_data, X86_FEATURE_CLFLUSH_MONITOR))
clflush((void *)&current_thread_info()->flags);
@@ -457,7 +458,7 @@ void mwait_idle_with_hints(unsigned long ax, unsigned long cx)
static void mwait_idle(void)
{
if (!need_resched()) {
- trace_power_start(POWER_CSTATE, 1);
+ trace_power_start(POWER_CSTATE, 1, smp_processor_id());
if (cpu_has(&current_cpu_data, X86_FEATURE_CLFLUSH_MONITOR))
clflush((void *)&current_thread_info()->flags);
@@ -478,7 +479,7 @@ static void mwait_idle(void)
*/
static void poll_idle(void)
{
- trace_power_start(POWER_CSTATE, 0);
+ trace_power_start(POWER_CSTATE, 0, smp_processor_id());
local_irq_enable();
while (!need_resched())
cpu_relax();
@@ -525,44 +526,10 @@ static int __cpuinit mwait_usable(const struct cpuinfo_x86 *c)
return (edx & MWAIT_EDX_C1);
}
-/*
- * Check for AMD CPUs, where APIC timer interrupt does not wake up CPU from C1e.
- * For more information see
- * - Erratum #400 for NPT family 0xf and family 0x10 CPUs
- * - Erratum #365 for family 0x11 (not affected because C1e not in use)
- */
-static int __cpuinit check_c1e_idle(const struct cpuinfo_x86 *c)
-{
- u64 val;
- if (c->x86_vendor != X86_VENDOR_AMD)
- goto no_c1e_idle;
-
- /* Family 0x0f models < rev F do not have C1E */
- if (c->x86 == 0x0F && c->x86_model >= 0x40)
- return 1;
-
- if (c->x86 == 0x10) {
- /*
- * check OSVW bit for CPUs that are not affected
- * by erratum #400
- */
- if (cpu_has(c, X86_FEATURE_OSVW)) {
- rdmsrl(MSR_AMD64_OSVW_ID_LENGTH, val);
- if (val >= 2) {
- rdmsrl(MSR_AMD64_OSVW_STATUS, val);
- if (!(val & BIT(1)))
- goto no_c1e_idle;
- }
- }
- return 1;
- }
-
-no_c1e_idle:
- return 0;
-}
+bool c1e_detected;
+EXPORT_SYMBOL(c1e_detected);
static cpumask_var_t c1e_mask;
-static int c1e_detected;
void c1e_remove_cpu(int cpu)
{
@@ -584,12 +551,12 @@ static void c1e_idle(void)
u32 lo, hi;
rdmsr(MSR_K8_INT_PENDING_MSG, lo, hi);
+
if (lo & K8_INTP_C1E_ACTIVE_MASK) {
- c1e_detected = 1;
+ c1e_detected = true;
if (!boot_cpu_has(X86_FEATURE_NONSTOP_TSC))
mark_tsc_unstable("TSC halt in AMD C1E");
printk(KERN_INFO "System has AMD C1E enabled\n");
- set_cpu_cap(&boot_cpu_data, X86_FEATURE_AMDC1E);
}
}
@@ -638,7 +605,8 @@ void __cpuinit select_idle_routine(const struct cpuinfo_x86 *c)
*/
printk(KERN_INFO "using mwait in idle threads.\n");
pm_idle = mwait_idle;
- } else if (check_c1e_idle(c)) {
+ } else if (cpu_has_amd_erratum(amd_erratum_400)) {
+ /* E400: APIC timer interrupt does not wake up CPU from C1e */
printk(KERN_INFO "using C1E aware idle routine\n");
pm_idle = c1e_idle;
} else
diff --git a/arch/x86/kernel/process_32.c b/arch/x86/kernel/process_32.c
index 8d128783af4..96586c3cbbb 100644
--- a/arch/x86/kernel/process_32.c
+++ b/arch/x86/kernel/process_32.c
@@ -57,6 +57,8 @@
#include <asm/syscalls.h>
#include <asm/debugreg.h>
+#include <trace/events/power.h>
+
asmlinkage void ret_from_fork(void) __asm__("ret_from_fork");
/*
@@ -111,6 +113,8 @@ void cpu_idle(void)
stop_critical_timings();
pm_idle();
start_critical_timings();
+
+ trace_power_end(smp_processor_id());
}
tick_nohz_restart_sched_tick();
preempt_enable_no_resched();
diff --git a/arch/x86/kernel/process_64.c b/arch/x86/kernel/process_64.c
index 3c2422a99f1..3d9ea531ddd 100644
--- a/arch/x86/kernel/process_64.c
+++ b/arch/x86/kernel/process_64.c
@@ -51,6 +51,8 @@
#include <asm/syscalls.h>
#include <asm/debugreg.h>
+#include <trace/events/power.h>
+
asmlinkage extern void ret_from_fork(void);
DEFINE_PER_CPU(unsigned long, old_rsp);
@@ -138,6 +140,9 @@ void cpu_idle(void)
stop_critical_timings();
pm_idle();
start_critical_timings();
+
+ trace_power_end(smp_processor_id());
+
/* In many cases the interrupt that ended idle
has already called exit_idle. But some idle
loops can be woken up without interrupt. */
diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c
index b4ae4acbd03..b008e788320 100644
--- a/arch/x86/kernel/setup.c
+++ b/arch/x86/kernel/setup.c
@@ -102,6 +102,7 @@
#include <asm/paravirt.h>
#include <asm/hypervisor.h>
+#include <asm/olpc_ofw.h>
#include <asm/percpu.h>
#include <asm/topology.h>
@@ -736,10 +737,15 @@ void __init setup_arch(char **cmdline_p)
/* VMI may relocate the fixmap; do this before touching ioremap area */
vmi_init();
+ /* OFW also may relocate the fixmap */
+ olpc_ofw_detect();
+
early_trap_init();
early_cpu_init();
early_ioremap_init();
+ setup_olpc_ofw_pgd();
+
ROOT_DEV = old_decode_dev(boot_params.hdr.root_dev);
screen_info = boot_params.screen_info;
edid_info = boot_params.edid_info;
diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c
index c4f33b2e77d..51620953b18 100644
--- a/arch/x86/kernel/smpboot.c
+++ b/arch/x86/kernel/smpboot.c
@@ -735,7 +735,7 @@ static int __cpuinit do_boot_cpu(int apicid, int cpu)
goto do_rest;
}
- if (!keventd_up() || current_is_keventd())
+ if (!keventd_up())
c_idle.work.func(&c_idle.work);
else {
schedule_work(&c_idle.work);
@@ -816,6 +816,13 @@ do_rest:
if (cpumask_test_cpu(cpu, cpu_callin_mask))
break; /* It has booted */
udelay(100);
+ /*
+ * Allow other tasks to run while we wait for the
+ * AP to come online. This also gives a chance
+ * for the MTRR work(triggered by the AP coming online)
+ * to be completed in the stop machine context.
+ */
+ schedule();
}
if (cpumask_test_cpu(cpu, cpu_callin_mask))
diff --git a/arch/x86/kernel/stacktrace.c b/arch/x86/kernel/stacktrace.c
index 922eefbb3f6..b53c525368a 100644
--- a/arch/x86/kernel/stacktrace.c
+++ b/arch/x86/kernel/stacktrace.c
@@ -23,11 +23,16 @@ static int save_stack_stack(void *data, char *name)
return 0;
}
-static void save_stack_address(void *data, unsigned long addr, int reliable)
+static void
+__save_stack_address(void *data, unsigned long addr, bool reliable, bool nosched)
{
struct stack_trace *trace = data;
+#ifdef CONFIG_FRAME_POINTER
if (!reliable)
return;
+#endif
+ if (nosched && in_sched_functions(addr))
+ return;
if (trace->skip > 0) {
trace->skip--;
return;
@@ -36,20 +41,15 @@ static void save_stack_address(void *data, unsigned long addr, int reliable)
trace->entries[trace->nr_entries++] = addr;
}
+static void save_stack_address(void *data, unsigned long addr, int reliable)
+{
+ return __save_stack_address(data, addr, reliable, false);
+}
+
static void
save_stack_address_nosched(void *data, unsigned long addr, int reliable)
{
- struct stack_trace *trace = (struct stack_trace *)data;
- if (!reliable)
- return;
- if (in_sched_functions(addr))
- return;
- if (trace->skip > 0) {
- trace->skip--;
- return;
- }
- if (trace->nr_entries < trace->max_entries)
- trace->entries[trace->nr_entries++] = addr;
+ return __save_stack_address(data, addr, reliable, true);
}
static const struct stacktrace_ops save_stack_ops = {
@@ -96,12 +96,13 @@ EXPORT_SYMBOL_GPL(save_stack_trace_tsk);
/* Userspace stacktrace - based on kernel/trace/trace_sysprof.c */
-struct stack_frame {
+struct stack_frame_user {
const void __user *next_fp;
unsigned long ret_addr;
};
-static int copy_stack_frame(const void __user *fp, struct stack_frame *frame)
+static int
+copy_stack_frame(const void __user *fp, struct stack_frame_user *frame)
{
int ret;
@@ -126,7 +127,7 @@ static inline void __save_stack_trace_user(struct stack_trace *trace)
trace->entries[trace->nr_entries++] = regs->ip;
while (trace->nr_entries < trace->max_entries) {
- struct stack_frame frame;
+ struct stack_frame_user frame;
frame.next_fp = NULL;
frame.ret_addr = 0;
diff --git a/arch/x86/kernel/traps.c b/arch/x86/kernel/traps.c
index 725ef4d17cd..60788dee0f8 100644
--- a/arch/x86/kernel/traps.c
+++ b/arch/x86/kernel/traps.c
@@ -392,7 +392,13 @@ static notrace __kprobes void default_do_nmi(struct pt_regs *regs)
if (notify_die(DIE_NMI_IPI, "nmi_ipi", regs, reason, 2, SIGINT)
== NOTIFY_STOP)
return;
+
#ifdef CONFIG_X86_LOCAL_APIC
+ if (notify_die(DIE_NMI, "nmi", regs, reason, 2, SIGINT)
+ == NOTIFY_STOP)
+ return;
+
+#ifndef CONFIG_LOCKUP_DETECTOR
/*
* Ok, so this is none of the documented NMI sources,
* so it must be the NMI watchdog.
@@ -400,6 +406,7 @@ static notrace __kprobes void default_do_nmi(struct pt_regs *regs)
if (nmi_watchdog_tick(regs, reason))
return;
if (!do_nmi_callback(regs, cpu))
+#endif /* !CONFIG_LOCKUP_DETECTOR */
unknown_nmi_error(reason, regs);
#else
unknown_nmi_error(reason, regs);
diff --git a/arch/x86/kernel/tsc.c b/arch/x86/kernel/tsc.c
index 9faf91ae184..ce8e5023933 100644
--- a/arch/x86/kernel/tsc.c
+++ b/arch/x86/kernel/tsc.c
@@ -751,7 +751,6 @@ static struct clocksource clocksource_tsc = {
.read = read_tsc,
.resume = resume_tsc,
.mask = CLOCKSOURCE_MASK(64),
- .shift = 22,
.flags = CLOCK_SOURCE_IS_CONTINUOUS |
CLOCK_SOURCE_MUST_VERIFY,
#ifdef CONFIG_X86_64
@@ -845,8 +844,6 @@ __cpuinit int unsynchronized_tsc(void)
static void __init init_tsc_clocksource(void)
{
- clocksource_tsc.mult = clocksource_khz2mult(tsc_khz,
- clocksource_tsc.shift);
if (tsc_clocksource_reliable)
clocksource_tsc.flags &= ~CLOCK_SOURCE_MUST_VERIFY;
/* lower the rating if we already know its unstable: */
@@ -854,7 +851,7 @@ static void __init init_tsc_clocksource(void)
clocksource_tsc.rating = 0;
clocksource_tsc.flags &= ~CLOCK_SOURCE_IS_CONTINUOUS;
}
- clocksource_register(&clocksource_tsc);
+ clocksource_register_khz(&clocksource_tsc, tsc_khz);
}
#ifdef CONFIG_X86_64
diff --git a/arch/x86/kernel/verify_cpu_64.S b/arch/x86/kernel/verify_cpu_64.S
index 45b6f8a975a..56a8c2a867d 100644
--- a/arch/x86/kernel/verify_cpu_64.S
+++ b/arch/x86/kernel/verify_cpu_64.S
@@ -31,6 +31,7 @@
*/
#include <asm/cpufeature.h>
+#include <asm/msr-index.h>
verify_cpu:
pushfl # Save caller passed flags
@@ -88,7 +89,7 @@ verify_cpu_sse_test:
je verify_cpu_sse_ok
test %di,%di
jz verify_cpu_no_longmode # only try to force SSE on AMD
- movl $0xc0010015,%ecx # HWCR
+ movl $MSR_K7_HWCR,%ecx
rdmsr
btr $15,%eax # enable SSE
wrmsr
diff --git a/arch/x86/kernel/vsyscall_64.c b/arch/x86/kernel/vsyscall_64.c
index 1c0c6ab9c60..dcbb28c4b69 100644
--- a/arch/x86/kernel/vsyscall_64.c
+++ b/arch/x86/kernel/vsyscall_64.c
@@ -73,8 +73,8 @@ void update_vsyscall_tz(void)
write_sequnlock_irqrestore(&vsyscall_gtod_data.lock, flags);
}
-void update_vsyscall(struct timespec *wall_time, struct clocksource *clock,
- u32 mult)
+void update_vsyscall(struct timespec *wall_time, struct timespec *wtm,
+ struct clocksource *clock, u32 mult)
{
unsigned long flags;
@@ -87,7 +87,7 @@ void update_vsyscall(struct timespec *wall_time, struct clocksource *clock,
vsyscall_gtod_data.clock.shift = clock->shift;
vsyscall_gtod_data.wall_time_sec = wall_time->tv_sec;
vsyscall_gtod_data.wall_time_nsec = wall_time->tv_nsec;
- vsyscall_gtod_data.wall_to_monotonic = wall_to_monotonic;
+ vsyscall_gtod_data.wall_to_monotonic = *wtm;
vsyscall_gtod_data.wall_time_coarse = __current_kernel_time();
write_sequnlock_irqrestore(&vsyscall_gtod_data.lock, flags);
}
@@ -169,13 +169,18 @@ int __vsyscall(0) vgettimeofday(struct timeval * tv, struct timezone * tz)
* unlikely */
time_t __vsyscall(1) vtime(time_t *t)
{
- struct timeval tv;
+ unsigned seq;
time_t result;
if (unlikely(!__vsyscall_gtod_data.sysctl_enabled))
return time_syscall(t);
- vgettimeofday(&tv, NULL);
- result = tv.tv_sec;
+ do {
+ seq = read_seqbegin(&__vsyscall_gtod_data.lock);
+
+ result = __vsyscall_gtod_data.wall_time_sec;
+
+ } while (read_seqretry(&__vsyscall_gtod_data.lock, seq));
+
if (t)
*t = result;
return result;
diff --git a/arch/x86/kernel/xsave.c b/arch/x86/kernel/xsave.c
index 37e68fc5e24..9c253bd65e2 100644
--- a/arch/x86/kernel/xsave.c
+++ b/arch/x86/kernel/xsave.c
@@ -16,11 +16,88 @@
*/
u64 pcntxt_mask;
+/*
+ * Represents init state for the supported extended state.
+ */
+static struct xsave_struct *init_xstate_buf;
+
struct _fpx_sw_bytes fx_sw_reserved;
#ifdef CONFIG_IA32_EMULATION
struct _fpx_sw_bytes fx_sw_reserved_ia32;
#endif
+static unsigned int *xstate_offsets, *xstate_sizes, xstate_features;
+
+/*
+ * If a processor implementation discern that a processor state component is
+ * in its initialized state it may modify the corresponding bit in the
+ * xsave_hdr.xstate_bv as '0', with out modifying the corresponding memory
+ * layout in the case of xsaveopt. While presenting the xstate information to
+ * the user, we always ensure that the memory layout of a feature will be in
+ * the init state if the corresponding header bit is zero. This is to ensure
+ * that the user doesn't see some stale state in the memory layout during
+ * signal handling, debugging etc.
+ */
+void __sanitize_i387_state(struct task_struct *tsk)
+{
+ u64 xstate_bv;
+ int feature_bit = 0x2;
+ struct i387_fxsave_struct *fx = &tsk->thread.fpu.state->fxsave;
+
+ if (!fx)
+ return;
+
+ BUG_ON(task_thread_info(tsk)->status & TS_USEDFPU);
+
+ xstate_bv = tsk->thread.fpu.state->xsave.xsave_hdr.xstate_bv;
+
+ /*
+ * None of the feature bits are in init state. So nothing else
+ * to do for us, as the memory layout is upto date.
+ */
+ if ((xstate_bv & pcntxt_mask) == pcntxt_mask)
+ return;
+
+ /*
+ * FP is in init state
+ */
+ if (!(xstate_bv & XSTATE_FP)) {
+ fx->cwd = 0x37f;
+ fx->swd = 0;
+ fx->twd = 0;
+ fx->fop = 0;
+ fx->rip = 0;
+ fx->rdp = 0;
+ memset(&fx->st_space[0], 0, 128);
+ }
+
+ /*
+ * SSE is in init state
+ */
+ if (!(xstate_bv & XSTATE_SSE))
+ memset(&fx->xmm_space[0], 0, 256);
+
+ xstate_bv = (pcntxt_mask & ~xstate_bv) >> 2;
+
+ /*
+ * Update all the other memory layouts for which the corresponding
+ * header bit is in the init state.
+ */
+ while (xstate_bv) {
+ if (xstate_bv & 0x1) {
+ int offset = xstate_offsets[feature_bit];
+ int size = xstate_sizes[feature_bit];
+
+ memcpy(((void *) fx) + offset,
+ ((void *) init_xstate_buf) + offset,
+ size);
+ }
+
+ xstate_bv >>= 1;
+ feature_bit++;
+ }
+}
+
/*
* Check for the presence of extended state information in the
* user fpstate pointer in the sigcontext.
@@ -36,15 +113,14 @@ int check_for_xstate(struct i387_fxsave_struct __user *buf,
err = __copy_from_user(fx_sw_user, &buf->sw_reserved[0],
sizeof(struct _fpx_sw_bytes));
-
if (err)
- return err;
+ return -EFAULT;
/*
* First Magic check failed.
*/
if (fx_sw_user->magic1 != FP_XSTATE_MAGIC1)
- return -1;
+ return -EINVAL;
/*
* Check for error scenarios.
@@ -52,19 +128,21 @@ int check_for_xstate(struct i387_fxsave_struct __user *buf,
if (fx_sw_user->xstate_size < min_xstate_size ||
fx_sw_user->xstate_size > xstate_size ||
fx_sw_user->xstate_size > fx_sw_user->extended_size)
- return -1;
+ return -EINVAL;
err = __get_user(magic2, (__u32 *) (((void *)fpstate) +
fx_sw_user->extended_size -
FP_XSTATE_MAGIC2_SIZE));
+ if (err)
+ return err;
/*
* Check for the presence of second magic word at the end of memory
* layout. This detects the case where the user just copied the legacy
* fpstate layout with out copying the extended state information
* in the memory layout.
*/
- if (err || magic2 != FP_XSTATE_MAGIC2)
- return -1;
+ if (magic2 != FP_XSTATE_MAGIC2)
+ return -EFAULT;
return 0;
}
@@ -91,14 +169,6 @@ int save_i387_xstate(void __user *buf)
return 0;
if (task_thread_info(tsk)->status & TS_USEDFPU) {
- /*
- * Start with clearing the user buffer. This will present a
- * clean context for the bytes not touched by the fxsave/xsave.
- */
- err = __clear_user(buf, sig_xstate_size);
- if (err)
- return err;
-
if (use_xsave())
err = xsave_user(buf);
else
@@ -109,6 +179,7 @@ int save_i387_xstate(void __user *buf)
task_thread_info(tsk)->status &= ~TS_USEDFPU;
stts();
} else {
+ sanitize_i387_state(tsk);
if (__copy_to_user(buf, &tsk->thread.fpu.state->fxsave,
xstate_size))
return -1;
@@ -184,8 +255,8 @@ static int restore_user_xstate(void __user *buf)
* init the state skipped by the user.
*/
mask = pcntxt_mask & ~mask;
-
- xrstor_state(init_xstate_buf, mask);
+ if (unlikely(mask))
+ xrstor_state(init_xstate_buf, mask);
return 0;
@@ -274,11 +345,6 @@ static void prepare_fx_sw_frame(void)
#endif
}
-/*
- * Represents init state for the supported extended state.
- */
-struct xsave_struct *init_xstate_buf;
-
#ifdef CONFIG_X86_64
unsigned int sig_xstate_size = sizeof(struct _fpstate);
#endif
@@ -286,37 +352,77 @@ unsigned int sig_xstate_size = sizeof(struct _fpstate);
/*
* Enable the extended processor state save/restore feature
*/
-void __cpuinit xsave_init(void)
+static inline void xstate_enable(void)
{
- if (!cpu_has_xsave)
- return;
-
set_in_cr4(X86_CR4_OSXSAVE);
-
- /*
- * Enable all the features that the HW is capable of
- * and the Linux kernel is aware of.
- */
xsetbv(XCR_XFEATURE_ENABLED_MASK, pcntxt_mask);
}
/*
+ * Record the offsets and sizes of different state managed by the xsave
+ * memory layout.
+ */
+static void __init setup_xstate_features(void)
+{
+ int eax, ebx, ecx, edx, leaf = 0x2;
+
+ xstate_features = fls64(pcntxt_mask);
+ xstate_offsets = alloc_bootmem(xstate_features * sizeof(int));
+ xstate_sizes = alloc_bootmem(xstate_features * sizeof(int));
+
+ do {
+ cpuid_count(XSTATE_CPUID, leaf, &eax, &ebx, &ecx, &edx);
+
+ if (eax == 0)
+ break;
+
+ xstate_offsets[leaf] = ebx;
+ xstate_sizes[leaf] = eax;
+
+ leaf++;
+ } while (1);
+}
+
+/*
* setup the xstate image representing the init state
*/
static void __init setup_xstate_init(void)
{
+ setup_xstate_features();
+
+ /*
+ * Setup init_xstate_buf to represent the init state of
+ * all the features managed by the xsave
+ */
init_xstate_buf = alloc_bootmem(xstate_size);
init_xstate_buf->i387.mxcsr = MXCSR_DEFAULT;
+
+ clts();
+ /*
+ * Init all the features state with header_bv being 0x0
+ */
+ xrstor_state(init_xstate_buf, -1);
+ /*
+ * Dump the init state again. This is to identify the init state
+ * of any feature which is not represented by all zero's.
+ */
+ xsave_state(init_xstate_buf, -1);
+ stts();
}
/*
* Enable and initialize the xsave feature.
*/
-void __ref xsave_cntxt_init(void)
+static void __init xstate_enable_boot_cpu(void)
{
unsigned int eax, ebx, ecx, edx;
- cpuid_count(0xd, 0, &eax, &ebx, &ecx, &edx);
+ if (boot_cpu_data.cpuid_level < XSTATE_CPUID) {
+ WARN(1, KERN_ERR "XSTATE_CPUID missing\n");
+ return;
+ }
+
+ cpuid_count(XSTATE_CPUID, 0, &eax, &ebx, &ecx, &edx);
pcntxt_mask = eax + ((u64)edx << 32);
if ((pcntxt_mask & XSTATE_FPSSE) != XSTATE_FPSSE) {
@@ -329,12 +435,13 @@ void __ref xsave_cntxt_init(void)
* Support only the state known to OS.
*/
pcntxt_mask = pcntxt_mask & XCNTXT_MASK;
- xsave_init();
+
+ xstate_enable();
/*
* Recompute the context size for enabled features
*/
- cpuid_count(0xd, 0, &eax, &ebx, &ecx, &edx);
+ cpuid_count(XSTATE_CPUID, 0, &eax, &ebx, &ecx, &edx);
xstate_size = ebx;
update_regset_xstate_info(xstate_size, pcntxt_mask);
@@ -346,3 +453,23 @@ void __ref xsave_cntxt_init(void)
"cntxt size 0x%x\n",
pcntxt_mask, xstate_size);
}
+
+/*
+ * For the very first instance, this calls xstate_enable_boot_cpu();
+ * for all subsequent instances, this calls xstate_enable().
+ *
+ * This is somewhat obfuscated due to the lack of powerful enough
+ * overrides for the section checks.
+ */
+void __cpuinit xsave_init(void)
+{
+ static __refdata void (*next_func)(void) = xstate_enable_boot_cpu;
+ void (*this_func)(void);
+
+ if (!cpu_has_xsave)
+ return;
+
+ this_func = next_func;
+ next_func = xstate_enable;
+ this_func();
+}
diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c
index 5ac0bb465ed..b38bd8b92aa 100644
--- a/arch/x86/kvm/emulate.c
+++ b/arch/x86/kvm/emulate.c
@@ -9,6 +9,7 @@
* privileged instructions:
*
* Copyright (C) 2006 Qumranet
+ * Copyright 2010 Red Hat, Inc. and/or its affilates.
*
* Avi Kivity <avi@qumranet.com>
* Yaniv Kamay <yaniv@qumranet.com>
@@ -67,6 +68,9 @@
#define SrcImmUByte (8<<4) /* 8-bit unsigned immediate operand. */
#define SrcImmU (9<<4) /* Immediate operand, unsigned */
#define SrcSI (0xa<<4) /* Source is in the DS:RSI */
+#define SrcImmFAddr (0xb<<4) /* Source is immediate far address */
+#define SrcMemFAddr (0xc<<4) /* Source is far address in memory */
+#define SrcAcc (0xd<<4) /* Source Accumulator */
#define SrcMask (0xf<<4)
/* Generic ModRM decode. */
#define ModRM (1<<8)
@@ -88,10 +92,6 @@
#define Src2CL (1<<29)
#define Src2ImmByte (2<<29)
#define Src2One (3<<29)
-#define Src2Imm16 (4<<29)
-#define Src2Mem16 (5<<29) /* Used for Ep encoding. First argument has to be
- in memory and second argument is located
- immediately after the first one in memory. */
#define Src2Mask (7<<29)
enum {
@@ -124,15 +124,15 @@ static u32 opcode_table[256] = {
/* 0x20 - 0x27 */
ByteOp | DstMem | SrcReg | ModRM | Lock, DstMem | SrcReg | ModRM | Lock,
ByteOp | DstReg | SrcMem | ModRM, DstReg | SrcMem | ModRM,
- DstAcc | SrcImmByte, DstAcc | SrcImm, 0, 0,
+ ByteOp | DstAcc | SrcImmByte, DstAcc | SrcImm, 0, 0,
/* 0x28 - 0x2F */
ByteOp | DstMem | SrcReg | ModRM | Lock, DstMem | SrcReg | ModRM | Lock,
ByteOp | DstReg | SrcMem | ModRM, DstReg | SrcMem | ModRM,
- 0, 0, 0, 0,
+ ByteOp | DstAcc | SrcImmByte, DstAcc | SrcImm, 0, 0,
/* 0x30 - 0x37 */
ByteOp | DstMem | SrcReg | ModRM | Lock, DstMem | SrcReg | ModRM | Lock,
ByteOp | DstReg | SrcMem | ModRM, DstReg | SrcMem | ModRM,
- 0, 0, 0, 0,
+ ByteOp | DstAcc | SrcImmByte, DstAcc | SrcImm, 0, 0,
/* 0x38 - 0x3F */
ByteOp | DstMem | SrcReg | ModRM, DstMem | SrcReg | ModRM,
ByteOp | DstReg | SrcMem | ModRM, DstReg | SrcMem | ModRM,
@@ -170,20 +170,20 @@ static u32 opcode_table[256] = {
/* 0x88 - 0x8F */
ByteOp | DstMem | SrcReg | ModRM | Mov, DstMem | SrcReg | ModRM | Mov,
ByteOp | DstReg | SrcMem | ModRM | Mov, DstReg | SrcMem | ModRM | Mov,
- DstMem | SrcReg | ModRM | Mov, ModRM | DstReg,
- DstReg | SrcMem | ModRM | Mov, Group | Group1A,
+ DstMem | SrcNone | ModRM | Mov, ModRM | DstReg,
+ ImplicitOps | SrcMem16 | ModRM, Group | Group1A,
/* 0x90 - 0x97 */
DstReg, DstReg, DstReg, DstReg, DstReg, DstReg, DstReg, DstReg,
/* 0x98 - 0x9F */
- 0, 0, SrcImm | Src2Imm16 | No64, 0,
+ 0, 0, SrcImmFAddr | No64, 0,
ImplicitOps | Stack, ImplicitOps | Stack, 0, 0,
/* 0xA0 - 0xA7 */
- ByteOp | DstReg | SrcMem | Mov | MemAbs, DstReg | SrcMem | Mov | MemAbs,
- ByteOp | DstMem | SrcReg | Mov | MemAbs, DstMem | SrcReg | Mov | MemAbs,
+ ByteOp | DstAcc | SrcMem | Mov | MemAbs, DstAcc | SrcMem | Mov | MemAbs,
+ ByteOp | DstMem | SrcAcc | Mov | MemAbs, DstMem | SrcAcc | Mov | MemAbs,
ByteOp | SrcSI | DstDI | Mov | String, SrcSI | DstDI | Mov | String,
ByteOp | SrcSI | DstDI | String, SrcSI | DstDI | String,
/* 0xA8 - 0xAF */
- 0, 0, ByteOp | DstDI | Mov | String, DstDI | Mov | String,
+ DstAcc | SrcImmByte | ByteOp, DstAcc | SrcImm, ByteOp | DstDI | Mov | String, DstDI | Mov | String,
ByteOp | SrcSI | DstAcc | Mov | String, SrcSI | DstAcc | Mov | String,
ByteOp | DstDI | String, DstDI | String,
/* 0xB0 - 0xB7 */
@@ -215,7 +215,7 @@ static u32 opcode_table[256] = {
ByteOp | SrcImmUByte | DstAcc, SrcImmUByte | DstAcc,
/* 0xE8 - 0xEF */
SrcImm | Stack, SrcImm | ImplicitOps,
- SrcImmU | Src2Imm16 | No64, SrcImmByte | ImplicitOps,
+ SrcImmFAddr | No64, SrcImmByte | ImplicitOps,
SrcNone | ByteOp | DstAcc, SrcNone | DstAcc,
SrcNone | ByteOp | DstAcc, SrcNone | DstAcc,
/* 0xF0 - 0xF7 */
@@ -337,20 +337,20 @@ static u32 group_table[] = {
[Group1A*8] =
DstMem | SrcNone | ModRM | Mov | Stack, 0, 0, 0, 0, 0, 0, 0,
[Group3_Byte*8] =
- ByteOp | SrcImm | DstMem | ModRM, 0,
+ ByteOp | SrcImm | DstMem | ModRM, ByteOp | SrcImm | DstMem | ModRM,
ByteOp | DstMem | SrcNone | ModRM, ByteOp | DstMem | SrcNone | ModRM,
0, 0, 0, 0,
[Group3*8] =
- DstMem | SrcImm | ModRM, 0,
+ DstMem | SrcImm | ModRM, DstMem | SrcImm | ModRM,
DstMem | SrcNone | ModRM, DstMem | SrcNone | ModRM,
0, 0, 0, 0,
[Group4*8] =
- ByteOp | DstMem | SrcNone | ModRM, ByteOp | DstMem | SrcNone | ModRM,
+ ByteOp | DstMem | SrcNone | ModRM | Lock, ByteOp | DstMem | SrcNone | ModRM | Lock,
0, 0, 0, 0, 0, 0,
[Group5*8] =
- DstMem | SrcNone | ModRM, DstMem | SrcNone | ModRM,
+ DstMem | SrcNone | ModRM | Lock, DstMem | SrcNone | ModRM | Lock,
SrcMem | ModRM | Stack, 0,
- SrcMem | ModRM | Stack, SrcMem | ModRM | Src2Mem16 | ImplicitOps,
+ SrcMem | ModRM | Stack, SrcMemFAddr | ModRM | ImplicitOps,
SrcMem | ModRM | Stack, 0,
[Group7*8] =
0, 0, ModRM | SrcMem | Priv, ModRM | SrcMem | Priv,
@@ -576,6 +576,13 @@ static u32 group2_table[] = {
(_type)_x; \
})
+#define insn_fetch_arr(_arr, _size, _eip) \
+({ rc = do_insn_fetch(ctxt, ops, (_eip), _arr, (_size)); \
+ if (rc != X86EMUL_CONTINUE) \
+ goto done; \
+ (_eip) += (_size); \
+})
+
static inline unsigned long ad_mask(struct decode_cache *c)
{
return (1UL << (c->ad_bytes << 3)) - 1;
@@ -617,31 +624,66 @@ static void set_seg_override(struct decode_cache *c, int seg)
c->seg_override = seg;
}
-static unsigned long seg_base(struct x86_emulate_ctxt *ctxt, int seg)
+static unsigned long seg_base(struct x86_emulate_ctxt *ctxt,
+ struct x86_emulate_ops *ops, int seg)
{
if (ctxt->mode == X86EMUL_MODE_PROT64 && seg < VCPU_SREG_FS)
return 0;
- return kvm_x86_ops->get_segment_base(ctxt->vcpu, seg);
+ return ops->get_cached_segment_base(seg, ctxt->vcpu);
}
static unsigned long seg_override_base(struct x86_emulate_ctxt *ctxt,
+ struct x86_emulate_ops *ops,
struct decode_cache *c)
{
if (!c->has_seg_override)
return 0;
- return seg_base(ctxt, c->seg_override);
+ return seg_base(ctxt, ops, c->seg_override);
+}
+
+static unsigned long es_base(struct x86_emulate_ctxt *ctxt,
+ struct x86_emulate_ops *ops)
+{
+ return seg_base(ctxt, ops, VCPU_SREG_ES);
+}
+
+static unsigned long ss_base(struct x86_emulate_ctxt *ctxt,
+ struct x86_emulate_ops *ops)
+{
+ return seg_base(ctxt, ops, VCPU_SREG_SS);
+}
+
+static void emulate_exception(struct x86_emulate_ctxt *ctxt, int vec,
+ u32 error, bool valid)
+{
+ ctxt->exception = vec;
+ ctxt->error_code = error;
+ ctxt->error_code_valid = valid;
+ ctxt->restart = false;
+}
+
+static void emulate_gp(struct x86_emulate_ctxt *ctxt, int err)
+{
+ emulate_exception(ctxt, GP_VECTOR, err, true);
}
-static unsigned long es_base(struct x86_emulate_ctxt *ctxt)
+static void emulate_pf(struct x86_emulate_ctxt *ctxt, unsigned long addr,
+ int err)
{
- return seg_base(ctxt, VCPU_SREG_ES);
+ ctxt->cr2 = addr;
+ emulate_exception(ctxt, PF_VECTOR, err, true);
}
-static unsigned long ss_base(struct x86_emulate_ctxt *ctxt)
+static void emulate_ud(struct x86_emulate_ctxt *ctxt)
{
- return seg_base(ctxt, VCPU_SREG_SS);
+ emulate_exception(ctxt, UD_VECTOR, 0, false);
+}
+
+static void emulate_ts(struct x86_emulate_ctxt *ctxt, int err)
+{
+ emulate_exception(ctxt, TS_VECTOR, err, true);
}
static int do_fetch_insn_byte(struct x86_emulate_ctxt *ctxt,
@@ -932,12 +974,9 @@ x86_decode_insn(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops)
/* we cannot decode insn before we complete previous rep insn */
WARN_ON(ctxt->restart);
- /* Shadow copy of register state. Committed on successful emulation. */
- memset(c, 0, sizeof(struct decode_cache));
c->eip = ctxt->eip;
c->fetch.start = c->fetch.end = c->eip;
- ctxt->cs_base = seg_base(ctxt, VCPU_SREG_CS);
- memcpy(c->regs, ctxt->vcpu->arch.regs, sizeof c->regs);
+ ctxt->cs_base = seg_base(ctxt, ops, VCPU_SREG_CS);
switch (mode) {
case X86EMUL_MODE_REAL:
@@ -1060,7 +1099,7 @@ done_prefixes:
set_seg_override(c, VCPU_SREG_DS);
if (!(!c->twobyte && c->b == 0x8d))
- c->modrm_ea += seg_override_base(ctxt, c);
+ c->modrm_ea += seg_override_base(ctxt, ops, c);
if (c->ad_bytes != 8)
c->modrm_ea = (u32)c->modrm_ea;
@@ -1148,6 +1187,25 @@ done_prefixes:
else
c->src.val = insn_fetch(u8, 1, c->eip);
break;
+ case SrcAcc:
+ c->src.type = OP_REG;
+ c->src.bytes = (c->d & ByteOp) ? 1 : c->op_bytes;
+ c->src.ptr = &c->regs[VCPU_REGS_RAX];
+ switch (c->src.bytes) {
+ case 1:
+ c->src.val = *(u8 *)c->src.ptr;
+ break;
+ case 2:
+ c->src.val = *(u16 *)c->src.ptr;
+ break;
+ case 4:
+ c->src.val = *(u32 *)c->src.ptr;
+ break;
+ case 8:
+ c->src.val = *(u64 *)c->src.ptr;
+ break;
+ }
+ break;
case SrcOne:
c->src.bytes = 1;
c->src.val = 1;
@@ -1156,10 +1214,21 @@ done_prefixes:
c->src.type = OP_MEM;
c->src.bytes = (c->d & ByteOp) ? 1 : c->op_bytes;
c->src.ptr = (unsigned long *)
- register_address(c, seg_override_base(ctxt, c),
+ register_address(c, seg_override_base(ctxt, ops, c),
c->regs[VCPU_REGS_RSI]);
c->src.val = 0;
break;
+ case SrcImmFAddr:
+ c->src.type = OP_IMM;
+ c->src.ptr = (unsigned long *)c->eip;
+ c->src.bytes = c->op_bytes + 2;
+ insn_fetch_arr(c->src.valptr, c->src.bytes, c->eip);
+ break;
+ case SrcMemFAddr:
+ c->src.type = OP_MEM;
+ c->src.ptr = (unsigned long *)c->modrm_ea;
+ c->src.bytes = c->op_bytes + 2;
+ break;
}
/*
@@ -1179,22 +1248,10 @@ done_prefixes:
c->src2.bytes = 1;
c->src2.val = insn_fetch(u8, 1, c->eip);
break;
- case Src2Imm16:
- c->src2.type = OP_IMM;
- c->src2.ptr = (unsigned long *)c->eip;
- c->src2.bytes = 2;
- c->src2.val = insn_fetch(u16, 2, c->eip);
- break;
case Src2One:
c->src2.bytes = 1;
c->src2.val = 1;
break;
- case Src2Mem16:
- c->src2.type = OP_MEM;
- c->src2.bytes = 2;
- c->src2.ptr = (unsigned long *)(c->modrm_ea + c->src.bytes);
- c->src2.val = 0;
- break;
}
/* Decode and fetch the destination operand: register or memory. */
@@ -1253,7 +1310,7 @@ done_prefixes:
c->dst.type = OP_MEM;
c->dst.bytes = (c->d & ByteOp) ? 1 : c->op_bytes;
c->dst.ptr = (unsigned long *)
- register_address(c, es_base(ctxt),
+ register_address(c, es_base(ctxt, ops),
c->regs[VCPU_REGS_RDI]);
c->dst.val = 0;
break;
@@ -1263,6 +1320,37 @@ done:
return (rc == X86EMUL_UNHANDLEABLE) ? -1 : 0;
}
+static int read_emulated(struct x86_emulate_ctxt *ctxt,
+ struct x86_emulate_ops *ops,
+ unsigned long addr, void *dest, unsigned size)
+{
+ int rc;
+ struct read_cache *mc = &ctxt->decode.mem_read;
+ u32 err;
+
+ while (size) {
+ int n = min(size, 8u);
+ size -= n;
+ if (mc->pos < mc->end)
+ goto read_cached;
+
+ rc = ops->read_emulated(addr, mc->data + mc->end, n, &err,
+ ctxt->vcpu);
+ if (rc == X86EMUL_PROPAGATE_FAULT)
+ emulate_pf(ctxt, addr, err);
+ if (rc != X86EMUL_CONTINUE)
+ return rc;
+ mc->end += n;
+
+ read_cached:
+ memcpy(dest, mc->data + mc->pos, n);
+ mc->pos += n;
+ dest += n;
+ addr += n;
+ }
+ return X86EMUL_CONTINUE;
+}
+
static int pio_in_emulated(struct x86_emulate_ctxt *ctxt,
struct x86_emulate_ops *ops,
unsigned int size, unsigned short port,
@@ -1330,13 +1418,13 @@ static int read_segment_descriptor(struct x86_emulate_ctxt *ctxt,
get_descriptor_table_ptr(ctxt, ops, selector, &dt);
if (dt.size < index * 8 + 7) {
- kvm_inject_gp(ctxt->vcpu, selector & 0xfffc);
+ emulate_gp(ctxt, selector & 0xfffc);
return X86EMUL_PROPAGATE_FAULT;
}
addr = dt.address + index * 8;
ret = ops->read_std(addr, desc, sizeof *desc, ctxt->vcpu, &err);
if (ret == X86EMUL_PROPAGATE_FAULT)
- kvm_inject_page_fault(ctxt->vcpu, addr, err);
+ emulate_pf(ctxt, addr, err);
return ret;
}
@@ -1355,14 +1443,14 @@ static int write_segment_descriptor(struct x86_emulate_ctxt *ctxt,
get_descriptor_table_ptr(ctxt, ops, selector, &dt);
if (dt.size < index * 8 + 7) {
- kvm_inject_gp(ctxt->vcpu, selector & 0xfffc);
+ emulate_gp(ctxt, selector & 0xfffc);
return X86EMUL_PROPAGATE_FAULT;
}
addr = dt.address + index * 8;
ret = ops->write_std(addr, desc, sizeof *desc, ctxt->vcpu, &err);
if (ret == X86EMUL_PROPAGATE_FAULT)
- kvm_inject_page_fault(ctxt->vcpu, addr, err);
+ emulate_pf(ctxt, addr, err);
return ret;
}
@@ -1481,11 +1569,70 @@ load:
ops->set_cached_descriptor(&seg_desc, seg, ctxt->vcpu);
return X86EMUL_CONTINUE;
exception:
- kvm_queue_exception_e(ctxt->vcpu, err_vec, err_code);
+ emulate_exception(ctxt, err_vec, err_code, true);
return X86EMUL_PROPAGATE_FAULT;
}
-static inline void emulate_push(struct x86_emulate_ctxt *ctxt)
+static inline int writeback(struct x86_emulate_ctxt *ctxt,
+ struct x86_emulate_ops *ops)
+{
+ int rc;
+ struct decode_cache *c = &ctxt->decode;
+ u32 err;
+
+ switch (c->dst.type) {
+ case OP_REG:
+ /* The 4-byte case *is* correct:
+ * in 64-bit mode we zero-extend.
+ */
+ switch (c->dst.bytes) {
+ case 1:
+ *(u8 *)c->dst.ptr = (u8)c->dst.val;
+ break;
+ case 2:
+ *(u16 *)c->dst.ptr = (u16)c->dst.val;
+ break;
+ case 4:
+ *c->dst.ptr = (u32)c->dst.val;
+ break; /* 64b: zero-ext */
+ case 8:
+ *c->dst.ptr = c->dst.val;
+ break;
+ }
+ break;
+ case OP_MEM:
+ if (c->lock_prefix)
+ rc = ops->cmpxchg_emulated(
+ (unsigned long)c->dst.ptr,
+ &c->dst.orig_val,
+ &c->dst.val,
+ c->dst.bytes,
+ &err,
+ ctxt->vcpu);
+ else
+ rc = ops->write_emulated(
+ (unsigned long)c->dst.ptr,
+ &c->dst.val,
+ c->dst.bytes,
+ &err,
+ ctxt->vcpu);
+ if (rc == X86EMUL_PROPAGATE_FAULT)
+ emulate_pf(ctxt,
+ (unsigned long)c->dst.ptr, err);
+ if (rc != X86EMUL_CONTINUE)
+ return rc;
+ break;
+ case OP_NONE:
+ /* no writeback */
+ break;
+ default:
+ break;
+ }
+ return X86EMUL_CONTINUE;
+}
+
+static inline void emulate_push(struct x86_emulate_ctxt *ctxt,
+ struct x86_emulate_ops *ops)
{
struct decode_cache *c = &ctxt->decode;
@@ -1493,7 +1640,7 @@ static inline void emulate_push(struct x86_emulate_ctxt *ctxt)
c->dst.bytes = c->op_bytes;
c->dst.val = c->src.val;
register_address_increment(c, &c->regs[VCPU_REGS_RSP], -c->op_bytes);
- c->dst.ptr = (void *) register_address(c, ss_base(ctxt),
+ c->dst.ptr = (void *) register_address(c, ss_base(ctxt, ops),
c->regs[VCPU_REGS_RSP]);
}
@@ -1504,9 +1651,9 @@ static int emulate_pop(struct x86_emulate_ctxt *ctxt,
struct decode_cache *c = &ctxt->decode;
int rc;
- rc = ops->read_emulated(register_address(c, ss_base(ctxt),
- c->regs[VCPU_REGS_RSP]),
- dest, len, ctxt->vcpu);
+ rc = read_emulated(ctxt, ops, register_address(c, ss_base(ctxt, ops),
+ c->regs[VCPU_REGS_RSP]),
+ dest, len);
if (rc != X86EMUL_CONTINUE)
return rc;
@@ -1541,7 +1688,7 @@ static int emulate_popf(struct x86_emulate_ctxt *ctxt,
break;
case X86EMUL_MODE_VM86:
if (iopl < 3) {
- kvm_inject_gp(ctxt->vcpu, 0);
+ emulate_gp(ctxt, 0);
return X86EMUL_PROPAGATE_FAULT;
}
change_mask |= EFLG_IF;
@@ -1557,15 +1704,14 @@ static int emulate_popf(struct x86_emulate_ctxt *ctxt,
return rc;
}
-static void emulate_push_sreg(struct x86_emulate_ctxt *ctxt, int seg)
+static void emulate_push_sreg(struct x86_emulate_ctxt *ctxt,
+ struct x86_emulate_ops *ops, int seg)
{
struct decode_cache *c = &ctxt->decode;
- struct kvm_segment segment;
- kvm_x86_ops->get_segment(ctxt->vcpu, &segment, seg);
+ c->src.val = ops->get_segment_selector(seg, ctxt->vcpu);
- c->src.val = segment.selector;
- emulate_push(ctxt);
+ emulate_push(ctxt, ops);
}
static int emulate_pop_sreg(struct x86_emulate_ctxt *ctxt,
@@ -1583,19 +1729,31 @@ static int emulate_pop_sreg(struct x86_emulate_ctxt *ctxt,
return rc;
}
-static void emulate_pusha(struct x86_emulate_ctxt *ctxt)
+static int emulate_pusha(struct x86_emulate_ctxt *ctxt,
+ struct x86_emulate_ops *ops)
{
struct decode_cache *c = &ctxt->decode;
unsigned long old_esp = c->regs[VCPU_REGS_RSP];
+ int rc = X86EMUL_CONTINUE;
int reg = VCPU_REGS_RAX;
while (reg <= VCPU_REGS_RDI) {
(reg == VCPU_REGS_RSP) ?
(c->src.val = old_esp) : (c->src.val = c->regs[reg]);
- emulate_push(ctxt);
+ emulate_push(ctxt, ops);
+
+ rc = writeback(ctxt, ops);
+ if (rc != X86EMUL_CONTINUE)
+ return rc;
+
++reg;
}
+
+ /* Disable writeback. */
+ c->dst.type = OP_NONE;
+
+ return rc;
}
static int emulate_popa(struct x86_emulate_ctxt *ctxt,
@@ -1695,14 +1853,14 @@ static inline int emulate_grp45(struct x86_emulate_ctxt *ctxt,
old_eip = c->eip;
c->eip = c->src.val;
c->src.val = old_eip;
- emulate_push(ctxt);
+ emulate_push(ctxt, ops);
break;
}
case 4: /* jmp abs */
c->eip = c->src.val;
break;
case 6: /* push */
- emulate_push(ctxt);
+ emulate_push(ctxt, ops);
break;
}
return X86EMUL_CONTINUE;
@@ -1748,145 +1906,82 @@ static int emulate_ret_far(struct x86_emulate_ctxt *ctxt,
return rc;
}
-static inline int writeback(struct x86_emulate_ctxt *ctxt,
- struct x86_emulate_ops *ops)
-{
- int rc;
- struct decode_cache *c = &ctxt->decode;
-
- switch (c->dst.type) {
- case OP_REG:
- /* The 4-byte case *is* correct:
- * in 64-bit mode we zero-extend.
- */
- switch (c->dst.bytes) {
- case 1:
- *(u8 *)c->dst.ptr = (u8)c->dst.val;
- break;
- case 2:
- *(u16 *)c->dst.ptr = (u16)c->dst.val;
- break;
- case 4:
- *c->dst.ptr = (u32)c->dst.val;
- break; /* 64b: zero-ext */
- case 8:
- *c->dst.ptr = c->dst.val;
- break;
- }
- break;
- case OP_MEM:
- if (c->lock_prefix)
- rc = ops->cmpxchg_emulated(
- (unsigned long)c->dst.ptr,
- &c->dst.orig_val,
- &c->dst.val,
- c->dst.bytes,
- ctxt->vcpu);
- else
- rc = ops->write_emulated(
- (unsigned long)c->dst.ptr,
- &c->dst.val,
- c->dst.bytes,
- ctxt->vcpu);
- if (rc != X86EMUL_CONTINUE)
- return rc;
- break;
- case OP_NONE:
- /* no writeback */
- break;
- default:
- break;
- }
- return X86EMUL_CONTINUE;
-}
-
-static void toggle_interruptibility(struct x86_emulate_ctxt *ctxt, u32 mask)
-{
- u32 int_shadow = kvm_x86_ops->get_interrupt_shadow(ctxt->vcpu, mask);
- /*
- * an sti; sti; sequence only disable interrupts for the first
- * instruction. So, if the last instruction, be it emulated or
- * not, left the system with the INT_STI flag enabled, it
- * means that the last instruction is an sti. We should not
- * leave the flag on in this case. The same goes for mov ss
- */
- if (!(int_shadow & mask))
- ctxt->interruptibility = mask;
-}
-
static inline void
setup_syscalls_segments(struct x86_emulate_ctxt *ctxt,
- struct kvm_segment *cs, struct kvm_segment *ss)
+ struct x86_emulate_ops *ops, struct desc_struct *cs,
+ struct desc_struct *ss)
{
- memset(cs, 0, sizeof(struct kvm_segment));
- kvm_x86_ops->get_segment(ctxt->vcpu, cs, VCPU_SREG_CS);
- memset(ss, 0, sizeof(struct kvm_segment));
+ memset(cs, 0, sizeof(struct desc_struct));
+ ops->get_cached_descriptor(cs, VCPU_SREG_CS, ctxt->vcpu);
+ memset(ss, 0, sizeof(struct desc_struct));
cs->l = 0; /* will be adjusted later */
- cs->base = 0; /* flat segment */
+ set_desc_base(cs, 0); /* flat segment */
cs->g = 1; /* 4kb granularity */
- cs->limit = 0xffffffff; /* 4GB limit */
+ set_desc_limit(cs, 0xfffff); /* 4GB limit */
cs->type = 0x0b; /* Read, Execute, Accessed */
cs->s = 1;
cs->dpl = 0; /* will be adjusted later */
- cs->present = 1;
- cs->db = 1;
+ cs->p = 1;
+ cs->d = 1;
- ss->unusable = 0;
- ss->base = 0; /* flat segment */
- ss->limit = 0xffffffff; /* 4GB limit */
+ set_desc_base(ss, 0); /* flat segment */
+ set_desc_limit(ss, 0xfffff); /* 4GB limit */
ss->g = 1; /* 4kb granularity */
ss->s = 1;
ss->type = 0x03; /* Read/Write, Accessed */
- ss->db = 1; /* 32bit stack segment */
+ ss->d = 1; /* 32bit stack segment */
ss->dpl = 0;
- ss->present = 1;
+ ss->p = 1;
}
static int
-emulate_syscall(struct x86_emulate_ctxt *ctxt)
+emulate_syscall(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops)
{
struct decode_cache *c = &ctxt->decode;
- struct kvm_segment cs, ss;
+ struct desc_struct cs, ss;
u64 msr_data;
+ u16 cs_sel, ss_sel;
/* syscall is not available in real mode */
if (ctxt->mode == X86EMUL_MODE_REAL ||
ctxt->mode == X86EMUL_MODE_VM86) {
- kvm_queue_exception(ctxt->vcpu, UD_VECTOR);
+ emulate_ud(ctxt);
return X86EMUL_PROPAGATE_FAULT;
}
- setup_syscalls_segments(ctxt, &cs, &ss);
+ setup_syscalls_segments(ctxt, ops, &cs, &ss);
- kvm_x86_ops->get_msr(ctxt->vcpu, MSR_STAR, &msr_data);
+ ops->get_msr(ctxt->vcpu, MSR_STAR, &msr_data);
msr_data >>= 32;
- cs.selector = (u16)(msr_data & 0xfffc);
- ss.selector = (u16)(msr_data + 8);
+ cs_sel = (u16)(msr_data & 0xfffc);
+ ss_sel = (u16)(msr_data + 8);
if (is_long_mode(ctxt->vcpu)) {
- cs.db = 0;
+ cs.d = 0;
cs.l = 1;
}
- kvm_x86_ops->set_segment(ctxt->vcpu, &cs, VCPU_SREG_CS);
- kvm_x86_ops->set_segment(ctxt->vcpu, &ss, VCPU_SREG_SS);
+ ops->set_cached_descriptor(&cs, VCPU_SREG_CS, ctxt->vcpu);
+ ops->set_segment_selector(cs_sel, VCPU_SREG_CS, ctxt->vcpu);
+ ops->set_cached_descriptor(&ss, VCPU_SREG_SS, ctxt->vcpu);
+ ops->set_segment_selector(ss_sel, VCPU_SREG_SS, ctxt->vcpu);
c->regs[VCPU_REGS_RCX] = c->eip;
if (is_long_mode(ctxt->vcpu)) {
#ifdef CONFIG_X86_64
c->regs[VCPU_REGS_R11] = ctxt->eflags & ~EFLG_RF;
- kvm_x86_ops->get_msr(ctxt->vcpu,
- ctxt->mode == X86EMUL_MODE_PROT64 ?
- MSR_LSTAR : MSR_CSTAR, &msr_data);
+ ops->get_msr(ctxt->vcpu,
+ ctxt->mode == X86EMUL_MODE_PROT64 ?
+ MSR_LSTAR : MSR_CSTAR, &msr_data);
c->eip = msr_data;
- kvm_x86_ops->get_msr(ctxt->vcpu, MSR_SYSCALL_MASK, &msr_data);
+ ops->get_msr(ctxt->vcpu, MSR_SYSCALL_MASK, &msr_data);
ctxt->eflags &= ~(msr_data | EFLG_RF);
#endif
} else {
/* legacy mode */
- kvm_x86_ops->get_msr(ctxt->vcpu, MSR_STAR, &msr_data);
+ ops->get_msr(ctxt->vcpu, MSR_STAR, &msr_data);
c->eip = (u32)msr_data;
ctxt->eflags &= ~(EFLG_VM | EFLG_IF | EFLG_RF);
@@ -1896,15 +1991,16 @@ emulate_syscall(struct x86_emulate_ctxt *ctxt)
}
static int
-emulate_sysenter(struct x86_emulate_ctxt *ctxt)
+emulate_sysenter(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops)
{
struct decode_cache *c = &ctxt->decode;
- struct kvm_segment cs, ss;
+ struct desc_struct cs, ss;
u64 msr_data;
+ u16 cs_sel, ss_sel;
/* inject #GP if in real mode */
if (ctxt->mode == X86EMUL_MODE_REAL) {
- kvm_inject_gp(ctxt->vcpu, 0);
+ emulate_gp(ctxt, 0);
return X86EMUL_PROPAGATE_FAULT;
}
@@ -1912,67 +2008,70 @@ emulate_sysenter(struct x86_emulate_ctxt *ctxt)
* Therefore, we inject an #UD.
*/
if (ctxt->mode == X86EMUL_MODE_PROT64) {
- kvm_queue_exception(ctxt->vcpu, UD_VECTOR);
+ emulate_ud(ctxt);
return X86EMUL_PROPAGATE_FAULT;
}
- setup_syscalls_segments(ctxt, &cs, &ss);
+ setup_syscalls_segments(ctxt, ops, &cs, &ss);
- kvm_x86_ops->get_msr(ctxt->vcpu, MSR_IA32_SYSENTER_CS, &msr_data);
+ ops->get_msr(ctxt->vcpu, MSR_IA32_SYSENTER_CS, &msr_data);
switch (ctxt->mode) {
case X86EMUL_MODE_PROT32:
if ((msr_data & 0xfffc) == 0x0) {
- kvm_inject_gp(ctxt->vcpu, 0);
+ emulate_gp(ctxt, 0);
return X86EMUL_PROPAGATE_FAULT;
}
break;
case X86EMUL_MODE_PROT64:
if (msr_data == 0x0) {
- kvm_inject_gp(ctxt->vcpu, 0);
+ emulate_gp(ctxt, 0);
return X86EMUL_PROPAGATE_FAULT;
}
break;
}
ctxt->eflags &= ~(EFLG_VM | EFLG_IF | EFLG_RF);
- cs.selector = (u16)msr_data;
- cs.selector &= ~SELECTOR_RPL_MASK;
- ss.selector = cs.selector + 8;
- ss.selector &= ~SELECTOR_RPL_MASK;
+ cs_sel = (u16)msr_data;
+ cs_sel &= ~SELECTOR_RPL_MASK;
+ ss_sel = cs_sel + 8;
+ ss_sel &= ~SELECTOR_RPL_MASK;
if (ctxt->mode == X86EMUL_MODE_PROT64
|| is_long_mode(ctxt->vcpu)) {
- cs.db = 0;
+ cs.d = 0;
cs.l = 1;
}
- kvm_x86_ops->set_segment(ctxt->vcpu, &cs, VCPU_SREG_CS);
- kvm_x86_ops->set_segment(ctxt->vcpu, &ss, VCPU_SREG_SS);
+ ops->set_cached_descriptor(&cs, VCPU_SREG_CS, ctxt->vcpu);
+ ops->set_segment_selector(cs_sel, VCPU_SREG_CS, ctxt->vcpu);
+ ops->set_cached_descriptor(&ss, VCPU_SREG_SS, ctxt->vcpu);
+ ops->set_segment_selector(ss_sel, VCPU_SREG_SS, ctxt->vcpu);
- kvm_x86_ops->get_msr(ctxt->vcpu, MSR_IA32_SYSENTER_EIP, &msr_data);
+ ops->get_msr(ctxt->vcpu, MSR_IA32_SYSENTER_EIP, &msr_data);
c->eip = msr_data;
- kvm_x86_ops->get_msr(ctxt->vcpu, MSR_IA32_SYSENTER_ESP, &msr_data);
+ ops->get_msr(ctxt->vcpu, MSR_IA32_SYSENTER_ESP, &msr_data);
c->regs[VCPU_REGS_RSP] = msr_data;
return X86EMUL_CONTINUE;
}
static int
-emulate_sysexit(struct x86_emulate_ctxt *ctxt)
+emulate_sysexit(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops)
{
struct decode_cache *c = &ctxt->decode;
- struct kvm_segment cs, ss;
+ struct desc_struct cs, ss;
u64 msr_data;
int usermode;
+ u16 cs_sel, ss_sel;
/* inject #GP if in real mode or Virtual 8086 mode */
if (ctxt->mode == X86EMUL_MODE_REAL ||
ctxt->mode == X86EMUL_MODE_VM86) {
- kvm_inject_gp(ctxt->vcpu, 0);
+ emulate_gp(ctxt, 0);
return X86EMUL_PROPAGATE_FAULT;
}
- setup_syscalls_segments(ctxt, &cs, &ss);
+ setup_syscalls_segments(ctxt, ops, &cs, &ss);
if ((c->rex_prefix & 0x8) != 0x0)
usermode = X86EMUL_MODE_PROT64;
@@ -1981,35 +2080,37 @@ emulate_sysexit(struct x86_emulate_ctxt *ctxt)
cs.dpl = 3;
ss.dpl = 3;
- kvm_x86_ops->get_msr(ctxt->vcpu, MSR_IA32_SYSENTER_CS, &msr_data);
+ ops->get_msr(ctxt->vcpu, MSR_IA32_SYSENTER_CS, &msr_data);
switch (usermode) {
case X86EMUL_MODE_PROT32:
- cs.selector = (u16)(msr_data + 16);
+ cs_sel = (u16)(msr_data + 16);
if ((msr_data & 0xfffc) == 0x0) {
- kvm_inject_gp(ctxt->vcpu, 0);
+ emulate_gp(ctxt, 0);
return X86EMUL_PROPAGATE_FAULT;
}
- ss.selector = (u16)(msr_data + 24);
+ ss_sel = (u16)(msr_data + 24);
break;
case X86EMUL_MODE_PROT64:
- cs.selector = (u16)(msr_data + 32);
+ cs_sel = (u16)(msr_data + 32);
if (msr_data == 0x0) {
- kvm_inject_gp(ctxt->vcpu, 0);
+ emulate_gp(ctxt, 0);
return X86EMUL_PROPAGATE_FAULT;
}
- ss.selector = cs.selector + 8;
- cs.db = 0;
+ ss_sel = cs_sel + 8;
+ cs.d = 0;
cs.l = 1;
break;
}
- cs.selector |= SELECTOR_RPL_MASK;
- ss.selector |= SELECTOR_RPL_MASK;
+ cs_sel |= SELECTOR_RPL_MASK;
+ ss_sel |= SELECTOR_RPL_MASK;
- kvm_x86_ops->set_segment(ctxt->vcpu, &cs, VCPU_SREG_CS);
- kvm_x86_ops->set_segment(ctxt->vcpu, &ss, VCPU_SREG_SS);
+ ops->set_cached_descriptor(&cs, VCPU_SREG_CS, ctxt->vcpu);
+ ops->set_segment_selector(cs_sel, VCPU_SREG_CS, ctxt->vcpu);
+ ops->set_cached_descriptor(&ss, VCPU_SREG_SS, ctxt->vcpu);
+ ops->set_segment_selector(ss_sel, VCPU_SREG_SS, ctxt->vcpu);
- c->eip = ctxt->vcpu->arch.regs[VCPU_REGS_RDX];
- c->regs[VCPU_REGS_RSP] = ctxt->vcpu->arch.regs[VCPU_REGS_RCX];
+ c->eip = c->regs[VCPU_REGS_RDX];
+ c->regs[VCPU_REGS_RSP] = c->regs[VCPU_REGS_RCX];
return X86EMUL_CONTINUE;
}
@@ -2030,25 +2131,25 @@ static bool emulator_io_port_access_allowed(struct x86_emulate_ctxt *ctxt,
struct x86_emulate_ops *ops,
u16 port, u16 len)
{
- struct kvm_segment tr_seg;
+ struct desc_struct tr_seg;
int r;
u16 io_bitmap_ptr;
u8 perm, bit_idx = port & 0x7;
unsigned mask = (1 << len) - 1;
- kvm_get_segment(ctxt->vcpu, &tr_seg, VCPU_SREG_TR);
- if (tr_seg.unusable)
+ ops->get_cached_descriptor(&tr_seg, VCPU_SREG_TR, ctxt->vcpu);
+ if (!tr_seg.p)
return false;
- if (tr_seg.limit < 103)
+ if (desc_limit_scaled(&tr_seg) < 103)
return false;
- r = ops->read_std(tr_seg.base + 102, &io_bitmap_ptr, 2, ctxt->vcpu,
- NULL);
+ r = ops->read_std(get_desc_base(&tr_seg) + 102, &io_bitmap_ptr, 2,
+ ctxt->vcpu, NULL);
if (r != X86EMUL_CONTINUE)
return false;
- if (io_bitmap_ptr + port/8 > tr_seg.limit)
+ if (io_bitmap_ptr + port/8 > desc_limit_scaled(&tr_seg))
return false;
- r = ops->read_std(tr_seg.base + io_bitmap_ptr + port/8, &perm, 1,
- ctxt->vcpu, NULL);
+ r = ops->read_std(get_desc_base(&tr_seg) + io_bitmap_ptr + port/8,
+ &perm, 1, ctxt->vcpu, NULL);
if (r != X86EMUL_CONTINUE)
return false;
if ((perm >> bit_idx) & mask)
@@ -2066,17 +2167,6 @@ static bool emulator_io_permited(struct x86_emulate_ctxt *ctxt,
return true;
}
-static u32 get_cached_descriptor_base(struct x86_emulate_ctxt *ctxt,
- struct x86_emulate_ops *ops,
- int seg)
-{
- struct desc_struct desc;
- if (ops->get_cached_descriptor(&desc, seg, ctxt->vcpu))
- return get_desc_base(&desc);
- else
- return ~0;
-}
-
static void save_state_to_tss16(struct x86_emulate_ctxt *ctxt,
struct x86_emulate_ops *ops,
struct tss_segment_16 *tss)
@@ -2165,7 +2255,7 @@ static int task_switch_16(struct x86_emulate_ctxt *ctxt,
&err);
if (ret == X86EMUL_PROPAGATE_FAULT) {
/* FIXME: need to provide precise fault address */
- kvm_inject_page_fault(ctxt->vcpu, old_tss_base, err);
+ emulate_pf(ctxt, old_tss_base, err);
return ret;
}
@@ -2175,7 +2265,7 @@ static int task_switch_16(struct x86_emulate_ctxt *ctxt,
&err);
if (ret == X86EMUL_PROPAGATE_FAULT) {
/* FIXME: need to provide precise fault address */
- kvm_inject_page_fault(ctxt->vcpu, old_tss_base, err);
+ emulate_pf(ctxt, old_tss_base, err);
return ret;
}
@@ -2183,7 +2273,7 @@ static int task_switch_16(struct x86_emulate_ctxt *ctxt,
&err);
if (ret == X86EMUL_PROPAGATE_FAULT) {
/* FIXME: need to provide precise fault address */
- kvm_inject_page_fault(ctxt->vcpu, new_tss_base, err);
+ emulate_pf(ctxt, new_tss_base, err);
return ret;
}
@@ -2196,7 +2286,7 @@ static int task_switch_16(struct x86_emulate_ctxt *ctxt,
ctxt->vcpu, &err);
if (ret == X86EMUL_PROPAGATE_FAULT) {
/* FIXME: need to provide precise fault address */
- kvm_inject_page_fault(ctxt->vcpu, new_tss_base, err);
+ emulate_pf(ctxt, new_tss_base, err);
return ret;
}
}
@@ -2238,7 +2328,10 @@ static int load_state_from_tss32(struct x86_emulate_ctxt *ctxt,
struct decode_cache *c = &ctxt->decode;
int ret;
- ops->set_cr(3, tss->cr3, ctxt->vcpu);
+ if (ops->set_cr(3, tss->cr3, ctxt->vcpu)) {
+ emulate_gp(ctxt, 0);
+ return X86EMUL_PROPAGATE_FAULT;
+ }
c->eip = tss->eip;
ctxt->eflags = tss->eflags | 2;
c->regs[VCPU_REGS_RAX] = tss->eax;
@@ -2304,7 +2397,7 @@ static int task_switch_32(struct x86_emulate_ctxt *ctxt,
&err);
if (ret == X86EMUL_PROPAGATE_FAULT) {
/* FIXME: need to provide precise fault address */
- kvm_inject_page_fault(ctxt->vcpu, old_tss_base, err);
+ emulate_pf(ctxt, old_tss_base, err);
return ret;
}
@@ -2314,7 +2407,7 @@ static int task_switch_32(struct x86_emulate_ctxt *ctxt,
&err);
if (ret == X86EMUL_PROPAGATE_FAULT) {
/* FIXME: need to provide precise fault address */
- kvm_inject_page_fault(ctxt->vcpu, old_tss_base, err);
+ emulate_pf(ctxt, old_tss_base, err);
return ret;
}
@@ -2322,7 +2415,7 @@ static int task_switch_32(struct x86_emulate_ctxt *ctxt,
&err);
if (ret == X86EMUL_PROPAGATE_FAULT) {
/* FIXME: need to provide precise fault address */
- kvm_inject_page_fault(ctxt->vcpu, new_tss_base, err);
+ emulate_pf(ctxt, new_tss_base, err);
return ret;
}
@@ -2335,7 +2428,7 @@ static int task_switch_32(struct x86_emulate_ctxt *ctxt,
ctxt->vcpu, &err);
if (ret == X86EMUL_PROPAGATE_FAULT) {
/* FIXME: need to provide precise fault address */
- kvm_inject_page_fault(ctxt->vcpu, new_tss_base, err);
+ emulate_pf(ctxt, new_tss_base, err);
return ret;
}
}
@@ -2352,7 +2445,7 @@ static int emulator_do_task_switch(struct x86_emulate_ctxt *ctxt,
int ret;
u16 old_tss_sel = ops->get_segment_selector(VCPU_SREG_TR, ctxt->vcpu);
ulong old_tss_base =
- get_cached_descriptor_base(ctxt, ops, VCPU_SREG_TR);
+ ops->get_cached_segment_base(VCPU_SREG_TR, ctxt->vcpu);
u32 desc_limit;
/* FIXME: old_tss_base == ~0 ? */
@@ -2369,7 +2462,7 @@ static int emulator_do_task_switch(struct x86_emulate_ctxt *ctxt,
if (reason != TASK_SWITCH_IRET) {
if ((tss_selector & 3) > next_tss_desc.dpl ||
ops->cpl(ctxt->vcpu) > next_tss_desc.dpl) {
- kvm_inject_gp(ctxt->vcpu, 0);
+ emulate_gp(ctxt, 0);
return X86EMUL_PROPAGATE_FAULT;
}
}
@@ -2378,8 +2471,7 @@ static int emulator_do_task_switch(struct x86_emulate_ctxt *ctxt,
if (!next_tss_desc.p ||
((desc_limit < 0x67 && (next_tss_desc.type & 8)) ||
desc_limit < 0x2b)) {
- kvm_queue_exception_e(ctxt->vcpu, TS_VECTOR,
- tss_selector & 0xfffc);
+ emulate_ts(ctxt, tss_selector & 0xfffc);
return X86EMUL_PROPAGATE_FAULT;
}
@@ -2425,7 +2517,7 @@ static int emulator_do_task_switch(struct x86_emulate_ctxt *ctxt,
c->op_bytes = c->ad_bytes = (next_tss_desc.type & 8) ? 4 : 2;
c->lock_prefix = 0;
c->src.val = (unsigned long) error_code;
- emulate_push(ctxt);
+ emulate_push(ctxt, ops);
}
return ret;
@@ -2439,18 +2531,16 @@ int emulator_task_switch(struct x86_emulate_ctxt *ctxt,
struct decode_cache *c = &ctxt->decode;
int rc;
- memset(c, 0, sizeof(struct decode_cache));
c->eip = ctxt->eip;
- memcpy(c->regs, ctxt->vcpu->arch.regs, sizeof c->regs);
c->dst.type = OP_NONE;
rc = emulator_do_task_switch(ctxt, ops, tss_selector, reason,
has_error_code, error_code);
if (rc == X86EMUL_CONTINUE) {
- memcpy(ctxt->vcpu->arch.regs, c->regs, sizeof c->regs);
- kvm_rip_write(ctxt->vcpu, c->eip);
rc = writeback(ctxt, ops);
+ if (rc == X86EMUL_CONTINUE)
+ ctxt->eip = c->eip;
}
return (rc == X86EMUL_UNHANDLEABLE) ? -1 : 0;
@@ -2474,29 +2564,22 @@ x86_emulate_insn(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops)
int rc = X86EMUL_CONTINUE;
int saved_dst_type = c->dst.type;
- ctxt->interruptibility = 0;
-
- /* Shadow copy of register state. Committed on successful emulation.
- * NOTE: we can copy them from vcpu as x86_decode_insn() doesn't
- * modify them.
- */
-
- memcpy(c->regs, ctxt->vcpu->arch.regs, sizeof c->regs);
+ ctxt->decode.mem_read.pos = 0;
if (ctxt->mode == X86EMUL_MODE_PROT64 && (c->d & No64)) {
- kvm_queue_exception(ctxt->vcpu, UD_VECTOR);
+ emulate_ud(ctxt);
goto done;
}
/* LOCK prefix is allowed only with some instructions */
if (c->lock_prefix && (!(c->d & Lock) || c->dst.type != OP_MEM)) {
- kvm_queue_exception(ctxt->vcpu, UD_VECTOR);
+ emulate_ud(ctxt);
goto done;
}
/* Privileged instruction can be executed only in CPL=0 */
if ((c->d & Priv) && ops->cpl(ctxt->vcpu)) {
- kvm_inject_gp(ctxt->vcpu, 0);
+ emulate_gp(ctxt, 0);
goto done;
}
@@ -2506,7 +2589,7 @@ x86_emulate_insn(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops)
if (address_mask(c, c->regs[VCPU_REGS_RCX]) == 0) {
string_done:
ctxt->restart = false;
- kvm_rip_write(ctxt->vcpu, c->eip);
+ ctxt->eip = c->eip;
goto done;
}
/* The second termination condition only applies for REPE
@@ -2529,20 +2612,16 @@ x86_emulate_insn(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops)
}
if (c->src.type == OP_MEM) {
- rc = ops->read_emulated((unsigned long)c->src.ptr,
- &c->src.val,
- c->src.bytes,
- ctxt->vcpu);
+ rc = read_emulated(ctxt, ops, (unsigned long)c->src.ptr,
+ c->src.valptr, c->src.bytes);
if (rc != X86EMUL_CONTINUE)
goto done;
c->src.orig_val = c->src.val;
}
if (c->src2.type == OP_MEM) {
- rc = ops->read_emulated((unsigned long)c->src2.ptr,
- &c->src2.val,
- c->src2.bytes,
- ctxt->vcpu);
+ rc = read_emulated(ctxt, ops, (unsigned long)c->src2.ptr,
+ &c->src2.val, c->src2.bytes);
if (rc != X86EMUL_CONTINUE)
goto done;
}
@@ -2553,8 +2632,8 @@ x86_emulate_insn(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops)
if ((c->dst.type == OP_MEM) && !(c->d & Mov)) {
/* optimisation - avoid slow emulated read if Mov */
- rc = ops->read_emulated((unsigned long)c->dst.ptr, &c->dst.val,
- c->dst.bytes, ctxt->vcpu);
+ rc = read_emulated(ctxt, ops, (unsigned long)c->dst.ptr,
+ &c->dst.val, c->dst.bytes);
if (rc != X86EMUL_CONTINUE)
goto done;
}
@@ -2571,7 +2650,7 @@ special_insn:
emulate_2op_SrcV("add", c->src, c->dst, ctxt->eflags);
break;
case 0x06: /* push es */
- emulate_push_sreg(ctxt, VCPU_SREG_ES);
+ emulate_push_sreg(ctxt, ops, VCPU_SREG_ES);
break;
case 0x07: /* pop es */
rc = emulate_pop_sreg(ctxt, ops, VCPU_SREG_ES);
@@ -2583,14 +2662,14 @@ special_insn:
emulate_2op_SrcV("or", c->src, c->dst, ctxt->eflags);
break;
case 0x0e: /* push cs */
- emulate_push_sreg(ctxt, VCPU_SREG_CS);
+ emulate_push_sreg(ctxt, ops, VCPU_SREG_CS);
break;
case 0x10 ... 0x15:
adc: /* adc */
emulate_2op_SrcV("adc", c->src, c->dst, ctxt->eflags);
break;
case 0x16: /* push ss */
- emulate_push_sreg(ctxt, VCPU_SREG_SS);
+ emulate_push_sreg(ctxt, ops, VCPU_SREG_SS);
break;
case 0x17: /* pop ss */
rc = emulate_pop_sreg(ctxt, ops, VCPU_SREG_SS);
@@ -2602,7 +2681,7 @@ special_insn:
emulate_2op_SrcV("sbb", c->src, c->dst, ctxt->eflags);
break;
case 0x1e: /* push ds */
- emulate_push_sreg(ctxt, VCPU_SREG_DS);
+ emulate_push_sreg(ctxt, ops, VCPU_SREG_DS);
break;
case 0x1f: /* pop ds */
rc = emulate_pop_sreg(ctxt, ops, VCPU_SREG_DS);
@@ -2632,7 +2711,7 @@ special_insn:
emulate_1op("dec", c->dst, ctxt->eflags);
break;
case 0x50 ... 0x57: /* push reg */
- emulate_push(ctxt);
+ emulate_push(ctxt, ops);
break;
case 0x58 ... 0x5f: /* pop reg */
pop_instruction:
@@ -2641,7 +2720,9 @@ special_insn:
goto done;
break;
case 0x60: /* pusha */
- emulate_pusha(ctxt);
+ rc = emulate_pusha(ctxt, ops);
+ if (rc != X86EMUL_CONTINUE)
+ goto done;
break;
case 0x61: /* popa */
rc = emulate_popa(ctxt, ops);
@@ -2655,14 +2736,14 @@ special_insn:
break;
case 0x68: /* push imm */
case 0x6a: /* push imm8 */
- emulate_push(ctxt);
+ emulate_push(ctxt, ops);
break;
case 0x6c: /* insb */
case 0x6d: /* insw/insd */
c->dst.bytes = min(c->dst.bytes, 4u);
if (!emulator_io_permited(ctxt, ops, c->regs[VCPU_REGS_RDX],
c->dst.bytes)) {
- kvm_inject_gp(ctxt->vcpu, 0);
+ emulate_gp(ctxt, 0);
goto done;
}
if (!pio_in_emulated(ctxt, ops, c->dst.bytes,
@@ -2674,7 +2755,7 @@ special_insn:
c->src.bytes = min(c->src.bytes, 4u);
if (!emulator_io_permited(ctxt, ops, c->regs[VCPU_REGS_RDX],
c->src.bytes)) {
- kvm_inject_gp(ctxt->vcpu, 0);
+ emulate_gp(ctxt, 0);
goto done;
}
ops->pio_out_emulated(c->src.bytes, c->regs[VCPU_REGS_RDX],
@@ -2707,6 +2788,7 @@ special_insn:
}
break;
case 0x84 ... 0x85:
+ test:
emulate_2op_SrcV("test", c->src, c->dst, ctxt->eflags);
break;
case 0x86 ... 0x87: /* xchg */
@@ -2735,18 +2817,13 @@ special_insn:
break;
case 0x88 ... 0x8b: /* mov */
goto mov;
- case 0x8c: { /* mov r/m, sreg */
- struct kvm_segment segreg;
-
- if (c->modrm_reg <= VCPU_SREG_GS)
- kvm_get_segment(ctxt->vcpu, &segreg, c->modrm_reg);
- else {
- kvm_queue_exception(ctxt->vcpu, UD_VECTOR);
+ case 0x8c: /* mov r/m, sreg */
+ if (c->modrm_reg > VCPU_SREG_GS) {
+ emulate_ud(ctxt);
goto done;
}
- c->dst.val = segreg.selector;
+ c->dst.val = ops->get_segment_selector(c->modrm_reg, ctxt->vcpu);
break;
- }
case 0x8d: /* lea r16/r32, m */
c->dst.val = c->modrm_ea;
break;
@@ -2757,12 +2834,12 @@ special_insn:
if (c->modrm_reg == VCPU_SREG_CS ||
c->modrm_reg > VCPU_SREG_GS) {
- kvm_queue_exception(ctxt->vcpu, UD_VECTOR);
+ emulate_ud(ctxt);
goto done;
}
if (c->modrm_reg == VCPU_SREG_SS)
- toggle_interruptibility(ctxt, KVM_X86_SHADOW_INT_MOV_SS);
+ ctxt->interruptibility = KVM_X86_SHADOW_INT_MOV_SS;
rc = load_segment_descriptor(ctxt, ops, sel, c->modrm_reg);
@@ -2775,19 +2852,19 @@ special_insn:
goto done;
break;
case 0x90: /* nop / xchg r8,rax */
- if (!(c->rex_prefix & 1)) { /* nop */
- c->dst.type = OP_NONE;
+ if (c->dst.ptr == (unsigned long *)&c->regs[VCPU_REGS_RAX]) {
+ c->dst.type = OP_NONE; /* nop */
break;
}
case 0x91 ... 0x97: /* xchg reg,rax */
- c->src.type = c->dst.type = OP_REG;
- c->src.bytes = c->dst.bytes = c->op_bytes;
+ c->src.type = OP_REG;
+ c->src.bytes = c->op_bytes;
c->src.ptr = (unsigned long *) &c->regs[VCPU_REGS_RAX];
c->src.val = *(c->src.ptr);
goto xchg;
case 0x9c: /* pushf */
c->src.val = (unsigned long) ctxt->eflags;
- emulate_push(ctxt);
+ emulate_push(ctxt, ops);
break;
case 0x9d: /* popf */
c->dst.type = OP_REG;
@@ -2797,19 +2874,15 @@ special_insn:
if (rc != X86EMUL_CONTINUE)
goto done;
break;
- case 0xa0 ... 0xa1: /* mov */
- c->dst.ptr = (unsigned long *)&c->regs[VCPU_REGS_RAX];
- c->dst.val = c->src.val;
- break;
- case 0xa2 ... 0xa3: /* mov */
- c->dst.val = (unsigned long)c->regs[VCPU_REGS_RAX];
- break;
+ case 0xa0 ... 0xa3: /* mov */
case 0xa4 ... 0xa5: /* movs */
goto mov;
case 0xa6 ... 0xa7: /* cmps */
c->dst.type = OP_NONE; /* Disable writeback. */
DPRINTF("cmps: mem1=0x%p mem2=0x%p\n", c->src.ptr, c->dst.ptr);
goto cmp;
+ case 0xa8 ... 0xa9: /* test ax, imm */
+ goto test;
case 0xaa ... 0xab: /* stos */
c->dst.val = c->regs[VCPU_REGS_RAX];
break;
@@ -2855,19 +2928,23 @@ special_insn:
long int rel = c->src.val;
c->src.val = (unsigned long) c->eip;
jmp_rel(c, rel);
- emulate_push(ctxt);
+ emulate_push(ctxt, ops);
break;
}
case 0xe9: /* jmp rel */
goto jmp;
- case 0xea: /* jmp far */
+ case 0xea: { /* jmp far */
+ unsigned short sel;
jump_far:
- if (load_segment_descriptor(ctxt, ops, c->src2.val,
- VCPU_SREG_CS))
+ memcpy(&sel, c->src.valptr + c->op_bytes, 2);
+
+ if (load_segment_descriptor(ctxt, ops, sel, VCPU_SREG_CS))
goto done;
- c->eip = c->src.val;
+ c->eip = 0;
+ memcpy(&c->eip, c->src.valptr, c->op_bytes);
break;
+ }
case 0xeb:
jmp: /* jmp rel short */
jmp_rel(c, c->src.val);
@@ -2879,20 +2956,20 @@ special_insn:
do_io_in:
c->dst.bytes = min(c->dst.bytes, 4u);
if (!emulator_io_permited(ctxt, ops, c->src.val, c->dst.bytes)) {
- kvm_inject_gp(ctxt->vcpu, 0);
+ emulate_gp(ctxt, 0);
goto done;
}
if (!pio_in_emulated(ctxt, ops, c->dst.bytes, c->src.val,
&c->dst.val))
goto done; /* IO is needed */
break;
- case 0xee: /* out al,dx */
- case 0xef: /* out (e/r)ax,dx */
+ case 0xee: /* out dx,al */
+ case 0xef: /* out dx,(e/r)ax */
c->src.val = c->regs[VCPU_REGS_RDX];
do_io_out:
c->dst.bytes = min(c->dst.bytes, 4u);
if (!emulator_io_permited(ctxt, ops, c->src.val, c->dst.bytes)) {
- kvm_inject_gp(ctxt->vcpu, 0);
+ emulate_gp(ctxt, 0);
goto done;
}
ops->pio_out_emulated(c->dst.bytes, c->src.val, &c->dst.val, 1,
@@ -2916,18 +2993,20 @@ special_insn:
c->dst.type = OP_NONE; /* Disable writeback. */
break;
case 0xfa: /* cli */
- if (emulator_bad_iopl(ctxt, ops))
- kvm_inject_gp(ctxt->vcpu, 0);
- else {
+ if (emulator_bad_iopl(ctxt, ops)) {
+ emulate_gp(ctxt, 0);
+ goto done;
+ } else {
ctxt->eflags &= ~X86_EFLAGS_IF;
c->dst.type = OP_NONE; /* Disable writeback. */
}
break;
case 0xfb: /* sti */
- if (emulator_bad_iopl(ctxt, ops))
- kvm_inject_gp(ctxt->vcpu, 0);
- else {
- toggle_interruptibility(ctxt, KVM_X86_SHADOW_INT_STI);
+ if (emulator_bad_iopl(ctxt, ops)) {
+ emulate_gp(ctxt, 0);
+ goto done;
+ } else {
+ ctxt->interruptibility = KVM_X86_SHADOW_INT_STI;
ctxt->eflags |= X86_EFLAGS_IF;
c->dst.type = OP_NONE; /* Disable writeback. */
}
@@ -2964,11 +3043,12 @@ writeback:
c->dst.type = saved_dst_type;
if ((c->d & SrcMask) == SrcSI)
- string_addr_inc(ctxt, seg_override_base(ctxt, c), VCPU_REGS_RSI,
- &c->src);
+ string_addr_inc(ctxt, seg_override_base(ctxt, ops, c),
+ VCPU_REGS_RSI, &c->src);
if ((c->d & DstMask) == DstDI)
- string_addr_inc(ctxt, es_base(ctxt), VCPU_REGS_RDI, &c->dst);
+ string_addr_inc(ctxt, es_base(ctxt, ops), VCPU_REGS_RDI,
+ &c->dst);
if (c->rep_prefix && (c->d & String)) {
struct read_cache *rc = &ctxt->decode.io_read;
@@ -2981,11 +3061,12 @@ writeback:
(rc->end != 0 && rc->end == rc->pos))
ctxt->restart = false;
}
-
- /* Commit shadow register state. */
- memcpy(ctxt->vcpu->arch.regs, c->regs, sizeof c->regs);
- kvm_rip_write(ctxt->vcpu, c->eip);
- ops->set_rflags(ctxt->vcpu, ctxt->eflags);
+ /*
+ * reset read cache here in case string instruction is restared
+ * without decoding
+ */
+ ctxt->decode.mem_read.end = 0;
+ ctxt->eip = c->eip;
done:
return (rc == X86EMUL_UNHANDLEABLE) ? -1 : 0;
@@ -3051,7 +3132,7 @@ twobyte_insn:
c->dst.type = OP_NONE;
break;
case 5: /* not defined */
- kvm_queue_exception(ctxt->vcpu, UD_VECTOR);
+ emulate_ud(ctxt);
goto done;
case 7: /* invlpg*/
emulate_invlpg(ctxt->vcpu, c->modrm_ea);
@@ -3063,7 +3144,7 @@ twobyte_insn:
}
break;
case 0x05: /* syscall */
- rc = emulate_syscall(ctxt);
+ rc = emulate_syscall(ctxt, ops);
if (rc != X86EMUL_CONTINUE)
goto done;
else
@@ -3073,8 +3154,11 @@ twobyte_insn:
emulate_clts(ctxt->vcpu);
c->dst.type = OP_NONE;
break;
- case 0x08: /* invd */
case 0x09: /* wbinvd */
+ kvm_emulate_wbinvd(ctxt->vcpu);
+ c->dst.type = OP_NONE;
+ break;
+ case 0x08: /* invd */
case 0x0d: /* GrpP (prefetch) */
case 0x18: /* Grp16 (prefetch/nop) */
c->dst.type = OP_NONE;
@@ -3084,7 +3168,7 @@ twobyte_insn:
case 1:
case 5 ... 7:
case 9 ... 15:
- kvm_queue_exception(ctxt->vcpu, UD_VECTOR);
+ emulate_ud(ctxt);
goto done;
}
c->regs[c->modrm_rm] = ops->get_cr(c->modrm_reg, ctxt->vcpu);
@@ -3093,31 +3177,42 @@ twobyte_insn:
case 0x21: /* mov from dr to reg */
if ((ops->get_cr(4, ctxt->vcpu) & X86_CR4_DE) &&
(c->modrm_reg == 4 || c->modrm_reg == 5)) {
- kvm_queue_exception(ctxt->vcpu, UD_VECTOR);
+ emulate_ud(ctxt);
goto done;
}
- emulator_get_dr(ctxt, c->modrm_reg, &c->regs[c->modrm_rm]);
+ ops->get_dr(c->modrm_reg, &c->regs[c->modrm_rm], ctxt->vcpu);
c->dst.type = OP_NONE; /* no writeback */
break;
case 0x22: /* mov reg, cr */
- ops->set_cr(c->modrm_reg, c->modrm_val, ctxt->vcpu);
+ if (ops->set_cr(c->modrm_reg, c->modrm_val, ctxt->vcpu)) {
+ emulate_gp(ctxt, 0);
+ goto done;
+ }
c->dst.type = OP_NONE;
break;
case 0x23: /* mov from reg to dr */
if ((ops->get_cr(4, ctxt->vcpu) & X86_CR4_DE) &&
(c->modrm_reg == 4 || c->modrm_reg == 5)) {
- kvm_queue_exception(ctxt->vcpu, UD_VECTOR);
+ emulate_ud(ctxt);
+ goto done;
+ }
+
+ if (ops->set_dr(c->modrm_reg, c->regs[c->modrm_rm] &
+ ((ctxt->mode == X86EMUL_MODE_PROT64) ?
+ ~0ULL : ~0U), ctxt->vcpu) < 0) {
+ /* #UD condition is already handled by the code above */
+ emulate_gp(ctxt, 0);
goto done;
}
- emulator_set_dr(ctxt, c->modrm_reg, c->regs[c->modrm_rm]);
+
c->dst.type = OP_NONE; /* no writeback */
break;
case 0x30:
/* wrmsr */
msr_data = (u32)c->regs[VCPU_REGS_RAX]
| ((u64)c->regs[VCPU_REGS_RDX] << 32);
- if (kvm_set_msr(ctxt->vcpu, c->regs[VCPU_REGS_RCX], msr_data)) {
- kvm_inject_gp(ctxt->vcpu, 0);
+ if (ops->set_msr(ctxt->vcpu, c->regs[VCPU_REGS_RCX], msr_data)) {
+ emulate_gp(ctxt, 0);
goto done;
}
rc = X86EMUL_CONTINUE;
@@ -3125,8 +3220,8 @@ twobyte_insn:
break;
case 0x32:
/* rdmsr */
- if (kvm_get_msr(ctxt->vcpu, c->regs[VCPU_REGS_RCX], &msr_data)) {
- kvm_inject_gp(ctxt->vcpu, 0);
+ if (ops->get_msr(ctxt->vcpu, c->regs[VCPU_REGS_RCX], &msr_data)) {
+ emulate_gp(ctxt, 0);
goto done;
} else {
c->regs[VCPU_REGS_RAX] = (u32)msr_data;
@@ -3136,14 +3231,14 @@ twobyte_insn:
c->dst.type = OP_NONE;
break;
case 0x34: /* sysenter */
- rc = emulate_sysenter(ctxt);
+ rc = emulate_sysenter(ctxt, ops);
if (rc != X86EMUL_CONTINUE)
goto done;
else
goto writeback;
break;
case 0x35: /* sysexit */
- rc = emulate_sysexit(ctxt);
+ rc = emulate_sysexit(ctxt, ops);
if (rc != X86EMUL_CONTINUE)
goto done;
else
@@ -3160,7 +3255,7 @@ twobyte_insn:
c->dst.type = OP_NONE;
break;
case 0xa0: /* push fs */
- emulate_push_sreg(ctxt, VCPU_SREG_FS);
+ emulate_push_sreg(ctxt, ops, VCPU_SREG_FS);
break;
case 0xa1: /* pop fs */
rc = emulate_pop_sreg(ctxt, ops, VCPU_SREG_FS);
@@ -3179,7 +3274,7 @@ twobyte_insn:
emulate_2op_cl("shld", c->src2, c->src, c->dst, ctxt->eflags);
break;
case 0xa8: /* push gs */
- emulate_push_sreg(ctxt, VCPU_SREG_GS);
+ emulate_push_sreg(ctxt, ops, VCPU_SREG_GS);
break;
case 0xa9: /* pop gs */
rc = emulate_pop_sreg(ctxt, ops, VCPU_SREG_GS);
diff --git a/arch/x86/kvm/i8254.c b/arch/x86/kvm/i8254.c
index 0150affad25..0fd6378981f 100644
--- a/arch/x86/kvm/i8254.c
+++ b/arch/x86/kvm/i8254.c
@@ -5,6 +5,7 @@
* Copyright (c) 2006 Intel Corporation
* Copyright (c) 2007 Keir Fraser, XenSource Inc
* Copyright (c) 2008 Intel Corporation
+ * Copyright 2009 Red Hat, Inc. and/or its affilates.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -33,6 +34,7 @@
#include <linux/kvm_host.h>
#include <linux/slab.h>
+#include <linux/workqueue.h>
#include "irq.h"
#include "i8254.h"
@@ -243,11 +245,22 @@ static void kvm_pit_ack_irq(struct kvm_irq_ack_notifier *kian)
{
struct kvm_kpit_state *ps = container_of(kian, struct kvm_kpit_state,
irq_ack_notifier);
- raw_spin_lock(&ps->inject_lock);
- if (atomic_dec_return(&ps->pit_timer.pending) < 0)
+ int value;
+
+ spin_lock(&ps->inject_lock);
+ value = atomic_dec_return(&ps->pit_timer.pending);
+ if (value < 0)
+ /* spurious acks can be generated if, for example, the
+ * PIC is being reset. Handle it gracefully here
+ */
atomic_inc(&ps->pit_timer.pending);
+ else if (value > 0)
+ /* in this case, we had multiple outstanding pit interrupts
+ * that we needed to inject. Reinject
+ */
+ queue_work(ps->pit->wq, &ps->pit->expired);
ps->irq_ack = 1;
- raw_spin_unlock(&ps->inject_lock);
+ spin_unlock(&ps->inject_lock);
}
void __kvm_migrate_pit_timer(struct kvm_vcpu *vcpu)
@@ -263,10 +276,10 @@ void __kvm_migrate_pit_timer(struct kvm_vcpu *vcpu)
hrtimer_start_expires(timer, HRTIMER_MODE_ABS);
}
-static void destroy_pit_timer(struct kvm_timer *pt)
+static void destroy_pit_timer(struct kvm_pit *pit)
{
- pr_debug("execute del timer!\n");
- hrtimer_cancel(&pt->timer);
+ hrtimer_cancel(&pit->pit_state.pit_timer.timer);
+ cancel_work_sync(&pit->expired);
}
static bool kpit_is_periodic(struct kvm_timer *ktimer)
@@ -280,6 +293,60 @@ static struct kvm_timer_ops kpit_ops = {
.is_periodic = kpit_is_periodic,
};
+static void pit_do_work(struct work_struct *work)
+{
+ struct kvm_pit *pit = container_of(work, struct kvm_pit, expired);
+ struct kvm *kvm = pit->kvm;
+ struct kvm_vcpu *vcpu;
+ int i;
+ struct kvm_kpit_state *ps = &pit->pit_state;
+ int inject = 0;
+
+ /* Try to inject pending interrupts when
+ * last one has been acked.
+ */
+ spin_lock(&ps->inject_lock);
+ if (ps->irq_ack) {
+ ps->irq_ack = 0;
+ inject = 1;
+ }
+ spin_unlock(&ps->inject_lock);
+ if (inject) {
+ kvm_set_irq(kvm, kvm->arch.vpit->irq_source_id, 0, 1);
+ kvm_set_irq(kvm, kvm->arch.vpit->irq_source_id, 0, 0);
+
+ /*
+ * Provides NMI watchdog support via Virtual Wire mode.
+ * The route is: PIT -> PIC -> LVT0 in NMI mode.
+ *
+ * Note: Our Virtual Wire implementation is simplified, only
+ * propagating PIT interrupts to all VCPUs when they have set
+ * LVT0 to NMI delivery. Other PIC interrupts are just sent to
+ * VCPU0, and only if its LVT0 is in EXTINT mode.
+ */
+ if (kvm->arch.vapics_in_nmi_mode > 0)
+ kvm_for_each_vcpu(i, vcpu, kvm)
+ kvm_apic_nmi_wd_deliver(vcpu);
+ }
+}
+
+static enum hrtimer_restart pit_timer_fn(struct hrtimer *data)
+{
+ struct kvm_timer *ktimer = container_of(data, struct kvm_timer, timer);
+ struct kvm_pit *pt = ktimer->kvm->arch.vpit;
+
+ if (ktimer->reinject || !atomic_read(&ktimer->pending)) {
+ atomic_inc(&ktimer->pending);
+ queue_work(pt->wq, &pt->expired);
+ }
+
+ if (ktimer->t_ops->is_periodic(ktimer)) {
+ hrtimer_add_expires_ns(&ktimer->timer, ktimer->period);
+ return HRTIMER_RESTART;
+ } else
+ return HRTIMER_NORESTART;
+}
+
static void create_pit_timer(struct kvm_kpit_state *ps, u32 val, int is_period)
{
struct kvm_timer *pt = &ps->pit_timer;
@@ -291,13 +358,13 @@ static void create_pit_timer(struct kvm_kpit_state *ps, u32 val, int is_period)
/* TODO The new value only affected after the retriggered */
hrtimer_cancel(&pt->timer);
+ cancel_work_sync(&ps->pit->expired);
pt->period = interval;
ps->is_periodic = is_period;
- pt->timer.function = kvm_timer_fn;
+ pt->timer.function = pit_timer_fn;
pt->t_ops = &kpit_ops;
pt->kvm = ps->pit->kvm;
- pt->vcpu = pt->kvm->bsp_vcpu;
atomic_set(&pt->pending, 0);
ps->irq_ack = 1;
@@ -346,7 +413,7 @@ static void pit_load_count(struct kvm *kvm, int channel, u32 val)
}
break;
default:
- destroy_pit_timer(&ps->pit_timer);
+ destroy_pit_timer(kvm->arch.vpit);
}
}
@@ -625,7 +692,15 @@ struct kvm_pit *kvm_create_pit(struct kvm *kvm, u32 flags)
mutex_init(&pit->pit_state.lock);
mutex_lock(&pit->pit_state.lock);
- raw_spin_lock_init(&pit->pit_state.inject_lock);
+ spin_lock_init(&pit->pit_state.inject_lock);
+
+ pit->wq = create_singlethread_workqueue("kvm-pit-wq");
+ if (!pit->wq) {
+ mutex_unlock(&pit->pit_state.lock);
+ kfree(pit);
+ return NULL;
+ }
+ INIT_WORK(&pit->expired, pit_do_work);
kvm->arch.vpit = pit;
pit->kvm = kvm;
@@ -677,6 +752,9 @@ void kvm_free_pit(struct kvm *kvm)
struct hrtimer *timer;
if (kvm->arch.vpit) {
+ kvm_io_bus_unregister_dev(kvm, KVM_PIO_BUS, &kvm->arch.vpit->dev);
+ kvm_io_bus_unregister_dev(kvm, KVM_PIO_BUS,
+ &kvm->arch.vpit->speaker_dev);
kvm_unregister_irq_mask_notifier(kvm, 0,
&kvm->arch.vpit->mask_notifier);
kvm_unregister_irq_ack_notifier(kvm,
@@ -684,54 +762,10 @@ void kvm_free_pit(struct kvm *kvm)
mutex_lock(&kvm->arch.vpit->pit_state.lock);
timer = &kvm->arch.vpit->pit_state.pit_timer.timer;
hrtimer_cancel(timer);
+ cancel_work_sync(&kvm->arch.vpit->expired);
kvm_free_irq_source_id(kvm, kvm->arch.vpit->irq_source_id);
mutex_unlock(&kvm->arch.vpit->pit_state.lock);
+ destroy_workqueue(kvm->arch.vpit->wq);
kfree(kvm->arch.vpit);
}
}
-
-static void __inject_pit_timer_intr(struct kvm *kvm)
-{
- struct kvm_vcpu *vcpu;
- int i;
-
- kvm_set_irq(kvm, kvm->arch.vpit->irq_source_id, 0, 1);
- kvm_set_irq(kvm, kvm->arch.vpit->irq_source_id, 0, 0);
-
- /*
- * Provides NMI watchdog support via Virtual Wire mode.
- * The route is: PIT -> PIC -> LVT0 in NMI mode.
- *
- * Note: Our Virtual Wire implementation is simplified, only
- * propagating PIT interrupts to all VCPUs when they have set
- * LVT0 to NMI delivery. Other PIC interrupts are just sent to
- * VCPU0, and only if its LVT0 is in EXTINT mode.
- */
- if (kvm->arch.vapics_in_nmi_mode > 0)
- kvm_for_each_vcpu(i, vcpu, kvm)
- kvm_apic_nmi_wd_deliver(vcpu);
-}
-
-void kvm_inject_pit_timer_irqs(struct kvm_vcpu *vcpu)
-{
- struct kvm_pit *pit = vcpu->kvm->arch.vpit;
- struct kvm *kvm = vcpu->kvm;
- struct kvm_kpit_state *ps;
-
- if (pit) {
- int inject = 0;
- ps = &pit->pit_state;
-
- /* Try to inject pending interrupts when
- * last one has been acked.
- */
- raw_spin_lock(&ps->inject_lock);
- if (atomic_read(&ps->pit_timer.pending) && ps->irq_ack) {
- ps->irq_ack = 0;
- inject = 1;
- }
- raw_spin_unlock(&ps->inject_lock);
- if (inject)
- __inject_pit_timer_intr(kvm);
- }
-}
diff --git a/arch/x86/kvm/i8254.h b/arch/x86/kvm/i8254.h
index 900d6b0ba7c..46d08ca0b48 100644
--- a/arch/x86/kvm/i8254.h
+++ b/arch/x86/kvm/i8254.h
@@ -27,7 +27,7 @@ struct kvm_kpit_state {
u32 speaker_data_on;
struct mutex lock;
struct kvm_pit *pit;
- raw_spinlock_t inject_lock;
+ spinlock_t inject_lock;
unsigned long irq_ack;
struct kvm_irq_ack_notifier irq_ack_notifier;
};
@@ -40,6 +40,8 @@ struct kvm_pit {
struct kvm_kpit_state pit_state;
int irq_source_id;
struct kvm_irq_mask_notifier mask_notifier;
+ struct workqueue_struct *wq;
+ struct work_struct expired;
};
#define KVM_PIT_BASE_ADDRESS 0x40
diff --git a/arch/x86/kvm/i8259.c b/arch/x86/kvm/i8259.c
index 93825ff3338..8d10c063d7f 100644
--- a/arch/x86/kvm/i8259.c
+++ b/arch/x86/kvm/i8259.c
@@ -3,6 +3,7 @@
*
* Copyright (c) 2003-2004 Fabrice Bellard
* Copyright (c) 2007 Intel Corporation
+ * Copyright 2009 Red Hat, Inc. and/or its affilates.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -33,6 +34,8 @@
#include <linux/kvm_host.h>
#include "trace.h"
+static void pic_irq_request(struct kvm *kvm, int level);
+
static void pic_lock(struct kvm_pic *s)
__acquires(&s->lock)
{
@@ -43,16 +46,25 @@ static void pic_unlock(struct kvm_pic *s)
__releases(&s->lock)
{
bool wakeup = s->wakeup_needed;
- struct kvm_vcpu *vcpu;
+ struct kvm_vcpu *vcpu, *found = NULL;
+ int i;
s->wakeup_needed = false;
raw_spin_unlock(&s->lock);
if (wakeup) {
- vcpu = s->kvm->bsp_vcpu;
- if (vcpu)
- kvm_vcpu_kick(vcpu);
+ kvm_for_each_vcpu(i, vcpu, s->kvm) {
+ if (kvm_apic_accept_pic_intr(vcpu)) {
+ found = vcpu;
+ break;
+ }
+ }
+
+ if (!found)
+ found = s->kvm->bsp_vcpu;
+
+ kvm_vcpu_kick(found);
}
}
@@ -173,10 +185,7 @@ static void pic_update_irq(struct kvm_pic *s)
pic_set_irq1(&s->pics[0], 2, 0);
}
irq = pic_get_irq(&s->pics[0]);
- if (irq >= 0)
- s->irq_request(s->irq_request_opaque, 1);
- else
- s->irq_request(s->irq_request_opaque, 0);
+ pic_irq_request(s->kvm, irq >= 0);
}
void kvm_pic_update_irq(struct kvm_pic *s)
@@ -261,8 +270,7 @@ int kvm_pic_read_irq(struct kvm *kvm)
void kvm_pic_reset(struct kvm_kpic_state *s)
{
int irq;
- struct kvm *kvm = s->pics_state->irq_request_opaque;
- struct kvm_vcpu *vcpu0 = kvm->bsp_vcpu;
+ struct kvm_vcpu *vcpu0 = s->pics_state->kvm->bsp_vcpu;
u8 irr = s->irr, isr = s->imr;
s->last_irr = 0;
@@ -301,8 +309,7 @@ static void pic_ioport_write(void *opaque, u32 addr, u32 val)
/*
* deassert a pending interrupt
*/
- s->pics_state->irq_request(s->pics_state->
- irq_request_opaque, 0);
+ pic_irq_request(s->pics_state->kvm, 0);
s->init_state = 1;
s->init4 = val & 1;
if (val & 0x02)
@@ -356,10 +363,20 @@ static void pic_ioport_write(void *opaque, u32 addr, u32 val)
}
} else
switch (s->init_state) {
- case 0: /* normal mode */
+ case 0: { /* normal mode */
+ u8 imr_diff = s->imr ^ val,
+ off = (s == &s->pics_state->pics[0]) ? 0 : 8;
s->imr = val;
+ for (irq = 0; irq < PIC_NUM_PINS/2; irq++)
+ if (imr_diff & (1 << irq))
+ kvm_fire_mask_notifiers(
+ s->pics_state->kvm,
+ SELECT_PIC(irq + off),
+ irq + off,
+ !!(s->imr & (1 << irq)));
pic_update_irq(s->pics_state);
break;
+ }
case 1:
s->irq_base = val & 0xf8;
s->init_state = 2;
@@ -518,9 +535,8 @@ static int picdev_read(struct kvm_io_device *this,
/*
* callback when PIC0 irq status changed
*/
-static void pic_irq_request(void *opaque, int level)
+static void pic_irq_request(struct kvm *kvm, int level)
{
- struct kvm *kvm = opaque;
struct kvm_vcpu *vcpu = kvm->bsp_vcpu;
struct kvm_pic *s = pic_irqchip(kvm);
int irq = pic_get_irq(&s->pics[0]);
@@ -549,8 +565,6 @@ struct kvm_pic *kvm_create_pic(struct kvm *kvm)
s->kvm = kvm;
s->pics[0].elcr_mask = 0xf8;
s->pics[1].elcr_mask = 0xde;
- s->irq_request = pic_irq_request;
- s->irq_request_opaque = kvm;
s->pics[0].pics_state = s;
s->pics[1].pics_state = s;
diff --git a/arch/x86/kvm/irq.c b/arch/x86/kvm/irq.c
index 96dfbb6ad2a..2095a049835 100644
--- a/arch/x86/kvm/irq.c
+++ b/arch/x86/kvm/irq.c
@@ -1,6 +1,7 @@
/*
* irq.c: API for in kernel interrupt controller
* Copyright (c) 2007, Intel Corporation.
+ * Copyright 2009 Red Hat, Inc. and/or its affilates.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
@@ -89,7 +90,6 @@ EXPORT_SYMBOL_GPL(kvm_cpu_get_interrupt);
void kvm_inject_pending_timer_irqs(struct kvm_vcpu *vcpu)
{
kvm_inject_apic_timer_irqs(vcpu);
- kvm_inject_pit_timer_irqs(vcpu);
/* TODO: PIT, RTC etc. */
}
EXPORT_SYMBOL_GPL(kvm_inject_pending_timer_irqs);
diff --git a/arch/x86/kvm/irq.h b/arch/x86/kvm/irq.h
index cd1f362f413..ffed06871c5 100644
--- a/arch/x86/kvm/irq.h
+++ b/arch/x86/kvm/irq.h
@@ -38,8 +38,6 @@
struct kvm;
struct kvm_vcpu;
-typedef void irq_request_func(void *opaque, int level);
-
struct kvm_kpic_state {
u8 last_irr; /* edge detection */
u8 irr; /* interrupt request register */
@@ -67,8 +65,6 @@ struct kvm_pic {
unsigned pending_acks;
struct kvm *kvm;
struct kvm_kpic_state pics[2]; /* 0 is master pic, 1 is slave pic */
- irq_request_func *irq_request;
- void *irq_request_opaque;
int output; /* intr from master PIC */
struct kvm_io_device dev;
void (*ack_notifier)(void *opaque, int irq);
diff --git a/arch/x86/kvm/kvm_cache_regs.h b/arch/x86/kvm/kvm_cache_regs.h
index cff851cf532..6491ac8e755 100644
--- a/arch/x86/kvm/kvm_cache_regs.h
+++ b/arch/x86/kvm/kvm_cache_regs.h
@@ -36,6 +36,8 @@ static inline void kvm_rip_write(struct kvm_vcpu *vcpu, unsigned long val)
static inline u64 kvm_pdptr_read(struct kvm_vcpu *vcpu, int index)
{
+ might_sleep(); /* on svm */
+
if (!test_bit(VCPU_EXREG_PDPTR,
(unsigned long *)&vcpu->arch.regs_avail))
kvm_x86_ops->cache_reg(vcpu, VCPU_EXREG_PDPTR);
@@ -69,4 +71,10 @@ static inline ulong kvm_read_cr4(struct kvm_vcpu *vcpu)
return kvm_read_cr4_bits(vcpu, ~0UL);
}
+static inline u64 kvm_read_edx_eax(struct kvm_vcpu *vcpu)
+{
+ return (kvm_register_read(vcpu, VCPU_REGS_RAX) & -1u)
+ | ((u64)(kvm_register_read(vcpu, VCPU_REGS_RDX) & -1u) << 32);
+}
+
#endif
diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c
index 1eb7a4ae0c9..77d8c0f4817 100644
--- a/arch/x86/kvm/lapic.c
+++ b/arch/x86/kvm/lapic.c
@@ -5,6 +5,7 @@
* Copyright (C) 2006 Qumranet, Inc.
* Copyright (C) 2007 Novell
* Copyright (C) 2007 Intel
+ * Copyright 2009 Red Hat, Inc. and/or its affilates.
*
* Authors:
* Dor Laor <dor.laor@qumranet.com>
@@ -328,7 +329,7 @@ int kvm_apic_match_dest(struct kvm_vcpu *vcpu, struct kvm_lapic *source,
"dest_mode 0x%x, short_hand 0x%x\n",
target, source, dest, dest_mode, short_hand);
- ASSERT(!target);
+ ASSERT(target);
switch (short_hand) {
case APIC_DEST_NOSHORT:
if (dest_mode == 0)
@@ -533,7 +534,7 @@ static void __report_tpr_access(struct kvm_lapic *apic, bool write)
struct kvm_vcpu *vcpu = apic->vcpu;
struct kvm_run *run = vcpu->run;
- set_bit(KVM_REQ_REPORT_TPR_ACCESS, &vcpu->requests);
+ kvm_make_request(KVM_REQ_REPORT_TPR_ACCESS, vcpu);
run->tpr_access.rip = kvm_rip_read(vcpu);
run->tpr_access.is_write = write;
}
@@ -1106,13 +1107,11 @@ int kvm_apic_accept_pic_intr(struct kvm_vcpu *vcpu)
u32 lvt0 = apic_get_reg(vcpu->arch.apic, APIC_LVT0);
int r = 0;
- if (kvm_vcpu_is_bsp(vcpu)) {
- if (!apic_hw_enabled(vcpu->arch.apic))
- r = 1;
- if ((lvt0 & APIC_LVT_MASKED) == 0 &&
- GET_APIC_DELIVERY_MODE(lvt0) == APIC_MODE_EXTINT)
- r = 1;
- }
+ if (!apic_hw_enabled(vcpu->arch.apic))
+ r = 1;
+ if ((lvt0 & APIC_LVT_MASKED) == 0 &&
+ GET_APIC_DELIVERY_MODE(lvt0) == APIC_MODE_EXTINT)
+ r = 1;
return r;
}
diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c
index b1ed0a1a591..311f6dad895 100644
--- a/arch/x86/kvm/mmu.c
+++ b/arch/x86/kvm/mmu.c
@@ -7,6 +7,7 @@
* MMU support
*
* Copyright (C) 2006 Qumranet, Inc.
+ * Copyright 2010 Red Hat, Inc. and/or its affilates.
*
* Authors:
* Yaniv Kamay <yaniv@qumranet.com>
@@ -32,6 +33,7 @@
#include <linux/compiler.h>
#include <linux/srcu.h>
#include <linux/slab.h>
+#include <linux/uaccess.h>
#include <asm/page.h>
#include <asm/cmpxchg.h>
@@ -90,8 +92,6 @@ module_param(oos_shadow, bool, 0644);
#define PT_FIRST_AVAIL_BITS_SHIFT 9
#define PT64_SECOND_AVAIL_BITS_SHIFT 52
-#define VALID_PAGE(x) ((x) != INVALID_PAGE)
-
#define PT64_LEVEL_BITS 9
#define PT64_LEVEL_SHIFT(level) \
@@ -173,7 +173,7 @@ struct kvm_shadow_walk_iterator {
shadow_walk_okay(&(_walker)); \
shadow_walk_next(&(_walker)))
-typedef int (*mmu_parent_walk_fn) (struct kvm_mmu_page *sp);
+typedef void (*mmu_parent_walk_fn) (struct kvm_mmu_page *sp, u64 *spte);
static struct kmem_cache *pte_chain_cache;
static struct kmem_cache *rmap_desc_cache;
@@ -281,13 +281,38 @@ static gfn_t pse36_gfn_delta(u32 gpte)
static void __set_spte(u64 *sptep, u64 spte)
{
+ set_64bit(sptep, spte);
+}
+
+static u64 __xchg_spte(u64 *sptep, u64 new_spte)
+{
#ifdef CONFIG_X86_64
- set_64bit((unsigned long *)sptep, spte);
+ return xchg(sptep, new_spte);
#else
- set_64bit((unsigned long long *)sptep, spte);
+ u64 old_spte;
+
+ do {
+ old_spte = *sptep;
+ } while (cmpxchg64(sptep, old_spte, new_spte) != old_spte);
+
+ return old_spte;
#endif
}
+static void update_spte(u64 *sptep, u64 new_spte)
+{
+ u64 old_spte;
+
+ if (!shadow_accessed_mask || (new_spte & shadow_accessed_mask) ||
+ !is_rmap_spte(*sptep))
+ __set_spte(sptep, new_spte);
+ else {
+ old_spte = __xchg_spte(sptep, new_spte);
+ if (old_spte & shadow_accessed_mask)
+ mark_page_accessed(pfn_to_page(spte_to_pfn(old_spte)));
+ }
+}
+
static int mmu_topup_memory_cache(struct kvm_mmu_memory_cache *cache,
struct kmem_cache *base_cache, int min)
{
@@ -304,10 +329,11 @@ static int mmu_topup_memory_cache(struct kvm_mmu_memory_cache *cache,
return 0;
}
-static void mmu_free_memory_cache(struct kvm_mmu_memory_cache *mc)
+static void mmu_free_memory_cache(struct kvm_mmu_memory_cache *mc,
+ struct kmem_cache *cache)
{
while (mc->nobjs)
- kfree(mc->objects[--mc->nobjs]);
+ kmem_cache_free(cache, mc->objects[--mc->nobjs]);
}
static int mmu_topup_memory_cache_page(struct kvm_mmu_memory_cache *cache,
@@ -355,10 +381,11 @@ out:
static void mmu_free_memory_caches(struct kvm_vcpu *vcpu)
{
- mmu_free_memory_cache(&vcpu->arch.mmu_pte_chain_cache);
- mmu_free_memory_cache(&vcpu->arch.mmu_rmap_desc_cache);
+ mmu_free_memory_cache(&vcpu->arch.mmu_pte_chain_cache, pte_chain_cache);
+ mmu_free_memory_cache(&vcpu->arch.mmu_rmap_desc_cache, rmap_desc_cache);
mmu_free_memory_cache_page(&vcpu->arch.mmu_page_cache);
- mmu_free_memory_cache(&vcpu->arch.mmu_page_header_cache);
+ mmu_free_memory_cache(&vcpu->arch.mmu_page_header_cache,
+ mmu_page_header_cache);
}
static void *mmu_memory_cache_alloc(struct kvm_mmu_memory_cache *mc,
@@ -379,7 +406,7 @@ static struct kvm_pte_chain *mmu_alloc_pte_chain(struct kvm_vcpu *vcpu)
static void mmu_free_pte_chain(struct kvm_pte_chain *pc)
{
- kfree(pc);
+ kmem_cache_free(pte_chain_cache, pc);
}
static struct kvm_rmap_desc *mmu_alloc_rmap_desc(struct kvm_vcpu *vcpu)
@@ -390,7 +417,23 @@ static struct kvm_rmap_desc *mmu_alloc_rmap_desc(struct kvm_vcpu *vcpu)
static void mmu_free_rmap_desc(struct kvm_rmap_desc *rd)
{
- kfree(rd);
+ kmem_cache_free(rmap_desc_cache, rd);
+}
+
+static gfn_t kvm_mmu_page_get_gfn(struct kvm_mmu_page *sp, int index)
+{
+ if (!sp->role.direct)
+ return sp->gfns[index];
+
+ return sp->gfn + (index << ((sp->role.level - 1) * PT64_LEVEL_BITS));
+}
+
+static void kvm_mmu_page_set_gfn(struct kvm_mmu_page *sp, int index, gfn_t gfn)
+{
+ if (sp->role.direct)
+ BUG_ON(gfn != kvm_mmu_page_get_gfn(sp, index));
+ else
+ sp->gfns[index] = gfn;
}
/*
@@ -403,8 +446,8 @@ static int *slot_largepage_idx(gfn_t gfn,
{
unsigned long idx;
- idx = (gfn / KVM_PAGES_PER_HPAGE(level)) -
- (slot->base_gfn / KVM_PAGES_PER_HPAGE(level));
+ idx = (gfn >> KVM_HPAGE_GFN_SHIFT(level)) -
+ (slot->base_gfn >> KVM_HPAGE_GFN_SHIFT(level));
return &slot->lpage_info[level - 2][idx].write_count;
}
@@ -414,9 +457,7 @@ static void account_shadowed(struct kvm *kvm, gfn_t gfn)
int *write_count;
int i;
- gfn = unalias_gfn(kvm, gfn);
-
- slot = gfn_to_memslot_unaliased(kvm, gfn);
+ slot = gfn_to_memslot(kvm, gfn);
for (i = PT_DIRECTORY_LEVEL;
i < PT_PAGE_TABLE_LEVEL + KVM_NR_PAGE_SIZES; ++i) {
write_count = slot_largepage_idx(gfn, slot, i);
@@ -430,8 +471,7 @@ static void unaccount_shadowed(struct kvm *kvm, gfn_t gfn)
int *write_count;
int i;
- gfn = unalias_gfn(kvm, gfn);
- slot = gfn_to_memslot_unaliased(kvm, gfn);
+ slot = gfn_to_memslot(kvm, gfn);
for (i = PT_DIRECTORY_LEVEL;
i < PT_PAGE_TABLE_LEVEL + KVM_NR_PAGE_SIZES; ++i) {
write_count = slot_largepage_idx(gfn, slot, i);
@@ -447,8 +487,7 @@ static int has_wrprotected_page(struct kvm *kvm,
struct kvm_memory_slot *slot;
int *largepage_idx;
- gfn = unalias_gfn(kvm, gfn);
- slot = gfn_to_memslot_unaliased(kvm, gfn);
+ slot = gfn_to_memslot(kvm, gfn);
if (slot) {
largepage_idx = slot_largepage_idx(gfn, slot, level);
return *largepage_idx;
@@ -501,7 +540,6 @@ static int mapping_level(struct kvm_vcpu *vcpu, gfn_t large_gfn)
/*
* Take gfn and return the reverse mapping to it.
- * Note: gfn must be unaliased before this function get called
*/
static unsigned long *gfn_to_rmap(struct kvm *kvm, gfn_t gfn, int level)
@@ -513,8 +551,8 @@ static unsigned long *gfn_to_rmap(struct kvm *kvm, gfn_t gfn, int level)
if (likely(level == PT_PAGE_TABLE_LEVEL))
return &slot->rmap[gfn - slot->base_gfn];
- idx = (gfn / KVM_PAGES_PER_HPAGE(level)) -
- (slot->base_gfn / KVM_PAGES_PER_HPAGE(level));
+ idx = (gfn >> KVM_HPAGE_GFN_SHIFT(level)) -
+ (slot->base_gfn >> KVM_HPAGE_GFN_SHIFT(level));
return &slot->lpage_info[level - 2][idx].rmap_pde;
}
@@ -541,9 +579,8 @@ static int rmap_add(struct kvm_vcpu *vcpu, u64 *spte, gfn_t gfn)
if (!is_rmap_spte(*spte))
return count;
- gfn = unalias_gfn(vcpu->kvm, gfn);
sp = page_header(__pa(spte));
- sp->gfns[spte - sp->spt] = gfn;
+ kvm_mmu_page_set_gfn(sp, spte - sp->spt, gfn);
rmapp = gfn_to_rmap(vcpu->kvm, gfn, sp->role.level);
if (!*rmapp) {
rmap_printk("rmap_add: %p %llx 0->1\n", spte, *spte);
@@ -600,19 +637,13 @@ static void rmap_remove(struct kvm *kvm, u64 *spte)
struct kvm_rmap_desc *desc;
struct kvm_rmap_desc *prev_desc;
struct kvm_mmu_page *sp;
- pfn_t pfn;
+ gfn_t gfn;
unsigned long *rmapp;
int i;
- if (!is_rmap_spte(*spte))
- return;
sp = page_header(__pa(spte));
- pfn = spte_to_pfn(*spte);
- if (*spte & shadow_accessed_mask)
- kvm_set_pfn_accessed(pfn);
- if (is_writable_pte(*spte))
- kvm_set_pfn_dirty(pfn);
- rmapp = gfn_to_rmap(kvm, sp->gfns[spte - sp->spt], sp->role.level);
+ gfn = kvm_mmu_page_get_gfn(sp, spte - sp->spt);
+ rmapp = gfn_to_rmap(kvm, gfn, sp->role.level);
if (!*rmapp) {
printk(KERN_ERR "rmap_remove: %p %llx 0->BUG\n", spte, *spte);
BUG();
@@ -644,6 +675,32 @@ static void rmap_remove(struct kvm *kvm, u64 *spte)
}
}
+static void set_spte_track_bits(u64 *sptep, u64 new_spte)
+{
+ pfn_t pfn;
+ u64 old_spte = *sptep;
+
+ if (!shadow_accessed_mask || !is_shadow_present_pte(old_spte) ||
+ old_spte & shadow_accessed_mask) {
+ __set_spte(sptep, new_spte);
+ } else
+ old_spte = __xchg_spte(sptep, new_spte);
+
+ if (!is_rmap_spte(old_spte))
+ return;
+ pfn = spte_to_pfn(old_spte);
+ if (!shadow_accessed_mask || old_spte & shadow_accessed_mask)
+ kvm_set_pfn_accessed(pfn);
+ if (is_writable_pte(old_spte))
+ kvm_set_pfn_dirty(pfn);
+}
+
+static void drop_spte(struct kvm *kvm, u64 *sptep, u64 new_spte)
+{
+ set_spte_track_bits(sptep, new_spte);
+ rmap_remove(kvm, sptep);
+}
+
static u64 *rmap_next(struct kvm *kvm, unsigned long *rmapp, u64 *spte)
{
struct kvm_rmap_desc *desc;
@@ -676,7 +733,6 @@ static int rmap_write_protect(struct kvm *kvm, u64 gfn)
u64 *spte;
int i, write_protected = 0;
- gfn = unalias_gfn(kvm, gfn);
rmapp = gfn_to_rmap(kvm, gfn, PT_PAGE_TABLE_LEVEL);
spte = rmap_next(kvm, rmapp, NULL);
@@ -685,7 +741,7 @@ static int rmap_write_protect(struct kvm *kvm, u64 gfn)
BUG_ON(!(*spte & PT_PRESENT_MASK));
rmap_printk("rmap_write_protect: spte %p %llx\n", spte, *spte);
if (is_writable_pte(*spte)) {
- __set_spte(spte, *spte & ~PT_WRITABLE_MASK);
+ update_spte(spte, *spte & ~PT_WRITABLE_MASK);
write_protected = 1;
}
spte = rmap_next(kvm, rmapp, spte);
@@ -709,9 +765,9 @@ static int rmap_write_protect(struct kvm *kvm, u64 gfn)
BUG_ON((*spte & (PT_PAGE_SIZE_MASK|PT_PRESENT_MASK)) != (PT_PAGE_SIZE_MASK|PT_PRESENT_MASK));
pgprintk("rmap_write_protect(large): spte %p %llx %lld\n", spte, *spte, gfn);
if (is_writable_pte(*spte)) {
- rmap_remove(kvm, spte);
+ drop_spte(kvm, spte,
+ shadow_trap_nonpresent_pte);
--kvm->stat.lpages;
- __set_spte(spte, shadow_trap_nonpresent_pte);
spte = NULL;
write_protected = 1;
}
@@ -731,8 +787,7 @@ static int kvm_unmap_rmapp(struct kvm *kvm, unsigned long *rmapp,
while ((spte = rmap_next(kvm, rmapp, NULL))) {
BUG_ON(!(*spte & PT_PRESENT_MASK));
rmap_printk("kvm_rmap_unmap_hva: spte %p %llx\n", spte, *spte);
- rmap_remove(kvm, spte);
- __set_spte(spte, shadow_trap_nonpresent_pte);
+ drop_spte(kvm, spte, shadow_trap_nonpresent_pte);
need_tlb_flush = 1;
}
return need_tlb_flush;
@@ -754,8 +809,7 @@ static int kvm_set_pte_rmapp(struct kvm *kvm, unsigned long *rmapp,
rmap_printk("kvm_set_pte_rmapp: spte %p %llx\n", spte, *spte);
need_flush = 1;
if (pte_write(*ptep)) {
- rmap_remove(kvm, spte);
- __set_spte(spte, shadow_trap_nonpresent_pte);
+ drop_spte(kvm, spte, shadow_trap_nonpresent_pte);
spte = rmap_next(kvm, rmapp, NULL);
} else {
new_spte = *spte &~ (PT64_BASE_ADDR_MASK);
@@ -763,9 +817,8 @@ static int kvm_set_pte_rmapp(struct kvm *kvm, unsigned long *rmapp,
new_spte &= ~PT_WRITABLE_MASK;
new_spte &= ~SPTE_HOST_WRITEABLE;
- if (is_writable_pte(*spte))
- kvm_set_pfn_dirty(spte_to_pfn(*spte));
- __set_spte(spte, new_spte);
+ new_spte &= ~shadow_accessed_mask;
+ set_spte_track_bits(spte, new_spte);
spte = rmap_next(kvm, rmapp, spte);
}
}
@@ -799,8 +852,12 @@ static int kvm_handle_hva(struct kvm *kvm, unsigned long hva,
ret = handler(kvm, &memslot->rmap[gfn_offset], data);
for (j = 0; j < KVM_NR_PAGE_SIZES - 1; ++j) {
- int idx = gfn_offset;
- idx /= KVM_PAGES_PER_HPAGE(PT_DIRECTORY_LEVEL + j);
+ unsigned long idx;
+ int sh;
+
+ sh = KVM_HPAGE_GFN_SHIFT(PT_DIRECTORY_LEVEL+j);
+ idx = ((memslot->base_gfn+gfn_offset) >> sh) -
+ (memslot->base_gfn >> sh);
ret |= handler(kvm,
&memslot->lpage_info[j][idx].rmap_pde,
data);
@@ -863,7 +920,6 @@ static void rmap_recycle(struct kvm_vcpu *vcpu, u64 *spte, gfn_t gfn)
sp = page_header(__pa(spte));
- gfn = unalias_gfn(vcpu->kvm, gfn);
rmapp = gfn_to_rmap(vcpu->kvm, gfn, sp->role.level);
kvm_unmap_rmapp(vcpu->kvm, rmapp, 0);
@@ -894,10 +950,12 @@ static int is_empty_shadow_page(u64 *spt)
static void kvm_mmu_free_page(struct kvm *kvm, struct kvm_mmu_page *sp)
{
ASSERT(is_empty_shadow_page(sp->spt));
+ hlist_del(&sp->hash_link);
list_del(&sp->link);
__free_page(virt_to_page(sp->spt));
- __free_page(virt_to_page(sp->gfns));
- kfree(sp);
+ if (!sp->role.direct)
+ __free_page(virt_to_page(sp->gfns));
+ kmem_cache_free(mmu_page_header_cache, sp);
++kvm->arch.n_free_mmu_pages;
}
@@ -907,13 +965,15 @@ static unsigned kvm_page_table_hashfn(gfn_t gfn)
}
static struct kvm_mmu_page *kvm_mmu_alloc_page(struct kvm_vcpu *vcpu,
- u64 *parent_pte)
+ u64 *parent_pte, int direct)
{
struct kvm_mmu_page *sp;
sp = mmu_memory_cache_alloc(&vcpu->arch.mmu_page_header_cache, sizeof *sp);
sp->spt = mmu_memory_cache_alloc(&vcpu->arch.mmu_page_cache, PAGE_SIZE);
- sp->gfns = mmu_memory_cache_alloc(&vcpu->arch.mmu_page_cache, PAGE_SIZE);
+ if (!direct)
+ sp->gfns = mmu_memory_cache_alloc(&vcpu->arch.mmu_page_cache,
+ PAGE_SIZE);
set_page_private(virt_to_page(sp->spt), (unsigned long)sp);
list_add(&sp->link, &vcpu->kvm->arch.active_mmu_pages);
bitmap_zero(sp->slot_bitmap, KVM_MEMORY_SLOTS + KVM_PRIVATE_MEM_SLOTS);
@@ -998,7 +1058,6 @@ static void mmu_page_remove_parent_pte(struct kvm_mmu_page *sp,
BUG();
}
-
static void mmu_parent_walk(struct kvm_mmu_page *sp, mmu_parent_walk_fn fn)
{
struct kvm_pte_chain *pte_chain;
@@ -1008,63 +1067,37 @@ static void mmu_parent_walk(struct kvm_mmu_page *sp, mmu_parent_walk_fn fn)
if (!sp->multimapped && sp->parent_pte) {
parent_sp = page_header(__pa(sp->parent_pte));
- fn(parent_sp);
- mmu_parent_walk(parent_sp, fn);
+ fn(parent_sp, sp->parent_pte);
return;
}
+
hlist_for_each_entry(pte_chain, node, &sp->parent_ptes, link)
for (i = 0; i < NR_PTE_CHAIN_ENTRIES; ++i) {
- if (!pte_chain->parent_ptes[i])
+ u64 *spte = pte_chain->parent_ptes[i];
+
+ if (!spte)
break;
- parent_sp = page_header(__pa(pte_chain->parent_ptes[i]));
- fn(parent_sp);
- mmu_parent_walk(parent_sp, fn);
+ parent_sp = page_header(__pa(spte));
+ fn(parent_sp, spte);
}
}
-static void kvm_mmu_update_unsync_bitmap(u64 *spte)
+static void mark_unsync(struct kvm_mmu_page *sp, u64 *spte);
+static void kvm_mmu_mark_parents_unsync(struct kvm_mmu_page *sp)
{
- unsigned int index;
- struct kvm_mmu_page *sp = page_header(__pa(spte));
-
- index = spte - sp->spt;
- if (!__test_and_set_bit(index, sp->unsync_child_bitmap))
- sp->unsync_children++;
- WARN_ON(!sp->unsync_children);
+ mmu_parent_walk(sp, mark_unsync);
}
-static void kvm_mmu_update_parents_unsync(struct kvm_mmu_page *sp)
+static void mark_unsync(struct kvm_mmu_page *sp, u64 *spte)
{
- struct kvm_pte_chain *pte_chain;
- struct hlist_node *node;
- int i;
+ unsigned int index;
- if (!sp->parent_pte)
+ index = spte - sp->spt;
+ if (__test_and_set_bit(index, sp->unsync_child_bitmap))
return;
-
- if (!sp->multimapped) {
- kvm_mmu_update_unsync_bitmap(sp->parent_pte);
+ if (sp->unsync_children++)
return;
- }
-
- hlist_for_each_entry(pte_chain, node, &sp->parent_ptes, link)
- for (i = 0; i < NR_PTE_CHAIN_ENTRIES; ++i) {
- if (!pte_chain->parent_ptes[i])
- break;
- kvm_mmu_update_unsync_bitmap(pte_chain->parent_ptes[i]);
- }
-}
-
-static int unsync_walk_fn(struct kvm_mmu_page *sp)
-{
- kvm_mmu_update_parents_unsync(sp);
- return 1;
-}
-
-static void kvm_mmu_mark_parents_unsync(struct kvm_mmu_page *sp)
-{
- mmu_parent_walk(sp, unsync_walk_fn);
- kvm_mmu_update_parents_unsync(sp);
+ kvm_mmu_mark_parents_unsync(sp);
}
static void nonpaging_prefetch_page(struct kvm_vcpu *vcpu,
@@ -1077,7 +1110,7 @@ static void nonpaging_prefetch_page(struct kvm_vcpu *vcpu,
}
static int nonpaging_sync_page(struct kvm_vcpu *vcpu,
- struct kvm_mmu_page *sp)
+ struct kvm_mmu_page *sp, bool clear_unsync)
{
return 1;
}
@@ -1123,35 +1156,40 @@ static int __mmu_unsync_walk(struct kvm_mmu_page *sp,
int i, ret, nr_unsync_leaf = 0;
for_each_unsync_children(sp->unsync_child_bitmap, i) {
+ struct kvm_mmu_page *child;
u64 ent = sp->spt[i];
- if (is_shadow_present_pte(ent) && !is_large_pte(ent)) {
- struct kvm_mmu_page *child;
- child = page_header(ent & PT64_BASE_ADDR_MASK);
-
- if (child->unsync_children) {
- if (mmu_pages_add(pvec, child, i))
- return -ENOSPC;
-
- ret = __mmu_unsync_walk(child, pvec);
- if (!ret)
- __clear_bit(i, sp->unsync_child_bitmap);
- else if (ret > 0)
- nr_unsync_leaf += ret;
- else
- return ret;
- }
+ if (!is_shadow_present_pte(ent) || is_large_pte(ent))
+ goto clear_child_bitmap;
+
+ child = page_header(ent & PT64_BASE_ADDR_MASK);
+
+ if (child->unsync_children) {
+ if (mmu_pages_add(pvec, child, i))
+ return -ENOSPC;
+
+ ret = __mmu_unsync_walk(child, pvec);
+ if (!ret)
+ goto clear_child_bitmap;
+ else if (ret > 0)
+ nr_unsync_leaf += ret;
+ else
+ return ret;
+ } else if (child->unsync) {
+ nr_unsync_leaf++;
+ if (mmu_pages_add(pvec, child, i))
+ return -ENOSPC;
+ } else
+ goto clear_child_bitmap;
- if (child->unsync) {
- nr_unsync_leaf++;
- if (mmu_pages_add(pvec, child, i))
- return -ENOSPC;
- }
- }
+ continue;
+
+clear_child_bitmap:
+ __clear_bit(i, sp->unsync_child_bitmap);
+ sp->unsync_children--;
+ WARN_ON((int)sp->unsync_children < 0);
}
- if (find_first_bit(sp->unsync_child_bitmap, 512) == 512)
- sp->unsync_children = 0;
return nr_unsync_leaf;
}
@@ -1166,26 +1204,6 @@ static int mmu_unsync_walk(struct kvm_mmu_page *sp,
return __mmu_unsync_walk(sp, pvec);
}
-static struct kvm_mmu_page *kvm_mmu_lookup_page(struct kvm *kvm, gfn_t gfn)
-{
- unsigned index;
- struct hlist_head *bucket;
- struct kvm_mmu_page *sp;
- struct hlist_node *node;
-
- pgprintk("%s: looking for gfn %lx\n", __func__, gfn);
- index = kvm_page_table_hashfn(gfn);
- bucket = &kvm->arch.mmu_page_hash[index];
- hlist_for_each_entry(sp, node, bucket, hash_link)
- if (sp->gfn == gfn && !sp->role.direct
- && !sp->role.invalid) {
- pgprintk("%s: found role %x\n",
- __func__, sp->role.word);
- return sp;
- }
- return NULL;
-}
-
static void kvm_unlink_unsync_page(struct kvm *kvm, struct kvm_mmu_page *sp)
{
WARN_ON(!sp->unsync);
@@ -1194,20 +1212,36 @@ static void kvm_unlink_unsync_page(struct kvm *kvm, struct kvm_mmu_page *sp)
--kvm->stat.mmu_unsync;
}
-static int kvm_mmu_zap_page(struct kvm *kvm, struct kvm_mmu_page *sp);
+static int kvm_mmu_prepare_zap_page(struct kvm *kvm, struct kvm_mmu_page *sp,
+ struct list_head *invalid_list);
+static void kvm_mmu_commit_zap_page(struct kvm *kvm,
+ struct list_head *invalid_list);
-static int kvm_sync_page(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp)
+#define for_each_gfn_sp(kvm, sp, gfn, pos) \
+ hlist_for_each_entry(sp, pos, \
+ &(kvm)->arch.mmu_page_hash[kvm_page_table_hashfn(gfn)], hash_link) \
+ if ((sp)->gfn != (gfn)) {} else
+
+#define for_each_gfn_indirect_valid_sp(kvm, sp, gfn, pos) \
+ hlist_for_each_entry(sp, pos, \
+ &(kvm)->arch.mmu_page_hash[kvm_page_table_hashfn(gfn)], hash_link) \
+ if ((sp)->gfn != (gfn) || (sp)->role.direct || \
+ (sp)->role.invalid) {} else
+
+/* @sp->gfn should be write-protected at the call site */
+static int __kvm_sync_page(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp,
+ struct list_head *invalid_list, bool clear_unsync)
{
if (sp->role.cr4_pae != !!is_pae(vcpu)) {
- kvm_mmu_zap_page(vcpu->kvm, sp);
+ kvm_mmu_prepare_zap_page(vcpu->kvm, sp, invalid_list);
return 1;
}
- if (rmap_write_protect(vcpu->kvm, sp->gfn))
- kvm_flush_remote_tlbs(vcpu->kvm);
- kvm_unlink_unsync_page(vcpu->kvm, sp);
- if (vcpu->arch.mmu.sync_page(vcpu, sp)) {
- kvm_mmu_zap_page(vcpu->kvm, sp);
+ if (clear_unsync)
+ kvm_unlink_unsync_page(vcpu->kvm, sp);
+
+ if (vcpu->arch.mmu.sync_page(vcpu, sp, clear_unsync)) {
+ kvm_mmu_prepare_zap_page(vcpu->kvm, sp, invalid_list);
return 1;
}
@@ -1215,6 +1249,52 @@ static int kvm_sync_page(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp)
return 0;
}
+static int kvm_sync_page_transient(struct kvm_vcpu *vcpu,
+ struct kvm_mmu_page *sp)
+{
+ LIST_HEAD(invalid_list);
+ int ret;
+
+ ret = __kvm_sync_page(vcpu, sp, &invalid_list, false);
+ if (ret)
+ kvm_mmu_commit_zap_page(vcpu->kvm, &invalid_list);
+
+ return ret;
+}
+
+static int kvm_sync_page(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp,
+ struct list_head *invalid_list)
+{
+ return __kvm_sync_page(vcpu, sp, invalid_list, true);
+}
+
+/* @gfn should be write-protected at the call site */
+static void kvm_sync_pages(struct kvm_vcpu *vcpu, gfn_t gfn)
+{
+ struct kvm_mmu_page *s;
+ struct hlist_node *node;
+ LIST_HEAD(invalid_list);
+ bool flush = false;
+
+ for_each_gfn_indirect_valid_sp(vcpu->kvm, s, gfn, node) {
+ if (!s->unsync)
+ continue;
+
+ WARN_ON(s->role.level != PT_PAGE_TABLE_LEVEL);
+ if ((s->role.cr4_pae != !!is_pae(vcpu)) ||
+ (vcpu->arch.mmu.sync_page(vcpu, s, true))) {
+ kvm_mmu_prepare_zap_page(vcpu->kvm, s, &invalid_list);
+ continue;
+ }
+ kvm_unlink_unsync_page(vcpu->kvm, s);
+ flush = true;
+ }
+
+ kvm_mmu_commit_zap_page(vcpu->kvm, &invalid_list);
+ if (flush)
+ kvm_mmu_flush_tlb(vcpu);
+}
+
struct mmu_page_path {
struct kvm_mmu_page *parent[PT64_ROOT_LEVEL-1];
unsigned int idx[PT64_ROOT_LEVEL-1];
@@ -1281,6 +1361,7 @@ static void mmu_sync_children(struct kvm_vcpu *vcpu,
struct kvm_mmu_page *sp;
struct mmu_page_path parents;
struct kvm_mmu_pages pages;
+ LIST_HEAD(invalid_list);
kvm_mmu_pages_init(parent, &parents, &pages);
while (mmu_unsync_walk(parent, &pages)) {
@@ -1293,9 +1374,10 @@ static void mmu_sync_children(struct kvm_vcpu *vcpu,
kvm_flush_remote_tlbs(vcpu->kvm);
for_each_sp(pages, sp, parents, i) {
- kvm_sync_page(vcpu, sp);
+ kvm_sync_page(vcpu, sp, &invalid_list);
mmu_pages_clear_parents(&parents);
}
+ kvm_mmu_commit_zap_page(vcpu->kvm, &invalid_list);
cond_resched_lock(&vcpu->kvm->mmu_lock);
kvm_mmu_pages_init(parent, &parents, &pages);
}
@@ -1310,11 +1392,10 @@ static struct kvm_mmu_page *kvm_mmu_get_page(struct kvm_vcpu *vcpu,
u64 *parent_pte)
{
union kvm_mmu_page_role role;
- unsigned index;
unsigned quadrant;
- struct hlist_head *bucket;
struct kvm_mmu_page *sp;
- struct hlist_node *node, *tmp;
+ struct hlist_node *node;
+ bool need_sync = false;
role = vcpu->arch.mmu.base_role;
role.level = level;
@@ -1322,40 +1403,45 @@ static struct kvm_mmu_page *kvm_mmu_get_page(struct kvm_vcpu *vcpu,
if (role.direct)
role.cr4_pae = 0;
role.access = access;
- if (vcpu->arch.mmu.root_level <= PT32_ROOT_LEVEL) {
+ if (!tdp_enabled && vcpu->arch.mmu.root_level <= PT32_ROOT_LEVEL) {
quadrant = gaddr >> (PAGE_SHIFT + (PT64_PT_BITS * level));
quadrant &= (1 << ((PT32_PT_BITS - PT64_PT_BITS) * level)) - 1;
role.quadrant = quadrant;
}
- index = kvm_page_table_hashfn(gfn);
- bucket = &vcpu->kvm->arch.mmu_page_hash[index];
- hlist_for_each_entry_safe(sp, node, tmp, bucket, hash_link)
- if (sp->gfn == gfn) {
- if (sp->unsync)
- if (kvm_sync_page(vcpu, sp))
- continue;
+ for_each_gfn_sp(vcpu->kvm, sp, gfn, node) {
+ if (!need_sync && sp->unsync)
+ need_sync = true;
- if (sp->role.word != role.word)
- continue;
+ if (sp->role.word != role.word)
+ continue;
- mmu_page_add_parent_pte(vcpu, sp, parent_pte);
- if (sp->unsync_children) {
- set_bit(KVM_REQ_MMU_SYNC, &vcpu->requests);
- kvm_mmu_mark_parents_unsync(sp);
- }
- trace_kvm_mmu_get_page(sp, false);
- return sp;
- }
+ if (sp->unsync && kvm_sync_page_transient(vcpu, sp))
+ break;
+
+ mmu_page_add_parent_pte(vcpu, sp, parent_pte);
+ if (sp->unsync_children) {
+ kvm_make_request(KVM_REQ_MMU_SYNC, vcpu);
+ kvm_mmu_mark_parents_unsync(sp);
+ } else if (sp->unsync)
+ kvm_mmu_mark_parents_unsync(sp);
+
+ trace_kvm_mmu_get_page(sp, false);
+ return sp;
+ }
++vcpu->kvm->stat.mmu_cache_miss;
- sp = kvm_mmu_alloc_page(vcpu, parent_pte);
+ sp = kvm_mmu_alloc_page(vcpu, parent_pte, direct);
if (!sp)
return sp;
sp->gfn = gfn;
sp->role = role;
- hlist_add_head(&sp->hash_link, bucket);
+ hlist_add_head(&sp->hash_link,
+ &vcpu->kvm->arch.mmu_page_hash[kvm_page_table_hashfn(gfn)]);
if (!direct) {
if (rmap_write_protect(vcpu->kvm, gfn))
kvm_flush_remote_tlbs(vcpu->kvm);
+ if (level > PT_PAGE_TABLE_LEVEL && need_sync)
+ kvm_sync_pages(vcpu, gfn);
+
account_shadowed(vcpu->kvm, gfn);
}
if (shadow_trap_nonpresent_pte != shadow_notrap_nonpresent_pte)
@@ -1402,6 +1488,47 @@ static void shadow_walk_next(struct kvm_shadow_walk_iterator *iterator)
--iterator->level;
}
+static void link_shadow_page(u64 *sptep, struct kvm_mmu_page *sp)
+{
+ u64 spte;
+
+ spte = __pa(sp->spt)
+ | PT_PRESENT_MASK | PT_ACCESSED_MASK
+ | PT_WRITABLE_MASK | PT_USER_MASK;
+ __set_spte(sptep, spte);
+}
+
+static void drop_large_spte(struct kvm_vcpu *vcpu, u64 *sptep)
+{
+ if (is_large_pte(*sptep)) {
+ drop_spte(vcpu->kvm, sptep, shadow_trap_nonpresent_pte);
+ kvm_flush_remote_tlbs(vcpu->kvm);
+ }
+}
+
+static void validate_direct_spte(struct kvm_vcpu *vcpu, u64 *sptep,
+ unsigned direct_access)
+{
+ if (is_shadow_present_pte(*sptep) && !is_large_pte(*sptep)) {
+ struct kvm_mmu_page *child;
+
+ /*
+ * For the direct sp, if the guest pte's dirty bit
+ * changed form clean to dirty, it will corrupt the
+ * sp's access: allow writable in the read-only sp,
+ * so we should update the spte at this point to get
+ * a new sp with the correct access.
+ */
+ child = page_header(*sptep & PT64_BASE_ADDR_MASK);
+ if (child->role.access == direct_access)
+ return;
+
+ mmu_page_remove_parent_pte(child, sptep);
+ __set_spte(sptep, shadow_trap_nonpresent_pte);
+ kvm_flush_remote_tlbs(vcpu->kvm);
+ }
+}
+
static void kvm_mmu_page_unlink_children(struct kvm *kvm,
struct kvm_mmu_page *sp)
{
@@ -1422,7 +1549,8 @@ static void kvm_mmu_page_unlink_children(struct kvm *kvm,
} else {
if (is_large_pte(ent))
--kvm->stat.lpages;
- rmap_remove(kvm, &pt[i]);
+ drop_spte(kvm, &pt[i],
+ shadow_trap_nonpresent_pte);
}
}
pt[i] = shadow_trap_nonpresent_pte;
@@ -1464,7 +1592,8 @@ static void kvm_mmu_unlink_parents(struct kvm *kvm, struct kvm_mmu_page *sp)
}
static int mmu_zap_unsync_children(struct kvm *kvm,
- struct kvm_mmu_page *parent)
+ struct kvm_mmu_page *parent,
+ struct list_head *invalid_list)
{
int i, zapped = 0;
struct mmu_page_path parents;
@@ -1478,7 +1607,7 @@ static int mmu_zap_unsync_children(struct kvm *kvm,
struct kvm_mmu_page *sp;
for_each_sp(pages, sp, parents, i) {
- kvm_mmu_zap_page(kvm, sp);
+ kvm_mmu_prepare_zap_page(kvm, sp, invalid_list);
mmu_pages_clear_parents(&parents);
zapped++;
}
@@ -1488,32 +1617,52 @@ static int mmu_zap_unsync_children(struct kvm *kvm,
return zapped;
}
-static int kvm_mmu_zap_page(struct kvm *kvm, struct kvm_mmu_page *sp)
+static int kvm_mmu_prepare_zap_page(struct kvm *kvm, struct kvm_mmu_page *sp,
+ struct list_head *invalid_list)
{
int ret;
- trace_kvm_mmu_zap_page(sp);
+ trace_kvm_mmu_prepare_zap_page(sp);
++kvm->stat.mmu_shadow_zapped;
- ret = mmu_zap_unsync_children(kvm, sp);
+ ret = mmu_zap_unsync_children(kvm, sp, invalid_list);
kvm_mmu_page_unlink_children(kvm, sp);
kvm_mmu_unlink_parents(kvm, sp);
- kvm_flush_remote_tlbs(kvm);
if (!sp->role.invalid && !sp->role.direct)
unaccount_shadowed(kvm, sp->gfn);
if (sp->unsync)
kvm_unlink_unsync_page(kvm, sp);
if (!sp->root_count) {
- hlist_del(&sp->hash_link);
- kvm_mmu_free_page(kvm, sp);
+ /* Count self */
+ ret++;
+ list_move(&sp->link, invalid_list);
} else {
- sp->role.invalid = 1;
list_move(&sp->link, &kvm->arch.active_mmu_pages);
kvm_reload_remote_mmus(kvm);
}
+
+ sp->role.invalid = 1;
kvm_mmu_reset_last_pte_updated(kvm);
return ret;
}
+static void kvm_mmu_commit_zap_page(struct kvm *kvm,
+ struct list_head *invalid_list)
+{
+ struct kvm_mmu_page *sp;
+
+ if (list_empty(invalid_list))
+ return;
+
+ kvm_flush_remote_tlbs(kvm);
+
+ do {
+ sp = list_first_entry(invalid_list, struct kvm_mmu_page, link);
+ WARN_ON(!sp->role.invalid || sp->root_count);
+ kvm_mmu_free_page(kvm, sp);
+ } while (!list_empty(invalid_list));
+
+}
+
/*
* Changing the number of mmu pages allocated to the vm
* Note: if kvm_nr_mmu_pages is too small, you will get dead lock
@@ -1521,6 +1670,7 @@ static int kvm_mmu_zap_page(struct kvm *kvm, struct kvm_mmu_page *sp)
void kvm_mmu_change_mmu_pages(struct kvm *kvm, unsigned int kvm_nr_mmu_pages)
{
int used_pages;
+ LIST_HEAD(invalid_list);
used_pages = kvm->arch.n_alloc_mmu_pages - kvm->arch.n_free_mmu_pages;
used_pages = max(0, used_pages);
@@ -1538,9 +1688,10 @@ void kvm_mmu_change_mmu_pages(struct kvm *kvm, unsigned int kvm_nr_mmu_pages)
page = container_of(kvm->arch.active_mmu_pages.prev,
struct kvm_mmu_page, link);
- used_pages -= kvm_mmu_zap_page(kvm, page);
- used_pages--;
+ used_pages -= kvm_mmu_prepare_zap_page(kvm, page,
+ &invalid_list);
}
+ kvm_mmu_commit_zap_page(kvm, &invalid_list);
kvm_nr_mmu_pages = used_pages;
kvm->arch.n_free_mmu_pages = 0;
}
@@ -1553,47 +1704,36 @@ void kvm_mmu_change_mmu_pages(struct kvm *kvm, unsigned int kvm_nr_mmu_pages)
static int kvm_mmu_unprotect_page(struct kvm *kvm, gfn_t gfn)
{
- unsigned index;
- struct hlist_head *bucket;
struct kvm_mmu_page *sp;
- struct hlist_node *node, *n;
+ struct hlist_node *node;
+ LIST_HEAD(invalid_list);
int r;
pgprintk("%s: looking for gfn %lx\n", __func__, gfn);
r = 0;
- index = kvm_page_table_hashfn(gfn);
- bucket = &kvm->arch.mmu_page_hash[index];
-restart:
- hlist_for_each_entry_safe(sp, node, n, bucket, hash_link)
- if (sp->gfn == gfn && !sp->role.direct) {
- pgprintk("%s: gfn %lx role %x\n", __func__, gfn,
- sp->role.word);
- r = 1;
- if (kvm_mmu_zap_page(kvm, sp))
- goto restart;
- }
+
+ for_each_gfn_indirect_valid_sp(kvm, sp, gfn, node) {
+ pgprintk("%s: gfn %lx role %x\n", __func__, gfn,
+ sp->role.word);
+ r = 1;
+ kvm_mmu_prepare_zap_page(kvm, sp, &invalid_list);
+ }
+ kvm_mmu_commit_zap_page(kvm, &invalid_list);
return r;
}
static void mmu_unshadow(struct kvm *kvm, gfn_t gfn)
{
- unsigned index;
- struct hlist_head *bucket;
struct kvm_mmu_page *sp;
- struct hlist_node *node, *nn;
+ struct hlist_node *node;
+ LIST_HEAD(invalid_list);
- index = kvm_page_table_hashfn(gfn);
- bucket = &kvm->arch.mmu_page_hash[index];
-restart:
- hlist_for_each_entry_safe(sp, node, nn, bucket, hash_link) {
- if (sp->gfn == gfn && !sp->role.direct
- && !sp->role.invalid) {
- pgprintk("%s: zap %lx %x\n",
- __func__, gfn, sp->role.word);
- if (kvm_mmu_zap_page(kvm, sp))
- goto restart;
- }
+ for_each_gfn_indirect_valid_sp(kvm, sp, gfn, node) {
+ pgprintk("%s: zap %lx %x\n",
+ __func__, gfn, sp->role.word);
+ kvm_mmu_prepare_zap_page(kvm, sp, &invalid_list);
}
+ kvm_mmu_commit_zap_page(kvm, &invalid_list);
}
static void page_header_update_slot(struct kvm *kvm, void *pte, gfn_t gfn)
@@ -1723,47 +1863,51 @@ u8 kvm_get_guest_memory_type(struct kvm_vcpu *vcpu, gfn_t gfn)
}
EXPORT_SYMBOL_GPL(kvm_get_guest_memory_type);
-static int kvm_unsync_page(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp)
+static void __kvm_unsync_page(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp)
{
- unsigned index;
- struct hlist_head *bucket;
- struct kvm_mmu_page *s;
- struct hlist_node *node, *n;
-
- index = kvm_page_table_hashfn(sp->gfn);
- bucket = &vcpu->kvm->arch.mmu_page_hash[index];
- /* don't unsync if pagetable is shadowed with multiple roles */
- hlist_for_each_entry_safe(s, node, n, bucket, hash_link) {
- if (s->gfn != sp->gfn || s->role.direct)
- continue;
- if (s->role.word != sp->role.word)
- return 1;
- }
trace_kvm_mmu_unsync_page(sp);
++vcpu->kvm->stat.mmu_unsync;
sp->unsync = 1;
kvm_mmu_mark_parents_unsync(sp);
-
mmu_convert_notrap(sp);
- return 0;
+}
+
+static void kvm_unsync_pages(struct kvm_vcpu *vcpu, gfn_t gfn)
+{
+ struct kvm_mmu_page *s;
+ struct hlist_node *node;
+
+ for_each_gfn_indirect_valid_sp(vcpu->kvm, s, gfn, node) {
+ if (s->unsync)
+ continue;
+ WARN_ON(s->role.level != PT_PAGE_TABLE_LEVEL);
+ __kvm_unsync_page(vcpu, s);
+ }
}
static int mmu_need_write_protect(struct kvm_vcpu *vcpu, gfn_t gfn,
bool can_unsync)
{
- struct kvm_mmu_page *shadow;
+ struct kvm_mmu_page *s;
+ struct hlist_node *node;
+ bool need_unsync = false;
- shadow = kvm_mmu_lookup_page(vcpu->kvm, gfn);
- if (shadow) {
- if (shadow->role.level != PT_PAGE_TABLE_LEVEL)
+ for_each_gfn_indirect_valid_sp(vcpu->kvm, s, gfn, node) {
+ if (!can_unsync)
return 1;
- if (shadow->unsync)
- return 0;
- if (can_unsync && oos_shadow)
- return kvm_unsync_page(vcpu, shadow);
- return 1;
+
+ if (s->role.level != PT_PAGE_TABLE_LEVEL)
+ return 1;
+
+ if (!need_unsync && !s->unsync) {
+ if (!oos_shadow)
+ return 1;
+ need_unsync = true;
+ }
}
+ if (need_unsync)
+ kvm_unsync_pages(vcpu, gfn);
return 0;
}
@@ -1804,13 +1948,14 @@ static int set_spte(struct kvm_vcpu *vcpu, u64 *sptep,
spte |= (u64)pfn << PAGE_SHIFT;
if ((pte_access & ACC_WRITE_MASK)
- || (write_fault && !is_write_protection(vcpu) && !user_fault)) {
+ || (!tdp_enabled && write_fault && !is_write_protection(vcpu)
+ && !user_fault)) {
if (level > PT_PAGE_TABLE_LEVEL &&
has_wrprotected_page(vcpu->kvm, gfn, level)) {
ret = 1;
- spte = shadow_trap_nonpresent_pte;
- goto set_pte;
+ drop_spte(vcpu->kvm, sptep, shadow_trap_nonpresent_pte);
+ goto done;
}
spte |= PT_WRITABLE_MASK;
@@ -1841,7 +1986,10 @@ static int set_spte(struct kvm_vcpu *vcpu, u64 *sptep,
mark_page_dirty(vcpu->kvm, gfn);
set_pte:
- __set_spte(sptep, spte);
+ if (is_writable_pte(*sptep) && !is_writable_pte(spte))
+ kvm_set_pfn_dirty(pfn);
+ update_spte(sptep, spte);
+done:
return ret;
}
@@ -1853,7 +2001,6 @@ static void mmu_set_spte(struct kvm_vcpu *vcpu, u64 *sptep,
bool reset_host_protection)
{
int was_rmapped = 0;
- int was_writable = is_writable_pte(*sptep);
int rmap_count;
pgprintk("%s: spte %llx access %x write_fault %d"
@@ -1878,8 +2025,7 @@ static void mmu_set_spte(struct kvm_vcpu *vcpu, u64 *sptep,
} else if (pfn != spte_to_pfn(*sptep)) {
pgprintk("hfn old %lx new %lx\n",
spte_to_pfn(*sptep), pfn);
- rmap_remove(vcpu->kvm, sptep);
- __set_spte(sptep, shadow_trap_nonpresent_pte);
+ drop_spte(vcpu->kvm, sptep, shadow_trap_nonpresent_pte);
kvm_flush_remote_tlbs(vcpu->kvm);
} else
was_rmapped = 1;
@@ -1890,7 +2036,7 @@ static void mmu_set_spte(struct kvm_vcpu *vcpu, u64 *sptep,
reset_host_protection)) {
if (write_fault)
*ptwrite = 1;
- kvm_x86_ops->tlb_flush(vcpu);
+ kvm_mmu_flush_tlb(vcpu);
}
pgprintk("%s: setting spte %llx\n", __func__, *sptep);
@@ -1904,15 +2050,10 @@ static void mmu_set_spte(struct kvm_vcpu *vcpu, u64 *sptep,
page_header_update_slot(vcpu->kvm, sptep, gfn);
if (!was_rmapped) {
rmap_count = rmap_add(vcpu, sptep, gfn);
- kvm_release_pfn_clean(pfn);
if (rmap_count > RMAP_RECYCLE_THRESHOLD)
rmap_recycle(vcpu, sptep, gfn);
- } else {
- if (was_writable)
- kvm_release_pfn_dirty(pfn);
- else
- kvm_release_pfn_clean(pfn);
}
+ kvm_release_pfn_clean(pfn);
if (speculative) {
vcpu->arch.last_pte_updated = sptep;
vcpu->arch.last_pte_gfn = gfn;
@@ -1941,7 +2082,10 @@ static int __direct_map(struct kvm_vcpu *vcpu, gpa_t v, int write,
}
if (*iterator.sptep == shadow_trap_nonpresent_pte) {
- pseudo_gfn = (iterator.addr & PT64_DIR_BASE_ADDR_MASK) >> PAGE_SHIFT;
+ u64 base_addr = iterator.addr;
+
+ base_addr &= PT64_LVL_ADDR_MASK(iterator.level);
+ pseudo_gfn = base_addr >> PAGE_SHIFT;
sp = kvm_mmu_get_page(vcpu, pseudo_gfn, iterator.addr,
iterator.level - 1,
1, ACC_ALL, iterator.sptep);
@@ -1960,6 +2104,29 @@ static int __direct_map(struct kvm_vcpu *vcpu, gpa_t v, int write,
return pt_write;
}
+static void kvm_send_hwpoison_signal(struct kvm *kvm, gfn_t gfn)
+{
+ char buf[1];
+ void __user *hva;
+ int r;
+
+ /* Touch the page, so send SIGBUS */
+ hva = (void __user *)gfn_to_hva(kvm, gfn);
+ r = copy_from_user(buf, hva, 1);
+}
+
+static int kvm_handle_bad_page(struct kvm *kvm, gfn_t gfn, pfn_t pfn)
+{
+ kvm_release_pfn_clean(pfn);
+ if (is_hwpoison_pfn(pfn)) {
+ kvm_send_hwpoison_signal(kvm, gfn);
+ return 0;
+ } else if (is_fault_pfn(pfn))
+ return -EFAULT;
+
+ return 1;
+}
+
static int nonpaging_map(struct kvm_vcpu *vcpu, gva_t v, int write, gfn_t gfn)
{
int r;
@@ -1983,10 +2150,8 @@ static int nonpaging_map(struct kvm_vcpu *vcpu, gva_t v, int write, gfn_t gfn)
pfn = gfn_to_pfn(vcpu->kvm, gfn);
/* mmio */
- if (is_error_pfn(pfn)) {
- kvm_release_pfn_clean(pfn);
- return 1;
- }
+ if (is_error_pfn(pfn))
+ return kvm_handle_bad_page(vcpu->kvm, gfn, pfn);
spin_lock(&vcpu->kvm->mmu_lock);
if (mmu_notifier_retry(vcpu, mmu_seq))
@@ -2009,6 +2174,7 @@ static void mmu_free_roots(struct kvm_vcpu *vcpu)
{
int i;
struct kvm_mmu_page *sp;
+ LIST_HEAD(invalid_list);
if (!VALID_PAGE(vcpu->arch.mmu.root_hpa))
return;
@@ -2018,8 +2184,10 @@ static void mmu_free_roots(struct kvm_vcpu *vcpu)
sp = page_header(root);
--sp->root_count;
- if (!sp->root_count && sp->role.invalid)
- kvm_mmu_zap_page(vcpu->kvm, sp);
+ if (!sp->root_count && sp->role.invalid) {
+ kvm_mmu_prepare_zap_page(vcpu->kvm, sp, &invalid_list);
+ kvm_mmu_commit_zap_page(vcpu->kvm, &invalid_list);
+ }
vcpu->arch.mmu.root_hpa = INVALID_PAGE;
spin_unlock(&vcpu->kvm->mmu_lock);
return;
@@ -2032,10 +2200,12 @@ static void mmu_free_roots(struct kvm_vcpu *vcpu)
sp = page_header(root);
--sp->root_count;
if (!sp->root_count && sp->role.invalid)
- kvm_mmu_zap_page(vcpu->kvm, sp);
+ kvm_mmu_prepare_zap_page(vcpu->kvm, sp,
+ &invalid_list);
}
vcpu->arch.mmu.pae_root[i] = INVALID_PAGE;
}
+ kvm_mmu_commit_zap_page(vcpu->kvm, &invalid_list);
spin_unlock(&vcpu->kvm->mmu_lock);
vcpu->arch.mmu.root_hpa = INVALID_PAGE;
}
@@ -2045,7 +2215,7 @@ static int mmu_check_root(struct kvm_vcpu *vcpu, gfn_t root_gfn)
int ret = 0;
if (!kvm_is_visible_gfn(vcpu->kvm, root_gfn)) {
- set_bit(KVM_REQ_TRIPLE_FAULT, &vcpu->requests);
+ kvm_make_request(KVM_REQ_TRIPLE_FAULT, vcpu);
ret = 1;
}
@@ -2073,6 +2243,7 @@ static int mmu_alloc_roots(struct kvm_vcpu *vcpu)
root_gfn = 0;
}
spin_lock(&vcpu->kvm->mmu_lock);
+ kvm_mmu_free_some_pages(vcpu);
sp = kvm_mmu_get_page(vcpu, root_gfn, 0,
PT64_ROOT_LEVEL, direct,
ACC_ALL, NULL);
@@ -2103,6 +2274,7 @@ static int mmu_alloc_roots(struct kvm_vcpu *vcpu)
root_gfn = i << 30;
}
spin_lock(&vcpu->kvm->mmu_lock);
+ kvm_mmu_free_some_pages(vcpu);
sp = kvm_mmu_get_page(vcpu, root_gfn, i << 30,
PT32_ROOT_LEVEL, direct,
ACC_ALL, NULL);
@@ -2198,10 +2370,8 @@ static int tdp_page_fault(struct kvm_vcpu *vcpu, gva_t gpa,
mmu_seq = vcpu->kvm->mmu_notifier_seq;
smp_rmb();
pfn = gfn_to_pfn(vcpu->kvm, gfn);
- if (is_error_pfn(pfn)) {
- kvm_release_pfn_clean(pfn);
- return 1;
- }
+ if (is_error_pfn(pfn))
+ return kvm_handle_bad_page(vcpu->kvm, gfn, pfn);
spin_lock(&vcpu->kvm->mmu_lock);
if (mmu_notifier_retry(vcpu, mmu_seq))
goto out_unlock;
@@ -2243,7 +2413,7 @@ static int nonpaging_init_context(struct kvm_vcpu *vcpu)
void kvm_mmu_flush_tlb(struct kvm_vcpu *vcpu)
{
++vcpu->stat.tlb_flush;
- kvm_x86_ops->tlb_flush(vcpu);
+ kvm_make_request(KVM_REQ_TLB_FLUSH, vcpu);
}
static void paging_new_cr3(struct kvm_vcpu *vcpu)
@@ -2457,10 +2627,9 @@ static int init_kvm_mmu(struct kvm_vcpu *vcpu)
static void destroy_kvm_mmu(struct kvm_vcpu *vcpu)
{
ASSERT(vcpu);
- if (VALID_PAGE(vcpu->arch.mmu.root_hpa)) {
+ if (VALID_PAGE(vcpu->arch.mmu.root_hpa))
+ /* mmu.free() should set root_hpa = INVALID_PAGE */
vcpu->arch.mmu.free(vcpu);
- vcpu->arch.mmu.root_hpa = INVALID_PAGE;
- }
}
int kvm_mmu_reset_context(struct kvm_vcpu *vcpu)
@@ -2477,9 +2646,6 @@ int kvm_mmu_load(struct kvm_vcpu *vcpu)
r = mmu_topup_memory_caches(vcpu);
if (r)
goto out;
- spin_lock(&vcpu->kvm->mmu_lock);
- kvm_mmu_free_some_pages(vcpu);
- spin_unlock(&vcpu->kvm->mmu_lock);
r = mmu_alloc_roots(vcpu);
spin_lock(&vcpu->kvm->mmu_lock);
mmu_sync_roots(vcpu);
@@ -2508,7 +2674,7 @@ static void mmu_pte_write_zap_pte(struct kvm_vcpu *vcpu,
pte = *spte;
if (is_shadow_present_pte(pte)) {
if (is_last_spte(pte, sp->role.level))
- rmap_remove(vcpu->kvm, spte);
+ drop_spte(vcpu->kvm, spte, shadow_trap_nonpresent_pte);
else {
child = page_header(pte & PT64_BASE_ADDR_MASK);
mmu_page_remove_parent_pte(child, spte);
@@ -2529,6 +2695,9 @@ static void mmu_pte_write_new_pte(struct kvm_vcpu *vcpu,
return;
}
+ if (is_rsvd_bits_set(vcpu, *(u64 *)new, PT_PAGE_TABLE_LEVEL))
+ return;
+
++vcpu->kvm->stat.mmu_pte_updated;
if (!sp->role.cr4_pae)
paging32_update_pte(vcpu, sp, spte, new);
@@ -2549,11 +2718,15 @@ static bool need_remote_flush(u64 old, u64 new)
return (old & ~new & PT64_PERM_MASK) != 0;
}
-static void mmu_pte_write_flush_tlb(struct kvm_vcpu *vcpu, u64 old, u64 new)
+static void mmu_pte_write_flush_tlb(struct kvm_vcpu *vcpu, bool zap_page,
+ bool remote_flush, bool local_flush)
{
- if (need_remote_flush(old, new))
+ if (zap_page)
+ return;
+
+ if (remote_flush)
kvm_flush_remote_tlbs(vcpu->kvm);
- else
+ else if (local_flush)
kvm_mmu_flush_tlb(vcpu);
}
@@ -2603,10 +2776,10 @@ void kvm_mmu_pte_write(struct kvm_vcpu *vcpu, gpa_t gpa,
bool guest_initiated)
{
gfn_t gfn = gpa >> PAGE_SHIFT;
+ union kvm_mmu_page_role mask = { .word = 0 };
struct kvm_mmu_page *sp;
- struct hlist_node *node, *n;
- struct hlist_head *bucket;
- unsigned index;
+ struct hlist_node *node;
+ LIST_HEAD(invalid_list);
u64 entry, gentry;
u64 *spte;
unsigned offset = offset_in_page(gpa);
@@ -2619,6 +2792,9 @@ void kvm_mmu_pte_write(struct kvm_vcpu *vcpu, gpa_t gpa,
int npte;
int r;
int invlpg_counter;
+ bool remote_flush, local_flush, zap_page;
+
+ zap_page = remote_flush = local_flush = false;
pgprintk("%s: gpa %llx bytes %d\n", __func__, gpa, bytes);
@@ -2674,13 +2850,9 @@ void kvm_mmu_pte_write(struct kvm_vcpu *vcpu, gpa_t gpa,
vcpu->arch.last_pte_updated = NULL;
}
}
- index = kvm_page_table_hashfn(gfn);
- bucket = &vcpu->kvm->arch.mmu_page_hash[index];
-restart:
- hlist_for_each_entry_safe(sp, node, n, bucket, hash_link) {
- if (sp->gfn != gfn || sp->role.direct || sp->role.invalid)
- continue;
+ mask.cr0_wp = mask.cr4_pae = mask.nxe = 1;
+ for_each_gfn_indirect_valid_sp(vcpu->kvm, sp, gfn, node) {
pte_size = sp->role.cr4_pae ? 8 : 4;
misaligned = (offset ^ (offset + bytes - 1)) & ~(pte_size - 1);
misaligned |= bytes < 4;
@@ -2697,8 +2869,8 @@ restart:
*/
pgprintk("misaligned: gpa %llx bytes %d role %x\n",
gpa, bytes, sp->role.word);
- if (kvm_mmu_zap_page(vcpu->kvm, sp))
- goto restart;
+ zap_page |= !!kvm_mmu_prepare_zap_page(vcpu->kvm, sp,
+ &invalid_list);
++vcpu->kvm->stat.mmu_flooded;
continue;
}
@@ -2722,16 +2894,22 @@ restart:
if (quadrant != sp->role.quadrant)
continue;
}
+ local_flush = true;
spte = &sp->spt[page_offset / sizeof(*spte)];
while (npte--) {
entry = *spte;
mmu_pte_write_zap_pte(vcpu, sp, spte);
- if (gentry)
+ if (gentry &&
+ !((sp->role.word ^ vcpu->arch.mmu.base_role.word)
+ & mask.word))
mmu_pte_write_new_pte(vcpu, sp, spte, &gentry);
- mmu_pte_write_flush_tlb(vcpu, entry, *spte);
+ if (!remote_flush && need_remote_flush(entry, *spte))
+ remote_flush = true;
++spte;
}
}
+ mmu_pte_write_flush_tlb(vcpu, zap_page, remote_flush, local_flush);
+ kvm_mmu_commit_zap_page(vcpu->kvm, &invalid_list);
kvm_mmu_audit(vcpu, "post pte write");
spin_unlock(&vcpu->kvm->mmu_lock);
if (!is_error_pfn(vcpu->arch.update_pte.pfn)) {
@@ -2759,15 +2937,21 @@ EXPORT_SYMBOL_GPL(kvm_mmu_unprotect_page_virt);
void __kvm_mmu_free_some_pages(struct kvm_vcpu *vcpu)
{
- while (vcpu->kvm->arch.n_free_mmu_pages < KVM_REFILL_PAGES &&
+ int free_pages;
+ LIST_HEAD(invalid_list);
+
+ free_pages = vcpu->kvm->arch.n_free_mmu_pages;
+ while (free_pages < KVM_REFILL_PAGES &&
!list_empty(&vcpu->kvm->arch.active_mmu_pages)) {
struct kvm_mmu_page *sp;
sp = container_of(vcpu->kvm->arch.active_mmu_pages.prev,
struct kvm_mmu_page, link);
- kvm_mmu_zap_page(vcpu->kvm, sp);
+ free_pages += kvm_mmu_prepare_zap_page(vcpu->kvm, sp,
+ &invalid_list);
++vcpu->kvm->stat.mmu_recycled;
}
+ kvm_mmu_commit_zap_page(vcpu->kvm, &invalid_list);
}
int kvm_mmu_page_fault(struct kvm_vcpu *vcpu, gva_t cr2, u32 error_code)
@@ -2795,11 +2979,8 @@ int kvm_mmu_page_fault(struct kvm_vcpu *vcpu, gva_t cr2, u32 error_code)
return 1;
case EMULATE_DO_MMIO:
++vcpu->stat.mmio_exits;
- return 0;
+ /* fall through */
case EMULATE_FAIL:
- vcpu->run->exit_reason = KVM_EXIT_INTERNAL_ERROR;
- vcpu->run->internal.suberror = KVM_INTERNAL_ERROR_EMULATION;
- vcpu->run->internal.ndata = 0;
return 0;
default:
BUG();
@@ -2896,7 +3077,7 @@ void kvm_mmu_slot_remove_write_access(struct kvm *kvm, int slot)
pt = sp->spt;
for (i = 0; i < PT64_ENT_PER_PAGE; ++i)
/* avoid RMW */
- if (pt[i] & PT_WRITABLE_MASK)
+ if (is_writable_pte(pt[i]))
pt[i] &= ~PT_WRITABLE_MASK;
}
kvm_flush_remote_tlbs(kvm);
@@ -2905,25 +3086,26 @@ void kvm_mmu_slot_remove_write_access(struct kvm *kvm, int slot)
void kvm_mmu_zap_all(struct kvm *kvm)
{
struct kvm_mmu_page *sp, *node;
+ LIST_HEAD(invalid_list);
spin_lock(&kvm->mmu_lock);
restart:
list_for_each_entry_safe(sp, node, &kvm->arch.active_mmu_pages, link)
- if (kvm_mmu_zap_page(kvm, sp))
+ if (kvm_mmu_prepare_zap_page(kvm, sp, &invalid_list))
goto restart;
+ kvm_mmu_commit_zap_page(kvm, &invalid_list);
spin_unlock(&kvm->mmu_lock);
-
- kvm_flush_remote_tlbs(kvm);
}
-static int kvm_mmu_remove_some_alloc_mmu_pages(struct kvm *kvm)
+static int kvm_mmu_remove_some_alloc_mmu_pages(struct kvm *kvm,
+ struct list_head *invalid_list)
{
struct kvm_mmu_page *page;
page = container_of(kvm->arch.active_mmu_pages.prev,
struct kvm_mmu_page, link);
- return kvm_mmu_zap_page(kvm, page) + 1;
+ return kvm_mmu_prepare_zap_page(kvm, page, invalid_list);
}
static int mmu_shrink(struct shrinker *shrink, int nr_to_scan, gfp_t gfp_mask)
@@ -2936,6 +3118,7 @@ static int mmu_shrink(struct shrinker *shrink, int nr_to_scan, gfp_t gfp_mask)
list_for_each_entry(kvm, &vm_list, vm_list) {
int npages, idx, freed_pages;
+ LIST_HEAD(invalid_list);
idx = srcu_read_lock(&kvm->srcu);
spin_lock(&kvm->mmu_lock);
@@ -2943,12 +3126,14 @@ static int mmu_shrink(struct shrinker *shrink, int nr_to_scan, gfp_t gfp_mask)
kvm->arch.n_free_mmu_pages;
cache_count += npages;
if (!kvm_freed && nr_to_scan > 0 && npages > 0) {
- freed_pages = kvm_mmu_remove_some_alloc_mmu_pages(kvm);
+ freed_pages = kvm_mmu_remove_some_alloc_mmu_pages(kvm,
+ &invalid_list);
cache_count -= freed_pages;
kvm_freed = kvm;
}
nr_to_scan--;
+ kvm_mmu_commit_zap_page(kvm, &invalid_list);
spin_unlock(&kvm->mmu_lock);
srcu_read_unlock(&kvm->srcu, idx);
}
@@ -3074,7 +3259,7 @@ static int kvm_pv_mmu_write(struct kvm_vcpu *vcpu,
static int kvm_pv_mmu_flush_tlb(struct kvm_vcpu *vcpu)
{
- kvm_set_cr3(vcpu, vcpu->arch.cr3);
+ (void)kvm_set_cr3(vcpu, vcpu->arch.cr3);
return 1;
}
@@ -3331,9 +3516,9 @@ void inspect_spte_has_rmap(struct kvm *kvm, u64 *sptep)
struct kvm_mmu_page *rev_sp;
gfn_t gfn;
- if (*sptep & PT_WRITABLE_MASK) {
+ if (is_writable_pte(*sptep)) {
rev_sp = page_header(__pa(sptep));
- gfn = rev_sp->gfns[sptep - rev_sp->spt];
+ gfn = kvm_mmu_page_get_gfn(rev_sp, sptep - rev_sp->spt);
if (!gfn_to_memslot(kvm, gfn)) {
if (!printk_ratelimit())
@@ -3347,8 +3532,7 @@ void inspect_spte_has_rmap(struct kvm *kvm, u64 *sptep)
return;
}
- rmapp = gfn_to_rmap(kvm, rev_sp->gfns[sptep - rev_sp->spt],
- rev_sp->role.level);
+ rmapp = gfn_to_rmap(kvm, gfn, rev_sp->role.level);
if (!*rmapp) {
if (!printk_ratelimit())
return;
@@ -3381,7 +3565,7 @@ static void check_writable_mappings_rmap(struct kvm_vcpu *vcpu)
if (!(ent & PT_PRESENT_MASK))
continue;
- if (!(ent & PT_WRITABLE_MASK))
+ if (!is_writable_pte(ent))
continue;
inspect_spte_has_rmap(vcpu->kvm, &pt[i]);
}
@@ -3409,13 +3593,12 @@ static void audit_write_protection(struct kvm_vcpu *vcpu)
if (sp->unsync)
continue;
- gfn = unalias_gfn(vcpu->kvm, sp->gfn);
- slot = gfn_to_memslot_unaliased(vcpu->kvm, sp->gfn);
+ slot = gfn_to_memslot(vcpu->kvm, sp->gfn);
rmapp = &slot->rmap[gfn - slot->base_gfn];
spte = rmap_next(vcpu->kvm, rmapp, NULL);
while (spte) {
- if (*spte & PT_WRITABLE_MASK)
+ if (is_writable_pte(*spte))
printk(KERN_ERR "%s: (%s) shadow page has "
"writable mappings: gfn %lx role %x\n",
__func__, audit_msg, sp->gfn,
diff --git a/arch/x86/kvm/mmutrace.h b/arch/x86/kvm/mmutrace.h
index 42f07b1bfbc..3aab0f0930e 100644
--- a/arch/x86/kvm/mmutrace.h
+++ b/arch/x86/kvm/mmutrace.h
@@ -190,7 +190,7 @@ DEFINE_EVENT(kvm_mmu_page_class, kvm_mmu_unsync_page,
TP_ARGS(sp)
);
-DEFINE_EVENT(kvm_mmu_page_class, kvm_mmu_zap_page,
+DEFINE_EVENT(kvm_mmu_page_class, kvm_mmu_prepare_zap_page,
TP_PROTO(struct kvm_mmu_page *sp),
TP_ARGS(sp)
diff --git a/arch/x86/kvm/paging_tmpl.h b/arch/x86/kvm/paging_tmpl.h
index 2331bdc2b54..51ef9097960 100644
--- a/arch/x86/kvm/paging_tmpl.h
+++ b/arch/x86/kvm/paging_tmpl.h
@@ -7,6 +7,7 @@
* MMU support
*
* Copyright (C) 2006 Qumranet, Inc.
+ * Copyright 2010 Red Hat, Inc. and/or its affilates.
*
* Authors:
* Yaniv Kamay <yaniv@qumranet.com>
@@ -118,21 +119,25 @@ static int FNAME(walk_addr)(struct guest_walker *walker,
{
pt_element_t pte;
gfn_t table_gfn;
- unsigned index, pt_access, pte_access;
+ unsigned index, pt_access, uninitialized_var(pte_access);
gpa_t pte_gpa;
- int rsvd_fault = 0;
+ bool eperm, present, rsvd_fault;
trace_kvm_mmu_pagetable_walk(addr, write_fault, user_fault,
fetch_fault);
walk:
+ present = true;
+ eperm = rsvd_fault = false;
walker->level = vcpu->arch.mmu.root_level;
pte = vcpu->arch.cr3;
#if PTTYPE == 64
if (!is_long_mode(vcpu)) {
pte = kvm_pdptr_read(vcpu, (addr >> 30) & 3);
trace_kvm_mmu_paging_element(pte, walker->level);
- if (!is_present_gpte(pte))
- goto not_present;
+ if (!is_present_gpte(pte)) {
+ present = false;
+ goto error;
+ }
--walker->level;
}
#endif
@@ -150,37 +155,42 @@ walk:
walker->table_gfn[walker->level - 1] = table_gfn;
walker->pte_gpa[walker->level - 1] = pte_gpa;
- if (kvm_read_guest(vcpu->kvm, pte_gpa, &pte, sizeof(pte)))
- goto not_present;
+ if (kvm_read_guest(vcpu->kvm, pte_gpa, &pte, sizeof(pte))) {
+ present = false;
+ break;
+ }
trace_kvm_mmu_paging_element(pte, walker->level);
- if (!is_present_gpte(pte))
- goto not_present;
+ if (!is_present_gpte(pte)) {
+ present = false;
+ break;
+ }
- rsvd_fault = is_rsvd_bits_set(vcpu, pte, walker->level);
- if (rsvd_fault)
- goto access_error;
+ if (is_rsvd_bits_set(vcpu, pte, walker->level)) {
+ rsvd_fault = true;
+ break;
+ }
if (write_fault && !is_writable_pte(pte))
if (user_fault || is_write_protection(vcpu))
- goto access_error;
+ eperm = true;
if (user_fault && !(pte & PT_USER_MASK))
- goto access_error;
+ eperm = true;
#if PTTYPE == 64
if (fetch_fault && (pte & PT64_NX_MASK))
- goto access_error;
+ eperm = true;
#endif
- if (!(pte & PT_ACCESSED_MASK)) {
+ if (!eperm && !rsvd_fault && !(pte & PT_ACCESSED_MASK)) {
trace_kvm_mmu_set_accessed_bit(table_gfn, index,
sizeof(pte));
- mark_page_dirty(vcpu->kvm, table_gfn);
if (FNAME(cmpxchg_gpte)(vcpu->kvm, table_gfn,
index, pte, pte|PT_ACCESSED_MASK))
goto walk;
+ mark_page_dirty(vcpu->kvm, table_gfn);
pte |= PT_ACCESSED_MASK;
}
@@ -213,15 +223,18 @@ walk:
--walker->level;
}
+ if (!present || eperm || rsvd_fault)
+ goto error;
+
if (write_fault && !is_dirty_gpte(pte)) {
bool ret;
trace_kvm_mmu_set_dirty_bit(table_gfn, index, sizeof(pte));
- mark_page_dirty(vcpu->kvm, table_gfn);
ret = FNAME(cmpxchg_gpte)(vcpu->kvm, table_gfn, index, pte,
pte|PT_DIRTY_MASK);
if (ret)
goto walk;
+ mark_page_dirty(vcpu->kvm, table_gfn);
pte |= PT_DIRTY_MASK;
walker->ptes[walker->level - 1] = pte;
}
@@ -229,22 +242,18 @@ walk:
walker->pt_access = pt_access;
walker->pte_access = pte_access;
pgprintk("%s: pte %llx pte_access %x pt_access %x\n",
- __func__, (u64)pte, pt_access, pte_access);
+ __func__, (u64)pte, pte_access, pt_access);
return 1;
-not_present:
+error:
walker->error_code = 0;
- goto err;
-
-access_error:
- walker->error_code = PFERR_PRESENT_MASK;
-
-err:
+ if (present)
+ walker->error_code |= PFERR_PRESENT_MASK;
if (write_fault)
walker->error_code |= PFERR_WRITE_MASK;
if (user_fault)
walker->error_code |= PFERR_USER_MASK;
- if (fetch_fault)
+ if (fetch_fault && is_nx(vcpu))
walker->error_code |= PFERR_FETCH_MASK;
if (rsvd_fault)
walker->error_code |= PFERR_RSVD_MASK;
@@ -252,7 +261,7 @@ err:
return 0;
}
-static void FNAME(update_pte)(struct kvm_vcpu *vcpu, struct kvm_mmu_page *page,
+static void FNAME(update_pte)(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp,
u64 *spte, const void *pte)
{
pt_element_t gpte;
@@ -263,7 +272,7 @@ static void FNAME(update_pte)(struct kvm_vcpu *vcpu, struct kvm_mmu_page *page,
gpte = *(const pt_element_t *)pte;
if (~gpte & (PT_PRESENT_MASK | PT_ACCESSED_MASK)) {
if (!is_present_gpte(gpte)) {
- if (page->unsync)
+ if (sp->unsync)
new_spte = shadow_trap_nonpresent_pte;
else
new_spte = shadow_notrap_nonpresent_pte;
@@ -272,7 +281,7 @@ static void FNAME(update_pte)(struct kvm_vcpu *vcpu, struct kvm_mmu_page *page,
return;
}
pgprintk("%s: gpte %llx spte %p\n", __func__, (u64)gpte, spte);
- pte_access = page->role.access & FNAME(gpte_access)(vcpu, gpte);
+ pte_access = sp->role.access & FNAME(gpte_access)(vcpu, gpte);
if (gpte_to_gfn(gpte) != vcpu->arch.update_pte.gfn)
return;
pfn = vcpu->arch.update_pte.pfn;
@@ -285,11 +294,22 @@ static void FNAME(update_pte)(struct kvm_vcpu *vcpu, struct kvm_mmu_page *page,
* we call mmu_set_spte() with reset_host_protection = true beacuse that
* vcpu->arch.update_pte.pfn was fetched from get_user_pages(write = 1).
*/
- mmu_set_spte(vcpu, spte, page->role.access, pte_access, 0, 0,
- gpte & PT_DIRTY_MASK, NULL, PT_PAGE_TABLE_LEVEL,
+ mmu_set_spte(vcpu, spte, sp->role.access, pte_access, 0, 0,
+ is_dirty_gpte(gpte), NULL, PT_PAGE_TABLE_LEVEL,
gpte_to_gfn(gpte), pfn, true, true);
}
+static bool FNAME(gpte_changed)(struct kvm_vcpu *vcpu,
+ struct guest_walker *gw, int level)
+{
+ int r;
+ pt_element_t curr_pte;
+
+ r = kvm_read_guest_atomic(vcpu->kvm, gw->pte_gpa[level - 1],
+ &curr_pte, sizeof(curr_pte));
+ return r || curr_pte != gw->ptes[level - 1];
+}
+
/*
* Fetch a shadow pte for a specific level in the paging hierarchy.
*/
@@ -299,75 +319,86 @@ static u64 *FNAME(fetch)(struct kvm_vcpu *vcpu, gva_t addr,
int *ptwrite, pfn_t pfn)
{
unsigned access = gw->pt_access;
- struct kvm_mmu_page *shadow_page;
- u64 spte, *sptep = NULL;
- int direct;
- gfn_t table_gfn;
- int r;
- int level;
- pt_element_t curr_pte;
- struct kvm_shadow_walk_iterator iterator;
+ struct kvm_mmu_page *sp = NULL;
+ bool dirty = is_dirty_gpte(gw->ptes[gw->level - 1]);
+ int top_level;
+ unsigned direct_access;
+ struct kvm_shadow_walk_iterator it;
if (!is_present_gpte(gw->ptes[gw->level - 1]))
return NULL;
- for_each_shadow_entry(vcpu, addr, iterator) {
- level = iterator.level;
- sptep = iterator.sptep;
- if (iterator.level == hlevel) {
- mmu_set_spte(vcpu, sptep, access,
- gw->pte_access & access,
- user_fault, write_fault,
- gw->ptes[gw->level-1] & PT_DIRTY_MASK,
- ptwrite, level,
- gw->gfn, pfn, false, true);
- break;
- }
+ direct_access = gw->pt_access & gw->pte_access;
+ if (!dirty)
+ direct_access &= ~ACC_WRITE_MASK;
- if (is_shadow_present_pte(*sptep) && !is_large_pte(*sptep))
- continue;
+ top_level = vcpu->arch.mmu.root_level;
+ if (top_level == PT32E_ROOT_LEVEL)
+ top_level = PT32_ROOT_LEVEL;
+ /*
+ * Verify that the top-level gpte is still there. Since the page
+ * is a root page, it is either write protected (and cannot be
+ * changed from now on) or it is invalid (in which case, we don't
+ * really care if it changes underneath us after this point).
+ */
+ if (FNAME(gpte_changed)(vcpu, gw, top_level))
+ goto out_gpte_changed;
- if (is_large_pte(*sptep)) {
- rmap_remove(vcpu->kvm, sptep);
- __set_spte(sptep, shadow_trap_nonpresent_pte);
- kvm_flush_remote_tlbs(vcpu->kvm);
- }
+ for (shadow_walk_init(&it, vcpu, addr);
+ shadow_walk_okay(&it) && it.level > gw->level;
+ shadow_walk_next(&it)) {
+ gfn_t table_gfn;
- if (level <= gw->level) {
- int delta = level - gw->level + 1;
- direct = 1;
- if (!is_dirty_gpte(gw->ptes[level - delta]))
- access &= ~ACC_WRITE_MASK;
- table_gfn = gpte_to_gfn(gw->ptes[level - delta]);
- /* advance table_gfn when emulating 1gb pages with 4k */
- if (delta == 0)
- table_gfn += PT_INDEX(addr, level);
- access &= gw->pte_access;
- } else {
- direct = 0;
- table_gfn = gw->table_gfn[level - 2];
- }
- shadow_page = kvm_mmu_get_page(vcpu, table_gfn, addr, level-1,
- direct, access, sptep);
- if (!direct) {
- r = kvm_read_guest_atomic(vcpu->kvm,
- gw->pte_gpa[level - 2],
- &curr_pte, sizeof(curr_pte));
- if (r || curr_pte != gw->ptes[level - 2]) {
- kvm_mmu_put_page(shadow_page, sptep);
- kvm_release_pfn_clean(pfn);
- sptep = NULL;
- break;
- }
+ drop_large_spte(vcpu, it.sptep);
+
+ sp = NULL;
+ if (!is_shadow_present_pte(*it.sptep)) {
+ table_gfn = gw->table_gfn[it.level - 2];
+ sp = kvm_mmu_get_page(vcpu, table_gfn, addr, it.level-1,
+ false, access, it.sptep);
}
- spte = __pa(shadow_page->spt)
- | PT_PRESENT_MASK | PT_ACCESSED_MASK
- | PT_WRITABLE_MASK | PT_USER_MASK;
- *sptep = spte;
+ /*
+ * Verify that the gpte in the page we've just write
+ * protected is still there.
+ */
+ if (FNAME(gpte_changed)(vcpu, gw, it.level - 1))
+ goto out_gpte_changed;
+
+ if (sp)
+ link_shadow_page(it.sptep, sp);
}
- return sptep;
+ for (;
+ shadow_walk_okay(&it) && it.level > hlevel;
+ shadow_walk_next(&it)) {
+ gfn_t direct_gfn;
+
+ validate_direct_spte(vcpu, it.sptep, direct_access);
+
+ drop_large_spte(vcpu, it.sptep);
+
+ if (is_shadow_present_pte(*it.sptep))
+ continue;
+
+ direct_gfn = gw->gfn & ~(KVM_PAGES_PER_HPAGE(it.level) - 1);
+
+ sp = kvm_mmu_get_page(vcpu, direct_gfn, addr, it.level-1,
+ true, direct_access, it.sptep);
+ link_shadow_page(it.sptep, sp);
+ }
+
+ mmu_set_spte(vcpu, it.sptep, access, gw->pte_access & access,
+ user_fault, write_fault, dirty, ptwrite, it.level,
+ gw->gfn, pfn, false, true);
+
+ return it.sptep;
+
+out_gpte_changed:
+ if (sp)
+ kvm_mmu_put_page(sp, it.sptep);
+ kvm_release_pfn_clean(pfn);
+ return NULL;
}
/*
@@ -431,11 +462,8 @@ static int FNAME(page_fault)(struct kvm_vcpu *vcpu, gva_t addr,
pfn = gfn_to_pfn(vcpu->kvm, walker.gfn);
/* mmio */
- if (is_error_pfn(pfn)) {
- pgprintk("gfn %lx is mmio\n", walker.gfn);
- kvm_release_pfn_clean(pfn);
- return 1;
- }
+ if (is_error_pfn(pfn))
+ return kvm_handle_bad_page(vcpu->kvm, walker.gfn, pfn);
spin_lock(&vcpu->kvm->mmu_lock);
if (mmu_notifier_retry(vcpu, mmu_seq))
@@ -443,6 +471,7 @@ static int FNAME(page_fault)(struct kvm_vcpu *vcpu, gva_t addr,
kvm_mmu_free_some_pages(vcpu);
sptep = FNAME(fetch)(vcpu, addr, &walker, user_fault, write_fault,
level, &write_pt, pfn);
+ (void)sptep;
pgprintk("%s: shadow pte %p %llx ptwrite %d\n", __func__,
sptep, *sptep, write_pt);
@@ -464,6 +493,7 @@ out_unlock:
static void FNAME(invlpg)(struct kvm_vcpu *vcpu, gva_t gva)
{
struct kvm_shadow_walk_iterator iterator;
+ struct kvm_mmu_page *sp;
gpa_t pte_gpa = -1;
int level;
u64 *sptep;
@@ -475,10 +505,13 @@ static void FNAME(invlpg)(struct kvm_vcpu *vcpu, gva_t gva)
level = iterator.level;
sptep = iterator.sptep;
+ sp = page_header(__pa(sptep));
if (is_last_spte(*sptep, level)) {
- struct kvm_mmu_page *sp = page_header(__pa(sptep));
int offset, shift;
+ if (!sp->unsync)
+ break;
+
shift = PAGE_SHIFT -
(PT_LEVEL_BITS - PT64_LEVEL_BITS) * level;
offset = sp->role.quadrant << shift;
@@ -487,16 +520,17 @@ static void FNAME(invlpg)(struct kvm_vcpu *vcpu, gva_t gva)
pte_gpa += (sptep - sp->spt) * sizeof(pt_element_t);
if (is_shadow_present_pte(*sptep)) {
- rmap_remove(vcpu->kvm, sptep);
if (is_large_pte(*sptep))
--vcpu->kvm->stat.lpages;
+ drop_spte(vcpu->kvm, sptep,
+ shadow_trap_nonpresent_pte);
need_flush = 1;
- }
- __set_spte(sptep, shadow_trap_nonpresent_pte);
+ } else
+ __set_spte(sptep, shadow_trap_nonpresent_pte);
break;
}
- if (!is_shadow_present_pte(*sptep))
+ if (!is_shadow_present_pte(*sptep) || !sp->unsync_children)
break;
}
@@ -570,9 +604,9 @@ static void FNAME(prefetch_page)(struct kvm_vcpu *vcpu,
* Using the cached information from sp->gfns is safe because:
* - The spte has a reference to the struct page, so the pfn for a given gfn
* can't change unless all sptes pointing to it are nuked first.
- * - Alias changes zap the entire shadow cache.
*/
-static int FNAME(sync_page)(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp)
+static int FNAME(sync_page)(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp,
+ bool clear_unsync)
{
int i, offset, nr_present;
bool reset_host_protection;
@@ -580,6 +614,9 @@ static int FNAME(sync_page)(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp)
offset = nr_present = 0;
+ /* direct kvm_mmu_page can not be unsync. */
+ BUG_ON(sp->role.direct);
+
if (PTTYPE == 32)
offset = sp->role.quadrant << PT64_LEVEL_BITS;
@@ -589,7 +626,7 @@ static int FNAME(sync_page)(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp)
unsigned pte_access;
pt_element_t gpte;
gpa_t pte_gpa;
- gfn_t gfn = sp->gfns[i];
+ gfn_t gfn;
if (!is_shadow_present_pte(sp->spt[i]))
continue;
@@ -600,16 +637,17 @@ static int FNAME(sync_page)(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp)
sizeof(pt_element_t)))
return -EINVAL;
- if (gpte_to_gfn(gpte) != gfn || !is_present_gpte(gpte) ||
- !(gpte & PT_ACCESSED_MASK)) {
+ gfn = gpte_to_gfn(gpte);
+ if (is_rsvd_bits_set(vcpu, gpte, PT_PAGE_TABLE_LEVEL)
+ || gfn != sp->gfns[i] || !is_present_gpte(gpte)
+ || !(gpte & PT_ACCESSED_MASK)) {
u64 nonpresent;
- rmap_remove(vcpu->kvm, &sp->spt[i]);
- if (is_present_gpte(gpte))
+ if (is_present_gpte(gpte) || !clear_unsync)
nonpresent = shadow_trap_nonpresent_pte;
else
nonpresent = shadow_notrap_nonpresent_pte;
- __set_spte(&sp->spt[i], nonpresent);
+ drop_spte(vcpu->kvm, &sp->spt[i], nonpresent);
continue;
}
diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c
index ce438e0fdd2..bc5b9b8d4a3 100644
--- a/arch/x86/kvm/svm.c
+++ b/arch/x86/kvm/svm.c
@@ -4,6 +4,7 @@
* AMD SVM support
*
* Copyright (C) 2006 Qumranet, Inc.
+ * Copyright 2010 Red Hat, Inc. and/or its affilates.
*
* Authors:
* Yaniv Kamay <yaniv@qumranet.com>
@@ -130,7 +131,7 @@ static struct svm_direct_access_msrs {
u32 index; /* Index of the MSR */
bool always; /* True if intercept is always on */
} direct_access_msrs[] = {
- { .index = MSR_K6_STAR, .always = true },
+ { .index = MSR_STAR, .always = true },
{ .index = MSR_IA32_SYSENTER_CS, .always = true },
#ifdef CONFIG_X86_64
{ .index = MSR_GS_BASE, .always = true },
@@ -285,11 +286,11 @@ static inline void flush_guest_tlb(struct kvm_vcpu *vcpu)
static void svm_set_efer(struct kvm_vcpu *vcpu, u64 efer)
{
+ vcpu->arch.efer = efer;
if (!npt_enabled && !(efer & EFER_LMA))
efer &= ~EFER_LME;
to_svm(vcpu)->vmcb->save.efer = efer | EFER_SVME;
- vcpu->arch.efer = efer;
}
static int is_external_interrupt(u32 info)
@@ -383,8 +384,7 @@ static void svm_init_erratum_383(void)
int err;
u64 val;
- /* Only Fam10h is affected */
- if (boot_cpu_data.x86 != 0x10)
+ if (!cpu_has_amd_erratum(amd_erratum_383))
return;
/* Use _safe variants to not break nested virtualization */
@@ -640,7 +640,7 @@ static __init int svm_hardware_setup(void)
if (nested) {
printk(KERN_INFO "kvm: Nested Virtualization enabled\n");
- kvm_enable_efer_bits(EFER_SVME);
+ kvm_enable_efer_bits(EFER_SVME | EFER_LMSLE);
}
for_each_possible_cpu(cpu) {
@@ -806,7 +806,7 @@ static void init_vmcb(struct vcpu_svm *svm)
* svm_set_cr0() sets PG and WP and clears NW and CD on save->cr0.
*/
svm->vcpu.arch.cr0 = X86_CR0_NW | X86_CR0_CD | X86_CR0_ET;
- kvm_set_cr0(&svm->vcpu, svm->vcpu.arch.cr0);
+ (void)kvm_set_cr0(&svm->vcpu, svm->vcpu.arch.cr0);
save->cr4 = X86_CR4_PAE;
/* rdx = ?? */
@@ -903,13 +903,18 @@ static struct kvm_vcpu *svm_create_vcpu(struct kvm *kvm, unsigned int id)
svm->asid_generation = 0;
init_vmcb(svm);
- fx_init(&svm->vcpu);
+ err = fx_init(&svm->vcpu);
+ if (err)
+ goto free_page4;
+
svm->vcpu.arch.apic_base = 0xfee00000 | MSR_IA32_APICBASE_ENABLE;
if (kvm_vcpu_is_bsp(&svm->vcpu))
svm->vcpu.arch.apic_base |= MSR_IA32_APICBASE_BSP;
return &svm->vcpu;
+free_page4:
+ __free_page(hsave_page);
free_page3:
__free_pages(nested_msrpm_pages, MSRPM_ALLOC_ORDER);
free_page2:
@@ -1488,7 +1493,7 @@ static void svm_handle_mce(struct vcpu_svm *svm)
*/
pr_err("KVM: Guest triggered AMD Erratum 383\n");
- set_bit(KVM_REQ_TRIPLE_FAULT, &svm->vcpu.requests);
+ kvm_make_request(KVM_REQ_TRIPLE_FAULT, &svm->vcpu);
return;
}
@@ -1535,7 +1540,7 @@ static int io_interception(struct vcpu_svm *svm)
string = (io_info & SVM_IOIO_STR_MASK) != 0;
in = (io_info & SVM_IOIO_TYPE_MASK) != 0;
if (string || in)
- return !(emulate_instruction(vcpu, 0, 0, 0) == EMULATE_DO_MMIO);
+ return emulate_instruction(vcpu, 0, 0, 0) == EMULATE_DONE;
port = io_info >> 16;
size = (io_info & SVM_IOIO_SIZE_MASK) >> SVM_IOIO_SIZE_SHIFT;
@@ -1957,7 +1962,7 @@ static int nested_svm_vmexit(struct vcpu_svm *svm)
svm->vmcb->save.cr3 = hsave->save.cr3;
svm->vcpu.arch.cr3 = hsave->save.cr3;
} else {
- kvm_set_cr3(&svm->vcpu, hsave->save.cr3);
+ (void)kvm_set_cr3(&svm->vcpu, hsave->save.cr3);
}
kvm_register_write(&svm->vcpu, VCPU_REGS_RAX, hsave->save.rax);
kvm_register_write(&svm->vcpu, VCPU_REGS_RSP, hsave->save.rsp);
@@ -2080,7 +2085,7 @@ static bool nested_svm_vmrun(struct vcpu_svm *svm)
svm->vmcb->save.cr3 = nested_vmcb->save.cr3;
svm->vcpu.arch.cr3 = nested_vmcb->save.cr3;
} else
- kvm_set_cr3(&svm->vcpu, nested_vmcb->save.cr3);
+ (void)kvm_set_cr3(&svm->vcpu, nested_vmcb->save.cr3);
/* Guest paging mode is active - reset mmu */
kvm_mmu_reset_context(&svm->vcpu);
@@ -2386,16 +2391,12 @@ static int iret_interception(struct vcpu_svm *svm)
static int invlpg_interception(struct vcpu_svm *svm)
{
- if (emulate_instruction(&svm->vcpu, 0, 0, 0) != EMULATE_DONE)
- pr_unimpl(&svm->vcpu, "%s: failed\n", __func__);
- return 1;
+ return emulate_instruction(&svm->vcpu, 0, 0, 0) == EMULATE_DONE;
}
static int emulate_on_interception(struct vcpu_svm *svm)
{
- if (emulate_instruction(&svm->vcpu, 0, 0, 0) != EMULATE_DONE)
- pr_unimpl(&svm->vcpu, "%s: failed\n", __func__);
- return 1;
+ return emulate_instruction(&svm->vcpu, 0, 0, 0) == EMULATE_DONE;
}
static int cr8_write_interception(struct vcpu_svm *svm)
@@ -2431,7 +2432,7 @@ static int svm_get_msr(struct kvm_vcpu *vcpu, unsigned ecx, u64 *data)
*data = tsc_offset + native_read_tsc();
break;
}
- case MSR_K6_STAR:
+ case MSR_STAR:
*data = svm->vmcb->save.star;
break;
#ifdef CONFIG_X86_64
@@ -2555,7 +2556,7 @@ static int svm_set_msr(struct kvm_vcpu *vcpu, unsigned ecx, u64 data)
break;
}
- case MSR_K6_STAR:
+ case MSR_STAR:
svm->vmcb->save.star = data;
break;
#ifdef CONFIG_X86_64
@@ -2726,6 +2727,99 @@ static int (*svm_exit_handlers[])(struct vcpu_svm *svm) = {
[SVM_EXIT_NPF] = pf_interception,
};
+void dump_vmcb(struct kvm_vcpu *vcpu)
+{
+ struct vcpu_svm *svm = to_svm(vcpu);
+ struct vmcb_control_area *control = &svm->vmcb->control;
+ struct vmcb_save_area *save = &svm->vmcb->save;
+
+ pr_err("VMCB Control Area:\n");
+ pr_err("cr_read: %04x\n", control->intercept_cr_read);
+ pr_err("cr_write: %04x\n", control->intercept_cr_write);
+ pr_err("dr_read: %04x\n", control->intercept_dr_read);
+ pr_err("dr_write: %04x\n", control->intercept_dr_write);
+ pr_err("exceptions: %08x\n", control->intercept_exceptions);
+ pr_err("intercepts: %016llx\n", control->intercept);
+ pr_err("pause filter count: %d\n", control->pause_filter_count);
+ pr_err("iopm_base_pa: %016llx\n", control->iopm_base_pa);
+ pr_err("msrpm_base_pa: %016llx\n", control->msrpm_base_pa);
+ pr_err("tsc_offset: %016llx\n", control->tsc_offset);
+ pr_err("asid: %d\n", control->asid);
+ pr_err("tlb_ctl: %d\n", control->tlb_ctl);
+ pr_err("int_ctl: %08x\n", control->int_ctl);
+ pr_err("int_vector: %08x\n", control->int_vector);
+ pr_err("int_state: %08x\n", control->int_state);
+ pr_err("exit_code: %08x\n", control->exit_code);
+ pr_err("exit_info1: %016llx\n", control->exit_info_1);
+ pr_err("exit_info2: %016llx\n", control->exit_info_2);
+ pr_err("exit_int_info: %08x\n", control->exit_int_info);
+ pr_err("exit_int_info_err: %08x\n", control->exit_int_info_err);
+ pr_err("nested_ctl: %lld\n", control->nested_ctl);
+ pr_err("nested_cr3: %016llx\n", control->nested_cr3);
+ pr_err("event_inj: %08x\n", control->event_inj);
+ pr_err("event_inj_err: %08x\n", control->event_inj_err);
+ pr_err("lbr_ctl: %lld\n", control->lbr_ctl);
+ pr_err("next_rip: %016llx\n", control->next_rip);
+ pr_err("VMCB State Save Area:\n");
+ pr_err("es: s: %04x a: %04x l: %08x b: %016llx\n",
+ save->es.selector, save->es.attrib,
+ save->es.limit, save->es.base);
+ pr_err("cs: s: %04x a: %04x l: %08x b: %016llx\n",
+ save->cs.selector, save->cs.attrib,
+ save->cs.limit, save->cs.base);
+ pr_err("ss: s: %04x a: %04x l: %08x b: %016llx\n",
+ save->ss.selector, save->ss.attrib,
+ save->ss.limit, save->ss.base);
+ pr_err("ds: s: %04x a: %04x l: %08x b: %016llx\n",
+ save->ds.selector, save->ds.attrib,
+ save->ds.limit, save->ds.base);
+ pr_err("fs: s: %04x a: %04x l: %08x b: %016llx\n",
+ save->fs.selector, save->fs.attrib,
+ save->fs.limit, save->fs.base);
+ pr_err("gs: s: %04x a: %04x l: %08x b: %016llx\n",
+ save->gs.selector, save->gs.attrib,
+ save->gs.limit, save->gs.base);
+ pr_err("gdtr: s: %04x a: %04x l: %08x b: %016llx\n",
+ save->gdtr.selector, save->gdtr.attrib,
+ save->gdtr.limit, save->gdtr.base);
+ pr_err("ldtr: s: %04x a: %04x l: %08x b: %016llx\n",
+ save->ldtr.selector, save->ldtr.attrib,
+ save->ldtr.limit, save->ldtr.base);
+ pr_err("idtr: s: %04x a: %04x l: %08x b: %016llx\n",
+ save->idtr.selector, save->idtr.attrib,
+ save->idtr.limit, save->idtr.base);
+ pr_err("tr: s: %04x a: %04x l: %08x b: %016llx\n",
+ save->tr.selector, save->tr.attrib,
+ save->tr.limit, save->tr.base);
+ pr_err("cpl: %d efer: %016llx\n",
+ save->cpl, save->efer);
+ pr_err("cr0: %016llx cr2: %016llx\n",
+ save->cr0, save->cr2);
+ pr_err("cr3: %016llx cr4: %016llx\n",
+ save->cr3, save->cr4);
+ pr_err("dr6: %016llx dr7: %016llx\n",
+ save->dr6, save->dr7);
+ pr_err("rip: %016llx rflags: %016llx\n",
+ save->rip, save->rflags);
+ pr_err("rsp: %016llx rax: %016llx\n",
+ save->rsp, save->rax);
+ pr_err("star: %016llx lstar: %016llx\n",
+ save->star, save->lstar);
+ pr_err("cstar: %016llx sfmask: %016llx\n",
+ save->cstar, save->sfmask);
+ pr_err("kernel_gs_base: %016llx sysenter_cs: %016llx\n",
+ save->kernel_gs_base, save->sysenter_cs);
+ pr_err("sysenter_esp: %016llx sysenter_eip: %016llx\n",
+ save->sysenter_esp, save->sysenter_eip);
+ pr_err("gpat: %016llx dbgctl: %016llx\n",
+ save->g_pat, save->dbgctl);
+ pr_err("br_from: %016llx br_to: %016llx\n",
+ save->br_from, save->br_to);
+ pr_err("excp_from: %016llx excp_to: %016llx\n",
+ save->last_excp_from, save->last_excp_to);
+
+}
+
static int handle_exit(struct kvm_vcpu *vcpu)
{
struct vcpu_svm *svm = to_svm(vcpu);
@@ -2770,6 +2864,8 @@ static int handle_exit(struct kvm_vcpu *vcpu)
kvm_run->exit_reason = KVM_EXIT_FAIL_ENTRY;
kvm_run->fail_entry.hardware_entry_failure_reason
= svm->vmcb->control.exit_code;
+ pr_err("KVM: FAILED VMRUN WITH VMCB:\n");
+ dump_vmcb(vcpu);
return 0;
}
@@ -2826,9 +2922,6 @@ static inline void svm_inject_irq(struct vcpu_svm *svm, int irq)
{
struct vmcb_control_area *control;
- trace_kvm_inj_virq(irq);
-
- ++svm->vcpu.stat.irq_injections;
control = &svm->vmcb->control;
control->int_vector = irq;
control->int_ctl &= ~V_INTR_PRIO_MASK;
@@ -2842,6 +2935,9 @@ static void svm_set_irq(struct kvm_vcpu *vcpu)
BUG_ON(!(gif_set(svm)));
+ trace_kvm_inj_virq(vcpu->arch.interrupt.nr);
+ ++vcpu->stat.irq_injections;
+
svm->vmcb->control.event_inj = vcpu->arch.interrupt.nr |
SVM_EVTINJ_VALID | SVM_EVTINJ_TYPE_INTR;
}
@@ -3327,6 +3423,11 @@ static bool svm_rdtscp_supported(void)
return false;
}
+static bool svm_has_wbinvd_exit(void)
+{
+ return true;
+}
+
static void svm_fpu_deactivate(struct kvm_vcpu *vcpu)
{
struct vcpu_svm *svm = to_svm(vcpu);
@@ -3411,6 +3512,8 @@ static struct kvm_x86_ops svm_x86_ops = {
.rdtscp_supported = svm_rdtscp_supported,
.set_supported_cpuid = svm_set_supported_cpuid,
+
+ .has_wbinvd_exit = svm_has_wbinvd_exit,
};
static int __init svm_init(void)
diff --git a/arch/x86/kvm/timer.c b/arch/x86/kvm/timer.c
index 4ddadb1a5ff..e16a0dbe74d 100644
--- a/arch/x86/kvm/timer.c
+++ b/arch/x86/kvm/timer.c
@@ -1,3 +1,17 @@
+/*
+ * Kernel-based Virtual Machine driver for Linux
+ *
+ * This module enables machines with Intel VT-x extensions to run virtual
+ * machines without emulation or binary translation.
+ *
+ * timer support
+ *
+ * Copyright 2010 Red Hat, Inc. and/or its affilates.
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2. See
+ * the COPYING file in the top-level directory.
+ */
+
#include <linux/kvm_host.h>
#include <linux/kvm.h>
#include <linux/hrtimer.h>
@@ -18,7 +32,7 @@ static int __kvm_timer_fn(struct kvm_vcpu *vcpu, struct kvm_timer *ktimer)
if (ktimer->reinject || !atomic_read(&ktimer->pending)) {
atomic_inc(&ktimer->pending);
/* FIXME: this code should not know anything about vcpus */
- set_bit(KVM_REQ_PENDING_TIMER, &vcpu->requests);
+ kvm_make_request(KVM_REQ_PENDING_TIMER, vcpu);
}
if (waitqueue_active(q))
diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
index ee03679efe7..49b25eee25a 100644
--- a/arch/x86/kvm/vmx.c
+++ b/arch/x86/kvm/vmx.c
@@ -5,6 +5,7 @@
* machines without emulation or binary translation.
*
* Copyright (C) 2006 Qumranet, Inc.
+ * Copyright 2010 Red Hat, Inc. and/or its affilates.
*
* Authors:
* Avi Kivity <avi@qumranet.com>
@@ -36,6 +37,8 @@
#include <asm/vmx.h>
#include <asm/virtext.h>
#include <asm/mce.h>
+#include <asm/i387.h>
+#include <asm/xcr.h>
#include "trace.h"
@@ -63,6 +66,9 @@ module_param_named(unrestricted_guest,
static int __read_mostly emulate_invalid_guest_state = 0;
module_param(emulate_invalid_guest_state, bool, S_IRUGO);
+static int __read_mostly vmm_exclusive = 1;
+module_param(vmm_exclusive, bool, S_IRUGO);
+
#define KVM_GUEST_CR0_MASK_UNRESTRICTED_GUEST \
(X86_CR0_WP | X86_CR0_NE | X86_CR0_NW | X86_CR0_CD)
#define KVM_GUEST_CR0_MASK \
@@ -173,10 +179,13 @@ static inline struct vcpu_vmx *to_vmx(struct kvm_vcpu *vcpu)
static int init_rmode(struct kvm *kvm);
static u64 construct_eptp(unsigned long root_hpa);
+static void kvm_cpu_vmxon(u64 addr);
+static void kvm_cpu_vmxoff(void);
static DEFINE_PER_CPU(struct vmcs *, vmxarea);
static DEFINE_PER_CPU(struct vmcs *, current_vmcs);
static DEFINE_PER_CPU(struct list_head, vcpus_on_cpu);
+static DEFINE_PER_CPU(struct desc_ptr, host_gdt);
static unsigned long *vmx_io_bitmap_a;
static unsigned long *vmx_io_bitmap_b;
@@ -231,14 +240,14 @@ static u64 host_efer;
static void ept_save_pdptrs(struct kvm_vcpu *vcpu);
/*
- * Keep MSR_K6_STAR at the end, as setup_msrs() will try to optimize it
+ * Keep MSR_STAR at the end, as setup_msrs() will try to optimize it
* away by decrementing the array size.
*/
static const u32 vmx_msr_index[] = {
#ifdef CONFIG_X86_64
MSR_SYSCALL_MASK, MSR_LSTAR, MSR_CSTAR,
#endif
- MSR_EFER, MSR_TSC_AUX, MSR_K6_STAR,
+ MSR_EFER, MSR_TSC_AUX, MSR_STAR,
};
#define NR_VMX_MSR ARRAY_SIZE(vmx_msr_index)
@@ -334,6 +343,11 @@ static inline bool cpu_has_vmx_ept_1g_page(void)
return vmx_capability.ept & VMX_EPT_1GB_PAGE_BIT;
}
+static inline bool cpu_has_vmx_ept_4levels(void)
+{
+ return vmx_capability.ept & VMX_EPT_PAGE_WALK_4_BIT;
+}
+
static inline bool cpu_has_vmx_invept_individual_addr(void)
{
return vmx_capability.ept & VMX_EPT_EXTENT_INDIVIDUAL_BIT;
@@ -349,6 +363,16 @@ static inline bool cpu_has_vmx_invept_global(void)
return vmx_capability.ept & VMX_EPT_EXTENT_GLOBAL_BIT;
}
+static inline bool cpu_has_vmx_invvpid_single(void)
+{
+ return vmx_capability.vpid & VMX_VPID_EXTENT_SINGLE_CONTEXT_BIT;
+}
+
+static inline bool cpu_has_vmx_invvpid_global(void)
+{
+ return vmx_capability.vpid & VMX_VPID_EXTENT_GLOBAL_CONTEXT_BIT;
+}
+
static inline bool cpu_has_vmx_ept(void)
{
return vmcs_config.cpu_based_2nd_exec_ctrl &
@@ -389,6 +413,12 @@ static inline bool cpu_has_virtual_nmis(void)
return vmcs_config.pin_based_exec_ctrl & PIN_BASED_VIRTUAL_NMIS;
}
+static inline bool cpu_has_vmx_wbinvd_exit(void)
+{
+ return vmcs_config.cpu_based_2nd_exec_ctrl &
+ SECONDARY_EXEC_WBINVD_EXITING;
+}
+
static inline bool report_flexpriority(void)
{
return flexpriority_enabled;
@@ -453,6 +483,19 @@ static void vmcs_clear(struct vmcs *vmcs)
vmcs, phys_addr);
}
+static void vmcs_load(struct vmcs *vmcs)
+{
+ u64 phys_addr = __pa(vmcs);
+ u8 error;
+
+ asm volatile (__ex(ASM_VMX_VMPTRLD_RAX) "; setna %0"
+ : "=g"(error) : "a"(&phys_addr), "m"(phys_addr)
+ : "cc", "memory");
+ if (error)
+ printk(KERN_ERR "kvm: vmptrld %p/%llx fail\n",
+ vmcs, phys_addr);
+}
+
static void __vcpu_clear(void *arg)
{
struct vcpu_vmx *vmx = arg;
@@ -475,12 +518,27 @@ static void vcpu_clear(struct vcpu_vmx *vmx)
smp_call_function_single(vmx->vcpu.cpu, __vcpu_clear, vmx, 1);
}
-static inline void vpid_sync_vcpu_all(struct vcpu_vmx *vmx)
+static inline void vpid_sync_vcpu_single(struct vcpu_vmx *vmx)
{
if (vmx->vpid == 0)
return;
- __invvpid(VMX_VPID_EXTENT_SINGLE_CONTEXT, vmx->vpid, 0);
+ if (cpu_has_vmx_invvpid_single())
+ __invvpid(VMX_VPID_EXTENT_SINGLE_CONTEXT, vmx->vpid, 0);
+}
+
+static inline void vpid_sync_vcpu_global(void)
+{
+ if (cpu_has_vmx_invvpid_global())
+ __invvpid(VMX_VPID_EXTENT_ALL_CONTEXT, 0, 0);
+}
+
+static inline void vpid_sync_context(struct vcpu_vmx *vmx)
+{
+ if (cpu_has_vmx_invvpid_single())
+ vpid_sync_vcpu_single(vmx);
+ else
+ vpid_sync_vcpu_global();
}
static inline void ept_sync_global(void)
@@ -812,6 +870,9 @@ static void __vmx_load_host_state(struct vcpu_vmx *vmx)
wrmsrl(MSR_KERNEL_GS_BASE, vmx->msr_host_kernel_gs_base);
}
#endif
+ if (current_thread_info()->status & TS_USEDFPU)
+ clts();
+ load_gdt(&__get_cpu_var(host_gdt));
}
static void vmx_load_host_state(struct vcpu_vmx *vmx)
@@ -828,35 +889,30 @@ static void vmx_load_host_state(struct vcpu_vmx *vmx)
static void vmx_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
{
struct vcpu_vmx *vmx = to_vmx(vcpu);
- u64 phys_addr = __pa(vmx->vmcs);
u64 tsc_this, delta, new_offset;
+ u64 phys_addr = __pa(per_cpu(vmxarea, cpu));
- if (vcpu->cpu != cpu) {
+ if (!vmm_exclusive)
+ kvm_cpu_vmxon(phys_addr);
+ else if (vcpu->cpu != cpu)
vcpu_clear(vmx);
- kvm_migrate_timers(vcpu);
- set_bit(KVM_REQ_TLB_FLUSH, &vcpu->requests);
- local_irq_disable();
- list_add(&vmx->local_vcpus_link,
- &per_cpu(vcpus_on_cpu, cpu));
- local_irq_enable();
- }
if (per_cpu(current_vmcs, cpu) != vmx->vmcs) {
- u8 error;
-
per_cpu(current_vmcs, cpu) = vmx->vmcs;
- asm volatile (__ex(ASM_VMX_VMPTRLD_RAX) "; setna %0"
- : "=g"(error) : "a"(&phys_addr), "m"(phys_addr)
- : "cc");
- if (error)
- printk(KERN_ERR "kvm: vmptrld %p/%llx fail\n",
- vmx->vmcs, phys_addr);
+ vmcs_load(vmx->vmcs);
}
if (vcpu->cpu != cpu) {
struct desc_ptr dt;
unsigned long sysenter_esp;
+ kvm_migrate_timers(vcpu);
+ kvm_make_request(KVM_REQ_TLB_FLUSH, vcpu);
+ local_irq_disable();
+ list_add(&vmx->local_vcpus_link,
+ &per_cpu(vcpus_on_cpu, cpu));
+ local_irq_enable();
+
vcpu->cpu = cpu;
/*
* Linux uses per-cpu TSS and GDT, so set these when switching
@@ -884,6 +940,10 @@ static void vmx_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
static void vmx_vcpu_put(struct kvm_vcpu *vcpu)
{
__vmx_load_host_state(to_vmx(vcpu));
+ if (!vmm_exclusive) {
+ __vcpu_clear(to_vmx(vcpu));
+ kvm_cpu_vmxoff();
+ }
}
static void vmx_fpu_activate(struct kvm_vcpu *vcpu)
@@ -1057,10 +1117,10 @@ static void setup_msrs(struct vcpu_vmx *vmx)
if (index >= 0 && vmx->rdtscp_enabled)
move_msr_up(vmx, index, save_nmsrs++);
/*
- * MSR_K6_STAR is only needed on long mode guests, and only
+ * MSR_STAR is only needed on long mode guests, and only
* if efer.sce is enabled.
*/
- index = __find_msr_index(vmx, MSR_K6_STAR);
+ index = __find_msr_index(vmx, MSR_STAR);
if ((index >= 0) && (vmx->vcpu.arch.efer & EFER_SCE))
move_msr_up(vmx, index, save_nmsrs++);
}
@@ -1286,6 +1346,13 @@ static __init int vmx_disabled_by_bios(void)
/* locked but not enabled */
}
+static void kvm_cpu_vmxon(u64 addr)
+{
+ asm volatile (ASM_VMX_VMXON_RAX
+ : : "a"(&addr), "m"(addr)
+ : "memory", "cc");
+}
+
static int hardware_enable(void *garbage)
{
int cpu = raw_smp_processor_id();
@@ -1308,11 +1375,13 @@ static int hardware_enable(void *garbage)
wrmsrl(MSR_IA32_FEATURE_CONTROL, old | test_bits);
}
write_cr4(read_cr4() | X86_CR4_VMXE); /* FIXME: not cpu hotplug safe */
- asm volatile (ASM_VMX_VMXON_RAX
- : : "a"(&phys_addr), "m"(phys_addr)
- : "memory", "cc");
- ept_sync_global();
+ if (vmm_exclusive) {
+ kvm_cpu_vmxon(phys_addr);
+ ept_sync_global();
+ }
+
+ store_gdt(&__get_cpu_var(host_gdt));
return 0;
}
@@ -1334,13 +1403,15 @@ static void vmclear_local_vcpus(void)
static void kvm_cpu_vmxoff(void)
{
asm volatile (__ex(ASM_VMX_VMXOFF) : : : "cc");
- write_cr4(read_cr4() & ~X86_CR4_VMXE);
}
static void hardware_disable(void *garbage)
{
- vmclear_local_vcpus();
- kvm_cpu_vmxoff();
+ if (vmm_exclusive) {
+ vmclear_local_vcpus();
+ kvm_cpu_vmxoff();
+ }
+ write_cr4(read_cr4() & ~X86_CR4_VMXE);
}
static __init int adjust_vmx_controls(u32 ctl_min, u32 ctl_opt,
@@ -1539,7 +1610,8 @@ static __init int hardware_setup(void)
if (!cpu_has_vmx_vpid())
enable_vpid = 0;
- if (!cpu_has_vmx_ept()) {
+ if (!cpu_has_vmx_ept() ||
+ !cpu_has_vmx_ept_4levels()) {
enable_ept = 0;
enable_unrestricted_guest = 0;
}
@@ -1628,7 +1700,7 @@ static gva_t rmode_tss_base(struct kvm *kvm)
gfn_t base_gfn;
slots = kvm_memslots(kvm);
- base_gfn = kvm->memslots->memslots[0].base_gfn +
+ base_gfn = slots->memslots[0].base_gfn +
kvm->memslots->memslots[0].npages - 3;
return base_gfn << PAGE_SHIFT;
}
@@ -1759,9 +1831,12 @@ static void exit_lmode(struct kvm_vcpu *vcpu)
static void vmx_flush_tlb(struct kvm_vcpu *vcpu)
{
- vpid_sync_vcpu_all(to_vmx(vcpu));
- if (enable_ept)
+ vpid_sync_context(to_vmx(vcpu));
+ if (enable_ept) {
+ if (!VALID_PAGE(vcpu->arch.mmu.root_hpa))
+ return;
ept_sync_context(construct_eptp(vcpu->arch.mmu.root_hpa));
+ }
}
static void vmx_decache_cr0_guest_bits(struct kvm_vcpu *vcpu)
@@ -2507,7 +2582,7 @@ static int vmx_vcpu_setup(struct vcpu_vmx *vmx)
vmcs_write32(PAGE_FAULT_ERROR_CODE_MATCH, !!bypass_guest_pf);
vmcs_write32(CR3_TARGET_COUNT, 0); /* 22.2.1 */
- vmcs_writel(HOST_CR0, read_cr0()); /* 22.2.3 */
+ vmcs_writel(HOST_CR0, read_cr0() | X86_CR0_TS); /* 22.2.3 */
vmcs_writel(HOST_CR4, read_cr4()); /* 22.2.3, 22.2.5 */
vmcs_writel(HOST_CR3, read_cr3()); /* 22.2.3 FIXME: shadow tables */
@@ -2599,21 +2674,27 @@ static int vmx_vcpu_setup(struct vcpu_vmx *vmx)
static int init_rmode(struct kvm *kvm)
{
+ int idx, ret = 0;
+
+ idx = srcu_read_lock(&kvm->srcu);
if (!init_rmode_tss(kvm))
- return 0;
+ goto exit;
if (!init_rmode_identity_map(kvm))
- return 0;
- return 1;
+ goto exit;
+
+ ret = 1;
+exit:
+ srcu_read_unlock(&kvm->srcu, idx);
+ return ret;
}
static int vmx_vcpu_reset(struct kvm_vcpu *vcpu)
{
struct vcpu_vmx *vmx = to_vmx(vcpu);
u64 msr;
- int ret, idx;
+ int ret;
vcpu->arch.regs_avail = ~((1 << VCPU_REGS_RIP) | (1 << VCPU_REGS_RSP));
- idx = srcu_read_lock(&vcpu->kvm->srcu);
if (!init_rmode(vmx->vcpu.kvm)) {
ret = -ENOMEM;
goto out;
@@ -2630,7 +2711,9 @@ static int vmx_vcpu_reset(struct kvm_vcpu *vcpu)
msr |= MSR_IA32_APICBASE_BSP;
kvm_set_apic_base(&vmx->vcpu, msr);
- fx_init(&vmx->vcpu);
+ ret = fx_init(&vmx->vcpu);
+ if (ret != 0)
+ goto out;
seg_setup(VCPU_SREG_CS);
/*
@@ -2713,7 +2796,7 @@ static int vmx_vcpu_reset(struct kvm_vcpu *vcpu)
vmx_fpu_activate(&vmx->vcpu);
update_exception_bitmap(&vmx->vcpu);
- vpid_sync_vcpu_all(vmx);
+ vpid_sync_context(vmx);
ret = 0;
@@ -2721,7 +2804,6 @@ static int vmx_vcpu_reset(struct kvm_vcpu *vcpu)
vmx->emulation_required = 0;
out:
- srcu_read_unlock(&vcpu->kvm->srcu, idx);
return ret;
}
@@ -2826,9 +2908,7 @@ static bool vmx_get_nmi_mask(struct kvm_vcpu *vcpu)
{
if (!cpu_has_virtual_nmis())
return to_vmx(vcpu)->soft_vnmi_blocked;
- else
- return !!(vmcs_read32(GUEST_INTERRUPTIBILITY_INFO) &
- GUEST_INTR_STATE_NMI);
+ return vmcs_read32(GUEST_INTERRUPTIBILITY_INFO) & GUEST_INTR_STATE_NMI;
}
static void vmx_set_nmi_mask(struct kvm_vcpu *vcpu, bool masked)
@@ -3070,7 +3150,7 @@ static int handle_io(struct kvm_vcpu *vcpu)
++vcpu->stat.io_exits;
if (string || in)
- return !(emulate_instruction(vcpu, 0, 0, 0) == EMULATE_DO_MMIO);
+ return emulate_instruction(vcpu, 0, 0, 0) == EMULATE_DONE;
port = exit_qualification >> 16;
size = (exit_qualification & 7) + 1;
@@ -3090,11 +3170,20 @@ vmx_patch_hypercall(struct kvm_vcpu *vcpu, unsigned char *hypercall)
hypercall[2] = 0xc1;
}
+static void complete_insn_gp(struct kvm_vcpu *vcpu, int err)
+{
+ if (err)
+ kvm_inject_gp(vcpu, 0);
+ else
+ skip_emulated_instruction(vcpu);
+}
+
static int handle_cr(struct kvm_vcpu *vcpu)
{
unsigned long exit_qualification, val;
int cr;
int reg;
+ int err;
exit_qualification = vmcs_readl(EXIT_QUALIFICATION);
cr = exit_qualification & 15;
@@ -3105,16 +3194,16 @@ static int handle_cr(struct kvm_vcpu *vcpu)
trace_kvm_cr_write(cr, val);
switch (cr) {
case 0:
- kvm_set_cr0(vcpu, val);
- skip_emulated_instruction(vcpu);
+ err = kvm_set_cr0(vcpu, val);
+ complete_insn_gp(vcpu, err);
return 1;
case 3:
- kvm_set_cr3(vcpu, val);
- skip_emulated_instruction(vcpu);
+ err = kvm_set_cr3(vcpu, val);
+ complete_insn_gp(vcpu, err);
return 1;
case 4:
- kvm_set_cr4(vcpu, val);
- skip_emulated_instruction(vcpu);
+ err = kvm_set_cr4(vcpu, val);
+ complete_insn_gp(vcpu, err);
return 1;
case 8: {
u8 cr8_prev = kvm_get_cr8(vcpu);
@@ -3321,30 +3410,25 @@ static int handle_invlpg(struct kvm_vcpu *vcpu)
static int handle_wbinvd(struct kvm_vcpu *vcpu)
{
skip_emulated_instruction(vcpu);
- /* TODO: Add support for VT-d/pass-through device */
+ kvm_emulate_wbinvd(vcpu);
return 1;
}
-static int handle_apic_access(struct kvm_vcpu *vcpu)
+static int handle_xsetbv(struct kvm_vcpu *vcpu)
{
- unsigned long exit_qualification;
- enum emulation_result er;
- unsigned long offset;
+ u64 new_bv = kvm_read_edx_eax(vcpu);
+ u32 index = kvm_register_read(vcpu, VCPU_REGS_RCX);
- exit_qualification = vmcs_readl(EXIT_QUALIFICATION);
- offset = exit_qualification & 0xffful;
-
- er = emulate_instruction(vcpu, 0, 0, 0);
-
- if (er != EMULATE_DONE) {
- printk(KERN_ERR
- "Fail to handle apic access vmexit! Offset is 0x%lx\n",
- offset);
- return -ENOEXEC;
- }
+ if (kvm_set_xcr(vcpu, index, new_bv) == 0)
+ skip_emulated_instruction(vcpu);
return 1;
}
+static int handle_apic_access(struct kvm_vcpu *vcpu)
+{
+ return emulate_instruction(vcpu, 0, 0, 0) == EMULATE_DONE;
+}
+
static int handle_task_switch(struct kvm_vcpu *vcpu)
{
struct vcpu_vmx *vmx = to_vmx(vcpu);
@@ -3554,13 +3638,8 @@ static int handle_invalid_guest_state(struct kvm_vcpu *vcpu)
goto out;
}
- if (err != EMULATE_DONE) {
- vcpu->run->exit_reason = KVM_EXIT_INTERNAL_ERROR;
- vcpu->run->internal.suberror = KVM_INTERNAL_ERROR_EMULATION;
- vcpu->run->internal.ndata = 0;
- ret = 0;
- goto out;
- }
+ if (err != EMULATE_DONE)
+ return 0;
if (signal_pending(current))
goto out;
@@ -3623,6 +3702,7 @@ static int (*kvm_vmx_exit_handlers[])(struct kvm_vcpu *vcpu) = {
[EXIT_REASON_TPR_BELOW_THRESHOLD] = handle_tpr_below_threshold,
[EXIT_REASON_APIC_ACCESS] = handle_apic_access,
[EXIT_REASON_WBINVD] = handle_wbinvd,
+ [EXIT_REASON_XSETBV] = handle_xsetbv,
[EXIT_REASON_TASK_SWITCH] = handle_task_switch,
[EXIT_REASON_MCE_DURING_VMENTRY] = handle_machine_check,
[EXIT_REASON_EPT_VIOLATION] = handle_ept_violation,
@@ -3656,6 +3736,13 @@ static int vmx_handle_exit(struct kvm_vcpu *vcpu)
if (enable_ept && is_paging(vcpu))
vcpu->arch.cr3 = vmcs_readl(GUEST_CR3);
+ if (exit_reason & VMX_EXIT_REASONS_FAILED_VMENTRY) {
+ vcpu->run->exit_reason = KVM_EXIT_FAIL_ENTRY;
+ vcpu->run->fail_entry.hardware_entry_failure_reason
+ = exit_reason;
+ return 0;
+ }
+
if (unlikely(vmx->fail)) {
vcpu->run->exit_reason = KVM_EXIT_FAIL_ENTRY;
vcpu->run->fail_entry.hardware_entry_failure_reason
@@ -3861,11 +3948,6 @@ static void vmx_vcpu_run(struct kvm_vcpu *vcpu)
if (vcpu->guest_debug & KVM_GUESTDBG_SINGLESTEP)
vmx_set_interrupt_shadow(vcpu, 0);
- /*
- * Loading guest fpu may have cleared host cr0.ts
- */
- vmcs_writel(HOST_CR0, read_cr0());
-
asm(
/* Store host registers */
"push %%"R"dx; push %%"R"bp;"
@@ -4001,6 +4083,19 @@ static void vmx_free_vcpu(struct kvm_vcpu *vcpu)
kmem_cache_free(kvm_vcpu_cache, vmx);
}
+static inline void vmcs_init(struct vmcs *vmcs)
+{
+ u64 phys_addr = __pa(per_cpu(vmxarea, raw_smp_processor_id()));
+
+ if (!vmm_exclusive)
+ kvm_cpu_vmxon(phys_addr);
+
+ vmcs_clear(vmcs);
+
+ if (!vmm_exclusive)
+ kvm_cpu_vmxoff();
+}
+
static struct kvm_vcpu *vmx_create_vcpu(struct kvm *kvm, unsigned int id)
{
int err;
@@ -4026,7 +4121,7 @@ static struct kvm_vcpu *vmx_create_vcpu(struct kvm *kvm, unsigned int id)
if (!vmx->vmcs)
goto free_msrs;
- vmcs_clear(vmx->vmcs);
+ vmcs_init(vmx->vmcs);
cpu = get_cpu();
vmx_vcpu_load(&vmx->vcpu, cpu);
@@ -4265,6 +4360,8 @@ static struct kvm_x86_ops vmx_x86_ops = {
.rdtscp_supported = vmx_rdtscp_supported,
.set_supported_cpuid = vmx_set_supported_cpuid,
+
+ .has_wbinvd_exit = cpu_has_vmx_wbinvd_exit,
};
static int __init vmx_init(void)
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 7fa89c39c64..25f19078b32 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -6,6 +6,7 @@
* Copyright (C) 2006 Qumranet, Inc.
* Copyright (C) 2008 Qumranet, Inc.
* Copyright IBM Corporation, 2008
+ * Copyright 2010 Red Hat, Inc. and/or its affilates.
*
* Authors:
* Avi Kivity <avi@qumranet.com>
@@ -41,17 +42,19 @@
#include <linux/srcu.h>
#include <linux/slab.h>
#include <linux/perf_event.h>
+#include <linux/uaccess.h>
#include <trace/events/kvm.h>
#define CREATE_TRACE_POINTS
#include "trace.h"
#include <asm/debugreg.h>
-#include <asm/uaccess.h>
#include <asm/msr.h>
#include <asm/desc.h>
#include <asm/mtrr.h>
#include <asm/mce.h>
+#include <asm/i387.h>
+#include <asm/xcr.h>
#define MAX_IO_MSRS 256
#define CR0_RESERVED_BITS \
@@ -62,6 +65,7 @@
(~(unsigned long)(X86_CR4_VME | X86_CR4_PVI | X86_CR4_TSD | X86_CR4_DE\
| X86_CR4_PSE | X86_CR4_PAE | X86_CR4_MCE \
| X86_CR4_PGE | X86_CR4_PCE | X86_CR4_OSFXSR \
+ | X86_CR4_OSXSAVE \
| X86_CR4_OSXMMEXCPT | X86_CR4_VMXE))
#define CR8_RESERVED_BITS (~(unsigned long)X86_CR8_TPR)
@@ -147,6 +151,13 @@ struct kvm_stats_debugfs_item debugfs_entries[] = {
{ NULL }
};
+u64 __read_mostly host_xcr0;
+
+static inline u32 bit(int bitno)
+{
+ return 1 << (bitno & 31);
+}
+
static void kvm_on_user_return(struct user_return_notifier *urn)
{
unsigned slot;
@@ -285,7 +296,7 @@ static void kvm_multiple_exception(struct kvm_vcpu *vcpu,
prev_nr = vcpu->arch.exception.nr;
if (prev_nr == DF_VECTOR) {
/* triple fault -> shutdown */
- set_bit(KVM_REQ_TRIPLE_FAULT, &vcpu->requests);
+ kvm_make_request(KVM_REQ_TRIPLE_FAULT, vcpu);
return;
}
class1 = exception_class(prev_nr);
@@ -414,121 +425,163 @@ out:
return changed;
}
-void kvm_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0)
+int kvm_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0)
{
+ unsigned long old_cr0 = kvm_read_cr0(vcpu);
+ unsigned long update_bits = X86_CR0_PG | X86_CR0_WP |
+ X86_CR0_CD | X86_CR0_NW;
+
cr0 |= X86_CR0_ET;
#ifdef CONFIG_X86_64
- if (cr0 & 0xffffffff00000000UL) {
- kvm_inject_gp(vcpu, 0);
- return;
- }
+ if (cr0 & 0xffffffff00000000UL)
+ return 1;
#endif
cr0 &= ~CR0_RESERVED_BITS;
- if ((cr0 & X86_CR0_NW) && !(cr0 & X86_CR0_CD)) {
- kvm_inject_gp(vcpu, 0);
- return;
- }
+ if ((cr0 & X86_CR0_NW) && !(cr0 & X86_CR0_CD))
+ return 1;
- if ((cr0 & X86_CR0_PG) && !(cr0 & X86_CR0_PE)) {
- kvm_inject_gp(vcpu, 0);
- return;
- }
+ if ((cr0 & X86_CR0_PG) && !(cr0 & X86_CR0_PE))
+ return 1;
if (!is_paging(vcpu) && (cr0 & X86_CR0_PG)) {
#ifdef CONFIG_X86_64
if ((vcpu->arch.efer & EFER_LME)) {
int cs_db, cs_l;
- if (!is_pae(vcpu)) {
- kvm_inject_gp(vcpu, 0);
- return;
- }
+ if (!is_pae(vcpu))
+ return 1;
kvm_x86_ops->get_cs_db_l_bits(vcpu, &cs_db, &cs_l);
- if (cs_l) {
- kvm_inject_gp(vcpu, 0);
- return;
-
- }
+ if (cs_l)
+ return 1;
} else
#endif
- if (is_pae(vcpu) && !load_pdptrs(vcpu, vcpu->arch.cr3)) {
- kvm_inject_gp(vcpu, 0);
- return;
- }
-
+ if (is_pae(vcpu) && !load_pdptrs(vcpu, vcpu->arch.cr3))
+ return 1;
}
kvm_x86_ops->set_cr0(vcpu, cr0);
- kvm_mmu_reset_context(vcpu);
- return;
+ if ((cr0 ^ old_cr0) & update_bits)
+ kvm_mmu_reset_context(vcpu);
+ return 0;
}
EXPORT_SYMBOL_GPL(kvm_set_cr0);
void kvm_lmsw(struct kvm_vcpu *vcpu, unsigned long msw)
{
- kvm_set_cr0(vcpu, kvm_read_cr0_bits(vcpu, ~0x0eul) | (msw & 0x0f));
+ (void)kvm_set_cr0(vcpu, kvm_read_cr0_bits(vcpu, ~0x0eul) | (msw & 0x0f));
}
EXPORT_SYMBOL_GPL(kvm_lmsw);
-void kvm_set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4)
+int __kvm_set_xcr(struct kvm_vcpu *vcpu, u32 index, u64 xcr)
{
- unsigned long old_cr4 = kvm_read_cr4(vcpu);
- unsigned long pdptr_bits = X86_CR4_PGE | X86_CR4_PSE | X86_CR4_PAE;
+ u64 xcr0;
- if (cr4 & CR4_RESERVED_BITS) {
+ /* Only support XCR_XFEATURE_ENABLED_MASK(xcr0) now */
+ if (index != XCR_XFEATURE_ENABLED_MASK)
+ return 1;
+ xcr0 = xcr;
+ if (kvm_x86_ops->get_cpl(vcpu) != 0)
+ return 1;
+ if (!(xcr0 & XSTATE_FP))
+ return 1;
+ if ((xcr0 & XSTATE_YMM) && !(xcr0 & XSTATE_SSE))
+ return 1;
+ if (xcr0 & ~host_xcr0)
+ return 1;
+ vcpu->arch.xcr0 = xcr0;
+ vcpu->guest_xcr0_loaded = 0;
+ return 0;
+}
+
+int kvm_set_xcr(struct kvm_vcpu *vcpu, u32 index, u64 xcr)
+{
+ if (__kvm_set_xcr(vcpu, index, xcr)) {
kvm_inject_gp(vcpu, 0);
+ return 1;
+ }
+ return 0;
+}
+EXPORT_SYMBOL_GPL(kvm_set_xcr);
+
+static bool guest_cpuid_has_xsave(struct kvm_vcpu *vcpu)
+{
+ struct kvm_cpuid_entry2 *best;
+
+ best = kvm_find_cpuid_entry(vcpu, 1, 0);
+ return best && (best->ecx & bit(X86_FEATURE_XSAVE));
+}
+
+static void update_cpuid(struct kvm_vcpu *vcpu)
+{
+ struct kvm_cpuid_entry2 *best;
+
+ best = kvm_find_cpuid_entry(vcpu, 1, 0);
+ if (!best)
return;
+
+ /* Update OSXSAVE bit */
+ if (cpu_has_xsave && best->function == 0x1) {
+ best->ecx &= ~(bit(X86_FEATURE_OSXSAVE));
+ if (kvm_read_cr4_bits(vcpu, X86_CR4_OSXSAVE))
+ best->ecx |= bit(X86_FEATURE_OSXSAVE);
}
+}
+
+int kvm_set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4)
+{
+ unsigned long old_cr4 = kvm_read_cr4(vcpu);
+ unsigned long pdptr_bits = X86_CR4_PGE | X86_CR4_PSE | X86_CR4_PAE;
+
+ if (cr4 & CR4_RESERVED_BITS)
+ return 1;
+
+ if (!guest_cpuid_has_xsave(vcpu) && (cr4 & X86_CR4_OSXSAVE))
+ return 1;
if (is_long_mode(vcpu)) {
- if (!(cr4 & X86_CR4_PAE)) {
- kvm_inject_gp(vcpu, 0);
- return;
- }
+ if (!(cr4 & X86_CR4_PAE))
+ return 1;
} else if (is_paging(vcpu) && (cr4 & X86_CR4_PAE)
&& ((cr4 ^ old_cr4) & pdptr_bits)
- && !load_pdptrs(vcpu, vcpu->arch.cr3)) {
- kvm_inject_gp(vcpu, 0);
- return;
- }
+ && !load_pdptrs(vcpu, vcpu->arch.cr3))
+ return 1;
+
+ if (cr4 & X86_CR4_VMXE)
+ return 1;
- if (cr4 & X86_CR4_VMXE) {
- kvm_inject_gp(vcpu, 0);
- return;
- }
kvm_x86_ops->set_cr4(vcpu, cr4);
- vcpu->arch.cr4 = cr4;
- kvm_mmu_reset_context(vcpu);
+
+ if ((cr4 ^ old_cr4) & pdptr_bits)
+ kvm_mmu_reset_context(vcpu);
+
+ if ((cr4 ^ old_cr4) & X86_CR4_OSXSAVE)
+ update_cpuid(vcpu);
+
+ return 0;
}
EXPORT_SYMBOL_GPL(kvm_set_cr4);
-void kvm_set_cr3(struct kvm_vcpu *vcpu, unsigned long cr3)
+int kvm_set_cr3(struct kvm_vcpu *vcpu, unsigned long cr3)
{
if (cr3 == vcpu->arch.cr3 && !pdptrs_changed(vcpu)) {
kvm_mmu_sync_roots(vcpu);
kvm_mmu_flush_tlb(vcpu);
- return;
+ return 0;
}
if (is_long_mode(vcpu)) {
- if (cr3 & CR3_L_MODE_RESERVED_BITS) {
- kvm_inject_gp(vcpu, 0);
- return;
- }
+ if (cr3 & CR3_L_MODE_RESERVED_BITS)
+ return 1;
} else {
if (is_pae(vcpu)) {
- if (cr3 & CR3_PAE_RESERVED_BITS) {
- kvm_inject_gp(vcpu, 0);
- return;
- }
- if (is_paging(vcpu) && !load_pdptrs(vcpu, cr3)) {
- kvm_inject_gp(vcpu, 0);
- return;
- }
+ if (cr3 & CR3_PAE_RESERVED_BITS)
+ return 1;
+ if (is_paging(vcpu) && !load_pdptrs(vcpu, cr3))
+ return 1;
}
/*
* We don't check reserved bits in nonpae mode, because
@@ -546,24 +599,28 @@ void kvm_set_cr3(struct kvm_vcpu *vcpu, unsigned long cr3)
* to debug) behavior on the guest side.
*/
if (unlikely(!gfn_to_memslot(vcpu->kvm, cr3 >> PAGE_SHIFT)))
- kvm_inject_gp(vcpu, 0);
- else {
- vcpu->arch.cr3 = cr3;
- vcpu->arch.mmu.new_cr3(vcpu);
- }
+ return 1;
+ vcpu->arch.cr3 = cr3;
+ vcpu->arch.mmu.new_cr3(vcpu);
+ return 0;
}
EXPORT_SYMBOL_GPL(kvm_set_cr3);
-void kvm_set_cr8(struct kvm_vcpu *vcpu, unsigned long cr8)
+int __kvm_set_cr8(struct kvm_vcpu *vcpu, unsigned long cr8)
{
- if (cr8 & CR8_RESERVED_BITS) {
- kvm_inject_gp(vcpu, 0);
- return;
- }
+ if (cr8 & CR8_RESERVED_BITS)
+ return 1;
if (irqchip_in_kernel(vcpu->kvm))
kvm_lapic_set_tpr(vcpu, cr8);
else
vcpu->arch.cr8 = cr8;
+ return 0;
+}
+
+void kvm_set_cr8(struct kvm_vcpu *vcpu, unsigned long cr8)
+{
+ if (__kvm_set_cr8(vcpu, cr8))
+ kvm_inject_gp(vcpu, 0);
}
EXPORT_SYMBOL_GPL(kvm_set_cr8);
@@ -576,7 +633,7 @@ unsigned long kvm_get_cr8(struct kvm_vcpu *vcpu)
}
EXPORT_SYMBOL_GPL(kvm_get_cr8);
-int kvm_set_dr(struct kvm_vcpu *vcpu, int dr, unsigned long val)
+static int __kvm_set_dr(struct kvm_vcpu *vcpu, int dr, unsigned long val)
{
switch (dr) {
case 0 ... 3:
@@ -585,29 +642,21 @@ int kvm_set_dr(struct kvm_vcpu *vcpu, int dr, unsigned long val)
vcpu->arch.eff_db[dr] = val;
break;
case 4:
- if (kvm_read_cr4_bits(vcpu, X86_CR4_DE)) {
- kvm_queue_exception(vcpu, UD_VECTOR);
- return 1;
- }
+ if (kvm_read_cr4_bits(vcpu, X86_CR4_DE))
+ return 1; /* #UD */
/* fall through */
case 6:
- if (val & 0xffffffff00000000ULL) {
- kvm_inject_gp(vcpu, 0);
- return 1;
- }
+ if (val & 0xffffffff00000000ULL)
+ return -1; /* #GP */
vcpu->arch.dr6 = (val & DR6_VOLATILE) | DR6_FIXED_1;
break;
case 5:
- if (kvm_read_cr4_bits(vcpu, X86_CR4_DE)) {
- kvm_queue_exception(vcpu, UD_VECTOR);
- return 1;
- }
+ if (kvm_read_cr4_bits(vcpu, X86_CR4_DE))
+ return 1; /* #UD */
/* fall through */
default: /* 7 */
- if (val & 0xffffffff00000000ULL) {
- kvm_inject_gp(vcpu, 0);
- return 1;
- }
+ if (val & 0xffffffff00000000ULL)
+ return -1; /* #GP */
vcpu->arch.dr7 = (val & DR7_VOLATILE) | DR7_FIXED_1;
if (!(vcpu->guest_debug & KVM_GUESTDBG_USE_HW_BP)) {
kvm_x86_ops->set_dr7(vcpu, vcpu->arch.dr7);
@@ -618,28 +667,37 @@ int kvm_set_dr(struct kvm_vcpu *vcpu, int dr, unsigned long val)
return 0;
}
+
+int kvm_set_dr(struct kvm_vcpu *vcpu, int dr, unsigned long val)
+{
+ int res;
+
+ res = __kvm_set_dr(vcpu, dr, val);
+ if (res > 0)
+ kvm_queue_exception(vcpu, UD_VECTOR);
+ else if (res < 0)
+ kvm_inject_gp(vcpu, 0);
+
+ return res;
+}
EXPORT_SYMBOL_GPL(kvm_set_dr);
-int kvm_get_dr(struct kvm_vcpu *vcpu, int dr, unsigned long *val)
+static int _kvm_get_dr(struct kvm_vcpu *vcpu, int dr, unsigned long *val)
{
switch (dr) {
case 0 ... 3:
*val = vcpu->arch.db[dr];
break;
case 4:
- if (kvm_read_cr4_bits(vcpu, X86_CR4_DE)) {
- kvm_queue_exception(vcpu, UD_VECTOR);
+ if (kvm_read_cr4_bits(vcpu, X86_CR4_DE))
return 1;
- }
/* fall through */
case 6:
*val = vcpu->arch.dr6;
break;
case 5:
- if (kvm_read_cr4_bits(vcpu, X86_CR4_DE)) {
- kvm_queue_exception(vcpu, UD_VECTOR);
+ if (kvm_read_cr4_bits(vcpu, X86_CR4_DE))
return 1;
- }
/* fall through */
default: /* 7 */
*val = vcpu->arch.dr7;
@@ -648,12 +706,16 @@ int kvm_get_dr(struct kvm_vcpu *vcpu, int dr, unsigned long *val)
return 0;
}
-EXPORT_SYMBOL_GPL(kvm_get_dr);
-static inline u32 bit(int bitno)
+int kvm_get_dr(struct kvm_vcpu *vcpu, int dr, unsigned long *val)
{
- return 1 << (bitno & 31);
+ if (_kvm_get_dr(vcpu, dr, val)) {
+ kvm_queue_exception(vcpu, UD_VECTOR);
+ return 1;
+ }
+ return 0;
}
+EXPORT_SYMBOL_GPL(kvm_get_dr);
/*
* List of msr numbers which we expose to userspace through KVM_GET_MSRS
@@ -671,7 +733,7 @@ static u32 msrs_to_save[] = {
HV_X64_MSR_GUEST_OS_ID, HV_X64_MSR_HYPERCALL,
HV_X64_MSR_APIC_ASSIST_PAGE,
MSR_IA32_SYSENTER_CS, MSR_IA32_SYSENTER_ESP, MSR_IA32_SYSENTER_EIP,
- MSR_K6_STAR,
+ MSR_STAR,
#ifdef CONFIG_X86_64
MSR_CSTAR, MSR_KERNEL_GS_BASE, MSR_SYSCALL_MASK, MSR_LSTAR,
#endif
@@ -682,10 +744,14 @@ static unsigned num_msrs_to_save;
static u32 emulated_msrs[] = {
MSR_IA32_MISC_ENABLE,
+ MSR_IA32_MCG_STATUS,
+ MSR_IA32_MCG_CTL,
};
static int set_efer(struct kvm_vcpu *vcpu, u64 efer)
{
+ u64 old_efer = vcpu->arch.efer;
+
if (efer & efer_reserved_bits)
return 1;
@@ -714,11 +780,13 @@ static int set_efer(struct kvm_vcpu *vcpu, u64 efer)
kvm_x86_ops->set_efer(vcpu, efer);
- vcpu->arch.efer = efer;
-
vcpu->arch.mmu.base_role.nxe = (efer & EFER_NX) && !tdp_enabled;
kvm_mmu_reset_context(vcpu);
+ /* Update reserved bits */
+ if ((efer ^ old_efer) & EFER_NX)
+ kvm_mmu_reset_context(vcpu);
+
return 0;
}
@@ -882,7 +950,7 @@ static int kvm_request_guest_time_update(struct kvm_vcpu *v)
if (!vcpu->time_page)
return 0;
- set_bit(KVM_REQ_KVMCLOCK_UPDATE, &v->requests);
+ kvm_make_request(KVM_REQ_KVMCLOCK_UPDATE, v);
return 1;
}
@@ -1524,16 +1592,12 @@ static int __msr_io(struct kvm_vcpu *vcpu, struct kvm_msrs *msrs,
{
int i, idx;
- vcpu_load(vcpu);
-
idx = srcu_read_lock(&vcpu->kvm->srcu);
for (i = 0; i < msrs->nmsrs; ++i)
if (do_msr(vcpu, entries[i].index, &entries[i].data))
break;
srcu_read_unlock(&vcpu->kvm->srcu, idx);
- vcpu_put(vcpu);
-
return i;
}
@@ -1618,6 +1682,7 @@ int kvm_dev_ioctl_check_extension(long ext)
case KVM_CAP_PCI_SEGMENT:
case KVM_CAP_DEBUGREGS:
case KVM_CAP_X86_ROBUST_SINGLESTEP:
+ case KVM_CAP_XSAVE:
r = 1;
break;
case KVM_CAP_COALESCED_MMIO:
@@ -1641,6 +1706,9 @@ int kvm_dev_ioctl_check_extension(long ext)
case KVM_CAP_MCE:
r = KVM_MAX_MCE_BANKS;
break;
+ case KVM_CAP_XCRS:
+ r = cpu_has_xsave;
+ break;
default:
r = 0;
break;
@@ -1717,8 +1785,28 @@ out:
return r;
}
+static void wbinvd_ipi(void *garbage)
+{
+ wbinvd();
+}
+
+static bool need_emulate_wbinvd(struct kvm_vcpu *vcpu)
+{
+ return vcpu->kvm->arch.iommu_domain &&
+ !(vcpu->kvm->arch.iommu_flags & KVM_IOMMU_CACHE_COHERENCY);
+}
+
void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
{
+ /* Address WBINVD may be executed by guest */
+ if (need_emulate_wbinvd(vcpu)) {
+ if (kvm_x86_ops->has_wbinvd_exit())
+ cpumask_set_cpu(cpu, vcpu->arch.wbinvd_dirty_mask);
+ else if (vcpu->cpu != -1 && vcpu->cpu != cpu)
+ smp_call_function_single(vcpu->cpu,
+ wbinvd_ipi, NULL, 1);
+ }
+
kvm_x86_ops->vcpu_load(vcpu, cpu);
if (unlikely(per_cpu(cpu_tsc_khz, cpu) == 0)) {
unsigned long khz = cpufreq_quick_get(cpu);
@@ -1731,8 +1819,8 @@ void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu)
{
- kvm_put_guest_fpu(vcpu);
kvm_x86_ops->vcpu_put(vcpu);
+ kvm_put_guest_fpu(vcpu);
}
static int is_efer_nx(void)
@@ -1781,7 +1869,6 @@ static int kvm_vcpu_ioctl_set_cpuid(struct kvm_vcpu *vcpu,
if (copy_from_user(cpuid_entries, entries,
cpuid->nent * sizeof(struct kvm_cpuid_entry)))
goto out_free;
- vcpu_load(vcpu);
for (i = 0; i < cpuid->nent; i++) {
vcpu->arch.cpuid_entries[i].function = cpuid_entries[i].function;
vcpu->arch.cpuid_entries[i].eax = cpuid_entries[i].eax;
@@ -1799,7 +1886,7 @@ static int kvm_vcpu_ioctl_set_cpuid(struct kvm_vcpu *vcpu,
r = 0;
kvm_apic_set_version(vcpu);
kvm_x86_ops->cpuid_update(vcpu);
- vcpu_put(vcpu);
+ update_cpuid(vcpu);
out_free:
vfree(cpuid_entries);
@@ -1820,11 +1907,10 @@ static int kvm_vcpu_ioctl_set_cpuid2(struct kvm_vcpu *vcpu,
if (copy_from_user(&vcpu->arch.cpuid_entries, entries,
cpuid->nent * sizeof(struct kvm_cpuid_entry2)))
goto out;
- vcpu_load(vcpu);
vcpu->arch.cpuid_nent = cpuid->nent;
kvm_apic_set_version(vcpu);
kvm_x86_ops->cpuid_update(vcpu);
- vcpu_put(vcpu);
+ update_cpuid(vcpu);
return 0;
out:
@@ -1837,7 +1923,6 @@ static int kvm_vcpu_ioctl_get_cpuid2(struct kvm_vcpu *vcpu,
{
int r;
- vcpu_load(vcpu);
r = -E2BIG;
if (cpuid->nent < vcpu->arch.cpuid_nent)
goto out;
@@ -1849,7 +1934,6 @@ static int kvm_vcpu_ioctl_get_cpuid2(struct kvm_vcpu *vcpu,
out:
cpuid->nent = vcpu->arch.cpuid_nent;
- vcpu_put(vcpu);
return r;
}
@@ -1901,13 +1985,13 @@ static void do_cpuid_ent(struct kvm_cpuid_entry2 *entry, u32 function,
0 /* Reserved */ | f_lm | F(3DNOWEXT) | F(3DNOW);
/* cpuid 1.ecx */
const u32 kvm_supported_word4_x86_features =
- F(XMM3) | 0 /* Reserved, DTES64, MONITOR */ |
+ F(XMM3) | F(PCLMULQDQ) | 0 /* DTES64, MONITOR */ |
0 /* DS-CPL, VMX, SMX, EST */ |
0 /* TM2 */ | F(SSSE3) | 0 /* CNXT-ID */ | 0 /* Reserved */ |
0 /* Reserved */ | F(CX16) | 0 /* xTPR Update, PDCM */ |
0 /* Reserved, DCA */ | F(XMM4_1) |
F(XMM4_2) | F(X2APIC) | F(MOVBE) | F(POPCNT) |
- 0 /* Reserved, XSAVE, OSXSAVE */;
+ 0 /* Reserved, AES */ | F(XSAVE) | 0 /* OSXSAVE */ | F(AVX);
/* cpuid 0x80000001.ecx */
const u32 kvm_supported_word6_x86_features =
F(LAHF_LM) | F(CMP_LEGACY) | F(SVM) | 0 /* ExtApicSpace */ |
@@ -1922,7 +2006,7 @@ static void do_cpuid_ent(struct kvm_cpuid_entry2 *entry, u32 function,
switch (function) {
case 0:
- entry->eax = min(entry->eax, (u32)0xb);
+ entry->eax = min(entry->eax, (u32)0xd);
break;
case 1:
entry->edx &= kvm_supported_word0_x86_features;
@@ -1980,6 +2064,20 @@ static void do_cpuid_ent(struct kvm_cpuid_entry2 *entry, u32 function,
}
break;
}
+ case 0xd: {
+ int i;
+
+ entry->flags |= KVM_CPUID_FLAG_SIGNIFCANT_INDEX;
+ for (i = 1; *nent < maxnent; ++i) {
+ if (entry[i - 1].eax == 0 && i != 2)
+ break;
+ do_cpuid_1_ent(&entry[i], function, i);
+ entry[i].flags |=
+ KVM_CPUID_FLAG_SIGNIFCANT_INDEX;
+ ++*nent;
+ }
+ break;
+ }
case KVM_CPUID_SIGNATURE: {
char signature[12] = "KVMKVMKVM\0\0";
u32 *sigptr = (u32 *)signature;
@@ -2081,9 +2179,7 @@ out:
static int kvm_vcpu_ioctl_get_lapic(struct kvm_vcpu *vcpu,
struct kvm_lapic_state *s)
{
- vcpu_load(vcpu);
memcpy(s->regs, vcpu->arch.apic->regs, sizeof *s);
- vcpu_put(vcpu);
return 0;
}
@@ -2091,11 +2187,9 @@ static int kvm_vcpu_ioctl_get_lapic(struct kvm_vcpu *vcpu,
static int kvm_vcpu_ioctl_set_lapic(struct kvm_vcpu *vcpu,
struct kvm_lapic_state *s)
{
- vcpu_load(vcpu);
memcpy(vcpu->arch.apic->regs, s->regs, sizeof *s);
kvm_apic_post_state_restore(vcpu);
update_cr8_intercept(vcpu);
- vcpu_put(vcpu);
return 0;
}
@@ -2107,20 +2201,15 @@ static int kvm_vcpu_ioctl_interrupt(struct kvm_vcpu *vcpu,
return -EINVAL;
if (irqchip_in_kernel(vcpu->kvm))
return -ENXIO;
- vcpu_load(vcpu);
kvm_queue_interrupt(vcpu, irq->irq, false);
- vcpu_put(vcpu);
-
return 0;
}
static int kvm_vcpu_ioctl_nmi(struct kvm_vcpu *vcpu)
{
- vcpu_load(vcpu);
kvm_inject_nmi(vcpu);
- vcpu_put(vcpu);
return 0;
}
@@ -2140,7 +2229,6 @@ static int kvm_vcpu_ioctl_x86_setup_mce(struct kvm_vcpu *vcpu,
int r;
unsigned bank_num = mcg_cap & 0xff, bank;
- vcpu_load(vcpu);
r = -EINVAL;
if (!bank_num || bank_num >= KVM_MAX_MCE_BANKS)
goto out;
@@ -2155,7 +2243,6 @@ static int kvm_vcpu_ioctl_x86_setup_mce(struct kvm_vcpu *vcpu,
for (bank = 0; bank < bank_num; bank++)
vcpu->arch.mce_banks[bank*4] = ~(u64)0;
out:
- vcpu_put(vcpu);
return r;
}
@@ -2188,7 +2275,7 @@ static int kvm_vcpu_ioctl_x86_set_mce(struct kvm_vcpu *vcpu,
printk(KERN_DEBUG "kvm: set_mce: "
"injects mce exception while "
"previous one is in progress!\n");
- set_bit(KVM_REQ_TRIPLE_FAULT, &vcpu->requests);
+ kvm_make_request(KVM_REQ_TRIPLE_FAULT, vcpu);
return 0;
}
if (banks[1] & MCI_STATUS_VAL)
@@ -2213,8 +2300,6 @@ static int kvm_vcpu_ioctl_x86_set_mce(struct kvm_vcpu *vcpu,
static void kvm_vcpu_ioctl_x86_get_vcpu_events(struct kvm_vcpu *vcpu,
struct kvm_vcpu_events *events)
{
- vcpu_load(vcpu);
-
events->exception.injected =
vcpu->arch.exception.pending &&
!kvm_exception_is_soft(vcpu->arch.exception.nr);
@@ -2239,8 +2324,6 @@ static void kvm_vcpu_ioctl_x86_get_vcpu_events(struct kvm_vcpu *vcpu,
events->flags = (KVM_VCPUEVENT_VALID_NMI_PENDING
| KVM_VCPUEVENT_VALID_SIPI_VECTOR
| KVM_VCPUEVENT_VALID_SHADOW);
-
- vcpu_put(vcpu);
}
static int kvm_vcpu_ioctl_x86_set_vcpu_events(struct kvm_vcpu *vcpu,
@@ -2251,8 +2334,6 @@ static int kvm_vcpu_ioctl_x86_set_vcpu_events(struct kvm_vcpu *vcpu,
| KVM_VCPUEVENT_VALID_SHADOW))
return -EINVAL;
- vcpu_load(vcpu);
-
vcpu->arch.exception.pending = events->exception.injected;
vcpu->arch.exception.nr = events->exception.nr;
vcpu->arch.exception.has_error_code = events->exception.has_error_code;
@@ -2275,22 +2356,16 @@ static int kvm_vcpu_ioctl_x86_set_vcpu_events(struct kvm_vcpu *vcpu,
if (events->flags & KVM_VCPUEVENT_VALID_SIPI_VECTOR)
vcpu->arch.sipi_vector = events->sipi_vector;
- vcpu_put(vcpu);
-
return 0;
}
static void kvm_vcpu_ioctl_x86_get_debugregs(struct kvm_vcpu *vcpu,
struct kvm_debugregs *dbgregs)
{
- vcpu_load(vcpu);
-
memcpy(dbgregs->db, vcpu->arch.db, sizeof(vcpu->arch.db));
dbgregs->dr6 = vcpu->arch.dr6;
dbgregs->dr7 = vcpu->arch.dr7;
dbgregs->flags = 0;
-
- vcpu_put(vcpu);
}
static int kvm_vcpu_ioctl_x86_set_debugregs(struct kvm_vcpu *vcpu,
@@ -2299,40 +2374,113 @@ static int kvm_vcpu_ioctl_x86_set_debugregs(struct kvm_vcpu *vcpu,
if (dbgregs->flags)
return -EINVAL;
- vcpu_load(vcpu);
-
memcpy(vcpu->arch.db, dbgregs->db, sizeof(vcpu->arch.db));
vcpu->arch.dr6 = dbgregs->dr6;
vcpu->arch.dr7 = dbgregs->dr7;
- vcpu_put(vcpu);
+ return 0;
+}
+
+static void kvm_vcpu_ioctl_x86_get_xsave(struct kvm_vcpu *vcpu,
+ struct kvm_xsave *guest_xsave)
+{
+ if (cpu_has_xsave)
+ memcpy(guest_xsave->region,
+ &vcpu->arch.guest_fpu.state->xsave,
+ sizeof(struct xsave_struct));
+ else {
+ memcpy(guest_xsave->region,
+ &vcpu->arch.guest_fpu.state->fxsave,
+ sizeof(struct i387_fxsave_struct));
+ *(u64 *)&guest_xsave->region[XSAVE_HDR_OFFSET / sizeof(u32)] =
+ XSTATE_FPSSE;
+ }
+}
+
+static int kvm_vcpu_ioctl_x86_set_xsave(struct kvm_vcpu *vcpu,
+ struct kvm_xsave *guest_xsave)
+{
+ u64 xstate_bv =
+ *(u64 *)&guest_xsave->region[XSAVE_HDR_OFFSET / sizeof(u32)];
+ if (cpu_has_xsave)
+ memcpy(&vcpu->arch.guest_fpu.state->xsave,
+ guest_xsave->region, sizeof(struct xsave_struct));
+ else {
+ if (xstate_bv & ~XSTATE_FPSSE)
+ return -EINVAL;
+ memcpy(&vcpu->arch.guest_fpu.state->fxsave,
+ guest_xsave->region, sizeof(struct i387_fxsave_struct));
+ }
return 0;
}
+static void kvm_vcpu_ioctl_x86_get_xcrs(struct kvm_vcpu *vcpu,
+ struct kvm_xcrs *guest_xcrs)
+{
+ if (!cpu_has_xsave) {
+ guest_xcrs->nr_xcrs = 0;
+ return;
+ }
+
+ guest_xcrs->nr_xcrs = 1;
+ guest_xcrs->flags = 0;
+ guest_xcrs->xcrs[0].xcr = XCR_XFEATURE_ENABLED_MASK;
+ guest_xcrs->xcrs[0].value = vcpu->arch.xcr0;
+}
+
+static int kvm_vcpu_ioctl_x86_set_xcrs(struct kvm_vcpu *vcpu,
+ struct kvm_xcrs *guest_xcrs)
+{
+ int i, r = 0;
+
+ if (!cpu_has_xsave)
+ return -EINVAL;
+
+ if (guest_xcrs->nr_xcrs > KVM_MAX_XCRS || guest_xcrs->flags)
+ return -EINVAL;
+
+ for (i = 0; i < guest_xcrs->nr_xcrs; i++)
+ /* Only support XCR0 currently */
+ if (guest_xcrs->xcrs[0].xcr == XCR_XFEATURE_ENABLED_MASK) {
+ r = __kvm_set_xcr(vcpu, XCR_XFEATURE_ENABLED_MASK,
+ guest_xcrs->xcrs[0].value);
+ break;
+ }
+ if (r)
+ r = -EINVAL;
+ return r;
+}
+
long kvm_arch_vcpu_ioctl(struct file *filp,
unsigned int ioctl, unsigned long arg)
{
struct kvm_vcpu *vcpu = filp->private_data;
void __user *argp = (void __user *)arg;
int r;
- struct kvm_lapic_state *lapic = NULL;
+ union {
+ struct kvm_lapic_state *lapic;
+ struct kvm_xsave *xsave;
+ struct kvm_xcrs *xcrs;
+ void *buffer;
+ } u;
+ u.buffer = NULL;
switch (ioctl) {
case KVM_GET_LAPIC: {
r = -EINVAL;
if (!vcpu->arch.apic)
goto out;
- lapic = kzalloc(sizeof(struct kvm_lapic_state), GFP_KERNEL);
+ u.lapic = kzalloc(sizeof(struct kvm_lapic_state), GFP_KERNEL);
r = -ENOMEM;
- if (!lapic)
+ if (!u.lapic)
goto out;
- r = kvm_vcpu_ioctl_get_lapic(vcpu, lapic);
+ r = kvm_vcpu_ioctl_get_lapic(vcpu, u.lapic);
if (r)
goto out;
r = -EFAULT;
- if (copy_to_user(argp, lapic, sizeof(struct kvm_lapic_state)))
+ if (copy_to_user(argp, u.lapic, sizeof(struct kvm_lapic_state)))
goto out;
r = 0;
break;
@@ -2341,14 +2489,14 @@ long kvm_arch_vcpu_ioctl(struct file *filp,
r = -EINVAL;
if (!vcpu->arch.apic)
goto out;
- lapic = kmalloc(sizeof(struct kvm_lapic_state), GFP_KERNEL);
+ u.lapic = kmalloc(sizeof(struct kvm_lapic_state), GFP_KERNEL);
r = -ENOMEM;
- if (!lapic)
+ if (!u.lapic)
goto out;
r = -EFAULT;
- if (copy_from_user(lapic, argp, sizeof(struct kvm_lapic_state)))
+ if (copy_from_user(u.lapic, argp, sizeof(struct kvm_lapic_state)))
goto out;
- r = kvm_vcpu_ioctl_set_lapic(vcpu, lapic);
+ r = kvm_vcpu_ioctl_set_lapic(vcpu, u.lapic);
if (r)
goto out;
r = 0;
@@ -2464,9 +2612,7 @@ long kvm_arch_vcpu_ioctl(struct file *filp,
r = -EFAULT;
if (copy_from_user(&mce, argp, sizeof mce))
goto out;
- vcpu_load(vcpu);
r = kvm_vcpu_ioctl_x86_set_mce(vcpu, &mce);
- vcpu_put(vcpu);
break;
}
case KVM_GET_VCPU_EVENTS: {
@@ -2513,11 +2659,67 @@ long kvm_arch_vcpu_ioctl(struct file *filp,
r = kvm_vcpu_ioctl_x86_set_debugregs(vcpu, &dbgregs);
break;
}
+ case KVM_GET_XSAVE: {
+ u.xsave = kzalloc(sizeof(struct kvm_xsave), GFP_KERNEL);
+ r = -ENOMEM;
+ if (!u.xsave)
+ break;
+
+ kvm_vcpu_ioctl_x86_get_xsave(vcpu, u.xsave);
+
+ r = -EFAULT;
+ if (copy_to_user(argp, u.xsave, sizeof(struct kvm_xsave)))
+ break;
+ r = 0;
+ break;
+ }
+ case KVM_SET_XSAVE: {
+ u.xsave = kzalloc(sizeof(struct kvm_xsave), GFP_KERNEL);
+ r = -ENOMEM;
+ if (!u.xsave)
+ break;
+
+ r = -EFAULT;
+ if (copy_from_user(u.xsave, argp, sizeof(struct kvm_xsave)))
+ break;
+
+ r = kvm_vcpu_ioctl_x86_set_xsave(vcpu, u.xsave);
+ break;
+ }
+ case KVM_GET_XCRS: {
+ u.xcrs = kzalloc(sizeof(struct kvm_xcrs), GFP_KERNEL);
+ r = -ENOMEM;
+ if (!u.xcrs)
+ break;
+
+ kvm_vcpu_ioctl_x86_get_xcrs(vcpu, u.xcrs);
+
+ r = -EFAULT;
+ if (copy_to_user(argp, u.xcrs,
+ sizeof(struct kvm_xcrs)))
+ break;
+ r = 0;
+ break;
+ }
+ case KVM_SET_XCRS: {
+ u.xcrs = kzalloc(sizeof(struct kvm_xcrs), GFP_KERNEL);
+ r = -ENOMEM;
+ if (!u.xcrs)
+ break;
+
+ r = -EFAULT;
+ if (copy_from_user(u.xcrs, argp,
+ sizeof(struct kvm_xcrs)))
+ break;
+
+ r = kvm_vcpu_ioctl_x86_set_xcrs(vcpu, u.xcrs);
+ break;
+ }
default:
r = -EINVAL;
}
out:
- kfree(lapic);
+ kfree(u.buffer);
return r;
}
@@ -2560,115 +2762,6 @@ static int kvm_vm_ioctl_get_nr_mmu_pages(struct kvm *kvm)
return kvm->arch.n_alloc_mmu_pages;
}
-gfn_t unalias_gfn_instantiation(struct kvm *kvm, gfn_t gfn)
-{
- int i;
- struct kvm_mem_alias *alias;
- struct kvm_mem_aliases *aliases;
-
- aliases = kvm_aliases(kvm);
-
- for (i = 0; i < aliases->naliases; ++i) {
- alias = &aliases->aliases[i];
- if (alias->flags & KVM_ALIAS_INVALID)
- continue;
- if (gfn >= alias->base_gfn
- && gfn < alias->base_gfn + alias->npages)
- return alias->target_gfn + gfn - alias->base_gfn;
- }
- return gfn;
-}
-
-gfn_t unalias_gfn(struct kvm *kvm, gfn_t gfn)
-{
- int i;
- struct kvm_mem_alias *alias;
- struct kvm_mem_aliases *aliases;
-
- aliases = kvm_aliases(kvm);
-
- for (i = 0; i < aliases->naliases; ++i) {
- alias = &aliases->aliases[i];
- if (gfn >= alias->base_gfn
- && gfn < alias->base_gfn + alias->npages)
- return alias->target_gfn + gfn - alias->base_gfn;
- }
- return gfn;
-}
-
-/*
- * Set a new alias region. Aliases map a portion of physical memory into
- * another portion. This is useful for memory windows, for example the PC
- * VGA region.
- */
-static int kvm_vm_ioctl_set_memory_alias(struct kvm *kvm,
- struct kvm_memory_alias *alias)
-{
- int r, n;
- struct kvm_mem_alias *p;
- struct kvm_mem_aliases *aliases, *old_aliases;
-
- r = -EINVAL;
- /* General sanity checks */
- if (alias->memory_size & (PAGE_SIZE - 1))
- goto out;
- if (alias->guest_phys_addr & (PAGE_SIZE - 1))
- goto out;
- if (alias->slot >= KVM_ALIAS_SLOTS)
- goto out;
- if (alias->guest_phys_addr + alias->memory_size
- < alias->guest_phys_addr)
- goto out;
- if (alias->target_phys_addr + alias->memory_size
- < alias->target_phys_addr)
- goto out;
-
- r = -ENOMEM;
- aliases = kzalloc(sizeof(struct kvm_mem_aliases), GFP_KERNEL);
- if (!aliases)
- goto out;
-
- mutex_lock(&kvm->slots_lock);
-
- /* invalidate any gfn reference in case of deletion/shrinking */
- memcpy(aliases, kvm->arch.aliases, sizeof(struct kvm_mem_aliases));
- aliases->aliases[alias->slot].flags |= KVM_ALIAS_INVALID;
- old_aliases = kvm->arch.aliases;
- rcu_assign_pointer(kvm->arch.aliases, aliases);
- synchronize_srcu_expedited(&kvm->srcu);
- kvm_mmu_zap_all(kvm);
- kfree(old_aliases);
-
- r = -ENOMEM;
- aliases = kzalloc(sizeof(struct kvm_mem_aliases), GFP_KERNEL);
- if (!aliases)
- goto out_unlock;
-
- memcpy(aliases, kvm->arch.aliases, sizeof(struct kvm_mem_aliases));
-
- p = &aliases->aliases[alias->slot];
- p->base_gfn = alias->guest_phys_addr >> PAGE_SHIFT;
- p->npages = alias->memory_size >> PAGE_SHIFT;
- p->target_gfn = alias->target_phys_addr >> PAGE_SHIFT;
- p->flags &= ~(KVM_ALIAS_INVALID);
-
- for (n = KVM_ALIAS_SLOTS; n > 0; --n)
- if (aliases->aliases[n - 1].npages)
- break;
- aliases->naliases = n;
-
- old_aliases = kvm->arch.aliases;
- rcu_assign_pointer(kvm->arch.aliases, aliases);
- synchronize_srcu_expedited(&kvm->srcu);
- kfree(old_aliases);
- r = 0;
-
-out_unlock:
- mutex_unlock(&kvm->slots_lock);
-out:
- return r;
-}
-
static int kvm_vm_ioctl_get_irqchip(struct kvm *kvm, struct kvm_irqchip *chip)
{
int r;
@@ -2797,7 +2890,6 @@ int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm,
struct kvm_memory_slot *memslot;
unsigned long n;
unsigned long is_dirty = 0;
- unsigned long *dirty_bitmap = NULL;
mutex_lock(&kvm->slots_lock);
@@ -2812,27 +2904,30 @@ int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm,
n = kvm_dirty_bitmap_bytes(memslot);
- r = -ENOMEM;
- dirty_bitmap = vmalloc(n);
- if (!dirty_bitmap)
- goto out;
- memset(dirty_bitmap, 0, n);
-
for (i = 0; !is_dirty && i < n/sizeof(long); i++)
is_dirty = memslot->dirty_bitmap[i];
/* If nothing is dirty, don't bother messing with page tables. */
if (is_dirty) {
struct kvm_memslots *slots, *old_slots;
+ unsigned long *dirty_bitmap;
spin_lock(&kvm->mmu_lock);
kvm_mmu_slot_remove_write_access(kvm, log->slot);
spin_unlock(&kvm->mmu_lock);
- slots = kzalloc(sizeof(struct kvm_memslots), GFP_KERNEL);
- if (!slots)
- goto out_free;
+ r = -ENOMEM;
+ dirty_bitmap = vmalloc(n);
+ if (!dirty_bitmap)
+ goto out;
+ memset(dirty_bitmap, 0, n);
+ r = -ENOMEM;
+ slots = kzalloc(sizeof(struct kvm_memslots), GFP_KERNEL);
+ if (!slots) {
+ vfree(dirty_bitmap);
+ goto out;
+ }
memcpy(slots, kvm->memslots, sizeof(struct kvm_memslots));
slots->memslots[log->slot].dirty_bitmap = dirty_bitmap;
@@ -2841,13 +2936,20 @@ int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm,
synchronize_srcu_expedited(&kvm->srcu);
dirty_bitmap = old_slots->memslots[log->slot].dirty_bitmap;
kfree(old_slots);
+
+ r = -EFAULT;
+ if (copy_to_user(log->dirty_bitmap, dirty_bitmap, n)) {
+ vfree(dirty_bitmap);
+ goto out;
+ }
+ vfree(dirty_bitmap);
+ } else {
+ r = -EFAULT;
+ if (clear_user(log->dirty_bitmap, n))
+ goto out;
}
r = 0;
- if (copy_to_user(log->dirty_bitmap, dirty_bitmap, n))
- r = -EFAULT;
-out_free:
- vfree(dirty_bitmap);
out:
mutex_unlock(&kvm->slots_lock);
return r;
@@ -2867,7 +2969,6 @@ long kvm_arch_vm_ioctl(struct file *filp,
union {
struct kvm_pit_state ps;
struct kvm_pit_state2 ps2;
- struct kvm_memory_alias alias;
struct kvm_pit_config pit_config;
} u;
@@ -2888,22 +2989,6 @@ long kvm_arch_vm_ioctl(struct file *filp,
goto out;
break;
}
- case KVM_SET_MEMORY_REGION: {
- struct kvm_memory_region kvm_mem;
- struct kvm_userspace_memory_region kvm_userspace_mem;
-
- r = -EFAULT;
- if (copy_from_user(&kvm_mem, argp, sizeof kvm_mem))
- goto out;
- kvm_userspace_mem.slot = kvm_mem.slot;
- kvm_userspace_mem.flags = kvm_mem.flags;
- kvm_userspace_mem.guest_phys_addr = kvm_mem.guest_phys_addr;
- kvm_userspace_mem.memory_size = kvm_mem.memory_size;
- r = kvm_vm_ioctl_set_memory_region(kvm, &kvm_userspace_mem, 0);
- if (r)
- goto out;
- break;
- }
case KVM_SET_NR_MMU_PAGES:
r = kvm_vm_ioctl_set_nr_mmu_pages(kvm, arg);
if (r)
@@ -2912,14 +2997,6 @@ long kvm_arch_vm_ioctl(struct file *filp,
case KVM_GET_NR_MMU_PAGES:
r = kvm_vm_ioctl_get_nr_mmu_pages(kvm);
break;
- case KVM_SET_MEMORY_ALIAS:
- r = -EFAULT;
- if (copy_from_user(&u.alias, argp, sizeof(struct kvm_memory_alias)))
- goto out;
- r = kvm_vm_ioctl_set_memory_alias(kvm, &u.alias);
- if (r)
- goto out;
- break;
case KVM_CREATE_IRQCHIP: {
struct kvm_pic *vpic;
@@ -3259,7 +3336,7 @@ static int kvm_read_guest_virt_helper(gva_t addr, void *val, unsigned int bytes,
}
ret = kvm_read_guest(vcpu->kvm, gpa, data, toread);
if (ret < 0) {
- r = X86EMUL_UNHANDLEABLE;
+ r = X86EMUL_IO_NEEDED;
goto out;
}
@@ -3315,7 +3392,7 @@ static int kvm_write_guest_virt_system(gva_t addr, void *val,
}
ret = kvm_write_guest(vcpu->kvm, gpa, data, towrite);
if (ret < 0) {
- r = X86EMUL_UNHANDLEABLE;
+ r = X86EMUL_IO_NEEDED;
goto out;
}
@@ -3330,10 +3407,10 @@ out:
static int emulator_read_emulated(unsigned long addr,
void *val,
unsigned int bytes,
+ unsigned int *error_code,
struct kvm_vcpu *vcpu)
{
gpa_t gpa;
- u32 error_code;
if (vcpu->mmio_read_completed) {
memcpy(val, vcpu->mmio_data, bytes);
@@ -3343,12 +3420,10 @@ static int emulator_read_emulated(unsigned long addr,
return X86EMUL_CONTINUE;
}
- gpa = kvm_mmu_gva_to_gpa_read(vcpu, addr, &error_code);
+ gpa = kvm_mmu_gva_to_gpa_read(vcpu, addr, error_code);
- if (gpa == UNMAPPED_GVA) {
- kvm_inject_page_fault(vcpu, addr, error_code);
+ if (gpa == UNMAPPED_GVA)
return X86EMUL_PROPAGATE_FAULT;
- }
/* For APIC access vmexit */
if ((gpa & PAGE_MASK) == APIC_DEFAULT_PHYS_BASE)
@@ -3370,11 +3445,12 @@ mmio:
trace_kvm_mmio(KVM_TRACE_MMIO_READ_UNSATISFIED, bytes, gpa, 0);
vcpu->mmio_needed = 1;
- vcpu->mmio_phys_addr = gpa;
- vcpu->mmio_size = bytes;
- vcpu->mmio_is_write = 0;
+ vcpu->run->exit_reason = KVM_EXIT_MMIO;
+ vcpu->run->mmio.phys_addr = vcpu->mmio_phys_addr = gpa;
+ vcpu->run->mmio.len = vcpu->mmio_size = bytes;
+ vcpu->run->mmio.is_write = vcpu->mmio_is_write = 0;
- return X86EMUL_UNHANDLEABLE;
+ return X86EMUL_IO_NEEDED;
}
int emulator_write_phys(struct kvm_vcpu *vcpu, gpa_t gpa,
@@ -3392,17 +3468,15 @@ int emulator_write_phys(struct kvm_vcpu *vcpu, gpa_t gpa,
static int emulator_write_emulated_onepage(unsigned long addr,
const void *val,
unsigned int bytes,
+ unsigned int *error_code,
struct kvm_vcpu *vcpu)
{
gpa_t gpa;
- u32 error_code;
- gpa = kvm_mmu_gva_to_gpa_write(vcpu, addr, &error_code);
+ gpa = kvm_mmu_gva_to_gpa_write(vcpu, addr, error_code);
- if (gpa == UNMAPPED_GVA) {
- kvm_inject_page_fault(vcpu, addr, error_code);
+ if (gpa == UNMAPPED_GVA)
return X86EMUL_PROPAGATE_FAULT;
- }
/* For APIC access vmexit */
if ((gpa & PAGE_MASK) == APIC_DEFAULT_PHYS_BASE)
@@ -3420,10 +3494,11 @@ mmio:
return X86EMUL_CONTINUE;
vcpu->mmio_needed = 1;
- vcpu->mmio_phys_addr = gpa;
- vcpu->mmio_size = bytes;
- vcpu->mmio_is_write = 1;
- memcpy(vcpu->mmio_data, val, bytes);
+ vcpu->run->exit_reason = KVM_EXIT_MMIO;
+ vcpu->run->mmio.phys_addr = vcpu->mmio_phys_addr = gpa;
+ vcpu->run->mmio.len = vcpu->mmio_size = bytes;
+ vcpu->run->mmio.is_write = vcpu->mmio_is_write = 1;
+ memcpy(vcpu->run->mmio.data, val, bytes);
return X86EMUL_CONTINUE;
}
@@ -3431,6 +3506,7 @@ mmio:
int emulator_write_emulated(unsigned long addr,
const void *val,
unsigned int bytes,
+ unsigned int *error_code,
struct kvm_vcpu *vcpu)
{
/* Crossing a page boundary? */
@@ -3438,16 +3514,17 @@ int emulator_write_emulated(unsigned long addr,
int rc, now;
now = -addr & ~PAGE_MASK;
- rc = emulator_write_emulated_onepage(addr, val, now, vcpu);
+ rc = emulator_write_emulated_onepage(addr, val, now, error_code,
+ vcpu);
if (rc != X86EMUL_CONTINUE)
return rc;
addr += now;
val += now;
bytes -= now;
}
- return emulator_write_emulated_onepage(addr, val, bytes, vcpu);
+ return emulator_write_emulated_onepage(addr, val, bytes, error_code,
+ vcpu);
}
-EXPORT_SYMBOL_GPL(emulator_write_emulated);
#define CMPXCHG_TYPE(t, ptr, old, new) \
(cmpxchg((t *)(ptr), *(t *)(old), *(t *)(new)) == *(t *)(old))
@@ -3463,6 +3540,7 @@ static int emulator_cmpxchg_emulated(unsigned long addr,
const void *old,
const void *new,
unsigned int bytes,
+ unsigned int *error_code,
struct kvm_vcpu *vcpu)
{
gpa_t gpa;
@@ -3484,6 +3562,10 @@ static int emulator_cmpxchg_emulated(unsigned long addr,
goto emul_write;
page = gfn_to_page(vcpu->kvm, gpa >> PAGE_SHIFT);
+ if (is_error_page(page)) {
+ kvm_release_page_clean(page);
+ goto emul_write;
+ }
kaddr = kmap_atomic(page, KM_USER0);
kaddr += offset_in_page(gpa);
@@ -3516,7 +3598,7 @@ static int emulator_cmpxchg_emulated(unsigned long addr,
emul_write:
printk_once(KERN_WARNING "kvm: emulating exchange as write\n");
- return emulator_write_emulated(addr, new, bytes, vcpu);
+ return emulator_write_emulated(addr, new, bytes, error_code, vcpu);
}
static int kernel_pio(struct kvm_vcpu *vcpu, void *pd)
@@ -3604,42 +3686,38 @@ int emulate_invlpg(struct kvm_vcpu *vcpu, gva_t address)
return X86EMUL_CONTINUE;
}
-int emulate_clts(struct kvm_vcpu *vcpu)
+int kvm_emulate_wbinvd(struct kvm_vcpu *vcpu)
{
- kvm_x86_ops->set_cr0(vcpu, kvm_read_cr0_bits(vcpu, ~X86_CR0_TS));
- kvm_x86_ops->fpu_activate(vcpu);
+ if (!need_emulate_wbinvd(vcpu))
+ return X86EMUL_CONTINUE;
+
+ if (kvm_x86_ops->has_wbinvd_exit()) {
+ smp_call_function_many(vcpu->arch.wbinvd_dirty_mask,
+ wbinvd_ipi, NULL, 1);
+ cpumask_clear(vcpu->arch.wbinvd_dirty_mask);
+ }
+ wbinvd();
return X86EMUL_CONTINUE;
}
+EXPORT_SYMBOL_GPL(kvm_emulate_wbinvd);
-int emulator_get_dr(struct x86_emulate_ctxt *ctxt, int dr, unsigned long *dest)
+int emulate_clts(struct kvm_vcpu *vcpu)
{
- return kvm_get_dr(ctxt->vcpu, dr, dest);
+ kvm_x86_ops->set_cr0(vcpu, kvm_read_cr0_bits(vcpu, ~X86_CR0_TS));
+ kvm_x86_ops->fpu_activate(vcpu);
+ return X86EMUL_CONTINUE;
}
-int emulator_set_dr(struct x86_emulate_ctxt *ctxt, int dr, unsigned long value)
+int emulator_get_dr(int dr, unsigned long *dest, struct kvm_vcpu *vcpu)
{
- unsigned long mask = (ctxt->mode == X86EMUL_MODE_PROT64) ? ~0ULL : ~0U;
-
- return kvm_set_dr(ctxt->vcpu, dr, value & mask);
+ return _kvm_get_dr(vcpu, dr, dest);
}
-void kvm_report_emulation_failure(struct kvm_vcpu *vcpu, const char *context)
+int emulator_set_dr(int dr, unsigned long value, struct kvm_vcpu *vcpu)
{
- u8 opcodes[4];
- unsigned long rip = kvm_rip_read(vcpu);
- unsigned long rip_linear;
-
- if (!printk_ratelimit())
- return;
- rip_linear = rip + get_segment_base(vcpu, VCPU_SREG_CS);
-
- kvm_read_guest_virt(rip_linear, (void *)opcodes, 4, vcpu, NULL);
-
- printk(KERN_ERR "emulation failed (%s) rip %lx %02x %02x %02x %02x\n",
- context, rip, opcodes[0], opcodes[1], opcodes[2], opcodes[3]);
+ return __kvm_set_dr(vcpu, dr, value);
}
-EXPORT_SYMBOL_GPL(kvm_report_emulation_failure);
static u64 mk_cr_64(u64 curr_cr, u32 new_val)
{
@@ -3674,27 +3752,32 @@ static unsigned long emulator_get_cr(int cr, struct kvm_vcpu *vcpu)
return value;
}
-static void emulator_set_cr(int cr, unsigned long val, struct kvm_vcpu *vcpu)
+static int emulator_set_cr(int cr, unsigned long val, struct kvm_vcpu *vcpu)
{
+ int res = 0;
+
switch (cr) {
case 0:
- kvm_set_cr0(vcpu, mk_cr_64(kvm_read_cr0(vcpu), val));
+ res = kvm_set_cr0(vcpu, mk_cr_64(kvm_read_cr0(vcpu), val));
break;
case 2:
vcpu->arch.cr2 = val;
break;
case 3:
- kvm_set_cr3(vcpu, val);
+ res = kvm_set_cr3(vcpu, val);
break;
case 4:
- kvm_set_cr4(vcpu, mk_cr_64(kvm_read_cr4(vcpu), val));
+ res = kvm_set_cr4(vcpu, mk_cr_64(kvm_read_cr4(vcpu), val));
break;
case 8:
- kvm_set_cr8(vcpu, val & 0xfUL);
+ res = __kvm_set_cr8(vcpu, val & 0xfUL);
break;
default:
vcpu_printf(vcpu, "%s: unexpected cr %u\n", __func__, cr);
+ res = -1;
}
+
+ return res;
}
static int emulator_get_cpl(struct kvm_vcpu *vcpu)
@@ -3707,6 +3790,12 @@ static void emulator_get_gdt(struct desc_ptr *dt, struct kvm_vcpu *vcpu)
kvm_x86_ops->get_gdt(vcpu, dt);
}
+static unsigned long emulator_get_cached_segment_base(int seg,
+ struct kvm_vcpu *vcpu)
+{
+ return get_segment_base(vcpu, seg);
+}
+
static bool emulator_get_cached_descriptor(struct desc_struct *desc, int seg,
struct kvm_vcpu *vcpu)
{
@@ -3779,11 +3868,6 @@ static void emulator_set_segment_selector(u16 sel, int seg,
kvm_set_segment(vcpu, &kvm_seg, seg);
}
-static void emulator_set_rflags(struct kvm_vcpu *vcpu, unsigned long rflags)
-{
- kvm_x86_ops->set_rflags(vcpu, rflags);
-}
-
static struct x86_emulate_ops emulate_ops = {
.read_std = kvm_read_guest_virt_system,
.write_std = kvm_write_guest_virt_system,
@@ -3797,11 +3881,15 @@ static struct x86_emulate_ops emulate_ops = {
.set_cached_descriptor = emulator_set_cached_descriptor,
.get_segment_selector = emulator_get_segment_selector,
.set_segment_selector = emulator_set_segment_selector,
+ .get_cached_segment_base = emulator_get_cached_segment_base,
.get_gdt = emulator_get_gdt,
.get_cr = emulator_get_cr,
.set_cr = emulator_set_cr,
.cpl = emulator_get_cpl,
- .set_rflags = emulator_set_rflags,
+ .get_dr = emulator_get_dr,
+ .set_dr = emulator_set_dr,
+ .set_msr = kvm_set_msr,
+ .get_msr = kvm_get_msr,
};
static void cache_all_regs(struct kvm_vcpu *vcpu)
@@ -3812,14 +3900,75 @@ static void cache_all_regs(struct kvm_vcpu *vcpu)
vcpu->arch.regs_dirty = ~0;
}
+static void toggle_interruptibility(struct kvm_vcpu *vcpu, u32 mask)
+{
+ u32 int_shadow = kvm_x86_ops->get_interrupt_shadow(vcpu, mask);
+ /*
+ * an sti; sti; sequence only disable interrupts for the first
+ * instruction. So, if the last instruction, be it emulated or
+ * not, left the system with the INT_STI flag enabled, it
+ * means that the last instruction is an sti. We should not
+ * leave the flag on in this case. The same goes for mov ss
+ */
+ if (!(int_shadow & mask))
+ kvm_x86_ops->set_interrupt_shadow(vcpu, mask);
+}
+
+static void inject_emulated_exception(struct kvm_vcpu *vcpu)
+{
+ struct x86_emulate_ctxt *ctxt = &vcpu->arch.emulate_ctxt;
+ if (ctxt->exception == PF_VECTOR)
+ kvm_inject_page_fault(vcpu, ctxt->cr2, ctxt->error_code);
+ else if (ctxt->error_code_valid)
+ kvm_queue_exception_e(vcpu, ctxt->exception, ctxt->error_code);
+ else
+ kvm_queue_exception(vcpu, ctxt->exception);
+}
+
+static int handle_emulation_failure(struct kvm_vcpu *vcpu)
+{
+ ++vcpu->stat.insn_emulation_fail;
+ trace_kvm_emulate_insn_failed(vcpu);
+ vcpu->run->exit_reason = KVM_EXIT_INTERNAL_ERROR;
+ vcpu->run->internal.suberror = KVM_INTERNAL_ERROR_EMULATION;
+ vcpu->run->internal.ndata = 0;
+ kvm_queue_exception(vcpu, UD_VECTOR);
+ return EMULATE_FAIL;
+}
+
+static bool reexecute_instruction(struct kvm_vcpu *vcpu, gva_t gva)
+{
+ gpa_t gpa;
+
+ if (tdp_enabled)
+ return false;
+
+ /*
+ * if emulation was due to access to shadowed page table
+ * and it failed try to unshadow page and re-entetr the
+ * guest to let CPU execute the instruction.
+ */
+ if (kvm_mmu_unprotect_page_virt(vcpu, gva))
+ return true;
+
+ gpa = kvm_mmu_gva_to_gpa_system(vcpu, gva, NULL);
+
+ if (gpa == UNMAPPED_GVA)
+ return true; /* let cpu generate fault */
+
+ if (!kvm_is_error_hva(gfn_to_hva(vcpu->kvm, gpa >> PAGE_SHIFT)))
+ return true;
+
+ return false;
+}
+
int emulate_instruction(struct kvm_vcpu *vcpu,
unsigned long cr2,
u16 error_code,
int emulation_type)
{
- int r, shadow_mask;
- struct decode_cache *c;
- struct kvm_run *run = vcpu->run;
+ int r;
+ struct decode_cache *c = &vcpu->arch.emulate_ctxt.decode;
kvm_clear_exception_queue(vcpu);
vcpu->arch.mmio_fault_cr2 = cr2;
@@ -3831,8 +3980,6 @@ int emulate_instruction(struct kvm_vcpu *vcpu,
*/
cache_all_regs(vcpu);
- vcpu->mmio_is_write = 0;
-
if (!(emulation_type & EMULTYPE_NO_DECODE)) {
int cs_db, cs_l;
kvm_x86_ops->get_cs_db_l_bits(vcpu, &cs_db, &cs_l);
@@ -3846,13 +3993,16 @@ int emulate_instruction(struct kvm_vcpu *vcpu,
? X86EMUL_MODE_VM86 : cs_l
? X86EMUL_MODE_PROT64 : cs_db
? X86EMUL_MODE_PROT32 : X86EMUL_MODE_PROT16;
+ memset(c, 0, sizeof(struct decode_cache));
+ memcpy(c->regs, vcpu->arch.regs, sizeof c->regs);
+ vcpu->arch.emulate_ctxt.interruptibility = 0;
+ vcpu->arch.emulate_ctxt.exception = -1;
r = x86_decode_insn(&vcpu->arch.emulate_ctxt, &emulate_ops);
trace_kvm_emulate_insn_start(vcpu);
/* Only allow emulation of specific instructions on #UD
* (namely VMMCALL, sysenter, sysexit, syscall)*/
- c = &vcpu->arch.emulate_ctxt.decode;
if (emulation_type & EMULTYPE_TRAP_UD) {
if (!c->twobyte)
return EMULATE_FAIL;
@@ -3880,11 +4030,11 @@ int emulate_instruction(struct kvm_vcpu *vcpu,
++vcpu->stat.insn_emulation;
if (r) {
- ++vcpu->stat.insn_emulation_fail;
- trace_kvm_emulate_insn_failed(vcpu);
- if (kvm_mmu_unprotect_page_virt(vcpu, cr2))
+ if (reexecute_instruction(vcpu, cr2))
return EMULATE_DONE;
- return EMULATE_FAIL;
+ if (emulation_type & EMULTYPE_SKIP)
+ return EMULATE_FAIL;
+ return handle_emulation_failure(vcpu);
}
}
@@ -3893,48 +4043,42 @@ int emulate_instruction(struct kvm_vcpu *vcpu,
return EMULATE_DONE;
}
+ /* this is needed for vmware backdor interface to work since it
+ changes registers values during IO operation */
+ memcpy(c->regs, vcpu->arch.regs, sizeof c->regs);
+
restart:
r = x86_emulate_insn(&vcpu->arch.emulate_ctxt, &emulate_ops);
- shadow_mask = vcpu->arch.emulate_ctxt.interruptibility;
- if (r == 0)
- kvm_x86_ops->set_interrupt_shadow(vcpu, shadow_mask);
+ if (r) { /* emulation failed */
+ if (reexecute_instruction(vcpu, cr2))
+ return EMULATE_DONE;
- if (vcpu->arch.pio.count) {
- if (!vcpu->arch.pio.in)
- vcpu->arch.pio.count = 0;
- return EMULATE_DO_MMIO;
+ return handle_emulation_failure(vcpu);
}
- if (r || vcpu->mmio_is_write) {
- run->exit_reason = KVM_EXIT_MMIO;
- run->mmio.phys_addr = vcpu->mmio_phys_addr;
- memcpy(run->mmio.data, vcpu->mmio_data, 8);
- run->mmio.len = vcpu->mmio_size;
- run->mmio.is_write = vcpu->mmio_is_write;
+ toggle_interruptibility(vcpu, vcpu->arch.emulate_ctxt.interruptibility);
+ kvm_x86_ops->set_rflags(vcpu, vcpu->arch.emulate_ctxt.eflags);
+ memcpy(vcpu->arch.regs, c->regs, sizeof c->regs);
+ kvm_rip_write(vcpu, vcpu->arch.emulate_ctxt.eip);
+
+ if (vcpu->arch.emulate_ctxt.exception >= 0) {
+ inject_emulated_exception(vcpu);
+ return EMULATE_DONE;
}
- if (r) {
- if (kvm_mmu_unprotect_page_virt(vcpu, cr2))
- goto done;
- if (!vcpu->mmio_needed) {
- ++vcpu->stat.insn_emulation_fail;
- trace_kvm_emulate_insn_failed(vcpu);
- kvm_report_emulation_failure(vcpu, "mmio");
- return EMULATE_FAIL;
- }
+ if (vcpu->arch.pio.count) {
+ if (!vcpu->arch.pio.in)
+ vcpu->arch.pio.count = 0;
return EMULATE_DO_MMIO;
}
- if (vcpu->mmio_is_write) {
- vcpu->mmio_needed = 0;
+ if (vcpu->mmio_needed) {
+ if (vcpu->mmio_is_write)
+ vcpu->mmio_needed = 0;
return EMULATE_DO_MMIO;
}
-done:
- if (vcpu->arch.exception.pending)
- vcpu->arch.emulate_ctxt.restart = false;
-
if (vcpu->arch.emulate_ctxt.restart)
goto restart;
@@ -4108,6 +4252,9 @@ int kvm_arch_init(void *opaque)
perf_register_guest_info_callbacks(&kvm_guest_cbs);
+ if (cpu_has_xsave)
+ host_xcr0 = xgetbv(XCR_XFEATURE_ENABLED_MASK);
+
return 0;
out:
@@ -4270,7 +4417,7 @@ int kvm_fix_hypercall(struct kvm_vcpu *vcpu)
kvm_x86_ops->patch_hypercall(vcpu, instruction);
- return emulator_write_emulated(rip, instruction, 3, vcpu);
+ return emulator_write_emulated(rip, instruction, 3, NULL, vcpu);
}
void realmode_lgdt(struct kvm_vcpu *vcpu, u16 limit, unsigned long base)
@@ -4506,59 +4653,78 @@ static void inject_pending_event(struct kvm_vcpu *vcpu)
}
}
+static void kvm_load_guest_xcr0(struct kvm_vcpu *vcpu)
+{
+ if (kvm_read_cr4_bits(vcpu, X86_CR4_OSXSAVE) &&
+ !vcpu->guest_xcr0_loaded) {
+ /* kvm_set_xcr() also depends on this */
+ xsetbv(XCR_XFEATURE_ENABLED_MASK, vcpu->arch.xcr0);
+ vcpu->guest_xcr0_loaded = 1;
+ }
+}
+
+static void kvm_put_guest_xcr0(struct kvm_vcpu *vcpu)
+{
+ if (vcpu->guest_xcr0_loaded) {
+ if (vcpu->arch.xcr0 != host_xcr0)
+ xsetbv(XCR_XFEATURE_ENABLED_MASK, host_xcr0);
+ vcpu->guest_xcr0_loaded = 0;
+ }
+}
+
static int vcpu_enter_guest(struct kvm_vcpu *vcpu)
{
int r;
bool req_int_win = !irqchip_in_kernel(vcpu->kvm) &&
vcpu->run->request_interrupt_window;
- if (vcpu->requests)
- if (test_and_clear_bit(KVM_REQ_MMU_RELOAD, &vcpu->requests))
- kvm_mmu_unload(vcpu);
-
- r = kvm_mmu_reload(vcpu);
- if (unlikely(r))
- goto out;
-
if (vcpu->requests) {
- if (test_and_clear_bit(KVM_REQ_MIGRATE_TIMER, &vcpu->requests))
+ if (kvm_check_request(KVM_REQ_MMU_RELOAD, vcpu))
+ kvm_mmu_unload(vcpu);
+ if (kvm_check_request(KVM_REQ_MIGRATE_TIMER, vcpu))
__kvm_migrate_timers(vcpu);
- if (test_and_clear_bit(KVM_REQ_KVMCLOCK_UPDATE, &vcpu->requests))
+ if (kvm_check_request(KVM_REQ_KVMCLOCK_UPDATE, vcpu))
kvm_write_guest_time(vcpu);
- if (test_and_clear_bit(KVM_REQ_MMU_SYNC, &vcpu->requests))
+ if (kvm_check_request(KVM_REQ_MMU_SYNC, vcpu))
kvm_mmu_sync_roots(vcpu);
- if (test_and_clear_bit(KVM_REQ_TLB_FLUSH, &vcpu->requests))
+ if (kvm_check_request(KVM_REQ_TLB_FLUSH, vcpu))
kvm_x86_ops->tlb_flush(vcpu);
- if (test_and_clear_bit(KVM_REQ_REPORT_TPR_ACCESS,
- &vcpu->requests)) {
+ if (kvm_check_request(KVM_REQ_REPORT_TPR_ACCESS, vcpu)) {
vcpu->run->exit_reason = KVM_EXIT_TPR_ACCESS;
r = 0;
goto out;
}
- if (test_and_clear_bit(KVM_REQ_TRIPLE_FAULT, &vcpu->requests)) {
+ if (kvm_check_request(KVM_REQ_TRIPLE_FAULT, vcpu)) {
vcpu->run->exit_reason = KVM_EXIT_SHUTDOWN;
r = 0;
goto out;
}
- if (test_and_clear_bit(KVM_REQ_DEACTIVATE_FPU, &vcpu->requests)) {
+ if (kvm_check_request(KVM_REQ_DEACTIVATE_FPU, vcpu)) {
vcpu->fpu_active = 0;
kvm_x86_ops->fpu_deactivate(vcpu);
}
}
+ r = kvm_mmu_reload(vcpu);
+ if (unlikely(r))
+ goto out;
+
preempt_disable();
kvm_x86_ops->prepare_guest_switch(vcpu);
if (vcpu->fpu_active)
kvm_load_guest_fpu(vcpu);
+ kvm_load_guest_xcr0(vcpu);
- local_irq_disable();
+ atomic_set(&vcpu->guest_mode, 1);
+ smp_wmb();
- clear_bit(KVM_REQ_KICK, &vcpu->requests);
- smp_mb__after_clear_bit();
+ local_irq_disable();
- if (vcpu->requests || need_resched() || signal_pending(current)) {
- set_bit(KVM_REQ_KICK, &vcpu->requests);
+ if (!atomic_read(&vcpu->guest_mode) || vcpu->requests
+ || need_resched() || signal_pending(current)) {
+ atomic_set(&vcpu->guest_mode, 0);
+ smp_wmb();
local_irq_enable();
preempt_enable();
r = 1;
@@ -4603,7 +4769,8 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu)
if (hw_breakpoint_active())
hw_breakpoint_restore();
- set_bit(KVM_REQ_KICK, &vcpu->requests);
+ atomic_set(&vcpu->guest_mode, 0);
+ smp_wmb();
local_irq_enable();
++vcpu->stat.exits;
@@ -4665,7 +4832,7 @@ static int __vcpu_run(struct kvm_vcpu *vcpu)
srcu_read_unlock(&kvm->srcu, vcpu->srcu_idx);
kvm_vcpu_block(vcpu);
vcpu->srcu_idx = srcu_read_lock(&kvm->srcu);
- if (test_and_clear_bit(KVM_REQ_UNHALT, &vcpu->requests))
+ if (kvm_check_request(KVM_REQ_UNHALT, vcpu))
{
switch(vcpu->arch.mp_state) {
case KVM_MP_STATE_HALTED:
@@ -4717,8 +4884,6 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
int r;
sigset_t sigsaved;
- vcpu_load(vcpu);
-
if (vcpu->sigset_active)
sigprocmask(SIG_SETMASK, &vcpu->sigset, &sigsaved);
@@ -4743,7 +4908,7 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
vcpu->srcu_idx = srcu_read_lock(&vcpu->kvm->srcu);
r = emulate_instruction(vcpu, 0, 0, EMULTYPE_NO_DECODE);
srcu_read_unlock(&vcpu->kvm->srcu, vcpu->srcu_idx);
- if (r == EMULATE_DO_MMIO) {
+ if (r != EMULATE_DONE) {
r = 0;
goto out;
}
@@ -4759,14 +4924,11 @@ out:
if (vcpu->sigset_active)
sigprocmask(SIG_SETMASK, &sigsaved, NULL);
- vcpu_put(vcpu);
return r;
}
int kvm_arch_vcpu_ioctl_get_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
{
- vcpu_load(vcpu);
-
regs->rax = kvm_register_read(vcpu, VCPU_REGS_RAX);
regs->rbx = kvm_register_read(vcpu, VCPU_REGS_RBX);
regs->rcx = kvm_register_read(vcpu, VCPU_REGS_RCX);
@@ -4789,15 +4951,11 @@ int kvm_arch_vcpu_ioctl_get_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
regs->rip = kvm_rip_read(vcpu);
regs->rflags = kvm_get_rflags(vcpu);
- vcpu_put(vcpu);
-
return 0;
}
int kvm_arch_vcpu_ioctl_set_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
{
- vcpu_load(vcpu);
-
kvm_register_write(vcpu, VCPU_REGS_RAX, regs->rax);
kvm_register_write(vcpu, VCPU_REGS_RBX, regs->rbx);
kvm_register_write(vcpu, VCPU_REGS_RCX, regs->rcx);
@@ -4822,8 +4980,6 @@ int kvm_arch_vcpu_ioctl_set_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
vcpu->arch.exception.pending = false;
- vcpu_put(vcpu);
-
return 0;
}
@@ -4842,8 +4998,6 @@ int kvm_arch_vcpu_ioctl_get_sregs(struct kvm_vcpu *vcpu,
{
struct desc_ptr dt;
- vcpu_load(vcpu);
-
kvm_get_segment(vcpu, &sregs->cs, VCPU_SREG_CS);
kvm_get_segment(vcpu, &sregs->ds, VCPU_SREG_DS);
kvm_get_segment(vcpu, &sregs->es, VCPU_SREG_ES);
@@ -4875,32 +5029,27 @@ int kvm_arch_vcpu_ioctl_get_sregs(struct kvm_vcpu *vcpu,
set_bit(vcpu->arch.interrupt.nr,
(unsigned long *)sregs->interrupt_bitmap);
- vcpu_put(vcpu);
-
return 0;
}
int kvm_arch_vcpu_ioctl_get_mpstate(struct kvm_vcpu *vcpu,
struct kvm_mp_state *mp_state)
{
- vcpu_load(vcpu);
mp_state->mp_state = vcpu->arch.mp_state;
- vcpu_put(vcpu);
return 0;
}
int kvm_arch_vcpu_ioctl_set_mpstate(struct kvm_vcpu *vcpu,
struct kvm_mp_state *mp_state)
{
- vcpu_load(vcpu);
vcpu->arch.mp_state = mp_state->mp_state;
- vcpu_put(vcpu);
return 0;
}
int kvm_task_switch(struct kvm_vcpu *vcpu, u16 tss_selector, int reason,
bool has_error_code, u32 error_code)
{
+ struct decode_cache *c = &vcpu->arch.emulate_ctxt.decode;
int cs_db, cs_l, ret;
cache_all_regs(vcpu);
@@ -4915,6 +5064,8 @@ int kvm_task_switch(struct kvm_vcpu *vcpu, u16 tss_selector, int reason,
? X86EMUL_MODE_VM86 : cs_l
? X86EMUL_MODE_PROT64 : cs_db
? X86EMUL_MODE_PROT32 : X86EMUL_MODE_PROT16;
+ memset(c, 0, sizeof(struct decode_cache));
+ memcpy(c->regs, vcpu->arch.regs, sizeof c->regs);
ret = emulator_task_switch(&vcpu->arch.emulate_ctxt, &emulate_ops,
tss_selector, reason, has_error_code,
@@ -4923,6 +5074,8 @@ int kvm_task_switch(struct kvm_vcpu *vcpu, u16 tss_selector, int reason,
if (ret)
return EMULATE_FAIL;
+ memcpy(vcpu->arch.regs, c->regs, sizeof c->regs);
+ kvm_rip_write(vcpu, vcpu->arch.emulate_ctxt.eip);
kvm_x86_ops->set_rflags(vcpu, vcpu->arch.emulate_ctxt.eflags);
return EMULATE_DONE;
}
@@ -4935,8 +5088,6 @@ int kvm_arch_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu,
int pending_vec, max_bits;
struct desc_ptr dt;
- vcpu_load(vcpu);
-
dt.size = sregs->idt.limit;
dt.address = sregs->idt.base;
kvm_x86_ops->set_idt(vcpu, &dt);
@@ -4996,8 +5147,6 @@ int kvm_arch_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu,
!is_protmode(vcpu))
vcpu->arch.mp_state = KVM_MP_STATE_RUNNABLE;
- vcpu_put(vcpu);
-
return 0;
}
@@ -5007,12 +5156,10 @@ int kvm_arch_vcpu_ioctl_set_guest_debug(struct kvm_vcpu *vcpu,
unsigned long rflags;
int i, r;
- vcpu_load(vcpu);
-
if (dbg->control & (KVM_GUESTDBG_INJECT_DB | KVM_GUESTDBG_INJECT_BP)) {
r = -EBUSY;
if (vcpu->arch.exception.pending)
- goto unlock_out;
+ goto out;
if (dbg->control & KVM_GUESTDBG_INJECT_DB)
kvm_queue_exception(vcpu, DB_VECTOR);
else
@@ -5054,34 +5201,12 @@ int kvm_arch_vcpu_ioctl_set_guest_debug(struct kvm_vcpu *vcpu,
r = 0;
-unlock_out:
- vcpu_put(vcpu);
+out:
return r;
}
/*
- * fxsave fpu state. Taken from x86_64/processor.h. To be killed when
- * we have asm/x86/processor.h
- */
-struct fxsave {
- u16 cwd;
- u16 swd;
- u16 twd;
- u16 fop;
- u64 rip;
- u64 rdp;
- u32 mxcsr;
- u32 mxcsr_mask;
- u32 st_space[32]; /* 8*16 bytes for each FP-reg = 128 bytes */
-#ifdef CONFIG_X86_64
- u32 xmm_space[64]; /* 16*16 bytes for each XMM-reg = 256 bytes */
-#else
- u32 xmm_space[32]; /* 8*16 bytes for each XMM-reg = 128 bytes */
-#endif
-};
-
-/*
* Translate a guest virtual address to a guest physical address.
*/
int kvm_arch_vcpu_ioctl_translate(struct kvm_vcpu *vcpu,
@@ -5091,7 +5216,6 @@ int kvm_arch_vcpu_ioctl_translate(struct kvm_vcpu *vcpu,
gpa_t gpa;
int idx;
- vcpu_load(vcpu);
idx = srcu_read_lock(&vcpu->kvm->srcu);
gpa = kvm_mmu_gva_to_gpa_system(vcpu, vaddr, NULL);
srcu_read_unlock(&vcpu->kvm->srcu, idx);
@@ -5099,16 +5223,14 @@ int kvm_arch_vcpu_ioctl_translate(struct kvm_vcpu *vcpu,
tr->valid = gpa != UNMAPPED_GVA;
tr->writeable = 1;
tr->usermode = 0;
- vcpu_put(vcpu);
return 0;
}
int kvm_arch_vcpu_ioctl_get_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu)
{
- struct fxsave *fxsave = (struct fxsave *)&vcpu->arch.guest_fx_image;
-
- vcpu_load(vcpu);
+ struct i387_fxsave_struct *fxsave =
+ &vcpu->arch.guest_fpu.state->fxsave;
memcpy(fpu->fpr, fxsave->st_space, 128);
fpu->fcw = fxsave->cwd;
@@ -5119,16 +5241,13 @@ int kvm_arch_vcpu_ioctl_get_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu)
fpu->last_dp = fxsave->rdp;
memcpy(fpu->xmm, fxsave->xmm_space, sizeof fxsave->xmm_space);
- vcpu_put(vcpu);
-
return 0;
}
int kvm_arch_vcpu_ioctl_set_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu)
{
- struct fxsave *fxsave = (struct fxsave *)&vcpu->arch.guest_fx_image;
-
- vcpu_load(vcpu);
+ struct i387_fxsave_struct *fxsave =
+ &vcpu->arch.guest_fpu.state->fxsave;
memcpy(fxsave->st_space, fpu->fpr, 128);
fxsave->cwd = fpu->fcw;
@@ -5139,61 +5258,63 @@ int kvm_arch_vcpu_ioctl_set_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu)
fxsave->rdp = fpu->last_dp;
memcpy(fxsave->xmm_space, fpu->xmm, sizeof fxsave->xmm_space);
- vcpu_put(vcpu);
-
return 0;
}
-void fx_init(struct kvm_vcpu *vcpu)
+int fx_init(struct kvm_vcpu *vcpu)
{
- unsigned after_mxcsr_mask;
+ int err;
+
+ err = fpu_alloc(&vcpu->arch.guest_fpu);
+ if (err)
+ return err;
+
+ fpu_finit(&vcpu->arch.guest_fpu);
/*
- * Touch the fpu the first time in non atomic context as if
- * this is the first fpu instruction the exception handler
- * will fire before the instruction returns and it'll have to
- * allocate ram with GFP_KERNEL.
+ * Ensure guest xcr0 is valid for loading
*/
- if (!used_math())
- kvm_fx_save(&vcpu->arch.host_fx_image);
-
- /* Initialize guest FPU by resetting ours and saving into guest's */
- preempt_disable();
- kvm_fx_save(&vcpu->arch.host_fx_image);
- kvm_fx_finit();
- kvm_fx_save(&vcpu->arch.guest_fx_image);
- kvm_fx_restore(&vcpu->arch.host_fx_image);
- preempt_enable();
+ vcpu->arch.xcr0 = XSTATE_FP;
vcpu->arch.cr0 |= X86_CR0_ET;
- after_mxcsr_mask = offsetof(struct i387_fxsave_struct, st_space);
- vcpu->arch.guest_fx_image.mxcsr = 0x1f80;
- memset((void *)&vcpu->arch.guest_fx_image + after_mxcsr_mask,
- 0, sizeof(struct i387_fxsave_struct) - after_mxcsr_mask);
+
+ return 0;
}
EXPORT_SYMBOL_GPL(fx_init);
+static void fx_free(struct kvm_vcpu *vcpu)
+{
+ fpu_free(&vcpu->arch.guest_fpu);
+}
+
void kvm_load_guest_fpu(struct kvm_vcpu *vcpu)
{
if (vcpu->guest_fpu_loaded)
return;
+ /*
+ * Restore all possible states in the guest,
+ * and assume host would use all available bits.
+ * Guest xcr0 would be loaded later.
+ */
+ kvm_put_guest_xcr0(vcpu);
vcpu->guest_fpu_loaded = 1;
- kvm_fx_save(&vcpu->arch.host_fx_image);
- kvm_fx_restore(&vcpu->arch.guest_fx_image);
+ unlazy_fpu(current);
+ fpu_restore_checking(&vcpu->arch.guest_fpu);
trace_kvm_fpu(1);
}
void kvm_put_guest_fpu(struct kvm_vcpu *vcpu)
{
+ kvm_put_guest_xcr0(vcpu);
+
if (!vcpu->guest_fpu_loaded)
return;
vcpu->guest_fpu_loaded = 0;
- kvm_fx_save(&vcpu->arch.guest_fx_image);
- kvm_fx_restore(&vcpu->arch.host_fx_image);
+ fpu_save_init(&vcpu->arch.guest_fpu);
++vcpu->stat.fpu_reload;
- set_bit(KVM_REQ_DEACTIVATE_FPU, &vcpu->requests);
+ kvm_make_request(KVM_REQ_DEACTIVATE_FPU, vcpu);
trace_kvm_fpu(0);
}
@@ -5204,6 +5325,8 @@ void kvm_arch_vcpu_free(struct kvm_vcpu *vcpu)
vcpu->arch.time_page = NULL;
}
+ free_cpumask_var(vcpu->arch.wbinvd_dirty_mask);
+ fx_free(vcpu);
kvm_x86_ops->vcpu_free(vcpu);
}
@@ -5217,9 +5340,6 @@ int kvm_arch_vcpu_setup(struct kvm_vcpu *vcpu)
{
int r;
- /* We do fxsave: this must be aligned. */
- BUG_ON((unsigned long)&vcpu->arch.host_fx_image & 0xF);
-
vcpu->arch.mtrr_state.have_fixed = 1;
vcpu_load(vcpu);
r = kvm_arch_vcpu_reset(vcpu);
@@ -5241,6 +5361,7 @@ void kvm_arch_vcpu_destroy(struct kvm_vcpu *vcpu)
kvm_mmu_unload(vcpu);
vcpu_put(vcpu);
+ fx_free(vcpu);
kvm_x86_ops->vcpu_free(vcpu);
}
@@ -5334,7 +5455,12 @@ int kvm_arch_vcpu_init(struct kvm_vcpu *vcpu)
}
vcpu->arch.mcg_cap = KVM_MAX_MCE_BANKS;
+ if (!zalloc_cpumask_var(&vcpu->arch.wbinvd_dirty_mask, GFP_KERNEL))
+ goto fail_free_mce_banks;
+
return 0;
+fail_free_mce_banks:
+ kfree(vcpu->arch.mce_banks);
fail_free_lapic:
kvm_free_lapic(vcpu);
fail_mmu_destroy:
@@ -5364,12 +5490,6 @@ struct kvm *kvm_arch_create_vm(void)
if (!kvm)
return ERR_PTR(-ENOMEM);
- kvm->arch.aliases = kzalloc(sizeof(struct kvm_mem_aliases), GFP_KERNEL);
- if (!kvm->arch.aliases) {
- kfree(kvm);
- return ERR_PTR(-ENOMEM);
- }
-
INIT_LIST_HEAD(&kvm->arch.active_mmu_pages);
INIT_LIST_HEAD(&kvm->arch.assigned_dev_head);
@@ -5412,12 +5532,12 @@ static void kvm_free_vcpus(struct kvm *kvm)
void kvm_arch_sync_events(struct kvm *kvm)
{
kvm_free_all_assigned_devices(kvm);
+ kvm_free_pit(kvm);
}
void kvm_arch_destroy_vm(struct kvm *kvm)
{
kvm_iommu_unmap_guest(kvm);
- kvm_free_pit(kvm);
kfree(kvm->arch.vpic);
kfree(kvm->arch.vioapic);
kvm_free_vcpus(kvm);
@@ -5427,7 +5547,6 @@ void kvm_arch_destroy_vm(struct kvm *kvm)
if (kvm->arch.ept_identity_pagetable)
put_page(kvm->arch.ept_identity_pagetable);
cleanup_srcu_struct(&kvm->srcu);
- kfree(kvm->arch.aliases);
kfree(kvm);
}
@@ -5438,6 +5557,11 @@ int kvm_arch_prepare_memory_region(struct kvm *kvm,
int user_alloc)
{
int npages = memslot->npages;
+ int map_flags = MAP_PRIVATE | MAP_ANONYMOUS;
+
+ /* Prevent internal slot pages from being moved by fork()/COW. */
+ if (memslot->id >= KVM_MEMORY_SLOTS)
+ map_flags = MAP_SHARED | MAP_ANONYMOUS;
/*To keep backward compatibility with older userspace,
*x86 needs to hanlde !user_alloc case.
@@ -5450,7 +5574,7 @@ int kvm_arch_prepare_memory_region(struct kvm *kvm,
userspace_addr = do_mmap(NULL, 0,
npages * PAGE_SIZE,
PROT_READ | PROT_WRITE,
- MAP_PRIVATE | MAP_ANONYMOUS,
+ map_flags,
0);
up_write(&current->mm->mmap_sem);
@@ -5523,7 +5647,7 @@ void kvm_vcpu_kick(struct kvm_vcpu *vcpu)
me = get_cpu();
if (cpu != me && (unsigned)cpu < nr_cpu_ids && cpu_online(cpu))
- if (!test_and_set_bit(KVM_REQ_KICK, &vcpu->requests))
+ if (atomic_xchg(&vcpu->guest_mode, 0))
smp_send_reschedule(cpu);
put_cpu();
}
diff --git a/arch/x86/kvm/x86.h b/arch/x86/kvm/x86.h
index f4b54458285..b7a404722d2 100644
--- a/arch/x86/kvm/x86.h
+++ b/arch/x86/kvm/x86.h
@@ -65,13 +65,6 @@ static inline int is_paging(struct kvm_vcpu *vcpu)
return kvm_read_cr0_bits(vcpu, X86_CR0_PG);
}
-static inline struct kvm_mem_aliases *kvm_aliases(struct kvm *kvm)
-{
- return rcu_dereference_check(kvm->arch.aliases,
- srcu_read_lock_held(&kvm->srcu)
- || lockdep_is_held(&kvm->slots_lock));
-}
-
void kvm_before_handle_nmi(struct kvm_vcpu *vcpu);
void kvm_after_handle_nmi(struct kvm_vcpu *vcpu);
diff --git a/arch/x86/lib/Makefile b/arch/x86/lib/Makefile
index f871e04b696..e10cf070ede 100644
--- a/arch/x86/lib/Makefile
+++ b/arch/x86/lib/Makefile
@@ -30,6 +30,7 @@ ifeq ($(CONFIG_X86_32),y)
lib-y += checksum_32.o
lib-y += strstr_32.o
lib-y += semaphore_32.o string_32.o
+ lib-y += cmpxchg.o
ifneq ($(CONFIG_X86_CMPXCHG64),y)
lib-y += cmpxchg8b_emu.o atomic64_386_32.o
endif
diff --git a/arch/x86/lib/clear_page_64.S b/arch/x86/lib/clear_page_64.S
index ebeafcce04a..aa4326bfb24 100644
--- a/arch/x86/lib/clear_page_64.S
+++ b/arch/x86/lib/clear_page_64.S
@@ -52,7 +52,7 @@ ENDPROC(clear_page)
.align 8
.quad clear_page
.quad 1b
- .byte X86_FEATURE_REP_GOOD
+ .word X86_FEATURE_REP_GOOD
.byte .Lclear_page_end - clear_page
.byte 2b - 1b
.previous
diff --git a/arch/x86/kernel/cpu/cmpxchg.c b/arch/x86/lib/cmpxchg.c
index 2056ccf572c..5d619f6df3e 100644
--- a/arch/x86/kernel/cpu/cmpxchg.c
+++ b/arch/x86/lib/cmpxchg.c
@@ -52,21 +52,3 @@ unsigned long cmpxchg_386_u32(volatile void *ptr, u32 old, u32 new)
}
EXPORT_SYMBOL(cmpxchg_386_u32);
#endif
-
-#ifndef CONFIG_X86_CMPXCHG64
-unsigned long long cmpxchg_486_u64(volatile void *ptr, u64 old, u64 new)
-{
- u64 prev;
- unsigned long flags;
-
- /* Poor man's cmpxchg8b for 386 and 486. Unsuitable for SMP */
- local_irq_save(flags);
- prev = *(u64 *)ptr;
- if (prev == old)
- *(u64 *)ptr = new;
- local_irq_restore(flags);
- return prev;
-}
-EXPORT_SYMBOL(cmpxchg_486_u64);
-#endif
-
diff --git a/arch/x86/lib/copy_page_64.S b/arch/x86/lib/copy_page_64.S
index 727a5d46d2f..6fec2d1cebe 100644
--- a/arch/x86/lib/copy_page_64.S
+++ b/arch/x86/lib/copy_page_64.S
@@ -113,7 +113,7 @@ ENDPROC(copy_page)
.align 8
.quad copy_page
.quad 1b
- .byte X86_FEATURE_REP_GOOD
+ .word X86_FEATURE_REP_GOOD
.byte .Lcopy_page_end - copy_page
.byte 2b - 1b
.previous
diff --git a/arch/x86/lib/copy_user_64.S b/arch/x86/lib/copy_user_64.S
index 71100c98e33..a460158b5ac 100644
--- a/arch/x86/lib/copy_user_64.S
+++ b/arch/x86/lib/copy_user_64.S
@@ -29,7 +29,7 @@
.align 8
.quad 0b
.quad 2b
- .byte \feature /* when feature is set */
+ .word \feature /* when feature is set */
.byte 5
.byte 5
.previous
diff --git a/arch/x86/lib/memcpy_64.S b/arch/x86/lib/memcpy_64.S
index f82e884928a..bcbcd1e0f7d 100644
--- a/arch/x86/lib/memcpy_64.S
+++ b/arch/x86/lib/memcpy_64.S
@@ -131,7 +131,7 @@ ENDPROC(__memcpy)
.align 8
.quad memcpy
.quad .Lmemcpy_c
- .byte X86_FEATURE_REP_GOOD
+ .word X86_FEATURE_REP_GOOD
/*
* Replace only beginning, memcpy is used to apply alternatives,
diff --git a/arch/x86/lib/memset_64.S b/arch/x86/lib/memset_64.S
index e88d3b81644..09d34426965 100644
--- a/arch/x86/lib/memset_64.S
+++ b/arch/x86/lib/memset_64.S
@@ -121,7 +121,7 @@ ENDPROC(__memset)
.align 8
.quad memset
.quad .Lmemset_c
- .byte X86_FEATURE_REP_GOOD
+ .word X86_FEATURE_REP_GOOD
.byte .Lfinal - memset
.byte .Lmemset_e - .Lmemset_c
.previous
diff --git a/arch/x86/mm/dump_pagetables.c b/arch/x86/mm/dump_pagetables.c
index a725b7f760a..0002a3a3308 100644
--- a/arch/x86/mm/dump_pagetables.c
+++ b/arch/x86/mm/dump_pagetables.c
@@ -37,6 +37,28 @@ struct addr_marker {
const char *name;
};
+/* indices for address_markers; keep sync'd w/ address_markers below */
+enum address_markers_idx {
+ USER_SPACE_NR = 0,
+#ifdef CONFIG_X86_64
+ KERNEL_SPACE_NR,
+ LOW_KERNEL_NR,
+ VMALLOC_START_NR,
+ VMEMMAP_START_NR,
+ HIGH_KERNEL_NR,
+ MODULES_VADDR_NR,
+ MODULES_END_NR,
+#else
+ KERNEL_SPACE_NR,
+ VMALLOC_START_NR,
+ VMALLOC_END_NR,
+# ifdef CONFIG_HIGHMEM
+ PKMAP_BASE_NR,
+# endif
+ FIXADDR_START_NR,
+#endif
+};
+
/* Address space markers hints */
static struct addr_marker address_markers[] = {
{ 0, "User Space" },
@@ -331,14 +353,12 @@ static int pt_dump_init(void)
#ifdef CONFIG_X86_32
/* Not a compile-time constant on x86-32 */
- address_markers[2].start_address = VMALLOC_START;
- address_markers[3].start_address = VMALLOC_END;
+ address_markers[VMALLOC_START_NR].start_address = VMALLOC_START;
+ address_markers[VMALLOC_END_NR].start_address = VMALLOC_END;
# ifdef CONFIG_HIGHMEM
- address_markers[4].start_address = PKMAP_BASE;
- address_markers[5].start_address = FIXADDR_START;
-# else
- address_markers[4].start_address = FIXADDR_START;
+ address_markers[PKMAP_BASE_NR].start_address = PKMAP_BASE;
# endif
+ address_markers[FIXADDR_START_NR].start_address = FIXADDR_START;
#endif
pe = debugfs_create_file("kernel_page_tables", 0600, NULL, NULL,
diff --git a/arch/x86/mm/init_64.c b/arch/x86/mm/init_64.c
index ee41bba315d..9a6674689a2 100644
--- a/arch/x86/mm/init_64.c
+++ b/arch/x86/mm/init_64.c
@@ -2,7 +2,7 @@
* linux/arch/x86_64/mm/init.c
*
* Copyright (C) 1995 Linus Torvalds
- * Copyright (C) 2000 Pavel Machek <pavel@suse.cz>
+ * Copyright (C) 2000 Pavel Machek <pavel@ucw.cz>
* Copyright (C) 2002,2003 Andi Kleen <ak@suse.de>
*/
diff --git a/arch/x86/mm/ioremap.c b/arch/x86/mm/ioremap.c
index 12e4d2d3c11..3ba6e0608c5 100644
--- a/arch/x86/mm/ioremap.c
+++ b/arch/x86/mm/ioremap.c
@@ -62,8 +62,8 @@ int ioremap_change_attr(unsigned long vaddr, unsigned long size,
static void __iomem *__ioremap_caller(resource_size_t phys_addr,
unsigned long size, unsigned long prot_val, void *caller)
{
- unsigned long pfn, offset, vaddr;
- resource_size_t last_addr;
+ unsigned long offset, vaddr;
+ resource_size_t pfn, last_pfn, last_addr;
const resource_size_t unaligned_phys_addr = phys_addr;
const unsigned long unaligned_size = size;
struct vm_struct *area;
@@ -100,10 +100,8 @@ static void __iomem *__ioremap_caller(resource_size_t phys_addr,
/*
* Don't allow anybody to remap normal RAM that we're using..
*/
- for (pfn = phys_addr >> PAGE_SHIFT;
- (pfn << PAGE_SHIFT) < (last_addr & PAGE_MASK);
- pfn++) {
-
+ last_pfn = last_addr >> PAGE_SHIFT;
+ for (pfn = phys_addr >> PAGE_SHIFT; pfn <= last_pfn; pfn++) {
int is_ram = page_is_ram(pfn);
if (is_ram && pfn_valid(pfn) && !PageReserved(pfn_to_page(pfn)))
@@ -115,7 +113,7 @@ static void __iomem *__ioremap_caller(resource_size_t phys_addr,
* Mappings have to be page-aligned
*/
offset = phys_addr & ~PAGE_MASK;
- phys_addr &= PAGE_MASK;
+ phys_addr &= PHYSICAL_PAGE_MASK;
size = PAGE_ALIGN(last_addr+1) - phys_addr;
retval = reserve_memtype(phys_addr, (u64)phys_addr + size,
@@ -613,7 +611,7 @@ void __init early_iounmap(void __iomem *addr, unsigned long size)
return;
}
offset = virt_addr & ~PAGE_MASK;
- nrpages = PAGE_ALIGN(offset + size - 1) >> PAGE_SHIFT;
+ nrpages = PAGE_ALIGN(offset + size) >> PAGE_SHIFT;
idx = FIX_BTMAP_BEGIN - NR_FIX_BTMAPS*slot;
while (nrpages > 0) {
diff --git a/arch/x86/mm/kmmio.c b/arch/x86/mm/kmmio.c
index 5d0e67fff1a..e5d5e2ce9f7 100644
--- a/arch/x86/mm/kmmio.c
+++ b/arch/x86/mm/kmmio.c
@@ -45,6 +45,8 @@ struct kmmio_fault_page {
* Protected by kmmio_lock, when linked into kmmio_page_table.
*/
int count;
+
+ bool scheduled_for_release;
};
struct kmmio_delayed_release {
@@ -398,8 +400,11 @@ static void release_kmmio_fault_page(unsigned long page,
BUG_ON(f->count < 0);
if (!f->count) {
disarm_kmmio_fault_page(f);
- f->release_next = *release_list;
- *release_list = f;
+ if (!f->scheduled_for_release) {
+ f->release_next = *release_list;
+ *release_list = f;
+ f->scheduled_for_release = true;
+ }
}
}
@@ -471,8 +476,10 @@ static void remove_kmmio_fault_pages(struct rcu_head *head)
prevp = &f->release_next;
} else {
*prevp = f->release_next;
+ f->release_next = NULL;
+ f->scheduled_for_release = false;
}
- f = f->release_next;
+ f = *prevp;
}
spin_unlock_irqrestore(&kmmio_lock, flags);
@@ -510,6 +517,9 @@ void unregister_kmmio_probe(struct kmmio_probe *p)
kmmio_count--;
spin_unlock_irqrestore(&kmmio_lock, flags);
+ if (!release_list)
+ return;
+
drelease = kmalloc(sizeof(*drelease), GFP_ATOMIC);
if (!drelease) {
pr_crit("leaking kmmio_fault_page objects.\n");
diff --git a/arch/x86/mm/pat.c b/arch/x86/mm/pat.c
index 64121a18b8c..f6ff57b7efa 100644
--- a/arch/x86/mm/pat.c
+++ b/arch/x86/mm/pat.c
@@ -158,7 +158,7 @@ static unsigned long pat_x_mtrr_type(u64 start, u64 end, unsigned long req_type)
return req_type;
}
-static int pat_pagerange_is_ram(unsigned long start, unsigned long end)
+static int pat_pagerange_is_ram(resource_size_t start, resource_size_t end)
{
int ram_page = 0, not_rampage = 0;
unsigned long page_nr;
diff --git a/arch/x86/mm/pf_in.c b/arch/x86/mm/pf_in.c
index 308e32570d8..38e6d174c49 100644
--- a/arch/x86/mm/pf_in.c
+++ b/arch/x86/mm/pf_in.c
@@ -40,16 +40,16 @@ static unsigned char prefix_codes[] = {
static unsigned int reg_rop[] = {
0x8A, 0x8B, 0xB60F, 0xB70F, 0xBE0F, 0xBF0F
};
-static unsigned int reg_wop[] = { 0x88, 0x89 };
+static unsigned int reg_wop[] = { 0x88, 0x89, 0xAA, 0xAB };
static unsigned int imm_wop[] = { 0xC6, 0xC7 };
/* IA32 Manual 3, 3-432*/
-static unsigned int rw8[] = { 0x88, 0x8A, 0xC6 };
+static unsigned int rw8[] = { 0x88, 0x8A, 0xC6, 0xAA };
static unsigned int rw32[] = {
- 0x89, 0x8B, 0xC7, 0xB60F, 0xB70F, 0xBE0F, 0xBF0F
+ 0x89, 0x8B, 0xC7, 0xB60F, 0xB70F, 0xBE0F, 0xBF0F, 0xAB
};
-static unsigned int mw8[] = { 0x88, 0x8A, 0xC6, 0xB60F, 0xBE0F };
+static unsigned int mw8[] = { 0x88, 0x8A, 0xC6, 0xB60F, 0xBE0F, 0xAA };
static unsigned int mw16[] = { 0xB70F, 0xBF0F };
-static unsigned int mw32[] = { 0x89, 0x8B, 0xC7 };
+static unsigned int mw32[] = { 0x89, 0x8B, 0xC7, 0xAB };
static unsigned int mw64[] = {};
#else /* not __i386__ */
static unsigned char prefix_codes[] = {
@@ -63,20 +63,20 @@ static unsigned char prefix_codes[] = {
static unsigned int reg_rop[] = {
0x8A, 0x8B, 0xB60F, 0xB70F, 0xBE0F, 0xBF0F
};
-static unsigned int reg_wop[] = { 0x88, 0x89 };
+static unsigned int reg_wop[] = { 0x88, 0x89, 0xAA, 0xAB };
static unsigned int imm_wop[] = { 0xC6, 0xC7 };
-static unsigned int rw8[] = { 0xC6, 0x88, 0x8A };
+static unsigned int rw8[] = { 0xC6, 0x88, 0x8A, 0xAA };
static unsigned int rw32[] = {
- 0xC7, 0x89, 0x8B, 0xB60F, 0xB70F, 0xBE0F, 0xBF0F
+ 0xC7, 0x89, 0x8B, 0xB60F, 0xB70F, 0xBE0F, 0xBF0F, 0xAB
};
/* 8 bit only */
-static unsigned int mw8[] = { 0xC6, 0x88, 0x8A, 0xB60F, 0xBE0F };
+static unsigned int mw8[] = { 0xC6, 0x88, 0x8A, 0xB60F, 0xBE0F, 0xAA };
/* 16 bit only */
static unsigned int mw16[] = { 0xB70F, 0xBF0F };
/* 16 or 32 bit */
static unsigned int mw32[] = { 0xC7 };
/* 16, 32 or 64 bit */
-static unsigned int mw64[] = { 0x89, 0x8B };
+static unsigned int mw64[] = { 0x89, 0x8B, 0xAB };
#endif /* not __i386__ */
struct prefix_bits {
@@ -410,7 +410,6 @@ static unsigned long *get_reg_w32(int no, struct pt_regs *regs)
unsigned long get_ins_reg_val(unsigned long ins_addr, struct pt_regs *regs)
{
unsigned int opcode;
- unsigned char mod_rm;
int reg;
unsigned char *p;
struct prefix_bits prf;
@@ -437,8 +436,13 @@ unsigned long get_ins_reg_val(unsigned long ins_addr, struct pt_regs *regs)
goto err;
do_work:
- mod_rm = *p;
- reg = ((mod_rm >> 3) & 0x7) | (prf.rexr << 3);
+ /* for STOS, source register is fixed */
+ if (opcode == 0xAA || opcode == 0xAB) {
+ reg = arg_AX;
+ } else {
+ unsigned char mod_rm = *p;
+ reg = ((mod_rm >> 3) & 0x7) | (prf.rexr << 3);
+ }
switch (get_ins_reg_width(ins_addr)) {
case 1:
return *get_reg_w8(reg, prf.rex, regs);
diff --git a/arch/x86/mm/testmmiotrace.c b/arch/x86/mm/testmmiotrace.c
index 8565d944f7c..38868adf07e 100644
--- a/arch/x86/mm/testmmiotrace.c
+++ b/arch/x86/mm/testmmiotrace.c
@@ -90,6 +90,27 @@ static void do_test(unsigned long size)
iounmap(p);
}
+/*
+ * Tests how mmiotrace behaves in face of multiple ioremap / iounmaps in
+ * a short time. We had a bug in deferred freeing procedure which tried
+ * to free this region multiple times (ioremap can reuse the same address
+ * for many mappings).
+ */
+static void do_test_bulk_ioremapping(void)
+{
+ void __iomem *p;
+ int i;
+
+ for (i = 0; i < 10; ++i) {
+ p = ioremap_nocache(mmio_address, PAGE_SIZE);
+ if (p)
+ iounmap(p);
+ }
+
+ /* Force freeing. If it will crash we will know why. */
+ synchronize_rcu();
+}
+
static int __init init(void)
{
unsigned long size = (read_far) ? (8 << 20) : (16 << 10);
@@ -104,6 +125,7 @@ static int __init init(void)
"and writing 16 kB of rubbish in there.\n",
size >> 10, mmio_address);
do_test(size);
+ do_test_bulk_ioremapping();
pr_info("All done.\n");
return 0;
}
diff --git a/arch/x86/mm/tlb.c b/arch/x86/mm/tlb.c
index 426f3a1a64d..c03f14ab666 100644
--- a/arch/x86/mm/tlb.c
+++ b/arch/x86/mm/tlb.c
@@ -278,11 +278,9 @@ void flush_tlb_page(struct vm_area_struct *vma, unsigned long va)
static void do_flush_tlb_all(void *info)
{
- unsigned long cpu = smp_processor_id();
-
__flush_tlb_all();
if (percpu_read(cpu_tlbstate.state) == TLBSTATE_LAZY)
- leave_mm(cpu);
+ leave_mm(smp_processor_id());
}
void flush_tlb_all(void)
diff --git a/arch/x86/oprofile/nmi_int.c b/arch/x86/oprofile/nmi_int.c
index b28d2f1253b..1ba67dc8006 100644
--- a/arch/x86/oprofile/nmi_int.c
+++ b/arch/x86/oprofile/nmi_int.c
@@ -634,6 +634,18 @@ static int __init ppro_init(char **cpu_type)
if (force_arch_perfmon && cpu_has_arch_perfmon)
return 0;
+ /*
+ * Documentation on identifying Intel processors by CPU family
+ * and model can be found in the Intel Software Developer's
+ * Manuals (SDM):
+ *
+ * http://www.intel.com/products/processor/manuals/
+ *
+ * As of May 2010 the documentation for this was in the:
+ * "Intel 64 and IA-32 Architectures Software Developer's
+ * Manual Volume 3B: System Programming Guide", "Table B-1
+ * CPUID Signature Values of DisplayFamily_DisplayModel".
+ */
switch (cpu_model) {
case 0 ... 2:
*cpu_type = "i386/ppro";
@@ -655,12 +667,12 @@ static int __init ppro_init(char **cpu_type)
case 15: case 23:
*cpu_type = "i386/core_2";
break;
+ case 0x1a:
case 0x2e:
- case 26:
spec = &op_arch_perfmon_spec;
*cpu_type = "i386/core_i7";
break;
- case 28:
+ case 0x1c:
*cpu_type = "i386/atom";
break;
default:
diff --git a/arch/x86/pci/acpi.c b/arch/x86/pci/acpi.c
index 2ec04c424a6..15466c096ba 100644
--- a/arch/x86/pci/acpi.c
+++ b/arch/x86/pci/acpi.c
@@ -34,6 +34,15 @@ static const struct dmi_system_id pci_use_crs_table[] __initconst = {
DMI_MATCH(DMI_PRODUCT_NAME, "x3800"),
},
},
+ /* https://bugzilla.kernel.org/show_bug.cgi?id=16007 */
+ /* 2006 AMD HT/VIA system with two host bridges */
+ {
+ .callback = set_use_crs,
+ .ident = "ASRock ALiveSATA2-GLAN",
+ .matches = {
+ DMI_MATCH(DMI_PRODUCT_NAME, "ALiveSATA2-GLAN"),
+ },
+ },
{}
};
diff --git a/arch/x86/pci/common.c b/arch/x86/pci/common.c
index 215a27ae050..a0772af64ef 100644
--- a/arch/x86/pci/common.c
+++ b/arch/x86/pci/common.c
@@ -125,6 +125,23 @@ void __init dmi_check_skip_isa_align(void)
static void __devinit pcibios_fixup_device_resources(struct pci_dev *dev)
{
struct resource *rom_r = &dev->resource[PCI_ROM_RESOURCE];
+ struct resource *bar_r;
+ int bar;
+
+ if (pci_probe & PCI_NOASSIGN_BARS) {
+ /*
+ * If the BIOS did not assign the BAR, zero out the
+ * resource so the kernel doesn't attmept to assign
+ * it later on in pci_assign_unassigned_resources
+ */
+ for (bar = 0; bar <= PCI_STD_RESOURCE_END; bar++) {
+ bar_r = &dev->resource[bar];
+ if (bar_r->start == 0 && bar_r->end != 0) {
+ bar_r->flags = 0;
+ bar_r->end = 0;
+ }
+ }
+ }
if (pci_probe & PCI_NOASSIGN_ROMS) {
if (rom_r->parent)
@@ -509,6 +526,9 @@ char * __devinit pcibios_setup(char *str)
} else if (!strcmp(str, "norom")) {
pci_probe |= PCI_NOASSIGN_ROMS;
return NULL;
+ } else if (!strcmp(str, "nobar")) {
+ pci_probe |= PCI_NOASSIGN_BARS;
+ return NULL;
} else if (!strcmp(str, "assign-busses")) {
pci_probe |= PCI_ASSIGN_ALL_BUSSES;
return NULL;
diff --git a/arch/x86/pci/irq.c b/arch/x86/pci/irq.c
index 9810a0f76c9..f547ee05f71 100644
--- a/arch/x86/pci/irq.c
+++ b/arch/x86/pci/irq.c
@@ -989,7 +989,7 @@ static int pcibios_lookup_irq(struct pci_dev *dev, int assign)
dev_info(&dev->dev, "%s PCI INT %c -> IRQ %d\n", msg, 'A' + pin - 1, irq);
/* Update IRQ for all devices with the same pirq value */
- while ((dev2 = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev2)) != NULL) {
+ for_each_pci_dev(dev2) {
pci_read_config_byte(dev2, PCI_INTERRUPT_PIN, &pin);
if (!pin)
continue;
@@ -1028,7 +1028,7 @@ void __init pcibios_fixup_irqs(void)
u8 pin;
DBG(KERN_DEBUG "PCI: IRQ fixup\n");
- while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {
+ for_each_pci_dev(dev) {
/*
* If the BIOS has set an out of range IRQ number, just
* ignore it. Also keep track of which IRQ's are
@@ -1052,7 +1052,7 @@ void __init pcibios_fixup_irqs(void)
return;
dev = NULL;
- while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {
+ for_each_pci_dev(dev) {
pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
if (!pin)
continue;
diff --git a/arch/x86/pci/legacy.c b/arch/x86/pci/legacy.c
index 8d460eaf524..c89266be604 100644
--- a/arch/x86/pci/legacy.c
+++ b/arch/x86/pci/legacy.c
@@ -36,7 +36,7 @@ int __init pci_legacy_init(void)
return 0;
}
-void pcibios_scan_specific_bus(int busn)
+void __devinit pcibios_scan_specific_bus(int busn)
{
int devfn;
long node;
diff --git a/arch/x86/power/cpu.c b/arch/x86/power/cpu.c
index 1290ba54b35..e7e8c5f5495 100644
--- a/arch/x86/power/cpu.c
+++ b/arch/x86/power/cpu.c
@@ -4,7 +4,7 @@
* Distribute under GPLv2
*
* Copyright (c) 2007 Rafael J. Wysocki <rjw@sisk.pl>
- * Copyright (c) 2002 Pavel Machek <pavel@suse.cz>
+ * Copyright (c) 2002 Pavel Machek <pavel@ucw.cz>
* Copyright (c) 2001 Patrick Mochel <mochel@osdl.org>
*/
diff --git a/arch/x86/power/hibernate_64.c b/arch/x86/power/hibernate_64.c
index d24f983ba1e..460f314d13e 100644
--- a/arch/x86/power/hibernate_64.c
+++ b/arch/x86/power/hibernate_64.c
@@ -4,7 +4,7 @@
* Distribute under GPLv2
*
* Copyright (c) 2007 Rafael J. Wysocki <rjw@sisk.pl>
- * Copyright (c) 2002 Pavel Machek <pavel@suse.cz>
+ * Copyright (c) 2002 Pavel Machek <pavel@ucw.cz>
* Copyright (c) 2001 Patrick Mochel <mochel@osdl.org>
*/
diff --git a/arch/x86/vdso/Makefile b/arch/x86/vdso/Makefile
index 6b4ffedb93c..4a2afa1bac5 100644
--- a/arch/x86/vdso/Makefile
+++ b/arch/x86/vdso/Makefile
@@ -120,7 +120,8 @@ $(obj)/vdso32-syms.lds: $(vdso32.so-y:%=$(obj)/vdso32-%-syms.lds) FORCE
quiet_cmd_vdso = VDSO $@
cmd_vdso = $(CC) -nostdlib -o $@ \
$(VDSO_LDFLAGS) $(VDSO_LDFLAGS_$(filter %.lds,$(^F))) \
- -Wl,-T,$(filter %.lds,$^) $(filter %.o,$^)
+ -Wl,-T,$(filter %.lds,$^) $(filter %.o,$^) && \
+ sh $(srctree)/$(src)/checkundef.sh '$(NM)' '$@'
VDSO_LDFLAGS = -fPIC -shared $(call cc-ldoption, -Wl$(comma)--hash-style=sysv)
GCOV_PROFILE := n
diff --git a/arch/x86/vdso/checkundef.sh b/arch/x86/vdso/checkundef.sh
new file mode 100755
index 00000000000..7ee90a9b549
--- /dev/null
+++ b/arch/x86/vdso/checkundef.sh
@@ -0,0 +1,10 @@
+#!/bin/sh
+nm="$1"
+file="$2"
+$nm "$file" | grep '^ *U' > /dev/null 2>&1
+if [ $? -eq 1 ]; then
+ exit 0
+else
+ echo "$file: undefined symbols found" >&2
+ exit 1
+fi
diff --git a/arch/x86/vdso/vdso32-setup.c b/arch/x86/vdso/vdso32-setup.c
index 02b442e9200..36df991985b 100644
--- a/arch/x86/vdso/vdso32-setup.c
+++ b/arch/x86/vdso/vdso32-setup.c
@@ -374,7 +374,7 @@ int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp)
#ifdef CONFIG_X86_64
-__initcall(sysenter_setup);
+subsys_initcall(sysenter_setup);
#ifdef CONFIG_SYSCTL
/* Register vsyscall32 into the ABI table */
diff --git a/arch/x86/vdso/vma.c b/arch/x86/vdso/vma.c
index ac74869b814..4b5d26f108b 100644
--- a/arch/x86/vdso/vma.c
+++ b/arch/x86/vdso/vma.c
@@ -67,6 +67,7 @@ static int __init init_vdso_vars(void)
*(typeof(__ ## x) **) var_ref(VDSO64_SYMBOL(vbase, x), #x) = &__ ## x;
#include "vextern.h"
#undef VEXTERN
+ vunmap(vbase);
return 0;
oom:
@@ -74,7 +75,7 @@ static int __init init_vdso_vars(void)
vdso_enabled = 0;
return -ENOMEM;
}
-__initcall(init_vdso_vars);
+subsys_initcall(init_vdso_vars);
struct linux_binprm;
diff --git a/arch/x86/xen/Kconfig b/arch/x86/xen/Kconfig
index b83e119fbeb..68128a1b401 100644
--- a/arch/x86/xen/Kconfig
+++ b/arch/x86/xen/Kconfig
@@ -13,6 +13,11 @@ config XEN
kernel to boot in a paravirtualized environment under the
Xen hypervisor.
+config XEN_PVHVM
+ def_bool y
+ depends on XEN
+ depends on X86_LOCAL_APIC
+
config XEN_MAX_DOMAIN_MEMORY
int "Maximum allowed size of a domain in gigabytes"
default 8 if X86_32
diff --git a/arch/x86/xen/Makefile b/arch/x86/xen/Makefile
index 3bb4fc21f4f..93095468598 100644
--- a/arch/x86/xen/Makefile
+++ b/arch/x86/xen/Makefile
@@ -12,7 +12,7 @@ CFLAGS_mmu.o := $(nostackp)
obj-y := enlighten.o setup.o multicalls.o mmu.o irq.o \
time.o xen-asm.o xen-asm_$(BITS).o \
- grant-table.o suspend.o
+ grant-table.o suspend.o platform-pci-unplug.o
obj-$(CONFIG_SMP) += smp.o
obj-$(CONFIG_PARAVIRT_SPINLOCKS)+= spinlock.o
diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c
index 65d8d79b46a..d4ff5e83621 100644
--- a/arch/x86/xen/enlighten.c
+++ b/arch/x86/xen/enlighten.c
@@ -11,6 +11,7 @@
* Jeremy Fitzhardinge <jeremy@xensource.com>, XenSource Inc, 2007
*/
+#include <linux/cpu.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/smp.h>
@@ -35,8 +36,10 @@
#include <xen/interface/version.h>
#include <xen/interface/physdev.h>
#include <xen/interface/vcpu.h>
+#include <xen/interface/memory.h>
#include <xen/features.h>
#include <xen/page.h>
+#include <xen/hvm.h>
#include <xen/hvc-console.h>
#include <asm/paravirt.h>
@@ -55,7 +58,9 @@
#include <asm/pgtable.h>
#include <asm/tlbflush.h>
#include <asm/reboot.h>
+#include <asm/setup.h>
#include <asm/stackprotector.h>
+#include <asm/hypervisor.h>
#include "xen-ops.h"
#include "mmu.h"
@@ -76,6 +81,10 @@ struct shared_info xen_dummy_shared_info;
void *xen_initial_gdt;
+RESERVE_BRK(shared_info_page_brk, PAGE_SIZE);
+__read_mostly int xen_have_vector_callback;
+EXPORT_SYMBOL_GPL(xen_have_vector_callback);
+
/*
* Point at some empty memory to start with. We map the real shared_info
* page as soon as fixmap is up and running.
@@ -97,6 +106,14 @@ struct shared_info *HYPERVISOR_shared_info = (void *)&xen_dummy_shared_info;
*/
static int have_vcpu_info_placement = 1;
+static void clamp_max_cpus(void)
+{
+#ifdef CONFIG_SMP
+ if (setup_max_cpus > MAX_VIRT_CPUS)
+ setup_max_cpus = MAX_VIRT_CPUS;
+#endif
+}
+
static void xen_vcpu_setup(int cpu)
{
struct vcpu_register_vcpu_info info;
@@ -104,13 +121,17 @@ static void xen_vcpu_setup(int cpu)
struct vcpu_info *vcpup;
BUG_ON(HYPERVISOR_shared_info == &xen_dummy_shared_info);
- per_cpu(xen_vcpu, cpu) = &HYPERVISOR_shared_info->vcpu_info[cpu];
- if (!have_vcpu_info_placement)
- return; /* already tested, not available */
+ if (cpu < MAX_VIRT_CPUS)
+ per_cpu(xen_vcpu,cpu) = &HYPERVISOR_shared_info->vcpu_info[cpu];
- vcpup = &per_cpu(xen_vcpu_info, cpu);
+ if (!have_vcpu_info_placement) {
+ if (cpu >= MAX_VIRT_CPUS)
+ clamp_max_cpus();
+ return;
+ }
+ vcpup = &per_cpu(xen_vcpu_info, cpu);
info.mfn = arbitrary_virt_to_mfn(vcpup);
info.offset = offset_in_page(vcpup);
@@ -125,6 +146,7 @@ static void xen_vcpu_setup(int cpu)
if (err) {
printk(KERN_DEBUG "register_vcpu_info failed: err=%d\n", err);
have_vcpu_info_placement = 0;
+ clamp_max_cpus();
} else {
/* This cpu is using the registered vcpu info, even if
later ones fail to. */
@@ -731,7 +753,6 @@ static void set_xen_basic_apic_ops(void)
#endif
-
static void xen_clts(void)
{
struct multicall_space mcs;
@@ -926,10 +947,6 @@ static const struct pv_init_ops xen_init_ops __initdata = {
.patch = xen_patch,
};
-static const struct pv_time_ops xen_time_ops __initdata = {
- .sched_clock = xen_sched_clock,
-};
-
static const struct pv_cpu_ops xen_cpu_ops __initdata = {
.cpuid = xen_cpuid,
@@ -1028,6 +1045,23 @@ static void xen_crash_shutdown(struct pt_regs *regs)
xen_reboot(SHUTDOWN_crash);
}
+static int
+xen_panic_event(struct notifier_block *this, unsigned long event, void *ptr)
+{
+ xen_reboot(SHUTDOWN_crash);
+ return NOTIFY_DONE;
+}
+
+static struct notifier_block xen_panic_block = {
+ .notifier_call= xen_panic_event,
+};
+
+int xen_panic_handler_init(void)
+{
+ atomic_notifier_chain_register(&panic_notifier_list, &xen_panic_block);
+ return 0;
+}
+
static const struct machine_ops __initdata xen_machine_ops = {
.restart = xen_restart,
.halt = xen_machine_halt,
@@ -1067,7 +1101,6 @@ asmlinkage void __init xen_start_kernel(void)
/* Install Xen paravirt ops */
pv_info = xen_info;
pv_init_ops = xen_init_ops;
- pv_time_ops = xen_time_ops;
pv_cpu_ops = xen_cpu_ops;
pv_apic_ops = xen_apic_ops;
@@ -1075,13 +1108,7 @@ asmlinkage void __init xen_start_kernel(void)
x86_init.oem.arch_setup = xen_arch_setup;
x86_init.oem.banner = xen_banner;
- x86_init.timers.timer_init = xen_time_init;
- x86_init.timers.setup_percpu_clockev = x86_init_noop;
- x86_cpuinit.setup_percpu_clockev = x86_init_noop;
-
- x86_platform.calibrate_tsc = xen_tsc_khz;
- x86_platform.get_wallclock = xen_get_wallclock;
- x86_platform.set_wallclock = xen_set_wallclock;
+ xen_init_time_ops();
/*
* Set up some pagetable state before starting to set any ptes.
@@ -1206,3 +1233,139 @@ asmlinkage void __init xen_start_kernel(void)
x86_64_start_reservations((char *)__pa_symbol(&boot_params));
#endif
}
+
+static uint32_t xen_cpuid_base(void)
+{
+ uint32_t base, eax, ebx, ecx, edx;
+ char signature[13];
+
+ for (base = 0x40000000; base < 0x40010000; base += 0x100) {
+ cpuid(base, &eax, &ebx, &ecx, &edx);
+ *(uint32_t *)(signature + 0) = ebx;
+ *(uint32_t *)(signature + 4) = ecx;
+ *(uint32_t *)(signature + 8) = edx;
+ signature[12] = 0;
+
+ if (!strcmp("XenVMMXenVMM", signature) && ((eax - base) >= 2))
+ return base;
+ }
+
+ return 0;
+}
+
+static int init_hvm_pv_info(int *major, int *minor)
+{
+ uint32_t eax, ebx, ecx, edx, pages, msr, base;
+ u64 pfn;
+
+ base = xen_cpuid_base();
+ cpuid(base + 1, &eax, &ebx, &ecx, &edx);
+
+ *major = eax >> 16;
+ *minor = eax & 0xffff;
+ printk(KERN_INFO "Xen version %d.%d.\n", *major, *minor);
+
+ cpuid(base + 2, &pages, &msr, &ecx, &edx);
+
+ pfn = __pa(hypercall_page);
+ wrmsr_safe(msr, (u32)pfn, (u32)(pfn >> 32));
+
+ xen_setup_features();
+
+ pv_info = xen_info;
+ pv_info.kernel_rpl = 0;
+
+ xen_domain_type = XEN_HVM_DOMAIN;
+
+ return 0;
+}
+
+void xen_hvm_init_shared_info(void)
+{
+ int cpu;
+ struct xen_add_to_physmap xatp;
+ static struct shared_info *shared_info_page = 0;
+
+ if (!shared_info_page)
+ shared_info_page = (struct shared_info *)
+ extend_brk(PAGE_SIZE, PAGE_SIZE);
+ xatp.domid = DOMID_SELF;
+ xatp.idx = 0;
+ xatp.space = XENMAPSPACE_shared_info;
+ xatp.gpfn = __pa(shared_info_page) >> PAGE_SHIFT;
+ if (HYPERVISOR_memory_op(XENMEM_add_to_physmap, &xatp))
+ BUG();
+
+ HYPERVISOR_shared_info = (struct shared_info *)shared_info_page;
+
+ /* xen_vcpu is a pointer to the vcpu_info struct in the shared_info
+ * page, we use it in the event channel upcall and in some pvclock
+ * related functions. We don't need the vcpu_info placement
+ * optimizations because we don't use any pv_mmu or pv_irq op on
+ * HVM.
+ * When xen_hvm_init_shared_info is run at boot time only vcpu 0 is
+ * online but xen_hvm_init_shared_info is run at resume time too and
+ * in that case multiple vcpus might be online. */
+ for_each_online_cpu(cpu) {
+ per_cpu(xen_vcpu, cpu) = &HYPERVISOR_shared_info->vcpu_info[cpu];
+ }
+}
+
+#ifdef CONFIG_XEN_PVHVM
+static int __cpuinit xen_hvm_cpu_notify(struct notifier_block *self,
+ unsigned long action, void *hcpu)
+{
+ int cpu = (long)hcpu;
+ switch (action) {
+ case CPU_UP_PREPARE:
+ per_cpu(xen_vcpu, cpu) = &HYPERVISOR_shared_info->vcpu_info[cpu];
+ break;
+ default:
+ break;
+ }
+ return NOTIFY_OK;
+}
+
+static struct notifier_block __cpuinitdata xen_hvm_cpu_notifier = {
+ .notifier_call = xen_hvm_cpu_notify,
+};
+
+static void __init xen_hvm_guest_init(void)
+{
+ int r;
+ int major, minor;
+
+ r = init_hvm_pv_info(&major, &minor);
+ if (r < 0)
+ return;
+
+ xen_hvm_init_shared_info();
+
+ if (xen_feature(XENFEAT_hvm_callback_vector))
+ xen_have_vector_callback = 1;
+ register_cpu_notifier(&xen_hvm_cpu_notifier);
+ xen_unplug_emulated_devices();
+ have_vcpu_info_placement = 0;
+ x86_init.irqs.intr_init = xen_init_IRQ;
+ xen_hvm_init_time_ops();
+ xen_hvm_init_mmu_ops();
+}
+
+static bool __init xen_hvm_platform(void)
+{
+ if (xen_pv_domain())
+ return false;
+
+ if (!xen_cpuid_base())
+ return false;
+
+ return true;
+}
+
+const __refconst struct hypervisor_x86 x86_hyper_xen_hvm = {
+ .name = "Xen HVM",
+ .detect = xen_hvm_platform,
+ .init_platform = xen_hvm_guest_init,
+};
+EXPORT_SYMBOL(x86_hyper_xen_hvm);
+#endif
diff --git a/arch/x86/xen/mmu.c b/arch/x86/xen/mmu.c
index 914f04695ce..413b19b3d0f 100644
--- a/arch/x86/xen/mmu.c
+++ b/arch/x86/xen/mmu.c
@@ -58,6 +58,7 @@
#include <xen/page.h>
#include <xen/interface/xen.h>
+#include <xen/interface/hvm/hvm_op.h>
#include <xen/interface/version.h>
#include <xen/hvc-console.h>
@@ -1941,6 +1942,40 @@ void __init xen_init_mmu_ops(void)
pv_mmu_ops = xen_mmu_ops;
}
+#ifdef CONFIG_XEN_PVHVM
+static void xen_hvm_exit_mmap(struct mm_struct *mm)
+{
+ struct xen_hvm_pagetable_dying a;
+ int rc;
+
+ a.domid = DOMID_SELF;
+ a.gpa = __pa(mm->pgd);
+ rc = HYPERVISOR_hvm_op(HVMOP_pagetable_dying, &a);
+ WARN_ON_ONCE(rc < 0);
+}
+
+static int is_pagetable_dying_supported(void)
+{
+ struct xen_hvm_pagetable_dying a;
+ int rc = 0;
+
+ a.domid = DOMID_SELF;
+ a.gpa = 0x00;
+ rc = HYPERVISOR_hvm_op(HVMOP_pagetable_dying, &a);
+ if (rc < 0) {
+ printk(KERN_DEBUG "HVMOP_pagetable_dying not supported\n");
+ return 0;
+ }
+ return 1;
+}
+
+void __init xen_hvm_init_mmu_ops(void)
+{
+ if (is_pagetable_dying_supported())
+ pv_mmu_ops.exit_mmap = xen_hvm_exit_mmap;
+}
+#endif
+
#ifdef CONFIG_XEN_DEBUG_FS
static struct dentry *d_mmu_debug;
diff --git a/arch/x86/xen/mmu.h b/arch/x86/xen/mmu.h
index 5fe6bc7f5ec..fa938c4aa2f 100644
--- a/arch/x86/xen/mmu.h
+++ b/arch/x86/xen/mmu.h
@@ -60,4 +60,5 @@ void xen_ptep_modify_prot_commit(struct mm_struct *mm, unsigned long addr,
unsigned long xen_read_cr2_direct(void);
extern void xen_init_mmu_ops(void);
+extern void xen_hvm_init_mmu_ops(void);
#endif /* _XEN_MMU_H */
diff --git a/arch/x86/xen/platform-pci-unplug.c b/arch/x86/xen/platform-pci-unplug.c
new file mode 100644
index 00000000000..554c002a1e1
--- /dev/null
+++ b/arch/x86/xen/platform-pci-unplug.c
@@ -0,0 +1,137 @@
+/******************************************************************************
+ * platform-pci-unplug.c
+ *
+ * Xen platform PCI device driver
+ * Copyright (c) 2010, Citrix
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place - Suite 330, Boston, MA 02111-1307 USA.
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/module.h>
+
+#include <xen/platform_pci.h>
+
+#define XEN_PLATFORM_ERR_MAGIC -1
+#define XEN_PLATFORM_ERR_PROTOCOL -2
+#define XEN_PLATFORM_ERR_BLACKLIST -3
+
+/* store the value of xen_emul_unplug after the unplug is done */
+int xen_platform_pci_unplug;
+EXPORT_SYMBOL_GPL(xen_platform_pci_unplug);
+#ifdef CONFIG_XEN_PVHVM
+static int xen_emul_unplug;
+
+static int __init check_platform_magic(void)
+{
+ short magic;
+ char protocol;
+
+ magic = inw(XEN_IOPORT_MAGIC);
+ if (magic != XEN_IOPORT_MAGIC_VAL) {
+ printk(KERN_ERR "Xen Platform PCI: unrecognised magic value\n");
+ return XEN_PLATFORM_ERR_MAGIC;
+ }
+
+ protocol = inb(XEN_IOPORT_PROTOVER);
+
+ printk(KERN_DEBUG "Xen Platform PCI: I/O protocol version %d\n",
+ protocol);
+
+ switch (protocol) {
+ case 1:
+ outw(XEN_IOPORT_LINUX_PRODNUM, XEN_IOPORT_PRODNUM);
+ outl(XEN_IOPORT_LINUX_DRVVER, XEN_IOPORT_DRVVER);
+ if (inw(XEN_IOPORT_MAGIC) != XEN_IOPORT_MAGIC_VAL) {
+ printk(KERN_ERR "Xen Platform: blacklisted by host\n");
+ return XEN_PLATFORM_ERR_BLACKLIST;
+ }
+ break;
+ default:
+ printk(KERN_WARNING "Xen Platform PCI: unknown I/O protocol version");
+ return XEN_PLATFORM_ERR_PROTOCOL;
+ }
+
+ return 0;
+}
+
+void __init xen_unplug_emulated_devices(void)
+{
+ int r;
+
+ /* check the version of the xen platform PCI device */
+ r = check_platform_magic();
+ /* If the version matches enable the Xen platform PCI driver.
+ * Also enable the Xen platform PCI driver if the version is really old
+ * and the user told us to ignore it. */
+ if (r && !(r == XEN_PLATFORM_ERR_MAGIC &&
+ (xen_emul_unplug & XEN_UNPLUG_IGNORE)))
+ return;
+ /* Set the default value of xen_emul_unplug depending on whether or
+ * not the Xen PV frontends and the Xen platform PCI driver have
+ * been compiled for this kernel (modules or built-in are both OK). */
+ if (!xen_emul_unplug) {
+ if (xen_must_unplug_nics()) {
+ printk(KERN_INFO "Netfront and the Xen platform PCI driver have "
+ "been compiled for this kernel: unplug emulated NICs.\n");
+ xen_emul_unplug |= XEN_UNPLUG_ALL_NICS;
+ }
+ if (xen_must_unplug_disks()) {
+ printk(KERN_INFO "Blkfront and the Xen platform PCI driver have "
+ "been compiled for this kernel: unplug emulated disks.\n"
+ "You might have to change the root device\n"
+ "from /dev/hd[a-d] to /dev/xvd[a-d]\n"
+ "in your root= kernel command line option\n");
+ xen_emul_unplug |= XEN_UNPLUG_ALL_IDE_DISKS;
+ }
+ }
+ /* Now unplug the emulated devices */
+ if (!(xen_emul_unplug & XEN_UNPLUG_IGNORE))
+ outw(xen_emul_unplug, XEN_IOPORT_UNPLUG);
+ xen_platform_pci_unplug = xen_emul_unplug;
+}
+
+static int __init parse_xen_emul_unplug(char *arg)
+{
+ char *p, *q;
+ int l;
+
+ for (p = arg; p; p = q) {
+ q = strchr(p, ',');
+ if (q) {
+ l = q - p;
+ q++;
+ } else {
+ l = strlen(p);
+ }
+ if (!strncmp(p, "all", l))
+ xen_emul_unplug |= XEN_UNPLUG_ALL;
+ else if (!strncmp(p, "ide-disks", l))
+ xen_emul_unplug |= XEN_UNPLUG_ALL_IDE_DISKS;
+ else if (!strncmp(p, "aux-ide-disks", l))
+ xen_emul_unplug |= XEN_UNPLUG_AUX_IDE_DISKS;
+ else if (!strncmp(p, "nics", l))
+ xen_emul_unplug |= XEN_UNPLUG_ALL_NICS;
+ else if (!strncmp(p, "ignore", l))
+ xen_emul_unplug |= XEN_UNPLUG_IGNORE;
+ else
+ printk(KERN_WARNING "unrecognised option '%s' "
+ "in parameter 'xen_emul_unplug'\n", p);
+ }
+ return 0;
+}
+early_param("xen_emul_unplug", parse_xen_emul_unplug);
+#endif
diff --git a/arch/x86/xen/setup.c b/arch/x86/xen/setup.c
index ad0047f47cd..328b0030542 100644
--- a/arch/x86/xen/setup.c
+++ b/arch/x86/xen/setup.c
@@ -20,6 +20,7 @@
#include <xen/page.h>
#include <xen/interface/callback.h>
#include <xen/interface/physdev.h>
+#include <xen/interface/memory.h>
#include <xen/features.h>
#include "xen-ops.h"
@@ -32,6 +33,73 @@ extern void xen_sysenter_target(void);
extern void xen_syscall_target(void);
extern void xen_syscall32_target(void);
+static unsigned long __init xen_release_chunk(phys_addr_t start_addr,
+ phys_addr_t end_addr)
+{
+ struct xen_memory_reservation reservation = {
+ .address_bits = 0,
+ .extent_order = 0,
+ .domid = DOMID_SELF
+ };
+ unsigned long start, end;
+ unsigned long len = 0;
+ unsigned long pfn;
+ int ret;
+
+ start = PFN_UP(start_addr);
+ end = PFN_DOWN(end_addr);
+
+ if (end <= start)
+ return 0;
+
+ printk(KERN_INFO "xen_release_chunk: looking at area pfn %lx-%lx: ",
+ start, end);
+ for(pfn = start; pfn < end; pfn++) {
+ unsigned long mfn = pfn_to_mfn(pfn);
+
+ /* Make sure pfn exists to start with */
+ if (mfn == INVALID_P2M_ENTRY || mfn_to_pfn(mfn) != pfn)
+ continue;
+
+ set_xen_guest_handle(reservation.extent_start, &mfn);
+ reservation.nr_extents = 1;
+
+ ret = HYPERVISOR_memory_op(XENMEM_decrease_reservation,
+ &reservation);
+ WARN(ret != 1, "Failed to release memory %lx-%lx err=%d\n",
+ start, end, ret);
+ if (ret == 1) {
+ set_phys_to_machine(pfn, INVALID_P2M_ENTRY);
+ len++;
+ }
+ }
+ printk(KERN_CONT "%ld pages freed\n", len);
+
+ return len;
+}
+
+static unsigned long __init xen_return_unused_memory(unsigned long max_pfn,
+ const struct e820map *e820)
+{
+ phys_addr_t max_addr = PFN_PHYS(max_pfn);
+ phys_addr_t last_end = 0;
+ unsigned long released = 0;
+ int i;
+
+ for (i = 0; i < e820->nr_map && last_end < max_addr; i++) {
+ phys_addr_t end = e820->map[i].addr;
+ end = min(max_addr, end);
+
+ released += xen_release_chunk(last_end, end);
+ last_end = e820->map[i].addr + e820->map[i].size;
+ }
+
+ if (last_end < max_addr)
+ released += xen_release_chunk(last_end, max_addr);
+
+ printk(KERN_INFO "released %ld pages of unused memory\n", released);
+ return released;
+}
/**
* machine_specific_memory_setup - Hook for machine specific memory setup.
@@ -67,6 +135,8 @@ char * __init xen_memory_setup(void)
sanitize_e820_map(e820.map, ARRAY_SIZE(e820.map), &e820.nr_map);
+ xen_return_unused_memory(xen_start_info->nr_pages, &e820);
+
return "Xen";
}
@@ -156,6 +226,8 @@ void __init xen_arch_setup(void)
struct physdev_set_iopl set_iopl;
int rc;
+ xen_panic_handler_init();
+
HYPERVISOR_vm_assist(VMASST_CMD_enable, VMASST_TYPE_4gb_segments);
HYPERVISOR_vm_assist(VMASST_CMD_enable, VMASST_TYPE_writable_pagetables);
diff --git a/arch/x86/xen/smp.c b/arch/x86/xen/smp.c
index a29693fd313..25f232b18a8 100644
--- a/arch/x86/xen/smp.c
+++ b/arch/x86/xen/smp.c
@@ -394,6 +394,8 @@ static void stop_self(void *v)
load_cr3(swapper_pg_dir);
/* should set up a minimal gdt */
+ set_cpu_online(cpu, false);
+
HYPERVISOR_vcpu_op(VCPUOP_down, cpu, NULL);
BUG();
}
diff --git a/arch/x86/xen/suspend.c b/arch/x86/xen/suspend.c
index a9c66110803..1d789d56877 100644
--- a/arch/x86/xen/suspend.c
+++ b/arch/x86/xen/suspend.c
@@ -26,6 +26,18 @@ void xen_pre_suspend(void)
BUG();
}
+void xen_hvm_post_suspend(int suspend_cancelled)
+{
+ int cpu;
+ xen_hvm_init_shared_info();
+ xen_callback_vector();
+ if (xen_feature(XENFEAT_hvm_safe_pvclock)) {
+ for_each_online_cpu(cpu) {
+ xen_setup_runstate_info(cpu);
+ }
+ }
+}
+
void xen_post_suspend(int suspend_cancelled)
{
xen_build_mfn_list_list();
diff --git a/arch/x86/xen/time.c b/arch/x86/xen/time.c
index b3c6c59ed30..1a5353a753f 100644
--- a/arch/x86/xen/time.c
+++ b/arch/x86/xen/time.c
@@ -20,6 +20,7 @@
#include <asm/xen/hypercall.h>
#include <xen/events.h>
+#include <xen/features.h>
#include <xen/interface/xen.h>
#include <xen/interface/vcpu.h>
@@ -155,47 +156,8 @@ static void do_stolen_accounting(void)
account_idle_ticks(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 TSC speed from Xen */
-unsigned long xen_tsc_khz(void)
+static unsigned long xen_tsc_khz(void)
{
struct pvclock_vcpu_time_info *info =
&HYPERVISOR_shared_info->vcpu_info[0].time;
@@ -230,7 +192,7 @@ static void xen_read_wallclock(struct timespec *ts)
put_cpu_var(xen_vcpu);
}
-unsigned long xen_get_wallclock(void)
+static unsigned long xen_get_wallclock(void)
{
struct timespec ts;
@@ -238,7 +200,7 @@ unsigned long xen_get_wallclock(void)
return ts.tv_sec;
}
-int xen_set_wallclock(unsigned long now)
+static int xen_set_wallclock(unsigned long now)
{
/* do nothing for domU */
return -1;
@@ -473,7 +435,11 @@ void xen_timer_resume(void)
}
}
-__init void xen_time_init(void)
+static const struct pv_time_ops xen_time_ops __initdata = {
+ .sched_clock = xen_clocksource_read,
+};
+
+static __init void xen_time_init(void)
{
int cpu = smp_processor_id();
struct timespec tp;
@@ -497,3 +463,47 @@ __init void xen_time_init(void)
xen_setup_timer(cpu);
xen_setup_cpu_clockevents();
}
+
+__init void xen_init_time_ops(void)
+{
+ pv_time_ops = xen_time_ops;
+
+ x86_init.timers.timer_init = xen_time_init;
+ x86_init.timers.setup_percpu_clockev = x86_init_noop;
+ x86_cpuinit.setup_percpu_clockev = x86_init_noop;
+
+ x86_platform.calibrate_tsc = xen_tsc_khz;
+ x86_platform.get_wallclock = xen_get_wallclock;
+ x86_platform.set_wallclock = xen_set_wallclock;
+}
+
+#ifdef CONFIG_XEN_PVHVM
+static void xen_hvm_setup_cpu_clockevents(void)
+{
+ int cpu = smp_processor_id();
+ xen_setup_runstate_info(cpu);
+ xen_setup_timer(cpu);
+ xen_setup_cpu_clockevents();
+}
+
+__init void xen_hvm_init_time_ops(void)
+{
+ /* vector callback is needed otherwise we cannot receive interrupts
+ * on cpu > 0 */
+ if (!xen_have_vector_callback && num_present_cpus() > 1)
+ return;
+ if (!xen_feature(XENFEAT_hvm_safe_pvclock)) {
+ printk(KERN_INFO "Xen doesn't support pvclock on HVM,"
+ "disable pv timer\n");
+ return;
+ }
+
+ pv_time_ops = xen_time_ops;
+ x86_init.timers.setup_percpu_clockev = xen_time_init;
+ x86_cpuinit.setup_percpu_clockev = xen_hvm_setup_cpu_clockevents;
+
+ x86_platform.calibrate_tsc = xen_tsc_khz;
+ x86_platform.get_wallclock = xen_get_wallclock;
+ x86_platform.set_wallclock = xen_set_wallclock;
+}
+#endif
diff --git a/arch/x86/xen/xen-ops.h b/arch/x86/xen/xen-ops.h
index f9153a300bc..7c8ab86163e 100644
--- a/arch/x86/xen/xen-ops.h
+++ b/arch/x86/xen/xen-ops.h
@@ -38,6 +38,10 @@ void xen_enable_sysenter(void);
void xen_enable_syscall(void);
void xen_vcpu_restore(void);
+void xen_callback_vector(void);
+void xen_hvm_init_shared_info(void);
+void __init xen_unplug_emulated_devices(void);
+
void __init xen_build_dynamic_phys_to_machine(void);
void xen_init_irq_ops(void);
@@ -46,11 +50,8 @@ void xen_setup_runstate_info(int cpu);
void xen_teardown_timer(int cpu);
cycle_t xen_clocksource_read(void);
void xen_setup_cpu_clockevents(void);
-unsigned long xen_tsc_khz(void);
-void __init xen_time_init(void);
-unsigned long xen_get_wallclock(void);
-int xen_set_wallclock(unsigned long time);
-unsigned long long xen_sched_clock(void);
+void __init xen_init_time_ops(void);
+void __init xen_hvm_init_time_ops(void);
irqreturn_t xen_debug_interrupt(int irq, void *dev_id);
@@ -101,4 +102,6 @@ void xen_sysret32(void);
void xen_sysret64(void);
void xen_adjust_exception_frame(void);
+extern int xen_panic_handler_init(void);
+
#endif /* XEN_OPS_H */
diff --git a/arch/xtensa/Kconfig b/arch/xtensa/Kconfig
index ebe228d02b0..0859bfd8ae9 100644
--- a/arch/xtensa/Kconfig
+++ b/arch/xtensa/Kconfig
@@ -48,9 +48,6 @@ config HZ
int
default 100
-config GENERIC_TIME
- def_bool y
-
source "init/Kconfig"
source "kernel/Kconfig.freezer"
diff --git a/arch/xtensa/Makefile b/arch/xtensa/Makefile
index 4caffac3ca2..7608559de93 100644
--- a/arch/xtensa/Makefile
+++ b/arch/xtensa/Makefile
@@ -35,6 +35,8 @@ KBUILD_CFLAGS += -ffreestanding
KBUILD_CFLAGS += -pipe -mlongcalls
+KBUILD_CFLAGS += $(call cc-option,-mforce-no-pic,)
+
vardirs := $(patsubst %,arch/xtensa/variants/%/,$(variant-y))
plfdirs := $(patsubst %,arch/xtensa/platforms/%/,$(platform-y))
diff --git a/arch/xtensa/configs/iss_defconfig b/arch/xtensa/configs/iss_defconfig
index f19854035e6..7368164843b 100644
--- a/arch/xtensa/configs/iss_defconfig
+++ b/arch/xtensa/configs/iss_defconfig
@@ -1,193 +1,214 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.11-rc2
-# Fri Feb 25 19:21:24 2005
+# Linux kernel version: 2.6.34-rc6
+# Tue Aug 3 00:10:54 2010
#
-CONFIG_FRAME_POINTER=y
+# CONFIG_FRAME_POINTER is not set
+CONFIG_ZONE_DMA=y
CONFIG_XTENSA=y
-# CONFIG_UID16 is not set
CONFIG_RWSEM_XCHGADD_ALGORITHM=y
-CONFIG_HAVE_DEC_LOCK=y
+CONFIG_GENERIC_FIND_NEXT_BIT=y
+CONFIG_GENERIC_HWEIGHT=y
CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_GPIO=y
+# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
+CONFIG_NO_IOPORT=y
+CONFIG_HZ=100
+CONFIG_GENERIC_TIME=y
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+CONFIG_CONSTRUCTORS=y
#
-# Code maturity level options
+# General setup
#
CONFIG_EXPERIMENTAL=y
-CONFIG_CLEAN_COMPILE=y
CONFIG_BROKEN_ON_SMP=y
-
-#
-# General setup
-#
+CONFIG_INIT_ENV_ARG_LIMIT=32
CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
CONFIG_SWAP=y
CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
# CONFIG_POSIX_MQUEUE is not set
# CONFIG_BSD_PROCESS_ACCT is not set
-CONFIG_SYSCTL=y
+# CONFIG_TASKSTATS is not set
# CONFIG_AUDIT is not set
-CONFIG_LOG_BUF_SHIFT=14
-# CONFIG_HOTPLUG is not set
-# CONFIG_KOBJECT_UEVENT is not set
+
+#
+# RCU Subsystem
+#
+CONFIG_TREE_RCU=y
+# CONFIG_TREE_PREEMPT_RCU is not set
+# CONFIG_TINY_RCU is not set
+# CONFIG_RCU_TRACE is not set
+CONFIG_RCU_FANOUT=32
+# CONFIG_RCU_FANOUT_EXACT is not set
+# CONFIG_TREE_RCU_TRACE is not set
# CONFIG_IKCONFIG is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_CGROUPS is not set
+# CONFIG_SYSFS_DEPRECATED_V2 is not set
+# CONFIG_RELAY is not set
+# CONFIG_NAMESPACES is not set
+# CONFIG_BLK_DEV_INITRD is not set
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SYSCTL=y
+CONFIG_ANON_INODES=y
CONFIG_EMBEDDED=y
+CONFIG_SYSCTL_SYSCALL=y
CONFIG_KALLSYMS=y
# CONFIG_KALLSYMS_ALL is not set
# CONFIG_KALLSYMS_EXTRA_PASS is not set
+# CONFIG_HOTPLUG is not set
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
CONFIG_FUTEX=y
CONFIG_EPOLL=y
-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
CONFIG_SHMEM=y
-CONFIG_CC_ALIGN_FUNCTIONS=0
-CONFIG_CC_ALIGN_LABELS=0
-CONFIG_CC_ALIGN_LOOPS=0
-CONFIG_CC_ALIGN_JUMPS=0
-# CONFIG_TINY_SHMEM is not set
+CONFIG_AIO=y
+
+#
+# Kernel Performance Events And Counters
+#
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_SLUB_DEBUG=y
+CONFIG_COMPAT_BRK=y
+# CONFIG_SLAB is not set
+CONFIG_SLUB=y
+# CONFIG_SLOB is not set
+# CONFIG_PROFILING is not set
#
-# Loadable module support
+# GCOV-based kernel profiling
#
+# CONFIG_SLOW_WORK is not set
+# CONFIG_HAVE_GENERIC_DMA_COHERENT is not set
+CONFIG_SLABINFO=y
+CONFIG_RT_MUTEXES=y
+CONFIG_BASE_SMALL=0
# CONFIG_MODULES is not set
+CONFIG_BLOCK=y
+CONFIG_LBDAF=y
+CONFIG_BLK_DEV_BSG=y
+# CONFIG_BLK_DEV_INTEGRITY is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+# CONFIG_IOSCHED_DEADLINE is not set
+# CONFIG_IOSCHED_CFQ is not set
+# CONFIG_DEFAULT_DEADLINE is not set
+# CONFIG_DEFAULT_CFQ is not set
+CONFIG_DEFAULT_NOOP=y
+CONFIG_DEFAULT_IOSCHED="noop"
+# CONFIG_INLINE_SPIN_TRYLOCK is not set
+# CONFIG_INLINE_SPIN_TRYLOCK_BH is not set
+# CONFIG_INLINE_SPIN_LOCK is not set
+# CONFIG_INLINE_SPIN_LOCK_BH is not set
+# CONFIG_INLINE_SPIN_LOCK_IRQ is not set
+# CONFIG_INLINE_SPIN_LOCK_IRQSAVE is not set
+CONFIG_INLINE_SPIN_UNLOCK=y
+# CONFIG_INLINE_SPIN_UNLOCK_BH is not set
+CONFIG_INLINE_SPIN_UNLOCK_IRQ=y
+# CONFIG_INLINE_SPIN_UNLOCK_IRQRESTORE is not set
+# CONFIG_INLINE_READ_TRYLOCK is not set
+# CONFIG_INLINE_READ_LOCK is not set
+# CONFIG_INLINE_READ_LOCK_BH is not set
+# CONFIG_INLINE_READ_LOCK_IRQ is not set
+# CONFIG_INLINE_READ_LOCK_IRQSAVE is not set
+CONFIG_INLINE_READ_UNLOCK=y
+# CONFIG_INLINE_READ_UNLOCK_BH is not set
+CONFIG_INLINE_READ_UNLOCK_IRQ=y
+# CONFIG_INLINE_READ_UNLOCK_IRQRESTORE is not set
+# CONFIG_INLINE_WRITE_TRYLOCK is not set
+# CONFIG_INLINE_WRITE_LOCK is not set
+# CONFIG_INLINE_WRITE_LOCK_BH is not set
+# CONFIG_INLINE_WRITE_LOCK_IRQ is not set
+# CONFIG_INLINE_WRITE_LOCK_IRQSAVE is not set
+CONFIG_INLINE_WRITE_UNLOCK=y
+# CONFIG_INLINE_WRITE_UNLOCK_BH is not set
+CONFIG_INLINE_WRITE_UNLOCK_IRQ=y
+# CONFIG_INLINE_WRITE_UNLOCK_IRQRESTORE is not set
+# CONFIG_MUTEX_SPIN_ON_OWNER is not set
+# CONFIG_FREEZER is not set
+CONFIG_MMU=y
+# CONFIG_VARIANT_IRQ_SWITCH is not set
#
# Processor type and features
#
CONFIG_XTENSA_VARIANT_FSF=y
-CONFIG_MMU=y
+# CONFIG_XTENSA_VARIANT_DC232B is not set
+# CONFIG_XTENSA_VARIANT_S6000 is not set
# CONFIG_XTENSA_UNALIGNED_USER is not set
# CONFIG_PREEMPT is not set
# CONFIG_MATH_EMULATION is not set
-# CONFIG_HIGHMEM is not set
-
-#
-# Platform options
-#
-CONFIG_XTENSA_PLATFORM_ISS=y
-# CONFIG_XTENSA_PLATFORM_XT2000 is not set
-# CONFIG_XTENSA_PLATFORM_ARUBA is not set
-# CONFIG_XTENSA_CALIBRATE_CCOUNT is not set
-CONFIG_XTENSA_CPU_CLOCK=10
-# CONFIG_GENERIC_CALIBRATE_DELAY is not set
-CONFIG_CMDLINE_BOOL=y
-CONFIG_CMDLINE="console=ttyS0,38400 eth0=tuntap,,tap0 ip=192.168.168.5:192.168.168.1 root=nfs nfsroot=192.168.168.1:/opt/montavista/pro/devkit/xtensa/linux_be/target"
+CONFIG_XTENSA_CALIBRATE_CCOUNT=y
CONFIG_SERIAL_CONSOLE=y
CONFIG_XTENSA_ISS_NETWORK=y
#
# Bus options
#
+# CONFIG_PCI is not set
+# CONFIG_ARCH_SUPPORTS_MSI is not set
#
-# PCCARD (PCMCIA/CardBus) support
-#
-# CONFIG_PCCARD is not set
-
-#
-# PC-card bridges
-#
-
-#
-# PCI Hotplug Support
-#
-
+# Platform options
#
-# Exectuable file formats
+CONFIG_XTENSA_PLATFORM_ISS=y
+# CONFIG_XTENSA_PLATFORM_XT2000 is not set
+# CONFIG_XTENSA_PLATFORM_S6105 is not set
+# CONFIG_GENERIC_CALIBRATE_DELAY is not set
+CONFIG_CMDLINE_BOOL=y
+CONFIG_CMDLINE="console=ttyS0,38400 eth0=tuntap,,tap0 ip=192.168.168.5:192.168.168.1 root=nfs nfsroot=192.168.168.1:/opt/montavista/pro/devkit/xtensa/linux_be/target"
+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_PAGEFLAGS_EXTENDED=y
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_PHYS_ADDR_T_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=1
+CONFIG_BOUNCE=y
+CONFIG_VIRT_TO_BUS=y
+# CONFIG_KSM is not set
+CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
+
+#
+# Executable file formats
#
CONFIG_KCORE_ELF=y
CONFIG_BINFMT_ELF=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+# CONFIG_HAVE_AOUT is not set
# CONFIG_BINFMT_MISC is not set
-
-#
-# Device Drivers
-#
-
-#
-# Generic Driver Options
-#
-# CONFIG_STANDALONE is not set
-CONFIG_PREVENT_FIRMWARE_BUILD=y
-# CONFIG_FW_LOADER is not set
-# CONFIG_DEBUG_DRIVER is not set
-
-#
-# Memory Technology Devices (MTD)
-#
-# CONFIG_MTD is not set
-
-#
-# Parallel port support
-#
-# CONFIG_PARPORT is not set
-
-#
-# Plug and Play support
-#
-
-#
-# Block devices
-#
-# CONFIG_BLK_DEV_FD is not set
-# CONFIG_BLK_DEV_COW_COMMON is not set
-# CONFIG_BLK_DEV_LOOP is not set
-# CONFIG_BLK_DEV_NBD is not set
-# CONFIG_BLK_DEV_RAM is not set
-CONFIG_BLK_DEV_RAM_COUNT=16
-CONFIG_INITRAMFS_SOURCE=""
-# CONFIG_CDROM_PKTCDVD is not set
-
-#
-# IO Schedulers
-#
-CONFIG_IOSCHED_NOOP=y
-# CONFIG_IOSCHED_AS is not set
-# CONFIG_IOSCHED_DEADLINE is not set
-# CONFIG_IOSCHED_CFQ is not set
-# CONFIG_ATA_OVER_ETH is not set
-
-#
-# ATA/ATAPI/MFM/RLL support
-#
-# CONFIG_IDE is not set
-
-#
-# SCSI device support
-#
-# CONFIG_SCSI is not set
-
-#
-# Multi-device support (RAID and LVM)
-#
-# CONFIG_MD is not set
-
-#
-# Fusion MPT device support
-#
-
-#
-# IEEE 1394 (FireWire) support
-#
-
-#
-# I2O device support
-#
-
-#
-# Networking support
-#
CONFIG_NET=y
#
# Networking options
#
CONFIG_PACKET=y
-# CONFIG_PACKET_MMAP is not set
-# CONFIG_NETLINK_DEV is not set
CONFIG_UNIX=y
+CONFIG_XFRM=y
+# CONFIG_XFRM_USER is not set
+# CONFIG_XFRM_SUB_POLICY is not set
+# CONFIG_XFRM_MIGRATE is not set
+# CONFIG_XFRM_STATISTICS is not set
# CONFIG_NET_KEY is not set
CONFIG_INET=y
# CONFIG_IP_MULTICAST is not set
# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
CONFIG_IP_PNP=y
CONFIG_IP_PNP_DHCP=y
CONFIG_IP_PNP_BOOTP=y
@@ -199,21 +220,28 @@ CONFIG_IP_PNP_RARP=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_IP_TCPDIAG is not set
-# CONFIG_IP_TCPDIAG_IPV6 is not set
+CONFIG_INET_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
+CONFIG_INET_XFRM_MODE_BEET=y
+CONFIG_INET_LRO=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_NETWORK_SECMARK is not set
# CONFIG_NETFILTER is not set
-
-#
-# SCTP Configuration (EXPERIMENTAL)
-#
+# CONFIG_IP_DCCP is not set
# CONFIG_IP_SCTP is not set
-# CONFIG_SCTP_HMAC_NONE is not set
-# CONFIG_SCTP_HMAC_SHA1 is not set
-# CONFIG_SCTP_HMAC_MD5 is not set
+# CONFIG_RDS is not set
+# CONFIG_TIPC is not set
# CONFIG_ATM is not set
# CONFIG_BRIDGE is not set
+# CONFIG_NET_DSA is not set
# CONFIG_VLAN_8021Q is not set
# CONFIG_DECNET is not set
# CONFIG_LLC2 is not set
@@ -221,77 +249,126 @@ CONFIG_IP_PNP_RARP=y
# CONFIG_ATALK is not set
# CONFIG_X25 is not set
# CONFIG_LAPB is not set
-# CONFIG_NET_DIVERT is not set
# CONFIG_ECONET is not set
# CONFIG_WAN_ROUTER is not set
-
-#
-# QoS and/or fair queueing
-#
+# CONFIG_PHONET is not set
+# CONFIG_IEEE802154 is not set
# CONFIG_NET_SCHED is not set
-# CONFIG_NET_SCH_CLK_JIFFIES is not set
-# CONFIG_NET_SCH_CLK_GETTIMEOFDAY is not set
-# CONFIG_NET_SCH_CLK_CPU is not set
-# CONFIG_NET_CLS_ROUTE is not set
+# CONFIG_DCB is not set
#
# Network testing
#
# CONFIG_NET_PKTGEN is not set
-# CONFIG_NETPOLL is not set
-# CONFIG_NET_POLL_CONTROLLER is not set
# CONFIG_HAMRADIO is not set
+# CONFIG_CAN is not set
# CONFIG_IRDA is not set
# CONFIG_BT is not set
-# CONFIG_NETDEVICES is not set
+# CONFIG_AF_RXRPC is not set
+CONFIG_WIRELESS=y
+# CONFIG_CFG80211 is not set
+# CONFIG_LIB80211 is not set
#
-# ISDN subsystem
+# CFG80211 needs to be enabled for MAC80211
#
-# CONFIG_ISDN is not set
+# CONFIG_WIMAX is not set
+# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+# CONFIG_STANDALONE is not set
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_DEBUG_DEVRES is not set
+# CONFIG_SYS_HYPERVISOR is not set
+# CONFIG_CONNECTOR is not set
+# CONFIG_MTD is not set
+# CONFIG_PARPORT is not set
+CONFIG_BLK_DEV=y
+# CONFIG_BLK_DEV_COW_COMMON is not set
+# CONFIG_BLK_DEV_LOOP is not set
#
-# Telephony Support
+# DRBD disabled because PROC_FS, INET or CONNECTOR not selected
+#
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_RAM is not set
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+# CONFIG_BLK_DEV_HD is not set
+CONFIG_MISC_DEVICES=y
+# CONFIG_ENCLOSURE_SERVICES is not set
+# CONFIG_C2PORT is not set
+
+#
+# EEPROM support
+#
+# CONFIG_EEPROM_93CX6 is not set
+CONFIG_HAVE_IDE=y
+# CONFIG_IDE is not set
+
#
+# SCSI device support
+#
+CONFIG_SCSI_MOD=y
+# CONFIG_RAID_ATTRS is not set
+# CONFIG_SCSI is not set
+# CONFIG_SCSI_DMA is not set
+# CONFIG_SCSI_NETLINK is not set
+# CONFIG_ATA is not set
+# CONFIG_MD is not set
+# CONFIG_NETDEVICES is not set
+# CONFIG_ISDN is not set
# CONFIG_PHONE is not set
#
# Input device support
#
CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
+# CONFIG_INPUT_SPARSEKMAP 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 I/O drivers
-#
-# CONFIG_GAMEPORT is not set
-CONFIG_SOUND_GAMEPORT=y
-# CONFIG_SERIO is not set
-# CONFIG_SERIO_I8042 is not set
-
-#
# Input Device Drivers
#
# CONFIG_INPUT_KEYBOARD is not set
# CONFIG_INPUT_MOUSE is not set
# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
# CONFIG_INPUT_TOUCHSCREEN is not set
# CONFIG_INPUT_MISC is not set
#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
# Character devices
#
CONFIG_VT=y
+CONFIG_CONSOLE_TRANSLATIONS=y
CONFIG_VT_CONSOLE=y
CONFIG_HW_CONSOLE=y
+# CONFIG_VT_HW_CONSOLE_BINDING is not set
+CONFIG_DEVKMEM=y
# CONFIG_SERIAL_NONSTANDARD is not set
#
@@ -302,117 +379,159 @@ CONFIG_HW_CONSOLE=y
#
# Non-8250 serial port support
#
+# CONFIG_SERIAL_TIMBERDALE is not set
CONFIG_UNIX98_PTYS=y
+# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
CONFIG_LEGACY_PTYS=y
CONFIG_LEGACY_PTY_COUNT=256
-
-#
-# IPMI
-#
# CONFIG_IPMI_HANDLER is not set
-
-#
-# Watchdog Cards
-#
-CONFIG_WATCHDOG=y
-CONFIG_WATCHDOG_NOWAYOUT=y
-
-#
-# Watchdog Device Drivers
-#
-CONFIG_SOFT_WATCHDOG=y
+CONFIG_HW_RANDOM=y
+# CONFIG_HW_RANDOM_TIMERIOMEM is not set
# CONFIG_RTC 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_DRM is not set
# CONFIG_RAW_DRIVER is not set
-
-#
-# I2C support
-#
+# CONFIG_TCG_TPM is not set
# CONFIG_I2C is not set
+# CONFIG_SPI is not set
#
-# Dallas's 1-wire bus
+# PPS support
#
+# CONFIG_PPS is not set
# CONFIG_W1 is not set
+# CONFIG_POWER_SUPPLY is not set
+CONFIG_HWMON=y
+# CONFIG_HWMON_VID is not set
+# CONFIG_HWMON_DEBUG_CHIP is not set
+
+#
+# Native drivers
+#
+# CONFIG_SENSORS_F71805F is not set
+# CONFIG_SENSORS_F71882FG is not set
+# CONFIG_SENSORS_IT87 is not set
+# CONFIG_SENSORS_PC87360 is not set
+# CONFIG_SENSORS_PC87427 is not set
+# CONFIG_SENSORS_SHT15 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_SENSORS_W83627EHF is not set
+# CONFIG_THERMAL is not set
+CONFIG_WATCHDOG=y
+CONFIG_WATCHDOG_NOWAYOUT=y
#
-# Misc devices
+# Watchdog Device Drivers
#
+CONFIG_SOFT_WATCHDOG=y
+CONFIG_SSB_POSSIBLE=y
#
-# Multimedia devices
+# Sonics Silicon Backplane
#
-# CONFIG_VIDEO_DEV is not set
+# CONFIG_SSB is not set
#
-# Digital Video Broadcasting Devices
+# Multifunction device drivers
#
-# CONFIG_DVB is not set
+# CONFIG_MFD_CORE is not set
+# CONFIG_MFD_SM501 is not set
+# CONFIG_HTC_PASIC3 is not set
+# CONFIG_MFD_TMIO is not set
+# CONFIG_REGULATOR is not set
+# CONFIG_MEDIA_SUPPORT is not set
#
# Graphics support
#
+# CONFIG_VGASTATE is not set
+# CONFIG_VIDEO_OUTPUT_CONTROL is not set
# CONFIG_FB is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
#
-# Console display driver support
+# Display device support
#
-# CONFIG_VGA_CONSOLE is not set
-CONFIG_DUMMY_CONSOLE=y
-# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+# CONFIG_DISPLAY_SUPPORT is not set
#
-# Sound
+# Console display driver support
#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
# CONFIG_SOUND is not set
+CONFIG_HID_SUPPORT=y
+CONFIG_HID=y
+# CONFIG_HIDRAW is not set
+# CONFIG_HID_PID is not set
#
-# USB support
+# Special HID drivers
#
+CONFIG_USB_SUPPORT=y
# CONFIG_USB_ARCH_HAS_HCD is not set
# CONFIG_USB_ARCH_HAS_OHCI is not set
+# CONFIG_USB_ARCH_HAS_EHCI is not set
+# CONFIG_USB_OTG_WHITELIST is not set
+# CONFIG_USB_OTG_BLACKLIST_HUB is not set
#
-# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information
+# Enable Host or Gadget support to see Inventra options
#
#
-# USB Gadget Support
+# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may
#
# CONFIG_USB_GADGET is not set
#
-# MMC/SD Card support
+# OTG and related infrastructure
#
# CONFIG_MMC is not set
+# CONFIG_MEMSTICK is not set
+# CONFIG_NEW_LEDS is not set
+# CONFIG_ACCESSIBILITY is not set
+# CONFIG_RTC_CLASS is not set
+# CONFIG_DMADEVICES is not set
+# CONFIG_AUXDISPLAY is not set
+# CONFIG_UIO is not set
#
-# InfiniBand support
+# TI VLYNQ
#
-# CONFIG_INFINIBAND is not set
+# CONFIG_STAGING is not set
#
# File systems
#
# CONFIG_EXT2_FS is not set
# CONFIG_EXT3_FS is not set
-# CONFIG_JBD is not set
+# CONFIG_EXT4_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_MINIX_FS is not set
-# CONFIG_ROMFS_FS is not set
-# CONFIG_QUOTA is not set
+# CONFIG_GFS2_FS is not set
+# CONFIG_OCFS2_FS is not set
+# CONFIG_BTRFS_FS is not set
+# CONFIG_NILFS2_FS is not set
+CONFIG_FILE_LOCKING=y
+CONFIG_FSNOTIFY=y
# CONFIG_DNOTIFY is not set
+# CONFIG_INOTIFY is not set
+CONFIG_INOTIFY_USER=y
+# CONFIG_QUOTA is not set
# CONFIG_AUTOFS_FS is not set
# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+
+#
+# Caches
+#
+# CONFIG_FSCACHE is not set
#
# CD-ROM/DVD Filesystems
@@ -432,19 +551,14 @@ CONFIG_DUMMY_CONSOLE=y
#
CONFIG_PROC_FS=y
CONFIG_PROC_KCORE=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_PROC_PAGE_MONITOR=y
CONFIG_SYSFS=y
-CONFIG_DEVFS_FS=y
-CONFIG_DEVFS_MOUNT=y
-# CONFIG_DEVFS_DEBUG is not set
-# CONFIG_DEVPTS_FS_XATTR is not set
CONFIG_TMPFS=y
-# CONFIG_TMPFS_XATTR is not set
+# CONFIG_TMPFS_POSIX_ACL is not set
# CONFIG_HUGETLB_PAGE is not set
-CONFIG_RAMFS=y
-
-#
-# Miscellaneous filesystems
-#
+# CONFIG_CONFIGFS_FS is not set
+CONFIG_MISC_FILESYSTEMS=y
# CONFIG_ADFS_FS is not set
# CONFIG_AFFS_FS is not set
# CONFIG_HFS_FS is not set
@@ -452,29 +566,22 @@ CONFIG_RAMFS=y
# CONFIG_BEFS_FS is not set
# CONFIG_BFS_FS is not set
# CONFIG_EFS_FS is not set
+# CONFIG_LOGFS is not set
# CONFIG_CRAMFS is not set
+# CONFIG_SQUASHFS is not set
# CONFIG_VXFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_OMFS_FS is not set
# CONFIG_HPFS_FS is not set
# CONFIG_QNX4FS_FS is not set
+# CONFIG_ROMFS_FS is not set
# CONFIG_SYSV_FS is not set
# CONFIG_UFS_FS is not set
-
-#
-# Network File Systems
-#
-CONFIG_NFS_FS=y
-CONFIG_NFS_V3=y
-# CONFIG_NFS_V4 is not set
-CONFIG_NFS_DIRECTIO=y
+CONFIG_NETWORK_FILESYSTEMS=y
+# CONFIG_NFS_FS is not set
# CONFIG_NFSD is not set
-CONFIG_ROOT_NFS=y
-CONFIG_LOCKD=y
-CONFIG_LOCKD_V4=y
-# CONFIG_EXPORTFS is not set
-CONFIG_SUNRPC=y
-# CONFIG_RPCSEC_GSS_KRB5 is not set
-# CONFIG_RPCSEC_GSS_SPKM3 is not set
# CONFIG_SMB_FS is not set
+# CONFIG_CEPH_FS is not set
# CONFIG_CIFS is not set
# CONFIG_NCP_FS is not set
# CONFIG_CODA_FS is not set
@@ -485,43 +592,175 @@ CONFIG_SUNRPC=y
#
# CONFIG_PARTITION_ADVANCED is not set
CONFIG_MSDOS_PARTITION=y
-
-#
-# Native Language Support
-#
# CONFIG_NLS is not set
+# CONFIG_DLM is not set
#
# Kernel hacking
#
-CONFIG_DEBUG_KERNEL=y
-# CONFIG_DEBUG_STACKOVERFLOW is not set
-# CONFIG_DEBUG_SLAB is not set
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_WARN_DEPRECATED=y
+CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_FRAME_WARN=1024
# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_STRIP_ASM_SYMS is not set
+# 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=y
+# CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set
+CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=0
+CONFIG_DETECT_HUNG_TASK=y
+# CONFIG_BOOTPARAM_HUNG_TASK_PANIC is not set
+CONFIG_BOOTPARAM_HUNG_TASK_PANIC_VALUE=0
+CONFIG_SCHED_DEBUG=y
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_TIMER_STATS is not set
+# CONFIG_DEBUG_OBJECTS is not set
+# CONFIG_SLUB_DEBUG_ON is not set
+# CONFIG_SLUB_STATS 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_PAGEALLOC is not set
-# CONFIG_DEBUG_INFO is not set
+# CONFIG_DEBUG_MUTEXES is not set
# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
-# CONFIG_KGDB is not set
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+# CONFIG_DEBUG_KOBJECT is not set
+# CONFIG_DEBUG_INFO is not set
+# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_WRITECOUNT is not set
+# CONFIG_DEBUG_MEMORY_INIT is not set
+# CONFIG_DEBUG_LIST is not set
+# CONFIG_DEBUG_SG is not set
+# CONFIG_DEBUG_NOTIFIERS is not set
+# CONFIG_DEBUG_CREDENTIALS is not set
+# CONFIG_RCU_TORTURE_TEST is not set
+CONFIG_RCU_CPU_STALL_DETECTOR=y
+# CONFIG_BACKTRACE_SELF_TEST is not set
+# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
+# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set
+# CONFIG_FAULT_INJECTION is not set
+# CONFIG_SYSCTL_SYSCALL_CHECK is not set
+# CONFIG_PAGE_POISONING is not set
+# CONFIG_SAMPLES is not set
#
# Security options
#
# CONFIG_KEYS is not set
# CONFIG_SECURITY is not set
+# CONFIG_SECURITYFS is not set
+# CONFIG_DEFAULT_SECURITY_SELINUX is not set
+# CONFIG_DEFAULT_SECURITY_SMACK is not set
+# CONFIG_DEFAULT_SECURITY_TOMOYO is not set
+CONFIG_DEFAULT_SECURITY_DAC=y
+CONFIG_DEFAULT_SECURITY=""
+CONFIG_CRYPTO=y
+
+#
+# Crypto core or helper
+#
+# CONFIG_CRYPTO_FIPS is not set
+CONFIG_CRYPTO_ALGAPI=y
+CONFIG_CRYPTO_ALGAPI2=y
+CONFIG_CRYPTO_RNG=y
+CONFIG_CRYPTO_RNG2=y
+# CONFIG_CRYPTO_MANAGER is not set
+# CONFIG_CRYPTO_MANAGER2 is not set
+# CONFIG_CRYPTO_GF128MUL is not set
+# CONFIG_CRYPTO_NULL is not set
+# CONFIG_CRYPTO_CRYPTD is not set
+# CONFIG_CRYPTO_AUTHENC is not set
+
+#
+# Authenticated Encryption with Associated Data
+#
+# CONFIG_CRYPTO_CCM is not set
+# CONFIG_CRYPTO_GCM is not set
+# CONFIG_CRYPTO_SEQIV is not set
+
+#
+# Block modes
+#
+# CONFIG_CRYPTO_CBC is not set
+# CONFIG_CRYPTO_CTR is not set
+# CONFIG_CRYPTO_CTS is not set
+# CONFIG_CRYPTO_ECB is not set
+# CONFIG_CRYPTO_LRW is not set
+# CONFIG_CRYPTO_PCBC is not set
+# CONFIG_CRYPTO_XTS is not set
+
+#
+# Hash modes
+#
+# CONFIG_CRYPTO_HMAC is not set
+# CONFIG_CRYPTO_XCBC is not set
+# CONFIG_CRYPTO_VMAC is not set
+
+#
+# Digest
+#
+# CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_GHASH is not set
+# CONFIG_CRYPTO_MD4 is not set
+# CONFIG_CRYPTO_MD5 is not set
+# CONFIG_CRYPTO_MICHAEL_MIC is not set
+# CONFIG_CRYPTO_RMD128 is not set
+# CONFIG_CRYPTO_RMD160 is not set
+# CONFIG_CRYPTO_RMD256 is not set
+# CONFIG_CRYPTO_RMD320 is not set
+# CONFIG_CRYPTO_SHA1 is not set
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_TGR192 is not set
+# CONFIG_CRYPTO_WP512 is not set
+
+#
+# Ciphers
+#
+CONFIG_CRYPTO_AES=y
+# CONFIG_CRYPTO_ANUBIS is not set
+# CONFIG_CRYPTO_ARC4 is not set
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_CAMELLIA is not set
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+# CONFIG_CRYPTO_DES is not set
+# CONFIG_CRYPTO_FCRYPT is not set
+# CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_SALSA20 is not set
+# CONFIG_CRYPTO_SEED is not set
+# CONFIG_CRYPTO_SERPENT is not set
+# CONFIG_CRYPTO_TEA is not set
+# CONFIG_CRYPTO_TWOFISH is not set
#
-# Cryptographic options
+# Compression
#
-# CONFIG_CRYPTO is not set
+# CONFIG_CRYPTO_DEFLATE is not set
+# CONFIG_CRYPTO_ZLIB is not set
+# CONFIG_CRYPTO_LZO is not set
#
-# Hardware crypto devices
+# Random Number Generation
#
+CONFIG_CRYPTO_ANSI_CPRNG=y
+CONFIG_CRYPTO_HW=y
+# CONFIG_BINARY_PRINTF is not set
#
# Library routines
#
+CONFIG_GENERIC_FIND_LAST_BIT=y
# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC16 is not set
+# CONFIG_CRC_T10DIF is not set
+# CONFIG_CRC_ITU_T is not set
# CONFIG_CRC32 is not set
+# CONFIG_CRC7 is not set
# CONFIG_LIBCRC32C is not set
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_DMA=y
+CONFIG_NLATTR=y
diff --git a/arch/xtensa/include/asm/cacheflush.h b/arch/xtensa/include/asm/cacheflush.h
index a508f2f73bd..376cd9d5f45 100644
--- a/arch/xtensa/include/asm/cacheflush.h
+++ b/arch/xtensa/include/asm/cacheflush.h
@@ -115,6 +115,7 @@ extern void flush_cache_page(struct vm_area_struct*, unsigned long, unsigned lon
#define flush_cache_vmap(start,end) do { } while (0)
#define flush_cache_vunmap(start,end) do { } while (0)
+#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 0
#define flush_dcache_page(page) do { } while (0)
#define flush_cache_page(vma,addr,pfn) do { } while (0)
diff --git a/arch/xtensa/include/asm/coprocessor.h b/arch/xtensa/include/asm/coprocessor.h
index 65a285d8d3f..75c94a1658b 100644
--- a/arch/xtensa/include/asm/coprocessor.h
+++ b/arch/xtensa/include/asm/coprocessor.h
@@ -13,6 +13,7 @@
#define _XTENSA_COPROCESSOR_H
#include <linux/stringify.h>
+#include <variant/core.h>
#include <variant/tie.h>
#include <asm/types.h>
diff --git a/arch/xtensa/include/asm/elf.h b/arch/xtensa/include/asm/elf.h
index 5eb6d695e98..6e65eadaae1 100644
--- a/arch/xtensa/include/asm/elf.h
+++ b/arch/xtensa/include/asm/elf.h
@@ -14,6 +14,7 @@
#define _XTENSA_ELF_H
#include <asm/ptrace.h>
+#include <asm/coprocessor.h>
/* Xtensa processor ELF architecture-magic number */
diff --git a/arch/xtensa/include/asm/local64.h b/arch/xtensa/include/asm/local64.h
new file mode 100644
index 00000000000..36c93b5cc23
--- /dev/null
+++ b/arch/xtensa/include/asm/local64.h
@@ -0,0 +1 @@
+#include <asm-generic/local64.h>
diff --git a/arch/xtensa/include/asm/pgalloc.h b/arch/xtensa/include/asm/pgalloc.h
index 4f4a7987ede..40cf9bceda2 100644
--- a/arch/xtensa/include/asm/pgalloc.h
+++ b/arch/xtensa/include/asm/pgalloc.h
@@ -14,6 +14,7 @@
#ifdef __KERNEL__
#include <linux/highmem.h>
+#include <linux/slab.h>
/*
* Allocating and freeing a pmd is trivial: the 1-entry pmd is
diff --git a/arch/xtensa/include/asm/processor.h b/arch/xtensa/include/asm/processor.h
index 0ea4937c0b6..3acb26e8dea 100644
--- a/arch/xtensa/include/asm/processor.h
+++ b/arch/xtensa/include/asm/processor.h
@@ -12,7 +12,6 @@
#define _XTENSA_PROCESSOR_H
#include <variant/core.h>
-#include <asm/coprocessor.h>
#include <platform/hardware.h>
#include <linux/compiler.h>
diff --git a/arch/xtensa/include/asm/ptrace.h b/arch/xtensa/include/asm/ptrace.h
index 3c549f79872..0d42c934b66 100644
--- a/arch/xtensa/include/asm/ptrace.h
+++ b/arch/xtensa/include/asm/ptrace.h
@@ -77,6 +77,8 @@
#ifndef __ASSEMBLY__
+#include <asm/coprocessor.h>
+
/*
* This struct defines the way the registers are stored on the
* kernel stack during a system call or other kernel entry.
diff --git a/arch/xtensa/kernel/Makefile b/arch/xtensa/kernel/Makefile
index 6f56d95f2c1..2d2728b3e86 100644
--- a/arch/xtensa/kernel/Makefile
+++ b/arch/xtensa/kernel/Makefile
@@ -23,8 +23,8 @@ obj-$(CONFIG_MODULES) += xtensa_ksyms.o module.o
#
# Replicate rules in scripts/Makefile.build
-sed-y = -e 's/(\(\.[a-z]*it\|\.ref\|\)\.text)/(\1.literal \1.text)/g' \
- -e 's/(\(\.text\.[a-z]*\))/(\1.literal \1)/g'
+sed-y = -e 's/\*(\(\.[a-z]*it\|\.ref\|\)\.text)/*(\1.literal \1.text)/g' \
+ -e 's/\*(\(\.text\.[a-z]*\))/*(\1.literal \1)/g'
quiet_cmd__cpp_lds_S = LDS $@
cmd__cpp_lds_S = $(CPP) $(cpp_flags) -P -C -Uxtensa -D__ASSEMBLY__ $< \
diff --git a/arch/xtensa/kernel/asm-offsets.c b/arch/xtensa/kernel/asm-offsets.c
index 070ff8af3a2..7dc3f915718 100644
--- a/arch/xtensa/kernel/asm-offsets.c
+++ b/arch/xtensa/kernel/asm-offsets.c
@@ -13,6 +13,7 @@
*/
#include <asm/processor.h>
+#include <asm/coprocessor.h>
#include <linux/types.h>
#include <linux/stddef.h>
diff --git a/arch/xtensa/kernel/entry.S b/arch/xtensa/kernel/entry.S
index 77fc9f6dc01..5fd01f6aaf3 100644
--- a/arch/xtensa/kernel/entry.S
+++ b/arch/xtensa/kernel/entry.S
@@ -16,6 +16,7 @@
#include <linux/linkage.h>
#include <asm/asm-offsets.h>
#include <asm/processor.h>
+#include <asm/coprocessor.h>
#include <asm/thread_info.h>
#include <asm/uaccess.h>
#include <asm/unistd.h>
diff --git a/arch/xtensa/kernel/head.S b/arch/xtensa/kernel/head.S
index d215adcfd4e..3ef91a73652 100644
--- a/arch/xtensa/kernel/head.S
+++ b/arch/xtensa/kernel/head.S
@@ -184,8 +184,8 @@ _startup:
* Now clear the BSS segment.
*/
- movi a2, _bss_start # start of BSS
- movi a3, _bss_end # end of BSS
+ movi a2, __bss_start # start of BSS
+ movi a3, __bss_stop # end of BSS
__loopt a2, a3, a4, 2
s32i a0, a2, 0
diff --git a/arch/xtensa/platforms/iss/network.c b/arch/xtensa/platforms/iss/network.c
index 87e218f98ef..f717e20d961 100644
--- a/arch/xtensa/platforms/iss/network.c
+++ b/arch/xtensa/platforms/iss/network.c
@@ -623,6 +623,19 @@ static struct platform_driver iss_net_driver = {
static int driver_registered;
+static const struct net_device_ops iss_netdev_ops = {
+ .ndo_open = iss_net_open,
+ .ndo_stop = iss_net_close,
+ .ndo_get_stats = iss_net_get_stats,
+ .ndo_start_xmit = iss_net_start_xmit,
+ .ndo_validate_addr = eth_validate_addr,
+ .ndo_change_mtu = iss_net_change_mtu,
+ .ndo_set_mac_address = iss_net_set_mac,
+ //.ndo_do_ioctl = iss_net_ioctl,
+ .ndo_tx_timeout = iss_net_tx_timeout,
+ .ndo_set_multicast_list = iss_net_set_multicast_list,
+};
+
static int iss_net_configure(int index, char *init)
{
struct net_device *dev;
@@ -686,15 +699,8 @@ static int iss_net_configure(int index, char *init)
*/
snprintf(dev->name, sizeof dev->name, "eth%d", index);
+ dev->netdev_ops = &iss_netdev_ops;
dev->mtu = lp->mtu;
- dev->open = iss_net_open;
- dev->hard_start_xmit = iss_net_start_xmit;
- dev->stop = iss_net_close;
- dev->get_stats = iss_net_get_stats;
- dev->set_multicast_list = iss_net_set_multicast_list;
- dev->tx_timeout = iss_net_tx_timeout;
- dev->set_mac_address = iss_net_set_mac;
- dev->change_mtu = iss_net_change_mtu;
dev->watchdog_timeo = (HZ >> 1);
dev->irq = -1;
diff --git a/crypto/Kconfig b/crypto/Kconfig
index 9d9434f08c9..1cd497d7a15 100644
--- a/crypto/Kconfig
+++ b/crypto/Kconfig
@@ -80,6 +80,11 @@ config CRYPTO_RNG2
config CRYPTO_PCOMP
tristate
+ select CRYPTO_PCOMP2
+ select CRYPTO_ALGAPI
+
+config CRYPTO_PCOMP2
+ tristate
select CRYPTO_ALGAPI2
config CRYPTO_MANAGER
@@ -94,7 +99,15 @@ config CRYPTO_MANAGER2
select CRYPTO_AEAD2
select CRYPTO_HASH2
select CRYPTO_BLKCIPHER2
- select CRYPTO_PCOMP
+ select CRYPTO_PCOMP2
+
+config CRYPTO_MANAGER_TESTS
+ bool "Run algolithms' self-tests"
+ default y
+ depends on CRYPTO_MANAGER2
+ help
+ Run cryptomanager's tests for the new crypto algorithms being
+ registered.
config CRYPTO_GF128MUL
tristate "GF(2^128) multiplication functions (EXPERIMENTAL)"
diff --git a/crypto/Makefile b/crypto/Makefile
index d7e6441df7f..423b7de61f9 100644
--- a/crypto/Makefile
+++ b/crypto/Makefile
@@ -26,7 +26,7 @@ crypto_hash-objs += ahash.o
crypto_hash-objs += shash.o
obj-$(CONFIG_CRYPTO_HASH2) += crypto_hash.o
-obj-$(CONFIG_CRYPTO_PCOMP) += pcompress.o
+obj-$(CONFIG_CRYPTO_PCOMP2) += pcompress.o
cryptomgr-objs := algboss.o testmgr.o
@@ -61,7 +61,7 @@ obj-$(CONFIG_CRYPTO_CRYPTD) += cryptd.o
obj-$(CONFIG_CRYPTO_DES) += des_generic.o
obj-$(CONFIG_CRYPTO_FCRYPT) += fcrypt.o
obj-$(CONFIG_CRYPTO_BLOWFISH) += blowfish.o
-obj-$(CONFIG_CRYPTO_TWOFISH) += twofish.o
+obj-$(CONFIG_CRYPTO_TWOFISH) += twofish_generic.o
obj-$(CONFIG_CRYPTO_TWOFISH_COMMON) += twofish_common.o
obj-$(CONFIG_CRYPTO_SERPENT) += serpent.o
obj-$(CONFIG_CRYPTO_AES) += aes_generic.o
diff --git a/crypto/algboss.c b/crypto/algboss.c
index c3c196b5823..40bd391f34d 100644
--- a/crypto/algboss.c
+++ b/crypto/algboss.c
@@ -206,6 +206,7 @@ err:
return NOTIFY_OK;
}
+#ifdef CONFIG_CRYPTO_MANAGER_TESTS
static int cryptomgr_test(void *data)
{
struct crypto_test_param *param = data;
@@ -266,6 +267,7 @@ err_put_module:
err:
return NOTIFY_OK;
}
+#endif /* CONFIG_CRYPTO_MANAGER_TESTS */
static int cryptomgr_notify(struct notifier_block *this, unsigned long msg,
void *data)
@@ -273,8 +275,10 @@ static int cryptomgr_notify(struct notifier_block *this, unsigned long msg,
switch (msg) {
case CRYPTO_MSG_ALG_REQUEST:
return cryptomgr_schedule_probe(data);
+#ifdef CONFIG_CRYPTO_MANAGER_TESTS
case CRYPTO_MSG_ALG_REGISTER:
return cryptomgr_schedule_test(data);
+#endif
}
return NOTIFY_DONE;
diff --git a/crypto/authenc.c b/crypto/authenc.c
index b9884ee0adb..a5a22cfcd07 100644
--- a/crypto/authenc.c
+++ b/crypto/authenc.c
@@ -616,7 +616,7 @@ static struct crypto_instance *crypto_authenc_alloc(struct rtattr **tb)
auth = ahash_attr_alg(tb[1], CRYPTO_ALG_TYPE_HASH,
CRYPTO_ALG_TYPE_AHASH_MASK);
if (IS_ERR(auth))
- return ERR_PTR(PTR_ERR(auth));
+ return ERR_CAST(auth);
auth_base = &auth->base;
diff --git a/crypto/ctr.c b/crypto/ctr.c
index 6c3bfabb9d1..4ca7222cfeb 100644
--- a/crypto/ctr.c
+++ b/crypto/ctr.c
@@ -185,7 +185,7 @@ static struct crypto_instance *crypto_ctr_alloc(struct rtattr **tb)
alg = crypto_attr_alg(tb[1], CRYPTO_ALG_TYPE_CIPHER,
CRYPTO_ALG_TYPE_MASK);
if (IS_ERR(alg))
- return ERR_PTR(PTR_ERR(alg));
+ return ERR_CAST(alg);
/* Block size must be >= 4 bytes. */
err = -EINVAL;
diff --git a/crypto/pcrypt.c b/crypto/pcrypt.c
index 247178cb98e..de3078215fe 100644
--- a/crypto/pcrypt.c
+++ b/crypto/pcrypt.c
@@ -24,12 +24,40 @@
#include <linux/init.h>
#include <linux/module.h>
#include <linux/slab.h>
+#include <linux/notifier.h>
+#include <linux/kobject.h>
+#include <linux/cpu.h>
#include <crypto/pcrypt.h>
-static struct padata_instance *pcrypt_enc_padata;
-static struct padata_instance *pcrypt_dec_padata;
-static struct workqueue_struct *encwq;
-static struct workqueue_struct *decwq;
+struct padata_pcrypt {
+ struct padata_instance *pinst;
+ struct workqueue_struct *wq;
+
+ /*
+ * Cpumask for callback CPUs. It should be
+ * equal to serial cpumask of corresponding padata instance,
+ * so it is updated when padata notifies us about serial
+ * cpumask change.
+ *
+ * cb_cpumask is protected by RCU. This fact prevents us from
+ * using cpumask_var_t directly because the actual type of
+ * cpumsak_var_t depends on kernel configuration(particularly on
+ * CONFIG_CPUMASK_OFFSTACK macro). Depending on the configuration
+ * cpumask_var_t may be either a pointer to the struct cpumask
+ * or a variable allocated on the stack. Thus we can not safely use
+ * cpumask_var_t with RCU operations such as rcu_assign_pointer or
+ * rcu_dereference. So cpumask_var_t is wrapped with struct
+ * pcrypt_cpumask which makes possible to use it with RCU.
+ */
+ struct pcrypt_cpumask {
+ cpumask_var_t mask;
+ } *cb_cpumask;
+ struct notifier_block nblock;
+};
+
+static struct padata_pcrypt pencrypt;
+static struct padata_pcrypt pdecrypt;
+static struct kset *pcrypt_kset;
struct pcrypt_instance_ctx {
struct crypto_spawn spawn;
@@ -42,25 +70,32 @@ struct pcrypt_aead_ctx {
};
static int pcrypt_do_parallel(struct padata_priv *padata, unsigned int *cb_cpu,
- struct padata_instance *pinst)
+ struct padata_pcrypt *pcrypt)
{
unsigned int cpu_index, cpu, i;
+ struct pcrypt_cpumask *cpumask;
cpu = *cb_cpu;
- if (cpumask_test_cpu(cpu, cpu_active_mask))
+ rcu_read_lock_bh();
+ cpumask = rcu_dereference(pcrypt->cb_cpumask);
+ if (cpumask_test_cpu(cpu, cpumask->mask))
+ goto out;
+
+ if (!cpumask_weight(cpumask->mask))
goto out;
- cpu_index = cpu % cpumask_weight(cpu_active_mask);
+ cpu_index = cpu % cpumask_weight(cpumask->mask);
- cpu = cpumask_first(cpu_active_mask);
+ cpu = cpumask_first(cpumask->mask);
for (i = 0; i < cpu_index; i++)
- cpu = cpumask_next(cpu, cpu_active_mask);
+ cpu = cpumask_next(cpu, cpumask->mask);
*cb_cpu = cpu;
out:
- return padata_do_parallel(pinst, padata, cpu);
+ rcu_read_unlock_bh();
+ return padata_do_parallel(pcrypt->pinst, padata, cpu);
}
static int pcrypt_aead_setkey(struct crypto_aead *parent,
@@ -142,11 +177,9 @@ static int pcrypt_aead_encrypt(struct aead_request *req)
req->cryptlen, req->iv);
aead_request_set_assoc(creq, req->assoc, req->assoclen);
- err = pcrypt_do_parallel(padata, &ctx->cb_cpu, pcrypt_enc_padata);
- if (err)
- return err;
- else
- err = crypto_aead_encrypt(creq);
+ err = pcrypt_do_parallel(padata, &ctx->cb_cpu, &pencrypt);
+ if (!err)
+ return -EINPROGRESS;
return err;
}
@@ -186,11 +219,9 @@ static int pcrypt_aead_decrypt(struct aead_request *req)
req->cryptlen, req->iv);
aead_request_set_assoc(creq, req->assoc, req->assoclen);
- err = pcrypt_do_parallel(padata, &ctx->cb_cpu, pcrypt_dec_padata);
- if (err)
- return err;
- else
- err = crypto_aead_decrypt(creq);
+ err = pcrypt_do_parallel(padata, &ctx->cb_cpu, &pdecrypt);
+ if (!err)
+ return -EINPROGRESS;
return err;
}
@@ -232,11 +263,9 @@ static int pcrypt_aead_givencrypt(struct aead_givcrypt_request *req)
aead_givcrypt_set_assoc(creq, areq->assoc, areq->assoclen);
aead_givcrypt_set_giv(creq, req->giv, req->seq);
- err = pcrypt_do_parallel(padata, &ctx->cb_cpu, pcrypt_enc_padata);
- if (err)
- return err;
- else
- err = crypto_aead_givencrypt(creq);
+ err = pcrypt_do_parallel(padata, &ctx->cb_cpu, &pencrypt);
+ if (!err)
+ return -EINPROGRESS;
return err;
}
@@ -376,6 +405,115 @@ static void pcrypt_free(struct crypto_instance *inst)
kfree(inst);
}
+static int pcrypt_cpumask_change_notify(struct notifier_block *self,
+ unsigned long val, void *data)
+{
+ struct padata_pcrypt *pcrypt;
+ struct pcrypt_cpumask *new_mask, *old_mask;
+ struct padata_cpumask *cpumask = (struct padata_cpumask *)data;
+
+ if (!(val & PADATA_CPU_SERIAL))
+ return 0;
+
+ pcrypt = container_of(self, struct padata_pcrypt, nblock);
+ new_mask = kmalloc(sizeof(*new_mask), GFP_KERNEL);
+ if (!new_mask)
+ return -ENOMEM;
+ if (!alloc_cpumask_var(&new_mask->mask, GFP_KERNEL)) {
+ kfree(new_mask);
+ return -ENOMEM;
+ }
+
+ old_mask = pcrypt->cb_cpumask;
+
+ cpumask_copy(new_mask->mask, cpumask->cbcpu);
+ rcu_assign_pointer(pcrypt->cb_cpumask, new_mask);
+ synchronize_rcu_bh();
+
+ free_cpumask_var(old_mask->mask);
+ kfree(old_mask);
+ return 0;
+}
+
+static int pcrypt_sysfs_add(struct padata_instance *pinst, const char *name)
+{
+ int ret;
+
+ pinst->kobj.kset = pcrypt_kset;
+ ret = kobject_add(&pinst->kobj, NULL, name);
+ if (!ret)
+ kobject_uevent(&pinst->kobj, KOBJ_ADD);
+
+ return ret;
+}
+
+static int pcrypt_init_padata(struct padata_pcrypt *pcrypt,
+ const char *name)
+{
+ int ret = -ENOMEM;
+ struct pcrypt_cpumask *mask;
+
+ get_online_cpus();
+
+ pcrypt->wq = create_workqueue(name);
+ if (!pcrypt->wq)
+ goto err;
+
+ pcrypt->pinst = padata_alloc_possible(pcrypt->wq);
+ if (!pcrypt->pinst)
+ goto err_destroy_workqueue;
+
+ mask = kmalloc(sizeof(*mask), GFP_KERNEL);
+ if (!mask)
+ goto err_free_padata;
+ if (!alloc_cpumask_var(&mask->mask, GFP_KERNEL)) {
+ kfree(mask);
+ goto err_free_padata;
+ }
+
+ cpumask_and(mask->mask, cpu_possible_mask, cpu_active_mask);
+ rcu_assign_pointer(pcrypt->cb_cpumask, mask);
+
+ pcrypt->nblock.notifier_call = pcrypt_cpumask_change_notify;
+ ret = padata_register_cpumask_notifier(pcrypt->pinst, &pcrypt->nblock);
+ if (ret)
+ goto err_free_cpumask;
+
+ ret = pcrypt_sysfs_add(pcrypt->pinst, name);
+ if (ret)
+ goto err_unregister_notifier;
+
+ put_online_cpus();
+
+ return ret;
+
+err_unregister_notifier:
+ padata_unregister_cpumask_notifier(pcrypt->pinst, &pcrypt->nblock);
+err_free_cpumask:
+ free_cpumask_var(mask->mask);
+ kfree(mask);
+err_free_padata:
+ padata_free(pcrypt->pinst);
+err_destroy_workqueue:
+ destroy_workqueue(pcrypt->wq);
+err:
+ put_online_cpus();
+
+ return ret;
+}
+
+static void pcrypt_fini_padata(struct padata_pcrypt *pcrypt)
+{
+ kobject_put(&pcrypt->pinst->kobj);
+ free_cpumask_var(pcrypt->cb_cpumask->mask);
+ kfree(pcrypt->cb_cpumask);
+
+ padata_stop(pcrypt->pinst);
+ padata_unregister_cpumask_notifier(pcrypt->pinst, &pcrypt->nblock);
+ destroy_workqueue(pcrypt->wq);
+ padata_free(pcrypt->pinst);
+}
+
static struct crypto_template pcrypt_tmpl = {
.name = "pcrypt",
.alloc = pcrypt_alloc,
@@ -385,52 +523,39 @@ static struct crypto_template pcrypt_tmpl = {
static int __init pcrypt_init(void)
{
- encwq = create_workqueue("pencrypt");
- if (!encwq)
- goto err;
-
- decwq = create_workqueue("pdecrypt");
- if (!decwq)
- goto err_destroy_encwq;
+ int err = -ENOMEM;
+ pcrypt_kset = kset_create_and_add("pcrypt", NULL, kernel_kobj);
+ if (!pcrypt_kset)
+ goto err;
- pcrypt_enc_padata = padata_alloc(cpu_possible_mask, encwq);
- if (!pcrypt_enc_padata)
- goto err_destroy_decwq;
+ err = pcrypt_init_padata(&pencrypt, "pencrypt");
+ if (err)
+ goto err_unreg_kset;
- pcrypt_dec_padata = padata_alloc(cpu_possible_mask, decwq);
- if (!pcrypt_dec_padata)
- goto err_free_padata;
+ err = pcrypt_init_padata(&pdecrypt, "pdecrypt");
+ if (err)
+ goto err_deinit_pencrypt;
- padata_start(pcrypt_enc_padata);
- padata_start(pcrypt_dec_padata);
+ padata_start(pencrypt.pinst);
+ padata_start(pdecrypt.pinst);
return crypto_register_template(&pcrypt_tmpl);
-err_free_padata:
- padata_free(pcrypt_enc_padata);
-
-err_destroy_decwq:
- destroy_workqueue(decwq);
-
-err_destroy_encwq:
- destroy_workqueue(encwq);
-
+err_deinit_pencrypt:
+ pcrypt_fini_padata(&pencrypt);
+err_unreg_kset:
+ kset_unregister(pcrypt_kset);
err:
- return -ENOMEM;
+ return err;
}
static void __exit pcrypt_exit(void)
{
- padata_stop(pcrypt_enc_padata);
- padata_stop(pcrypt_dec_padata);
-
- destroy_workqueue(encwq);
- destroy_workqueue(decwq);
-
- padata_free(pcrypt_enc_padata);
- padata_free(pcrypt_dec_padata);
+ pcrypt_fini_padata(&pencrypt);
+ pcrypt_fini_padata(&pdecrypt);
+ kset_unregister(pcrypt_kset);
crypto_unregister_template(&pcrypt_tmpl);
}
diff --git a/crypto/testmgr.c b/crypto/testmgr.c
index 5c8aaa0cb0b..abd980c729e 100644
--- a/crypto/testmgr.c
+++ b/crypto/testmgr.c
@@ -22,6 +22,17 @@
#include <crypto/rng.h>
#include "internal.h"
+
+#ifndef CONFIG_CRYPTO_MANAGER_TESTS
+
+/* a perfect nop */
+int alg_test(const char *driver, const char *alg, u32 type, u32 mask)
+{
+ return 0;
+}
+
+#else
+
#include "testmgr.h"
/*
@@ -2530,4 +2541,7 @@ notest:
non_fips_alg:
return -EINVAL;
}
+
+#endif /* CONFIG_CRYPTO_MANAGER_TESTS */
+
EXPORT_SYMBOL_GPL(alg_test);
diff --git a/crypto/twofish.c b/crypto/twofish_generic.c
index dfcda231f87..1f07b843e07 100644
--- a/crypto/twofish.c
+++ b/crypto/twofish_generic.c
@@ -212,3 +212,4 @@ module_exit(twofish_mod_fini);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION ("Twofish Cipher Algorithm");
+MODULE_ALIAS("twofish");
diff --git a/crypto/xts.c b/crypto/xts.c
index d87b0f3102c..555ecaab1e5 100644
--- a/crypto/xts.c
+++ b/crypto/xts.c
@@ -224,7 +224,7 @@ static struct crypto_instance *alloc(struct rtattr **tb)
alg = crypto_get_attr_alg(tb, CRYPTO_ALG_TYPE_CIPHER,
CRYPTO_ALG_TYPE_MASK);
if (IS_ERR(alg))
- return ERR_PTR(PTR_ERR(alg));
+ return ERR_CAST(alg);
inst = crypto_alloc_instance("xts", alg);
if (IS_ERR(inst))
diff --git a/drivers/Makefile b/drivers/Makefile
index 91874e04855..ae473445ad6 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -101,7 +101,9 @@ obj-y += firmware/
obj-$(CONFIG_CRYPTO) += crypto/
obj-$(CONFIG_SUPERH) += sh/
obj-$(CONFIG_ARCH_SHMOBILE) += sh/
-obj-$(CONFIG_GENERIC_TIME) += clocksource/
+ifndef CONFIG_ARCH_USES_GETTIMEOFFSET
+obj-y += clocksource/
+endif
obj-$(CONFIG_DMA_ENGINE) += dma/
obj-$(CONFIG_DCA) += dca/
obj-$(CONFIG_HID) += hid/
diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
index 74641151880..08e0140920e 100644
--- a/drivers/acpi/Kconfig
+++ b/drivers/acpi/Kconfig
@@ -104,6 +104,24 @@ config ACPI_SYSFS_POWER
help
Say N to disable power /sys interface
+config ACPI_EC_DEBUGFS
+ tristate "EC read/write access through /sys/kernel/debug/ec"
+ default n
+ help
+ Say N to disable Embedded Controller /sys/kernel/debug interface
+
+ Be aware that using this interface can confuse your Embedded
+ Controller in a way that a normal reboot is not enough. You then
+ have to power of your system, and remove the laptop battery for
+ some seconds.
+ An Embedded Controller typically is available on laptops and reads
+ sensor values like battery state and temperature.
+ The kernel accesses the EC through ACPI parsed code provided by BIOS
+ tables. This option allows to access the EC directly without ACPI
+ code being involved.
+ Thus this option is a debug option that helps to write ACPI drivers
+ and can be used to identify ACPI code or EC firmware bugs.
+
config ACPI_PROC_EVENT
bool "Deprecated /proc/acpi/event support"
depends on PROC_FS
diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile
index 6ee33169e1d..833b582d176 100644
--- a/drivers/acpi/Makefile
+++ b/drivers/acpi/Makefile
@@ -60,6 +60,7 @@ obj-$(CONFIG_ACPI_SBS) += sbshc.o
obj-$(CONFIG_ACPI_SBS) += sbs.o
obj-$(CONFIG_ACPI_POWER_METER) += power_meter.o
obj-$(CONFIG_ACPI_HED) += hed.o
+obj-$(CONFIG_ACPI_EC_DEBUGFS) += ec_sys.o
# processor has its own "processor." module_param namespace
processor-y := processor_driver.o processor_throttling.o
diff --git a/drivers/acpi/acpi_pad.c b/drivers/acpi/acpi_pad.c
index 446aced33af..b76848c80be 100644
--- a/drivers/acpi/acpi_pad.c
+++ b/drivers/acpi/acpi_pad.c
@@ -77,7 +77,7 @@ static void power_saving_mwait_init(void)
power_saving_mwait_eax = (highest_cstate << MWAIT_SUBSTATE_SIZE) |
(highest_subcstate - 1);
-#if defined(CONFIG_GENERIC_TIME) && defined(CONFIG_X86)
+#if defined(CONFIG_X86)
switch (boot_cpu_data.x86_vendor) {
case X86_VENDOR_AMD:
case X86_VENDOR_INTEL:
diff --git a/drivers/acpi/acpica/acevents.h b/drivers/acpi/acpica/acevents.h
index c3f43daa8be..e0e6affb0d8 100644
--- a/drivers/acpi/acpica/acevents.h
+++ b/drivers/acpi/acpica/acevents.h
@@ -78,7 +78,9 @@ acpi_ev_queue_notify_request(struct acpi_namespace_node *node,
u32 acpi_ev_gpe_detect(struct acpi_gpe_xrupt_info *gpe_xrupt_list);
acpi_status
-acpi_ev_update_gpe_enable_masks(struct acpi_gpe_event_info *gpe_event_info);
+acpi_ev_update_gpe_enable_mask(struct acpi_gpe_event_info *gpe_event_info);
+
+acpi_status acpi_ev_enable_gpe(struct acpi_gpe_event_info *gpe_event_info);
struct acpi_gpe_event_info *acpi_ev_get_gpe_event_info(acpi_handle gpe_device,
u32 gpe_number);
diff --git a/drivers/acpi/acpica/acglobal.h b/drivers/acpi/acpica/acglobal.h
index 899d68afc3c..18e796fe429 100644
--- a/drivers/acpi/acpica/acglobal.h
+++ b/drivers/acpi/acpica/acglobal.h
@@ -100,13 +100,6 @@ u8 ACPI_INIT_GLOBAL(acpi_gbl_all_methods_serialized, FALSE);
u8 ACPI_INIT_GLOBAL(acpi_gbl_create_osi_method, TRUE);
/*
- * Disable wakeup GPEs during runtime? Default is TRUE because WAKE and
- * RUNTIME GPEs should never be shared, and WAKE GPEs should typically only
- * be enabled just before going to sleep.
- */
-u8 ACPI_INIT_GLOBAL(acpi_gbl_leave_wake_gpes_disabled, TRUE);
-
-/*
* Optionally use default values for the ACPI register widths. Set this to
* TRUE to use the defaults, if an FADT contains incorrect widths/lengths.
*/
diff --git a/drivers/acpi/acpica/achware.h b/drivers/acpi/acpica/achware.h
index 32391588e16..120b3af5659 100644
--- a/drivers/acpi/acpica/achware.h
+++ b/drivers/acpi/acpica/achware.h
@@ -90,16 +90,13 @@ acpi_status acpi_hw_write_port(acpi_io_address address, u32 value, u32 width);
/*
* hwgpe - GPE support
*/
-u32 acpi_hw_gpe_register_bit(struct acpi_gpe_event_info *gpe_event_info,
+u32 acpi_hw_get_gpe_register_bit(struct acpi_gpe_event_info *gpe_event_info,
struct acpi_gpe_register_info *gpe_register_info);
acpi_status
acpi_hw_low_set_gpe(struct acpi_gpe_event_info *gpe_event_info, u8 action);
acpi_status
-acpi_hw_write_gpe_enable_reg(struct acpi_gpe_event_info *gpe_event_info);
-
-acpi_status
acpi_hw_disable_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info,
struct acpi_gpe_block_info *gpe_block, void *context);
diff --git a/drivers/acpi/acpica/aclocal.h b/drivers/acpi/acpica/aclocal.h
index 147a7e6bd38..1ee0bcf399a 100644
--- a/drivers/acpi/acpica/aclocal.h
+++ b/drivers/acpi/acpica/aclocal.h
@@ -184,8 +184,9 @@ struct acpi_namespace_node {
u8 flags; /* Miscellaneous flags */
acpi_owner_id owner_id; /* Node creator */
union acpi_name_union name; /* ACPI Name, always 4 chars per ACPI spec */
+ struct acpi_namespace_node *parent; /* Parent node */
struct acpi_namespace_node *child; /* First child */
- struct acpi_namespace_node *peer; /* Peer. Parent if ANOBJ_END_OF_PEER_LIST set */
+ struct acpi_namespace_node *peer; /* First peer */
/*
* The following fields are used by the ASL compiler and disassembler only
@@ -199,7 +200,7 @@ struct acpi_namespace_node {
/* Namespace Node flags */
-#define ANOBJ_END_OF_PEER_LIST 0x01 /* End-of-list, Peer field points to parent */
+#define ANOBJ_RESERVED 0x01 /* Available for use */
#define ANOBJ_TEMPORARY 0x02 /* Node is create by a method and is temporary */
#define ANOBJ_METHOD_ARG 0x04 /* Node is a method argument */
#define ANOBJ_METHOD_LOCAL 0x08 /* Node is a method local */
@@ -428,7 +429,6 @@ struct acpi_gpe_event_info {
u8 flags; /* Misc info about this GPE */
u8 gpe_number; /* This GPE */
u8 runtime_count; /* References to a run GPE */
- u8 wakeup_count; /* References to a wake GPE */
};
/* Information about a GPE register pair, one per each status/enable pair in an array */
diff --git a/drivers/acpi/acpica/acnamesp.h b/drivers/acpi/acpica/acnamesp.h
index 258159cfcdf..9f60ff00220 100644
--- a/drivers/acpi/acpica/acnamesp.h
+++ b/drivers/acpi/acpica/acnamesp.h
@@ -369,11 +369,4 @@ struct acpi_namespace_node *acpi_ns_validate_handle(acpi_handle handle);
void acpi_ns_terminate(void);
-struct acpi_namespace_node *acpi_ns_get_parent_node(struct acpi_namespace_node
- *node);
-
-struct acpi_namespace_node *acpi_ns_get_next_valid_node(struct
- acpi_namespace_node
- *node);
-
#endif /* __ACNAMESP_H__ */
diff --git a/drivers/acpi/acpica/acobject.h b/drivers/acpi/acpica/acobject.h
index cde18ea8265..54857fa87aa 100644
--- a/drivers/acpi/acpica/acobject.h
+++ b/drivers/acpi/acpica/acobject.h
@@ -91,14 +91,14 @@
/* Values for Flag byte above */
-#define AOPOBJ_AML_CONSTANT 0x01
-#define AOPOBJ_STATIC_POINTER 0x02
-#define AOPOBJ_DATA_VALID 0x04
-#define AOPOBJ_OBJECT_INITIALIZED 0x08
-#define AOPOBJ_SETUP_COMPLETE 0x10
-#define AOPOBJ_SINGLE_DATUM 0x20
-#define AOPOBJ_INVALID 0x40 /* Used if host OS won't allow an op_region address */
-#define AOPOBJ_MODULE_LEVEL 0x80
+#define AOPOBJ_AML_CONSTANT 0x01 /* Integer is an AML constant */
+#define AOPOBJ_STATIC_POINTER 0x02 /* Data is part of an ACPI table, don't delete */
+#define AOPOBJ_DATA_VALID 0x04 /* Object is intialized and data is valid */
+#define AOPOBJ_OBJECT_INITIALIZED 0x08 /* Region is initialized, _REG was run */
+#define AOPOBJ_SETUP_COMPLETE 0x10 /* Region setup is complete */
+#define AOPOBJ_INVALID 0x20 /* Host OS won't allow a Region address */
+#define AOPOBJ_MODULE_LEVEL 0x40 /* Method is actually module-level code */
+#define AOPOBJ_MODIFIED_NAMESPACE 0x80 /* Method modified the namespace */
/******************************************************************************
*
diff --git a/drivers/acpi/acpica/acpredef.h b/drivers/acpi/acpica/acpredef.h
index 97116082cb6..10998d369ad 100644
--- a/drivers/acpi/acpica/acpredef.h
+++ b/drivers/acpi/acpica/acpredef.h
@@ -503,15 +503,16 @@ static const union acpi_predefined_info predefined_names[] =
{{"_WAK", 1, ACPI_RTYPE_NONE | ACPI_RTYPE_INTEGER | ACPI_RTYPE_PACKAGE}},
{{{ACPI_PTYPE1_FIXED, ACPI_RTYPE_INTEGER, 2,0}, 0,0}}, /* Fixed-length (2 Int), but is optional */
- {{{0,0,0,0}, 0,0}} /* Table terminator */
-};
+ /* _WDG/_WED are MS extensions defined by "Windows Instrumentation" */
-#if 0
- /* Not implemented */
+ {{"_WDG", 0, ACPI_RTYPE_BUFFER}},
+ {{"_WED", 1,
+ ACPI_RTYPE_INTEGER | ACPI_RTYPE_STRING | ACPI_RTYPE_BUFFER}},
- {{"_WDG", 0, ACPI_RTYPE_BUFFER}}, /* MS Extension */
- {{"_WED", 1, ACPI_RTYPE_PACKAGE}}, /* MS Extension */
+ {{{0, 0, 0, 0}, 0, 0}} /* Table terminator */
+};
+#if 0
/* This is an internally implemented control method, no need to check */
{{"_OSI", 1, ACPI_RTYPE_INTEGER}},
diff --git a/drivers/acpi/acpica/acstruct.h b/drivers/acpi/acpica/acstruct.h
index 161bc0e3d70..6e5dd97949f 100644
--- a/drivers/acpi/acpica/acstruct.h
+++ b/drivers/acpi/acpica/acstruct.h
@@ -127,22 +127,22 @@ struct acpi_walk_state {
acpi_parse_upwards ascending_callback;
};
-/* Info used by acpi_ps_init_objects */
+/* Info used by acpi_ns_initialize_objects and acpi_ds_initialize_objects */
struct acpi_init_walk_info {
- u16 method_count;
- u16 device_count;
- u16 op_region_count;
- u16 field_count;
- u16 buffer_count;
- u16 package_count;
- u16 op_region_init;
- u16 field_init;
- u16 buffer_init;
- u16 package_init;
- u16 object_count;
- acpi_owner_id owner_id;
u32 table_index;
+ u32 object_count;
+ u32 method_count;
+ u32 device_count;
+ u32 op_region_count;
+ u32 field_count;
+ u32 buffer_count;
+ u32 package_count;
+ u32 op_region_init;
+ u32 field_init;
+ u32 buffer_init;
+ u32 package_init;
+ acpi_owner_id owner_id;
};
struct acpi_get_devices_info {
@@ -201,11 +201,11 @@ struct acpi_evaluate_info {
/* Info used by acpi_ns_initialize_devices */
struct acpi_device_walk_info {
- u16 device_count;
- u16 num_STA;
- u16 num_INI;
struct acpi_table_desc *table_desc;
struct acpi_evaluate_info *evaluate_info;
+ u32 device_count;
+ u32 num_STA;
+ u32 num_INI;
};
/* TBD: [Restructure] Merge with struct above */
diff --git a/drivers/acpi/acpica/dsinit.c b/drivers/acpi/acpica/dsinit.c
index abe140318a7..cc4a38c5755 100644
--- a/drivers/acpi/acpica/dsinit.c
+++ b/drivers/acpi/acpica/dsinit.c
@@ -171,12 +171,12 @@ acpi_ds_initialize_objects(u32 table_index,
"**** Starting initialization of namespace objects ****\n"));
ACPI_DEBUG_PRINT_RAW((ACPI_DB_INIT, "Parsing all Control Methods:"));
- info.method_count = 0;
- info.op_region_count = 0;
- info.object_count = 0;
- info.device_count = 0;
- info.table_index = table_index;
+ /* Set all init info to zero */
+
+ ACPI_MEMSET(&info, 0, sizeof(struct acpi_init_walk_info));
+
info.owner_id = owner_id;
+ info.table_index = table_index;
/* Walk entire namespace from the supplied root */
@@ -204,13 +204,13 @@ acpi_ds_initialize_objects(u32 table_index,
}
ACPI_DEBUG_PRINT_RAW((ACPI_DB_INIT,
- "\nTable [%4.4s](id %4.4X) - %hd Objects with %hd Devices %hd Methods %hd Regions\n",
+ "\nTable [%4.4s](id %4.4X) - %u Objects with %u Devices %u Methods %u Regions\n",
table->signature, owner_id, info.object_count,
info.device_count, info.method_count,
info.op_region_count));
ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
- "%hd Methods, %hd Regions\n", info.method_count,
+ "%u Methods, %u Regions\n", info.method_count,
info.op_region_count));
return_ACPI_STATUS(AE_OK);
diff --git a/drivers/acpi/acpica/dsmethod.c b/drivers/acpi/acpica/dsmethod.c
index 2a9a561c2f0..64750ee96e2 100644
--- a/drivers/acpi/acpica/dsmethod.c
+++ b/drivers/acpi/acpica/dsmethod.c
@@ -584,8 +584,22 @@ acpi_ds_terminate_control_method(union acpi_operand_object *method_desc,
* want make the objects permanent.
*/
if (!(method_desc->method.flags & AOPOBJ_MODULE_LEVEL)) {
- acpi_ns_delete_namespace_by_owner(method_desc->method.
- owner_id);
+
+ /* Delete any direct children of (created by) this method */
+
+ acpi_ns_delete_namespace_subtree(walk_state->
+ method_node);
+
+ /*
+ * Delete any objects that were created by this method
+ * elsewhere in the namespace (if any were created).
+ */
+ if (method_desc->method.
+ flags & AOPOBJ_MODIFIED_NAMESPACE) {
+ acpi_ns_delete_namespace_by_owner(method_desc->
+ method.
+ owner_id);
+ }
}
}
@@ -605,7 +619,7 @@ acpi_ds_terminate_control_method(union acpi_operand_object *method_desc,
* we immediately reuse it for the next thread executing this method
*/
ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
- "*** Completed execution of one thread, %d threads remaining\n",
+ "*** Completed execution of one thread, %u threads remaining\n",
method_desc->method.thread_count));
} else {
/* This is the only executing thread for this method */
diff --git a/drivers/acpi/acpica/dsmthdat.c b/drivers/acpi/acpica/dsmthdat.c
index f3d52f59250..8095306fcd8 100644
--- a/drivers/acpi/acpica/dsmthdat.c
+++ b/drivers/acpi/acpica/dsmthdat.c
@@ -102,8 +102,7 @@ void acpi_ds_method_data_init(struct acpi_walk_state *walk_state)
walk_state->arguments[i].name.integer |= (i << 24);
walk_state->arguments[i].descriptor_type = ACPI_DESC_TYPE_NAMED;
walk_state->arguments[i].type = ACPI_TYPE_ANY;
- walk_state->arguments[i].flags =
- ANOBJ_END_OF_PEER_LIST | ANOBJ_METHOD_ARG;
+ walk_state->arguments[i].flags = ANOBJ_METHOD_ARG;
}
/* Init the method locals */
@@ -116,8 +115,7 @@ void acpi_ds_method_data_init(struct acpi_walk_state *walk_state)
walk_state->local_variables[i].descriptor_type =
ACPI_DESC_TYPE_NAMED;
walk_state->local_variables[i].type = ACPI_TYPE_ANY;
- walk_state->local_variables[i].flags =
- ANOBJ_END_OF_PEER_LIST | ANOBJ_METHOD_LOCAL;
+ walk_state->local_variables[i].flags = ANOBJ_METHOD_LOCAL;
}
return_VOID;
@@ -146,7 +144,7 @@ void acpi_ds_method_data_delete_all(struct acpi_walk_state *walk_state)
for (index = 0; index < ACPI_METHOD_NUM_LOCALS; index++) {
if (walk_state->local_variables[index].object) {
- ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Deleting Local%d=%p\n",
+ ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Deleting Local%u=%p\n",
index,
walk_state->local_variables[index].
object));
@@ -162,7 +160,7 @@ void acpi_ds_method_data_delete_all(struct acpi_walk_state *walk_state)
for (index = 0; index < ACPI_METHOD_NUM_ARGS; index++) {
if (walk_state->arguments[index].object) {
- ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Deleting Arg%d=%p\n",
+ ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Deleting Arg%u=%p\n",
index,
walk_state->arguments[index].object));
@@ -226,7 +224,7 @@ acpi_ds_method_data_init_args(union acpi_operand_object **params,
index++;
}
- ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "%d args passed to method\n", index));
+ ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "%u args passed to method\n", index));
return_ACPI_STATUS(AE_OK);
}
@@ -323,7 +321,7 @@ acpi_ds_method_data_set_value(u8 type,
ACPI_FUNCTION_TRACE(ds_method_data_set_value);
ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
- "NewObj %p Type %2.2X, Refs=%d [%s]\n", object,
+ "NewObj %p Type %2.2X, Refs=%u [%s]\n", object,
type, object->common.reference_count,
acpi_ut_get_type_name(object->common.type)));
@@ -543,7 +541,7 @@ acpi_ds_store_object_to_local(u8 type,
union acpi_operand_object *new_obj_desc;
ACPI_FUNCTION_TRACE(ds_store_object_to_local);
- ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Type=%2.2X Index=%d Obj=%p\n",
+ ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Type=%2.2X Index=%u Obj=%p\n",
type, index, obj_desc));
/* Parameter validation */
diff --git a/drivers/acpi/acpica/dsobject.c b/drivers/acpi/acpica/dsobject.c
index 3607adcaf08..8e85f54a8e0 100644
--- a/drivers/acpi/acpica/dsobject.c
+++ b/drivers/acpi/acpica/dsobject.c
@@ -81,6 +81,7 @@ acpi_ds_build_internal_object(struct acpi_walk_state *walk_state,
{
union acpi_operand_object *obj_desc;
acpi_status status;
+ acpi_object_type type;
ACPI_FUNCTION_TRACE(ds_build_internal_object);
@@ -172,7 +173,20 @@ acpi_ds_build_internal_object(struct acpi_walk_state *walk_state,
return_ACPI_STATUS(status);
}
- switch (op->common.node->type) {
+ /*
+ * Special handling for Alias objects. We need to setup the type
+ * and the Op->Common.Node to point to the Alias target. Note,
+ * Alias has at most one level of indirection internally.
+ */
+ type = op->common.node->type;
+ if (type == ACPI_TYPE_LOCAL_ALIAS) {
+ type = obj_desc->common.type;
+ op->common.node =
+ ACPI_CAST_PTR(struct acpi_namespace_node,
+ op->common.node->object);
+ }
+
+ switch (type) {
/*
* For these types, we need the actual node, not the subobject.
* However, the subobject did not get an extra reference count above.
diff --git a/drivers/acpi/acpica/dsopcode.c b/drivers/acpi/acpica/dsopcode.c
index 53a7e416f33..7c0e7422717 100644
--- a/drivers/acpi/acpica/dsopcode.c
+++ b/drivers/acpi/acpica/dsopcode.c
@@ -213,7 +213,7 @@ acpi_ds_get_buffer_field_arguments(union acpi_operand_object *obj_desc)
/* Execute the AML code for the term_arg arguments */
- status = acpi_ds_execute_arguments(node, acpi_ns_get_parent_node(node),
+ status = acpi_ds_execute_arguments(node, node->parent,
extra_desc->extra.aml_length,
extra_desc->extra.aml_start);
return_ACPI_STATUS(status);
@@ -257,7 +257,7 @@ acpi_ds_get_bank_field_arguments(union acpi_operand_object *obj_desc)
/* Execute the AML code for the term_arg arguments */
- status = acpi_ds_execute_arguments(node, acpi_ns_get_parent_node(node),
+ status = acpi_ds_execute_arguments(node, node->parent,
extra_desc->extra.aml_length,
extra_desc->extra.aml_start);
return_ACPI_STATUS(status);
@@ -394,7 +394,7 @@ acpi_status acpi_ds_get_region_arguments(union acpi_operand_object *obj_desc)
/* Execute the argument AML */
- status = acpi_ds_execute_arguments(node, acpi_ns_get_parent_node(node),
+ status = acpi_ds_execute_arguments(node, node->parent,
extra_desc->extra.aml_length,
extra_desc->extra.aml_start);
if (ACPI_FAILURE(status)) {
diff --git a/drivers/acpi/acpica/dsutils.c b/drivers/acpi/acpica/dsutils.c
index 306c62ab2e8..15135c25aa9 100644
--- a/drivers/acpi/acpica/dsutils.c
+++ b/drivers/acpi/acpica/dsutils.c
@@ -746,7 +746,7 @@ acpi_ds_create_operands(struct acpi_walk_state *walk_state,
index--;
ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
- "Arg #%d (%p) done, Arg1=%p\n", index, arg,
+ "Arg #%u (%p) done, Arg1=%p\n", index, arg,
first_arg));
}
@@ -760,7 +760,7 @@ acpi_ds_create_operands(struct acpi_walk_state *walk_state,
*/
acpi_ds_obj_stack_pop_and_delete(arg_count, walk_state);
- ACPI_EXCEPTION((AE_INFO, status, "While creating Arg %d", index));
+ ACPI_EXCEPTION((AE_INFO, status, "While creating Arg %u", index));
return_ACPI_STATUS(status);
}
diff --git a/drivers/acpi/acpica/evevent.c b/drivers/acpi/acpica/evevent.c
index f5795915a2e..303618889da 100644
--- a/drivers/acpi/acpica/evevent.c
+++ b/drivers/acpi/acpica/evevent.c
@@ -102,9 +102,8 @@ acpi_status acpi_ev_initialize_events(void)
* RETURN: Status
*
* DESCRIPTION: Completes initialization of the FADT-defined GPE blocks
- * (0 and 1). This causes the _PRW methods to be run, so the HW
- * must be fully initialized at this point, including global lock
- * support.
+ * (0 and 1). The HW must be fully initialized at this point,
+ * including global lock support.
*
******************************************************************************/
diff --git a/drivers/acpi/acpica/evgpe.c b/drivers/acpi/acpica/evgpe.c
index 7c2c336006a..7a6a3e6f4be 100644
--- a/drivers/acpi/acpica/evgpe.c
+++ b/drivers/acpi/acpica/evgpe.c
@@ -54,49 +54,84 @@ static void ACPI_SYSTEM_XFACE acpi_ev_asynch_execute_gpe_method(void *context);
/*******************************************************************************
*
- * FUNCTION: acpi_ev_update_gpe_enable_masks
+ * FUNCTION: acpi_ev_update_gpe_enable_mask
*
* PARAMETERS: gpe_event_info - GPE to update
*
* RETURN: Status
*
- * DESCRIPTION: Updates GPE register enable masks based upon whether there are
- * references (either wake or run) to this GPE
+ * DESCRIPTION: Updates GPE register enable mask based upon whether there are
+ * runtime references to this GPE
*
******************************************************************************/
acpi_status
-acpi_ev_update_gpe_enable_masks(struct acpi_gpe_event_info *gpe_event_info)
+acpi_ev_update_gpe_enable_mask(struct acpi_gpe_event_info *gpe_event_info)
{
struct acpi_gpe_register_info *gpe_register_info;
u32 register_bit;
- ACPI_FUNCTION_TRACE(ev_update_gpe_enable_masks);
+ ACPI_FUNCTION_TRACE(ev_update_gpe_enable_mask);
gpe_register_info = gpe_event_info->register_info;
if (!gpe_register_info) {
return_ACPI_STATUS(AE_NOT_EXIST);
}
- register_bit = acpi_hw_gpe_register_bit(gpe_event_info,
+ register_bit = acpi_hw_get_gpe_register_bit(gpe_event_info,
gpe_register_info);
- /* Clear the wake/run bits up front */
+ /* Clear the run bit up front */
- ACPI_CLEAR_BIT(gpe_register_info->enable_for_wake, register_bit);
ACPI_CLEAR_BIT(gpe_register_info->enable_for_run, register_bit);
- /* Set the mask bits only if there are references to this GPE */
+ /* Set the mask bit only if there are references to this GPE */
if (gpe_event_info->runtime_count) {
- ACPI_SET_BIT(gpe_register_info->enable_for_run, register_bit);
+ ACPI_SET_BIT(gpe_register_info->enable_for_run, (u8)register_bit);
}
- if (gpe_event_info->wakeup_count) {
- ACPI_SET_BIT(gpe_register_info->enable_for_wake, register_bit);
+ return_ACPI_STATUS(AE_OK);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ev_enable_gpe
+ *
+ * PARAMETERS: gpe_event_info - GPE to enable
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Clear the given GPE from stale events and enable it.
+ *
+ ******************************************************************************/
+acpi_status
+acpi_ev_enable_gpe(struct acpi_gpe_event_info *gpe_event_info)
+{
+ acpi_status status;
+
+ ACPI_FUNCTION_TRACE(ev_enable_gpe);
+
+ /*
+ * We will only allow a GPE to be enabled if it has either an
+ * associated method (_Lxx/_Exx) or a handler. Otherwise, the
+ * GPE will be immediately disabled by acpi_ev_gpe_dispatch the
+ * first time it fires.
+ */
+ if (!(gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK)) {
+ return_ACPI_STATUS(AE_NO_HANDLER);
}
- return_ACPI_STATUS(AE_OK);
+ /* Clear the GPE (of stale events) */
+ status = acpi_hw_clear_gpe(gpe_event_info);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
+
+ /* Enable the requested GPE */
+ status = acpi_hw_low_set_gpe(gpe_event_info, ACPI_GPE_ENABLE);
+
+ return_ACPI_STATUS(status);
}
@@ -417,8 +452,12 @@ static void acpi_ev_asynch_enable_gpe(void *context)
}
}
- /* Enable this GPE */
- (void)acpi_hw_write_gpe_enable_reg(gpe_event_info);
+ /*
+ * Enable this GPE, conditionally. This means that the GPE will only be
+ * physically enabled if the enable_for_run bit is set in the event_info
+ */
+ (void)acpi_hw_low_set_gpe(gpe_event_info, ACPI_GPE_COND_ENABLE);
+
return_VOID;
}
diff --git a/drivers/acpi/acpica/evgpeblk.c b/drivers/acpi/acpica/evgpeblk.c
index 341a38ce8aa..85445fb5844 100644
--- a/drivers/acpi/acpica/evgpeblk.c
+++ b/drivers/acpi/acpica/evgpeblk.c
@@ -439,8 +439,6 @@ acpi_ev_initialize_gpe_block(struct acpi_namespace_node *gpe_device,
{
acpi_status status;
struct acpi_gpe_event_info *gpe_event_info;
- struct acpi_gpe_walk_info walk_info;
- u32 wake_gpe_count;
u32 gpe_enabled_count;
u32 gpe_index;
u32 gpe_number;
@@ -456,37 +454,9 @@ acpi_ev_initialize_gpe_block(struct acpi_namespace_node *gpe_device,
}
/*
- * Runtime option: Should wake GPEs be enabled at runtime? The default
- * is no, they should only be enabled just as the machine goes to sleep.
+ * Enable all GPEs that have a corresponding method. Any other GPEs
+ * within this block must be enabled via the acpi_enable_gpe interface.
*/
- if (acpi_gbl_leave_wake_gpes_disabled) {
- /*
- * Differentiate runtime vs wake GPEs, via the _PRW control methods.
- * Each GPE that has one or more _PRWs that reference it is by
- * definition a wake GPE and will not be enabled while the machine
- * is running.
- */
- walk_info.gpe_block = gpe_block;
- walk_info.gpe_device = gpe_device;
- walk_info.execute_by_owner_id = FALSE;
-
- status =
- acpi_ns_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
- ACPI_UINT32_MAX, ACPI_NS_WALK_UNLOCK,
- acpi_ev_match_prw_and_gpe, NULL,
- &walk_info, NULL);
- if (ACPI_FAILURE(status)) {
- ACPI_EXCEPTION((AE_INFO, status,
- "While executing _PRW methods"));
- }
- }
-
- /*
- * Enable all GPEs that have a corresponding method and are not
- * capable of generating wakeups. Any other GPEs within this block
- * must be enabled via the acpi_enable_gpe interface.
- */
- wake_gpe_count = 0;
gpe_enabled_count = 0;
if (gpe_device == acpi_gbl_fadt_gpe_device) {
@@ -502,35 +472,21 @@ acpi_ev_initialize_gpe_block(struct acpi_namespace_node *gpe_device,
gpe_event_info = &gpe_block->event_info[gpe_index];
gpe_number = gpe_index + gpe_block->block_base_number;
- /*
- * If the GPE has already been enabled for runtime
- * signaling, make sure it remains enabled, but do not
- * increment its reference counter.
- */
- if (gpe_event_info->runtime_count) {
- acpi_set_gpe(gpe_device, gpe_number,
- ACPI_GPE_ENABLE);
- gpe_enabled_count++;
- continue;
- }
-
- if (gpe_event_info->flags & ACPI_GPE_CAN_WAKE) {
- wake_gpe_count++;
- if (acpi_gbl_leave_wake_gpes_disabled) {
- continue;
- }
- }
-
/* Ignore GPEs that have no corresponding _Lxx/_Exx method */
if (!(gpe_event_info->flags & ACPI_GPE_DISPATCH_METHOD)) {
continue;
}
- /* Enable this GPE */
+ /*
+ * If the GPE has already been enabled for runtime
+ * signaling, make sure it remains enabled, but do not
+ * increment its reference counter.
+ */
+ status = gpe_event_info->runtime_count ?
+ acpi_ev_enable_gpe(gpe_event_info) :
+ acpi_enable_gpe(gpe_device, gpe_number);
- status = acpi_enable_gpe(gpe_device, gpe_number,
- ACPI_GPE_TYPE_RUNTIME);
if (ACPI_FAILURE(status)) {
ACPI_EXCEPTION((AE_INFO, status,
"Could not enable GPE 0x%02X",
@@ -542,10 +498,10 @@ acpi_ev_initialize_gpe_block(struct acpi_namespace_node *gpe_device,
}
}
- if (gpe_enabled_count || wake_gpe_count) {
+ if (gpe_enabled_count) {
ACPI_DEBUG_PRINT((ACPI_DB_INIT,
- "Enabled %u Runtime GPEs, added %u Wake GPEs in this block\n",
- gpe_enabled_count, wake_gpe_count));
+ "Enabled %u GPEs in this block\n",
+ gpe_enabled_count));
}
return_ACPI_STATUS(AE_OK);
diff --git a/drivers/acpi/acpica/evgpeinit.c b/drivers/acpi/acpica/evgpeinit.c
index 3f6c2d26410..3084c5de1bb 100644
--- a/drivers/acpi/acpica/evgpeinit.c
+++ b/drivers/acpi/acpica/evgpeinit.c
@@ -211,9 +211,7 @@ acpi_status acpi_ev_gpe_initialize(void)
* DESCRIPTION: Check for new GPE methods (_Lxx/_Exx) made available as a
* result of a Load() or load_table() operation. If new GPE
* methods have been installed, register the new methods and
- * enable and runtime GPEs that are associated with them. Also,
- * run any newly loaded _PRW methods in order to discover any
- * new CAN_WAKE GPEs.
+ * enable and runtime GPEs that are associated with them.
*
******************************************************************************/
@@ -223,49 +221,12 @@ void acpi_ev_update_gpes(acpi_owner_id table_owner_id)
struct acpi_gpe_block_info *gpe_block;
struct acpi_gpe_walk_info walk_info;
acpi_status status = AE_OK;
- u32 new_wake_gpe_count = 0;
-
- /* We will examine only _PRW/_Lxx/_Exx methods owned by this table */
-
- walk_info.owner_id = table_owner_id;
- walk_info.execute_by_owner_id = TRUE;
- walk_info.count = 0;
-
- if (acpi_gbl_leave_wake_gpes_disabled) {
- /*
- * 1) Run any newly-loaded _PRW methods to find any GPEs that
- * can now be marked as CAN_WAKE GPEs. Note: We must run the
- * _PRW methods before we process the _Lxx/_Exx methods because
- * we will enable all runtime GPEs associated with the new
- * _Lxx/_Exx methods at the time we process those methods.
- *
- * Unlock interpreter so that we can run the _PRW methods.
- */
- walk_info.gpe_block = NULL;
- walk_info.gpe_device = NULL;
-
- acpi_ex_exit_interpreter();
-
- status =
- acpi_ns_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
- ACPI_UINT32_MAX,
- ACPI_NS_WALK_NO_UNLOCK,
- acpi_ev_match_prw_and_gpe, NULL,
- &walk_info, NULL);
- if (ACPI_FAILURE(status)) {
- ACPI_EXCEPTION((AE_INFO, status,
- "While executing _PRW methods"));
- }
-
- acpi_ex_enter_interpreter();
- new_wake_gpe_count = walk_info.count;
- }
/*
* 2) Find any _Lxx/_Exx GPE methods that have just been loaded.
*
- * Any GPEs that correspond to new _Lxx/_Exx methods and are not
- * marked as CAN_WAKE are immediately enabled.
+ * Any GPEs that correspond to new _Lxx/_Exx methods are immediately
+ * enabled.
*
* Examine the namespace underneath each gpe_device within the
* gpe_block lists.
@@ -275,6 +236,8 @@ void acpi_ev_update_gpes(acpi_owner_id table_owner_id)
return;
}
+ walk_info.owner_id = table_owner_id;
+ walk_info.execute_by_owner_id = TRUE;
walk_info.count = 0;
walk_info.enable_this_gpe = TRUE;
@@ -307,10 +270,8 @@ void acpi_ev_update_gpes(acpi_owner_id table_owner_id)
gpe_xrupt_info = gpe_xrupt_info->next;
}
- if (walk_info.count || new_wake_gpe_count) {
- ACPI_INFO((AE_INFO,
- "Enabled %u new runtime GPEs, added %u new wakeup GPEs",
- walk_info.count, new_wake_gpe_count));
+ if (walk_info.count) {
+ ACPI_INFO((AE_INFO, "Enabled %u new GPEs", walk_info.count));
}
(void)acpi_ut_release_mutex(ACPI_MTX_EVENTS);
@@ -386,9 +347,6 @@ acpi_ev_match_gpe_method(acpi_handle obj_handle,
/*
* 3) Edge/Level determination is based on the 2nd character
* of the method name
- *
- * NOTE: Default GPE type is RUNTIME only. Later, if a _PRW object is
- * found that points to this GPE, the ACPI_GPE_CAN_WAKE flag is set.
*/
switch (name[1]) {
case 'L':
@@ -471,24 +429,18 @@ acpi_ev_match_gpe_method(acpi_handle obj_handle,
*/
if (walk_info->enable_this_gpe) {
- /* Ignore GPEs that can wake the system */
+ walk_info->count++;
+ gpe_device = walk_info->gpe_device;
- if (!(gpe_event_info->flags & ACPI_GPE_CAN_WAKE) ||
- !acpi_gbl_leave_wake_gpes_disabled) {
- walk_info->count++;
- gpe_device = walk_info->gpe_device;
-
- if (gpe_device == acpi_gbl_fadt_gpe_device) {
- gpe_device = NULL;
- }
+ if (gpe_device == acpi_gbl_fadt_gpe_device) {
+ gpe_device = NULL;
+ }
- status = acpi_enable_gpe(gpe_device, gpe_number,
- ACPI_GPE_TYPE_RUNTIME);
- if (ACPI_FAILURE(status)) {
- ACPI_EXCEPTION((AE_INFO, status,
- "Could not enable GPE 0x%02X",
- gpe_number));
- }
+ status = acpi_enable_gpe(gpe_device, gpe_number);
+ if (ACPI_FAILURE(status)) {
+ ACPI_EXCEPTION((AE_INFO, status,
+ "Could not enable GPE 0x%02X",
+ gpe_number));
}
}
@@ -497,157 +449,3 @@ acpi_ev_match_gpe_method(acpi_handle obj_handle,
name, gpe_number));
return_ACPI_STATUS(AE_OK);
}
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_ev_match_prw_and_gpe
- *
- * PARAMETERS: Callback from walk_namespace
- *
- * RETURN: Status. NOTE: We ignore errors so that the _PRW walk is
- * not aborted on a single _PRW failure.
- *
- * DESCRIPTION: Called from acpi_walk_namespace. Expects each object to be a
- * Device. Run the _PRW method. If present, extract the GPE
- * number and mark the GPE as a CAN_WAKE GPE. Allows a
- * per-owner_id execution if execute_by_owner_id is TRUE in the
- * walk_info parameter block.
- *
- * If walk_info->execute_by_owner_id is TRUE, we only execute _PRWs with that
- * owner.
- * If walk_info->gpe_device is NULL, we execute every _PRW found. Otherwise,
- * we only execute _PRWs that refer to the input gpe_device.
- *
- ******************************************************************************/
-
-acpi_status
-acpi_ev_match_prw_and_gpe(acpi_handle obj_handle,
- u32 level, void *context, void **return_value)
-{
- struct acpi_gpe_walk_info *walk_info =
- ACPI_CAST_PTR(struct acpi_gpe_walk_info, context);
- struct acpi_namespace_node *gpe_device;
- struct acpi_gpe_block_info *gpe_block;
- struct acpi_namespace_node *target_gpe_device;
- struct acpi_namespace_node *prw_node;
- struct acpi_gpe_event_info *gpe_event_info;
- union acpi_operand_object *pkg_desc;
- union acpi_operand_object *obj_desc;
- u32 gpe_number;
- acpi_status status;
-
- ACPI_FUNCTION_TRACE(ev_match_prw_and_gpe);
-
- /* Check for a _PRW method under this device */
-
- status = acpi_ns_get_node(obj_handle, METHOD_NAME__PRW,
- ACPI_NS_NO_UPSEARCH, &prw_node);
- if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(AE_OK);
- }
-
- /* Check if requested owner_id matches this owner_id */
-
- if ((walk_info->execute_by_owner_id) &&
- (prw_node->owner_id != walk_info->owner_id)) {
- return_ACPI_STATUS(AE_OK);
- }
-
- /* Execute the _PRW */
-
- status = acpi_ut_evaluate_object(prw_node, NULL,
- ACPI_BTYPE_PACKAGE, &pkg_desc);
- if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(AE_OK);
- }
-
- /* The returned _PRW package must have at least two elements */
-
- if (pkg_desc->package.count < 2) {
- goto cleanup;
- }
-
- /* Extract pointers from the input context */
-
- gpe_device = walk_info->gpe_device;
- gpe_block = walk_info->gpe_block;
-
- /*
- * The _PRW object must return a package, we are only interested
- * in the first element
- */
- obj_desc = pkg_desc->package.elements[0];
-
- if (obj_desc->common.type == ACPI_TYPE_INTEGER) {
-
- /* Use FADT-defined GPE device (from definition of _PRW) */
-
- target_gpe_device = NULL;
- if (gpe_device) {
- target_gpe_device = acpi_gbl_fadt_gpe_device;
- }
-
- /* Integer is the GPE number in the FADT described GPE blocks */
-
- gpe_number = (u32)obj_desc->integer.value;
- } else if (obj_desc->common.type == ACPI_TYPE_PACKAGE) {
-
- /* Package contains a GPE reference and GPE number within a GPE block */
-
- if ((obj_desc->package.count < 2) ||
- ((obj_desc->package.elements[0])->common.type !=
- ACPI_TYPE_LOCAL_REFERENCE) ||
- ((obj_desc->package.elements[1])->common.type !=
- ACPI_TYPE_INTEGER)) {
- goto cleanup;
- }
-
- /* Get GPE block reference and decode */
-
- target_gpe_device =
- obj_desc->package.elements[0]->reference.node;
- gpe_number = (u32)obj_desc->package.elements[1]->integer.value;
- } else {
- /* Unknown type, just ignore it */
-
- goto cleanup;
- }
-
- /* Get the gpe_event_info for this GPE */
-
- if (gpe_device) {
- /*
- * Is this GPE within this block?
- *
- * TRUE if and only if these conditions are true:
- * 1) The GPE devices match.
- * 2) The GPE index(number) is within the range of the Gpe Block
- * associated with the GPE device.
- */
- if (gpe_device != target_gpe_device) {
- goto cleanup;
- }
-
- gpe_event_info =
- acpi_ev_low_get_gpe_info(gpe_number, gpe_block);
- } else {
- /* gpe_device is NULL, just match the target_device and gpe_number */
-
- gpe_event_info =
- acpi_ev_get_gpe_event_info(target_gpe_device, gpe_number);
- }
-
- if (gpe_event_info) {
- if (!(gpe_event_info->flags & ACPI_GPE_CAN_WAKE)) {
-
- /* This GPE can wake the system */
-
- gpe_event_info->flags |= ACPI_GPE_CAN_WAKE;
- walk_info->count++;
- }
- }
-
- cleanup:
- acpi_ut_remove_reference(pkg_desc);
- return_ACPI_STATUS(AE_OK);
-}
diff --git a/drivers/acpi/acpica/evrgnini.c b/drivers/acpi/acpica/evrgnini.c
index 2e3b0334072..f40d271bf56 100644
--- a/drivers/acpi/acpica/evrgnini.c
+++ b/drivers/acpi/acpica/evrgnini.c
@@ -199,7 +199,7 @@ acpi_ev_pci_config_region_setup(acpi_handle handle,
return_ACPI_STATUS(status);
}
- parent_node = acpi_ns_get_parent_node(region_obj->region.node);
+ parent_node = region_obj->region.node->parent;
/*
* Get the _SEG and _BBN values from the device upon which the handler
@@ -248,7 +248,7 @@ acpi_ev_pci_config_region_setup(acpi_handle handle,
break;
}
- pci_root_node = acpi_ns_get_parent_node(pci_root_node);
+ pci_root_node = pci_root_node->parent;
}
/* PCI root bridge not found, use namespace root node */
@@ -280,7 +280,7 @@ acpi_ev_pci_config_region_setup(acpi_handle handle,
*/
pci_device_node = region_obj->region.node;
while (pci_device_node && (pci_device_node->type != ACPI_TYPE_DEVICE)) {
- pci_device_node = acpi_ns_get_parent_node(pci_device_node);
+ pci_device_node = pci_device_node->parent;
}
if (!pci_device_node) {
@@ -521,7 +521,7 @@ acpi_ev_initialize_region(union acpi_operand_object *region_obj,
return_ACPI_STATUS(AE_NOT_EXIST);
}
- node = acpi_ns_get_parent_node(region_obj->region.node);
+ node = region_obj->region.node->parent;
space_id = region_obj->region.space_id;
/* Setup defaults */
@@ -654,7 +654,7 @@ acpi_ev_initialize_region(union acpi_operand_object *region_obj,
/* This node does not have the handler we need; Pop up one level */
- node = acpi_ns_get_parent_node(node);
+ node = node->parent;
}
/* If we get here, there is no handler for this region */
diff --git a/drivers/acpi/acpica/evxfevnt.c b/drivers/acpi/acpica/evxfevnt.c
index 18b3f1468b7..0ec900da579 100644
--- a/drivers/acpi/acpica/evxfevnt.c
+++ b/drivers/acpi/acpica/evxfevnt.c
@@ -213,101 +213,71 @@ ACPI_EXPORT_SYMBOL(acpi_enable_event)
/*******************************************************************************
*
- * FUNCTION: acpi_clear_and_enable_gpe
- *
- * PARAMETERS: gpe_event_info - GPE to enable
- *
- * RETURN: Status
- *
- * DESCRIPTION: Clear the given GPE from stale events and enable it.
- *
- ******************************************************************************/
-static acpi_status
-acpi_clear_and_enable_gpe(struct acpi_gpe_event_info *gpe_event_info)
-{
- acpi_status status;
-
- /*
- * We will only allow a GPE to be enabled if it has either an
- * associated method (_Lxx/_Exx) or a handler. Otherwise, the
- * GPE will be immediately disabled by acpi_ev_gpe_dispatch the
- * first time it fires.
- */
- if (!(gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK)) {
- return_ACPI_STATUS(AE_NO_HANDLER);
- }
-
- /* Clear the GPE (of stale events) */
- status = acpi_hw_clear_gpe(gpe_event_info);
- if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
- }
-
- /* Enable the requested GPE */
- status = acpi_hw_low_set_gpe(gpe_event_info, ACPI_GPE_ENABLE);
-
- return_ACPI_STATUS(status);
-}
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_set_gpe
+ * FUNCTION: acpi_gpe_wakeup
*
* PARAMETERS: gpe_device - Parent GPE Device. NULL for GPE0/GPE1
* gpe_number - GPE level within the GPE block
- * action - ACPI_GPE_ENABLE or ACPI_GPE_DISABLE
+ * Action - Enable or Disable
*
* RETURN: Status
*
- * DESCRIPTION: Enable or disable an individual GPE. This function bypasses
- * the reference count mechanism used in the acpi_enable_gpe and
- * acpi_disable_gpe interfaces -- and should be used with care.
- *
- * Note: Typically used to disable a runtime GPE for short period of time,
- * then re-enable it, without disturbing the existing reference counts. This
- * is useful, for example, in the Embedded Controller (EC) driver.
+ * DESCRIPTION: Set or clear the GPE's wakeup enable mask bit.
*
******************************************************************************/
-acpi_status acpi_set_gpe(acpi_handle gpe_device, u32 gpe_number, u8 action)
+acpi_status acpi_gpe_wakeup(acpi_handle gpe_device, u32 gpe_number, u8 action)
{
+ acpi_status status = AE_OK;
struct acpi_gpe_event_info *gpe_event_info;
- acpi_status status;
+ struct acpi_gpe_register_info *gpe_register_info;
acpi_cpu_flags flags;
+ u32 register_bit;
- ACPI_FUNCTION_TRACE(acpi_set_gpe);
+ ACPI_FUNCTION_TRACE(acpi_gpe_wakeup);
flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);
/* Ensure that we have a valid GPE number */
gpe_event_info = acpi_ev_get_gpe_event_info(gpe_device, gpe_number);
- if (!gpe_event_info) {
+ if (!gpe_event_info || !(gpe_event_info->flags & ACPI_GPE_CAN_WAKE)) {
status = AE_BAD_PARAMETER;
goto unlock_and_exit;
}
+ gpe_register_info = gpe_event_info->register_info;
+ if (!gpe_register_info) {
+ status = AE_NOT_EXIST;
+ goto unlock_and_exit;
+ }
+
+ register_bit =
+ acpi_hw_get_gpe_register_bit(gpe_event_info, gpe_register_info);
+
/* Perform the action */
switch (action) {
case ACPI_GPE_ENABLE:
- status = acpi_clear_and_enable_gpe(gpe_event_info);
+ ACPI_SET_BIT(gpe_register_info->enable_for_wake,
+ (u8)register_bit);
break;
case ACPI_GPE_DISABLE:
- status = acpi_hw_low_set_gpe(gpe_event_info, ACPI_GPE_DISABLE);
+ ACPI_CLEAR_BIT(gpe_register_info->enable_for_wake,
+ (u8)register_bit);
break;
default:
+ ACPI_ERROR((AE_INFO, "%u, Invalid action", action));
status = AE_BAD_PARAMETER;
break;
}
- unlock_and_exit:
+unlock_and_exit:
acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
return_ACPI_STATUS(status);
}
-ACPI_EXPORT_SYMBOL(acpi_set_gpe)
+ACPI_EXPORT_SYMBOL(acpi_gpe_wakeup)
/*******************************************************************************
*
@@ -315,17 +285,14 @@ ACPI_EXPORT_SYMBOL(acpi_set_gpe)
*
* PARAMETERS: gpe_device - Parent GPE Device. NULL for GPE0/GPE1
* gpe_number - GPE level within the GPE block
- * gpe_type - ACPI_GPE_TYPE_RUNTIME or ACPI_GPE_TYPE_WAKE
- * or both
*
* RETURN: Status
*
* DESCRIPTION: Add a reference to a GPE. On the first reference, the GPE is
- * hardware-enabled (for runtime GPEs), or the GPE register mask
- * is updated (for wake GPEs).
+ * hardware-enabled.
*
******************************************************************************/
-acpi_status acpi_enable_gpe(acpi_handle gpe_device, u32 gpe_number, u8 gpe_type)
+acpi_status acpi_enable_gpe(acpi_handle gpe_device, u32 gpe_number)
{
acpi_status status = AE_OK;
struct acpi_gpe_event_info *gpe_event_info;
@@ -333,12 +300,6 @@ acpi_status acpi_enable_gpe(acpi_handle gpe_device, u32 gpe_number, u8 gpe_type)
ACPI_FUNCTION_TRACE(acpi_enable_gpe);
- /* Parameter validation */
-
- if (!gpe_type || (gpe_type & ~ACPI_GPE_TYPE_WAKE_RUN)) {
- return_ACPI_STATUS(AE_BAD_PARAMETER);
- }
-
flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);
/* Ensure that we have a valid GPE number */
@@ -349,46 +310,19 @@ acpi_status acpi_enable_gpe(acpi_handle gpe_device, u32 gpe_number, u8 gpe_type)
goto unlock_and_exit;
}
- if (gpe_type & ACPI_GPE_TYPE_RUNTIME) {
- if (gpe_event_info->runtime_count == ACPI_UINT8_MAX) {
- status = AE_LIMIT; /* Too many references */
- goto unlock_and_exit;
- }
-
- gpe_event_info->runtime_count++;
- if (gpe_event_info->runtime_count == 1) {
- status = acpi_ev_update_gpe_enable_masks(gpe_event_info);
- if (ACPI_SUCCESS(status)) {
- status = acpi_clear_and_enable_gpe(gpe_event_info);
- }
-
- if (ACPI_FAILURE(status)) {
- gpe_event_info->runtime_count--;
- goto unlock_and_exit;
- }
- }
+ if (gpe_event_info->runtime_count == ACPI_UINT8_MAX) {
+ status = AE_LIMIT; /* Too many references */
+ goto unlock_and_exit;
}
- if (gpe_type & ACPI_GPE_TYPE_WAKE) {
- /* The GPE must have the ability to wake the system */
-
- if (!(gpe_event_info->flags & ACPI_GPE_CAN_WAKE)) {
- status = AE_TYPE;
- goto unlock_and_exit;
+ gpe_event_info->runtime_count++;
+ if (gpe_event_info->runtime_count == 1) {
+ status = acpi_ev_update_gpe_enable_mask(gpe_event_info);
+ if (ACPI_SUCCESS(status)) {
+ status = acpi_ev_enable_gpe(gpe_event_info);
}
-
- if (gpe_event_info->wakeup_count == ACPI_UINT8_MAX) {
- status = AE_LIMIT; /* Too many references */
- goto unlock_and_exit;
- }
-
- /*
- * Update the enable mask on the first wakeup reference. Wake GPEs
- * are only hardware-enabled just before sleeping.
- */
- gpe_event_info->wakeup_count++;
- if (gpe_event_info->wakeup_count == 1) {
- status = acpi_ev_update_gpe_enable_masks(gpe_event_info);
+ if (ACPI_FAILURE(status)) {
+ gpe_event_info->runtime_count--;
}
}
@@ -404,8 +338,6 @@ ACPI_EXPORT_SYMBOL(acpi_enable_gpe)
*
* PARAMETERS: gpe_device - Parent GPE Device. NULL for GPE0/GPE1
* gpe_number - GPE level within the GPE block
- * gpe_type - ACPI_GPE_TYPE_RUNTIME or ACPI_GPE_TYPE_WAKE
- * or both
*
* RETURN: Status
*
@@ -414,7 +346,7 @@ ACPI_EXPORT_SYMBOL(acpi_enable_gpe)
* the GPE mask bit disabled (for wake GPEs)
*
******************************************************************************/
-acpi_status acpi_disable_gpe(acpi_handle gpe_device, u32 gpe_number, u8 gpe_type)
+acpi_status acpi_disable_gpe(acpi_handle gpe_device, u32 gpe_number)
{
acpi_status status = AE_OK;
struct acpi_gpe_event_info *gpe_event_info;
@@ -422,12 +354,6 @@ acpi_status acpi_disable_gpe(acpi_handle gpe_device, u32 gpe_number, u8 gpe_type
ACPI_FUNCTION_TRACE(acpi_disable_gpe);
- /* Parameter validation */
-
- if (!gpe_type || (gpe_type & ~ACPI_GPE_TYPE_WAKE_RUN)) {
- return_ACPI_STATUS(AE_BAD_PARAMETER);
- }
-
flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);
/* Ensure that we have a valid GPE number */
@@ -440,41 +366,21 @@ acpi_status acpi_disable_gpe(acpi_handle gpe_device, u32 gpe_number, u8 gpe_type
/* Hardware-disable a runtime GPE on removal of the last reference */
- if (gpe_type & ACPI_GPE_TYPE_RUNTIME) {
- if (!gpe_event_info->runtime_count) {
- status = AE_LIMIT; /* There are no references to remove */
- goto unlock_and_exit;
- }
-
- gpe_event_info->runtime_count--;
- if (!gpe_event_info->runtime_count) {
- status = acpi_ev_update_gpe_enable_masks(gpe_event_info);
- if (ACPI_SUCCESS(status)) {
- status = acpi_hw_low_set_gpe(gpe_event_info,
- ACPI_GPE_DISABLE);
- }
-
- if (ACPI_FAILURE(status)) {
- gpe_event_info->runtime_count++;
- goto unlock_and_exit;
- }
- }
+ if (!gpe_event_info->runtime_count) {
+ status = AE_LIMIT; /* There are no references to remove */
+ goto unlock_and_exit;
}
- /*
- * Update masks for wake GPE on removal of the last reference.
- * No need to hardware-disable wake GPEs here, they are not currently
- * enabled.
- */
- if (gpe_type & ACPI_GPE_TYPE_WAKE) {
- if (!gpe_event_info->wakeup_count) {
- status = AE_LIMIT; /* There are no references to remove */
- goto unlock_and_exit;
+ gpe_event_info->runtime_count--;
+ if (!gpe_event_info->runtime_count) {
+ status = acpi_ev_update_gpe_enable_mask(gpe_event_info);
+ if (ACPI_SUCCESS(status)) {
+ status =
+ acpi_hw_low_set_gpe(gpe_event_info,
+ ACPI_GPE_DISABLE);
}
-
- gpe_event_info->wakeup_count--;
- if (!gpe_event_info->wakeup_count) {
- status = acpi_ev_update_gpe_enable_masks(gpe_event_info);
+ if (ACPI_FAILURE(status)) {
+ gpe_event_info->runtime_count++;
}
}
@@ -486,6 +392,59 @@ ACPI_EXPORT_SYMBOL(acpi_disable_gpe)
/*******************************************************************************
*
+ * FUNCTION: acpi_gpe_can_wake
+ *
+ * PARAMETERS: gpe_device - Parent GPE Device. NULL for GPE0/GPE1
+ * gpe_number - GPE level within the GPE block
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Set the ACPI_GPE_CAN_WAKE flag for the given GPE. If the GPE
+ * has a corresponding method and is currently enabled, disable it
+ * (GPEs with corresponding methods are enabled unconditionally
+ * during initialization, but GPEs that can wake up are expected
+ * to be initially disabled).
+ *
+ ******************************************************************************/
+acpi_status acpi_gpe_can_wake(acpi_handle gpe_device, u32 gpe_number)
+{
+ acpi_status status = AE_OK;
+ struct acpi_gpe_event_info *gpe_event_info;
+ acpi_cpu_flags flags;
+ u8 disable = 0;
+
+ ACPI_FUNCTION_TRACE(acpi_gpe_can_wake);
+
+ flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);
+
+ /* Ensure that we have a valid GPE number */
+
+ gpe_event_info = acpi_ev_get_gpe_event_info(gpe_device, gpe_number);
+ if (!gpe_event_info) {
+ status = AE_BAD_PARAMETER;
+ goto unlock_and_exit;
+ }
+
+ if (gpe_event_info->flags & ACPI_GPE_CAN_WAKE) {
+ goto unlock_and_exit;
+ }
+
+ gpe_event_info->flags |= ACPI_GPE_CAN_WAKE;
+ disable = (gpe_event_info->flags & ACPI_GPE_DISPATCH_METHOD)
+ && gpe_event_info->runtime_count;
+
+unlock_and_exit:
+ acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
+
+ if (disable)
+ status = acpi_disable_gpe(gpe_device, gpe_number);
+
+ return_ACPI_STATUS(status);
+}
+ACPI_EXPORT_SYMBOL(acpi_gpe_can_wake)
+
+/*******************************************************************************
+ *
* FUNCTION: acpi_disable_event
*
* PARAMETERS: Event - The fixed eventto be enabled
@@ -800,7 +759,7 @@ acpi_install_gpe_block(acpi_handle gpe_device,
obj_desc->device.gpe_block = gpe_block;
- /* Run the _PRW methods and enable the runtime GPEs in the new block */
+ /* Enable the runtime GPEs in the new block */
status = acpi_ev_initialize_gpe_block(node, gpe_block);
diff --git a/drivers/acpi/acpica/exconfig.c b/drivers/acpi/acpica/exconfig.c
index 008621c5ad8..18832205b63 100644
--- a/drivers/acpi/acpica/exconfig.c
+++ b/drivers/acpi/acpica/exconfig.c
@@ -120,7 +120,7 @@ acpi_ex_add_table(u32 table_index,
acpi_ns_exec_module_code_list();
acpi_ex_enter_interpreter();
- /* Update GPEs for any new _PRW or _Lxx/_Exx methods. Ignore errors */
+ /* Update GPEs for any new _Lxx/_Exx methods. Ignore errors */
status = acpi_tb_get_owner_id(table_index, &owner_id);
if (ACPI_SUCCESS(status)) {
diff --git a/drivers/acpi/acpica/exdump.c b/drivers/acpi/acpica/exdump.c
index d39d438ba1e..f067bbb0d96 100644
--- a/drivers/acpi/acpica/exdump.c
+++ b/drivers/acpi/acpica/exdump.c
@@ -742,7 +742,7 @@ acpi_ex_dump_operands(union acpi_operand_object **operands,
}
ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
- "**** Start operand dump for opcode [%s], %d operands\n",
+ "**** Start operand dump for opcode [%s], %u operands\n",
opcode_name, num_operands));
if (num_operands == 0) {
@@ -812,7 +812,7 @@ void acpi_ex_dump_namespace_node(struct acpi_namespace_node *node, u32 flags)
acpi_ex_out_string("Type", acpi_ut_get_type_name(node->type));
acpi_ex_out_pointer("Attached Object",
acpi_ns_get_attached_object(node));
- acpi_ex_out_pointer("Parent", acpi_ns_get_parent_node(node));
+ acpi_ex_out_pointer("Parent", node->parent);
acpi_ex_dump_object(ACPI_CAST_PTR(union acpi_operand_object, node),
acpi_ex_dump_node);
@@ -945,7 +945,7 @@ acpi_ex_dump_package_obj(union acpi_operand_object *obj_desc,
case ACPI_TYPE_PACKAGE:
- acpi_os_printf("[Package] Contains %d Elements:\n",
+ acpi_os_printf("[Package] Contains %u Elements:\n",
obj_desc->package.count);
for (i = 0; i < obj_desc->package.count; i++) {
diff --git a/drivers/acpi/acpica/exfldio.c b/drivers/acpi/acpica/exfldio.c
index a6dc26f0b3b..047217303a4 100644
--- a/drivers/acpi/acpica/exfldio.c
+++ b/drivers/acpi/acpica/exfldio.c
@@ -534,13 +534,13 @@ acpi_ex_field_datum_io(union acpi_operand_object *obj_desc,
if (ACPI_SUCCESS(status)) {
if (read_write == ACPI_READ) {
ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
- "Value Read %8.8X%8.8X, Width %d\n",
+ "Value Read %8.8X%8.8X, Width %u\n",
ACPI_FORMAT_UINT64(*value),
obj_desc->common_field.
access_byte_width));
} else {
ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
- "Value Written %8.8X%8.8X, Width %d\n",
+ "Value Written %8.8X%8.8X, Width %u\n",
ACPI_FORMAT_UINT64(*value),
obj_desc->common_field.
access_byte_width));
diff --git a/drivers/acpi/acpica/exprep.c b/drivers/acpi/acpica/exprep.c
index 25059dace0a..98a331d2249 100644
--- a/drivers/acpi/acpica/exprep.c
+++ b/drivers/acpi/acpica/exprep.c
@@ -108,11 +108,11 @@ acpi_ex_generate_access(u32 field_bit_offset,
field_byte_length = field_byte_end_offset - field_byte_offset;
ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
- "Bit length %d, Bit offset %d\n",
+ "Bit length %u, Bit offset %u\n",
field_bit_length, field_bit_offset));
ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
- "Byte Length %d, Byte Offset %d, End Offset %d\n",
+ "Byte Length %u, Byte Offset %u, End Offset %u\n",
field_byte_length, field_byte_offset,
field_byte_end_offset));
@@ -147,11 +147,11 @@ acpi_ex_generate_access(u32 field_bit_offset,
accesses = field_end_offset - field_start_offset;
ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
- "AccessWidth %d end is within region\n",
+ "AccessWidth %u end is within region\n",
access_byte_width));
ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
- "Field Start %d, Field End %d -- requires %d accesses\n",
+ "Field Start %u, Field End %u -- requires %u accesses\n",
field_start_offset, field_end_offset,
accesses));
@@ -159,7 +159,7 @@ acpi_ex_generate_access(u32 field_bit_offset,
if (accesses <= 1) {
ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
- "Entire field can be accessed with one operation of size %d\n",
+ "Entire field can be accessed with one operation of size %u\n",
access_byte_width));
return_VALUE(access_byte_width);
}
@@ -174,7 +174,7 @@ acpi_ex_generate_access(u32 field_bit_offset,
}
} else {
ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
- "AccessWidth %d end is NOT within region\n",
+ "AccessWidth %u end is NOT within region\n",
access_byte_width));
if (access_byte_width == 1) {
ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
@@ -190,7 +190,7 @@ acpi_ex_generate_access(u32 field_bit_offset,
* previous access
*/
ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
- "Backing off to previous optimal access width of %d\n",
+ "Backing off to previous optimal access width of %u\n",
minimum_access_width));
return_VALUE(minimum_access_width);
}
@@ -385,15 +385,6 @@ acpi_ex_prep_common_field_object(union acpi_operand_object *obj_desc,
(field_bit_position -
ACPI_MUL_8(obj_desc->common_field.base_byte_offset));
- /*
- * Does the entire field fit within a single field access element? (datum)
- * (i.e., without crossing a datum boundary)
- */
- if ((obj_desc->common_field.start_field_bit_offset +
- field_bit_length) <= (u16) access_bit_width) {
- obj_desc->common.flags |= AOPOBJ_SINGLE_DATUM;
- }
-
return_ACPI_STATUS(AE_OK);
}
diff --git a/drivers/acpi/acpica/exregion.c b/drivers/acpi/acpica/exregion.c
index 531000fc77d..8819d2ac5ae 100644
--- a/drivers/acpi/acpica/exregion.c
+++ b/drivers/acpi/acpica/exregion.c
@@ -194,7 +194,7 @@ acpi_ex_system_memory_space_handler(u32 function,
((u64) address - (u64) mem_info->mapped_physical_address);
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
- "System-Memory (width %d) R/W %d Address=%8.8X%8.8X\n",
+ "System-Memory (width %u) R/W %u Address=%8.8X%8.8X\n",
bit_width, function,
ACPI_FORMAT_NATIVE_UINT(address)));
@@ -297,7 +297,7 @@ acpi_ex_system_io_space_handler(u32 function,
ACPI_FUNCTION_TRACE(ex_system_io_space_handler);
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
- "System-IO (width %d) R/W %d Address=%8.8X%8.8X\n",
+ "System-IO (width %u) R/W %u Address=%8.8X%8.8X\n",
bit_width, function,
ACPI_FORMAT_NATIVE_UINT(address)));
@@ -373,7 +373,7 @@ acpi_ex_pci_config_space_handler(u32 function,
pci_register = (u16) (u32) address;
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
- "Pci-Config %d (%d) Seg(%04x) Bus(%04x) Dev(%04x) Func(%04x) Reg(%04x)\n",
+ "Pci-Config %u (%u) Seg(%04x) Bus(%04x) Dev(%04x) Func(%04x) Reg(%04x)\n",
function, bit_width, pci_id->segment, pci_id->bus,
pci_id->device, pci_id->function, pci_register));
diff --git a/drivers/acpi/acpica/hwgpe.c b/drivers/acpi/acpica/hwgpe.c
index 3450309c278..14750db2a1b 100644
--- a/drivers/acpi/acpica/hwgpe.c
+++ b/drivers/acpi/acpica/hwgpe.c
@@ -57,7 +57,7 @@ acpi_hw_enable_wakeup_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info,
/******************************************************************************
*
- * FUNCTION: acpi_hw_gpe_register_bit
+ * FUNCTION: acpi_hw_get_gpe_register_bit
*
* PARAMETERS: gpe_event_info - Info block for the GPE
* gpe_register_info - Info block for the GPE register
@@ -69,7 +69,7 @@ acpi_hw_enable_wakeup_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info,
*
******************************************************************************/
-u32 acpi_hw_gpe_register_bit(struct acpi_gpe_event_info *gpe_event_info,
+u32 acpi_hw_get_gpe_register_bit(struct acpi_gpe_event_info *gpe_event_info,
struct acpi_gpe_register_info *gpe_register_info)
{
return (u32)1 << (gpe_event_info->gpe_number -
@@ -115,7 +115,7 @@ acpi_hw_low_set_gpe(struct acpi_gpe_event_info *gpe_event_info, u8 action)
/* Set ot clear just the bit that corresponds to this GPE */
- register_bit = acpi_hw_gpe_register_bit(gpe_event_info,
+ register_bit = acpi_hw_get_gpe_register_bit(gpe_event_info,
gpe_register_info);
switch (action) {
case ACPI_GPE_COND_ENABLE:
@@ -143,31 +143,6 @@ acpi_hw_low_set_gpe(struct acpi_gpe_event_info *gpe_event_info, u8 action)
/******************************************************************************
*
- * FUNCTION: acpi_hw_write_gpe_enable_reg
- *
- * PARAMETERS: gpe_event_info - Info block for the GPE to be enabled
- *
- * RETURN: Status
- *
- * DESCRIPTION: Write a GPE enable register. Note: The bit for this GPE must
- * already be cleared or set in the parent register
- * enable_for_run mask.
- *
- ******************************************************************************/
-
-acpi_status
-acpi_hw_write_gpe_enable_reg(struct acpi_gpe_event_info * gpe_event_info)
-{
- acpi_status status;
-
- ACPI_FUNCTION_ENTRY();
-
- status = acpi_hw_low_set_gpe(gpe_event_info, ACPI_GPE_COND_ENABLE);
- return (status);
-}
-
-/******************************************************************************
- *
* FUNCTION: acpi_hw_clear_gpe
*
* PARAMETERS: gpe_event_info - Info block for the GPE to be cleared
@@ -193,7 +168,7 @@ acpi_status acpi_hw_clear_gpe(struct acpi_gpe_event_info * gpe_event_info)
return (AE_NOT_EXIST);
}
- register_bit = acpi_hw_gpe_register_bit(gpe_event_info,
+ register_bit = acpi_hw_get_gpe_register_bit(gpe_event_info,
gpe_register_info);
/*
@@ -241,7 +216,7 @@ acpi_hw_get_gpe_status(struct acpi_gpe_event_info * gpe_event_info,
/* Get the register bitmask for this GPE */
- register_bit = acpi_hw_gpe_register_bit(gpe_event_info,
+ register_bit = acpi_hw_get_gpe_register_bit(gpe_event_info,
gpe_register_info);
/* GPE currently enabled? (enabled for runtime?) */
diff --git a/drivers/acpi/acpica/hwsleep.c b/drivers/acpi/acpica/hwsleep.c
index 36eb803dd9d..3796811276a 100644
--- a/drivers/acpi/acpica/hwsleep.c
+++ b/drivers/acpi/acpica/hwsleep.c
@@ -307,7 +307,7 @@ acpi_status asmlinkage acpi_enter_sleep_state(u8 sleep_state)
return_ACPI_STATUS(status);
}
ACPI_DEBUG_PRINT((ACPI_DB_INIT,
- "Entering sleep state [S%d]\n", sleep_state));
+ "Entering sleep state [S%u]\n", sleep_state));
/* Clear the SLP_EN and SLP_TYP fields */
diff --git a/drivers/acpi/acpica/nsaccess.c b/drivers/acpi/acpica/nsaccess.c
index 3a2814676ac..0cd925be5fc 100644
--- a/drivers/acpi/acpica/nsaccess.c
+++ b/drivers/acpi/acpica/nsaccess.c
@@ -338,8 +338,7 @@ acpi_ns_lookup(union acpi_generic_state *scope_info,
*/
while (!acpi_ns_opens_scope(prefix_node->type) &&
prefix_node->type != ACPI_TYPE_ANY) {
- prefix_node =
- acpi_ns_get_parent_node(prefix_node);
+ prefix_node = prefix_node->parent;
}
}
}
@@ -419,7 +418,7 @@ acpi_ns_lookup(union acpi_generic_state *scope_info,
/* Backup to the parent node */
num_carats++;
- this_node = acpi_ns_get_parent_node(this_node);
+ this_node = this_node->parent;
if (!this_node) {
/* Current scope has no parent scope */
@@ -433,7 +432,7 @@ acpi_ns_lookup(union acpi_generic_state *scope_info,
if (search_parent_flag == ACPI_NS_NO_UPSEARCH) {
ACPI_DEBUG_PRINT((ACPI_DB_NAMES,
- "Search scope is [%4.4s], path has %d carat(s)\n",
+ "Search scope is [%4.4s], path has %u carat(s)\n",
acpi_ut_get_node_name
(this_node), num_carats));
}
@@ -495,7 +494,7 @@ acpi_ns_lookup(union acpi_generic_state *scope_info,
path++;
ACPI_DEBUG_PRINT((ACPI_DB_NAMES,
- "Multi Pathname (%d Segments, Flags=%X)\n",
+ "Multi Pathname (%u Segments, Flags=%X)\n",
num_segments, flags));
break;
diff --git a/drivers/acpi/acpica/nsalloc.c b/drivers/acpi/acpica/nsalloc.c
index 982269c1fa4..1e5ff803d9a 100644
--- a/drivers/acpi/acpica/nsalloc.c
+++ b/drivers/acpi/acpica/nsalloc.c
@@ -159,7 +159,7 @@ void acpi_ns_remove_node(struct acpi_namespace_node *node)
ACPI_FUNCTION_TRACE_PTR(ns_remove_node, node);
- parent_node = acpi_ns_get_parent_node(node);
+ parent_node = node->parent;
prev_node = NULL;
next_node = parent_node->child;
@@ -168,29 +168,20 @@ void acpi_ns_remove_node(struct acpi_namespace_node *node)
while (next_node != node) {
prev_node = next_node;
- next_node = prev_node->peer;
+ next_node = next_node->peer;
}
if (prev_node) {
/* Node is not first child, unlink it */
- prev_node->peer = next_node->peer;
- if (next_node->flags & ANOBJ_END_OF_PEER_LIST) {
- prev_node->flags |= ANOBJ_END_OF_PEER_LIST;
- }
+ prev_node->peer = node->peer;
} else {
- /* Node is first child (has no previous peer) */
-
- if (next_node->flags & ANOBJ_END_OF_PEER_LIST) {
-
- /* No peers at all */
-
- parent_node->child = NULL;
- } else { /* Link peer list to parent */
-
- parent_node->child = next_node->peer;
- }
+ /*
+ * Node is first child (has no previous peer).
+ * Link peer list to parent
+ */
+ parent_node->child = node->peer;
}
/* Delete the node and any attached objects */
@@ -228,33 +219,42 @@ void acpi_ns_install_node(struct acpi_walk_state *walk_state, struct acpi_namesp
ACPI_FUNCTION_TRACE(ns_install_node);
- /*
- * Get the owner ID from the Walk state. The owner ID is used to track
- * table deletion and deletion of objects created by methods.
- */
if (walk_state) {
+ /*
+ * Get the owner ID from the Walk state. The owner ID is used to
+ * track table deletion and deletion of objects created by methods.
+ */
owner_id = walk_state->owner_id;
+
+ if ((walk_state->method_desc) &&
+ (parent_node != walk_state->method_node)) {
+ /*
+ * A method is creating a new node that is not a child of the
+ * method (it is non-local). Mark the executing method as having
+ * modified the namespace. This is used for cleanup when the
+ * method exits.
+ */
+ walk_state->method_desc->method.flags |=
+ AOPOBJ_MODIFIED_NAMESPACE;
+ }
}
/* Link the new entry into the parent and existing children */
+ node->peer = NULL;
+ node->parent = parent_node;
child_node = parent_node->child;
+
if (!child_node) {
parent_node->child = node;
- node->flags |= ANOBJ_END_OF_PEER_LIST;
- node->peer = parent_node;
} else {
- while (!(child_node->flags & ANOBJ_END_OF_PEER_LIST)) {
+ /* Add node to the end of the peer list */
+
+ while (child_node->peer) {
child_node = child_node->peer;
}
child_node->peer = node;
-
- /* Clear end-of-list flag */
-
- child_node->flags &= ~ANOBJ_END_OF_PEER_LIST;
- node->flags |= ANOBJ_END_OF_PEER_LIST;
- node->peer = parent_node;
}
/* Init the new entry */
@@ -288,9 +288,8 @@ void acpi_ns_install_node(struct acpi_walk_state *walk_state, struct acpi_namesp
void acpi_ns_delete_children(struct acpi_namespace_node *parent_node)
{
- struct acpi_namespace_node *child_node;
struct acpi_namespace_node *next_node;
- u8 flags;
+ struct acpi_namespace_node *node_to_delete;
ACPI_FUNCTION_TRACE_PTR(ns_delete_children, parent_node);
@@ -298,37 +297,26 @@ void acpi_ns_delete_children(struct acpi_namespace_node *parent_node)
return_VOID;
}
- /* If no children, all done! */
-
- child_node = parent_node->child;
- if (!child_node) {
- return_VOID;
- }
-
/* Deallocate all children at this level */
- do {
-
- /* Get the things we need */
-
- next_node = child_node->peer;
- flags = child_node->flags;
+ next_node = parent_node->child;
+ while (next_node) {
/* Grandchildren should have all been deleted already */
- if (child_node->child) {
+ if (next_node->child) {
ACPI_ERROR((AE_INFO, "Found a grandchild! P=%p C=%p",
- parent_node, child_node));
+ parent_node, next_node));
}
/*
* Delete this child node and move on to the next child in the list.
* No need to unlink the node since we are deleting the entire branch.
*/
- acpi_ns_delete_node(child_node);
- child_node = next_node;
-
- } while (!(flags & ANOBJ_END_OF_PEER_LIST));
+ node_to_delete = next_node;
+ next_node = next_node->peer;
+ acpi_ns_delete_node(node_to_delete);
+ };
/* Clear the parent's child pointer */
@@ -405,7 +393,7 @@ void acpi_ns_delete_namespace_subtree(struct acpi_namespace_node *parent_node)
/* Move up the tree to the grandparent */
- parent_node = acpi_ns_get_parent_node(parent_node);
+ parent_node = parent_node->parent;
}
}
@@ -510,7 +498,7 @@ void acpi_ns_delete_namespace_by_owner(acpi_owner_id owner_id)
/* Move up the tree to the grandparent */
- parent_node = acpi_ns_get_parent_node(parent_node);
+ parent_node = parent_node->parent;
}
}
diff --git a/drivers/acpi/acpica/nsdump.c b/drivers/acpi/acpica/nsdump.c
index 2110cc2360f..a54dc39e304 100644
--- a/drivers/acpi/acpica/nsdump.c
+++ b/drivers/acpi/acpica/nsdump.c
@@ -441,7 +441,7 @@ acpi_ns_dump_one_object(acpi_handle obj_handle,
return (AE_OK);
}
- acpi_os_printf("(R%d)", obj_desc->common.reference_count);
+ acpi_os_printf("(R%u)", obj_desc->common.reference_count);
switch (type) {
case ACPI_TYPE_METHOD:
diff --git a/drivers/acpi/acpica/nsinit.c b/drivers/acpi/acpica/nsinit.c
index 4e5272c313e..660a2728908 100644
--- a/drivers/acpi/acpica/nsinit.c
+++ b/drivers/acpi/acpica/nsinit.c
@@ -103,8 +103,8 @@ acpi_status acpi_ns_initialize_objects(void)
}
ACPI_DEBUG_PRINT_RAW((ACPI_DB_INIT,
- "\nInitialized %hd/%hd Regions %hd/%hd Fields %hd/%hd "
- "Buffers %hd/%hd Packages (%hd nodes)\n",
+ "\nInitialized %u/%u Regions %u/%u Fields %u/%u "
+ "Buffers %u/%u Packages (%u nodes)\n",
info.op_region_init, info.op_region_count,
info.field_init, info.field_count,
info.buffer_init, info.buffer_count,
@@ -112,9 +112,9 @@ acpi_status acpi_ns_initialize_objects(void)
info.object_count));
ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
- "%hd Control Methods found\n", info.method_count));
+ "%u Control Methods found\n", info.method_count));
ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
- "%hd Op Regions found\n", info.op_region_count));
+ "%u Op Regions found\n", info.op_region_count));
return_ACPI_STATUS(AE_OK);
}
@@ -208,8 +208,8 @@ acpi_status acpi_ns_initialize_devices(void)
}
ACPI_DEBUG_PRINT_RAW((ACPI_DB_INIT,
- "\nExecuted %hd _INI methods requiring %hd _STA executions "
- "(examined %hd objects)\n",
+ "\nExecuted %u _INI methods requiring %u _STA executions "
+ "(examined %u objects)\n",
info.num_INI, info.num_STA, info.device_count));
return_ACPI_STATUS(status);
@@ -410,7 +410,7 @@ acpi_ns_find_ini_methods(acpi_handle obj_handle,
* The only _INI methods that we care about are those that are
* present under Device, Processor, and Thermal objects.
*/
- parent_node = acpi_ns_get_parent_node(node);
+ parent_node = node->parent;
switch (parent_node->type) {
case ACPI_TYPE_DEVICE:
case ACPI_TYPE_PROCESSOR:
@@ -420,7 +420,7 @@ acpi_ns_find_ini_methods(acpi_handle obj_handle,
while (parent_node) {
parent_node->flags |= ANOBJ_SUBTREE_HAS_INI;
- parent_node = acpi_ns_get_parent_node(parent_node);
+ parent_node = parent_node->parent;
}
break;
diff --git a/drivers/acpi/acpica/nsnames.c b/drivers/acpi/acpica/nsnames.c
index 7dea0031605..d3104af57e1 100644
--- a/drivers/acpi/acpica/nsnames.c
+++ b/drivers/acpi/acpica/nsnames.c
@@ -93,7 +93,7 @@ acpi_ns_build_external_path(struct acpi_namespace_node *node,
/* Put the name into the buffer */
ACPI_MOVE_32_TO_32((name_buffer + index), &parent_node->name);
- parent_node = acpi_ns_get_parent_node(parent_node);
+ parent_node = parent_node->parent;
/* Prefix name with the path separator */
@@ -198,7 +198,7 @@ acpi_size acpi_ns_get_pathname_length(struct acpi_namespace_node *node)
return 0;
}
size += ACPI_PATH_SEGMENT_LENGTH;
- next_node = acpi_ns_get_parent_node(next_node);
+ next_node = next_node->parent;
}
if (!size) {
diff --git a/drivers/acpi/acpica/nsparse.c b/drivers/acpi/acpica/nsparse.c
index 27cda52c76b..5808c89e9fa 100644
--- a/drivers/acpi/acpica/nsparse.c
+++ b/drivers/acpi/acpica/nsparse.c
@@ -136,8 +136,8 @@ acpi_ns_one_complete_parse(u32 pass_number,
/* Parse the AML */
- ACPI_DEBUG_PRINT((ACPI_DB_PARSE, "*PARSE* pass %d parse\n",
- (unsigned)pass_number));
+ ACPI_DEBUG_PRINT((ACPI_DB_PARSE, "*PARSE* pass %u parse\n",
+ pass_number));
status = acpi_ps_parse_aml(walk_state);
cleanup:
diff --git a/drivers/acpi/acpica/nsrepair.c b/drivers/acpi/acpica/nsrepair.c
index d4be37751be..d1c13669266 100644
--- a/drivers/acpi/acpica/nsrepair.c
+++ b/drivers/acpi/acpica/nsrepair.c
@@ -556,7 +556,7 @@ acpi_ns_repair_null_element(struct acpi_predefined_data *data,
/* Need an Integer - create a zero-value integer */
- new_object = acpi_ut_create_integer_object(0);
+ new_object = acpi_ut_create_integer_object((u64)0);
} else if (expected_btypes & ACPI_RTYPE_STRING) {
/* Need a String - create a NULL string */
diff --git a/drivers/acpi/acpica/nsrepair2.c b/drivers/acpi/acpica/nsrepair2.c
index 61bd0f6755d..4009498fbab 100644
--- a/drivers/acpi/acpica/nsrepair2.c
+++ b/drivers/acpi/acpica/nsrepair2.c
@@ -112,6 +112,13 @@ acpi_ns_sort_list(union acpi_operand_object **elements,
* _GTM: Convert Buffer of BYTEs to a Buffer of DWORDs
* _PSS: Sort the list descending by Power
* _TSS: Sort the list descending by Power
+ *
+ * Names that must be packages, but cannot be sorted:
+ *
+ * _BCL: Values are tied to the Package index where they appear, and cannot
+ * be moved or sorted. These index values are used for _BQC and _BCM.
+ * However, we can fix the case where a buffer is returned, by converting
+ * it to a Package of integers.
*/
static const struct acpi_repair_info acpi_ns_repairable_names[] = {
{"_ALR", acpi_ns_repair_ALR},
diff --git a/drivers/acpi/acpica/nssearch.c b/drivers/acpi/acpica/nssearch.c
index a8e42b5e946..41102a84272 100644
--- a/drivers/acpi/acpica/nssearch.c
+++ b/drivers/acpi/acpica/nssearch.c
@@ -152,17 +152,6 @@ acpi_ns_search_one_scope(u32 target_name,
return_ACPI_STATUS(AE_OK);
}
- /*
- * The last entry in the list points back to the parent,
- * so a flag is used to indicate the end-of-list
- */
- if (node->flags & ANOBJ_END_OF_PEER_LIST) {
-
- /* Searched entire list, we are done */
-
- break;
- }
-
/* Didn't match name, move on to the next peer object */
node = node->peer;
@@ -217,7 +206,7 @@ acpi_ns_search_parent_tree(u32 target_name,
ACPI_FUNCTION_TRACE(ns_search_parent_tree);
- parent_node = acpi_ns_get_parent_node(node);
+ parent_node = node->parent;
/*
* If there is no parent (i.e., we are at the root) or type is "local",
@@ -261,7 +250,7 @@ acpi_ns_search_parent_tree(u32 target_name,
/* Not found here, go up another level (until we reach the root) */
- parent_node = acpi_ns_get_parent_node(parent_node);
+ parent_node = parent_node->parent;
}
/* Not found in parent tree */
diff --git a/drivers/acpi/acpica/nsutils.c b/drivers/acpi/acpica/nsutils.c
index bab559712da..e1add3491b0 100644
--- a/drivers/acpi/acpica/nsutils.c
+++ b/drivers/acpi/acpica/nsutils.c
@@ -847,116 +847,3 @@ acpi_ns_get_node(struct acpi_namespace_node *prefix_node,
ACPI_FREE(internal_path);
return_ACPI_STATUS(status);
}
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_ns_get_parent_node
- *
- * PARAMETERS: Node - Current table entry
- *
- * RETURN: Parent entry of the given entry
- *
- * DESCRIPTION: Obtain the parent entry for a given entry in the namespace.
- *
- ******************************************************************************/
-
-struct acpi_namespace_node *acpi_ns_get_parent_node(struct acpi_namespace_node
- *node)
-{
- ACPI_FUNCTION_ENTRY();
-
- if (!node) {
- return (NULL);
- }
-
- /*
- * Walk to the end of this peer list. The last entry is marked with a flag
- * and the peer pointer is really a pointer back to the parent. This saves
- * putting a parent back pointer in each and every named object!
- */
- while (!(node->flags & ANOBJ_END_OF_PEER_LIST)) {
- node = node->peer;
- }
-
- return (node->peer);
-}
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_ns_get_next_valid_node
- *
- * PARAMETERS: Node - Current table entry
- *
- * RETURN: Next valid Node in the linked node list. NULL if no more valid
- * nodes.
- *
- * DESCRIPTION: Find the next valid node within a name table.
- * Useful for implementing NULL-end-of-list loops.
- *
- ******************************************************************************/
-
-struct acpi_namespace_node *acpi_ns_get_next_valid_node(struct
- acpi_namespace_node
- *node)
-{
-
- /* If we are at the end of this peer list, return NULL */
-
- if (node->flags & ANOBJ_END_OF_PEER_LIST) {
- return NULL;
- }
-
- /* Otherwise just return the next peer */
-
- return (node->peer);
-}
-
-#ifdef ACPI_OBSOLETE_FUNCTIONS
-/*******************************************************************************
- *
- * FUNCTION: acpi_ns_find_parent_name
- *
- * PARAMETERS: *child_node - Named Obj whose name is to be found
- *
- * RETURN: The ACPI name
- *
- * DESCRIPTION: Search for the given obj in its parent scope and return the
- * name segment, or "????" if the parent name can't be found
- * (which "should not happen").
- *
- ******************************************************************************/
-
-acpi_name acpi_ns_find_parent_name(struct acpi_namespace_node * child_node)
-{
- struct acpi_namespace_node *parent_node;
-
- ACPI_FUNCTION_TRACE(ns_find_parent_name);
-
- if (child_node) {
-
- /* Valid entry. Get the parent Node */
-
- parent_node = acpi_ns_get_parent_node(child_node);
- if (parent_node) {
- ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
- "Parent of %p [%4.4s] is %p [%4.4s]\n",
- child_node,
- acpi_ut_get_node_name(child_node),
- parent_node,
- acpi_ut_get_node_name(parent_node)));
-
- if (parent_node->name.integer) {
- return_VALUE((acpi_name) parent_node->name.
- integer);
- }
- }
-
- ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
- "Unable to find parent of %p (%4.4s)\n",
- child_node,
- acpi_ut_get_node_name(child_node)));
- }
-
- return_VALUE(ACPI_UNKNOWN_NAME);
-}
-#endif
diff --git a/drivers/acpi/acpica/nswalk.c b/drivers/acpi/acpica/nswalk.c
index 00e79fb2602..2cd5be8fe10 100644
--- a/drivers/acpi/acpica/nswalk.c
+++ b/drivers/acpi/acpica/nswalk.c
@@ -79,15 +79,6 @@ struct acpi_namespace_node *acpi_ns_get_next_node(struct acpi_namespace_node
return parent_node->child;
}
- /*
- * Get the next node.
- *
- * If we are at the end of this peer list, return NULL
- */
- if (child_node->flags & ANOBJ_END_OF_PEER_LIST) {
- return NULL;
- }
-
/* Otherwise just return the next peer */
return child_node->peer;
@@ -146,9 +137,9 @@ struct acpi_namespace_node *acpi_ns_get_next_node_typed(acpi_object_type type,
return (next_node);
}
- /* Otherwise, move on to the next node */
+ /* Otherwise, move on to the next peer node */
- next_node = acpi_ns_get_next_valid_node(next_node);
+ next_node = next_node->peer;
}
/* Not found */
@@ -355,7 +346,7 @@ acpi_ns_walk_namespace(acpi_object_type type,
*/
level--;
child_node = parent_node;
- parent_node = acpi_ns_get_parent_node(parent_node);
+ parent_node = parent_node->parent;
node_previously_visited = TRUE;
}
diff --git a/drivers/acpi/acpica/nsxfobj.c b/drivers/acpi/acpica/nsxfobj.c
index eafef24ea44..a1f04e9b803 100644
--- a/drivers/acpi/acpica/nsxfobj.c
+++ b/drivers/acpi/acpica/nsxfobj.c
@@ -190,7 +190,7 @@ acpi_status acpi_get_parent(acpi_handle handle, acpi_handle * ret_handle)
/* Get the parent entry */
- parent_node = acpi_ns_get_parent_node(node);
+ parent_node = node->parent;
*ret_handle = ACPI_CAST_PTR(acpi_handle, parent_node);
/* Return exception if parent is null */
diff --git a/drivers/acpi/acpica/utglobal.c b/drivers/acpi/acpica/utglobal.c
index 66116750a0f..0558747579e 100644
--- a/drivers/acpi/acpica/utglobal.c
+++ b/drivers/acpi/acpica/utglobal.c
@@ -813,10 +813,10 @@ acpi_status acpi_ut_init_globals(void)
acpi_gbl_root_node_struct.name.integer = ACPI_ROOT_NAME;
acpi_gbl_root_node_struct.descriptor_type = ACPI_DESC_TYPE_NAMED;
acpi_gbl_root_node_struct.type = ACPI_TYPE_DEVICE;
+ acpi_gbl_root_node_struct.parent = NULL;
acpi_gbl_root_node_struct.child = NULL;
acpi_gbl_root_node_struct.peer = NULL;
acpi_gbl_root_node_struct.object = NULL;
- acpi_gbl_root_node_struct.flags = ANOBJ_END_OF_PEER_LIST;
#ifdef ACPI_DEBUG_OUTPUT
acpi_gbl_lowest_stack_pointer = ACPI_CAST_PTR(acpi_size, ACPI_SIZE_MAX);
diff --git a/drivers/acpi/acpica/utxface.c b/drivers/acpi/acpica/utxface.c
index db9d8ca5798..7f8cefcb2b3 100644
--- a/drivers/acpi/acpica/utxface.c
+++ b/drivers/acpi/acpica/utxface.c
@@ -293,12 +293,8 @@ acpi_status acpi_initialize_objects(u32 flags)
* Complete the GPE initialization for the GPE blocks defined in the FADT
* (GPE block 0 and 1).
*
- * Note1: This is where the _PRW methods are executed for the GPEs. These
- * methods can only be executed after the SCI and Global Lock handlers are
- * installed and initialized.
- *
- * Note2: Currently, there seems to be no need to run the _REG methods
- * before execution of the _PRW methods and enabling of the GPEs.
+ * NOTE: Currently, there seems to be no need to run the _REG methods
+ * before enabling the GPEs.
*/
if (!(flags & ACPI_NO_EVENT_INIT)) {
status = acpi_ev_install_fadt_gpes();
diff --git a/drivers/acpi/button.c b/drivers/acpi/button.c
index 7d857dabdde..1575a9b51f1 100644
--- a/drivers/acpi/button.c
+++ b/drivers/acpi/button.c
@@ -424,8 +424,7 @@ static int acpi_button_add(struct acpi_device *device)
if (device->wakeup.flags.valid) {
/* Button's GPE is run-wake GPE */
acpi_enable_gpe(device->wakeup.gpe_device,
- device->wakeup.gpe_number,
- ACPI_GPE_TYPE_RUNTIME);
+ device->wakeup.gpe_number);
device->wakeup.run_wake_count++;
device->wakeup.state.enabled = 1;
}
@@ -448,8 +447,7 @@ static int acpi_button_remove(struct acpi_device *device, int type)
if (device->wakeup.flags.valid) {
acpi_disable_gpe(device->wakeup.gpe_device,
- device->wakeup.gpe_number,
- ACPI_GPE_TYPE_RUNTIME);
+ device->wakeup.gpe_number);
device->wakeup.run_wake_count--;
device->wakeup.state.enabled = 0;
}
diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index 5f2027d782e..f31291ba94d 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -34,8 +34,6 @@
#include <linux/init.h>
#include <linux/types.h>
#include <linux/delay.h>
-#include <linux/proc_fs.h>
-#include <linux/seq_file.h>
#include <linux/interrupt.h>
#include <linux/list.h>
#include <linux/spinlock.h>
@@ -45,10 +43,13 @@
#include <acpi/acpi_drivers.h>
#include <linux/dmi.h>
+#include "internal.h"
+
#define ACPI_EC_CLASS "embedded_controller"
#define ACPI_EC_DEVICE_NAME "Embedded Controller"
#define ACPI_EC_FILE_INFO "info"
+#undef PREFIX
#define PREFIX "ACPI: EC: "
/* EC status register */
@@ -106,19 +107,8 @@ struct transaction {
bool done;
};
-static struct acpi_ec {
- acpi_handle handle;
- unsigned long gpe;
- unsigned long command_addr;
- unsigned long data_addr;
- unsigned long global_lock;
- unsigned long flags;
- struct mutex lock;
- wait_queue_head_t wait;
- struct list_head list;
- struct transaction *curr;
- spinlock_t curr_lock;
-} *boot_ec, *first_ec;
+struct acpi_ec *boot_ec, *first_ec;
+EXPORT_SYMBOL(first_ec);
static int EC_FLAGS_MSI; /* Out-of-spec MSI controller */
static int EC_FLAGS_VALIDATE_ECDT; /* ASUStec ECDTs need to be validated */
@@ -313,11 +303,8 @@ static int acpi_ec_transaction(struct acpi_ec *ec, struct transaction *t)
pr_debug(PREFIX "transaction start\n");
/* disable GPE during transaction if storm is detected */
if (test_bit(EC_FLAGS_GPE_STORM, &ec->flags)) {
- /*
- * It has to be disabled at the hardware level regardless of the
- * GPE reference counting, so that it doesn't trigger.
- */
- acpi_set_gpe(NULL, ec->gpe, ACPI_GPE_DISABLE);
+ /* It has to be disabled, so that it doesn't trigger. */
+ acpi_disable_gpe(NULL, ec->gpe);
}
status = acpi_ec_transaction_unlocked(ec, t);
@@ -326,12 +313,8 @@ static int acpi_ec_transaction(struct acpi_ec *ec, struct transaction *t)
ec_check_sci_sync(ec, acpi_ec_read_status(ec));
if (test_bit(EC_FLAGS_GPE_STORM, &ec->flags)) {
msleep(1);
- /*
- * It is safe to enable the GPE outside of the transaction. Use
- * acpi_set_gpe() for that, since we used it to disable the GPE
- * above.
- */
- acpi_set_gpe(NULL, ec->gpe, ACPI_GPE_ENABLE);
+ /* It is safe to enable the GPE outside of the transaction. */
+ acpi_enable_gpe(NULL, ec->gpe);
} else if (t->irq_count > ACPI_EC_STORM_THRESHOLD) {
pr_info(PREFIX "GPE storm detected, "
"transactions will use polling mode\n");
@@ -679,72 +662,6 @@ acpi_ec_space_handler(u32 function, acpi_physical_address address,
}
/* --------------------------------------------------------------------------
- FS Interface (/proc)
- -------------------------------------------------------------------------- */
-
-static struct proc_dir_entry *acpi_ec_dir;
-
-static int acpi_ec_read_info(struct seq_file *seq, void *offset)
-{
- struct acpi_ec *ec = seq->private;
-
- if (!ec)
- goto end;
-
- seq_printf(seq, "gpe:\t\t\t0x%02x\n", (u32) ec->gpe);
- seq_printf(seq, "ports:\t\t\t0x%02x, 0x%02x\n",
- (unsigned)ec->command_addr, (unsigned)ec->data_addr);
- seq_printf(seq, "use global lock:\t%s\n",
- ec->global_lock ? "yes" : "no");
- end:
- return 0;
-}
-
-static int acpi_ec_info_open_fs(struct inode *inode, struct file *file)
-{
- return single_open(file, acpi_ec_read_info, PDE(inode)->data);
-}
-
-static const struct file_operations acpi_ec_info_ops = {
- .open = acpi_ec_info_open_fs,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
- .owner = THIS_MODULE,
-};
-
-static int acpi_ec_add_fs(struct acpi_device *device)
-{
- struct proc_dir_entry *entry = NULL;
-
- if (!acpi_device_dir(device)) {
- acpi_device_dir(device) = proc_mkdir(acpi_device_bid(device),
- acpi_ec_dir);
- if (!acpi_device_dir(device))
- return -ENODEV;
- }
-
- entry = proc_create_data(ACPI_EC_FILE_INFO, S_IRUGO,
- acpi_device_dir(device),
- &acpi_ec_info_ops, acpi_driver_data(device));
- if (!entry)
- return -ENODEV;
- return 0;
-}
-
-static int acpi_ec_remove_fs(struct acpi_device *device)
-{
-
- if (acpi_device_dir(device)) {
- remove_proc_entry(ACPI_EC_FILE_INFO, acpi_device_dir(device));
- remove_proc_entry(acpi_device_bid(device), acpi_ec_dir);
- acpi_device_dir(device) = NULL;
- }
-
- return 0;
-}
-
-/* --------------------------------------------------------------------------
Driver Interface
-------------------------------------------------------------------------- */
static acpi_status
@@ -822,7 +739,7 @@ static int ec_install_handlers(struct acpi_ec *ec)
if (ACPI_FAILURE(status))
return -ENODEV;
- acpi_enable_gpe(NULL, ec->gpe, ACPI_GPE_TYPE_RUNTIME);
+ acpi_enable_gpe(NULL, ec->gpe);
status = acpi_install_address_space_handler(ec->handle,
ACPI_ADR_SPACE_EC,
&acpi_ec_space_handler,
@@ -839,7 +756,7 @@ static int ec_install_handlers(struct acpi_ec *ec)
} else {
acpi_remove_gpe_handler(NULL, ec->gpe,
&acpi_ec_gpe_handler);
- acpi_disable_gpe(NULL, ec->gpe, ACPI_GPE_TYPE_RUNTIME);
+ acpi_disable_gpe(NULL, ec->gpe);
return -ENODEV;
}
}
@@ -850,7 +767,7 @@ static int ec_install_handlers(struct acpi_ec *ec)
static void ec_remove_handlers(struct acpi_ec *ec)
{
- acpi_disable_gpe(NULL, ec->gpe, ACPI_GPE_TYPE_RUNTIME);
+ acpi_disable_gpe(NULL, ec->gpe);
if (ACPI_FAILURE(acpi_remove_address_space_handler(ec->handle,
ACPI_ADR_SPACE_EC, &acpi_ec_space_handler)))
pr_err(PREFIX "failed to remove space handler\n");
@@ -894,7 +811,12 @@ static int acpi_ec_add(struct acpi_device *device)
if (!first_ec)
first_ec = ec;
device->driver_data = ec;
- acpi_ec_add_fs(device);
+
+ WARN(!request_region(ec->data_addr, 1, "EC data"),
+ "Could not request EC data io port 0x%lx", ec->data_addr);
+ WARN(!request_region(ec->command_addr, 1, "EC cmd"),
+ "Could not request EC cmd io port 0x%lx", ec->command_addr);
+
pr_info(PREFIX "GPE = 0x%lx, I/O: command/status = 0x%lx, data = 0x%lx\n",
ec->gpe, ec->command_addr, ec->data_addr);
@@ -921,7 +843,8 @@ static int acpi_ec_remove(struct acpi_device *device, int type)
kfree(handler);
}
mutex_unlock(&ec->lock);
- acpi_ec_remove_fs(device);
+ release_region(ec->data_addr, 1);
+ release_region(ec->command_addr, 1);
device->driver_data = NULL;
if (ec == first_ec)
first_ec = NULL;
@@ -1088,22 +1011,6 @@ error:
return -ENODEV;
}
-static int acpi_ec_suspend(struct acpi_device *device, pm_message_t state)
-{
- struct acpi_ec *ec = acpi_driver_data(device);
- /* Stop using the GPE, but keep it reference counted. */
- acpi_set_gpe(NULL, ec->gpe, ACPI_GPE_DISABLE);
- return 0;
-}
-
-static int acpi_ec_resume(struct acpi_device *device)
-{
- struct acpi_ec *ec = acpi_driver_data(device);
- /* Enable the GPE again, but don't reference count it once more. */
- acpi_set_gpe(NULL, ec->gpe, ACPI_GPE_ENABLE);
- return 0;
-}
-
static struct acpi_driver acpi_ec_driver = {
.name = "ec",
.class = ACPI_EC_CLASS,
@@ -1111,8 +1018,6 @@ static struct acpi_driver acpi_ec_driver = {
.ops = {
.add = acpi_ec_add,
.remove = acpi_ec_remove,
- .suspend = acpi_ec_suspend,
- .resume = acpi_ec_resume,
},
};
@@ -1120,16 +1025,10 @@ int __init acpi_ec_init(void)
{
int result = 0;
- acpi_ec_dir = proc_mkdir(ACPI_EC_CLASS, acpi_root_dir);
- if (!acpi_ec_dir)
- return -ENODEV;
-
/* Now register the driver for the EC */
result = acpi_bus_register_driver(&acpi_ec_driver);
- if (result < 0) {
- remove_proc_entry(ACPI_EC_CLASS, acpi_root_dir);
+ if (result < 0)
return -ENODEV;
- }
return result;
}
@@ -1140,9 +1039,6 @@ static void __exit acpi_ec_exit(void)
{
acpi_bus_unregister_driver(&acpi_ec_driver);
-
- remove_proc_entry(ACPI_EC_CLASS, acpi_root_dir);
-
return;
}
#endif /* 0 */
diff --git a/drivers/acpi/ec_sys.c b/drivers/acpi/ec_sys.c
new file mode 100644
index 00000000000..0e869b3f81c
--- /dev/null
+++ b/drivers/acpi/ec_sys.c
@@ -0,0 +1,160 @@
+/*
+ * ec_sys.c
+ *
+ * Copyright (C) 2010 SUSE Products GmbH/Novell
+ * Author:
+ * Thomas Renninger <trenn@suse.de>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.
+ */
+
+#include <linux/kernel.h>
+#include <linux/acpi.h>
+#include <linux/debugfs.h>
+#include "internal.h"
+
+MODULE_AUTHOR("Thomas Renninger <trenn@suse.de>");
+MODULE_DESCRIPTION("ACPI EC sysfs access driver");
+MODULE_LICENSE("GPL");
+
+static bool write_support;
+module_param(write_support, bool, 0644);
+MODULE_PARM_DESC(write_support, "Dangerous, reboot and removal of battery may "
+ "be needed.");
+
+#define EC_SPACE_SIZE 256
+
+struct sysdev_class acpi_ec_sysdev_class = {
+ .name = "ec",
+};
+
+static struct dentry *acpi_ec_debugfs_dir;
+
+static int acpi_ec_open_io(struct inode *i, struct file *f)
+{
+ f->private_data = i->i_private;
+ return 0;
+}
+
+static ssize_t acpi_ec_read_io(struct file *f, char __user *buf,
+ size_t count, loff_t *off)
+{
+ /* Use this if support reading/writing multiple ECs exists in ec.c:
+ * struct acpi_ec *ec = ((struct seq_file *)f->private_data)->private;
+ */
+ unsigned int size = EC_SPACE_SIZE;
+ u8 *data = (u8 *) buf;
+ loff_t init_off = *off;
+ int err = 0;
+
+ if (*off >= size)
+ return 0;
+ if (*off + count >= size) {
+ size -= *off;
+ count = size;
+ } else
+ size = count;
+
+ while (size) {
+ err = ec_read(*off, &data[*off - init_off]);
+ if (err)
+ return err;
+ *off += 1;
+ size--;
+ }
+ return count;
+}
+
+static ssize_t acpi_ec_write_io(struct file *f, const char __user *buf,
+ size_t count, loff_t *off)
+{
+ /* Use this if support reading/writing multiple ECs exists in ec.c:
+ * struct acpi_ec *ec = ((struct seq_file *)f->private_data)->private;
+ */
+
+ unsigned int size = count;
+ loff_t init_off = *off;
+ u8 *data = (u8 *) buf;
+ int err = 0;
+
+ if (*off >= EC_SPACE_SIZE)
+ return 0;
+ if (*off + count >= EC_SPACE_SIZE) {
+ size = EC_SPACE_SIZE - *off;
+ count = size;
+ }
+
+ while (size) {
+ u8 byte_write = data[*off - init_off];
+ err = ec_write(*off, byte_write);
+ if (err)
+ return err;
+
+ *off += 1;
+ size--;
+ }
+ return count;
+}
+
+static struct file_operations acpi_ec_io_ops = {
+ .owner = THIS_MODULE,
+ .open = acpi_ec_open_io,
+ .read = acpi_ec_read_io,
+ .write = acpi_ec_write_io,
+};
+
+int acpi_ec_add_debugfs(struct acpi_ec *ec, unsigned int ec_device_count)
+{
+ struct dentry *dev_dir;
+ char name[64];
+ mode_t mode = 0400;
+
+ if (ec_device_count == 0) {
+ acpi_ec_debugfs_dir = debugfs_create_dir("ec", NULL);
+ if (!acpi_ec_debugfs_dir)
+ return -ENOMEM;
+ }
+
+ sprintf(name, "ec%u", ec_device_count);
+ dev_dir = debugfs_create_dir(name, acpi_ec_debugfs_dir);
+ if (!dev_dir) {
+ if (ec_device_count != 0)
+ goto error;
+ return -ENOMEM;
+ }
+
+ if (!debugfs_create_x32("gpe", 0444, dev_dir, (u32 *)&first_ec->gpe))
+ goto error;
+ if (!debugfs_create_bool("use_global_lock", 0444, dev_dir,
+ (u32 *)&first_ec->global_lock))
+ goto error;
+
+ if (write_support)
+ mode = 0600;
+ if (!debugfs_create_file("io", mode, dev_dir, ec, &acpi_ec_io_ops))
+ goto error;
+
+ return 0;
+
+error:
+ debugfs_remove_recursive(acpi_ec_debugfs_dir);
+ return -ENOMEM;
+}
+
+static int __init acpi_ec_sys_init(void)
+{
+ int err = 0;
+ if (first_ec)
+ err = acpi_ec_add_debugfs(first_ec, 0);
+ else
+ err = -ENODEV;
+ return err;
+}
+
+static void __exit acpi_ec_sys_exit(void)
+{
+ debugfs_remove_recursive(acpi_ec_debugfs_dir);
+}
+
+module_init(acpi_ec_sys_init);
+module_exit(acpi_ec_sys_exit);
diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h
index f8f190ec066..8ae27264a00 100644
--- a/drivers/acpi/internal.h
+++ b/drivers/acpi/internal.h
@@ -18,6 +18,11 @@
* 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
*/
+#ifndef _ACPI_INTERNAL_H_
+#define _ACPI_INTERNAL_H_
+
+#include <linux/sysdev.h>
+
#define PREFIX "ACPI: "
int init_acpi_device_notify(void);
@@ -46,6 +51,23 @@ void acpi_early_processor_set_pdc(void);
/* --------------------------------------------------------------------------
Embedded Controller
-------------------------------------------------------------------------- */
+struct acpi_ec {
+ acpi_handle handle;
+ unsigned long gpe;
+ unsigned long command_addr;
+ unsigned long data_addr;
+ unsigned long global_lock;
+ unsigned long flags;
+ struct mutex lock;
+ wait_queue_head_t wait;
+ struct list_head list;
+ struct transaction *curr;
+ spinlock_t curr_lock;
+ struct sys_device sysdev;
+};
+
+extern struct acpi_ec *first_ec;
+
int acpi_ec_init(void);
int acpi_ec_ecdt_probe(void);
int acpi_boot_ec_enable(void);
@@ -63,3 +85,5 @@ int acpi_sleep_proc_init(void);
#else
static inline int acpi_sleep_proc_init(void) { return 0; }
#endif
+
+#endif /* _ACPI_INTERNAL_H_ */
diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c
index 78418ce4fc7..f14d3f251d2 100644
--- a/drivers/acpi/osl.c
+++ b/drivers/acpi/osl.c
@@ -191,36 +191,11 @@ acpi_status __init acpi_os_initialize(void)
return AE_OK;
}
-static void bind_to_cpu0(struct work_struct *work)
-{
- set_cpus_allowed_ptr(current, cpumask_of(0));
- kfree(work);
-}
-
-static void bind_workqueue(struct workqueue_struct *wq)
-{
- struct work_struct *work;
-
- work = kzalloc(sizeof(struct work_struct), GFP_KERNEL);
- INIT_WORK(work, bind_to_cpu0);
- queue_work(wq, work);
-}
-
acpi_status acpi_os_initialize1(void)
{
- /*
- * On some machines, a software-initiated SMI causes corruption unless
- * the SMI runs on CPU 0. An SMI can be initiated by any AML, but
- * typically it's done in GPE-related methods that are run via
- * workqueues, so we can avoid the known corruption cases by binding
- * the workqueues to CPU 0.
- */
- kacpid_wq = create_singlethread_workqueue("kacpid");
- bind_workqueue(kacpid_wq);
- kacpi_notify_wq = create_singlethread_workqueue("kacpi_notify");
- bind_workqueue(kacpi_notify_wq);
- kacpi_hotplug_wq = create_singlethread_workqueue("kacpi_hotplug");
- bind_workqueue(kacpi_hotplug_wq);
+ kacpid_wq = create_workqueue("kacpid");
+ kacpi_notify_wq = create_workqueue("kacpi_notify");
+ kacpi_hotplug_wq = create_workqueue("kacpi_hotplug");
BUG_ON(!kacpid_wq);
BUG_ON(!kacpi_notify_wq);
BUG_ON(!kacpi_hotplug_wq);
@@ -766,7 +741,14 @@ static acpi_status __acpi_os_execute(acpi_execute_type type,
else
INIT_WORK(&dpc->work, acpi_os_execute_deferred);
- ret = queue_work(queue, &dpc->work);
+ /*
+ * On some machines, a software-initiated SMI causes corruption unless
+ * the SMI runs on CPU 0. An SMI can be initiated by any AML, but
+ * typically it's done in GPE-related methods that are run via
+ * workqueues, so we can avoid the known corruption cases by always
+ * queueing on CPU 0.
+ */
+ ret = queue_work_on(0, queue, &dpc->work);
if (!ret) {
printk(KERN_ERR PREFIX
@@ -1064,26 +1046,6 @@ static int __init acpi_serialize_setup(char *str)
__setup("acpi_serialize", acpi_serialize_setup);
-/*
- * Wake and Run-Time GPES are expected to be separate.
- * We disable wake-GPEs at run-time to prevent spurious
- * interrupts.
- *
- * However, if a system exists that shares Wake and
- * Run-time events on the same GPE this flag is available
- * to tell Linux to keep the wake-time GPEs enabled at run-time.
- */
-static int __init acpi_wake_gpes_always_on_setup(char *str)
-{
- printk(KERN_INFO PREFIX "wake GPEs not disabled\n");
-
- acpi_gbl_leave_wake_gpes_disabled = FALSE;
-
- return 1;
-}
-
-__setup("acpi_wake_gpes_always_on", acpi_wake_gpes_always_on_setup);
-
/* Check of resource interference between native drivers and ACPI
* OperationRegions (SystemIO and System Memory only).
* IO ports and memory declared in ACPI might be used by the ACPI subsystem
diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c
index 4eac59393ed..1f67057af2a 100644
--- a/drivers/acpi/pci_root.c
+++ b/drivers/acpi/pci_root.c
@@ -33,6 +33,7 @@
#include <linux/pm_runtime.h>
#include <linux/pci.h>
#include <linux/pci-acpi.h>
+#include <linux/pci-aspm.h>
#include <linux/acpi.h>
#include <linux/slab.h>
#include <acpi/acpi_bus.h>
@@ -543,6 +544,14 @@ static int __devinit acpi_pci_root_add(struct acpi_device *device)
if (flags != base_flags)
acpi_pci_osc_support(root, flags);
+ status = acpi_pci_osc_control_set(root->device->handle,
+ OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL);
+
+ if (ACPI_FAILURE(status)) {
+ printk(KERN_INFO "Unable to assume PCIe control: Disabling ASPM\n");
+ pcie_no_aspm();
+ }
+
pci_acpi_add_bus_pm_notifier(device, root->bus);
if (device->wakeup.flags.run_wake)
device_set_run_wake(root->bus->bridge, true);
diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c
index e9a8026d39f..b4c2f3bdade 100644
--- a/drivers/acpi/processor_idle.c
+++ b/drivers/acpi/processor_idle.c
@@ -164,7 +164,7 @@ static void lapic_timer_check_state(int state, struct acpi_processor *pr,
if (cpu_has(&cpu_data(pr->id), X86_FEATURE_ARAT))
return;
- if (boot_cpu_has(X86_FEATURE_AMDC1E))
+ if (c1e_detected)
type = ACPI_STATE_C1;
/*
@@ -264,7 +264,7 @@ int acpi_processor_resume(struct acpi_device * device)
return 0;
}
-#if defined (CONFIG_GENERIC_TIME) && defined (CONFIG_X86)
+#if defined(CONFIG_X86)
static void tsc_check_state(int state)
{
switch (boot_cpu_data.x86_vendor) {
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
index 7f2e051ed4f..b23825ecfa3 100644
--- a/drivers/acpi/scan.c
+++ b/drivers/acpi/scan.c
@@ -740,6 +740,8 @@ acpi_bus_extract_wakeup_device_power_package(struct acpi_device *device,
device->wakeup.resources.handles[i] = element->reference.handle;
}
+ acpi_gpe_can_wake(device->wakeup.gpe_device, device->wakeup.gpe_number);
+
return AE_OK;
}
@@ -764,8 +766,9 @@ static void acpi_bus_set_run_wake_flags(struct acpi_device *device)
return;
}
- status = acpi_get_gpe_status(NULL, device->wakeup.gpe_number,
- &event_status);
+ status = acpi_get_gpe_status(device->wakeup.gpe_device,
+ device->wakeup.gpe_number,
+ &event_status);
if (status == AE_OK)
device->wakeup.flags.run_wake =
!!(event_status & ACPI_EVENT_FLAG_HANDLE);
diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c
index 2862c781b37..e143203254a 100644
--- a/drivers/acpi/sleep.c
+++ b/drivers/acpi/sleep.c
@@ -663,18 +663,9 @@ int acpi_pm_device_sleep_wake(struct device *dev, bool enable)
return -ENODEV;
}
- if (enable) {
- error = acpi_enable_wakeup_device_power(adev,
- acpi_target_sleep_state);
- if (!error)
- acpi_enable_gpe(adev->wakeup.gpe_device,
- adev->wakeup.gpe_number,
- ACPI_GPE_TYPE_WAKE);
- } else {
- acpi_disable_gpe(adev->wakeup.gpe_device, adev->wakeup.gpe_number,
- ACPI_GPE_TYPE_WAKE);
- error = acpi_disable_wakeup_device_power(adev);
- }
+ error = enable ?
+ acpi_enable_wakeup_device_power(adev, acpi_target_sleep_state) :
+ acpi_disable_wakeup_device_power(adev);
if (!error)
dev_info(dev, "wake-up capability %s by ACPI\n",
enable ? "enabled" : "disabled");
diff --git a/drivers/acpi/system.c b/drivers/acpi/system.c
index f8db50a0941..5981bd07e20 100644
--- a/drivers/acpi/system.c
+++ b/drivers/acpi/system.c
@@ -388,12 +388,10 @@ static ssize_t counter_set(struct kobject *kobj,
if (index < num_gpes) {
if (!strcmp(buf, "disable\n") &&
(status & ACPI_EVENT_FLAG_ENABLED))
- result = acpi_disable_gpe(handle, index,
- ACPI_GPE_TYPE_RUNTIME);
+ result = acpi_disable_gpe(handle, index);
else if (!strcmp(buf, "enable\n") &&
!(status & ACPI_EVENT_FLAG_ENABLED))
- result = acpi_enable_gpe(handle, index,
- ACPI_GPE_TYPE_RUNTIME);
+ result = acpi_enable_gpe(handle, index);
else if (!strcmp(buf, "clear\n") &&
(status & ACPI_EVENT_FLAG_SET))
result = acpi_clear_gpe(handle, index);
diff --git a/drivers/acpi/wakeup.c b/drivers/acpi/wakeup.c
index 388747a7ef4..c80537bc323 100644
--- a/drivers/acpi/wakeup.c
+++ b/drivers/acpi/wakeup.c
@@ -64,13 +64,14 @@ void acpi_enable_wakeup_device(u8 sleep_state)
struct acpi_device *dev =
container_of(node, struct acpi_device, wakeup_list);
- if (!dev->wakeup.flags.valid || !dev->wakeup.state.enabled
+ if (!dev->wakeup.flags.valid
+ || !(dev->wakeup.state.enabled || dev->wakeup.prepare_count)
|| sleep_state > (u32) dev->wakeup.sleep_state)
continue;
/* The wake-up power should have been enabled already. */
- acpi_enable_gpe(dev->wakeup.gpe_device, dev->wakeup.gpe_number,
- ACPI_GPE_TYPE_WAKE);
+ acpi_gpe_wakeup(dev->wakeup.gpe_device, dev->wakeup.gpe_number,
+ ACPI_GPE_ENABLE);
}
}
@@ -89,13 +90,16 @@ void acpi_disable_wakeup_device(u8 sleep_state)
struct acpi_device *dev =
container_of(node, struct acpi_device, wakeup_list);
- if (!dev->wakeup.flags.valid || !dev->wakeup.state.enabled
+ if (!dev->wakeup.flags.valid
+ || !(dev->wakeup.state.enabled || dev->wakeup.prepare_count)
|| (sleep_state > (u32) dev->wakeup.sleep_state))
continue;
- acpi_disable_gpe(dev->wakeup.gpe_device, dev->wakeup.gpe_number,
- ACPI_GPE_TYPE_WAKE);
- acpi_disable_wakeup_device_power(dev);
+ acpi_gpe_wakeup(dev->wakeup.gpe_device, dev->wakeup.gpe_number,
+ ACPI_GPE_DISABLE);
+
+ if (dev->wakeup.state.enabled)
+ acpi_disable_wakeup_device_power(dev);
}
}
diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig
index aa85a98d3a4..8fae6afd6a3 100644
--- a/drivers/ata/Kconfig
+++ b/drivers/ata/Kconfig
@@ -187,6 +187,15 @@ config ATA_PIIX
If unsure, say N.
+config SATA_DWC
+ tristate "DesignWare Cores SATA support"
+ depends on 460EX
+ help
+ This option enables support for the on-chip SATA controller of the
+ AppliedMicro processor 460EX.
+
+ If unsure, say N.
+
config SATA_MV
tristate "Marvell SATA support"
help
@@ -796,6 +805,15 @@ config PATA_RZ1000
If unsure, say N.
+config PATA_SAMSUNG_CF
+ tristate "Samsung SoC PATA support"
+ depends on SAMSUNG_DEV_IDE
+ help
+ This option enables basic support for Samsung's S3C/S5P board
+ PATA controllers via the new ATA layer
+
+ If unsure, say N.
+
config PATA_WINBOND_VLB
tristate "Winbond W83759A VLB PATA support (Experimental)"
depends on ISA && EXPERIMENTAL
diff --git a/drivers/ata/Makefile b/drivers/ata/Makefile
index 7ef89d73df6..6540632bda0 100644
--- a/drivers/ata/Makefile
+++ b/drivers/ata/Makefile
@@ -7,6 +7,7 @@ obj-$(CONFIG_SATA_AHCI_PLATFORM) += ahci_platform.o libahci.o
obj-$(CONFIG_SATA_FSL) += sata_fsl.o
obj-$(CONFIG_SATA_INIC162X) += sata_inic162x.o
obj-$(CONFIG_SATA_SIL24) += sata_sil24.o
+obj-$(CONFIG_SATA_DWC) += sata_dwc_460ex.o
# SFF w/ custom DMA
obj-$(CONFIG_PDC_ADMA) += pdc_adma.o
@@ -87,6 +88,7 @@ obj-$(CONFIG_PATA_OF_PLATFORM) += pata_of_platform.o
obj-$(CONFIG_PATA_QDI) += pata_qdi.o
obj-$(CONFIG_PATA_RB532) += pata_rb532_cf.o
obj-$(CONFIG_PATA_RZ1000) += pata_rz1000.o
+obj-$(CONFIG_PATA_SAMSUNG_CF) += pata_samsung_cf.o
obj-$(CONFIG_PATA_WINBOND_VLB) += pata_winbond.o
# Should be last but two libata driver
diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c
index f2522534ae6..fe75d8befc3 100644
--- a/drivers/ata/ahci.c
+++ b/drivers/ata/ahci.c
@@ -1042,7 +1042,7 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
VPRINTK("ENTER\n");
- WARN_ON(ATA_MAX_QUEUE > AHCI_MAX_CMDS);
+ WARN_ON((int)ATA_MAX_QUEUE > AHCI_MAX_CMDS);
if (!printed_version++)
dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
diff --git a/drivers/ata/ahci_platform.c b/drivers/ata/ahci_platform.c
index 5e11b160f24..4e97f33cca4 100644
--- a/drivers/ata/ahci_platform.c
+++ b/drivers/ata/ahci_platform.c
@@ -54,19 +54,13 @@ static int __init ahci_probe(struct platform_device *pdev)
return -EINVAL;
}
- if (pdata && pdata->init) {
- rc = pdata->init(dev);
- if (rc)
- return rc;
- }
-
if (pdata && pdata->ata_port_info)
pi = *pdata->ata_port_info;
hpriv = devm_kzalloc(dev, sizeof(*hpriv), GFP_KERNEL);
if (!hpriv) {
- rc = -ENOMEM;
- goto err0;
+ dev_err(dev, "can't alloc ahci_host_priv\n");
+ return -ENOMEM;
}
hpriv->flags |= (unsigned long)pi.private_data;
@@ -74,8 +68,19 @@ static int __init ahci_probe(struct platform_device *pdev)
hpriv->mmio = devm_ioremap(dev, mem->start, resource_size(mem));
if (!hpriv->mmio) {
dev_err(dev, "can't map %pR\n", mem);
- rc = -ENOMEM;
- goto err0;
+ return -ENOMEM;
+ }
+
+ /*
+ * Some platforms might need to prepare for mmio region access,
+ * which could be done in the following init call. So, the mmio
+ * region shouldn't be accessed before init (if provided) has
+ * returned successfully.
+ */
+ if (pdata && pdata->init) {
+ rc = pdata->init(dev, hpriv->mmio);
+ if (rc)
+ return rc;
}
ahci_save_initial_config(dev, hpriv,
@@ -166,7 +171,6 @@ static int __devexit ahci_remove(struct platform_device *pdev)
}
static struct platform_driver ahci_driver = {
- .probe = ahci_probe,
.remove = __devexit_p(ahci_remove),
.driver = {
.name = "ahci",
diff --git a/drivers/ata/ata_generic.c b/drivers/ata/ata_generic.c
index 7107a6929de..cc5f7726bde 100644
--- a/drivers/ata/ata_generic.c
+++ b/drivers/ata/ata_generic.c
@@ -54,7 +54,6 @@ static int generic_set_mode(struct ata_link *link, struct ata_device **unused)
const struct pci_device_id *id = ap->host->private_data;
int dma_enabled = 0;
struct ata_device *dev;
- struct pci_dev *pdev = to_pci_dev(ap->host->dev);
if (id->driver_data & ATA_GEN_FORCE_DMA) {
dma_enabled = 0xff;
@@ -63,9 +62,6 @@ static int generic_set_mode(struct ata_link *link, struct ata_device **unused)
dma_enabled = ioread8(ap->ioaddr.bmdma_addr + ATA_DMA_STATUS);
}
- if (pdev->vendor == PCI_VENDOR_ID_CENATEK)
- dma_enabled = 0xFF;
-
ata_for_each_dev(dev, link, ENABLED) {
/* We don't really care */
dev->pio_mode = XFER_PIO_0;
diff --git a/drivers/ata/ata_piix.c b/drivers/ata/ata_piix.c
index 7409f98d2ae..3971bc0a483 100644
--- a/drivers/ata/ata_piix.c
+++ b/drivers/ata/ata_piix.c
@@ -158,6 +158,7 @@ struct piix_map_db {
struct piix_host_priv {
const int *map;
u32 saved_iocfg;
+ spinlock_t sidpr_lock; /* FIXME: remove once locking in EH is fixed */
void __iomem *sidpr;
};
@@ -951,12 +952,15 @@ static int piix_sidpr_scr_read(struct ata_link *link,
unsigned int reg, u32 *val)
{
struct piix_host_priv *hpriv = link->ap->host->private_data;
+ unsigned long flags;
if (reg >= ARRAY_SIZE(piix_sidx_map))
return -EINVAL;
+ spin_lock_irqsave(&hpriv->sidpr_lock, flags);
piix_sidpr_sel(link, reg);
*val = ioread32(hpriv->sidpr + PIIX_SIDPR_DATA);
+ spin_unlock_irqrestore(&hpriv->sidpr_lock, flags);
return 0;
}
@@ -964,12 +968,15 @@ static int piix_sidpr_scr_write(struct ata_link *link,
unsigned int reg, u32 val)
{
struct piix_host_priv *hpriv = link->ap->host->private_data;
+ unsigned long flags;
if (reg >= ARRAY_SIZE(piix_sidx_map))
return -EINVAL;
+ spin_lock_irqsave(&hpriv->sidpr_lock, flags);
piix_sidpr_sel(link, reg);
iowrite32(val, hpriv->sidpr + PIIX_SIDPR_DATA);
+ spin_unlock_irqrestore(&hpriv->sidpr_lock, flags);
return 0;
}
@@ -1566,6 +1573,7 @@ static int __devinit piix_init_one(struct pci_dev *pdev,
hpriv = devm_kzalloc(dev, sizeof(*hpriv), GFP_KERNEL);
if (!hpriv)
return -ENOMEM;
+ spin_lock_init(&hpriv->sidpr_lock);
/* Save IOCFG, this will be used for cable detection, quirk
* detection and restoration on detach. This is necessary
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
index ddf8e486278..4972fdf4bd3 100644
--- a/drivers/ata/libata-core.c
+++ b/drivers/ata/libata-core.c
@@ -98,8 +98,6 @@ static unsigned long ata_dev_blacklisted(const struct ata_device *dev);
unsigned int ata_print_id = 1;
-struct workqueue_struct *ata_aux_wq;
-
struct ata_force_param {
const char *name;
unsigned int cbl;
@@ -4167,15 +4165,13 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = {
{ "WDC AC23200L", "21.10N21", ATA_HORKAGE_NODMA },
{ "Compaq CRD-8241B", NULL, ATA_HORKAGE_NODMA },
{ "CRD-8400B", NULL, ATA_HORKAGE_NODMA },
- { "CRD-8480B", NULL, ATA_HORKAGE_NODMA },
- { "CRD-8482B", NULL, ATA_HORKAGE_NODMA },
+ { "CRD-848[02]B", NULL, ATA_HORKAGE_NODMA },
{ "CRD-84", NULL, ATA_HORKAGE_NODMA },
{ "SanDisk SDP3B", NULL, ATA_HORKAGE_NODMA },
{ "SanDisk SDP3B-64", NULL, ATA_HORKAGE_NODMA },
{ "SANYO CD-ROM CRD", NULL, ATA_HORKAGE_NODMA },
{ "HITACHI CDR-8", NULL, ATA_HORKAGE_NODMA },
- { "HITACHI CDR-8335", NULL, ATA_HORKAGE_NODMA },
- { "HITACHI CDR-8435", NULL, ATA_HORKAGE_NODMA },
+ { "HITACHI CDR-8[34]35",NULL, ATA_HORKAGE_NODMA },
{ "Toshiba CD-ROM XM-6202B", NULL, ATA_HORKAGE_NODMA },
{ "TOSHIBA CD-ROM XM-1702BC", NULL, ATA_HORKAGE_NODMA },
{ "CD-532E-A", NULL, ATA_HORKAGE_NODMA },
@@ -4211,70 +4207,16 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = {
{ "OCZ CORE_SSD", "02.10104", ATA_HORKAGE_NONCQ },
/* Seagate NCQ + FLUSH CACHE firmware bug */
- { "ST31500341AS", "SD15", ATA_HORKAGE_NONCQ |
- ATA_HORKAGE_FIRMWARE_WARN },
- { "ST31500341AS", "SD16", ATA_HORKAGE_NONCQ |
- ATA_HORKAGE_FIRMWARE_WARN },
- { "ST31500341AS", "SD17", ATA_HORKAGE_NONCQ |
- ATA_HORKAGE_FIRMWARE_WARN },
- { "ST31500341AS", "SD18", ATA_HORKAGE_NONCQ |
- ATA_HORKAGE_FIRMWARE_WARN },
- { "ST31500341AS", "SD19", ATA_HORKAGE_NONCQ |
- ATA_HORKAGE_FIRMWARE_WARN },
-
- { "ST31000333AS", "SD15", ATA_HORKAGE_NONCQ |
- ATA_HORKAGE_FIRMWARE_WARN },
- { "ST31000333AS", "SD16", ATA_HORKAGE_NONCQ |
- ATA_HORKAGE_FIRMWARE_WARN },
- { "ST31000333AS", "SD17", ATA_HORKAGE_NONCQ |
- ATA_HORKAGE_FIRMWARE_WARN },
- { "ST31000333AS", "SD18", ATA_HORKAGE_NONCQ |
- ATA_HORKAGE_FIRMWARE_WARN },
- { "ST31000333AS", "SD19", ATA_HORKAGE_NONCQ |
- ATA_HORKAGE_FIRMWARE_WARN },
-
- { "ST3640623AS", "SD15", ATA_HORKAGE_NONCQ |
- ATA_HORKAGE_FIRMWARE_WARN },
- { "ST3640623AS", "SD16", ATA_HORKAGE_NONCQ |
- ATA_HORKAGE_FIRMWARE_WARN },
- { "ST3640623AS", "SD17", ATA_HORKAGE_NONCQ |
- ATA_HORKAGE_FIRMWARE_WARN },
- { "ST3640623AS", "SD18", ATA_HORKAGE_NONCQ |
- ATA_HORKAGE_FIRMWARE_WARN },
- { "ST3640623AS", "SD19", ATA_HORKAGE_NONCQ |
+ { "ST31500341AS", "SD1[5-9]", ATA_HORKAGE_NONCQ |
ATA_HORKAGE_FIRMWARE_WARN },
- { "ST3640323AS", "SD15", ATA_HORKAGE_NONCQ |
- ATA_HORKAGE_FIRMWARE_WARN },
- { "ST3640323AS", "SD16", ATA_HORKAGE_NONCQ |
- ATA_HORKAGE_FIRMWARE_WARN },
- { "ST3640323AS", "SD17", ATA_HORKAGE_NONCQ |
- ATA_HORKAGE_FIRMWARE_WARN },
- { "ST3640323AS", "SD18", ATA_HORKAGE_NONCQ |
- ATA_HORKAGE_FIRMWARE_WARN },
- { "ST3640323AS", "SD19", ATA_HORKAGE_NONCQ |
+ { "ST31000333AS", "SD1[5-9]", ATA_HORKAGE_NONCQ |
ATA_HORKAGE_FIRMWARE_WARN },
- { "ST3320813AS", "SD15", ATA_HORKAGE_NONCQ |
- ATA_HORKAGE_FIRMWARE_WARN },
- { "ST3320813AS", "SD16", ATA_HORKAGE_NONCQ |
- ATA_HORKAGE_FIRMWARE_WARN },
- { "ST3320813AS", "SD17", ATA_HORKAGE_NONCQ |
- ATA_HORKAGE_FIRMWARE_WARN },
- { "ST3320813AS", "SD18", ATA_HORKAGE_NONCQ |
- ATA_HORKAGE_FIRMWARE_WARN },
- { "ST3320813AS", "SD19", ATA_HORKAGE_NONCQ |
+ { "ST3640[36]23AS", "SD1[5-9]", ATA_HORKAGE_NONCQ |
ATA_HORKAGE_FIRMWARE_WARN },
- { "ST3320613AS", "SD15", ATA_HORKAGE_NONCQ |
- ATA_HORKAGE_FIRMWARE_WARN },
- { "ST3320613AS", "SD16", ATA_HORKAGE_NONCQ |
- ATA_HORKAGE_FIRMWARE_WARN },
- { "ST3320613AS", "SD17", ATA_HORKAGE_NONCQ |
- ATA_HORKAGE_FIRMWARE_WARN },
- { "ST3320613AS", "SD18", ATA_HORKAGE_NONCQ |
- ATA_HORKAGE_FIRMWARE_WARN },
- { "ST3320613AS", "SD19", ATA_HORKAGE_NONCQ |
+ { "ST3320[68]13AS", "SD1[5-9]", ATA_HORKAGE_NONCQ |
ATA_HORKAGE_FIRMWARE_WARN },
/* Blacklist entries taken from Silicon Image 3124/3132
@@ -4303,12 +4245,7 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = {
/* Devices which get the IVB wrong */
{ "QUANTUM FIREBALLlct10 05", "A03.0900", ATA_HORKAGE_IVB, },
/* Maybe we should just blacklist TSSTcorp... */
- { "TSSTcorp CDDVDW SH-S202H", "SB00", ATA_HORKAGE_IVB, },
- { "TSSTcorp CDDVDW SH-S202H", "SB01", ATA_HORKAGE_IVB, },
- { "TSSTcorp CDDVDW SH-S202J", "SB00", ATA_HORKAGE_IVB, },
- { "TSSTcorp CDDVDW SH-S202J", "SB01", ATA_HORKAGE_IVB, },
- { "TSSTcorp CDDVDW SH-S202N", "SB00", ATA_HORKAGE_IVB, },
- { "TSSTcorp CDDVDW SH-S202N", "SB01", ATA_HORKAGE_IVB, },
+ { "TSSTcorp CDDVDW SH-S202[HJN]", "SB0[01]", ATA_HORKAGE_IVB, },
/* Devices that do not need bridging limits applied */
{ "MTRON MSP-SATA*", NULL, ATA_HORKAGE_BRIDGE_OK, },
@@ -4326,29 +4263,73 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = {
{ }
};
-static int strn_pattern_cmp(const char *patt, const char *name, int wildchar)
+/**
+ * glob_match - match a text string against a glob-style pattern
+ * @text: the string to be examined
+ * @pattern: the glob-style pattern to be matched against
+ *
+ * Either/both of text and pattern can be empty strings.
+ *
+ * Match text against a glob-style pattern, with wildcards and simple sets:
+ *
+ * ? matches any single character.
+ * * matches any run of characters.
+ * [xyz] matches a single character from the set: x, y, or z.
+ * [a-d] matches a single character from the range: a, b, c, or d.
+ * [a-d0-9] matches a single character from either range.
+ *
+ * The special characters ?, [, -, or *, can be matched using a set, eg. [*]
+ * Behaviour with malformed patterns is undefined, though generally reasonable.
+ *
+ * Example patterns: "SD1?", "SD1[0-5]", "*R0", SD*1?[012]*xx"
+ *
+ * This function uses one level of recursion per '*' in pattern.
+ * Since it calls _nothing_ else, and has _no_ explicit local variables,
+ * this will not cause stack problems for any reasonable use here.
+ *
+ * RETURNS:
+ * 0 on match, 1 otherwise.
+ */
+static int glob_match (const char *text, const char *pattern)
{
- const char *p;
- int len;
-
- /*
- * check for trailing wildcard: *\0
- */
- p = strchr(patt, wildchar);
- if (p && ((*(p + 1)) == 0))
- len = p - patt;
- else {
- len = strlen(name);
- if (!len) {
- if (!*patt)
- return 0;
- return -1;
+ do {
+ /* Match single character or a '?' wildcard */
+ if (*text == *pattern || *pattern == '?') {
+ if (!*pattern++)
+ return 0; /* End of both strings: match */
+ } else {
+ /* Match single char against a '[' bracketed ']' pattern set */
+ if (!*text || *pattern != '[')
+ break; /* Not a pattern set */
+ while (*++pattern && *pattern != ']' && *text != *pattern) {
+ if (*pattern == '-' && *(pattern - 1) != '[')
+ if (*text > *(pattern - 1) && *text < *(pattern + 1)) {
+ ++pattern;
+ break;
+ }
+ }
+ if (!*pattern || *pattern == ']')
+ return 1; /* No match */
+ while (*pattern && *pattern++ != ']');
+ }
+ } while (*++text && *pattern);
+
+ /* Match any run of chars against a '*' wildcard */
+ if (*pattern == '*') {
+ if (!*++pattern)
+ return 0; /* Match: avoid recursion at end of pattern */
+ /* Loop to handle additional pattern chars after the wildcard */
+ while (*text) {
+ if (glob_match(text, pattern) == 0)
+ return 0; /* Remainder matched */
+ ++text; /* Absorb (match) this char and try again */
}
}
-
- return strncmp(patt, name, len);
+ if (!*text && !*pattern)
+ return 0; /* End of both strings: match */
+ return 1; /* No match */
}
-
+
static unsigned long ata_dev_blacklisted(const struct ata_device *dev)
{
unsigned char model_num[ATA_ID_PROD_LEN + 1];
@@ -4359,10 +4340,10 @@ static unsigned long ata_dev_blacklisted(const struct ata_device *dev)
ata_id_c_string(dev->id, model_rev, ATA_ID_FW_REV, sizeof(model_rev));
while (ad->model_num) {
- if (!strn_pattern_cmp(ad->model_num, model_num, '*')) {
+ if (!glob_match(model_num, ad->model_num)) {
if (ad->model_rev == NULL)
return ad->horkage;
- if (!strn_pattern_cmp(ad->model_rev, model_rev, '*'))
+ if (!glob_match(model_rev, ad->model_rev))
return ad->horkage;
}
ad++;
@@ -5611,6 +5592,7 @@ struct ata_port *ata_port_alloc(struct ata_host *host)
ap->msg_enable = ATA_MSG_DRV | ATA_MSG_ERR | ATA_MSG_WARN;
#endif
+ mutex_init(&ap->scsi_scan_mutex);
INIT_DELAYED_WORK(&ap->hotplug_task, ata_scsi_hotplug);
INIT_WORK(&ap->scsi_rescan_task, ata_scsi_dev_rescan);
INIT_LIST_HEAD(&ap->eh_done_q);
@@ -6549,29 +6531,20 @@ static int __init ata_init(void)
ata_parse_force_param();
- ata_aux_wq = create_singlethread_workqueue("ata_aux");
- if (!ata_aux_wq)
- goto fail;
-
rc = ata_sff_init();
- if (rc)
- goto fail;
+ if (rc) {
+ kfree(ata_force_tbl);
+ return rc;
+ }
printk(KERN_DEBUG "libata version " DRV_VERSION " loaded.\n");
return 0;
-
-fail:
- kfree(ata_force_tbl);
- if (ata_aux_wq)
- destroy_workqueue(ata_aux_wq);
- return rc;
}
static void __exit ata_exit(void)
{
ata_sff_exit();
kfree(ata_force_tbl);
- destroy_workqueue(ata_aux_wq);
}
subsys_initcall(ata_init);
diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c
index f77a67303f8..c9ae299b834 100644
--- a/drivers/ata/libata-eh.c
+++ b/drivers/ata/libata-eh.c
@@ -727,7 +727,7 @@ void ata_scsi_error(struct Scsi_Host *host)
if (ap->pflags & ATA_PFLAG_LOADING)
ap->pflags &= ~ATA_PFLAG_LOADING;
else if (ap->pflags & ATA_PFLAG_SCSI_HOTPLUG)
- queue_delayed_work(ata_aux_wq, &ap->hotplug_task, 0);
+ schedule_delayed_work(&ap->hotplug_task, 0);
if (ap->pflags & ATA_PFLAG_RECOVERED)
ata_port_printk(ap, KERN_INFO, "EH complete\n");
@@ -2214,6 +2214,7 @@ const char *ata_get_cmd_descript(u8 command)
{ ATA_CMD_SMART, "SMART" },
{ ATA_CMD_MEDIA_LOCK, "DOOR LOCK" },
{ ATA_CMD_MEDIA_UNLOCK, "DOOR UNLOCK" },
+ { ATA_CMD_DSM, "DATA SET MANAGEMENT" },
{ ATA_CMD_CHK_MED_CRD_TYP, "CHECK MEDIA CARD TYPE" },
{ ATA_CMD_CFA_REQ_EXT_ERR, "CFA REQUEST EXTENDED ERROR" },
{ ATA_CMD_CFA_WRITE_NE, "CFA WRITE SECTORS WITHOUT ERASE" },
@@ -2944,7 +2945,7 @@ static int ata_eh_revalidate_and_attach(struct ata_link *link,
ehc->i.flags |= ATA_EHI_SETMODE;
/* schedule the scsi_rescan_device() here */
- queue_work(ata_aux_wq, &(ap->scsi_rescan_task));
+ schedule_work(&(ap->scsi_rescan_task));
} else if (dev->class == ATA_DEV_UNKNOWN &&
ehc->tries[dev->devno] &&
ata_class_enabled(ehc->classes[dev->devno])) {
diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c
index a54273d2c3c..d75c9c479d1 100644
--- a/drivers/ata/libata-scsi.c
+++ b/drivers/ata/libata-scsi.c
@@ -3435,7 +3435,7 @@ void ata_scsi_scan_host(struct ata_port *ap, int sync)
" switching to async\n");
}
- queue_delayed_work(ata_aux_wq, &ap->hotplug_task,
+ queue_delayed_work(system_long_wq, &ap->hotplug_task,
round_jiffies_relative(HZ));
}
@@ -3582,6 +3582,7 @@ void ata_scsi_hotplug(struct work_struct *work)
}
DPRINTK("ENTER\n");
+ mutex_lock(&ap->scsi_scan_mutex);
/* Unplug detached devices. We cannot use link iterator here
* because PMP links have to be scanned even if PMP is
@@ -3595,6 +3596,7 @@ void ata_scsi_hotplug(struct work_struct *work)
/* scan for new ones */
ata_scsi_scan_host(ap, 0);
+ mutex_unlock(&ap->scsi_scan_mutex);
DPRINTK("EXIT\n");
}
@@ -3673,9 +3675,7 @@ static int ata_scsi_user_scan(struct Scsi_Host *shost, unsigned int channel,
* @work: Pointer to ATA port to perform scsi_rescan_device()
*
* After ATA pass thru (SAT) commands are executed successfully,
- * libata need to propagate the changes to SCSI layer. This
- * function must be executed from ata_aux_wq such that sdev
- * attach/detach don't race with rescan.
+ * libata need to propagate the changes to SCSI layer.
*
* LOCKING:
* Kernel thread context (may sleep).
@@ -3688,6 +3688,7 @@ void ata_scsi_dev_rescan(struct work_struct *work)
struct ata_device *dev;
unsigned long flags;
+ mutex_lock(&ap->scsi_scan_mutex);
spin_lock_irqsave(ap->lock, flags);
ata_for_each_link(link, ap, EDGE) {
@@ -3707,6 +3708,7 @@ void ata_scsi_dev_rescan(struct work_struct *work)
}
spin_unlock_irqrestore(ap->lock, flags);
+ mutex_unlock(&ap->scsi_scan_mutex);
}
/**
diff --git a/drivers/ata/libata-sff.c b/drivers/ata/libata-sff.c
index efa4a18cfb9..674c1436491 100644
--- a/drivers/ata/libata-sff.c
+++ b/drivers/ata/libata-sff.c
@@ -3318,14 +3318,7 @@ void ata_sff_port_init(struct ata_port *ap)
int __init ata_sff_init(void)
{
- /*
- * FIXME: In UP case, there is only one workqueue thread and if you
- * have more than one PIO device, latency is bloody awful, with
- * occasional multi-second "hiccups" as one PIO device waits for
- * another. It's an ugly wart that users DO occasionally complain
- * about; luckily most users have at most one PIO polled device.
- */
- ata_sff_wq = create_workqueue("ata_sff");
+ ata_sff_wq = alloc_workqueue("ata_sff", WQ_RESCUER, WQ_MAX_ACTIVE);
if (!ata_sff_wq)
return -ENOMEM;
diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h
index 4b84ed60324..9ce1ecc63e3 100644
--- a/drivers/ata/libata.h
+++ b/drivers/ata/libata.h
@@ -54,7 +54,6 @@ enum {
};
extern unsigned int ata_print_id;
-extern struct workqueue_struct *ata_aux_wq;
extern int atapi_passthru16;
extern int libata_fua;
extern int libata_noacpi;
diff --git a/drivers/ata/pata_pcmcia.c b/drivers/ata/pata_pcmcia.c
index 118c28e8aba..e944aa0c551 100644
--- a/drivers/ata/pata_pcmcia.c
+++ b/drivers/ata/pata_pcmcia.c
@@ -34,7 +34,6 @@
#include <linux/ata.h>
#include <linux/libata.h>
-#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/cistpl.h>
#include <pcmcia/ds.h>
@@ -201,23 +200,25 @@ static int pcmcia_check_one_config(struct pcmcia_device *pdev,
if ((cfg->io.nwin > 0) || (dflt->io.nwin > 0)) {
cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt->io;
- pdev->io.BasePort1 = io->win[0].base;
- pdev->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK;
- if (!(io->flags & CISTPL_IO_16BIT))
- pdev->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
+ pdev->io_lines = io->flags & CISTPL_IO_LINES_MASK;
+ pdev->resource[0]->start = io->win[0].base;
+ if (!(io->flags & CISTPL_IO_16BIT)) {
+ pdev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH;
+ pdev->resource[0]->flags |= IO_DATA_PATH_WIDTH_8;
+ }
if (io->nwin == 2) {
- pdev->io.NumPorts1 = 8;
- pdev->io.BasePort2 = io->win[1].base;
- pdev->io.NumPorts2 = (stk->is_kme) ? 2 : 1;
- if (pcmcia_request_io(pdev, &pdev->io) != 0)
+ pdev->resource[0]->end = 8;
+ pdev->resource[1]->start = io->win[1].base;
+ pdev->resource[1]->end = (stk->is_kme) ? 2 : 1;
+ if (pcmcia_request_io(pdev) != 0)
return -ENODEV;
- stk->ctl_base = pdev->io.BasePort2;
+ stk->ctl_base = pdev->resource[1]->start;
} else if ((io->nwin == 1) && (io->win[0].len >= 16)) {
- pdev->io.NumPorts1 = io->win[0].len;
- pdev->io.NumPorts2 = 0;
- if (pcmcia_request_io(pdev, &pdev->io) != 0)
+ pdev->resource[0]->end = io->win[0].len;
+ pdev->resource[1]->end = 0;
+ if (pcmcia_request_io(pdev) != 0)
return -ENODEV;
- stk->ctl_base = pdev->io.BasePort1 + 0x0e;
+ stk->ctl_base = pdev->resource[0]->start + 0x0e;
} else
return -ENODEV;
/* If we've got this far, we're done */
@@ -246,9 +247,8 @@ static int pcmcia_init_one(struct pcmcia_device *pdev)
struct ata_port_operations *ops = &pcmcia_port_ops;
/* Set up attributes in order to probe card and get resources */
- pdev->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
- pdev->io.Attributes2 = IO_DATA_PATH_WIDTH_8;
- pdev->io.IOAddrLines = 3;
+ pdev->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO;
+ pdev->resource[1]->flags |= IO_DATA_PATH_WIDTH_8;
pdev->conf.Attributes = CONF_ENABLE_IRQ;
pdev->conf.IntType = INT_MEMORY_AND_IO;
@@ -271,7 +271,7 @@ static int pcmcia_init_one(struct pcmcia_device *pdev)
if (pcmcia_loop_config(pdev, pcmcia_check_one_config, stk))
goto failed; /* No suitable config found */
}
- io_base = pdev->io.BasePort1;
+ io_base = pdev->resource[0]->start;
ctl_base = stk->ctl_base;
if (!pdev->irq)
goto failed;
@@ -294,7 +294,7 @@ static int pcmcia_init_one(struct pcmcia_device *pdev)
/* FIXME: Could be more ports at base + 0x10 but we only deal with
one right now */
- if (pdev->io.NumPorts1 >= 0x20)
+ if (resource_size(pdev->resource[0]) >= 0x20)
n_ports = 2;
if (pdev->manf_id == 0x0097 && pdev->card_id == 0x1620)
diff --git a/drivers/ata/pata_samsung_cf.c b/drivers/ata/pata_samsung_cf.c
new file mode 100644
index 00000000000..6f9cfb24b75
--- /dev/null
+++ b/drivers/ata/pata_samsung_cf.c
@@ -0,0 +1,683 @@
+/*
+ * Copyright (c) 2010 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
+ *
+ * PATA driver for Samsung SoCs.
+ * Supports CF Interface in True IDE mode. Currently only PIO mode has been
+ * implemented; UDMA support has to be added.
+ *
+ * Based on:
+ * PATA driver for AT91SAM9260 Static Memory Controller
+ * PATA driver for Toshiba SCC controller
+ *
+ * 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/clk.h>
+#include <linux/libata.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+#include <plat/ata.h>
+#include <plat/regs-ata.h>
+
+#define DRV_NAME "pata_samsung_cf"
+#define DRV_VERSION "0.1"
+
+enum s3c_cpu_type {
+ TYPE_S3C64XX,
+ TYPE_S5PC100,
+ TYPE_S5PV210,
+};
+
+/*
+ * struct s3c_ide_info - S3C PATA instance.
+ * @clk: The clock resource for this controller.
+ * @ide_addr: The area mapped for the hardware registers.
+ * @sfr_addr: The area mapped for the special function registers.
+ * @irq: The IRQ number we are using.
+ * @cpu_type: The exact type of this controller.
+ * @fifo_status_reg: The ATA_FIFO_STATUS register offset.
+ */
+struct s3c_ide_info {
+ struct clk *clk;
+ void __iomem *ide_addr;
+ void __iomem *sfr_addr;
+ unsigned int irq;
+ enum s3c_cpu_type cpu_type;
+ unsigned int fifo_status_reg;
+};
+
+static void pata_s3c_set_endian(void __iomem *s3c_ide_regbase, u8 mode)
+{
+ u32 reg = readl(s3c_ide_regbase + S3C_ATA_CFG);
+ reg = mode ? (reg & ~S3C_ATA_CFG_SWAP) : (reg | S3C_ATA_CFG_SWAP);
+ writel(reg, s3c_ide_regbase + S3C_ATA_CFG);
+}
+
+static void pata_s3c_cfg_mode(void __iomem *s3c_ide_sfrbase)
+{
+ /* Select true-ide as the internal operating mode */
+ writel(readl(s3c_ide_sfrbase + S3C_CFATA_MUX) | S3C_CFATA_MUX_TRUEIDE,
+ s3c_ide_sfrbase + S3C_CFATA_MUX);
+}
+
+static unsigned long
+pata_s3c_setup_timing(struct s3c_ide_info *info, const struct ata_timing *ata)
+{
+ int t1 = ata->setup;
+ int t2 = ata->act8b;
+ int t2i = ata->rec8b;
+ ulong piotime;
+
+ piotime = ((t2i & 0xff) << 12) | ((t2 & 0xff) << 4) | (t1 & 0xf);
+
+ return piotime;
+}
+
+static void pata_s3c_set_piomode(struct ata_port *ap, struct ata_device *adev)
+{
+ struct s3c_ide_info *info = ap->host->private_data;
+ struct ata_timing timing;
+ int cycle_time;
+ ulong ata_cfg = readl(info->ide_addr + S3C_ATA_CFG);
+ ulong piotime;
+
+ /* Enables IORDY if mode requires it */
+ if (ata_pio_need_iordy(adev))
+ ata_cfg |= S3C_ATA_CFG_IORDYEN;
+ else
+ ata_cfg &= ~S3C_ATA_CFG_IORDYEN;
+
+ cycle_time = (int)(1000000000UL / clk_get_rate(info->clk));
+
+ ata_timing_compute(adev, adev->pio_mode, &timing,
+ cycle_time * 1000, 0);
+
+ piotime = pata_s3c_setup_timing(info, &timing);
+
+ writel(ata_cfg, info->ide_addr + S3C_ATA_CFG);
+ writel(piotime, info->ide_addr + S3C_ATA_PIO_TIME);
+}
+
+/*
+ * Waits until the IDE controller is able to perform next read/write
+ * operation to the disk. Needed for 64XX series boards only.
+ */
+static int wait_for_host_ready(struct s3c_ide_info *info)
+{
+ ulong timeout;
+ void __iomem *fifo_reg = info->ide_addr + info->fifo_status_reg;
+
+ /* wait for maximum of 20 msec */
+ timeout = jiffies + msecs_to_jiffies(20);
+ while (time_before(jiffies, timeout)) {
+ if ((readl(fifo_reg) >> 28) == 0)
+ return 0;
+ }
+ return -EBUSY;
+}
+
+/*
+ * Writes to one of the task file registers.
+ */
+static void ata_outb(struct ata_host *host, u8 addr, void __iomem *reg)
+{
+ struct s3c_ide_info *info = host->private_data;
+
+ wait_for_host_ready(info);
+ writeb(addr, reg);
+}
+
+/*
+ * Reads from one of the task file registers.
+ */
+static u8 ata_inb(struct ata_host *host, void __iomem *reg)
+{
+ struct s3c_ide_info *info = host->private_data;
+ u8 temp;
+
+ wait_for_host_ready(info);
+ (void) readb(reg);
+ wait_for_host_ready(info);
+ temp = readb(info->ide_addr + S3C_ATA_PIO_RDATA);
+ return temp;
+}
+
+/*
+ * pata_s3c_tf_load - send taskfile registers to host controller
+ */
+static void pata_s3c_tf_load(struct ata_port *ap,
+ const struct ata_taskfile *tf)
+{
+ struct ata_ioports *ioaddr = &ap->ioaddr;
+ unsigned int is_addr = tf->flags & ATA_TFLAG_ISADDR;
+
+ if (tf->ctl != ap->last_ctl) {
+ ata_outb(ap->host, tf->ctl, ioaddr->ctl_addr);
+ ap->last_ctl = tf->ctl;
+ ata_wait_idle(ap);
+ }
+
+ if (is_addr && (tf->flags & ATA_TFLAG_LBA48)) {
+ ata_outb(ap->host, tf->hob_feature, ioaddr->feature_addr);
+ ata_outb(ap->host, tf->hob_nsect, ioaddr->nsect_addr);
+ ata_outb(ap->host, tf->hob_lbal, ioaddr->lbal_addr);
+ ata_outb(ap->host, tf->hob_lbam, ioaddr->lbam_addr);
+ ata_outb(ap->host, tf->hob_lbah, ioaddr->lbah_addr);
+ }
+
+ if (is_addr) {
+ ata_outb(ap->host, tf->feature, ioaddr->feature_addr);
+ ata_outb(ap->host, tf->nsect, ioaddr->nsect_addr);
+ ata_outb(ap->host, tf->lbal, ioaddr->lbal_addr);
+ ata_outb(ap->host, tf->lbam, ioaddr->lbam_addr);
+ ata_outb(ap->host, tf->lbah, ioaddr->lbah_addr);
+ }
+
+ if (tf->flags & ATA_TFLAG_DEVICE)
+ ata_outb(ap->host, tf->device, ioaddr->device_addr);
+
+ ata_wait_idle(ap);
+}
+
+/*
+ * pata_s3c_tf_read - input device's ATA taskfile shadow registers
+ */
+static void pata_s3c_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
+{
+ struct ata_ioports *ioaddr = &ap->ioaddr;
+
+ tf->feature = ata_inb(ap->host, ioaddr->error_addr);
+ tf->nsect = ata_inb(ap->host, ioaddr->nsect_addr);
+ tf->lbal = ata_inb(ap->host, ioaddr->lbal_addr);
+ tf->lbam = ata_inb(ap->host, ioaddr->lbam_addr);
+ tf->lbah = ata_inb(ap->host, ioaddr->lbah_addr);
+ tf->device = ata_inb(ap->host, ioaddr->device_addr);
+
+ if (tf->flags & ATA_TFLAG_LBA48) {
+ ata_outb(ap->host, tf->ctl | ATA_HOB, ioaddr->ctl_addr);
+ tf->hob_feature = ata_inb(ap->host, ioaddr->error_addr);
+ tf->hob_nsect = ata_inb(ap->host, ioaddr->nsect_addr);
+ tf->hob_lbal = ata_inb(ap->host, ioaddr->lbal_addr);
+ tf->hob_lbam = ata_inb(ap->host, ioaddr->lbam_addr);
+ tf->hob_lbah = ata_inb(ap->host, ioaddr->lbah_addr);
+ ata_outb(ap->host, tf->ctl, ioaddr->ctl_addr);
+ ap->last_ctl = tf->ctl;
+ }
+}
+
+/*
+ * pata_s3c_exec_command - issue ATA command to host controller
+ */
+static void pata_s3c_exec_command(struct ata_port *ap,
+ const struct ata_taskfile *tf)
+{
+ ata_outb(ap->host, tf->command, ap->ioaddr.command_addr);
+ ata_sff_pause(ap);
+}
+
+/*
+ * pata_s3c_check_status - Read device status register
+ */
+static u8 pata_s3c_check_status(struct ata_port *ap)
+{
+ return ata_inb(ap->host, ap->ioaddr.status_addr);
+}
+
+/*
+ * pata_s3c_check_altstatus - Read alternate device status register
+ */
+static u8 pata_s3c_check_altstatus(struct ata_port *ap)
+{
+ return ata_inb(ap->host, ap->ioaddr.altstatus_addr);
+}
+
+/*
+ * pata_s3c_data_xfer - Transfer data by PIO
+ */
+unsigned int pata_s3c_data_xfer(struct ata_device *dev, unsigned char *buf,
+ unsigned int buflen, int rw)
+{
+ struct ata_port *ap = dev->link->ap;
+ struct s3c_ide_info *info = ap->host->private_data;
+ void __iomem *data_addr = ap->ioaddr.data_addr;
+ unsigned int words = buflen >> 1, i;
+ u16 *data_ptr = (u16 *)buf;
+
+ /* Requires wait same as in ata_inb/ata_outb */
+ if (rw == READ)
+ for (i = 0; i < words; i++, data_ptr++) {
+ wait_for_host_ready(info);
+ (void) readw(data_addr);
+ wait_for_host_ready(info);
+ *data_ptr = readw(info->ide_addr
+ + S3C_ATA_PIO_RDATA);
+ }
+ else
+ for (i = 0; i < words; i++, data_ptr++) {
+ wait_for_host_ready(info);
+ writew(*data_ptr, data_addr);
+ }
+
+ if (buflen & 0x01)
+ dev_err(ap->dev, "unexpected trailing data\n");
+
+ return words << 1;
+}
+
+/*
+ * pata_s3c_dev_select - Select device on ATA bus
+ */
+static void pata_s3c_dev_select(struct ata_port *ap, unsigned int device)
+{
+ u8 tmp = ATA_DEVICE_OBS;
+
+ if (device != 0)
+ tmp |= ATA_DEV1;
+
+ ata_outb(ap->host, tmp, ap->ioaddr.device_addr);
+ ata_sff_pause(ap);
+}
+
+/*
+ * pata_s3c_devchk - PATA device presence detection
+ */
+static unsigned int pata_s3c_devchk(struct ata_port *ap,
+ unsigned int device)
+{
+ struct ata_ioports *ioaddr = &ap->ioaddr;
+ u8 nsect, lbal;
+
+ pata_s3c_dev_select(ap, device);
+
+ ata_outb(ap->host, 0x55, ioaddr->nsect_addr);
+ ata_outb(ap->host, 0xaa, ioaddr->lbal_addr);
+
+ ata_outb(ap->host, 0xaa, ioaddr->nsect_addr);
+ ata_outb(ap->host, 0x55, ioaddr->lbal_addr);
+
+ ata_outb(ap->host, 0x55, ioaddr->nsect_addr);
+ ata_outb(ap->host, 0xaa, ioaddr->lbal_addr);
+
+ nsect = ata_inb(ap->host, ioaddr->nsect_addr);
+ lbal = ata_inb(ap->host, ioaddr->lbal_addr);
+
+ if ((nsect == 0x55) && (lbal == 0xaa))
+ return 1; /* we found a device */
+
+ return 0; /* nothing found */
+}
+
+/*
+ * pata_s3c_wait_after_reset - wait for devices to become ready after reset
+ */
+static int pata_s3c_wait_after_reset(struct ata_link *link,
+ unsigned long deadline)
+{
+ int rc;
+
+ msleep(ATA_WAIT_AFTER_RESET);
+
+ /* always check readiness of the master device */
+ rc = ata_sff_wait_ready(link, deadline);
+ /* -ENODEV means the odd clown forgot the D7 pulldown resistor
+ * and TF status is 0xff, bail out on it too.
+ */
+ if (rc)
+ return rc;
+
+ return 0;
+}
+
+/*
+ * pata_s3c_bus_softreset - PATA device software reset
+ */
+static unsigned int pata_s3c_bus_softreset(struct ata_port *ap,
+ unsigned long deadline)
+{
+ struct ata_ioports *ioaddr = &ap->ioaddr;
+
+ /* software reset. causes dev0 to be selected */
+ ata_outb(ap->host, ap->ctl, ioaddr->ctl_addr);
+ udelay(20);
+ ata_outb(ap->host, ap->ctl | ATA_SRST, ioaddr->ctl_addr);
+ udelay(20);
+ ata_outb(ap->host, ap->ctl, ioaddr->ctl_addr);
+ ap->last_ctl = ap->ctl;
+
+ return pata_s3c_wait_after_reset(&ap->link, deadline);
+}
+
+/*
+ * pata_s3c_softreset - reset host port via ATA SRST
+ */
+static int pata_s3c_softreset(struct ata_link *link, unsigned int *classes,
+ unsigned long deadline)
+{
+ struct ata_port *ap = link->ap;
+ unsigned int devmask = 0;
+ int rc;
+ u8 err;
+
+ /* determine if device 0 is present */
+ if (pata_s3c_devchk(ap, 0))
+ devmask |= (1 << 0);
+
+ /* select device 0 again */
+ pata_s3c_dev_select(ap, 0);
+
+ /* issue bus reset */
+ rc = pata_s3c_bus_softreset(ap, deadline);
+ /* if link is occupied, -ENODEV too is an error */
+ if (rc && rc != -ENODEV) {
+ ata_link_printk(link, KERN_ERR, "SRST failed (errno=%d)\n", rc);
+ return rc;
+ }
+
+ /* determine by signature whether we have ATA or ATAPI devices */
+ classes[0] = ata_sff_dev_classify(&ap->link.device[0],
+ devmask & (1 << 0), &err);
+
+ return 0;
+}
+
+/*
+ * pata_s3c_set_devctl - Write device control register
+ */
+static void pata_s3c_set_devctl(struct ata_port *ap, u8 ctl)
+{
+ ata_outb(ap->host, ctl, ap->ioaddr.ctl_addr);
+}
+
+static struct scsi_host_template pata_s3c_sht = {
+ ATA_PIO_SHT(DRV_NAME),
+};
+
+static struct ata_port_operations pata_s3c_port_ops = {
+ .inherits = &ata_sff_port_ops,
+ .sff_check_status = pata_s3c_check_status,
+ .sff_check_altstatus = pata_s3c_check_altstatus,
+ .sff_tf_load = pata_s3c_tf_load,
+ .sff_tf_read = pata_s3c_tf_read,
+ .sff_data_xfer = pata_s3c_data_xfer,
+ .sff_exec_command = pata_s3c_exec_command,
+ .sff_dev_select = pata_s3c_dev_select,
+ .sff_set_devctl = pata_s3c_set_devctl,
+ .softreset = pata_s3c_softreset,
+ .set_piomode = pata_s3c_set_piomode,
+};
+
+static struct ata_port_operations pata_s5p_port_ops = {
+ .inherits = &ata_sff_port_ops,
+ .set_piomode = pata_s3c_set_piomode,
+};
+
+static void pata_s3c_enable(void *s3c_ide_regbase, bool state)
+{
+ u32 temp = readl(s3c_ide_regbase + S3C_ATA_CTRL);
+ temp = state ? (temp | 1) : (temp & ~1);
+ writel(temp, s3c_ide_regbase + S3C_ATA_CTRL);
+}
+
+static irqreturn_t pata_s3c_irq(int irq, void *dev_instance)
+{
+ struct ata_host *host = dev_instance;
+ struct s3c_ide_info *info = host->private_data;
+ u32 reg;
+
+ reg = readl(info->ide_addr + S3C_ATA_IRQ);
+ writel(reg, info->ide_addr + S3C_ATA_IRQ);
+
+ return ata_sff_interrupt(irq, dev_instance);
+}
+
+static void pata_s3c_hwinit(struct s3c_ide_info *info,
+ struct s3c_ide_platdata *pdata)
+{
+ switch (info->cpu_type) {
+ case TYPE_S3C64XX:
+ /* Configure as big endian */
+ pata_s3c_cfg_mode(info->sfr_addr);
+ pata_s3c_set_endian(info->ide_addr, 1);
+ pata_s3c_enable(info->ide_addr, true);
+ msleep(100);
+
+ /* Remove IRQ Status */
+ writel(0x1f, info->ide_addr + S3C_ATA_IRQ);
+ writel(0x1b, info->ide_addr + S3C_ATA_IRQ_MSK);
+ break;
+
+ case TYPE_S5PC100:
+ pata_s3c_cfg_mode(info->sfr_addr);
+ /* FALLTHROUGH */
+
+ case TYPE_S5PV210:
+ /* Configure as little endian */
+ pata_s3c_set_endian(info->ide_addr, 0);
+ pata_s3c_enable(info->ide_addr, true);
+ msleep(100);
+
+ /* Remove IRQ Status */
+ writel(0x3f, info->ide_addr + S3C_ATA_IRQ);
+ writel(0x3f, info->ide_addr + S3C_ATA_IRQ_MSK);
+ break;
+
+ default:
+ BUG();
+ }
+}
+
+static int __init pata_s3c_probe(struct platform_device *pdev)
+{
+ struct s3c_ide_platdata *pdata = pdev->dev.platform_data;
+ struct device *dev = &pdev->dev;
+ struct s3c_ide_info *info;
+ struct resource *res;
+ struct ata_port *ap;
+ struct ata_host *host;
+ enum s3c_cpu_type cpu_type;
+ int ret;
+
+ cpu_type = platform_get_device_id(pdev)->driver_data;
+
+ info = devm_kzalloc(dev, sizeof(*info), GFP_KERNEL);
+ if (!info) {
+ dev_err(dev, "failed to allocate memory for device data\n");
+ return -ENOMEM;
+ }
+
+ info->irq = platform_get_irq(pdev, 0);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (res == NULL) {
+ dev_err(dev, "failed to get mem resource\n");
+ return -EINVAL;
+ }
+
+ if (!devm_request_mem_region(dev, res->start,
+ resource_size(res), DRV_NAME)) {
+ dev_err(dev, "error requesting register region\n");
+ return -EBUSY;
+ }
+
+ info->ide_addr = devm_ioremap(dev, res->start, resource_size(res));
+ if (!info->ide_addr) {
+ dev_err(dev, "failed to map IO base address\n");
+ return -ENOMEM;
+ }
+
+ info->clk = clk_get(&pdev->dev, "cfcon");
+ if (IS_ERR(info->clk)) {
+ dev_err(dev, "failed to get access to cf controller clock\n");
+ ret = PTR_ERR(info->clk);
+ info->clk = NULL;
+ return ret;
+ }
+
+ clk_enable(info->clk);
+
+ /* init ata host */
+ host = ata_host_alloc(dev, 1);
+ if (!host) {
+ dev_err(dev, "failed to allocate ide host\n");
+ ret = -ENOMEM;
+ goto stop_clk;
+ }
+
+ ap = host->ports[0];
+ ap->flags |= ATA_FLAG_MMIO;
+ ap->pio_mask = ATA_PIO4;
+
+ if (cpu_type == TYPE_S3C64XX) {
+ ap->ops = &pata_s3c_port_ops;
+ info->sfr_addr = info->ide_addr + 0x1800;
+ info->ide_addr += 0x1900;
+ info->fifo_status_reg = 0x94;
+ } else if (cpu_type == TYPE_S5PC100) {
+ ap->ops = &pata_s5p_port_ops;
+ info->sfr_addr = info->ide_addr + 0x1800;
+ info->ide_addr += 0x1900;
+ info->fifo_status_reg = 0x84;
+ } else {
+ ap->ops = &pata_s5p_port_ops;
+ info->fifo_status_reg = 0x84;
+ }
+
+ info->cpu_type = cpu_type;
+
+ if (info->irq <= 0) {
+ ap->flags |= ATA_FLAG_PIO_POLLING;
+ info->irq = 0;
+ ata_port_desc(ap, "no IRQ, using PIO polling\n");
+ }
+
+ ap->ioaddr.cmd_addr = info->ide_addr + S3C_ATA_CMD;
+ ap->ioaddr.data_addr = info->ide_addr + S3C_ATA_PIO_DTR;
+ ap->ioaddr.error_addr = info->ide_addr + S3C_ATA_PIO_FED;
+ ap->ioaddr.feature_addr = info->ide_addr + S3C_ATA_PIO_FED;
+ ap->ioaddr.nsect_addr = info->ide_addr + S3C_ATA_PIO_SCR;
+ ap->ioaddr.lbal_addr = info->ide_addr + S3C_ATA_PIO_LLR;
+ ap->ioaddr.lbam_addr = info->ide_addr + S3C_ATA_PIO_LMR;
+ ap->ioaddr.lbah_addr = info->ide_addr + S3C_ATA_PIO_LHR;
+ ap->ioaddr.device_addr = info->ide_addr + S3C_ATA_PIO_DVR;
+ ap->ioaddr.status_addr = info->ide_addr + S3C_ATA_PIO_CSD;
+ ap->ioaddr.command_addr = info->ide_addr + S3C_ATA_PIO_CSD;
+ ap->ioaddr.altstatus_addr = info->ide_addr + S3C_ATA_PIO_DAD;
+ ap->ioaddr.ctl_addr = info->ide_addr + S3C_ATA_PIO_DAD;
+
+ ata_port_desc(ap, "mmio cmd 0x%llx ",
+ (unsigned long long)res->start);
+
+ host->private_data = info;
+
+ if (pdata && pdata->setup_gpio)
+ pdata->setup_gpio();
+
+ /* Set endianness and enable the interface */
+ pata_s3c_hwinit(info, pdata);
+
+ platform_set_drvdata(pdev, host);
+
+ return ata_host_activate(host, info->irq,
+ info->irq ? pata_s3c_irq : NULL,
+ 0, &pata_s3c_sht);
+
+stop_clk:
+ clk_disable(info->clk);
+ clk_put(info->clk);
+ return ret;
+}
+
+static int __exit pata_s3c_remove(struct platform_device *pdev)
+{
+ struct ata_host *host = platform_get_drvdata(pdev);
+ struct s3c_ide_info *info = host->private_data;
+
+ ata_host_detach(host);
+
+ clk_disable(info->clk);
+ clk_put(info->clk);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int pata_s3c_suspend(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct ata_host *host = platform_get_drvdata(pdev);
+
+ return ata_host_suspend(host, PMSG_SUSPEND);
+}
+
+static int pata_s3c_resume(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct ata_host *host = platform_get_drvdata(pdev);
+ struct s3c_ide_platdata *pdata = pdev->dev.platform_data;
+ struct s3c_ide_info *info = host->private_data;
+
+ pata_s3c_hwinit(info, pdata);
+ ata_host_resume(host);
+
+ return 0;
+}
+
+static const struct dev_pm_ops pata_s3c_pm_ops = {
+ .suspend = pata_s3c_suspend,
+ .resume = pata_s3c_resume,
+};
+#endif
+
+/* driver device registration */
+static struct platform_device_id pata_s3c_driver_ids[] = {
+ {
+ .name = "s3c64xx-pata",
+ .driver_data = TYPE_S3C64XX,
+ }, {
+ .name = "s5pc100-pata",
+ .driver_data = TYPE_S5PC100,
+ }, {
+ .name = "s5pv210-pata",
+ .driver_data = TYPE_S5PV210,
+ },
+ { }
+};
+
+MODULE_DEVICE_TABLE(platform, pata_s3c_driver_ids);
+
+static struct platform_driver pata_s3c_driver = {
+ .remove = __exit_p(pata_s3c_remove),
+ .id_table = pata_s3c_driver_ids,
+ .driver = {
+ .name = DRV_NAME,
+ .owner = THIS_MODULE,
+#ifdef CONFIG_PM
+ .pm = &pata_s3c_pm_ops,
+#endif
+ },
+};
+
+static int __init pata_s3c_init(void)
+{
+ return platform_driver_probe(&pata_s3c_driver, pata_s3c_probe);
+}
+
+static void __exit pata_s3c_exit(void)
+{
+ platform_driver_unregister(&pata_s3c_driver);
+}
+
+module_init(pata_s3c_init);
+module_exit(pata_s3c_exit);
+
+MODULE_AUTHOR("Abhilash Kesavan, <a.kesavan@samsung.com>");
+MODULE_DESCRIPTION("low-level driver for Samsung PATA controller");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_VERSION);
diff --git a/drivers/ata/pata_scc.c b/drivers/ata/pata_scc.c
index d9db3f8d60e..fe36966f7e3 100644
--- a/drivers/ata/pata_scc.c
+++ b/drivers/ata/pata_scc.c
@@ -168,8 +168,7 @@ static const unsigned long JCACTSELtbl[2][7] = {
};
static const struct pci_device_id scc_pci_tbl[] = {
- {PCI_VENDOR_ID_TOSHIBA_2, PCI_DEVICE_ID_TOSHIBA_SCC_ATA,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ { PCI_VDEVICE(TOSHIBA_2, PCI_DEVICE_ID_TOSHIBA_SCC_ATA), 0},
{ } /* terminate list */
};
diff --git a/drivers/ata/sata_dwc_460ex.c b/drivers/ata/sata_dwc_460ex.c
new file mode 100644
index 00000000000..ea24c1e51be
--- /dev/null
+++ b/drivers/ata/sata_dwc_460ex.c
@@ -0,0 +1,1756 @@
+/*
+ * drivers/ata/sata_dwc_460ex.c
+ *
+ * Synopsys DesignWare Cores (DWC) SATA host driver
+ *
+ * Author: Mark Miesfeld <mmiesfeld@amcc.com>
+ *
+ * Ported from 2.6.19.2 to 2.6.25/26 by Stefan Roese <sr@denx.de>
+ * Copyright 2008 DENX Software Engineering
+ *
+ * Based on versions provided by AMCC and Synopsys which are:
+ * Copyright 2006 Applied Micro Circuits Corporation
+ * COPYRIGHT (C) 2005 SYNOPSYS, 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.
+ */
+
+#ifdef CONFIG_SATA_DWC_DEBUG
+#define DEBUG
+#endif
+
+#ifdef CONFIG_SATA_DWC_VDEBUG
+#define VERBOSE_DEBUG
+#define DEBUG_NCQ
+#endif
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/libata.h>
+#include <linux/slab.h>
+#include "libata.h"
+
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_cmnd.h>
+
+#define DRV_NAME "sata-dwc"
+#define DRV_VERSION "1.0"
+
+/* SATA DMA driver Globals */
+#define DMA_NUM_CHANS 1
+#define DMA_NUM_CHAN_REGS 8
+
+/* SATA DMA Register definitions */
+#define AHB_DMA_BRST_DFLT 64 /* 16 data items burst length*/
+
+struct dmareg {
+ u32 low; /* Low bits 0-31 */
+ u32 high; /* High bits 32-63 */
+};
+
+/* DMA Per Channel registers */
+struct dma_chan_regs {
+ struct dmareg sar; /* Source Address */
+ struct dmareg dar; /* Destination address */
+ struct dmareg llp; /* Linked List Pointer */
+ struct dmareg ctl; /* Control */
+ struct dmareg sstat; /* Source Status not implemented in core */
+ struct dmareg dstat; /* Destination Status not implemented in core*/
+ struct dmareg sstatar; /* Source Status Address not impl in core */
+ struct dmareg dstatar; /* Destination Status Address not implemente */
+ struct dmareg cfg; /* Config */
+ struct dmareg sgr; /* Source Gather */
+ struct dmareg dsr; /* Destination Scatter */
+};
+
+/* Generic Interrupt Registers */
+struct dma_interrupt_regs {
+ struct dmareg tfr; /* Transfer Interrupt */
+ struct dmareg block; /* Block Interrupt */
+ struct dmareg srctran; /* Source Transfer Interrupt */
+ struct dmareg dsttran; /* Dest Transfer Interrupt */
+ struct dmareg error; /* Error */
+};
+
+struct ahb_dma_regs {
+ struct dma_chan_regs chan_regs[DMA_NUM_CHAN_REGS];
+ struct dma_interrupt_regs interrupt_raw; /* Raw Interrupt */
+ struct dma_interrupt_regs interrupt_status; /* Interrupt Status */
+ struct dma_interrupt_regs interrupt_mask; /* Interrupt Mask */
+ struct dma_interrupt_regs interrupt_clear; /* Interrupt Clear */
+ struct dmareg statusInt; /* Interrupt combined*/
+ struct dmareg rq_srcreg; /* Src Trans Req */
+ struct dmareg rq_dstreg; /* Dst Trans Req */
+ struct dmareg rq_sgl_srcreg; /* Sngl Src Trans Req*/
+ struct dmareg rq_sgl_dstreg; /* Sngl Dst Trans Req*/
+ struct dmareg rq_lst_srcreg; /* Last Src Trans Req*/
+ struct dmareg rq_lst_dstreg; /* Last Dst Trans Req*/
+ struct dmareg dma_cfg; /* DMA Config */
+ struct dmareg dma_chan_en; /* DMA Channel Enable*/
+ struct dmareg dma_id; /* DMA ID */
+ struct dmareg dma_test; /* DMA Test */
+ struct dmareg res1; /* reserved */
+ struct dmareg res2; /* reserved */
+ /*
+ * DMA Comp Params
+ * Param 6 = dma_param[0], Param 5 = dma_param[1],
+ * Param 4 = dma_param[2] ...
+ */
+ struct dmareg dma_params[6];
+};
+
+/* Data structure for linked list item */
+struct lli {
+ u32 sar; /* Source Address */
+ u32 dar; /* Destination address */
+ u32 llp; /* Linked List Pointer */
+ struct dmareg ctl; /* Control */
+ struct dmareg dstat; /* Destination Status */
+};
+
+enum {
+ SATA_DWC_DMAC_LLI_SZ = (sizeof(struct lli)),
+ SATA_DWC_DMAC_LLI_NUM = 256,
+ SATA_DWC_DMAC_LLI_TBL_SZ = (SATA_DWC_DMAC_LLI_SZ * \
+ SATA_DWC_DMAC_LLI_NUM),
+ SATA_DWC_DMAC_TWIDTH_BYTES = 4,
+ SATA_DWC_DMAC_CTRL_TSIZE_MAX = (0x00000800 * \
+ SATA_DWC_DMAC_TWIDTH_BYTES),
+};
+
+/* DMA Register Operation Bits */
+enum {
+ DMA_EN = 0x00000001, /* Enable AHB DMA */
+ DMA_CTL_LLP_SRCEN = 0x10000000, /* Blk chain enable Src */
+ DMA_CTL_LLP_DSTEN = 0x08000000, /* Blk chain enable Dst */
+};
+
+#define DMA_CTL_BLK_TS(size) ((size) & 0x000000FFF) /* Blk Transfer size */
+#define DMA_CHANNEL(ch) (0x00000001 << (ch)) /* Select channel */
+ /* Enable channel */
+#define DMA_ENABLE_CHAN(ch) ((0x00000001 << (ch)) | \
+ ((0x000000001 << (ch)) << 8))
+ /* Disable channel */
+#define DMA_DISABLE_CHAN(ch) (0x00000000 | ((0x000000001 << (ch)) << 8))
+ /* Transfer Type & Flow Controller */
+#define DMA_CTL_TTFC(type) (((type) & 0x7) << 20)
+#define DMA_CTL_SMS(num) (((num) & 0x3) << 25) /* Src Master Select */
+#define DMA_CTL_DMS(num) (((num) & 0x3) << 23)/* Dst Master Select */
+ /* Src Burst Transaction Length */
+#define DMA_CTL_SRC_MSIZE(size) (((size) & 0x7) << 14)
+ /* Dst Burst Transaction Length */
+#define DMA_CTL_DST_MSIZE(size) (((size) & 0x7) << 11)
+ /* Source Transfer Width */
+#define DMA_CTL_SRC_TRWID(size) (((size) & 0x7) << 4)
+ /* Destination Transfer Width */
+#define DMA_CTL_DST_TRWID(size) (((size) & 0x7) << 1)
+
+/* Assign HW handshaking interface (x) to destination / source peripheral */
+#define DMA_CFG_HW_HS_DEST(int_num) (((int_num) & 0xF) << 11)
+#define DMA_CFG_HW_HS_SRC(int_num) (((int_num) & 0xF) << 7)
+#define DMA_LLP_LMS(addr, master) (((addr) & 0xfffffffc) | (master))
+
+/*
+ * This define is used to set block chaining disabled in the control low
+ * register. It is already in little endian format so it can be &'d dirctly.
+ * It is essentially: cpu_to_le32(~(DMA_CTL_LLP_SRCEN | DMA_CTL_LLP_DSTEN))
+ */
+enum {
+ DMA_CTL_LLP_DISABLE_LE32 = 0xffffffe7,
+ DMA_CTL_TTFC_P2M_DMAC = 0x00000002, /* Per to mem, DMAC cntr */
+ DMA_CTL_TTFC_M2P_PER = 0x00000003, /* Mem to per, peripheral cntr */
+ DMA_CTL_SINC_INC = 0x00000000, /* Source Address Increment */
+ DMA_CTL_SINC_DEC = 0x00000200,
+ DMA_CTL_SINC_NOCHANGE = 0x00000400,
+ DMA_CTL_DINC_INC = 0x00000000, /* Destination Address Increment */
+ DMA_CTL_DINC_DEC = 0x00000080,
+ DMA_CTL_DINC_NOCHANGE = 0x00000100,
+ DMA_CTL_INT_EN = 0x00000001, /* Interrupt Enable */
+
+/* Channel Configuration Register high bits */
+ DMA_CFG_FCMOD_REQ = 0x00000001, /* Flow Control - request based */
+ DMA_CFG_PROTCTL = (0x00000003 << 2),/* Protection Control */
+
+/* Channel Configuration Register low bits */
+ DMA_CFG_RELD_DST = 0x80000000, /* Reload Dest / Src Addr */
+ DMA_CFG_RELD_SRC = 0x40000000,
+ DMA_CFG_HS_SELSRC = 0x00000800, /* Software handshake Src/ Dest */
+ DMA_CFG_HS_SELDST = 0x00000400,
+ DMA_CFG_FIFOEMPTY = (0x00000001 << 9), /* FIFO Empty bit */
+
+/* Channel Linked List Pointer Register */
+ DMA_LLP_AHBMASTER1 = 0, /* List Master Select */
+ DMA_LLP_AHBMASTER2 = 1,
+
+ SATA_DWC_MAX_PORTS = 1,
+
+ SATA_DWC_SCR_OFFSET = 0x24,
+ SATA_DWC_REG_OFFSET = 0x64,
+};
+
+/* DWC SATA Registers */
+struct sata_dwc_regs {
+ u32 fptagr; /* 1st party DMA tag */
+ u32 fpbor; /* 1st party DMA buffer offset */
+ u32 fptcr; /* 1st party DMA Xfr count */
+ u32 dmacr; /* DMA Control */
+ u32 dbtsr; /* DMA Burst Transac size */
+ u32 intpr; /* Interrupt Pending */
+ u32 intmr; /* Interrupt Mask */
+ u32 errmr; /* Error Mask */
+ u32 llcr; /* Link Layer Control */
+ u32 phycr; /* PHY Control */
+ u32 physr; /* PHY Status */
+ u32 rxbistpd; /* Recvd BIST pattern def register */
+ u32 rxbistpd1; /* Recvd BIST data dword1 */
+ u32 rxbistpd2; /* Recvd BIST pattern data dword2 */
+ u32 txbistpd; /* Trans BIST pattern def register */
+ u32 txbistpd1; /* Trans BIST data dword1 */
+ u32 txbistpd2; /* Trans BIST data dword2 */
+ u32 bistcr; /* BIST Control Register */
+ u32 bistfctr; /* BIST FIS Count Register */
+ u32 bistsr; /* BIST Status Register */
+ u32 bistdecr; /* BIST Dword Error count register */
+ u32 res[15]; /* Reserved locations */
+ u32 testr; /* Test Register */
+ u32 versionr; /* Version Register */
+ u32 idr; /* ID Register */
+ u32 unimpl[192]; /* Unimplemented */
+ u32 dmadr[256]; /* FIFO Locations in DMA Mode */
+};
+
+enum {
+ SCR_SCONTROL_DET_ENABLE = 0x00000001,
+ SCR_SSTATUS_DET_PRESENT = 0x00000001,
+ SCR_SERROR_DIAG_X = 0x04000000,
+/* DWC SATA Register Operations */
+ SATA_DWC_TXFIFO_DEPTH = 0x01FF,
+ SATA_DWC_RXFIFO_DEPTH = 0x01FF,
+ SATA_DWC_DMACR_TMOD_TXCHEN = 0x00000004,
+ SATA_DWC_DMACR_TXCHEN = (0x00000001 | SATA_DWC_DMACR_TMOD_TXCHEN),
+ SATA_DWC_DMACR_RXCHEN = (0x00000002 | SATA_DWC_DMACR_TMOD_TXCHEN),
+ SATA_DWC_DMACR_TXRXCH_CLEAR = SATA_DWC_DMACR_TMOD_TXCHEN,
+ SATA_DWC_INTPR_DMAT = 0x00000001,
+ SATA_DWC_INTPR_NEWFP = 0x00000002,
+ SATA_DWC_INTPR_PMABRT = 0x00000004,
+ SATA_DWC_INTPR_ERR = 0x00000008,
+ SATA_DWC_INTPR_NEWBIST = 0x00000010,
+ SATA_DWC_INTPR_IPF = 0x10000000,
+ SATA_DWC_INTMR_DMATM = 0x00000001,
+ SATA_DWC_INTMR_NEWFPM = 0x00000002,
+ SATA_DWC_INTMR_PMABRTM = 0x00000004,
+ SATA_DWC_INTMR_ERRM = 0x00000008,
+ SATA_DWC_INTMR_NEWBISTM = 0x00000010,
+ SATA_DWC_LLCR_SCRAMEN = 0x00000001,
+ SATA_DWC_LLCR_DESCRAMEN = 0x00000002,
+ SATA_DWC_LLCR_RPDEN = 0x00000004,
+/* This is all error bits, zero's are reserved fields. */
+ SATA_DWC_SERROR_ERR_BITS = 0x0FFF0F03
+};
+
+#define SATA_DWC_SCR0_SPD_GET(v) (((v) >> 4) & 0x0000000F)
+#define SATA_DWC_DMACR_TX_CLEAR(v) (((v) & ~SATA_DWC_DMACR_TXCHEN) |\
+ SATA_DWC_DMACR_TMOD_TXCHEN)
+#define SATA_DWC_DMACR_RX_CLEAR(v) (((v) & ~SATA_DWC_DMACR_RXCHEN) |\
+ SATA_DWC_DMACR_TMOD_TXCHEN)
+#define SATA_DWC_DBTSR_MWR(size) (((size)/4) & SATA_DWC_TXFIFO_DEPTH)
+#define SATA_DWC_DBTSR_MRD(size) ((((size)/4) & SATA_DWC_RXFIFO_DEPTH)\
+ << 16)
+struct sata_dwc_device {
+ struct device *dev; /* generic device struct */
+ struct ata_probe_ent *pe; /* ptr to probe-ent */
+ struct ata_host *host;
+ u8 *reg_base;
+ struct sata_dwc_regs *sata_dwc_regs; /* DW Synopsys SATA specific */
+ int irq_dma;
+};
+
+#define SATA_DWC_QCMD_MAX 32
+
+struct sata_dwc_device_port {
+ struct sata_dwc_device *hsdev;
+ int cmd_issued[SATA_DWC_QCMD_MAX];
+ struct lli *llit[SATA_DWC_QCMD_MAX]; /* DMA LLI table */
+ dma_addr_t llit_dma[SATA_DWC_QCMD_MAX];
+ u32 dma_chan[SATA_DWC_QCMD_MAX];
+ int dma_pending[SATA_DWC_QCMD_MAX];
+};
+
+/*
+ * Commonly used DWC SATA driver Macros
+ */
+#define HSDEV_FROM_HOST(host) ((struct sata_dwc_device *)\
+ (host)->private_data)
+#define HSDEV_FROM_AP(ap) ((struct sata_dwc_device *)\
+ (ap)->host->private_data)
+#define HSDEVP_FROM_AP(ap) ((struct sata_dwc_device_port *)\
+ (ap)->private_data)
+#define HSDEV_FROM_QC(qc) ((struct sata_dwc_device *)\
+ (qc)->ap->host->private_data)
+#define HSDEV_FROM_HSDEVP(p) ((struct sata_dwc_device *)\
+ (hsdevp)->hsdev)
+
+enum {
+ SATA_DWC_CMD_ISSUED_NOT = 0,
+ SATA_DWC_CMD_ISSUED_PEND = 1,
+ SATA_DWC_CMD_ISSUED_EXEC = 2,
+ SATA_DWC_CMD_ISSUED_NODATA = 3,
+
+ SATA_DWC_DMA_PENDING_NONE = 0,
+ SATA_DWC_DMA_PENDING_TX = 1,
+ SATA_DWC_DMA_PENDING_RX = 2,
+};
+
+struct sata_dwc_host_priv {
+ void __iomem *scr_addr_sstatus;
+ u32 sata_dwc_sactive_issued ;
+ u32 sata_dwc_sactive_queued ;
+ u32 dma_interrupt_count;
+ struct ahb_dma_regs *sata_dma_regs;
+ struct device *dwc_dev;
+};
+struct sata_dwc_host_priv host_pvt;
+/*
+ * Prototypes
+ */
+static void sata_dwc_bmdma_start_by_tag(struct ata_queued_cmd *qc, u8 tag);
+static int sata_dwc_qc_complete(struct ata_port *ap, struct ata_queued_cmd *qc,
+ u32 check_status);
+static void sata_dwc_dma_xfer_complete(struct ata_port *ap, u32 check_status);
+static void sata_dwc_port_stop(struct ata_port *ap);
+static void sata_dwc_clear_dmacr(struct sata_dwc_device_port *hsdevp, u8 tag);
+static int dma_dwc_init(struct sata_dwc_device *hsdev, int irq);
+static void dma_dwc_exit(struct sata_dwc_device *hsdev);
+static int dma_dwc_xfer_setup(struct scatterlist *sg, int num_elems,
+ struct lli *lli, dma_addr_t dma_lli,
+ void __iomem *addr, int dir);
+static void dma_dwc_xfer_start(int dma_ch);
+
+static void sata_dwc_tf_dump(struct ata_taskfile *tf)
+{
+ dev_vdbg(host_pvt.dwc_dev, "taskfile cmd: 0x%02x protocol: %s flags:"
+ "0x%lx device: %x\n", tf->command, ata_get_cmd_descript\
+ (tf->protocol), tf->flags, tf->device);
+ dev_vdbg(host_pvt.dwc_dev, "feature: 0x%02x nsect: 0x%x lbal: 0x%x "
+ "lbam: 0x%x lbah: 0x%x\n", tf->feature, tf->nsect, tf->lbal,
+ tf->lbam, tf->lbah);
+ dev_vdbg(host_pvt.dwc_dev, "hob_feature: 0x%02x hob_nsect: 0x%x "
+ "hob_lbal: 0x%x hob_lbam: 0x%x hob_lbah: 0x%x\n",
+ tf->hob_feature, tf->hob_nsect, tf->hob_lbal, tf->hob_lbam,
+ tf->hob_lbah);
+}
+
+/*
+ * Function: get_burst_length_encode
+ * arguments: datalength: length in bytes of data
+ * returns value to be programmed in register corrresponding to data length
+ * This value is effectively the log(base 2) of the length
+ */
+static int get_burst_length_encode(int datalength)
+{
+ int items = datalength >> 2; /* div by 4 to get lword count */
+
+ if (items >= 64)
+ return 5;
+
+ if (items >= 32)
+ return 4;
+
+ if (items >= 16)
+ return 3;
+
+ if (items >= 8)
+ return 2;
+
+ if (items >= 4)
+ return 1;
+
+ return 0;
+}
+
+static void clear_chan_interrupts(int c)
+{
+ out_le32(&(host_pvt.sata_dma_regs->interrupt_clear.tfr.low),
+ DMA_CHANNEL(c));
+ out_le32(&(host_pvt.sata_dma_regs->interrupt_clear.block.low),
+ DMA_CHANNEL(c));
+ out_le32(&(host_pvt.sata_dma_regs->interrupt_clear.srctran.low),
+ DMA_CHANNEL(c));
+ out_le32(&(host_pvt.sata_dma_regs->interrupt_clear.dsttran.low),
+ DMA_CHANNEL(c));
+ out_le32(&(host_pvt.sata_dma_regs->interrupt_clear.error.low),
+ DMA_CHANNEL(c));
+}
+
+/*
+ * Function: dma_request_channel
+ * arguments: None
+ * returns channel number if available else -1
+ * This function assigns the next available DMA channel from the list to the
+ * requester
+ */
+static int dma_request_channel(void)
+{
+ int i;
+
+ for (i = 0; i < DMA_NUM_CHANS; i++) {
+ if (!(in_le32(&(host_pvt.sata_dma_regs->dma_chan_en.low)) &\
+ DMA_CHANNEL(i)))
+ return i;
+ }
+ dev_err(host_pvt.dwc_dev, "%s NO channel chan_en: 0x%08x\n", __func__,
+ in_le32(&(host_pvt.sata_dma_regs->dma_chan_en.low)));
+ return -1;
+}
+
+/*
+ * Function: dma_dwc_interrupt
+ * arguments: irq, dev_id, pt_regs
+ * returns channel number if available else -1
+ * Interrupt Handler for DW AHB SATA DMA
+ */
+static irqreturn_t dma_dwc_interrupt(int irq, void *hsdev_instance)
+{
+ int chan;
+ u32 tfr_reg, err_reg;
+ unsigned long flags;
+ struct sata_dwc_device *hsdev =
+ (struct sata_dwc_device *)hsdev_instance;
+ struct ata_host *host = (struct ata_host *)hsdev->host;
+ struct ata_port *ap;
+ struct sata_dwc_device_port *hsdevp;
+ u8 tag = 0;
+ unsigned int port = 0;
+
+ spin_lock_irqsave(&host->lock, flags);
+ ap = host->ports[port];
+ hsdevp = HSDEVP_FROM_AP(ap);
+ tag = ap->link.active_tag;
+
+ tfr_reg = in_le32(&(host_pvt.sata_dma_regs->interrupt_status.tfr\
+ .low));
+ err_reg = in_le32(&(host_pvt.sata_dma_regs->interrupt_status.error\
+ .low));
+
+ dev_dbg(ap->dev, "eot=0x%08x err=0x%08x pending=%d active port=%d\n",
+ tfr_reg, err_reg, hsdevp->dma_pending[tag], port);
+
+ for (chan = 0; chan < DMA_NUM_CHANS; chan++) {
+ /* Check for end-of-transfer interrupt. */
+ if (tfr_reg & DMA_CHANNEL(chan)) {
+ /*
+ * Each DMA command produces 2 interrupts. Only
+ * complete the command after both interrupts have been
+ * seen. (See sata_dwc_isr())
+ */
+ host_pvt.dma_interrupt_count++;
+ sata_dwc_clear_dmacr(hsdevp, tag);
+
+ if (hsdevp->dma_pending[tag] ==
+ SATA_DWC_DMA_PENDING_NONE) {
+ dev_err(ap->dev, "DMA not pending eot=0x%08x "
+ "err=0x%08x tag=0x%02x pending=%d\n",
+ tfr_reg, err_reg, tag,
+ hsdevp->dma_pending[tag]);
+ }
+
+ if ((host_pvt.dma_interrupt_count % 2) == 0)
+ sata_dwc_dma_xfer_complete(ap, 1);
+
+ /* Clear the interrupt */
+ out_le32(&(host_pvt.sata_dma_regs->interrupt_clear\
+ .tfr.low),
+ DMA_CHANNEL(chan));
+ }
+
+ /* Check for error interrupt. */
+ if (err_reg & DMA_CHANNEL(chan)) {
+ /* TODO Need error handler ! */
+ dev_err(ap->dev, "error interrupt err_reg=0x%08x\n",
+ err_reg);
+
+ /* Clear the interrupt. */
+ out_le32(&(host_pvt.sata_dma_regs->interrupt_clear\
+ .error.low),
+ DMA_CHANNEL(chan));
+ }
+ }
+ spin_unlock_irqrestore(&host->lock, flags);
+ return IRQ_HANDLED;
+}
+
+/*
+ * Function: dma_request_interrupts
+ * arguments: hsdev
+ * returns status
+ * This function registers ISR for a particular DMA channel interrupt
+ */
+static int dma_request_interrupts(struct sata_dwc_device *hsdev, int irq)
+{
+ int retval = 0;
+ int chan;
+
+ for (chan = 0; chan < DMA_NUM_CHANS; chan++) {
+ /* Unmask error interrupt */
+ out_le32(&(host_pvt.sata_dma_regs)->interrupt_mask.error.low,
+ DMA_ENABLE_CHAN(chan));
+
+ /* Unmask end-of-transfer interrupt */
+ out_le32(&(host_pvt.sata_dma_regs)->interrupt_mask.tfr.low,
+ DMA_ENABLE_CHAN(chan));
+ }
+
+ retval = request_irq(irq, dma_dwc_interrupt, 0, "SATA DMA", hsdev);
+ if (retval) {
+ dev_err(host_pvt.dwc_dev, "%s: could not get IRQ %d\n",
+ __func__, irq);
+ return -ENODEV;
+ }
+
+ /* Mark this interrupt as requested */
+ hsdev->irq_dma = irq;
+ return 0;
+}
+
+/*
+ * Function: map_sg_to_lli
+ * The Synopsis driver has a comment proposing that better performance
+ * is possible by only enabling interrupts on the last item in the linked list.
+ * However, it seems that could be a problem if an error happened on one of the
+ * first items. The transfer would halt, but no error interrupt would occur.
+ * Currently this function sets interrupts enabled for each linked list item:
+ * DMA_CTL_INT_EN.
+ */
+static int map_sg_to_lli(struct scatterlist *sg, int num_elems,
+ struct lli *lli, dma_addr_t dma_lli,
+ void __iomem *dmadr_addr, int dir)
+{
+ int i, idx = 0;
+ int fis_len = 0;
+ dma_addr_t next_llp;
+ int bl;
+
+ dev_dbg(host_pvt.dwc_dev, "%s: sg=%p nelem=%d lli=%p dma_lli=0x%08x"
+ " dmadr=0x%08x\n", __func__, sg, num_elems, lli, (u32)dma_lli,
+ (u32)dmadr_addr);
+
+ bl = get_burst_length_encode(AHB_DMA_BRST_DFLT);
+
+ for (i = 0; i < num_elems; i++, sg++) {
+ u32 addr, offset;
+ u32 sg_len, len;
+
+ addr = (u32) sg_dma_address(sg);
+ sg_len = sg_dma_len(sg);
+
+ dev_dbg(host_pvt.dwc_dev, "%s: elem=%d sg_addr=0x%x sg_len"
+ "=%d\n", __func__, i, addr, sg_len);
+
+ while (sg_len) {
+ if (idx >= SATA_DWC_DMAC_LLI_NUM) {
+ /* The LLI table is not large enough. */
+ dev_err(host_pvt.dwc_dev, "LLI table overrun "
+ "(idx=%d)\n", idx);
+ break;
+ }
+ len = (sg_len > SATA_DWC_DMAC_CTRL_TSIZE_MAX) ?
+ SATA_DWC_DMAC_CTRL_TSIZE_MAX : sg_len;
+
+ offset = addr & 0xffff;
+ if ((offset + sg_len) > 0x10000)
+ len = 0x10000 - offset;
+
+ /*
+ * Make sure a LLI block is not created that will span
+ * 8K max FIS boundary. If the block spans such a FIS
+ * boundary, there is a chance that a DMA burst will
+ * cross that boundary -- this results in an error in
+ * the host controller.
+ */
+ if (fis_len + len > 8192) {
+ dev_dbg(host_pvt.dwc_dev, "SPLITTING: fis_len="
+ "%d(0x%x) len=%d(0x%x)\n", fis_len,
+ fis_len, len, len);
+ len = 8192 - fis_len;
+ fis_len = 0;
+ } else {
+ fis_len += len;
+ }
+ if (fis_len == 8192)
+ fis_len = 0;
+
+ /*
+ * Set DMA addresses and lower half of control register
+ * based on direction.
+ */
+ if (dir == DMA_FROM_DEVICE) {
+ lli[idx].dar = cpu_to_le32(addr);
+ lli[idx].sar = cpu_to_le32((u32)dmadr_addr);
+
+ lli[idx].ctl.low = cpu_to_le32(
+ DMA_CTL_TTFC(DMA_CTL_TTFC_P2M_DMAC) |
+ DMA_CTL_SMS(0) |
+ DMA_CTL_DMS(1) |
+ DMA_CTL_SRC_MSIZE(bl) |
+ DMA_CTL_DST_MSIZE(bl) |
+ DMA_CTL_SINC_NOCHANGE |
+ DMA_CTL_SRC_TRWID(2) |
+ DMA_CTL_DST_TRWID(2) |
+ DMA_CTL_INT_EN |
+ DMA_CTL_LLP_SRCEN |
+ DMA_CTL_LLP_DSTEN);
+ } else { /* DMA_TO_DEVICE */
+ lli[idx].sar = cpu_to_le32(addr);
+ lli[idx].dar = cpu_to_le32((u32)dmadr_addr);
+
+ lli[idx].ctl.low = cpu_to_le32(
+ DMA_CTL_TTFC(DMA_CTL_TTFC_M2P_PER) |
+ DMA_CTL_SMS(1) |
+ DMA_CTL_DMS(0) |
+ DMA_CTL_SRC_MSIZE(bl) |
+ DMA_CTL_DST_MSIZE(bl) |
+ DMA_CTL_DINC_NOCHANGE |
+ DMA_CTL_SRC_TRWID(2) |
+ DMA_CTL_DST_TRWID(2) |
+ DMA_CTL_INT_EN |
+ DMA_CTL_LLP_SRCEN |
+ DMA_CTL_LLP_DSTEN);
+ }
+
+ dev_dbg(host_pvt.dwc_dev, "%s setting ctl.high len: "
+ "0x%08x val: 0x%08x\n", __func__,
+ len, DMA_CTL_BLK_TS(len / 4));
+
+ /* Program the LLI CTL high register */
+ lli[idx].ctl.high = cpu_to_le32(DMA_CTL_BLK_TS\
+ (len / 4));
+
+ /* Program the next pointer. The next pointer must be
+ * the physical address, not the virtual address.
+ */
+ next_llp = (dma_lli + ((idx + 1) * sizeof(struct \
+ lli)));
+
+ /* The last 2 bits encode the list master select. */
+ next_llp = DMA_LLP_LMS(next_llp, DMA_LLP_AHBMASTER2);
+
+ lli[idx].llp = cpu_to_le32(next_llp);
+ idx++;
+ sg_len -= len;
+ addr += len;
+ }
+ }
+
+ /*
+ * The last next ptr has to be zero and the last control low register
+ * has to have LLP_SRC_EN and LLP_DST_EN (linked list pointer source
+ * and destination enable) set back to 0 (disabled.) This is what tells
+ * the core that this is the last item in the linked list.
+ */
+ if (idx) {
+ lli[idx-1].llp = 0x00000000;
+ lli[idx-1].ctl.low &= DMA_CTL_LLP_DISABLE_LE32;
+
+ /* Flush cache to memory */
+ dma_cache_sync(NULL, lli, (sizeof(struct lli) * idx),
+ DMA_BIDIRECTIONAL);
+ }
+
+ return idx;
+}
+
+/*
+ * Function: dma_dwc_xfer_start
+ * arguments: Channel number
+ * Return : None
+ * Enables the DMA channel
+ */
+static void dma_dwc_xfer_start(int dma_ch)
+{
+ /* Enable the DMA channel */
+ out_le32(&(host_pvt.sata_dma_regs->dma_chan_en.low),
+ in_le32(&(host_pvt.sata_dma_regs->dma_chan_en.low)) |
+ DMA_ENABLE_CHAN(dma_ch));
+}
+
+static int dma_dwc_xfer_setup(struct scatterlist *sg, int num_elems,
+ struct lli *lli, dma_addr_t dma_lli,
+ void __iomem *addr, int dir)
+{
+ int dma_ch;
+ int num_lli;
+ /* Acquire DMA channel */
+ dma_ch = dma_request_channel();
+ if (dma_ch == -1) {
+ dev_err(host_pvt.dwc_dev, "%s: dma channel unavailable\n",
+ __func__);
+ return -EAGAIN;
+ }
+
+ /* Convert SG list to linked list of items (LLIs) for AHB DMA */
+ num_lli = map_sg_to_lli(sg, num_elems, lli, dma_lli, addr, dir);
+
+ dev_dbg(host_pvt.dwc_dev, "%s sg: 0x%p, count: %d lli: %p dma_lli:"
+ " 0x%0xlx addr: %p lli count: %d\n", __func__, sg, num_elems,
+ lli, (u32)dma_lli, addr, num_lli);
+
+ clear_chan_interrupts(dma_ch);
+
+ /* Program the CFG register. */
+ out_le32(&(host_pvt.sata_dma_regs->chan_regs[dma_ch].cfg.high),
+ DMA_CFG_PROTCTL | DMA_CFG_FCMOD_REQ);
+ out_le32(&(host_pvt.sata_dma_regs->chan_regs[dma_ch].cfg.low), 0);
+
+ /* Program the address of the linked list */
+ out_le32(&(host_pvt.sata_dma_regs->chan_regs[dma_ch].llp.low),
+ DMA_LLP_LMS(dma_lli, DMA_LLP_AHBMASTER2));
+
+ /* Program the CTL register with src enable / dst enable */
+ out_le32(&(host_pvt.sata_dma_regs->chan_regs[dma_ch].ctl.low),
+ DMA_CTL_LLP_SRCEN | DMA_CTL_LLP_DSTEN);
+ return 0;
+}
+
+/*
+ * Function: dma_dwc_exit
+ * arguments: None
+ * returns status
+ * This function exits the SATA DMA driver
+ */
+static void dma_dwc_exit(struct sata_dwc_device *hsdev)
+{
+ dev_dbg(host_pvt.dwc_dev, "%s:\n", __func__);
+ if (host_pvt.sata_dma_regs)
+ iounmap(host_pvt.sata_dma_regs);
+
+ if (hsdev->irq_dma)
+ free_irq(hsdev->irq_dma, hsdev);
+}
+
+/*
+ * Function: dma_dwc_init
+ * arguments: hsdev
+ * returns status
+ * This function initializes the SATA DMA driver
+ */
+static int dma_dwc_init(struct sata_dwc_device *hsdev, int irq)
+{
+ int err;
+
+ err = dma_request_interrupts(hsdev, irq);
+ if (err) {
+ dev_err(host_pvt.dwc_dev, "%s: dma_request_interrupts returns"
+ " %d\n", __func__, err);
+ goto error_out;
+ }
+
+ /* Enabe DMA */
+ out_le32(&(host_pvt.sata_dma_regs->dma_cfg.low), DMA_EN);
+
+ dev_notice(host_pvt.dwc_dev, "DMA initialized\n");
+ dev_dbg(host_pvt.dwc_dev, "SATA DMA registers=0x%p\n", host_pvt.\
+ sata_dma_regs);
+
+ return 0;
+
+error_out:
+ dma_dwc_exit(hsdev);
+
+ return err;
+}
+
+static int sata_dwc_scr_read(struct ata_link *link, unsigned int scr, u32 *val)
+{
+ if (scr > SCR_NOTIFICATION) {
+ dev_err(link->ap->dev, "%s: Incorrect SCR offset 0x%02x\n",
+ __func__, scr);
+ return -EINVAL;
+ }
+
+ *val = in_le32((void *)link->ap->ioaddr.scr_addr + (scr * 4));
+ dev_dbg(link->ap->dev, "%s: id=%d reg=%d val=val=0x%08x\n",
+ __func__, link->ap->print_id, scr, *val);
+
+ return 0;
+}
+
+static int sata_dwc_scr_write(struct ata_link *link, unsigned int scr, u32 val)
+{
+ dev_dbg(link->ap->dev, "%s: id=%d reg=%d val=val=0x%08x\n",
+ __func__, link->ap->print_id, scr, val);
+ if (scr > SCR_NOTIFICATION) {
+ dev_err(link->ap->dev, "%s: Incorrect SCR offset 0x%02x\n",
+ __func__, scr);
+ return -EINVAL;
+ }
+ out_le32((void *)link->ap->ioaddr.scr_addr + (scr * 4), val);
+
+ return 0;
+}
+
+static u32 core_scr_read(unsigned int scr)
+{
+ return in_le32((void __iomem *)(host_pvt.scr_addr_sstatus) +\
+ (scr * 4));
+}
+
+static void core_scr_write(unsigned int scr, u32 val)
+{
+ out_le32((void __iomem *)(host_pvt.scr_addr_sstatus) + (scr * 4),
+ val);
+}
+
+static void clear_serror(void)
+{
+ u32 val;
+ val = core_scr_read(SCR_ERROR);
+ core_scr_write(SCR_ERROR, val);
+
+}
+
+static void clear_interrupt_bit(struct sata_dwc_device *hsdev, u32 bit)
+{
+ out_le32(&hsdev->sata_dwc_regs->intpr,
+ in_le32(&hsdev->sata_dwc_regs->intpr));
+}
+
+static u32 qcmd_tag_to_mask(u8 tag)
+{
+ return 0x00000001 << (tag & 0x1f);
+}
+
+/* See ahci.c */
+static void sata_dwc_error_intr(struct ata_port *ap,
+ struct sata_dwc_device *hsdev, uint intpr)
+{
+ struct sata_dwc_device_port *hsdevp = HSDEVP_FROM_AP(ap);
+ struct ata_eh_info *ehi = &ap->link.eh_info;
+ unsigned int err_mask = 0, action = 0;
+ struct ata_queued_cmd *qc;
+ u32 serror;
+ u8 status, tag;
+ u32 err_reg;
+
+ ata_ehi_clear_desc(ehi);
+
+ serror = core_scr_read(SCR_ERROR);
+ status = ap->ops->sff_check_status(ap);
+
+ err_reg = in_le32(&(host_pvt.sata_dma_regs->interrupt_status.error.\
+ low));
+ tag = ap->link.active_tag;
+
+ dev_err(ap->dev, "%s SCR_ERROR=0x%08x intpr=0x%08x status=0x%08x "
+ "dma_intp=%d pending=%d issued=%d dma_err_status=0x%08x\n",
+ __func__, serror, intpr, status, host_pvt.dma_interrupt_count,
+ hsdevp->dma_pending[tag], hsdevp->cmd_issued[tag], err_reg);
+
+ /* Clear error register and interrupt bit */
+ clear_serror();
+ clear_interrupt_bit(hsdev, SATA_DWC_INTPR_ERR);
+
+ /* This is the only error happening now. TODO check for exact error */
+
+ err_mask |= AC_ERR_HOST_BUS;
+ action |= ATA_EH_RESET;
+
+ /* Pass this on to EH */
+ ehi->serror |= serror;
+ ehi->action |= action;
+
+ qc = ata_qc_from_tag(ap, tag);
+ if (qc)
+ qc->err_mask |= err_mask;
+ else
+ ehi->err_mask |= err_mask;
+
+ ata_port_abort(ap);
+}
+
+/*
+ * Function : sata_dwc_isr
+ * arguments : irq, void *dev_instance, struct pt_regs *regs
+ * Return value : irqreturn_t - status of IRQ
+ * This Interrupt handler called via port ops registered function.
+ * .irq_handler = sata_dwc_isr
+ */
+static irqreturn_t sata_dwc_isr(int irq, void *dev_instance)
+{
+ struct ata_host *host = (struct ata_host *)dev_instance;
+ struct sata_dwc_device *hsdev = HSDEV_FROM_HOST(host);
+ struct ata_port *ap;
+ struct ata_queued_cmd *qc;
+ unsigned long flags;
+ u8 status, tag;
+ int handled, num_processed, port = 0;
+ uint intpr, sactive, sactive2, tag_mask;
+ struct sata_dwc_device_port *hsdevp;
+ host_pvt.sata_dwc_sactive_issued = 0;
+
+ spin_lock_irqsave(&host->lock, flags);
+
+ /* Read the interrupt register */
+ intpr = in_le32(&hsdev->sata_dwc_regs->intpr);
+
+ ap = host->ports[port];
+ hsdevp = HSDEVP_FROM_AP(ap);
+
+ dev_dbg(ap->dev, "%s intpr=0x%08x active_tag=%d\n", __func__, intpr,
+ ap->link.active_tag);
+
+ /* Check for error interrupt */
+ if (intpr & SATA_DWC_INTPR_ERR) {
+ sata_dwc_error_intr(ap, hsdev, intpr);
+ handled = 1;
+ goto DONE;
+ }
+
+ /* Check for DMA SETUP FIS (FP DMA) interrupt */
+ if (intpr & SATA_DWC_INTPR_NEWFP) {
+ clear_interrupt_bit(hsdev, SATA_DWC_INTPR_NEWFP);
+
+ tag = (u8)(in_le32(&hsdev->sata_dwc_regs->fptagr));
+ dev_dbg(ap->dev, "%s: NEWFP tag=%d\n", __func__, tag);
+ if (hsdevp->cmd_issued[tag] != SATA_DWC_CMD_ISSUED_PEND)
+ dev_warn(ap->dev, "CMD tag=%d not pending?\n", tag);
+
+ host_pvt.sata_dwc_sactive_issued |= qcmd_tag_to_mask(tag);
+
+ qc = ata_qc_from_tag(ap, tag);
+ /*
+ * Start FP DMA for NCQ command. At this point the tag is the
+ * active tag. It is the tag that matches the command about to
+ * be completed.
+ */
+ qc->ap->link.active_tag = tag;
+ sata_dwc_bmdma_start_by_tag(qc, tag);
+
+ handled = 1;
+ goto DONE;
+ }
+ sactive = core_scr_read(SCR_ACTIVE);
+ tag_mask = (host_pvt.sata_dwc_sactive_issued | sactive) ^ sactive;
+
+ /* If no sactive issued and tag_mask is zero then this is not NCQ */
+ if (host_pvt.sata_dwc_sactive_issued == 0 && tag_mask == 0) {
+ if (ap->link.active_tag == ATA_TAG_POISON)
+ tag = 0;
+ else
+ tag = ap->link.active_tag;
+ qc = ata_qc_from_tag(ap, tag);
+
+ /* DEV interrupt w/ no active qc? */
+ if (unlikely(!qc || (qc->tf.flags & ATA_TFLAG_POLLING))) {
+ dev_err(ap->dev, "%s interrupt with no active qc "
+ "qc=%p\n", __func__, qc);
+ ap->ops->sff_check_status(ap);
+ handled = 1;
+ goto DONE;
+ }
+ status = ap->ops->sff_check_status(ap);
+
+ qc->ap->link.active_tag = tag;
+ hsdevp->cmd_issued[tag] = SATA_DWC_CMD_ISSUED_NOT;
+
+ if (status & ATA_ERR) {
+ dev_dbg(ap->dev, "interrupt ATA_ERR (0x%x)\n", status);
+ sata_dwc_qc_complete(ap, qc, 1);
+ handled = 1;
+ goto DONE;
+ }
+
+ dev_dbg(ap->dev, "%s non-NCQ cmd interrupt, protocol: %s\n",
+ __func__, ata_get_cmd_descript(qc->tf.protocol));
+DRVSTILLBUSY:
+ if (ata_is_dma(qc->tf.protocol)) {
+ /*
+ * Each DMA transaction produces 2 interrupts. The DMAC
+ * transfer complete interrupt and the SATA controller
+ * operation done interrupt. The command should be
+ * completed only after both interrupts are seen.
+ */
+ host_pvt.dma_interrupt_count++;
+ if (hsdevp->dma_pending[tag] == \
+ SATA_DWC_DMA_PENDING_NONE) {
+ dev_err(ap->dev, "%s: DMA not pending "
+ "intpr=0x%08x status=0x%08x pending"
+ "=%d\n", __func__, intpr, status,
+ hsdevp->dma_pending[tag]);
+ }
+
+ if ((host_pvt.dma_interrupt_count % 2) == 0)
+ sata_dwc_dma_xfer_complete(ap, 1);
+ } else if (ata_is_pio(qc->tf.protocol)) {
+ ata_sff_hsm_move(ap, qc, status, 0);
+ handled = 1;
+ goto DONE;
+ } else {
+ if (unlikely(sata_dwc_qc_complete(ap, qc, 1)))
+ goto DRVSTILLBUSY;
+ }
+
+ handled = 1;
+ goto DONE;
+ }
+
+ /*
+ * This is a NCQ command. At this point we need to figure out for which
+ * tags we have gotten a completion interrupt. One interrupt may serve
+ * as completion for more than one operation when commands are queued
+ * (NCQ). We need to process each completed command.
+ */
+
+ /* process completed commands */
+ sactive = core_scr_read(SCR_ACTIVE);
+ tag_mask = (host_pvt.sata_dwc_sactive_issued | sactive) ^ sactive;
+
+ if (sactive != 0 || (host_pvt.sata_dwc_sactive_issued) > 1 || \
+ tag_mask > 1) {
+ dev_dbg(ap->dev, "%s NCQ:sactive=0x%08x sactive_issued=0x%08x"
+ "tag_mask=0x%08x\n", __func__, sactive,
+ host_pvt.sata_dwc_sactive_issued, tag_mask);
+ }
+
+ if ((tag_mask | (host_pvt.sata_dwc_sactive_issued)) != \
+ (host_pvt.sata_dwc_sactive_issued)) {
+ dev_warn(ap->dev, "Bad tag mask? sactive=0x%08x "
+ "(host_pvt.sata_dwc_sactive_issued)=0x%08x tag_mask"
+ "=0x%08x\n", sactive, host_pvt.sata_dwc_sactive_issued,
+ tag_mask);
+ }
+
+ /* read just to clear ... not bad if currently still busy */
+ status = ap->ops->sff_check_status(ap);
+ dev_dbg(ap->dev, "%s ATA status register=0x%x\n", __func__, status);
+
+ tag = 0;
+ num_processed = 0;
+ while (tag_mask) {
+ num_processed++;
+ while (!(tag_mask & 0x00000001)) {
+ tag++;
+ tag_mask <<= 1;
+ }
+
+ tag_mask &= (~0x00000001);
+ qc = ata_qc_from_tag(ap, tag);
+
+ /* To be picked up by completion functions */
+ qc->ap->link.active_tag = tag;
+ hsdevp->cmd_issued[tag] = SATA_DWC_CMD_ISSUED_NOT;
+
+ /* Let libata/scsi layers handle error */
+ if (status & ATA_ERR) {
+ dev_dbg(ap->dev, "%s ATA_ERR (0x%x)\n", __func__,
+ status);
+ sata_dwc_qc_complete(ap, qc, 1);
+ handled = 1;
+ goto DONE;
+ }
+
+ /* Process completed command */
+ dev_dbg(ap->dev, "%s NCQ command, protocol: %s\n", __func__,
+ ata_get_cmd_descript(qc->tf.protocol));
+ if (ata_is_dma(qc->tf.protocol)) {
+ host_pvt.dma_interrupt_count++;
+ if (hsdevp->dma_pending[tag] == \
+ SATA_DWC_DMA_PENDING_NONE)
+ dev_warn(ap->dev, "%s: DMA not pending?\n",
+ __func__);
+ if ((host_pvt.dma_interrupt_count % 2) == 0)
+ sata_dwc_dma_xfer_complete(ap, 1);
+ } else {
+ if (unlikely(sata_dwc_qc_complete(ap, qc, 1)))
+ goto STILLBUSY;
+ }
+ continue;
+
+STILLBUSY:
+ ap->stats.idle_irq++;
+ dev_warn(ap->dev, "STILL BUSY IRQ ata%d: irq trap\n",
+ ap->print_id);
+ } /* while tag_mask */
+
+ /*
+ * Check to see if any commands completed while we were processing our
+ * initial set of completed commands (read status clears interrupts,
+ * so we might miss a completed command interrupt if one came in while
+ * we were processing --we read status as part of processing a completed
+ * command).
+ */
+ sactive2 = core_scr_read(SCR_ACTIVE);
+ if (sactive2 != sactive) {
+ dev_dbg(ap->dev, "More completed - sactive=0x%x sactive2"
+ "=0x%x\n", sactive, sactive2);
+ }
+ handled = 1;
+
+DONE:
+ spin_unlock_irqrestore(&host->lock, flags);
+ return IRQ_RETVAL(handled);
+}
+
+static void sata_dwc_clear_dmacr(struct sata_dwc_device_port *hsdevp, u8 tag)
+{
+ struct sata_dwc_device *hsdev = HSDEV_FROM_HSDEVP(hsdevp);
+
+ if (hsdevp->dma_pending[tag] == SATA_DWC_DMA_PENDING_RX) {
+ out_le32(&(hsdev->sata_dwc_regs->dmacr),
+ SATA_DWC_DMACR_RX_CLEAR(
+ in_le32(&(hsdev->sata_dwc_regs->dmacr))));
+ } else if (hsdevp->dma_pending[tag] == SATA_DWC_DMA_PENDING_TX) {
+ out_le32(&(hsdev->sata_dwc_regs->dmacr),
+ SATA_DWC_DMACR_TX_CLEAR(
+ in_le32(&(hsdev->sata_dwc_regs->dmacr))));
+ } else {
+ /*
+ * This should not happen, it indicates the driver is out of
+ * sync. If it does happen, clear dmacr anyway.
+ */
+ dev_err(host_pvt.dwc_dev, "%s DMA protocol RX and"
+ "TX DMA not pending tag=0x%02x pending=%d"
+ " dmacr: 0x%08x\n", __func__, tag,
+ hsdevp->dma_pending[tag],
+ in_le32(&(hsdev->sata_dwc_regs->dmacr)));
+ out_le32(&(hsdev->sata_dwc_regs->dmacr),
+ SATA_DWC_DMACR_TXRXCH_CLEAR);
+ }
+}
+
+static void sata_dwc_dma_xfer_complete(struct ata_port *ap, u32 check_status)
+{
+ struct ata_queued_cmd *qc;
+ struct sata_dwc_device_port *hsdevp = HSDEVP_FROM_AP(ap);
+ struct sata_dwc_device *hsdev = HSDEV_FROM_AP(ap);
+ u8 tag = 0;
+
+ tag = ap->link.active_tag;
+ qc = ata_qc_from_tag(ap, tag);
+ if (!qc) {
+ dev_err(ap->dev, "failed to get qc");
+ return;
+ }
+
+#ifdef DEBUG_NCQ
+ if (tag > 0) {
+ dev_info(ap->dev, "%s tag=%u cmd=0x%02x dma dir=%s proto=%s "
+ "dmacr=0x%08x\n", __func__, qc->tag, qc->tf.command,
+ ata_get_cmd_descript(qc->dma_dir),
+ ata_get_cmd_descript(qc->tf.protocol),
+ in_le32(&(hsdev->sata_dwc_regs->dmacr)));
+ }
+#endif
+
+ if (ata_is_dma(qc->tf.protocol)) {
+ if (hsdevp->dma_pending[tag] == SATA_DWC_DMA_PENDING_NONE) {
+ dev_err(ap->dev, "%s DMA protocol RX and TX DMA not "
+ "pending dmacr: 0x%08x\n", __func__,
+ in_le32(&(hsdev->sata_dwc_regs->dmacr)));
+ }
+
+ hsdevp->dma_pending[tag] = SATA_DWC_DMA_PENDING_NONE;
+ sata_dwc_qc_complete(ap, qc, check_status);
+ ap->link.active_tag = ATA_TAG_POISON;
+ } else {
+ sata_dwc_qc_complete(ap, qc, check_status);
+ }
+}
+
+static int sata_dwc_qc_complete(struct ata_port *ap, struct ata_queued_cmd *qc,
+ u32 check_status)
+{
+ u8 status = 0;
+ u32 mask = 0x0;
+ u8 tag = qc->tag;
+ struct sata_dwc_device_port *hsdevp = HSDEVP_FROM_AP(ap);
+ host_pvt.sata_dwc_sactive_queued = 0;
+ dev_dbg(ap->dev, "%s checkstatus? %x\n", __func__, check_status);
+
+ if (hsdevp->dma_pending[tag] == SATA_DWC_DMA_PENDING_TX)
+ dev_err(ap->dev, "TX DMA PENDING\n");
+ else if (hsdevp->dma_pending[tag] == SATA_DWC_DMA_PENDING_RX)
+ dev_err(ap->dev, "RX DMA PENDING\n");
+ dev_dbg(ap->dev, "QC complete cmd=0x%02x status=0x%02x ata%u:"
+ " protocol=%d\n", qc->tf.command, status, ap->print_id,
+ qc->tf.protocol);
+
+ /* clear active bit */
+ mask = (~(qcmd_tag_to_mask(tag)));
+ host_pvt.sata_dwc_sactive_queued = (host_pvt.sata_dwc_sactive_queued) \
+ & mask;
+ host_pvt.sata_dwc_sactive_issued = (host_pvt.sata_dwc_sactive_issued) \
+ & mask;
+ ata_qc_complete(qc);
+ return 0;
+}
+
+static void sata_dwc_enable_interrupts(struct sata_dwc_device *hsdev)
+{
+ /* Enable selective interrupts by setting the interrupt maskregister*/
+ out_le32(&hsdev->sata_dwc_regs->intmr,
+ SATA_DWC_INTMR_ERRM |
+ SATA_DWC_INTMR_NEWFPM |
+ SATA_DWC_INTMR_PMABRTM |
+ SATA_DWC_INTMR_DMATM);
+ /*
+ * Unmask the error bits that should trigger an error interrupt by
+ * setting the error mask register.
+ */
+ out_le32(&hsdev->sata_dwc_regs->errmr, SATA_DWC_SERROR_ERR_BITS);
+
+ dev_dbg(host_pvt.dwc_dev, "%s: INTMR = 0x%08x, ERRMR = 0x%08x\n",
+ __func__, in_le32(&hsdev->sata_dwc_regs->intmr),
+ in_le32(&hsdev->sata_dwc_regs->errmr));
+}
+
+static void sata_dwc_setup_port(struct ata_ioports *port, unsigned long base)
+{
+ port->cmd_addr = (void *)base + 0x00;
+ port->data_addr = (void *)base + 0x00;
+
+ port->error_addr = (void *)base + 0x04;
+ port->feature_addr = (void *)base + 0x04;
+
+ port->nsect_addr = (void *)base + 0x08;
+
+ port->lbal_addr = (void *)base + 0x0c;
+ port->lbam_addr = (void *)base + 0x10;
+ port->lbah_addr = (void *)base + 0x14;
+
+ port->device_addr = (void *)base + 0x18;
+ port->command_addr = (void *)base + 0x1c;
+ port->status_addr = (void *)base + 0x1c;
+
+ port->altstatus_addr = (void *)base + 0x20;
+ port->ctl_addr = (void *)base + 0x20;
+}
+
+/*
+ * Function : sata_dwc_port_start
+ * arguments : struct ata_ioports *port
+ * Return value : returns 0 if success, error code otherwise
+ * This function allocates the scatter gather LLI table for AHB DMA
+ */
+static int sata_dwc_port_start(struct ata_port *ap)
+{
+ int err = 0;
+ struct sata_dwc_device *hsdev;
+ struct sata_dwc_device_port *hsdevp = NULL;
+ struct device *pdev;
+ int i;
+
+ hsdev = HSDEV_FROM_AP(ap);
+
+ dev_dbg(ap->dev, "%s: port_no=%d\n", __func__, ap->port_no);
+
+ hsdev->host = ap->host;
+ pdev = ap->host->dev;
+ if (!pdev) {
+ dev_err(ap->dev, "%s: no ap->host->dev\n", __func__);
+ err = -ENODEV;
+ goto CLEANUP;
+ }
+
+ /* Allocate Port Struct */
+ hsdevp = kzalloc(sizeof(*hsdevp), GFP_KERNEL);
+ if (!hsdevp) {
+ dev_err(ap->dev, "%s: kmalloc failed for hsdevp\n", __func__);
+ err = -ENOMEM;
+ goto CLEANUP;
+ }
+ hsdevp->hsdev = hsdev;
+
+ for (i = 0; i < SATA_DWC_QCMD_MAX; i++)
+ hsdevp->cmd_issued[i] = SATA_DWC_CMD_ISSUED_NOT;
+
+ ap->bmdma_prd = 0; /* set these so libata doesn't use them */
+ ap->bmdma_prd_dma = 0;
+
+ /*
+ * DMA - Assign scatter gather LLI table. We can't use the libata
+ * version since it's PRD is IDE PCI specific.
+ */
+ for (i = 0; i < SATA_DWC_QCMD_MAX; i++) {
+ hsdevp->llit[i] = dma_alloc_coherent(pdev,
+ SATA_DWC_DMAC_LLI_TBL_SZ,
+ &(hsdevp->llit_dma[i]),
+ GFP_ATOMIC);
+ if (!hsdevp->llit[i]) {
+ dev_err(ap->dev, "%s: dma_alloc_coherent failed\n",
+ __func__);
+ err = -ENOMEM;
+ goto CLEANUP;
+ }
+ }
+
+ if (ap->port_no == 0) {
+ dev_dbg(ap->dev, "%s: clearing TXCHEN, RXCHEN in DMAC\n",
+ __func__);
+ out_le32(&hsdev->sata_dwc_regs->dmacr,
+ SATA_DWC_DMACR_TXRXCH_CLEAR);
+
+ dev_dbg(ap->dev, "%s: setting burst size in DBTSR\n",
+ __func__);
+ out_le32(&hsdev->sata_dwc_regs->dbtsr,
+ (SATA_DWC_DBTSR_MWR(AHB_DMA_BRST_DFLT) |
+ SATA_DWC_DBTSR_MRD(AHB_DMA_BRST_DFLT)));
+ }
+
+ /* Clear any error bits before libata starts issuing commands */
+ clear_serror();
+ ap->private_data = hsdevp;
+
+CLEANUP:
+ if (err) {
+ sata_dwc_port_stop(ap);
+ dev_dbg(ap->dev, "%s: fail\n", __func__);
+ } else {
+ dev_dbg(ap->dev, "%s: done\n", __func__);
+ }
+
+ return err;
+}
+
+static void sata_dwc_port_stop(struct ata_port *ap)
+{
+ int i;
+ struct sata_dwc_device *hsdev = HSDEV_FROM_AP(ap);
+ struct sata_dwc_device_port *hsdevp = HSDEVP_FROM_AP(ap);
+
+ dev_dbg(ap->dev, "%s: ap->id = %d\n", __func__, ap->print_id);
+
+ if (hsdevp && hsdev) {
+ /* deallocate LLI table */
+ for (i = 0; i < SATA_DWC_QCMD_MAX; i++) {
+ dma_free_coherent(ap->host->dev,
+ SATA_DWC_DMAC_LLI_TBL_SZ,
+ hsdevp->llit[i], hsdevp->llit_dma[i]);
+ }
+
+ kfree(hsdevp);
+ }
+ ap->private_data = NULL;
+}
+
+/*
+ * Function : sata_dwc_exec_command_by_tag
+ * arguments : ata_port *ap, ata_taskfile *tf, u8 tag, u32 cmd_issued
+ * Return value : None
+ * This function keeps track of individual command tag ids and calls
+ * ata_exec_command in libata
+ */
+static void sata_dwc_exec_command_by_tag(struct ata_port *ap,
+ struct ata_taskfile *tf,
+ u8 tag, u32 cmd_issued)
+{
+ unsigned long flags;
+ struct sata_dwc_device_port *hsdevp = HSDEVP_FROM_AP(ap);
+
+ dev_dbg(ap->dev, "%s cmd(0x%02x): %s tag=%d\n", __func__, tf->command,
+ ata_get_cmd_descript(tf), tag);
+
+ spin_lock_irqsave(&ap->host->lock, flags);
+ hsdevp->cmd_issued[tag] = cmd_issued;
+ spin_unlock_irqrestore(&ap->host->lock, flags);
+ /*
+ * Clear SError before executing a new command.
+ * sata_dwc_scr_write and read can not be used here. Clearing the PM
+ * managed SError register for the disk needs to be done before the
+ * task file is loaded.
+ */
+ clear_serror();
+ ata_sff_exec_command(ap, tf);
+}
+
+static void sata_dwc_bmdma_setup_by_tag(struct ata_queued_cmd *qc, u8 tag)
+{
+ sata_dwc_exec_command_by_tag(qc->ap, &qc->tf, tag,
+ SATA_DWC_CMD_ISSUED_PEND);
+}
+
+static void sata_dwc_bmdma_setup(struct ata_queued_cmd *qc)
+{
+ u8 tag = qc->tag;
+
+ if (ata_is_ncq(qc->tf.protocol)) {
+ dev_dbg(qc->ap->dev, "%s: ap->link.sactive=0x%08x tag=%d\n",
+ __func__, qc->ap->link.sactive, tag);
+ } else {
+ tag = 0;
+ }
+ sata_dwc_bmdma_setup_by_tag(qc, tag);
+}
+
+static void sata_dwc_bmdma_start_by_tag(struct ata_queued_cmd *qc, u8 tag)
+{
+ int start_dma;
+ u32 reg, dma_chan;
+ struct sata_dwc_device *hsdev = HSDEV_FROM_QC(qc);
+ struct ata_port *ap = qc->ap;
+ struct sata_dwc_device_port *hsdevp = HSDEVP_FROM_AP(ap);
+ int dir = qc->dma_dir;
+ dma_chan = hsdevp->dma_chan[tag];
+
+ if (hsdevp->cmd_issued[tag] != SATA_DWC_CMD_ISSUED_NOT) {
+ start_dma = 1;
+ if (dir == DMA_TO_DEVICE)
+ hsdevp->dma_pending[tag] = SATA_DWC_DMA_PENDING_TX;
+ else
+ hsdevp->dma_pending[tag] = SATA_DWC_DMA_PENDING_RX;
+ } else {
+ dev_err(ap->dev, "%s: Command not pending cmd_issued=%d "
+ "(tag=%d) DMA NOT started\n", __func__,
+ hsdevp->cmd_issued[tag], tag);
+ start_dma = 0;
+ }
+
+ dev_dbg(ap->dev, "%s qc=%p tag: %x cmd: 0x%02x dma_dir: %s "
+ "start_dma? %x\n", __func__, qc, tag, qc->tf.command,
+ ata_get_cmd_descript(qc->dma_dir), start_dma);
+ sata_dwc_tf_dump(&(qc->tf));
+
+ if (start_dma) {
+ reg = core_scr_read(SCR_ERROR);
+ if (reg & SATA_DWC_SERROR_ERR_BITS) {
+ dev_err(ap->dev, "%s: ****** SError=0x%08x ******\n",
+ __func__, reg);
+ }
+
+ if (dir == DMA_TO_DEVICE)
+ out_le32(&hsdev->sata_dwc_regs->dmacr,
+ SATA_DWC_DMACR_TXCHEN);
+ else
+ out_le32(&hsdev->sata_dwc_regs->dmacr,
+ SATA_DWC_DMACR_RXCHEN);
+
+ /* Enable AHB DMA transfer on the specified channel */
+ dma_dwc_xfer_start(dma_chan);
+ }
+}
+
+static void sata_dwc_bmdma_start(struct ata_queued_cmd *qc)
+{
+ u8 tag = qc->tag;
+
+ if (ata_is_ncq(qc->tf.protocol)) {
+ dev_dbg(qc->ap->dev, "%s: ap->link.sactive=0x%08x tag=%d\n",
+ __func__, qc->ap->link.sactive, tag);
+ } else {
+ tag = 0;
+ }
+ dev_dbg(qc->ap->dev, "%s\n", __func__);
+ sata_dwc_bmdma_start_by_tag(qc, tag);
+}
+
+/*
+ * Function : sata_dwc_qc_prep_by_tag
+ * arguments : ata_queued_cmd *qc, u8 tag
+ * Return value : None
+ * qc_prep for a particular queued command based on tag
+ */
+static void sata_dwc_qc_prep_by_tag(struct ata_queued_cmd *qc, u8 tag)
+{
+ struct scatterlist *sg = qc->sg;
+ struct ata_port *ap = qc->ap;
+ u32 dma_chan;
+ struct sata_dwc_device *hsdev = HSDEV_FROM_AP(ap);
+ struct sata_dwc_device_port *hsdevp = HSDEVP_FROM_AP(ap);
+ int err;
+
+ dev_dbg(ap->dev, "%s: port=%d dma dir=%s n_elem=%d\n",
+ __func__, ap->port_no, ata_get_cmd_descript(qc->dma_dir),
+ qc->n_elem);
+
+ dma_chan = dma_dwc_xfer_setup(sg, qc->n_elem, hsdevp->llit[tag],
+ hsdevp->llit_dma[tag],
+ (void *__iomem)(&hsdev->sata_dwc_regs->\
+ dmadr), qc->dma_dir);
+ if (dma_chan < 0) {
+ dev_err(ap->dev, "%s: dma_dwc_xfer_setup returns err %d\n",
+ __func__, err);
+ return;
+ }
+ hsdevp->dma_chan[tag] = dma_chan;
+}
+
+static unsigned int sata_dwc_qc_issue(struct ata_queued_cmd *qc)
+{
+ u32 sactive;
+ u8 tag = qc->tag;
+ struct ata_port *ap = qc->ap;
+
+#ifdef DEBUG_NCQ
+ if (qc->tag > 0 || ap->link.sactive > 1)
+ dev_info(ap->dev, "%s ap id=%d cmd(0x%02x)=%s qc tag=%d "
+ "prot=%s ap active_tag=0x%08x ap sactive=0x%08x\n",
+ __func__, ap->print_id, qc->tf.command,
+ ata_get_cmd_descript(&qc->tf),
+ qc->tag, ata_get_cmd_descript(qc->tf.protocol),
+ ap->link.active_tag, ap->link.sactive);
+#endif
+
+ if (!ata_is_ncq(qc->tf.protocol))
+ tag = 0;
+ sata_dwc_qc_prep_by_tag(qc, tag);
+
+ if (ata_is_ncq(qc->tf.protocol)) {
+ sactive = core_scr_read(SCR_ACTIVE);
+ sactive |= (0x00000001 << tag);
+ core_scr_write(SCR_ACTIVE, sactive);
+
+ dev_dbg(qc->ap->dev, "%s: tag=%d ap->link.sactive = 0x%08x "
+ "sactive=0x%08x\n", __func__, tag, qc->ap->link.sactive,
+ sactive);
+
+ ap->ops->sff_tf_load(ap, &qc->tf);
+ sata_dwc_exec_command_by_tag(ap, &qc->tf, qc->tag,
+ SATA_DWC_CMD_ISSUED_PEND);
+ } else {
+ ata_sff_qc_issue(qc);
+ }
+ return 0;
+}
+
+/*
+ * Function : sata_dwc_qc_prep
+ * arguments : ata_queued_cmd *qc
+ * Return value : None
+ * qc_prep for a particular queued command
+ */
+
+static void sata_dwc_qc_prep(struct ata_queued_cmd *qc)
+{
+ if ((qc->dma_dir == DMA_NONE) || (qc->tf.protocol == ATA_PROT_PIO))
+ return;
+
+#ifdef DEBUG_NCQ
+ if (qc->tag > 0)
+ dev_info(qc->ap->dev, "%s: qc->tag=%d ap->active_tag=0x%08x\n",
+ __func__, tag, qc->ap->link.active_tag);
+
+ return ;
+#endif
+}
+
+static void sata_dwc_error_handler(struct ata_port *ap)
+{
+ ap->link.flags |= ATA_LFLAG_NO_HRST;
+ ata_sff_error_handler(ap);
+}
+
+/*
+ * scsi mid-layer and libata interface structures
+ */
+static struct scsi_host_template sata_dwc_sht = {
+ ATA_NCQ_SHT(DRV_NAME),
+ /*
+ * test-only: Currently this driver doesn't handle NCQ
+ * correctly. We enable NCQ but set the queue depth to a
+ * max of 1. This will get fixed in in a future release.
+ */
+ .sg_tablesize = LIBATA_MAX_PRD,
+ .can_queue = ATA_DEF_QUEUE, /* ATA_MAX_QUEUE */
+ .dma_boundary = ATA_DMA_BOUNDARY,
+};
+
+static struct ata_port_operations sata_dwc_ops = {
+ .inherits = &ata_sff_port_ops,
+
+ .error_handler = sata_dwc_error_handler,
+
+ .qc_prep = sata_dwc_qc_prep,
+ .qc_issue = sata_dwc_qc_issue,
+
+ .scr_read = sata_dwc_scr_read,
+ .scr_write = sata_dwc_scr_write,
+
+ .port_start = sata_dwc_port_start,
+ .port_stop = sata_dwc_port_stop,
+
+ .bmdma_setup = sata_dwc_bmdma_setup,
+ .bmdma_start = sata_dwc_bmdma_start,
+};
+
+static const struct ata_port_info sata_dwc_port_info[] = {
+ {
+ .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
+ ATA_FLAG_MMIO | ATA_FLAG_NCQ,
+ .pio_mask = 0x1f, /* pio 0-4 */
+ .udma_mask = ATA_UDMA6,
+ .port_ops = &sata_dwc_ops,
+ },
+};
+
+static int sata_dwc_probe(struct of_device *ofdev,
+ const struct of_device_id *match)
+{
+ struct sata_dwc_device *hsdev;
+ u32 idr, versionr;
+ char *ver = (char *)&versionr;
+ u8 *base = NULL;
+ int err = 0;
+ int irq, rc;
+ struct ata_host *host;
+ struct ata_port_info pi = sata_dwc_port_info[0];
+ const struct ata_port_info *ppi[] = { &pi, NULL };
+
+ /* Allocate DWC SATA device */
+ hsdev = kmalloc(sizeof(*hsdev), GFP_KERNEL);
+ if (hsdev == NULL) {
+ dev_err(&ofdev->dev, "kmalloc failed for hsdev\n");
+ err = -ENOMEM;
+ goto error_out;
+ }
+ memset(hsdev, 0, sizeof(*hsdev));
+
+ /* Ioremap SATA registers */
+ base = of_iomap(ofdev->dev.of_node, 0);
+ if (!base) {
+ dev_err(&ofdev->dev, "ioremap failed for SATA register"
+ " address\n");
+ err = -ENODEV;
+ goto error_out;
+ }
+ hsdev->reg_base = base;
+ dev_dbg(&ofdev->dev, "ioremap done for SATA register address\n");
+
+ /* Synopsys DWC SATA specific Registers */
+ hsdev->sata_dwc_regs = (void *__iomem)(base + SATA_DWC_REG_OFFSET);
+
+ /* Allocate and fill host */
+ host = ata_host_alloc_pinfo(&ofdev->dev, ppi, SATA_DWC_MAX_PORTS);
+ if (!host) {
+ dev_err(&ofdev->dev, "ata_host_alloc_pinfo failed\n");
+ err = -ENOMEM;
+ goto error_out;
+ }
+
+ host->private_data = hsdev;
+
+ /* Setup port */
+ host->ports[0]->ioaddr.cmd_addr = base;
+ host->ports[0]->ioaddr.scr_addr = base + SATA_DWC_SCR_OFFSET;
+ host_pvt.scr_addr_sstatus = base + SATA_DWC_SCR_OFFSET;
+ sata_dwc_setup_port(&host->ports[0]->ioaddr, (unsigned long)base);
+
+ /* Read the ID and Version Registers */
+ idr = in_le32(&hsdev->sata_dwc_regs->idr);
+ versionr = in_le32(&hsdev->sata_dwc_regs->versionr);
+ dev_notice(&ofdev->dev, "id %d, controller version %c.%c%c\n",
+ idr, ver[0], ver[1], ver[2]);
+
+ /* Get SATA DMA interrupt number */
+ irq = irq_of_parse_and_map(ofdev->dev.of_node, 1);
+ if (irq == NO_IRQ) {
+ dev_err(&ofdev->dev, "no SATA DMA irq\n");
+ err = -ENODEV;
+ goto error_out;
+ }
+
+ /* Get physical SATA DMA register base address */
+ host_pvt.sata_dma_regs = of_iomap(ofdev->dev.of_node, 1);
+ if (!(host_pvt.sata_dma_regs)) {
+ dev_err(&ofdev->dev, "ioremap failed for AHBDMA register"
+ " address\n");
+ err = -ENODEV;
+ goto error_out;
+ }
+
+ /* Save dev for later use in dev_xxx() routines */
+ host_pvt.dwc_dev = &ofdev->dev;
+
+ /* Initialize AHB DMAC */
+ dma_dwc_init(hsdev, irq);
+
+ /* Enable SATA Interrupts */
+ sata_dwc_enable_interrupts(hsdev);
+
+ /* Get SATA interrupt number */
+ irq = irq_of_parse_and_map(ofdev->dev.of_node, 0);
+ if (irq == NO_IRQ) {
+ dev_err(&ofdev->dev, "no SATA DMA irq\n");
+ err = -ENODEV;
+ goto error_out;
+ }
+
+ /*
+ * Now, register with libATA core, this will also initiate the
+ * device discovery process, invoking our port_start() handler &
+ * error_handler() to execute a dummy Softreset EH session
+ */
+ rc = ata_host_activate(host, irq, sata_dwc_isr, 0, &sata_dwc_sht);
+
+ if (rc != 0)
+ dev_err(&ofdev->dev, "failed to activate host");
+
+ dev_set_drvdata(&ofdev->dev, host);
+ return 0;
+
+error_out:
+ /* Free SATA DMA resources */
+ dma_dwc_exit(hsdev);
+
+ if (base)
+ iounmap(base);
+ return err;
+}
+
+static int sata_dwc_remove(struct of_device *ofdev)
+{
+ struct device *dev = &ofdev->dev;
+ struct ata_host *host = dev_get_drvdata(dev);
+ struct sata_dwc_device *hsdev = host->private_data;
+
+ ata_host_detach(host);
+ dev_set_drvdata(dev, NULL);
+
+ /* Free SATA DMA resources */
+ dma_dwc_exit(hsdev);
+
+ iounmap(hsdev->reg_base);
+ kfree(hsdev);
+ kfree(host);
+ dev_dbg(&ofdev->dev, "done\n");
+ return 0;
+}
+
+static const struct of_device_id sata_dwc_match[] = {
+ { .compatible = "amcc,sata-460ex", },
+ {}
+};
+MODULE_DEVICE_TABLE(of, sata_dwc_match);
+
+static struct of_platform_driver sata_dwc_driver = {
+ .driver = {
+ .name = DRV_NAME,
+ .owner = THIS_MODULE,
+ .of_match_table = sata_dwc_match,
+ },
+ .probe = sata_dwc_probe,
+ .remove = sata_dwc_remove,
+};
+
+static int __init sata_dwc_init(void)
+{
+ return of_register_platform_driver(&sata_dwc_driver);
+}
+
+static void __exit sata_dwc_exit(void)
+{
+ of_unregister_platform_driver(&sata_dwc_driver);
+}
+
+module_init(sata_dwc_init);
+module_exit(sata_dwc_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mark Miesfeld <mmiesfeld@amcc.com>");
+MODULE_DESCRIPTION("DesignWare Cores SATA controller low lever driver");
+MODULE_VERSION(DRV_VERSION);
diff --git a/drivers/ata/sata_fsl.c b/drivers/ata/sata_fsl.c
index 61c89b54ea2..18c986dbb7f 100644
--- a/drivers/ata/sata_fsl.c
+++ b/drivers/ata/sata_fsl.c
@@ -1096,7 +1096,7 @@ static void sata_fsl_host_intr(struct ata_port *ap)
{
struct sata_fsl_host_priv *host_priv = ap->host->private_data;
void __iomem *hcr_base = host_priv->hcr_base;
- u32 hstatus, qc_active = 0;
+ u32 hstatus, done_mask = 0;
struct ata_queued_cmd *qc;
u32 SError;
@@ -1116,28 +1116,28 @@ static void sata_fsl_host_intr(struct ata_port *ap)
}
/* Read command completed register */
- qc_active = ioread32(hcr_base + CC);
+ done_mask = ioread32(hcr_base + CC);
VPRINTK("Status of all queues :\n");
- VPRINTK("qc_active/CC = 0x%x, CA = 0x%x, CE=0x%x,CQ=0x%x,apqa=0x%x\n",
- qc_active,
+ VPRINTK("done_mask/CC = 0x%x, CA = 0x%x, CE=0x%x,CQ=0x%x,apqa=0x%x\n",
+ done_mask,
ioread32(hcr_base + CA),
ioread32(hcr_base + CE),
ioread32(hcr_base + CQ),
ap->qc_active);
- if (qc_active & ap->qc_active) {
+ if (done_mask & ap->qc_active) {
int i;
/* clear CC bit, this will also complete the interrupt */
- iowrite32(qc_active, hcr_base + CC);
+ iowrite32(done_mask, hcr_base + CC);
DPRINTK("Status of all queues :\n");
- DPRINTK("qc_active/CC = 0x%x, CA = 0x%x, CE=0x%x\n",
- qc_active, ioread32(hcr_base + CA),
+ DPRINTK("done_mask/CC = 0x%x, CA = 0x%x, CE=0x%x\n",
+ done_mask, ioread32(hcr_base + CA),
ioread32(hcr_base + CE));
for (i = 0; i < SATA_FSL_QUEUE_DEPTH; i++) {
- if (qc_active & (1 << i)) {
+ if (done_mask & (1 << i)) {
qc = ata_qc_from_tag(ap, i);
if (qc) {
ata_qc_complete(qc);
@@ -1164,7 +1164,7 @@ static void sata_fsl_host_intr(struct ata_port *ap)
/* Spurious Interrupt!! */
DPRINTK("spurious interrupt!!, CC = 0x%x\n",
ioread32(hcr_base + CC));
- iowrite32(qc_active, hcr_base + CC);
+ iowrite32(done_mask, hcr_base + CC);
return;
}
}
diff --git a/drivers/ata/sata_mv.c b/drivers/ata/sata_mv.c
index a476cd99b95..9463c71dd38 100644
--- a/drivers/ata/sata_mv.c
+++ b/drivers/ata/sata_mv.c
@@ -2716,34 +2716,35 @@ static void mv_err_intr(struct ata_port *ap)
static void mv_process_crpb_response(struct ata_port *ap,
struct mv_crpb *response, unsigned int tag, int ncq_enabled)
{
+ u8 ata_status;
+ u16 edma_status = le16_to_cpu(response->flags);
struct ata_queued_cmd *qc = ata_qc_from_tag(ap, tag);
- if (qc) {
- u8 ata_status;
- u16 edma_status = le16_to_cpu(response->flags);
- /*
- * edma_status from a response queue entry:
- * LSB is from EDMA_ERR_IRQ_CAUSE (non-NCQ only).
- * MSB is saved ATA status from command completion.
- */
- if (!ncq_enabled) {
- u8 err_cause = edma_status & 0xff & ~EDMA_ERR_DEV;
- if (err_cause) {
- /*
- * Error will be seen/handled by mv_err_intr().
- * So do nothing at all here.
- */
- return;
- }
- }
- ata_status = edma_status >> CRPB_FLAG_STATUS_SHIFT;
- if (!ac_err_mask(ata_status))
- ata_qc_complete(qc);
- /* else: leave it for mv_err_intr() */
- } else {
+ if (unlikely(!qc)) {
ata_port_printk(ap, KERN_ERR, "%s: no qc for tag=%d\n",
__func__, tag);
+ return;
+ }
+
+ /*
+ * edma_status from a response queue entry:
+ * LSB is from EDMA_ERR_IRQ_CAUSE (non-NCQ only).
+ * MSB is saved ATA status from command completion.
+ */
+ if (!ncq_enabled) {
+ u8 err_cause = edma_status & 0xff & ~EDMA_ERR_DEV;
+ if (err_cause) {
+ /*
+ * Error will be seen/handled by
+ * mv_err_intr(). So do nothing at all here.
+ */
+ return;
+ }
}
+ ata_status = edma_status >> CRPB_FLAG_STATUS_SHIFT;
+ if (!ac_err_mask(ata_status))
+ ata_qc_complete(qc);
+ /* else: leave it for mv_err_intr() */
}
static void mv_process_crpb_entries(struct ata_port *ap, struct mv_port_priv *pp)
diff --git a/drivers/ata/sata_nv.c b/drivers/ata/sata_nv.c
index 21161136cad..cb89ef8d99d 100644
--- a/drivers/ata/sata_nv.c
+++ b/drivers/ata/sata_nv.c
@@ -1018,7 +1018,7 @@ static irqreturn_t nv_adma_interrupt(int irq, void *dev_instance)
NV_ADMA_STAT_CPBERR |
NV_ADMA_STAT_CMD_COMPLETE)) {
u32 check_commands = notifier_clears[i];
- int pos, error = 0;
+ int pos, rc;
if (status & NV_ADMA_STAT_CPBERR) {
/* check all active commands */
@@ -1030,10 +1030,12 @@ static irqreturn_t nv_adma_interrupt(int irq, void *dev_instance)
}
/* check CPBs for completed commands */
- while ((pos = ffs(check_commands)) && !error) {
+ while ((pos = ffs(check_commands))) {
pos--;
- error = nv_adma_check_cpb(ap, pos,
+ rc = nv_adma_check_cpb(ap, pos,
notifier_error & (1 << pos));
+ if (unlikely(rc))
+ check_commands = 0;
check_commands &= ~(1 << pos);
}
}
@@ -2129,7 +2131,6 @@ static int nv_swncq_sdbfis(struct ata_port *ap)
struct nv_swncq_port_priv *pp = ap->private_data;
struct ata_eh_info *ehi = &ap->link.eh_info;
u32 sactive;
- int nr_done = 0;
u32 done_mask;
int i;
u8 host_stat;
@@ -2170,22 +2171,21 @@ static int nv_swncq_sdbfis(struct ata_port *ap)
pp->dhfis_bits &= ~(1 << i);
pp->dmafis_bits &= ~(1 << i);
pp->sdbfis_bits |= (1 << i);
- nr_done++;
}
}
if (!ap->qc_active) {
DPRINTK("over\n");
nv_swncq_pp_reinit(ap);
- return nr_done;
+ return 0;
}
if (pp->qc_active & pp->dhfis_bits)
- return nr_done;
+ return 0;
if ((pp->ncq_flags & ncq_saw_backout) ||
(pp->qc_active ^ pp->dhfis_bits))
- /* if the controller cann't get a device to host register FIS,
+ /* if the controller can't get a device to host register FIS,
* The driver needs to reissue the new command.
*/
lack_dhfis = 1;
@@ -2202,7 +2202,7 @@ static int nv_swncq_sdbfis(struct ata_port *ap)
if (lack_dhfis) {
qc = ata_qc_from_tag(ap, pp->last_issue_tag);
nv_swncq_issue_atacmd(ap, qc);
- return nr_done;
+ return 0;
}
if (pp->defer_queue.defer_bits) {
@@ -2212,7 +2212,7 @@ static int nv_swncq_sdbfis(struct ata_port *ap)
nv_swncq_issue_atacmd(ap, qc);
}
- return nr_done;
+ return 0;
}
static inline u32 nv_swncq_tag(struct ata_port *ap)
@@ -2224,7 +2224,7 @@ static inline u32 nv_swncq_tag(struct ata_port *ap)
return (tag & 0x1f);
}
-static int nv_swncq_dmafis(struct ata_port *ap)
+static void nv_swncq_dmafis(struct ata_port *ap)
{
struct ata_queued_cmd *qc;
unsigned int rw;
@@ -2239,7 +2239,7 @@ static int nv_swncq_dmafis(struct ata_port *ap)
qc = ata_qc_from_tag(ap, tag);
if (unlikely(!qc))
- return 0;
+ return;
rw = qc->tf.flags & ATA_TFLAG_WRITE;
@@ -2254,8 +2254,6 @@ static int nv_swncq_dmafis(struct ata_port *ap)
dmactl |= ATA_DMA_WR;
iowrite8(dmactl | ATA_DMA_START, ap->ioaddr.bmdma_addr + ATA_DMA_CMD);
-
- return 1;
}
static void nv_swncq_host_interrupt(struct ata_port *ap, u16 fis)
@@ -2265,7 +2263,6 @@ static void nv_swncq_host_interrupt(struct ata_port *ap, u16 fis)
struct ata_eh_info *ehi = &ap->link.eh_info;
u32 serror;
u8 ata_stat;
- int rc = 0;
ata_stat = ap->ops->sff_check_status(ap);
nv_swncq_irq_clear(ap, fis);
@@ -2310,8 +2307,7 @@ static void nv_swncq_host_interrupt(struct ata_port *ap, u16 fis)
"dhfis 0x%X dmafis 0x%X sactive 0x%X\n",
ap->print_id, pp->qc_active, pp->dhfis_bits,
pp->dmafis_bits, readl(pp->sactive_block));
- rc = nv_swncq_sdbfis(ap);
- if (rc < 0)
+ if (nv_swncq_sdbfis(ap) < 0)
goto irq_error;
}
@@ -2348,7 +2344,7 @@ static void nv_swncq_host_interrupt(struct ata_port *ap, u16 fis)
*/
pp->dmafis_bits |= (0x1 << nv_swncq_tag(ap));
pp->ncq_flags |= ncq_saw_dmas;
- rc = nv_swncq_dmafis(ap);
+ nv_swncq_dmafis(ap);
}
irq_exit:
diff --git a/drivers/atm/Kconfig b/drivers/atm/Kconfig
index f1a0a00b3b0..be7461c9a87 100644
--- a/drivers/atm/Kconfig
+++ b/drivers/atm/Kconfig
@@ -177,7 +177,7 @@ config ATM_ZATM_DEBUG
config ATM_NICSTAR
tristate "IDT 77201 (NICStAR) (ForeRunnerLE)"
- depends on PCI && !64BIT && VIRT_TO_BUS
+ depends on PCI
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
diff --git a/drivers/atm/adummy.c b/drivers/atm/adummy.c
index 6d44f07b69f..46b94762125 100644
--- a/drivers/atm/adummy.c
+++ b/drivers/atm/adummy.c
@@ -40,6 +40,42 @@ struct adummy_dev {
static LIST_HEAD(adummy_devs);
+static ssize_t __set_signal(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t len)
+{
+ struct atm_dev *atm_dev = container_of(dev, struct atm_dev, class_dev);
+ int signal;
+
+ if (sscanf(buf, "%d", &signal) == 1) {
+
+ if (signal < ATM_PHY_SIG_LOST || signal > ATM_PHY_SIG_FOUND)
+ signal = ATM_PHY_SIG_UNKNOWN;
+
+ atm_dev_signal_change(atm_dev, signal);
+ return 1;
+ }
+ return -EINVAL;
+}
+
+static ssize_t __show_signal(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct atm_dev *atm_dev = container_of(dev, struct atm_dev, class_dev);
+ return sprintf(buf, "%d\n", atm_dev->signal);
+}
+static DEVICE_ATTR(signal, 0644, __show_signal, __set_signal);
+
+static struct attribute *adummy_attrs[] = {
+ &dev_attr_signal.attr,
+ NULL
+};
+
+static struct attribute_group adummy_group_attrs = {
+ .name = NULL, /* We want them in dev's root folder */
+ .attrs = adummy_attrs
+};
+
static int __init
adummy_start(struct atm_dev *dev)
{
@@ -128,6 +164,9 @@ static int __init adummy_init(void)
adummy_dev->atm_dev = atm_dev;
atm_dev->dev_data = adummy_dev;
+ if (sysfs_create_group(&atm_dev->class_dev.kobj, &adummy_group_attrs))
+ dev_err(&atm_dev->class_dev, "Could not register attrs for adummy\n");
+
if (adummy_start(atm_dev)) {
printk(KERN_ERR DEV_LABEL ": adummy_start() failed\n");
err = -ENODEV;
diff --git a/drivers/atm/ambassador.c b/drivers/atm/ambassador.c
index 9d18644c897..a33896a482e 100644
--- a/drivers/atm/ambassador.c
+++ b/drivers/atm/ambassador.c
@@ -2371,10 +2371,8 @@ MODULE_PARM_DESC(pci_lat, "PCI latency in bus cycles");
/********** module entry **********/
static struct pci_device_id amb_pci_tbl[] = {
- { PCI_VENDOR_ID_MADGE, PCI_DEVICE_ID_MADGE_AMBASSADOR, PCI_ANY_ID, PCI_ANY_ID,
- 0, 0, 0 },
- { PCI_VENDOR_ID_MADGE, PCI_DEVICE_ID_MADGE_AMBASSADOR_BAD, PCI_ANY_ID, PCI_ANY_ID,
- 0, 0, 0 },
+ { PCI_VDEVICE(MADGE, PCI_DEVICE_ID_MADGE_AMBASSADOR), 0 },
+ { PCI_VDEVICE(MADGE, PCI_DEVICE_ID_MADGE_AMBASSADOR_BAD), 0 },
{ 0, }
};
diff --git a/drivers/atm/eni.c b/drivers/atm/eni.c
index 90a5a7cac74..80f9f3659e4 100644
--- a/drivers/atm/eni.c
+++ b/drivers/atm/eni.c
@@ -2269,10 +2269,8 @@ out0:
static struct pci_device_id eni_pci_tbl[] = {
- { PCI_VENDOR_ID_EF, PCI_DEVICE_ID_EF_ATM_FPGA, PCI_ANY_ID, PCI_ANY_ID,
- 0, 0, 0 /* FPGA */ },
- { PCI_VENDOR_ID_EF, PCI_DEVICE_ID_EF_ATM_ASIC, PCI_ANY_ID, PCI_ANY_ID,
- 0, 0, 1 /* ASIC */ },
+ { PCI_VDEVICE(EF, PCI_DEVICE_ID_EF_ATM_FPGA), 0 /* FPGA */ },
+ { PCI_VDEVICE(EF, PCI_DEVICE_ID_EF_ATM_ASIC), 1 /* ASIC */ },
{ 0, }
};
MODULE_DEVICE_TABLE(pci,eni_pci_tbl);
diff --git a/drivers/atm/firestream.c b/drivers/atm/firestream.c
index 6e600afd06a..8717809787f 100644
--- a/drivers/atm/firestream.c
+++ b/drivers/atm/firestream.c
@@ -2027,10 +2027,8 @@ static void __devexit firestream_remove_one (struct pci_dev *pdev)
}
static struct pci_device_id firestream_pci_tbl[] = {
- { PCI_VENDOR_ID_FUJITSU_ME, PCI_DEVICE_ID_FUJITSU_FS50,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, FS_IS50},
- { PCI_VENDOR_ID_FUJITSU_ME, PCI_DEVICE_ID_FUJITSU_FS155,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, FS_IS155},
+ { PCI_VDEVICE(FUJITSU_ME, PCI_DEVICE_ID_FUJITSU_FS50), FS_IS50},
+ { PCI_VDEVICE(FUJITSU_ME, PCI_DEVICE_ID_FUJITSU_FS155), FS_IS155},
{ 0, }
};
diff --git a/drivers/atm/fore200e.c b/drivers/atm/fore200e.c
index da8f176c051..b7385e07771 100644
--- a/drivers/atm/fore200e.c
+++ b/drivers/atm/fore200e.c
@@ -2657,7 +2657,7 @@ static int __devinit fore200e_sba_probe(struct of_device *op,
fore200e->bus = bus;
fore200e->bus_dev = op;
- fore200e->irq = op->irqs[0];
+ fore200e->irq = op->archdata.irqs[0];
fore200e->phys_base = op->resource[0].start;
sprintf(fore200e->name, "%s-%d", bus->model_name, index);
@@ -2795,7 +2795,7 @@ static int __init fore200e_module_init(void)
printk(FORE200E "FORE Systems 200E-series ATM driver - version " FORE200E_VERSION "\n");
#ifdef CONFIG_SBUS
- err = of_register_driver(&fore200e_sba_driver, &of_bus_type);
+ err = of_register_platform_driver(&fore200e_sba_driver);
if (err)
return err;
#endif
@@ -2806,7 +2806,7 @@ static int __init fore200e_module_init(void)
#ifdef CONFIG_SBUS
if (err)
- of_unregister_driver(&fore200e_sba_driver);
+ of_unregister_platform_driver(&fore200e_sba_driver);
#endif
return err;
@@ -2818,7 +2818,7 @@ static void __exit fore200e_module_cleanup(void)
pci_unregister_driver(&fore200e_pca_driver);
#endif
#ifdef CONFIG_SBUS
- of_unregister_driver(&fore200e_sba_driver);
+ of_unregister_platform_driver(&fore200e_sba_driver);
#endif
}
diff --git a/drivers/atm/he.c b/drivers/atm/he.c
index 56c2e99e458..801e8b6e9d1 100644
--- a/drivers/atm/he.c
+++ b/drivers/atm/he.c
@@ -67,6 +67,7 @@
#include <linux/timer.h>
#include <linux/interrupt.h>
#include <linux/dma-mapping.h>
+#include <linux/bitmap.h>
#include <linux/slab.h>
#include <asm/io.h>
#include <asm/byteorder.h>
@@ -778,61 +779,39 @@ he_init_cs_block_rcm(struct he_dev *he_dev)
static int __devinit
he_init_group(struct he_dev *he_dev, int group)
{
+ struct he_buff *heb, *next;
+ dma_addr_t mapping;
int i;
- /* small buffer pool */
- he_dev->rbps_pool = pci_pool_create("rbps", he_dev->pci_dev,
- CONFIG_RBPS_BUFSIZE, 8, 0);
- if (he_dev->rbps_pool == NULL) {
- hprintk("unable to create rbps pages\n");
+ he_writel(he_dev, 0x0, G0_RBPS_S + (group * 32));
+ he_writel(he_dev, 0x0, G0_RBPS_T + (group * 32));
+ he_writel(he_dev, 0x0, G0_RBPS_QI + (group * 32));
+ he_writel(he_dev, RBP_THRESH(0x1) | RBP_QSIZE(0x0),
+ G0_RBPS_BS + (group * 32));
+
+ /* bitmap table */
+ he_dev->rbpl_table = kmalloc(BITS_TO_LONGS(RBPL_TABLE_SIZE)
+ * sizeof(unsigned long), GFP_KERNEL);
+ if (!he_dev->rbpl_table) {
+ hprintk("unable to allocate rbpl bitmap table\n");
return -ENOMEM;
}
+ bitmap_zero(he_dev->rbpl_table, RBPL_TABLE_SIZE);
- he_dev->rbps_base = pci_alloc_consistent(he_dev->pci_dev,
- CONFIG_RBPS_SIZE * sizeof(struct he_rbp), &he_dev->rbps_phys);
- if (he_dev->rbps_base == NULL) {
- hprintk("failed to alloc rbps_base\n");
- goto out_destroy_rbps_pool;
+ /* rbpl_virt 64-bit pointers */
+ he_dev->rbpl_virt = kmalloc(RBPL_TABLE_SIZE
+ * sizeof(struct he_buff *), GFP_KERNEL);
+ if (!he_dev->rbpl_virt) {
+ hprintk("unable to allocate rbpl virt table\n");
+ goto out_free_rbpl_table;
}
- memset(he_dev->rbps_base, 0, CONFIG_RBPS_SIZE * sizeof(struct he_rbp));
- he_dev->rbps_virt = kmalloc(CONFIG_RBPS_SIZE * sizeof(struct he_virt), GFP_KERNEL);
- if (he_dev->rbps_virt == NULL) {
- hprintk("failed to alloc rbps_virt\n");
- goto out_free_rbps_base;
- }
-
- for (i = 0; i < CONFIG_RBPS_SIZE; ++i) {
- dma_addr_t dma_handle;
- void *cpuaddr;
-
- cpuaddr = pci_pool_alloc(he_dev->rbps_pool, GFP_KERNEL|GFP_DMA, &dma_handle);
- if (cpuaddr == NULL)
- goto out_free_rbps_virt;
-
- he_dev->rbps_virt[i].virt = cpuaddr;
- he_dev->rbps_base[i].status = RBP_LOANED | RBP_SMALLBUF | (i << RBP_INDEX_OFF);
- he_dev->rbps_base[i].phys = dma_handle;
-
- }
- he_dev->rbps_tail = &he_dev->rbps_base[CONFIG_RBPS_SIZE - 1];
-
- he_writel(he_dev, he_dev->rbps_phys, G0_RBPS_S + (group * 32));
- he_writel(he_dev, RBPS_MASK(he_dev->rbps_tail),
- G0_RBPS_T + (group * 32));
- he_writel(he_dev, CONFIG_RBPS_BUFSIZE/4,
- G0_RBPS_BS + (group * 32));
- he_writel(he_dev,
- RBP_THRESH(CONFIG_RBPS_THRESH) |
- RBP_QSIZE(CONFIG_RBPS_SIZE - 1) |
- RBP_INT_ENB,
- G0_RBPS_QI + (group * 32));
/* large buffer pool */
he_dev->rbpl_pool = pci_pool_create("rbpl", he_dev->pci_dev,
- CONFIG_RBPL_BUFSIZE, 8, 0);
+ CONFIG_RBPL_BUFSIZE, 64, 0);
if (he_dev->rbpl_pool == NULL) {
hprintk("unable to create rbpl pool\n");
- goto out_free_rbps_virt;
+ goto out_free_rbpl_virt;
}
he_dev->rbpl_base = pci_alloc_consistent(he_dev->pci_dev,
@@ -842,30 +821,29 @@ he_init_group(struct he_dev *he_dev, int group)
goto out_destroy_rbpl_pool;
}
memset(he_dev->rbpl_base, 0, CONFIG_RBPL_SIZE * sizeof(struct he_rbp));
- he_dev->rbpl_virt = kmalloc(CONFIG_RBPL_SIZE * sizeof(struct he_virt), GFP_KERNEL);
- if (he_dev->rbpl_virt == NULL) {
- hprintk("failed to alloc rbpl_virt\n");
- goto out_free_rbpl_base;
- }
+
+ INIT_LIST_HEAD(&he_dev->rbpl_outstanding);
for (i = 0; i < CONFIG_RBPL_SIZE; ++i) {
- dma_addr_t dma_handle;
- void *cpuaddr;
- cpuaddr = pci_pool_alloc(he_dev->rbpl_pool, GFP_KERNEL|GFP_DMA, &dma_handle);
- if (cpuaddr == NULL)
- goto out_free_rbpl_virt;
+ heb = pci_pool_alloc(he_dev->rbpl_pool, GFP_KERNEL|GFP_DMA, &mapping);
+ if (!heb)
+ goto out_free_rbpl;
+ heb->mapping = mapping;
+ list_add(&heb->entry, &he_dev->rbpl_outstanding);
- he_dev->rbpl_virt[i].virt = cpuaddr;
- he_dev->rbpl_base[i].status = RBP_LOANED | (i << RBP_INDEX_OFF);
- he_dev->rbpl_base[i].phys = dma_handle;
+ set_bit(i, he_dev->rbpl_table);
+ he_dev->rbpl_virt[i] = heb;
+ he_dev->rbpl_hint = i + 1;
+ he_dev->rbpl_base[i].idx = i << RBP_IDX_OFFSET;
+ he_dev->rbpl_base[i].phys = mapping + offsetof(struct he_buff, data);
}
he_dev->rbpl_tail = &he_dev->rbpl_base[CONFIG_RBPL_SIZE - 1];
he_writel(he_dev, he_dev->rbpl_phys, G0_RBPL_S + (group * 32));
he_writel(he_dev, RBPL_MASK(he_dev->rbpl_tail),
G0_RBPL_T + (group * 32));
- he_writel(he_dev, CONFIG_RBPL_BUFSIZE/4,
+ he_writel(he_dev, (CONFIG_RBPL_BUFSIZE - sizeof(struct he_buff))/4,
G0_RBPL_BS + (group * 32));
he_writel(he_dev,
RBP_THRESH(CONFIG_RBPL_THRESH) |
@@ -879,7 +857,7 @@ he_init_group(struct he_dev *he_dev, int group)
CONFIG_RBRQ_SIZE * sizeof(struct he_rbrq), &he_dev->rbrq_phys);
if (he_dev->rbrq_base == NULL) {
hprintk("failed to allocate rbrq\n");
- goto out_free_rbpl_virt;
+ goto out_free_rbpl;
}
memset(he_dev->rbrq_base, 0, CONFIG_RBRQ_SIZE * sizeof(struct he_rbrq));
@@ -920,33 +898,20 @@ out_free_rbpq_base:
pci_free_consistent(he_dev->pci_dev, CONFIG_RBRQ_SIZE *
sizeof(struct he_rbrq), he_dev->rbrq_base,
he_dev->rbrq_phys);
- i = CONFIG_RBPL_SIZE;
-out_free_rbpl_virt:
- while (i--)
- pci_pool_free(he_dev->rbpl_pool, he_dev->rbpl_virt[i].virt,
- he_dev->rbpl_base[i].phys);
- kfree(he_dev->rbpl_virt);
+out_free_rbpl:
+ list_for_each_entry_safe(heb, next, &he_dev->rbpl_outstanding, entry)
+ pci_pool_free(he_dev->rbpl_pool, heb, heb->mapping);
-out_free_rbpl_base:
pci_free_consistent(he_dev->pci_dev, CONFIG_RBPL_SIZE *
sizeof(struct he_rbp), he_dev->rbpl_base,
he_dev->rbpl_phys);
out_destroy_rbpl_pool:
pci_pool_destroy(he_dev->rbpl_pool);
+out_free_rbpl_virt:
+ kfree(he_dev->rbpl_virt);
+out_free_rbpl_table:
+ kfree(he_dev->rbpl_table);
- i = CONFIG_RBPS_SIZE;
-out_free_rbps_virt:
- while (i--)
- pci_pool_free(he_dev->rbps_pool, he_dev->rbps_virt[i].virt,
- he_dev->rbps_base[i].phys);
- kfree(he_dev->rbps_virt);
-
-out_free_rbps_base:
- pci_free_consistent(he_dev->pci_dev, CONFIG_RBPS_SIZE *
- sizeof(struct he_rbp), he_dev->rbps_base,
- he_dev->rbps_phys);
-out_destroy_rbps_pool:
- pci_pool_destroy(he_dev->rbps_pool);
return -ENOMEM;
}
@@ -1002,7 +967,8 @@ he_init_irq(struct he_dev *he_dev)
he_writel(he_dev, 0x0, GRP_54_MAP);
he_writel(he_dev, 0x0, GRP_76_MAP);
- if (request_irq(he_dev->pci_dev->irq, he_irq_handler, IRQF_DISABLED|IRQF_SHARED, DEV_LABEL, he_dev)) {
+ if (request_irq(he_dev->pci_dev->irq,
+ he_irq_handler, IRQF_SHARED, DEV_LABEL, he_dev)) {
hprintk("irq %d already in use\n", he_dev->pci_dev->irq);
return -EINVAL;
}
@@ -1576,9 +1542,10 @@ he_start(struct atm_dev *dev)
static void
he_stop(struct he_dev *he_dev)
{
- u16 command;
- u32 gen_cntl_0, reg;
+ struct he_buff *heb, *next;
struct pci_dev *pci_dev;
+ u32 gen_cntl_0, reg;
+ u16 command;
pci_dev = he_dev->pci_dev;
@@ -1619,37 +1586,19 @@ he_stop(struct he_dev *he_dev)
he_dev->hsp, he_dev->hsp_phys);
if (he_dev->rbpl_base) {
- int i;
-
- for (i = 0; i < CONFIG_RBPL_SIZE; ++i) {
- void *cpuaddr = he_dev->rbpl_virt[i].virt;
- dma_addr_t dma_handle = he_dev->rbpl_base[i].phys;
+ list_for_each_entry_safe(heb, next, &he_dev->rbpl_outstanding, entry)
+ pci_pool_free(he_dev->rbpl_pool, heb, heb->mapping);
- pci_pool_free(he_dev->rbpl_pool, cpuaddr, dma_handle);
- }
pci_free_consistent(he_dev->pci_dev, CONFIG_RBPL_SIZE
* sizeof(struct he_rbp), he_dev->rbpl_base, he_dev->rbpl_phys);
}
+ kfree(he_dev->rbpl_virt);
+ kfree(he_dev->rbpl_table);
+
if (he_dev->rbpl_pool)
pci_pool_destroy(he_dev->rbpl_pool);
- if (he_dev->rbps_base) {
- int i;
-
- for (i = 0; i < CONFIG_RBPS_SIZE; ++i) {
- void *cpuaddr = he_dev->rbps_virt[i].virt;
- dma_addr_t dma_handle = he_dev->rbps_base[i].phys;
-
- pci_pool_free(he_dev->rbps_pool, cpuaddr, dma_handle);
- }
- pci_free_consistent(he_dev->pci_dev, CONFIG_RBPS_SIZE
- * sizeof(struct he_rbp), he_dev->rbps_base, he_dev->rbps_phys);
- }
-
- if (he_dev->rbps_pool)
- pci_pool_destroy(he_dev->rbps_pool);
-
if (he_dev->rbrq_base)
pci_free_consistent(he_dev->pci_dev, CONFIG_RBRQ_SIZE * sizeof(struct he_rbrq),
he_dev->rbrq_base, he_dev->rbrq_phys);
@@ -1679,13 +1628,13 @@ static struct he_tpd *
__alloc_tpd(struct he_dev *he_dev)
{
struct he_tpd *tpd;
- dma_addr_t dma_handle;
+ dma_addr_t mapping;
- tpd = pci_pool_alloc(he_dev->tpd_pool, GFP_ATOMIC|GFP_DMA, &dma_handle);
+ tpd = pci_pool_alloc(he_dev->tpd_pool, GFP_ATOMIC|GFP_DMA, &mapping);
if (tpd == NULL)
return NULL;
- tpd->status = TPD_ADDR(dma_handle);
+ tpd->status = TPD_ADDR(mapping);
tpd->reserved = 0;
tpd->iovec[0].addr = 0; tpd->iovec[0].len = 0;
tpd->iovec[1].addr = 0; tpd->iovec[1].len = 0;
@@ -1714,13 +1663,12 @@ he_service_rbrq(struct he_dev *he_dev, int group)
struct he_rbrq *rbrq_tail = (struct he_rbrq *)
((unsigned long)he_dev->rbrq_base |
he_dev->hsp->group[group].rbrq_tail);
- struct he_rbp *rbp = NULL;
unsigned cid, lastcid = -1;
- unsigned buf_len = 0;
struct sk_buff *skb;
struct atm_vcc *vcc = NULL;
struct he_vcc *he_vcc;
- struct he_iovec *iov;
+ struct he_buff *heb, *next;
+ int i;
int pdus_assembled = 0;
int updated = 0;
@@ -1740,44 +1688,35 @@ he_service_rbrq(struct he_dev *he_dev, int group)
RBRQ_CON_CLOSED(he_dev->rbrq_head) ? " CON_CLOSED" : "",
RBRQ_HBUF_ERR(he_dev->rbrq_head) ? " HBUF_ERR" : "");
- if (RBRQ_ADDR(he_dev->rbrq_head) & RBP_SMALLBUF)
- rbp = &he_dev->rbps_base[RBP_INDEX(RBRQ_ADDR(he_dev->rbrq_head))];
- else
- rbp = &he_dev->rbpl_base[RBP_INDEX(RBRQ_ADDR(he_dev->rbrq_head))];
-
- buf_len = RBRQ_BUFLEN(he_dev->rbrq_head) * 4;
- cid = RBRQ_CID(he_dev->rbrq_head);
+ i = RBRQ_ADDR(he_dev->rbrq_head) >> RBP_IDX_OFFSET;
+ heb = he_dev->rbpl_virt[i];
+ cid = RBRQ_CID(he_dev->rbrq_head);
if (cid != lastcid)
vcc = __find_vcc(he_dev, cid);
lastcid = cid;
- if (vcc == NULL) {
- hprintk("vcc == NULL (cid 0x%x)\n", cid);
- if (!RBRQ_HBUF_ERR(he_dev->rbrq_head))
- rbp->status &= ~RBP_LOANED;
+ if (vcc == NULL || (he_vcc = HE_VCC(vcc)) == NULL) {
+ hprintk("vcc/he_vcc == NULL (cid 0x%x)\n", cid);
+ if (!RBRQ_HBUF_ERR(he_dev->rbrq_head)) {
+ clear_bit(i, he_dev->rbpl_table);
+ list_del(&heb->entry);
+ pci_pool_free(he_dev->rbpl_pool, heb, heb->mapping);
+ }
goto next_rbrq_entry;
}
- he_vcc = HE_VCC(vcc);
- if (he_vcc == NULL) {
- hprintk("he_vcc == NULL (cid 0x%x)\n", cid);
- if (!RBRQ_HBUF_ERR(he_dev->rbrq_head))
- rbp->status &= ~RBP_LOANED;
- goto next_rbrq_entry;
- }
-
if (RBRQ_HBUF_ERR(he_dev->rbrq_head)) {
hprintk("HBUF_ERR! (cid 0x%x)\n", cid);
atomic_inc(&vcc->stats->rx_drop);
goto return_host_buffers;
}
- he_vcc->iov_tail->iov_base = RBRQ_ADDR(he_dev->rbrq_head);
- he_vcc->iov_tail->iov_len = buf_len;
- he_vcc->pdu_len += buf_len;
- ++he_vcc->iov_tail;
+ heb->len = RBRQ_BUFLEN(he_dev->rbrq_head) * 4;
+ clear_bit(i, he_dev->rbpl_table);
+ list_move_tail(&heb->entry, &he_vcc->buffers);
+ he_vcc->pdu_len += heb->len;
if (RBRQ_CON_CLOSED(he_dev->rbrq_head)) {
lastcid = -1;
@@ -1786,12 +1725,6 @@ he_service_rbrq(struct he_dev *he_dev, int group)
goto return_host_buffers;
}
-#ifdef notdef
- if ((he_vcc->iov_tail - he_vcc->iov_head) > HE_MAXIOV) {
- hprintk("iovec full! cid 0x%x\n", cid);
- goto return_host_buffers;
- }
-#endif
if (!RBRQ_END_PDU(he_dev->rbrq_head))
goto next_rbrq_entry;
@@ -1819,15 +1752,8 @@ he_service_rbrq(struct he_dev *he_dev, int group)
__net_timestamp(skb);
- for (iov = he_vcc->iov_head;
- iov < he_vcc->iov_tail; ++iov) {
- if (iov->iov_base & RBP_SMALLBUF)
- memcpy(skb_put(skb, iov->iov_len),
- he_dev->rbps_virt[RBP_INDEX(iov->iov_base)].virt, iov->iov_len);
- else
- memcpy(skb_put(skb, iov->iov_len),
- he_dev->rbpl_virt[RBP_INDEX(iov->iov_base)].virt, iov->iov_len);
- }
+ list_for_each_entry(heb, &he_vcc->buffers, entry)
+ memcpy(skb_put(skb, heb->len), &heb->data, heb->len);
switch (vcc->qos.aal) {
case ATM_AAL0:
@@ -1867,17 +1793,9 @@ he_service_rbrq(struct he_dev *he_dev, int group)
return_host_buffers:
++pdus_assembled;
- for (iov = he_vcc->iov_head;
- iov < he_vcc->iov_tail; ++iov) {
- if (iov->iov_base & RBP_SMALLBUF)
- rbp = &he_dev->rbps_base[RBP_INDEX(iov->iov_base)];
- else
- rbp = &he_dev->rbpl_base[RBP_INDEX(iov->iov_base)];
-
- rbp->status &= ~RBP_LOANED;
- }
-
- he_vcc->iov_tail = he_vcc->iov_head;
+ list_for_each_entry_safe(heb, next, &he_vcc->buffers, entry)
+ pci_pool_free(he_dev->rbpl_pool, heb, heb->mapping);
+ INIT_LIST_HEAD(&he_vcc->buffers);
he_vcc->pdu_len = 0;
next_rbrq_entry:
@@ -1978,59 +1896,51 @@ next_tbrq_entry:
}
}
-
static void
he_service_rbpl(struct he_dev *he_dev, int group)
{
- struct he_rbp *newtail;
+ struct he_rbp *new_tail;
struct he_rbp *rbpl_head;
+ struct he_buff *heb;
+ dma_addr_t mapping;
+ int i;
int moved = 0;
rbpl_head = (struct he_rbp *) ((unsigned long)he_dev->rbpl_base |
RBPL_MASK(he_readl(he_dev, G0_RBPL_S)));
for (;;) {
- newtail = (struct he_rbp *) ((unsigned long)he_dev->rbpl_base |
+ new_tail = (struct he_rbp *) ((unsigned long)he_dev->rbpl_base |
RBPL_MASK(he_dev->rbpl_tail+1));
/* table 3.42 -- rbpl_tail should never be set to rbpl_head */
- if ((newtail == rbpl_head) || (newtail->status & RBP_LOANED))
+ if (new_tail == rbpl_head)
break;
- newtail->status |= RBP_LOANED;
- he_dev->rbpl_tail = newtail;
- ++moved;
- }
-
- if (moved)
- he_writel(he_dev, RBPL_MASK(he_dev->rbpl_tail), G0_RBPL_T);
-}
-
-static void
-he_service_rbps(struct he_dev *he_dev, int group)
-{
- struct he_rbp *newtail;
- struct he_rbp *rbps_head;
- int moved = 0;
-
- rbps_head = (struct he_rbp *) ((unsigned long)he_dev->rbps_base |
- RBPS_MASK(he_readl(he_dev, G0_RBPS_S)));
-
- for (;;) {
- newtail = (struct he_rbp *) ((unsigned long)he_dev->rbps_base |
- RBPS_MASK(he_dev->rbps_tail+1));
+ i = find_next_zero_bit(he_dev->rbpl_table, RBPL_TABLE_SIZE, he_dev->rbpl_hint);
+ if (i > (RBPL_TABLE_SIZE - 1)) {
+ i = find_first_zero_bit(he_dev->rbpl_table, RBPL_TABLE_SIZE);
+ if (i > (RBPL_TABLE_SIZE - 1))
+ break;
+ }
+ he_dev->rbpl_hint = i + 1;
- /* table 3.42 -- rbps_tail should never be set to rbps_head */
- if ((newtail == rbps_head) || (newtail->status & RBP_LOANED))
+ heb = pci_pool_alloc(he_dev->rbpl_pool, GFP_ATOMIC|GFP_DMA, &mapping);
+ if (!heb)
break;
-
- newtail->status |= RBP_LOANED;
- he_dev->rbps_tail = newtail;
+ heb->mapping = mapping;
+ list_add(&heb->entry, &he_dev->rbpl_outstanding);
+ he_dev->rbpl_virt[i] = heb;
+ set_bit(i, he_dev->rbpl_table);
+ new_tail->idx = i << RBP_IDX_OFFSET;
+ new_tail->phys = mapping + offsetof(struct he_buff, data);
+
+ he_dev->rbpl_tail = new_tail;
++moved;
}
if (moved)
- he_writel(he_dev, RBPS_MASK(he_dev->rbps_tail), G0_RBPS_T);
+ he_writel(he_dev, RBPL_MASK(he_dev->rbpl_tail), G0_RBPL_T);
}
static void
@@ -2055,10 +1965,8 @@ he_tasklet(unsigned long data)
HPRINTK("rbrq%d threshold\n", group);
/* fall through */
case ITYPE_RBRQ_TIMER:
- if (he_service_rbrq(he_dev, group)) {
+ if (he_service_rbrq(he_dev, group))
he_service_rbpl(he_dev, group);
- he_service_rbps(he_dev, group);
- }
break;
case ITYPE_TBRQ_THRESH:
HPRINTK("tbrq%d threshold\n", group);
@@ -2070,7 +1978,7 @@ he_tasklet(unsigned long data)
he_service_rbpl(he_dev, group);
break;
case ITYPE_RBPS_THRESH:
- he_service_rbps(he_dev, group);
+ /* shouldn't happen unless small buffers enabled */
break;
case ITYPE_PHY:
HPRINTK("phy interrupt\n");
@@ -2098,7 +2006,6 @@ he_tasklet(unsigned long data)
he_service_rbrq(he_dev, 0);
he_service_rbpl(he_dev, 0);
- he_service_rbps(he_dev, 0);
he_service_tbrq(he_dev, 0);
break;
default:
@@ -2252,7 +2159,7 @@ he_open(struct atm_vcc *vcc)
return -ENOMEM;
}
- he_vcc->iov_tail = he_vcc->iov_head;
+ INIT_LIST_HEAD(&he_vcc->buffers);
he_vcc->pdu_len = 0;
he_vcc->rc_index = -1;
@@ -2406,8 +2313,8 @@ he_open(struct atm_vcc *vcc)
goto open_failed;
}
- rsr1 = RSR1_GROUP(0);
- rsr4 = RSR4_GROUP(0);
+ rsr1 = RSR1_GROUP(0) | RSR1_RBPL_ONLY;
+ rsr4 = RSR4_GROUP(0) | RSR4_RBPL_ONLY;
rsr0 = vcc->qos.rxtp.traffic_class == ATM_UBR ?
(RSR0_EPD_ENABLE|RSR0_PPD_ENABLE) : 0;
@@ -2963,8 +2870,7 @@ module_param(sdh, bool, 0);
MODULE_PARM_DESC(sdh, "use SDH framing (default 0)");
static struct pci_device_id he_pci_tbl[] = {
- { PCI_VENDOR_ID_FORE, PCI_DEVICE_ID_FORE_HE, PCI_ANY_ID, PCI_ANY_ID,
- 0, 0, 0 },
+ { PCI_VDEVICE(FORE, PCI_DEVICE_ID_FORE_HE), 0 },
{ 0, }
};
diff --git a/drivers/atm/he.h b/drivers/atm/he.h
index c2983e0d4ec..110a27d2ecf 100644
--- a/drivers/atm/he.h
+++ b/drivers/atm/he.h
@@ -67,11 +67,6 @@
#define CONFIG_RBPL_BUFSIZE 4096
#define RBPL_MASK(x) (((unsigned long)(x))&((CONFIG_RBPL_SIZE<<3)-1))
-#define CONFIG_RBPS_SIZE 1024
-#define CONFIG_RBPS_THRESH 64
-#define CONFIG_RBPS_BUFSIZE 128
-#define RBPS_MASK(x) (((unsigned long)(x))&((CONFIG_RBPS_SIZE<<3)-1))
-
/* 5.1.3 initialize connection memory */
#define CONFIG_RSRA 0x00000
@@ -203,36 +198,37 @@ struct he_hsp {
} group[HE_NUM_GROUPS];
};
-/* figure 2.9 receive buffer pools */
+/*
+ * figure 2.9 receive buffer pools
+ *
+ * since a virtual address might be more than 32 bits, we store an index
+ * in the virt member of he_rbp. NOTE: the lower six bits in the rbrq
+ * addr member are used for buffer status further limiting us to 26 bits.
+ */
struct he_rbp {
volatile u32 phys;
- volatile u32 status;
+ volatile u32 idx; /* virt */
};
-/* NOTE: it is suggested that virt be the virtual address of the host
- buffer. on a 64-bit machine, this would not work. Instead, we
- store the real virtual address in another list, and store an index
- (and buffer status) in the virt member.
-*/
+#define RBP_IDX_OFFSET 6
-#define RBP_INDEX_OFF 6
-#define RBP_INDEX(x) (((long)(x) >> RBP_INDEX_OFF) & 0xffff)
-#define RBP_LOANED 0x80000000
-#define RBP_SMALLBUF 0x40000000
+/*
+ * the he dma engine will try to hold an extra 16 buffers in its local
+ * caches. and add a couple buffers for safety.
+ */
-struct he_virt {
- void *virt;
-};
+#define RBPL_TABLE_SIZE (CONFIG_RBPL_SIZE + 16 + 2)
-#define RBPL_ALIGNMENT CONFIG_RBPL_SIZE
-#define RBPS_ALIGNMENT CONFIG_RBPS_SIZE
+struct he_buff {
+ struct list_head entry;
+ dma_addr_t mapping;
+ unsigned long len;
+ u8 data[];
+};
#ifdef notyet
struct he_group {
- u32 rpbs_size, rpbs_qsize;
- struct he_rbp rbps_ba;
-
u32 rpbl_size, rpbl_qsize;
struct he_rpb_entry *rbpl_ba;
};
@@ -297,18 +293,15 @@ struct he_dev {
struct he_rbrq *rbrq_base, *rbrq_head;
int rbrq_peak;
+ struct he_buff **rbpl_virt;
+ unsigned long *rbpl_table;
+ unsigned long rbpl_hint;
struct pci_pool *rbpl_pool;
dma_addr_t rbpl_phys;
struct he_rbp *rbpl_base, *rbpl_tail;
- struct he_virt *rbpl_virt;
+ struct list_head rbpl_outstanding;
int rbpl_peak;
- struct pci_pool *rbps_pool;
- dma_addr_t rbps_phys;
- struct he_rbp *rbps_base, *rbps_tail;
- struct he_virt *rbps_virt;
- int rbps_peak;
-
dma_addr_t tbrq_phys;
struct he_tbrq *tbrq_base, *tbrq_head;
int tbrq_peak;
@@ -321,20 +314,12 @@ struct he_dev {
struct he_dev *next;
};
-struct he_iovec
-{
- u32 iov_base;
- u32 iov_len;
-};
-
#define HE_MAXIOV 20
struct he_vcc
{
- struct he_iovec iov_head[HE_MAXIOV];
- struct he_iovec *iov_tail;
+ struct list_head buffers;
int pdu_len;
-
int rc_index;
wait_queue_head_t rx_waitq;
diff --git a/drivers/atm/idt77105.c b/drivers/atm/idt77105.c
index dab5cf5274f..bca9cb89a11 100644
--- a/drivers/atm/idt77105.c
+++ b/drivers/atm/idt77105.c
@@ -126,7 +126,7 @@ static void idt77105_restart_timer_func(unsigned long dummy)
istat = GET(ISTAT); /* side effect: clears all interrupt status bits */
if (istat & IDT77105_ISTAT_GOODSIG) {
/* Found signal again */
- dev->signal = ATM_PHY_SIG_FOUND;
+ atm_dev_signal_change(dev, ATM_PHY_SIG_FOUND);
printk(KERN_NOTICE "%s(itf %d): signal detected again\n",
dev->type,dev->number);
/* flush the receive FIFO */
@@ -222,7 +222,7 @@ static void idt77105_int(struct atm_dev *dev)
/* Rx Signal Condition Change - line went up or down */
if (istat & IDT77105_ISTAT_GOODSIG) { /* signal detected again */
/* This should not happen (restart timer does it) but JIC */
- dev->signal = ATM_PHY_SIG_FOUND;
+ atm_dev_signal_change(dev, ATM_PHY_SIG_FOUND);
} else { /* signal lost */
/*
* Disable interrupts and stop all transmission and
@@ -235,7 +235,7 @@ static void idt77105_int(struct atm_dev *dev)
IDT77105_MCR_DRIC|
IDT77105_MCR_HALTTX
) & ~IDT77105_MCR_EIP, MCR);
- dev->signal = ATM_PHY_SIG_LOST;
+ atm_dev_signal_change(dev, ATM_PHY_SIG_LOST);
printk(KERN_NOTICE "%s(itf %d): signal lost\n",
dev->type,dev->number);
}
@@ -272,8 +272,9 @@ static int idt77105_start(struct atm_dev *dev)
memset(&PRIV(dev)->stats,0,sizeof(struct idt77105_stats));
/* initialise dev->signal from Good Signal Bit */
- dev->signal = GET(ISTAT) & IDT77105_ISTAT_GOODSIG ? ATM_PHY_SIG_FOUND :
- ATM_PHY_SIG_LOST;
+ atm_dev_signal_change(dev,
+ GET(ISTAT) & IDT77105_ISTAT_GOODSIG ?
+ ATM_PHY_SIG_FOUND : ATM_PHY_SIG_LOST);
if (dev->signal == ATM_PHY_SIG_LOST)
printk(KERN_WARNING "%s(itf %d): no signal\n",dev->type,
dev->number);
diff --git a/drivers/atm/idt77252.c b/drivers/atm/idt77252.c
index 98657a6a330..1679cbf0c58 100644
--- a/drivers/atm/idt77252.c
+++ b/drivers/atm/idt77252.c
@@ -3364,7 +3364,7 @@ init_card(struct atm_dev *dev)
writel(SAR_STAT_TMROF, SAR_REG_STAT);
}
IPRINTK("%s: Request IRQ ... ", card->name);
- if (request_irq(pcidev->irq, idt77252_interrupt, IRQF_DISABLED|IRQF_SHARED,
+ if (request_irq(pcidev->irq, idt77252_interrupt, IRQF_SHARED,
card->name, card) != 0) {
printk("%s: can't allocate IRQ.\n", card->name);
deinit_card(card);
@@ -3779,8 +3779,7 @@ err_out_disable_pdev:
static struct pci_device_id idt77252_pci_tbl[] =
{
- { PCI_VENDOR_ID_IDT, PCI_DEVICE_ID_IDT_IDT77252,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+ { PCI_VDEVICE(IDT, PCI_DEVICE_ID_IDT_IDT77252), 0 },
{ 0, }
};
diff --git a/drivers/atm/nicstar.c b/drivers/atm/nicstar.c
index b7473a6110a..2f3516b7f11 100644
--- a/drivers/atm/nicstar.c
+++ b/drivers/atm/nicstar.c
@@ -1,5 +1,4 @@
-/******************************************************************************
- *
+/*
* nicstar.c
*
* Device driver supporting CBR for IDT 77201/77211 "NICStAR" based cards.
@@ -16,12 +15,10 @@
*
*
* (C) INESC 1999
- *
- *
- ******************************************************************************/
-
+ */
-/**** IMPORTANT INFORMATION ***************************************************
+/*
+ * IMPORTANT INFORMATION
*
* There are currently three types of spinlocks:
*
@@ -31,9 +28,9 @@
*
* These must NEVER be grabbed in reverse order.
*
- ******************************************************************************/
+ */
-/* Header files ***************************************************************/
+/* Header files */
#include <linux/module.h>
#include <linux/kernel.h>
@@ -41,6 +38,7 @@
#include <linux/atmdev.h>
#include <linux/atm.h>
#include <linux/pci.h>
+#include <linux/dma-mapping.h>
#include <linux/types.h>
#include <linux/string.h>
#include <linux/delay.h>
@@ -50,6 +48,7 @@
#include <linux/interrupt.h>
#include <linux/bitops.h>
#include <linux/slab.h>
+#include <linux/idr.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include <asm/atomic.h>
@@ -61,16 +60,11 @@
#include "idt77105.h"
#endif /* CONFIG_ATM_NICSTAR_USE_IDT77105 */
-#if BITS_PER_LONG != 32
-# error FIXME: this driver requires a 32-bit platform
-#endif
-
-/* Additional code ************************************************************/
+/* Additional code */
#include "nicstarmac.c"
-
-/* Configurable parameters ****************************************************/
+/* Configurable parameters */
#undef PHY_LOOPBACK
#undef TX_DEBUG
@@ -78,11 +72,10 @@
#undef GENERAL_DEBUG
#undef EXTRA_DEBUG
-#undef NS_USE_DESTRUCTORS /* For now keep this undefined unless you know
- you're going to use only raw ATM */
+#undef NS_USE_DESTRUCTORS /* For now keep this undefined unless you know
+ you're going to use only raw ATM */
-
-/* Do not touch these *********************************************************/
+/* Do not touch these */
#ifdef TX_DEBUG
#define TXPRINTK(args...) printk(args)
@@ -108,2908 +101,2773 @@
#define XPRINTK(args...)
#endif /* EXTRA_DEBUG */
-
-/* Macros *********************************************************************/
+/* Macros */
#define CMD_BUSY(card) (readl((card)->membase + STAT) & NS_STAT_CMDBZ)
#define NS_DELAY mdelay(1)
-#define ALIGN_BUS_ADDR(addr, alignment) \
- ((((u32) (addr)) + (((u32) (alignment)) - 1)) & ~(((u32) (alignment)) - 1))
-#define ALIGN_ADDRESS(addr, alignment) \
- bus_to_virt(ALIGN_BUS_ADDR(virt_to_bus(addr), alignment))
-
-#undef CEIL
+#define PTR_DIFF(a, b) ((u32)((unsigned long)(a) - (unsigned long)(b)))
#ifndef ATM_SKB
#define ATM_SKB(s) (&(s)->atm)
#endif
+#define scq_virt_to_bus(scq, p) \
+ (scq->dma + ((unsigned long)(p) - (unsigned long)(scq)->org))
-/* Function declarations ******************************************************/
+/* Function declarations */
-static u32 ns_read_sram(ns_dev *card, u32 sram_address);
-static void ns_write_sram(ns_dev *card, u32 sram_address, u32 *value, int count);
+static u32 ns_read_sram(ns_dev * card, u32 sram_address);
+static void ns_write_sram(ns_dev * card, u32 sram_address, u32 * value,
+ int count);
static int __devinit ns_init_card(int i, struct pci_dev *pcidev);
-static void __devinit ns_init_card_error(ns_dev *card, int error);
-static scq_info *get_scq(int size, u32 scd);
-static void free_scq(scq_info *scq, struct atm_vcc *vcc);
+static void __devinit ns_init_card_error(ns_dev * card, int error);
+static scq_info *get_scq(ns_dev *card, int size, u32 scd);
+static void free_scq(ns_dev *card, scq_info * scq, struct atm_vcc *vcc);
static void push_rxbufs(ns_dev *, struct sk_buff *);
static irqreturn_t ns_irq_handler(int irq, void *dev_id);
static int ns_open(struct atm_vcc *vcc);
static void ns_close(struct atm_vcc *vcc);
-static void fill_tst(ns_dev *card, int n, vc_map *vc);
+static void fill_tst(ns_dev * card, int n, vc_map * vc);
static int ns_send(struct atm_vcc *vcc, struct sk_buff *skb);
-static int push_scqe(ns_dev *card, vc_map *vc, scq_info *scq, ns_scqe *tbd,
- struct sk_buff *skb);
-static void process_tsq(ns_dev *card);
-static void drain_scq(ns_dev *card, scq_info *scq, int pos);
-static void process_rsq(ns_dev *card);
-static void dequeue_rx(ns_dev *card, ns_rsqe *rsqe);
+static int push_scqe(ns_dev * card, vc_map * vc, scq_info * scq, ns_scqe * tbd,
+ struct sk_buff *skb);
+static void process_tsq(ns_dev * card);
+static void drain_scq(ns_dev * card, scq_info * scq, int pos);
+static void process_rsq(ns_dev * card);
+static void dequeue_rx(ns_dev * card, ns_rsqe * rsqe);
#ifdef NS_USE_DESTRUCTORS
static void ns_sb_destructor(struct sk_buff *sb);
static void ns_lb_destructor(struct sk_buff *lb);
static void ns_hb_destructor(struct sk_buff *hb);
#endif /* NS_USE_DESTRUCTORS */
-static void recycle_rx_buf(ns_dev *card, struct sk_buff *skb);
-static void recycle_iovec_rx_bufs(ns_dev *card, struct iovec *iov, int count);
-static void recycle_iov_buf(ns_dev *card, struct sk_buff *iovb);
-static void dequeue_sm_buf(ns_dev *card, struct sk_buff *sb);
-static void dequeue_lg_buf(ns_dev *card, struct sk_buff *lb);
-static int ns_proc_read(struct atm_dev *dev, loff_t *pos, char *page);
-static int ns_ioctl(struct atm_dev *dev, unsigned int cmd, void __user *arg);
-static void which_list(ns_dev *card, struct sk_buff *skb);
+static void recycle_rx_buf(ns_dev * card, struct sk_buff *skb);
+static void recycle_iovec_rx_bufs(ns_dev * card, struct iovec *iov, int count);
+static void recycle_iov_buf(ns_dev * card, struct sk_buff *iovb);
+static void dequeue_sm_buf(ns_dev * card, struct sk_buff *sb);
+static void dequeue_lg_buf(ns_dev * card, struct sk_buff *lb);
+static int ns_proc_read(struct atm_dev *dev, loff_t * pos, char *page);
+static int ns_ioctl(struct atm_dev *dev, unsigned int cmd, void __user * arg);
+#ifdef EXTRA_DEBUG
+static void which_list(ns_dev * card, struct sk_buff *skb);
+#endif
static void ns_poll(unsigned long arg);
static int ns_parse_mac(char *mac, unsigned char *esi);
-static short ns_h2i(char c);
static void ns_phy_put(struct atm_dev *dev, unsigned char value,
- unsigned long addr);
+ unsigned long addr);
static unsigned char ns_phy_get(struct atm_dev *dev, unsigned long addr);
-
-
-/* Global variables ***********************************************************/
+/* Global variables */
static struct ns_dev *cards[NS_MAX_CARDS];
static unsigned num_cards;
-static struct atmdev_ops atm_ops =
-{
- .open = ns_open,
- .close = ns_close,
- .ioctl = ns_ioctl,
- .send = ns_send,
- .phy_put = ns_phy_put,
- .phy_get = ns_phy_get,
- .proc_read = ns_proc_read,
- .owner = THIS_MODULE,
+static struct atmdev_ops atm_ops = {
+ .open = ns_open,
+ .close = ns_close,
+ .ioctl = ns_ioctl,
+ .send = ns_send,
+ .phy_put = ns_phy_put,
+ .phy_get = ns_phy_get,
+ .proc_read = ns_proc_read,
+ .owner = THIS_MODULE,
};
+
static struct timer_list ns_timer;
static char *mac[NS_MAX_CARDS];
module_param_array(mac, charp, NULL, 0);
MODULE_LICENSE("GPL");
-
-/* Functions*******************************************************************/
+/* Functions */
static int __devinit nicstar_init_one(struct pci_dev *pcidev,
const struct pci_device_id *ent)
{
- static int index = -1;
- unsigned int error;
+ static int index = -1;
+ unsigned int error;
- index++;
- cards[index] = NULL;
+ index++;
+ cards[index] = NULL;
- error = ns_init_card(index, pcidev);
- if (error) {
- cards[index--] = NULL; /* don't increment index */
- goto err_out;
- }
+ error = ns_init_card(index, pcidev);
+ if (error) {
+ cards[index--] = NULL; /* don't increment index */
+ goto err_out;
+ }
- return 0;
+ return 0;
err_out:
- return -ENODEV;
+ return -ENODEV;
}
-
-
static void __devexit nicstar_remove_one(struct pci_dev *pcidev)
{
- int i, j;
- ns_dev *card = pci_get_drvdata(pcidev);
- struct sk_buff *hb;
- struct sk_buff *iovb;
- struct sk_buff *lb;
- struct sk_buff *sb;
-
- i = card->index;
-
- if (cards[i] == NULL)
- return;
-
- if (card->atmdev->phy && card->atmdev->phy->stop)
- card->atmdev->phy->stop(card->atmdev);
-
- /* Stop everything */
- writel(0x00000000, card->membase + CFG);
-
- /* De-register device */
- atm_dev_deregister(card->atmdev);
-
- /* Disable PCI device */
- pci_disable_device(pcidev);
-
- /* Free up resources */
- j = 0;
- PRINTK("nicstar%d: freeing %d huge buffers.\n", i, card->hbpool.count);
- while ((hb = skb_dequeue(&card->hbpool.queue)) != NULL)
- {
- dev_kfree_skb_any(hb);
- j++;
- }
- PRINTK("nicstar%d: %d huge buffers freed.\n", i, j);
- j = 0;
- PRINTK("nicstar%d: freeing %d iovec buffers.\n", i, card->iovpool.count);
- while ((iovb = skb_dequeue(&card->iovpool.queue)) != NULL)
- {
- dev_kfree_skb_any(iovb);
- j++;
- }
- PRINTK("nicstar%d: %d iovec buffers freed.\n", i, j);
- while ((lb = skb_dequeue(&card->lbpool.queue)) != NULL)
- dev_kfree_skb_any(lb);
- while ((sb = skb_dequeue(&card->sbpool.queue)) != NULL)
- dev_kfree_skb_any(sb);
- free_scq(card->scq0, NULL);
- for (j = 0; j < NS_FRSCD_NUM; j++)
- {
- if (card->scd2vc[j] != NULL)
- free_scq(card->scd2vc[j]->scq, card->scd2vc[j]->tx_vcc);
- }
- kfree(card->rsq.org);
- kfree(card->tsq.org);
- free_irq(card->pcidev->irq, card);
- iounmap(card->membase);
- kfree(card);
+ int i, j;
+ ns_dev *card = pci_get_drvdata(pcidev);
+ struct sk_buff *hb;
+ struct sk_buff *iovb;
+ struct sk_buff *lb;
+ struct sk_buff *sb;
+
+ i = card->index;
+
+ if (cards[i] == NULL)
+ return;
+
+ if (card->atmdev->phy && card->atmdev->phy->stop)
+ card->atmdev->phy->stop(card->atmdev);
+
+ /* Stop everything */
+ writel(0x00000000, card->membase + CFG);
+
+ /* De-register device */
+ atm_dev_deregister(card->atmdev);
+
+ /* Disable PCI device */
+ pci_disable_device(pcidev);
+
+ /* Free up resources */
+ j = 0;
+ PRINTK("nicstar%d: freeing %d huge buffers.\n", i, card->hbpool.count);
+ while ((hb = skb_dequeue(&card->hbpool.queue)) != NULL) {
+ dev_kfree_skb_any(hb);
+ j++;
+ }
+ PRINTK("nicstar%d: %d huge buffers freed.\n", i, j);
+ j = 0;
+ PRINTK("nicstar%d: freeing %d iovec buffers.\n", i,
+ card->iovpool.count);
+ while ((iovb = skb_dequeue(&card->iovpool.queue)) != NULL) {
+ dev_kfree_skb_any(iovb);
+ j++;
+ }
+ PRINTK("nicstar%d: %d iovec buffers freed.\n", i, j);
+ while ((lb = skb_dequeue(&card->lbpool.queue)) != NULL)
+ dev_kfree_skb_any(lb);
+ while ((sb = skb_dequeue(&card->sbpool.queue)) != NULL)
+ dev_kfree_skb_any(sb);
+ free_scq(card, card->scq0, NULL);
+ for (j = 0; j < NS_FRSCD_NUM; j++) {
+ if (card->scd2vc[j] != NULL)
+ free_scq(card, card->scd2vc[j]->scq, card->scd2vc[j]->tx_vcc);
+ }
+ idr_remove_all(&card->idr);
+ idr_destroy(&card->idr);
+ pci_free_consistent(card->pcidev, NS_RSQSIZE + NS_RSQ_ALIGNMENT,
+ card->rsq.org, card->rsq.dma);
+ pci_free_consistent(card->pcidev, NS_TSQSIZE + NS_TSQ_ALIGNMENT,
+ card->tsq.org, card->tsq.dma);
+ free_irq(card->pcidev->irq, card);
+ iounmap(card->membase);
+ kfree(card);
}
-
-
-static struct pci_device_id nicstar_pci_tbl[] __devinitdata =
-{
- {PCI_VENDOR_ID_IDT, PCI_DEVICE_ID_IDT_IDT77201,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+static struct pci_device_id nicstar_pci_tbl[] __devinitdata = {
+ { PCI_VDEVICE(IDT, PCI_DEVICE_ID_IDT_IDT77201), 0 },
{0,} /* terminate list */
};
-MODULE_DEVICE_TABLE(pci, nicstar_pci_tbl);
-
+MODULE_DEVICE_TABLE(pci, nicstar_pci_tbl);
static struct pci_driver nicstar_driver = {
- .name = "nicstar",
- .id_table = nicstar_pci_tbl,
- .probe = nicstar_init_one,
- .remove = __devexit_p(nicstar_remove_one),
+ .name = "nicstar",
+ .id_table = nicstar_pci_tbl,
+ .probe = nicstar_init_one,
+ .remove = __devexit_p(nicstar_remove_one),
};
-
-
static int __init nicstar_init(void)
{
- unsigned error = 0; /* Initialized to remove compile warning */
+ unsigned error = 0; /* Initialized to remove compile warning */
+
+ XPRINTK("nicstar: nicstar_init() called.\n");
- XPRINTK("nicstar: nicstar_init() called.\n");
+ error = pci_register_driver(&nicstar_driver);
- error = pci_register_driver(&nicstar_driver);
-
- TXPRINTK("nicstar: TX debug enabled.\n");
- RXPRINTK("nicstar: RX debug enabled.\n");
- PRINTK("nicstar: General debug enabled.\n");
+ TXPRINTK("nicstar: TX debug enabled.\n");
+ RXPRINTK("nicstar: RX debug enabled.\n");
+ PRINTK("nicstar: General debug enabled.\n");
#ifdef PHY_LOOPBACK
- printk("nicstar: using PHY loopback.\n");
+ printk("nicstar: using PHY loopback.\n");
#endif /* PHY_LOOPBACK */
- XPRINTK("nicstar: nicstar_init() returned.\n");
-
- if (!error) {
- init_timer(&ns_timer);
- ns_timer.expires = jiffies + NS_POLL_PERIOD;
- ns_timer.data = 0UL;
- ns_timer.function = ns_poll;
- add_timer(&ns_timer);
- }
-
- return error;
-}
+ XPRINTK("nicstar: nicstar_init() returned.\n");
+ if (!error) {
+ init_timer(&ns_timer);
+ ns_timer.expires = jiffies + NS_POLL_PERIOD;
+ ns_timer.data = 0UL;
+ ns_timer.function = ns_poll;
+ add_timer(&ns_timer);
+ }
+ return error;
+}
static void __exit nicstar_cleanup(void)
{
- XPRINTK("nicstar: nicstar_cleanup() called.\n");
+ XPRINTK("nicstar: nicstar_cleanup() called.\n");
- del_timer(&ns_timer);
+ del_timer(&ns_timer);
- pci_unregister_driver(&nicstar_driver);
+ pci_unregister_driver(&nicstar_driver);
- XPRINTK("nicstar: nicstar_cleanup() returned.\n");
+ XPRINTK("nicstar: nicstar_cleanup() returned.\n");
}
-
-
-static u32 ns_read_sram(ns_dev *card, u32 sram_address)
+static u32 ns_read_sram(ns_dev * card, u32 sram_address)
{
- unsigned long flags;
- u32 data;
- sram_address <<= 2;
- sram_address &= 0x0007FFFC; /* address must be dword aligned */
- sram_address |= 0x50000000; /* SRAM read command */
- spin_lock_irqsave(&card->res_lock, flags);
- while (CMD_BUSY(card));
- writel(sram_address, card->membase + CMD);
- while (CMD_BUSY(card));
- data = readl(card->membase + DR0);
- spin_unlock_irqrestore(&card->res_lock, flags);
- return data;
+ unsigned long flags;
+ u32 data;
+ sram_address <<= 2;
+ sram_address &= 0x0007FFFC; /* address must be dword aligned */
+ sram_address |= 0x50000000; /* SRAM read command */
+ spin_lock_irqsave(&card->res_lock, flags);
+ while (CMD_BUSY(card)) ;
+ writel(sram_address, card->membase + CMD);
+ while (CMD_BUSY(card)) ;
+ data = readl(card->membase + DR0);
+ spin_unlock_irqrestore(&card->res_lock, flags);
+ return data;
}
-
-
-static void ns_write_sram(ns_dev *card, u32 sram_address, u32 *value, int count)
+static void ns_write_sram(ns_dev * card, u32 sram_address, u32 * value,
+ int count)
{
- unsigned long flags;
- int i, c;
- count--; /* count range now is 0..3 instead of 1..4 */
- c = count;
- c <<= 2; /* to use increments of 4 */
- spin_lock_irqsave(&card->res_lock, flags);
- while (CMD_BUSY(card));
- for (i = 0; i <= c; i += 4)
- writel(*(value++), card->membase + i);
- /* Note: DR# registers are the first 4 dwords in nicstar's memspace,
- so card->membase + DR0 == card->membase */
- sram_address <<= 2;
- sram_address &= 0x0007FFFC;
- sram_address |= (0x40000000 | count);
- writel(sram_address, card->membase + CMD);
- spin_unlock_irqrestore(&card->res_lock, flags);
+ unsigned long flags;
+ int i, c;
+ count--; /* count range now is 0..3 instead of 1..4 */
+ c = count;
+ c <<= 2; /* to use increments of 4 */
+ spin_lock_irqsave(&card->res_lock, flags);
+ while (CMD_BUSY(card)) ;
+ for (i = 0; i <= c; i += 4)
+ writel(*(value++), card->membase + i);
+ /* Note: DR# registers are the first 4 dwords in nicstar's memspace,
+ so card->membase + DR0 == card->membase */
+ sram_address <<= 2;
+ sram_address &= 0x0007FFFC;
+ sram_address |= (0x40000000 | count);
+ writel(sram_address, card->membase + CMD);
+ spin_unlock_irqrestore(&card->res_lock, flags);
}
-
static int __devinit ns_init_card(int i, struct pci_dev *pcidev)
{
- int j;
- struct ns_dev *card = NULL;
- unsigned char pci_latency;
- unsigned error;
- u32 data;
- u32 u32d[4];
- u32 ns_cfg_rctsize;
- int bcount;
- unsigned long membase;
-
- error = 0;
-
- if (pci_enable_device(pcidev))
- {
- printk("nicstar%d: can't enable PCI device\n", i);
- error = 2;
- ns_init_card_error(card, error);
- return error;
- }
-
- if ((card = kmalloc(sizeof(ns_dev), GFP_KERNEL)) == NULL)
- {
- printk("nicstar%d: can't allocate memory for device structure.\n", i);
- error = 2;
- ns_init_card_error(card, error);
- return error;
- }
- cards[i] = card;
- spin_lock_init(&card->int_lock);
- spin_lock_init(&card->res_lock);
-
- pci_set_drvdata(pcidev, card);
-
- card->index = i;
- card->atmdev = NULL;
- card->pcidev = pcidev;
- membase = pci_resource_start(pcidev, 1);
- card->membase = ioremap(membase, NS_IOREMAP_SIZE);
- if (!card->membase)
- {
- printk("nicstar%d: can't ioremap() membase.\n",i);
- error = 3;
- ns_init_card_error(card, error);
- return error;
- }
- PRINTK("nicstar%d: membase at 0x%x.\n", i, card->membase);
-
- pci_set_master(pcidev);
-
- if (pci_read_config_byte(pcidev, PCI_LATENCY_TIMER, &pci_latency) != 0)
- {
- printk("nicstar%d: can't read PCI latency timer.\n", i);
- error = 6;
- ns_init_card_error(card, error);
- return error;
- }
+ int j;
+ struct ns_dev *card = NULL;
+ unsigned char pci_latency;
+ unsigned error;
+ u32 data;
+ u32 u32d[4];
+ u32 ns_cfg_rctsize;
+ int bcount;
+ unsigned long membase;
+
+ error = 0;
+
+ if (pci_enable_device(pcidev)) {
+ printk("nicstar%d: can't enable PCI device\n", i);
+ error = 2;
+ ns_init_card_error(card, error);
+ return error;
+ }
+ if ((pci_set_dma_mask(pcidev, DMA_BIT_MASK(32)) != 0) ||
+ (pci_set_consistent_dma_mask(pcidev, DMA_BIT_MASK(32)) != 0)) {
+ printk(KERN_WARNING
+ "nicstar%d: No suitable DMA available.\n", i);
+ error = 2;
+ ns_init_card_error(card, error);
+ return error;
+ }
+
+ if ((card = kmalloc(sizeof(ns_dev), GFP_KERNEL)) == NULL) {
+ printk
+ ("nicstar%d: can't allocate memory for device structure.\n",
+ i);
+ error = 2;
+ ns_init_card_error(card, error);
+ return error;
+ }
+ cards[i] = card;
+ spin_lock_init(&card->int_lock);
+ spin_lock_init(&card->res_lock);
+
+ pci_set_drvdata(pcidev, card);
+
+ card->index = i;
+ card->atmdev = NULL;
+ card->pcidev = pcidev;
+ membase = pci_resource_start(pcidev, 1);
+ card->membase = ioremap(membase, NS_IOREMAP_SIZE);
+ if (!card->membase) {
+ printk("nicstar%d: can't ioremap() membase.\n", i);
+ error = 3;
+ ns_init_card_error(card, error);
+ return error;
+ }
+ PRINTK("nicstar%d: membase at 0x%p.\n", i, card->membase);
+
+ pci_set_master(pcidev);
+
+ if (pci_read_config_byte(pcidev, PCI_LATENCY_TIMER, &pci_latency) != 0) {
+ printk("nicstar%d: can't read PCI latency timer.\n", i);
+ error = 6;
+ ns_init_card_error(card, error);
+ return error;
+ }
#ifdef NS_PCI_LATENCY
- if (pci_latency < NS_PCI_LATENCY)
- {
- PRINTK("nicstar%d: setting PCI latency timer to %d.\n", i, NS_PCI_LATENCY);
- for (j = 1; j < 4; j++)
- {
- if (pci_write_config_byte(pcidev, PCI_LATENCY_TIMER, NS_PCI_LATENCY) != 0)
- break;
- }
- if (j == 4)
- {
- printk("nicstar%d: can't set PCI latency timer to %d.\n", i, NS_PCI_LATENCY);
- error = 7;
- ns_init_card_error(card, error);
- return error;
- }
- }
+ if (pci_latency < NS_PCI_LATENCY) {
+ PRINTK("nicstar%d: setting PCI latency timer to %d.\n", i,
+ NS_PCI_LATENCY);
+ for (j = 1; j < 4; j++) {
+ if (pci_write_config_byte
+ (pcidev, PCI_LATENCY_TIMER, NS_PCI_LATENCY) != 0)
+ break;
+ }
+ if (j == 4) {
+ printk
+ ("nicstar%d: can't set PCI latency timer to %d.\n",
+ i, NS_PCI_LATENCY);
+ error = 7;
+ ns_init_card_error(card, error);
+ return error;
+ }
+ }
#endif /* NS_PCI_LATENCY */
-
- /* Clear timer overflow */
- data = readl(card->membase + STAT);
- if (data & NS_STAT_TMROF)
- writel(NS_STAT_TMROF, card->membase + STAT);
-
- /* Software reset */
- writel(NS_CFG_SWRST, card->membase + CFG);
- NS_DELAY;
- writel(0x00000000, card->membase + CFG);
-
- /* PHY reset */
- writel(0x00000008, card->membase + GP);
- NS_DELAY;
- writel(0x00000001, card->membase + GP);
- NS_DELAY;
- while (CMD_BUSY(card));
- writel(NS_CMD_WRITE_UTILITY | 0x00000100, card->membase + CMD); /* Sync UTOPIA with SAR clock */
- NS_DELAY;
-
- /* Detect PHY type */
- while (CMD_BUSY(card));
- writel(NS_CMD_READ_UTILITY | 0x00000200, card->membase + CMD);
- while (CMD_BUSY(card));
- data = readl(card->membase + DR0);
- switch(data) {
- case 0x00000009:
- printk("nicstar%d: PHY seems to be 25 Mbps.\n", i);
- card->max_pcr = ATM_25_PCR;
- while(CMD_BUSY(card));
- writel(0x00000008, card->membase + DR0);
- writel(NS_CMD_WRITE_UTILITY | 0x00000200, card->membase + CMD);
- /* Clear an eventual pending interrupt */
- writel(NS_STAT_SFBQF, card->membase + STAT);
+
+ /* Clear timer overflow */
+ data = readl(card->membase + STAT);
+ if (data & NS_STAT_TMROF)
+ writel(NS_STAT_TMROF, card->membase + STAT);
+
+ /* Software reset */
+ writel(NS_CFG_SWRST, card->membase + CFG);
+ NS_DELAY;
+ writel(0x00000000, card->membase + CFG);
+
+ /* PHY reset */
+ writel(0x00000008, card->membase + GP);
+ NS_DELAY;
+ writel(0x00000001, card->membase + GP);
+ NS_DELAY;
+ while (CMD_BUSY(card)) ;
+ writel(NS_CMD_WRITE_UTILITY | 0x00000100, card->membase + CMD); /* Sync UTOPIA with SAR clock */
+ NS_DELAY;
+
+ /* Detect PHY type */
+ while (CMD_BUSY(card)) ;
+ writel(NS_CMD_READ_UTILITY | 0x00000200, card->membase + CMD);
+ while (CMD_BUSY(card)) ;
+ data = readl(card->membase + DR0);
+ switch (data) {
+ case 0x00000009:
+ printk("nicstar%d: PHY seems to be 25 Mbps.\n", i);
+ card->max_pcr = ATM_25_PCR;
+ while (CMD_BUSY(card)) ;
+ writel(0x00000008, card->membase + DR0);
+ writel(NS_CMD_WRITE_UTILITY | 0x00000200, card->membase + CMD);
+ /* Clear an eventual pending interrupt */
+ writel(NS_STAT_SFBQF, card->membase + STAT);
#ifdef PHY_LOOPBACK
- while(CMD_BUSY(card));
- writel(0x00000022, card->membase + DR0);
- writel(NS_CMD_WRITE_UTILITY | 0x00000202, card->membase + CMD);
+ while (CMD_BUSY(card)) ;
+ writel(0x00000022, card->membase + DR0);
+ writel(NS_CMD_WRITE_UTILITY | 0x00000202, card->membase + CMD);
#endif /* PHY_LOOPBACK */
- break;
- case 0x00000030:
- case 0x00000031:
- printk("nicstar%d: PHY seems to be 155 Mbps.\n", i);
- card->max_pcr = ATM_OC3_PCR;
+ break;
+ case 0x00000030:
+ case 0x00000031:
+ printk("nicstar%d: PHY seems to be 155 Mbps.\n", i);
+ card->max_pcr = ATM_OC3_PCR;
#ifdef PHY_LOOPBACK
- while(CMD_BUSY(card));
- writel(0x00000002, card->membase + DR0);
- writel(NS_CMD_WRITE_UTILITY | 0x00000205, card->membase + CMD);
+ while (CMD_BUSY(card)) ;
+ writel(0x00000002, card->membase + DR0);
+ writel(NS_CMD_WRITE_UTILITY | 0x00000205, card->membase + CMD);
#endif /* PHY_LOOPBACK */
- break;
- default:
- printk("nicstar%d: unknown PHY type (0x%08X).\n", i, data);
- error = 8;
- ns_init_card_error(card, error);
- return error;
- }
- writel(0x00000000, card->membase + GP);
-
- /* Determine SRAM size */
- data = 0x76543210;
- ns_write_sram(card, 0x1C003, &data, 1);
- data = 0x89ABCDEF;
- ns_write_sram(card, 0x14003, &data, 1);
- if (ns_read_sram(card, 0x14003) == 0x89ABCDEF &&
- ns_read_sram(card, 0x1C003) == 0x76543210)
- card->sram_size = 128;
- else
- card->sram_size = 32;
- PRINTK("nicstar%d: %dK x 32bit SRAM size.\n", i, card->sram_size);
-
- card->rct_size = NS_MAX_RCTSIZE;
+ break;
+ default:
+ printk("nicstar%d: unknown PHY type (0x%08X).\n", i, data);
+ error = 8;
+ ns_init_card_error(card, error);
+ return error;
+ }
+ writel(0x00000000, card->membase + GP);
+
+ /* Determine SRAM size */
+ data = 0x76543210;
+ ns_write_sram(card, 0x1C003, &data, 1);
+ data = 0x89ABCDEF;
+ ns_write_sram(card, 0x14003, &data, 1);
+ if (ns_read_sram(card, 0x14003) == 0x89ABCDEF &&
+ ns_read_sram(card, 0x1C003) == 0x76543210)
+ card->sram_size = 128;
+ else
+ card->sram_size = 32;
+ PRINTK("nicstar%d: %dK x 32bit SRAM size.\n", i, card->sram_size);
+
+ card->rct_size = NS_MAX_RCTSIZE;
#if (NS_MAX_RCTSIZE == 4096)
- if (card->sram_size == 128)
- printk("nicstar%d: limiting maximum VCI. See NS_MAX_RCTSIZE in nicstar.h\n", i);
+ if (card->sram_size == 128)
+ printk
+ ("nicstar%d: limiting maximum VCI. See NS_MAX_RCTSIZE in nicstar.h\n",
+ i);
#elif (NS_MAX_RCTSIZE == 16384)
- if (card->sram_size == 32)
- {
- printk("nicstar%d: wasting memory. See NS_MAX_RCTSIZE in nicstar.h\n", i);
- card->rct_size = 4096;
- }
+ if (card->sram_size == 32) {
+ printk
+ ("nicstar%d: wasting memory. See NS_MAX_RCTSIZE in nicstar.h\n",
+ i);
+ card->rct_size = 4096;
+ }
#else
#error NS_MAX_RCTSIZE must be either 4096 or 16384 in nicstar.c
#endif
- card->vpibits = NS_VPIBITS;
- if (card->rct_size == 4096)
- card->vcibits = 12 - NS_VPIBITS;
- else /* card->rct_size == 16384 */
- card->vcibits = 14 - NS_VPIBITS;
-
- /* Initialize the nicstar eeprom/eprom stuff, for the MAC addr */
- if (mac[i] == NULL)
- nicstar_init_eprom(card->membase);
-
- /* Set the VPI/VCI MSb mask to zero so we can receive OAM cells */
- writel(0x00000000, card->membase + VPM);
-
- /* Initialize TSQ */
- card->tsq.org = kmalloc(NS_TSQSIZE + NS_TSQ_ALIGNMENT, GFP_KERNEL);
- if (card->tsq.org == NULL)
- {
- printk("nicstar%d: can't allocate TSQ.\n", i);
- error = 10;
- ns_init_card_error(card, error);
- return error;
- }
- card->tsq.base = (ns_tsi *) ALIGN_ADDRESS(card->tsq.org, NS_TSQ_ALIGNMENT);
- card->tsq.next = card->tsq.base;
- card->tsq.last = card->tsq.base + (NS_TSQ_NUM_ENTRIES - 1);
- for (j = 0; j < NS_TSQ_NUM_ENTRIES; j++)
- ns_tsi_init(card->tsq.base + j);
- writel(0x00000000, card->membase + TSQH);
- writel((u32) virt_to_bus(card->tsq.base), card->membase + TSQB);
- PRINTK("nicstar%d: TSQ base at 0x%x 0x%x 0x%x.\n", i, (u32) card->tsq.base,
- (u32) virt_to_bus(card->tsq.base), readl(card->membase + TSQB));
-
- /* Initialize RSQ */
- card->rsq.org = kmalloc(NS_RSQSIZE + NS_RSQ_ALIGNMENT, GFP_KERNEL);
- if (card->rsq.org == NULL)
- {
- printk("nicstar%d: can't allocate RSQ.\n", i);
- error = 11;
- ns_init_card_error(card, error);
- return error;
- }
- card->rsq.base = (ns_rsqe *) ALIGN_ADDRESS(card->rsq.org, NS_RSQ_ALIGNMENT);
- card->rsq.next = card->rsq.base;
- card->rsq.last = card->rsq.base + (NS_RSQ_NUM_ENTRIES - 1);
- for (j = 0; j < NS_RSQ_NUM_ENTRIES; j++)
- ns_rsqe_init(card->rsq.base + j);
- writel(0x00000000, card->membase + RSQH);
- writel((u32) virt_to_bus(card->rsq.base), card->membase + RSQB);
- PRINTK("nicstar%d: RSQ base at 0x%x.\n", i, (u32) card->rsq.base);
-
- /* Initialize SCQ0, the only VBR SCQ used */
- card->scq1 = NULL;
- card->scq2 = NULL;
- card->scq0 = get_scq(VBR_SCQSIZE, NS_VRSCD0);
- if (card->scq0 == NULL)
- {
- printk("nicstar%d: can't get SCQ0.\n", i);
- error = 12;
- ns_init_card_error(card, error);
- return error;
- }
- u32d[0] = (u32) virt_to_bus(card->scq0->base);
- u32d[1] = (u32) 0x00000000;
- u32d[2] = (u32) 0xffffffff;
- u32d[3] = (u32) 0x00000000;
- ns_write_sram(card, NS_VRSCD0, u32d, 4);
- ns_write_sram(card, NS_VRSCD1, u32d, 4); /* These last two won't be used */
- ns_write_sram(card, NS_VRSCD2, u32d, 4); /* but are initialized, just in case... */
- card->scq0->scd = NS_VRSCD0;
- PRINTK("nicstar%d: VBR-SCQ0 base at 0x%x.\n", i, (u32) card->scq0->base);
-
- /* Initialize TSTs */
- card->tst_addr = NS_TST0;
- card->tst_free_entries = NS_TST_NUM_ENTRIES;
- data = NS_TST_OPCODE_VARIABLE;
- for (j = 0; j < NS_TST_NUM_ENTRIES; j++)
- ns_write_sram(card, NS_TST0 + j, &data, 1);
- data = ns_tste_make(NS_TST_OPCODE_END, NS_TST0);
- ns_write_sram(card, NS_TST0 + NS_TST_NUM_ENTRIES, &data, 1);
- for (j = 0; j < NS_TST_NUM_ENTRIES; j++)
- ns_write_sram(card, NS_TST1 + j, &data, 1);
- data = ns_tste_make(NS_TST_OPCODE_END, NS_TST1);
- ns_write_sram(card, NS_TST1 + NS_TST_NUM_ENTRIES, &data, 1);
- for (j = 0; j < NS_TST_NUM_ENTRIES; j++)
- card->tste2vc[j] = NULL;
- writel(NS_TST0 << 2, card->membase + TSTB);
-
-
- /* Initialize RCT. AAL type is set on opening the VC. */
+ card->vpibits = NS_VPIBITS;
+ if (card->rct_size == 4096)
+ card->vcibits = 12 - NS_VPIBITS;
+ else /* card->rct_size == 16384 */
+ card->vcibits = 14 - NS_VPIBITS;
+
+ /* Initialize the nicstar eeprom/eprom stuff, for the MAC addr */
+ if (mac[i] == NULL)
+ nicstar_init_eprom(card->membase);
+
+ /* Set the VPI/VCI MSb mask to zero so we can receive OAM cells */
+ writel(0x00000000, card->membase + VPM);
+
+ /* Initialize TSQ */
+ card->tsq.org = pci_alloc_consistent(card->pcidev,
+ NS_TSQSIZE + NS_TSQ_ALIGNMENT,
+ &card->tsq.dma);
+ if (card->tsq.org == NULL) {
+ printk("nicstar%d: can't allocate TSQ.\n", i);
+ error = 10;
+ ns_init_card_error(card, error);
+ return error;
+ }
+ card->tsq.base = PTR_ALIGN(card->tsq.org, NS_TSQ_ALIGNMENT);
+ card->tsq.next = card->tsq.base;
+ card->tsq.last = card->tsq.base + (NS_TSQ_NUM_ENTRIES - 1);
+ for (j = 0; j < NS_TSQ_NUM_ENTRIES; j++)
+ ns_tsi_init(card->tsq.base + j);
+ writel(0x00000000, card->membase + TSQH);
+ writel(ALIGN(card->tsq.dma, NS_TSQ_ALIGNMENT), card->membase + TSQB);
+ PRINTK("nicstar%d: TSQ base at 0x%p.\n", i, card->tsq.base);
+
+ /* Initialize RSQ */
+ card->rsq.org = pci_alloc_consistent(card->pcidev,
+ NS_RSQSIZE + NS_RSQ_ALIGNMENT,
+ &card->rsq.dma);
+ if (card->rsq.org == NULL) {
+ printk("nicstar%d: can't allocate RSQ.\n", i);
+ error = 11;
+ ns_init_card_error(card, error);
+ return error;
+ }
+ card->rsq.base = PTR_ALIGN(card->rsq.org, NS_RSQ_ALIGNMENT);
+ card->rsq.next = card->rsq.base;
+ card->rsq.last = card->rsq.base + (NS_RSQ_NUM_ENTRIES - 1);
+ for (j = 0; j < NS_RSQ_NUM_ENTRIES; j++)
+ ns_rsqe_init(card->rsq.base + j);
+ writel(0x00000000, card->membase + RSQH);
+ writel(ALIGN(card->rsq.dma, NS_RSQ_ALIGNMENT), card->membase + RSQB);
+ PRINTK("nicstar%d: RSQ base at 0x%p.\n", i, card->rsq.base);
+
+ /* Initialize SCQ0, the only VBR SCQ used */
+ card->scq1 = NULL;
+ card->scq2 = NULL;
+ card->scq0 = get_scq(card, VBR_SCQSIZE, NS_VRSCD0);
+ if (card->scq0 == NULL) {
+ printk("nicstar%d: can't get SCQ0.\n", i);
+ error = 12;
+ ns_init_card_error(card, error);
+ return error;
+ }
+ u32d[0] = scq_virt_to_bus(card->scq0, card->scq0->base);
+ u32d[1] = (u32) 0x00000000;
+ u32d[2] = (u32) 0xffffffff;
+ u32d[3] = (u32) 0x00000000;
+ ns_write_sram(card, NS_VRSCD0, u32d, 4);
+ ns_write_sram(card, NS_VRSCD1, u32d, 4); /* These last two won't be used */
+ ns_write_sram(card, NS_VRSCD2, u32d, 4); /* but are initialized, just in case... */
+ card->scq0->scd = NS_VRSCD0;
+ PRINTK("nicstar%d: VBR-SCQ0 base at 0x%p.\n", i, card->scq0->base);
+
+ /* Initialize TSTs */
+ card->tst_addr = NS_TST0;
+ card->tst_free_entries = NS_TST_NUM_ENTRIES;
+ data = NS_TST_OPCODE_VARIABLE;
+ for (j = 0; j < NS_TST_NUM_ENTRIES; j++)
+ ns_write_sram(card, NS_TST0 + j, &data, 1);
+ data = ns_tste_make(NS_TST_OPCODE_END, NS_TST0);
+ ns_write_sram(card, NS_TST0 + NS_TST_NUM_ENTRIES, &data, 1);
+ for (j = 0; j < NS_TST_NUM_ENTRIES; j++)
+ ns_write_sram(card, NS_TST1 + j, &data, 1);
+ data = ns_tste_make(NS_TST_OPCODE_END, NS_TST1);
+ ns_write_sram(card, NS_TST1 + NS_TST_NUM_ENTRIES, &data, 1);
+ for (j = 0; j < NS_TST_NUM_ENTRIES; j++)
+ card->tste2vc[j] = NULL;
+ writel(NS_TST0 << 2, card->membase + TSTB);
+
+ /* Initialize RCT. AAL type is set on opening the VC. */
#ifdef RCQ_SUPPORT
- u32d[0] = NS_RCTE_RAWCELLINTEN;
+ u32d[0] = NS_RCTE_RAWCELLINTEN;
#else
- u32d[0] = 0x00000000;
+ u32d[0] = 0x00000000;
#endif /* RCQ_SUPPORT */
- u32d[1] = 0x00000000;
- u32d[2] = 0x00000000;
- u32d[3] = 0xFFFFFFFF;
- for (j = 0; j < card->rct_size; j++)
- ns_write_sram(card, j * 4, u32d, 4);
-
- memset(card->vcmap, 0, NS_MAX_RCTSIZE * sizeof(vc_map));
-
- for (j = 0; j < NS_FRSCD_NUM; j++)
- card->scd2vc[j] = NULL;
-
- /* Initialize buffer levels */
- card->sbnr.min = MIN_SB;
- card->sbnr.init = NUM_SB;
- card->sbnr.max = MAX_SB;
- card->lbnr.min = MIN_LB;
- card->lbnr.init = NUM_LB;
- card->lbnr.max = MAX_LB;
- card->iovnr.min = MIN_IOVB;
- card->iovnr.init = NUM_IOVB;
- card->iovnr.max = MAX_IOVB;
- card->hbnr.min = MIN_HB;
- card->hbnr.init = NUM_HB;
- card->hbnr.max = MAX_HB;
-
- card->sm_handle = 0x00000000;
- card->sm_addr = 0x00000000;
- card->lg_handle = 0x00000000;
- card->lg_addr = 0x00000000;
-
- card->efbie = 1; /* To prevent push_rxbufs from enabling the interrupt */
-
- /* Pre-allocate some huge buffers */
- skb_queue_head_init(&card->hbpool.queue);
- card->hbpool.count = 0;
- for (j = 0; j < NUM_HB; j++)
- {
- struct sk_buff *hb;
- hb = __dev_alloc_skb(NS_HBUFSIZE, GFP_KERNEL);
- if (hb == NULL)
- {
- printk("nicstar%d: can't allocate %dth of %d huge buffers.\n",
- i, j, NUM_HB);
- error = 13;
- ns_init_card_error(card, error);
- return error;
- }
- NS_SKB_CB(hb)->buf_type = BUF_NONE;
- skb_queue_tail(&card->hbpool.queue, hb);
- card->hbpool.count++;
- }
-
-
- /* Allocate large buffers */
- skb_queue_head_init(&card->lbpool.queue);
- card->lbpool.count = 0; /* Not used */
- for (j = 0; j < NUM_LB; j++)
- {
- struct sk_buff *lb;
- lb = __dev_alloc_skb(NS_LGSKBSIZE, GFP_KERNEL);
- if (lb == NULL)
- {
- printk("nicstar%d: can't allocate %dth of %d large buffers.\n",
- i, j, NUM_LB);
- error = 14;
- ns_init_card_error(card, error);
- return error;
- }
- NS_SKB_CB(lb)->buf_type = BUF_LG;
- skb_queue_tail(&card->lbpool.queue, lb);
- skb_reserve(lb, NS_SMBUFSIZE);
- push_rxbufs(card, lb);
- /* Due to the implementation of push_rxbufs() this is 1, not 0 */
- if (j == 1)
- {
- card->rcbuf = lb;
- card->rawch = (u32) virt_to_bus(lb->data);
- }
- }
- /* Test for strange behaviour which leads to crashes */
- if ((bcount = ns_stat_lfbqc_get(readl(card->membase + STAT))) < card->lbnr.min)
- {
- printk("nicstar%d: Strange... Just allocated %d large buffers and lfbqc = %d.\n",
- i, j, bcount);
- error = 14;
- ns_init_card_error(card, error);
- return error;
- }
-
-
- /* Allocate small buffers */
- skb_queue_head_init(&card->sbpool.queue);
- card->sbpool.count = 0; /* Not used */
- for (j = 0; j < NUM_SB; j++)
- {
- struct sk_buff *sb;
- sb = __dev_alloc_skb(NS_SMSKBSIZE, GFP_KERNEL);
- if (sb == NULL)
- {
- printk("nicstar%d: can't allocate %dth of %d small buffers.\n",
- i, j, NUM_SB);
- error = 15;
- ns_init_card_error(card, error);
- return error;
- }
- NS_SKB_CB(sb)->buf_type = BUF_SM;
- skb_queue_tail(&card->sbpool.queue, sb);
- skb_reserve(sb, NS_AAL0_HEADER);
- push_rxbufs(card, sb);
- }
- /* Test for strange behaviour which leads to crashes */
- if ((bcount = ns_stat_sfbqc_get(readl(card->membase + STAT))) < card->sbnr.min)
- {
- printk("nicstar%d: Strange... Just allocated %d small buffers and sfbqc = %d.\n",
- i, j, bcount);
- error = 15;
- ns_init_card_error(card, error);
- return error;
- }
-
-
- /* Allocate iovec buffers */
- skb_queue_head_init(&card->iovpool.queue);
- card->iovpool.count = 0;
- for (j = 0; j < NUM_IOVB; j++)
- {
- struct sk_buff *iovb;
- iovb = alloc_skb(NS_IOVBUFSIZE, GFP_KERNEL);
- if (iovb == NULL)
- {
- printk("nicstar%d: can't allocate %dth of %d iovec buffers.\n",
- i, j, NUM_IOVB);
- error = 16;
- ns_init_card_error(card, error);
- return error;
- }
- NS_SKB_CB(iovb)->buf_type = BUF_NONE;
- skb_queue_tail(&card->iovpool.queue, iovb);
- card->iovpool.count++;
- }
-
- /* Configure NICStAR */
- if (card->rct_size == 4096)
- ns_cfg_rctsize = NS_CFG_RCTSIZE_4096_ENTRIES;
- else /* (card->rct_size == 16384) */
- ns_cfg_rctsize = NS_CFG_RCTSIZE_16384_ENTRIES;
-
- card->efbie = 1;
-
- card->intcnt = 0;
- if (request_irq(pcidev->irq, &ns_irq_handler, IRQF_DISABLED | IRQF_SHARED, "nicstar", card) != 0)
- {
- printk("nicstar%d: can't allocate IRQ %d.\n", i, pcidev->irq);
- error = 9;
- ns_init_card_error(card, error);
- return error;
- }
-
- /* Register device */
- card->atmdev = atm_dev_register("nicstar", &atm_ops, -1, NULL);
- if (card->atmdev == NULL)
- {
- printk("nicstar%d: can't register device.\n", i);
- error = 17;
- ns_init_card_error(card, error);
- return error;
- }
-
- if (ns_parse_mac(mac[i], card->atmdev->esi)) {
- nicstar_read_eprom(card->membase, NICSTAR_EPROM_MAC_ADDR_OFFSET,
- card->atmdev->esi, 6);
- if (memcmp(card->atmdev->esi, "\x00\x00\x00\x00\x00\x00", 6) == 0) {
- nicstar_read_eprom(card->membase, NICSTAR_EPROM_MAC_ADDR_OFFSET_ALT,
- card->atmdev->esi, 6);
- }
- }
-
- printk("nicstar%d: MAC address %pM\n", i, card->atmdev->esi);
-
- card->atmdev->dev_data = card;
- card->atmdev->ci_range.vpi_bits = card->vpibits;
- card->atmdev->ci_range.vci_bits = card->vcibits;
- card->atmdev->link_rate = card->max_pcr;
- card->atmdev->phy = NULL;
+ u32d[1] = 0x00000000;
+ u32d[2] = 0x00000000;
+ u32d[3] = 0xFFFFFFFF;
+ for (j = 0; j < card->rct_size; j++)
+ ns_write_sram(card, j * 4, u32d, 4);
+
+ memset(card->vcmap, 0, NS_MAX_RCTSIZE * sizeof(vc_map));
+
+ for (j = 0; j < NS_FRSCD_NUM; j++)
+ card->scd2vc[j] = NULL;
+
+ /* Initialize buffer levels */
+ card->sbnr.min = MIN_SB;
+ card->sbnr.init = NUM_SB;
+ card->sbnr.max = MAX_SB;
+ card->lbnr.min = MIN_LB;
+ card->lbnr.init = NUM_LB;
+ card->lbnr.max = MAX_LB;
+ card->iovnr.min = MIN_IOVB;
+ card->iovnr.init = NUM_IOVB;
+ card->iovnr.max = MAX_IOVB;
+ card->hbnr.min = MIN_HB;
+ card->hbnr.init = NUM_HB;
+ card->hbnr.max = MAX_HB;
+
+ card->sm_handle = 0x00000000;
+ card->sm_addr = 0x00000000;
+ card->lg_handle = 0x00000000;
+ card->lg_addr = 0x00000000;
+
+ card->efbie = 1; /* To prevent push_rxbufs from enabling the interrupt */
+
+ idr_init(&card->idr);
+
+ /* Pre-allocate some huge buffers */
+ skb_queue_head_init(&card->hbpool.queue);
+ card->hbpool.count = 0;
+ for (j = 0; j < NUM_HB; j++) {
+ struct sk_buff *hb;
+ hb = __dev_alloc_skb(NS_HBUFSIZE, GFP_KERNEL);
+ if (hb == NULL) {
+ printk
+ ("nicstar%d: can't allocate %dth of %d huge buffers.\n",
+ i, j, NUM_HB);
+ error = 13;
+ ns_init_card_error(card, error);
+ return error;
+ }
+ NS_PRV_BUFTYPE(hb) = BUF_NONE;
+ skb_queue_tail(&card->hbpool.queue, hb);
+ card->hbpool.count++;
+ }
+
+ /* Allocate large buffers */
+ skb_queue_head_init(&card->lbpool.queue);
+ card->lbpool.count = 0; /* Not used */
+ for (j = 0; j < NUM_LB; j++) {
+ struct sk_buff *lb;
+ lb = __dev_alloc_skb(NS_LGSKBSIZE, GFP_KERNEL);
+ if (lb == NULL) {
+ printk
+ ("nicstar%d: can't allocate %dth of %d large buffers.\n",
+ i, j, NUM_LB);
+ error = 14;
+ ns_init_card_error(card, error);
+ return error;
+ }
+ NS_PRV_BUFTYPE(lb) = BUF_LG;
+ skb_queue_tail(&card->lbpool.queue, lb);
+ skb_reserve(lb, NS_SMBUFSIZE);
+ push_rxbufs(card, lb);
+ /* Due to the implementation of push_rxbufs() this is 1, not 0 */
+ if (j == 1) {
+ card->rcbuf = lb;
+ card->rawcell = (struct ns_rcqe *) lb->data;
+ card->rawch = NS_PRV_DMA(lb);
+ }
+ }
+ /* Test for strange behaviour which leads to crashes */
+ if ((bcount =
+ ns_stat_lfbqc_get(readl(card->membase + STAT))) < card->lbnr.min) {
+ printk
+ ("nicstar%d: Strange... Just allocated %d large buffers and lfbqc = %d.\n",
+ i, j, bcount);
+ error = 14;
+ ns_init_card_error(card, error);
+ return error;
+ }
+
+ /* Allocate small buffers */
+ skb_queue_head_init(&card->sbpool.queue);
+ card->sbpool.count = 0; /* Not used */
+ for (j = 0; j < NUM_SB; j++) {
+ struct sk_buff *sb;
+ sb = __dev_alloc_skb(NS_SMSKBSIZE, GFP_KERNEL);
+ if (sb == NULL) {
+ printk
+ ("nicstar%d: can't allocate %dth of %d small buffers.\n",
+ i, j, NUM_SB);
+ error = 15;
+ ns_init_card_error(card, error);
+ return error;
+ }
+ NS_PRV_BUFTYPE(sb) = BUF_SM;
+ skb_queue_tail(&card->sbpool.queue, sb);
+ skb_reserve(sb, NS_AAL0_HEADER);
+ push_rxbufs(card, sb);
+ }
+ /* Test for strange behaviour which leads to crashes */
+ if ((bcount =
+ ns_stat_sfbqc_get(readl(card->membase + STAT))) < card->sbnr.min) {
+ printk
+ ("nicstar%d: Strange... Just allocated %d small buffers and sfbqc = %d.\n",
+ i, j, bcount);
+ error = 15;
+ ns_init_card_error(card, error);
+ return error;
+ }
+
+ /* Allocate iovec buffers */
+ skb_queue_head_init(&card->iovpool.queue);
+ card->iovpool.count = 0;
+ for (j = 0; j < NUM_IOVB; j++) {
+ struct sk_buff *iovb;
+ iovb = alloc_skb(NS_IOVBUFSIZE, GFP_KERNEL);
+ if (iovb == NULL) {
+ printk
+ ("nicstar%d: can't allocate %dth of %d iovec buffers.\n",
+ i, j, NUM_IOVB);
+ error = 16;
+ ns_init_card_error(card, error);
+ return error;
+ }
+ NS_PRV_BUFTYPE(iovb) = BUF_NONE;
+ skb_queue_tail(&card->iovpool.queue, iovb);
+ card->iovpool.count++;
+ }
+
+ /* Configure NICStAR */
+ if (card->rct_size == 4096)
+ ns_cfg_rctsize = NS_CFG_RCTSIZE_4096_ENTRIES;
+ else /* (card->rct_size == 16384) */
+ ns_cfg_rctsize = NS_CFG_RCTSIZE_16384_ENTRIES;
+
+ card->efbie = 1;
+
+ card->intcnt = 0;
+ if (request_irq
+ (pcidev->irq, &ns_irq_handler, IRQF_SHARED, "nicstar", card) != 0) {
+ printk("nicstar%d: can't allocate IRQ %d.\n", i, pcidev->irq);
+ error = 9;
+ ns_init_card_error(card, error);
+ return error;
+ }
+
+ /* Register device */
+ card->atmdev = atm_dev_register("nicstar", &atm_ops, -1, NULL);
+ if (card->atmdev == NULL) {
+ printk("nicstar%d: can't register device.\n", i);
+ error = 17;
+ ns_init_card_error(card, error);
+ return error;
+ }
+
+ if (ns_parse_mac(mac[i], card->atmdev->esi)) {
+ nicstar_read_eprom(card->membase, NICSTAR_EPROM_MAC_ADDR_OFFSET,
+ card->atmdev->esi, 6);
+ if (memcmp(card->atmdev->esi, "\x00\x00\x00\x00\x00\x00", 6) ==
+ 0) {
+ nicstar_read_eprom(card->membase,
+ NICSTAR_EPROM_MAC_ADDR_OFFSET_ALT,
+ card->atmdev->esi, 6);
+ }
+ }
+
+ printk("nicstar%d: MAC address %pM\n", i, card->atmdev->esi);
+
+ card->atmdev->dev_data = card;
+ card->atmdev->ci_range.vpi_bits = card->vpibits;
+ card->atmdev->ci_range.vci_bits = card->vcibits;
+ card->atmdev->link_rate = card->max_pcr;
+ card->atmdev->phy = NULL;
#ifdef CONFIG_ATM_NICSTAR_USE_SUNI
- if (card->max_pcr == ATM_OC3_PCR)
- suni_init(card->atmdev);
+ if (card->max_pcr == ATM_OC3_PCR)
+ suni_init(card->atmdev);
#endif /* CONFIG_ATM_NICSTAR_USE_SUNI */
#ifdef CONFIG_ATM_NICSTAR_USE_IDT77105
- if (card->max_pcr == ATM_25_PCR)
- idt77105_init(card->atmdev);
+ if (card->max_pcr == ATM_25_PCR)
+ idt77105_init(card->atmdev);
#endif /* CONFIG_ATM_NICSTAR_USE_IDT77105 */
- if (card->atmdev->phy && card->atmdev->phy->start)
- card->atmdev->phy->start(card->atmdev);
-
- writel(NS_CFG_RXPATH |
- NS_CFG_SMBUFSIZE |
- NS_CFG_LGBUFSIZE |
- NS_CFG_EFBIE |
- NS_CFG_RSQSIZE |
- NS_CFG_VPIBITS |
- ns_cfg_rctsize |
- NS_CFG_RXINT_NODELAY |
- NS_CFG_RAWIE | /* Only enabled if RCQ_SUPPORT */
- NS_CFG_RSQAFIE |
- NS_CFG_TXEN |
- NS_CFG_TXIE |
- NS_CFG_TSQFIE_OPT | /* Only enabled if ENABLE_TSQFIE */
- NS_CFG_PHYIE,
- card->membase + CFG);
-
- num_cards++;
-
- return error;
-}
+ if (card->atmdev->phy && card->atmdev->phy->start)
+ card->atmdev->phy->start(card->atmdev);
+ writel(NS_CFG_RXPATH | NS_CFG_SMBUFSIZE | NS_CFG_LGBUFSIZE | NS_CFG_EFBIE | NS_CFG_RSQSIZE | NS_CFG_VPIBITS | ns_cfg_rctsize | NS_CFG_RXINT_NODELAY | NS_CFG_RAWIE | /* Only enabled if RCQ_SUPPORT */
+ NS_CFG_RSQAFIE | NS_CFG_TXEN | NS_CFG_TXIE | NS_CFG_TSQFIE_OPT | /* Only enabled if ENABLE_TSQFIE */
+ NS_CFG_PHYIE, card->membase + CFG);
+ num_cards++;
-static void __devinit ns_init_card_error(ns_dev *card, int error)
-{
- if (error >= 17)
- {
- writel(0x00000000, card->membase + CFG);
- }
- if (error >= 16)
- {
- struct sk_buff *iovb;
- while ((iovb = skb_dequeue(&card->iovpool.queue)) != NULL)
- dev_kfree_skb_any(iovb);
- }
- if (error >= 15)
- {
- struct sk_buff *sb;
- while ((sb = skb_dequeue(&card->sbpool.queue)) != NULL)
- dev_kfree_skb_any(sb);
- free_scq(card->scq0, NULL);
- }
- if (error >= 14)
- {
- struct sk_buff *lb;
- while ((lb = skb_dequeue(&card->lbpool.queue)) != NULL)
- dev_kfree_skb_any(lb);
- }
- if (error >= 13)
- {
- struct sk_buff *hb;
- while ((hb = skb_dequeue(&card->hbpool.queue)) != NULL)
- dev_kfree_skb_any(hb);
- }
- if (error >= 12)
- {
- kfree(card->rsq.org);
- }
- if (error >= 11)
- {
- kfree(card->tsq.org);
- }
- if (error >= 10)
- {
- free_irq(card->pcidev->irq, card);
- }
- if (error >= 4)
- {
- iounmap(card->membase);
- }
- if (error >= 3)
- {
- pci_disable_device(card->pcidev);
- kfree(card);
- }
+ return error;
}
-
-
-static scq_info *get_scq(int size, u32 scd)
+static void __devinit ns_init_card_error(ns_dev * card, int error)
{
- scq_info *scq;
- int i;
-
- if (size != VBR_SCQSIZE && size != CBR_SCQSIZE)
- return NULL;
-
- scq = kmalloc(sizeof(scq_info), GFP_KERNEL);
- if (scq == NULL)
- return NULL;
- scq->org = kmalloc(2 * size, GFP_KERNEL);
- if (scq->org == NULL)
- {
- kfree(scq);
- return NULL;
- }
- scq->skb = kmalloc(sizeof(struct sk_buff *) *
- (size / NS_SCQE_SIZE), GFP_KERNEL);
- if (scq->skb == NULL)
- {
- kfree(scq->org);
- kfree(scq);
- return NULL;
- }
- scq->num_entries = size / NS_SCQE_SIZE;
- scq->base = (ns_scqe *) ALIGN_ADDRESS(scq->org, size);
- scq->next = scq->base;
- scq->last = scq->base + (scq->num_entries - 1);
- scq->tail = scq->last;
- scq->scd = scd;
- scq->num_entries = size / NS_SCQE_SIZE;
- scq->tbd_count = 0;
- init_waitqueue_head(&scq->scqfull_waitq);
- scq->full = 0;
- spin_lock_init(&scq->lock);
-
- for (i = 0; i < scq->num_entries; i++)
- scq->skb[i] = NULL;
-
- return scq;
+ if (error >= 17) {
+ writel(0x00000000, card->membase + CFG);
+ }
+ if (error >= 16) {
+ struct sk_buff *iovb;
+ while ((iovb = skb_dequeue(&card->iovpool.queue)) != NULL)
+ dev_kfree_skb_any(iovb);
+ }
+ if (error >= 15) {
+ struct sk_buff *sb;
+ while ((sb = skb_dequeue(&card->sbpool.queue)) != NULL)
+ dev_kfree_skb_any(sb);
+ free_scq(card, card->scq0, NULL);
+ }
+ if (error >= 14) {
+ struct sk_buff *lb;
+ while ((lb = skb_dequeue(&card->lbpool.queue)) != NULL)
+ dev_kfree_skb_any(lb);
+ }
+ if (error >= 13) {
+ struct sk_buff *hb;
+ while ((hb = skb_dequeue(&card->hbpool.queue)) != NULL)
+ dev_kfree_skb_any(hb);
+ }
+ if (error >= 12) {
+ kfree(card->rsq.org);
+ }
+ if (error >= 11) {
+ kfree(card->tsq.org);
+ }
+ if (error >= 10) {
+ free_irq(card->pcidev->irq, card);
+ }
+ if (error >= 4) {
+ iounmap(card->membase);
+ }
+ if (error >= 3) {
+ pci_disable_device(card->pcidev);
+ kfree(card);
+ }
}
-
+static scq_info *get_scq(ns_dev *card, int size, u32 scd)
+{
+ scq_info *scq;
+ int i;
+
+ if (size != VBR_SCQSIZE && size != CBR_SCQSIZE)
+ return NULL;
+
+ scq = kmalloc(sizeof(scq_info), GFP_KERNEL);
+ if (!scq)
+ return NULL;
+ scq->org = pci_alloc_consistent(card->pcidev, 2 * size, &scq->dma);
+ if (!scq->org) {
+ kfree(scq);
+ return NULL;
+ }
+ scq->skb = kmalloc(sizeof(struct sk_buff *) *
+ (size / NS_SCQE_SIZE), GFP_KERNEL);
+ if (!scq->skb) {
+ kfree(scq->org);
+ kfree(scq);
+ return NULL;
+ }
+ scq->num_entries = size / NS_SCQE_SIZE;
+ scq->base = PTR_ALIGN(scq->org, size);
+ scq->next = scq->base;
+ scq->last = scq->base + (scq->num_entries - 1);
+ scq->tail = scq->last;
+ scq->scd = scd;
+ scq->num_entries = size / NS_SCQE_SIZE;
+ scq->tbd_count = 0;
+ init_waitqueue_head(&scq->scqfull_waitq);
+ scq->full = 0;
+ spin_lock_init(&scq->lock);
+
+ for (i = 0; i < scq->num_entries; i++)
+ scq->skb[i] = NULL;
+
+ return scq;
+}
/* For variable rate SCQ vcc must be NULL */
-static void free_scq(scq_info *scq, struct atm_vcc *vcc)
+static void free_scq(ns_dev *card, scq_info *scq, struct atm_vcc *vcc)
{
- int i;
-
- if (scq->num_entries == VBR_SCQ_NUM_ENTRIES)
- for (i = 0; i < scq->num_entries; i++)
- {
- if (scq->skb[i] != NULL)
- {
- vcc = ATM_SKB(scq->skb[i])->vcc;
- if (vcc->pop != NULL)
- vcc->pop(vcc, scq->skb[i]);
- else
- dev_kfree_skb_any(scq->skb[i]);
- }
- }
- else /* vcc must be != NULL */
- {
- if (vcc == NULL)
- {
- printk("nicstar: free_scq() called with vcc == NULL for fixed rate scq.");
- for (i = 0; i < scq->num_entries; i++)
- dev_kfree_skb_any(scq->skb[i]);
- }
- else
- for (i = 0; i < scq->num_entries; i++)
- {
- if (scq->skb[i] != NULL)
- {
- if (vcc->pop != NULL)
- vcc->pop(vcc, scq->skb[i]);
- else
- dev_kfree_skb_any(scq->skb[i]);
- }
- }
- }
- kfree(scq->skb);
- kfree(scq->org);
- kfree(scq);
+ int i;
+
+ if (scq->num_entries == VBR_SCQ_NUM_ENTRIES)
+ for (i = 0; i < scq->num_entries; i++) {
+ if (scq->skb[i] != NULL) {
+ vcc = ATM_SKB(scq->skb[i])->vcc;
+ if (vcc->pop != NULL)
+ vcc->pop(vcc, scq->skb[i]);
+ else
+ dev_kfree_skb_any(scq->skb[i]);
+ }
+ } else { /* vcc must be != NULL */
+
+ if (vcc == NULL) {
+ printk
+ ("nicstar: free_scq() called with vcc == NULL for fixed rate scq.");
+ for (i = 0; i < scq->num_entries; i++)
+ dev_kfree_skb_any(scq->skb[i]);
+ } else
+ for (i = 0; i < scq->num_entries; i++) {
+ if (scq->skb[i] != NULL) {
+ if (vcc->pop != NULL)
+ vcc->pop(vcc, scq->skb[i]);
+ else
+ dev_kfree_skb_any(scq->skb[i]);
+ }
+ }
+ }
+ kfree(scq->skb);
+ pci_free_consistent(card->pcidev,
+ 2 * (scq->num_entries == VBR_SCQ_NUM_ENTRIES ?
+ VBR_SCQSIZE : CBR_SCQSIZE),
+ scq->org, scq->dma);
+ kfree(scq);
}
-
-
/* The handles passed must be pointers to the sk_buff containing the small
or large buffer(s) cast to u32. */
-static void push_rxbufs(ns_dev *card, struct sk_buff *skb)
+static void push_rxbufs(ns_dev * card, struct sk_buff *skb)
{
- struct ns_skb_cb *cb = NS_SKB_CB(skb);
- u32 handle1, addr1;
- u32 handle2, addr2;
- u32 stat;
- unsigned long flags;
-
- /* *BARF* */
- handle2 = addr2 = 0;
- handle1 = (u32)skb;
- addr1 = (u32)virt_to_bus(skb->data);
+ struct sk_buff *handle1, *handle2;
+ u32 id1 = 0, id2 = 0;
+ u32 addr1, addr2;
+ u32 stat;
+ unsigned long flags;
+ int err;
+
+ /* *BARF* */
+ handle2 = NULL;
+ addr2 = 0;
+ handle1 = skb;
+ addr1 = pci_map_single(card->pcidev,
+ skb->data,
+ (NS_PRV_BUFTYPE(skb) == BUF_SM
+ ? NS_SMSKBSIZE : NS_LGSKBSIZE),
+ PCI_DMA_TODEVICE);
+ NS_PRV_DMA(skb) = addr1; /* save so we can unmap later */
#ifdef GENERAL_DEBUG
- if (!addr1)
- printk("nicstar%d: push_rxbufs called with addr1 = 0.\n", card->index);
+ if (!addr1)
+ printk("nicstar%d: push_rxbufs called with addr1 = 0.\n",
+ card->index);
#endif /* GENERAL_DEBUG */
- stat = readl(card->membase + STAT);
- card->sbfqc = ns_stat_sfbqc_get(stat);
- card->lbfqc = ns_stat_lfbqc_get(stat);
- if (cb->buf_type == BUF_SM)
- {
- if (!addr2)
- {
- if (card->sm_addr)
- {
- addr2 = card->sm_addr;
- handle2 = card->sm_handle;
- card->sm_addr = 0x00000000;
- card->sm_handle = 0x00000000;
- }
- else /* (!sm_addr) */
- {
- card->sm_addr = addr1;
- card->sm_handle = handle1;
- }
- }
- }
- else /* buf_type == BUF_LG */
- {
- if (!addr2)
- {
- if (card->lg_addr)
- {
- addr2 = card->lg_addr;
- handle2 = card->lg_handle;
- card->lg_addr = 0x00000000;
- card->lg_handle = 0x00000000;
- }
- else /* (!lg_addr) */
- {
- card->lg_addr = addr1;
- card->lg_handle = handle1;
- }
- }
- }
-
- if (addr2)
- {
- if (cb->buf_type == BUF_SM)
- {
- if (card->sbfqc >= card->sbnr.max)
- {
- skb_unlink((struct sk_buff *) handle1, &card->sbpool.queue);
- dev_kfree_skb_any((struct sk_buff *) handle1);
- skb_unlink((struct sk_buff *) handle2, &card->sbpool.queue);
- dev_kfree_skb_any((struct sk_buff *) handle2);
- return;
- }
- else
- card->sbfqc += 2;
- }
- else /* (buf_type == BUF_LG) */
- {
- if (card->lbfqc >= card->lbnr.max)
- {
- skb_unlink((struct sk_buff *) handle1, &card->lbpool.queue);
- dev_kfree_skb_any((struct sk_buff *) handle1);
- skb_unlink((struct sk_buff *) handle2, &card->lbpool.queue);
- dev_kfree_skb_any((struct sk_buff *) handle2);
- return;
- }
- else
- card->lbfqc += 2;
- }
-
- spin_lock_irqsave(&card->res_lock, flags);
-
- while (CMD_BUSY(card));
- writel(addr2, card->membase + DR3);
- writel(handle2, card->membase + DR2);
- writel(addr1, card->membase + DR1);
- writel(handle1, card->membase + DR0);
- writel(NS_CMD_WRITE_FREEBUFQ | cb->buf_type, card->membase + CMD);
-
- spin_unlock_irqrestore(&card->res_lock, flags);
-
- XPRINTK("nicstar%d: Pushing %s buffers at 0x%x and 0x%x.\n", card->index,
- (cb->buf_type == BUF_SM ? "small" : "large"), addr1, addr2);
- }
-
- if (!card->efbie && card->sbfqc >= card->sbnr.min &&
- card->lbfqc >= card->lbnr.min)
- {
- card->efbie = 1;
- writel((readl(card->membase + CFG) | NS_CFG_EFBIE), card->membase + CFG);
- }
-
- return;
+ stat = readl(card->membase + STAT);
+ card->sbfqc = ns_stat_sfbqc_get(stat);
+ card->lbfqc = ns_stat_lfbqc_get(stat);
+ if (NS_PRV_BUFTYPE(skb) == BUF_SM) {
+ if (!addr2) {
+ if (card->sm_addr) {
+ addr2 = card->sm_addr;
+ handle2 = card->sm_handle;
+ card->sm_addr = 0x00000000;
+ card->sm_handle = 0x00000000;
+ } else { /* (!sm_addr) */
+
+ card->sm_addr = addr1;
+ card->sm_handle = handle1;
+ }
+ }
+ } else { /* buf_type == BUF_LG */
+
+ if (!addr2) {
+ if (card->lg_addr) {
+ addr2 = card->lg_addr;
+ handle2 = card->lg_handle;
+ card->lg_addr = 0x00000000;
+ card->lg_handle = 0x00000000;
+ } else { /* (!lg_addr) */
+
+ card->lg_addr = addr1;
+ card->lg_handle = handle1;
+ }
+ }
+ }
+
+ if (addr2) {
+ if (NS_PRV_BUFTYPE(skb) == BUF_SM) {
+ if (card->sbfqc >= card->sbnr.max) {
+ skb_unlink(handle1, &card->sbpool.queue);
+ dev_kfree_skb_any(handle1);
+ skb_unlink(handle2, &card->sbpool.queue);
+ dev_kfree_skb_any(handle2);
+ return;
+ } else
+ card->sbfqc += 2;
+ } else { /* (buf_type == BUF_LG) */
+
+ if (card->lbfqc >= card->lbnr.max) {
+ skb_unlink(handle1, &card->lbpool.queue);
+ dev_kfree_skb_any(handle1);
+ skb_unlink(handle2, &card->lbpool.queue);
+ dev_kfree_skb_any(handle2);
+ return;
+ } else
+ card->lbfqc += 2;
+ }
+
+ do {
+ if (!idr_pre_get(&card->idr, GFP_ATOMIC)) {
+ printk(KERN_ERR
+ "nicstar%d: no free memory for idr\n",
+ card->index);
+ goto out;
+ }
+
+ if (!id1)
+ err = idr_get_new_above(&card->idr, handle1, 0, &id1);
+
+ if (!id2 && err == 0)
+ err = idr_get_new_above(&card->idr, handle2, 0, &id2);
+
+ } while (err == -EAGAIN);
+
+ if (err)
+ goto out;
+
+ spin_lock_irqsave(&card->res_lock, flags);
+ while (CMD_BUSY(card)) ;
+ writel(addr2, card->membase + DR3);
+ writel(id2, card->membase + DR2);
+ writel(addr1, card->membase + DR1);
+ writel(id1, card->membase + DR0);
+ writel(NS_CMD_WRITE_FREEBUFQ | NS_PRV_BUFTYPE(skb),
+ card->membase + CMD);
+ spin_unlock_irqrestore(&card->res_lock, flags);
+
+ XPRINTK("nicstar%d: Pushing %s buffers at 0x%x and 0x%x.\n",
+ card->index,
+ (NS_PRV_BUFTYPE(skb) == BUF_SM ? "small" : "large"),
+ addr1, addr2);
+ }
+
+ if (!card->efbie && card->sbfqc >= card->sbnr.min &&
+ card->lbfqc >= card->lbnr.min) {
+ card->efbie = 1;
+ writel((readl(card->membase + CFG) | NS_CFG_EFBIE),
+ card->membase + CFG);
+ }
+
+out:
+ return;
}
-
-
static irqreturn_t ns_irq_handler(int irq, void *dev_id)
{
- u32 stat_r;
- ns_dev *card;
- struct atm_dev *dev;
- unsigned long flags;
-
- card = (ns_dev *) dev_id;
- dev = card->atmdev;
- card->intcnt++;
-
- PRINTK("nicstar%d: NICStAR generated an interrupt\n", card->index);
-
- spin_lock_irqsave(&card->int_lock, flags);
-
- stat_r = readl(card->membase + STAT);
-
- /* Transmit Status Indicator has been written to T. S. Queue */
- if (stat_r & NS_STAT_TSIF)
- {
- TXPRINTK("nicstar%d: TSI interrupt\n", card->index);
- process_tsq(card);
- writel(NS_STAT_TSIF, card->membase + STAT);
- }
-
- /* Incomplete CS-PDU has been transmitted */
- if (stat_r & NS_STAT_TXICP)
- {
- writel(NS_STAT_TXICP, card->membase + STAT);
- TXPRINTK("nicstar%d: Incomplete CS-PDU transmitted.\n",
- card->index);
- }
-
- /* Transmit Status Queue 7/8 full */
- if (stat_r & NS_STAT_TSQF)
- {
- writel(NS_STAT_TSQF, card->membase + STAT);
- PRINTK("nicstar%d: TSQ full.\n", card->index);
- process_tsq(card);
- }
-
- /* Timer overflow */
- if (stat_r & NS_STAT_TMROF)
- {
- writel(NS_STAT_TMROF, card->membase + STAT);
- PRINTK("nicstar%d: Timer overflow.\n", card->index);
- }
-
- /* PHY device interrupt signal active */
- if (stat_r & NS_STAT_PHYI)
- {
- writel(NS_STAT_PHYI, card->membase + STAT);
- PRINTK("nicstar%d: PHY interrupt.\n", card->index);
- if (dev->phy && dev->phy->interrupt) {
- dev->phy->interrupt(dev);
- }
- }
-
- /* Small Buffer Queue is full */
- if (stat_r & NS_STAT_SFBQF)
- {
- writel(NS_STAT_SFBQF, card->membase + STAT);
- printk("nicstar%d: Small free buffer queue is full.\n", card->index);
- }
-
- /* Large Buffer Queue is full */
- if (stat_r & NS_STAT_LFBQF)
- {
- writel(NS_STAT_LFBQF, card->membase + STAT);
- printk("nicstar%d: Large free buffer queue is full.\n", card->index);
- }
-
- /* Receive Status Queue is full */
- if (stat_r & NS_STAT_RSQF)
- {
- writel(NS_STAT_RSQF, card->membase + STAT);
- printk("nicstar%d: RSQ full.\n", card->index);
- process_rsq(card);
- }
-
- /* Complete CS-PDU received */
- if (stat_r & NS_STAT_EOPDU)
- {
- RXPRINTK("nicstar%d: End of CS-PDU received.\n", card->index);
- process_rsq(card);
- writel(NS_STAT_EOPDU, card->membase + STAT);
- }
-
- /* Raw cell received */
- if (stat_r & NS_STAT_RAWCF)
- {
- writel(NS_STAT_RAWCF, card->membase + STAT);
+ u32 stat_r;
+ ns_dev *card;
+ struct atm_dev *dev;
+ unsigned long flags;
+
+ card = (ns_dev *) dev_id;
+ dev = card->atmdev;
+ card->intcnt++;
+
+ PRINTK("nicstar%d: NICStAR generated an interrupt\n", card->index);
+
+ spin_lock_irqsave(&card->int_lock, flags);
+
+ stat_r = readl(card->membase + STAT);
+
+ /* Transmit Status Indicator has been written to T. S. Queue */
+ if (stat_r & NS_STAT_TSIF) {
+ TXPRINTK("nicstar%d: TSI interrupt\n", card->index);
+ process_tsq(card);
+ writel(NS_STAT_TSIF, card->membase + STAT);
+ }
+
+ /* Incomplete CS-PDU has been transmitted */
+ if (stat_r & NS_STAT_TXICP) {
+ writel(NS_STAT_TXICP, card->membase + STAT);
+ TXPRINTK("nicstar%d: Incomplete CS-PDU transmitted.\n",
+ card->index);
+ }
+
+ /* Transmit Status Queue 7/8 full */
+ if (stat_r & NS_STAT_TSQF) {
+ writel(NS_STAT_TSQF, card->membase + STAT);
+ PRINTK("nicstar%d: TSQ full.\n", card->index);
+ process_tsq(card);
+ }
+
+ /* Timer overflow */
+ if (stat_r & NS_STAT_TMROF) {
+ writel(NS_STAT_TMROF, card->membase + STAT);
+ PRINTK("nicstar%d: Timer overflow.\n", card->index);
+ }
+
+ /* PHY device interrupt signal active */
+ if (stat_r & NS_STAT_PHYI) {
+ writel(NS_STAT_PHYI, card->membase + STAT);
+ PRINTK("nicstar%d: PHY interrupt.\n", card->index);
+ if (dev->phy && dev->phy->interrupt) {
+ dev->phy->interrupt(dev);
+ }
+ }
+
+ /* Small Buffer Queue is full */
+ if (stat_r & NS_STAT_SFBQF) {
+ writel(NS_STAT_SFBQF, card->membase + STAT);
+ printk("nicstar%d: Small free buffer queue is full.\n",
+ card->index);
+ }
+
+ /* Large Buffer Queue is full */
+ if (stat_r & NS_STAT_LFBQF) {
+ writel(NS_STAT_LFBQF, card->membase + STAT);
+ printk("nicstar%d: Large free buffer queue is full.\n",
+ card->index);
+ }
+
+ /* Receive Status Queue is full */
+ if (stat_r & NS_STAT_RSQF) {
+ writel(NS_STAT_RSQF, card->membase + STAT);
+ printk("nicstar%d: RSQ full.\n", card->index);
+ process_rsq(card);
+ }
+
+ /* Complete CS-PDU received */
+ if (stat_r & NS_STAT_EOPDU) {
+ RXPRINTK("nicstar%d: End of CS-PDU received.\n", card->index);
+ process_rsq(card);
+ writel(NS_STAT_EOPDU, card->membase + STAT);
+ }
+
+ /* Raw cell received */
+ if (stat_r & NS_STAT_RAWCF) {
+ writel(NS_STAT_RAWCF, card->membase + STAT);
#ifndef RCQ_SUPPORT
- printk("nicstar%d: Raw cell received and no support yet...\n",
- card->index);
+ printk("nicstar%d: Raw cell received and no support yet...\n",
+ card->index);
#endif /* RCQ_SUPPORT */
- /* NOTE: the following procedure may keep a raw cell pending until the
- next interrupt. As this preliminary support is only meant to
- avoid buffer leakage, this is not an issue. */
- while (readl(card->membase + RAWCT) != card->rawch)
- {
- ns_rcqe *rawcell;
-
- rawcell = (ns_rcqe *) bus_to_virt(card->rawch);
- if (ns_rcqe_islast(rawcell))
- {
- struct sk_buff *oldbuf;
-
- oldbuf = card->rcbuf;
- card->rcbuf = (struct sk_buff *) ns_rcqe_nextbufhandle(rawcell);
- card->rawch = (u32) virt_to_bus(card->rcbuf->data);
- recycle_rx_buf(card, oldbuf);
- }
- else
- card->rawch += NS_RCQE_SIZE;
- }
- }
-
- /* Small buffer queue is empty */
- if (stat_r & NS_STAT_SFBQE)
- {
- int i;
- struct sk_buff *sb;
-
- writel(NS_STAT_SFBQE, card->membase + STAT);
- printk("nicstar%d: Small free buffer queue empty.\n",
- card->index);
- for (i = 0; i < card->sbnr.min; i++)
- {
- sb = dev_alloc_skb(NS_SMSKBSIZE);
- if (sb == NULL)
- {
- writel(readl(card->membase + CFG) & ~NS_CFG_EFBIE, card->membase + CFG);
- card->efbie = 0;
- break;
- }
- NS_SKB_CB(sb)->buf_type = BUF_SM;
- skb_queue_tail(&card->sbpool.queue, sb);
- skb_reserve(sb, NS_AAL0_HEADER);
- push_rxbufs(card, sb);
- }
- card->sbfqc = i;
- process_rsq(card);
- }
-
- /* Large buffer queue empty */
- if (stat_r & NS_STAT_LFBQE)
- {
- int i;
- struct sk_buff *lb;
-
- writel(NS_STAT_LFBQE, card->membase + STAT);
- printk("nicstar%d: Large free buffer queue empty.\n",
- card->index);
- for (i = 0; i < card->lbnr.min; i++)
- {
- lb = dev_alloc_skb(NS_LGSKBSIZE);
- if (lb == NULL)
- {
- writel(readl(card->membase + CFG) & ~NS_CFG_EFBIE, card->membase + CFG);
- card->efbie = 0;
- break;
- }
- NS_SKB_CB(lb)->buf_type = BUF_LG;
- skb_queue_tail(&card->lbpool.queue, lb);
- skb_reserve(lb, NS_SMBUFSIZE);
- push_rxbufs(card, lb);
- }
- card->lbfqc = i;
- process_rsq(card);
- }
-
- /* Receive Status Queue is 7/8 full */
- if (stat_r & NS_STAT_RSQAF)
- {
- writel(NS_STAT_RSQAF, card->membase + STAT);
- RXPRINTK("nicstar%d: RSQ almost full.\n", card->index);
- process_rsq(card);
- }
-
- spin_unlock_irqrestore(&card->int_lock, flags);
- PRINTK("nicstar%d: end of interrupt service\n", card->index);
- return IRQ_HANDLED;
+ /* NOTE: the following procedure may keep a raw cell pending until the
+ next interrupt. As this preliminary support is only meant to
+ avoid buffer leakage, this is not an issue. */
+ while (readl(card->membase + RAWCT) != card->rawch) {
+
+ if (ns_rcqe_islast(card->rawcell)) {
+ struct sk_buff *oldbuf;
+
+ oldbuf = card->rcbuf;
+ card->rcbuf = idr_find(&card->idr,
+ ns_rcqe_nextbufhandle(card->rawcell));
+ card->rawch = NS_PRV_DMA(card->rcbuf);
+ card->rawcell = (struct ns_rcqe *)
+ card->rcbuf->data;
+ recycle_rx_buf(card, oldbuf);
+ } else {
+ card->rawch += NS_RCQE_SIZE;
+ card->rawcell++;
+ }
+ }
+ }
+
+ /* Small buffer queue is empty */
+ if (stat_r & NS_STAT_SFBQE) {
+ int i;
+ struct sk_buff *sb;
+
+ writel(NS_STAT_SFBQE, card->membase + STAT);
+ printk("nicstar%d: Small free buffer queue empty.\n",
+ card->index);
+ for (i = 0; i < card->sbnr.min; i++) {
+ sb = dev_alloc_skb(NS_SMSKBSIZE);
+ if (sb == NULL) {
+ writel(readl(card->membase + CFG) &
+ ~NS_CFG_EFBIE, card->membase + CFG);
+ card->efbie = 0;
+ break;
+ }
+ NS_PRV_BUFTYPE(sb) = BUF_SM;
+ skb_queue_tail(&card->sbpool.queue, sb);
+ skb_reserve(sb, NS_AAL0_HEADER);
+ push_rxbufs(card, sb);
+ }
+ card->sbfqc = i;
+ process_rsq(card);
+ }
+
+ /* Large buffer queue empty */
+ if (stat_r & NS_STAT_LFBQE) {
+ int i;
+ struct sk_buff *lb;
+
+ writel(NS_STAT_LFBQE, card->membase + STAT);
+ printk("nicstar%d: Large free buffer queue empty.\n",
+ card->index);
+ for (i = 0; i < card->lbnr.min; i++) {
+ lb = dev_alloc_skb(NS_LGSKBSIZE);
+ if (lb == NULL) {
+ writel(readl(card->membase + CFG) &
+ ~NS_CFG_EFBIE, card->membase + CFG);
+ card->efbie = 0;
+ break;
+ }
+ NS_PRV_BUFTYPE(lb) = BUF_LG;
+ skb_queue_tail(&card->lbpool.queue, lb);
+ skb_reserve(lb, NS_SMBUFSIZE);
+ push_rxbufs(card, lb);
+ }
+ card->lbfqc = i;
+ process_rsq(card);
+ }
+
+ /* Receive Status Queue is 7/8 full */
+ if (stat_r & NS_STAT_RSQAF) {
+ writel(NS_STAT_RSQAF, card->membase + STAT);
+ RXPRINTK("nicstar%d: RSQ almost full.\n", card->index);
+ process_rsq(card);
+ }
+
+ spin_unlock_irqrestore(&card->int_lock, flags);
+ PRINTK("nicstar%d: end of interrupt service\n", card->index);
+ return IRQ_HANDLED;
}
-
-
static int ns_open(struct atm_vcc *vcc)
{
- ns_dev *card;
- vc_map *vc;
- unsigned long tmpl, modl;
- int tcr, tcra; /* target cell rate, and absolute value */
- int n = 0; /* Number of entries in the TST. Initialized to remove
- the compiler warning. */
- u32 u32d[4];
- int frscdi = 0; /* Index of the SCD. Initialized to remove the compiler
- warning. How I wish compilers were clever enough to
- tell which variables can truly be used
- uninitialized... */
- int inuse; /* tx or rx vc already in use by another vcc */
- short vpi = vcc->vpi;
- int vci = vcc->vci;
-
- card = (ns_dev *) vcc->dev->dev_data;
- PRINTK("nicstar%d: opening vpi.vci %d.%d \n", card->index, (int) vpi, vci);
- if (vcc->qos.aal != ATM_AAL5 && vcc->qos.aal != ATM_AAL0)
- {
- PRINTK("nicstar%d: unsupported AAL.\n", card->index);
- return -EINVAL;
- }
-
- vc = &(card->vcmap[vpi << card->vcibits | vci]);
- vcc->dev_data = vc;
-
- inuse = 0;
- if (vcc->qos.txtp.traffic_class != ATM_NONE && vc->tx)
- inuse = 1;
- if (vcc->qos.rxtp.traffic_class != ATM_NONE && vc->rx)
- inuse += 2;
- if (inuse)
- {
- printk("nicstar%d: %s vci already in use.\n", card->index,
- inuse == 1 ? "tx" : inuse == 2 ? "rx" : "tx and rx");
- return -EINVAL;
- }
-
- set_bit(ATM_VF_ADDR,&vcc->flags);
-
- /* NOTE: You are not allowed to modify an open connection's QOS. To change
- that, remove the ATM_VF_PARTIAL flag checking. There may be other changes
- needed to do that. */
- if (!test_bit(ATM_VF_PARTIAL,&vcc->flags))
- {
- scq_info *scq;
-
- set_bit(ATM_VF_PARTIAL,&vcc->flags);
- if (vcc->qos.txtp.traffic_class == ATM_CBR)
- {
- /* Check requested cell rate and availability of SCD */
- if (vcc->qos.txtp.max_pcr == 0 && vcc->qos.txtp.pcr == 0 &&
- vcc->qos.txtp.min_pcr == 0)
- {
- PRINTK("nicstar%d: trying to open a CBR vc with cell rate = 0 \n",
- card->index);
- clear_bit(ATM_VF_PARTIAL,&vcc->flags);
- clear_bit(ATM_VF_ADDR,&vcc->flags);
- return -EINVAL;
- }
-
- tcr = atm_pcr_goal(&(vcc->qos.txtp));
- tcra = tcr >= 0 ? tcr : -tcr;
-
- PRINTK("nicstar%d: target cell rate = %d.\n", card->index,
- vcc->qos.txtp.max_pcr);
-
- tmpl = (unsigned long)tcra * (unsigned long)NS_TST_NUM_ENTRIES;
- modl = tmpl % card->max_pcr;
-
- n = (int)(tmpl / card->max_pcr);
- if (tcr > 0)
- {
- if (modl > 0) n++;
- }
- else if (tcr == 0)
- {
- if ((n = (card->tst_free_entries - NS_TST_RESERVED)) <= 0)
- {
- PRINTK("nicstar%d: no CBR bandwidth free.\n", card->index);
- clear_bit(ATM_VF_PARTIAL,&vcc->flags);
- clear_bit(ATM_VF_ADDR,&vcc->flags);
- return -EINVAL;
- }
- }
-
- if (n == 0)
- {
- printk("nicstar%d: selected bandwidth < granularity.\n", card->index);
- clear_bit(ATM_VF_PARTIAL,&vcc->flags);
- clear_bit(ATM_VF_ADDR,&vcc->flags);
- return -EINVAL;
- }
-
- if (n > (card->tst_free_entries - NS_TST_RESERVED))
- {
- PRINTK("nicstar%d: not enough free CBR bandwidth.\n", card->index);
- clear_bit(ATM_VF_PARTIAL,&vcc->flags);
- clear_bit(ATM_VF_ADDR,&vcc->flags);
- return -EINVAL;
- }
- else
- card->tst_free_entries -= n;
-
- XPRINTK("nicstar%d: writing %d tst entries.\n", card->index, n);
- for (frscdi = 0; frscdi < NS_FRSCD_NUM; frscdi++)
- {
- if (card->scd2vc[frscdi] == NULL)
- {
- card->scd2vc[frscdi] = vc;
- break;
- }
- }
- if (frscdi == NS_FRSCD_NUM)
- {
- PRINTK("nicstar%d: no SCD available for CBR channel.\n", card->index);
- card->tst_free_entries += n;
- clear_bit(ATM_VF_PARTIAL,&vcc->flags);
- clear_bit(ATM_VF_ADDR,&vcc->flags);
- return -EBUSY;
- }
-
- vc->cbr_scd = NS_FRSCD + frscdi * NS_FRSCD_SIZE;
-
- scq = get_scq(CBR_SCQSIZE, vc->cbr_scd);
- if (scq == NULL)
- {
- PRINTK("nicstar%d: can't get fixed rate SCQ.\n", card->index);
- card->scd2vc[frscdi] = NULL;
- card->tst_free_entries += n;
- clear_bit(ATM_VF_PARTIAL,&vcc->flags);
- clear_bit(ATM_VF_ADDR,&vcc->flags);
- return -ENOMEM;
- }
- vc->scq = scq;
- u32d[0] = (u32) virt_to_bus(scq->base);
- u32d[1] = (u32) 0x00000000;
- u32d[2] = (u32) 0xffffffff;
- u32d[3] = (u32) 0x00000000;
- ns_write_sram(card, vc->cbr_scd, u32d, 4);
-
- fill_tst(card, n, vc);
- }
- else if (vcc->qos.txtp.traffic_class == ATM_UBR)
- {
- vc->cbr_scd = 0x00000000;
- vc->scq = card->scq0;
- }
-
- if (vcc->qos.txtp.traffic_class != ATM_NONE)
- {
- vc->tx = 1;
- vc->tx_vcc = vcc;
- vc->tbd_count = 0;
- }
- if (vcc->qos.rxtp.traffic_class != ATM_NONE)
- {
- u32 status;
-
- vc->rx = 1;
- vc->rx_vcc = vcc;
- vc->rx_iov = NULL;
-
- /* Open the connection in hardware */
- if (vcc->qos.aal == ATM_AAL5)
- status = NS_RCTE_AAL5 | NS_RCTE_CONNECTOPEN;
- else /* vcc->qos.aal == ATM_AAL0 */
- status = NS_RCTE_AAL0 | NS_RCTE_CONNECTOPEN;
+ ns_dev *card;
+ vc_map *vc;
+ unsigned long tmpl, modl;
+ int tcr, tcra; /* target cell rate, and absolute value */
+ int n = 0; /* Number of entries in the TST. Initialized to remove
+ the compiler warning. */
+ u32 u32d[4];
+ int frscdi = 0; /* Index of the SCD. Initialized to remove the compiler
+ warning. How I wish compilers were clever enough to
+ tell which variables can truly be used
+ uninitialized... */
+ int inuse; /* tx or rx vc already in use by another vcc */
+ short vpi = vcc->vpi;
+ int vci = vcc->vci;
+
+ card = (ns_dev *) vcc->dev->dev_data;
+ PRINTK("nicstar%d: opening vpi.vci %d.%d \n", card->index, (int)vpi,
+ vci);
+ if (vcc->qos.aal != ATM_AAL5 && vcc->qos.aal != ATM_AAL0) {
+ PRINTK("nicstar%d: unsupported AAL.\n", card->index);
+ return -EINVAL;
+ }
+
+ vc = &(card->vcmap[vpi << card->vcibits | vci]);
+ vcc->dev_data = vc;
+
+ inuse = 0;
+ if (vcc->qos.txtp.traffic_class != ATM_NONE && vc->tx)
+ inuse = 1;
+ if (vcc->qos.rxtp.traffic_class != ATM_NONE && vc->rx)
+ inuse += 2;
+ if (inuse) {
+ printk("nicstar%d: %s vci already in use.\n", card->index,
+ inuse == 1 ? "tx" : inuse == 2 ? "rx" : "tx and rx");
+ return -EINVAL;
+ }
+
+ set_bit(ATM_VF_ADDR, &vcc->flags);
+
+ /* NOTE: You are not allowed to modify an open connection's QOS. To change
+ that, remove the ATM_VF_PARTIAL flag checking. There may be other changes
+ needed to do that. */
+ if (!test_bit(ATM_VF_PARTIAL, &vcc->flags)) {
+ scq_info *scq;
+
+ set_bit(ATM_VF_PARTIAL, &vcc->flags);
+ if (vcc->qos.txtp.traffic_class == ATM_CBR) {
+ /* Check requested cell rate and availability of SCD */
+ if (vcc->qos.txtp.max_pcr == 0 && vcc->qos.txtp.pcr == 0
+ && vcc->qos.txtp.min_pcr == 0) {
+ PRINTK
+ ("nicstar%d: trying to open a CBR vc with cell rate = 0 \n",
+ card->index);
+ clear_bit(ATM_VF_PARTIAL, &vcc->flags);
+ clear_bit(ATM_VF_ADDR, &vcc->flags);
+ return -EINVAL;
+ }
+
+ tcr = atm_pcr_goal(&(vcc->qos.txtp));
+ tcra = tcr >= 0 ? tcr : -tcr;
+
+ PRINTK("nicstar%d: target cell rate = %d.\n",
+ card->index, vcc->qos.txtp.max_pcr);
+
+ tmpl =
+ (unsigned long)tcra *(unsigned long)
+ NS_TST_NUM_ENTRIES;
+ modl = tmpl % card->max_pcr;
+
+ n = (int)(tmpl / card->max_pcr);
+ if (tcr > 0) {
+ if (modl > 0)
+ n++;
+ } else if (tcr == 0) {
+ if ((n =
+ (card->tst_free_entries -
+ NS_TST_RESERVED)) <= 0) {
+ PRINTK
+ ("nicstar%d: no CBR bandwidth free.\n",
+ card->index);
+ clear_bit(ATM_VF_PARTIAL, &vcc->flags);
+ clear_bit(ATM_VF_ADDR, &vcc->flags);
+ return -EINVAL;
+ }
+ }
+
+ if (n == 0) {
+ printk
+ ("nicstar%d: selected bandwidth < granularity.\n",
+ card->index);
+ clear_bit(ATM_VF_PARTIAL, &vcc->flags);
+ clear_bit(ATM_VF_ADDR, &vcc->flags);
+ return -EINVAL;
+ }
+
+ if (n > (card->tst_free_entries - NS_TST_RESERVED)) {
+ PRINTK
+ ("nicstar%d: not enough free CBR bandwidth.\n",
+ card->index);
+ clear_bit(ATM_VF_PARTIAL, &vcc->flags);
+ clear_bit(ATM_VF_ADDR, &vcc->flags);
+ return -EINVAL;
+ } else
+ card->tst_free_entries -= n;
+
+ XPRINTK("nicstar%d: writing %d tst entries.\n",
+ card->index, n);
+ for (frscdi = 0; frscdi < NS_FRSCD_NUM; frscdi++) {
+ if (card->scd2vc[frscdi] == NULL) {
+ card->scd2vc[frscdi] = vc;
+ break;
+ }
+ }
+ if (frscdi == NS_FRSCD_NUM) {
+ PRINTK
+ ("nicstar%d: no SCD available for CBR channel.\n",
+ card->index);
+ card->tst_free_entries += n;
+ clear_bit(ATM_VF_PARTIAL, &vcc->flags);
+ clear_bit(ATM_VF_ADDR, &vcc->flags);
+ return -EBUSY;
+ }
+
+ vc->cbr_scd = NS_FRSCD + frscdi * NS_FRSCD_SIZE;
+
+ scq = get_scq(card, CBR_SCQSIZE, vc->cbr_scd);
+ if (scq == NULL) {
+ PRINTK("nicstar%d: can't get fixed rate SCQ.\n",
+ card->index);
+ card->scd2vc[frscdi] = NULL;
+ card->tst_free_entries += n;
+ clear_bit(ATM_VF_PARTIAL, &vcc->flags);
+ clear_bit(ATM_VF_ADDR, &vcc->flags);
+ return -ENOMEM;
+ }
+ vc->scq = scq;
+ u32d[0] = scq_virt_to_bus(scq, scq->base);
+ u32d[1] = (u32) 0x00000000;
+ u32d[2] = (u32) 0xffffffff;
+ u32d[3] = (u32) 0x00000000;
+ ns_write_sram(card, vc->cbr_scd, u32d, 4);
+
+ fill_tst(card, n, vc);
+ } else if (vcc->qos.txtp.traffic_class == ATM_UBR) {
+ vc->cbr_scd = 0x00000000;
+ vc->scq = card->scq0;
+ }
+
+ if (vcc->qos.txtp.traffic_class != ATM_NONE) {
+ vc->tx = 1;
+ vc->tx_vcc = vcc;
+ vc->tbd_count = 0;
+ }
+ if (vcc->qos.rxtp.traffic_class != ATM_NONE) {
+ u32 status;
+
+ vc->rx = 1;
+ vc->rx_vcc = vcc;
+ vc->rx_iov = NULL;
+
+ /* Open the connection in hardware */
+ if (vcc->qos.aal == ATM_AAL5)
+ status = NS_RCTE_AAL5 | NS_RCTE_CONNECTOPEN;
+ else /* vcc->qos.aal == ATM_AAL0 */
+ status = NS_RCTE_AAL0 | NS_RCTE_CONNECTOPEN;
#ifdef RCQ_SUPPORT
- status |= NS_RCTE_RAWCELLINTEN;
+ status |= NS_RCTE_RAWCELLINTEN;
#endif /* RCQ_SUPPORT */
- ns_write_sram(card, NS_RCT + (vpi << card->vcibits | vci) *
- NS_RCT_ENTRY_SIZE, &status, 1);
- }
-
- }
-
- set_bit(ATM_VF_READY,&vcc->flags);
- return 0;
-}
+ ns_write_sram(card,
+ NS_RCT +
+ (vpi << card->vcibits | vci) *
+ NS_RCT_ENTRY_SIZE, &status, 1);
+ }
+ }
+ set_bit(ATM_VF_READY, &vcc->flags);
+ return 0;
+}
static void ns_close(struct atm_vcc *vcc)
{
- vc_map *vc;
- ns_dev *card;
- u32 data;
- int i;
-
- vc = vcc->dev_data;
- card = vcc->dev->dev_data;
- PRINTK("nicstar%d: closing vpi.vci %d.%d \n", card->index,
- (int) vcc->vpi, vcc->vci);
-
- clear_bit(ATM_VF_READY,&vcc->flags);
-
- if (vcc->qos.rxtp.traffic_class != ATM_NONE)
- {
- u32 addr;
- unsigned long flags;
-
- addr = NS_RCT + (vcc->vpi << card->vcibits | vcc->vci) * NS_RCT_ENTRY_SIZE;
- spin_lock_irqsave(&card->res_lock, flags);
- while(CMD_BUSY(card));
- writel(NS_CMD_CLOSE_CONNECTION | addr << 2, card->membase + CMD);
- spin_unlock_irqrestore(&card->res_lock, flags);
-
- vc->rx = 0;
- if (vc->rx_iov != NULL)
- {
- struct sk_buff *iovb;
- u32 stat;
-
- stat = readl(card->membase + STAT);
- card->sbfqc = ns_stat_sfbqc_get(stat);
- card->lbfqc = ns_stat_lfbqc_get(stat);
-
- PRINTK("nicstar%d: closing a VC with pending rx buffers.\n",
- card->index);
- iovb = vc->rx_iov;
- recycle_iovec_rx_bufs(card, (struct iovec *) iovb->data,
- NS_SKB(iovb)->iovcnt);
- NS_SKB(iovb)->iovcnt = 0;
- NS_SKB(iovb)->vcc = NULL;
- spin_lock_irqsave(&card->int_lock, flags);
- recycle_iov_buf(card, iovb);
- spin_unlock_irqrestore(&card->int_lock, flags);
- vc->rx_iov = NULL;
- }
- }
-
- if (vcc->qos.txtp.traffic_class != ATM_NONE)
- {
- vc->tx = 0;
- }
-
- if (vcc->qos.txtp.traffic_class == ATM_CBR)
- {
- unsigned long flags;
- ns_scqe *scqep;
- scq_info *scq;
-
- scq = vc->scq;
-
- for (;;)
- {
- spin_lock_irqsave(&scq->lock, flags);
- scqep = scq->next;
- if (scqep == scq->base)
- scqep = scq->last;
- else
- scqep--;
- if (scqep == scq->tail)
- {
- spin_unlock_irqrestore(&scq->lock, flags);
- break;
- }
- /* If the last entry is not a TSR, place one in the SCQ in order to
- be able to completely drain it and then close. */
- if (!ns_scqe_is_tsr(scqep) && scq->tail != scq->next)
- {
- ns_scqe tsr;
- u32 scdi, scqi;
- u32 data;
- int index;
-
- tsr.word_1 = ns_tsr_mkword_1(NS_TSR_INTENABLE);
- scdi = (vc->cbr_scd - NS_FRSCD) / NS_FRSCD_SIZE;
- scqi = scq->next - scq->base;
- tsr.word_2 = ns_tsr_mkword_2(scdi, scqi);
- tsr.word_3 = 0x00000000;
- tsr.word_4 = 0x00000000;
- *scq->next = tsr;
- index = (int) scqi;
- scq->skb[index] = NULL;
- if (scq->next == scq->last)
- scq->next = scq->base;
- else
- scq->next++;
- data = (u32) virt_to_bus(scq->next);
- ns_write_sram(card, scq->scd, &data, 1);
- }
- spin_unlock_irqrestore(&scq->lock, flags);
- schedule();
- }
-
- /* Free all TST entries */
- data = NS_TST_OPCODE_VARIABLE;
- for (i = 0; i < NS_TST_NUM_ENTRIES; i++)
- {
- if (card->tste2vc[i] == vc)
- {
- ns_write_sram(card, card->tst_addr + i, &data, 1);
- card->tste2vc[i] = NULL;
- card->tst_free_entries++;
- }
- }
-
- card->scd2vc[(vc->cbr_scd - NS_FRSCD) / NS_FRSCD_SIZE] = NULL;
- free_scq(vc->scq, vcc);
- }
-
- /* remove all references to vcc before deleting it */
- if (vcc->qos.txtp.traffic_class != ATM_NONE)
- {
- unsigned long flags;
- scq_info *scq = card->scq0;
-
- spin_lock_irqsave(&scq->lock, flags);
-
- for(i = 0; i < scq->num_entries; i++) {
- if(scq->skb[i] && ATM_SKB(scq->skb[i])->vcc == vcc) {
- ATM_SKB(scq->skb[i])->vcc = NULL;
- atm_return(vcc, scq->skb[i]->truesize);
- PRINTK("nicstar: deleted pending vcc mapping\n");
- }
- }
-
- spin_unlock_irqrestore(&scq->lock, flags);
- }
-
- vcc->dev_data = NULL;
- clear_bit(ATM_VF_PARTIAL,&vcc->flags);
- clear_bit(ATM_VF_ADDR,&vcc->flags);
+ vc_map *vc;
+ ns_dev *card;
+ u32 data;
+ int i;
+
+ vc = vcc->dev_data;
+ card = vcc->dev->dev_data;
+ PRINTK("nicstar%d: closing vpi.vci %d.%d \n", card->index,
+ (int)vcc->vpi, vcc->vci);
+
+ clear_bit(ATM_VF_READY, &vcc->flags);
+
+ if (vcc->qos.rxtp.traffic_class != ATM_NONE) {
+ u32 addr;
+ unsigned long flags;
+
+ addr =
+ NS_RCT +
+ (vcc->vpi << card->vcibits | vcc->vci) * NS_RCT_ENTRY_SIZE;
+ spin_lock_irqsave(&card->res_lock, flags);
+ while (CMD_BUSY(card)) ;
+ writel(NS_CMD_CLOSE_CONNECTION | addr << 2,
+ card->membase + CMD);
+ spin_unlock_irqrestore(&card->res_lock, flags);
+
+ vc->rx = 0;
+ if (vc->rx_iov != NULL) {
+ struct sk_buff *iovb;
+ u32 stat;
+
+ stat = readl(card->membase + STAT);
+ card->sbfqc = ns_stat_sfbqc_get(stat);
+ card->lbfqc = ns_stat_lfbqc_get(stat);
+
+ PRINTK
+ ("nicstar%d: closing a VC with pending rx buffers.\n",
+ card->index);
+ iovb = vc->rx_iov;
+ recycle_iovec_rx_bufs(card, (struct iovec *)iovb->data,
+ NS_PRV_IOVCNT(iovb));
+ NS_PRV_IOVCNT(iovb) = 0;
+ spin_lock_irqsave(&card->int_lock, flags);
+ recycle_iov_buf(card, iovb);
+ spin_unlock_irqrestore(&card->int_lock, flags);
+ vc->rx_iov = NULL;
+ }
+ }
+
+ if (vcc->qos.txtp.traffic_class != ATM_NONE) {
+ vc->tx = 0;
+ }
+
+ if (vcc->qos.txtp.traffic_class == ATM_CBR) {
+ unsigned long flags;
+ ns_scqe *scqep;
+ scq_info *scq;
+
+ scq = vc->scq;
+
+ for (;;) {
+ spin_lock_irqsave(&scq->lock, flags);
+ scqep = scq->next;
+ if (scqep == scq->base)
+ scqep = scq->last;
+ else
+ scqep--;
+ if (scqep == scq->tail) {
+ spin_unlock_irqrestore(&scq->lock, flags);
+ break;
+ }
+ /* If the last entry is not a TSR, place one in the SCQ in order to
+ be able to completely drain it and then close. */
+ if (!ns_scqe_is_tsr(scqep) && scq->tail != scq->next) {
+ ns_scqe tsr;
+ u32 scdi, scqi;
+ u32 data;
+ int index;
+
+ tsr.word_1 = ns_tsr_mkword_1(NS_TSR_INTENABLE);
+ scdi = (vc->cbr_scd - NS_FRSCD) / NS_FRSCD_SIZE;
+ scqi = scq->next - scq->base;
+ tsr.word_2 = ns_tsr_mkword_2(scdi, scqi);
+ tsr.word_3 = 0x00000000;
+ tsr.word_4 = 0x00000000;
+ *scq->next = tsr;
+ index = (int)scqi;
+ scq->skb[index] = NULL;
+ if (scq->next == scq->last)
+ scq->next = scq->base;
+ else
+ scq->next++;
+ data = scq_virt_to_bus(scq, scq->next);
+ ns_write_sram(card, scq->scd, &data, 1);
+ }
+ spin_unlock_irqrestore(&scq->lock, flags);
+ schedule();
+ }
+
+ /* Free all TST entries */
+ data = NS_TST_OPCODE_VARIABLE;
+ for (i = 0; i < NS_TST_NUM_ENTRIES; i++) {
+ if (card->tste2vc[i] == vc) {
+ ns_write_sram(card, card->tst_addr + i, &data,
+ 1);
+ card->tste2vc[i] = NULL;
+ card->tst_free_entries++;
+ }
+ }
+
+ card->scd2vc[(vc->cbr_scd - NS_FRSCD) / NS_FRSCD_SIZE] = NULL;
+ free_scq(card, vc->scq, vcc);
+ }
+
+ /* remove all references to vcc before deleting it */
+ if (vcc->qos.txtp.traffic_class != ATM_NONE) {
+ unsigned long flags;
+ scq_info *scq = card->scq0;
+
+ spin_lock_irqsave(&scq->lock, flags);
+
+ for (i = 0; i < scq->num_entries; i++) {
+ if (scq->skb[i] && ATM_SKB(scq->skb[i])->vcc == vcc) {
+ ATM_SKB(scq->skb[i])->vcc = NULL;
+ atm_return(vcc, scq->skb[i]->truesize);
+ PRINTK
+ ("nicstar: deleted pending vcc mapping\n");
+ }
+ }
+
+ spin_unlock_irqrestore(&scq->lock, flags);
+ }
+
+ vcc->dev_data = NULL;
+ clear_bit(ATM_VF_PARTIAL, &vcc->flags);
+ clear_bit(ATM_VF_ADDR, &vcc->flags);
#ifdef RX_DEBUG
- {
- u32 stat, cfg;
- stat = readl(card->membase + STAT);
- cfg = readl(card->membase + CFG);
- printk("STAT = 0x%08X CFG = 0x%08X \n", stat, cfg);
- printk("TSQ: base = 0x%08X next = 0x%08X last = 0x%08X TSQT = 0x%08X \n",
- (u32) card->tsq.base, (u32) card->tsq.next,(u32) card->tsq.last,
- readl(card->membase + TSQT));
- printk("RSQ: base = 0x%08X next = 0x%08X last = 0x%08X RSQT = 0x%08X \n",
- (u32) card->rsq.base, (u32) card->rsq.next,(u32) card->rsq.last,
- readl(card->membase + RSQT));
- printk("Empty free buffer queue interrupt %s \n",
- card->efbie ? "enabled" : "disabled");
- printk("SBCNT = %d count = %d LBCNT = %d count = %d \n",
- ns_stat_sfbqc_get(stat), card->sbpool.count,
- ns_stat_lfbqc_get(stat), card->lbpool.count);
- printk("hbpool.count = %d iovpool.count = %d \n",
- card->hbpool.count, card->iovpool.count);
- }
+ {
+ u32 stat, cfg;
+ stat = readl(card->membase + STAT);
+ cfg = readl(card->membase + CFG);
+ printk("STAT = 0x%08X CFG = 0x%08X \n", stat, cfg);
+ printk
+ ("TSQ: base = 0x%p next = 0x%p last = 0x%p TSQT = 0x%08X \n",
+ card->tsq.base, card->tsq.next,
+ card->tsq.last, readl(card->membase + TSQT));
+ printk
+ ("RSQ: base = 0x%p next = 0x%p last = 0x%p RSQT = 0x%08X \n",
+ card->rsq.base, card->rsq.next,
+ card->rsq.last, readl(card->membase + RSQT));
+ printk("Empty free buffer queue interrupt %s \n",
+ card->efbie ? "enabled" : "disabled");
+ printk("SBCNT = %d count = %d LBCNT = %d count = %d \n",
+ ns_stat_sfbqc_get(stat), card->sbpool.count,
+ ns_stat_lfbqc_get(stat), card->lbpool.count);
+ printk("hbpool.count = %d iovpool.count = %d \n",
+ card->hbpool.count, card->iovpool.count);
+ }
#endif /* RX_DEBUG */
}
-
-
-static void fill_tst(ns_dev *card, int n, vc_map *vc)
+static void fill_tst(ns_dev * card, int n, vc_map * vc)
{
- u32 new_tst;
- unsigned long cl;
- int e, r;
- u32 data;
-
- /* It would be very complicated to keep the two TSTs synchronized while
- assuring that writes are only made to the inactive TST. So, for now I
- will use only one TST. If problems occur, I will change this again */
-
- new_tst = card->tst_addr;
-
- /* Fill procedure */
-
- for (e = 0; e < NS_TST_NUM_ENTRIES; e++)
- {
- if (card->tste2vc[e] == NULL)
- break;
- }
- if (e == NS_TST_NUM_ENTRIES) {
- printk("nicstar%d: No free TST entries found. \n", card->index);
- return;
- }
-
- r = n;
- cl = NS_TST_NUM_ENTRIES;
- data = ns_tste_make(NS_TST_OPCODE_FIXED, vc->cbr_scd);
-
- while (r > 0)
- {
- if (cl >= NS_TST_NUM_ENTRIES && card->tste2vc[e] == NULL)
- {
- card->tste2vc[e] = vc;
- ns_write_sram(card, new_tst + e, &data, 1);
- cl -= NS_TST_NUM_ENTRIES;
- r--;
- }
-
- if (++e == NS_TST_NUM_ENTRIES) {
- e = 0;
- }
- cl += n;
- }
-
- /* End of fill procedure */
-
- data = ns_tste_make(NS_TST_OPCODE_END, new_tst);
- ns_write_sram(card, new_tst + NS_TST_NUM_ENTRIES, &data, 1);
- ns_write_sram(card, card->tst_addr + NS_TST_NUM_ENTRIES, &data, 1);
- card->tst_addr = new_tst;
+ u32 new_tst;
+ unsigned long cl;
+ int e, r;
+ u32 data;
+
+ /* It would be very complicated to keep the two TSTs synchronized while
+ assuring that writes are only made to the inactive TST. So, for now I
+ will use only one TST. If problems occur, I will change this again */
+
+ new_tst = card->tst_addr;
+
+ /* Fill procedure */
+
+ for (e = 0; e < NS_TST_NUM_ENTRIES; e++) {
+ if (card->tste2vc[e] == NULL)
+ break;
+ }
+ if (e == NS_TST_NUM_ENTRIES) {
+ printk("nicstar%d: No free TST entries found. \n", card->index);
+ return;
+ }
+
+ r = n;
+ cl = NS_TST_NUM_ENTRIES;
+ data = ns_tste_make(NS_TST_OPCODE_FIXED, vc->cbr_scd);
+
+ while (r > 0) {
+ if (cl >= NS_TST_NUM_ENTRIES && card->tste2vc[e] == NULL) {
+ card->tste2vc[e] = vc;
+ ns_write_sram(card, new_tst + e, &data, 1);
+ cl -= NS_TST_NUM_ENTRIES;
+ r--;
+ }
+
+ if (++e == NS_TST_NUM_ENTRIES) {
+ e = 0;
+ }
+ cl += n;
+ }
+
+ /* End of fill procedure */
+
+ data = ns_tste_make(NS_TST_OPCODE_END, new_tst);
+ ns_write_sram(card, new_tst + NS_TST_NUM_ENTRIES, &data, 1);
+ ns_write_sram(card, card->tst_addr + NS_TST_NUM_ENTRIES, &data, 1);
+ card->tst_addr = new_tst;
}
-
-
static int ns_send(struct atm_vcc *vcc, struct sk_buff *skb)
{
- ns_dev *card;
- vc_map *vc;
- scq_info *scq;
- unsigned long buflen;
- ns_scqe scqe;
- u32 flags; /* TBD flags, not CPU flags */
-
- card = vcc->dev->dev_data;
- TXPRINTK("nicstar%d: ns_send() called.\n", card->index);
- if ((vc = (vc_map *) vcc->dev_data) == NULL)
- {
- printk("nicstar%d: vcc->dev_data == NULL on ns_send().\n", card->index);
- atomic_inc(&vcc->stats->tx_err);
- dev_kfree_skb_any(skb);
- return -EINVAL;
- }
-
- if (!vc->tx)
- {
- printk("nicstar%d: Trying to transmit on a non-tx VC.\n", card->index);
- atomic_inc(&vcc->stats->tx_err);
- dev_kfree_skb_any(skb);
- return -EINVAL;
- }
-
- if (vcc->qos.aal != ATM_AAL5 && vcc->qos.aal != ATM_AAL0)
- {
- printk("nicstar%d: Only AAL0 and AAL5 are supported.\n", card->index);
- atomic_inc(&vcc->stats->tx_err);
- dev_kfree_skb_any(skb);
- return -EINVAL;
- }
-
- if (skb_shinfo(skb)->nr_frags != 0)
- {
- printk("nicstar%d: No scatter-gather yet.\n", card->index);
- atomic_inc(&vcc->stats->tx_err);
- dev_kfree_skb_any(skb);
- return -EINVAL;
- }
-
- ATM_SKB(skb)->vcc = vcc;
-
- if (vcc->qos.aal == ATM_AAL5)
- {
- buflen = (skb->len + 47 + 8) / 48 * 48; /* Multiple of 48 */
- flags = NS_TBD_AAL5;
- scqe.word_2 = cpu_to_le32((u32) virt_to_bus(skb->data));
- scqe.word_3 = cpu_to_le32((u32) skb->len);
- scqe.word_4 = ns_tbd_mkword_4(0, (u32) vcc->vpi, (u32) vcc->vci, 0,
- ATM_SKB(skb)->atm_options & ATM_ATMOPT_CLP ? 1 : 0);
- flags |= NS_TBD_EOPDU;
- }
- else /* (vcc->qos.aal == ATM_AAL0) */
- {
- buflen = ATM_CELL_PAYLOAD; /* i.e., 48 bytes */
- flags = NS_TBD_AAL0;
- scqe.word_2 = cpu_to_le32((u32) virt_to_bus(skb->data) + NS_AAL0_HEADER);
- scqe.word_3 = cpu_to_le32(0x00000000);
- if (*skb->data & 0x02) /* Payload type 1 - end of pdu */
- flags |= NS_TBD_EOPDU;
- scqe.word_4 = cpu_to_le32(*((u32 *) skb->data) & ~NS_TBD_VC_MASK);
- /* Force the VPI/VCI to be the same as in VCC struct */
- scqe.word_4 |= cpu_to_le32((((u32) vcc->vpi) << NS_TBD_VPI_SHIFT |
- ((u32) vcc->vci) << NS_TBD_VCI_SHIFT) &
- NS_TBD_VC_MASK);
- }
-
- if (vcc->qos.txtp.traffic_class == ATM_CBR)
- {
- scqe.word_1 = ns_tbd_mkword_1_novbr(flags, (u32) buflen);
- scq = ((vc_map *) vcc->dev_data)->scq;
- }
- else
- {
- scqe.word_1 = ns_tbd_mkword_1(flags, (u32) 1, (u32) 1, (u32) buflen);
- scq = card->scq0;
- }
-
- if (push_scqe(card, vc, scq, &scqe, skb) != 0)
- {
- atomic_inc(&vcc->stats->tx_err);
- dev_kfree_skb_any(skb);
- return -EIO;
- }
- atomic_inc(&vcc->stats->tx);
-
- return 0;
-}
-
+ ns_dev *card;
+ vc_map *vc;
+ scq_info *scq;
+ unsigned long buflen;
+ ns_scqe scqe;
+ u32 flags; /* TBD flags, not CPU flags */
+
+ card = vcc->dev->dev_data;
+ TXPRINTK("nicstar%d: ns_send() called.\n", card->index);
+ if ((vc = (vc_map *) vcc->dev_data) == NULL) {
+ printk("nicstar%d: vcc->dev_data == NULL on ns_send().\n",
+ card->index);
+ atomic_inc(&vcc->stats->tx_err);
+ dev_kfree_skb_any(skb);
+ return -EINVAL;
+ }
+ if (!vc->tx) {
+ printk("nicstar%d: Trying to transmit on a non-tx VC.\n",
+ card->index);
+ atomic_inc(&vcc->stats->tx_err);
+ dev_kfree_skb_any(skb);
+ return -EINVAL;
+ }
-static int push_scqe(ns_dev *card, vc_map *vc, scq_info *scq, ns_scqe *tbd,
- struct sk_buff *skb)
-{
- unsigned long flags;
- ns_scqe tsr;
- u32 scdi, scqi;
- int scq_is_vbr;
- u32 data;
- int index;
-
- spin_lock_irqsave(&scq->lock, flags);
- while (scq->tail == scq->next)
- {
- if (in_interrupt()) {
- spin_unlock_irqrestore(&scq->lock, flags);
- printk("nicstar%d: Error pushing TBD.\n", card->index);
- return 1;
- }
-
- scq->full = 1;
- spin_unlock_irqrestore(&scq->lock, flags);
- interruptible_sleep_on_timeout(&scq->scqfull_waitq, SCQFULL_TIMEOUT);
- spin_lock_irqsave(&scq->lock, flags);
-
- if (scq->full) {
- spin_unlock_irqrestore(&scq->lock, flags);
- printk("nicstar%d: Timeout pushing TBD.\n", card->index);
- return 1;
- }
- }
- *scq->next = *tbd;
- index = (int) (scq->next - scq->base);
- scq->skb[index] = skb;
- XPRINTK("nicstar%d: sending skb at 0x%x (pos %d).\n",
- card->index, (u32) skb, index);
- XPRINTK("nicstar%d: TBD written:\n0x%x\n0x%x\n0x%x\n0x%x\n at 0x%x.\n",
- card->index, le32_to_cpu(tbd->word_1), le32_to_cpu(tbd->word_2),
- le32_to_cpu(tbd->word_3), le32_to_cpu(tbd->word_4),
- (u32) scq->next);
- if (scq->next == scq->last)
- scq->next = scq->base;
- else
- scq->next++;
-
- vc->tbd_count++;
- if (scq->num_entries == VBR_SCQ_NUM_ENTRIES)
- {
- scq->tbd_count++;
- scq_is_vbr = 1;
- }
- else
- scq_is_vbr = 0;
-
- if (vc->tbd_count >= MAX_TBD_PER_VC || scq->tbd_count >= MAX_TBD_PER_SCQ)
- {
- int has_run = 0;
-
- while (scq->tail == scq->next)
- {
- if (in_interrupt()) {
- data = (u32) virt_to_bus(scq->next);
- ns_write_sram(card, scq->scd, &data, 1);
- spin_unlock_irqrestore(&scq->lock, flags);
- printk("nicstar%d: Error pushing TSR.\n", card->index);
- return 0;
- }
-
- scq->full = 1;
- if (has_run++) break;
- spin_unlock_irqrestore(&scq->lock, flags);
- interruptible_sleep_on_timeout(&scq->scqfull_waitq, SCQFULL_TIMEOUT);
- spin_lock_irqsave(&scq->lock, flags);
- }
-
- if (!scq->full)
- {
- tsr.word_1 = ns_tsr_mkword_1(NS_TSR_INTENABLE);
- if (scq_is_vbr)
- scdi = NS_TSR_SCDISVBR;
- else
- scdi = (vc->cbr_scd - NS_FRSCD) / NS_FRSCD_SIZE;
- scqi = scq->next - scq->base;
- tsr.word_2 = ns_tsr_mkword_2(scdi, scqi);
- tsr.word_3 = 0x00000000;
- tsr.word_4 = 0x00000000;
-
- *scq->next = tsr;
- index = (int) scqi;
- scq->skb[index] = NULL;
- XPRINTK("nicstar%d: TSR written:\n0x%x\n0x%x\n0x%x\n0x%x\n at 0x%x.\n",
- card->index, le32_to_cpu(tsr.word_1), le32_to_cpu(tsr.word_2),
- le32_to_cpu(tsr.word_3), le32_to_cpu(tsr.word_4),
- (u32) scq->next);
- if (scq->next == scq->last)
- scq->next = scq->base;
- else
- scq->next++;
- vc->tbd_count = 0;
- scq->tbd_count = 0;
- }
- else
- PRINTK("nicstar%d: Timeout pushing TSR.\n", card->index);
- }
- data = (u32) virt_to_bus(scq->next);
- ns_write_sram(card, scq->scd, &data, 1);
-
- spin_unlock_irqrestore(&scq->lock, flags);
-
- return 0;
-}
+ if (vcc->qos.aal != ATM_AAL5 && vcc->qos.aal != ATM_AAL0) {
+ printk("nicstar%d: Only AAL0 and AAL5 are supported.\n",
+ card->index);
+ atomic_inc(&vcc->stats->tx_err);
+ dev_kfree_skb_any(skb);
+ return -EINVAL;
+ }
+ if (skb_shinfo(skb)->nr_frags != 0) {
+ printk("nicstar%d: No scatter-gather yet.\n", card->index);
+ atomic_inc(&vcc->stats->tx_err);
+ dev_kfree_skb_any(skb);
+ return -EINVAL;
+ }
+
+ ATM_SKB(skb)->vcc = vcc;
+
+ NS_PRV_DMA(skb) = pci_map_single(card->pcidev, skb->data,
+ skb->len, PCI_DMA_TODEVICE);
+
+ if (vcc->qos.aal == ATM_AAL5) {
+ buflen = (skb->len + 47 + 8) / 48 * 48; /* Multiple of 48 */
+ flags = NS_TBD_AAL5;
+ scqe.word_2 = cpu_to_le32(NS_PRV_DMA(skb));
+ scqe.word_3 = cpu_to_le32(skb->len);
+ scqe.word_4 =
+ ns_tbd_mkword_4(0, (u32) vcc->vpi, (u32) vcc->vci, 0,
+ ATM_SKB(skb)->
+ atm_options & ATM_ATMOPT_CLP ? 1 : 0);
+ flags |= NS_TBD_EOPDU;
+ } else { /* (vcc->qos.aal == ATM_AAL0) */
+
+ buflen = ATM_CELL_PAYLOAD; /* i.e., 48 bytes */
+ flags = NS_TBD_AAL0;
+ scqe.word_2 = cpu_to_le32(NS_PRV_DMA(skb) + NS_AAL0_HEADER);
+ scqe.word_3 = cpu_to_le32(0x00000000);
+ if (*skb->data & 0x02) /* Payload type 1 - end of pdu */
+ flags |= NS_TBD_EOPDU;
+ scqe.word_4 =
+ cpu_to_le32(*((u32 *) skb->data) & ~NS_TBD_VC_MASK);
+ /* Force the VPI/VCI to be the same as in VCC struct */
+ scqe.word_4 |=
+ cpu_to_le32((((u32) vcc->
+ vpi) << NS_TBD_VPI_SHIFT | ((u32) vcc->
+ vci) <<
+ NS_TBD_VCI_SHIFT) & NS_TBD_VC_MASK);
+ }
+
+ if (vcc->qos.txtp.traffic_class == ATM_CBR) {
+ scqe.word_1 = ns_tbd_mkword_1_novbr(flags, (u32) buflen);
+ scq = ((vc_map *) vcc->dev_data)->scq;
+ } else {
+ scqe.word_1 =
+ ns_tbd_mkword_1(flags, (u32) 1, (u32) 1, (u32) buflen);
+ scq = card->scq0;
+ }
+
+ if (push_scqe(card, vc, scq, &scqe, skb) != 0) {
+ atomic_inc(&vcc->stats->tx_err);
+ dev_kfree_skb_any(skb);
+ return -EIO;
+ }
+ atomic_inc(&vcc->stats->tx);
+ return 0;
+}
-static void process_tsq(ns_dev *card)
+static int push_scqe(ns_dev * card, vc_map * vc, scq_info * scq, ns_scqe * tbd,
+ struct sk_buff *skb)
{
- u32 scdi;
- scq_info *scq;
- ns_tsi *previous = NULL, *one_ahead, *two_ahead;
- int serviced_entries; /* flag indicating at least on entry was serviced */
-
- serviced_entries = 0;
-
- if (card->tsq.next == card->tsq.last)
- one_ahead = card->tsq.base;
- else
- one_ahead = card->tsq.next + 1;
-
- if (one_ahead == card->tsq.last)
- two_ahead = card->tsq.base;
- else
- two_ahead = one_ahead + 1;
-
- while (!ns_tsi_isempty(card->tsq.next) || !ns_tsi_isempty(one_ahead) ||
- !ns_tsi_isempty(two_ahead))
- /* At most two empty, as stated in the 77201 errata */
- {
- serviced_entries = 1;
-
- /* Skip the one or two possible empty entries */
- while (ns_tsi_isempty(card->tsq.next)) {
- if (card->tsq.next == card->tsq.last)
- card->tsq.next = card->tsq.base;
- else
- card->tsq.next++;
- }
-
- if (!ns_tsi_tmrof(card->tsq.next))
- {
- scdi = ns_tsi_getscdindex(card->tsq.next);
- if (scdi == NS_TSI_SCDISVBR)
- scq = card->scq0;
- else
- {
- if (card->scd2vc[scdi] == NULL)
- {
- printk("nicstar%d: could not find VC from SCD index.\n",
- card->index);
- ns_tsi_init(card->tsq.next);
- return;
- }
- scq = card->scd2vc[scdi]->scq;
- }
- drain_scq(card, scq, ns_tsi_getscqpos(card->tsq.next));
- scq->full = 0;
- wake_up_interruptible(&(scq->scqfull_waitq));
- }
-
- ns_tsi_init(card->tsq.next);
- previous = card->tsq.next;
- if (card->tsq.next == card->tsq.last)
- card->tsq.next = card->tsq.base;
- else
- card->tsq.next++;
-
- if (card->tsq.next == card->tsq.last)
- one_ahead = card->tsq.base;
- else
- one_ahead = card->tsq.next + 1;
-
- if (one_ahead == card->tsq.last)
- two_ahead = card->tsq.base;
- else
- two_ahead = one_ahead + 1;
- }
-
- if (serviced_entries) {
- writel((((u32) previous) - ((u32) card->tsq.base)),
- card->membase + TSQH);
- }
+ unsigned long flags;
+ ns_scqe tsr;
+ u32 scdi, scqi;
+ int scq_is_vbr;
+ u32 data;
+ int index;
+
+ spin_lock_irqsave(&scq->lock, flags);
+ while (scq->tail == scq->next) {
+ if (in_interrupt()) {
+ spin_unlock_irqrestore(&scq->lock, flags);
+ printk("nicstar%d: Error pushing TBD.\n", card->index);
+ return 1;
+ }
+
+ scq->full = 1;
+ spin_unlock_irqrestore(&scq->lock, flags);
+ interruptible_sleep_on_timeout(&scq->scqfull_waitq,
+ SCQFULL_TIMEOUT);
+ spin_lock_irqsave(&scq->lock, flags);
+
+ if (scq->full) {
+ spin_unlock_irqrestore(&scq->lock, flags);
+ printk("nicstar%d: Timeout pushing TBD.\n",
+ card->index);
+ return 1;
+ }
+ }
+ *scq->next = *tbd;
+ index = (int)(scq->next - scq->base);
+ scq->skb[index] = skb;
+ XPRINTK("nicstar%d: sending skb at 0x%p (pos %d).\n",
+ card->index, skb, index);
+ XPRINTK("nicstar%d: TBD written:\n0x%x\n0x%x\n0x%x\n0x%x\n at 0x%p.\n",
+ card->index, le32_to_cpu(tbd->word_1), le32_to_cpu(tbd->word_2),
+ le32_to_cpu(tbd->word_3), le32_to_cpu(tbd->word_4),
+ scq->next);
+ if (scq->next == scq->last)
+ scq->next = scq->base;
+ else
+ scq->next++;
+
+ vc->tbd_count++;
+ if (scq->num_entries == VBR_SCQ_NUM_ENTRIES) {
+ scq->tbd_count++;
+ scq_is_vbr = 1;
+ } else
+ scq_is_vbr = 0;
+
+ if (vc->tbd_count >= MAX_TBD_PER_VC
+ || scq->tbd_count >= MAX_TBD_PER_SCQ) {
+ int has_run = 0;
+
+ while (scq->tail == scq->next) {
+ if (in_interrupt()) {
+ data = scq_virt_to_bus(scq, scq->next);
+ ns_write_sram(card, scq->scd, &data, 1);
+ spin_unlock_irqrestore(&scq->lock, flags);
+ printk("nicstar%d: Error pushing TSR.\n",
+ card->index);
+ return 0;
+ }
+
+ scq->full = 1;
+ if (has_run++)
+ break;
+ spin_unlock_irqrestore(&scq->lock, flags);
+ interruptible_sleep_on_timeout(&scq->scqfull_waitq,
+ SCQFULL_TIMEOUT);
+ spin_lock_irqsave(&scq->lock, flags);
+ }
+
+ if (!scq->full) {
+ tsr.word_1 = ns_tsr_mkword_1(NS_TSR_INTENABLE);
+ if (scq_is_vbr)
+ scdi = NS_TSR_SCDISVBR;
+ else
+ scdi = (vc->cbr_scd - NS_FRSCD) / NS_FRSCD_SIZE;
+ scqi = scq->next - scq->base;
+ tsr.word_2 = ns_tsr_mkword_2(scdi, scqi);
+ tsr.word_3 = 0x00000000;
+ tsr.word_4 = 0x00000000;
+
+ *scq->next = tsr;
+ index = (int)scqi;
+ scq->skb[index] = NULL;
+ XPRINTK
+ ("nicstar%d: TSR written:\n0x%x\n0x%x\n0x%x\n0x%x\n at 0x%p.\n",
+ card->index, le32_to_cpu(tsr.word_1),
+ le32_to_cpu(tsr.word_2), le32_to_cpu(tsr.word_3),
+ le32_to_cpu(tsr.word_4), scq->next);
+ if (scq->next == scq->last)
+ scq->next = scq->base;
+ else
+ scq->next++;
+ vc->tbd_count = 0;
+ scq->tbd_count = 0;
+ } else
+ PRINTK("nicstar%d: Timeout pushing TSR.\n",
+ card->index);
+ }
+ data = scq_virt_to_bus(scq, scq->next);
+ ns_write_sram(card, scq->scd, &data, 1);
+
+ spin_unlock_irqrestore(&scq->lock, flags);
+
+ return 0;
}
-
-
-static void drain_scq(ns_dev *card, scq_info *scq, int pos)
+static void process_tsq(ns_dev * card)
{
- struct atm_vcc *vcc;
- struct sk_buff *skb;
- int i;
- unsigned long flags;
-
- XPRINTK("nicstar%d: drain_scq() called, scq at 0x%x, pos %d.\n",
- card->index, (u32) scq, pos);
- if (pos >= scq->num_entries)
- {
- printk("nicstar%d: Bad index on drain_scq().\n", card->index);
- return;
- }
-
- spin_lock_irqsave(&scq->lock, flags);
- i = (int) (scq->tail - scq->base);
- if (++i == scq->num_entries)
- i = 0;
- while (i != pos)
- {
- skb = scq->skb[i];
- XPRINTK("nicstar%d: freeing skb at 0x%x (index %d).\n",
- card->index, (u32) skb, i);
- if (skb != NULL)
- {
- vcc = ATM_SKB(skb)->vcc;
- if (vcc && vcc->pop != NULL) {
- vcc->pop(vcc, skb);
- } else {
- dev_kfree_skb_irq(skb);
- }
- scq->skb[i] = NULL;
- }
- if (++i == scq->num_entries)
- i = 0;
- }
- scq->tail = scq->base + pos;
- spin_unlock_irqrestore(&scq->lock, flags);
+ u32 scdi;
+ scq_info *scq;
+ ns_tsi *previous = NULL, *one_ahead, *two_ahead;
+ int serviced_entries; /* flag indicating at least on entry was serviced */
+
+ serviced_entries = 0;
+
+ if (card->tsq.next == card->tsq.last)
+ one_ahead = card->tsq.base;
+ else
+ one_ahead = card->tsq.next + 1;
+
+ if (one_ahead == card->tsq.last)
+ two_ahead = card->tsq.base;
+ else
+ two_ahead = one_ahead + 1;
+
+ while (!ns_tsi_isempty(card->tsq.next) || !ns_tsi_isempty(one_ahead) ||
+ !ns_tsi_isempty(two_ahead))
+ /* At most two empty, as stated in the 77201 errata */
+ {
+ serviced_entries = 1;
+
+ /* Skip the one or two possible empty entries */
+ while (ns_tsi_isempty(card->tsq.next)) {
+ if (card->tsq.next == card->tsq.last)
+ card->tsq.next = card->tsq.base;
+ else
+ card->tsq.next++;
+ }
+
+ if (!ns_tsi_tmrof(card->tsq.next)) {
+ scdi = ns_tsi_getscdindex(card->tsq.next);
+ if (scdi == NS_TSI_SCDISVBR)
+ scq = card->scq0;
+ else {
+ if (card->scd2vc[scdi] == NULL) {
+ printk
+ ("nicstar%d: could not find VC from SCD index.\n",
+ card->index);
+ ns_tsi_init(card->tsq.next);
+ return;
+ }
+ scq = card->scd2vc[scdi]->scq;
+ }
+ drain_scq(card, scq, ns_tsi_getscqpos(card->tsq.next));
+ scq->full = 0;
+ wake_up_interruptible(&(scq->scqfull_waitq));
+ }
+
+ ns_tsi_init(card->tsq.next);
+ previous = card->tsq.next;
+ if (card->tsq.next == card->tsq.last)
+ card->tsq.next = card->tsq.base;
+ else
+ card->tsq.next++;
+
+ if (card->tsq.next == card->tsq.last)
+ one_ahead = card->tsq.base;
+ else
+ one_ahead = card->tsq.next + 1;
+
+ if (one_ahead == card->tsq.last)
+ two_ahead = card->tsq.base;
+ else
+ two_ahead = one_ahead + 1;
+ }
+
+ if (serviced_entries)
+ writel(PTR_DIFF(previous, card->tsq.base),
+ card->membase + TSQH);
}
+static void drain_scq(ns_dev * card, scq_info * scq, int pos)
+{
+ struct atm_vcc *vcc;
+ struct sk_buff *skb;
+ int i;
+ unsigned long flags;
+
+ XPRINTK("nicstar%d: drain_scq() called, scq at 0x%p, pos %d.\n",
+ card->index, scq, pos);
+ if (pos >= scq->num_entries) {
+ printk("nicstar%d: Bad index on drain_scq().\n", card->index);
+ return;
+ }
+
+ spin_lock_irqsave(&scq->lock, flags);
+ i = (int)(scq->tail - scq->base);
+ if (++i == scq->num_entries)
+ i = 0;
+ while (i != pos) {
+ skb = scq->skb[i];
+ XPRINTK("nicstar%d: freeing skb at 0x%p (index %d).\n",
+ card->index, skb, i);
+ if (skb != NULL) {
+ pci_unmap_single(card->pcidev,
+ NS_PRV_DMA(skb),
+ skb->len,
+ PCI_DMA_TODEVICE);
+ vcc = ATM_SKB(skb)->vcc;
+ if (vcc && vcc->pop != NULL) {
+ vcc->pop(vcc, skb);
+ } else {
+ dev_kfree_skb_irq(skb);
+ }
+ scq->skb[i] = NULL;
+ }
+ if (++i == scq->num_entries)
+ i = 0;
+ }
+ scq->tail = scq->base + pos;
+ spin_unlock_irqrestore(&scq->lock, flags);
+}
-
-static void process_rsq(ns_dev *card)
+static void process_rsq(ns_dev * card)
{
- ns_rsqe *previous;
-
- if (!ns_rsqe_valid(card->rsq.next))
- return;
- do {
- dequeue_rx(card, card->rsq.next);
- ns_rsqe_init(card->rsq.next);
- previous = card->rsq.next;
- if (card->rsq.next == card->rsq.last)
- card->rsq.next = card->rsq.base;
- else
- card->rsq.next++;
- } while (ns_rsqe_valid(card->rsq.next));
- writel((((u32) previous) - ((u32) card->rsq.base)),
- card->membase + RSQH);
+ ns_rsqe *previous;
+
+ if (!ns_rsqe_valid(card->rsq.next))
+ return;
+ do {
+ dequeue_rx(card, card->rsq.next);
+ ns_rsqe_init(card->rsq.next);
+ previous = card->rsq.next;
+ if (card->rsq.next == card->rsq.last)
+ card->rsq.next = card->rsq.base;
+ else
+ card->rsq.next++;
+ } while (ns_rsqe_valid(card->rsq.next));
+ writel(PTR_DIFF(previous, card->rsq.base), card->membase + RSQH);
}
+static void dequeue_rx(ns_dev * card, ns_rsqe * rsqe)
+{
+ u32 vpi, vci;
+ vc_map *vc;
+ struct sk_buff *iovb;
+ struct iovec *iov;
+ struct atm_vcc *vcc;
+ struct sk_buff *skb;
+ unsigned short aal5_len;
+ int len;
+ u32 stat;
+ u32 id;
+
+ stat = readl(card->membase + STAT);
+ card->sbfqc = ns_stat_sfbqc_get(stat);
+ card->lbfqc = ns_stat_lfbqc_get(stat);
+
+ id = le32_to_cpu(rsqe->buffer_handle);
+ skb = idr_find(&card->idr, id);
+ if (!skb) {
+ RXPRINTK(KERN_ERR
+ "nicstar%d: idr_find() failed!\n", card->index);
+ return;
+ }
+ idr_remove(&card->idr, id);
+ pci_dma_sync_single_for_cpu(card->pcidev,
+ NS_PRV_DMA(skb),
+ (NS_PRV_BUFTYPE(skb) == BUF_SM
+ ? NS_SMSKBSIZE : NS_LGSKBSIZE),
+ PCI_DMA_FROMDEVICE);
+ pci_unmap_single(card->pcidev,
+ NS_PRV_DMA(skb),
+ (NS_PRV_BUFTYPE(skb) == BUF_SM
+ ? NS_SMSKBSIZE : NS_LGSKBSIZE),
+ PCI_DMA_FROMDEVICE);
+ vpi = ns_rsqe_vpi(rsqe);
+ vci = ns_rsqe_vci(rsqe);
+ if (vpi >= 1UL << card->vpibits || vci >= 1UL << card->vcibits) {
+ printk("nicstar%d: SDU received for out-of-range vc %d.%d.\n",
+ card->index, vpi, vci);
+ recycle_rx_buf(card, skb);
+ return;
+ }
+
+ vc = &(card->vcmap[vpi << card->vcibits | vci]);
+ if (!vc->rx) {
+ RXPRINTK("nicstar%d: SDU received on non-rx vc %d.%d.\n",
+ card->index, vpi, vci);
+ recycle_rx_buf(card, skb);
+ return;
+ }
+
+ vcc = vc->rx_vcc;
+
+ if (vcc->qos.aal == ATM_AAL0) {
+ struct sk_buff *sb;
+ unsigned char *cell;
+ int i;
+
+ cell = skb->data;
+ for (i = ns_rsqe_cellcount(rsqe); i; i--) {
+ if ((sb = dev_alloc_skb(NS_SMSKBSIZE)) == NULL) {
+ printk
+ ("nicstar%d: Can't allocate buffers for aal0.\n",
+ card->index);
+ atomic_add(i, &vcc->stats->rx_drop);
+ break;
+ }
+ if (!atm_charge(vcc, sb->truesize)) {
+ RXPRINTK
+ ("nicstar%d: atm_charge() dropped aal0 packets.\n",
+ card->index);
+ atomic_add(i - 1, &vcc->stats->rx_drop); /* already increased by 1 */
+ dev_kfree_skb_any(sb);
+ break;
+ }
+ /* Rebuild the header */
+ *((u32 *) sb->data) = le32_to_cpu(rsqe->word_1) << 4 |
+ (ns_rsqe_clp(rsqe) ? 0x00000001 : 0x00000000);
+ if (i == 1 && ns_rsqe_eopdu(rsqe))
+ *((u32 *) sb->data) |= 0x00000002;
+ skb_put(sb, NS_AAL0_HEADER);
+ memcpy(skb_tail_pointer(sb), cell, ATM_CELL_PAYLOAD);
+ skb_put(sb, ATM_CELL_PAYLOAD);
+ ATM_SKB(sb)->vcc = vcc;
+ __net_timestamp(sb);
+ vcc->push(vcc, sb);
+ atomic_inc(&vcc->stats->rx);
+ cell += ATM_CELL_PAYLOAD;
+ }
+
+ recycle_rx_buf(card, skb);
+ return;
+ }
+
+ /* To reach this point, the AAL layer can only be AAL5 */
+
+ if ((iovb = vc->rx_iov) == NULL) {
+ iovb = skb_dequeue(&(card->iovpool.queue));
+ if (iovb == NULL) { /* No buffers in the queue */
+ iovb = alloc_skb(NS_IOVBUFSIZE, GFP_ATOMIC);
+ if (iovb == NULL) {
+ printk("nicstar%d: Out of iovec buffers.\n",
+ card->index);
+ atomic_inc(&vcc->stats->rx_drop);
+ recycle_rx_buf(card, skb);
+ return;
+ }
+ NS_PRV_BUFTYPE(iovb) = BUF_NONE;
+ } else if (--card->iovpool.count < card->iovnr.min) {
+ struct sk_buff *new_iovb;
+ if ((new_iovb =
+ alloc_skb(NS_IOVBUFSIZE, GFP_ATOMIC)) != NULL) {
+ NS_PRV_BUFTYPE(iovb) = BUF_NONE;
+ skb_queue_tail(&card->iovpool.queue, new_iovb);
+ card->iovpool.count++;
+ }
+ }
+ vc->rx_iov = iovb;
+ NS_PRV_IOVCNT(iovb) = 0;
+ iovb->len = 0;
+ iovb->data = iovb->head;
+ skb_reset_tail_pointer(iovb);
+ /* IMPORTANT: a pointer to the sk_buff containing the small or large
+ buffer is stored as iovec base, NOT a pointer to the
+ small or large buffer itself. */
+ } else if (NS_PRV_IOVCNT(iovb) >= NS_MAX_IOVECS) {
+ printk("nicstar%d: received too big AAL5 SDU.\n", card->index);
+ atomic_inc(&vcc->stats->rx_err);
+ recycle_iovec_rx_bufs(card, (struct iovec *)iovb->data,
+ NS_MAX_IOVECS);
+ NS_PRV_IOVCNT(iovb) = 0;
+ iovb->len = 0;
+ iovb->data = iovb->head;
+ skb_reset_tail_pointer(iovb);
+ }
+ iov = &((struct iovec *)iovb->data)[NS_PRV_IOVCNT(iovb)++];
+ iov->iov_base = (void *)skb;
+ iov->iov_len = ns_rsqe_cellcount(rsqe) * 48;
+ iovb->len += iov->iov_len;
+#ifdef EXTRA_DEBUG
+ if (NS_PRV_IOVCNT(iovb) == 1) {
+ if (NS_PRV_BUFTYPE(skb) != BUF_SM) {
+ printk
+ ("nicstar%d: Expected a small buffer, and this is not one.\n",
+ card->index);
+ which_list(card, skb);
+ atomic_inc(&vcc->stats->rx_err);
+ recycle_rx_buf(card, skb);
+ vc->rx_iov = NULL;
+ recycle_iov_buf(card, iovb);
+ return;
+ }
+ } else { /* NS_PRV_IOVCNT(iovb) >= 2 */
+
+ if (NS_PRV_BUFTYPE(skb) != BUF_LG) {
+ printk
+ ("nicstar%d: Expected a large buffer, and this is not one.\n",
+ card->index);
+ which_list(card, skb);
+ atomic_inc(&vcc->stats->rx_err);
+ recycle_iovec_rx_bufs(card, (struct iovec *)iovb->data,
+ NS_PRV_IOVCNT(iovb));
+ vc->rx_iov = NULL;
+ recycle_iov_buf(card, iovb);
+ return;
+ }
+ }
+#endif /* EXTRA_DEBUG */
-static void dequeue_rx(ns_dev *card, ns_rsqe *rsqe)
-{
- u32 vpi, vci;
- vc_map *vc;
- struct sk_buff *iovb;
- struct iovec *iov;
- struct atm_vcc *vcc;
- struct sk_buff *skb;
- unsigned short aal5_len;
- int len;
- u32 stat;
-
- stat = readl(card->membase + STAT);
- card->sbfqc = ns_stat_sfbqc_get(stat);
- card->lbfqc = ns_stat_lfbqc_get(stat);
-
- skb = (struct sk_buff *) le32_to_cpu(rsqe->buffer_handle);
- vpi = ns_rsqe_vpi(rsqe);
- vci = ns_rsqe_vci(rsqe);
- if (vpi >= 1UL << card->vpibits || vci >= 1UL << card->vcibits)
- {
- printk("nicstar%d: SDU received for out-of-range vc %d.%d.\n",
- card->index, vpi, vci);
- recycle_rx_buf(card, skb);
- return;
- }
-
- vc = &(card->vcmap[vpi << card->vcibits | vci]);
- if (!vc->rx)
- {
- RXPRINTK("nicstar%d: SDU received on non-rx vc %d.%d.\n",
- card->index, vpi, vci);
- recycle_rx_buf(card, skb);
- return;
- }
-
- vcc = vc->rx_vcc;
-
- if (vcc->qos.aal == ATM_AAL0)
- {
- struct sk_buff *sb;
- unsigned char *cell;
- int i;
-
- cell = skb->data;
- for (i = ns_rsqe_cellcount(rsqe); i; i--)
- {
- if ((sb = dev_alloc_skb(NS_SMSKBSIZE)) == NULL)
- {
- printk("nicstar%d: Can't allocate buffers for aal0.\n",
- card->index);
- atomic_add(i,&vcc->stats->rx_drop);
- break;
- }
- if (!atm_charge(vcc, sb->truesize))
- {
- RXPRINTK("nicstar%d: atm_charge() dropped aal0 packets.\n",
- card->index);
- atomic_add(i-1,&vcc->stats->rx_drop); /* already increased by 1 */
- dev_kfree_skb_any(sb);
- break;
- }
- /* Rebuild the header */
- *((u32 *) sb->data) = le32_to_cpu(rsqe->word_1) << 4 |
- (ns_rsqe_clp(rsqe) ? 0x00000001 : 0x00000000);
- if (i == 1 && ns_rsqe_eopdu(rsqe))
- *((u32 *) sb->data) |= 0x00000002;
- skb_put(sb, NS_AAL0_HEADER);
- memcpy(skb_tail_pointer(sb), cell, ATM_CELL_PAYLOAD);
- skb_put(sb, ATM_CELL_PAYLOAD);
- ATM_SKB(sb)->vcc = vcc;
- __net_timestamp(sb);
- vcc->push(vcc, sb);
- atomic_inc(&vcc->stats->rx);
- cell += ATM_CELL_PAYLOAD;
- }
-
- recycle_rx_buf(card, skb);
- return;
- }
-
- /* To reach this point, the AAL layer can only be AAL5 */
-
- if ((iovb = vc->rx_iov) == NULL)
- {
- iovb = skb_dequeue(&(card->iovpool.queue));
- if (iovb == NULL) /* No buffers in the queue */
- {
- iovb = alloc_skb(NS_IOVBUFSIZE, GFP_ATOMIC);
- if (iovb == NULL)
- {
- printk("nicstar%d: Out of iovec buffers.\n", card->index);
- atomic_inc(&vcc->stats->rx_drop);
- recycle_rx_buf(card, skb);
- return;
- }
- NS_SKB_CB(iovb)->buf_type = BUF_NONE;
- }
- else
- if (--card->iovpool.count < card->iovnr.min)
- {
- struct sk_buff *new_iovb;
- if ((new_iovb = alloc_skb(NS_IOVBUFSIZE, GFP_ATOMIC)) != NULL)
- {
- NS_SKB_CB(iovb)->buf_type = BUF_NONE;
- skb_queue_tail(&card->iovpool.queue, new_iovb);
- card->iovpool.count++;
- }
- }
- vc->rx_iov = iovb;
- NS_SKB(iovb)->iovcnt = 0;
- iovb->len = 0;
- iovb->data = iovb->head;
- skb_reset_tail_pointer(iovb);
- NS_SKB(iovb)->vcc = vcc;
- /* IMPORTANT: a pointer to the sk_buff containing the small or large
- buffer is stored as iovec base, NOT a pointer to the
- small or large buffer itself. */
- }
- else if (NS_SKB(iovb)->iovcnt >= NS_MAX_IOVECS)
- {
- printk("nicstar%d: received too big AAL5 SDU.\n", card->index);
- atomic_inc(&vcc->stats->rx_err);
- recycle_iovec_rx_bufs(card, (struct iovec *) iovb->data, NS_MAX_IOVECS);
- NS_SKB(iovb)->iovcnt = 0;
- iovb->len = 0;
- iovb->data = iovb->head;
- skb_reset_tail_pointer(iovb);
- NS_SKB(iovb)->vcc = vcc;
- }
- iov = &((struct iovec *) iovb->data)[NS_SKB(iovb)->iovcnt++];
- iov->iov_base = (void *) skb;
- iov->iov_len = ns_rsqe_cellcount(rsqe) * 48;
- iovb->len += iov->iov_len;
-
- if (NS_SKB(iovb)->iovcnt == 1)
- {
- if (NS_SKB_CB(skb)->buf_type != BUF_SM)
- {
- printk("nicstar%d: Expected a small buffer, and this is not one.\n",
- card->index);
- which_list(card, skb);
- atomic_inc(&vcc->stats->rx_err);
- recycle_rx_buf(card, skb);
- vc->rx_iov = NULL;
- recycle_iov_buf(card, iovb);
- return;
- }
- }
- else /* NS_SKB(iovb)->iovcnt >= 2 */
- {
- if (NS_SKB_CB(skb)->buf_type != BUF_LG)
- {
- printk("nicstar%d: Expected a large buffer, and this is not one.\n",
- card->index);
- which_list(card, skb);
- atomic_inc(&vcc->stats->rx_err);
- recycle_iovec_rx_bufs(card, (struct iovec *) iovb->data,
- NS_SKB(iovb)->iovcnt);
- vc->rx_iov = NULL;
- recycle_iov_buf(card, iovb);
- return;
- }
- }
-
- if (ns_rsqe_eopdu(rsqe))
- {
- /* This works correctly regardless of the endianness of the host */
- unsigned char *L1L2 = (unsigned char *)((u32)skb->data +
- iov->iov_len - 6);
- aal5_len = L1L2[0] << 8 | L1L2[1];
- len = (aal5_len == 0x0000) ? 0x10000 : aal5_len;
- if (ns_rsqe_crcerr(rsqe) ||
- len + 8 > iovb->len || len + (47 + 8) < iovb->len)
- {
- printk("nicstar%d: AAL5 CRC error", card->index);
- if (len + 8 > iovb->len || len + (47 + 8) < iovb->len)
- printk(" - PDU size mismatch.\n");
- else
- printk(".\n");
- atomic_inc(&vcc->stats->rx_err);
- recycle_iovec_rx_bufs(card, (struct iovec *) iovb->data,
- NS_SKB(iovb)->iovcnt);
- vc->rx_iov = NULL;
- recycle_iov_buf(card, iovb);
- return;
- }
-
- /* By this point we (hopefully) have a complete SDU without errors. */
-
- if (NS_SKB(iovb)->iovcnt == 1) /* Just a small buffer */
- {
- /* skb points to a small buffer */
- if (!atm_charge(vcc, skb->truesize))
- {
- push_rxbufs(card, skb);
- atomic_inc(&vcc->stats->rx_drop);
- }
- else
- {
- skb_put(skb, len);
- dequeue_sm_buf(card, skb);
+ if (ns_rsqe_eopdu(rsqe)) {
+ /* This works correctly regardless of the endianness of the host */
+ unsigned char *L1L2 = (unsigned char *)
+ (skb->data + iov->iov_len - 6);
+ aal5_len = L1L2[0] << 8 | L1L2[1];
+ len = (aal5_len == 0x0000) ? 0x10000 : aal5_len;
+ if (ns_rsqe_crcerr(rsqe) ||
+ len + 8 > iovb->len || len + (47 + 8) < iovb->len) {
+ printk("nicstar%d: AAL5 CRC error", card->index);
+ if (len + 8 > iovb->len || len + (47 + 8) < iovb->len)
+ printk(" - PDU size mismatch.\n");
+ else
+ printk(".\n");
+ atomic_inc(&vcc->stats->rx_err);
+ recycle_iovec_rx_bufs(card, (struct iovec *)iovb->data,
+ NS_PRV_IOVCNT(iovb));
+ vc->rx_iov = NULL;
+ recycle_iov_buf(card, iovb);
+ return;
+ }
+
+ /* By this point we (hopefully) have a complete SDU without errors. */
+
+ if (NS_PRV_IOVCNT(iovb) == 1) { /* Just a small buffer */
+ /* skb points to a small buffer */
+ if (!atm_charge(vcc, skb->truesize)) {
+ push_rxbufs(card, skb);
+ atomic_inc(&vcc->stats->rx_drop);
+ } else {
+ skb_put(skb, len);
+ dequeue_sm_buf(card, skb);
#ifdef NS_USE_DESTRUCTORS
- skb->destructor = ns_sb_destructor;
+ skb->destructor = ns_sb_destructor;
#endif /* NS_USE_DESTRUCTORS */
- ATM_SKB(skb)->vcc = vcc;
- __net_timestamp(skb);
- vcc->push(vcc, skb);
- atomic_inc(&vcc->stats->rx);
- }
- }
- else if (NS_SKB(iovb)->iovcnt == 2) /* One small plus one large buffer */
- {
- struct sk_buff *sb;
-
- sb = (struct sk_buff *) (iov - 1)->iov_base;
- /* skb points to a large buffer */
-
- if (len <= NS_SMBUFSIZE)
- {
- if (!atm_charge(vcc, sb->truesize))
- {
- push_rxbufs(card, sb);
- atomic_inc(&vcc->stats->rx_drop);
- }
- else
- {
- skb_put(sb, len);
- dequeue_sm_buf(card, sb);
+ ATM_SKB(skb)->vcc = vcc;
+ __net_timestamp(skb);
+ vcc->push(vcc, skb);
+ atomic_inc(&vcc->stats->rx);
+ }
+ } else if (NS_PRV_IOVCNT(iovb) == 2) { /* One small plus one large buffer */
+ struct sk_buff *sb;
+
+ sb = (struct sk_buff *)(iov - 1)->iov_base;
+ /* skb points to a large buffer */
+
+ if (len <= NS_SMBUFSIZE) {
+ if (!atm_charge(vcc, sb->truesize)) {
+ push_rxbufs(card, sb);
+ atomic_inc(&vcc->stats->rx_drop);
+ } else {
+ skb_put(sb, len);
+ dequeue_sm_buf(card, sb);
#ifdef NS_USE_DESTRUCTORS
- sb->destructor = ns_sb_destructor;
+ sb->destructor = ns_sb_destructor;
#endif /* NS_USE_DESTRUCTORS */
- ATM_SKB(sb)->vcc = vcc;
- __net_timestamp(sb);
- vcc->push(vcc, sb);
- atomic_inc(&vcc->stats->rx);
- }
-
- push_rxbufs(card, skb);
-
- }
- else /* len > NS_SMBUFSIZE, the usual case */
- {
- if (!atm_charge(vcc, skb->truesize))
- {
- push_rxbufs(card, skb);
- atomic_inc(&vcc->stats->rx_drop);
- }
- else
- {
- dequeue_lg_buf(card, skb);
+ ATM_SKB(sb)->vcc = vcc;
+ __net_timestamp(sb);
+ vcc->push(vcc, sb);
+ atomic_inc(&vcc->stats->rx);
+ }
+
+ push_rxbufs(card, skb);
+
+ } else { /* len > NS_SMBUFSIZE, the usual case */
+
+ if (!atm_charge(vcc, skb->truesize)) {
+ push_rxbufs(card, skb);
+ atomic_inc(&vcc->stats->rx_drop);
+ } else {
+ dequeue_lg_buf(card, skb);
#ifdef NS_USE_DESTRUCTORS
- skb->destructor = ns_lb_destructor;
+ skb->destructor = ns_lb_destructor;
#endif /* NS_USE_DESTRUCTORS */
- skb_push(skb, NS_SMBUFSIZE);
- skb_copy_from_linear_data(sb, skb->data, NS_SMBUFSIZE);
- skb_put(skb, len - NS_SMBUFSIZE);
- ATM_SKB(skb)->vcc = vcc;
- __net_timestamp(skb);
- vcc->push(vcc, skb);
- atomic_inc(&vcc->stats->rx);
- }
-
- push_rxbufs(card, sb);
-
- }
-
- }
- else /* Must push a huge buffer */
- {
- struct sk_buff *hb, *sb, *lb;
- int remaining, tocopy;
- int j;
-
- hb = skb_dequeue(&(card->hbpool.queue));
- if (hb == NULL) /* No buffers in the queue */
- {
-
- hb = dev_alloc_skb(NS_HBUFSIZE);
- if (hb == NULL)
- {
- printk("nicstar%d: Out of huge buffers.\n", card->index);
- atomic_inc(&vcc->stats->rx_drop);
- recycle_iovec_rx_bufs(card, (struct iovec *) iovb->data,
- NS_SKB(iovb)->iovcnt);
- vc->rx_iov = NULL;
- recycle_iov_buf(card, iovb);
- return;
- }
- else if (card->hbpool.count < card->hbnr.min)
- {
- struct sk_buff *new_hb;
- if ((new_hb = dev_alloc_skb(NS_HBUFSIZE)) != NULL)
- {
- skb_queue_tail(&card->hbpool.queue, new_hb);
- card->hbpool.count++;
- }
- }
- NS_SKB_CB(hb)->buf_type = BUF_NONE;
- }
- else
- if (--card->hbpool.count < card->hbnr.min)
- {
- struct sk_buff *new_hb;
- if ((new_hb = dev_alloc_skb(NS_HBUFSIZE)) != NULL)
- {
- NS_SKB_CB(new_hb)->buf_type = BUF_NONE;
- skb_queue_tail(&card->hbpool.queue, new_hb);
- card->hbpool.count++;
- }
- if (card->hbpool.count < card->hbnr.min)
- {
- if ((new_hb = dev_alloc_skb(NS_HBUFSIZE)) != NULL)
- {
- NS_SKB_CB(new_hb)->buf_type = BUF_NONE;
- skb_queue_tail(&card->hbpool.queue, new_hb);
- card->hbpool.count++;
- }
- }
- }
-
- iov = (struct iovec *) iovb->data;
-
- if (!atm_charge(vcc, hb->truesize))
- {
- recycle_iovec_rx_bufs(card, iov, NS_SKB(iovb)->iovcnt);
- if (card->hbpool.count < card->hbnr.max)
- {
- skb_queue_tail(&card->hbpool.queue, hb);
- card->hbpool.count++;
- }
- else
- dev_kfree_skb_any(hb);
- atomic_inc(&vcc->stats->rx_drop);
- }
- else
- {
- /* Copy the small buffer to the huge buffer */
- sb = (struct sk_buff *) iov->iov_base;
- skb_copy_from_linear_data(sb, hb->data, iov->iov_len);
- skb_put(hb, iov->iov_len);
- remaining = len - iov->iov_len;
- iov++;
- /* Free the small buffer */
- push_rxbufs(card, sb);
-
- /* Copy all large buffers to the huge buffer and free them */
- for (j = 1; j < NS_SKB(iovb)->iovcnt; j++)
- {
- lb = (struct sk_buff *) iov->iov_base;
- tocopy = min_t(int, remaining, iov->iov_len);
- skb_copy_from_linear_data(lb, skb_tail_pointer(hb), tocopy);
- skb_put(hb, tocopy);
- iov++;
- remaining -= tocopy;
- push_rxbufs(card, lb);
- }
+ skb_push(skb, NS_SMBUFSIZE);
+ skb_copy_from_linear_data(sb, skb->data,
+ NS_SMBUFSIZE);
+ skb_put(skb, len - NS_SMBUFSIZE);
+ ATM_SKB(skb)->vcc = vcc;
+ __net_timestamp(skb);
+ vcc->push(vcc, skb);
+ atomic_inc(&vcc->stats->rx);
+ }
+
+ push_rxbufs(card, sb);
+
+ }
+
+ } else { /* Must push a huge buffer */
+
+ struct sk_buff *hb, *sb, *lb;
+ int remaining, tocopy;
+ int j;
+
+ hb = skb_dequeue(&(card->hbpool.queue));
+ if (hb == NULL) { /* No buffers in the queue */
+
+ hb = dev_alloc_skb(NS_HBUFSIZE);
+ if (hb == NULL) {
+ printk
+ ("nicstar%d: Out of huge buffers.\n",
+ card->index);
+ atomic_inc(&vcc->stats->rx_drop);
+ recycle_iovec_rx_bufs(card,
+ (struct iovec *)
+ iovb->data,
+ NS_PRV_IOVCNT(iovb));
+ vc->rx_iov = NULL;
+ recycle_iov_buf(card, iovb);
+ return;
+ } else if (card->hbpool.count < card->hbnr.min) {
+ struct sk_buff *new_hb;
+ if ((new_hb =
+ dev_alloc_skb(NS_HBUFSIZE)) !=
+ NULL) {
+ skb_queue_tail(&card->hbpool.
+ queue, new_hb);
+ card->hbpool.count++;
+ }
+ }
+ NS_PRV_BUFTYPE(hb) = BUF_NONE;
+ } else if (--card->hbpool.count < card->hbnr.min) {
+ struct sk_buff *new_hb;
+ if ((new_hb =
+ dev_alloc_skb(NS_HBUFSIZE)) != NULL) {
+ NS_PRV_BUFTYPE(new_hb) = BUF_NONE;
+ skb_queue_tail(&card->hbpool.queue,
+ new_hb);
+ card->hbpool.count++;
+ }
+ if (card->hbpool.count < card->hbnr.min) {
+ if ((new_hb =
+ dev_alloc_skb(NS_HBUFSIZE)) !=
+ NULL) {
+ NS_PRV_BUFTYPE(new_hb) =
+ BUF_NONE;
+ skb_queue_tail(&card->hbpool.
+ queue, new_hb);
+ card->hbpool.count++;
+ }
+ }
+ }
+
+ iov = (struct iovec *)iovb->data;
+
+ if (!atm_charge(vcc, hb->truesize)) {
+ recycle_iovec_rx_bufs(card, iov,
+ NS_PRV_IOVCNT(iovb));
+ if (card->hbpool.count < card->hbnr.max) {
+ skb_queue_tail(&card->hbpool.queue, hb);
+ card->hbpool.count++;
+ } else
+ dev_kfree_skb_any(hb);
+ atomic_inc(&vcc->stats->rx_drop);
+ } else {
+ /* Copy the small buffer to the huge buffer */
+ sb = (struct sk_buff *)iov->iov_base;
+ skb_copy_from_linear_data(sb, hb->data,
+ iov->iov_len);
+ skb_put(hb, iov->iov_len);
+ remaining = len - iov->iov_len;
+ iov++;
+ /* Free the small buffer */
+ push_rxbufs(card, sb);
+
+ /* Copy all large buffers to the huge buffer and free them */
+ for (j = 1; j < NS_PRV_IOVCNT(iovb); j++) {
+ lb = (struct sk_buff *)iov->iov_base;
+ tocopy =
+ min_t(int, remaining, iov->iov_len);
+ skb_copy_from_linear_data(lb,
+ skb_tail_pointer
+ (hb), tocopy);
+ skb_put(hb, tocopy);
+ iov++;
+ remaining -= tocopy;
+ push_rxbufs(card, lb);
+ }
#ifdef EXTRA_DEBUG
- if (remaining != 0 || hb->len != len)
- printk("nicstar%d: Huge buffer len mismatch.\n", card->index);
+ if (remaining != 0 || hb->len != len)
+ printk
+ ("nicstar%d: Huge buffer len mismatch.\n",
+ card->index);
#endif /* EXTRA_DEBUG */
- ATM_SKB(hb)->vcc = vcc;
+ ATM_SKB(hb)->vcc = vcc;
#ifdef NS_USE_DESTRUCTORS
- hb->destructor = ns_hb_destructor;
+ hb->destructor = ns_hb_destructor;
#endif /* NS_USE_DESTRUCTORS */
- __net_timestamp(hb);
- vcc->push(vcc, hb);
- atomic_inc(&vcc->stats->rx);
- }
- }
+ __net_timestamp(hb);
+ vcc->push(vcc, hb);
+ atomic_inc(&vcc->stats->rx);
+ }
+ }
- vc->rx_iov = NULL;
- recycle_iov_buf(card, iovb);
- }
+ vc->rx_iov = NULL;
+ recycle_iov_buf(card, iovb);
+ }
}
-
-
#ifdef NS_USE_DESTRUCTORS
static void ns_sb_destructor(struct sk_buff *sb)
{
- ns_dev *card;
- u32 stat;
-
- card = (ns_dev *) ATM_SKB(sb)->vcc->dev->dev_data;
- stat = readl(card->membase + STAT);
- card->sbfqc = ns_stat_sfbqc_get(stat);
- card->lbfqc = ns_stat_lfbqc_get(stat);
-
- do
- {
- sb = __dev_alloc_skb(NS_SMSKBSIZE, GFP_KERNEL);
- if (sb == NULL)
- break;
- NS_SKB_CB(sb)->buf_type = BUF_SM;
- skb_queue_tail(&card->sbpool.queue, sb);
- skb_reserve(sb, NS_AAL0_HEADER);
- push_rxbufs(card, sb);
- } while (card->sbfqc < card->sbnr.min);
+ ns_dev *card;
+ u32 stat;
+
+ card = (ns_dev *) ATM_SKB(sb)->vcc->dev->dev_data;
+ stat = readl(card->membase + STAT);
+ card->sbfqc = ns_stat_sfbqc_get(stat);
+ card->lbfqc = ns_stat_lfbqc_get(stat);
+
+ do {
+ sb = __dev_alloc_skb(NS_SMSKBSIZE, GFP_KERNEL);
+ if (sb == NULL)
+ break;
+ NS_PRV_BUFTYPE(sb) = BUF_SM;
+ skb_queue_tail(&card->sbpool.queue, sb);
+ skb_reserve(sb, NS_AAL0_HEADER);
+ push_rxbufs(card, sb);
+ } while (card->sbfqc < card->sbnr.min);
}
-
-
static void ns_lb_destructor(struct sk_buff *lb)
{
- ns_dev *card;
- u32 stat;
-
- card = (ns_dev *) ATM_SKB(lb)->vcc->dev->dev_data;
- stat = readl(card->membase + STAT);
- card->sbfqc = ns_stat_sfbqc_get(stat);
- card->lbfqc = ns_stat_lfbqc_get(stat);
-
- do
- {
- lb = __dev_alloc_skb(NS_LGSKBSIZE, GFP_KERNEL);
- if (lb == NULL)
- break;
- NS_SKB_CB(lb)->buf_type = BUF_LG;
- skb_queue_tail(&card->lbpool.queue, lb);
- skb_reserve(lb, NS_SMBUFSIZE);
- push_rxbufs(card, lb);
- } while (card->lbfqc < card->lbnr.min);
+ ns_dev *card;
+ u32 stat;
+
+ card = (ns_dev *) ATM_SKB(lb)->vcc->dev->dev_data;
+ stat = readl(card->membase + STAT);
+ card->sbfqc = ns_stat_sfbqc_get(stat);
+ card->lbfqc = ns_stat_lfbqc_get(stat);
+
+ do {
+ lb = __dev_alloc_skb(NS_LGSKBSIZE, GFP_KERNEL);
+ if (lb == NULL)
+ break;
+ NS_PRV_BUFTYPE(lb) = BUF_LG;
+ skb_queue_tail(&card->lbpool.queue, lb);
+ skb_reserve(lb, NS_SMBUFSIZE);
+ push_rxbufs(card, lb);
+ } while (card->lbfqc < card->lbnr.min);
}
-
-
static void ns_hb_destructor(struct sk_buff *hb)
{
- ns_dev *card;
-
- card = (ns_dev *) ATM_SKB(hb)->vcc->dev->dev_data;
-
- while (card->hbpool.count < card->hbnr.init)
- {
- hb = __dev_alloc_skb(NS_HBUFSIZE, GFP_KERNEL);
- if (hb == NULL)
- break;
- NS_SKB_CB(hb)->buf_type = BUF_NONE;
- skb_queue_tail(&card->hbpool.queue, hb);
- card->hbpool.count++;
- }
+ ns_dev *card;
+
+ card = (ns_dev *) ATM_SKB(hb)->vcc->dev->dev_data;
+
+ while (card->hbpool.count < card->hbnr.init) {
+ hb = __dev_alloc_skb(NS_HBUFSIZE, GFP_KERNEL);
+ if (hb == NULL)
+ break;
+ NS_PRV_BUFTYPE(hb) = BUF_NONE;
+ skb_queue_tail(&card->hbpool.queue, hb);
+ card->hbpool.count++;
+ }
}
#endif /* NS_USE_DESTRUCTORS */
-
-static void recycle_rx_buf(ns_dev *card, struct sk_buff *skb)
+static void recycle_rx_buf(ns_dev * card, struct sk_buff *skb)
{
- struct ns_skb_cb *cb = NS_SKB_CB(skb);
-
- if (unlikely(cb->buf_type == BUF_NONE)) {
- printk("nicstar%d: What kind of rx buffer is this?\n", card->index);
+ if (unlikely(NS_PRV_BUFTYPE(skb) == BUF_NONE)) {
+ printk("nicstar%d: What kind of rx buffer is this?\n",
+ card->index);
dev_kfree_skb_any(skb);
} else
push_rxbufs(card, skb);
}
-
-static void recycle_iovec_rx_bufs(ns_dev *card, struct iovec *iov, int count)
+static void recycle_iovec_rx_bufs(ns_dev * card, struct iovec *iov, int count)
{
while (count-- > 0)
- recycle_rx_buf(card, (struct sk_buff *) (iov++)->iov_base);
+ recycle_rx_buf(card, (struct sk_buff *)(iov++)->iov_base);
}
-
-static void recycle_iov_buf(ns_dev *card, struct sk_buff *iovb)
+static void recycle_iov_buf(ns_dev * card, struct sk_buff *iovb)
{
- if (card->iovpool.count < card->iovnr.max)
- {
- skb_queue_tail(&card->iovpool.queue, iovb);
- card->iovpool.count++;
- }
- else
- dev_kfree_skb_any(iovb);
+ if (card->iovpool.count < card->iovnr.max) {
+ skb_queue_tail(&card->iovpool.queue, iovb);
+ card->iovpool.count++;
+ } else
+ dev_kfree_skb_any(iovb);
}
-
-
-static void dequeue_sm_buf(ns_dev *card, struct sk_buff *sb)
+static void dequeue_sm_buf(ns_dev * card, struct sk_buff *sb)
{
- skb_unlink(sb, &card->sbpool.queue);
+ skb_unlink(sb, &card->sbpool.queue);
#ifdef NS_USE_DESTRUCTORS
- if (card->sbfqc < card->sbnr.min)
+ if (card->sbfqc < card->sbnr.min)
#else
- if (card->sbfqc < card->sbnr.init)
- {
- struct sk_buff *new_sb;
- if ((new_sb = dev_alloc_skb(NS_SMSKBSIZE)) != NULL)
- {
- NS_SKB_CB(new_sb)->buf_type = BUF_SM;
- skb_queue_tail(&card->sbpool.queue, new_sb);
- skb_reserve(new_sb, NS_AAL0_HEADER);
- push_rxbufs(card, new_sb);
- }
- }
- if (card->sbfqc < card->sbnr.init)
+ if (card->sbfqc < card->sbnr.init) {
+ struct sk_buff *new_sb;
+ if ((new_sb = dev_alloc_skb(NS_SMSKBSIZE)) != NULL) {
+ NS_PRV_BUFTYPE(new_sb) = BUF_SM;
+ skb_queue_tail(&card->sbpool.queue, new_sb);
+ skb_reserve(new_sb, NS_AAL0_HEADER);
+ push_rxbufs(card, new_sb);
+ }
+ }
+ if (card->sbfqc < card->sbnr.init)
#endif /* NS_USE_DESTRUCTORS */
- {
- struct sk_buff *new_sb;
- if ((new_sb = dev_alloc_skb(NS_SMSKBSIZE)) != NULL)
- {
- NS_SKB_CB(new_sb)->buf_type = BUF_SM;
- skb_queue_tail(&card->sbpool.queue, new_sb);
- skb_reserve(new_sb, NS_AAL0_HEADER);
- push_rxbufs(card, new_sb);
- }
- }
+ {
+ struct sk_buff *new_sb;
+ if ((new_sb = dev_alloc_skb(NS_SMSKBSIZE)) != NULL) {
+ NS_PRV_BUFTYPE(new_sb) = BUF_SM;
+ skb_queue_tail(&card->sbpool.queue, new_sb);
+ skb_reserve(new_sb, NS_AAL0_HEADER);
+ push_rxbufs(card, new_sb);
+ }
+ }
}
-
-
-static void dequeue_lg_buf(ns_dev *card, struct sk_buff *lb)
+static void dequeue_lg_buf(ns_dev * card, struct sk_buff *lb)
{
- skb_unlink(lb, &card->lbpool.queue);
+ skb_unlink(lb, &card->lbpool.queue);
#ifdef NS_USE_DESTRUCTORS
- if (card->lbfqc < card->lbnr.min)
+ if (card->lbfqc < card->lbnr.min)
#else
- if (card->lbfqc < card->lbnr.init)
- {
- struct sk_buff *new_lb;
- if ((new_lb = dev_alloc_skb(NS_LGSKBSIZE)) != NULL)
- {
- NS_SKB_CB(new_lb)->buf_type = BUF_LG;
- skb_queue_tail(&card->lbpool.queue, new_lb);
- skb_reserve(new_lb, NS_SMBUFSIZE);
- push_rxbufs(card, new_lb);
- }
- }
- if (card->lbfqc < card->lbnr.init)
+ if (card->lbfqc < card->lbnr.init) {
+ struct sk_buff *new_lb;
+ if ((new_lb = dev_alloc_skb(NS_LGSKBSIZE)) != NULL) {
+ NS_PRV_BUFTYPE(new_lb) = BUF_LG;
+ skb_queue_tail(&card->lbpool.queue, new_lb);
+ skb_reserve(new_lb, NS_SMBUFSIZE);
+ push_rxbufs(card, new_lb);
+ }
+ }
+ if (card->lbfqc < card->lbnr.init)
#endif /* NS_USE_DESTRUCTORS */
- {
- struct sk_buff *new_lb;
- if ((new_lb = dev_alloc_skb(NS_LGSKBSIZE)) != NULL)
- {
- NS_SKB_CB(new_lb)->buf_type = BUF_LG;
- skb_queue_tail(&card->lbpool.queue, new_lb);
- skb_reserve(new_lb, NS_SMBUFSIZE);
- push_rxbufs(card, new_lb);
- }
- }
+ {
+ struct sk_buff *new_lb;
+ if ((new_lb = dev_alloc_skb(NS_LGSKBSIZE)) != NULL) {
+ NS_PRV_BUFTYPE(new_lb) = BUF_LG;
+ skb_queue_tail(&card->lbpool.queue, new_lb);
+ skb_reserve(new_lb, NS_SMBUFSIZE);
+ push_rxbufs(card, new_lb);
+ }
+ }
}
-
-
-static int ns_proc_read(struct atm_dev *dev, loff_t *pos, char *page)
+static int ns_proc_read(struct atm_dev *dev, loff_t * pos, char *page)
{
- u32 stat;
- ns_dev *card;
- int left;
-
- left = (int) *pos;
- card = (ns_dev *) dev->dev_data;
- stat = readl(card->membase + STAT);
- if (!left--)
- return sprintf(page, "Pool count min init max \n");
- if (!left--)
- return sprintf(page, "Small %5d %5d %5d %5d \n",
- ns_stat_sfbqc_get(stat), card->sbnr.min, card->sbnr.init,
- card->sbnr.max);
- if (!left--)
- return sprintf(page, "Large %5d %5d %5d %5d \n",
- ns_stat_lfbqc_get(stat), card->lbnr.min, card->lbnr.init,
- card->lbnr.max);
- if (!left--)
- return sprintf(page, "Huge %5d %5d %5d %5d \n", card->hbpool.count,
- card->hbnr.min, card->hbnr.init, card->hbnr.max);
- if (!left--)
- return sprintf(page, "Iovec %5d %5d %5d %5d \n", card->iovpool.count,
- card->iovnr.min, card->iovnr.init, card->iovnr.max);
- if (!left--)
- {
- int retval;
- retval = sprintf(page, "Interrupt counter: %u \n", card->intcnt);
- card->intcnt = 0;
- return retval;
- }
+ u32 stat;
+ ns_dev *card;
+ int left;
+
+ left = (int)*pos;
+ card = (ns_dev *) dev->dev_data;
+ stat = readl(card->membase + STAT);
+ if (!left--)
+ return sprintf(page, "Pool count min init max \n");
+ if (!left--)
+ return sprintf(page, "Small %5d %5d %5d %5d \n",
+ ns_stat_sfbqc_get(stat), card->sbnr.min,
+ card->sbnr.init, card->sbnr.max);
+ if (!left--)
+ return sprintf(page, "Large %5d %5d %5d %5d \n",
+ ns_stat_lfbqc_get(stat), card->lbnr.min,
+ card->lbnr.init, card->lbnr.max);
+ if (!left--)
+ return sprintf(page, "Huge %5d %5d %5d %5d \n",
+ card->hbpool.count, card->hbnr.min,
+ card->hbnr.init, card->hbnr.max);
+ if (!left--)
+ return sprintf(page, "Iovec %5d %5d %5d %5d \n",
+ card->iovpool.count, card->iovnr.min,
+ card->iovnr.init, card->iovnr.max);
+ if (!left--) {
+ int retval;
+ retval =
+ sprintf(page, "Interrupt counter: %u \n", card->intcnt);
+ card->intcnt = 0;
+ return retval;
+ }
#if 0
- /* Dump 25.6 Mbps PHY registers */
- /* Now there's a 25.6 Mbps PHY driver this code isn't needed. I left it
- here just in case it's needed for debugging. */
- if (card->max_pcr == ATM_25_PCR && !left--)
- {
- u32 phy_regs[4];
- u32 i;
-
- for (i = 0; i < 4; i++)
- {
- while (CMD_BUSY(card));
- writel(NS_CMD_READ_UTILITY | 0x00000200 | i, card->membase + CMD);
- while (CMD_BUSY(card));
- phy_regs[i] = readl(card->membase + DR0) & 0x000000FF;
- }
-
- return sprintf(page, "PHY regs: 0x%02X 0x%02X 0x%02X 0x%02X \n",
- phy_regs[0], phy_regs[1], phy_regs[2], phy_regs[3]);
- }
+ /* Dump 25.6 Mbps PHY registers */
+ /* Now there's a 25.6 Mbps PHY driver this code isn't needed. I left it
+ here just in case it's needed for debugging. */
+ if (card->max_pcr == ATM_25_PCR && !left--) {
+ u32 phy_regs[4];
+ u32 i;
+
+ for (i = 0; i < 4; i++) {
+ while (CMD_BUSY(card)) ;
+ writel(NS_CMD_READ_UTILITY | 0x00000200 | i,
+ card->membase + CMD);
+ while (CMD_BUSY(card)) ;
+ phy_regs[i] = readl(card->membase + DR0) & 0x000000FF;
+ }
+
+ return sprintf(page, "PHY regs: 0x%02X 0x%02X 0x%02X 0x%02X \n",
+ phy_regs[0], phy_regs[1], phy_regs[2],
+ phy_regs[3]);
+ }
#endif /* 0 - Dump 25.6 Mbps PHY registers */
#if 0
- /* Dump TST */
- if (left-- < NS_TST_NUM_ENTRIES)
- {
- if (card->tste2vc[left + 1] == NULL)
- return sprintf(page, "%5d - VBR/UBR \n", left + 1);
- else
- return sprintf(page, "%5d - %d %d \n", left + 1,
- card->tste2vc[left + 1]->tx_vcc->vpi,
- card->tste2vc[left + 1]->tx_vcc->vci);
- }
+ /* Dump TST */
+ if (left-- < NS_TST_NUM_ENTRIES) {
+ if (card->tste2vc[left + 1] == NULL)
+ return sprintf(page, "%5d - VBR/UBR \n", left + 1);
+ else
+ return sprintf(page, "%5d - %d %d \n", left + 1,
+ card->tste2vc[left + 1]->tx_vcc->vpi,
+ card->tste2vc[left + 1]->tx_vcc->vci);
+ }
#endif /* 0 */
- return 0;
+ return 0;
}
-
-
-static int ns_ioctl(struct atm_dev *dev, unsigned int cmd, void __user *arg)
+static int ns_ioctl(struct atm_dev *dev, unsigned int cmd, void __user * arg)
{
- ns_dev *card;
- pool_levels pl;
- long btype;
- unsigned long flags;
-
- card = dev->dev_data;
- switch (cmd)
- {
- case NS_GETPSTAT:
- if (get_user(pl.buftype, &((pool_levels __user *) arg)->buftype))
- return -EFAULT;
- switch (pl.buftype)
- {
- case NS_BUFTYPE_SMALL:
- pl.count = ns_stat_sfbqc_get(readl(card->membase + STAT));
- pl.level.min = card->sbnr.min;
- pl.level.init = card->sbnr.init;
- pl.level.max = card->sbnr.max;
- break;
-
- case NS_BUFTYPE_LARGE:
- pl.count = ns_stat_lfbqc_get(readl(card->membase + STAT));
- pl.level.min = card->lbnr.min;
- pl.level.init = card->lbnr.init;
- pl.level.max = card->lbnr.max;
- break;
-
- case NS_BUFTYPE_HUGE:
- pl.count = card->hbpool.count;
- pl.level.min = card->hbnr.min;
- pl.level.init = card->hbnr.init;
- pl.level.max = card->hbnr.max;
- break;
-
- case NS_BUFTYPE_IOVEC:
- pl.count = card->iovpool.count;
- pl.level.min = card->iovnr.min;
- pl.level.init = card->iovnr.init;
- pl.level.max = card->iovnr.max;
- break;
-
- default:
- return -ENOIOCTLCMD;
-
- }
- if (!copy_to_user((pool_levels __user *) arg, &pl, sizeof(pl)))
- return (sizeof(pl));
- else
- return -EFAULT;
-
- case NS_SETBUFLEV:
- if (!capable(CAP_NET_ADMIN))
- return -EPERM;
- if (copy_from_user(&pl, (pool_levels __user *) arg, sizeof(pl)))
- return -EFAULT;
- if (pl.level.min >= pl.level.init || pl.level.init >= pl.level.max)
- return -EINVAL;
- if (pl.level.min == 0)
- return -EINVAL;
- switch (pl.buftype)
- {
- case NS_BUFTYPE_SMALL:
- if (pl.level.max > TOP_SB)
- return -EINVAL;
- card->sbnr.min = pl.level.min;
- card->sbnr.init = pl.level.init;
- card->sbnr.max = pl.level.max;
- break;
-
- case NS_BUFTYPE_LARGE:
- if (pl.level.max > TOP_LB)
- return -EINVAL;
- card->lbnr.min = pl.level.min;
- card->lbnr.init = pl.level.init;
- card->lbnr.max = pl.level.max;
- break;
-
- case NS_BUFTYPE_HUGE:
- if (pl.level.max > TOP_HB)
- return -EINVAL;
- card->hbnr.min = pl.level.min;
- card->hbnr.init = pl.level.init;
- card->hbnr.max = pl.level.max;
- break;
-
- case NS_BUFTYPE_IOVEC:
- if (pl.level.max > TOP_IOVB)
- return -EINVAL;
- card->iovnr.min = pl.level.min;
- card->iovnr.init = pl.level.init;
- card->iovnr.max = pl.level.max;
- break;
-
- default:
- return -EINVAL;
-
- }
- return 0;
-
- case NS_ADJBUFLEV:
- if (!capable(CAP_NET_ADMIN))
- return -EPERM;
- btype = (long) arg; /* a long is the same size as a pointer or bigger */
- switch (btype)
- {
- case NS_BUFTYPE_SMALL:
- while (card->sbfqc < card->sbnr.init)
- {
- struct sk_buff *sb;
-
- sb = __dev_alloc_skb(NS_SMSKBSIZE, GFP_KERNEL);
- if (sb == NULL)
- return -ENOMEM;
- NS_SKB_CB(sb)->buf_type = BUF_SM;
- skb_queue_tail(&card->sbpool.queue, sb);
- skb_reserve(sb, NS_AAL0_HEADER);
- push_rxbufs(card, sb);
- }
- break;
-
- case NS_BUFTYPE_LARGE:
- while (card->lbfqc < card->lbnr.init)
- {
- struct sk_buff *lb;
-
- lb = __dev_alloc_skb(NS_LGSKBSIZE, GFP_KERNEL);
- if (lb == NULL)
- return -ENOMEM;
- NS_SKB_CB(lb)->buf_type = BUF_LG;
- skb_queue_tail(&card->lbpool.queue, lb);
- skb_reserve(lb, NS_SMBUFSIZE);
- push_rxbufs(card, lb);
- }
- break;
-
- case NS_BUFTYPE_HUGE:
- while (card->hbpool.count > card->hbnr.init)
- {
- struct sk_buff *hb;
-
- spin_lock_irqsave(&card->int_lock, flags);
- hb = skb_dequeue(&card->hbpool.queue);
- card->hbpool.count--;
- spin_unlock_irqrestore(&card->int_lock, flags);
- if (hb == NULL)
- printk("nicstar%d: huge buffer count inconsistent.\n",
- card->index);
- else
- dev_kfree_skb_any(hb);
-
- }
- while (card->hbpool.count < card->hbnr.init)
- {
- struct sk_buff *hb;
-
- hb = __dev_alloc_skb(NS_HBUFSIZE, GFP_KERNEL);
- if (hb == NULL)
- return -ENOMEM;
- NS_SKB_CB(hb)->buf_type = BUF_NONE;
- spin_lock_irqsave(&card->int_lock, flags);
- skb_queue_tail(&card->hbpool.queue, hb);
- card->hbpool.count++;
- spin_unlock_irqrestore(&card->int_lock, flags);
- }
- break;
-
- case NS_BUFTYPE_IOVEC:
- while (card->iovpool.count > card->iovnr.init)
- {
- struct sk_buff *iovb;
-
- spin_lock_irqsave(&card->int_lock, flags);
- iovb = skb_dequeue(&card->iovpool.queue);
- card->iovpool.count--;
- spin_unlock_irqrestore(&card->int_lock, flags);
- if (iovb == NULL)
- printk("nicstar%d: iovec buffer count inconsistent.\n",
- card->index);
- else
- dev_kfree_skb_any(iovb);
-
- }
- while (card->iovpool.count < card->iovnr.init)
- {
- struct sk_buff *iovb;
-
- iovb = alloc_skb(NS_IOVBUFSIZE, GFP_KERNEL);
- if (iovb == NULL)
- return -ENOMEM;
- NS_SKB_CB(iovb)->buf_type = BUF_NONE;
- spin_lock_irqsave(&card->int_lock, flags);
- skb_queue_tail(&card->iovpool.queue, iovb);
- card->iovpool.count++;
- spin_unlock_irqrestore(&card->int_lock, flags);
- }
- break;
-
- default:
- return -EINVAL;
-
- }
- return 0;
-
- default:
- if (dev->phy && dev->phy->ioctl) {
- return dev->phy->ioctl(dev, cmd, arg);
- }
- else {
- printk("nicstar%d: %s == NULL \n", card->index,
- dev->phy ? "dev->phy->ioctl" : "dev->phy");
- return -ENOIOCTLCMD;
- }
- }
+ ns_dev *card;
+ pool_levels pl;
+ long btype;
+ unsigned long flags;
+
+ card = dev->dev_data;
+ switch (cmd) {
+ case NS_GETPSTAT:
+ if (get_user
+ (pl.buftype, &((pool_levels __user *) arg)->buftype))
+ return -EFAULT;
+ switch (pl.buftype) {
+ case NS_BUFTYPE_SMALL:
+ pl.count =
+ ns_stat_sfbqc_get(readl(card->membase + STAT));
+ pl.level.min = card->sbnr.min;
+ pl.level.init = card->sbnr.init;
+ pl.level.max = card->sbnr.max;
+ break;
+
+ case NS_BUFTYPE_LARGE:
+ pl.count =
+ ns_stat_lfbqc_get(readl(card->membase + STAT));
+ pl.level.min = card->lbnr.min;
+ pl.level.init = card->lbnr.init;
+ pl.level.max = card->lbnr.max;
+ break;
+
+ case NS_BUFTYPE_HUGE:
+ pl.count = card->hbpool.count;
+ pl.level.min = card->hbnr.min;
+ pl.level.init = card->hbnr.init;
+ pl.level.max = card->hbnr.max;
+ break;
+
+ case NS_BUFTYPE_IOVEC:
+ pl.count = card->iovpool.count;
+ pl.level.min = card->iovnr.min;
+ pl.level.init = card->iovnr.init;
+ pl.level.max = card->iovnr.max;
+ break;
+
+ default:
+ return -ENOIOCTLCMD;
+
+ }
+ if (!copy_to_user((pool_levels __user *) arg, &pl, sizeof(pl)))
+ return (sizeof(pl));
+ else
+ return -EFAULT;
+
+ case NS_SETBUFLEV:
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+ if (copy_from_user(&pl, (pool_levels __user *) arg, sizeof(pl)))
+ return -EFAULT;
+ if (pl.level.min >= pl.level.init
+ || pl.level.init >= pl.level.max)
+ return -EINVAL;
+ if (pl.level.min == 0)
+ return -EINVAL;
+ switch (pl.buftype) {
+ case NS_BUFTYPE_SMALL:
+ if (pl.level.max > TOP_SB)
+ return -EINVAL;
+ card->sbnr.min = pl.level.min;
+ card->sbnr.init = pl.level.init;
+ card->sbnr.max = pl.level.max;
+ break;
+
+ case NS_BUFTYPE_LARGE:
+ if (pl.level.max > TOP_LB)
+ return -EINVAL;
+ card->lbnr.min = pl.level.min;
+ card->lbnr.init = pl.level.init;
+ card->lbnr.max = pl.level.max;
+ break;
+
+ case NS_BUFTYPE_HUGE:
+ if (pl.level.max > TOP_HB)
+ return -EINVAL;
+ card->hbnr.min = pl.level.min;
+ card->hbnr.init = pl.level.init;
+ card->hbnr.max = pl.level.max;
+ break;
+
+ case NS_BUFTYPE_IOVEC:
+ if (pl.level.max > TOP_IOVB)
+ return -EINVAL;
+ card->iovnr.min = pl.level.min;
+ card->iovnr.init = pl.level.init;
+ card->iovnr.max = pl.level.max;
+ break;
+
+ default:
+ return -EINVAL;
+
+ }
+ return 0;
+
+ case NS_ADJBUFLEV:
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+ btype = (long)arg; /* a long is the same size as a pointer or bigger */
+ switch (btype) {
+ case NS_BUFTYPE_SMALL:
+ while (card->sbfqc < card->sbnr.init) {
+ struct sk_buff *sb;
+
+ sb = __dev_alloc_skb(NS_SMSKBSIZE, GFP_KERNEL);
+ if (sb == NULL)
+ return -ENOMEM;
+ NS_PRV_BUFTYPE(sb) = BUF_SM;
+ skb_queue_tail(&card->sbpool.queue, sb);
+ skb_reserve(sb, NS_AAL0_HEADER);
+ push_rxbufs(card, sb);
+ }
+ break;
+
+ case NS_BUFTYPE_LARGE:
+ while (card->lbfqc < card->lbnr.init) {
+ struct sk_buff *lb;
+
+ lb = __dev_alloc_skb(NS_LGSKBSIZE, GFP_KERNEL);
+ if (lb == NULL)
+ return -ENOMEM;
+ NS_PRV_BUFTYPE(lb) = BUF_LG;
+ skb_queue_tail(&card->lbpool.queue, lb);
+ skb_reserve(lb, NS_SMBUFSIZE);
+ push_rxbufs(card, lb);
+ }
+ break;
+
+ case NS_BUFTYPE_HUGE:
+ while (card->hbpool.count > card->hbnr.init) {
+ struct sk_buff *hb;
+
+ spin_lock_irqsave(&card->int_lock, flags);
+ hb = skb_dequeue(&card->hbpool.queue);
+ card->hbpool.count--;
+ spin_unlock_irqrestore(&card->int_lock, flags);
+ if (hb == NULL)
+ printk
+ ("nicstar%d: huge buffer count inconsistent.\n",
+ card->index);
+ else
+ dev_kfree_skb_any(hb);
+
+ }
+ while (card->hbpool.count < card->hbnr.init) {
+ struct sk_buff *hb;
+
+ hb = __dev_alloc_skb(NS_HBUFSIZE, GFP_KERNEL);
+ if (hb == NULL)
+ return -ENOMEM;
+ NS_PRV_BUFTYPE(hb) = BUF_NONE;
+ spin_lock_irqsave(&card->int_lock, flags);
+ skb_queue_tail(&card->hbpool.queue, hb);
+ card->hbpool.count++;
+ spin_unlock_irqrestore(&card->int_lock, flags);
+ }
+ break;
+
+ case NS_BUFTYPE_IOVEC:
+ while (card->iovpool.count > card->iovnr.init) {
+ struct sk_buff *iovb;
+
+ spin_lock_irqsave(&card->int_lock, flags);
+ iovb = skb_dequeue(&card->iovpool.queue);
+ card->iovpool.count--;
+ spin_unlock_irqrestore(&card->int_lock, flags);
+ if (iovb == NULL)
+ printk
+ ("nicstar%d: iovec buffer count inconsistent.\n",
+ card->index);
+ else
+ dev_kfree_skb_any(iovb);
+
+ }
+ while (card->iovpool.count < card->iovnr.init) {
+ struct sk_buff *iovb;
+
+ iovb = alloc_skb(NS_IOVBUFSIZE, GFP_KERNEL);
+ if (iovb == NULL)
+ return -ENOMEM;
+ NS_PRV_BUFTYPE(iovb) = BUF_NONE;
+ spin_lock_irqsave(&card->int_lock, flags);
+ skb_queue_tail(&card->iovpool.queue, iovb);
+ card->iovpool.count++;
+ spin_unlock_irqrestore(&card->int_lock, flags);
+ }
+ break;
+
+ default:
+ return -EINVAL;
+
+ }
+ return 0;
+
+ default:
+ if (dev->phy && dev->phy->ioctl) {
+ return dev->phy->ioctl(dev, cmd, arg);
+ } else {
+ printk("nicstar%d: %s == NULL \n", card->index,
+ dev->phy ? "dev->phy->ioctl" : "dev->phy");
+ return -ENOIOCTLCMD;
+ }
+ }
}
-
-static void which_list(ns_dev *card, struct sk_buff *skb)
+#ifdef EXTRA_DEBUG
+static void which_list(ns_dev * card, struct sk_buff *skb)
{
- printk("skb buf_type: 0x%08x\n", NS_SKB_CB(skb)->buf_type);
+ printk("skb buf_type: 0x%08x\n", NS_PRV_BUFTYPE(skb));
}
-
+#endif /* EXTRA_DEBUG */
static void ns_poll(unsigned long arg)
{
- int i;
- ns_dev *card;
- unsigned long flags;
- u32 stat_r, stat_w;
-
- PRINTK("nicstar: Entering ns_poll().\n");
- for (i = 0; i < num_cards; i++)
- {
- card = cards[i];
- if (spin_is_locked(&card->int_lock)) {
- /* Probably it isn't worth spinning */
- continue;
- }
- spin_lock_irqsave(&card->int_lock, flags);
-
- stat_w = 0;
- stat_r = readl(card->membase + STAT);
- if (stat_r & NS_STAT_TSIF)
- stat_w |= NS_STAT_TSIF;
- if (stat_r & NS_STAT_EOPDU)
- stat_w |= NS_STAT_EOPDU;
-
- process_tsq(card);
- process_rsq(card);
-
- writel(stat_w, card->membase + STAT);
- spin_unlock_irqrestore(&card->int_lock, flags);
- }
- mod_timer(&ns_timer, jiffies + NS_POLL_PERIOD);
- PRINTK("nicstar: Leaving ns_poll().\n");
+ int i;
+ ns_dev *card;
+ unsigned long flags;
+ u32 stat_r, stat_w;
+
+ PRINTK("nicstar: Entering ns_poll().\n");
+ for (i = 0; i < num_cards; i++) {
+ card = cards[i];
+ if (spin_is_locked(&card->int_lock)) {
+ /* Probably it isn't worth spinning */
+ continue;
+ }
+ spin_lock_irqsave(&card->int_lock, flags);
+
+ stat_w = 0;
+ stat_r = readl(card->membase + STAT);
+ if (stat_r & NS_STAT_TSIF)
+ stat_w |= NS_STAT_TSIF;
+ if (stat_r & NS_STAT_EOPDU)
+ stat_w |= NS_STAT_EOPDU;
+
+ process_tsq(card);
+ process_rsq(card);
+
+ writel(stat_w, card->membase + STAT);
+ spin_unlock_irqrestore(&card->int_lock, flags);
+ }
+ mod_timer(&ns_timer, jiffies + NS_POLL_PERIOD);
+ PRINTK("nicstar: Leaving ns_poll().\n");
}
-
-
static int ns_parse_mac(char *mac, unsigned char *esi)
{
- int i, j;
- short byte1, byte0;
-
- if (mac == NULL || esi == NULL)
- return -1;
- j = 0;
- for (i = 0; i < 6; i++)
- {
- if ((byte1 = ns_h2i(mac[j++])) < 0)
- return -1;
- if ((byte0 = ns_h2i(mac[j++])) < 0)
- return -1;
- esi[i] = (unsigned char) (byte1 * 16 + byte0);
- if (i < 5)
- {
- if (mac[j++] != ':')
- return -1;
- }
- }
- return 0;
-}
-
-
-
-static short ns_h2i(char c)
-{
- if (c >= '0' && c <= '9')
- return (short) (c - '0');
- if (c >= 'A' && c <= 'F')
- return (short) (c - 'A' + 10);
- if (c >= 'a' && c <= 'f')
- return (short) (c - 'a' + 10);
- return -1;
+ int i, j;
+ short byte1, byte0;
+
+ if (mac == NULL || esi == NULL)
+ return -1;
+ j = 0;
+ for (i = 0; i < 6; i++) {
+ if ((byte1 = hex_to_bin(mac[j++])) < 0)
+ return -1;
+ if ((byte0 = hex_to_bin(mac[j++])) < 0)
+ return -1;
+ esi[i] = (unsigned char)(byte1 * 16 + byte0);
+ if (i < 5) {
+ if (mac[j++] != ':')
+ return -1;
+ }
+ }
+ return 0;
}
-
static void ns_phy_put(struct atm_dev *dev, unsigned char value,
- unsigned long addr)
+ unsigned long addr)
{
- ns_dev *card;
- unsigned long flags;
-
- card = dev->dev_data;
- spin_lock_irqsave(&card->res_lock, flags);
- while(CMD_BUSY(card));
- writel((unsigned long) value, card->membase + DR0);
- writel(NS_CMD_WRITE_UTILITY | 0x00000200 | (addr & 0x000000FF),
- card->membase + CMD);
- spin_unlock_irqrestore(&card->res_lock, flags);
+ ns_dev *card;
+ unsigned long flags;
+
+ card = dev->dev_data;
+ spin_lock_irqsave(&card->res_lock, flags);
+ while (CMD_BUSY(card)) ;
+ writel((u32) value, card->membase + DR0);
+ writel(NS_CMD_WRITE_UTILITY | 0x00000200 | (addr & 0x000000FF),
+ card->membase + CMD);
+ spin_unlock_irqrestore(&card->res_lock, flags);
}
-
-
static unsigned char ns_phy_get(struct atm_dev *dev, unsigned long addr)
{
- ns_dev *card;
- unsigned long flags;
- unsigned long data;
-
- card = dev->dev_data;
- spin_lock_irqsave(&card->res_lock, flags);
- while(CMD_BUSY(card));
- writel(NS_CMD_READ_UTILITY | 0x00000200 | (addr & 0x000000FF),
- card->membase + CMD);
- while(CMD_BUSY(card));
- data = readl(card->membase + DR0) & 0x000000FF;
- spin_unlock_irqrestore(&card->res_lock, flags);
- return (unsigned char) data;
+ ns_dev *card;
+ unsigned long flags;
+ u32 data;
+
+ card = dev->dev_data;
+ spin_lock_irqsave(&card->res_lock, flags);
+ while (CMD_BUSY(card)) ;
+ writel(NS_CMD_READ_UTILITY | 0x00000200 | (addr & 0x000000FF),
+ card->membase + CMD);
+ while (CMD_BUSY(card)) ;
+ data = readl(card->membase + DR0) & 0x000000FF;
+ spin_unlock_irqrestore(&card->res_lock, flags);
+ return (unsigned char)data;
}
-
-
module_init(nicstar_init);
module_exit(nicstar_cleanup);
diff --git a/drivers/atm/nicstar.h b/drivers/atm/nicstar.h
index 6010e3daa6a..9bc27ea5088 100644
--- a/drivers/atm/nicstar.h
+++ b/drivers/atm/nicstar.h
@@ -1,5 +1,4 @@
-/******************************************************************************
- *
+/*
* nicstar.h
*
* Header file for the nicstar device driver.
@@ -8,29 +7,26 @@
* PowerPC support by Jay Talbott (jay_talbott@mcg.mot.com) April 1999
*
* (C) INESC 1998
- *
- ******************************************************************************/
-
+ */
#ifndef _LINUX_NICSTAR_H_
#define _LINUX_NICSTAR_H_
-
-/* Includes *******************************************************************/
+/* Includes */
#include <linux/types.h>
#include <linux/pci.h>
+#include <linux/idr.h>
#include <linux/uio.h>
#include <linux/skbuff.h>
#include <linux/atmdev.h>
#include <linux/atm_nicstar.h>
-
-/* Options ********************************************************************/
+/* Options */
#define NS_MAX_CARDS 4 /* Maximum number of NICStAR based cards
controlled by the device driver. Must
- be <= 5 */
+ be <= 5 */
#undef RCQ_SUPPORT /* Do not define this for now */
@@ -43,7 +39,7 @@
#define NS_VPIBITS 2 /* 0, 1, 2, or 8 */
#define NS_MAX_RCTSIZE 4096 /* Number of entries. 4096 or 16384.
- Define 4096 only if (all) your card(s)
+ Define 4096 only if (all) your card(s)
have 32K x 32bit SRAM, in which case
setting this to 16384 will just waste a
lot of memory.
@@ -51,33 +47,32 @@
128K x 32bit SRAM will limit the maximum
VCI. */
-/*#define NS_PCI_LATENCY 64*/ /* Must be a multiple of 32 */
+ /*#define NS_PCI_LATENCY 64*//* Must be a multiple of 32 */
/* Number of buffers initially allocated */
-#define NUM_SB 32 /* Must be even */
-#define NUM_LB 24 /* Must be even */
-#define NUM_HB 8 /* Pre-allocated huge buffers */
-#define NUM_IOVB 48 /* Iovec buffers */
+#define NUM_SB 32 /* Must be even */
+#define NUM_LB 24 /* Must be even */
+#define NUM_HB 8 /* Pre-allocated huge buffers */
+#define NUM_IOVB 48 /* Iovec buffers */
/* Lower level for count of buffers */
-#define MIN_SB 8 /* Must be even */
-#define MIN_LB 8 /* Must be even */
+#define MIN_SB 8 /* Must be even */
+#define MIN_LB 8 /* Must be even */
#define MIN_HB 6
#define MIN_IOVB 8
/* Upper level for count of buffers */
-#define MAX_SB 64 /* Must be even, <= 508 */
-#define MAX_LB 48 /* Must be even, <= 508 */
+#define MAX_SB 64 /* Must be even, <= 508 */
+#define MAX_LB 48 /* Must be even, <= 508 */
#define MAX_HB 10
#define MAX_IOVB 80
/* These are the absolute maximum allowed for the ioctl() */
-#define TOP_SB 256 /* Must be even, <= 508 */
-#define TOP_LB 128 /* Must be even, <= 508 */
+#define TOP_SB 256 /* Must be even, <= 508 */
+#define TOP_LB 128 /* Must be even, <= 508 */
#define TOP_HB 64
#define TOP_IOVB 256
-
#define MAX_TBD_PER_VC 1 /* Number of TBDs before a TSR */
#define MAX_TBD_PER_SCQ 10 /* Only meaningful for variable rate SCQs */
@@ -89,15 +84,12 @@
#define PCR_TOLERANCE (1.0001)
-
-
-/* ESI stuff ******************************************************************/
+/* ESI stuff */
#define NICSTAR_EPROM_MAC_ADDR_OFFSET 0x6C
#define NICSTAR_EPROM_MAC_ADDR_OFFSET_ALT 0xF6
-
-/* #defines *******************************************************************/
+/* #defines */
#define NS_IOREMAP_SIZE 4096
@@ -123,22 +115,19 @@
#define NS_SMSKBSIZE (NS_SMBUFSIZE + NS_AAL0_HEADER)
#define NS_LGSKBSIZE (NS_SMBUFSIZE + NS_LGBUFSIZE)
+/* NICStAR structures located in host memory */
-/* NICStAR structures located in host memory **********************************/
-
-
-
-/* RSQ - Receive Status Queue
+/*
+ * RSQ - Receive Status Queue
*
* Written by the NICStAR, read by the device driver.
*/
-typedef struct ns_rsqe
-{
- u32 word_1;
- u32 buffer_handle;
- u32 final_aal5_crc32;
- u32 word_4;
+typedef struct ns_rsqe {
+ u32 word_1;
+ u32 buffer_handle;
+ u32 final_aal5_crc32;
+ u32 word_4;
} ns_rsqe;
#define ns_rsqe_vpi(ns_rsqep) \
@@ -175,30 +164,27 @@ typedef struct ns_rsqe
#define ns_rsqe_cellcount(ns_rsqep) \
(le32_to_cpu((ns_rsqep)->word_4) & 0x000001FF)
#define ns_rsqe_init(ns_rsqep) \
- ((ns_rsqep)->word_4 = cpu_to_le32(0x00000000))
+ ((ns_rsqep)->word_4 = cpu_to_le32(0x00000000))
#define NS_RSQ_NUM_ENTRIES (NS_RSQSIZE / 16)
#define NS_RSQ_ALIGNMENT NS_RSQSIZE
-
-
-/* RCQ - Raw Cell Queue
+/*
+ * RCQ - Raw Cell Queue
*
* Written by the NICStAR, read by the device driver.
*/
-typedef struct cell_payload
-{
- u32 word[12];
+typedef struct cell_payload {
+ u32 word[12];
} cell_payload;
-typedef struct ns_rcqe
-{
- u32 word_1;
- u32 word_2;
- u32 word_3;
- u32 word_4;
- cell_payload payload;
+typedef struct ns_rcqe {
+ u32 word_1;
+ u32 word_2;
+ u32 word_3;
+ u32 word_4;
+ cell_payload payload;
} ns_rcqe;
#define NS_RCQE_SIZE 64 /* bytes */
@@ -210,28 +196,25 @@ typedef struct ns_rcqe
#define ns_rcqe_nextbufhandle(ns_rcqep) \
(le32_to_cpu((ns_rcqep)->word_2))
-
-
-/* SCQ - Segmentation Channel Queue
+/*
+ * SCQ - Segmentation Channel Queue
*
* Written by the device driver, read by the NICStAR.
*/
-typedef struct ns_scqe
-{
- u32 word_1;
- u32 word_2;
- u32 word_3;
- u32 word_4;
+typedef struct ns_scqe {
+ u32 word_1;
+ u32 word_2;
+ u32 word_3;
+ u32 word_4;
} ns_scqe;
/* NOTE: SCQ entries can be either a TBD (Transmit Buffer Descriptors)
- or TSR (Transmit Status Requests) */
+ or TSR (Transmit Status Requests) */
#define NS_SCQE_TYPE_TBD 0x00000000
#define NS_SCQE_TYPE_TSR 0x80000000
-
#define NS_TBD_EOPDU 0x40000000
#define NS_TBD_AAL0 0x00000000
#define NS_TBD_AAL34 0x04000000
@@ -253,10 +236,9 @@ typedef struct ns_scqe
#define ns_tbd_mkword_4(gfc, vpi, vci, pt, clp) \
(cpu_to_le32((gfc) << 28 | (vpi) << 20 | (vci) << 4 | (pt) << 1 | (clp)))
-
#define NS_TSR_INTENABLE 0x20000000
-#define NS_TSR_SCDISVBR 0xFFFF /* Use as scdi for VBR SCD */
+#define NS_TSR_SCDISVBR 0xFFFF /* Use as scdi for VBR SCD */
#define ns_tsr_mkword_1(flags) \
(cpu_to_le32(NS_SCQE_TYPE_TSR | (flags)))
@@ -273,22 +255,20 @@ typedef struct ns_scqe
#define NS_SCQE_SIZE 16
-
-
-/* TSQ - Transmit Status Queue
+/*
+ * TSQ - Transmit Status Queue
*
* Written by the NICStAR, read by the device driver.
*/
-typedef struct ns_tsi
-{
- u32 word_1;
- u32 word_2;
+typedef struct ns_tsi {
+ u32 word_1;
+ u32 word_2;
} ns_tsi;
/* NOTE: The first word can be a status word copied from the TSR which
- originated the TSI, or a timer overflow indicator. In this last
- case, the value of the first word is all zeroes. */
+ originated the TSI, or a timer overflow indicator. In this last
+ case, the value of the first word is all zeroes. */
#define NS_TSI_EMPTY 0x80000000
#define NS_TSI_TIMESTAMP_MASK 0x00FFFFFF
@@ -301,12 +281,10 @@ typedef struct ns_tsi
#define ns_tsi_init(ns_tsip) \
((ns_tsip)->word_2 = cpu_to_le32(NS_TSI_EMPTY))
-
#define NS_TSQSIZE 8192
#define NS_TSQ_NUM_ENTRIES 1024
#define NS_TSQ_ALIGNMENT 8192
-
#define NS_TSI_SCDISVBR NS_TSR_SCDISVBR
#define ns_tsi_tmrof(ns_tsip) \
@@ -316,26 +294,22 @@ typedef struct ns_tsi
#define ns_tsi_getscqpos(ns_tsip) \
(le32_to_cpu((ns_tsip)->word_1) & 0x00007FFF)
+/* NICStAR structures located in local SRAM */
-
-/* NICStAR structures located in local SRAM ***********************************/
-
-
-
-/* RCT - Receive Connection Table
+/*
+ * RCT - Receive Connection Table
*
* Written by both the NICStAR and the device driver.
*/
-typedef struct ns_rcte
-{
- u32 word_1;
- u32 buffer_handle;
- u32 dma_address;
- u32 aal5_crc32;
+typedef struct ns_rcte {
+ u32 word_1;
+ u32 buffer_handle;
+ u32 dma_address;
+ u32 aal5_crc32;
} ns_rcte;
-#define NS_RCTE_BSFB 0x00200000 /* Rev. D only */
+#define NS_RCTE_BSFB 0x00200000 /* Rev. D only */
#define NS_RCTE_NZGFC 0x00100000
#define NS_RCTE_CONNECTOPEN 0x00080000
#define NS_RCTE_AALMASK 0x00070000
@@ -358,25 +332,21 @@ typedef struct ns_rcte
#define NS_RCT_ENTRY_SIZE 4 /* Number of dwords */
/* NOTE: We could make macros to contruct the first word of the RCTE,
- but that doesn't seem to make much sense... */
+ but that doesn't seem to make much sense... */
-
-
-/* FBD - Free Buffer Descriptor
+/*
+ * FBD - Free Buffer Descriptor
*
* Written by the device driver using via the command register.
*/
-typedef struct ns_fbd
-{
- u32 buffer_handle;
- u32 dma_address;
+typedef struct ns_fbd {
+ u32 buffer_handle;
+ u32 dma_address;
} ns_fbd;
-
-
-
-/* TST - Transmit Schedule Table
+/*
+ * TST - Transmit Schedule Table
*
* Written by the device driver.
*/
@@ -385,40 +355,38 @@ typedef u32 ns_tste;
#define NS_TST_OPCODE_MASK 0x60000000
-#define NS_TST_OPCODE_NULL 0x00000000 /* Insert null cell */
-#define NS_TST_OPCODE_FIXED 0x20000000 /* Cell from a fixed rate channel */
+#define NS_TST_OPCODE_NULL 0x00000000 /* Insert null cell */
+#define NS_TST_OPCODE_FIXED 0x20000000 /* Cell from a fixed rate channel */
#define NS_TST_OPCODE_VARIABLE 0x40000000
-#define NS_TST_OPCODE_END 0x60000000 /* Jump */
+#define NS_TST_OPCODE_END 0x60000000 /* Jump */
#define ns_tste_make(opcode, sramad) (opcode | sramad)
/* NOTE:
- When the opcode is FIXED, sramad specifies the SRAM address of the
- SCD for that fixed rate channel.
+ SCD for that fixed rate channel.
- When the opcode is END, sramad specifies the SRAM address of the
- location of the next TST entry to read.
+ location of the next TST entry to read.
*/
-
-
-/* SCD - Segmentation Channel Descriptor
+/*
+ * SCD - Segmentation Channel Descriptor
*
* Written by both the device driver and the NICStAR
*/
-typedef struct ns_scd
-{
- u32 word_1;
- u32 word_2;
- u32 partial_aal5_crc;
- u32 reserved;
- ns_scqe cache_a;
- ns_scqe cache_b;
+typedef struct ns_scd {
+ u32 word_1;
+ u32 word_2;
+ u32 partial_aal5_crc;
+ u32 reserved;
+ ns_scqe cache_a;
+ ns_scqe cache_b;
} ns_scd;
-#define NS_SCD_BASE_MASK_VAR 0xFFFFE000 /* Variable rate */
-#define NS_SCD_BASE_MASK_FIX 0xFFFFFC00 /* Fixed rate */
+#define NS_SCD_BASE_MASK_VAR 0xFFFFE000 /* Variable rate */
+#define NS_SCD_BASE_MASK_FIX 0xFFFFFC00 /* Fixed rate */
#define NS_SCD_TAIL_MASK_VAR 0x00001FF0
#define NS_SCD_TAIL_MASK_FIX 0x000003F0
#define NS_SCD_HEAD_MASK_VAR 0x00001FF0
@@ -426,13 +394,9 @@ typedef struct ns_scd
#define NS_SCD_XMITFOREVER 0x02000000
/* NOTE: There are other fields in word 2 of the SCD, but as they should
- not be needed in the device driver they are not defined here. */
-
-
-
-
-/* NICStAR local SRAM memory map **********************************************/
+ not be needed in the device driver they are not defined here. */
+/* NICStAR local SRAM memory map */
#define NS_RCT 0x00000
#define NS_RCT_32_END 0x03FFF
@@ -455,100 +419,93 @@ typedef struct ns_scd
#define NS_LGFBQ 0x1FC00
#define NS_LGFBQ_END 0x1FFFF
-
-
-/* NISCtAR operation registers ************************************************/
-
+/* NISCtAR operation registers */
/* See Section 3.4 of `IDT77211 NICStAR User Manual' from www.idt.com */
-enum ns_regs
-{
- DR0 = 0x00, /* Data Register 0 R/W*/
- DR1 = 0x04, /* Data Register 1 W */
- DR2 = 0x08, /* Data Register 2 W */
- DR3 = 0x0C, /* Data Register 3 W */
- CMD = 0x10, /* Command W */
- CFG = 0x14, /* Configuration R/W */
- STAT = 0x18, /* Status R/W */
- RSQB = 0x1C, /* Receive Status Queue Base W */
- RSQT = 0x20, /* Receive Status Queue Tail R */
- RSQH = 0x24, /* Receive Status Queue Head W */
- CDC = 0x28, /* Cell Drop Counter R/clear */
- VPEC = 0x2C, /* VPI/VCI Lookup Error Count R/clear */
- ICC = 0x30, /* Invalid Cell Count R/clear */
- RAWCT = 0x34, /* Raw Cell Tail R */
- TMR = 0x38, /* Timer R */
- TSTB = 0x3C, /* Transmit Schedule Table Base R/W */
- TSQB = 0x40, /* Transmit Status Queue Base W */
- TSQT = 0x44, /* Transmit Status Queue Tail R */
- TSQH = 0x48, /* Transmit Status Queue Head W */
- GP = 0x4C, /* General Purpose R/W */
- VPM = 0x50 /* VPI/VCI Mask W */
+enum ns_regs {
+ DR0 = 0x00, /* Data Register 0 R/W */
+ DR1 = 0x04, /* Data Register 1 W */
+ DR2 = 0x08, /* Data Register 2 W */
+ DR3 = 0x0C, /* Data Register 3 W */
+ CMD = 0x10, /* Command W */
+ CFG = 0x14, /* Configuration R/W */
+ STAT = 0x18, /* Status R/W */
+ RSQB = 0x1C, /* Receive Status Queue Base W */
+ RSQT = 0x20, /* Receive Status Queue Tail R */
+ RSQH = 0x24, /* Receive Status Queue Head W */
+ CDC = 0x28, /* Cell Drop Counter R/clear */
+ VPEC = 0x2C, /* VPI/VCI Lookup Error Count R/clear */
+ ICC = 0x30, /* Invalid Cell Count R/clear */
+ RAWCT = 0x34, /* Raw Cell Tail R */
+ TMR = 0x38, /* Timer R */
+ TSTB = 0x3C, /* Transmit Schedule Table Base R/W */
+ TSQB = 0x40, /* Transmit Status Queue Base W */
+ TSQT = 0x44, /* Transmit Status Queue Tail R */
+ TSQH = 0x48, /* Transmit Status Queue Head W */
+ GP = 0x4C, /* General Purpose R/W */
+ VPM = 0x50 /* VPI/VCI Mask W */
};
-
-/* NICStAR commands issued to the CMD register ********************************/
-
+/* NICStAR commands issued to the CMD register */
/* Top 4 bits are command opcode, lower 28 are parameters. */
#define NS_CMD_NO_OPERATION 0x00000000
- /* params always 0 */
+ /* params always 0 */
#define NS_CMD_OPENCLOSE_CONNECTION 0x20000000
- /* b19{1=open,0=close} b18-2{SRAM addr} */
+ /* b19{1=open,0=close} b18-2{SRAM addr} */
#define NS_CMD_WRITE_SRAM 0x40000000
- /* b18-2{SRAM addr} b1-0{burst size} */
+ /* b18-2{SRAM addr} b1-0{burst size} */
#define NS_CMD_READ_SRAM 0x50000000
- /* b18-2{SRAM addr} */
+ /* b18-2{SRAM addr} */
#define NS_CMD_WRITE_FREEBUFQ 0x60000000
- /* b0{large buf indicator} */
+ /* b0{large buf indicator} */
#define NS_CMD_READ_UTILITY 0x80000000
- /* b8{1=select UTL_CS1} b9{1=select UTL_CS0} b7-0{bus addr} */
+ /* b8{1=select UTL_CS1} b9{1=select UTL_CS0} b7-0{bus addr} */
#define NS_CMD_WRITE_UTILITY 0x90000000
- /* b8{1=select UTL_CS1} b9{1=select UTL_CS0} b7-0{bus addr} */
+ /* b8{1=select UTL_CS1} b9{1=select UTL_CS0} b7-0{bus addr} */
#define NS_CMD_OPEN_CONNECTION (NS_CMD_OPENCLOSE_CONNECTION | 0x00080000)
#define NS_CMD_CLOSE_CONNECTION NS_CMD_OPENCLOSE_CONNECTION
-
-/* NICStAR configuration bits *************************************************/
-
-#define NS_CFG_SWRST 0x80000000 /* Software Reset */
-#define NS_CFG_RXPATH 0x20000000 /* Receive Path Enable */
-#define NS_CFG_SMBUFSIZE_MASK 0x18000000 /* Small Receive Buffer Size */
-#define NS_CFG_LGBUFSIZE_MASK 0x06000000 /* Large Receive Buffer Size */
-#define NS_CFG_EFBIE 0x01000000 /* Empty Free Buffer Queue
- Interrupt Enable */
-#define NS_CFG_RSQSIZE_MASK 0x00C00000 /* Receive Status Queue Size */
-#define NS_CFG_ICACCEPT 0x00200000 /* Invalid Cell Accept */
-#define NS_CFG_IGNOREGFC 0x00100000 /* Ignore General Flow Control */
-#define NS_CFG_VPIBITS_MASK 0x000C0000 /* VPI/VCI Bits Size Select */
-#define NS_CFG_RCTSIZE_MASK 0x00030000 /* Receive Connection Table Size */
-#define NS_CFG_VCERRACCEPT 0x00008000 /* VPI/VCI Error Cell Accept */
-#define NS_CFG_RXINT_MASK 0x00007000 /* End of Receive PDU Interrupt
- Handling */
-#define NS_CFG_RAWIE 0x00000800 /* Raw Cell Qu' Interrupt Enable */
-#define NS_CFG_RSQAFIE 0x00000400 /* Receive Queue Almost Full
- Interrupt Enable */
-#define NS_CFG_RXRM 0x00000200 /* Receive RM Cells */
-#define NS_CFG_TMRROIE 0x00000080 /* Timer Roll Over Interrupt
- Enable */
-#define NS_CFG_TXEN 0x00000020 /* Transmit Operation Enable */
-#define NS_CFG_TXIE 0x00000010 /* Transmit Status Interrupt
- Enable */
-#define NS_CFG_TXURIE 0x00000008 /* Transmit Under-run Interrupt
- Enable */
-#define NS_CFG_UMODE 0x00000004 /* Utopia Mode (cell/byte) Select */
-#define NS_CFG_TSQFIE 0x00000002 /* Transmit Status Queue Full
- Interrupt Enable */
-#define NS_CFG_PHYIE 0x00000001 /* PHY Interrupt Enable */
+/* NICStAR configuration bits */
+
+#define NS_CFG_SWRST 0x80000000 /* Software Reset */
+#define NS_CFG_RXPATH 0x20000000 /* Receive Path Enable */
+#define NS_CFG_SMBUFSIZE_MASK 0x18000000 /* Small Receive Buffer Size */
+#define NS_CFG_LGBUFSIZE_MASK 0x06000000 /* Large Receive Buffer Size */
+#define NS_CFG_EFBIE 0x01000000 /* Empty Free Buffer Queue
+ Interrupt Enable */
+#define NS_CFG_RSQSIZE_MASK 0x00C00000 /* Receive Status Queue Size */
+#define NS_CFG_ICACCEPT 0x00200000 /* Invalid Cell Accept */
+#define NS_CFG_IGNOREGFC 0x00100000 /* Ignore General Flow Control */
+#define NS_CFG_VPIBITS_MASK 0x000C0000 /* VPI/VCI Bits Size Select */
+#define NS_CFG_RCTSIZE_MASK 0x00030000 /* Receive Connection Table Size */
+#define NS_CFG_VCERRACCEPT 0x00008000 /* VPI/VCI Error Cell Accept */
+#define NS_CFG_RXINT_MASK 0x00007000 /* End of Receive PDU Interrupt
+ Handling */
+#define NS_CFG_RAWIE 0x00000800 /* Raw Cell Qu' Interrupt Enable */
+#define NS_CFG_RSQAFIE 0x00000400 /* Receive Queue Almost Full
+ Interrupt Enable */
+#define NS_CFG_RXRM 0x00000200 /* Receive RM Cells */
+#define NS_CFG_TMRROIE 0x00000080 /* Timer Roll Over Interrupt
+ Enable */
+#define NS_CFG_TXEN 0x00000020 /* Transmit Operation Enable */
+#define NS_CFG_TXIE 0x00000010 /* Transmit Status Interrupt
+ Enable */
+#define NS_CFG_TXURIE 0x00000008 /* Transmit Under-run Interrupt
+ Enable */
+#define NS_CFG_UMODE 0x00000004 /* Utopia Mode (cell/byte) Select */
+#define NS_CFG_TSQFIE 0x00000002 /* Transmit Status Queue Full
+ Interrupt Enable */
+#define NS_CFG_PHYIE 0x00000001 /* PHY Interrupt Enable */
#define NS_CFG_SMBUFSIZE_48 0x00000000
#define NS_CFG_SMBUFSIZE_96 0x08000000
@@ -579,33 +536,29 @@ enum ns_regs
#define NS_CFG_RXINT_624US 0x00003000
#define NS_CFG_RXINT_899US 0x00004000
-
-/* NICStAR STATus bits ********************************************************/
-
-#define NS_STAT_SFBQC_MASK 0xFF000000 /* hi 8 bits Small Buffer Queue Count */
-#define NS_STAT_LFBQC_MASK 0x00FF0000 /* hi 8 bits Large Buffer Queue Count */
-#define NS_STAT_TSIF 0x00008000 /* Transmit Status Queue Indicator */
-#define NS_STAT_TXICP 0x00004000 /* Transmit Incomplete PDU */
-#define NS_STAT_TSQF 0x00001000 /* Transmit Status Queue Full */
-#define NS_STAT_TMROF 0x00000800 /* Timer Overflow */
-#define NS_STAT_PHYI 0x00000400 /* PHY Device Interrupt */
-#define NS_STAT_CMDBZ 0x00000200 /* Command Busy */
-#define NS_STAT_SFBQF 0x00000100 /* Small Buffer Queue Full */
-#define NS_STAT_LFBQF 0x00000080 /* Large Buffer Queue Full */
-#define NS_STAT_RSQF 0x00000040 /* Receive Status Queue Full */
-#define NS_STAT_EOPDU 0x00000020 /* End of PDU */
-#define NS_STAT_RAWCF 0x00000010 /* Raw Cell Flag */
-#define NS_STAT_SFBQE 0x00000008 /* Small Buffer Queue Empty */
-#define NS_STAT_LFBQE 0x00000004 /* Large Buffer Queue Empty */
-#define NS_STAT_RSQAF 0x00000002 /* Receive Status Queue Almost Full */
+/* NICStAR STATus bits */
+
+#define NS_STAT_SFBQC_MASK 0xFF000000 /* hi 8 bits Small Buffer Queue Count */
+#define NS_STAT_LFBQC_MASK 0x00FF0000 /* hi 8 bits Large Buffer Queue Count */
+#define NS_STAT_TSIF 0x00008000 /* Transmit Status Queue Indicator */
+#define NS_STAT_TXICP 0x00004000 /* Transmit Incomplete PDU */
+#define NS_STAT_TSQF 0x00001000 /* Transmit Status Queue Full */
+#define NS_STAT_TMROF 0x00000800 /* Timer Overflow */
+#define NS_STAT_PHYI 0x00000400 /* PHY Device Interrupt */
+#define NS_STAT_CMDBZ 0x00000200 /* Command Busy */
+#define NS_STAT_SFBQF 0x00000100 /* Small Buffer Queue Full */
+#define NS_STAT_LFBQF 0x00000080 /* Large Buffer Queue Full */
+#define NS_STAT_RSQF 0x00000040 /* Receive Status Queue Full */
+#define NS_STAT_EOPDU 0x00000020 /* End of PDU */
+#define NS_STAT_RAWCF 0x00000010 /* Raw Cell Flag */
+#define NS_STAT_SFBQE 0x00000008 /* Small Buffer Queue Empty */
+#define NS_STAT_LFBQE 0x00000004 /* Large Buffer Queue Empty */
+#define NS_STAT_RSQAF 0x00000002 /* Receive Status Queue Almost Full */
#define ns_stat_sfbqc_get(stat) (((stat) & NS_STAT_SFBQC_MASK) >> 23)
#define ns_stat_lfbqc_get(stat) (((stat) & NS_STAT_LFBQC_MASK) >> 15)
-
-
-/* #defines which depend on other #defines ************************************/
-
+/* #defines which depend on other #defines */
#define NS_TST0 NS_TST_FRSCD
#define NS_TST1 (NS_TST_FRSCD + NS_TST_NUM_ENTRIES + 1)
@@ -672,8 +625,7 @@ enum ns_regs
#define NS_CFG_TSQFIE_OPT 0x00000000
#endif /* ENABLE_TSQFIE */
-
-/* PCI stuff ******************************************************************/
+/* PCI stuff */
#ifndef PCI_VENDOR_ID_IDT
#define PCI_VENDOR_ID_IDT 0x111D
@@ -683,138 +635,124 @@ enum ns_regs
#define PCI_DEVICE_ID_IDT_IDT77201 0x0001
#endif /* PCI_DEVICE_ID_IDT_IDT77201 */
+/* Device driver structures */
-
-/* Device driver structures ***************************************************/
-
-
-struct ns_skb_cb {
- u32 buf_type; /* BUF_SM/BUF_LG/BUF_NONE */
+struct ns_skb_prv {
+ u32 buf_type; /* BUF_SM/BUF_LG/BUF_NONE */
+ u32 dma;
+ int iovcnt;
};
-#define NS_SKB_CB(skb) ((struct ns_skb_cb *)((skb)->cb))
-
-typedef struct tsq_info
-{
- void *org;
- ns_tsi *base;
- ns_tsi *next;
- ns_tsi *last;
+#define NS_PRV_BUFTYPE(skb) \
+ (((struct ns_skb_prv *)(ATM_SKB(skb)+1))->buf_type)
+#define NS_PRV_DMA(skb) \
+ (((struct ns_skb_prv *)(ATM_SKB(skb)+1))->dma)
+#define NS_PRV_IOVCNT(skb) \
+ (((struct ns_skb_prv *)(ATM_SKB(skb)+1))->iovcnt)
+
+typedef struct tsq_info {
+ void *org;
+ dma_addr_t dma;
+ ns_tsi *base;
+ ns_tsi *next;
+ ns_tsi *last;
} tsq_info;
-
-typedef struct scq_info
-{
- void *org;
- ns_scqe *base;
- ns_scqe *last;
- ns_scqe *next;
- volatile ns_scqe *tail; /* Not related to the nicstar register */
- unsigned num_entries;
- struct sk_buff **skb; /* Pointer to an array of pointers
- to the sk_buffs used for tx */
- u32 scd; /* SRAM address of the corresponding
- SCD */
- int tbd_count; /* Only meaningful on variable rate */
- wait_queue_head_t scqfull_waitq;
- volatile char full; /* SCQ full indicator */
- spinlock_t lock; /* SCQ spinlock */
+typedef struct scq_info {
+ void *org;
+ dma_addr_t dma;
+ ns_scqe *base;
+ ns_scqe *last;
+ ns_scqe *next;
+ volatile ns_scqe *tail; /* Not related to the nicstar register */
+ unsigned num_entries;
+ struct sk_buff **skb; /* Pointer to an array of pointers
+ to the sk_buffs used for tx */
+ u32 scd; /* SRAM address of the corresponding
+ SCD */
+ int tbd_count; /* Only meaningful on variable rate */
+ wait_queue_head_t scqfull_waitq;
+ volatile char full; /* SCQ full indicator */
+ spinlock_t lock; /* SCQ spinlock */
} scq_info;
-
-
-typedef struct rsq_info
-{
- void *org;
- ns_rsqe *base;
- ns_rsqe *next;
- ns_rsqe *last;
+typedef struct rsq_info {
+ void *org;
+ dma_addr_t dma;
+ ns_rsqe *base;
+ ns_rsqe *next;
+ ns_rsqe *last;
} rsq_info;
-
-typedef struct skb_pool
-{
- volatile int count; /* number of buffers in the queue */
- struct sk_buff_head queue;
+typedef struct skb_pool {
+ volatile int count; /* number of buffers in the queue */
+ struct sk_buff_head queue;
} skb_pool;
/* NOTE: for small and large buffer pools, the count is not used, as the
actual value used for buffer management is the one read from the
card. */
-
-typedef struct vc_map
-{
- volatile unsigned int tx:1; /* TX vc? */
- volatile unsigned int rx:1; /* RX vc? */
- struct atm_vcc *tx_vcc, *rx_vcc;
- struct sk_buff *rx_iov; /* RX iovector skb */
- scq_info *scq; /* To keep track of the SCQ */
- u32 cbr_scd; /* SRAM address of the corresponding
- SCD. 0x00000000 for UBR/VBR/ABR */
- int tbd_count;
+typedef struct vc_map {
+ volatile unsigned int tx:1; /* TX vc? */
+ volatile unsigned int rx:1; /* RX vc? */
+ struct atm_vcc *tx_vcc, *rx_vcc;
+ struct sk_buff *rx_iov; /* RX iovector skb */
+ scq_info *scq; /* To keep track of the SCQ */
+ u32 cbr_scd; /* SRAM address of the corresponding
+ SCD. 0x00000000 for UBR/VBR/ABR */
+ int tbd_count;
} vc_map;
-
-struct ns_skb_data
-{
- struct atm_vcc *vcc;
- int iovcnt;
-};
-
-#define NS_SKB(skb) (((struct ns_skb_data *) (skb)->cb))
-
-
-typedef struct ns_dev
-{
- int index; /* Card ID to the device driver */
- int sram_size; /* In k x 32bit words. 32 or 128 */
- void __iomem *membase; /* Card's memory base address */
- unsigned long max_pcr;
- int rct_size; /* Number of entries */
- int vpibits;
- int vcibits;
- struct pci_dev *pcidev;
- struct atm_dev *atmdev;
- tsq_info tsq;
- rsq_info rsq;
- scq_info *scq0, *scq1, *scq2; /* VBR SCQs */
- skb_pool sbpool; /* Small buffers */
- skb_pool lbpool; /* Large buffers */
- skb_pool hbpool; /* Pre-allocated huge buffers */
- skb_pool iovpool; /* iovector buffers */
- volatile int efbie; /* Empty free buf. queue int. enabled */
- volatile u32 tst_addr; /* SRAM address of the TST in use */
- volatile int tst_free_entries;
- vc_map vcmap[NS_MAX_RCTSIZE];
- vc_map *tste2vc[NS_TST_NUM_ENTRIES];
- vc_map *scd2vc[NS_FRSCD_NUM];
- buf_nr sbnr;
- buf_nr lbnr;
- buf_nr hbnr;
- buf_nr iovnr;
- int sbfqc;
- int lbfqc;
- u32 sm_handle;
- u32 sm_addr;
- u32 lg_handle;
- u32 lg_addr;
- struct sk_buff *rcbuf; /* Current raw cell buffer */
- u32 rawch; /* Raw cell queue head */
- unsigned intcnt; /* Interrupt counter */
- spinlock_t int_lock; /* Interrupt lock */
- spinlock_t res_lock; /* Card resource lock */
+typedef struct ns_dev {
+ int index; /* Card ID to the device driver */
+ int sram_size; /* In k x 32bit words. 32 or 128 */
+ void __iomem *membase; /* Card's memory base address */
+ unsigned long max_pcr;
+ int rct_size; /* Number of entries */
+ int vpibits;
+ int vcibits;
+ struct pci_dev *pcidev;
+ struct idr idr;
+ struct atm_dev *atmdev;
+ tsq_info tsq;
+ rsq_info rsq;
+ scq_info *scq0, *scq1, *scq2; /* VBR SCQs */
+ skb_pool sbpool; /* Small buffers */
+ skb_pool lbpool; /* Large buffers */
+ skb_pool hbpool; /* Pre-allocated huge buffers */
+ skb_pool iovpool; /* iovector buffers */
+ volatile int efbie; /* Empty free buf. queue int. enabled */
+ volatile u32 tst_addr; /* SRAM address of the TST in use */
+ volatile int tst_free_entries;
+ vc_map vcmap[NS_MAX_RCTSIZE];
+ vc_map *tste2vc[NS_TST_NUM_ENTRIES];
+ vc_map *scd2vc[NS_FRSCD_NUM];
+ buf_nr sbnr;
+ buf_nr lbnr;
+ buf_nr hbnr;
+ buf_nr iovnr;
+ int sbfqc;
+ int lbfqc;
+ struct sk_buff *sm_handle;
+ u32 sm_addr;
+ struct sk_buff *lg_handle;
+ u32 lg_addr;
+ struct sk_buff *rcbuf; /* Current raw cell buffer */
+ struct ns_rcqe *rawcell;
+ u32 rawch; /* Raw cell queue head */
+ unsigned intcnt; /* Interrupt counter */
+ spinlock_t int_lock; /* Interrupt lock */
+ spinlock_t res_lock; /* Card resource lock */
} ns_dev;
-
/* NOTE: Each tste2vc entry relates a given TST entry to the corresponding
- CBR vc. If the entry is not allocated, it must be NULL.
-
- There are two TSTs so the driver can modify them on the fly
- without stopping the transmission.
-
- scd2vc allows us to find out unused fixed rate SCDs, because
- they must have a NULL pointer here. */
+ CBR vc. If the entry is not allocated, it must be NULL.
+
+ There are two TSTs so the driver can modify them on the fly
+ without stopping the transmission.
+ scd2vc allows us to find out unused fixed rate SCDs, because
+ they must have a NULL pointer here. */
#endif /* _LINUX_NICSTAR_H_ */
diff --git a/drivers/atm/nicstarmac.c b/drivers/atm/nicstarmac.c
index 842e26c4555..f594526f8c6 100644
--- a/drivers/atm/nicstarmac.c
+++ b/drivers/atm/nicstarmac.c
@@ -13,15 +13,15 @@ typedef void __iomem *virt_addr_t;
#define CYCLE_DELAY 5
-/* This was the original definition
+/*
+ This was the original definition
#define osp_MicroDelay(microsec) \
do { int _i = 4*microsec; while (--_i > 0) { __SLOW_DOWN_IO; }} while (0)
*/
#define osp_MicroDelay(microsec) {unsigned long useconds = (microsec); \
udelay((useconds));}
-
-
-/* The following tables represent the timing diagrams found in
+/*
+ * The following tables represent the timing diagrams found in
* the Data Sheet for the Xicor X25020 EEProm. The #defines below
* represent the bits in the NICStAR's General Purpose register
* that must be toggled for the corresponding actions on the EEProm
@@ -31,86 +31,80 @@ typedef void __iomem *virt_addr_t;
/* Write Data To EEProm from SI line on rising edge of CLK */
/* Read Data From EEProm on falling edge of CLK */
-#define CS_HIGH 0x0002 /* Chip select high */
-#define CS_LOW 0x0000 /* Chip select low (active low)*/
-#define CLK_HIGH 0x0004 /* Clock high */
-#define CLK_LOW 0x0000 /* Clock low */
-#define SI_HIGH 0x0001 /* Serial input data high */
-#define SI_LOW 0x0000 /* Serial input data low */
+#define CS_HIGH 0x0002 /* Chip select high */
+#define CS_LOW 0x0000 /* Chip select low (active low) */
+#define CLK_HIGH 0x0004 /* Clock high */
+#define CLK_LOW 0x0000 /* Clock low */
+#define SI_HIGH 0x0001 /* Serial input data high */
+#define SI_LOW 0x0000 /* Serial input data low */
/* Read Status Register = 0000 0101b */
#if 0
-static u_int32_t rdsrtab[] =
-{
- CS_HIGH | CLK_HIGH,
- CS_LOW | CLK_LOW,
- CLK_HIGH, /* 0 */
- CLK_LOW,
- CLK_HIGH, /* 0 */
- CLK_LOW,
- CLK_HIGH, /* 0 */
- CLK_LOW,
- CLK_HIGH, /* 0 */
- CLK_LOW,
- CLK_HIGH, /* 0 */
- CLK_LOW | SI_HIGH,
- CLK_HIGH | SI_HIGH, /* 1 */
- CLK_LOW | SI_LOW,
- CLK_HIGH, /* 0 */
- CLK_LOW | SI_HIGH,
- CLK_HIGH | SI_HIGH /* 1 */
+static u_int32_t rdsrtab[] = {
+ CS_HIGH | CLK_HIGH,
+ CS_LOW | CLK_LOW,
+ CLK_HIGH, /* 0 */
+ CLK_LOW,
+ CLK_HIGH, /* 0 */
+ CLK_LOW,
+ CLK_HIGH, /* 0 */
+ CLK_LOW,
+ CLK_HIGH, /* 0 */
+ CLK_LOW,
+ CLK_HIGH, /* 0 */
+ CLK_LOW | SI_HIGH,
+ CLK_HIGH | SI_HIGH, /* 1 */
+ CLK_LOW | SI_LOW,
+ CLK_HIGH, /* 0 */
+ CLK_LOW | SI_HIGH,
+ CLK_HIGH | SI_HIGH /* 1 */
};
-#endif /* 0 */
-
+#endif /* 0 */
/* Read from EEPROM = 0000 0011b */
-static u_int32_t readtab[] =
-{
- /*
- CS_HIGH | CLK_HIGH,
- */
- CS_LOW | CLK_LOW,
- CLK_HIGH, /* 0 */
- CLK_LOW,
- CLK_HIGH, /* 0 */
- CLK_LOW,
- CLK_HIGH, /* 0 */
- CLK_LOW,
- CLK_HIGH, /* 0 */
- CLK_LOW,
- CLK_HIGH, /* 0 */
- CLK_LOW,
- CLK_HIGH, /* 0 */
- CLK_LOW | SI_HIGH,
- CLK_HIGH | SI_HIGH, /* 1 */
- CLK_LOW | SI_HIGH,
- CLK_HIGH | SI_HIGH /* 1 */
+static u_int32_t readtab[] = {
+ /*
+ CS_HIGH | CLK_HIGH,
+ */
+ CS_LOW | CLK_LOW,
+ CLK_HIGH, /* 0 */
+ CLK_LOW,
+ CLK_HIGH, /* 0 */
+ CLK_LOW,
+ CLK_HIGH, /* 0 */
+ CLK_LOW,
+ CLK_HIGH, /* 0 */
+ CLK_LOW,
+ CLK_HIGH, /* 0 */
+ CLK_LOW,
+ CLK_HIGH, /* 0 */
+ CLK_LOW | SI_HIGH,
+ CLK_HIGH | SI_HIGH, /* 1 */
+ CLK_LOW | SI_HIGH,
+ CLK_HIGH | SI_HIGH /* 1 */
};
-
/* Clock to read from/write to the eeprom */
-static u_int32_t clocktab[] =
-{
- CLK_LOW,
- CLK_HIGH,
- CLK_LOW,
- CLK_HIGH,
- CLK_LOW,
- CLK_HIGH,
- CLK_LOW,
- CLK_HIGH,
- CLK_LOW,
- CLK_HIGH,
- CLK_LOW,
- CLK_HIGH,
- CLK_LOW,
- CLK_HIGH,
- CLK_LOW,
- CLK_HIGH,
- CLK_LOW
+static u_int32_t clocktab[] = {
+ CLK_LOW,
+ CLK_HIGH,
+ CLK_LOW,
+ CLK_HIGH,
+ CLK_LOW,
+ CLK_HIGH,
+ CLK_LOW,
+ CLK_HIGH,
+ CLK_LOW,
+ CLK_HIGH,
+ CLK_LOW,
+ CLK_HIGH,
+ CLK_LOW,
+ CLK_HIGH,
+ CLK_LOW,
+ CLK_HIGH,
+ CLK_LOW
};
-
#define NICSTAR_REG_WRITE(bs, reg, val) \
while ( readl(bs + STAT) & 0x0200 ) ; \
writel((val),(base)+(reg))
@@ -124,153 +118,131 @@ static u_int32_t clocktab[] =
* register.
*/
#if 0
-u_int32_t
-nicstar_read_eprom_status( virt_addr_t base )
+u_int32_t nicstar_read_eprom_status(virt_addr_t base)
{
- u_int32_t val;
- u_int32_t rbyte;
- int32_t i, j;
-
- /* Send read instruction */
- val = NICSTAR_REG_READ( base, NICSTAR_REG_GENERAL_PURPOSE ) & 0xFFFFFFF0;
-
- for (i=0; i<ARRAY_SIZE(rdsrtab); i++)
- {
- NICSTAR_REG_WRITE( base, NICSTAR_REG_GENERAL_PURPOSE,
- (val | rdsrtab[i]) );
- osp_MicroDelay( CYCLE_DELAY );
- }
-
- /* Done sending instruction - now pull data off of bit 16, MSB first */
- /* Data clocked out of eeprom on falling edge of clock */
-
- rbyte = 0;
- for (i=7, j=0; i>=0; i--)
- {
- NICSTAR_REG_WRITE( base, NICSTAR_REG_GENERAL_PURPOSE,
- (val | clocktab[j++]) );
- rbyte |= (((NICSTAR_REG_READ( base, NICSTAR_REG_GENERAL_PURPOSE)
- & 0x00010000) >> 16) << i);
- NICSTAR_REG_WRITE( base, NICSTAR_REG_GENERAL_PURPOSE,
- (val | clocktab[j++]) );
- osp_MicroDelay( CYCLE_DELAY );
- }
- NICSTAR_REG_WRITE( base, NICSTAR_REG_GENERAL_PURPOSE, 2 );
- osp_MicroDelay( CYCLE_DELAY );
- return rbyte;
+ u_int32_t val;
+ u_int32_t rbyte;
+ int32_t i, j;
+
+ /* Send read instruction */
+ val = NICSTAR_REG_READ(base, NICSTAR_REG_GENERAL_PURPOSE) & 0xFFFFFFF0;
+
+ for (i = 0; i < ARRAY_SIZE(rdsrtab); i++) {
+ NICSTAR_REG_WRITE(base, NICSTAR_REG_GENERAL_PURPOSE,
+ (val | rdsrtab[i]));
+ osp_MicroDelay(CYCLE_DELAY);
+ }
+
+ /* Done sending instruction - now pull data off of bit 16, MSB first */
+ /* Data clocked out of eeprom on falling edge of clock */
+
+ rbyte = 0;
+ for (i = 7, j = 0; i >= 0; i--) {
+ NICSTAR_REG_WRITE(base, NICSTAR_REG_GENERAL_PURPOSE,
+ (val | clocktab[j++]));
+ rbyte |= (((NICSTAR_REG_READ(base, NICSTAR_REG_GENERAL_PURPOSE)
+ & 0x00010000) >> 16) << i);
+ NICSTAR_REG_WRITE(base, NICSTAR_REG_GENERAL_PURPOSE,
+ (val | clocktab[j++]));
+ osp_MicroDelay(CYCLE_DELAY);
+ }
+ NICSTAR_REG_WRITE(base, NICSTAR_REG_GENERAL_PURPOSE, 2);
+ osp_MicroDelay(CYCLE_DELAY);
+ return rbyte;
}
-#endif /* 0 */
-
+#endif /* 0 */
/*
* This routine will clock the Read_data function into the X2520
* eeprom, followed by the address to read from, through the NicSTaR's General
* Purpose register.
*/
-
-static u_int8_t
-read_eprom_byte(virt_addr_t base, u_int8_t offset)
+
+static u_int8_t read_eprom_byte(virt_addr_t base, u_int8_t offset)
{
- u_int32_t val = 0;
- int i,j=0;
- u_int8_t tempread = 0;
-
- val = NICSTAR_REG_READ( base, NICSTAR_REG_GENERAL_PURPOSE ) & 0xFFFFFFF0;
-
- /* Send READ instruction */
- for (i=0; i<ARRAY_SIZE(readtab); i++)
- {
- NICSTAR_REG_WRITE( base, NICSTAR_REG_GENERAL_PURPOSE,
- (val | readtab[i]) );
- osp_MicroDelay( CYCLE_DELAY );
- }
-
- /* Next, we need to send the byte address to read from */
- for (i=7; i>=0; i--)
- {
- NICSTAR_REG_WRITE( base, NICSTAR_REG_GENERAL_PURPOSE,
- (val | clocktab[j++] | ((offset >> i) & 1) ) );
- osp_MicroDelay(CYCLE_DELAY);
- NICSTAR_REG_WRITE( base, NICSTAR_REG_GENERAL_PURPOSE,
- (val | clocktab[j++] | ((offset >> i) & 1) ) );
- osp_MicroDelay( CYCLE_DELAY );
- }
-
- j = 0;
-
- /* Now, we can read data from the eeprom by clocking it in */
- for (i=7; i>=0; i--)
- {
- NICSTAR_REG_WRITE( base, NICSTAR_REG_GENERAL_PURPOSE,
- (val | clocktab[j++]) );
- osp_MicroDelay( CYCLE_DELAY );
- tempread |= (((NICSTAR_REG_READ( base, NICSTAR_REG_GENERAL_PURPOSE )
- & 0x00010000) >> 16) << i);
- NICSTAR_REG_WRITE( base, NICSTAR_REG_GENERAL_PURPOSE,
- (val | clocktab[j++]) );
- osp_MicroDelay( CYCLE_DELAY );
- }
-
- NICSTAR_REG_WRITE( base, NICSTAR_REG_GENERAL_PURPOSE, 2 );
- osp_MicroDelay( CYCLE_DELAY );
- return tempread;
+ u_int32_t val = 0;
+ int i, j = 0;
+ u_int8_t tempread = 0;
+
+ val = NICSTAR_REG_READ(base, NICSTAR_REG_GENERAL_PURPOSE) & 0xFFFFFFF0;
+
+ /* Send READ instruction */
+ for (i = 0; i < ARRAY_SIZE(readtab); i++) {
+ NICSTAR_REG_WRITE(base, NICSTAR_REG_GENERAL_PURPOSE,
+ (val | readtab[i]));
+ osp_MicroDelay(CYCLE_DELAY);
+ }
+
+ /* Next, we need to send the byte address to read from */
+ for (i = 7; i >= 0; i--) {
+ NICSTAR_REG_WRITE(base, NICSTAR_REG_GENERAL_PURPOSE,
+ (val | clocktab[j++] | ((offset >> i) & 1)));
+ osp_MicroDelay(CYCLE_DELAY);
+ NICSTAR_REG_WRITE(base, NICSTAR_REG_GENERAL_PURPOSE,
+ (val | clocktab[j++] | ((offset >> i) & 1)));
+ osp_MicroDelay(CYCLE_DELAY);
+ }
+
+ j = 0;
+
+ /* Now, we can read data from the eeprom by clocking it in */
+ for (i = 7; i >= 0; i--) {
+ NICSTAR_REG_WRITE(base, NICSTAR_REG_GENERAL_PURPOSE,
+ (val | clocktab[j++]));
+ osp_MicroDelay(CYCLE_DELAY);
+ tempread |=
+ (((NICSTAR_REG_READ(base, NICSTAR_REG_GENERAL_PURPOSE)
+ & 0x00010000) >> 16) << i);
+ NICSTAR_REG_WRITE(base, NICSTAR_REG_GENERAL_PURPOSE,
+ (val | clocktab[j++]));
+ osp_MicroDelay(CYCLE_DELAY);
+ }
+
+ NICSTAR_REG_WRITE(base, NICSTAR_REG_GENERAL_PURPOSE, 2);
+ osp_MicroDelay(CYCLE_DELAY);
+ return tempread;
}
-
-static void
-nicstar_init_eprom( virt_addr_t base )
+static void nicstar_init_eprom(virt_addr_t base)
{
- u_int32_t val;
+ u_int32_t val;
- /*
- * turn chip select off
- */
- val = NICSTAR_REG_READ(base, NICSTAR_REG_GENERAL_PURPOSE) & 0xFFFFFFF0;
+ /*
+ * turn chip select off
+ */
+ val = NICSTAR_REG_READ(base, NICSTAR_REG_GENERAL_PURPOSE) & 0xFFFFFFF0;
- NICSTAR_REG_WRITE(base, NICSTAR_REG_GENERAL_PURPOSE,
- (val | CS_HIGH | CLK_HIGH));
- osp_MicroDelay( CYCLE_DELAY );
+ NICSTAR_REG_WRITE(base, NICSTAR_REG_GENERAL_PURPOSE,
+ (val | CS_HIGH | CLK_HIGH));
+ osp_MicroDelay(CYCLE_DELAY);
- NICSTAR_REG_WRITE(base, NICSTAR_REG_GENERAL_PURPOSE,
- (val | CS_HIGH | CLK_LOW));
- osp_MicroDelay( CYCLE_DELAY );
+ NICSTAR_REG_WRITE(base, NICSTAR_REG_GENERAL_PURPOSE,
+ (val | CS_HIGH | CLK_LOW));
+ osp_MicroDelay(CYCLE_DELAY);
- NICSTAR_REG_WRITE(base, NICSTAR_REG_GENERAL_PURPOSE,
- (val | CS_HIGH | CLK_HIGH));
- osp_MicroDelay( CYCLE_DELAY );
+ NICSTAR_REG_WRITE(base, NICSTAR_REG_GENERAL_PURPOSE,
+ (val | CS_HIGH | CLK_HIGH));
+ osp_MicroDelay(CYCLE_DELAY);
- NICSTAR_REG_WRITE(base, NICSTAR_REG_GENERAL_PURPOSE,
- (val | CS_HIGH | CLK_LOW));
- osp_MicroDelay( CYCLE_DELAY );
+ NICSTAR_REG_WRITE(base, NICSTAR_REG_GENERAL_PURPOSE,
+ (val | CS_HIGH | CLK_LOW));
+ osp_MicroDelay(CYCLE_DELAY);
}
-
/*
* This routine will be the interface to the ReadPromByte function
* above.
- */
+ */
static void
-nicstar_read_eprom(
- virt_addr_t base,
- u_int8_t prom_offset,
- u_int8_t *buffer,
- u_int32_t nbytes )
+nicstar_read_eprom(virt_addr_t base,
+ u_int8_t prom_offset, u_int8_t * buffer, u_int32_t nbytes)
{
- u_int i;
-
- for (i=0; i<nbytes; i++)
- {
- buffer[i] = read_eprom_byte( base, prom_offset );
- ++prom_offset;
- osp_MicroDelay( CYCLE_DELAY );
- }
-}
-
+ u_int i;
-/*
-void osp_MicroDelay(int x) {
-
+ for (i = 0; i < nbytes; i++) {
+ buffer[i] = read_eprom_byte(base, prom_offset);
+ ++prom_offset;
+ osp_MicroDelay(CYCLE_DELAY);
+ }
}
-*/
-
diff --git a/drivers/atm/solos-pci.c b/drivers/atm/solos-pci.c
index ded76c4c9f4..6174965d9a4 100644
--- a/drivers/atm/solos-pci.c
+++ b/drivers/atm/solos-pci.c
@@ -383,7 +383,7 @@ static int process_status(struct solos_card *card, int port, struct sk_buff *skb
/* Anything but 'Showtime' is down */
if (strcmp(state_str, "Showtime")) {
- card->atmdev[port]->signal = ATM_PHY_SIG_LOST;
+ atm_dev_signal_change(card->atmdev[port], ATM_PHY_SIG_LOST);
release_vccs(card->atmdev[port]);
dev_info(&card->dev->dev, "Port %d: %s\n", port, state_str);
return 0;
@@ -401,7 +401,7 @@ static int process_status(struct solos_card *card, int port, struct sk_buff *skb
snr[0]?", SNR ":"", snr, attn[0]?", Attn ":"", attn);
card->atmdev[port]->link_rate = rate_down / 424;
- card->atmdev[port]->signal = ATM_PHY_SIG_FOUND;
+ atm_dev_signal_change(card->atmdev[port], ATM_PHY_SIG_FOUND);
return 0;
}
@@ -1246,7 +1246,7 @@ static int atm_init(struct solos_card *card)
card->atmdev[i]->ci_range.vci_bits = 16;
card->atmdev[i]->dev_data = card;
card->atmdev[i]->phy_data = (void *)(unsigned long)i;
- card->atmdev[i]->signal = ATM_PHY_SIG_UNKNOWN;
+ atm_dev_signal_change(card->atmdev[i], ATM_PHY_SIG_UNKNOWN);
skb = alloc_skb(sizeof(*header), GFP_ATOMIC);
if (!skb) {
diff --git a/drivers/atm/suni.c b/drivers/atm/suni.c
index da4b91ffa53..41c56eae4c8 100644
--- a/drivers/atm/suni.c
+++ b/drivers/atm/suni.c
@@ -291,8 +291,9 @@ static int suni_ioctl(struct atm_dev *dev,unsigned int cmd,void __user *arg)
static void poll_los(struct atm_dev *dev)
{
- dev->signal = GET(RSOP_SIS) & SUNI_RSOP_SIS_LOSV ? ATM_PHY_SIG_LOST :
- ATM_PHY_SIG_FOUND;
+ atm_dev_signal_change(dev,
+ GET(RSOP_SIS) & SUNI_RSOP_SIS_LOSV ?
+ ATM_PHY_SIG_LOST : ATM_PHY_SIG_FOUND);
}
diff --git a/drivers/atm/zatm.c b/drivers/atm/zatm.c
index 702accec89e..4e885d2da49 100644
--- a/drivers/atm/zatm.c
+++ b/drivers/atm/zatm.c
@@ -1637,10 +1637,8 @@ out_free:
MODULE_LICENSE("GPL");
static struct pci_device_id zatm_pci_tbl[] __devinitdata = {
- { PCI_VENDOR_ID_ZEITNET, PCI_DEVICE_ID_ZEITNET_1221,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, ZATM_COPPER },
- { PCI_VENDOR_ID_ZEITNET, PCI_DEVICE_ID_ZEITNET_1225,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+ { PCI_VDEVICE(ZEITNET, PCI_DEVICE_ID_ZEITNET_1221), ZATM_COPPER },
+ { PCI_VDEVICE(ZEITNET, PCI_DEVICE_ID_ZEITNET_1225), 0 },
{ 0, }
};
MODULE_DEVICE_TABLE(pci, zatm_pci_tbl);
diff --git a/drivers/base/bus.c b/drivers/base/bus.c
index 12eec3f633b..eb1b7fa20dc 100644
--- a/drivers/base/bus.c
+++ b/drivers/base/bus.c
@@ -945,8 +945,8 @@ bus_devices_fail:
bus_remove_file(bus, &bus_attr_uevent);
bus_uevent_fail:
kset_unregister(&bus->p->subsys);
- kfree(bus->p);
out:
+ kfree(bus->p);
bus->p = NULL;
return retval;
}
diff --git a/drivers/base/core.c b/drivers/base/core.c
index 9b9d3bd54e3..d1b2c9adc27 100644
--- a/drivers/base/core.c
+++ b/drivers/base/core.c
@@ -1599,7 +1599,7 @@ EXPORT_SYMBOL_GPL(device_destroy);
* on the same device to ensure that new_name is valid and
* won't conflict with other devices.
*/
-int device_rename(struct device *dev, char *new_name)
+int device_rename(struct device *dev, const char *new_name)
{
char *old_class_name = NULL;
char *new_class_name = NULL;
@@ -1819,3 +1819,67 @@ void device_shutdown(void)
spin_unlock(&devices_kset->list_lock);
async_synchronize_full();
}
+
+/*
+ * Device logging functions
+ */
+
+#ifdef CONFIG_PRINTK
+
+static int __dev_printk(const char *level, const struct device *dev,
+ struct va_format *vaf)
+{
+ if (!dev)
+ return printk("%s(NULL device *): %pV", level, vaf);
+
+ return printk("%s%s %s: %pV",
+ level, dev_driver_string(dev), dev_name(dev), vaf);
+}
+
+int dev_printk(const char *level, const struct device *dev,
+ const char *fmt, ...)
+{
+ struct va_format vaf;
+ va_list args;
+ int r;
+
+ va_start(args, fmt);
+
+ vaf.fmt = fmt;
+ vaf.va = &args;
+
+ r = __dev_printk(level, dev, &vaf);
+ va_end(args);
+
+ return r;
+}
+EXPORT_SYMBOL(dev_printk);
+
+#define define_dev_printk_level(func, kern_level) \
+int func(const struct device *dev, const char *fmt, ...) \
+{ \
+ struct va_format vaf; \
+ va_list args; \
+ int r; \
+ \
+ va_start(args, fmt); \
+ \
+ vaf.fmt = fmt; \
+ vaf.va = &args; \
+ \
+ r = __dev_printk(kern_level, dev, &vaf); \
+ va_end(args); \
+ \
+ return r; \
+} \
+EXPORT_SYMBOL(func);
+
+define_dev_printk_level(dev_emerg, KERN_EMERG);
+define_dev_printk_level(dev_alert, KERN_ALERT);
+define_dev_printk_level(dev_crit, KERN_CRIT);
+define_dev_printk_level(dev_err, KERN_ERR);
+define_dev_printk_level(dev_warn, KERN_WARNING);
+define_dev_printk_level(dev_notice, KERN_NOTICE);
+define_dev_printk_level(_dev_info, KERN_INFO);
+
+#endif
diff --git a/drivers/base/dd.c b/drivers/base/dd.c
index 503c2620bbc..da57ee9d63f 100644
--- a/drivers/base/dd.c
+++ b/drivers/base/dd.c
@@ -51,6 +51,10 @@ static int driver_sysfs_add(struct device *dev)
{
int ret;
+ if (dev->bus)
+ blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
+ BUS_NOTIFY_BIND_DRIVER, dev);
+
ret = sysfs_create_link(&dev->driver->p->kobj, &dev->kobj,
kobject_name(&dev->kobj));
if (ret == 0) {
diff --git a/drivers/base/dma-coherent.c b/drivers/base/dma-coherent.c
index d4d8ce53886..f369e279598 100644
--- a/drivers/base/dma-coherent.c
+++ b/drivers/base/dma-coherent.c
@@ -8,7 +8,7 @@
struct dma_coherent_mem {
void *virt_base;
- u32 device_base;
+ dma_addr_t device_base;
int size;
int flags;
unsigned long *bitmap;
diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c
index 3f093b0dd21..c8a44f5e058 100644
--- a/drivers/base/firmware_class.c
+++ b/drivers/base/firmware_class.c
@@ -87,29 +87,32 @@ static DEFINE_MUTEX(fw_lock);
struct firmware_priv {
struct completion completion;
- struct bin_attribute attr_data;
struct firmware *fw;
unsigned long status;
struct page **pages;
int nr_pages;
int page_array_size;
struct timer_list timeout;
+ struct device dev;
bool nowait;
char fw_id[];
};
-static void
-fw_load_abort(struct firmware_priv *fw_priv)
+static struct firmware_priv *to_firmware_priv(struct device *dev)
+{
+ return container_of(dev, struct firmware_priv, dev);
+}
+
+static void fw_load_abort(struct firmware_priv *fw_priv)
{
set_bit(FW_STATUS_ABORT, &fw_priv->status);
wmb();
complete(&fw_priv->completion);
}
-static ssize_t
-firmware_timeout_show(struct class *class,
- struct class_attribute *attr,
- char *buf)
+static ssize_t firmware_timeout_show(struct class *class,
+ struct class_attribute *attr,
+ char *buf)
{
return sprintf(buf, "%d\n", loading_timeout);
}
@@ -127,14 +130,14 @@ firmware_timeout_show(struct class *class,
*
* Note: zero means 'wait forever'.
**/
-static ssize_t
-firmware_timeout_store(struct class *class,
- struct class_attribute *attr,
- const char *buf, size_t count)
+static ssize_t firmware_timeout_store(struct class *class,
+ struct class_attribute *attr,
+ const char *buf, size_t count)
{
loading_timeout = simple_strtol(buf, NULL, 10);
if (loading_timeout < 0)
loading_timeout = 0;
+
return count;
}
@@ -146,21 +149,20 @@ static struct class_attribute firmware_class_attrs[] = {
static void fw_dev_release(struct device *dev)
{
- struct firmware_priv *fw_priv = dev_get_drvdata(dev);
+ struct firmware_priv *fw_priv = to_firmware_priv(dev);
int i;
for (i = 0; i < fw_priv->nr_pages; i++)
__free_page(fw_priv->pages[i]);
kfree(fw_priv->pages);
kfree(fw_priv);
- kfree(dev);
module_put(THIS_MODULE);
}
static int firmware_uevent(struct device *dev, struct kobj_uevent_env *env)
{
- struct firmware_priv *fw_priv = dev_get_drvdata(dev);
+ struct firmware_priv *fw_priv = to_firmware_priv(dev);
if (add_uevent_var(env, "FIRMWARE=%s", fw_priv->fw_id))
return -ENOMEM;
@@ -182,8 +184,9 @@ static struct class firmware_class = {
static ssize_t firmware_loading_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct firmware_priv *fw_priv = dev_get_drvdata(dev);
+ struct firmware_priv *fw_priv = to_firmware_priv(dev);
int loading = test_bit(FW_STATUS_LOADING, &fw_priv->status);
+
return sprintf(buf, "%d\n", loading);
}
@@ -219,7 +222,7 @@ static ssize_t firmware_loading_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
- struct firmware_priv *fw_priv = dev_get_drvdata(dev);
+ struct firmware_priv *fw_priv = to_firmware_priv(dev);
int loading = simple_strtol(buf, NULL, 10);
int i;
@@ -277,13 +280,12 @@ 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 file *filp, struct kobject *kobj,
- struct bin_attribute *bin_attr, char *buffer, loff_t offset,
- size_t count)
+static ssize_t firmware_data_read(struct file *filp, struct kobject *kobj,
+ struct bin_attribute *bin_attr,
+ char *buffer, loff_t offset, size_t count)
{
struct device *dev = to_dev(kobj);
- struct firmware_priv *fw_priv = dev_get_drvdata(dev);
+ struct firmware_priv *fw_priv = to_firmware_priv(dev);
struct firmware *fw;
ssize_t ret_count;
@@ -322,8 +324,7 @@ out:
return ret_count;
}
-static int
-fw_realloc_buffer(struct firmware_priv *fw_priv, int min_size)
+static int fw_realloc_buffer(struct firmware_priv *fw_priv, int min_size)
{
int pages_needed = ALIGN(min_size, PAGE_SIZE) >> PAGE_SHIFT;
@@ -373,13 +374,12 @@ fw_realloc_buffer(struct firmware_priv *fw_priv, int min_size)
* Data written to the 'data' attribute will be later handed to
* the driver as a firmware image.
**/
-static ssize_t
-firmware_data_write(struct file* filp, struct kobject *kobj,
- struct bin_attribute *bin_attr, char *buffer,
- loff_t offset, size_t count)
+static ssize_t firmware_data_write(struct file *filp, struct kobject *kobj,
+ struct bin_attribute *bin_attr,
+ char *buffer, loff_t offset, size_t count)
{
struct device *dev = to_dev(kobj);
- struct firmware_priv *fw_priv = dev_get_drvdata(dev);
+ struct firmware_priv *fw_priv = to_firmware_priv(dev);
struct firmware *fw;
ssize_t retval;
@@ -420,116 +420,103 @@ out:
return retval;
}
-static struct bin_attribute firmware_attr_data_tmpl = {
- .attr = {.name = "data", .mode = 0644},
+static struct bin_attribute firmware_attr_data = {
+ .attr = { .name = "data", .mode = 0644 },
.size = 0,
.read = firmware_data_read,
.write = firmware_data_write,
};
-static void
-firmware_class_timeout(u_long data)
+static void firmware_class_timeout(u_long data)
{
struct firmware_priv *fw_priv = (struct firmware_priv *) data;
+
fw_load_abort(fw_priv);
}
-static int fw_register_device(struct device **dev_p, const char *fw_name,
- struct device *device)
+static struct firmware_priv *
+fw_create_instance(struct firmware *firmware, const char *fw_name,
+ struct device *device, bool uevent, bool nowait)
{
- int retval;
- struct firmware_priv *fw_priv =
- kzalloc(sizeof(*fw_priv) + strlen(fw_name) + 1 , GFP_KERNEL);
- struct device *f_dev = kzalloc(sizeof(*f_dev), GFP_KERNEL);
-
- *dev_p = NULL;
+ struct firmware_priv *fw_priv;
+ struct device *f_dev;
+ int error;
- if (!fw_priv || !f_dev) {
+ fw_priv = kzalloc(sizeof(*fw_priv) + strlen(fw_name) + 1 , GFP_KERNEL);
+ if (!fw_priv) {
dev_err(device, "%s: kmalloc failed\n", __func__);
- retval = -ENOMEM;
- goto error_kfree;
+ error = -ENOMEM;
+ goto err_out;
}
+ fw_priv->fw = firmware;
+ fw_priv->nowait = nowait;
strcpy(fw_priv->fw_id, fw_name);
init_completion(&fw_priv->completion);
- fw_priv->attr_data = firmware_attr_data_tmpl;
- fw_priv->timeout.function = firmware_class_timeout;
- fw_priv->timeout.data = (u_long) fw_priv;
- init_timer(&fw_priv->timeout);
+ setup_timer(&fw_priv->timeout,
+ firmware_class_timeout, (u_long) fw_priv);
+ f_dev = &fw_priv->dev;
+
+ device_initialize(f_dev);
dev_set_name(f_dev, "%s", dev_name(device));
f_dev->parent = device;
f_dev->class = &firmware_class;
- dev_set_drvdata(f_dev, fw_priv);
- dev_set_uevent_suppress(f_dev, 1);
- retval = device_register(f_dev);
- if (retval) {
- dev_err(device, "%s: device_register failed\n", __func__);
- put_device(f_dev);
- return retval;
- }
- *dev_p = f_dev;
- return 0;
-
-error_kfree:
- kfree(f_dev);
- kfree(fw_priv);
- return retval;
-}
-static int fw_setup_device(struct firmware *fw, struct device **dev_p,
- const char *fw_name, struct device *device,
- int uevent, bool nowait)
-{
- struct device *f_dev;
- struct firmware_priv *fw_priv;
- int retval;
-
- *dev_p = NULL;
- retval = fw_register_device(&f_dev, fw_name, device);
- if (retval)
- goto out;
+ dev_set_uevent_suppress(f_dev, true);
/* Need to pin this module until class device is destroyed */
__module_get(THIS_MODULE);
- fw_priv = dev_get_drvdata(f_dev);
-
- fw_priv->nowait = nowait;
+ error = device_add(f_dev);
+ if (error) {
+ dev_err(device, "%s: device_register failed\n", __func__);
+ goto err_put_dev;
+ }
- fw_priv->fw = fw;
- sysfs_bin_attr_init(&fw_priv->attr_data);
- retval = sysfs_create_bin_file(&f_dev->kobj, &fw_priv->attr_data);
- if (retval) {
+ error = device_create_bin_file(f_dev, &firmware_attr_data);
+ if (error) {
dev_err(device, "%s: sysfs_create_bin_file failed\n", __func__);
- goto error_unreg;
+ goto err_del_dev;
}
- retval = device_create_file(f_dev, &dev_attr_loading);
- if (retval) {
+ error = device_create_file(f_dev, &dev_attr_loading);
+ if (error) {
dev_err(device, "%s: device_create_file failed\n", __func__);
- goto error_unreg;
+ goto err_del_bin_attr;
}
if (uevent)
- dev_set_uevent_suppress(f_dev, 0);
- *dev_p = f_dev;
- goto out;
+ dev_set_uevent_suppress(f_dev, false);
+
+ return fw_priv;
+
+err_del_bin_attr:
+ device_remove_bin_file(f_dev, &firmware_attr_data);
+err_del_dev:
+ device_del(f_dev);
+err_put_dev:
+ put_device(f_dev);
+err_out:
+ return ERR_PTR(error);
+}
+
+static void fw_destroy_instance(struct firmware_priv *fw_priv)
+{
+ struct device *f_dev = &fw_priv->dev;
-error_unreg:
+ device_remove_file(f_dev, &dev_attr_loading);
+ device_remove_bin_file(f_dev, &firmware_attr_data);
device_unregister(f_dev);
-out:
- return retval;
}
-static int
-_request_firmware(const struct firmware **firmware_p, const char *name,
- struct device *device, int uevent, bool nowait)
+static int _request_firmware(const struct firmware **firmware_p,
+ const char *name, struct device *device,
+ bool uevent, bool nowait)
{
- struct device *f_dev;
struct firmware_priv *fw_priv;
struct firmware *firmware;
- int retval;
+ int retval = 0;
if (!firmware_p)
return -EINVAL;
@@ -550,41 +537,40 @@ _request_firmware(const struct firmware **firmware_p, const char *name,
if (uevent)
dev_dbg(device, "firmware: requesting %s\n", name);
- retval = fw_setup_device(firmware, &f_dev, name, device,
- uevent, nowait);
- if (retval)
- goto error_kfree_fw;
-
- fw_priv = dev_get_drvdata(f_dev);
+ fw_priv = fw_create_instance(firmware, name, device, uevent, nowait);
+ if (IS_ERR(fw_priv)) {
+ retval = PTR_ERR(fw_priv);
+ goto out;
+ }
if (uevent) {
- if (loading_timeout > 0) {
- fw_priv->timeout.expires = jiffies + loading_timeout * HZ;
- add_timer(&fw_priv->timeout);
- }
+ if (loading_timeout > 0)
+ mod_timer(&fw_priv->timeout,
+ round_jiffies_up(jiffies +
+ loading_timeout * HZ));
+
+ kobject_uevent(&fw_priv->dev.kobj, KOBJ_ADD);
+ }
+
+ wait_for_completion(&fw_priv->completion);
- kobject_uevent(&f_dev->kobj, KOBJ_ADD);
- wait_for_completion(&fw_priv->completion);
- set_bit(FW_STATUS_DONE, &fw_priv->status);
- del_timer_sync(&fw_priv->timeout);
- } else
- wait_for_completion(&fw_priv->completion);
+ set_bit(FW_STATUS_DONE, &fw_priv->status);
+ del_timer_sync(&fw_priv->timeout);
mutex_lock(&fw_lock);
- if (!fw_priv->fw->size || test_bit(FW_STATUS_ABORT, &fw_priv->status)) {
+ if (!fw_priv->fw->size || test_bit(FW_STATUS_ABORT, &fw_priv->status))
retval = -ENOENT;
- release_firmware(fw_priv->fw);
- *firmware_p = NULL;
- }
fw_priv->fw = NULL;
mutex_unlock(&fw_lock);
- device_unregister(f_dev);
- goto out;
-error_kfree_fw:
- kfree(firmware);
- *firmware_p = NULL;
+ fw_destroy_instance(fw_priv);
+
out:
+ if (retval) {
+ release_firmware(firmware);
+ firmware_p = NULL;
+ }
+
return retval;
}
@@ -635,23 +621,24 @@ struct firmware_work {
int uevent;
};
-static int
-request_firmware_work_func(void *arg)
+static int request_firmware_work_func(void *arg)
{
struct firmware_work *fw_work = arg;
const struct firmware *fw;
int ret;
+
if (!arg) {
WARN_ON(1);
return 0;
}
- ret = _request_firmware(&fw, fw_work->name, fw_work->device,
- fw_work->uevent, true);
+ ret = _request_firmware(&fw, fw_work->name, fw_work->device,
+ fw_work->uevent, true);
fw_work->cont(fw, fw_work->context);
module_put(fw_work->module);
kfree(fw_work);
+
return ret;
}
@@ -679,34 +666,33 @@ request_firmware_nowait(
void (*cont)(const struct firmware *fw, void *context))
{
struct task_struct *task;
- struct firmware_work *fw_work = kmalloc(sizeof (struct firmware_work),
- gfp);
+ struct firmware_work *fw_work;
+ fw_work = kzalloc(sizeof (struct firmware_work), gfp);
if (!fw_work)
return -ENOMEM;
+
+ fw_work->module = module;
+ fw_work->name = name;
+ fw_work->device = device;
+ fw_work->context = context;
+ fw_work->cont = cont;
+ fw_work->uevent = uevent;
+
if (!try_module_get(module)) {
kfree(fw_work);
return -EFAULT;
}
- *fw_work = (struct firmware_work) {
- .module = module,
- .name = name,
- .device = device,
- .context = context,
- .cont = cont,
- .uevent = uevent,
- };
-
task = kthread_run(request_firmware_work_func, fw_work,
"firmware/%s", name);
-
if (IS_ERR(task)) {
fw_work->cont(NULL, fw_work->context);
module_put(fw_work->module);
kfree(fw_work);
return PTR_ERR(task);
}
+
return 0;
}
diff --git a/drivers/base/platform.c b/drivers/base/platform.c
index 4d99c8bdfed..c6c933f5810 100644
--- a/drivers/base/platform.c
+++ b/drivers/base/platform.c
@@ -12,6 +12,7 @@
#include <linux/string.h>
#include <linux/platform_device.h>
+#include <linux/of_device.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/dma-mapping.h>
@@ -191,13 +192,13 @@ int platform_device_add_resources(struct platform_device *pdev,
{
struct resource *r;
- r = kmalloc(sizeof(struct resource) * num, GFP_KERNEL);
+ r = kmemdup(res, sizeof(struct resource) * num, GFP_KERNEL);
if (r) {
- memcpy(r, res, sizeof(struct resource) * num);
pdev->resource = r;
pdev->num_resources = num;
+ return 0;
}
- return r ? 0 : -ENOMEM;
+ return -ENOMEM;
}
EXPORT_SYMBOL_GPL(platform_device_add_resources);
@@ -344,108 +345,56 @@ void platform_device_unregister(struct platform_device *pdev)
EXPORT_SYMBOL_GPL(platform_device_unregister);
/**
- * platform_device_register_simple - add a platform-level device and its resources
- * @name: base name of the device we're adding
- * @id: instance id
- * @res: set of resources that needs to be allocated for the device
- * @num: number of resources
+ * platform_device_register_resndata - add a platform-level device with
+ * resources and platform-specific data
*
- * This function creates a simple platform device that requires minimal
- * resource and memory management. Canned release function freeing memory
- * allocated for the device allows drivers using such devices to be
- * unloaded without waiting for the last reference to the device to be
- * dropped.
- *
- * This interface is primarily intended for use with legacy drivers which
- * probe hardware directly. Because such drivers create sysfs device nodes
- * themselves, rather than letting system infrastructure handle such device
- * enumeration tasks, they don't fully conform to the Linux driver model.
- * In particular, when such drivers are built as modules, they can't be
- * "hotplugged".
- *
- * Returns &struct platform_device pointer on success, or ERR_PTR() on error.
- */
-struct platform_device *platform_device_register_simple(const char *name,
- int id,
- const struct resource *res,
- unsigned int num)
-{
- struct platform_device *pdev;
- int retval;
-
- pdev = platform_device_alloc(name, id);
- if (!pdev) {
- retval = -ENOMEM;
- goto error;
- }
-
- if (num) {
- retval = platform_device_add_resources(pdev, res, num);
- if (retval)
- goto error;
- }
-
- retval = platform_device_add(pdev);
- if (retval)
- goto error;
-
- return pdev;
-
-error:
- platform_device_put(pdev);
- return ERR_PTR(retval);
-}
-EXPORT_SYMBOL_GPL(platform_device_register_simple);
-
-/**
- * platform_device_register_data - add a platform-level device with platform-specific data
* @parent: parent device for the device we're adding
* @name: base name of the device we're adding
* @id: instance id
+ * @res: set of resources that needs to be allocated for the device
+ * @num: number of resources
* @data: platform specific data for this platform device
* @size: size of platform specific data
*
- * This function creates a simple platform device that requires minimal
- * resource and memory management. Canned release function freeing memory
- * allocated for the device allows drivers using such devices to be
- * unloaded without waiting for the last reference to the device to be
- * dropped.
- *
* Returns &struct platform_device pointer on success, or ERR_PTR() on error.
*/
-struct platform_device *platform_device_register_data(
+struct platform_device *__init_or_module platform_device_register_resndata(
struct device *parent,
const char *name, int id,
+ const struct resource *res, unsigned int num,
const void *data, size_t size)
{
+ int ret = -ENOMEM;
struct platform_device *pdev;
- int retval;
pdev = platform_device_alloc(name, id);
- if (!pdev) {
- retval = -ENOMEM;
- goto error;
- }
+ if (!pdev)
+ goto err;
pdev->dev.parent = parent;
- if (size) {
- retval = platform_device_add_data(pdev, data, size);
- if (retval)
- goto error;
+ if (res) {
+ ret = platform_device_add_resources(pdev, res, num);
+ if (ret)
+ goto err;
}
- retval = platform_device_add(pdev);
- if (retval)
- goto error;
+ if (data) {
+ ret = platform_device_add_data(pdev, data, size);
+ if (ret)
+ goto err;
+ }
- return pdev;
+ ret = platform_device_add(pdev);
+ if (ret) {
+err:
+ platform_device_put(pdev);
+ return ERR_PTR(ret);
+ }
-error:
- platform_device_put(pdev);
- return ERR_PTR(retval);
+ return pdev;
}
-EXPORT_SYMBOL_GPL(platform_device_register_data);
+EXPORT_SYMBOL_GPL(platform_device_register_resndata);
static int platform_drv_probe(struct device *_dev)
{
@@ -635,6 +584,12 @@ static struct device_attribute platform_dev_attrs[] = {
static int platform_uevent(struct device *dev, struct kobj_uevent_env *env)
{
struct platform_device *pdev = to_platform_device(dev);
+ int rc;
+
+ /* Some devices have extra OF data and an OF-style MODALIAS */
+ rc = of_device_uevent(dev,env);
+ if (rc != -ENODEV)
+ return rc;
add_uevent_var(env, "MODALIAS=%s%s", PLATFORM_MODULE_PREFIX,
(pdev->id_entry) ? pdev->id_entry->name : pdev->name);
@@ -673,7 +628,11 @@ static int platform_match(struct device *dev, struct device_driver *drv)
struct platform_device *pdev = to_platform_device(dev);
struct platform_driver *pdrv = to_platform_driver(drv);
- /* match against the id table first */
+ /* Attempt an OF style match first */
+ if (of_driver_match_device(dev, drv))
+ return 1;
+
+ /* Then try to match against the id table */
if (pdrv->id_table)
return platform_match_id(pdrv->id_table, pdev) != NULL;
diff --git a/drivers/base/power/Makefile b/drivers/base/power/Makefile
index 89de75325ce..cbccf9a3cee 100644
--- a/drivers/base/power/Makefile
+++ b/drivers/base/power/Makefile
@@ -1,5 +1,5 @@
obj-$(CONFIG_PM) += sysfs.o
-obj-$(CONFIG_PM_SLEEP) += main.o
+obj-$(CONFIG_PM_SLEEP) += main.o wakeup.o
obj-$(CONFIG_PM_RUNTIME) += runtime.o
obj-$(CONFIG_PM_OPS) += generic_ops.o
obj-$(CONFIG_PM_TRACE_RTC) += trace.o
diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c
index 941fcb87e52..5419a49ff13 100644
--- a/drivers/base/power/main.c
+++ b/drivers/base/power/main.c
@@ -59,6 +59,7 @@ void device_pm_init(struct device *dev)
{
dev->power.status = DPM_ON;
init_completion(&dev->power.completion);
+ dev->power.wakeup_count = 0;
pm_runtime_init(dev);
}
diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c
index b0ec0e9f27e..b78c401ffa7 100644
--- a/drivers/base/power/runtime.c
+++ b/drivers/base/power/runtime.c
@@ -123,6 +123,45 @@ int pm_runtime_idle(struct device *dev)
}
EXPORT_SYMBOL_GPL(pm_runtime_idle);
+
+/**
+ * update_pm_runtime_accounting - Update the time accounting of power states
+ * @dev: Device to update the accounting for
+ *
+ * In order to be able to have time accounting of the various power states
+ * (as used by programs such as PowerTOP to show the effectiveness of runtime
+ * PM), we need to track the time spent in each state.
+ * update_pm_runtime_accounting must be called each time before the
+ * runtime_status field is updated, to account the time in the old state
+ * correctly.
+ */
+void update_pm_runtime_accounting(struct device *dev)
+{
+ unsigned long now = jiffies;
+ int delta;
+
+ delta = now - dev->power.accounting_timestamp;
+
+ if (delta < 0)
+ delta = 0;
+
+ dev->power.accounting_timestamp = now;
+
+ if (dev->power.disable_depth > 0)
+ return;
+
+ if (dev->power.runtime_status == RPM_SUSPENDED)
+ dev->power.suspended_jiffies += delta;
+ else
+ dev->power.active_jiffies += delta;
+}
+
+static void __update_runtime_status(struct device *dev, enum rpm_status status)
+{
+ update_pm_runtime_accounting(dev);
+ dev->power.runtime_status = status;
+}
+
/**
* __pm_runtime_suspend - Carry out run-time suspend of given device.
* @dev: Device to suspend.
@@ -197,7 +236,7 @@ int __pm_runtime_suspend(struct device *dev, bool from_wq)
goto repeat;
}
- dev->power.runtime_status = RPM_SUSPENDING;
+ __update_runtime_status(dev, RPM_SUSPENDING);
dev->power.deferred_resume = false;
if (dev->bus && dev->bus->pm && dev->bus->pm->runtime_suspend) {
@@ -228,7 +267,7 @@ int __pm_runtime_suspend(struct device *dev, bool from_wq)
}
if (retval) {
- dev->power.runtime_status = RPM_ACTIVE;
+ __update_runtime_status(dev, RPM_ACTIVE);
if (retval == -EAGAIN || retval == -EBUSY) {
if (dev->power.timer_expires == 0)
notify = true;
@@ -237,7 +276,7 @@ int __pm_runtime_suspend(struct device *dev, bool from_wq)
pm_runtime_cancel_pending(dev);
}
} else {
- dev->power.runtime_status = RPM_SUSPENDED;
+ __update_runtime_status(dev, RPM_SUSPENDED);
pm_runtime_deactivate_timer(dev);
if (dev->parent) {
@@ -381,7 +420,7 @@ int __pm_runtime_resume(struct device *dev, bool from_wq)
goto repeat;
}
- dev->power.runtime_status = RPM_RESUMING;
+ __update_runtime_status(dev, RPM_RESUMING);
if (dev->bus && dev->bus->pm && dev->bus->pm->runtime_resume) {
spin_unlock_irq(&dev->power.lock);
@@ -411,10 +450,10 @@ int __pm_runtime_resume(struct device *dev, bool from_wq)
}
if (retval) {
- dev->power.runtime_status = RPM_SUSPENDED;
+ __update_runtime_status(dev, RPM_SUSPENDED);
pm_runtime_cancel_pending(dev);
} else {
- dev->power.runtime_status = RPM_ACTIVE;
+ __update_runtime_status(dev, RPM_ACTIVE);
if (parent)
atomic_inc(&parent->power.child_count);
}
@@ -848,7 +887,7 @@ int __pm_runtime_set_status(struct device *dev, unsigned int status)
}
out_set:
- dev->power.runtime_status = status;
+ __update_runtime_status(dev, status);
dev->power.runtime_error = 0;
out:
spin_unlock_irqrestore(&dev->power.lock, flags);
@@ -1077,6 +1116,7 @@ void pm_runtime_init(struct device *dev)
dev->power.request_pending = false;
dev->power.request = RPM_REQ_NONE;
dev->power.deferred_resume = false;
+ dev->power.accounting_timestamp = jiffies;
INIT_WORK(&dev->power.work, pm_runtime_work);
dev->power.timer_expires = 0;
diff --git a/drivers/base/power/sysfs.c b/drivers/base/power/sysfs.c
index a4c33bc5125..e56b4388fe6 100644
--- a/drivers/base/power/sysfs.c
+++ b/drivers/base/power/sysfs.c
@@ -6,6 +6,7 @@
#include <linux/string.h>
#include <linux/pm_runtime.h>
#include <asm/atomic.h>
+#include <linux/jiffies.h>
#include "power.h"
/*
@@ -73,6 +74,8 @@
* device are known to the PM core. However, for some devices this
* attribute is set to "enabled" by bus type code or device drivers and in
* that cases it should be safe to leave the default value.
+ *
+ * wakeup_count - Report the number of wakeup events related to the device
*/
static const char enabled[] = "enabled";
@@ -108,6 +111,65 @@ static ssize_t control_store(struct device * dev, struct device_attribute *attr,
}
static DEVICE_ATTR(control, 0644, control_show, control_store);
+
+static ssize_t rtpm_active_time_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ int ret;
+ spin_lock_irq(&dev->power.lock);
+ update_pm_runtime_accounting(dev);
+ ret = sprintf(buf, "%i\n", jiffies_to_msecs(dev->power.active_jiffies));
+ spin_unlock_irq(&dev->power.lock);
+ return ret;
+}
+
+static DEVICE_ATTR(runtime_active_time, 0444, rtpm_active_time_show, NULL);
+
+static ssize_t rtpm_suspended_time_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ int ret;
+ spin_lock_irq(&dev->power.lock);
+ update_pm_runtime_accounting(dev);
+ ret = sprintf(buf, "%i\n",
+ jiffies_to_msecs(dev->power.suspended_jiffies));
+ spin_unlock_irq(&dev->power.lock);
+ return ret;
+}
+
+static DEVICE_ATTR(runtime_suspended_time, 0444, rtpm_suspended_time_show, NULL);
+
+static ssize_t rtpm_status_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ const char *p;
+
+ if (dev->power.runtime_error) {
+ p = "error\n";
+ } else if (dev->power.disable_depth) {
+ p = "unsupported\n";
+ } else {
+ switch (dev->power.runtime_status) {
+ case RPM_SUSPENDED:
+ p = "suspended\n";
+ break;
+ case RPM_SUSPENDING:
+ p = "suspending\n";
+ break;
+ case RPM_RESUMING:
+ p = "resuming\n";
+ break;
+ case RPM_ACTIVE:
+ p = "active\n";
+ break;
+ default:
+ return -EIO;
+ }
+ }
+ return sprintf(buf, p);
+}
+
+static DEVICE_ATTR(runtime_status, 0444, rtpm_status_show, NULL);
#endif
static ssize_t
@@ -144,6 +206,16 @@ wake_store(struct device * dev, struct device_attribute *attr,
static DEVICE_ATTR(wakeup, 0644, wake_show, wake_store);
+#ifdef CONFIG_PM_SLEEP
+static ssize_t wakeup_count_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return sprintf(buf, "%lu\n", dev->power.wakeup_count);
+}
+
+static DEVICE_ATTR(wakeup_count, 0444, wakeup_count_show, NULL);
+#endif
+
#ifdef CONFIG_PM_ADVANCED_DEBUG
#ifdef CONFIG_PM_RUNTIME
@@ -172,27 +244,8 @@ static ssize_t rtpm_enabled_show(struct device *dev,
return sprintf(buf, "enabled\n");
}
-static ssize_t rtpm_status_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- if (dev->power.runtime_error)
- return sprintf(buf, "error\n");
- switch (dev->power.runtime_status) {
- case RPM_SUSPENDED:
- return sprintf(buf, "suspended\n");
- case RPM_SUSPENDING:
- return sprintf(buf, "suspending\n");
- case RPM_RESUMING:
- return sprintf(buf, "resuming\n");
- case RPM_ACTIVE:
- return sprintf(buf, "active\n");
- }
- return -EIO;
-}
-
static DEVICE_ATTR(runtime_usage, 0444, rtpm_usagecount_show, NULL);
static DEVICE_ATTR(runtime_active_kids, 0444, rtpm_children_show, NULL);
-static DEVICE_ATTR(runtime_status, 0444, rtpm_status_show, NULL);
static DEVICE_ATTR(runtime_enabled, 0444, rtpm_enabled_show, NULL);
#endif
@@ -228,14 +281,19 @@ static DEVICE_ATTR(async, 0644, async_show, async_store);
static struct attribute * power_attrs[] = {
#ifdef CONFIG_PM_RUNTIME
&dev_attr_control.attr,
+ &dev_attr_runtime_status.attr,
+ &dev_attr_runtime_suspended_time.attr,
+ &dev_attr_runtime_active_time.attr,
#endif
&dev_attr_wakeup.attr,
+#ifdef CONFIG_PM_SLEEP
+ &dev_attr_wakeup_count.attr,
+#endif
#ifdef CONFIG_PM_ADVANCED_DEBUG
&dev_attr_async.attr,
#ifdef CONFIG_PM_RUNTIME
&dev_attr_runtime_usage.attr,
&dev_attr_runtime_active_kids.attr,
- &dev_attr_runtime_status.attr,
&dev_attr_runtime_enabled.attr,
#endif
#endif
diff --git a/drivers/base/power/wakeup.c b/drivers/base/power/wakeup.c
new file mode 100644
index 00000000000..eb594facfc3
--- /dev/null
+++ b/drivers/base/power/wakeup.c
@@ -0,0 +1,247 @@
+/*
+ * drivers/base/power/wakeup.c - System wakeup events framework
+ *
+ * Copyright (c) 2010 Rafael J. Wysocki <rjw@sisk.pl>, Novell Inc.
+ *
+ * This file is released under the GPLv2.
+ */
+
+#include <linux/device.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+#include <linux/capability.h>
+#include <linux/suspend.h>
+#include <linux/pm.h>
+
+/*
+ * If set, the suspend/hibernate code will abort transitions to a sleep state
+ * if wakeup events are registered during or immediately before the transition.
+ */
+bool events_check_enabled;
+
+/* The counter of registered wakeup events. */
+static unsigned long event_count;
+/* A preserved old value of event_count. */
+static unsigned long saved_event_count;
+/* The counter of wakeup events being processed. */
+static unsigned long events_in_progress;
+
+static DEFINE_SPINLOCK(events_lock);
+
+static void pm_wakeup_timer_fn(unsigned long data);
+
+static DEFINE_TIMER(events_timer, pm_wakeup_timer_fn, 0, 0);
+static unsigned long events_timer_expires;
+
+/*
+ * The functions below use the observation that each wakeup event starts a
+ * period in which the system should not be suspended. The moment this period
+ * will end depends on how the wakeup event is going to be processed after being
+ * detected and all of the possible cases can be divided into two distinct
+ * groups.
+ *
+ * First, a wakeup event may be detected by the same functional unit that will
+ * carry out the entire processing of it and possibly will pass it to user space
+ * for further processing. In that case the functional unit that has detected
+ * the event may later "close" the "no suspend" period associated with it
+ * directly as soon as it has been dealt with. The pair of pm_stay_awake() and
+ * pm_relax(), balanced with each other, is supposed to be used in such
+ * situations.
+ *
+ * Second, a wakeup event may be detected by one functional unit and processed
+ * by another one. In that case the unit that has detected it cannot really
+ * "close" the "no suspend" period associated with it, unless it knows in
+ * advance what's going to happen to the event during processing. This
+ * knowledge, however, may not be available to it, so it can simply specify time
+ * to wait before the system can be suspended and pass it as the second
+ * argument of pm_wakeup_event().
+ */
+
+/**
+ * pm_stay_awake - Notify the PM core that a wakeup event is being processed.
+ * @dev: Device the wakeup event is related to.
+ *
+ * Notify the PM core of a wakeup event (signaled by @dev) by incrementing the
+ * counter of wakeup events being processed. If @dev is not NULL, the counter
+ * of wakeup events related to @dev is incremented too.
+ *
+ * Call this function after detecting of a wakeup event if pm_relax() is going
+ * to be called directly after processing the event (and possibly passing it to
+ * user space for further processing).
+ *
+ * It is safe to call this function from interrupt context.
+ */
+void pm_stay_awake(struct device *dev)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&events_lock, flags);
+ if (dev)
+ dev->power.wakeup_count++;
+
+ events_in_progress++;
+ spin_unlock_irqrestore(&events_lock, flags);
+}
+
+/**
+ * pm_relax - Notify the PM core that processing of a wakeup event has ended.
+ *
+ * Notify the PM core that a wakeup event has been processed by decrementing
+ * the counter of wakeup events being processed and incrementing the counter
+ * of registered wakeup events.
+ *
+ * Call this function for wakeup events whose processing started with calling
+ * pm_stay_awake().
+ *
+ * It is safe to call it from interrupt context.
+ */
+void pm_relax(void)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&events_lock, flags);
+ if (events_in_progress) {
+ events_in_progress--;
+ event_count++;
+ }
+ spin_unlock_irqrestore(&events_lock, flags);
+}
+
+/**
+ * pm_wakeup_timer_fn - Delayed finalization of a wakeup event.
+ *
+ * Decrease the counter of wakeup events being processed after it was increased
+ * by pm_wakeup_event().
+ */
+static void pm_wakeup_timer_fn(unsigned long data)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&events_lock, flags);
+ if (events_timer_expires
+ && time_before_eq(events_timer_expires, jiffies)) {
+ events_in_progress--;
+ events_timer_expires = 0;
+ }
+ spin_unlock_irqrestore(&events_lock, flags);
+}
+
+/**
+ * pm_wakeup_event - Notify the PM core of a wakeup event.
+ * @dev: Device the wakeup event is related to.
+ * @msec: Anticipated event processing time (in milliseconds).
+ *
+ * Notify the PM core of a wakeup event (signaled by @dev) that will take
+ * approximately @msec milliseconds to be processed by the kernel. Increment
+ * the counter of registered wakeup events and (if @msec is nonzero) set up
+ * the wakeup events timer to execute pm_wakeup_timer_fn() in future (if the
+ * timer has not been set up already, increment the counter of wakeup events
+ * being processed). If @dev is not NULL, the counter of wakeup events related
+ * to @dev is incremented too.
+ *
+ * It is safe to call this function from interrupt context.
+ */
+void pm_wakeup_event(struct device *dev, unsigned int msec)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&events_lock, flags);
+ event_count++;
+ if (dev)
+ dev->power.wakeup_count++;
+
+ if (msec) {
+ unsigned long expires;
+
+ expires = jiffies + msecs_to_jiffies(msec);
+ if (!expires)
+ expires = 1;
+
+ if (!events_timer_expires
+ || time_after(expires, events_timer_expires)) {
+ if (!events_timer_expires)
+ events_in_progress++;
+
+ mod_timer(&events_timer, expires);
+ events_timer_expires = expires;
+ }
+ }
+ spin_unlock_irqrestore(&events_lock, flags);
+}
+
+/**
+ * pm_check_wakeup_events - Check for new wakeup events.
+ *
+ * Compare the current number of registered wakeup events with its preserved
+ * value from the past to check if new wakeup events have been registered since
+ * the old value was stored. Check if the current number of wakeup events being
+ * processed is zero.
+ */
+bool pm_check_wakeup_events(void)
+{
+ unsigned long flags;
+ bool ret = true;
+
+ spin_lock_irqsave(&events_lock, flags);
+ if (events_check_enabled) {
+ ret = (event_count == saved_event_count) && !events_in_progress;
+ events_check_enabled = ret;
+ }
+ spin_unlock_irqrestore(&events_lock, flags);
+ return ret;
+}
+
+/**
+ * pm_get_wakeup_count - Read the number of registered wakeup events.
+ * @count: Address to store the value at.
+ *
+ * Store the number of registered wakeup events at the address in @count. Block
+ * if the current number of wakeup events being processed is nonzero.
+ *
+ * Return false if the wait for the number of wakeup events being processed to
+ * drop down to zero has been interrupted by a signal (and the current number
+ * of wakeup events being processed is still nonzero). Otherwise return true.
+ */
+bool pm_get_wakeup_count(unsigned long *count)
+{
+ bool ret;
+
+ spin_lock_irq(&events_lock);
+ if (capable(CAP_SYS_ADMIN))
+ events_check_enabled = false;
+
+ while (events_in_progress && !signal_pending(current)) {
+ spin_unlock_irq(&events_lock);
+
+ schedule_timeout_interruptible(msecs_to_jiffies(100));
+
+ spin_lock_irq(&events_lock);
+ }
+ *count = event_count;
+ ret = !events_in_progress;
+ spin_unlock_irq(&events_lock);
+ return ret;
+}
+
+/**
+ * pm_save_wakeup_count - Save the current number of registered wakeup events.
+ * @count: Value to compare with the current number of registered wakeup events.
+ *
+ * If @count is equal to the current number of registered wakeup events and the
+ * current number of wakeup events being processed is zero, store @count as the
+ * old number of registered wakeup events to be used by pm_check_wakeup_events()
+ * and return true. Otherwise return false.
+ */
+bool pm_save_wakeup_count(unsigned long count)
+{
+ bool ret = false;
+
+ spin_lock_irq(&events_lock);
+ if (count == event_count && !events_in_progress) {
+ saved_event_count = count;
+ events_check_enabled = true;
+ ret = true;
+ }
+ spin_unlock_irq(&events_lock);
+ return ret;
+}
diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c
index 51ceaee98f9..e1e7143ca1e 100644
--- a/drivers/block/cciss.c
+++ b/drivers/block/cciss.c
@@ -335,7 +335,7 @@ static void cciss_map_sg_chain_block(ctlr_info_t *h, CommandList_struct *c,
static const char *raid_label[] = { "0", "4", "1(1+0)", "5", "5+1", "ADG",
"UNKNOWN"
};
-#define RAID_UNKNOWN (sizeof(raid_label) / sizeof(raid_label[0])-1)
+#define RAID_UNKNOWN (ARRAY_SIZE(raid_label)-1)
#ifdef CONFIG_PROC_FS
diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c
index dff48701b84..ec1711f7c5c 100644
--- a/drivers/block/drbd/drbd_receiver.c
+++ b/drivers/block/drbd/drbd_receiver.c
@@ -1087,7 +1087,7 @@ static enum finish_epoch drbd_may_finish_epoch(struct drbd_conf *mdev,
} else {
epoch->flags = 0;
atomic_set(&epoch->epoch_size, 0);
- /* atomic_set(&epoch->active, 0); is alrady zero */
+ /* atomic_set(&epoch->active, 0); is already zero */
if (rv == FE_STILL_LIVE)
rv = FE_RECYCLED;
}
diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c
index 218d091f3c5..16c3c8613cd 100644
--- a/drivers/block/nbd.c
+++ b/drivers/block/nbd.c
@@ -4,7 +4,7 @@
* Note that you can not swap over this thing, yet. Seems to work but
* deadlocks sometimes - you can not swap over TCP in general.
*
- * Copyright 1997-2000, 2008 Pavel Machek <pavel@suse.cz>
+ * Copyright 1997-2000, 2008 Pavel Machek <pavel@ucw.cz>
* Parts copyright 2001 Steven Whitehouse <steve@chygwyn.com>
*
* This file is released under GPLv2 or later.
diff --git a/drivers/block/virtio_blk.c b/drivers/block/virtio_blk.c
index 258bc2ae288..23b7c48df84 100644
--- a/drivers/block/virtio_blk.c
+++ b/drivers/block/virtio_blk.c
@@ -225,16 +225,6 @@ static int virtblk_ioctl(struct block_device *bdev, fmode_t mode,
struct gendisk *disk = bdev->bd_disk;
struct virtio_blk *vblk = disk->private_data;
- if (cmd == 0x56424944) { /* 'VBID' */
- void __user *usr_data = (void __user *)data;
- char id_str[VIRTIO_BLK_ID_BYTES];
- int err;
-
- err = virtblk_get_id(disk, id_str);
- if (!err && copy_to_user(usr_data, id_str, VIRTIO_BLK_ID_BYTES))
- err = -EFAULT;
- return err;
- }
/*
* Only allow the generic SCSI ioctls if the host can support it.
*/
@@ -281,6 +271,27 @@ static int index_to_minor(int index)
return index << PART_BITS;
}
+static ssize_t virtblk_serial_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct gendisk *disk = dev_to_disk(dev);
+ int err;
+
+ /* sysfs gives us a PAGE_SIZE buffer */
+ BUILD_BUG_ON(PAGE_SIZE < VIRTIO_BLK_ID_BYTES);
+
+ buf[VIRTIO_BLK_ID_BYTES] = '\0';
+ err = virtblk_get_id(disk, buf);
+ if (!err)
+ return strlen(buf);
+
+ if (err == -EIO) /* Unsupported? Make it empty. */
+ return 0;
+
+ return err;
+}
+DEVICE_ATTR(serial, S_IRUGO, virtblk_serial_show, NULL);
+
static int __devinit virtblk_probe(struct virtio_device *vdev)
{
struct virtio_blk *vblk;
@@ -366,12 +377,32 @@ static int __devinit virtblk_probe(struct virtio_device *vdev)
vblk->disk->driverfs_dev = &vdev->dev;
index++;
- /* If barriers are supported, tell block layer that queue is ordered */
- if (virtio_has_feature(vdev, VIRTIO_BLK_F_FLUSH))
+ if (virtio_has_feature(vdev, VIRTIO_BLK_F_FLUSH)) {
+ /*
+ * If the FLUSH feature is supported we do have support for
+ * flushing a volatile write cache on the host. Use that
+ * to implement write barrier support.
+ */
blk_queue_ordered(q, QUEUE_ORDERED_DRAIN_FLUSH,
virtblk_prepare_flush);
- else if (virtio_has_feature(vdev, VIRTIO_BLK_F_BARRIER))
+ } else if (virtio_has_feature(vdev, VIRTIO_BLK_F_BARRIER)) {
+ /*
+ * If the BARRIER feature is supported the host expects us
+ * to order request by tags. This implies there is not
+ * volatile write cache on the host, and that the host
+ * never re-orders outstanding I/O. This feature is not
+ * useful for real life scenarious and deprecated.
+ */
blk_queue_ordered(q, QUEUE_ORDERED_TAG, NULL);
+ } else {
+ /*
+ * If the FLUSH feature is not supported we must assume that
+ * the host does not perform any kind of volatile write
+ * caching. We still need to drain the queue to provider
+ * proper barrier semantics.
+ */
+ blk_queue_ordered(q, QUEUE_ORDERED_DRAIN, NULL);
+ }
/* If disk is read-only in the host, the guest should obey */
if (virtio_has_feature(vdev, VIRTIO_BLK_F_RO))
@@ -445,8 +476,15 @@ static int __devinit virtblk_probe(struct virtio_device *vdev)
add_disk(vblk->disk);
+ err = device_create_file(disk_to_dev(vblk->disk), &dev_attr_serial);
+ if (err)
+ goto out_del_disk;
+
return 0;
+out_del_disk:
+ del_gendisk(vblk->disk);
+ blk_cleanup_queue(vblk->disk->queue);
out_put_disk:
put_disk(vblk->disk);
out_mempool:
diff --git a/drivers/block/xen-blkfront.c b/drivers/block/xen-blkfront.c
index 82ed403147c..f63ac3d1f8a 100644
--- a/drivers/block/xen-blkfront.c
+++ b/drivers/block/xen-blkfront.c
@@ -48,6 +48,7 @@
#include <xen/grant_table.h>
#include <xen/events.h>
#include <xen/page.h>
+#include <xen/platform_pci.h>
#include <xen/interface/grant_table.h>
#include <xen/interface/io/blkif.h>
@@ -737,6 +738,35 @@ static int blkfront_probe(struct xenbus_device *dev,
}
}
+ if (xen_hvm_domain()) {
+ char *type;
+ int len;
+ /* no unplug has been done: do not hook devices != xen vbds */
+ if (xen_platform_pci_unplug & XEN_UNPLUG_IGNORE) {
+ int major;
+
+ if (!VDEV_IS_EXTENDED(vdevice))
+ major = BLKIF_MAJOR(vdevice);
+ else
+ major = XENVBD_MAJOR;
+
+ if (major != XENVBD_MAJOR) {
+ printk(KERN_INFO
+ "%s: HVM does not support vbd %d as xen block device\n",
+ __FUNCTION__, vdevice);
+ return -ENODEV;
+ }
+ }
+ /* do not create a PV cdrom device if we are an HVM guest */
+ type = xenbus_read(XBT_NIL, dev->nodename, "device-type", &len);
+ if (IS_ERR(type))
+ return -ENODEV;
+ if (strncmp(type, "cdrom", 5) == 0) {
+ kfree(type);
+ return -ENODEV;
+ }
+ kfree(type);
+ }
info = kzalloc(sizeof(*info), GFP_KERNEL);
if (!info) {
xenbus_dev_fatal(dev, -ENOMEM, "allocating info structure");
diff --git a/drivers/bluetooth/Kconfig b/drivers/bluetooth/Kconfig
index 058fbccf2f5..02deef42492 100644
--- a/drivers/bluetooth/Kconfig
+++ b/drivers/bluetooth/Kconfig
@@ -58,6 +58,18 @@ config BT_HCIUART_BCSP
Say Y here to compile support for HCI BCSP protocol.
+config BT_HCIUART_ATH3K
+ bool "Atheros AR300x serial support"
+ depends on BT_HCIUART
+ help
+ HCIATH3K (HCI Atheros AR300x) is a serial protocol for
+ communication between host and Atheros AR300x Bluetooth devices.
+ This protocol enables AR300x chips to be enabled with
+ power management support.
+ Enable this if you have Atheros AR300x serial Bluetooth device.
+
+ Say Y here to compile support for HCI UART ATH3K protocol.
+
config BT_HCIUART_LL
bool "HCILL protocol support"
depends on BT_HCIUART
diff --git a/drivers/bluetooth/Makefile b/drivers/bluetooth/Makefile
index 7e5aed59812..71bdf13287c 100644
--- a/drivers/bluetooth/Makefile
+++ b/drivers/bluetooth/Makefile
@@ -26,4 +26,5 @@ hci_uart-y := hci_ldisc.o
hci_uart-$(CONFIG_BT_HCIUART_H4) += hci_h4.o
hci_uart-$(CONFIG_BT_HCIUART_BCSP) += hci_bcsp.o
hci_uart-$(CONFIG_BT_HCIUART_LL) += hci_ll.o
+hci_uart-$(CONFIG_BT_HCIUART_ATH3K) += hci_ath.o
hci_uart-objs := $(hci_uart-y)
diff --git a/drivers/bluetooth/bcm203x.c b/drivers/bluetooth/bcm203x.c
index b0c84c19f44..8b1b643a519 100644
--- a/drivers/bluetooth/bcm203x.c
+++ b/drivers/bluetooth/bcm203x.c
@@ -224,7 +224,7 @@ static int bcm203x_probe(struct usb_interface *intf, const struct usb_device_id
BT_DBG("firmware data %p size %zu", firmware->data, firmware->size);
- data->fw_data = kmalloc(firmware->size, GFP_KERNEL);
+ data->fw_data = kmemdup(firmware->data, firmware->size, GFP_KERNEL);
if (!data->fw_data) {
BT_ERR("Can't allocate memory for firmware image");
release_firmware(firmware);
@@ -234,7 +234,6 @@ static int bcm203x_probe(struct usb_interface *intf, const struct usb_device_id
return -ENOMEM;
}
- memcpy(data->fw_data, firmware->data, firmware->size);
data->fw_size = firmware->size;
data->fw_sent = 0;
diff --git a/drivers/bluetooth/bluecard_cs.c b/drivers/bluetooth/bluecard_cs.c
index 6d34f405a2f..d52e90a5a61 100644
--- a/drivers/bluetooth/bluecard_cs.c
+++ b/drivers/bluetooth/bluecard_cs.c
@@ -39,7 +39,6 @@
#include <linux/skbuff.h>
#include <linux/io.h>
-#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/cistpl.h>
#include <pcmcia/ciscode.h>
@@ -160,7 +159,7 @@ static void bluecard_detach(struct pcmcia_device *p_dev);
static void bluecard_activity_led_timeout(u_long arg)
{
bluecard_info_t *info = (bluecard_info_t *)arg;
- unsigned int iobase = info->p_dev->io.BasePort1;
+ unsigned int iobase = info->p_dev->resource[0]->start;
if (!test_bit(CARD_HAS_PCCARD_ID, &(info->hw_state)))
return;
@@ -177,7 +176,7 @@ static void bluecard_activity_led_timeout(u_long arg)
static void bluecard_enable_activity_led(bluecard_info_t *info)
{
- unsigned int iobase = info->p_dev->io.BasePort1;
+ unsigned int iobase = info->p_dev->resource[0]->start;
if (!test_bit(CARD_HAS_PCCARD_ID, &(info->hw_state)))
return;
@@ -233,7 +232,7 @@ static void bluecard_write_wakeup(bluecard_info_t *info)
}
do {
- register unsigned int iobase = info->p_dev->io.BasePort1;
+ register unsigned int iobase = info->p_dev->resource[0]->start;
register unsigned int offset;
register unsigned char command;
register unsigned long ready_bit;
@@ -380,7 +379,7 @@ static void bluecard_receive(bluecard_info_t *info, unsigned int offset)
return;
}
- iobase = info->p_dev->io.BasePort1;
+ iobase = info->p_dev->resource[0]->start;
if (test_bit(XMIT_SENDING_READY, &(info->tx_state)))
bluecard_enable_activity_led(info);
@@ -509,7 +508,7 @@ static irqreturn_t bluecard_interrupt(int irq, void *dev_inst)
if (!test_bit(CARD_READY, &(info->hw_state)))
return IRQ_HANDLED;
- iobase = info->p_dev->io.BasePort1;
+ iobase = info->p_dev->resource[0]->start;
spin_lock(&(info->lock));
@@ -623,7 +622,7 @@ static int bluecard_hci_flush(struct hci_dev *hdev)
static int bluecard_hci_open(struct hci_dev *hdev)
{
bluecard_info_t *info = (bluecard_info_t *)(hdev->driver_data);
- unsigned int iobase = info->p_dev->io.BasePort1;
+ unsigned int iobase = info->p_dev->resource[0]->start;
if (test_bit(CARD_HAS_PCCARD_ID, &(info->hw_state)))
bluecard_hci_set_baud_rate(hdev, DEFAULT_BAUD_RATE);
@@ -643,7 +642,7 @@ static int bluecard_hci_open(struct hci_dev *hdev)
static int bluecard_hci_close(struct hci_dev *hdev)
{
bluecard_info_t *info = (bluecard_info_t *)(hdev->driver_data);
- unsigned int iobase = info->p_dev->io.BasePort1;
+ unsigned int iobase = info->p_dev->resource[0]->start;
if (!test_and_clear_bit(HCI_RUNNING, &(hdev->flags)))
return 0;
@@ -710,7 +709,7 @@ static int bluecard_hci_ioctl(struct hci_dev *hdev, unsigned int cmd, unsigned l
static int bluecard_open(bluecard_info_t *info)
{
- unsigned int iobase = info->p_dev->io.BasePort1;
+ unsigned int iobase = info->p_dev->resource[0]->start;
struct hci_dev *hdev;
unsigned char id;
@@ -829,7 +828,7 @@ static int bluecard_open(bluecard_info_t *info)
static int bluecard_close(bluecard_info_t *info)
{
- unsigned int iobase = info->p_dev->io.BasePort1;
+ unsigned int iobase = info->p_dev->resource[0]->start;
struct hci_dev *hdev = info->hdev;
if (!hdev)
@@ -866,9 +865,6 @@ static int bluecard_probe(struct pcmcia_device *link)
info->p_dev = link;
link->priv = info;
- link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
- link->io.NumPorts1 = 8;
-
link->conf.Attributes = CONF_ENABLE_IRQ;
link->conf.IntType = INT_MEMORY_AND_IO;
@@ -891,12 +887,14 @@ static int bluecard_config(struct pcmcia_device *link)
int i, n;
link->conf.ConfigIndex = 0x20;
- link->io.NumPorts1 = 64;
- link->io.IOAddrLines = 6;
+
+ link->resource[0]->flags |= IO_DATA_PATH_WIDTH_8;
+ link->resource[0]->end = 64;
+ link->io_lines = 6;
for (n = 0; n < 0x400; n += 0x40) {
- link->io.BasePort1 = n ^ 0x300;
- i = pcmcia_request_io(link, &link->io);
+ link->resource[0]->start = n ^ 0x300;
+ i = pcmcia_request_io(link);
if (i == 0)
break;
}
diff --git a/drivers/bluetooth/bpa10x.c b/drivers/bluetooth/bpa10x.c
index d945cd12433..751b338d904 100644
--- a/drivers/bluetooth/bpa10x.c
+++ b/drivers/bluetooth/bpa10x.c
@@ -62,7 +62,7 @@ struct hci_vendor_hdr {
__u8 type;
__le16 snum;
__le16 dlen;
-} __attribute__ ((packed));
+} __packed;
static int bpa10x_recv(struct hci_dev *hdev, int queue, void *buf, int count)
{
diff --git a/drivers/bluetooth/bt3c_cs.c b/drivers/bluetooth/bt3c_cs.c
index 21e05fdc912..7ab8f29d5e0 100644
--- a/drivers/bluetooth/bt3c_cs.c
+++ b/drivers/bluetooth/bt3c_cs.c
@@ -45,7 +45,6 @@
#include <linux/device.h>
#include <linux/firmware.h>
-#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/cistpl.h>
#include <pcmcia/ciscode.h>
@@ -189,7 +188,7 @@ static void bt3c_write_wakeup(bt3c_info_t *info)
return;
do {
- register unsigned int iobase = info->p_dev->io.BasePort1;
+ register unsigned int iobase = info->p_dev->resource[0]->start;
register struct sk_buff *skb;
register int len;
@@ -227,7 +226,7 @@ static void bt3c_receive(bt3c_info_t *info)
return;
}
- iobase = info->p_dev->io.BasePort1;
+ iobase = info->p_dev->resource[0]->start;
avail = bt3c_read(iobase, 0x7006);
//printk("bt3c_cs: receiving %d bytes\n", avail);
@@ -348,7 +347,7 @@ static irqreturn_t bt3c_interrupt(int irq, void *dev_inst)
/* our irq handler is shared */
return IRQ_NONE;
- iobase = info->p_dev->io.BasePort1;
+ iobase = info->p_dev->resource[0]->start;
spin_lock(&(info->lock));
@@ -481,7 +480,7 @@ static int bt3c_load_firmware(bt3c_info_t *info, const unsigned char *firmware,
unsigned int iobase, size, addr, fcs, tmp;
int i, err = 0;
- iobase = info->p_dev->io.BasePort1;
+ iobase = info->p_dev->resource[0]->start;
/* Reset */
bt3c_io_write(iobase, 0x8040, 0x0404);
@@ -658,8 +657,8 @@ static int bt3c_probe(struct pcmcia_device *link)
info->p_dev = link;
link->priv = info;
- link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
- link->io.NumPorts1 = 8;
+ link->resource[0]->flags |= IO_DATA_PATH_WIDTH_8;
+ link->resource[0]->end = 8;
link->conf.Attributes = CONF_ENABLE_IRQ;
link->conf.IntType = INT_MEMORY_AND_IO;
@@ -684,14 +683,14 @@ static int bt3c_check_config(struct pcmcia_device *p_dev,
{
unsigned long try = (unsigned long) priv_data;
+ p_dev->io_lines = (try == 0) ? 16 : cf->io.flags & CISTPL_IO_LINES_MASK;
+
if (cf->vpp1.present & (1 << CISTPL_POWER_VNOM))
p_dev->conf.Vpp = cf->vpp1.param[CISTPL_POWER_VNOM] / 10000;
if ((cf->io.nwin > 0) && (cf->io.win[0].len == 8) &&
(cf->io.win[0].base != 0)) {
- p_dev->io.BasePort1 = cf->io.win[0].base;
- p_dev->io.IOAddrLines = (try == 0) ? 16 :
- cf->io.flags & CISTPL_IO_LINES_MASK;
- if (!pcmcia_request_io(p_dev, &p_dev->io))
+ p_dev->resource[0]->start = cf->io.win[0].base;
+ if (!pcmcia_request_io(p_dev))
return 0;
}
return -ENODEV;
@@ -708,9 +707,9 @@ static int bt3c_check_config_notpicky(struct pcmcia_device *p_dev,
if ((cf->io.nwin > 0) && ((cf->io.flags & CISTPL_IO_LINES_MASK) <= 3)) {
for (j = 0; j < 5; j++) {
- p_dev->io.BasePort1 = base[j];
- p_dev->io.IOAddrLines = base[j] ? 16 : 3;
- if (!pcmcia_request_io(p_dev, &p_dev->io))
+ p_dev->resource[0]->start = base[j];
+ p_dev->io_lines = base[j] ? 16 : 3;
+ if (!pcmcia_request_io(p_dev))
return 0;
}
}
diff --git a/drivers/bluetooth/btmrvl_debugfs.c b/drivers/bluetooth/btmrvl_debugfs.c
index b50b41d97a7..54739b08c30 100644
--- a/drivers/bluetooth/btmrvl_debugfs.c
+++ b/drivers/bluetooth/btmrvl_debugfs.c
@@ -216,7 +216,7 @@ static const struct file_operations btmrvl_gpiogap_fops = {
static ssize_t btmrvl_hscmd_write(struct file *file, const char __user *ubuf,
size_t count, loff_t *ppos)
{
- struct btmrvl_private *priv = (struct btmrvl_private *) file->private_data;
+ struct btmrvl_private *priv = file->private_data;
char buf[16];
long result, ret;
diff --git a/drivers/bluetooth/btmrvl_drv.h b/drivers/bluetooth/btmrvl_drv.h
index bed0ba63023..90bda50dc44 100644
--- a/drivers/bluetooth/btmrvl_drv.h
+++ b/drivers/bluetooth/btmrvl_drv.h
@@ -76,6 +76,7 @@ struct btmrvl_private {
int (*hw_host_to_card) (struct btmrvl_private *priv,
u8 *payload, u16 nb);
int (*hw_wakeup_firmware) (struct btmrvl_private *priv);
+ int (*hw_process_int_status) (struct btmrvl_private *priv);
spinlock_t driver_lock; /* spinlock used by driver */
#ifdef CONFIG_DEBUG_FS
void *debugfs_data;
@@ -118,13 +119,13 @@ struct btmrvl_cmd {
__le16 ocf_ogf;
u8 length;
u8 data[4];
-} __attribute__ ((packed));
+} __packed;
struct btmrvl_event {
u8 ec; /* event counter */
u8 length;
u8 data[4];
-} __attribute__ ((packed));
+} __packed;
/* Prototype of global function */
diff --git a/drivers/bluetooth/btmrvl_main.c b/drivers/bluetooth/btmrvl_main.c
index ee37ef0caee..0d32ec82e9b 100644
--- a/drivers/bluetooth/btmrvl_main.c
+++ b/drivers/bluetooth/btmrvl_main.c
@@ -502,14 +502,17 @@ static int btmrvl_service_main_thread(void *data)
spin_lock_irqsave(&priv->driver_lock, flags);
if (adapter->int_count) {
adapter->int_count = 0;
+ spin_unlock_irqrestore(&priv->driver_lock, flags);
+ priv->hw_process_int_status(priv);
} else if (adapter->ps_state == PS_SLEEP &&
!skb_queue_empty(&adapter->tx_queue)) {
spin_unlock_irqrestore(&priv->driver_lock, flags);
adapter->wakeup_tries++;
priv->hw_wakeup_firmware(priv);
continue;
+ } else {
+ spin_unlock_irqrestore(&priv->driver_lock, flags);
}
- spin_unlock_irqrestore(&priv->driver_lock, flags);
if (adapter->ps_state == PS_SLEEP)
continue;
diff --git a/drivers/bluetooth/btmrvl_sdio.c b/drivers/bluetooth/btmrvl_sdio.c
index df0773ebd9e..dcc2a6ec23f 100644
--- a/drivers/bluetooth/btmrvl_sdio.c
+++ b/drivers/bluetooth/btmrvl_sdio.c
@@ -47,6 +47,7 @@
* module_exit function is called.
*/
static u8 user_rmmod;
+static u8 sdio_ireg;
static const struct btmrvl_sdio_device btmrvl_sdio_sd6888 = {
.helper = "sd8688_helper.bin",
@@ -83,10 +84,10 @@ static int btmrvl_sdio_read_fw_status(struct btmrvl_sdio_card *card, u16 *dat)
*dat = 0;
fws0 = sdio_readb(card->func, CARD_FW_STATUS0_REG, &ret);
+ if (ret)
+ return -EIO;
- if (!ret)
- fws1 = sdio_readb(card->func, CARD_FW_STATUS1_REG, &ret);
-
+ fws1 = sdio_readb(card->func, CARD_FW_STATUS1_REG, &ret);
if (ret)
return -EIO;
@@ -216,7 +217,7 @@ static int btmrvl_sdio_download_helper(struct btmrvl_sdio_card *card)
tmphlprbufsz = ALIGN_SZ(BTM_UPLD_SIZE, BTSDIO_DMA_ALIGN);
- tmphlprbuf = kmalloc(tmphlprbufsz, GFP_KERNEL);
+ tmphlprbuf = kzalloc(tmphlprbufsz, GFP_KERNEL);
if (!tmphlprbuf) {
BT_ERR("Unable to allocate buffer for helper."
" Terminating download");
@@ -224,8 +225,6 @@ static int btmrvl_sdio_download_helper(struct btmrvl_sdio_card *card)
goto done;
}
- memset(tmphlprbuf, 0, tmphlprbufsz);
-
helperbuf = (u8 *) ALIGN_ADDR(tmphlprbuf, BTSDIO_DMA_ALIGN);
/* Perform helper data transfer */
@@ -318,7 +317,7 @@ static int btmrvl_sdio_download_fw_w_helper(struct btmrvl_sdio_card *card)
BT_DBG("Downloading FW image (%d bytes)", firmwarelen);
tmpfwbufsz = ALIGN_SZ(BTM_UPLD_SIZE, BTSDIO_DMA_ALIGN);
- tmpfwbuf = kmalloc(tmpfwbufsz, GFP_KERNEL);
+ tmpfwbuf = kzalloc(tmpfwbufsz, GFP_KERNEL);
if (!tmpfwbuf) {
BT_ERR("Unable to allocate buffer for firmware."
" Terminating download");
@@ -326,8 +325,6 @@ static int btmrvl_sdio_download_fw_w_helper(struct btmrvl_sdio_card *card)
goto done;
}
- memset(tmpfwbuf, 0, tmpfwbufsz);
-
/* Ensure aligned firmware buffer */
fwbuf = (u8 *) ALIGN_ADDR(tmpfwbuf, BTSDIO_DMA_ALIGN);
@@ -555,78 +552,79 @@ exit:
return ret;
}
-static int btmrvl_sdio_get_int_status(struct btmrvl_private *priv, u8 * ireg)
+static int btmrvl_sdio_process_int_status(struct btmrvl_private *priv)
{
- int ret;
- u8 sdio_ireg = 0;
+ ulong flags;
+ u8 ireg;
struct btmrvl_sdio_card *card = priv->btmrvl_dev.card;
- *ireg = 0;
-
- sdio_ireg = sdio_readb(card->func, HOST_INTSTATUS_REG, &ret);
- if (ret) {
- BT_ERR("sdio_readb: read int status register failed");
- ret = -EIO;
- goto done;
- }
-
- if (sdio_ireg != 0) {
- /*
- * DN_LD_HOST_INT_STATUS and/or UP_LD_HOST_INT_STATUS
- * Clear the interrupt status register and re-enable the
- * interrupt.
- */
- BT_DBG("sdio_ireg = 0x%x", sdio_ireg);
-
- sdio_writeb(card->func, ~(sdio_ireg) & (DN_LD_HOST_INT_STATUS |
- UP_LD_HOST_INT_STATUS),
- HOST_INTSTATUS_REG, &ret);
- if (ret) {
- BT_ERR("sdio_writeb: clear int status register "
- "failed");
- ret = -EIO;
- goto done;
- }
- }
+ spin_lock_irqsave(&priv->driver_lock, flags);
+ ireg = sdio_ireg;
+ sdio_ireg = 0;
+ spin_unlock_irqrestore(&priv->driver_lock, flags);
- if (sdio_ireg & DN_LD_HOST_INT_STATUS) {
+ sdio_claim_host(card->func);
+ if (ireg & DN_LD_HOST_INT_STATUS) {
if (priv->btmrvl_dev.tx_dnld_rdy)
BT_DBG("tx_done already received: "
- " int_status=0x%x", sdio_ireg);
+ " int_status=0x%x", ireg);
else
priv->btmrvl_dev.tx_dnld_rdy = true;
}
- if (sdio_ireg & UP_LD_HOST_INT_STATUS)
+ if (ireg & UP_LD_HOST_INT_STATUS)
btmrvl_sdio_card_to_host(priv);
- *ireg = sdio_ireg;
-
- ret = 0;
+ sdio_release_host(card->func);
-done:
- return ret;
+ return 0;
}
static void btmrvl_sdio_interrupt(struct sdio_func *func)
{
struct btmrvl_private *priv;
- struct hci_dev *hcidev;
struct btmrvl_sdio_card *card;
+ ulong flags;
u8 ireg = 0;
+ int ret;
card = sdio_get_drvdata(func);
- if (card && card->priv) {
- priv = card->priv;
- hcidev = priv->btmrvl_dev.hcidev;
+ if (!card || !card->priv) {
+ BT_ERR("sbi_interrupt(%p) card or priv is "
+ "NULL, card=%p\n", func, card);
+ return;
+ }
- if (btmrvl_sdio_get_int_status(priv, &ireg))
- BT_ERR("reading HOST_INT_STATUS_REG failed");
- else
- BT_DBG("HOST_INT_STATUS_REG %#x", ireg);
+ priv = card->priv;
+
+ ireg = sdio_readb(card->func, HOST_INTSTATUS_REG, &ret);
+ if (ret) {
+ BT_ERR("sdio_readb: read int status register failed");
+ return;
+ }
+
+ if (ireg != 0) {
+ /*
+ * DN_LD_HOST_INT_STATUS and/or UP_LD_HOST_INT_STATUS
+ * Clear the interrupt status register and re-enable the
+ * interrupt.
+ */
+ BT_DBG("ireg = 0x%x", ireg);
- btmrvl_interrupt(priv);
+ sdio_writeb(card->func, ~(ireg) & (DN_LD_HOST_INT_STATUS |
+ UP_LD_HOST_INT_STATUS),
+ HOST_INTSTATUS_REG, &ret);
+ if (ret) {
+ BT_ERR("sdio_writeb: clear int status register failed");
+ return;
+ }
}
+
+ spin_lock_irqsave(&priv->driver_lock, flags);
+ sdio_ireg |= ireg;
+ spin_unlock_irqrestore(&priv->driver_lock, flags);
+
+ btmrvl_interrupt(priv);
}
static int btmrvl_sdio_register_dev(struct btmrvl_sdio_card *card)
@@ -930,6 +928,7 @@ static int btmrvl_sdio_probe(struct sdio_func *func,
/* Initialize the interface specific function pointers */
priv->hw_host_to_card = btmrvl_sdio_host_to_card;
priv->hw_wakeup_firmware = btmrvl_sdio_wakeup_fw;
+ priv->hw_process_int_status = btmrvl_sdio_process_int_status;
if (btmrvl_register_hdev(priv)) {
BT_ERR("Register hdev failed!");
diff --git a/drivers/bluetooth/btuart_cs.c b/drivers/bluetooth/btuart_cs.c
index 4ed7288f99d..1c4f5e863b0 100644
--- a/drivers/bluetooth/btuart_cs.c
+++ b/drivers/bluetooth/btuart_cs.c
@@ -41,7 +41,6 @@
#include <asm/system.h>
#include <asm/io.h>
-#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/cistpl.h>
#include <pcmcia/ciscode.h>
@@ -143,7 +142,7 @@ static void btuart_write_wakeup(btuart_info_t *info)
}
do {
- register unsigned int iobase = info->p_dev->io.BasePort1;
+ register unsigned int iobase = info->p_dev->resource[0]->start;
register struct sk_buff *skb;
register int len;
@@ -184,7 +183,7 @@ static void btuart_receive(btuart_info_t *info)
return;
}
- iobase = info->p_dev->io.BasePort1;
+ iobase = info->p_dev->resource[0]->start;
do {
info->hdev->stat.byte_rx++;
@@ -298,7 +297,7 @@ static irqreturn_t btuart_interrupt(int irq, void *dev_inst)
/* our irq handler is shared */
return IRQ_NONE;
- iobase = info->p_dev->io.BasePort1;
+ iobase = info->p_dev->resource[0]->start;
spin_lock(&(info->lock));
@@ -355,7 +354,7 @@ static void btuart_change_speed(btuart_info_t *info, unsigned int speed)
return;
}
- iobase = info->p_dev->io.BasePort1;
+ iobase = info->p_dev->resource[0]->start;
spin_lock_irqsave(&(info->lock), flags);
@@ -479,7 +478,7 @@ static int btuart_hci_ioctl(struct hci_dev *hdev, unsigned int cmd, unsigned lon
static int btuart_open(btuart_info_t *info)
{
unsigned long flags;
- unsigned int iobase = info->p_dev->io.BasePort1;
+ unsigned int iobase = info->p_dev->resource[0]->start;
struct hci_dev *hdev;
spin_lock_init(&(info->lock));
@@ -549,7 +548,7 @@ static int btuart_open(btuart_info_t *info)
static int btuart_close(btuart_info_t *info)
{
unsigned long flags;
- unsigned int iobase = info->p_dev->io.BasePort1;
+ unsigned int iobase = info->p_dev->resource[0]->start;
struct hci_dev *hdev = info->hdev;
if (!hdev)
@@ -587,8 +586,8 @@ static int btuart_probe(struct pcmcia_device *link)
info->p_dev = link;
link->priv = info;
- link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
- link->io.NumPorts1 = 8;
+ link->resource[0]->flags |= IO_DATA_PATH_WIDTH_8;
+ link->resource[0]->end = 8;
link->conf.Attributes = CONF_ENABLE_IRQ;
link->conf.IntType = INT_MEMORY_AND_IO;
@@ -613,14 +612,14 @@ static int btuart_check_config(struct pcmcia_device *p_dev,
{
int *try = priv_data;
+ p_dev->io_lines = (try == 0) ? 16 : cf->io.flags & CISTPL_IO_LINES_MASK;
+
if (cf->vpp1.present & (1 << CISTPL_POWER_VNOM))
p_dev->conf.Vpp = cf->vpp1.param[CISTPL_POWER_VNOM] / 10000;
if ((cf->io.nwin > 0) && (cf->io.win[0].len == 8) &&
(cf->io.win[0].base != 0)) {
- p_dev->io.BasePort1 = cf->io.win[0].base;
- p_dev->io.IOAddrLines = (*try == 0) ? 16 :
- cf->io.flags & CISTPL_IO_LINES_MASK;
- if (!pcmcia_request_io(p_dev, &p_dev->io))
+ p_dev->resource[0]->start = cf->io.win[0].base;
+ if (!pcmcia_request_io(p_dev))
return 0;
}
return -ENODEV;
@@ -637,9 +636,9 @@ static int btuart_check_config_notpicky(struct pcmcia_device *p_dev,
if ((cf->io.nwin > 0) && ((cf->io.flags & CISTPL_IO_LINES_MASK) <= 3)) {
for (j = 0; j < 5; j++) {
- p_dev->io.BasePort1 = base[j];
- p_dev->io.IOAddrLines = base[j] ? 16 : 3;
- if (!pcmcia_request_io(p_dev, &p_dev->io))
+ p_dev->resource[0]->start = base[j];
+ p_dev->io_lines = base[j] ? 16 : 3;
+ if (!pcmcia_request_io(p_dev))
return 0;
}
}
diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
index 5d9cc53bd64..d22ce3cc611 100644
--- a/drivers/bluetooth/btusb.c
+++ b/drivers/bluetooth/btusb.c
@@ -59,6 +59,9 @@ static struct usb_device_id btusb_table[] = {
/* Generic Bluetooth USB device */
{ USB_DEVICE_INFO(0xe0, 0x01, 0x01) },
+ /* Apple iMac11,1 */
+ { USB_DEVICE(0x05ac, 0x8215) },
+
/* AVM BlueFRITZ! USB v2.0 */
{ USB_DEVICE(0x057c, 0x3800) },
@@ -146,6 +149,7 @@ static struct usb_device_id blacklist_table[] = {
#define BTUSB_BULK_RUNNING 1
#define BTUSB_ISOC_RUNNING 2
#define BTUSB_SUSPENDING 3
+#define BTUSB_DID_ISO_RESUME 4
struct btusb_data {
struct hci_dev *hdev;
@@ -179,7 +183,6 @@ struct btusb_data {
unsigned int sco_num;
int isoc_altsetting;
int suspend_count;
- int did_iso_resume:1;
};
static int inc_tx(struct btusb_data *data)
@@ -807,7 +810,7 @@ static void btusb_work(struct work_struct *work)
int err;
if (hdev->conn_hash.sco_num > 0) {
- if (!data->did_iso_resume) {
+ if (!test_bit(BTUSB_DID_ISO_RESUME, &data->flags)) {
err = usb_autopm_get_interface(data->isoc);
if (err < 0) {
clear_bit(BTUSB_ISOC_RUNNING, &data->flags);
@@ -815,7 +818,7 @@ static void btusb_work(struct work_struct *work)
return;
}
- data->did_iso_resume = 1;
+ set_bit(BTUSB_DID_ISO_RESUME, &data->flags);
}
if (data->isoc_altsetting != 2) {
clear_bit(BTUSB_ISOC_RUNNING, &data->flags);
@@ -836,10 +839,8 @@ static void btusb_work(struct work_struct *work)
usb_kill_anchored_urbs(&data->isoc_anchor);
__set_isoc_interface(hdev, 0);
- if (data->did_iso_resume) {
- data->did_iso_resume = 0;
+ if (test_and_clear_bit(BTUSB_DID_ISO_RESUME, &data->flags))
usb_autopm_put_interface(data->isoc);
- }
}
}
diff --git a/drivers/bluetooth/dtl1_cs.c b/drivers/bluetooth/dtl1_cs.c
index ef044d55cb2..db7c8db695f 100644
--- a/drivers/bluetooth/dtl1_cs.c
+++ b/drivers/bluetooth/dtl1_cs.c
@@ -41,7 +41,6 @@
#include <asm/system.h>
#include <asm/io.h>
-#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/cistpl.h>
#include <pcmcia/ciscode.h>
@@ -104,7 +103,7 @@ typedef struct {
u8 type;
u8 zero;
u16 len;
-} __attribute__ ((packed)) nsh_t; /* Nokia Specific Header */
+} __packed nsh_t; /* Nokia Specific Header */
#define NSHL 4 /* Nokia Specific Header Length */
@@ -150,7 +149,7 @@ static void dtl1_write_wakeup(dtl1_info_t *info)
}
do {
- register unsigned int iobase = info->p_dev->io.BasePort1;
+ register unsigned int iobase = info->p_dev->resource[0]->start;
register struct sk_buff *skb;
register int len;
@@ -215,7 +214,7 @@ static void dtl1_receive(dtl1_info_t *info)
return;
}
- iobase = info->p_dev->io.BasePort1;
+ iobase = info->p_dev->resource[0]->start;
do {
info->hdev->stat.byte_rx++;
@@ -302,7 +301,7 @@ static irqreturn_t dtl1_interrupt(int irq, void *dev_inst)
/* our irq handler is shared */
return IRQ_NONE;
- iobase = info->p_dev->io.BasePort1;
+ iobase = info->p_dev->resource[0]->start;
spin_lock(&(info->lock));
@@ -462,7 +461,7 @@ static int dtl1_hci_ioctl(struct hci_dev *hdev, unsigned int cmd, unsigned long
static int dtl1_open(dtl1_info_t *info)
{
unsigned long flags;
- unsigned int iobase = info->p_dev->io.BasePort1;
+ unsigned int iobase = info->p_dev->resource[0]->start;
struct hci_dev *hdev;
spin_lock_init(&(info->lock));
@@ -509,7 +508,8 @@ static int dtl1_open(dtl1_info_t *info)
outb(UART_LCR_WLEN8, iobase + UART_LCR); /* Reset DLAB */
outb((UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2), iobase + UART_MCR);
- info->ri_latch = inb(info->p_dev->io.BasePort1 + UART_MSR) & UART_MSR_RI;
+ info->ri_latch = inb(info->p_dev->resource[0]->start + UART_MSR)
+ & UART_MSR_RI;
/* Turn on interrupts */
outb(UART_IER_RLSI | UART_IER_RDI | UART_IER_THRI, iobase + UART_IER);
@@ -534,7 +534,7 @@ static int dtl1_open(dtl1_info_t *info)
static int dtl1_close(dtl1_info_t *info)
{
unsigned long flags;
- unsigned int iobase = info->p_dev->io.BasePort1;
+ unsigned int iobase = info->p_dev->resource[0]->start;
struct hci_dev *hdev = info->hdev;
if (!hdev)
@@ -572,8 +572,8 @@ static int dtl1_probe(struct pcmcia_device *link)
info->p_dev = link;
link->priv = info;
- link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
- link->io.NumPorts1 = 8;
+ link->resource[0]->flags |= IO_DATA_PATH_WIDTH_8;
+ link->resource[0]->end = 8;
link->conf.Attributes = CONF_ENABLE_IRQ;
link->conf.IntType = INT_MEMORY_AND_IO;
@@ -597,14 +597,13 @@ static int dtl1_confcheck(struct pcmcia_device *p_dev,
unsigned int vcc,
void *priv_data)
{
- if ((cf->io.nwin == 1) && (cf->io.win[0].len > 8)) {
- p_dev->io.BasePort1 = cf->io.win[0].base;
- p_dev->io.NumPorts1 = cf->io.win[0].len; /*yo */
- p_dev->io.IOAddrLines = cf->io.flags & CISTPL_IO_LINES_MASK;
- if (!pcmcia_request_io(p_dev, &p_dev->io))
- return 0;
- }
- return -ENODEV;
+ if ((cf->io.nwin != 1) || (cf->io.win[0].len <= 8))
+ return -ENODEV;
+
+ p_dev->resource[0]->start = cf->io.win[0].base;
+ p_dev->resource[0]->end = cf->io.win[0].len; /*yo */
+ p_dev->io_lines = cf->io.flags & CISTPL_IO_LINES_MASK;
+ return pcmcia_request_io(p_dev);
}
static int dtl1_config(struct pcmcia_device *link)
@@ -613,7 +612,7 @@ static int dtl1_config(struct pcmcia_device *link)
int i;
/* Look for a generic full-sized window */
- link->io.NumPorts1 = 8;
+ link->resource[0]->end = 8;
if (pcmcia_loop_config(link, dtl1_confcheck, NULL) < 0)
goto failed;
diff --git a/drivers/bluetooth/hci_ath.c b/drivers/bluetooth/hci_ath.c
new file mode 100644
index 00000000000..6a160c17ea9
--- /dev/null
+++ b/drivers/bluetooth/hci_ath.c
@@ -0,0 +1,235 @@
+/*
+ * Atheros Communication Bluetooth HCIATH3K UART protocol
+ *
+ * HCIATH3K (HCI Atheros AR300x Protocol) is a Atheros Communication's
+ * power management protocol extension to H4 to support AR300x Bluetooth Chip.
+ *
+ * Copyright (c) 2009-2010 Atheros Communications Inc.
+ *
+ * Acknowledgements:
+ * This file is based on hci_h4.c, which was written
+ * by Maxim Krasnyansky and Marcel Holtmann.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * 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/init.h>
+#include <linux/slab.h>
+#include <linux/tty.h>
+#include <linux/errno.h>
+#include <linux/ioctl.h>
+#include <linux/skbuff.h>
+
+#include <net/bluetooth/bluetooth.h>
+#include <net/bluetooth/hci_core.h>
+
+#include "hci_uart.h"
+
+struct ath_struct {
+ struct hci_uart *hu;
+ unsigned int cur_sleep;
+
+ struct sk_buff_head txq;
+ struct work_struct ctxtsw;
+};
+
+static int ath_wakeup_ar3k(struct tty_struct *tty)
+{
+ struct termios settings;
+ int status = tty->driver->ops->tiocmget(tty, NULL);
+
+ if (status & TIOCM_CTS)
+ return status;
+
+ /* Disable Automatic RTSCTS */
+ n_tty_ioctl_helper(tty, NULL, TCGETS, (unsigned long)&settings);
+ settings.c_cflag &= ~CRTSCTS;
+ n_tty_ioctl_helper(tty, NULL, TCSETS, (unsigned long)&settings);
+
+ /* Clear RTS first */
+ status = tty->driver->ops->tiocmget(tty, NULL);
+ tty->driver->ops->tiocmset(tty, NULL, 0x00, TIOCM_RTS);
+ mdelay(20);
+
+ /* Set RTS, wake up board */
+ status = tty->driver->ops->tiocmget(tty, NULL);
+ tty->driver->ops->tiocmset(tty, NULL, TIOCM_RTS, 0x00);
+ mdelay(20);
+
+ status = tty->driver->ops->tiocmget(tty, NULL);
+
+ n_tty_ioctl_helper(tty, NULL, TCGETS, (unsigned long)&settings);
+ settings.c_cflag |= CRTSCTS;
+ n_tty_ioctl_helper(tty, NULL, TCSETS, (unsigned long)&settings);
+
+ return status;
+}
+
+static void ath_hci_uart_work(struct work_struct *work)
+{
+ int status;
+ struct ath_struct *ath;
+ struct hci_uart *hu;
+ struct tty_struct *tty;
+
+ ath = container_of(work, struct ath_struct, ctxtsw);
+
+ hu = ath->hu;
+ tty = hu->tty;
+
+ /* verify and wake up controller */
+ if (ath->cur_sleep) {
+ status = ath_wakeup_ar3k(tty);
+ if (!(status & TIOCM_CTS))
+ return;
+ }
+
+ /* Ready to send Data */
+ clear_bit(HCI_UART_SENDING, &hu->tx_state);
+ hci_uart_tx_wakeup(hu);
+}
+
+/* Initialize protocol */
+static int ath_open(struct hci_uart *hu)
+{
+ struct ath_struct *ath;
+
+ BT_DBG("hu %p", hu);
+
+ ath = kzalloc(sizeof(*ath), GFP_ATOMIC);
+ if (!ath)
+ return -ENOMEM;
+
+ skb_queue_head_init(&ath->txq);
+
+ hu->priv = ath;
+ ath->hu = hu;
+
+ INIT_WORK(&ath->ctxtsw, ath_hci_uart_work);
+
+ return 0;
+}
+
+/* Flush protocol data */
+static int ath_flush(struct hci_uart *hu)
+{
+ struct ath_struct *ath = hu->priv;
+
+ BT_DBG("hu %p", hu);
+
+ skb_queue_purge(&ath->txq);
+
+ return 0;
+}
+
+/* Close protocol */
+static int ath_close(struct hci_uart *hu)
+{
+ struct ath_struct *ath = hu->priv;
+
+ BT_DBG("hu %p", hu);
+
+ skb_queue_purge(&ath->txq);
+
+ cancel_work_sync(&ath->ctxtsw);
+
+ hu->priv = NULL;
+ kfree(ath);
+
+ return 0;
+}
+
+#define HCI_OP_ATH_SLEEP 0xFC04
+
+/* Enqueue frame for transmittion */
+static int ath_enqueue(struct hci_uart *hu, struct sk_buff *skb)
+{
+ struct ath_struct *ath = hu->priv;
+
+ if (bt_cb(skb)->pkt_type == HCI_SCODATA_PKT) {
+ kfree_skb(skb);
+ return 0;
+ }
+
+ /*
+ * Update power management enable flag with parameters of
+ * HCI sleep enable vendor specific HCI command.
+ */
+ if (bt_cb(skb)->pkt_type == HCI_COMMAND_PKT) {
+ struct hci_command_hdr *hdr = (void *)skb->data;
+
+ if (__le16_to_cpu(hdr->opcode) == HCI_OP_ATH_SLEEP)
+ ath->cur_sleep = skb->data[HCI_COMMAND_HDR_SIZE];
+ }
+
+ BT_DBG("hu %p skb %p", hu, skb);
+
+ /* Prepend skb with frame type */
+ memcpy(skb_push(skb, 1), &bt_cb(skb)->pkt_type, 1);
+
+ skb_queue_tail(&ath->txq, skb);
+ set_bit(HCI_UART_SENDING, &hu->tx_state);
+
+ schedule_work(&ath->ctxtsw);
+
+ return 0;
+}
+
+static struct sk_buff *ath_dequeue(struct hci_uart *hu)
+{
+ struct ath_struct *ath = hu->priv;
+
+ return skb_dequeue(&ath->txq);
+}
+
+/* Recv data */
+static int ath_recv(struct hci_uart *hu, void *data, int count)
+{
+ if (hci_recv_stream_fragment(hu->hdev, data, count) < 0)
+ BT_ERR("Frame Reassembly Failed");
+
+ return count;
+}
+
+static struct hci_uart_proto athp = {
+ .id = HCI_UART_ATH3K,
+ .open = ath_open,
+ .close = ath_close,
+ .recv = ath_recv,
+ .enqueue = ath_enqueue,
+ .dequeue = ath_dequeue,
+ .flush = ath_flush,
+};
+
+int __init ath_init(void)
+{
+ int err = hci_uart_register_proto(&athp);
+
+ if (!err)
+ BT_INFO("HCIATH3K protocol initialized");
+ else
+ BT_ERR("HCIATH3K protocol registration failed");
+
+ return err;
+}
+
+int __exit ath_deinit(void)
+{
+ return hci_uart_unregister_proto(&athp);
+}
diff --git a/drivers/bluetooth/hci_bcsp.c b/drivers/bluetooth/hci_bcsp.c
index 42d69d4de05..9c5b2dc38e2 100644
--- a/drivers/bluetooth/hci_bcsp.c
+++ b/drivers/bluetooth/hci_bcsp.c
@@ -739,7 +739,7 @@ static struct hci_uart_proto bcsp = {
.flush = bcsp_flush
};
-int bcsp_init(void)
+int __init bcsp_init(void)
{
int err = hci_uart_register_proto(&bcsp);
@@ -751,7 +751,7 @@ int bcsp_init(void)
return err;
}
-int bcsp_deinit(void)
+int __exit bcsp_deinit(void)
{
return hci_uart_unregister_proto(&bcsp);
}
diff --git a/drivers/bluetooth/hci_h4.c b/drivers/bluetooth/hci_h4.c
index 3f038f5308a..7b8ad93e2c3 100644
--- a/drivers/bluetooth/hci_h4.c
+++ b/drivers/bluetooth/hci_h4.c
@@ -151,107 +151,8 @@ static inline int h4_check_data_len(struct h4_struct *h4, int len)
/* Recv data */
static int h4_recv(struct hci_uart *hu, void *data, int count)
{
- struct h4_struct *h4 = hu->priv;
- register char *ptr;
- struct hci_event_hdr *eh;
- struct hci_acl_hdr *ah;
- struct hci_sco_hdr *sh;
- register int len, type, dlen;
-
- BT_DBG("hu %p count %d rx_state %ld rx_count %ld",
- hu, count, h4->rx_state, h4->rx_count);
-
- ptr = data;
- while (count) {
- if (h4->rx_count) {
- len = min_t(unsigned int, h4->rx_count, count);
- memcpy(skb_put(h4->rx_skb, len), ptr, len);
- h4->rx_count -= len; count -= len; ptr += len;
-
- if (h4->rx_count)
- continue;
-
- switch (h4->rx_state) {
- case H4_W4_DATA:
- BT_DBG("Complete data");
-
- hci_recv_frame(h4->rx_skb);
-
- h4->rx_state = H4_W4_PACKET_TYPE;
- h4->rx_skb = NULL;
- continue;
-
- case H4_W4_EVENT_HDR:
- eh = hci_event_hdr(h4->rx_skb);
-
- BT_DBG("Event header: evt 0x%2.2x plen %d", eh->evt, eh->plen);
-
- h4_check_data_len(h4, eh->plen);
- continue;
-
- case H4_W4_ACL_HDR:
- ah = hci_acl_hdr(h4->rx_skb);
- dlen = __le16_to_cpu(ah->dlen);
-
- BT_DBG("ACL header: dlen %d", dlen);
-
- h4_check_data_len(h4, dlen);
- continue;
-
- case H4_W4_SCO_HDR:
- sh = hci_sco_hdr(h4->rx_skb);
-
- BT_DBG("SCO header: dlen %d", sh->dlen);
-
- h4_check_data_len(h4, sh->dlen);
- continue;
- }
- }
-
- /* H4_W4_PACKET_TYPE */
- switch (*ptr) {
- case HCI_EVENT_PKT:
- BT_DBG("Event packet");
- h4->rx_state = H4_W4_EVENT_HDR;
- h4->rx_count = HCI_EVENT_HDR_SIZE;
- type = HCI_EVENT_PKT;
- break;
-
- case HCI_ACLDATA_PKT:
- BT_DBG("ACL packet");
- h4->rx_state = H4_W4_ACL_HDR;
- h4->rx_count = HCI_ACL_HDR_SIZE;
- type = HCI_ACLDATA_PKT;
- break;
-
- case HCI_SCODATA_PKT:
- BT_DBG("SCO packet");
- h4->rx_state = H4_W4_SCO_HDR;
- h4->rx_count = HCI_SCO_HDR_SIZE;
- type = HCI_SCODATA_PKT;
- break;
-
- default:
- BT_ERR("Unknown HCI packet type %2.2x", (__u8)*ptr);
- hu->hdev->stat.err_rx++;
- ptr++; count--;
- continue;
- };
-
- ptr++; count--;
-
- /* Allocate packet */
- h4->rx_skb = bt_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC);
- if (!h4->rx_skb) {
- BT_ERR("Can't allocate mem for new packet");
- h4->rx_state = H4_W4_PACKET_TYPE;
- h4->rx_count = 0;
- return -ENOMEM;
- }
-
- h4->rx_skb->dev = (void *) hu->hdev;
- bt_cb(h4->rx_skb)->pkt_type = type;
- }
+ if (hci_recv_stream_fragment(hu->hdev, data, count) < 0)
+ BT_ERR("Frame Reassembly Failed");
return count;
}
@@ -272,7 +173,7 @@ static struct hci_uart_proto h4p = {
.flush = h4_flush,
};
-int h4_init(void)
+int __init h4_init(void)
{
int err = hci_uart_register_proto(&h4p);
@@ -284,7 +185,7 @@ int h4_init(void)
return err;
}
-int h4_deinit(void)
+int __exit h4_deinit(void)
{
return hci_uart_unregister_proto(&h4p);
}
diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c
index 76a1abb8f21..998833d93c1 100644
--- a/drivers/bluetooth/hci_ldisc.c
+++ b/drivers/bluetooth/hci_ldisc.c
@@ -210,7 +210,6 @@ static int hci_uart_close(struct hci_dev *hdev)
static int hci_uart_send_frame(struct sk_buff *skb)
{
struct hci_dev* hdev = (struct hci_dev *) skb->dev;
- struct tty_struct *tty;
struct hci_uart *hu;
if (!hdev) {
@@ -222,7 +221,6 @@ static int hci_uart_send_frame(struct sk_buff *skb)
return -EBUSY;
hu = (struct hci_uart *) hdev->driver_data;
- tty = hu->tty;
BT_DBG("%s: type %d len %d", hdev->name, bt_cb(skb)->pkt_type, skb->len);
@@ -397,6 +395,9 @@ static int hci_uart_register_dev(struct hci_uart *hu)
if (!reset)
set_bit(HCI_QUIRK_NO_RESET, &hdev->quirks);
+ if (test_bit(HCI_UART_RAW_DEVICE, &hu->hdev_flags))
+ set_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks);
+
if (hci_register_dev(hdev) < 0) {
BT_ERR("Can't register HCI device");
hci_free_dev(hdev);
@@ -477,6 +478,15 @@ static int hci_uart_tty_ioctl(struct tty_struct *tty, struct file * file,
return hu->hdev->id;
return -EUNATCH;
+ case HCIUARTSETFLAGS:
+ if (test_bit(HCI_UART_PROTO_SET, &hu->flags))
+ return -EBUSY;
+ hu->hdev_flags = arg;
+ break;
+
+ case HCIUARTGETFLAGS:
+ return hu->hdev_flags;
+
default:
err = n_tty_ioctl_helper(tty, file, cmd, arg);
break;
@@ -542,6 +552,9 @@ static int __init hci_uart_init(void)
#ifdef CONFIG_BT_HCIUART_LL
ll_init();
#endif
+#ifdef CONFIG_BT_HCIUART_ATH3K
+ ath_init();
+#endif
return 0;
}
@@ -559,6 +572,9 @@ static void __exit hci_uart_exit(void)
#ifdef CONFIG_BT_HCIUART_LL
ll_deinit();
#endif
+#ifdef CONFIG_BT_HCIUART_ATH3K
+ ath_deinit();
+#endif
/* Release tty registration of line discipline */
if ((err = tty_unregister_ldisc(N_HCI)))
diff --git a/drivers/bluetooth/hci_ll.c b/drivers/bluetooth/hci_ll.c
index fb8445c7365..38595e782d0 100644
--- a/drivers/bluetooth/hci_ll.c
+++ b/drivers/bluetooth/hci_ll.c
@@ -74,7 +74,7 @@ enum hcill_states_e {
struct hcill_cmd {
u8 cmd;
-} __attribute__((packed));
+} __packed;
struct ll_struct {
unsigned long rx_state;
@@ -517,7 +517,7 @@ static struct hci_uart_proto llp = {
.flush = ll_flush,
};
-int ll_init(void)
+int __init ll_init(void)
{
int err = hci_uart_register_proto(&llp);
@@ -529,7 +529,7 @@ int ll_init(void)
return err;
}
-int ll_deinit(void)
+int __exit ll_deinit(void)
{
return hci_uart_unregister_proto(&llp);
}
diff --git a/drivers/bluetooth/hci_uart.h b/drivers/bluetooth/hci_uart.h
index 50113db06b9..99fb35239d1 100644
--- a/drivers/bluetooth/hci_uart.h
+++ b/drivers/bluetooth/hci_uart.h
@@ -31,15 +31,20 @@
#define HCIUARTSETPROTO _IOW('U', 200, int)
#define HCIUARTGETPROTO _IOR('U', 201, int)
#define HCIUARTGETDEVICE _IOR('U', 202, int)
+#define HCIUARTSETFLAGS _IOW('U', 203, int)
+#define HCIUARTGETFLAGS _IOR('U', 204, int)
/* UART protocols */
-#define HCI_UART_MAX_PROTO 5
+#define HCI_UART_MAX_PROTO 6
#define HCI_UART_H4 0
#define HCI_UART_BCSP 1
#define HCI_UART_3WIRE 2
#define HCI_UART_H4DS 3
#define HCI_UART_LL 4
+#define HCI_UART_ATH3K 5
+
+#define HCI_UART_RAW_DEVICE 0
struct hci_uart;
@@ -57,6 +62,7 @@ struct hci_uart {
struct tty_struct *tty;
struct hci_dev *hdev;
unsigned long flags;
+ unsigned long hdev_flags;
struct hci_uart_proto *proto;
void *priv;
@@ -66,7 +72,7 @@ struct hci_uart {
spinlock_t rx_lock;
};
-/* HCI_UART flag bits */
+/* HCI_UART proto flag bits */
#define HCI_UART_PROTO_SET 0
/* TX states */
@@ -91,3 +97,8 @@ int bcsp_deinit(void);
int ll_init(void);
int ll_deinit(void);
#endif
+
+#ifdef CONFIG_BT_HCIUART_ATH3K
+int ath_init(void);
+int ath_deinit(void);
+#endif
diff --git a/drivers/char/agp/efficeon-agp.c b/drivers/char/agp/efficeon-agp.c
index aa109cbe0e6..d607f53d8af 100644
--- a/drivers/char/agp/efficeon-agp.c
+++ b/drivers/char/agp/efficeon-agp.c
@@ -372,6 +372,17 @@ static int __devinit agp_efficeon_probe(struct pci_dev *pdev,
bridge->capndx = cap_ptr;
/*
+ * If the device has not been properly setup, the following will catch
+ * the problem and should stop the system from crashing.
+ * 20030610 - hamish@zot.org
+ */
+ if (pci_enable_device(pdev)) {
+ printk(KERN_ERR PFX "Unable to Enable PCI device\n");
+ agp_put_bridge(bridge);
+ return -ENODEV;
+ }
+
+ /*
* The following fixes the case where the BIOS has "forgotten" to
* provide an address range for the GART.
* 20030610 - hamish@zot.org
@@ -385,17 +396,6 @@ static int __devinit agp_efficeon_probe(struct pci_dev *pdev,
}
}
- /*
- * If the device has not been properly setup, the following will catch
- * the problem and should stop the system from crashing.
- * 20030610 - hamish@zot.org
- */
- if (pci_enable_device(pdev)) {
- printk(KERN_ERR PFX "Unable to Enable PCI device\n");
- agp_put_bridge(bridge);
- return -ENODEV;
- }
-
/* Fill in the mode register */
if (cap_ptr) {
pci_read_config_dword(pdev,
diff --git a/drivers/char/agp/intel-agp.c b/drivers/char/agp/intel-agp.c
index d836a71bf06..ddf5def1b0d 100644
--- a/drivers/char/agp/intel-agp.c
+++ b/drivers/char/agp/intel-agp.c
@@ -816,9 +816,9 @@ static const struct intel_driver_description {
{ PCI_DEVICE_ID_INTEL_IRONLAKE_MC2_HB, PCI_DEVICE_ID_INTEL_IRONLAKE_M_IG,
"HD Graphics", NULL, &intel_i965_driver },
{ PCI_DEVICE_ID_INTEL_SANDYBRIDGE_HB, PCI_DEVICE_ID_INTEL_SANDYBRIDGE_IG,
- "Sandybridge", NULL, &intel_i965_driver },
+ "Sandybridge", NULL, &intel_gen6_driver },
{ PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_HB, PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_IG,
- "Sandybridge", NULL, &intel_i965_driver },
+ "Sandybridge", NULL, &intel_gen6_driver },
{ 0, 0, NULL, NULL, NULL }
};
@@ -908,6 +908,17 @@ static int __devinit agp_intel_probe(struct pci_dev *pdev,
dev_info(&pdev->dev, "Intel %s Chipset\n", intel_agp_chipsets[i].name);
/*
+ * If the device has not been properly setup, the following will catch
+ * the problem and should stop the system from crashing.
+ * 20030610 - hamish@zot.org
+ */
+ if (pci_enable_device(pdev)) {
+ dev_err(&pdev->dev, "can't enable PCI device\n");
+ agp_put_bridge(bridge);
+ return -ENODEV;
+ }
+
+ /*
* The following fixes the case where the BIOS has "forgotten" to
* provide an address range for the GART.
* 20030610 - hamish@zot.org
@@ -921,17 +932,6 @@ static int __devinit agp_intel_probe(struct pci_dev *pdev,
}
}
- /*
- * If the device has not been properly setup, the following will catch
- * the problem and should stop the system from crashing.
- * 20030610 - hamish@zot.org
- */
- if (pci_enable_device(pdev)) {
- dev_err(&pdev->dev, "can't enable PCI device\n");
- agp_put_bridge(bridge);
- return -ENODEV;
- }
-
/* Fill in the mode register */
if (cap_ptr) {
pci_read_config_dword(pdev,
diff --git a/drivers/char/agp/intel-agp.h b/drivers/char/agp/intel-agp.h
index 2547465d465..c05e3e51826 100644
--- a/drivers/char/agp/intel-agp.h
+++ b/drivers/char/agp/intel-agp.h
@@ -60,6 +60,12 @@
#define I810_PTE_LOCAL 0x00000002
#define I810_PTE_VALID 0x00000001
#define I830_PTE_SYSTEM_CACHED 0x00000006
+/* GT PTE cache control fields */
+#define GEN6_PTE_UNCACHED 0x00000002
+#define GEN6_PTE_LLC 0x00000004
+#define GEN6_PTE_LLC_MLC 0x00000006
+#define GEN6_PTE_GFDT 0x00000008
+
#define I810_SMRAM_MISCC 0x70
#define I810_GFX_MEM_WIN_SIZE 0x00010000
#define I810_GFX_MEM_WIN_32M 0x00010000
diff --git a/drivers/char/agp/intel-gtt.c b/drivers/char/agp/intel-gtt.c
index a7547150a70..d22ffb811bf 100644
--- a/drivers/char/agp/intel-gtt.c
+++ b/drivers/char/agp/intel-gtt.c
@@ -25,6 +25,10 @@
#define USE_PCI_DMA_API 1
#endif
+/* Max amount of stolen space, anything above will be returned to Linux */
+int intel_max_stolen = 32 * 1024 * 1024;
+EXPORT_SYMBOL(intel_max_stolen);
+
static const struct aper_size_info_fixed intel_i810_sizes[] =
{
{64, 16384, 4},
@@ -104,7 +108,7 @@ static int intel_agp_map_memory(struct agp_memory *mem)
DBG("try mapping %lu pages\n", (unsigned long)mem->page_count);
if (sg_alloc_table(&st, mem->page_count, GFP_KERNEL))
- return -ENOMEM;
+ goto err;
mem->sg_list = sg = st.sgl;
@@ -113,11 +117,14 @@ static int intel_agp_map_memory(struct agp_memory *mem)
mem->num_sg = pci_map_sg(intel_private.pcidev, mem->sg_list,
mem->page_count, PCI_DMA_BIDIRECTIONAL);
- if (unlikely(!mem->num_sg)) {
- intel_agp_free_sglist(mem);
- return -ENOMEM;
- }
+ if (unlikely(!mem->num_sg))
+ goto err;
+
return 0;
+
+err:
+ sg_free_table(&st);
+ return -ENOMEM;
}
static void intel_agp_unmap_memory(struct agp_memory *mem)
@@ -176,7 +183,7 @@ static void intel_agp_insert_sg_entries(struct agp_memory *mem,
if (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_SANDYBRIDGE_HB ||
agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_HB)
{
- cache_bits = I830_PTE_SYSTEM_CACHED;
+ cache_bits = GEN6_PTE_LLC_MLC;
}
for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {
@@ -710,7 +717,12 @@ static void intel_i830_init_gtt_entries(void)
break;
}
}
- if (gtt_entries > 0) {
+ if (!local && gtt_entries > intel_max_stolen) {
+ dev_info(&agp_bridge->dev->dev,
+ "detected %dK stolen memory, trimming to %dK\n",
+ gtt_entries / KB(1), intel_max_stolen / KB(1));
+ gtt_entries = intel_max_stolen / KB(4);
+ } else if (gtt_entries > 0) {
dev_info(&agp_bridge->dev->dev, "detected %dK %s memory\n",
gtt_entries / KB(1), local ? "local" : "stolen");
gtt_entries /= KB(4);
@@ -797,6 +809,10 @@ static int intel_i830_create_gatt_table(struct agp_bridge_data *bridge)
/* we have to call this as early as possible after the MMIO base address is known */
intel_i830_init_gtt_entries();
+ if (intel_private.gtt_entries == 0) {
+ iounmap(intel_private.registers);
+ return -ENOMEM;
+ }
agp_bridge->gatt_table = NULL;
@@ -1282,6 +1298,11 @@ static int intel_i915_create_gatt_table(struct agp_bridge_data *bridge)
/* we have to call this as early as possible after the MMIO base address is known */
intel_i830_init_gtt_entries();
+ if (intel_private.gtt_entries == 0) {
+ iounmap(intel_private.gtt);
+ iounmap(intel_private.registers);
+ return -ENOMEM;
+ }
agp_bridge->gatt_table = NULL;
@@ -1309,6 +1330,16 @@ static unsigned long intel_i965_mask_memory(struct agp_bridge_data *bridge,
return addr | bridge->driver->masks[type].mask;
}
+static unsigned long intel_gen6_mask_memory(struct agp_bridge_data *bridge,
+ dma_addr_t addr, int type)
+{
+ /* Shift high bits down */
+ addr |= (addr >> 28) & 0xff;
+
+ /* Type checking must be done elsewhere */
+ return addr | bridge->driver->masks[type].mask;
+}
+
static void intel_i965_get_gtt_range(int *gtt_offset, int *gtt_size)
{
u16 snb_gmch_ctl;
@@ -1390,6 +1421,11 @@ static int intel_i965_create_gatt_table(struct agp_bridge_data *bridge)
/* we have to call this as early as possible after the MMIO base address is known */
intel_i830_init_gtt_entries();
+ if (intel_private.gtt_entries == 0) {
+ iounmap(intel_private.gtt);
+ iounmap(intel_private.registers);
+ return -ENOMEM;
+ }
agp_bridge->gatt_table = NULL;
@@ -1517,6 +1553,39 @@ static const struct agp_bridge_driver intel_i965_driver = {
#endif
};
+static const struct agp_bridge_driver intel_gen6_driver = {
+ .owner = THIS_MODULE,
+ .aperture_sizes = intel_i830_sizes,
+ .size_type = FIXED_APER_SIZE,
+ .num_aperture_sizes = 4,
+ .needs_scratch_page = true,
+ .configure = intel_i9xx_configure,
+ .fetch_size = intel_i9xx_fetch_size,
+ .cleanup = intel_i915_cleanup,
+ .mask_memory = intel_gen6_mask_memory,
+ .masks = intel_i810_masks,
+ .agp_enable = intel_i810_agp_enable,
+ .cache_flush = global_cache_flush,
+ .create_gatt_table = intel_i965_create_gatt_table,
+ .free_gatt_table = intel_i830_free_gatt_table,
+ .insert_memory = intel_i915_insert_entries,
+ .remove_memory = intel_i915_remove_entries,
+ .alloc_by_type = intel_i830_alloc_by_type,
+ .free_by_type = intel_i810_free_by_type,
+ .agp_alloc_page = agp_generic_alloc_page,
+ .agp_alloc_pages = agp_generic_alloc_pages,
+ .agp_destroy_page = agp_generic_destroy_page,
+ .agp_destroy_pages = agp_generic_destroy_pages,
+ .agp_type_to_mask_type = intel_i830_type_to_mask_type,
+ .chipset_flush = intel_i915_chipset_flush,
+#ifdef USE_PCI_DMA_API
+ .agp_map_page = intel_agp_map_page,
+ .agp_unmap_page = intel_agp_unmap_page,
+ .agp_map_memory = intel_agp_map_memory,
+ .agp_unmap_memory = intel_agp_unmap_memory,
+#endif
+};
+
static const struct agp_bridge_driver intel_g33_driver = {
.owner = THIS_MODULE,
.aperture_sizes = intel_i830_sizes,
diff --git a/drivers/char/bsr.c b/drivers/char/bsr.c
index 89d871ef8c2..91917133ae0 100644
--- a/drivers/char/bsr.c
+++ b/drivers/char/bsr.c
@@ -23,6 +23,7 @@
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/of_platform.h>
+#include <linux/fs.h>
#include <linux/module.h>
#include <linux/cdev.h>
#include <linux/list.h>
diff --git a/drivers/char/hvc_console.c b/drivers/char/hvc_console.c
index 35cca4c7fb1..fa27d1676ee 100644
--- a/drivers/char/hvc_console.c
+++ b/drivers/char/hvc_console.c
@@ -194,7 +194,7 @@ static int __init hvc_console_setup(struct console *co, char *options)
return 0;
}
-static struct console hvc_con_driver = {
+static struct console hvc_console = {
.name = "hvc",
.write = hvc_console_print,
.device = hvc_console_device,
@@ -220,7 +220,7 @@ static struct console hvc_con_driver = {
*/
static int __init hvc_console_init(void)
{
- register_console(&hvc_con_driver);
+ register_console(&hvc_console);
return 0;
}
console_initcall(hvc_console_init);
@@ -276,8 +276,8 @@ int hvc_instantiate(uint32_t vtermno, int index, const struct hv_ops *ops)
* now (setup won't fail at this point). It's ok to just
* call register again if previously .setup failed.
*/
- if (index == hvc_con_driver.index)
- register_console(&hvc_con_driver);
+ if (index == hvc_console.index)
+ register_console(&hvc_console);
return 0;
}
@@ -641,7 +641,7 @@ int hvc_poll(struct hvc_struct *hp)
}
for (i = 0; i < n; ++i) {
#ifdef CONFIG_MAGIC_SYSRQ
- if (hp->index == hvc_con_driver.index) {
+ if (hp->index == hvc_console.index) {
/* Handle the SysRq Hack */
/* XXX should support a sequence */
if (buf[i] == '\x0f') { /* ^O */
@@ -909,7 +909,7 @@ static void __exit hvc_exit(void)
tty_unregister_driver(hvc_driver);
/* return tty_struct instances allocated in hvc_init(). */
put_tty_driver(hvc_driver);
- unregister_console(&hvc_con_driver);
+ unregister_console(&hvc_console);
}
}
module_exit(hvc_exit);
diff --git a/drivers/char/hvsi.c b/drivers/char/hvsi.c
index d4b14ff1c4c..1f4b6de65a2 100644
--- a/drivers/char/hvsi.c
+++ b/drivers/char/hvsi.c
@@ -1255,7 +1255,7 @@ static int __init hvsi_console_setup(struct console *console, char *options)
return 0;
}
-static struct console hvsi_con_driver = {
+static struct console hvsi_console = {
.name = "hvsi",
.write = hvsi_console_print,
.device = hvsi_console_device,
@@ -1308,7 +1308,7 @@ static int __init hvsi_console_init(void)
}
if (hvsi_count)
- register_console(&hvsi_con_driver);
+ register_console(&hvsi_console);
return 0;
}
console_initcall(hvsi_console_init);
diff --git a/drivers/char/hw_random/n2-drv.c b/drivers/char/hw_random/n2-drv.c
index 0f9cbf1aaf1..7a4f080f835 100644
--- a/drivers/char/hw_random/n2-drv.c
+++ b/drivers/char/hw_random/n2-drv.c
@@ -387,7 +387,7 @@ static int n2rng_init_control(struct n2rng *np)
static int n2rng_data_read(struct hwrng *rng, u32 *data)
{
- struct n2rng *np = (struct n2rng *) rng->priv;
+ struct n2rng *np = rng->priv;
unsigned long ra = __pa(&np->test_data);
int len;
@@ -762,12 +762,12 @@ static struct of_platform_driver n2rng_driver = {
static int __init n2rng_init(void)
{
- return of_register_driver(&n2rng_driver, &of_bus_type);
+ return of_register_platform_driver(&n2rng_driver);
}
static void __exit n2rng_exit(void)
{
- of_unregister_driver(&n2rng_driver);
+ of_unregister_platform_driver(&n2rng_driver);
}
module_init(n2rng_init);
diff --git a/drivers/char/keyboard.c b/drivers/char/keyboard.c
index 54109dc9240..25be2102a60 100644
--- a/drivers/char/keyboard.c
+++ b/drivers/char/keyboard.c
@@ -1315,10 +1315,14 @@ static bool kbd_match(struct input_handler *handler, struct input_dev *dev)
if (test_bit(EV_SND, dev->evbit))
return true;
- if (test_bit(EV_KEY, dev->evbit))
+ if (test_bit(EV_KEY, dev->evbit)) {
for (i = KEY_RESERVED; i < BTN_MISC; i++)
if (test_bit(i, dev->keybit))
return true;
+ for (i = KEY_BRL_DOT1; i <= KEY_BRL_DOT10; i++)
+ if (test_bit(i, dev->keybit))
+ return true;
+ }
return false;
}
diff --git a/drivers/char/mem.c b/drivers/char/mem.c
index f54dab8acdc..a398ecdbd75 100644
--- a/drivers/char/mem.c
+++ b/drivers/char/mem.c
@@ -916,7 +916,7 @@ static int __init chr_dev_init(void)
NULL, devlist[minor].name);
}
- return 0;
+ return tty_init();
}
fs_initcall(chr_dev_init);
diff --git a/drivers/char/pcmcia/cm4000_cs.c b/drivers/char/pcmcia/cm4000_cs.c
index e7956acf2ad..ec73d9f6d9e 100644
--- a/drivers/char/pcmcia/cm4000_cs.c
+++ b/drivers/char/pcmcia/cm4000_cs.c
@@ -34,7 +34,6 @@
#include <linux/uaccess.h>
#include <linux/io.h>
-#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/cistpl.h>
#include <pcmcia/cisreg.h>
@@ -422,7 +421,7 @@ static struct card_fixup card_fixups[] = {
static void set_cardparameter(struct cm4000_dev *dev)
{
int i;
- unsigned int iobase = dev->p_dev->io.BasePort1;
+ unsigned int iobase = dev->p_dev->resource[0]->start;
u_int8_t stopbits = 0x02; /* ISO default */
DEBUGP(3, dev, "-> set_cardparameter\n");
@@ -455,7 +454,7 @@ static int set_protocol(struct cm4000_dev *dev, struct ptsreq *ptsreq)
unsigned short num_bytes_read;
unsigned char pts_reply[4];
ssize_t rc;
- unsigned int iobase = dev->p_dev->io.BasePort1;
+ unsigned int iobase = dev->p_dev->resource[0]->start;
rc = 0;
@@ -664,7 +663,7 @@ static void terminate_monitor(struct cm4000_dev *dev)
static void monitor_card(unsigned long p)
{
struct cm4000_dev *dev = (struct cm4000_dev *) p;
- unsigned int iobase = dev->p_dev->io.BasePort1;
+ unsigned int iobase = dev->p_dev->resource[0]->start;
unsigned short s;
struct ptsreq ptsreq;
int i, atrc;
@@ -925,7 +924,7 @@ static ssize_t cmm_read(struct file *filp, __user char *buf, size_t count,
loff_t *ppos)
{
struct cm4000_dev *dev = filp->private_data;
- unsigned int iobase = dev->p_dev->io.BasePort1;
+ unsigned int iobase = dev->p_dev->resource[0]->start;
ssize_t rc;
int i, j, k;
@@ -1048,7 +1047,7 @@ static ssize_t cmm_write(struct file *filp, const char __user *buf,
size_t count, loff_t *ppos)
{
struct cm4000_dev *dev = filp->private_data;
- unsigned int iobase = dev->p_dev->io.BasePort1;
+ unsigned int iobase = dev->p_dev->resource[0]->start;
unsigned short s;
unsigned char tmp;
unsigned char infolen;
@@ -1401,7 +1400,7 @@ static void stop_monitor(struct cm4000_dev *dev)
static long cmm_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
struct cm4000_dev *dev = filp->private_data;
- unsigned int iobase = dev->p_dev->io.BasePort1;
+ unsigned int iobase = dev->p_dev->resource[0]->start;
struct inode *inode = filp->f_path.dentry->d_inode;
struct pcmcia_device *link;
int size;
@@ -1752,17 +1751,12 @@ static int cm4000_config_check(struct pcmcia_device *p_dev,
if (!cfg->io.nwin)
return -ENODEV;
- /* Get the IOaddr */
- p_dev->io.BasePort1 = cfg->io.win[0].base;
- p_dev->io.NumPorts1 = cfg->io.win[0].len;
- p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
- if (!(cfg->io.flags & CISTPL_IO_8BIT))
- p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_16;
- if (!(cfg->io.flags & CISTPL_IO_16BIT))
- p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
- p_dev->io.IOAddrLines = cfg->io.flags & CISTPL_IO_LINES_MASK;
-
- return pcmcia_request_io(p_dev, &p_dev->io);
+ p_dev->resource[0]->start = cfg->io.win[0].base;
+ p_dev->resource[0]->end = cfg->io.win[0].len;
+ p_dev->resource[0]->flags |= pcmcia_io_cfg_data_width(cfg->io.flags);
+ p_dev->io_lines = cfg->io.flags & CISTPL_IO_LINES_MASK;
+
+ return pcmcia_request_io(p_dev);
}
static int cm4000_config(struct pcmcia_device * link, int devno)
diff --git a/drivers/char/pcmcia/cm4040_cs.c b/drivers/char/pcmcia/cm4040_cs.c
index c0775c844e0..815cde1d057 100644
--- a/drivers/char/pcmcia/cm4040_cs.c
+++ b/drivers/char/pcmcia/cm4040_cs.c
@@ -29,7 +29,6 @@
#include <asm/uaccess.h>
#include <asm/io.h>
-#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/cistpl.h>
#include <pcmcia/cisreg.h>
@@ -110,7 +109,7 @@ static inline unsigned char xinb(unsigned short port)
static void cm4040_do_poll(unsigned long dummy)
{
struct reader_dev *dev = (struct reader_dev *) dummy;
- unsigned int obs = xinb(dev->p_dev->io.BasePort1
+ unsigned int obs = xinb(dev->p_dev->resource[0]->start
+ REG_OFFSET_BUFFER_STATUS);
if ((obs & BSR_BULK_IN_FULL)) {
@@ -141,7 +140,7 @@ static void cm4040_stop_poll(struct reader_dev *dev)
static int wait_for_bulk_out_ready(struct reader_dev *dev)
{
int i, rc;
- int iobase = dev->p_dev->io.BasePort1;
+ int iobase = dev->p_dev->resource[0]->start;
for (i = 0; i < POLL_LOOP_COUNT; i++) {
if ((xinb(iobase + REG_OFFSET_BUFFER_STATUS)
@@ -171,7 +170,7 @@ static int wait_for_bulk_out_ready(struct reader_dev *dev)
/* Write to Sync Control Register */
static int write_sync_reg(unsigned char val, struct reader_dev *dev)
{
- int iobase = dev->p_dev->io.BasePort1;
+ int iobase = dev->p_dev->resource[0]->start;
int rc;
rc = wait_for_bulk_out_ready(dev);
@@ -189,7 +188,7 @@ static int write_sync_reg(unsigned char val, struct reader_dev *dev)
static int wait_for_bulk_in_ready(struct reader_dev *dev)
{
int i, rc;
- int iobase = dev->p_dev->io.BasePort1;
+ int iobase = dev->p_dev->resource[0]->start;
for (i = 0; i < POLL_LOOP_COUNT; i++) {
if ((xinb(iobase + REG_OFFSET_BUFFER_STATUS)
@@ -219,7 +218,7 @@ static ssize_t cm4040_read(struct file *filp, char __user *buf,
size_t count, loff_t *ppos)
{
struct reader_dev *dev = filp->private_data;
- int iobase = dev->p_dev->io.BasePort1;
+ int iobase = dev->p_dev->resource[0]->start;
size_t bytes_to_read;
unsigned long i;
size_t min_bytes_to_read;
@@ -321,7 +320,7 @@ static ssize_t cm4040_write(struct file *filp, const char __user *buf,
size_t count, loff_t *ppos)
{
struct reader_dev *dev = filp->private_data;
- int iobase = dev->p_dev->io.BasePort1;
+ int iobase = dev->p_dev->resource[0]->start;
ssize_t rc;
int i;
unsigned int bytes_to_write;
@@ -528,16 +527,12 @@ static int cm4040_config_check(struct pcmcia_device *p_dev,
return -ENODEV;
/* Get the IOaddr */
- p_dev->io.BasePort1 = cfg->io.win[0].base;
- p_dev->io.NumPorts1 = cfg->io.win[0].len;
- p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
- if (!(cfg->io.flags & CISTPL_IO_8BIT))
- p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_16;
- if (!(cfg->io.flags & CISTPL_IO_16BIT))
- p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
- p_dev->io.IOAddrLines = cfg->io.flags & CISTPL_IO_LINES_MASK;
-
- rc = pcmcia_request_io(p_dev, &p_dev->io);
+ p_dev->resource[0]->start = cfg->io.win[0].base;
+ p_dev->resource[0]->end = cfg->io.win[0].len;
+ p_dev->resource[0]->flags |= pcmcia_io_cfg_data_width(cfg->io.flags);
+ p_dev->io_lines = cfg->io.flags & CISTPL_IO_LINES_MASK;
+ rc = pcmcia_request_io(p_dev);
+
dev_printk(KERN_INFO, &p_dev->dev,
"pcmcia_request_io returned 0x%x\n", rc);
return rc;
@@ -549,10 +544,6 @@ static int reader_config(struct pcmcia_device *link, int devno)
struct reader_dev *dev;
int fail_rc;
- link->io.BasePort2 = 0;
- link->io.NumPorts2 = 0;
- link->io.Attributes2 = 0;
-
if (pcmcia_loop_config(link, cm4040_config_check, NULL))
goto cs_release;
@@ -568,8 +559,8 @@ static int reader_config(struct pcmcia_device *link, int devno)
dev = link->priv;
- DEBUGP(2, dev, "device " DEVICE_NAME "%d at 0x%.4x-0x%.4x\n", devno,
- link->io.BasePort1, link->io.BasePort1+link->io.NumPorts1);
+ DEBUGP(2, dev, "device " DEVICE_NAME "%d at %pR\n", devno,
+ link->resource[0]);
DEBUGP(2, dev, "<- reader_config (succ)\n");
return 0;
diff --git a/drivers/char/pcmcia/ipwireless/main.c b/drivers/char/pcmcia/ipwireless/main.c
index 63c32e3f23b..67bdb05798b 100644
--- a/drivers/char/pcmcia/ipwireless/main.c
+++ b/drivers/char/pcmcia/ipwireless/main.c
@@ -84,23 +84,22 @@ static int ipwireless_probe(struct pcmcia_device *p_dev,
{
struct ipw_dev *ipw = priv_data;
struct resource *io_resource;
- memreq_t memreq_attr_memory;
- memreq_t memreq_common_memory;
int ret;
- p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
- p_dev->io.BasePort1 = cfg->io.win[0].base;
- p_dev->io.NumPorts1 = cfg->io.win[0].len;
- p_dev->io.IOAddrLines = 16;
+ p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO;
+ p_dev->resource[0]->start = cfg->io.win[0].base;
+ p_dev->resource[0]->end = cfg->io.win[0].len;
/* 0x40 causes it to generate level mode interrupts. */
/* 0x04 enables IREQ pin. */
p_dev->conf.ConfigIndex = cfg->index | 0x44;
- ret = pcmcia_request_io(p_dev, &p_dev->io);
+ p_dev->io_lines = 16;
+ ret = pcmcia_request_io(p_dev);
if (ret)
return ret;
- io_resource = request_region(p_dev->io.BasePort1, p_dev->io.NumPorts1,
+ io_resource = request_region(p_dev->resource[0]->start,
+ resource_size(p_dev->resource[0]),
IPWIRELESS_PCCARD_NAME);
if (cfg->mem.nwin == 0)
@@ -120,11 +119,8 @@ static int ipwireless_probe(struct pcmcia_device *p_dev,
if (ret != 0)
goto exit1;
- memreq_common_memory.CardOffset = cfg->mem.win[0].card_addr;
- memreq_common_memory.Page = 0;
-
ret = pcmcia_map_mem_page(p_dev, ipw->handle_common_memory,
- &memreq_common_memory);
+ cfg->mem.win[0].card_addr);
if (ret != 0)
goto exit2;
@@ -149,12 +145,7 @@ static int ipwireless_probe(struct pcmcia_device *p_dev,
if (ret != 0)
goto exit2;
- memreq_attr_memory.CardOffset = 0;
- memreq_attr_memory.Page = 0;
-
- ret = pcmcia_map_mem_page(p_dev, ipw->handle_attr_memory,
- &memreq_attr_memory);
-
+ ret = pcmcia_map_mem_page(p_dev, ipw->handle_attr_memory, 0);
if (ret != 0)
goto exit3;
@@ -166,15 +157,12 @@ static int ipwireless_probe(struct pcmcia_device *p_dev,
return 0;
exit3:
- pcmcia_release_window(p_dev, ipw->handle_attr_memory);
exit2:
if (ipw->common_memory) {
release_mem_region(ipw->request_common_memory.Base,
ipw->request_common_memory.Size);
iounmap(ipw->common_memory);
- pcmcia_release_window(p_dev, ipw->handle_common_memory);
- } else
- pcmcia_release_window(p_dev, ipw->handle_common_memory);
+ }
exit1:
release_resource(io_resource);
pcmcia_disable_device(p_dev);
@@ -197,7 +185,7 @@ static int config_ipwireless(struct ipw_dev *ipw)
INIT_WORK(&ipw->work_reboot, signalled_reboot_work);
- ipwireless_init_hardware_v1(ipw->hardware, link->io.BasePort1,
+ ipwireless_init_hardware_v1(ipw->hardware, link->resource[0]->start,
ipw->attr_memory, ipw->common_memory,
ipw->is_v2_card, signalled_reboot_callback,
ipw);
@@ -209,10 +197,7 @@ static int config_ipwireless(struct ipw_dev *ipw)
printk(KERN_INFO IPWIRELESS_PCCARD_NAME ": Card type %s\n",
ipw->is_v2_card ? "V2/V3" : "V1");
printk(KERN_INFO IPWIRELESS_PCCARD_NAME
- ": I/O ports 0x%04x-0x%04x, irq %d\n",
- (unsigned int) link->io.BasePort1,
- (unsigned int) (link->io.BasePort1 +
- link->io.NumPorts1 - 1),
+ ": I/O ports %pR, irq %d\n", link->resource[0],
(unsigned int) link->irq);
if (ipw->attr_memory && ipw->common_memory)
printk(KERN_INFO IPWIRELESS_PCCARD_NAME
@@ -250,13 +235,12 @@ exit:
release_mem_region(ipw->request_attr_memory.Base,
ipw->request_attr_memory.Size);
iounmap(ipw->attr_memory);
- pcmcia_release_window(link, ipw->handle_attr_memory);
+
}
if (ipw->common_memory) {
release_mem_region(ipw->request_common_memory.Base,
ipw->request_common_memory.Size);
iounmap(ipw->common_memory);
- pcmcia_release_window(link, ipw->handle_common_memory);
}
pcmcia_disable_device(link);
return -1;
@@ -274,11 +258,6 @@ static void release_ipwireless(struct ipw_dev *ipw)
ipw->request_attr_memory.Size);
iounmap(ipw->attr_memory);
}
- if (ipw->common_memory)
- pcmcia_release_window(ipw->link, ipw->handle_common_memory);
- if (ipw->attr_memory)
- pcmcia_release_window(ipw->link, ipw->handle_attr_memory);
-
pcmcia_disable_device(ipw->link);
}
diff --git a/drivers/char/pcmcia/ipwireless/main.h b/drivers/char/pcmcia/ipwireless/main.h
index 96d0ef31b17..c207be87b59 100644
--- a/drivers/char/pcmcia/ipwireless/main.h
+++ b/drivers/char/pcmcia/ipwireless/main.h
@@ -21,7 +21,6 @@
#include <linux/sched.h>
#include <linux/types.h>
-#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/cistpl.h>
#include <pcmcia/ds.h>
diff --git a/drivers/char/pcmcia/ipwireless/tty.h b/drivers/char/pcmcia/ipwireless/tty.h
index 4da6c201f72..3e163d4cab1 100644
--- a/drivers/char/pcmcia/ipwireless/tty.h
+++ b/drivers/char/pcmcia/ipwireless/tty.h
@@ -21,7 +21,6 @@
#include <linux/types.h>
#include <linux/sched.h>
-#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/cistpl.h>
#include <pcmcia/ds.h>
diff --git a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c
index 308903ec8bf..9ecd6bef5d3 100644
--- a/drivers/char/pcmcia/synclink_cs.c
+++ b/drivers/char/pcmcia/synclink_cs.c
@@ -70,7 +70,6 @@
#include <linux/workqueue.h>
#include <linux/hdlc.h>
-#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/cistpl.h>
#include <pcmcia/cisreg.h>
@@ -572,18 +571,15 @@ static int mgslpc_ioprobe(struct pcmcia_device *p_dev,
unsigned int vcc,
void *priv_data)
{
- if (cfg->io.nwin > 0) {
- p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
- if (!(cfg->io.flags & CISTPL_IO_8BIT))
- p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_16;
- if (!(cfg->io.flags & CISTPL_IO_16BIT))
- p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
- p_dev->io.IOAddrLines = cfg->io.flags & CISTPL_IO_LINES_MASK;
- p_dev->io.BasePort1 = cfg->io.win[0].base;
- p_dev->io.NumPorts1 = cfg->io.win[0].len;
- return pcmcia_request_io(p_dev, &p_dev->io);
- }
- return -ENODEV;
+ if (!cfg->io.nwin)
+ return -ENODEV;
+
+ p_dev->resource[0]->start = cfg->io.win[0].base;
+ p_dev->resource[0]->end = cfg->io.win[0].len;
+ p_dev->resource[0]->flags |= pcmcia_io_cfg_data_width(cfg->io.flags);
+ p_dev->io_lines = cfg->io.flags & CISTPL_IO_LINES_MASK;
+
+ return pcmcia_request_io(p_dev);
}
static int mgslpc_config(struct pcmcia_device *link)
@@ -610,16 +606,15 @@ static int mgslpc_config(struct pcmcia_device *link)
if (ret)
goto failed;
- info->io_base = link->io.BasePort1;
+ info->io_base = link->resource[0]->start;
info->irq_level = link->irq;
dev_info(&link->dev, "index 0x%02x:",
link->conf.ConfigIndex);
if (link->conf.Attributes & CONF_ENABLE_IRQ)
printk(", irq %d", link->irq);
- if (link->io.NumPorts1)
- printk(", io 0x%04x-0x%04x", link->io.BasePort1,
- link->io.BasePort1+link->io.NumPorts1-1);
+ if (link->resource[0])
+ printk(", io %pR", link->resource[0]);
printk("\n");
return 0;
diff --git a/drivers/char/random.c b/drivers/char/random.c
index 8d85587b6d4..caef35a4689 100644
--- a/drivers/char/random.c
+++ b/drivers/char/random.c
@@ -407,8 +407,8 @@ struct entropy_store {
struct poolinfo *poolinfo;
__u32 *pool;
const char *name;
- int limit;
struct entropy_store *pull;
+ int limit;
/* read-write data: */
spinlock_t lock;
diff --git a/drivers/char/synclink_gt.c b/drivers/char/synclink_gt.c
index 4561ce2fba6..334cf5c8c8b 100644
--- a/drivers/char/synclink_gt.c
+++ b/drivers/char/synclink_gt.c
@@ -4845,7 +4845,7 @@ static int register_test(struct slgt_info *info)
{
static unsigned short patterns[] =
{0x0000, 0xffff, 0xaaaa, 0x5555, 0x6969, 0x9696};
- static unsigned int count = sizeof(patterns)/sizeof(patterns[0]);
+ static unsigned int count = ARRAY_SIZE(patterns);
unsigned int i;
int rc = 0;
diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c
index d71f0fc34b4..507441ac6ed 100644
--- a/drivers/char/tty_io.c
+++ b/drivers/char/tty_io.c
@@ -3128,7 +3128,7 @@ static struct cdev tty_cdev, console_cdev;
* Ok, now we can initialize the rest of the tty devices and can count
* on memory allocations, interrupts etc..
*/
-static int __init tty_init(void)
+int __init tty_init(void)
{
cdev_init(&tty_cdev, &tty_fops);
if (cdev_add(&tty_cdev, MKDEV(TTYAUX_MAJOR, 0), 1) ||
@@ -3149,4 +3149,4 @@ static int __init tty_init(void)
#endif
return 0;
}
-module_init(tty_init);
+
diff --git a/drivers/char/vt.c b/drivers/char/vt.c
index 7cdb6ee569c..4a9eb3044e5 100644
--- a/drivers/char/vt.c
+++ b/drivers/char/vt.c
@@ -104,6 +104,7 @@
#include <linux/io.h>
#include <asm/system.h>
#include <linux/uaccess.h>
+#include <linux/kdb.h>
#define MAX_NR_CON_DRIVER 16
@@ -187,10 +188,15 @@ static DECLARE_WORK(console_work, console_callback);
* fg_console is the current virtual console,
* last_console is the last used one,
* want_console is the console we want to switch to,
+ * saved_* variants are for save/restore around kernel debugger enter/leave
*/
int fg_console;
int last_console;
int want_console = -1;
+int saved_fg_console;
+int saved_last_console;
+int saved_want_console;
+int saved_vc_mode;
/*
* For each existing display, we have a pointer to console currently visible
@@ -3414,6 +3420,78 @@ int con_is_bound(const struct consw *csw)
EXPORT_SYMBOL(con_is_bound);
/**
+ * con_debug_enter - prepare the console for the kernel debugger
+ * @sw: console driver
+ *
+ * Called when the console is taken over by the kernel debugger, this
+ * function needs to save the current console state, then put the console
+ * into a state suitable for the kernel debugger.
+ *
+ * RETURNS:
+ * Zero on success, nonzero if a failure occurred when trying to prepare
+ * the console for the debugger.
+ */
+int con_debug_enter(struct vc_data *vc)
+{
+ int ret = 0;
+
+ saved_fg_console = fg_console;
+ saved_last_console = last_console;
+ saved_want_console = want_console;
+ saved_vc_mode = vc->vc_mode;
+ vc->vc_mode = KD_TEXT;
+ console_blanked = 0;
+ if (vc->vc_sw->con_debug_enter)
+ ret = vc->vc_sw->con_debug_enter(vc);
+#ifdef CONFIG_KGDB_KDB
+ /* Set the initial LINES variable if it is not already set */
+ if (vc->vc_rows < 999) {
+ int linecount;
+ char lns[4];
+ const char *setargs[3] = {
+ "set",
+ "LINES",
+ lns,
+ };
+ if (kdbgetintenv(setargs[0], &linecount)) {
+ snprintf(lns, 4, "%i", vc->vc_rows);
+ kdb_set(2, setargs);
+ }
+ }
+#endif /* CONFIG_KGDB_KDB */
+ return ret;
+}
+EXPORT_SYMBOL_GPL(con_debug_enter);
+
+/**
+ * con_debug_leave - restore console state
+ * @sw: console driver
+ *
+ * Restore the console state to what it was before the kernel debugger
+ * was invoked.
+ *
+ * RETURNS:
+ * Zero on success, nonzero if a failure occurred when trying to restore
+ * the console.
+ */
+int con_debug_leave(void)
+{
+ struct vc_data *vc;
+ int ret = 0;
+
+ fg_console = saved_fg_console;
+ last_console = saved_last_console;
+ want_console = saved_want_console;
+ vc_cons[fg_console].d->vc_mode = saved_vc_mode;
+
+ vc = vc_cons[fg_console].d;
+ if (vc->vc_sw->con_debug_leave)
+ ret = vc->vc_sw->con_debug_leave(vc);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(con_debug_leave);
+
+/**
* register_con_driver - register console driver to console layer
* @csw: console driver
* @first: the first console to take over, minimum value is 0
diff --git a/drivers/clocksource/acpi_pm.c b/drivers/clocksource/acpi_pm.c
index 72a633a6ec9..cfb0f527841 100644
--- a/drivers/clocksource/acpi_pm.c
+++ b/drivers/clocksource/acpi_pm.c
@@ -68,10 +68,7 @@ static struct clocksource clocksource_acpi_pm = {
.rating = 200,
.read = acpi_pm_read,
.mask = (cycle_t)ACPI_PM_MASK,
- .mult = 0, /*to be calculated*/
- .shift = 22,
.flags = CLOCK_SOURCE_IS_CONTINUOUS,
-
};
@@ -190,9 +187,6 @@ static int __init init_acpi_pm_clocksource(void)
if (!pmtmr_ioport)
return -ENODEV;
- clocksource_acpi_pm.mult = clocksource_hz2mult(PMTMR_TICKS_PER_SEC,
- clocksource_acpi_pm.shift);
-
/* "verify" this timing source: */
for (j = 0; j < ACPI_PM_MONOTONICITY_CHECKS; j++) {
udelay(100 * j);
@@ -220,7 +214,8 @@ static int __init init_acpi_pm_clocksource(void)
if (verify_pmtmr_rate() != 0)
return -ENODEV;
- return clocksource_register(&clocksource_acpi_pm);
+ return clocksource_register_hz(&clocksource_acpi_pm,
+ PMTMR_TICKS_PER_SEC);
}
/* We use fs_initcall because we want the PCI fixups to have run
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
index 938b74ea9ff..199dcb9f0b8 100644
--- a/drivers/cpufreq/cpufreq.c
+++ b/drivers/cpufreq/cpufreq.c
@@ -29,6 +29,8 @@
#include <linux/completion.h>
#include <linux/mutex.h>
+#include <trace/events/power.h>
+
#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_CORE, \
"cpufreq-core", msg)
@@ -68,7 +70,7 @@ static DEFINE_PER_CPU(int, cpufreq_policy_cpu);
static DEFINE_PER_CPU(struct rw_semaphore, cpu_policy_rwsem);
#define lock_policy_rwsem(mode, cpu) \
-int lock_policy_rwsem_##mode \
+static int lock_policy_rwsem_##mode \
(int cpu) \
{ \
int policy_cpu = per_cpu(cpufreq_policy_cpu, cpu); \
@@ -83,26 +85,22 @@ int lock_policy_rwsem_##mode \
}
lock_policy_rwsem(read, cpu);
-EXPORT_SYMBOL_GPL(lock_policy_rwsem_read);
lock_policy_rwsem(write, cpu);
-EXPORT_SYMBOL_GPL(lock_policy_rwsem_write);
-void unlock_policy_rwsem_read(int cpu)
+static void unlock_policy_rwsem_read(int cpu)
{
int policy_cpu = per_cpu(cpufreq_policy_cpu, cpu);
BUG_ON(policy_cpu == -1);
up_read(&per_cpu(cpu_policy_rwsem, policy_cpu));
}
-EXPORT_SYMBOL_GPL(unlock_policy_rwsem_read);
-void unlock_policy_rwsem_write(int cpu)
+static void unlock_policy_rwsem_write(int cpu)
{
int policy_cpu = per_cpu(cpufreq_policy_cpu, cpu);
BUG_ON(policy_cpu == -1);
up_write(&per_cpu(cpu_policy_rwsem, policy_cpu));
}
-EXPORT_SYMBOL_GPL(unlock_policy_rwsem_write);
/* internal prototypes */
@@ -354,6 +352,9 @@ void cpufreq_notify_transition(struct cpufreq_freqs *freqs, unsigned int state)
case CPUFREQ_POSTCHANGE:
adjust_jiffies(CPUFREQ_POSTCHANGE, freqs);
+ dprintk("FREQ: %lu - CPU: %lu", (unsigned long)freqs->new,
+ (unsigned long)freqs->cpu);
+ trace_power_frequency(POWER_PSTATE, freqs->new, freqs->cpu);
srcu_notifier_call_chain(&cpufreq_transition_notifier_list,
CPUFREQ_POSTCHANGE, freqs);
if (likely(policy) && likely(policy->cpu == freqs->cpu))
@@ -1875,8 +1876,7 @@ static int __cpuinit cpufreq_cpu_callback(struct notifier_block *nfb,
return NOTIFY_OK;
}
-static struct notifier_block __refdata cpufreq_cpu_notifier =
-{
+static struct notifier_block __refdata cpufreq_cpu_notifier = {
.notifier_call = cpufreq_cpu_callback,
};
diff --git a/drivers/cpufreq/cpufreq_ondemand.c b/drivers/cpufreq/cpufreq_ondemand.c
index e1314212d8d..7b5093664e4 100644
--- a/drivers/cpufreq/cpufreq_ondemand.c
+++ b/drivers/cpufreq/cpufreq_ondemand.c
@@ -459,6 +459,17 @@ static struct attribute_group dbs_attr_group_old = {
/************************** sysfs end ************************/
+static void dbs_freq_increase(struct cpufreq_policy *p, unsigned int freq)
+{
+ if (dbs_tuners_ins.powersave_bias)
+ freq = powersave_bias_target(p, freq, CPUFREQ_RELATION_H);
+ else if (p->cur == p->max)
+ return;
+
+ __cpufreq_driver_target(p, freq, dbs_tuners_ins.powersave_bias ?
+ CPUFREQ_RELATION_L : CPUFREQ_RELATION_H);
+}
+
static void dbs_check_cpu(struct cpu_dbs_info_s *this_dbs_info)
{
unsigned int max_load_freq;
@@ -551,19 +562,7 @@ static void dbs_check_cpu(struct cpu_dbs_info_s *this_dbs_info)
/* Check for frequency increase */
if (max_load_freq > dbs_tuners_ins.up_threshold * policy->cur) {
- /* if we are already at full speed then break out early */
- if (!dbs_tuners_ins.powersave_bias) {
- if (policy->cur == policy->max)
- return;
-
- __cpufreq_driver_target(policy, policy->max,
- CPUFREQ_RELATION_H);
- } else {
- int freq = powersave_bias_target(policy, policy->max,
- CPUFREQ_RELATION_H);
- __cpufreq_driver_target(policy, freq,
- CPUFREQ_RELATION_L);
- }
+ dbs_freq_increase(policy, policy->max);
return;
}
@@ -610,7 +609,9 @@ static void do_dbs_timer(struct work_struct *work)
/* We want all CPUs to do sampling nearly on same jiffy */
int delay = usecs_to_jiffies(dbs_tuners_ins.sampling_rate);
- delay -= jiffies % delay;
+ if (num_online_cpus() > 1)
+ delay -= jiffies % delay;
+
mutex_lock(&dbs_info->timer_mutex);
/* Common NORMAL_SAMPLE setup */
@@ -635,7 +636,9 @@ static inline void dbs_timer_init(struct cpu_dbs_info_s *dbs_info)
{
/* We want all CPUs to do sampling nearly on same jiffy */
int delay = usecs_to_jiffies(dbs_tuners_ins.sampling_rate);
- delay -= jiffies % delay;
+
+ if (num_online_cpus() > 1)
+ delay -= jiffies % delay;
dbs_info->sample_type = DBS_NORMAL_SAMPLE;
INIT_DELAYED_WORK_DEFERRABLE(&dbs_info->work, do_dbs_timer);
diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c
index 199488576a0..dbefe15bd58 100644
--- a/drivers/cpuidle/cpuidle.c
+++ b/drivers/cpuidle/cpuidle.c
@@ -95,7 +95,7 @@ static void cpuidle_idle_call(void)
/* give the governor an opportunity to reflect on the outcome */
if (cpuidle_curr_governor->reflect)
cpuidle_curr_governor->reflect(dev);
- trace_power_end(0);
+ trace_power_end(smp_processor_id());
}
/**
diff --git a/drivers/crypto/amcc/crypto4xx_reg_def.h b/drivers/crypto/amcc/crypto4xx_reg_def.h
index 7d4edb00261..5f5fbc0716f 100644
--- a/drivers/crypto/amcc/crypto4xx_reg_def.h
+++ b/drivers/crypto/amcc/crypto4xx_reg_def.h
@@ -113,7 +113,7 @@
#define CRYPTO4XX_PRNG_LFSR_H 0x00070034
/**
- * Initilize CRYPTO ENGINE registers, and memory bases.
+ * Initialize CRYPTO ENGINE registers, and memory bases.
*/
#define PPC4XX_PDR_POLL 0x3ff
#define PPC4XX_OUTPUT_THRESHOLD 2
diff --git a/drivers/crypto/geode-aes.c b/drivers/crypto/geode-aes.c
index 09389dd2f96..219d09cbb0d 100644
--- a/drivers/crypto/geode-aes.c
+++ b/drivers/crypto/geode-aes.c
@@ -573,7 +573,7 @@ geode_aes_probe(struct pci_dev *dev, const struct pci_device_id *id)
}
static struct pci_device_id geode_aes_tbl[] = {
- { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_LX_AES, PCI_ANY_ID, PCI_ANY_ID} ,
+ { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_LX_AES), } ,
{ 0, }
};
diff --git a/drivers/crypto/hifn_795x.c b/drivers/crypto/hifn_795x.c
index 16fce3aadf4..e449ac5627a 100644
--- a/drivers/crypto/hifn_795x.c
+++ b/drivers/crypto/hifn_795x.c
@@ -2018,7 +2018,6 @@ static void hifn_flush(struct hifn_device *dev)
{
unsigned long flags;
struct crypto_async_request *async_req;
- struct hifn_context *ctx;
struct ablkcipher_request *req;
struct hifn_dma *dma = (struct hifn_dma *)dev->desc_virt;
int i;
@@ -2035,7 +2034,6 @@ static void hifn_flush(struct hifn_device *dev)
spin_lock_irqsave(&dev->lock, flags);
while ((async_req = crypto_dequeue_request(&dev->queue))) {
- ctx = crypto_tfm_ctx(async_req->tfm);
req = container_of(async_req, struct ablkcipher_request, base);
spin_unlock_irqrestore(&dev->lock, flags);
@@ -2139,7 +2137,6 @@ static int hifn_setup_crypto_req(struct ablkcipher_request *req, u8 op,
static int hifn_process_queue(struct hifn_device *dev)
{
struct crypto_async_request *async_req, *backlog;
- struct hifn_context *ctx;
struct ablkcipher_request *req;
unsigned long flags;
int err = 0;
@@ -2156,7 +2153,6 @@ static int hifn_process_queue(struct hifn_device *dev)
if (backlog)
backlog->complete(backlog, -EINPROGRESS);
- ctx = crypto_tfm_ctx(async_req->tfm);
req = container_of(async_req, struct ablkcipher_request, base);
err = hifn_handle_req(req);
diff --git a/drivers/crypto/mv_cesa.c b/drivers/crypto/mv_cesa.c
index e095422b58d..7d279e578df 100644
--- a/drivers/crypto/mv_cesa.c
+++ b/drivers/crypto/mv_cesa.c
@@ -1055,20 +1055,20 @@ static int mv_probe(struct platform_device *pdev)
cp->queue_th = kthread_run(queue_manag, cp, "mv_crypto");
if (IS_ERR(cp->queue_th)) {
ret = PTR_ERR(cp->queue_th);
- goto err_thread;
+ goto err_unmap_sram;
}
ret = request_irq(irq, crypto_int, IRQF_DISABLED, dev_name(&pdev->dev),
cp);
if (ret)
- goto err_unmap_sram;
+ goto err_thread;
writel(SEC_INT_ACCEL0_DONE, cpg->reg + SEC_ACCEL_INT_MASK);
writel(SEC_CFG_STOP_DIG_ERR, cpg->reg + SEC_ACCEL_CFG);
ret = crypto_register_alg(&mv_aes_alg_ecb);
if (ret)
- goto err_reg;
+ goto err_irq;
ret = crypto_register_alg(&mv_aes_alg_cbc);
if (ret)
@@ -1091,9 +1091,9 @@ static int mv_probe(struct platform_device *pdev)
return 0;
err_unreg_ecb:
crypto_unregister_alg(&mv_aes_alg_ecb);
-err_thread:
+err_irq:
free_irq(irq, cp);
-err_reg:
+err_thread:
kthread_stop(cp->queue_th);
err_unmap_sram:
iounmap(cp->sram);
diff --git a/drivers/crypto/n2_core.c b/drivers/crypto/n2_core.c
index 23163fda503..26af2dd5d83 100644
--- a/drivers/crypto/n2_core.c
+++ b/drivers/crypto/n2_core.c
@@ -239,21 +239,57 @@ static inline bool n2_should_run_async(struct spu_queue *qp, int this_len)
}
#endif
-struct n2_base_ctx {
- struct list_head list;
+struct n2_ahash_alg {
+ struct list_head entry;
+ const char *hash_zero;
+ const u32 *hash_init;
+ u8 hw_op_hashsz;
+ u8 digest_size;
+ u8 auth_type;
+ u8 hmac_type;
+ struct ahash_alg alg;
};
-static void n2_base_ctx_init(struct n2_base_ctx *ctx)
+static inline struct n2_ahash_alg *n2_ahash_alg(struct crypto_tfm *tfm)
{
- INIT_LIST_HEAD(&ctx->list);
+ struct crypto_alg *alg = tfm->__crt_alg;
+ struct ahash_alg *ahash_alg;
+
+ ahash_alg = container_of(alg, struct ahash_alg, halg.base);
+
+ return container_of(ahash_alg, struct n2_ahash_alg, alg);
}
-struct n2_hash_ctx {
- struct n2_base_ctx base;
+struct n2_hmac_alg {
+ const char *child_alg;
+ struct n2_ahash_alg derived;
+};
+
+static inline struct n2_hmac_alg *n2_hmac_alg(struct crypto_tfm *tfm)
+{
+ struct crypto_alg *alg = tfm->__crt_alg;
+ struct ahash_alg *ahash_alg;
+
+ ahash_alg = container_of(alg, struct ahash_alg, halg.base);
+
+ return container_of(ahash_alg, struct n2_hmac_alg, derived.alg);
+}
+struct n2_hash_ctx {
struct crypto_ahash *fallback_tfm;
};
+#define N2_HASH_KEY_MAX 32 /* HW limit for all HMAC requests */
+
+struct n2_hmac_ctx {
+ struct n2_hash_ctx base;
+
+ struct crypto_shash *child_shash;
+
+ int hash_key_len;
+ unsigned char hash_key[N2_HASH_KEY_MAX];
+};
+
struct n2_hash_req_ctx {
union {
struct md5_state md5;
@@ -261,9 +297,6 @@ struct n2_hash_req_ctx {
struct sha256_state sha256;
} u;
- unsigned char hash_key[64];
- unsigned char keyed_zero_hash[32];
-
struct ahash_request fallback_req;
};
@@ -356,6 +389,94 @@ static void n2_hash_cra_exit(struct crypto_tfm *tfm)
crypto_free_ahash(ctx->fallback_tfm);
}
+static int n2_hmac_cra_init(struct crypto_tfm *tfm)
+{
+ const char *fallback_driver_name = tfm->__crt_alg->cra_name;
+ struct crypto_ahash *ahash = __crypto_ahash_cast(tfm);
+ struct n2_hmac_ctx *ctx = crypto_ahash_ctx(ahash);
+ struct n2_hmac_alg *n2alg = n2_hmac_alg(tfm);
+ struct crypto_ahash *fallback_tfm;
+ struct crypto_shash *child_shash;
+ int err;
+
+ fallback_tfm = crypto_alloc_ahash(fallback_driver_name, 0,
+ CRYPTO_ALG_NEED_FALLBACK);
+ if (IS_ERR(fallback_tfm)) {
+ pr_warning("Fallback driver '%s' could not be loaded!\n",
+ fallback_driver_name);
+ err = PTR_ERR(fallback_tfm);
+ goto out;
+ }
+
+ child_shash = crypto_alloc_shash(n2alg->child_alg, 0, 0);
+ if (IS_ERR(child_shash)) {
+ pr_warning("Child shash '%s' could not be loaded!\n",
+ n2alg->child_alg);
+ err = PTR_ERR(child_shash);
+ goto out_free_fallback;
+ }
+
+ crypto_ahash_set_reqsize(ahash, (sizeof(struct n2_hash_req_ctx) +
+ crypto_ahash_reqsize(fallback_tfm)));
+
+ ctx->child_shash = child_shash;
+ ctx->base.fallback_tfm = fallback_tfm;
+ return 0;
+
+out_free_fallback:
+ crypto_free_ahash(fallback_tfm);
+
+out:
+ return err;
+}
+
+static void n2_hmac_cra_exit(struct crypto_tfm *tfm)
+{
+ struct crypto_ahash *ahash = __crypto_ahash_cast(tfm);
+ struct n2_hmac_ctx *ctx = crypto_ahash_ctx(ahash);
+
+ crypto_free_ahash(ctx->base.fallback_tfm);
+ crypto_free_shash(ctx->child_shash);
+}
+
+static int n2_hmac_async_setkey(struct crypto_ahash *tfm, const u8 *key,
+ unsigned int keylen)
+{
+ struct n2_hmac_ctx *ctx = crypto_ahash_ctx(tfm);
+ struct crypto_shash *child_shash = ctx->child_shash;
+ struct crypto_ahash *fallback_tfm;
+ struct {
+ struct shash_desc shash;
+ char ctx[crypto_shash_descsize(child_shash)];
+ } desc;
+ int err, bs, ds;
+
+ fallback_tfm = ctx->base.fallback_tfm;
+ err = crypto_ahash_setkey(fallback_tfm, key, keylen);
+ if (err)
+ return err;
+
+ desc.shash.tfm = child_shash;
+ desc.shash.flags = crypto_ahash_get_flags(tfm) &
+ CRYPTO_TFM_REQ_MAY_SLEEP;
+
+ bs = crypto_shash_blocksize(child_shash);
+ ds = crypto_shash_digestsize(child_shash);
+ BUG_ON(ds > N2_HASH_KEY_MAX);
+ if (keylen > bs) {
+ err = crypto_shash_digest(&desc.shash, key, keylen,
+ ctx->hash_key);
+ if (err)
+ return err;
+ keylen = ds;
+ } else if (keylen <= N2_HASH_KEY_MAX)
+ memcpy(ctx->hash_key, key, keylen);
+
+ ctx->hash_key_len = keylen;
+
+ return err;
+}
+
static unsigned long wait_for_tail(struct spu_queue *qp)
{
unsigned long head, hv_ret;
@@ -385,12 +506,12 @@ static unsigned long submit_and_wait_for_tail(struct spu_queue *qp,
return hv_ret;
}
-static int n2_hash_async_digest(struct ahash_request *req,
- unsigned int auth_type, unsigned int digest_size,
- unsigned int result_size, void *hash_loc)
+static int n2_do_async_digest(struct ahash_request *req,
+ unsigned int auth_type, unsigned int digest_size,
+ unsigned int result_size, void *hash_loc,
+ unsigned long auth_key, unsigned int auth_key_len)
{
struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
- struct n2_hash_ctx *ctx = crypto_ahash_ctx(tfm);
struct cwq_initial_entry *ent;
struct crypto_hash_walk walk;
struct spu_queue *qp;
@@ -403,6 +524,7 @@ static int n2_hash_async_digest(struct ahash_request *req,
*/
if (unlikely(req->nbytes > (1 << 16))) {
struct n2_hash_req_ctx *rctx = ahash_request_ctx(req);
+ struct n2_hash_ctx *ctx = crypto_ahash_ctx(tfm);
ahash_request_set_tfm(&rctx->fallback_req, ctx->fallback_tfm);
rctx->fallback_req.base.flags =
@@ -414,8 +536,6 @@ static int n2_hash_async_digest(struct ahash_request *req,
return crypto_ahash_digest(&rctx->fallback_req);
}
- n2_base_ctx_init(&ctx->base);
-
nbytes = crypto_hash_walk_first(req, &walk);
cpu = get_cpu();
@@ -430,13 +550,13 @@ static int n2_hash_async_digest(struct ahash_request *req,
*/
ent = qp->q + qp->tail;
- ent->control = control_word_base(nbytes, 0, 0,
+ ent->control = control_word_base(nbytes, auth_key_len, 0,
auth_type, digest_size,
false, true, false, false,
OPCODE_INPLACE_BIT |
OPCODE_AUTH_MAC);
ent->src_addr = __pa(walk.data);
- ent->auth_key_addr = 0UL;
+ ent->auth_key_addr = auth_key;
ent->auth_iv_addr = __pa(hash_loc);
ent->final_auth_state_addr = 0UL;
ent->enc_key_addr = 0UL;
@@ -475,114 +595,55 @@ out:
return err;
}
-static int n2_md5_async_digest(struct ahash_request *req)
+static int n2_hash_async_digest(struct ahash_request *req)
{
+ struct n2_ahash_alg *n2alg = n2_ahash_alg(req->base.tfm);
struct n2_hash_req_ctx *rctx = ahash_request_ctx(req);
- struct md5_state *m = &rctx->u.md5;
+ int ds;
+ ds = n2alg->digest_size;
if (unlikely(req->nbytes == 0)) {
- static const char md5_zero[MD5_DIGEST_SIZE] = {
- 0xd4, 0x1d, 0x8c, 0xd9, 0x8f, 0x00, 0xb2, 0x04,
- 0xe9, 0x80, 0x09, 0x98, 0xec, 0xf8, 0x42, 0x7e,
- };
-
- memcpy(req->result, md5_zero, MD5_DIGEST_SIZE);
+ memcpy(req->result, n2alg->hash_zero, ds);
return 0;
}
- m->hash[0] = cpu_to_le32(0x67452301);
- m->hash[1] = cpu_to_le32(0xefcdab89);
- m->hash[2] = cpu_to_le32(0x98badcfe);
- m->hash[3] = cpu_to_le32(0x10325476);
+ memcpy(&rctx->u, n2alg->hash_init, n2alg->hw_op_hashsz);
- return n2_hash_async_digest(req, AUTH_TYPE_MD5,
- MD5_DIGEST_SIZE, MD5_DIGEST_SIZE,
- m->hash);
+ return n2_do_async_digest(req, n2alg->auth_type,
+ n2alg->hw_op_hashsz, ds,
+ &rctx->u, 0UL, 0);
}
-static int n2_sha1_async_digest(struct ahash_request *req)
+static int n2_hmac_async_digest(struct ahash_request *req)
{
+ struct n2_hmac_alg *n2alg = n2_hmac_alg(req->base.tfm);
struct n2_hash_req_ctx *rctx = ahash_request_ctx(req);
- struct sha1_state *s = &rctx->u.sha1;
-
- if (unlikely(req->nbytes == 0)) {
- static const char sha1_zero[SHA1_DIGEST_SIZE] = {
- 0xda, 0x39, 0xa3, 0xee, 0x5e, 0x6b, 0x4b, 0x0d, 0x32,
- 0x55, 0xbf, 0xef, 0x95, 0x60, 0x18, 0x90, 0xaf, 0xd8,
- 0x07, 0x09
- };
-
- memcpy(req->result, sha1_zero, SHA1_DIGEST_SIZE);
- return 0;
- }
- s->state[0] = SHA1_H0;
- s->state[1] = SHA1_H1;
- s->state[2] = SHA1_H2;
- s->state[3] = SHA1_H3;
- s->state[4] = SHA1_H4;
-
- return n2_hash_async_digest(req, AUTH_TYPE_SHA1,
- SHA1_DIGEST_SIZE, SHA1_DIGEST_SIZE,
- s->state);
-}
-
-static int n2_sha256_async_digest(struct ahash_request *req)
-{
- struct n2_hash_req_ctx *rctx = ahash_request_ctx(req);
- struct sha256_state *s = &rctx->u.sha256;
-
- if (req->nbytes == 0) {
- static const char sha256_zero[SHA256_DIGEST_SIZE] = {
- 0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, 0x9a,
- 0xfb, 0xf4, 0xc8, 0x99, 0x6f, 0xb9, 0x24, 0x27, 0xae,
- 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c, 0xa4, 0x95, 0x99,
- 0x1b, 0x78, 0x52, 0xb8, 0x55
- };
-
- memcpy(req->result, sha256_zero, SHA256_DIGEST_SIZE);
- return 0;
- }
- s->state[0] = SHA256_H0;
- s->state[1] = SHA256_H1;
- s->state[2] = SHA256_H2;
- s->state[3] = SHA256_H3;
- s->state[4] = SHA256_H4;
- s->state[5] = SHA256_H5;
- s->state[6] = SHA256_H6;
- s->state[7] = SHA256_H7;
-
- return n2_hash_async_digest(req, AUTH_TYPE_SHA256,
- SHA256_DIGEST_SIZE, SHA256_DIGEST_SIZE,
- s->state);
-}
+ struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
+ struct n2_hmac_ctx *ctx = crypto_ahash_ctx(tfm);
+ int ds;
-static int n2_sha224_async_digest(struct ahash_request *req)
-{
- struct n2_hash_req_ctx *rctx = ahash_request_ctx(req);
- struct sha256_state *s = &rctx->u.sha256;
+ ds = n2alg->derived.digest_size;
+ if (unlikely(req->nbytes == 0) ||
+ unlikely(ctx->hash_key_len > N2_HASH_KEY_MAX)) {
+ struct n2_hash_req_ctx *rctx = ahash_request_ctx(req);
+ struct n2_hash_ctx *ctx = crypto_ahash_ctx(tfm);
- if (req->nbytes == 0) {
- static const char sha224_zero[SHA224_DIGEST_SIZE] = {
- 0xd1, 0x4a, 0x02, 0x8c, 0x2a, 0x3a, 0x2b, 0xc9, 0x47,
- 0x61, 0x02, 0xbb, 0x28, 0x82, 0x34, 0xc4, 0x15, 0xa2,
- 0xb0, 0x1f, 0x82, 0x8e, 0xa6, 0x2a, 0xc5, 0xb3, 0xe4,
- 0x2f
- };
+ ahash_request_set_tfm(&rctx->fallback_req, ctx->fallback_tfm);
+ rctx->fallback_req.base.flags =
+ req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP;
+ rctx->fallback_req.nbytes = req->nbytes;
+ rctx->fallback_req.src = req->src;
+ rctx->fallback_req.result = req->result;
- memcpy(req->result, sha224_zero, SHA224_DIGEST_SIZE);
- return 0;
+ return crypto_ahash_digest(&rctx->fallback_req);
}
- s->state[0] = SHA224_H0;
- s->state[1] = SHA224_H1;
- s->state[2] = SHA224_H2;
- s->state[3] = SHA224_H3;
- s->state[4] = SHA224_H4;
- s->state[5] = SHA224_H5;
- s->state[6] = SHA224_H6;
- s->state[7] = SHA224_H7;
+ memcpy(&rctx->u, n2alg->derived.hash_init,
+ n2alg->derived.hw_op_hashsz);
- return n2_hash_async_digest(req, AUTH_TYPE_SHA256,
- SHA256_DIGEST_SIZE, SHA224_DIGEST_SIZE,
- s->state);
+ return n2_do_async_digest(req, n2alg->derived.hmac_type,
+ n2alg->derived.hw_op_hashsz, ds,
+ &rctx->u,
+ __pa(&ctx->hash_key),
+ ctx->hash_key_len);
}
struct n2_cipher_context {
@@ -1209,35 +1270,92 @@ static LIST_HEAD(cipher_algs);
struct n2_hash_tmpl {
const char *name;
- int (*digest)(struct ahash_request *req);
+ const char *hash_zero;
+ const u32 *hash_init;
+ u8 hw_op_hashsz;
u8 digest_size;
u8 block_size;
+ u8 auth_type;
+ u8 hmac_type;
+};
+
+static const char md5_zero[MD5_DIGEST_SIZE] = {
+ 0xd4, 0x1d, 0x8c, 0xd9, 0x8f, 0x00, 0xb2, 0x04,
+ 0xe9, 0x80, 0x09, 0x98, 0xec, 0xf8, 0x42, 0x7e,
+};
+static const u32 md5_init[MD5_HASH_WORDS] = {
+ cpu_to_le32(0x67452301),
+ cpu_to_le32(0xefcdab89),
+ cpu_to_le32(0x98badcfe),
+ cpu_to_le32(0x10325476),
+};
+static const char sha1_zero[SHA1_DIGEST_SIZE] = {
+ 0xda, 0x39, 0xa3, 0xee, 0x5e, 0x6b, 0x4b, 0x0d, 0x32,
+ 0x55, 0xbf, 0xef, 0x95, 0x60, 0x18, 0x90, 0xaf, 0xd8,
+ 0x07, 0x09
};
+static const u32 sha1_init[SHA1_DIGEST_SIZE / 4] = {
+ SHA1_H0, SHA1_H1, SHA1_H2, SHA1_H3, SHA1_H4,
+};
+static const char sha256_zero[SHA256_DIGEST_SIZE] = {
+ 0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, 0x9a,
+ 0xfb, 0xf4, 0xc8, 0x99, 0x6f, 0xb9, 0x24, 0x27, 0xae,
+ 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c, 0xa4, 0x95, 0x99,
+ 0x1b, 0x78, 0x52, 0xb8, 0x55
+};
+static const u32 sha256_init[SHA256_DIGEST_SIZE / 4] = {
+ SHA256_H0, SHA256_H1, SHA256_H2, SHA256_H3,
+ SHA256_H4, SHA256_H5, SHA256_H6, SHA256_H7,
+};
+static const char sha224_zero[SHA224_DIGEST_SIZE] = {
+ 0xd1, 0x4a, 0x02, 0x8c, 0x2a, 0x3a, 0x2b, 0xc9, 0x47,
+ 0x61, 0x02, 0xbb, 0x28, 0x82, 0x34, 0xc4, 0x15, 0xa2,
+ 0xb0, 0x1f, 0x82, 0x8e, 0xa6, 0x2a, 0xc5, 0xb3, 0xe4,
+ 0x2f
+};
+static const u32 sha224_init[SHA256_DIGEST_SIZE / 4] = {
+ SHA224_H0, SHA224_H1, SHA224_H2, SHA224_H3,
+ SHA224_H4, SHA224_H5, SHA224_H6, SHA224_H7,
+};
+
static const struct n2_hash_tmpl hash_tmpls[] = {
{ .name = "md5",
- .digest = n2_md5_async_digest,
+ .hash_zero = md5_zero,
+ .hash_init = md5_init,
+ .auth_type = AUTH_TYPE_MD5,
+ .hmac_type = AUTH_TYPE_HMAC_MD5,
+ .hw_op_hashsz = MD5_DIGEST_SIZE,
.digest_size = MD5_DIGEST_SIZE,
.block_size = MD5_HMAC_BLOCK_SIZE },
{ .name = "sha1",
- .digest = n2_sha1_async_digest,
+ .hash_zero = sha1_zero,
+ .hash_init = sha1_init,
+ .auth_type = AUTH_TYPE_SHA1,
+ .hmac_type = AUTH_TYPE_HMAC_SHA1,
+ .hw_op_hashsz = SHA1_DIGEST_SIZE,
.digest_size = SHA1_DIGEST_SIZE,
.block_size = SHA1_BLOCK_SIZE },
{ .name = "sha256",
- .digest = n2_sha256_async_digest,
+ .hash_zero = sha256_zero,
+ .hash_init = sha256_init,
+ .auth_type = AUTH_TYPE_SHA256,
+ .hmac_type = AUTH_TYPE_HMAC_SHA256,
+ .hw_op_hashsz = SHA256_DIGEST_SIZE,
.digest_size = SHA256_DIGEST_SIZE,
.block_size = SHA256_BLOCK_SIZE },
{ .name = "sha224",
- .digest = n2_sha224_async_digest,
+ .hash_zero = sha224_zero,
+ .hash_init = sha224_init,
+ .auth_type = AUTH_TYPE_SHA256,
+ .hmac_type = AUTH_TYPE_RESERVED,
+ .hw_op_hashsz = SHA256_DIGEST_SIZE,
.digest_size = SHA224_DIGEST_SIZE,
.block_size = SHA224_BLOCK_SIZE },
};
#define NUM_HASH_TMPLS ARRAY_SIZE(hash_tmpls)
-struct n2_ahash_alg {
- struct list_head entry;
- struct ahash_alg alg;
-};
static LIST_HEAD(ahash_algs);
+static LIST_HEAD(hmac_algs);
static int algs_registered;
@@ -1245,12 +1363,18 @@ static void __n2_unregister_algs(void)
{
struct n2_cipher_alg *cipher, *cipher_tmp;
struct n2_ahash_alg *alg, *alg_tmp;
+ struct n2_hmac_alg *hmac, *hmac_tmp;
list_for_each_entry_safe(cipher, cipher_tmp, &cipher_algs, entry) {
crypto_unregister_alg(&cipher->alg);
list_del(&cipher->entry);
kfree(cipher);
}
+ list_for_each_entry_safe(hmac, hmac_tmp, &hmac_algs, derived.entry) {
+ crypto_unregister_ahash(&hmac->derived.alg);
+ list_del(&hmac->derived.entry);
+ kfree(hmac);
+ }
list_for_each_entry_safe(alg, alg_tmp, &ahash_algs, entry) {
crypto_unregister_ahash(&alg->alg);
list_del(&alg->entry);
@@ -1290,8 +1414,49 @@ static int __devinit __n2_register_one_cipher(const struct n2_cipher_tmpl *tmpl)
list_add(&p->entry, &cipher_algs);
err = crypto_register_alg(alg);
if (err) {
+ pr_err("%s alg registration failed\n", alg->cra_name);
list_del(&p->entry);
kfree(p);
+ } else {
+ pr_info("%s alg registered\n", alg->cra_name);
+ }
+ return err;
+}
+
+static int __devinit __n2_register_one_hmac(struct n2_ahash_alg *n2ahash)
+{
+ struct n2_hmac_alg *p = kzalloc(sizeof(*p), GFP_KERNEL);
+ struct ahash_alg *ahash;
+ struct crypto_alg *base;
+ int err;
+
+ if (!p)
+ return -ENOMEM;
+
+ p->child_alg = n2ahash->alg.halg.base.cra_name;
+ memcpy(&p->derived, n2ahash, sizeof(struct n2_ahash_alg));
+ INIT_LIST_HEAD(&p->derived.entry);
+
+ ahash = &p->derived.alg;
+ ahash->digest = n2_hmac_async_digest;
+ ahash->setkey = n2_hmac_async_setkey;
+
+ base = &ahash->halg.base;
+ snprintf(base->cra_name, CRYPTO_MAX_ALG_NAME, "hmac(%s)", p->child_alg);
+ snprintf(base->cra_driver_name, CRYPTO_MAX_ALG_NAME, "hmac-%s-n2", p->child_alg);
+
+ base->cra_ctxsize = sizeof(struct n2_hmac_ctx);
+ base->cra_init = n2_hmac_cra_init;
+ base->cra_exit = n2_hmac_cra_exit;
+
+ list_add(&p->derived.entry, &hmac_algs);
+ err = crypto_register_ahash(ahash);
+ if (err) {
+ pr_err("%s alg registration failed\n", base->cra_name);
+ list_del(&p->derived.entry);
+ kfree(p);
+ } else {
+ pr_info("%s alg registered\n", base->cra_name);
}
return err;
}
@@ -1307,12 +1472,19 @@ static int __devinit __n2_register_one_ahash(const struct n2_hash_tmpl *tmpl)
if (!p)
return -ENOMEM;
+ p->hash_zero = tmpl->hash_zero;
+ p->hash_init = tmpl->hash_init;
+ p->auth_type = tmpl->auth_type;
+ p->hmac_type = tmpl->hmac_type;
+ p->hw_op_hashsz = tmpl->hw_op_hashsz;
+ p->digest_size = tmpl->digest_size;
+
ahash = &p->alg;
ahash->init = n2_hash_async_init;
ahash->update = n2_hash_async_update;
ahash->final = n2_hash_async_final;
ahash->finup = n2_hash_async_finup;
- ahash->digest = tmpl->digest;
+ ahash->digest = n2_hash_async_digest;
halg = &ahash->halg;
halg->digestsize = tmpl->digest_size;
@@ -1331,9 +1503,14 @@ static int __devinit __n2_register_one_ahash(const struct n2_hash_tmpl *tmpl)
list_add(&p->entry, &ahash_algs);
err = crypto_register_ahash(ahash);
if (err) {
+ pr_err("%s alg registration failed\n", base->cra_name);
list_del(&p->entry);
kfree(p);
+ } else {
+ pr_info("%s alg registered\n", base->cra_name);
}
+ if (!err && p->hmac_type != AUTH_TYPE_RESERVED)
+ err = __n2_register_one_hmac(p);
return err;
}
@@ -2070,20 +2247,20 @@ static struct of_platform_driver n2_mau_driver = {
static int __init n2_init(void)
{
- int err = of_register_driver(&n2_crypto_driver, &of_bus_type);
+ int err = of_register_platform_driver(&n2_crypto_driver);
if (!err) {
- err = of_register_driver(&n2_mau_driver, &of_bus_type);
+ err = of_register_platform_driver(&n2_mau_driver);
if (err)
- of_unregister_driver(&n2_crypto_driver);
+ of_unregister_platform_driver(&n2_crypto_driver);
}
return err;
}
static void __exit n2_exit(void)
{
- of_unregister_driver(&n2_mau_driver);
- of_unregister_driver(&n2_crypto_driver);
+ of_unregister_platform_driver(&n2_mau_driver);
+ of_unregister_platform_driver(&n2_crypto_driver);
}
module_init(n2_init);
diff --git a/drivers/crypto/omap-sham.c b/drivers/crypto/omap-sham.c
index 8b034337793..7d148567688 100644
--- a/drivers/crypto/omap-sham.c
+++ b/drivers/crypto/omap-sham.c
@@ -15,7 +15,6 @@
#define pr_fmt(fmt) "%s: " fmt, __func__
-#include <linux/version.h>
#include <linux/err.h>
#include <linux/device.h>
#include <linux/module.h>
diff --git a/drivers/crypto/talitos.c b/drivers/crypto/talitos.c
index bd78acf3c36..97f4af1d8a6 100644
--- a/drivers/crypto/talitos.c
+++ b/drivers/crypto/talitos.c
@@ -720,7 +720,6 @@ struct talitos_ctx {
#define TALITOS_MDEU_MAX_CONTEXT_SIZE TALITOS_MDEU_CONTEXT_SIZE_SHA384_SHA512
struct talitos_ahash_req_ctx {
- u64 count;
u32 hw_context[TALITOS_MDEU_MAX_CONTEXT_SIZE / sizeof(u32)];
unsigned int hw_context_size;
u8 buf[HASH_MAX_BLOCK_SIZE];
@@ -729,6 +728,7 @@ struct talitos_ahash_req_ctx {
unsigned int first;
unsigned int last;
unsigned int to_hash_later;
+ u64 nbuf;
struct scatterlist bufsl[2];
struct scatterlist *psrc;
};
@@ -1613,6 +1613,7 @@ static void ahash_done(struct device *dev,
if (!req_ctx->last && req_ctx->to_hash_later) {
/* Position any partial block for next update/final/finup */
memcpy(req_ctx->buf, req_ctx->bufnext, req_ctx->to_hash_later);
+ req_ctx->nbuf = req_ctx->to_hash_later;
}
common_nonsnoop_hash_unmap(dev, edesc, areq);
@@ -1728,7 +1729,7 @@ static int ahash_init(struct ahash_request *areq)
struct talitos_ahash_req_ctx *req_ctx = ahash_request_ctx(areq);
/* Initialize the context */
- req_ctx->count = 0;
+ req_ctx->nbuf = 0;
req_ctx->first = 1; /* first indicates h/w must init its context */
req_ctx->swinit = 0; /* assume h/w init of context */
req_ctx->hw_context_size =
@@ -1776,52 +1777,54 @@ static int ahash_process_req(struct ahash_request *areq, unsigned int nbytes)
crypto_tfm_alg_blocksize(crypto_ahash_tfm(tfm));
unsigned int nbytes_to_hash;
unsigned int to_hash_later;
- unsigned int index;
+ unsigned int nsg;
int chained;
- index = req_ctx->count & (blocksize - 1);
- req_ctx->count += nbytes;
-
- if (!req_ctx->last && (index + nbytes) < blocksize) {
- /* Buffer the partial block */
+ if (!req_ctx->last && (nbytes + req_ctx->nbuf <= blocksize)) {
+ /* Buffer up to one whole block */
sg_copy_to_buffer(areq->src,
sg_count(areq->src, nbytes, &chained),
- req_ctx->buf + index, nbytes);
+ req_ctx->buf + req_ctx->nbuf, nbytes);
+ req_ctx->nbuf += nbytes;
return 0;
}
- if (index) {
- /* partial block from previous update; chain it in. */
- sg_init_table(req_ctx->bufsl, (nbytes) ? 2 : 1);
- sg_set_buf(req_ctx->bufsl, req_ctx->buf, index);
- if (nbytes)
- scatterwalk_sg_chain(req_ctx->bufsl, 2,
- areq->src);
+ /* At least (blocksize + 1) bytes are available to hash */
+ nbytes_to_hash = nbytes + req_ctx->nbuf;
+ to_hash_later = nbytes_to_hash & (blocksize - 1);
+
+ if (req_ctx->last)
+ to_hash_later = 0;
+ else if (to_hash_later)
+ /* There is a partial block. Hash the full block(s) now */
+ nbytes_to_hash -= to_hash_later;
+ else {
+ /* Keep one block buffered */
+ nbytes_to_hash -= blocksize;
+ to_hash_later = blocksize;
+ }
+
+ /* Chain in any previously buffered data */
+ if (req_ctx->nbuf) {
+ nsg = (req_ctx->nbuf < nbytes_to_hash) ? 2 : 1;
+ sg_init_table(req_ctx->bufsl, nsg);
+ sg_set_buf(req_ctx->bufsl, req_ctx->buf, req_ctx->nbuf);
+ if (nsg > 1)
+ scatterwalk_sg_chain(req_ctx->bufsl, 2, areq->src);
req_ctx->psrc = req_ctx->bufsl;
- } else {
+ } else
req_ctx->psrc = areq->src;
+
+ if (to_hash_later) {
+ int nents = sg_count(areq->src, nbytes, &chained);
+ sg_copy_end_to_buffer(areq->src, nents,
+ req_ctx->bufnext,
+ to_hash_later,
+ nbytes - to_hash_later);
}
- nbytes_to_hash = index + nbytes;
- if (!req_ctx->last) {
- to_hash_later = (nbytes_to_hash & (blocksize - 1));
- if (to_hash_later) {
- int nents;
- /* Must copy to_hash_later bytes from the end
- * to bufnext (a partial block) for later.
- */
- nents = sg_count(areq->src, nbytes, &chained);
- sg_copy_end_to_buffer(areq->src, nents,
- req_ctx->bufnext,
- to_hash_later,
- nbytes - to_hash_later);
-
- /* Adjust count for what will be hashed now */
- nbytes_to_hash -= to_hash_later;
- }
- req_ctx->to_hash_later = to_hash_later;
- }
+ req_ctx->to_hash_later = to_hash_later;
- /* allocate extended descriptor */
+ /* Allocate extended descriptor */
edesc = ahash_edesc_alloc(areq, nbytes_to_hash);
if (IS_ERR(edesc))
return PTR_ERR(edesc);
diff --git a/drivers/dma/at_hdmac.c b/drivers/dma/at_hdmac.c
index bd5250e8c00..e88076022a7 100644
--- a/drivers/dma/at_hdmac.c
+++ b/drivers/dma/at_hdmac.c
@@ -69,7 +69,7 @@ static struct at_desc *atc_first_queued(struct at_dma_chan *atchan)
}
/**
- * atc_alloc_descriptor - allocate and return an initilized descriptor
+ * atc_alloc_descriptor - allocate and return an initialized descriptor
* @chan: the channel to allocate descriptors for
* @gfp_flags: GFP allocation flags
*
diff --git a/drivers/dma/fsldma.c b/drivers/dma/fsldma.c
index 8088b14ba5f..f0fd6db6063 100644
--- a/drivers/dma/fsldma.c
+++ b/drivers/dma/fsldma.c
@@ -10,7 +10,7 @@
* Description:
* DMA engine driver for Freescale MPC8540 DMA controller, which is
* also fit for MPC8560, MPC8555, MPC8548, MPC8641, and etc.
- * The support for MPC8349 DMA contorller is also added.
+ * The support for MPC8349 DMA controller is also added.
*
* This driver instructs the DMA controller to issue the PCI Read Multiple
* command for PCI read operations, instead of using the default PCI Read Line
diff --git a/drivers/edac/Kconfig b/drivers/edac/Kconfig
index 0d2f9dbb47e..70bb350de99 100644
--- a/drivers/edac/Kconfig
+++ b/drivers/edac/Kconfig
@@ -39,14 +39,6 @@ config EDAC_DEBUG
there're four debug levels (x=0,1,2,3 from low to high).
Usually you should select 'N'.
-config EDAC_DEBUG_VERBOSE
- bool "More verbose debugging"
- depends on EDAC_DEBUG
- help
- This option makes debugging information more verbose.
- Source file name and line number where debugging message
- printed will be added to debugging message.
-
config EDAC_DECODE_MCE
tristate "Decode MCEs in human-readable form (only on AMD for now)"
depends on CPU_SUP_AMD && X86_MCE
diff --git a/drivers/edac/amd64_edac.c b/drivers/edac/amd64_edac.c
index ac9f7985096..670239ab751 100644
--- a/drivers/edac/amd64_edac.c
+++ b/drivers/edac/amd64_edac.c
@@ -160,7 +160,7 @@ static int amd64_search_set_scrub_rate(struct pci_dev *ctl, u32 new_bw,
return 0;
}
-static int amd64_set_scrub_rate(struct mem_ctl_info *mci, u32 *bandwidth)
+static int amd64_set_scrub_rate(struct mem_ctl_info *mci, u32 bandwidth)
{
struct amd64_pvt *pvt = mci->pvt_info;
u32 min_scrubrate = 0x0;
@@ -178,10 +178,10 @@ static int amd64_set_scrub_rate(struct mem_ctl_info *mci, u32 *bandwidth)
default:
amd64_printk(KERN_ERR, "Unsupported family!\n");
- break;
+ return -EINVAL;
}
- return amd64_search_set_scrub_rate(pvt->misc_f3_ctl, *bandwidth,
- min_scrubrate);
+ return amd64_search_set_scrub_rate(pvt->misc_f3_ctl, bandwidth,
+ min_scrubrate);
}
static int amd64_get_scrub_rate(struct mem_ctl_info *mci, u32 *bw)
@@ -796,6 +796,11 @@ static int sys_addr_to_csrow(struct mem_ctl_info *mci, u64 sys_addr)
static int get_channel_from_ecc_syndrome(struct mem_ctl_info *, u16);
+static u16 extract_syndrome(struct err_regs *err)
+{
+ return ((err->nbsh >> 15) & 0xff) | ((err->nbsl >> 16) & 0xff00);
+}
+
static void amd64_cpu_display_info(struct amd64_pvt *pvt)
{
if (boot_cpu_data.x86 == 0x11)
@@ -888,6 +893,9 @@ static void amd64_dump_misc_regs(struct amd64_pvt *pvt)
return;
}
+ amd64_printk(KERN_INFO, "using %s syndromes.\n",
+ ((pvt->syn_type == 8) ? "x8" : "x4"));
+
/* Only if NOT ganged does dclr1 have valid info */
if (!dct_ganging_enabled(pvt))
amd64_dump_dramcfg_low(pvt->dclr1, 1);
@@ -1101,20 +1109,17 @@ static void k8_read_dram_base_limit(struct amd64_pvt *pvt, int dram)
}
static void k8_map_sysaddr_to_csrow(struct mem_ctl_info *mci,
- struct err_regs *info,
- u64 sys_addr)
+ struct err_regs *err_info, u64 sys_addr)
{
struct mem_ctl_info *src_mci;
- unsigned short syndrome;
int channel, csrow;
u32 page, offset;
+ u16 syndrome;
- /* Extract the syndrome parts and form a 16-bit syndrome */
- syndrome = HIGH_SYNDROME(info->nbsl) << 8;
- syndrome |= LOW_SYNDROME(info->nbsh);
+ syndrome = extract_syndrome(err_info);
/* CHIPKILL enabled */
- if (info->nbcfg & K8_NBCFG_CHIPKILL) {
+ if (err_info->nbcfg & K8_NBCFG_CHIPKILL) {
channel = get_channel_from_ecc_syndrome(mci, syndrome);
if (channel < 0) {
/*
@@ -1123,8 +1128,8 @@ static void k8_map_sysaddr_to_csrow(struct mem_ctl_info *mci,
* as suspect.
*/
amd64_mc_printk(mci, KERN_WARNING,
- "unknown syndrome 0x%x - possible error "
- "reporting race\n", syndrome);
+ "unknown syndrome 0x%04x - possible "
+ "error reporting race\n", syndrome);
edac_mc_handle_ce_no_info(mci, EDAC_MOD_STR);
return;
}
@@ -1430,7 +1435,7 @@ static inline u64 f10_get_base_addr_offset(u64 sys_addr, int hi_range_sel,
u64 chan_off;
if (hi_range_sel) {
- if (!(dct_sel_base_addr & 0xFFFFF800) &&
+ if (!(dct_sel_base_addr & 0xFFFF0000) &&
hole_valid && (sys_addr >= 0x100000000ULL))
chan_off = hole_off << 16;
else
@@ -1654,13 +1659,13 @@ static int f10_translate_sysaddr_to_cs(struct amd64_pvt *pvt, u64 sys_addr,
* (MCX_ADDR).
*/
static void f10_map_sysaddr_to_csrow(struct mem_ctl_info *mci,
- struct err_regs *info,
+ struct err_regs *err_info,
u64 sys_addr)
{
struct amd64_pvt *pvt = mci->pvt_info;
u32 page, offset;
- unsigned short syndrome;
int nid, csrow, chan = 0;
+ u16 syndrome;
csrow = f10_translate_sysaddr_to_cs(pvt, sys_addr, &nid, &chan);
@@ -1671,15 +1676,14 @@ static void f10_map_sysaddr_to_csrow(struct mem_ctl_info *mci,
error_address_to_page_and_offset(sys_addr, &page, &offset);
- syndrome = HIGH_SYNDROME(info->nbsl) << 8;
- syndrome |= LOW_SYNDROME(info->nbsh);
+ syndrome = extract_syndrome(err_info);
/*
* We need the syndromes for channel detection only when we're
* ganged. Otherwise @chan should already contain the channel at
* this point.
*/
- if (dct_ganging_enabled(pvt) && pvt->nbcfg & K8_NBCFG_CHIPKILL)
+ if (dct_ganging_enabled(pvt) && (pvt->nbcfg & K8_NBCFG_CHIPKILL))
chan = get_channel_from_ecc_syndrome(mci, syndrome);
if (chan >= 0)
@@ -1878,7 +1882,7 @@ static u16 x8_vectors[] = {
};
static int decode_syndrome(u16 syndrome, u16 *vectors, int num_vecs,
- int v_dim)
+ int v_dim)
{
unsigned int i, err_sym;
@@ -1955,124 +1959,23 @@ static int map_err_sym_to_channel(int err_sym, int sym_size)
static int get_channel_from_ecc_syndrome(struct mem_ctl_info *mci, u16 syndrome)
{
struct amd64_pvt *pvt = mci->pvt_info;
- u32 value = 0;
- int err_sym = 0;
-
- if (boot_cpu_data.x86 == 0x10) {
-
- amd64_read_pci_cfg(pvt->misc_f3_ctl, 0x180, &value);
-
- /* F3x180[EccSymbolSize]=1 => x8 symbols */
- if (boot_cpu_data.x86_model > 7 &&
- value & BIT(25)) {
- err_sym = decode_syndrome(syndrome, x8_vectors,
- ARRAY_SIZE(x8_vectors), 8);
- return map_err_sym_to_channel(err_sym, 8);
- }
+ int err_sym = -1;
+
+ if (pvt->syn_type == 8)
+ err_sym = decode_syndrome(syndrome, x8_vectors,
+ ARRAY_SIZE(x8_vectors),
+ pvt->syn_type);
+ else if (pvt->syn_type == 4)
+ err_sym = decode_syndrome(syndrome, x4_vectors,
+ ARRAY_SIZE(x4_vectors),
+ pvt->syn_type);
+ else {
+ amd64_printk(KERN_WARNING, "%s: Illegal syndrome type: %u\n",
+ __func__, pvt->syn_type);
+ return err_sym;
}
- err_sym = decode_syndrome(syndrome, x4_vectors, ARRAY_SIZE(x4_vectors), 4);
- return map_err_sym_to_channel(err_sym, 4);
-}
-
-/*
- * Check for valid error in the NB Status High register. If so, proceed to read
- * NB Status Low, NB Address Low and NB Address High registers and store data
- * into error structure.
- *
- * Returns:
- * - 1: if hardware regs contains valid error info
- * - 0: if no valid error is indicated
- */
-static int amd64_get_error_info_regs(struct mem_ctl_info *mci,
- struct err_regs *regs)
-{
- struct amd64_pvt *pvt;
- struct pci_dev *misc_f3_ctl;
-
- pvt = mci->pvt_info;
- misc_f3_ctl = pvt->misc_f3_ctl;
-
- if (amd64_read_pci_cfg(misc_f3_ctl, K8_NBSH, &regs->nbsh))
- return 0;
-
- if (!(regs->nbsh & K8_NBSH_VALID_BIT))
- return 0;
-
- /* valid error, read remaining error information registers */
- if (amd64_read_pci_cfg(misc_f3_ctl, K8_NBSL, &regs->nbsl) ||
- amd64_read_pci_cfg(misc_f3_ctl, K8_NBEAL, &regs->nbeal) ||
- amd64_read_pci_cfg(misc_f3_ctl, K8_NBEAH, &regs->nbeah) ||
- amd64_read_pci_cfg(misc_f3_ctl, K8_NBCFG, &regs->nbcfg))
- return 0;
-
- return 1;
-}
-
-/*
- * This function is called to retrieve the error data from hardware and store it
- * in the info structure.
- *
- * Returns:
- * - 1: if a valid error is found
- * - 0: if no error is found
- */
-static int amd64_get_error_info(struct mem_ctl_info *mci,
- struct err_regs *info)
-{
- struct amd64_pvt *pvt;
- struct err_regs regs;
-
- pvt = mci->pvt_info;
-
- if (!amd64_get_error_info_regs(mci, info))
- return 0;
-
- /*
- * Here's the problem with the K8's EDAC reporting: There are four
- * registers which report pieces of error information. They are shared
- * between CEs and UEs. Furthermore, contrary to what is stated in the
- * BKDG, the overflow bit is never used! Every error always updates the
- * reporting registers.
- *
- * Can you see the race condition? All four error reporting registers
- * must be read before a new error updates them! There is no way to read
- * all four registers atomically. The best than can be done is to detect
- * that a race has occured and then report the error without any kind of
- * precision.
- *
- * What is still positive is that errors are still reported and thus
- * problems can still be detected - just not localized because the
- * syndrome and address are spread out across registers.
- *
- * Grrrrr!!!!! Here's hoping that AMD fixes this in some future K8 rev.
- * UEs and CEs should have separate register sets with proper overflow
- * bits that are used! At very least the problem can be fixed by
- * honoring the ErrValid bit in 'nbsh' and not updating registers - just
- * set the overflow bit - unless the current error is CE and the new
- * error is UE which would be the only situation for overwriting the
- * current values.
- */
-
- regs = *info;
-
- /* Use info from the second read - most current */
- if (unlikely(!amd64_get_error_info_regs(mci, info)))
- return 0;
- /* clear the error bits in hardware */
- pci_write_bits32(pvt->misc_f3_ctl, K8_NBSH, 0, K8_NBSH_VALID_BIT);
-
- /* Check for the possible race condition */
- if ((regs.nbsh != info->nbsh) ||
- (regs.nbsl != info->nbsl) ||
- (regs.nbeah != info->nbeah) ||
- (regs.nbeal != info->nbeal)) {
- amd64_mc_printk(mci, KERN_WARNING,
- "hardware STATUS read access race condition "
- "detected!\n");
- return 0;
- }
- return 1;
+ return map_err_sym_to_channel(err_sym, pvt->syn_type);
}
/*
@@ -2177,7 +2080,7 @@ static inline void __amd64_decode_bus_error(struct mem_ctl_info *mci,
* catastrophic.
*/
if (info->nbsh & K8_NBSH_OVERFLOW)
- edac_mc_handle_ce_no_info(mci, EDAC_MOD_STR "Error Overflow");
+ edac_mc_handle_ce_no_info(mci, EDAC_MOD_STR " Error Overflow");
}
void amd64_decode_bus_error(int node_id, struct err_regs *regs)
@@ -2199,20 +2102,6 @@ void amd64_decode_bus_error(int node_id, struct err_regs *regs)
}
/*
- * The main polling 'check' function, called FROM the edac core to perform the
- * error checking and if an error is encountered, error processing.
- */
-static void amd64_check(struct mem_ctl_info *mci)
-{
- struct err_regs regs;
-
- if (amd64_get_error_info(mci, &regs)) {
- struct amd64_pvt *pvt = mci->pvt_info;
- amd_decode_nb_mce(pvt->mc_node_id, &regs, 1);
- }
-}
-
-/*
* Input:
* 1) struct amd64_pvt which contains pvt->dram_f2_ctl pointer
* 2) AMD Family index value
@@ -2284,6 +2173,7 @@ static void amd64_free_mc_sibling_devices(struct amd64_pvt *pvt)
static void amd64_read_mc_registers(struct amd64_pvt *pvt)
{
u64 msr_val;
+ u32 tmp;
int dram;
/*
@@ -2349,10 +2239,22 @@ static void amd64_read_mc_registers(struct amd64_pvt *pvt)
amd64_read_pci_cfg(pvt->dram_f2_ctl, F10_DCLR_0, &pvt->dclr0);
amd64_read_pci_cfg(pvt->dram_f2_ctl, F10_DCHR_0, &pvt->dchr0);
- if (!dct_ganging_enabled(pvt) && boot_cpu_data.x86 >= 0x10) {
- amd64_read_pci_cfg(pvt->dram_f2_ctl, F10_DCLR_1, &pvt->dclr1);
- amd64_read_pci_cfg(pvt->dram_f2_ctl, F10_DCHR_1, &pvt->dchr1);
+ if (boot_cpu_data.x86 >= 0x10) {
+ if (!dct_ganging_enabled(pvt)) {
+ amd64_read_pci_cfg(pvt->dram_f2_ctl, F10_DCLR_1, &pvt->dclr1);
+ amd64_read_pci_cfg(pvt->dram_f2_ctl, F10_DCHR_1, &pvt->dchr1);
+ }
+ amd64_read_pci_cfg(pvt->misc_f3_ctl, EXT_NB_MCA_CFG, &tmp);
}
+
+ if (boot_cpu_data.x86 == 0x10 &&
+ boot_cpu_data.x86_model > 7 &&
+ /* F3x180[EccSymbolSize]=1 => x8 symbols */
+ tmp & BIT(25))
+ pvt->syn_type = 8;
+ else
+ pvt->syn_type = 4;
+
amd64_dump_misc_regs(pvt);
}
@@ -2739,9 +2641,6 @@ static void amd64_setup_mci_misc_attributes(struct mem_ctl_info *mci)
mci->dev_name = pci_name(pvt->dram_f2_ctl);
mci->ctl_page_to_phys = NULL;
- /* IMPORTANT: Set the polling 'check' function in this module */
- mci->edac_check = amd64_check;
-
/* memory scrubber interface */
mci->set_sdram_scrub_rate = amd64_set_scrub_rate;
mci->get_sdram_scrub_rate = amd64_get_scrub_rate;
diff --git a/drivers/edac/amd64_edac.h b/drivers/edac/amd64_edac.h
index 0d4bf563824..613b9381e71 100644
--- a/drivers/edac/amd64_edac.h
+++ b/drivers/edac/amd64_edac.h
@@ -244,44 +244,17 @@
#define F10_DCTL_SEL_LOW 0x110
-
-#define dct_sel_baseaddr(pvt) \
- ((pvt->dram_ctl_select_low) & 0xFFFFF800)
-
-#define dct_sel_interleave_addr(pvt) \
- (((pvt->dram_ctl_select_low) >> 6) & 0x3)
-
-enum {
- F10_DCTL_SEL_LOW_DctSelHiRngEn = BIT(0),
- F10_DCTL_SEL_LOW_DctSelIntLvEn = BIT(2),
- F10_DCTL_SEL_LOW_DctGangEn = BIT(4),
- F10_DCTL_SEL_LOW_DctDatIntLv = BIT(5),
- F10_DCTL_SEL_LOW_DramEnable = BIT(8),
- F10_DCTL_SEL_LOW_MemCleared = BIT(10),
-};
-
-#define dct_high_range_enabled(pvt) \
- (pvt->dram_ctl_select_low & F10_DCTL_SEL_LOW_DctSelHiRngEn)
-
-#define dct_interleave_enabled(pvt) \
- (pvt->dram_ctl_select_low & F10_DCTL_SEL_LOW_DctSelIntLvEn)
-
-#define dct_ganging_enabled(pvt) \
- (pvt->dram_ctl_select_low & F10_DCTL_SEL_LOW_DctGangEn)
-
-#define dct_data_intlv_enabled(pvt) \
- (pvt->dram_ctl_select_low & F10_DCTL_SEL_LOW_DctDatIntLv)
-
-#define dct_dram_enabled(pvt) \
- (pvt->dram_ctl_select_low & F10_DCTL_SEL_LOW_DramEnable)
-
-#define dct_memory_cleared(pvt) \
- (pvt->dram_ctl_select_low & F10_DCTL_SEL_LOW_MemCleared)
-
+#define dct_sel_baseaddr(pvt) ((pvt->dram_ctl_select_low) & 0xFFFFF800)
+#define dct_sel_interleave_addr(pvt) (((pvt->dram_ctl_select_low) >> 6) & 0x3)
+#define dct_high_range_enabled(pvt) (pvt->dram_ctl_select_low & BIT(0))
+#define dct_interleave_enabled(pvt) (pvt->dram_ctl_select_low & BIT(2))
+#define dct_ganging_enabled(pvt) (pvt->dram_ctl_select_low & BIT(4))
+#define dct_data_intlv_enabled(pvt) (pvt->dram_ctl_select_low & BIT(5))
+#define dct_dram_enabled(pvt) (pvt->dram_ctl_select_low & BIT(8))
+#define dct_memory_cleared(pvt) (pvt->dram_ctl_select_low & BIT(10))
#define F10_DCTL_SEL_HIGH 0x114
-
/*
* Function 3 - Misc Control
*/
@@ -382,6 +355,8 @@ enum {
#define K8_NBCAP_SECDED BIT(3)
#define K8_NBCAP_DCT_DUAL BIT(0)
+#define EXT_NB_MCA_CFG 0x180
+
/* MSRs */
#define K8_MSR_MCGCTL_NBE BIT(4)
@@ -471,6 +446,9 @@ struct amd64_pvt {
u32 dram_ctl_select_high; /* DRAM Controller Select High Reg */
u32 online_spare; /* On-Line spare Reg */
+ /* x4 or x8 syndromes in use */
+ u8 syn_type;
+
/* temp storage for when input is received from sysfs */
struct err_regs ctl_error_info;
diff --git a/drivers/edac/e752x_edac.c b/drivers/edac/e752x_edac.c
index ae3f80c5419..073f5a06d23 100644
--- a/drivers/edac/e752x_edac.c
+++ b/drivers/edac/e752x_edac.c
@@ -958,7 +958,7 @@ static void e752x_check(struct mem_ctl_info *mci)
}
/* Program byte/sec bandwidth scrub rate to hardware */
-static int set_sdram_scrub_rate(struct mem_ctl_info *mci, u32 *new_bw)
+static int set_sdram_scrub_rate(struct mem_ctl_info *mci, u32 new_bw)
{
const struct scrubrate *scrubrates;
struct e752x_pvt *pvt = (struct e752x_pvt *) mci->pvt_info;
@@ -975,7 +975,7 @@ static int set_sdram_scrub_rate(struct mem_ctl_info *mci, u32 *new_bw)
* desired rate and program the cooresponding register value.
*/
for (i = 0; scrubrates[i].bandwidth != SDRATE_EOT; i++)
- if (scrubrates[i].bandwidth >= *new_bw)
+ if (scrubrates[i].bandwidth >= new_bw)
break;
if (scrubrates[i].bandwidth == SDRATE_EOT)
diff --git a/drivers/edac/edac_core.h b/drivers/edac/edac_core.h
index efca9343d26..ce7146677e9 100644
--- a/drivers/edac/edac_core.h
+++ b/drivers/edac/edac_core.h
@@ -49,21 +49,15 @@
#define edac_printk(level, prefix, fmt, arg...) \
printk(level "EDAC " prefix ": " fmt, ##arg)
-#define edac_printk_verbose(level, prefix, fmt, arg...) \
- printk(level "EDAC " prefix ": " "in %s, line at %d: " fmt, \
- __FILE__, __LINE__, ##arg)
-
#define edac_mc_printk(mci, level, fmt, arg...) \
printk(level "EDAC MC%d: " fmt, mci->mc_idx, ##arg)
#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)
@@ -76,21 +70,12 @@
extern int edac_debug_level;
extern const char *edac_mem_types[];
-#ifndef CONFIG_EDAC_DEBUG_VERBOSE
#define edac_debug_printk(level, fmt, arg...) \
do { \
if (level <= edac_debug_level) \
edac_printk(KERN_DEBUG, EDAC_DEBUG, \
"%s: " fmt, __func__, ##arg); \
} while (0)
-#else /* CONFIG_EDAC_DEBUG_VERBOSE */
-#define edac_debug_printk(level, fmt, arg...) \
- do { \
- if (level <= edac_debug_level) \
- edac_printk_verbose(KERN_DEBUG, EDAC_DEBUG, fmt, \
- ##arg); \
- } while (0)
-#endif
#define debugf0( ... ) edac_debug_printk(0, __VA_ARGS__ )
#define debugf1( ... ) edac_debug_printk(1, __VA_ARGS__ )
@@ -393,7 +378,7 @@ struct mem_ctl_info {
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
diff --git a/drivers/edac/edac_mc_sysfs.c b/drivers/edac/edac_mc_sysfs.c
index c200c2fd43e..8aad94d10c0 100644
--- a/drivers/edac/edac_mc_sysfs.c
+++ b/drivers/edac/edac_mc_sysfs.c
@@ -124,19 +124,6 @@ static const char *edac_caps[] = {
[EDAC_S16ECD16ED] = "S16ECD16ED"
};
-
-
-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
*/
@@ -450,53 +437,54 @@ static ssize_t mci_reset_counters_store(struct mem_ctl_info *mci,
/* memory scrubbing */
static ssize_t mci_sdram_scrub_rate_store(struct mem_ctl_info *mci,
- const char *data, size_t count)
+ const char *data, size_t count)
{
- u32 bandwidth = -1;
+ unsigned long bandwidth = 0;
+ int err;
- if (mci->set_sdram_scrub_rate) {
+ if (!mci->set_sdram_scrub_rate) {
+ edac_printk(KERN_WARNING, EDAC_MC,
+ "Memory scrub rate setting not implemented!\n");
+ return -EINVAL;
+ }
- memctrl_int_store(&bandwidth, data, count);
+ if (strict_strtoul(data, 10, &bandwidth) < 0)
+ return -EINVAL;
- 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");
+ err = mci->set_sdram_scrub_rate(mci, (u32)bandwidth);
+ if (err) {
+ edac_printk(KERN_DEBUG, EDAC_MC,
+ "Failed setting scrub rate to %lu\n", bandwidth);
+ return -EINVAL;
+ }
+ else {
+ edac_printk(KERN_DEBUG, EDAC_MC,
+ "Scrub rate set to: %lu\n", bandwidth);
+ return count;
}
- 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. */
+ u32 bandwidth = 0;
+ int err;
+
+ if (!mci->get_sdram_scrub_rate) {
edac_printk(KERN_WARNING, EDAC_MC,
- "Memory scrubbing 'get' control is not implemented\n");
+ "Memory scrub rate reading not implemented\n");
+ return -EINVAL;
+ }
+
+ err = mci->get_sdram_scrub_rate(mci, &bandwidth);
+ if (err) {
+ edac_printk(KERN_DEBUG, EDAC_MC, "Error reading scrub rate\n");
+ return err;
+ }
+ else {
+ edac_printk(KERN_DEBUG, EDAC_MC,
+ "Read scrub rate: %d\n", bandwidth);
+ return sprintf(data, "%d\n", bandwidth);
}
- return sprintf(data, "%d\n", bandwidth);
}
/* default attribute files for the MCI object */
diff --git a/drivers/edac/edac_mce_amd.c b/drivers/edac/edac_mce_amd.c
index 97e64bcdbc0..bae9351e947 100644
--- a/drivers/edac/edac_mce_amd.c
+++ b/drivers/edac/edac_mce_amd.c
@@ -133,7 +133,7 @@ static void amd_decode_dc_mce(u64 mc0_status)
u32 ec = mc0_status & 0xffff;
u32 xec = (mc0_status >> 16) & 0xf;
- pr_emerg(" Data Cache Error");
+ pr_emerg("Data Cache Error");
if (xec == 1 && TLB_ERROR(ec))
pr_cont(": %s TLB multimatch.\n", LL_MSG(ec));
@@ -176,7 +176,7 @@ static void amd_decode_ic_mce(u64 mc1_status)
u32 ec = mc1_status & 0xffff;
u32 xec = (mc1_status >> 16) & 0xf;
- pr_emerg(" Instruction Cache Error");
+ pr_emerg("Instruction Cache Error");
if (xec == 1 && TLB_ERROR(ec))
pr_cont(": %s TLB multimatch.\n", LL_MSG(ec));
@@ -233,7 +233,7 @@ static void amd_decode_bu_mce(u64 mc2_status)
u32 ec = mc2_status & 0xffff;
u32 xec = (mc2_status >> 16) & 0xf;
- pr_emerg(" Bus Unit Error");
+ pr_emerg("Bus Unit Error");
if (xec == 0x1)
pr_cont(" in the write data buffers.\n");
@@ -275,7 +275,7 @@ static void amd_decode_ls_mce(u64 mc3_status)
u32 ec = mc3_status & 0xffff;
u32 xec = (mc3_status >> 16) & 0xf;
- pr_emerg(" Load Store Error");
+ pr_emerg("Load Store Error");
if (xec == 0x0) {
u8 rrrr = (ec >> 4) & 0xf;
@@ -304,7 +304,7 @@ void amd_decode_nb_mce(int node_id, struct err_regs *regs, int handle_errors)
if (TLB_ERROR(ec) && !report_gart_errors)
return;
- pr_emerg(" Northbridge Error, node %d", node_id);
+ pr_emerg("Northbridge Error, node %d", node_id);
/*
* F10h, revD can disable ErrCpu[3:0] so check that first and also the
@@ -342,13 +342,13 @@ static void amd_decode_fr_mce(u64 mc5_status)
static inline void amd_decode_err_code(unsigned int ec)
{
if (TLB_ERROR(ec)) {
- pr_emerg(" Transaction: %s, Cache Level %s\n",
+ pr_emerg("Transaction: %s, Cache Level %s\n",
TT_MSG(ec), LL_MSG(ec));
} else if (MEM_ERROR(ec)) {
- pr_emerg(" Transaction: %s, Type: %s, Cache Level: %s",
+ pr_emerg("Transaction: %s, Type: %s, Cache Level: %s",
RRRR_MSG(ec), TT_MSG(ec), LL_MSG(ec));
} else if (BUS_ERROR(ec)) {
- pr_emerg(" Transaction type: %s(%s), %s, Cache Level: %s, "
+ pr_emerg("Transaction type: %s(%s), %s, Cache Level: %s, "
"Participating Processor: %s\n",
RRRR_MSG(ec), II_MSG(ec), TO_MSG(ec), LL_MSG(ec),
PP_MSG(ec));
diff --git a/drivers/edac/i5100_edac.c b/drivers/edac/i5100_edac.c
index ee9753cf362..f459a6c0886 100644
--- a/drivers/edac/i5100_edac.c
+++ b/drivers/edac/i5100_edac.c
@@ -589,14 +589,13 @@ static void i5100_refresh_scrubbing(struct work_struct *work)
/*
* The bandwidth is based on experimentation, feel free to refine it.
*/
-static int i5100_set_scrub_rate(struct mem_ctl_info *mci,
- u32 *bandwidth)
+static int i5100_set_scrub_rate(struct mem_ctl_info *mci, u32 bandwidth)
{
struct i5100_priv *priv = mci->pvt_info;
u32 dw;
pci_read_config_dword(priv->mc, I5100_MC, &dw);
- if (*bandwidth) {
+ if (bandwidth) {
priv->scrub_enable = 1;
dw |= I5100_MC_SCRBEN_MASK;
schedule_delayed_work(&(priv->i5100_scrubbing),
@@ -610,7 +609,7 @@ static int i5100_set_scrub_rate(struct mem_ctl_info *mci,
pci_read_config_dword(priv->mc, I5100_MC, &dw);
- *bandwidth = 5900000 * i5100_mc_scrben(dw);
+ bandwidth = 5900000 * i5100_mc_scrben(dw);
return 0;
}
diff --git a/drivers/firewire/Kconfig b/drivers/firewire/Kconfig
index a9371b36a9b..fcf3ea28340 100644
--- a/drivers/firewire/Kconfig
+++ b/drivers/firewire/Kconfig
@@ -66,4 +66,28 @@ config FIREWIRE_NET
source "drivers/ieee1394/Kconfig"
+config FIREWIRE_NOSY
+ tristate "Nosy - a FireWire traffic sniffer for PCILynx cards"
+ depends on PCI
+ help
+ Nosy is an IEEE 1394 packet sniffer that is used for protocol
+ analysis and in development of IEEE 1394 drivers, applications,
+ or firmwares.
+
+ This driver lets you use a Texas Instruments PCILynx 1394 to PCI
+ link layer controller TSB12LV21/A/B as a low-budget bus analyzer.
+ PCILynx is a nowadays very rare IEEE 1394 controller which is
+ not OHCI 1394 compliant.
+
+ The following cards are known to be based on PCILynx or PCILynx-2:
+ IOI IOI-1394TT (PCI card), Unibrain Fireboard 400 PCI Lynx-2
+ (PCI card), Newer Technology FireWire 2 Go (CardBus card),
+ Apple Power Mac G3 blue & white (onboard controller).
+
+ To compile this driver as a module, say M here: The module will be
+ called nosy. Source code of a userspace interface to nosy, called
+ nosy-dump, can be found in tools/firewire/ of the kernel sources.
+
+ If unsure, say N.
+
endmenu
diff --git a/drivers/firewire/Makefile b/drivers/firewire/Makefile
index a8f9bb6d9fd..3c6a7fb20aa 100644
--- a/drivers/firewire/Makefile
+++ b/drivers/firewire/Makefile
@@ -12,3 +12,4 @@ obj-$(CONFIG_FIREWIRE) += firewire-core.o
obj-$(CONFIG_FIREWIRE_OHCI) += firewire-ohci.o
obj-$(CONFIG_FIREWIRE_SBP2) += firewire-sbp2.o
obj-$(CONFIG_FIREWIRE_NET) += firewire-net.o
+obj-$(CONFIG_FIREWIRE_NOSY) += nosy.o
diff --git a/drivers/firewire/core-card.c b/drivers/firewire/core-card.c
index 371713ff026..be0492398ef 100644
--- a/drivers/firewire/core-card.c
+++ b/drivers/firewire/core-card.c
@@ -204,17 +204,62 @@ void fw_core_remove_descriptor(struct fw_descriptor *desc)
}
EXPORT_SYMBOL(fw_core_remove_descriptor);
+static int reset_bus(struct fw_card *card, bool short_reset)
+{
+ int reg = short_reset ? 5 : 1;
+ int bit = short_reset ? PHY_BUS_SHORT_RESET : PHY_BUS_RESET;
+
+ return card->driver->update_phy_reg(card, reg, 0, bit);
+}
+
+void fw_schedule_bus_reset(struct fw_card *card, bool delayed, bool short_reset)
+{
+ /* We don't try hard to sort out requests of long vs. short resets. */
+ card->br_short = short_reset;
+
+ /* Use an arbitrary short delay to combine multiple reset requests. */
+ fw_card_get(card);
+ if (!schedule_delayed_work(&card->br_work,
+ delayed ? DIV_ROUND_UP(HZ, 100) : 0))
+ fw_card_put(card);
+}
+EXPORT_SYMBOL(fw_schedule_bus_reset);
+
+static void br_work(struct work_struct *work)
+{
+ struct fw_card *card = container_of(work, struct fw_card, br_work.work);
+
+ /* Delay for 2s after last reset per IEEE 1394 clause 8.2.1. */
+ if (card->reset_jiffies != 0 &&
+ time_is_after_jiffies(card->reset_jiffies + 2 * HZ)) {
+ if (!schedule_delayed_work(&card->br_work, 2 * HZ))
+ fw_card_put(card);
+ return;
+ }
+
+ fw_send_phy_config(card, FW_PHY_CONFIG_NO_NODE_ID, card->generation,
+ FW_PHY_CONFIG_CURRENT_GAP_COUNT);
+ reset_bus(card, card->br_short);
+ fw_card_put(card);
+}
+
static void allocate_broadcast_channel(struct fw_card *card, int generation)
{
int channel, bandwidth = 0;
- fw_iso_resource_manage(card, generation, 1ULL << 31, &channel,
- &bandwidth, true, card->bm_transaction_data);
- if (channel == 31) {
+ if (!card->broadcast_channel_allocated) {
+ fw_iso_resource_manage(card, generation, 1ULL << 31,
+ &channel, &bandwidth, true,
+ card->bm_transaction_data);
+ if (channel != 31) {
+ fw_notify("failed to allocate broadcast channel\n");
+ return;
+ }
card->broadcast_channel_allocated = true;
- device_for_each_child(card->device, (void *)(long)generation,
- fw_device_set_broadcast_channel);
}
+
+ device_for_each_child(card->device, (void *)(long)generation,
+ fw_device_set_broadcast_channel);
}
static const char gap_count_table[] = {
@@ -224,27 +269,26 @@ static const char gap_count_table[] = {
void fw_schedule_bm_work(struct fw_card *card, unsigned long delay)
{
fw_card_get(card);
- if (!schedule_delayed_work(&card->work, delay))
+ if (!schedule_delayed_work(&card->bm_work, delay))
fw_card_put(card);
}
-static void fw_card_bm_work(struct work_struct *work)
+static void bm_work(struct work_struct *work)
{
- struct fw_card *card = container_of(work, struct fw_card, work.work);
+ struct fw_card *card = container_of(work, struct fw_card, bm_work.work);
struct fw_device *root_device, *irm_device;
struct fw_node *root_node;
- unsigned long flags;
- int root_id, new_root_id, irm_id, local_id;
+ int root_id, new_root_id, irm_id, bm_id, local_id;
int gap_count, generation, grace, rcode;
bool do_reset = false;
bool root_device_is_running;
bool root_device_is_cmc;
bool irm_is_1394_1995_only;
- spin_lock_irqsave(&card->lock, flags);
+ spin_lock_irq(&card->lock);
if (card->local_node == NULL) {
- spin_unlock_irqrestore(&card->lock, flags);
+ spin_unlock_irq(&card->lock);
goto out_put_card;
}
@@ -267,7 +311,8 @@ static void fw_card_bm_work(struct work_struct *work)
grace = time_after(jiffies, card->reset_jiffies + DIV_ROUND_UP(HZ, 8));
- if (is_next_generation(generation, card->bm_generation) ||
+ if ((is_next_generation(generation, card->bm_generation) &&
+ !card->bm_abdicate) ||
(card->bm_generation != generation && grace)) {
/*
* This first step is to figure out who is IRM and
@@ -298,21 +343,26 @@ static void fw_card_bm_work(struct work_struct *work)
card->bm_transaction_data[0] = cpu_to_be32(0x3f);
card->bm_transaction_data[1] = cpu_to_be32(local_id);
- spin_unlock_irqrestore(&card->lock, flags);
+ spin_unlock_irq(&card->lock);
rcode = fw_run_transaction(card, TCODE_LOCK_COMPARE_SWAP,
irm_id, generation, SCODE_100,
CSR_REGISTER_BASE + CSR_BUS_MANAGER_ID,
- card->bm_transaction_data,
- sizeof(card->bm_transaction_data));
+ card->bm_transaction_data, 8);
if (rcode == RCODE_GENERATION)
/* Another bus reset, BM work has been rescheduled. */
goto out;
- if (rcode == RCODE_COMPLETE &&
- card->bm_transaction_data[0] != cpu_to_be32(0x3f)) {
+ bm_id = be32_to_cpu(card->bm_transaction_data[0]);
+ spin_lock_irq(&card->lock);
+ if (rcode == RCODE_COMPLETE && generation == card->generation)
+ card->bm_node_id =
+ bm_id == 0x3f ? local_id : 0xffc0 | bm_id;
+ spin_unlock_irq(&card->lock);
+
+ if (rcode == RCODE_COMPLETE && bm_id != 0x3f) {
/* Somebody else is BM. Only act as IRM. */
if (local_id == irm_id)
allocate_broadcast_channel(card, generation);
@@ -320,7 +370,17 @@ static void fw_card_bm_work(struct work_struct *work)
goto out;
}
- spin_lock_irqsave(&card->lock, flags);
+ if (rcode == RCODE_SEND_ERROR) {
+ /*
+ * We have been unable to send the lock request due to
+ * some local problem. Let's try again later and hope
+ * that the problem has gone away by then.
+ */
+ fw_schedule_bm_work(card, DIV_ROUND_UP(HZ, 8));
+ goto out;
+ }
+
+ spin_lock_irq(&card->lock);
if (rcode != RCODE_COMPLETE) {
/*
@@ -339,7 +399,7 @@ static void fw_card_bm_work(struct work_struct *work)
* We weren't BM in the last generation, and the last
* bus reset is less than 125ms ago. Reschedule this job.
*/
- spin_unlock_irqrestore(&card->lock, flags);
+ spin_unlock_irq(&card->lock);
fw_schedule_bm_work(card, DIV_ROUND_UP(HZ, 8));
goto out;
}
@@ -362,14 +422,12 @@ static void fw_card_bm_work(struct work_struct *work)
* If we haven't probed this device yet, bail out now
* and let's try again once that's done.
*/
- spin_unlock_irqrestore(&card->lock, flags);
+ spin_unlock_irq(&card->lock);
goto out;
} else if (root_device_is_cmc) {
/*
- * FIXME: I suppose we should set the cmstr bit in the
- * STATE_CLEAR register of this node, as described in
- * 1394-1995, 8.4.2.6. Also, send out a force root
- * packet for this node.
+ * We will send out a force root packet for this
+ * node as part of the gap count optimization.
*/
new_root_id = root_id;
} else {
@@ -402,19 +460,33 @@ static void fw_card_bm_work(struct work_struct *work)
(card->gap_count != gap_count || new_root_id != root_id))
do_reset = true;
- spin_unlock_irqrestore(&card->lock, flags);
+ spin_unlock_irq(&card->lock);
if (do_reset) {
fw_notify("phy config: card %d, new root=%x, gap_count=%d\n",
card->index, new_root_id, gap_count);
fw_send_phy_config(card, new_root_id, generation, gap_count);
- fw_core_initiate_bus_reset(card, 1);
+ reset_bus(card, true);
/* Will allocate broadcast channel after the reset. */
- } else {
- if (local_id == irm_id)
- allocate_broadcast_channel(card, generation);
+ goto out;
+ }
+
+ if (root_device_is_cmc) {
+ /*
+ * Make sure that the cycle master sends cycle start packets.
+ */
+ card->bm_transaction_data[0] = cpu_to_be32(CSR_STATE_BIT_CMSTR);
+ rcode = fw_run_transaction(card, TCODE_WRITE_QUADLET_REQUEST,
+ root_id, generation, SCODE_100,
+ CSR_REGISTER_BASE + CSR_STATE_SET,
+ card->bm_transaction_data, 4);
+ if (rcode == RCODE_GENERATION)
+ goto out;
}
+ if (local_id == irm_id)
+ allocate_broadcast_channel(card, generation);
+
out:
fw_node_put(root_node);
out_put_card:
@@ -432,17 +504,23 @@ void fw_card_initialize(struct fw_card *card,
card->device = device;
card->current_tlabel = 0;
card->tlabel_mask = 0;
+ card->split_timeout_hi = 0;
+ card->split_timeout_lo = 800 << 19;
+ card->split_timeout_cycles = 800;
+ card->split_timeout_jiffies = DIV_ROUND_UP(HZ, 10);
card->color = 0;
card->broadcast_channel = BROADCAST_CHANNEL_INITIAL;
kref_init(&card->kref);
init_completion(&card->done);
INIT_LIST_HEAD(&card->transaction_list);
+ INIT_LIST_HEAD(&card->phy_receiver_list);
spin_lock_init(&card->lock);
card->local_node = NULL;
- INIT_DELAYED_WORK(&card->work, fw_card_bm_work);
+ INIT_DELAYED_WORK(&card->br_work, br_work);
+ INIT_DELAYED_WORK(&card->bm_work, bm_work);
}
EXPORT_SYMBOL(fw_card_initialize);
@@ -468,20 +546,22 @@ int fw_card_add(struct fw_card *card,
}
EXPORT_SYMBOL(fw_card_add);
-
/*
* The next few functions implement a dummy driver that is used once a card
* driver shuts down an fw_card. This allows the driver to cleanly unload,
* as all IO to the card will be handled (and failed) by the dummy driver
* instead of calling into the module. Only functions for iso context
* shutdown still need to be provided by the card driver.
+ *
+ * .read/write_csr() should never be called anymore after the dummy driver
+ * was bound since they are only used within request handler context.
+ * .set_config_rom() is never called since the card is taken out of card_list
+ * before switching to the dummy driver.
*/
-static int dummy_enable(struct fw_card *card,
- const __be32 *config_rom, size_t length)
+static int dummy_read_phy_reg(struct fw_card *card, int address)
{
- BUG();
- return -1;
+ return -ENODEV;
}
static int dummy_update_phy_reg(struct fw_card *card, int address,
@@ -490,25 +570,14 @@ static int dummy_update_phy_reg(struct fw_card *card, int address,
return -ENODEV;
}
-static int dummy_set_config_rom(struct fw_card *card,
- const __be32 *config_rom, size_t length)
-{
- /*
- * We take the card out of card_list before setting the dummy
- * driver, so this should never get called.
- */
- BUG();
- return -1;
-}
-
static void dummy_send_request(struct fw_card *card, struct fw_packet *packet)
{
- packet->callback(packet, card, -ENODEV);
+ packet->callback(packet, card, RCODE_CANCELLED);
}
static void dummy_send_response(struct fw_card *card, struct fw_packet *packet)
{
- packet->callback(packet, card, -ENODEV);
+ packet->callback(packet, card, RCODE_CANCELLED);
}
static int dummy_cancel_packet(struct fw_card *card, struct fw_packet *packet)
@@ -522,14 +591,40 @@ static int dummy_enable_phys_dma(struct fw_card *card,
return -ENODEV;
}
+static struct fw_iso_context *dummy_allocate_iso_context(struct fw_card *card,
+ int type, int channel, size_t header_size)
+{
+ return ERR_PTR(-ENODEV);
+}
+
+static int dummy_start_iso(struct fw_iso_context *ctx,
+ s32 cycle, u32 sync, u32 tags)
+{
+ return -ENODEV;
+}
+
+static int dummy_set_iso_channels(struct fw_iso_context *ctx, u64 *channels)
+{
+ return -ENODEV;
+}
+
+static int dummy_queue_iso(struct fw_iso_context *ctx, struct fw_iso_packet *p,
+ struct fw_iso_buffer *buffer, unsigned long payload)
+{
+ return -ENODEV;
+}
+
static const struct fw_card_driver dummy_driver_template = {
- .enable = dummy_enable,
- .update_phy_reg = dummy_update_phy_reg,
- .set_config_rom = dummy_set_config_rom,
- .send_request = dummy_send_request,
- .cancel_packet = dummy_cancel_packet,
- .send_response = dummy_send_response,
- .enable_phys_dma = dummy_enable_phys_dma,
+ .read_phy_reg = dummy_read_phy_reg,
+ .update_phy_reg = dummy_update_phy_reg,
+ .send_request = dummy_send_request,
+ .send_response = dummy_send_response,
+ .cancel_packet = dummy_cancel_packet,
+ .enable_phys_dma = dummy_enable_phys_dma,
+ .allocate_iso_context = dummy_allocate_iso_context,
+ .start_iso = dummy_start_iso,
+ .set_iso_channels = dummy_set_iso_channels,
+ .queue_iso = dummy_queue_iso,
};
void fw_card_release(struct kref *kref)
@@ -545,7 +640,7 @@ void fw_core_remove_card(struct fw_card *card)
card->driver->update_phy_reg(card, 4,
PHY_LINK_ACTIVE | PHY_CONTENDER, 0);
- fw_core_initiate_bus_reset(card, 1);
+ fw_schedule_bus_reset(card, false, true);
mutex_lock(&card_mutex);
list_del_init(&card->link);
@@ -565,12 +660,3 @@ void fw_core_remove_card(struct fw_card *card)
WARN_ON(!list_empty(&card->transaction_list));
}
EXPORT_SYMBOL(fw_core_remove_card);
-
-int fw_core_initiate_bus_reset(struct fw_card *card, int short_reset)
-{
- int reg = short_reset ? 5 : 1;
- int bit = short_reset ? PHY_BUS_SHORT_RESET : PHY_BUS_RESET;
-
- return card->driver->update_phy_reg(card, reg, 0, bit);
-}
-EXPORT_SYMBOL(fw_core_initiate_bus_reset);
diff --git a/drivers/firewire/core-cdev.c b/drivers/firewire/core-cdev.c
index 5bf106b9d79..14bb7b7b5dd 100644
--- a/drivers/firewire/core-cdev.c
+++ b/drivers/firewire/core-cdev.c
@@ -18,6 +18,7 @@
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
+#include <linux/bug.h>
#include <linux/compat.h>
#include <linux/delay.h>
#include <linux/device.h>
@@ -33,7 +34,7 @@
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/poll.h>
-#include <linux/sched.h>
+#include <linux/sched.h> /* required for linux/wait.h */
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/string.h>
@@ -47,6 +48,13 @@
#include "core.h"
+/*
+ * ABI version history is documented in linux/firewire-cdev.h.
+ */
+#define FW_CDEV_KERNEL_VERSION 4
+#define FW_CDEV_VERSION_EVENT_REQUEST2 4
+#define FW_CDEV_VERSION_ALLOCATE_REGION_END 4
+
struct client {
u32 version;
struct fw_device *device;
@@ -63,6 +71,9 @@ struct client {
struct fw_iso_buffer buffer;
unsigned long vm_start;
+ struct list_head phy_receiver_link;
+ u64 phy_receiver_closure;
+
struct list_head link;
struct kref kref;
};
@@ -107,6 +118,7 @@ struct outbound_transaction_resource {
struct inbound_transaction_resource {
struct client_resource resource;
+ struct fw_card *card;
struct fw_request *request;
void *data;
size_t length;
@@ -171,7 +183,10 @@ struct outbound_transaction_event {
struct inbound_transaction_event {
struct event event;
- struct fw_cdev_event_request request;
+ union {
+ struct fw_cdev_event_request request;
+ struct fw_cdev_event_request2 request2;
+ } req;
};
struct iso_interrupt_event {
@@ -179,11 +194,28 @@ struct iso_interrupt_event {
struct fw_cdev_event_iso_interrupt interrupt;
};
+struct iso_interrupt_mc_event {
+ struct event event;
+ struct fw_cdev_event_iso_interrupt_mc interrupt;
+};
+
struct iso_resource_event {
struct event event;
struct fw_cdev_event_iso_resource iso_resource;
};
+struct outbound_phy_packet_event {
+ struct event event;
+ struct client *client;
+ struct fw_packet p;
+ struct fw_cdev_event_phy_packet phy_packet;
+};
+
+struct inbound_phy_packet_event {
+ struct event event;
+ struct fw_cdev_event_phy_packet phy_packet;
+};
+
static inline void __user *u64_to_uptr(__u64 value)
{
return (void __user *)(unsigned long)value;
@@ -219,6 +251,7 @@ static int fw_device_op_open(struct inode *inode, struct file *file)
idr_init(&client->resource_idr);
INIT_LIST_HEAD(&client->event_list);
init_waitqueue_head(&client->wait);
+ INIT_LIST_HEAD(&client->phy_receiver_link);
kref_init(&client->kref);
file->private_data = client;
@@ -309,7 +342,7 @@ static void fill_bus_reset_event(struct fw_cdev_event_bus_reset *event,
event->generation = client->device->generation;
event->node_id = client->device->node_id;
event->local_node_id = card->local_node->node_id;
- event->bm_node_id = 0; /* FIXME: We don't track the BM. */
+ event->bm_node_id = card->bm_node_id;
event->irm_node_id = card->irm_node->node_id;
event->root_node_id = card->root_node->node_id;
@@ -340,7 +373,7 @@ static void queue_bus_reset_event(struct client *client)
e = kzalloc(sizeof(*e), GFP_KERNEL);
if (e == NULL) {
- fw_notify("Out of memory when allocating bus reset event\n");
+ fw_notify("Out of memory when allocating event\n");
return;
}
@@ -386,6 +419,9 @@ union ioctl_arg {
struct fw_cdev_allocate_iso_resource allocate_iso_resource;
struct fw_cdev_send_stream_packet send_stream_packet;
struct fw_cdev_get_cycle_timer2 get_cycle_timer2;
+ struct fw_cdev_send_phy_packet send_phy_packet;
+ struct fw_cdev_receive_phy_packets receive_phy_packets;
+ struct fw_cdev_set_iso_channels set_iso_channels;
};
static int ioctl_get_info(struct client *client, union ioctl_arg *arg)
@@ -395,7 +431,7 @@ static int ioctl_get_info(struct client *client, union ioctl_arg *arg)
unsigned long ret = 0;
client->version = a->version;
- a->version = FW_CDEV_VERSION;
+ a->version = FW_CDEV_KERNEL_VERSION;
a->card = client->device->card->index;
down_read(&fw_device_rwsem);
@@ -554,6 +590,10 @@ static int init_request(struct client *client,
(request->length > 4096 || request->length > 512 << speed))
return -EIO;
+ if (request->tcode == TCODE_WRITE_QUADLET_REQUEST &&
+ request->length < 4)
+ return -EINVAL;
+
e = kmalloc(sizeof(*e) + request->length, GFP_KERNEL);
if (e == NULL)
return -ENOMEM;
@@ -626,28 +666,34 @@ static void release_request(struct client *client,
if (is_fcp_request(r->request))
kfree(r->data);
else
- fw_send_response(client->device->card, r->request,
- RCODE_CONFLICT_ERROR);
+ fw_send_response(r->card, r->request, RCODE_CONFLICT_ERROR);
+
+ fw_card_put(r->card);
kfree(r);
}
static void handle_request(struct fw_card *card, struct fw_request *request,
int tcode, int destination, int source,
- int generation, int speed,
- unsigned long long offset,
+ int generation, unsigned long long offset,
void *payload, size_t length, void *callback_data)
{
struct address_handler_resource *handler = callback_data;
struct inbound_transaction_resource *r;
struct inbound_transaction_event *e;
+ size_t event_size0;
void *fcp_frame = NULL;
int ret;
+ /* card may be different from handler->client->device->card */
+ fw_card_get(card);
+
r = kmalloc(sizeof(*r), GFP_ATOMIC);
e = kmalloc(sizeof(*e), GFP_ATOMIC);
- if (r == NULL || e == NULL)
+ if (r == NULL || e == NULL) {
+ fw_notify("Out of memory when allocating event\n");
goto failed;
-
+ }
+ r->card = card;
r->request = request;
r->data = payload;
r->length = length;
@@ -669,15 +715,37 @@ static void handle_request(struct fw_card *card, struct fw_request *request,
if (ret < 0)
goto failed;
- e->request.type = FW_CDEV_EVENT_REQUEST;
- e->request.tcode = tcode;
- e->request.offset = offset;
- e->request.length = length;
- e->request.handle = r->resource.handle;
- e->request.closure = handler->closure;
+ if (handler->client->version < FW_CDEV_VERSION_EVENT_REQUEST2) {
+ struct fw_cdev_event_request *req = &e->req.request;
+
+ if (tcode & 0x10)
+ tcode = TCODE_LOCK_REQUEST;
+
+ req->type = FW_CDEV_EVENT_REQUEST;
+ req->tcode = tcode;
+ req->offset = offset;
+ req->length = length;
+ req->handle = r->resource.handle;
+ req->closure = handler->closure;
+ event_size0 = sizeof(*req);
+ } else {
+ struct fw_cdev_event_request2 *req = &e->req.request2;
+
+ req->type = FW_CDEV_EVENT_REQUEST2;
+ req->tcode = tcode;
+ req->offset = offset;
+ req->source_node_id = source;
+ req->destination_node_id = destination;
+ req->card = card->index;
+ req->generation = generation;
+ req->length = length;
+ req->handle = r->resource.handle;
+ req->closure = handler->closure;
+ event_size0 = sizeof(*req);
+ }
queue_event(handler->client, &e->event,
- &e->request, sizeof(e->request), r->data, length);
+ &e->req, event_size0, r->data, length);
return;
failed:
@@ -687,6 +755,8 @@ static void handle_request(struct fw_card *card, struct fw_request *request,
if (!is_fcp_request(request))
fw_send_response(card, request, RCODE_CONFLICT_ERROR);
+
+ fw_card_put(card);
}
static void release_address_handler(struct client *client,
@@ -711,7 +781,11 @@ static int ioctl_allocate(struct client *client, union ioctl_arg *arg)
return -ENOMEM;
region.start = a->offset;
- region.end = a->offset + a->length;
+ if (client->version < FW_CDEV_VERSION_ALLOCATE_REGION_END)
+ region.end = a->offset + a->length;
+ else
+ region.end = a->region_end;
+
r->handler.length = a->length;
r->handler.address_callback = handle_request;
r->handler.callback_data = r;
@@ -723,6 +797,7 @@ static int ioctl_allocate(struct client *client, union ioctl_arg *arg)
kfree(r);
return ret;
}
+ a->offset = r->handler.offset;
r->resource.release = release_address_handler;
ret = add_client_resource(client, &r->resource, GFP_KERNEL);
@@ -757,15 +832,19 @@ static int ioctl_send_response(struct client *client, union ioctl_arg *arg)
if (is_fcp_request(r->request))
goto out;
- if (a->length < r->length)
- r->length = a->length;
- if (copy_from_user(r->data, u64_to_uptr(a->data), r->length)) {
+ if (a->length != fw_get_response_length(r->request)) {
+ ret = -EINVAL;
+ kfree(r->request);
+ goto out;
+ }
+ if (copy_from_user(r->data, u64_to_uptr(a->data), a->length)) {
ret = -EFAULT;
kfree(r->request);
goto out;
}
- fw_send_response(client->device->card, r->request, a->rcode);
+ fw_send_response(r->card, r->request, a->rcode);
out:
+ fw_card_put(r->card);
kfree(r);
return ret;
@@ -773,8 +852,9 @@ static int ioctl_send_response(struct client *client, union ioctl_arg *arg)
static int ioctl_initiate_bus_reset(struct client *client, union ioctl_arg *arg)
{
- return fw_core_initiate_bus_reset(client->device->card,
+ fw_schedule_bus_reset(client->device->card, true,
arg->initiate_bus_reset.type == FW_CDEV_SHORT_RESET);
+ return 0;
}
static void release_descriptor(struct client *client,
@@ -845,10 +925,11 @@ static void iso_callback(struct fw_iso_context *context, u32 cycle,
struct client *client = data;
struct iso_interrupt_event *e;
- e = kzalloc(sizeof(*e) + header_length, GFP_ATOMIC);
- if (e == NULL)
+ e = kmalloc(sizeof(*e) + header_length, GFP_ATOMIC);
+ if (e == NULL) {
+ fw_notify("Out of memory when allocating event\n");
return;
-
+ }
e->interrupt.type = FW_CDEV_EVENT_ISO_INTERRUPT;
e->interrupt.closure = client->iso_closure;
e->interrupt.cycle = cycle;
@@ -858,27 +939,54 @@ static void iso_callback(struct fw_iso_context *context, u32 cycle,
sizeof(e->interrupt) + header_length, NULL, 0);
}
+static void iso_mc_callback(struct fw_iso_context *context,
+ dma_addr_t completed, void *data)
+{
+ struct client *client = data;
+ struct iso_interrupt_mc_event *e;
+
+ e = kmalloc(sizeof(*e), GFP_ATOMIC);
+ if (e == NULL) {
+ fw_notify("Out of memory when allocating event\n");
+ return;
+ }
+ e->interrupt.type = FW_CDEV_EVENT_ISO_INTERRUPT_MULTICHANNEL;
+ e->interrupt.closure = client->iso_closure;
+ e->interrupt.completed = fw_iso_buffer_lookup(&client->buffer,
+ completed);
+ queue_event(client, &e->event, &e->interrupt,
+ sizeof(e->interrupt), NULL, 0);
+}
+
static int ioctl_create_iso_context(struct client *client, union ioctl_arg *arg)
{
struct fw_cdev_create_iso_context *a = &arg->create_iso_context;
struct fw_iso_context *context;
+ fw_iso_callback_t cb;
- /* We only support one context at this time. */
- if (client->iso_context != NULL)
- return -EBUSY;
-
- if (a->channel > 63)
- return -EINVAL;
+ BUILD_BUG_ON(FW_CDEV_ISO_CONTEXT_TRANSMIT != FW_ISO_CONTEXT_TRANSMIT ||
+ FW_CDEV_ISO_CONTEXT_RECEIVE != FW_ISO_CONTEXT_RECEIVE ||
+ FW_CDEV_ISO_CONTEXT_RECEIVE_MULTICHANNEL !=
+ FW_ISO_CONTEXT_RECEIVE_MULTICHANNEL);
switch (a->type) {
- case FW_ISO_CONTEXT_RECEIVE:
- if (a->header_size < 4 || (a->header_size & 3))
+ case FW_ISO_CONTEXT_TRANSMIT:
+ if (a->speed > SCODE_3200 || a->channel > 63)
return -EINVAL;
+
+ cb = iso_callback;
break;
- case FW_ISO_CONTEXT_TRANSMIT:
- if (a->speed > SCODE_3200)
+ case FW_ISO_CONTEXT_RECEIVE:
+ if (a->header_size < 4 || (a->header_size & 3) ||
+ a->channel > 63)
return -EINVAL;
+
+ cb = iso_callback;
+ break;
+
+ case FW_ISO_CONTEXT_RECEIVE_MULTICHANNEL:
+ cb = (fw_iso_callback_t)iso_mc_callback;
break;
default:
@@ -886,20 +994,37 @@ static int ioctl_create_iso_context(struct client *client, union ioctl_arg *arg)
}
context = fw_iso_context_create(client->device->card, a->type,
- a->channel, a->speed, a->header_size,
- iso_callback, client);
+ a->channel, a->speed, a->header_size, cb, client);
if (IS_ERR(context))
return PTR_ERR(context);
+ /* We only support one context at this time. */
+ spin_lock_irq(&client->lock);
+ if (client->iso_context != NULL) {
+ spin_unlock_irq(&client->lock);
+ fw_iso_context_destroy(context);
+ return -EBUSY;
+ }
client->iso_closure = a->closure;
client->iso_context = context;
+ spin_unlock_irq(&client->lock);
- /* We only support one context at this time. */
a->handle = 0;
return 0;
}
+static int ioctl_set_iso_channels(struct client *client, union ioctl_arg *arg)
+{
+ struct fw_cdev_set_iso_channels *a = &arg->set_iso_channels;
+ struct fw_iso_context *ctx = client->iso_context;
+
+ if (ctx == NULL || a->handle != 0)
+ return -EINVAL;
+
+ return fw_iso_context_set_channels(ctx, &a->channels);
+}
+
/* Macros for decoding the iso packet control header. */
#define GET_PAYLOAD_LENGTH(v) ((v) & 0xffff)
#define GET_INTERRUPT(v) (((v) >> 16) & 0x01)
@@ -913,7 +1038,7 @@ static int ioctl_queue_iso(struct client *client, union ioctl_arg *arg)
struct fw_cdev_queue_iso *a = &arg->queue_iso;
struct fw_cdev_iso_packet __user *p, *end, *next;
struct fw_iso_context *ctx = client->iso_context;
- unsigned long payload, buffer_end, header_length;
+ unsigned long payload, buffer_end, transmit_header_bytes = 0;
u32 control;
int count;
struct {
@@ -933,7 +1058,6 @@ static int ioctl_queue_iso(struct client *client, union ioctl_arg *arg)
* use the indirect payload, the iso buffer need not be mapped
* and the a->data pointer is ignored.
*/
-
payload = (unsigned long)a->data - client->vm_start;
buffer_end = client->buffer.page_count << PAGE_SHIFT;
if (a->data == 0 || client->buffer.pages == NULL ||
@@ -942,8 +1066,10 @@ static int ioctl_queue_iso(struct client *client, union ioctl_arg *arg)
buffer_end = 0;
}
- p = (struct fw_cdev_iso_packet __user *)u64_to_uptr(a->packets);
+ if (ctx->type == FW_ISO_CONTEXT_RECEIVE_MULTICHANNEL && payload & 3)
+ return -EINVAL;
+ p = (struct fw_cdev_iso_packet __user *)u64_to_uptr(a->packets);
if (!access_ok(VERIFY_READ, p, a->size))
return -EFAULT;
@@ -959,31 +1085,32 @@ static int ioctl_queue_iso(struct client *client, union ioctl_arg *arg)
u.packet.sy = GET_SY(control);
u.packet.header_length = GET_HEADER_LENGTH(control);
- if (ctx->type == FW_ISO_CONTEXT_TRANSMIT) {
- if (u.packet.header_length % 4 != 0)
+ switch (ctx->type) {
+ case FW_ISO_CONTEXT_TRANSMIT:
+ if (u.packet.header_length & 3)
+ return -EINVAL;
+ transmit_header_bytes = u.packet.header_length;
+ break;
+
+ case FW_ISO_CONTEXT_RECEIVE:
+ if (u.packet.header_length == 0 ||
+ u.packet.header_length % ctx->header_size != 0)
return -EINVAL;
- header_length = u.packet.header_length;
- } else {
- /*
- * We require that header_length is a multiple of
- * the fixed header size, ctx->header_size.
- */
- if (ctx->header_size == 0) {
- if (u.packet.header_length > 0)
- return -EINVAL;
- } else if (u.packet.header_length == 0 ||
- u.packet.header_length % ctx->header_size != 0) {
+ break;
+
+ case FW_ISO_CONTEXT_RECEIVE_MULTICHANNEL:
+ if (u.packet.payload_length == 0 ||
+ u.packet.payload_length & 3)
return -EINVAL;
- }
- header_length = 0;
+ break;
}
next = (struct fw_cdev_iso_packet __user *)
- &p->header[header_length / 4];
+ &p->header[transmit_header_bytes / 4];
if (next > end)
return -EINVAL;
if (__copy_from_user
- (u.packet.header, p->header, header_length))
+ (u.packet.header, p->header, transmit_header_bytes))
return -EFAULT;
if (u.packet.skip && ctx->type == FW_ISO_CONTEXT_TRANSMIT &&
u.packet.header_length + u.packet.payload_length > 0)
@@ -1011,6 +1138,13 @@ static int ioctl_start_iso(struct client *client, union ioctl_arg *arg)
{
struct fw_cdev_start_iso *a = &arg->start_iso;
+ BUILD_BUG_ON(
+ FW_CDEV_ISO_CONTEXT_MATCH_TAG0 != FW_ISO_CONTEXT_MATCH_TAG0 ||
+ FW_CDEV_ISO_CONTEXT_MATCH_TAG1 != FW_ISO_CONTEXT_MATCH_TAG1 ||
+ FW_CDEV_ISO_CONTEXT_MATCH_TAG2 != FW_ISO_CONTEXT_MATCH_TAG2 ||
+ FW_CDEV_ISO_CONTEXT_MATCH_TAG3 != FW_ISO_CONTEXT_MATCH_TAG3 ||
+ FW_CDEV_ISO_CONTEXT_MATCH_ALL_TAGS != FW_ISO_CONTEXT_MATCH_ALL_TAGS);
+
if (client->iso_context == NULL || a->handle != 0)
return -EINVAL;
@@ -1042,7 +1176,7 @@ static int ioctl_get_cycle_timer2(struct client *client, union ioctl_arg *arg)
local_irq_disable();
- cycle_time = card->driver->get_cycle_time(card);
+ cycle_time = card->driver->read_csr(card, CSR_CYCLE_TIME);
switch (a->clk_id) {
case CLOCK_REALTIME: getnstimeofday(&ts); break;
@@ -1323,28 +1457,135 @@ static int ioctl_send_stream_packet(struct client *client, union ioctl_arg *arg)
return init_request(client, &request, dest, a->speed);
}
+static void outbound_phy_packet_callback(struct fw_packet *packet,
+ struct fw_card *card, int status)
+{
+ struct outbound_phy_packet_event *e =
+ container_of(packet, struct outbound_phy_packet_event, p);
+
+ switch (status) {
+ /* expected: */
+ case ACK_COMPLETE: e->phy_packet.rcode = RCODE_COMPLETE; break;
+ /* should never happen with PHY packets: */
+ case ACK_PENDING: e->phy_packet.rcode = RCODE_COMPLETE; break;
+ case ACK_BUSY_X:
+ case ACK_BUSY_A:
+ case ACK_BUSY_B: e->phy_packet.rcode = RCODE_BUSY; break;
+ case ACK_DATA_ERROR: e->phy_packet.rcode = RCODE_DATA_ERROR; break;
+ case ACK_TYPE_ERROR: e->phy_packet.rcode = RCODE_TYPE_ERROR; break;
+ /* stale generation; cancelled; on certain controllers: no ack */
+ default: e->phy_packet.rcode = status; break;
+ }
+ e->phy_packet.data[0] = packet->timestamp;
+
+ queue_event(e->client, &e->event, &e->phy_packet,
+ sizeof(e->phy_packet) + e->phy_packet.length, NULL, 0);
+ client_put(e->client);
+}
+
+static int ioctl_send_phy_packet(struct client *client, union ioctl_arg *arg)
+{
+ struct fw_cdev_send_phy_packet *a = &arg->send_phy_packet;
+ struct fw_card *card = client->device->card;
+ struct outbound_phy_packet_event *e;
+
+ /* Access policy: Allow this ioctl only on local nodes' device files. */
+ if (!client->device->is_local)
+ return -ENOSYS;
+
+ e = kzalloc(sizeof(*e) + 4, GFP_KERNEL);
+ if (e == NULL)
+ return -ENOMEM;
+
+ client_get(client);
+ e->client = client;
+ e->p.speed = SCODE_100;
+ e->p.generation = a->generation;
+ e->p.header[0] = a->data[0];
+ e->p.header[1] = a->data[1];
+ e->p.header_length = 8;
+ e->p.callback = outbound_phy_packet_callback;
+ e->phy_packet.closure = a->closure;
+ e->phy_packet.type = FW_CDEV_EVENT_PHY_PACKET_SENT;
+ if (is_ping_packet(a->data))
+ e->phy_packet.length = 4;
+
+ card->driver->send_request(card, &e->p);
+
+ return 0;
+}
+
+static int ioctl_receive_phy_packets(struct client *client, union ioctl_arg *arg)
+{
+ struct fw_cdev_receive_phy_packets *a = &arg->receive_phy_packets;
+ struct fw_card *card = client->device->card;
+
+ /* Access policy: Allow this ioctl only on local nodes' device files. */
+ if (!client->device->is_local)
+ return -ENOSYS;
+
+ spin_lock_irq(&card->lock);
+
+ list_move_tail(&client->phy_receiver_link, &card->phy_receiver_list);
+ client->phy_receiver_closure = a->closure;
+
+ spin_unlock_irq(&card->lock);
+
+ return 0;
+}
+
+void fw_cdev_handle_phy_packet(struct fw_card *card, struct fw_packet *p)
+{
+ struct client *client;
+ struct inbound_phy_packet_event *e;
+ unsigned long flags;
+
+ spin_lock_irqsave(&card->lock, flags);
+
+ list_for_each_entry(client, &card->phy_receiver_list, phy_receiver_link) {
+ e = kmalloc(sizeof(*e) + 8, GFP_ATOMIC);
+ if (e == NULL) {
+ fw_notify("Out of memory when allocating event\n");
+ break;
+ }
+ e->phy_packet.closure = client->phy_receiver_closure;
+ e->phy_packet.type = FW_CDEV_EVENT_PHY_PACKET_RECEIVED;
+ e->phy_packet.rcode = RCODE_COMPLETE;
+ e->phy_packet.length = 8;
+ e->phy_packet.data[0] = p->header[1];
+ e->phy_packet.data[1] = p->header[2];
+ queue_event(client, &e->event,
+ &e->phy_packet, sizeof(e->phy_packet) + 8, NULL, 0);
+ }
+
+ spin_unlock_irqrestore(&card->lock, flags);
+}
+
static int (* const ioctl_handlers[])(struct client *, union ioctl_arg *) = {
- ioctl_get_info,
- ioctl_send_request,
- ioctl_allocate,
- ioctl_deallocate,
- ioctl_send_response,
- ioctl_initiate_bus_reset,
- ioctl_add_descriptor,
- ioctl_remove_descriptor,
- ioctl_create_iso_context,
- ioctl_queue_iso,
- ioctl_start_iso,
- ioctl_stop_iso,
- ioctl_get_cycle_timer,
- ioctl_allocate_iso_resource,
- ioctl_deallocate_iso_resource,
- ioctl_allocate_iso_resource_once,
- ioctl_deallocate_iso_resource_once,
- ioctl_get_speed,
- ioctl_send_broadcast_request,
- ioctl_send_stream_packet,
- ioctl_get_cycle_timer2,
+ [0x00] = ioctl_get_info,
+ [0x01] = ioctl_send_request,
+ [0x02] = ioctl_allocate,
+ [0x03] = ioctl_deallocate,
+ [0x04] = ioctl_send_response,
+ [0x05] = ioctl_initiate_bus_reset,
+ [0x06] = ioctl_add_descriptor,
+ [0x07] = ioctl_remove_descriptor,
+ [0x08] = ioctl_create_iso_context,
+ [0x09] = ioctl_queue_iso,
+ [0x0a] = ioctl_start_iso,
+ [0x0b] = ioctl_stop_iso,
+ [0x0c] = ioctl_get_cycle_timer,
+ [0x0d] = ioctl_allocate_iso_resource,
+ [0x0e] = ioctl_deallocate_iso_resource,
+ [0x0f] = ioctl_allocate_iso_resource_once,
+ [0x10] = ioctl_deallocate_iso_resource_once,
+ [0x11] = ioctl_get_speed,
+ [0x12] = ioctl_send_broadcast_request,
+ [0x13] = ioctl_send_stream_packet,
+ [0x14] = ioctl_get_cycle_timer2,
+ [0x15] = ioctl_send_phy_packet,
+ [0x16] = ioctl_receive_phy_packets,
+ [0x17] = ioctl_set_iso_channels,
};
static int dispatch_ioctl(struct client *client,
@@ -1452,6 +1693,10 @@ static int fw_device_op_release(struct inode *inode, struct file *file)
struct client *client = file->private_data;
struct event *event, *next_event;
+ spin_lock_irq(&client->device->card->lock);
+ list_del(&client->phy_receiver_link);
+ spin_unlock_irq(&client->device->card->lock);
+
mutex_lock(&client->device->client_list_mutex);
list_del(&client->link);
mutex_unlock(&client->device->client_list_mutex);
diff --git a/drivers/firewire/core-device.c b/drivers/firewire/core-device.c
index 4b8523f00dc..6113b896e79 100644
--- a/drivers/firewire/core-device.c
+++ b/drivers/firewire/core-device.c
@@ -107,11 +107,11 @@ static int textual_leaf_to_string(const u32 *block, char *buf, size_t size)
}
/**
- * fw_csr_string - reads a string from the configuration ROM
- * @directory: e.g. root directory or unit directory
- * @key: the key of the preceding directory entry
- * @buf: where to put the string
- * @size: size of @buf, in bytes
+ * fw_csr_string() - reads a string from the configuration ROM
+ * @directory: e.g. root directory or unit directory
+ * @key: the key of the preceding directory entry
+ * @buf: where to put the string
+ * @size: size of @buf, in bytes
*
* The string is taken from a minimal ASCII text descriptor leaf after
* the immediate entry with @key. The string is zero-terminated.
@@ -1136,6 +1136,7 @@ static void fw_device_refresh(struct work_struct *work)
goto give_up;
}
+ fw_device_cdev_update(device);
create_units(device);
/* Userspace may want to re-read attributes. */
diff --git a/drivers/firewire/core-iso.c b/drivers/firewire/core-iso.c
index 8f5aebfb29d..c003fa4e2db 100644
--- a/drivers/firewire/core-iso.c
+++ b/drivers/firewire/core-iso.c
@@ -118,6 +118,23 @@ void fw_iso_buffer_destroy(struct fw_iso_buffer *buffer,
}
EXPORT_SYMBOL(fw_iso_buffer_destroy);
+/* Convert DMA address to offset into virtually contiguous buffer. */
+size_t fw_iso_buffer_lookup(struct fw_iso_buffer *buffer, dma_addr_t completed)
+{
+ int i;
+ dma_addr_t address;
+ ssize_t offset;
+
+ for (i = 0; i < buffer->page_count; i++) {
+ address = page_private(buffer->pages[i]);
+ offset = (ssize_t)completed - (ssize_t)address;
+ if (offset > 0 && offset <= PAGE_SIZE)
+ return (i << PAGE_SHIFT) + offset;
+ }
+
+ return 0;
+}
+
struct fw_iso_context *fw_iso_context_create(struct fw_card *card,
int type, int channel, int speed, size_t header_size,
fw_iso_callback_t callback, void *callback_data)
@@ -134,7 +151,7 @@ struct fw_iso_context *fw_iso_context_create(struct fw_card *card,
ctx->channel = channel;
ctx->speed = speed;
ctx->header_size = header_size;
- ctx->callback = callback;
+ ctx->callback.sc = callback;
ctx->callback_data = callback_data;
return ctx;
@@ -143,9 +160,7 @@ EXPORT_SYMBOL(fw_iso_context_create);
void fw_iso_context_destroy(struct fw_iso_context *ctx)
{
- struct fw_card *card = ctx->card;
-
- card->driver->free_iso_context(ctx);
+ ctx->card->driver->free_iso_context(ctx);
}
EXPORT_SYMBOL(fw_iso_context_destroy);
@@ -156,14 +171,17 @@ int fw_iso_context_start(struct fw_iso_context *ctx,
}
EXPORT_SYMBOL(fw_iso_context_start);
+int fw_iso_context_set_channels(struct fw_iso_context *ctx, u64 *channels)
+{
+ return ctx->card->driver->set_iso_channels(ctx, channels);
+}
+
int fw_iso_context_queue(struct fw_iso_context *ctx,
struct fw_iso_packet *packet,
struct fw_iso_buffer *buffer,
unsigned long payload)
{
- struct fw_card *card = ctx->card;
-
- return card->driver->queue_iso(ctx, packet, buffer, payload);
+ return ctx->card->driver->queue_iso(ctx, packet, buffer, payload);
}
EXPORT_SYMBOL(fw_iso_context_queue);
@@ -279,7 +297,7 @@ static void deallocate_channel(struct fw_card *card, int irm_id,
}
/**
- * fw_iso_resource_manage - Allocate or deallocate a channel and/or bandwidth
+ * fw_iso_resource_manage() - Allocate or deallocate a channel and/or bandwidth
*
* In parameters: card, generation, channels_mask, bandwidth, allocate
* Out parameters: channel, bandwidth
diff --git a/drivers/firewire/core-topology.c b/drivers/firewire/core-topology.c
index 93ec64cdeef..09be1a63550 100644
--- a/drivers/firewire/core-topology.c
+++ b/drivers/firewire/core-topology.c
@@ -174,12 +174,7 @@ static inline struct fw_node *fw_node(struct list_head *l)
return list_entry(l, struct fw_node, link);
}
-/**
- * build_tree - Build the tree representation of the topology
- * @self_ids: array of self IDs to create the tree from
- * @self_id_count: the length of the self_ids array
- * @local_id: the node ID of the local node
- *
+/*
* This function builds the tree representation of the topology given
* by the self IDs from the latest bus reset. During the construction
* of the tree, the function checks that the self IDs are valid and
@@ -420,11 +415,10 @@ static void move_tree(struct fw_node *node0, struct fw_node *node1, int port)
}
}
-/**
- * update_tree - compare the old topology tree for card with the new
- * one specified by root. Queue the nodes and mark them as either
- * found, lost or updated. Update the nodes in the card topology tree
- * as we go.
+/*
+ * Compare the old topology tree for card with the new one specified by root.
+ * Queue the nodes and mark them as either found, lost or updated.
+ * Update the nodes in the card topology tree as we go.
*/
static void update_tree(struct fw_card *card, struct fw_node *root)
{
@@ -524,7 +518,7 @@ static void update_topology_map(struct fw_card *card,
}
void fw_core_handle_bus_reset(struct fw_card *card, int node_id, int generation,
- int self_id_count, u32 *self_ids)
+ int self_id_count, u32 *self_ids, bool bm_abdicate)
{
struct fw_node *local_node;
unsigned long flags;
@@ -543,7 +537,7 @@ void fw_core_handle_bus_reset(struct fw_card *card, int node_id, int generation,
spin_lock_irqsave(&card->lock, flags);
- card->broadcast_channel_allocated = false;
+ card->broadcast_channel_allocated = card->broadcast_channel_auto_allocated;
card->node_id = node_id;
/*
* Update node_id before generation to prevent anybody from using
@@ -552,6 +546,8 @@ void fw_core_handle_bus_reset(struct fw_card *card, int node_id, int generation,
smp_wmb();
card->generation = generation;
card->reset_jiffies = jiffies;
+ card->bm_node_id = 0xffff;
+ card->bm_abdicate = bm_abdicate;
fw_schedule_bm_work(card, 0);
local_node = build_tree(card, self_ids, self_id_count);
diff --git a/drivers/firewire/core-transaction.c b/drivers/firewire/core-transaction.c
index fdc33ff06dc..ca7ca56661e 100644
--- a/drivers/firewire/core-transaction.c
+++ b/drivers/firewire/core-transaction.c
@@ -246,7 +246,7 @@ static void fw_fill_request(struct fw_packet *packet, int tcode, int tlabel,
break;
default:
- WARN(1, KERN_ERR "wrong tcode %d", tcode);
+ WARN(1, "wrong tcode %d", tcode);
}
common:
packet->speed = speed;
@@ -273,43 +273,52 @@ static int allocate_tlabel(struct fw_card *card)
}
/**
- * This function provides low-level access to the IEEE1394 transaction
- * logic. Most C programs would use either fw_read(), fw_write() or
- * fw_lock() instead - those function are convenience wrappers for
- * this function. The fw_send_request() function is primarily
- * provided as a flexible, one-stop entry point for languages bindings
- * and protocol bindings.
+ * fw_send_request() - submit a request packet for transmission
+ * @card: interface to send the request at
+ * @t: transaction instance to which the request belongs
+ * @tcode: transaction code
+ * @destination_id: destination node ID, consisting of bus_ID and phy_ID
+ * @generation: bus generation in which request and response are valid
+ * @speed: transmission speed
+ * @offset: 48bit wide offset into destination's address space
+ * @payload: data payload for the request subaction
+ * @length: length of the payload, in bytes
+ * @callback: function to be called when the transaction is completed
+ * @callback_data: data to be passed to the transaction completion callback
*
- * FIXME: Document this function further, in particular the possible
- * values for rcode in the callback. In short, we map ACK_COMPLETE to
- * RCODE_COMPLETE, internal errors set errno and set rcode to
- * RCODE_SEND_ERROR (which is out of range for standard ieee1394
- * rcodes). All other rcodes are forwarded unchanged. For all
- * errors, payload is NULL, length is 0.
+ * Submit a request packet into the asynchronous request transmission queue.
+ * Can be called from atomic context. If you prefer a blocking API, use
+ * fw_run_transaction() in a context that can sleep.
*
- * Can not expect the callback to be called before the function
- * returns, though this does happen in some cases (ACK_COMPLETE and
- * errors).
+ * In case of lock requests, specify one of the firewire-core specific %TCODE_
+ * constants instead of %TCODE_LOCK_REQUEST in @tcode.
*
- * The payload is only used for write requests and must not be freed
- * until the callback has been called.
+ * Make sure that the value in @destination_id is not older than the one in
+ * @generation. Otherwise the request is in danger to be sent to a wrong node.
*
- * @param card the card from which to send the request
- * @param tcode the tcode for this transaction. Do not use
- * TCODE_LOCK_REQUEST directly, instead use TCODE_LOCK_MASK_SWAP
- * etc. to specify tcode and ext_tcode.
- * @param node_id the destination node ID (bus ID and PHY ID concatenated)
- * @param generation the generation for which node_id is valid
- * @param speed the speed to use for sending the request
- * @param offset the 48 bit offset on the destination node
- * @param payload the data payload for the request subaction
- * @param length the length in bytes of the data to read
- * @param callback function to be called when the transaction is completed
- * @param callback_data pointer to arbitrary data, which will be
- * passed to the callback
- *
- * In case of asynchronous stream packets i.e. TCODE_STREAM_DATA, the caller
+ * In case of asynchronous stream packets i.e. %TCODE_STREAM_DATA, the caller
* needs to synthesize @destination_id with fw_stream_packet_destination_id().
+ * It will contain tag, channel, and sy data instead of a node ID then.
+ *
+ * The payload buffer at @data is going to be DMA-mapped except in case of
+ * quadlet-sized payload or of local (loopback) requests. Hence make sure that
+ * the buffer complies with the restrictions for DMA-mapped memory. The
+ * @payload must not be freed before the @callback is called.
+ *
+ * In case of request types without payload, @data is NULL and @length is 0.
+ *
+ * After the transaction is completed successfully or unsuccessfully, the
+ * @callback will be called. Among its parameters is the response code which
+ * is either one of the rcodes per IEEE 1394 or, in case of internal errors,
+ * the firewire-core specific %RCODE_SEND_ERROR. The other firewire-core
+ * specific rcodes (%RCODE_CANCELLED, %RCODE_BUSY, %RCODE_GENERATION,
+ * %RCODE_NO_ACK) denote transaction timeout, busy responder, stale request
+ * generation, or missing ACK respectively.
+ *
+ * Note some timing corner cases: fw_send_request() may complete much earlier
+ * than when the request packet actually hits the wire. On the other hand,
+ * transaction completion and hence execution of @callback may happen even
+ * before fw_send_request() returns.
*/
void fw_send_request(struct fw_card *card, struct fw_transaction *t, int tcode,
int destination_id, int generation, int speed,
@@ -339,7 +348,8 @@ void fw_send_request(struct fw_card *card, struct fw_transaction *t, int tcode,
setup_timer(&t->split_timeout_timer,
split_transaction_timeout_callback, (unsigned long)t);
/* FIXME: start this timer later, relative to t->timestamp */
- mod_timer(&t->split_timeout_timer, jiffies + DIV_ROUND_UP(HZ, 10));
+ mod_timer(&t->split_timeout_timer,
+ jiffies + card->split_timeout_jiffies);
t->callback = callback;
t->callback_data = callback_data;
@@ -374,9 +384,11 @@ static void transaction_callback(struct fw_card *card, int rcode,
}
/**
- * fw_run_transaction - send request and sleep until transaction is completed
+ * fw_run_transaction() - send request and sleep until transaction is completed
*
- * Returns the RCODE.
+ * Returns the RCODE. See fw_send_request() for parameter documentation.
+ * Unlike fw_send_request(), @data points to the payload of the request or/and
+ * to the payload of the response.
*/
int fw_run_transaction(struct fw_card *card, int tcode, int destination_id,
int generation, int speed, unsigned long long offset,
@@ -417,9 +429,21 @@ void fw_send_phy_config(struct fw_card *card,
int node_id, int generation, int gap_count)
{
long timeout = DIV_ROUND_UP(HZ, 10);
- u32 data = PHY_IDENTIFIER(PHY_PACKET_CONFIG) |
- PHY_CONFIG_ROOT_ID(node_id) |
- PHY_CONFIG_GAP_COUNT(gap_count);
+ u32 data = PHY_IDENTIFIER(PHY_PACKET_CONFIG);
+
+ if (node_id != FW_PHY_CONFIG_NO_NODE_ID)
+ data |= PHY_CONFIG_ROOT_ID(node_id);
+
+ if (gap_count == FW_PHY_CONFIG_CURRENT_GAP_COUNT) {
+ gap_count = card->driver->read_phy_reg(card, 1);
+ if (gap_count < 0)
+ return;
+
+ gap_count &= 63;
+ if (gap_count == 63)
+ return;
+ }
+ data |= PHY_CONFIG_GAP_COUNT(gap_count);
mutex_lock(&phy_config_mutex);
@@ -494,9 +518,9 @@ static bool is_in_fcp_region(u64 offset, size_t length)
}
/**
- * fw_core_add_address_handler - register for incoming requests
- * @handler: callback
- * @region: region in the IEEE 1212 node space address range
+ * fw_core_add_address_handler() - register for incoming requests
+ * @handler: callback
+ * @region: region in the IEEE 1212 node space address range
*
* region->start, ->end, and handler->length have to be quadlet-aligned.
*
@@ -519,8 +543,8 @@ int fw_core_add_address_handler(struct fw_address_handler *handler,
int ret = -EBUSY;
if (region->start & 0xffff000000000003ULL ||
- region->end & 0xffff000000000003ULL ||
region->start >= region->end ||
+ region->end > 0x0001000000000000ULL ||
handler->length & 3 ||
handler->length == 0)
return -EINVAL;
@@ -551,7 +575,7 @@ int fw_core_add_address_handler(struct fw_address_handler *handler,
EXPORT_SYMBOL(fw_core_add_address_handler);
/**
- * fw_core_remove_address_handler - unregister an address handler
+ * fw_core_remove_address_handler() - unregister an address handler
*/
void fw_core_remove_address_handler(struct fw_address_handler *handler)
{
@@ -580,6 +604,41 @@ static void free_response_callback(struct fw_packet *packet,
kfree(request);
}
+int fw_get_response_length(struct fw_request *r)
+{
+ int tcode, ext_tcode, data_length;
+
+ tcode = HEADER_GET_TCODE(r->request_header[0]);
+
+ switch (tcode) {
+ case TCODE_WRITE_QUADLET_REQUEST:
+ case TCODE_WRITE_BLOCK_REQUEST:
+ return 0;
+
+ case TCODE_READ_QUADLET_REQUEST:
+ return 4;
+
+ case TCODE_READ_BLOCK_REQUEST:
+ data_length = HEADER_GET_DATA_LENGTH(r->request_header[3]);
+ return data_length;
+
+ case TCODE_LOCK_REQUEST:
+ ext_tcode = HEADER_GET_EXTENDED_TCODE(r->request_header[3]);
+ data_length = HEADER_GET_DATA_LENGTH(r->request_header[3]);
+ switch (ext_tcode) {
+ case EXTCODE_FETCH_ADD:
+ case EXTCODE_LITTLE_ADD:
+ return data_length;
+ default:
+ return data_length / 2;
+ }
+
+ default:
+ WARN(1, "wrong tcode %d", tcode);
+ return 0;
+ }
+}
+
void fw_fill_response(struct fw_packet *response, u32 *request_header,
int rcode, void *payload, size_t length)
{
@@ -631,18 +690,35 @@ void fw_fill_response(struct fw_packet *response, u32 *request_header,
break;
default:
- WARN(1, KERN_ERR "wrong tcode %d", tcode);
+ WARN(1, "wrong tcode %d", tcode);
}
response->payload_mapped = false;
}
EXPORT_SYMBOL(fw_fill_response);
-static struct fw_request *allocate_request(struct fw_packet *p)
+static u32 compute_split_timeout_timestamp(struct fw_card *card,
+ u32 request_timestamp)
+{
+ unsigned int cycles;
+ u32 timestamp;
+
+ cycles = card->split_timeout_cycles;
+ cycles += request_timestamp & 0x1fff;
+
+ timestamp = request_timestamp & ~0x1fff;
+ timestamp += (cycles / 8000) << 13;
+ timestamp |= cycles % 8000;
+
+ return timestamp;
+}
+
+static struct fw_request *allocate_request(struct fw_card *card,
+ struct fw_packet *p)
{
struct fw_request *request;
u32 *data, length;
- int request_tcode, t;
+ int request_tcode;
request_tcode = HEADER_GET_TCODE(p->header[0]);
switch (request_tcode) {
@@ -677,14 +753,9 @@ static struct fw_request *allocate_request(struct fw_packet *p)
if (request == NULL)
return NULL;
- t = (p->timestamp & 0x1fff) + 4000;
- if (t >= 8000)
- t = (p->timestamp & ~0x1fff) + 0x2000 + t - 8000;
- else
- t = (p->timestamp & ~0x1fff) + t;
-
request->response.speed = p->speed;
- request->response.timestamp = t;
+ request->response.timestamp =
+ compute_split_timeout_timestamp(card, p->timestamp);
request->response.generation = p->generation;
request->response.ack = 0;
request->response.callback = free_response_callback;
@@ -713,7 +784,8 @@ void fw_send_response(struct fw_card *card,
if (rcode == RCODE_COMPLETE)
fw_fill_response(&request->response, request->request_header,
- rcode, request->data, request->length);
+ rcode, request->data,
+ fw_get_response_length(request));
else
fw_fill_response(&request->response, request->request_header,
rcode, NULL, 0);
@@ -731,9 +803,11 @@ static void handle_exclusive_region_request(struct fw_card *card,
unsigned long flags;
int tcode, destination, source;
- tcode = HEADER_GET_TCODE(p->header[0]);
destination = HEADER_GET_DESTINATION(p->header[0]);
source = HEADER_GET_SOURCE(p->header[1]);
+ tcode = HEADER_GET_TCODE(p->header[0]);
+ if (tcode == TCODE_LOCK_REQUEST)
+ tcode = 0x10 + HEADER_GET_EXTENDED_TCODE(p->header[3]);
spin_lock_irqsave(&address_handler_lock, flags);
handler = lookup_enclosing_address_handler(&address_handler_list,
@@ -753,7 +827,7 @@ static void handle_exclusive_region_request(struct fw_card *card,
else
handler->address_callback(card, request,
tcode, destination, source,
- p->generation, p->speed, offset,
+ p->generation, offset,
request->data, request->length,
handler->callback_data);
}
@@ -791,8 +865,8 @@ static void handle_fcp_region_request(struct fw_card *card,
if (is_enclosing_handler(handler, offset, request->length))
handler->address_callback(card, NULL, tcode,
destination, source,
- p->generation, p->speed,
- offset, request->data,
+ p->generation, offset,
+ request->data,
request->length,
handler->callback_data);
}
@@ -809,7 +883,12 @@ void fw_core_handle_request(struct fw_card *card, struct fw_packet *p)
if (p->ack != ACK_PENDING && p->ack != ACK_COMPLETE)
return;
- request = allocate_request(p);
+ if (TCODE_IS_LINK_INTERNAL(HEADER_GET_TCODE(p->header[0]))) {
+ fw_cdev_handle_phy_packet(card, p);
+ return;
+ }
+
+ request = allocate_request(card, p);
if (request == NULL) {
/* FIXME: send statically allocated busy packet. */
return;
@@ -832,13 +911,12 @@ void fw_core_handle_response(struct fw_card *card, struct fw_packet *p)
unsigned long flags;
u32 *data;
size_t data_length;
- int tcode, tlabel, destination, source, rcode;
+ int tcode, tlabel, source, rcode;
- tcode = HEADER_GET_TCODE(p->header[0]);
- tlabel = HEADER_GET_TLABEL(p->header[0]);
- destination = HEADER_GET_DESTINATION(p->header[0]);
- source = HEADER_GET_SOURCE(p->header[1]);
- rcode = HEADER_GET_RCODE(p->header[1]);
+ tcode = HEADER_GET_TCODE(p->header[0]);
+ tlabel = HEADER_GET_TLABEL(p->header[0]);
+ source = HEADER_GET_SOURCE(p->header[1]);
+ rcode = HEADER_GET_RCODE(p->header[1]);
spin_lock_irqsave(&card->lock, flags);
list_for_each_entry(t, &card->transaction_list, link) {
@@ -903,8 +981,8 @@ static const struct fw_address_region topology_map_region =
static void handle_topology_map(struct fw_card *card, struct fw_request *request,
int tcode, int destination, int source, int generation,
- int speed, unsigned long long offset,
- void *payload, size_t length, void *callback_data)
+ unsigned long long offset, void *payload, size_t length,
+ void *callback_data)
{
int start;
@@ -933,19 +1011,97 @@ static const struct fw_address_region registers_region =
{ .start = CSR_REGISTER_BASE,
.end = CSR_REGISTER_BASE | CSR_CONFIG_ROM, };
+static void update_split_timeout(struct fw_card *card)
+{
+ unsigned int cycles;
+
+ cycles = card->split_timeout_hi * 8000 + (card->split_timeout_lo >> 19);
+
+ cycles = max(cycles, 800u); /* minimum as per the spec */
+ cycles = min(cycles, 3u * 8000u); /* maximum OHCI timeout */
+
+ card->split_timeout_cycles = cycles;
+ card->split_timeout_jiffies = DIV_ROUND_UP(cycles * HZ, 8000);
+}
+
static void handle_registers(struct fw_card *card, struct fw_request *request,
int tcode, int destination, int source, int generation,
- int speed, unsigned long long offset,
- void *payload, size_t length, void *callback_data)
+ unsigned long long offset, void *payload, size_t length,
+ void *callback_data)
{
int reg = offset & ~CSR_REGISTER_BASE;
__be32 *data = payload;
int rcode = RCODE_COMPLETE;
+ unsigned long flags;
switch (reg) {
+ case CSR_PRIORITY_BUDGET:
+ if (!card->priority_budget_implemented) {
+ rcode = RCODE_ADDRESS_ERROR;
+ break;
+ }
+ /* else fall through */
+
+ case CSR_NODE_IDS:
+ /*
+ * per IEEE 1394-2008 8.3.22.3, not IEEE 1394.1-2004 3.2.8
+ * and 9.6, but interoperable with IEEE 1394.1-2004 bridges
+ */
+ /* fall through */
+
+ case CSR_STATE_CLEAR:
+ case CSR_STATE_SET:
case CSR_CYCLE_TIME:
- if (TCODE_IS_READ_REQUEST(tcode) && length == 4)
- *data = cpu_to_be32(card->driver->get_cycle_time(card));
+ case CSR_BUS_TIME:
+ case CSR_BUSY_TIMEOUT:
+ if (tcode == TCODE_READ_QUADLET_REQUEST)
+ *data = cpu_to_be32(card->driver->read_csr(card, reg));
+ else if (tcode == TCODE_WRITE_QUADLET_REQUEST)
+ card->driver->write_csr(card, reg, be32_to_cpu(*data));
+ else
+ rcode = RCODE_TYPE_ERROR;
+ break;
+
+ case CSR_RESET_START:
+ if (tcode == TCODE_WRITE_QUADLET_REQUEST)
+ card->driver->write_csr(card, CSR_STATE_CLEAR,
+ CSR_STATE_BIT_ABDICATE);
+ else
+ rcode = RCODE_TYPE_ERROR;
+ break;
+
+ case CSR_SPLIT_TIMEOUT_HI:
+ if (tcode == TCODE_READ_QUADLET_REQUEST) {
+ *data = cpu_to_be32(card->split_timeout_hi);
+ } else if (tcode == TCODE_WRITE_QUADLET_REQUEST) {
+ spin_lock_irqsave(&card->lock, flags);
+ card->split_timeout_hi = be32_to_cpu(*data) & 7;
+ update_split_timeout(card);
+ spin_unlock_irqrestore(&card->lock, flags);
+ } else {
+ rcode = RCODE_TYPE_ERROR;
+ }
+ break;
+
+ case CSR_SPLIT_TIMEOUT_LO:
+ if (tcode == TCODE_READ_QUADLET_REQUEST) {
+ *data = cpu_to_be32(card->split_timeout_lo);
+ } else if (tcode == TCODE_WRITE_QUADLET_REQUEST) {
+ spin_lock_irqsave(&card->lock, flags);
+ card->split_timeout_lo =
+ be32_to_cpu(*data) & 0xfff80000;
+ update_split_timeout(card);
+ spin_unlock_irqrestore(&card->lock, flags);
+ } else {
+ rcode = RCODE_TYPE_ERROR;
+ }
+ break;
+
+ case CSR_MAINT_UTILITY:
+ if (tcode == TCODE_READ_QUADLET_REQUEST)
+ *data = card->maint_utility_register;
+ else if (tcode == TCODE_WRITE_QUADLET_REQUEST)
+ card->maint_utility_register = *data;
else
rcode = RCODE_TYPE_ERROR;
break;
@@ -975,12 +1131,6 @@ static void handle_registers(struct fw_card *card, struct fw_request *request,
BUG();
break;
- case CSR_BUSY_TIMEOUT:
- /* FIXME: Implement this. */
-
- case CSR_BUS_TIME:
- /* Useless without initialization by the bus manager. */
-
default:
rcode = RCODE_ADDRESS_ERROR;
break;
diff --git a/drivers/firewire/core.h b/drivers/firewire/core.h
index 0ecfcd95f4c..e6239f971be 100644
--- a/drivers/firewire/core.h
+++ b/drivers/firewire/core.h
@@ -38,6 +38,9 @@ struct fw_packet;
#define BROADCAST_CHANNEL_INITIAL (1 << 31 | 31)
#define BROADCAST_CHANNEL_VALID (1 << 30)
+#define CSR_STATE_BIT_CMSTR (1 << 8)
+#define CSR_STATE_BIT_ABDICATE (1 << 10)
+
struct fw_card_driver {
/*
* Enable the given card with the given initial config rom.
@@ -48,6 +51,7 @@ struct fw_card_driver {
int (*enable)(struct fw_card *card,
const __be32 *config_rom, size_t length);
+ int (*read_phy_reg)(struct fw_card *card, int address);
int (*update_phy_reg)(struct fw_card *card, int address,
int clear_bits, int set_bits);
@@ -75,7 +79,8 @@ struct fw_card_driver {
int (*enable_phys_dma)(struct fw_card *card,
int node_id, int generation);
- u32 (*get_cycle_time)(struct fw_card *card);
+ u32 (*read_csr)(struct fw_card *card, int csr_offset);
+ void (*write_csr)(struct fw_card *card, int csr_offset, u32 value);
struct fw_iso_context *
(*allocate_iso_context)(struct fw_card *card,
@@ -85,6 +90,8 @@ struct fw_card_driver {
int (*start_iso)(struct fw_iso_context *ctx,
s32 cycle, u32 sync, u32 tags);
+ int (*set_iso_channels)(struct fw_iso_context *ctx, u64 *channels);
+
int (*queue_iso)(struct fw_iso_context *ctx,
struct fw_iso_packet *packet,
struct fw_iso_buffer *buffer,
@@ -98,8 +105,8 @@ void fw_card_initialize(struct fw_card *card,
int fw_card_add(struct fw_card *card,
u32 max_receive, u32 link_speed, u64 guid);
void fw_core_remove_card(struct fw_card *card);
-int fw_core_initiate_bus_reset(struct fw_card *card, int short_reset);
int fw_compute_block_crc(__be32 *block);
+void fw_schedule_bus_reset(struct fw_card *card, bool delayed, bool short_reset);
void fw_schedule_bm_work(struct fw_card *card, unsigned long delay);
static inline struct fw_card *fw_card_get(struct fw_card *card)
@@ -123,6 +130,7 @@ extern const struct file_operations fw_device_ops;
void fw_device_cdev_update(struct fw_device *device);
void fw_device_cdev_remove(struct fw_device *device);
+void fw_cdev_handle_phy_packet(struct fw_card *card, struct fw_packet *p);
/* -device */
@@ -192,7 +200,7 @@ static inline void fw_node_put(struct fw_node *node)
}
void fw_core_handle_bus_reset(struct fw_card *card, int node_id,
- int generation, int self_id_count, u32 *self_ids);
+ int generation, int self_id_count, u32 *self_ids, bool bm_abdicate);
void fw_destroy_nodes(struct fw_card *card);
/*
@@ -209,6 +217,7 @@ static inline bool is_next_generation(int new_generation, int old_generation)
#define TCODE_IS_READ_REQUEST(tcode) (((tcode) & ~1) == 4)
#define TCODE_IS_BLOCK_PACKET(tcode) (((tcode) & 1) != 0)
+#define TCODE_IS_LINK_INTERNAL(tcode) ((tcode) == 0xe)
#define TCODE_IS_REQUEST(tcode) (((tcode) & 2) == 0)
#define TCODE_IS_RESPONSE(tcode) (((tcode) & 2) != 0)
#define TCODE_HAS_REQUEST_DATA(tcode) (((tcode) & 12) != 4)
@@ -218,9 +227,18 @@ static inline bool is_next_generation(int new_generation, int old_generation)
void fw_core_handle_request(struct fw_card *card, struct fw_packet *request);
void fw_core_handle_response(struct fw_card *card, struct fw_packet *packet);
+int fw_get_response_length(struct fw_request *request);
void fw_fill_response(struct fw_packet *response, u32 *request_header,
int rcode, void *payload, size_t length);
+
+#define FW_PHY_CONFIG_NO_NODE_ID -1
+#define FW_PHY_CONFIG_CURRENT_GAP_COUNT -1
void fw_send_phy_config(struct fw_card *card,
int node_id, int generation, int gap_count);
+static inline bool is_ping_packet(u32 *data)
+{
+ return (data[0] & 0xc0ffffff) == 0 && ~data[0] == data[1];
+}
+
#endif /* _FIREWIRE_CORE_H */
diff --git a/drivers/firewire/net.c b/drivers/firewire/net.c
index 7142eeec807..da17d409a24 100644
--- a/drivers/firewire/net.c
+++ b/drivers/firewire/net.c
@@ -806,8 +806,8 @@ static int fwnet_incoming_packet(struct fwnet_device *dev, __be32 *buf, int len,
static void fwnet_receive_packet(struct fw_card *card, struct fw_request *r,
int tcode, int destination, int source, int generation,
- int speed, unsigned long long offset, void *payload,
- size_t length, void *callback_data)
+ unsigned long long offset, void *payload, size_t length,
+ void *callback_data)
{
struct fwnet_device *dev = callback_data;
int rcode;
diff --git a/drivers/firewire/nosy-user.h b/drivers/firewire/nosy-user.h
new file mode 100644
index 00000000000..e48aa6200c7
--- /dev/null
+++ b/drivers/firewire/nosy-user.h
@@ -0,0 +1,25 @@
+#ifndef __nosy_user_h
+#define __nosy_user_h
+
+#include <linux/ioctl.h>
+#include <linux/types.h>
+
+#define NOSY_IOC_GET_STATS _IOR('&', 0, struct nosy_stats)
+#define NOSY_IOC_START _IO('&', 1)
+#define NOSY_IOC_STOP _IO('&', 2)
+#define NOSY_IOC_FILTER _IOW('&', 2, __u32)
+
+struct nosy_stats {
+ __u32 total_packet_count;
+ __u32 lost_packet_count;
+};
+
+/*
+ * Format of packets returned from the kernel driver:
+ *
+ * quadlet with timestamp (microseconds, CPU endian)
+ * quadlet-padded packet data... (little endian)
+ * quadlet with ack (little endian)
+ */
+
+#endif /* __nosy_user_h */
diff --git a/drivers/firewire/nosy.c b/drivers/firewire/nosy.c
new file mode 100644
index 00000000000..8528b10763e
--- /dev/null
+++ b/drivers/firewire/nosy.c
@@ -0,0 +1,721 @@
+/*
+ * nosy - Snoop mode driver for TI PCILynx 1394 controllers
+ * Copyright (C) 2002-2007 Kristian Høgsberg
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * 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/device.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/kref.h>
+#include <linux/miscdevice.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/pci.h>
+#include <linux/poll.h>
+#include <linux/sched.h> /* required for linux/wait.h */
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/timex.h>
+#include <linux/uaccess.h>
+#include <linux/wait.h>
+
+#include <asm/atomic.h>
+#include <asm/byteorder.h>
+
+#include "nosy.h"
+#include "nosy-user.h"
+
+#define TCODE_PHY_PACKET 0x10
+#define PCI_DEVICE_ID_TI_PCILYNX 0x8000
+
+static char driver_name[] = KBUILD_MODNAME;
+
+/* this is the physical layout of a PCL, its size is 128 bytes */
+struct pcl {
+ __le32 next;
+ __le32 async_error_next;
+ u32 user_data;
+ __le32 pcl_status;
+ __le32 remaining_transfer_count;
+ __le32 next_data_buffer;
+ struct {
+ __le32 control;
+ __le32 pointer;
+ } buffer[13];
+};
+
+struct packet {
+ unsigned int length;
+ char data[0];
+};
+
+struct packet_buffer {
+ char *data;
+ size_t capacity;
+ long total_packet_count, lost_packet_count;
+ atomic_t size;
+ struct packet *head, *tail;
+ wait_queue_head_t wait;
+};
+
+struct pcilynx {
+ struct pci_dev *pci_device;
+ __iomem char *registers;
+
+ struct pcl *rcv_start_pcl, *rcv_pcl;
+ __le32 *rcv_buffer;
+
+ dma_addr_t rcv_start_pcl_bus, rcv_pcl_bus, rcv_buffer_bus;
+
+ spinlock_t client_list_lock;
+ struct list_head client_list;
+
+ struct miscdevice misc;
+ struct list_head link;
+ struct kref kref;
+};
+
+static inline struct pcilynx *
+lynx_get(struct pcilynx *lynx)
+{
+ kref_get(&lynx->kref);
+
+ return lynx;
+}
+
+static void
+lynx_release(struct kref *kref)
+{
+ kfree(container_of(kref, struct pcilynx, kref));
+}
+
+static inline void
+lynx_put(struct pcilynx *lynx)
+{
+ kref_put(&lynx->kref, lynx_release);
+}
+
+struct client {
+ struct pcilynx *lynx;
+ u32 tcode_mask;
+ struct packet_buffer buffer;
+ struct list_head link;
+};
+
+static DEFINE_MUTEX(card_mutex);
+static LIST_HEAD(card_list);
+
+static int
+packet_buffer_init(struct packet_buffer *buffer, size_t capacity)
+{
+ buffer->data = kmalloc(capacity, GFP_KERNEL);
+ if (buffer->data == NULL)
+ return -ENOMEM;
+ buffer->head = (struct packet *) buffer->data;
+ buffer->tail = (struct packet *) buffer->data;
+ buffer->capacity = capacity;
+ buffer->lost_packet_count = 0;
+ atomic_set(&buffer->size, 0);
+ init_waitqueue_head(&buffer->wait);
+
+ return 0;
+}
+
+static void
+packet_buffer_destroy(struct packet_buffer *buffer)
+{
+ kfree(buffer->data);
+}
+
+static int
+packet_buffer_get(struct client *client, char __user *data, size_t user_length)
+{
+ struct packet_buffer *buffer = &client->buffer;
+ size_t length;
+ char *end;
+
+ if (wait_event_interruptible(buffer->wait,
+ atomic_read(&buffer->size) > 0) ||
+ list_empty(&client->lynx->link))
+ return -ERESTARTSYS;
+
+ if (atomic_read(&buffer->size) == 0)
+ return -ENODEV;
+
+ /* FIXME: Check length <= user_length. */
+
+ end = buffer->data + buffer->capacity;
+ length = buffer->head->length;
+
+ if (&buffer->head->data[length] < end) {
+ if (copy_to_user(data, buffer->head->data, length))
+ return -EFAULT;
+ buffer->head = (struct packet *) &buffer->head->data[length];
+ } else {
+ size_t split = end - buffer->head->data;
+
+ if (copy_to_user(data, buffer->head->data, split))
+ return -EFAULT;
+ if (copy_to_user(data + split, buffer->data, length - split))
+ return -EFAULT;
+ buffer->head = (struct packet *) &buffer->data[length - split];
+ }
+
+ /*
+ * Decrease buffer->size as the last thing, since this is what
+ * keeps the interrupt from overwriting the packet we are
+ * retrieving from the buffer.
+ */
+ atomic_sub(sizeof(struct packet) + length, &buffer->size);
+
+ return length;
+}
+
+static void
+packet_buffer_put(struct packet_buffer *buffer, void *data, size_t length)
+{
+ char *end;
+
+ buffer->total_packet_count++;
+
+ if (buffer->capacity <
+ atomic_read(&buffer->size) + sizeof(struct packet) + length) {
+ buffer->lost_packet_count++;
+ return;
+ }
+
+ end = buffer->data + buffer->capacity;
+ buffer->tail->length = length;
+
+ if (&buffer->tail->data[length] < end) {
+ memcpy(buffer->tail->data, data, length);
+ buffer->tail = (struct packet *) &buffer->tail->data[length];
+ } else {
+ size_t split = end - buffer->tail->data;
+
+ memcpy(buffer->tail->data, data, split);
+ memcpy(buffer->data, data + split, length - split);
+ buffer->tail = (struct packet *) &buffer->data[length - split];
+ }
+
+ /* Finally, adjust buffer size and wake up userspace reader. */
+
+ atomic_add(sizeof(struct packet) + length, &buffer->size);
+ wake_up_interruptible(&buffer->wait);
+}
+
+static inline void
+reg_write(struct pcilynx *lynx, int offset, u32 data)
+{
+ writel(data, lynx->registers + offset);
+}
+
+static inline u32
+reg_read(struct pcilynx *lynx, int offset)
+{
+ return readl(lynx->registers + offset);
+}
+
+static inline void
+reg_set_bits(struct pcilynx *lynx, int offset, u32 mask)
+{
+ reg_write(lynx, offset, (reg_read(lynx, offset) | mask));
+}
+
+/*
+ * Maybe the pcl programs could be set up to just append data instead
+ * of using a whole packet.
+ */
+static inline void
+run_pcl(struct pcilynx *lynx, dma_addr_t pcl_bus,
+ int dmachan)
+{
+ reg_write(lynx, DMA0_CURRENT_PCL + dmachan * 0x20, pcl_bus);
+ reg_write(lynx, DMA0_CHAN_CTRL + dmachan * 0x20,
+ DMA_CHAN_CTRL_ENABLE | DMA_CHAN_CTRL_LINK);
+}
+
+static int
+set_phy_reg(struct pcilynx *lynx, int addr, int val)
+{
+ if (addr > 15) {
+ dev_err(&lynx->pci_device->dev,
+ "PHY register address %d out of range\n", addr);
+ return -1;
+ }
+ if (val > 0xff) {
+ dev_err(&lynx->pci_device->dev,
+ "PHY register value %d out of range\n", val);
+ return -1;
+ }
+ reg_write(lynx, LINK_PHY, LINK_PHY_WRITE |
+ LINK_PHY_ADDR(addr) | LINK_PHY_WDATA(val));
+
+ return 0;
+}
+
+static int
+nosy_open(struct inode *inode, struct file *file)
+{
+ int minor = iminor(inode);
+ struct client *client;
+ struct pcilynx *tmp, *lynx = NULL;
+
+ mutex_lock(&card_mutex);
+ list_for_each_entry(tmp, &card_list, link)
+ if (tmp->misc.minor == minor) {
+ lynx = lynx_get(tmp);
+ break;
+ }
+ mutex_unlock(&card_mutex);
+ if (lynx == NULL)
+ return -ENODEV;
+
+ client = kmalloc(sizeof *client, GFP_KERNEL);
+ if (client == NULL)
+ goto fail;
+
+ client->tcode_mask = ~0;
+ client->lynx = lynx;
+ INIT_LIST_HEAD(&client->link);
+
+ if (packet_buffer_init(&client->buffer, 128 * 1024) < 0)
+ goto fail;
+
+ file->private_data = client;
+
+ return 0;
+fail:
+ kfree(client);
+ lynx_put(lynx);
+
+ return -ENOMEM;
+}
+
+static int
+nosy_release(struct inode *inode, struct file *file)
+{
+ struct client *client = file->private_data;
+ struct pcilynx *lynx = client->lynx;
+
+ spin_lock_irq(&lynx->client_list_lock);
+ list_del_init(&client->link);
+ spin_unlock_irq(&lynx->client_list_lock);
+
+ packet_buffer_destroy(&client->buffer);
+ kfree(client);
+ lynx_put(lynx);
+
+ return 0;
+}
+
+static unsigned int
+nosy_poll(struct file *file, poll_table *pt)
+{
+ struct client *client = file->private_data;
+ unsigned int ret = 0;
+
+ poll_wait(file, &client->buffer.wait, pt);
+
+ if (atomic_read(&client->buffer.size) > 0)
+ ret = POLLIN | POLLRDNORM;
+
+ if (list_empty(&client->lynx->link))
+ ret |= POLLHUP;
+
+ return ret;
+}
+
+static ssize_t
+nosy_read(struct file *file, char __user *buffer, size_t count, loff_t *offset)
+{
+ struct client *client = file->private_data;
+
+ return packet_buffer_get(client, buffer, count);
+}
+
+static long
+nosy_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+ struct client *client = file->private_data;
+ spinlock_t *client_list_lock = &client->lynx->client_list_lock;
+ struct nosy_stats stats;
+
+ switch (cmd) {
+ case NOSY_IOC_GET_STATS:
+ spin_lock_irq(client_list_lock);
+ stats.total_packet_count = client->buffer.total_packet_count;
+ stats.lost_packet_count = client->buffer.lost_packet_count;
+ spin_unlock_irq(client_list_lock);
+
+ if (copy_to_user((void __user *) arg, &stats, sizeof stats))
+ return -EFAULT;
+ else
+ return 0;
+
+ case NOSY_IOC_START:
+ spin_lock_irq(client_list_lock);
+ list_add_tail(&client->link, &client->lynx->client_list);
+ spin_unlock_irq(client_list_lock);
+
+ return 0;
+
+ case NOSY_IOC_STOP:
+ spin_lock_irq(client_list_lock);
+ list_del_init(&client->link);
+ spin_unlock_irq(client_list_lock);
+
+ return 0;
+
+ case NOSY_IOC_FILTER:
+ spin_lock_irq(client_list_lock);
+ client->tcode_mask = arg;
+ spin_unlock_irq(client_list_lock);
+
+ return 0;
+
+ default:
+ return -EINVAL;
+ /* Flush buffer, configure filter. */
+ }
+}
+
+static const struct file_operations nosy_ops = {
+ .owner = THIS_MODULE,
+ .read = nosy_read,
+ .unlocked_ioctl = nosy_ioctl,
+ .poll = nosy_poll,
+ .open = nosy_open,
+ .release = nosy_release,
+};
+
+#define PHY_PACKET_SIZE 12 /* 1 payload, 1 inverse, 1 ack = 3 quadlets */
+
+static void
+packet_irq_handler(struct pcilynx *lynx)
+{
+ struct client *client;
+ u32 tcode_mask, tcode;
+ size_t length;
+ struct timeval tv;
+
+ /* FIXME: Also report rcv_speed. */
+
+ length = __le32_to_cpu(lynx->rcv_pcl->pcl_status) & 0x00001fff;
+ tcode = __le32_to_cpu(lynx->rcv_buffer[1]) >> 4 & 0xf;
+
+ do_gettimeofday(&tv);
+ lynx->rcv_buffer[0] = (__force __le32)tv.tv_usec;
+
+ if (length == PHY_PACKET_SIZE)
+ tcode_mask = 1 << TCODE_PHY_PACKET;
+ else
+ tcode_mask = 1 << tcode;
+
+ spin_lock(&lynx->client_list_lock);
+
+ list_for_each_entry(client, &lynx->client_list, link)
+ if (client->tcode_mask & tcode_mask)
+ packet_buffer_put(&client->buffer,
+ lynx->rcv_buffer, length + 4);
+
+ spin_unlock(&lynx->client_list_lock);
+}
+
+static void
+bus_reset_irq_handler(struct pcilynx *lynx)
+{
+ struct client *client;
+ struct timeval tv;
+
+ do_gettimeofday(&tv);
+
+ spin_lock(&lynx->client_list_lock);
+
+ list_for_each_entry(client, &lynx->client_list, link)
+ packet_buffer_put(&client->buffer, &tv.tv_usec, 4);
+
+ spin_unlock(&lynx->client_list_lock);
+}
+
+static irqreturn_t
+irq_handler(int irq, void *device)
+{
+ struct pcilynx *lynx = device;
+ u32 pci_int_status;
+
+ pci_int_status = reg_read(lynx, PCI_INT_STATUS);
+
+ if (pci_int_status == ~0)
+ /* Card was ejected. */
+ return IRQ_NONE;
+
+ if ((pci_int_status & PCI_INT_INT_PEND) == 0)
+ /* Not our interrupt, bail out quickly. */
+ return IRQ_NONE;
+
+ if ((pci_int_status & PCI_INT_P1394_INT) != 0) {
+ u32 link_int_status;
+
+ link_int_status = reg_read(lynx, LINK_INT_STATUS);
+ reg_write(lynx, LINK_INT_STATUS, link_int_status);
+
+ if ((link_int_status & LINK_INT_PHY_BUSRESET) > 0)
+ bus_reset_irq_handler(lynx);
+ }
+
+ /* Clear the PCI_INT_STATUS register only after clearing the
+ * LINK_INT_STATUS register; otherwise the PCI_INT_P1394 will
+ * be set again immediately. */
+
+ reg_write(lynx, PCI_INT_STATUS, pci_int_status);
+
+ if ((pci_int_status & PCI_INT_DMA0_HLT) > 0) {
+ packet_irq_handler(lynx);
+ run_pcl(lynx, lynx->rcv_start_pcl_bus, 0);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static void
+remove_card(struct pci_dev *dev)
+{
+ struct pcilynx *lynx = pci_get_drvdata(dev);
+ struct client *client;
+
+ mutex_lock(&card_mutex);
+ list_del_init(&lynx->link);
+ misc_deregister(&lynx->misc);
+ mutex_unlock(&card_mutex);
+
+ reg_write(lynx, PCI_INT_ENABLE, 0);
+ free_irq(lynx->pci_device->irq, lynx);
+
+ spin_lock_irq(&lynx->client_list_lock);
+ list_for_each_entry(client, &lynx->client_list, link)
+ wake_up_interruptible(&client->buffer.wait);
+ spin_unlock_irq(&lynx->client_list_lock);
+
+ pci_free_consistent(lynx->pci_device, sizeof(struct pcl),
+ lynx->rcv_start_pcl, lynx->rcv_start_pcl_bus);
+ pci_free_consistent(lynx->pci_device, sizeof(struct pcl),
+ lynx->rcv_pcl, lynx->rcv_pcl_bus);
+ pci_free_consistent(lynx->pci_device, PAGE_SIZE,
+ lynx->rcv_buffer, lynx->rcv_buffer_bus);
+
+ iounmap(lynx->registers);
+ pci_disable_device(dev);
+ lynx_put(lynx);
+}
+
+#define RCV_BUFFER_SIZE (16 * 1024)
+
+static int __devinit
+add_card(struct pci_dev *dev, const struct pci_device_id *unused)
+{
+ struct pcilynx *lynx;
+ u32 p, end;
+ int ret, i;
+
+ if (pci_set_dma_mask(dev, 0xffffffff)) {
+ dev_err(&dev->dev,
+ "DMA address limits not supported for PCILynx hardware\n");
+ return -ENXIO;
+ }
+ if (pci_enable_device(dev)) {
+ dev_err(&dev->dev, "Failed to enable PCILynx hardware\n");
+ return -ENXIO;
+ }
+ pci_set_master(dev);
+
+ lynx = kzalloc(sizeof *lynx, GFP_KERNEL);
+ if (lynx == NULL) {
+ dev_err(&dev->dev, "Failed to allocate control structure\n");
+ ret = -ENOMEM;
+ goto fail_disable;
+ }
+ lynx->pci_device = dev;
+ pci_set_drvdata(dev, lynx);
+
+ spin_lock_init(&lynx->client_list_lock);
+ INIT_LIST_HEAD(&lynx->client_list);
+ kref_init(&lynx->kref);
+
+ lynx->registers = ioremap_nocache(pci_resource_start(dev, 0),
+ PCILYNX_MAX_REGISTER);
+
+ lynx->rcv_start_pcl = pci_alloc_consistent(lynx->pci_device,
+ sizeof(struct pcl), &lynx->rcv_start_pcl_bus);
+ lynx->rcv_pcl = pci_alloc_consistent(lynx->pci_device,
+ sizeof(struct pcl), &lynx->rcv_pcl_bus);
+ lynx->rcv_buffer = pci_alloc_consistent(lynx->pci_device,
+ RCV_BUFFER_SIZE, &lynx->rcv_buffer_bus);
+ if (lynx->rcv_start_pcl == NULL ||
+ lynx->rcv_pcl == NULL ||
+ lynx->rcv_buffer == NULL) {
+ dev_err(&dev->dev, "Failed to allocate receive buffer\n");
+ ret = -ENOMEM;
+ goto fail_deallocate;
+ }
+ lynx->rcv_start_pcl->next = cpu_to_le32(lynx->rcv_pcl_bus);
+ lynx->rcv_pcl->next = cpu_to_le32(PCL_NEXT_INVALID);
+ lynx->rcv_pcl->async_error_next = cpu_to_le32(PCL_NEXT_INVALID);
+
+ lynx->rcv_pcl->buffer[0].control =
+ cpu_to_le32(PCL_CMD_RCV | PCL_BIGENDIAN | 2044);
+ lynx->rcv_pcl->buffer[0].pointer =
+ cpu_to_le32(lynx->rcv_buffer_bus + 4);
+ p = lynx->rcv_buffer_bus + 2048;
+ end = lynx->rcv_buffer_bus + RCV_BUFFER_SIZE;
+ for (i = 1; p < end; i++, p += 2048) {
+ lynx->rcv_pcl->buffer[i].control =
+ cpu_to_le32(PCL_CMD_RCV | PCL_BIGENDIAN | 2048);
+ lynx->rcv_pcl->buffer[i].pointer = cpu_to_le32(p);
+ }
+ lynx->rcv_pcl->buffer[i - 1].control |= cpu_to_le32(PCL_LAST_BUFF);
+
+ reg_set_bits(lynx, MISC_CONTROL, MISC_CONTROL_SWRESET);
+ /* Fix buggy cards with autoboot pin not tied low: */
+ reg_write(lynx, DMA0_CHAN_CTRL, 0);
+ reg_write(lynx, DMA_GLOBAL_REGISTER, 0x00 << 24);
+
+#if 0
+ /* now, looking for PHY register set */
+ if ((get_phy_reg(lynx, 2) & 0xe0) == 0xe0) {
+ lynx->phyic.reg_1394a = 1;
+ PRINT(KERN_INFO, lynx->id,
+ "found 1394a conform PHY (using extended register set)");
+ lynx->phyic.vendor = get_phy_vendorid(lynx);
+ lynx->phyic.product = get_phy_productid(lynx);
+ } else {
+ lynx->phyic.reg_1394a = 0;
+ PRINT(KERN_INFO, lynx->id, "found old 1394 PHY");
+ }
+#endif
+
+ /* Setup the general receive FIFO max size. */
+ reg_write(lynx, FIFO_SIZES, 255);
+
+ reg_set_bits(lynx, PCI_INT_ENABLE, PCI_INT_DMA_ALL);
+
+ reg_write(lynx, LINK_INT_ENABLE,
+ LINK_INT_PHY_TIME_OUT | LINK_INT_PHY_REG_RCVD |
+ LINK_INT_PHY_BUSRESET | LINK_INT_IT_STUCK |
+ LINK_INT_AT_STUCK | LINK_INT_SNTRJ |
+ LINK_INT_TC_ERR | LINK_INT_GRF_OVER_FLOW |
+ LINK_INT_ITF_UNDER_FLOW | LINK_INT_ATF_UNDER_FLOW);
+
+ /* Disable the L flag in self ID packets. */
+ set_phy_reg(lynx, 4, 0);
+
+ /* Put this baby into snoop mode */
+ reg_set_bits(lynx, LINK_CONTROL, LINK_CONTROL_SNOOP_ENABLE);
+
+ run_pcl(lynx, lynx->rcv_start_pcl_bus, 0);
+
+ if (request_irq(dev->irq, irq_handler, IRQF_SHARED,
+ driver_name, lynx)) {
+ dev_err(&dev->dev,
+ "Failed to allocate shared interrupt %d\n", dev->irq);
+ ret = -EIO;
+ goto fail_deallocate;
+ }
+
+ lynx->misc.parent = &dev->dev;
+ lynx->misc.minor = MISC_DYNAMIC_MINOR;
+ lynx->misc.name = "nosy";
+ lynx->misc.fops = &nosy_ops;
+
+ mutex_lock(&card_mutex);
+ ret = misc_register(&lynx->misc);
+ if (ret) {
+ dev_err(&dev->dev, "Failed to register misc char device\n");
+ mutex_unlock(&card_mutex);
+ goto fail_free_irq;
+ }
+ list_add_tail(&lynx->link, &card_list);
+ mutex_unlock(&card_mutex);
+
+ dev_info(&dev->dev,
+ "Initialized PCILynx IEEE1394 card, irq=%d\n", dev->irq);
+
+ return 0;
+
+fail_free_irq:
+ reg_write(lynx, PCI_INT_ENABLE, 0);
+ free_irq(lynx->pci_device->irq, lynx);
+
+fail_deallocate:
+ if (lynx->rcv_start_pcl)
+ pci_free_consistent(lynx->pci_device, sizeof(struct pcl),
+ lynx->rcv_start_pcl, lynx->rcv_start_pcl_bus);
+ if (lynx->rcv_pcl)
+ pci_free_consistent(lynx->pci_device, sizeof(struct pcl),
+ lynx->rcv_pcl, lynx->rcv_pcl_bus);
+ if (lynx->rcv_buffer)
+ pci_free_consistent(lynx->pci_device, PAGE_SIZE,
+ lynx->rcv_buffer, lynx->rcv_buffer_bus);
+ iounmap(lynx->registers);
+ kfree(lynx);
+
+fail_disable:
+ pci_disable_device(dev);
+
+ return ret;
+}
+
+static struct pci_device_id pci_table[] __devinitdata = {
+ {
+ .vendor = PCI_VENDOR_ID_TI,
+ .device = PCI_DEVICE_ID_TI_PCILYNX,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ },
+ { } /* Terminating entry */
+};
+
+static struct pci_driver lynx_pci_driver = {
+ .name = driver_name,
+ .id_table = pci_table,
+ .probe = add_card,
+ .remove = remove_card,
+};
+
+MODULE_AUTHOR("Kristian Hoegsberg");
+MODULE_DESCRIPTION("Snoop mode driver for TI pcilynx 1394 controllers");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(pci, pci_table);
+
+static int __init nosy_init(void)
+{
+ return pci_register_driver(&lynx_pci_driver);
+}
+
+static void __exit nosy_cleanup(void)
+{
+ pci_unregister_driver(&lynx_pci_driver);
+
+ pr_info("Unloaded %s\n", driver_name);
+}
+
+module_init(nosy_init);
+module_exit(nosy_cleanup);
diff --git a/drivers/firewire/nosy.h b/drivers/firewire/nosy.h
new file mode 100644
index 00000000000..078ff27f475
--- /dev/null
+++ b/drivers/firewire/nosy.h
@@ -0,0 +1,237 @@
+/*
+ * Chip register definitions for PCILynx chipset. Based on pcilynx.h
+ * from the Linux 1394 drivers, but modified a bit so the names here
+ * match the specification exactly (even though they have weird names,
+ * like xxx_OVER_FLOW, or arbitrary abbreviations like SNTRJ for "sent
+ * reject" etc.)
+ */
+
+#define PCILYNX_MAX_REGISTER 0xfff
+#define PCILYNX_MAX_MEMORY 0xffff
+
+#define PCI_LATENCY_CACHELINE 0x0c
+
+#define MISC_CONTROL 0x40
+#define MISC_CONTROL_SWRESET (1<<0)
+
+#define SERIAL_EEPROM_CONTROL 0x44
+
+#define PCI_INT_STATUS 0x48
+#define PCI_INT_ENABLE 0x4c
+/* status and enable have identical bit numbers */
+#define PCI_INT_INT_PEND (1<<31)
+#define PCI_INT_FRC_INT (1<<30)
+#define PCI_INT_SLV_ADR_PERR (1<<28)
+#define PCI_INT_SLV_DAT_PERR (1<<27)
+#define PCI_INT_MST_DAT_PERR (1<<26)
+#define PCI_INT_MST_DEV_TO (1<<25)
+#define PCI_INT_INT_SLV_TO (1<<23)
+#define PCI_INT_AUX_TO (1<<18)
+#define PCI_INT_AUX_INT (1<<17)
+#define PCI_INT_P1394_INT (1<<16)
+#define PCI_INT_DMA4_PCL (1<<9)
+#define PCI_INT_DMA4_HLT (1<<8)
+#define PCI_INT_DMA3_PCL (1<<7)
+#define PCI_INT_DMA3_HLT (1<<6)
+#define PCI_INT_DMA2_PCL (1<<5)
+#define PCI_INT_DMA2_HLT (1<<4)
+#define PCI_INT_DMA1_PCL (1<<3)
+#define PCI_INT_DMA1_HLT (1<<2)
+#define PCI_INT_DMA0_PCL (1<<1)
+#define PCI_INT_DMA0_HLT (1<<0)
+/* all DMA interrupts combined: */
+#define PCI_INT_DMA_ALL 0x3ff
+
+#define PCI_INT_DMA_HLT(chan) (1 << (chan * 2))
+#define PCI_INT_DMA_PCL(chan) (1 << (chan * 2 + 1))
+
+#define LBUS_ADDR 0xb4
+#define LBUS_ADDR_SEL_RAM (0x0<<16)
+#define LBUS_ADDR_SEL_ROM (0x1<<16)
+#define LBUS_ADDR_SEL_AUX (0x2<<16)
+#define LBUS_ADDR_SEL_ZV (0x3<<16)
+
+#define GPIO_CTRL_A 0xb8
+#define GPIO_CTRL_B 0xbc
+#define GPIO_DATA_BASE 0xc0
+
+#define DMA_BREG(base, chan) (base + chan * 0x20)
+#define DMA_SREG(base, chan) (base + chan * 0x10)
+
+#define PCL_NEXT_INVALID (1<<0)
+
+/* transfer commands */
+#define PCL_CMD_RCV (0x1<<24)
+#define PCL_CMD_RCV_AND_UPDATE (0xa<<24)
+#define PCL_CMD_XMT (0x2<<24)
+#define PCL_CMD_UNFXMT (0xc<<24)
+#define PCL_CMD_PCI_TO_LBUS (0x8<<24)
+#define PCL_CMD_LBUS_TO_PCI (0x9<<24)
+
+/* aux commands */
+#define PCL_CMD_NOP (0x0<<24)
+#define PCL_CMD_LOAD (0x3<<24)
+#define PCL_CMD_STOREQ (0x4<<24)
+#define PCL_CMD_STORED (0xb<<24)
+#define PCL_CMD_STORE0 (0x5<<24)
+#define PCL_CMD_STORE1 (0x6<<24)
+#define PCL_CMD_COMPARE (0xe<<24)
+#define PCL_CMD_SWAP_COMPARE (0xf<<24)
+#define PCL_CMD_ADD (0xd<<24)
+#define PCL_CMD_BRANCH (0x7<<24)
+
+/* BRANCH condition codes */
+#define PCL_COND_DMARDY_SET (0x1<<20)
+#define PCL_COND_DMARDY_CLEAR (0x2<<20)
+
+#define PCL_GEN_INTR (1<<19)
+#define PCL_LAST_BUFF (1<<18)
+#define PCL_LAST_CMD (PCL_LAST_BUFF)
+#define PCL_WAITSTAT (1<<17)
+#define PCL_BIGENDIAN (1<<16)
+#define PCL_ISOMODE (1<<12)
+
+#define DMA0_PREV_PCL 0x100
+#define DMA1_PREV_PCL 0x120
+#define DMA2_PREV_PCL 0x140
+#define DMA3_PREV_PCL 0x160
+#define DMA4_PREV_PCL 0x180
+#define DMA_PREV_PCL(chan) (DMA_BREG(DMA0_PREV_PCL, chan))
+
+#define DMA0_CURRENT_PCL 0x104
+#define DMA1_CURRENT_PCL 0x124
+#define DMA2_CURRENT_PCL 0x144
+#define DMA3_CURRENT_PCL 0x164
+#define DMA4_CURRENT_PCL 0x184
+#define DMA_CURRENT_PCL(chan) (DMA_BREG(DMA0_CURRENT_PCL, chan))
+
+#define DMA0_CHAN_STAT 0x10c
+#define DMA1_CHAN_STAT 0x12c
+#define DMA2_CHAN_STAT 0x14c
+#define DMA3_CHAN_STAT 0x16c
+#define DMA4_CHAN_STAT 0x18c
+#define DMA_CHAN_STAT(chan) (DMA_BREG(DMA0_CHAN_STAT, chan))
+/* CHAN_STATUS registers share bits */
+#define DMA_CHAN_STAT_SELFID (1<<31)
+#define DMA_CHAN_STAT_ISOPKT (1<<30)
+#define DMA_CHAN_STAT_PCIERR (1<<29)
+#define DMA_CHAN_STAT_PKTERR (1<<28)
+#define DMA_CHAN_STAT_PKTCMPL (1<<27)
+#define DMA_CHAN_STAT_SPECIALACK (1<<14)
+
+#define DMA0_CHAN_CTRL 0x110
+#define DMA1_CHAN_CTRL 0x130
+#define DMA2_CHAN_CTRL 0x150
+#define DMA3_CHAN_CTRL 0x170
+#define DMA4_CHAN_CTRL 0x190
+#define DMA_CHAN_CTRL(chan) (DMA_BREG(DMA0_CHAN_CTRL, chan))
+/* CHAN_CTRL registers share bits */
+#define DMA_CHAN_CTRL_ENABLE (1<<31)
+#define DMA_CHAN_CTRL_BUSY (1<<30)
+#define DMA_CHAN_CTRL_LINK (1<<29)
+
+#define DMA0_READY 0x114
+#define DMA1_READY 0x134
+#define DMA2_READY 0x154
+#define DMA3_READY 0x174
+#define DMA4_READY 0x194
+#define DMA_READY(chan) (DMA_BREG(DMA0_READY, chan))
+
+#define DMA_GLOBAL_REGISTER 0x908
+
+#define FIFO_SIZES 0xa00
+
+#define FIFO_CONTROL 0xa10
+#define FIFO_CONTROL_GRF_FLUSH (1<<4)
+#define FIFO_CONTROL_ITF_FLUSH (1<<3)
+#define FIFO_CONTROL_ATF_FLUSH (1<<2)
+
+#define FIFO_XMIT_THRESHOLD 0xa14
+
+#define DMA0_WORD0_CMP_VALUE 0xb00
+#define DMA1_WORD0_CMP_VALUE 0xb10
+#define DMA2_WORD0_CMP_VALUE 0xb20
+#define DMA3_WORD0_CMP_VALUE 0xb30
+#define DMA4_WORD0_CMP_VALUE 0xb40
+#define DMA_WORD0_CMP_VALUE(chan) (DMA_SREG(DMA0_WORD0_CMP_VALUE, chan))
+
+#define DMA0_WORD0_CMP_ENABLE 0xb04
+#define DMA1_WORD0_CMP_ENABLE 0xb14
+#define DMA2_WORD0_CMP_ENABLE 0xb24
+#define DMA3_WORD0_CMP_ENABLE 0xb34
+#define DMA4_WORD0_CMP_ENABLE 0xb44
+#define DMA_WORD0_CMP_ENABLE(chan) (DMA_SREG(DMA0_WORD0_CMP_ENABLE, chan))
+
+#define DMA0_WORD1_CMP_VALUE 0xb08
+#define DMA1_WORD1_CMP_VALUE 0xb18
+#define DMA2_WORD1_CMP_VALUE 0xb28
+#define DMA3_WORD1_CMP_VALUE 0xb38
+#define DMA4_WORD1_CMP_VALUE 0xb48
+#define DMA_WORD1_CMP_VALUE(chan) (DMA_SREG(DMA0_WORD1_CMP_VALUE, chan))
+
+#define DMA0_WORD1_CMP_ENABLE 0xb0c
+#define DMA1_WORD1_CMP_ENABLE 0xb1c
+#define DMA2_WORD1_CMP_ENABLE 0xb2c
+#define DMA3_WORD1_CMP_ENABLE 0xb3c
+#define DMA4_WORD1_CMP_ENABLE 0xb4c
+#define DMA_WORD1_CMP_ENABLE(chan) (DMA_SREG(DMA0_WORD1_CMP_ENABLE, chan))
+/* word 1 compare enable flags */
+#define DMA_WORD1_CMP_MATCH_OTHERBUS (1<<15)
+#define DMA_WORD1_CMP_MATCH_BROADCAST (1<<14)
+#define DMA_WORD1_CMP_MATCH_BUS_BCAST (1<<13)
+#define DMA_WORD1_CMP_MATCH_LOCAL_NODE (1<<12)
+#define DMA_WORD1_CMP_MATCH_EXACT (1<<11)
+#define DMA_WORD1_CMP_ENABLE_SELF_ID (1<<10)
+#define DMA_WORD1_CMP_ENABLE_MASTER (1<<8)
+
+#define LINK_ID 0xf00
+#define LINK_ID_BUS(id) (id<<22)
+#define LINK_ID_NODE(id) (id<<16)
+
+#define LINK_CONTROL 0xf04
+#define LINK_CONTROL_BUSY (1<<29)
+#define LINK_CONTROL_TX_ISO_EN (1<<26)
+#define LINK_CONTROL_RX_ISO_EN (1<<25)
+#define LINK_CONTROL_TX_ASYNC_EN (1<<24)
+#define LINK_CONTROL_RX_ASYNC_EN (1<<23)
+#define LINK_CONTROL_RESET_TX (1<<21)
+#define LINK_CONTROL_RESET_RX (1<<20)
+#define LINK_CONTROL_CYCMASTER (1<<11)
+#define LINK_CONTROL_CYCSOURCE (1<<10)
+#define LINK_CONTROL_CYCTIMEREN (1<<9)
+#define LINK_CONTROL_RCV_CMP_VALID (1<<7)
+#define LINK_CONTROL_SNOOP_ENABLE (1<<6)
+
+#define CYCLE_TIMER 0xf08
+
+#define LINK_PHY 0xf0c
+#define LINK_PHY_READ (1<<31)
+#define LINK_PHY_WRITE (1<<30)
+#define LINK_PHY_ADDR(addr) (addr<<24)
+#define LINK_PHY_WDATA(data) (data<<16)
+#define LINK_PHY_RADDR(addr) (addr<<8)
+
+#define LINK_INT_STATUS 0xf14
+#define LINK_INT_ENABLE 0xf18
+/* status and enable have identical bit numbers */
+#define LINK_INT_LINK_INT (1<<31)
+#define LINK_INT_PHY_TIME_OUT (1<<30)
+#define LINK_INT_PHY_REG_RCVD (1<<29)
+#define LINK_INT_PHY_BUSRESET (1<<28)
+#define LINK_INT_TX_RDY (1<<26)
+#define LINK_INT_RX_DATA_RDY (1<<25)
+#define LINK_INT_IT_STUCK (1<<20)
+#define LINK_INT_AT_STUCK (1<<19)
+#define LINK_INT_SNTRJ (1<<17)
+#define LINK_INT_HDR_ERR (1<<16)
+#define LINK_INT_TC_ERR (1<<15)
+#define LINK_INT_CYC_SEC (1<<11)
+#define LINK_INT_CYC_STRT (1<<10)
+#define LINK_INT_CYC_DONE (1<<9)
+#define LINK_INT_CYC_PEND (1<<8)
+#define LINK_INT_CYC_LOST (1<<7)
+#define LINK_INT_CYC_ARB_FAILED (1<<6)
+#define LINK_INT_GRF_OVER_FLOW (1<<5)
+#define LINK_INT_ITF_UNDER_FLOW (1<<4)
+#define LINK_INT_ATF_UNDER_FLOW (1<<3)
+#define LINK_INT_IARB_FAILED (1<<0)
diff --git a/drivers/firewire/ohci.c b/drivers/firewire/ohci.c
index 9f627e758cf..7f03540cabe 100644
--- a/drivers/firewire/ohci.c
+++ b/drivers/firewire/ohci.c
@@ -18,6 +18,7 @@
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
+#include <linux/bug.h>
#include <linux/compiler.h>
#include <linux/delay.h>
#include <linux/device.h>
@@ -32,11 +33,13 @@
#include <linux/mm.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
+#include <linux/mutex.h>
#include <linux/pci.h>
#include <linux/pci_ids.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/string.h>
+#include <linux/time.h>
#include <asm/byteorder.h>
#include <asm/page.h>
@@ -170,6 +173,10 @@ struct fw_ohci {
int generation;
int request_generation; /* for timestamping incoming requests */
unsigned quirks;
+ unsigned int pri_req_max;
+ u32 bus_time;
+ bool is_root;
+ bool csr_state_setclear_abdicate;
/*
* Spinlock for accessing fw_ohci data. Never call out of
@@ -177,16 +184,20 @@ struct fw_ohci {
*/
spinlock_t lock;
+ struct mutex phy_reg_mutex;
+
struct ar_context ar_request_ctx;
struct ar_context ar_response_ctx;
struct context at_request_ctx;
struct context at_response_ctx;
- u32 it_context_mask;
+ u32 it_context_mask; /* unoccupied IT contexts */
struct iso_context *it_context_list;
- u64 ir_context_channels;
- u32 ir_context_mask;
+ u64 ir_context_channels; /* unoccupied channels */
+ u32 ir_context_mask; /* unoccupied IR contexts */
struct iso_context *ir_context_list;
+ u64 mc_channels; /* channels in use by the multichannel IR context */
+ bool mc_allocated;
__be32 *config_rom;
dma_addr_t config_rom_bus;
@@ -231,12 +242,14 @@ static inline struct fw_ohci *fw_ohci(struct fw_card *card)
static char ohci_driver_name[] = KBUILD_MODNAME;
+#define PCI_DEVICE_ID_JMICRON_JMB38X_FW 0x2380
#define PCI_DEVICE_ID_TI_TSB12LV22 0x8009
#define QUIRK_CYCLE_TIMER 1
#define QUIRK_RESET_PACKET 2
#define QUIRK_BE_HEADERS 4
#define QUIRK_NO_1394A 8
+#define QUIRK_NO_MSI 16
/* In case of multiple matches in ohci_quirks[], only the first one is used. */
static const struct {
@@ -247,6 +260,7 @@ static const struct {
QUIRK_NO_1394A},
{PCI_VENDOR_ID_TI, PCI_ANY_ID, QUIRK_RESET_PACKET},
{PCI_VENDOR_ID_AL, PCI_ANY_ID, QUIRK_CYCLE_TIMER},
+ {PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB38X_FW, QUIRK_NO_MSI},
{PCI_VENDOR_ID_NEC, PCI_ANY_ID, QUIRK_CYCLE_TIMER},
{PCI_VENDOR_ID_VIA, PCI_ANY_ID, QUIRK_CYCLE_TIMER},
{PCI_VENDOR_ID_APPLE, PCI_DEVICE_ID_APPLE_UNI_N_FW, QUIRK_BE_HEADERS},
@@ -260,6 +274,7 @@ MODULE_PARM_DESC(quirks, "Chip quirks (default = 0"
", reset packet generation = " __stringify(QUIRK_RESET_PACKET)
", AR/selfID endianess = " __stringify(QUIRK_BE_HEADERS)
", no 1394a enhancements = " __stringify(QUIRK_NO_1394A)
+ ", disable MSI = " __stringify(QUIRK_NO_MSI)
")");
#define OHCI_PARAM_DEBUG_AT_AR 1
@@ -288,7 +303,7 @@ static void log_irqs(u32 evt)
!(evt & OHCI1394_busReset))
return;
- fw_notify("IRQ %08x%s%s%s%s%s%s%s%s%s%s%s%s%s\n", evt,
+ fw_notify("IRQ %08x%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n", evt,
evt & OHCI1394_selfIDComplete ? " selfID" : "",
evt & OHCI1394_RQPkt ? " AR_req" : "",
evt & OHCI1394_RSPkt ? " AR_resp" : "",
@@ -298,6 +313,7 @@ static void log_irqs(u32 evt)
evt & OHCI1394_isochTx ? " IT" : "",
evt & OHCI1394_postedWriteErr ? " postedWriteErr" : "",
evt & OHCI1394_cycleTooLong ? " cycleTooLong" : "",
+ evt & OHCI1394_cycle64Seconds ? " cycle64Seconds" : "",
evt & OHCI1394_cycleInconsistent ? " cycleInconsistent" : "",
evt & OHCI1394_regAccessFail ? " regAccessFail" : "",
evt & OHCI1394_busReset ? " busReset" : "",
@@ -305,7 +321,8 @@ static void log_irqs(u32 evt)
OHCI1394_RSPkt | OHCI1394_reqTxComplete |
OHCI1394_respTxComplete | OHCI1394_isochRx |
OHCI1394_isochTx | OHCI1394_postedWriteErr |
- OHCI1394_cycleTooLong | OHCI1394_cycleInconsistent |
+ OHCI1394_cycleTooLong | OHCI1394_cycle64Seconds |
+ OHCI1394_cycleInconsistent |
OHCI1394_regAccessFail | OHCI1394_busReset)
? " ?" : "");
}
@@ -470,12 +487,17 @@ static int read_phy_reg(struct fw_ohci *ohci, int addr)
int i;
reg_write(ohci, OHCI1394_PhyControl, OHCI1394_PhyControl_Read(addr));
- for (i = 0; i < 10; i++) {
+ for (i = 0; i < 3 + 100; i++) {
val = reg_read(ohci, OHCI1394_PhyControl);
if (val & OHCI1394_PhyControl_ReadDone)
return OHCI1394_PhyControl_ReadData(val);
- msleep(1);
+ /*
+ * Try a few times without waiting. Sleeping is necessary
+ * only when the link/PHY interface is busy.
+ */
+ if (i >= 3)
+ msleep(1);
}
fw_error("failed to read phy reg\n");
@@ -488,25 +510,23 @@ static int write_phy_reg(const struct fw_ohci *ohci, int addr, u32 val)
reg_write(ohci, OHCI1394_PhyControl,
OHCI1394_PhyControl_Write(addr, val));
- for (i = 0; i < 100; i++) {
+ for (i = 0; i < 3 + 100; i++) {
val = reg_read(ohci, OHCI1394_PhyControl);
if (!(val & OHCI1394_PhyControl_WritePending))
return 0;
- msleep(1);
+ if (i >= 3)
+ msleep(1);
}
fw_error("failed to write phy reg\n");
return -EBUSY;
}
-static int ohci_update_phy_reg(struct fw_card *card, int addr,
- int clear_bits, int set_bits)
+static int update_phy_reg(struct fw_ohci *ohci, int addr,
+ int clear_bits, int set_bits)
{
- struct fw_ohci *ohci = fw_ohci(card);
- int ret;
-
- ret = read_phy_reg(ohci, addr);
+ int ret = read_phy_reg(ohci, addr);
if (ret < 0)
return ret;
@@ -524,13 +544,38 @@ static int read_paged_phy_reg(struct fw_ohci *ohci, int page, int addr)
{
int ret;
- ret = ohci_update_phy_reg(&ohci->card, 7, PHY_PAGE_SELECT, page << 5);
+ ret = update_phy_reg(ohci, 7, PHY_PAGE_SELECT, page << 5);
if (ret < 0)
return ret;
return read_phy_reg(ohci, addr);
}
+static int ohci_read_phy_reg(struct fw_card *card, int addr)
+{
+ struct fw_ohci *ohci = fw_ohci(card);
+ int ret;
+
+ mutex_lock(&ohci->phy_reg_mutex);
+ ret = read_phy_reg(ohci, addr);
+ mutex_unlock(&ohci->phy_reg_mutex);
+
+ return ret;
+}
+
+static int ohci_update_phy_reg(struct fw_card *card, int addr,
+ int clear_bits, int set_bits)
+{
+ struct fw_ohci *ohci = fw_ohci(card);
+ int ret;
+
+ mutex_lock(&ohci->phy_reg_mutex);
+ ret = update_phy_reg(ohci, addr, clear_bits, set_bits);
+ mutex_unlock(&ohci->phy_reg_mutex);
+
+ return ret;
+}
+
static int ar_context_add_page(struct ar_context *ctx)
{
struct device *dev = ctx->ohci->card.device;
@@ -553,6 +598,7 @@ static int ar_context_add_page(struct ar_context *ctx)
ab->descriptor.res_count = cpu_to_le16(PAGE_SIZE - offset);
ab->descriptor.branch_address = 0;
+ wmb(); /* finish init of new descriptors before branch_address update */
ctx->last_buffer->descriptor.branch_address = cpu_to_le32(ab_bus | 1);
ctx->last_buffer->next = ab;
ctx->last_buffer = ab;
@@ -940,6 +986,8 @@ static void context_append(struct context *ctx,
d_bus = desc->buffer_bus + (d - desc->buffer) * sizeof(*d);
desc->used += (z + extra) * sizeof(*d);
+
+ wmb(); /* finish init of new descriptors before branch_address update */
ctx->prev->branch_address = cpu_to_le32(d_bus | z);
ctx->prev = find_branch_descriptor(d, z);
@@ -1026,6 +1074,9 @@ static int at_context_queue_packet(struct context *ctx,
header[1] = cpu_to_le32(packet->header[0]);
header[2] = cpu_to_le32(packet->header[1]);
d[0].req_count = cpu_to_le16(12);
+
+ if (is_ping_packet(packet->header))
+ d[0].control |= cpu_to_le16(DESCRIPTOR_PING);
break;
case 4:
@@ -1311,6 +1362,78 @@ static void at_context_transmit(struct context *ctx, struct fw_packet *packet)
}
+static u32 cycle_timer_ticks(u32 cycle_timer)
+{
+ u32 ticks;
+
+ ticks = cycle_timer & 0xfff;
+ ticks += 3072 * ((cycle_timer >> 12) & 0x1fff);
+ ticks += (3072 * 8000) * (cycle_timer >> 25);
+
+ return ticks;
+}
+
+/*
+ * Some controllers exhibit one or more of the following bugs when updating the
+ * iso cycle timer register:
+ * - When the lowest six bits are wrapping around to zero, a read that happens
+ * at the same time will return garbage in the lowest ten bits.
+ * - When the cycleOffset field wraps around to zero, the cycleCount field is
+ * not incremented for about 60 ns.
+ * - Occasionally, the entire register reads zero.
+ *
+ * To catch these, we read the register three times and ensure that the
+ * difference between each two consecutive reads is approximately the same, i.e.
+ * less than twice the other. Furthermore, any negative difference indicates an
+ * error. (A PCI read should take at least 20 ticks of the 24.576 MHz timer to
+ * execute, so we have enough precision to compute the ratio of the differences.)
+ */
+static u32 get_cycle_time(struct fw_ohci *ohci)
+{
+ u32 c0, c1, c2;
+ u32 t0, t1, t2;
+ s32 diff01, diff12;
+ int i;
+
+ c2 = reg_read(ohci, OHCI1394_IsochronousCycleTimer);
+
+ if (ohci->quirks & QUIRK_CYCLE_TIMER) {
+ i = 0;
+ c1 = c2;
+ c2 = reg_read(ohci, OHCI1394_IsochronousCycleTimer);
+ do {
+ c0 = c1;
+ c1 = c2;
+ c2 = reg_read(ohci, OHCI1394_IsochronousCycleTimer);
+ t0 = cycle_timer_ticks(c0);
+ t1 = cycle_timer_ticks(c1);
+ t2 = cycle_timer_ticks(c2);
+ diff01 = t1 - t0;
+ diff12 = t2 - t1;
+ } while ((diff01 <= 0 || diff12 <= 0 ||
+ diff01 / diff12 >= 2 || diff12 / diff01 >= 2)
+ && i++ < 20);
+ }
+
+ return c2;
+}
+
+/*
+ * This function has to be called at least every 64 seconds. The bus_time
+ * field stores not only the upper 25 bits of the BUS_TIME register but also
+ * the most significant bit of the cycle timer in bit 6 so that we can detect
+ * changes in this bit.
+ */
+static u32 update_bus_time(struct fw_ohci *ohci)
+{
+ u32 cycle_time_seconds = get_cycle_time(ohci) >> 25;
+
+ if ((ohci->bus_time & 0x40) != (cycle_time_seconds & 0x40))
+ ohci->bus_time += 0x40;
+
+ return ohci->bus_time | cycle_time_seconds;
+}
+
static void bus_reset_tasklet(unsigned long data)
{
struct fw_ohci *ohci = (struct fw_ohci *)data;
@@ -1319,6 +1442,7 @@ static void bus_reset_tasklet(unsigned long data)
unsigned long flags;
void *free_rom = NULL;
dma_addr_t free_rom_bus = 0;
+ bool is_new_root;
reg = reg_read(ohci, OHCI1394_NodeID);
if (!(reg & OHCI1394_NodeID_idValid)) {
@@ -1332,6 +1456,12 @@ static void bus_reset_tasklet(unsigned long data)
ohci->node_id = reg & (OHCI1394_NodeID_busNumber |
OHCI1394_NodeID_nodeNumber);
+ is_new_root = (reg & OHCI1394_NodeID_root) != 0;
+ if (!(ohci->is_root && is_new_root))
+ reg_write(ohci, OHCI1394_LinkControlSet,
+ OHCI1394_LinkControl_cycleMaster);
+ ohci->is_root = is_new_root;
+
reg = reg_read(ohci, OHCI1394_SelfIDCount);
if (reg & OHCI1394_SelfIDCount_selfIDError) {
fw_notify("inconsistent self IDs\n");
@@ -1439,7 +1569,9 @@ static void bus_reset_tasklet(unsigned long data)
self_id_count, ohci->self_id_buffer);
fw_core_handle_bus_reset(&ohci->card, ohci->node_id, generation,
- self_id_count, ohci->self_id_buffer);
+ self_id_count, ohci->self_id_buffer,
+ ohci->csr_state_setclear_abdicate);
+ ohci->csr_state_setclear_abdicate = false;
}
static irqreturn_t irq_handler(int irq, void *data)
@@ -1515,6 +1647,12 @@ static irqreturn_t irq_handler(int irq, void *data)
fw_notify("isochronous cycle inconsistent\n");
}
+ if (event & OHCI1394_cycle64Seconds) {
+ spin_lock(&ohci->lock);
+ update_bus_time(ohci);
+ spin_unlock(&ohci->lock);
+ }
+
return IRQ_HANDLED;
}
@@ -1577,7 +1715,7 @@ static int configure_1394a_enhancements(struct fw_ohci *ohci)
clear = PHY_ENABLE_ACCEL | PHY_ENABLE_MULTI;
set = 0;
}
- ret = ohci_update_phy_reg(&ohci->card, 5, clear, set);
+ ret = update_phy_reg(ohci, 5, clear, set);
if (ret < 0)
return ret;
@@ -1599,7 +1737,7 @@ static int ohci_enable(struct fw_card *card,
{
struct fw_ohci *ohci = fw_ohci(card);
struct pci_dev *dev = to_pci_dev(card->device);
- u32 lps;
+ u32 lps, seconds, version, irqs;
int i, ret;
if (software_reset(ohci)) {
@@ -1635,17 +1773,34 @@ static int ohci_enable(struct fw_card *card,
OHCI1394_HCControl_noByteSwapData);
reg_write(ohci, OHCI1394_SelfIDBuffer, ohci->self_id_bus);
- reg_write(ohci, OHCI1394_LinkControlClear,
- OHCI1394_LinkControl_rcvPhyPkt);
reg_write(ohci, OHCI1394_LinkControlSet,
OHCI1394_LinkControl_rcvSelfID |
+ OHCI1394_LinkControl_rcvPhyPkt |
OHCI1394_LinkControl_cycleTimerEnable |
OHCI1394_LinkControl_cycleMaster);
reg_write(ohci, OHCI1394_ATRetries,
OHCI1394_MAX_AT_REQ_RETRIES |
(OHCI1394_MAX_AT_RESP_RETRIES << 4) |
- (OHCI1394_MAX_PHYS_RESP_RETRIES << 8));
+ (OHCI1394_MAX_PHYS_RESP_RETRIES << 8) |
+ (200 << 16));
+
+ seconds = lower_32_bits(get_seconds());
+ reg_write(ohci, OHCI1394_IsochronousCycleTimer, seconds << 25);
+ ohci->bus_time = seconds & ~0x3f;
+
+ version = reg_read(ohci, OHCI1394_Version) & 0x00ff00ff;
+ if (version >= OHCI_VERSION_1_1) {
+ reg_write(ohci, OHCI1394_InitialChannelsAvailableHi,
+ 0xfffffffe);
+ card->broadcast_channel_auto_allocated = true;
+ }
+
+ /* Get implemented bits of the priority arbitration request counter. */
+ reg_write(ohci, OHCI1394_FairnessControl, 0x3f);
+ ohci->pri_req_max = reg_read(ohci, OHCI1394_FairnessControl) & 0x3f;
+ reg_write(ohci, OHCI1394_FairnessControl, 0);
+ card->priority_budget_implemented = ohci->pri_req_max != 0;
ar_context_run(&ohci->ar_request_ctx);
ar_context_run(&ohci->ar_response_ctx);
@@ -1653,16 +1808,6 @@ static int ohci_enable(struct fw_card *card,
reg_write(ohci, OHCI1394_PhyUpperBound, 0x00010000);
reg_write(ohci, OHCI1394_IntEventClear, ~0);
reg_write(ohci, OHCI1394_IntMaskClear, ~0);
- reg_write(ohci, OHCI1394_IntMaskSet,
- OHCI1394_selfIDComplete |
- OHCI1394_RQPkt | OHCI1394_RSPkt |
- OHCI1394_reqTxComplete | OHCI1394_respTxComplete |
- OHCI1394_isochRx | OHCI1394_isochTx |
- OHCI1394_postedWriteErr | OHCI1394_cycleTooLong |
- OHCI1394_cycleInconsistent | OHCI1394_regAccessFail |
- OHCI1394_masterIntEnable);
- if (param_debug & OHCI_PARAM_DEBUG_BUSRESETS)
- reg_write(ohci, OHCI1394_IntMaskSet, OHCI1394_busReset);
ret = configure_1394a_enhancements(ohci);
if (ret < 0)
@@ -1719,26 +1864,38 @@ static int ohci_enable(struct fw_card *card,
reg_write(ohci, OHCI1394_AsReqFilterHiSet, 0x80000000);
+ if (!(ohci->quirks & QUIRK_NO_MSI))
+ pci_enable_msi(dev);
if (request_irq(dev->irq, irq_handler,
- IRQF_SHARED, ohci_driver_name, ohci)) {
- fw_error("Failed to allocate shared interrupt %d.\n",
- dev->irq);
+ pci_dev_msi_enabled(dev) ? 0 : IRQF_SHARED,
+ ohci_driver_name, ohci)) {
+ fw_error("Failed to allocate interrupt %d.\n", dev->irq);
+ pci_disable_msi(dev);
dma_free_coherent(ohci->card.device, CONFIG_ROM_SIZE,
ohci->config_rom, ohci->config_rom_bus);
return -EIO;
}
+ irqs = OHCI1394_reqTxComplete | OHCI1394_respTxComplete |
+ OHCI1394_RQPkt | OHCI1394_RSPkt |
+ OHCI1394_isochTx | OHCI1394_isochRx |
+ OHCI1394_postedWriteErr |
+ OHCI1394_selfIDComplete |
+ OHCI1394_regAccessFail |
+ OHCI1394_cycle64Seconds |
+ OHCI1394_cycleInconsistent | OHCI1394_cycleTooLong |
+ OHCI1394_masterIntEnable;
+ if (param_debug & OHCI_PARAM_DEBUG_BUSRESETS)
+ irqs |= OHCI1394_busReset;
+ reg_write(ohci, OHCI1394_IntMaskSet, irqs);
+
reg_write(ohci, OHCI1394_HCControlSet,
OHCI1394_HCControl_linkEnable |
OHCI1394_HCControl_BIBimageValid);
flush_writes(ohci);
- /*
- * We are ready to go, initiate bus reset to finish the
- * initialization.
- */
-
- fw_core_initiate_bus_reset(&ohci->card, 1);
+ /* We are ready to go, reset bus to finish initialization. */
+ fw_schedule_bus_reset(&ohci->card, false, true);
return 0;
}
@@ -1813,7 +1970,7 @@ static int ohci_set_config_rom(struct fw_card *card,
* takes effect.
*/
if (ret == 0)
- fw_core_initiate_bus_reset(&ohci->card, 1);
+ fw_schedule_bus_reset(&ohci->card, true, true);
else
dma_free_coherent(ohci->card.device, CONFIG_ROM_SIZE,
next_config_rom, next_config_rom_bus);
@@ -1903,61 +2060,117 @@ static int ohci_enable_phys_dma(struct fw_card *card,
#endif /* CONFIG_FIREWIRE_OHCI_REMOTE_DMA */
}
-static u32 cycle_timer_ticks(u32 cycle_timer)
+static u32 ohci_read_csr(struct fw_card *card, int csr_offset)
{
- u32 ticks;
+ struct fw_ohci *ohci = fw_ohci(card);
+ unsigned long flags;
+ u32 value;
+
+ switch (csr_offset) {
+ case CSR_STATE_CLEAR:
+ case CSR_STATE_SET:
+ if (ohci->is_root &&
+ (reg_read(ohci, OHCI1394_LinkControlSet) &
+ OHCI1394_LinkControl_cycleMaster))
+ value = CSR_STATE_BIT_CMSTR;
+ else
+ value = 0;
+ if (ohci->csr_state_setclear_abdicate)
+ value |= CSR_STATE_BIT_ABDICATE;
- ticks = cycle_timer & 0xfff;
- ticks += 3072 * ((cycle_timer >> 12) & 0x1fff);
- ticks += (3072 * 8000) * (cycle_timer >> 25);
+ return value;
- return ticks;
+ case CSR_NODE_IDS:
+ return reg_read(ohci, OHCI1394_NodeID) << 16;
+
+ case CSR_CYCLE_TIME:
+ return get_cycle_time(ohci);
+
+ case CSR_BUS_TIME:
+ /*
+ * We might be called just after the cycle timer has wrapped
+ * around but just before the cycle64Seconds handler, so we
+ * better check here, too, if the bus time needs to be updated.
+ */
+ spin_lock_irqsave(&ohci->lock, flags);
+ value = update_bus_time(ohci);
+ spin_unlock_irqrestore(&ohci->lock, flags);
+ return value;
+
+ case CSR_BUSY_TIMEOUT:
+ value = reg_read(ohci, OHCI1394_ATRetries);
+ return (value >> 4) & 0x0ffff00f;
+
+ case CSR_PRIORITY_BUDGET:
+ return (reg_read(ohci, OHCI1394_FairnessControl) & 0x3f) |
+ (ohci->pri_req_max << 8);
+
+ default:
+ WARN_ON(1);
+ return 0;
+ }
}
-/*
- * Some controllers exhibit one or more of the following bugs when updating the
- * iso cycle timer register:
- * - When the lowest six bits are wrapping around to zero, a read that happens
- * at the same time will return garbage in the lowest ten bits.
- * - When the cycleOffset field wraps around to zero, the cycleCount field is
- * not incremented for about 60 ns.
- * - Occasionally, the entire register reads zero.
- *
- * To catch these, we read the register three times and ensure that the
- * difference between each two consecutive reads is approximately the same, i.e.
- * less than twice the other. Furthermore, any negative difference indicates an
- * error. (A PCI read should take at least 20 ticks of the 24.576 MHz timer to
- * execute, so we have enough precision to compute the ratio of the differences.)
- */
-static u32 ohci_get_cycle_time(struct fw_card *card)
+static void ohci_write_csr(struct fw_card *card, int csr_offset, u32 value)
{
struct fw_ohci *ohci = fw_ohci(card);
- u32 c0, c1, c2;
- u32 t0, t1, t2;
- s32 diff01, diff12;
- int i;
+ unsigned long flags;
- c2 = reg_read(ohci, OHCI1394_IsochronousCycleTimer);
+ switch (csr_offset) {
+ case CSR_STATE_CLEAR:
+ if ((value & CSR_STATE_BIT_CMSTR) && ohci->is_root) {
+ reg_write(ohci, OHCI1394_LinkControlClear,
+ OHCI1394_LinkControl_cycleMaster);
+ flush_writes(ohci);
+ }
+ if (value & CSR_STATE_BIT_ABDICATE)
+ ohci->csr_state_setclear_abdicate = false;
+ break;
- if (ohci->quirks & QUIRK_CYCLE_TIMER) {
- i = 0;
- c1 = c2;
- c2 = reg_read(ohci, OHCI1394_IsochronousCycleTimer);
- do {
- c0 = c1;
- c1 = c2;
- c2 = reg_read(ohci, OHCI1394_IsochronousCycleTimer);
- t0 = cycle_timer_ticks(c0);
- t1 = cycle_timer_ticks(c1);
- t2 = cycle_timer_ticks(c2);
- diff01 = t1 - t0;
- diff12 = t2 - t1;
- } while ((diff01 <= 0 || diff12 <= 0 ||
- diff01 / diff12 >= 2 || diff12 / diff01 >= 2)
- && i++ < 20);
- }
+ case CSR_STATE_SET:
+ if ((value & CSR_STATE_BIT_CMSTR) && ohci->is_root) {
+ reg_write(ohci, OHCI1394_LinkControlSet,
+ OHCI1394_LinkControl_cycleMaster);
+ flush_writes(ohci);
+ }
+ if (value & CSR_STATE_BIT_ABDICATE)
+ ohci->csr_state_setclear_abdicate = true;
+ break;
- return c2;
+ case CSR_NODE_IDS:
+ reg_write(ohci, OHCI1394_NodeID, value >> 16);
+ flush_writes(ohci);
+ break;
+
+ case CSR_CYCLE_TIME:
+ reg_write(ohci, OHCI1394_IsochronousCycleTimer, value);
+ reg_write(ohci, OHCI1394_IntEventSet,
+ OHCI1394_cycleInconsistent);
+ flush_writes(ohci);
+ break;
+
+ case CSR_BUS_TIME:
+ spin_lock_irqsave(&ohci->lock, flags);
+ ohci->bus_time = (ohci->bus_time & 0x7f) | (value & ~0x7f);
+ spin_unlock_irqrestore(&ohci->lock, flags);
+ break;
+
+ case CSR_BUSY_TIMEOUT:
+ value = (value & 0xf) | ((value & 0xf) << 4) |
+ ((value & 0xf) << 8) | ((value & 0x0ffff000) << 4);
+ reg_write(ohci, OHCI1394_ATRetries, value);
+ flush_writes(ohci);
+ break;
+
+ case CSR_PRIORITY_BUDGET:
+ reg_write(ohci, OHCI1394_FairnessControl, value & 0x3f);
+ flush_writes(ohci);
+ break;
+
+ default:
+ WARN_ON(1);
+ break;
+ }
}
static void copy_iso_headers(struct iso_context *ctx, void *p)
@@ -1992,10 +2205,9 @@ static int handle_ir_packet_per_buffer(struct context *context,
__le32 *ir_header;
void *p;
- for (pd = d; pd <= last; pd++) {
+ for (pd = d; pd <= last; pd++)
if (pd->transfer_status)
break;
- }
if (pd > last)
/* Descriptor(s) not done yet, stop iteration */
return 0;
@@ -2005,16 +2217,38 @@ static int handle_ir_packet_per_buffer(struct context *context,
if (le16_to_cpu(last->control) & DESCRIPTOR_IRQ_ALWAYS) {
ir_header = (__le32 *) p;
- ctx->base.callback(&ctx->base,
- le32_to_cpu(ir_header[0]) & 0xffff,
- ctx->header_length, ctx->header,
- ctx->base.callback_data);
+ ctx->base.callback.sc(&ctx->base,
+ le32_to_cpu(ir_header[0]) & 0xffff,
+ ctx->header_length, ctx->header,
+ ctx->base.callback_data);
ctx->header_length = 0;
}
return 1;
}
+/* d == last because each descriptor block is only a single descriptor. */
+static int handle_ir_buffer_fill(struct context *context,
+ struct descriptor *d,
+ struct descriptor *last)
+{
+ struct iso_context *ctx =
+ container_of(context, struct iso_context, context);
+
+ if (!last->transfer_status)
+ /* Descriptor(s) not done yet, stop iteration */
+ return 0;
+
+ if (le16_to_cpu(last->control) & DESCRIPTOR_IRQ_ALWAYS)
+ ctx->base.callback.mc(&ctx->base,
+ le32_to_cpu(last->data_address) +
+ le16_to_cpu(last->req_count) -
+ le16_to_cpu(last->res_count),
+ ctx->base.callback_data);
+
+ return 1;
+}
+
static int handle_it_packet(struct context *context,
struct descriptor *d,
struct descriptor *last)
@@ -2040,71 +2274,118 @@ static int handle_it_packet(struct context *context,
ctx->header_length += 4;
}
if (le16_to_cpu(last->control) & DESCRIPTOR_IRQ_ALWAYS) {
- ctx->base.callback(&ctx->base, le16_to_cpu(last->res_count),
- ctx->header_length, ctx->header,
- ctx->base.callback_data);
+ ctx->base.callback.sc(&ctx->base, le16_to_cpu(last->res_count),
+ ctx->header_length, ctx->header,
+ ctx->base.callback_data);
ctx->header_length = 0;
}
return 1;
}
+static void set_multichannel_mask(struct fw_ohci *ohci, u64 channels)
+{
+ u32 hi = channels >> 32, lo = channels;
+
+ reg_write(ohci, OHCI1394_IRMultiChanMaskHiClear, ~hi);
+ reg_write(ohci, OHCI1394_IRMultiChanMaskLoClear, ~lo);
+ reg_write(ohci, OHCI1394_IRMultiChanMaskHiSet, hi);
+ reg_write(ohci, OHCI1394_IRMultiChanMaskLoSet, lo);
+ mmiowb();
+ ohci->mc_channels = channels;
+}
+
static struct fw_iso_context *ohci_allocate_iso_context(struct fw_card *card,
int type, int channel, size_t header_size)
{
struct fw_ohci *ohci = fw_ohci(card);
- struct iso_context *ctx, *list;
- descriptor_callback_t callback;
- u64 *channels, dont_care = ~0ULL;
- u32 *mask, regs;
+ struct iso_context *uninitialized_var(ctx);
+ descriptor_callback_t uninitialized_var(callback);
+ u64 *uninitialized_var(channels);
+ u32 *uninitialized_var(mask), uninitialized_var(regs);
unsigned long flags;
- int index, ret = -ENOMEM;
+ int index, ret = -EBUSY;
+
+ spin_lock_irqsave(&ohci->lock, flags);
- if (type == FW_ISO_CONTEXT_TRANSMIT) {
- channels = &dont_care;
- mask = &ohci->it_context_mask;
- list = ohci->it_context_list;
+ switch (type) {
+ case FW_ISO_CONTEXT_TRANSMIT:
+ mask = &ohci->it_context_mask;
callback = handle_it_packet;
- } else {
+ index = ffs(*mask) - 1;
+ if (index >= 0) {
+ *mask &= ~(1 << index);
+ regs = OHCI1394_IsoXmitContextBase(index);
+ ctx = &ohci->it_context_list[index];
+ }
+ break;
+
+ case FW_ISO_CONTEXT_RECEIVE:
channels = &ohci->ir_context_channels;
- mask = &ohci->ir_context_mask;
- list = ohci->ir_context_list;
+ mask = &ohci->ir_context_mask;
callback = handle_ir_packet_per_buffer;
- }
+ index = *channels & 1ULL << channel ? ffs(*mask) - 1 : -1;
+ if (index >= 0) {
+ *channels &= ~(1ULL << channel);
+ *mask &= ~(1 << index);
+ regs = OHCI1394_IsoRcvContextBase(index);
+ ctx = &ohci->ir_context_list[index];
+ }
+ break;
- spin_lock_irqsave(&ohci->lock, flags);
- index = *channels & 1ULL << channel ? ffs(*mask) - 1 : -1;
- if (index >= 0) {
- *channels &= ~(1ULL << channel);
- *mask &= ~(1 << index);
+ case FW_ISO_CONTEXT_RECEIVE_MULTICHANNEL:
+ mask = &ohci->ir_context_mask;
+ callback = handle_ir_buffer_fill;
+ index = !ohci->mc_allocated ? ffs(*mask) - 1 : -1;
+ if (index >= 0) {
+ ohci->mc_allocated = true;
+ *mask &= ~(1 << index);
+ regs = OHCI1394_IsoRcvContextBase(index);
+ ctx = &ohci->ir_context_list[index];
+ }
+ break;
+
+ default:
+ index = -1;
+ ret = -ENOSYS;
}
+
spin_unlock_irqrestore(&ohci->lock, flags);
if (index < 0)
- return ERR_PTR(-EBUSY);
-
- if (type == FW_ISO_CONTEXT_TRANSMIT)
- regs = OHCI1394_IsoXmitContextBase(index);
- else
- regs = OHCI1394_IsoRcvContextBase(index);
+ return ERR_PTR(ret);
- ctx = &list[index];
memset(ctx, 0, sizeof(*ctx));
ctx->header_length = 0;
ctx->header = (void *) __get_free_page(GFP_KERNEL);
- if (ctx->header == NULL)
+ if (ctx->header == NULL) {
+ ret = -ENOMEM;
goto out;
-
+ }
ret = context_init(&ctx->context, ohci, regs, callback);
if (ret < 0)
goto out_with_header;
+ if (type == FW_ISO_CONTEXT_RECEIVE_MULTICHANNEL)
+ set_multichannel_mask(ohci, 0);
+
return &ctx->base;
out_with_header:
free_page((unsigned long)ctx->header);
out:
spin_lock_irqsave(&ohci->lock, flags);
+
+ switch (type) {
+ case FW_ISO_CONTEXT_RECEIVE:
+ *channels |= 1ULL << channel;
+ break;
+
+ case FW_ISO_CONTEXT_RECEIVE_MULTICHANNEL:
+ ohci->mc_allocated = false;
+ break;
+ }
*mask |= 1 << index;
+
spin_unlock_irqrestore(&ohci->lock, flags);
return ERR_PTR(ret);
@@ -2115,10 +2396,11 @@ static int ohci_start_iso(struct fw_iso_context *base,
{
struct iso_context *ctx = container_of(base, struct iso_context, base);
struct fw_ohci *ohci = ctx->context.ohci;
- u32 control, match;
+ u32 control = IR_CONTEXT_ISOCH_HEADER, match;
int index;
- if (ctx->base.type == FW_ISO_CONTEXT_TRANSMIT) {
+ switch (ctx->base.type) {
+ case FW_ISO_CONTEXT_TRANSMIT:
index = ctx - ohci->it_context_list;
match = 0;
if (cycle >= 0)
@@ -2128,9 +2410,13 @@ static int ohci_start_iso(struct fw_iso_context *base,
reg_write(ohci, OHCI1394_IsoXmitIntEventClear, 1 << index);
reg_write(ohci, OHCI1394_IsoXmitIntMaskSet, 1 << index);
context_run(&ctx->context, match);
- } else {
+ break;
+
+ case FW_ISO_CONTEXT_RECEIVE_MULTICHANNEL:
+ control |= IR_CONTEXT_BUFFER_FILL|IR_CONTEXT_MULTI_CHANNEL_MODE;
+ /* fall through */
+ case FW_ISO_CONTEXT_RECEIVE:
index = ctx - ohci->ir_context_list;
- control = IR_CONTEXT_ISOCH_HEADER;
match = (tags << 28) | (sync << 8) | ctx->base.channel;
if (cycle >= 0) {
match |= (cycle & 0x07fff) << 12;
@@ -2141,6 +2427,7 @@ static int ohci_start_iso(struct fw_iso_context *base,
reg_write(ohci, OHCI1394_IsoRecvIntMaskSet, 1 << index);
reg_write(ohci, CONTEXT_MATCH(ctx->context.regs), match);
context_run(&ctx->context, control);
+ break;
}
return 0;
@@ -2152,12 +2439,17 @@ static int ohci_stop_iso(struct fw_iso_context *base)
struct iso_context *ctx = container_of(base, struct iso_context, base);
int index;
- if (ctx->base.type == FW_ISO_CONTEXT_TRANSMIT) {
+ switch (ctx->base.type) {
+ case FW_ISO_CONTEXT_TRANSMIT:
index = ctx - ohci->it_context_list;
reg_write(ohci, OHCI1394_IsoXmitIntMaskClear, 1 << index);
- } else {
+ break;
+
+ case FW_ISO_CONTEXT_RECEIVE:
+ case FW_ISO_CONTEXT_RECEIVE_MULTICHANNEL:
index = ctx - ohci->ir_context_list;
reg_write(ohci, OHCI1394_IsoRecvIntMaskClear, 1 << index);
+ break;
}
flush_writes(ohci);
context_stop(&ctx->context);
@@ -2178,24 +2470,65 @@ static void ohci_free_iso_context(struct fw_iso_context *base)
spin_lock_irqsave(&ohci->lock, flags);
- if (ctx->base.type == FW_ISO_CONTEXT_TRANSMIT) {
+ switch (base->type) {
+ case FW_ISO_CONTEXT_TRANSMIT:
index = ctx - ohci->it_context_list;
ohci->it_context_mask |= 1 << index;
- } else {
+ break;
+
+ case FW_ISO_CONTEXT_RECEIVE:
index = ctx - ohci->ir_context_list;
ohci->ir_context_mask |= 1 << index;
ohci->ir_context_channels |= 1ULL << base->channel;
+ break;
+
+ case FW_ISO_CONTEXT_RECEIVE_MULTICHANNEL:
+ index = ctx - ohci->ir_context_list;
+ ohci->ir_context_mask |= 1 << index;
+ ohci->ir_context_channels |= ohci->mc_channels;
+ ohci->mc_channels = 0;
+ ohci->mc_allocated = false;
+ break;
}
spin_unlock_irqrestore(&ohci->lock, flags);
}
-static int ohci_queue_iso_transmit(struct fw_iso_context *base,
- struct fw_iso_packet *packet,
- struct fw_iso_buffer *buffer,
- unsigned long payload)
+static int ohci_set_iso_channels(struct fw_iso_context *base, u64 *channels)
+{
+ struct fw_ohci *ohci = fw_ohci(base->card);
+ unsigned long flags;
+ int ret;
+
+ switch (base->type) {
+ case FW_ISO_CONTEXT_RECEIVE_MULTICHANNEL:
+
+ spin_lock_irqsave(&ohci->lock, flags);
+
+ /* Don't allow multichannel to grab other contexts' channels. */
+ if (~ohci->ir_context_channels & ~ohci->mc_channels & *channels) {
+ *channels = ohci->ir_context_channels;
+ ret = -EBUSY;
+ } else {
+ set_multichannel_mask(ohci, *channels);
+ ret = 0;
+ }
+
+ spin_unlock_irqrestore(&ohci->lock, flags);
+
+ break;
+ default:
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+static int queue_iso_transmit(struct iso_context *ctx,
+ struct fw_iso_packet *packet,
+ struct fw_iso_buffer *buffer,
+ unsigned long payload)
{
- struct iso_context *ctx = container_of(base, struct iso_context, base);
struct descriptor *d, *last, *pd;
struct fw_iso_packet *p;
__le32 *header;
@@ -2291,14 +2624,12 @@ static int ohci_queue_iso_transmit(struct fw_iso_context *base,
return 0;
}
-static int ohci_queue_iso_receive_packet_per_buffer(struct fw_iso_context *base,
- struct fw_iso_packet *packet,
- struct fw_iso_buffer *buffer,
- unsigned long payload)
+static int queue_iso_packet_per_buffer(struct iso_context *ctx,
+ struct fw_iso_packet *packet,
+ struct fw_iso_buffer *buffer,
+ unsigned long payload)
{
- struct iso_context *ctx = container_of(base, struct iso_context, base);
struct descriptor *d, *pd;
- struct fw_iso_packet *p = packet;
dma_addr_t d_bus, page_bus;
u32 z, header_z, rest;
int i, j, length;
@@ -2308,14 +2639,14 @@ static int ohci_queue_iso_receive_packet_per_buffer(struct fw_iso_context *base,
* The OHCI controller puts the isochronous header and trailer in the
* buffer, so we need at least 8 bytes.
*/
- packet_count = p->header_length / ctx->base.header_size;
+ packet_count = packet->header_length / ctx->base.header_size;
header_size = max(ctx->base.header_size, (size_t)8);
/* Get header size in number of descriptors. */
header_z = DIV_ROUND_UP(header_size, sizeof(*d));
page = payload >> PAGE_SHIFT;
offset = payload & ~PAGE_MASK;
- payload_per_buffer = p->payload_length / packet_count;
+ payload_per_buffer = packet->payload_length / packet_count;
for (i = 0; i < packet_count; i++) {
/* d points to the header descriptor */
@@ -2327,7 +2658,7 @@ static int ohci_queue_iso_receive_packet_per_buffer(struct fw_iso_context *base,
d->control = cpu_to_le16(DESCRIPTOR_STATUS |
DESCRIPTOR_INPUT_MORE);
- if (p->skip && i == 0)
+ if (packet->skip && i == 0)
d->control |= cpu_to_le16(DESCRIPTOR_WAIT);
d->req_count = cpu_to_le16(header_size);
d->res_count = d->req_count;
@@ -2360,7 +2691,7 @@ static int ohci_queue_iso_receive_packet_per_buffer(struct fw_iso_context *base,
pd->control = cpu_to_le16(DESCRIPTOR_STATUS |
DESCRIPTOR_INPUT_LAST |
DESCRIPTOR_BRANCH_ALWAYS);
- if (p->interrupt && i == packet_count - 1)
+ if (packet->interrupt && i == packet_count - 1)
pd->control |= cpu_to_le16(DESCRIPTOR_IRQ_ALWAYS);
context_append(&ctx->context, d, z, header_z);
@@ -2369,6 +2700,58 @@ static int ohci_queue_iso_receive_packet_per_buffer(struct fw_iso_context *base,
return 0;
}
+static int queue_iso_buffer_fill(struct iso_context *ctx,
+ struct fw_iso_packet *packet,
+ struct fw_iso_buffer *buffer,
+ unsigned long payload)
+{
+ struct descriptor *d;
+ dma_addr_t d_bus, page_bus;
+ int page, offset, rest, z, i, length;
+
+ page = payload >> PAGE_SHIFT;
+ offset = payload & ~PAGE_MASK;
+ rest = packet->payload_length;
+
+ /* We need one descriptor for each page in the buffer. */
+ z = DIV_ROUND_UP(offset + rest, PAGE_SIZE);
+
+ if (WARN_ON(offset & 3 || rest & 3 || page + z > buffer->page_count))
+ return -EFAULT;
+
+ for (i = 0; i < z; i++) {
+ d = context_get_descriptors(&ctx->context, 1, &d_bus);
+ if (d == NULL)
+ return -ENOMEM;
+
+ d->control = cpu_to_le16(DESCRIPTOR_INPUT_MORE |
+ DESCRIPTOR_BRANCH_ALWAYS);
+ if (packet->skip && i == 0)
+ d->control |= cpu_to_le16(DESCRIPTOR_WAIT);
+ if (packet->interrupt && i == z - 1)
+ d->control |= cpu_to_le16(DESCRIPTOR_IRQ_ALWAYS);
+
+ if (offset + rest < PAGE_SIZE)
+ length = rest;
+ else
+ length = PAGE_SIZE - offset;
+ d->req_count = cpu_to_le16(length);
+ d->res_count = d->req_count;
+ d->transfer_status = 0;
+
+ page_bus = page_private(buffer->pages[page]);
+ d->data_address = cpu_to_le32(page_bus + offset);
+
+ rest -= length;
+ offset = 0;
+ page++;
+
+ context_append(&ctx->context, d, 1, 0);
+ }
+
+ return 0;
+}
+
static int ohci_queue_iso(struct fw_iso_context *base,
struct fw_iso_packet *packet,
struct fw_iso_buffer *buffer,
@@ -2376,14 +2759,20 @@ static int ohci_queue_iso(struct fw_iso_context *base,
{
struct iso_context *ctx = container_of(base, struct iso_context, base);
unsigned long flags;
- int ret;
+ int ret = -ENOSYS;
spin_lock_irqsave(&ctx->context.ohci->lock, flags);
- if (base->type == FW_ISO_CONTEXT_TRANSMIT)
- ret = ohci_queue_iso_transmit(base, packet, buffer, payload);
- else
- ret = ohci_queue_iso_receive_packet_per_buffer(base, packet,
- buffer, payload);
+ switch (base->type) {
+ case FW_ISO_CONTEXT_TRANSMIT:
+ ret = queue_iso_transmit(ctx, packet, buffer, payload);
+ break;
+ case FW_ISO_CONTEXT_RECEIVE:
+ ret = queue_iso_packet_per_buffer(ctx, packet, buffer, payload);
+ break;
+ case FW_ISO_CONTEXT_RECEIVE_MULTICHANNEL:
+ ret = queue_iso_buffer_fill(ctx, packet, buffer, payload);
+ break;
+ }
spin_unlock_irqrestore(&ctx->context.ohci->lock, flags);
return ret;
@@ -2391,16 +2780,19 @@ static int ohci_queue_iso(struct fw_iso_context *base,
static const struct fw_card_driver ohci_driver = {
.enable = ohci_enable,
+ .read_phy_reg = ohci_read_phy_reg,
.update_phy_reg = ohci_update_phy_reg,
.set_config_rom = ohci_set_config_rom,
.send_request = ohci_send_request,
.send_response = ohci_send_response,
.cancel_packet = ohci_cancel_packet,
.enable_phys_dma = ohci_enable_phys_dma,
- .get_cycle_time = ohci_get_cycle_time,
+ .read_csr = ohci_read_csr,
+ .write_csr = ohci_write_csr,
.allocate_iso_context = ohci_allocate_iso_context,
.free_iso_context = ohci_free_iso_context,
+ .set_iso_channels = ohci_set_iso_channels,
.queue_iso = ohci_queue_iso,
.start_iso = ohci_start_iso,
.stop_iso = ohci_stop_iso,
@@ -2465,6 +2857,7 @@ static int __devinit pci_probe(struct pci_dev *dev,
pci_set_drvdata(dev, ohci);
spin_lock_init(&ohci->lock);
+ mutex_init(&ohci->phy_reg_mutex);
tasklet_init(&ohci->bus_reset_tasklet,
bus_reset_tasklet, (unsigned long)ohci);
@@ -2625,6 +3018,7 @@ static void pci_remove(struct pci_dev *dev)
context_release(&ohci->at_response_ctx);
kfree(ohci->it_context_list);
kfree(ohci->ir_context_list);
+ pci_disable_msi(dev);
pci_iounmap(dev, ohci->registers);
pci_release_region(dev, 0);
pci_disable_device(dev);
@@ -2642,6 +3036,7 @@ static int pci_suspend(struct pci_dev *dev, pm_message_t state)
software_reset(ohci);
free_irq(dev->irq, ohci);
+ pci_disable_msi(dev);
err = pci_save_state(dev);
if (err) {
fw_error("pci_save_state failed\n");
diff --git a/drivers/firewire/ohci.h b/drivers/firewire/ohci.h
index 3bc9a5d744e..0e6c5a46690 100644
--- a/drivers/firewire/ohci.h
+++ b/drivers/firewire/ohci.h
@@ -60,6 +60,7 @@
#define OHCI1394_LinkControl_cycleSource (1 << 22)
#define OHCI1394_NodeID 0x0E8
#define OHCI1394_NodeID_idValid 0x80000000
+#define OHCI1394_NodeID_root 0x40000000
#define OHCI1394_NodeID_nodeNumber 0x0000003f
#define OHCI1394_NodeID_busNumber 0x0000ffc0
#define OHCI1394_PhyControl 0x0EC
diff --git a/drivers/firewire/sbp2.c b/drivers/firewire/sbp2.c
index ca264f2fdf0..9f76171717e 100644
--- a/drivers/firewire/sbp2.c
+++ b/drivers/firewire/sbp2.c
@@ -410,8 +410,7 @@ static void free_orb(struct kref *kref)
static void sbp2_status_write(struct fw_card *card, struct fw_request *request,
int tcode, int destination, int source,
- int generation, int speed,
- unsigned long long offset,
+ int generation, unsigned long long offset,
void *payload, size_t length, void *callback_data)
{
struct sbp2_logical_unit *lu = callback_data;
@@ -508,8 +507,7 @@ static void sbp2_send_orb(struct sbp2_orb *orb, struct sbp2_logical_unit *lu,
fw_send_request(device->card, &orb->t, TCODE_WRITE_BLOCK_REQUEST,
node_id, generation, device->max_speed, offset,
- &orb->pointer, sizeof(orb->pointer),
- complete_transaction, orb);
+ &orb->pointer, 8, complete_transaction, orb);
}
static int sbp2_cancel_orbs(struct sbp2_logical_unit *lu)
@@ -654,7 +652,7 @@ static void sbp2_agent_reset(struct sbp2_logical_unit *lu)
fw_run_transaction(device->card, TCODE_WRITE_QUADLET_REQUEST,
lu->tgt->node_id, lu->generation, device->max_speed,
lu->command_block_agent_address + SBP2_AGENT_RESET,
- &d, sizeof(d));
+ &d, 4);
}
static void complete_agent_reset_write_no_wait(struct fw_card *card,
@@ -676,7 +674,7 @@ static void sbp2_agent_reset_no_wait(struct sbp2_logical_unit *lu)
fw_send_request(device->card, t, TCODE_WRITE_QUADLET_REQUEST,
lu->tgt->node_id, lu->generation, device->max_speed,
lu->command_block_agent_address + SBP2_AGENT_RESET,
- &d, sizeof(d), complete_agent_reset_write_no_wait, t);
+ &d, 4, complete_agent_reset_write_no_wait, t);
}
static inline void sbp2_allow_block(struct sbp2_logical_unit *lu)
@@ -866,8 +864,7 @@ static void sbp2_set_busy_timeout(struct sbp2_logical_unit *lu)
fw_run_transaction(device->card, TCODE_WRITE_QUADLET_REQUEST,
lu->tgt->node_id, lu->generation, device->max_speed,
- CSR_REGISTER_BASE + CSR_BUSY_TIMEOUT,
- &d, sizeof(d));
+ CSR_REGISTER_BASE + CSR_BUSY_TIMEOUT, &d, 4);
}
static void sbp2_reconnect(struct work_struct *work);
diff --git a/drivers/firmware/Kconfig b/drivers/firmware/Kconfig
index 1b03ba1d083..a6c670b8ce5 100644
--- a/drivers/firmware/Kconfig
+++ b/drivers/firmware/Kconfig
@@ -122,8 +122,17 @@ config ISCSI_IBFT_FIND
is necessary for iSCSI Boot Firmware Table Attributes module to work
properly.
+config ISCSI_BOOT_SYSFS
+ tristate "iSCSI Boot Sysfs Interface"
+ default n
+ help
+ This option enables support for exposing iSCSI boot information
+ via sysfs to userspace. If you wish to export this information,
+ say Y. Otherwise, say N.
+
config ISCSI_IBFT
tristate "iSCSI Boot Firmware Table Attributes module"
+ select ISCSI_BOOT_SYSFS
depends on ISCSI_IBFT_FIND
default n
help
diff --git a/drivers/firmware/Makefile b/drivers/firmware/Makefile
index 1c3c17343db..5fe7e166292 100644
--- a/drivers/firmware/Makefile
+++ b/drivers/firmware/Makefile
@@ -10,4 +10,5 @@ obj-$(CONFIG_DCDBAS) += dcdbas.o
obj-$(CONFIG_DMIID) += dmi-id.o
obj-$(CONFIG_ISCSI_IBFT_FIND) += iscsi_ibft_find.o
obj-$(CONFIG_ISCSI_IBFT) += iscsi_ibft.o
+obj-$(CONFIG_ISCSI_BOOT_SYSFS) += iscsi_boot_sysfs.o
obj-$(CONFIG_FIRMWARE_MEMMAP) += memmap.o
diff --git a/drivers/firmware/dcdbas.c b/drivers/firmware/dcdbas.c
index aa9bc9e980e..69ad529d92f 100644
--- a/drivers/firmware/dcdbas.c
+++ b/drivers/firmware/dcdbas.c
@@ -634,9 +634,6 @@ static void __exit dcdbas_exit(void)
* before platform_device_unregister
*/
unregister_reboot_notifier(&dcdbas_reboot_nb);
- smi_data_buf_free();
- platform_device_unregister(dcdbas_pdev);
- platform_driver_unregister(&dcdbas_driver);
/*
* We have to free the buffer here instead of dcdbas_remove
@@ -645,6 +642,8 @@ static void __exit dcdbas_exit(void)
* released.
*/
smi_data_buf_free();
+ platform_device_unregister(dcdbas_pdev);
+ platform_driver_unregister(&dcdbas_driver);
}
module_init(dcdbas_init);
diff --git a/drivers/firmware/dmi-id.c b/drivers/firmware/dmi-id.c
index a777a35381d..94a58a082b9 100644
--- a/drivers/firmware/dmi-id.c
+++ b/drivers/firmware/dmi-id.c
@@ -229,10 +229,12 @@ static int __init dmi_id_init(void)
ret = device_register(dmi_dev);
if (ret)
- goto fail_class_unregister;
+ goto fail_free_dmi_dev;
return 0;
+fail_free_dmi_dev:
+ kfree(dmi_dev);
fail_class_unregister:
class_unregister(&dmi_class);
diff --git a/drivers/firmware/dmi_scan.c b/drivers/firmware/dmi_scan.c
index d4646727134..b3d22d65999 100644
--- a/drivers/firmware/dmi_scan.c
+++ b/drivers/firmware/dmi_scan.c
@@ -277,6 +277,29 @@ static void __init dmi_save_ipmi_device(const struct dmi_header *dm)
list_add_tail(&dev->list, &dmi_devices);
}
+static void __init dmi_save_dev_onboard(int instance, int segment, int bus,
+ int devfn, const char *name)
+{
+ struct dmi_dev_onboard *onboard_dev;
+
+ onboard_dev = dmi_alloc(sizeof(*onboard_dev) + strlen(name) + 1);
+ if (!onboard_dev) {
+ printk(KERN_ERR "dmi_save_dev_onboard: out of memory.\n");
+ return;
+ }
+ onboard_dev->instance = instance;
+ onboard_dev->segment = segment;
+ onboard_dev->bus = bus;
+ onboard_dev->devfn = devfn;
+
+ strcpy((char *)&onboard_dev[1], name);
+ onboard_dev->dev.type = DMI_DEV_TYPE_DEV_ONBOARD;
+ onboard_dev->dev.name = (char *)&onboard_dev[1];
+ onboard_dev->dev.device_data = onboard_dev;
+
+ list_add(&onboard_dev->dev.list, &dmi_devices);
+}
+
static void __init dmi_save_extended_devices(const struct dmi_header *dm)
{
const u8 *d = (u8*) dm + 5;
@@ -285,6 +308,8 @@ static void __init dmi_save_extended_devices(const struct dmi_header *dm)
if ((*d & 0x80) == 0)
return;
+ dmi_save_dev_onboard(*(d+1), *(u16 *)(d+2), *(d+4), *(d+5),
+ dmi_string_nosave(dm, *(d-1)));
dmi_save_one_device(*d & 0x7f, dmi_string_nosave(dm, *(d - 1)));
}
diff --git a/drivers/firmware/iscsi_boot_sysfs.c b/drivers/firmware/iscsi_boot_sysfs.c
new file mode 100644
index 00000000000..df6bff7366c
--- /dev/null
+++ b/drivers/firmware/iscsi_boot_sysfs.c
@@ -0,0 +1,481 @@
+/*
+ * Export the iSCSI boot info to userland via sysfs.
+ *
+ * Copyright (C) 2010 Red Hat, Inc. All rights reserved.
+ * Copyright (C) 2010 Mike Christie
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License v2.0 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.
+ */
+
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+#include <linux/capability.h>
+#include <linux/iscsi_boot_sysfs.h>
+
+
+MODULE_AUTHOR("Mike Christie <michaelc@cs.wisc.edu>");
+MODULE_DESCRIPTION("sysfs interface and helpers to export iSCSI boot information");
+MODULE_LICENSE("GPL");
+/*
+ * The kobject and attribute structures.
+ */
+struct iscsi_boot_attr {
+ struct attribute attr;
+ int type;
+ ssize_t (*show) (void *data, int type, char *buf);
+};
+
+/*
+ * The routine called for all sysfs attributes.
+ */
+static ssize_t iscsi_boot_show_attribute(struct kobject *kobj,
+ struct attribute *attr, char *buf)
+{
+ struct iscsi_boot_kobj *boot_kobj =
+ container_of(kobj, struct iscsi_boot_kobj, kobj);
+ struct iscsi_boot_attr *boot_attr =
+ container_of(attr, struct iscsi_boot_attr, attr);
+ ssize_t ret = -EIO;
+ char *str = buf;
+
+ if (!capable(CAP_SYS_ADMIN))
+ return -EACCES;
+
+ if (boot_kobj->show)
+ ret = boot_kobj->show(boot_kobj->data, boot_attr->type, str);
+ return ret;
+}
+
+static const struct sysfs_ops iscsi_boot_attr_ops = {
+ .show = iscsi_boot_show_attribute,
+};
+
+static void iscsi_boot_kobj_release(struct kobject *kobj)
+{
+ struct iscsi_boot_kobj *boot_kobj =
+ container_of(kobj, struct iscsi_boot_kobj, kobj);
+
+ kfree(boot_kobj->data);
+ kfree(boot_kobj);
+}
+
+static struct kobj_type iscsi_boot_ktype = {
+ .release = iscsi_boot_kobj_release,
+ .sysfs_ops = &iscsi_boot_attr_ops,
+};
+
+#define iscsi_boot_rd_attr(fnname, sysfs_name, attr_type) \
+static struct iscsi_boot_attr iscsi_boot_attr_##fnname = { \
+ .attr = { .name = __stringify(sysfs_name), .mode = 0444 }, \
+ .type = attr_type, \
+}
+
+/* Target attrs */
+iscsi_boot_rd_attr(tgt_index, index, ISCSI_BOOT_TGT_INDEX);
+iscsi_boot_rd_attr(tgt_flags, flags, ISCSI_BOOT_TGT_FLAGS);
+iscsi_boot_rd_attr(tgt_ip, ip-addr, ISCSI_BOOT_TGT_IP_ADDR);
+iscsi_boot_rd_attr(tgt_port, port, ISCSI_BOOT_TGT_PORT);
+iscsi_boot_rd_attr(tgt_lun, lun, ISCSI_BOOT_TGT_LUN);
+iscsi_boot_rd_attr(tgt_chap, chap-type, ISCSI_BOOT_TGT_CHAP_TYPE);
+iscsi_boot_rd_attr(tgt_nic, nic-assoc, ISCSI_BOOT_TGT_NIC_ASSOC);
+iscsi_boot_rd_attr(tgt_name, target-name, ISCSI_BOOT_TGT_NAME);
+iscsi_boot_rd_attr(tgt_chap_name, chap-name, ISCSI_BOOT_TGT_CHAP_NAME);
+iscsi_boot_rd_attr(tgt_chap_secret, chap-secret, ISCSI_BOOT_TGT_CHAP_SECRET);
+iscsi_boot_rd_attr(tgt_chap_rev_name, rev-chap-name,
+ ISCSI_BOOT_TGT_REV_CHAP_NAME);
+iscsi_boot_rd_attr(tgt_chap_rev_secret, rev-chap-name-secret,
+ ISCSI_BOOT_TGT_REV_CHAP_SECRET);
+
+static struct attribute *target_attrs[] = {
+ &iscsi_boot_attr_tgt_index.attr,
+ &iscsi_boot_attr_tgt_flags.attr,
+ &iscsi_boot_attr_tgt_ip.attr,
+ &iscsi_boot_attr_tgt_port.attr,
+ &iscsi_boot_attr_tgt_lun.attr,
+ &iscsi_boot_attr_tgt_chap.attr,
+ &iscsi_boot_attr_tgt_nic.attr,
+ &iscsi_boot_attr_tgt_name.attr,
+ &iscsi_boot_attr_tgt_chap_name.attr,
+ &iscsi_boot_attr_tgt_chap_secret.attr,
+ &iscsi_boot_attr_tgt_chap_rev_name.attr,
+ &iscsi_boot_attr_tgt_chap_rev_secret.attr,
+ NULL
+};
+
+static mode_t iscsi_boot_tgt_attr_is_visible(struct kobject *kobj,
+ struct attribute *attr, int i)
+{
+ struct iscsi_boot_kobj *boot_kobj =
+ container_of(kobj, struct iscsi_boot_kobj, kobj);
+
+ if (attr == &iscsi_boot_attr_tgt_index.attr)
+ return boot_kobj->is_visible(boot_kobj->data,
+ ISCSI_BOOT_TGT_INDEX);
+ else if (attr == &iscsi_boot_attr_tgt_flags.attr)
+ return boot_kobj->is_visible(boot_kobj->data,
+ ISCSI_BOOT_TGT_FLAGS);
+ else if (attr == &iscsi_boot_attr_tgt_ip.attr)
+ return boot_kobj->is_visible(boot_kobj->data,
+ ISCSI_BOOT_TGT_IP_ADDR);
+ else if (attr == &iscsi_boot_attr_tgt_port.attr)
+ return boot_kobj->is_visible(boot_kobj->data,
+ ISCSI_BOOT_TGT_PORT);
+ else if (attr == &iscsi_boot_attr_tgt_lun.attr)
+ return boot_kobj->is_visible(boot_kobj->data,
+ ISCSI_BOOT_TGT_LUN);
+ else if (attr == &iscsi_boot_attr_tgt_chap.attr)
+ return boot_kobj->is_visible(boot_kobj->data,
+ ISCSI_BOOT_TGT_CHAP_TYPE);
+ else if (attr == &iscsi_boot_attr_tgt_nic.attr)
+ return boot_kobj->is_visible(boot_kobj->data,
+ ISCSI_BOOT_TGT_NIC_ASSOC);
+ else if (attr == &iscsi_boot_attr_tgt_name.attr)
+ return boot_kobj->is_visible(boot_kobj->data,
+ ISCSI_BOOT_TGT_NAME);
+ else if (attr == &iscsi_boot_attr_tgt_chap_name.attr)
+ return boot_kobj->is_visible(boot_kobj->data,
+ ISCSI_BOOT_TGT_CHAP_NAME);
+ else if (attr == &iscsi_boot_attr_tgt_chap_secret.attr)
+ return boot_kobj->is_visible(boot_kobj->data,
+ ISCSI_BOOT_TGT_CHAP_SECRET);
+ else if (attr == &iscsi_boot_attr_tgt_chap_rev_name.attr)
+ return boot_kobj->is_visible(boot_kobj->data,
+ ISCSI_BOOT_TGT_REV_CHAP_NAME);
+ else if (attr == &iscsi_boot_attr_tgt_chap_rev_secret.attr)
+ return boot_kobj->is_visible(boot_kobj->data,
+ ISCSI_BOOT_TGT_REV_CHAP_SECRET);
+ return 0;
+}
+
+static struct attribute_group iscsi_boot_target_attr_group = {
+ .attrs = target_attrs,
+ .is_visible = iscsi_boot_tgt_attr_is_visible,
+};
+
+/* Ethernet attrs */
+iscsi_boot_rd_attr(eth_index, index, ISCSI_BOOT_ETH_INDEX);
+iscsi_boot_rd_attr(eth_flags, flags, ISCSI_BOOT_ETH_FLAGS);
+iscsi_boot_rd_attr(eth_ip, ip-addr, ISCSI_BOOT_ETH_IP_ADDR);
+iscsi_boot_rd_attr(eth_subnet, subnet-mask, ISCSI_BOOT_ETH_SUBNET_MASK);
+iscsi_boot_rd_attr(eth_origin, origin, ISCSI_BOOT_ETH_ORIGIN);
+iscsi_boot_rd_attr(eth_gateway, gateway, ISCSI_BOOT_ETH_GATEWAY);
+iscsi_boot_rd_attr(eth_primary_dns, primary-dns, ISCSI_BOOT_ETH_PRIMARY_DNS);
+iscsi_boot_rd_attr(eth_secondary_dns, secondary-dns,
+ ISCSI_BOOT_ETH_SECONDARY_DNS);
+iscsi_boot_rd_attr(eth_dhcp, dhcp, ISCSI_BOOT_ETH_DHCP);
+iscsi_boot_rd_attr(eth_vlan, vlan, ISCSI_BOOT_ETH_VLAN);
+iscsi_boot_rd_attr(eth_mac, mac, ISCSI_BOOT_ETH_MAC);
+iscsi_boot_rd_attr(eth_hostname, hostname, ISCSI_BOOT_ETH_HOSTNAME);
+
+static struct attribute *ethernet_attrs[] = {
+ &iscsi_boot_attr_eth_index.attr,
+ &iscsi_boot_attr_eth_flags.attr,
+ &iscsi_boot_attr_eth_ip.attr,
+ &iscsi_boot_attr_eth_subnet.attr,
+ &iscsi_boot_attr_eth_origin.attr,
+ &iscsi_boot_attr_eth_gateway.attr,
+ &iscsi_boot_attr_eth_primary_dns.attr,
+ &iscsi_boot_attr_eth_secondary_dns.attr,
+ &iscsi_boot_attr_eth_dhcp.attr,
+ &iscsi_boot_attr_eth_vlan.attr,
+ &iscsi_boot_attr_eth_mac.attr,
+ &iscsi_boot_attr_eth_hostname.attr,
+ NULL
+};
+
+static mode_t iscsi_boot_eth_attr_is_visible(struct kobject *kobj,
+ struct attribute *attr, int i)
+{
+ struct iscsi_boot_kobj *boot_kobj =
+ container_of(kobj, struct iscsi_boot_kobj, kobj);
+
+ if (attr == &iscsi_boot_attr_eth_index.attr)
+ return boot_kobj->is_visible(boot_kobj->data,
+ ISCSI_BOOT_ETH_INDEX);
+ else if (attr == &iscsi_boot_attr_eth_flags.attr)
+ return boot_kobj->is_visible(boot_kobj->data,
+ ISCSI_BOOT_ETH_FLAGS);
+ else if (attr == &iscsi_boot_attr_eth_ip.attr)
+ return boot_kobj->is_visible(boot_kobj->data,
+ ISCSI_BOOT_ETH_IP_ADDR);
+ else if (attr == &iscsi_boot_attr_eth_subnet.attr)
+ return boot_kobj->is_visible(boot_kobj->data,
+ ISCSI_BOOT_ETH_SUBNET_MASK);
+ else if (attr == &iscsi_boot_attr_eth_origin.attr)
+ return boot_kobj->is_visible(boot_kobj->data,
+ ISCSI_BOOT_ETH_ORIGIN);
+ else if (attr == &iscsi_boot_attr_eth_gateway.attr)
+ return boot_kobj->is_visible(boot_kobj->data,
+ ISCSI_BOOT_ETH_GATEWAY);
+ else if (attr == &iscsi_boot_attr_eth_primary_dns.attr)
+ return boot_kobj->is_visible(boot_kobj->data,
+ ISCSI_BOOT_ETH_PRIMARY_DNS);
+ else if (attr == &iscsi_boot_attr_eth_secondary_dns.attr)
+ return boot_kobj->is_visible(boot_kobj->data,
+ ISCSI_BOOT_ETH_SECONDARY_DNS);
+ else if (attr == &iscsi_boot_attr_eth_dhcp.attr)
+ return boot_kobj->is_visible(boot_kobj->data,
+ ISCSI_BOOT_ETH_DHCP);
+ else if (attr == &iscsi_boot_attr_eth_vlan.attr)
+ return boot_kobj->is_visible(boot_kobj->data,
+ ISCSI_BOOT_ETH_VLAN);
+ else if (attr == &iscsi_boot_attr_eth_mac.attr)
+ return boot_kobj->is_visible(boot_kobj->data,
+ ISCSI_BOOT_ETH_MAC);
+ else if (attr == &iscsi_boot_attr_eth_hostname.attr)
+ return boot_kobj->is_visible(boot_kobj->data,
+ ISCSI_BOOT_ETH_HOSTNAME);
+ return 0;
+}
+
+static struct attribute_group iscsi_boot_ethernet_attr_group = {
+ .attrs = ethernet_attrs,
+ .is_visible = iscsi_boot_eth_attr_is_visible,
+};
+
+/* Initiator attrs */
+iscsi_boot_rd_attr(ini_index, index, ISCSI_BOOT_INI_INDEX);
+iscsi_boot_rd_attr(ini_flags, flags, ISCSI_BOOT_INI_FLAGS);
+iscsi_boot_rd_attr(ini_isns, isns-server, ISCSI_BOOT_INI_ISNS_SERVER);
+iscsi_boot_rd_attr(ini_slp, slp-server, ISCSI_BOOT_INI_SLP_SERVER);
+iscsi_boot_rd_attr(ini_primary_radius, pri-radius-server,
+ ISCSI_BOOT_INI_PRI_RADIUS_SERVER);
+iscsi_boot_rd_attr(ini_secondary_radius, sec-radius-server,
+ ISCSI_BOOT_INI_SEC_RADIUS_SERVER);
+iscsi_boot_rd_attr(ini_name, initiator-name, ISCSI_BOOT_INI_INITIATOR_NAME);
+
+static struct attribute *initiator_attrs[] = {
+ &iscsi_boot_attr_ini_index.attr,
+ &iscsi_boot_attr_ini_flags.attr,
+ &iscsi_boot_attr_ini_isns.attr,
+ &iscsi_boot_attr_ini_slp.attr,
+ &iscsi_boot_attr_ini_primary_radius.attr,
+ &iscsi_boot_attr_ini_secondary_radius.attr,
+ &iscsi_boot_attr_ini_name.attr,
+ NULL
+};
+
+static mode_t iscsi_boot_ini_attr_is_visible(struct kobject *kobj,
+ struct attribute *attr, int i)
+{
+ struct iscsi_boot_kobj *boot_kobj =
+ container_of(kobj, struct iscsi_boot_kobj, kobj);
+
+ if (attr == &iscsi_boot_attr_ini_index.attr)
+ return boot_kobj->is_visible(boot_kobj->data,
+ ISCSI_BOOT_INI_INDEX);
+ if (attr == &iscsi_boot_attr_ini_flags.attr)
+ return boot_kobj->is_visible(boot_kobj->data,
+ ISCSI_BOOT_INI_FLAGS);
+ if (attr == &iscsi_boot_attr_ini_isns.attr)
+ return boot_kobj->is_visible(boot_kobj->data,
+ ISCSI_BOOT_INI_ISNS_SERVER);
+ if (attr == &iscsi_boot_attr_ini_slp.attr)
+ return boot_kobj->is_visible(boot_kobj->data,
+ ISCSI_BOOT_INI_SLP_SERVER);
+ if (attr == &iscsi_boot_attr_ini_primary_radius.attr)
+ return boot_kobj->is_visible(boot_kobj->data,
+ ISCSI_BOOT_INI_PRI_RADIUS_SERVER);
+ if (attr == &iscsi_boot_attr_ini_secondary_radius.attr)
+ return boot_kobj->is_visible(boot_kobj->data,
+ ISCSI_BOOT_INI_SEC_RADIUS_SERVER);
+ if (attr == &iscsi_boot_attr_ini_name.attr)
+ return boot_kobj->is_visible(boot_kobj->data,
+ ISCSI_BOOT_INI_INITIATOR_NAME);
+
+ return 0;
+}
+
+static struct attribute_group iscsi_boot_initiator_attr_group = {
+ .attrs = initiator_attrs,
+ .is_visible = iscsi_boot_ini_attr_is_visible,
+};
+
+static struct iscsi_boot_kobj *
+iscsi_boot_create_kobj(struct iscsi_boot_kset *boot_kset,
+ struct attribute_group *attr_group,
+ const char *name, int index, void *data,
+ ssize_t (*show) (void *data, int type, char *buf),
+ mode_t (*is_visible) (void *data, int type))
+{
+ struct iscsi_boot_kobj *boot_kobj;
+
+ boot_kobj = kzalloc(sizeof(*boot_kobj), GFP_KERNEL);
+ if (!boot_kobj)
+ return NULL;
+ INIT_LIST_HEAD(&boot_kobj->list);
+
+ boot_kobj->kobj.kset = boot_kset->kset;
+ if (kobject_init_and_add(&boot_kobj->kobj, &iscsi_boot_ktype,
+ NULL, name, index)) {
+ kfree(boot_kobj);
+ return NULL;
+ }
+ boot_kobj->data = data;
+ boot_kobj->show = show;
+ boot_kobj->is_visible = is_visible;
+
+ if (sysfs_create_group(&boot_kobj->kobj, attr_group)) {
+ /*
+ * We do not want to free this because the caller
+ * will assume that since the creation call failed
+ * the boot kobj was not setup and the normal release
+ * path is not being run.
+ */
+ boot_kobj->data = NULL;
+ kobject_put(&boot_kobj->kobj);
+ return NULL;
+ }
+ boot_kobj->attr_group = attr_group;
+
+ kobject_uevent(&boot_kobj->kobj, KOBJ_ADD);
+ /* Nothing broke so lets add it to the list. */
+ list_add_tail(&boot_kobj->list, &boot_kset->kobj_list);
+ return boot_kobj;
+}
+
+static void iscsi_boot_remove_kobj(struct iscsi_boot_kobj *boot_kobj)
+{
+ list_del(&boot_kobj->list);
+ sysfs_remove_group(&boot_kobj->kobj, boot_kobj->attr_group);
+ kobject_put(&boot_kobj->kobj);
+}
+
+/**
+ * iscsi_boot_create_target() - create boot target sysfs dir
+ * @boot_kset: boot kset
+ * @index: the target id
+ * @data: driver specific data for target
+ * @show: attr show function
+ * @is_visible: attr visibility function
+ *
+ * Note: The boot sysfs lib will free the data passed in for the caller
+ * when all refs to the target kobject have been released.
+ */
+struct iscsi_boot_kobj *
+iscsi_boot_create_target(struct iscsi_boot_kset *boot_kset, int index,
+ void *data,
+ ssize_t (*show) (void *data, int type, char *buf),
+ mode_t (*is_visible) (void *data, int type))
+{
+ return iscsi_boot_create_kobj(boot_kset, &iscsi_boot_target_attr_group,
+ "target%d", index, data, show, is_visible);
+}
+EXPORT_SYMBOL_GPL(iscsi_boot_create_target);
+
+/**
+ * iscsi_boot_create_initiator() - create boot initiator sysfs dir
+ * @boot_kset: boot kset
+ * @index: the initiator id
+ * @data: driver specific data
+ * @show: attr show function
+ * @is_visible: attr visibility function
+ *
+ * Note: The boot sysfs lib will free the data passed in for the caller
+ * when all refs to the initiator kobject have been released.
+ */
+struct iscsi_boot_kobj *
+iscsi_boot_create_initiator(struct iscsi_boot_kset *boot_kset, int index,
+ void *data,
+ ssize_t (*show) (void *data, int type, char *buf),
+ mode_t (*is_visible) (void *data, int type))
+{
+ return iscsi_boot_create_kobj(boot_kset,
+ &iscsi_boot_initiator_attr_group,
+ "initiator", index, data, show,
+ is_visible);
+}
+EXPORT_SYMBOL_GPL(iscsi_boot_create_initiator);
+
+/**
+ * iscsi_boot_create_ethernet() - create boot ethernet sysfs dir
+ * @boot_kset: boot kset
+ * @index: the ethernet device id
+ * @data: driver specific data
+ * @show: attr show function
+ * @is_visible: attr visibility function
+ *
+ * Note: The boot sysfs lib will free the data passed in for the caller
+ * when all refs to the ethernet kobject have been released.
+ */
+struct iscsi_boot_kobj *
+iscsi_boot_create_ethernet(struct iscsi_boot_kset *boot_kset, int index,
+ void *data,
+ ssize_t (*show) (void *data, int type, char *buf),
+ mode_t (*is_visible) (void *data, int type))
+{
+ return iscsi_boot_create_kobj(boot_kset,
+ &iscsi_boot_ethernet_attr_group,
+ "ethernet%d", index, data, show,
+ is_visible);
+}
+EXPORT_SYMBOL_GPL(iscsi_boot_create_ethernet);
+
+/**
+ * iscsi_boot_create_kset() - creates root sysfs tree
+ * @set_name: name of root dir
+ */
+struct iscsi_boot_kset *iscsi_boot_create_kset(const char *set_name)
+{
+ struct iscsi_boot_kset *boot_kset;
+
+ boot_kset = kzalloc(sizeof(*boot_kset), GFP_KERNEL);
+ if (!boot_kset)
+ return NULL;
+
+ boot_kset->kset = kset_create_and_add(set_name, NULL, firmware_kobj);
+ if (!boot_kset->kset) {
+ kfree(boot_kset);
+ return NULL;
+ }
+
+ INIT_LIST_HEAD(&boot_kset->kobj_list);
+ return boot_kset;
+}
+EXPORT_SYMBOL_GPL(iscsi_boot_create_kset);
+
+/**
+ * iscsi_boot_create_host_kset() - creates root sysfs tree for a scsi host
+ * @hostno: host number of scsi host
+ */
+struct iscsi_boot_kset *iscsi_boot_create_host_kset(unsigned int hostno)
+{
+ struct iscsi_boot_kset *boot_kset;
+ char *set_name;
+
+ set_name = kasprintf(GFP_KERNEL, "iscsi_boot%u", hostno);
+ if (!set_name)
+ return NULL;
+
+ boot_kset = iscsi_boot_create_kset(set_name);
+ kfree(set_name);
+ return boot_kset;
+}
+EXPORT_SYMBOL_GPL(iscsi_boot_create_host_kset);
+
+/**
+ * iscsi_boot_destroy_kset() - destroy kset and kobjects under it
+ * @boot_kset: boot kset
+ *
+ * This will remove the kset and kobjects and attrs under it.
+ */
+void iscsi_boot_destroy_kset(struct iscsi_boot_kset *boot_kset)
+{
+ struct iscsi_boot_kobj *boot_kobj, *tmp_kobj;
+
+ list_for_each_entry_safe(boot_kobj, tmp_kobj,
+ &boot_kset->kobj_list, list)
+ iscsi_boot_remove_kobj(boot_kobj);
+
+ kset_unregister(boot_kset->kset);
+}
+EXPORT_SYMBOL_GPL(iscsi_boot_destroy_kset);
diff --git a/drivers/firmware/iscsi_ibft.c b/drivers/firmware/iscsi_ibft.c
index ed2801c378d..4f04ec0410a 100644
--- a/drivers/firmware/iscsi_ibft.c
+++ b/drivers/firmware/iscsi_ibft.c
@@ -1,5 +1,5 @@
/*
- * Copyright 2007 Red Hat, Inc.
+ * Copyright 2007-2010 Red Hat, Inc.
* by Peter Jones <pjones@redhat.com>
* Copyright 2008 IBM, Inc.
* by Konrad Rzeszutek <konradr@linux.vnet.ibm.com>
@@ -19,6 +19,9 @@
*
* Changelog:
*
+ * 06 Jan 2010 - Peter Jones <pjones@redhat.com>
+ * New changelog entries are in the git log from now on. Not here.
+ *
* 14 Mar 2008 - Konrad Rzeszutek <ketuzsezr@darnok.org>
* Updated comments and copyrights. (v0.4.9)
*
@@ -78,9 +81,11 @@
#include <linux/stat.h>
#include <linux/string.h>
#include <linux/types.h>
+#include <linux/acpi.h>
+#include <linux/iscsi_boot_sysfs.h>
-#define IBFT_ISCSI_VERSION "0.4.9"
-#define IBFT_ISCSI_DATE "2008-Mar-14"
+#define IBFT_ISCSI_VERSION "0.5.0"
+#define IBFT_ISCSI_DATE "2010-Feb-25"
MODULE_AUTHOR("Peter Jones <pjones@redhat.com> and \
Konrad Rzeszutek <ketuzsezr@darnok.org>");
@@ -166,108 +171,20 @@ enum ibft_id {
};
/*
- * We do not support the other types, hence the usage of NULL.
- * This maps to the enum ibft_id.
- */
-static const char *ibft_id_names[] =
- {NULL, NULL, "initiator", "ethernet%d", "target%d", NULL, NULL};
-
-/*
- * The text attributes names for each of the kobjects.
-*/
-enum ibft_eth_properties_enum {
- ibft_eth_index,
- ibft_eth_flags,
- ibft_eth_ip_addr,
- ibft_eth_subnet_mask,
- ibft_eth_origin,
- ibft_eth_gateway,
- ibft_eth_primary_dns,
- ibft_eth_secondary_dns,
- ibft_eth_dhcp,
- ibft_eth_vlan,
- ibft_eth_mac,
- /* ibft_eth_pci_bdf - this is replaced by link to the device itself. */
- ibft_eth_hostname,
- ibft_eth_end_marker,
-};
-
-static const char *ibft_eth_properties[] =
- {"index", "flags", "ip-addr", "subnet-mask", "origin", "gateway",
- "primary-dns", "secondary-dns", "dhcp", "vlan", "mac", "hostname",
- NULL};
-
-enum ibft_tgt_properties_enum {
- ibft_tgt_index,
- ibft_tgt_flags,
- ibft_tgt_ip_addr,
- ibft_tgt_port,
- ibft_tgt_lun,
- ibft_tgt_chap_type,
- ibft_tgt_nic_assoc,
- ibft_tgt_name,
- ibft_tgt_chap_name,
- ibft_tgt_chap_secret,
- ibft_tgt_rev_chap_name,
- ibft_tgt_rev_chap_secret,
- ibft_tgt_end_marker,
-};
-
-static const char *ibft_tgt_properties[] =
- {"index", "flags", "ip-addr", "port", "lun", "chap-type", "nic-assoc",
- "target-name", "chap-name", "chap-secret", "rev-chap-name",
- "rev-chap-name-secret", NULL};
-
-enum ibft_initiator_properties_enum {
- ibft_init_index,
- ibft_init_flags,
- ibft_init_isns_server,
- ibft_init_slp_server,
- ibft_init_pri_radius_server,
- ibft_init_sec_radius_server,
- ibft_init_initiator_name,
- ibft_init_end_marker,
-};
-
-static const char *ibft_initiator_properties[] =
- {"index", "flags", "isns-server", "slp-server", "pri-radius-server",
- "sec-radius-server", "initiator-name", NULL};
-
-/*
* The kobject and attribute structures.
*/
struct ibft_kobject {
- struct ibft_table_header *header;
+ struct acpi_table_ibft *header;
union {
struct ibft_initiator *initiator;
struct ibft_nic *nic;
struct ibft_tgt *tgt;
struct ibft_hdr *hdr;
};
- struct kobject kobj;
- struct list_head node;
};
-struct ibft_attribute {
- struct attribute attr;
- ssize_t (*show) (struct ibft_kobject *entry,
- struct ibft_attribute *attr, char *buf);
- union {
- struct ibft_initiator *initiator;
- struct ibft_nic *nic;
- struct ibft_tgt *tgt;
- struct ibft_hdr *hdr;
- };
- struct kobject *kobj;
- int type; /* The enum of the type. This can be any value of:
- ibft_eth_properties_enum, ibft_tgt_properties_enum,
- or ibft_initiator_properties_enum. */
- struct list_head node;
-};
-
-static LIST_HEAD(ibft_attr_list);
-static LIST_HEAD(ibft_kobject_list);
+static struct iscsi_boot_kset *boot_kset;
static const char nulls[16];
@@ -306,35 +223,27 @@ static ssize_t sprintf_string(char *str, int len, char *buf)
static int ibft_verify_hdr(char *t, struct ibft_hdr *hdr, int id, int length)
{
if (hdr->id != id) {
- printk(KERN_ERR "iBFT error: We expected the " \
+ printk(KERN_ERR "iBFT error: We expected the %s " \
"field header.id to have %d but " \
- "found %d instead!\n", id, hdr->id);
+ "found %d instead!\n", t, id, hdr->id);
return -ENODEV;
}
if (hdr->length != length) {
- printk(KERN_ERR "iBFT error: We expected the " \
+ printk(KERN_ERR "iBFT error: We expected the %s " \
"field header.length to have %d but " \
- "found %d instead!\n", length, hdr->length);
+ "found %d instead!\n", t, length, hdr->length);
return -ENODEV;
}
return 0;
}
-static void ibft_release(struct kobject *kobj)
-{
- struct ibft_kobject *ibft =
- container_of(kobj, struct ibft_kobject, kobj);
- kfree(ibft);
-}
-
/*
* Routines for parsing the iBFT data to be human readable.
*/
-static ssize_t ibft_attr_show_initiator(struct ibft_kobject *entry,
- struct ibft_attribute *attr,
- char *buf)
+static ssize_t ibft_attr_show_initiator(void *data, int type, char *buf)
{
+ struct ibft_kobject *entry = data;
struct ibft_initiator *initiator = entry->initiator;
void *ibft_loc = entry->header;
char *str = buf;
@@ -342,26 +251,26 @@ static ssize_t ibft_attr_show_initiator(struct ibft_kobject *entry,
if (!initiator)
return 0;
- switch (attr->type) {
- case ibft_init_index:
+ switch (type) {
+ case ISCSI_BOOT_INI_INDEX:
str += sprintf(str, "%d\n", initiator->hdr.index);
break;
- case ibft_init_flags:
+ case ISCSI_BOOT_INI_FLAGS:
str += sprintf(str, "%d\n", initiator->hdr.flags);
break;
- case ibft_init_isns_server:
+ case ISCSI_BOOT_INI_ISNS_SERVER:
str += sprintf_ipaddr(str, initiator->isns_server);
break;
- case ibft_init_slp_server:
+ case ISCSI_BOOT_INI_SLP_SERVER:
str += sprintf_ipaddr(str, initiator->slp_server);
break;
- case ibft_init_pri_radius_server:
+ case ISCSI_BOOT_INI_PRI_RADIUS_SERVER:
str += sprintf_ipaddr(str, initiator->pri_radius_server);
break;
- case ibft_init_sec_radius_server:
+ case ISCSI_BOOT_INI_SEC_RADIUS_SERVER:
str += sprintf_ipaddr(str, initiator->sec_radius_server);
break;
- case ibft_init_initiator_name:
+ case ISCSI_BOOT_INI_INITIATOR_NAME:
str += sprintf_string(str, initiator->initiator_name_len,
(char *)ibft_loc +
initiator->initiator_name_off);
@@ -373,10 +282,9 @@ static ssize_t ibft_attr_show_initiator(struct ibft_kobject *entry,
return str - buf;
}
-static ssize_t ibft_attr_show_nic(struct ibft_kobject *entry,
- struct ibft_attribute *attr,
- char *buf)
+static ssize_t ibft_attr_show_nic(void *data, int type, char *buf)
{
+ struct ibft_kobject *entry = data;
struct ibft_nic *nic = entry->nic;
void *ibft_loc = entry->header;
char *str = buf;
@@ -385,42 +293,42 @@ static ssize_t ibft_attr_show_nic(struct ibft_kobject *entry,
if (!nic)
return 0;
- switch (attr->type) {
- case ibft_eth_index:
+ switch (type) {
+ case ISCSI_BOOT_ETH_INDEX:
str += sprintf(str, "%d\n", nic->hdr.index);
break;
- case ibft_eth_flags:
+ case ISCSI_BOOT_ETH_FLAGS:
str += sprintf(str, "%d\n", nic->hdr.flags);
break;
- case ibft_eth_ip_addr:
+ case ISCSI_BOOT_ETH_IP_ADDR:
str += sprintf_ipaddr(str, nic->ip_addr);
break;
- case ibft_eth_subnet_mask:
+ case ISCSI_BOOT_ETH_SUBNET_MASK:
val = cpu_to_be32(~((1 << (32-nic->subnet_mask_prefix))-1));
str += sprintf(str, "%pI4", &val);
break;
- case ibft_eth_origin:
+ case ISCSI_BOOT_ETH_ORIGIN:
str += sprintf(str, "%d\n", nic->origin);
break;
- case ibft_eth_gateway:
+ case ISCSI_BOOT_ETH_GATEWAY:
str += sprintf_ipaddr(str, nic->gateway);
break;
- case ibft_eth_primary_dns:
+ case ISCSI_BOOT_ETH_PRIMARY_DNS:
str += sprintf_ipaddr(str, nic->primary_dns);
break;
- case ibft_eth_secondary_dns:
+ case ISCSI_BOOT_ETH_SECONDARY_DNS:
str += sprintf_ipaddr(str, nic->secondary_dns);
break;
- case ibft_eth_dhcp:
+ case ISCSI_BOOT_ETH_DHCP:
str += sprintf_ipaddr(str, nic->dhcp);
break;
- case ibft_eth_vlan:
+ case ISCSI_BOOT_ETH_VLAN:
str += sprintf(str, "%d\n", nic->vlan);
break;
- case ibft_eth_mac:
+ case ISCSI_BOOT_ETH_MAC:
str += sprintf(str, "%pM\n", nic->mac);
break;
- case ibft_eth_hostname:
+ case ISCSI_BOOT_ETH_HOSTNAME:
str += sprintf_string(str, nic->hostname_len,
(char *)ibft_loc + nic->hostname_off);
break;
@@ -431,10 +339,9 @@ static ssize_t ibft_attr_show_nic(struct ibft_kobject *entry,
return str - buf;
};
-static ssize_t ibft_attr_show_target(struct ibft_kobject *entry,
- struct ibft_attribute *attr,
- char *buf)
+static ssize_t ibft_attr_show_target(void *data, int type, char *buf)
{
+ struct ibft_kobject *entry = data;
struct ibft_tgt *tgt = entry->tgt;
void *ibft_loc = entry->header;
char *str = buf;
@@ -443,48 +350,48 @@ static ssize_t ibft_attr_show_target(struct ibft_kobject *entry,
if (!tgt)
return 0;
- switch (attr->type) {
- case ibft_tgt_index:
+ switch (type) {
+ case ISCSI_BOOT_TGT_INDEX:
str += sprintf(str, "%d\n", tgt->hdr.index);
break;
- case ibft_tgt_flags:
+ case ISCSI_BOOT_TGT_FLAGS:
str += sprintf(str, "%d\n", tgt->hdr.flags);
break;
- case ibft_tgt_ip_addr:
+ case ISCSI_BOOT_TGT_IP_ADDR:
str += sprintf_ipaddr(str, tgt->ip_addr);
break;
- case ibft_tgt_port:
+ case ISCSI_BOOT_TGT_PORT:
str += sprintf(str, "%d\n", tgt->port);
break;
- case ibft_tgt_lun:
+ case ISCSI_BOOT_TGT_LUN:
for (i = 0; i < 8; i++)
str += sprintf(str, "%x", (u8)tgt->lun[i]);
str += sprintf(str, "\n");
break;
- case ibft_tgt_nic_assoc:
+ case ISCSI_BOOT_TGT_NIC_ASSOC:
str += sprintf(str, "%d\n", tgt->nic_assoc);
break;
- case ibft_tgt_chap_type:
+ case ISCSI_BOOT_TGT_CHAP_TYPE:
str += sprintf(str, "%d\n", tgt->chap_type);
break;
- case ibft_tgt_name:
+ case ISCSI_BOOT_TGT_NAME:
str += sprintf_string(str, tgt->tgt_name_len,
(char *)ibft_loc + tgt->tgt_name_off);
break;
- case ibft_tgt_chap_name:
+ case ISCSI_BOOT_TGT_CHAP_NAME:
str += sprintf_string(str, tgt->chap_name_len,
(char *)ibft_loc + tgt->chap_name_off);
break;
- case ibft_tgt_chap_secret:
+ case ISCSI_BOOT_TGT_CHAP_SECRET:
str += sprintf_string(str, tgt->chap_secret_len,
(char *)ibft_loc + tgt->chap_secret_off);
break;
- case ibft_tgt_rev_chap_name:
+ case ISCSI_BOOT_TGT_REV_CHAP_NAME:
str += sprintf_string(str, tgt->rev_chap_name_len,
(char *)ibft_loc +
tgt->rev_chap_name_off);
break;
- case ibft_tgt_rev_chap_secret:
+ case ISCSI_BOOT_TGT_REV_CHAP_SECRET:
str += sprintf_string(str, tgt->rev_chap_secret_len,
(char *)ibft_loc +
tgt->rev_chap_secret_off);
@@ -496,52 +403,19 @@ static ssize_t ibft_attr_show_target(struct ibft_kobject *entry,
return str - buf;
}
-/*
- * The routine called for all sysfs attributes.
- */
-static ssize_t ibft_show_attribute(struct kobject *kobj,
- struct attribute *attr,
- char *buf)
-{
- struct ibft_kobject *dev =
- container_of(kobj, struct ibft_kobject, kobj);
- struct ibft_attribute *ibft_attr =
- container_of(attr, struct ibft_attribute, attr);
- ssize_t ret = -EIO;
- char *str = buf;
-
- if (!capable(CAP_SYS_ADMIN))
- return -EACCES;
-
- if (ibft_attr->show)
- ret = ibft_attr->show(dev, ibft_attr, str);
-
- return ret;
-}
-
-static const struct sysfs_ops ibft_attr_ops = {
- .show = ibft_show_attribute,
-};
-
-static struct kobj_type ibft_ktype = {
- .release = ibft_release,
- .sysfs_ops = &ibft_attr_ops,
-};
-
-static struct kset *ibft_kset;
-
static int __init ibft_check_device(void)
{
int len;
u8 *pos;
u8 csum = 0;
- len = ibft_addr->length;
+ len = ibft_addr->header.length;
/* Sanity checking of iBFT. */
- if (ibft_addr->revision != 1) {
+ if (ibft_addr->header.revision != 1) {
printk(KERN_ERR "iBFT module supports only revision 1, " \
- "while this is %d.\n", ibft_addr->revision);
+ "while this is %d.\n",
+ ibft_addr->header.revision);
return -ENOENT;
}
for (pos = (u8 *)ibft_addr; pos < (u8 *)ibft_addr + len; pos++)
@@ -556,12 +430,149 @@ static int __init ibft_check_device(void)
}
/*
+ * Helper routiners to check to determine if the entry is valid
+ * in the proper iBFT structure.
+ */
+static mode_t ibft_check_nic_for(void *data, int type)
+{
+ struct ibft_kobject *entry = data;
+ struct ibft_nic *nic = entry->nic;
+ mode_t rc = 0;
+
+ switch (type) {
+ case ISCSI_BOOT_ETH_INDEX:
+ case ISCSI_BOOT_ETH_FLAGS:
+ rc = S_IRUGO;
+ break;
+ case ISCSI_BOOT_ETH_IP_ADDR:
+ if (memcmp(nic->ip_addr, nulls, sizeof(nic->ip_addr)))
+ rc = S_IRUGO;
+ break;
+ case ISCSI_BOOT_ETH_SUBNET_MASK:
+ if (nic->subnet_mask_prefix)
+ rc = S_IRUGO;
+ break;
+ case ISCSI_BOOT_ETH_ORIGIN:
+ rc = S_IRUGO;
+ break;
+ case ISCSI_BOOT_ETH_GATEWAY:
+ if (memcmp(nic->gateway, nulls, sizeof(nic->gateway)))
+ rc = S_IRUGO;
+ break;
+ case ISCSI_BOOT_ETH_PRIMARY_DNS:
+ if (memcmp(nic->primary_dns, nulls,
+ sizeof(nic->primary_dns)))
+ rc = S_IRUGO;
+ break;
+ case ISCSI_BOOT_ETH_SECONDARY_DNS:
+ if (memcmp(nic->secondary_dns, nulls,
+ sizeof(nic->secondary_dns)))
+ rc = S_IRUGO;
+ break;
+ case ISCSI_BOOT_ETH_DHCP:
+ if (memcmp(nic->dhcp, nulls, sizeof(nic->dhcp)))
+ rc = S_IRUGO;
+ break;
+ case ISCSI_BOOT_ETH_VLAN:
+ case ISCSI_BOOT_ETH_MAC:
+ rc = S_IRUGO;
+ break;
+ case ISCSI_BOOT_ETH_HOSTNAME:
+ if (nic->hostname_off)
+ rc = S_IRUGO;
+ break;
+ default:
+ break;
+ }
+
+ return rc;
+}
+
+static mode_t __init ibft_check_tgt_for(void *data, int type)
+{
+ struct ibft_kobject *entry = data;
+ struct ibft_tgt *tgt = entry->tgt;
+ mode_t rc = 0;
+
+ switch (type) {
+ case ISCSI_BOOT_TGT_INDEX:
+ case ISCSI_BOOT_TGT_FLAGS:
+ case ISCSI_BOOT_TGT_IP_ADDR:
+ case ISCSI_BOOT_TGT_PORT:
+ case ISCSI_BOOT_TGT_LUN:
+ case ISCSI_BOOT_TGT_NIC_ASSOC:
+ case ISCSI_BOOT_TGT_CHAP_TYPE:
+ rc = S_IRUGO;
+ case ISCSI_BOOT_TGT_NAME:
+ if (tgt->tgt_name_len)
+ rc = S_IRUGO;
+ break;
+ case ISCSI_BOOT_TGT_CHAP_NAME:
+ case ISCSI_BOOT_TGT_CHAP_SECRET:
+ if (tgt->chap_name_len)
+ rc = S_IRUGO;
+ break;
+ case ISCSI_BOOT_TGT_REV_CHAP_NAME:
+ case ISCSI_BOOT_TGT_REV_CHAP_SECRET:
+ if (tgt->rev_chap_name_len)
+ rc = S_IRUGO;
+ break;
+ default:
+ break;
+ }
+
+ return rc;
+}
+
+static mode_t __init ibft_check_initiator_for(void *data, int type)
+{
+ struct ibft_kobject *entry = data;
+ struct ibft_initiator *init = entry->initiator;
+ mode_t rc = 0;
+
+ switch (type) {
+ case ISCSI_BOOT_INI_INDEX:
+ case ISCSI_BOOT_INI_FLAGS:
+ rc = S_IRUGO;
+ break;
+ case ISCSI_BOOT_INI_ISNS_SERVER:
+ if (memcmp(init->isns_server, nulls,
+ sizeof(init->isns_server)))
+ rc = S_IRUGO;
+ break;
+ case ISCSI_BOOT_INI_SLP_SERVER:
+ if (memcmp(init->slp_server, nulls,
+ sizeof(init->slp_server)))
+ rc = S_IRUGO;
+ break;
+ case ISCSI_BOOT_INI_PRI_RADIUS_SERVER:
+ if (memcmp(init->pri_radius_server, nulls,
+ sizeof(init->pri_radius_server)))
+ rc = S_IRUGO;
+ break;
+ case ISCSI_BOOT_INI_SEC_RADIUS_SERVER:
+ if (memcmp(init->sec_radius_server, nulls,
+ sizeof(init->sec_radius_server)))
+ rc = S_IRUGO;
+ break;
+ case ISCSI_BOOT_INI_INITIATOR_NAME:
+ if (init->initiator_name_len)
+ rc = S_IRUGO;
+ break;
+ default:
+ break;
+ }
+
+ return rc;
+}
+
+/*
* Helper function for ibft_register_kobjects.
*/
-static int __init ibft_create_kobject(struct ibft_table_header *header,
- struct ibft_hdr *hdr,
- struct list_head *list)
+static int __init ibft_create_kobject(struct acpi_table_ibft *header,
+ struct ibft_hdr *hdr)
{
+ struct iscsi_boot_kobj *boot_kobj = NULL;
struct ibft_kobject *ibft_kobj = NULL;
struct ibft_nic *nic = (struct ibft_nic *)hdr;
struct pci_dev *pci_dev;
@@ -578,14 +589,47 @@ static int __init ibft_create_kobject(struct ibft_table_header *header,
case id_initiator:
rc = ibft_verify_hdr("initiator", hdr, id_initiator,
sizeof(*ibft_kobj->initiator));
+ if (rc)
+ break;
+
+ boot_kobj = iscsi_boot_create_initiator(boot_kset, hdr->index,
+ ibft_kobj,
+ ibft_attr_show_initiator,
+ ibft_check_initiator_for);
+ if (!boot_kobj) {
+ rc = -ENOMEM;
+ goto free_ibft_obj;
+ }
break;
case id_nic:
rc = ibft_verify_hdr("ethernet", hdr, id_nic,
sizeof(*ibft_kobj->nic));
+ if (rc)
+ break;
+
+ boot_kobj = iscsi_boot_create_ethernet(boot_kset, hdr->index,
+ ibft_kobj,
+ ibft_attr_show_nic,
+ ibft_check_nic_for);
+ if (!boot_kobj) {
+ rc = -ENOMEM;
+ goto free_ibft_obj;
+ }
break;
case id_target:
rc = ibft_verify_hdr("target", hdr, id_target,
sizeof(*ibft_kobj->tgt));
+ if (rc)
+ break;
+
+ boot_kobj = iscsi_boot_create_target(boot_kset, hdr->index,
+ ibft_kobj,
+ ibft_attr_show_target,
+ ibft_check_tgt_for);
+ if (!boot_kobj) {
+ rc = -ENOMEM;
+ goto free_ibft_obj;
+ }
break;
case id_reserved:
case id_control:
@@ -596,29 +640,17 @@ static int __init ibft_create_kobject(struct ibft_table_header *header,
default:
printk(KERN_ERR "iBFT has unknown structure type (%d). " \
"Report this bug to %.6s!\n", hdr->id,
- header->oem_id);
+ header->header.oem_id);
rc = 1;
break;
}
if (rc) {
/* Skip adding this kobject, but exit with non-fatal error. */
- kfree(ibft_kobj);
- goto out_invalid_struct;
+ rc = 0;
+ goto free_ibft_obj;
}
- ibft_kobj->kobj.kset = ibft_kset;
-
- rc = kobject_init_and_add(&ibft_kobj->kobj, &ibft_ktype,
- NULL, ibft_id_names[hdr->id], hdr->index);
-
- if (rc) {
- kfree(ibft_kobj);
- goto out;
- }
-
- kobject_uevent(&ibft_kobj->kobj, KOBJ_ADD);
-
if (hdr->id == id_nic) {
/*
* We don't search for the device in other domains than
@@ -629,19 +661,16 @@ static int __init ibft_create_kobject(struct ibft_table_header *header,
pci_dev = pci_get_bus_and_slot((nic->pci_bdf & 0xff00) >> 8,
(nic->pci_bdf & 0xff));
if (pci_dev) {
- rc = sysfs_create_link(&ibft_kobj->kobj,
+ rc = sysfs_create_link(&boot_kobj->kobj,
&pci_dev->dev.kobj, "device");
pci_dev_put(pci_dev);
}
}
+ return 0;
- /* Nothing broke so lets add it to the list. */
- list_add_tail(&ibft_kobj->node, list);
-out:
+free_ibft_obj:
+ kfree(ibft_kobj);
return rc;
-out_invalid_struct:
- /* Unsupported structs are skipped. */
- return 0;
}
/*
@@ -649,8 +678,7 @@ out_invalid_struct:
* found add them on the passed-in list. We do not support the other
* fields at this point, so they are skipped.
*/
-static int __init ibft_register_kobjects(struct ibft_table_header *header,
- struct list_head *list)
+static int __init ibft_register_kobjects(struct acpi_table_ibft *header)
{
struct ibft_control *control = NULL;
void *ptr, *end;
@@ -660,7 +688,7 @@ static int __init ibft_register_kobjects(struct ibft_table_header *header,
control = (void *)header + sizeof(*header);
end = (void *)control + control->hdr.length;
- eot_offset = (void *)header + header->length - (void *)control;
+ eot_offset = (void *)header + header->header.length - (void *)control;
rc = ibft_verify_hdr("control", (struct ibft_hdr *)control, id_control,
sizeof(*control));
@@ -672,10 +700,10 @@ static int __init ibft_register_kobjects(struct ibft_table_header *header,
}
for (ptr = &control->initiator_off; ptr < end; ptr += sizeof(u16)) {
offset = *(u16 *)ptr;
- if (offset && offset < header->length && offset < eot_offset) {
+ if (offset && offset < header->header.length &&
+ offset < eot_offset) {
rc = ibft_create_kobject(header,
- (void *)header + offset,
- list);
+ (void *)header + offset);
if (rc)
break;
}
@@ -684,240 +712,28 @@ static int __init ibft_register_kobjects(struct ibft_table_header *header,
return rc;
}
-static void ibft_unregister(struct list_head *attr_list,
- struct list_head *kobj_list)
+static void ibft_unregister(void)
{
- struct ibft_kobject *data = NULL, *n;
- struct ibft_attribute *attr = NULL, *m;
-
- list_for_each_entry_safe(attr, m, attr_list, node) {
- sysfs_remove_file(attr->kobj, &attr->attr);
- list_del(&attr->node);
- kfree(attr);
+ struct iscsi_boot_kobj *boot_kobj, *tmp_kobj;
+ struct ibft_kobject *ibft_kobj;
+
+ list_for_each_entry_safe(boot_kobj, tmp_kobj,
+ &boot_kset->kobj_list, list) {
+ ibft_kobj = boot_kobj->data;
+ if (ibft_kobj->hdr->id == id_nic)
+ sysfs_remove_link(&boot_kobj->kobj, "device");
};
- list_del_init(attr_list);
-
- list_for_each_entry_safe(data, n, kobj_list, node) {
- list_del(&data->node);
- if (data->hdr->id == id_nic)
- sysfs_remove_link(&data->kobj, "device");
- kobject_put(&data->kobj);
- };
- list_del_init(kobj_list);
}
-static int __init ibft_create_attribute(struct ibft_kobject *kobj_data,
- int type,
- const char *name,
- ssize_t (*show)(struct ibft_kobject *,
- struct ibft_attribute*,
- char *buf),
- struct list_head *list)
+static void ibft_cleanup(void)
{
- struct ibft_attribute *attr = NULL;
- struct ibft_hdr *hdr = kobj_data->hdr;
-
- attr = kmalloc(sizeof(*attr), GFP_KERNEL);
- if (!attr)
- return -ENOMEM;
-
- attr->attr.name = name;
- attr->attr.mode = S_IRUSR;
-
- attr->hdr = hdr;
- attr->show = show;
- attr->kobj = &kobj_data->kobj;
- attr->type = type;
-
- list_add_tail(&attr->node, list);
-
- return 0;
-}
-
-/*
- * Helper routiners to check to determine if the entry is valid
- * in the proper iBFT structure.
- */
-static int __init ibft_check_nic_for(struct ibft_nic *nic, int entry)
-{
- int rc = 0;
-
- switch (entry) {
- case ibft_eth_index:
- case ibft_eth_flags:
- rc = 1;
- break;
- case ibft_eth_ip_addr:
- if (memcmp(nic->ip_addr, nulls, sizeof(nic->ip_addr)))
- rc = 1;
- break;
- case ibft_eth_subnet_mask:
- if (nic->subnet_mask_prefix)
- rc = 1;
- break;
- case ibft_eth_origin:
- rc = 1;
- break;
- case ibft_eth_gateway:
- if (memcmp(nic->gateway, nulls, sizeof(nic->gateway)))
- rc = 1;
- break;
- case ibft_eth_primary_dns:
- if (memcmp(nic->primary_dns, nulls,
- sizeof(nic->primary_dns)))
- rc = 1;
- break;
- case ibft_eth_secondary_dns:
- if (memcmp(nic->secondary_dns, nulls,
- sizeof(nic->secondary_dns)))
- rc = 1;
- break;
- case ibft_eth_dhcp:
- if (memcmp(nic->dhcp, nulls, sizeof(nic->dhcp)))
- rc = 1;
- break;
- case ibft_eth_vlan:
- case ibft_eth_mac:
- rc = 1;
- break;
- case ibft_eth_hostname:
- if (nic->hostname_off)
- rc = 1;
- break;
- default:
- break;
- }
-
- return rc;
+ ibft_unregister();
+ iscsi_boot_destroy_kset(boot_kset);
}
-static int __init ibft_check_tgt_for(struct ibft_tgt *tgt, int entry)
-{
- int rc = 0;
-
- switch (entry) {
- case ibft_tgt_index:
- case ibft_tgt_flags:
- case ibft_tgt_ip_addr:
- case ibft_tgt_port:
- case ibft_tgt_lun:
- case ibft_tgt_nic_assoc:
- case ibft_tgt_chap_type:
- rc = 1;
- case ibft_tgt_name:
- if (tgt->tgt_name_len)
- rc = 1;
- break;
- case ibft_tgt_chap_name:
- case ibft_tgt_chap_secret:
- if (tgt->chap_name_len)
- rc = 1;
- break;
- case ibft_tgt_rev_chap_name:
- case ibft_tgt_rev_chap_secret:
- if (tgt->rev_chap_name_len)
- rc = 1;
- break;
- default:
- break;
- }
-
- return rc;
-}
-
-static int __init ibft_check_initiator_for(struct ibft_initiator *init,
- int entry)
-{
- int rc = 0;
-
- switch (entry) {
- case ibft_init_index:
- case ibft_init_flags:
- rc = 1;
- break;
- case ibft_init_isns_server:
- if (memcmp(init->isns_server, nulls,
- sizeof(init->isns_server)))
- rc = 1;
- break;
- case ibft_init_slp_server:
- if (memcmp(init->slp_server, nulls,
- sizeof(init->slp_server)))
- rc = 1;
- break;
- case ibft_init_pri_radius_server:
- if (memcmp(init->pri_radius_server, nulls,
- sizeof(init->pri_radius_server)))
- rc = 1;
- break;
- case ibft_init_sec_radius_server:
- if (memcmp(init->sec_radius_server, nulls,
- sizeof(init->sec_radius_server)))
- rc = 1;
- break;
- case ibft_init_initiator_name:
- if (init->initiator_name_len)
- rc = 1;
- break;
- default:
- break;
- }
-
- return rc;
-}
-
-/*
- * Register the attributes for all of the kobjects.
- */
-static int __init ibft_register_attributes(struct list_head *kobject_list,
- struct list_head *attr_list)
+static void __exit ibft_exit(void)
{
- int rc = 0, i = 0;
- struct ibft_kobject *data = NULL;
- struct ibft_attribute *attr = NULL, *m;
-
- list_for_each_entry(data, kobject_list, node) {
- switch (data->hdr->id) {
- case id_nic:
- for (i = 0; i < ibft_eth_end_marker && !rc; i++)
- if (ibft_check_nic_for(data->nic, i))
- rc = ibft_create_attribute(data, i,
- ibft_eth_properties[i],
- ibft_attr_show_nic, attr_list);
- break;
- case id_target:
- for (i = 0; i < ibft_tgt_end_marker && !rc; i++)
- if (ibft_check_tgt_for(data->tgt, i))
- rc = ibft_create_attribute(data, i,
- ibft_tgt_properties[i],
- ibft_attr_show_target,
- attr_list);
- break;
- case id_initiator:
- for (i = 0; i < ibft_init_end_marker && !rc; i++)
- if (ibft_check_initiator_for(
- data->initiator, i))
- rc = ibft_create_attribute(data, i,
- ibft_initiator_properties[i],
- ibft_attr_show_initiator,
- attr_list);
- break;
- default:
- break;
- }
- if (rc)
- break;
- }
- list_for_each_entry_safe(attr, m, attr_list, node) {
- rc = sysfs_create_file(attr->kobj, &attr->attr);
- if (rc) {
- list_del(&attr->node);
- kfree(attr);
- break;
- }
- }
-
- return rc;
+ ibft_cleanup();
}
/*
@@ -927,26 +743,20 @@ static int __init ibft_init(void)
{
int rc = 0;
- ibft_kset = kset_create_and_add("ibft", NULL, firmware_kobj);
- if (!ibft_kset)
- return -ENOMEM;
-
if (ibft_addr) {
printk(KERN_INFO "iBFT detected at 0x%llx.\n",
(u64)isa_virt_to_bus(ibft_addr));
rc = ibft_check_device();
if (rc)
- goto out_firmware_unregister;
+ return rc;
- /* Scan the IBFT for data and register the kobjects. */
- rc = ibft_register_kobjects(ibft_addr, &ibft_kobject_list);
- if (rc)
- goto out_free;
+ boot_kset = iscsi_boot_create_kset("ibft");
+ if (!boot_kset)
+ return -ENOMEM;
- /* Register the attributes */
- rc = ibft_register_attributes(&ibft_kobject_list,
- &ibft_attr_list);
+ /* Scan the IBFT for data and register the kobjects. */
+ rc = ibft_register_kobjects(ibft_addr);
if (rc)
goto out_free;
} else
@@ -955,17 +765,9 @@ static int __init ibft_init(void)
return 0;
out_free:
- ibft_unregister(&ibft_attr_list, &ibft_kobject_list);
-out_firmware_unregister:
- kset_unregister(ibft_kset);
+ ibft_cleanup();
return rc;
}
-static void __exit ibft_exit(void)
-{
- ibft_unregister(&ibft_attr_list, &ibft_kobject_list);
- kset_unregister(ibft_kset);
-}
-
module_init(ibft_init);
module_exit(ibft_exit);
diff --git a/drivers/firmware/iscsi_ibft_find.c b/drivers/firmware/iscsi_ibft_find.c
index d6470ef36e4..2192456dfd6 100644
--- a/drivers/firmware/iscsi_ibft_find.c
+++ b/drivers/firmware/iscsi_ibft_find.c
@@ -1,5 +1,5 @@
/*
- * Copyright 2007 Red Hat, Inc.
+ * Copyright 2007-2010 Red Hat, Inc.
* by Peter Jones <pjones@redhat.com>
* Copyright 2007 IBM, Inc.
* by Konrad Rzeszutek <konradr@linux.vnet.ibm.com>
@@ -22,6 +22,7 @@
#include <linux/blkdev.h>
#include <linux/ctype.h>
#include <linux/device.h>
+#include <linux/efi.h>
#include <linux/err.h>
#include <linux/init.h>
#include <linux/limits.h>
@@ -30,13 +31,15 @@
#include <linux/stat.h>
#include <linux/string.h>
#include <linux/types.h>
+#include <linux/acpi.h>
+#include <linux/iscsi_ibft.h>
#include <asm/mmzone.h>
/*
* Physical location of iSCSI Boot Format Table.
*/
-struct ibft_table_header *ibft_addr;
+struct acpi_table_ibft *ibft_addr;
EXPORT_SYMBOL_GPL(ibft_addr);
#define IBFT_SIGN "iBFT"
@@ -46,19 +49,20 @@ EXPORT_SYMBOL_GPL(ibft_addr);
#define VGA_MEM 0xA0000 /* VGA buffer */
#define VGA_SIZE 0x20000 /* 128kB */
+#ifdef CONFIG_ACPI
+static int __init acpi_find_ibft(struct acpi_table_header *header)
+{
+ ibft_addr = (struct acpi_table_ibft *)header;
+ return 0;
+}
+#endif /* CONFIG_ACPI */
-/*
- * Routine used to find the iSCSI Boot Format Table. The logical
- * kernel address is set in the ibft_addr global variable.
- */
-unsigned long __init find_ibft_region(unsigned long *sizep)
+static int __init find_ibft_in_mem(void)
{
unsigned long pos;
unsigned int len = 0;
void *virt;
- ibft_addr = NULL;
-
for (pos = IBFT_START; pos < IBFT_END; pos += 16) {
/* The table can't be inside the VGA BIOS reserved space,
* so skip that area */
@@ -72,14 +76,42 @@ unsigned long __init find_ibft_region(unsigned long *sizep)
/* if the length of the table extends past 1M,
* the table cannot be valid. */
if (pos + len <= (IBFT_END-1)) {
- ibft_addr = (struct ibft_table_header *)virt;
+ ibft_addr = (struct acpi_table_ibft *)virt;
break;
}
}
}
+ return len;
+}
+/*
+ * Routine used to find the iSCSI Boot Format Table. The logical
+ * kernel address is set in the ibft_addr global variable.
+ */
+unsigned long __init find_ibft_region(unsigned long *sizep)
+{
+
+ ibft_addr = NULL;
+
+#ifdef CONFIG_ACPI
+ /*
+ * One spec says "IBFT", the other says "iBFT". We have to check
+ * for both.
+ */
+ if (!ibft_addr)
+ acpi_table_parse(ACPI_SIG_IBFT, acpi_find_ibft);
+ if (!ibft_addr)
+ acpi_table_parse(IBFT_SIGN, acpi_find_ibft);
+#endif /* CONFIG_ACPI */
+
+ /* iBFT 1.03 section 1.4.3.1 mandates that UEFI machines will
+ * only use ACPI for this */
+
+ if (!ibft_addr && !efi_enabled)
+ find_ibft_in_mem();
+
if (ibft_addr) {
- *sizep = PAGE_ALIGN(len);
- return pos;
+ *sizep = PAGE_ALIGN(ibft_addr->header.length);
+ return (u64)isa_virt_to_bus(ibft_addr);
}
*sizep = 0;
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index 4e51fe3c1fc..6a6bd569e1f 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -8,6 +8,7 @@
#include <linux/debugfs.h>
#include <linux/seq_file.h>
#include <linux/gpio.h>
+#include <linux/of_gpio.h>
#include <linux/idr.h>
#include <linux/slab.h>
@@ -1100,16 +1101,24 @@ int gpiochip_add(struct gpio_chip *chip)
}
}
+ of_gpiochip_add(chip);
+
unlock:
spin_unlock_irqrestore(&gpio_lock, flags);
- if (status == 0)
- status = gpiochip_export(chip);
+
+ if (status)
+ goto fail;
+
+ status = gpiochip_export(chip);
+ if (status)
+ goto fail;
+
+ return 0;
fail:
/* failures here can mean systems won't boot... */
- if (status)
- pr_err("gpiochip_add: gpios %d..%d (%s) failed to register\n",
- chip->base, chip->base + chip->ngpio - 1,
- chip->label ? : "generic");
+ pr_err("gpiochip_add: gpios %d..%d (%s) failed to register\n",
+ chip->base, chip->base + chip->ngpio - 1,
+ chip->label ? : "generic");
return status;
}
EXPORT_SYMBOL_GPL(gpiochip_add);
@@ -1128,6 +1137,8 @@ int gpiochip_remove(struct gpio_chip *chip)
spin_lock_irqsave(&gpio_lock, flags);
+ of_gpiochip_remove(chip);
+
for (id = chip->base; id < chip->base + chip->ngpio; id++) {
if (test_bit(FLAG_REQUESTED, &gpio_desc[id].flags)) {
status = -EBUSY;
@@ -1148,6 +1159,38 @@ int gpiochip_remove(struct gpio_chip *chip)
}
EXPORT_SYMBOL_GPL(gpiochip_remove);
+/**
+ * gpiochip_find() - iterator for locating a specific gpio_chip
+ * @data: data to pass to match function
+ * @callback: Callback function to check gpio_chip
+ *
+ * Similar to bus_find_device. It returns a reference to a gpio_chip as
+ * determined by a user supplied @match callback. The callback should return
+ * 0 if the device doesn't match and non-zero if it does. If the callback is
+ * non-zero, this function will return to the caller and not iterate over any
+ * more gpio_chips.
+ */
+struct gpio_chip *gpiochip_find(void *data,
+ int (*match)(struct gpio_chip *chip, void *data))
+{
+ struct gpio_chip *chip = NULL;
+ unsigned long flags;
+ int i;
+
+ spin_lock_irqsave(&gpio_lock, flags);
+ for (i = 0; i < ARCH_NR_GPIOS; i++) {
+ if (!gpio_desc[i].chip)
+ continue;
+
+ if (match(gpio_desc[i].chip, data)) {
+ chip = gpio_desc[i].chip;
+ break;
+ }
+ }
+ spin_unlock_irqrestore(&gpio_lock, flags);
+
+ return chip;
+}
/* These "optional" allocation calls help prevent drivers from stomping
* on each other, and help provide better diagnostics in debugfs.
diff --git a/drivers/gpio/xilinx_gpio.c b/drivers/gpio/xilinx_gpio.c
index b8fa65b5bfc..709690995d0 100644
--- a/drivers/gpio/xilinx_gpio.c
+++ b/drivers/gpio/xilinx_gpio.c
@@ -161,14 +161,12 @@ static void xgpio_save_regs(struct of_mm_gpio_chip *mm_gc)
static int __devinit xgpio_of_probe(struct device_node *np)
{
struct xgpio_instance *chip;
- struct of_gpio_chip *ofchip;
int status = 0;
const u32 *tree_info;
chip = kzalloc(sizeof(*chip), GFP_KERNEL);
if (!chip)
return -ENOMEM;
- ofchip = &chip->mmchip.of_gc;
/* Update GPIO state shadow register with default value */
tree_info = of_get_property(np, "xlnx,dout-default", NULL);
@@ -182,21 +180,20 @@ static int __devinit xgpio_of_probe(struct device_node *np)
chip->gpio_dir = *tree_info;
/* Check device node and parent device node for device width */
- ofchip->gc.ngpio = 32; /* By default assume full GPIO controller */
+ chip->mmchip.gc.ngpio = 32; /* By default assume full GPIO controller */
tree_info = of_get_property(np, "xlnx,gpio-width", NULL);
if (!tree_info)
tree_info = of_get_property(np->parent,
"xlnx,gpio-width", NULL);
if (tree_info)
- ofchip->gc.ngpio = *tree_info;
+ chip->mmchip.gc.ngpio = *tree_info;
spin_lock_init(&chip->gpio_lock);
- ofchip->gpio_cells = 2;
- ofchip->gc.direction_input = xgpio_dir_in;
- ofchip->gc.direction_output = xgpio_dir_out;
- ofchip->gc.get = xgpio_get;
- ofchip->gc.set = xgpio_set;
+ chip->mmchip.gc.direction_input = xgpio_dir_in;
+ chip->mmchip.gc.direction_output = xgpio_dir_out;
+ chip->mmchip.gc.get = xgpio_get;
+ chip->mmchip.gc.set = xgpio_set;
chip->mmchip.save_regs = xgpio_save_regs;
diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
index 88910e5a2c7..4cab0c6397e 100644
--- a/drivers/gpu/drm/Kconfig
+++ b/drivers/gpu/drm/Kconfig
@@ -6,7 +6,7 @@
#
menuconfig DRM
tristate "Direct Rendering Manager (XFree86 4.1.0 and higher DRI support)"
- depends on (AGP || AGP=n) && PCI && !EMULATED_CMPXCHG && MMU
+ depends on (AGP || AGP=n) && !EMULATED_CMPXCHG && MMU
select I2C
select I2C_ALGOBIT
select SLOW_WORK
@@ -17,7 +17,7 @@ menuconfig DRM
These modules provide support for synchronization, security, and
DMA transfers. Please see <http://dri.sourceforge.net/> for more
details. You should also select and configure AGP
- (/dev/agpgart) support.
+ (/dev/agpgart) support if it is available for your platform.
config DRM_KMS_HELPER
tristate
@@ -61,6 +61,7 @@ config DRM_RADEON
select DRM_KMS_HELPER
select DRM_TTM
select POWER_SUPPLY
+ select HWMON
help
Choose this option if you have an ATI Radeon graphics card. There
are both PCI and AGP versions. You don't need to choose this to
@@ -130,7 +131,7 @@ endchoice
config DRM_MGA
tristate "Matrox g200/g400"
- depends on DRM
+ depends on DRM && PCI
select FW_LOADER
help
Choose this option if you have a Matrox G200, G400 or G450 graphics
@@ -148,14 +149,14 @@ config DRM_SIS
config DRM_VIA
tristate "Via unichrome video cards"
- depends on DRM
+ depends on DRM && PCI
help
Choose this option if you have a Via unichrome or compatible video
chipset. If M is selected the module will be called via.
config DRM_SAVAGE
tristate "Savage video cards"
- depends on DRM
+ depends on DRM && PCI
help
Choose this option if you have a Savage3D/4/SuperSavage/Pro/Twister
chipset. If M is selected the module will be called savage.
diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
index abe3f446ca4..f3a23a329f4 100644
--- a/drivers/gpu/drm/Makefile
+++ b/drivers/gpu/drm/Makefile
@@ -9,9 +9,10 @@ drm-y := drm_auth.o drm_buffer.o drm_bufs.o drm_cache.o \
drm_drv.o drm_fops.o drm_gem.o drm_ioctl.o drm_irq.o \
drm_lock.o drm_memory.o drm_proc.o drm_stub.o drm_vm.o \
drm_agpsupport.o drm_scatter.o ati_pcigart.o drm_pci.o \
- drm_sysfs.o drm_hashtab.o drm_sman.o drm_mm.o \
+ drm_platform.o drm_sysfs.o drm_hashtab.o drm_sman.o drm_mm.o \
drm_crtc.o drm_modes.o drm_edid.o \
- drm_info.o drm_debugfs.o drm_encoder_slave.o
+ drm_info.o drm_debugfs.o drm_encoder_slave.o \
+ drm_trace_points.o drm_global.o
drm-$(CONFIG_COMPAT) += drm_ioc32.o
@@ -19,6 +20,8 @@ drm_kms_helper-y := drm_fb_helper.o drm_crtc_helper.o drm_dp_i2c_helper.o
obj-$(CONFIG_DRM_KMS_HELPER) += drm_kms_helper.o
+CFLAGS_drm_trace_points.o := -I$(src)
+
obj-$(CONFIG_DRM) += drm.o
obj-$(CONFIG_DRM_TTM) += ttm/
obj-$(CONFIG_DRM_TDFX) += tdfx/
diff --git a/drivers/gpu/drm/drm_bufs.c b/drivers/gpu/drm/drm_bufs.c
index 2092e7bb788..a5c9ce93bbc 100644
--- a/drivers/gpu/drm/drm_bufs.c
+++ b/drivers/gpu/drm/drm_bufs.c
@@ -39,19 +39,6 @@
#include <asm/shmparam.h>
#include "drmP.h"
-resource_size_t drm_get_resource_start(struct drm_device *dev, unsigned int resource)
-{
- return pci_resource_start(dev->pdev, resource);
-}
-EXPORT_SYMBOL(drm_get_resource_start);
-
-resource_size_t 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 struct drm_map_list *drm_find_matching_map(struct drm_device *dev,
struct drm_local_map *map)
{
@@ -189,7 +176,7 @@ static int drm_addmap_core(struct drm_device * dev, resource_size_t offset,
switch (map->type) {
case _DRM_REGISTERS:
case _DRM_FRAME_BUFFER:
-#if !defined(__sparc__) && !defined(__alpha__) && !defined(__ia64__) && !defined(__powerpc64__) && !defined(__x86_64__)
+#if !defined(__sparc__) && !defined(__alpha__) && !defined(__ia64__) && !defined(__powerpc64__) && !defined(__x86_64__) && !defined(__arm__)
if (map->offset + (map->size-1) < map->offset ||
map->offset < virt_to_phys(high_memory)) {
kfree(map);
diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
index 57cea01c4ff..4c68f76993d 100644
--- a/drivers/gpu/drm/drm_crtc.c
+++ b/drivers/gpu/drm/drm_crtc.c
@@ -80,6 +80,7 @@ static struct drm_prop_enum_list drm_dithering_mode_enum_list[] =
{
{ DRM_MODE_DITHERING_OFF, "Off" },
{ DRM_MODE_DITHERING_ON, "On" },
+ { DRM_MODE_DITHERING_AUTO, "Automatic" },
};
/*
@@ -1126,7 +1127,7 @@ int drm_mode_getresources(struct drm_device *dev, void *data,
if (file_priv->master->minor->type == DRM_MINOR_CONTROL) {
list_for_each_entry(crtc, &dev->mode_config.crtc_list,
head) {
- DRM_DEBUG_KMS("CRTC ID is %d\n", crtc->base.id);
+ DRM_DEBUG_KMS("[CRTC:%d]\n", crtc->base.id);
if (put_user(crtc->base.id, crtc_id + copied)) {
ret = -EFAULT;
goto out;
@@ -1154,8 +1155,8 @@ int drm_mode_getresources(struct drm_device *dev, void *data,
list_for_each_entry(encoder,
&dev->mode_config.encoder_list,
head) {
- DRM_DEBUG_KMS("ENCODER ID is %d\n",
- encoder->base.id);
+ DRM_DEBUG_KMS("[ENCODER:%d:%s]\n", encoder->base.id,
+ drm_get_encoder_name(encoder));
if (put_user(encoder->base.id, encoder_id +
copied)) {
ret = -EFAULT;
@@ -1185,8 +1186,9 @@ int drm_mode_getresources(struct drm_device *dev, void *data,
list_for_each_entry(connector,
&dev->mode_config.connector_list,
head) {
- DRM_DEBUG_KMS("CONNECTOR ID is %d\n",
- connector->base.id);
+ DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n",
+ connector->base.id,
+ drm_get_connector_name(connector));
if (put_user(connector->base.id,
connector_id + copied)) {
ret = -EFAULT;
@@ -1209,7 +1211,7 @@ int drm_mode_getresources(struct drm_device *dev, void *data,
}
card_res->count_connectors = connector_count;
- DRM_DEBUG_KMS("Counted %d %d %d\n", card_res->count_crtcs,
+ DRM_DEBUG_KMS("CRTC[%d] CONNECTORS[%d] ENCODERS[%d]\n", card_res->count_crtcs,
card_res->count_connectors, card_res->count_encoders);
out:
@@ -1312,7 +1314,7 @@ int drm_mode_getconnector(struct drm_device *dev, void *data,
memset(&u_mode, 0, sizeof(struct drm_mode_modeinfo));
- DRM_DEBUG_KMS("connector id %d:\n", out_resp->connector_id);
+ DRM_DEBUG_KMS("[CONNECTOR:%d:?]\n", out_resp->connector_id);
mutex_lock(&dev->mode_config.mutex);
@@ -1493,6 +1495,7 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data,
goto out;
}
crtc = obj_to_crtc(obj);
+ DRM_DEBUG_KMS("[CRTC:%d]\n", crtc->base.id);
if (crtc_req->mode_valid) {
/* If we have a mode we need a framebuffer. */
@@ -1569,6 +1572,9 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data,
goto out;
}
connector = obj_to_connector(obj);
+ DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n",
+ connector->base.id,
+ drm_get_connector_name(connector));
connector_set[i] = connector;
}
@@ -1684,6 +1690,7 @@ int drm_mode_addfb(struct drm_device *dev,
r->fb_id = fb->base.id;
list_add(&fb->filp_head, &file_priv->fbs);
+ DRM_DEBUG_KMS("[FB:%d]\n", fb->base.id);
out:
mutex_unlock(&dev->mode_config.mutex);
@@ -2610,6 +2617,15 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev,
goto out;
crtc = obj_to_crtc(obj);
+ if (crtc->fb == NULL) {
+ /* The framebuffer is currently unbound, presumably
+ * due to a hotplug event, that userspace has not
+ * yet discovered.
+ */
+ ret = -EBUSY;
+ goto out;
+ }
+
if (crtc->funcs->page_flip == NULL)
goto out;
diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c
index 9b2a54117c9..45981304feb 100644
--- a/drivers/gpu/drm/drm_crtc_helper.c
+++ b/drivers/gpu/drm/drm_crtc_helper.c
@@ -86,7 +86,8 @@ int drm_helper_probe_single_connector_modes(struct drm_connector *connector,
int count = 0;
int mode_flags = 0;
- DRM_DEBUG_KMS("%s\n", drm_get_connector_name(connector));
+ DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n", connector->base.id,
+ drm_get_connector_name(connector));
/* set all modes to the unverified state */
list_for_each_entry_safe(mode, t, &connector->modes, head)
mode->status = MODE_UNVERIFIED;
@@ -102,8 +103,8 @@ int drm_helper_probe_single_connector_modes(struct drm_connector *connector,
connector->status = connector->funcs->detect(connector);
if (connector->status == connector_status_disconnected) {
- DRM_DEBUG_KMS("%s is disconnected\n",
- drm_get_connector_name(connector));
+ DRM_DEBUG_KMS("[CONNECTOR:%d:%s] disconnected\n",
+ connector->base.id, drm_get_connector_name(connector));
drm_mode_connector_update_edid_property(connector, NULL);
goto prune;
}
@@ -141,8 +142,8 @@ prune:
drm_mode_sort(&connector->modes);
- DRM_DEBUG_KMS("Probed modes for %s\n",
- drm_get_connector_name(connector));
+ DRM_DEBUG_KMS("[CONNECTOR:%d:%s] probed modes :\n", connector->base.id,
+ drm_get_connector_name(connector));
list_for_each_entry_safe(mode, t, &connector->modes, head) {
mode->vrefresh = drm_mode_vrefresh(mode);
@@ -201,6 +202,17 @@ bool drm_helper_crtc_in_use(struct drm_crtc *crtc)
}
EXPORT_SYMBOL(drm_helper_crtc_in_use);
+static void
+drm_encoder_disable(struct drm_encoder *encoder)
+{
+ struct drm_encoder_helper_funcs *encoder_funcs = encoder->helper_private;
+
+ if (encoder_funcs->disable)
+ (*encoder_funcs->disable)(encoder);
+ else
+ (*encoder_funcs->dpms)(encoder, DRM_MODE_DPMS_OFF);
+}
+
/**
* drm_helper_disable_unused_functions - disable unused objects
* @dev: DRM device
@@ -215,7 +227,6 @@ void drm_helper_disable_unused_functions(struct drm_device *dev)
{
struct drm_encoder *encoder;
struct drm_connector *connector;
- struct drm_encoder_helper_funcs *encoder_funcs;
struct drm_crtc *crtc;
list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
@@ -226,12 +237,8 @@ void drm_helper_disable_unused_functions(struct drm_device *dev)
}
list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
- encoder_funcs = encoder->helper_private;
if (!drm_helper_encoder_in_use(encoder)) {
- if (encoder_funcs->disable)
- (*encoder_funcs->disable)(encoder);
- else
- (*encoder_funcs->dpms)(encoder, DRM_MODE_DPMS_OFF);
+ drm_encoder_disable(encoder);
/* disconnector encoder from any connector */
encoder->crtc = NULL;
}
@@ -241,7 +248,10 @@ void drm_helper_disable_unused_functions(struct drm_device *dev)
struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
crtc->enabled = drm_helper_crtc_in_use(crtc);
if (!crtc->enabled) {
- crtc_funcs->dpms(crtc, DRM_MODE_DPMS_OFF);
+ if (crtc_funcs->disable)
+ (*crtc_funcs->disable)(crtc);
+ else
+ (*crtc_funcs->dpms)(crtc, DRM_MODE_DPMS_OFF);
crtc->fb = NULL;
}
}
@@ -292,11 +302,11 @@ drm_crtc_prepare_encoders(struct drm_device *dev)
encoder_funcs = encoder->helper_private;
/* Disable unused encoders */
if (encoder->crtc == NULL)
- (*encoder_funcs->dpms)(encoder, DRM_MODE_DPMS_OFF);
+ drm_encoder_disable(encoder);
/* Disable encoders whose CRTC is about to change */
if (encoder_funcs->get_crtc &&
encoder->crtc != (*encoder_funcs->get_crtc)(encoder))
- (*encoder_funcs->dpms)(encoder, DRM_MODE_DPMS_OFF);
+ drm_encoder_disable(encoder);
}
}
@@ -365,6 +375,7 @@ bool drm_crtc_helper_set_mode(struct drm_crtc *crtc,
if (!(ret = crtc_funcs->mode_fixup(crtc, mode, adjusted_mode))) {
goto done;
}
+ DRM_DEBUG_KMS("[CRTC:%d]\n", crtc->base.id);
/* Prepare the encoders and CRTCs before setting the mode. */
list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
@@ -392,8 +403,9 @@ bool drm_crtc_helper_set_mode(struct drm_crtc *crtc,
if (encoder->crtc != crtc)
continue;
- DRM_DEBUG("%s: set mode %s %x\n", drm_get_encoder_name(encoder),
- mode->name, mode->base.id);
+ DRM_DEBUG_KMS("[ENCODER:%d:%s] set [MODE:%d:%s]\n",
+ encoder->base.id, drm_get_encoder_name(encoder),
+ mode->base.id, mode->name);
encoder_funcs = encoder->helper_private;
encoder_funcs->mode_set(encoder, mode, adjusted_mode);
}
@@ -469,10 +481,15 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set)
crtc_funcs = set->crtc->helper_private;
- DRM_DEBUG_KMS("crtc: %p %d fb: %p connectors: %p num_connectors:"
- " %d (x, y) (%i, %i)\n",
- set->crtc, set->crtc->base.id, set->fb, set->connectors,
- (int)set->num_connectors, set->x, set->y);
+ if (set->fb) {
+ DRM_DEBUG_KMS("[CRTC:%d] [FB:%d] #connectors=%d (x y) (%i %i)\n",
+ set->crtc->base.id, set->fb->base.id,
+ (int)set->num_connectors, set->x, set->y);
+ } else {
+ DRM_DEBUG_KMS("[CRTC:%d] [NOFB] #connectors=%d (x y) (%i %i)\n",
+ set->crtc->base.id, (int)set->num_connectors,
+ set->x, set->y);
+ }
dev = set->crtc->dev;
@@ -601,8 +618,14 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set)
mode_changed = true;
connector->encoder->crtc = new_crtc;
}
- DRM_DEBUG_KMS("setting connector %d crtc to %p\n",
- connector->base.id, new_crtc);
+ if (new_crtc) {
+ DRM_DEBUG_KMS("[CONNECTOR:%d:%s] to [CRTC:%d]\n",
+ connector->base.id, drm_get_connector_name(connector),
+ new_crtc->base.id);
+ } else {
+ DRM_DEBUG_KMS("[CONNECTOR:%d:%s] to [NOCRTC]\n",
+ connector->base.id, drm_get_connector_name(connector));
+ }
}
/* mode_set_base is not a required function */
@@ -620,8 +643,8 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set)
if (!drm_crtc_helper_set_mode(set->crtc, set->mode,
set->x, set->y,
old_fb)) {
- DRM_ERROR("failed to set mode on crtc %p\n",
- set->crtc);
+ DRM_ERROR("failed to set mode on [CRTC:%d]\n",
+ set->crtc->base.id);
ret = -EINVAL;
goto fail;
}
@@ -808,13 +831,11 @@ int drm_helper_resume_force_mode(struct drm_device *dev)
}
EXPORT_SYMBOL(drm_helper_resume_force_mode);
-static struct slow_work_ops output_poll_ops;
-
#define DRM_OUTPUT_POLL_PERIOD (10*HZ)
-static void output_poll_execute(struct slow_work *work)
+static void output_poll_execute(struct work_struct *work)
{
- struct delayed_slow_work *delayed_work = container_of(work, struct delayed_slow_work, work);
- struct drm_device *dev = container_of(delayed_work, struct drm_device, mode_config.output_poll_slow_work);
+ struct delayed_work *delayed_work = to_delayed_work(work);
+ struct drm_device *dev = container_of(delayed_work, struct drm_device, mode_config.output_poll_work);
struct drm_connector *connector;
enum drm_connector_status old_status, status;
bool repoll = false, changed = false;
@@ -854,7 +875,7 @@ static void output_poll_execute(struct slow_work *work)
}
if (repoll) {
- ret = delayed_slow_work_enqueue(delayed_work, DRM_OUTPUT_POLL_PERIOD);
+ ret = queue_delayed_work(system_nrt_wq, delayed_work, DRM_OUTPUT_POLL_PERIOD);
if (ret)
DRM_ERROR("delayed enqueue failed %d\n", ret);
}
@@ -864,7 +885,7 @@ void drm_kms_helper_poll_disable(struct drm_device *dev)
{
if (!dev->mode_config.poll_enabled)
return;
- delayed_slow_work_cancel(&dev->mode_config.output_poll_slow_work);
+ cancel_delayed_work_sync(&dev->mode_config.output_poll_work);
}
EXPORT_SYMBOL(drm_kms_helper_poll_disable);
@@ -880,7 +901,7 @@ void drm_kms_helper_poll_enable(struct drm_device *dev)
}
if (poll) {
- ret = delayed_slow_work_enqueue(&dev->mode_config.output_poll_slow_work, DRM_OUTPUT_POLL_PERIOD);
+ ret = queue_delayed_work(system_nrt_wq, &dev->mode_config.output_poll_work, DRM_OUTPUT_POLL_PERIOD);
if (ret)
DRM_ERROR("delayed enqueue failed %d\n", ret);
}
@@ -889,9 +910,7 @@ EXPORT_SYMBOL(drm_kms_helper_poll_enable);
void drm_kms_helper_poll_init(struct drm_device *dev)
{
- slow_work_register_user(THIS_MODULE);
- delayed_slow_work_init(&dev->mode_config.output_poll_slow_work,
- &output_poll_ops);
+ INIT_DELAYED_WORK(&dev->mode_config.output_poll_work, output_poll_execute);
dev->mode_config.poll_enabled = true;
drm_kms_helper_poll_enable(dev);
@@ -901,7 +920,6 @@ EXPORT_SYMBOL(drm_kms_helper_poll_init);
void drm_kms_helper_poll_fini(struct drm_device *dev)
{
drm_kms_helper_poll_disable(dev);
- slow_work_unregister_user(THIS_MODULE);
}
EXPORT_SYMBOL(drm_kms_helper_poll_fini);
@@ -909,12 +927,8 @@ void drm_helper_hpd_irq_event(struct drm_device *dev)
{
if (!dev->mode_config.poll_enabled)
return;
- delayed_slow_work_cancel(&dev->mode_config.output_poll_slow_work);
- /* schedule a slow work asap */
- delayed_slow_work_enqueue(&dev->mode_config.output_poll_slow_work, 0);
+ /* kill timer and schedule immediate execution, this doesn't block */
+ cancel_delayed_work(&dev->mode_config.output_poll_work);
+ queue_delayed_work(system_nrt_wq, &dev->mode_config.output_poll_work, 0);
}
EXPORT_SYMBOL(drm_helper_hpd_irq_event);
-
-static struct slow_work_ops output_poll_ops = {
- .execute = output_poll_execute,
-};
diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c
index 4a66201edae..90288ec7c28 100644
--- a/drivers/gpu/drm/drm_drv.c
+++ b/drivers/gpu/drm/drm_drv.c
@@ -243,47 +243,20 @@ int drm_lastclose(struct drm_device * dev)
*
* Initializes an array of drm_device structures, and attempts to
* initialize all available devices, using consecutive minors, registering the
- * stubs and initializing the AGP device.
+ * stubs and initializing the device.
*
* Expands the \c DRIVER_PREINIT and \c DRIVER_POST_INIT macros before and
* after the initialization for driver customization.
*/
int drm_init(struct drm_driver *driver)
{
- struct pci_dev *pdev = NULL;
- const struct pci_device_id *pid;
- int i;
-
DRM_DEBUG("\n");
-
INIT_LIST_HEAD(&driver->device_list);
- if (driver->driver_features & DRIVER_MODESET)
- return pci_register_driver(&driver->pci_driver);
-
- /* If not using KMS, fall back to stealth mode manual scanning. */
- for (i = 0; driver->pci_driver.id_table[i].vendor != 0; i++) {
- pid = &driver->pci_driver.id_table[i];
-
- /* Loop around setting up a DRM device for each PCI device
- * matching our ID and device class. If we had the internal
- * function that pci_get_subsys and pci_get_class used, we'd
- * be able to just pass pid in instead of doing a two-stage
- * thing.
- */
- pdev = NULL;
- while ((pdev =
- pci_get_subsys(pid->vendor, pid->device, pid->subvendor,
- pid->subdevice, pdev)) != NULL) {
- if ((pdev->class & pid->class_mask) != pid->class)
- continue;
-
- /* stealth mode requires a manual probe */
- pci_dev_get(pdev);
- drm_get_dev(pdev, pid, driver);
- }
- }
- return 0;
+ if (driver->driver_features & DRIVER_USE_PLATFORM_DEVICE)
+ return drm_platform_init(driver);
+ else
+ return drm_pci_init(driver);
}
EXPORT_SYMBOL(drm_init);
@@ -315,6 +288,7 @@ static int __init drm_core_init(void)
{
int ret = -ENOMEM;
+ drm_global_init();
idr_init(&drm_minors_idr);
if (register_chrdev(DRM_MAJOR, "drm", &drm_stub_fops))
@@ -362,6 +336,7 @@ static void __exit drm_core_exit(void)
unregister_chrdev(DRM_MAJOR, "drm");
+ idr_remove_all(&drm_minors_idr);
idr_destroy(&drm_minors_idr);
}
@@ -506,9 +481,9 @@ long drm_ioctl(struct file *filp,
if (ioctl->flags & DRM_UNLOCKED)
retcode = func(dev, kdata, file_priv);
else {
- lock_kernel();
+ mutex_lock(&drm_global_mutex);
retcode = func(dev, kdata, file_priv);
- unlock_kernel();
+ mutex_unlock(&drm_global_mutex);
}
if (cmd & IOC_OUT) {
diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c
index f87bf104df7..dce5c4a97f8 100644
--- a/drivers/gpu/drm/drm_edid.c
+++ b/drivers/gpu/drm/drm_edid.c
@@ -282,7 +282,7 @@ drm_do_get_edid(struct drm_connector *connector, struct i2c_adapter *adapter)
return block;
carp:
- dev_warn(&connector->dev->pdev->dev, "%s: EDID block %d invalid.\n",
+ dev_warn(connector->dev->dev, "%s: EDID block %d invalid.\n",
drm_get_connector_name(connector), j);
out:
@@ -929,13 +929,11 @@ drm_mode_do_interlace_quirk(struct drm_display_mode *mode,
{ 1440, 576 },
{ 2880, 576 },
};
- static const int n_sizes =
- sizeof(cea_interlaced)/sizeof(cea_interlaced[0]);
if (!(pt->misc & DRM_EDID_PT_INTERLACED))
return;
- for (i = 0; i < n_sizes; i++) {
+ for (i = 0; i < ARRAY_SIZE(cea_interlaced); i++) {
if ((mode->hdisplay == cea_interlaced[i].w) &&
(mode->vdisplay == cea_interlaced[i].h / 2)) {
mode->vdisplay *= 2;
@@ -1375,7 +1373,6 @@ static const struct {
{ 1920, 1440, 60, 0 },
{ 1920, 1440, 75, 0 },
};
-static const int num_est3_modes = sizeof(est3_modes) / sizeof(est3_modes[0]);
static int
drm_est3_modes(struct drm_connector *connector, struct detailed_timing *timing)
@@ -1387,7 +1384,7 @@ drm_est3_modes(struct drm_connector *connector, struct detailed_timing *timing)
for (i = 0; i < 6; i++) {
for (j = 7; j > 0; j--) {
m = (i * 8) + (7 - j);
- if (m >= num_est3_modes)
+ if (m >= ARRAY_SIZE(est3_modes))
break;
if (est[i] & (1 << j)) {
mode = drm_mode_find_dmt(connector->dev,
@@ -1626,7 +1623,7 @@ int drm_add_edid_modes(struct drm_connector *connector, struct edid *edid)
return 0;
}
if (!drm_edid_is_valid(edid)) {
- dev_warn(&connector->dev->pdev->dev, "%s: EDID invalid.\n",
+ dev_warn(connector->dev->dev, "%s: EDID invalid.\n",
drm_get_connector_name(connector));
return 0;
}
diff --git a/drivers/gpu/drm/drm_encoder_slave.c b/drivers/gpu/drm/drm_encoder_slave.c
index f0184696edf..d62c064fbaa 100644
--- a/drivers/gpu/drm/drm_encoder_slave.c
+++ b/drivers/gpu/drm/drm_encoder_slave.c
@@ -41,6 +41,9 @@
* &drm_encoder_slave. The @slave_funcs field will be initialized with
* the hooks provided by the slave driver.
*
+ * If @info->platform_data is non-NULL it will be used as the initial
+ * slave config.
+ *
* Returns 0 on success or a negative errno on failure, in particular,
* -ENODEV is returned when no matching driver is found.
*/
@@ -85,6 +88,10 @@ int drm_i2c_encoder_init(struct drm_device *dev,
if (err)
goto fail_unregister;
+ if (info->platform_data)
+ encoder->slave_funcs->set_config(&encoder->base,
+ info->platform_data);
+
return 0;
fail_unregister:
diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
index 719662034bb..de82e201d68 100644
--- a/drivers/gpu/drm/drm_fb_helper.c
+++ b/drivers/gpu/drm/drm_fb_helper.c
@@ -241,6 +241,80 @@ static int drm_fb_helper_parse_command_line(struct drm_fb_helper *fb_helper)
return 0;
}
+int drm_fb_helper_debug_enter(struct fb_info *info)
+{
+ struct drm_fb_helper *helper = info->par;
+ struct drm_crtc_helper_funcs *funcs;
+ int i;
+
+ if (list_empty(&kernel_fb_helper_list))
+ return false;
+
+ list_for_each_entry(helper, &kernel_fb_helper_list, kernel_fb_list) {
+ for (i = 0; i < helper->crtc_count; i++) {
+ struct drm_mode_set *mode_set =
+ &helper->crtc_info[i].mode_set;
+
+ if (!mode_set->crtc->enabled)
+ continue;
+
+ funcs = mode_set->crtc->helper_private;
+ funcs->mode_set_base_atomic(mode_set->crtc,
+ mode_set->fb,
+ mode_set->x,
+ mode_set->y);
+
+ }
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(drm_fb_helper_debug_enter);
+
+/* Find the real fb for a given fb helper CRTC */
+static struct drm_framebuffer *drm_mode_config_fb(struct drm_crtc *crtc)
+{
+ struct drm_device *dev = crtc->dev;
+ struct drm_crtc *c;
+
+ list_for_each_entry(c, &dev->mode_config.crtc_list, head) {
+ if (crtc->base.id == c->base.id)
+ return c->fb;
+ }
+
+ return NULL;
+}
+
+int drm_fb_helper_debug_leave(struct fb_info *info)
+{
+ struct drm_fb_helper *helper = info->par;
+ struct drm_crtc *crtc;
+ struct drm_crtc_helper_funcs *funcs;
+ struct drm_framebuffer *fb;
+ int i;
+
+ for (i = 0; i < helper->crtc_count; i++) {
+ struct drm_mode_set *mode_set = &helper->crtc_info[i].mode_set;
+ crtc = mode_set->crtc;
+ funcs = crtc->helper_private;
+ fb = drm_mode_config_fb(crtc);
+
+ if (!crtc->enabled)
+ continue;
+
+ if (!fb) {
+ DRM_ERROR("no fb to restore??\n");
+ continue;
+ }
+
+ funcs->mode_set_base_atomic(mode_set->crtc, fb, crtc->x,
+ crtc->y);
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(drm_fb_helper_debug_leave);
+
bool drm_fb_helper_force_kernel_mode(void)
{
int i = 0;
@@ -611,7 +685,7 @@ int drm_fb_helper_check_var(struct fb_var_screeninfo *var,
struct drm_framebuffer *fb = fb_helper->fb;
int depth;
- if (var->pixclock != 0)
+ if (var->pixclock != 0 || in_dbg_master())
return -EINVAL;
/* Need to resize the fb object !!! */
diff --git a/drivers/gpu/drm/drm_fops.c b/drivers/gpu/drm/drm_fops.c
index e7aace20981..2ca8df8b610 100644
--- a/drivers/gpu/drm/drm_fops.c
+++ b/drivers/gpu/drm/drm_fops.c
@@ -39,6 +39,9 @@
#include <linux/slab.h>
#include <linux/smp_lock.h>
+/* from BKL pushdown: note that nothing else serializes idr_find() */
+DEFINE_MUTEX(drm_global_mutex);
+
static int drm_open_helper(struct inode *inode, struct file *filp,
struct drm_device * dev);
@@ -175,8 +178,7 @@ int drm_stub_open(struct inode *inode, struct file *filp)
DRM_DEBUG("\n");
- /* BKL pushdown: note that nothing else serializes idr_find() */
- lock_kernel();
+ mutex_lock(&drm_global_mutex);
minor = idr_find(&drm_minors_idr, minor_id);
if (!minor)
goto out;
@@ -197,7 +199,7 @@ int drm_stub_open(struct inode *inode, struct file *filp)
fops_put(old_fops);
out:
- unlock_kernel();
+ mutex_unlock(&drm_global_mutex);
return err;
}
@@ -472,7 +474,7 @@ int drm_release(struct inode *inode, struct file *filp)
struct drm_device *dev = file_priv->minor->dev;
int retcode = 0;
- lock_kernel();
+ mutex_lock(&drm_global_mutex);
DRM_DEBUG("open_count = %d\n", dev->open_count);
@@ -573,17 +575,14 @@ int drm_release(struct inode *inode, struct file *filp)
if (atomic_read(&dev->ioctl_count)) {
DRM_ERROR("Device busy: %d\n",
atomic_read(&dev->ioctl_count));
- spin_unlock(&dev->count_lock);
- unlock_kernel();
- return -EBUSY;
+ retcode = -EBUSY;
+ goto out;
}
- spin_unlock(&dev->count_lock);
- unlock_kernel();
- return drm_lastclose(dev);
+ retcode = drm_lastclose(dev);
}
+out:
spin_unlock(&dev->count_lock);
-
- unlock_kernel();
+ mutex_unlock(&drm_global_mutex);
return retcode;
}
diff --git a/drivers/gpu/drm/drm_gem.c b/drivers/gpu/drm/drm_gem.c
index 33dad3fa604..4f1b8671448 100644
--- a/drivers/gpu/drm/drm_gem.c
+++ b/drivers/gpu/drm/drm_gem.c
@@ -68,8 +68,18 @@
* We make up offsets for buffer objects so we can recognize them at
* mmap time.
*/
+
+/* pgoff in mmap is an unsigned long, so we need to make sure that
+ * the faked up offset will fit
+ */
+
+#if BITS_PER_LONG == 64
#define DRM_FILE_PAGE_OFFSET_START ((0xFFFFFFFFUL >> PAGE_SHIFT) + 1)
#define DRM_FILE_PAGE_OFFSET_SIZE ((0xFFFFFFFFUL >> PAGE_SHIFT) * 16)
+#else
+#define DRM_FILE_PAGE_OFFSET_START ((0xFFFFFFFUL >> PAGE_SHIFT) + 1)
+#define DRM_FILE_PAGE_OFFSET_SIZE ((0xFFFFFFFUL >> PAGE_SHIFT) * 16)
+#endif
/**
* Initialize the GEM device fields
@@ -419,6 +429,7 @@ drm_gem_release(struct drm_device *dev, struct drm_file *file_private)
idr_for_each(&file_private->object_idr,
&drm_gem_object_release_handle, NULL);
+ idr_remove_all(&file_private->object_idr);
idr_destroy(&file_private->object_idr);
}
diff --git a/drivers/gpu/drm/ttm/ttm_global.c b/drivers/gpu/drm/drm_global.c
index b17007178a3..c87dc96444d 100644
--- a/drivers/gpu/drm/ttm/ttm_global.c
+++ b/drivers/gpu/drm/drm_global.c
@@ -28,45 +28,45 @@
* Authors: Thomas Hellstrom <thellstrom-at-vmware-dot-com>
*/
-#include "ttm/ttm_module.h"
#include <linux/mutex.h>
#include <linux/slab.h>
#include <linux/module.h>
+#include "drm_global.h"
-struct ttm_global_item {
+struct drm_global_item {
struct mutex mutex;
void *object;
int refcount;
};
-static struct ttm_global_item glob[TTM_GLOBAL_NUM];
+static struct drm_global_item glob[DRM_GLOBAL_NUM];
-void ttm_global_init(void)
+void drm_global_init(void)
{
int i;
- for (i = 0; i < TTM_GLOBAL_NUM; ++i) {
- struct ttm_global_item *item = &glob[i];
+ for (i = 0; i < DRM_GLOBAL_NUM; ++i) {
+ struct drm_global_item *item = &glob[i];
mutex_init(&item->mutex);
item->object = NULL;
item->refcount = 0;
}
}
-void ttm_global_release(void)
+void drm_global_release(void)
{
int i;
- for (i = 0; i < TTM_GLOBAL_NUM; ++i) {
- struct ttm_global_item *item = &glob[i];
+ for (i = 0; i < DRM_GLOBAL_NUM; ++i) {
+ struct drm_global_item *item = &glob[i];
BUG_ON(item->object != NULL);
BUG_ON(item->refcount != 0);
}
}
-int ttm_global_item_ref(struct ttm_global_reference *ref)
+int drm_global_item_ref(struct drm_global_reference *ref)
{
int ret;
- struct ttm_global_item *item = &glob[ref->global_type];
+ struct drm_global_item *item = &glob[ref->global_type];
void *object;
mutex_lock(&item->mutex);
@@ -93,11 +93,11 @@ out_err:
item->object = NULL;
return ret;
}
-EXPORT_SYMBOL(ttm_global_item_ref);
+EXPORT_SYMBOL(drm_global_item_ref);
-void ttm_global_item_unref(struct ttm_global_reference *ref)
+void drm_global_item_unref(struct drm_global_reference *ref)
{
- struct ttm_global_item *item = &glob[ref->global_type];
+ struct drm_global_item *item = &glob[ref->global_type];
mutex_lock(&item->mutex);
BUG_ON(item->refcount == 0);
@@ -108,5 +108,5 @@ void ttm_global_item_unref(struct ttm_global_reference *ref)
}
mutex_unlock(&item->mutex);
}
-EXPORT_SYMBOL(ttm_global_item_unref);
+EXPORT_SYMBOL(drm_global_item_unref);
diff --git a/drivers/gpu/drm/drm_info.c b/drivers/gpu/drm/drm_info.c
index f0f6c6b93f3..2ef2c782724 100644
--- a/drivers/gpu/drm/drm_info.c
+++ b/drivers/gpu/drm/drm_info.c
@@ -51,13 +51,24 @@ int drm_name_info(struct seq_file *m, void *data)
if (!master)
return 0;
- if (master->unique) {
- seq_printf(m, "%s %s %s\n",
- dev->driver->pci_driver.name,
- pci_name(dev->pdev), master->unique);
+ if (drm_core_check_feature(dev, DRIVER_USE_PLATFORM_DEVICE)) {
+ if (master->unique) {
+ seq_printf(m, "%s %s %s\n",
+ dev->driver->platform_device->name,
+ dev_name(dev->dev), master->unique);
+ } else {
+ seq_printf(m, "%s\n",
+ dev->driver->platform_device->name);
+ }
} else {
- seq_printf(m, "%s %s\n", dev->driver->pci_driver.name,
- pci_name(dev->pdev));
+ if (master->unique) {
+ seq_printf(m, "%s %s %s\n",
+ dev->driver->pci_driver.name,
+ dev_name(dev->dev), master->unique);
+ } else {
+ seq_printf(m, "%s %s\n", dev->driver->pci_driver.name,
+ dev_name(dev->dev));
+ }
}
return 0;
diff --git a/drivers/gpu/drm/drm_ioctl.c b/drivers/gpu/drm/drm_ioctl.c
index 9b9ff46c237..7b03b197fc0 100644
--- a/drivers/gpu/drm/drm_ioctl.c
+++ b/drivers/gpu/drm/drm_ioctl.c
@@ -64,6 +64,19 @@ int drm_getunique(struct drm_device *dev, void *data,
return 0;
}
+static void
+drm_unset_busid(struct drm_device *dev,
+ struct drm_master *master)
+{
+ kfree(dev->devname);
+ dev->devname = NULL;
+
+ kfree(master->unique);
+ master->unique = NULL;
+ master->unique_len = 0;
+ master->unique_size = 0;
+}
+
/**
* Set the bus id.
*
@@ -94,17 +107,24 @@ int drm_setunique(struct drm_device *dev, void *data,
master->unique_len = u->unique_len;
master->unique_size = u->unique_len + 1;
master->unique = kmalloc(master->unique_size, GFP_KERNEL);
- if (!master->unique)
- return -ENOMEM;
- if (copy_from_user(master->unique, u->unique, master->unique_len))
- return -EFAULT;
+ if (!master->unique) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ if (copy_from_user(master->unique, u->unique, master->unique_len)) {
+ ret = -EFAULT;
+ goto err;
+ }
master->unique[master->unique_len] = '\0';
dev->devname = kmalloc(strlen(dev->driver->pci_driver.name) +
strlen(master->unique) + 2, GFP_KERNEL);
- if (!dev->devname)
- return -ENOMEM;
+ if (!dev->devname) {
+ ret = -ENOMEM;
+ goto err;
+ }
sprintf(dev->devname, "%s@%s", dev->driver->pci_driver.name,
master->unique);
@@ -113,53 +133,103 @@ int drm_setunique(struct drm_device *dev, void *data,
* busid.
*/
ret = sscanf(master->unique, "PCI:%d:%d:%d", &bus, &slot, &func);
- if (ret != 3)
- return -EINVAL;
+ if (ret != 3) {
+ ret = -EINVAL;
+ goto err;
+ }
+
domain = bus >> 8;
bus &= 0xff;
if ((domain != drm_get_pci_domain(dev)) ||
(bus != dev->pdev->bus->number) ||
(slot != PCI_SLOT(dev->pdev->devfn)) ||
- (func != PCI_FUNC(dev->pdev->devfn)))
- return -EINVAL;
+ (func != PCI_FUNC(dev->pdev->devfn))) {
+ ret = -EINVAL;
+ goto err;
+ }
return 0;
+
+err:
+ drm_unset_busid(dev, master);
+ return ret;
}
static int drm_set_busid(struct drm_device *dev, struct drm_file *file_priv)
{
struct drm_master *master = file_priv->master;
- int len;
+ int len, ret;
if (master->unique != NULL)
- return -EBUSY;
+ drm_unset_busid(dev, master);
- master->unique_len = 40;
- master->unique_size = master->unique_len;
- master->unique = kmalloc(master->unique_size, GFP_KERNEL);
- if (master->unique == NULL)
- return -ENOMEM;
-
- len = snprintf(master->unique, master->unique_len, "pci:%04x:%02x:%02x.%d",
- drm_get_pci_domain(dev),
- dev->pdev->bus->number,
- PCI_SLOT(dev->pdev->devfn),
- PCI_FUNC(dev->pdev->devfn));
- if (len >= master->unique_len)
- DRM_ERROR("buffer overflow");
- else
- master->unique_len = len;
+ if (drm_core_check_feature(dev, DRIVER_USE_PLATFORM_DEVICE)) {
+ master->unique_len = 10 + strlen(dev->platformdev->name);
+ master->unique = kmalloc(master->unique_len + 1, GFP_KERNEL);
- dev->devname = kmalloc(strlen(dev->driver->pci_driver.name) +
- master->unique_len + 2, GFP_KERNEL);
- if (dev->devname == NULL)
- return -ENOMEM;
+ if (master->unique == NULL)
+ return -ENOMEM;
- sprintf(dev->devname, "%s@%s", dev->driver->pci_driver.name,
- master->unique);
+ len = snprintf(master->unique, master->unique_len,
+ "platform:%s", dev->platformdev->name);
+
+ if (len > master->unique_len) {
+ DRM_ERROR("Unique buffer overflowed\n");
+ ret = -EINVAL;
+ goto err;
+ }
+
+ dev->devname =
+ kmalloc(strlen(dev->platformdev->name) +
+ master->unique_len + 2, GFP_KERNEL);
+
+ if (dev->devname == NULL) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ sprintf(dev->devname, "%s@%s", dev->platformdev->name,
+ master->unique);
+
+ } else {
+ master->unique_len = 40;
+ master->unique_size = master->unique_len;
+ master->unique = kmalloc(master->unique_size, GFP_KERNEL);
+ if (master->unique == NULL)
+ return -ENOMEM;
+
+ len = snprintf(master->unique, master->unique_len,
+ "pci:%04x:%02x:%02x.%d",
+ drm_get_pci_domain(dev),
+ dev->pdev->bus->number,
+ PCI_SLOT(dev->pdev->devfn),
+ PCI_FUNC(dev->pdev->devfn));
+ if (len >= master->unique_len) {
+ DRM_ERROR("buffer overflow");
+ ret = -EINVAL;
+ goto err;
+ } else
+ master->unique_len = len;
+
+ dev->devname =
+ kmalloc(strlen(dev->driver->pci_driver.name) +
+ master->unique_len + 2, GFP_KERNEL);
+
+ if (dev->devname == NULL) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ sprintf(dev->devname, "%s@%s", dev->driver->pci_driver.name,
+ master->unique);
+ }
return 0;
+
+err:
+ drm_unset_busid(dev, master);
+ return ret;
}
/**
@@ -323,7 +393,9 @@ int drm_setversion(struct drm_device *dev, void *data, struct drm_file *file_pri
/*
* Version 1.1 includes tying of DRM to specific device
*/
- drm_set_busid(dev, file_priv);
+ retcode = drm_set_busid(dev, file_priv);
+ if (retcode)
+ goto done;
}
}
diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c
index a263b7070fc..9d3a5030b6e 100644
--- a/drivers/gpu/drm/drm_irq.c
+++ b/drivers/gpu/drm/drm_irq.c
@@ -34,6 +34,7 @@
*/
#include "drmP.h"
+#include "drm_trace.h"
#include <linux/interrupt.h> /* For task queue support */
#include <linux/slab.h>
@@ -57,6 +58,9 @@ int drm_irq_by_busid(struct drm_device *dev, void *data,
{
struct drm_irq_busid *p = data;
+ if (drm_core_check_feature(dev, DRIVER_USE_PLATFORM_DEVICE))
+ return -EINVAL;
+
if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ))
return -EINVAL;
@@ -211,7 +215,7 @@ int drm_irq_install(struct drm_device *dev)
if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ))
return -EINVAL;
- if (dev->pdev->irq == 0)
+ if (drm_dev_to_irq(dev) == 0)
return -EINVAL;
mutex_lock(&dev->struct_mutex);
@@ -229,7 +233,7 @@ int drm_irq_install(struct drm_device *dev)
dev->irq_enabled = 1;
mutex_unlock(&dev->struct_mutex);
- DRM_DEBUG("irq=%d\n", dev->pdev->irq);
+ DRM_DEBUG("irq=%d\n", drm_dev_to_irq(dev));
/* Before installing handler */
dev->driver->irq_preinstall(dev);
@@ -302,14 +306,14 @@ int drm_irq_uninstall(struct drm_device * dev)
if (!irq_enabled)
return -EINVAL;
- DRM_DEBUG("irq=%d\n", dev->pdev->irq);
+ DRM_DEBUG("irq=%d\n", drm_dev_to_irq(dev));
if (!drm_core_check_feature(dev, DRIVER_MODESET))
vga_client_register(dev->pdev, NULL, NULL, NULL);
dev->driver->irq_uninstall(dev);
- free_irq(dev->pdev->irq, dev);
+ free_irq(drm_dev_to_irq(dev), dev);
return 0;
}
@@ -341,7 +345,7 @@ int drm_control(struct drm_device *dev, void *data,
if (drm_core_check_feature(dev, DRIVER_MODESET))
return 0;
if (dev->if_version < DRM_IF_VERSION(1, 2) &&
- ctl->irq != dev->pdev->irq)
+ ctl->irq != drm_dev_to_irq(dev))
return -EINVAL;
return drm_irq_install(dev);
case DRM_UNINST_HANDLER:
@@ -587,6 +591,7 @@ static int drm_queue_vblank_event(struct drm_device *dev, int pipe,
return -ENOMEM;
e->pipe = pipe;
+ e->base.pid = current->pid;
e->event.base.type = DRM_EVENT_VBLANK;
e->event.base.length = sizeof e->event;
e->event.user_data = vblwait->request.signal;
@@ -614,6 +619,9 @@ static int drm_queue_vblank_event(struct drm_device *dev, int pipe,
DRM_DEBUG("event on vblank count %d, current %d, crtc %d\n",
vblwait->request.sequence, seq, pipe);
+ trace_drm_vblank_event_queued(current->pid, pipe,
+ vblwait->request.sequence);
+
e->event.sequence = vblwait->request.sequence;
if ((seq - vblwait->request.sequence) <= (1 << 23)) {
e->event.tv_sec = now.tv_sec;
@@ -621,6 +629,8 @@ static int drm_queue_vblank_event(struct drm_device *dev, int pipe,
drm_vblank_put(dev, e->pipe);
list_add_tail(&e->base.link, &e->base.file_priv->event_list);
wake_up_interruptible(&e->base.file_priv->event_wait);
+ trace_drm_vblank_event_delivered(current->pid, pipe,
+ vblwait->request.sequence);
} else {
list_add_tail(&e->base.link, &dev->vblank_event_list);
}
@@ -651,7 +661,7 @@ int drm_wait_vblank(struct drm_device *dev, void *data,
int ret = 0;
unsigned int flags, seq, crtc;
- if ((!dev->pdev->irq) || (!dev->irq_enabled))
+ if ((!drm_dev_to_irq(dev)) || (!dev->irq_enabled))
return -EINVAL;
if (vblwait->request.type & _DRM_VBLANK_SIGNAL)
@@ -751,9 +761,13 @@ void drm_handle_vblank_events(struct drm_device *dev, int crtc)
drm_vblank_put(dev, e->pipe);
list_move_tail(&e->base.link, &e->base.file_priv->event_list);
wake_up_interruptible(&e->base.file_priv->event_wait);
+ trace_drm_vblank_event_delivered(e->base.pid, e->pipe,
+ e->event.sequence);
}
spin_unlock_irqrestore(&dev->event_lock, flags);
+
+ trace_drm_vblank_event(crtc, seq);
}
/**
diff --git a/drivers/gpu/drm/drm_mm.c b/drivers/gpu/drm/drm_mm.c
index 2ac074c8f5d..da99edc5088 100644
--- a/drivers/gpu/drm/drm_mm.c
+++ b/drivers/gpu/drm/drm_mm.c
@@ -48,44 +48,14 @@
#define MM_UNUSED_TARGET 4
-unsigned long drm_mm_tail_space(struct drm_mm *mm)
-{
- struct list_head *tail_node;
- struct drm_mm_node *entry;
-
- tail_node = mm->ml_entry.prev;
- 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(struct drm_mm *mm, unsigned long size)
-{
- struct list_head *tail_node;
- struct drm_mm_node *entry;
-
- tail_node = mm->ml_entry.prev;
- entry = list_entry(tail_node, struct drm_mm_node, ml_entry);
- if (!entry->free)
- return -ENOMEM;
-
- if (entry->size <= size)
- return -ENOMEM;
-
- entry->size -= size;
- return 0;
-}
-
static struct drm_mm_node *drm_mm_kmalloc(struct drm_mm *mm, int atomic)
{
struct drm_mm_node *child;
if (atomic)
- child = kmalloc(sizeof(*child), GFP_ATOMIC);
+ child = kzalloc(sizeof(*child), GFP_ATOMIC);
else
- child = kmalloc(sizeof(*child), GFP_KERNEL);
+ child = kzalloc(sizeof(*child), GFP_KERNEL);
if (unlikely(child == NULL)) {
spin_lock(&mm->unused_lock);
@@ -94,8 +64,8 @@ static struct drm_mm_node *drm_mm_kmalloc(struct drm_mm *mm, int atomic)
else {
child =
list_entry(mm->unused_nodes.next,
- struct drm_mm_node, fl_entry);
- list_del(&child->fl_entry);
+ struct drm_mm_node, free_stack);
+ list_del(&child->free_stack);
--mm->num_unused;
}
spin_unlock(&mm->unused_lock);
@@ -115,7 +85,7 @@ int drm_mm_pre_get(struct drm_mm *mm)
spin_lock(&mm->unused_lock);
while (mm->num_unused < MM_UNUSED_TARGET) {
spin_unlock(&mm->unused_lock);
- node = kmalloc(sizeof(*node), GFP_KERNEL);
+ node = kzalloc(sizeof(*node), GFP_KERNEL);
spin_lock(&mm->unused_lock);
if (unlikely(node == NULL)) {
@@ -124,7 +94,7 @@ int drm_mm_pre_get(struct drm_mm *mm)
return ret;
}
++mm->num_unused;
- list_add_tail(&node->fl_entry, &mm->unused_nodes);
+ list_add_tail(&node->free_stack, &mm->unused_nodes);
}
spin_unlock(&mm->unused_lock);
return 0;
@@ -146,27 +116,12 @@ static int drm_mm_create_tail_node(struct drm_mm *mm,
child->start = start;
child->mm = mm;
- list_add_tail(&child->ml_entry, &mm->ml_entry);
- list_add_tail(&child->fl_entry, &mm->fl_entry);
+ list_add_tail(&child->node_list, &mm->node_list);
+ list_add_tail(&child->free_stack, &mm->free_stack);
return 0;
}
-int drm_mm_add_space_to_tail(struct drm_mm *mm, unsigned long size, int atomic)
-{
- struct list_head *tail_node;
- struct drm_mm_node *entry;
-
- tail_node = mm->ml_entry.prev;
- 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, atomic);
- }
- entry->size += size;
- return 0;
-}
-
static struct drm_mm_node *drm_mm_split_at_start(struct drm_mm_node *parent,
unsigned long size,
int atomic)
@@ -177,15 +132,14 @@ static struct drm_mm_node *drm_mm_split_at_start(struct drm_mm_node *parent,
if (unlikely(child == NULL))
return NULL;
- INIT_LIST_HEAD(&child->fl_entry);
+ INIT_LIST_HEAD(&child->free_stack);
- child->free = 0;
child->size = size;
child->start = parent->start;
child->mm = parent->mm;
- list_add_tail(&child->ml_entry, &parent->ml_entry);
- INIT_LIST_HEAD(&child->fl_entry);
+ list_add_tail(&child->node_list, &parent->node_list);
+ INIT_LIST_HEAD(&child->free_stack);
parent->size -= size;
parent->start += size;
@@ -213,7 +167,7 @@ struct drm_mm_node *drm_mm_get_block_generic(struct drm_mm_node *node,
}
if (node->size == size) {
- list_del_init(&node->fl_entry);
+ list_del_init(&node->free_stack);
node->free = 0;
} else {
node = drm_mm_split_at_start(node, size, atomic);
@@ -251,7 +205,7 @@ struct drm_mm_node *drm_mm_get_block_range_generic(struct drm_mm_node *node,
}
if (node->size == size) {
- list_del_init(&node->fl_entry);
+ list_del_init(&node->free_stack);
node->free = 0;
} else {
node = drm_mm_split_at_start(node, size, atomic);
@@ -273,16 +227,19 @@ void drm_mm_put_block(struct drm_mm_node *cur)
{
struct drm_mm *mm = cur->mm;
- struct list_head *cur_head = &cur->ml_entry;
- struct list_head *root_head = &mm->ml_entry;
+ struct list_head *cur_head = &cur->node_list;
+ struct list_head *root_head = &mm->node_list;
struct drm_mm_node *prev_node = NULL;
struct drm_mm_node *next_node;
int merged = 0;
+ BUG_ON(cur->scanned_block || cur->scanned_prev_free
+ || cur->scanned_next_free);
+
if (cur_head->prev != root_head) {
prev_node =
- list_entry(cur_head->prev, struct drm_mm_node, ml_entry);
+ list_entry(cur_head->prev, struct drm_mm_node, node_list);
if (prev_node->free) {
prev_node->size += cur->size;
merged = 1;
@@ -290,15 +247,15 @@ void drm_mm_put_block(struct drm_mm_node *cur)
}
if (cur_head->next != root_head) {
next_node =
- list_entry(cur_head->next, struct drm_mm_node, ml_entry);
+ list_entry(cur_head->next, struct drm_mm_node, node_list);
if (next_node->free) {
if (merged) {
prev_node->size += next_node->size;
- list_del(&next_node->ml_entry);
- list_del(&next_node->fl_entry);
+ list_del(&next_node->node_list);
+ list_del(&next_node->free_stack);
spin_lock(&mm->unused_lock);
if (mm->num_unused < MM_UNUSED_TARGET) {
- list_add(&next_node->fl_entry,
+ list_add(&next_node->free_stack,
&mm->unused_nodes);
++mm->num_unused;
} else
@@ -313,12 +270,12 @@ void drm_mm_put_block(struct drm_mm_node *cur)
}
if (!merged) {
cur->free = 1;
- list_add(&cur->fl_entry, &mm->fl_entry);
+ list_add(&cur->free_stack, &mm->free_stack);
} else {
- list_del(&cur->ml_entry);
+ list_del(&cur->node_list);
spin_lock(&mm->unused_lock);
if (mm->num_unused < MM_UNUSED_TARGET) {
- list_add(&cur->fl_entry, &mm->unused_nodes);
+ list_add(&cur->free_stack, &mm->unused_nodes);
++mm->num_unused;
} else
kfree(cur);
@@ -328,40 +285,50 @@ void drm_mm_put_block(struct drm_mm_node *cur)
EXPORT_SYMBOL(drm_mm_put_block);
+static int check_free_mm_node(struct drm_mm_node *entry, unsigned long size,
+ unsigned alignment)
+{
+ unsigned wasted = 0;
+
+ if (entry->size < size)
+ return 0;
+
+ if (alignment) {
+ register unsigned tmp = entry->start % alignment;
+ if (tmp)
+ wasted = alignment - tmp;
+ }
+
+ if (entry->size >= size + wasted) {
+ return 1;
+ }
+
+ return 0;
+}
+
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;
struct drm_mm_node *entry;
struct drm_mm_node *best;
unsigned long best_size;
- unsigned wasted;
+
+ BUG_ON(mm->scanned_blocks);
best = NULL;
best_size = ~0UL;
- list_for_each(list, free_stack) {
- entry = list_entry(list, struct drm_mm_node, fl_entry);
- wasted = 0;
-
- if (entry->size < size)
+ list_for_each_entry(entry, &mm->free_stack, free_stack) {
+ if (!check_free_mm_node(entry, size, alignment))
continue;
- if (alignment) {
- register unsigned tmp = entry->start % alignment;
- if (tmp)
- wasted += alignment - tmp;
- }
+ if (!best_match)
+ return entry;
- if (entry->size >= size + wasted) {
- if (!best_match)
- return entry;
- if (entry->size < best_size) {
- best = entry;
- best_size = entry->size;
- }
+ if (entry->size < best_size) {
+ best = entry;
+ best_size = entry->size;
}
}
@@ -376,43 +343,28 @@ struct drm_mm_node *drm_mm_search_free_in_range(const struct drm_mm *mm,
unsigned long end,
int best_match)
{
- struct list_head *list;
- const struct list_head *free_stack = &mm->fl_entry;
struct drm_mm_node *entry;
struct drm_mm_node *best;
unsigned long best_size;
- unsigned wasted;
+
+ BUG_ON(mm->scanned_blocks);
best = NULL;
best_size = ~0UL;
- list_for_each(list, free_stack) {
- entry = list_entry(list, struct drm_mm_node, fl_entry);
- wasted = 0;
-
- if (entry->size < size)
- continue;
-
+ list_for_each_entry(entry, &mm->free_stack, free_stack) {
if (entry->start > end || (entry->start+entry->size) < start)
continue;
- if (entry->start < start)
- wasted += start - entry->start;
+ if (!check_free_mm_node(entry, size, alignment))
+ continue;
- if (alignment) {
- register unsigned tmp = (entry->start + wasted) % alignment;
- if (tmp)
- wasted += alignment - tmp;
- }
+ if (!best_match)
+ return entry;
- if (entry->size >= size + wasted &&
- (entry->start + wasted + size) <= end) {
- if (!best_match)
- return entry;
- if (entry->size < best_size) {
- best = entry;
- best_size = entry->size;
- }
+ if (entry->size < best_size) {
+ best = entry;
+ best_size = entry->size;
}
}
@@ -420,9 +372,161 @@ struct drm_mm_node *drm_mm_search_free_in_range(const struct drm_mm *mm,
}
EXPORT_SYMBOL(drm_mm_search_free_in_range);
+/**
+ * Initializa lru scanning.
+ *
+ * This simply sets up the scanning routines with the parameters for the desired
+ * hole.
+ *
+ * Warning: As long as the scan list is non-empty, no other operations than
+ * adding/removing nodes to/from the scan list are allowed.
+ */
+void drm_mm_init_scan(struct drm_mm *mm, unsigned long size,
+ unsigned alignment)
+{
+ mm->scan_alignment = alignment;
+ mm->scan_size = size;
+ mm->scanned_blocks = 0;
+ mm->scan_hit_start = 0;
+ mm->scan_hit_size = 0;
+}
+EXPORT_SYMBOL(drm_mm_init_scan);
+
+/**
+ * Add a node to the scan list that might be freed to make space for the desired
+ * hole.
+ *
+ * Returns non-zero, if a hole has been found, zero otherwise.
+ */
+int drm_mm_scan_add_block(struct drm_mm_node *node)
+{
+ struct drm_mm *mm = node->mm;
+ struct list_head *prev_free, *next_free;
+ struct drm_mm_node *prev_node, *next_node;
+
+ mm->scanned_blocks++;
+
+ prev_free = next_free = NULL;
+
+ BUG_ON(node->free);
+ node->scanned_block = 1;
+ node->free = 1;
+
+ if (node->node_list.prev != &mm->node_list) {
+ prev_node = list_entry(node->node_list.prev, struct drm_mm_node,
+ node_list);
+
+ if (prev_node->free) {
+ list_del(&prev_node->node_list);
+
+ node->start = prev_node->start;
+ node->size += prev_node->size;
+
+ prev_node->scanned_prev_free = 1;
+
+ prev_free = &prev_node->free_stack;
+ }
+ }
+
+ if (node->node_list.next != &mm->node_list) {
+ next_node = list_entry(node->node_list.next, struct drm_mm_node,
+ node_list);
+
+ if (next_node->free) {
+ list_del(&next_node->node_list);
+
+ node->size += next_node->size;
+
+ next_node->scanned_next_free = 1;
+
+ next_free = &next_node->free_stack;
+ }
+ }
+
+ /* The free_stack list is not used for allocated objects, so these two
+ * pointers can be abused (as long as no allocations in this memory
+ * manager happens). */
+ node->free_stack.prev = prev_free;
+ node->free_stack.next = next_free;
+
+ if (check_free_mm_node(node, mm->scan_size, mm->scan_alignment)) {
+ mm->scan_hit_start = node->start;
+ mm->scan_hit_size = node->size;
+
+ return 1;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(drm_mm_scan_add_block);
+
+/**
+ * Remove a node from the scan list.
+ *
+ * Nodes _must_ be removed in the exact same order from the scan list as they
+ * have been added, otherwise the internal state of the memory manager will be
+ * corrupted.
+ *
+ * When the scan list is empty, the selected memory nodes can be freed. An
+ * immediatly following drm_mm_search_free with best_match = 0 will then return
+ * the just freed block (because its at the top of the free_stack list).
+ *
+ * Returns one if this block should be evicted, zero otherwise. Will always
+ * return zero when no hole has been found.
+ */
+int drm_mm_scan_remove_block(struct drm_mm_node *node)
+{
+ struct drm_mm *mm = node->mm;
+ struct drm_mm_node *prev_node, *next_node;
+
+ mm->scanned_blocks--;
+
+ BUG_ON(!node->scanned_block);
+ node->scanned_block = 0;
+ node->free = 0;
+
+ prev_node = list_entry(node->free_stack.prev, struct drm_mm_node,
+ free_stack);
+ next_node = list_entry(node->free_stack.next, struct drm_mm_node,
+ free_stack);
+
+ if (prev_node) {
+ BUG_ON(!prev_node->scanned_prev_free);
+ prev_node->scanned_prev_free = 0;
+
+ list_add_tail(&prev_node->node_list, &node->node_list);
+
+ node->start = prev_node->start + prev_node->size;
+ node->size -= prev_node->size;
+ }
+
+ if (next_node) {
+ BUG_ON(!next_node->scanned_next_free);
+ next_node->scanned_next_free = 0;
+
+ list_add(&next_node->node_list, &node->node_list);
+
+ node->size -= next_node->size;
+ }
+
+ INIT_LIST_HEAD(&node->free_stack);
+
+ /* Only need to check for containement because start&size for the
+ * complete resulting free block (not just the desired part) is
+ * stored. */
+ if (node->start >= mm->scan_hit_start &&
+ node->start + node->size
+ <= mm->scan_hit_start + mm->scan_hit_size) {
+ return 1;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(drm_mm_scan_remove_block);
+
int drm_mm_clean(struct drm_mm * mm)
{
- struct list_head *head = &mm->ml_entry;
+ struct list_head *head = &mm->node_list;
return (head->next->next == head);
}
@@ -430,10 +534,11 @@ EXPORT_SYMBOL(drm_mm_clean);
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);
+ INIT_LIST_HEAD(&mm->node_list);
+ INIT_LIST_HEAD(&mm->free_stack);
INIT_LIST_HEAD(&mm->unused_nodes);
mm->num_unused = 0;
+ mm->scanned_blocks = 0;
spin_lock_init(&mm->unused_lock);
return drm_mm_create_tail_node(mm, start, size, 0);
@@ -442,25 +547,25 @@ EXPORT_SYMBOL(drm_mm_init);
void drm_mm_takedown(struct drm_mm * mm)
{
- struct list_head *bnode = mm->fl_entry.next;
+ struct list_head *bnode = mm->free_stack.next;
struct drm_mm_node *entry;
struct drm_mm_node *next;
- entry = list_entry(bnode, struct drm_mm_node, fl_entry);
+ entry = list_entry(bnode, struct drm_mm_node, free_stack);
- if (entry->ml_entry.next != &mm->ml_entry ||
- entry->fl_entry.next != &mm->fl_entry) {
+ if (entry->node_list.next != &mm->node_list ||
+ entry->free_stack.next != &mm->free_stack) {
DRM_ERROR("Memory manager not clean. Delaying takedown\n");
return;
}
- list_del(&entry->fl_entry);
- list_del(&entry->ml_entry);
+ list_del(&entry->free_stack);
+ list_del(&entry->node_list);
kfree(entry);
spin_lock(&mm->unused_lock);
- list_for_each_entry_safe(entry, next, &mm->unused_nodes, fl_entry) {
- list_del(&entry->fl_entry);
+ list_for_each_entry_safe(entry, next, &mm->unused_nodes, free_stack) {
+ list_del(&entry->free_stack);
kfree(entry);
--mm->num_unused;
}
@@ -475,7 +580,7 @@ void drm_mm_debug_table(struct drm_mm *mm, const char *prefix)
struct drm_mm_node *entry;
int total_used = 0, total_free = 0, total = 0;
- list_for_each_entry(entry, &mm->ml_entry, ml_entry) {
+ list_for_each_entry(entry, &mm->node_list, node_list) {
printk(KERN_DEBUG "%s 0x%08lx-0x%08lx: %8ld: %s\n",
prefix, entry->start, entry->start + entry->size,
entry->size, entry->free ? "free" : "used");
@@ -496,7 +601,7 @@ int drm_mm_dump_table(struct seq_file *m, struct drm_mm *mm)
struct drm_mm_node *entry;
int total_used = 0, total_free = 0, total = 0;
- list_for_each_entry(entry, &mm->ml_entry, ml_entry) {
+ list_for_each_entry(entry, &mm->node_list, node_list) {
seq_printf(m, "0x%08lx-0x%08lx: 0x%08lx: %s\n", entry->start, entry->start + entry->size, entry->size, entry->free ? "free" : "used");
total += entry->size;
if (entry->free)
diff --git a/drivers/gpu/drm/drm_pci.c b/drivers/gpu/drm/drm_pci.c
index 2ea9ad4a8d6..e20f78b542a 100644
--- a/drivers/gpu/drm/drm_pci.c
+++ b/drivers/gpu/drm/drm_pci.c
@@ -124,4 +124,147 @@ void drm_pci_free(struct drm_device * dev, drm_dma_handle_t * dmah)
EXPORT_SYMBOL(drm_pci_free);
+#ifdef CONFIG_PCI
+/**
+ * Register.
+ *
+ * \param pdev - PCI device structure
+ * \param ent entry from the PCI ID table with device type flags
+ * \return zero on success or a negative number on failure.
+ *
+ * Attempt to gets inter module "drm" information. If we are first
+ * then register the character device and inter module information.
+ * Try and register, if we fail to register, backout previous work.
+ */
+int drm_get_pci_dev(struct pci_dev *pdev, const struct pci_device_id *ent,
+ struct drm_driver *driver)
+{
+ struct drm_device *dev;
+ int ret;
+
+ DRM_DEBUG("\n");
+
+ dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+ if (!dev)
+ return -ENOMEM;
+
+ ret = pci_enable_device(pdev);
+ if (ret)
+ goto err_g1;
+
+ pci_set_master(pdev);
+
+ dev->pdev = pdev;
+ dev->dev = &pdev->dev;
+
+ dev->pci_device = pdev->device;
+ dev->pci_vendor = pdev->vendor;
+
+#ifdef __alpha__
+ dev->hose = pdev->sysdata;
+#endif
+
+ if ((ret = drm_fill_in_dev(dev, ent, driver))) {
+ printk(KERN_ERR "DRM: Fill_in_dev failed.\n");
+ goto err_g2;
+ }
+
+ if (drm_core_check_feature(dev, DRIVER_MODESET)) {
+ pci_set_drvdata(pdev, dev);
+ ret = drm_get_minor(dev, &dev->control, DRM_MINOR_CONTROL);
+ if (ret)
+ goto err_g2;
+ }
+
+ if ((ret = drm_get_minor(dev, &dev->primary, DRM_MINOR_LEGACY)))
+ goto err_g3;
+
+ if (dev->driver->load) {
+ ret = dev->driver->load(dev, ent->driver_data);
+ if (ret)
+ goto err_g4;
+ }
+
+ /* setup the grouping for the legacy output */
+ if (drm_core_check_feature(dev, DRIVER_MODESET)) {
+ ret = drm_mode_group_init_legacy_group(dev,
+ &dev->primary->mode_group);
+ if (ret)
+ goto err_g4;
+ }
+
+ list_add_tail(&dev->driver_item, &driver->device_list);
+
+ DRM_INFO("Initialized %s %d.%d.%d %s for %s on minor %d\n",
+ driver->name, driver->major, driver->minor, driver->patchlevel,
+ driver->date, pci_name(pdev), dev->primary->index);
+
+ return 0;
+
+err_g4:
+ drm_put_minor(&dev->primary);
+err_g3:
+ if (drm_core_check_feature(dev, DRIVER_MODESET))
+ drm_put_minor(&dev->control);
+err_g2:
+ pci_disable_device(pdev);
+err_g1:
+ kfree(dev);
+ return ret;
+}
+EXPORT_SYMBOL(drm_get_pci_dev);
+
+/**
+ * PCI device initialization. Called via drm_init at module load time,
+ *
+ * \return zero on success or a negative number on failure.
+ *
+ * Initializes a drm_device structures,registering the
+ * stubs and initializing the AGP device.
+ *
+ * Expands the \c DRIVER_PREINIT and \c DRIVER_POST_INIT macros before and
+ * after the initialization for driver customization.
+ */
+int drm_pci_init(struct drm_driver *driver)
+{
+ struct pci_dev *pdev = NULL;
+ const struct pci_device_id *pid;
+ int i;
+
+ if (driver->driver_features & DRIVER_MODESET)
+ return pci_register_driver(&driver->pci_driver);
+
+ /* If not using KMS, fall back to stealth mode manual scanning. */
+ for (i = 0; driver->pci_driver.id_table[i].vendor != 0; i++) {
+ pid = &driver->pci_driver.id_table[i];
+
+ /* Loop around setting up a DRM device for each PCI device
+ * matching our ID and device class. If we had the internal
+ * function that pci_get_subsys and pci_get_class used, we'd
+ * be able to just pass pid in instead of doing a two-stage
+ * thing.
+ */
+ pdev = NULL;
+ while ((pdev =
+ pci_get_subsys(pid->vendor, pid->device, pid->subvendor,
+ pid->subdevice, pdev)) != NULL) {
+ if ((pdev->class & pid->class_mask) != pid->class)
+ continue;
+
+ /* stealth mode requires a manual probe */
+ pci_dev_get(pdev);
+ drm_get_pci_dev(pdev, pid, driver);
+ }
+ }
+ return 0;
+}
+
+#else
+
+int drm_pci_init(struct drm_driver *driver)
+{
+ return -1;
+}
+
+#endif
/*@}*/
diff --git a/drivers/gpu/drm/drm_platform.c b/drivers/gpu/drm/drm_platform.c
new file mode 100644
index 00000000000..460e9a3afa8
--- /dev/null
+++ b/drivers/gpu/drm/drm_platform.c
@@ -0,0 +1,122 @@
+/*
+ * Derived from drm_pci.c
+ *
+ * Copyright 2003 José Fonseca.
+ * Copyright 2003 Leif Delgass.
+ * Copyright (c) 2009, Code Aurora Forum.
+ * All Rights Reserved.
+ *
+ * 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 (including the next
+ * paragraph) 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 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 "drmP.h"
+
+/**
+ * Register.
+ *
+ * \param platdev - Platform device struture
+ * \return zero on success or a negative number on failure.
+ *
+ * Attempt to gets inter module "drm" information. If we are first
+ * then register the character device and inter module information.
+ * Try and register, if we fail to register, backout previous work.
+ */
+
+int drm_get_platform_dev(struct platform_device *platdev,
+ struct drm_driver *driver)
+{
+ struct drm_device *dev;
+ int ret;
+
+ DRM_DEBUG("\n");
+
+ dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+ if (!dev)
+ return -ENOMEM;
+
+ dev->platformdev = platdev;
+ dev->dev = &platdev->dev;
+
+ ret = drm_fill_in_dev(dev, NULL, driver);
+
+ if (ret) {
+ printk(KERN_ERR "DRM: Fill_in_dev failed.\n");
+ goto err_g1;
+ }
+
+ if (drm_core_check_feature(dev, DRIVER_MODESET)) {
+ dev_set_drvdata(&platdev->dev, dev);
+ ret = drm_get_minor(dev, &dev->control, DRM_MINOR_CONTROL);
+ if (ret)
+ goto err_g1;
+ }
+
+ ret = drm_get_minor(dev, &dev->primary, DRM_MINOR_LEGACY);
+ if (ret)
+ goto err_g2;
+
+ if (dev->driver->load) {
+ ret = dev->driver->load(dev, 0);
+ if (ret)
+ goto err_g3;
+ }
+
+ /* setup the grouping for the legacy output */
+ if (drm_core_check_feature(dev, DRIVER_MODESET)) {
+ ret = drm_mode_group_init_legacy_group(dev,
+ &dev->primary->mode_group);
+ if (ret)
+ goto err_g3;
+ }
+
+ list_add_tail(&dev->driver_item, &driver->device_list);
+
+ DRM_INFO("Initialized %s %d.%d.%d %s on minor %d\n",
+ driver->name, driver->major, driver->minor, driver->patchlevel,
+ driver->date, dev->primary->index);
+
+ return 0;
+
+err_g3:
+ drm_put_minor(&dev->primary);
+err_g2:
+ if (drm_core_check_feature(dev, DRIVER_MODESET))
+ drm_put_minor(&dev->control);
+err_g1:
+ kfree(dev);
+ return ret;
+}
+EXPORT_SYMBOL(drm_get_platform_dev);
+
+/**
+ * Platform device initialization. Called via drm_init at module load time,
+ *
+ * \return zero on success or a negative number on failure.
+ *
+ * Initializes a drm_device structures,registering the
+ * stubs
+ *
+ * Expands the \c DRIVER_PREINIT and \c DRIVER_POST_INIT macros before and
+ * after the initialization for driver customization.
+ */
+
+int drm_platform_init(struct drm_driver *driver)
+{
+ return drm_get_platform_dev(driver->platform_device, driver);
+}
diff --git a/drivers/gpu/drm/drm_stub.c b/drivers/gpu/drm/drm_stub.c
index a0c365f2e52..d1ad57450df 100644
--- a/drivers/gpu/drm/drm_stub.c
+++ b/drivers/gpu/drm/drm_stub.c
@@ -156,6 +156,9 @@ static void drm_master_destroy(struct kref *kref)
master->unique_len = 0;
}
+ kfree(dev->devname);
+ dev->devname = NULL;
+
list_for_each_entry_safe(pt, next, &master->magicfree, head) {
list_del(&pt->head);
drm_ht_remove_item(&master->magiclist, &pt->hash_item);
@@ -224,7 +227,7 @@ int drm_dropmaster_ioctl(struct drm_device *dev, void *data,
return 0;
}
-static int drm_fill_in_dev(struct drm_device * dev, struct pci_dev *pdev,
+int drm_fill_in_dev(struct drm_device *dev,
const struct pci_device_id *ent,
struct drm_driver *driver)
{
@@ -245,14 +248,6 @@ static int drm_fill_in_dev(struct drm_device * dev, struct pci_dev *pdev,
idr_init(&dev->drw_idr);
- dev->pdev = pdev;
- dev->pci_device = pdev->device;
- dev->pci_vendor = pdev->vendor;
-
-#ifdef __alpha__
- dev->hose = pdev->sysdata;
-#endif
-
if (drm_ht_create(&dev->map_hash, 12)) {
return -ENOMEM;
}
@@ -321,7 +316,7 @@ static int drm_fill_in_dev(struct drm_device * dev, struct pci_dev *pdev,
* create the proc init entry via proc_init(). This routines assigns
* minor numbers to secondary heads of multi-headed cards
*/
-static int drm_get_minor(struct drm_device *dev, struct drm_minor **minor, int type)
+int drm_get_minor(struct drm_device *dev, struct drm_minor **minor, int type)
{
struct drm_minor *new_minor;
int ret;
@@ -388,83 +383,6 @@ err_idr:
}
/**
- * Register.
- *
- * \param pdev - PCI device structure
- * \param ent entry from the PCI ID table with device type flags
- * \return zero on success or a negative number on failure.
- *
- * Attempt to gets inter module "drm" information. If we are first
- * then register the character device and inter module information.
- * Try and register, if we fail to register, backout previous work.
- */
-int drm_get_dev(struct pci_dev *pdev, const struct pci_device_id *ent,
- struct drm_driver *driver)
-{
- struct drm_device *dev;
- int ret;
-
- DRM_DEBUG("\n");
-
- dev = kzalloc(sizeof(*dev), GFP_KERNEL);
- if (!dev)
- return -ENOMEM;
-
- ret = pci_enable_device(pdev);
- if (ret)
- goto err_g1;
-
- pci_set_master(pdev);
- if ((ret = drm_fill_in_dev(dev, pdev, ent, driver))) {
- printk(KERN_ERR "DRM: Fill_in_dev failed.\n");
- goto err_g2;
- }
-
- if (drm_core_check_feature(dev, DRIVER_MODESET)) {
- pci_set_drvdata(pdev, dev);
- ret = drm_get_minor(dev, &dev->control, DRM_MINOR_CONTROL);
- if (ret)
- goto err_g2;
- }
-
- if ((ret = drm_get_minor(dev, &dev->primary, DRM_MINOR_LEGACY)))
- goto err_g3;
-
- if (dev->driver->load) {
- ret = dev->driver->load(dev, ent->driver_data);
- if (ret)
- goto err_g4;
- }
-
- /* setup the grouping for the legacy output */
- if (drm_core_check_feature(dev, DRIVER_MODESET)) {
- ret = drm_mode_group_init_legacy_group(dev, &dev->primary->mode_group);
- if (ret)
- goto err_g4;
- }
-
- list_add_tail(&dev->driver_item, &driver->device_list);
-
- DRM_INFO("Initialized %s %d.%d.%d %s for %s on minor %d\n",
- driver->name, driver->major, driver->minor, driver->patchlevel,
- driver->date, pci_name(pdev), dev->primary->index);
-
- return 0;
-
-err_g4:
- drm_put_minor(&dev->primary);
-err_g3:
- if (drm_core_check_feature(dev, DRIVER_MODESET))
- drm_put_minor(&dev->control);
-err_g2:
- pci_disable_device(pdev);
-err_g1:
- kfree(dev);
- return ret;
-}
-EXPORT_SYMBOL(drm_get_dev);
-
-/**
* Put a secondary minor number.
*
* \param sec_minor - structure to be released
diff --git a/drivers/gpu/drm/drm_sysfs.c b/drivers/gpu/drm/drm_sysfs.c
index 101d381e9d8..86118a74223 100644
--- a/drivers/gpu/drm/drm_sysfs.c
+++ b/drivers/gpu/drm/drm_sysfs.c
@@ -489,7 +489,8 @@ int drm_sysfs_device_add(struct drm_minor *minor)
int err;
char *minor_str;
- minor->kdev.parent = &minor->dev->pdev->dev;
+ minor->kdev.parent = minor->dev->dev;
+
minor->kdev.class = drm_class;
minor->kdev.release = drm_sysfs_device_release;
minor->kdev.devt = minor->device;
diff --git a/drivers/gpu/drm/drm_trace.h b/drivers/gpu/drm/drm_trace.h
new file mode 100644
index 00000000000..03ea964aa60
--- /dev/null
+++ b/drivers/gpu/drm/drm_trace.h
@@ -0,0 +1,66 @@
+#if !defined(_DRM_TRACE_H_) || defined(TRACE_HEADER_MULTI_READ)
+#define _DRM_TRACE_H_
+
+#include <linux/stringify.h>
+#include <linux/types.h>
+#include <linux/tracepoint.h>
+
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM drm
+#define TRACE_SYSTEM_STRING __stringify(TRACE_SYSTEM)
+#define TRACE_INCLUDE_FILE drm_trace
+
+TRACE_EVENT(drm_vblank_event,
+ TP_PROTO(int crtc, unsigned int seq),
+ TP_ARGS(crtc, seq),
+ TP_STRUCT__entry(
+ __field(int, crtc)
+ __field(unsigned int, seq)
+ ),
+ TP_fast_assign(
+ __entry->crtc = crtc;
+ __entry->seq = seq;
+ ),
+ TP_printk("crtc=%d, seq=%d", __entry->crtc, __entry->seq)
+);
+
+TRACE_EVENT(drm_vblank_event_queued,
+ TP_PROTO(pid_t pid, int crtc, unsigned int seq),
+ TP_ARGS(pid, crtc, seq),
+ TP_STRUCT__entry(
+ __field(pid_t, pid)
+ __field(int, crtc)
+ __field(unsigned int, seq)
+ ),
+ TP_fast_assign(
+ __entry->pid = pid;
+ __entry->crtc = crtc;
+ __entry->seq = seq;
+ ),
+ TP_printk("pid=%d, crtc=%d, seq=%d", __entry->pid, __entry->crtc, \
+ __entry->seq)
+);
+
+TRACE_EVENT(drm_vblank_event_delivered,
+ TP_PROTO(pid_t pid, int crtc, unsigned int seq),
+ TP_ARGS(pid, crtc, seq),
+ TP_STRUCT__entry(
+ __field(pid_t, pid)
+ __field(int, crtc)
+ __field(unsigned int, seq)
+ ),
+ TP_fast_assign(
+ __entry->pid = pid;
+ __entry->crtc = crtc;
+ __entry->seq = seq;
+ ),
+ TP_printk("pid=%d, crtc=%d, seq=%d", __entry->pid, __entry->crtc, \
+ __entry->seq)
+);
+
+#endif /* _DRM_TRACE_H_ */
+
+/* This part must be outside protection */
+#undef TRACE_INCLUDE_PATH
+#define TRACE_INCLUDE_PATH .
+#include <trace/define_trace.h>
diff --git a/drivers/gpu/drm/drm_trace_points.c b/drivers/gpu/drm/drm_trace_points.c
new file mode 100644
index 00000000000..0d0eb90864a
--- /dev/null
+++ b/drivers/gpu/drm/drm_trace_points.c
@@ -0,0 +1,4 @@
+#include "drmP.h"
+
+#define CREATE_TRACE_POINTS
+#include "drm_trace.h"
diff --git a/drivers/gpu/drm/drm_vm.c b/drivers/gpu/drm/drm_vm.c
index c3b13fb41d0..3778360ecee 100644
--- a/drivers/gpu/drm/drm_vm.c
+++ b/drivers/gpu/drm/drm_vm.c
@@ -61,7 +61,7 @@ static pgprot_t drm_io_prot(uint32_t map_type, struct vm_area_struct *vma)
tmp = pgprot_writecombine(tmp);
else
tmp = pgprot_noncached(tmp);
-#elif defined(__sparc__)
+#elif defined(__sparc__) || defined(__arm__)
tmp = pgprot_noncached(tmp);
#endif
return tmp;
@@ -601,6 +601,7 @@ int drm_mmap_locked(struct file *filp, struct vm_area_struct *vma)
}
switch (map->type) {
+#if !defined(__arm__)
case _DRM_AGP:
if (drm_core_has_AGP(dev) && dev->agp->cant_use_aperture) {
/*
@@ -615,20 +616,31 @@ int drm_mmap_locked(struct file *filp, struct vm_area_struct *vma)
break;
}
/* fall through to _DRM_FRAME_BUFFER... */
+#endif
case _DRM_FRAME_BUFFER:
case _DRM_REGISTERS:
offset = dev->driver->get_reg_ofs(dev);
vma->vm_flags |= VM_IO; /* not in core dump */
vma->vm_page_prot = drm_io_prot(map->type, vma);
+#if !defined(__arm__)
if (io_remap_pfn_range(vma, vma->vm_start,
(map->offset + offset) >> PAGE_SHIFT,
vma->vm_end - vma->vm_start,
vma->vm_page_prot))
return -EAGAIN;
+#else
+ if (remap_pfn_range(vma, vma->vm_start,
+ (map->offset + offset) >> PAGE_SHIFT,
+ vma->vm_end - vma->vm_start,
+ vma->vm_page_prot))
+ return -EAGAIN;
+#endif
+
DRM_DEBUG(" Type = %d; start = 0x%lx, end = 0x%lx,"
" offset = 0x%llx\n",
map->type,
vma->vm_start, vma->vm_end, (unsigned long long)(map->offset + offset));
+
vma->vm_ops = &drm_vm_ops;
break;
case _DRM_CONSISTENT:
diff --git a/drivers/gpu/drm/i2c/Makefile b/drivers/gpu/drm/i2c/Makefile
index 6d2abaf35ba..92862563e7e 100644
--- a/drivers/gpu/drm/i2c/Makefile
+++ b/drivers/gpu/drm/i2c/Makefile
@@ -2,3 +2,6 @@ ccflags-y := -Iinclude/drm
ch7006-y := ch7006_drv.o ch7006_mode.o
obj-$(CONFIG_DRM_I2C_CH7006) += ch7006.o
+
+sil164-y := sil164_drv.o
+obj-$(CONFIG_DRM_I2C_SIL164) += sil164.o
diff --git a/drivers/gpu/drm/i2c/ch7006_drv.c b/drivers/gpu/drm/i2c/ch7006_drv.c
index 81681a07a80..833b35f44a7 100644
--- a/drivers/gpu/drm/i2c/ch7006_drv.c
+++ b/drivers/gpu/drm/i2c/ch7006_drv.c
@@ -33,7 +33,7 @@ static void ch7006_encoder_set_config(struct drm_encoder *encoder,
{
struct ch7006_priv *priv = to_ch7006_priv(encoder);
- priv->params = params;
+ priv->params = *(struct ch7006_encoder_params *)params;
}
static void ch7006_encoder_destroy(struct drm_encoder *encoder)
@@ -114,7 +114,7 @@ static void ch7006_encoder_mode_set(struct drm_encoder *encoder,
{
struct i2c_client *client = drm_i2c_encoder_get_client(encoder);
struct ch7006_priv *priv = to_ch7006_priv(encoder);
- struct ch7006_encoder_params *params = priv->params;
+ struct ch7006_encoder_params *params = &priv->params;
struct ch7006_state *state = &priv->state;
uint8_t *regs = state->regs;
struct ch7006_mode *mode = priv->mode;
@@ -428,6 +428,22 @@ static int ch7006_remove(struct i2c_client *client)
return 0;
}
+static int ch7006_suspend(struct i2c_client *client, pm_message_t mesg)
+{
+ ch7006_dbg(client, "\n");
+
+ return 0;
+}
+
+static int ch7006_resume(struct i2c_client *client)
+{
+ ch7006_dbg(client, "\n");
+
+ ch7006_write(client, 0x3d, 0x0);
+
+ return 0;
+}
+
static int ch7006_encoder_init(struct i2c_client *client,
struct drm_device *dev,
struct drm_encoder_slave *encoder)
@@ -487,6 +503,8 @@ static struct drm_i2c_encoder_driver ch7006_driver = {
.i2c_driver = {
.probe = ch7006_probe,
.remove = ch7006_remove,
+ .suspend = ch7006_suspend,
+ .resume = ch7006_resume,
.driver = {
.name = "ch7006",
diff --git a/drivers/gpu/drm/i2c/ch7006_priv.h b/drivers/gpu/drm/i2c/ch7006_priv.h
index b06d3d93d8a..1c6d2e3bd96 100644
--- a/drivers/gpu/drm/i2c/ch7006_priv.h
+++ b/drivers/gpu/drm/i2c/ch7006_priv.h
@@ -77,7 +77,7 @@ struct ch7006_state {
};
struct ch7006_priv {
- struct ch7006_encoder_params *params;
+ struct ch7006_encoder_params params;
struct ch7006_mode *mode;
struct ch7006_state state;
diff --git a/drivers/gpu/drm/i2c/sil164_drv.c b/drivers/gpu/drm/i2c/sil164_drv.c
new file mode 100644
index 00000000000..0b6773290c0
--- /dev/null
+++ b/drivers/gpu/drm/i2c/sil164_drv.c
@@ -0,0 +1,462 @@
+/*
+ * Copyright (C) 2010 Francisco Jerez.
+ * All Rights Reserved.
+ *
+ * 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 (including the
+ * next paragraph) 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 COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS 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 "drmP.h"
+#include "drm_crtc_helper.h"
+#include "drm_encoder_slave.h"
+#include "i2c/sil164.h"
+
+struct sil164_priv {
+ struct sil164_encoder_params config;
+ struct i2c_client *duallink_slave;
+
+ uint8_t saved_state[0x10];
+ uint8_t saved_slave_state[0x10];
+};
+
+#define to_sil164_priv(x) \
+ ((struct sil164_priv *)to_encoder_slave(x)->slave_priv)
+
+#define sil164_dbg(client, format, ...) do { \
+ if (drm_debug & DRM_UT_KMS) \
+ dev_printk(KERN_DEBUG, &client->dev, \
+ "%s: " format, __func__, ## __VA_ARGS__); \
+ } while (0)
+#define sil164_info(client, format, ...) \
+ dev_info(&client->dev, format, __VA_ARGS__)
+#define sil164_err(client, format, ...) \
+ dev_err(&client->dev, format, __VA_ARGS__)
+
+#define SIL164_I2C_ADDR_MASTER 0x38
+#define SIL164_I2C_ADDR_SLAVE 0x39
+
+/* HW register definitions */
+
+#define SIL164_VENDOR_LO 0x0
+#define SIL164_VENDOR_HI 0x1
+#define SIL164_DEVICE_LO 0x2
+#define SIL164_DEVICE_HI 0x3
+#define SIL164_REVISION 0x4
+#define SIL164_FREQ_MIN 0x6
+#define SIL164_FREQ_MAX 0x7
+#define SIL164_CONTROL0 0x8
+# define SIL164_CONTROL0_POWER_ON 0x01
+# define SIL164_CONTROL0_EDGE_RISING 0x02
+# define SIL164_CONTROL0_INPUT_24BIT 0x04
+# define SIL164_CONTROL0_DUAL_EDGE 0x08
+# define SIL164_CONTROL0_HSYNC_ON 0x10
+# define SIL164_CONTROL0_VSYNC_ON 0x20
+#define SIL164_DETECT 0x9
+# define SIL164_DETECT_INTR_STAT 0x01
+# define SIL164_DETECT_HOTPLUG_STAT 0x02
+# define SIL164_DETECT_RECEIVER_STAT 0x04
+# define SIL164_DETECT_INTR_MODE_RECEIVER 0x00
+# define SIL164_DETECT_INTR_MODE_HOTPLUG 0x08
+# define SIL164_DETECT_OUT_MODE_HIGH 0x00
+# define SIL164_DETECT_OUT_MODE_INTR 0x10
+# define SIL164_DETECT_OUT_MODE_RECEIVER 0x20
+# define SIL164_DETECT_OUT_MODE_HOTPLUG 0x30
+# define SIL164_DETECT_VSWING_STAT 0x80
+#define SIL164_CONTROL1 0xa
+# define SIL164_CONTROL1_DESKEW_ENABLE 0x10
+# define SIL164_CONTROL1_DESKEW_INCR_SHIFT 5
+#define SIL164_GPIO 0xb
+#define SIL164_CONTROL2 0xc
+# define SIL164_CONTROL2_FILTER_ENABLE 0x01
+# define SIL164_CONTROL2_FILTER_SETTING_SHIFT 1
+# define SIL164_CONTROL2_DUALLINK_MASTER 0x40
+# define SIL164_CONTROL2_SYNC_CONT 0x80
+#define SIL164_DUALLINK 0xd
+# define SIL164_DUALLINK_ENABLE 0x10
+# define SIL164_DUALLINK_SKEW_SHIFT 5
+#define SIL164_PLLZONE 0xe
+# define SIL164_PLLZONE_STAT 0x08
+# define SIL164_PLLZONE_FORCE_ON 0x10
+# define SIL164_PLLZONE_FORCE_HIGH 0x20
+
+/* HW access functions */
+
+static void
+sil164_write(struct i2c_client *client, uint8_t addr, uint8_t val)
+{
+ uint8_t buf[] = {addr, val};
+ int ret;
+
+ ret = i2c_master_send(client, buf, ARRAY_SIZE(buf));
+ if (ret < 0)
+ sil164_err(client, "Error %d writing to subaddress 0x%x\n",
+ ret, addr);
+}
+
+static uint8_t
+sil164_read(struct i2c_client *client, uint8_t addr)
+{
+ uint8_t val;
+ int ret;
+
+ ret = i2c_master_send(client, &addr, sizeof(addr));
+ if (ret < 0)
+ goto fail;
+
+ ret = i2c_master_recv(client, &val, sizeof(val));
+ if (ret < 0)
+ goto fail;
+
+ return val;
+
+fail:
+ sil164_err(client, "Error %d reading from subaddress 0x%x\n",
+ ret, addr);
+ return 0;
+}
+
+static void
+sil164_save_state(struct i2c_client *client, uint8_t *state)
+{
+ int i;
+
+ for (i = 0x8; i <= 0xe; i++)
+ state[i] = sil164_read(client, i);
+}
+
+static void
+sil164_restore_state(struct i2c_client *client, uint8_t *state)
+{
+ int i;
+
+ for (i = 0x8; i <= 0xe; i++)
+ sil164_write(client, i, state[i]);
+}
+
+static void
+sil164_set_power_state(struct i2c_client *client, bool on)
+{
+ uint8_t control0 = sil164_read(client, SIL164_CONTROL0);
+
+ if (on)
+ control0 |= SIL164_CONTROL0_POWER_ON;
+ else
+ control0 &= ~SIL164_CONTROL0_POWER_ON;
+
+ sil164_write(client, SIL164_CONTROL0, control0);
+}
+
+static void
+sil164_init_state(struct i2c_client *client,
+ struct sil164_encoder_params *config,
+ bool duallink)
+{
+ sil164_write(client, SIL164_CONTROL0,
+ SIL164_CONTROL0_HSYNC_ON |
+ SIL164_CONTROL0_VSYNC_ON |
+ (config->input_edge ? SIL164_CONTROL0_EDGE_RISING : 0) |
+ (config->input_width ? SIL164_CONTROL0_INPUT_24BIT : 0) |
+ (config->input_dual ? SIL164_CONTROL0_DUAL_EDGE : 0));
+
+ sil164_write(client, SIL164_DETECT,
+ SIL164_DETECT_INTR_STAT |
+ SIL164_DETECT_OUT_MODE_RECEIVER);
+
+ sil164_write(client, SIL164_CONTROL1,
+ (config->input_skew ? SIL164_CONTROL1_DESKEW_ENABLE : 0) |
+ (((config->input_skew + 4) & 0x7)
+ << SIL164_CONTROL1_DESKEW_INCR_SHIFT));
+
+ sil164_write(client, SIL164_CONTROL2,
+ SIL164_CONTROL2_SYNC_CONT |
+ (config->pll_filter ? 0 : SIL164_CONTROL2_FILTER_ENABLE) |
+ (4 << SIL164_CONTROL2_FILTER_SETTING_SHIFT));
+
+ sil164_write(client, SIL164_PLLZONE, 0);
+
+ if (duallink)
+ sil164_write(client, SIL164_DUALLINK,
+ SIL164_DUALLINK_ENABLE |
+ (((config->duallink_skew + 4) & 0x7)
+ << SIL164_DUALLINK_SKEW_SHIFT));
+ else
+ sil164_write(client, SIL164_DUALLINK, 0);
+}
+
+/* DRM encoder functions */
+
+static void
+sil164_encoder_set_config(struct drm_encoder *encoder, void *params)
+{
+ struct sil164_priv *priv = to_sil164_priv(encoder);
+
+ priv->config = *(struct sil164_encoder_params *)params;
+}
+
+static void
+sil164_encoder_dpms(struct drm_encoder *encoder, int mode)
+{
+ struct sil164_priv *priv = to_sil164_priv(encoder);
+ bool on = (mode == DRM_MODE_DPMS_ON);
+ bool duallink = (on && encoder->crtc->mode.clock > 165000);
+
+ sil164_set_power_state(drm_i2c_encoder_get_client(encoder), on);
+
+ if (priv->duallink_slave)
+ sil164_set_power_state(priv->duallink_slave, duallink);
+}
+
+static void
+sil164_encoder_save(struct drm_encoder *encoder)
+{
+ struct sil164_priv *priv = to_sil164_priv(encoder);
+
+ sil164_save_state(drm_i2c_encoder_get_client(encoder),
+ priv->saved_state);
+
+ if (priv->duallink_slave)
+ sil164_save_state(priv->duallink_slave,
+ priv->saved_slave_state);
+}
+
+static void
+sil164_encoder_restore(struct drm_encoder *encoder)
+{
+ struct sil164_priv *priv = to_sil164_priv(encoder);
+
+ sil164_restore_state(drm_i2c_encoder_get_client(encoder),
+ priv->saved_state);
+
+ if (priv->duallink_slave)
+ sil164_restore_state(priv->duallink_slave,
+ priv->saved_slave_state);
+}
+
+static bool
+sil164_encoder_mode_fixup(struct drm_encoder *encoder,
+ struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode)
+{
+ return true;
+}
+
+static int
+sil164_encoder_mode_valid(struct drm_encoder *encoder,
+ struct drm_display_mode *mode)
+{
+ struct sil164_priv *priv = to_sil164_priv(encoder);
+
+ if (mode->clock < 32000)
+ return MODE_CLOCK_LOW;
+
+ if (mode->clock > 330000 ||
+ (mode->clock > 165000 && !priv->duallink_slave))
+ return MODE_CLOCK_HIGH;
+
+ return MODE_OK;
+}
+
+static void
+sil164_encoder_mode_set(struct drm_encoder *encoder,
+ struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode)
+{
+ struct sil164_priv *priv = to_sil164_priv(encoder);
+ bool duallink = adjusted_mode->clock > 165000;
+
+ sil164_init_state(drm_i2c_encoder_get_client(encoder),
+ &priv->config, duallink);
+
+ if (priv->duallink_slave)
+ sil164_init_state(priv->duallink_slave,
+ &priv->config, duallink);
+
+ sil164_encoder_dpms(encoder, DRM_MODE_DPMS_ON);
+}
+
+static enum drm_connector_status
+sil164_encoder_detect(struct drm_encoder *encoder,
+ struct drm_connector *connector)
+{
+ struct i2c_client *client = drm_i2c_encoder_get_client(encoder);
+
+ if (sil164_read(client, SIL164_DETECT) & SIL164_DETECT_HOTPLUG_STAT)
+ return connector_status_connected;
+ else
+ return connector_status_disconnected;
+}
+
+static int
+sil164_encoder_get_modes(struct drm_encoder *encoder,
+ struct drm_connector *connector)
+{
+ return 0;
+}
+
+static int
+sil164_encoder_create_resources(struct drm_encoder *encoder,
+ struct drm_connector *connector)
+{
+ return 0;
+}
+
+static int
+sil164_encoder_set_property(struct drm_encoder *encoder,
+ struct drm_connector *connector,
+ struct drm_property *property,
+ uint64_t val)
+{
+ return 0;
+}
+
+static void
+sil164_encoder_destroy(struct drm_encoder *encoder)
+{
+ struct sil164_priv *priv = to_sil164_priv(encoder);
+
+ if (priv->duallink_slave)
+ i2c_unregister_device(priv->duallink_slave);
+
+ kfree(priv);
+ drm_i2c_encoder_destroy(encoder);
+}
+
+static struct drm_encoder_slave_funcs sil164_encoder_funcs = {
+ .set_config = sil164_encoder_set_config,
+ .destroy = sil164_encoder_destroy,
+ .dpms = sil164_encoder_dpms,
+ .save = sil164_encoder_save,
+ .restore = sil164_encoder_restore,
+ .mode_fixup = sil164_encoder_mode_fixup,
+ .mode_valid = sil164_encoder_mode_valid,
+ .mode_set = sil164_encoder_mode_set,
+ .detect = sil164_encoder_detect,
+ .get_modes = sil164_encoder_get_modes,
+ .create_resources = sil164_encoder_create_resources,
+ .set_property = sil164_encoder_set_property,
+};
+
+/* I2C driver functions */
+
+static int
+sil164_probe(struct i2c_client *client, const struct i2c_device_id *id)
+{
+ int vendor = sil164_read(client, SIL164_VENDOR_HI) << 8 |
+ sil164_read(client, SIL164_VENDOR_LO);
+ int device = sil164_read(client, SIL164_DEVICE_HI) << 8 |
+ sil164_read(client, SIL164_DEVICE_LO);
+ int rev = sil164_read(client, SIL164_REVISION);
+
+ if (vendor != 0x1 || device != 0x6) {
+ sil164_dbg(client, "Unknown device %x:%x.%x\n",
+ vendor, device, rev);
+ return -ENODEV;
+ }
+
+ sil164_info(client, "Detected device %x:%x.%x\n",
+ vendor, device, rev);
+
+ return 0;
+}
+
+static int
+sil164_remove(struct i2c_client *client)
+{
+ return 0;
+}
+
+static struct i2c_client *
+sil164_detect_slave(struct i2c_client *client)
+{
+ struct i2c_adapter *adap = client->adapter;
+ struct i2c_msg msg = {
+ .addr = SIL164_I2C_ADDR_SLAVE,
+ .len = 0,
+ };
+ const struct i2c_board_info info = {
+ I2C_BOARD_INFO("sil164", SIL164_I2C_ADDR_SLAVE)
+ };
+
+ if (i2c_transfer(adap, &msg, 1) != 1) {
+ sil164_dbg(adap, "No dual-link slave found.");
+ return NULL;
+ }
+
+ return i2c_new_device(adap, &info);
+}
+
+static int
+sil164_encoder_init(struct i2c_client *client,
+ struct drm_device *dev,
+ struct drm_encoder_slave *encoder)
+{
+ struct sil164_priv *priv;
+
+ priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ encoder->slave_priv = priv;
+ encoder->slave_funcs = &sil164_encoder_funcs;
+
+ priv->duallink_slave = sil164_detect_slave(client);
+
+ return 0;
+}
+
+static struct i2c_device_id sil164_ids[] = {
+ { "sil164", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, sil164_ids);
+
+static struct drm_i2c_encoder_driver sil164_driver = {
+ .i2c_driver = {
+ .probe = sil164_probe,
+ .remove = sil164_remove,
+ .driver = {
+ .name = "sil164",
+ },
+ .id_table = sil164_ids,
+ },
+ .encoder_init = sil164_encoder_init,
+};
+
+/* Module initialization */
+
+static int __init
+sil164_init(void)
+{
+ return drm_i2c_encoder_register(THIS_MODULE, &sil164_driver);
+}
+
+static void __exit
+sil164_exit(void)
+{
+ drm_i2c_encoder_unregister(&sil164_driver);
+}
+
+MODULE_AUTHOR("Francisco Jerez <currojerez@riseup.net>");
+MODULE_DESCRIPTION("Silicon Image sil164 TMDS transmitter driver");
+MODULE_LICENSE("GPL and additional rights");
+
+module_init(sil164_init);
+module_exit(sil164_exit);
diff --git a/drivers/gpu/drm/i810/i810_dma.c b/drivers/gpu/drm/i810/i810_dma.c
index 997d91707ad..0e6c131313d 100644
--- a/drivers/gpu/drm/i810/i810_dma.c
+++ b/drivers/gpu/drm/i810/i810_dma.c
@@ -37,6 +37,7 @@
#include <linux/interrupt.h> /* For task queue support */
#include <linux/delay.h>
#include <linux/slab.h>
+#include <linux/smp_lock.h>
#include <linux/pagemap.h>
#define I810_BUF_FREE 2
@@ -60,9 +61,8 @@ static struct drm_buf *i810_freelist_get(struct drm_device * dev)
/* In use is already a pointer */
used = cmpxchg(buf_priv->in_use, I810_BUF_FREE,
I810_BUF_CLIENT);
- if (used == I810_BUF_FREE) {
+ if (used == I810_BUF_FREE)
return buf;
- }
}
return NULL;
}
@@ -71,7 +71,7 @@ static struct drm_buf *i810_freelist_get(struct drm_device * dev)
* yet, the hardware updates in use for us once its on the ring buffer.
*/
-static int i810_freelist_put(struct drm_device * dev, struct drm_buf * 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;
@@ -121,7 +121,7 @@ static const struct file_operations i810_buffer_fops = {
.fasync = drm_fasync,
};
-static int i810_map_buffer(struct drm_buf * buf, struct drm_file *file_priv)
+static int i810_map_buffer(struct drm_buf *buf, struct drm_file *file_priv)
{
struct drm_device *dev = file_priv->minor->dev;
drm_i810_buf_priv_t *buf_priv = buf->dev_private;
@@ -152,7 +152,7 @@ static int i810_map_buffer(struct drm_buf * buf, struct drm_file *file_priv)
return retcode;
}
-static int i810_unmap_buffer(struct drm_buf * buf)
+static int i810_unmap_buffer(struct drm_buf *buf)
{
drm_i810_buf_priv_t *buf_priv = buf->dev_private;
int retcode = 0;
@@ -172,7 +172,7 @@ static int i810_unmap_buffer(struct drm_buf * buf)
return retcode;
}
-static int i810_dma_get_buffer(struct drm_device * dev, drm_i810_dma_t * d,
+static int i810_dma_get_buffer(struct drm_device *dev, drm_i810_dma_t *d,
struct drm_file *file_priv)
{
struct drm_buf *buf;
@@ -202,7 +202,7 @@ static int i810_dma_get_buffer(struct drm_device * dev, drm_i810_dma_t * d,
return retcode;
}
-static int i810_dma_cleanup(struct drm_device * dev)
+static int i810_dma_cleanup(struct drm_device *dev)
{
struct drm_device_dma *dma = dev->dma;
@@ -218,9 +218,8 @@ static int i810_dma_cleanup(struct drm_device * dev)
drm_i810_private_t *dev_priv =
(drm_i810_private_t *) dev->dev_private;
- if (dev_priv->ring.virtual_start) {
+ if (dev_priv->ring.virtual_start)
drm_core_ioremapfree(&dev_priv->ring.map, dev);
- }
if (dev_priv->hw_status_page) {
pci_free_consistent(dev->pdev, PAGE_SIZE,
dev_priv->hw_status_page,
@@ -242,7 +241,7 @@ static int i810_dma_cleanup(struct drm_device * dev)
return 0;
}
-static int i810_wait_ring(struct drm_device * 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);
@@ -271,11 +270,11 @@ static int i810_wait_ring(struct drm_device * dev, int n)
udelay(1);
}
- out_wait_ring:
+out_wait_ring:
return iters;
}
-static void i810_kernel_lost_context(struct drm_device * 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);
@@ -287,7 +286,7 @@ static void i810_kernel_lost_context(struct drm_device * dev)
ring->space += ring->Size;
}
-static int i810_freelist_init(struct drm_device * dev, drm_i810_private_t * dev_priv)
+static int i810_freelist_init(struct drm_device *dev, drm_i810_private_t *dev_priv)
{
struct drm_device_dma *dma = dev->dma;
int my_idx = 24;
@@ -322,9 +321,9 @@ static int i810_freelist_init(struct drm_device * dev, drm_i810_private_t * dev_
return 0;
}
-static int i810_dma_initialize(struct drm_device * dev,
- drm_i810_private_t * dev_priv,
- drm_i810_init_t * init)
+static int i810_dma_initialize(struct drm_device *dev,
+ drm_i810_private_t *dev_priv,
+ drm_i810_init_t *init)
{
struct drm_map_list *r_list;
memset(dev_priv, 0, sizeof(drm_i810_private_t));
@@ -462,7 +461,7 @@ static int i810_dma_init(struct drm_device *dev, void *data,
* Use 'volatile' & local var tmp to force the emitted values to be
* identical to the verified ones.
*/
-static void i810EmitContextVerified(struct drm_device * dev,
+static void i810EmitContextVerified(struct drm_device *dev,
volatile unsigned int *code)
{
drm_i810_private_t *dev_priv = dev->dev_private;
@@ -495,7 +494,7 @@ static void i810EmitContextVerified(struct drm_device * dev,
ADVANCE_LP_RING();
}
-static void i810EmitTexVerified(struct drm_device * 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;
@@ -528,7 +527,7 @@ static void i810EmitTexVerified(struct drm_device * dev, volatile unsigned int *
/* Need to do some additional checking when setting the dest buffer.
*/
-static void i810EmitDestVerified(struct drm_device * dev,
+static void i810EmitDestVerified(struct drm_device *dev,
volatile unsigned int *code)
{
drm_i810_private_t *dev_priv = dev->dev_private;
@@ -563,7 +562,7 @@ static void i810EmitDestVerified(struct drm_device * dev,
ADVANCE_LP_RING();
}
-static void i810EmitState(struct drm_device * 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;
@@ -594,7 +593,7 @@ static void i810EmitState(struct drm_device * dev)
/* need to verify
*/
-static void i810_dma_dispatch_clear(struct drm_device * dev, int flags,
+static void i810_dma_dispatch_clear(struct drm_device *dev, int flags,
unsigned int clear_color,
unsigned int clear_zval)
{
@@ -669,7 +668,7 @@ static void i810_dma_dispatch_clear(struct drm_device * dev, int flags,
}
}
-static void i810_dma_dispatch_swap(struct drm_device * 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;
@@ -715,8 +714,8 @@ static void i810_dma_dispatch_swap(struct drm_device * dev)
}
}
-static void i810_dma_dispatch_vertex(struct drm_device * dev,
- struct drm_buf * 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;
@@ -795,7 +794,7 @@ static void i810_dma_dispatch_vertex(struct drm_device * dev,
}
}
-static void i810_dma_dispatch_flip(struct drm_device * 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;
@@ -841,7 +840,7 @@ static void i810_dma_dispatch_flip(struct drm_device * dev)
}
-static void i810_dma_quiescent(struct drm_device * dev)
+static void i810_dma_quiescent(struct drm_device *dev)
{
drm_i810_private_t *dev_priv = dev->dev_private;
RING_LOCALS;
@@ -858,7 +857,7 @@ static void i810_dma_quiescent(struct drm_device * dev)
i810_wait_ring(dev, dev_priv->ring.Size - 8);
}
-static int i810_flush_queue(struct drm_device * dev)
+static int i810_flush_queue(struct drm_device *dev)
{
drm_i810_private_t *dev_priv = dev->dev_private;
struct drm_device_dma *dma = dev->dma;
@@ -891,7 +890,7 @@ static int i810_flush_queue(struct drm_device * dev)
}
/* Must be called with the lock held */
-static void i810_reclaim_buffers(struct drm_device * dev,
+static void i810_reclaim_buffers(struct drm_device *dev,
struct drm_file *file_priv)
{
struct drm_device_dma *dma = dev->dma;
@@ -969,9 +968,8 @@ static int i810_clear_bufs(struct drm_device *dev, void *data,
LOCK_TEST_WITH_RETURN(dev, file_priv);
/* GH: Someone's doing nasty things... */
- if (!dev->dev_private) {
+ if (!dev->dev_private)
return -EINVAL;
- }
i810_dma_dispatch_clear(dev, clear->flags,
clear->clear_color, clear->clear_depth);
@@ -1039,7 +1037,7 @@ static int i810_docopy(struct drm_device *dev, void *data,
return 0;
}
-static void i810_dma_dispatch_mc(struct drm_device * dev, struct drm_buf * 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;
@@ -1053,9 +1051,8 @@ static void i810_dma_dispatch_mc(struct drm_device * dev, struct drm_buf * buf,
i810_kernel_lost_context(dev);
u = cmpxchg(buf_priv->in_use, I810_BUF_CLIENT, I810_BUF_HARDWARE);
- if (u != I810_BUF_CLIENT) {
+ if (u != I810_BUF_CLIENT)
DRM_DEBUG("MC found buffer that isn't mine!\n");
- }
if (used > 4 * 1024)
used = 0;
@@ -1160,7 +1157,7 @@ static int i810_ov0_flip(struct drm_device *dev, void *data,
LOCK_TEST_WITH_RETURN(dev, file_priv);
- //Tell the overlay to update
+ /* Tell the overlay to update */
I810_WRITE(0x30000, dev_priv->overlay_physical | 0x80000000);
return 0;
@@ -1168,7 +1165,7 @@ static int i810_ov0_flip(struct drm_device *dev, void *data,
/* Not sure why this isn't set all the time:
*/
-static void i810_do_init_pageflip(struct drm_device * dev)
+static void i810_do_init_pageflip(struct drm_device *dev)
{
drm_i810_private_t *dev_priv = dev->dev_private;
@@ -1178,7 +1175,7 @@ static void i810_do_init_pageflip(struct drm_device * dev)
dev_priv->sarea_priv->pf_current_page = dev_priv->current_page;
}
-static int i810_do_cleanup_pageflip(struct drm_device * dev)
+static int i810_do_cleanup_pageflip(struct drm_device *dev)
{
drm_i810_private_t *dev_priv = dev->dev_private;
@@ -1218,49 +1215,61 @@ int i810_driver_load(struct drm_device *dev, unsigned long flags)
return 0;
}
-void i810_driver_lastclose(struct drm_device * dev)
+void i810_driver_lastclose(struct drm_device *dev)
{
i810_dma_cleanup(dev);
}
-void i810_driver_preclose(struct drm_device * dev, struct drm_file *file_priv)
+void i810_driver_preclose(struct drm_device *dev, struct drm_file *file_priv)
{
if (dev->dev_private) {
drm_i810_private_t *dev_priv = dev->dev_private;
- if (dev_priv->page_flipping) {
+ if (dev_priv->page_flipping)
i810_do_cleanup_pageflip(dev);
- }
}
}
-void i810_driver_reclaim_buffers_locked(struct drm_device * dev,
+void i810_driver_reclaim_buffers_locked(struct drm_device *dev,
struct drm_file *file_priv)
{
i810_reclaim_buffers(dev, file_priv);
}
-int i810_driver_dma_quiescent(struct drm_device * dev)
+int i810_driver_dma_quiescent(struct drm_device *dev)
{
i810_dma_quiescent(dev);
return 0;
}
+/*
+ * call the drm_ioctl under the big kernel lock because
+ * to lock against the i810_mmap_buffers function.
+ */
+long i810_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+ int ret;
+ lock_kernel();
+ ret = drm_ioctl(file, cmd, arg);
+ unlock_kernel();
+ return ret;
+}
+
struct drm_ioctl_desc i810_ioctls[] = {
- DRM_IOCTL_DEF(DRM_I810_INIT, i810_dma_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
- DRM_IOCTL_DEF(DRM_I810_VERTEX, i810_dma_vertex, DRM_AUTH),
- DRM_IOCTL_DEF(DRM_I810_CLEAR, i810_clear_bufs, DRM_AUTH),
- DRM_IOCTL_DEF(DRM_I810_FLUSH, i810_flush_ioctl, DRM_AUTH),
- DRM_IOCTL_DEF(DRM_I810_GETAGE, i810_getage, DRM_AUTH),
- DRM_IOCTL_DEF(DRM_I810_GETBUF, i810_getbuf, DRM_AUTH),
- DRM_IOCTL_DEF(DRM_I810_SWAP, i810_swap_bufs, DRM_AUTH),
- DRM_IOCTL_DEF(DRM_I810_COPY, i810_copybuf, DRM_AUTH),
- DRM_IOCTL_DEF(DRM_I810_DOCOPY, i810_docopy, DRM_AUTH),
- DRM_IOCTL_DEF(DRM_I810_OV0INFO, i810_ov0_info, DRM_AUTH),
- DRM_IOCTL_DEF(DRM_I810_FSTATUS, i810_fstatus, DRM_AUTH),
- DRM_IOCTL_DEF(DRM_I810_OV0FLIP, i810_ov0_flip, DRM_AUTH),
- DRM_IOCTL_DEF(DRM_I810_MC, i810_dma_mc, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
- DRM_IOCTL_DEF(DRM_I810_RSTATUS, i810_rstatus, DRM_AUTH),
- DRM_IOCTL_DEF(DRM_I810_FLIP, i810_flip_bufs, DRM_AUTH)
+ DRM_IOCTL_DEF(DRM_I810_INIT, i810_dma_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY|DRM_UNLOCKED),
+ DRM_IOCTL_DEF(DRM_I810_VERTEX, i810_dma_vertex, DRM_AUTH|DRM_UNLOCKED),
+ DRM_IOCTL_DEF(DRM_I810_CLEAR, i810_clear_bufs, DRM_AUTH|DRM_UNLOCKED),
+ DRM_IOCTL_DEF(DRM_I810_FLUSH, i810_flush_ioctl, DRM_AUTH|DRM_UNLOCKED),
+ DRM_IOCTL_DEF(DRM_I810_GETAGE, i810_getage, DRM_AUTH|DRM_UNLOCKED),
+ DRM_IOCTL_DEF(DRM_I810_GETBUF, i810_getbuf, DRM_AUTH|DRM_UNLOCKED),
+ DRM_IOCTL_DEF(DRM_I810_SWAP, i810_swap_bufs, DRM_AUTH|DRM_UNLOCKED),
+ DRM_IOCTL_DEF(DRM_I810_COPY, i810_copybuf, DRM_AUTH|DRM_UNLOCKED),
+ DRM_IOCTL_DEF(DRM_I810_DOCOPY, i810_docopy, DRM_AUTH|DRM_UNLOCKED),
+ DRM_IOCTL_DEF(DRM_I810_OV0INFO, i810_ov0_info, DRM_AUTH|DRM_UNLOCKED),
+ DRM_IOCTL_DEF(DRM_I810_FSTATUS, i810_fstatus, DRM_AUTH|DRM_UNLOCKED),
+ DRM_IOCTL_DEF(DRM_I810_OV0FLIP, i810_ov0_flip, DRM_AUTH|DRM_UNLOCKED),
+ DRM_IOCTL_DEF(DRM_I810_MC, i810_dma_mc, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY|DRM_UNLOCKED),
+ DRM_IOCTL_DEF(DRM_I810_RSTATUS, i810_rstatus, DRM_AUTH|DRM_UNLOCKED),
+ DRM_IOCTL_DEF(DRM_I810_FLIP, i810_flip_bufs, DRM_AUTH|DRM_UNLOCKED),
};
int i810_max_ioctl = DRM_ARRAY_SIZE(i810_ioctls);
@@ -1276,7 +1285,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(struct drm_device * dev)
+int i810_driver_device_is_agp(struct drm_device *dev)
{
return 1;
}
diff --git a/drivers/gpu/drm/i810/i810_drv.c b/drivers/gpu/drm/i810/i810_drv.c
index c1e02752e02..b4250b2cac1 100644
--- a/drivers/gpu/drm/i810/i810_drv.c
+++ b/drivers/gpu/drm/i810/i810_drv.c
@@ -59,7 +59,7 @@ static struct drm_driver driver = {
.owner = THIS_MODULE,
.open = drm_open,
.release = drm_release,
- .unlocked_ioctl = drm_ioctl,
+ .unlocked_ioctl = i810_ioctl,
.mmap = drm_mmap,
.poll = drm_poll,
.fasync = drm_fasync,
diff --git a/drivers/gpu/drm/i810/i810_drv.h b/drivers/gpu/drm/i810/i810_drv.h
index 21e2691f28f..c9339f48179 100644
--- a/drivers/gpu/drm/i810/i810_drv.h
+++ b/drivers/gpu/drm/i810/i810_drv.h
@@ -115,56 +115,59 @@ typedef struct drm_i810_private {
} drm_i810_private_t;
/* i810_dma.c */
-extern int i810_driver_dma_quiescent(struct drm_device * dev);
-extern void i810_driver_reclaim_buffers_locked(struct drm_device * dev,
+extern int i810_driver_dma_quiescent(struct drm_device *dev);
+extern void i810_driver_reclaim_buffers_locked(struct drm_device *dev,
struct drm_file *file_priv);
extern int i810_driver_load(struct drm_device *, unsigned long flags);
-extern void i810_driver_lastclose(struct drm_device * dev);
-extern void i810_driver_preclose(struct drm_device * dev,
+extern void i810_driver_lastclose(struct drm_device *dev);
+extern void i810_driver_preclose(struct drm_device *dev,
struct drm_file *file_priv);
-extern void i810_driver_reclaim_buffers_locked(struct drm_device * dev,
+extern void i810_driver_reclaim_buffers_locked(struct drm_device *dev,
struct drm_file *file_priv);
-extern int i810_driver_device_is_agp(struct drm_device * dev);
+extern int i810_driver_device_is_agp(struct drm_device *dev);
+extern long i810_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
extern struct drm_ioctl_desc i810_ioctls[];
extern int i810_max_ioctl;
#define I810_BASE(reg) ((unsigned long) \
dev_priv->mmio_map->handle)
#define I810_ADDR(reg) (I810_BASE(reg) + reg)
-#define I810_DEREF(reg) *(__volatile__ int *)I810_ADDR(reg)
+#define I810_DEREF(reg) (*(__volatile__ int *)I810_ADDR(reg))
#define I810_READ(reg) I810_DEREF(reg)
-#define I810_WRITE(reg,val) do { I810_DEREF(reg) = val; } while (0)
-#define I810_DEREF16(reg) *(__volatile__ u16 *)I810_ADDR(reg)
+#define I810_WRITE(reg, val) do { I810_DEREF(reg) = val; } while (0)
+#define I810_DEREF16(reg) (*(__volatile__ u16 *)I810_ADDR(reg))
#define I810_READ16(reg) I810_DEREF16(reg)
-#define I810_WRITE16(reg,val) do { I810_DEREF16(reg) = val; } while (0)
+#define I810_WRITE16(reg, val) do { I810_DEREF16(reg) = val; } while (0)
#define I810_VERBOSE 0
#define RING_LOCALS unsigned int outring, ringmask; \
- volatile char *virt;
-
-#define BEGIN_LP_RING(n) do { \
- if (I810_VERBOSE) \
- DRM_DEBUG("BEGIN_LP_RING(%d)\n", n); \
- if (dev_priv->ring.space < n*4) \
- i810_wait_ring(dev, n*4); \
- dev_priv->ring.space -= n*4; \
- outring = dev_priv->ring.tail; \
- ringmask = dev_priv->ring.tail_mask; \
- virt = dev_priv->ring.virtual_start; \
+ volatile char *virt;
+
+#define BEGIN_LP_RING(n) do { \
+ if (I810_VERBOSE) \
+ DRM_DEBUG("BEGIN_LP_RING(%d)\n", n); \
+ if (dev_priv->ring.space < n*4) \
+ i810_wait_ring(dev, n*4); \
+ dev_priv->ring.space -= n*4; \
+ outring = dev_priv->ring.tail; \
+ ringmask = dev_priv->ring.tail_mask; \
+ virt = dev_priv->ring.virtual_start; \
} while (0)
-#define ADVANCE_LP_RING() do { \
- if (I810_VERBOSE) DRM_DEBUG("ADVANCE_LP_RING\n"); \
+#define ADVANCE_LP_RING() do { \
+ if (I810_VERBOSE) \
+ DRM_DEBUG("ADVANCE_LP_RING\n"); \
dev_priv->ring.tail = outring; \
- I810_WRITE(LP_RING + RING_TAIL, outring); \
-} while(0)
-
-#define OUT_RING(n) do { \
- if (I810_VERBOSE) DRM_DEBUG(" OUT_RING %x\n", (int)(n)); \
- *(volatile unsigned int *)(virt + outring) = n; \
- outring += 4; \
- outring &= ringmask; \
+ I810_WRITE(LP_RING + RING_TAIL, outring); \
+} while (0)
+
+#define OUT_RING(n) do { \
+ if (I810_VERBOSE) \
+ DRM_DEBUG(" OUT_RING %x\n", (int)(n)); \
+ *(volatile unsigned int *)(virt + outring) = n; \
+ outring += 4; \
+ outring &= ringmask; \
} while (0)
#define GFX_OP_USER_INTERRUPT ((0<<29)|(2<<23))
diff --git a/drivers/gpu/drm/i830/i830_dma.c b/drivers/gpu/drm/i830/i830_dma.c
index 65759a9a85c..5168862c922 100644
--- a/drivers/gpu/drm/i830/i830_dma.c
+++ b/drivers/gpu/drm/i830/i830_dma.c
@@ -36,6 +36,7 @@
#include "i830_drm.h"
#include "i830_drv.h"
#include <linux/interrupt.h> /* For task queue support */
+#include <linux/smp_lock.h>
#include <linux/pagemap.h>
#include <linux/delay.h>
#include <linux/slab.h>
@@ -62,9 +63,8 @@ static struct drm_buf *i830_freelist_get(struct drm_device * dev)
/* In use is already a pointer */
used = cmpxchg(buf_priv->in_use, I830_BUF_FREE,
I830_BUF_CLIENT);
- if (used == I830_BUF_FREE) {
+ if (used == I830_BUF_FREE)
return buf;
- }
}
return NULL;
}
@@ -73,7 +73,7 @@ static struct drm_buf *i830_freelist_get(struct drm_device * dev)
* yet, the hardware updates in use for us once its on the ring buffer.
*/
-static int i830_freelist_put(struct drm_device * dev, struct drm_buf * 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;
@@ -123,7 +123,7 @@ static const struct file_operations i830_buffer_fops = {
.fasync = drm_fasync,
};
-static int i830_map_buffer(struct drm_buf * buf, struct drm_file *file_priv)
+static int i830_map_buffer(struct drm_buf *buf, struct drm_file *file_priv)
{
struct drm_device *dev = file_priv->minor->dev;
drm_i830_buf_priv_t *buf_priv = buf->dev_private;
@@ -156,7 +156,7 @@ static int i830_map_buffer(struct drm_buf * buf, struct drm_file *file_priv)
return retcode;
}
-static int i830_unmap_buffer(struct drm_buf * buf)
+static int i830_unmap_buffer(struct drm_buf *buf)
{
drm_i830_buf_priv_t *buf_priv = buf->dev_private;
int retcode = 0;
@@ -176,7 +176,7 @@ static int i830_unmap_buffer(struct drm_buf * buf)
return retcode;
}
-static int i830_dma_get_buffer(struct drm_device * dev, drm_i830_dma_t * d,
+static int i830_dma_get_buffer(struct drm_device *dev, drm_i830_dma_t *d,
struct drm_file *file_priv)
{
struct drm_buf *buf;
@@ -206,7 +206,7 @@ static int i830_dma_get_buffer(struct drm_device * dev, drm_i830_dma_t * d,
return retcode;
}
-static int i830_dma_cleanup(struct drm_device * dev)
+static int i830_dma_cleanup(struct drm_device *dev)
{
struct drm_device_dma *dma = dev->dma;
@@ -222,9 +222,8 @@ static int i830_dma_cleanup(struct drm_device * dev)
drm_i830_private_t *dev_priv =
(drm_i830_private_t *) dev->dev_private;
- if (dev_priv->ring.virtual_start) {
+ if (dev_priv->ring.virtual_start)
drm_core_ioremapfree(&dev_priv->ring.map, dev);
- }
if (dev_priv->hw_status_page) {
pci_free_consistent(dev->pdev, PAGE_SIZE,
dev_priv->hw_status_page,
@@ -246,7 +245,7 @@ static int i830_dma_cleanup(struct drm_device * dev)
return 0;
}
-int i830_wait_ring(struct drm_device * 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);
@@ -276,11 +275,11 @@ int i830_wait_ring(struct drm_device * dev, int n, const char *caller)
dev_priv->sarea_priv->perf_boxes |= I830_BOX_WAIT;
}
- out_wait_ring:
+out_wait_ring:
return iters;
}
-static void i830_kernel_lost_context(struct drm_device * 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);
@@ -295,7 +294,7 @@ static void i830_kernel_lost_context(struct drm_device * dev)
dev_priv->sarea_priv->perf_boxes |= I830_BOX_RING_EMPTY;
}
-static int i830_freelist_init(struct drm_device * dev, drm_i830_private_t * dev_priv)
+static int i830_freelist_init(struct drm_device *dev, drm_i830_private_t *dev_priv)
{
struct drm_device_dma *dma = dev->dma;
int my_idx = 36;
@@ -329,9 +328,9 @@ static int i830_freelist_init(struct drm_device * dev, drm_i830_private_t * dev_
return 0;
}
-static int i830_dma_initialize(struct drm_device * dev,
- drm_i830_private_t * dev_priv,
- drm_i830_init_t * init)
+static int i830_dma_initialize(struct drm_device *dev,
+ drm_i830_private_t *dev_priv,
+ drm_i830_init_t *init)
{
struct drm_map_list *r_list;
@@ -482,7 +481,7 @@ static int i830_dma_init(struct drm_device *dev, void *data,
/* Most efficient way to verify state for the i830 is as it is
* emitted. Non-conformant state is silently dropped.
*/
-static void i830EmitContextVerified(struct drm_device * 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;
@@ -527,7 +526,7 @@ static void i830EmitContextVerified(struct drm_device * dev, unsigned int *code)
ADVANCE_LP_RING();
}
-static void i830EmitTexVerified(struct drm_device * 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;
@@ -561,7 +560,7 @@ static void i830EmitTexVerified(struct drm_device * dev, unsigned int *code)
printk("rejected packet %x\n", code[0]);
}
-static void i830EmitTexBlendVerified(struct drm_device * dev,
+static void i830EmitTexBlendVerified(struct drm_device *dev,
unsigned int *code, unsigned int num)
{
drm_i830_private_t *dev_priv = dev->dev_private;
@@ -586,7 +585,7 @@ static void i830EmitTexBlendVerified(struct drm_device * dev,
ADVANCE_LP_RING();
}
-static void i830EmitTexPalette(struct drm_device * 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;
@@ -603,9 +602,8 @@ static void i830EmitTexPalette(struct drm_device * dev,
} else {
OUT_RING(CMD_OP_MAP_PALETTE_LOAD | MAP_PALETTE_NUM(number));
}
- for (i = 0; i < 256; i++) {
+ for (i = 0; i < 256; i++)
OUT_RING(palette[i]);
- }
OUT_RING(0);
/* KW: WHERE IS THE ADVANCE_LP_RING? This is effectively a noop!
*/
@@ -613,7 +611,7 @@ static void i830EmitTexPalette(struct drm_device * dev,
/* Need to do some additional checking when setting the dest buffer.
*/
-static void i830EmitDestVerified(struct drm_device * 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;
@@ -674,7 +672,7 @@ static void i830EmitDestVerified(struct drm_device * dev, unsigned int *code)
ADVANCE_LP_RING();
}
-static void i830EmitStippleVerified(struct drm_device * 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;
@@ -685,7 +683,7 @@ static void i830EmitStippleVerified(struct drm_device * dev, unsigned int *code)
ADVANCE_LP_RING();
}
-static void i830EmitState(struct drm_device * 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;
@@ -788,7 +786,7 @@ static void i830EmitState(struct drm_device * dev)
* Performance monitoring functions
*/
-static void i830_fill_box(struct drm_device * 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;
@@ -816,17 +814,16 @@ static void i830_fill_box(struct drm_device * dev,
OUT_RING((y << 16) | x);
OUT_RING(((y + h) << 16) | (x + w));
- if (dev_priv->current_page == 1) {
+ if (dev_priv->current_page == 1)
OUT_RING(dev_priv->front_offset);
- } else {
+ else
OUT_RING(dev_priv->back_offset);
- }
OUT_RING(color);
ADVANCE_LP_RING();
}
-static void i830_cp_performance_boxes(struct drm_device * dev)
+static void i830_cp_performance_boxes(struct drm_device *dev)
{
drm_i830_private_t *dev_priv = dev->dev_private;
@@ -871,7 +868,7 @@ static void i830_cp_performance_boxes(struct drm_device * dev)
dev_priv->sarea_priv->perf_boxes = 0;
}
-static void i830_dma_dispatch_clear(struct drm_device * 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)
@@ -966,7 +963,7 @@ static void i830_dma_dispatch_clear(struct drm_device * dev, int flags,
}
}
-static void i830_dma_dispatch_swap(struct drm_device * 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;
@@ -1036,7 +1033,7 @@ static void i830_dma_dispatch_swap(struct drm_device * dev)
}
}
-static void i830_dma_dispatch_flip(struct drm_device * dev)
+static void i830_dma_dispatch_flip(struct drm_device *dev)
{
drm_i830_private_t *dev_priv = dev->dev_private;
RING_LOCALS;
@@ -1079,8 +1076,8 @@ static void i830_dma_dispatch_flip(struct drm_device * dev)
dev_priv->sarea_priv->pf_current_page = dev_priv->current_page;
}
-static void i830_dma_dispatch_vertex(struct drm_device * dev,
- struct drm_buf * 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;
@@ -1100,9 +1097,8 @@ static void i830_dma_dispatch_vertex(struct drm_device * dev,
if (discard) {
u = cmpxchg(buf_priv->in_use, I830_BUF_CLIENT,
I830_BUF_HARDWARE);
- if (u != I830_BUF_CLIENT) {
+ if (u != I830_BUF_CLIENT)
DRM_DEBUG("xxxx 2\n");
- }
}
if (used > 4 * 1023)
@@ -1191,7 +1187,7 @@ static void i830_dma_dispatch_vertex(struct drm_device * dev,
}
}
-static void i830_dma_quiescent(struct drm_device * dev)
+static void i830_dma_quiescent(struct drm_device *dev)
{
drm_i830_private_t *dev_priv = dev->dev_private;
RING_LOCALS;
@@ -1208,7 +1204,7 @@ static void i830_dma_quiescent(struct drm_device * dev)
i830_wait_ring(dev, dev_priv->ring.Size - 8, __func__);
}
-static int i830_flush_queue(struct drm_device * dev)
+static int i830_flush_queue(struct drm_device *dev)
{
drm_i830_private_t *dev_priv = dev->dev_private;
struct drm_device_dma *dma = dev->dma;
@@ -1241,7 +1237,7 @@ static int i830_flush_queue(struct drm_device * dev)
}
/* Must be called with the lock held */
-static void i830_reclaim_buffers(struct drm_device * dev, struct drm_file *file_priv)
+static void i830_reclaim_buffers(struct drm_device *dev, struct drm_file *file_priv)
{
struct drm_device_dma *dma = dev->dma;
int i;
@@ -1316,9 +1312,8 @@ static int i830_clear_bufs(struct drm_device *dev, void *data,
LOCK_TEST_WITH_RETURN(dev, file_priv);
/* GH: Someone's doing nasty things... */
- if (!dev->dev_private) {
+ if (!dev->dev_private)
return -EINVAL;
- }
i830_dma_dispatch_clear(dev, clear->flags,
clear->clear_color,
@@ -1339,7 +1334,7 @@ static int i830_swap_bufs(struct drm_device *dev, void *data,
/* Not sure why this isn't set all the time:
*/
-static void i830_do_init_pageflip(struct drm_device * dev)
+static void i830_do_init_pageflip(struct drm_device *dev)
{
drm_i830_private_t *dev_priv = dev->dev_private;
@@ -1349,7 +1344,7 @@ static void i830_do_init_pageflip(struct drm_device * dev)
dev_priv->sarea_priv->pf_current_page = dev_priv->current_page;
}
-static int i830_do_cleanup_pageflip(struct drm_device * dev)
+static int i830_do_cleanup_pageflip(struct drm_device *dev)
{
drm_i830_private_t *dev_priv = dev->dev_private;
@@ -1490,47 +1485,59 @@ int i830_driver_load(struct drm_device *dev, unsigned long flags)
return 0;
}
-void i830_driver_lastclose(struct drm_device * dev)
+void i830_driver_lastclose(struct drm_device *dev)
{
i830_dma_cleanup(dev);
}
-void i830_driver_preclose(struct drm_device * dev, struct drm_file *file_priv)
+void i830_driver_preclose(struct drm_device *dev, struct drm_file *file_priv)
{
if (dev->dev_private) {
drm_i830_private_t *dev_priv = dev->dev_private;
- if (dev_priv->page_flipping) {
+ if (dev_priv->page_flipping)
i830_do_cleanup_pageflip(dev);
- }
}
}
-void i830_driver_reclaim_buffers_locked(struct drm_device * dev, struct drm_file *file_priv)
+void i830_driver_reclaim_buffers_locked(struct drm_device *dev, struct drm_file *file_priv)
{
i830_reclaim_buffers(dev, file_priv);
}
-int i830_driver_dma_quiescent(struct drm_device * dev)
+int i830_driver_dma_quiescent(struct drm_device *dev)
{
i830_dma_quiescent(dev);
return 0;
}
+/*
+ * call the drm_ioctl under the big kernel lock because
+ * to lock against the i830_mmap_buffers function.
+ */
+long i830_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+ int ret;
+ lock_kernel();
+ ret = drm_ioctl(file, cmd, arg);
+ unlock_kernel();
+ return ret;
+}
+
struct drm_ioctl_desc i830_ioctls[] = {
- DRM_IOCTL_DEF(DRM_I830_INIT, i830_dma_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
- DRM_IOCTL_DEF(DRM_I830_VERTEX, i830_dma_vertex, DRM_AUTH),
- DRM_IOCTL_DEF(DRM_I830_CLEAR, i830_clear_bufs, DRM_AUTH),
- DRM_IOCTL_DEF(DRM_I830_FLUSH, i830_flush_ioctl, DRM_AUTH),
- DRM_IOCTL_DEF(DRM_I830_GETAGE, i830_getage, DRM_AUTH),
- DRM_IOCTL_DEF(DRM_I830_GETBUF, i830_getbuf, DRM_AUTH),
- DRM_IOCTL_DEF(DRM_I830_SWAP, i830_swap_bufs, DRM_AUTH),
- DRM_IOCTL_DEF(DRM_I830_COPY, i830_copybuf, DRM_AUTH),
- DRM_IOCTL_DEF(DRM_I830_DOCOPY, i830_docopy, DRM_AUTH),
- DRM_IOCTL_DEF(DRM_I830_FLIP, i830_flip_bufs, DRM_AUTH),
- DRM_IOCTL_DEF(DRM_I830_IRQ_EMIT, i830_irq_emit, DRM_AUTH),
- DRM_IOCTL_DEF(DRM_I830_IRQ_WAIT, i830_irq_wait, DRM_AUTH),
- DRM_IOCTL_DEF(DRM_I830_GETPARAM, i830_getparam, DRM_AUTH),
- DRM_IOCTL_DEF(DRM_I830_SETPARAM, i830_setparam, DRM_AUTH)
+ DRM_IOCTL_DEF(DRM_I830_INIT, i830_dma_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY|DRM_UNLOCKED),
+ DRM_IOCTL_DEF(DRM_I830_VERTEX, i830_dma_vertex, DRM_AUTH|DRM_UNLOCKED),
+ DRM_IOCTL_DEF(DRM_I830_CLEAR, i830_clear_bufs, DRM_AUTH|DRM_UNLOCKED),
+ DRM_IOCTL_DEF(DRM_I830_FLUSH, i830_flush_ioctl, DRM_AUTH|DRM_UNLOCKED),
+ DRM_IOCTL_DEF(DRM_I830_GETAGE, i830_getage, DRM_AUTH|DRM_UNLOCKED),
+ DRM_IOCTL_DEF(DRM_I830_GETBUF, i830_getbuf, DRM_AUTH|DRM_UNLOCKED),
+ DRM_IOCTL_DEF(DRM_I830_SWAP, i830_swap_bufs, DRM_AUTH|DRM_UNLOCKED),
+ DRM_IOCTL_DEF(DRM_I830_COPY, i830_copybuf, DRM_AUTH|DRM_UNLOCKED),
+ DRM_IOCTL_DEF(DRM_I830_DOCOPY, i830_docopy, DRM_AUTH|DRM_UNLOCKED),
+ DRM_IOCTL_DEF(DRM_I830_FLIP, i830_flip_bufs, DRM_AUTH|DRM_UNLOCKED),
+ DRM_IOCTL_DEF(DRM_I830_IRQ_EMIT, i830_irq_emit, DRM_AUTH|DRM_UNLOCKED),
+ DRM_IOCTL_DEF(DRM_I830_IRQ_WAIT, i830_irq_wait, DRM_AUTH|DRM_UNLOCKED),
+ DRM_IOCTL_DEF(DRM_I830_GETPARAM, i830_getparam, DRM_AUTH|DRM_UNLOCKED),
+ DRM_IOCTL_DEF(DRM_I830_SETPARAM, i830_setparam, DRM_AUTH|DRM_UNLOCKED),
};
int i830_max_ioctl = DRM_ARRAY_SIZE(i830_ioctls);
@@ -1546,7 +1553,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(struct drm_device * dev)
+int i830_driver_device_is_agp(struct drm_device *dev)
{
return 1;
}
diff --git a/drivers/gpu/drm/i830/i830_drv.c b/drivers/gpu/drm/i830/i830_drv.c
index 44f990bed8f..a5c66aa82f0 100644
--- a/drivers/gpu/drm/i830/i830_drv.c
+++ b/drivers/gpu/drm/i830/i830_drv.c
@@ -70,7 +70,7 @@ static struct drm_driver driver = {
.owner = THIS_MODULE,
.open = drm_open,
.release = drm_release,
- .unlocked_ioctl = drm_ioctl,
+ .unlocked_ioctl = i830_ioctl,
.mmap = drm_mmap,
.poll = drm_poll,
.fasync = drm_fasync,
diff --git a/drivers/gpu/drm/i830/i830_drv.h b/drivers/gpu/drm/i830/i830_drv.h
index da82afe4ded..0df1c720560 100644
--- a/drivers/gpu/drm/i830/i830_drv.h
+++ b/drivers/gpu/drm/i830/i830_drv.h
@@ -122,6 +122,7 @@ typedef struct drm_i830_private {
} drm_i830_private_t;
+long i830_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
extern struct drm_ioctl_desc i830_ioctls[];
extern int i830_max_ioctl;
@@ -132,33 +133,33 @@ extern int i830_irq_wait(struct drm_device *dev, void *data,
struct drm_file *file_priv);
extern irqreturn_t i830_driver_irq_handler(DRM_IRQ_ARGS);
-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 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(struct drm_device * dev,
+extern void i830_driver_preclose(struct drm_device *dev,
struct drm_file *file_priv);
-extern void i830_driver_lastclose(struct drm_device * dev);
-extern void i830_driver_reclaim_buffers_locked(struct drm_device * dev,
+extern void i830_driver_lastclose(struct drm_device *dev);
+extern void i830_driver_reclaim_buffers_locked(struct drm_device *dev,
struct drm_file *file_priv);
-extern int i830_driver_dma_quiescent(struct drm_device * dev);
-extern int i830_driver_device_is_agp(struct drm_device * 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)
-#define I830_READ16(reg) DRM_READ16(dev_priv->mmio_map, reg)
-#define I830_WRITE16(reg,val) DRM_WRITE16(dev_priv->mmio_map, reg, val)
+#define I830_READ(reg) DRM_READ32(dev_priv->mmio_map, reg)
+#define I830_WRITE(reg, val) DRM_WRITE32(dev_priv->mmio_map, reg, val)
+#define I830_READ16(reg) DRM_READ16(dev_priv->mmio_map, reg)
+#define I830_WRITE16(reg, val) DRM_WRITE16(dev_priv->mmio_map, reg, val)
#define I830_VERBOSE 0
#define RING_LOCALS unsigned int outring, ringmask, outcount; \
- volatile char *virt;
+ volatile char *virt;
#define BEGIN_LP_RING(n) do { \
if (I830_VERBOSE) \
printk("BEGIN_LP_RING(%d)\n", (n)); \
if (dev_priv->ring.space < n*4) \
- i830_wait_ring(dev, n*4, __func__); \
+ i830_wait_ring(dev, n*4, __func__); \
outcount = 0; \
outring = dev_priv->ring.tail; \
ringmask = dev_priv->ring.tail_mask; \
@@ -166,21 +167,23 @@ extern int i830_driver_device_is_agp(struct drm_device * dev);
} while (0)
#define OUT_RING(n) do { \
- if (I830_VERBOSE) printk(" OUT_RING %x\n", (int)(n)); \
+ if (I830_VERBOSE) \
+ printk(" OUT_RING %x\n", (int)(n)); \
*(volatile unsigned int *)(virt + outring) = n; \
- outcount++; \
+ outcount++; \
outring += 4; \
outring &= ringmask; \
} while (0)
-#define ADVANCE_LP_RING() do { \
- if (I830_VERBOSE) printk("ADVANCE_LP_RING %x\n", outring); \
- dev_priv->ring.tail = outring; \
- dev_priv->ring.space -= outcount * 4; \
- I830_WRITE(LP_RING + RING_TAIL, outring); \
-} while(0)
+#define ADVANCE_LP_RING() do { \
+ if (I830_VERBOSE) \
+ printk("ADVANCE_LP_RING %x\n", outring); \
+ dev_priv->ring.tail = outring; \
+ dev_priv->ring.space -= outcount * 4; \
+ I830_WRITE(LP_RING + RING_TAIL, outring); \
+} while (0)
-extern int i830_wait_ring(struct drm_device * 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/gpu/drm/i830/i830_irq.c b/drivers/gpu/drm/i830/i830_irq.c
index 91ec2bb497e..d1a6b95d631 100644
--- a/drivers/gpu/drm/i830/i830_irq.c
+++ b/drivers/gpu/drm/i830/i830_irq.c
@@ -53,7 +53,7 @@ irqreturn_t i830_driver_irq_handler(DRM_IRQ_ARGS)
return IRQ_HANDLED;
}
-static int i830_emit_irq(struct drm_device * 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(struct drm_device * dev)
return atomic_read(&dev_priv->irq_emitted);
}
-static int i830_wait_irq(struct drm_device * 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);
@@ -156,7 +156,7 @@ int i830_irq_wait(struct drm_device *dev, void *data,
/* drm_dma.h hooks
*/
-void i830_driver_irq_preinstall(struct drm_device * dev)
+void i830_driver_irq_preinstall(struct drm_device *dev)
{
drm_i830_private_t *dev_priv = (drm_i830_private_t *) dev->dev_private;
@@ -168,14 +168,14 @@ void i830_driver_irq_preinstall(struct drm_device * dev)
init_waitqueue_head(&dev_priv->irq_queue);
}
-void i830_driver_irq_postinstall(struct drm_device * 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(struct drm_device * 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/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c
index 2305a1234f1..f19ffe87af3 100644
--- a/drivers/gpu/drm/i915/i915_dma.c
+++ b/drivers/gpu/drm/i915/i915_dma.c
@@ -34,12 +34,15 @@
#include "i915_drm.h"
#include "i915_drv.h"
#include "i915_trace.h"
+#include <linux/pci.h>
#include <linux/vgaarb.h>
#include <linux/acpi.h>
#include <linux/pnp.h>
#include <linux/vga_switcheroo.h>
#include <linux/slab.h>
+extern int intel_max_stolen; /* from AGP driver */
+
/**
* Sets up the hardware status page for devices that need a physical address
* in the register.
@@ -1256,7 +1259,7 @@ static void i915_setup_compression(struct drm_device *dev, int size)
drm_mm_put_block(compressed_fb);
}
- if (!IS_GM45(dev)) {
+ if (!(IS_GM45(dev) || IS_IRONLAKE_M(dev))) {
compressed_llb = drm_mm_search_free(&dev_priv->vram, 4096,
4096, 0);
if (!compressed_llb) {
@@ -1282,8 +1285,9 @@ static void i915_setup_compression(struct drm_device *dev, int size)
intel_disable_fbc(dev);
dev_priv->compressed_fb = compressed_fb;
-
- if (IS_GM45(dev)) {
+ if (IS_IRONLAKE_M(dev))
+ I915_WRITE(ILK_DPFC_CB_BASE, compressed_fb->start);
+ else if (IS_GM45(dev)) {
I915_WRITE(DPFC_CB_BASE, compressed_fb->start);
} else {
I915_WRITE(FBC_CFB_BASE, cfb_base);
@@ -1291,7 +1295,7 @@ static void i915_setup_compression(struct drm_device *dev, int size)
dev_priv->compressed_llb = compressed_llb;
}
- DRM_DEBUG("FBC base 0x%08lx, ll base 0x%08lx, size %dM\n", cfb_base,
+ DRM_DEBUG_KMS("FBC base 0x%08lx, ll base 0x%08lx, size %dM\n", cfb_base,
ll_base, size >> 20);
}
@@ -1354,7 +1358,7 @@ static int i915_load_modeset_init(struct drm_device *dev,
int fb_bar = IS_I9XX(dev) ? 2 : 0;
int ret = 0;
- dev->mode_config.fb_base = drm_get_resource_start(dev, fb_bar) &
+ dev->mode_config.fb_base = pci_resource_start(dev->pdev, fb_bar) &
0xff000000;
/* Basic memrange allocator for stolen space (aka vram) */
@@ -2063,8 +2067,8 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
/* Add register map (needed for suspend/resume) */
mmio_bar = IS_I9XX(dev) ? 0 : 1;
- base = drm_get_resource_start(dev, mmio_bar);
- size = drm_get_resource_len(dev, mmio_bar);
+ base = pci_resource_start(dev->pdev, mmio_bar);
+ size = pci_resource_len(dev->pdev, mmio_bar);
if (i915_get_bridge_dev(dev)) {
ret = -EIO;
@@ -2104,6 +2108,12 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
if (ret)
goto out_iomapfree;
+ if (prealloc_size > intel_max_stolen) {
+ DRM_INFO("detected %dM stolen memory, trimming to %dM\n",
+ prealloc_size >> 20, intel_max_stolen >> 20);
+ prealloc_size = intel_max_stolen;
+ }
+
dev_priv->wq = create_singlethread_workqueue("i915");
if (dev_priv->wq == NULL) {
DRM_ERROR("Failed to create our workqueue.\n");
diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c
index 423dc90c1e2..5044f653e8e 100644
--- a/drivers/gpu/drm/i915/i915_drv.c
+++ b/drivers/gpu/drm/i915/i915_drv.c
@@ -93,11 +93,11 @@ static const struct intel_device_info intel_i945gm_info = {
};
static const struct intel_device_info intel_i965g_info = {
- .is_i965g = 1, .is_i9xx = 1, .has_hotplug = 1,
+ .is_broadwater = 1, .is_i965g = 1, .is_i9xx = 1, .has_hotplug = 1,
};
static const struct intel_device_info intel_i965gm_info = {
- .is_i965g = 1, .is_mobile = 1, .is_i965gm = 1, .is_i9xx = 1,
+ .is_crestline = 1, .is_i965g = 1, .is_i965gm = 1, .is_i9xx = 1,
.is_mobile = 1, .has_fbc = 1, .has_rc6 = 1,
.has_hotplug = 1,
};
@@ -114,7 +114,7 @@ static const struct intel_device_info intel_g45_info = {
};
static const struct intel_device_info intel_gm45_info = {
- .is_i965g = 1, .is_mobile = 1, .is_g4x = 1, .is_i9xx = 1,
+ .is_i965g = 1, .is_g4x = 1, .is_i9xx = 1,
.is_mobile = 1, .need_gfx_hws = 1, .has_fbc = 1, .has_rc6 = 1,
.has_pipe_cxsr = 1,
.has_hotplug = 1,
@@ -134,7 +134,7 @@ static const struct intel_device_info intel_ironlake_d_info = {
static const struct intel_device_info intel_ironlake_m_info = {
.is_ironlake = 1, .is_mobile = 1, .is_i965g = 1, .is_i9xx = 1,
- .need_gfx_hws = 1, .has_rc6 = 1,
+ .need_gfx_hws = 1, .has_fbc = 1, .has_rc6 = 1,
.has_hotplug = 1,
};
@@ -148,33 +148,33 @@ static const struct intel_device_info intel_sandybridge_m_info = {
.has_hotplug = 1, .is_gen6 = 1,
};
-static const struct pci_device_id pciidlist[] = {
- INTEL_VGA_DEVICE(0x3577, &intel_i830_info),
- INTEL_VGA_DEVICE(0x2562, &intel_845g_info),
- INTEL_VGA_DEVICE(0x3582, &intel_i85x_info),
+static const struct pci_device_id pciidlist[] = { /* aka */
+ INTEL_VGA_DEVICE(0x3577, &intel_i830_info), /* I830_M */
+ INTEL_VGA_DEVICE(0x2562, &intel_845g_info), /* 845_G */
+ INTEL_VGA_DEVICE(0x3582, &intel_i85x_info), /* I855_GM */
INTEL_VGA_DEVICE(0x358e, &intel_i85x_info),
- INTEL_VGA_DEVICE(0x2572, &intel_i865g_info),
- INTEL_VGA_DEVICE(0x2582, &intel_i915g_info),
- INTEL_VGA_DEVICE(0x258a, &intel_i915g_info),
- INTEL_VGA_DEVICE(0x2592, &intel_i915gm_info),
- INTEL_VGA_DEVICE(0x2772, &intel_i945g_info),
- INTEL_VGA_DEVICE(0x27a2, &intel_i945gm_info),
- INTEL_VGA_DEVICE(0x27ae, &intel_i945gm_info),
- INTEL_VGA_DEVICE(0x2972, &intel_i965g_info),
- INTEL_VGA_DEVICE(0x2982, &intel_i965g_info),
- INTEL_VGA_DEVICE(0x2992, &intel_i965g_info),
- INTEL_VGA_DEVICE(0x29a2, &intel_i965g_info),
- INTEL_VGA_DEVICE(0x29b2, &intel_g33_info),
- INTEL_VGA_DEVICE(0x29c2, &intel_g33_info),
- INTEL_VGA_DEVICE(0x29d2, &intel_g33_info),
- INTEL_VGA_DEVICE(0x2a02, &intel_i965gm_info),
- INTEL_VGA_DEVICE(0x2a12, &intel_i965gm_info),
- INTEL_VGA_DEVICE(0x2a42, &intel_gm45_info),
- INTEL_VGA_DEVICE(0x2e02, &intel_g45_info),
- INTEL_VGA_DEVICE(0x2e12, &intel_g45_info),
- INTEL_VGA_DEVICE(0x2e22, &intel_g45_info),
- INTEL_VGA_DEVICE(0x2e32, &intel_g45_info),
- INTEL_VGA_DEVICE(0x2e42, &intel_g45_info),
+ INTEL_VGA_DEVICE(0x2572, &intel_i865g_info), /* I865_G */
+ INTEL_VGA_DEVICE(0x2582, &intel_i915g_info), /* I915_G */
+ INTEL_VGA_DEVICE(0x258a, &intel_i915g_info), /* E7221_G */
+ INTEL_VGA_DEVICE(0x2592, &intel_i915gm_info), /* I915_GM */
+ INTEL_VGA_DEVICE(0x2772, &intel_i945g_info), /* I945_G */
+ INTEL_VGA_DEVICE(0x27a2, &intel_i945gm_info), /* I945_GM */
+ INTEL_VGA_DEVICE(0x27ae, &intel_i945gm_info), /* I945_GME */
+ INTEL_VGA_DEVICE(0x2972, &intel_i965g_info), /* I946_GZ */
+ INTEL_VGA_DEVICE(0x2982, &intel_i965g_info), /* G35_G */
+ INTEL_VGA_DEVICE(0x2992, &intel_i965g_info), /* I965_Q */
+ INTEL_VGA_DEVICE(0x29a2, &intel_i965g_info), /* I965_G */
+ INTEL_VGA_DEVICE(0x29b2, &intel_g33_info), /* Q35_G */
+ INTEL_VGA_DEVICE(0x29c2, &intel_g33_info), /* G33_G */
+ INTEL_VGA_DEVICE(0x29d2, &intel_g33_info), /* Q33_G */
+ INTEL_VGA_DEVICE(0x2a02, &intel_i965gm_info), /* I965_GM */
+ INTEL_VGA_DEVICE(0x2a12, &intel_i965gm_info), /* I965_GME */
+ INTEL_VGA_DEVICE(0x2a42, &intel_gm45_info), /* GM45_G */
+ INTEL_VGA_DEVICE(0x2e02, &intel_g45_info), /* IGD_E_G */
+ INTEL_VGA_DEVICE(0x2e12, &intel_g45_info), /* Q45_G */
+ INTEL_VGA_DEVICE(0x2e22, &intel_g45_info), /* G45_G */
+ INTEL_VGA_DEVICE(0x2e32, &intel_g45_info), /* G41_G */
+ INTEL_VGA_DEVICE(0x2e42, &intel_g45_info), /* B43_G */
INTEL_VGA_DEVICE(0xa001, &intel_pineview_info),
INTEL_VGA_DEVICE(0xa011, &intel_pineview_info),
INTEL_VGA_DEVICE(0x0042, &intel_ironlake_d_info),
@@ -340,7 +340,7 @@ int i965_reset(struct drm_device *dev, u8 flags)
/*
* Clear request list
*/
- i915_gem_retire_requests(dev, &dev_priv->render_ring);
+ i915_gem_retire_requests(dev);
if (need_display)
i915_save_display(dev);
@@ -413,7 +413,7 @@ int i965_reset(struct drm_device *dev, u8 flags)
static int __devinit
i915_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
{
- return drm_get_dev(pdev, ent, &driver);
+ return drm_get_pci_dev(pdev, ent, &driver);
}
static void
@@ -482,7 +482,7 @@ static int i915_pm_poweroff(struct device *dev)
return i915_drm_freeze(drm_dev);
}
-const struct dev_pm_ops i915_pm_ops = {
+static const struct dev_pm_ops i915_pm_ops = {
.suspend = i915_pm_suspend,
.resume = i915_pm_resume,
.freeze = i915_pm_freeze,
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 2e1744d37ad..906663b9929 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -176,7 +176,8 @@ struct drm_i915_display_funcs {
int (*get_display_clock_speed)(struct drm_device *dev);
int (*get_fifo_size)(struct drm_device *dev, int plane);
void (*update_wm)(struct drm_device *dev, int planea_clock,
- int planeb_clock, int sr_hdisplay, int pixel_size);
+ int planeb_clock, int sr_hdisplay, int sr_htotal,
+ int pixel_size);
/* clock updates for mode set */
/* cursor updates */
/* render clock increase/decrease */
@@ -200,6 +201,8 @@ struct intel_device_info {
u8 need_gfx_hws : 1;
u8 is_g4x : 1;
u8 is_pineview : 1;
+ u8 is_broadwater : 1;
+ u8 is_crestline : 1;
u8 is_ironlake : 1;
u8 is_gen6 : 1;
u8 has_fbc : 1;
@@ -288,6 +291,8 @@ typedef struct drm_i915_private {
struct timer_list hangcheck_timer;
int hangcheck_count;
uint32_t last_acthd;
+ uint32_t last_instdone;
+ uint32_t last_instdone1;
struct drm_mm vram;
@@ -547,6 +552,14 @@ typedef struct drm_i915_private {
struct list_head fence_list;
/**
+ * List of objects currently pending being freed.
+ *
+ * These objects are no longer in use, but due to a signal
+ * we were prevented from freeing them at the appointed time.
+ */
+ struct list_head deferred_free_list;
+
+ /**
* We leave the user IRQ off as much as possible,
* but this means that requests will finish and never
* be retired once the system goes idle. Set a timer to
@@ -677,7 +690,7 @@ struct drm_i915_gem_object {
*
* Size: 4 bits for 16 fences + sign (for FENCE_REG_NONE)
*/
- int fence_reg : 5;
+ signed int fence_reg : 5;
/**
* Used for checking the object doesn't appear more than once
@@ -713,7 +726,7 @@ struct drm_i915_gem_object {
*
* In the worst case this is 1 + 1 + 1 + 2*2 = 7. That would fit into 3
* bits with absolutely no headroom. So use 4 bits. */
- int pin_count : 4;
+ unsigned int pin_count : 4;
#define DRM_I915_GEM_OBJECT_MAX_PIN_COUNT 0xf
/** AGP memory structure for our GTT binding. */
@@ -743,7 +756,7 @@ struct drm_i915_gem_object {
uint32_t stride;
/** Record of address bit 17 of each page at last unbind. */
- long *bit_17;
+ unsigned long *bit_17;
/** AGP mapping type (AGP_USER_MEMORY or AGP_USER_CACHED_MEMORY */
uint32_t agp_type;
@@ -955,8 +968,7 @@ uint32_t i915_get_gem_seqno(struct drm_device *dev,
bool i915_seqno_passed(uint32_t seq1, uint32_t seq2);
int i915_gem_object_get_fence_reg(struct drm_gem_object *obj);
int i915_gem_object_put_fence_reg(struct drm_gem_object *obj);
-void i915_gem_retire_requests(struct drm_device *dev,
- struct intel_ring_buffer *ring);
+void i915_gem_retire_requests(struct drm_device *dev);
void i915_gem_retire_work_handler(struct work_struct *work);
void i915_gem_clflush_object(struct drm_gem_object *obj);
int i915_gem_object_set_domain(struct drm_gem_object *obj,
@@ -986,7 +998,7 @@ void i915_gem_free_all_phys_object(struct drm_device *dev);
int i915_gem_object_get_pages(struct drm_gem_object *obj, gfp_t gfpmask);
void i915_gem_object_put_pages(struct drm_gem_object *obj);
void i915_gem_release(struct drm_device * dev, struct drm_file *file_priv);
-void i915_gem_object_flush_write_domain(struct drm_gem_object *obj);
+int i915_gem_object_flush_write_domain(struct drm_gem_object *obj);
void i915_gem_shrinker_init(void);
void i915_gem_shrinker_exit(void);
@@ -1046,6 +1058,7 @@ extern void intel_modeset_cleanup(struct drm_device *dev);
extern int intel_modeset_vga_set_state(struct drm_device *dev, bool state);
extern void i8xx_disable_fbc(struct drm_device *dev);
extern void g4x_disable_fbc(struct drm_device *dev);
+extern void ironlake_disable_fbc(struct drm_device *dev);
extern void intel_disable_fbc(struct drm_device *dev);
extern void intel_enable_fbc(struct drm_crtc *crtc, unsigned long interval);
extern bool intel_fbc_enabled(struct drm_device *dev);
@@ -1135,6 +1148,8 @@ extern int intel_trans_dp_port_sel (struct drm_crtc *crtc);
#define IS_I945GM(dev) (INTEL_INFO(dev)->is_i945gm)
#define IS_I965G(dev) (INTEL_INFO(dev)->is_i965g)
#define IS_I965GM(dev) (INTEL_INFO(dev)->is_i965gm)
+#define IS_BROADWATER(dev) (INTEL_INFO(dev)->is_broadwater)
+#define IS_CRESTLINE(dev) (INTEL_INFO(dev)->is_crestline)
#define IS_GM45(dev) ((dev)->pci_device == 0x2A42)
#define IS_G4X(dev) (INTEL_INFO(dev)->is_g4x)
#define IS_PINEVIEW_G(dev) ((dev)->pci_device == 0xa001)
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
index 5aa747fc25a..2a4ed7ca8b4 100644
--- a/drivers/gpu/drm/i915/i915_gem.c
+++ b/drivers/gpu/drm/i915/i915_gem.c
@@ -35,7 +35,7 @@
#include <linux/swap.h>
#include <linux/pci.h>
-static void i915_gem_object_flush_gpu_write_domain(struct drm_gem_object *obj);
+static int i915_gem_object_flush_gpu_write_domain(struct drm_gem_object *obj);
static void i915_gem_object_flush_gtt_write_domain(struct drm_gem_object *obj);
static void i915_gem_object_flush_cpu_write_domain(struct drm_gem_object *obj);
static int i915_gem_object_set_to_cpu_domain(struct drm_gem_object *obj,
@@ -53,6 +53,7 @@ static int i915_gem_evict_from_inactive_list(struct drm_device *dev);
static int i915_gem_phys_pwrite(struct drm_device *dev, struct drm_gem_object *obj,
struct drm_i915_gem_pwrite *args,
struct drm_file *file_priv);
+static void i915_gem_free_object_tail(struct drm_gem_object *obj);
static LIST_HEAD(shrink_list);
static DEFINE_SPINLOCK(shrink_list_lock);
@@ -127,8 +128,7 @@ i915_gem_create_ioctl(struct drm_device *dev, void *data,
return -ENOMEM;
ret = drm_gem_handle_create(file_priv, obj, &handle);
- drm_gem_object_handle_unreference_unlocked(obj);
-
+ drm_gem_object_unreference_unlocked(obj);
if (ret)
return ret;
@@ -496,10 +496,10 @@ fast_user_write(struct io_mapping *mapping,
char *vaddr_atomic;
unsigned long unwritten;
- vaddr_atomic = io_mapping_map_atomic_wc(mapping, page_base);
+ vaddr_atomic = io_mapping_map_atomic_wc(mapping, page_base, KM_USER0);
unwritten = __copy_from_user_inatomic_nocache(vaddr_atomic + page_offset,
user_data, length);
- io_mapping_unmap_atomic(vaddr_atomic);
+ io_mapping_unmap_atomic(vaddr_atomic, KM_USER0);
if (unwritten)
return -EFAULT;
return 0;
@@ -1709,9 +1709,9 @@ i915_get_gem_seqno(struct drm_device *dev,
/**
* This function clears the request list as sequence numbers are passed.
*/
-void
-i915_gem_retire_requests(struct drm_device *dev,
- struct intel_ring_buffer *ring)
+static void
+i915_gem_retire_requests_ring(struct drm_device *dev,
+ struct intel_ring_buffer *ring)
{
drm_i915_private_t *dev_priv = dev->dev_private;
uint32_t seqno;
@@ -1751,6 +1751,30 @@ i915_gem_retire_requests(struct drm_device *dev,
}
void
+i915_gem_retire_requests(struct drm_device *dev)
+{
+ drm_i915_private_t *dev_priv = dev->dev_private;
+
+ if (!list_empty(&dev_priv->mm.deferred_free_list)) {
+ struct drm_i915_gem_object *obj_priv, *tmp;
+
+ /* We must be careful that during unbind() we do not
+ * accidentally infinitely recurse into retire requests.
+ * Currently:
+ * retire -> free -> unbind -> wait -> retire_ring
+ */
+ list_for_each_entry_safe(obj_priv, tmp,
+ &dev_priv->mm.deferred_free_list,
+ list)
+ i915_gem_free_object_tail(&obj_priv->base);
+ }
+
+ i915_gem_retire_requests_ring(dev, &dev_priv->render_ring);
+ if (HAS_BSD(dev))
+ i915_gem_retire_requests_ring(dev, &dev_priv->bsd_ring);
+}
+
+void
i915_gem_retire_work_handler(struct work_struct *work)
{
drm_i915_private_t *dev_priv;
@@ -1761,10 +1785,7 @@ i915_gem_retire_work_handler(struct work_struct *work)
dev = dev_priv->dev;
mutex_lock(&dev->struct_mutex);
- i915_gem_retire_requests(dev, &dev_priv->render_ring);
-
- if (HAS_BSD(dev))
- i915_gem_retire_requests(dev, &dev_priv->bsd_ring);
+ i915_gem_retire_requests(dev);
if (!dev_priv->mm.suspended &&
(!list_empty(&dev_priv->render_ring.request_list) ||
@@ -1832,7 +1853,7 @@ i915_do_wait_request(struct drm_device *dev, uint32_t seqno,
* a separate wait queue to handle that.
*/
if (ret == 0)
- i915_gem_retire_requests(dev, ring);
+ i915_gem_retire_requests_ring(dev, ring);
return ret;
}
@@ -1945,11 +1966,12 @@ i915_gem_object_unbind(struct drm_gem_object *obj)
* before we unbind.
*/
ret = i915_gem_object_set_to_cpu_domain(obj, 1);
- if (ret) {
- if (ret != -ERESTARTSYS)
- DRM_ERROR("set_domain failed: %d\n", ret);
+ if (ret == -ERESTARTSYS)
return ret;
- }
+ /* Continue on if we fail due to EIO, the GPU is hung so we
+ * should be safe and we need to cleanup or else we might
+ * cause memory corruption through use-after-free.
+ */
BUG_ON(obj_priv->active);
@@ -1985,7 +2007,7 @@ i915_gem_object_unbind(struct drm_gem_object *obj)
trace_i915_gem_object_unbind(obj);
- return 0;
+ return ret;
}
static struct drm_gem_object *
@@ -2107,10 +2129,7 @@ i915_gem_evict_something(struct drm_device *dev, int min_size)
struct intel_ring_buffer *render_ring = &dev_priv->render_ring;
struct intel_ring_buffer *bsd_ring = &dev_priv->bsd_ring;
for (;;) {
- i915_gem_retire_requests(dev, render_ring);
-
- if (HAS_BSD(dev))
- i915_gem_retire_requests(dev, bsd_ring);
+ i915_gem_retire_requests(dev);
/* If there's an inactive buffer available now, grab it
* and be done.
@@ -2583,7 +2602,10 @@ i915_gem_object_put_fence_reg(struct drm_gem_object *obj)
if (!IS_I965G(dev)) {
int ret;
- i915_gem_object_flush_gpu_write_domain(obj);
+ ret = i915_gem_object_flush_gpu_write_domain(obj);
+ if (ret != 0)
+ return ret;
+
ret = i915_gem_object_wait_rendering(obj);
if (ret != 0)
return ret;
@@ -2634,10 +2656,8 @@ i915_gem_object_bind_to_gtt(struct drm_gem_object *obj, unsigned alignment)
if (free_space != NULL) {
obj_priv->gtt_space = drm_mm_get_block(free_space, obj->size,
alignment);
- if (obj_priv->gtt_space != NULL) {
- obj_priv->gtt_space->private = obj;
+ if (obj_priv->gtt_space != NULL)
obj_priv->gtt_offset = obj_priv->gtt_space->start;
- }
}
if (obj_priv->gtt_space == NULL) {
/* If the gtt is empty and we're still having trouble
@@ -2733,7 +2753,7 @@ i915_gem_clflush_object(struct drm_gem_object *obj)
}
/** Flushes any GPU write domain for the object if it's dirty. */
-static void
+static int
i915_gem_object_flush_gpu_write_domain(struct drm_gem_object *obj)
{
struct drm_device *dev = obj->dev;
@@ -2741,17 +2761,18 @@ i915_gem_object_flush_gpu_write_domain(struct drm_gem_object *obj)
struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
if ((obj->write_domain & I915_GEM_GPU_DOMAINS) == 0)
- return;
+ return 0;
/* Queue the GPU write cache flushing we need. */
old_write_domain = obj->write_domain;
i915_gem_flush(dev, 0, obj->write_domain);
- (void) i915_add_request(dev, NULL, obj->write_domain, obj_priv->ring);
- BUG_ON(obj->write_domain);
+ if (i915_add_request(dev, NULL, obj->write_domain, obj_priv->ring) == 0)
+ return -ENOMEM;
trace_i915_gem_object_change_domain(obj,
obj->read_domains,
old_write_domain);
+ return 0;
}
/** Flushes the GTT write domain for the object if it's dirty. */
@@ -2795,9 +2816,11 @@ i915_gem_object_flush_cpu_write_domain(struct drm_gem_object *obj)
old_write_domain);
}
-void
+int
i915_gem_object_flush_write_domain(struct drm_gem_object *obj)
{
+ int ret = 0;
+
switch (obj->write_domain) {
case I915_GEM_DOMAIN_GTT:
i915_gem_object_flush_gtt_write_domain(obj);
@@ -2806,9 +2829,11 @@ i915_gem_object_flush_write_domain(struct drm_gem_object *obj)
i915_gem_object_flush_cpu_write_domain(obj);
break;
default:
- i915_gem_object_flush_gpu_write_domain(obj);
+ ret = i915_gem_object_flush_gpu_write_domain(obj);
break;
}
+
+ return ret;
}
/**
@@ -2828,7 +2853,10 @@ i915_gem_object_set_to_gtt_domain(struct drm_gem_object *obj, int write)
if (obj_priv->gtt_space == NULL)
return -EINVAL;
- i915_gem_object_flush_gpu_write_domain(obj);
+ ret = i915_gem_object_flush_gpu_write_domain(obj);
+ if (ret != 0)
+ return ret;
+
/* Wait on any GPU rendering and flushing to occur. */
ret = i915_gem_object_wait_rendering(obj);
if (ret != 0)
@@ -2878,7 +2906,9 @@ i915_gem_object_set_to_display_plane(struct drm_gem_object *obj)
if (obj_priv->gtt_space == NULL)
return -EINVAL;
- i915_gem_object_flush_gpu_write_domain(obj);
+ ret = i915_gem_object_flush_gpu_write_domain(obj);
+ if (ret)
+ return ret;
/* Wait on any GPU rendering and flushing to occur. */
if (obj_priv->active) {
@@ -2926,7 +2956,10 @@ i915_gem_object_set_to_cpu_domain(struct drm_gem_object *obj, int write)
uint32_t old_write_domain, old_read_domains;
int ret;
- i915_gem_object_flush_gpu_write_domain(obj);
+ ret = i915_gem_object_flush_gpu_write_domain(obj);
+ if (ret)
+ return ret;
+
/* Wait on any GPU rendering and flushing to occur. */
ret = i915_gem_object_wait_rendering(obj);
if (ret != 0)
@@ -3216,7 +3249,10 @@ i915_gem_object_set_cpu_read_domain_range(struct drm_gem_object *obj,
if (offset == 0 && size == obj->size)
return i915_gem_object_set_to_cpu_domain(obj, 0);
- i915_gem_object_flush_gpu_write_domain(obj);
+ ret = i915_gem_object_flush_gpu_write_domain(obj);
+ if (ret)
+ return ret;
+
/* Wait on any GPU rendering and flushing to occur. */
ret = i915_gem_object_wait_rendering(obj);
if (ret != 0)
@@ -3451,7 +3487,8 @@ i915_gem_object_pin_and_relocate(struct drm_gem_object *obj,
reloc_offset = obj_priv->gtt_offset + reloc->offset;
reloc_page = io_mapping_map_atomic_wc(dev_priv->mm.gtt_mapping,
(reloc_offset &
- ~(PAGE_SIZE - 1)));
+ ~(PAGE_SIZE - 1)),
+ KM_USER0);
reloc_entry = (uint32_t __iomem *)(reloc_page +
(reloc_offset & (PAGE_SIZE - 1)));
reloc_val = target_obj_priv->gtt_offset + reloc->delta;
@@ -3462,7 +3499,7 @@ i915_gem_object_pin_and_relocate(struct drm_gem_object *obj,
readl(reloc_entry), reloc_val);
#endif
writel(reloc_val, reloc_entry);
- io_mapping_unmap_atomic(reloc_page);
+ io_mapping_unmap_atomic(reloc_page, KM_USER0);
/* The updated presumed offset for this entry will be
* copied back out to the user.
@@ -4313,7 +4350,6 @@ i915_gem_busy_ioctl(struct drm_device *dev, void *data,
struct drm_i915_gem_busy *args = data;
struct drm_gem_object *obj;
struct drm_i915_gem_object *obj_priv;
- drm_i915_private_t *dev_priv = dev->dev_private;
obj = drm_gem_object_lookup(dev, file_priv, args->handle);
if (obj == NULL) {
@@ -4328,10 +4364,7 @@ i915_gem_busy_ioctl(struct drm_device *dev, void *data,
* actually unmasked, and our working set ends up being larger than
* required.
*/
- i915_gem_retire_requests(dev, &dev_priv->render_ring);
-
- if (HAS_BSD(dev))
- i915_gem_retire_requests(dev, &dev_priv->bsd_ring);
+ i915_gem_retire_requests(dev);
obj_priv = to_intel_bo(obj);
/* Don't count being on the flushing list against the object being
@@ -4441,20 +4474,19 @@ int i915_gem_init_object(struct drm_gem_object *obj)
return 0;
}
-void i915_gem_free_object(struct drm_gem_object *obj)
+static void i915_gem_free_object_tail(struct drm_gem_object *obj)
{
struct drm_device *dev = obj->dev;
+ drm_i915_private_t *dev_priv = dev->dev_private;
struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
+ int ret;
- trace_i915_gem_object_destroy(obj);
-
- while (obj_priv->pin_count > 0)
- i915_gem_object_unpin(obj);
-
- if (obj_priv->phys_obj)
- i915_gem_detach_phys_object(dev, obj);
-
- i915_gem_object_unbind(obj);
+ ret = i915_gem_object_unbind(obj);
+ if (ret == -ERESTARTSYS) {
+ list_move(&obj_priv->list,
+ &dev_priv->mm.deferred_free_list);
+ return;
+ }
if (obj_priv->mmap_offset)
i915_gem_free_mmap_offset(obj);
@@ -4466,6 +4498,22 @@ void i915_gem_free_object(struct drm_gem_object *obj)
kfree(obj_priv);
}
+void i915_gem_free_object(struct drm_gem_object *obj)
+{
+ struct drm_device *dev = obj->dev;
+ struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
+
+ trace_i915_gem_object_destroy(obj);
+
+ while (obj_priv->pin_count > 0)
+ i915_gem_object_unpin(obj);
+
+ if (obj_priv->phys_obj)
+ i915_gem_detach_phys_object(dev, obj);
+
+ i915_gem_free_object_tail(obj);
+}
+
/** Unbinds all inactive objects. */
static int
i915_gem_evict_from_inactive_list(struct drm_device *dev)
@@ -4689,9 +4737,19 @@ i915_gem_entervt_ioctl(struct drm_device *dev, void *data,
BUG_ON(HAS_BSD(dev) && !list_empty(&dev_priv->bsd_ring.request_list));
mutex_unlock(&dev->struct_mutex);
- drm_irq_install(dev);
+ ret = drm_irq_install(dev);
+ if (ret)
+ goto cleanup_ringbuffer;
return 0;
+
+cleanup_ringbuffer:
+ mutex_lock(&dev->struct_mutex);
+ i915_gem_cleanup_ringbuffer(dev);
+ dev_priv->mm.suspended = 1;
+ mutex_unlock(&dev->struct_mutex);
+
+ return ret;
}
int
@@ -4729,6 +4787,7 @@ i915_gem_load(struct drm_device *dev)
INIT_LIST_HEAD(&dev_priv->mm.gpu_write_list);
INIT_LIST_HEAD(&dev_priv->mm.inactive_list);
INIT_LIST_HEAD(&dev_priv->mm.fence_list);
+ INIT_LIST_HEAD(&dev_priv->mm.deferred_free_list);
INIT_LIST_HEAD(&dev_priv->render_ring.active_list);
INIT_LIST_HEAD(&dev_priv->render_ring.request_list);
if (HAS_BSD(dev)) {
@@ -5027,10 +5086,7 @@ rescan:
continue;
spin_unlock(&shrink_list_lock);
- i915_gem_retire_requests(dev, &dev_priv->render_ring);
-
- if (HAS_BSD(dev))
- i915_gem_retire_requests(dev, &dev_priv->bsd_ring);
+ i915_gem_retire_requests(dev);
list_for_each_entry_safe(obj_priv, next_obj,
&dev_priv->mm.inactive_list,
diff --git a/drivers/gpu/drm/i915/i915_gem_tiling.c b/drivers/gpu/drm/i915/i915_gem_tiling.c
index 4b7c49d4257..155719e4d16 100644
--- a/drivers/gpu/drm/i915/i915_gem_tiling.c
+++ b/drivers/gpu/drm/i915/i915_gem_tiling.c
@@ -333,8 +333,6 @@ i915_gem_set_tiling(struct drm_device *dev, void *data,
i915_gem_release_mmap(obj);
if (ret != 0) {
- WARN(ret != -ERESTARTSYS,
- "failed to reset object for tiling switch");
args->tiling_mode = obj_priv->tiling_mode;
args->stride = obj_priv->stride;
goto err;
diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index dba53d4b9fb..85785a8844e 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -171,10 +171,10 @@ void intel_enable_asle (struct drm_device *dev)
ironlake_enable_display_irq(dev_priv, DE_GSE);
else {
i915_enable_pipestat(dev_priv, 1,
- I915_LEGACY_BLC_EVENT_ENABLE);
+ PIPE_LEGACY_BLC_EVENT_ENABLE);
if (IS_I965G(dev))
i915_enable_pipestat(dev_priv, 0,
- I915_LEGACY_BLC_EVENT_ENABLE);
+ PIPE_LEGACY_BLC_EVENT_ENABLE);
}
}
@@ -842,7 +842,6 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
u32 iir, new_iir;
u32 pipea_stats, pipeb_stats;
u32 vblank_status;
- u32 vblank_enable;
int vblank = 0;
unsigned long irqflags;
int irq_received;
@@ -856,13 +855,10 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
iir = I915_READ(IIR);
- if (IS_I965G(dev)) {
- vblank_status = I915_START_VBLANK_INTERRUPT_STATUS;
- vblank_enable = PIPE_START_VBLANK_INTERRUPT_ENABLE;
- } else {
- vblank_status = I915_VBLANK_INTERRUPT_STATUS;
- vblank_enable = I915_VBLANK_INTERRUPT_ENABLE;
- }
+ if (IS_I965G(dev))
+ vblank_status = PIPE_START_VBLANK_INTERRUPT_STATUS;
+ else
+ vblank_status = PIPE_VBLANK_INTERRUPT_STATUS;
for (;;) {
irq_received = iir != 0;
@@ -966,8 +962,8 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
intel_finish_page_flip(dev, 1);
}
- if ((pipea_stats & I915_LEGACY_BLC_EVENT_STATUS) ||
- (pipeb_stats & I915_LEGACY_BLC_EVENT_STATUS) ||
+ if ((pipea_stats & PIPE_LEGACY_BLC_EVENT_STATUS) ||
+ (pipeb_stats & PIPE_LEGACY_BLC_EVENT_STATUS) ||
(iir & I915_ASLE_INTERRUPT))
opregion_asle_intr(dev);
@@ -1233,16 +1229,21 @@ void i915_hangcheck_elapsed(unsigned long data)
{
struct drm_device *dev = (struct drm_device *)data;
drm_i915_private_t *dev_priv = dev->dev_private;
- uint32_t acthd;
+ uint32_t acthd, instdone, instdone1;
/* No reset support on this chip yet. */
if (IS_GEN6(dev))
return;
- if (!IS_I965G(dev))
+ if (!IS_I965G(dev)) {
acthd = I915_READ(ACTHD);
- else
+ instdone = I915_READ(INSTDONE);
+ instdone1 = 0;
+ } else {
acthd = I915_READ(ACTHD_I965);
+ instdone = I915_READ(INSTDONE_I965);
+ instdone1 = I915_READ(INSTDONE1);
+ }
/* If all work is done then ACTHD clearly hasn't advanced. */
if (list_empty(&dev_priv->render_ring.request_list) ||
@@ -1253,21 +1254,24 @@ void i915_hangcheck_elapsed(unsigned long data)
return;
}
- if (dev_priv->last_acthd == acthd && dev_priv->hangcheck_count > 0) {
- DRM_ERROR("Hangcheck timer elapsed... GPU hung\n");
- i915_handle_error(dev, true);
- return;
- }
+ if (dev_priv->last_acthd == acthd &&
+ dev_priv->last_instdone == instdone &&
+ dev_priv->last_instdone1 == instdone1) {
+ if (dev_priv->hangcheck_count++ > 1) {
+ DRM_ERROR("Hangcheck timer elapsed... GPU hung\n");
+ i915_handle_error(dev, true);
+ return;
+ }
+ } else {
+ dev_priv->hangcheck_count = 0;
+
+ dev_priv->last_acthd = acthd;
+ dev_priv->last_instdone = instdone;
+ dev_priv->last_instdone1 = instdone1;
+ }
/* Reset timer case chip hangs without another request being added */
mod_timer(&dev_priv->hangcheck_timer, jiffies + DRM_I915_HANGCHECK_PERIOD);
-
- if (acthd != dev_priv->last_acthd)
- dev_priv->hangcheck_count = 0;
- else
- dev_priv->hangcheck_count++;
-
- dev_priv->last_acthd = acthd;
}
/* drm_dma.h hooks
diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
index cf41c672def..281db6e5403 100644
--- a/drivers/gpu/drm/i915/i915_reg.h
+++ b/drivers/gpu/drm/i915/i915_reg.h
@@ -442,7 +442,7 @@
#define GEN6_RENDER_IMR 0x20a8
#define GEN6_RENDER_CONTEXT_SWITCH_INTERRUPT (1 << 8)
#define GEN6_RENDER_PPGTT_PAGE_FAULT (1 << 7)
-#define GEN6_RENDER TIMEOUT_COUNTER_EXPIRED (1 << 6)
+#define GEN6_RENDER_TIMEOUT_COUNTER_EXPIRED (1 << 6)
#define GEN6_RENDER_L3_PARITY_ERROR (1 << 5)
#define GEN6_RENDER_PIPE_CONTROL_NOTIFY_INTERRUPT (1 << 4)
#define GEN6_RENDER_COMMAND_PARSER_MASTER_ERROR (1 << 3)
@@ -530,6 +530,21 @@
#define DPFC_CHICKEN 0x3224
#define DPFC_HT_MODIFY (1<<31)
+/* Framebuffer compression for Ironlake */
+#define ILK_DPFC_CB_BASE 0x43200
+#define ILK_DPFC_CONTROL 0x43208
+/* The bit 28-8 is reserved */
+#define DPFC_RESERVED (0x1FFFFF00)
+#define ILK_DPFC_RECOMP_CTL 0x4320c
+#define ILK_DPFC_STATUS 0x43210
+#define ILK_DPFC_FENCE_YOFF 0x43218
+#define ILK_DPFC_CHICKEN 0x43224
+#define ILK_FBC_RT_BASE 0x2128
+#define ILK_FBC_RT_VALID (1<<0)
+
+#define ILK_DISPLAY_CHICKEN1 0x42000
+#define ILK_FBCQ_DIS (1<<22)
+
/*
* GPIO regs
*/
@@ -595,32 +610,6 @@
#define DPLL_FPA01_P1_POST_DIV_MASK 0x00ff0000 /* i915 */
#define DPLL_FPA01_P1_POST_DIV_MASK_PINEVIEW 0x00ff8000 /* Pineview */
-#define I915_FIFO_UNDERRUN_STATUS (1UL<<31)
-#define I915_CRC_ERROR_ENABLE (1UL<<29)
-#define I915_CRC_DONE_ENABLE (1UL<<28)
-#define I915_GMBUS_EVENT_ENABLE (1UL<<27)
-#define I915_VSYNC_INTERRUPT_ENABLE (1UL<<25)
-#define I915_DISPLAY_LINE_COMPARE_ENABLE (1UL<<24)
-#define I915_DPST_EVENT_ENABLE (1UL<<23)
-#define I915_LEGACY_BLC_EVENT_ENABLE (1UL<<22)
-#define I915_ODD_FIELD_INTERRUPT_ENABLE (1UL<<21)
-#define I915_EVEN_FIELD_INTERRUPT_ENABLE (1UL<<20)
-#define I915_START_VBLANK_INTERRUPT_ENABLE (1UL<<18) /* 965 or later */
-#define I915_VBLANK_INTERRUPT_ENABLE (1UL<<17)
-#define I915_OVERLAY_UPDATED_ENABLE (1UL<<16)
-#define I915_CRC_ERROR_INTERRUPT_STATUS (1UL<<13)
-#define I915_CRC_DONE_INTERRUPT_STATUS (1UL<<12)
-#define I915_GMBUS_INTERRUPT_STATUS (1UL<<11)
-#define I915_VSYNC_INTERRUPT_STATUS (1UL<<9)
-#define I915_DISPLAY_LINE_COMPARE_STATUS (1UL<<8)
-#define I915_DPST_EVENT_STATUS (1UL<<7)
-#define I915_LEGACY_BLC_EVENT_STATUS (1UL<<6)
-#define I915_ODD_FIELD_INTERRUPT_STATUS (1UL<<5)
-#define I915_EVEN_FIELD_INTERRUPT_STATUS (1UL<<4)
-#define I915_START_VBLANK_INTERRUPT_STATUS (1UL<<2) /* 965 or later */
-#define I915_VBLANK_INTERRUPT_STATUS (1UL<<1)
-#define I915_OVERLAY_UPDATED_STATUS (1UL<<0)
-
#define SRX_INDEX 0x3c4
#define SRX_DATA 0x3c5
#define SR01 1
@@ -2166,7 +2155,8 @@
#define I830_FIFO_LINE_SIZE 32
#define G4X_FIFO_SIZE 127
-#define I945_FIFO_SIZE 127 /* 945 & 965 */
+#define I965_FIFO_SIZE 512
+#define I945_FIFO_SIZE 127
#define I915_FIFO_SIZE 95
#define I855GM_FIFO_SIZE 127 /* In cachelines */
#define I830_FIFO_SIZE 95
@@ -2185,6 +2175,9 @@
#define PINEVIEW_CURSOR_DFT_WM 0
#define PINEVIEW_CURSOR_GUARD_WM 5
+#define I965_CURSOR_FIFO 64
+#define I965_CURSOR_MAX_WM 32
+#define I965_CURSOR_DFT_WM 8
/* define the Watermark register on Ironlake */
#define WM0_PIPEA_ILK 0x45100
@@ -2212,6 +2205,9 @@
#define ILK_DISPLAY_FIFO 128
#define ILK_DISPLAY_MAXWM 64
#define ILK_DISPLAY_DFTWM 8
+#define ILK_CURSOR_FIFO 32
+#define ILK_CURSOR_MAXWM 16
+#define ILK_CURSOR_DFTWM 8
#define ILK_DISPLAY_SR_FIFO 512
#define ILK_DISPLAY_MAX_SRWM 0x1ff
@@ -2510,6 +2506,10 @@
#define ILK_VSDPFD_FULL (1<<21)
#define ILK_DSPCLK_GATE 0x42020
#define ILK_DPARB_CLK_GATE (1<<5)
+/* According to spec this bit 7/8/9 of 0x42020 should be set to enable FBC */
+#define ILK_CLK_FBC (1<<7)
+#define ILK_DPFC_DIS1 (1<<8)
+#define ILK_DPFC_DIS2 (1<<9)
#define DISP_ARB_CTL 0x45000
#define DISP_TILE_SURFACE_SWIZZLING (1<<13)
diff --git a/drivers/gpu/drm/i915/i915_suspend.c b/drivers/gpu/drm/i915/i915_suspend.c
index 60a5800fba6..6e2025274db 100644
--- a/drivers/gpu/drm/i915/i915_suspend.c
+++ b/drivers/gpu/drm/i915/i915_suspend.c
@@ -602,7 +602,9 @@ void i915_save_display(struct drm_device *dev)
/* Only save FBC state on the platform that supports FBC */
if (I915_HAS_FBC(dev)) {
- if (IS_GM45(dev)) {
+ if (IS_IRONLAKE_M(dev)) {
+ dev_priv->saveDPFC_CB_BASE = I915_READ(ILK_DPFC_CB_BASE);
+ } else if (IS_GM45(dev)) {
dev_priv->saveDPFC_CB_BASE = I915_READ(DPFC_CB_BASE);
} else {
dev_priv->saveFBC_CFB_BASE = I915_READ(FBC_CFB_BASE);
@@ -706,7 +708,10 @@ void i915_restore_display(struct drm_device *dev)
/* only restore FBC info on the platform that supports FBC*/
if (I915_HAS_FBC(dev)) {
- if (IS_GM45(dev)) {
+ if (IS_IRONLAKE_M(dev)) {
+ ironlake_disable_fbc(dev);
+ I915_WRITE(ILK_DPFC_CB_BASE, dev_priv->saveDPFC_CB_BASE);
+ } else if (IS_GM45(dev)) {
g4x_disable_fbc(dev);
I915_WRITE(DPFC_CB_BASE, dev_priv->saveDPFC_CB_BASE);
} else {
diff --git a/drivers/gpu/drm/i915/i915_trace.h b/drivers/gpu/drm/i915/i915_trace.h
index fab21760dd5..fea97a21cc1 100644
--- a/drivers/gpu/drm/i915/i915_trace.h
+++ b/drivers/gpu/drm/i915/i915_trace.h
@@ -262,6 +262,42 @@ DEFINE_EVENT(i915_ring, i915_ring_wait_end,
TP_ARGS(dev)
);
+TRACE_EVENT(i915_flip_request,
+ TP_PROTO(int plane, struct drm_gem_object *obj),
+
+ TP_ARGS(plane, obj),
+
+ TP_STRUCT__entry(
+ __field(int, plane)
+ __field(struct drm_gem_object *, obj)
+ ),
+
+ TP_fast_assign(
+ __entry->plane = plane;
+ __entry->obj = obj;
+ ),
+
+ TP_printk("plane=%d, obj=%p", __entry->plane, __entry->obj)
+);
+
+TRACE_EVENT(i915_flip_complete,
+ TP_PROTO(int plane, struct drm_gem_object *obj),
+
+ TP_ARGS(plane, obj),
+
+ TP_STRUCT__entry(
+ __field(int, plane)
+ __field(struct drm_gem_object *, obj)
+ ),
+
+ TP_fast_assign(
+ __entry->plane = plane;
+ __entry->obj = obj;
+ ),
+
+ TP_printk("plane=%d, obj=%p", __entry->plane, __entry->obj)
+);
+
#endif /* _I915_TRACE_H_ */
/* This part must be outside protection */
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 5e21b311982..1e5e0d379fa 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -33,6 +33,7 @@
#include "intel_drv.h"
#include "i915_drm.h"
#include "i915_drv.h"
+#include "i915_trace.h"
#include "drm_dp_helper.h"
#include "drm_crtc_helper.h"
@@ -42,6 +43,7 @@
bool intel_pipe_has_type (struct drm_crtc *crtc, int type);
static void intel_update_watermarks(struct drm_device *dev);
static void intel_increase_pllclock(struct drm_crtc *crtc, bool schedule);
+static void intel_crtc_update_cursor(struct drm_crtc *crtc);
typedef struct {
/* given values */
@@ -322,6 +324,9 @@ struct intel_limit {
#define IRONLAKE_DP_P1_MIN 1
#define IRONLAKE_DP_P1_MAX 2
+/* FDI */
+#define IRONLAKE_FDI_FREQ 2700000 /* in kHz for mode->clock */
+
static bool
intel_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc,
int target, int refclk, intel_clock_t *best_clock);
@@ -975,7 +980,10 @@ void
intel_wait_for_vblank(struct drm_device *dev)
{
/* Wait for 20ms, i.e. one cycle at 50hz. */
- msleep(20);
+ if (in_dbg_master())
+ mdelay(20); /* The kernel debugger cannot call msleep() */
+ else
+ msleep(20);
}
/* Parameters have changed, update FBC info */
@@ -1122,6 +1130,67 @@ static bool g4x_fbc_enabled(struct drm_device *dev)
return I915_READ(DPFC_CONTROL) & DPFC_CTL_EN;
}
+static void ironlake_enable_fbc(struct drm_crtc *crtc, unsigned long interval)
+{
+ struct drm_device *dev = crtc->dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct drm_framebuffer *fb = crtc->fb;
+ struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb);
+ struct drm_i915_gem_object *obj_priv = to_intel_bo(intel_fb->obj);
+ struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+ int plane = (intel_crtc->plane == 0) ? DPFC_CTL_PLANEA :
+ DPFC_CTL_PLANEB;
+ unsigned long stall_watermark = 200;
+ u32 dpfc_ctl;
+
+ dev_priv->cfb_pitch = (dev_priv->cfb_pitch / 64) - 1;
+ dev_priv->cfb_fence = obj_priv->fence_reg;
+ dev_priv->cfb_plane = intel_crtc->plane;
+
+ dpfc_ctl = I915_READ(ILK_DPFC_CONTROL);
+ dpfc_ctl &= DPFC_RESERVED;
+ dpfc_ctl |= (plane | DPFC_CTL_LIMIT_1X);
+ if (obj_priv->tiling_mode != I915_TILING_NONE) {
+ dpfc_ctl |= (DPFC_CTL_FENCE_EN | dev_priv->cfb_fence);
+ I915_WRITE(ILK_DPFC_CHICKEN, DPFC_HT_MODIFY);
+ } else {
+ I915_WRITE(ILK_DPFC_CHICKEN, ~DPFC_HT_MODIFY);
+ }
+
+ I915_WRITE(ILK_DPFC_CONTROL, dpfc_ctl);
+ I915_WRITE(ILK_DPFC_RECOMP_CTL, DPFC_RECOMP_STALL_EN |
+ (stall_watermark << DPFC_RECOMP_STALL_WM_SHIFT) |
+ (interval << DPFC_RECOMP_TIMER_COUNT_SHIFT));
+ I915_WRITE(ILK_DPFC_FENCE_YOFF, crtc->y);
+ I915_WRITE(ILK_FBC_RT_BASE, obj_priv->gtt_offset | ILK_FBC_RT_VALID);
+ /* enable it... */
+ I915_WRITE(ILK_DPFC_CONTROL, I915_READ(ILK_DPFC_CONTROL) |
+ DPFC_CTL_EN);
+
+ DRM_DEBUG_KMS("enabled fbc on plane %d\n", intel_crtc->plane);
+}
+
+void ironlake_disable_fbc(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ u32 dpfc_ctl;
+
+ /* Disable compression */
+ dpfc_ctl = I915_READ(ILK_DPFC_CONTROL);
+ dpfc_ctl &= ~DPFC_CTL_EN;
+ I915_WRITE(ILK_DPFC_CONTROL, dpfc_ctl);
+ intel_wait_for_vblank(dev);
+
+ DRM_DEBUG_KMS("disabled FBC\n");
+}
+
+static bool ironlake_fbc_enabled(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+
+ return I915_READ(ILK_DPFC_CONTROL) & DPFC_CTL_EN;
+}
+
bool intel_fbc_enabled(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
@@ -1248,6 +1317,10 @@ static void intel_update_fbc(struct drm_crtc *crtc,
goto out_disable;
}
+ /* If the kernel debugger is active, always disable compression */
+ if (in_dbg_master())
+ goto out_disable;
+
if (intel_fbc_enabled(dev)) {
/* We can re-enable it in this case, but need to update pitch */
if ((fb->pitch > dev_priv->cfb_pitch) ||
@@ -1279,7 +1352,12 @@ intel_pin_and_fence_fb_obj(struct drm_device *dev, struct drm_gem_object *obj)
switch (obj_priv->tiling_mode) {
case I915_TILING_NONE:
- alignment = 64 * 1024;
+ if (IS_BROADWATER(dev) || IS_CRESTLINE(dev))
+ alignment = 128 * 1024;
+ else if (IS_I965G(dev))
+ alignment = 4 * 1024;
+ else
+ alignment = 64 * 1024;
break;
case I915_TILING_X:
/* pin() will align the object as required by fence */
@@ -1314,6 +1392,98 @@ intel_pin_and_fence_fb_obj(struct drm_device *dev, struct drm_gem_object *obj)
return 0;
}
+/* Assume fb object is pinned & idle & fenced and just update base pointers */
+static int
+intel_pipe_set_base_atomic(struct drm_crtc *crtc, struct drm_framebuffer *fb,
+ int x, int y)
+{
+ struct drm_device *dev = crtc->dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+ struct intel_framebuffer *intel_fb;
+ struct drm_i915_gem_object *obj_priv;
+ struct drm_gem_object *obj;
+ int plane = intel_crtc->plane;
+ unsigned long Start, Offset;
+ int dspbase = (plane == 0 ? DSPAADDR : DSPBADDR);
+ int dspsurf = (plane == 0 ? DSPASURF : DSPBSURF);
+ int dspstride = (plane == 0) ? DSPASTRIDE : DSPBSTRIDE;
+ int dsptileoff = (plane == 0 ? DSPATILEOFF : DSPBTILEOFF);
+ int dspcntr_reg = (plane == 0) ? DSPACNTR : DSPBCNTR;
+ u32 dspcntr;
+
+ switch (plane) {
+ case 0:
+ case 1:
+ break;
+ default:
+ DRM_ERROR("Can't update plane %d in SAREA\n", plane);
+ return -EINVAL;
+ }
+
+ intel_fb = to_intel_framebuffer(fb);
+ obj = intel_fb->obj;
+ obj_priv = to_intel_bo(obj);
+
+ dspcntr = I915_READ(dspcntr_reg);
+ /* Mask out pixel format bits in case we change it */
+ dspcntr &= ~DISPPLANE_PIXFORMAT_MASK;
+ switch (fb->bits_per_pixel) {
+ case 8:
+ dspcntr |= DISPPLANE_8BPP;
+ break;
+ case 16:
+ if (fb->depth == 15)
+ dspcntr |= DISPPLANE_15_16BPP;
+ else
+ dspcntr |= DISPPLANE_16BPP;
+ break;
+ case 24:
+ case 32:
+ dspcntr |= DISPPLANE_32BPP_NO_ALPHA;
+ break;
+ default:
+ DRM_ERROR("Unknown color depth\n");
+ return -EINVAL;
+ }
+ if (IS_I965G(dev)) {
+ if (obj_priv->tiling_mode != I915_TILING_NONE)
+ dspcntr |= DISPPLANE_TILED;
+ else
+ dspcntr &= ~DISPPLANE_TILED;
+ }
+
+ if (IS_IRONLAKE(dev))
+ /* must disable */
+ dspcntr |= DISPPLANE_TRICKLE_FEED_DISABLE;
+
+ I915_WRITE(dspcntr_reg, dspcntr);
+
+ Start = obj_priv->gtt_offset;
+ Offset = y * fb->pitch + x * (fb->bits_per_pixel / 8);
+
+ DRM_DEBUG("Writing base %08lX %08lX %d %d\n", Start, Offset, x, y);
+ I915_WRITE(dspstride, fb->pitch);
+ if (IS_I965G(dev)) {
+ I915_WRITE(dspbase, Offset);
+ I915_READ(dspbase);
+ I915_WRITE(dspsurf, Start);
+ I915_READ(dspsurf);
+ I915_WRITE(dsptileoff, (y << 16) | x);
+ } else {
+ I915_WRITE(dspbase, Start + Offset);
+ I915_READ(dspbase);
+ }
+
+ if ((IS_I965G(dev) || plane == 0))
+ intel_update_fbc(crtc, &crtc->mode);
+
+ intel_wait_for_vblank(dev);
+ intel_increase_pllclock(crtc, true);
+
+ return 0;
+}
+
static int
intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
struct drm_framebuffer *old_fb)
@@ -1554,6 +1724,15 @@ static void ironlake_fdi_link_train(struct drm_crtc *crtc)
int fdi_rx_imr_reg = (pipe == 0) ? FDI_RXA_IMR : FDI_RXB_IMR;
u32 temp, tries = 0;
+ /* Train 1: umask FDI RX Interrupt symbol_lock and bit_lock bit
+ for train result */
+ temp = I915_READ(fdi_rx_imr_reg);
+ temp &= ~FDI_RX_SYMBOL_LOCK;
+ temp &= ~FDI_RX_BIT_LOCK;
+ I915_WRITE(fdi_rx_imr_reg, temp);
+ I915_READ(fdi_rx_imr_reg);
+ udelay(150);
+
/* enable CPU FDI TX and PCH FDI RX */
temp = I915_READ(fdi_tx_reg);
temp |= FDI_TX_ENABLE;
@@ -1571,16 +1750,7 @@ static void ironlake_fdi_link_train(struct drm_crtc *crtc)
I915_READ(fdi_rx_reg);
udelay(150);
- /* Train 1: umask FDI RX Interrupt symbol_lock and bit_lock bit
- for train result */
- temp = I915_READ(fdi_rx_imr_reg);
- temp &= ~FDI_RX_SYMBOL_LOCK;
- temp &= ~FDI_RX_BIT_LOCK;
- I915_WRITE(fdi_rx_imr_reg, temp);
- I915_READ(fdi_rx_imr_reg);
- udelay(150);
-
- for (;;) {
+ for (tries = 0; tries < 5; tries++) {
temp = I915_READ(fdi_rx_iir_reg);
DRM_DEBUG_KMS("FDI_RX_IIR 0x%x\n", temp);
@@ -1590,14 +1760,9 @@ static void ironlake_fdi_link_train(struct drm_crtc *crtc)
temp | FDI_RX_BIT_LOCK);
break;
}
-
- tries++;
-
- if (tries > 5) {
- DRM_DEBUG_KMS("FDI train 1 fail!\n");
- break;
- }
}
+ if (tries == 5)
+ DRM_DEBUG_KMS("FDI train 1 fail!\n");
/* Train 2 */
temp = I915_READ(fdi_tx_reg);
@@ -1613,7 +1778,7 @@ static void ironlake_fdi_link_train(struct drm_crtc *crtc)
tries = 0;
- for (;;) {
+ for (tries = 0; tries < 5; tries++) {
temp = I915_READ(fdi_rx_iir_reg);
DRM_DEBUG_KMS("FDI_RX_IIR 0x%x\n", temp);
@@ -1623,14 +1788,9 @@ static void ironlake_fdi_link_train(struct drm_crtc *crtc)
DRM_DEBUG_KMS("FDI train 2 done.\n");
break;
}
-
- tries++;
-
- if (tries > 5) {
- DRM_DEBUG_KMS("FDI train 2 fail!\n");
- break;
- }
}
+ if (tries == 5)
+ DRM_DEBUG_KMS("FDI train 2 fail!\n");
DRM_DEBUG_KMS("FDI train done\n");
}
@@ -1655,6 +1815,15 @@ static void gen6_fdi_link_train(struct drm_crtc *crtc)
int fdi_rx_imr_reg = (pipe == 0) ? FDI_RXA_IMR : FDI_RXB_IMR;
u32 temp, i;
+ /* Train 1: umask FDI RX Interrupt symbol_lock and bit_lock bit
+ for train result */
+ temp = I915_READ(fdi_rx_imr_reg);
+ temp &= ~FDI_RX_SYMBOL_LOCK;
+ temp &= ~FDI_RX_BIT_LOCK;
+ I915_WRITE(fdi_rx_imr_reg, temp);
+ I915_READ(fdi_rx_imr_reg);
+ udelay(150);
+
/* enable CPU FDI TX and PCH FDI RX */
temp = I915_READ(fdi_tx_reg);
temp |= FDI_TX_ENABLE;
@@ -1680,15 +1849,6 @@ static void gen6_fdi_link_train(struct drm_crtc *crtc)
I915_READ(fdi_rx_reg);
udelay(150);
- /* Train 1: umask FDI RX Interrupt symbol_lock and bit_lock bit
- for train result */
- temp = I915_READ(fdi_rx_imr_reg);
- temp &= ~FDI_RX_SYMBOL_LOCK;
- temp &= ~FDI_RX_BIT_LOCK;
- I915_WRITE(fdi_rx_imr_reg, temp);
- I915_READ(fdi_rx_imr_reg);
- udelay(150);
-
for (i = 0; i < 4; i++ ) {
temp = I915_READ(fdi_tx_reg);
temp &= ~FDI_LINK_TRAIN_VOL_EMP_MASK;
@@ -1843,7 +2003,8 @@ static void ironlake_crtc_dpms(struct drm_crtc *crtc, int mode)
}
/* Enable panel fitting for LVDS */
- if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) {
+ if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)
+ || HAS_eDP || intel_pch_has_edp(crtc)) {
temp = I915_READ(pf_ctl_reg);
I915_WRITE(pf_ctl_reg, temp | PF_ENABLE | PF_FILTER_MED_3x3);
@@ -1938,9 +2099,12 @@ static void ironlake_crtc_dpms(struct drm_crtc *crtc, int mode)
reg = I915_READ(trans_dp_ctl);
reg &= ~TRANS_DP_PORT_SEL_MASK;
reg = TRANS_DP_OUTPUT_ENABLE |
- TRANS_DP_ENH_FRAMING |
- TRANS_DP_VSYNC_ACTIVE_HIGH |
- TRANS_DP_HSYNC_ACTIVE_HIGH;
+ TRANS_DP_ENH_FRAMING;
+
+ if (crtc->mode.flags & DRM_MODE_FLAG_PHSYNC)
+ reg |= TRANS_DP_HSYNC_ACTIVE_HIGH;
+ if (crtc->mode.flags & DRM_MODE_FLAG_PVSYNC)
+ reg |= TRANS_DP_VSYNC_ACTIVE_HIGH;
switch (intel_trans_dp_port_sel(crtc)) {
case PCH_DP_B:
@@ -1980,6 +2144,8 @@ static void ironlake_crtc_dpms(struct drm_crtc *crtc, int mode)
intel_crtc_load_lut(crtc);
+ intel_update_fbc(crtc, &crtc->mode);
+
break;
case DRM_MODE_DPMS_OFF:
DRM_DEBUG_KMS("crtc %d dpms off\n", pipe);
@@ -1994,6 +2160,10 @@ static void ironlake_crtc_dpms(struct drm_crtc *crtc, int mode)
I915_READ(dspbase_reg);
}
+ if (dev_priv->cfb_plane == plane &&
+ dev_priv->display.disable_fbc)
+ dev_priv->display.disable_fbc(dev);
+
i915_disable_vga(dev);
/* disable cpu pipe, disable after all planes disabled */
@@ -2373,8 +2543,8 @@ static bool intel_crtc_mode_fixup(struct drm_crtc *crtc,
struct drm_device *dev = crtc->dev;
if (HAS_PCH_SPLIT(dev)) {
/* FDI link clock is fixed at 2.7G */
- if (mode->clock * 3 > 27000 * 4)
- return MODE_CLOCK_HIGH;
+ if (mode->clock * 3 > IRONLAKE_FDI_FREQ * 4)
+ return false;
}
return true;
}
@@ -2556,6 +2726,20 @@ static struct intel_watermark_params g4x_wm_info = {
2,
G4X_FIFO_LINE_SIZE,
};
+static struct intel_watermark_params g4x_cursor_wm_info = {
+ I965_CURSOR_FIFO,
+ I965_CURSOR_MAX_WM,
+ I965_CURSOR_DFT_WM,
+ 2,
+ G4X_FIFO_LINE_SIZE,
+};
+static struct intel_watermark_params i965_cursor_wm_info = {
+ I965_CURSOR_FIFO,
+ I965_CURSOR_MAX_WM,
+ I965_CURSOR_DFT_WM,
+ 2,
+ I915_FIFO_LINE_SIZE,
+};
static struct intel_watermark_params i945_wm_info = {
I945_FIFO_SIZE,
I915_MAX_WM,
@@ -2593,6 +2777,14 @@ static struct intel_watermark_params ironlake_display_wm_info = {
ILK_FIFO_LINE_SIZE
};
+static struct intel_watermark_params ironlake_cursor_wm_info = {
+ ILK_CURSOR_FIFO,
+ ILK_CURSOR_MAXWM,
+ ILK_CURSOR_DFTWM,
+ 2,
+ ILK_FIFO_LINE_SIZE
+};
+
static struct intel_watermark_params ironlake_display_srwm_info = {
ILK_DISPLAY_SR_FIFO,
ILK_DISPLAY_MAX_SRWM,
@@ -2642,7 +2834,7 @@ static unsigned long intel_calculate_wm(unsigned long clock_in_khz,
*/
entries_required = ((clock_in_khz / 1000) * pixel_size * latency_ns) /
1000;
- entries_required /= wm->cacheline_size;
+ entries_required = DIV_ROUND_UP(entries_required, wm->cacheline_size);
DRM_DEBUG_KMS("FIFO entries required for mode: %d\n", entries_required);
@@ -2653,8 +2845,14 @@ static unsigned long intel_calculate_wm(unsigned long clock_in_khz,
/* Don't promote wm_size to unsigned... */
if (wm_size > (long)wm->max_wm)
wm_size = wm->max_wm;
- if (wm_size <= 0)
+ if (wm_size <= 0) {
wm_size = wm->default_wm;
+ DRM_ERROR("Insufficient FIFO for plane, expect flickering:"
+ " entries required = %ld, available = %lu.\n",
+ entries_required + wm->guard_size,
+ wm->fifo_size);
+ }
+
return wm_size;
}
@@ -2763,11 +2961,9 @@ static int i9xx_get_fifo_size(struct drm_device *dev, int plane)
uint32_t dsparb = I915_READ(DSPARB);
int size;
- if (plane == 0)
- size = dsparb & 0x7f;
- else
- size = ((dsparb >> DSPARB_CSTART_SHIFT) & 0x7f) -
- (dsparb & 0x7f);
+ size = dsparb & 0x7f;
+ if (plane)
+ size = ((dsparb >> DSPARB_CSTART_SHIFT) & 0x7f) - size;
DRM_DEBUG_KMS("FIFO size - (0x%08x) %s: %d\n", dsparb,
plane ? "B" : "A", size);
@@ -2781,11 +2977,9 @@ static int i85x_get_fifo_size(struct drm_device *dev, int plane)
uint32_t dsparb = I915_READ(DSPARB);
int size;
- if (plane == 0)
- size = dsparb & 0x1ff;
- else
- size = ((dsparb >> DSPARB_BEND_SHIFT) & 0x1ff) -
- (dsparb & 0x1ff);
+ size = dsparb & 0x1ff;
+ if (plane)
+ size = ((dsparb >> DSPARB_BEND_SHIFT) & 0x1ff) - size;
size >>= 1; /* Convert to cachelines */
DRM_DEBUG_KMS("FIFO size - (0x%08x) %s: %d\n", dsparb,
@@ -2826,7 +3020,8 @@ static int i830_get_fifo_size(struct drm_device *dev, int plane)
}
static void pineview_update_wm(struct drm_device *dev, int planea_clock,
- int planeb_clock, int sr_hdisplay, int pixel_size)
+ int planeb_clock, int sr_hdisplay, int unused,
+ int pixel_size)
{
struct drm_i915_private *dev_priv = dev->dev_private;
u32 reg;
@@ -2891,7 +3086,8 @@ static void pineview_update_wm(struct drm_device *dev, int planea_clock,
}
static void g4x_update_wm(struct drm_device *dev, int planea_clock,
- int planeb_clock, int sr_hdisplay, int pixel_size)
+ int planeb_clock, int sr_hdisplay, int sr_htotal,
+ int pixel_size)
{
struct drm_i915_private *dev_priv = dev->dev_private;
int total_size, cacheline_size;
@@ -2915,12 +3111,12 @@ static void g4x_update_wm(struct drm_device *dev, int planea_clock,
*/
entries_required = ((planea_clock / 1000) * pixel_size * latency_ns) /
1000;
- entries_required /= G4X_FIFO_LINE_SIZE;
+ entries_required = DIV_ROUND_UP(entries_required, G4X_FIFO_LINE_SIZE);
planea_wm = entries_required + planea_params.guard_size;
entries_required = ((planeb_clock / 1000) * pixel_size * latency_ns) /
1000;
- entries_required /= G4X_FIFO_LINE_SIZE;
+ entries_required = DIV_ROUND_UP(entries_required, G4X_FIFO_LINE_SIZE);
planeb_wm = entries_required + planeb_params.guard_size;
cursora_wm = cursorb_wm = 16;
@@ -2934,13 +3130,24 @@ static void g4x_update_wm(struct drm_device *dev, int planea_clock,
static const int sr_latency_ns = 12000;
sr_clock = planea_clock ? planea_clock : planeb_clock;
- line_time_us = ((sr_hdisplay * 1000) / sr_clock);
+ line_time_us = ((sr_htotal * 1000) / sr_clock);
/* Use ns/us then divide to preserve precision */
- sr_entries = (((sr_latency_ns / line_time_us) + 1) *
- pixel_size * sr_hdisplay) / 1000;
- sr_entries = roundup(sr_entries / cacheline_size, 1);
- DRM_DEBUG("self-refresh entries: %d\n", sr_entries);
+ sr_entries = (((sr_latency_ns / line_time_us) + 1000) / 1000) *
+ pixel_size * sr_hdisplay;
+ sr_entries = DIV_ROUND_UP(sr_entries, cacheline_size);
+
+ entries_required = (((sr_latency_ns / line_time_us) +
+ 1000) / 1000) * pixel_size * 64;
+ entries_required = DIV_ROUND_UP(entries_required,
+ g4x_cursor_wm_info.cacheline_size);
+ cursor_sr = entries_required + g4x_cursor_wm_info.guard_size;
+
+ if (cursor_sr > g4x_cursor_wm_info.max_wm)
+ cursor_sr = g4x_cursor_wm_info.max_wm;
+ DRM_DEBUG_KMS("self-refresh watermark: display plane %d "
+ "cursor %d\n", sr_entries, cursor_sr);
+
I915_WRITE(FW_BLC_SELF, FW_BLC_SELF_EN);
} else {
/* Turn off self refresh if both pipes are enabled */
@@ -2965,11 +3172,13 @@ static void g4x_update_wm(struct drm_device *dev, int planea_clock,
}
static void i965_update_wm(struct drm_device *dev, int planea_clock,
- int planeb_clock, int sr_hdisplay, int pixel_size)
+ int planeb_clock, int sr_hdisplay, int sr_htotal,
+ int pixel_size)
{
struct drm_i915_private *dev_priv = dev->dev_private;
unsigned long line_time_us;
int sr_clock, sr_entries, srwm = 1;
+ int cursor_sr = 16;
/* Calc sr entries for one plane configs */
if (sr_hdisplay && (!planea_clock || !planeb_clock)) {
@@ -2977,17 +3186,31 @@ static void i965_update_wm(struct drm_device *dev, int planea_clock,
static const int sr_latency_ns = 12000;
sr_clock = planea_clock ? planea_clock : planeb_clock;
- line_time_us = ((sr_hdisplay * 1000) / sr_clock);
+ line_time_us = ((sr_htotal * 1000) / sr_clock);
/* Use ns/us then divide to preserve precision */
- sr_entries = (((sr_latency_ns / line_time_us) + 1) *
- pixel_size * sr_hdisplay) / 1000;
- sr_entries = roundup(sr_entries / I915_FIFO_LINE_SIZE, 1);
+ sr_entries = (((sr_latency_ns / line_time_us) + 1000) / 1000) *
+ pixel_size * sr_hdisplay;
+ sr_entries = DIV_ROUND_UP(sr_entries, I915_FIFO_LINE_SIZE);
DRM_DEBUG("self-refresh entries: %d\n", sr_entries);
- srwm = I945_FIFO_SIZE - sr_entries;
+ srwm = I965_FIFO_SIZE - sr_entries;
if (srwm < 0)
srwm = 1;
- srwm &= 0x3f;
+ srwm &= 0x1ff;
+
+ sr_entries = (((sr_latency_ns / line_time_us) + 1000) / 1000) *
+ pixel_size * 64;
+ sr_entries = DIV_ROUND_UP(sr_entries,
+ i965_cursor_wm_info.cacheline_size);
+ cursor_sr = i965_cursor_wm_info.fifo_size -
+ (sr_entries + i965_cursor_wm_info.guard_size);
+
+ if (cursor_sr > i965_cursor_wm_info.max_wm)
+ cursor_sr = i965_cursor_wm_info.max_wm;
+
+ DRM_DEBUG_KMS("self-refresh watermark: display plane %d "
+ "cursor %d\n", srwm, cursor_sr);
+
if (IS_I965GM(dev))
I915_WRITE(FW_BLC_SELF, FW_BLC_SELF_EN);
} else {
@@ -3004,10 +3227,13 @@ static void i965_update_wm(struct drm_device *dev, int planea_clock,
I915_WRITE(DSPFW1, (srwm << DSPFW_SR_SHIFT) | (8 << 16) | (8 << 8) |
(8 << 0));
I915_WRITE(DSPFW2, (8 << 8) | (8 << 0));
+ /* update cursor SR watermark */
+ I915_WRITE(DSPFW3, (cursor_sr << DSPFW_CURSOR_SR_SHIFT));
}
static void i9xx_update_wm(struct drm_device *dev, int planea_clock,
- int planeb_clock, int sr_hdisplay, int pixel_size)
+ int planeb_clock, int sr_hdisplay, int sr_htotal,
+ int pixel_size)
{
struct drm_i915_private *dev_priv = dev->dev_private;
uint32_t fwater_lo;
@@ -3052,12 +3278,12 @@ static void i9xx_update_wm(struct drm_device *dev, int planea_clock,
static const int sr_latency_ns = 6000;
sr_clock = planea_clock ? planea_clock : planeb_clock;
- line_time_us = ((sr_hdisplay * 1000) / sr_clock);
+ line_time_us = ((sr_htotal * 1000) / sr_clock);
/* Use ns/us then divide to preserve precision */
- sr_entries = (((sr_latency_ns / line_time_us) + 1) *
- pixel_size * sr_hdisplay) / 1000;
- sr_entries = roundup(sr_entries / cacheline_size, 1);
+ sr_entries = (((sr_latency_ns / line_time_us) + 1000) / 1000) *
+ pixel_size * sr_hdisplay;
+ sr_entries = DIV_ROUND_UP(sr_entries, cacheline_size);
DRM_DEBUG_KMS("self-refresh entries: %d\n", sr_entries);
srwm = total_size - sr_entries;
if (srwm < 0)
@@ -3095,7 +3321,7 @@ static void i9xx_update_wm(struct drm_device *dev, int planea_clock,
}
static void i830_update_wm(struct drm_device *dev, int planea_clock, int unused,
- int unused2, int pixel_size)
+ int unused2, int unused3, int pixel_size)
{
struct drm_i915_private *dev_priv = dev->dev_private;
uint32_t fwater_lo = I915_READ(FW_BLC) & ~0xfff;
@@ -3113,9 +3339,11 @@ static void i830_update_wm(struct drm_device *dev, int planea_clock, int unused,
}
#define ILK_LP0_PLANE_LATENCY 700
+#define ILK_LP0_CURSOR_LATENCY 1300
static void ironlake_update_wm(struct drm_device *dev, int planea_clock,
- int planeb_clock, int sr_hdisplay, int pixel_size)
+ int planeb_clock, int sr_hdisplay, int sr_htotal,
+ int pixel_size)
{
struct drm_i915_private *dev_priv = dev->dev_private;
int planea_wm, planeb_wm, cursora_wm, cursorb_wm;
@@ -3123,20 +3351,48 @@ static void ironlake_update_wm(struct drm_device *dev, int planea_clock,
unsigned long line_time_us;
int sr_clock, entries_required;
u32 reg_value;
+ int line_count;
+ int planea_htotal = 0, planeb_htotal = 0;
+ struct drm_crtc *crtc;
+ struct intel_crtc *intel_crtc;
+
+ /* Need htotal for all active display plane */
+ list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+ intel_crtc = to_intel_crtc(crtc);
+ if (crtc->enabled) {
+ if (intel_crtc->plane == 0)
+ planea_htotal = crtc->mode.htotal;
+ else
+ planeb_htotal = crtc->mode.htotal;
+ }
+ }
/* Calculate and update the watermark for plane A */
if (planea_clock) {
entries_required = ((planea_clock / 1000) * pixel_size *
ILK_LP0_PLANE_LATENCY) / 1000;
entries_required = DIV_ROUND_UP(entries_required,
- ironlake_display_wm_info.cacheline_size);
+ ironlake_display_wm_info.cacheline_size);
planea_wm = entries_required +
ironlake_display_wm_info.guard_size;
if (planea_wm > (int)ironlake_display_wm_info.max_wm)
planea_wm = ironlake_display_wm_info.max_wm;
- cursora_wm = 16;
+ /* Use the large buffer method to calculate cursor watermark */
+ line_time_us = (planea_htotal * 1000) / planea_clock;
+
+ /* Use ns/us then divide to preserve precision */
+ line_count = (ILK_LP0_CURSOR_LATENCY / line_time_us + 1000) / 1000;
+
+ /* calculate the cursor watermark for cursor A */
+ entries_required = line_count * 64 * pixel_size;
+ entries_required = DIV_ROUND_UP(entries_required,
+ ironlake_cursor_wm_info.cacheline_size);
+ cursora_wm = entries_required + ironlake_cursor_wm_info.guard_size;
+ if (cursora_wm > ironlake_cursor_wm_info.max_wm)
+ cursora_wm = ironlake_cursor_wm_info.max_wm;
+
reg_value = I915_READ(WM0_PIPEA_ILK);
reg_value &= ~(WM0_PIPE_PLANE_MASK | WM0_PIPE_CURSOR_MASK);
reg_value |= (planea_wm << WM0_PIPE_PLANE_SHIFT) |
@@ -3150,14 +3406,27 @@ static void ironlake_update_wm(struct drm_device *dev, int planea_clock,
entries_required = ((planeb_clock / 1000) * pixel_size *
ILK_LP0_PLANE_LATENCY) / 1000;
entries_required = DIV_ROUND_UP(entries_required,
- ironlake_display_wm_info.cacheline_size);
+ ironlake_display_wm_info.cacheline_size);
planeb_wm = entries_required +
ironlake_display_wm_info.guard_size;
if (planeb_wm > (int)ironlake_display_wm_info.max_wm)
planeb_wm = ironlake_display_wm_info.max_wm;
- cursorb_wm = 16;
+ /* Use the large buffer method to calculate cursor watermark */
+ line_time_us = (planeb_htotal * 1000) / planeb_clock;
+
+ /* Use ns/us then divide to preserve precision */
+ line_count = (ILK_LP0_CURSOR_LATENCY / line_time_us + 1000) / 1000;
+
+ /* calculate the cursor watermark for cursor B */
+ entries_required = line_count * 64 * pixel_size;
+ entries_required = DIV_ROUND_UP(entries_required,
+ ironlake_cursor_wm_info.cacheline_size);
+ cursorb_wm = entries_required + ironlake_cursor_wm_info.guard_size;
+ if (cursorb_wm > ironlake_cursor_wm_info.max_wm)
+ cursorb_wm = ironlake_cursor_wm_info.max_wm;
+
reg_value = I915_READ(WM0_PIPEB_ILK);
reg_value &= ~(WM0_PIPE_PLANE_MASK | WM0_PIPE_CURSOR_MASK);
reg_value |= (planeb_wm << WM0_PIPE_PLANE_SHIFT) |
@@ -3172,12 +3441,12 @@ static void ironlake_update_wm(struct drm_device *dev, int planea_clock,
* display plane is used.
*/
if (!planea_clock || !planeb_clock) {
- int line_count;
+
/* Read the self-refresh latency. The unit is 0.5us */
int ilk_sr_latency = I915_READ(MLTR_ILK) & ILK_SRLT_MASK;
sr_clock = planea_clock ? planea_clock : planeb_clock;
- line_time_us = ((sr_hdisplay * 1000) / sr_clock);
+ line_time_us = ((sr_htotal * 1000) / sr_clock);
/* Use ns/us then divide to preserve precision */
line_count = ((ilk_sr_latency * 500) / line_time_us + 1000)
@@ -3186,14 +3455,14 @@ static void ironlake_update_wm(struct drm_device *dev, int planea_clock,
/* calculate the self-refresh watermark for display plane */
entries_required = line_count * sr_hdisplay * pixel_size;
entries_required = DIV_ROUND_UP(entries_required,
- ironlake_display_srwm_info.cacheline_size);
+ ironlake_display_srwm_info.cacheline_size);
sr_wm = entries_required +
ironlake_display_srwm_info.guard_size;
/* calculate the self-refresh watermark for display cursor */
entries_required = line_count * pixel_size * 64;
entries_required = DIV_ROUND_UP(entries_required,
- ironlake_cursor_srwm_info.cacheline_size);
+ ironlake_cursor_srwm_info.cacheline_size);
cursor_wm = entries_required +
ironlake_cursor_srwm_info.guard_size;
@@ -3237,6 +3506,7 @@ static void ironlake_update_wm(struct drm_device *dev, int planea_clock,
* bytes per pixel
* where
* line time = htotal / dotclock
+ * surface width = hdisplay for normal plane and 64 for cursor
* and latency is assumed to be high, as above.
*
* The final value programmed to the register should always be rounded up,
@@ -3253,6 +3523,7 @@ static void intel_update_watermarks(struct drm_device *dev)
int sr_hdisplay = 0;
unsigned long planea_clock = 0, planeb_clock = 0, sr_clock = 0;
int enabled = 0, pixel_size = 0;
+ int sr_htotal = 0;
if (!dev_priv->display.update_wm)
return;
@@ -3273,6 +3544,7 @@ static void intel_update_watermarks(struct drm_device *dev)
}
sr_hdisplay = crtc->mode.hdisplay;
sr_clock = crtc->mode.clock;
+ sr_htotal = crtc->mode.htotal;
if (crtc->fb)
pixel_size = crtc->fb->bits_per_pixel / 8;
else
@@ -3284,7 +3556,7 @@ static void intel_update_watermarks(struct drm_device *dev)
return;
dev_priv->display.update_wm(dev, planea_clock, planeb_clock,
- sr_hdisplay, pixel_size);
+ sr_hdisplay, sr_htotal, pixel_size);
}
static int intel_crtc_mode_set(struct drm_crtc *crtc,
@@ -3403,6 +3675,9 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
return -EINVAL;
}
+ /* Ensure that the cursor is valid for the new mode before changing... */
+ intel_crtc_update_cursor(crtc);
+
if (is_lvds && dev_priv->lvds_downclock_avail) {
has_reduced_clock = limit->find_pll(limit, crtc,
dev_priv->lvds_downclock,
@@ -3469,7 +3744,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
temp |= PIPE_8BPC;
else
temp |= PIPE_6BPC;
- } else if (is_edp) {
+ } else if (is_edp || (is_dp && intel_pch_has_edp(crtc))) {
switch (dev_priv->edp_bpp/3) {
case 8:
temp |= PIPE_8BPC;
@@ -3712,6 +3987,11 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
udelay(150);
}
+ if (HAS_PCH_SPLIT(dev)) {
+ pipeconf &= ~PIPE_ENABLE_DITHER;
+ pipeconf &= ~PIPE_DITHER_TYPE_MASK;
+ }
+
/* The LVDS pin pair needs to be on before the DPLLs are enabled.
* This is an exception to the general rule that mode_set doesn't turn
* things on.
@@ -3754,16 +4034,13 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
if (dev_priv->lvds_dither) {
if (HAS_PCH_SPLIT(dev)) {
pipeconf |= PIPE_ENABLE_DITHER;
- pipeconf &= ~PIPE_DITHER_TYPE_MASK;
pipeconf |= PIPE_DITHER_TYPE_ST01;
} else
lvds |= LVDS_ENABLE_DITHER;
} else {
- if (HAS_PCH_SPLIT(dev)) {
- pipeconf &= ~PIPE_ENABLE_DITHER;
- pipeconf &= ~PIPE_DITHER_TYPE_MASK;
- } else
+ if (!HAS_PCH_SPLIT(dev)) {
lvds &= ~LVDS_ENABLE_DITHER;
+ }
}
}
I915_WRITE(lvds_reg, lvds);
@@ -3939,6 +4216,85 @@ void intel_crtc_load_lut(struct drm_crtc *crtc)
}
}
+/* If no-part of the cursor is visible on the framebuffer, then the GPU may hang... */
+static void intel_crtc_update_cursor(struct drm_crtc *crtc)
+{
+ struct drm_device *dev = crtc->dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+ int pipe = intel_crtc->pipe;
+ int x = intel_crtc->cursor_x;
+ int y = intel_crtc->cursor_y;
+ uint32_t base, pos;
+ bool visible;
+
+ pos = 0;
+
+ if (crtc->fb) {
+ base = intel_crtc->cursor_addr;
+ if (x > (int) crtc->fb->width)
+ base = 0;
+
+ if (y > (int) crtc->fb->height)
+ base = 0;
+ } else
+ base = 0;
+
+ if (x < 0) {
+ if (x + intel_crtc->cursor_width < 0)
+ base = 0;
+
+ pos |= CURSOR_POS_SIGN << CURSOR_X_SHIFT;
+ x = -x;
+ }
+ pos |= x << CURSOR_X_SHIFT;
+
+ if (y < 0) {
+ if (y + intel_crtc->cursor_height < 0)
+ base = 0;
+
+ pos |= CURSOR_POS_SIGN << CURSOR_Y_SHIFT;
+ y = -y;
+ }
+ pos |= y << CURSOR_Y_SHIFT;
+
+ visible = base != 0;
+ if (!visible && !intel_crtc->cursor_visble)
+ return;
+
+ I915_WRITE(pipe == 0 ? CURAPOS : CURBPOS, pos);
+ if (intel_crtc->cursor_visble != visible) {
+ uint32_t cntl = I915_READ(pipe == 0 ? CURACNTR : CURBCNTR);
+ if (base) {
+ /* Hooray for CUR*CNTR differences */
+ if (IS_MOBILE(dev) || IS_I9XX(dev)) {
+ cntl &= ~(CURSOR_MODE | MCURSOR_PIPE_SELECT);
+ cntl |= CURSOR_MODE_64_ARGB_AX | MCURSOR_GAMMA_ENABLE;
+ cntl |= pipe << 28; /* Connect to correct pipe */
+ } else {
+ cntl &= ~(CURSOR_FORMAT_MASK);
+ cntl |= CURSOR_ENABLE;
+ cntl |= CURSOR_FORMAT_ARGB | CURSOR_GAMMA_ENABLE;
+ }
+ } else {
+ if (IS_MOBILE(dev) || IS_I9XX(dev)) {
+ cntl &= ~(CURSOR_MODE | MCURSOR_GAMMA_ENABLE);
+ cntl |= CURSOR_MODE_DISABLE;
+ } else {
+ cntl &= ~(CURSOR_ENABLE | CURSOR_GAMMA_ENABLE);
+ }
+ }
+ I915_WRITE(pipe == 0 ? CURACNTR : CURBCNTR, cntl);
+
+ intel_crtc->cursor_visble = visible;
+ }
+ /* and commit changes on next vblank */
+ I915_WRITE(pipe == 0 ? CURABASE : CURBBASE, base);
+
+ if (visible)
+ intel_mark_busy(dev, to_intel_framebuffer(crtc->fb)->obj);
+}
+
static int intel_crtc_cursor_set(struct drm_crtc *crtc,
struct drm_file *file_priv,
uint32_t handle,
@@ -3949,11 +4305,7 @@ static int intel_crtc_cursor_set(struct drm_crtc *crtc,
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
struct drm_gem_object *bo;
struct drm_i915_gem_object *obj_priv;
- int pipe = intel_crtc->pipe;
- uint32_t control = (pipe == 0) ? CURACNTR : CURBCNTR;
- uint32_t base = (pipe == 0) ? CURABASE : CURBBASE;
- uint32_t temp = I915_READ(control);
- size_t addr;
+ uint32_t addr;
int ret;
DRM_DEBUG_KMS("\n");
@@ -3961,12 +4313,6 @@ static int intel_crtc_cursor_set(struct drm_crtc *crtc,
/* if we want to turn off the cursor ignore width and height */
if (!handle) {
DRM_DEBUG_KMS("cursor off\n");
- if (IS_MOBILE(dev) || IS_I9XX(dev)) {
- temp &= ~(CURSOR_MODE | MCURSOR_GAMMA_ENABLE);
- temp |= CURSOR_MODE_DISABLE;
- } else {
- temp &= ~(CURSOR_ENABLE | CURSOR_GAMMA_ENABLE);
- }
addr = 0;
bo = NULL;
mutex_lock(&dev->struct_mutex);
@@ -4008,7 +4354,8 @@ static int intel_crtc_cursor_set(struct drm_crtc *crtc,
addr = obj_priv->gtt_offset;
} else {
- ret = i915_gem_attach_phys_object(dev, bo, (pipe == 0) ? I915_GEM_PHYS_CURSOR_0 : I915_GEM_PHYS_CURSOR_1);
+ ret = i915_gem_attach_phys_object(dev, bo,
+ (intel_crtc->pipe == 0) ? I915_GEM_PHYS_CURSOR_0 : I915_GEM_PHYS_CURSOR_1);
if (ret) {
DRM_ERROR("failed to attach phys object\n");
goto fail_locked;
@@ -4019,21 +4366,7 @@ static int intel_crtc_cursor_set(struct drm_crtc *crtc,
if (!IS_I9XX(dev))
I915_WRITE(CURSIZE, (height << 12) | width);
- /* Hooray for CUR*CNTR differences */
- if (IS_MOBILE(dev) || IS_I9XX(dev)) {
- temp &= ~(CURSOR_MODE | MCURSOR_PIPE_SELECT);
- temp |= CURSOR_MODE_64_ARGB_AX | MCURSOR_GAMMA_ENABLE;
- temp |= (pipe << 28); /* Connect to correct pipe */
- } else {
- temp &= ~(CURSOR_FORMAT_MASK);
- temp |= CURSOR_ENABLE;
- temp |= CURSOR_FORMAT_ARGB | CURSOR_GAMMA_ENABLE;
- }
-
finish:
- I915_WRITE(control, temp);
- I915_WRITE(base, addr);
-
if (intel_crtc->cursor_bo) {
if (dev_priv->info->cursor_needs_physical) {
if (intel_crtc->cursor_bo != bo)
@@ -4047,6 +4380,10 @@ static int intel_crtc_cursor_set(struct drm_crtc *crtc,
intel_crtc->cursor_addr = addr;
intel_crtc->cursor_bo = bo;
+ intel_crtc->cursor_width = width;
+ intel_crtc->cursor_height = height;
+
+ intel_crtc_update_cursor(crtc);
return 0;
fail_unpin:
@@ -4060,34 +4397,12 @@ fail:
static int intel_crtc_cursor_move(struct drm_crtc *crtc, int x, int y)
{
- struct drm_device *dev = crtc->dev;
- struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
- struct intel_framebuffer *intel_fb;
- int pipe = intel_crtc->pipe;
- uint32_t temp = 0;
- uint32_t adder;
-
- if (crtc->fb) {
- intel_fb = to_intel_framebuffer(crtc->fb);
- intel_mark_busy(dev, intel_fb->obj);
- }
-
- if (x < 0) {
- temp |= CURSOR_POS_SIGN << CURSOR_X_SHIFT;
- x = -x;
- }
- if (y < 0) {
- temp |= CURSOR_POS_SIGN << CURSOR_Y_SHIFT;
- y = -y;
- }
- temp |= x << CURSOR_X_SHIFT;
- temp |= y << CURSOR_Y_SHIFT;
+ intel_crtc->cursor_x = x;
+ intel_crtc->cursor_y = y;
- adder = intel_crtc->cursor_addr;
- I915_WRITE((pipe == 0) ? CURAPOS : CURBPOS, temp);
- I915_WRITE((pipe == 0) ? CURABASE : CURBBASE, adder);
+ intel_crtc_update_cursor(crtc);
return 0;
}
@@ -4671,6 +4986,8 @@ static void do_intel_finish_page_flip(struct drm_device *dev,
atomic_dec_and_test(&obj_priv->pending_flip))
DRM_WAKEUP(&dev_priv->pending_flip_queue);
schedule_work(&work->work);
+
+ trace_i915_flip_complete(intel_crtc->plane, work->pending_flip_obj);
}
void intel_finish_page_flip(struct drm_device *dev, int pipe)
@@ -4748,27 +5065,22 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
mutex_lock(&dev->struct_mutex);
ret = intel_pin_and_fence_fb_obj(dev, obj);
- if (ret != 0) {
- mutex_unlock(&dev->struct_mutex);
-
- spin_lock_irqsave(&dev->event_lock, flags);
- intel_crtc->unpin_work = NULL;
- spin_unlock_irqrestore(&dev->event_lock, flags);
-
- kfree(work);
-
- DRM_DEBUG_DRIVER("flip queue: %p pin & fence failed\n",
- to_intel_bo(obj));
- return ret;
- }
+ if (ret)
+ goto cleanup_work;
/* Reference the objects for the scheduled work. */
drm_gem_object_reference(work->old_fb_obj);
drm_gem_object_reference(obj);
crtc->fb = fb;
- i915_gem_object_flush_write_domain(obj);
- drm_vblank_get(dev, intel_crtc->pipe);
+ ret = i915_gem_object_flush_write_domain(obj);
+ if (ret)
+ goto cleanup_objs;
+
+ ret = drm_vblank_get(dev, intel_crtc->pipe);
+ if (ret)
+ goto cleanup_objs;
+
obj_priv = to_intel_bo(obj);
atomic_inc(&obj_priv->pending_flip);
work->pending_flip_obj = obj;
@@ -4806,7 +5118,23 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
mutex_unlock(&dev->struct_mutex);
+ trace_i915_flip_request(intel_crtc->plane, obj);
+
return 0;
+
+cleanup_objs:
+ drm_gem_object_unreference(work->old_fb_obj);
+ drm_gem_object_unreference(obj);
+cleanup_work:
+ mutex_unlock(&dev->struct_mutex);
+
+ spin_lock_irqsave(&dev->event_lock, flags);
+ intel_crtc->unpin_work = NULL;
+ spin_unlock_irqrestore(&dev->event_lock, flags);
+
+ kfree(work);
+
+ return ret;
}
static const struct drm_crtc_helper_funcs intel_helper_funcs = {
@@ -4814,6 +5142,7 @@ static const struct drm_crtc_helper_funcs intel_helper_funcs = {
.mode_fixup = intel_crtc_mode_fixup,
.mode_set = intel_crtc_mode_set,
.mode_set_base = intel_pipe_set_base,
+ .mode_set_base_atomic = intel_pipe_set_base_atomic,
.prepare = intel_crtc_prepare,
.commit = intel_crtc_commit,
.load_lut = intel_crtc_load_lut,
@@ -4932,19 +5261,26 @@ static void intel_setup_outputs(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
struct drm_encoder *encoder;
+ bool dpd_is_edp = false;
- intel_crt_init(dev);
-
- /* Set up integrated LVDS */
if (IS_MOBILE(dev) && !IS_I830(dev))
intel_lvds_init(dev);
if (HAS_PCH_SPLIT(dev)) {
- int found;
+ dpd_is_edp = intel_dpd_is_edp(dev);
if (IS_MOBILE(dev) && (I915_READ(DP_A) & DP_DETECTED))
intel_dp_init(dev, DP_A);
+ if (dpd_is_edp && (I915_READ(PCH_DP_D) & DP_DETECTED))
+ intel_dp_init(dev, PCH_DP_D);
+ }
+
+ intel_crt_init(dev);
+
+ if (HAS_PCH_SPLIT(dev)) {
+ int found;
+
if (I915_READ(HDMIB) & PORT_DETECTED) {
/* PCH SDVOB multiplex with HDMIB */
found = intel_sdvo_init(dev, PCH_SDVOB);
@@ -4963,7 +5299,7 @@ static void intel_setup_outputs(struct drm_device *dev)
if (I915_READ(PCH_DP_C) & DP_DETECTED)
intel_dp_init(dev, PCH_DP_C);
- if (I915_READ(PCH_DP_D) & DP_DETECTED)
+ if (!dpd_is_edp && (I915_READ(PCH_DP_D) & DP_DETECTED))
intel_dp_init(dev, PCH_DP_D);
} else if (SUPPORTS_DIGITAL_OUTPUTS(dev)) {
@@ -5372,6 +5708,26 @@ void intel_init_clock_gating(struct drm_device *dev)
(I915_READ(DISP_ARB_CTL) |
DISP_FBC_WM_DIS));
}
+ /*
+ * Based on the document from hardware guys the following bits
+ * should be set unconditionally in order to enable FBC.
+ * The bit 22 of 0x42000
+ * The bit 22 of 0x42004
+ * The bit 7,8,9 of 0x42020.
+ */
+ if (IS_IRONLAKE_M(dev)) {
+ I915_WRITE(ILK_DISPLAY_CHICKEN1,
+ I915_READ(ILK_DISPLAY_CHICKEN1) |
+ ILK_FBCQ_DIS);
+ I915_WRITE(ILK_DISPLAY_CHICKEN2,
+ I915_READ(ILK_DISPLAY_CHICKEN2) |
+ ILK_DPARB_GATE);
+ I915_WRITE(ILK_DSPCLK_GATE,
+ I915_READ(ILK_DSPCLK_GATE) |
+ ILK_DPFC_DIS1 |
+ ILK_DPFC_DIS2 |
+ ILK_CLK_FBC);
+ }
return;
} else if (IS_G4X(dev)) {
uint32_t dspclk_gate;
@@ -5450,7 +5806,11 @@ static void intel_init_display(struct drm_device *dev)
dev_priv->display.dpms = i9xx_crtc_dpms;
if (I915_HAS_FBC(dev)) {
- if (IS_GM45(dev)) {
+ if (IS_IRONLAKE_M(dev)) {
+ dev_priv->display.fbc_enabled = ironlake_fbc_enabled;
+ dev_priv->display.enable_fbc = ironlake_enable_fbc;
+ dev_priv->display.disable_fbc = ironlake_disable_fbc;
+ } else if (IS_GM45(dev)) {
dev_priv->display.fbc_enabled = g4x_fbc_enabled;
dev_priv->display.enable_fbc = g4x_enable_fbc;
dev_priv->display.disable_fbc = g4x_disable_fbc;
diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
index 5dde80f9e65..40be1fa65be 100644
--- a/drivers/gpu/drm/i915/intel_dp.c
+++ b/drivers/gpu/drm/i915/intel_dp.c
@@ -43,6 +43,7 @@
#define DP_LINK_CONFIGURATION_SIZE 9
#define IS_eDP(i) ((i)->type == INTEL_OUTPUT_EDP)
+#define IS_PCH_eDP(dp_priv) ((dp_priv)->is_pch_edp)
struct intel_dp_priv {
uint32_t output_reg;
@@ -56,6 +57,7 @@ struct intel_dp_priv {
struct intel_encoder *intel_encoder;
struct i2c_adapter adapter;
struct i2c_algo_dp_aux_data algo;
+ bool is_pch_edp;
};
static void
@@ -128,8 +130,9 @@ intel_dp_link_required(struct drm_device *dev,
struct intel_encoder *intel_encoder, int pixel_clock)
{
struct drm_i915_private *dev_priv = dev->dev_private;
+ struct intel_dp_priv *dp_priv = intel_encoder->dev_priv;
- if (IS_eDP(intel_encoder))
+ if (IS_eDP(intel_encoder) || IS_PCH_eDP(dp_priv))
return (pixel_clock * dev_priv->edp_bpp) / 8;
else
return pixel_clock * 3;
@@ -147,9 +150,21 @@ intel_dp_mode_valid(struct drm_connector *connector,
{
struct drm_encoder *encoder = intel_attached_encoder(connector);
struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder);
+ struct intel_dp_priv *dp_priv = intel_encoder->dev_priv;
+ struct drm_device *dev = connector->dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
int max_link_clock = intel_dp_link_clock(intel_dp_max_link_bw(intel_encoder));
int max_lanes = intel_dp_max_lane_count(intel_encoder);
+ if ((IS_eDP(intel_encoder) || IS_PCH_eDP(dp_priv)) &&
+ dev_priv->panel_fixed_mode) {
+ if (mode->hdisplay > dev_priv->panel_fixed_mode->hdisplay)
+ return MODE_PANEL;
+
+ if (mode->vdisplay > dev_priv->panel_fixed_mode->vdisplay)
+ return MODE_PANEL;
+ }
+
/* only refuse the mode on non eDP since we have seen some wierd eDP panels
which are outside spec tolerances but somehow work by magic */
if (!IS_eDP(intel_encoder) &&
@@ -508,11 +523,37 @@ intel_dp_mode_fixup(struct drm_encoder *encoder, struct drm_display_mode *mode,
{
struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder);
struct intel_dp_priv *dp_priv = intel_encoder->dev_priv;
+ struct drm_device *dev = encoder->dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
int lane_count, clock;
int max_lane_count = intel_dp_max_lane_count(intel_encoder);
int max_clock = intel_dp_max_link_bw(intel_encoder) == DP_LINK_BW_2_7 ? 1 : 0;
static int bws[2] = { DP_LINK_BW_1_62, DP_LINK_BW_2_7 };
+ if ((IS_eDP(intel_encoder) || IS_PCH_eDP(dp_priv)) &&
+ dev_priv->panel_fixed_mode) {
+ struct drm_display_mode *fixed_mode = dev_priv->panel_fixed_mode;
+
+ adjusted_mode->hdisplay = fixed_mode->hdisplay;
+ adjusted_mode->hsync_start = fixed_mode->hsync_start;
+ adjusted_mode->hsync_end = fixed_mode->hsync_end;
+ adjusted_mode->htotal = fixed_mode->htotal;
+
+ adjusted_mode->vdisplay = fixed_mode->vdisplay;
+ adjusted_mode->vsync_start = fixed_mode->vsync_start;
+ adjusted_mode->vsync_end = fixed_mode->vsync_end;
+ adjusted_mode->vtotal = fixed_mode->vtotal;
+
+ adjusted_mode->clock = fixed_mode->clock;
+ drm_mode_set_crtcinfo(adjusted_mode, CRTC_INTERLACE_HALVE_V);
+
+ /*
+ * the mode->clock is used to calculate the Data&Link M/N
+ * of the pipe. For the eDP the fixed clock should be used.
+ */
+ mode->clock = dev_priv->panel_fixed_mode->clock;
+ }
+
for (lane_count = 1; lane_count <= max_lane_count; lane_count <<= 1) {
for (clock = 0; clock <= max_clock; clock++) {
int link_avail = intel_dp_max_data_rate(intel_dp_link_clock(bws[clock]), lane_count);
@@ -531,7 +572,7 @@ intel_dp_mode_fixup(struct drm_encoder *encoder, struct drm_display_mode *mode,
}
}
- if (IS_eDP(intel_encoder)) {
+ if (IS_eDP(intel_encoder) || IS_PCH_eDP(dp_priv)) {
/* okay we failed just pick the highest */
dp_priv->lane_count = max_lane_count;
dp_priv->link_bw = bws[max_clock];
@@ -563,14 +604,14 @@ intel_reduce_ratio(uint32_t *num, uint32_t *den)
}
static void
-intel_dp_compute_m_n(int bytes_per_pixel,
+intel_dp_compute_m_n(int bpp,
int nlanes,
int pixel_clock,
int link_clock,
struct intel_dp_m_n *m_n)
{
m_n->tu = 64;
- m_n->gmch_m = pixel_clock * bytes_per_pixel;
+ m_n->gmch_m = (pixel_clock * bpp) >> 3;
m_n->gmch_n = link_clock * nlanes;
intel_reduce_ratio(&m_n->gmch_m, &m_n->gmch_n);
m_n->link_m = pixel_clock;
@@ -578,6 +619,28 @@ intel_dp_compute_m_n(int bytes_per_pixel,
intel_reduce_ratio(&m_n->link_m, &m_n->link_n);
}
+bool intel_pch_has_edp(struct drm_crtc *crtc)
+{
+ struct drm_device *dev = crtc->dev;
+ struct drm_mode_config *mode_config = &dev->mode_config;
+ struct drm_encoder *encoder;
+
+ list_for_each_entry(encoder, &mode_config->encoder_list, head) {
+ struct intel_encoder *intel_encoder;
+ struct intel_dp_priv *dp_priv;
+
+ if (!encoder || encoder->crtc != crtc)
+ continue;
+
+ intel_encoder = enc_to_intel_encoder(encoder);
+ dp_priv = intel_encoder->dev_priv;
+
+ if (intel_encoder->type == INTEL_OUTPUT_DISPLAYPORT)
+ return dp_priv->is_pch_edp;
+ }
+ return false;
+}
+
void
intel_dp_set_m_n(struct drm_crtc *crtc, struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode)
@@ -587,7 +650,7 @@ intel_dp_set_m_n(struct drm_crtc *crtc, struct drm_display_mode *mode,
struct drm_encoder *encoder;
struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
- int lane_count = 4;
+ int lane_count = 4, bpp = 24;
struct intel_dp_m_n m_n;
/*
@@ -605,6 +668,8 @@ intel_dp_set_m_n(struct drm_crtc *crtc, struct drm_display_mode *mode,
if (intel_encoder->type == INTEL_OUTPUT_DISPLAYPORT) {
lane_count = dp_priv->lane_count;
+ if (IS_PCH_eDP(dp_priv))
+ bpp = dev_priv->edp_bpp;
break;
}
}
@@ -614,7 +679,7 @@ intel_dp_set_m_n(struct drm_crtc *crtc, struct drm_display_mode *mode,
* the number of bytes_per_pixel post-LUT, which we always
* set up for 8-bits of R/G/B, or 3 bytes total.
*/
- intel_dp_compute_m_n(3, lane_count,
+ intel_dp_compute_m_n(bpp, lane_count,
mode->clock, adjusted_mode->clock, &m_n);
if (HAS_PCH_SPLIT(dev)) {
@@ -796,7 +861,7 @@ intel_dp_dpms(struct drm_encoder *encoder, int mode)
if (mode != DRM_MODE_DPMS_ON) {
if (dp_reg & DP_PORT_EN) {
intel_dp_link_down(intel_encoder, dp_priv->DP);
- if (IS_eDP(intel_encoder)) {
+ if (IS_eDP(intel_encoder) || IS_PCH_eDP(dp_priv)) {
ironlake_edp_backlight_off(dev);
ironlake_edp_panel_off(dev);
}
@@ -804,7 +869,7 @@ intel_dp_dpms(struct drm_encoder *encoder, int mode)
} else {
if (!(dp_reg & DP_PORT_EN)) {
intel_dp_link_train(intel_encoder, dp_priv->DP, dp_priv->link_configuration);
- if (IS_eDP(intel_encoder)) {
+ if (IS_eDP(intel_encoder) || IS_PCH_eDP(dp_priv)) {
ironlake_edp_panel_on(dev);
ironlake_edp_backlight_on(dev);
}
@@ -1340,17 +1405,32 @@ static int intel_dp_get_modes(struct drm_connector *connector)
struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder);
struct drm_device *dev = intel_encoder->enc.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
+ struct intel_dp_priv *dp_priv = intel_encoder->dev_priv;
int ret;
/* We should parse the EDID data and find out if it has an audio sink
*/
ret = intel_ddc_get_modes(connector, intel_encoder->ddc_bus);
- if (ret)
+ if (ret) {
+ if ((IS_eDP(intel_encoder) || IS_PCH_eDP(dp_priv)) &&
+ !dev_priv->panel_fixed_mode) {
+ struct drm_display_mode *newmode;
+ list_for_each_entry(newmode, &connector->probed_modes,
+ head) {
+ if (newmode->type & DRM_MODE_TYPE_PREFERRED) {
+ dev_priv->panel_fixed_mode =
+ drm_mode_duplicate(dev, newmode);
+ break;
+ }
+ }
+ }
+
return ret;
+ }
/* if eDP has no EDID, try to use fixed panel mode from VBT */
- if (IS_eDP(intel_encoder)) {
+ if (IS_eDP(intel_encoder) || IS_PCH_eDP(dp_priv)) {
if (dev_priv->panel_fixed_mode != NULL) {
struct drm_display_mode *mode;
mode = drm_mode_duplicate(dev, dev_priv->panel_fixed_mode);
@@ -1435,6 +1515,26 @@ intel_trans_dp_port_sel (struct drm_crtc *crtc)
return -1;
}
+/* check the VBT to see whether the eDP is on DP-D port */
+bool intel_dpd_is_edp(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct child_device_config *p_child;
+ int i;
+
+ if (!dev_priv->child_dev_num)
+ return false;
+
+ for (i = 0; i < dev_priv->child_dev_num; i++) {
+ p_child = dev_priv->child_dev + i;
+
+ if (p_child->dvo_port == PORT_IDPD &&
+ p_child->device_type == DEVICE_TYPE_eDP)
+ return true;
+ }
+ return false;
+}
+
void
intel_dp_init(struct drm_device *dev, int output_reg)
{
@@ -1444,6 +1544,7 @@ intel_dp_init(struct drm_device *dev, int output_reg)
struct intel_connector *intel_connector;
struct intel_dp_priv *dp_priv;
const char *name = NULL;
+ int type;
intel_encoder = kcalloc(sizeof(struct intel_encoder) +
sizeof(struct intel_dp_priv), 1, GFP_KERNEL);
@@ -1458,18 +1559,24 @@ intel_dp_init(struct drm_device *dev, int output_reg)
dp_priv = (struct intel_dp_priv *)(intel_encoder + 1);
+ if (HAS_PCH_SPLIT(dev) && (output_reg == PCH_DP_D))
+ if (intel_dpd_is_edp(dev))
+ dp_priv->is_pch_edp = true;
+
+ if (output_reg == DP_A || IS_PCH_eDP(dp_priv)) {
+ type = DRM_MODE_CONNECTOR_eDP;
+ intel_encoder->type = INTEL_OUTPUT_EDP;
+ } else {
+ type = DRM_MODE_CONNECTOR_DisplayPort;
+ intel_encoder->type = INTEL_OUTPUT_DISPLAYPORT;
+ }
+
connector = &intel_connector->base;
- drm_connector_init(dev, connector, &intel_dp_connector_funcs,
- DRM_MODE_CONNECTOR_DisplayPort);
+ drm_connector_init(dev, connector, &intel_dp_connector_funcs, type);
drm_connector_helper_add(connector, &intel_dp_connector_helper_funcs);
connector->polled = DRM_CONNECTOR_POLL_HPD;
- if (output_reg == DP_A)
- intel_encoder->type = INTEL_OUTPUT_EDP;
- else
- intel_encoder->type = INTEL_OUTPUT_DISPLAYPORT;
-
if (output_reg == DP_B || output_reg == PCH_DP_B)
intel_encoder->clone_mask = (1 << INTEL_DP_B_CLONE_BIT);
else if (output_reg == DP_C || output_reg == PCH_DP_C)
@@ -1528,7 +1635,7 @@ intel_dp_init(struct drm_device *dev, int output_reg)
intel_encoder->ddc_bus = &dp_priv->adapter;
intel_encoder->hot_plug = intel_dp_hot_plug;
- if (output_reg == DP_A) {
+ if (output_reg == DP_A || IS_PCH_eDP(dp_priv)) {
/* initialize panel mode from VBT if available for eDP */
if (dev_priv->lfp_lvds_vbt_mode) {
dev_priv->panel_fixed_mode =
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 2f7970be905..b2190148703 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -143,8 +143,6 @@ struct intel_crtc {
struct drm_crtc base;
enum pipe pipe;
enum plane plane;
- struct drm_gem_object *cursor_bo;
- uint32_t cursor_addr;
u8 lut_r[256], lut_g[256], lut_b[256];
int dpms_mode;
bool busy; /* is scanout buffer being updated frequently? */
@@ -153,6 +151,12 @@ struct intel_crtc {
struct intel_overlay *overlay;
struct intel_unpin_work *unpin_work;
int fdi_lanes;
+
+ struct drm_gem_object *cursor_bo;
+ uint32_t cursor_addr;
+ int16_t cursor_x, cursor_y;
+ int16_t cursor_width, cursor_height;
+ bool cursor_visble;
};
#define to_intel_crtc(x) container_of(x, struct intel_crtc, base)
@@ -179,6 +183,8 @@ extern void intel_dp_init(struct drm_device *dev, int dp_reg);
void
intel_dp_set_m_n(struct drm_crtc *crtc, struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode);
+extern bool intel_pch_has_edp(struct drm_crtc *crtc);
+extern bool intel_dpd_is_edp(struct drm_device *dev);
extern void intel_edp_link_config (struct intel_encoder *, int *, int *);
diff --git a/drivers/gpu/drm/i915/intel_fb.c b/drivers/gpu/drm/i915/intel_fb.c
index 3e18c9e7729..54acd8b534d 100644
--- a/drivers/gpu/drm/i915/intel_fb.c
+++ b/drivers/gpu/drm/i915/intel_fb.c
@@ -61,6 +61,8 @@ static struct fb_ops intelfb_ops = {
.fb_pan_display = drm_fb_helper_pan_display,
.fb_blank = drm_fb_helper_blank,
.fb_setcmap = drm_fb_helper_setcmap,
+ .fb_debug_enter = drm_fb_helper_debug_enter,
+ .fb_debug_leave = drm_fb_helper_debug_leave,
};
static int intelfb_create(struct intel_fbdev *ifbdev,
diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c
index 83bd764b000..197887ed182 100644
--- a/drivers/gpu/drm/i915/intel_hdmi.c
+++ b/drivers/gpu/drm/i915/intel_hdmi.c
@@ -54,10 +54,11 @@ static void intel_hdmi_mode_set(struct drm_encoder *encoder,
struct intel_hdmi_priv *hdmi_priv = intel_encoder->dev_priv;
u32 sdvox;
- sdvox = SDVO_ENCODING_HDMI |
- SDVO_BORDER_ENABLE |
- SDVO_VSYNC_ACTIVE_HIGH |
- SDVO_HSYNC_ACTIVE_HIGH;
+ sdvox = SDVO_ENCODING_HDMI | SDVO_BORDER_ENABLE;
+ if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC)
+ sdvox |= SDVO_VSYNC_ACTIVE_HIGH;
+ if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC)
+ sdvox |= SDVO_HSYNC_ACTIVE_HIGH;
if (hdmi_priv->has_hdmi_sink) {
sdvox |= SDVO_AUDIO_ENABLE;
diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c
index 0eab8df5bf7..0a2e60059fb 100644
--- a/drivers/gpu/drm/i915/intel_lvds.c
+++ b/drivers/gpu/drm/i915/intel_lvds.c
@@ -156,31 +156,73 @@ static int intel_lvds_mode_valid(struct drm_connector *connector,
return MODE_OK;
}
+static void
+centre_horizontally(struct drm_display_mode *mode,
+ int width)
+{
+ u32 border, sync_pos, blank_width, sync_width;
+
+ /* keep the hsync and hblank widths constant */
+ sync_width = mode->crtc_hsync_end - mode->crtc_hsync_start;
+ blank_width = mode->crtc_hblank_end - mode->crtc_hblank_start;
+ sync_pos = (blank_width - sync_width + 1) / 2;
+
+ border = (mode->hdisplay - width + 1) / 2;
+ border += border & 1; /* make the border even */
+
+ mode->crtc_hdisplay = width;
+ mode->crtc_hblank_start = width + border;
+ mode->crtc_hblank_end = mode->crtc_hblank_start + blank_width;
+
+ mode->crtc_hsync_start = mode->crtc_hblank_start + sync_pos;
+ mode->crtc_hsync_end = mode->crtc_hsync_start + sync_width;
+}
+
+static void
+centre_vertically(struct drm_display_mode *mode,
+ int height)
+{
+ u32 border, sync_pos, blank_width, sync_width;
+
+ /* keep the vsync and vblank widths constant */
+ sync_width = mode->crtc_vsync_end - mode->crtc_vsync_start;
+ blank_width = mode->crtc_vblank_end - mode->crtc_vblank_start;
+ sync_pos = (blank_width - sync_width + 1) / 2;
+
+ border = (mode->vdisplay - height + 1) / 2;
+
+ mode->crtc_vdisplay = height;
+ mode->crtc_vblank_start = height + border;
+ mode->crtc_vblank_end = mode->crtc_vblank_start + blank_width;
+
+ mode->crtc_vsync_start = mode->crtc_vblank_start + sync_pos;
+ mode->crtc_vsync_end = mode->crtc_vsync_start + sync_width;
+}
+
+static inline u32 panel_fitter_scaling(u32 source, u32 target)
+{
+ /*
+ * Floating point operation is not supported. So the FACTOR
+ * is defined, which can avoid the floating point computation
+ * when calculating the panel ratio.
+ */
+#define ACCURACY 12
+#define FACTOR (1 << ACCURACY)
+ u32 ratio = source * FACTOR / target;
+ return (FACTOR * ratio + FACTOR/2) / FACTOR;
+}
+
static bool intel_lvds_mode_fixup(struct drm_encoder *encoder,
struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode)
{
- /*
- * float point operation is not supported . So the PANEL_RATIO_FACTOR
- * is defined, which can avoid the float point computation when
- * calculating the panel ratio.
- */
-#define PANEL_RATIO_FACTOR 8192
struct drm_device *dev = encoder->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
struct drm_encoder *tmp_encoder;
struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder);
struct intel_lvds_priv *lvds_priv = intel_encoder->dev_priv;
- u32 pfit_control = 0, pfit_pgm_ratios = 0;
- int left_border = 0, right_border = 0, top_border = 0;
- int bottom_border = 0;
- bool border = 0;
- int panel_ratio, desired_ratio, vert_scale, horiz_scale;
- int horiz_ratio, vert_ratio;
- u32 hsync_width, vsync_width;
- u32 hblank_width, vblank_width;
- u32 hsync_pos, vsync_pos;
+ u32 pfit_control = 0, pfit_pgm_ratios = 0, border = 0;
/* Should never happen!! */
if (!IS_I965G(dev) && intel_crtc->pipe == 0) {
@@ -200,27 +242,25 @@ static bool intel_lvds_mode_fixup(struct drm_encoder *encoder,
if (dev_priv->panel_fixed_mode == NULL)
return true;
/*
- * If we have timings from the BIOS for the panel, put them in
+ * We have timings from the BIOS for the panel, put them in
* to the adjusted mode. The CRTC will be set up for this mode,
* with the panel scaling set up to source from the H/VDisplay
* of the original mode.
*/
- if (dev_priv->panel_fixed_mode != NULL) {
- adjusted_mode->hdisplay = dev_priv->panel_fixed_mode->hdisplay;
- adjusted_mode->hsync_start =
- dev_priv->panel_fixed_mode->hsync_start;
- adjusted_mode->hsync_end =
- dev_priv->panel_fixed_mode->hsync_end;
- adjusted_mode->htotal = dev_priv->panel_fixed_mode->htotal;
- adjusted_mode->vdisplay = dev_priv->panel_fixed_mode->vdisplay;
- adjusted_mode->vsync_start =
- dev_priv->panel_fixed_mode->vsync_start;
- adjusted_mode->vsync_end =
- dev_priv->panel_fixed_mode->vsync_end;
- adjusted_mode->vtotal = dev_priv->panel_fixed_mode->vtotal;
- adjusted_mode->clock = dev_priv->panel_fixed_mode->clock;
- drm_mode_set_crtcinfo(adjusted_mode, CRTC_INTERLACE_HALVE_V);
- }
+ adjusted_mode->hdisplay = dev_priv->panel_fixed_mode->hdisplay;
+ adjusted_mode->hsync_start =
+ dev_priv->panel_fixed_mode->hsync_start;
+ adjusted_mode->hsync_end =
+ dev_priv->panel_fixed_mode->hsync_end;
+ adjusted_mode->htotal = dev_priv->panel_fixed_mode->htotal;
+ adjusted_mode->vdisplay = dev_priv->panel_fixed_mode->vdisplay;
+ adjusted_mode->vsync_start =
+ dev_priv->panel_fixed_mode->vsync_start;
+ adjusted_mode->vsync_end =
+ dev_priv->panel_fixed_mode->vsync_end;
+ adjusted_mode->vtotal = dev_priv->panel_fixed_mode->vtotal;
+ adjusted_mode->clock = dev_priv->panel_fixed_mode->clock;
+ drm_mode_set_crtcinfo(adjusted_mode, CRTC_INTERLACE_HALVE_V);
/* Make sure pre-965s set dither correctly */
if (!IS_I965G(dev)) {
@@ -230,11 +270,8 @@ static bool intel_lvds_mode_fixup(struct drm_encoder *encoder,
/* Native modes don't need fitting */
if (adjusted_mode->hdisplay == mode->hdisplay &&
- adjusted_mode->vdisplay == mode->vdisplay) {
- pfit_pgm_ratios = 0;
- border = 0;
+ adjusted_mode->vdisplay == mode->vdisplay)
goto out;
- }
/* full screen scale for now */
if (HAS_PCH_SPLIT(dev))
@@ -242,25 +279,9 @@ static bool intel_lvds_mode_fixup(struct drm_encoder *encoder,
/* 965+ wants fuzzy fitting */
if (IS_I965G(dev))
- pfit_control |= (intel_crtc->pipe << PFIT_PIPE_SHIFT) |
- PFIT_FILTER_FUZZY;
-
- hsync_width = adjusted_mode->crtc_hsync_end -
- adjusted_mode->crtc_hsync_start;
- vsync_width = adjusted_mode->crtc_vsync_end -
- adjusted_mode->crtc_vsync_start;
- hblank_width = adjusted_mode->crtc_hblank_end -
- adjusted_mode->crtc_hblank_start;
- vblank_width = adjusted_mode->crtc_vblank_end -
- adjusted_mode->crtc_vblank_start;
- /*
- * Deal with panel fitting options. Figure out how to stretch the
- * image based on its aspect ratio & the current panel fitting mode.
- */
- panel_ratio = adjusted_mode->hdisplay * PANEL_RATIO_FACTOR /
- adjusted_mode->vdisplay;
- desired_ratio = mode->hdisplay * PANEL_RATIO_FACTOR /
- mode->vdisplay;
+ pfit_control |= ((intel_crtc->pipe << PFIT_PIPE_SHIFT) |
+ PFIT_FILTER_FUZZY);
+
/*
* Enable automatic panel scaling for non-native modes so that they fill
* the screen. Should be enabled before the pipe is enabled, according
@@ -278,170 +299,63 @@ static bool intel_lvds_mode_fixup(struct drm_encoder *encoder,
* For centered modes, we have to calculate border widths &
* heights and modify the values programmed into the CRTC.
*/
- left_border = (adjusted_mode->hdisplay - mode->hdisplay) / 2;
- right_border = left_border;
- if (mode->hdisplay & 1)
- right_border++;
- top_border = (adjusted_mode->vdisplay - mode->vdisplay) / 2;
- bottom_border = top_border;
- if (mode->vdisplay & 1)
- bottom_border++;
- /* Set active & border values */
- adjusted_mode->crtc_hdisplay = mode->hdisplay;
- /* Keep the boder be even */
- if (right_border & 1)
- right_border++;
- /* use the border directly instead of border minuse one */
- adjusted_mode->crtc_hblank_start = mode->hdisplay +
- right_border;
- /* keep the blank width constant */
- adjusted_mode->crtc_hblank_end =
- adjusted_mode->crtc_hblank_start + hblank_width;
- /* get the hsync pos relative to hblank start */
- hsync_pos = (hblank_width - hsync_width) / 2;
- /* keep the hsync pos be even */
- if (hsync_pos & 1)
- hsync_pos++;
- adjusted_mode->crtc_hsync_start =
- adjusted_mode->crtc_hblank_start + hsync_pos;
- /* keep the hsync width constant */
- adjusted_mode->crtc_hsync_end =
- adjusted_mode->crtc_hsync_start + hsync_width;
- adjusted_mode->crtc_vdisplay = mode->vdisplay;
- /* use the border instead of border minus one */
- adjusted_mode->crtc_vblank_start = mode->vdisplay +
- bottom_border;
- /* keep the vblank width constant */
- adjusted_mode->crtc_vblank_end =
- adjusted_mode->crtc_vblank_start + vblank_width;
- /* get the vsync start postion relative to vblank start */
- vsync_pos = (vblank_width - vsync_width) / 2;
- adjusted_mode->crtc_vsync_start =
- adjusted_mode->crtc_vblank_start + vsync_pos;
- /* keep the vsync width constant */
- adjusted_mode->crtc_vsync_end =
- adjusted_mode->crtc_vsync_start + vsync_width;
- border = 1;
+ centre_horizontally(adjusted_mode, mode->hdisplay);
+ centre_vertically(adjusted_mode, mode->vdisplay);
+ border = LVDS_BORDER_ENABLE;
break;
+
case DRM_MODE_SCALE_ASPECT:
- /* Scale but preserve the spect ratio */
- pfit_control |= PFIT_ENABLE;
+ /* Scale but preserve the aspect ratio */
if (IS_I965G(dev)) {
+ u32 scaled_width = adjusted_mode->hdisplay * mode->vdisplay;
+ u32 scaled_height = mode->hdisplay * adjusted_mode->vdisplay;
+
+ pfit_control |= PFIT_ENABLE;
/* 965+ is easy, it does everything in hw */
- if (panel_ratio > desired_ratio)
+ if (scaled_width > scaled_height)
pfit_control |= PFIT_SCALING_PILLAR;
- else if (panel_ratio < desired_ratio)
+ else if (scaled_width < scaled_height)
pfit_control |= PFIT_SCALING_LETTER;
else
pfit_control |= PFIT_SCALING_AUTO;
} else {
+ u32 scaled_width = adjusted_mode->hdisplay * mode->vdisplay;
+ u32 scaled_height = mode->hdisplay * adjusted_mode->vdisplay;
/*
* For earlier chips we have to calculate the scaling
* ratio by hand and program it into the
* PFIT_PGM_RATIO register
*/
- u32 horiz_bits, vert_bits, bits = 12;
- horiz_ratio = mode->hdisplay * PANEL_RATIO_FACTOR/
- adjusted_mode->hdisplay;
- vert_ratio = mode->vdisplay * PANEL_RATIO_FACTOR/
- adjusted_mode->vdisplay;
- horiz_scale = adjusted_mode->hdisplay *
- PANEL_RATIO_FACTOR / mode->hdisplay;
- vert_scale = adjusted_mode->vdisplay *
- PANEL_RATIO_FACTOR / mode->vdisplay;
-
- /* retain aspect ratio */
- if (panel_ratio > desired_ratio) { /* Pillar */
- u32 scaled_width;
- scaled_width = mode->hdisplay * vert_scale /
- PANEL_RATIO_FACTOR;
- horiz_ratio = vert_ratio;
- pfit_control |= (VERT_AUTO_SCALE |
- VERT_INTERP_BILINEAR |
- HORIZ_INTERP_BILINEAR);
- /* Pillar will have left/right borders */
- left_border = (adjusted_mode->hdisplay -
- scaled_width) / 2;
- right_border = left_border;
- if (mode->hdisplay & 1) /* odd resolutions */
- right_border++;
- /* keep the border be even */
- if (right_border & 1)
- right_border++;
- adjusted_mode->crtc_hdisplay = scaled_width;
- /* use border instead of border minus one */
- adjusted_mode->crtc_hblank_start =
- scaled_width + right_border;
- /* keep the hblank width constant */
- adjusted_mode->crtc_hblank_end =
- adjusted_mode->crtc_hblank_start +
- hblank_width;
- /*
- * get the hsync start pos relative to
- * hblank start
- */
- hsync_pos = (hblank_width - hsync_width) / 2;
- /* keep the hsync_pos be even */
- if (hsync_pos & 1)
- hsync_pos++;
- adjusted_mode->crtc_hsync_start =
- adjusted_mode->crtc_hblank_start +
- hsync_pos;
- /* keept hsync width constant */
- adjusted_mode->crtc_hsync_end =
- adjusted_mode->crtc_hsync_start +
- hsync_width;
- border = 1;
- } else if (panel_ratio < desired_ratio) { /* letter */
- u32 scaled_height = mode->vdisplay *
- horiz_scale / PANEL_RATIO_FACTOR;
- vert_ratio = horiz_ratio;
- pfit_control |= (HORIZ_AUTO_SCALE |
- VERT_INTERP_BILINEAR |
- HORIZ_INTERP_BILINEAR);
- /* Letterbox will have top/bottom border */
- top_border = (adjusted_mode->vdisplay -
- scaled_height) / 2;
- bottom_border = top_border;
- if (mode->vdisplay & 1)
- bottom_border++;
- adjusted_mode->crtc_vdisplay = scaled_height;
- /* use border instead of border minus one */
- adjusted_mode->crtc_vblank_start =
- scaled_height + bottom_border;
- /* keep the vblank width constant */
- adjusted_mode->crtc_vblank_end =
- adjusted_mode->crtc_vblank_start +
- vblank_width;
- /*
- * get the vsync start pos relative to
- * vblank start
- */
- vsync_pos = (vblank_width - vsync_width) / 2;
- adjusted_mode->crtc_vsync_start =
- adjusted_mode->crtc_vblank_start +
- vsync_pos;
- /* keep the vsync width constant */
- adjusted_mode->crtc_vsync_end =
- adjusted_mode->crtc_vsync_start +
- vsync_width;
- border = 1;
- } else {
- /* Aspects match, Let hw scale both directions */
- pfit_control |= (VERT_AUTO_SCALE |
- HORIZ_AUTO_SCALE |
+ if (scaled_width > scaled_height) { /* pillar */
+ centre_horizontally(adjusted_mode, scaled_height / mode->vdisplay);
+
+ border = LVDS_BORDER_ENABLE;
+ if (mode->vdisplay != adjusted_mode->vdisplay) {
+ u32 bits = panel_fitter_scaling(mode->vdisplay, adjusted_mode->vdisplay);
+ pfit_pgm_ratios |= (bits << PFIT_HORIZ_SCALE_SHIFT |
+ bits << PFIT_VERT_SCALE_SHIFT);
+ pfit_control |= (PFIT_ENABLE |
+ VERT_INTERP_BILINEAR |
+ HORIZ_INTERP_BILINEAR);
+ }
+ } else if (scaled_width < scaled_height) { /* letter */
+ centre_vertically(adjusted_mode, scaled_width / mode->hdisplay);
+
+ border = LVDS_BORDER_ENABLE;
+ if (mode->hdisplay != adjusted_mode->hdisplay) {
+ u32 bits = panel_fitter_scaling(mode->hdisplay, adjusted_mode->hdisplay);
+ pfit_pgm_ratios |= (bits << PFIT_HORIZ_SCALE_SHIFT |
+ bits << PFIT_VERT_SCALE_SHIFT);
+ pfit_control |= (PFIT_ENABLE |
+ VERT_INTERP_BILINEAR |
+ HORIZ_INTERP_BILINEAR);
+ }
+ } else
+ /* Aspects match, Let hw scale both directions */
+ pfit_control |= (PFIT_ENABLE |
+ VERT_AUTO_SCALE | HORIZ_AUTO_SCALE |
VERT_INTERP_BILINEAR |
HORIZ_INTERP_BILINEAR);
- }
- horiz_bits = (1 << bits) * horiz_ratio /
- PANEL_RATIO_FACTOR;
- vert_bits = (1 << bits) * vert_ratio /
- PANEL_RATIO_FACTOR;
- pfit_pgm_ratios =
- ((vert_bits << PFIT_VERT_SCALE_SHIFT) &
- PFIT_VERT_SCALE_MASK) |
- ((horiz_bits << PFIT_HORIZ_SCALE_SHIFT) &
- PFIT_HORIZ_SCALE_MASK);
}
break;
@@ -458,6 +372,7 @@ static bool intel_lvds_mode_fixup(struct drm_encoder *encoder,
VERT_INTERP_BILINEAR |
HORIZ_INTERP_BILINEAR);
break;
+
default:
break;
}
@@ -465,14 +380,8 @@ static bool intel_lvds_mode_fixup(struct drm_encoder *encoder,
out:
lvds_priv->pfit_control = pfit_control;
lvds_priv->pfit_pgm_ratios = pfit_pgm_ratios;
- /*
- * When there exists the border, it means that the LVDS_BORDR
- * should be enabled.
- */
- if (border)
- dev_priv->lvds_border_bits |= LVDS_BORDER_ENABLE;
- else
- dev_priv->lvds_border_bits &= ~(LVDS_BORDER_ENABLE);
+ dev_priv->lvds_border_bits = border;
+
/*
* XXX: It would be nice to support lower refresh rates on the
* panels to reduce power consumption, and perhaps match the
diff --git a/drivers/gpu/drm/i915/intel_overlay.c b/drivers/gpu/drm/i915/intel_overlay.c
index d7ad5139d17..d39aea24eab 100644
--- a/drivers/gpu/drm/i915/intel_overlay.c
+++ b/drivers/gpu/drm/i915/intel_overlay.c
@@ -65,7 +65,7 @@
#define OCMD_YUV_410_PLANAR (0xe<<10) /* also 411 */
#define OCMD_TVSYNCFLIP_PARITY (0x1<<9)
#define OCMD_TVSYNCFLIP_ENABLE (0x1<<7)
-#define OCMD_BUF_TYPE_MASK (Ox1<<5)
+#define OCMD_BUF_TYPE_MASK (0x1<<5)
#define OCMD_BUF_TYPE_FRAME (0x0<<5)
#define OCMD_BUF_TYPE_FIELD (0x1<<5)
#define OCMD_TEST_MODE (0x1<<4)
@@ -185,7 +185,8 @@ static struct overlay_registers *intel_overlay_map_regs_atomic(struct intel_over
if (OVERLAY_NONPHYSICAL(overlay->dev)) {
regs = io_mapping_map_atomic_wc(dev_priv->mm.gtt_mapping,
- overlay->reg_bo->gtt_offset);
+ overlay->reg_bo->gtt_offset,
+ KM_USER0);
if (!regs) {
DRM_ERROR("failed to map overlay regs in GTT\n");
@@ -200,7 +201,7 @@ static struct overlay_registers *intel_overlay_map_regs_atomic(struct intel_over
static void intel_overlay_unmap_regs_atomic(struct intel_overlay *overlay)
{
if (OVERLAY_NONPHYSICAL(overlay->dev))
- io_mapping_unmap_atomic(overlay->virt_addr);
+ io_mapping_unmap_atomic(overlay->virt_addr, KM_USER0);
overlay->virt_addr = NULL;
@@ -958,7 +959,7 @@ static int check_overlay_src(struct drm_device *dev,
|| rec->src_width < N_HORIZ_Y_TAPS*4)
return -EINVAL;
- /* check alingment constrains */
+ /* check alignment constraints */
switch (rec->flags & I915_OVERLAY_TYPE_MASK) {
case I915_OVERLAY_RGB:
/* not implemented */
@@ -990,7 +991,10 @@ static int check_overlay_src(struct drm_device *dev,
return -EINVAL;
/* stride checking */
- stride_mask = 63;
+ if (IS_I830(dev) || IS_845G(dev))
+ stride_mask = 255;
+ else
+ stride_mask = 63;
if (rec->stride_Y & stride_mask || rec->stride_UV & stride_mask)
return -EINVAL;
diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c
index 76993ac16cc..d9d4d51aa89 100644
--- a/drivers/gpu/drm/i915/intel_sdvo.c
+++ b/drivers/gpu/drm/i915/intel_sdvo.c
@@ -392,13 +392,13 @@ static void intel_sdvo_debug_write(struct intel_encoder *intel_encoder, u8 cmd,
DRM_LOG_KMS("%02X ", ((u8 *)args)[i]);
for (; i < 8; i++)
DRM_LOG_KMS(" ");
- for (i = 0; i < sizeof(sdvo_cmd_names) / sizeof(sdvo_cmd_names[0]); i++) {
+ for (i = 0; i < ARRAY_SIZE(sdvo_cmd_names); i++) {
if (cmd == sdvo_cmd_names[i].cmd) {
DRM_LOG_KMS("(%s)", sdvo_cmd_names[i].name);
break;
}
}
- if (i == sizeof(sdvo_cmd_names)/ sizeof(sdvo_cmd_names[0]))
+ if (i == ARRAY_SIZE(sdvo_cmd_names))
DRM_LOG_KMS("(%02X)", cmd);
DRM_LOG_KMS("\n");
}
@@ -1237,9 +1237,11 @@ static void intel_sdvo_mode_set(struct drm_encoder *encoder,
/* Set the SDVO control regs. */
if (IS_I965G(dev)) {
- sdvox |= SDVO_BORDER_ENABLE |
- SDVO_VSYNC_ACTIVE_HIGH |
- SDVO_HSYNC_ACTIVE_HIGH;
+ sdvox |= SDVO_BORDER_ENABLE;
+ if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC)
+ sdvox |= SDVO_VSYNC_ACTIVE_HIGH;
+ if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC)
+ sdvox |= SDVO_HSYNC_ACTIVE_HIGH;
} else {
sdvox |= I915_READ(sdvo_priv->sdvo_reg);
switch (sdvo_priv->sdvo_reg) {
diff --git a/drivers/gpu/drm/i915/intel_tv.c b/drivers/gpu/drm/i915/intel_tv.c
index 6d553c29d10..cc3726a4a1c 100644
--- a/drivers/gpu/drm/i915/intel_tv.c
+++ b/drivers/gpu/drm/i915/intel_tv.c
@@ -476,7 +476,7 @@ static const struct tv_mode tv_modes[] = {
.vi_end_f1 = 20, .vi_end_f2 = 21,
.nbr_end = 240,
- .burst_ena = 8,
+ .burst_ena = true,
.hburst_start = 72, .hburst_len = 34,
.vburst_start_f1 = 9, .vburst_end_f1 = 240,
.vburst_start_f2 = 10, .vburst_end_f2 = 240,
@@ -896,8 +896,6 @@ static const struct tv_mode tv_modes[] = {
},
};
-#define NUM_TV_MODES sizeof(tv_modes) / sizeof (tv_modes[0])
-
static void
intel_tv_dpms(struct drm_encoder *encoder, int mode)
{
@@ -1424,7 +1422,7 @@ intel_tv_get_modes(struct drm_connector *connector)
int j, count = 0;
u64 tmp;
- for (j = 0; j < sizeof(input_res_table) / sizeof(input_res_table[0]);
+ for (j = 0; j < ARRAY_SIZE(input_res_table);
j++) {
struct input_res *input = &input_res_table[j];
unsigned int hactive_s = input->w;
@@ -1512,7 +1510,7 @@ intel_tv_set_property(struct drm_connector *connector, struct drm_property *prop
tv_priv->margin[TV_MARGIN_BOTTOM] = val;
changed = true;
} else if (property == dev->mode_config.tv_mode_property) {
- if (val >= NUM_TV_MODES) {
+ if (val >= ARRAY_SIZE(tv_modes)) {
ret = -EINVAL;
goto out;
}
@@ -1693,13 +1691,13 @@ intel_tv_init(struct drm_device *dev)
connector->doublescan_allowed = false;
/* Create TV properties then attach current values */
- tv_format_names = kmalloc(sizeof(char *) * NUM_TV_MODES,
+ tv_format_names = kmalloc(sizeof(char *) * ARRAY_SIZE(tv_modes),
GFP_KERNEL);
if (!tv_format_names)
goto out;
- for (i = 0; i < NUM_TV_MODES; i++)
+ for (i = 0; i < ARRAY_SIZE(tv_modes); i++)
tv_format_names[i] = tv_modes[i].name;
- drm_mode_create_tv_properties(dev, NUM_TV_MODES, tv_format_names);
+ drm_mode_create_tv_properties(dev, ARRAY_SIZE(tv_modes), tv_format_names);
drm_connector_attach_property(connector, dev->mode_config.tv_mode_property,
initial_mode);
diff --git a/drivers/gpu/drm/mga/mga_dma.c b/drivers/gpu/drm/mga/mga_dma.c
index 3c917fb3a60..08868ac3048 100644
--- a/drivers/gpu/drm/mga/mga_dma.c
+++ b/drivers/gpu/drm/mga/mga_dma.c
@@ -52,7 +52,7 @@ static int mga_do_cleanup_dma(struct drm_device *dev, int full_cleanup);
* Engine control
*/
-int mga_do_wait_for_idle(drm_mga_private_t * dev_priv)
+int mga_do_wait_for_idle(drm_mga_private_t *dev_priv)
{
u32 status = 0;
int i;
@@ -74,7 +74,7 @@ int mga_do_wait_for_idle(drm_mga_private_t * dev_priv)
return -EBUSY;
}
-static int mga_do_dma_reset(drm_mga_private_t * dev_priv)
+static int mga_do_dma_reset(drm_mga_private_t *dev_priv)
{
drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
drm_mga_primary_buffer_t *primary = &dev_priv->prim;
@@ -102,7 +102,7 @@ static int mga_do_dma_reset(drm_mga_private_t * dev_priv)
* Primary DMA stream
*/
-void mga_do_dma_flush(drm_mga_private_t * dev_priv)
+void mga_do_dma_flush(drm_mga_private_t *dev_priv)
{
drm_mga_primary_buffer_t *primary = &dev_priv->prim;
u32 head, tail;
@@ -142,11 +142,10 @@ void mga_do_dma_flush(drm_mga_private_t * dev_priv)
head = MGA_READ(MGA_PRIMADDRESS);
- if (head <= tail) {
+ if (head <= tail)
primary->space = primary->size - primary->tail;
- } else {
+ else
primary->space = head - tail;
- }
DRM_DEBUG(" head = 0x%06lx\n", (unsigned long)(head - dev_priv->primary->offset));
DRM_DEBUG(" tail = 0x%06lx\n", (unsigned long)(tail - dev_priv->primary->offset));
@@ -158,7 +157,7 @@ void mga_do_dma_flush(drm_mga_private_t * dev_priv)
DRM_DEBUG("done.\n");
}
-void mga_do_dma_wrap_start(drm_mga_private_t * dev_priv)
+void mga_do_dma_wrap_start(drm_mga_private_t *dev_priv)
{
drm_mga_primary_buffer_t *primary = &dev_priv->prim;
u32 head, tail;
@@ -181,11 +180,10 @@ void mga_do_dma_wrap_start(drm_mga_private_t * dev_priv)
head = MGA_READ(MGA_PRIMADDRESS);
- if (head == dev_priv->primary->offset) {
+ if (head == dev_priv->primary->offset)
primary->space = primary->size;
- } else {
+ else
primary->space = head - dev_priv->primary->offset;
- }
DRM_DEBUG(" head = 0x%06lx\n", (unsigned long)(head - dev_priv->primary->offset));
DRM_DEBUG(" tail = 0x%06x\n", primary->tail);
@@ -199,7 +197,7 @@ void mga_do_dma_wrap_start(drm_mga_private_t * dev_priv)
DRM_DEBUG("done.\n");
}
-void mga_do_dma_wrap_end(drm_mga_private_t * dev_priv)
+void mga_do_dma_wrap_end(drm_mga_private_t *dev_priv)
{
drm_mga_primary_buffer_t *primary = &dev_priv->prim;
drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
@@ -220,11 +218,11 @@ void mga_do_dma_wrap_end(drm_mga_private_t * dev_priv)
* Freelist management
*/
-#define MGA_BUFFER_USED ~0
+#define MGA_BUFFER_USED (~0)
#define MGA_BUFFER_FREE 0
#if MGA_FREELIST_DEBUG
-static void mga_freelist_print(struct drm_device * 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,7 +243,7 @@ static void mga_freelist_print(struct drm_device * dev)
}
#endif
-static int mga_freelist_init(struct drm_device * dev, drm_mga_private_t * dev_priv)
+static int mga_freelist_init(struct drm_device *dev, drm_mga_private_t *dev_priv)
{
struct drm_device_dma *dma = dev->dma;
struct drm_buf *buf;
@@ -288,7 +286,7 @@ static int mga_freelist_init(struct drm_device * dev, drm_mga_private_t * dev_pr
return 0;
}
-static void mga_freelist_cleanup(struct drm_device * dev)
+static void mga_freelist_cleanup(struct drm_device *dev)
{
drm_mga_private_t *dev_priv = dev->dev_private;
drm_mga_freelist_t *entry;
@@ -308,7 +306,7 @@ static void mga_freelist_cleanup(struct drm_device * dev)
#if 0
/* FIXME: Still needed?
*/
-static void mga_freelist_reset(struct drm_device * dev)
+static void mga_freelist_reset(struct drm_device *dev)
{
struct drm_device_dma *dma = dev->dma;
struct drm_buf *buf;
@@ -356,7 +354,7 @@ static struct drm_buf *mga_freelist_get(struct drm_device * dev)
return NULL;
}
-int mga_freelist_put(struct drm_device * dev, struct drm_buf * 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;
@@ -391,7 +389,7 @@ int mga_freelist_put(struct drm_device * dev, struct drm_buf * buf)
* DMA initialization, cleanup
*/
-int mga_driver_load(struct drm_device * dev, unsigned long flags)
+int mga_driver_load(struct drm_device *dev, unsigned long flags)
{
drm_mga_private_t *dev_priv;
int ret;
@@ -405,8 +403,8 @@ int mga_driver_load(struct drm_device * dev, unsigned long flags)
dev_priv->usec_timeout = MGA_DEFAULT_USEC_TIMEOUT;
dev_priv->chipset = flags;
- dev_priv->mmio_base = drm_get_resource_start(dev, 1);
- dev_priv->mmio_size = drm_get_resource_len(dev, 1);
+ dev_priv->mmio_base = pci_resource_start(dev->pdev, 1);
+ dev_priv->mmio_size = pci_resource_len(dev->pdev, 1);
dev->counters += 3;
dev->types[6] = _DRM_STAT_IRQ;
@@ -439,8 +437,8 @@ int mga_driver_load(struct drm_device * dev, unsigned long flags)
*
* \sa mga_do_dma_bootstrap, mga_do_pci_dma_bootstrap
*/
-static int mga_do_agp_dma_bootstrap(struct drm_device * dev,
- drm_mga_dma_bootstrap_t * dma_bs)
+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 =
(drm_mga_private_t *) dev->dev_private;
@@ -481,11 +479,10 @@ static int mga_do_agp_dma_bootstrap(struct drm_device * dev,
*/
if (dev_priv->chipset == MGA_CARD_TYPE_G200) {
- if (mode.mode & 0x02) {
+ if (mode.mode & 0x02)
MGA_WRITE(MGA_AGP_PLL, MGA_AGP2XPLL_ENABLE);
- } else {
+ else
MGA_WRITE(MGA_AGP_PLL, MGA_AGP2XPLL_DISABLE);
- }
}
/* Allocate and bind AGP memory. */
@@ -593,8 +590,8 @@ static int mga_do_agp_dma_bootstrap(struct drm_device * dev,
return 0;
}
#else
-static int mga_do_agp_dma_bootstrap(struct drm_device * dev,
- drm_mga_dma_bootstrap_t * dma_bs)
+static int mga_do_agp_dma_bootstrap(struct drm_device *dev,
+ drm_mga_dma_bootstrap_t *dma_bs)
{
return -EINVAL;
}
@@ -614,8 +611,8 @@ static int mga_do_agp_dma_bootstrap(struct drm_device * dev,
*
* \sa mga_do_dma_bootstrap, mga_do_agp_dma_bootstrap
*/
-static int mga_do_pci_dma_bootstrap(struct drm_device * dev,
- drm_mga_dma_bootstrap_t * dma_bs)
+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 =
(drm_mga_private_t *) dev->dev_private;
@@ -678,9 +675,8 @@ static int mga_do_pci_dma_bootstrap(struct drm_device * dev,
req.size = dma_bs->secondary_bin_size;
err = drm_addbufs_pci(dev, &req);
- if (!err) {
+ if (!err)
break;
- }
}
if (bin_count == 0) {
@@ -704,8 +700,8 @@ static int mga_do_pci_dma_bootstrap(struct drm_device * dev,
return 0;
}
-static int mga_do_dma_bootstrap(struct drm_device * dev,
- drm_mga_dma_bootstrap_t * dma_bs)
+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);
int err;
@@ -737,17 +733,15 @@ static int mga_do_dma_bootstrap(struct drm_device * dev,
* carve off portions of it for internal uses. The remaining memory
* is returned to user-mode to be used for AGP textures.
*/
- if (is_agp) {
+ if (is_agp)
err = mga_do_agp_dma_bootstrap(dev, dma_bs);
- }
/* If we attempted to initialize the card for AGP DMA but failed,
* clean-up any mess that may have been created.
*/
- if (err) {
+ if (err)
mga_do_cleanup_dma(dev, MINIMAL_CLEANUP);
- }
/* Not only do we want to try and initialized PCI cards for PCI DMA,
* but we also try to initialized AGP cards that could not be
@@ -757,9 +751,8 @@ static int mga_do_dma_bootstrap(struct drm_device * dev,
* AGP memory, etc.
*/
- if (!is_agp || err) {
+ if (!is_agp || err)
err = mga_do_pci_dma_bootstrap(dev, dma_bs);
- }
return err;
}
@@ -792,7 +785,7 @@ int mga_dma_bootstrap(struct drm_device *dev, void *data,
return err;
}
-static int mga_do_init_dma(struct drm_device * 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;
@@ -800,11 +793,10 @@ static int mga_do_init_dma(struct drm_device * dev, drm_mga_init_t * init)
dev_priv = dev->dev_private;
- if (init->sgram) {
+ if (init->sgram)
dev_priv->clear_cmd = MGA_DWGCTL_CLEAR | MGA_ATYPE_BLK;
- } else {
+ else
dev_priv->clear_cmd = MGA_DWGCTL_CLEAR | MGA_ATYPE_RSTR;
- }
dev_priv->maccess = init->maccess;
dev_priv->fb_cpp = init->fb_cpp;
@@ -975,9 +967,8 @@ static int mga_do_cleanup_dma(struct drm_device *dev, int full_cleanup)
dev_priv->agp_handle = 0;
}
- if ((dev->agp != NULL) && dev->agp->acquired) {
+ if ((dev->agp != NULL) && dev->agp->acquired)
err = drm_agp_release(dev);
- }
#endif
}
@@ -998,9 +989,8 @@ static int mga_do_cleanup_dma(struct drm_device *dev, int full_cleanup)
memset(dev_priv->warp_pipe_phys, 0,
sizeof(dev_priv->warp_pipe_phys));
- if (dev_priv->head != NULL) {
+ if (dev_priv->head != NULL)
mga_freelist_cleanup(dev);
- }
}
return err;
@@ -1017,9 +1007,8 @@ int mga_dma_init(struct drm_device *dev, void *data,
switch (init->func) {
case MGA_INIT_DMA:
err = mga_do_init_dma(dev, init);
- if (err) {
+ if (err)
(void)mga_do_cleanup_dma(dev, FULL_CLEANUP);
- }
return err;
case MGA_CLEANUP_DMA:
return mga_do_cleanup_dma(dev, FULL_CLEANUP);
@@ -1047,9 +1036,8 @@ int mga_dma_flush(struct drm_device *dev, void *data,
WRAP_WAIT_WITH_RETURN(dev_priv);
- if (lock->flags & (_DRM_LOCK_FLUSH | _DRM_LOCK_FLUSH_ALL)) {
+ if (lock->flags & (_DRM_LOCK_FLUSH | _DRM_LOCK_FLUSH_ALL))
mga_do_dma_flush(dev_priv);
- }
if (lock->flags & _DRM_LOCK_QUIESCENT) {
#if MGA_DMA_DEBUG
@@ -1079,8 +1067,8 @@ int mga_dma_reset(struct drm_device *dev, void *data,
* DMA buffer management
*/
-static int mga_dma_get_buffers(struct drm_device * dev,
- struct drm_file *file_priv, struct drm_dma * d)
+static int mga_dma_get_buffers(struct drm_device *dev,
+ struct drm_file *file_priv, struct drm_dma *d)
{
struct drm_buf *buf;
int i;
@@ -1134,9 +1122,8 @@ int mga_dma_buffers(struct drm_device *dev, void *data,
d->granted_count = 0;
- if (d->request_count) {
+ if (d->request_count)
ret = mga_dma_get_buffers(dev, file_priv, d);
- }
return ret;
}
@@ -1144,7 +1131,7 @@ int mga_dma_buffers(struct drm_device *dev, void *data,
/**
* Called just before the module is unloaded.
*/
-int mga_driver_unload(struct drm_device * dev)
+int mga_driver_unload(struct drm_device *dev)
{
kfree(dev->dev_private);
dev->dev_private = NULL;
@@ -1155,12 +1142,12 @@ int mga_driver_unload(struct drm_device * dev)
/**
* Called when the last opener of the device is closed.
*/
-void mga_driver_lastclose(struct drm_device * dev)
+void mga_driver_lastclose(struct drm_device *dev)
{
mga_do_cleanup_dma(dev, FULL_CLEANUP);
}
-int mga_driver_dma_quiescent(struct drm_device * 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/gpu/drm/mga/mga_drv.c b/drivers/gpu/drm/mga/mga_drv.c
index ddfe16197b5..26d0d8ced80 100644
--- a/drivers/gpu/drm/mga/mga_drv.c
+++ b/drivers/gpu/drm/mga/mga_drv.c
@@ -36,7 +36,7 @@
#include "drm_pciids.h"
-static int mga_driver_device_is_agp(struct drm_device * dev);
+static int mga_driver_device_is_agp(struct drm_device *dev);
static struct pci_device_id pciidlist[] = {
mga_PCI_IDS
@@ -119,7 +119,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(struct drm_device * dev)
+static int mga_driver_device_is_agp(struct drm_device *dev)
{
const struct pci_dev *const pdev = dev->pdev;
diff --git a/drivers/gpu/drm/mga/mga_drv.h b/drivers/gpu/drm/mga/mga_drv.h
index be6c6b9b0e8..1084fa4d261 100644
--- a/drivers/gpu/drm/mga/mga_drv.h
+++ b/drivers/gpu/drm/mga/mga_drv.h
@@ -164,59 +164,59 @@ extern int mga_dma_reset(struct drm_device *dev, void *data,
extern int mga_dma_buffers(struct drm_device *dev, void *data,
struct drm_file *file_priv);
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_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);
+extern int mga_do_wait_for_idle(drm_mga_private_t *dev_priv);
-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 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(struct drm_device * dev, struct drm_buf * buf);
+extern int mga_freelist_put(struct drm_device *dev, struct drm_buf *buf);
/* mga_warp.c */
-extern int mga_warp_install_microcode(drm_mga_private_t * dev_priv);
-extern int mga_warp_init(drm_mga_private_t * dev_priv);
+extern int mga_warp_install_microcode(drm_mga_private_t *dev_priv);
+extern int mga_warp_init(drm_mga_private_t *dev_priv);
/* mga_irq.c */
extern int mga_enable_vblank(struct drm_device *dev, int crtc);
extern void mga_disable_vblank(struct drm_device *dev, int crtc);
extern u32 mga_get_vblank_counter(struct drm_device *dev, int crtc);
-extern int mga_driver_fence_wait(struct drm_device * dev, unsigned int *sequence);
-extern int mga_driver_vblank_wait(struct drm_device * dev, unsigned int *sequence);
+extern int mga_driver_fence_wait(struct drm_device *dev, unsigned int *sequence);
+extern int mga_driver_vblank_wait(struct drm_device *dev, unsigned int *sequence);
extern irqreturn_t mga_driver_irq_handler(DRM_IRQ_ARGS);
-extern void mga_driver_irq_preinstall(struct drm_device * dev);
+extern void mga_driver_irq_preinstall(struct drm_device *dev);
extern int mga_driver_irq_postinstall(struct drm_device *dev);
-extern void mga_driver_irq_uninstall(struct drm_device * dev);
+extern void mga_driver_irq_uninstall(struct drm_device *dev);
extern long mga_compat_ioctl(struct file *filp, unsigned int cmd,
unsigned long arg);
#define mga_flush_write_combine() DRM_WRITEMEMORYBARRIER()
#if defined(__linux__) && defined(__alpha__)
-#define MGA_BASE( reg ) ((unsigned long)(dev_priv->mmio->handle))
-#define MGA_ADDR( reg ) (MGA_BASE(reg) + reg)
+#define MGA_BASE(reg) ((unsigned long)(dev_priv->mmio->handle))
+#define MGA_ADDR(reg) (MGA_BASE(reg) + reg)
-#define MGA_DEREF( reg ) *(volatile u32 *)MGA_ADDR( reg )
-#define MGA_DEREF8( reg ) *(volatile u8 *)MGA_ADDR( reg )
+#define MGA_DEREF(reg) (*(volatile u32 *)MGA_ADDR(reg))
+#define MGA_DEREF8(reg) (*(volatile u8 *)MGA_ADDR(reg))
-#define MGA_READ( reg ) (_MGA_READ((u32 *)MGA_ADDR(reg)))
-#define MGA_READ8( reg ) (_MGA_READ((u8 *)MGA_ADDR(reg)))
-#define MGA_WRITE( reg, val ) do { DRM_WRITEMEMORYBARRIER(); MGA_DEREF( reg ) = val; } while (0)
-#define MGA_WRITE8( reg, val ) do { DRM_WRITEMEMORYBARRIER(); MGA_DEREF8( reg ) = val; } while (0)
+#define MGA_READ(reg) (_MGA_READ((u32 *)MGA_ADDR(reg)))
+#define MGA_READ8(reg) (_MGA_READ((u8 *)MGA_ADDR(reg)))
+#define MGA_WRITE(reg, val) do { DRM_WRITEMEMORYBARRIER(); MGA_DEREF(reg) = val; } while (0)
+#define MGA_WRITE8(reg, val) do { DRM_WRITEMEMORYBARRIER(); MGA_DEREF8(reg) = val; } while (0)
-static inline u32 _MGA_READ(u32 * addr)
+static inline u32 _MGA_READ(u32 *addr)
{
DRM_MEMORYBARRIER();
return *(volatile u32 *)addr;
}
#else
-#define MGA_READ8( reg ) DRM_READ8(dev_priv->mmio, (reg))
-#define MGA_READ( reg ) DRM_READ32(dev_priv->mmio, (reg))
-#define MGA_WRITE8( reg, val ) DRM_WRITE8(dev_priv->mmio, (reg), (val))
-#define MGA_WRITE( reg, val ) DRM_WRITE32(dev_priv->mmio, (reg), (val))
+#define MGA_READ8(reg) DRM_READ8(dev_priv->mmio, (reg))
+#define MGA_READ(reg) DRM_READ32(dev_priv->mmio, (reg))
+#define MGA_WRITE8(reg, val) DRM_WRITE8(dev_priv->mmio, (reg), (val))
+#define MGA_WRITE(reg, val) DRM_WRITE32(dev_priv->mmio, (reg), (val))
#endif
#define DWGREG0 0x1c00
@@ -233,40 +233,39 @@ static inline u32 _MGA_READ(u32 * addr)
* Helper macross...
*/
-#define MGA_EMIT_STATE( dev_priv, dirty ) \
+#define MGA_EMIT_STATE(dev_priv, dirty) \
do { \
- if ( (dirty) & ~MGA_UPLOAD_CLIPRECTS ) { \
- if ( dev_priv->chipset >= MGA_CARD_TYPE_G400 ) { \
- mga_g400_emit_state( dev_priv ); \
- } else { \
- mga_g200_emit_state( dev_priv ); \
- } \
+ if ((dirty) & ~MGA_UPLOAD_CLIPRECTS) { \
+ if (dev_priv->chipset >= MGA_CARD_TYPE_G400) \
+ mga_g400_emit_state(dev_priv); \
+ else \
+ mga_g200_emit_state(dev_priv); \
} \
} while (0)
-#define WRAP_TEST_WITH_RETURN( dev_priv ) \
+#define WRAP_TEST_WITH_RETURN(dev_priv) \
do { \
- if ( test_bit( 0, &dev_priv->prim.wrapped ) ) { \
- if ( mga_is_idle( dev_priv ) ) { \
- mga_do_dma_wrap_end( dev_priv ); \
- } else if ( dev_priv->prim.space < \
- dev_priv->prim.high_mark ) { \
- if ( MGA_DMA_DEBUG ) \
- DRM_INFO( "wrap...\n"); \
- return -EBUSY; \
+ if (test_bit(0, &dev_priv->prim.wrapped)) { \
+ if (mga_is_idle(dev_priv)) { \
+ mga_do_dma_wrap_end(dev_priv); \
+ } else if (dev_priv->prim.space < \
+ dev_priv->prim.high_mark) { \
+ if (MGA_DMA_DEBUG) \
+ DRM_INFO("wrap...\n"); \
+ return -EBUSY; \
} \
} \
} while (0)
-#define WRAP_WAIT_WITH_RETURN( dev_priv ) \
+#define WRAP_WAIT_WITH_RETURN(dev_priv) \
do { \
- if ( test_bit( 0, &dev_priv->prim.wrapped ) ) { \
- if ( mga_do_wait_for_idle( dev_priv ) < 0 ) { \
- if ( MGA_DMA_DEBUG ) \
- DRM_INFO( "wrap...\n"); \
- return -EBUSY; \
+ if (test_bit(0, &dev_priv->prim.wrapped)) { \
+ if (mga_do_wait_for_idle(dev_priv) < 0) { \
+ if (MGA_DMA_DEBUG) \
+ DRM_INFO("wrap...\n"); \
+ return -EBUSY; \
} \
- mga_do_dma_wrap_end( dev_priv ); \
+ mga_do_dma_wrap_end(dev_priv); \
} \
} while (0)
@@ -280,12 +279,12 @@ do { \
#define DMA_BLOCK_SIZE (5 * sizeof(u32))
-#define BEGIN_DMA( n ) \
+#define BEGIN_DMA(n) \
do { \
- if ( MGA_VERBOSE ) { \
- DRM_INFO( "BEGIN_DMA( %d )\n", (n) ); \
- DRM_INFO( " space=0x%x req=0x%Zx\n", \
- dev_priv->prim.space, (n) * DMA_BLOCK_SIZE ); \
+ if (MGA_VERBOSE) { \
+ DRM_INFO("BEGIN_DMA(%d)\n", (n)); \
+ DRM_INFO(" space=0x%x req=0x%Zx\n", \
+ dev_priv->prim.space, (n) * DMA_BLOCK_SIZE); \
} \
prim = dev_priv->prim.start; \
write = dev_priv->prim.tail; \
@@ -293,9 +292,9 @@ do { \
#define BEGIN_DMA_WRAP() \
do { \
- if ( MGA_VERBOSE ) { \
- DRM_INFO( "BEGIN_DMA()\n" ); \
- DRM_INFO( " space=0x%x\n", dev_priv->prim.space ); \
+ if (MGA_VERBOSE) { \
+ DRM_INFO("BEGIN_DMA()\n"); \
+ DRM_INFO(" space=0x%x\n", dev_priv->prim.space); \
} \
prim = dev_priv->prim.start; \
write = dev_priv->prim.tail; \
@@ -304,72 +303,68 @@ do { \
#define ADVANCE_DMA() \
do { \
dev_priv->prim.tail = write; \
- if ( MGA_VERBOSE ) { \
- DRM_INFO( "ADVANCE_DMA() tail=0x%05x sp=0x%x\n", \
- write, dev_priv->prim.space ); \
- } \
+ if (MGA_VERBOSE) \
+ DRM_INFO("ADVANCE_DMA() tail=0x%05x sp=0x%x\n", \
+ write, dev_priv->prim.space); \
} while (0)
#define FLUSH_DMA() \
do { \
- if ( 0 ) { \
- DRM_INFO( "\n" ); \
- DRM_INFO( " tail=0x%06x head=0x%06lx\n", \
- dev_priv->prim.tail, \
- (unsigned long)(MGA_READ(MGA_PRIMADDRESS) - \
- dev_priv->primary->offset)); \
+ if (0) { \
+ DRM_INFO("\n"); \
+ DRM_INFO(" tail=0x%06x head=0x%06lx\n", \
+ dev_priv->prim.tail, \
+ (unsigned long)(MGA_READ(MGA_PRIMADDRESS) - \
+ dev_priv->primary->offset)); \
} \
- if ( !test_bit( 0, &dev_priv->prim.wrapped ) ) { \
- if ( dev_priv->prim.space < \
- dev_priv->prim.high_mark ) { \
- mga_do_dma_wrap_start( dev_priv ); \
- } else { \
- mga_do_dma_flush( dev_priv ); \
- } \
+ if (!test_bit(0, &dev_priv->prim.wrapped)) { \
+ if (dev_priv->prim.space < dev_priv->prim.high_mark) \
+ mga_do_dma_wrap_start(dev_priv); \
+ else \
+ mga_do_dma_flush(dev_priv); \
} \
} while (0)
/* Never use this, always use DMA_BLOCK(...) for primary DMA output.
*/
-#define DMA_WRITE( offset, val ) \
+#define DMA_WRITE(offset, val) \
do { \
- if ( MGA_VERBOSE ) { \
- DRM_INFO( " DMA_WRITE( 0x%08x ) at 0x%04Zx\n", \
- (u32)(val), write + (offset) * sizeof(u32) ); \
- } \
+ if (MGA_VERBOSE) \
+ DRM_INFO(" DMA_WRITE( 0x%08x ) at 0x%04Zx\n", \
+ (u32)(val), write + (offset) * sizeof(u32)); \
*(volatile u32 *)(prim + write + (offset) * sizeof(u32)) = val; \
} while (0)
-#define DMA_BLOCK( reg0, val0, reg1, val1, reg2, val2, reg3, val3 ) \
+#define DMA_BLOCK(reg0, val0, reg1, val1, reg2, val2, reg3, val3) \
do { \
- DMA_WRITE( 0, ((DMAREG( reg0 ) << 0) | \
- (DMAREG( reg1 ) << 8) | \
- (DMAREG( reg2 ) << 16) | \
- (DMAREG( reg3 ) << 24)) ); \
- DMA_WRITE( 1, val0 ); \
- DMA_WRITE( 2, val1 ); \
- DMA_WRITE( 3, val2 ); \
- DMA_WRITE( 4, val3 ); \
+ DMA_WRITE(0, ((DMAREG(reg0) << 0) | \
+ (DMAREG(reg1) << 8) | \
+ (DMAREG(reg2) << 16) | \
+ (DMAREG(reg3) << 24))); \
+ DMA_WRITE(1, val0); \
+ DMA_WRITE(2, val1); \
+ DMA_WRITE(3, val2); \
+ DMA_WRITE(4, val3); \
write += DMA_BLOCK_SIZE; \
} while (0)
/* Buffer aging via primary DMA stream head pointer.
*/
-#define SET_AGE( age, h, w ) \
+#define SET_AGE(age, h, w) \
do { \
(age)->head = h; \
(age)->wrap = w; \
} while (0)
-#define TEST_AGE( age, h, w ) ( (age)->wrap < w || \
- ( (age)->wrap == w && \
- (age)->head < h ) )
+#define TEST_AGE(age, h, w) ((age)->wrap < w || \
+ ((age)->wrap == w && \
+ (age)->head < h))
-#define AGE_BUFFER( buf_priv ) \
+#define AGE_BUFFER(buf_priv) \
do { \
drm_mga_freelist_t *entry = (buf_priv)->list_entry; \
- if ( (buf_priv)->dispatched ) { \
+ if ((buf_priv)->dispatched) { \
entry->age.head = (dev_priv->prim.tail + \
dev_priv->primary->offset); \
entry->age.wrap = dev_priv->sarea_priv->last_wrap; \
@@ -681,7 +676,7 @@ do { \
/* Simple idle test.
*/
-static __inline__ int mga_is_idle(drm_mga_private_t * dev_priv)
+static __inline__ int mga_is_idle(drm_mga_private_t *dev_priv)
{
u32 status = MGA_READ(MGA_STATUS) & MGA_ENGINE_IDLE_MASK;
return (status == MGA_ENDPRDMASTS);
diff --git a/drivers/gpu/drm/mga/mga_irq.c b/drivers/gpu/drm/mga/mga_irq.c
index daa6041a483..2581202297e 100644
--- a/drivers/gpu/drm/mga/mga_irq.c
+++ b/drivers/gpu/drm/mga/mga_irq.c
@@ -76,9 +76,8 @@ irqreturn_t mga_driver_irq_handler(DRM_IRQ_ARGS)
/* In addition to clearing the interrupt-pending bit, we
* have to write to MGA_PRIMEND to re-start the DMA operation.
*/
- if ((prim_start & ~0x03) != (prim_end & ~0x03)) {
+ if ((prim_start & ~0x03) != (prim_end & ~0x03))
MGA_WRITE(MGA_PRIMEND, prim_end);
- }
atomic_inc(&dev_priv->last_fence_retired);
DRM_WAKEUP(&dev_priv->fence_queue);
@@ -120,7 +119,7 @@ void mga_disable_vblank(struct drm_device *dev, int crtc)
/* MGA_WRITE(MGA_IEN, MGA_VLINEIEN | MGA_SOFTRAPEN); */
}
-int mga_driver_fence_wait(struct drm_device * 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;
@@ -139,7 +138,7 @@ int mga_driver_fence_wait(struct drm_device * dev, unsigned int *sequence)
return ret;
}
-void mga_driver_irq_preinstall(struct drm_device * dev)
+void mga_driver_irq_preinstall(struct drm_device *dev)
{
drm_mga_private_t *dev_priv = (drm_mga_private_t *) dev->dev_private;
@@ -162,7 +161,7 @@ int mga_driver_irq_postinstall(struct drm_device *dev)
return 0;
}
-void mga_driver_irq_uninstall(struct drm_device * 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/gpu/drm/mga/mga_state.c b/drivers/gpu/drm/mga/mga_state.c
index a53b848e0f1..fff82045c42 100644
--- a/drivers/gpu/drm/mga/mga_state.c
+++ b/drivers/gpu/drm/mga/mga_state.c
@@ -41,8 +41,8 @@
* DMA hardware state programming functions
*/
-static void mga_emit_clip_rect(drm_mga_private_t * dev_priv,
- struct drm_clip_rect * box)
+static void mga_emit_clip_rect(drm_mga_private_t *dev_priv,
+ 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;
@@ -66,7 +66,7 @@ static void mga_emit_clip_rect(drm_mga_private_t * dev_priv,
ADVANCE_DMA();
}
-static __inline__ void mga_g200_emit_context(drm_mga_private_t * dev_priv)
+static __inline__ void mga_g200_emit_context(drm_mga_private_t *dev_priv)
{
drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
drm_mga_context_regs_t *ctx = &sarea_priv->context_state;
@@ -89,7 +89,7 @@ static __inline__ void mga_g200_emit_context(drm_mga_private_t * dev_priv)
ADVANCE_DMA();
}
-static __inline__ void mga_g400_emit_context(drm_mga_private_t * dev_priv)
+static __inline__ void mga_g400_emit_context(drm_mga_private_t *dev_priv)
{
drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
drm_mga_context_regs_t *ctx = &sarea_priv->context_state;
@@ -116,7 +116,7 @@ static __inline__ void mga_g400_emit_context(drm_mga_private_t * dev_priv)
ADVANCE_DMA();
}
-static __inline__ void mga_g200_emit_tex0(drm_mga_private_t * dev_priv)
+static __inline__ void mga_g200_emit_tex0(drm_mga_private_t *dev_priv)
{
drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
drm_mga_texture_regs_t *tex = &sarea_priv->tex_state[0];
@@ -144,7 +144,7 @@ static __inline__ void mga_g200_emit_tex0(drm_mga_private_t * dev_priv)
ADVANCE_DMA();
}
-static __inline__ void mga_g400_emit_tex0(drm_mga_private_t * dev_priv)
+static __inline__ void mga_g400_emit_tex0(drm_mga_private_t *dev_priv)
{
drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
drm_mga_texture_regs_t *tex = &sarea_priv->tex_state[0];
@@ -184,7 +184,7 @@ static __inline__ void mga_g400_emit_tex0(drm_mga_private_t * dev_priv)
ADVANCE_DMA();
}
-static __inline__ void mga_g400_emit_tex1(drm_mga_private_t * dev_priv)
+static __inline__ void mga_g400_emit_tex1(drm_mga_private_t *dev_priv)
{
drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
drm_mga_texture_regs_t *tex = &sarea_priv->tex_state[1];
@@ -223,7 +223,7 @@ static __inline__ void mga_g400_emit_tex1(drm_mga_private_t * dev_priv)
ADVANCE_DMA();
}
-static __inline__ void mga_g200_emit_pipe(drm_mga_private_t * dev_priv)
+static __inline__ void mga_g200_emit_pipe(drm_mga_private_t *dev_priv)
{
drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
unsigned int pipe = sarea_priv->warp_pipe;
@@ -250,7 +250,7 @@ static __inline__ void mga_g200_emit_pipe(drm_mga_private_t * dev_priv)
ADVANCE_DMA();
}
-static __inline__ void mga_g400_emit_pipe(drm_mga_private_t * dev_priv)
+static __inline__ void mga_g400_emit_pipe(drm_mga_private_t *dev_priv)
{
drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
unsigned int pipe = sarea_priv->warp_pipe;
@@ -327,7 +327,7 @@ static __inline__ void mga_g400_emit_pipe(drm_mga_private_t * dev_priv)
ADVANCE_DMA();
}
-static void mga_g200_emit_state(drm_mga_private_t * dev_priv)
+static void mga_g200_emit_state(drm_mga_private_t *dev_priv)
{
drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
unsigned int dirty = sarea_priv->dirty;
@@ -348,7 +348,7 @@ static void mga_g200_emit_state(drm_mga_private_t * dev_priv)
}
}
-static void mga_g400_emit_state(drm_mga_private_t * dev_priv)
+static void mga_g400_emit_state(drm_mga_private_t *dev_priv)
{
drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
unsigned int dirty = sarea_priv->dirty;
@@ -381,7 +381,7 @@ static void mga_g400_emit_state(drm_mga_private_t * dev_priv)
/* Disallow all write destinations except the front and backbuffer.
*/
-static int mga_verify_context(drm_mga_private_t * dev_priv)
+static int mga_verify_context(drm_mga_private_t *dev_priv)
{
drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
drm_mga_context_regs_t *ctx = &sarea_priv->context_state;
@@ -400,7 +400,7 @@ static int mga_verify_context(drm_mga_private_t * dev_priv)
/* Disallow texture reads from PCI space.
*/
-static int mga_verify_tex(drm_mga_private_t * dev_priv, int unit)
+static int mga_verify_tex(drm_mga_private_t *dev_priv, int unit)
{
drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
drm_mga_texture_regs_t *tex = &sarea_priv->tex_state[unit];
@@ -417,7 +417,7 @@ static int mga_verify_tex(drm_mga_private_t * dev_priv, int unit)
return 0;
}
-static int mga_verify_state(drm_mga_private_t * dev_priv)
+static int mga_verify_state(drm_mga_private_t *dev_priv)
{
drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
unsigned int dirty = sarea_priv->dirty;
@@ -446,7 +446,7 @@ static int mga_verify_state(drm_mga_private_t * dev_priv)
return (ret == 0);
}
-static int mga_verify_iload(drm_mga_private_t * dev_priv,
+static int mga_verify_iload(drm_mga_private_t *dev_priv,
unsigned int dstorg, unsigned int length)
{
if (dstorg < dev_priv->texture_offset ||
@@ -465,7 +465,7 @@ static int mga_verify_iload(drm_mga_private_t * dev_priv,
return 0;
}
-static int mga_verify_blit(drm_mga_private_t * dev_priv,
+static int mga_verify_blit(drm_mga_private_t *dev_priv,
unsigned int srcorg, unsigned int dstorg)
{
if ((srcorg & 0x3) == (MGA_SRCACC_PCI | MGA_SRCMAP_SYSMEM) ||
@@ -480,7 +480,7 @@ static int mga_verify_blit(drm_mga_private_t * dev_priv,
*
*/
-static void mga_dma_dispatch_clear(struct drm_device * 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;
@@ -568,7 +568,7 @@ static void mga_dma_dispatch_clear(struct drm_device * dev, drm_mga_clear_t * cl
FLUSH_DMA();
}
-static void mga_dma_dispatch_swap(struct drm_device * 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;
@@ -622,7 +622,7 @@ static void mga_dma_dispatch_swap(struct drm_device * dev)
DRM_DEBUG("... done.\n");
}
-static void mga_dma_dispatch_vertex(struct drm_device * dev, struct drm_buf * 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(struct drm_device * dev, struct drm_buf * bu
FLUSH_DMA();
}
-static void mga_dma_dispatch_indices(struct drm_device * dev, struct drm_buf * 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(struct drm_device * dev, struct drm_buf * b
/* 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(struct drm_device * dev, struct drm_buf * 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,7 +766,7 @@ static void mga_dma_dispatch_iload(struct drm_device * dev, struct drm_buf * buf
FLUSH_DMA();
}
-static void mga_dma_dispatch_blit(struct drm_device * 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;
@@ -801,9 +801,8 @@ static void mga_dma_dispatch_blit(struct drm_device * dev, drm_mga_blit_t * blit
int w = pbox[i].x2 - pbox[i].x1 - 1;
int start;
- if (blit->ydir == -1) {
+ if (blit->ydir == -1)
srcy = blit->height - srcy - 1;
- }
start = srcy * blit->src_pitch + srcx;
diff --git a/drivers/gpu/drm/mga/mga_warp.c b/drivers/gpu/drm/mga/mga_warp.c
index 9aad4847afd..f172bd5c257 100644
--- a/drivers/gpu/drm/mga/mga_warp.c
+++ b/drivers/gpu/drm/mga/mga_warp.c
@@ -46,7 +46,7 @@ MODULE_FIRMWARE(FIRMWARE_G400);
#define WARP_UCODE_SIZE(size) ALIGN(size, MGA_WARP_CODE_ALIGN)
-int mga_warp_install_microcode(drm_mga_private_t * dev_priv)
+int mga_warp_install_microcode(drm_mga_private_t *dev_priv)
{
unsigned char *vcbase = dev_priv->warp->handle;
unsigned long pcbase = dev_priv->warp->offset;
@@ -133,7 +133,7 @@ out:
#define WMISC_EXPECTED (MGA_WUCODECACHE_ENABLE | MGA_WMASTER_ENABLE)
-int mga_warp_init(drm_mga_private_t * dev_priv)
+int mga_warp_init(drm_mga_private_t *dev_priv)
{
u32 wmisc;
diff --git a/drivers/gpu/drm/nouveau/Kconfig b/drivers/gpu/drm/nouveau/Kconfig
index 1175429da10..d2d28048efb 100644
--- a/drivers/gpu/drm/nouveau/Kconfig
+++ b/drivers/gpu/drm/nouveau/Kconfig
@@ -1,6 +1,6 @@
config DRM_NOUVEAU
tristate "Nouveau (nVidia) cards"
- depends on DRM
+ depends on DRM && PCI
select FW_LOADER
select DRM_KMS_HELPER
select DRM_TTM
@@ -41,4 +41,13 @@ config DRM_I2C_CH7006
This driver is currently only useful if you're also using
the nouveau driver.
+
+config DRM_I2C_SIL164
+ tristate "Silicon Image sil164 TMDS transmitter"
+ default m if DRM_NOUVEAU
+ help
+ Support for sil164 and similar single-link (or dual-link
+ when used in pairs) TMDS transmitters, used in some nVidia
+ video cards.
+
endmenu
diff --git a/drivers/gpu/drm/nouveau/Makefile b/drivers/gpu/drm/nouveau/Makefile
index acd31ed861e..2405d5ef0ca 100644
--- a/drivers/gpu/drm/nouveau/Makefile
+++ b/drivers/gpu/drm/nouveau/Makefile
@@ -9,10 +9,10 @@ nouveau-y := nouveau_drv.o nouveau_state.o nouveau_channel.o nouveau_mem.o \
nouveau_bo.o nouveau_fence.o nouveau_gem.o nouveau_ttm.o \
nouveau_hw.o nouveau_calc.o nouveau_bios.o nouveau_i2c.o \
nouveau_display.o nouveau_connector.o nouveau_fbcon.o \
- nouveau_dp.o nouveau_grctx.o \
+ nouveau_dp.o \
nv04_timer.o \
nv04_mc.o nv40_mc.o nv50_mc.o \
- nv04_fb.o nv10_fb.o nv40_fb.o nv50_fb.o \
+ nv04_fb.o nv10_fb.o nv30_fb.o nv40_fb.o nv50_fb.o \
nv04_fifo.o nv10_fifo.o nv40_fifo.o nv50_fifo.o \
nv04_graph.o nv10_graph.o nv20_graph.o \
nv40_graph.o nv50_graph.o \
@@ -22,7 +22,7 @@ nouveau-y := nouveau_drv.o nouveau_state.o nouveau_channel.o nouveau_mem.o \
nv50_cursor.o nv50_display.o nv50_fbcon.o \
nv04_dac.o nv04_dfp.o nv04_tv.o nv17_tv.o nv17_tv_modes.o \
nv04_crtc.o nv04_display.o nv04_cursor.o nv04_fbcon.o \
- nv17_gpio.o nv50_gpio.o \
+ nv10_gpio.o nv50_gpio.o \
nv50_calc.o
nouveau-$(CONFIG_DRM_NOUVEAU_DEBUG) += nouveau_debugfs.o
diff --git a/drivers/gpu/drm/nouveau/nouveau_acpi.c b/drivers/gpu/drm/nouveau/nouveau_acpi.c
index d4bcca8a513..c17a055ee3e 100644
--- a/drivers/gpu/drm/nouveau/nouveau_acpi.c
+++ b/drivers/gpu/drm/nouveau/nouveau_acpi.c
@@ -3,6 +3,7 @@
#include <linux/slab.h>
#include <acpi/acpi_drivers.h>
#include <acpi/acpi_bus.h>
+#include <acpi/video.h>
#include "drmP.h"
#include "drm.h"
@@ -11,6 +12,7 @@
#include "nouveau_drv.h"
#include "nouveau_drm.h"
#include "nv50_display.h"
+#include "nouveau_connector.h"
#include <linux/vga_switcheroo.h>
@@ -42,7 +44,7 @@ static const char nouveau_dsm_muid[] = {
0xB3, 0x4D, 0x7E, 0x5F, 0xEA, 0x12, 0x9F, 0xD4,
};
-static int nouveau_dsm(acpi_handle handle, int func, int arg, int *result)
+static int nouveau_dsm(acpi_handle handle, int func, int arg, uint32_t *result)
{
struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
struct acpi_object_list input;
@@ -259,3 +261,37 @@ int nouveau_acpi_get_bios_chunk(uint8_t *bios, int offset, int len)
{
return nouveau_rom_call(nouveau_dsm_priv.rom_handle, bios, offset, len);
}
+
+int
+nouveau_acpi_edid(struct drm_device *dev, struct drm_connector *connector)
+{
+ struct nouveau_connector *nv_connector = nouveau_connector(connector);
+ struct acpi_device *acpidev;
+ acpi_handle handle;
+ int type, ret;
+ void *edid;
+
+ switch (connector->connector_type) {
+ case DRM_MODE_CONNECTOR_LVDS:
+ case DRM_MODE_CONNECTOR_eDP:
+ type = ACPI_VIDEO_DISPLAY_LCD;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ handle = DEVICE_ACPI_HANDLE(&dev->pdev->dev);
+ if (!handle)
+ return -ENODEV;
+
+ ret = acpi_bus_get_device(handle, &acpidev);
+ if (ret)
+ return -ENODEV;
+
+ ret = acpi_video_get_edid(acpidev, type, -1, &edid);
+ if (ret < 0)
+ return ret;
+
+ nv_connector->edid = edid;
+ return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.c b/drivers/gpu/drm/nouveau/nouveau_bios.c
index e492919faf4..7369b5e7364 100644
--- a/drivers/gpu/drm/nouveau/nouveau_bios.c
+++ b/drivers/gpu/drm/nouveau/nouveau_bios.c
@@ -28,6 +28,8 @@
#include "nouveau_hw.h"
#include "nouveau_encoder.h"
+#include <linux/io-mapping.h>
+
/* these defines are made up */
#define NV_CIO_CRE_44_HEADA 0x0
#define NV_CIO_CRE_44_HEADB 0x3
@@ -209,20 +211,20 @@ static struct methods shadow_methods[] = {
{ "PCIROM", load_vbios_pci, true },
{ "ACPI", load_vbios_acpi, true },
};
+#define NUM_SHADOW_METHODS ARRAY_SIZE(shadow_methods)
static bool NVShadowVBIOS(struct drm_device *dev, uint8_t *data)
{
- const int nr_methods = ARRAY_SIZE(shadow_methods);
struct methods *methods = shadow_methods;
int testscore = 3;
- int scores[nr_methods], i;
+ int scores[NUM_SHADOW_METHODS], i;
if (nouveau_vbios) {
- for (i = 0; i < nr_methods; i++)
+ for (i = 0; i < NUM_SHADOW_METHODS; i++)
if (!strcasecmp(nouveau_vbios, methods[i].desc))
break;
- if (i < nr_methods) {
+ if (i < NUM_SHADOW_METHODS) {
NV_INFO(dev, "Attempting to use BIOS image from %s\n",
methods[i].desc);
@@ -234,7 +236,7 @@ static bool NVShadowVBIOS(struct drm_device *dev, uint8_t *data)
NV_ERROR(dev, "VBIOS source \'%s\' invalid\n", nouveau_vbios);
}
- for (i = 0; i < nr_methods; i++) {
+ for (i = 0; i < NUM_SHADOW_METHODS; i++) {
NV_TRACE(dev, "Attempting to load BIOS image from %s\n",
methods[i].desc);
data[0] = data[1] = 0; /* avoid reuse of previous image */
@@ -245,7 +247,7 @@ static bool NVShadowVBIOS(struct drm_device *dev, uint8_t *data)
}
while (--testscore > 0) {
- for (i = 0; i < nr_methods; i++) {
+ for (i = 0; i < NUM_SHADOW_METHODS; i++) {
if (scores[i] == testscore) {
NV_TRACE(dev, "Using BIOS image from %s\n",
methods[i].desc);
@@ -920,7 +922,7 @@ init_io_restrict_prog(struct nvbios *bios, uint16_t offset,
NV_ERROR(bios->dev,
"0x%04X: Config 0x%02X exceeds maximal bound 0x%02X\n",
offset, config, count);
- return -EINVAL;
+ return len;
}
configval = ROM32(bios->data[offset + 11 + config * 4]);
@@ -1022,7 +1024,7 @@ init_io_restrict_pll(struct nvbios *bios, uint16_t offset,
NV_ERROR(bios->dev,
"0x%04X: Config 0x%02X exceeds maximal bound 0x%02X\n",
offset, config, count);
- return -EINVAL;
+ return len;
}
freq = ROM16(bios->data[offset + 12 + config * 2]);
@@ -1194,7 +1196,7 @@ init_dp_condition(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
dpe = nouveau_bios_dp_table(dev, dcb, &dummy);
if (!dpe) {
NV_ERROR(dev, "0x%04X: INIT_3A: no encoder table!!\n", offset);
- return -EINVAL;
+ return 3;
}
switch (cond) {
@@ -1218,12 +1220,16 @@ init_dp_condition(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
int ret;
auxch = nouveau_i2c_find(dev, bios->display.output->i2c_index);
- if (!auxch)
- return -ENODEV;
+ if (!auxch) {
+ NV_ERROR(dev, "0x%04X: couldn't get auxch\n", offset);
+ return 3;
+ }
ret = nouveau_dp_auxch(auxch, 9, 0xd, &cond, 1);
- if (ret)
- return ret;
+ if (ret) {
+ NV_ERROR(dev, "0x%04X: auxch rd fail: %d\n", offset, ret);
+ return 3;
+ }
if (cond & 1)
iexec->execute = false;
@@ -1392,7 +1398,7 @@ init_io_restrict_pll2(struct nvbios *bios, uint16_t offset,
NV_ERROR(bios->dev,
"0x%04X: Config 0x%02X exceeds maximal bound 0x%02X\n",
offset, config, count);
- return -EINVAL;
+ return len;
}
freq = ROM32(bios->data[offset + 11 + config * 4]);
@@ -1452,6 +1458,7 @@ init_i2c_byte(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
* "mask n" and OR it with "data n" before writing it back to the device
*/
+ struct drm_device *dev = bios->dev;
uint8_t i2c_index = bios->data[offset + 1];
uint8_t i2c_address = bios->data[offset + 2] >> 1;
uint8_t count = bios->data[offset + 3];
@@ -1466,9 +1473,11 @@ init_i2c_byte(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
"Count: 0x%02X\n",
offset, i2c_index, i2c_address, count);
- chan = init_i2c_device_find(bios->dev, i2c_index);
- if (!chan)
- return -ENODEV;
+ chan = init_i2c_device_find(dev, i2c_index);
+ if (!chan) {
+ NV_ERROR(dev, "0x%04X: i2c bus not found\n", offset);
+ return len;
+ }
for (i = 0; i < count; i++) {
uint8_t reg = bios->data[offset + 4 + i * 3];
@@ -1479,8 +1488,10 @@ init_i2c_byte(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
ret = i2c_smbus_xfer(&chan->adapter, i2c_address, 0,
I2C_SMBUS_READ, reg,
I2C_SMBUS_BYTE_DATA, &val);
- if (ret < 0)
- return ret;
+ if (ret < 0) {
+ NV_ERROR(dev, "0x%04X: i2c rd fail: %d\n", offset, ret);
+ return len;
+ }
BIOSLOG(bios, "0x%04X: I2CReg: 0x%02X, Value: 0x%02X, "
"Mask: 0x%02X, Data: 0x%02X\n",
@@ -1494,8 +1505,10 @@ init_i2c_byte(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
ret = i2c_smbus_xfer(&chan->adapter, i2c_address, 0,
I2C_SMBUS_WRITE, reg,
I2C_SMBUS_BYTE_DATA, &val);
- if (ret < 0)
- return ret;
+ if (ret < 0) {
+ NV_ERROR(dev, "0x%04X: i2c wr fail: %d\n", offset, ret);
+ return len;
+ }
}
return len;
@@ -1520,6 +1533,7 @@ init_zm_i2c_byte(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
* "DCB I2C table entry index", set the register to "data n"
*/
+ struct drm_device *dev = bios->dev;
uint8_t i2c_index = bios->data[offset + 1];
uint8_t i2c_address = bios->data[offset + 2] >> 1;
uint8_t count = bios->data[offset + 3];
@@ -1534,9 +1548,11 @@ init_zm_i2c_byte(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
"Count: 0x%02X\n",
offset, i2c_index, i2c_address, count);
- chan = init_i2c_device_find(bios->dev, i2c_index);
- if (!chan)
- return -ENODEV;
+ chan = init_i2c_device_find(dev, i2c_index);
+ if (!chan) {
+ NV_ERROR(dev, "0x%04X: i2c bus not found\n", offset);
+ return len;
+ }
for (i = 0; i < count; i++) {
uint8_t reg = bios->data[offset + 4 + i * 2];
@@ -1553,8 +1569,10 @@ init_zm_i2c_byte(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
ret = i2c_smbus_xfer(&chan->adapter, i2c_address, 0,
I2C_SMBUS_WRITE, reg,
I2C_SMBUS_BYTE_DATA, &val);
- if (ret < 0)
- return ret;
+ if (ret < 0) {
+ NV_ERROR(dev, "0x%04X: i2c wr fail: %d\n", offset, ret);
+ return len;
+ }
}
return len;
@@ -1577,6 +1595,7 @@ init_zm_i2c(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
* address" on the I2C bus given by "DCB I2C table entry index"
*/
+ struct drm_device *dev = bios->dev;
uint8_t i2c_index = bios->data[offset + 1];
uint8_t i2c_address = bios->data[offset + 2] >> 1;
uint8_t count = bios->data[offset + 3];
@@ -1584,7 +1603,7 @@ init_zm_i2c(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
struct nouveau_i2c_chan *chan;
struct i2c_msg msg;
uint8_t data[256];
- int i;
+ int ret, i;
if (!iexec->execute)
return len;
@@ -1593,9 +1612,11 @@ init_zm_i2c(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
"Count: 0x%02X\n",
offset, i2c_index, i2c_address, count);
- chan = init_i2c_device_find(bios->dev, i2c_index);
- if (!chan)
- return -ENODEV;
+ chan = init_i2c_device_find(dev, i2c_index);
+ if (!chan) {
+ NV_ERROR(dev, "0x%04X: i2c bus not found\n", offset);
+ return len;
+ }
for (i = 0; i < count; i++) {
data[i] = bios->data[offset + 4 + i];
@@ -1608,8 +1629,11 @@ init_zm_i2c(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
msg.flags = 0;
msg.len = count;
msg.buf = data;
- if (i2c_transfer(&chan->adapter, &msg, 1) != 1)
- return -EIO;
+ ret = i2c_transfer(&chan->adapter, &msg, 1);
+ if (ret != 1) {
+ NV_ERROR(dev, "0x%04X: i2c wr fail: %d\n", offset, ret);
+ return len;
+ }
}
return len;
@@ -1633,6 +1657,7 @@ init_tmds(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
* used -- see get_tmds_index_reg()
*/
+ struct drm_device *dev = bios->dev;
uint8_t mlv = bios->data[offset + 1];
uint32_t tmdsaddr = bios->data[offset + 2];
uint8_t mask = bios->data[offset + 3];
@@ -1647,8 +1672,10 @@ init_tmds(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
offset, mlv, tmdsaddr, mask, data);
reg = get_tmds_index_reg(bios->dev, mlv);
- if (!reg)
- return -EINVAL;
+ if (!reg) {
+ NV_ERROR(dev, "0x%04X: no tmds_index_reg\n", offset);
+ return 5;
+ }
bios_wr32(bios, reg,
tmdsaddr | NV_PRAMDAC_FP_TMDS_CONTROL_WRITE_DISABLE);
@@ -1678,6 +1705,7 @@ init_zm_tmds_group(struct nvbios *bios, uint16_t offset,
* register is used -- see get_tmds_index_reg()
*/
+ struct drm_device *dev = bios->dev;
uint8_t mlv = bios->data[offset + 1];
uint8_t count = bios->data[offset + 2];
int len = 3 + count * 2;
@@ -1691,8 +1719,10 @@ init_zm_tmds_group(struct nvbios *bios, uint16_t offset,
offset, mlv, count);
reg = get_tmds_index_reg(bios->dev, mlv);
- if (!reg)
- return -EINVAL;
+ if (!reg) {
+ NV_ERROR(dev, "0x%04X: no tmds_index_reg\n", offset);
+ return len;
+ }
for (i = 0; i < count; i++) {
uint8_t tmdsaddr = bios->data[offset + 3 + i * 2];
@@ -2039,6 +2069,323 @@ init_zm_index_io(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
return 5;
}
+static inline void
+bios_md32(struct nvbios *bios, uint32_t reg,
+ uint32_t mask, uint32_t val)
+{
+ bios_wr32(bios, reg, (bios_rd32(bios, reg) & ~mask) | val);
+}
+
+static uint32_t
+peek_fb(struct drm_device *dev, struct io_mapping *fb,
+ uint32_t off)
+{
+ uint32_t val = 0;
+
+ if (off < pci_resource_len(dev->pdev, 1)) {
+ uint32_t __iomem *p = io_mapping_map_atomic_wc(fb, off, KM_USER0);
+
+ val = ioread32(p);
+
+ io_mapping_unmap_atomic(p, KM_USER0);
+ }
+
+ return val;
+}
+
+static void
+poke_fb(struct drm_device *dev, struct io_mapping *fb,
+ uint32_t off, uint32_t val)
+{
+ if (off < pci_resource_len(dev->pdev, 1)) {
+ uint32_t __iomem *p = io_mapping_map_atomic_wc(fb, off, KM_USER0);
+
+ iowrite32(val, p);
+ wmb();
+
+ io_mapping_unmap_atomic(p, KM_USER0);
+ }
+}
+
+static inline bool
+read_back_fb(struct drm_device *dev, struct io_mapping *fb,
+ uint32_t off, uint32_t val)
+{
+ poke_fb(dev, fb, off, val);
+ return val == peek_fb(dev, fb, off);
+}
+
+static int
+nv04_init_compute_mem(struct nvbios *bios)
+{
+ struct drm_device *dev = bios->dev;
+ uint32_t patt = 0xdeadbeef;
+ struct io_mapping *fb;
+ int i;
+
+ /* Map the framebuffer aperture */
+ fb = io_mapping_create_wc(pci_resource_start(dev->pdev, 1),
+ pci_resource_len(dev->pdev, 1));
+ if (!fb)
+ return -ENOMEM;
+
+ /* Sequencer and refresh off */
+ NVWriteVgaSeq(dev, 0, 1, NVReadVgaSeq(dev, 0, 1) | 0x20);
+ bios_md32(bios, NV04_PFB_DEBUG_0, 0, NV04_PFB_DEBUG_0_REFRESH_OFF);
+
+ bios_md32(bios, NV04_PFB_BOOT_0, ~0,
+ NV04_PFB_BOOT_0_RAM_AMOUNT_16MB |
+ NV04_PFB_BOOT_0_RAM_WIDTH_128 |
+ NV04_PFB_BOOT_0_RAM_TYPE_SGRAM_16MBIT);
+
+ for (i = 0; i < 4; i++)
+ poke_fb(dev, fb, 4 * i, patt);
+
+ poke_fb(dev, fb, 0x400000, patt + 1);
+
+ if (peek_fb(dev, fb, 0) == patt + 1) {
+ bios_md32(bios, NV04_PFB_BOOT_0, NV04_PFB_BOOT_0_RAM_TYPE,
+ NV04_PFB_BOOT_0_RAM_TYPE_SDRAM_16MBIT);
+ bios_md32(bios, NV04_PFB_DEBUG_0,
+ NV04_PFB_DEBUG_0_REFRESH_OFF, 0);
+
+ for (i = 0; i < 4; i++)
+ poke_fb(dev, fb, 4 * i, patt);
+
+ if ((peek_fb(dev, fb, 0xc) & 0xffff) != (patt & 0xffff))
+ bios_md32(bios, NV04_PFB_BOOT_0,
+ NV04_PFB_BOOT_0_RAM_WIDTH_128 |
+ NV04_PFB_BOOT_0_RAM_AMOUNT,
+ NV04_PFB_BOOT_0_RAM_AMOUNT_8MB);
+
+ } else if ((peek_fb(dev, fb, 0xc) & 0xffff0000) !=
+ (patt & 0xffff0000)) {
+ bios_md32(bios, NV04_PFB_BOOT_0,
+ NV04_PFB_BOOT_0_RAM_WIDTH_128 |
+ NV04_PFB_BOOT_0_RAM_AMOUNT,
+ NV04_PFB_BOOT_0_RAM_AMOUNT_4MB);
+
+ } else if (peek_fb(dev, fb, 0) == patt) {
+ if (read_back_fb(dev, fb, 0x800000, patt))
+ bios_md32(bios, NV04_PFB_BOOT_0,
+ NV04_PFB_BOOT_0_RAM_AMOUNT,
+ NV04_PFB_BOOT_0_RAM_AMOUNT_8MB);
+ else
+ bios_md32(bios, NV04_PFB_BOOT_0,
+ NV04_PFB_BOOT_0_RAM_AMOUNT,
+ NV04_PFB_BOOT_0_RAM_AMOUNT_4MB);
+
+ bios_md32(bios, NV04_PFB_BOOT_0, NV04_PFB_BOOT_0_RAM_TYPE,
+ NV04_PFB_BOOT_0_RAM_TYPE_SGRAM_8MBIT);
+
+ } else if (!read_back_fb(dev, fb, 0x800000, patt)) {
+ bios_md32(bios, NV04_PFB_BOOT_0, NV04_PFB_BOOT_0_RAM_AMOUNT,
+ NV04_PFB_BOOT_0_RAM_AMOUNT_8MB);
+
+ }
+
+ /* Refresh on, sequencer on */
+ bios_md32(bios, NV04_PFB_DEBUG_0, NV04_PFB_DEBUG_0_REFRESH_OFF, 0);
+ NVWriteVgaSeq(dev, 0, 1, NVReadVgaSeq(dev, 0, 1) & ~0x20);
+
+ io_mapping_free(fb);
+ return 0;
+}
+
+static const uint8_t *
+nv05_memory_config(struct nvbios *bios)
+{
+ /* Defaults for BIOSes lacking a memory config table */
+ static const uint8_t default_config_tab[][2] = {
+ { 0x24, 0x00 },
+ { 0x28, 0x00 },
+ { 0x24, 0x01 },
+ { 0x1f, 0x00 },
+ { 0x0f, 0x00 },
+ { 0x17, 0x00 },
+ { 0x06, 0x00 },
+ { 0x00, 0x00 }
+ };
+ int i = (bios_rd32(bios, NV_PEXTDEV_BOOT_0) &
+ NV_PEXTDEV_BOOT_0_RAMCFG) >> 2;
+
+ if (bios->legacy.mem_init_tbl_ptr)
+ return &bios->data[bios->legacy.mem_init_tbl_ptr + 2 * i];
+ else
+ return default_config_tab[i];
+}
+
+static int
+nv05_init_compute_mem(struct nvbios *bios)
+{
+ struct drm_device *dev = bios->dev;
+ const uint8_t *ramcfg = nv05_memory_config(bios);
+ uint32_t patt = 0xdeadbeef;
+ struct io_mapping *fb;
+ int i, v;
+
+ /* Map the framebuffer aperture */
+ fb = io_mapping_create_wc(pci_resource_start(dev->pdev, 1),
+ pci_resource_len(dev->pdev, 1));
+ if (!fb)
+ return -ENOMEM;
+
+ /* Sequencer off */
+ NVWriteVgaSeq(dev, 0, 1, NVReadVgaSeq(dev, 0, 1) | 0x20);
+
+ if (bios_rd32(bios, NV04_PFB_BOOT_0) & NV04_PFB_BOOT_0_UMA_ENABLE)
+ goto out;
+
+ bios_md32(bios, NV04_PFB_DEBUG_0, NV04_PFB_DEBUG_0_REFRESH_OFF, 0);
+
+ /* If present load the hardcoded scrambling table */
+ if (bios->legacy.mem_init_tbl_ptr) {
+ uint32_t *scramble_tab = (uint32_t *)&bios->data[
+ bios->legacy.mem_init_tbl_ptr + 0x10];
+
+ for (i = 0; i < 8; i++)
+ bios_wr32(bios, NV04_PFB_SCRAMBLE(i),
+ ROM32(scramble_tab[i]));
+ }
+
+ /* Set memory type/width/length defaults depending on the straps */
+ bios_md32(bios, NV04_PFB_BOOT_0, 0x3f, ramcfg[0]);
+
+ if (ramcfg[1] & 0x80)
+ bios_md32(bios, NV04_PFB_CFG0, 0, NV04_PFB_CFG0_SCRAMBLE);
+
+ bios_md32(bios, NV04_PFB_CFG1, 0x700001, (ramcfg[1] & 1) << 20);
+ bios_md32(bios, NV04_PFB_CFG1, 0, 1);
+
+ /* Probe memory bus width */
+ for (i = 0; i < 4; i++)
+ poke_fb(dev, fb, 4 * i, patt);
+
+ if (peek_fb(dev, fb, 0xc) != patt)
+ bios_md32(bios, NV04_PFB_BOOT_0,
+ NV04_PFB_BOOT_0_RAM_WIDTH_128, 0);
+
+ /* Probe memory length */
+ v = bios_rd32(bios, NV04_PFB_BOOT_0) & NV04_PFB_BOOT_0_RAM_AMOUNT;
+
+ if (v == NV04_PFB_BOOT_0_RAM_AMOUNT_32MB &&
+ (!read_back_fb(dev, fb, 0x1000000, ++patt) ||
+ !read_back_fb(dev, fb, 0, ++patt)))
+ bios_md32(bios, NV04_PFB_BOOT_0, NV04_PFB_BOOT_0_RAM_AMOUNT,
+ NV04_PFB_BOOT_0_RAM_AMOUNT_16MB);
+
+ if (v == NV04_PFB_BOOT_0_RAM_AMOUNT_16MB &&
+ !read_back_fb(dev, fb, 0x800000, ++patt))
+ bios_md32(bios, NV04_PFB_BOOT_0, NV04_PFB_BOOT_0_RAM_AMOUNT,
+ NV04_PFB_BOOT_0_RAM_AMOUNT_8MB);
+
+ if (!read_back_fb(dev, fb, 0x400000, ++patt))
+ bios_md32(bios, NV04_PFB_BOOT_0, NV04_PFB_BOOT_0_RAM_AMOUNT,
+ NV04_PFB_BOOT_0_RAM_AMOUNT_4MB);
+
+out:
+ /* Sequencer on */
+ NVWriteVgaSeq(dev, 0, 1, NVReadVgaSeq(dev, 0, 1) & ~0x20);
+
+ io_mapping_free(fb);
+ return 0;
+}
+
+static int
+nv10_init_compute_mem(struct nvbios *bios)
+{
+ struct drm_device *dev = bios->dev;
+ struct drm_nouveau_private *dev_priv = bios->dev->dev_private;
+ const int mem_width[] = { 0x10, 0x00, 0x20 };
+ const int mem_width_count = (dev_priv->chipset >= 0x17 ? 3 : 2);
+ uint32_t patt = 0xdeadbeef;
+ struct io_mapping *fb;
+ int i, j, k;
+
+ /* Map the framebuffer aperture */
+ fb = io_mapping_create_wc(pci_resource_start(dev->pdev, 1),
+ pci_resource_len(dev->pdev, 1));
+ if (!fb)
+ return -ENOMEM;
+
+ bios_wr32(bios, NV10_PFB_REFCTRL, NV10_PFB_REFCTRL_VALID_1);
+
+ /* Probe memory bus width */
+ for (i = 0; i < mem_width_count; i++) {
+ bios_md32(bios, NV04_PFB_CFG0, 0x30, mem_width[i]);
+
+ for (j = 0; j < 4; j++) {
+ for (k = 0; k < 4; k++)
+ poke_fb(dev, fb, 0x1c, 0);
+
+ poke_fb(dev, fb, 0x1c, patt);
+ poke_fb(dev, fb, 0x3c, 0);
+
+ if (peek_fb(dev, fb, 0x1c) == patt)
+ goto mem_width_found;
+ }
+ }
+
+mem_width_found:
+ patt <<= 1;
+
+ /* Probe amount of installed memory */
+ for (i = 0; i < 4; i++) {
+ int off = bios_rd32(bios, NV04_PFB_FIFO_DATA) - 0x100000;
+
+ poke_fb(dev, fb, off, patt);
+ poke_fb(dev, fb, 0, 0);
+
+ peek_fb(dev, fb, 0);
+ peek_fb(dev, fb, 0);
+ peek_fb(dev, fb, 0);
+ peek_fb(dev, fb, 0);
+
+ if (peek_fb(dev, fb, off) == patt)
+ goto amount_found;
+ }
+
+ /* IC missing - disable the upper half memory space. */
+ bios_md32(bios, NV04_PFB_CFG0, 0x1000, 0);
+
+amount_found:
+ io_mapping_free(fb);
+ return 0;
+}
+
+static int
+nv20_init_compute_mem(struct nvbios *bios)
+{
+ struct drm_device *dev = bios->dev;
+ struct drm_nouveau_private *dev_priv = bios->dev->dev_private;
+ uint32_t mask = (dev_priv->chipset >= 0x25 ? 0x300 : 0x900);
+ uint32_t amount, off;
+ struct io_mapping *fb;
+
+ /* Map the framebuffer aperture */
+ fb = io_mapping_create_wc(pci_resource_start(dev->pdev, 1),
+ pci_resource_len(dev->pdev, 1));
+ if (!fb)
+ return -ENOMEM;
+
+ bios_wr32(bios, NV10_PFB_REFCTRL, NV10_PFB_REFCTRL_VALID_1);
+
+ /* Allow full addressing */
+ bios_md32(bios, NV04_PFB_CFG0, 0, mask);
+
+ amount = bios_rd32(bios, NV04_PFB_FIFO_DATA);
+ for (off = amount; off > 0x2000000; off -= 0x2000000)
+ poke_fb(dev, fb, off - 4, off);
+
+ amount = bios_rd32(bios, NV04_PFB_FIFO_DATA);
+ if (amount != peek_fb(dev, fb, amount - 4))
+ /* IC missing - disable the upper half memory space. */
+ bios_md32(bios, NV04_PFB_CFG0, mask, 0);
+
+ io_mapping_free(fb);
+ return 0;
+}
+
static int
init_compute_mem(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
{
@@ -2047,64 +2394,57 @@ init_compute_mem(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
*
* offset (8 bit): opcode
*
- * This opcode is meant to set NV_PFB_CFG0 (0x100200) appropriately so
- * that the hardware can correctly calculate how much VRAM it has
- * (and subsequently report that value in NV_PFB_CSTATUS (0x10020C))
+ * This opcode is meant to set the PFB memory config registers
+ * appropriately so that we can correctly calculate how much VRAM it
+ * has (on nv10 and better chipsets the amount of installed VRAM is
+ * subsequently reported in NV_PFB_CSTATUS (0x10020C)).
*
- * The implementation of this opcode in general consists of two parts:
- * 1) determination of the memory bus width
- * 2) determination of how many of the card's RAM pads have ICs attached
+ * The implementation of this opcode in general consists of several
+ * parts:
*
- * 1) is done by a cunning combination of writes to offsets 0x1c and
- * 0x3c in the framebuffer, and seeing whether the written values are
- * read back correctly. This then affects bits 4-7 of NV_PFB_CFG0
+ * 1) Determination of memory type and density. Only necessary for
+ * really old chipsets, the memory type reported by the strap bits
+ * (0x101000) is assumed to be accurate on nv05 and newer.
*
- * 2) is done by a cunning combination of writes to an offset slightly
- * less than the maximum memory reported by NV_PFB_CSTATUS, then seeing
- * if the test pattern can be read back. This then affects bits 12-15 of
- * NV_PFB_CFG0
+ * 2) Determination of the memory bus width. Usually done by a cunning
+ * combination of writes to offsets 0x1c and 0x3c in the fb, and
+ * seeing whether the written values are read back correctly.
*
- * In this context a "cunning combination" may include multiple reads
- * and writes to varying locations, often alternating the test pattern
- * and 0, doubtless to make sure buffers are filled, residual charges
- * on tracks are removed etc.
+ * Only necessary on nv0x-nv1x and nv34, on the other cards we can
+ * trust the straps.
*
- * Unfortunately, the "cunning combination"s mentioned above, and the
- * changes to the bits in NV_PFB_CFG0 differ with nearly every bios
- * trace I have.
+ * 3) Determination of how many of the card's RAM pads have ICs
+ * attached, usually done by a cunning combination of writes to an
+ * offset slightly less than the maximum memory reported by
+ * NV_PFB_CSTATUS, then seeing if the test pattern can be read back.
*
- * Therefore, we cheat and assume the value of NV_PFB_CFG0 with which
- * we started was correct, and use that instead
+ * This appears to be a NOP on IGPs and NV4x or newer chipsets, both io
+ * logs of the VBIOS and kmmio traces of the binary driver POSTing the
+ * card show nothing being done for this opcode. Why is it still listed
+ * in the table?!
*/
/* no iexec->execute check by design */
- /*
- * This appears to be a NOP on G8x chipsets, both io logs of the VBIOS
- * and kmmio traces of the binary driver POSTing the card show nothing
- * being done for this opcode. why is it still listed in the table?!
- */
-
struct drm_nouveau_private *dev_priv = bios->dev->dev_private;
+ int ret;
- if (dev_priv->card_type >= NV_40)
- return 1;
-
- /*
- * On every card I've seen, this step gets done for us earlier in
- * the init scripts
- uint8_t crdata = bios_idxprt_rd(dev, NV_VIO_SRX, 0x01);
- bios_idxprt_wr(dev, NV_VIO_SRX, 0x01, crdata | 0x20);
- */
-
- /*
- * This also has probably been done in the scripts, but an mmio trace of
- * s3 resume shows nvidia doing it anyway (unlike the NV_VIO_SRX write)
- */
- bios_wr32(bios, NV_PFB_REFCTRL, NV_PFB_REFCTRL_VALID_1);
+ if (dev_priv->chipset >= 0x40 ||
+ dev_priv->chipset == 0x1a ||
+ dev_priv->chipset == 0x1f)
+ ret = 0;
+ else if (dev_priv->chipset >= 0x20 &&
+ dev_priv->chipset != 0x34)
+ ret = nv20_init_compute_mem(bios);
+ else if (dev_priv->chipset >= 0x10)
+ ret = nv10_init_compute_mem(bios);
+ else if (dev_priv->chipset >= 0x5)
+ ret = nv05_init_compute_mem(bios);
+ else
+ ret = nv04_init_compute_mem(bios);
- /* write back the saved configuration value */
- bios_wr32(bios, NV_PFB_CFG0, bios->state.saved_nv_pfb_cfg0);
+ if (ret)
+ return ret;
return 1;
}
@@ -2131,7 +2471,8 @@ init_reset(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
/* no iexec->execute check by design */
pci_nv_19 = bios_rd32(bios, NV_PBUS_PCI_NV_19);
- bios_wr32(bios, NV_PBUS_PCI_NV_19, 0);
+ bios_wr32(bios, NV_PBUS_PCI_NV_19, pci_nv_19 & ~0xf00);
+
bios_wr32(bios, reg, value1);
udelay(10);
@@ -2167,7 +2508,7 @@ init_configure_mem(struct nvbios *bios, uint16_t offset,
uint32_t reg, data;
if (bios->major_version > 2)
- return -ENODEV;
+ return 0;
bios_idxprt_wr(bios, NV_VIO_SRX, NV_VIO_SR_CLOCK_INDEX, bios_idxprt_rd(
bios, NV_VIO_SRX, NV_VIO_SR_CLOCK_INDEX) | 0x20);
@@ -2180,14 +2521,14 @@ init_configure_mem(struct nvbios *bios, uint16_t offset,
reg = ROM32(bios->data[seqtbloffs += 4])) {
switch (reg) {
- case NV_PFB_PRE:
- data = NV_PFB_PRE_CMD_PRECHARGE;
+ case NV04_PFB_PRE:
+ data = NV04_PFB_PRE_CMD_PRECHARGE;
break;
- case NV_PFB_PAD:
- data = NV_PFB_PAD_CKE_NORMAL;
+ case NV04_PFB_PAD:
+ data = NV04_PFB_PAD_CKE_NORMAL;
break;
- case NV_PFB_REF:
- data = NV_PFB_REF_CMD_REFRESH;
+ case NV04_PFB_REF:
+ data = NV04_PFB_REF_CMD_REFRESH;
break;
default:
data = ROM32(bios->data[meminitdata]);
@@ -2222,7 +2563,7 @@ init_configure_clk(struct nvbios *bios, uint16_t offset,
int clock;
if (bios->major_version > 2)
- return -ENODEV;
+ return 0;
clock = ROM16(bios->data[meminitoffs + 4]) * 10;
setPLL(bios, NV_PRAMDAC_NVPLL_COEFF, clock);
@@ -2255,7 +2596,7 @@ init_configure_preinit(struct nvbios *bios, uint16_t offset,
uint8_t cr3c = ((straps << 2) & 0xf0) | (straps & (1 << 6));
if (bios->major_version > 2)
- return -ENODEV;
+ return 0;
bios_idxprt_wr(bios, NV_CIO_CRX__COLOR,
NV_CIO_CRE_SCRATCH4__INDEX, cr3c);
@@ -2389,7 +2730,7 @@ init_ram_condition(struct nvbios *bios, uint16_t offset,
* offset + 1 (8 bit): mask
* offset + 2 (8 bit): cmpval
*
- * Test if (NV_PFB_BOOT_0 & "mask") equals "cmpval".
+ * Test if (NV04_PFB_BOOT_0 & "mask") equals "cmpval".
* If condition not met skip subsequent opcodes until condition is
* inverted (INIT_NOT), or we hit INIT_RESUME
*/
@@ -2401,7 +2742,7 @@ init_ram_condition(struct nvbios *bios, uint16_t offset,
if (!iexec->execute)
return 3;
- data = bios_rd32(bios, NV_PFB_BOOT_0) & mask;
+ data = bios_rd32(bios, NV04_PFB_BOOT_0) & mask;
BIOSLOG(bios, "0x%04X: Checking if 0x%08X equals 0x%08X\n",
offset, data, cmpval);
@@ -2795,12 +3136,13 @@ init_gpio(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
*/
struct drm_nouveau_private *dev_priv = bios->dev->dev_private;
+ struct nouveau_gpio_engine *pgpio = &dev_priv->engine.gpio;
const uint32_t nv50_gpio_ctl[2] = { 0xe100, 0xe28c };
int i;
if (dev_priv->card_type != NV_50) {
NV_ERROR(bios->dev, "INIT_GPIO on unsupported chipset\n");
- return -ENODEV;
+ return 1;
}
if (!iexec->execute)
@@ -2815,7 +3157,7 @@ init_gpio(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
BIOSLOG(bios, "0x%04X: set gpio 0x%02x, state %d\n",
offset, gpio->tag, gpio->state_default);
if (bios->execute)
- nv50_gpio_set(bios->dev, gpio->tag, gpio->state_default);
+ pgpio->set(bios->dev, gpio->tag, gpio->state_default);
/* The NVIDIA binary driver doesn't appear to actually do
* any of this, my VBIOS does however.
@@ -2872,10 +3214,7 @@ init_ram_restrict_zm_reg_group(struct nvbios *bios, uint16_t offset,
uint8_t index;
int i;
-
- if (!iexec->execute)
- return len;
-
+ /* critical! to know the length of the opcode */;
if (!blocklen) {
NV_ERROR(bios->dev,
"0x%04X: Zero block length - has the M table "
@@ -2883,6 +3222,9 @@ init_ram_restrict_zm_reg_group(struct nvbios *bios, uint16_t offset,
return -EINVAL;
}
+ if (!iexec->execute)
+ return len;
+
strap_ramcfg = (bios_rd32(bios, NV_PEXTDEV_BOOT_0) >> 2) & 0xf;
index = bios->data[bios->ram_restrict_tbl_ptr + strap_ramcfg];
@@ -3064,14 +3406,14 @@ init_auxch(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
if (!bios->display.output) {
NV_ERROR(dev, "INIT_AUXCH: no active output\n");
- return -EINVAL;
+ return len;
}
auxch = init_i2c_device_find(dev, bios->display.output->i2c_index);
if (!auxch) {
NV_ERROR(dev, "INIT_AUXCH: couldn't get auxch %d\n",
bios->display.output->i2c_index);
- return -ENODEV;
+ return len;
}
if (!iexec->execute)
@@ -3084,7 +3426,7 @@ init_auxch(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
ret = nouveau_dp_auxch(auxch, 9, addr, &data, 1);
if (ret) {
NV_ERROR(dev, "INIT_AUXCH: rd auxch fail %d\n", ret);
- return ret;
+ return len;
}
data &= bios->data[offset + 0];
@@ -3093,7 +3435,7 @@ init_auxch(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
ret = nouveau_dp_auxch(auxch, 8, addr, &data, 1);
if (ret) {
NV_ERROR(dev, "INIT_AUXCH: wr auxch fail %d\n", ret);
- return ret;
+ return len;
}
}
@@ -3123,14 +3465,14 @@ init_zm_auxch(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
if (!bios->display.output) {
NV_ERROR(dev, "INIT_ZM_AUXCH: no active output\n");
- return -EINVAL;
+ return len;
}
auxch = init_i2c_device_find(dev, bios->display.output->i2c_index);
if (!auxch) {
NV_ERROR(dev, "INIT_ZM_AUXCH: couldn't get auxch %d\n",
bios->display.output->i2c_index);
- return -ENODEV;
+ return len;
}
if (!iexec->execute)
@@ -3141,7 +3483,7 @@ init_zm_auxch(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
ret = nouveau_dp_auxch(auxch, 8, addr, &bios->data[offset], 1);
if (ret) {
NV_ERROR(dev, "INIT_ZM_AUXCH: wr auxch fail %d\n", ret);
- return ret;
+ return len;
}
}
@@ -5151,10 +5493,14 @@ static int parse_bmp_structure(struct drm_device *dev, struct nvbios *bios, unsi
bios->legacy.i2c_indices.crt = bios->data[legacy_i2c_offset];
bios->legacy.i2c_indices.tv = bios->data[legacy_i2c_offset + 1];
bios->legacy.i2c_indices.panel = bios->data[legacy_i2c_offset + 2];
- bios->dcb.i2c[0].write = bios->data[legacy_i2c_offset + 4];
- bios->dcb.i2c[0].read = bios->data[legacy_i2c_offset + 5];
- bios->dcb.i2c[1].write = bios->data[legacy_i2c_offset + 6];
- bios->dcb.i2c[1].read = bios->data[legacy_i2c_offset + 7];
+ if (bios->data[legacy_i2c_offset + 4])
+ bios->dcb.i2c[0].write = bios->data[legacy_i2c_offset + 4];
+ if (bios->data[legacy_i2c_offset + 5])
+ bios->dcb.i2c[0].read = bios->data[legacy_i2c_offset + 5];
+ if (bios->data[legacy_i2c_offset + 6])
+ bios->dcb.i2c[1].write = bios->data[legacy_i2c_offset + 6];
+ if (bios->data[legacy_i2c_offset + 7])
+ bios->dcb.i2c[1].read = bios->data[legacy_i2c_offset + 7];
if (bmplength > 74) {
bios->fmaxvco = ROM32(bmp[67]);
@@ -5589,9 +5935,12 @@ parse_dcb20_entry(struct drm_device *dev, struct dcb_table *dcb,
if (conf & 0x4 || conf & 0x8)
entry->lvdsconf.use_power_scripts = true;
} else {
- mask = ~0x5;
+ mask = ~0x7;
+ if (conf & 0x2)
+ entry->lvdsconf.use_acpi_for_edid = true;
if (conf & 0x4)
entry->lvdsconf.use_power_scripts = true;
+ entry->lvdsconf.sor.link = (conf & 0x00000030) >> 4;
}
if (conf & mask) {
/*
@@ -5706,13 +6055,6 @@ parse_dcb15_entry(struct drm_device *dev, struct dcb_table *dcb,
case OUTPUT_TV:
entry->tvconf.has_component_output = false;
break;
- case OUTPUT_TMDS:
- /*
- * Invent a DVI-A output, by copying the fields of the DVI-D
- * output; reported to work by math_b on an NV20(!).
- */
- fabricate_vga_output(dcb, entry->i2c_index, entry->heads);
- break;
case OUTPUT_LVDS:
if ((conn & 0x00003f00) != 0x10)
entry->lvdsconf.use_straps_for_mode = true;
@@ -5793,6 +6135,31 @@ void merge_like_dcb_entries(struct drm_device *dev, struct dcb_table *dcb)
dcb->entries = newentries;
}
+static bool
+apply_dcb_encoder_quirks(struct drm_device *dev, int idx, u32 *conn, u32 *conf)
+{
+ /* Dell Precision M6300
+ * DCB entry 2: 02025312 00000010
+ * DCB entry 3: 02026312 00000020
+ *
+ * Identical, except apparently a different connector on a
+ * different SOR link. Not a clue how we're supposed to know
+ * which one is in use if it even shares an i2c line...
+ *
+ * Ignore the connector on the second SOR link to prevent
+ * nasty problems until this is sorted (assuming it's not a
+ * VBIOS bug).
+ */
+ if ((dev->pdev->device == 0x040d) &&
+ (dev->pdev->subsystem_vendor == 0x1028) &&
+ (dev->pdev->subsystem_device == 0x019b)) {
+ if (*conn == 0x02026312 && *conf == 0x00000020)
+ return false;
+ }
+
+ return true;
+}
+
static int
parse_dcb_table(struct drm_device *dev, struct nvbios *bios, bool twoHeads)
{
@@ -5926,6 +6293,9 @@ parse_dcb_table(struct drm_device *dev, struct nvbios *bios, bool twoHeads)
if ((connection & 0x0000000f) == 0x0000000f)
continue;
+ if (!apply_dcb_encoder_quirks(dev, i, &connection, &config))
+ continue;
+
NV_TRACEWARN(dev, "Raw DCB entry %d: %08x %08x\n",
dcb->entries, connection, config);
@@ -6181,9 +6551,8 @@ nouveau_run_vbios_init(struct drm_device *dev)
struct nvbios *bios = &dev_priv->vbios;
int i, ret = 0;
- NVLockVgaCrtcs(dev, false);
- if (nv_two_heads(dev))
- NVSetOwner(dev, bios->state.crtchead);
+ /* Reset the BIOS head to 0. */
+ bios->state.crtchead = 0;
if (bios->major_version < 5) /* BMP only */
load_nv17_hw_sequencer_ucode(dev, bios);
@@ -6216,8 +6585,6 @@ nouveau_run_vbios_init(struct drm_device *dev)
}
}
- NVLockVgaCrtcs(dev, true);
-
return ret;
}
@@ -6238,7 +6605,6 @@ static bool
nouveau_bios_posted(struct drm_device *dev)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
- bool was_locked;
unsigned htotal;
if (dev_priv->chipset >= NV_50) {
@@ -6248,13 +6614,12 @@ nouveau_bios_posted(struct drm_device *dev)
return true;
}
- was_locked = NVLockVgaCrtcs(dev, false);
htotal = NVReadVgaCrtc(dev, 0, 0x06);
htotal |= (NVReadVgaCrtc(dev, 0, 0x07) & 0x01) << 8;
htotal |= (NVReadVgaCrtc(dev, 0, 0x07) & 0x20) << 4;
htotal |= (NVReadVgaCrtc(dev, 0, 0x25) & 0x01) << 10;
htotal |= (NVReadVgaCrtc(dev, 0, 0x41) & 0x01) << 11;
- NVLockVgaCrtcs(dev, was_locked);
+
return (htotal != 0);
}
@@ -6263,8 +6628,6 @@ nouveau_bios_init(struct drm_device *dev)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nvbios *bios = &dev_priv->vbios;
- uint32_t saved_nv_pextdev_boot_0;
- bool was_locked;
int ret;
if (!NVInitVBIOS(dev))
@@ -6284,40 +6647,27 @@ nouveau_bios_init(struct drm_device *dev)
if (!bios->major_version) /* we don't run version 0 bios */
return 0;
- /* these will need remembering across a suspend */
- saved_nv_pextdev_boot_0 = bios_rd32(bios, NV_PEXTDEV_BOOT_0);
- bios->state.saved_nv_pfb_cfg0 = bios_rd32(bios, NV_PFB_CFG0);
-
/* init script execution disabled */
bios->execute = false;
/* ... unless card isn't POSTed already */
if (!nouveau_bios_posted(dev)) {
- NV_INFO(dev, "Adaptor not initialised\n");
- if (dev_priv->card_type < NV_40) {
- NV_ERROR(dev, "Unable to POST this chipset\n");
- return -ENODEV;
- }
-
- NV_INFO(dev, "Running VBIOS init tables\n");
+ NV_INFO(dev, "Adaptor not initialised, "
+ "running VBIOS init tables.\n");
bios->execute = true;
}
- bios_wr32(bios, NV_PEXTDEV_BOOT_0, saved_nv_pextdev_boot_0);
-
ret = nouveau_run_vbios_init(dev);
if (ret)
return ret;
/* feature_byte on BMP is poor, but init always sets CR4B */
- was_locked = NVLockVgaCrtcs(dev, false);
if (bios->major_version < 5)
bios->is_mobile = NVReadVgaCrtc(dev, 0, NV_CIO_CRE_4B) & 0x40;
/* all BIT systems need p_f_m_t for digital_min_front_porch */
if (bios->is_mobile || bios->major_version >= 5)
ret = parse_fp_mode_table(dev, bios);
- NVLockVgaCrtcs(dev, was_locked);
/* allow subsequent scripts to execute */
bios->execute = true;
diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.h b/drivers/gpu/drm/nouveau/nouveau_bios.h
index adf4ec2d06c..024458a8d06 100644
--- a/drivers/gpu/drm/nouveau/nouveau_bios.h
+++ b/drivers/gpu/drm/nouveau/nouveau_bios.h
@@ -81,6 +81,7 @@ struct dcb_connector_table_entry {
enum dcb_connector_type type;
uint8_t index2;
uint8_t gpio_tag;
+ void *drm;
};
struct dcb_connector_table {
@@ -117,6 +118,7 @@ struct dcb_entry {
struct {
struct sor_conf sor;
bool use_straps_for_mode;
+ bool use_acpi_for_edid;
bool use_power_scripts;
} lvdsconf;
struct {
@@ -249,8 +251,6 @@ struct nvbios {
struct {
int crtchead;
- /* these need remembering across suspend */
- uint32_t saved_nv_pfb_cfg0;
} state;
struct {
diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c b/drivers/gpu/drm/nouveau/nouveau_bo.c
index 6f3c1952237..3ca8343c15d 100644
--- a/drivers/gpu/drm/nouveau/nouveau_bo.c
+++ b/drivers/gpu/drm/nouveau/nouveau_bo.c
@@ -461,9 +461,9 @@ nouveau_bo_move_accel_cleanup(struct nouveau_channel *chan,
return ret;
ret = ttm_bo_move_accel_cleanup(&nvbo->bo, fence, NULL,
- evict, no_wait_reserve, no_wait_gpu, new_mem);
- if (nvbo->channel && nvbo->channel != chan)
- ret = nouveau_fence_wait(fence, NULL, false, false);
+ evict || (nvbo->channel &&
+ nvbo->channel != chan),
+ no_wait_reserve, no_wait_gpu, new_mem);
nouveau_fence_unref((void *)&fence);
return ret;
}
@@ -711,8 +711,7 @@ nouveau_bo_move(struct ttm_buffer_object *bo, bool evict, bool intr,
return ret;
/* Software copy if the card isn't up and running yet. */
- if (dev_priv->init_state != NOUVEAU_CARD_INIT_DONE ||
- !dev_priv->channel) {
+ if (!dev_priv->channel) {
ret = ttm_bo_move_memcpy(bo, evict, no_wait_reserve, no_wait_gpu, new_mem);
goto out;
}
@@ -783,7 +782,7 @@ nouveau_ttm_io_mem_reserve(struct ttm_bo_device *bdev, struct ttm_mem_reg *mem)
break;
case TTM_PL_VRAM:
mem->bus.offset = mem->mm_node->start << PAGE_SHIFT;
- mem->bus.base = drm_get_resource_start(dev, 1);
+ mem->bus.base = pci_resource_start(dev->pdev, 1);
mem->bus.is_iomem = true;
break;
default:
diff --git a/drivers/gpu/drm/nouveau/nouveau_calc.c b/drivers/gpu/drm/nouveau/nouveau_calc.c
index 88f9bc0941e..ca85da78484 100644
--- a/drivers/gpu/drm/nouveau/nouveau_calc.c
+++ b/drivers/gpu/drm/nouveau/nouveau_calc.c
@@ -200,7 +200,7 @@ nv04_update_arb(struct drm_device *dev, int VClk, int bpp,
struct nv_sim_state sim_data;
int MClk = nouveau_hw_get_clock(dev, MPLL);
int NVClk = nouveau_hw_get_clock(dev, NVPLL);
- uint32_t cfg1 = nvReadFB(dev, NV_PFB_CFG1);
+ uint32_t cfg1 = nvReadFB(dev, NV04_PFB_CFG1);
sim_data.pclk_khz = VClk;
sim_data.mclk_khz = MClk;
@@ -218,7 +218,7 @@ nv04_update_arb(struct drm_device *dev, int VClk, int bpp,
sim_data.mem_latency = 3;
sim_data.mem_page_miss = 10;
} else {
- sim_data.memory_type = nvReadFB(dev, NV_PFB_CFG0) & 0x1;
+ sim_data.memory_type = nvReadFB(dev, NV04_PFB_CFG0) & 0x1;
sim_data.memory_width = (nvReadEXTDEV(dev, NV_PEXTDEV_BOOT_0) & 0x10) ? 128 : 64;
sim_data.mem_latency = cfg1 & 0xf;
sim_data.mem_page_miss = ((cfg1 >> 4) & 0xf) + ((cfg1 >> 31) & 0x1);
diff --git a/drivers/gpu/drm/nouveau/nouveau_channel.c b/drivers/gpu/drm/nouveau/nouveau_channel.c
index 1fc57ef5829..90fdcda332b 100644
--- a/drivers/gpu/drm/nouveau/nouveau_channel.c
+++ b/drivers/gpu/drm/nouveau/nouveau_channel.c
@@ -62,7 +62,8 @@ nouveau_channel_pushbuf_ctxdma_init(struct nouveau_channel *chan)
* VRAM.
*/
ret = nouveau_gpuobj_dma_new(chan, NV_CLASS_DMA_IN_MEMORY,
- drm_get_resource_start(dev, 1),
+ pci_resource_start(dev->pdev,
+ 1),
dev_priv->fb_available_size,
NV_DMA_ACCESS_RO,
NV_DMA_TARGET_PCI, &pushbuf);
@@ -257,9 +258,7 @@ nouveau_channel_free(struct nouveau_channel *chan)
nouveau_debugfs_channel_fini(chan);
/* Give outstanding push buffers a chance to complete */
- spin_lock_irqsave(&chan->fence.lock, flags);
nouveau_fence_update(chan);
- spin_unlock_irqrestore(&chan->fence.lock, flags);
if (chan->fence.sequence != chan->fence.sequence_ack) {
struct nouveau_fence *fence = NULL;
@@ -368,8 +367,6 @@ nouveau_ioctl_fifo_alloc(struct drm_device *dev, void *data,
struct nouveau_channel *chan;
int ret;
- NOUVEAU_CHECK_INITIALISED_WITH_RETURN;
-
if (dev_priv->engine.graph.accel_blocked)
return -ENODEV;
@@ -418,7 +415,6 @@ nouveau_ioctl_fifo_free(struct drm_device *dev, void *data,
struct drm_nouveau_channel_free *cfree = data;
struct nouveau_channel *chan;
- NOUVEAU_CHECK_INITIALISED_WITH_RETURN;
NOUVEAU_GET_USER_CHANNEL_WITH_RETURN(cfree->channel, file_priv, chan);
nouveau_channel_free(chan);
diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c b/drivers/gpu/drm/nouveau/nouveau_connector.c
index 149ed224c3c..734e92635e8 100644
--- a/drivers/gpu/drm/nouveau/nouveau_connector.c
+++ b/drivers/gpu/drm/nouveau/nouveau_connector.c
@@ -102,63 +102,15 @@ nouveau_connector_destroy(struct drm_connector *drm_connector)
kfree(drm_connector);
}
-static void
-nouveau_connector_ddc_prepare(struct drm_connector *connector, int *flags)
-{
- struct drm_nouveau_private *dev_priv = connector->dev->dev_private;
-
- if (dev_priv->card_type >= NV_50)
- return;
-
- *flags = 0;
- if (NVLockVgaCrtcs(dev_priv->dev, false))
- *flags |= 1;
- if (nv_heads_tied(dev_priv->dev))
- *flags |= 2;
-
- if (*flags & 2)
- NVSetOwner(dev_priv->dev, 0); /* necessary? */
-}
-
-static void
-nouveau_connector_ddc_finish(struct drm_connector *connector, int flags)
-{
- struct drm_nouveau_private *dev_priv = connector->dev->dev_private;
-
- if (dev_priv->card_type >= NV_50)
- return;
-
- if (flags & 2)
- NVSetOwner(dev_priv->dev, 4);
- if (flags & 1)
- NVLockVgaCrtcs(dev_priv->dev, true);
-}
-
static struct nouveau_i2c_chan *
nouveau_connector_ddc_detect(struct drm_connector *connector,
struct nouveau_encoder **pnv_encoder)
{
struct drm_device *dev = connector->dev;
- uint8_t out_buf[] = { 0x0, 0x0}, buf[2];
- int ret, flags, i;
-
- struct i2c_msg msgs[] = {
- {
- .addr = 0x50,
- .flags = 0,
- .len = 1,
- .buf = out_buf,
- },
- {
- .addr = 0x50,
- .flags = I2C_M_RD,
- .len = 1,
- .buf = buf,
- }
- };
+ int i;
for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) {
- struct nouveau_i2c_chan *i2c = NULL;
+ struct nouveau_i2c_chan *i2c;
struct nouveau_encoder *nv_encoder;
struct drm_mode_object *obj;
int id;
@@ -171,17 +123,9 @@ nouveau_connector_ddc_detect(struct drm_connector *connector,
if (!obj)
continue;
nv_encoder = nouveau_encoder(obj_to_encoder(obj));
+ i2c = nouveau_i2c_find(dev, nv_encoder->dcb->i2c_index);
- if (nv_encoder->dcb->i2c_index < 0xf)
- i2c = nouveau_i2c_find(dev, nv_encoder->dcb->i2c_index);
- if (!i2c)
- continue;
-
- nouveau_connector_ddc_prepare(connector, &flags);
- ret = i2c_transfer(&i2c->adapter, msgs, 2);
- nouveau_connector_ddc_finish(connector, flags);
-
- if (ret == 2) {
+ if (i2c && nouveau_probe_i2c_addr(i2c, 0x50)) {
*pnv_encoder = nv_encoder;
return i2c;
}
@@ -234,21 +178,7 @@ nouveau_connector_detect(struct drm_connector *connector)
struct nouveau_connector *nv_connector = nouveau_connector(connector);
struct nouveau_encoder *nv_encoder = NULL;
struct nouveau_i2c_chan *i2c;
- int type, flags;
-
- if (nv_connector->dcb->type == DCB_CONNECTOR_LVDS)
- nv_encoder = find_encoder_by_type(connector, OUTPUT_LVDS);
- if (nv_encoder && nv_connector->native_mode) {
- unsigned status = connector_status_connected;
-
-#if defined(CONFIG_ACPI_BUTTON) || \
- (defined(CONFIG_ACPI_BUTTON_MODULE) && defined(MODULE))
- if (!nouveau_ignorelid && !acpi_lid_open())
- status = connector_status_unknown;
-#endif
- nouveau_connector_set_encoder(connector, nv_encoder);
- return status;
- }
+ int type;
/* Cleanup the previous EDID block. */
if (nv_connector->edid) {
@@ -259,9 +189,7 @@ nouveau_connector_detect(struct drm_connector *connector)
i2c = nouveau_connector_ddc_detect(connector, &nv_encoder);
if (i2c) {
- nouveau_connector_ddc_prepare(connector, &flags);
nv_connector->edid = drm_get_edid(connector, &i2c->adapter);
- nouveau_connector_ddc_finish(connector, flags);
drm_mode_connector_update_edid_property(connector,
nv_connector->edid);
if (!nv_connector->edid) {
@@ -321,6 +249,85 @@ detect_analog:
return connector_status_disconnected;
}
+static enum drm_connector_status
+nouveau_connector_detect_lvds(struct drm_connector *connector)
+{
+ struct drm_device *dev = connector->dev;
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nouveau_connector *nv_connector = nouveau_connector(connector);
+ struct nouveau_encoder *nv_encoder = NULL;
+ enum drm_connector_status status = connector_status_disconnected;
+
+ /* Cleanup the previous EDID block. */
+ if (nv_connector->edid) {
+ drm_mode_connector_update_edid_property(connector, NULL);
+ kfree(nv_connector->edid);
+ nv_connector->edid = NULL;
+ }
+
+ nv_encoder = find_encoder_by_type(connector, OUTPUT_LVDS);
+ if (!nv_encoder)
+ return connector_status_disconnected;
+
+ /* Try retrieving EDID via DDC */
+ if (!dev_priv->vbios.fp_no_ddc) {
+ status = nouveau_connector_detect(connector);
+ if (status == connector_status_connected)
+ goto out;
+ }
+
+ /* On some laptops (Sony, i'm looking at you) there appears to
+ * be no direct way of accessing the panel's EDID. The only
+ * option available to us appears to be to ask ACPI for help..
+ *
+ * It's important this check's before trying straps, one of the
+ * said manufacturer's laptops are configured in such a way
+ * the nouveau decides an entry in the VBIOS FP mode table is
+ * valid - it's not (rh#613284)
+ */
+ if (nv_encoder->dcb->lvdsconf.use_acpi_for_edid) {
+ if (!nouveau_acpi_edid(dev, connector)) {
+ status = connector_status_connected;
+ goto out;
+ }
+ }
+
+ /* If no EDID found above, and the VBIOS indicates a hardcoded
+ * modeline is avalilable for the panel, set it as the panel's
+ * native mode and exit.
+ */
+ if (nouveau_bios_fp_mode(dev, NULL) && (dev_priv->vbios.fp_no_ddc ||
+ nv_encoder->dcb->lvdsconf.use_straps_for_mode)) {
+ status = connector_status_connected;
+ goto out;
+ }
+
+ /* Still nothing, some VBIOS images have a hardcoded EDID block
+ * stored for the panel stored in them.
+ */
+ if (!dev_priv->vbios.fp_no_ddc) {
+ struct edid *edid =
+ (struct edid *)nouveau_bios_embedded_edid(dev);
+ if (edid) {
+ nv_connector->edid = kmalloc(EDID_LENGTH, GFP_KERNEL);
+ *(nv_connector->edid) = *edid;
+ status = connector_status_connected;
+ }
+ }
+
+out:
+#if defined(CONFIG_ACPI_BUTTON) || \
+ (defined(CONFIG_ACPI_BUTTON_MODULE) && defined(MODULE))
+ if (status == connector_status_connected &&
+ !nouveau_ignorelid && !acpi_lid_open())
+ status = connector_status_unknown;
+#endif
+
+ drm_mode_connector_update_edid_property(connector, nv_connector->edid);
+ nouveau_connector_set_encoder(connector, nv_encoder);
+ return status;
+}
+
static void
nouveau_connector_force(struct drm_connector *connector)
{
@@ -441,7 +448,8 @@ nouveau_connector_native_mode(struct drm_connector *connector)
int high_w = 0, high_h = 0, high_v = 0;
list_for_each_entry(mode, &nv_connector->base.probed_modes, head) {
- if (helper->mode_valid(connector, mode) != MODE_OK)
+ if (helper->mode_valid(connector, mode) != MODE_OK ||
+ (mode->flags & DRM_MODE_FLAG_INTERLACE))
continue;
/* Use preferred mode if there is one.. */
@@ -534,21 +542,27 @@ static int
nouveau_connector_get_modes(struct drm_connector *connector)
{
struct drm_device *dev = connector->dev;
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_connector *nv_connector = nouveau_connector(connector);
struct nouveau_encoder *nv_encoder = nv_connector->detected_encoder;
int ret = 0;
- /* If we're not LVDS, destroy the previous native mode, the attached
- * monitor could have changed.
+ /* destroy the native mode, the attached monitor could have changed.
*/
- if (nv_connector->dcb->type != DCB_CONNECTOR_LVDS &&
- nv_connector->native_mode) {
+ if (nv_connector->native_mode) {
drm_mode_destroy(dev, nv_connector->native_mode);
nv_connector->native_mode = NULL;
}
if (nv_connector->edid)
ret = drm_add_edid_modes(connector, nv_connector->edid);
+ else
+ if (nv_encoder->dcb->type == OUTPUT_LVDS &&
+ (nv_encoder->dcb->lvdsconf.use_straps_for_mode ||
+ dev_priv->vbios.fp_no_ddc) && nouveau_bios_fp_mode(dev, NULL)) {
+ nv_connector->native_mode = drm_mode_create(dev);
+ nouveau_bios_fp_mode(dev, nv_connector->native_mode);
+ }
/* Find the native mode if this is a digital panel, if we didn't
* find any modes through DDC previously add the native mode to
@@ -569,7 +583,8 @@ nouveau_connector_get_modes(struct drm_connector *connector)
ret = get_slave_funcs(nv_encoder)->
get_modes(to_drm_encoder(nv_encoder), connector);
- if (nv_encoder->dcb->type == OUTPUT_LVDS)
+ if (nv_connector->dcb->type == DCB_CONNECTOR_LVDS ||
+ nv_connector->dcb->type == DCB_CONNECTOR_eDP)
ret += nouveau_connector_scaler_modes_add(connector);
return ret;
@@ -643,6 +658,44 @@ nouveau_connector_best_encoder(struct drm_connector *connector)
return NULL;
}
+void
+nouveau_connector_set_polling(struct drm_connector *connector)
+{
+ struct drm_device *dev = connector->dev;
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct drm_crtc *crtc;
+ bool spare_crtc = false;
+
+ list_for_each_entry(crtc, &dev->mode_config.crtc_list, head)
+ spare_crtc |= !crtc->enabled;
+
+ connector->polled = 0;
+
+ switch (connector->connector_type) {
+ case DRM_MODE_CONNECTOR_VGA:
+ case DRM_MODE_CONNECTOR_TV:
+ if (dev_priv->card_type >= NV_50 ||
+ (nv_gf4_disp_arch(dev) && spare_crtc))
+ connector->polled = DRM_CONNECTOR_POLL_CONNECT;
+ break;
+
+ case DRM_MODE_CONNECTOR_DVII:
+ case DRM_MODE_CONNECTOR_DVID:
+ case DRM_MODE_CONNECTOR_HDMIA:
+ case DRM_MODE_CONNECTOR_DisplayPort:
+ case DRM_MODE_CONNECTOR_eDP:
+ if (dev_priv->card_type >= NV_50)
+ connector->polled = DRM_CONNECTOR_POLL_HPD;
+ else if (connector->connector_type == DRM_MODE_CONNECTOR_DVID ||
+ spare_crtc)
+ connector->polled = DRM_CONNECTOR_POLL_CONNECT;
+ break;
+
+ default:
+ break;
+ }
+}
+
static const struct drm_connector_helper_funcs
nouveau_connector_helper_funcs = {
.get_modes = nouveau_connector_get_modes,
@@ -662,148 +715,74 @@ nouveau_connector_funcs = {
.force = nouveau_connector_force
};
-static int
-nouveau_connector_create_lvds(struct drm_device *dev,
- struct drm_connector *connector)
-{
- struct nouveau_connector *nv_connector = nouveau_connector(connector);
- struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nouveau_i2c_chan *i2c = NULL;
- struct nouveau_encoder *nv_encoder;
- struct drm_display_mode native, *mode, *temp;
- bool dummy, if_is_24bit = false;
- int ret, flags;
-
- nv_encoder = find_encoder_by_type(connector, OUTPUT_LVDS);
- if (!nv_encoder)
- return -ENODEV;
-
- ret = nouveau_bios_parse_lvds_table(dev, 0, &dummy, &if_is_24bit);
- if (ret) {
- NV_ERROR(dev, "Error parsing LVDS table, disabling LVDS\n");
- return ret;
- }
- nv_connector->use_dithering = !if_is_24bit;
-
- /* Firstly try getting EDID over DDC, if allowed and I2C channel
- * is available.
- */
- if (!dev_priv->vbios.fp_no_ddc && nv_encoder->dcb->i2c_index < 0xf)
- i2c = nouveau_i2c_find(dev, nv_encoder->dcb->i2c_index);
-
- if (i2c) {
- nouveau_connector_ddc_prepare(connector, &flags);
- nv_connector->edid = drm_get_edid(connector, &i2c->adapter);
- nouveau_connector_ddc_finish(connector, flags);
- }
-
- /* If no EDID found above, and the VBIOS indicates a hardcoded
- * modeline is avalilable for the panel, set it as the panel's
- * native mode and exit.
- */
- if (!nv_connector->edid && nouveau_bios_fp_mode(dev, &native) &&
- (nv_encoder->dcb->lvdsconf.use_straps_for_mode ||
- dev_priv->vbios.fp_no_ddc)) {
- nv_connector->native_mode = drm_mode_duplicate(dev, &native);
- goto out;
- }
-
- /* Still nothing, some VBIOS images have a hardcoded EDID block
- * stored for the panel stored in them.
- */
- if (!nv_connector->edid && !nv_connector->native_mode &&
- !dev_priv->vbios.fp_no_ddc) {
- struct edid *edid =
- (struct edid *)nouveau_bios_embedded_edid(dev);
- if (edid) {
- nv_connector->edid = kmalloc(EDID_LENGTH, GFP_KERNEL);
- *(nv_connector->edid) = *edid;
- }
- }
-
- if (!nv_connector->edid)
- goto out;
-
- /* We didn't find/use a panel mode from the VBIOS, so parse the EDID
- * block and look for the preferred mode there.
- */
- ret = drm_add_edid_modes(connector, nv_connector->edid);
- if (ret == 0)
- goto out;
- nv_connector->detected_encoder = nv_encoder;
- nv_connector->native_mode = nouveau_connector_native_mode(connector);
- list_for_each_entry_safe(mode, temp, &connector->probed_modes, head)
- drm_mode_remove(connector, mode);
-
-out:
- if (!nv_connector->native_mode) {
- NV_ERROR(dev, "LVDS present in DCB table, but couldn't "
- "determine its native mode. Disabling.\n");
- return -ENODEV;
- }
-
- drm_mode_connector_update_edid_property(connector, nv_connector->edid);
- return 0;
-}
+static const struct drm_connector_funcs
+nouveau_connector_funcs_lvds = {
+ .dpms = drm_helper_connector_dpms,
+ .save = NULL,
+ .restore = NULL,
+ .detect = nouveau_connector_detect_lvds,
+ .destroy = nouveau_connector_destroy,
+ .fill_modes = drm_helper_probe_single_connector_modes,
+ .set_property = nouveau_connector_set_property,
+ .force = nouveau_connector_force
+};
-int
-nouveau_connector_create(struct drm_device *dev,
- struct dcb_connector_table_entry *dcb)
+struct drm_connector *
+nouveau_connector_create(struct drm_device *dev, int index)
{
+ const struct drm_connector_funcs *funcs = &nouveau_connector_funcs;
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_connector *nv_connector = NULL;
+ struct dcb_connector_table_entry *dcb = NULL;
struct drm_connector *connector;
- struct drm_encoder *encoder;
- int ret, type;
+ int type, ret = 0;
NV_DEBUG_KMS(dev, "\n");
+ if (index >= dev_priv->vbios.dcb.connector.entries)
+ return ERR_PTR(-EINVAL);
+
+ dcb = &dev_priv->vbios.dcb.connector.entry[index];
+ if (dcb->drm)
+ return dcb->drm;
+
switch (dcb->type) {
- case DCB_CONNECTOR_NONE:
- return 0;
case DCB_CONNECTOR_VGA:
- NV_INFO(dev, "Detected a VGA connector\n");
type = DRM_MODE_CONNECTOR_VGA;
break;
case DCB_CONNECTOR_TV_0:
case DCB_CONNECTOR_TV_1:
case DCB_CONNECTOR_TV_3:
- NV_INFO(dev, "Detected a TV connector\n");
type = DRM_MODE_CONNECTOR_TV;
break;
case DCB_CONNECTOR_DVI_I:
- NV_INFO(dev, "Detected a DVI-I connector\n");
type = DRM_MODE_CONNECTOR_DVII;
break;
case DCB_CONNECTOR_DVI_D:
- NV_INFO(dev, "Detected a DVI-D connector\n");
type = DRM_MODE_CONNECTOR_DVID;
break;
case DCB_CONNECTOR_HDMI_0:
case DCB_CONNECTOR_HDMI_1:
- NV_INFO(dev, "Detected a HDMI connector\n");
type = DRM_MODE_CONNECTOR_HDMIA;
break;
case DCB_CONNECTOR_LVDS:
- NV_INFO(dev, "Detected a LVDS connector\n");
type = DRM_MODE_CONNECTOR_LVDS;
+ funcs = &nouveau_connector_funcs_lvds;
break;
case DCB_CONNECTOR_DP:
- NV_INFO(dev, "Detected a DisplayPort connector\n");
type = DRM_MODE_CONNECTOR_DisplayPort;
break;
case DCB_CONNECTOR_eDP:
- NV_INFO(dev, "Detected an eDP connector\n");
type = DRM_MODE_CONNECTOR_eDP;
break;
default:
NV_ERROR(dev, "unknown connector type: 0x%02x!!\n", dcb->type);
- return -EINVAL;
+ return ERR_PTR(-EINVAL);
}
nv_connector = kzalloc(sizeof(*nv_connector), GFP_KERNEL);
if (!nv_connector)
- return -ENOMEM;
+ return ERR_PTR(-ENOMEM);
nv_connector->dcb = dcb;
connector = &nv_connector->base;
@@ -811,27 +790,21 @@ nouveau_connector_create(struct drm_device *dev,
connector->interlace_allowed = false;
connector->doublescan_allowed = false;
- drm_connector_init(dev, connector, &nouveau_connector_funcs, type);
+ drm_connector_init(dev, connector, funcs, type);
drm_connector_helper_add(connector, &nouveau_connector_helper_funcs);
- /* attach encoders */
- list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
- struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
-
- if (nv_encoder->dcb->connector != dcb->index)
- continue;
-
- if (get_slave_funcs(nv_encoder))
- get_slave_funcs(nv_encoder)->create_resources(encoder, connector);
+ /* Check if we need dithering enabled */
+ if (dcb->type == DCB_CONNECTOR_LVDS) {
+ bool dummy, is_24bit = false;
- drm_mode_connector_attach_encoder(connector, encoder);
- }
+ ret = nouveau_bios_parse_lvds_table(dev, 0, &dummy, &is_24bit);
+ if (ret) {
+ NV_ERROR(dev, "Error parsing LVDS table, disabling "
+ "LVDS\n");
+ goto fail;
+ }
- if (!connector->encoder_ids[0]) {
- NV_WARN(dev, " no encoders, ignoring\n");
- drm_connector_cleanup(connector);
- kfree(connector);
- return 0;
+ nv_connector->use_dithering = !is_24bit;
}
/* Init DVI-I specific properties */
@@ -841,12 +814,8 @@ nouveau_connector_create(struct drm_device *dev,
drm_connector_attach_property(connector, dev->mode_config.dvi_i_select_subconnector_property, 0);
}
- if (dcb->type != DCB_CONNECTOR_LVDS)
- nv_connector->use_dithering = false;
-
switch (dcb->type) {
case DCB_CONNECTOR_VGA:
- connector->polled = DRM_CONNECTOR_POLL_CONNECT;
if (dev_priv->card_type >= NV_50) {
drm_connector_attach_property(connector,
dev->mode_config.scaling_mode_property,
@@ -858,17 +827,6 @@ nouveau_connector_create(struct drm_device *dev,
case DCB_CONNECTOR_TV_3:
nv_connector->scaling_mode = DRM_MODE_SCALE_NONE;
break;
- case DCB_CONNECTOR_DP:
- case DCB_CONNECTOR_eDP:
- case DCB_CONNECTOR_HDMI_0:
- case DCB_CONNECTOR_HDMI_1:
- case DCB_CONNECTOR_DVI_I:
- case DCB_CONNECTOR_DVI_D:
- if (dev_priv->card_type >= NV_50)
- connector->polled = DRM_CONNECTOR_POLL_HPD;
- else
- connector->polled = DRM_CONNECTOR_POLL_CONNECT;
- /* fall-through */
default:
nv_connector->scaling_mode = DRM_MODE_SCALE_FULLSCREEN;
@@ -882,15 +840,15 @@ nouveau_connector_create(struct drm_device *dev,
break;
}
+ nouveau_connector_set_polling(connector);
+
drm_sysfs_connector_add(connector);
+ dcb->drm = connector;
+ return dcb->drm;
- if (dcb->type == DCB_CONNECTOR_LVDS) {
- ret = nouveau_connector_create_lvds(dev, connector);
- if (ret) {
- connector->funcs->destroy(connector);
- return ret;
- }
- }
+fail:
+ drm_connector_cleanup(connector);
+ kfree(connector);
+ return ERR_PTR(ret);
- return 0;
}
diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.h b/drivers/gpu/drm/nouveau/nouveau_connector.h
index 4ef38abc2d9..0d2e668ccfe 100644
--- a/drivers/gpu/drm/nouveau/nouveau_connector.h
+++ b/drivers/gpu/drm/nouveau/nouveau_connector.h
@@ -49,7 +49,10 @@ static inline struct nouveau_connector *nouveau_connector(
return container_of(con, struct nouveau_connector, base);
}
-int nouveau_connector_create(struct drm_device *,
- struct dcb_connector_table_entry *);
+struct drm_connector *
+nouveau_connector_create(struct drm_device *, int index);
+
+void
+nouveau_connector_set_polling(struct drm_connector *);
#endif /* __NOUVEAU_CONNECTOR_H__ */
diff --git a/drivers/gpu/drm/nouveau/nouveau_dma.c b/drivers/gpu/drm/nouveau/nouveau_dma.c
index 65c441a1999..2e3c6caa97e 100644
--- a/drivers/gpu/drm/nouveau/nouveau_dma.c
+++ b/drivers/gpu/drm/nouveau/nouveau_dma.c
@@ -92,11 +92,9 @@ nouveau_dma_init(struct nouveau_channel *chan)
return ret;
/* Map M2MF notifier object - fbcon. */
- if (drm_core_check_feature(dev, DRIVER_MODESET)) {
- ret = nouveau_bo_map(chan->notifier_bo);
- if (ret)
- return ret;
- }
+ ret = nouveau_bo_map(chan->notifier_bo);
+ if (ret)
+ return ret;
/* Insert NOPS for NOUVEAU_DMA_SKIPS */
ret = RING_SPACE(chan, NOUVEAU_DMA_SKIPS);
diff --git a/drivers/gpu/drm/nouveau/nouveau_dp.c b/drivers/gpu/drm/nouveau/nouveau_dp.c
index deeb21c6865..33742b11188 100644
--- a/drivers/gpu/drm/nouveau/nouveau_dp.c
+++ b/drivers/gpu/drm/nouveau/nouveau_dp.c
@@ -23,8 +23,10 @@
*/
#include "drmP.h"
+
#include "nouveau_drv.h"
#include "nouveau_i2c.h"
+#include "nouveau_connector.h"
#include "nouveau_encoder.h"
static int
@@ -270,13 +272,39 @@ bool
nouveau_dp_link_train(struct drm_encoder *encoder)
{
struct drm_device *dev = encoder->dev;
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nouveau_gpio_engine *pgpio = &dev_priv->engine.gpio;
struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
- uint8_t config[4];
- uint8_t status[3];
+ struct nouveau_connector *nv_connector;
+ struct bit_displayport_encoder_table *dpe;
+ int dpe_headerlen;
+ uint8_t config[4], status[3];
bool cr_done, cr_max_vs, eq_done;
int ret = 0, i, tries, voltage;
NV_DEBUG_KMS(dev, "link training!!\n");
+
+ nv_connector = nouveau_encoder_connector_get(nv_encoder);
+ if (!nv_connector)
+ return false;
+
+ dpe = nouveau_bios_dp_table(dev, nv_encoder->dcb, &dpe_headerlen);
+ if (!dpe) {
+ NV_ERROR(dev, "SOR-%d: no DP encoder table!\n", nv_encoder->or);
+ return false;
+ }
+
+ /* disable hotplug detect, this flips around on some panels during
+ * link training.
+ */
+ pgpio->irq_enable(dev, nv_connector->dcb->gpio_tag, false);
+
+ if (dpe->script0) {
+ NV_DEBUG_KMS(dev, "SOR-%d: running DP script 0\n", nv_encoder->or);
+ nouveau_bios_run_init_table(dev, le16_to_cpu(dpe->script0),
+ nv_encoder->dcb);
+ }
+
train:
cr_done = eq_done = false;
@@ -403,6 +431,15 @@ stop:
}
}
+ if (dpe->script1) {
+ NV_DEBUG_KMS(dev, "SOR-%d: running DP script 1\n", nv_encoder->or);
+ nouveau_bios_run_init_table(dev, le16_to_cpu(dpe->script1),
+ nv_encoder->dcb);
+ }
+
+ /* re-enable hotplug detect */
+ pgpio->irq_enable(dev, nv_connector->dcb->gpio_tag, true);
+
return eq_done;
}
diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.c b/drivers/gpu/drm/nouveau/nouveau_drv.c
index 27377043229..1de5eb53e01 100644
--- a/drivers/gpu/drm/nouveau/nouveau_drv.c
+++ b/drivers/gpu/drm/nouveau/nouveau_drv.c
@@ -35,10 +35,6 @@
#include "drm_pciids.h"
-MODULE_PARM_DESC(ctxfw, "Use external firmware blob for grctx init (NV40)");
-int nouveau_ctxfw = 0;
-module_param_named(ctxfw, nouveau_ctxfw, int, 0400);
-
MODULE_PARM_DESC(noagp, "Disable AGP");
int nouveau_noagp;
module_param_named(noagp, nouveau_noagp, int, 0400);
@@ -56,7 +52,7 @@ int nouveau_vram_pushbuf;
module_param_named(vram_pushbuf, nouveau_vram_pushbuf, int, 0400);
MODULE_PARM_DESC(vram_notify, "Force DMA notifiers to be in VRAM");
-int nouveau_vram_notify = 1;
+int nouveau_vram_notify = 0;
module_param_named(vram_notify, nouveau_vram_notify, int, 0400);
MODULE_PARM_DESC(duallink, "Allow dual-link TMDS (>=GeForce 8)");
@@ -132,7 +128,7 @@ static struct drm_driver driver;
static int __devinit
nouveau_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
{
- return drm_get_dev(pdev, ent, &driver);
+ return drm_get_pci_dev(pdev, ent, &driver);
}
static void
@@ -155,9 +151,6 @@ nouveau_pci_suspend(struct pci_dev *pdev, pm_message_t pm_state)
struct drm_crtc *crtc;
int ret, i;
- if (!drm_core_check_feature(dev, DRIVER_MODESET))
- return -ENODEV;
-
if (pm_state.event == PM_EVENT_PRETHAW)
return 0;
@@ -257,9 +250,6 @@ nouveau_pci_resume(struct pci_dev *pdev)
struct drm_crtc *crtc;
int ret, i;
- if (!drm_core_check_feature(dev, DRIVER_MODESET))
- return -ENODEV;
-
nouveau_fbcon_save_disable_accel(dev);
NV_INFO(dev, "We're back, enabling device...\n");
@@ -269,6 +259,13 @@ nouveau_pci_resume(struct pci_dev *pdev)
return -1;
pci_set_master(dev->pdev);
+ /* Make sure the AGP controller is in a consistent state */
+ if (dev_priv->gart_info.type == NOUVEAU_GART_AGP)
+ nouveau_mem_reset_agp(dev);
+
+ /* Make the CRTCs accessible */
+ engine->display.early_init(dev);
+
NV_INFO(dev, "POSTing device...\n");
ret = nouveau_run_vbios_init(dev);
if (ret)
@@ -323,7 +320,6 @@ nouveau_pci_resume(struct pci_dev *pdev)
list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
- int ret;
ret = nouveau_bo_pin(nv_crtc->cursor.nvbo, TTM_PL_FLAG_VRAM);
if (!ret)
@@ -332,11 +328,7 @@ nouveau_pci_resume(struct pci_dev *pdev)
NV_ERROR(dev, "Could not pin/map cursor.\n");
}
- if (dev_priv->card_type < NV_50) {
- nv04_display_restore(dev);
- NVLockVgaCrtcs(dev, false);
- } else
- nv50_display_init(dev);
+ engine->display.init(dev);
list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
@@ -371,7 +363,8 @@ nouveau_pci_resume(struct pci_dev *pdev)
static struct drm_driver driver = {
.driver_features =
DRIVER_USE_AGP | DRIVER_PCI_DMA | DRIVER_SG |
- DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED | DRIVER_GEM,
+ DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED | DRIVER_GEM |
+ DRIVER_MODESET,
.load = nouveau_load,
.firstopen = nouveau_firstopen,
.lastclose = nouveau_lastclose,
@@ -438,16 +431,18 @@ static int __init nouveau_init(void)
nouveau_modeset = 1;
}
- if (nouveau_modeset == 1) {
- driver.driver_features |= DRIVER_MODESET;
- nouveau_register_dsm_handler();
- }
+ if (!nouveau_modeset)
+ return 0;
+ nouveau_register_dsm_handler();
return drm_init(&driver);
}
static void __exit nouveau_exit(void)
{
+ if (!nouveau_modeset)
+ return;
+
drm_exit(&driver);
nouveau_unregister_dsm_handler();
}
diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h
index c6971910648..e15db15dca7 100644
--- a/drivers/gpu/drm/nouveau/nouveau_drv.h
+++ b/drivers/gpu/drm/nouveau/nouveau_drv.h
@@ -123,14 +123,6 @@ nvbo_kmap_obj_iovirtual(struct nouveau_bo *nvbo)
return ioptr;
}
-struct mem_block {
- struct mem_block *next;
- struct mem_block *prev;
- uint64_t start;
- uint64_t size;
- struct drm_file *file_priv; /* NULL: free, -1: heap, other: real files */
-};
-
enum nouveau_flags {
NV_NFORCE = 0x10000000,
NV_NFORCE2 = 0x20000000
@@ -149,7 +141,7 @@ struct nouveau_gpuobj {
struct list_head list;
struct nouveau_channel *im_channel;
- struct mem_block *im_pramin;
+ struct drm_mm_node *im_pramin;
struct nouveau_bo *im_backing;
uint32_t im_backing_start;
uint32_t *im_backing_suspend;
@@ -196,7 +188,7 @@ struct nouveau_channel {
struct list_head pending;
uint32_t sequence;
uint32_t sequence_ack;
- uint32_t last_sequence_irq;
+ atomic_t last_sequence_irq;
} fence;
/* DMA push buffer */
@@ -206,7 +198,7 @@ struct nouveau_channel {
/* Notifier memory */
struct nouveau_bo *notifier_bo;
- struct mem_block *notifier_heap;
+ struct drm_mm notifier_heap;
/* PFIFO context */
struct nouveau_gpuobj_ref *ramfc;
@@ -224,7 +216,7 @@ struct nouveau_channel {
/* Objects */
struct nouveau_gpuobj_ref *ramin; /* Private instmem */
- struct mem_block *ramin_heap; /* Private PRAMIN heap */
+ struct drm_mm ramin_heap; /* Private PRAMIN heap */
struct nouveau_gpuobj_ref *ramht; /* Hash table */
struct list_head ramht_refs; /* Objects referenced by RAMHT */
@@ -277,8 +269,7 @@ struct nouveau_instmem_engine {
void (*clear)(struct drm_device *, struct nouveau_gpuobj *);
int (*bind)(struct drm_device *, struct nouveau_gpuobj *);
int (*unbind)(struct drm_device *, struct nouveau_gpuobj *);
- void (*prepare_access)(struct drm_device *, bool write);
- void (*finish_access)(struct drm_device *);
+ void (*flush)(struct drm_device *);
};
struct nouveau_mc_engine {
@@ -303,10 +294,11 @@ struct nouveau_fb_engine {
};
struct nouveau_fifo_engine {
- void *priv;
-
int channels;
+ struct nouveau_gpuobj_ref *playlist[2];
+ int cur_playlist;
+
int (*init)(struct drm_device *);
void (*takedown)(struct drm_device *);
@@ -339,10 +331,11 @@ struct nouveau_pgraph_object_class {
struct nouveau_pgraph_engine {
struct nouveau_pgraph_object_class *grclass;
bool accel_blocked;
- void *ctxprog;
- void *ctxvals;
int grctx_size;
+ /* NV2x/NV3x context table (0x400780) */
+ struct nouveau_gpuobj_ref *ctx_table;
+
int (*init)(struct drm_device *);
void (*takedown)(struct drm_device *);
@@ -358,6 +351,24 @@ struct nouveau_pgraph_engine {
uint32_t size, uint32_t pitch);
};
+struct nouveau_display_engine {
+ int (*early_init)(struct drm_device *);
+ void (*late_takedown)(struct drm_device *);
+ int (*create)(struct drm_device *);
+ int (*init)(struct drm_device *);
+ void (*destroy)(struct drm_device *);
+};
+
+struct nouveau_gpio_engine {
+ int (*init)(struct drm_device *);
+ void (*takedown)(struct drm_device *);
+
+ int (*get)(struct drm_device *, enum dcb_gpio_tag);
+ int (*set)(struct drm_device *, enum dcb_gpio_tag, int state);
+
+ void (*irq_enable)(struct drm_device *, enum dcb_gpio_tag, bool on);
+};
+
struct nouveau_engine {
struct nouveau_instmem_engine instmem;
struct nouveau_mc_engine mc;
@@ -365,6 +376,8 @@ struct nouveau_engine {
struct nouveau_fb_engine fb;
struct nouveau_pgraph_engine graph;
struct nouveau_fifo_engine fifo;
+ struct nouveau_display_engine display;
+ struct nouveau_gpio_engine gpio;
};
struct nouveau_pll_vals {
@@ -500,11 +513,6 @@ enum nouveau_card_type {
struct drm_nouveau_private {
struct drm_device *dev;
- enum {
- NOUVEAU_CARD_INIT_DOWN,
- NOUVEAU_CARD_INIT_DONE,
- NOUVEAU_CARD_INIT_FAILED
- } init_state;
/* the card type, takes NV_* as values */
enum nouveau_card_type card_type;
@@ -525,7 +533,7 @@ struct drm_nouveau_private {
struct list_head vbl_waiting;
struct {
- struct ttm_global_reference mem_global_ref;
+ struct drm_global_reference mem_global_ref;
struct ttm_bo_global_ref bo_global_ref;
struct ttm_bo_device bdev;
spinlock_t bo_list_lock;
@@ -533,8 +541,6 @@ struct drm_nouveau_private {
atomic_t validate_sequence;
} ttm;
- struct fb_info *fbdev_info;
-
int fifo_alloc_count;
struct nouveau_channel *fifos[NOUVEAU_MAX_CHANNEL_NR];
@@ -595,11 +601,7 @@ struct drm_nouveau_private {
struct nouveau_gpuobj *vm_vram_pt[NV50_VM_VRAM_NR];
int vm_vram_pt_nr;
- struct mem_block *ramin_heap;
-
- /* context table pointed to be NV_PGRAPH_CHANNEL_CTX_TABLE (0x400780) */
- uint32_t ctx_table_size;
- struct nouveau_gpuobj_ref *ctx_table;
+ struct drm_mm ramin_heap;
struct list_head gpuobj_list;
@@ -618,6 +620,11 @@ struct drm_nouveau_private {
struct backlight_device *backlight;
struct nouveau_channel *evo;
+ struct {
+ struct dcb_entry *dcb;
+ u16 script;
+ u32 pclk;
+ } evo_irq;
struct {
struct dentry *channel_root;
@@ -652,14 +659,6 @@ nouveau_bo_ref(struct nouveau_bo *ref, struct nouveau_bo **pnvbo)
return 0;
}
-#define NOUVEAU_CHECK_INITIALISED_WITH_RETURN do { \
- struct drm_nouveau_private *nv = dev->dev_private; \
- if (nv->init_state != NOUVEAU_CARD_INIT_DONE) { \
- NV_ERROR(dev, "called without init\n"); \
- return -EINVAL; \
- } \
-} while (0)
-
#define NOUVEAU_GET_USER_CHANNEL_WITH_RETURN(id, cl, ch) do { \
struct drm_nouveau_private *nv = dev->dev_private; \
if (!nouveau_channel_owner(dev, (cl), (id))) { \
@@ -682,7 +681,6 @@ extern int nouveau_tv_disable;
extern char *nouveau_tv_norm;
extern int nouveau_reg_debug;
extern char *nouveau_vbios;
-extern int nouveau_ctxfw;
extern int nouveau_ignorelid;
extern int nouveau_nofbaccel;
extern int nouveau_noaccel;
@@ -707,17 +705,10 @@ extern bool nouveau_wait_for_idle(struct drm_device *);
extern int nouveau_card_init(struct drm_device *);
/* nouveau_mem.c */
-extern int nouveau_mem_init_heap(struct mem_block **, uint64_t start,
- uint64_t size);
-extern struct mem_block *nouveau_mem_alloc_block(struct mem_block *,
- uint64_t size, int align2,
- struct drm_file *, int tail);
-extern void nouveau_mem_takedown(struct mem_block **heap);
-extern void nouveau_mem_free_block(struct mem_block *);
extern int nouveau_mem_detect(struct drm_device *dev);
-extern void nouveau_mem_release(struct drm_file *, struct mem_block *heap);
extern int nouveau_mem_init(struct drm_device *);
extern int nouveau_mem_init_agp(struct drm_device *);
+extern int nouveau_mem_reset_agp(struct drm_device *);
extern void nouveau_mem_close(struct drm_device *);
extern struct nouveau_tile_reg *nv10_mem_set_tiling(struct drm_device *dev,
uint32_t addr,
@@ -857,11 +848,13 @@ void nouveau_register_dsm_handler(void);
void nouveau_unregister_dsm_handler(void);
int nouveau_acpi_get_bios_chunk(uint8_t *bios, int offset, int len);
bool nouveau_acpi_rom_supported(struct pci_dev *pdev);
+int nouveau_acpi_edid(struct drm_device *, struct drm_connector *);
#else
static inline void nouveau_register_dsm_handler(void) {}
static inline void nouveau_unregister_dsm_handler(void) {}
static inline bool nouveau_acpi_rom_supported(struct pci_dev *pdev) { return false; }
static inline int nouveau_acpi_get_bios_chunk(uint8_t *bios, int offset, int len) { return -EINVAL; }
+static inline int nouveau_acpi_edid(struct drm_device *dev, struct drm_connector *connector) { return -EINVAL; }
#endif
/* nouveau_backlight.c */
@@ -924,6 +917,10 @@ extern void nv10_fb_takedown(struct drm_device *);
extern void nv10_fb_set_region_tiling(struct drm_device *, int, uint32_t,
uint32_t, uint32_t);
+/* nv30_fb.c */
+extern int nv30_fb_init(struct drm_device *);
+extern void nv30_fb_takedown(struct drm_device *);
+
/* nv40_fb.c */
extern int nv40_fb_init(struct drm_device *);
extern void nv40_fb_takedown(struct drm_device *);
@@ -1035,12 +1032,6 @@ extern int nv50_graph_unload_context(struct drm_device *);
extern void nv50_graph_context_switch(struct drm_device *);
extern int nv50_grctx_init(struct nouveau_grctx *);
-/* nouveau_grctx.c */
-extern int nouveau_grctx_prog_load(struct drm_device *);
-extern void nouveau_grctx_vals_load(struct drm_device *,
- struct nouveau_gpuobj *);
-extern void nouveau_grctx_fini(struct drm_device *);
-
/* nv04_instmem.c */
extern int nv04_instmem_init(struct drm_device *);
extern void nv04_instmem_takedown(struct drm_device *);
@@ -1051,8 +1042,7 @@ extern int nv04_instmem_populate(struct drm_device *, struct nouveau_gpuobj *,
extern void nv04_instmem_clear(struct drm_device *, struct nouveau_gpuobj *);
extern int nv04_instmem_bind(struct drm_device *, struct nouveau_gpuobj *);
extern int nv04_instmem_unbind(struct drm_device *, struct nouveau_gpuobj *);
-extern void nv04_instmem_prepare_access(struct drm_device *, bool write);
-extern void nv04_instmem_finish_access(struct drm_device *);
+extern void nv04_instmem_flush(struct drm_device *);
/* nv50_instmem.c */
extern int nv50_instmem_init(struct drm_device *);
@@ -1064,8 +1054,9 @@ extern int nv50_instmem_populate(struct drm_device *, struct nouveau_gpuobj *,
extern void nv50_instmem_clear(struct drm_device *, struct nouveau_gpuobj *);
extern int nv50_instmem_bind(struct drm_device *, struct nouveau_gpuobj *);
extern int nv50_instmem_unbind(struct drm_device *, struct nouveau_gpuobj *);
-extern void nv50_instmem_prepare_access(struct drm_device *, bool write);
-extern void nv50_instmem_finish_access(struct drm_device *);
+extern void nv50_instmem_flush(struct drm_device *);
+extern void nv84_instmem_flush(struct drm_device *);
+extern void nv50_vm_flush(struct drm_device *, int engine);
/* nv04_mc.c */
extern int nv04_mc_init(struct drm_device *);
@@ -1088,13 +1079,14 @@ extern long nouveau_compat_ioctl(struct file *file, unsigned int cmd,
unsigned long arg);
/* nv04_dac.c */
-extern int nv04_dac_create(struct drm_device *dev, struct dcb_entry *entry);
+extern int nv04_dac_create(struct drm_connector *, struct dcb_entry *);
extern uint32_t nv17_dac_sample_load(struct drm_encoder *encoder);
extern int nv04_dac_output_offset(struct drm_encoder *encoder);
extern void nv04_dac_update_dacclk(struct drm_encoder *encoder, bool enable);
+extern bool nv04_dac_in_use(struct drm_encoder *encoder);
/* nv04_dfp.c */
-extern int nv04_dfp_create(struct drm_device *dev, struct dcb_entry *entry);
+extern int nv04_dfp_create(struct drm_connector *, struct dcb_entry *);
extern int nv04_dfp_get_bound_head(struct drm_device *dev, struct dcb_entry *dcbent);
extern void nv04_dfp_bind_head(struct drm_device *dev, struct dcb_entry *dcbent,
int head, bool dl);
@@ -1103,15 +1095,17 @@ extern void nv04_dfp_update_fp_control(struct drm_encoder *encoder, int mode);
/* nv04_tv.c */
extern int nv04_tv_identify(struct drm_device *dev, int i2c_index);
-extern int nv04_tv_create(struct drm_device *dev, struct dcb_entry *entry);
+extern int nv04_tv_create(struct drm_connector *, struct dcb_entry *);
/* nv17_tv.c */
-extern int nv17_tv_create(struct drm_device *dev, struct dcb_entry *entry);
+extern int nv17_tv_create(struct drm_connector *, struct dcb_entry *);
/* nv04_display.c */
+extern int nv04_display_early_init(struct drm_device *);
+extern void nv04_display_late_takedown(struct drm_device *);
extern int nv04_display_create(struct drm_device *);
+extern int nv04_display_init(struct drm_device *);
extern void nv04_display_destroy(struct drm_device *);
-extern void nv04_display_restore(struct drm_device *);
/* nv04_crtc.c */
extern int nv04_crtc_create(struct drm_device *, int index);
@@ -1147,7 +1141,6 @@ extern int nouveau_fence_wait(void *obj, void *arg, bool lazy, bool intr);
extern int nouveau_fence_flush(void *obj, void *arg);
extern void nouveau_fence_unref(void **obj);
extern void *nouveau_fence_ref(void *obj);
-extern void nouveau_fence_handler(struct drm_device *dev, int channel);
/* nouveau_gem.c */
extern int nouveau_gem_new(struct drm_device *, struct nouveau_channel *,
@@ -1167,13 +1160,15 @@ extern int nouveau_gem_ioctl_cpu_fini(struct drm_device *, void *,
extern int nouveau_gem_ioctl_info(struct drm_device *, void *,
struct drm_file *);
-/* nv17_gpio.c */
-int nv17_gpio_get(struct drm_device *dev, enum dcb_gpio_tag tag);
-int nv17_gpio_set(struct drm_device *dev, enum dcb_gpio_tag tag, int state);
+/* nv10_gpio.c */
+int nv10_gpio_get(struct drm_device *dev, enum dcb_gpio_tag tag);
+int nv10_gpio_set(struct drm_device *dev, enum dcb_gpio_tag tag, int state);
/* nv50_gpio.c */
+int nv50_gpio_init(struct drm_device *dev);
int nv50_gpio_get(struct drm_device *dev, enum dcb_gpio_tag tag);
int nv50_gpio_set(struct drm_device *dev, enum dcb_gpio_tag tag, int state);
+void nv50_gpio_irq_enable(struct drm_device *, enum dcb_gpio_tag, bool on);
/* nv50_calc. */
int nv50_calc_pll(struct drm_device *, struct pll_lims *, int clk,
@@ -1220,6 +1215,14 @@ static inline void nv_wr32(struct drm_device *dev, unsigned reg, u32 val)
iowrite32_native(val, dev_priv->mmio + reg);
}
+static inline void nv_mask(struct drm_device *dev, u32 reg, u32 mask, u32 val)
+{
+ u32 tmp = nv_rd32(dev, reg);
+ tmp &= ~mask;
+ tmp |= val;
+ nv_wr32(dev, reg, tmp);
+}
+
static inline u8 nv_rd08(struct drm_device *dev, unsigned reg)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
diff --git a/drivers/gpu/drm/nouveau/nouveau_encoder.h b/drivers/gpu/drm/nouveau/nouveau_encoder.h
index e1df8209cd0..a1a0d48ae70 100644
--- a/drivers/gpu/drm/nouveau/nouveau_encoder.h
+++ b/drivers/gpu/drm/nouveau/nouveau_encoder.h
@@ -38,13 +38,15 @@ struct nouveau_encoder {
struct dcb_entry *dcb;
int or;
+ /* different to drm_encoder.crtc, this reflects what's
+ * actually programmed on the hw, not the proposed crtc */
+ struct drm_crtc *crtc;
+
struct drm_display_mode mode;
int last_dpms;
struct nv04_output_reg restore;
- void (*disconnect)(struct nouveau_encoder *encoder);
-
union {
struct {
int mc_unknown;
@@ -71,8 +73,8 @@ static inline struct drm_encoder *to_drm_encoder(struct nouveau_encoder *enc)
struct nouveau_connector *
nouveau_encoder_connector_get(struct nouveau_encoder *encoder);
-int nv50_sor_create(struct drm_device *dev, struct dcb_entry *entry);
-int nv50_dac_create(struct drm_device *dev, struct dcb_entry *entry);
+int nv50_sor_create(struct drm_connector *, struct dcb_entry *);
+int nv50_dac_create(struct drm_connector *, struct dcb_entry *);
struct bit_displayport_encoder_table {
uint32_t match;
diff --git a/drivers/gpu/drm/nouveau/nouveau_fbcon.c b/drivers/gpu/drm/nouveau/nouveau_fbcon.c
index 257ea130ae1..2fb2444d232 100644
--- a/drivers/gpu/drm/nouveau/nouveau_fbcon.c
+++ b/drivers/gpu/drm/nouveau/nouveau_fbcon.c
@@ -333,7 +333,7 @@ nouveau_fbcon_output_poll_changed(struct drm_device *dev)
drm_fb_helper_hotplug_event(&dev_priv->nfbdev->helper);
}
-int
+static int
nouveau_fbcon_destroy(struct drm_device *dev, struct nouveau_fbdev *nfbdev)
{
struct nouveau_framebuffer *nouveau_fb = &nfbdev->nouveau_fb;
diff --git a/drivers/gpu/drm/nouveau/nouveau_fence.c b/drivers/gpu/drm/nouveau/nouveau_fence.c
index faddf53ff9e..6b208ffafa8 100644
--- a/drivers/gpu/drm/nouveau/nouveau_fence.c
+++ b/drivers/gpu/drm/nouveau/nouveau_fence.c
@@ -67,12 +67,13 @@ nouveau_fence_update(struct nouveau_channel *chan)
if (USE_REFCNT)
sequence = nvchan_rd32(chan, 0x48);
else
- sequence = chan->fence.last_sequence_irq;
+ sequence = atomic_read(&chan->fence.last_sequence_irq);
if (chan->fence.sequence_ack == sequence)
return;
chan->fence.sequence_ack = sequence;
+ spin_lock(&chan->fence.lock);
list_for_each_safe(entry, tmp, &chan->fence.pending) {
fence = list_entry(entry, struct nouveau_fence, entry);
@@ -84,6 +85,7 @@ nouveau_fence_update(struct nouveau_channel *chan)
if (sequence == chan->fence.sequence_ack)
break;
}
+ spin_unlock(&chan->fence.lock);
}
int
@@ -119,7 +121,6 @@ nouveau_fence_emit(struct nouveau_fence *fence)
{
struct drm_nouveau_private *dev_priv = fence->channel->dev->dev_private;
struct nouveau_channel *chan = fence->channel;
- unsigned long flags;
int ret;
ret = RING_SPACE(chan, 2);
@@ -127,9 +128,7 @@ nouveau_fence_emit(struct nouveau_fence *fence)
return ret;
if (unlikely(chan->fence.sequence == chan->fence.sequence_ack - 1)) {
- spin_lock_irqsave(&chan->fence.lock, flags);
nouveau_fence_update(chan);
- spin_unlock_irqrestore(&chan->fence.lock, flags);
BUG_ON(chan->fence.sequence ==
chan->fence.sequence_ack - 1);
@@ -138,9 +137,9 @@ nouveau_fence_emit(struct nouveau_fence *fence)
fence->sequence = ++chan->fence.sequence;
kref_get(&fence->refcount);
- spin_lock_irqsave(&chan->fence.lock, flags);
+ spin_lock(&chan->fence.lock);
list_add_tail(&fence->entry, &chan->fence.pending);
- spin_unlock_irqrestore(&chan->fence.lock, flags);
+ spin_unlock(&chan->fence.lock);
BEGIN_RING(chan, NvSubSw, USE_REFCNT ? 0x0050 : 0x0150, 1);
OUT_RING(chan, fence->sequence);
@@ -173,14 +172,11 @@ nouveau_fence_signalled(void *sync_obj, void *sync_arg)
{
struct nouveau_fence *fence = nouveau_fence(sync_obj);
struct nouveau_channel *chan = fence->channel;
- unsigned long flags;
if (fence->signalled)
return true;
- spin_lock_irqsave(&chan->fence.lock, flags);
nouveau_fence_update(chan);
- spin_unlock_irqrestore(&chan->fence.lock, flags);
return fence->signalled;
}
@@ -190,8 +186,6 @@ nouveau_fence_wait(void *sync_obj, void *sync_arg, bool lazy, bool intr)
unsigned long timeout = jiffies + (3 * DRM_HZ);
int ret = 0;
- __set_current_state(intr ? TASK_INTERRUPTIBLE : TASK_UNINTERRUPTIBLE);
-
while (1) {
if (nouveau_fence_signalled(sync_obj, sync_arg))
break;
@@ -201,6 +195,8 @@ nouveau_fence_wait(void *sync_obj, void *sync_arg, bool lazy, bool intr)
break;
}
+ __set_current_state(intr ? TASK_INTERRUPTIBLE
+ : TASK_UNINTERRUPTIBLE);
if (lazy)
schedule_timeout(1);
@@ -221,27 +217,12 @@ nouveau_fence_flush(void *sync_obj, void *sync_arg)
return 0;
}
-void
-nouveau_fence_handler(struct drm_device *dev, int channel)
-{
- struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nouveau_channel *chan = NULL;
-
- if (channel >= 0 && channel < dev_priv->engine.fifo.channels)
- chan = dev_priv->fifos[channel];
-
- if (chan) {
- spin_lock_irq(&chan->fence.lock);
- nouveau_fence_update(chan);
- spin_unlock_irq(&chan->fence.lock);
- }
-}
-
int
nouveau_fence_init(struct nouveau_channel *chan)
{
INIT_LIST_HEAD(&chan->fence.pending);
spin_lock_init(&chan->fence.lock);
+ atomic_set(&chan->fence.last_sequence_irq, 0);
return 0;
}
diff --git a/drivers/gpu/drm/nouveau/nouveau_gem.c b/drivers/gpu/drm/nouveau/nouveau_gem.c
index 69c76cf9340..547f2c24c1e 100644
--- a/drivers/gpu/drm/nouveau/nouveau_gem.c
+++ b/drivers/gpu/drm/nouveau/nouveau_gem.c
@@ -137,8 +137,6 @@ nouveau_gem_ioctl_new(struct drm_device *dev, void *data,
uint32_t flags = 0;
int ret = 0;
- NOUVEAU_CHECK_INITIALISED_WITH_RETURN;
-
if (unlikely(dev_priv->ttm.bdev.dev_mapping == NULL))
dev_priv->ttm.bdev.dev_mapping = dev_priv->dev->dev_mapping;
@@ -577,10 +575,9 @@ nouveau_gem_ioctl_pushbuf(struct drm_device *dev, void *data,
struct drm_nouveau_gem_pushbuf_bo *bo;
struct nouveau_channel *chan;
struct validate_op op;
- struct nouveau_fence *fence = 0;
+ struct nouveau_fence *fence = NULL;
int i, j, ret = 0, do_reloc = 0;
- NOUVEAU_CHECK_INITIALISED_WITH_RETURN;
NOUVEAU_GET_USER_CHANNEL_WITH_RETURN(req->channel, file_priv, chan);
req->vram_available = dev_priv->fb_aper_free;
@@ -760,8 +757,6 @@ nouveau_gem_ioctl_cpu_prep(struct drm_device *dev, void *data,
bool no_wait = !!(req->flags & NOUVEAU_GEM_CPU_PREP_NOWAIT);
int ret = -EINVAL;
- NOUVEAU_CHECK_INITIALISED_WITH_RETURN;
-
gem = drm_gem_object_lookup(dev, file_priv, req->handle);
if (!gem)
return ret;
@@ -800,8 +795,6 @@ nouveau_gem_ioctl_cpu_fini(struct drm_device *dev, void *data,
struct nouveau_bo *nvbo;
int ret = -EINVAL;
- NOUVEAU_CHECK_INITIALISED_WITH_RETURN;
-
gem = drm_gem_object_lookup(dev, file_priv, req->handle);
if (!gem)
return ret;
@@ -827,8 +820,6 @@ nouveau_gem_ioctl_info(struct drm_device *dev, void *data,
struct drm_gem_object *gem;
int ret;
- NOUVEAU_CHECK_INITIALISED_WITH_RETURN;
-
gem = drm_gem_object_lookup(dev, file_priv, req->handle);
if (!gem)
return -EINVAL;
diff --git a/drivers/gpu/drm/nouveau/nouveau_grctx.c b/drivers/gpu/drm/nouveau/nouveau_grctx.c
deleted file mode 100644
index f731c5f6053..00000000000
--- a/drivers/gpu/drm/nouveau/nouveau_grctx.c
+++ /dev/null
@@ -1,160 +0,0 @@
-/*
- * Copyright 2009 Red Hat Inc.
- *
- * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include <linux/firmware.h>
-#include <linux/slab.h>
-
-#include "drmP.h"
-#include "nouveau_drv.h"
-
-struct nouveau_ctxprog {
- uint32_t signature;
- uint8_t version;
- uint16_t length;
- uint32_t data[];
-} __attribute__ ((packed));
-
-struct nouveau_ctxvals {
- uint32_t signature;
- uint8_t version;
- uint32_t length;
- struct {
- uint32_t offset;
- uint32_t value;
- } data[];
-} __attribute__ ((packed));
-
-int
-nouveau_grctx_prog_load(struct drm_device *dev)
-{
- struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
- const int chipset = dev_priv->chipset;
- const struct firmware *fw;
- const struct nouveau_ctxprog *cp;
- const struct nouveau_ctxvals *cv;
- char name[32];
- int ret, i;
-
- if (pgraph->accel_blocked)
- return -ENODEV;
-
- if (!pgraph->ctxprog) {
- sprintf(name, "nouveau/nv%02x.ctxprog", chipset);
- ret = request_firmware(&fw, name, &dev->pdev->dev);
- if (ret) {
- NV_ERROR(dev, "No ctxprog for NV%02x\n", chipset);
- return ret;
- }
-
- pgraph->ctxprog = kmemdup(fw->data, fw->size, GFP_KERNEL);
- if (!pgraph->ctxprog) {
- NV_ERROR(dev, "OOM copying ctxprog\n");
- release_firmware(fw);
- return -ENOMEM;
- }
-
- cp = pgraph->ctxprog;
- if (le32_to_cpu(cp->signature) != 0x5043564e ||
- cp->version != 0 ||
- le16_to_cpu(cp->length) != ((fw->size - 7) / 4)) {
- NV_ERROR(dev, "ctxprog invalid\n");
- release_firmware(fw);
- nouveau_grctx_fini(dev);
- return -EINVAL;
- }
- release_firmware(fw);
- }
-
- if (!pgraph->ctxvals) {
- sprintf(name, "nouveau/nv%02x.ctxvals", chipset);
- ret = request_firmware(&fw, name, &dev->pdev->dev);
- if (ret) {
- NV_ERROR(dev, "No ctxvals for NV%02x\n", chipset);
- nouveau_grctx_fini(dev);
- return ret;
- }
-
- pgraph->ctxvals = kmemdup(fw->data, fw->size, GFP_KERNEL);
- if (!pgraph->ctxvals) {
- NV_ERROR(dev, "OOM copying ctxvals\n");
- release_firmware(fw);
- nouveau_grctx_fini(dev);
- return -ENOMEM;
- }
-
- cv = (void *)pgraph->ctxvals;
- if (le32_to_cpu(cv->signature) != 0x5643564e ||
- cv->version != 0 ||
- le32_to_cpu(cv->length) != ((fw->size - 9) / 8)) {
- NV_ERROR(dev, "ctxvals invalid\n");
- release_firmware(fw);
- nouveau_grctx_fini(dev);
- return -EINVAL;
- }
- release_firmware(fw);
- }
-
- cp = pgraph->ctxprog;
-
- nv_wr32(dev, NV40_PGRAPH_CTXCTL_UCODE_INDEX, 0);
- for (i = 0; i < le16_to_cpu(cp->length); i++)
- nv_wr32(dev, NV40_PGRAPH_CTXCTL_UCODE_DATA,
- le32_to_cpu(cp->data[i]));
-
- return 0;
-}
-
-void
-nouveau_grctx_fini(struct drm_device *dev)
-{
- struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
-
- if (pgraph->ctxprog) {
- kfree(pgraph->ctxprog);
- pgraph->ctxprog = NULL;
- }
-
- if (pgraph->ctxvals) {
- kfree(pgraph->ctxprog);
- pgraph->ctxvals = NULL;
- }
-}
-
-void
-nouveau_grctx_vals_load(struct drm_device *dev, struct nouveau_gpuobj *ctx)
-{
- struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
- struct nouveau_ctxvals *cv = pgraph->ctxvals;
- int i;
-
- if (!cv)
- return;
-
- for (i = 0; i < le32_to_cpu(cv->length); i++)
- nv_wo32(dev, ctx, le32_to_cpu(cv->data[i].offset),
- le32_to_cpu(cv->data[i].value));
-}
diff --git a/drivers/gpu/drm/nouveau/nouveau_i2c.c b/drivers/gpu/drm/nouveau/nouveau_i2c.c
index 316a3c7e6eb..cb0cb34440c 100644
--- a/drivers/gpu/drm/nouveau/nouveau_i2c.c
+++ b/drivers/gpu/drm/nouveau/nouveau_i2c.c
@@ -278,3 +278,45 @@ nouveau_i2c_find(struct drm_device *dev, int index)
return i2c->chan;
}
+bool
+nouveau_probe_i2c_addr(struct nouveau_i2c_chan *i2c, int addr)
+{
+ uint8_t buf[] = { 0 };
+ struct i2c_msg msgs[] = {
+ {
+ .addr = addr,
+ .flags = 0,
+ .len = 1,
+ .buf = buf,
+ },
+ {
+ .addr = addr,
+ .flags = I2C_M_RD,
+ .len = 1,
+ .buf = buf,
+ }
+ };
+
+ return i2c_transfer(&i2c->adapter, msgs, 2) == 2;
+}
+
+int
+nouveau_i2c_identify(struct drm_device *dev, const char *what,
+ struct i2c_board_info *info, int index)
+{
+ struct nouveau_i2c_chan *i2c = nouveau_i2c_find(dev, index);
+ int i;
+
+ NV_DEBUG(dev, "Probing %ss on I2C bus: %d\n", what, index);
+
+ for (i = 0; info[i].addr; i++) {
+ if (nouveau_probe_i2c_addr(i2c, info[i].addr)) {
+ NV_INFO(dev, "Detected %s: %s\n", what, info[i].type);
+ return i;
+ }
+ }
+
+ NV_DEBUG(dev, "No devices found.\n");
+
+ return -ENODEV;
+}
diff --git a/drivers/gpu/drm/nouveau/nouveau_i2c.h b/drivers/gpu/drm/nouveau/nouveau_i2c.h
index c8eaf7a9fcb..6dd2f8713cd 100644
--- a/drivers/gpu/drm/nouveau/nouveau_i2c.h
+++ b/drivers/gpu/drm/nouveau/nouveau_i2c.h
@@ -45,6 +45,9 @@ struct nouveau_i2c_chan {
int nouveau_i2c_init(struct drm_device *, struct dcb_i2c_entry *, int index);
void nouveau_i2c_fini(struct drm_device *, struct dcb_i2c_entry *);
struct nouveau_i2c_chan *nouveau_i2c_find(struct drm_device *, int index);
+bool nouveau_probe_i2c_addr(struct nouveau_i2c_chan *i2c, int addr);
+int nouveau_i2c_identify(struct drm_device *dev, const char *what,
+ struct i2c_board_info *info, int index);
int nouveau_dp_i2c_aux_ch(struct i2c_adapter *, int mode, uint8_t write_byte,
uint8_t *read_byte);
diff --git a/drivers/gpu/drm/nouveau/nouveau_mem.c b/drivers/gpu/drm/nouveau/nouveau_mem.c
index c1fd42b0dad..a9f36ab256b 100644
--- a/drivers/gpu/drm/nouveau/nouveau_mem.c
+++ b/drivers/gpu/drm/nouveau/nouveau_mem.c
@@ -35,162 +35,6 @@
#include "drm_sarea.h"
#include "nouveau_drv.h"
-static struct mem_block *
-split_block(struct mem_block *p, uint64_t start, uint64_t size,
- struct drm_file *file_priv)
-{
- /* Maybe cut off the start of an existing block */
- if (start > p->start) {
- struct mem_block *newblock =
- kmalloc(sizeof(*newblock), GFP_KERNEL);
- if (!newblock)
- goto out;
- newblock->start = start;
- newblock->size = p->size - (start - p->start);
- newblock->file_priv = NULL;
- newblock->next = p->next;
- newblock->prev = p;
- p->next->prev = newblock;
- p->next = newblock;
- p->size -= newblock->size;
- p = newblock;
- }
-
- /* Maybe cut off the end of an existing block */
- if (size < p->size) {
- struct mem_block *newblock =
- kmalloc(sizeof(*newblock), GFP_KERNEL);
- if (!newblock)
- goto out;
- newblock->start = start + size;
- newblock->size = p->size - size;
- newblock->file_priv = NULL;
- newblock->next = p->next;
- newblock->prev = p;
- p->next->prev = newblock;
- p->next = newblock;
- p->size = size;
- }
-
-out:
- /* Our block is in the middle */
- p->file_priv = file_priv;
- return p;
-}
-
-struct mem_block *
-nouveau_mem_alloc_block(struct mem_block *heap, uint64_t size,
- int align2, struct drm_file *file_priv, int tail)
-{
- struct mem_block *p;
- uint64_t mask = (1 << align2) - 1;
-
- if (!heap)
- return NULL;
-
- if (tail) {
- list_for_each_prev(p, heap) {
- uint64_t start = ((p->start + p->size) - size) & ~mask;
-
- if (p->file_priv == NULL && start >= p->start &&
- start + size <= p->start + p->size)
- return split_block(p, start, size, file_priv);
- }
- } else {
- list_for_each(p, heap) {
- uint64_t start = (p->start + mask) & ~mask;
-
- if (p->file_priv == NULL &&
- start + size <= p->start + p->size)
- return split_block(p, start, size, file_priv);
- }
- }
-
- return NULL;
-}
-
-void nouveau_mem_free_block(struct mem_block *p)
-{
- p->file_priv = NULL;
-
- /* Assumes a single contiguous range. Needs a special file_priv in
- * 'heap' to stop it being subsumed.
- */
- if (p->next->file_priv == NULL) {
- struct mem_block *q = p->next;
- p->size += q->size;
- p->next = q->next;
- p->next->prev = p;
- kfree(q);
- }
-
- if (p->prev->file_priv == NULL) {
- struct mem_block *q = p->prev;
- q->size += p->size;
- q->next = p->next;
- q->next->prev = q;
- kfree(p);
- }
-}
-
-/* Initialize. How to check for an uninitialized heap?
- */
-int nouveau_mem_init_heap(struct mem_block **heap, uint64_t start,
- uint64_t size)
-{
- struct mem_block *blocks = kmalloc(sizeof(*blocks), GFP_KERNEL);
-
- if (!blocks)
- return -ENOMEM;
-
- *heap = kmalloc(sizeof(**heap), GFP_KERNEL);
- if (!*heap) {
- kfree(blocks);
- return -ENOMEM;
- }
-
- blocks->start = start;
- blocks->size = size;
- blocks->file_priv = NULL;
- blocks->next = blocks->prev = *heap;
-
- memset(*heap, 0, sizeof(**heap));
- (*heap)->file_priv = (struct drm_file *) -1;
- (*heap)->next = (*heap)->prev = blocks;
- return 0;
-}
-
-/*
- * Free all blocks associated with the releasing file_priv
- */
-void nouveau_mem_release(struct drm_file *file_priv, struct mem_block *heap)
-{
- struct mem_block *p;
-
- if (!heap || !heap->next)
- return;
-
- list_for_each(p, heap) {
- if (p->file_priv == file_priv)
- p->file_priv = NULL;
- }
-
- /* Assumes a single contiguous range. Needs a special file_priv in
- * 'heap' to stop it being subsumed.
- */
- list_for_each(p, heap) {
- while ((p->file_priv == NULL) &&
- (p->next->file_priv == NULL) &&
- (p->next != heap)) {
- struct mem_block *q = p->next;
- p->size += q->size;
- p->next = q->next;
- p->next->prev = p;
- kfree(q);
- }
- }
-}
-
/*
* NV10-NV40 tiling helpers
*/
@@ -299,7 +143,6 @@ nv50_mem_vm_bind_linear(struct drm_device *dev, uint64_t virt, uint32_t size,
phys |= 0x30;
}
- dev_priv->engine.instmem.prepare_access(dev, true);
while (size) {
unsigned offset_h = upper_32_bits(phys);
unsigned offset_l = lower_32_bits(phys);
@@ -331,36 +174,12 @@ nv50_mem_vm_bind_linear(struct drm_device *dev, uint64_t virt, uint32_t size,
}
}
}
- dev_priv->engine.instmem.finish_access(dev);
-
- nv_wr32(dev, 0x100c80, 0x00050001);
- if (!nv_wait(0x100c80, 0x00000001, 0x00000000)) {
- NV_ERROR(dev, "timeout: (0x100c80 & 1) == 0 (2)\n");
- NV_ERROR(dev, "0x100c80 = 0x%08x\n", nv_rd32(dev, 0x100c80));
- return -EBUSY;
- }
-
- nv_wr32(dev, 0x100c80, 0x00000001);
- if (!nv_wait(0x100c80, 0x00000001, 0x00000000)) {
- NV_ERROR(dev, "timeout: (0x100c80 & 1) == 0 (2)\n");
- NV_ERROR(dev, "0x100c80 = 0x%08x\n", nv_rd32(dev, 0x100c80));
- return -EBUSY;
- }
-
- nv_wr32(dev, 0x100c80, 0x00040001);
- if (!nv_wait(0x100c80, 0x00000001, 0x00000000)) {
- NV_ERROR(dev, "timeout: (0x100c80 & 1) == 0 (2)\n");
- NV_ERROR(dev, "0x100c80 = 0x%08x\n", nv_rd32(dev, 0x100c80));
- return -EBUSY;
- }
-
- nv_wr32(dev, 0x100c80, 0x00060001);
- if (!nv_wait(0x100c80, 0x00000001, 0x00000000)) {
- NV_ERROR(dev, "timeout: (0x100c80 & 1) == 0 (2)\n");
- NV_ERROR(dev, "0x100c80 = 0x%08x\n", nv_rd32(dev, 0x100c80));
- return -EBUSY;
- }
+ dev_priv->engine.instmem.flush(dev);
+ nv50_vm_flush(dev, 5);
+ nv50_vm_flush(dev, 0);
+ nv50_vm_flush(dev, 4);
+ nv50_vm_flush(dev, 6);
return 0;
}
@@ -374,7 +193,6 @@ nv50_mem_vm_unbind(struct drm_device *dev, uint64_t virt, uint32_t size)
virt -= dev_priv->vm_vram_base;
pages = (size >> 16) << 1;
- dev_priv->engine.instmem.prepare_access(dev, true);
while (pages) {
pgt = dev_priv->vm_vram_pt[virt >> 29];
pte = (virt & 0x1ffe0000ULL) >> 15;
@@ -388,57 +206,19 @@ nv50_mem_vm_unbind(struct drm_device *dev, uint64_t virt, uint32_t size)
while (pte < end)
nv_wo32(dev, pgt, pte++, 0);
}
- dev_priv->engine.instmem.finish_access(dev);
-
- nv_wr32(dev, 0x100c80, 0x00050001);
- if (!nv_wait(0x100c80, 0x00000001, 0x00000000)) {
- NV_ERROR(dev, "timeout: (0x100c80 & 1) == 0 (2)\n");
- NV_ERROR(dev, "0x100c80 = 0x%08x\n", nv_rd32(dev, 0x100c80));
- return;
- }
-
- nv_wr32(dev, 0x100c80, 0x00000001);
- if (!nv_wait(0x100c80, 0x00000001, 0x00000000)) {
- NV_ERROR(dev, "timeout: (0x100c80 & 1) == 0 (2)\n");
- NV_ERROR(dev, "0x100c80 = 0x%08x\n", nv_rd32(dev, 0x100c80));
- return;
- }
-
- nv_wr32(dev, 0x100c80, 0x00040001);
- if (!nv_wait(0x100c80, 0x00000001, 0x00000000)) {
- NV_ERROR(dev, "timeout: (0x100c80 & 1) == 0 (2)\n");
- NV_ERROR(dev, "0x100c80 = 0x%08x\n", nv_rd32(dev, 0x100c80));
- return;
- }
+ dev_priv->engine.instmem.flush(dev);
- nv_wr32(dev, 0x100c80, 0x00060001);
- if (!nv_wait(0x100c80, 0x00000001, 0x00000000)) {
- NV_ERROR(dev, "timeout: (0x100c80 & 1) == 0 (2)\n");
- NV_ERROR(dev, "0x100c80 = 0x%08x\n", nv_rd32(dev, 0x100c80));
- }
+ nv50_vm_flush(dev, 5);
+ nv50_vm_flush(dev, 0);
+ nv50_vm_flush(dev, 4);
+ nv50_vm_flush(dev, 6);
}
/*
* Cleanup everything
*/
-void nouveau_mem_takedown(struct mem_block **heap)
-{
- struct mem_block *p;
-
- if (!*heap)
- return;
-
- for (p = (*heap)->next; p != *heap;) {
- struct mem_block *q = p;
- p = p->next;
- kfree(q);
- }
-
- kfree(*heap);
- *heap = NULL;
-}
-
-void nouveau_mem_close(struct drm_device *dev)
+void
+nouveau_mem_close(struct drm_device *dev)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
@@ -449,8 +229,7 @@ void nouveau_mem_close(struct drm_device *dev)
nouveau_ttm_global_release(dev_priv);
- if (drm_core_has_AGP(dev) && dev->agp &&
- drm_core_check_feature(dev, DRIVER_MODESET)) {
+ if (drm_core_has_AGP(dev) && dev->agp) {
struct drm_agp_mem *entry, *tempe;
/* Remove AGP resources, but leave dev->agp
@@ -471,28 +250,29 @@ void nouveau_mem_close(struct drm_device *dev)
}
if (dev_priv->fb_mtrr) {
- drm_mtrr_del(dev_priv->fb_mtrr, drm_get_resource_start(dev, 1),
- drm_get_resource_len(dev, 1), DRM_MTRR_WC);
- dev_priv->fb_mtrr = 0;
+ drm_mtrr_del(dev_priv->fb_mtrr,
+ pci_resource_start(dev->pdev, 1),
+ pci_resource_len(dev->pdev, 1), DRM_MTRR_WC);
+ dev_priv->fb_mtrr = -1;
}
}
static uint32_t
nouveau_mem_detect_nv04(struct drm_device *dev)
{
- uint32_t boot0 = nv_rd32(dev, NV03_BOOT_0);
+ uint32_t boot0 = nv_rd32(dev, NV04_PFB_BOOT_0);
if (boot0 & 0x00000100)
return (((boot0 >> 12) & 0xf) * 2 + 2) * 1024 * 1024;
- switch (boot0 & NV03_BOOT_0_RAM_AMOUNT) {
- case NV04_BOOT_0_RAM_AMOUNT_32MB:
+ switch (boot0 & NV04_PFB_BOOT_0_RAM_AMOUNT) {
+ case NV04_PFB_BOOT_0_RAM_AMOUNT_32MB:
return 32 * 1024 * 1024;
- case NV04_BOOT_0_RAM_AMOUNT_16MB:
+ case NV04_PFB_BOOT_0_RAM_AMOUNT_16MB:
return 16 * 1024 * 1024;
- case NV04_BOOT_0_RAM_AMOUNT_8MB:
+ case NV04_PFB_BOOT_0_RAM_AMOUNT_8MB:
return 8 * 1024 * 1024;
- case NV04_BOOT_0_RAM_AMOUNT_4MB:
+ case NV04_PFB_BOOT_0_RAM_AMOUNT_4MB:
return 4 * 1024 * 1024;
}
@@ -536,12 +316,18 @@ nouveau_mem_detect(struct drm_device *dev)
} else
if (dev_priv->flags & (NV_NFORCE | NV_NFORCE2)) {
dev_priv->vram_size = nouveau_mem_detect_nforce(dev);
+ } else
+ if (dev_priv->card_type < NV_50) {
+ dev_priv->vram_size = nv_rd32(dev, NV04_PFB_FIFO_DATA);
+ dev_priv->vram_size &= NV10_PFB_FIFO_DATA_RAM_AMOUNT_MB_MASK;
} else {
- dev_priv->vram_size = nv_rd32(dev, NV04_FIFO_DATA);
- dev_priv->vram_size &= NV10_FIFO_DATA_RAM_AMOUNT_MB_MASK;
- if (dev_priv->chipset == 0xaa || dev_priv->chipset == 0xac)
+ dev_priv->vram_size = nv_rd32(dev, NV04_PFB_FIFO_DATA);
+ dev_priv->vram_size |= (dev_priv->vram_size & 0xff) << 32;
+ dev_priv->vram_size &= 0xffffffff00ll;
+ if (dev_priv->chipset == 0xaa || dev_priv->chipset == 0xac) {
dev_priv->vram_sys_base = nv_rd32(dev, 0x100e10);
dev_priv->vram_sys_base <<= 12;
+ }
}
NV_INFO(dev, "Detected %dMiB VRAM\n", (int)(dev_priv->vram_size >> 20));
@@ -555,18 +341,36 @@ nouveau_mem_detect(struct drm_device *dev)
return -ENOMEM;
}
-#if __OS_HAS_AGP
-static void nouveau_mem_reset_agp(struct drm_device *dev)
+int
+nouveau_mem_reset_agp(struct drm_device *dev)
{
- uint32_t saved_pci_nv_1, saved_pci_nv_19, pmc_enable;
+#if __OS_HAS_AGP
+ uint32_t saved_pci_nv_1, pmc_enable;
+ int ret;
+
+ /* First of all, disable fast writes, otherwise if it's
+ * already enabled in the AGP bridge and we disable the card's
+ * AGP controller we might be locking ourselves out of it. */
+ if (dev->agp->acquired) {
+ struct drm_agp_info info;
+ struct drm_agp_mode mode;
+
+ ret = drm_agp_info(dev, &info);
+ if (ret)
+ return ret;
+
+ mode.mode = info.mode & ~0x10;
+ ret = drm_agp_enable(dev, mode);
+ if (ret)
+ return ret;
+ }
saved_pci_nv_1 = nv_rd32(dev, NV04_PBUS_PCI_NV_1);
- saved_pci_nv_19 = nv_rd32(dev, NV04_PBUS_PCI_NV_19);
/* clear busmaster bit */
nv_wr32(dev, NV04_PBUS_PCI_NV_1, saved_pci_nv_1 & ~0x4);
- /* clear SBA and AGP bits */
- nv_wr32(dev, NV04_PBUS_PCI_NV_19, saved_pci_nv_19 & 0xfffff0ff);
+ /* disable AGP */
+ nv_wr32(dev, NV04_PBUS_PCI_NV_19, 0);
/* power cycle pgraph, if enabled */
pmc_enable = nv_rd32(dev, NV03_PMC_ENABLE);
@@ -578,11 +382,12 @@ static void nouveau_mem_reset_agp(struct drm_device *dev)
}
/* and restore (gives effect of resetting AGP) */
- nv_wr32(dev, NV04_PBUS_PCI_NV_19, saved_pci_nv_19);
nv_wr32(dev, NV04_PBUS_PCI_NV_1, saved_pci_nv_1);
-}
#endif
+ return 0;
+}
+
int
nouveau_mem_init_agp(struct drm_device *dev)
{
@@ -592,11 +397,6 @@ nouveau_mem_init_agp(struct drm_device *dev)
struct drm_agp_mode mode;
int ret;
- if (nouveau_noagp)
- return 0;
-
- nouveau_mem_reset_agp(dev);
-
if (!dev->agp->acquired) {
ret = drm_agp_acquire(dev);
if (ret) {
@@ -633,7 +433,7 @@ nouveau_mem_init(struct drm_device *dev)
struct ttm_bo_device *bdev = &dev_priv->ttm.bdev;
int ret, dma_bits = 32;
- dev_priv->fb_phys = drm_get_resource_start(dev, 1);
+ dev_priv->fb_phys = pci_resource_start(dev->pdev, 1);
dev_priv->gart_info.type = NOUVEAU_GART_NONE;
if (dev_priv->card_type >= NV_50 &&
@@ -665,8 +465,9 @@ nouveau_mem_init(struct drm_device *dev)
dev_priv->fb_available_size = dev_priv->vram_size;
dev_priv->fb_mappable_pages = dev_priv->fb_available_size;
- if (dev_priv->fb_mappable_pages > drm_get_resource_len(dev, 1))
- dev_priv->fb_mappable_pages = drm_get_resource_len(dev, 1);
+ if (dev_priv->fb_mappable_pages > pci_resource_len(dev->pdev, 1))
+ dev_priv->fb_mappable_pages =
+ pci_resource_len(dev->pdev, 1);
dev_priv->fb_mappable_pages >>= PAGE_SHIFT;
/* remove reserved space at end of vram from available amount */
@@ -692,7 +493,8 @@ nouveau_mem_init(struct drm_device *dev)
/* GART */
#if !defined(__powerpc__) && !defined(__ia64__)
- if (drm_device_is_agp(dev) && dev->agp) {
+ if (drm_device_is_agp(dev) && dev->agp && !nouveau_noagp) {
+ nouveau_mem_reset_agp(dev);
ret = nouveau_mem_init_agp(dev);
if (ret)
NV_ERROR(dev, "Error initialising AGP: %d\n", ret);
@@ -718,8 +520,8 @@ nouveau_mem_init(struct drm_device *dev)
return ret;
}
- dev_priv->fb_mtrr = drm_mtrr_add(drm_get_resource_start(dev, 1),
- drm_get_resource_len(dev, 1),
+ dev_priv->fb_mtrr = drm_mtrr_add(pci_resource_start(dev->pdev, 1),
+ pci_resource_len(dev->pdev, 1),
DRM_MTRR_WC);
return 0;
diff --git a/drivers/gpu/drm/nouveau/nouveau_notifier.c b/drivers/gpu/drm/nouveau/nouveau_notifier.c
index 9537f3e3011..3ec181ff50c 100644
--- a/drivers/gpu/drm/nouveau/nouveau_notifier.c
+++ b/drivers/gpu/drm/nouveau/nouveau_notifier.c
@@ -55,7 +55,7 @@ nouveau_notifier_init_channel(struct nouveau_channel *chan)
if (ret)
goto out_err;
- ret = nouveau_mem_init_heap(&chan->notifier_heap, 0, ntfy->bo.mem.size);
+ ret = drm_mm_init(&chan->notifier_heap, 0, ntfy->bo.mem.size);
if (ret)
goto out_err;
@@ -80,7 +80,7 @@ nouveau_notifier_takedown_channel(struct nouveau_channel *chan)
nouveau_bo_unpin(chan->notifier_bo);
mutex_unlock(&dev->struct_mutex);
drm_gem_object_unreference_unlocked(chan->notifier_bo->gem);
- nouveau_mem_takedown(&chan->notifier_heap);
+ drm_mm_takedown(&chan->notifier_heap);
}
static void
@@ -90,7 +90,7 @@ nouveau_notifier_gpuobj_dtor(struct drm_device *dev,
NV_DEBUG(dev, "\n");
if (gpuobj->priv)
- nouveau_mem_free_block(gpuobj->priv);
+ drm_mm_put_block(gpuobj->priv);
}
int
@@ -100,18 +100,13 @@ nouveau_notifier_alloc(struct nouveau_channel *chan, uint32_t handle,
struct drm_device *dev = chan->dev;
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_gpuobj *nobj = NULL;
- struct mem_block *mem;
+ struct drm_mm_node *mem;
uint32_t offset;
int target, ret;
- if (!chan->notifier_heap) {
- NV_ERROR(dev, "Channel %d doesn't have a notifier heap!\n",
- chan->id);
- return -EINVAL;
- }
-
- mem = nouveau_mem_alloc_block(chan->notifier_heap, size, 0,
- (struct drm_file *)-2, 0);
+ mem = drm_mm_search_free(&chan->notifier_heap, size, 0, 0);
+ if (mem)
+ mem = drm_mm_get_block(mem, size, 0);
if (!mem) {
NV_ERROR(dev, "Channel %d notifier block full\n", chan->id);
return -ENOMEM;
@@ -144,17 +139,17 @@ nouveau_notifier_alloc(struct nouveau_channel *chan, uint32_t handle,
mem->size, NV_DMA_ACCESS_RW, target,
&nobj);
if (ret) {
- nouveau_mem_free_block(mem);
+ drm_mm_put_block(mem);
NV_ERROR(dev, "Error creating notifier ctxdma: %d\n", ret);
return ret;
}
- nobj->dtor = nouveau_notifier_gpuobj_dtor;
- nobj->priv = mem;
+ nobj->dtor = nouveau_notifier_gpuobj_dtor;
+ nobj->priv = mem;
ret = nouveau_gpuobj_ref_add(dev, chan, handle, nobj, NULL);
if (ret) {
nouveau_gpuobj_del(dev, &nobj);
- nouveau_mem_free_block(mem);
+ drm_mm_put_block(mem);
NV_ERROR(dev, "Error referencing notifier ctxdma: %d\n", ret);
return ret;
}
@@ -170,7 +165,7 @@ nouveau_notifier_offset(struct nouveau_gpuobj *nobj, uint32_t *poffset)
return -EINVAL;
if (poffset) {
- struct mem_block *mem = nobj->priv;
+ struct drm_mm_node *mem = nobj->priv;
if (*poffset >= mem->size)
return false;
@@ -189,7 +184,6 @@ nouveau_ioctl_notifier_alloc(struct drm_device *dev, void *data,
struct nouveau_channel *chan;
int ret;
- NOUVEAU_CHECK_INITIALISED_WITH_RETURN;
NOUVEAU_GET_USER_CHANNEL_WITH_RETURN(na->channel, file_priv, chan);
ret = nouveau_notifier_alloc(chan, na->handle, na->size, &na->offset);
diff --git a/drivers/gpu/drm/nouveau/nouveau_object.c b/drivers/gpu/drm/nouveau/nouveau_object.c
index e7c100ba63a..b6bcb254f4a 100644
--- a/drivers/gpu/drm/nouveau/nouveau_object.c
+++ b/drivers/gpu/drm/nouveau/nouveau_object.c
@@ -132,7 +132,6 @@ nouveau_ramht_insert(struct drm_device *dev, struct nouveau_gpuobj_ref *ref)
}
}
- instmem->prepare_access(dev, true);
co = ho = nouveau_ramht_hash_handle(dev, chan->id, ref->handle);
do {
if (!nouveau_ramht_entry_valid(dev, ramht, co)) {
@@ -143,7 +142,7 @@ nouveau_ramht_insert(struct drm_device *dev, struct nouveau_gpuobj_ref *ref)
nv_wo32(dev, ramht, (co + 4)/4, ctx);
list_add_tail(&ref->list, &chan->ramht_refs);
- instmem->finish_access(dev);
+ instmem->flush(dev);
return 0;
}
NV_DEBUG(dev, "collision ch%d 0x%08x: h=0x%08x\n",
@@ -153,7 +152,6 @@ nouveau_ramht_insert(struct drm_device *dev, struct nouveau_gpuobj_ref *ref)
if (co >= dev_priv->ramht_size)
co = 0;
} while (co != ho);
- instmem->finish_access(dev);
NV_ERROR(dev, "RAMHT space exhausted. ch=%d\n", chan->id);
return -ENOMEM;
@@ -173,7 +171,6 @@ nouveau_ramht_remove(struct drm_device *dev, struct nouveau_gpuobj_ref *ref)
return;
}
- instmem->prepare_access(dev, true);
co = ho = nouveau_ramht_hash_handle(dev, chan->id, ref->handle);
do {
if (nouveau_ramht_entry_valid(dev, ramht, co) &&
@@ -186,7 +183,7 @@ nouveau_ramht_remove(struct drm_device *dev, struct nouveau_gpuobj_ref *ref)
nv_wo32(dev, ramht, (co + 4)/4, 0x00000000);
list_del(&ref->list);
- instmem->finish_access(dev);
+ instmem->flush(dev);
return;
}
@@ -195,7 +192,6 @@ nouveau_ramht_remove(struct drm_device *dev, struct nouveau_gpuobj_ref *ref)
co = 0;
} while (co != ho);
list_del(&ref->list);
- instmem->finish_access(dev);
NV_ERROR(dev, "RAMHT entry not found. ch=%d, handle=0x%08x\n",
chan->id, ref->handle);
@@ -209,7 +205,7 @@ nouveau_gpuobj_new(struct drm_device *dev, struct nouveau_channel *chan,
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_engine *engine = &dev_priv->engine;
struct nouveau_gpuobj *gpuobj;
- struct mem_block *pramin = NULL;
+ struct drm_mm *pramin = NULL;
int ret;
NV_DEBUG(dev, "ch%d size=%u align=%d flags=0x%08x\n",
@@ -233,25 +229,12 @@ nouveau_gpuobj_new(struct drm_device *dev, struct nouveau_channel *chan,
* available.
*/
if (chan) {
- if (chan->ramin_heap) {
- NV_DEBUG(dev, "private heap\n");
- pramin = chan->ramin_heap;
- } else
- if (dev_priv->card_type < NV_50) {
- NV_DEBUG(dev, "global heap fallback\n");
- pramin = dev_priv->ramin_heap;
- }
+ NV_DEBUG(dev, "channel heap\n");
+ pramin = &chan->ramin_heap;
} else {
NV_DEBUG(dev, "global heap\n");
- pramin = dev_priv->ramin_heap;
- }
-
- if (!pramin) {
- NV_ERROR(dev, "No PRAMIN heap!\n");
- return -EINVAL;
- }
+ pramin = &dev_priv->ramin_heap;
- if (!chan) {
ret = engine->instmem.populate(dev, gpuobj, &size);
if (ret) {
nouveau_gpuobj_del(dev, &gpuobj);
@@ -260,9 +243,10 @@ nouveau_gpuobj_new(struct drm_device *dev, struct nouveau_channel *chan,
}
/* Allocate a chunk of the PRAMIN aperture */
- gpuobj->im_pramin = nouveau_mem_alloc_block(pramin, size,
- drm_order(align),
- (struct drm_file *)-2, 0);
+ gpuobj->im_pramin = drm_mm_search_free(pramin, size, align, 0);
+ if (gpuobj->im_pramin)
+ gpuobj->im_pramin = drm_mm_get_block(gpuobj->im_pramin, size, align);
+
if (!gpuobj->im_pramin) {
nouveau_gpuobj_del(dev, &gpuobj);
return -ENOMEM;
@@ -279,10 +263,9 @@ nouveau_gpuobj_new(struct drm_device *dev, struct nouveau_channel *chan,
if (gpuobj->flags & NVOBJ_FLAG_ZERO_ALLOC) {
int i;
- engine->instmem.prepare_access(dev, true);
for (i = 0; i < gpuobj->im_pramin->size; i += 4)
nv_wo32(dev, gpuobj, i/4, 0);
- engine->instmem.finish_access(dev);
+ engine->instmem.flush(dev);
}
*gpuobj_ret = gpuobj;
@@ -370,10 +353,9 @@ nouveau_gpuobj_del(struct drm_device *dev, struct nouveau_gpuobj **pgpuobj)
}
if (gpuobj->im_pramin && (gpuobj->flags & NVOBJ_FLAG_ZERO_FREE)) {
- engine->instmem.prepare_access(dev, true);
for (i = 0; i < gpuobj->im_pramin->size; i += 4)
nv_wo32(dev, gpuobj, i/4, 0);
- engine->instmem.finish_access(dev);
+ engine->instmem.flush(dev);
}
if (gpuobj->dtor)
@@ -386,7 +368,7 @@ nouveau_gpuobj_del(struct drm_device *dev, struct nouveau_gpuobj **pgpuobj)
if (gpuobj->flags & NVOBJ_FLAG_FAKE)
kfree(gpuobj->im_pramin);
else
- nouveau_mem_free_block(gpuobj->im_pramin);
+ drm_mm_put_block(gpuobj->im_pramin);
}
list_del(&gpuobj->list);
@@ -589,7 +571,7 @@ nouveau_gpuobj_new_fake(struct drm_device *dev, uint32_t p_offset,
list_add_tail(&gpuobj->list, &dev_priv->gpuobj_list);
if (p_offset != ~0) {
- gpuobj->im_pramin = kzalloc(sizeof(struct mem_block),
+ gpuobj->im_pramin = kzalloc(sizeof(struct drm_mm_node),
GFP_KERNEL);
if (!gpuobj->im_pramin) {
nouveau_gpuobj_del(dev, &gpuobj);
@@ -605,10 +587,9 @@ nouveau_gpuobj_new_fake(struct drm_device *dev, uint32_t p_offset,
}
if (gpuobj->flags & NVOBJ_FLAG_ZERO_ALLOC) {
- dev_priv->engine.instmem.prepare_access(dev, true);
for (i = 0; i < gpuobj->im_pramin->size; i += 4)
nv_wo32(dev, gpuobj, i/4, 0);
- dev_priv->engine.instmem.finish_access(dev);
+ dev_priv->engine.instmem.flush(dev);
}
if (pref) {
@@ -696,8 +677,6 @@ nouveau_gpuobj_dma_new(struct nouveau_channel *chan, int class,
return ret;
}
- instmem->prepare_access(dev, true);
-
if (dev_priv->card_type < NV_50) {
uint32_t frame, adjust, pte_flags = 0;
@@ -734,7 +713,7 @@ nouveau_gpuobj_dma_new(struct nouveau_channel *chan, int class,
nv_wo32(dev, *gpuobj, 5, flags5);
}
- instmem->finish_access(dev);
+ instmem->flush(dev);
(*gpuobj)->engine = NVOBJ_ENGINE_SW;
(*gpuobj)->class = class;
@@ -849,7 +828,6 @@ nouveau_gpuobj_gr_new(struct nouveau_channel *chan, int class,
return ret;
}
- dev_priv->engine.instmem.prepare_access(dev, true);
if (dev_priv->card_type >= NV_50) {
nv_wo32(dev, *gpuobj, 0, class);
nv_wo32(dev, *gpuobj, 5, 0x00010000);
@@ -874,7 +852,7 @@ nouveau_gpuobj_gr_new(struct nouveau_channel *chan, int class,
}
}
}
- dev_priv->engine.instmem.finish_access(dev);
+ dev_priv->engine.instmem.flush(dev);
(*gpuobj)->engine = NVOBJ_ENGINE_GR;
(*gpuobj)->class = class;
@@ -920,6 +898,7 @@ nouveau_gpuobj_channel_init_pramin(struct nouveau_channel *chan)
base = 0;
/* PGRAPH context */
+ size += dev_priv->engine.graph.grctx_size;
if (dev_priv->card_type == NV_50) {
/* Various fixed table thingos */
@@ -930,12 +909,8 @@ nouveau_gpuobj_channel_init_pramin(struct nouveau_channel *chan)
size += 0x8000;
/* RAMFC */
size += 0x1000;
- /* PGRAPH context */
- size += 0x70000;
}
- NV_DEBUG(dev, "ch%d PRAMIN size: 0x%08x bytes, base alloc=0x%08x\n",
- chan->id, size, base);
ret = nouveau_gpuobj_new_ref(dev, NULL, NULL, 0, size, 0x1000, 0,
&chan->ramin);
if (ret) {
@@ -944,8 +919,7 @@ nouveau_gpuobj_channel_init_pramin(struct nouveau_channel *chan)
}
pramin = chan->ramin->gpuobj;
- ret = nouveau_mem_init_heap(&chan->ramin_heap,
- pramin->im_pramin->start + base, size);
+ ret = drm_mm_init(&chan->ramin_heap, pramin->im_pramin->start + base, size);
if (ret) {
NV_ERROR(dev, "Error creating PRAMIN heap: %d\n", ret);
nouveau_gpuobj_ref_del(dev, &chan->ramin);
@@ -969,15 +943,11 @@ nouveau_gpuobj_channel_init(struct nouveau_channel *chan,
NV_DEBUG(dev, "ch%d vram=0x%08x tt=0x%08x\n", chan->id, vram_h, tt_h);
- /* Reserve a block of PRAMIN for the channel
- *XXX: maybe on <NV50 too at some point
- */
- if (0 || dev_priv->card_type == NV_50) {
- ret = nouveau_gpuobj_channel_init_pramin(chan);
- if (ret) {
- NV_ERROR(dev, "init pramin\n");
- return ret;
- }
+ /* Allocate a chunk of memory for per-channel object storage */
+ ret = nouveau_gpuobj_channel_init_pramin(chan);
+ if (ret) {
+ NV_ERROR(dev, "init pramin\n");
+ return ret;
}
/* NV50 VM
@@ -988,17 +958,13 @@ nouveau_gpuobj_channel_init(struct nouveau_channel *chan,
if (dev_priv->card_type >= NV_50) {
uint32_t vm_offset, pde;
- instmem->prepare_access(dev, true);
-
vm_offset = (dev_priv->chipset & 0xf0) == 0x50 ? 0x1400 : 0x200;
vm_offset += chan->ramin->gpuobj->im_pramin->start;
ret = nouveau_gpuobj_new_fake(dev, vm_offset, ~0, 0x4000,
0, &chan->vm_pd, NULL);
- if (ret) {
- instmem->finish_access(dev);
+ if (ret)
return ret;
- }
for (i = 0; i < 0x4000; i += 8) {
nv_wo32(dev, chan->vm_pd, (i+0)/4, 0x00000000);
nv_wo32(dev, chan->vm_pd, (i+4)/4, 0xdeadcafe);
@@ -1008,10 +974,8 @@ nouveau_gpuobj_channel_init(struct nouveau_channel *chan,
ret = nouveau_gpuobj_ref_add(dev, NULL, 0,
dev_priv->gart_info.sg_ctxdma,
&chan->vm_gart_pt);
- if (ret) {
- instmem->finish_access(dev);
+ if (ret)
return ret;
- }
nv_wo32(dev, chan->vm_pd, pde++,
chan->vm_gart_pt->instance | 0x03);
nv_wo32(dev, chan->vm_pd, pde++, 0x00000000);
@@ -1021,17 +985,15 @@ nouveau_gpuobj_channel_init(struct nouveau_channel *chan,
ret = nouveau_gpuobj_ref_add(dev, NULL, 0,
dev_priv->vm_vram_pt[i],
&chan->vm_vram_pt[i]);
- if (ret) {
- instmem->finish_access(dev);
+ if (ret)
return ret;
- }
nv_wo32(dev, chan->vm_pd, pde++,
chan->vm_vram_pt[i]->instance | 0x61);
nv_wo32(dev, chan->vm_pd, pde++, 0x00000000);
}
- instmem->finish_access(dev);
+ instmem->flush(dev);
}
/* RAMHT */
@@ -1130,8 +1092,8 @@ nouveau_gpuobj_channel_takedown(struct nouveau_channel *chan)
for (i = 0; i < dev_priv->vm_vram_pt_nr; i++)
nouveau_gpuobj_ref_del(dev, &chan->vm_vram_pt[i]);
- if (chan->ramin_heap)
- nouveau_mem_takedown(&chan->ramin_heap);
+ if (chan->ramin_heap.free_stack.next)
+ drm_mm_takedown(&chan->ramin_heap);
if (chan->ramin)
nouveau_gpuobj_ref_del(dev, &chan->ramin);
@@ -1164,10 +1126,8 @@ nouveau_gpuobj_suspend(struct drm_device *dev)
return -ENOMEM;
}
- dev_priv->engine.instmem.prepare_access(dev, false);
for (i = 0; i < gpuobj->im_pramin->size / 4; i++)
gpuobj->im_backing_suspend[i] = nv_ro32(dev, gpuobj, i);
- dev_priv->engine.instmem.finish_access(dev);
}
return 0;
@@ -1212,10 +1172,9 @@ nouveau_gpuobj_resume(struct drm_device *dev)
if (!gpuobj->im_backing_suspend)
continue;
- dev_priv->engine.instmem.prepare_access(dev, true);
for (i = 0; i < gpuobj->im_pramin->size / 4; i++)
nv_wo32(dev, gpuobj, i, gpuobj->im_backing_suspend[i]);
- dev_priv->engine.instmem.finish_access(dev);
+ dev_priv->engine.instmem.flush(dev);
}
nouveau_gpuobj_suspend_cleanup(dev);
@@ -1232,7 +1191,6 @@ int nouveau_ioctl_grobj_alloc(struct drm_device *dev, void *data,
struct nouveau_channel *chan;
int ret;
- NOUVEAU_CHECK_INITIALISED_WITH_RETURN;
NOUVEAU_GET_USER_CHANNEL_WITH_RETURN(init->channel, file_priv, chan);
if (init->handle == ~0)
@@ -1283,7 +1241,6 @@ int nouveau_ioctl_gpuobj_free(struct drm_device *dev, void *data,
struct nouveau_channel *chan;
int ret;
- NOUVEAU_CHECK_INITIALISED_WITH_RETURN;
NOUVEAU_GET_USER_CHANNEL_WITH_RETURN(objfree->channel, file_priv, chan);
ret = nouveau_gpuobj_ref_find(chan, objfree->handle, &ref);
diff --git a/drivers/gpu/drm/nouveau/nouveau_reg.h b/drivers/gpu/drm/nouveau/nouveau_reg.h
index 6ca80a3fe70..9c1056cb8a9 100644
--- a/drivers/gpu/drm/nouveau/nouveau_reg.h
+++ b/drivers/gpu/drm/nouveau/nouveau_reg.h
@@ -1,19 +1,64 @@
+#define NV04_PFB_BOOT_0 0x00100000
+# define NV04_PFB_BOOT_0_RAM_AMOUNT 0x00000003
+# define NV04_PFB_BOOT_0_RAM_AMOUNT_32MB 0x00000000
+# define NV04_PFB_BOOT_0_RAM_AMOUNT_4MB 0x00000001
+# define NV04_PFB_BOOT_0_RAM_AMOUNT_8MB 0x00000002
+# define NV04_PFB_BOOT_0_RAM_AMOUNT_16MB 0x00000003
+# define NV04_PFB_BOOT_0_RAM_WIDTH_128 0x00000004
+# define NV04_PFB_BOOT_0_RAM_TYPE 0x00000028
+# define NV04_PFB_BOOT_0_RAM_TYPE_SGRAM_8MBIT 0x00000000
+# define NV04_PFB_BOOT_0_RAM_TYPE_SGRAM_16MBIT 0x00000008
+# define NV04_PFB_BOOT_0_RAM_TYPE_SGRAM_16MBIT_4BANK 0x00000010
+# define NV04_PFB_BOOT_0_RAM_TYPE_SDRAM_16MBIT 0x00000018
+# define NV04_PFB_BOOT_0_RAM_TYPE_SDRAM_64MBIT 0x00000020
+# define NV04_PFB_BOOT_0_RAM_TYPE_SDRAM_64MBITX16 0x00000028
+# define NV04_PFB_BOOT_0_UMA_ENABLE 0x00000100
+# define NV04_PFB_BOOT_0_UMA_SIZE 0x0000f000
+#define NV04_PFB_DEBUG_0 0x00100080
+# define NV04_PFB_DEBUG_0_PAGE_MODE 0x00000001
+# define NV04_PFB_DEBUG_0_REFRESH_OFF 0x00000010
+# define NV04_PFB_DEBUG_0_REFRESH_COUNTX64 0x00003f00
+# define NV04_PFB_DEBUG_0_REFRESH_SLOW_CLK 0x00004000
+# define NV04_PFB_DEBUG_0_SAFE_MODE 0x00008000
+# define NV04_PFB_DEBUG_0_ALOM_ENABLE 0x00010000
+# define NV04_PFB_DEBUG_0_CASOE 0x00100000
+# define NV04_PFB_DEBUG_0_CKE_INVERT 0x10000000
+# define NV04_PFB_DEBUG_0_REFINC 0x20000000
+# define NV04_PFB_DEBUG_0_SAVE_POWER_OFF 0x40000000
+#define NV04_PFB_CFG0 0x00100200
+# define NV04_PFB_CFG0_SCRAMBLE 0x20000000
+#define NV04_PFB_CFG1 0x00100204
+#define NV04_PFB_FIFO_DATA 0x0010020c
+# define NV10_PFB_FIFO_DATA_RAM_AMOUNT_MB_MASK 0xfff00000
+# define NV10_PFB_FIFO_DATA_RAM_AMOUNT_MB_SHIFT 20
+#define NV10_PFB_REFCTRL 0x00100210
+# define NV10_PFB_REFCTRL_VALID_1 (1 << 31)
+#define NV04_PFB_PAD 0x0010021c
+# define NV04_PFB_PAD_CKE_NORMAL (1 << 0)
+#define NV10_PFB_TILE(i) (0x00100240 + (i*16))
+#define NV10_PFB_TILE__SIZE 8
+#define NV10_PFB_TLIMIT(i) (0x00100244 + (i*16))
+#define NV10_PFB_TSIZE(i) (0x00100248 + (i*16))
+#define NV10_PFB_TSTATUS(i) (0x0010024c + (i*16))
+#define NV04_PFB_REF 0x001002d0
+# define NV04_PFB_REF_CMD_REFRESH (1 << 0)
+#define NV04_PFB_PRE 0x001002d4
+# define NV04_PFB_PRE_CMD_PRECHARGE (1 << 0)
+#define NV10_PFB_CLOSE_PAGE2 0x0010033c
+#define NV04_PFB_SCRAMBLE(i) (0x00100400 + 4 * (i))
+#define NV40_PFB_TILE(i) (0x00100600 + (i*16))
+#define NV40_PFB_TILE__SIZE_0 12
+#define NV40_PFB_TILE__SIZE_1 15
+#define NV40_PFB_TLIMIT(i) (0x00100604 + (i*16))
+#define NV40_PFB_TSIZE(i) (0x00100608 + (i*16))
+#define NV40_PFB_TSTATUS(i) (0x0010060c + (i*16))
+#define NV40_PFB_UNK_800 0x00100800
-#define NV03_BOOT_0 0x00100000
-# define NV03_BOOT_0_RAM_AMOUNT 0x00000003
-# define NV03_BOOT_0_RAM_AMOUNT_8MB 0x00000000
-# define NV03_BOOT_0_RAM_AMOUNT_2MB 0x00000001
-# define NV03_BOOT_0_RAM_AMOUNT_4MB 0x00000002
-# define NV03_BOOT_0_RAM_AMOUNT_8MB_SDRAM 0x00000003
-# define NV04_BOOT_0_RAM_AMOUNT_32MB 0x00000000
-# define NV04_BOOT_0_RAM_AMOUNT_4MB 0x00000001
-# define NV04_BOOT_0_RAM_AMOUNT_8MB 0x00000002
-# define NV04_BOOT_0_RAM_AMOUNT_16MB 0x00000003
-
-#define NV04_FIFO_DATA 0x0010020c
-# define NV10_FIFO_DATA_RAM_AMOUNT_MB_MASK 0xfff00000
-# define NV10_FIFO_DATA_RAM_AMOUNT_MB_SHIFT 20
+#define NV_PEXTDEV_BOOT_0 0x00101000
+#define NV_PEXTDEV_BOOT_0_RAMCFG 0x0000003c
+# define NV_PEXTDEV_BOOT_0_STRAP_FP_IFACE_12BIT (8 << 12)
+#define NV_PEXTDEV_BOOT_3 0x0010100c
#define NV_RAMIN 0x00700000
@@ -131,23 +176,6 @@
#define NV04_PTIMER_TIME_1 0x00009410
#define NV04_PTIMER_ALARM_0 0x00009420
-#define NV04_PFB_CFG0 0x00100200
-#define NV04_PFB_CFG1 0x00100204
-#define NV40_PFB_020C 0x0010020C
-#define NV10_PFB_TILE(i) (0x00100240 + (i*16))
-#define NV10_PFB_TILE__SIZE 8
-#define NV10_PFB_TLIMIT(i) (0x00100244 + (i*16))
-#define NV10_PFB_TSIZE(i) (0x00100248 + (i*16))
-#define NV10_PFB_TSTATUS(i) (0x0010024C + (i*16))
-#define NV10_PFB_CLOSE_PAGE2 0x0010033C
-#define NV40_PFB_TILE(i) (0x00100600 + (i*16))
-#define NV40_PFB_TILE__SIZE_0 12
-#define NV40_PFB_TILE__SIZE_1 15
-#define NV40_PFB_TLIMIT(i) (0x00100604 + (i*16))
-#define NV40_PFB_TSIZE(i) (0x00100608 + (i*16))
-#define NV40_PFB_TSTATUS(i) (0x0010060C + (i*16))
-#define NV40_PFB_UNK_800 0x00100800
-
#define NV04_PGRAPH_DEBUG_0 0x00400080
#define NV04_PGRAPH_DEBUG_1 0x00400084
#define NV04_PGRAPH_DEBUG_2 0x00400088
@@ -814,6 +842,7 @@
#define NV50_PDISPLAY_SOR_BACKLIGHT_ENABLE 0x80000000
#define NV50_PDISPLAY_SOR_BACKLIGHT_LEVEL 0x00000fff
#define NV50_SOR_DP_CTRL(i,l) (0x0061c10c + (i) * 0x800 + (l) * 0x80)
+#define NV50_SOR_DP_CTRL_ENABLED 0x00000001
#define NV50_SOR_DP_CTRL_ENHANCED_FRAME_ENABLED 0x00004000
#define NV50_SOR_DP_CTRL_LANE_MASK 0x001f0000
#define NV50_SOR_DP_CTRL_LANE_0_ENABLED 0x00010000
diff --git a/drivers/gpu/drm/nouveau/nouveau_sgdma.c b/drivers/gpu/drm/nouveau/nouveau_sgdma.c
index 1d6ee8b5515..491767fe4fc 100644
--- a/drivers/gpu/drm/nouveau/nouveau_sgdma.c
+++ b/drivers/gpu/drm/nouveau/nouveau_sgdma.c
@@ -97,7 +97,6 @@ nouveau_sgdma_bind(struct ttm_backend *be, struct ttm_mem_reg *mem)
NV_DEBUG(dev, "pg=0x%lx\n", mem->mm_node->start);
- dev_priv->engine.instmem.prepare_access(nvbe->dev, true);
pte = nouveau_sgdma_pte(nvbe->dev, mem->mm_node->start << PAGE_SHIFT);
nvbe->pte_start = pte;
for (i = 0; i < nvbe->nr_pages; i++) {
@@ -116,24 +115,11 @@ nouveau_sgdma_bind(struct ttm_backend *be, struct ttm_mem_reg *mem)
dma_offset += NV_CTXDMA_PAGE_SIZE;
}
}
- dev_priv->engine.instmem.finish_access(nvbe->dev);
+ dev_priv->engine.instmem.flush(nvbe->dev);
if (dev_priv->card_type == NV_50) {
- nv_wr32(dev, 0x100c80, 0x00050001);
- if (!nv_wait(0x100c80, 0x00000001, 0x00000000)) {
- NV_ERROR(dev, "timeout: (0x100c80 & 1) == 0 (2)\n");
- NV_ERROR(dev, "0x100c80 = 0x%08x\n",
- nv_rd32(dev, 0x100c80));
- return -EBUSY;
- }
-
- nv_wr32(dev, 0x100c80, 0x00000001);
- if (!nv_wait(0x100c80, 0x00000001, 0x00000000)) {
- NV_ERROR(dev, "timeout: (0x100c80 & 1) == 0 (2)\n");
- NV_ERROR(dev, "0x100c80 = 0x%08x\n",
- nv_rd32(dev, 0x100c80));
- return -EBUSY;
- }
+ nv50_vm_flush(dev, 5); /* PGRAPH */
+ nv50_vm_flush(dev, 0); /* PFIFO */
}
nvbe->bound = true;
@@ -154,7 +140,6 @@ nouveau_sgdma_unbind(struct ttm_backend *be)
if (!nvbe->bound)
return 0;
- dev_priv->engine.instmem.prepare_access(nvbe->dev, true);
pte = nvbe->pte_start;
for (i = 0; i < nvbe->nr_pages; i++) {
dma_addr_t dma_offset = dev_priv->gart_info.sg_dummy_bus;
@@ -170,24 +155,11 @@ nouveau_sgdma_unbind(struct ttm_backend *be)
dma_offset += NV_CTXDMA_PAGE_SIZE;
}
}
- dev_priv->engine.instmem.finish_access(nvbe->dev);
+ dev_priv->engine.instmem.flush(nvbe->dev);
if (dev_priv->card_type == NV_50) {
- nv_wr32(dev, 0x100c80, 0x00050001);
- if (!nv_wait(0x100c80, 0x00000001, 0x00000000)) {
- NV_ERROR(dev, "timeout: (0x100c80 & 1) == 0 (2)\n");
- NV_ERROR(dev, "0x100c80 = 0x%08x\n",
- nv_rd32(dev, 0x100c80));
- return -EBUSY;
- }
-
- nv_wr32(dev, 0x100c80, 0x00000001);
- if (!nv_wait(0x100c80, 0x00000001, 0x00000000)) {
- NV_ERROR(dev, "timeout: (0x100c80 & 1) == 0 (2)\n");
- NV_ERROR(dev, "0x100c80 = 0x%08x\n",
- nv_rd32(dev, 0x100c80));
- return -EBUSY;
- }
+ nv50_vm_flush(dev, 5);
+ nv50_vm_flush(dev, 0);
}
nvbe->bound = false;
@@ -272,7 +244,6 @@ nouveau_sgdma_init(struct drm_device *dev)
pci_map_page(dev->pdev, dev_priv->gart_info.sg_dummy_page, 0,
PAGE_SIZE, PCI_DMA_BIDIRECTIONAL);
- dev_priv->engine.instmem.prepare_access(dev, true);
if (dev_priv->card_type < NV_50) {
/* Maybe use NV_DMA_TARGET_AGP for PCIE? NVIDIA do this, and
* confirmed to work on c51. Perhaps means NV_DMA_TARGET_PCIE
@@ -294,7 +265,7 @@ nouveau_sgdma_init(struct drm_device *dev)
nv_wo32(dev, gpuobj, (i+4)/4, 0);
}
}
- dev_priv->engine.instmem.finish_access(dev);
+ dev_priv->engine.instmem.flush(dev);
dev_priv->gart_info.type = NOUVEAU_GART_SGDMA;
dev_priv->gart_info.aper_base = 0;
@@ -325,14 +296,11 @@ nouveau_sgdma_get_page(struct drm_device *dev, uint32_t offset, uint32_t *page)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_gpuobj *gpuobj = dev_priv->gart_info.sg_ctxdma;
- struct nouveau_instmem_engine *instmem = &dev_priv->engine.instmem;
int pte;
pte = (offset >> NV_CTXDMA_PAGE_SHIFT);
if (dev_priv->card_type < NV_50) {
- instmem->prepare_access(dev, false);
*page = nv_ro32(dev, gpuobj, (pte + 2)) & ~NV_CTXDMA_PAGE_MASK;
- instmem->finish_access(dev);
return 0;
}
diff --git a/drivers/gpu/drm/nouveau/nouveau_state.c b/drivers/gpu/drm/nouveau/nouveau_state.c
index b02a231d693..ee3729e7823 100644
--- a/drivers/gpu/drm/nouveau/nouveau_state.c
+++ b/drivers/gpu/drm/nouveau/nouveau_state.c
@@ -38,6 +38,7 @@
#include "nv50_display.h"
static void nouveau_stub_takedown(struct drm_device *dev) {}
+static int nouveau_stub_init(struct drm_device *dev) { return 0; }
static int nouveau_init_engine_ptrs(struct drm_device *dev)
{
@@ -54,8 +55,7 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
engine->instmem.clear = nv04_instmem_clear;
engine->instmem.bind = nv04_instmem_bind;
engine->instmem.unbind = nv04_instmem_unbind;
- engine->instmem.prepare_access = nv04_instmem_prepare_access;
- engine->instmem.finish_access = nv04_instmem_finish_access;
+ engine->instmem.flush = nv04_instmem_flush;
engine->mc.init = nv04_mc_init;
engine->mc.takedown = nv04_mc_takedown;
engine->timer.init = nv04_timer_init;
@@ -85,6 +85,16 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
engine->fifo.destroy_context = nv04_fifo_destroy_context;
engine->fifo.load_context = nv04_fifo_load_context;
engine->fifo.unload_context = nv04_fifo_unload_context;
+ engine->display.early_init = nv04_display_early_init;
+ engine->display.late_takedown = nv04_display_late_takedown;
+ engine->display.create = nv04_display_create;
+ engine->display.init = nv04_display_init;
+ engine->display.destroy = nv04_display_destroy;
+ engine->gpio.init = nouveau_stub_init;
+ engine->gpio.takedown = nouveau_stub_takedown;
+ engine->gpio.get = NULL;
+ engine->gpio.set = NULL;
+ engine->gpio.irq_enable = NULL;
break;
case 0x10:
engine->instmem.init = nv04_instmem_init;
@@ -95,8 +105,7 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
engine->instmem.clear = nv04_instmem_clear;
engine->instmem.bind = nv04_instmem_bind;
engine->instmem.unbind = nv04_instmem_unbind;
- engine->instmem.prepare_access = nv04_instmem_prepare_access;
- engine->instmem.finish_access = nv04_instmem_finish_access;
+ engine->instmem.flush = nv04_instmem_flush;
engine->mc.init = nv04_mc_init;
engine->mc.takedown = nv04_mc_takedown;
engine->timer.init = nv04_timer_init;
@@ -128,6 +137,16 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
engine->fifo.destroy_context = nv10_fifo_destroy_context;
engine->fifo.load_context = nv10_fifo_load_context;
engine->fifo.unload_context = nv10_fifo_unload_context;
+ engine->display.early_init = nv04_display_early_init;
+ engine->display.late_takedown = nv04_display_late_takedown;
+ engine->display.create = nv04_display_create;
+ engine->display.init = nv04_display_init;
+ engine->display.destroy = nv04_display_destroy;
+ engine->gpio.init = nouveau_stub_init;
+ engine->gpio.takedown = nouveau_stub_takedown;
+ engine->gpio.get = nv10_gpio_get;
+ engine->gpio.set = nv10_gpio_set;
+ engine->gpio.irq_enable = NULL;
break;
case 0x20:
engine->instmem.init = nv04_instmem_init;
@@ -138,8 +157,7 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
engine->instmem.clear = nv04_instmem_clear;
engine->instmem.bind = nv04_instmem_bind;
engine->instmem.unbind = nv04_instmem_unbind;
- engine->instmem.prepare_access = nv04_instmem_prepare_access;
- engine->instmem.finish_access = nv04_instmem_finish_access;
+ engine->instmem.flush = nv04_instmem_flush;
engine->mc.init = nv04_mc_init;
engine->mc.takedown = nv04_mc_takedown;
engine->timer.init = nv04_timer_init;
@@ -171,6 +189,16 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
engine->fifo.destroy_context = nv10_fifo_destroy_context;
engine->fifo.load_context = nv10_fifo_load_context;
engine->fifo.unload_context = nv10_fifo_unload_context;
+ engine->display.early_init = nv04_display_early_init;
+ engine->display.late_takedown = nv04_display_late_takedown;
+ engine->display.create = nv04_display_create;
+ engine->display.init = nv04_display_init;
+ engine->display.destroy = nv04_display_destroy;
+ engine->gpio.init = nouveau_stub_init;
+ engine->gpio.takedown = nouveau_stub_takedown;
+ engine->gpio.get = nv10_gpio_get;
+ engine->gpio.set = nv10_gpio_set;
+ engine->gpio.irq_enable = NULL;
break;
case 0x30:
engine->instmem.init = nv04_instmem_init;
@@ -181,15 +209,14 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
engine->instmem.clear = nv04_instmem_clear;
engine->instmem.bind = nv04_instmem_bind;
engine->instmem.unbind = nv04_instmem_unbind;
- engine->instmem.prepare_access = nv04_instmem_prepare_access;
- engine->instmem.finish_access = nv04_instmem_finish_access;
+ engine->instmem.flush = nv04_instmem_flush;
engine->mc.init = nv04_mc_init;
engine->mc.takedown = nv04_mc_takedown;
engine->timer.init = nv04_timer_init;
engine->timer.read = nv04_timer_read;
engine->timer.takedown = nv04_timer_takedown;
- engine->fb.init = nv10_fb_init;
- engine->fb.takedown = nv10_fb_takedown;
+ engine->fb.init = nv30_fb_init;
+ engine->fb.takedown = nv30_fb_takedown;
engine->fb.set_region_tiling = nv10_fb_set_region_tiling;
engine->graph.grclass = nv30_graph_grclass;
engine->graph.init = nv30_graph_init;
@@ -214,6 +241,16 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
engine->fifo.destroy_context = nv10_fifo_destroy_context;
engine->fifo.load_context = nv10_fifo_load_context;
engine->fifo.unload_context = nv10_fifo_unload_context;
+ engine->display.early_init = nv04_display_early_init;
+ engine->display.late_takedown = nv04_display_late_takedown;
+ engine->display.create = nv04_display_create;
+ engine->display.init = nv04_display_init;
+ engine->display.destroy = nv04_display_destroy;
+ engine->gpio.init = nouveau_stub_init;
+ engine->gpio.takedown = nouveau_stub_takedown;
+ engine->gpio.get = nv10_gpio_get;
+ engine->gpio.set = nv10_gpio_set;
+ engine->gpio.irq_enable = NULL;
break;
case 0x40:
case 0x60:
@@ -225,8 +262,7 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
engine->instmem.clear = nv04_instmem_clear;
engine->instmem.bind = nv04_instmem_bind;
engine->instmem.unbind = nv04_instmem_unbind;
- engine->instmem.prepare_access = nv04_instmem_prepare_access;
- engine->instmem.finish_access = nv04_instmem_finish_access;
+ engine->instmem.flush = nv04_instmem_flush;
engine->mc.init = nv40_mc_init;
engine->mc.takedown = nv40_mc_takedown;
engine->timer.init = nv04_timer_init;
@@ -258,6 +294,16 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
engine->fifo.destroy_context = nv40_fifo_destroy_context;
engine->fifo.load_context = nv40_fifo_load_context;
engine->fifo.unload_context = nv40_fifo_unload_context;
+ engine->display.early_init = nv04_display_early_init;
+ engine->display.late_takedown = nv04_display_late_takedown;
+ engine->display.create = nv04_display_create;
+ engine->display.init = nv04_display_init;
+ engine->display.destroy = nv04_display_destroy;
+ engine->gpio.init = nouveau_stub_init;
+ engine->gpio.takedown = nouveau_stub_takedown;
+ engine->gpio.get = nv10_gpio_get;
+ engine->gpio.set = nv10_gpio_set;
+ engine->gpio.irq_enable = NULL;
break;
case 0x50:
case 0x80: /* gotta love NVIDIA's consistency.. */
@@ -271,8 +317,10 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
engine->instmem.clear = nv50_instmem_clear;
engine->instmem.bind = nv50_instmem_bind;
engine->instmem.unbind = nv50_instmem_unbind;
- engine->instmem.prepare_access = nv50_instmem_prepare_access;
- engine->instmem.finish_access = nv50_instmem_finish_access;
+ if (dev_priv->chipset == 0x50)
+ engine->instmem.flush = nv50_instmem_flush;
+ else
+ engine->instmem.flush = nv84_instmem_flush;
engine->mc.init = nv50_mc_init;
engine->mc.takedown = nv50_mc_takedown;
engine->timer.init = nv04_timer_init;
@@ -300,6 +348,16 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
engine->fifo.destroy_context = nv50_fifo_destroy_context;
engine->fifo.load_context = nv50_fifo_load_context;
engine->fifo.unload_context = nv50_fifo_unload_context;
+ engine->display.early_init = nv50_display_early_init;
+ engine->display.late_takedown = nv50_display_late_takedown;
+ engine->display.create = nv50_display_create;
+ engine->display.init = nv50_display_init;
+ engine->display.destroy = nv50_display_destroy;
+ engine->gpio.init = nv50_gpio_init;
+ engine->gpio.takedown = nouveau_stub_takedown;
+ engine->gpio.get = nv50_gpio_get;
+ engine->gpio.set = nv50_gpio_set;
+ engine->gpio.irq_enable = nv50_gpio_irq_enable;
break;
default:
NV_ERROR(dev, "NV%02x unsupported\n", dev_priv->chipset);
@@ -407,11 +465,6 @@ nouveau_card_init(struct drm_device *dev)
struct nouveau_engine *engine;
int ret;
- NV_DEBUG(dev, "prev state = %d\n", dev_priv->init_state);
-
- if (dev_priv->init_state == NOUVEAU_CARD_INIT_DONE)
- return 0;
-
vga_client_register(dev->pdev, dev, NULL, nouveau_vga_set_decode);
vga_switcheroo_register_client(dev->pdev, nouveau_switcheroo_set_state,
nouveau_switcheroo_can_switch);
@@ -421,15 +474,17 @@ nouveau_card_init(struct drm_device *dev)
if (ret)
goto out;
engine = &dev_priv->engine;
- dev_priv->init_state = NOUVEAU_CARD_INIT_FAILED;
spin_lock_init(&dev_priv->context_switch_lock);
+ /* Make the CRTCs and I2C buses accessible */
+ ret = engine->display.early_init(dev);
+ if (ret)
+ goto out;
+
/* Parse BIOS tables / Run init tables if card not POSTed */
- if (drm_core_check_feature(dev, DRIVER_MODESET)) {
- ret = nouveau_bios_init(dev);
- if (ret)
- goto out;
- }
+ ret = nouveau_bios_init(dev);
+ if (ret)
+ goto out_display_early;
ret = nouveau_mem_detect(dev);
if (ret)
@@ -461,10 +516,15 @@ nouveau_card_init(struct drm_device *dev)
if (ret)
goto out_gpuobj;
+ /* PGPIO */
+ ret = engine->gpio.init(dev);
+ if (ret)
+ goto out_mc;
+
/* PTIMER */
ret = engine->timer.init(dev);
if (ret)
- goto out_mc;
+ goto out_gpio;
/* PFB */
ret = engine->fb.init(dev);
@@ -485,12 +545,16 @@ nouveau_card_init(struct drm_device *dev)
goto out_graph;
}
+ ret = engine->display.create(dev);
+ if (ret)
+ goto out_fifo;
+
/* this call irq_preinstall, register irq handler and
* call irq_postinstall
*/
ret = drm_irq_install(dev);
if (ret)
- goto out_fifo;
+ goto out_display;
ret = drm_vblank_init(dev, 0);
if (ret)
@@ -504,35 +568,18 @@ nouveau_card_init(struct drm_device *dev)
goto out_irq;
}
- if (drm_core_check_feature(dev, DRIVER_MODESET)) {
- if (dev_priv->card_type >= NV_50)
- ret = nv50_display_create(dev);
- else
- ret = nv04_display_create(dev);
- if (ret)
- goto out_channel;
- }
-
ret = nouveau_backlight_init(dev);
if (ret)
NV_ERROR(dev, "Error %d registering backlight\n", ret);
- dev_priv->init_state = NOUVEAU_CARD_INIT_DONE;
-
- if (drm_core_check_feature(dev, DRIVER_MODESET)) {
- nouveau_fbcon_init(dev);
- drm_kms_helper_poll_init(dev);
- }
-
+ nouveau_fbcon_init(dev);
+ drm_kms_helper_poll_init(dev);
return 0;
-out_channel:
- if (dev_priv->channel) {
- nouveau_channel_free(dev_priv->channel);
- dev_priv->channel = NULL;
- }
out_irq:
drm_irq_uninstall(dev);
+out_display:
+ engine->display.destroy(dev);
out_fifo:
if (!nouveau_noaccel)
engine->fifo.takedown(dev);
@@ -543,6 +590,8 @@ out_fb:
engine->fb.takedown(dev);
out_timer:
engine->timer.takedown(dev);
+out_gpio:
+ engine->gpio.takedown(dev);
out_mc:
engine->mc.takedown(dev);
out_gpuobj:
@@ -556,6 +605,8 @@ out_gpuobj_early:
nouveau_gpuobj_late_takedown(dev);
out_bios:
nouveau_bios_takedown(dev);
+out_display_early:
+ engine->display.late_takedown(dev);
out:
vga_client_register(dev->pdev, NULL, NULL, NULL);
return ret;
@@ -566,45 +617,39 @@ static void nouveau_card_takedown(struct drm_device *dev)
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_engine *engine = &dev_priv->engine;
- NV_DEBUG(dev, "prev state = %d\n", dev_priv->init_state);
-
- if (dev_priv->init_state != NOUVEAU_CARD_INIT_DOWN) {
-
- nouveau_backlight_exit(dev);
-
- if (dev_priv->channel) {
- nouveau_channel_free(dev_priv->channel);
- dev_priv->channel = NULL;
- }
+ nouveau_backlight_exit(dev);
- if (!nouveau_noaccel) {
- engine->fifo.takedown(dev);
- engine->graph.takedown(dev);
- }
- engine->fb.takedown(dev);
- engine->timer.takedown(dev);
- engine->mc.takedown(dev);
+ if (dev_priv->channel) {
+ nouveau_channel_free(dev_priv->channel);
+ dev_priv->channel = NULL;
+ }
- mutex_lock(&dev->struct_mutex);
- ttm_bo_clean_mm(&dev_priv->ttm.bdev, TTM_PL_VRAM);
- ttm_bo_clean_mm(&dev_priv->ttm.bdev, TTM_PL_TT);
- mutex_unlock(&dev->struct_mutex);
- nouveau_sgdma_takedown(dev);
+ if (!nouveau_noaccel) {
+ engine->fifo.takedown(dev);
+ engine->graph.takedown(dev);
+ }
+ engine->fb.takedown(dev);
+ engine->timer.takedown(dev);
+ engine->gpio.takedown(dev);
+ engine->mc.takedown(dev);
+ engine->display.late_takedown(dev);
- nouveau_gpuobj_takedown(dev);
- nouveau_mem_close(dev);
- engine->instmem.takedown(dev);
+ mutex_lock(&dev->struct_mutex);
+ ttm_bo_clean_mm(&dev_priv->ttm.bdev, TTM_PL_VRAM);
+ ttm_bo_clean_mm(&dev_priv->ttm.bdev, TTM_PL_TT);
+ mutex_unlock(&dev->struct_mutex);
+ nouveau_sgdma_takedown(dev);
- if (drm_core_check_feature(dev, DRIVER_MODESET))
- drm_irq_uninstall(dev);
+ nouveau_gpuobj_takedown(dev);
+ nouveau_mem_close(dev);
+ engine->instmem.takedown(dev);
- nouveau_gpuobj_late_takedown(dev);
- nouveau_bios_takedown(dev);
+ drm_irq_uninstall(dev);
- vga_client_register(dev->pdev, NULL, NULL, NULL);
+ nouveau_gpuobj_late_takedown(dev);
+ nouveau_bios_takedown(dev);
- dev_priv->init_state = NOUVEAU_CARD_INIT_DOWN;
- }
+ vga_client_register(dev->pdev, NULL, NULL, NULL);
}
/* here a client dies, release the stuff that was allocated for its
@@ -691,6 +736,7 @@ int nouveau_load(struct drm_device *dev, unsigned long flags)
struct drm_nouveau_private *dev_priv;
uint32_t reg0;
resource_size_t mmio_start_offs;
+ int ret;
dev_priv = kzalloc(sizeof(*dev_priv), GFP_KERNEL);
if (!dev_priv)
@@ -699,7 +745,6 @@ int nouveau_load(struct drm_device *dev, unsigned long flags)
dev_priv->dev = dev;
dev_priv->flags = flags & NOUVEAU_FLAGS;
- dev_priv->init_state = NOUVEAU_CARD_INIT_DOWN;
NV_DEBUG(dev, "vendor: 0x%X device: 0x%X class: 0x%X\n",
dev->pci_vendor, dev->pci_device, dev->pdev->class);
@@ -773,11 +818,9 @@ int nouveau_load(struct drm_device *dev, unsigned long flags)
NV_INFO(dev, "Detected an NV%2x generation card (0x%08x)\n",
dev_priv->card_type, reg0);
- if (drm_core_check_feature(dev, DRIVER_MODESET)) {
- int ret = nouveau_remove_conflicting_drivers(dev);
- if (ret)
- return ret;
- }
+ ret = nouveau_remove_conflicting_drivers(dev);
+ if (ret)
+ return ret;
/* Map PRAMIN BAR, or on older cards, the aperture withing BAR0 */
if (dev_priv->card_type >= NV_40) {
@@ -812,46 +855,26 @@ int nouveau_load(struct drm_device *dev, unsigned long flags)
dev_priv->flags |= NV_NFORCE2;
/* For kernel modesetting, init card now and bring up fbcon */
- if (drm_core_check_feature(dev, DRIVER_MODESET)) {
- int ret = nouveau_card_init(dev);
- if (ret)
- return ret;
- }
+ ret = nouveau_card_init(dev);
+ if (ret)
+ return ret;
return 0;
}
-static void nouveau_close(struct drm_device *dev)
-{
- struct drm_nouveau_private *dev_priv = dev->dev_private;
-
- /* In the case of an error dev_priv may not be allocated yet */
- if (dev_priv)
- nouveau_card_takedown(dev);
-}
-
-/* KMS: we need mmio at load time, not when the first drm client opens. */
void nouveau_lastclose(struct drm_device *dev)
{
- if (drm_core_check_feature(dev, DRIVER_MODESET))
- return;
-
- nouveau_close(dev);
}
int nouveau_unload(struct drm_device *dev)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nouveau_engine *engine = &dev_priv->engine;
- if (drm_core_check_feature(dev, DRIVER_MODESET)) {
- drm_kms_helper_poll_fini(dev);
- nouveau_fbcon_fini(dev);
- if (dev_priv->card_type >= NV_50)
- nv50_display_destroy(dev);
- else
- nv04_display_destroy(dev);
- nouveau_close(dev);
- }
+ drm_kms_helper_poll_fini(dev);
+ nouveau_fbcon_fini(dev);
+ engine->display.destroy(dev);
+ nouveau_card_takedown(dev);
iounmap(dev_priv->mmio);
iounmap(dev_priv->ramin);
@@ -867,8 +890,6 @@ int nouveau_ioctl_getparam(struct drm_device *dev, void *data,
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct drm_nouveau_getparam *getparam = data;
- NOUVEAU_CHECK_INITIALISED_WITH_RETURN;
-
switch (getparam->param) {
case NOUVEAU_GETPARAM_CHIPSET_ID:
getparam->value = dev_priv->chipset;
@@ -937,8 +958,6 @@ nouveau_ioctl_setparam(struct drm_device *dev, void *data,
{
struct drm_nouveau_setparam *setparam = data;
- NOUVEAU_CHECK_INITIALISED_WITH_RETURN;
-
switch (setparam->param) {
default:
NV_ERROR(dev, "unknown parameter %lld\n", setparam->param);
diff --git a/drivers/gpu/drm/nouveau/nouveau_ttm.c b/drivers/gpu/drm/nouveau/nouveau_ttm.c
index c385d50f041..bd35f930568 100644
--- a/drivers/gpu/drm/nouveau/nouveau_ttm.c
+++ b/drivers/gpu/drm/nouveau/nouveau_ttm.c
@@ -42,13 +42,13 @@ nouveau_ttm_mmap(struct file *filp, struct vm_area_struct *vma)
}
static int
-nouveau_ttm_mem_global_init(struct ttm_global_reference *ref)
+nouveau_ttm_mem_global_init(struct drm_global_reference *ref)
{
return ttm_mem_global_init(ref->object);
}
static void
-nouveau_ttm_mem_global_release(struct ttm_global_reference *ref)
+nouveau_ttm_mem_global_release(struct drm_global_reference *ref)
{
ttm_mem_global_release(ref->object);
}
@@ -56,16 +56,16 @@ nouveau_ttm_mem_global_release(struct ttm_global_reference *ref)
int
nouveau_ttm_global_init(struct drm_nouveau_private *dev_priv)
{
- struct ttm_global_reference *global_ref;
+ struct drm_global_reference *global_ref;
int ret;
global_ref = &dev_priv->ttm.mem_global_ref;
- global_ref->global_type = TTM_GLOBAL_TTM_MEM;
+ global_ref->global_type = DRM_GLOBAL_TTM_MEM;
global_ref->size = sizeof(struct ttm_mem_global);
global_ref->init = &nouveau_ttm_mem_global_init;
global_ref->release = &nouveau_ttm_mem_global_release;
- ret = ttm_global_item_ref(global_ref);
+ ret = drm_global_item_ref(global_ref);
if (unlikely(ret != 0)) {
DRM_ERROR("Failed setting up TTM memory accounting\n");
dev_priv->ttm.mem_global_ref.release = NULL;
@@ -74,15 +74,15 @@ nouveau_ttm_global_init(struct drm_nouveau_private *dev_priv)
dev_priv->ttm.bo_global_ref.mem_glob = global_ref->object;
global_ref = &dev_priv->ttm.bo_global_ref.ref;
- global_ref->global_type = TTM_GLOBAL_TTM_BO;
+ global_ref->global_type = DRM_GLOBAL_TTM_BO;
global_ref->size = sizeof(struct ttm_bo_global);
global_ref->init = &ttm_bo_global_init;
global_ref->release = &ttm_bo_global_release;
- ret = ttm_global_item_ref(global_ref);
+ ret = drm_global_item_ref(global_ref);
if (unlikely(ret != 0)) {
DRM_ERROR("Failed setting up TTM BO subsystem\n");
- ttm_global_item_unref(&dev_priv->ttm.mem_global_ref);
+ drm_global_item_unref(&dev_priv->ttm.mem_global_ref);
dev_priv->ttm.mem_global_ref.release = NULL;
return ret;
}
@@ -96,8 +96,8 @@ nouveau_ttm_global_release(struct drm_nouveau_private *dev_priv)
if (dev_priv->ttm.mem_global_ref.release == NULL)
return;
- ttm_global_item_unref(&dev_priv->ttm.bo_global_ref.ref);
- ttm_global_item_unref(&dev_priv->ttm.mem_global_ref);
+ drm_global_item_unref(&dev_priv->ttm.bo_global_ref.ref);
+ drm_global_item_unref(&dev_priv->ttm.mem_global_ref);
dev_priv->ttm.mem_global_ref.release = NULL;
}
diff --git a/drivers/gpu/drm/nouveau/nv04_crtc.c b/drivers/gpu/drm/nouveau/nv04_crtc.c
index eba687f1099..1c20c08ce67 100644
--- a/drivers/gpu/drm/nouveau/nv04_crtc.c
+++ b/drivers/gpu/drm/nouveau/nv04_crtc.c
@@ -157,6 +157,7 @@ nv_crtc_dpms(struct drm_crtc *crtc, int mode)
{
struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
struct drm_device *dev = crtc->dev;
+ struct drm_connector *connector;
unsigned char seq1 = 0, crtc17 = 0;
unsigned char crtc1A;
@@ -211,6 +212,10 @@ nv_crtc_dpms(struct drm_crtc *crtc, int mode)
NVVgaSeqReset(dev, nv_crtc->index, false);
NVWriteVgaCrtc(dev, nv_crtc->index, NV_CIO_CRE_RPC1_INDEX, crtc1A);
+
+ /* Update connector polling modes */
+ list_for_each_entry(connector, &dev->mode_config.connector_list, head)
+ nouveau_connector_set_polling(connector);
}
static bool
diff --git a/drivers/gpu/drm/nouveau/nv04_dac.c b/drivers/gpu/drm/nouveau/nv04_dac.c
index 1cb19e3acb5..ea3627041ec 100644
--- a/drivers/gpu/drm/nouveau/nv04_dac.c
+++ b/drivers/gpu/drm/nouveau/nv04_dac.c
@@ -220,6 +220,7 @@ uint32_t nv17_dac_sample_load(struct drm_encoder *encoder)
{
struct drm_device *dev = encoder->dev;
struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nouveau_gpio_engine *gpio = &dev_priv->engine.gpio;
struct dcb_entry *dcb = nouveau_encoder(encoder)->dcb;
uint32_t sample, testval, regoffset = nv04_dac_output_offset(encoder);
uint32_t saved_powerctrl_2 = 0, saved_powerctrl_4 = 0, saved_routput,
@@ -251,22 +252,21 @@ uint32_t nv17_dac_sample_load(struct drm_encoder *encoder)
nvWriteMC(dev, NV_PBUS_POWERCTRL_4, saved_powerctrl_4 & 0xffffffcf);
}
- saved_gpio1 = nv17_gpio_get(dev, DCB_GPIO_TVDAC1);
- saved_gpio0 = nv17_gpio_get(dev, DCB_GPIO_TVDAC0);
+ saved_gpio1 = gpio->get(dev, DCB_GPIO_TVDAC1);
+ saved_gpio0 = gpio->get(dev, DCB_GPIO_TVDAC0);
- nv17_gpio_set(dev, DCB_GPIO_TVDAC1, dcb->type == OUTPUT_TV);
- nv17_gpio_set(dev, DCB_GPIO_TVDAC0, dcb->type == OUTPUT_TV);
+ gpio->set(dev, DCB_GPIO_TVDAC1, dcb->type == OUTPUT_TV);
+ gpio->set(dev, DCB_GPIO_TVDAC0, dcb->type == OUTPUT_TV);
msleep(4);
saved_routput = NVReadRAMDAC(dev, 0, NV_PRAMDAC_DACCLK + regoffset);
head = (saved_routput & 0x100) >> 8;
-#if 0
- /* if there's a spare crtc, using it will minimise flicker for the case
- * where the in-use crtc is in use by an off-chip tmds encoder */
- if (xf86_config->crtc[head]->enabled && !xf86_config->crtc[head ^ 1]->enabled)
+
+ /* if there's a spare crtc, using it will minimise flicker */
+ if (!(NVReadVgaCrtc(dev, head, NV_CIO_CRE_RPC1_INDEX) & 0xC0))
head ^= 1;
-#endif
+
/* nv driver and nv31 use 0xfffffeee, nv34 and 6600 use 0xfffffece */
routput = (saved_routput & 0xfffffece) | head << 8;
@@ -304,8 +304,8 @@ uint32_t nv17_dac_sample_load(struct drm_encoder *encoder)
nvWriteMC(dev, NV_PBUS_POWERCTRL_4, saved_powerctrl_4);
nvWriteMC(dev, NV_PBUS_POWERCTRL_2, saved_powerctrl_2);
- nv17_gpio_set(dev, DCB_GPIO_TVDAC1, saved_gpio1);
- nv17_gpio_set(dev, DCB_GPIO_TVDAC0, saved_gpio0);
+ gpio->set(dev, DCB_GPIO_TVDAC1, saved_gpio1);
+ gpio->set(dev, DCB_GPIO_TVDAC0, saved_gpio0);
return sample;
}
@@ -315,9 +315,12 @@ nv17_dac_detect(struct drm_encoder *encoder, struct drm_connector *connector)
{
struct drm_device *dev = encoder->dev;
struct dcb_entry *dcb = nouveau_encoder(encoder)->dcb;
- uint32_t sample = nv17_dac_sample_load(encoder);
- if (sample & NV_PRAMDAC_TEST_CONTROL_SENSEB_ALLHI) {
+ if (nv04_dac_in_use(encoder))
+ return connector_status_disconnected;
+
+ if (nv17_dac_sample_load(encoder) &
+ NV_PRAMDAC_TEST_CONTROL_SENSEB_ALLHI) {
NV_INFO(dev, "Load detected on output %c\n",
'@' + ffs(dcb->or));
return connector_status_connected;
@@ -330,6 +333,9 @@ static bool nv04_dac_mode_fixup(struct drm_encoder *encoder,
struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode)
{
+ if (nv04_dac_in_use(encoder))
+ return false;
+
return true;
}
@@ -428,6 +434,17 @@ void nv04_dac_update_dacclk(struct drm_encoder *encoder, bool enable)
}
}
+/* Check if the DAC corresponding to 'encoder' is being used by
+ * someone else. */
+bool nv04_dac_in_use(struct drm_encoder *encoder)
+{
+ struct drm_nouveau_private *dev_priv = encoder->dev->dev_private;
+ struct dcb_entry *dcb = nouveau_encoder(encoder)->dcb;
+
+ return nv_gf4_disp_arch(encoder->dev) &&
+ (dev_priv->dac_users[ffs(dcb->or) - 1] & ~(1 << dcb->index));
+}
+
static void nv04_dac_dpms(struct drm_encoder *encoder, int mode)
{
struct drm_device *dev = encoder->dev;
@@ -501,11 +518,13 @@ static const struct drm_encoder_funcs nv04_dac_funcs = {
.destroy = nv04_dac_destroy,
};
-int nv04_dac_create(struct drm_device *dev, struct dcb_entry *entry)
+int
+nv04_dac_create(struct drm_connector *connector, struct dcb_entry *entry)
{
const struct drm_encoder_helper_funcs *helper;
- struct drm_encoder *encoder;
struct nouveau_encoder *nv_encoder = NULL;
+ struct drm_device *dev = connector->dev;
+ struct drm_encoder *encoder;
nv_encoder = kzalloc(sizeof(*nv_encoder), GFP_KERNEL);
if (!nv_encoder)
@@ -527,5 +546,6 @@ int nv04_dac_create(struct drm_device *dev, struct dcb_entry *entry)
encoder->possible_crtcs = entry->heads;
encoder->possible_clones = 0;
+ drm_mode_connector_attach_encoder(connector, encoder);
return 0;
}
diff --git a/drivers/gpu/drm/nouveau/nv04_dfp.c b/drivers/gpu/drm/nouveau/nv04_dfp.c
index 41634d4752f..3311f3a8c81 100644
--- a/drivers/gpu/drm/nouveau/nv04_dfp.c
+++ b/drivers/gpu/drm/nouveau/nv04_dfp.c
@@ -413,10 +413,6 @@ static void nv04_dfp_commit(struct drm_encoder *encoder)
struct dcb_entry *dcbe = nv_encoder->dcb;
int head = nouveau_crtc(encoder->crtc)->index;
- NV_INFO(dev, "Output %s is running on CRTC %d using output %c\n",
- drm_get_connector_name(&nouveau_encoder_connector_get(nv_encoder)->base),
- nv_crtc->index, '@' + ffs(nv_encoder->dcb->or));
-
if (dcbe->type == OUTPUT_TMDS)
run_tmds_table(dev, dcbe, head, nv_encoder->mode.clock);
else if (dcbe->type == OUTPUT_LVDS)
@@ -584,11 +580,12 @@ static const struct drm_encoder_funcs nv04_dfp_funcs = {
.destroy = nv04_dfp_destroy,
};
-int nv04_dfp_create(struct drm_device *dev, struct dcb_entry *entry)
+int
+nv04_dfp_create(struct drm_connector *connector, struct dcb_entry *entry)
{
const struct drm_encoder_helper_funcs *helper;
- struct drm_encoder *encoder;
struct nouveau_encoder *nv_encoder = NULL;
+ struct drm_encoder *encoder;
int type;
switch (entry->type) {
@@ -613,11 +610,12 @@ int nv04_dfp_create(struct drm_device *dev, struct dcb_entry *entry)
nv_encoder->dcb = entry;
nv_encoder->or = ffs(entry->or) - 1;
- drm_encoder_init(dev, encoder, &nv04_dfp_funcs, type);
+ drm_encoder_init(connector->dev, encoder, &nv04_dfp_funcs, type);
drm_encoder_helper_add(encoder, helper);
encoder->possible_crtcs = entry->heads;
encoder->possible_clones = 0;
+ drm_mode_connector_attach_encoder(connector, encoder);
return 0;
}
diff --git a/drivers/gpu/drm/nouveau/nv04_display.c b/drivers/gpu/drm/nouveau/nv04_display.c
index c7898b4f6df..9e28cf772e3 100644
--- a/drivers/gpu/drm/nouveau/nv04_display.c
+++ b/drivers/gpu/drm/nouveau/nv04_display.c
@@ -32,8 +32,6 @@
#include "nouveau_encoder.h"
#include "nouveau_connector.h"
-#define MULTIPLE_ENCODERS(e) (e & (e - 1))
-
static void
nv04_display_store_initial_head_owner(struct drm_device *dev)
{
@@ -41,7 +39,7 @@ nv04_display_store_initial_head_owner(struct drm_device *dev)
if (dev_priv->chipset != 0x11) {
dev_priv->crtc_owner = NVReadVgaCrtc(dev, 0, NV_CIO_CRE_44);
- goto ownerknown;
+ return;
}
/* reading CR44 is broken on nv11, so we attempt to infer it */
@@ -52,8 +50,6 @@ nv04_display_store_initial_head_owner(struct drm_device *dev)
bool tvA = false;
bool tvB = false;
- NVLockVgaCrtcs(dev, false);
-
slaved_on_B = NVReadVgaCrtc(dev, 1, NV_CIO_CRE_PIXEL_INDEX) &
0x80;
if (slaved_on_B)
@@ -66,8 +62,6 @@ nv04_display_store_initial_head_owner(struct drm_device *dev)
tvA = !(NVReadVgaCrtc(dev, 0, NV_CIO_CRE_LCD__INDEX) &
MASK(NV_CIO_CRE_LCD_LCD_SELECT));
- NVLockVgaCrtcs(dev, true);
-
if (slaved_on_A && !tvA)
dev_priv->crtc_owner = 0x0;
else if (slaved_on_B && !tvB)
@@ -79,14 +73,40 @@ nv04_display_store_initial_head_owner(struct drm_device *dev)
else
dev_priv->crtc_owner = 0x0;
}
+}
+
+int
+nv04_display_early_init(struct drm_device *dev)
+{
+ /* Make the I2C buses accessible. */
+ if (!nv_gf4_disp_arch(dev)) {
+ uint32_t pmc_enable = nv_rd32(dev, NV03_PMC_ENABLE);
+
+ if (!(pmc_enable & 1))
+ nv_wr32(dev, NV03_PMC_ENABLE, pmc_enable | 1);
+ }
-ownerknown:
- NV_INFO(dev, "Initial CRTC_OWNER is %d\n", dev_priv->crtc_owner);
+ /* Unlock the VGA CRTCs. */
+ NVLockVgaCrtcs(dev, false);
+
+ /* Make sure the CRTCs aren't in slaved mode. */
+ if (nv_two_heads(dev)) {
+ nv04_display_store_initial_head_owner(dev);
+ NVSetOwner(dev, 0);
+ }
+
+ return 0;
+}
+
+void
+nv04_display_late_takedown(struct drm_device *dev)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+
+ if (nv_two_heads(dev))
+ NVSetOwner(dev, dev_priv->crtc_owner);
- /* we need to ensure the heads are not tied henceforth, or reading any
- * 8 bit reg on head B will fail
- * setting a single arbitrary head solves that */
- NVSetOwner(dev, 0);
+ NVLockVgaCrtcs(dev, true);
}
int
@@ -94,14 +114,13 @@ nv04_display_create(struct drm_device *dev)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct dcb_table *dcb = &dev_priv->vbios.dcb;
+ struct drm_connector *connector, *ct;
struct drm_encoder *encoder;
struct drm_crtc *crtc;
int i, ret;
NV_DEBUG_KMS(dev, "\n");
- if (nv_two_heads(dev))
- nv04_display_store_initial_head_owner(dev);
nouveau_hw_save_vga_fonts(dev, 1);
drm_mode_config_init(dev);
@@ -132,19 +151,23 @@ nv04_display_create(struct drm_device *dev)
for (i = 0; i < dcb->entries; i++) {
struct dcb_entry *dcbent = &dcb->entry[i];
+ connector = nouveau_connector_create(dev, dcbent->connector);
+ if (IS_ERR(connector))
+ continue;
+
switch (dcbent->type) {
case OUTPUT_ANALOG:
- ret = nv04_dac_create(dev, dcbent);
+ ret = nv04_dac_create(connector, dcbent);
break;
case OUTPUT_LVDS:
case OUTPUT_TMDS:
- ret = nv04_dfp_create(dev, dcbent);
+ ret = nv04_dfp_create(connector, dcbent);
break;
case OUTPUT_TV:
if (dcbent->location == DCB_LOC_ON_CHIP)
- ret = nv17_tv_create(dev, dcbent);
+ ret = nv17_tv_create(connector, dcbent);
else
- ret = nv04_tv_create(dev, dcbent);
+ ret = nv04_tv_create(connector, dcbent);
break;
default:
NV_WARN(dev, "DCB type %d not known\n", dcbent->type);
@@ -155,12 +178,16 @@ nv04_display_create(struct drm_device *dev)
continue;
}
- for (i = 0; i < dcb->connector.entries; i++)
- nouveau_connector_create(dev, &dcb->connector.entry[i]);
+ list_for_each_entry_safe(connector, ct,
+ &dev->mode_config.connector_list, head) {
+ if (!connector->encoder_ids[0]) {
+ NV_WARN(dev, "%s has no encoders, removing\n",
+ drm_get_connector_name(connector));
+ connector->funcs->destroy(connector);
+ }
+ }
/* Save previous state */
- NVLockVgaCrtcs(dev, false);
-
list_for_each_entry(crtc, &dev->mode_config.crtc_list, head)
crtc->funcs->save(crtc);
@@ -191,8 +218,6 @@ nv04_display_destroy(struct drm_device *dev)
}
/* Restore state */
- NVLockVgaCrtcs(dev, false);
-
list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
struct drm_encoder_helper_funcs *func = encoder->helper_private;
@@ -207,15 +232,12 @@ nv04_display_destroy(struct drm_device *dev)
nouveau_hw_save_vga_fonts(dev, 0);
}
-void
-nv04_display_restore(struct drm_device *dev)
+int
+nv04_display_init(struct drm_device *dev)
{
- struct drm_nouveau_private *dev_priv = dev->dev_private;
struct drm_encoder *encoder;
struct drm_crtc *crtc;
- NVLockVgaCrtcs(dev, false);
-
/* meh.. modeset apparently doesn't setup all the regs and depends
* on pre-existing state, for now load the state of the card *before*
* nouveau was loaded, and then do a modeset.
@@ -233,12 +255,6 @@ nv04_display_restore(struct drm_device *dev)
list_for_each_entry(crtc, &dev->mode_config.crtc_list, head)
crtc->funcs->restore(crtc);
- if (nv_two_heads(dev)) {
- NV_INFO(dev, "Restoring CRTC_OWNER to %d.\n",
- dev_priv->crtc_owner);
- NVSetOwner(dev, dev_priv->crtc_owner);
- }
-
- NVLockVgaCrtcs(dev, true);
+ return 0;
}
diff --git a/drivers/gpu/drm/nouveau/nv04_fifo.c b/drivers/gpu/drm/nouveau/nv04_fifo.c
index 66fe55983b6..06cedd99c26 100644
--- a/drivers/gpu/drm/nouveau/nv04_fifo.c
+++ b/drivers/gpu/drm/nouveau/nv04_fifo.c
@@ -112,6 +112,12 @@ nv04_fifo_channel_id(struct drm_device *dev)
NV03_PFIFO_CACHE1_PUSH1_CHID_MASK;
}
+#ifdef __BIG_ENDIAN
+#define DMA_FETCH_ENDIANNESS NV_PFIFO_CACHE1_BIG_ENDIAN
+#else
+#define DMA_FETCH_ENDIANNESS 0
+#endif
+
int
nv04_fifo_create_context(struct nouveau_channel *chan)
{
@@ -131,18 +137,13 @@ nv04_fifo_create_context(struct nouveau_channel *chan)
spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
/* Setup initial state */
- dev_priv->engine.instmem.prepare_access(dev, true);
RAMFC_WR(DMA_PUT, chan->pushbuf_base);
RAMFC_WR(DMA_GET, chan->pushbuf_base);
RAMFC_WR(DMA_INSTANCE, chan->pushbuf->instance >> 4);
RAMFC_WR(DMA_FETCH, (NV_PFIFO_CACHE1_DMA_FETCH_TRIG_128_BYTES |
NV_PFIFO_CACHE1_DMA_FETCH_SIZE_128_BYTES |
NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_8 |
-#ifdef __BIG_ENDIAN
- NV_PFIFO_CACHE1_BIG_ENDIAN |
-#endif
- 0));
- dev_priv->engine.instmem.finish_access(dev);
+ DMA_FETCH_ENDIANNESS));
/* enable the fifo dma operation */
nv_wr32(dev, NV04_PFIFO_MODE,
@@ -169,8 +170,6 @@ nv04_fifo_do_load_context(struct drm_device *dev, int chid)
struct drm_nouveau_private *dev_priv = dev->dev_private;
uint32_t fc = NV04_RAMFC(chid), tmp;
- dev_priv->engine.instmem.prepare_access(dev, false);
-
nv_wr32(dev, NV04_PFIFO_CACHE1_DMA_PUT, nv_ri32(dev, fc + 0));
nv_wr32(dev, NV04_PFIFO_CACHE1_DMA_GET, nv_ri32(dev, fc + 4));
tmp = nv_ri32(dev, fc + 8);
@@ -181,8 +180,6 @@ nv04_fifo_do_load_context(struct drm_device *dev, int chid)
nv_wr32(dev, NV04_PFIFO_CACHE1_ENGINE, nv_ri32(dev, fc + 20));
nv_wr32(dev, NV04_PFIFO_CACHE1_PULL1, nv_ri32(dev, fc + 24));
- dev_priv->engine.instmem.finish_access(dev);
-
nv_wr32(dev, NV03_PFIFO_CACHE1_GET, 0);
nv_wr32(dev, NV03_PFIFO_CACHE1_PUT, 0);
}
@@ -223,7 +220,6 @@ nv04_fifo_unload_context(struct drm_device *dev)
return -EINVAL;
}
- dev_priv->engine.instmem.prepare_access(dev, true);
RAMFC_WR(DMA_PUT, nv_rd32(dev, NV04_PFIFO_CACHE1_DMA_PUT));
RAMFC_WR(DMA_GET, nv_rd32(dev, NV04_PFIFO_CACHE1_DMA_GET));
tmp = nv_rd32(dev, NV04_PFIFO_CACHE1_DMA_DCOUNT) << 16;
@@ -233,7 +229,6 @@ nv04_fifo_unload_context(struct drm_device *dev)
RAMFC_WR(DMA_FETCH, nv_rd32(dev, NV04_PFIFO_CACHE1_DMA_FETCH));
RAMFC_WR(ENGINE, nv_rd32(dev, NV04_PFIFO_CACHE1_ENGINE));
RAMFC_WR(PULL1_ENGINE, nv_rd32(dev, NV04_PFIFO_CACHE1_PULL1));
- dev_priv->engine.instmem.finish_access(dev);
nv04_fifo_do_load_context(dev, pfifo->channels - 1);
nv_wr32(dev, NV03_PFIFO_CACHE1_PUSH1, pfifo->channels - 1);
@@ -297,6 +292,7 @@ nv04_fifo_init(struct drm_device *dev)
nv04_fifo_init_intr(dev);
pfifo->enable(dev);
+ pfifo->reassign(dev, true);
for (i = 0; i < dev_priv->engine.fifo.channels; i++) {
if (dev_priv->fifos[i]) {
diff --git a/drivers/gpu/drm/nouveau/nv04_graph.c b/drivers/gpu/drm/nouveau/nv04_graph.c
index 618355e9cdd..c8973421b63 100644
--- a/drivers/gpu/drm/nouveau/nv04_graph.c
+++ b/drivers/gpu/drm/nouveau/nv04_graph.c
@@ -342,7 +342,7 @@ static uint32_t nv04_graph_ctx_regs[] = {
};
struct graph_state {
- int nv04[ARRAY_SIZE(nv04_graph_ctx_regs)];
+ uint32_t nv04[ARRAY_SIZE(nv04_graph_ctx_regs)];
};
struct nouveau_channel *
@@ -527,8 +527,7 @@ static int
nv04_graph_mthd_set_ref(struct nouveau_channel *chan, int grclass,
int mthd, uint32_t data)
{
- chan->fence.last_sequence_irq = data;
- nouveau_fence_handler(chan->dev, chan->id);
+ atomic_set(&chan->fence.last_sequence_irq, data);
return 0;
}
diff --git a/drivers/gpu/drm/nouveau/nv04_instmem.c b/drivers/gpu/drm/nouveau/nv04_instmem.c
index a3b9563a6f6..4408232d33f 100644
--- a/drivers/gpu/drm/nouveau/nv04_instmem.c
+++ b/drivers/gpu/drm/nouveau/nv04_instmem.c
@@ -49,10 +49,8 @@ nv04_instmem_determine_amount(struct drm_device *dev)
NV_DEBUG(dev, "RAMIN size: %dKiB\n", dev_priv->ramin_rsvd_vram >> 10);
/* Clear all of it, except the BIOS image that's in the first 64KiB */
- dev_priv->engine.instmem.prepare_access(dev, true);
for (i = 64 * 1024; i < dev_priv->ramin_rsvd_vram; i += 4)
nv_wi32(dev, i, 0x00000000);
- dev_priv->engine.instmem.finish_access(dev);
}
static void
@@ -106,7 +104,7 @@ int nv04_instmem_init(struct drm_device *dev)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
uint32_t offset;
- int ret = 0;
+ int ret;
nv04_instmem_determine_amount(dev);
nv04_instmem_configure_fixed_tables(dev);
@@ -129,14 +127,14 @@ int nv04_instmem_init(struct drm_device *dev)
offset = 0x40000;
}
- ret = nouveau_mem_init_heap(&dev_priv->ramin_heap,
- offset, dev_priv->ramin_rsvd_vram - offset);
+ ret = drm_mm_init(&dev_priv->ramin_heap, offset,
+ dev_priv->ramin_rsvd_vram - offset);
if (ret) {
- dev_priv->ramin_heap = NULL;
- NV_ERROR(dev, "Failed to init RAMIN heap\n");
+ NV_ERROR(dev, "Failed to init RAMIN heap: %d\n", ret);
+ return ret;
}
- return ret;
+ return 0;
}
void
@@ -186,12 +184,7 @@ nv04_instmem_unbind(struct drm_device *dev, struct nouveau_gpuobj *gpuobj)
}
void
-nv04_instmem_prepare_access(struct drm_device *dev, bool write)
-{
-}
-
-void
-nv04_instmem_finish_access(struct drm_device *dev)
+nv04_instmem_flush(struct drm_device *dev)
{
}
diff --git a/drivers/gpu/drm/nouveau/nv04_mc.c b/drivers/gpu/drm/nouveau/nv04_mc.c
index 617ed1e0526..2af43a1cb2e 100644
--- a/drivers/gpu/drm/nouveau/nv04_mc.c
+++ b/drivers/gpu/drm/nouveau/nv04_mc.c
@@ -11,6 +11,10 @@ nv04_mc_init(struct drm_device *dev)
*/
nv_wr32(dev, NV03_PMC_ENABLE, 0xFFFFFFFF);
+
+ /* Disable PROM access. */
+ nv_wr32(dev, NV_PBUS_PCI_NV_20, NV_PBUS_PCI_NV_20_ROM_SHADOW_ENABLED);
+
return 0;
}
diff --git a/drivers/gpu/drm/nouveau/nv04_tv.c b/drivers/gpu/drm/nouveau/nv04_tv.c
index c4e3404337d..94e299cef0b 100644
--- a/drivers/gpu/drm/nouveau/nv04_tv.c
+++ b/drivers/gpu/drm/nouveau/nv04_tv.c
@@ -34,69 +34,26 @@
#include "i2c/ch7006.h"
-static struct {
- struct i2c_board_info board_info;
- struct drm_encoder_funcs funcs;
- struct drm_encoder_helper_funcs hfuncs;
- void *params;
-
-} nv04_tv_encoder_info[] = {
+static struct i2c_board_info nv04_tv_encoder_info[] = {
{
- .board_info = { I2C_BOARD_INFO("ch7006", 0x75) },
- .params = &(struct ch7006_encoder_params) {
+ I2C_BOARD_INFO("ch7006", 0x75),
+ .platform_data = &(struct ch7006_encoder_params) {
CH7006_FORMAT_RGB24m12I, CH7006_CLOCK_MASTER,
0, 0, 0,
CH7006_SYNC_SLAVE, CH7006_SYNC_SEPARATED,
CH7006_POUT_3_3V, CH7006_ACTIVE_HSYNC
- },
+ }
},
+ { }
};
-static bool probe_i2c_addr(struct i2c_adapter *adapter, int addr)
-{
- struct i2c_msg msg = {
- .addr = addr,
- .len = 0,
- };
-
- return i2c_transfer(adapter, &msg, 1) == 1;
-}
-
int nv04_tv_identify(struct drm_device *dev, int i2c_index)
{
- struct nouveau_i2c_chan *i2c;
- bool was_locked;
- int i, ret;
-
- NV_TRACE(dev, "Probing TV encoders on I2C bus: %d\n", i2c_index);
-
- i2c = nouveau_i2c_find(dev, i2c_index);
- if (!i2c)
- return -ENODEV;
-
- was_locked = NVLockVgaCrtcs(dev, false);
-
- for (i = 0; i < ARRAY_SIZE(nv04_tv_encoder_info); i++) {
- if (probe_i2c_addr(&i2c->adapter,
- nv04_tv_encoder_info[i].board_info.addr)) {
- ret = i;
- break;
- }
- }
-
- if (i < ARRAY_SIZE(nv04_tv_encoder_info)) {
- NV_TRACE(dev, "Detected TV encoder: %s\n",
- nv04_tv_encoder_info[i].board_info.type);
-
- } else {
- NV_TRACE(dev, "No TV encoders found.\n");
- i = -ENODEV;
- }
-
- NVLockVgaCrtcs(dev, was_locked);
- return i;
+ return nouveau_i2c_identify(dev, "TV encoder",
+ nv04_tv_encoder_info, i2c_index);
}
+
#define PLLSEL_TV_CRTC1_MASK \
(NV_PRAMDAC_PLL_COEFF_SELECT_TV_VSCLK1 \
| NV_PRAMDAC_PLL_COEFF_SELECT_TV_PCLK1)
@@ -214,30 +171,32 @@ static void nv04_tv_commit(struct drm_encoder *encoder)
static void nv04_tv_destroy(struct drm_encoder *encoder)
{
- struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
-
to_encoder_slave(encoder)->slave_funcs->destroy(encoder);
drm_encoder_cleanup(encoder);
- kfree(nv_encoder);
+ kfree(encoder->helper_private);
+ kfree(nouveau_encoder(encoder));
}
-int nv04_tv_create(struct drm_device *dev, struct dcb_entry *entry)
+static const struct drm_encoder_funcs nv04_tv_funcs = {
+ .destroy = nv04_tv_destroy,
+};
+
+int
+nv04_tv_create(struct drm_connector *connector, struct dcb_entry *entry)
{
struct nouveau_encoder *nv_encoder;
struct drm_encoder *encoder;
- struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct i2c_adapter *adap;
- struct drm_encoder_funcs *funcs = NULL;
- struct drm_encoder_helper_funcs *hfuncs = NULL;
- struct drm_encoder_slave_funcs *sfuncs = NULL;
- int i2c_index = entry->i2c_index;
+ struct drm_device *dev = connector->dev;
+ struct drm_encoder_helper_funcs *hfuncs;
+ struct drm_encoder_slave_funcs *sfuncs;
+ struct nouveau_i2c_chan *i2c =
+ nouveau_i2c_find(dev, entry->i2c_index);
int type, ret;
- bool was_locked;
/* Ensure that we can talk to this encoder */
- type = nv04_tv_identify(dev, i2c_index);
+ type = nv04_tv_identify(dev, entry->i2c_index);
if (type < 0)
return type;
@@ -246,41 +205,32 @@ int nv04_tv_create(struct drm_device *dev, struct dcb_entry *entry)
if (!nv_encoder)
return -ENOMEM;
+ hfuncs = kzalloc(sizeof(*hfuncs), GFP_KERNEL);
+ if (!hfuncs) {
+ ret = -ENOMEM;
+ goto fail_free;
+ }
+
/* Initialize the common members */
encoder = to_drm_encoder(nv_encoder);
- funcs = &nv04_tv_encoder_info[type].funcs;
- hfuncs = &nv04_tv_encoder_info[type].hfuncs;
-
- drm_encoder_init(dev, encoder, funcs, DRM_MODE_ENCODER_TVDAC);
+ drm_encoder_init(dev, encoder, &nv04_tv_funcs, DRM_MODE_ENCODER_TVDAC);
drm_encoder_helper_add(encoder, hfuncs);
encoder->possible_crtcs = entry->heads;
encoder->possible_clones = 0;
-
nv_encoder->dcb = entry;
nv_encoder->or = ffs(entry->or) - 1;
/* Run the slave-specific initialization */
- adap = &dev_priv->vbios.dcb.i2c[i2c_index].chan->adapter;
-
- was_locked = NVLockVgaCrtcs(dev, false);
-
- ret = drm_i2c_encoder_init(encoder->dev, to_encoder_slave(encoder), adap,
- &nv04_tv_encoder_info[type].board_info);
-
- NVLockVgaCrtcs(dev, was_locked);
-
+ ret = drm_i2c_encoder_init(dev, to_encoder_slave(encoder),
+ &i2c->adapter, &nv04_tv_encoder_info[type]);
if (ret < 0)
- goto fail;
+ goto fail_cleanup;
/* Fill the function pointers */
sfuncs = to_encoder_slave(encoder)->slave_funcs;
- *funcs = (struct drm_encoder_funcs) {
- .destroy = nv04_tv_destroy,
- };
-
*hfuncs = (struct drm_encoder_helper_funcs) {
.dpms = nv04_tv_dpms,
.save = sfuncs->save,
@@ -292,14 +242,17 @@ int nv04_tv_create(struct drm_device *dev, struct dcb_entry *entry)
.detect = sfuncs->detect,
};
- /* Set the slave encoder configuration */
- sfuncs->set_config(encoder, nv04_tv_encoder_info[type].params);
+ /* Attach it to the specified connector. */
+ sfuncs->set_config(encoder, nv04_tv_encoder_info[type].platform_data);
+ sfuncs->create_resources(encoder, connector);
+ drm_mode_connector_attach_encoder(connector, encoder);
return 0;
-fail:
+fail_cleanup:
drm_encoder_cleanup(encoder);
-
+ kfree(hfuncs);
+fail_free:
kfree(nv_encoder);
return ret;
}
diff --git a/drivers/gpu/drm/nouveau/nv10_fifo.c b/drivers/gpu/drm/nouveau/nv10_fifo.c
index 7aeabf262bc..7a4069cf5d0 100644
--- a/drivers/gpu/drm/nouveau/nv10_fifo.c
+++ b/drivers/gpu/drm/nouveau/nv10_fifo.c
@@ -55,7 +55,6 @@ nv10_fifo_create_context(struct nouveau_channel *chan)
/* Fill entries that are seen filled in dumps of nvidia driver just
* after channel's is put into DMA mode
*/
- dev_priv->engine.instmem.prepare_access(dev, true);
nv_wi32(dev, fc + 0, chan->pushbuf_base);
nv_wi32(dev, fc + 4, chan->pushbuf_base);
nv_wi32(dev, fc + 12, chan->pushbuf->instance >> 4);
@@ -66,7 +65,6 @@ nv10_fifo_create_context(struct nouveau_channel *chan)
NV_PFIFO_CACHE1_BIG_ENDIAN |
#endif
0);
- dev_priv->engine.instmem.finish_access(dev);
/* enable the fifo dma operation */
nv_wr32(dev, NV04_PFIFO_MODE,
@@ -91,8 +89,6 @@ nv10_fifo_do_load_context(struct drm_device *dev, int chid)
struct drm_nouveau_private *dev_priv = dev->dev_private;
uint32_t fc = NV10_RAMFC(chid), tmp;
- dev_priv->engine.instmem.prepare_access(dev, false);
-
nv_wr32(dev, NV04_PFIFO_CACHE1_DMA_PUT, nv_ri32(dev, fc + 0));
nv_wr32(dev, NV04_PFIFO_CACHE1_DMA_GET, nv_ri32(dev, fc + 4));
nv_wr32(dev, NV10_PFIFO_CACHE1_REF_CNT, nv_ri32(dev, fc + 8));
@@ -117,8 +113,6 @@ nv10_fifo_do_load_context(struct drm_device *dev, int chid)
nv_wr32(dev, NV10_PFIFO_CACHE1_DMA_SUBROUTINE, nv_ri32(dev, fc + 48));
out:
- dev_priv->engine.instmem.finish_access(dev);
-
nv_wr32(dev, NV03_PFIFO_CACHE1_GET, 0);
nv_wr32(dev, NV03_PFIFO_CACHE1_PUT, 0);
}
@@ -155,8 +149,6 @@ nv10_fifo_unload_context(struct drm_device *dev)
return 0;
fc = NV10_RAMFC(chid);
- dev_priv->engine.instmem.prepare_access(dev, true);
-
nv_wi32(dev, fc + 0, nv_rd32(dev, NV04_PFIFO_CACHE1_DMA_PUT));
nv_wi32(dev, fc + 4, nv_rd32(dev, NV04_PFIFO_CACHE1_DMA_GET));
nv_wi32(dev, fc + 8, nv_rd32(dev, NV10_PFIFO_CACHE1_REF_CNT));
@@ -179,8 +171,6 @@ nv10_fifo_unload_context(struct drm_device *dev)
nv_wi32(dev, fc + 48, nv_rd32(dev, NV04_PFIFO_CACHE1_DMA_GET));
out:
- dev_priv->engine.instmem.finish_access(dev);
-
nv10_fifo_do_load_context(dev, pfifo->channels - 1);
nv_wr32(dev, NV03_PFIFO_CACHE1_PUSH1, pfifo->channels - 1);
return 0;
diff --git a/drivers/gpu/drm/nouveau/nv17_gpio.c b/drivers/gpu/drm/nouveau/nv10_gpio.c
index 2e58c331e9b..007fc29e2f8 100644
--- a/drivers/gpu/drm/nouveau/nv17_gpio.c
+++ b/drivers/gpu/drm/nouveau/nv10_gpio.c
@@ -55,7 +55,7 @@ get_gpio_location(struct dcb_gpio_entry *ent, uint32_t *reg, uint32_t *shift,
}
int
-nv17_gpio_get(struct drm_device *dev, enum dcb_gpio_tag tag)
+nv10_gpio_get(struct drm_device *dev, enum dcb_gpio_tag tag)
{
struct dcb_gpio_entry *ent = nouveau_bios_gpio_entry(dev, tag);
uint32_t reg, shift, mask, value;
@@ -72,7 +72,7 @@ nv17_gpio_get(struct drm_device *dev, enum dcb_gpio_tag tag)
}
int
-nv17_gpio_set(struct drm_device *dev, enum dcb_gpio_tag tag, int state)
+nv10_gpio_set(struct drm_device *dev, enum dcb_gpio_tag tag, int state)
{
struct dcb_gpio_entry *ent = nouveau_bios_gpio_entry(dev, tag);
uint32_t reg, shift, mask, value;
diff --git a/drivers/gpu/drm/nouveau/nv17_tv.c b/drivers/gpu/drm/nouveau/nv17_tv.c
index 74c880374fb..44fefb0c708 100644
--- a/drivers/gpu/drm/nouveau/nv17_tv.c
+++ b/drivers/gpu/drm/nouveau/nv17_tv.c
@@ -37,6 +37,7 @@ static uint32_t nv42_tv_sample_load(struct drm_encoder *encoder)
{
struct drm_device *dev = encoder->dev;
struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nouveau_gpio_engine *gpio = &dev_priv->engine.gpio;
uint32_t testval, regoffset = nv04_dac_output_offset(encoder);
uint32_t gpio0, gpio1, fp_htotal, fp_hsync_start, fp_hsync_end,
fp_control, test_ctrl, dacclk, ctv_14, ctv_1c, ctv_6c;
@@ -52,8 +53,8 @@ static uint32_t nv42_tv_sample_load(struct drm_encoder *encoder)
head = (dacclk & 0x100) >> 8;
/* Save the previous state. */
- gpio1 = nv17_gpio_get(dev, DCB_GPIO_TVDAC1);
- gpio0 = nv17_gpio_get(dev, DCB_GPIO_TVDAC0);
+ gpio1 = gpio->get(dev, DCB_GPIO_TVDAC1);
+ gpio0 = gpio->get(dev, DCB_GPIO_TVDAC0);
fp_htotal = NVReadRAMDAC(dev, head, NV_PRAMDAC_FP_HTOTAL);
fp_hsync_start = NVReadRAMDAC(dev, head, NV_PRAMDAC_FP_HSYNC_START);
fp_hsync_end = NVReadRAMDAC(dev, head, NV_PRAMDAC_FP_HSYNC_END);
@@ -64,8 +65,8 @@ static uint32_t nv42_tv_sample_load(struct drm_encoder *encoder)
ctv_6c = NVReadRAMDAC(dev, head, 0x680c6c);
/* Prepare the DAC for load detection. */
- nv17_gpio_set(dev, DCB_GPIO_TVDAC1, true);
- nv17_gpio_set(dev, DCB_GPIO_TVDAC0, true);
+ gpio->set(dev, DCB_GPIO_TVDAC1, true);
+ gpio->set(dev, DCB_GPIO_TVDAC0, true);
NVWriteRAMDAC(dev, head, NV_PRAMDAC_FP_HTOTAL, 1343);
NVWriteRAMDAC(dev, head, NV_PRAMDAC_FP_HSYNC_START, 1047);
@@ -110,12 +111,27 @@ static uint32_t nv42_tv_sample_load(struct drm_encoder *encoder)
NVWriteRAMDAC(dev, head, NV_PRAMDAC_FP_HSYNC_END, fp_hsync_end);
NVWriteRAMDAC(dev, head, NV_PRAMDAC_FP_HSYNC_START, fp_hsync_start);
NVWriteRAMDAC(dev, head, NV_PRAMDAC_FP_HTOTAL, fp_htotal);
- nv17_gpio_set(dev, DCB_GPIO_TVDAC1, gpio1);
- nv17_gpio_set(dev, DCB_GPIO_TVDAC0, gpio0);
+ gpio->set(dev, DCB_GPIO_TVDAC1, gpio1);
+ gpio->set(dev, DCB_GPIO_TVDAC0, gpio0);
return sample;
}
+static bool
+get_tv_detect_quirks(struct drm_device *dev, uint32_t *pin_mask)
+{
+ /* Zotac FX5200 */
+ if (dev->pdev->device == 0x0322 &&
+ dev->pdev->subsystem_vendor == 0x19da &&
+ (dev->pdev->subsystem_device == 0x1035 ||
+ dev->pdev->subsystem_device == 0x2035)) {
+ *pin_mask = 0xc;
+ return false;
+ }
+
+ return true;
+}
+
static enum drm_connector_status
nv17_tv_detect(struct drm_encoder *encoder, struct drm_connector *connector)
{
@@ -124,12 +140,20 @@ nv17_tv_detect(struct drm_encoder *encoder, struct drm_connector *connector)
struct drm_mode_config *conf = &dev->mode_config;
struct nv17_tv_encoder *tv_enc = to_tv_enc(encoder);
struct dcb_entry *dcb = tv_enc->base.dcb;
+ bool reliable = get_tv_detect_quirks(dev, &tv_enc->pin_mask);
- if (dev_priv->chipset == 0x42 ||
- dev_priv->chipset == 0x43)
- tv_enc->pin_mask = nv42_tv_sample_load(encoder) >> 28 & 0xe;
- else
- tv_enc->pin_mask = nv17_dac_sample_load(encoder) >> 28 & 0xe;
+ if (nv04_dac_in_use(encoder))
+ return connector_status_disconnected;
+
+ if (reliable) {
+ if (dev_priv->chipset == 0x42 ||
+ dev_priv->chipset == 0x43)
+ tv_enc->pin_mask =
+ nv42_tv_sample_load(encoder) >> 28 & 0xe;
+ else
+ tv_enc->pin_mask =
+ nv17_dac_sample_load(encoder) >> 28 & 0xe;
+ }
switch (tv_enc->pin_mask) {
case 0x2:
@@ -154,7 +178,9 @@ nv17_tv_detect(struct drm_encoder *encoder, struct drm_connector *connector)
conf->tv_subconnector_property,
tv_enc->subconnector);
- if (tv_enc->subconnector) {
+ if (!reliable) {
+ return connector_status_unknown;
+ } else if (tv_enc->subconnector) {
NV_INFO(dev, "Load detected on output %c\n",
'@' + ffs(dcb->or));
return connector_status_connected;
@@ -296,6 +322,9 @@ static bool nv17_tv_mode_fixup(struct drm_encoder *encoder,
{
struct nv17_tv_norm_params *tv_norm = get_tv_norm(encoder);
+ if (nv04_dac_in_use(encoder))
+ return false;
+
if (tv_norm->kind == CTV_ENC_MODE)
adjusted_mode->clock = tv_norm->ctv_enc_mode.mode.clock;
else
@@ -307,6 +336,8 @@ static bool nv17_tv_mode_fixup(struct drm_encoder *encoder,
static void nv17_tv_dpms(struct drm_encoder *encoder, int mode)
{
struct drm_device *dev = encoder->dev;
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nouveau_gpio_engine *gpio = &dev_priv->engine.gpio;
struct nv17_tv_state *regs = &to_tv_enc(encoder)->state;
struct nv17_tv_norm_params *tv_norm = get_tv_norm(encoder);
@@ -331,8 +362,8 @@ static void nv17_tv_dpms(struct drm_encoder *encoder, int mode)
nv_load_ptv(dev, regs, 200);
- nv17_gpio_set(dev, DCB_GPIO_TVDAC1, mode == DRM_MODE_DPMS_ON);
- nv17_gpio_set(dev, DCB_GPIO_TVDAC0, mode == DRM_MODE_DPMS_ON);
+ gpio->set(dev, DCB_GPIO_TVDAC1, mode == DRM_MODE_DPMS_ON);
+ gpio->set(dev, DCB_GPIO_TVDAC0, mode == DRM_MODE_DPMS_ON);
nv04_dac_update_dacclk(encoder, mode == DRM_MODE_DPMS_ON);
}
@@ -744,8 +775,10 @@ static struct drm_encoder_funcs nv17_tv_funcs = {
.destroy = nv17_tv_destroy,
};
-int nv17_tv_create(struct drm_device *dev, struct dcb_entry *entry)
+int
+nv17_tv_create(struct drm_connector *connector, struct dcb_entry *entry)
{
+ struct drm_device *dev = connector->dev;
struct drm_encoder *encoder;
struct nv17_tv_encoder *tv_enc = NULL;
@@ -774,5 +807,7 @@ int nv17_tv_create(struct drm_device *dev, struct dcb_entry *entry)
encoder->possible_crtcs = entry->heads;
encoder->possible_clones = 0;
+ nv17_tv_create_resources(encoder, connector);
+ drm_mode_connector_attach_encoder(connector, encoder);
return 0;
}
diff --git a/drivers/gpu/drm/nouveau/nv20_graph.c b/drivers/gpu/drm/nouveau/nv20_graph.c
index d6fc0a82f03..17f309b36c9 100644
--- a/drivers/gpu/drm/nouveau/nv20_graph.c
+++ b/drivers/gpu/drm/nouveau/nv20_graph.c
@@ -370,68 +370,54 @@ nv20_graph_create_context(struct nouveau_channel *chan)
{
struct drm_device *dev = chan->dev;
struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
void (*ctx_init)(struct drm_device *, struct nouveau_gpuobj *);
- unsigned int ctx_size;
unsigned int idoffs = 0x28/4;
int ret;
switch (dev_priv->chipset) {
case 0x20:
- ctx_size = NV20_GRCTX_SIZE;
ctx_init = nv20_graph_context_init;
idoffs = 0;
break;
case 0x25:
case 0x28:
- ctx_size = NV25_GRCTX_SIZE;
ctx_init = nv25_graph_context_init;
break;
case 0x2a:
- ctx_size = NV2A_GRCTX_SIZE;
ctx_init = nv2a_graph_context_init;
idoffs = 0;
break;
case 0x30:
case 0x31:
- ctx_size = NV30_31_GRCTX_SIZE;
ctx_init = nv30_31_graph_context_init;
break;
case 0x34:
- ctx_size = NV34_GRCTX_SIZE;
ctx_init = nv34_graph_context_init;
break;
case 0x35:
case 0x36:
- ctx_size = NV35_36_GRCTX_SIZE;
ctx_init = nv35_36_graph_context_init;
break;
default:
- ctx_size = 0;
- ctx_init = nv35_36_graph_context_init;
- NV_ERROR(dev, "Please contact the devs if you want your NV%x"
- " card to work\n", dev_priv->chipset);
- return -ENOSYS;
- break;
+ BUG_ON(1);
}
- ret = nouveau_gpuobj_new_ref(dev, chan, NULL, 0, ctx_size, 16,
- NVOBJ_FLAG_ZERO_ALLOC,
- &chan->ramin_grctx);
+ ret = nouveau_gpuobj_new_ref(dev, chan, NULL, 0, pgraph->grctx_size,
+ 16, NVOBJ_FLAG_ZERO_ALLOC,
+ &chan->ramin_grctx);
if (ret)
return ret;
/* Initialise default context values */
- dev_priv->engine.instmem.prepare_access(dev, true);
ctx_init(dev, chan->ramin_grctx->gpuobj);
/* nv20: nv_wo32(dev, chan->ramin_grctx->gpuobj, 10, chan->id<<24); */
nv_wo32(dev, chan->ramin_grctx->gpuobj, idoffs,
(chan->id << 24) | 0x1); /* CTX_USER */
- nv_wo32(dev, dev_priv->ctx_table->gpuobj, chan->id,
- chan->ramin_grctx->instance >> 4);
-
- dev_priv->engine.instmem.finish_access(dev);
+ nv_wo32(dev, pgraph->ctx_table->gpuobj, chan->id,
+ chan->ramin_grctx->instance >> 4);
return 0;
}
@@ -440,13 +426,12 @@ nv20_graph_destroy_context(struct nouveau_channel *chan)
{
struct drm_device *dev = chan->dev;
struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
if (chan->ramin_grctx)
nouveau_gpuobj_ref_del(dev, &chan->ramin_grctx);
- dev_priv->engine.instmem.prepare_access(dev, true);
- nv_wo32(dev, dev_priv->ctx_table->gpuobj, chan->id, 0);
- dev_priv->engine.instmem.finish_access(dev);
+ nv_wo32(dev, pgraph->ctx_table->gpuobj, chan->id, 0);
}
int
@@ -538,29 +523,44 @@ nv20_graph_set_region_tiling(struct drm_device *dev, int i, uint32_t addr,
int
nv20_graph_init(struct drm_device *dev)
{
- struct drm_nouveau_private *dev_priv =
- (struct drm_nouveau_private *)dev->dev_private;
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
uint32_t tmp, vramsz;
int ret, i;
+ switch (dev_priv->chipset) {
+ case 0x20:
+ pgraph->grctx_size = NV20_GRCTX_SIZE;
+ break;
+ case 0x25:
+ case 0x28:
+ pgraph->grctx_size = NV25_GRCTX_SIZE;
+ break;
+ case 0x2a:
+ pgraph->grctx_size = NV2A_GRCTX_SIZE;
+ break;
+ default:
+ NV_ERROR(dev, "unknown chipset, disabling acceleration\n");
+ pgraph->accel_blocked = true;
+ return 0;
+ }
+
nv_wr32(dev, NV03_PMC_ENABLE,
nv_rd32(dev, NV03_PMC_ENABLE) & ~NV_PMC_ENABLE_PGRAPH);
nv_wr32(dev, NV03_PMC_ENABLE,
nv_rd32(dev, NV03_PMC_ENABLE) | NV_PMC_ENABLE_PGRAPH);
- if (!dev_priv->ctx_table) {
+ if (!pgraph->ctx_table) {
/* Create Context Pointer Table */
- dev_priv->ctx_table_size = 32 * 4;
- ret = nouveau_gpuobj_new_ref(dev, NULL, NULL, 0,
- dev_priv->ctx_table_size, 16,
+ ret = nouveau_gpuobj_new_ref(dev, NULL, NULL, 0, 32 * 4, 16,
NVOBJ_FLAG_ZERO_ALLOC,
- &dev_priv->ctx_table);
+ &pgraph->ctx_table);
if (ret)
return ret;
}
nv_wr32(dev, NV20_PGRAPH_CHANNEL_CTX_TABLE,
- dev_priv->ctx_table->instance >> 4);
+ pgraph->ctx_table->instance >> 4);
nv20_graph_rdi(dev);
@@ -616,7 +616,7 @@ nv20_graph_init(struct drm_device *dev)
nv_wr32(dev, NV10_PGRAPH_SURFACE, tmp);
/* begin RAM config */
- vramsz = drm_get_resource_len(dev, 0) - 1;
+ vramsz = pci_resource_len(dev->pdev, 0) - 1;
nv_wr32(dev, 0x4009A4, nv_rd32(dev, NV04_PFB_CFG0));
nv_wr32(dev, 0x4009A8, nv_rd32(dev, NV04_PFB_CFG1));
nv_wr32(dev, NV10_PGRAPH_RDI_INDEX, 0x00EA0000);
@@ -644,34 +644,52 @@ void
nv20_graph_takedown(struct drm_device *dev)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
- nouveau_gpuobj_ref_del(dev, &dev_priv->ctx_table);
+ nouveau_gpuobj_ref_del(dev, &pgraph->ctx_table);
}
int
nv30_graph_init(struct drm_device *dev)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
int ret, i;
+ switch (dev_priv->chipset) {
+ case 0x30:
+ case 0x31:
+ pgraph->grctx_size = NV30_31_GRCTX_SIZE;
+ break;
+ case 0x34:
+ pgraph->grctx_size = NV34_GRCTX_SIZE;
+ break;
+ case 0x35:
+ case 0x36:
+ pgraph->grctx_size = NV35_36_GRCTX_SIZE;
+ break;
+ default:
+ NV_ERROR(dev, "unknown chipset, disabling acceleration\n");
+ pgraph->accel_blocked = true;
+ return 0;
+ }
+
nv_wr32(dev, NV03_PMC_ENABLE,
nv_rd32(dev, NV03_PMC_ENABLE) & ~NV_PMC_ENABLE_PGRAPH);
nv_wr32(dev, NV03_PMC_ENABLE,
nv_rd32(dev, NV03_PMC_ENABLE) | NV_PMC_ENABLE_PGRAPH);
- if (!dev_priv->ctx_table) {
+ if (!pgraph->ctx_table) {
/* Create Context Pointer Table */
- dev_priv->ctx_table_size = 32 * 4;
- ret = nouveau_gpuobj_new_ref(dev, NULL, NULL, 0,
- dev_priv->ctx_table_size, 16,
+ ret = nouveau_gpuobj_new_ref(dev, NULL, NULL, 0, 32 * 4, 16,
NVOBJ_FLAG_ZERO_ALLOC,
- &dev_priv->ctx_table);
+ &pgraph->ctx_table);
if (ret)
return ret;
}
nv_wr32(dev, NV20_PGRAPH_CHANNEL_CTX_TABLE,
- dev_priv->ctx_table->instance >> 4);
+ pgraph->ctx_table->instance >> 4);
nv_wr32(dev, NV03_PGRAPH_INTR , 0xFFFFFFFF);
nv_wr32(dev, NV03_PGRAPH_INTR_EN, 0xFFFFFFFF);
@@ -717,7 +735,7 @@ nv30_graph_init(struct drm_device *dev)
nv_wr32(dev, 0x0040075c , 0x00000001);
/* begin RAM config */
- /* vramsz = drm_get_resource_len(dev, 0) - 1; */
+ /* vramsz = pci_resource_len(dev->pdev, 0) - 1; */
nv_wr32(dev, 0x4009A4, nv_rd32(dev, NV04_PFB_CFG0));
nv_wr32(dev, 0x4009A8, nv_rd32(dev, NV04_PFB_CFG1));
if (dev_priv->chipset != 0x34) {
diff --git a/drivers/gpu/drm/nouveau/nv30_fb.c b/drivers/gpu/drm/nouveau/nv30_fb.c
new file mode 100644
index 00000000000..9d35c8b3b83
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nv30_fb.c
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2010 Francisco Jerez.
+ * All Rights Reserved.
+ *
+ * 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 (including the
+ * next paragraph) 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 COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS 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 "drmP.h"
+#include "drm.h"
+#include "nouveau_drv.h"
+#include "nouveau_drm.h"
+
+static int
+calc_ref(int b, int l, int i)
+{
+ int j, x = 0;
+
+ for (j = 0; j < 4; j++) {
+ int n = (b >> (8 * j) & 0xf);
+ int m = (l >> (8 * i) & 0xff) + 2 * (n & 0x8 ? n - 0x10 : n);
+
+ x |= (0x80 | (m & 0x1f)) << (8 * j);
+ }
+
+ return x;
+}
+
+int
+nv30_fb_init(struct drm_device *dev)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nouveau_fb_engine *pfb = &dev_priv->engine.fb;
+ int i, j;
+
+ pfb->num_tiles = NV10_PFB_TILE__SIZE;
+
+ /* Turn all the tiling regions off. */
+ for (i = 0; i < pfb->num_tiles; i++)
+ pfb->set_region_tiling(dev, i, 0, 0, 0);
+
+ /* Init the memory timing regs at 0x10037c/0x1003ac */
+ if (dev_priv->chipset == 0x30 ||
+ dev_priv->chipset == 0x31 ||
+ dev_priv->chipset == 0x35) {
+ /* Related to ROP count */
+ int n = (dev_priv->chipset == 0x31 ? 2 : 4);
+ int b = (dev_priv->chipset > 0x30 ?
+ nv_rd32(dev, 0x122c) & 0xf : 0);
+ int l = nv_rd32(dev, 0x1003d0);
+
+ for (i = 0; i < n; i++) {
+ for (j = 0; j < 3; j++)
+ nv_wr32(dev, 0x10037c + 0xc * i + 0x4 * j,
+ calc_ref(b, l, j));
+
+ for (j = 0; j < 2; j++)
+ nv_wr32(dev, 0x1003ac + 0x8 * i + 0x4 * j,
+ calc_ref(b, l, j));
+ }
+ }
+
+ return 0;
+}
+
+void
+nv30_fb_takedown(struct drm_device *dev)
+{
+}
diff --git a/drivers/gpu/drm/nouveau/nv40_fifo.c b/drivers/gpu/drm/nouveau/nv40_fifo.c
index 500ccfd3a0b..2b67f1835c3 100644
--- a/drivers/gpu/drm/nouveau/nv40_fifo.c
+++ b/drivers/gpu/drm/nouveau/nv40_fifo.c
@@ -48,7 +48,6 @@ nv40_fifo_create_context(struct nouveau_channel *chan)
spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
- dev_priv->engine.instmem.prepare_access(dev, true);
nv_wi32(dev, fc + 0, chan->pushbuf_base);
nv_wi32(dev, fc + 4, chan->pushbuf_base);
nv_wi32(dev, fc + 12, chan->pushbuf->instance >> 4);
@@ -61,7 +60,6 @@ nv40_fifo_create_context(struct nouveau_channel *chan)
0x30000000 /* no idea.. */);
nv_wi32(dev, fc + 56, chan->ramin_grctx->instance >> 4);
nv_wi32(dev, fc + 60, 0x0001FFFF);
- dev_priv->engine.instmem.finish_access(dev);
/* enable the fifo dma operation */
nv_wr32(dev, NV04_PFIFO_MODE,
@@ -89,8 +87,6 @@ nv40_fifo_do_load_context(struct drm_device *dev, int chid)
struct drm_nouveau_private *dev_priv = dev->dev_private;
uint32_t fc = NV40_RAMFC(chid), tmp, tmp2;
- dev_priv->engine.instmem.prepare_access(dev, false);
-
nv_wr32(dev, NV04_PFIFO_CACHE1_DMA_PUT, nv_ri32(dev, fc + 0));
nv_wr32(dev, NV04_PFIFO_CACHE1_DMA_GET, nv_ri32(dev, fc + 4));
nv_wr32(dev, NV10_PFIFO_CACHE1_REF_CNT, nv_ri32(dev, fc + 8));
@@ -127,8 +123,6 @@ nv40_fifo_do_load_context(struct drm_device *dev, int chid)
nv_wr32(dev, 0x2088, nv_ri32(dev, fc + 76));
nv_wr32(dev, 0x3300, nv_ri32(dev, fc + 80));
- dev_priv->engine.instmem.finish_access(dev);
-
nv_wr32(dev, NV03_PFIFO_CACHE1_GET, 0);
nv_wr32(dev, NV03_PFIFO_CACHE1_PUT, 0);
}
@@ -166,7 +160,6 @@ nv40_fifo_unload_context(struct drm_device *dev)
return 0;
fc = NV40_RAMFC(chid);
- dev_priv->engine.instmem.prepare_access(dev, true);
nv_wi32(dev, fc + 0, nv_rd32(dev, NV04_PFIFO_CACHE1_DMA_PUT));
nv_wi32(dev, fc + 4, nv_rd32(dev, NV04_PFIFO_CACHE1_DMA_GET));
nv_wi32(dev, fc + 8, nv_rd32(dev, NV10_PFIFO_CACHE1_REF_CNT));
@@ -200,7 +193,6 @@ nv40_fifo_unload_context(struct drm_device *dev)
tmp |= (nv_rd32(dev, NV04_PFIFO_CACHE1_PUT) << 16);
nv_wi32(dev, fc + 72, tmp);
#endif
- dev_priv->engine.instmem.finish_access(dev);
nv40_fifo_do_load_context(dev, pfifo->channels - 1);
nv_wr32(dev, NV03_PFIFO_CACHE1_PUSH1,
diff --git a/drivers/gpu/drm/nouveau/nv40_graph.c b/drivers/gpu/drm/nouveau/nv40_graph.c
index 704a25d04ac..fd7d2b50131 100644
--- a/drivers/gpu/drm/nouveau/nv40_graph.c
+++ b/drivers/gpu/drm/nouveau/nv40_graph.c
@@ -58,6 +58,7 @@ nv40_graph_create_context(struct nouveau_channel *chan)
struct drm_device *dev = chan->dev;
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
+ struct nouveau_grctx ctx = {};
int ret;
ret = nouveau_gpuobj_new_ref(dev, chan, NULL, 0, pgraph->grctx_size,
@@ -67,20 +68,13 @@ nv40_graph_create_context(struct nouveau_channel *chan)
return ret;
/* Initialise default context values */
- dev_priv->engine.instmem.prepare_access(dev, true);
- if (!pgraph->ctxprog) {
- struct nouveau_grctx ctx = {};
-
- ctx.dev = chan->dev;
- ctx.mode = NOUVEAU_GRCTX_VALS;
- ctx.data = chan->ramin_grctx->gpuobj;
- nv40_grctx_init(&ctx);
- } else {
- nouveau_grctx_vals_load(dev, chan->ramin_grctx->gpuobj);
- }
+ ctx.dev = chan->dev;
+ ctx.mode = NOUVEAU_GRCTX_VALS;
+ ctx.data = chan->ramin_grctx->gpuobj;
+ nv40_grctx_init(&ctx);
+
nv_wo32(dev, chan->ramin_grctx->gpuobj, 0,
chan->ramin_grctx->gpuobj->im_pramin->start);
- dev_priv->engine.instmem.finish_access(dev);
return 0;
}
@@ -238,7 +232,8 @@ nv40_graph_init(struct drm_device *dev)
struct drm_nouveau_private *dev_priv =
(struct drm_nouveau_private *)dev->dev_private;
struct nouveau_fb_engine *pfb = &dev_priv->engine.fb;
- uint32_t vramsz;
+ struct nouveau_grctx ctx = {};
+ uint32_t vramsz, *cp;
int i, j;
nv_wr32(dev, NV03_PMC_ENABLE, nv_rd32(dev, NV03_PMC_ENABLE) &
@@ -246,32 +241,22 @@ nv40_graph_init(struct drm_device *dev)
nv_wr32(dev, NV03_PMC_ENABLE, nv_rd32(dev, NV03_PMC_ENABLE) |
NV_PMC_ENABLE_PGRAPH);
- if (nouveau_ctxfw) {
- nouveau_grctx_prog_load(dev);
- dev_priv->engine.graph.grctx_size = 175 * 1024;
- }
+ cp = kmalloc(sizeof(*cp) * 256, GFP_KERNEL);
+ if (!cp)
+ return -ENOMEM;
- if (!dev_priv->engine.graph.ctxprog) {
- struct nouveau_grctx ctx = {};
- uint32_t *cp;
+ ctx.dev = dev;
+ ctx.mode = NOUVEAU_GRCTX_PROG;
+ ctx.data = cp;
+ ctx.ctxprog_max = 256;
+ nv40_grctx_init(&ctx);
+ dev_priv->engine.graph.grctx_size = ctx.ctxvals_pos * 4;
- cp = kmalloc(sizeof(*cp) * 256, GFP_KERNEL);
- if (!cp)
- return -ENOMEM;
+ nv_wr32(dev, NV40_PGRAPH_CTXCTL_UCODE_INDEX, 0);
+ for (i = 0; i < ctx.ctxprog_len; i++)
+ nv_wr32(dev, NV40_PGRAPH_CTXCTL_UCODE_DATA, cp[i]);
- ctx.dev = dev;
- ctx.mode = NOUVEAU_GRCTX_PROG;
- ctx.data = cp;
- ctx.ctxprog_max = 256;
- nv40_grctx_init(&ctx);
- dev_priv->engine.graph.grctx_size = ctx.ctxvals_pos * 4;
-
- nv_wr32(dev, NV40_PGRAPH_CTXCTL_UCODE_INDEX, 0);
- for (i = 0; i < ctx.ctxprog_len; i++)
- nv_wr32(dev, NV40_PGRAPH_CTXCTL_UCODE_DATA, cp[i]);
-
- kfree(cp);
- }
+ kfree(cp);
/* No context present currently */
nv_wr32(dev, NV40_PGRAPH_CTXCTL_CUR, 0x00000000);
@@ -367,7 +352,7 @@ nv40_graph_init(struct drm_device *dev)
nv40_graph_set_region_tiling(dev, i, 0, 0, 0);
/* begin RAM config */
- vramsz = drm_get_resource_len(dev, 0) - 1;
+ vramsz = pci_resource_len(dev->pdev, 0) - 1;
switch (dev_priv->chipset) {
case 0x40:
nv_wr32(dev, 0x4009A4, nv_rd32(dev, NV04_PFB_CFG0));
@@ -407,7 +392,6 @@ nv40_graph_init(struct drm_device *dev)
void nv40_graph_takedown(struct drm_device *dev)
{
- nouveau_grctx_fini(dev);
}
struct nouveau_pgraph_object_class nv40_graph_grclass[] = {
diff --git a/drivers/gpu/drm/nouveau/nv40_mc.c b/drivers/gpu/drm/nouveau/nv40_mc.c
index 2a3495e848e..e4e72c12ab6 100644
--- a/drivers/gpu/drm/nouveau/nv40_mc.c
+++ b/drivers/gpu/drm/nouveau/nv40_mc.c
@@ -19,7 +19,7 @@ nv40_mc_init(struct drm_device *dev)
case 0x46: /* G72 */
case 0x4e:
case 0x4c: /* C51_G7X */
- tmp = nv_rd32(dev, NV40_PFB_020C);
+ tmp = nv_rd32(dev, NV04_PFB_FIFO_DATA);
nv_wr32(dev, NV40_PMC_1700, tmp);
nv_wr32(dev, NV40_PMC_1704, 0);
nv_wr32(dev, NV40_PMC_1708, 0);
diff --git a/drivers/gpu/drm/nouveau/nv50_crtc.c b/drivers/gpu/drm/nouveau/nv50_crtc.c
index b4e4a3b05ea..5d11ea10166 100644
--- a/drivers/gpu/drm/nouveau/nv50_crtc.c
+++ b/drivers/gpu/drm/nouveau/nv50_crtc.c
@@ -440,47 +440,15 @@ nv50_crtc_prepare(struct drm_crtc *crtc)
{
struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
struct drm_device *dev = crtc->dev;
- struct drm_encoder *encoder;
- uint32_t dac = 0, sor = 0;
NV_DEBUG_KMS(dev, "index %d\n", nv_crtc->index);
- /* Disconnect all unused encoders. */
- list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
- struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
-
- if (!drm_helper_encoder_in_use(encoder))
- continue;
-
- if (nv_encoder->dcb->type == OUTPUT_ANALOG ||
- nv_encoder->dcb->type == OUTPUT_TV)
- dac |= (1 << nv_encoder->or);
- else
- sor |= (1 << nv_encoder->or);
- }
-
- list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
- struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
-
- if (nv_encoder->dcb->type == OUTPUT_ANALOG ||
- nv_encoder->dcb->type == OUTPUT_TV) {
- if (dac & (1 << nv_encoder->or))
- continue;
- } else {
- if (sor & (1 << nv_encoder->or))
- continue;
- }
-
- nv_encoder->disconnect(nv_encoder);
- }
-
nv50_crtc_blank(nv_crtc, true);
}
static void
nv50_crtc_commit(struct drm_crtc *crtc)
{
- struct drm_crtc *crtc2;
struct drm_device *dev = crtc->dev;
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_channel *evo = dev_priv->evo;
@@ -491,20 +459,14 @@ nv50_crtc_commit(struct drm_crtc *crtc)
nv50_crtc_blank(nv_crtc, false);
- /* Explicitly blank all unused crtc's. */
- list_for_each_entry(crtc2, &dev->mode_config.crtc_list, head) {
- if (!drm_helper_crtc_in_use(crtc2))
- nv50_crtc_blank(nouveau_crtc(crtc2), true);
- }
-
ret = RING_SPACE(evo, 2);
if (ret) {
NV_ERROR(dev, "no space while committing crtc\n");
return;
}
BEGIN_RING(evo, 0, NV50_EVO_UPDATE, 1);
- OUT_RING(evo, 0);
- FIRE_RING(evo);
+ OUT_RING (evo, 0);
+ FIRE_RING (evo);
}
static bool
diff --git a/drivers/gpu/drm/nouveau/nv50_dac.c b/drivers/gpu/drm/nouveau/nv50_dac.c
index 1fd9537beff..1bc08596294 100644
--- a/drivers/gpu/drm/nouveau/nv50_dac.c
+++ b/drivers/gpu/drm/nouveau/nv50_dac.c
@@ -37,22 +37,31 @@
#include "nv50_display.h"
static void
-nv50_dac_disconnect(struct nouveau_encoder *nv_encoder)
+nv50_dac_disconnect(struct drm_encoder *encoder)
{
- struct drm_device *dev = to_drm_encoder(nv_encoder)->dev;
+ struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
+ struct drm_device *dev = encoder->dev;
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_channel *evo = dev_priv->evo;
int ret;
+ if (!nv_encoder->crtc)
+ return;
+ nv50_crtc_blank(nouveau_crtc(nv_encoder->crtc), true);
+
NV_DEBUG_KMS(dev, "Disconnecting DAC %d\n", nv_encoder->or);
- ret = RING_SPACE(evo, 2);
+ ret = RING_SPACE(evo, 4);
if (ret) {
NV_ERROR(dev, "no space while disconnecting DAC\n");
return;
}
BEGIN_RING(evo, 0, NV50_EVO_DAC(nv_encoder->or, MODE_CTRL), 1);
- OUT_RING(evo, 0);
+ OUT_RING (evo, 0);
+ BEGIN_RING(evo, 0, NV50_EVO_UPDATE, 1);
+ OUT_RING (evo, 0);
+
+ nv_encoder->crtc = NULL;
}
static enum drm_connector_status
@@ -213,7 +222,8 @@ nv50_dac_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode,
uint32_t mode_ctl = 0, mode_ctl2 = 0;
int ret;
- NV_DEBUG_KMS(dev, "or %d\n", nv_encoder->or);
+ NV_DEBUG_KMS(dev, "or %d type %d crtc %d\n",
+ nv_encoder->or, nv_encoder->dcb->type, crtc->index);
nv50_dac_dpms(encoder, DRM_MODE_DPMS_ON);
@@ -243,6 +253,14 @@ nv50_dac_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode,
BEGIN_RING(evo, 0, NV50_EVO_DAC(nv_encoder->or, MODE_CTRL), 2);
OUT_RING(evo, mode_ctl);
OUT_RING(evo, mode_ctl2);
+
+ nv_encoder->crtc = encoder->crtc;
+}
+
+static struct drm_crtc *
+nv50_dac_crtc_get(struct drm_encoder *encoder)
+{
+ return nouveau_encoder(encoder)->crtc;
}
static const struct drm_encoder_helper_funcs nv50_dac_helper_funcs = {
@@ -253,7 +271,9 @@ static const struct drm_encoder_helper_funcs nv50_dac_helper_funcs = {
.prepare = nv50_dac_prepare,
.commit = nv50_dac_commit,
.mode_set = nv50_dac_mode_set,
- .detect = nv50_dac_detect
+ .get_crtc = nv50_dac_crtc_get,
+ .detect = nv50_dac_detect,
+ .disable = nv50_dac_disconnect
};
static void
@@ -275,14 +295,11 @@ static const struct drm_encoder_funcs nv50_dac_encoder_funcs = {
};
int
-nv50_dac_create(struct drm_device *dev, struct dcb_entry *entry)
+nv50_dac_create(struct drm_connector *connector, struct dcb_entry *entry)
{
struct nouveau_encoder *nv_encoder;
struct drm_encoder *encoder;
- NV_DEBUG_KMS(dev, "\n");
- NV_INFO(dev, "Detected a DAC output\n");
-
nv_encoder = kzalloc(sizeof(*nv_encoder), GFP_KERNEL);
if (!nv_encoder)
return -ENOMEM;
@@ -291,14 +308,14 @@ nv50_dac_create(struct drm_device *dev, struct dcb_entry *entry)
nv_encoder->dcb = entry;
nv_encoder->or = ffs(entry->or) - 1;
- nv_encoder->disconnect = nv50_dac_disconnect;
-
- drm_encoder_init(dev, encoder, &nv50_dac_encoder_funcs,
+ drm_encoder_init(connector->dev, encoder, &nv50_dac_encoder_funcs,
DRM_MODE_ENCODER_DAC);
drm_encoder_helper_add(encoder, &nv50_dac_helper_funcs);
encoder->possible_crtcs = entry->heads;
encoder->possible_clones = 0;
+
+ drm_mode_connector_attach_encoder(connector, encoder);
return 0;
}
diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c
index 580a5d10be9..f13ad0de9c8 100644
--- a/drivers/gpu/drm/nouveau/nv50_display.c
+++ b/drivers/gpu/drm/nouveau/nv50_display.c
@@ -71,14 +71,13 @@ nv50_evo_dmaobj_new(struct nouveau_channel *evo, uint32_t class, uint32_t name,
return ret;
}
- dev_priv->engine.instmem.prepare_access(dev, true);
nv_wo32(dev, obj, 0, (tile_flags << 22) | (magic_flags << 16) | class);
nv_wo32(dev, obj, 1, limit);
nv_wo32(dev, obj, 2, offset);
nv_wo32(dev, obj, 3, 0x00000000);
nv_wo32(dev, obj, 4, 0x00000000);
nv_wo32(dev, obj, 5, 0x00010000);
- dev_priv->engine.instmem.finish_access(dev);
+ dev_priv->engine.instmem.flush(dev);
return 0;
}
@@ -110,8 +109,8 @@ nv50_evo_channel_new(struct drm_device *dev, struct nouveau_channel **pchan)
return ret;
}
- ret = nouveau_mem_init_heap(&chan->ramin_heap, chan->ramin->gpuobj->
- im_pramin->start, 32768);
+ ret = drm_mm_init(&chan->ramin_heap,
+ chan->ramin->gpuobj->im_pramin->start, 32768);
if (ret) {
NV_ERROR(dev, "Error initialising EVO PRAMIN heap: %d\n", ret);
nv50_evo_channel_del(pchan);
@@ -179,13 +178,25 @@ nv50_evo_channel_new(struct drm_device *dev, struct nouveau_channel **pchan)
}
int
+nv50_display_early_init(struct drm_device *dev)
+{
+ return 0;
+}
+
+void
+nv50_display_late_takedown(struct drm_device *dev)
+{
+}
+
+int
nv50_display_init(struct drm_device *dev)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_timer_engine *ptimer = &dev_priv->engine.timer;
+ struct nouveau_gpio_engine *pgpio = &dev_priv->engine.gpio;
struct nouveau_channel *evo = dev_priv->evo;
struct drm_connector *connector;
- uint32_t val, ram_amount, hpd_en[2];
+ uint32_t val, ram_amount;
uint64_t start;
int ret, i;
@@ -366,26 +377,13 @@ nv50_display_init(struct drm_device *dev)
NV50_PDISPLAY_INTR_EN_CLK_UNK40));
/* enable hotplug interrupts */
- hpd_en[0] = hpd_en[1] = 0;
list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
struct nouveau_connector *conn = nouveau_connector(connector);
- struct dcb_gpio_entry *gpio;
if (conn->dcb->gpio_tag == 0xff)
continue;
- gpio = nouveau_bios_gpio_entry(dev, conn->dcb->gpio_tag);
- if (!gpio)
- continue;
-
- hpd_en[gpio->line >> 4] |= (0x00010001 << (gpio->line & 0xf));
- }
-
- nv_wr32(dev, 0xe054, 0xffffffff);
- nv_wr32(dev, 0xe050, hpd_en[0]);
- if (dev_priv->chipset >= 0x90) {
- nv_wr32(dev, 0xe074, 0xffffffff);
- nv_wr32(dev, 0xe070, hpd_en[1]);
+ pgpio->irq_enable(dev, conn->dcb->gpio_tag, true);
}
return 0;
@@ -465,6 +463,7 @@ int nv50_display_create(struct drm_device *dev)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct dcb_table *dcb = &dev_priv->vbios.dcb;
+ struct drm_connector *connector, *ct;
int ret, i;
NV_DEBUG_KMS(dev, "\n");
@@ -507,14 +506,18 @@ int nv50_display_create(struct drm_device *dev)
continue;
}
+ connector = nouveau_connector_create(dev, entry->connector);
+ if (IS_ERR(connector))
+ continue;
+
switch (entry->type) {
case OUTPUT_TMDS:
case OUTPUT_LVDS:
case OUTPUT_DP:
- nv50_sor_create(dev, entry);
+ nv50_sor_create(connector, entry);
break;
case OUTPUT_ANALOG:
- nv50_dac_create(dev, entry);
+ nv50_dac_create(connector, entry);
break;
default:
NV_WARN(dev, "DCB encoder %d unknown\n", entry->type);
@@ -522,11 +525,13 @@ int nv50_display_create(struct drm_device *dev)
}
}
- for (i = 0 ; i < dcb->connector.entries; i++) {
- if (i != 0 && dcb->connector.entry[i].index2 ==
- dcb->connector.entry[i - 1].index2)
- continue;
- nouveau_connector_create(dev, &dcb->connector.entry[i]);
+ list_for_each_entry_safe(connector, ct,
+ &dev->mode_config.connector_list, head) {
+ if (!connector->encoder_ids[0]) {
+ NV_WARN(dev, "%s has no encoders, removing\n",
+ drm_get_connector_name(connector));
+ connector->funcs->destroy(connector);
+ }
}
ret = nv50_display_init(dev);
@@ -538,7 +543,8 @@ int nv50_display_create(struct drm_device *dev)
return 0;
}
-int nv50_display_destroy(struct drm_device *dev)
+void
+nv50_display_destroy(struct drm_device *dev)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
@@ -548,135 +554,30 @@ int nv50_display_destroy(struct drm_device *dev)
nv50_display_disable(dev);
nv50_evo_channel_del(&dev_priv->evo);
-
- return 0;
-}
-
-static inline uint32_t
-nv50_display_mode_ctrl(struct drm_device *dev, bool sor, int or)
-{
- struct drm_nouveau_private *dev_priv = dev->dev_private;
- uint32_t mc;
-
- if (sor) {
- if (dev_priv->chipset < 0x90 ||
- dev_priv->chipset == 0x92 || dev_priv->chipset == 0xa0)
- mc = nv_rd32(dev, NV50_PDISPLAY_SOR_MODE_CTRL_P(or));
- else
- mc = nv_rd32(dev, NV90_PDISPLAY_SOR_MODE_CTRL_P(or));
- } else {
- mc = nv_rd32(dev, NV50_PDISPLAY_DAC_MODE_CTRL_P(or));
- }
-
- return mc;
-}
-
-static int
-nv50_display_irq_head(struct drm_device *dev, int *phead,
- struct dcb_entry **pdcbent)
-{
- struct drm_nouveau_private *dev_priv = dev->dev_private;
- uint32_t unk30 = nv_rd32(dev, NV50_PDISPLAY_UNK30_CTRL);
- uint32_t dac = 0, sor = 0;
- int head, i, or = 0, type = OUTPUT_ANY;
-
- /* We're assuming that head 0 *or* head 1 will be active here,
- * and not both. I'm not sure if the hw will even signal both
- * ever, but it definitely shouldn't for us as we commit each
- * CRTC separately, and submission will be blocked by the GPU
- * until we handle each in turn.
- */
- NV_DEBUG_KMS(dev, "0x610030: 0x%08x\n", unk30);
- head = ffs((unk30 >> 9) & 3) - 1;
- if (head < 0)
- return -EINVAL;
-
- /* This assumes CRTCs are never bound to multiple encoders, which
- * should be the case.
- */
- for (i = 0; i < 3 && type == OUTPUT_ANY; i++) {
- uint32_t mc = nv50_display_mode_ctrl(dev, false, i);
- if (!(mc & (1 << head)))
- continue;
-
- switch ((mc >> 8) & 0xf) {
- case 0: type = OUTPUT_ANALOG; break;
- case 1: type = OUTPUT_TV; break;
- default:
- NV_ERROR(dev, "unknown dac mode_ctrl: 0x%08x\n", dac);
- return -1;
- }
-
- or = i;
- }
-
- for (i = 0; i < 4 && type == OUTPUT_ANY; i++) {
- uint32_t mc = nv50_display_mode_ctrl(dev, true, i);
- if (!(mc & (1 << head)))
- continue;
-
- switch ((mc >> 8) & 0xf) {
- case 0: type = OUTPUT_LVDS; break;
- case 1: type = OUTPUT_TMDS; break;
- case 2: type = OUTPUT_TMDS; break;
- case 5: type = OUTPUT_TMDS; break;
- case 8: type = OUTPUT_DP; break;
- case 9: type = OUTPUT_DP; break;
- default:
- NV_ERROR(dev, "unknown sor mode_ctrl: 0x%08x\n", sor);
- return -1;
- }
-
- or = i;
- }
-
- NV_DEBUG_KMS(dev, "type %d, or %d\n", type, or);
- if (type == OUTPUT_ANY) {
- NV_ERROR(dev, "unknown encoder!!\n");
- return -1;
- }
-
- for (i = 0; i < dev_priv->vbios.dcb.entries; i++) {
- struct dcb_entry *dcbent = &dev_priv->vbios.dcb.entry[i];
-
- if (dcbent->type != type)
- continue;
-
- if (!(dcbent->or & (1 << or)))
- continue;
-
- *phead = head;
- *pdcbent = dcbent;
- return 0;
- }
-
- NV_ERROR(dev, "no DCB entry for %d %d\n", dac != 0, or);
- return 0;
}
-static uint32_t
-nv50_display_script_select(struct drm_device *dev, struct dcb_entry *dcbent,
- int pxclk)
+static u16
+nv50_display_script_select(struct drm_device *dev, struct dcb_entry *dcb,
+ u32 mc, int pxclk)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_connector *nv_connector = NULL;
struct drm_encoder *encoder;
struct nvbios *bios = &dev_priv->vbios;
- uint32_t mc, script = 0, or;
+ u32 script = 0, or;
list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
- if (nv_encoder->dcb != dcbent)
+ if (nv_encoder->dcb != dcb)
continue;
nv_connector = nouveau_encoder_connector_get(nv_encoder);
break;
}
- or = ffs(dcbent->or) - 1;
- mc = nv50_display_mode_ctrl(dev, dcbent->type != OUTPUT_ANALOG, or);
- switch (dcbent->type) {
+ or = ffs(dcb->or) - 1;
+ switch (dcb->type) {
case OUTPUT_LVDS:
script = (mc >> 8) & 0xf;
if (bios->fp_no_ddc) {
@@ -767,17 +668,88 @@ nv50_display_vblank_handler(struct drm_device *dev, uint32_t intr)
static void
nv50_display_unk10_handler(struct drm_device *dev)
{
- struct dcb_entry *dcbent;
- int head, ret;
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ u32 unk30 = nv_rd32(dev, 0x610030), mc;
+ int i, crtc, or, type = OUTPUT_ANY;
- ret = nv50_display_irq_head(dev, &head, &dcbent);
- if (ret)
- goto ack;
+ NV_DEBUG_KMS(dev, "0x610030: 0x%08x\n", unk30);
+ dev_priv->evo_irq.dcb = NULL;
nv_wr32(dev, 0x619494, nv_rd32(dev, 0x619494) & ~8);
- nouveau_bios_run_display_table(dev, dcbent, 0, -1);
+ /* Determine which CRTC we're dealing with, only 1 ever will be
+ * signalled at the same time with the current nouveau code.
+ */
+ crtc = ffs((unk30 & 0x00000060) >> 5) - 1;
+ if (crtc < 0)
+ goto ack;
+
+ /* Nothing needs to be done for the encoder */
+ crtc = ffs((unk30 & 0x00000180) >> 7) - 1;
+ if (crtc < 0)
+ goto ack;
+ /* Find which encoder was connected to the CRTC */
+ for (i = 0; type == OUTPUT_ANY && i < 3; i++) {
+ mc = nv_rd32(dev, NV50_PDISPLAY_DAC_MODE_CTRL_C(i));
+ NV_DEBUG_KMS(dev, "DAC-%d mc: 0x%08x\n", i, mc);
+ if (!(mc & (1 << crtc)))
+ continue;
+
+ switch ((mc & 0x00000f00) >> 8) {
+ case 0: type = OUTPUT_ANALOG; break;
+ case 1: type = OUTPUT_TV; break;
+ default:
+ NV_ERROR(dev, "invalid mc, DAC-%d: 0x%08x\n", i, mc);
+ goto ack;
+ }
+
+ or = i;
+ }
+
+ for (i = 0; type == OUTPUT_ANY && i < 4; i++) {
+ if (dev_priv->chipset < 0x90 ||
+ dev_priv->chipset == 0x92 ||
+ dev_priv->chipset == 0xa0)
+ mc = nv_rd32(dev, NV50_PDISPLAY_SOR_MODE_CTRL_C(i));
+ else
+ mc = nv_rd32(dev, NV90_PDISPLAY_SOR_MODE_CTRL_C(i));
+
+ NV_DEBUG_KMS(dev, "SOR-%d mc: 0x%08x\n", i, mc);
+ if (!(mc & (1 << crtc)))
+ continue;
+
+ switch ((mc & 0x00000f00) >> 8) {
+ case 0: type = OUTPUT_LVDS; break;
+ case 1: type = OUTPUT_TMDS; break;
+ case 2: type = OUTPUT_TMDS; break;
+ case 5: type = OUTPUT_TMDS; break;
+ case 8: type = OUTPUT_DP; break;
+ case 9: type = OUTPUT_DP; break;
+ default:
+ NV_ERROR(dev, "invalid mc, SOR-%d: 0x%08x\n", i, mc);
+ goto ack;
+ }
+
+ or = i;
+ }
+
+ /* There was no encoder to disable */
+ if (type == OUTPUT_ANY)
+ goto ack;
+
+ /* Disable the encoder */
+ for (i = 0; i < dev_priv->vbios.dcb.entries; i++) {
+ struct dcb_entry *dcb = &dev_priv->vbios.dcb.entry[i];
+
+ if (dcb->type == type && (dcb->or & (1 << or))) {
+ nouveau_bios_run_display_table(dev, dcb, 0, -1);
+ dev_priv->evo_irq.dcb = dcb;
+ goto ack;
+ }
+ }
+
+ NV_ERROR(dev, "no dcb for %d %d 0x%08x\n", or, type, mc);
ack:
nv_wr32(dev, NV50_PDISPLAY_INTR_1, NV50_PDISPLAY_INTR_1_CLK_UNK10);
nv_wr32(dev, 0x610030, 0x80000000);
@@ -817,33 +789,103 @@ nv50_display_unk20_dp_hack(struct drm_device *dev, struct dcb_entry *dcb)
static void
nv50_display_unk20_handler(struct drm_device *dev)
{
- struct dcb_entry *dcbent;
- uint32_t tmp, pclk, script;
- int head, or, ret;
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ u32 unk30 = nv_rd32(dev, 0x610030), tmp, pclk, script, mc;
+ struct dcb_entry *dcb;
+ int i, crtc, or, type = OUTPUT_ANY;
- ret = nv50_display_irq_head(dev, &head, &dcbent);
- if (ret)
+ NV_DEBUG_KMS(dev, "0x610030: 0x%08x\n", unk30);
+ dcb = dev_priv->evo_irq.dcb;
+ if (dcb) {
+ nouveau_bios_run_display_table(dev, dcb, 0, -2);
+ dev_priv->evo_irq.dcb = NULL;
+ }
+
+ /* CRTC clock change requested? */
+ crtc = ffs((unk30 & 0x00000600) >> 9) - 1;
+ if (crtc >= 0) {
+ pclk = nv_rd32(dev, NV50_PDISPLAY_CRTC_P(crtc, CLOCK));
+ pclk &= 0x003fffff;
+
+ nv50_crtc_set_clock(dev, crtc, pclk);
+
+ tmp = nv_rd32(dev, NV50_PDISPLAY_CRTC_CLK_CTRL2(crtc));
+ tmp &= ~0x000000f;
+ nv_wr32(dev, NV50_PDISPLAY_CRTC_CLK_CTRL2(crtc), tmp);
+ }
+
+ /* Nothing needs to be done for the encoder */
+ crtc = ffs((unk30 & 0x00000180) >> 7) - 1;
+ if (crtc < 0)
goto ack;
- or = ffs(dcbent->or) - 1;
- pclk = nv_rd32(dev, NV50_PDISPLAY_CRTC_P(head, CLOCK)) & 0x3fffff;
- script = nv50_display_script_select(dev, dcbent, pclk);
+ pclk = nv_rd32(dev, NV50_PDISPLAY_CRTC_P(crtc, CLOCK)) & 0x003fffff;
- NV_DEBUG_KMS(dev, "head %d pxclk: %dKHz\n", head, pclk);
+ /* Find which encoder is connected to the CRTC */
+ for (i = 0; type == OUTPUT_ANY && i < 3; i++) {
+ mc = nv_rd32(dev, NV50_PDISPLAY_DAC_MODE_CTRL_P(i));
+ NV_DEBUG_KMS(dev, "DAC-%d mc: 0x%08x\n", i, mc);
+ if (!(mc & (1 << crtc)))
+ continue;
- if (dcbent->type != OUTPUT_DP)
- nouveau_bios_run_display_table(dev, dcbent, 0, -2);
+ switch ((mc & 0x00000f00) >> 8) {
+ case 0: type = OUTPUT_ANALOG; break;
+ case 1: type = OUTPUT_TV; break;
+ default:
+ NV_ERROR(dev, "invalid mc, DAC-%d: 0x%08x\n", i, mc);
+ goto ack;
+ }
- nv50_crtc_set_clock(dev, head, pclk);
+ or = i;
+ }
- nouveau_bios_run_display_table(dev, dcbent, script, pclk);
+ for (i = 0; type == OUTPUT_ANY && i < 4; i++) {
+ if (dev_priv->chipset < 0x90 ||
+ dev_priv->chipset == 0x92 ||
+ dev_priv->chipset == 0xa0)
+ mc = nv_rd32(dev, NV50_PDISPLAY_SOR_MODE_CTRL_P(i));
+ else
+ mc = nv_rd32(dev, NV90_PDISPLAY_SOR_MODE_CTRL_P(i));
- nv50_display_unk20_dp_hack(dev, dcbent);
+ NV_DEBUG_KMS(dev, "SOR-%d mc: 0x%08x\n", i, mc);
+ if (!(mc & (1 << crtc)))
+ continue;
+
+ switch ((mc & 0x00000f00) >> 8) {
+ case 0: type = OUTPUT_LVDS; break;
+ case 1: type = OUTPUT_TMDS; break;
+ case 2: type = OUTPUT_TMDS; break;
+ case 5: type = OUTPUT_TMDS; break;
+ case 8: type = OUTPUT_DP; break;
+ case 9: type = OUTPUT_DP; break;
+ default:
+ NV_ERROR(dev, "invalid mc, SOR-%d: 0x%08x\n", i, mc);
+ goto ack;
+ }
+
+ or = i;
+ }
+
+ if (type == OUTPUT_ANY)
+ goto ack;
+
+ /* Enable the encoder */
+ for (i = 0; i < dev_priv->vbios.dcb.entries; i++) {
+ dcb = &dev_priv->vbios.dcb.entry[i];
+ if (dcb->type == type && (dcb->or & (1 << or)))
+ break;
+ }
+
+ if (i == dev_priv->vbios.dcb.entries) {
+ NV_ERROR(dev, "no dcb for %d %d 0x%08x\n", or, type, mc);
+ goto ack;
+ }
- tmp = nv_rd32(dev, NV50_PDISPLAY_CRTC_CLK_CTRL2(head));
- tmp &= ~0x000000f;
- nv_wr32(dev, NV50_PDISPLAY_CRTC_CLK_CTRL2(head), tmp);
+ script = nv50_display_script_select(dev, dcb, mc, pclk);
+ nouveau_bios_run_display_table(dev, dcb, script, pclk);
- if (dcbent->type != OUTPUT_ANALOG) {
+ nv50_display_unk20_dp_hack(dev, dcb);
+
+ if (dcb->type != OUTPUT_ANALOG) {
tmp = nv_rd32(dev, NV50_PDISPLAY_SOR_CLK_CTRL2(or));
tmp &= ~0x00000f0f;
if (script & 0x0100)
@@ -853,24 +895,61 @@ nv50_display_unk20_handler(struct drm_device *dev)
nv_wr32(dev, NV50_PDISPLAY_DAC_CLK_CTRL2(or), 0);
}
+ dev_priv->evo_irq.dcb = dcb;
+ dev_priv->evo_irq.pclk = pclk;
+ dev_priv->evo_irq.script = script;
+
ack:
nv_wr32(dev, NV50_PDISPLAY_INTR_1, NV50_PDISPLAY_INTR_1_CLK_UNK20);
nv_wr32(dev, 0x610030, 0x80000000);
}
+/* If programming a TMDS output on a SOR that can also be configured for
+ * DisplayPort, make sure NV50_SOR_DP_CTRL_ENABLE is forced off.
+ *
+ * It looks like the VBIOS TMDS scripts make an attempt at this, however,
+ * the VBIOS scripts on at least one board I have only switch it off on
+ * link 0, causing a blank display if the output has previously been
+ * programmed for DisplayPort.
+ */
+static void
+nv50_display_unk40_dp_set_tmds(struct drm_device *dev, struct dcb_entry *dcb)
+{
+ int or = ffs(dcb->or) - 1, link = !(dcb->dpconf.sor.link & 1);
+ struct drm_encoder *encoder;
+ u32 tmp;
+
+ if (dcb->type != OUTPUT_TMDS)
+ return;
+
+ list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
+ struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
+
+ if (nv_encoder->dcb->type == OUTPUT_DP &&
+ nv_encoder->dcb->or & (1 << or)) {
+ tmp = nv_rd32(dev, NV50_SOR_DP_CTRL(or, link));
+ tmp &= ~NV50_SOR_DP_CTRL_ENABLED;
+ nv_wr32(dev, NV50_SOR_DP_CTRL(or, link), tmp);
+ break;
+ }
+ }
+}
+
static void
nv50_display_unk40_handler(struct drm_device *dev)
{
- struct dcb_entry *dcbent;
- int head, pclk, script, ret;
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct dcb_entry *dcb = dev_priv->evo_irq.dcb;
+ u16 script = dev_priv->evo_irq.script;
+ u32 unk30 = nv_rd32(dev, 0x610030), pclk = dev_priv->evo_irq.pclk;
- ret = nv50_display_irq_head(dev, &head, &dcbent);
- if (ret)
+ NV_DEBUG_KMS(dev, "0x610030: 0x%08x\n", unk30);
+ dev_priv->evo_irq.dcb = NULL;
+ if (!dcb)
goto ack;
- pclk = nv_rd32(dev, NV50_PDISPLAY_CRTC_P(head, CLOCK)) & 0x3fffff;
- script = nv50_display_script_select(dev, dcbent, pclk);
- nouveau_bios_run_display_table(dev, dcbent, script, -pclk);
+ nouveau_bios_run_display_table(dev, dcb, script, -pclk);
+ nv50_display_unk40_dp_set_tmds(dev, dcb);
ack:
nv_wr32(dev, NV50_PDISPLAY_INTR_1, NV50_PDISPLAY_INTR_1_CLK_UNK40);
diff --git a/drivers/gpu/drm/nouveau/nv50_display.h b/drivers/gpu/drm/nouveau/nv50_display.h
index 581d405ac01..c551f0b85ee 100644
--- a/drivers/gpu/drm/nouveau/nv50_display.h
+++ b/drivers/gpu/drm/nouveau/nv50_display.h
@@ -38,9 +38,11 @@
void nv50_display_irq_handler(struct drm_device *dev);
void nv50_display_irq_handler_bh(struct work_struct *work);
void nv50_display_irq_hotplug_bh(struct work_struct *work);
-int nv50_display_init(struct drm_device *dev);
+int nv50_display_early_init(struct drm_device *dev);
+void nv50_display_late_takedown(struct drm_device *dev);
int nv50_display_create(struct drm_device *dev);
-int nv50_display_destroy(struct drm_device *dev);
+int nv50_display_init(struct drm_device *dev);
+void nv50_display_destroy(struct drm_device *dev);
int nv50_crtc_blank(struct nouveau_crtc *, bool blank);
int nv50_crtc_set_clock(struct drm_device *, int head, int pclk);
diff --git a/drivers/gpu/drm/nouveau/nv50_fifo.c b/drivers/gpu/drm/nouveau/nv50_fifo.c
index e20c0e2474f..fb0281ae8f9 100644
--- a/drivers/gpu/drm/nouveau/nv50_fifo.c
+++ b/drivers/gpu/drm/nouveau/nv50_fifo.c
@@ -28,41 +28,33 @@
#include "drm.h"
#include "nouveau_drv.h"
-struct nv50_fifo_priv {
- struct nouveau_gpuobj_ref *thingo[2];
- int cur_thingo;
-};
-
-#define IS_G80 ((dev_priv->chipset & 0xf0) == 0x50)
-
static void
-nv50_fifo_init_thingo(struct drm_device *dev)
+nv50_fifo_playlist_update(struct drm_device *dev)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nv50_fifo_priv *priv = dev_priv->engine.fifo.priv;
+ struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo;
struct nouveau_gpuobj_ref *cur;
int i, nr;
NV_DEBUG(dev, "\n");
- cur = priv->thingo[priv->cur_thingo];
- priv->cur_thingo = !priv->cur_thingo;
+ cur = pfifo->playlist[pfifo->cur_playlist];
+ pfifo->cur_playlist = !pfifo->cur_playlist;
/* We never schedule channel 0 or 127 */
- dev_priv->engine.instmem.prepare_access(dev, true);
for (i = 1, nr = 0; i < 127; i++) {
if (dev_priv->fifos[i] && dev_priv->fifos[i]->ramfc)
nv_wo32(dev, cur->gpuobj, nr++, i);
}
- dev_priv->engine.instmem.finish_access(dev);
+ dev_priv->engine.instmem.flush(dev);
nv_wr32(dev, 0x32f4, cur->instance >> 12);
nv_wr32(dev, 0x32ec, nr);
nv_wr32(dev, 0x2500, 0x101);
}
-static int
-nv50_fifo_channel_enable(struct drm_device *dev, int channel, bool nt)
+static void
+nv50_fifo_channel_enable(struct drm_device *dev, int channel)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_channel *chan = dev_priv->fifos[channel];
@@ -70,37 +62,28 @@ nv50_fifo_channel_enable(struct drm_device *dev, int channel, bool nt)
NV_DEBUG(dev, "ch%d\n", channel);
- if (!chan->ramfc)
- return -EINVAL;
-
- if (IS_G80)
+ if (dev_priv->chipset == 0x50)
inst = chan->ramfc->instance >> 12;
else
inst = chan->ramfc->instance >> 8;
- nv_wr32(dev, NV50_PFIFO_CTX_TABLE(channel),
- inst | NV50_PFIFO_CTX_TABLE_CHANNEL_ENABLED);
- if (!nt)
- nv50_fifo_init_thingo(dev);
- return 0;
+ nv_wr32(dev, NV50_PFIFO_CTX_TABLE(channel), inst |
+ NV50_PFIFO_CTX_TABLE_CHANNEL_ENABLED);
}
static void
-nv50_fifo_channel_disable(struct drm_device *dev, int channel, bool nt)
+nv50_fifo_channel_disable(struct drm_device *dev, int channel)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
uint32_t inst;
- NV_DEBUG(dev, "ch%d, nt=%d\n", channel, nt);
+ NV_DEBUG(dev, "ch%d\n", channel);
- if (IS_G80)
+ if (dev_priv->chipset == 0x50)
inst = NV50_PFIFO_CTX_TABLE_INSTANCE_MASK_G80;
else
inst = NV50_PFIFO_CTX_TABLE_INSTANCE_MASK_G84;
nv_wr32(dev, NV50_PFIFO_CTX_TABLE(channel), inst);
-
- if (!nt)
- nv50_fifo_init_thingo(dev);
}
static void
@@ -133,12 +116,12 @@ nv50_fifo_init_context_table(struct drm_device *dev)
for (i = 0; i < NV50_PFIFO_CTX_TABLE__SIZE; i++) {
if (dev_priv->fifos[i])
- nv50_fifo_channel_enable(dev, i, true);
+ nv50_fifo_channel_enable(dev, i);
else
- nv50_fifo_channel_disable(dev, i, true);
+ nv50_fifo_channel_disable(dev, i);
}
- nv50_fifo_init_thingo(dev);
+ nv50_fifo_playlist_update(dev);
}
static void
@@ -162,41 +145,38 @@ nv50_fifo_init_regs(struct drm_device *dev)
nv_wr32(dev, 0x3270, 0);
/* Enable dummy channels setup by nv50_instmem.c */
- nv50_fifo_channel_enable(dev, 0, true);
- nv50_fifo_channel_enable(dev, 127, true);
+ nv50_fifo_channel_enable(dev, 0);
+ nv50_fifo_channel_enable(dev, 127);
}
int
nv50_fifo_init(struct drm_device *dev)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nv50_fifo_priv *priv;
+ struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo;
int ret;
NV_DEBUG(dev, "\n");
- priv = dev_priv->engine.fifo.priv;
- if (priv) {
- priv->cur_thingo = !priv->cur_thingo;
+ if (pfifo->playlist[0]) {
+ pfifo->cur_playlist = !pfifo->cur_playlist;
goto just_reset;
}
- priv = kzalloc(sizeof(*priv), GFP_KERNEL);
- if (!priv)
- return -ENOMEM;
- dev_priv->engine.fifo.priv = priv;
-
ret = nouveau_gpuobj_new_ref(dev, NULL, NULL, 0, 128*4, 0x1000,
- NVOBJ_FLAG_ZERO_ALLOC, &priv->thingo[0]);
+ NVOBJ_FLAG_ZERO_ALLOC,
+ &pfifo->playlist[0]);
if (ret) {
- NV_ERROR(dev, "error creating thingo0: %d\n", ret);
+ NV_ERROR(dev, "error creating playlist 0: %d\n", ret);
return ret;
}
ret = nouveau_gpuobj_new_ref(dev, NULL, NULL, 0, 128*4, 0x1000,
- NVOBJ_FLAG_ZERO_ALLOC, &priv->thingo[1]);
+ NVOBJ_FLAG_ZERO_ALLOC,
+ &pfifo->playlist[1]);
if (ret) {
- NV_ERROR(dev, "error creating thingo1: %d\n", ret);
+ nouveau_gpuobj_ref_del(dev, &pfifo->playlist[0]);
+ NV_ERROR(dev, "error creating playlist 1: %d\n", ret);
return ret;
}
@@ -216,18 +196,15 @@ void
nv50_fifo_takedown(struct drm_device *dev)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nv50_fifo_priv *priv = dev_priv->engine.fifo.priv;
+ struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo;
NV_DEBUG(dev, "\n");
- if (!priv)
+ if (!pfifo->playlist[0])
return;
- nouveau_gpuobj_ref_del(dev, &priv->thingo[0]);
- nouveau_gpuobj_ref_del(dev, &priv->thingo[1]);
-
- dev_priv->engine.fifo.priv = NULL;
- kfree(priv);
+ nouveau_gpuobj_ref_del(dev, &pfifo->playlist[0]);
+ nouveau_gpuobj_ref_del(dev, &pfifo->playlist[1]);
}
int
@@ -248,7 +225,7 @@ nv50_fifo_create_context(struct nouveau_channel *chan)
NV_DEBUG(dev, "ch%d\n", chan->id);
- if (IS_G80) {
+ if (dev_priv->chipset == 0x50) {
uint32_t ramin_poffset = chan->ramin->gpuobj->im_pramin->start;
uint32_t ramin_voffset = chan->ramin->gpuobj->im_backing_start;
@@ -281,10 +258,10 @@ nv50_fifo_create_context(struct nouveau_channel *chan)
spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
- dev_priv->engine.instmem.prepare_access(dev, true);
-
nv_wo32(dev, ramfc, 0x48/4, chan->pushbuf->instance >> 4);
- nv_wo32(dev, ramfc, 0x80/4, (0xc << 24) | (chan->ramht->instance >> 4));
+ nv_wo32(dev, ramfc, 0x80/4, (0 << 27) /* 4KiB */ |
+ (4 << 24) /* SEARCH_FULL */ |
+ (chan->ramht->instance >> 4));
nv_wo32(dev, ramfc, 0x44/4, 0x2101ffff);
nv_wo32(dev, ramfc, 0x60/4, 0x7fffffff);
nv_wo32(dev, ramfc, 0x40/4, 0x00000000);
@@ -295,7 +272,7 @@ nv50_fifo_create_context(struct nouveau_channel *chan)
chan->dma.ib_base * 4);
nv_wo32(dev, ramfc, 0x54/4, drm_order(chan->dma.ib_max + 1) << 16);
- if (!IS_G80) {
+ if (dev_priv->chipset != 0x50) {
nv_wo32(dev, chan->ramin->gpuobj, 0, chan->id);
nv_wo32(dev, chan->ramin->gpuobj, 1,
chan->ramfc->instance >> 8);
@@ -304,16 +281,10 @@ nv50_fifo_create_context(struct nouveau_channel *chan)
nv_wo32(dev, ramfc, 0x98/4, chan->ramin->instance >> 12);
}
- dev_priv->engine.instmem.finish_access(dev);
-
- ret = nv50_fifo_channel_enable(dev, chan->id, false);
- if (ret) {
- NV_ERROR(dev, "error enabling ch%d: %d\n", chan->id, ret);
- spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
- nouveau_gpuobj_ref_del(dev, &chan->ramfc);
- return ret;
- }
+ dev_priv->engine.instmem.flush(dev);
+ nv50_fifo_channel_enable(dev, chan->id);
+ nv50_fifo_playlist_update(dev);
spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
return 0;
}
@@ -328,11 +299,12 @@ nv50_fifo_destroy_context(struct nouveau_channel *chan)
/* This will ensure the channel is seen as disabled. */
chan->ramfc = NULL;
- nv50_fifo_channel_disable(dev, chan->id, false);
+ nv50_fifo_channel_disable(dev, chan->id);
/* Dummy channel, also used on ch 127 */
if (chan->id == 0)
- nv50_fifo_channel_disable(dev, 127, false);
+ nv50_fifo_channel_disable(dev, 127);
+ nv50_fifo_playlist_update(dev);
nouveau_gpuobj_ref_del(dev, &ramfc);
nouveau_gpuobj_ref_del(dev, &chan->cache);
@@ -349,8 +321,6 @@ nv50_fifo_load_context(struct nouveau_channel *chan)
NV_DEBUG(dev, "ch%d\n", chan->id);
- dev_priv->engine.instmem.prepare_access(dev, false);
-
nv_wr32(dev, 0x3330, nv_ro32(dev, ramfc, 0x00/4));
nv_wr32(dev, 0x3334, nv_ro32(dev, ramfc, 0x04/4));
nv_wr32(dev, 0x3240, nv_ro32(dev, ramfc, 0x08/4));
@@ -396,7 +366,7 @@ nv50_fifo_load_context(struct nouveau_channel *chan)
nv_wr32(dev, NV03_PFIFO_CACHE1_GET, 0);
/* guessing that all the 0x34xx regs aren't on NV50 */
- if (!IS_G80) {
+ if (dev_priv->chipset != 0x50) {
nv_wr32(dev, 0x340c, nv_ro32(dev, ramfc, 0x88/4));
nv_wr32(dev, 0x3400, nv_ro32(dev, ramfc, 0x8c/4));
nv_wr32(dev, 0x3404, nv_ro32(dev, ramfc, 0x90/4));
@@ -404,8 +374,6 @@ nv50_fifo_load_context(struct nouveau_channel *chan)
nv_wr32(dev, 0x3410, nv_ro32(dev, ramfc, 0x98/4));
}
- dev_priv->engine.instmem.finish_access(dev);
-
nv_wr32(dev, NV03_PFIFO_CACHE1_PUSH1, chan->id | (1<<16));
return 0;
}
@@ -434,8 +402,6 @@ nv50_fifo_unload_context(struct drm_device *dev)
ramfc = chan->ramfc->gpuobj;
cache = chan->cache->gpuobj;
- dev_priv->engine.instmem.prepare_access(dev, true);
-
nv_wo32(dev, ramfc, 0x00/4, nv_rd32(dev, 0x3330));
nv_wo32(dev, ramfc, 0x04/4, nv_rd32(dev, 0x3334));
nv_wo32(dev, ramfc, 0x08/4, nv_rd32(dev, 0x3240));
@@ -482,7 +448,7 @@ nv50_fifo_unload_context(struct drm_device *dev)
}
/* guessing that all the 0x34xx regs aren't on NV50 */
- if (!IS_G80) {
+ if (dev_priv->chipset != 0x50) {
nv_wo32(dev, ramfc, 0x84/4, ptr >> 1);
nv_wo32(dev, ramfc, 0x88/4, nv_rd32(dev, 0x340c));
nv_wo32(dev, ramfc, 0x8c/4, nv_rd32(dev, 0x3400));
@@ -491,7 +457,7 @@ nv50_fifo_unload_context(struct drm_device *dev)
nv_wo32(dev, ramfc, 0x98/4, nv_rd32(dev, 0x3410));
}
- dev_priv->engine.instmem.finish_access(dev);
+ dev_priv->engine.instmem.flush(dev);
/*XXX: probably reload ch127 (NULL) state back too */
nv_wr32(dev, NV03_PFIFO_CACHE1_PUSH1, 127);
diff --git a/drivers/gpu/drm/nouveau/nv50_gpio.c b/drivers/gpu/drm/nouveau/nv50_gpio.c
index bb47ad73726..b2fab2bf3d6 100644
--- a/drivers/gpu/drm/nouveau/nv50_gpio.c
+++ b/drivers/gpu/drm/nouveau/nv50_gpio.c
@@ -74,3 +74,38 @@ nv50_gpio_set(struct drm_device *dev, enum dcb_gpio_tag tag, int state)
nv_wr32(dev, r, v);
return 0;
}
+
+void
+nv50_gpio_irq_enable(struct drm_device *dev, enum dcb_gpio_tag tag, bool on)
+{
+ struct dcb_gpio_entry *gpio;
+ u32 reg, mask;
+
+ gpio = nouveau_bios_gpio_entry(dev, tag);
+ if (!gpio) {
+ NV_ERROR(dev, "gpio tag 0x%02x not found\n", tag);
+ return;
+ }
+
+ reg = gpio->line < 16 ? 0xe050 : 0xe070;
+ mask = 0x00010001 << (gpio->line & 0xf);
+
+ nv_wr32(dev, reg + 4, mask);
+ nv_mask(dev, reg + 0, mask, on ? mask : 0);
+}
+
+int
+nv50_gpio_init(struct drm_device *dev)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+
+ /* disable, and ack any pending gpio interrupts */
+ nv_wr32(dev, 0xe050, 0x00000000);
+ nv_wr32(dev, 0xe054, 0xffffffff);
+ if (dev_priv->chipset >= 0x90) {
+ nv_wr32(dev, 0xe070, 0x00000000);
+ nv_wr32(dev, 0xe074, 0xffffffff);
+ }
+
+ return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/nv50_graph.c b/drivers/gpu/drm/nouveau/nv50_graph.c
index b203d06f601..1413028e158 100644
--- a/drivers/gpu/drm/nouveau/nv50_graph.c
+++ b/drivers/gpu/drm/nouveau/nv50_graph.c
@@ -30,8 +30,6 @@
#include "nouveau_grctx.h"
-#define IS_G80 ((dev_priv->chipset & 0xf0) == 0x50)
-
static void
nv50_graph_init_reset(struct drm_device *dev)
{
@@ -103,37 +101,33 @@ static int
nv50_graph_init_ctxctl(struct drm_device *dev)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nouveau_grctx ctx = {};
+ uint32_t *cp;
+ int i;
NV_DEBUG(dev, "\n");
- if (nouveau_ctxfw) {
- nouveau_grctx_prog_load(dev);
- dev_priv->engine.graph.grctx_size = 0x70000;
+ cp = kmalloc(512 * 4, GFP_KERNEL);
+ if (!cp) {
+ NV_ERROR(dev, "failed to allocate ctxprog\n");
+ dev_priv->engine.graph.accel_blocked = true;
+ return 0;
}
- if (!dev_priv->engine.graph.ctxprog) {
- struct nouveau_grctx ctx = {};
- uint32_t *cp = kmalloc(512 * 4, GFP_KERNEL);
- int i;
- if (!cp) {
- NV_ERROR(dev, "Couldn't alloc ctxprog! Disabling acceleration.\n");
- dev_priv->engine.graph.accel_blocked = true;
- return 0;
- }
- ctx.dev = dev;
- ctx.mode = NOUVEAU_GRCTX_PROG;
- ctx.data = cp;
- ctx.ctxprog_max = 512;
- if (!nv50_grctx_init(&ctx)) {
- dev_priv->engine.graph.grctx_size = ctx.ctxvals_pos * 4;
-
- nv_wr32(dev, NV40_PGRAPH_CTXCTL_UCODE_INDEX, 0);
- for (i = 0; i < ctx.ctxprog_len; i++)
- nv_wr32(dev, NV40_PGRAPH_CTXCTL_UCODE_DATA, cp[i]);
- } else {
- dev_priv->engine.graph.accel_blocked = true;
- }
- kfree(cp);
+
+ ctx.dev = dev;
+ ctx.mode = NOUVEAU_GRCTX_PROG;
+ ctx.data = cp;
+ ctx.ctxprog_max = 512;
+ if (!nv50_grctx_init(&ctx)) {
+ dev_priv->engine.graph.grctx_size = ctx.ctxvals_pos * 4;
+
+ nv_wr32(dev, NV40_PGRAPH_CTXCTL_UCODE_INDEX, 0);
+ for (i = 0; i < ctx.ctxprog_len; i++)
+ nv_wr32(dev, NV40_PGRAPH_CTXCTL_UCODE_DATA, cp[i]);
+ } else {
+ dev_priv->engine.graph.accel_blocked = true;
}
+ kfree(cp);
nv_wr32(dev, 0x400320, 4);
nv_wr32(dev, NV40_PGRAPH_CTXCTL_CUR, 0);
@@ -164,7 +158,6 @@ void
nv50_graph_takedown(struct drm_device *dev)
{
NV_DEBUG(dev, "\n");
- nouveau_grctx_fini(dev);
}
void
@@ -212,8 +205,9 @@ nv50_graph_create_context(struct nouveau_channel *chan)
struct drm_device *dev = chan->dev;
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_gpuobj *ramin = chan->ramin->gpuobj;
- struct nouveau_gpuobj *ctx;
+ struct nouveau_gpuobj *obj;
struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
+ struct nouveau_grctx ctx = {};
int hdr, ret;
NV_DEBUG(dev, "ch%d\n", chan->id);
@@ -223,10 +217,9 @@ nv50_graph_create_context(struct nouveau_channel *chan)
NVOBJ_FLAG_ZERO_FREE, &chan->ramin_grctx);
if (ret)
return ret;
- ctx = chan->ramin_grctx->gpuobj;
+ obj = chan->ramin_grctx->gpuobj;
- hdr = IS_G80 ? 0x200 : 0x20;
- dev_priv->engine.instmem.prepare_access(dev, true);
+ hdr = (dev_priv->chipset == 0x50) ? 0x200 : 0x20;
nv_wo32(dev, ramin, (hdr + 0x00)/4, 0x00190002);
nv_wo32(dev, ramin, (hdr + 0x04)/4, chan->ramin_grctx->instance +
pgraph->grctx_size - 1);
@@ -234,21 +227,15 @@ nv50_graph_create_context(struct nouveau_channel *chan)
nv_wo32(dev, ramin, (hdr + 0x0c)/4, 0);
nv_wo32(dev, ramin, (hdr + 0x10)/4, 0);
nv_wo32(dev, ramin, (hdr + 0x14)/4, 0x00010000);
- dev_priv->engine.instmem.finish_access(dev);
-
- dev_priv->engine.instmem.prepare_access(dev, true);
- if (!pgraph->ctxprog) {
- struct nouveau_grctx ctx = {};
- ctx.dev = chan->dev;
- ctx.mode = NOUVEAU_GRCTX_VALS;
- ctx.data = chan->ramin_grctx->gpuobj;
- nv50_grctx_init(&ctx);
- } else {
- nouveau_grctx_vals_load(dev, ctx);
- }
- nv_wo32(dev, ctx, 0x00000/4, chan->ramin->instance >> 12);
- dev_priv->engine.instmem.finish_access(dev);
+ ctx.dev = chan->dev;
+ ctx.mode = NOUVEAU_GRCTX_VALS;
+ ctx.data = obj;
+ nv50_grctx_init(&ctx);
+
+ nv_wo32(dev, obj, 0x00000/4, chan->ramin->instance >> 12);
+
+ dev_priv->engine.instmem.flush(dev);
return 0;
}
@@ -257,17 +244,16 @@ nv50_graph_destroy_context(struct nouveau_channel *chan)
{
struct drm_device *dev = chan->dev;
struct drm_nouveau_private *dev_priv = dev->dev_private;
- int i, hdr = IS_G80 ? 0x200 : 0x20;
+ int i, hdr = (dev_priv->chipset == 0x50) ? 0x200 : 0x20;
NV_DEBUG(dev, "ch%d\n", chan->id);
if (!chan->ramin || !chan->ramin->gpuobj)
return;
- dev_priv->engine.instmem.prepare_access(dev, true);
for (i = hdr; i < hdr + 24; i += 4)
nv_wo32(dev, chan->ramin->gpuobj, i/4, 0);
- dev_priv->engine.instmem.finish_access(dev);
+ dev_priv->engine.instmem.flush(dev);
nouveau_gpuobj_ref_del(dev, &chan->ramin_grctx);
}
diff --git a/drivers/gpu/drm/nouveau/nv50_instmem.c b/drivers/gpu/drm/nouveau/nv50_instmem.c
index 5f21df31f3a..37c7b48ab24 100644
--- a/drivers/gpu/drm/nouveau/nv50_instmem.c
+++ b/drivers/gpu/drm/nouveau/nv50_instmem.c
@@ -35,8 +35,6 @@ struct nv50_instmem_priv {
struct nouveau_gpuobj_ref *pramin_pt;
struct nouveau_gpuobj_ref *pramin_bar;
struct nouveau_gpuobj_ref *fb_bar;
-
- bool last_access_wr;
};
#define NV50_INSTMEM_PAGE_SHIFT 12
@@ -147,7 +145,7 @@ nv50_instmem_init(struct drm_device *dev)
if (ret)
return ret;
- if (nouveau_mem_init_heap(&chan->ramin_heap, c_base, c_size - c_base))
+ if (drm_mm_init(&chan->ramin_heap, c_base, c_size - c_base))
return -ENOMEM;
/* RAMFC + zero channel's PRAMIN up to start of VM pagedir */
@@ -241,7 +239,7 @@ nv50_instmem_init(struct drm_device *dev)
return ret;
BAR0_WI32(priv->fb_bar->gpuobj, 0x00, 0x7fc00000);
BAR0_WI32(priv->fb_bar->gpuobj, 0x04, 0x40000000 +
- drm_get_resource_len(dev, 1) - 1);
+ pci_resource_len(dev->pdev, 1) - 1);
BAR0_WI32(priv->fb_bar->gpuobj, 0x08, 0x40000000);
BAR0_WI32(priv->fb_bar->gpuobj, 0x0c, 0x00000000);
BAR0_WI32(priv->fb_bar->gpuobj, 0x10, 0x00000000);
@@ -262,23 +260,18 @@ nv50_instmem_init(struct drm_device *dev)
/* Assume that praying isn't enough, check that we can re-read the
* entire fake channel back from the PRAMIN BAR */
- dev_priv->engine.instmem.prepare_access(dev, false);
for (i = 0; i < c_size; i += 4) {
if (nv_rd32(dev, NV_RAMIN + i) != nv_ri32(dev, i)) {
NV_ERROR(dev, "Error reading back PRAMIN at 0x%08x\n",
i);
- dev_priv->engine.instmem.finish_access(dev);
return -EINVAL;
}
}
- dev_priv->engine.instmem.finish_access(dev);
nv_wr32(dev, NV50_PUNK_BAR0_PRAMIN, save_nv001700);
/* Global PRAMIN heap */
- if (nouveau_mem_init_heap(&dev_priv->ramin_heap,
- c_size, dev_priv->ramin_size - c_size)) {
- dev_priv->ramin_heap = NULL;
+ if (drm_mm_init(&dev_priv->ramin_heap, c_size, dev_priv->ramin_size - c_size)) {
NV_ERROR(dev, "Failed to init RAMIN heap\n");
}
@@ -321,7 +314,7 @@ nv50_instmem_takedown(struct drm_device *dev)
nouveau_gpuobj_del(dev, &chan->vm_pd);
nouveau_gpuobj_ref_del(dev, &chan->ramfc);
nouveau_gpuobj_ref_del(dev, &chan->ramin);
- nouveau_mem_takedown(&chan->ramin_heap);
+ drm_mm_takedown(&chan->ramin_heap);
dev_priv->fifos[0] = dev_priv->fifos[127] = NULL;
kfree(chan);
@@ -436,14 +429,14 @@ nv50_instmem_bind(struct drm_device *dev, struct nouveau_gpuobj *gpuobj)
if (!gpuobj->im_backing || !gpuobj->im_pramin || gpuobj->im_bound)
return -EINVAL;
- NV_DEBUG(dev, "st=0x%0llx sz=0x%0llx\n",
+ NV_DEBUG(dev, "st=0x%lx sz=0x%lx\n",
gpuobj->im_pramin->start, gpuobj->im_pramin->size);
pte = (gpuobj->im_pramin->start >> 12) << 1;
pte_end = ((gpuobj->im_pramin->size >> 12) << 1) + pte;
vram = gpuobj->im_backing_start;
- NV_DEBUG(dev, "pramin=0x%llx, pte=%d, pte_end=%d\n",
+ NV_DEBUG(dev, "pramin=0x%lx, pte=%d, pte_end=%d\n",
gpuobj->im_pramin->start, pte, pte_end);
NV_DEBUG(dev, "first vram page: 0x%08x\n", gpuobj->im_backing_start);
@@ -453,27 +446,15 @@ nv50_instmem_bind(struct drm_device *dev, struct nouveau_gpuobj *gpuobj)
vram |= 0x30;
}
- dev_priv->engine.instmem.prepare_access(dev, true);
while (pte < pte_end) {
nv_wo32(dev, pramin_pt, pte++, lower_32_bits(vram));
nv_wo32(dev, pramin_pt, pte++, upper_32_bits(vram));
vram += NV50_INSTMEM_PAGE_SIZE;
}
- dev_priv->engine.instmem.finish_access(dev);
-
- nv_wr32(dev, 0x100c80, 0x00040001);
- if (!nv_wait(0x100c80, 0x00000001, 0x00000000)) {
- NV_ERROR(dev, "timeout: (0x100c80 & 1) == 0 (1)\n");
- NV_ERROR(dev, "0x100c80 = 0x%08x\n", nv_rd32(dev, 0x100c80));
- return -EBUSY;
- }
+ dev_priv->engine.instmem.flush(dev);
- nv_wr32(dev, 0x100c80, 0x00060001);
- if (!nv_wait(0x100c80, 0x00000001, 0x00000000)) {
- NV_ERROR(dev, "timeout: (0x100c80 & 1) == 0 (2)\n");
- NV_ERROR(dev, "0x100c80 = 0x%08x\n", nv_rd32(dev, 0x100c80));
- return -EBUSY;
- }
+ nv50_vm_flush(dev, 4);
+ nv50_vm_flush(dev, 6);
gpuobj->im_bound = 1;
return 0;
@@ -492,36 +473,37 @@ nv50_instmem_unbind(struct drm_device *dev, struct nouveau_gpuobj *gpuobj)
pte = (gpuobj->im_pramin->start >> 12) << 1;
pte_end = ((gpuobj->im_pramin->size >> 12) << 1) + pte;
- dev_priv->engine.instmem.prepare_access(dev, true);
while (pte < pte_end) {
nv_wo32(dev, priv->pramin_pt->gpuobj, pte++, 0x00000000);
nv_wo32(dev, priv->pramin_pt->gpuobj, pte++, 0x00000000);
}
- dev_priv->engine.instmem.finish_access(dev);
+ dev_priv->engine.instmem.flush(dev);
gpuobj->im_bound = 0;
return 0;
}
void
-nv50_instmem_prepare_access(struct drm_device *dev, bool write)
+nv50_instmem_flush(struct drm_device *dev)
{
- struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nv50_instmem_priv *priv = dev_priv->engine.instmem.priv;
-
- priv->last_access_wr = write;
+ nv_wr32(dev, 0x00330c, 0x00000001);
+ if (!nv_wait(0x00330c, 0x00000002, 0x00000000))
+ NV_ERROR(dev, "PRAMIN flush timeout\n");
}
void
-nv50_instmem_finish_access(struct drm_device *dev)
+nv84_instmem_flush(struct drm_device *dev)
{
- struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nv50_instmem_priv *priv = dev_priv->engine.instmem.priv;
+ nv_wr32(dev, 0x070000, 0x00000001);
+ if (!nv_wait(0x070000, 0x00000002, 0x00000000))
+ NV_ERROR(dev, "PRAMIN flush timeout\n");
+}
- if (priv->last_access_wr) {
- nv_wr32(dev, 0x070000, 0x00000001);
- if (!nv_wait(0x070000, 0x00000001, 0x00000000))
- NV_ERROR(dev, "PRAMIN flush timeout\n");
- }
+void
+nv50_vm_flush(struct drm_device *dev, int engine)
+{
+ nv_wr32(dev, 0x100c80, (engine << 16) | 1);
+ if (!nv_wait(0x100c80, 0x00000001, 0x00000000))
+ NV_ERROR(dev, "vm flush timeout: engine %d\n", engine);
}
diff --git a/drivers/gpu/drm/nouveau/nv50_sor.c b/drivers/gpu/drm/nouveau/nv50_sor.c
index 812778db76a..bcd4cf84a7e 100644
--- a/drivers/gpu/drm/nouveau/nv50_sor.c
+++ b/drivers/gpu/drm/nouveau/nv50_sor.c
@@ -37,52 +37,32 @@
#include "nv50_display.h"
static void
-nv50_sor_disconnect(struct nouveau_encoder *nv_encoder)
+nv50_sor_disconnect(struct drm_encoder *encoder)
{
- struct drm_device *dev = to_drm_encoder(nv_encoder)->dev;
+ struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
+ struct drm_device *dev = encoder->dev;
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_channel *evo = dev_priv->evo;
int ret;
+ if (!nv_encoder->crtc)
+ return;
+ nv50_crtc_blank(nouveau_crtc(nv_encoder->crtc), true);
+
NV_DEBUG_KMS(dev, "Disconnecting SOR %d\n", nv_encoder->or);
- ret = RING_SPACE(evo, 2);
+ ret = RING_SPACE(evo, 4);
if (ret) {
NV_ERROR(dev, "no space while disconnecting SOR\n");
return;
}
BEGIN_RING(evo, 0, NV50_EVO_SOR(nv_encoder->or, MODE_CTRL), 1);
- OUT_RING(evo, 0);
-}
-
-static void
-nv50_sor_dp_link_train(struct drm_encoder *encoder)
-{
- struct drm_device *dev = encoder->dev;
- struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
- struct bit_displayport_encoder_table *dpe;
- int dpe_headerlen;
-
- dpe = nouveau_bios_dp_table(dev, nv_encoder->dcb, &dpe_headerlen);
- if (!dpe) {
- NV_ERROR(dev, "SOR-%d: no DP encoder table!\n", nv_encoder->or);
- return;
- }
+ OUT_RING (evo, 0);
+ BEGIN_RING(evo, 0, NV50_EVO_UPDATE, 1);
+ OUT_RING (evo, 0);
- if (dpe->script0) {
- NV_DEBUG_KMS(dev, "SOR-%d: running DP script 0\n", nv_encoder->or);
- nouveau_bios_run_init_table(dev, le16_to_cpu(dpe->script0),
- nv_encoder->dcb);
- }
-
- if (!nouveau_dp_link_train(encoder))
- NV_ERROR(dev, "SOR-%d: link training failed\n", nv_encoder->or);
-
- if (dpe->script1) {
- NV_DEBUG_KMS(dev, "SOR-%d: running DP script 1\n", nv_encoder->or);
- nouveau_bios_run_init_table(dev, le16_to_cpu(dpe->script1),
- nv_encoder->dcb);
- }
+ nv_encoder->crtc = NULL;
+ nv_encoder->last_dpms = DRM_MODE_DPMS_OFF;
}
static void
@@ -94,14 +74,16 @@ nv50_sor_dpms(struct drm_encoder *encoder, int mode)
uint32_t val;
int or = nv_encoder->or;
- NV_DEBUG_KMS(dev, "or %d mode %d\n", or, mode);
+ NV_DEBUG_KMS(dev, "or %d type %d mode %d\n", or, nv_encoder->dcb->type, mode);
nv_encoder->last_dpms = mode;
list_for_each_entry(enc, &dev->mode_config.encoder_list, head) {
struct nouveau_encoder *nvenc = nouveau_encoder(enc);
if (nvenc == nv_encoder ||
- nvenc->disconnect != nv50_sor_disconnect ||
+ (nvenc->dcb->type != OUTPUT_TMDS &&
+ nvenc->dcb->type != OUTPUT_LVDS &&
+ nvenc->dcb->type != OUTPUT_DP) ||
nvenc->dcb->or != nv_encoder->dcb->or)
continue;
@@ -133,8 +115,22 @@ nv50_sor_dpms(struct drm_encoder *encoder, int mode)
nv_rd32(dev, NV50_PDISPLAY_SOR_DPMS_STATE(or)));
}
- if (nv_encoder->dcb->type == OUTPUT_DP && mode == DRM_MODE_DPMS_ON)
- nv50_sor_dp_link_train(encoder);
+ if (nv_encoder->dcb->type == OUTPUT_DP) {
+ struct nouveau_i2c_chan *auxch;
+
+ auxch = nouveau_i2c_find(dev, nv_encoder->dcb->i2c_index);
+ if (!auxch)
+ return;
+
+ if (mode == DRM_MODE_DPMS_ON) {
+ u8 status = DP_SET_POWER_D0;
+ nouveau_dp_auxch(auxch, 8, DP_SET_POWER, &status, 1);
+ nouveau_dp_link_train(encoder);
+ } else {
+ u8 status = DP_SET_POWER_D3;
+ nouveau_dp_auxch(auxch, 8, DP_SET_POWER, &status, 1);
+ }
+ }
}
static void
@@ -196,7 +192,8 @@ nv50_sor_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode,
uint32_t mode_ctl = 0;
int ret;
- NV_DEBUG_KMS(dev, "or %d\n", nv_encoder->or);
+ NV_DEBUG_KMS(dev, "or %d type %d -> crtc %d\n",
+ nv_encoder->or, nv_encoder->dcb->type, crtc->index);
nv50_sor_dpms(encoder, DRM_MODE_DPMS_ON);
@@ -239,6 +236,14 @@ nv50_sor_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode,
}
BEGIN_RING(evo, 0, NV50_EVO_SOR(nv_encoder->or, MODE_CTRL), 1);
OUT_RING(evo, mode_ctl);
+
+ nv_encoder->crtc = encoder->crtc;
+}
+
+static struct drm_crtc *
+nv50_sor_crtc_get(struct drm_encoder *encoder)
+{
+ return nouveau_encoder(encoder)->crtc;
}
static const struct drm_encoder_helper_funcs nv50_sor_helper_funcs = {
@@ -249,7 +254,9 @@ static const struct drm_encoder_helper_funcs nv50_sor_helper_funcs = {
.prepare = nv50_sor_prepare,
.commit = nv50_sor_commit,
.mode_set = nv50_sor_mode_set,
- .detect = NULL
+ .get_crtc = nv50_sor_crtc_get,
+ .detect = NULL,
+ .disable = nv50_sor_disconnect
};
static void
@@ -272,32 +279,22 @@ static const struct drm_encoder_funcs nv50_sor_encoder_funcs = {
};
int
-nv50_sor_create(struct drm_device *dev, struct dcb_entry *entry)
+nv50_sor_create(struct drm_connector *connector, struct dcb_entry *entry)
{
struct nouveau_encoder *nv_encoder = NULL;
+ struct drm_device *dev = connector->dev;
struct drm_encoder *encoder;
- bool dum;
int type;
NV_DEBUG_KMS(dev, "\n");
switch (entry->type) {
case OUTPUT_TMDS:
- NV_INFO(dev, "Detected a TMDS output\n");
+ case OUTPUT_DP:
type = DRM_MODE_ENCODER_TMDS;
break;
case OUTPUT_LVDS:
- NV_INFO(dev, "Detected a LVDS output\n");
type = DRM_MODE_ENCODER_LVDS;
-
- if (nouveau_bios_parse_lvds_table(dev, 0, &dum, &dum)) {
- NV_ERROR(dev, "Failed parsing LVDS table\n");
- return -EINVAL;
- }
- break;
- case OUTPUT_DP:
- NV_INFO(dev, "Detected a DP output\n");
- type = DRM_MODE_ENCODER_TMDS;
break;
default:
return -EINVAL;
@@ -310,8 +307,7 @@ nv50_sor_create(struct drm_device *dev, struct dcb_entry *entry)
nv_encoder->dcb = entry;
nv_encoder->or = ffs(entry->or) - 1;
-
- nv_encoder->disconnect = nv50_sor_disconnect;
+ nv_encoder->last_dpms = DRM_MODE_DPMS_OFF;
drm_encoder_init(dev, encoder, &nv50_sor_encoder_funcs, type);
drm_encoder_helper_add(encoder, &nv50_sor_helper_funcs);
@@ -342,5 +338,6 @@ nv50_sor_create(struct drm_device *dev, struct dcb_entry *entry)
nv_encoder->dp.mc_unknown = 5;
}
+ drm_mode_connector_attach_encoder(connector, encoder);
return 0;
}
diff --git a/drivers/gpu/drm/nouveau/nvreg.h b/drivers/gpu/drm/nouveau/nvreg.h
index 5998c35237b..ad64673ace1 100644
--- a/drivers/gpu/drm/nouveau/nvreg.h
+++ b/drivers/gpu/drm/nouveau/nvreg.h
@@ -147,28 +147,6 @@
# define NV_VIO_GX_DONT_CARE_INDEX 0x07
# define NV_VIO_GX_BIT_MASK_INDEX 0x08
-#define NV_PFB_BOOT_0 0x00100000
-#define NV_PFB_CFG0 0x00100200
-#define NV_PFB_CFG1 0x00100204
-#define NV_PFB_CSTATUS 0x0010020C
-#define NV_PFB_REFCTRL 0x00100210
-# define NV_PFB_REFCTRL_VALID_1 (1 << 31)
-#define NV_PFB_PAD 0x0010021C
-# define NV_PFB_PAD_CKE_NORMAL (1 << 0)
-#define NV_PFB_TILE_NV10 0x00100240
-#define NV_PFB_TILE_SIZE_NV10 0x00100244
-#define NV_PFB_REF 0x001002D0
-# define NV_PFB_REF_CMD_REFRESH (1 << 0)
-#define NV_PFB_PRE 0x001002D4
-# define NV_PFB_PRE_CMD_PRECHARGE (1 << 0)
-#define NV_PFB_CLOSE_PAGE2 0x0010033C
-#define NV_PFB_TILE_NV40 0x00100600
-#define NV_PFB_TILE_SIZE_NV40 0x00100604
-
-#define NV_PEXTDEV_BOOT_0 0x00101000
-# define NV_PEXTDEV_BOOT_0_STRAP_FP_IFACE_12BIT (8 << 12)
-#define NV_PEXTDEV_BOOT_3 0x0010100c
-
#define NV_PCRTC_INTR_0 0x00600100
# define NV_PCRTC_INTR_0_VBLANK (1 << 0)
#define NV_PCRTC_INTR_EN_0 0x00600140
diff --git a/drivers/gpu/drm/r128/r128_cce.c b/drivers/gpu/drm/r128/r128_cce.c
index e671d0e74d4..570e190710b 100644
--- a/drivers/gpu/drm/r128/r128_cce.c
+++ b/drivers/gpu/drm/r128/r128_cce.c
@@ -44,7 +44,7 @@
MODULE_FIRMWARE(FIRMWARE_NAME);
-static int R128_READ_PLL(struct drm_device * dev, int addr)
+static int R128_READ_PLL(struct drm_device *dev, int addr)
{
drm_r128_private_t *dev_priv = dev->dev_private;
@@ -53,7 +53,7 @@ static int R128_READ_PLL(struct drm_device * dev, int addr)
}
#if R128_FIFO_DEBUG
-static void r128_status(drm_r128_private_t * dev_priv)
+static void r128_status(drm_r128_private_t *dev_priv)
{
printk("GUI_STAT = 0x%08x\n",
(unsigned int)R128_READ(R128_GUI_STAT));
@@ -74,7 +74,7 @@ static void r128_status(drm_r128_private_t * dev_priv)
* Engine, FIFO control
*/
-static int r128_do_pixcache_flush(drm_r128_private_t * dev_priv)
+static int r128_do_pixcache_flush(drm_r128_private_t *dev_priv)
{
u32 tmp;
int i;
@@ -83,9 +83,8 @@ static int r128_do_pixcache_flush(drm_r128_private_t * dev_priv)
R128_WRITE(R128_PC_NGUI_CTLSTAT, tmp);
for (i = 0; i < dev_priv->usec_timeout; i++) {
- if (!(R128_READ(R128_PC_NGUI_CTLSTAT) & R128_PC_BUSY)) {
+ if (!(R128_READ(R128_PC_NGUI_CTLSTAT) & R128_PC_BUSY))
return 0;
- }
DRM_UDELAY(1);
}
@@ -95,7 +94,7 @@ static int r128_do_pixcache_flush(drm_r128_private_t * dev_priv)
return -EBUSY;
}
-static int r128_do_wait_for_fifo(drm_r128_private_t * dev_priv, int entries)
+static int r128_do_wait_for_fifo(drm_r128_private_t *dev_priv, int entries)
{
int i;
@@ -112,7 +111,7 @@ static int r128_do_wait_for_fifo(drm_r128_private_t * dev_priv, int entries)
return -EBUSY;
}
-static int r128_do_wait_for_idle(drm_r128_private_t * dev_priv)
+static int r128_do_wait_for_idle(drm_r128_private_t *dev_priv)
{
int i, ret;
@@ -189,7 +188,7 @@ out_release:
* prior to a wait for idle, as it informs the engine that the command
* stream is ending.
*/
-static void r128_do_cce_flush(drm_r128_private_t * dev_priv)
+static void r128_do_cce_flush(drm_r128_private_t *dev_priv)
{
u32 tmp;
@@ -199,7 +198,7 @@ static void r128_do_cce_flush(drm_r128_private_t * dev_priv)
/* Wait for the CCE to go idle.
*/
-int r128_do_cce_idle(drm_r128_private_t * dev_priv)
+int r128_do_cce_idle(drm_r128_private_t *dev_priv)
{
int i;
@@ -225,7 +224,7 @@ int r128_do_cce_idle(drm_r128_private_t * dev_priv)
/* Start the Concurrent Command Engine.
*/
-static void r128_do_cce_start(drm_r128_private_t * dev_priv)
+static void r128_do_cce_start(drm_r128_private_t *dev_priv)
{
r128_do_wait_for_idle(dev_priv);
@@ -242,7 +241,7 @@ static void r128_do_cce_start(drm_r128_private_t * dev_priv)
* commands, so you must wait for the CCE command stream to complete
* before calling this routine.
*/
-static void r128_do_cce_reset(drm_r128_private_t * dev_priv)
+static void r128_do_cce_reset(drm_r128_private_t *dev_priv)
{
R128_WRITE(R128_PM4_BUFFER_DL_WPTR, 0);
R128_WRITE(R128_PM4_BUFFER_DL_RPTR, 0);
@@ -253,7 +252,7 @@ static void r128_do_cce_reset(drm_r128_private_t * dev_priv)
* commands, so you must flush the command stream and wait for the CCE
* to go idle before calling this routine.
*/
-static void r128_do_cce_stop(drm_r128_private_t * dev_priv)
+static void r128_do_cce_stop(drm_r128_private_t *dev_priv)
{
R128_WRITE(R128_PM4_MICRO_CNTL, 0);
R128_WRITE(R128_PM4_BUFFER_CNTL,
@@ -264,7 +263,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(struct drm_device * 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;
@@ -301,8 +300,8 @@ static int r128_do_engine_reset(struct drm_device * dev)
return 0;
}
-static void r128_cce_init_ring_buffer(struct drm_device * dev,
- drm_r128_private_t * dev_priv)
+static void r128_cce_init_ring_buffer(struct drm_device *dev,
+ drm_r128_private_t *dev_priv)
{
u32 ring_start;
u32 tmp;
@@ -340,7 +339,7 @@ static void r128_cce_init_ring_buffer(struct drm_device * dev,
R128_WRITE(R128_BUS_CNTL, tmp);
}
-static int r128_do_init_cce(struct drm_device * 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;
int rc;
@@ -588,7 +587,7 @@ static int r128_do_init_cce(struct drm_device * dev, drm_r128_init_t * init)
return rc;
}
-int r128_do_cleanup_cce(struct drm_device * dev)
+int r128_do_cleanup_cce(struct drm_device *dev)
{
/* Make sure interrupts are disabled here because the uninstall ioctl
@@ -682,9 +681,8 @@ int r128_cce_stop(struct drm_device *dev, void *data, struct drm_file *file_priv
/* Flush any pending CCE commands. This ensures any outstanding
* commands are exectuted by the engine before we turn it off.
*/
- if (stop->flush) {
+ if (stop->flush)
r128_do_cce_flush(dev_priv);
- }
/* If we fail to make the engine go idle, we return an error
* code so that the DRM ioctl wrapper can try again.
@@ -735,9 +733,8 @@ int r128_cce_idle(struct drm_device *dev, void *data, struct drm_file *file_priv
DEV_INIT_TEST_WITH_RETURN(dev_priv);
- if (dev_priv->cce_running) {
+ if (dev_priv->cce_running)
r128_do_cce_flush(dev_priv);
- }
return r128_do_cce_idle(dev_priv);
}
@@ -765,7 +762,7 @@ int r128_fullscreen(struct drm_device *dev, void *data, struct drm_file *file_pr
#define R128_BUFFER_FREE 0
#if 0
-static int r128_freelist_init(struct drm_device * dev)
+static int r128_freelist_init(struct drm_device *dev)
{
struct drm_device_dma *dma = dev->dma;
drm_r128_private_t *dev_priv = dev->dev_private;
@@ -848,7 +845,7 @@ static struct drm_buf *r128_freelist_get(struct drm_device * dev)
return NULL;
}
-void r128_freelist_reset(struct drm_device * dev)
+void r128_freelist_reset(struct drm_device *dev)
{
struct drm_device_dma *dma = dev->dma;
int i;
@@ -864,7 +861,7 @@ void r128_freelist_reset(struct drm_device * dev)
* CCE command submission
*/
-int r128_wait_ring(drm_r128_private_t * dev_priv, int n)
+int r128_wait_ring(drm_r128_private_t *dev_priv, int n)
{
drm_r128_ring_buffer_t *ring = &dev_priv->ring;
int i;
@@ -881,9 +878,9 @@ int r128_wait_ring(drm_r128_private_t * dev_priv, int n)
return -EBUSY;
}
-static int r128_cce_get_buffers(struct drm_device * dev,
+static int r128_cce_get_buffers(struct drm_device *dev,
struct drm_file *file_priv,
- struct drm_dma * d)
+ struct drm_dma *d)
{
int i;
struct drm_buf *buf;
@@ -933,9 +930,8 @@ int r128_cce_buffers(struct drm_device *dev, void *data, struct drm_file *file_p
d->granted_count = 0;
- if (d->request_count) {
+ if (d->request_count)
ret = r128_cce_get_buffers(dev, file_priv, d);
- }
return ret;
}
diff --git a/drivers/gpu/drm/r128/r128_drv.c b/drivers/gpu/drm/r128/r128_drv.c
index b806fdcc717..1e2971f13aa 100644
--- a/drivers/gpu/drm/r128/r128_drv.c
+++ b/drivers/gpu/drm/r128/r128_drv.c
@@ -85,7 +85,7 @@ static struct drm_driver driver = {
.patchlevel = DRIVER_PATCHLEVEL,
};
-int r128_driver_load(struct drm_device * dev, unsigned long flags)
+int r128_driver_load(struct drm_device *dev, unsigned long flags)
{
return drm_vblank_init(dev, 1);
}
diff --git a/drivers/gpu/drm/r128/r128_drv.h b/drivers/gpu/drm/r128/r128_drv.h
index 3c60829d82e..930c71b2fb5 100644
--- a/drivers/gpu/drm/r128/r128_drv.h
+++ b/drivers/gpu/drm/r128/r128_drv.h
@@ -53,7 +53,7 @@
#define DRIVER_MINOR 5
#define DRIVER_PATCHLEVEL 0
-#define GET_RING_HEAD(dev_priv) R128_READ( R128_PM4_BUFFER_DL_RPTR )
+#define GET_RING_HEAD(dev_priv) R128_READ(R128_PM4_BUFFER_DL_RPTR)
typedef struct drm_r128_freelist {
unsigned int age;
@@ -144,23 +144,23 @@ extern int r128_engine_reset(struct drm_device *dev, void *data, struct drm_file
extern int r128_fullscreen(struct drm_device *dev, void *data, struct drm_file *file_priv);
extern int r128_cce_buffers(struct drm_device *dev, void *data, struct drm_file *file_priv);
-extern void r128_freelist_reset(struct drm_device * 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_wait_ring(drm_r128_private_t *dev_priv, int n);
-extern int r128_do_cce_idle(drm_r128_private_t * dev_priv);
-extern int r128_do_cleanup_cce(struct drm_device * dev);
+extern int r128_do_cce_idle(drm_r128_private_t *dev_priv);
+extern int r128_do_cleanup_cce(struct drm_device *dev);
extern int r128_enable_vblank(struct drm_device *dev, int crtc);
extern void r128_disable_vblank(struct drm_device *dev, int crtc);
extern u32 r128_get_vblank_counter(struct drm_device *dev, int crtc);
extern irqreturn_t r128_driver_irq_handler(DRM_IRQ_ARGS);
-extern void r128_driver_irq_preinstall(struct drm_device * dev);
+extern void r128_driver_irq_preinstall(struct drm_device *dev);
extern int r128_driver_irq_postinstall(struct drm_device *dev);
-extern void r128_driver_irq_uninstall(struct drm_device * dev);
-extern void r128_driver_lastclose(struct drm_device * dev);
-extern int r128_driver_load(struct drm_device * dev, unsigned long flags);
-extern void r128_driver_preclose(struct drm_device * dev,
+extern void r128_driver_irq_uninstall(struct drm_device *dev);
+extern void r128_driver_lastclose(struct drm_device *dev);
+extern int r128_driver_load(struct drm_device *dev, unsigned long flags);
+extern void r128_driver_preclose(struct drm_device *dev,
struct drm_file *file_priv);
extern long r128_compat_ioctl(struct file *filp, unsigned int cmd,
@@ -390,27 +390,27 @@ extern long r128_compat_ioctl(struct file *filp, unsigned int cmd,
#define R128_PCIGART_TABLE_SIZE 32768
-#define R128_READ(reg) DRM_READ32( dev_priv->mmio, (reg) )
-#define R128_WRITE(reg,val) DRM_WRITE32( dev_priv->mmio, (reg), (val) )
-#define R128_READ8(reg) DRM_READ8( dev_priv->mmio, (reg) )
-#define R128_WRITE8(reg,val) DRM_WRITE8( dev_priv->mmio, (reg), (val) )
+#define R128_READ(reg) DRM_READ32(dev_priv->mmio, (reg))
+#define R128_WRITE(reg, val) DRM_WRITE32(dev_priv->mmio, (reg), (val))
+#define R128_READ8(reg) DRM_READ8(dev_priv->mmio, (reg))
+#define R128_WRITE8(reg, val) DRM_WRITE8(dev_priv->mmio, (reg), (val))
-#define R128_WRITE_PLL(addr,val) \
+#define R128_WRITE_PLL(addr, val) \
do { \
R128_WRITE8(R128_CLOCK_CNTL_INDEX, \
((addr) & 0x1f) | R128_PLL_WR_EN); \
R128_WRITE(R128_CLOCK_CNTL_DATA, (val)); \
} while (0)
-#define CCE_PACKET0( reg, n ) (R128_CCE_PACKET0 | \
+#define CCE_PACKET0(reg, n) (R128_CCE_PACKET0 | \
((n) << 16) | ((reg) >> 2))
-#define CCE_PACKET1( reg0, reg1 ) (R128_CCE_PACKET1 | \
+#define CCE_PACKET1(reg0, reg1) (R128_CCE_PACKET1 | \
(((reg1) >> 2) << 11) | ((reg0) >> 2))
#define CCE_PACKET2() (R128_CCE_PACKET2)
-#define CCE_PACKET3( pkt, n ) (R128_CCE_PACKET3 | \
+#define CCE_PACKET3(pkt, n) (R128_CCE_PACKET3 | \
(pkt) | ((n) << 16))
-static __inline__ void r128_update_ring_snapshot(drm_r128_private_t * dev_priv)
+static __inline__ void r128_update_ring_snapshot(drm_r128_private_t *dev_priv)
{
drm_r128_ring_buffer_t *ring = &dev_priv->ring;
ring->space = (GET_RING_HEAD(dev_priv) - ring->tail) * sizeof(u32);
@@ -430,37 +430,38 @@ do { \
} \
} while (0)
-#define RING_SPACE_TEST_WITH_RETURN( dev_priv ) \
+#define RING_SPACE_TEST_WITH_RETURN(dev_priv) \
do { \
drm_r128_ring_buffer_t *ring = &dev_priv->ring; int i; \
- if ( ring->space < ring->high_mark ) { \
- for ( i = 0 ; i < dev_priv->usec_timeout ; i++ ) { \
- r128_update_ring_snapshot( dev_priv ); \
- if ( ring->space >= ring->high_mark ) \
+ if (ring->space < ring->high_mark) { \
+ for (i = 0 ; i < dev_priv->usec_timeout ; i++) { \
+ r128_update_ring_snapshot(dev_priv); \
+ if (ring->space >= ring->high_mark) \
goto __ring_space_done; \
- DRM_UDELAY(1); \
+ DRM_UDELAY(1); \
} \
- DRM_ERROR( "ring space check failed!\n" ); \
- return -EBUSY; \
+ DRM_ERROR("ring space check failed!\n"); \
+ return -EBUSY; \
} \
__ring_space_done: \
; \
} while (0)
-#define VB_AGE_TEST_WITH_RETURN( dev_priv ) \
+#define VB_AGE_TEST_WITH_RETURN(dev_priv) \
do { \
drm_r128_sarea_t *sarea_priv = dev_priv->sarea_priv; \
- if ( sarea_priv->last_dispatch >= R128_MAX_VB_AGE ) { \
- int __ret = r128_do_cce_idle( dev_priv ); \
- if ( __ret ) return __ret; \
+ if (sarea_priv->last_dispatch >= R128_MAX_VB_AGE) { \
+ int __ret = r128_do_cce_idle(dev_priv); \
+ if (__ret) \
+ return __ret; \
sarea_priv->last_dispatch = 0; \
- r128_freelist_reset( dev ); \
+ r128_freelist_reset(dev); \
} \
} while (0)
#define R128_WAIT_UNTIL_PAGE_FLIPPED() do { \
- OUT_RING( CCE_PACKET0( R128_WAIT_UNTIL, 0 ) ); \
- OUT_RING( R128_EVENT_CRTC_OFFSET ); \
+ OUT_RING(CCE_PACKET0(R128_WAIT_UNTIL, 0)); \
+ OUT_RING(R128_EVENT_CRTC_OFFSET); \
} while (0)
/* ================================================================
@@ -472,13 +473,12 @@ do { \
#define RING_LOCALS \
int write, _nr; unsigned int tail_mask; volatile u32 *ring;
-#define BEGIN_RING( n ) do { \
- if ( R128_VERBOSE ) { \
- DRM_INFO( "BEGIN_RING( %d )\n", (n)); \
- } \
- if ( dev_priv->ring.space <= (n) * sizeof(u32) ) { \
+#define BEGIN_RING(n) do { \
+ if (R128_VERBOSE) \
+ DRM_INFO("BEGIN_RING(%d)\n", (n)); \
+ if (dev_priv->ring.space <= (n) * sizeof(u32)) { \
COMMIT_RING(); \
- r128_wait_ring( dev_priv, (n) * sizeof(u32) ); \
+ r128_wait_ring(dev_priv, (n) * sizeof(u32)); \
} \
_nr = n; dev_priv->ring.space -= (n) * sizeof(u32); \
ring = dev_priv->ring.start; \
@@ -494,40 +494,36 @@ do { \
#define R128_BROKEN_CCE 1
#define ADVANCE_RING() do { \
- if ( R128_VERBOSE ) { \
- DRM_INFO( "ADVANCE_RING() wr=0x%06x tail=0x%06x\n", \
- write, dev_priv->ring.tail ); \
- } \
- if ( R128_BROKEN_CCE && write < 32 ) { \
- memcpy( dev_priv->ring.end, \
- dev_priv->ring.start, \
- write * sizeof(u32) ); \
- } \
- if (((dev_priv->ring.tail + _nr) & tail_mask) != write) { \
+ if (R128_VERBOSE) \
+ DRM_INFO("ADVANCE_RING() wr=0x%06x tail=0x%06x\n", \
+ write, dev_priv->ring.tail); \
+ if (R128_BROKEN_CCE && write < 32) \
+ memcpy(dev_priv->ring.end, \
+ dev_priv->ring.start, \
+ write * sizeof(u32)); \
+ if (((dev_priv->ring.tail + _nr) & tail_mask) != write) \
DRM_ERROR( \
"ADVANCE_RING(): mismatch: nr: %x write: %x line: %d\n", \
((dev_priv->ring.tail + _nr) & tail_mask), \
write, __LINE__); \
- } else \
+ else \
dev_priv->ring.tail = write; \
} while (0)
#define COMMIT_RING() do { \
- if ( R128_VERBOSE ) { \
- DRM_INFO( "COMMIT_RING() tail=0x%06x\n", \
- dev_priv->ring.tail ); \
- } \
+ if (R128_VERBOSE) \
+ DRM_INFO("COMMIT_RING() tail=0x%06x\n", \
+ dev_priv->ring.tail); \
DRM_MEMORYBARRIER(); \
- R128_WRITE( R128_PM4_BUFFER_DL_WPTR, dev_priv->ring.tail ); \
- R128_READ( R128_PM4_BUFFER_DL_WPTR ); \
+ R128_WRITE(R128_PM4_BUFFER_DL_WPTR, dev_priv->ring.tail); \
+ R128_READ(R128_PM4_BUFFER_DL_WPTR); \
} while (0)
-#define OUT_RING( x ) do { \
- if ( R128_VERBOSE ) { \
- DRM_INFO( " OUT_RING( 0x%08x ) at 0x%x\n", \
- (unsigned int)(x), write ); \
- } \
- ring[write++] = cpu_to_le32( x ); \
+#define OUT_RING(x) do { \
+ if (R128_VERBOSE) \
+ DRM_INFO(" OUT_RING( 0x%08x ) at 0x%x\n", \
+ (unsigned int)(x), write); \
+ ring[write++] = cpu_to_le32(x); \
write &= tail_mask; \
} while (0)
diff --git a/drivers/gpu/drm/r128/r128_irq.c b/drivers/gpu/drm/r128/r128_irq.c
index 69810fb8ac4..429d5a02695 100644
--- a/drivers/gpu/drm/r128/r128_irq.c
+++ b/drivers/gpu/drm/r128/r128_irq.c
@@ -90,7 +90,7 @@ void r128_disable_vblank(struct drm_device *dev, int crtc)
*/
}
-void r128_driver_irq_preinstall(struct drm_device * dev)
+void r128_driver_irq_preinstall(struct drm_device *dev)
{
drm_r128_private_t *dev_priv = (drm_r128_private_t *) dev->dev_private;
@@ -105,7 +105,7 @@ int r128_driver_irq_postinstall(struct drm_device *dev)
return 0;
}
-void r128_driver_irq_uninstall(struct drm_device * 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/gpu/drm/r128/r128_state.c b/drivers/gpu/drm/r128/r128_state.c
index af2665cf471..077af1f2f9b 100644
--- a/drivers/gpu/drm/r128/r128_state.c
+++ b/drivers/gpu/drm/r128/r128_state.c
@@ -37,8 +37,8 @@
* CCE hardware state programming functions
*/
-static void r128_emit_clip_rects(drm_r128_private_t * dev_priv,
- struct drm_clip_rect * boxes, int count)
+static void r128_emit_clip_rects(drm_r128_private_t *dev_priv,
+ struct drm_clip_rect *boxes, int count)
{
u32 aux_sc_cntl = 0x00000000;
RING_LOCALS;
@@ -80,7 +80,7 @@ static void r128_emit_clip_rects(drm_r128_private_t * dev_priv,
ADVANCE_RING();
}
-static __inline__ void r128_emit_core(drm_r128_private_t * dev_priv)
+static __inline__ void r128_emit_core(drm_r128_private_t *dev_priv)
{
drm_r128_sarea_t *sarea_priv = dev_priv->sarea_priv;
drm_r128_context_regs_t *ctx = &sarea_priv->context_state;
@@ -95,7 +95,7 @@ static __inline__ void r128_emit_core(drm_r128_private_t * dev_priv)
ADVANCE_RING();
}
-static __inline__ void r128_emit_context(drm_r128_private_t * dev_priv)
+static __inline__ void r128_emit_context(drm_r128_private_t *dev_priv)
{
drm_r128_sarea_t *sarea_priv = dev_priv->sarea_priv;
drm_r128_context_regs_t *ctx = &sarea_priv->context_state;
@@ -121,7 +121,7 @@ static __inline__ void r128_emit_context(drm_r128_private_t * dev_priv)
ADVANCE_RING();
}
-static __inline__ void r128_emit_setup(drm_r128_private_t * dev_priv)
+static __inline__ void r128_emit_setup(drm_r128_private_t *dev_priv)
{
drm_r128_sarea_t *sarea_priv = dev_priv->sarea_priv;
drm_r128_context_regs_t *ctx = &sarea_priv->context_state;
@@ -137,7 +137,7 @@ static __inline__ void r128_emit_setup(drm_r128_private_t * dev_priv)
ADVANCE_RING();
}
-static __inline__ void r128_emit_masks(drm_r128_private_t * dev_priv)
+static __inline__ void r128_emit_masks(drm_r128_private_t *dev_priv)
{
drm_r128_sarea_t *sarea_priv = dev_priv->sarea_priv;
drm_r128_context_regs_t *ctx = &sarea_priv->context_state;
@@ -156,7 +156,7 @@ static __inline__ void r128_emit_masks(drm_r128_private_t * dev_priv)
ADVANCE_RING();
}
-static __inline__ void r128_emit_window(drm_r128_private_t * dev_priv)
+static __inline__ void r128_emit_window(drm_r128_private_t *dev_priv)
{
drm_r128_sarea_t *sarea_priv = dev_priv->sarea_priv;
drm_r128_context_regs_t *ctx = &sarea_priv->context_state;
@@ -171,7 +171,7 @@ static __inline__ void r128_emit_window(drm_r128_private_t * dev_priv)
ADVANCE_RING();
}
-static __inline__ void r128_emit_tex0(drm_r128_private_t * dev_priv)
+static __inline__ void r128_emit_tex0(drm_r128_private_t *dev_priv)
{
drm_r128_sarea_t *sarea_priv = dev_priv->sarea_priv;
drm_r128_context_regs_t *ctx = &sarea_priv->context_state;
@@ -187,9 +187,8 @@ static __inline__ void r128_emit_tex0(drm_r128_private_t * dev_priv)
OUT_RING(tex->tex_cntl);
OUT_RING(tex->tex_combine_cntl);
OUT_RING(ctx->tex_size_pitch_c);
- for (i = 0; i < R128_MAX_TEXTURE_LEVELS; i++) {
+ for (i = 0; i < R128_MAX_TEXTURE_LEVELS; i++)
OUT_RING(tex->tex_offset[i]);
- }
OUT_RING(CCE_PACKET0(R128_CONSTANT_COLOR_C, 1));
OUT_RING(ctx->constant_color_c);
@@ -198,7 +197,7 @@ static __inline__ void r128_emit_tex0(drm_r128_private_t * dev_priv)
ADVANCE_RING();
}
-static __inline__ void r128_emit_tex1(drm_r128_private_t * dev_priv)
+static __inline__ void r128_emit_tex1(drm_r128_private_t *dev_priv)
{
drm_r128_sarea_t *sarea_priv = dev_priv->sarea_priv;
drm_r128_texture_regs_t *tex = &sarea_priv->tex_state[1];
@@ -211,9 +210,8 @@ static __inline__ void r128_emit_tex1(drm_r128_private_t * dev_priv)
OUT_RING(CCE_PACKET0(R128_SEC_TEX_CNTL_C, 1 + R128_MAX_TEXTURE_LEVELS));
OUT_RING(tex->tex_cntl);
OUT_RING(tex->tex_combine_cntl);
- for (i = 0; i < R128_MAX_TEXTURE_LEVELS; i++) {
+ for (i = 0; i < R128_MAX_TEXTURE_LEVELS; i++)
OUT_RING(tex->tex_offset[i]);
- }
OUT_RING(CCE_PACKET0(R128_SEC_TEXTURE_BORDER_COLOR_C, 0));
OUT_RING(tex->tex_border_color);
@@ -221,7 +219,7 @@ static __inline__ void r128_emit_tex1(drm_r128_private_t * dev_priv)
ADVANCE_RING();
}
-static void r128_emit_state(drm_r128_private_t * dev_priv)
+static void r128_emit_state(drm_r128_private_t *dev_priv)
{
drm_r128_sarea_t *sarea_priv = dev_priv->sarea_priv;
unsigned int dirty = sarea_priv->dirty;
@@ -274,7 +272,7 @@ static void r128_emit_state(drm_r128_private_t * dev_priv)
* Performance monitoring functions
*/
-static void r128_clear_box(drm_r128_private_t * dev_priv,
+static void r128_clear_box(drm_r128_private_t *dev_priv,
int x, int y, int w, int h, int r, int g, int b)
{
u32 pitch, offset;
@@ -321,13 +319,12 @@ static void r128_clear_box(drm_r128_private_t * dev_priv,
ADVANCE_RING();
}
-static void r128_cce_performance_boxes(drm_r128_private_t * dev_priv)
+static void r128_cce_performance_boxes(drm_r128_private_t *dev_priv)
{
- if (atomic_read(&dev_priv->idle_count) == 0) {
+ if (atomic_read(&dev_priv->idle_count) == 0)
r128_clear_box(dev_priv, 64, 4, 8, 8, 0, 255, 0);
- } else {
+ else
atomic_set(&dev_priv->idle_count, 0);
- }
}
#endif
@@ -352,8 +349,8 @@ static void r128_print_dirty(const char *msg, unsigned int flags)
(flags & R128_REQUIRE_QUIESCENCE) ? "quiescence, " : "");
}
-static void r128_cce_dispatch_clear(struct drm_device * dev,
- drm_r128_clear_t * clear)
+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;
@@ -458,7 +455,7 @@ static void r128_cce_dispatch_clear(struct drm_device * dev,
}
}
-static void r128_cce_dispatch_swap(struct drm_device * 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;
@@ -524,7 +521,7 @@ static void r128_cce_dispatch_swap(struct drm_device * dev)
ADVANCE_RING();
}
-static void r128_cce_dispatch_flip(struct drm_device * dev)
+static void r128_cce_dispatch_flip(struct drm_device *dev)
{
drm_r128_private_t *dev_priv = dev->dev_private;
RING_LOCALS;
@@ -542,11 +539,10 @@ static void r128_cce_dispatch_flip(struct drm_device * dev)
R128_WAIT_UNTIL_PAGE_FLIPPED();
OUT_RING(CCE_PACKET0(R128_CRTC_OFFSET, 0));
- if (dev_priv->current_page == 0) {
+ if (dev_priv->current_page == 0)
OUT_RING(dev_priv->back_offset);
- } else {
+ else
OUT_RING(dev_priv->front_offset);
- }
ADVANCE_RING();
@@ -566,7 +562,7 @@ static void r128_cce_dispatch_flip(struct drm_device * dev)
ADVANCE_RING();
}
-static void r128_cce_dispatch_vertex(struct drm_device * dev, struct drm_buf * 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;
@@ -585,9 +581,8 @@ static void r128_cce_dispatch_vertex(struct drm_device * dev, struct drm_buf * b
if (buf->used) {
buf_priv->dispatched = 1;
- if (sarea_priv->dirty & ~R128_UPLOAD_CLIPRECTS) {
+ if (sarea_priv->dirty & ~R128_UPLOAD_CLIPRECTS)
r128_emit_state(dev_priv);
- }
do {
/* Emit the next set of up to three cliprects */
@@ -636,8 +631,8 @@ static void r128_cce_dispatch_vertex(struct drm_device * dev, struct drm_buf * b
sarea_priv->nbox = 0;
}
-static void r128_cce_dispatch_indirect(struct drm_device * dev,
- struct drm_buf * 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;
@@ -691,8 +686,8 @@ static void r128_cce_dispatch_indirect(struct drm_device * dev,
dev_priv->sarea_priv->last_dispatch++;
}
-static void r128_cce_dispatch_indices(struct drm_device * dev,
- struct drm_buf * 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;
@@ -713,9 +708,8 @@ static void r128_cce_dispatch_indices(struct drm_device * dev,
if (start != end) {
buf_priv->dispatched = 1;
- if (sarea_priv->dirty & ~R128_UPLOAD_CLIPRECTS) {
+ if (sarea_priv->dirty & ~R128_UPLOAD_CLIPRECTS)
r128_emit_state(dev_priv);
- }
dwords = (end - start + 3) / sizeof(u32);
@@ -775,9 +769,9 @@ static void r128_cce_dispatch_indices(struct drm_device * dev,
sarea_priv->nbox = 0;
}
-static int r128_cce_dispatch_blit(struct drm_device * dev,
+static int r128_cce_dispatch_blit(struct drm_device *dev,
struct drm_file *file_priv,
- drm_r128_blit_t * blit)
+ drm_r128_blit_t *blit)
{
drm_r128_private_t *dev_priv = dev->dev_private;
struct drm_device_dma *dma = dev->dma;
@@ -887,8 +881,8 @@ static int r128_cce_dispatch_blit(struct drm_device * dev,
* have hardware stencil support.
*/
-static int r128_cce_dispatch_write_span(struct drm_device * dev,
- drm_r128_depth_t * depth)
+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;
int count, x, y;
@@ -902,12 +896,10 @@ static int r128_cce_dispatch_write_span(struct drm_device * dev,
if (count > 4096 || count <= 0)
return -EMSGSIZE;
- if (DRM_COPY_FROM_USER(&x, depth->x, sizeof(x))) {
+ if (DRM_COPY_FROM_USER(&x, depth->x, sizeof(x)))
return -EFAULT;
- }
- if (DRM_COPY_FROM_USER(&y, depth->y, sizeof(y))) {
+ if (DRM_COPY_FROM_USER(&y, depth->y, sizeof(y)))
return -EFAULT;
- }
buffer_size = depth->n * sizeof(u32);
buffer = kmalloc(buffer_size, GFP_KERNEL);
@@ -983,8 +975,8 @@ static int r128_cce_dispatch_write_span(struct drm_device * dev,
return 0;
}
-static int r128_cce_dispatch_write_pixels(struct drm_device * dev,
- drm_r128_depth_t * depth)
+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;
int count, *x, *y;
@@ -1001,9 +993,8 @@ static int r128_cce_dispatch_write_pixels(struct drm_device * dev,
xbuf_size = count * sizeof(*x);
ybuf_size = count * sizeof(*y);
x = kmalloc(xbuf_size, GFP_KERNEL);
- if (x == NULL) {
+ if (x == NULL)
return -ENOMEM;
- }
y = kmalloc(ybuf_size, GFP_KERNEL);
if (y == NULL) {
kfree(x);
@@ -1105,8 +1096,8 @@ static int r128_cce_dispatch_write_pixels(struct drm_device * dev,
return 0;
}
-static int r128_cce_dispatch_read_span(struct drm_device * dev,
- drm_r128_depth_t * depth)
+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;
int count, x, y;
@@ -1117,12 +1108,10 @@ static int r128_cce_dispatch_read_span(struct drm_device * dev,
if (count > 4096 || count <= 0)
return -EMSGSIZE;
- if (DRM_COPY_FROM_USER(&x, depth->x, sizeof(x))) {
+ if (DRM_COPY_FROM_USER(&x, depth->x, sizeof(x)))
return -EFAULT;
- }
- if (DRM_COPY_FROM_USER(&y, depth->y, sizeof(y))) {
+ if (DRM_COPY_FROM_USER(&y, depth->y, sizeof(y)))
return -EFAULT;
- }
BEGIN_RING(7);
@@ -1148,8 +1137,8 @@ static int r128_cce_dispatch_read_span(struct drm_device * dev,
return 0;
}
-static int r128_cce_dispatch_read_pixels(struct drm_device * dev,
- drm_r128_depth_t * depth)
+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;
int count, *x, *y;
@@ -1161,16 +1150,14 @@ static int r128_cce_dispatch_read_pixels(struct drm_device * dev,
if (count > 4096 || count <= 0)
return -EMSGSIZE;
- if (count > dev_priv->depth_pitch) {
+ if (count > dev_priv->depth_pitch)
count = dev_priv->depth_pitch;
- }
xbuf_size = count * sizeof(*x);
ybuf_size = count * sizeof(*y);
x = kmalloc(xbuf_size, GFP_KERNEL);
- if (x == NULL) {
+ if (x == NULL)
return -ENOMEM;
- }
y = kmalloc(ybuf_size, GFP_KERNEL);
if (y == NULL) {
kfree(x);
@@ -1220,7 +1207,7 @@ static int r128_cce_dispatch_read_pixels(struct drm_device * dev,
* Polygon stipple
*/
-static void r128_cce_dispatch_stipple(struct drm_device * 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;
@@ -1230,9 +1217,8 @@ static void r128_cce_dispatch_stipple(struct drm_device * dev, u32 * stipple)
BEGIN_RING(33);
OUT_RING(CCE_PACKET0(R128_BRUSH_DATA0, 31));
- for (i = 0; i < 32; i++) {
+ for (i = 0; i < 32; i++)
OUT_RING(stipple[i]);
- }
ADVANCE_RING();
}
@@ -1269,7 +1255,7 @@ static int r128_cce_clear(struct drm_device *dev, void *data, struct drm_file *f
return 0;
}
-static int r128_do_init_pageflip(struct drm_device * 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 +1274,7 @@ static int r128_do_init_pageflip(struct drm_device * dev)
return 0;
}
-static int r128_do_cleanup_pageflip(struct drm_device * dev)
+static int r128_do_cleanup_pageflip(struct drm_device *dev)
{
drm_r128_private_t *dev_priv = dev->dev_private;
DRM_DEBUG("\n");
@@ -1645,17 +1631,16 @@ static int r128_getparam(struct drm_device *dev, void *data, struct drm_file *fi
return 0;
}
-void r128_driver_preclose(struct drm_device * dev, struct drm_file *file_priv)
+void r128_driver_preclose(struct drm_device *dev, struct drm_file *file_priv)
{
if (dev->dev_private) {
drm_r128_private_t *dev_priv = dev->dev_private;
- if (dev_priv->page_flipping) {
+ if (dev_priv->page_flipping)
r128_do_cleanup_pageflip(dev);
- }
}
}
-void r128_driver_lastclose(struct drm_device * dev)
+void r128_driver_lastclose(struct drm_device *dev)
{
r128_do_cleanup_cce(dev);
}
diff --git a/drivers/gpu/drm/radeon/Makefile b/drivers/gpu/drm/radeon/Makefile
index 84b1f2729d4..aebe0087504 100644
--- a/drivers/gpu/drm/radeon/Makefile
+++ b/drivers/gpu/drm/radeon/Makefile
@@ -69,5 +69,6 @@ radeon-y += radeon_device.o radeon_asic.o radeon_kms.o \
radeon-$(CONFIG_COMPAT) += radeon_ioc32.o
radeon-$(CONFIG_VGA_SWITCHEROO) += radeon_atpx_handler.o
+radeon-$(CONFIG_ACPI) += radeon_acpi.o
obj-$(CONFIG_DRM_RADEON)+= radeon.o
diff --git a/drivers/gpu/drm/radeon/atom.c b/drivers/gpu/drm/radeon/atom.c
index 1d569830ed9..8e421f644a5 100644
--- a/drivers/gpu/drm/radeon/atom.c
+++ b/drivers/gpu/drm/radeon/atom.c
@@ -108,12 +108,11 @@ static uint32_t atom_iio_execute(struct atom_context *ctx, int base,
base++;
break;
case ATOM_IIO_READ:
- temp = ctx->card->reg_read(ctx->card, CU16(base + 1));
+ temp = ctx->card->ioreg_read(ctx->card, CU16(base + 1));
base += 3;
break;
case ATOM_IIO_WRITE:
- (void)ctx->card->reg_read(ctx->card, CU16(base + 1));
- ctx->card->reg_write(ctx->card, CU16(base + 1), temp);
+ ctx->card->ioreg_write(ctx->card, CU16(base + 1), temp);
base += 3;
break;
case ATOM_IIO_CLEAR:
@@ -715,8 +714,8 @@ static void atom_op_jump(atom_exec_context *ctx, int *ptr, int arg)
cjiffies = jiffies;
if (time_after(cjiffies, ctx->last_jump_jiffies)) {
cjiffies -= ctx->last_jump_jiffies;
- if ((jiffies_to_msecs(cjiffies) > 1000)) {
- DRM_ERROR("atombios stuck in loop for more than 1sec aborting\n");
+ if ((jiffies_to_msecs(cjiffies) > 5000)) {
+ DRM_ERROR("atombios stuck in loop for more than 5secs aborting\n");
ctx->abort = true;
}
} else {
diff --git a/drivers/gpu/drm/radeon/atom.h b/drivers/gpu/drm/radeon/atom.h
index cd1b64ab5ca..a589a55b223 100644
--- a/drivers/gpu/drm/radeon/atom.h
+++ b/drivers/gpu/drm/radeon/atom.h
@@ -113,6 +113,8 @@ struct card_info {
struct drm_device *dev;
void (* reg_write)(struct card_info *, uint32_t, uint32_t); /* filled by driver */
uint32_t (* reg_read)(struct card_info *, uint32_t); /* filled by driver */
+ void (* ioreg_write)(struct card_info *, uint32_t, uint32_t); /* filled by driver */
+ uint32_t (* ioreg_read)(struct card_info *, uint32_t); /* filled by driver */
void (* mc_write)(struct card_info *, uint32_t, uint32_t); /* filled by driver */
uint32_t (* mc_read)(struct card_info *, uint32_t); /* filled by driver */
void (* pll_write)(struct card_info *, uint32_t, uint32_t); /* filled by driver */
diff --git a/drivers/gpu/drm/radeon/atombios_crtc.c b/drivers/gpu/drm/radeon/atombios_crtc.c
index 8c2d6478a22..12ad512bd3d 100644
--- a/drivers/gpu/drm/radeon/atombios_crtc.c
+++ b/drivers/gpu/drm/radeon/atombios_crtc.c
@@ -44,10 +44,6 @@ static void atombios_overscan_setup(struct drm_crtc *crtc,
memset(&args, 0, sizeof(args));
- args.usOverscanRight = 0;
- args.usOverscanLeft = 0;
- args.usOverscanBottom = 0;
- args.usOverscanTop = 0;
args.ucCRTC = radeon_crtc->crtc_id;
switch (radeon_crtc->rmx_type) {
@@ -56,7 +52,6 @@ static void atombios_overscan_setup(struct drm_crtc *crtc,
args.usOverscanBottom = (adjusted_mode->crtc_vdisplay - mode->crtc_vdisplay) / 2;
args.usOverscanLeft = (adjusted_mode->crtc_hdisplay - mode->crtc_hdisplay) / 2;
args.usOverscanRight = (adjusted_mode->crtc_hdisplay - mode->crtc_hdisplay) / 2;
- atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
break;
case RMX_ASPECT:
a1 = mode->crtc_vdisplay * adjusted_mode->crtc_hdisplay;
@@ -69,17 +64,16 @@ static void atombios_overscan_setup(struct drm_crtc *crtc,
args.usOverscanLeft = (adjusted_mode->crtc_vdisplay - (a1 / mode->crtc_hdisplay)) / 2;
args.usOverscanRight = (adjusted_mode->crtc_vdisplay - (a1 / mode->crtc_hdisplay)) / 2;
}
- atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
break;
case RMX_FULL:
default:
- args.usOverscanRight = 0;
- args.usOverscanLeft = 0;
- args.usOverscanBottom = 0;
- args.usOverscanTop = 0;
- atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
+ args.usOverscanRight = radeon_crtc->h_border;
+ args.usOverscanLeft = radeon_crtc->h_border;
+ args.usOverscanBottom = radeon_crtc->v_border;
+ args.usOverscanTop = radeon_crtc->v_border;
break;
}
+ atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
}
static void atombios_scaler_setup(struct drm_crtc *crtc)
@@ -282,22 +276,22 @@ atombios_set_crtc_dtd_timing(struct drm_crtc *crtc,
u16 misc = 0;
memset(&args, 0, sizeof(args));
- args.usH_Size = cpu_to_le16(mode->crtc_hdisplay);
+ args.usH_Size = cpu_to_le16(mode->crtc_hdisplay - (radeon_crtc->h_border * 2));
args.usH_Blanking_Time =
- cpu_to_le16(mode->crtc_hblank_end - mode->crtc_hdisplay);
- args.usV_Size = cpu_to_le16(mode->crtc_vdisplay);
+ cpu_to_le16(mode->crtc_hblank_end - mode->crtc_hdisplay + (radeon_crtc->h_border * 2));
+ args.usV_Size = cpu_to_le16(mode->crtc_vdisplay - (radeon_crtc->v_border * 2));
args.usV_Blanking_Time =
- cpu_to_le16(mode->crtc_vblank_end - mode->crtc_vdisplay);
+ cpu_to_le16(mode->crtc_vblank_end - mode->crtc_vdisplay + (radeon_crtc->v_border * 2));
args.usH_SyncOffset =
- cpu_to_le16(mode->crtc_hsync_start - mode->crtc_hdisplay);
+ cpu_to_le16(mode->crtc_hsync_start - mode->crtc_hdisplay + radeon_crtc->h_border);
args.usH_SyncWidth =
cpu_to_le16(mode->crtc_hsync_end - mode->crtc_hsync_start);
args.usV_SyncOffset =
- cpu_to_le16(mode->crtc_vsync_start - mode->crtc_vdisplay);
+ cpu_to_le16(mode->crtc_vsync_start - mode->crtc_vdisplay + radeon_crtc->v_border);
args.usV_SyncWidth =
cpu_to_le16(mode->crtc_vsync_end - mode->crtc_vsync_start);
- /*args.ucH_Border = mode->hborder;*/
- /*args.ucV_Border = mode->vborder;*/
+ args.ucH_Border = radeon_crtc->h_border;
+ args.ucV_Border = radeon_crtc->v_border;
if (mode->flags & DRM_MODE_FLAG_NVSYNC)
misc |= ATOM_VSYNC_POLARITY;
@@ -669,56 +663,25 @@ static void atombios_crtc_set_dcpll(struct drm_crtc *crtc)
atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
}
-static void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode *mode)
+static void atombios_crtc_program_pll(struct drm_crtc *crtc,
+ int crtc_id,
+ int pll_id,
+ u32 encoder_mode,
+ u32 encoder_id,
+ u32 clock,
+ u32 ref_div,
+ u32 fb_div,
+ u32 frac_fb_div,
+ u32 post_div)
{
- struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
struct drm_device *dev = crtc->dev;
struct radeon_device *rdev = dev->dev_private;
- struct drm_encoder *encoder = NULL;
- struct radeon_encoder *radeon_encoder = NULL;
u8 frev, crev;
- int index;
+ int index = GetIndexIntoMasterTable(COMMAND, SetPixelClock);
union set_pixel_clock args;
- u32 pll_clock = mode->clock;
- u32 ref_div = 0, fb_div = 0, frac_fb_div = 0, post_div = 0;
- struct radeon_pll *pll;
- u32 adjusted_clock;
- int encoder_mode = 0;
memset(&args, 0, sizeof(args));
- list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
- if (encoder->crtc == crtc) {
- radeon_encoder = to_radeon_encoder(encoder);
- encoder_mode = atombios_get_encoder_mode(encoder);
- break;
- }
- }
-
- if (!radeon_encoder)
- return;
-
- switch (radeon_crtc->pll_id) {
- case ATOM_PPLL1:
- pll = &rdev->clock.p1pll;
- break;
- case ATOM_PPLL2:
- pll = &rdev->clock.p2pll;
- break;
- case ATOM_DCPLL:
- case ATOM_PPLL_INVALID:
- default:
- pll = &rdev->clock.dcpll;
- break;
- }
-
- /* adjust pixel clock as needed */
- adjusted_clock = atombios_adjust_pll(crtc, mode, pll);
-
- radeon_compute_pll(pll, adjusted_clock, &pll_clock, &fb_div, &frac_fb_div,
- &ref_div, &post_div);
-
- index = GetIndexIntoMasterTable(COMMAND, SetPixelClock);
if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev,
&crev))
return;
@@ -727,47 +690,49 @@ static void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode
case 1:
switch (crev) {
case 1:
- args.v1.usPixelClock = cpu_to_le16(mode->clock / 10);
+ if (clock == ATOM_DISABLE)
+ return;
+ args.v1.usPixelClock = cpu_to_le16(clock / 10);
args.v1.usRefDiv = cpu_to_le16(ref_div);
args.v1.usFbDiv = cpu_to_le16(fb_div);
args.v1.ucFracFbDiv = frac_fb_div;
args.v1.ucPostDiv = post_div;
- args.v1.ucPpll = radeon_crtc->pll_id;
- args.v1.ucCRTC = radeon_crtc->crtc_id;
+ args.v1.ucPpll = pll_id;
+ args.v1.ucCRTC = crtc_id;
args.v1.ucRefDivSrc = 1;
break;
case 2:
- args.v2.usPixelClock = cpu_to_le16(mode->clock / 10);
+ args.v2.usPixelClock = cpu_to_le16(clock / 10);
args.v2.usRefDiv = cpu_to_le16(ref_div);
args.v2.usFbDiv = cpu_to_le16(fb_div);
args.v2.ucFracFbDiv = frac_fb_div;
args.v2.ucPostDiv = post_div;
- args.v2.ucPpll = radeon_crtc->pll_id;
- args.v2.ucCRTC = radeon_crtc->crtc_id;
+ args.v2.ucPpll = pll_id;
+ args.v2.ucCRTC = crtc_id;
args.v2.ucRefDivSrc = 1;
break;
case 3:
- args.v3.usPixelClock = cpu_to_le16(mode->clock / 10);
+ args.v3.usPixelClock = cpu_to_le16(clock / 10);
args.v3.usRefDiv = cpu_to_le16(ref_div);
args.v3.usFbDiv = cpu_to_le16(fb_div);
args.v3.ucFracFbDiv = frac_fb_div;
args.v3.ucPostDiv = post_div;
- args.v3.ucPpll = radeon_crtc->pll_id;
- args.v3.ucMiscInfo = (radeon_crtc->pll_id << 2);
- args.v3.ucTransmitterId = radeon_encoder->encoder_id;
+ args.v3.ucPpll = pll_id;
+ args.v3.ucMiscInfo = (pll_id << 2);
+ args.v3.ucTransmitterId = encoder_id;
args.v3.ucEncoderMode = encoder_mode;
break;
case 5:
- args.v5.ucCRTC = radeon_crtc->crtc_id;
- args.v5.usPixelClock = cpu_to_le16(mode->clock / 10);
+ args.v5.ucCRTC = crtc_id;
+ args.v5.usPixelClock = cpu_to_le16(clock / 10);
args.v5.ucRefDiv = ref_div;
args.v5.usFbDiv = cpu_to_le16(fb_div);
args.v5.ulFbDivDecFrac = cpu_to_le32(frac_fb_div * 100000);
args.v5.ucPostDiv = post_div;
args.v5.ucMiscInfo = 0; /* HDMI depth, etc. */
- args.v5.ucTransmitterID = radeon_encoder->encoder_id;
+ args.v5.ucTransmitterID = encoder_id;
args.v5.ucEncoderMode = encoder_mode;
- args.v5.ucPpll = radeon_crtc->pll_id;
+ args.v5.ucPpll = pll_id;
break;
default:
DRM_ERROR("Unknown table version %d %d\n", frev, crev);
@@ -782,6 +747,56 @@ static void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode
atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
}
+static void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode *mode)
+{
+ struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
+ struct drm_device *dev = crtc->dev;
+ struct radeon_device *rdev = dev->dev_private;
+ struct drm_encoder *encoder = NULL;
+ struct radeon_encoder *radeon_encoder = NULL;
+ u32 pll_clock = mode->clock;
+ u32 ref_div = 0, fb_div = 0, frac_fb_div = 0, post_div = 0;
+ struct radeon_pll *pll;
+ u32 adjusted_clock;
+ int encoder_mode = 0;
+
+ list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
+ if (encoder->crtc == crtc) {
+ radeon_encoder = to_radeon_encoder(encoder);
+ encoder_mode = atombios_get_encoder_mode(encoder);
+ break;
+ }
+ }
+
+ if (!radeon_encoder)
+ return;
+
+ switch (radeon_crtc->pll_id) {
+ case ATOM_PPLL1:
+ pll = &rdev->clock.p1pll;
+ break;
+ case ATOM_PPLL2:
+ pll = &rdev->clock.p2pll;
+ break;
+ case ATOM_DCPLL:
+ case ATOM_PPLL_INVALID:
+ default:
+ pll = &rdev->clock.dcpll;
+ break;
+ }
+
+ /* adjust pixel clock as needed */
+ adjusted_clock = atombios_adjust_pll(crtc, mode, pll);
+
+ radeon_compute_pll(pll, adjusted_clock, &pll_clock, &fb_div, &frac_fb_div,
+ &ref_div, &post_div);
+
+ atombios_crtc_program_pll(crtc, radeon_crtc->crtc_id, radeon_crtc->pll_id,
+ encoder_mode, radeon_encoder->encoder_id, mode->clock,
+ ref_div, fb_div, frac_fb_div, post_div);
+
+}
+
static int evergreen_crtc_set_base(struct drm_crtc *crtc, int x, int y,
struct drm_framebuffer *old_fb)
{
@@ -797,7 +812,7 @@ static int evergreen_crtc_set_base(struct drm_crtc *crtc, int x, int y,
/* no fb bound */
if (!crtc->fb) {
- DRM_DEBUG("No FB bound\n");
+ DRM_DEBUG_KMS("No FB bound\n");
return 0;
}
@@ -841,6 +856,11 @@ static int evergreen_crtc_set_base(struct drm_crtc *crtc, int x, int y,
return -EINVAL;
}
+ if (tiling_flags & RADEON_TILING_MACRO)
+ fb_format |= EVERGREEN_GRPH_ARRAY_MODE(EVERGREEN_GRPH_ARRAY_2D_TILED_THIN1);
+ else if (tiling_flags & RADEON_TILING_MICRO)
+ fb_format |= EVERGREEN_GRPH_ARRAY_MODE(EVERGREEN_GRPH_ARRAY_1D_TILED_THIN1);
+
switch (radeon_crtc->crtc_id) {
case 0:
WREG32(AVIVO_D1VGA_CONTROL, 0);
@@ -931,7 +951,7 @@ static int avivo_crtc_set_base(struct drm_crtc *crtc, int x, int y,
/* no fb bound */
if (!crtc->fb) {
- DRM_DEBUG("No FB bound\n");
+ DRM_DEBUG_KMS("No FB bound\n");
return 0;
}
@@ -979,11 +999,18 @@ static int avivo_crtc_set_base(struct drm_crtc *crtc, int x, int y,
return -EINVAL;
}
- if (tiling_flags & RADEON_TILING_MACRO)
- fb_format |= AVIVO_D1GRPH_MACRO_ADDRESS_MODE;
+ if (rdev->family >= CHIP_R600) {
+ if (tiling_flags & RADEON_TILING_MACRO)
+ fb_format |= R600_D1GRPH_ARRAY_MODE_2D_TILED_THIN1;
+ else if (tiling_flags & RADEON_TILING_MICRO)
+ fb_format |= R600_D1GRPH_ARRAY_MODE_1D_TILED_THIN1;
+ } else {
+ if (tiling_flags & RADEON_TILING_MACRO)
+ fb_format |= AVIVO_D1GRPH_MACRO_ADDRESS_MODE;
- if (tiling_flags & RADEON_TILING_MICRO)
- fb_format |= AVIVO_D1GRPH_TILED;
+ if (tiling_flags & RADEON_TILING_MICRO)
+ fb_format |= AVIVO_D1GRPH_TILED;
+ }
if (radeon_crtc->crtc_id == 0)
WREG32(AVIVO_D1VGA_CONTROL, 0);
@@ -1143,10 +1170,8 @@ int atombios_crtc_mode_set(struct drm_crtc *crtc,
atombios_crtc_set_pll(crtc, adjusted_mode);
atombios_enable_ss(crtc);
- if (ASIC_IS_DCE4(rdev))
+ if (ASIC_IS_AVIVO(rdev))
atombios_set_crtc_dtd_timing(crtc, adjusted_mode);
- else if (ASIC_IS_AVIVO(rdev))
- atombios_crtc_set_timing(crtc, adjusted_mode);
else {
atombios_crtc_set_timing(crtc, adjusted_mode);
if (radeon_crtc->crtc_id == 0)
@@ -1191,6 +1216,24 @@ static void atombios_crtc_commit(struct drm_crtc *crtc)
atombios_lock_crtc(crtc, ATOM_DISABLE);
}
+static void atombios_crtc_disable(struct drm_crtc *crtc)
+{
+ struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
+ atombios_crtc_dpms(crtc, DRM_MODE_DPMS_OFF);
+
+ switch (radeon_crtc->pll_id) {
+ case ATOM_PPLL1:
+ case ATOM_PPLL2:
+ /* disable the ppll */
+ atombios_crtc_program_pll(crtc, radeon_crtc->crtc_id, radeon_crtc->pll_id,
+ 0, 0, ATOM_DISABLE, 0, 0, 0, 0);
+ break;
+ default:
+ break;
+ }
+ radeon_crtc->pll_id = -1;
+}
+
static const struct drm_crtc_helper_funcs atombios_helper_funcs = {
.dpms = atombios_crtc_dpms,
.mode_fixup = atombios_crtc_mode_fixup,
@@ -1199,6 +1242,7 @@ static const struct drm_crtc_helper_funcs atombios_helper_funcs = {
.prepare = atombios_crtc_prepare,
.commit = atombios_crtc_commit,
.load_lut = radeon_crtc_load_lut,
+ .disable = atombios_crtc_disable,
};
void radeon_atombios_init_crtc(struct drm_device *dev,
diff --git a/drivers/gpu/drm/radeon/atombios_dp.c b/drivers/gpu/drm/radeon/atombios_dp.c
index abffb1499e2..36e0d4b545e 100644
--- a/drivers/gpu/drm/radeon/atombios_dp.c
+++ b/drivers/gpu/drm/radeon/atombios_dp.c
@@ -296,7 +296,7 @@ static void dp_get_adjust_train(u8 link_status[DP_LINK_STATUS_SIZE],
u8 this_v = dp_get_adjust_request_voltage(link_status, lane);
u8 this_p = dp_get_adjust_request_pre_emphasis(link_status, lane);
- DRM_DEBUG("requested signal parameters: lane %d voltage %s pre_emph %s\n",
+ DRM_DEBUG_KMS("requested signal parameters: lane %d voltage %s pre_emph %s\n",
lane,
voltage_names[this_v >> DP_TRAIN_VOLTAGE_SWING_SHIFT],
pre_emph_names[this_p >> DP_TRAIN_PRE_EMPHASIS_SHIFT]);
@@ -313,7 +313,7 @@ static void dp_get_adjust_train(u8 link_status[DP_LINK_STATUS_SIZE],
if (p >= dp_pre_emphasis_max(v))
p = dp_pre_emphasis_max(v) | DP_TRAIN_MAX_PRE_EMPHASIS_REACHED;
- DRM_DEBUG("using signal parameters: voltage %s pre_emph %s\n",
+ DRM_DEBUG_KMS("using signal parameters: voltage %s pre_emph %s\n",
voltage_names[(v & DP_TRAIN_VOLTAGE_SWING_MASK) >> DP_TRAIN_VOLTAGE_SWING_SHIFT],
pre_emph_names[(p & DP_TRAIN_PRE_EMPHASIS_MASK) >> DP_TRAIN_PRE_EMPHASIS_SHIFT]);
@@ -358,7 +358,7 @@ retry:
if (args.v1.ucReplyStatus && !args.v1.ucDataOutLen) {
if (args.v1.ucReplyStatus == 0x20 && retry_count++ < 10)
goto retry;
- DRM_DEBUG("failed to get auxch %02x%02x %02x %02x 0x%02x %02x after %d retries\n",
+ DRM_DEBUG_KMS("failed to get auxch %02x%02x %02x %02x 0x%02x %02x after %d retries\n",
req_bytes[1], req_bytes[0], req_bytes[2], req_bytes[3],
chan->rec.i2c_id, args.v1.ucReplyStatus, retry_count);
return false;
@@ -461,10 +461,10 @@ bool radeon_dp_getdpcd(struct radeon_connector *radeon_connector)
memcpy(dig_connector->dpcd, msg, 8);
{
int i;
- DRM_DEBUG("DPCD: ");
+ DRM_DEBUG_KMS("DPCD: ");
for (i = 0; i < 8; i++)
- DRM_DEBUG("%02x ", msg[i]);
- DRM_DEBUG("\n");
+ DRM_DEBUG_KMS("%02x ", msg[i]);
+ DRM_DEBUG_KMS("\n");
}
return true;
}
@@ -512,7 +512,7 @@ static bool atom_dp_get_link_status(struct radeon_connector *radeon_connector,
return false;
}
- DRM_DEBUG("link status %02x %02x %02x %02x %02x %02x\n",
+ DRM_DEBUG_KMS("link status %02x %02x %02x %02x %02x %02x\n",
link_status[0], link_status[1], link_status[2],
link_status[3], link_status[4], link_status[5]);
return true;
@@ -695,7 +695,7 @@ void dp_link_train(struct drm_encoder *encoder,
if (!clock_recovery)
DRM_ERROR("clock recovery failed\n");
else
- DRM_DEBUG("clock recovery at voltage %d pre-emphasis %d\n",
+ DRM_DEBUG_KMS("clock recovery at voltage %d pre-emphasis %d\n",
train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK,
(train_set[0] & DP_TRAIN_PRE_EMPHASIS_MASK) >>
DP_TRAIN_PRE_EMPHASIS_SHIFT);
@@ -739,7 +739,7 @@ void dp_link_train(struct drm_encoder *encoder,
if (!channel_eq)
DRM_ERROR("channel eq failed\n");
else
- DRM_DEBUG("channel eq at voltage %d pre-emphasis %d\n",
+ DRM_DEBUG_KMS("channel eq at voltage %d pre-emphasis %d\n",
train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK,
(train_set[0] & DP_TRAIN_PRE_EMPHASIS_MASK)
>> DP_TRAIN_PRE_EMPHASIS_SHIFT);
diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c
index 1caf625e472..957d5067ad9 100644
--- a/drivers/gpu/drm/radeon/evergreen.c
+++ b/drivers/gpu/drm/radeon/evergreen.c
@@ -39,6 +39,23 @@
static void evergreen_gpu_init(struct radeon_device *rdev);
void evergreen_fini(struct radeon_device *rdev);
+/* get temperature in millidegrees */
+u32 evergreen_get_temp(struct radeon_device *rdev)
+{
+ u32 temp = (RREG32(CG_MULT_THERMAL_STATUS) & ASIC_T_MASK) >>
+ ASIC_T_SHIFT;
+ u32 actual_temp = 0;
+
+ if ((temp >> 10) & 1)
+ actual_temp = 0;
+ else if ((temp >> 9) & 1)
+ actual_temp = 255;
+ else
+ actual_temp = (temp >> 1) & 0xff;
+
+ return actual_temp * 1000;
+}
+
void evergreen_pm_misc(struct radeon_device *rdev)
{
int req_ps_idx = rdev->pm.requested_power_state_index;
@@ -1115,6 +1132,7 @@ static void evergreen_gpu_init(struct radeon_device *rdev)
rdev->config.evergreen.max_backends) &
EVERGREEN_MAX_BACKENDS_MASK));
+ rdev->config.evergreen.tile_config = gb_addr_config;
WREG32(GB_BACKEND_MAP, gb_backend_map);
WREG32(GB_ADDR_CONFIG, gb_addr_config);
WREG32(DMIF_ADDR_CONFIG, gb_addr_config);
@@ -1334,8 +1352,8 @@ int evergreen_mc_init(struct radeon_device *rdev)
}
rdev->mc.vram_width = numchan * chansize;
/* Could aper size report 0 ? */
- rdev->mc.aper_base = drm_get_resource_start(rdev->ddev, 0);
- rdev->mc.aper_size = drm_get_resource_len(rdev->ddev, 0);
+ rdev->mc.aper_base = pci_resource_start(rdev->pdev, 0);
+ rdev->mc.aper_size = pci_resource_len(rdev->pdev, 0);
/* Setup GPU memory space */
/* size in MB on evergreen */
rdev->mc.mc_vram_size = RREG32(CONFIG_MEMSIZE) * 1024 * 1024;
diff --git a/drivers/gpu/drm/radeon/evergreen_reg.h b/drivers/gpu/drm/radeon/evergreen_reg.h
index e028c1cd9d9..2330f3a36fd 100644
--- a/drivers/gpu/drm/radeon/evergreen_reg.h
+++ b/drivers/gpu/drm/radeon/evergreen_reg.h
@@ -61,6 +61,11 @@
# define EVERGREEN_GRPH_FORMAT_8B_BGRA1010102 5
# define EVERGREEN_GRPH_FORMAT_RGB111110 6
# define EVERGREEN_GRPH_FORMAT_BGR101111 7
+# define EVERGREEN_GRPH_ARRAY_MODE(x) (((x) & 0x7) << 20)
+# define EVERGREEN_GRPH_ARRAY_LINEAR_GENERAL 0
+# define EVERGREEN_GRPH_ARRAY_LINEAR_ALIGNED 1
+# define EVERGREEN_GRPH_ARRAY_1D_TILED_THIN1 2
+# define EVERGREEN_GRPH_ARRAY_2D_TILED_THIN1 4
#define EVERGREEN_GRPH_SWAP_CONTROL 0x680c
# define EVERGREEN_GRPH_ENDIAN_SWAP(x) (((x) & 0x3) << 0)
# define EVERGREEN_GRPH_ENDIAN_NONE 0
diff --git a/drivers/gpu/drm/radeon/evergreend.h b/drivers/gpu/drm/radeon/evergreend.h
index a1cd621780e..9b7532dd30f 100644
--- a/drivers/gpu/drm/radeon/evergreend.h
+++ b/drivers/gpu/drm/radeon/evergreend.h
@@ -165,6 +165,11 @@
#define SE_DB_BUSY (1 << 30)
#define SE_CB_BUSY (1 << 31)
+#define CG_MULT_THERMAL_STATUS 0x740
+#define ASIC_T(x) ((x) << 16)
+#define ASIC_T_MASK 0x7FF0000
+#define ASIC_T_SHIFT 16
+
#define HDP_HOST_PATH_CNTL 0x2C00
#define HDP_NONSURFACE_BASE 0x2C04
#define HDP_NONSURFACE_INFO 0x2C08
diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c
index a89a15ab524..e817a0bb5eb 100644
--- a/drivers/gpu/drm/radeon/r100.c
+++ b/drivers/gpu/drm/radeon/r100.c
@@ -141,7 +141,7 @@ void r100_pm_get_dynpm_state(struct radeon_device *rdev)
/* only one clock mode per power state */
rdev->pm.requested_clock_mode_index = 0;
- DRM_DEBUG("Requested: e: %d m: %d p: %d\n",
+ DRM_DEBUG_DRIVER("Requested: e: %d m: %d p: %d\n",
rdev->pm.power_state[rdev->pm.requested_power_state_index].
clock_info[rdev->pm.requested_clock_mode_index].sclk,
rdev->pm.power_state[rdev->pm.requested_power_state_index].
@@ -276,7 +276,7 @@ void r100_pm_misc(struct radeon_device *rdev)
rdev->pm.power_state[rdev->pm.current_power_state_index].pcie_lanes)) {
radeon_set_pcie_lanes(rdev,
ps->pcie_lanes);
- DRM_DEBUG("Setting: p: %d\n", ps->pcie_lanes);
+ DRM_DEBUG_DRIVER("Setting: p: %d\n", ps->pcie_lanes);
}
}
@@ -849,7 +849,7 @@ static int r100_cp_init_microcode(struct radeon_device *rdev)
const char *fw_name = NULL;
int err;
- DRM_DEBUG("\n");
+ DRM_DEBUG_KMS("\n");
pdev = platform_device_register_simple("radeon_cp", 0, NULL, 0);
err = IS_ERR(pdev);
@@ -1803,6 +1803,11 @@ static int r100_packet3_check(struct radeon_cs_parser *p,
return r;
break;
/* triggers drawing using indices to vertex buffer */
+ case PACKET3_3D_CLEAR_HIZ:
+ case PACKET3_3D_CLEAR_ZMASK:
+ if (p->rdev->hyperz_filp != p->filp)
+ return -EINVAL;
+ break;
case PACKET3_NOP:
break;
default:
@@ -2295,8 +2300,8 @@ void r100_vram_init_sizes(struct radeon_device *rdev)
u64 config_aper_size;
/* work out accessible VRAM */
- rdev->mc.aper_base = drm_get_resource_start(rdev->ddev, 0);
- rdev->mc.aper_size = drm_get_resource_len(rdev->ddev, 0);
+ rdev->mc.aper_base = pci_resource_start(rdev->pdev, 0);
+ rdev->mc.aper_size = pci_resource_len(rdev->pdev, 0);
rdev->mc.visible_vram_size = r100_get_accessible_vram(rdev);
/* FIXME we don't use the second aperture yet when we could use it */
if (rdev->mc.visible_vram_size > rdev->mc.aper_size)
@@ -2364,11 +2369,10 @@ void r100_mc_init(struct radeon_device *rdev)
*/
void r100_pll_errata_after_index(struct radeon_device *rdev)
{
- if (!(rdev->pll_errata & CHIP_ERRATA_PLL_DUMMYREADS)) {
- return;
+ if (rdev->pll_errata & CHIP_ERRATA_PLL_DUMMYREADS) {
+ (void)RREG32(RADEON_CLOCK_CNTL_DATA);
+ (void)RREG32(RADEON_CRTC_GEN_CNTL);
}
- (void)RREG32(RADEON_CLOCK_CNTL_DATA);
- (void)RREG32(RADEON_CRTC_GEN_CNTL);
}
static void r100_pll_errata_after_data(struct radeon_device *rdev)
@@ -2643,7 +2647,7 @@ int r100_set_surface_reg(struct radeon_device *rdev, int reg,
flags |= pitch / 8;
- DRM_DEBUG("writing surface %d %d %x %x\n", reg, flags, offset, offset+obj_size-1);
+ DRM_DEBUG_KMS("writing surface %d %d %x %x\n", reg, flags, offset, offset+obj_size-1);
WREG32(RADEON_SURFACE0_INFO + surf_index, flags);
WREG32(RADEON_SURFACE0_LOWER_BOUND + surf_index, offset);
WREG32(RADEON_SURFACE0_UPPER_BOUND + surf_index, offset + obj_size - 1);
@@ -3039,7 +3043,7 @@ void r100_bandwidth_update(struct radeon_device *rdev)
}
#endif
- DRM_DEBUG("GRPH_BUFFER_CNTL from to %x\n",
+ DRM_DEBUG_KMS("GRPH_BUFFER_CNTL from to %x\n",
/* (unsigned int)info->SavedReg->grph_buffer_cntl, */
(unsigned int)RREG32(RADEON_GRPH_BUFFER_CNTL));
}
@@ -3135,7 +3139,7 @@ void r100_bandwidth_update(struct radeon_device *rdev)
WREG32(RS400_DISP1_REQ_CNTL1, 0x28FBC3AC);
}
- DRM_DEBUG("GRPH2_BUFFER_CNTL from to %x\n",
+ DRM_DEBUG_KMS("GRPH2_BUFFER_CNTL from to %x\n",
(unsigned int)RREG32(RADEON_GRPH2_BUFFER_CNTL));
}
}
@@ -3809,6 +3813,31 @@ void r100_fini(struct radeon_device *rdev)
rdev->bios = NULL;
}
+/*
+ * Due to how kexec works, it can leave the hw fully initialised when it
+ * boots the new kernel. However doing our init sequence with the CP and
+ * WB stuff setup causes GPU hangs on the RN50 at least. So at startup
+ * do some quick sanity checks and restore sane values to avoid this
+ * problem.
+ */
+void r100_restore_sanity(struct radeon_device *rdev)
+{
+ u32 tmp;
+
+ tmp = RREG32(RADEON_CP_CSQ_CNTL);
+ if (tmp) {
+ WREG32(RADEON_CP_CSQ_CNTL, 0);
+ }
+ tmp = RREG32(RADEON_CP_RB_CNTL);
+ if (tmp) {
+ WREG32(RADEON_CP_RB_CNTL, 0);
+ }
+ tmp = RREG32(RADEON_SCRATCH_UMSK);
+ if (tmp) {
+ WREG32(RADEON_SCRATCH_UMSK, 0);
+ }
+}
+
int r100_init(struct radeon_device *rdev)
{
int r;
@@ -3821,6 +3850,8 @@ int r100_init(struct radeon_device *rdev)
radeon_scratch_init(rdev);
/* Initialize surface registers */
radeon_surface_init(rdev);
+ /* sanity check some register to avoid hangs like after kexec */
+ r100_restore_sanity(rdev);
/* TODO: disable VGA need to use VGA request */
/* BIOS*/
if (!radeon_get_bios(rdev)) {
diff --git a/drivers/gpu/drm/radeon/r100d.h b/drivers/gpu/drm/radeon/r100d.h
index d016b16fa11..b121b6c678d 100644
--- a/drivers/gpu/drm/radeon/r100d.h
+++ b/drivers/gpu/drm/radeon/r100d.h
@@ -48,10 +48,12 @@
#define PACKET3_3D_DRAW_IMMD 0x29
#define PACKET3_3D_DRAW_INDX 0x2A
#define PACKET3_3D_LOAD_VBPNTR 0x2F
+#define PACKET3_3D_CLEAR_ZMASK 0x32
#define PACKET3_INDX_BUFFER 0x33
#define PACKET3_3D_DRAW_VBUF_2 0x34
#define PACKET3_3D_DRAW_IMMD_2 0x35
#define PACKET3_3D_DRAW_INDX_2 0x36
+#define PACKET3_3D_CLEAR_HIZ 0x37
#define PACKET3_BITBLT_MULTI 0x9B
#define PACKET0(reg, n) (CP_PACKET0 | \
diff --git a/drivers/gpu/drm/radeon/r300.c b/drivers/gpu/drm/radeon/r300.c
index 19a7ef7ee34..c827738ad7d 100644
--- a/drivers/gpu/drm/radeon/r300.c
+++ b/drivers/gpu/drm/radeon/r300.c
@@ -1048,14 +1048,47 @@ static int r300_packet0_check(struct radeon_cs_parser *p,
/* RB3D_COLOR_CHANNEL_MASK */
track->color_channel_mask = idx_value;
break;
- case 0x4d1c:
+ case 0x43a4:
+ /* SC_HYPERZ_EN */
+ /* r300c emits this register - we need to disable hyperz for it
+ * without complaining */
+ if (p->rdev->hyperz_filp != p->filp) {
+ if (idx_value & 0x1)
+ ib[idx] = idx_value & ~1;
+ }
+ break;
+ case 0x4f1c:
/* ZB_BW_CNTL */
track->zb_cb_clear = !!(idx_value & (1 << 5));
+ if (p->rdev->hyperz_filp != p->filp) {
+ if (idx_value & (R300_HIZ_ENABLE |
+ R300_RD_COMP_ENABLE |
+ R300_WR_COMP_ENABLE |
+ R300_FAST_FILL_ENABLE))
+ goto fail;
+ }
break;
case 0x4e04:
/* RB3D_BLENDCNTL */
track->blend_read_enable = !!(idx_value & (1 << 2));
break;
+ case 0x4f28: /* ZB_DEPTHCLEARVALUE */
+ break;
+ case 0x4f30: /* ZB_MASK_OFFSET */
+ case 0x4f34: /* ZB_ZMASK_PITCH */
+ case 0x4f44: /* ZB_HIZ_OFFSET */
+ case 0x4f54: /* ZB_HIZ_PITCH */
+ if (idx_value && (p->rdev->hyperz_filp != p->filp))
+ goto fail;
+ break;
+ case 0x4028:
+ if (idx_value && (p->rdev->hyperz_filp != p->filp))
+ goto fail;
+ /* GB_Z_PEQ_CONFIG */
+ if (p->rdev->family >= CHIP_RV350)
+ break;
+ goto fail;
+ break;
case 0x4be8:
/* valid register only on RV530 */
if (p->rdev->family == CHIP_RV530)
@@ -1066,8 +1099,8 @@ static int r300_packet0_check(struct radeon_cs_parser *p,
}
return 0;
fail:
- printk(KERN_ERR "Forbidden register 0x%04X in cs at %d\n",
- reg, idx);
+ printk(KERN_ERR "Forbidden register 0x%04X in cs at %d (val=%08x)\n",
+ reg, idx, idx_value);
return -EINVAL;
}
@@ -1161,6 +1194,11 @@ static int r300_packet3_check(struct radeon_cs_parser *p,
return r;
}
break;
+ case PACKET3_3D_CLEAR_HIZ:
+ case PACKET3_3D_CLEAR_ZMASK:
+ if (p->rdev->hyperz_filp != p->filp)
+ return -EINVAL;
+ break;
case PACKET3_NOP:
break;
default:
@@ -1380,6 +1418,8 @@ int r300_init(struct radeon_device *rdev)
/* Initialize surface registers */
radeon_surface_init(rdev);
/* TODO: disable VGA need to use VGA request */
+ /* restore some register to sane defaults */
+ r100_restore_sanity(rdev);
/* BIOS*/
if (!radeon_get_bios(rdev)) {
if (ASIC_IS_AVIVO(rdev))
diff --git a/drivers/gpu/drm/radeon/r300d.h b/drivers/gpu/drm/radeon/r300d.h
index 968a33317fb..0c036c60d9d 100644
--- a/drivers/gpu/drm/radeon/r300d.h
+++ b/drivers/gpu/drm/radeon/r300d.h
@@ -48,10 +48,12 @@
#define PACKET3_3D_DRAW_IMMD 0x29
#define PACKET3_3D_DRAW_INDX 0x2A
#define PACKET3_3D_LOAD_VBPNTR 0x2F
+#define PACKET3_3D_CLEAR_ZMASK 0x32
#define PACKET3_INDX_BUFFER 0x33
#define PACKET3_3D_DRAW_VBUF_2 0x34
#define PACKET3_3D_DRAW_IMMD_2 0x35
#define PACKET3_3D_DRAW_INDX_2 0x36
+#define PACKET3_3D_CLEAR_HIZ 0x37
#define PACKET3_BITBLT_MULTI 0x9B
#define PACKET0(reg, n) (CP_PACKET0 | \
diff --git a/drivers/gpu/drm/radeon/r420.c b/drivers/gpu/drm/radeon/r420.c
index e6c89142bb4..59f7bccc5be 100644
--- a/drivers/gpu/drm/radeon/r420.c
+++ b/drivers/gpu/drm/radeon/r420.c
@@ -343,6 +343,8 @@ int r420_init(struct radeon_device *rdev)
/* Initialize surface registers */
radeon_surface_init(rdev);
/* TODO: disable VGA need to use VGA request */
+ /* restore some register to sane defaults */
+ r100_restore_sanity(rdev);
/* BIOS*/
if (!radeon_get_bios(rdev)) {
if (ASIC_IS_AVIVO(rdev))
diff --git a/drivers/gpu/drm/radeon/r500_reg.h b/drivers/gpu/drm/radeon/r500_reg.h
index 93c9a2bbccf..6ac1f604e29 100644
--- a/drivers/gpu/drm/radeon/r500_reg.h
+++ b/drivers/gpu/drm/radeon/r500_reg.h
@@ -386,6 +386,11 @@
# define AVIVO_D1GRPH_TILED (1 << 20)
# define AVIVO_D1GRPH_MACRO_ADDRESS_MODE (1 << 21)
+# define R600_D1GRPH_ARRAY_MODE_LINEAR_GENERAL (0 << 20)
+# define R600_D1GRPH_ARRAY_MODE_LINEAR_ALIGNED (1 << 20)
+# define R600_D1GRPH_ARRAY_MODE_1D_TILED_THIN1 (2 << 20)
+# define R600_D1GRPH_ARRAY_MODE_2D_TILED_THIN1 (4 << 20)
+
/* The R7xx *_HIGH surface regs are backwards; the D1 regs are in the D2
* block and vice versa. This applies to GRPH, CUR, etc.
*/
diff --git a/drivers/gpu/drm/radeon/r520.c b/drivers/gpu/drm/radeon/r520.c
index 694af7cc23a..1458dee902d 100644
--- a/drivers/gpu/drm/radeon/r520.c
+++ b/drivers/gpu/drm/radeon/r520.c
@@ -231,6 +231,8 @@ int r520_init(struct radeon_device *rdev)
radeon_scratch_init(rdev);
/* Initialize surface registers */
radeon_surface_init(rdev);
+ /* restore some register to sane defaults */
+ r100_restore_sanity(rdev);
/* TODO: disable VGA need to use VGA request */
/* BIOS*/
if (!radeon_get_bios(rdev)) {
diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c
index e100f69faee..d0ebae9dde2 100644
--- a/drivers/gpu/drm/radeon/r600.c
+++ b/drivers/gpu/drm/radeon/r600.c
@@ -92,6 +92,21 @@ void r600_gpu_init(struct radeon_device *rdev);
void r600_fini(struct radeon_device *rdev);
void r600_irq_disable(struct radeon_device *rdev);
+/* get temperature in millidegrees */
+u32 rv6xx_get_temp(struct radeon_device *rdev)
+{
+ u32 temp = (RREG32(CG_THERMAL_STATUS) & ASIC_T_MASK) >>
+ ASIC_T_SHIFT;
+ u32 actual_temp = 0;
+
+ if ((temp >> 7) & 1)
+ actual_temp = 0;
+ else
+ actual_temp = (temp >> 1) & 0xff;
+
+ return actual_temp * 1000;
+}
+
void r600_pm_get_dynpm_state(struct radeon_device *rdev)
{
int i;
@@ -256,7 +271,7 @@ void r600_pm_get_dynpm_state(struct radeon_device *rdev)
}
}
- DRM_DEBUG("Requested: e: %d m: %d p: %d\n",
+ DRM_DEBUG_DRIVER("Requested: e: %d m: %d p: %d\n",
rdev->pm.power_state[rdev->pm.requested_power_state_index].
clock_info[rdev->pm.requested_clock_mode_index].sclk,
rdev->pm.power_state[rdev->pm.requested_power_state_index].
@@ -571,7 +586,7 @@ void r600_pm_misc(struct radeon_device *rdev)
if (voltage->voltage != rdev->pm.current_vddc) {
radeon_atom_set_voltage(rdev, voltage->voltage);
rdev->pm.current_vddc = voltage->voltage;
- DRM_DEBUG("Setting: v: %d\n", voltage->voltage);
+ DRM_DEBUG_DRIVER("Setting: v: %d\n", voltage->voltage);
}
}
}
@@ -869,7 +884,17 @@ void r600_pcie_gart_tlb_flush(struct radeon_device *rdev)
u32 tmp;
/* flush hdp cache so updates hit vram */
- WREG32(R_005480_HDP_MEM_COHERENCY_FLUSH_CNTL, 0x1);
+ if ((rdev->family >= CHIP_RV770) && (rdev->family <= CHIP_RV740)) {
+ void __iomem *ptr = (void *)rdev->gart.table.vram.ptr;
+ u32 tmp;
+
+ /* r7xx hw bug. write to HDP_DEBUG1 followed by fb read
+ * rather than write to HDP_REG_COHERENCY_FLUSH_CNTL
+ */
+ WREG32(HDP_DEBUG1, 0);
+ tmp = readl((void __iomem *)ptr);
+ } else
+ WREG32(R_005480_HDP_MEM_COHERENCY_FLUSH_CNTL, 0x1);
WREG32(VM_CONTEXT0_INVALIDATION_LOW_ADDR, rdev->mc.gtt_start >> 12);
WREG32(VM_CONTEXT0_INVALIDATION_HIGH_ADDR, (rdev->mc.gtt_end - 1) >> 12);
@@ -1217,8 +1242,8 @@ int r600_mc_init(struct radeon_device *rdev)
}
rdev->mc.vram_width = numchan * chansize;
/* Could aper size report 0 ? */
- rdev->mc.aper_base = drm_get_resource_start(rdev->ddev, 0);
- rdev->mc.aper_size = drm_get_resource_len(rdev->ddev, 0);
+ rdev->mc.aper_base = pci_resource_start(rdev->pdev, 0);
+ rdev->mc.aper_size = pci_resource_len(rdev->pdev, 0);
/* Setup GPU memory space */
rdev->mc.mc_vram_size = RREG32(CONFIG_MEMSIZE);
rdev->mc.real_vram_size = RREG32(CONFIG_MEMSIZE);
@@ -1609,7 +1634,7 @@ void r600_gpu_init(struct radeon_device *rdev)
r600_count_pipe_bits((cc_rb_backend_disable &
R6XX_MAX_BACKENDS_MASK) >> 16)),
(cc_rb_backend_disable >> 16));
-
+ rdev->config.r600.tile_config = tiling_config;
tiling_config |= BACKEND_MAP(backend_map);
WREG32(GB_TILING_CONFIG, tiling_config);
WREG32(DCP_TILING_CONFIG, tiling_config & 0xffff);
@@ -3512,5 +3537,15 @@ int r600_debugfs_mc_info_init(struct radeon_device *rdev)
*/
void r600_ioctl_wait_idle(struct radeon_device *rdev, struct radeon_bo *bo)
{
- WREG32(R_005480_HDP_MEM_COHERENCY_FLUSH_CNTL, 0x1);
+ /* r7xx hw bug. write to HDP_DEBUG1 followed by fb read
+ * rather than write to HDP_REG_COHERENCY_FLUSH_CNTL
+ */
+ if ((rdev->family >= CHIP_RV770) && (rdev->family <= CHIP_RV740)) {
+ void __iomem *ptr = (void *)rdev->gart.table.vram.ptr;
+ u32 tmp;
+
+ WREG32(HDP_DEBUG1, 0);
+ tmp = readl((void __iomem *)ptr);
+ } else
+ WREG32(R_005480_HDP_MEM_COHERENCY_FLUSH_CNTL, 0x1);
}
diff --git a/drivers/gpu/drm/radeon/r600_audio.c b/drivers/gpu/drm/radeon/r600_audio.c
index 2b26553c352..b5443fe1c1d 100644
--- a/drivers/gpu/drm/radeon/r600_audio.c
+++ b/drivers/gpu/drm/radeon/r600_audio.c
@@ -63,7 +63,8 @@ int r600_audio_bits_per_sample(struct radeon_device *rdev)
case 0x4: return 32;
}
- DRM_ERROR("Unknown bits per sample 0x%x using 16 instead.\n", (int)value);
+ dev_err(rdev->dev, "Unknown bits per sample 0x%x using 16 instead\n",
+ (int)value);
return 16;
}
@@ -150,7 +151,8 @@ static void r600_audio_update_hdmi(unsigned long param)
r600_hdmi_update_audio_settings(encoder);
}
- if(still_going) r600_audio_schedule_polling(rdev);
+ if (still_going)
+ r600_audio_schedule_polling(rdev);
}
/*
@@ -158,8 +160,9 @@ static void r600_audio_update_hdmi(unsigned long param)
*/
static void r600_audio_engine_enable(struct radeon_device *rdev, bool enable)
{
- DRM_INFO("%s audio support", enable ? "Enabling" : "Disabling");
+ DRM_INFO("%s audio support\n", enable ? "Enabling" : "Disabling");
WREG32_P(R600_AUDIO_ENABLE, enable ? 0x81000000 : 0x0, ~0x81000000);
+ rdev->audio_enabled = enable;
}
/*
@@ -195,12 +198,14 @@ void r600_audio_enable_polling(struct drm_encoder *encoder)
struct radeon_device *rdev = dev->dev_private;
struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
- DRM_DEBUG("r600_audio_enable_polling: %d", radeon_encoder->audio_polling_active);
+ DRM_DEBUG("r600_audio_enable_polling: %d\n",
+ radeon_encoder->audio_polling_active);
if (radeon_encoder->audio_polling_active)
return;
radeon_encoder->audio_polling_active = 1;
- mod_timer(&rdev->audio_timer, jiffies + 1);
+ if (rdev->audio_enabled)
+ mod_timer(&rdev->audio_timer, jiffies + 1);
}
/*
@@ -209,7 +214,8 @@ void r600_audio_enable_polling(struct drm_encoder *encoder)
void r600_audio_disable_polling(struct drm_encoder *encoder)
{
struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
- DRM_DEBUG("r600_audio_disable_polling: %d", radeon_encoder->audio_polling_active);
+ DRM_DEBUG("r600_audio_disable_polling: %d\n",
+ radeon_encoder->audio_polling_active);
radeon_encoder->audio_polling_active = 0;
}
@@ -236,7 +242,7 @@ void r600_audio_set_clock(struct drm_encoder *encoder, int clock)
WREG32_P(R600_AUDIO_TIMING, 0x100, ~0x301);
break;
default:
- DRM_ERROR("Unsupported encoder type 0x%02X\n",
+ dev_err(rdev->dev, "Unsupported encoder type 0x%02X\n",
radeon_encoder->encoder_id);
return;
}
@@ -266,7 +272,7 @@ void r600_audio_set_clock(struct drm_encoder *encoder, int clock)
*/
void r600_audio_fini(struct radeon_device *rdev)
{
- if (!radeon_audio || !r600_audio_chipset_supported(rdev))
+ if (!rdev->audio_enabled)
return;
del_timer(&rdev->audio_timer);
diff --git a/drivers/gpu/drm/radeon/r600_blit_shaders.c b/drivers/gpu/drm/radeon/r600_blit_shaders.c
index 0271b53fa2d..e8151c1d55b 100644
--- a/drivers/gpu/drm/radeon/r600_blit_shaders.c
+++ b/drivers/gpu/drm/radeon/r600_blit_shaders.c
@@ -39,37 +39,45 @@
const u32 r6xx_default_state[] =
{
- 0xc0002400,
+ 0xc0002400, /* START_3D_CMDBUF */
0x00000000,
- 0xc0012800,
+
+ 0xc0012800, /* CONTEXT_CONTROL */
0x80000000,
0x80000000,
+
0xc0016800,
0x00000010,
- 0x00008000,
+ 0x00008000, /* WAIT_UNTIL */
+
0xc0016800,
0x00000542,
- 0x07000003,
+ 0x07000003, /* TA_CNTL_AUX */
+
0xc0016800,
0x000005c5,
- 0x00000000,
+ 0x00000000, /* VC_ENHANCE */
+
0xc0016800,
0x00000363,
- 0x00000000,
+ 0x00000000, /* SQ_DYN_GPR_CNTL_PS_FLUSH_REQ */
+
0xc0016800,
0x0000060c,
- 0x82000000,
+ 0x82000000, /* DB_DEBUG */
+
0xc0016800,
0x0000060e,
- 0x01020204,
- 0xc0016f00,
- 0x00000000,
- 0x00000000,
- 0xc0016f00,
- 0x00000001,
+ 0x01020204, /* DB_WATERMARKS */
+
+ 0xc0026f00,
0x00000000,
+ 0x00000000, /* SQ_VTX_BASE_VTX_LOC */
+ 0x00000000, /* SQ_VTX_START_INST_LOC */
+
0xc0096900,
0x0000022a,
+ 0x00000000, /* SQ_ESGS_RING_ITEMSIZE */
0x00000000,
0x00000000,
0x00000000,
@@ -78,515 +86,317 @@ const u32 r6xx_default_state[] =
0x00000000,
0x00000000,
0x00000000,
- 0x00000000,
+
0xc0016900,
0x00000004,
- 0x00000000,
- 0xc0016900,
+ 0x00000000, /* DB_DEPTH_INFO */
+
+ 0xc0026900,
0x0000000a,
- 0x00000000,
- 0xc0016900,
- 0x0000000b,
- 0x00000000,
- 0xc0016900,
- 0x0000010c,
- 0x00000000,
- 0xc0016900,
- 0x0000010d,
- 0x00000000,
+ 0x00000000, /* DB_STENCIL_CLEAR */
+ 0x00000000, /* DB_DEPTH_CLEAR */
+
0xc0016900,
0x00000200,
- 0x00000000,
- 0xc0016900,
+ 0x00000000, /* DB_DEPTH_CONTROL */
+
+ 0xc0026900,
0x00000343,
- 0x00000060,
- 0xc0016900,
- 0x00000344,
- 0x00000040,
+ 0x00000060, /* DB_RENDER_CONTROL */
+ 0x00000040, /* DB_RENDER_OVERRIDE */
+
0xc0016900,
0x00000351,
- 0x0000aa00,
- 0xc0016900,
- 0x00000104,
- 0x00000000,
- 0xc0016900,
- 0x0000010e,
- 0x00000000,
- 0xc0046900,
- 0x00000105,
- 0x00000000,
- 0x00000000,
+ 0x0000aa00, /* DB_ALPHA_TO_MASK */
+
+ 0xc00f6900,
+ 0x00000100,
+ 0x00000800, /* VGT_MAX_VTX_INDX */
+ 0x00000000, /* VGT_MIN_VTX_INDX */
+ 0x00000000, /* VGT_INDX_OFFSET */
+ 0x00000000, /* VGT_MULTI_PRIM_IB_RESET_INDX */
+ 0x00000000, /* SX_ALPHA_TEST_CONTROL */
+ 0x00000000, /* CB_BLEND_RED */
0x00000000,
0x00000000,
- 0xc0036900,
- 0x00000109,
0x00000000,
+ 0x00000000, /* CB_FOG_RED */
0x00000000,
0x00000000,
+ 0x00000000, /* DB_STENCILREFMASK */
+ 0x00000000, /* DB_STENCILREFMASK_BF */
+ 0x00000000, /* SX_ALPHA_REF */
+
0xc0046900,
0x0000030c,
- 0x01000000,
+ 0x01000000, /* CB_CLRCMP_CNTL */
0x00000000,
0x00000000,
0x00000000,
+
0xc0046900,
0x00000048,
- 0x3f800000,
+ 0x3f800000, /* CB_CLEAR_RED */
0x00000000,
0x3f800000,
0x3f800000,
- 0xc0016900,
- 0x0000008e,
- 0x0000000f,
+
0xc0016900,
0x00000080,
- 0x00000000,
- 0xc0016900,
+ 0x00000000, /* PA_SC_WINDOW_OFFSET */
+
+ 0xc00a6900,
0x00000083,
- 0x0000ffff,
- 0xc0016900,
- 0x00000084,
- 0x00000000,
- 0xc0016900,
- 0x00000085,
+ 0x0000ffff, /* PA_SC_CLIP_RECT_RULE */
+ 0x00000000, /* PA_SC_CLIPRECT_0_TL */
0x20002000,
- 0xc0016900,
- 0x00000086,
0x00000000,
- 0xc0016900,
- 0x00000087,
0x20002000,
- 0xc0016900,
- 0x00000088,
0x00000000,
- 0xc0016900,
- 0x00000089,
0x20002000,
- 0xc0016900,
- 0x0000008a,
0x00000000,
- 0xc0016900,
- 0x0000008b,
0x20002000,
- 0xc0016900,
- 0x0000008c,
- 0x00000000,
- 0xc0016900,
+ 0x00000000, /* PA_SC_EDGERULE */
+
+ 0xc0406900,
0x00000094,
- 0x80000000,
- 0xc0016900,
- 0x00000095,
+ 0x80000000, /* PA_SC_VPORT_SCISSOR_0_TL */
+ 0x20002000, /* PA_SC_VPORT_SCISSOR_0_BR */
+ 0x80000000, /* PA_SC_VPORT_SCISSOR_1_TL */
0x20002000,
- 0xc0026900,
- 0x000000b4,
- 0x00000000,
- 0x3f800000,
- 0xc0016900,
- 0x00000096,
0x80000000,
- 0xc0016900,
- 0x00000097,
0x20002000,
- 0xc0026900,
- 0x000000b6,
- 0x00000000,
- 0x3f800000,
- 0xc0016900,
- 0x00000098,
0x80000000,
- 0xc0016900,
- 0x00000099,
0x20002000,
- 0xc0026900,
- 0x000000b8,
- 0x00000000,
- 0x3f800000,
- 0xc0016900,
- 0x0000009a,
0x80000000,
- 0xc0016900,
- 0x0000009b,
0x20002000,
- 0xc0026900,
- 0x000000ba,
- 0x00000000,
- 0x3f800000,
- 0xc0016900,
- 0x0000009c,
0x80000000,
- 0xc0016900,
- 0x0000009d,
0x20002000,
- 0xc0026900,
- 0x000000bc,
- 0x00000000,
- 0x3f800000,
- 0xc0016900,
- 0x0000009e,
0x80000000,
- 0xc0016900,
- 0x0000009f,
0x20002000,
- 0xc0026900,
- 0x000000be,
- 0x00000000,
- 0x3f800000,
- 0xc0016900,
- 0x000000a0,
0x80000000,
- 0xc0016900,
- 0x000000a1,
0x20002000,
- 0xc0026900,
- 0x000000c0,
- 0x00000000,
- 0x3f800000,
- 0xc0016900,
- 0x000000a2,
0x80000000,
- 0xc0016900,
- 0x000000a3,
0x20002000,
- 0xc0026900,
- 0x000000c2,
- 0x00000000,
- 0x3f800000,
- 0xc0016900,
- 0x000000a4,
0x80000000,
- 0xc0016900,
- 0x000000a5,
0x20002000,
- 0xc0026900,
- 0x000000c4,
- 0x00000000,
- 0x3f800000,
- 0xc0016900,
- 0x000000a6,
0x80000000,
- 0xc0016900,
- 0x000000a7,
0x20002000,
- 0xc0026900,
- 0x000000c6,
- 0x00000000,
- 0x3f800000,
- 0xc0016900,
- 0x000000a8,
0x80000000,
- 0xc0016900,
- 0x000000a9,
0x20002000,
- 0xc0026900,
- 0x000000c8,
- 0x00000000,
- 0x3f800000,
- 0xc0016900,
- 0x000000aa,
0x80000000,
- 0xc0016900,
- 0x000000ab,
0x20002000,
- 0xc0026900,
- 0x000000ca,
- 0x00000000,
- 0x3f800000,
- 0xc0016900,
- 0x000000ac,
0x80000000,
- 0xc0016900,
- 0x000000ad,
0x20002000,
- 0xc0026900,
- 0x000000cc,
- 0x00000000,
- 0x3f800000,
- 0xc0016900,
- 0x000000ae,
0x80000000,
- 0xc0016900,
- 0x000000af,
0x20002000,
- 0xc0026900,
- 0x000000ce,
- 0x00000000,
- 0x3f800000,
- 0xc0016900,
- 0x000000b0,
0x80000000,
- 0xc0016900,
- 0x000000b1,
0x20002000,
- 0xc0026900,
- 0x000000d0,
- 0x00000000,
+ 0x00000000, /* PA_SC_VPORT_ZMIN_0 */
0x3f800000,
- 0xc0016900,
- 0x000000b2,
- 0x80000000,
- 0xc0016900,
- 0x000000b3,
- 0x20002000,
- 0xc0026900,
- 0x000000d2,
0x00000000,
0x3f800000,
- 0xc0016900,
- 0x00000293,
- 0x00004010,
- 0xc0016900,
- 0x00000300,
0x00000000,
- 0xc0016900,
- 0x00000301,
- 0x00000000,
- 0xc0016900,
- 0x00000312,
- 0xffffffff,
- 0xc0016900,
- 0x00000307,
+ 0x3f800000,
0x00000000,
- 0xc0016900,
- 0x00000308,
+ 0x3f800000,
0x00000000,
- 0xc0016900,
- 0x00000283,
+ 0x3f800000,
0x00000000,
- 0xc0016900,
- 0x00000292,
+ 0x3f800000,
0x00000000,
- 0xc0066900,
- 0x0000010f,
+ 0x3f800000,
0x00000000,
+ 0x3f800000,
0x00000000,
+ 0x3f800000,
0x00000000,
+ 0x3f800000,
0x00000000,
+ 0x3f800000,
0x00000000,
+ 0x3f800000,
0x00000000,
- 0xc0016900,
- 0x00000206,
+ 0x3f800000,
0x00000000,
- 0xc0016900,
- 0x00000207,
+ 0x3f800000,
0x00000000,
- 0xc0016900,
- 0x00000208,
+ 0x3f800000,
0x00000000,
- 0xc0046900,
- 0x00000303,
0x3f800000,
+
+ 0xc0026900,
+ 0x00000292,
+ 0x00000000, /* PA_SC_MPASS_PS_CNTL */
+ 0x00004010, /* PA_SC_MODE_CNTL */
+
+ 0xc0096900,
+ 0x00000300,
+ 0x00000000, /* PA_SC_LINE_CNTL */
+ 0x00000000, /* PA_SC_AA_CONFIG */
+ 0x0000002d, /* PA_SU_VTX_CNTL */
+ 0x3f800000, /* PA_CL_GB_VERT_CLIP_ADJ */
0x3f800000,
0x3f800000,
0x3f800000,
- 0xc0016900,
- 0x00000205,
- 0x00000004,
- 0xc0016900,
- 0x00000280,
- 0x00000000,
- 0xc0016900,
- 0x00000281,
+ 0x00000000, /* PA_SC_SAMPLE_LOCS_MCTX */
0x00000000,
+
0xc0016900,
+ 0x00000312,
+ 0xffffffff, /* PA_SC_AA_MASK */
+
+ 0xc0066900,
0x0000037e,
- 0x00000000,
- 0xc0016900,
- 0x00000382,
- 0x00000000,
- 0xc0016900,
- 0x00000380,
- 0x00000000,
- 0xc0016900,
- 0x00000383,
- 0x00000000,
- 0xc0016900,
- 0x00000381,
- 0x00000000,
- 0xc0016900,
- 0x00000282,
- 0x00000008,
- 0xc0016900,
- 0x00000302,
- 0x0000002d,
- 0xc0016900,
- 0x0000037f,
- 0x00000000,
- 0xc0016900,
- 0x000001b2,
- 0x00000000,
- 0xc0016900,
+ 0x00000000, /* PA_SU_POLY_OFFSET_DB_FMT_CNTL */
+ 0x00000000, /* PA_SU_POLY_OFFSET_CLAMP */
+ 0x00000000, /* PA_SU_POLY_OFFSET_FRONT_SCALE */
+ 0x00000000, /* PA_SU_POLY_OFFSET_FRONT_OFFSET */
+ 0x00000000, /* PA_SU_POLY_OFFSET_BACK_SCALE */
+ 0x00000000, /* PA_SU_POLY_OFFSET_BACK_OFFSET */
+
+ 0xc0046900,
0x000001b6,
- 0x00000000,
- 0xc0016900,
- 0x000001b7,
- 0x00000000,
- 0xc0016900,
- 0x000001b8,
- 0x00000000,
- 0xc0016900,
- 0x000001b9,
- 0x00000000,
+ 0x00000000, /* SPI_INPUT_Z */
+ 0x00000000, /* SPI_FOG_CNTL */
+ 0x00000000, /* SPI_FOG_FUNC_SCALE */
+ 0x00000000, /* SPI_FOG_FUNC_BIAS */
+
0xc0016900,
0x00000225,
- 0x00000000,
+ 0x00000000, /* SQ_PGM_START_FS */
+
0xc0016900,
0x00000229,
- 0x00000000,
+ 0x00000000, /* SQ_PGM_RESOURCES_FS */
+
0xc0016900,
0x00000237,
- 0x00000000,
- 0xc0016900,
- 0x00000100,
- 0x00000800,
- 0xc0016900,
- 0x00000101,
- 0x00000000,
- 0xc0016900,
- 0x00000102,
- 0x00000000,
- 0xc0016900,
+ 0x00000000, /* SQ_PGM_CF_OFFSET_FS */
+
+ 0xc0026900,
0x000002a8,
- 0x00000000,
- 0xc0016900,
- 0x000002a9,
- 0x00000000,
- 0xc0016900,
- 0x00000103,
- 0x00000000,
- 0xc0016900,
- 0x00000284,
- 0x00000000,
- 0xc0016900,
- 0x00000290,
- 0x00000000,
- 0xc0016900,
- 0x00000285,
- 0x00000000,
- 0xc0016900,
- 0x00000286,
- 0x00000000,
- 0xc0016900,
- 0x00000287,
- 0x00000000,
- 0xc0016900,
- 0x00000288,
- 0x00000000,
- 0xc0016900,
- 0x00000289,
- 0x00000000,
- 0xc0016900,
- 0x0000028a,
- 0x00000000,
- 0xc0016900,
- 0x0000028b,
- 0x00000000,
- 0xc0016900,
- 0x0000028c,
- 0x00000000,
- 0xc0016900,
- 0x0000028d,
- 0x00000000,
- 0xc0016900,
- 0x0000028e,
- 0x00000000,
- 0xc0016900,
- 0x0000028f,
- 0x00000000,
+ 0x00000000, /* VGT_INSTANCE_STEP_RATE_0 */
+ 0x00000000, /* VGT_INSTANCE_STEP_RATE_1 */
+
+ 0xc0116900,
+ 0x00000280,
+ 0x00000000, /* PA_SU_POINT_SIZE */
+ 0x00000000, /* PA_SU_POINT_MINMAX */
+ 0x00000008, /* PA_SU_LINE_CNTL */
+ 0x00000000, /* PA_SC_LINE_STIPPLE */
+ 0x00000000, /* VGT_OUTPUT_PATH_CNTL */
+ 0x00000000, /* VGT_HOS_CNTL */
+ 0x00000000, /* VGT_HOS_MAX_TESS_LEVEL */
+ 0x00000000, /* VGT_HOS_MIN_TESS_LEVEL */
+ 0x00000000, /* VGT_HOS_REUSE_DEPTH */
+ 0x00000000, /* VGT_GROUP_PRIM_TYPE */
+ 0x00000000, /* VGT_GROUP_FIRST_DECR */
+ 0x00000000, /* VGT_GROUP_DECR */
+ 0x00000000, /* VGT_GROUP_VECT_0_CNTL */
+ 0x00000000, /* VGT_GROUP_VECT_1_CNTL */
+ 0x00000000, /* VGT_GROUP_VECT_0_FMT_CNTL */
+ 0x00000000, /* VGT_GROUP_VECT_1_FMT_CNTL */
+ 0x00000000, /* VGT_GS_MODE */
+
0xc0016900,
0x000002a1,
- 0x00000000,
+ 0x00000000, /* VGT_PRIMITIVEID_EN */
+
0xc0016900,
0x000002a5,
- 0x00000000,
- 0xc0016900,
+ 0x00000000, /* VGT_MULTI_PRIM_ID_RESET_EN */
+
+ 0xc0036900,
0x000002ac,
- 0x00000000,
- 0xc0016900,
- 0x000002ad,
- 0x00000000,
- 0xc0016900,
- 0x000002ae,
- 0x00000000,
+ 0x00000000, /* VGT_STRMOUT_EN */
+ 0x00000000, /* VGT_REUSE_OFF */
+ 0x00000000, /* VGT_VTX_CNT_EN */
+
0xc0016900,
0x000002c8,
- 0x00000000,
- 0xc0016900,
- 0x00000206,
- 0x00000100,
- 0xc0016900,
- 0x00000204,
- 0x00010000,
- 0xc0036e00,
- 0x00000000,
- 0x00000012,
- 0x00000000,
- 0x00000000,
- 0xc0016900,
- 0x0000008f,
- 0x0000000f,
- 0xc0016900,
- 0x000001e8,
- 0x00000001,
- 0xc0016900,
+ 0x00000000, /* VGT_STRMOUT_BUFFER_EN */
+
+ 0xc0076900,
0x00000202,
- 0x00cc0000,
+ 0x00cc0000, /* CB_COLOR_CONTROL */
+ 0x00000210, /* DB_SHADER_CNTL */
+ 0x00010000, /* PA_CL_CLIP_CNTL */
+ 0x00000244, /* PA_SU_SC_MODE_CNTL */
+ 0x00000100, /* PA_CL_VTE_CNTL */
+ 0x00000000, /* PA_CL_VS_OUT_CNTL */
+ 0x00000000, /* PA_CL_NANINF_CNTL */
+
+ 0xc0026900,
+ 0x0000008e,
+ 0x0000000f, /* CB_TARGET_MASK */
+ 0x0000000f, /* CB_SHADER_MASK */
+
0xc0016900,
- 0x00000205,
- 0x00000244,
+ 0x000001e8,
+ 0x00000001, /* CB_SHADER_CONTROL */
+
0xc0016900,
- 0x00000203,
- 0x00000210,
+ 0x00000185,
+ 0x00000000, /* SPI_VS_OUT_ID_0 */
+
0xc0016900,
+ 0x00000191,
+ 0x00000b00, /* SPI_PS_INPUT_CNTL_0 */
+
+ 0xc0056900,
0x000001b1,
+ 0x00000000, /* SPI_VS_OUT_CONFIG */
+ 0x00000000, /* SPI_THREAD_GROUPING */
+ 0x00000001, /* SPI_PS_IN_CONTROL_0 */
+ 0x00000000, /* SPI_PS_IN_CONTROL_1 */
+ 0x00000000, /* SPI_INTERP_CONTROL_0 */
+
+ 0xc0036e00, /* SET_SAMPLER */
0x00000000,
- 0xc0016900,
- 0x00000185,
- 0x00000000,
- 0xc0016900,
- 0x000001b3,
- 0x00000001,
- 0xc0016900,
- 0x000001b4,
+ 0x00000012,
0x00000000,
- 0xc0016900,
- 0x00000191,
- 0x00000b00,
- 0xc0016900,
- 0x000001b5,
0x00000000,
};
const u32 r7xx_default_state[] =
{
- 0xc0012800,
+ 0xc0012800, /* CONTEXT_CONTROL */
0x80000000,
0x80000000,
+
0xc0016800,
0x00000010,
- 0x00008000,
+ 0x00008000, /* WAIT_UNTIL */
+
0xc0016800,
0x00000542,
- 0x07000002,
+ 0x07000002, /* TA_CNTL_AUX */
+
0xc0016800,
0x000005c5,
- 0x00000000,
+ 0x00000000, /* VC_ENHANCE */
+
0xc0016800,
0x00000363,
- 0x00004000,
+ 0x00004000, /* SQ_DYN_GPR_CNTL_PS_FLUSH_REQ */
+
0xc0016800,
0x0000060c,
- 0x00000000,
+ 0x00000000, /* DB_DEBUG */
+
0xc0016800,
0x0000060e,
- 0x00420204,
- 0xc0016f00,
- 0x00000000,
- 0x00000000,
- 0xc0016f00,
- 0x00000001,
+ 0x00420204, /* DB_WATERMARKS */
+
+ 0xc0026f00,
0x00000000,
+ 0x00000000, /* SQ_VTX_BASE_VTX_LOC */
+ 0x00000000, /* SQ_VTX_START_INST_LOC */
+
0xc0096900,
0x0000022a,
+ 0x00000000, /* SQ_ESGS_RING_ITEMSIZE */
0x00000000,
0x00000000,
0x00000000,
@@ -595,470 +405,269 @@ const u32 r7xx_default_state[] =
0x00000000,
0x00000000,
0x00000000,
- 0x00000000,
+
0xc0016900,
0x00000004,
- 0x00000000,
- 0xc0016900,
+ 0x00000000, /* DB_DEPTH_INFO */
+
+ 0xc0026900,
0x0000000a,
- 0x00000000,
- 0xc0016900,
- 0x0000000b,
- 0x00000000,
- 0xc0016900,
- 0x0000010c,
- 0x00000000,
- 0xc0016900,
- 0x0000010d,
- 0x00000000,
+ 0x00000000, /* DB_STENCIL_CLEAR */
+ 0x00000000, /* DB_DEPTH_CLEAR */
+
0xc0016900,
0x00000200,
- 0x00000000,
- 0xc0016900,
+ 0x00000000, /* DB_DEPTH_CONTROL */
+
+ 0xc0026900,
0x00000343,
- 0x00000060,
- 0xc0016900,
- 0x00000344,
- 0x00000000,
+ 0x00000060, /* DB_RENDER_CONTROL */
+ 0x00000000, /* DB_RENDER_OVERRIDE */
+
0xc0016900,
0x00000351,
- 0x0000aa00,
- 0xc0016900,
- 0x00000104,
- 0x00000000,
- 0xc0016900,
- 0x0000010e,
- 0x00000000,
- 0xc0046900,
- 0x00000105,
- 0x00000000,
+ 0x0000aa00, /* DB_ALPHA_TO_MASK */
+
+ 0xc0096900,
+ 0x00000100,
+ 0x00000800, /* VGT_MAX_VTX_INDX */
+ 0x00000000, /* VGT_MIN_VTX_INDX */
+ 0x00000000, /* VGT_INDX_OFFSET */
+ 0x00000000, /* VGT_MULTI_PRIM_IB_RESET_INDX */
+ 0x00000000, /* SX_ALPHA_TEST_CONTROL */
+ 0x00000000, /* CB_BLEND_RED */
0x00000000,
0x00000000,
0x00000000,
+
+ 0xc0036900,
+ 0x0000010c,
+ 0x00000000, /* DB_STENCILREFMASK */
+ 0x00000000, /* DB_STENCILREFMASK_BF */
+ 0x00000000, /* SX_ALPHA_REF */
+
0xc0046900,
- 0x0000030c,
+ 0x0000030c, /* CB_CLRCMP_CNTL */
0x01000000,
0x00000000,
0x00000000,
0x00000000,
- 0xc0016900,
- 0x0000008e,
- 0x0000000f,
+
0xc0016900,
0x00000080,
- 0x00000000,
- 0xc0016900,
+ 0x00000000, /* PA_SC_WINDOW_OFFSET */
+
+ 0xc00a6900,
0x00000083,
- 0x0000ffff,
- 0xc0016900,
- 0x00000084,
- 0x00000000,
- 0xc0016900,
- 0x00000085,
+ 0x0000ffff, /* PA_SC_CLIP_RECT_RULE */
+ 0x00000000, /* PA_SC_CLIPRECT_0_TL */
0x20002000,
- 0xc0016900,
- 0x00000086,
0x00000000,
- 0xc0016900,
- 0x00000087,
0x20002000,
- 0xc0016900,
- 0x00000088,
0x00000000,
- 0xc0016900,
- 0x00000089,
0x20002000,
- 0xc0016900,
- 0x0000008a,
0x00000000,
- 0xc0016900,
- 0x0000008b,
0x20002000,
- 0xc0016900,
- 0x0000008c,
- 0xaaaaaaaa,
- 0xc0016900,
+ 0xaaaaaaaa, /* PA_SC_EDGERULE */
+
+ 0xc0406900,
0x00000094,
- 0x80000000,
- 0xc0016900,
- 0x00000095,
+ 0x80000000, /* PA_SC_VPORT_SCISSOR_0_TL */
+ 0x20002000, /* PA_SC_VPORT_SCISSOR_0_BR */
+ 0x80000000, /* PA_SC_VPORT_SCISSOR_1_TL */
0x20002000,
- 0xc0026900,
- 0x000000b4,
- 0x00000000,
- 0x3f800000,
- 0xc0016900,
- 0x00000096,
0x80000000,
- 0xc0016900,
- 0x00000097,
0x20002000,
- 0xc0026900,
- 0x000000b6,
- 0x00000000,
- 0x3f800000,
- 0xc0016900,
- 0x00000098,
0x80000000,
- 0xc0016900,
- 0x00000099,
0x20002000,
- 0xc0026900,
- 0x000000b8,
- 0x00000000,
- 0x3f800000,
- 0xc0016900,
- 0x0000009a,
0x80000000,
- 0xc0016900,
- 0x0000009b,
0x20002000,
- 0xc0026900,
- 0x000000ba,
- 0x00000000,
- 0x3f800000,
- 0xc0016900,
- 0x0000009c,
0x80000000,
- 0xc0016900,
- 0x0000009d,
0x20002000,
- 0xc0026900,
- 0x000000bc,
- 0x00000000,
- 0x3f800000,
- 0xc0016900,
- 0x0000009e,
0x80000000,
- 0xc0016900,
- 0x0000009f,
0x20002000,
- 0xc0026900,
- 0x000000be,
- 0x00000000,
- 0x3f800000,
- 0xc0016900,
- 0x000000a0,
0x80000000,
- 0xc0016900,
- 0x000000a1,
0x20002000,
- 0xc0026900,
- 0x000000c0,
- 0x00000000,
- 0x3f800000,
- 0xc0016900,
- 0x000000a2,
0x80000000,
- 0xc0016900,
- 0x000000a3,
0x20002000,
- 0xc0026900,
- 0x000000c2,
- 0x00000000,
- 0x3f800000,
- 0xc0016900,
- 0x000000a4,
0x80000000,
- 0xc0016900,
- 0x000000a5,
0x20002000,
- 0xc0026900,
- 0x000000c4,
- 0x00000000,
- 0x3f800000,
- 0xc0016900,
- 0x000000a6,
0x80000000,
- 0xc0016900,
- 0x000000a7,
0x20002000,
- 0xc0026900,
- 0x000000c6,
- 0x00000000,
- 0x3f800000,
- 0xc0016900,
- 0x000000a8,
0x80000000,
- 0xc0016900,
- 0x000000a9,
0x20002000,
- 0xc0026900,
- 0x000000c8,
- 0x00000000,
- 0x3f800000,
- 0xc0016900,
- 0x000000aa,
0x80000000,
- 0xc0016900,
- 0x000000ab,
0x20002000,
- 0xc0026900,
- 0x000000ca,
- 0x00000000,
- 0x3f800000,
- 0xc0016900,
- 0x000000ac,
0x80000000,
- 0xc0016900,
- 0x000000ad,
0x20002000,
- 0xc0026900,
- 0x000000cc,
- 0x00000000,
- 0x3f800000,
- 0xc0016900,
- 0x000000ae,
0x80000000,
- 0xc0016900,
- 0x000000af,
0x20002000,
- 0xc0026900,
- 0x000000ce,
- 0x00000000,
- 0x3f800000,
- 0xc0016900,
- 0x000000b0,
0x80000000,
- 0xc0016900,
- 0x000000b1,
0x20002000,
- 0xc0026900,
- 0x000000d0,
- 0x00000000,
+ 0x00000000, /* PA_SC_VPORT_ZMIN_0 */
0x3f800000,
- 0xc0016900,
- 0x000000b2,
- 0x80000000,
- 0xc0016900,
- 0x000000b3,
- 0x20002000,
- 0xc0026900,
- 0x000000d2,
0x00000000,
0x3f800000,
- 0xc0016900,
- 0x00000293,
- 0x00514000,
- 0xc0016900,
- 0x00000300,
- 0x00000000,
- 0xc0016900,
- 0x00000301,
0x00000000,
- 0xc0016900,
- 0x00000312,
- 0xffffffff,
- 0xc0016900,
- 0x00000307,
+ 0x3f800000,
0x00000000,
- 0xc0016900,
- 0x00000308,
+ 0x3f800000,
0x00000000,
- 0xc0016900,
- 0x00000283,
+ 0x3f800000,
0x00000000,
- 0xc0016900,
- 0x00000292,
+ 0x3f800000,
0x00000000,
- 0xc0066900,
- 0x0000010f,
+ 0x3f800000,
0x00000000,
+ 0x3f800000,
0x00000000,
+ 0x3f800000,
0x00000000,
+ 0x3f800000,
0x00000000,
+ 0x3f800000,
0x00000000,
+ 0x3f800000,
0x00000000,
- 0xc0016900,
- 0x00000206,
+ 0x3f800000,
0x00000000,
- 0xc0016900,
- 0x00000207,
+ 0x3f800000,
0x00000000,
- 0xc0016900,
- 0x00000208,
+ 0x3f800000,
0x00000000,
- 0xc0046900,
- 0x00000303,
0x3f800000,
+
+ 0xc0026900,
+ 0x00000292,
+ 0x00000000, /* PA_SC_MPASS_PS_CNTL */
+ 0x00514000, /* PA_SC_MODE_CNTL */
+
+ 0xc0096900,
+ 0x00000300,
+ 0x00000000, /* PA_SC_LINE_CNTL */
+ 0x00000000, /* PA_SC_AA_CONFIG */
+ 0x0000002d, /* PA_SU_VTX_CNTL */
+ 0x3f800000, /* PA_CL_GB_VERT_CLIP_ADJ */
0x3f800000,
0x3f800000,
0x3f800000,
- 0xc0016900,
- 0x00000205,
- 0x00000004,
- 0xc0016900,
- 0x00000280,
- 0x00000000,
- 0xc0016900,
- 0x00000281,
+ 0x00000000, /* PA_SC_SAMPLE_LOCS_MCTX */
0x00000000,
+
0xc0016900,
+ 0x00000312,
+ 0xffffffff, /* PA_SC_AA_MASK */
+
+ 0xc0066900,
0x0000037e,
- 0x00000000,
- 0xc0016900,
- 0x00000382,
- 0x00000000,
- 0xc0016900,
- 0x00000380,
- 0x00000000,
- 0xc0016900,
- 0x00000383,
- 0x00000000,
- 0xc0016900,
- 0x00000381,
- 0x00000000,
- 0xc0016900,
- 0x00000282,
- 0x00000008,
- 0xc0016900,
- 0x00000302,
- 0x0000002d,
- 0xc0016900,
- 0x0000037f,
- 0x00000000,
- 0xc0016900,
- 0x000001b2,
- 0x00000001,
- 0xc0016900,
+ 0x00000000, /* PA_SU_POLY_OFFSET_DB_FMT_CNTL */
+ 0x00000000, /* PA_SU_POLY_OFFSET_CLAMP */
+ 0x00000000, /* PA_SU_POLY_OFFSET_FRONT_SCALE */
+ 0x00000000, /* PA_SU_POLY_OFFSET_FRONT_OFFSET */
+ 0x00000000, /* PA_SU_POLY_OFFSET_BACK_SCALE */
+ 0x00000000, /* PA_SU_POLY_OFFSET_BACK_OFFSET */
+
+ 0xc0046900,
0x000001b6,
- 0x00000000,
- 0xc0016900,
- 0x000001b7,
- 0x00000000,
- 0xc0016900,
- 0x000001b8,
- 0x00000000,
- 0xc0016900,
- 0x000001b9,
- 0x00000000,
+ 0x00000000, /* SPI_INPUT_Z */
+ 0x00000000, /* SPI_FOG_CNTL */
+ 0x00000000, /* SPI_FOG_FUNC_SCALE */
+ 0x00000000, /* SPI_FOG_FUNC_BIAS */
+
0xc0016900,
0x00000225,
- 0x00000000,
+ 0x00000000, /* SQ_PGM_START_FS */
+
0xc0016900,
0x00000229,
- 0x00000000,
+ 0x00000000, /* SQ_PGM_RESOURCES_FS */
+
0xc0016900,
0x00000237,
- 0x00000000,
- 0xc0016900,
- 0x00000100,
- 0x00000800,
- 0xc0016900,
- 0x00000101,
- 0x00000000,
- 0xc0016900,
- 0x00000102,
- 0x00000000,
- 0xc0016900,
+ 0x00000000, /* SQ_PGM_CF_OFFSET_FS */
+
+ 0xc0026900,
0x000002a8,
- 0x00000000,
- 0xc0016900,
- 0x000002a9,
- 0x00000000,
- 0xc0016900,
- 0x00000103,
- 0x00000000,
- 0xc0016900,
- 0x00000284,
- 0x00000000,
- 0xc0016900,
- 0x00000290,
- 0x00000000,
- 0xc0016900,
- 0x00000285,
- 0x00000000,
- 0xc0016900,
- 0x00000286,
- 0x00000000,
- 0xc0016900,
- 0x00000287,
- 0x00000000,
- 0xc0016900,
- 0x00000288,
- 0x00000000,
- 0xc0016900,
- 0x00000289,
- 0x00000000,
- 0xc0016900,
- 0x0000028a,
- 0x00000000,
- 0xc0016900,
- 0x0000028b,
- 0x00000000,
- 0xc0016900,
- 0x0000028c,
- 0x00000000,
- 0xc0016900,
- 0x0000028d,
- 0x00000000,
- 0xc0016900,
- 0x0000028e,
- 0x00000000,
- 0xc0016900,
- 0x0000028f,
- 0x00000000,
+ 0x00000000, /* VGT_INSTANCE_STEP_RATE_0 */
+ 0x00000000, /* VGT_INSTANCE_STEP_RATE_1 */
+
+ 0xc0116900,
+ 0x00000280,
+ 0x00000000, /* PA_SU_POINT_SIZE */
+ 0x00000000, /* PA_SU_POINT_MINMAX */
+ 0x00000008, /* PA_SU_LINE_CNTL */
+ 0x00000000, /* PA_SC_LINE_STIPPLE */
+ 0x00000000, /* VGT_OUTPUT_PATH_CNTL */
+ 0x00000000, /* VGT_HOS_CNTL */
+ 0x00000000, /* VGT_HOS_MAX_TESS_LEVEL */
+ 0x00000000, /* VGT_HOS_MIN_TESS_LEVEL */
+ 0x00000000, /* VGT_HOS_REUSE_DEPTH */
+ 0x00000000, /* VGT_GROUP_PRIM_TYPE */
+ 0x00000000, /* VGT_GROUP_FIRST_DECR */
+ 0x00000000, /* VGT_GROUP_DECR */
+ 0x00000000, /* VGT_GROUP_VECT_0_CNTL */
+ 0x00000000, /* VGT_GROUP_VECT_1_CNTL */
+ 0x00000000, /* VGT_GROUP_VECT_0_FMT_CNTL */
+ 0x00000000, /* VGT_GROUP_VECT_1_FMT_CNTL */
+ 0x00000000, /* VGT_GS_MODE */
+
0xc0016900,
0x000002a1,
- 0x00000000,
+ 0x00000000, /* VGT_PRIMITIVEID_EN */
+
0xc0016900,
0x000002a5,
- 0x00000000,
- 0xc0016900,
+ 0x00000000, /* VGT_MULTI_PRIM_ID_RESET_EN */
+
+ 0xc0036900,
0x000002ac,
- 0x00000000,
- 0xc0016900,
- 0x000002ad,
- 0x00000000,
- 0xc0016900,
- 0x000002ae,
- 0x00000000,
+ 0x00000000, /* VGT_STRMOUT_EN */
+ 0x00000000, /* VGT_REUSE_OFF */
+ 0x00000000, /* VGT_VTX_CNT_EN */
+
0xc0016900,
0x000002c8,
- 0x00000000,
- 0xc0016900,
- 0x00000206,
- 0x00000100,
- 0xc0016900,
- 0x00000204,
- 0x00010000,
- 0xc0036e00,
- 0x00000000,
- 0x00000012,
- 0x00000000,
- 0x00000000,
- 0xc0016900,
- 0x0000008f,
- 0x0000000f,
- 0xc0016900,
- 0x000001e8,
- 0x00000001,
- 0xc0016900,
+ 0x00000000, /* VGT_STRMOUT_BUFFER_EN */
+
+ 0xc0076900,
0x00000202,
- 0x00cc0000,
+ 0x00cc0000, /* CB_COLOR_CONTROL */
+ 0x00000210, /* DB_SHADER_CNTL */
+ 0x00010000, /* PA_CL_CLIP_CNTL */
+ 0x00000244, /* PA_SU_SC_MODE_CNTL */
+ 0x00000100, /* PA_CL_VTE_CNTL */
+ 0x00000000, /* PA_CL_VS_OUT_CNTL */
+ 0x00000000, /* PA_CL_NANINF_CNTL */
+
+ 0xc0026900,
+ 0x0000008e,
+ 0x0000000f, /* CB_TARGET_MASK */
+ 0x0000000f, /* CB_SHADER_MASK */
+
0xc0016900,
- 0x00000205,
- 0x00000244,
+ 0x000001e8,
+ 0x00000001, /* CB_SHADER_CONTROL */
+
0xc0016900,
- 0x00000203,
- 0x00000210,
+ 0x00000185,
+ 0x00000000, /* SPI_VS_OUT_ID_0 */
+
0xc0016900,
+ 0x00000191,
+ 0x00000b00, /* SPI_PS_INPUT_CNTL_0 */
+
+ 0xc0056900,
0x000001b1,
+ 0x00000000, /* SPI_VS_OUT_CONFIG */
+ 0x00000001, /* SPI_THREAD_GROUPING */
+ 0x00000001, /* SPI_PS_IN_CONTROL_0 */
+ 0x00000000, /* SPI_PS_IN_CONTROL_1 */
+ 0x00000000, /* SPI_INTERP_CONTROL_0 */
+
+ 0xc0036e00, /* SET_SAMPLER */
0x00000000,
- 0xc0016900,
- 0x00000185,
- 0x00000000,
- 0xc0016900,
- 0x000001b3,
- 0x00000001,
- 0xc0016900,
- 0x000001b4,
+ 0x00000012,
0x00000000,
- 0xc0016900,
- 0x00000191,
- 0x00000b00,
- 0xc0016900,
- 0x000001b5,
0x00000000,
};
diff --git a/drivers/gpu/drm/radeon/r600_cs.c b/drivers/gpu/drm/radeon/r600_cs.c
index 144c32d3713..c3ea212e0c3 100644
--- a/drivers/gpu/drm/radeon/r600_cs.c
+++ b/drivers/gpu/drm/radeon/r600_cs.c
@@ -25,6 +25,7 @@
* Alex Deucher
* Jerome Glisse
*/
+#include <linux/kernel.h>
#include "drmP.h"
#include "radeon.h"
#include "r600d.h"
@@ -166,7 +167,7 @@ static void r600_cs_track_init(struct r600_cs_track *track)
static inline int r600_cs_track_validate_cb(struct radeon_cs_parser *p, int i)
{
struct r600_cs_track *track = p->track;
- u32 bpe = 0, pitch, slice_tile_max, size, tmp, height;
+ u32 bpe = 0, pitch, slice_tile_max, size, tmp, height, pitch_align;
volatile u32 *ib = p->ib->ptr;
if (G_0280A0_TILE_MODE(track->cb_color_info[i])) {
@@ -180,56 +181,57 @@ static inline int r600_cs_track_validate_cb(struct radeon_cs_parser *p, int i)
i, track->cb_color_info[i]);
return -EINVAL;
}
- pitch = (G_028060_PITCH_TILE_MAX(track->cb_color_size[i]) + 1) << 3;
+ /* pitch is the number of 8x8 tiles per row */
+ pitch = G_028060_PITCH_TILE_MAX(track->cb_color_size[i]) + 1;
slice_tile_max = G_028060_SLICE_TILE_MAX(track->cb_color_size[i]) + 1;
- if (!pitch) {
- dev_warn(p->dev, "%s:%d cb pitch (%d) for %d invalid (0x%08X)\n",
- __func__, __LINE__, pitch, i, track->cb_color_size[i]);
- return -EINVAL;
- }
- height = size / (pitch * bpe);
+ height = size / (pitch * 8 * bpe);
if (height > 8192)
height = 8192;
+ if (height > 7)
+ height &= ~0x7;
switch (G_0280A0_ARRAY_MODE(track->cb_color_info[i])) {
case V_0280A0_ARRAY_LINEAR_GENERAL:
+ /* technically height & 0x7 */
+ break;
case V_0280A0_ARRAY_LINEAR_ALIGNED:
- if (pitch & 0x3f) {
- dev_warn(p->dev, "%s:%d cb pitch (%d x %d = %d) invalid\n",
- __func__, __LINE__, pitch, bpe, pitch * bpe);
+ pitch_align = max((u32)64, (u32)(track->group_size / bpe)) / 8;
+ if (!IS_ALIGNED(pitch, pitch_align)) {
+ dev_warn(p->dev, "%s:%d cb pitch (%d) invalid\n",
+ __func__, __LINE__, pitch);
return -EINVAL;
}
- if ((pitch * bpe) & (track->group_size - 1)) {
- dev_warn(p->dev, "%s:%d cb pitch (%d) invalid\n",
- __func__, __LINE__, pitch);
+ if (!IS_ALIGNED(height, 8)) {
+ dev_warn(p->dev, "%s:%d cb height (%d) invalid\n",
+ __func__, __LINE__, height);
return -EINVAL;
}
break;
case V_0280A0_ARRAY_1D_TILED_THIN1:
- if ((pitch * 8 * bpe * track->nsamples) & (track->group_size - 1)) {
+ pitch_align = max((u32)8, (u32)(track->group_size / (8 * bpe * track->nsamples))) / 8;
+ if (!IS_ALIGNED(pitch, pitch_align)) {
dev_warn(p->dev, "%s:%d cb pitch (%d) invalid\n",
- __func__, __LINE__, pitch);
+ __func__, __LINE__, pitch);
+ return -EINVAL;
+ }
+ if (!IS_ALIGNED(height, 8)) {
+ dev_warn(p->dev, "%s:%d cb height (%d) invalid\n",
+ __func__, __LINE__, height);
return -EINVAL;
}
- height &= ~0x7;
- if (!height)
- height = 8;
break;
case V_0280A0_ARRAY_2D_TILED_THIN1:
- if (pitch & ((8 * track->nbanks) - 1)) {
+ pitch_align = max((u32)track->nbanks,
+ (u32)(((track->group_size / 8) / (bpe * track->nsamples)) * track->nbanks));
+ if (!IS_ALIGNED(pitch, pitch_align)) {
dev_warn(p->dev, "%s:%d cb pitch (%d) invalid\n",
__func__, __LINE__, pitch);
return -EINVAL;
}
- tmp = pitch * 8 * bpe * track->nsamples;
- tmp = tmp / track->nbanks;
- if (tmp & (track->group_size - 1)) {
- dev_warn(p->dev, "%s:%d cb pitch (%d) invalid\n",
- __func__, __LINE__, pitch);
+ if (!IS_ALIGNED((height / 8), track->nbanks)) {
+ dev_warn(p->dev, "%s:%d cb height (%d) invalid\n",
+ __func__, __LINE__, height);
return -EINVAL;
}
- height &= ~((16 * track->npipes) - 1);
- if (!height)
- height = 16 * track->npipes;
break;
default:
dev_warn(p->dev, "%s invalid tiling %d for %d (0x%08X)\n", __func__,
@@ -238,16 +240,20 @@ static inline int r600_cs_track_validate_cb(struct radeon_cs_parser *p, int i)
return -EINVAL;
}
/* check offset */
- tmp = height * pitch;
+ tmp = height * pitch * 8 * bpe;
if ((tmp + track->cb_color_bo_offset[i]) > radeon_bo_size(track->cb_color_bo[i])) {
- dev_warn(p->dev, "%s offset[%d] %d to big\n", __func__, i, track->cb_color_bo_offset[i]);
+ dev_warn(p->dev, "%s offset[%d] %d too big\n", __func__, i, track->cb_color_bo_offset[i]);
+ return -EINVAL;
+ }
+ if (!IS_ALIGNED(track->cb_color_bo_offset[i], track->group_size)) {
+ dev_warn(p->dev, "%s offset[%d] %d not aligned\n", __func__, i, track->cb_color_bo_offset[i]);
return -EINVAL;
}
/* limit max tile */
- tmp = (height * pitch) >> 6;
+ tmp = (height * pitch * 8) >> 6;
if (tmp < slice_tile_max)
slice_tile_max = tmp;
- tmp = S_028060_PITCH_TILE_MAX((pitch >> 3) - 1) |
+ tmp = S_028060_PITCH_TILE_MAX(pitch - 1) |
S_028060_SLICE_TILE_MAX(slice_tile_max - 1);
ib[track->cb_color_size_idx[i]] = tmp;
return 0;
@@ -289,7 +295,7 @@ static int r600_cs_track_check(struct radeon_cs_parser *p)
/* Check depth buffer */
if (G_028800_STENCIL_ENABLE(track->db_depth_control) ||
G_028800_Z_ENABLE(track->db_depth_control)) {
- u32 nviews, bpe, ntiles;
+ u32 nviews, bpe, ntiles, pitch, pitch_align, height, size;
if (track->db_bo == NULL) {
dev_warn(p->dev, "z/stencil with no depth buffer\n");
return -EINVAL;
@@ -332,6 +338,51 @@ static int r600_cs_track_check(struct radeon_cs_parser *p)
}
ib[track->db_depth_size_idx] = S_028000_SLICE_TILE_MAX(tmp - 1) | (track->db_depth_size & 0x3FF);
} else {
+ size = radeon_bo_size(track->db_bo);
+ pitch = G_028000_PITCH_TILE_MAX(track->db_depth_size) + 1;
+ height = size / (pitch * 8 * bpe);
+ height &= ~0x7;
+ if (!height)
+ height = 8;
+
+ switch (G_028010_ARRAY_MODE(track->db_depth_info)) {
+ case V_028010_ARRAY_1D_TILED_THIN1:
+ pitch_align = (max((u32)8, (u32)(track->group_size / (8 * bpe))) / 8);
+ if (!IS_ALIGNED(pitch, pitch_align)) {
+ dev_warn(p->dev, "%s:%d db pitch (%d) invalid\n",
+ __func__, __LINE__, pitch);
+ return -EINVAL;
+ }
+ if (!IS_ALIGNED(height, 8)) {
+ dev_warn(p->dev, "%s:%d db height (%d) invalid\n",
+ __func__, __LINE__, height);
+ return -EINVAL;
+ }
+ break;
+ case V_028010_ARRAY_2D_TILED_THIN1:
+ pitch_align = max((u32)track->nbanks,
+ (u32)(((track->group_size / 8) / bpe) * track->nbanks));
+ if (!IS_ALIGNED(pitch, pitch_align)) {
+ dev_warn(p->dev, "%s:%d db pitch (%d) invalid\n",
+ __func__, __LINE__, pitch);
+ return -EINVAL;
+ }
+ if ((height / 8) & (track->nbanks - 1)) {
+ dev_warn(p->dev, "%s:%d db height (%d) invalid\n",
+ __func__, __LINE__, height);
+ return -EINVAL;
+ }
+ break;
+ default:
+ dev_warn(p->dev, "%s invalid tiling %d (0x%08X)\n", __func__,
+ G_028010_ARRAY_MODE(track->db_depth_info),
+ track->db_depth_info);
+ return -EINVAL;
+ }
+ if (!IS_ALIGNED(track->db_offset, track->group_size)) {
+ dev_warn(p->dev, "%s offset[%d] %d not aligned\n", __func__, i, track->db_offset);
+ return -EINVAL;
+ }
ntiles = G_028000_SLICE_TILE_MAX(track->db_depth_size) + 1;
nviews = G_028004_SLICE_MAX(track->db_depth_view) + 1;
tmp = ntiles * bpe * 64 * nviews;
@@ -724,7 +775,25 @@ static inline int r600_cs_check_reg(struct radeon_cs_parser *p, u32 reg, u32 idx
track->db_depth_control = radeon_get_ib_value(p, idx);
break;
case R_028010_DB_DEPTH_INFO:
- track->db_depth_info = radeon_get_ib_value(p, idx);
+ if (r600_cs_packet_next_is_pkt3_nop(p)) {
+ r = r600_cs_packet_next_reloc(p, &reloc);
+ if (r) {
+ dev_warn(p->dev, "bad SET_CONTEXT_REG "
+ "0x%04X\n", reg);
+ return -EINVAL;
+ }
+ track->db_depth_info = radeon_get_ib_value(p, idx);
+ ib[idx] &= C_028010_ARRAY_MODE;
+ track->db_depth_info &= C_028010_ARRAY_MODE;
+ if (reloc->lobj.tiling_flags & RADEON_TILING_MACRO) {
+ ib[idx] |= S_028010_ARRAY_MODE(V_028010_ARRAY_2D_TILED_THIN1);
+ track->db_depth_info |= S_028010_ARRAY_MODE(V_028010_ARRAY_2D_TILED_THIN1);
+ } else {
+ ib[idx] |= S_028010_ARRAY_MODE(V_028010_ARRAY_1D_TILED_THIN1);
+ track->db_depth_info |= S_028010_ARRAY_MODE(V_028010_ARRAY_1D_TILED_THIN1);
+ }
+ } else
+ track->db_depth_info = radeon_get_ib_value(p, idx);
break;
case R_028004_DB_DEPTH_VIEW:
track->db_depth_view = radeon_get_ib_value(p, idx);
@@ -757,8 +826,25 @@ static inline int r600_cs_check_reg(struct radeon_cs_parser *p, u32 reg, u32 idx
case R_0280B4_CB_COLOR5_INFO:
case R_0280B8_CB_COLOR6_INFO:
case R_0280BC_CB_COLOR7_INFO:
- tmp = (reg - R_0280A0_CB_COLOR0_INFO) / 4;
- track->cb_color_info[tmp] = radeon_get_ib_value(p, idx);
+ if (r600_cs_packet_next_is_pkt3_nop(p)) {
+ r = r600_cs_packet_next_reloc(p, &reloc);
+ if (r) {
+ dev_err(p->dev, "bad SET_CONTEXT_REG 0x%04X\n", reg);
+ return -EINVAL;
+ }
+ tmp = (reg - R_0280A0_CB_COLOR0_INFO) / 4;
+ track->cb_color_info[tmp] = radeon_get_ib_value(p, idx);
+ if (reloc->lobj.tiling_flags & RADEON_TILING_MACRO) {
+ ib[idx] |= S_0280A0_ARRAY_MODE(V_0280A0_ARRAY_2D_TILED_THIN1);
+ track->cb_color_info[tmp] |= S_0280A0_ARRAY_MODE(V_0280A0_ARRAY_2D_TILED_THIN1);
+ } else if (reloc->lobj.tiling_flags & RADEON_TILING_MICRO) {
+ ib[idx] |= S_0280A0_ARRAY_MODE(V_0280A0_ARRAY_1D_TILED_THIN1);
+ track->cb_color_info[tmp] |= S_0280A0_ARRAY_MODE(V_0280A0_ARRAY_1D_TILED_THIN1);
+ }
+ } else {
+ tmp = (reg - R_0280A0_CB_COLOR0_INFO) / 4;
+ track->cb_color_info[tmp] = radeon_get_ib_value(p, idx);
+ }
break;
case R_028060_CB_COLOR0_SIZE:
case R_028064_CB_COLOR1_SIZE:
@@ -946,8 +1032,9 @@ static inline unsigned minify(unsigned size, unsigned levels)
}
static void r600_texture_size(unsigned nfaces, unsigned blevel, unsigned nlevels,
- unsigned w0, unsigned h0, unsigned d0, unsigned bpe,
- unsigned *l0_size, unsigned *mipmap_size)
+ unsigned w0, unsigned h0, unsigned d0, unsigned bpe,
+ unsigned pitch_align,
+ unsigned *l0_size, unsigned *mipmap_size)
{
unsigned offset, i, level, face;
unsigned width, height, depth, rowstride, size;
@@ -960,13 +1047,13 @@ static void r600_texture_size(unsigned nfaces, unsigned blevel, unsigned nlevels
height = minify(h0, i);
depth = minify(d0, i);
for(face = 0; face < nfaces; face++) {
- rowstride = ((width * bpe) + 255) & ~255;
+ rowstride = ALIGN((width * bpe), pitch_align);
size = height * rowstride * depth;
offset += size;
offset = (offset + 0x1f) & ~0x1f;
}
}
- *l0_size = (((w0 * bpe) + 255) & ~255) * h0 * d0;
+ *l0_size = ALIGN((w0 * bpe), pitch_align) * h0 * d0;
*mipmap_size = offset;
if (!blevel)
*mipmap_size -= *l0_size;
@@ -985,16 +1072,23 @@ static void r600_texture_size(unsigned nfaces, unsigned blevel, unsigned nlevels
* the texture and mipmap bo object are big enough to cover this resource.
*/
static inline int r600_check_texture_resource(struct radeon_cs_parser *p, u32 idx,
- struct radeon_bo *texture,
- struct radeon_bo *mipmap)
+ struct radeon_bo *texture,
+ struct radeon_bo *mipmap,
+ u32 tiling_flags)
{
+ struct r600_cs_track *track = p->track;
u32 nfaces, nlevels, blevel, w0, h0, d0, bpe = 0;
- u32 word0, word1, l0_size, mipmap_size;
+ u32 word0, word1, l0_size, mipmap_size, pitch, pitch_align;
/* on legacy kernel we don't perform advanced check */
if (p->rdev == NULL)
return 0;
+
word0 = radeon_get_ib_value(p, idx + 0);
+ if (tiling_flags & RADEON_TILING_MACRO)
+ word0 |= S_038000_TILE_MODE(V_038000_ARRAY_2D_TILED_THIN1);
+ else if (tiling_flags & RADEON_TILING_MICRO)
+ word0 |= S_038000_TILE_MODE(V_038000_ARRAY_1D_TILED_THIN1);
word1 = radeon_get_ib_value(p, idx + 1);
w0 = G_038000_TEX_WIDTH(word0) + 1;
h0 = G_038004_TEX_HEIGHT(word1) + 1;
@@ -1021,11 +1115,55 @@ static inline int r600_check_texture_resource(struct radeon_cs_parser *p, u32 i
__func__, __LINE__, G_038004_DATA_FORMAT(word1));
return -EINVAL;
}
+
+ pitch = G_038000_PITCH(word0) + 1;
+ switch (G_038000_TILE_MODE(word0)) {
+ case V_038000_ARRAY_LINEAR_GENERAL:
+ pitch_align = 1;
+ /* XXX check height align */
+ break;
+ case V_038000_ARRAY_LINEAR_ALIGNED:
+ pitch_align = max((u32)64, (u32)(track->group_size / bpe)) / 8;
+ if (!IS_ALIGNED(pitch, pitch_align)) {
+ dev_warn(p->dev, "%s:%d tex pitch (%d) invalid\n",
+ __func__, __LINE__, pitch);
+ return -EINVAL;
+ }
+ /* XXX check height align */
+ break;
+ case V_038000_ARRAY_1D_TILED_THIN1:
+ pitch_align = max((u32)8, (u32)(track->group_size / (8 * bpe))) / 8;
+ if (!IS_ALIGNED(pitch, pitch_align)) {
+ dev_warn(p->dev, "%s:%d tex pitch (%d) invalid\n",
+ __func__, __LINE__, pitch);
+ return -EINVAL;
+ }
+ /* XXX check height align */
+ break;
+ case V_038000_ARRAY_2D_TILED_THIN1:
+ pitch_align = max((u32)track->nbanks,
+ (u32)(((track->group_size / 8) / bpe) * track->nbanks));
+ if (!IS_ALIGNED(pitch, pitch_align)) {
+ dev_warn(p->dev, "%s:%d tex pitch (%d) invalid\n",
+ __func__, __LINE__, pitch);
+ return -EINVAL;
+ }
+ /* XXX check height align */
+ break;
+ default:
+ dev_warn(p->dev, "%s invalid tiling %d (0x%08X)\n", __func__,
+ G_038000_TILE_MODE(word0), word0);
+ return -EINVAL;
+ }
+ /* XXX check offset align */
+
word0 = radeon_get_ib_value(p, idx + 4);
word1 = radeon_get_ib_value(p, idx + 5);
blevel = G_038010_BASE_LEVEL(word0);
nlevels = G_038014_LAST_LEVEL(word1);
- r600_texture_size(nfaces, blevel, nlevels, w0, h0, d0, bpe, &l0_size, &mipmap_size);
+ r600_texture_size(nfaces, blevel, nlevels, w0, h0, d0, bpe,
+ (pitch_align * bpe),
+ &l0_size, &mipmap_size);
/* using get ib will give us the offset into the texture bo */
word0 = radeon_get_ib_value(p, idx + 2);
if ((l0_size + word0) > radeon_bo_size(texture)) {
@@ -1239,6 +1377,10 @@ static int r600_packet3_check(struct radeon_cs_parser *p,
return -EINVAL;
}
ib[idx+1+(i*7)+2] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff);
+ if (reloc->lobj.tiling_flags & RADEON_TILING_MACRO)
+ ib[idx+1+(i*7)+0] |= S_038000_TILE_MODE(V_038000_ARRAY_2D_TILED_THIN1);
+ else if (reloc->lobj.tiling_flags & RADEON_TILING_MICRO)
+ ib[idx+1+(i*7)+0] |= S_038000_TILE_MODE(V_038000_ARRAY_1D_TILED_THIN1);
texture = reloc->robj;
/* tex mip base */
r = r600_cs_packet_next_reloc(p, &reloc);
@@ -1249,7 +1391,7 @@ static int r600_packet3_check(struct radeon_cs_parser *p,
ib[idx+1+(i*7)+3] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff);
mipmap = reloc->robj;
r = r600_check_texture_resource(p, idx+(i*7)+1,
- texture, mipmap);
+ texture, mipmap, reloc->lobj.tiling_flags);
if (r)
return r;
break;
diff --git a/drivers/gpu/drm/radeon/r600_hdmi.c b/drivers/gpu/drm/radeon/r600_hdmi.c
index 26b4bc9d89a..e6a58ed48dc 100644
--- a/drivers/gpu/drm/radeon/r600_hdmi.c
+++ b/drivers/gpu/drm/radeon/r600_hdmi.c
@@ -435,7 +435,8 @@ static int r600_hdmi_find_free_block(struct drm_device *dev)
}
}
- if (rdev->family == CHIP_RS600 || rdev->family == CHIP_RS690) {
+ if (rdev->family == CHIP_RS600 || rdev->family == CHIP_RS690 ||
+ rdev->family == CHIP_RS740) {
return free_blocks[0] ? R600_HDMI_BLOCK1 : 0;
} else if (rdev->family >= CHIP_R600) {
if (free_blocks[0])
@@ -466,7 +467,8 @@ static void r600_hdmi_assign_block(struct drm_encoder *encoder)
if (ASIC_IS_DCE32(rdev))
radeon_encoder->hdmi_config_offset = dig->dig_encoder ?
R600_HDMI_CONFIG2 : R600_HDMI_CONFIG1;
- } else if (rdev->family >= CHIP_R600) {
+ } else if (rdev->family >= CHIP_R600 || rdev->family == CHIP_RS600 ||
+ rdev->family == CHIP_RS690 || rdev->family == CHIP_RS740) {
radeon_encoder->hdmi_offset = r600_hdmi_find_free_block(dev);
}
}
diff --git a/drivers/gpu/drm/radeon/r600d.h b/drivers/gpu/drm/radeon/r600d.h
index 59c1f8793e6..858a1920c0d 100644
--- a/drivers/gpu/drm/radeon/r600d.h
+++ b/drivers/gpu/drm/radeon/r600d.h
@@ -239,12 +239,18 @@
#define GRBM_SOFT_RESET 0x8020
#define SOFT_RESET_CP (1<<0)
+#define CG_THERMAL_STATUS 0x7F4
+#define ASIC_T(x) ((x) << 0)
+#define ASIC_T_MASK 0x1FF
+#define ASIC_T_SHIFT 0
+
#define HDP_HOST_PATH_CNTL 0x2C00
#define HDP_NONSURFACE_BASE 0x2C04
#define HDP_NONSURFACE_INFO 0x2C08
#define HDP_NONSURFACE_SIZE 0x2C0C
#define HDP_REG_COHERENCY_FLUSH_CNTL 0x54A0
#define HDP_TILING_CONFIG 0x2F3C
+#define HDP_DEBUG1 0x2F34
#define MC_VM_AGP_TOP 0x2184
#define MC_VM_AGP_BOT 0x2188
@@ -1154,6 +1160,10 @@
#define S_038000_TILE_MODE(x) (((x) & 0xF) << 3)
#define G_038000_TILE_MODE(x) (((x) >> 3) & 0xF)
#define C_038000_TILE_MODE 0xFFFFFF87
+#define V_038000_ARRAY_LINEAR_GENERAL 0x00000000
+#define V_038000_ARRAY_LINEAR_ALIGNED 0x00000001
+#define V_038000_ARRAY_1D_TILED_THIN1 0x00000002
+#define V_038000_ARRAY_2D_TILED_THIN1 0x00000004
#define S_038000_TILE_TYPE(x) (((x) & 0x1) << 7)
#define G_038000_TILE_TYPE(x) (((x) >> 7) & 0x1)
#define C_038000_TILE_TYPE 0xFFFFFF7F
@@ -1357,6 +1367,8 @@
#define S_028010_ARRAY_MODE(x) (((x) & 0xF) << 15)
#define G_028010_ARRAY_MODE(x) (((x) >> 15) & 0xF)
#define C_028010_ARRAY_MODE 0xFFF87FFF
+#define V_028010_ARRAY_1D_TILED_THIN1 0x00000002
+#define V_028010_ARRAY_2D_TILED_THIN1 0x00000004
#define S_028010_TILE_SURFACE_ENABLE(x) (((x) & 0x1) << 25)
#define G_028010_TILE_SURFACE_ENABLE(x) (((x) >> 25) & 0x1)
#define C_028010_TILE_SURFACE_ENABLE 0xFDFFFFFF
diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h
index 2f94dc66c18..3cd1c470b77 100644
--- a/drivers/gpu/drm/radeon/radeon.h
+++ b/drivers/gpu/drm/radeon/radeon.h
@@ -178,6 +178,9 @@ void radeon_combios_get_power_modes(struct radeon_device *rdev);
void radeon_atombios_get_power_modes(struct radeon_device *rdev);
void radeon_atom_set_voltage(struct radeon_device *rdev, u16 level);
void rs690_pm_info(struct radeon_device *rdev);
+extern u32 rv6xx_get_temp(struct radeon_device *rdev);
+extern u32 rv770_get_temp(struct radeon_device *rdev);
+extern u32 evergreen_get_temp(struct radeon_device *rdev);
/*
* Fences.
@@ -232,7 +235,7 @@ struct radeon_surface_reg {
*/
struct radeon_mman {
struct ttm_bo_global_ref bo_global_ref;
- struct ttm_global_reference mem_global_ref;
+ struct drm_global_reference mem_global_ref;
struct ttm_bo_device bdev;
bool mem_global_referenced;
bool initialized;
@@ -671,6 +674,13 @@ struct radeon_pm_profile {
int dpms_on_cm_idx;
};
+enum radeon_int_thermal_type {
+ THERMAL_TYPE_NONE,
+ THERMAL_TYPE_RV6XX,
+ THERMAL_TYPE_RV770,
+ THERMAL_TYPE_EVERGREEN,
+};
+
struct radeon_voltage {
enum radeon_voltage_type type;
/* gpio voltage */
@@ -766,6 +776,9 @@ struct radeon_pm {
enum radeon_pm_profile_type profile;
int profile_index;
struct radeon_pm_profile profiles[PM_PROFILE_MAX];
+ /* internal thermal controller on rv6xx+ */
+ enum radeon_int_thermal_type int_thermal_type;
+ struct device *int_hwmon_dev;
};
@@ -902,6 +915,7 @@ struct r600_asic {
unsigned tiling_nbanks;
unsigned tiling_npipes;
unsigned tiling_group_size;
+ unsigned tile_config;
struct r100_gpu_lockup lockup;
};
@@ -926,6 +940,7 @@ struct rv770_asic {
unsigned tiling_nbanks;
unsigned tiling_npipes;
unsigned tiling_group_size;
+ unsigned tile_config;
struct r100_gpu_lockup lockup;
};
@@ -951,6 +966,7 @@ struct evergreen_asic {
unsigned tiling_nbanks;
unsigned tiling_npipes;
unsigned tiling_group_size;
+ unsigned tile_config;
};
union radeon_asic_config {
@@ -1033,6 +1049,9 @@ struct radeon_device {
uint32_t pcie_reg_mask;
radeon_rreg_t pciep_rreg;
radeon_wreg_t pciep_wreg;
+ /* io port */
+ void __iomem *rio_mem;
+ resource_size_t rio_mem_size;
struct radeon_clock clock;
struct radeon_mc mc;
struct radeon_gart gart;
@@ -1069,6 +1088,7 @@ struct radeon_device {
struct mutex vram_mutex;
/* audio stuff */
+ bool audio_enabled;
struct timer_list audio_timer;
int audio_channels;
int audio_rate;
@@ -1078,6 +1098,8 @@ struct radeon_device {
bool powered_down;
struct notifier_block acpi_nb;
+ /* only one userspace can use Hyperz features at a time */
+ struct drm_file *hyperz_filp;
};
int radeon_device_init(struct radeon_device *rdev,
@@ -1114,6 +1136,26 @@ static inline void r100_mm_wreg(struct radeon_device *rdev, uint32_t reg, uint32
}
}
+static inline u32 r100_io_rreg(struct radeon_device *rdev, u32 reg)
+{
+ if (reg < rdev->rio_mem_size)
+ return ioread32(rdev->rio_mem + reg);
+ else {
+ iowrite32(reg, rdev->rio_mem + RADEON_MM_INDEX);
+ return ioread32(rdev->rio_mem + RADEON_MM_DATA);
+ }
+}
+
+static inline void r100_io_wreg(struct radeon_device *rdev, u32 reg, u32 v)
+{
+ if (reg < rdev->rio_mem_size)
+ iowrite32(v, rdev->rio_mem + reg);
+ else {
+ iowrite32(reg, rdev->rio_mem + RADEON_MM_INDEX);
+ iowrite32(v, rdev->rio_mem + RADEON_MM_DATA);
+ }
+}
+
/*
* Cast helper
*/
@@ -1152,6 +1194,8 @@ static inline void r100_mm_wreg(struct radeon_device *rdev, uint32_t reg, uint32
WREG32_PLL(reg, tmp_); \
} while (0)
#define DREG32_SYS(sqf, rdev, reg) seq_printf((sqf), #reg " : 0x%08X\n", r100_mm_rreg((rdev), (reg)))
+#define RREG32_IO(reg) r100_io_rreg(rdev, (reg))
+#define WREG32_IO(reg, v) r100_io_wreg(rdev, (reg), (v))
/*
* Indirect registers accessor
@@ -1415,6 +1459,13 @@ extern void r700_cp_fini(struct radeon_device *rdev);
extern void evergreen_disable_interrupt_state(struct radeon_device *rdev);
extern int evergreen_irq_set(struct radeon_device *rdev);
+/* radeon_acpi.c */
+#if defined(CONFIG_ACPI)
+extern int radeon_acpi_init(struct radeon_device *rdev);
+#else
+static inline int radeon_acpi_init(struct radeon_device *rdev) { return 0; }
+#endif
+
/* evergreen */
struct evergreen_mc_save {
u32 vga_control[6];
diff --git a/drivers/gpu/drm/radeon/radeon_acpi.c b/drivers/gpu/drm/radeon/radeon_acpi.c
new file mode 100644
index 00000000000..3f6636bb2d7
--- /dev/null
+++ b/drivers/gpu/drm/radeon/radeon_acpi.c
@@ -0,0 +1,67 @@
+#include <linux/pci.h>
+#include <linux/acpi.h>
+#include <linux/slab.h>
+#include <acpi/acpi_drivers.h>
+#include <acpi/acpi_bus.h>
+
+#include "drmP.h"
+#include "drm.h"
+#include "drm_sarea.h"
+#include "drm_crtc_helper.h"
+#include "radeon.h"
+
+#include <linux/vga_switcheroo.h>
+
+/* Call the ATIF method
+ *
+ * Note: currently we discard the output
+ */
+static int radeon_atif_call(acpi_handle handle)
+{
+ acpi_status status;
+ union acpi_object atif_arg_elements[2];
+ struct acpi_object_list atif_arg;
+ struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL};
+
+ atif_arg.count = 2;
+ atif_arg.pointer = &atif_arg_elements[0];
+
+ atif_arg_elements[0].type = ACPI_TYPE_INTEGER;
+ atif_arg_elements[0].integer.value = 0;
+ atif_arg_elements[1].type = ACPI_TYPE_INTEGER;
+ atif_arg_elements[1].integer.value = 0;
+
+ status = acpi_evaluate_object(handle, "ATIF", &atif_arg, &buffer);
+
+ /* Fail only if calling the method fails and ATIF is supported */
+ if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) {
+ printk(KERN_DEBUG "failed to evaluate ATIF got %s\n", acpi_format_exception(status));
+ kfree(buffer.pointer);
+ return 1;
+ }
+
+ kfree(buffer.pointer);
+ return 0;
+}
+
+/* Call all ACPI methods here */
+int radeon_acpi_init(struct radeon_device *rdev)
+{
+ acpi_handle handle;
+ int ret;
+
+ /* No need to proceed if we're sure that ATIF is not supported */
+ if (!ASIC_IS_AVIVO(rdev) || !rdev->bios)
+ return 0;
+
+ /* Get the device handle */
+ handle = DEVICE_ACPI_HANDLE(&rdev->pdev->dev);
+
+ /* Call the ATIF method */
+ ret = radeon_atif_call(handle);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
diff --git a/drivers/gpu/drm/radeon/radeon_asic.h b/drivers/gpu/drm/radeon/radeon_asic.h
index c0bbaa64157..a5aff755f0d 100644
--- a/drivers/gpu/drm/radeon/radeon_asic.h
+++ b/drivers/gpu/drm/radeon/radeon_asic.h
@@ -113,6 +113,7 @@ void r100_wb_fini(struct radeon_device *rdev);
int r100_wb_init(struct radeon_device *rdev);
int r100_cp_reset(struct radeon_device *rdev);
void r100_vga_render_disable(struct radeon_device *rdev);
+void r100_restore_sanity(struct radeon_device *rdev);
int r100_cs_track_check_pkt3_indx_buffer(struct radeon_cs_parser *p,
struct radeon_cs_packet *pkt,
struct radeon_bo *robj);
diff --git a/drivers/gpu/drm/radeon/radeon_atombios.c b/drivers/gpu/drm/radeon/radeon_atombios.c
index 10673ae59cf..3bc2bcdf530 100644
--- a/drivers/gpu/drm/radeon/radeon_atombios.c
+++ b/drivers/gpu/drm/radeon/radeon_atombios.c
@@ -723,7 +723,7 @@ bool radeon_get_atom_connector_info_from_supported_devices_table(struct
}
if (i == ATOM_DEVICE_CV_INDEX) {
- DRM_DEBUG("Skipping Component Video\n");
+ DRM_DEBUG_KMS("Skipping Component Video\n");
continue;
}
@@ -1032,21 +1032,18 @@ bool radeon_atombios_sideport_present(struct radeon_device *rdev)
u8 frev, crev;
u16 data_offset;
+ /* sideport is AMD only */
+ if (rdev->family == CHIP_RS600)
+ return false;
+
if (atom_parse_data_header(mode_info->atom_context, index, NULL,
&frev, &crev, &data_offset)) {
igp_info = (union igp_info *)(mode_info->atom_context->bios +
data_offset);
switch (crev) {
case 1:
- /* AMD IGPS */
- if ((rdev->family == CHIP_RS690) ||
- (rdev->family == CHIP_RS740)) {
- if (igp_info->info.ulBootUpMemoryClock)
- return true;
- } else {
- if (igp_info->info.ucMemoryType & 0xf0)
- return true;
- }
+ if (igp_info->info.ulBootUpMemoryClock)
+ return true;
break;
case 2:
if (igp_info->info_2.ucMemoryType & 0x0f)
@@ -1095,7 +1092,7 @@ bool radeon_atombios_get_tmds_info(struct radeon_encoder *encoder,
(tmds_info->asMiscInfo[i].
ucPLL_VoltageSwing & 0xf) << 16;
- DRM_DEBUG("TMDS PLL From ATOMBIOS %u %x\n",
+ DRM_DEBUG_KMS("TMDS PLL From ATOMBIOS %u %x\n",
tmds->tmds_pll[i].freq,
tmds->tmds_pll[i].value);
@@ -1789,14 +1786,22 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev)
}
/* add the i2c bus for thermal/fan chip */
- /* no support for internal controller yet */
if (controller->ucType > 0) {
- if ((controller->ucType == ATOM_PP_THERMALCONTROLLER_RV6xx) ||
- (controller->ucType == ATOM_PP_THERMALCONTROLLER_RV770) ||
- (controller->ucType == ATOM_PP_THERMALCONTROLLER_EVERGREEN)) {
+ if (controller->ucType == ATOM_PP_THERMALCONTROLLER_RV6xx) {
+ DRM_INFO("Internal thermal controller %s fan control\n",
+ (controller->ucFanParameters &
+ ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with");
+ rdev->pm.int_thermal_type = THERMAL_TYPE_RV6XX;
+ } else if (controller->ucType == ATOM_PP_THERMALCONTROLLER_RV770) {
+ DRM_INFO("Internal thermal controller %s fan control\n",
+ (controller->ucFanParameters &
+ ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with");
+ rdev->pm.int_thermal_type = THERMAL_TYPE_RV770;
+ } else if (controller->ucType == ATOM_PP_THERMALCONTROLLER_EVERGREEN) {
DRM_INFO("Internal thermal controller %s fan control\n",
(controller->ucFanParameters &
ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with");
+ rdev->pm.int_thermal_type = THERMAL_TYPE_EVERGREEN;
} else if ((controller->ucType ==
ATOM_PP_THERMALCONTROLLER_EXTERNAL_GPIO) ||
(controller->ucType ==
@@ -2179,11 +2184,11 @@ radeon_atombios_connected_scratch_regs(struct drm_connector *connector,
if ((radeon_encoder->devices & ATOM_DEVICE_TV1_SUPPORT) &&
(radeon_connector->devices & ATOM_DEVICE_TV1_SUPPORT)) {
if (connected) {
- DRM_DEBUG("TV1 connected\n");
+ DRM_DEBUG_KMS("TV1 connected\n");
bios_3_scratch |= ATOM_S3_TV1_ACTIVE;
bios_6_scratch |= ATOM_S6_ACC_REQ_TV1;
} else {
- DRM_DEBUG("TV1 disconnected\n");
+ DRM_DEBUG_KMS("TV1 disconnected\n");
bios_0_scratch &= ~ATOM_S0_TV1_MASK;
bios_3_scratch &= ~ATOM_S3_TV1_ACTIVE;
bios_6_scratch &= ~ATOM_S6_ACC_REQ_TV1;
@@ -2192,11 +2197,11 @@ radeon_atombios_connected_scratch_regs(struct drm_connector *connector,
if ((radeon_encoder->devices & ATOM_DEVICE_CV_SUPPORT) &&
(radeon_connector->devices & ATOM_DEVICE_CV_SUPPORT)) {
if (connected) {
- DRM_DEBUG("CV connected\n");
+ DRM_DEBUG_KMS("CV connected\n");
bios_3_scratch |= ATOM_S3_CV_ACTIVE;
bios_6_scratch |= ATOM_S6_ACC_REQ_CV;
} else {
- DRM_DEBUG("CV disconnected\n");
+ DRM_DEBUG_KMS("CV disconnected\n");
bios_0_scratch &= ~ATOM_S0_CV_MASK;
bios_3_scratch &= ~ATOM_S3_CV_ACTIVE;
bios_6_scratch &= ~ATOM_S6_ACC_REQ_CV;
@@ -2205,12 +2210,12 @@ radeon_atombios_connected_scratch_regs(struct drm_connector *connector,
if ((radeon_encoder->devices & ATOM_DEVICE_LCD1_SUPPORT) &&
(radeon_connector->devices & ATOM_DEVICE_LCD1_SUPPORT)) {
if (connected) {
- DRM_DEBUG("LCD1 connected\n");
+ DRM_DEBUG_KMS("LCD1 connected\n");
bios_0_scratch |= ATOM_S0_LCD1;
bios_3_scratch |= ATOM_S3_LCD1_ACTIVE;
bios_6_scratch |= ATOM_S6_ACC_REQ_LCD1;
} else {
- DRM_DEBUG("LCD1 disconnected\n");
+ DRM_DEBUG_KMS("LCD1 disconnected\n");
bios_0_scratch &= ~ATOM_S0_LCD1;
bios_3_scratch &= ~ATOM_S3_LCD1_ACTIVE;
bios_6_scratch &= ~ATOM_S6_ACC_REQ_LCD1;
@@ -2219,12 +2224,12 @@ radeon_atombios_connected_scratch_regs(struct drm_connector *connector,
if ((radeon_encoder->devices & ATOM_DEVICE_CRT1_SUPPORT) &&
(radeon_connector->devices & ATOM_DEVICE_CRT1_SUPPORT)) {
if (connected) {
- DRM_DEBUG("CRT1 connected\n");
+ DRM_DEBUG_KMS("CRT1 connected\n");
bios_0_scratch |= ATOM_S0_CRT1_COLOR;
bios_3_scratch |= ATOM_S3_CRT1_ACTIVE;
bios_6_scratch |= ATOM_S6_ACC_REQ_CRT1;
} else {
- DRM_DEBUG("CRT1 disconnected\n");
+ DRM_DEBUG_KMS("CRT1 disconnected\n");
bios_0_scratch &= ~ATOM_S0_CRT1_MASK;
bios_3_scratch &= ~ATOM_S3_CRT1_ACTIVE;
bios_6_scratch &= ~ATOM_S6_ACC_REQ_CRT1;
@@ -2233,12 +2238,12 @@ radeon_atombios_connected_scratch_regs(struct drm_connector *connector,
if ((radeon_encoder->devices & ATOM_DEVICE_CRT2_SUPPORT) &&
(radeon_connector->devices & ATOM_DEVICE_CRT2_SUPPORT)) {
if (connected) {
- DRM_DEBUG("CRT2 connected\n");
+ DRM_DEBUG_KMS("CRT2 connected\n");
bios_0_scratch |= ATOM_S0_CRT2_COLOR;
bios_3_scratch |= ATOM_S3_CRT2_ACTIVE;
bios_6_scratch |= ATOM_S6_ACC_REQ_CRT2;
} else {
- DRM_DEBUG("CRT2 disconnected\n");
+ DRM_DEBUG_KMS("CRT2 disconnected\n");
bios_0_scratch &= ~ATOM_S0_CRT2_MASK;
bios_3_scratch &= ~ATOM_S3_CRT2_ACTIVE;
bios_6_scratch &= ~ATOM_S6_ACC_REQ_CRT2;
@@ -2247,12 +2252,12 @@ radeon_atombios_connected_scratch_regs(struct drm_connector *connector,
if ((radeon_encoder->devices & ATOM_DEVICE_DFP1_SUPPORT) &&
(radeon_connector->devices & ATOM_DEVICE_DFP1_SUPPORT)) {
if (connected) {
- DRM_DEBUG("DFP1 connected\n");
+ DRM_DEBUG_KMS("DFP1 connected\n");
bios_0_scratch |= ATOM_S0_DFP1;
bios_3_scratch |= ATOM_S3_DFP1_ACTIVE;
bios_6_scratch |= ATOM_S6_ACC_REQ_DFP1;
} else {
- DRM_DEBUG("DFP1 disconnected\n");
+ DRM_DEBUG_KMS("DFP1 disconnected\n");
bios_0_scratch &= ~ATOM_S0_DFP1;
bios_3_scratch &= ~ATOM_S3_DFP1_ACTIVE;
bios_6_scratch &= ~ATOM_S6_ACC_REQ_DFP1;
@@ -2261,12 +2266,12 @@ radeon_atombios_connected_scratch_regs(struct drm_connector *connector,
if ((radeon_encoder->devices & ATOM_DEVICE_DFP2_SUPPORT) &&
(radeon_connector->devices & ATOM_DEVICE_DFP2_SUPPORT)) {
if (connected) {
- DRM_DEBUG("DFP2 connected\n");
+ DRM_DEBUG_KMS("DFP2 connected\n");
bios_0_scratch |= ATOM_S0_DFP2;
bios_3_scratch |= ATOM_S3_DFP2_ACTIVE;
bios_6_scratch |= ATOM_S6_ACC_REQ_DFP2;
} else {
- DRM_DEBUG("DFP2 disconnected\n");
+ DRM_DEBUG_KMS("DFP2 disconnected\n");
bios_0_scratch &= ~ATOM_S0_DFP2;
bios_3_scratch &= ~ATOM_S3_DFP2_ACTIVE;
bios_6_scratch &= ~ATOM_S6_ACC_REQ_DFP2;
@@ -2275,12 +2280,12 @@ radeon_atombios_connected_scratch_regs(struct drm_connector *connector,
if ((radeon_encoder->devices & ATOM_DEVICE_DFP3_SUPPORT) &&
(radeon_connector->devices & ATOM_DEVICE_DFP3_SUPPORT)) {
if (connected) {
- DRM_DEBUG("DFP3 connected\n");
+ DRM_DEBUG_KMS("DFP3 connected\n");
bios_0_scratch |= ATOM_S0_DFP3;
bios_3_scratch |= ATOM_S3_DFP3_ACTIVE;
bios_6_scratch |= ATOM_S6_ACC_REQ_DFP3;
} else {
- DRM_DEBUG("DFP3 disconnected\n");
+ DRM_DEBUG_KMS("DFP3 disconnected\n");
bios_0_scratch &= ~ATOM_S0_DFP3;
bios_3_scratch &= ~ATOM_S3_DFP3_ACTIVE;
bios_6_scratch &= ~ATOM_S6_ACC_REQ_DFP3;
@@ -2289,12 +2294,12 @@ radeon_atombios_connected_scratch_regs(struct drm_connector *connector,
if ((radeon_encoder->devices & ATOM_DEVICE_DFP4_SUPPORT) &&
(radeon_connector->devices & ATOM_DEVICE_DFP4_SUPPORT)) {
if (connected) {
- DRM_DEBUG("DFP4 connected\n");
+ DRM_DEBUG_KMS("DFP4 connected\n");
bios_0_scratch |= ATOM_S0_DFP4;
bios_3_scratch |= ATOM_S3_DFP4_ACTIVE;
bios_6_scratch |= ATOM_S6_ACC_REQ_DFP4;
} else {
- DRM_DEBUG("DFP4 disconnected\n");
+ DRM_DEBUG_KMS("DFP4 disconnected\n");
bios_0_scratch &= ~ATOM_S0_DFP4;
bios_3_scratch &= ~ATOM_S3_DFP4_ACTIVE;
bios_6_scratch &= ~ATOM_S6_ACC_REQ_DFP4;
@@ -2303,12 +2308,12 @@ radeon_atombios_connected_scratch_regs(struct drm_connector *connector,
if ((radeon_encoder->devices & ATOM_DEVICE_DFP5_SUPPORT) &&
(radeon_connector->devices & ATOM_DEVICE_DFP5_SUPPORT)) {
if (connected) {
- DRM_DEBUG("DFP5 connected\n");
+ DRM_DEBUG_KMS("DFP5 connected\n");
bios_0_scratch |= ATOM_S0_DFP5;
bios_3_scratch |= ATOM_S3_DFP5_ACTIVE;
bios_6_scratch |= ATOM_S6_ACC_REQ_DFP5;
} else {
- DRM_DEBUG("DFP5 disconnected\n");
+ DRM_DEBUG_KMS("DFP5 disconnected\n");
bios_0_scratch &= ~ATOM_S0_DFP5;
bios_3_scratch &= ~ATOM_S3_DFP5_ACTIVE;
bios_6_scratch &= ~ATOM_S6_ACC_REQ_DFP5;
diff --git a/drivers/gpu/drm/radeon/radeon_bios.c b/drivers/gpu/drm/radeon/radeon_bios.c
index 2c921373999..654787ec43f 100644
--- a/drivers/gpu/drm/radeon/radeon_bios.c
+++ b/drivers/gpu/drm/radeon/radeon_bios.c
@@ -53,7 +53,7 @@ static bool igp_read_bios_from_vram(struct radeon_device *rdev)
return false;
rdev->bios = NULL;
- vram_base = drm_get_resource_start(rdev->ddev, 0);
+ vram_base = pci_resource_start(rdev->pdev, 0);
bios = ioremap(vram_base, size);
if (!bios) {
return false;
diff --git a/drivers/gpu/drm/radeon/radeon_combios.c b/drivers/gpu/drm/radeon/radeon_combios.c
index 2417d7b06fd..5e1474cde4b 100644
--- a/drivers/gpu/drm/radeon/radeon_combios.c
+++ b/drivers/gpu/drm/radeon/radeon_combios.c
@@ -693,6 +693,10 @@ bool radeon_combios_sideport_present(struct radeon_device *rdev)
struct drm_device *dev = rdev->ddev;
u16 igp_info;
+ /* sideport is AMD only */
+ if (rdev->family == CHIP_RS400)
+ return false;
+
igp_info = combios_get_table_offset(dev, COMBIOS_INTEGRATED_SYSTEM_INFO_TABLE);
if (igp_info) {
@@ -1205,7 +1209,7 @@ bool radeon_legacy_get_tmds_info_from_combios(struct radeon_encoder *encoder,
RBIOS32(tmds_info + i * 10 + 0x08);
tmds->tmds_pll[i].freq =
RBIOS16(tmds_info + i * 10 + 0x10);
- DRM_DEBUG("TMDS PLL From COMBIOS %u %x\n",
+ DRM_DEBUG_KMS("TMDS PLL From COMBIOS %u %x\n",
tmds->tmds_pll[i].freq,
tmds->tmds_pll[i].value);
}
@@ -1223,7 +1227,7 @@ bool radeon_legacy_get_tmds_info_from_combios(struct radeon_encoder *encoder,
stride += 10;
else
stride += 6;
- DRM_DEBUG("TMDS PLL From COMBIOS %u %x\n",
+ DRM_DEBUG_KMS("TMDS PLL From COMBIOS %u %x\n",
tmds->tmds_pll[i].freq,
tmds->tmds_pll[i].value);
}
@@ -2208,7 +2212,7 @@ bool radeon_get_legacy_connector_info_from_bios(struct drm_device *dev)
uint16_t tmds_info =
combios_get_table_offset(dev, COMBIOS_DFP_INFO_TABLE);
if (tmds_info) {
- DRM_DEBUG("Found DFP table, assuming DVI connector\n");
+ DRM_DEBUG_KMS("Found DFP table, assuming DVI connector\n");
radeon_add_legacy_encoder(dev,
radeon_get_encoder_id(dev,
@@ -2234,7 +2238,7 @@ bool radeon_get_legacy_connector_info_from_bios(struct drm_device *dev)
} else {
uint16_t crt_info =
combios_get_table_offset(dev, COMBIOS_CRT_INFO_TABLE);
- DRM_DEBUG("Found CRT table, assuming VGA connector\n");
+ DRM_DEBUG_KMS("Found CRT table, assuming VGA connector\n");
if (crt_info) {
radeon_add_legacy_encoder(dev,
radeon_get_encoder_id(dev,
@@ -2251,7 +2255,7 @@ bool radeon_get_legacy_connector_info_from_bios(struct drm_device *dev)
CONNECTOR_OBJECT_ID_VGA,
&hpd);
} else {
- DRM_DEBUG("No connector info found\n");
+ DRM_DEBUG_KMS("No connector info found\n");
return false;
}
}
@@ -2340,7 +2344,7 @@ bool radeon_get_legacy_connector_info_from_bios(struct drm_device *dev)
ddc_i2c.valid = false;
break;
}
- DRM_DEBUG("LCD DDC Info Table found!\n");
+ DRM_DEBUG_KMS("LCD DDC Info Table found!\n");
} else
ddc_i2c.valid = false;
@@ -2941,9 +2945,8 @@ static void combios_write_ram_size(struct drm_device *dev)
if (rev < 3) {
mem_cntl = RBIOS32(offset + 1);
mem_size = RBIOS16(offset + 5);
- if (((rdev->flags & RADEON_FAMILY_MASK) < CHIP_R200) &&
- ((dev->pdev->device != 0x515e)
- && (dev->pdev->device != 0x5969)))
+ if ((rdev->family < CHIP_R200) &&
+ !ASIC_IS_RN50(rdev))
WREG32(RADEON_MEM_CNTL, mem_cntl);
}
}
@@ -2954,10 +2957,8 @@ static void combios_write_ram_size(struct drm_device *dev)
if (offset) {
rev = RBIOS8(offset - 1);
if (rev < 1) {
- if (((rdev->flags & RADEON_FAMILY_MASK) <
- CHIP_R200)
- && ((dev->pdev->device != 0x515e)
- && (dev->pdev->device != 0x5969))) {
+ if ((rdev->family < CHIP_R200)
+ && !ASIC_IS_RN50(rdev)) {
int ram = 0;
int mem_addr_mapping = 0;
@@ -3121,14 +3122,14 @@ radeon_combios_connected_scratch_regs(struct drm_connector *connector,
if ((radeon_encoder->devices & ATOM_DEVICE_TV1_SUPPORT) &&
(radeon_connector->devices & ATOM_DEVICE_TV1_SUPPORT)) {
if (connected) {
- DRM_DEBUG("TV1 connected\n");
+ DRM_DEBUG_KMS("TV1 connected\n");
/* fix me */
bios_4_scratch |= RADEON_TV1_ATTACHED_SVIDEO;
/*save->bios_4_scratch |= RADEON_TV1_ATTACHED_COMP; */
bios_5_scratch |= RADEON_TV1_ON;
bios_5_scratch |= RADEON_ACC_REQ_TV1;
} else {
- DRM_DEBUG("TV1 disconnected\n");
+ DRM_DEBUG_KMS("TV1 disconnected\n");
bios_4_scratch &= ~RADEON_TV1_ATTACHED_MASK;
bios_5_scratch &= ~RADEON_TV1_ON;
bios_5_scratch &= ~RADEON_ACC_REQ_TV1;
@@ -3137,12 +3138,12 @@ radeon_combios_connected_scratch_regs(struct drm_connector *connector,
if ((radeon_encoder->devices & ATOM_DEVICE_LCD1_SUPPORT) &&
(radeon_connector->devices & ATOM_DEVICE_LCD1_SUPPORT)) {
if (connected) {
- DRM_DEBUG("LCD1 connected\n");
+ DRM_DEBUG_KMS("LCD1 connected\n");
bios_4_scratch |= RADEON_LCD1_ATTACHED;
bios_5_scratch |= RADEON_LCD1_ON;
bios_5_scratch |= RADEON_ACC_REQ_LCD1;
} else {
- DRM_DEBUG("LCD1 disconnected\n");
+ DRM_DEBUG_KMS("LCD1 disconnected\n");
bios_4_scratch &= ~RADEON_LCD1_ATTACHED;
bios_5_scratch &= ~RADEON_LCD1_ON;
bios_5_scratch &= ~RADEON_ACC_REQ_LCD1;
@@ -3151,12 +3152,12 @@ radeon_combios_connected_scratch_regs(struct drm_connector *connector,
if ((radeon_encoder->devices & ATOM_DEVICE_CRT1_SUPPORT) &&
(radeon_connector->devices & ATOM_DEVICE_CRT1_SUPPORT)) {
if (connected) {
- DRM_DEBUG("CRT1 connected\n");
+ DRM_DEBUG_KMS("CRT1 connected\n");
bios_4_scratch |= RADEON_CRT1_ATTACHED_COLOR;
bios_5_scratch |= RADEON_CRT1_ON;
bios_5_scratch |= RADEON_ACC_REQ_CRT1;
} else {
- DRM_DEBUG("CRT1 disconnected\n");
+ DRM_DEBUG_KMS("CRT1 disconnected\n");
bios_4_scratch &= ~RADEON_CRT1_ATTACHED_MASK;
bios_5_scratch &= ~RADEON_CRT1_ON;
bios_5_scratch &= ~RADEON_ACC_REQ_CRT1;
@@ -3165,12 +3166,12 @@ radeon_combios_connected_scratch_regs(struct drm_connector *connector,
if ((radeon_encoder->devices & ATOM_DEVICE_CRT2_SUPPORT) &&
(radeon_connector->devices & ATOM_DEVICE_CRT2_SUPPORT)) {
if (connected) {
- DRM_DEBUG("CRT2 connected\n");
+ DRM_DEBUG_KMS("CRT2 connected\n");
bios_4_scratch |= RADEON_CRT2_ATTACHED_COLOR;
bios_5_scratch |= RADEON_CRT2_ON;
bios_5_scratch |= RADEON_ACC_REQ_CRT2;
} else {
- DRM_DEBUG("CRT2 disconnected\n");
+ DRM_DEBUG_KMS("CRT2 disconnected\n");
bios_4_scratch &= ~RADEON_CRT2_ATTACHED_MASK;
bios_5_scratch &= ~RADEON_CRT2_ON;
bios_5_scratch &= ~RADEON_ACC_REQ_CRT2;
@@ -3179,12 +3180,12 @@ radeon_combios_connected_scratch_regs(struct drm_connector *connector,
if ((radeon_encoder->devices & ATOM_DEVICE_DFP1_SUPPORT) &&
(radeon_connector->devices & ATOM_DEVICE_DFP1_SUPPORT)) {
if (connected) {
- DRM_DEBUG("DFP1 connected\n");
+ DRM_DEBUG_KMS("DFP1 connected\n");
bios_4_scratch |= RADEON_DFP1_ATTACHED;
bios_5_scratch |= RADEON_DFP1_ON;
bios_5_scratch |= RADEON_ACC_REQ_DFP1;
} else {
- DRM_DEBUG("DFP1 disconnected\n");
+ DRM_DEBUG_KMS("DFP1 disconnected\n");
bios_4_scratch &= ~RADEON_DFP1_ATTACHED;
bios_5_scratch &= ~RADEON_DFP1_ON;
bios_5_scratch &= ~RADEON_ACC_REQ_DFP1;
@@ -3193,12 +3194,12 @@ radeon_combios_connected_scratch_regs(struct drm_connector *connector,
if ((radeon_encoder->devices & ATOM_DEVICE_DFP2_SUPPORT) &&
(radeon_connector->devices & ATOM_DEVICE_DFP2_SUPPORT)) {
if (connected) {
- DRM_DEBUG("DFP2 connected\n");
+ DRM_DEBUG_KMS("DFP2 connected\n");
bios_4_scratch |= RADEON_DFP2_ATTACHED;
bios_5_scratch |= RADEON_DFP2_ON;
bios_5_scratch |= RADEON_ACC_REQ_DFP2;
} else {
- DRM_DEBUG("DFP2 disconnected\n");
+ DRM_DEBUG_KMS("DFP2 disconnected\n");
bios_4_scratch &= ~RADEON_DFP2_ATTACHED;
bios_5_scratch &= ~RADEON_DFP2_ON;
bios_5_scratch &= ~RADEON_ACC_REQ_DFP2;
diff --git a/drivers/gpu/drm/radeon/radeon_connectors.c b/drivers/gpu/drm/radeon/radeon_connectors.c
index adccbc2c202..2395c8600cf 100644
--- a/drivers/gpu/drm/radeon/radeon_connectors.c
+++ b/drivers/gpu/drm/radeon/radeon_connectors.c
@@ -214,7 +214,7 @@ static struct drm_display_mode *radeon_fp_native_mode(struct drm_encoder *encode
mode->type = DRM_MODE_TYPE_PREFERRED | DRM_MODE_TYPE_DRIVER;
drm_mode_set_name(mode);
- DRM_DEBUG("Adding native panel mode %s\n", mode->name);
+ DRM_DEBUG_KMS("Adding native panel mode %s\n", mode->name);
} else if (native_mode->hdisplay != 0 &&
native_mode->vdisplay != 0) {
/* mac laptops without an edid */
@@ -226,7 +226,7 @@ static struct drm_display_mode *radeon_fp_native_mode(struct drm_encoder *encode
*/
mode = drm_cvt_mode(dev, native_mode->hdisplay, native_mode->vdisplay, 60, true, false, false);
mode->type = DRM_MODE_TYPE_PREFERRED | DRM_MODE_TYPE_DRIVER;
- DRM_DEBUG("Adding cvt approximation of native panel mode %s\n", mode->name);
+ DRM_DEBUG_KMS("Adding cvt approximation of native panel mode %s\n", mode->name);
}
return mode;
}
@@ -312,6 +312,20 @@ int radeon_connector_set_property(struct drm_connector *connector, struct drm_pr
}
}
+ if (property == rdev->mode_info.underscan_property) {
+ /* need to find digital encoder on connector */
+ encoder = radeon_find_encoder(connector, DRM_MODE_ENCODER_TMDS);
+ if (!encoder)
+ return 0;
+
+ radeon_encoder = to_radeon_encoder(encoder);
+
+ if (radeon_encoder->underscan_type != val) {
+ radeon_encoder->underscan_type = val;
+ radeon_property_change_mode(&radeon_encoder->base);
+ }
+ }
+
if (property == rdev->mode_info.tv_std_property) {
encoder = radeon_find_encoder(connector, DRM_MODE_ENCODER_TVDAC);
if (!encoder) {
@@ -522,7 +536,7 @@ static int radeon_lvds_set_property(struct drm_connector *connector,
struct radeon_encoder *radeon_encoder;
enum radeon_rmx_type rmx_type;
- DRM_DEBUG("\n");
+ DRM_DEBUG_KMS("\n");
if (property != dev->mode_config.scaling_mode_property)
return 0;
@@ -1082,6 +1096,8 @@ radeon_add_atom_connector(struct drm_device *dev,
drm_connector_attach_property(&radeon_connector->base,
rdev->mode_info.load_detect_property,
1);
+ /* no HPD on analog connectors */
+ radeon_connector->hpd.hpd = RADEON_HPD_NONE;
connector->polled = DRM_CONNECTOR_POLL_CONNECT;
break;
case DRM_MODE_CONNECTOR_DVIA:
@@ -1096,6 +1112,8 @@ radeon_add_atom_connector(struct drm_device *dev,
drm_connector_attach_property(&radeon_connector->base,
rdev->mode_info.load_detect_property,
1);
+ /* no HPD on analog connectors */
+ radeon_connector->hpd.hpd = RADEON_HPD_NONE;
break;
case DRM_MODE_CONNECTOR_DVII:
case DRM_MODE_CONNECTOR_DVID:
@@ -1116,6 +1134,10 @@ radeon_add_atom_connector(struct drm_device *dev,
drm_connector_attach_property(&radeon_connector->base,
rdev->mode_info.coherent_mode_property,
1);
+ if (ASIC_IS_AVIVO(rdev))
+ drm_connector_attach_property(&radeon_connector->base,
+ rdev->mode_info.underscan_property,
+ UNDERSCAN_AUTO);
if (connector_type == DRM_MODE_CONNECTOR_DVII) {
radeon_connector->dac_load_detect = true;
drm_connector_attach_property(&radeon_connector->base,
@@ -1141,6 +1163,10 @@ radeon_add_atom_connector(struct drm_device *dev,
drm_connector_attach_property(&radeon_connector->base,
rdev->mode_info.coherent_mode_property,
1);
+ if (ASIC_IS_AVIVO(rdev))
+ drm_connector_attach_property(&radeon_connector->base,
+ rdev->mode_info.underscan_property,
+ UNDERSCAN_AUTO);
subpixel_order = SubPixelHorizontalRGB;
break;
case DRM_MODE_CONNECTOR_DisplayPort:
@@ -1172,6 +1198,10 @@ radeon_add_atom_connector(struct drm_device *dev,
drm_connector_attach_property(&radeon_connector->base,
rdev->mode_info.coherent_mode_property,
1);
+ if (ASIC_IS_AVIVO(rdev))
+ drm_connector_attach_property(&radeon_connector->base,
+ rdev->mode_info.underscan_property,
+ UNDERSCAN_AUTO);
break;
case DRM_MODE_CONNECTOR_SVIDEO:
case DRM_MODE_CONNECTOR_Composite:
@@ -1186,6 +1216,8 @@ radeon_add_atom_connector(struct drm_device *dev,
drm_connector_attach_property(&radeon_connector->base,
rdev->mode_info.tv_std_property,
radeon_atombios_get_tv_info(rdev));
+ /* no HPD on analog connectors */
+ radeon_connector->hpd.hpd = RADEON_HPD_NONE;
}
break;
case DRM_MODE_CONNECTOR_LVDS:
@@ -1209,7 +1241,7 @@ radeon_add_atom_connector(struct drm_device *dev,
break;
}
- if (hpd->hpd == RADEON_HPD_NONE) {
+ if (radeon_connector->hpd.hpd == RADEON_HPD_NONE) {
if (i2c_bus->valid)
connector->polled = DRM_CONNECTOR_POLL_CONNECT;
} else
@@ -1276,6 +1308,8 @@ radeon_add_legacy_connector(struct drm_device *dev,
drm_connector_attach_property(&radeon_connector->base,
rdev->mode_info.load_detect_property,
1);
+ /* no HPD on analog connectors */
+ radeon_connector->hpd.hpd = RADEON_HPD_NONE;
connector->polled = DRM_CONNECTOR_POLL_CONNECT;
break;
case DRM_MODE_CONNECTOR_DVIA:
@@ -1290,6 +1324,8 @@ radeon_add_legacy_connector(struct drm_device *dev,
drm_connector_attach_property(&radeon_connector->base,
rdev->mode_info.load_detect_property,
1);
+ /* no HPD on analog connectors */
+ radeon_connector->hpd.hpd = RADEON_HPD_NONE;
break;
case DRM_MODE_CONNECTOR_DVII:
case DRM_MODE_CONNECTOR_DVID:
@@ -1328,6 +1364,8 @@ radeon_add_legacy_connector(struct drm_device *dev,
drm_connector_attach_property(&radeon_connector->base,
rdev->mode_info.tv_std_property,
radeon_combios_get_tv_info(rdev));
+ /* no HPD on analog connectors */
+ radeon_connector->hpd.hpd = RADEON_HPD_NONE;
}
break;
case DRM_MODE_CONNECTOR_LVDS:
@@ -1345,7 +1383,7 @@ radeon_add_legacy_connector(struct drm_device *dev,
break;
}
- if (hpd->hpd == RADEON_HPD_NONE) {
+ if (radeon_connector->hpd.hpd == RADEON_HPD_NONE) {
if (i2c_bus->valid)
connector->polled = DRM_CONNECTOR_POLL_CONNECT;
} else
diff --git a/drivers/gpu/drm/radeon/radeon_cp.c b/drivers/gpu/drm/radeon/radeon_cp.c
index 2f042a3c0e6..eb6b9eed734 100644
--- a/drivers/gpu/drm/radeon/radeon_cp.c
+++ b/drivers/gpu/drm/radeon/radeon_cp.c
@@ -2120,8 +2120,8 @@ int radeon_driver_load(struct drm_device *dev, unsigned long flags)
else
dev_priv->flags |= RADEON_IS_PCI;
- ret = drm_addmap(dev, drm_get_resource_start(dev, 2),
- drm_get_resource_len(dev, 2), _DRM_REGISTERS,
+ ret = drm_addmap(dev, pci_resource_start(dev->pdev, 2),
+ pci_resource_len(dev->pdev, 2), _DRM_REGISTERS,
_DRM_READ_ONLY | _DRM_DRIVER, &dev_priv->mmio);
if (ret != 0)
return ret;
@@ -2194,9 +2194,9 @@ int radeon_driver_firstopen(struct drm_device *dev)
dev_priv->gart_info.table_size = RADEON_PCIGART_TABLE_SIZE;
- dev_priv->fb_aper_offset = drm_get_resource_start(dev, 0);
+ dev_priv->fb_aper_offset = pci_resource_start(dev->pdev, 0);
ret = drm_addmap(dev, dev_priv->fb_aper_offset,
- drm_get_resource_len(dev, 0), _DRM_FRAME_BUFFER,
+ pci_resource_len(dev->pdev, 0), _DRM_FRAME_BUFFER,
_DRM_WRITE_COMBINING, &map);
if (ret != 0)
return ret;
diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c
index dd279da9054..a64811a9451 100644
--- a/drivers/gpu/drm/radeon/radeon_device.c
+++ b/drivers/gpu/drm/radeon/radeon_device.c
@@ -415,6 +415,22 @@ static uint32_t cail_reg_read(struct card_info *info, uint32_t reg)
return r;
}
+static void cail_ioreg_write(struct card_info *info, uint32_t reg, uint32_t val)
+{
+ struct radeon_device *rdev = info->dev->dev_private;
+
+ WREG32_IO(reg*4, val);
+}
+
+static uint32_t cail_ioreg_read(struct card_info *info, uint32_t reg)
+{
+ struct radeon_device *rdev = info->dev->dev_private;
+ uint32_t r;
+
+ r = RREG32_IO(reg*4);
+ return r;
+}
+
int radeon_atombios_init(struct radeon_device *rdev)
{
struct card_info *atom_card_info =
@@ -427,6 +443,15 @@ int radeon_atombios_init(struct radeon_device *rdev)
atom_card_info->dev = rdev->ddev;
atom_card_info->reg_read = cail_reg_read;
atom_card_info->reg_write = cail_reg_write;
+ /* needed for iio ops */
+ if (rdev->rio_mem) {
+ atom_card_info->ioreg_read = cail_ioreg_read;
+ atom_card_info->ioreg_write = cail_ioreg_write;
+ } else {
+ DRM_ERROR("Unable to find PCI I/O BAR; using MMIO for ATOM IIO\n");
+ atom_card_info->ioreg_read = cail_reg_read;
+ atom_card_info->ioreg_write = cail_reg_write;
+ }
atom_card_info->mc_read = cail_mc_read;
atom_card_info->mc_write = cail_mc_write;
atom_card_info->pll_read = cail_pll_read;
@@ -573,7 +598,7 @@ int radeon_device_init(struct radeon_device *rdev,
struct pci_dev *pdev,
uint32_t flags)
{
- int r;
+ int r, i;
int dma_bits;
rdev->shutdown = false;
@@ -650,8 +675,8 @@ int radeon_device_init(struct radeon_device *rdev,
/* Registers mapping */
/* TODO: block userspace mapping of io register */
- rdev->rmmio_base = drm_get_resource_start(rdev->ddev, 2);
- rdev->rmmio_size = drm_get_resource_len(rdev->ddev, 2);
+ rdev->rmmio_base = pci_resource_start(rdev->pdev, 2);
+ rdev->rmmio_size = pci_resource_len(rdev->pdev, 2);
rdev->rmmio = ioremap(rdev->rmmio_base, rdev->rmmio_size);
if (rdev->rmmio == NULL) {
return -ENOMEM;
@@ -659,6 +684,17 @@ int radeon_device_init(struct radeon_device *rdev,
DRM_INFO("register mmio base: 0x%08X\n", (uint32_t)rdev->rmmio_base);
DRM_INFO("register mmio size: %u\n", (unsigned)rdev->rmmio_size);
+ /* io port mapping */
+ for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) {
+ if (pci_resource_flags(rdev->pdev, i) & IORESOURCE_IO) {
+ rdev->rio_mem_size = pci_resource_len(rdev->pdev, i);
+ rdev->rio_mem = pci_iomap(rdev->pdev, i, rdev->rio_mem_size);
+ break;
+ }
+ }
+ if (rdev->rio_mem == NULL)
+ DRM_ERROR("Unable to find PCI I/O BAR\n");
+
/* if we have > 1 VGA cards, then disable the radeon VGA resources */
/* this will fail for cards that aren't VGA class devices, just
* ignore it */
@@ -701,6 +737,9 @@ void radeon_device_fini(struct radeon_device *rdev)
destroy_workqueue(rdev->wq);
vga_switcheroo_unregister_client(rdev->pdev);
vga_client_register(rdev->pdev, NULL, NULL, NULL);
+ if (rdev->rio_mem)
+ pci_iounmap(rdev->pdev, rdev->rio_mem);
+ rdev->rio_mem = NULL;
iounmap(rdev->rmmio);
rdev->rmmio = NULL;
}
diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c
index 8154cdf796e..74dac9635d7 100644
--- a/drivers/gpu/drm/radeon/radeon_display.c
+++ b/drivers/gpu/drm/radeon/radeon_display.c
@@ -42,7 +42,7 @@ static void avivo_crtc_load_lut(struct drm_crtc *crtc)
struct radeon_device *rdev = dev->dev_private;
int i;
- DRM_DEBUG("%d\n", radeon_crtc->crtc_id);
+ DRM_DEBUG_KMS("%d\n", radeon_crtc->crtc_id);
WREG32(AVIVO_DC_LUTA_CONTROL + radeon_crtc->crtc_offset, 0);
WREG32(AVIVO_DC_LUTA_BLACK_OFFSET_BLUE + radeon_crtc->crtc_offset, 0);
@@ -75,7 +75,7 @@ static void evergreen_crtc_load_lut(struct drm_crtc *crtc)
struct radeon_device *rdev = dev->dev_private;
int i;
- DRM_DEBUG("%d\n", radeon_crtc->crtc_id);
+ DRM_DEBUG_KMS("%d\n", radeon_crtc->crtc_id);
WREG32(EVERGREEN_DC_LUT_CONTROL + radeon_crtc->crtc_offset, 0);
WREG32(EVERGREEN_DC_LUT_BLACK_OFFSET_BLUE + radeon_crtc->crtc_offset, 0);
@@ -469,7 +469,7 @@ static void radeon_compute_pll_legacy(struct radeon_pll *pll,
uint32_t post_div;
u32 pll_out_min, pll_out_max;
- DRM_DEBUG("PLL freq %llu %u %u\n", freq, pll->min_ref_div, pll->max_ref_div);
+ DRM_DEBUG_KMS("PLL freq %llu %u %u\n", freq, pll->min_ref_div, pll->max_ref_div);
freq = freq * 1000;
if (pll->flags & RADEON_PLL_IS_LCD) {
@@ -558,15 +558,17 @@ static void radeon_compute_pll_legacy(struct radeon_pll *pll,
current_freq = radeon_div(tmp, ref_div * post_div);
if (pll->flags & RADEON_PLL_PREFER_CLOSEST_LOWER) {
- error = freq - current_freq;
- error = error < 0 ? 0xffffffff : error;
+ if (freq < current_freq)
+ error = 0xffffffff;
+ else
+ error = freq - current_freq;
} else
error = abs(current_freq - freq);
vco_diff = abs(vco - best_vco);
if ((best_vco == 0 && error < best_error) ||
(best_vco != 0 &&
- (error < best_error - 100 ||
+ ((best_error > 100 && error < best_error - 100) ||
(abs(error - best_error) < 100 && vco_diff < best_vco_diff)))) {
best_post_div = post_div;
best_ref_div = ref_div;
@@ -803,7 +805,7 @@ done:
*ref_div_p = ref_div;
*post_div_p = post_div;
- DRM_DEBUG("%u %d.%d, %d, %d\n", *dot_clock_p, *fb_div_p, *frac_fb_div_p, *ref_div_p, *post_div_p);
+ DRM_DEBUG_KMS("%u %d.%d, %d, %d\n", *dot_clock_p, *fb_div_p, *frac_fb_div_p, *ref_div_p, *post_div_p);
}
void radeon_compute_pll(struct radeon_pll *pll,
@@ -919,6 +921,12 @@ static struct drm_prop_enum_list radeon_tv_std_enum_list[] =
{ TV_STD_SECAM, "secam" },
};
+static struct drm_prop_enum_list radeon_underscan_enum_list[] =
+{ { UNDERSCAN_OFF, "off" },
+ { UNDERSCAN_ON, "on" },
+ { UNDERSCAN_AUTO, "auto" },
+};
+
static int radeon_modeset_create_props(struct radeon_device *rdev)
{
int i, sz;
@@ -972,6 +980,18 @@ static int radeon_modeset_create_props(struct radeon_device *rdev)
radeon_tv_std_enum_list[i].name);
}
+ sz = ARRAY_SIZE(radeon_underscan_enum_list);
+ rdev->mode_info.underscan_property =
+ drm_property_create(rdev->ddev,
+ DRM_MODE_PROP_ENUM,
+ "underscan", sz);
+ for (i = 0; i < sz; i++) {
+ drm_property_add_enum(rdev->mode_info.underscan_property,
+ i,
+ radeon_underscan_enum_list[i].type,
+ radeon_underscan_enum_list[i].name);
+ }
+
return 0;
}
@@ -1067,15 +1087,26 @@ bool radeon_crtc_scaling_mode_fixup(struct drm_crtc *crtc,
struct drm_display_mode *adjusted_mode)
{
struct drm_device *dev = crtc->dev;
+ struct radeon_device *rdev = dev->dev_private;
struct drm_encoder *encoder;
struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
struct radeon_encoder *radeon_encoder;
+ struct drm_connector *connector;
+ struct radeon_connector *radeon_connector;
bool first = true;
+ u32 src_v = 1, dst_v = 1;
+ u32 src_h = 1, dst_h = 1;
+
+ radeon_crtc->h_border = 0;
+ radeon_crtc->v_border = 0;
list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
- radeon_encoder = to_radeon_encoder(encoder);
if (encoder->crtc != crtc)
continue;
+ radeon_encoder = to_radeon_encoder(encoder);
+ connector = radeon_get_connector_for_encoder(encoder);
+ radeon_connector = to_radeon_connector(connector);
+
if (first) {
/* set scaling */
if (radeon_encoder->rmx_type == RMX_OFF)
@@ -1085,31 +1116,49 @@ bool radeon_crtc_scaling_mode_fixup(struct drm_crtc *crtc,
radeon_crtc->rmx_type = radeon_encoder->rmx_type;
else
radeon_crtc->rmx_type = RMX_OFF;
+ src_v = crtc->mode.vdisplay;
+ dst_v = radeon_crtc->native_mode.vdisplay;
+ src_h = crtc->mode.hdisplay;
+ dst_h = radeon_crtc->native_mode.vdisplay;
/* copy native mode */
memcpy(&radeon_crtc->native_mode,
&radeon_encoder->native_mode,
sizeof(struct drm_display_mode));
+
+ /* fix up for overscan on hdmi */
+ if (ASIC_IS_AVIVO(rdev) &&
+ ((radeon_encoder->underscan_type == UNDERSCAN_ON) ||
+ ((radeon_encoder->underscan_type == UNDERSCAN_AUTO) &&
+ drm_detect_hdmi_monitor(radeon_connector->edid)))) {
+ radeon_crtc->h_border = (mode->hdisplay >> 5) + 16;
+ radeon_crtc->v_border = (mode->vdisplay >> 5) + 16;
+ radeon_crtc->rmx_type = RMX_FULL;
+ src_v = crtc->mode.vdisplay;
+ dst_v = crtc->mode.vdisplay - (radeon_crtc->v_border * 2);
+ src_h = crtc->mode.hdisplay;
+ dst_h = crtc->mode.hdisplay - (radeon_crtc->h_border * 2);
+ }
first = false;
} else {
if (radeon_crtc->rmx_type != radeon_encoder->rmx_type) {
/* WARNING: Right now this can't happen but
* in the future we need to check that scaling
- * are consistent accross different encoder
+ * are consistent across different encoder
* (ie all encoder can work with the same
* scaling).
*/
- DRM_ERROR("Scaling not consistent accross encoder.\n");
+ DRM_ERROR("Scaling not consistent across encoder.\n");
return false;
}
}
}
if (radeon_crtc->rmx_type != RMX_OFF) {
fixed20_12 a, b;
- a.full = dfixed_const(crtc->mode.vdisplay);
- b.full = dfixed_const(radeon_crtc->native_mode.hdisplay);
+ a.full = dfixed_const(src_v);
+ b.full = dfixed_const(dst_v);
radeon_crtc->vsc.full = dfixed_div(a, b);
- a.full = dfixed_const(crtc->mode.hdisplay);
- b.full = dfixed_const(radeon_crtc->native_mode.vdisplay);
+ a.full = dfixed_const(src_h);
+ b.full = dfixed_const(dst_h);
radeon_crtc->hsc.full = dfixed_div(a, b);
} else {
radeon_crtc->vsc.full = dfixed_const(1);
diff --git a/drivers/gpu/drm/radeon/radeon_drv.c b/drivers/gpu/drm/radeon/radeon_drv.c
index e166fe4d7c3..795403b0e2c 100644
--- a/drivers/gpu/drm/radeon/radeon_drv.c
+++ b/drivers/gpu/drm/radeon/radeon_drv.c
@@ -46,9 +46,10 @@
* - 2.3.0 - add MSPOS + 3D texture + r500 VAP regs
* - 2.4.0 - add crtc id query
* - 2.5.0 - add get accel 2 to work around ddx breakage for evergreen
+ * - 2.6.0 - add tiling config query (r6xx+), add initial HiZ support (r300->r500)
*/
#define KMS_DRIVER_MAJOR 2
-#define KMS_DRIVER_MINOR 5
+#define KMS_DRIVER_MINOR 6
#define KMS_DRIVER_PATCHLEVEL 0
int radeon_driver_load_kms(struct drm_device *dev, unsigned long flags);
int radeon_driver_unload_kms(struct drm_device *dev);
@@ -238,7 +239,7 @@ static struct drm_driver kms_driver;
static int __devinit
radeon_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
{
- return drm_get_dev(pdev, ent, &kms_driver);
+ return drm_get_pci_dev(pdev, ent, &kms_driver);
}
static void
diff --git a/drivers/gpu/drm/radeon/radeon_encoders.c b/drivers/gpu/drm/radeon/radeon_encoders.c
index e0b30b264c2..263c8098d7d 100644
--- a/drivers/gpu/drm/radeon/radeon_encoders.c
+++ b/drivers/gpu/drm/radeon/radeon_encoders.c
@@ -205,14 +205,14 @@ void radeon_encoder_set_active_device(struct drm_encoder *encoder)
if (connector->encoder == encoder) {
struct radeon_connector *radeon_connector = to_radeon_connector(connector);
radeon_encoder->active_device = radeon_encoder->devices & radeon_connector->devices;
- DRM_DEBUG("setting active device to %08x from %08x %08x for encoder %d\n",
+ DRM_DEBUG_KMS("setting active device to %08x from %08x %08x for encoder %d\n",
radeon_encoder->active_device, radeon_encoder->devices,
radeon_connector->devices, encoder->encoder_type);
}
}
}
-static struct drm_connector *
+struct drm_connector *
radeon_get_connector_for_encoder(struct drm_encoder *encoder)
{
struct drm_device *dev = encoder->dev;
@@ -1021,7 +1021,7 @@ radeon_atom_encoder_dpms(struct drm_encoder *encoder, int mode)
memset(&args, 0, sizeof(args));
- DRM_DEBUG("encoder dpms %d to mode %d, devices %08x, active_devices %08x\n",
+ DRM_DEBUG_KMS("encoder dpms %d to mode %d, devices %08x, active_devices %08x\n",
radeon_encoder->encoder_id, mode, radeon_encoder->devices,
radeon_encoder->active_device);
switch (radeon_encoder->encoder_id) {
@@ -1484,7 +1484,7 @@ radeon_atom_dac_detect(struct drm_encoder *encoder, struct drm_connector *connec
uint32_t bios_0_scratch;
if (!atombios_dac_load_detect(encoder, connector)) {
- DRM_DEBUG("detect returned false \n");
+ DRM_DEBUG_KMS("detect returned false \n");
return connector_status_unknown;
}
@@ -1493,7 +1493,7 @@ radeon_atom_dac_detect(struct drm_encoder *encoder, struct drm_connector *connec
else
bios_0_scratch = RREG32(RADEON_BIOS_0_SCRATCH);
- DRM_DEBUG("Bios 0 scratch %x %08x\n", bios_0_scratch, radeon_encoder->devices);
+ DRM_DEBUG_KMS("Bios 0 scratch %x %08x\n", bios_0_scratch, radeon_encoder->devices);
if (radeon_connector->devices & ATOM_DEVICE_CRT1_SUPPORT) {
if (bios_0_scratch & ATOM_S0_CRT1_MASK)
return connector_status_connected;
@@ -1694,6 +1694,7 @@ radeon_add_atom_encoder(struct drm_device *dev, uint32_t encoder_id, uint32_t su
radeon_encoder->encoder_id = encoder_id;
radeon_encoder->devices = supported_device;
radeon_encoder->rmx_type = RMX_OFF;
+ radeon_encoder->underscan_type = UNDERSCAN_OFF;
switch (radeon_encoder->encoder_id) {
case ENCODER_OBJECT_ID_INTERNAL_LVDS:
@@ -1707,6 +1708,8 @@ radeon_add_atom_encoder(struct drm_device *dev, uint32_t encoder_id, uint32_t su
} else {
drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs, DRM_MODE_ENCODER_TMDS);
radeon_encoder->enc_priv = radeon_atombios_set_dig_info(radeon_encoder);
+ if (ASIC_IS_AVIVO(rdev))
+ radeon_encoder->underscan_type = UNDERSCAN_AUTO;
}
drm_encoder_helper_add(encoder, &radeon_atom_dig_helper_funcs);
break;
@@ -1736,6 +1739,8 @@ radeon_add_atom_encoder(struct drm_device *dev, uint32_t encoder_id, uint32_t su
} else {
drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs, DRM_MODE_ENCODER_TMDS);
radeon_encoder->enc_priv = radeon_atombios_set_dig_info(radeon_encoder);
+ if (ASIC_IS_AVIVO(rdev))
+ radeon_encoder->underscan_type = UNDERSCAN_AUTO;
}
drm_encoder_helper_add(encoder, &radeon_atom_dig_helper_funcs);
break;
diff --git a/drivers/gpu/drm/radeon/radeon_kms.c b/drivers/gpu/drm/radeon/radeon_kms.c
index ab389f89fa8..ddcd3b13f15 100644
--- a/drivers/gpu/drm/radeon/radeon_kms.c
+++ b/drivers/gpu/drm/radeon/radeon_kms.c
@@ -49,7 +49,7 @@ int radeon_driver_unload_kms(struct drm_device *dev)
int radeon_driver_load_kms(struct drm_device *dev, unsigned long flags)
{
struct radeon_device *rdev;
- int r;
+ int r, acpi_status;
rdev = kzalloc(sizeof(struct radeon_device), GFP_KERNEL);
if (rdev == NULL) {
@@ -77,6 +77,12 @@ int radeon_driver_load_kms(struct drm_device *dev, unsigned long flags)
dev_err(&dev->pdev->dev, "Fatal error during GPU init\n");
goto out;
}
+
+ /* Call ACPI methods */
+ acpi_status = radeon_acpi_init(rdev);
+ if (acpi_status)
+ dev_dbg(&dev->pdev->dev, "Error during ACPI methods call\n");
+
/* Again modeset_init should fail only on fatal error
* otherwise it should provide enough functionalities
* for shadowfb to run
@@ -135,15 +141,36 @@ int radeon_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp)
}
}
if (!found) {
- DRM_DEBUG("unknown crtc id %d\n", value);
+ DRM_DEBUG_KMS("unknown crtc id %d\n", value);
return -EINVAL;
}
break;
case RADEON_INFO_ACCEL_WORKING2:
value = rdev->accel_working;
break;
+ case RADEON_INFO_TILING_CONFIG:
+ if (rdev->family >= CHIP_CEDAR)
+ value = rdev->config.evergreen.tile_config;
+ else if (rdev->family >= CHIP_RV770)
+ value = rdev->config.rv770.tile_config;
+ else if (rdev->family >= CHIP_R600)
+ value = rdev->config.r600.tile_config;
+ else {
+ DRM_DEBUG_KMS("tiling config is r6xx+ only!\n");
+ return -EINVAL;
+ }
+ case RADEON_INFO_WANT_HYPERZ:
+ mutex_lock(&dev->struct_mutex);
+ if (rdev->hyperz_filp)
+ value = 0;
+ else {
+ rdev->hyperz_filp = filp;
+ value = 1;
+ }
+ mutex_unlock(&dev->struct_mutex);
+ break;
default:
- DRM_DEBUG("Invalid request %d\n", info->request);
+ DRM_DEBUG_KMS("Invalid request %d\n", info->request);
return -EINVAL;
}
if (DRM_COPY_TO_USER(value_ptr, &value, sizeof(uint32_t))) {
@@ -181,9 +208,11 @@ void radeon_driver_postclose_kms(struct drm_device *dev,
void radeon_driver_preclose_kms(struct drm_device *dev,
struct drm_file *file_priv)
{
+ struct radeon_device *rdev = dev->dev_private;
+ if (rdev->hyperz_filp == file_priv)
+ rdev->hyperz_filp = NULL;
}
-
/*
* VBlank related functions.
*/
diff --git a/drivers/gpu/drm/radeon/radeon_legacy_crtc.c b/drivers/gpu/drm/radeon/radeon_legacy_crtc.c
index e1e5255396a..989df519a1e 100644
--- a/drivers/gpu/drm/radeon/radeon_legacy_crtc.c
+++ b/drivers/gpu/drm/radeon/radeon_legacy_crtc.c
@@ -362,10 +362,10 @@ int radeon_crtc_set_base(struct drm_crtc *crtc, int x, int y,
uint32_t gen_cntl_reg, gen_cntl_val;
int r;
- DRM_DEBUG("\n");
+ DRM_DEBUG_KMS("\n");
/* no fb bound */
if (!crtc->fb) {
- DRM_DEBUG("No FB bound\n");
+ DRM_DEBUG_KMS("No FB bound\n");
return 0;
}
@@ -528,7 +528,7 @@ static bool radeon_set_crtc_timing(struct drm_crtc *crtc, struct drm_display_mod
uint32_t crtc_v_sync_strt_wid;
bool is_tv = false;
- DRM_DEBUG("\n");
+ DRM_DEBUG_KMS("\n");
list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
if (encoder->crtc == crtc) {
struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
@@ -757,7 +757,7 @@ static void radeon_set_pll(struct drm_crtc *crtc, struct drm_display_mode *mode)
}
}
- DRM_DEBUG("\n");
+ DRM_DEBUG_KMS("\n");
if (!use_bios_divs) {
radeon_compute_pll(pll, mode->clock,
@@ -772,7 +772,7 @@ static void radeon_set_pll(struct drm_crtc *crtc, struct drm_display_mode *mode)
if (!post_div->divider)
post_div = &post_divs[0];
- DRM_DEBUG("dc=%u, fd=%d, rd=%d, pd=%d\n",
+ DRM_DEBUG_KMS("dc=%u, fd=%d, rd=%d, pd=%d\n",
(unsigned)freq,
feedback_div,
reference_div,
@@ -841,12 +841,12 @@ static void radeon_set_pll(struct drm_crtc *crtc, struct drm_display_mode *mode)
| RADEON_P2PLL_SLEEP
| RADEON_P2PLL_ATOMIC_UPDATE_EN));
- DRM_DEBUG("Wrote2: 0x%08x 0x%08x 0x%08x (0x%08x)\n",
+ DRM_DEBUG_KMS("Wrote2: 0x%08x 0x%08x 0x%08x (0x%08x)\n",
(unsigned)pll_ref_div,
(unsigned)pll_fb_post_div,
(unsigned)htotal_cntl,
RREG32_PLL(RADEON_P2PLL_CNTL));
- DRM_DEBUG("Wrote2: rd=%u, fd=%u, pd=%u\n",
+ DRM_DEBUG_KMS("Wrote2: rd=%u, fd=%u, pd=%u\n",
(unsigned)pll_ref_div & RADEON_P2PLL_REF_DIV_MASK,
(unsigned)pll_fb_post_div & RADEON_P2PLL_FB0_DIV_MASK,
(unsigned)((pll_fb_post_div &
@@ -947,12 +947,12 @@ static void radeon_set_pll(struct drm_crtc *crtc, struct drm_display_mode *mode)
| RADEON_PPLL_ATOMIC_UPDATE_EN
| RADEON_PPLL_VGA_ATOMIC_UPDATE_EN));
- DRM_DEBUG("Wrote: 0x%08x 0x%08x 0x%08x (0x%08x)\n",
+ DRM_DEBUG_KMS("Wrote: 0x%08x 0x%08x 0x%08x (0x%08x)\n",
pll_ref_div,
pll_fb_post_div,
(unsigned)htotal_cntl,
RREG32_PLL(RADEON_PPLL_CNTL));
- DRM_DEBUG("Wrote: rd=%d, fd=%d, pd=%d\n",
+ DRM_DEBUG_KMS("Wrote: rd=%d, fd=%d, pd=%d\n",
pll_ref_div & RADEON_PPLL_REF_DIV_MASK,
pll_fb_post_div & RADEON_PPLL_FB3_DIV_MASK,
(pll_fb_post_div & RADEON_PPLL_POST3_DIV_MASK) >> 16);
diff --git a/drivers/gpu/drm/radeon/radeon_legacy_encoders.c b/drivers/gpu/drm/radeon/radeon_legacy_encoders.c
index 5688a0cf6bb..b8149cbc0c7 100644
--- a/drivers/gpu/drm/radeon/radeon_legacy_encoders.c
+++ b/drivers/gpu/drm/radeon/radeon_legacy_encoders.c
@@ -47,7 +47,7 @@ static void radeon_legacy_lvds_dpms(struct drm_encoder *encoder, int mode)
uint32_t lvds_gen_cntl, lvds_pll_cntl, pixclks_cntl, disp_pwr_man;
int panel_pwr_delay = 2000;
bool is_mac = false;
- DRM_DEBUG("\n");
+ DRM_DEBUG_KMS("\n");
if (radeon_encoder->enc_priv) {
if (rdev->is_atom_bios) {
@@ -151,7 +151,7 @@ static void radeon_legacy_lvds_mode_set(struct drm_encoder *encoder,
struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
uint32_t lvds_pll_cntl, lvds_gen_cntl, lvds_ss_gen_cntl;
- DRM_DEBUG("\n");
+ DRM_DEBUG_KMS("\n");
lvds_pll_cntl = RREG32(RADEON_LVDS_PLL_CNTL);
lvds_pll_cntl &= ~RADEON_LVDS_PLL_EN;
@@ -167,7 +167,7 @@ static void radeon_legacy_lvds_mode_set(struct drm_encoder *encoder,
} else {
struct radeon_encoder_lvds *lvds = (struct radeon_encoder_lvds *)radeon_encoder->enc_priv;
if (lvds) {
- DRM_DEBUG("bios LVDS_GEN_CNTL: 0x%x\n", lvds->lvds_gen_cntl);
+ DRM_DEBUG_KMS("bios LVDS_GEN_CNTL: 0x%x\n", lvds->lvds_gen_cntl);
lvds_gen_cntl = lvds->lvds_gen_cntl;
lvds_ss_gen_cntl &= ~((0xf << RADEON_LVDS_PWRSEQ_DELAY1_SHIFT) |
(0xf << RADEON_LVDS_PWRSEQ_DELAY2_SHIFT));
@@ -250,7 +250,7 @@ static void radeon_legacy_primary_dac_dpms(struct drm_encoder *encoder, int mode
uint32_t dac_cntl = RREG32(RADEON_DAC_CNTL);
uint32_t dac_macro_cntl = RREG32(RADEON_DAC_MACRO_CNTL);
- DRM_DEBUG("\n");
+ DRM_DEBUG_KMS("\n");
switch (mode) {
case DRM_MODE_DPMS_ON:
@@ -315,7 +315,7 @@ static void radeon_legacy_primary_dac_mode_set(struct drm_encoder *encoder,
struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
uint32_t disp_output_cntl, dac_cntl, dac2_cntl, dac_macro_cntl;
- DRM_DEBUG("\n");
+ DRM_DEBUG_KMS("\n");
if (radeon_crtc->crtc_id == 0) {
if (rdev->family == CHIP_R200 || ASIC_IS_R300(rdev)) {
@@ -446,7 +446,7 @@ static void radeon_legacy_tmds_int_dpms(struct drm_encoder *encoder, int mode)
struct drm_device *dev = encoder->dev;
struct radeon_device *rdev = dev->dev_private;
uint32_t fp_gen_cntl = RREG32(RADEON_FP_GEN_CNTL);
- DRM_DEBUG("\n");
+ DRM_DEBUG_KMS("\n");
switch (mode) {
case DRM_MODE_DPMS_ON:
@@ -502,7 +502,7 @@ static void radeon_legacy_tmds_int_mode_set(struct drm_encoder *encoder,
uint32_t tmp, tmds_pll_cntl, tmds_transmitter_cntl, fp_gen_cntl;
int i;
- DRM_DEBUG("\n");
+ DRM_DEBUG_KMS("\n");
tmp = tmds_pll_cntl = RREG32(RADEON_TMDS_PLL_CNTL);
tmp &= 0xfffff;
@@ -610,7 +610,7 @@ static void radeon_legacy_tmds_ext_dpms(struct drm_encoder *encoder, int mode)
struct drm_device *dev = encoder->dev;
struct radeon_device *rdev = dev->dev_private;
uint32_t fp2_gen_cntl = RREG32(RADEON_FP2_GEN_CNTL);
- DRM_DEBUG("\n");
+ DRM_DEBUG_KMS("\n");
switch (mode) {
case DRM_MODE_DPMS_ON:
@@ -666,7 +666,7 @@ static void radeon_legacy_tmds_ext_mode_set(struct drm_encoder *encoder,
struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
uint32_t fp2_gen_cntl;
- DRM_DEBUG("\n");
+ DRM_DEBUG_KMS("\n");
if (rdev->is_atom_bios) {
radeon_encoder->pixel_clock = adjusted_mode->clock;
@@ -760,7 +760,7 @@ static void radeon_legacy_tv_dac_dpms(struct drm_encoder *encoder, int mode)
uint32_t fp2_gen_cntl = 0, crtc2_gen_cntl = 0, tv_dac_cntl = 0;
uint32_t tv_master_cntl = 0;
bool is_tv;
- DRM_DEBUG("\n");
+ DRM_DEBUG_KMS("\n");
is_tv = radeon_encoder->active_device & ATOM_DEVICE_TV_SUPPORT ? true : false;
@@ -878,7 +878,7 @@ static void radeon_legacy_tv_dac_mode_set(struct drm_encoder *encoder,
uint32_t disp_hw_debug = 0, fp2_gen_cntl = 0, disp_tv_out_cntl = 0;
bool is_tv = false;
- DRM_DEBUG("\n");
+ DRM_DEBUG_KMS("\n");
is_tv = radeon_encoder->active_device & ATOM_DEVICE_TV_SUPPORT ? true : false;
@@ -1075,10 +1075,10 @@ static bool r300_legacy_tv_detect(struct drm_encoder *encoder,
tmp = RREG32(RADEON_TV_DAC_CNTL);
if ((tmp & RADEON_TV_DAC_GDACDET) != 0) {
found = true;
- DRM_DEBUG("S-video TV connection detected\n");
+ DRM_DEBUG_KMS("S-video TV connection detected\n");
} else if ((tmp & RADEON_TV_DAC_BDACDET) != 0) {
found = true;
- DRM_DEBUG("Composite TV connection detected\n");
+ DRM_DEBUG_KMS("Composite TV connection detected\n");
}
WREG32(RADEON_TV_DAC_CNTL, tv_dac_cntl);
@@ -1141,10 +1141,10 @@ static bool radeon_legacy_tv_detect(struct drm_encoder *encoder,
tmp = RREG32(RADEON_TV_DAC_CNTL);
if (tmp & RADEON_TV_DAC_GDACDET) {
found = true;
- DRM_DEBUG("S-video TV connection detected\n");
+ DRM_DEBUG_KMS("S-video TV connection detected\n");
} else if ((tmp & RADEON_TV_DAC_BDACDET) != 0) {
found = true;
- DRM_DEBUG("Composite TV connection detected\n");
+ DRM_DEBUG_KMS("Composite TV connection detected\n");
}
WREG32(RADEON_TV_PRE_DAC_MUX_CNTL, tv_pre_dac_mux_cntl);
diff --git a/drivers/gpu/drm/radeon/radeon_legacy_tv.c b/drivers/gpu/drm/radeon/radeon_legacy_tv.c
index 03204039774..c7b6cb428d0 100644
--- a/drivers/gpu/drm/radeon/radeon_legacy_tv.c
+++ b/drivers/gpu/drm/radeon/radeon_legacy_tv.c
@@ -496,7 +496,7 @@ static bool radeon_legacy_tv_init_restarts(struct drm_encoder *encoder)
restart -= v_offset + h_offset;
- DRM_DEBUG("compute_restarts: def = %u h = %d v = %d, p1 = %04x, p2 = %04x, restart = %d\n",
+ DRM_DEBUG_KMS("compute_restarts: def = %u h = %d v = %d, p1 = %04x, p2 = %04x, restart = %d\n",
const_ptr->def_restart, tv_dac->h_pos, tv_dac->v_pos, p1, p2, restart);
tv_dac->tv.hrestart = restart % h_total;
@@ -505,7 +505,7 @@ static bool radeon_legacy_tv_init_restarts(struct drm_encoder *encoder)
restart /= v_total;
tv_dac->tv.frestart = restart % f_total;
- DRM_DEBUG("compute_restart: F/H/V=%u,%u,%u\n",
+ DRM_DEBUG_KMS("compute_restart: F/H/V=%u,%u,%u\n",
(unsigned)tv_dac->tv.frestart,
(unsigned)tv_dac->tv.vrestart,
(unsigned)tv_dac->tv.hrestart);
@@ -523,7 +523,7 @@ static bool radeon_legacy_tv_init_restarts(struct drm_encoder *encoder)
tv_dac->tv.timing_cntl = (tv_dac->tv.timing_cntl & ~RADEON_H_INC_MASK) |
((u32)h_inc << RADEON_H_INC_SHIFT);
- DRM_DEBUG("compute_restart: h_size = %d h_inc = %d\n", tv_dac->h_size, h_inc);
+ DRM_DEBUG_KMS("compute_restart: h_size = %d h_inc = %d\n", tv_dac->h_size, h_inc);
return h_changed;
}
diff --git a/drivers/gpu/drm/radeon/radeon_mode.h b/drivers/gpu/drm/radeon/radeon_mode.h
index 95696aa57ac..71aea4037e9 100644
--- a/drivers/gpu/drm/radeon/radeon_mode.h
+++ b/drivers/gpu/drm/radeon/radeon_mode.h
@@ -66,6 +66,12 @@ enum radeon_tv_std {
TV_STD_PAL_N,
};
+enum radeon_underscan_type {
+ UNDERSCAN_OFF,
+ UNDERSCAN_ON,
+ UNDERSCAN_AUTO,
+};
+
enum radeon_hpd_id {
RADEON_HPD_1 = 0,
RADEON_HPD_2,
@@ -226,10 +232,12 @@ struct radeon_mode_info {
struct drm_property *coherent_mode_property;
/* DAC enable load detect */
struct drm_property *load_detect_property;
- /* TV standard load detect */
+ /* TV standard */
struct drm_property *tv_std_property;
/* legacy TMDS PLL detect */
struct drm_property *tmds_pll_property;
+ /* underscan */
+ struct drm_property *underscan_property;
/* hardcoded DFP edid from BIOS */
struct edid *bios_hardcoded_edid;
@@ -266,6 +274,8 @@ struct radeon_crtc {
uint32_t legacy_display_base_addr;
uint32_t legacy_cursor_offset;
enum radeon_rmx_type rmx_type;
+ u8 h_border;
+ u8 v_border;
fixed20_12 vsc;
fixed20_12 hsc;
struct drm_display_mode native_mode;
@@ -354,6 +364,7 @@ struct radeon_encoder {
uint32_t flags;
uint32_t pixel_clock;
enum radeon_rmx_type rmx_type;
+ enum radeon_underscan_type underscan_type;
struct drm_display_mode native_mode;
void *enc_priv;
int audio_polling_active;
@@ -392,7 +403,7 @@ struct radeon_connector {
uint32_t connector_id;
uint32_t devices;
struct radeon_i2c_chan *ddc_bus;
- /* some systems have a an hdmi and vga port with a shared ddc line */
+ /* some systems have an hdmi and vga port with a shared ddc line */
bool shared_ddc;
bool use_digital;
/* we need to mind the EDID between detect
@@ -414,6 +425,9 @@ radeon_combios_get_tv_info(struct radeon_device *rdev);
extern enum radeon_tv_std
radeon_atombios_get_tv_info(struct radeon_device *rdev);
+extern struct drm_connector *
+radeon_get_connector_for_encoder(struct drm_encoder *encoder);
+
extern void radeon_connector_hotplug(struct drm_connector *connector);
extern bool radeon_dp_needs_link_train(struct radeon_connector *radeon_connector);
extern int radeon_dp_mode_valid_helper(struct radeon_connector *radeon_connector,
diff --git a/drivers/gpu/drm/radeon/radeon_object.c b/drivers/gpu/drm/radeon/radeon_object.c
index d5b9373ce06..0afd1e62347 100644
--- a/drivers/gpu/drm/radeon/radeon_object.c
+++ b/drivers/gpu/drm/radeon/radeon_object.c
@@ -110,6 +110,7 @@ int radeon_bo_create(struct radeon_device *rdev, struct drm_gem_object *gobj,
bo->surface_reg = -1;
INIT_LIST_HEAD(&bo->list);
+retry:
radeon_ttm_placement_from_domain(bo, domain);
/* Kernel allocation are uninterruptible */
mutex_lock(&rdev->vram_mutex);
@@ -118,10 +119,15 @@ int radeon_bo_create(struct radeon_device *rdev, struct drm_gem_object *gobj,
&radeon_ttm_bo_destroy);
mutex_unlock(&rdev->vram_mutex);
if (unlikely(r != 0)) {
- if (r != -ERESTARTSYS)
+ if (r != -ERESTARTSYS) {
+ if (domain == RADEON_GEM_DOMAIN_VRAM) {
+ domain |= RADEON_GEM_DOMAIN_GTT;
+ goto retry;
+ }
dev_err(rdev->dev,
"object_init failed for (%lu, 0x%08X)\n",
size, domain);
+ }
return r;
}
*bo_ptr = bo;
@@ -321,6 +327,7 @@ int radeon_bo_list_validate(struct list_head *head)
{
struct radeon_bo_list *lobj;
struct radeon_bo *bo;
+ u32 domain;
int r;
list_for_each_entry(lobj, head, list) {
@@ -333,17 +340,19 @@ int radeon_bo_list_validate(struct list_head *head)
list_for_each_entry(lobj, head, list) {
bo = lobj->bo;
if (!bo->pin_count) {
- if (lobj->wdomain) {
- radeon_ttm_placement_from_domain(bo,
- lobj->wdomain);
- } else {
- radeon_ttm_placement_from_domain(bo,
- lobj->rdomain);
- }
+ domain = lobj->wdomain ? lobj->wdomain : lobj->rdomain;
+
+ retry:
+ radeon_ttm_placement_from_domain(bo, domain);
r = ttm_bo_validate(&bo->tbo, &bo->placement,
true, false, false);
- if (unlikely(r))
+ if (unlikely(r)) {
+ if (r != -ERESTARTSYS && domain == RADEON_GEM_DOMAIN_VRAM) {
+ domain |= RADEON_GEM_DOMAIN_GTT;
+ goto retry;
+ }
return r;
+ }
}
lobj->gpu_offset = radeon_bo_gpu_offset(bo);
lobj->tiling_flags = bo->tiling_flags;
diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c
index 3fa6984d989..95f8b3a3c43 100644
--- a/drivers/gpu/drm/radeon/radeon_pm.c
+++ b/drivers/gpu/drm/radeon/radeon_pm.c
@@ -27,6 +27,8 @@
#include <linux/acpi.h>
#endif
#include <linux/power_supply.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
#define RADEON_IDLE_LOOP_MS 100
#define RADEON_RECLOCK_DELAY_MS 200
@@ -60,9 +62,9 @@ static int radeon_acpi_event(struct notifier_block *nb,
if (strcmp(entry->device_class, ACPI_AC_CLASS) == 0) {
if (power_supply_is_system_supplied() > 0)
- DRM_DEBUG("pm: AC\n");
+ DRM_DEBUG_DRIVER("pm: AC\n");
else
- DRM_DEBUG("pm: DC\n");
+ DRM_DEBUG_DRIVER("pm: DC\n");
if (rdev->pm.pm_method == PM_METHOD_PROFILE) {
if (rdev->pm.profile == PM_PROFILE_AUTO) {
@@ -196,7 +198,7 @@ static void radeon_set_power_state(struct radeon_device *rdev)
radeon_set_engine_clock(rdev, sclk);
radeon_pm_debug_check_in_vbl(rdev, true);
rdev->pm.current_sclk = sclk;
- DRM_DEBUG("Setting: e: %d\n", sclk);
+ DRM_DEBUG_DRIVER("Setting: e: %d\n", sclk);
}
/* set memory clock */
@@ -205,7 +207,7 @@ static void radeon_set_power_state(struct radeon_device *rdev)
radeon_set_memory_clock(rdev, mclk);
radeon_pm_debug_check_in_vbl(rdev, true);
rdev->pm.current_mclk = mclk;
- DRM_DEBUG("Setting: m: %d\n", mclk);
+ DRM_DEBUG_DRIVER("Setting: m: %d\n", mclk);
}
if (misc_after)
@@ -217,7 +219,7 @@ static void radeon_set_power_state(struct radeon_device *rdev)
rdev->pm.current_power_state_index = rdev->pm.requested_power_state_index;
rdev->pm.current_clock_mode_index = rdev->pm.requested_clock_mode_index;
} else
- DRM_DEBUG("pm: GUI not idle!!!\n");
+ DRM_DEBUG_DRIVER("pm: GUI not idle!!!\n");
}
static void radeon_pm_set_clocks(struct radeon_device *rdev)
@@ -292,27 +294,27 @@ static void radeon_pm_print_states(struct radeon_device *rdev)
struct radeon_power_state *power_state;
struct radeon_pm_clock_info *clock_info;
- DRM_DEBUG("%d Power State(s)\n", rdev->pm.num_power_states);
+ DRM_DEBUG_DRIVER("%d Power State(s)\n", rdev->pm.num_power_states);
for (i = 0; i < rdev->pm.num_power_states; i++) {
power_state = &rdev->pm.power_state[i];
- DRM_DEBUG("State %d: %s\n", i,
+ DRM_DEBUG_DRIVER("State %d: %s\n", i,
radeon_pm_state_type_name[power_state->type]);
if (i == rdev->pm.default_power_state_index)
- DRM_DEBUG("\tDefault");
+ DRM_DEBUG_DRIVER("\tDefault");
if ((rdev->flags & RADEON_IS_PCIE) && !(rdev->flags & RADEON_IS_IGP))
- DRM_DEBUG("\t%d PCIE Lanes\n", power_state->pcie_lanes);
+ DRM_DEBUG_DRIVER("\t%d PCIE Lanes\n", power_state->pcie_lanes);
if (power_state->flags & RADEON_PM_STATE_SINGLE_DISPLAY_ONLY)
- DRM_DEBUG("\tSingle display only\n");
- DRM_DEBUG("\t%d Clock Mode(s)\n", power_state->num_clock_modes);
+ DRM_DEBUG_DRIVER("\tSingle display only\n");
+ DRM_DEBUG_DRIVER("\t%d Clock Mode(s)\n", power_state->num_clock_modes);
for (j = 0; j < power_state->num_clock_modes; j++) {
clock_info = &(power_state->clock_info[j]);
if (rdev->flags & RADEON_IS_IGP)
- DRM_DEBUG("\t\t%d e: %d%s\n",
+ DRM_DEBUG_DRIVER("\t\t%d e: %d%s\n",
j,
clock_info->sclk * 10,
clock_info->flags & RADEON_PM_MODE_NO_DISPLAY ? "\tNo display only" : "");
else
- DRM_DEBUG("\t\t%d e: %d\tm: %d\tv: %d%s\n",
+ DRM_DEBUG_DRIVER("\t\t%d e: %d\tm: %d\tv: %d%s\n",
j,
clock_info->sclk * 10,
clock_info->mclk * 10,
@@ -424,6 +426,82 @@ fail:
static DEVICE_ATTR(power_profile, S_IRUGO | S_IWUSR, radeon_get_pm_profile, radeon_set_pm_profile);
static DEVICE_ATTR(power_method, S_IRUGO | S_IWUSR, radeon_get_pm_method, radeon_set_pm_method);
+static ssize_t radeon_hwmon_show_temp(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct drm_device *ddev = pci_get_drvdata(to_pci_dev(dev));
+ struct radeon_device *rdev = ddev->dev_private;
+ u32 temp;
+
+ switch (rdev->pm.int_thermal_type) {
+ case THERMAL_TYPE_RV6XX:
+ temp = rv6xx_get_temp(rdev);
+ break;
+ case THERMAL_TYPE_RV770:
+ temp = rv770_get_temp(rdev);
+ break;
+ case THERMAL_TYPE_EVERGREEN:
+ temp = evergreen_get_temp(rdev);
+ break;
+ default:
+ temp = 0;
+ break;
+ }
+
+ return snprintf(buf, PAGE_SIZE, "%d\n", temp);
+}
+
+static ssize_t radeon_hwmon_show_name(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return sprintf(buf, "radeon\n");
+}
+
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, radeon_hwmon_show_temp, NULL, 0);
+static SENSOR_DEVICE_ATTR(name, S_IRUGO, radeon_hwmon_show_name, NULL, 0);
+
+static struct attribute *hwmon_attributes[] = {
+ &sensor_dev_attr_temp1_input.dev_attr.attr,
+ &sensor_dev_attr_name.dev_attr.attr,
+ NULL
+};
+
+static const struct attribute_group hwmon_attrgroup = {
+ .attrs = hwmon_attributes,
+};
+
+static void radeon_hwmon_init(struct radeon_device *rdev)
+{
+ int err;
+
+ rdev->pm.int_hwmon_dev = NULL;
+
+ switch (rdev->pm.int_thermal_type) {
+ case THERMAL_TYPE_RV6XX:
+ case THERMAL_TYPE_RV770:
+ case THERMAL_TYPE_EVERGREEN:
+ rdev->pm.int_hwmon_dev = hwmon_device_register(rdev->dev);
+ dev_set_drvdata(rdev->pm.int_hwmon_dev, rdev->ddev);
+ err = sysfs_create_group(&rdev->pm.int_hwmon_dev->kobj,
+ &hwmon_attrgroup);
+ if (err)
+ DRM_ERROR("Unable to create hwmon sysfs file: %d\n", err);
+ break;
+ default:
+ break;
+ }
+}
+
+static void radeon_hwmon_fini(struct radeon_device *rdev)
+{
+ if (rdev->pm.int_hwmon_dev) {
+ sysfs_remove_group(&rdev->pm.int_hwmon_dev->kobj, &hwmon_attrgroup);
+ hwmon_device_unregister(rdev->pm.int_hwmon_dev);
+ }
+}
+
void radeon_pm_suspend(struct radeon_device *rdev)
{
bool flush_wq = false;
@@ -471,6 +549,7 @@ int radeon_pm_init(struct radeon_device *rdev)
rdev->pm.dynpm_can_downclock = true;
rdev->pm.current_sclk = rdev->clock.default_sclk;
rdev->pm.current_mclk = rdev->clock.default_mclk;
+ rdev->pm.int_thermal_type = THERMAL_TYPE_NONE;
if (rdev->bios) {
if (rdev->is_atom_bios)
@@ -481,6 +560,8 @@ int radeon_pm_init(struct radeon_device *rdev)
radeon_pm_init_profile(rdev);
}
+ /* set up the internal thermal sensor if applicable */
+ radeon_hwmon_init(rdev);
if (rdev->pm.num_power_states > 1) {
/* where's the best place to put these? */
ret = device_create_file(rdev->dev, &dev_attr_power_profile);
@@ -536,6 +617,7 @@ void radeon_pm_fini(struct radeon_device *rdev)
#endif
}
+ radeon_hwmon_fini(rdev);
if (rdev->pm.i2c_bus)
radeon_i2c_destroy(rdev->pm.i2c_bus);
}
@@ -576,7 +658,7 @@ void radeon_pm_compute_clocks(struct radeon_device *rdev)
radeon_pm_get_dynpm_state(rdev);
radeon_pm_set_clocks(rdev);
- DRM_DEBUG("radeon: dynamic power management deactivated\n");
+ DRM_DEBUG_DRIVER("radeon: dynamic power management deactivated\n");
}
} else if (rdev->pm.active_crtc_count == 1) {
/* TODO: Increase clocks if needed for current mode */
@@ -593,7 +675,7 @@ void radeon_pm_compute_clocks(struct radeon_device *rdev)
rdev->pm.dynpm_state = DYNPM_STATE_ACTIVE;
queue_delayed_work(rdev->wq, &rdev->pm.dynpm_idle_work,
msecs_to_jiffies(RADEON_IDLE_LOOP_MS));
- DRM_DEBUG("radeon: dynamic power management activated\n");
+ DRM_DEBUG_DRIVER("radeon: dynamic power management activated\n");
}
} else { /* count == 0 */
if (rdev->pm.dynpm_state != DYNPM_STATE_MINIMUM) {
@@ -689,7 +771,7 @@ static bool radeon_pm_debug_check_in_vbl(struct radeon_device *rdev, bool finish
bool in_vbl = radeon_pm_in_vbl(rdev);
if (in_vbl == false)
- DRM_DEBUG("not in vbl for pm change %08x at %s\n", stat_crtc,
+ DRM_DEBUG_DRIVER("not in vbl for pm change %08x at %s\n", stat_crtc,
finish ? "exit" : "entry");
return in_vbl;
}
diff --git a/drivers/gpu/drm/radeon/radeon_ttm.c b/drivers/gpu/drm/radeon/radeon_ttm.c
index e9918d88f5b..84c53e41a88 100644
--- a/drivers/gpu/drm/radeon/radeon_ttm.c
+++ b/drivers/gpu/drm/radeon/radeon_ttm.c
@@ -59,28 +59,28 @@ static struct radeon_device *radeon_get_rdev(struct ttm_bo_device *bdev)
/*
* Global memory.
*/
-static int radeon_ttm_mem_global_init(struct ttm_global_reference *ref)
+static int radeon_ttm_mem_global_init(struct drm_global_reference *ref)
{
return ttm_mem_global_init(ref->object);
}
-static void radeon_ttm_mem_global_release(struct ttm_global_reference *ref)
+static void radeon_ttm_mem_global_release(struct drm_global_reference *ref)
{
ttm_mem_global_release(ref->object);
}
static int radeon_ttm_global_init(struct radeon_device *rdev)
{
- struct ttm_global_reference *global_ref;
+ struct drm_global_reference *global_ref;
int r;
rdev->mman.mem_global_referenced = false;
global_ref = &rdev->mman.mem_global_ref;
- global_ref->global_type = TTM_GLOBAL_TTM_MEM;
+ global_ref->global_type = DRM_GLOBAL_TTM_MEM;
global_ref->size = sizeof(struct ttm_mem_global);
global_ref->init = &radeon_ttm_mem_global_init;
global_ref->release = &radeon_ttm_mem_global_release;
- r = ttm_global_item_ref(global_ref);
+ r = drm_global_item_ref(global_ref);
if (r != 0) {
DRM_ERROR("Failed setting up TTM memory accounting "
"subsystem.\n");
@@ -90,14 +90,14 @@ static int radeon_ttm_global_init(struct radeon_device *rdev)
rdev->mman.bo_global_ref.mem_glob =
rdev->mman.mem_global_ref.object;
global_ref = &rdev->mman.bo_global_ref.ref;
- global_ref->global_type = TTM_GLOBAL_TTM_BO;
+ global_ref->global_type = DRM_GLOBAL_TTM_BO;
global_ref->size = sizeof(struct ttm_bo_global);
global_ref->init = &ttm_bo_global_init;
global_ref->release = &ttm_bo_global_release;
- r = ttm_global_item_ref(global_ref);
+ r = drm_global_item_ref(global_ref);
if (r != 0) {
DRM_ERROR("Failed setting up TTM BO subsystem.\n");
- ttm_global_item_unref(&rdev->mman.mem_global_ref);
+ drm_global_item_unref(&rdev->mman.mem_global_ref);
return r;
}
@@ -108,8 +108,8 @@ static int radeon_ttm_global_init(struct radeon_device *rdev)
static void radeon_ttm_global_fini(struct radeon_device *rdev)
{
if (rdev->mman.mem_global_referenced) {
- ttm_global_item_unref(&rdev->mman.bo_global_ref.ref);
- ttm_global_item_unref(&rdev->mman.mem_global_ref);
+ drm_global_item_unref(&rdev->mman.bo_global_ref.ref);
+ drm_global_item_unref(&rdev->mman.mem_global_ref);
rdev->mman.mem_global_referenced = false;
}
}
diff --git a/drivers/gpu/drm/radeon/reg_srcs/r300 b/drivers/gpu/drm/radeon/reg_srcs/r300
index 1e97b2d129f..b506ec1cab4 100644
--- a/drivers/gpu/drm/radeon/reg_srcs/r300
+++ b/drivers/gpu/drm/radeon/reg_srcs/r300
@@ -187,7 +187,6 @@ r300 0x4f60
0x4364 RS_INST_13
0x4368 RS_INST_14
0x436C RS_INST_15
-0x43A4 SC_HYPERZ_EN
0x43A8 SC_EDGERULE
0x43B0 SC_CLIP_0_A
0x43B4 SC_CLIP_0_B
@@ -716,16 +715,4 @@ r300 0x4f60
0x4F08 ZB_STENCILREFMASK
0x4F14 ZB_ZTOP
0x4F18 ZB_ZCACHE_CTLSTAT
-0x4F1C ZB_BW_CNTL
-0x4F28 ZB_DEPTHCLEARVALUE
-0x4F30 ZB_ZMASK_OFFSET
-0x4F34 ZB_ZMASK_PITCH
-0x4F38 ZB_ZMASK_WRINDEX
-0x4F3C ZB_ZMASK_DWORD
-0x4F40 ZB_ZMASK_RDINDEX
-0x4F44 ZB_HIZ_OFFSET
-0x4F48 ZB_HIZ_WRINDEX
-0x4F4C ZB_HIZ_DWORD
-0x4F50 ZB_HIZ_RDINDEX
-0x4F54 ZB_HIZ_PITCH
0x4F58 ZB_ZPASS_DATA
diff --git a/drivers/gpu/drm/radeon/reg_srcs/r420 b/drivers/gpu/drm/radeon/reg_srcs/r420
index e958980d00f..8c1214c2390 100644
--- a/drivers/gpu/drm/radeon/reg_srcs/r420
+++ b/drivers/gpu/drm/radeon/reg_srcs/r420
@@ -130,6 +130,7 @@ r420 0x4f60
0x401C GB_SELECT
0x4020 GB_AA_CONFIG
0x4024 GB_FIFO_SIZE
+0x4028 GB_Z_PEQ_CONFIG
0x4100 TX_INVALTAGS
0x4200 GA_POINT_S0
0x4204 GA_POINT_T0
@@ -187,7 +188,6 @@ r420 0x4f60
0x4364 RS_INST_13
0x4368 RS_INST_14
0x436C RS_INST_15
-0x43A4 SC_HYPERZ_EN
0x43A8 SC_EDGERULE
0x43B0 SC_CLIP_0_A
0x43B4 SC_CLIP_0_B
@@ -782,16 +782,4 @@ r420 0x4f60
0x4F08 ZB_STENCILREFMASK
0x4F14 ZB_ZTOP
0x4F18 ZB_ZCACHE_CTLSTAT
-0x4F1C ZB_BW_CNTL
-0x4F28 ZB_DEPTHCLEARVALUE
-0x4F30 ZB_ZMASK_OFFSET
-0x4F34 ZB_ZMASK_PITCH
-0x4F38 ZB_ZMASK_WRINDEX
-0x4F3C ZB_ZMASK_DWORD
-0x4F40 ZB_ZMASK_RDINDEX
-0x4F44 ZB_HIZ_OFFSET
-0x4F48 ZB_HIZ_WRINDEX
-0x4F4C ZB_HIZ_DWORD
-0x4F50 ZB_HIZ_RDINDEX
-0x4F54 ZB_HIZ_PITCH
0x4F58 ZB_ZPASS_DATA
diff --git a/drivers/gpu/drm/radeon/reg_srcs/rs600 b/drivers/gpu/drm/radeon/reg_srcs/rs600
index 83e8bc0c2bb..0828d80396f 100644
--- a/drivers/gpu/drm/radeon/reg_srcs/rs600
+++ b/drivers/gpu/drm/radeon/reg_srcs/rs600
@@ -187,7 +187,6 @@ rs600 0x6d40
0x4364 RS_INST_13
0x4368 RS_INST_14
0x436C RS_INST_15
-0x43A4 SC_HYPERZ_EN
0x43A8 SC_EDGERULE
0x43B0 SC_CLIP_0_A
0x43B4 SC_CLIP_0_B
@@ -782,16 +781,4 @@ rs600 0x6d40
0x4F08 ZB_STENCILREFMASK
0x4F14 ZB_ZTOP
0x4F18 ZB_ZCACHE_CTLSTAT
-0x4F1C ZB_BW_CNTL
-0x4F28 ZB_DEPTHCLEARVALUE
-0x4F30 ZB_ZMASK_OFFSET
-0x4F34 ZB_ZMASK_PITCH
-0x4F38 ZB_ZMASK_WRINDEX
-0x4F3C ZB_ZMASK_DWORD
-0x4F40 ZB_ZMASK_RDINDEX
-0x4F44 ZB_HIZ_OFFSET
-0x4F48 ZB_HIZ_WRINDEX
-0x4F4C ZB_HIZ_DWORD
-0x4F50 ZB_HIZ_RDINDEX
-0x4F54 ZB_HIZ_PITCH
0x4F58 ZB_ZPASS_DATA
diff --git a/drivers/gpu/drm/radeon/reg_srcs/rv515 b/drivers/gpu/drm/radeon/reg_srcs/rv515
index 1e46233985e..8293855f5f0 100644
--- a/drivers/gpu/drm/radeon/reg_srcs/rv515
+++ b/drivers/gpu/drm/radeon/reg_srcs/rv515
@@ -235,7 +235,6 @@ rv515 0x6d40
0x4354 RS_INST_13
0x4358 RS_INST_14
0x435C RS_INST_15
-0x43A4 SC_HYPERZ_EN
0x43A8 SC_EDGERULE
0x43B0 SC_CLIP_0_A
0x43B4 SC_CLIP_0_B
@@ -479,17 +478,5 @@ rv515 0x6d40
0x4F08 ZB_STENCILREFMASK
0x4F14 ZB_ZTOP
0x4F18 ZB_ZCACHE_CTLSTAT
-0x4F1C ZB_BW_CNTL
-0x4F28 ZB_DEPTHCLEARVALUE
-0x4F30 ZB_ZMASK_OFFSET
-0x4F34 ZB_ZMASK_PITCH
-0x4F38 ZB_ZMASK_WRINDEX
-0x4F3C ZB_ZMASK_DWORD
-0x4F40 ZB_ZMASK_RDINDEX
-0x4F44 ZB_HIZ_OFFSET
-0x4F48 ZB_HIZ_WRINDEX
-0x4F4C ZB_HIZ_DWORD
-0x4F50 ZB_HIZ_RDINDEX
-0x4F54 ZB_HIZ_PITCH
0x4F58 ZB_ZPASS_DATA
0x4FD4 ZB_STENCILREFMASK_BF
diff --git a/drivers/gpu/drm/radeon/rs400.c b/drivers/gpu/drm/radeon/rs400.c
index f454c9a5e7f..ae2b76b9a38 100644
--- a/drivers/gpu/drm/radeon/rs400.c
+++ b/drivers/gpu/drm/radeon/rs400.c
@@ -55,14 +55,6 @@ void rs400_gart_adjust_size(struct radeon_device *rdev)
rdev->mc.gtt_size = 32 * 1024 * 1024;
return;
}
- if (rdev->family == CHIP_RS400 || rdev->family == CHIP_RS480) {
- /* FIXME: RS400 & RS480 seems to have issue with GART size
- * if 4G of system memory (needs more testing)
- */
- /* XXX is this still an issue with proper alignment? */
- rdev->mc.gtt_size = 32 * 1024 * 1024;
- DRM_ERROR("Forcing to 32M GART size (because of ASIC bug ?)\n");
- }
}
void rs400_gart_tlb_flush(struct radeon_device *rdev)
@@ -483,6 +475,8 @@ int rs400_init(struct radeon_device *rdev)
/* Initialize surface registers */
radeon_surface_init(rdev);
/* TODO: disable VGA need to use VGA request */
+ /* restore some register to sane defaults */
+ r100_restore_sanity(rdev);
/* BIOS*/
if (!radeon_get_bios(rdev)) {
if (ASIC_IS_AVIVO(rdev))
diff --git a/drivers/gpu/drm/radeon/rs600.c b/drivers/gpu/drm/radeon/rs600.c
index 6dc15ea8ba3..cc05b230d7e 100644
--- a/drivers/gpu/drm/radeon/rs600.c
+++ b/drivers/gpu/drm/radeon/rs600.c
@@ -686,8 +686,8 @@ void rs600_mc_init(struct radeon_device *rdev)
{
u64 base;
- rdev->mc.aper_base = drm_get_resource_start(rdev->ddev, 0);
- rdev->mc.aper_size = drm_get_resource_len(rdev->ddev, 0);
+ rdev->mc.aper_base = pci_resource_start(rdev->pdev, 0);
+ rdev->mc.aper_size = pci_resource_len(rdev->pdev, 0);
rdev->mc.vram_is_ddr = true;
rdev->mc.vram_width = 128;
rdev->mc.real_vram_size = RREG32(RADEON_CONFIG_MEMSIZE);
@@ -696,7 +696,6 @@ void rs600_mc_init(struct radeon_device *rdev)
rdev->mc.igp_sideport_enabled = radeon_atombios_sideport_present(rdev);
base = RREG32_MC(R_000004_MC_FB_LOCATION);
base = G_000004_MC_FB_START(base) << 16;
- rdev->mc.igp_sideport_enabled = radeon_atombios_sideport_present(rdev);
radeon_vram_location(rdev, &rdev->mc, base);
rdev->mc.gtt_base_align = 0;
radeon_gtt_location(rdev, &rdev->mc);
@@ -813,6 +812,13 @@ static int rs600_startup(struct radeon_device *rdev)
dev_err(rdev->dev, "failled initializing IB (%d).\n", r);
return r;
}
+
+ r = r600_audio_init(rdev);
+ if (r) {
+ dev_err(rdev->dev, "failed initializing audio\n");
+ return r;
+ }
+
return 0;
}
@@ -839,6 +845,7 @@ int rs600_resume(struct radeon_device *rdev)
int rs600_suspend(struct radeon_device *rdev)
{
+ r600_audio_fini(rdev);
r100_cp_disable(rdev);
r100_wb_disable(rdev);
rs600_irq_disable(rdev);
@@ -848,6 +855,7 @@ int rs600_suspend(struct radeon_device *rdev)
void rs600_fini(struct radeon_device *rdev)
{
+ r600_audio_fini(rdev);
r100_cp_fini(rdev);
r100_wb_fini(rdev);
r100_ib_fini(rdev);
@@ -871,6 +879,8 @@ int rs600_init(struct radeon_device *rdev)
radeon_scratch_init(rdev);
/* Initialize surface registers */
radeon_surface_init(rdev);
+ /* restore some register to sane defaults */
+ r100_restore_sanity(rdev);
/* BIOS */
if (!radeon_get_bios(rdev)) {
if (ASIC_IS_AVIVO(rdev))
diff --git a/drivers/gpu/drm/radeon/rs690.c b/drivers/gpu/drm/radeon/rs690.c
index ce4ecbe1081..3e3f75718be 100644
--- a/drivers/gpu/drm/radeon/rs690.c
+++ b/drivers/gpu/drm/radeon/rs690.c
@@ -154,13 +154,13 @@ void rs690_mc_init(struct radeon_device *rdev)
rdev->mc.vram_width = 128;
rdev->mc.real_vram_size = RREG32(RADEON_CONFIG_MEMSIZE);
rdev->mc.mc_vram_size = rdev->mc.real_vram_size;
- rdev->mc.aper_base = drm_get_resource_start(rdev->ddev, 0);
- rdev->mc.aper_size = drm_get_resource_len(rdev->ddev, 0);
+ rdev->mc.aper_base = pci_resource_start(rdev->pdev, 0);
+ rdev->mc.aper_size = pci_resource_len(rdev->pdev, 0);
rdev->mc.visible_vram_size = rdev->mc.aper_size;
base = RREG32_MC(R_000100_MCCFG_FB_LOCATION);
base = G_000100_MC_FB_START(base) << 16;
- rs690_pm_info(rdev);
rdev->mc.igp_sideport_enabled = radeon_atombios_sideport_present(rdev);
+ rs690_pm_info(rdev);
radeon_vram_location(rdev, &rdev->mc, base);
rdev->mc.gtt_base_align = rdev->mc.gtt_size - 1;
radeon_gtt_location(rdev, &rdev->mc);
@@ -398,7 +398,9 @@ void rs690_bandwidth_update(struct radeon_device *rdev)
struct drm_display_mode *mode1 = NULL;
struct rs690_watermark wm0;
struct rs690_watermark wm1;
- u32 tmp, d1mode_priority_a_cnt, d2mode_priority_a_cnt;
+ u32 tmp;
+ u32 d1mode_priority_a_cnt = S_006548_D1MODE_PRIORITY_A_OFF(1);
+ u32 d2mode_priority_a_cnt = S_006548_D1MODE_PRIORITY_A_OFF(1);
fixed20_12 priority_mark02, priority_mark12, fill_rate;
fixed20_12 a, b;
@@ -495,10 +497,6 @@ void rs690_bandwidth_update(struct radeon_device *rdev)
d1mode_priority_a_cnt |= S_006548_D1MODE_PRIORITY_A_ALWAYS_ON(1);
d2mode_priority_a_cnt |= S_006D48_D2MODE_PRIORITY_A_ALWAYS_ON(1);
}
- WREG32(R_006548_D1MODE_PRIORITY_A_CNT, d1mode_priority_a_cnt);
- WREG32(R_00654C_D1MODE_PRIORITY_B_CNT, d1mode_priority_a_cnt);
- WREG32(R_006D48_D2MODE_PRIORITY_A_CNT, d2mode_priority_a_cnt);
- WREG32(R_006D4C_D2MODE_PRIORITY_B_CNT, d2mode_priority_a_cnt);
} else if (mode0) {
if (dfixed_trunc(wm0.dbpp) > 64)
a.full = dfixed_mul(wm0.dbpp, wm0.num_line_pair);
@@ -528,13 +526,7 @@ void rs690_bandwidth_update(struct radeon_device *rdev)
d1mode_priority_a_cnt = dfixed_trunc(priority_mark02);
if (rdev->disp_priority == 2)
d1mode_priority_a_cnt |= S_006548_D1MODE_PRIORITY_A_ALWAYS_ON(1);
- WREG32(R_006548_D1MODE_PRIORITY_A_CNT, d1mode_priority_a_cnt);
- WREG32(R_00654C_D1MODE_PRIORITY_B_CNT, d1mode_priority_a_cnt);
- WREG32(R_006D48_D2MODE_PRIORITY_A_CNT,
- S_006D48_D2MODE_PRIORITY_A_OFF(1));
- WREG32(R_006D4C_D2MODE_PRIORITY_B_CNT,
- S_006D4C_D2MODE_PRIORITY_B_OFF(1));
- } else {
+ } else if (mode1) {
if (dfixed_trunc(wm1.dbpp) > 64)
a.full = dfixed_mul(wm1.dbpp, wm1.num_line_pair);
else
@@ -563,13 +555,12 @@ void rs690_bandwidth_update(struct radeon_device *rdev)
d2mode_priority_a_cnt = dfixed_trunc(priority_mark12);
if (rdev->disp_priority == 2)
d2mode_priority_a_cnt |= S_006D48_D2MODE_PRIORITY_A_ALWAYS_ON(1);
- WREG32(R_006548_D1MODE_PRIORITY_A_CNT,
- S_006548_D1MODE_PRIORITY_A_OFF(1));
- WREG32(R_00654C_D1MODE_PRIORITY_B_CNT,
- S_00654C_D1MODE_PRIORITY_B_OFF(1));
- WREG32(R_006D48_D2MODE_PRIORITY_A_CNT, d2mode_priority_a_cnt);
- WREG32(R_006D4C_D2MODE_PRIORITY_B_CNT, d2mode_priority_a_cnt);
}
+
+ WREG32(R_006548_D1MODE_PRIORITY_A_CNT, d1mode_priority_a_cnt);
+ WREG32(R_00654C_D1MODE_PRIORITY_B_CNT, d1mode_priority_a_cnt);
+ WREG32(R_006D48_D2MODE_PRIORITY_A_CNT, d2mode_priority_a_cnt);
+ WREG32(R_006D4C_D2MODE_PRIORITY_B_CNT, d2mode_priority_a_cnt);
}
uint32_t rs690_mc_rreg(struct radeon_device *rdev, uint32_t reg)
@@ -641,6 +632,13 @@ static int rs690_startup(struct radeon_device *rdev)
dev_err(rdev->dev, "failled initializing IB (%d).\n", r);
return r;
}
+
+ r = r600_audio_init(rdev);
+ if (r) {
+ dev_err(rdev->dev, "failed initializing audio\n");
+ return r;
+ }
+
return 0;
}
@@ -667,6 +665,7 @@ int rs690_resume(struct radeon_device *rdev)
int rs690_suspend(struct radeon_device *rdev)
{
+ r600_audio_fini(rdev);
r100_cp_disable(rdev);
r100_wb_disable(rdev);
rs600_irq_disable(rdev);
@@ -676,6 +675,7 @@ int rs690_suspend(struct radeon_device *rdev)
void rs690_fini(struct radeon_device *rdev)
{
+ r600_audio_fini(rdev);
r100_cp_fini(rdev);
r100_wb_fini(rdev);
r100_ib_fini(rdev);
@@ -699,6 +699,8 @@ int rs690_init(struct radeon_device *rdev)
radeon_scratch_init(rdev);
/* Initialize surface registers */
radeon_surface_init(rdev);
+ /* restore some register to sane defaults */
+ r100_restore_sanity(rdev);
/* TODO: disable VGA need to use VGA request */
/* BIOS*/
if (!radeon_get_bios(rdev)) {
diff --git a/drivers/gpu/drm/radeon/rv515.c b/drivers/gpu/drm/radeon/rv515.c
index 0c9c169a685..4d6e86041a9 100644
--- a/drivers/gpu/drm/radeon/rv515.c
+++ b/drivers/gpu/drm/radeon/rv515.c
@@ -469,6 +469,8 @@ int rv515_init(struct radeon_device *rdev)
/* Initialize surface registers */
radeon_surface_init(rdev);
/* TODO: disable VGA need to use VGA request */
+ /* restore some register to sane defaults */
+ r100_restore_sanity(rdev);
/* BIOS*/
if (!radeon_get_bios(rdev)) {
if (ASIC_IS_AVIVO(rdev))
@@ -925,7 +927,9 @@ void rv515_bandwidth_avivo_update(struct radeon_device *rdev)
struct drm_display_mode *mode1 = NULL;
struct rv515_watermark wm0;
struct rv515_watermark wm1;
- u32 tmp, d1mode_priority_a_cnt, d2mode_priority_a_cnt;
+ u32 tmp;
+ u32 d1mode_priority_a_cnt = MODE_PRIORITY_OFF;
+ u32 d2mode_priority_a_cnt = MODE_PRIORITY_OFF;
fixed20_12 priority_mark02, priority_mark12, fill_rate;
fixed20_12 a, b;
@@ -999,10 +1003,6 @@ void rv515_bandwidth_avivo_update(struct radeon_device *rdev)
d1mode_priority_a_cnt |= MODE_PRIORITY_ALWAYS_ON;
d2mode_priority_a_cnt |= MODE_PRIORITY_ALWAYS_ON;
}
- WREG32(D1MODE_PRIORITY_A_CNT, d1mode_priority_a_cnt);
- WREG32(D1MODE_PRIORITY_B_CNT, d1mode_priority_a_cnt);
- WREG32(D2MODE_PRIORITY_A_CNT, d2mode_priority_a_cnt);
- WREG32(D2MODE_PRIORITY_B_CNT, d2mode_priority_a_cnt);
} else if (mode0) {
if (dfixed_trunc(wm0.dbpp) > 64)
a.full = dfixed_div(wm0.dbpp, wm0.num_line_pair);
@@ -1032,11 +1032,7 @@ void rv515_bandwidth_avivo_update(struct radeon_device *rdev)
d1mode_priority_a_cnt = dfixed_trunc(priority_mark02);
if (rdev->disp_priority == 2)
d1mode_priority_a_cnt |= MODE_PRIORITY_ALWAYS_ON;
- WREG32(D1MODE_PRIORITY_A_CNT, d1mode_priority_a_cnt);
- WREG32(D1MODE_PRIORITY_B_CNT, d1mode_priority_a_cnt);
- WREG32(D2MODE_PRIORITY_A_CNT, MODE_PRIORITY_OFF);
- WREG32(D2MODE_PRIORITY_B_CNT, MODE_PRIORITY_OFF);
- } else {
+ } else if (mode1) {
if (dfixed_trunc(wm1.dbpp) > 64)
a.full = dfixed_div(wm1.dbpp, wm1.num_line_pair);
else
@@ -1065,11 +1061,12 @@ void rv515_bandwidth_avivo_update(struct radeon_device *rdev)
d2mode_priority_a_cnt = dfixed_trunc(priority_mark12);
if (rdev->disp_priority == 2)
d2mode_priority_a_cnt |= MODE_PRIORITY_ALWAYS_ON;
- WREG32(D1MODE_PRIORITY_A_CNT, MODE_PRIORITY_OFF);
- WREG32(D1MODE_PRIORITY_B_CNT, MODE_PRIORITY_OFF);
- WREG32(D2MODE_PRIORITY_A_CNT, d2mode_priority_a_cnt);
- WREG32(D2MODE_PRIORITY_B_CNT, d2mode_priority_a_cnt);
}
+
+ WREG32(D1MODE_PRIORITY_A_CNT, d1mode_priority_a_cnt);
+ WREG32(D1MODE_PRIORITY_B_CNT, d1mode_priority_a_cnt);
+ WREG32(D2MODE_PRIORITY_A_CNT, d2mode_priority_a_cnt);
+ WREG32(D2MODE_PRIORITY_B_CNT, d2mode_priority_a_cnt);
}
void rv515_bandwidth_update(struct radeon_device *rdev)
diff --git a/drivers/gpu/drm/radeon/rv770.c b/drivers/gpu/drm/radeon/rv770.c
index b7fd8206492..f1c79681011 100644
--- a/drivers/gpu/drm/radeon/rv770.c
+++ b/drivers/gpu/drm/radeon/rv770.c
@@ -42,6 +42,21 @@
static void rv770_gpu_init(struct radeon_device *rdev);
void rv770_fini(struct radeon_device *rdev);
+/* get temperature in millidegrees */
+u32 rv770_get_temp(struct radeon_device *rdev)
+{
+ u32 temp = (RREG32(CG_MULT_THERMAL_STATUS) & ASIC_T_MASK) >>
+ ASIC_T_SHIFT;
+ u32 actual_temp = 0;
+
+ if ((temp >> 9) & 1)
+ actual_temp = 0;
+ else
+ actual_temp = (temp >> 1) & 0xff;
+
+ return actual_temp * 1000;
+}
+
void rv770_pm_misc(struct radeon_device *rdev)
{
int req_ps_idx = rdev->pm.requested_power_state_index;
@@ -189,7 +204,10 @@ static void rv770_mc_program(struct radeon_device *rdev)
WREG32((0x2c20 + j), 0x00000000);
WREG32((0x2c24 + j), 0x00000000);
}
- WREG32(HDP_REG_COHERENCY_FLUSH_CNTL, 0);
+ /* r7xx hw bug. Read from HDP_DEBUG1 rather
+ * than writing to HDP_REG_COHERENCY_FLUSH_CNTL
+ */
+ tmp = RREG32(HDP_DEBUG1);
rv515_mc_stop(rdev, &save);
if (r600_mc_wait_for_idle(rdev)) {
@@ -659,8 +677,9 @@ static void rv770_gpu_init(struct radeon_device *rdev)
r600_count_pipe_bits((cc_rb_backend_disable &
R7XX_MAX_BACKENDS_MASK) >> 16)),
(cc_rb_backend_disable >> 16));
- gb_tiling_config |= BACKEND_MAP(backend_map);
+ rdev->config.rv770.tile_config = gb_tiling_config;
+ gb_tiling_config |= BACKEND_MAP(backend_map);
WREG32(GB_TILING_CONFIG, gb_tiling_config);
WREG32(DCP_TILING_CONFIG, (gb_tiling_config & 0xffff));
@@ -919,8 +938,8 @@ int rv770_mc_init(struct radeon_device *rdev)
}
rdev->mc.vram_width = numchan * chansize;
/* Could aper size report 0 ? */
- rdev->mc.aper_base = drm_get_resource_start(rdev->ddev, 0);
- rdev->mc.aper_size = drm_get_resource_len(rdev->ddev, 0);
+ rdev->mc.aper_base = pci_resource_start(rdev->pdev, 0);
+ rdev->mc.aper_size = pci_resource_len(rdev->pdev, 0);
/* Setup GPU memory space */
rdev->mc.mc_vram_size = RREG32(CONFIG_MEMSIZE);
rdev->mc.real_vram_size = RREG32(CONFIG_MEMSIZE);
diff --git a/drivers/gpu/drm/radeon/rv770d.h b/drivers/gpu/drm/radeon/rv770d.h
index 9506f8cb99e..b7a5a20e81d 100644
--- a/drivers/gpu/drm/radeon/rv770d.h
+++ b/drivers/gpu/drm/radeon/rv770d.h
@@ -122,12 +122,18 @@
#define GUI_ACTIVE (1<<31)
#define GRBM_STATUS2 0x8014
+#define CG_MULT_THERMAL_STATUS 0x740
+#define ASIC_T(x) ((x) << 16)
+#define ASIC_T_MASK 0x3FF0000
+#define ASIC_T_SHIFT 16
+
#define HDP_HOST_PATH_CNTL 0x2C00
#define HDP_NONSURFACE_BASE 0x2C04
#define HDP_NONSURFACE_INFO 0x2C08
#define HDP_NONSURFACE_SIZE 0x2C0C
#define HDP_REG_COHERENCY_FLUSH_CNTL 0x54A0
#define HDP_TILING_CONFIG 0x2F3C
+#define HDP_DEBUG1 0x2F34
#define MC_SHARED_CHMAP 0x2004
#define NOOFCHAN_SHIFT 12
diff --git a/drivers/gpu/drm/savage/savage_bci.c b/drivers/gpu/drm/savage/savage_bci.c
index 2d0c9ca484c..976dc8d2528 100644
--- a/drivers/gpu/drm/savage/savage_bci.c
+++ b/drivers/gpu/drm/savage/savage_bci.c
@@ -552,7 +552,7 @@ int savage_driver_load(struct drm_device *dev, unsigned long chipset)
/*
- * Initalize mappings. On Savage4 and SavageIX the alignment
+ * Initialize mappings. On Savage4 and SavageIX the alignment
* and size of the aperture is not suitable for automatic MTRR setup
* in drm_addmap. Therefore we add them manually before the maps are
* initialized, and tear them down on last close.
@@ -573,13 +573,13 @@ int savage_driver_firstopen(struct drm_device *dev)
dev_priv->mtrr[2].handle = -1;
if (S3_SAVAGE3D_SERIES(dev_priv->chipset)) {
fb_rsrc = 0;
- fb_base = drm_get_resource_start(dev, 0);
+ fb_base = pci_resource_start(dev->pdev, 0);
fb_size = SAVAGE_FB_SIZE_S3;
mmio_base = fb_base + SAVAGE_FB_SIZE_S3;
aper_rsrc = 0;
aperture_base = fb_base + SAVAGE_APERTURE_OFFSET;
/* this should always be true */
- if (drm_get_resource_len(dev, 0) == 0x08000000) {
+ if (pci_resource_len(dev->pdev, 0) == 0x08000000) {
/* Don't make MMIO write-cobining! We need 3
* MTRRs. */
dev_priv->mtrr[0].base = fb_base;
@@ -599,18 +599,19 @@ int savage_driver_firstopen(struct drm_device *dev)
dev_priv->mtrr[2].size, DRM_MTRR_WC);
} else {
DRM_ERROR("strange pci_resource_len %08llx\n",
- (unsigned long long)drm_get_resource_len(dev, 0));
+ (unsigned long long)
+ pci_resource_len(dev->pdev, 0));
}
} else if (dev_priv->chipset != S3_SUPERSAVAGE &&
dev_priv->chipset != S3_SAVAGE2000) {
- mmio_base = drm_get_resource_start(dev, 0);
+ mmio_base = pci_resource_start(dev->pdev, 0);
fb_rsrc = 1;
- fb_base = drm_get_resource_start(dev, 1);
+ fb_base = pci_resource_start(dev->pdev, 1);
fb_size = SAVAGE_FB_SIZE_S4;
aper_rsrc = 1;
aperture_base = fb_base + SAVAGE_APERTURE_OFFSET;
/* this should always be true */
- if (drm_get_resource_len(dev, 1) == 0x08000000) {
+ if (pci_resource_len(dev->pdev, 1) == 0x08000000) {
/* Can use one MTRR to cover both fb and
* aperture. */
dev_priv->mtrr[0].base = fb_base;
@@ -620,15 +621,16 @@ int savage_driver_firstopen(struct drm_device *dev)
dev_priv->mtrr[0].size, DRM_MTRR_WC);
} else {
DRM_ERROR("strange pci_resource_len %08llx\n",
- (unsigned long long)drm_get_resource_len(dev, 1));
+ (unsigned long long)
+ pci_resource_len(dev->pdev, 1));
}
} else {
- mmio_base = drm_get_resource_start(dev, 0);
+ mmio_base = pci_resource_start(dev->pdev, 0);
fb_rsrc = 1;
- fb_base = drm_get_resource_start(dev, 1);
- fb_size = drm_get_resource_len(dev, 1);
+ fb_base = pci_resource_start(dev->pdev, 1);
+ fb_size = pci_resource_len(dev->pdev, 1);
aper_rsrc = 2;
- aperture_base = drm_get_resource_start(dev, 2);
+ aperture_base = pci_resource_start(dev->pdev, 2);
/* Automatic MTRR setup will do the right thing. */
}
diff --git a/drivers/gpu/drm/sis/sis_drv.c b/drivers/gpu/drm/sis/sis_drv.c
index 4fd1f067d38..776bf9e9ea1 100644
--- a/drivers/gpu/drm/sis/sis_drv.c
+++ b/drivers/gpu/drm/sis/sis_drv.c
@@ -47,9 +47,8 @@ static int sis_driver_load(struct drm_device *dev, unsigned long chipset)
dev->dev_private = (void *)dev_priv;
dev_priv->chipset = chipset;
ret = drm_sman_init(&dev_priv->sman, 2, 12, 8);
- if (ret) {
+ if (ret)
kfree(dev_priv);
- }
return ret;
}
diff --git a/drivers/gpu/drm/sis/sis_mm.c b/drivers/gpu/drm/sis/sis_mm.c
index af22111397d..07d0f2979ca 100644
--- a/drivers/gpu/drm/sis/sis_mm.c
+++ b/drivers/gpu/drm/sis/sis_mm.c
@@ -78,7 +78,7 @@ static unsigned long sis_sman_mm_offset(void *private, void *ref)
#else /* CONFIG_FB_SIS[_MODULE] */
#define SIS_MM_ALIGN_SHIFT 4
-#define SIS_MM_ALIGN_MASK ( (1 << SIS_MM_ALIGN_SHIFT) - 1)
+#define SIS_MM_ALIGN_MASK ((1 << SIS_MM_ALIGN_SHIFT) - 1)
#endif /* CONFIG_FB_SIS[_MODULE] */
@@ -225,9 +225,8 @@ static drm_local_map_t *sis_reg_init(struct drm_device *dev)
map = entry->map;
if (!map)
continue;
- if (map->type == _DRM_REGISTERS) {
+ if (map->type == _DRM_REGISTERS)
return map;
- }
}
return NULL;
}
@@ -264,10 +263,10 @@ int sis_idle(struct drm_device *dev)
end = jiffies + (DRM_HZ * 3);
- for (i=0; i<4; ++i) {
+ for (i = 0; i < 4; ++i) {
do {
idle_reg = SIS_READ(0x85cc);
- } while ( !time_after_eq(jiffies, end) &&
+ } while (!time_after_eq(jiffies, end) &&
((idle_reg & 0x80000000) != 0x80000000));
}
@@ -301,7 +300,7 @@ void sis_lastclose(struct drm_device *dev)
mutex_unlock(&dev->struct_mutex);
}
-void sis_reclaim_buffers_locked(struct drm_device * dev,
+void sis_reclaim_buffers_locked(struct drm_device *dev,
struct drm_file *file_priv)
{
drm_sis_private_t *dev_priv = dev->dev_private;
@@ -312,9 +311,8 @@ void sis_reclaim_buffers_locked(struct drm_device * dev,
return;
}
- if (dev->driver->dma_quiescent) {
+ if (dev->driver->dma_quiescent)
dev->driver->dma_quiescent(dev);
- }
drm_sman_owner_cleanup(&dev_priv->sman, (unsigned long)file_priv);
mutex_unlock(&dev->struct_mutex);
diff --git a/drivers/gpu/drm/ttm/Makefile b/drivers/gpu/drm/ttm/Makefile
index 4256e200647..b256d4adfaf 100644
--- a/drivers/gpu/drm/ttm/Makefile
+++ b/drivers/gpu/drm/ttm/Makefile
@@ -3,7 +3,7 @@
ccflags-y := -Iinclude/drm
ttm-y := ttm_agp_backend.o ttm_memory.o ttm_tt.o ttm_bo.o \
- ttm_bo_util.o ttm_bo_vm.o ttm_module.o ttm_global.o \
+ ttm_bo_util.o ttm_bo_vm.o ttm_module.o \
ttm_object.o ttm_lock.o ttm_execbuf_util.o ttm_page_alloc.o
obj-$(CONFIG_DRM_TTM) += ttm.o
diff --git a/drivers/gpu/drm/ttm/ttm_bo.c b/drivers/gpu/drm/ttm/ttm_bo.c
index 555ebb12ace..cb4cf7ef4d1 100644
--- a/drivers/gpu/drm/ttm/ttm_bo.c
+++ b/drivers/gpu/drm/ttm/ttm_bo.c
@@ -476,7 +476,6 @@ static int ttm_bo_cleanup_refs(struct ttm_buffer_object *bo, bool remove_all)
++put_count;
}
if (bo->mem.mm_node) {
- bo->mem.mm_node->private = NULL;
drm_mm_put_block(bo->mem.mm_node);
bo->mem.mm_node = NULL;
}
@@ -670,7 +669,6 @@ static int ttm_bo_evict(struct ttm_buffer_object *bo, bool interruptible,
printk(KERN_ERR TTM_PFX "Buffer eviction failed\n");
spin_lock(&glob->lru_lock);
if (evict_mem.mm_node) {
- evict_mem.mm_node->private = NULL;
drm_mm_put_block(evict_mem.mm_node);
evict_mem.mm_node = NULL;
}
@@ -929,8 +927,6 @@ int ttm_bo_mem_space(struct ttm_buffer_object *bo,
mem->mm_node = node;
mem->mem_type = mem_type;
mem->placement = cur_flags;
- if (node)
- node->private = bo;
return 0;
}
@@ -973,7 +969,6 @@ int ttm_bo_mem_space(struct ttm_buffer_object *bo,
interruptible, no_wait_reserve, no_wait_gpu);
if (ret == 0 && mem->mm_node) {
mem->placement = cur_flags;
- mem->mm_node->private = bo;
return 0;
}
if (ret == -ERESTARTSYS)
@@ -1029,7 +1024,6 @@ int ttm_bo_move_buffer(struct ttm_buffer_object *bo,
out_unlock:
if (ret && mem.mm_node) {
spin_lock(&glob->lru_lock);
- mem.mm_node->private = NULL;
drm_mm_put_block(mem.mm_node);
spin_unlock(&glob->lru_lock);
}
@@ -1401,7 +1395,7 @@ static void ttm_bo_global_kobj_release(struct kobject *kobj)
kfree(glob);
}
-void ttm_bo_global_release(struct ttm_global_reference *ref)
+void ttm_bo_global_release(struct drm_global_reference *ref)
{
struct ttm_bo_global *glob = ref->object;
@@ -1410,7 +1404,7 @@ void ttm_bo_global_release(struct ttm_global_reference *ref)
}
EXPORT_SYMBOL(ttm_bo_global_release);
-int ttm_bo_global_init(struct ttm_global_reference *ref)
+int ttm_bo_global_init(struct drm_global_reference *ref)
{
struct ttm_bo_global_ref *bo_ref =
container_of(ref, struct ttm_bo_global_ref, ref);
diff --git a/drivers/gpu/drm/ttm/ttm_bo_util.c b/drivers/gpu/drm/ttm/ttm_bo_util.c
index 13012a1f148..7cffb3e0423 100644
--- a/drivers/gpu/drm/ttm/ttm_bo_util.c
+++ b/drivers/gpu/drm/ttm/ttm_bo_util.c
@@ -353,8 +353,6 @@ static int ttm_buffer_object_transfer(struct ttm_buffer_object *bo,
fbo->vm_node = NULL;
fbo->sync_obj = driver->sync_obj_ref(bo->sync_obj);
- if (fbo->mem.mm_node)
- fbo->mem.mm_node->private = (void *)fbo;
kref_init(&fbo->list_kref);
kref_init(&fbo->kref);
fbo->destroy = &ttm_transfered_destroy;
diff --git a/drivers/gpu/drm/ttm/ttm_module.c b/drivers/gpu/drm/ttm/ttm_module.c
index 9a6edbfeaa9..902d7cf9fb4 100644
--- a/drivers/gpu/drm/ttm/ttm_module.c
+++ b/drivers/gpu/drm/ttm/ttm_module.c
@@ -70,8 +70,6 @@ static int __init ttm_init(void)
if (unlikely(ret != 0))
return ret;
- ttm_global_init();
-
atomic_set(&device_released, 0);
ret = drm_class_device_register(&ttm_drm_class_device);
if (unlikely(ret != 0))
@@ -81,7 +79,6 @@ static int __init ttm_init(void)
out_no_dev_reg:
atomic_set(&device_released, 1);
wake_up_all(&exit_q);
- ttm_global_release();
return ret;
}
@@ -95,7 +92,6 @@ static void __exit ttm_exit(void)
*/
wait_event(exit_q, atomic_read(&device_released) == 1);
- ttm_global_release();
}
module_init(ttm_init);
diff --git a/drivers/gpu/drm/via/via_dma.c b/drivers/gpu/drm/via/via_dma.c
index bfb92d28326..68dda74a50a 100644
--- a/drivers/gpu/drm/via/via_dma.c
+++ b/drivers/gpu/drm/via/via_dma.c
@@ -58,28 +58,29 @@
*((uint32_t *)(vb)) = ((nReg) >> 2) | HALCYON_HEADER1; \
*((uint32_t *)(vb) + 1) = (nData); \
vb = ((uint32_t *)vb) + 2; \
- dev_priv->dma_low +=8; \
+ dev_priv->dma_low += 8; \
}
#define via_flush_write_combine() DRM_MEMORYBARRIER()
-#define VIA_OUT_RING_QW(w1,w2) \
+#define VIA_OUT_RING_QW(w1, w2) do { \
*vb++ = (w1); \
*vb++ = (w2); \
- dev_priv->dma_low += 8;
+ dev_priv->dma_low += 8; \
+} while (0)
-static void via_cmdbuf_start(drm_via_private_t * dev_priv);
-static void via_cmdbuf_pause(drm_via_private_t * dev_priv);
-static void via_cmdbuf_reset(drm_via_private_t * dev_priv);
-static void via_cmdbuf_rewind(drm_via_private_t * dev_priv);
-static int via_wait_idle(drm_via_private_t * dev_priv);
-static void via_pad_cache(drm_via_private_t * dev_priv, int qwords);
+static void via_cmdbuf_start(drm_via_private_t *dev_priv);
+static void via_cmdbuf_pause(drm_via_private_t *dev_priv);
+static void via_cmdbuf_reset(drm_via_private_t *dev_priv);
+static void via_cmdbuf_rewind(drm_via_private_t *dev_priv);
+static int via_wait_idle(drm_via_private_t *dev_priv);
+static void via_pad_cache(drm_via_private_t *dev_priv, int qwords);
/*
* Free space in command buffer.
*/
-static uint32_t via_cmdbuf_space(drm_via_private_t * dev_priv)
+static uint32_t via_cmdbuf_space(drm_via_private_t *dev_priv)
{
uint32_t agp_base = dev_priv->dma_offset + (uint32_t) dev_priv->agpAddr;
uint32_t hw_addr = *(dev_priv->hw_addr_ptr) - agp_base;
@@ -93,7 +94,7 @@ static uint32_t via_cmdbuf_space(drm_via_private_t * dev_priv)
* How much does the command regulator lag behind?
*/
-static uint32_t via_cmdbuf_lag(drm_via_private_t * dev_priv)
+static uint32_t via_cmdbuf_lag(drm_via_private_t *dev_priv)
{
uint32_t agp_base = dev_priv->dma_offset + (uint32_t) dev_priv->agpAddr;
uint32_t hw_addr = *(dev_priv->hw_addr_ptr) - agp_base;
@@ -108,7 +109,7 @@ static uint32_t via_cmdbuf_lag(drm_via_private_t * dev_priv)
*/
static inline int
-via_cmdbuf_wait(drm_via_private_t * dev_priv, unsigned int size)
+via_cmdbuf_wait(drm_via_private_t *dev_priv, unsigned int size)
{
uint32_t agp_base = dev_priv->dma_offset + (uint32_t) dev_priv->agpAddr;
uint32_t cur_addr, hw_addr, next_addr;
@@ -146,14 +147,13 @@ static inline uint32_t *via_check_dma(drm_via_private_t * dev_priv,
dev_priv->dma_high) {
via_cmdbuf_rewind(dev_priv);
}
- if (via_cmdbuf_wait(dev_priv, size) != 0) {
+ if (via_cmdbuf_wait(dev_priv, size) != 0)
return NULL;
- }
return (uint32_t *) (dev_priv->dma_ptr + dev_priv->dma_low);
}
-int via_dma_cleanup(struct drm_device * dev)
+int via_dma_cleanup(struct drm_device *dev)
{
if (dev->dev_private) {
drm_via_private_t *dev_priv =
@@ -171,9 +171,9 @@ int via_dma_cleanup(struct drm_device * dev)
return 0;
}
-static int via_initialize(struct drm_device * dev,
- drm_via_private_t * dev_priv,
- drm_via_dma_init_t * init)
+static int via_initialize(struct drm_device *dev,
+ drm_via_private_t *dev_priv,
+ drm_via_dma_init_t *init)
{
if (!dev_priv || !dev_priv->mmio) {
DRM_ERROR("via_dma_init called before via_map_init\n");
@@ -258,7 +258,7 @@ static int via_dma_init(struct drm_device *dev, void *data, struct drm_file *fil
return retcode;
}
-static int via_dispatch_cmdbuffer(struct drm_device * 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;
@@ -271,9 +271,8 @@ static int via_dispatch_cmdbuffer(struct drm_device * dev, drm_via_cmdbuffer_t *
return -EFAULT;
}
- if (cmd->size > VIA_PCI_BUF_SIZE) {
+ if (cmd->size > VIA_PCI_BUF_SIZE)
return -ENOMEM;
- }
if (DRM_COPY_FROM_USER(dev_priv->pci_buf, cmd->buf, cmd->size))
return -EFAULT;
@@ -291,9 +290,8 @@ static int via_dispatch_cmdbuffer(struct drm_device * dev, drm_via_cmdbuffer_t *
}
vb = via_check_dma(dev_priv, (cmd->size < 0x100) ? 0x102 : cmd->size);
- if (vb == NULL) {
+ if (vb == NULL)
return -EAGAIN;
- }
memcpy(vb, dev_priv->pci_buf, cmd->size);
@@ -311,13 +309,12 @@ static int via_dispatch_cmdbuffer(struct drm_device * dev, drm_via_cmdbuffer_t *
return 0;
}
-int via_driver_dma_quiescent(struct drm_device * dev)
+int via_driver_dma_quiescent(struct drm_device *dev)
{
drm_via_private_t *dev_priv = dev->dev_private;
- if (!via_wait_idle(dev_priv)) {
+ if (!via_wait_idle(dev_priv))
return -EBUSY;
- }
return 0;
}
@@ -339,22 +336,17 @@ static int via_cmdbuffer(struct drm_device *dev, void *data, struct drm_file *fi
DRM_DEBUG("buf %p size %lu\n", cmdbuf->buf, cmdbuf->size);
ret = via_dispatch_cmdbuffer(dev, cmdbuf);
- if (ret) {
- return ret;
- }
-
- return 0;
+ return ret;
}
-static int via_dispatch_pci_cmdbuffer(struct drm_device * dev,
- drm_via_cmdbuffer_t * cmd)
+static int via_dispatch_pci_cmdbuffer(struct drm_device *dev,
+ drm_via_cmdbuffer_t *cmd)
{
drm_via_private_t *dev_priv = dev->dev_private;
int ret;
- if (cmd->size > VIA_PCI_BUF_SIZE) {
+ if (cmd->size > VIA_PCI_BUF_SIZE)
return -ENOMEM;
- }
if (DRM_COPY_FROM_USER(dev_priv->pci_buf, cmd->buf, cmd->size))
return -EFAULT;
@@ -380,19 +372,14 @@ static int via_pci_cmdbuffer(struct drm_device *dev, void *data, struct drm_file
DRM_DEBUG("buf %p size %lu\n", cmdbuf->buf, cmdbuf->size);
ret = via_dispatch_pci_cmdbuffer(dev, cmdbuf);
- if (ret) {
- return ret;
- }
-
- return 0;
+ return ret;
}
-static inline uint32_t *via_align_buffer(drm_via_private_t * dev_priv,
+static inline uint32_t *via_align_buffer(drm_via_private_t *dev_priv,
uint32_t * vb, int qw_count)
{
- for (; qw_count > 0; --qw_count) {
+ for (; qw_count > 0; --qw_count)
VIA_OUT_RING_QW(HC_DUMMY, HC_DUMMY);
- }
return vb;
}
@@ -401,7 +388,7 @@ static inline uint32_t *via_align_buffer(drm_via_private_t * dev_priv,
*
* Returns virtual pointer to ring buffer.
*/
-static inline uint32_t *via_get_dma(drm_via_private_t * dev_priv)
+static inline uint32_t *via_get_dma(drm_via_private_t *dev_priv)
{
return (uint32_t *) (dev_priv->dma_ptr + dev_priv->dma_low);
}
@@ -411,18 +398,18 @@ static inline uint32_t *via_get_dma(drm_via_private_t * dev_priv)
* modifying the pause address stored in the buffer itself. If
* the regulator has already paused, restart it.
*/
-static int via_hook_segment(drm_via_private_t * dev_priv,
+static int via_hook_segment(drm_via_private_t *dev_priv,
uint32_t pause_addr_hi, uint32_t pause_addr_lo,
int no_pci_fire)
{
int paused, count;
volatile uint32_t *paused_at = dev_priv->last_pause_ptr;
- uint32_t reader,ptr;
+ uint32_t reader, ptr;
uint32_t diff;
paused = 0;
via_flush_write_combine();
- (void) *(volatile uint32_t *)(via_get_dma(dev_priv) -1);
+ (void) *(volatile uint32_t *)(via_get_dma(dev_priv) - 1);
*paused_at = pause_addr_lo;
via_flush_write_combine();
@@ -435,7 +422,7 @@ static int via_hook_segment(drm_via_private_t * dev_priv,
dev_priv->last_pause_ptr = via_get_dma(dev_priv) - 1;
/*
- * If there is a possibility that the command reader will
+ * If there is a possibility that the command reader will
* miss the new pause address and pause on the old one,
* In that case we need to program the new start address
* using PCI.
@@ -443,9 +430,9 @@ static int via_hook_segment(drm_via_private_t * dev_priv,
diff = (uint32_t) (ptr - reader) - dev_priv->dma_diff;
count = 10000000;
- while(diff == 0 && count--) {
+ while (diff == 0 && count--) {
paused = (VIA_READ(0x41c) & 0x80000000);
- if (paused)
+ if (paused)
break;
reader = *(dev_priv->hw_addr_ptr);
diff = (uint32_t) (ptr - reader) - dev_priv->dma_diff;
@@ -477,7 +464,7 @@ static int via_hook_segment(drm_via_private_t * dev_priv,
return paused;
}
-static int via_wait_idle(drm_via_private_t * dev_priv)
+static int via_wait_idle(drm_via_private_t *dev_priv)
{
int count = 10000000;
@@ -491,9 +478,9 @@ static int via_wait_idle(drm_via_private_t * dev_priv)
return count;
}
-static uint32_t *via_align_cmd(drm_via_private_t * dev_priv, uint32_t cmd_type,
- uint32_t addr, uint32_t * cmd_addr_hi,
- uint32_t * cmd_addr_lo, int skip_wait)
+static uint32_t *via_align_cmd(drm_via_private_t *dev_priv, uint32_t cmd_type,
+ uint32_t addr, uint32_t *cmd_addr_hi,
+ uint32_t *cmd_addr_lo, int skip_wait)
{
uint32_t agp_base;
uint32_t cmd_addr, addr_lo, addr_hi;
@@ -521,7 +508,7 @@ static uint32_t *via_align_cmd(drm_via_private_t * dev_priv, uint32_t cmd_type,
return vb;
}
-static void via_cmdbuf_start(drm_via_private_t * dev_priv)
+static void via_cmdbuf_start(drm_via_private_t *dev_priv)
{
uint32_t pause_addr_lo, pause_addr_hi;
uint32_t start_addr, start_addr_lo;
@@ -580,7 +567,7 @@ static void via_cmdbuf_start(drm_via_private_t * dev_priv)
dev_priv->dma_diff = ptr - reader;
}
-static void via_pad_cache(drm_via_private_t * dev_priv, int qwords)
+static void via_pad_cache(drm_via_private_t *dev_priv, int qwords)
{
uint32_t *vb;
@@ -590,7 +577,7 @@ static void via_pad_cache(drm_via_private_t * dev_priv, int qwords)
via_align_buffer(dev_priv, vb, qwords);
}
-static inline void via_dummy_bitblt(drm_via_private_t * dev_priv)
+static inline void via_dummy_bitblt(drm_via_private_t *dev_priv)
{
uint32_t *vb = via_get_dma(dev_priv);
SetReg2DAGP(0x0C, (0 | (0 << 16)));
@@ -598,7 +585,7 @@ static inline void via_dummy_bitblt(drm_via_private_t * dev_priv)
SetReg2DAGP(0x0, 0x1 | 0x2000 | 0xAA000000);
}
-static void via_cmdbuf_jump(drm_via_private_t * dev_priv)
+static void via_cmdbuf_jump(drm_via_private_t *dev_priv)
{
uint32_t agp_base;
uint32_t pause_addr_lo, pause_addr_hi;
@@ -617,9 +604,8 @@ static void via_cmdbuf_jump(drm_via_private_t * dev_priv)
*/
dev_priv->dma_low = 0;
- if (via_cmdbuf_wait(dev_priv, CMDBUF_ALIGNMENT_SIZE) != 0) {
+ if (via_cmdbuf_wait(dev_priv, CMDBUF_ALIGNMENT_SIZE) != 0)
DRM_ERROR("via_cmdbuf_jump failed\n");
- }
via_dummy_bitblt(dev_priv);
via_dummy_bitblt(dev_priv);
@@ -657,12 +643,12 @@ static void via_cmdbuf_jump(drm_via_private_t * dev_priv)
}
-static void via_cmdbuf_rewind(drm_via_private_t * dev_priv)
+static void via_cmdbuf_rewind(drm_via_private_t *dev_priv)
{
via_cmdbuf_jump(dev_priv);
}
-static void via_cmdbuf_flush(drm_via_private_t * dev_priv, uint32_t cmd_type)
+static void via_cmdbuf_flush(drm_via_private_t *dev_priv, uint32_t cmd_type)
{
uint32_t pause_addr_lo, pause_addr_hi;
@@ -670,12 +656,12 @@ static void via_cmdbuf_flush(drm_via_private_t * dev_priv, uint32_t cmd_type)
via_hook_segment(dev_priv, pause_addr_hi, pause_addr_lo, 0);
}
-static void via_cmdbuf_pause(drm_via_private_t * dev_priv)
+static void via_cmdbuf_pause(drm_via_private_t *dev_priv)
{
via_cmdbuf_flush(dev_priv, HC_HAGPBpID_PAUSE);
}
-static void via_cmdbuf_reset(drm_via_private_t * dev_priv)
+static void via_cmdbuf_reset(drm_via_private_t *dev_priv)
{
via_cmdbuf_flush(dev_priv, HC_HAGPBpID_STOP);
via_wait_idle(dev_priv);
@@ -708,9 +694,8 @@ static int via_cmdbuf_size(struct drm_device *dev, void *data, struct drm_file *
case VIA_CMDBUF_SPACE:
while (((tmp_size = via_cmdbuf_space(dev_priv)) < d_siz->size)
&& --count) {
- if (!d_siz->wait) {
+ if (!d_siz->wait)
break;
- }
}
if (!count) {
DRM_ERROR("VIA_CMDBUF_SPACE timed out.\n");
@@ -720,9 +705,8 @@ static int via_cmdbuf_size(struct drm_device *dev, void *data, struct drm_file *
case VIA_CMDBUF_LAG:
while (((tmp_size = via_cmdbuf_lag(dev_priv)) > d_siz->size)
&& --count) {
- if (!d_siz->wait) {
+ if (!d_siz->wait)
break;
- }
}
if (!count) {
DRM_ERROR("VIA_CMDBUF_LAG timed out.\n");
diff --git a/drivers/gpu/drm/via/via_dmablit.c b/drivers/gpu/drm/via/via_dmablit.c
index 4c54f043068..9b5b4d9dd62 100644
--- a/drivers/gpu/drm/via/via_dmablit.c
+++ b/drivers/gpu/drm/via/via_dmablit.c
@@ -70,7 +70,7 @@ via_unmap_blit_from_device(struct pci_dev *pdev, drm_via_sg_info_t *vsg)
descriptor_this_page;
dma_addr_t next = vsg->chain_start;
- while(num_desc--) {
+ while (num_desc--) {
if (descriptor_this_page-- == 0) {
cur_descriptor_page--;
descriptor_this_page = vsg->descriptors_per_page - 1;
@@ -174,19 +174,19 @@ via_free_sg_info(struct pci_dev *pdev, drm_via_sg_info_t *vsg)
struct page *page;
int i;
- switch(vsg->state) {
+ switch (vsg->state) {
case dr_via_device_mapped:
via_unmap_blit_from_device(pdev, vsg);
case dr_via_desc_pages_alloc:
- for (i=0; i<vsg->num_desc_pages; ++i) {
+ for (i = 0; i < vsg->num_desc_pages; ++i) {
if (vsg->desc_pages[i] != NULL)
- free_page((unsigned long)vsg->desc_pages[i]);
+ free_page((unsigned long)vsg->desc_pages[i]);
}
kfree(vsg->desc_pages);
case dr_via_pages_locked:
- for (i=0; i<vsg->num_pages; ++i) {
- if ( NULL != (page = vsg->pages[i])) {
- if (! PageReserved(page) && (DMA_FROM_DEVICE == vsg->direction))
+ for (i = 0; i < vsg->num_pages; ++i) {
+ if (NULL != (page = vsg->pages[i])) {
+ if (!PageReserved(page) && (DMA_FROM_DEVICE == vsg->direction))
SetPageDirty(page);
page_cache_release(page);
}
@@ -232,7 +232,7 @@ via_lock_all_dma_pages(drm_via_sg_info_t *vsg, drm_via_dmablit_t *xfer)
{
int ret;
unsigned long first_pfn = VIA_PFN(xfer->mem_addr);
- vsg->num_pages = VIA_PFN(xfer->mem_addr + (xfer->num_lines * xfer->mem_stride -1)) -
+ vsg->num_pages = VIA_PFN(xfer->mem_addr + (xfer->num_lines * xfer->mem_stride - 1)) -
first_pfn + 1;
if (NULL == (vsg->pages = vmalloc(sizeof(struct page *) * vsg->num_pages)))
@@ -268,7 +268,7 @@ via_alloc_desc_pages(drm_via_sg_info_t *vsg)
{
int i;
- vsg->descriptors_per_page = PAGE_SIZE / sizeof( drm_via_descriptor_t);
+ vsg->descriptors_per_page = PAGE_SIZE / sizeof(drm_via_descriptor_t);
vsg->num_desc_pages = (vsg->num_desc + vsg->descriptors_per_page - 1) /
vsg->descriptors_per_page;
@@ -276,7 +276,7 @@ via_alloc_desc_pages(drm_via_sg_info_t *vsg)
return -ENOMEM;
vsg->state = dr_via_desc_pages_alloc;
- for (i=0; i<vsg->num_desc_pages; ++i) {
+ for (i = 0; i < vsg->num_desc_pages; ++i) {
if (NULL == (vsg->desc_pages[i] =
(drm_via_descriptor_t *) __get_free_page(GFP_KERNEL)))
return -ENOMEM;
@@ -318,21 +318,20 @@ via_dmablit_handler(struct drm_device *dev, int engine, int from_irq)
drm_via_blitq_t *blitq = dev_priv->blit_queues + engine;
int cur;
int done_transfer;
- unsigned long irqsave=0;
+ unsigned long irqsave = 0;
uint32_t status = 0;
DRM_DEBUG("DMA blit handler called. engine = %d, from_irq = %d, blitq = 0x%lx\n",
engine, from_irq, (unsigned long) blitq);
- if (from_irq) {
+ if (from_irq)
spin_lock(&blitq->blit_lock);
- } else {
+ else
spin_lock_irqsave(&blitq->blit_lock, irqsave);
- }
done_transfer = blitq->is_active &&
- (( status = VIA_READ(VIA_PCI_DMA_CSR0 + engine*0x04)) & VIA_DMA_CSR_TD);
- done_transfer = done_transfer || ( blitq->aborting && !(status & VIA_DMA_CSR_DE));
+ ((status = VIA_READ(VIA_PCI_DMA_CSR0 + engine*0x04)) & VIA_DMA_CSR_TD);
+ done_transfer = done_transfer || (blitq->aborting && !(status & VIA_DMA_CSR_DE));
cur = blitq->cur;
if (done_transfer) {
@@ -377,18 +376,16 @@ via_dmablit_handler(struct drm_device *dev, int engine, int from_irq)
if (!timer_pending(&blitq->poll_timer))
mod_timer(&blitq->poll_timer, jiffies + 1);
} else {
- if (timer_pending(&blitq->poll_timer)) {
+ if (timer_pending(&blitq->poll_timer))
del_timer(&blitq->poll_timer);
- }
via_dmablit_engine_off(dev, engine);
}
}
- if (from_irq) {
+ if (from_irq)
spin_unlock(&blitq->blit_lock);
- } else {
+ else
spin_unlock_irqrestore(&blitq->blit_lock, irqsave);
- }
}
@@ -414,10 +411,9 @@ via_dmablit_active(drm_via_blitq_t *blitq, int engine, uint32_t handle, wait_que
((blitq->cur_blit_handle - handle) <= (1 << 23));
if (queue && active) {
- slot = handle - blitq->done_blit_handle + blitq->cur -1;
- if (slot >= VIA_NUM_BLIT_SLOTS) {
+ slot = handle - blitq->done_blit_handle + blitq->cur - 1;
+ if (slot >= VIA_NUM_BLIT_SLOTS)
slot -= VIA_NUM_BLIT_SLOTS;
- }
*queue = blitq->blit_queue + slot;
}
@@ -506,12 +502,12 @@ via_dmablit_workqueue(struct work_struct *work)
int cur_released;
- DRM_DEBUG("Workqueue task called for blit engine %ld\n",(unsigned long)
+ DRM_DEBUG("Workqueue task called for blit engine %ld\n", (unsigned long)
(blitq - ((drm_via_private_t *)dev->dev_private)->blit_queues));
spin_lock_irqsave(&blitq->blit_lock, irqsave);
- while(blitq->serviced != blitq->cur) {
+ while (blitq->serviced != blitq->cur) {
cur_released = blitq->serviced++;
@@ -545,13 +541,13 @@ via_dmablit_workqueue(struct work_struct *work)
void
via_init_dmablit(struct drm_device *dev)
{
- int i,j;
+ int i, j;
drm_via_private_t *dev_priv = (drm_via_private_t *)dev->dev_private;
drm_via_blitq_t *blitq;
pci_set_master(dev->pdev);
- for (i=0; i< VIA_NUM_BLIT_ENGINES; ++i) {
+ for (i = 0; i < VIA_NUM_BLIT_ENGINES; ++i) {
blitq = dev_priv->blit_queues + i;
blitq->dev = dev;
blitq->cur_blit_handle = 0;
@@ -564,9 +560,8 @@ via_init_dmablit(struct drm_device *dev)
blitq->is_active = 0;
blitq->aborting = 0;
spin_lock_init(&blitq->blit_lock);
- for (j=0; j<VIA_NUM_BLIT_SLOTS; ++j) {
+ for (j = 0; j < VIA_NUM_BLIT_SLOTS; ++j)
DRM_INIT_WAITQUEUE(blitq->blit_queue + j);
- }
DRM_INIT_WAITQUEUE(&blitq->busy_queue);
INIT_WORK(&blitq->wq, via_dmablit_workqueue);
setup_timer(&blitq->poll_timer, via_dmablit_timer,
@@ -685,18 +680,17 @@ via_build_sg_info(struct drm_device *dev, drm_via_sg_info_t *vsg, drm_via_dmabli
static int
via_dmablit_grab_slot(drm_via_blitq_t *blitq, int engine)
{
- int ret=0;
+ int ret = 0;
unsigned long irqsave;
DRM_DEBUG("Num free is %d\n", blitq->num_free);
spin_lock_irqsave(&blitq->blit_lock, irqsave);
- while(blitq->num_free == 0) {
+ while (blitq->num_free == 0) {
spin_unlock_irqrestore(&blitq->blit_lock, irqsave);
DRM_WAIT_ON(ret, blitq->busy_queue, DRM_HZ, blitq->num_free > 0);
- if (ret) {
+ if (ret)
return (-EINTR == ret) ? -EAGAIN : ret;
- }
spin_lock_irqsave(&blitq->blit_lock, irqsave);
}
@@ -719,7 +713,7 @@ via_dmablit_release_slot(drm_via_blitq_t *blitq)
spin_lock_irqsave(&blitq->blit_lock, irqsave);
blitq->num_free++;
spin_unlock_irqrestore(&blitq->blit_lock, irqsave);
- DRM_WAKEUP( &blitq->busy_queue );
+ DRM_WAKEUP(&blitq->busy_queue);
}
/*
@@ -744,9 +738,8 @@ via_dmablit(struct drm_device *dev, drm_via_dmablit_t *xfer)
engine = (xfer->to_fb) ? 0 : 1;
blitq = dev_priv->blit_queues + engine;
- if (0 != (ret = via_dmablit_grab_slot(blitq, engine))) {
+ if (0 != (ret = via_dmablit_grab_slot(blitq, engine)))
return ret;
- }
if (NULL == (vsg = kmalloc(sizeof(*vsg), GFP_KERNEL))) {
via_dmablit_release_slot(blitq);
return -ENOMEM;
@@ -780,7 +773,7 @@ via_dmablit(struct drm_device *dev, drm_via_dmablit_t *xfer)
*/
int
-via_dma_blit_sync( struct drm_device *dev, void *data, struct drm_file *file_priv )
+via_dma_blit_sync(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
drm_via_blitsync_t *sync = data;
int err;
@@ -804,7 +797,7 @@ via_dma_blit_sync( struct drm_device *dev, void *data, struct drm_file *file_pri
*/
int
-via_dma_blit( struct drm_device *dev, void *data, struct drm_file *file_priv )
+via_dma_blit(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
drm_via_dmablit_t *xfer = data;
int err;
diff --git a/drivers/gpu/drm/via/via_dmablit.h b/drivers/gpu/drm/via/via_dmablit.h
index 7408a547a03..9b662a327ce 100644
--- a/drivers/gpu/drm/via/via_dmablit.h
+++ b/drivers/gpu/drm/via/via_dmablit.h
@@ -45,12 +45,12 @@ typedef struct _drm_via_sg_info {
int num_desc;
enum dma_data_direction direction;
unsigned char *bounce_buffer;
- dma_addr_t chain_start;
+ dma_addr_t chain_start;
uint32_t free_on_sequence;
- unsigned int descriptors_per_page;
+ unsigned int descriptors_per_page;
int aborted;
enum {
- dr_via_device_mapped,
+ dr_via_device_mapped,
dr_via_desc_pages_alloc,
dr_via_pages_locked,
dr_via_pages_alloc,
@@ -68,7 +68,7 @@ typedef struct _drm_via_blitq {
unsigned num_free;
unsigned num_outstanding;
unsigned long end;
- int aborting;
+ int aborting;
int is_active;
drm_via_sg_info_t *blits[VIA_NUM_BLIT_SLOTS];
spinlock_t blit_lock;
diff --git a/drivers/gpu/drm/via/via_drv.h b/drivers/gpu/drm/via/via_drv.h
index cafcb844a22..9cf87d91232 100644
--- a/drivers/gpu/drm/via/via_drv.h
+++ b/drivers/gpu/drm/via/via_drv.h
@@ -107,9 +107,9 @@ enum via_family {
#define VIA_BASE ((dev_priv->mmio))
#define VIA_READ(reg) DRM_READ32(VIA_BASE, reg)
-#define VIA_WRITE(reg,val) DRM_WRITE32(VIA_BASE, reg, val)
+#define VIA_WRITE(reg, val) DRM_WRITE32(VIA_BASE, reg, val)
#define VIA_READ8(reg) DRM_READ8(VIA_BASE, reg)
-#define VIA_WRITE8(reg,val) DRM_WRITE8(VIA_BASE, reg, val)
+#define VIA_WRITE8(reg, val) DRM_WRITE8(VIA_BASE, reg, val)
extern struct drm_ioctl_desc via_ioctls[];
extern int via_max_ioctl;
@@ -121,28 +121,28 @@ extern int via_agp_init(struct drm_device *dev, void *data, struct drm_file *fil
extern int via_map_init(struct drm_device *dev, void *data, struct drm_file *file_priv);
extern int via_decoder_futex(struct drm_device *dev, void *data, struct drm_file *file_priv);
extern int via_wait_irq(struct drm_device *dev, void *data, struct drm_file *file_priv);
-extern int via_dma_blit_sync( struct drm_device *dev, void *data, struct drm_file *file_priv );
-extern int via_dma_blit( struct drm_device *dev, void *data, struct drm_file *file_priv );
+extern int via_dma_blit_sync(struct drm_device *dev, void *data, struct drm_file *file_priv);
+extern int via_dma_blit(struct drm_device *dev, void *data, struct drm_file *file_priv);
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(struct drm_device * dev, int context);
-extern int via_final_context(struct drm_device * 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(struct drm_device * dev);
+extern int via_do_cleanup_map(struct drm_device *dev);
extern u32 via_get_vblank_counter(struct drm_device *dev, int crtc);
extern int via_enable_vblank(struct drm_device *dev, int crtc);
extern void via_disable_vblank(struct drm_device *dev, int crtc);
extern irqreturn_t via_driver_irq_handler(DRM_IRQ_ARGS);
-extern void via_driver_irq_preinstall(struct drm_device * dev);
+extern void via_driver_irq_preinstall(struct drm_device *dev);
extern int via_driver_irq_postinstall(struct drm_device *dev);
-extern void via_driver_irq_uninstall(struct drm_device * dev);
+extern void via_driver_irq_uninstall(struct drm_device *dev);
-extern int via_dma_cleanup(struct drm_device * dev);
+extern int via_dma_cleanup(struct drm_device *dev);
extern void via_init_command_verifier(void);
-extern int via_driver_dma_quiescent(struct drm_device * 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);
diff --git a/drivers/gpu/drm/via/via_irq.c b/drivers/gpu/drm/via/via_irq.c
index 34079f251cd..d391f48ef87 100644
--- a/drivers/gpu/drm/via/via_irq.c
+++ b/drivers/gpu/drm/via/via_irq.c
@@ -141,11 +141,10 @@ irqreturn_t via_driver_irq_handler(DRM_IRQ_ARGS)
atomic_inc(&cur_irq->irq_received);
DRM_WAKEUP(&cur_irq->irq_queue);
handled = 1;
- if (dev_priv->irq_map[drm_via_irq_dma0_td] == i) {
+ if (dev_priv->irq_map[drm_via_irq_dma0_td] == i)
via_dmablit_handler(dev, 0, 1);
- } else if (dev_priv->irq_map[drm_via_irq_dma1_td] == i) {
+ else if (dev_priv->irq_map[drm_via_irq_dma1_td] == i)
via_dmablit_handler(dev, 1, 1);
- }
}
cur_irq++;
}
@@ -160,7 +159,7 @@ irqreturn_t via_driver_irq_handler(DRM_IRQ_ARGS)
return IRQ_NONE;
}
-static __inline__ void viadrv_acknowledge_irqs(drm_via_private_t * dev_priv)
+static __inline__ void viadrv_acknowledge_irqs(drm_via_private_t *dev_priv)
{
u32 status;
@@ -207,7 +206,7 @@ void via_disable_vblank(struct drm_device *dev, int crtc)
}
static int
-via_driver_irq_wait(struct drm_device * 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;
@@ -260,7 +259,7 @@ via_driver_irq_wait(struct drm_device * dev, unsigned int irq, int force_sequenc
* drm_dma.h hooks
*/
-void via_driver_irq_preinstall(struct drm_device * 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;
@@ -329,7 +328,7 @@ int via_driver_irq_postinstall(struct drm_device *dev)
return 0;
}
-void via_driver_irq_uninstall(struct drm_device * 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/gpu/drm/via/via_map.c b/drivers/gpu/drm/via/via_map.c
index 6e6f9159163..6cca9a709f7 100644
--- a/drivers/gpu/drm/via/via_map.c
+++ b/drivers/gpu/drm/via/via_map.c
@@ -25,7 +25,7 @@
#include "via_drm.h"
#include "via_drv.h"
-static int via_do_init_map(struct drm_device * 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;
@@ -68,7 +68,7 @@ static int via_do_init_map(struct drm_device * dev, drm_via_init_t * init)
return 0;
}
-int via_do_cleanup_map(struct drm_device * dev)
+int via_do_cleanup_map(struct drm_device *dev)
{
via_dma_cleanup(dev);
diff --git a/drivers/gpu/drm/via/via_mm.c b/drivers/gpu/drm/via/via_mm.c
index f694cb5eded..6cc2dadae3e 100644
--- a/drivers/gpu/drm/via/via_mm.c
+++ b/drivers/gpu/drm/via/via_mm.c
@@ -31,7 +31,7 @@
#include "drm_sman.h"
#define VIA_MM_ALIGN_SHIFT 4
-#define VIA_MM_ALIGN_MASK ( (1 << VIA_MM_ALIGN_SHIFT) - 1)
+#define VIA_MM_ALIGN_MASK ((1 << VIA_MM_ALIGN_SHIFT) - 1)
int via_agp_init(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
@@ -172,7 +172,7 @@ int via_mem_free(struct drm_device *dev, void *data, struct drm_file *file_priv)
}
-void via_reclaim_buffers_locked(struct drm_device * dev,
+void via_reclaim_buffers_locked(struct drm_device *dev,
struct drm_file *file_priv)
{
drm_via_private_t *dev_priv = dev->dev_private;
@@ -183,9 +183,8 @@ void via_reclaim_buffers_locked(struct drm_device * dev,
return;
}
- if (dev->driver->dma_quiescent) {
+ if (dev->driver->dma_quiescent)
dev->driver->dma_quiescent(dev);
- }
drm_sman_owner_cleanup(&dev_priv->sman, (unsigned long)file_priv);
mutex_unlock(&dev->struct_mutex);
diff --git a/drivers/gpu/drm/via/via_verifier.c b/drivers/gpu/drm/via/via_verifier.c
index 46a57919874..48957b856d4 100644
--- a/drivers/gpu/drm/via/via_verifier.c
+++ b/drivers/gpu/drm/via/via_verifier.c
@@ -235,7 +235,7 @@ static hazard_t table2[256];
static hazard_t table3[256];
static __inline__ int
-eat_words(const uint32_t ** buf, const uint32_t * buf_end, unsigned num_words)
+eat_words(const uint32_t **buf, const uint32_t *buf_end, unsigned num_words)
{
if ((buf_end - *buf) >= num_words) {
*buf += num_words;
@@ -252,7 +252,7 @@ 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,
- struct drm_device * dev)
+ struct drm_device *dev)
{
struct drm_map_list *r_list;
drm_local_map_t *map = seq->map_cache;
@@ -344,7 +344,7 @@ static __inline__ int finish_current_sequence(drm_via_state_t * cur_seq)
}
static __inline__ int
-investigate_hazard(uint32_t cmd, hazard_t hz, drm_via_state_t * cur_seq)
+investigate_hazard(uint32_t cmd, hazard_t hz, drm_via_state_t *cur_seq)
{
register uint32_t tmp, *tmp_addr;
@@ -518,7 +518,7 @@ investigate_hazard(uint32_t cmd, hazard_t hz, drm_via_state_t * cur_seq)
static __inline__ int
via_check_prim_list(uint32_t const **buffer, const uint32_t * buf_end,
- drm_via_state_t * cur_seq)
+ drm_via_state_t *cur_seq)
{
drm_via_private_t *dev_priv =
(drm_via_private_t *) cur_seq->dev->dev_private;
@@ -621,8 +621,8 @@ via_check_prim_list(uint32_t const **buffer, const uint32_t * buf_end,
}
static __inline__ verifier_state_t
-via_check_header2(uint32_t const **buffer, const uint32_t * buf_end,
- drm_via_state_t * hc_state)
+via_check_header2(uint32_t const **buffer, const uint32_t *buf_end,
+ drm_via_state_t *hc_state)
{
uint32_t cmd;
int hz_mode;
@@ -706,16 +706,15 @@ via_check_header2(uint32_t const **buffer, const uint32_t * buf_end,
return state_error;
}
}
- if (hc_state->unfinished && finish_current_sequence(hc_state)) {
+ if (hc_state->unfinished && finish_current_sequence(hc_state))
return state_error;
- }
*buffer = buf;
return state_command;
}
static __inline__ verifier_state_t
-via_parse_header2(drm_via_private_t * dev_priv, uint32_t const **buffer,
- const uint32_t * buf_end, int *fire_count)
+via_parse_header2(drm_via_private_t *dev_priv, uint32_t const **buffer,
+ const uint32_t *buf_end, int *fire_count)
{
uint32_t cmd;
const uint32_t *buf = *buffer;
@@ -833,8 +832,8 @@ via_check_header1(uint32_t const **buffer, const uint32_t * buf_end)
}
static __inline__ verifier_state_t
-via_parse_header1(drm_via_private_t * dev_priv, uint32_t const **buffer,
- const uint32_t * buf_end)
+via_parse_header1(drm_via_private_t *dev_priv, uint32_t const **buffer,
+ const uint32_t *buf_end)
{
register uint32_t cmd;
const uint32_t *buf = *buffer;
@@ -851,7 +850,7 @@ via_parse_header1(drm_via_private_t * dev_priv, uint32_t const **buffer,
}
static __inline__ verifier_state_t
-via_check_vheader5(uint32_t const **buffer, const uint32_t * buf_end)
+via_check_vheader5(uint32_t const **buffer, const uint32_t *buf_end)
{
uint32_t data;
const uint32_t *buf = *buffer;
@@ -884,8 +883,8 @@ via_check_vheader5(uint32_t const **buffer, const uint32_t * buf_end)
}
static __inline__ verifier_state_t
-via_parse_vheader5(drm_via_private_t * dev_priv, uint32_t const **buffer,
- const uint32_t * buf_end)
+via_parse_vheader5(drm_via_private_t *dev_priv, uint32_t const **buffer,
+ const uint32_t *buf_end)
{
uint32_t addr, count, i;
const uint32_t *buf = *buffer;
@@ -893,9 +892,8 @@ via_parse_vheader5(drm_via_private_t * dev_priv, uint32_t const **buffer,
addr = *buf++ & ~VIA_VIDEOMASK;
i = count = *buf;
buf += 3;
- while (i--) {
+ while (i--)
VIA_WRITE(addr, *buf++);
- }
if (count & 3)
buf += 4 - (count & 3);
*buffer = buf;
@@ -940,8 +938,8 @@ via_check_vheader6(uint32_t const **buffer, const uint32_t * buf_end)
}
static __inline__ verifier_state_t
-via_parse_vheader6(drm_via_private_t * dev_priv, uint32_t const **buffer,
- const uint32_t * buf_end)
+via_parse_vheader6(drm_via_private_t *dev_priv, uint32_t const **buffer,
+ const uint32_t *buf_end)
{
uint32_t addr, count, i;
@@ -1037,7 +1035,7 @@ via_verify_command_stream(const uint32_t * buf, unsigned int size,
}
int
-via_parse_command_stream(struct drm_device * dev, const uint32_t * buf,
+via_parse_command_stream(struct drm_device *dev, const uint32_t *buf,
unsigned int size)
{
@@ -1085,9 +1083,8 @@ via_parse_command_stream(struct drm_device * dev, const uint32_t * buf,
return -EINVAL;
}
}
- if (state == state_error) {
+ if (state == state_error)
return -EINVAL;
- }
return 0;
}
@@ -1096,13 +1093,11 @@ setup_hazard_table(hz_init_t init_table[], hazard_t table[], int size)
{
int i;
- for (i = 0; i < 256; ++i) {
+ for (i = 0; i < 256; ++i)
table[i] = forbidden_command;
- }
- for (i = 0; i < size; ++i) {
+ for (i = 0; i < size; ++i)
table[init_table[i].code] = init_table[i].hz;
- }
}
void via_init_command_verifier(void)
diff --git a/drivers/gpu/drm/via/via_verifier.h b/drivers/gpu/drm/via/via_verifier.h
index d6f8214b69f..26b6d361ab9 100644
--- a/drivers/gpu/drm/via/via_verifier.h
+++ b/drivers/gpu/drm/via/via_verifier.h
@@ -54,8 +54,8 @@ typedef struct {
const uint32_t *buf_start;
} drm_via_state_t;
-extern int via_verify_command_stream(const uint32_t * buf, unsigned int size,
- struct drm_device * dev, int agp);
+extern int via_verify_command_stream(const uint32_t *buf, unsigned int size,
+ struct drm_device *dev, int agp);
extern int via_parse_command_stream(struct drm_device *dev, const uint32_t *buf,
unsigned int size);
diff --git a/drivers/gpu/drm/via/via_video.c b/drivers/gpu/drm/via/via_video.c
index 6efac8117c9..675d311f038 100644
--- a/drivers/gpu/drm/via/via_video.c
+++ b/drivers/gpu/drm/via/via_video.c
@@ -29,7 +29,7 @@
#include "via_drm.h"
#include "via_drv.h"
-void via_init_futex(drm_via_private_t * dev_priv)
+void via_init_futex(drm_via_private_t *dev_priv)
{
unsigned int i;
@@ -41,11 +41,11 @@ void via_init_futex(drm_via_private_t * dev_priv)
}
}
-void via_cleanup_futex(drm_via_private_t * dev_priv)
+void via_cleanup_futex(drm_via_private_t *dev_priv)
{
}
-void via_release_futex(drm_via_private_t * dev_priv, int context)
+void via_release_futex(drm_via_private_t *dev_priv, int context)
{
unsigned int i;
volatile int *lock;
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
index b793c8c9acb..9dd395b9021 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
@@ -764,7 +764,7 @@ static struct drm_driver driver = {
static int vmw_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
{
- return drm_get_dev(pdev, ent, &driver);
+ return drm_get_pci_dev(pdev, ent, &driver);
}
static int __init vmwgfx_init(void)
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
index eaad5209533..429f917b60b 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
@@ -164,7 +164,7 @@ struct vmw_vga_topology_state {
struct vmw_private {
struct ttm_bo_device bdev;
struct ttm_bo_global_ref bo_global_ref;
- struct ttm_global_reference mem_global_ref;
+ struct drm_global_reference mem_global_ref;
struct vmw_fifo_state fifo;
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c b/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c
index b0866f04ec7..870967a97c1 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c
@@ -528,7 +528,7 @@ int vmw_fb_init(struct vmw_private *vmw_priv)
* Dirty & Deferred IO
*/
par->dirty.x1 = par->dirty.x2 = 0;
- par->dirty.y1 = par->dirty.y1 = 0;
+ par->dirty.y1 = par->dirty.y2 = 0;
par->dirty.active = true;
spin_lock_init(&par->dirty.lock);
info->fbdefio = &vmw_defio;
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c b/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c
index 8612378b131..5f2d5df01e5 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c
@@ -1017,7 +1017,7 @@ int vmw_gmr_id_alloc(struct vmw_private *dev_priv, uint32_t *p_id)
}
/*
- * Stream managment
+ * Stream management
*/
static void vmw_stream_destroy(struct vmw_resource *res)
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ttm_glue.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ttm_glue.c
index e3df4adfb4d..83123287c60 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_ttm_glue.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ttm_glue.c
@@ -44,29 +44,29 @@ int vmw_mmap(struct file *filp, struct vm_area_struct *vma)
return ttm_bo_mmap(filp, vma, &dev_priv->bdev);
}
-static int vmw_ttm_mem_global_init(struct ttm_global_reference *ref)
+static int vmw_ttm_mem_global_init(struct drm_global_reference *ref)
{
DRM_INFO("global init.\n");
return ttm_mem_global_init(ref->object);
}
-static void vmw_ttm_mem_global_release(struct ttm_global_reference *ref)
+static void vmw_ttm_mem_global_release(struct drm_global_reference *ref)
{
ttm_mem_global_release(ref->object);
}
int vmw_ttm_global_init(struct vmw_private *dev_priv)
{
- struct ttm_global_reference *global_ref;
+ struct drm_global_reference *global_ref;
int ret;
global_ref = &dev_priv->mem_global_ref;
- global_ref->global_type = TTM_GLOBAL_TTM_MEM;
+ global_ref->global_type = DRM_GLOBAL_TTM_MEM;
global_ref->size = sizeof(struct ttm_mem_global);
global_ref->init = &vmw_ttm_mem_global_init;
global_ref->release = &vmw_ttm_mem_global_release;
- ret = ttm_global_item_ref(global_ref);
+ ret = drm_global_item_ref(global_ref);
if (unlikely(ret != 0)) {
DRM_ERROR("Failed setting up TTM memory accounting.\n");
return ret;
@@ -75,11 +75,11 @@ int vmw_ttm_global_init(struct vmw_private *dev_priv)
dev_priv->bo_global_ref.mem_glob =
dev_priv->mem_global_ref.object;
global_ref = &dev_priv->bo_global_ref.ref;
- global_ref->global_type = TTM_GLOBAL_TTM_BO;
+ global_ref->global_type = DRM_GLOBAL_TTM_BO;
global_ref->size = sizeof(struct ttm_bo_global);
global_ref->init = &ttm_bo_global_init;
global_ref->release = &ttm_bo_global_release;
- ret = ttm_global_item_ref(global_ref);
+ ret = drm_global_item_ref(global_ref);
if (unlikely(ret != 0)) {
DRM_ERROR("Failed setting up TTM buffer objects.\n");
@@ -88,12 +88,12 @@ int vmw_ttm_global_init(struct vmw_private *dev_priv)
return 0;
out_no_bo:
- ttm_global_item_unref(&dev_priv->mem_global_ref);
+ drm_global_item_unref(&dev_priv->mem_global_ref);
return ret;
}
void vmw_ttm_global_release(struct vmw_private *dev_priv)
{
- ttm_global_item_unref(&dev_priv->bo_global_ref.ref);
- ttm_global_item_unref(&dev_priv->mem_global_ref);
+ drm_global_item_unref(&dev_priv->bo_global_ref.ref);
+ drm_global_item_unref(&dev_priv->mem_global_ref);
}
diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
index 43409936905..6369ba7f96f 100644
--- a/drivers/hid/Kconfig
+++ b/drivers/hid/Kconfig
@@ -68,6 +68,14 @@ config HID_A4TECH
---help---
Support for A4 tech X5 and WOP-35 / Trust 450L mice.
+config HID_ACRUX_FF
+ tristate "ACRUX force feedback support"
+ depends on USB_HID
+ select INPUT_FF_MEMLESS
+ ---help---
+ Say Y here if you want to enable force feedback support for ACRUX
+ game controllers.
+
config HID_APPLE
tristate "Apple" if EMBEDDED
depends on (USB_HID || BT_HIDP)
@@ -148,6 +156,12 @@ config HID_EGALAX
---help---
Support for the eGalax dual-touch panel.
+config HID_ELECOM
+ tristate "ELECOM"
+ depends on BT_HIDP
+ ---help---
+ Support for the ELECOM BM084 (bluetooth mouse).
+
config HID_EZKEY
tristate "Ezkey" if EMBEDDED
depends on USB_HID
@@ -417,10 +431,11 @@ config SMARTJOYPLUS_FF
enable force feedback support for it.
config HID_TOPSEED
- tristate "TopSeed Cyberlink remote control support"
+ tristate "TopSeed Cyberlink, BTC Emprex, Conceptronic remote control support"
depends on USB_HID
---help---
- Say Y if you have a TopSeed Cyberlink or BTC Emprex remote control.
+ Say Y if you have a TopSeed Cyberlink or BTC Emprex or Conceptronic
+ CLLRCMCE remote control.
config HID_THRUSTMASTER
tristate "ThrustMaster devices support"
diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile
index 987fa062736..46f037f3df8 100644
--- a/drivers/hid/Makefile
+++ b/drivers/hid/Makefile
@@ -24,6 +24,7 @@ endif
obj-$(CONFIG_HID_3M_PCT) += hid-3m-pct.o
obj-$(CONFIG_HID_A4TECH) += hid-a4tech.o
+obj-$(CONFIG_HID_ACRUX_FF) += hid-axff.o
obj-$(CONFIG_HID_APPLE) += hid-apple.o
obj-$(CONFIG_HID_BELKIN) += hid-belkin.o
obj-$(CONFIG_HID_CANDO) += hid-cando.o
@@ -32,6 +33,7 @@ obj-$(CONFIG_HID_CHICONY) += hid-chicony.o
obj-$(CONFIG_HID_CYPRESS) += hid-cypress.o
obj-$(CONFIG_HID_DRAGONRISE) += hid-drff.o
obj-$(CONFIG_HID_EGALAX) += hid-egalax.o
+obj-$(CONFIG_HID_ELECOM) += hid-elecom.o
obj-$(CONFIG_HID_EZKEY) += hid-ezkey.o
obj-$(CONFIG_HID_GYRATION) += hid-gyration.o
obj-$(CONFIG_HID_KENSINGTON) += hid-kensington.o
diff --git a/drivers/hid/hid-axff.c b/drivers/hid/hid-axff.c
new file mode 100644
index 00000000000..f42ee140738
--- /dev/null
+++ b/drivers/hid/hid-axff.c
@@ -0,0 +1,172 @@
+/*
+ * Force feedback support for ACRUX game controllers
+ *
+ * From what I have gathered, these devices are mass produced in China
+ * by several vendors. They often share the same design as the original
+ * Xbox 360 controller.
+ *
+ * 1a34:0802 "ACRUX USB GAMEPAD 8116"
+ * - tested with a EXEQ EQ-PCU-02090 game controller.
+ *
+ * Copyright (c) 2010 Sergei Kolzun <x0r@dv-life.ru>
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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/input.h>
+#include <linux/slab.h>
+#include <linux/usb.h>
+#include <linux/hid.h>
+
+#include "hid-ids.h"
+#include "usbhid/usbhid.h"
+
+struct axff_device {
+ struct hid_report *report;
+};
+
+static int axff_play(struct input_dev *dev, void *data, struct ff_effect *effect)
+{
+ struct hid_device *hid = input_get_drvdata(dev);
+ struct axff_device *axff = data;
+ int left, right;
+
+ left = effect->u.rumble.strong_magnitude;
+ right = effect->u.rumble.weak_magnitude;
+
+ dbg_hid("called with 0x%04x 0x%04x", left, right);
+
+ left = left * 0xff / 0xffff;
+ right = right * 0xff / 0xffff;
+
+ axff->report->field[0]->value[0] = left;
+ axff->report->field[1]->value[0] = right;
+ axff->report->field[2]->value[0] = left;
+ axff->report->field[3]->value[0] = right;
+ dbg_hid("running with 0x%02x 0x%02x", left, right);
+ usbhid_submit_report(hid, axff->report, USB_DIR_OUT);
+
+ return 0;
+}
+
+static int axff_init(struct hid_device *hid)
+{
+ struct axff_device *axff;
+ struct hid_report *report;
+ struct hid_input *hidinput = list_first_entry(&hid->inputs, struct hid_input, list);
+ struct list_head *report_list =&hid->report_enum[HID_OUTPUT_REPORT].report_list;
+ struct input_dev *dev = hidinput->input;
+ int error;
+
+ if (list_empty(report_list)) {
+ dev_err(&hid->dev, "no output reports found\n");
+ return -ENODEV;
+ }
+
+ report = list_first_entry(report_list, struct hid_report, list);
+
+ if (report->maxfield < 4) {
+ dev_err(&hid->dev, "no fields in the report: %d\n", report->maxfield);
+ return -ENODEV;
+ }
+
+ axff = kzalloc(sizeof(struct axff_device), GFP_KERNEL);
+ if (!axff)
+ return -ENOMEM;
+
+ set_bit(FF_RUMBLE, dev->ffbit);
+
+ error = input_ff_create_memless(dev, axff, axff_play);
+ if (error)
+ goto err_free_mem;
+
+ axff->report = report;
+ axff->report->field[0]->value[0] = 0x00;
+ axff->report->field[1]->value[0] = 0x00;
+ axff->report->field[2]->value[0] = 0x00;
+ axff->report->field[3]->value[0] = 0x00;
+ usbhid_submit_report(hid, axff->report, USB_DIR_OUT);
+
+ dev_info(&hid->dev, "Force Feedback for ACRUX game controllers by Sergei Kolzun<x0r@dv-life.ru>\n");
+
+ return 0;
+
+err_free_mem:
+ kfree(axff);
+ return error;
+}
+
+static int ax_probe(struct hid_device *hdev, const struct hid_device_id *id)
+{
+ int error;
+
+ dev_dbg(&hdev->dev, "ACRUX HID hardware probe...");
+
+ error = hid_parse(hdev);
+ if (error) {
+ dev_err(&hdev->dev, "parse failed\n");
+ return error;
+ }
+
+ error = hid_hw_start(hdev, HID_CONNECT_DEFAULT & ~HID_CONNECT_FF);
+ if (error) {
+ dev_err(&hdev->dev, "hw start failed\n");
+ return error;
+ }
+
+ error = axff_init(hdev);
+ if (error) {
+ /*
+ * Do not fail device initialization completely as device
+ * may still be partially operable, just warn.
+ */
+ dev_warn(&hdev->dev,
+ "Failed to enable force feedback support, error: %d\n",
+ error);
+ }
+
+ return 0;
+}
+
+static const struct hid_device_id ax_devices[] = {
+ { HID_USB_DEVICE(USB_VENDOR_ID_ACRUX, 0x0802), },
+ { }
+};
+MODULE_DEVICE_TABLE(hid, ax_devices);
+
+static struct hid_driver ax_driver = {
+ .name = "acrux",
+ .id_table = ax_devices,
+ .probe = ax_probe,
+};
+
+static int __init ax_init(void)
+{
+ return hid_register_driver(&ax_driver);
+}
+
+static void __exit ax_exit(void)
+{
+ hid_unregister_driver(&ax_driver);
+}
+
+module_init(ax_init);
+module_exit(ax_exit);
+
+MODULE_AUTHOR("Sergei Kolzun");
+MODULE_DESCRIPTION("Force feedback support for ACRUX game controllers");
+MODULE_LICENSE("GPL");
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
index 866e54ec5fb..e635199a0cd 100644
--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -1157,6 +1157,8 @@ int hid_connect(struct hid_device *hdev, unsigned int connect_mask)
if (hdev->quirks & HID_QUIRK_HIDDEV_FORCE)
connect_mask |= (HID_CONNECT_HIDDEV_FORCE | HID_CONNECT_HIDDEV);
+ if (hdev->quirks & HID_QUIRK_HIDINPUT_FORCE)
+ connect_mask |= HID_CONNECT_HIDINPUT_FORCE;
if (hdev->bus != BUS_USB)
connect_mask &= ~HID_CONNECT_HIDDEV;
if (hid_hiddev(hdev))
@@ -1239,6 +1241,9 @@ static const struct hid_device_id hid_blacklist[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_3M, USB_DEVICE_ID_3M2256) },
{ HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_WCP32PU) },
{ HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_X5_005D) },
+#if defined(CONFIG_HID_ACRUX_FF) || defined(CONFIG_HID_ACRUX_FF_MODULE)
+ { HID_USB_DEVICE(USB_VENDOR_ID_ACRUX, 0x0802) },
+#endif
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ATV_IRCONTROL) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL4) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MIGHTYMOUSE) },
@@ -1294,6 +1299,7 @@ static const struct hid_device_id hid_blacklist[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_MOUSE) },
{ HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, 0x0006) },
{ HID_USB_DEVICE(USB_VENDOR_ID_DWAV, USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH) },
+ { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_BM084) },
{ HID_USB_DEVICE(USB_VENDOR_ID_EZKEY, USB_DEVICE_ID_BTC_8193) },
{ HID_USB_DEVICE(USB_VENDOR_ID_GAMERON, USB_DEVICE_ID_GAMERON_DUAL_PSX_ADAPTOR) },
{ HID_USB_DEVICE(USB_VENDOR_ID_GAMERON, USB_DEVICE_ID_GAMERON_DUAL_PCS_ADAPTOR) },
@@ -1375,10 +1381,10 @@ static const struct hid_device_id hid_blacklist[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb653) },
{ HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb654) },
{ HID_USB_DEVICE(USB_VENDOR_ID_TOPSEED, USB_DEVICE_ID_TOPSEED_CYBERLINK) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_TOPSEED2, USB_DEVICE_ID_TOPSEED2_RF_COMBO) },
{ HID_USB_DEVICE(USB_VENDOR_ID_TWINHAN, USB_DEVICE_ID_TWINHAN_IR_REMOTE) },
{ HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_SMARTJOY_PLUS) },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_GRAPHIRE_BLUETOOTH) },
- { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS4_BLUETOOTH) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ZEROPLUS, 0x0005) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ZEROPLUS, 0x0030) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ZYDACRON, USB_DEVICE_ID_ZYDACRON_REMOTE_CONTROL) },
@@ -1586,6 +1592,7 @@ static const struct hid_device_id hid_ignore_list[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_DELORME, USB_DEVICE_ID_DELORME_EM_LT20) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ESSENTIAL_REALITY, USB_DEVICE_ID_ESSENTIAL_REALITY_P5) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ETT, USB_DEVICE_ID_TC5UH) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_ETT, USB_DEVICE_ID_TC4UM) },
{ HID_USB_DEVICE(USB_VENDOR_ID_GENERAL_TOUCH, 0x0001) },
{ HID_USB_DEVICE(USB_VENDOR_ID_GENERAL_TOUCH, 0x0002) },
{ HID_USB_DEVICE(USB_VENDOR_ID_GENERAL_TOUCH, 0x0003) },
diff --git a/drivers/hid/hid-elecom.c b/drivers/hid/hid-elecom.c
new file mode 100644
index 00000000000..7a40878f46b
--- /dev/null
+++ b/drivers/hid/hid-elecom.c
@@ -0,0 +1,57 @@
+/*
+ * HID driver for Elecom BM084 (bluetooth mouse).
+ * Removes a non-existing horizontal wheel from
+ * the HID descriptor.
+ * (This module is based on "hid-ortek".)
+ *
+ * Copyright (c) 2010 Richard Nauber <Richard.Nauber@gmail.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/device.h>
+#include <linux/hid.h>
+#include <linux/module.h>
+
+#include "hid-ids.h"
+
+static void elecom_report_fixup(struct hid_device *hdev, __u8 *rdesc,
+ unsigned int rsize)
+{
+ if (rsize >= 48 && rdesc[46] == 0x05 && rdesc[47] == 0x0c) {
+ dev_info(&hdev->dev, "Fixing up Elecom BM084 "
+ "report descriptor.\n");
+ rdesc[47] = 0x00;
+ }
+}
+
+static const struct hid_device_id elecom_devices[] = {
+ { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_BM084)},
+ { }
+};
+MODULE_DEVICE_TABLE(hid, elecom_devices);
+
+static struct hid_driver elecom_driver = {
+ .name = "elecom",
+ .id_table = elecom_devices,
+ .report_fixup = elecom_report_fixup
+};
+
+static int __init elecom_init(void)
+{
+ return hid_register_driver(&elecom_driver);
+}
+
+static void __exit elecom_exit(void)
+{
+ hid_unregister_driver(&elecom_driver);
+}
+
+module_init(elecom_init);
+module_exit(elecom_exit);
+MODULE_LICENSE("GPL");
diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
index 31601eef25d..d3fc13ae094 100644
--- a/drivers/hid/hid-ids.h
+++ b/drivers/hid/hid-ids.h
@@ -34,6 +34,8 @@
#define USB_DEVICE_ID_ACECAD_FLAIR 0x0004
#define USB_DEVICE_ID_ACECAD_302 0x0008
+#define USB_VENDOR_ID_ACRUX 0x1a34
+
#define USB_VENDOR_ID_ADS_TECH 0x06e1
#define USB_DEVICE_ID_ADS_TECH_RADIO_SI470X 0xa155
@@ -81,12 +83,12 @@
#define USB_DEVICE_ID_APPLE_WELLSPRING_ANSI 0x0223
#define USB_DEVICE_ID_APPLE_WELLSPRING_ISO 0x0224
#define USB_DEVICE_ID_APPLE_WELLSPRING_JIS 0x0225
-#define USB_DEVICE_ID_APPLE_GEYSER4_HF_ANSI 0x0229
-#define USB_DEVICE_ID_APPLE_GEYSER4_HF_ISO 0x022a
-#define USB_DEVICE_ID_APPLE_GEYSER4_HF_JIS 0x022b
-#define USB_DEVICE_ID_APPLE_ALU_WIRELESS_ANSI 0x022c
-#define USB_DEVICE_ID_APPLE_ALU_WIRELESS_ISO 0x022d
-#define USB_DEVICE_ID_APPLE_ALU_WIRELESS_JIS 0x022e
+#define USB_DEVICE_ID_APPLE_GEYSER4_HF_ANSI 0x0229
+#define USB_DEVICE_ID_APPLE_GEYSER4_HF_ISO 0x022a
+#define USB_DEVICE_ID_APPLE_GEYSER4_HF_JIS 0x022b
+#define USB_DEVICE_ID_APPLE_ALU_WIRELESS_ANSI 0x022c
+#define USB_DEVICE_ID_APPLE_ALU_WIRELESS_ISO 0x022d
+#define USB_DEVICE_ID_APPLE_ALU_WIRELESS_JIS 0x022e
#define USB_DEVICE_ID_APPLE_WELLSPRING2_ANSI 0x0230
#define USB_DEVICE_ID_APPLE_WELLSPRING2_ISO 0x0231
#define USB_DEVICE_ID_APPLE_WELLSPRING2_JIS 0x0232
@@ -118,8 +120,8 @@
#define USB_VENDOR_ID_AVERMEDIA 0x07ca
#define USB_DEVICE_ID_AVER_FM_MR800 0xb800
-#define USB_VENDOR_ID_BELKIN 0x050d
-#define USB_DEVICE_ID_FLIP_KVM 0x3201
+#define USB_VENDOR_ID_BELKIN 0x050d
+#define USB_DEVICE_ID_FLIP_KVM 0x3201
#define USB_VENDOR_ID_BERKSHIRE 0x0c98
#define USB_DEVICE_ID_BERKSHIRE_PCWD 0x1140
@@ -128,7 +130,7 @@
#define USB_DEVICE_ID_BTC_EMPREX_REMOTE 0x5578
#define USB_VENDOR_ID_CANDO 0x2087
-#define USB_DEVICE_ID_CANDO_MULTI_TOUCH 0x0a01
+#define USB_DEVICE_ID_CANDO_MULTI_TOUCH 0x0a01
#define USB_DEVICE_ID_CANDO_MULTI_TOUCH_11_6 0x0b03
#define USB_VENDOR_ID_CH 0x068e
@@ -175,7 +177,7 @@
#define USB_DEVICE_ID_DEALEXTREAME_RADIO_SI4701 0x819a
#define USB_VENDOR_ID_DELORME 0x1163
-#define USB_DEVICE_ID_DELORME_EARTHMATE 0x0100
+#define USB_DEVICE_ID_DELORME_EARTHMATE 0x0100
#define USB_DEVICE_ID_DELORME_EM_LT20 0x0200
#define USB_VENDOR_ID_DMI 0x0c0b
@@ -187,19 +189,23 @@
#define USB_DEVICE_ID_EGALAX_TOUCHCONTROLLER 0x0001
#define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH 0x480d
+#define USB_VENDOR_ID_ELECOM 0x056e
+#define USB_DEVICE_ID_ELECOM_BM084 0x0061
+
#define USB_VENDOR_ID_ELO 0x04E7
#define USB_DEVICE_ID_ELO_TS2700 0x0020
#define USB_VENDOR_ID_ESSENTIAL_REALITY 0x0d7f
#define USB_DEVICE_ID_ESSENTIAL_REALITY_P5 0x0100
-#define USB_VENDOR_ID_ETURBOTOUCH 0x22b9
-#define USB_DEVICE_ID_ETURBOTOUCH 0x0006
-
#define USB_VENDOR_ID_ETT 0x0664
#define USB_DEVICE_ID_TC5UH 0x0309
+#define USB_DEVICE_ID_TC4UM 0x0306
+
+#define USB_VENDOR_ID_ETURBOTOUCH 0x22b9
+#define USB_DEVICE_ID_ETURBOTOUCH 0x0006
-#define USB_VENDOR_ID_EZKEY 0x0518
+#define USB_VENDOR_ID_EZKEY 0x0518
#define USB_DEVICE_ID_BTC_8193 0x0002
#define USB_VENDOR_ID_GAMERON 0x0810
@@ -296,9 +302,16 @@
#define USB_VENDOR_ID_KBGEAR 0x084e
#define USB_DEVICE_ID_KBGEAR_JAMSTUDIO 0x1001
+#define USB_VENDOR_ID_KENSINGTON 0x047d
+#define USB_DEVICE_ID_KS_SLIMBLADE 0x2041
+
#define USB_VENDOR_ID_KWORLD 0x1b80
#define USB_DEVICE_ID_KWORLD_RADIO_FM700 0xd700
+#define USB_VENDOR_ID_KYE 0x0458
+#define USB_DEVICE_ID_KYE_ERGO_525V 0x0087
+#define USB_DEVICE_ID_KYE_GPEN_560 0x5003
+
#define USB_VENDOR_ID_LABTEC 0x1020
#define USB_DEVICE_ID_LABTEC_WIRELESS_KEYBOARD 0x0006
@@ -318,9 +331,6 @@
#define USB_DEVICE_ID_LD_POWERCONTROL 0x2030
#define USB_DEVICE_ID_LD_MACHINETEST 0x2040
-#define USB_VENDOR_ID_KENSINGTON 0x047d
-#define USB_DEVICE_ID_KS_SLIMBLADE 0x2041
-
#define USB_VENDOR_ID_LOGITECH 0x046d
#define USB_DEVICE_ID_LOGITECH_RECEIVER 0xc101
#define USB_DEVICE_ID_LOGITECH_HARMONY_FIRST 0xc110
@@ -376,23 +386,23 @@
#define USB_VENDOR_ID_MONTEREY 0x0566
#define USB_DEVICE_ID_GENIUS_KB29E 0x3004
+#define USB_VENDOR_ID_NATIONAL_SEMICONDUCTOR 0x0400
+#define USB_DEVICE_ID_N_S_HARMONY 0xc359
+
+#define USB_VENDOR_ID_NATSU 0x08b7
+#define USB_DEVICE_ID_NATSU_GAMEPAD 0x0001
+
#define USB_VENDOR_ID_NCR 0x0404
#define USB_DEVICE_ID_NCR_FIRST 0x0300
#define USB_DEVICE_ID_NCR_LAST 0x03ff
-#define USB_VENDOR_ID_NATIONAL_SEMICONDUCTOR 0x0400
-#define USB_DEVICE_ID_N_S_HARMONY 0xc359
-
-#define USB_VENDOR_ID_NATSU 0x08b7
-#define USB_DEVICE_ID_NATSU_GAMEPAD 0x0001
-
#define USB_VENDOR_ID_NEC 0x073e
#define USB_DEVICE_ID_NEC_USB_GAME_PAD 0x0301
#define USB_VENDOR_ID_NEXTWINDOW 0x1926
#define USB_DEVICE_ID_NEXTWINDOW_TOUCHSCREEN 0x0003
-#define USB_VENDOR_ID_NTRIG 0x1b96
+#define USB_VENDOR_ID_NTRIG 0x1b96
#define USB_DEVICE_ID_NTRIG_TOUCH_SCREEN 0x0001
#define USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_1 0x0003
#define USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_2 0x0004
@@ -427,9 +437,12 @@
#define USB_VENDOR_ID_PETALYNX 0x18b1
#define USB_DEVICE_ID_PETALYNX_MAXTER_REMOTE 0x0037
-#define USB_VENDOR_ID_PHILIPS 0x0471
+#define USB_VENDOR_ID_PHILIPS 0x0471
#define USB_DEVICE_ID_PHILIPS_IEEE802154_DONGLE 0x0617
+#define USB_VENDOR_ID_PI_ENGINEERING 0x05f3
+#define USB_DEVICE_ID_PI_ENGINEERING_VEC_USB_FOOTPEDAL 0xff
+
#define USB_VENDOR_ID_PLAYDOTCOM 0x0b43
#define USB_DEVICE_ID_PLAYDOTCOM_EMS_USBII 0x0003
@@ -439,16 +452,16 @@
#define USB_VENDOR_ID_PRODIGE 0x05af
#define USB_DEVICE_ID_PRODIGE_CORDLESS 0x3062
+#define USB_VENDOR_ID_QUANTA 0x0408
+#define USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH 0x3000
+#define USB_DEVICE_ID_PIXART_IMAGING_INC_OPTICAL_TOUCH_SCREEN 0x3001
+
#define USB_VENDOR_ID_ROCCAT 0x1e7d
#define USB_DEVICE_ID_ROCCAT_KONE 0x2ced
#define USB_VENDOR_ID_SAITEK 0x06a3
#define USB_DEVICE_ID_SAITEK_RUMBLEPAD 0xff17
-#define USB_VENDOR_ID_QUANTA 0x0408
-#define USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH 0x3000
-#define USB_DEVICE_ID_PIXART_IMAGING_INC_OPTICAL_TOUCH_SCREEN 0x3001
-
#define USB_VENDOR_ID_SAMSUNG 0x0419
#define USB_DEVICE_ID_SAMSUNG_IR_REMOTE 0x0001
#define USB_DEVICE_ID_SAMSUNG_WIRELESS_KBD_MOUSE 0x0600
@@ -472,20 +485,23 @@
#define USB_VENDOR_ID_THRUSTMASTER 0x044f
-#define USB_VENDOR_ID_TOUCHPACK 0x1bfd
-#define USB_DEVICE_ID_TOUCHPACK_RTS 0x1688
+#define USB_VENDOR_ID_TOPSEED 0x0766
+#define USB_DEVICE_ID_TOPSEED_CYBERLINK 0x0204
+
+#define USB_VENDOR_ID_TOPSEED2 0x1784
+#define USB_DEVICE_ID_TOPSEED2_RF_COMBO 0x0004
#define USB_VENDOR_ID_TOPMAX 0x0663
#define USB_DEVICE_ID_TOPMAX_COBRAPAD 0x0103
-#define USB_VENDOR_ID_TOPSEED 0x0766
-#define USB_DEVICE_ID_TOPSEED_CYBERLINK 0x0204
+#define USB_VENDOR_ID_TOUCHPACK 0x1bfd
+#define USB_DEVICE_ID_TOUCHPACK_RTS 0x1688
#define USB_VENDOR_ID_TURBOX 0x062a
#define USB_DEVICE_ID_TURBOX_KEYBOARD 0x0201
-#define USB_VENDOR_ID_TWINHAN 0x6253
-#define USB_DEVICE_ID_TWINHAN_IR_REMOTE 0x0100
+#define USB_VENDOR_ID_TWINHAN 0x6253
+#define USB_DEVICE_ID_TWINHAN_IR_REMOTE 0x0100
#define USB_VENDOR_ID_UCLOGIC 0x5543
#define USB_DEVICE_ID_UCLOGIC_TABLET_PF1209 0x0042
@@ -500,7 +516,6 @@
#define USB_VENDOR_ID_WACOM 0x056a
#define USB_DEVICE_ID_WACOM_GRAPHIRE_BLUETOOTH 0x81
-#define USB_DEVICE_ID_WACOM_INTUOS4_BLUETOOTH 0xbd
#define USB_VENDOR_ID_WISEGROUP 0x0925
#define USB_DEVICE_ID_SMARTJOY_PLUS 0x0005
@@ -522,9 +537,4 @@
#define USB_VENDOR_ID_ZYDACRON 0x13EC
#define USB_DEVICE_ID_ZYDACRON_REMOTE_CONTROL 0x0006
-#define USB_VENDOR_ID_KYE 0x0458
-#define USB_DEVICE_ID_KYE_ERGO_525V 0x0087
-#define USB_DEVICE_ID_KYE_GPEN_560 0x5003
-
-
#endif
diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c
index 7a0d2e4661a..6c03dcc5760 100644
--- a/drivers/hid/hid-input.c
+++ b/drivers/hid/hid-input.c
@@ -199,11 +199,11 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
case HID_GD_MOUSE:
case HID_GD_POINTER: code += 0x110; break;
case HID_GD_JOYSTICK:
- if (code <= 0xf)
- code += BTN_JOYSTICK;
- else
- code += BTN_TRIGGER_HAPPY;
- break;
+ if (code <= 0xf)
+ code += BTN_JOYSTICK;
+ else
+ code += BTN_TRIGGER_HAPPY;
+ break;
case HID_GD_GAMEPAD: code += 0x130; break;
default:
switch (field->physical) {
@@ -301,6 +301,9 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
case HID_UP_DIGITIZER:
switch (usage->hid & 0xff) {
+ case 0x00: /* Undefined */
+ goto ignore;
+
case 0x30: /* TipPressure */
if (!test_bit(BTN_TOUCH, input->keybit)) {
device->quirks |= HID_QUIRK_NOTOUCH;
@@ -480,7 +483,7 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
case HID_UP_LOGIVENDOR:
goto ignore;
-
+
case HID_UP_PID:
switch (usage->hid & HID_USAGE) {
case 0xa4: map_key_clear(BTN_DEAD); break;
@@ -534,6 +537,9 @@ mapped:
input_set_abs_params(input, usage->code, a, b, (b - a) >> 8, (b - a) >> 4);
else input_set_abs_params(input, usage->code, a, b, 0, 0);
+ /* use a larger default input buffer for MT devices */
+ if (usage->code == ABS_MT_POSITION_X && input->hint_events_per_packet == 0)
+ input_set_events_per_packet(input, 60);
}
if (usage->type == EV_ABS &&
@@ -586,9 +592,9 @@ void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct
hat_dir = (value - usage->hat_min) * 8 / (usage->hat_max - usage->hat_min + 1) + 1;
if (hat_dir < 0 || hat_dir > 8) hat_dir = 0;
input_event(input, usage->type, usage->code , hid_hat_to_axis[hat_dir].x);
- input_event(input, usage->type, usage->code + 1, hid_hat_to_axis[hat_dir].y);
- return;
- }
+ input_event(input, usage->type, usage->code + 1, hid_hat_to_axis[hat_dir].y);
+ return;
+ }
if (usage->hid == (HID_UP_DIGITIZER | 0x003c)) { /* Invert */
*quirks = value ? (*quirks | HID_QUIRK_INVERT) : (*quirks & ~HID_QUIRK_INVERT);
diff --git a/drivers/hid/hid-magicmouse.c b/drivers/hid/hid-magicmouse.c
index f10d56a15f2..319b0e57ee4 100644
--- a/drivers/hid/hid-magicmouse.c
+++ b/drivers/hid/hid-magicmouse.c
@@ -30,6 +30,21 @@ static bool emulate_scroll_wheel = true;
module_param(emulate_scroll_wheel, bool, 0644);
MODULE_PARM_DESC(emulate_scroll_wheel, "Emulate a scroll wheel");
+static unsigned int scroll_speed = 32;
+static int param_set_scroll_speed(const char *val, struct kernel_param *kp) {
+ unsigned long speed;
+ if (!val || strict_strtoul(val, 0, &speed) || speed > 63)
+ return -EINVAL;
+ scroll_speed = speed;
+ return 0;
+}
+module_param_call(scroll_speed, param_set_scroll_speed, param_get_uint, &scroll_speed, 0644);
+MODULE_PARM_DESC(scroll_speed, "Scroll speed, value from 0 (slow) to 63 (fast)");
+
+static bool scroll_acceleration = false;
+module_param(scroll_acceleration, bool, 0644);
+MODULE_PARM_DESC(scroll_acceleration, "Accelerate sequential scroll events");
+
static bool report_touches = true;
module_param(report_touches, bool, 0644);
MODULE_PARM_DESC(report_touches, "Emit touch records (otherwise, only use them for emulation)");
@@ -50,6 +65,8 @@ MODULE_PARM_DESC(report_undeciphered, "Report undeciphered multi-touch state fie
#define TOUCH_STATE_START 0x30
#define TOUCH_STATE_DRAG 0x40
+#define SCROLL_ACCEL_DEFAULT 7
+
/**
* struct magicmouse_sc - Tracks Magic Mouse-specific data.
* @input: Input device through which we report events.
@@ -78,8 +95,10 @@ struct magicmouse_sc {
struct {
short x;
short y;
+ short scroll_x;
short scroll_y;
u8 size;
+ u8 down;
} touches[16];
int tracking_ids[16];
};
@@ -141,7 +160,7 @@ static void magicmouse_emit_buttons(struct magicmouse_sc *msc, int state)
input_report_key(msc->input, BTN_RIGHT, state & 2);
if (state != last_state)
- msc->scroll_accel = 0;
+ msc->scroll_accel = SCROLL_ACCEL_DEFAULT;
}
static void magicmouse_emit_touch(struct magicmouse_sc *msc, int raw_id, u8 *tdata)
@@ -152,6 +171,7 @@ static void magicmouse_emit_touch(struct magicmouse_sc *msc, int raw_id, u8 *tda
int id = (misc >> 6) & 15;
int x = x_y << 12 >> 20;
int y = -(x_y >> 20);
+ int down = (tdata[7] & TOUCH_STATE_MASK) != TOUCH_STATE_NONE;
/* Store tracking ID and other fields. */
msc->tracking_ids[raw_id] = id;
@@ -160,42 +180,54 @@ static void magicmouse_emit_touch(struct magicmouse_sc *msc, int raw_id, u8 *tda
msc->touches[id].size = misc & 63;
/* If requested, emulate a scroll wheel by detecting small
- * vertical touch motions along the middle of the mouse.
+ * vertical touch motions.
*/
- if (emulate_scroll_wheel &&
- middle_button_start < x && x < middle_button_stop) {
- static const int accel_profile[] = {
- 256, 228, 192, 160, 128, 96, 64, 32,
- };
+ if (emulate_scroll_wheel) {
unsigned long now = jiffies;
- int step = msc->touches[id].scroll_y - y;
-
- /* Reset acceleration after half a second. */
- if (time_after(now, msc->scroll_jiffies + HZ / 2))
- msc->scroll_accel = 0;
+ int step_x = msc->touches[id].scroll_x - x;
+ int step_y = msc->touches[id].scroll_y - y;
/* Calculate and apply the scroll motion. */
switch (tdata[7] & TOUCH_STATE_MASK) {
case TOUCH_STATE_START:
+ msc->touches[id].scroll_x = x;
msc->touches[id].scroll_y = y;
- msc->scroll_accel = min_t(int, msc->scroll_accel + 1,
- ARRAY_SIZE(accel_profile) - 1);
+
+ /* Reset acceleration after half a second. */
+ if (scroll_acceleration && time_before(now,
+ msc->scroll_jiffies + HZ / 2))
+ msc->scroll_accel = max_t(int,
+ msc->scroll_accel - 1, 1);
+ else
+ msc->scroll_accel = SCROLL_ACCEL_DEFAULT;
+
break;
case TOUCH_STATE_DRAG:
- step = step / accel_profile[msc->scroll_accel];
- if (step != 0) {
- msc->touches[id].scroll_y = y;
+ step_x /= (64 - (int)scroll_speed) * msc->scroll_accel;
+ if (step_x != 0) {
+ msc->touches[id].scroll_x -= step_x *
+ (64 - scroll_speed) * msc->scroll_accel;
msc->scroll_jiffies = now;
- input_report_rel(input, REL_WHEEL, step);
+ input_report_rel(input, REL_HWHEEL, -step_x);
+ }
+
+ step_y /= (64 - (int)scroll_speed) * msc->scroll_accel;
+ if (step_y != 0) {
+ msc->touches[id].scroll_y -= step_y *
+ (64 - scroll_speed) * msc->scroll_accel;
+ msc->scroll_jiffies = now;
+ input_report_rel(input, REL_WHEEL, step_y);
}
break;
}
}
/* Generate the input events for this touch. */
- if (report_touches) {
+ if (report_touches && down) {
int orientation = (misc >> 10) - 32;
+ msc->touches[id].down = 1;
+
input_report_abs(input, ABS_MT_TRACKING_ID, id);
input_report_abs(input, ABS_MT_TOUCH_MAJOR, tdata[3]);
input_report_abs(input, ABS_MT_TOUCH_MINOR, tdata[4]);
@@ -215,7 +247,7 @@ static int magicmouse_raw_event(struct hid_device *hdev,
{
struct magicmouse_sc *msc = hid_get_drvdata(hdev);
struct input_dev *input = msc->input;
- int x, y, ts, ii, clicks;
+ int x, y, ts, ii, clicks, last_up;
switch (data[0]) {
case 0x10:
@@ -235,12 +267,26 @@ static int magicmouse_raw_event(struct hid_device *hdev,
msc->ntouches = (size - 6) / 8;
for (ii = 0; ii < msc->ntouches; ii++)
magicmouse_emit_touch(msc, ii, data + ii * 8 + 6);
+
+ if (report_touches) {
+ last_up = 1;
+ for (ii = 0; ii < ARRAY_SIZE(msc->touches); ii++) {
+ if (msc->touches[ii].down) {
+ last_up = 0;
+ msc->touches[ii].down = 0;
+ }
+ }
+ if (last_up) {
+ input_mt_sync(input);
+ }
+ }
+
/* When emulating three-button mode, it is important
* to have the current touch information before
* generating a click event.
*/
- x = (signed char)data[1];
- y = (signed char)data[2];
+ x = (int)(((data[3] & 0x0c) << 28) | (data[1] << 22)) >> 22;
+ y = (int)(((data[3] & 0x30) << 26) | (data[2] << 22)) >> 22;
clicks = data[3];
break;
case 0x20: /* Theoretically battery status (0-100), but I have
@@ -301,8 +347,10 @@ static void magicmouse_setup_input(struct input_dev *input, struct hid_device *h
__set_bit(EV_REL, input->evbit);
__set_bit(REL_X, input->relbit);
__set_bit(REL_Y, input->relbit);
- if (emulate_scroll_wheel)
+ if (emulate_scroll_wheel) {
__set_bit(REL_WHEEL, input->relbit);
+ __set_bit(REL_HWHEEL, input->relbit);
+ }
if (report_touches) {
__set_bit(EV_ABS, input->evbit);
@@ -345,6 +393,8 @@ static int magicmouse_probe(struct hid_device *hdev,
return -ENOMEM;
}
+ msc->scroll_accel = SCROLL_ACCEL_DEFAULT;
+
msc->quirks = id->driver_data;
hid_set_drvdata(hdev, msc);
diff --git a/drivers/hid/hid-picolcd.c b/drivers/hid/hid-picolcd.c
index 7aabf65c48e..346f0e34987 100644
--- a/drivers/hid/hid-picolcd.c
+++ b/drivers/hid/hid-picolcd.c
@@ -127,6 +127,26 @@ static const struct fb_var_screeninfo picolcdfb_var = {
.height = 26,
.bits_per_pixel = 1,
.grayscale = 1,
+ .red = {
+ .offset = 0,
+ .length = 1,
+ .msb_right = 0,
+ },
+ .green = {
+ .offset = 0,
+ .length = 1,
+ .msb_right = 0,
+ },
+ .blue = {
+ .offset = 0,
+ .length = 1,
+ .msb_right = 0,
+ },
+ .transp = {
+ .offset = 0,
+ .length = 0,
+ .msb_right = 0,
+ },
};
#endif /* CONFIG_HID_PICOLCD_FB */
@@ -188,6 +208,7 @@ struct picolcd_data {
/* Framebuffer stuff */
u8 fb_update_rate;
u8 fb_bpp;
+ u8 fb_force;
u8 *fb_vbitmap; /* local copy of what was sent to PicoLCD */
u8 *fb_bitmap; /* framebuffer */
struct fb_info *fb_info;
@@ -346,7 +367,7 @@ static int picolcd_fb_update_tile(u8 *vbitmap, const u8 *bitmap, int bpp,
const u8 *bdata = bitmap + tile * 256 + chip * 8 + b * 32;
for (i = 0; i < 64; i++) {
tdata[i] <<= 1;
- tdata[i] |= (bdata[i/8] >> (7 - i % 8)) & 0x01;
+ tdata[i] |= (bdata[i/8] >> (i % 8)) & 0x01;
}
}
} else if (bpp == 8) {
@@ -399,13 +420,10 @@ static int picolcd_fb_reset(struct picolcd_data *data, int clear)
if (data->fb_bitmap) {
if (clear) {
- memset(data->fb_vbitmap, 0xff, PICOLCDFB_SIZE);
+ memset(data->fb_vbitmap, 0, PICOLCDFB_SIZE);
memset(data->fb_bitmap, 0, PICOLCDFB_SIZE*data->fb_bpp);
- } else {
- /* invert 1 byte in each tile to force resend */
- for (i = 0; i < PICOLCDFB_SIZE; i += 64)
- data->fb_vbitmap[i] = ~data->fb_vbitmap[i];
}
+ data->fb_force = 1;
}
/* schedule first output of framebuffer */
@@ -421,6 +439,9 @@ static void picolcd_fb_update(struct picolcd_data *data)
int chip, tile, n;
unsigned long flags;
+ if (!data)
+ return;
+
spin_lock_irqsave(&data->lock, flags);
if (!(data->status & PICOLCD_READY_FB)) {
spin_unlock_irqrestore(&data->lock, flags);
@@ -440,14 +461,18 @@ static void picolcd_fb_update(struct picolcd_data *data)
for (chip = 0; chip < 4; chip++)
for (tile = 0; tile < 8; tile++)
if (picolcd_fb_update_tile(data->fb_vbitmap,
- data->fb_bitmap, data->fb_bpp, chip, tile)) {
+ data->fb_bitmap, data->fb_bpp, chip, tile) ||
+ data->fb_force) {
n += 2;
+ if (!data->fb_info->par)
+ return; /* device lost! */
if (n >= HID_OUTPUT_FIFO_SIZE / 2) {
usbhid_wait_io(data->hdev);
n = 0;
}
picolcd_fb_send_tile(data->hdev, chip, tile);
}
+ data->fb_force = false;
if (n)
usbhid_wait_io(data->hdev);
}
@@ -511,11 +536,23 @@ static int picolcd_fb_blank(int blank, struct fb_info *info)
static void picolcd_fb_destroy(struct fb_info *info)
{
struct picolcd_data *data = info->par;
+ u32 *ref_cnt = info->pseudo_palette;
+ int may_release;
+
info->par = NULL;
if (data)
data->fb_info = NULL;
fb_deferred_io_cleanup(info);
- framebuffer_release(info);
+
+ ref_cnt--;
+ mutex_lock(&info->lock);
+ (*ref_cnt)--;
+ may_release = !ref_cnt;
+ mutex_unlock(&info->lock);
+ if (may_release) {
+ framebuffer_release(info);
+ vfree((u8 *)info->fix.smem_start);
+ }
}
static int picolcd_fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
@@ -526,29 +563,37 @@ static int picolcd_fb_check_var(struct fb_var_screeninfo *var, struct fb_info *i
/* only allow 1/8 bit depth (8-bit is grayscale) */
*var = picolcdfb_var;
var->activate = activate;
- if (bpp >= 8)
+ if (bpp >= 8) {
var->bits_per_pixel = 8;
- else
+ var->red.length = 8;
+ var->green.length = 8;
+ var->blue.length = 8;
+ } else {
var->bits_per_pixel = 1;
+ var->red.length = 1;
+ var->green.length = 1;
+ var->blue.length = 1;
+ }
return 0;
}
static int picolcd_set_par(struct fb_info *info)
{
struct picolcd_data *data = info->par;
- u8 *o_fb, *n_fb;
+ u8 *tmp_fb, *o_fb;
+ if (!data)
+ return -ENODEV;
if (info->var.bits_per_pixel == data->fb_bpp)
return 0;
/* switch between 1/8 bit depths */
if (info->var.bits_per_pixel != 1 && info->var.bits_per_pixel != 8)
return -EINVAL;
- o_fb = data->fb_bitmap;
- n_fb = vmalloc(PICOLCDFB_SIZE*info->var.bits_per_pixel);
- if (!n_fb)
+ o_fb = data->fb_bitmap;
+ tmp_fb = kmalloc(PICOLCDFB_SIZE*info->var.bits_per_pixel, GFP_KERNEL);
+ if (!tmp_fb)
return -ENOMEM;
- fb_deferred_io_cleanup(info);
/* translate FB content to new bits-per-pixel */
if (info->var.bits_per_pixel == 1) {
int i, b;
@@ -558,24 +603,87 @@ static int picolcd_set_par(struct fb_info *info)
p <<= 1;
p |= o_fb[i*8+b] ? 0x01 : 0x00;
}
+ tmp_fb[i] = p;
}
+ memcpy(o_fb, tmp_fb, PICOLCDFB_SIZE);
info->fix.visual = FB_VISUAL_MONO01;
info->fix.line_length = PICOLCDFB_WIDTH / 8;
} else {
int i;
+ memcpy(tmp_fb, o_fb, PICOLCDFB_SIZE);
for (i = 0; i < PICOLCDFB_SIZE * 8; i++)
- n_fb[i] = o_fb[i/8] & (0x01 << (7 - i % 8)) ? 0xff : 0x00;
- info->fix.visual = FB_VISUAL_TRUECOLOR;
+ o_fb[i] = tmp_fb[i/8] & (0x01 << (7 - i % 8)) ? 0xff : 0x00;
+ info->fix.visual = FB_VISUAL_DIRECTCOLOR;
info->fix.line_length = PICOLCDFB_WIDTH;
}
- data->fb_bitmap = n_fb;
+ kfree(tmp_fb);
data->fb_bpp = info->var.bits_per_pixel;
- info->screen_base = (char __force __iomem *)n_fb;
- info->fix.smem_start = (unsigned long)n_fb;
- info->fix.smem_len = PICOLCDFB_SIZE*data->fb_bpp;
- fb_deferred_io_init(info);
- vfree(o_fb);
+ return 0;
+}
+
+/* Do refcounting on our FB and cleanup per worker if FB is
+ * closed after unplug of our device
+ * (fb_release holds info->lock and still touches info after
+ * we return so we can't release it immediately.
+ */
+struct picolcd_fb_cleanup_item {
+ struct fb_info *info;
+ struct picolcd_fb_cleanup_item *next;
+};
+static struct picolcd_fb_cleanup_item *fb_pending;
+DEFINE_SPINLOCK(fb_pending_lock);
+
+static void picolcd_fb_do_cleanup(struct work_struct *data)
+{
+ struct picolcd_fb_cleanup_item *item;
+ unsigned long flags;
+
+ do {
+ spin_lock_irqsave(&fb_pending_lock, flags);
+ item = fb_pending;
+ fb_pending = item ? item->next : NULL;
+ spin_unlock_irqrestore(&fb_pending_lock, flags);
+
+ if (item) {
+ u8 *fb = (u8 *)item->info->fix.smem_start;
+ /* make sure we do not race against fb core when
+ * releasing */
+ mutex_lock(&item->info->lock);
+ mutex_unlock(&item->info->lock);
+ framebuffer_release(item->info);
+ vfree(fb);
+ }
+ } while (item);
+}
+
+DECLARE_WORK(picolcd_fb_cleanup, picolcd_fb_do_cleanup);
+
+static int picolcd_fb_open(struct fb_info *info, int u)
+{
+ u32 *ref_cnt = info->pseudo_palette;
+ ref_cnt--;
+
+ (*ref_cnt)++;
+ return 0;
+}
+
+static int picolcd_fb_release(struct fb_info *info, int u)
+{
+ u32 *ref_cnt = info->pseudo_palette;
+ ref_cnt--;
+
+ (*ref_cnt)++;
+ if (!*ref_cnt) {
+ unsigned long flags;
+ struct picolcd_fb_cleanup_item *item = (struct picolcd_fb_cleanup_item *)ref_cnt;
+ item--;
+ spin_lock_irqsave(&fb_pending_lock, flags);
+ item->next = fb_pending;
+ fb_pending = item;
+ spin_unlock_irqrestore(&fb_pending_lock, flags);
+ schedule_work(&picolcd_fb_cleanup);
+ }
return 0;
}
@@ -583,6 +691,8 @@ static int picolcd_set_par(struct fb_info *info)
static struct fb_ops picolcdfb_ops = {
.owner = THIS_MODULE,
.fb_destroy = picolcd_fb_destroy,
+ .fb_open = picolcd_fb_open,
+ .fb_release = picolcd_fb_release,
.fb_read = fb_sys_read,
.fb_write = picolcd_fb_write,
.fb_blank = picolcd_fb_blank,
@@ -660,11 +770,12 @@ static int picolcd_init_framebuffer(struct picolcd_data *data)
{
struct device *dev = &data->hdev->dev;
struct fb_info *info = NULL;
- int error = -ENOMEM;
+ int i, error = -ENOMEM;
u8 *fb_vbitmap = NULL;
u8 *fb_bitmap = NULL;
+ u32 *palette;
- fb_bitmap = vmalloc(PICOLCDFB_SIZE*picolcdfb_var.bits_per_pixel);
+ fb_bitmap = vmalloc(PICOLCDFB_SIZE*8);
if (fb_bitmap == NULL) {
dev_err(dev, "can't get a free page for framebuffer\n");
goto err_nomem;
@@ -678,18 +789,29 @@ static int picolcd_init_framebuffer(struct picolcd_data *data)
data->fb_update_rate = PICOLCDFB_UPDATE_RATE_DEFAULT;
data->fb_defio = picolcd_fb_defio;
- info = framebuffer_alloc(0, dev);
+ /* The extra memory is:
+ * - struct picolcd_fb_cleanup_item
+ * - u32 for ref_count
+ * - 256*u32 for pseudo_palette
+ */
+ info = framebuffer_alloc(257 * sizeof(u32) + sizeof(struct picolcd_fb_cleanup_item), dev);
if (info == NULL) {
dev_err(dev, "failed to allocate a framebuffer\n");
goto err_nomem;
}
+ palette = info->par + sizeof(struct picolcd_fb_cleanup_item);
+ *palette = 1;
+ palette++;
+ for (i = 0; i < 256; i++)
+ palette[i] = i > 0 && i < 16 ? 0xff : 0;
+ info->pseudo_palette = palette;
info->fbdefio = &data->fb_defio;
info->screen_base = (char __force __iomem *)fb_bitmap;
info->fbops = &picolcdfb_ops;
info->var = picolcdfb_var;
info->fix = picolcdfb_fix;
- info->fix.smem_len = PICOLCDFB_SIZE;
+ info->fix.smem_len = PICOLCDFB_SIZE*8;
info->fix.smem_start = (unsigned long)fb_bitmap;
info->par = data;
info->flags = FBINFO_FLAG_DEFAULT;
@@ -707,18 +829,20 @@ static int picolcd_init_framebuffer(struct picolcd_data *data)
dev_err(dev, "failed to create sysfs attributes\n");
goto err_cleanup;
}
+ fb_deferred_io_init(info);
data->fb_info = info;
error = register_framebuffer(info);
if (error) {
dev_err(dev, "failed to register framebuffer\n");
goto err_sysfs;
}
- fb_deferred_io_init(info);
/* schedule first output of framebuffer */
+ data->fb_force = 1;
schedule_delayed_work(&info->deferred_work, 0);
return 0;
err_sysfs:
+ fb_deferred_io_cleanup(info);
device_remove_file(dev, &dev_attr_fb_update_rate);
err_cleanup:
data->fb_vbitmap = NULL;
@@ -737,19 +861,17 @@ static void picolcd_exit_framebuffer(struct picolcd_data *data)
{
struct fb_info *info = data->fb_info;
u8 *fb_vbitmap = data->fb_vbitmap;
- u8 *fb_bitmap = data->fb_bitmap;
if (!info)
return;
+ info->par = NULL;
+ device_remove_file(&data->hdev->dev, &dev_attr_fb_update_rate);
+ unregister_framebuffer(info);
data->fb_vbitmap = NULL;
data->fb_bitmap = NULL;
data->fb_bpp = 0;
data->fb_info = NULL;
- device_remove_file(&data->hdev->dev, &dev_attr_fb_update_rate);
- fb_deferred_io_cleanup(info);
- unregister_framebuffer(info);
- vfree(fb_bitmap);
kfree(fb_vbitmap);
}
@@ -2566,6 +2688,13 @@ static void picolcd_remove(struct hid_device *hdev)
spin_lock_irqsave(&data->lock, flags);
data->status |= PICOLCD_FAILED;
spin_unlock_irqrestore(&data->lock, flags);
+#ifdef CONFIG_HID_PICOLCD_FB
+ /* short-circuit FB as early as possible in order to
+ * avoid long delays if we host console.
+ */
+ if (data->fb_info)
+ data->fb_info->par = NULL;
+#endif
picolcd_exit_devfs(data);
device_remove_file(&hdev->dev, &dev_attr_operation_mode);
@@ -2623,6 +2752,10 @@ static int __init picolcd_init(void)
static void __exit picolcd_exit(void)
{
hid_unregister_driver(&picolcd_driver);
+#ifdef CONFIG_HID_PICOLCD_FB
+ flush_scheduled_work();
+ WARN_ON(fb_pending);
+#endif
}
module_init(picolcd_init);
diff --git a/drivers/hid/hid-roccat-kone.c b/drivers/hid/hid-roccat-kone.c
index 17f2dc04f88..f77695762cb 100644
--- a/drivers/hid/hid-roccat-kone.c
+++ b/drivers/hid/hid-roccat-kone.c
@@ -22,11 +22,6 @@
* Is it possible to remove and reinstall the urb in raw-event- or any
* other handler, or to defer this action to be executed somewhere else?
*
- * TODO implement notification mechanism for overlong macro execution
- * If user wants to execute an overlong macro only the names of macroset
- * and macro are given. Should userland tap hidraw or is there an
- * additional streaming mechanism?
- *
* TODO is it possible to overwrite group for sysfs attributes via udev?
*/
@@ -277,7 +272,7 @@ static ssize_t kone_sysfs_read_settings(struct file *fp, struct kobject *kobj,
count = sizeof(struct kone_settings) - off;
mutex_lock(&kone->kone_lock);
- memcpy(buf, &kone->settings + off, count);
+ memcpy(buf, ((char const *)&kone->settings) + off, count);
mutex_unlock(&kone->kone_lock);
return count;
@@ -337,7 +332,7 @@ static ssize_t kone_sysfs_read_profilex(struct kobject *kobj,
count = sizeof(struct kone_profile) - off;
mutex_lock(&kone->kone_lock);
- memcpy(buf, &kone->profiles[number - 1], sizeof(struct kone_profile));
+ memcpy(buf, ((char const *)&kone->profiles[number - 1]) + off, count);
mutex_unlock(&kone->kone_lock);
return count;
@@ -623,18 +618,6 @@ static ssize_t kone_sysfs_set_startup_profile(struct device *dev,
}
/*
- * This file is used by userland software to find devices that are handled by
- * this driver. This provides a consistent way for actual and older kernels
- * where this driver replaced usbhid instead of generic-usb.
- * Driver capabilities are determined by version number.
- */
-static ssize_t kone_sysfs_show_driver_version(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- return snprintf(buf, PAGE_SIZE, ROCCAT_KONE_DRIVER_VERSION "\n");
-}
-
-/*
* Read actual dpi settings.
* Returns raw value for further processing. Refer to enum kone_polling_rates to
* get real value.
@@ -671,9 +654,6 @@ static DEVICE_ATTR(startup_profile, 0660,
kone_sysfs_show_startup_profile,
kone_sysfs_set_startup_profile);
-static DEVICE_ATTR(kone_driver_version, 0440,
- kone_sysfs_show_driver_version, NULL);
-
static struct attribute *kone_attributes[] = {
&dev_attr_actual_dpi.attr,
&dev_attr_actual_profile.attr,
@@ -681,7 +661,6 @@ static struct attribute *kone_attributes[] = {
&dev_attr_firmware_version.attr,
&dev_attr_tcu.attr,
&dev_attr_startup_profile.attr,
- &dev_attr_kone_driver_version.attr,
NULL
};
diff --git a/drivers/hid/hid-roccat-kone.h b/drivers/hid/hid-roccat-kone.h
index 003e6f81c19..130d6566ea8 100644
--- a/drivers/hid/hid-roccat-kone.h
+++ b/drivers/hid/hid-roccat-kone.h
@@ -14,8 +14,6 @@
#include <linux/types.h>
-#define ROCCAT_KONE_DRIVER_VERSION "v0.3.1"
-
#pragma pack(push)
#pragma pack(1)
diff --git a/drivers/hid/hid-roccat.c b/drivers/hid/hid-roccat.c
index e05d48edb66..f6e80c7ca61 100644
--- a/drivers/hid/hid-roccat.c
+++ b/drivers/hid/hid-roccat.c
@@ -168,7 +168,7 @@ static int roccat_open(struct inode *inode, struct file *file)
printk(KERN_EMERG "roccat device with minor %d doesn't exist\n",
minor);
error = -ENODEV;
- goto exit_unlock;
+ goto exit_err;
}
if (!device->open++) {
@@ -178,7 +178,7 @@ static int roccat_open(struct inode *inode, struct file *file)
PM_HINT_FULLON);
if (error < 0) {
--device->open;
- goto exit_unlock;
+ goto exit_err;
}
}
error = device->hid->ll_driver->open(device->hid);
@@ -187,7 +187,7 @@ static int roccat_open(struct inode *inode, struct file *file)
device->hid->ll_driver->power(device->hid,
PM_HINT_NORMAL);
--device->open;
- goto exit_unlock;
+ goto exit_err;
}
}
@@ -202,6 +202,9 @@ exit_unlock:
mutex_unlock(&device->readers_lock);
mutex_unlock(&devices_lock);
return error;
+exit_err:
+ kfree(reader);
+ goto exit_unlock;
}
static int roccat_release(struct inode *inode, struct file *file)
diff --git a/drivers/hid/hid-roccat.h b/drivers/hid/hid-roccat.h
index d8aae0c1fa7..09e864e9f79 100644
--- a/drivers/hid/hid-roccat.h
+++ b/drivers/hid/hid-roccat.h
@@ -15,7 +15,7 @@
#include <linux/hid.h>
#include <linux/types.h>
-#if defined(CONFIG_HID_ROCCAT) || defined (CONFIG_HID_ROCCAT_MODULE)
+#if defined(CONFIG_HID_ROCCAT) || defined(CONFIG_HID_ROCCAT_MODULE)
int roccat_connect(struct hid_device *hid);
void roccat_disconnect(int minor);
int roccat_report_event(int minor, u8 const *data, int len);
diff --git a/drivers/hid/hid-topseed.c b/drivers/hid/hid-topseed.c
index 2eebdcc57bc..5771f851f85 100644
--- a/drivers/hid/hid-topseed.c
+++ b/drivers/hid/hid-topseed.c
@@ -6,6 +6,9 @@
*
* Modified to also support BTC "Emprex 3009URF III Vista MCE Remote" by
* Wayne Thomas 2010.
+ *
+ * Modified to support Conceptronic CLLRCMCE by
+ * Kees Bakker 2010.
*/
/*
@@ -34,6 +37,7 @@ static int ts_input_mapping(struct hid_device *hdev, struct hid_input *hi,
case 0x00d: ts_map_key_clear(KEY_MEDIA); break;
case 0x024: ts_map_key_clear(KEY_MENU); break;
case 0x025: ts_map_key_clear(KEY_TV); break;
+ case 0x027: ts_map_key_clear(KEY_MODE); break;
case 0x031: ts_map_key_clear(KEY_AUDIO); break;
case 0x032: ts_map_key_clear(KEY_TEXT); break;
case 0x033: ts_map_key_clear(KEY_CHANNEL); break;
@@ -60,6 +64,7 @@ static int ts_input_mapping(struct hid_device *hdev, struct hid_input *hi,
static const struct hid_device_id ts_devices[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_TOPSEED, USB_DEVICE_ID_TOPSEED_CYBERLINK) },
{ HID_USB_DEVICE(USB_VENDOR_ID_BTC, USB_DEVICE_ID_BTC_EMPREX_REMOTE) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_TOPSEED2, USB_DEVICE_ID_TOPSEED2_RF_COMBO) },
{ }
};
MODULE_DEVICE_TABLE(hid, ts_devices);
diff --git a/drivers/hid/hid-wacom.c b/drivers/hid/hid-wacom.c
index 1e051f1171e..807dcd1555a 100644
--- a/drivers/hid/hid-wacom.c
+++ b/drivers/hid/hid-wacom.c
@@ -436,7 +436,7 @@ static void wacom_remove(struct hid_device *hdev)
static const struct hid_device_id wacom_devices[] = {
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_GRAPHIRE_BLUETOOTH) },
- { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS4_BLUETOOTH) },
+
{ }
};
MODULE_DEVICE_TABLE(hid, wacom_devices);
diff --git a/drivers/hid/hidraw.c b/drivers/hid/hidraw.c
index 3ccd4785067..47d70c523d9 100644
--- a/drivers/hid/hidraw.c
+++ b/drivers/hid/hidraw.c
@@ -46,7 +46,6 @@ static ssize_t hidraw_read(struct file *file, char __user *buffer, size_t count,
{
struct hidraw_list *list = file->private_data;
int ret = 0, len;
- char *report;
DECLARE_WAITQUEUE(wait, current);
mutex_lock(&list->read_mutex);
@@ -84,7 +83,6 @@ static ssize_t hidraw_read(struct file *file, char __user *buffer, size_t count,
if (ret)
goto out;
- report = list->buffer[list->tail].value;
len = list->buffer[list->tail].len > count ?
count : list->buffer[list->tail].len;
diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c
index 5f5aa39b398..2643d314762 100644
--- a/drivers/hid/usbhid/hid-quirks.c
+++ b/drivers/hid/usbhid/hid-quirks.c
@@ -75,6 +75,8 @@ static const struct hid_blacklist {
{ USB_VENDOR_ID_WISEGROUP_LTD, USB_DEVICE_ID_SMARTJOY_DUAL_PLUS, HID_QUIRK_NOGET | HID_QUIRK_MULTI_INPUT },
{ USB_VENDOR_ID_WISEGROUP_LTD2, USB_DEVICE_ID_SMARTJOY_DUAL_PLUS, HID_QUIRK_NOGET | HID_QUIRK_MULTI_INPUT },
+ { USB_VENDOR_ID_PI_ENGINEERING, USB_DEVICE_ID_PI_ENGINEERING_VEC_USB_FOOTPEDAL, HID_QUIRK_HIDINPUT_FORCE },
+
{ 0, 0 }
};
diff --git a/drivers/hid/usbhid/hiddev.c b/drivers/hid/usbhid/hiddev.c
index c24d2fa3e3b..254a003af04 100644
--- a/drivers/hid/usbhid/hiddev.c
+++ b/drivers/hid/usbhid/hiddev.c
@@ -67,7 +67,7 @@ struct hiddev_list {
struct mutex thread_lock;
};
-static struct hiddev *hiddev_table[HIDDEV_MINORS];
+static struct usb_driver hiddev_driver;
/*
* Find a report, given the report's type and ID. The ID can be specified
@@ -265,22 +265,19 @@ static int hiddev_release(struct inode * inode, struct file * file)
static int hiddev_open(struct inode *inode, struct file *file)
{
struct hiddev_list *list;
- int res, i;
-
- /* See comment in hiddev_connect() for BKL explanation */
- lock_kernel();
- i = iminor(inode) - HIDDEV_MINOR_BASE;
+ struct usb_interface *intf;
+ struct hiddev *hiddev;
+ int res;
- if (i >= HIDDEV_MINORS || i < 0 || !hiddev_table[i])
+ intf = usb_find_interface(&hiddev_driver, iminor(inode));
+ if (!intf)
return -ENODEV;
+ hiddev = usb_get_intfdata(intf);
if (!(list = kzalloc(sizeof(struct hiddev_list), GFP_KERNEL)))
return -ENOMEM;
mutex_init(&list->thread_lock);
-
- list->hiddev = hiddev_table[i];
-
-
+ list->hiddev = hiddev;
file->private_data = list;
/*
@@ -289,7 +286,7 @@ static int hiddev_open(struct inode *inode, struct file *file)
*/
if (list->hiddev->exist) {
if (!list->hiddev->open++) {
- res = usbhid_open(hiddev_table[i]->hid);
+ res = usbhid_open(hiddev->hid);
if (res < 0) {
res = -EIO;
goto bail;
@@ -301,12 +298,12 @@ static int hiddev_open(struct inode *inode, struct file *file)
}
spin_lock_irq(&list->hiddev->list_lock);
- list_add_tail(&list->node, &hiddev_table[i]->list);
+ list_add_tail(&list->node, &hiddev->list);
spin_unlock_irq(&list->hiddev->list_lock);
if (!list->hiddev->open++)
if (list->hiddev->exist) {
- struct hid_device *hid = hiddev_table[i]->hid;
+ struct hid_device *hid = hiddev->hid;
res = usbhid_get_power(hid);
if (res < 0) {
res = -EIO;
@@ -314,13 +311,10 @@ static int hiddev_open(struct inode *inode, struct file *file)
}
usbhid_open(hid);
}
-
- unlock_kernel();
return 0;
bail:
file->private_data = NULL;
kfree(list);
- unlock_kernel();
return res;
}
@@ -894,37 +888,14 @@ int hiddev_connect(struct hid_device *hid, unsigned int force)
hid->hiddev = hiddev;
hiddev->hid = hid;
hiddev->exist = 1;
-
- /*
- * BKL here is used to avoid race after usb_register_dev().
- * Once the device node has been created, open() could happen on it.
- * The code below will then fail, as hiddev_table hasn't been
- * updated.
- *
- * The obvious fix -- introducing mutex to guard hiddev_table[]
- * doesn't work, as usb_open() and usb_register_dev() both take
- * minor_rwsem, thus we'll have ABBA deadlock.
- *
- * Before BKL pushdown, usb_open() had been acquiring it in right
- * order, so _open() was safe to use it to protect from this race.
- * Now the order is different, but AB-BA deadlock still doesn't occur
- * as BKL is dropped on schedule() (i.e. while sleeping on
- * minor_rwsem). Fugly.
- */
- lock_kernel();
+ usb_set_intfdata(usbhid->intf, usbhid);
retval = usb_register_dev(usbhid->intf, &hiddev_class);
if (retval) {
err_hid("Not able to get a minor for this device.");
hid->hiddev = NULL;
- unlock_kernel();
kfree(hiddev);
return -1;
- } else {
- hid->minor = usbhid->intf->minor;
- hiddev_table[usbhid->intf->minor - HIDDEV_MINOR_BASE] = hiddev;
}
- unlock_kernel();
-
return 0;
}
@@ -942,7 +913,6 @@ void hiddev_disconnect(struct hid_device *hid)
hiddev->exist = 0;
mutex_unlock(&hiddev->existancelock);
- hiddev_table[hiddev->hid->minor - HIDDEV_MINOR_BASE] = NULL;
usb_deregister_dev(usbhid->intf, &hiddev_class);
if (hiddev->open) {
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index e19cf8eb6cc..4d382ae5309 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -407,6 +407,13 @@ config SENSORS_CORETEMP
sensor inside your CPU. Most of the family 6 CPUs
are supported. Check documentation/driver for details.
+config SENSORS_PKGTEMP
+ tristate "Intel processor package temperature sensor"
+ depends on X86 && PCI && EXPERIMENTAL
+ help
+ If you say yes here you get support for the package level temperature
+ sensor inside your CPU. Check documentation/driver for details.
+
config SENSORS_IBMAEM
tristate "IBM Active Energy Manager temperature/power sensors and control"
select IPMI_SI
@@ -446,6 +453,16 @@ config SENSORS_IT87
This driver can also be built as a module. If so, the module
will be called it87.
+config SENSORS_JZ4740
+ tristate "Ingenic JZ4740 SoC ADC driver"
+ depends on MACH_JZ4740 && MFD_JZ4740_ADC
+ help
+ If you say yes here you get support for reading adc values from the ADCIN
+ pin on Ingenic JZ4740 SoC based boards.
+
+ This driver can also be build as a module. If so, the module will be
+ called jz4740-hwmon.
+
config SENSORS_LM63
tristate "National Semiconductor LM63 and LM64"
depends on I2C
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
index 2138ceb1a71..9103bd6ea73 100644
--- a/drivers/hwmon/Makefile
+++ b/drivers/hwmon/Makefile
@@ -39,6 +39,7 @@ obj-$(CONFIG_SENSORS_AMS) += ams/
obj-$(CONFIG_SENSORS_ASC7621) += asc7621.o
obj-$(CONFIG_SENSORS_ATXP1) += atxp1.o
obj-$(CONFIG_SENSORS_CORETEMP) += coretemp.o
+obj-$(CONFIG_SENSORS_PKGTEMP) += pkgtemp.o
obj-$(CONFIG_SENSORS_DME1737) += dme1737.o
obj-$(CONFIG_SENSORS_DS1621) += ds1621.o
obj-$(CONFIG_SENSORS_EMC1403) += emc1403.o
@@ -55,6 +56,7 @@ obj-$(CONFIG_SENSORS_I5K_AMB) += i5k_amb.o
obj-$(CONFIG_SENSORS_IBMAEM) += ibmaem.o
obj-$(CONFIG_SENSORS_IBMPEX) += ibmpex.o
obj-$(CONFIG_SENSORS_IT87) += it87.o
+obj-$(CONFIG_SENSORS_JZ4740) += jz4740-hwmon.o
obj-$(CONFIG_SENSORS_K8TEMP) += k8temp.o
obj-$(CONFIG_SENSORS_K10TEMP) += k10temp.o
obj-$(CONFIG_SENSORS_LIS3LV02D) += lis3lv02d.o hp_accel.o
diff --git a/drivers/hwmon/jz4740-hwmon.c b/drivers/hwmon/jz4740-hwmon.c
new file mode 100644
index 00000000000..1c8b3d9e205
--- /dev/null
+++ b/drivers/hwmon/jz4740-hwmon.c
@@ -0,0 +1,230 @@
+/*
+ * Copyright (C) 2009-2010, Lars-Peter Clausen <lars@metafoo.de>
+ * JZ4740 SoC HWMON 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.
+ *
+ * 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/err.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+#include <linux/completion.h>
+#include <linux/mfd/core.h>
+
+#include <linux/hwmon.h>
+
+struct jz4740_hwmon {
+ struct resource *mem;
+ void __iomem *base;
+
+ int irq;
+
+ struct mfd_cell *cell;
+ struct device *hwmon;
+
+ struct completion read_completion;
+
+ struct mutex lock;
+};
+
+static ssize_t jz4740_hwmon_show_name(struct device *dev,
+ struct device_attribute *dev_attr, char *buf)
+{
+ return sprintf(buf, "jz4740\n");
+}
+
+static irqreturn_t jz4740_hwmon_irq(int irq, void *data)
+{
+ struct jz4740_hwmon *hwmon = data;
+
+ complete(&hwmon->read_completion);
+ return IRQ_HANDLED;
+}
+
+static ssize_t jz4740_hwmon_read_adcin(struct device *dev,
+ struct device_attribute *dev_attr, char *buf)
+{
+ struct jz4740_hwmon *hwmon = dev_get_drvdata(dev);
+ struct completion *completion = &hwmon->read_completion;
+ unsigned long t;
+ unsigned long val;
+ int ret;
+
+ mutex_lock(&hwmon->lock);
+
+ INIT_COMPLETION(*completion);
+
+ enable_irq(hwmon->irq);
+ hwmon->cell->enable(to_platform_device(dev));
+
+ t = wait_for_completion_interruptible_timeout(completion, HZ);
+
+ if (t > 0) {
+ val = readw(hwmon->base) & 0xfff;
+ val = (val * 3300) >> 12;
+ ret = sprintf(buf, "%lu\n", val);
+ } else {
+ ret = t ? t : -ETIMEDOUT;
+ }
+
+ hwmon->cell->disable(to_platform_device(dev));
+ disable_irq(hwmon->irq);
+
+ mutex_unlock(&hwmon->lock);
+
+ return ret;
+}
+
+static DEVICE_ATTR(name, S_IRUGO, jz4740_hwmon_show_name, NULL);
+static DEVICE_ATTR(in0_input, S_IRUGO, jz4740_hwmon_read_adcin, NULL);
+
+static struct attribute *jz4740_hwmon_attributes[] = {
+ &dev_attr_name.attr,
+ &dev_attr_in0_input.attr,
+ NULL
+};
+
+static const struct attribute_group jz4740_hwmon_attr_group = {
+ .attrs = jz4740_hwmon_attributes,
+};
+
+static int __devinit jz4740_hwmon_probe(struct platform_device *pdev)
+{
+ int ret;
+ struct jz4740_hwmon *hwmon;
+
+ hwmon = kmalloc(sizeof(*hwmon), GFP_KERNEL);
+ if (!hwmon) {
+ dev_err(&pdev->dev, "Failed to allocate driver structure\n");
+ return -ENOMEM;
+ }
+
+ hwmon->cell = pdev->dev.platform_data;
+
+ hwmon->irq = platform_get_irq(pdev, 0);
+ if (hwmon->irq < 0) {
+ ret = hwmon->irq;
+ dev_err(&pdev->dev, "Failed to get platform irq: %d\n", ret);
+ goto err_free;
+ }
+
+ hwmon->mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!hwmon->mem) {
+ ret = -ENOENT;
+ dev_err(&pdev->dev, "Failed to get platform mmio resource\n");
+ goto err_free;
+ }
+
+ hwmon->mem = request_mem_region(hwmon->mem->start,
+ resource_size(hwmon->mem), pdev->name);
+ if (!hwmon->mem) {
+ ret = -EBUSY;
+ dev_err(&pdev->dev, "Failed to request mmio memory region\n");
+ goto err_free;
+ }
+
+ hwmon->base = ioremap_nocache(hwmon->mem->start,
+ resource_size(hwmon->mem));
+ if (!hwmon->base) {
+ ret = -EBUSY;
+ dev_err(&pdev->dev, "Failed to ioremap mmio memory\n");
+ goto err_release_mem_region;
+ }
+
+ init_completion(&hwmon->read_completion);
+ mutex_init(&hwmon->lock);
+
+ platform_set_drvdata(pdev, hwmon);
+
+ ret = request_irq(hwmon->irq, jz4740_hwmon_irq, 0, pdev->name, hwmon);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to request irq: %d\n", ret);
+ goto err_iounmap;
+ }
+ disable_irq(hwmon->irq);
+
+ ret = sysfs_create_group(&pdev->dev.kobj, &jz4740_hwmon_attr_group);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to create sysfs group: %d\n", ret);
+ goto err_free_irq;
+ }
+
+ hwmon->hwmon = hwmon_device_register(&pdev->dev);
+ if (IS_ERR(hwmon->hwmon)) {
+ ret = PTR_ERR(hwmon->hwmon);
+ goto err_remove_file;
+ }
+
+ return 0;
+
+err_remove_file:
+ sysfs_remove_group(&pdev->dev.kobj, &jz4740_hwmon_attr_group);
+err_free_irq:
+ free_irq(hwmon->irq, hwmon);
+err_iounmap:
+ platform_set_drvdata(pdev, NULL);
+ iounmap(hwmon->base);
+err_release_mem_region:
+ release_mem_region(hwmon->mem->start, resource_size(hwmon->mem));
+err_free:
+ kfree(hwmon);
+
+ return ret;
+}
+
+static int __devexit jz4740_hwmon_remove(struct platform_device *pdev)
+{
+ struct jz4740_hwmon *hwmon = platform_get_drvdata(pdev);
+
+ hwmon_device_unregister(hwmon->hwmon);
+ sysfs_remove_group(&pdev->dev.kobj, &jz4740_hwmon_attr_group);
+
+ free_irq(hwmon->irq, hwmon);
+
+ iounmap(hwmon->base);
+ release_mem_region(hwmon->mem->start, resource_size(hwmon->mem));
+
+ platform_set_drvdata(pdev, NULL);
+ kfree(hwmon);
+
+ return 0;
+}
+
+struct platform_driver jz4740_hwmon_driver = {
+ .probe = jz4740_hwmon_probe,
+ .remove = __devexit_p(jz4740_hwmon_remove),
+ .driver = {
+ .name = "jz4740-hwmon",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init jz4740_hwmon_init(void)
+{
+ return platform_driver_register(&jz4740_hwmon_driver);
+}
+module_init(jz4740_hwmon_init);
+
+static void __exit jz4740_hwmon_exit(void)
+{
+ platform_driver_unregister(&jz4740_hwmon_driver);
+}
+module_exit(jz4740_hwmon_exit);
+
+MODULE_DESCRIPTION("JZ4740 SoC HWMON driver");
+MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:jz4740-hwmon");
diff --git a/drivers/hwmon/pkgtemp.c b/drivers/hwmon/pkgtemp.c
new file mode 100644
index 00000000000..74157fcda6e
--- /dev/null
+++ b/drivers/hwmon/pkgtemp.c
@@ -0,0 +1,456 @@
+/*
+ * pkgtemp.c - Linux kernel module for processor package hardware monitoring
+ *
+ * Copyright (C) 2010 Fenghua Yu <fenghua.yu@intel.com>
+ *
+ * Inspired from many hwmon drivers especially coretemp.
+ *
+ * This program is free software; 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/module.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/jiffies.h>
+#include <linux/hwmon.h>
+#include <linux/sysfs.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include <linux/list.h>
+#include <linux/platform_device.h>
+#include <linux/cpu.h>
+#include <linux/pci.h>
+#include <asm/msr.h>
+#include <asm/processor.h>
+
+#define DRVNAME "pkgtemp"
+
+enum { SHOW_TEMP, SHOW_TJMAX, SHOW_TTARGET, SHOW_LABEL, SHOW_NAME };
+
+/*
+ * Functions declaration
+ */
+
+static struct pkgtemp_data *pkgtemp_update_device(struct device *dev);
+
+struct pkgtemp_data {
+ struct device *hwmon_dev;
+ struct mutex update_lock;
+ const char *name;
+ u32 id;
+ u16 phys_proc_id;
+ char valid; /* zero until following fields are valid */
+ unsigned long last_updated; /* in jiffies */
+ int temp;
+ int tjmax;
+ int ttarget;
+ u8 alarm;
+};
+
+/*
+ * Sysfs stuff
+ */
+
+static ssize_t show_name(struct device *dev, struct device_attribute
+ *devattr, char *buf)
+{
+ int ret;
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct pkgtemp_data *data = dev_get_drvdata(dev);
+
+ if (attr->index == SHOW_NAME)
+ ret = sprintf(buf, "%s\n", data->name);
+ else /* show label */
+ ret = sprintf(buf, "physical id %d\n",
+ data->phys_proc_id);
+ return ret;
+}
+
+static ssize_t show_alarm(struct device *dev, struct device_attribute
+ *devattr, char *buf)
+{
+ struct pkgtemp_data *data = pkgtemp_update_device(dev);
+ /* read the Out-of-spec log, never clear */
+ return sprintf(buf, "%d\n", data->alarm);
+}
+
+static ssize_t show_temp(struct device *dev,
+ struct device_attribute *devattr, char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct pkgtemp_data *data = pkgtemp_update_device(dev);
+ int err = 0;
+
+ if (attr->index == SHOW_TEMP)
+ err = data->valid ? sprintf(buf, "%d\n", data->temp) : -EAGAIN;
+ else if (attr->index == SHOW_TJMAX)
+ err = sprintf(buf, "%d\n", data->tjmax);
+ else
+ err = sprintf(buf, "%d\n", data->ttarget);
+ return err;
+}
+
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL, SHOW_TEMP);
+static SENSOR_DEVICE_ATTR(temp1_crit, S_IRUGO, show_temp, NULL, SHOW_TJMAX);
+static SENSOR_DEVICE_ATTR(temp1_max, S_IRUGO, show_temp, NULL, SHOW_TTARGET);
+static DEVICE_ATTR(temp1_crit_alarm, S_IRUGO, show_alarm, NULL);
+static SENSOR_DEVICE_ATTR(temp1_label, S_IRUGO, show_name, NULL, SHOW_LABEL);
+static SENSOR_DEVICE_ATTR(name, S_IRUGO, show_name, NULL, SHOW_NAME);
+
+static struct attribute *pkgtemp_attributes[] = {
+ &sensor_dev_attr_name.dev_attr.attr,
+ &sensor_dev_attr_temp1_label.dev_attr.attr,
+ &dev_attr_temp1_crit_alarm.attr,
+ &sensor_dev_attr_temp1_input.dev_attr.attr,
+ &sensor_dev_attr_temp1_crit.dev_attr.attr,
+ NULL
+};
+
+static const struct attribute_group pkgtemp_group = {
+ .attrs = pkgtemp_attributes,
+};
+
+static struct pkgtemp_data *pkgtemp_update_device(struct device *dev)
+{
+ struct pkgtemp_data *data = dev_get_drvdata(dev);
+ unsigned int cpu;
+ int err;
+
+ mutex_lock(&data->update_lock);
+
+ if (!data->valid || time_after(jiffies, data->last_updated + HZ)) {
+ u32 eax, edx;
+
+ data->valid = 0;
+ cpu = data->id;
+ err = rdmsr_on_cpu(cpu, MSR_IA32_PACKAGE_THERM_STATUS,
+ &eax, &edx);
+ if (!err) {
+ data->alarm = (eax >> 5) & 1;
+ data->temp = data->tjmax - (((eax >> 16)
+ & 0x7f) * 1000);
+ data->valid = 1;
+ } else
+ dev_dbg(dev, "Temperature data invalid (0x%x)\n", eax);
+
+ data->last_updated = jiffies;
+ }
+
+ mutex_unlock(&data->update_lock);
+ return data;
+}
+
+static int get_tjmax(int cpu, struct device *dev)
+{
+ int default_tjmax = 100000;
+ int err;
+ u32 eax, edx;
+ u32 val;
+
+ /* IA32_TEMPERATURE_TARGET contains the TjMax value */
+ err = rdmsr_safe_on_cpu(cpu, MSR_IA32_TEMPERATURE_TARGET, &eax, &edx);
+ if (!err) {
+ val = (eax >> 16) & 0xff;
+ if ((val > 80) && (val < 120)) {
+ dev_info(dev, "TjMax is %d C.\n", val);
+ return val * 1000;
+ }
+ }
+ dev_warn(dev, "Unable to read TjMax from CPU.\n");
+ return default_tjmax;
+}
+
+static int __devinit pkgtemp_probe(struct platform_device *pdev)
+{
+ struct pkgtemp_data *data;
+ int err;
+ u32 eax, edx;
+#ifdef CONFIG_SMP
+ struct cpuinfo_x86 *c = &cpu_data(pdev->id);
+#endif
+
+ data = kzalloc(sizeof(struct pkgtemp_data), GFP_KERNEL);
+ if (!data) {
+ err = -ENOMEM;
+ dev_err(&pdev->dev, "Out of memory\n");
+ goto exit;
+ }
+
+ data->id = pdev->id;
+#ifdef CONFIG_SMP
+ data->phys_proc_id = c->phys_proc_id;
+#endif
+ data->name = "pkgtemp";
+ mutex_init(&data->update_lock);
+
+ /* test if we can access the THERM_STATUS MSR */
+ err = rdmsr_safe_on_cpu(data->id, MSR_IA32_PACKAGE_THERM_STATUS,
+ &eax, &edx);
+ if (err) {
+ dev_err(&pdev->dev,
+ "Unable to access THERM_STATUS MSR, giving up\n");
+ goto exit_free;
+ }
+
+ data->tjmax = get_tjmax(data->id, &pdev->dev);
+ platform_set_drvdata(pdev, data);
+
+ err = rdmsr_safe_on_cpu(data->id, MSR_IA32_TEMPERATURE_TARGET,
+ &eax, &edx);
+ if (err) {
+ dev_warn(&pdev->dev, "Unable to read"
+ " IA32_TEMPERATURE_TARGET MSR\n");
+ } else {
+ data->ttarget = data->tjmax - (((eax >> 8) & 0xff) * 1000);
+ err = device_create_file(&pdev->dev,
+ &sensor_dev_attr_temp1_max.dev_attr);
+ if (err)
+ goto exit_free;
+ }
+
+ err = sysfs_create_group(&pdev->dev.kobj, &pkgtemp_group);
+ if (err)
+ goto exit_free;
+
+ data->hwmon_dev = hwmon_device_register(&pdev->dev);
+ if (IS_ERR(data->hwmon_dev)) {
+ err = PTR_ERR(data->hwmon_dev);
+ dev_err(&pdev->dev, "Class registration failed (%d)\n",
+ err);
+ goto exit_class;
+ }
+
+ return 0;
+
+exit_class:
+ sysfs_remove_group(&pdev->dev.kobj, &pkgtemp_group);
+exit_free:
+ kfree(data);
+exit:
+ return err;
+}
+
+static int __devexit pkgtemp_remove(struct platform_device *pdev)
+{
+ struct pkgtemp_data *data = platform_get_drvdata(pdev);
+
+ hwmon_device_unregister(data->hwmon_dev);
+ sysfs_remove_group(&pdev->dev.kobj, &pkgtemp_group);
+ platform_set_drvdata(pdev, NULL);
+ kfree(data);
+ return 0;
+}
+
+static struct platform_driver pkgtemp_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = DRVNAME,
+ },
+ .probe = pkgtemp_probe,
+ .remove = __devexit_p(pkgtemp_remove),
+};
+
+struct pdev_entry {
+ struct list_head list;
+ struct platform_device *pdev;
+ unsigned int cpu;
+#ifdef CONFIG_SMP
+ u16 phys_proc_id;
+#endif
+};
+
+static LIST_HEAD(pdev_list);
+static DEFINE_MUTEX(pdev_list_mutex);
+
+static int __cpuinit pkgtemp_device_add(unsigned int cpu)
+{
+ int err;
+ struct platform_device *pdev;
+ struct pdev_entry *pdev_entry;
+#ifdef CONFIG_SMP
+ struct cpuinfo_x86 *c = &cpu_data(cpu);
+#endif
+
+ mutex_lock(&pdev_list_mutex);
+
+#ifdef CONFIG_SMP
+ /* Only keep the first entry in each package */
+ list_for_each_entry(pdev_entry, &pdev_list, list) {
+ if (c->phys_proc_id == pdev_entry->phys_proc_id) {
+ err = 0; /* Not an error */
+ goto exit;
+ }
+ }
+#endif
+
+ pdev = platform_device_alloc(DRVNAME, cpu);
+ if (!pdev) {
+ err = -ENOMEM;
+ printk(KERN_ERR DRVNAME ": Device allocation failed\n");
+ goto exit;
+ }
+
+ pdev_entry = kzalloc(sizeof(struct pdev_entry), GFP_KERNEL);
+ if (!pdev_entry) {
+ err = -ENOMEM;
+ goto exit_device_put;
+ }
+
+ err = platform_device_add(pdev);
+ if (err) {
+ printk(KERN_ERR DRVNAME ": Device addition failed (%d)\n",
+ err);
+ goto exit_device_free;
+ }
+
+#ifdef CONFIG_SMP
+ pdev_entry->phys_proc_id = c->phys_proc_id;
+#endif
+ pdev_entry->pdev = pdev;
+ pdev_entry->cpu = cpu;
+ list_add_tail(&pdev_entry->list, &pdev_list);
+ mutex_unlock(&pdev_list_mutex);
+
+ return 0;
+
+exit_device_free:
+ kfree(pdev_entry);
+exit_device_put:
+ platform_device_put(pdev);
+exit:
+ mutex_unlock(&pdev_list_mutex);
+ return err;
+}
+
+#ifdef CONFIG_HOTPLUG_CPU
+static void pkgtemp_device_remove(unsigned int cpu)
+{
+ struct pdev_entry *p, *n;
+ unsigned int i;
+ int err;
+
+ mutex_lock(&pdev_list_mutex);
+ list_for_each_entry_safe(p, n, &pdev_list, list) {
+ if (p->cpu != cpu)
+ continue;
+
+ platform_device_unregister(p->pdev);
+ list_del(&p->list);
+ kfree(p);
+ for_each_cpu(i, cpu_core_mask(cpu)) {
+ if (i != cpu) {
+ err = pkgtemp_device_add(i);
+ if (!err)
+ break;
+ }
+ }
+ break;
+ }
+ mutex_unlock(&pdev_list_mutex);
+}
+
+static int __cpuinit pkgtemp_cpu_callback(struct notifier_block *nfb,
+ unsigned long action, void *hcpu)
+{
+ unsigned int cpu = (unsigned long) hcpu;
+
+ switch (action) {
+ case CPU_ONLINE:
+ case CPU_DOWN_FAILED:
+ pkgtemp_device_add(cpu);
+ break;
+ case CPU_DOWN_PREPARE:
+ pkgtemp_device_remove(cpu);
+ break;
+ }
+ return NOTIFY_OK;
+}
+
+static struct notifier_block pkgtemp_cpu_notifier __refdata = {
+ .notifier_call = pkgtemp_cpu_callback,
+};
+#endif /* !CONFIG_HOTPLUG_CPU */
+
+static int __init pkgtemp_init(void)
+{
+ int i, err = -ENODEV;
+ struct pdev_entry *p, *n;
+
+ /* quick check if we run Intel */
+ if (cpu_data(0).x86_vendor != X86_VENDOR_INTEL)
+ goto exit;
+
+ err = platform_driver_register(&pkgtemp_driver);
+ if (err)
+ goto exit;
+
+ for_each_online_cpu(i) {
+ struct cpuinfo_x86 *c = &cpu_data(i);
+
+ if (!cpu_has(c, X86_FEATURE_PTS))
+ continue;
+
+ err = pkgtemp_device_add(i);
+ if (err)
+ goto exit_devices_unreg;
+ }
+ if (list_empty(&pdev_list)) {
+ err = -ENODEV;
+ goto exit_driver_unreg;
+ }
+
+#ifdef CONFIG_HOTPLUG_CPU
+ register_hotcpu_notifier(&pkgtemp_cpu_notifier);
+#endif
+ return 0;
+
+exit_devices_unreg:
+ mutex_lock(&pdev_list_mutex);
+ list_for_each_entry_safe(p, n, &pdev_list, list) {
+ platform_device_unregister(p->pdev);
+ list_del(&p->list);
+ kfree(p);
+ }
+ mutex_unlock(&pdev_list_mutex);
+exit_driver_unreg:
+ platform_driver_unregister(&pkgtemp_driver);
+exit:
+ return err;
+}
+
+static void __exit pkgtemp_exit(void)
+{
+ struct pdev_entry *p, *n;
+#ifdef CONFIG_HOTPLUG_CPU
+ unregister_hotcpu_notifier(&pkgtemp_cpu_notifier);
+#endif
+ mutex_lock(&pdev_list_mutex);
+ list_for_each_entry_safe(p, n, &pdev_list, list) {
+ platform_device_unregister(p->pdev);
+ list_del(&p->list);
+ kfree(p);
+ }
+ mutex_unlock(&pdev_list_mutex);
+ platform_driver_unregister(&pkgtemp_driver);
+}
+
+MODULE_AUTHOR("Fenghua Yu <fenghua.yu@intel.com>");
+MODULE_DESCRIPTION("Intel processor package temperature monitor");
+MODULE_LICENSE("GPL");
+
+module_init(pkgtemp_init)
+module_exit(pkgtemp_exit)
diff --git a/drivers/hwmon/ultra45_env.c b/drivers/hwmon/ultra45_env.c
index 5da5942cf97..89643261ccd 100644
--- a/drivers/hwmon/ultra45_env.c
+++ b/drivers/hwmon/ultra45_env.c
@@ -311,12 +311,12 @@ static struct of_platform_driver env_driver = {
static int __init env_init(void)
{
- return of_register_driver(&env_driver, &of_bus_type);
+ return of_register_platform_driver(&env_driver);
}
static void __exit env_exit(void)
{
- of_unregister_driver(&env_driver);
+ of_unregister_platform_driver(&env_driver);
}
module_init(env_init);
diff --git a/drivers/i2c/busses/i2c-cpm.c b/drivers/i2c/busses/i2c-cpm.c
index b02b4533651..e591de1bc70 100644
--- a/drivers/i2c/busses/i2c-cpm.c
+++ b/drivers/i2c/busses/i2c-cpm.c
@@ -652,6 +652,7 @@ static int __devinit cpm_i2c_probe(struct of_device *ofdev,
cpm->adap = cpm_ops;
i2c_set_adapdata(&cpm->adap, cpm);
cpm->adap.dev.parent = &ofdev->dev;
+ cpm->adap.dev.of_node = of_node_get(ofdev->dev.of_node);
result = cpm_i2c_setup(cpm);
if (result) {
@@ -676,11 +677,6 @@ static int __devinit cpm_i2c_probe(struct of_device *ofdev,
dev_dbg(&ofdev->dev, "hw routines for %s registered.\n",
cpm->adap.name);
- /*
- * register OF I2C devices
- */
- of_register_i2c_devices(&cpm->adap, ofdev->dev.of_node);
-
return 0;
out_shut:
cpm_i2c_shutdown(cpm);
diff --git a/drivers/i2c/busses/i2c-ibm_iic.c b/drivers/i2c/busses/i2c-ibm_iic.c
index bf344135647..1168d61418c 100644
--- a/drivers/i2c/busses/i2c-ibm_iic.c
+++ b/drivers/i2c/busses/i2c-ibm_iic.c
@@ -745,6 +745,7 @@ static int __devinit iic_probe(struct of_device *ofdev,
/* Register it with i2c layer */
adap = &dev->adap;
adap->dev.parent = &ofdev->dev;
+ adap->dev.of_node = of_node_get(np);
strlcpy(adap->name, "IBM IIC", sizeof(adap->name));
i2c_set_adapdata(adap, dev);
adap->class = I2C_CLASS_HWMON | I2C_CLASS_SPD;
@@ -760,9 +761,6 @@ static int __devinit iic_probe(struct of_device *ofdev,
dev_info(&ofdev->dev, "using %s mode\n",
dev->fast_mode ? "fast (400 kHz)" : "standard (100 kHz)");
- /* Now register all the child nodes */
- of_register_i2c_devices(adap, np);
-
return 0;
error_cleanup:
diff --git a/drivers/i2c/busses/i2c-mpc.c b/drivers/i2c/busses/i2c-mpc.c
index df00eb1f11f..6545d1c99b6 100644
--- a/drivers/i2c/busses/i2c-mpc.c
+++ b/drivers/i2c/busses/i2c-mpc.c
@@ -63,6 +63,7 @@ struct mpc_i2c {
wait_queue_head_t queue;
struct i2c_adapter adap;
int irq;
+ u32 real_clk;
};
struct mpc_i2c_divider {
@@ -96,20 +97,23 @@ static irqreturn_t mpc_i2c_isr(int irq, void *dev_id)
/* 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.
+ * the 9 pulses, 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);
+ int k;
+ u32 delay_val = 1000000 / i2c->real_clk + 1;
+
+ if (delay_val < 2)
+ delay_val = 2;
+
+ for (k = 9; k; k--) {
+ writeccr(i2c, 0);
+ writeccr(i2c, CCR_MSTA | CCR_MTX | CCR_MEN);
+ udelay(delay_val);
+ writeccr(i2c, CCR_MEN);
+ udelay(delay_val << 1);
+ }
}
static int i2c_wait(struct mpc_i2c *i2c, unsigned timeout, int writing)
@@ -190,15 +194,18 @@ static const struct mpc_i2c_divider mpc_i2c_dividers_52xx[] __devinitconst = {
};
static int __devinit mpc_i2c_get_fdr_52xx(struct device_node *node, u32 clock,
- int prescaler)
+ int prescaler, u32 *real_clk)
{
const struct mpc_i2c_divider *div = NULL;
unsigned int pvr = mfspr(SPRN_PVR);
u32 divider;
int i;
- if (clock == MPC_I2C_CLOCK_LEGACY)
+ if (clock == MPC_I2C_CLOCK_LEGACY) {
+ /* see below - default fdr = 0x3f -> div = 2048 */
+ *real_clk = mpc5xxx_get_bus_frequency(node) / 2048;
return -EINVAL;
+ }
/* Determine divider value */
divider = mpc5xxx_get_bus_frequency(node) / clock;
@@ -216,7 +223,8 @@ static int __devinit mpc_i2c_get_fdr_52xx(struct device_node *node, u32 clock,
break;
}
- return div ? (int)div->fdr : -EINVAL;
+ *real_clk = mpc5xxx_get_bus_frequency(node) / div->divider;
+ return (int)div->fdr;
}
static void __devinit mpc_i2c_setup_52xx(struct device_node *node,
@@ -231,13 +239,14 @@ static void __devinit mpc_i2c_setup_52xx(struct device_node *node,
return;
}
- ret = mpc_i2c_get_fdr_52xx(node, clock, prescaler);
+ ret = mpc_i2c_get_fdr_52xx(node, clock, prescaler, &i2c->real_clk);
fdr = (ret >= 0) ? ret : 0x3f; /* backward compatibility */
writeb(fdr & 0xff, i2c->base + MPC_I2C_FDR);
if (ret >= 0)
- dev_info(i2c->dev, "clock %d Hz (fdr=%d)\n", clock, fdr);
+ dev_info(i2c->dev, "clock %u Hz (fdr=%d)\n", i2c->real_clk,
+ fdr);
}
#else /* !(CONFIG_PPC_MPC52xx || CONFIG_PPC_MPC512x) */
static void __devinit mpc_i2c_setup_52xx(struct device_node *node,
@@ -334,14 +343,17 @@ static u32 __devinit mpc_i2c_get_sec_cfg_8xxx(void)
}
static int __devinit mpc_i2c_get_fdr_8xxx(struct device_node *node, u32 clock,
- u32 prescaler)
+ u32 prescaler, u32 *real_clk)
{
const struct mpc_i2c_divider *div = NULL;
u32 divider;
int i;
- if (clock == MPC_I2C_CLOCK_LEGACY)
+ if (clock == MPC_I2C_CLOCK_LEGACY) {
+ /* see below - default fdr = 0x1031 -> div = 16 * 3072 */
+ *real_clk = fsl_get_sys_freq() / prescaler / (16 * 3072);
return -EINVAL;
+ }
/* Determine proper divider value */
if (of_device_is_compatible(node, "fsl,mpc8544-i2c"))
@@ -364,6 +376,7 @@ static int __devinit mpc_i2c_get_fdr_8xxx(struct device_node *node, u32 clock,
break;
}
+ *real_clk = fsl_get_sys_freq() / prescaler / div->divider;
return div ? (int)div->fdr : -EINVAL;
}
@@ -380,7 +393,7 @@ static void __devinit mpc_i2c_setup_8xxx(struct device_node *node,
return;
}
- ret = mpc_i2c_get_fdr_8xxx(node, clock, prescaler);
+ ret = mpc_i2c_get_fdr_8xxx(node, clock, prescaler, &i2c->real_clk);
fdr = (ret >= 0) ? ret : 0x1031; /* backward compatibility */
writeb(fdr & 0xff, i2c->base + MPC_I2C_FDR);
@@ -388,7 +401,7 @@ static void __devinit mpc_i2c_setup_8xxx(struct device_node *node,
if (ret >= 0)
dev_info(i2c->dev, "clock %d Hz (dfsrr=%d fdr=%d)\n",
- clock, fdr >> 8, fdr & 0xff);
+ i2c->real_clk, fdr >> 8, fdr & 0xff);
}
#else /* !CONFIG_FSL_SOC */
@@ -500,10 +513,14 @@ static int mpc_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
return -EINTR;
}
if (time_after(jiffies, orig_jiffies + HZ)) {
+ u8 status = readb(i2c->base + MPC_I2C_SR);
+
dev_dbg(i2c->dev, "timeout\n");
- if (readb(i2c->base + MPC_I2C_SR) ==
- (CSR_MCF | CSR_MBB | CSR_RXAK))
+ if ((status & (CSR_MCF | CSR_MBB | CSR_RXAK)) != 0) {
+ writeb(status & ~CSR_MAL,
+ i2c->base + MPC_I2C_SR);
mpc_i2c_fixup(i2c);
+ }
return -EIO;
}
schedule();
@@ -595,18 +612,26 @@ static int __devinit fsl_i2c_probe(struct of_device *op,
mpc_i2c_setup_8xxx(op->dev.of_node, i2c, clock, 0);
}
+ prop = of_get_property(op->dev.of_node, "fsl,timeout", &plen);
+ if (prop && plen == sizeof(u32)) {
+ mpc_ops.timeout = *prop * HZ / 1000000;
+ if (mpc_ops.timeout < 5)
+ mpc_ops.timeout = 5;
+ }
+ dev_info(i2c->dev, "timeout %u us\n", mpc_ops.timeout * 1000000 / HZ);
+
dev_set_drvdata(&op->dev, i2c);
i2c->adap = mpc_ops;
i2c_set_adapdata(&i2c->adap, i2c);
i2c->adap.dev.parent = &op->dev;
+ i2c->adap.dev.of_node = of_node_get(op->dev.of_node);
result = i2c_add_adapter(&i2c->adap);
if (result < 0) {
dev_err(i2c->dev, "failed to add adapter\n");
goto fail_add;
}
- of_register_i2c_devices(&i2c->adap, op->dev.of_node);
return result;
diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c
index 0815e10da7c..df937df845e 100644
--- a/drivers/i2c/i2c-core.c
+++ b/drivers/i2c/i2c-core.c
@@ -30,6 +30,8 @@
#include <linux/init.h>
#include <linux/idr.h>
#include <linux/mutex.h>
+#include <linux/of_i2c.h>
+#include <linux/of_device.h>
#include <linux/completion.h>
#include <linux/hardirq.h>
#include <linux/irqflags.h>
@@ -70,6 +72,10 @@ static int i2c_device_match(struct device *dev, struct device_driver *drv)
if (!client)
return 0;
+ /* Attempt an OF style match */
+ if (of_driver_match_device(dev, drv))
+ return 1;
+
driver = to_i2c_driver(drv);
/* match on an id table if there is one */
if (driver->id_table)
@@ -790,6 +796,9 @@ static int i2c_register_adapter(struct i2c_adapter *adap)
if (adap->nr < __i2c_first_dynamic_bus_num)
i2c_scan_static_board_info(adap);
+ /* Register devices from the device tree */
+ of_i2c_register_devices(adap);
+
/* Notify drivers */
mutex_lock(&core_lock);
dummy = bus_for_each_drv(&i2c_bus_type, NULL, adap,
diff --git a/drivers/ide/ide-cs.c b/drivers/ide/ide-cs.c
index 0b7815d2581..2a4cb9c18f0 100644
--- a/drivers/ide/ide-cs.c
+++ b/drivers/ide/ide-cs.c
@@ -43,7 +43,6 @@
#include <asm/io.h>
#include <asm/system.h>
-#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/cistpl.h>
#include <pcmcia/ds.h>
@@ -98,9 +97,8 @@ static int ide_probe(struct pcmcia_device *link)
info->p_dev = link;
link->priv = info;
- link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
- link->io.Attributes2 = IO_DATA_PATH_WIDTH_8;
- link->io.IOAddrLines = 3;
+ link->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO;
+ link->resource[1]->flags |= IO_DATA_PATH_WIDTH_8;
link->conf.Attributes = CONF_ENABLE_IRQ;
link->conf.IntType = INT_MEMORY_AND_IO;
@@ -229,24 +227,27 @@ static int pcmcia_check_one_config(struct pcmcia_device *pdev,
if ((cfg->io.nwin > 0) || (dflt->io.nwin > 0)) {
cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt->io;
+ pdev->io_lines = io->flags & CISTPL_IO_LINES_MASK;
+
pdev->conf.ConfigIndex = cfg->index;
- pdev->io.BasePort1 = io->win[0].base;
- pdev->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK;
- if (!(io->flags & CISTPL_IO_16BIT))
- pdev->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
+ pdev->resource[0]->start = io->win[0].base;
+ if (!(io->flags & CISTPL_IO_16BIT)) {
+ pdev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH;
+ pdev->resource[0]->flags |= IO_DATA_PATH_WIDTH_8;
+ }
if (io->nwin == 2) {
- pdev->io.NumPorts1 = 8;
- pdev->io.BasePort2 = io->win[1].base;
- pdev->io.NumPorts2 = (stk->is_kme) ? 2 : 1;
- if (pcmcia_request_io(pdev, &pdev->io) != 0)
+ pdev->resource[0]->end = 8;
+ pdev->resource[1]->start = io->win[1].base;
+ pdev->resource[1]->end = (stk->is_kme) ? 2 : 1;
+ if (pcmcia_request_io(pdev) != 0)
return -ENODEV;
- stk->ctl_base = pdev->io.BasePort2;
+ stk->ctl_base = pdev->resource[1]->start;
} else if ((io->nwin == 1) && (io->win[0].len >= 16)) {
- pdev->io.NumPorts1 = io->win[0].len;
- pdev->io.NumPorts2 = 0;
- if (pcmcia_request_io(pdev, &pdev->io) != 0)
+ pdev->resource[0]->end = io->win[0].len;
+ pdev->resource[1]->end = 0;
+ if (pcmcia_request_io(pdev) != 0)
return -ENODEV;
- stk->ctl_base = pdev->io.BasePort1 + 0x0e;
+ stk->ctl_base = pdev->resource[0]->start + 0x0e;
} else
return -ENODEV;
/* If we've got this far, we're done */
@@ -280,7 +281,7 @@ static int ide_config(struct pcmcia_device *link)
if (pcmcia_loop_config(link, pcmcia_check_one_config, stk))
goto failed; /* No suitable config found */
}
- io_base = link->io.BasePort1;
+ io_base = link->resource[0]->start;
ctl_base = stk->ctl_base;
if (!link->irq)
@@ -297,7 +298,7 @@ static int ide_config(struct pcmcia_device *link)
outb(0x81, ctl_base+1);
host = idecs_register(io_base, ctl_base, link->irq, link);
- if (host == NULL && link->io.NumPorts1 == 0x20) {
+ if (host == NULL && resource_size(link->resource[0]) == 0x20) {
outb(0x02, ctl_base + 0x10);
host = idecs_register(io_base + 0x10, ctl_base + 0x10,
link->irq, link);
diff --git a/drivers/ide/ide-gd.c b/drivers/ide/ide-gd.c
index c102d23d9b3..79399534782 100644
--- a/drivers/ide/ide-gd.c
+++ b/drivers/ide/ide-gd.c
@@ -92,7 +92,7 @@ static void ide_disk_release(struct device *dev)
/*
* On HPA drives the capacity needs to be
- * reinitilized on resume otherwise the disk
+ * reinitialized on resume otherwise the disk
* can not be used and a hard reset is required
*/
static void ide_gd_resume(ide_drive_t *drive)
diff --git a/drivers/idle/intel_idle.c b/drivers/idle/intel_idle.c
index 54f0fb4cd5d..03d202b1ff2 100755
--- a/drivers/idle/intel_idle.c
+++ b/drivers/idle/intel_idle.c
@@ -231,7 +231,7 @@ static int intel_idle(struct cpuidle_device *dev, struct cpuidle_state *state)
stop_critical_timings();
#ifndef MODULE
- trace_power_start(POWER_CSTATE, (eax >> 4) + 1);
+ trace_power_start(POWER_CSTATE, (eax >> 4) + 1, cpu);
#endif
if (!need_resched()) {
diff --git a/drivers/ieee1394/dv1394.c b/drivers/ieee1394/dv1394.c
index adaefabc40e..c5a031b79d0 100644
--- a/drivers/ieee1394/dv1394.c
+++ b/drivers/ieee1394/dv1394.c
@@ -172,7 +172,7 @@ static DEFINE_SPINLOCK(dv1394_cards_lock);
static inline struct video_card* file_to_video_card(struct file *file)
{
- return (struct video_card*) file->private_data;
+ return file->private_data;
}
/*** FRAME METHODS *********************************************************/
@@ -610,7 +610,7 @@ static void frame_prepare(struct video_card *video, unsigned int this_frame)
} else {
u32 transmit_sec, transmit_cyc;
- u32 ts_cyc, ts_off;
+ u32 ts_cyc;
/* DMA is stopped, so this is the very first frame */
video->active_frame = this_frame;
@@ -636,7 +636,6 @@ static void frame_prepare(struct video_card *video, unsigned int this_frame)
transmit_sec += transmit_cyc/8000;
transmit_cyc %= 8000;
- ts_off = ct_off;
ts_cyc = transmit_cyc + 3;
ts_cyc %= 8000;
@@ -1784,7 +1783,7 @@ static int dv1394_open(struct inode *inode, struct file *file)
struct video_card *video = NULL;
if (file->private_data) {
- video = (struct video_card*) file->private_data;
+ video = file->private_data;
} else {
/* look up the card by ID */
@@ -2004,7 +2003,7 @@ static void ir_tasklet_func(unsigned long data)
int sof=0; /* start-of-frame flag */
struct frame *f;
- u16 packet_length, packet_time;
+ u16 packet_length;
int i, dbc=0;
struct DMA_descriptor_block *block = NULL;
u16 xferstatus;
@@ -2024,11 +2023,6 @@ static void ir_tasklet_func(unsigned long data)
sizeof(struct packet));
packet_length = le16_to_cpu(p->data_length);
- packet_time = le16_to_cpu(p->timestamp);
-
- irq_printk("received packet %02d, timestamp=%04x, length=%04x, sof=%02x%02x\n", video->current_packet,
- packet_time, packet_length,
- p->data[0], p->data[1]);
/* get the descriptor based on packet_buffer cursor */
f = video->frames[video->current_packet / MAX_PACKETS];
@@ -2320,7 +2314,6 @@ static void dv1394_add_host(struct hpsb_host *host)
static void dv1394_host_reset(struct hpsb_host *host)
{
- struct ti_ohci *ohci;
struct video_card *video = NULL, *tmp_vid;
unsigned long flags;
@@ -2328,9 +2321,6 @@ static void dv1394_host_reset(struct hpsb_host *host)
if (strcmp(host->driver->name, OHCI1394_DRIVER_NAME))
return;
- ohci = (struct ti_ohci *)host->hostdata;
-
-
/* find the corresponding video_cards */
spin_lock_irqsave(&dv1394_cards_lock, flags);
list_for_each_entry(tmp_vid, &dv1394_cards, list) {
diff --git a/drivers/ieee1394/eth1394.c b/drivers/ieee1394/eth1394.c
index a4e9dcb6d4a..bc289e367e3 100644
--- a/drivers/ieee1394/eth1394.c
+++ b/drivers/ieee1394/eth1394.c
@@ -1258,7 +1258,6 @@ static void ether1394_iso(struct hpsb_iso *iso)
char *buf;
struct eth1394_host_info *hi;
struct net_device *dev;
- struct eth1394_priv *priv;
unsigned int len;
u32 specifier_id;
u16 source_id;
@@ -1288,8 +1287,6 @@ static void ether1394_iso(struct hpsb_iso *iso)
(be32_to_cpu(data[1]) & 0xff000000) >> 24;
source_id = be32_to_cpu(data[0]) >> 16;
- priv = netdev_priv(dev);
-
if (info->channel != (iso->host->csr.broadcast_channel & 0x3f)
|| specifier_id != ETHER1394_GASP_SPECIFIER_ID) {
/* This packet is not for us */
diff --git a/drivers/ieee1394/raw1394.c b/drivers/ieee1394/raw1394.c
index b563d5e9fa2..f3401427404 100644
--- a/drivers/ieee1394/raw1394.c
+++ b/drivers/ieee1394/raw1394.c
@@ -440,7 +440,7 @@ static struct pending_request *next_complete_req(struct file_info *fi)
static ssize_t raw1394_read(struct file *file, char __user * buffer,
size_t count, loff_t * offset_is_ignored)
{
- struct file_info *fi = (struct file_info *)file->private_data;
+ struct file_info *fi = file->private_data;
struct pending_request *req;
ssize_t ret;
@@ -1015,7 +1015,7 @@ static int arm_write(struct hpsb_host *host, int nodeid, int destid,
struct arm_addr *arm_addr = NULL;
struct arm_request *arm_req = NULL;
struct arm_response *arm_resp = NULL;
- int found = 0, size = 0, rcode = -1, length_conflict = 0;
+ int found = 0, size = 0, rcode = -1;
struct arm_request_response *arm_req_resp = NULL;
DBGMSG("arm_write called by node: %X "
@@ -1054,7 +1054,6 @@ static int arm_write(struct hpsb_host *host, int nodeid, int destid,
}
if (arm_addr->rec_length < length) {
DBGMSG("arm_write blocklength too big -> rcode_data_error");
- length_conflict = 1;
rcode = RCODE_DATA_ERROR; /* hardware error, data is unavailable */
}
if (rcode == -1) {
@@ -2245,7 +2244,7 @@ static int state_connected(struct file_info *fi, struct pending_request *req)
static ssize_t raw1394_write(struct file *file, const char __user * buffer,
size_t count, loff_t * offset_is_ignored)
{
- struct file_info *fi = (struct file_info *)file->private_data;
+ struct file_info *fi = file->private_data;
struct pending_request *req;
ssize_t retval = -EBADFD;
diff --git a/drivers/ieee1394/sbp2.c b/drivers/ieee1394/sbp2.c
index 4565cb5d3d1..d6e251a300c 100644
--- a/drivers/ieee1394/sbp2.c
+++ b/drivers/ieee1394/sbp2.c
@@ -1350,12 +1350,11 @@ static void sbp2_parse_unit_directory(struct sbp2_lu *lu,
struct csr1212_keyval *kv;
struct csr1212_dentry *dentry;
u64 management_agent_addr;
- u32 unit_characteristics, firmware_revision, model;
+ u32 firmware_revision, model;
unsigned workarounds;
int i;
management_agent_addr = 0;
- unit_characteristics = 0;
firmware_revision = SBP2_ROM_VALUE_MISSING;
model = ud->flags & UNIT_DIRECTORY_MODEL_ID ?
ud->model_id : SBP2_ROM_VALUE_MISSING;
@@ -1372,17 +1371,15 @@ static void sbp2_parse_unit_directory(struct sbp2_lu *lu,
lu->lun = ORB_SET_LUN(kv->value.immediate);
break;
- case SBP2_UNIT_CHARACTERISTICS_KEY:
- /* FIXME: This is ignored so far.
- * See SBP-2 clause 7.4.8. */
- unit_characteristics = kv->value.immediate;
- break;
case SBP2_FIRMWARE_REVISION_KEY:
firmware_revision = kv->value.immediate;
break;
default:
+ /* FIXME: Check for SBP2_UNIT_CHARACTERISTICS_KEY
+ * mgt_ORB_timeout and ORB_size, SBP-2 clause 7.4.8. */
+
/* FIXME: Check for SBP2_DEVICE_TYPE_AND_LUN_KEY.
* Its "ordered" bit has consequences for command ORB
* list handling. See SBP-2 clauses 4.6, 7.4.11, 10.2 */
diff --git a/drivers/ieee1394/video1394.c b/drivers/ieee1394/video1394.c
index a42bd6893bc..5c74f796d7f 100644
--- a/drivers/ieee1394/video1394.c
+++ b/drivers/ieee1394/video1394.c
@@ -720,7 +720,7 @@ static inline unsigned video1394_buffer_state(struct dma_iso_ctx *d,
static long video1394_ioctl(struct file *file,
unsigned int cmd, unsigned long arg)
{
- struct file_ctx *ctx = (struct file_ctx *)file->private_data;
+ struct file_ctx *ctx = file->private_data;
struct ti_ohci *ohci = ctx->ohci;
unsigned long flags;
void __user *argp = (void __user *)arg;
@@ -1045,14 +1045,9 @@ static long video1394_ioctl(struct file *file,
if (get_user(qv, &p->packet_sizes))
return -EFAULT;
- psizes = kmalloc(buf_size, GFP_KERNEL);
- if (!psizes)
- return -ENOMEM;
-
- if (copy_from_user(psizes, qv, buf_size)) {
- kfree(psizes);
- return -EFAULT;
- }
+ psizes = memdup_user(qv, buf_size);
+ if (IS_ERR(psizes))
+ return PTR_ERR(psizes);
}
spin_lock_irqsave(&d->lock,flags);
@@ -1177,7 +1172,7 @@ static long video1394_ioctl(struct file *file,
static int video1394_mmap(struct file *file, struct vm_area_struct *vma)
{
- struct file_ctx *ctx = (struct file_ctx *)file->private_data;
+ struct file_ctx *ctx = file->private_data;
if (ctx->current_ctx == NULL) {
PRINT(KERN_ERR, ctx->ohci->host->id,
@@ -1244,7 +1239,7 @@ static int video1394_open(struct inode *inode, struct file *file)
static int video1394_release(struct inode *inode, struct file *file)
{
- struct file_ctx *ctx = (struct file_ctx *)file->private_data;
+ struct file_ctx *ctx = file->private_data;
struct ti_ohci *ohci = ctx->ohci;
struct list_head *lh, *next;
u64 mask;
diff --git a/drivers/infiniband/core/addr.c b/drivers/infiniband/core/addr.c
index 0b926e45afe..a5ea1bce968 100644
--- a/drivers/infiniband/core/addr.c
+++ b/drivers/infiniband/core/addr.c
@@ -215,7 +215,7 @@ static int addr4_resolve(struct sockaddr_in *src_in,
neigh = neigh_lookup(&arp_tbl, &rt->rt_gateway, rt->idev->dev);
if (!neigh || !(neigh->nud_state & NUD_VALID)) {
- neigh_event_send(rt->u.dst.neighbour, NULL);
+ neigh_event_send(rt->dst.neighbour, NULL);
ret = -ENODATA;
if (neigh)
goto release;
diff --git a/drivers/infiniband/core/cm.c b/drivers/infiniband/core/cm.c
index ad63b79afac..64e0903091a 100644
--- a/drivers/infiniband/core/cm.c
+++ b/drivers/infiniband/core/cm.c
@@ -2409,10 +2409,12 @@ int ib_send_cm_mra(struct ib_cm_id *cm_id,
msg_response = CM_MSG_RESPONSE_REP;
break;
case IB_CM_ESTABLISHED:
- cm_state = cm_id->state;
- lap_state = IB_CM_MRA_LAP_SENT;
- msg_response = CM_MSG_RESPONSE_OTHER;
- break;
+ if (cm_id->lap_state == IB_CM_LAP_RCVD) {
+ cm_state = cm_id->state;
+ lap_state = IB_CM_MRA_LAP_SENT;
+ msg_response = CM_MSG_RESPONSE_OTHER;
+ break;
+ }
default:
ret = -EINVAL;
goto error1;
diff --git a/drivers/infiniband/core/user_mad.c b/drivers/infiniband/core/user_mad.c
index 6babb72b39f..5fa85690951 100644
--- a/drivers/infiniband/core/user_mad.c
+++ b/drivers/infiniband/core/user_mad.c
@@ -1085,7 +1085,6 @@ err_cdev:
static void ib_umad_kill_port(struct ib_umad_port *port)
{
struct ib_umad_file *file;
- int already_dead;
int id;
dev_set_drvdata(port->dev, NULL);
@@ -1103,7 +1102,6 @@ static void ib_umad_kill_port(struct ib_umad_port *port)
list_for_each_entry(file, &port->file_list, port_list) {
mutex_lock(&file->mutex);
- already_dead = file->agents_dead;
file->agents_dead = 1;
mutex_unlock(&file->mutex);
diff --git a/drivers/infiniband/core/verbs.c b/drivers/infiniband/core/verbs.c
index a7da9be43e6..e0fa2223871 100644
--- a/drivers/infiniband/core/verbs.c
+++ b/drivers/infiniband/core/verbs.c
@@ -310,8 +310,8 @@ EXPORT_SYMBOL(ib_create_qp);
static const struct {
int valid;
- enum ib_qp_attr_mask req_param[IB_QPT_RAW_ETY + 1];
- enum ib_qp_attr_mask opt_param[IB_QPT_RAW_ETY + 1];
+ enum ib_qp_attr_mask req_param[IB_QPT_RAW_ETHERTYPE + 1];
+ enum ib_qp_attr_mask opt_param[IB_QPT_RAW_ETHERTYPE + 1];
} qp_state_table[IB_QPS_ERR + 1][IB_QPS_ERR + 1] = {
[IB_QPS_RESET] = {
[IB_QPS_RESET] = { .valid = 1 },
diff --git a/drivers/infiniband/hw/cxgb3/iwch_cm.c b/drivers/infiniband/hw/cxgb3/iwch_cm.c
index ebfb117ba68..d88077a2199 100644
--- a/drivers/infiniband/hw/cxgb3/iwch_cm.c
+++ b/drivers/infiniband/hw/cxgb3/iwch_cm.c
@@ -137,7 +137,7 @@ static void stop_ep_timer(struct iwch_ep *ep)
put_ep(&ep->com);
}
-int iwch_l2t_send(struct t3cdev *tdev, struct sk_buff *skb, struct l2t_entry *l2e)
+static int iwch_l2t_send(struct t3cdev *tdev, struct sk_buff *skb, struct l2t_entry *l2e)
{
int error = 0;
struct cxio_rdev *rdev;
@@ -1364,7 +1364,7 @@ static int pass_accept_req(struct t3cdev *tdev, struct sk_buff *skb, void *ctx)
__func__);
goto reject;
}
- dst = &rt->u.dst;
+ dst = &rt->dst;
l2t = t3_l2t_get(tdev, dst->neighbour, dst->neighbour->dev);
if (!l2t) {
printk(KERN_ERR MOD "%s - failed to allocate l2t entry!\n",
@@ -1932,7 +1932,7 @@ int iwch_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
err = -EHOSTUNREACH;
goto fail3;
}
- ep->dst = &rt->u.dst;
+ ep->dst = &rt->dst;
/* get a l2t entry */
ep->l2t = t3_l2t_get(ep->com.tdev, ep->dst->neighbour,
diff --git a/drivers/infiniband/hw/cxgb3/iwch_qp.c b/drivers/infiniband/hw/cxgb3/iwch_qp.c
index ae47bfd22bd..c64d27bf2c1 100644
--- a/drivers/infiniband/hw/cxgb3/iwch_qp.c
+++ b/drivers/infiniband/hw/cxgb3/iwch_qp.c
@@ -371,7 +371,7 @@ int iwch_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
}
num_wrs = Q_FREECNT(qhp->wq.sq_rptr, qhp->wq.sq_wptr,
qhp->wq.sq_size_log2);
- if (num_wrs <= 0) {
+ if (num_wrs == 0) {
spin_unlock_irqrestore(&qhp->lock, flag);
err = -ENOMEM;
goto out;
@@ -554,7 +554,7 @@ int iwch_bind_mw(struct ib_qp *qp,
}
num_wrs = Q_FREECNT(qhp->wq.sq_rptr, qhp->wq.sq_wptr,
qhp->wq.sq_size_log2);
- if ((num_wrs) <= 0) {
+ if (num_wrs == 0) {
spin_unlock_irqrestore(&qhp->lock, flag);
return -ENOMEM;
}
@@ -816,7 +816,7 @@ static void __flush_qp(struct iwch_qp *qhp, unsigned long *flag)
atomic_inc(&qhp->refcnt);
spin_unlock_irqrestore(&qhp->lock, *flag);
- /* locking heirarchy: cq lock first, then qp lock. */
+ /* locking hierarchy: cq lock first, then qp lock. */
spin_lock_irqsave(&rchp->lock, *flag);
spin_lock(&qhp->lock);
cxio_flush_hw_cq(&rchp->cq);
@@ -827,7 +827,7 @@ static void __flush_qp(struct iwch_qp *qhp, unsigned long *flag)
if (flushed)
(*rchp->ibcq.comp_handler)(&rchp->ibcq, rchp->ibcq.cq_context);
- /* locking heirarchy: cq lock first, then qp lock. */
+ /* locking hierarchy: cq lock first, then qp lock. */
spin_lock_irqsave(&schp->lock, *flag);
spin_lock(&qhp->lock);
cxio_flush_hw_cq(&schp->cq);
diff --git a/drivers/infiniband/hw/cxgb4/cm.c b/drivers/infiniband/hw/cxgb4/cm.c
index 855ee44fdb5..32d352a88d5 100644
--- a/drivers/infiniband/hw/cxgb4/cm.c
+++ b/drivers/infiniband/hw/cxgb4/cm.c
@@ -61,6 +61,10 @@ static char *states[] = {
NULL,
};
+static int dack_mode;
+module_param(dack_mode, int, 0644);
+MODULE_PARM_DESC(dack_mode, "Delayed ack mode (default=0)");
+
int c4iw_max_read_depth = 8;
module_param(c4iw_max_read_depth, int, 0644);
MODULE_PARM_DESC(c4iw_max_read_depth, "Per-connection max ORD/IRD (default=8)");
@@ -469,11 +473,12 @@ static int send_connect(struct c4iw_ep *ep)
__func__);
return -ENOMEM;
}
- set_wr_txq(skb, CPL_PRIORITY_SETUP, ep->txq_idx);
+ set_wr_txq(skb, CPL_PRIORITY_SETUP, ep->ctrlq_idx);
cxgb4_best_mtu(ep->com.dev->rdev.lldi.mtus, ep->mtu, &mtu_idx);
wscale = compute_wscale(rcv_win);
opt0 = KEEP_ALIVE(1) |
+ DELACK(1) |
WND_SCALE(wscale) |
MSS_IDX(mtu_idx) |
L2T_IDX(ep->l2t->idx) |
@@ -780,11 +785,11 @@ static void connect_reply_upcall(struct c4iw_ep *ep, int status)
event.private_data_len = ep->plen;
event.private_data = ep->mpa_pkt + sizeof(struct mpa_message);
}
- if (ep->com.cm_id) {
- PDBG("%s ep %p tid %u status %d\n", __func__, ep,
- ep->hwtid, status);
- ep->com.cm_id->event_handler(ep->com.cm_id, &event);
- }
+
+ PDBG("%s ep %p tid %u status %d\n", __func__, ep,
+ ep->hwtid, status);
+ ep->com.cm_id->event_handler(ep->com.cm_id, &event);
+
if (status < 0) {
ep->com.cm_id->rem_ref(ep->com.cm_id);
ep->com.cm_id = NULL;
@@ -845,8 +850,10 @@ static int update_rx_credits(struct c4iw_ep *ep, u32 credits)
INIT_TP_WR(req, ep->hwtid);
OPCODE_TID(req) = cpu_to_be32(MK_OPCODE_TID(CPL_RX_DATA_ACK,
ep->hwtid));
- req->credit_dack = cpu_to_be32(credits);
- set_wr_txq(skb, CPL_PRIORITY_ACK, ep->txq_idx);
+ req->credit_dack = cpu_to_be32(credits | RX_FORCE_ACK(1) |
+ F_RX_DACK_CHANGE |
+ V_RX_DACK_MODE(dack_mode));
+ set_wr_txq(skb, CPL_PRIORITY_ACK, ep->ctrlq_idx);
c4iw_ofld_send(&ep->com.dev->rdev, skb);
return credits;
}
@@ -1264,6 +1271,7 @@ static void accept_cr(struct c4iw_ep *ep, __be32 peer_ip, struct sk_buff *skb,
cxgb4_best_mtu(ep->com.dev->rdev.lldi.mtus, ep->mtu, &mtu_idx);
wscale = compute_wscale(rcv_win);
opt0 = KEEP_ALIVE(1) |
+ DELACK(1) |
WND_SCALE(wscale) |
MSS_IDX(mtu_idx) |
L2T_IDX(ep->l2t->idx) |
@@ -1287,7 +1295,7 @@ static void accept_cr(struct c4iw_ep *ep, __be32 peer_ip, struct sk_buff *skb,
ep->hwtid));
rpl->opt0 = cpu_to_be64(opt0);
rpl->opt2 = cpu_to_be32(opt2);
- set_wr_txq(skb, CPL_PRIORITY_SETUP, ep->txq_idx);
+ set_wr_txq(skb, CPL_PRIORITY_SETUP, ep->ctrlq_idx);
c4iw_l2t_send(&ep->com.dev->rdev, skb, ep->l2t);
return;
@@ -1344,7 +1352,7 @@ static int pass_accept_req(struct c4iw_dev *dev, struct sk_buff *skb)
u16 rss_qid;
u32 mtu;
int step;
- int txq_idx;
+ int txq_idx, ctrlq_idx;
parent_ep = lookup_stid(t, stid);
PDBG("%s parent ep %p tid %u\n", __func__, parent_ep, hwtid);
@@ -1365,7 +1373,7 @@ static int pass_accept_req(struct c4iw_dev *dev, struct sk_buff *skb)
__func__);
goto reject;
}
- dst = &rt->u.dst;
+ dst = &rt->dst;
if (dst->neighbour->dev->flags & IFF_LOOPBACK) {
pdev = ip_dev_find(&init_net, peer_ip);
BUG_ON(!pdev);
@@ -1376,6 +1384,7 @@ static int pass_accept_req(struct c4iw_dev *dev, struct sk_buff *skb)
smac_idx = (cxgb4_port_viid(pdev) & 0x7F) << 1;
step = dev->rdev.lldi.ntxq / dev->rdev.lldi.nchan;
txq_idx = cxgb4_port_idx(pdev) * step;
+ ctrlq_idx = cxgb4_port_idx(pdev);
step = dev->rdev.lldi.nrxq / dev->rdev.lldi.nchan;
rss_qid = dev->rdev.lldi.rxq_ids[cxgb4_port_idx(pdev) * step];
dev_put(pdev);
@@ -1387,6 +1396,7 @@ static int pass_accept_req(struct c4iw_dev *dev, struct sk_buff *skb)
smac_idx = (cxgb4_port_viid(dst->neighbour->dev) & 0x7F) << 1;
step = dev->rdev.lldi.ntxq / dev->rdev.lldi.nchan;
txq_idx = cxgb4_port_idx(dst->neighbour->dev) * step;
+ ctrlq_idx = cxgb4_port_idx(dst->neighbour->dev);
step = dev->rdev.lldi.nrxq / dev->rdev.lldi.nchan;
rss_qid = dev->rdev.lldi.rxq_ids[
cxgb4_port_idx(dst->neighbour->dev) * step];
@@ -1426,6 +1436,7 @@ static int pass_accept_req(struct c4iw_dev *dev, struct sk_buff *skb)
child_ep->rss_qid = rss_qid;
child_ep->mtu = mtu;
child_ep->txq_idx = txq_idx;
+ child_ep->ctrlq_idx = ctrlq_idx;
PDBG("%s tx_chan %u smac_idx %u rss_qid %u\n", __func__,
tx_chan, smac_idx, rss_qid);
@@ -1473,8 +1484,6 @@ static int peer_close(struct c4iw_dev *dev, struct sk_buff *skb)
int closing = 0;
struct tid_info *t = dev->rdev.lldi.tids;
unsigned int tid = GET_TID(hdr);
- int start_timer = 0;
- int stop_timer = 0;
ep = lookup_tid(t, tid);
PDBG("%s ep %p tid %u\n", __func__, ep, ep->hwtid);
@@ -1511,7 +1520,7 @@ static int peer_close(struct c4iw_dev *dev, struct sk_buff *skb)
wake_up(&ep->com.waitq);
break;
case FPDU_MODE:
- start_timer = 1;
+ start_ep_timer(ep);
__state_set(&ep->com, CLOSING);
closing = 1;
peer_close_upcall(ep);
@@ -1524,7 +1533,7 @@ static int peer_close(struct c4iw_dev *dev, struct sk_buff *skb)
disconnect = 0;
break;
case MORIBUND:
- stop_timer = 1;
+ stop_ep_timer(ep);
if (ep->com.cm_id && ep->com.qp) {
attrs.next_state = C4IW_QP_STATE_IDLE;
c4iw_modify_qp(ep->com.qp->rhp, ep->com.qp,
@@ -1547,10 +1556,6 @@ static int peer_close(struct c4iw_dev *dev, struct sk_buff *skb)
c4iw_modify_qp(ep->com.qp->rhp, ep->com.qp,
C4IW_QP_ATTR_NEXT_STATE, &attrs, 1);
}
- if (start_timer)
- start_ep_timer(ep);
- if (stop_timer)
- stop_ep_timer(ep);
if (disconnect)
c4iw_ep_disconnect(ep, 0, GFP_KERNEL);
if (release)
@@ -1579,7 +1584,6 @@ static int peer_abort(struct c4iw_dev *dev, struct sk_buff *skb)
unsigned long flags;
struct tid_info *t = dev->rdev.lldi.tids;
unsigned int tid = GET_TID(req);
- int stop_timer = 0;
ep = lookup_tid(t, tid);
if (is_neg_adv_abort(req->status)) {
@@ -1594,10 +1598,10 @@ static int peer_abort(struct c4iw_dev *dev, struct sk_buff *skb)
case CONNECTING:
break;
case MPA_REQ_WAIT:
- stop_timer = 1;
+ stop_ep_timer(ep);
break;
case MPA_REQ_SENT:
- stop_timer = 1;
+ stop_ep_timer(ep);
connect_reply_upcall(ep, -ECONNRESET);
break;
case MPA_REP_SENT:
@@ -1621,7 +1625,7 @@ static int peer_abort(struct c4iw_dev *dev, struct sk_buff *skb)
break;
case MORIBUND:
case CLOSING:
- stop_timer = 1;
+ stop_ep_timer(ep);
/*FALLTHROUGH*/
case FPDU_MODE:
if (ep->com.cm_id && ep->com.qp) {
@@ -1667,8 +1671,6 @@ static int peer_abort(struct c4iw_dev *dev, struct sk_buff *skb)
rpl->cmd = CPL_ABORT_NO_RST;
c4iw_ofld_send(&ep->com.dev->rdev, rpl_skb);
out:
- if (stop_timer)
- stop_ep_timer(ep);
if (release)
release_ep_resources(ep);
return 0;
@@ -1683,7 +1685,6 @@ static int close_con_rpl(struct c4iw_dev *dev, struct sk_buff *skb)
int release = 0;
struct tid_info *t = dev->rdev.lldi.tids;
unsigned int tid = GET_TID(rpl);
- int stop_timer = 0;
ep = lookup_tid(t, tid);
@@ -1697,7 +1698,7 @@ static int close_con_rpl(struct c4iw_dev *dev, struct sk_buff *skb)
__state_set(&ep->com, MORIBUND);
break;
case MORIBUND:
- stop_timer = 1;
+ stop_ep_timer(ep);
if ((ep->com.cm_id) && (ep->com.qp)) {
attrs.next_state = C4IW_QP_STATE_IDLE;
c4iw_modify_qp(ep->com.qp->rhp,
@@ -1717,8 +1718,6 @@ static int close_con_rpl(struct c4iw_dev *dev, struct sk_buff *skb)
break;
}
spin_unlock_irqrestore(&ep->com.lock, flags);
- if (stop_timer)
- stop_ep_timer(ep);
if (release)
release_ep_resources(ep);
return 0;
@@ -1939,7 +1938,7 @@ int c4iw_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
err = -EHOSTUNREACH;
goto fail3;
}
- ep->dst = &rt->u.dst;
+ ep->dst = &rt->dst;
/* get a l2t entry */
if (ep->dst->neighbour->dev->flags & IFF_LOOPBACK) {
@@ -1957,6 +1956,7 @@ int c4iw_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
ep->txq_idx = cxgb4_port_idx(pdev) * step;
step = ep->com.dev->rdev.lldi.nrxq /
ep->com.dev->rdev.lldi.nchan;
+ ep->ctrlq_idx = cxgb4_port_idx(pdev);
ep->rss_qid = ep->com.dev->rdev.lldi.rxq_ids[
cxgb4_port_idx(pdev) * step];
dev_put(pdev);
@@ -1971,6 +1971,7 @@ int c4iw_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
step = ep->com.dev->rdev.lldi.ntxq /
ep->com.dev->rdev.lldi.nchan;
ep->txq_idx = cxgb4_port_idx(ep->dst->neighbour->dev) * step;
+ ep->ctrlq_idx = cxgb4_port_idx(ep->dst->neighbour->dev);
step = ep->com.dev->rdev.lldi.nrxq /
ep->com.dev->rdev.lldi.nchan;
ep->rss_qid = ep->com.dev->rdev.lldi.rxq_ids[
@@ -2049,8 +2050,15 @@ int c4iw_create_listen(struct iw_cm_id *cm_id, int backlog)
goto fail3;
/* wait for pass_open_rpl */
- wait_event(ep->com.waitq, ep->com.rpl_done);
- err = ep->com.rpl_err;
+ wait_event_timeout(ep->com.waitq, ep->com.rpl_done, C4IW_WR_TO);
+ if (ep->com.rpl_done)
+ err = ep->com.rpl_err;
+ else {
+ printk(KERN_ERR MOD "Device %s not responding!\n",
+ pci_name(ep->com.dev->rdev.lldi.pdev));
+ ep->com.dev->rdev.flags = T4_FATAL_ERROR;
+ err = -EIO;
+ }
if (!err) {
cm_id->provider_data = ep;
goto out;
@@ -2079,10 +2087,17 @@ int c4iw_destroy_listen(struct iw_cm_id *cm_id)
err = listen_stop(ep);
if (err)
goto done;
- wait_event(ep->com.waitq, ep->com.rpl_done);
+ wait_event_timeout(ep->com.waitq, ep->com.rpl_done, C4IW_WR_TO);
+ if (ep->com.rpl_done)
+ err = ep->com.rpl_err;
+ else {
+ printk(KERN_ERR MOD "Device %s not responding!\n",
+ pci_name(ep->com.dev->rdev.lldi.pdev));
+ ep->com.dev->rdev.flags = T4_FATAL_ERROR;
+ err = -EIO;
+ }
cxgb4_free_stid(ep->com.dev->rdev.lldi.tids, ep->stid, PF_INET);
done:
- err = ep->com.rpl_err;
cm_id->rem_ref(cm_id);
c4iw_put_ep(&ep->com);
return err;
@@ -2095,8 +2110,6 @@ int c4iw_ep_disconnect(struct c4iw_ep *ep, int abrupt, gfp_t gfp)
int close = 0;
int fatal = 0;
struct c4iw_rdev *rdev;
- int start_timer = 0;
- int stop_timer = 0;
spin_lock_irqsave(&ep->com.lock, flags);
@@ -2120,7 +2133,7 @@ int c4iw_ep_disconnect(struct c4iw_ep *ep, int abrupt, gfp_t gfp)
ep->com.state = ABORTING;
else {
ep->com.state = CLOSING;
- start_timer = 1;
+ start_ep_timer(ep);
}
set_bit(CLOSE_SENT, &ep->com.flags);
break;
@@ -2128,7 +2141,7 @@ int c4iw_ep_disconnect(struct c4iw_ep *ep, int abrupt, gfp_t gfp)
if (!test_and_set_bit(CLOSE_SENT, &ep->com.flags)) {
close = 1;
if (abrupt) {
- stop_timer = 1;
+ stop_ep_timer(ep);
ep->com.state = ABORTING;
} else
ep->com.state = MORIBUND;
@@ -2146,10 +2159,6 @@ int c4iw_ep_disconnect(struct c4iw_ep *ep, int abrupt, gfp_t gfp)
}
spin_unlock_irqrestore(&ep->com.lock, flags);
- if (start_timer)
- start_ep_timer(ep);
- if (stop_timer)
- stop_ep_timer(ep);
if (close) {
if (abrupt)
ret = abort_connection(ep, NULL, gfp);
@@ -2244,7 +2253,7 @@ static void process_work(struct work_struct *work)
{
struct sk_buff *skb = NULL;
struct c4iw_dev *dev;
- struct cpl_act_establish *rpl = cplhdr(skb);
+ struct cpl_act_establish *rpl;
unsigned int opcode;
int ret;
diff --git a/drivers/infiniband/hw/cxgb4/cq.c b/drivers/infiniband/hw/cxgb4/cq.c
index fac5c6e6801..b3daf39eed4 100644
--- a/drivers/infiniband/hw/cxgb4/cq.c
+++ b/drivers/infiniband/hw/cxgb4/cq.c
@@ -43,7 +43,7 @@ static int destroy_cq(struct c4iw_rdev *rdev, struct t4_cq *cq,
int ret;
wr_len = sizeof *res_wr + sizeof *res;
- skb = alloc_skb(wr_len, GFP_KERNEL | __GFP_NOFAIL);
+ skb = alloc_skb(wr_len, GFP_KERNEL);
if (!skb)
return -ENOMEM;
set_wr_txq(skb, CPL_PRIORITY_CONTROL, 0);
@@ -118,7 +118,7 @@ static int create_cq(struct c4iw_rdev *rdev, struct t4_cq *cq,
/* build fw_ri_res_wr */
wr_len = sizeof *res_wr + sizeof *res;
- skb = alloc_skb(wr_len, GFP_KERNEL | __GFP_NOFAIL);
+ skb = alloc_skb(wr_len, GFP_KERNEL);
if (!skb) {
ret = -ENOMEM;
goto err4;
diff --git a/drivers/infiniband/hw/cxgb4/iw_cxgb4.h b/drivers/infiniband/hw/cxgb4/iw_cxgb4.h
index d33e1a66881..ed459b8f800 100644
--- a/drivers/infiniband/hw/cxgb4/iw_cxgb4.h
+++ b/drivers/infiniband/hw/cxgb4/iw_cxgb4.h
@@ -619,6 +619,7 @@ struct c4iw_ep {
u16 plen;
u16 rss_qid;
u16 txq_idx;
+ u16 ctrlq_idx;
u8 tos;
};
diff --git a/drivers/infiniband/hw/cxgb4/mem.c b/drivers/infiniband/hw/cxgb4/mem.c
index 82b5703b894..269373a62f2 100644
--- a/drivers/infiniband/hw/cxgb4/mem.c
+++ b/drivers/infiniband/hw/cxgb4/mem.c
@@ -59,7 +59,7 @@ static int write_adapter_mem(struct c4iw_rdev *rdev, u32 addr, u32 len,
wr_len = roundup(sizeof *req + sizeof *sc +
roundup(copy_len, T4_ULPTX_MIN_IO), 16);
- skb = alloc_skb(wr_len, GFP_KERNEL | __GFP_NOFAIL);
+ skb = alloc_skb(wr_len, GFP_KERNEL);
if (!skb)
return -ENOMEM;
set_wr_txq(skb, CPL_PRIORITY_CONTROL, 0);
diff --git a/drivers/infiniband/hw/cxgb4/qp.c b/drivers/infiniband/hw/cxgb4/qp.c
index 7065cb31055..93f6e5bf0ec 100644
--- a/drivers/infiniband/hw/cxgb4/qp.c
+++ b/drivers/infiniband/hw/cxgb4/qp.c
@@ -130,7 +130,7 @@ static int create_qp(struct c4iw_rdev *rdev, struct t4_wq *wq,
/* build fw_ri_res_wr */
wr_len = sizeof *res_wr + 2 * sizeof *res;
- skb = alloc_skb(wr_len, GFP_KERNEL | __GFP_NOFAIL);
+ skb = alloc_skb(wr_len, GFP_KERNEL);
if (!skb) {
ret = -ENOMEM;
goto err7;
@@ -162,7 +162,7 @@ static int create_qp(struct c4iw_rdev *rdev, struct t4_wq *wq,
res->u.sqrq.dcaen_to_eqsize = cpu_to_be32(
V_FW_RI_RES_WR_DCAEN(0) |
V_FW_RI_RES_WR_DCACPU(0) |
- V_FW_RI_RES_WR_FBMIN(3) |
+ V_FW_RI_RES_WR_FBMIN(2) |
V_FW_RI_RES_WR_FBMAX(3) |
V_FW_RI_RES_WR_CIDXFTHRESHO(0) |
V_FW_RI_RES_WR_CIDXFTHRESH(0) |
@@ -185,7 +185,7 @@ static int create_qp(struct c4iw_rdev *rdev, struct t4_wq *wq,
res->u.sqrq.dcaen_to_eqsize = cpu_to_be32(
V_FW_RI_RES_WR_DCAEN(0) |
V_FW_RI_RES_WR_DCACPU(0) |
- V_FW_RI_RES_WR_FBMIN(3) |
+ V_FW_RI_RES_WR_FBMIN(2) |
V_FW_RI_RES_WR_FBMAX(3) |
V_FW_RI_RES_WR_CIDXFTHRESHO(0) |
V_FW_RI_RES_WR_CIDXFTHRESH(0) |
@@ -235,12 +235,78 @@ err1:
return -ENOMEM;
}
-static int build_rdma_send(union t4_wr *wqe, struct ib_send_wr *wr, u8 *len16)
+static int build_immd(struct t4_sq *sq, struct fw_ri_immd *immdp,
+ struct ib_send_wr *wr, int max, u32 *plenp)
{
+ u8 *dstp, *srcp;
+ u32 plen = 0;
int i;
+ int rem, len;
+
+ dstp = (u8 *)immdp->data;
+ for (i = 0; i < wr->num_sge; i++) {
+ if ((plen + wr->sg_list[i].length) > max)
+ return -EMSGSIZE;
+ srcp = (u8 *)(unsigned long)wr->sg_list[i].addr;
+ plen += wr->sg_list[i].length;
+ rem = wr->sg_list[i].length;
+ while (rem) {
+ if (dstp == (u8 *)&sq->queue[sq->size])
+ dstp = (u8 *)sq->queue;
+ if (rem <= (u8 *)&sq->queue[sq->size] - dstp)
+ len = rem;
+ else
+ len = (u8 *)&sq->queue[sq->size] - dstp;
+ memcpy(dstp, srcp, len);
+ dstp += len;
+ srcp += len;
+ rem -= len;
+ }
+ }
+ immdp->op = FW_RI_DATA_IMMD;
+ immdp->r1 = 0;
+ immdp->r2 = 0;
+ immdp->immdlen = cpu_to_be32(plen);
+ *plenp = plen;
+ return 0;
+}
+
+static int build_isgl(__be64 *queue_start, __be64 *queue_end,
+ struct fw_ri_isgl *isglp, struct ib_sge *sg_list,
+ int num_sge, u32 *plenp)
+
+{
+ int i;
+ u32 plen = 0;
+ __be64 *flitp = (__be64 *)isglp->sge;
+
+ for (i = 0; i < num_sge; i++) {
+ if ((plen + sg_list[i].length) < plen)
+ return -EMSGSIZE;
+ plen += sg_list[i].length;
+ *flitp = cpu_to_be64(((u64)sg_list[i].lkey << 32) |
+ sg_list[i].length);
+ if (++flitp == queue_end)
+ flitp = queue_start;
+ *flitp = cpu_to_be64(sg_list[i].addr);
+ if (++flitp == queue_end)
+ flitp = queue_start;
+ }
+ isglp->op = FW_RI_DATA_ISGL;
+ isglp->r1 = 0;
+ isglp->nsge = cpu_to_be16(num_sge);
+ isglp->r2 = 0;
+ if (plenp)
+ *plenp = plen;
+ return 0;
+}
+
+static int build_rdma_send(struct t4_sq *sq, union t4_wr *wqe,
+ struct ib_send_wr *wr, u8 *len16)
+{
u32 plen;
int size;
- u8 *datap;
+ int ret;
if (wr->num_sge > T4_MAX_SEND_SGE)
return -EINVAL;
@@ -267,43 +333,23 @@ static int build_rdma_send(union t4_wr *wqe, struct ib_send_wr *wr, u8 *len16)
default:
return -EINVAL;
}
+
plen = 0;
if (wr->num_sge) {
if (wr->send_flags & IB_SEND_INLINE) {
- datap = (u8 *)wqe->send.u.immd_src[0].data;
- for (i = 0; i < wr->num_sge; i++) {
- if ((plen + wr->sg_list[i].length) >
- T4_MAX_SEND_INLINE) {
- return -EMSGSIZE;
- }
- plen += wr->sg_list[i].length;
- memcpy(datap,
- (void *)(unsigned long)wr->sg_list[i].addr,
- wr->sg_list[i].length);
- datap += wr->sg_list[i].length;
- }
- wqe->send.u.immd_src[0].op = FW_RI_DATA_IMMD;
- wqe->send.u.immd_src[0].r1 = 0;
- wqe->send.u.immd_src[0].r2 = 0;
- wqe->send.u.immd_src[0].immdlen = cpu_to_be32(plen);
+ ret = build_immd(sq, wqe->send.u.immd_src, wr,
+ T4_MAX_SEND_INLINE, &plen);
+ if (ret)
+ return ret;
size = sizeof wqe->send + sizeof(struct fw_ri_immd) +
plen;
} else {
- for (i = 0; i < wr->num_sge; i++) {
- if ((plen + wr->sg_list[i].length) < plen)
- return -EMSGSIZE;
- plen += wr->sg_list[i].length;
- wqe->send.u.isgl_src[0].sge[i].stag =
- cpu_to_be32(wr->sg_list[i].lkey);
- wqe->send.u.isgl_src[0].sge[i].len =
- cpu_to_be32(wr->sg_list[i].length);
- wqe->send.u.isgl_src[0].sge[i].to =
- cpu_to_be64(wr->sg_list[i].addr);
- }
- wqe->send.u.isgl_src[0].op = FW_RI_DATA_ISGL;
- wqe->send.u.isgl_src[0].r1 = 0;
- wqe->send.u.isgl_src[0].nsge = cpu_to_be16(wr->num_sge);
- wqe->send.u.isgl_src[0].r2 = 0;
+ ret = build_isgl((__be64 *)sq->queue,
+ (__be64 *)&sq->queue[sq->size],
+ wqe->send.u.isgl_src,
+ wr->sg_list, wr->num_sge, &plen);
+ if (ret)
+ return ret;
size = sizeof wqe->send + sizeof(struct fw_ri_isgl) +
wr->num_sge * sizeof(struct fw_ri_sge);
}
@@ -313,62 +359,40 @@ static int build_rdma_send(union t4_wr *wqe, struct ib_send_wr *wr, u8 *len16)
wqe->send.u.immd_src[0].r2 = 0;
wqe->send.u.immd_src[0].immdlen = 0;
size = sizeof wqe->send + sizeof(struct fw_ri_immd);
+ plen = 0;
}
*len16 = DIV_ROUND_UP(size, 16);
wqe->send.plen = cpu_to_be32(plen);
return 0;
}
-static int build_rdma_write(union t4_wr *wqe, struct ib_send_wr *wr, u8 *len16)
+static int build_rdma_write(struct t4_sq *sq, union t4_wr *wqe,
+ struct ib_send_wr *wr, u8 *len16)
{
- int i;
u32 plen;
int size;
- u8 *datap;
+ int ret;
- if (wr->num_sge > T4_MAX_WRITE_SGE)
+ if (wr->num_sge > T4_MAX_SEND_SGE)
return -EINVAL;
wqe->write.r2 = 0;
wqe->write.stag_sink = cpu_to_be32(wr->wr.rdma.rkey);
wqe->write.to_sink = cpu_to_be64(wr->wr.rdma.remote_addr);
- plen = 0;
if (wr->num_sge) {
if (wr->send_flags & IB_SEND_INLINE) {
- datap = (u8 *)wqe->write.u.immd_src[0].data;
- for (i = 0; i < wr->num_sge; i++) {
- if ((plen + wr->sg_list[i].length) >
- T4_MAX_WRITE_INLINE) {
- return -EMSGSIZE;
- }
- plen += wr->sg_list[i].length;
- memcpy(datap,
- (void *)(unsigned long)wr->sg_list[i].addr,
- wr->sg_list[i].length);
- datap += wr->sg_list[i].length;
- }
- wqe->write.u.immd_src[0].op = FW_RI_DATA_IMMD;
- wqe->write.u.immd_src[0].r1 = 0;
- wqe->write.u.immd_src[0].r2 = 0;
- wqe->write.u.immd_src[0].immdlen = cpu_to_be32(plen);
+ ret = build_immd(sq, wqe->write.u.immd_src, wr,
+ T4_MAX_WRITE_INLINE, &plen);
+ if (ret)
+ return ret;
size = sizeof wqe->write + sizeof(struct fw_ri_immd) +
plen;
} else {
- for (i = 0; i < wr->num_sge; i++) {
- if ((plen + wr->sg_list[i].length) < plen)
- return -EMSGSIZE;
- plen += wr->sg_list[i].length;
- wqe->write.u.isgl_src[0].sge[i].stag =
- cpu_to_be32(wr->sg_list[i].lkey);
- wqe->write.u.isgl_src[0].sge[i].len =
- cpu_to_be32(wr->sg_list[i].length);
- wqe->write.u.isgl_src[0].sge[i].to =
- cpu_to_be64(wr->sg_list[i].addr);
- }
- wqe->write.u.isgl_src[0].op = FW_RI_DATA_ISGL;
- wqe->write.u.isgl_src[0].r1 = 0;
- wqe->write.u.isgl_src[0].nsge =
- cpu_to_be16(wr->num_sge);
- wqe->write.u.isgl_src[0].r2 = 0;
+ ret = build_isgl((__be64 *)sq->queue,
+ (__be64 *)&sq->queue[sq->size],
+ wqe->write.u.isgl_src,
+ wr->sg_list, wr->num_sge, &plen);
+ if (ret)
+ return ret;
size = sizeof wqe->write + sizeof(struct fw_ri_isgl) +
wr->num_sge * sizeof(struct fw_ri_sge);
}
@@ -378,6 +402,7 @@ static int build_rdma_write(union t4_wr *wqe, struct ib_send_wr *wr, u8 *len16)
wqe->write.u.immd_src[0].r2 = 0;
wqe->write.u.immd_src[0].immdlen = 0;
size = sizeof wqe->write + sizeof(struct fw_ri_immd);
+ plen = 0;
}
*len16 = DIV_ROUND_UP(size, 16);
wqe->write.plen = cpu_to_be32(plen);
@@ -416,29 +441,13 @@ static int build_rdma_read(union t4_wr *wqe, struct ib_send_wr *wr, u8 *len16)
static int build_rdma_recv(struct c4iw_qp *qhp, union t4_recv_wr *wqe,
struct ib_recv_wr *wr, u8 *len16)
{
- int i;
- int plen = 0;
+ int ret;
- for (i = 0; i < wr->num_sge; i++) {
- if ((plen + wr->sg_list[i].length) < plen)
- return -EMSGSIZE;
- plen += wr->sg_list[i].length;
- wqe->recv.isgl.sge[i].stag =
- cpu_to_be32(wr->sg_list[i].lkey);
- wqe->recv.isgl.sge[i].len =
- cpu_to_be32(wr->sg_list[i].length);
- wqe->recv.isgl.sge[i].to =
- cpu_to_be64(wr->sg_list[i].addr);
- }
- for (; i < T4_MAX_RECV_SGE; i++) {
- wqe->recv.isgl.sge[i].stag = 0;
- wqe->recv.isgl.sge[i].len = 0;
- wqe->recv.isgl.sge[i].to = 0;
- }
- wqe->recv.isgl.op = FW_RI_DATA_ISGL;
- wqe->recv.isgl.r1 = 0;
- wqe->recv.isgl.nsge = cpu_to_be16(wr->num_sge);
- wqe->recv.isgl.r2 = 0;
+ ret = build_isgl((__be64 *)qhp->wq.rq.queue,
+ (__be64 *)&qhp->wq.rq.queue[qhp->wq.rq.size],
+ &wqe->recv.isgl, wr->sg_list, wr->num_sge, NULL);
+ if (ret)
+ return ret;
*len16 = DIV_ROUND_UP(sizeof wqe->recv +
wr->num_sge * sizeof(struct fw_ri_sge), 16);
return 0;
@@ -547,7 +556,9 @@ int c4iw_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
*bad_wr = wr;
break;
}
- wqe = &qhp->wq.sq.queue[qhp->wq.sq.pidx];
+ wqe = (union t4_wr *)((u8 *)qhp->wq.sq.queue +
+ qhp->wq.sq.wq_pidx * T4_EQ_ENTRY_SIZE);
+
fw_flags = 0;
if (wr->send_flags & IB_SEND_SOLICITED)
fw_flags |= FW_RI_SOLICITED_EVENT_FLAG;
@@ -564,12 +575,12 @@ int c4iw_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
swsqe->opcode = FW_RI_SEND;
else
swsqe->opcode = FW_RI_SEND_WITH_INV;
- err = build_rdma_send(wqe, wr, &len16);
+ err = build_rdma_send(&qhp->wq.sq, wqe, wr, &len16);
break;
case IB_WR_RDMA_WRITE:
fw_opcode = FW_RI_RDMA_WRITE_WR;
swsqe->opcode = FW_RI_RDMA_WRITE;
- err = build_rdma_write(wqe, wr, &len16);
+ err = build_rdma_write(&qhp->wq.sq, wqe, wr, &len16);
break;
case IB_WR_RDMA_READ:
case IB_WR_RDMA_READ_WITH_INV:
@@ -619,8 +630,8 @@ int c4iw_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
swsqe->opcode, swsqe->read_len);
wr = wr->next;
num_wrs--;
- t4_sq_produce(&qhp->wq);
- idx++;
+ t4_sq_produce(&qhp->wq, len16);
+ idx += DIV_ROUND_UP(len16*16, T4_EQ_ENTRY_SIZE);
}
if (t4_wq_db_enabled(&qhp->wq))
t4_ring_sq_db(&qhp->wq, idx);
@@ -656,7 +667,9 @@ int c4iw_post_receive(struct ib_qp *ibqp, struct ib_recv_wr *wr,
*bad_wr = wr;
break;
}
- wqe = &qhp->wq.rq.queue[qhp->wq.rq.pidx];
+ wqe = (union t4_recv_wr *)((u8 *)qhp->wq.rq.queue +
+ qhp->wq.rq.wq_pidx *
+ T4_EQ_ENTRY_SIZE);
if (num_wrs)
err = build_rdma_recv(qhp, wqe, wr, &len16);
else
@@ -675,15 +688,12 @@ int c4iw_post_receive(struct ib_qp *ibqp, struct ib_recv_wr *wr,
wqe->recv.r2[1] = 0;
wqe->recv.r2[2] = 0;
wqe->recv.len16 = len16;
- if (len16 < 5)
- wqe->flits[8] = 0;
-
PDBG("%s cookie 0x%llx pidx %u\n", __func__,
(unsigned long long) wr->wr_id, qhp->wq.rq.pidx);
- t4_rq_produce(&qhp->wq);
+ t4_rq_produce(&qhp->wq, len16);
+ idx += DIV_ROUND_UP(len16*16, T4_EQ_ENTRY_SIZE);
wr = wr->next;
num_wrs--;
- idx++;
}
if (t4_wq_db_enabled(&qhp->wq))
t4_ring_rq_db(&qhp->wq, idx);
@@ -905,7 +915,7 @@ static void __flush_qp(struct c4iw_qp *qhp, struct c4iw_cq *rchp,
atomic_inc(&qhp->refcnt);
spin_unlock_irqrestore(&qhp->lock, *flag);
- /* locking heirarchy: cq lock first, then qp lock. */
+ /* locking hierarchy: cq lock first, then qp lock. */
spin_lock_irqsave(&rchp->lock, *flag);
spin_lock(&qhp->lock);
c4iw_flush_hw_cq(&rchp->cq);
@@ -916,7 +926,7 @@ static void __flush_qp(struct c4iw_qp *qhp, struct c4iw_cq *rchp,
if (flushed)
(*rchp->ibcq.comp_handler)(&rchp->ibcq, rchp->ibcq.cq_context);
- /* locking heirarchy: cq lock first, then qp lock. */
+ /* locking hierarchy: cq lock first, then qp lock. */
spin_lock_irqsave(&schp->lock, *flag);
spin_lock(&qhp->lock);
c4iw_flush_hw_cq(&schp->cq);
@@ -951,7 +961,8 @@ static void flush_qp(struct c4iw_qp *qhp, unsigned long *flag)
__flush_qp(qhp, rchp, schp, flag);
}
-static int rdma_fini(struct c4iw_dev *rhp, struct c4iw_qp *qhp)
+static int rdma_fini(struct c4iw_dev *rhp, struct c4iw_qp *qhp,
+ struct c4iw_ep *ep)
{
struct fw_ri_wr *wqe;
int ret;
@@ -959,12 +970,12 @@ static int rdma_fini(struct c4iw_dev *rhp, struct c4iw_qp *qhp)
struct sk_buff *skb;
PDBG("%s qhp %p qid 0x%x tid %u\n", __func__, qhp, qhp->wq.sq.qid,
- qhp->ep->hwtid);
+ ep->hwtid);
- skb = alloc_skb(sizeof *wqe, GFP_KERNEL | __GFP_NOFAIL);
+ skb = alloc_skb(sizeof *wqe, GFP_KERNEL);
if (!skb)
return -ENOMEM;
- set_wr_txq(skb, CPL_PRIORITY_DATA, qhp->ep->txq_idx);
+ set_wr_txq(skb, CPL_PRIORITY_DATA, ep->txq_idx);
wqe = (struct fw_ri_wr *)__skb_put(skb, sizeof(*wqe));
memset(wqe, 0, sizeof *wqe);
@@ -972,7 +983,7 @@ static int rdma_fini(struct c4iw_dev *rhp, struct c4iw_qp *qhp)
FW_WR_OP(FW_RI_INIT_WR) |
FW_WR_COMPL(1));
wqe->flowid_len16 = cpu_to_be32(
- FW_WR_FLOWID(qhp->ep->hwtid) |
+ FW_WR_FLOWID(ep->hwtid) |
FW_WR_LEN16(DIV_ROUND_UP(sizeof *wqe, 16)));
wqe->cookie = (u64)&wr_wait;
@@ -1035,7 +1046,7 @@ static int rdma_init(struct c4iw_dev *rhp, struct c4iw_qp *qhp)
PDBG("%s qhp %p qid 0x%x tid %u\n", __func__, qhp, qhp->wq.sq.qid,
qhp->ep->hwtid);
- skb = alloc_skb(sizeof *wqe, GFP_KERNEL | __GFP_NOFAIL);
+ skb = alloc_skb(sizeof *wqe, GFP_KERNEL);
if (!skb)
return -ENOMEM;
set_wr_txq(skb, CPL_PRIORITY_DATA, qhp->ep->txq_idx);
@@ -1202,17 +1213,16 @@ int c4iw_modify_qp(struct c4iw_dev *rhp, struct c4iw_qp *qhp,
case C4IW_QP_STATE_CLOSING:
BUG_ON(atomic_read(&qhp->ep->com.kref.refcount) < 2);
qhp->attr.state = C4IW_QP_STATE_CLOSING;
+ ep = qhp->ep;
if (!internal) {
abort = 0;
disconnect = 1;
- ep = qhp->ep;
c4iw_get_ep(&ep->com);
}
spin_unlock_irqrestore(&qhp->lock, flag);
- ret = rdma_fini(rhp, qhp);
+ ret = rdma_fini(rhp, qhp, ep);
spin_lock_irqsave(&qhp->lock, flag);
if (ret) {
- ep = qhp->ep;
c4iw_get_ep(&ep->com);
disconnect = abort = 1;
goto err;
diff --git a/drivers/infiniband/hw/cxgb4/t4.h b/drivers/infiniband/hw/cxgb4/t4.h
index 9cf8d85bfcf..aef55f42bea 100644
--- a/drivers/infiniband/hw/cxgb4/t4.h
+++ b/drivers/infiniband/hw/cxgb4/t4.h
@@ -65,10 +65,10 @@ struct t4_status_page {
u8 db_off;
};
-#define T4_EQ_SIZE 64
+#define T4_EQ_ENTRY_SIZE 64
#define T4_SQ_NUM_SLOTS 4
-#define T4_SQ_NUM_BYTES (T4_EQ_SIZE * T4_SQ_NUM_SLOTS)
+#define T4_SQ_NUM_BYTES (T4_EQ_ENTRY_SIZE * T4_SQ_NUM_SLOTS)
#define T4_MAX_SEND_SGE ((T4_SQ_NUM_BYTES - sizeof(struct fw_ri_send_wr) - \
sizeof(struct fw_ri_isgl)) / sizeof(struct fw_ri_sge))
#define T4_MAX_SEND_INLINE ((T4_SQ_NUM_BYTES - sizeof(struct fw_ri_send_wr) - \
@@ -84,7 +84,7 @@ struct t4_status_page {
#define T4_MAX_FR_DEPTH (T4_MAX_FR_IMMD / sizeof(u64))
#define T4_RQ_NUM_SLOTS 2
-#define T4_RQ_NUM_BYTES (T4_EQ_SIZE * T4_RQ_NUM_SLOTS)
+#define T4_RQ_NUM_BYTES (T4_EQ_ENTRY_SIZE * T4_RQ_NUM_SLOTS)
#define T4_MAX_RECV_SGE 4
union t4_wr {
@@ -97,20 +97,18 @@ union t4_wr {
struct fw_ri_fr_nsmr_wr fr;
struct fw_ri_inv_lstag_wr inv;
struct t4_status_page status;
- __be64 flits[T4_EQ_SIZE / sizeof(__be64) * T4_SQ_NUM_SLOTS];
+ __be64 flits[T4_EQ_ENTRY_SIZE / sizeof(__be64) * T4_SQ_NUM_SLOTS];
};
union t4_recv_wr {
struct fw_ri_recv_wr recv;
struct t4_status_page status;
- __be64 flits[T4_EQ_SIZE / sizeof(__be64) * T4_RQ_NUM_SLOTS];
+ __be64 flits[T4_EQ_ENTRY_SIZE / sizeof(__be64) * T4_RQ_NUM_SLOTS];
};
static inline void init_wr_hdr(union t4_wr *wqe, u16 wrid,
enum fw_wr_opcodes opcode, u8 flags, u8 len16)
{
- int slots_used;
-
wqe->send.opcode = (u8)opcode;
wqe->send.flags = flags;
wqe->send.wrid = wrid;
@@ -118,12 +116,6 @@ static inline void init_wr_hdr(union t4_wr *wqe, u16 wrid,
wqe->send.r1[1] = 0;
wqe->send.r1[2] = 0;
wqe->send.len16 = len16;
-
- slots_used = DIV_ROUND_UP(len16*16, T4_EQ_SIZE);
- while (slots_used < T4_SQ_NUM_SLOTS) {
- wqe->flits[slots_used * T4_EQ_SIZE / sizeof(__be64)] = 0;
- slots_used++;
- }
}
/* CQE/AE status codes */
@@ -289,6 +281,7 @@ struct t4_sq {
u16 size;
u16 cidx;
u16 pidx;
+ u16 wq_pidx;
};
struct t4_swrqe {
@@ -310,6 +303,7 @@ struct t4_rq {
u16 size;
u16 cidx;
u16 pidx;
+ u16 wq_pidx;
};
struct t4_wq {
@@ -340,11 +334,14 @@ static inline u32 t4_rq_avail(struct t4_wq *wq)
return wq->rq.size - 1 - wq->rq.in_use;
}
-static inline void t4_rq_produce(struct t4_wq *wq)
+static inline void t4_rq_produce(struct t4_wq *wq, u8 len16)
{
wq->rq.in_use++;
if (++wq->rq.pidx == wq->rq.size)
wq->rq.pidx = 0;
+ wq->rq.wq_pidx += DIV_ROUND_UP(len16*16, T4_EQ_ENTRY_SIZE);
+ if (wq->rq.wq_pidx >= wq->rq.size * T4_RQ_NUM_SLOTS)
+ wq->rq.wq_pidx %= wq->rq.size * T4_RQ_NUM_SLOTS;
}
static inline void t4_rq_consume(struct t4_wq *wq)
@@ -370,11 +367,14 @@ static inline u32 t4_sq_avail(struct t4_wq *wq)
return wq->sq.size - 1 - wq->sq.in_use;
}
-static inline void t4_sq_produce(struct t4_wq *wq)
+static inline void t4_sq_produce(struct t4_wq *wq, u8 len16)
{
wq->sq.in_use++;
if (++wq->sq.pidx == wq->sq.size)
wq->sq.pidx = 0;
+ wq->sq.wq_pidx += DIV_ROUND_UP(len16*16, T4_EQ_ENTRY_SIZE);
+ if (wq->sq.wq_pidx >= wq->sq.size * T4_SQ_NUM_SLOTS)
+ wq->sq.wq_pidx %= wq->sq.size * T4_SQ_NUM_SLOTS;
}
static inline void t4_sq_consume(struct t4_wq *wq)
@@ -386,14 +386,12 @@ static inline void t4_sq_consume(struct t4_wq *wq)
static inline void t4_ring_sq_db(struct t4_wq *wq, u16 inc)
{
- inc *= T4_SQ_NUM_SLOTS;
wmb();
writel(QID(wq->sq.qid) | PIDX(inc), wq->db);
}
static inline void t4_ring_rq_db(struct t4_wq *wq, u16 inc)
{
- inc *= T4_RQ_NUM_SLOTS;
wmb();
writel(QID(wq->rq.qid) | PIDX(inc), wq->db);
}
diff --git a/drivers/infiniband/hw/cxgb4/t4fw_ri_api.h b/drivers/infiniband/hw/cxgb4/t4fw_ri_api.h
index fc706bd07fa..dc193c29267 100644
--- a/drivers/infiniband/hw/cxgb4/t4fw_ri_api.h
+++ b/drivers/infiniband/hw/cxgb4/t4fw_ri_api.h
@@ -826,4 +826,14 @@ struct ulptx_idata {
#define S_ULPTX_NSGE 0
#define M_ULPTX_NSGE 0xFFFF
#define V_ULPTX_NSGE(x) ((x) << S_ULPTX_NSGE)
+
+#define S_RX_DACK_MODE 29
+#define M_RX_DACK_MODE 0x3
+#define V_RX_DACK_MODE(x) ((x) << S_RX_DACK_MODE)
+#define G_RX_DACK_MODE(x) (((x) >> S_RX_DACK_MODE) & M_RX_DACK_MODE)
+
+#define S_RX_DACK_CHANGE 31
+#define V_RX_DACK_CHANGE(x) ((x) << S_RX_DACK_CHANGE)
+#define F_RX_DACK_CHANGE V_RX_DACK_CHANGE(1U)
+
#endif /* _T4FW_RI_API_H_ */
diff --git a/drivers/infiniband/hw/ehca/ehca_eq.c b/drivers/infiniband/hw/ehca/ehca_eq.c
index 3b87589b8ea..d9b1bb40f48 100644
--- a/drivers/infiniband/hw/ehca/ehca_eq.c
+++ b/drivers/infiniband/hw/ehca/ehca_eq.c
@@ -122,21 +122,21 @@ int ehca_create_eq(struct ehca_shca *shca,
/* register interrupt handlers and initialize work queues */
if (type == EHCA_EQ) {
+ tasklet_init(&eq->interrupt_task, ehca_tasklet_eq, (long)shca);
+
ret = ibmebus_request_irq(eq->ist, ehca_interrupt_eq,
IRQF_DISABLED, "ehca_eq",
(void *)shca);
if (ret < 0)
ehca_err(ib_dev, "Can't map interrupt handler.");
-
- tasklet_init(&eq->interrupt_task, ehca_tasklet_eq, (long)shca);
} else if (type == EHCA_NEQ) {
+ tasklet_init(&eq->interrupt_task, ehca_tasklet_neq, (long)shca);
+
ret = ibmebus_request_irq(eq->ist, ehca_interrupt_neq,
IRQF_DISABLED, "ehca_neq",
(void *)shca);
if (ret < 0)
ehca_err(ib_dev, "Can't map interrupt handler.");
-
- tasklet_init(&eq->interrupt_task, ehca_tasklet_neq, (long)shca);
}
eq->is_initialized = 1;
diff --git a/drivers/infiniband/hw/ehca/ehca_main.c b/drivers/infiniband/hw/ehca/ehca_main.c
index ecb51b396c4..cfc4de7a5da 100644
--- a/drivers/infiniband/hw/ehca/ehca_main.c
+++ b/drivers/infiniband/hw/ehca/ehca_main.c
@@ -360,7 +360,8 @@ static int ehca_sense_attributes(struct ehca_shca *shca)
* a firmware property, so it's valid across all adapters
*/
if (ehca_lock_hcalls == -1)
- ehca_lock_hcalls = !(shca->hca_cap & HCA_CAP_H_ALLOC_RES_SYNC);
+ ehca_lock_hcalls = !EHCA_BMASK_GET(HCA_CAP_H_ALLOC_RES_SYNC,
+ shca->hca_cap);
/* translate supported MR page sizes; always support 4K */
shca->hca_cap_mr_pgsize = EHCA_PAGESIZE;
diff --git a/drivers/infiniband/hw/ehca/ehca_mrmw.c b/drivers/infiniband/hw/ehca/ehca_mrmw.c
index 31a68b9c52d..53f4cd4fc19 100644
--- a/drivers/infiniband/hw/ehca/ehca_mrmw.c
+++ b/drivers/infiniband/hw/ehca/ehca_mrmw.c
@@ -933,11 +933,6 @@ int ehca_unmap_fmr(struct list_head *fmr_list)
/* check all FMR belong to same SHCA, and check internal flag */
list_for_each_entry(ib_fmr, fmr_list, list) {
prev_shca = shca;
- if (!ib_fmr) {
- ehca_gen_err("bad fmr=%p in list", ib_fmr);
- ret = -EINVAL;
- goto unmap_fmr_exit0;
- }
shca = container_of(ib_fmr->device, struct ehca_shca,
ib_device);
e_fmr = container_of(ib_fmr, struct ehca_mr, ib.ib_fmr);
diff --git a/drivers/infiniband/hw/ehca/ehca_qp.c b/drivers/infiniband/hw/ehca/ehca_qp.c
index 47d388ec1cd..32fb34201ab 100644
--- a/drivers/infiniband/hw/ehca/ehca_qp.c
+++ b/drivers/infiniband/hw/ehca/ehca_qp.c
@@ -251,7 +251,7 @@ static inline int ibqptype2servicetype(enum ib_qp_type ibqptype)
return ST_UD;
case IB_QPT_RAW_IPV6:
return -EINVAL;
- case IB_QPT_RAW_ETY:
+ case IB_QPT_RAW_ETHERTYPE:
return -EINVAL;
default:
ehca_gen_err("Invalid ibqptype=%x", ibqptype);
diff --git a/drivers/infiniband/hw/ehca/hcp_if.c b/drivers/infiniband/hw/ehca/hcp_if.c
index 4d5dc3304d4..e6f9cdd94c7 100644
--- a/drivers/infiniband/hw/ehca/hcp_if.c
+++ b/drivers/infiniband/hw/ehca/hcp_if.c
@@ -269,6 +269,7 @@ u64 hipz_h_alloc_resource_cq(const struct ipz_adapter_handle adapter_handle,
struct ehca_cq *cq,
struct ehca_alloc_cq_parms *param)
{
+ int rc;
u64 ret;
unsigned long outs[PLPAR_HCALL9_BUFSIZE];
@@ -283,8 +284,19 @@ u64 hipz_h_alloc_resource_cq(const struct ipz_adapter_handle adapter_handle,
param->act_nr_of_entries = (u32)outs[3];
param->act_pages = (u32)outs[4];
- if (ret == H_SUCCESS)
- hcp_galpas_ctor(&cq->galpas, 0, outs[5], outs[6]);
+ if (ret == H_SUCCESS) {
+ rc = hcp_galpas_ctor(&cq->galpas, 0, outs[5], outs[6]);
+ if (rc) {
+ ehca_gen_err("Could not establish HW access. rc=%d paddr=%#lx",
+ rc, outs[5]);
+
+ ehca_plpar_hcall_norets(H_FREE_RESOURCE,
+ adapter_handle.handle, /* r4 */
+ cq->ipz_cq_handle.handle, /* r5 */
+ 0, 0, 0, 0, 0);
+ ret = H_NO_MEM;
+ }
+ }
if (ret == H_NOT_ENOUGH_RESOURCES)
ehca_gen_err("Not enough resources. ret=%lli", ret);
@@ -295,6 +307,7 @@ 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_alloc_qp_parms *parms, int is_user)
{
+ int rc;
u64 ret;
u64 allocate_controls, max_r10_reg, r11, r12;
unsigned long outs[PLPAR_HCALL9_BUFSIZE];
@@ -358,8 +371,19 @@ u64 hipz_h_alloc_resource_qp(const struct ipz_adapter_handle adapter_handle,
parms->rqueue.queue_size =
(u32)EHCA_BMASK_GET(H_ALL_RES_QP_RQUEUE_SIZE_PAGES, outs[4]);
- if (ret == H_SUCCESS)
- hcp_galpas_ctor(&parms->galpas, is_user, outs[6], outs[6]);
+ if (ret == H_SUCCESS) {
+ rc = hcp_galpas_ctor(&parms->galpas, is_user, outs[6], outs[6]);
+ if (rc) {
+ ehca_gen_err("Could not establish HW access. rc=%d paddr=%#lx",
+ rc, outs[6]);
+
+ ehca_plpar_hcall_norets(H_FREE_RESOURCE,
+ adapter_handle.handle, /* r4 */
+ parms->qp_handle.handle, /* r5 */
+ 0, 0, 0, 0, 0);
+ ret = H_NO_MEM;
+ }
+ }
if (ret == H_NOT_ENOUGH_RESOURCES)
ehca_gen_err("Not enough resources. ret=%lli", ret);
diff --git a/drivers/infiniband/hw/ehca/hcp_if.h b/drivers/infiniband/hw/ehca/hcp_if.h
index 39c1c3618ec..a46e514c367 100644
--- a/drivers/infiniband/hw/ehca/hcp_if.h
+++ b/drivers/infiniband/hw/ehca/hcp_if.h
@@ -49,7 +49,7 @@
#include "hipz_hw.h"
/*
- * hipz_h_alloc_resource_eq allocates EQ resources in HW and FW, initalize
+ * hipz_h_alloc_resource_eq allocates EQ resources in HW and FW, initialize
* resources, create the empty EQPT (ring).
*/
u64 hipz_h_alloc_resource_eq(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 b3e0e72e8a7..077376ff3d2 100644
--- a/drivers/infiniband/hw/ehca/hcp_phyp.c
+++ b/drivers/infiniband/hw/ehca/hcp_phyp.c
@@ -42,10 +42,9 @@
#include "ehca_classes.h"
#include "hipz_hw.h"
-int hcall_map_page(u64 physaddr, u64 *mapaddr)
+u64 hcall_map_page(u64 physaddr)
{
- *mapaddr = (u64)(ioremap(physaddr, EHCA_PAGESIZE));
- return 0;
+ return (u64)ioremap(physaddr, EHCA_PAGESIZE);
}
int hcall_unmap_page(u64 mapaddr)
@@ -58,9 +57,9 @@ int hcp_galpas_ctor(struct h_galpas *galpas, int is_user,
u64 paddr_kernel, u64 paddr_user)
{
if (!is_user) {
- int ret = hcall_map_page(paddr_kernel, &galpas->kernel.fw_handle);
- if (ret)
- return ret;
+ galpas->kernel.fw_handle = hcall_map_page(paddr_kernel);
+ if (!galpas->kernel.fw_handle)
+ return -ENOMEM;
} else
galpas->kernel.fw_handle = 0;
diff --git a/drivers/infiniband/hw/ehca/hcp_phyp.h b/drivers/infiniband/hw/ehca/hcp_phyp.h
index 204227d5303..d1b02991024 100644
--- a/drivers/infiniband/hw/ehca/hcp_phyp.h
+++ b/drivers/infiniband/hw/ehca/hcp_phyp.h
@@ -83,7 +83,7 @@ int hcp_galpas_ctor(struct h_galpas *galpas, int is_user,
int hcp_galpas_dtor(struct h_galpas *galpas);
-int hcall_map_page(u64 physaddr, u64 * mapaddr);
+u64 hcall_map_page(u64 physaddr);
int hcall_unmap_page(u64 mapaddr);
diff --git a/drivers/infiniband/hw/ipath/ipath_driver.c b/drivers/infiniband/hw/ipath/ipath_driver.c
index 21337468c65..765f0fc1da7 100644
--- a/drivers/infiniband/hw/ipath/ipath_driver.c
+++ b/drivers/infiniband/hw/ipath/ipath_driver.c
@@ -390,6 +390,8 @@ done:
ipath_enable_armlaunch(dd);
}
+static void cleanup_device(struct ipath_devdata *dd);
+
static int __devinit ipath_init_one(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
@@ -616,8 +618,13 @@ static int __devinit ipath_init_one(struct pci_dev *pdev,
goto bail;
bail_irqsetup:
- if (pdev->irq)
- free_irq(pdev->irq, dd);
+ cleanup_device(dd);
+
+ if (dd->ipath_irq)
+ dd->ipath_f_free_irq(dd);
+
+ if (dd->ipath_f_cleanup)
+ dd->ipath_f_cleanup(dd);
bail_iounmap:
iounmap((volatile void __iomem *) dd->ipath_kregbase);
@@ -635,7 +642,7 @@ bail:
return ret;
}
-static void __devexit cleanup_device(struct ipath_devdata *dd)
+static void cleanup_device(struct ipath_devdata *dd)
{
int port;
struct ipath_portdata **tmp;
diff --git a/drivers/infiniband/hw/ipath/ipath_file_ops.c b/drivers/infiniband/hw/ipath/ipath_file_ops.c
index 9c5c66d16a2..65eb8929db2 100644
--- a/drivers/infiniband/hw/ipath/ipath_file_ops.c
+++ b/drivers/infiniband/hw/ipath/ipath_file_ops.c
@@ -2055,7 +2055,7 @@ static int ipath_close(struct inode *in, struct file *fp)
mutex_lock(&ipath_mutex);
- fd = (struct ipath_filedata *) fp->private_data;
+ fd = fp->private_data;
fp->private_data = NULL;
pd = fd->pd;
if (!pd) {
diff --git a/drivers/infiniband/hw/mthca/mthca_cmd.c b/drivers/infiniband/hw/mthca/mthca_cmd.c
index 3603ae89b60..f4ceecd9684 100644
--- a/drivers/infiniband/hw/mthca/mthca_cmd.c
+++ b/drivers/infiniband/hw/mthca/mthca_cmd.c
@@ -1817,7 +1817,7 @@ int mthca_CONF_SPECIAL_QP(struct mthca_dev *dev, int type, u32 qpn,
case IB_QPT_RAW_IPV6:
op_mod = 2;
break;
- case IB_QPT_RAW_ETY:
+ case IB_QPT_RAW_ETHERTYPE:
op_mod = 3;
break;
default:
diff --git a/drivers/infiniband/hw/nes/nes.c b/drivers/infiniband/hw/nes/nes.c
index de7b9d7166f..0c9f0aa5d4e 100644
--- a/drivers/infiniband/hw/nes/nes.c
+++ b/drivers/infiniband/hw/nes/nes.c
@@ -110,8 +110,8 @@ static unsigned int sysfs_nonidx_addr;
static unsigned int sysfs_idx_addr;
static struct pci_device_id nes_pci_table[] = {
- {PCI_VENDOR_ID_NETEFFECT, PCI_DEVICE_ID_NETEFFECT_NE020, PCI_ANY_ID, PCI_ANY_ID},
- {PCI_VENDOR_ID_NETEFFECT, PCI_DEVICE_ID_NETEFFECT_NE020_KR, PCI_ANY_ID, PCI_ANY_ID},
+ { PCI_VDEVICE(NETEFFECT, PCI_DEVICE_ID_NETEFFECT_NE020), },
+ { PCI_VDEVICE(NETEFFECT, PCI_DEVICE_ID_NETEFFECT_NE020_KR), },
{0}
};
@@ -259,13 +259,11 @@ static void nes_cqp_rem_ref_callback(struct nes_device *nesdev, struct nes_cqp_r
unsigned long flags;
struct nes_qp *nesqp = cqp_request->cqp_callback_pointer;
struct nes_adapter *nesadapter = nesdev->nesadapter;
- u32 qp_id;
atomic_inc(&qps_destroyed);
/* Free the control structures */
- qp_id = nesqp->hwqp.qp_id;
if (nesqp->pbl_vbase) {
pci_free_consistent(nesdev->pcidev, nesqp->qp_mem_size,
nesqp->hwqp.q2_vbase, nesqp->hwqp.q2_pbase);
@@ -441,7 +439,6 @@ static int __devinit nes_probe(struct pci_dev *pcidev, const struct pci_device_i
struct net_device *netdev = NULL;
struct nes_device *nesdev = NULL;
int ret = 0;
- struct nes_vnic *nesvnic = NULL;
void __iomem *mmio_regs = NULL;
u8 hw_rev;
@@ -664,25 +661,21 @@ static int __devinit nes_probe(struct pci_dev *pcidev, const struct pci_device_i
nes_notifiers_registered++;
/* Initialize network devices */
- if ((netdev = nes_netdev_init(nesdev, mmio_regs)) == NULL) {
- goto bail7;
- }
-
- /* Register network device */
- ret = register_netdev(netdev);
- if (ret) {
- printk(KERN_ERR PFX "Unable to register netdev, ret = %d\n", ret);
- nes_netdev_destroy(netdev);
- goto bail7;
- }
+ if ((netdev = nes_netdev_init(nesdev, mmio_regs)) == NULL)
+ goto bail7;
- nes_print_macaddr(netdev);
- /* create a CM core for this netdev */
- nesvnic = netdev_priv(netdev);
+ /* Register network device */
+ ret = register_netdev(netdev);
+ if (ret) {
+ printk(KERN_ERR PFX "Unable to register netdev, ret = %d\n", ret);
+ nes_netdev_destroy(netdev);
+ goto bail7;
+ }
- nesdev->netdev_count++;
- nesdev->nesadapter->netdev_count++;
+ nes_print_macaddr(netdev);
+ nesdev->netdev_count++;
+ nesdev->nesadapter->netdev_count++;
printk(KERN_ERR PFX "%s: NetEffect RNIC driver successfully loaded.\n",
pci_name(pcidev));
@@ -1104,7 +1097,7 @@ static ssize_t nes_show_wqm_quanta(struct device_driver *ddp, char *buf)
i++;
}
- return snprintf(buf, PAGE_SIZE, "0x%X\n", wqm_quanta);
+ return snprintf(buf, PAGE_SIZE, "0x%X\n", wqm_quanta_value);
}
diff --git a/drivers/infiniband/hw/nes/nes.h b/drivers/infiniband/hw/nes/nes.h
index cc78fee1dd5..b3d145e82b4 100644
--- a/drivers/infiniband/hw/nes/nes.h
+++ b/drivers/infiniband/hw/nes/nes.h
@@ -262,6 +262,7 @@ struct nes_device {
u16 base_doorbell_index;
u16 currcq_count;
u16 deepcq_count;
+ u8 iw_status;
u8 msi_enabled;
u8 netdev_count;
u8 napi_isr_ran;
@@ -527,6 +528,7 @@ void nes_cm_disconn_worker(void *);
int nes_hw_modify_qp(struct nes_device *, struct nes_qp *, u32, u32, u32);
int nes_modify_qp(struct ib_qp *, struct ib_qp_attr *, int, struct ib_udata *);
struct nes_ib_device *nes_init_ofa_device(struct net_device *);
+void nes_port_ibevent(struct nes_vnic *nesvnic);
void nes_destroy_ofa_device(struct nes_ib_device *);
int nes_register_ofa_device(struct nes_ib_device *);
diff --git a/drivers/infiniband/hw/nes/nes_cm.c b/drivers/infiniband/hw/nes/nes_cm.c
index 986d6f32dde..443cea55daa 100644
--- a/drivers/infiniband/hw/nes/nes_cm.c
+++ b/drivers/infiniband/hw/nes/nes_cm.c
@@ -1146,7 +1146,7 @@ static int nes_addr_resolve_neigh(struct nes_vnic *nesvnic, u32 dst_ip, int arpi
}
if ((neigh == NULL) || (!(neigh->nud_state & NUD_VALID)))
- neigh_event_send(rt->u.dst.neighbour, NULL);
+ neigh_event_send(rt->dst.neighbour, NULL);
ip_rt_put(rt);
return rc;
@@ -1719,8 +1719,6 @@ static int handle_ack_pkt(struct nes_cm_node *cm_node, struct sk_buff *skb,
{
int datasize = 0;
u32 inc_sequence;
- u32 rem_seq_ack;
- u32 rem_seq;
int ret = 0;
int optionsize;
optionsize = (tcph->doff << 2) - sizeof(struct tcphdr);
@@ -1730,8 +1728,6 @@ static int handle_ack_pkt(struct nes_cm_node *cm_node, struct sk_buff *skb,
skb_pull(skb, tcph->doff << 2);
inc_sequence = ntohl(tcph->seq);
- rem_seq = ntohl(tcph->seq);
- rem_seq_ack = ntohl(tcph->ack_seq);
datasize = skb->len;
switch (cm_node->state) {
case NES_CM_STATE_SYN_RCVD:
@@ -2565,7 +2561,7 @@ static int nes_cm_disconn_true(struct nes_qp *nesqp)
u16 last_ae;
u8 original_hw_tcp_state;
u8 original_ibqp_state;
- enum iw_cm_event_type disconn_status = IW_CM_EVENT_STATUS_OK;
+ enum iw_cm_event_status disconn_status = IW_CM_EVENT_STATUS_OK;
int issue_disconn = 0;
int issue_close = 0;
int issue_flush = 0;
@@ -3128,17 +3124,15 @@ int nes_create_listen(struct iw_cm_id *cm_id, int backlog)
struct nes_vnic *nesvnic;
struct nes_cm_listener *cm_node;
struct nes_cm_info cm_info;
- struct nes_adapter *adapter;
int err;
-
nes_debug(NES_DBG_CM, "cm_id = %p, local port = 0x%04X.\n",
cm_id, ntohs(cm_id->local_addr.sin_port));
nesvnic = to_nesvnic(cm_id->device);
if (!nesvnic)
return -EINVAL;
- adapter = nesvnic->nesdev->nesadapter;
+
nes_debug(NES_DBG_CM, "nesvnic=%p, netdev=%p, %s\n",
nesvnic, nesvnic->netdev, nesvnic->netdev->name);
diff --git a/drivers/infiniband/hw/nes/nes_hw.c b/drivers/infiniband/hw/nes/nes_hw.c
index 57874a16508..f8233c851c6 100644
--- a/drivers/infiniband/hw/nes/nes_hw.c
+++ b/drivers/infiniband/hw/nes/nes_hw.c
@@ -1970,7 +1970,7 @@ void nes_destroy_nic_qp(struct nes_vnic *nesvnic)
dev_kfree_skb(
nesvnic->nic.tx_skb[nesvnic->nic.sq_tail]);
- nesvnic->nic.sq_tail = (++nesvnic->nic.sq_tail)
+ nesvnic->nic.sq_tail = (nesvnic->nic.sq_tail + 1)
& (nesvnic->nic.sq_size - 1);
}
@@ -2737,9 +2737,9 @@ void nes_nic_ce_handler(struct nes_device *nesdev, struct nes_hw_nic_cq *cq)
nesnic->sq_tail &= nesnic->sq_size-1;
if (sq_cqes > 128) {
barrier();
- /* restart the queue if it had been stopped */
- if (netif_queue_stopped(nesvnic->netdev))
- netif_wake_queue(nesvnic->netdev);
+ /* restart the queue if it had been stopped */
+ if (netif_queue_stopped(nesvnic->netdev))
+ netif_wake_queue(nesvnic->netdev);
sq_cqes = 0;
}
} else {
@@ -2999,11 +2999,8 @@ static void nes_cqp_ce_handler(struct nes_device *nesdev, struct nes_hw_cq *cq)
static u8 *locate_mpa(u8 *pkt, u32 aeq_info)
{
- u16 pkt_len;
-
if (aeq_info & NES_AEQE_Q2_DATA_ETHERNET) {
/* skip over ethernet header */
- pkt_len = be16_to_cpu(*(u16 *)(pkt + ETH_HLEN - 2));
pkt += ETH_HLEN;
/* Skip over IP and TCP headers */
@@ -3283,9 +3280,15 @@ static void nes_terminate_connection(struct nes_device *nesdev, struct nes_qp *n
else
mod_qp_flags |= NES_CQP_QP_TERM_DONT_SEND_TERM_MSG;
- nes_terminate_start_timer(nesqp);
- nesqp->term_flags |= NES_TERM_SENT;
- nes_hw_modify_qp(nesdev, nesqp, mod_qp_flags, termlen, 0);
+ if (!nesdev->iw_status) {
+ nesqp->term_flags = NES_TERM_DONE;
+ nes_hw_modify_qp(nesdev, nesqp, NES_CQP_QP_IWARP_STATE_ERROR, 0, 0);
+ nes_cm_disconn(nesqp);
+ } else {
+ nes_terminate_start_timer(nesqp);
+ nesqp->term_flags |= NES_TERM_SENT;
+ nes_hw_modify_qp(nesdev, nesqp, mod_qp_flags, termlen, 0);
+ }
}
static void nes_terminate_send_fin(struct nes_device *nesdev,
diff --git a/drivers/infiniband/hw/nes/nes_hw.h b/drivers/infiniband/hw/nes/nes_hw.h
index bbbfe9fc5a5..aa9183db32b 100644
--- a/drivers/infiniband/hw/nes/nes_hw.h
+++ b/drivers/infiniband/hw/nes/nes_hw.h
@@ -1100,11 +1100,12 @@ struct nes_adapter {
u32 wqm_wat;
u32 core_clock;
u32 firmware_version;
+ u32 eeprom_version;
u32 nic_rx_eth_route_err;
u32 et_rx_coalesce_usecs;
- u32 et_rx_max_coalesced_frames;
+ u32 et_rx_max_coalesced_frames;
u32 et_rx_coalesce_usecs_irq;
u32 et_rx_max_coalesced_frames_irq;
u32 et_pkt_rate_low;
diff --git a/drivers/infiniband/hw/nes/nes_nic.c b/drivers/infiniband/hw/nes/nes_nic.c
index 5cc0a9ae5bb..6dfdd49cdbc 100644
--- a/drivers/infiniband/hw/nes/nes_nic.c
+++ b/drivers/infiniband/hw/nes/nes_nic.c
@@ -232,6 +232,13 @@ static int nes_netdev_open(struct net_device *netdev)
NES_MAC_INT_TX_UNDERFLOW | NES_MAC_INT_TX_ERROR));
first_nesvnic = nesvnic;
}
+
+ if (nesvnic->of_device_registered) {
+ nesdev->iw_status = 1;
+ nesdev->nesadapter->send_term_ok = 1;
+ nes_port_ibevent(nesvnic);
+ }
+
if (first_nesvnic->linkup) {
/* Enable network packets */
nesvnic->linkup = 1;
@@ -309,9 +316,9 @@ static int nes_netdev_stop(struct net_device *netdev)
if (nesvnic->of_device_registered) {
- nes_destroy_ofa_device(nesvnic->nesibdev);
- nesvnic->nesibdev = NULL;
- nesvnic->of_device_registered = 0;
+ nesdev->nesadapter->send_term_ok = 0;
+ nesdev->iw_status = 0;
+ nes_port_ibevent(nesvnic);
}
nes_destroy_nic_qp(nesvnic);
@@ -463,7 +470,6 @@ static int nes_netdev_start_xmit(struct sk_buff *skb, struct net_device *netdev)
u16 nhoffset;
u16 wqes_needed;
u16 wqes_available;
- u32 old_head;
u32 wqe_misc;
/*
@@ -503,7 +509,6 @@ sq_no_longer_full:
if (skb_is_gso(skb)) {
nesvnic->segmented_tso_requests++;
nesvnic->tso_requests++;
- old_head = nesnic->sq_head;
/* Basically 4 fragments available per WQE with extended fragments */
wqes_needed = nr_frags >> 2;
wqes_needed += (nr_frags&3)?1:0;
@@ -1567,6 +1572,12 @@ static int nes_netdev_set_settings(struct net_device *netdev, struct ethtool_cmd
}
+static int nes_netdev_set_flags(struct net_device *netdev, u32 flags)
+{
+ return ethtool_op_set_flags(netdev, flags, ETH_FLAG_LRO);
+}
+
+
static const struct ethtool_ops nes_ethtool_ops = {
.get_link = ethtool_op_get_link,
.get_settings = nes_netdev_get_settings,
@@ -1588,7 +1599,7 @@ static const struct ethtool_ops nes_ethtool_ops = {
.get_tso = ethtool_op_get_tso,
.set_tso = ethtool_op_set_tso,
.get_flags = ethtool_op_get_flags,
- .set_flags = ethtool_op_set_flags,
+ .set_flags = nes_netdev_set_flags,
};
diff --git a/drivers/infiniband/hw/nes/nes_utils.c b/drivers/infiniband/hw/nes/nes_utils.c
index a9f5dd272f1..f9c417c6b3b 100644
--- a/drivers/infiniband/hw/nes/nes_utils.c
+++ b/drivers/infiniband/hw/nes/nes_utils.c
@@ -190,6 +190,11 @@ int nes_read_eeprom_values(struct nes_device *nesdev, struct nes_adapter *nesada
nesadapter->firmware_version = (((u32)(u8)(eeprom_data>>8)) << 16) +
(u32)((u8)eeprom_data);
+ eeprom_data = nes_read16_eeprom(nesdev->regs, next_section_address + 10);
+ printk(PFX "EEPROM version %u.%u\n", (u8)(eeprom_data>>8), (u8)eeprom_data);
+ nesadapter->eeprom_version = (((u32)(u8)(eeprom_data>>8)) << 16) +
+ (u32)((u8)eeprom_data);
+
no_fw_rev:
/* eeprom is valid */
eeprom_offset = nesadapter->software_eeprom_offset;
diff --git a/drivers/infiniband/hw/nes/nes_verbs.c b/drivers/infiniband/hw/nes/nes_verbs.c
index 9bc2d744b2e..9046e667568 100644
--- a/drivers/infiniband/hw/nes/nes_verbs.c
+++ b/drivers/infiniband/hw/nes/nes_verbs.c
@@ -518,7 +518,7 @@ static int nes_query_device(struct ib_device *ibdev, struct ib_device_attr *prop
memset(props, 0, sizeof(*props));
memcpy(&props->sys_image_guid, nesvnic->netdev->dev_addr, 6);
- props->fw_ver = nesdev->nesadapter->fw_ver;
+ props->fw_ver = nesdev->nesadapter->firmware_version;
props->device_cap_flags = nesdev->nesadapter->device_cap_flags;
props->vendor_id = nesdev->nesadapter->vendor_id;
props->vendor_part_id = nesdev->nesadapter->vendor_part_id;
@@ -1941,7 +1941,7 @@ static int nes_reg_mr(struct nes_device *nesdev, struct nes_pd *nespd,
u8 use_256_pbls = 0;
u8 use_4k_pbls = 0;
u16 use_two_level = (pbl_count_4k > 1) ? 1 : 0;
- struct nes_root_vpbl new_root = {0, 0, 0};
+ struct nes_root_vpbl new_root = { 0, NULL, NULL };
u32 opcode = 0;
u16 major_code;
@@ -2112,13 +2112,12 @@ static struct ib_mr *nes_reg_phys_mr(struct ib_pd *ib_pd,
u32 driver_key = 0;
u32 root_pbl_index = 0;
u32 cur_pbl_index = 0;
- int err = 0, pbl_depth = 0;
+ int err = 0;
int ret = 0;
u16 pbl_count = 0;
u8 single_page = 1;
u8 stag_key = 0;
- pbl_depth = 0;
region_length = 0;
vpbl.pbl_vbase = NULL;
root_vpbl.pbl_vbase = NULL;
@@ -2931,7 +2930,6 @@ int nes_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
int ret;
u16 original_last_aeq;
u8 issue_modify_qp = 0;
- u8 issue_disconnect = 0;
u8 dont_wait = 0;
nes_debug(NES_DBG_MOD_QP, "QP%u: QP State=%u, cur QP State=%u,"
@@ -3058,6 +3056,7 @@ int nes_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
nesqp->hte_added = 0;
}
if ((nesqp->hw_tcp_state > NES_AEQE_TCP_STATE_CLOSED) &&
+ (nesdev->iw_status) &&
(nesqp->hw_tcp_state != NES_AEQE_TCP_STATE_TIME_WAIT)) {
next_iwarp_state |= NES_CQP_QP_RESET;
} else {
@@ -3082,7 +3081,6 @@ int nes_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
nesqp->iwarp_state = next_iwarp_state & NES_CQP_QP_IWARP_STATE_MASK;
nes_debug(NES_DBG_MOD_QP, "Change nesqp->iwarp_state=%08x\n",
nesqp->iwarp_state);
- issue_disconnect = 1;
} else {
nesqp->iwarp_state = next_iwarp_state & NES_CQP_QP_IWARP_STATE_MASK;
nes_debug(NES_DBG_MOD_QP, "Change nesqp->iwarp_state=%08x\n",
@@ -3936,6 +3934,17 @@ struct nes_ib_device *nes_init_ofa_device(struct net_device *netdev)
return nesibdev;
}
+void nes_port_ibevent(struct nes_vnic *nesvnic)
+{
+ struct nes_ib_device *nesibdev = nesvnic->nesibdev;
+ struct nes_device *nesdev = nesvnic->nesdev;
+ struct ib_event event;
+ event.device = &nesibdev->ibdev;
+ event.element.port_num = nesvnic->logical_port + 1;
+ event.event = nesdev->iw_status ? IB_EVENT_PORT_ACTIVE : IB_EVENT_PORT_ERR;
+ ib_dispatch_event(&event);
+}
+
/**
* nes_destroy_ofa_device
diff --git a/drivers/infiniband/hw/qib/qib.h b/drivers/infiniband/hw/qib/qib.h
index 3593983df7b..61de0654820 100644
--- a/drivers/infiniband/hw/qib/qib.h
+++ b/drivers/infiniband/hw/qib/qib.h
@@ -45,6 +45,7 @@
#include <linux/mutex.h>
#include <linux/list.h>
#include <linux/scatterlist.h>
+#include <linux/slab.h>
#include <linux/io.h>
#include <linux/fs.h>
#include <linux/completion.h>
@@ -326,6 +327,9 @@ struct qib_verbs_txreq {
#define QIB_DEFAULT_MTU 4096
+/* max number of IB ports supported per HCA */
+#define QIB_MAX_IB_PORTS 2
+
/*
* Possible IB config parameters for f_get/set_ib_table()
*/
diff --git a/drivers/infiniband/hw/qib/qib_common.h b/drivers/infiniband/hw/qib/qib_common.h
index b3955ed8f79..145da404088 100644
--- a/drivers/infiniband/hw/qib/qib_common.h
+++ b/drivers/infiniband/hw/qib/qib_common.h
@@ -279,7 +279,7 @@ struct qib_base_info {
* may not be implemented; the user code must deal with this if it
* cares, or it must abort after initialization reports the difference.
*/
-#define QIB_USER_SWMINOR 10
+#define QIB_USER_SWMINOR 11
#define QIB_USER_SWVERSION ((QIB_USER_SWMAJOR << 16) | QIB_USER_SWMINOR)
@@ -302,6 +302,18 @@ struct qib_base_info {
#define QIB_KERN_SWVERSION ((QIB_KERN_TYPE << 31) | QIB_USER_SWVERSION)
/*
+ * If the unit is specified via open, HCA choice is fixed. If port is
+ * specified, it's also fixed. Otherwise we try to spread contexts
+ * across ports and HCAs, using different algorithims. WITHIN is
+ * the old default, prior to this mechanism.
+ */
+#define QIB_PORT_ALG_ACROSS 0 /* round robin contexts across HCAs, then
+ * ports; this is the default */
+#define QIB_PORT_ALG_WITHIN 1 /* use all contexts on an HCA (round robin
+ * active ports within), then next HCA */
+#define QIB_PORT_ALG_COUNT 2 /* number of algorithm choices */
+
+/*
* This structure is passed to qib_userinit() to tell the driver where
* user code buffers are, sizes, etc. The offsets and sizes of the
* fields must remain unchanged, for binary compatibility. It can
@@ -319,7 +331,7 @@ struct qib_user_info {
/* size of struct base_info to write to */
__u32 spu_base_info_size;
- __u32 _spu_unused3;
+ __u32 spu_port_alg; /* which QIB_PORT_ALG_*; unused user minor < 11 */
/*
* If two or more processes wish to share a context, each process
diff --git a/drivers/infiniband/hw/qib/qib_driver.c b/drivers/infiniband/hw/qib/qib_driver.c
index f15ce076ac4..9cd193603fb 100644
--- a/drivers/infiniband/hw/qib/qib_driver.c
+++ b/drivers/infiniband/hw/qib/qib_driver.c
@@ -335,7 +335,7 @@ u32 qib_kreceive(struct qib_ctxtdata *rcd, u32 *llic, u32 *npkts)
smp_rmb(); /* prevent speculative reads of dma'ed hdrq */
}
- for (last = 0, i = 1; !last; i += !last) {
+ for (last = 0, i = 1; !last && i <= 64; i += !last) {
hdr = dd->f_get_msgheader(dd, rhf_addr);
eflags = qib_hdrget_err_flags(rhf_addr);
etype = qib_hdrget_rcv_type(rhf_addr);
diff --git a/drivers/infiniband/hw/qib/qib_file_ops.c b/drivers/infiniband/hw/qib/qib_file_ops.c
index a142a9eb522..6b11645edf3 100644
--- a/drivers/infiniband/hw/qib/qib_file_ops.c
+++ b/drivers/infiniband/hw/qib/qib_file_ops.c
@@ -1294,128 +1294,130 @@ bail:
return ret;
}
-static inline int usable(struct qib_pportdata *ppd, int active_only)
+static inline int usable(struct qib_pportdata *ppd)
{
struct qib_devdata *dd = ppd->dd;
- u32 linkok = active_only ? QIBL_LINKACTIVE :
- (QIBL_LINKINIT | QIBL_LINKARMED | QIBL_LINKACTIVE);
return dd && (dd->flags & QIB_PRESENT) && dd->kregbase && ppd->lid &&
- (ppd->lflags & linkok);
+ (ppd->lflags & QIBL_LINKACTIVE);
}
-static int find_free_ctxt(int unit, struct file *fp,
- const struct qib_user_info *uinfo)
+/*
+ * Select a context on the given device, either using a requested port
+ * or the port based on the context number.
+ */
+static int choose_port_ctxt(struct file *fp, struct qib_devdata *dd, u32 port,
+ const struct qib_user_info *uinfo)
{
- struct qib_devdata *dd = qib_lookup(unit);
struct qib_pportdata *ppd = NULL;
- int ret;
- u32 ctxt;
+ int ret, ctxt;
- if (!dd || (uinfo->spu_port && uinfo->spu_port > dd->num_pports)) {
- ret = -ENODEV;
- goto bail;
- }
-
- /*
- * If users requests specific port, only try that one port, else
- * select "best" port below, based on context.
- */
- if (uinfo->spu_port) {
- ppd = dd->pport + uinfo->spu_port - 1;
- if (!usable(ppd, 0)) {
+ if (port) {
+ if (!usable(dd->pport + port - 1)) {
ret = -ENETDOWN;
- goto bail;
- }
+ goto done;
+ } else
+ ppd = dd->pport + port - 1;
}
-
- for (ctxt = dd->first_user_ctxt; ctxt < dd->cfgctxts; ctxt++) {
- if (dd->rcd[ctxt])
- continue;
- /*
- * The setting and clearing of user context rcd[x] protected
- * by the qib_mutex
- */
- if (!ppd) {
- /* choose port based on ctxt, if up, else 1st up */
- ppd = dd->pport + (ctxt % dd->num_pports);
- if (!usable(ppd, 0)) {
- int i;
- for (i = 0; i < dd->num_pports; i++) {
- ppd = dd->pport + i;
- if (usable(ppd, 0))
- break;
- }
- if (i == dd->num_pports) {
- ret = -ENETDOWN;
- goto bail;
- }
- }
+ for (ctxt = dd->first_user_ctxt; ctxt < dd->cfgctxts && dd->rcd[ctxt];
+ ctxt++)
+ ;
+ if (ctxt == dd->cfgctxts) {
+ ret = -EBUSY;
+ goto done;
+ }
+ if (!ppd) {
+ u32 pidx = ctxt % dd->num_pports;
+ if (usable(dd->pport + pidx))
+ ppd = dd->pport + pidx;
+ else {
+ for (pidx = 0; pidx < dd->num_pports && !ppd;
+ pidx++)
+ if (usable(dd->pport + pidx))
+ ppd = dd->pport + pidx;
}
- ret = setup_ctxt(ppd, ctxt, fp, uinfo);
- goto bail;
}
- ret = -EBUSY;
+ ret = ppd ? setup_ctxt(ppd, ctxt, fp, uinfo) : -ENETDOWN;
+done:
+ return ret;
+}
+
+static int find_free_ctxt(int unit, struct file *fp,
+ const struct qib_user_info *uinfo)
+{
+ struct qib_devdata *dd = qib_lookup(unit);
+ int ret;
+
+ if (!dd || (uinfo->spu_port && uinfo->spu_port > dd->num_pports))
+ ret = -ENODEV;
+ else
+ ret = choose_port_ctxt(fp, dd, uinfo->spu_port, uinfo);
-bail:
return ret;
}
-static int get_a_ctxt(struct file *fp, const struct qib_user_info *uinfo)
+static int get_a_ctxt(struct file *fp, const struct qib_user_info *uinfo,
+ unsigned alg)
{
- struct qib_pportdata *ppd;
- int ret = 0, devmax;
- int npresent, nup;
- int ndev;
+ struct qib_devdata *udd = NULL;
+ int ret = 0, devmax, npresent, nup, ndev, dusable = 0, i;
u32 port = uinfo->spu_port, ctxt;
devmax = qib_count_units(&npresent, &nup);
+ if (!npresent) {
+ ret = -ENXIO;
+ goto done;
+ }
+ if (nup == 0) {
+ ret = -ENETDOWN;
+ goto done;
+ }
- for (ndev = 0; ndev < devmax; ndev++) {
- struct qib_devdata *dd = qib_lookup(ndev);
-
- /* device portion of usable() */
- if (!(dd && (dd->flags & QIB_PRESENT) && dd->kregbase))
- continue;
- for (ctxt = dd->first_user_ctxt; ctxt < dd->cfgctxts; ctxt++) {
- if (dd->rcd[ctxt])
+ if (alg == QIB_PORT_ALG_ACROSS) {
+ unsigned inuse = ~0U;
+ /* find device (with ACTIVE ports) with fewest ctxts in use */
+ for (ndev = 0; ndev < devmax; ndev++) {
+ struct qib_devdata *dd = qib_lookup(ndev);
+ unsigned cused = 0, cfree = 0;
+ if (!dd)
continue;
- if (port) {
- if (port > dd->num_pports)
- continue;
- ppd = dd->pport + port - 1;
- if (!usable(ppd, 0))
- continue;
- } else {
- /*
- * choose port based on ctxt, if up, else
- * first port that's up for multi-port HCA
- */
- ppd = dd->pport + (ctxt % dd->num_pports);
- if (!usable(ppd, 0)) {
- int j;
-
- ppd = NULL;
- for (j = 0; j < dd->num_pports &&
- !ppd; j++)
- if (usable(dd->pport + j, 0))
- ppd = dd->pport + j;
- if (!ppd)
- continue; /* to next unit */
- }
+ if (port && port <= dd->num_pports &&
+ usable(dd->pport + port - 1))
+ dusable = 1;
+ else
+ for (i = 0; i < dd->num_pports; i++)
+ if (usable(dd->pport + i))
+ dusable++;
+ if (!dusable)
+ continue;
+ for (ctxt = dd->first_user_ctxt; ctxt < dd->cfgctxts;
+ ctxt++)
+ if (dd->rcd[ctxt])
+ cused++;
+ else
+ cfree++;
+ if (cfree && cused < inuse) {
+ udd = dd;
+ inuse = cused;
}
- ret = setup_ctxt(ppd, ctxt, fp, uinfo);
+ }
+ if (udd) {
+ ret = choose_port_ctxt(fp, udd, port, uinfo);
goto done;
}
+ } else {
+ for (ndev = 0; ndev < devmax; ndev++) {
+ struct qib_devdata *dd = qib_lookup(ndev);
+ if (dd) {
+ ret = choose_port_ctxt(fp, dd, port, uinfo);
+ if (!ret)
+ goto done;
+ if (ret == -EBUSY)
+ dusable++;
+ }
+ }
}
-
- if (npresent) {
- if (nup == 0)
- ret = -ENETDOWN;
- else
- ret = -EBUSY;
- } else
- ret = -ENXIO;
+ ret = dusable ? -EBUSY : -ENETDOWN;
done:
return ret;
@@ -1481,7 +1483,7 @@ static int qib_assign_ctxt(struct file *fp, const struct qib_user_info *uinfo)
{
int ret;
int i_minor;
- unsigned swmajor, swminor;
+ unsigned swmajor, swminor, alg = QIB_PORT_ALG_ACROSS;
/* Check to be sure we haven't already initialized this file */
if (ctxt_fp(fp)) {
@@ -1498,6 +1500,9 @@ static int qib_assign_ctxt(struct file *fp, const struct qib_user_info *uinfo)
swminor = uinfo->spu_userversion & 0xffff;
+ if (swminor >= 11 && uinfo->spu_port_alg < QIB_PORT_ALG_COUNT)
+ alg = uinfo->spu_port_alg;
+
mutex_lock(&qib_mutex);
if (qib_compatible_subctxts(swmajor, swminor) &&
@@ -1514,7 +1519,7 @@ static int qib_assign_ctxt(struct file *fp, const struct qib_user_info *uinfo)
if (i_minor)
ret = find_free_ctxt(i_minor - 1, fp, uinfo);
else
- ret = get_a_ctxt(fp, uinfo);
+ ret = get_a_ctxt(fp, uinfo, alg);
done_chk_sdma:
if (!ret) {
@@ -1862,7 +1867,7 @@ static int disarm_req_delay(struct qib_ctxtdata *rcd)
{
int ret = 0;
- if (!usable(rcd->ppd, 1)) {
+ if (!usable(rcd->ppd)) {
int i;
/*
* if link is down, or otherwise not usable, delay
@@ -1881,7 +1886,7 @@ static int disarm_req_delay(struct qib_ctxtdata *rcd)
set_bit(_QIB_EVENT_DISARM_BUFS_BIT,
&rcd->user_event_mask[i]);
}
- for (i = 0; !usable(rcd->ppd, 1) && i < 300; i++)
+ for (i = 0; !usable(rcd->ppd) && i < 300; i++)
msleep(100);
ret = -ENETDOWN;
}
diff --git a/drivers/infiniband/hw/qib/qib_fs.c b/drivers/infiniband/hw/qib/qib_fs.c
index 844954bf417..9f989c0ba9d 100644
--- a/drivers/infiniband/hw/qib/qib_fs.c
+++ b/drivers/infiniband/hw/qib/qib_fs.c
@@ -135,8 +135,8 @@ static ssize_t driver_names_read(struct file *file, char __user *buf,
}
static const struct file_operations driver_ops[] = {
- { .read = driver_stats_read, },
- { .read = driver_names_read, },
+ { .read = driver_stats_read, .llseek = generic_file_llseek, },
+ { .read = driver_names_read, .llseek = generic_file_llseek, },
};
/* read the per-device counters */
@@ -164,8 +164,8 @@ static ssize_t dev_names_read(struct file *file, char __user *buf,
}
static const struct file_operations cntr_ops[] = {
- { .read = dev_counters_read, },
- { .read = dev_names_read, },
+ { .read = dev_counters_read, .llseek = generic_file_llseek, },
+ { .read = dev_names_read, .llseek = generic_file_llseek, },
};
/*
@@ -210,9 +210,9 @@ static ssize_t portcntrs_2_read(struct file *file, char __user *buf,
}
static const struct file_operations portcntr_ops[] = {
- { .read = portnames_read, },
- { .read = portcntrs_1_read, },
- { .read = portcntrs_2_read, },
+ { .read = portnames_read, .llseek = generic_file_llseek, },
+ { .read = portcntrs_1_read, .llseek = generic_file_llseek, },
+ { .read = portcntrs_2_read, .llseek = generic_file_llseek, },
};
/*
@@ -261,8 +261,8 @@ static ssize_t qsfp_2_read(struct file *file, char __user *buf,
}
static const struct file_operations qsfp_ops[] = {
- { .read = qsfp_1_read, },
- { .read = qsfp_2_read, },
+ { .read = qsfp_1_read, .llseek = generic_file_llseek, },
+ { .read = qsfp_2_read, .llseek = generic_file_llseek, },
};
static ssize_t flash_read(struct file *file, char __user *buf,
diff --git a/drivers/infiniband/hw/qib/qib_iba7322.c b/drivers/infiniband/hw/qib/qib_iba7322.c
index 5eedf83e2c3..584d443b533 100644
--- a/drivers/infiniband/hw/qib/qib_iba7322.c
+++ b/drivers/infiniband/hw/qib/qib_iba7322.c
@@ -5864,7 +5864,7 @@ static void write_7322_initregs(struct qib_devdata *dd)
* Doesn't clear any of the error bits that might be set.
*/
val = TIDFLOW_ERRBITS; /* these are W1C */
- for (i = 0; i < dd->ctxtcnt; i++) {
+ for (i = 0; i < dd->cfgctxts; i++) {
int flow;
for (flow = 0; flow < NUM_TIDFLOWS_CTXT; flow++)
qib_write_ureg(dd, ur_rcvflowtable+flow, val, i);
@@ -7271,6 +7271,8 @@ static int serdes_7322_init(struct qib_pportdata *ppd)
ibsd_wr_allchans(ppd, 20, (4 << 13), BMASK(15, 13)); /* SDR */
data = qib_read_kreg_port(ppd, krp_serdesctrl);
+ /* Turn off IB latency mode */
+ data &= ~SYM_MASK(IBSerdesCtrl_0, IB_LAT_MODE);
qib_write_kreg_port(ppd, krp_serdesctrl, data |
SYM_MASK(IBSerdesCtrl_0, RXLOSEN));
diff --git a/drivers/infiniband/hw/qib/qib_init.c b/drivers/infiniband/hw/qib/qib_init.c
index a873dd596e8..f1d16d3a01f 100644
--- a/drivers/infiniband/hw/qib/qib_init.c
+++ b/drivers/infiniband/hw/qib/qib_init.c
@@ -93,7 +93,7 @@ unsigned long *qib_cpulist;
void qib_set_ctxtcnt(struct qib_devdata *dd)
{
if (!qib_cfgctxts)
- dd->cfgctxts = dd->ctxtcnt;
+ dd->cfgctxts = dd->first_user_ctxt + num_online_cpus();
else if (qib_cfgctxts < dd->num_pports)
dd->cfgctxts = dd->ctxtcnt;
else if (qib_cfgctxts <= dd->ctxtcnt)
diff --git a/drivers/infiniband/hw/qib/qib_qp.c b/drivers/infiniband/hw/qib/qib_qp.c
index e0f65e39076..6c39851d2de 100644
--- a/drivers/infiniband/hw/qib/qib_qp.c
+++ b/drivers/infiniband/hw/qib/qib_qp.c
@@ -450,7 +450,7 @@ static void clear_mr_refs(struct qib_qp *qp, int clr_sends)
*
* Flushes both send and receive work queues.
* Returns true if last WQE event should be generated.
- * The QP s_lock should be held and interrupts disabled.
+ * The QP r_lock and s_lock should be held and interrupts disabled.
* If we are already in error state, just return.
*/
int qib_error_qp(struct qib_qp *qp, enum ib_wc_status err)
diff --git a/drivers/infiniband/hw/qib/qib_rc.c b/drivers/infiniband/hw/qib/qib_rc.c
index 40c0a373719..a0931119bd7 100644
--- a/drivers/infiniband/hw/qib/qib_rc.c
+++ b/drivers/infiniband/hw/qib/qib_rc.c
@@ -868,7 +868,7 @@ done:
/*
* Back up requester to resend the last un-ACKed request.
- * The QP s_lock should be held and interrupts disabled.
+ * The QP r_lock and s_lock should be held and interrupts disabled.
*/
static void qib_restart_rc(struct qib_qp *qp, u32 psn, int wait)
{
@@ -911,7 +911,8 @@ static void rc_timeout(unsigned long arg)
struct qib_ibport *ibp;
unsigned long flags;
- spin_lock_irqsave(&qp->s_lock, flags);
+ spin_lock_irqsave(&qp->r_lock, flags);
+ spin_lock(&qp->s_lock);
if (qp->s_flags & QIB_S_TIMER) {
ibp = to_iport(qp->ibqp.device, qp->port_num);
ibp->n_rc_timeouts++;
@@ -920,7 +921,8 @@ static void rc_timeout(unsigned long arg)
qib_restart_rc(qp, qp->s_last_psn + 1, 1);
qib_schedule_send(qp);
}
- spin_unlock_irqrestore(&qp->s_lock, flags);
+ spin_unlock(&qp->s_lock);
+ spin_unlock_irqrestore(&qp->r_lock, flags);
}
/*
@@ -1414,10 +1416,6 @@ static void qib_rc_rcv_resp(struct qib_ibport *ibp,
spin_lock_irqsave(&qp->s_lock, flags);
- /* Double check we can process this now that we hold the s_lock. */
- if (!(ib_qib_state_ops[qp->state] & QIB_PROCESS_RECV_OK))
- goto ack_done;
-
/* Ignore invalid responses. */
if (qib_cmp24(psn, qp->s_next_psn) >= 0)
goto ack_done;
@@ -1661,9 +1659,6 @@ static int qib_rc_rcv_error(struct qib_other_headers *ohdr,
ibp->n_rc_dupreq++;
spin_lock_irqsave(&qp->s_lock, flags);
- /* Double check we can process this now that we hold the s_lock. */
- if (!(ib_qib_state_ops[qp->state] & QIB_PROCESS_RECV_OK))
- goto unlock_done;
for (i = qp->r_head_ack_queue; ; i = prev) {
if (i == qp->s_tail_ack_queue)
@@ -1878,9 +1873,6 @@ void qib_rc_rcv(struct qib_ctxtdata *rcd, struct qib_ib_header *hdr,
psn = be32_to_cpu(ohdr->bth[2]);
opcode >>= 24;
- /* Prevent simultaneous processing after APM on different CPUs */
- spin_lock(&qp->r_lock);
-
/*
* Process responses (ACKs) before anything else. Note that the
* packet sequence number will be for something in the send work
@@ -1891,14 +1883,14 @@ void qib_rc_rcv(struct qib_ctxtdata *rcd, struct qib_ib_header *hdr,
opcode <= OP(ATOMIC_ACKNOWLEDGE)) {
qib_rc_rcv_resp(ibp, ohdr, data, tlen, qp, opcode, psn,
hdrsize, pmtu, rcd);
- goto runlock;
+ return;
}
/* Compute 24 bits worth of difference. */
diff = qib_cmp24(psn, qp->r_psn);
if (unlikely(diff)) {
if (qib_rc_rcv_error(ohdr, data, qp, opcode, psn, diff, rcd))
- goto runlock;
+ return;
goto send_ack;
}
@@ -2090,9 +2082,6 @@ send_last:
if (next > QIB_MAX_RDMA_ATOMIC)
next = 0;
spin_lock_irqsave(&qp->s_lock, flags);
- /* Double check we can process this while holding the s_lock. */
- if (!(ib_qib_state_ops[qp->state] & QIB_PROCESS_RECV_OK))
- goto srunlock;
if (unlikely(next == qp->s_tail_ack_queue)) {
if (!qp->s_ack_queue[next].sent)
goto nack_inv_unlck;
@@ -2146,7 +2135,7 @@ send_last:
qp->s_flags |= QIB_S_RESP_PENDING;
qib_schedule_send(qp);
- goto srunlock;
+ goto sunlock;
}
case OP(COMPARE_SWAP):
@@ -2165,9 +2154,6 @@ send_last:
if (next > QIB_MAX_RDMA_ATOMIC)
next = 0;
spin_lock_irqsave(&qp->s_lock, flags);
- /* Double check we can process this while holding the s_lock. */
- if (!(ib_qib_state_ops[qp->state] & QIB_PROCESS_RECV_OK))
- goto srunlock;
if (unlikely(next == qp->s_tail_ack_queue)) {
if (!qp->s_ack_queue[next].sent)
goto nack_inv_unlck;
@@ -2213,7 +2199,7 @@ send_last:
qp->s_flags |= QIB_S_RESP_PENDING;
qib_schedule_send(qp);
- goto srunlock;
+ goto sunlock;
}
default:
@@ -2227,7 +2213,7 @@ send_last:
/* Send an ACK if requested or required. */
if (psn & (1 << 31))
goto send_ack;
- goto runlock;
+ return;
rnr_nak:
qp->r_nak_state = IB_RNR_NAK | qp->r_min_rnr_timer;
@@ -2238,7 +2224,7 @@ rnr_nak:
atomic_inc(&qp->refcount);
list_add_tail(&qp->rspwait, &rcd->qp_wait_list);
}
- goto runlock;
+ return;
nack_op_err:
qib_rc_error(qp, IB_WC_LOC_QP_OP_ERR);
@@ -2250,7 +2236,7 @@ nack_op_err:
atomic_inc(&qp->refcount);
list_add_tail(&qp->rspwait, &rcd->qp_wait_list);
}
- goto runlock;
+ return;
nack_inv_unlck:
spin_unlock_irqrestore(&qp->s_lock, flags);
@@ -2264,7 +2250,7 @@ nack_inv:
atomic_inc(&qp->refcount);
list_add_tail(&qp->rspwait, &rcd->qp_wait_list);
}
- goto runlock;
+ return;
nack_acc_unlck:
spin_unlock_irqrestore(&qp->s_lock, flags);
@@ -2274,13 +2260,6 @@ nack_acc:
qp->r_ack_psn = qp->r_psn;
send_ack:
qib_send_rc_ack(qp);
-runlock:
- spin_unlock(&qp->r_lock);
- return;
-
-srunlock:
- spin_unlock_irqrestore(&qp->s_lock, flags);
- spin_unlock(&qp->r_lock);
return;
sunlock:
diff --git a/drivers/infiniband/hw/qib/qib_sdma.c b/drivers/infiniband/hw/qib/qib_sdma.c
index b8456881f7f..cad44491320 100644
--- a/drivers/infiniband/hw/qib/qib_sdma.c
+++ b/drivers/infiniband/hw/qib/qib_sdma.c
@@ -656,6 +656,7 @@ unmap:
}
qp = tx->qp;
qib_put_txreq(tx);
+ spin_lock(&qp->r_lock);
spin_lock(&qp->s_lock);
if (qp->ibqp.qp_type == IB_QPT_RC) {
/* XXX what about error sending RDMA read responses? */
@@ -664,6 +665,7 @@ unmap:
} else if (qp->s_wqe)
qib_send_complete(qp, qp->s_wqe, IB_WC_GENERAL_ERR);
spin_unlock(&qp->s_lock);
+ spin_unlock(&qp->r_lock);
/* return zero to process the next send work request */
goto unlock;
diff --git a/drivers/infiniband/hw/qib/qib_sysfs.c b/drivers/infiniband/hw/qib/qib_sysfs.c
index dab4d9f4a2c..d50a33fe8bb 100644
--- a/drivers/infiniband/hw/qib/qib_sysfs.c
+++ b/drivers/infiniband/hw/qib/qib_sysfs.c
@@ -347,7 +347,7 @@ static struct kobj_type qib_sl2vl_ktype = {
#define QIB_DIAGC_ATTR(N) \
static struct qib_diagc_attr qib_diagc_attr_##N = { \
- .attr = { .name = __stringify(N), .mode = 0444 }, \
+ .attr = { .name = __stringify(N), .mode = 0664 }, \
.counter = offsetof(struct qib_ibport, n_##N) \
}
@@ -403,8 +403,27 @@ static ssize_t diagc_attr_show(struct kobject *kobj, struct attribute *attr,
return sprintf(buf, "%u\n", *(u32 *)((char *)qibp + dattr->counter));
}
+static ssize_t diagc_attr_store(struct kobject *kobj, struct attribute *attr,
+ const char *buf, size_t size)
+{
+ struct qib_diagc_attr *dattr =
+ container_of(attr, struct qib_diagc_attr, attr);
+ struct qib_pportdata *ppd =
+ container_of(kobj, struct qib_pportdata, diagc_kobj);
+ struct qib_ibport *qibp = &ppd->ibport_data;
+ char *endp;
+ long val = simple_strtol(buf, &endp, 0);
+
+ if (val < 0 || endp == buf)
+ return -EINVAL;
+
+ *(u32 *)((char *) qibp + dattr->counter) = val;
+ return size;
+}
+
static const struct sysfs_ops qib_diagc_ops = {
.show = diagc_attr_show,
+ .store = diagc_attr_store,
};
static struct kobj_type qib_diagc_ktype = {
diff --git a/drivers/infiniband/hw/qib/qib_tx.c b/drivers/infiniband/hw/qib/qib_tx.c
index af30232b683..7f36454c225 100644
--- a/drivers/infiniband/hw/qib/qib_tx.c
+++ b/drivers/infiniband/hw/qib/qib_tx.c
@@ -170,7 +170,7 @@ static int find_ctxt(struct qib_devdata *dd, unsigned bufn)
void qib_disarm_piobufs_set(struct qib_devdata *dd, unsigned long *mask,
unsigned cnt)
{
- struct qib_pportdata *ppd, *pppd[dd->num_pports];
+ struct qib_pportdata *ppd, *pppd[QIB_MAX_IB_PORTS];
unsigned i;
unsigned long flags;
diff --git a/drivers/infiniband/hw/qib/qib_uc.c b/drivers/infiniband/hw/qib/qib_uc.c
index 6c7fe78cca6..b9c8b6346c1 100644
--- a/drivers/infiniband/hw/qib/qib_uc.c
+++ b/drivers/infiniband/hw/qib/qib_uc.c
@@ -272,9 +272,6 @@ void qib_uc_rcv(struct qib_ibport *ibp, struct qib_ib_header *hdr,
opcode >>= 24;
memset(&wc, 0, sizeof wc);
- /* Prevent simultaneous processing after APM on different CPUs */
- spin_lock(&qp->r_lock);
-
/* Compare the PSN verses the expected PSN. */
if (unlikely(qib_cmp24(psn, qp->r_psn) != 0)) {
/*
@@ -534,7 +531,6 @@ rdma_last:
}
qp->r_psn++;
qp->r_state = opcode;
- spin_unlock(&qp->r_lock);
return;
rewind:
@@ -542,12 +538,10 @@ rewind:
qp->r_sge.num_sge = 0;
drop:
ibp->n_pkt_drops++;
- spin_unlock(&qp->r_lock);
return;
op_err:
qib_rc_error(qp, IB_WC_LOC_QP_OP_ERR);
- spin_unlock(&qp->r_lock);
return;
sunlock:
diff --git a/drivers/infiniband/hw/qib/qib_ud.c b/drivers/infiniband/hw/qib/qib_ud.c
index c838cda7334..e1b3da2a1f8 100644
--- a/drivers/infiniband/hw/qib/qib_ud.c
+++ b/drivers/infiniband/hw/qib/qib_ud.c
@@ -535,13 +535,6 @@ void qib_ud_rcv(struct qib_ibport *ibp, struct qib_ib_header *hdr,
wc.byte_len = tlen + sizeof(struct ib_grh);
/*
- * We need to serialize getting a receive work queue entry and
- * generating a completion for it against QPs sending to this QP
- * locally.
- */
- spin_lock(&qp->r_lock);
-
- /*
* Get the next work request entry to find where to put the data.
*/
if (qp->r_flags & QIB_R_REUSE_SGE)
@@ -552,19 +545,19 @@ void qib_ud_rcv(struct qib_ibport *ibp, struct qib_ib_header *hdr,
ret = qib_get_rwqe(qp, 0);
if (ret < 0) {
qib_rc_error(qp, IB_WC_LOC_QP_OP_ERR);
- goto bail_unlock;
+ return;
}
if (!ret) {
if (qp->ibqp.qp_num == 0)
ibp->n_vl15_dropped++;
- goto bail_unlock;
+ return;
}
}
/* Silently drop packets which are too big. */
if (unlikely(wc.byte_len > qp->r_len)) {
qp->r_flags |= QIB_R_REUSE_SGE;
ibp->n_pkt_drops++;
- goto bail_unlock;
+ return;
}
if (has_grh) {
qib_copy_sge(&qp->r_sge, &hdr->u.l.grh,
@@ -579,7 +572,7 @@ void qib_ud_rcv(struct qib_ibport *ibp, struct qib_ib_header *hdr,
qp->r_sge.sge = *qp->r_sge.sg_list++;
}
if (!test_and_clear_bit(QIB_R_WRID_VALID, &qp->r_aflags))
- goto bail_unlock;
+ return;
wc.wr_id = qp->r_wr_id;
wc.status = IB_WC_SUCCESS;
wc.opcode = IB_WC_RECV;
@@ -601,7 +594,5 @@ void qib_ud_rcv(struct qib_ibport *ibp, struct qib_ib_header *hdr,
qib_cq_enter(to_icq(qp->ibqp.recv_cq), &wc,
(ohdr->bth[0] &
cpu_to_be32(IB_BTH_SOLICITED)) != 0);
-bail_unlock:
- spin_unlock(&qp->r_lock);
bail:;
}
diff --git a/drivers/infiniband/hw/qib/qib_verbs.c b/drivers/infiniband/hw/qib/qib_verbs.c
index cda8f4173d2..9fab4048885 100644
--- a/drivers/infiniband/hw/qib/qib_verbs.c
+++ b/drivers/infiniband/hw/qib/qib_verbs.c
@@ -550,10 +550,12 @@ static void qib_qp_rcv(struct qib_ctxtdata *rcd, struct qib_ib_header *hdr,
{
struct qib_ibport *ibp = &rcd->ppd->ibport_data;
+ spin_lock(&qp->r_lock);
+
/* Check for valid receive state. */
if (!(ib_qib_state_ops[qp->state] & QIB_PROCESS_RECV_OK)) {
ibp->n_pkt_drops++;
- return;
+ goto unlock;
}
switch (qp->ibqp.qp_type) {
@@ -577,6 +579,9 @@ static void qib_qp_rcv(struct qib_ctxtdata *rcd, struct qib_ib_header *hdr,
default:
break;
}
+
+unlock:
+ spin_unlock(&qp->r_lock);
}
/**
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_ethtool.c b/drivers/infiniband/ulp/ipoib/ipoib_ethtool.c
index 40e858492f9..1a1657c82ed 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_ethtool.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_ethtool.c
@@ -147,6 +147,11 @@ static void ipoib_get_ethtool_stats(struct net_device *dev,
data[index++] = priv->lro.lro_mgr.stats.no_desc;
}
+static int ipoib_set_flags(struct net_device *dev, u32 flags)
+{
+ return ethtool_op_set_flags(dev, flags, ETH_FLAG_LRO);
+}
+
static const struct ethtool_ops ipoib_ethtool_ops = {
.get_drvinfo = ipoib_get_drvinfo,
.get_rx_csum = ipoib_get_rx_csum,
@@ -154,7 +159,7 @@ static const struct ethtool_ops ipoib_ethtool_ops = {
.get_coalesce = ipoib_get_coalesce,
.set_coalesce = ipoib_set_coalesce,
.get_flags = ethtool_op_get_flags,
- .set_flags = ethtool_op_set_flags,
+ .set_flags = ipoib_set_flags,
.get_strings = ipoib_get_strings,
.get_sset_count = ipoib_get_sset_count,
.get_ethtool_stats = ipoib_get_ethtool_stats,
diff --git a/drivers/infiniband/ulp/iser/iser_initiator.c b/drivers/infiniband/ulp/iser/iser_initiator.c
index 0b9ef071658..95a08a8ca8a 100644
--- a/drivers/infiniband/ulp/iser/iser_initiator.c
+++ b/drivers/infiniband/ulp/iser/iser_initiator.c
@@ -170,7 +170,7 @@ static void iser_create_send_desc(struct iser_conn *ib_conn,
}
-int iser_alloc_rx_descriptors(struct iser_conn *ib_conn)
+static int iser_alloc_rx_descriptors(struct iser_conn *ib_conn)
{
int i, j;
u64 dma_addr;
diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c
index ed3f9ebae88..7f8f16bad75 100644
--- a/drivers/infiniband/ulp/srp/ib_srp.c
+++ b/drivers/infiniband/ulp/srp/ib_srp.c
@@ -811,6 +811,38 @@ static int srp_map_data(struct scsi_cmnd *scmnd, struct srp_target_port *target,
return len;
}
+static int srp_post_recv(struct srp_target_port *target)
+{
+ unsigned long flags;
+ struct srp_iu *iu;
+ struct ib_sge list;
+ struct ib_recv_wr wr, *bad_wr;
+ unsigned int next;
+ int ret;
+
+ spin_lock_irqsave(target->scsi_host->host_lock, flags);
+
+ next = target->rx_head & (SRP_RQ_SIZE - 1);
+ wr.wr_id = next;
+ iu = target->rx_ring[next];
+
+ list.addr = iu->dma;
+ list.length = iu->size;
+ list.lkey = target->srp_host->srp_dev->mr->lkey;
+
+ wr.next = NULL;
+ wr.sg_list = &list;
+ wr.num_sge = 1;
+
+ ret = ib_post_recv(target->qp, &wr, &bad_wr);
+ if (!ret)
+ ++target->rx_head;
+
+ spin_unlock_irqrestore(target->scsi_host->host_lock, flags);
+
+ return ret;
+}
+
static void srp_process_rsp(struct srp_target_port *target, struct srp_rsp *rsp)
{
struct srp_request *req;
@@ -868,6 +900,7 @@ static void srp_handle_recv(struct srp_target_port *target, struct ib_wc *wc)
{
struct ib_device *dev;
struct srp_iu *iu;
+ int res;
u8 opcode;
iu = target->rx_ring[wc->wr_id];
@@ -879,21 +912,10 @@ static void srp_handle_recv(struct srp_target_port *target, struct ib_wc *wc)
opcode = *(u8 *) iu->buf;
if (0) {
- int i;
-
shost_printk(KERN_ERR, target->scsi_host,
PFX "recv completion, opcode 0x%02x\n", opcode);
-
- for (i = 0; i < wc->byte_len; ++i) {
- if (i % 8 == 0)
- printk(KERN_ERR " [%02x] ", i);
- printk(" %02x", ((u8 *) iu->buf)[i]);
- if ((i + 1) % 8 == 0)
- printk("\n");
- }
-
- if (wc->byte_len % 8)
- printk("\n");
+ print_hex_dump(KERN_ERR, "", DUMP_PREFIX_OFFSET, 8, 1,
+ iu->buf, wc->byte_len, true);
}
switch (opcode) {
@@ -915,6 +937,11 @@ static void srp_handle_recv(struct srp_target_port *target, struct ib_wc *wc)
ib_dma_sync_single_for_device(dev, iu->dma, target->max_ti_iu_len,
DMA_FROM_DEVICE);
+
+ res = srp_post_recv(target);
+ if (res != 0)
+ shost_printk(KERN_ERR, target->scsi_host,
+ PFX "Recv failed with error code %d\n", res);
}
static void srp_recv_completion(struct ib_cq *cq, void *target_ptr)
@@ -954,45 +981,6 @@ static void srp_send_completion(struct ib_cq *cq, void *target_ptr)
}
}
-static int __srp_post_recv(struct srp_target_port *target)
-{
- struct srp_iu *iu;
- struct ib_sge list;
- struct ib_recv_wr wr, *bad_wr;
- unsigned int next;
- int ret;
-
- next = target->rx_head & (SRP_RQ_SIZE - 1);
- wr.wr_id = next;
- iu = target->rx_ring[next];
-
- list.addr = iu->dma;
- list.length = iu->size;
- list.lkey = target->srp_host->srp_dev->mr->lkey;
-
- wr.next = NULL;
- wr.sg_list = &list;
- wr.num_sge = 1;
-
- ret = ib_post_recv(target->qp, &wr, &bad_wr);
- if (!ret)
- ++target->rx_head;
-
- return ret;
-}
-
-static int srp_post_recv(struct srp_target_port *target)
-{
- unsigned long flags;
- int ret;
-
- spin_lock_irqsave(target->scsi_host->host_lock, flags);
- ret = __srp_post_recv(target);
- spin_unlock_irqrestore(target->scsi_host->host_lock, flags);
-
- return ret;
-}
-
/*
* Must be called with target->scsi_host->host_lock held to protect
* req_lim and tx_head. Lock cannot be dropped between call here and
@@ -1102,11 +1090,6 @@ static int srp_queuecommand(struct scsi_cmnd *scmnd,
goto err;
}
- if (__srp_post_recv(target)) {
- shost_printk(KERN_ERR, target->scsi_host, PFX "Recv failed\n");
- goto err_unmap;
- }
-
ib_dma_sync_single_for_device(dev, iu->dma, srp_max_iu_len,
DMA_TO_DEVICE);
@@ -1249,6 +1232,7 @@ static int srp_cm_handler(struct ib_cm_id *cm_id, struct ib_cm_event *event)
int attr_mask = 0;
int comp = 0;
int opcode = 0;
+ int i;
switch (event->event) {
case IB_CM_REQ_ERROR:
@@ -1298,7 +1282,11 @@ static int srp_cm_handler(struct ib_cm_id *cm_id, struct ib_cm_event *event)
if (target->status)
break;
- target->status = srp_post_recv(target);
+ for (i = 0; i < SRP_RQ_SIZE; i++) {
+ target->status = srp_post_recv(target);
+ if (target->status)
+ break;
+ }
if (target->status)
break;
@@ -1564,6 +1552,18 @@ static ssize_t show_orig_dgid(struct device *dev,
return sprintf(buf, "%pI6\n", target->orig_dgid);
}
+static ssize_t show_req_lim(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct srp_target_port *target = host_to_target(class_to_shost(dev));
+
+ if (target->state == SRP_TARGET_DEAD ||
+ target->state == SRP_TARGET_REMOVED)
+ return -ENODEV;
+
+ return sprintf(buf, "%d\n", target->req_lim);
+}
+
static ssize_t show_zero_req_lim(struct device *dev,
struct device_attribute *attr, char *buf)
{
@@ -1598,6 +1598,7 @@ static DEVICE_ATTR(service_id, S_IRUGO, show_service_id, NULL);
static DEVICE_ATTR(pkey, S_IRUGO, show_pkey, NULL);
static DEVICE_ATTR(dgid, S_IRUGO, show_dgid, NULL);
static DEVICE_ATTR(orig_dgid, S_IRUGO, show_orig_dgid, NULL);
+static DEVICE_ATTR(req_lim, S_IRUGO, show_req_lim, NULL);
static DEVICE_ATTR(zero_req_lim, S_IRUGO, show_zero_req_lim, NULL);
static DEVICE_ATTR(local_ib_port, S_IRUGO, show_local_ib_port, NULL);
static DEVICE_ATTR(local_ib_device, S_IRUGO, show_local_ib_device, NULL);
@@ -1609,6 +1610,7 @@ static struct device_attribute *srp_host_attrs[] = {
&dev_attr_pkey,
&dev_attr_dgid,
&dev_attr_orig_dgid,
+ &dev_attr_req_lim,
&dev_attr_zero_req_lim,
&dev_attr_local_ib_port,
&dev_attr_local_ib_device,
diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c
index 2ee6c7a68bd..054edf346e0 100644
--- a/drivers/input/evdev.c
+++ b/drivers/input/evdev.c
@@ -10,7 +10,8 @@
#define EVDEV_MINOR_BASE 64
#define EVDEV_MINORS 32
-#define EVDEV_BUFFER_SIZE 64
+#define EVDEV_MIN_BUFFER_SIZE 64U
+#define EVDEV_BUF_PACKETS 8
#include <linux/poll.h>
#include <linux/sched.h>
@@ -23,7 +24,6 @@
#include "input-compat.h"
struct evdev {
- int exist;
int open;
int minor;
struct input_handle handle;
@@ -33,16 +33,18 @@ struct evdev {
spinlock_t client_lock; /* protects client_list */
struct mutex mutex;
struct device dev;
+ bool exist;
};
struct evdev_client {
- struct input_event buffer[EVDEV_BUFFER_SIZE];
int head;
int tail;
spinlock_t buffer_lock; /* protects access to buffer, head and tail */
struct fasync_struct *fasync;
struct evdev *evdev;
struct list_head node;
+ int bufsize;
+ struct input_event buffer[];
};
static struct evdev *evdev_table[EVDEV_MINORS];
@@ -52,11 +54,15 @@ static void evdev_pass_event(struct evdev_client *client,
struct input_event *event)
{
/*
- * Interrupts are disabled, just acquire the lock
+ * Interrupts are disabled, just acquire the lock.
+ * Make sure we don't leave with the client buffer
+ * "empty" by having client->head == client->tail.
*/
spin_lock(&client->buffer_lock);
- client->buffer[client->head++] = *event;
- client->head &= EVDEV_BUFFER_SIZE - 1;
+ do {
+ client->buffer[client->head++] = *event;
+ client->head &= client->bufsize - 1;
+ } while (client->head == client->tail);
spin_unlock(&client->buffer_lock);
if (event->type == EV_SYN)
@@ -242,11 +248,21 @@ static int evdev_release(struct inode *inode, struct file *file)
return 0;
}
+static unsigned int evdev_compute_buffer_size(struct input_dev *dev)
+{
+ unsigned int n_events =
+ max(dev->hint_events_per_packet * EVDEV_BUF_PACKETS,
+ EVDEV_MIN_BUFFER_SIZE);
+
+ return roundup_pow_of_two(n_events);
+}
+
static int evdev_open(struct inode *inode, struct file *file)
{
struct evdev *evdev;
struct evdev_client *client;
int i = iminor(inode) - EVDEV_MINOR_BASE;
+ unsigned int bufsize;
int error;
if (i >= EVDEV_MINORS)
@@ -263,12 +279,17 @@ static int evdev_open(struct inode *inode, struct file *file)
if (!evdev)
return -ENODEV;
- client = kzalloc(sizeof(struct evdev_client), GFP_KERNEL);
+ bufsize = evdev_compute_buffer_size(evdev->handle.dev);
+
+ client = kzalloc(sizeof(struct evdev_client) +
+ bufsize * sizeof(struct input_event),
+ GFP_KERNEL);
if (!client) {
error = -ENOMEM;
goto err_put_evdev;
}
+ client->bufsize = bufsize;
spin_lock_init(&client->buffer_lock);
client->evdev = evdev;
evdev_attach_client(evdev, client);
@@ -334,7 +355,7 @@ static int evdev_fetch_next_event(struct evdev_client *client,
have_event = client->head != client->tail;
if (have_event) {
*event = client->buffer[client->tail++];
- client->tail &= EVDEV_BUFFER_SIZE - 1;
+ client->tail &= client->bufsize - 1;
}
spin_unlock_irq(&client->buffer_lock);
@@ -382,10 +403,15 @@ static unsigned int evdev_poll(struct file *file, poll_table *wait)
{
struct evdev_client *client = file->private_data;
struct evdev *evdev = client->evdev;
+ unsigned int mask;
poll_wait(file, &evdev->wait, wait);
- return ((client->head == client->tail) ? 0 : (POLLIN | POLLRDNORM)) |
- (evdev->exist ? 0 : (POLLHUP | POLLERR));
+
+ mask = evdev->exist ? POLLOUT | POLLWRNORM : POLLHUP | POLLERR;
+ if (client->head != client->tail)
+ mask |= POLLIN | POLLRDNORM;
+
+ return mask;
}
#ifdef CONFIG_COMPAT
@@ -665,6 +691,10 @@ static long evdev_do_ioctl(struct file *file, unsigned int cmd,
sizeof(struct input_absinfo))))
return -EFAULT;
+ /* We can't change number of reserved MT slots */
+ if (t == ABS_MT_SLOT)
+ return -EINVAL;
+
/*
* Take event lock to ensure that we are not
* changing device parameters in the middle
@@ -768,7 +798,7 @@ static void evdev_remove_chrdev(struct evdev *evdev)
static void evdev_mark_dead(struct evdev *evdev)
{
mutex_lock(&evdev->mutex);
- evdev->exist = 0;
+ evdev->exist = false;
mutex_unlock(&evdev->mutex);
}
@@ -817,7 +847,7 @@ static int evdev_connect(struct input_handler *handler, struct input_dev *dev,
init_waitqueue_head(&evdev->wait);
dev_set_name(&evdev->dev, "event%d", minor);
- evdev->exist = 1;
+ evdev->exist = true;
evdev->minor = minor;
evdev->handle.dev = input_get_device(dev);
diff --git a/drivers/input/input.c b/drivers/input/input.c
index 9c79bd56b51..e1243b4b32a 100644
--- a/drivers/input/input.c
+++ b/drivers/input/input.c
@@ -33,25 +33,6 @@ MODULE_LICENSE("GPL");
#define INPUT_DEVICES 256
-/*
- * EV_ABS events which should not be cached are listed here.
- */
-static unsigned int input_abs_bypass_init_data[] __initdata = {
- ABS_MT_TOUCH_MAJOR,
- ABS_MT_TOUCH_MINOR,
- ABS_MT_WIDTH_MAJOR,
- ABS_MT_WIDTH_MINOR,
- ABS_MT_ORIENTATION,
- ABS_MT_POSITION_X,
- ABS_MT_POSITION_Y,
- ABS_MT_TOOL_TYPE,
- ABS_MT_BLOB_ID,
- ABS_MT_TRACKING_ID,
- ABS_MT_PRESSURE,
- 0
-};
-static unsigned long input_abs_bypass[BITS_TO_LONGS(ABS_CNT)];
-
static LIST_HEAD(input_dev_list);
static LIST_HEAD(input_handler_list);
@@ -181,6 +162,56 @@ static void input_stop_autorepeat(struct input_dev *dev)
#define INPUT_PASS_TO_DEVICE 2
#define INPUT_PASS_TO_ALL (INPUT_PASS_TO_HANDLERS | INPUT_PASS_TO_DEVICE)
+static int input_handle_abs_event(struct input_dev *dev,
+ unsigned int code, int *pval)
+{
+ bool is_mt_event;
+ int *pold;
+
+ if (code == ABS_MT_SLOT) {
+ /*
+ * "Stage" the event; we'll flush it later, when we
+ * get actiual touch data.
+ */
+ if (*pval >= 0 && *pval < dev->mtsize)
+ dev->slot = *pval;
+
+ return INPUT_IGNORE_EVENT;
+ }
+
+ is_mt_event = code >= ABS_MT_FIRST && code <= ABS_MT_LAST;
+
+ if (!is_mt_event) {
+ pold = &dev->abs[code];
+ } else if (dev->mt) {
+ struct input_mt_slot *mtslot = &dev->mt[dev->slot];
+ pold = &mtslot->abs[code - ABS_MT_FIRST];
+ } else {
+ /*
+ * Bypass filtering for multitouch events when
+ * not employing slots.
+ */
+ pold = NULL;
+ }
+
+ if (pold) {
+ *pval = input_defuzz_abs_event(*pval, *pold,
+ dev->absfuzz[code]);
+ if (*pold == *pval)
+ return INPUT_IGNORE_EVENT;
+
+ *pold = *pval;
+ }
+
+ /* Flush pending "slot" event */
+ if (is_mt_event && dev->slot != dev->abs[ABS_MT_SLOT]) {
+ dev->abs[ABS_MT_SLOT] = dev->slot;
+ input_pass_event(dev, EV_ABS, ABS_MT_SLOT, dev->slot);
+ }
+
+ return INPUT_PASS_TO_HANDLERS;
+}
+
static void input_handle_event(struct input_dev *dev,
unsigned int type, unsigned int code, int value)
{
@@ -196,12 +227,12 @@ static void input_handle_event(struct input_dev *dev,
case SYN_REPORT:
if (!dev->sync) {
- dev->sync = 1;
+ dev->sync = true;
disposition = INPUT_PASS_TO_HANDLERS;
}
break;
case SYN_MT_REPORT:
- dev->sync = 0;
+ dev->sync = false;
disposition = INPUT_PASS_TO_HANDLERS;
break;
}
@@ -233,21 +264,9 @@ static void input_handle_event(struct input_dev *dev,
break;
case EV_ABS:
- if (is_event_supported(code, dev->absbit, ABS_MAX)) {
-
- if (test_bit(code, input_abs_bypass)) {
- disposition = INPUT_PASS_TO_HANDLERS;
- break;
- }
+ if (is_event_supported(code, dev->absbit, ABS_MAX))
+ disposition = input_handle_abs_event(dev, code, &value);
- value = input_defuzz_abs_event(value,
- dev->abs[code], dev->absfuzz[code]);
-
- if (dev->abs[code] != value) {
- dev->abs[code] = value;
- disposition = INPUT_PASS_TO_HANDLERS;
- }
- }
break;
case EV_REL:
@@ -298,7 +317,7 @@ static void input_handle_event(struct input_dev *dev,
}
if (disposition != INPUT_IGNORE_EVENT && type != EV_SYN)
- dev->sync = 0;
+ dev->sync = false;
if ((disposition & INPUT_PASS_TO_DEVICE) && dev->event)
dev->event(dev, type, code, value);
@@ -528,12 +547,30 @@ void input_close_device(struct input_handle *handle)
EXPORT_SYMBOL(input_close_device);
/*
+ * Simulate keyup events for all keys that are marked as pressed.
+ * The function must be called with dev->event_lock held.
+ */
+static void input_dev_release_keys(struct input_dev *dev)
+{
+ int code;
+
+ if (is_event_supported(EV_KEY, dev->evbit, EV_MAX)) {
+ for (code = 0; code <= KEY_MAX; code++) {
+ if (is_event_supported(code, dev->keybit, KEY_MAX) &&
+ __test_and_clear_bit(code, dev->key)) {
+ input_pass_event(dev, EV_KEY, code, 0);
+ }
+ }
+ input_pass_event(dev, EV_SYN, SYN_REPORT, 1);
+ }
+}
+
+/*
* Prepare device for unregistering
*/
static void input_disconnect_device(struct input_dev *dev)
{
struct input_handle *handle;
- int code;
/*
* Mark device as going away. Note that we take dev->mutex here
@@ -552,15 +589,7 @@ static void input_disconnect_device(struct input_dev *dev)
* generate events even after we done here but they will not
* reach any handlers.
*/
- if (is_event_supported(EV_KEY, dev->evbit, EV_MAX)) {
- for (code = 0; code <= KEY_MAX; code++) {
- if (is_event_supported(code, dev->keybit, KEY_MAX) &&
- __test_and_clear_bit(code, dev->key)) {
- input_pass_event(dev, EV_KEY, code, 0);
- }
- }
- input_pass_event(dev, EV_SYN, SYN_REPORT, 1);
- }
+ input_dev_release_keys(dev);
list_for_each_entry(handle, &dev->h_list, d_node)
handle->open = 0;
@@ -684,7 +713,7 @@ int input_set_keycode(struct input_dev *dev,
unsigned int scancode, unsigned int keycode)
{
unsigned long flags;
- int old_keycode;
+ unsigned int old_keycode;
int retval;
if (keycode > KEY_MAX)
@@ -1278,6 +1307,7 @@ static void input_dev_release(struct device *device)
struct input_dev *dev = to_input_dev(device);
input_ff_destroy(dev);
+ input_mt_destroy_slots(dev);
kfree(dev);
module_put(THIS_MODULE);
@@ -1433,6 +1463,15 @@ static int input_dev_resume(struct device *dev)
mutex_lock(&input_dev->mutex);
input_dev_reset(input_dev, true);
+
+ /*
+ * Keys that have been pressed at suspend time are unlikely
+ * to be still pressed when we resume.
+ */
+ spin_lock_irq(&input_dev->event_lock);
+ input_dev_release_keys(input_dev);
+ spin_unlock_irq(&input_dev->event_lock);
+
mutex_unlock(&input_dev->mutex);
return 0;
@@ -1518,6 +1557,45 @@ void input_free_device(struct input_dev *dev)
EXPORT_SYMBOL(input_free_device);
/**
+ * input_mt_create_slots() - create MT input slots
+ * @dev: input device supporting MT events and finger tracking
+ * @num_slots: number of slots used by the device
+ *
+ * This function allocates all necessary memory for MT slot handling
+ * in the input device, and adds ABS_MT_SLOT to the device capabilities.
+ */
+int input_mt_create_slots(struct input_dev *dev, unsigned int num_slots)
+{
+ if (!num_slots)
+ return 0;
+
+ dev->mt = kcalloc(num_slots, sizeof(struct input_mt_slot), GFP_KERNEL);
+ if (!dev->mt)
+ return -ENOMEM;
+
+ dev->mtsize = num_slots;
+ input_set_abs_params(dev, ABS_MT_SLOT, 0, num_slots - 1, 0, 0);
+
+ return 0;
+}
+EXPORT_SYMBOL(input_mt_create_slots);
+
+/**
+ * input_mt_destroy_slots() - frees the MT slots of the input device
+ * @dev: input device with allocated MT slots
+ *
+ * This function is only needed in error path as the input core will
+ * automatically free the MT slots when the device is destroyed.
+ */
+void input_mt_destroy_slots(struct input_dev *dev)
+{
+ kfree(dev->mt);
+ dev->mt = NULL;
+ dev->mtsize = 0;
+}
+EXPORT_SYMBOL(input_mt_destroy_slots);
+
+/**
* input_set_capability - mark device as capable of a certain event
* @dev: device that is capable of emitting or accepting event
* @type: type of the event (EV_KEY, EV_REL, etc...)
@@ -1926,20 +2004,10 @@ static const struct file_operations input_fops = {
.open = input_open_file,
};
-static void __init input_init_abs_bypass(void)
-{
- const unsigned int *p;
-
- for (p = input_abs_bypass_init_data; *p; p++)
- input_abs_bypass[BIT_WORD(*p)] |= BIT_MASK(*p);
-}
-
static int __init input_init(void)
{
int err;
- input_init_abs_bypass();
-
err = class_register(&input_class);
if (err) {
printk(KERN_ERR "input: unable to register input_dev class\n");
diff --git a/drivers/input/joydev.c b/drivers/input/joydev.c
index 34157bb97ed..63834585c28 100644
--- a/drivers/input/joydev.c
+++ b/drivers/input/joydev.c
@@ -37,7 +37,6 @@ MODULE_LICENSE("GPL");
#define JOYDEV_BUFFER_SIZE 64
struct joydev {
- int exist;
int open;
int minor;
struct input_handle handle;
@@ -46,6 +45,7 @@ struct joydev {
spinlock_t client_lock; /* protects client_list */
struct mutex mutex;
struct device dev;
+ bool exist;
struct js_corr corr[ABS_CNT];
struct JS_DATA_SAVE_TYPE glue;
@@ -760,7 +760,7 @@ static void joydev_remove_chrdev(struct joydev *joydev)
static void joydev_mark_dead(struct joydev *joydev)
{
mutex_lock(&joydev->mutex);
- joydev->exist = 0;
+ joydev->exist = false;
mutex_unlock(&joydev->mutex);
}
@@ -817,10 +817,9 @@ static int joydev_connect(struct input_handler *handler, struct input_dev *dev,
init_waitqueue_head(&joydev->wait);
dev_set_name(&joydev->dev, "js%d", minor);
- joydev->exist = 1;
+ joydev->exist = true;
joydev->minor = minor;
- joydev->exist = 1;
joydev->handle.dev = input_get_device(dev);
joydev->handle.name = dev_name(&joydev->dev);
joydev->handle.handler = handler;
diff --git a/drivers/input/joystick/xpad.c b/drivers/input/joystick/xpad.c
index c1087ce4cef..269a846f369 100644
--- a/drivers/input/joystick/xpad.c
+++ b/drivers/input/joystick/xpad.c
@@ -9,6 +9,7 @@
* 2005 Dominic Cerquetti <binary1230@yahoo.com>
* 2006 Adam Buchbinder <adam.buchbinder@gmail.com>
* 2007 Jan Kratochvil <honza@jikos.cz>
+ * 2010 Christoph Fritz <chf.fritz@googlemail.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
@@ -88,6 +89,9 @@
but we map them to axes when possible to simplify things */
#define MAP_DPAD_TO_BUTTONS (1 << 0)
#define MAP_TRIGGERS_TO_BUTTONS (1 << 1)
+#define MAP_STICKS_TO_NULL (1 << 2)
+#define DANCEPAD_MAP_CONFIG (MAP_DPAD_TO_BUTTONS | \
+ MAP_TRIGGERS_TO_BUTTONS | MAP_STICKS_TO_NULL)
#define XTYPE_XBOX 0
#define XTYPE_XBOX360 1
@@ -102,6 +106,10 @@ static int triggers_to_buttons;
module_param(triggers_to_buttons, bool, S_IRUGO);
MODULE_PARM_DESC(triggers_to_buttons, "Map triggers to buttons rather than axes for unknown pads");
+static int sticks_to_null;
+module_param(sticks_to_null, bool, S_IRUGO);
+MODULE_PARM_DESC(sticks_to_null, "Do not map sticks at all for unknown pads");
+
static const struct xpad_device {
u16 idVendor;
u16 idProduct;
@@ -114,7 +122,7 @@ static const struct xpad_device {
{ 0x045e, 0x0285, "Microsoft X-Box pad (Japan)", 0, XTYPE_XBOX },
{ 0x045e, 0x0287, "Microsoft Xbox Controller S", 0, XTYPE_XBOX },
{ 0x045e, 0x0719, "Xbox 360 Wireless Receiver", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360W },
- { 0x0c12, 0x8809, "RedOctane Xbox Dance Pad", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX },
+ { 0x0c12, 0x8809, "RedOctane Xbox Dance Pad", DANCEPAD_MAP_CONFIG, XTYPE_XBOX },
{ 0x044f, 0x0f07, "Thrustmaster, Inc. Controller", 0, XTYPE_XBOX },
{ 0x046d, 0xc242, "Logitech Chillstream Controller", 0, XTYPE_XBOX360 },
{ 0x046d, 0xca84, "Logitech Xbox Cordless Controller", 0, XTYPE_XBOX },
@@ -151,6 +159,7 @@ static const struct xpad_device {
{ 0x045e, 0x028e, "Microsoft X-Box 360 pad", 0, XTYPE_XBOX360 },
{ 0x1bad, 0x0003, "Harmonix Rock Band Drumkit", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360 },
{ 0x0f0d, 0x0016, "Hori Real Arcade Pro.EX", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 },
+ { 0x0f0d, 0x000d, "Hori Fighting Stick EX2", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 },
{ 0xffff, 0xffff, "Chinese-made Xbox Controller", 0, XTYPE_XBOX },
{ 0x0000, 0x0000, "Generic X-Box pad", 0, XTYPE_UNKNOWN }
};
@@ -158,7 +167,7 @@ static const struct xpad_device {
/* buttons shared with xbox and xbox360 */
static const signed short xpad_common_btn[] = {
BTN_A, BTN_B, BTN_X, BTN_Y, /* "analog" buttons */
- BTN_START, BTN_BACK, BTN_THUMBL, BTN_THUMBR, /* start/back/sticks */
+ BTN_START, BTN_SELECT, BTN_THUMBL, BTN_THUMBR, /* start/back/sticks */
-1 /* terminating entry */
};
@@ -168,10 +177,10 @@ static const signed short xpad_btn[] = {
-1 /* terminating entry */
};
-/* used when dpad is mapped to nuttons */
+/* used when dpad is mapped to buttons */
static const signed short xpad_btn_pad[] = {
- BTN_LEFT, BTN_RIGHT, /* d-pad left, right */
- BTN_0, BTN_1, /* d-pad up, down (XXX names??) */
+ BTN_TRIGGER_HAPPY1, BTN_TRIGGER_HAPPY2, /* d-pad left, right */
+ BTN_TRIGGER_HAPPY3, BTN_TRIGGER_HAPPY4, /* d-pad up, down */
-1 /* terminating entry */
};
@@ -279,17 +288,19 @@ static void xpad_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char *d
{
struct input_dev *dev = xpad->dev;
- /* left stick */
- input_report_abs(dev, ABS_X,
- (__s16) le16_to_cpup((__le16 *)(data + 12)));
- input_report_abs(dev, ABS_Y,
- ~(__s16) le16_to_cpup((__le16 *)(data + 14)));
-
- /* right stick */
- input_report_abs(dev, ABS_RX,
- (__s16) le16_to_cpup((__le16 *)(data + 16)));
- input_report_abs(dev, ABS_RY,
- ~(__s16) le16_to_cpup((__le16 *)(data + 18)));
+ if (!(xpad->mapping & MAP_STICKS_TO_NULL)) {
+ /* left stick */
+ input_report_abs(dev, ABS_X,
+ (__s16) le16_to_cpup((__le16 *)(data + 12)));
+ input_report_abs(dev, ABS_Y,
+ ~(__s16) le16_to_cpup((__le16 *)(data + 14)));
+
+ /* right stick */
+ input_report_abs(dev, ABS_RX,
+ (__s16) le16_to_cpup((__le16 *)(data + 16)));
+ input_report_abs(dev, ABS_RY,
+ ~(__s16) le16_to_cpup((__le16 *)(data + 18)));
+ }
/* triggers left/right */
if (xpad->mapping & MAP_TRIGGERS_TO_BUTTONS) {
@@ -302,10 +313,11 @@ static void xpad_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char *d
/* digital pad */
if (xpad->mapping & MAP_DPAD_TO_BUTTONS) {
- input_report_key(dev, BTN_LEFT, data[2] & 0x04);
- input_report_key(dev, BTN_RIGHT, data[2] & 0x08);
- input_report_key(dev, BTN_0, data[2] & 0x01); /* up */
- input_report_key(dev, BTN_1, data[2] & 0x02); /* down */
+ /* dpad as buttons (left, right, up, down) */
+ input_report_key(dev, BTN_TRIGGER_HAPPY1, data[2] & 0x04);
+ input_report_key(dev, BTN_TRIGGER_HAPPY2, data[2] & 0x08);
+ input_report_key(dev, BTN_TRIGGER_HAPPY3, data[2] & 0x01);
+ input_report_key(dev, BTN_TRIGGER_HAPPY4, data[2] & 0x02);
} else {
input_report_abs(dev, ABS_HAT0X,
!!(data[2] & 0x08) - !!(data[2] & 0x04));
@@ -315,7 +327,7 @@ static void xpad_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char *d
/* start/back buttons and stick press left/right */
input_report_key(dev, BTN_START, data[2] & 0x10);
- input_report_key(dev, BTN_BACK, data[2] & 0x20);
+ input_report_key(dev, BTN_SELECT, data[2] & 0x20);
input_report_key(dev, BTN_THUMBL, data[2] & 0x40);
input_report_key(dev, BTN_THUMBR, data[2] & 0x80);
@@ -349,11 +361,11 @@ static void xpad360_process_packet(struct usb_xpad *xpad,
/* digital pad */
if (xpad->mapping & MAP_DPAD_TO_BUTTONS) {
- /* dpad as buttons (right, left, down, up) */
- input_report_key(dev, BTN_LEFT, data[2] & 0x04);
- input_report_key(dev, BTN_RIGHT, data[2] & 0x08);
- input_report_key(dev, BTN_0, data[2] & 0x01); /* up */
- input_report_key(dev, BTN_1, data[2] & 0x02); /* down */
+ /* dpad as buttons (left, right, up, down) */
+ input_report_key(dev, BTN_TRIGGER_HAPPY1, data[2] & 0x04);
+ input_report_key(dev, BTN_TRIGGER_HAPPY2, data[2] & 0x08);
+ input_report_key(dev, BTN_TRIGGER_HAPPY3, data[2] & 0x01);
+ input_report_key(dev, BTN_TRIGGER_HAPPY4, data[2] & 0x02);
} else {
input_report_abs(dev, ABS_HAT0X,
!!(data[2] & 0x08) - !!(data[2] & 0x04));
@@ -363,7 +375,7 @@ static void xpad360_process_packet(struct usb_xpad *xpad,
/* start/back buttons */
input_report_key(dev, BTN_START, data[2] & 0x10);
- input_report_key(dev, BTN_BACK, data[2] & 0x20);
+ input_report_key(dev, BTN_SELECT, data[2] & 0x20);
/* stick press left/right */
input_report_key(dev, BTN_THUMBL, data[2] & 0x40);
@@ -378,17 +390,19 @@ static void xpad360_process_packet(struct usb_xpad *xpad,
input_report_key(dev, BTN_TR, data[3] & 0x02);
input_report_key(dev, BTN_MODE, data[3] & 0x04);
- /* left stick */
- input_report_abs(dev, ABS_X,
- (__s16) le16_to_cpup((__le16 *)(data + 6)));
- input_report_abs(dev, ABS_Y,
- ~(__s16) le16_to_cpup((__le16 *)(data + 8)));
-
- /* right stick */
- input_report_abs(dev, ABS_RX,
- (__s16) le16_to_cpup((__le16 *)(data + 10)));
- input_report_abs(dev, ABS_RY,
- ~(__s16) le16_to_cpup((__le16 *)(data + 12)));
+ if (!(xpad->mapping & MAP_STICKS_TO_NULL)) {
+ /* left stick */
+ input_report_abs(dev, ABS_X,
+ (__s16) le16_to_cpup((__le16 *)(data + 6)));
+ input_report_abs(dev, ABS_Y,
+ ~(__s16) le16_to_cpup((__le16 *)(data + 8)));
+
+ /* right stick */
+ input_report_abs(dev, ABS_RX,
+ (__s16) le16_to_cpup((__le16 *)(data + 10)));
+ input_report_abs(dev, ABS_RY,
+ ~(__s16) le16_to_cpup((__le16 *)(data + 12)));
+ }
/* triggers left/right */
if (xpad->mapping & MAP_TRIGGERS_TO_BUTTONS) {
@@ -814,6 +828,8 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id
xpad->mapping |= MAP_DPAD_TO_BUTTONS;
if (triggers_to_buttons)
xpad->mapping |= MAP_TRIGGERS_TO_BUTTONS;
+ if (sticks_to_null)
+ xpad->mapping |= MAP_STICKS_TO_NULL;
}
xpad->dev = input_dev;
@@ -830,16 +846,20 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id
input_dev->open = xpad_open;
input_dev->close = xpad_close;
- input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
+ input_dev->evbit[0] = BIT_MASK(EV_KEY);
+
+ if (!(xpad->mapping & MAP_STICKS_TO_NULL)) {
+ input_dev->evbit[0] |= BIT_MASK(EV_ABS);
+ /* set up axes */
+ for (i = 0; xpad_abs[i] >= 0; i++)
+ xpad_set_up_abs(input_dev, xpad_abs[i]);
+ }
- /* set up standard buttons and axes */
+ /* set up standard buttons */
for (i = 0; xpad_common_btn[i] >= 0; i++)
__set_bit(xpad_common_btn[i], input_dev->keybit);
- for (i = 0; xpad_abs[i] >= 0; i++)
- xpad_set_up_abs(input_dev, xpad_abs[i]);
-
- /* Now set up model-specific ones */
+ /* set up model-specific ones */
if (xpad->xtype == XTYPE_XBOX360 || xpad->xtype == XTYPE_XBOX360W) {
for (i = 0; xpad360_btn[i] >= 0; i++)
__set_bit(xpad360_btn[i], input_dev->keybit);
diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig
index 1ba25145b33..b171f63fe4d 100644
--- a/drivers/input/keyboard/Kconfig
+++ b/drivers/input/keyboard/Kconfig
@@ -297,6 +297,18 @@ config KEYBOARD_MAX7359
To compile this driver as a module, choose M here: the
module will be called max7359_keypad.
+config KEYBOARD_MCS
+ tristate "MELFAS MCS Touchkey"
+ depends on I2C
+ help
+ Say Y here if you have the MELFAS MCS5000/5080 touchkey controller
+ chip in your system.
+
+ If unsure, say N.
+
+ To compile this driver as a module, choose M here: the
+ module will be called mcs_touchkey.
+
config KEYBOARD_IMX
tristate "IMX keypad support"
depends on ARCH_MXC
@@ -342,6 +354,15 @@ config KEYBOARD_PXA930_ROTARY
To compile this driver as a module, choose M here: the
module will be called pxa930_rotary.
+config KEYBOARD_SAMSUNG
+ tristate "Samsung keypad support"
+ depends on SAMSUNG_DEV_KEYPAD
+ help
+ Say Y here if you want to use the Samsung keypad.
+
+ To compile this driver as a module, choose M here: the
+ module will be called samsung-keypad.
+
config KEYBOARD_STOWAWAY
tristate "Stowaway keyboard"
select SERIO
diff --git a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile
index 4596d0c6f92..1a66d5f1ca8 100644
--- a/drivers/input/keyboard/Makefile
+++ b/drivers/input/keyboard/Makefile
@@ -26,12 +26,14 @@ obj-$(CONFIG_KEYBOARD_LOCOMO) += locomokbd.o
obj-$(CONFIG_KEYBOARD_MAPLE) += maple_keyb.o
obj-$(CONFIG_KEYBOARD_MATRIX) += matrix_keypad.o
obj-$(CONFIG_KEYBOARD_MAX7359) += max7359_keypad.o
+obj-$(CONFIG_KEYBOARD_MCS) += mcs_touchkey.o
obj-$(CONFIG_KEYBOARD_NEWTON) += newtonkbd.o
obj-$(CONFIG_KEYBOARD_OMAP) += omap-keypad.o
obj-$(CONFIG_KEYBOARD_OPENCORES) += opencores-kbd.o
obj-$(CONFIG_KEYBOARD_PXA27x) += pxa27x_keypad.o
obj-$(CONFIG_KEYBOARD_PXA930_ROTARY) += pxa930_rotary.o
obj-$(CONFIG_KEYBOARD_QT2160) += qt2160.o
+obj-$(CONFIG_KEYBOARD_SAMSUNG) += samsung-keypad.o
obj-$(CONFIG_KEYBOARD_SH_KEYSC) += sh_keysc.o
obj-$(CONFIG_KEYBOARD_STOWAWAY) += stowaway.o
obj-$(CONFIG_KEYBOARD_SUNKBD) += sunkbd.o
diff --git a/drivers/input/keyboard/adp5588-keys.c b/drivers/input/keyboard/adp5588-keys.c
index 744600eff22..d6918cb966c 100644
--- a/drivers/input/keyboard/adp5588-keys.c
+++ b/drivers/input/keyboard/adp5588-keys.c
@@ -19,6 +19,7 @@
#include <linux/platform_device.h>
#include <linux/input.h>
#include <linux/i2c.h>
+#include <linux/gpio.h>
#include <linux/slab.h>
#include <linux/i2c/adp5588.h>
@@ -54,6 +55,10 @@
#define KEYP_MAX_EVENT 10
+#define MAXGPIO 18
+#define ADP_BANK(offs) ((offs) >> 3)
+#define ADP_BIT(offs) (1u << ((offs) & 0x7))
+
/*
* Early pre 4.0 Silicon required to delay readout by at least 25ms,
* since the Event Counter Register updated 25ms after the interrupt
@@ -67,6 +72,16 @@ struct adp5588_kpad {
struct delayed_work work;
unsigned long delay;
unsigned short keycode[ADP5588_KEYMAPSIZE];
+ const struct adp5588_gpi_map *gpimap;
+ unsigned short gpimapsize;
+#ifdef CONFIG_GPIOLIB
+ unsigned char gpiomap[MAXGPIO];
+ bool export_gpio;
+ struct gpio_chip gc;
+ struct mutex gpio_lock; /* Protect cached dir, dat_out */
+ u8 dat_out[3];
+ u8 dir[3];
+#endif
};
static int adp5588_read(struct i2c_client *client, u8 reg)
@@ -84,12 +99,222 @@ static int adp5588_write(struct i2c_client *client, u8 reg, u8 val)
return i2c_smbus_write_byte_data(client, reg, val);
}
+#ifdef CONFIG_GPIOLIB
+static int adp5588_gpio_get_value(struct gpio_chip *chip, unsigned off)
+{
+ struct adp5588_kpad *kpad = container_of(chip, struct adp5588_kpad, gc);
+ unsigned int bank = ADP_BANK(kpad->gpiomap[off]);
+ unsigned int bit = ADP_BIT(kpad->gpiomap[off]);
+
+ return !!(adp5588_read(kpad->client, GPIO_DAT_STAT1 + bank) & bit);
+}
+
+static void adp5588_gpio_set_value(struct gpio_chip *chip,
+ unsigned off, int val)
+{
+ struct adp5588_kpad *kpad = container_of(chip, struct adp5588_kpad, gc);
+ unsigned int bank = ADP_BANK(kpad->gpiomap[off]);
+ unsigned int bit = ADP_BIT(kpad->gpiomap[off]);
+
+ mutex_lock(&kpad->gpio_lock);
+
+ if (val)
+ kpad->dat_out[bank] |= bit;
+ else
+ kpad->dat_out[bank] &= ~bit;
+
+ adp5588_write(kpad->client, GPIO_DAT_OUT1 + bank,
+ kpad->dat_out[bank]);
+
+ mutex_unlock(&kpad->gpio_lock);
+}
+
+static int adp5588_gpio_direction_input(struct gpio_chip *chip, unsigned off)
+{
+ struct adp5588_kpad *kpad = container_of(chip, struct adp5588_kpad, gc);
+ unsigned int bank = ADP_BANK(kpad->gpiomap[off]);
+ unsigned int bit = ADP_BIT(kpad->gpiomap[off]);
+ int ret;
+
+ mutex_lock(&kpad->gpio_lock);
+
+ kpad->dir[bank] &= ~bit;
+ ret = adp5588_write(kpad->client, GPIO_DIR1 + bank, kpad->dir[bank]);
+
+ mutex_unlock(&kpad->gpio_lock);
+
+ return ret;
+}
+
+static int adp5588_gpio_direction_output(struct gpio_chip *chip,
+ unsigned off, int val)
+{
+ struct adp5588_kpad *kpad = container_of(chip, struct adp5588_kpad, gc);
+ unsigned int bank = ADP_BANK(kpad->gpiomap[off]);
+ unsigned int bit = ADP_BIT(kpad->gpiomap[off]);
+ int ret;
+
+ mutex_lock(&kpad->gpio_lock);
+
+ kpad->dir[bank] |= bit;
+
+ if (val)
+ kpad->dat_out[bank] |= bit;
+ else
+ kpad->dat_out[bank] &= ~bit;
+
+ ret = adp5588_write(kpad->client, GPIO_DAT_OUT1 + bank,
+ kpad->dat_out[bank]);
+ ret |= adp5588_write(kpad->client, GPIO_DIR1 + bank,
+ kpad->dir[bank]);
+
+ mutex_unlock(&kpad->gpio_lock);
+
+ return ret;
+}
+
+static int __devinit adp5588_build_gpiomap(struct adp5588_kpad *kpad,
+ const struct adp5588_kpad_platform_data *pdata)
+{
+ bool pin_used[MAXGPIO];
+ int n_unused = 0;
+ int i;
+
+ memset(pin_used, 0, sizeof(pin_used));
+
+ for (i = 0; i < pdata->rows; i++)
+ pin_used[i] = true;
+
+ for (i = 0; i < pdata->cols; i++)
+ pin_used[i + GPI_PIN_COL_BASE - GPI_PIN_BASE] = true;
+
+ for (i = 0; i < kpad->gpimapsize; i++)
+ pin_used[kpad->gpimap[i].pin - GPI_PIN_BASE] = true;
+
+ for (i = 0; i < MAXGPIO; i++)
+ if (!pin_used[i])
+ kpad->gpiomap[n_unused++] = i;
+
+ return n_unused;
+}
+
+static int __devinit adp5588_gpio_add(struct adp5588_kpad *kpad)
+{
+ struct device *dev = &kpad->client->dev;
+ const struct adp5588_kpad_platform_data *pdata = dev->platform_data;
+ const struct adp5588_gpio_platform_data *gpio_data = pdata->gpio_data;
+ int i, error;
+
+ if (!gpio_data)
+ return 0;
+
+ kpad->gc.ngpio = adp5588_build_gpiomap(kpad, pdata);
+ if (kpad->gc.ngpio == 0) {
+ dev_info(dev, "No unused gpios left to export\n");
+ return 0;
+ }
+
+ kpad->export_gpio = true;
+
+ kpad->gc.direction_input = adp5588_gpio_direction_input;
+ kpad->gc.direction_output = adp5588_gpio_direction_output;
+ kpad->gc.get = adp5588_gpio_get_value;
+ kpad->gc.set = adp5588_gpio_set_value;
+ kpad->gc.can_sleep = 1;
+
+ kpad->gc.base = gpio_data->gpio_start;
+ kpad->gc.label = kpad->client->name;
+ kpad->gc.owner = THIS_MODULE;
+
+ mutex_init(&kpad->gpio_lock);
+
+ error = gpiochip_add(&kpad->gc);
+ if (error) {
+ dev_err(dev, "gpiochip_add failed, err: %d\n", error);
+ return error;
+ }
+
+ for (i = 0; i <= ADP_BANK(MAXGPIO); i++) {
+ kpad->dat_out[i] = adp5588_read(kpad->client,
+ GPIO_DAT_OUT1 + i);
+ kpad->dir[i] = adp5588_read(kpad->client, GPIO_DIR1 + i);
+ }
+
+ if (gpio_data->setup) {
+ error = gpio_data->setup(kpad->client,
+ kpad->gc.base, kpad->gc.ngpio,
+ gpio_data->context);
+ if (error)
+ dev_warn(dev, "setup failed, %d\n", error);
+ }
+
+ return 0;
+}
+
+static void __devexit adp5588_gpio_remove(struct adp5588_kpad *kpad)
+{
+ struct device *dev = &kpad->client->dev;
+ const struct adp5588_kpad_platform_data *pdata = dev->platform_data;
+ const struct adp5588_gpio_platform_data *gpio_data = pdata->gpio_data;
+ int error;
+
+ if (!kpad->export_gpio)
+ return;
+
+ if (gpio_data->teardown) {
+ error = gpio_data->teardown(kpad->client,
+ kpad->gc.base, kpad->gc.ngpio,
+ gpio_data->context);
+ if (error)
+ dev_warn(dev, "teardown failed %d\n", error);
+ }
+
+ error = gpiochip_remove(&kpad->gc);
+ if (error)
+ dev_warn(dev, "gpiochip_remove failed %d\n", error);
+}
+#else
+static inline int adp5588_gpio_add(struct adp5588_kpad *kpad)
+{
+ return 0;
+}
+
+static inline void adp5588_gpio_remove(struct adp5588_kpad *kpad)
+{
+}
+#endif
+
+static void adp5588_report_events(struct adp5588_kpad *kpad, int ev_cnt)
+{
+ int i, j;
+
+ for (i = 0; i < ev_cnt; i++) {
+ int key = adp5588_read(kpad->client, Key_EVENTA + i);
+ int key_val = key & KEY_EV_MASK;
+
+ if (key_val >= GPI_PIN_BASE && key_val <= GPI_PIN_END) {
+ for (j = 0; j < kpad->gpimapsize; j++) {
+ if (key_val == kpad->gpimap[j].pin) {
+ input_report_switch(kpad->input,
+ kpad->gpimap[j].sw_evt,
+ key & KEY_EV_PRESSED);
+ break;
+ }
+ }
+ } else {
+ input_report_key(kpad->input,
+ kpad->keycode[key_val - 1],
+ key & KEY_EV_PRESSED);
+ }
+ }
+}
+
static void adp5588_work(struct work_struct *work)
{
struct adp5588_kpad *kpad = container_of(work,
struct adp5588_kpad, work.work);
struct i2c_client *client = kpad->client;
- int i, key, status, ev_cnt;
+ int status, ev_cnt;
status = adp5588_read(client, INT_STAT);
@@ -99,12 +324,7 @@ static void adp5588_work(struct work_struct *work)
if (status & KE_INT) {
ev_cnt = adp5588_read(client, KEY_LCK_EC_STAT) & KEC;
if (ev_cnt) {
- for (i = 0; i < ev_cnt; i++) {
- key = adp5588_read(client, Key_EVENTA + i);
- input_report_key(kpad->input,
- kpad->keycode[(key & KEY_EV_MASK) - 1],
- key & KEY_EV_PRESSED);
- }
+ adp5588_report_events(kpad, ev_cnt);
input_sync(kpad->input);
}
}
@@ -128,8 +348,10 @@ static irqreturn_t adp5588_irq(int irq, void *handle)
static int __devinit adp5588_setup(struct i2c_client *client)
{
- struct adp5588_kpad_platform_data *pdata = client->dev.platform_data;
+ const struct adp5588_kpad_platform_data *pdata = client->dev.platform_data;
+ const struct adp5588_gpio_platform_data *gpio_data = pdata->gpio_data;
int i, ret;
+ unsigned char evt_mode1 = 0, evt_mode2 = 0, evt_mode3 = 0;
ret = adp5588_write(client, KP_GPIO1, KP_SEL(pdata->rows));
ret |= adp5588_write(client, KP_GPIO2, KP_SEL(pdata->cols) & 0xFF);
@@ -144,6 +366,32 @@ static int __devinit adp5588_setup(struct i2c_client *client)
for (i = 0; i < KEYP_MAX_EVENT; i++)
ret |= adp5588_read(client, Key_EVENTA);
+ for (i = 0; i < pdata->gpimapsize; i++) {
+ unsigned short pin = pdata->gpimap[i].pin;
+
+ if (pin <= GPI_PIN_ROW_END) {
+ evt_mode1 |= (1 << (pin - GPI_PIN_ROW_BASE));
+ } else {
+ evt_mode2 |= ((1 << (pin - GPI_PIN_COL_BASE)) & 0xFF);
+ evt_mode3 |= ((1 << (pin - GPI_PIN_COL_BASE)) >> 8);
+ }
+ }
+
+ if (pdata->gpimapsize) {
+ ret |= adp5588_write(client, GPI_EM1, evt_mode1);
+ ret |= adp5588_write(client, GPI_EM2, evt_mode2);
+ ret |= adp5588_write(client, GPI_EM3, evt_mode3);
+ }
+
+ if (gpio_data) {
+ for (i = 0; i <= ADP_BANK(MAXGPIO); i++) {
+ int pull_mask = gpio_data->pullup_dis_mask;
+
+ ret |= adp5588_write(client, GPIO_PULL1 + i,
+ (pull_mask >> (8 * i)) & 0xFF);
+ }
+ }
+
ret |= adp5588_write(client, INT_STAT, CMP2_INT | CMP1_INT |
OVR_FLOW_INT | K_LCK_INT |
GPI_INT | KE_INT); /* Status is W1C */
@@ -158,11 +406,49 @@ static int __devinit adp5588_setup(struct i2c_client *client)
return 0;
}
+static void __devinit adp5588_report_switch_state(struct adp5588_kpad *kpad)
+{
+ int gpi_stat1 = adp5588_read(kpad->client, GPIO_DAT_STAT1);
+ int gpi_stat2 = adp5588_read(kpad->client, GPIO_DAT_STAT2);
+ int gpi_stat3 = adp5588_read(kpad->client, GPIO_DAT_STAT3);
+ int gpi_stat_tmp, pin_loc;
+ int i;
+
+ for (i = 0; i < kpad->gpimapsize; i++) {
+ unsigned short pin = kpad->gpimap[i].pin;
+
+ if (pin <= GPI_PIN_ROW_END) {
+ gpi_stat_tmp = gpi_stat1;
+ pin_loc = pin - GPI_PIN_ROW_BASE;
+ } else if ((pin - GPI_PIN_COL_BASE) < 8) {
+ gpi_stat_tmp = gpi_stat2;
+ pin_loc = pin - GPI_PIN_COL_BASE;
+ } else {
+ gpi_stat_tmp = gpi_stat3;
+ pin_loc = pin - GPI_PIN_COL_BASE - 8;
+ }
+
+ if (gpi_stat_tmp < 0) {
+ dev_err(&kpad->client->dev,
+ "Can't read GPIO_DAT_STAT switch %d default to OFF\n",
+ pin);
+ gpi_stat_tmp = 0;
+ }
+
+ input_report_switch(kpad->input,
+ kpad->gpimap[i].sw_evt,
+ !(gpi_stat_tmp & (1 << pin_loc)));
+ }
+
+ input_sync(kpad->input);
+}
+
+
static int __devinit adp5588_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct adp5588_kpad *kpad;
- struct adp5588_kpad_platform_data *pdata = client->dev.platform_data;
+ const struct adp5588_kpad_platform_data *pdata = client->dev.platform_data;
struct input_dev *input;
unsigned int revid;
int ret, i;
@@ -189,6 +475,37 @@ static int __devinit adp5588_probe(struct i2c_client *client,
return -EINVAL;
}
+ if (!pdata->gpimap && pdata->gpimapsize) {
+ dev_err(&client->dev, "invalid gpimap from pdata\n");
+ return -EINVAL;
+ }
+
+ if (pdata->gpimapsize > ADP5588_GPIMAPSIZE_MAX) {
+ dev_err(&client->dev, "invalid gpimapsize\n");
+ return -EINVAL;
+ }
+
+ for (i = 0; i < pdata->gpimapsize; i++) {
+ unsigned short pin = pdata->gpimap[i].pin;
+
+ if (pin < GPI_PIN_BASE || pin > GPI_PIN_END) {
+ dev_err(&client->dev, "invalid gpi pin data\n");
+ return -EINVAL;
+ }
+
+ if (pin <= GPI_PIN_ROW_END) {
+ if (pin - GPI_PIN_ROW_BASE + 1 <= pdata->rows) {
+ dev_err(&client->dev, "invalid gpi row data\n");
+ return -EINVAL;
+ }
+ } else {
+ if (pin - GPI_PIN_COL_BASE + 1 <= pdata->cols) {
+ dev_err(&client->dev, "invalid gpi col data\n");
+ return -EINVAL;
+ }
+ }
+ }
+
if (!client->irq) {
dev_err(&client->dev, "no IRQ?\n");
return -EINVAL;
@@ -233,6 +550,9 @@ static int __devinit adp5588_probe(struct i2c_client *client,
memcpy(kpad->keycode, pdata->keymap,
pdata->keymapsize * input->keycodesize);
+ kpad->gpimap = pdata->gpimap;
+ kpad->gpimapsize = pdata->gpimapsize;
+
/* setup input device */
__set_bit(EV_KEY, input->evbit);
@@ -243,6 +563,11 @@ static int __devinit adp5588_probe(struct i2c_client *client,
__set_bit(kpad->keycode[i] & KEY_MAX, input->keybit);
__clear_bit(KEY_RESERVED, input->keybit);
+ if (kpad->gpimapsize)
+ __set_bit(EV_SW, input->evbit);
+ for (i = 0; i < kpad->gpimapsize; i++)
+ __set_bit(kpad->gpimap[i].sw_evt, input->swbit);
+
error = input_register_device(input);
if (error) {
dev_err(&client->dev, "unable to register input device\n");
@@ -261,6 +586,13 @@ static int __devinit adp5588_probe(struct i2c_client *client,
if (error)
goto err_free_irq;
+ if (kpad->gpimapsize)
+ adp5588_report_switch_state(kpad);
+
+ error = adp5588_gpio_add(kpad);
+ if (error)
+ goto err_free_irq;
+
device_init_wakeup(&client->dev, 1);
i2c_set_clientdata(client, kpad);
@@ -287,6 +619,7 @@ static int __devexit adp5588_remove(struct i2c_client *client)
free_irq(client->irq, kpad);
cancel_delayed_work_sync(&kpad->work);
input_unregister_device(kpad->input);
+ adp5588_gpio_remove(kpad);
kfree(kpad);
return 0;
diff --git a/drivers/input/keyboard/gpio_keys.c b/drivers/input/keyboard/gpio_keys.c
index b8213fd13c3..a9fd147f2ba 100644
--- a/drivers/input/keyboard/gpio_keys.c
+++ b/drivers/input/keyboard/gpio_keys.c
@@ -31,6 +31,7 @@ struct gpio_button_data {
struct input_dev *input;
struct timer_list timer;
struct work_struct work;
+ int timer_debounce; /* in msecs */
bool disabled;
};
@@ -109,7 +110,7 @@ static void gpio_keys_disable_button(struct gpio_button_data *bdata)
* Disable IRQ and possible debouncing timer.
*/
disable_irq(gpio_to_irq(bdata->button->gpio));
- if (bdata->button->debounce_interval)
+ if (bdata->timer_debounce)
del_timer_sync(&bdata->timer);
bdata->disabled = true;
@@ -347,9 +348,9 @@ static irqreturn_t gpio_keys_isr(int irq, void *dev_id)
BUG_ON(irq != gpio_to_irq(button->gpio));
- if (button->debounce_interval)
+ if (bdata->timer_debounce)
mod_timer(&bdata->timer,
- jiffies + msecs_to_jiffies(button->debounce_interval));
+ jiffies + msecs_to_jiffies(bdata->timer_debounce));
else
schedule_work(&bdata->work);
@@ -383,6 +384,14 @@ static int __devinit gpio_keys_setup_key(struct platform_device *pdev,
goto fail3;
}
+ if (button->debounce_interval) {
+ error = gpio_set_debounce(button->gpio,
+ button->debounce_interval * 1000);
+ /* use timer if gpiolib doesn't provide debounce */
+ if (error < 0)
+ bdata->timer_debounce = button->debounce_interval;
+ }
+
irq = gpio_to_irq(button->gpio);
if (irq < 0) {
error = irq;
@@ -498,7 +507,7 @@ static int __devinit gpio_keys_probe(struct platform_device *pdev)
fail2:
while (--i >= 0) {
free_irq(gpio_to_irq(pdata->buttons[i].gpio), &ddata->data[i]);
- if (pdata->buttons[i].debounce_interval)
+ if (ddata->data[i].timer_debounce)
del_timer_sync(&ddata->data[i].timer);
cancel_work_sync(&ddata->data[i].work);
gpio_free(pdata->buttons[i].gpio);
@@ -526,7 +535,7 @@ static int __devexit gpio_keys_remove(struct platform_device *pdev)
for (i = 0; i < pdata->nbuttons; i++) {
int irq = gpio_to_irq(pdata->buttons[i].gpio);
free_irq(irq, &ddata->data[i]);
- if (pdata->buttons[i].debounce_interval)
+ if (ddata->data[i].timer_debounce)
del_timer_sync(&ddata->data[i].timer);
cancel_work_sync(&ddata->data[i].work);
gpio_free(pdata->buttons[i].gpio);
diff --git a/drivers/input/keyboard/lm8323.c b/drivers/input/keyboard/lm8323.c
index 40b032f0e32..f7c2a166576 100644
--- a/drivers/input/keyboard/lm8323.c
+++ b/drivers/input/keyboard/lm8323.c
@@ -642,6 +642,7 @@ static int __devinit lm8323_probe(struct i2c_client *client,
struct lm8323_platform_data *pdata = client->dev.platform_data;
struct input_dev *idev;
struct lm8323_chip *lm;
+ int pwm;
int i, err;
unsigned long tmo;
u8 data[2];
@@ -710,8 +711,9 @@ static int __devinit lm8323_probe(struct i2c_client *client,
goto fail1;
}
- for (i = 0; i < LM8323_NUM_PWMS; i++) {
- err = init_pwm(lm, i + 1, &client->dev, pdata->pwm_names[i]);
+ for (pwm = 0; pwm < LM8323_NUM_PWMS; pwm++) {
+ err = init_pwm(lm, pwm + 1, &client->dev,
+ pdata->pwm_names[pwm]);
if (err < 0)
goto fail2;
}
@@ -764,9 +766,9 @@ fail4:
fail3:
device_remove_file(&client->dev, &dev_attr_disable_kp);
fail2:
- while (--i >= 0)
- if (lm->pwm[i].enabled)
- led_classdev_unregister(&lm->pwm[i].cdev);
+ while (--pwm >= 0)
+ if (lm->pwm[pwm].enabled)
+ led_classdev_unregister(&lm->pwm[pwm].cdev);
fail1:
input_free_device(idev);
kfree(lm);
diff --git a/drivers/input/keyboard/matrix_keypad.c b/drivers/input/keyboard/matrix_keypad.c
index b443e088fd3..b02e4268e18 100644
--- a/drivers/input/keyboard/matrix_keypad.c
+++ b/drivers/input/keyboard/matrix_keypad.c
@@ -37,6 +37,7 @@ struct matrix_keypad {
spinlock_t lock;
bool scan_pending;
bool stopped;
+ bool gpio_all_disabled;
};
/*
@@ -87,8 +88,12 @@ static void enable_row_irqs(struct matrix_keypad *keypad)
const struct matrix_keypad_platform_data *pdata = keypad->pdata;
int i;
- for (i = 0; i < pdata->num_row_gpios; i++)
- enable_irq(gpio_to_irq(pdata->row_gpios[i]));
+ if (pdata->clustered_irq > 0)
+ enable_irq(pdata->clustered_irq);
+ else {
+ for (i = 0; i < pdata->num_row_gpios; i++)
+ enable_irq(gpio_to_irq(pdata->row_gpios[i]));
+ }
}
static void disable_row_irqs(struct matrix_keypad *keypad)
@@ -96,8 +101,12 @@ static void disable_row_irqs(struct matrix_keypad *keypad)
const struct matrix_keypad_platform_data *pdata = keypad->pdata;
int i;
- for (i = 0; i < pdata->num_row_gpios; i++)
- disable_irq_nosync(gpio_to_irq(pdata->row_gpios[i]));
+ if (pdata->clustered_irq > 0)
+ disable_irq_nosync(pdata->clustered_irq);
+ else {
+ for (i = 0; i < pdata->num_row_gpios; i++)
+ disable_irq_nosync(gpio_to_irq(pdata->row_gpios[i]));
+ }
}
/*
@@ -216,45 +225,69 @@ static void matrix_keypad_stop(struct input_dev *dev)
}
#ifdef CONFIG_PM
-static int matrix_keypad_suspend(struct device *dev)
+static void matrix_keypad_enable_wakeup(struct matrix_keypad *keypad)
{
- struct platform_device *pdev = to_platform_device(dev);
- struct matrix_keypad *keypad = platform_get_drvdata(pdev);
const struct matrix_keypad_platform_data *pdata = keypad->pdata;
+ unsigned int gpio;
int i;
- matrix_keypad_stop(keypad->input_dev);
+ if (pdata->clustered_irq > 0) {
+ if (enable_irq_wake(pdata->clustered_irq) == 0)
+ keypad->gpio_all_disabled = true;
+ } else {
- if (device_may_wakeup(&pdev->dev)) {
for (i = 0; i < pdata->num_row_gpios; i++) {
if (!test_bit(i, keypad->disabled_gpios)) {
- unsigned int gpio = pdata->row_gpios[i];
+ gpio = pdata->row_gpios[i];
if (enable_irq_wake(gpio_to_irq(gpio)) == 0)
__set_bit(i, keypad->disabled_gpios);
}
}
}
-
- return 0;
}
-static int matrix_keypad_resume(struct device *dev)
+static void matrix_keypad_disable_wakeup(struct matrix_keypad *keypad)
{
- struct platform_device *pdev = to_platform_device(dev);
- struct matrix_keypad *keypad = platform_get_drvdata(pdev);
const struct matrix_keypad_platform_data *pdata = keypad->pdata;
+ unsigned int gpio;
int i;
- if (device_may_wakeup(&pdev->dev)) {
+ if (pdata->clustered_irq > 0) {
+ if (keypad->gpio_all_disabled) {
+ disable_irq_wake(pdata->clustered_irq);
+ keypad->gpio_all_disabled = false;
+ }
+ } else {
for (i = 0; i < pdata->num_row_gpios; i++) {
if (test_and_clear_bit(i, keypad->disabled_gpios)) {
- unsigned int gpio = pdata->row_gpios[i];
-
+ gpio = pdata->row_gpios[i];
disable_irq_wake(gpio_to_irq(gpio));
}
}
}
+}
+
+static int matrix_keypad_suspend(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct matrix_keypad *keypad = platform_get_drvdata(pdev);
+
+ matrix_keypad_stop(keypad->input_dev);
+
+ if (device_may_wakeup(&pdev->dev))
+ matrix_keypad_enable_wakeup(keypad);
+
+ return 0;
+}
+
+static int matrix_keypad_resume(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct matrix_keypad *keypad = platform_get_drvdata(pdev);
+
+ if (device_may_wakeup(&pdev->dev))
+ matrix_keypad_disable_wakeup(keypad);
matrix_keypad_start(keypad->input_dev);
@@ -296,17 +329,31 @@ static int __devinit init_matrix_gpio(struct platform_device *pdev,
gpio_direction_input(pdata->row_gpios[i]);
}
- for (i = 0; i < pdata->num_row_gpios; i++) {
- err = request_irq(gpio_to_irq(pdata->row_gpios[i]),
+ if (pdata->clustered_irq > 0) {
+ err = request_irq(pdata->clustered_irq,
matrix_keypad_interrupt,
- IRQF_DISABLED |
- IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
+ pdata->clustered_irq_flags,
"matrix-keypad", keypad);
if (err) {
dev_err(&pdev->dev,
- "Unable to acquire interrupt for GPIO line %i\n",
- pdata->row_gpios[i]);
- goto err_free_irqs;
+ "Unable to acquire clustered interrupt\n");
+ goto err_free_rows;
+ }
+ } else {
+ for (i = 0; i < pdata->num_row_gpios; i++) {
+ err = request_irq(gpio_to_irq(pdata->row_gpios[i]),
+ matrix_keypad_interrupt,
+ IRQF_DISABLED |
+ IRQF_TRIGGER_RISING |
+ IRQF_TRIGGER_FALLING,
+ "matrix-keypad", keypad);
+ if (err) {
+ dev_err(&pdev->dev,
+ "Unable to acquire interrupt "
+ "for GPIO line %i\n",
+ pdata->row_gpios[i]);
+ goto err_free_irqs;
+ }
}
}
@@ -418,11 +465,16 @@ static int __devexit matrix_keypad_remove(struct platform_device *pdev)
device_init_wakeup(&pdev->dev, 0);
- for (i = 0; i < pdata->num_row_gpios; i++) {
- free_irq(gpio_to_irq(pdata->row_gpios[i]), keypad);
- gpio_free(pdata->row_gpios[i]);
+ if (pdata->clustered_irq > 0) {
+ free_irq(pdata->clustered_irq, keypad);
+ } else {
+ for (i = 0; i < pdata->num_row_gpios; i++)
+ free_irq(gpio_to_irq(pdata->row_gpios[i]), keypad);
}
+ for (i = 0; i < pdata->num_row_gpios; i++)
+ gpio_free(pdata->row_gpios[i]);
+
for (i = 0; i < pdata->num_col_gpios; i++)
gpio_free(pdata->col_gpios[i]);
diff --git a/drivers/input/keyboard/mcs_touchkey.c b/drivers/input/keyboard/mcs_touchkey.c
new file mode 100644
index 00000000000..63b849d7e90
--- /dev/null
+++ b/drivers/input/keyboard/mcs_touchkey.c
@@ -0,0 +1,239 @@
+/*
+ * mcs_touchkey.c - Touchkey driver for MELFAS MCS5000/5080 controller
+ *
+ * Copyright (C) 2010 Samsung Electronics Co.Ltd
+ * Author: HeungJun Kim <riverful.kim@samsung.com>
+ * Author: Joonyoung Shim <jy0922.shim@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/i2c/mcs.h>
+#include <linux/interrupt.h>
+#include <linux/input.h>
+#include <linux/irq.h>
+#include <linux/slab.h>
+
+/* MCS5000 Touchkey */
+#define MCS5000_TOUCHKEY_STATUS 0x04
+#define MCS5000_TOUCHKEY_STATUS_PRESS 7
+#define MCS5000_TOUCHKEY_FW 0x0a
+#define MCS5000_TOUCHKEY_BASE_VAL 0x61
+
+/* MCS5080 Touchkey */
+#define MCS5080_TOUCHKEY_STATUS 0x00
+#define MCS5080_TOUCHKEY_STATUS_PRESS 3
+#define MCS5080_TOUCHKEY_FW 0x01
+#define MCS5080_TOUCHKEY_BASE_VAL 0x1
+
+enum mcs_touchkey_type {
+ MCS5000_TOUCHKEY,
+ MCS5080_TOUCHKEY,
+};
+
+struct mcs_touchkey_chip {
+ unsigned int status_reg;
+ unsigned int pressbit;
+ unsigned int press_invert;
+ unsigned int baseval;
+};
+
+struct mcs_touchkey_data {
+ struct i2c_client *client;
+ struct input_dev *input_dev;
+ struct mcs_touchkey_chip chip;
+ unsigned int key_code;
+ unsigned int key_val;
+ unsigned short keycodes[];
+};
+
+static irqreturn_t mcs_touchkey_interrupt(int irq, void *dev_id)
+{
+ struct mcs_touchkey_data *data = dev_id;
+ struct mcs_touchkey_chip *chip = &data->chip;
+ struct i2c_client *client = data->client;
+ struct input_dev *input = data->input_dev;
+ unsigned int key_val;
+ unsigned int pressed;
+ int val;
+
+ val = i2c_smbus_read_byte_data(client, chip->status_reg);
+ if (val < 0) {
+ dev_err(&client->dev, "i2c read error [%d]\n", val);
+ goto out;
+ }
+
+ pressed = (val & (1 << chip->pressbit)) >> chip->pressbit;
+ if (chip->press_invert)
+ pressed ^= chip->press_invert;
+
+ /* key_val is 0 when released, so we should use key_val of press. */
+ if (pressed) {
+ key_val = val & (0xff >> (8 - chip->pressbit));
+ if (!key_val)
+ goto out;
+ key_val -= chip->baseval;
+ data->key_code = data->keycodes[key_val];
+ data->key_val = key_val;
+ }
+
+ input_event(input, EV_MSC, MSC_SCAN, data->key_val);
+ input_report_key(input, data->key_code, pressed);
+ input_sync(input);
+
+ dev_dbg(&client->dev, "key %d %d %s\n", data->key_val, data->key_code,
+ pressed ? "pressed" : "released");
+
+ out:
+ return IRQ_HANDLED;
+}
+
+static int __devinit mcs_touchkey_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ const struct mcs_platform_data *pdata;
+ struct mcs_touchkey_data *data;
+ struct input_dev *input_dev;
+ unsigned int fw_reg;
+ int fw_ver;
+ int error;
+ int i;
+
+ pdata = client->dev.platform_data;
+ if (!pdata) {
+ dev_err(&client->dev, "no platform data defined\n");
+ return -EINVAL;
+ }
+
+ data = kzalloc(sizeof(struct mcs_touchkey_data) +
+ sizeof(data->keycodes[0]) * (pdata->key_maxval + 1),
+ GFP_KERNEL);
+ input_dev = input_allocate_device();
+ if (!data || !input_dev) {
+ dev_err(&client->dev, "Failed to allocate memory\n");
+ error = -ENOMEM;
+ goto err_free_mem;
+ }
+
+ data->client = client;
+ data->input_dev = input_dev;
+
+ if (id->driver_data == MCS5000_TOUCHKEY) {
+ data->chip.status_reg = MCS5000_TOUCHKEY_STATUS;
+ data->chip.pressbit = MCS5000_TOUCHKEY_STATUS_PRESS;
+ data->chip.baseval = MCS5000_TOUCHKEY_BASE_VAL;
+ fw_reg = MCS5000_TOUCHKEY_FW;
+ } else {
+ data->chip.status_reg = MCS5080_TOUCHKEY_STATUS;
+ data->chip.pressbit = MCS5080_TOUCHKEY_STATUS_PRESS;
+ data->chip.press_invert = 1;
+ data->chip.baseval = MCS5080_TOUCHKEY_BASE_VAL;
+ fw_reg = MCS5080_TOUCHKEY_FW;
+ }
+
+ fw_ver = i2c_smbus_read_byte_data(client, fw_reg);
+ if (fw_ver < 0) {
+ error = fw_ver;
+ dev_err(&client->dev, "i2c read error[%d]\n", error);
+ goto err_free_mem;
+ }
+ dev_info(&client->dev, "Firmware version: %d\n", fw_ver);
+
+ input_dev->name = "MELPAS MCS Touchkey";
+ input_dev->id.bustype = BUS_I2C;
+ input_dev->dev.parent = &client->dev;
+ input_dev->evbit[0] = BIT_MASK(EV_KEY);
+ if (!pdata->no_autorepeat)
+ input_dev->evbit[0] |= BIT_MASK(EV_REP);
+ input_dev->keycode = data->keycodes;
+ input_dev->keycodesize = sizeof(data->keycodes[0]);
+ input_dev->keycodemax = pdata->key_maxval + 1;
+
+ for (i = 0; i < pdata->keymap_size; i++) {
+ unsigned int val = MCS_KEY_VAL(pdata->keymap[i]);
+ unsigned int code = MCS_KEY_CODE(pdata->keymap[i]);
+
+ data->keycodes[val] = code;
+ __set_bit(code, input_dev->keybit);
+ }
+
+ input_set_capability(input_dev, EV_MSC, MSC_SCAN);
+ input_set_drvdata(input_dev, data);
+
+ if (pdata->cfg_pin)
+ pdata->cfg_pin();
+
+ error = request_threaded_irq(client->irq, NULL, mcs_touchkey_interrupt,
+ IRQF_TRIGGER_FALLING, client->dev.driver->name, data);
+ if (error) {
+ dev_err(&client->dev, "Failed to register interrupt\n");
+ goto err_free_mem;
+ }
+
+ error = input_register_device(input_dev);
+ if (error)
+ goto err_free_irq;
+
+ i2c_set_clientdata(client, data);
+ return 0;
+
+err_free_irq:
+ free_irq(client->irq, data);
+err_free_mem:
+ input_free_device(input_dev);
+ kfree(data);
+ return error;
+}
+
+static int __devexit mcs_touchkey_remove(struct i2c_client *client)
+{
+ struct mcs_touchkey_data *data = i2c_get_clientdata(client);
+
+ free_irq(client->irq, data);
+ input_unregister_device(data->input_dev);
+ kfree(data);
+
+ return 0;
+}
+
+static const struct i2c_device_id mcs_touchkey_id[] = {
+ { "mcs5000_touchkey", MCS5000_TOUCHKEY },
+ { "mcs5080_touchkey", MCS5080_TOUCHKEY },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, mcs_touchkey_id);
+
+static struct i2c_driver mcs_touchkey_driver = {
+ .driver = {
+ .name = "mcs_touchkey",
+ .owner = THIS_MODULE,
+ },
+ .probe = mcs_touchkey_probe,
+ .remove = __devexit_p(mcs_touchkey_remove),
+ .id_table = mcs_touchkey_id,
+};
+
+static int __init mcs_touchkey_init(void)
+{
+ return i2c_add_driver(&mcs_touchkey_driver);
+}
+
+static void __exit mcs_touchkey_exit(void)
+{
+ i2c_del_driver(&mcs_touchkey_driver);
+}
+
+module_init(mcs_touchkey_init);
+module_exit(mcs_touchkey_exit);
+
+/* Module information */
+MODULE_AUTHOR("Joonyoung Shim <jy0922.shim@samsung.com>");
+MODULE_AUTHOR("HeungJun Kim <riverful.kim@samsung.com>");
+MODULE_DESCRIPTION("Touchkey driver for MELFAS MCS5000/5080 controller");
+MODULE_LICENSE("GPL");
diff --git a/drivers/input/keyboard/samsung-keypad.c b/drivers/input/keyboard/samsung-keypad.c
new file mode 100644
index 00000000000..f689f49e310
--- /dev/null
+++ b/drivers/input/keyboard/samsung-keypad.c
@@ -0,0 +1,491 @@
+/*
+ * Samsung keypad driver
+ *
+ * Copyright (C) 2010 Samsung Electronics Co.Ltd
+ * Author: Joonyoung Shim <jy0922.shim@samsung.com>
+ * Author: Donghwa Lee <dh09.lee@samsung.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/clk.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+#include <plat/keypad.h>
+
+#define SAMSUNG_KEYIFCON 0x00
+#define SAMSUNG_KEYIFSTSCLR 0x04
+#define SAMSUNG_KEYIFCOL 0x08
+#define SAMSUNG_KEYIFROW 0x0c
+#define SAMSUNG_KEYIFFC 0x10
+
+/* SAMSUNG_KEYIFCON */
+#define SAMSUNG_KEYIFCON_INT_F_EN (1 << 0)
+#define SAMSUNG_KEYIFCON_INT_R_EN (1 << 1)
+#define SAMSUNG_KEYIFCON_DF_EN (1 << 2)
+#define SAMSUNG_KEYIFCON_FC_EN (1 << 3)
+#define SAMSUNG_KEYIFCON_WAKEUPEN (1 << 4)
+
+/* SAMSUNG_KEYIFSTSCLR */
+#define SAMSUNG_KEYIFSTSCLR_P_INT_MASK (0xff << 0)
+#define SAMSUNG_KEYIFSTSCLR_R_INT_MASK (0xff << 8)
+#define SAMSUNG_KEYIFSTSCLR_R_INT_OFFSET 8
+#define S5PV210_KEYIFSTSCLR_P_INT_MASK (0x3fff << 0)
+#define S5PV210_KEYIFSTSCLR_R_INT_MASK (0x3fff << 16)
+#define S5PV210_KEYIFSTSCLR_R_INT_OFFSET 16
+
+/* SAMSUNG_KEYIFCOL */
+#define SAMSUNG_KEYIFCOL_MASK (0xff << 0)
+#define S5PV210_KEYIFCOLEN_MASK (0xff << 8)
+
+/* SAMSUNG_KEYIFROW */
+#define SAMSUNG_KEYIFROW_MASK (0xff << 0)
+#define S5PV210_KEYIFROW_MASK (0x3fff << 0)
+
+/* SAMSUNG_KEYIFFC */
+#define SAMSUNG_KEYIFFC_MASK (0x3ff << 0)
+
+enum samsung_keypad_type {
+ KEYPAD_TYPE_SAMSUNG,
+ KEYPAD_TYPE_S5PV210,
+};
+
+struct samsung_keypad {
+ struct input_dev *input_dev;
+ struct clk *clk;
+ void __iomem *base;
+ wait_queue_head_t wait;
+ bool stopped;
+ int irq;
+ unsigned int row_shift;
+ unsigned int rows;
+ unsigned int cols;
+ unsigned int row_state[SAMSUNG_MAX_COLS];
+ unsigned short keycodes[];
+};
+
+static int samsung_keypad_is_s5pv210(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ enum samsung_keypad_type type =
+ platform_get_device_id(pdev)->driver_data;
+
+ return type == KEYPAD_TYPE_S5PV210;
+}
+
+static void samsung_keypad_scan(struct samsung_keypad *keypad,
+ unsigned int *row_state)
+{
+ struct device *dev = keypad->input_dev->dev.parent;
+ unsigned int col;
+ unsigned int val;
+
+ for (col = 0; col < keypad->cols; col++) {
+ if (samsung_keypad_is_s5pv210(dev)) {
+ val = S5PV210_KEYIFCOLEN_MASK;
+ val &= ~(1 << col) << 8;
+ } else {
+ val = SAMSUNG_KEYIFCOL_MASK;
+ val &= ~(1 << col);
+ }
+
+ writel(val, keypad->base + SAMSUNG_KEYIFCOL);
+ mdelay(1);
+
+ val = readl(keypad->base + SAMSUNG_KEYIFROW);
+ row_state[col] = ~val & ((1 << keypad->rows) - 1);
+ }
+
+ /* KEYIFCOL reg clear */
+ writel(0, keypad->base + SAMSUNG_KEYIFCOL);
+}
+
+static bool samsung_keypad_report(struct samsung_keypad *keypad,
+ unsigned int *row_state)
+{
+ struct input_dev *input_dev = keypad->input_dev;
+ unsigned int changed;
+ unsigned int pressed;
+ unsigned int key_down = 0;
+ unsigned int val;
+ unsigned int col, row;
+
+ for (col = 0; col < keypad->cols; col++) {
+ changed = row_state[col] ^ keypad->row_state[col];
+ key_down |= row_state[col];
+ if (!changed)
+ continue;
+
+ for (row = 0; row < keypad->rows; row++) {
+ if (!(changed & (1 << row)))
+ continue;
+
+ pressed = row_state[col] & (1 << row);
+
+ dev_dbg(&keypad->input_dev->dev,
+ "key %s, row: %d, col: %d\n",
+ pressed ? "pressed" : "released", row, col);
+
+ val = MATRIX_SCAN_CODE(row, col, keypad->row_shift);
+
+ input_event(input_dev, EV_MSC, MSC_SCAN, val);
+ input_report_key(input_dev,
+ keypad->keycodes[val], pressed);
+ }
+ input_sync(keypad->input_dev);
+ }
+
+ memcpy(keypad->row_state, row_state, sizeof(keypad->row_state));
+
+ return key_down;
+}
+
+static irqreturn_t samsung_keypad_irq(int irq, void *dev_id)
+{
+ struct samsung_keypad *keypad = dev_id;
+ unsigned int row_state[SAMSUNG_MAX_COLS];
+ unsigned int val;
+ bool key_down;
+
+ do {
+ val = readl(keypad->base + SAMSUNG_KEYIFSTSCLR);
+ /* Clear interrupt. */
+ writel(~0x0, keypad->base + SAMSUNG_KEYIFSTSCLR);
+
+ samsung_keypad_scan(keypad, row_state);
+
+ key_down = samsung_keypad_report(keypad, row_state);
+ if (key_down)
+ wait_event_timeout(keypad->wait, keypad->stopped,
+ msecs_to_jiffies(50));
+
+ } while (key_down && !keypad->stopped);
+
+ return IRQ_HANDLED;
+}
+
+static void samsung_keypad_start(struct samsung_keypad *keypad)
+{
+ unsigned int val;
+
+ /* Tell IRQ thread that it may poll the device. */
+ keypad->stopped = false;
+
+ clk_enable(keypad->clk);
+
+ /* Enable interrupt bits. */
+ val = readl(keypad->base + SAMSUNG_KEYIFCON);
+ val |= SAMSUNG_KEYIFCON_INT_F_EN | SAMSUNG_KEYIFCON_INT_R_EN;
+ writel(val, keypad->base + SAMSUNG_KEYIFCON);
+
+ /* KEYIFCOL reg clear. */
+ writel(0, keypad->base + SAMSUNG_KEYIFCOL);
+}
+
+static void samsung_keypad_stop(struct samsung_keypad *keypad)
+{
+ unsigned int val;
+
+ /* Signal IRQ thread to stop polling and disable the handler. */
+ keypad->stopped = true;
+ wake_up(&keypad->wait);
+ disable_irq(keypad->irq);
+
+ /* Clear interrupt. */
+ writel(~0x0, keypad->base + SAMSUNG_KEYIFSTSCLR);
+
+ /* Disable interrupt bits. */
+ val = readl(keypad->base + SAMSUNG_KEYIFCON);
+ val &= ~(SAMSUNG_KEYIFCON_INT_F_EN | SAMSUNG_KEYIFCON_INT_R_EN);
+ writel(val, keypad->base + SAMSUNG_KEYIFCON);
+
+ clk_disable(keypad->clk);
+
+ /*
+ * Now that chip should not generate interrupts we can safely
+ * re-enable the handler.
+ */
+ enable_irq(keypad->irq);
+}
+
+static int samsung_keypad_open(struct input_dev *input_dev)
+{
+ struct samsung_keypad *keypad = input_get_drvdata(input_dev);
+
+ samsung_keypad_start(keypad);
+
+ return 0;
+}
+
+static void samsung_keypad_close(struct input_dev *input_dev)
+{
+ struct samsung_keypad *keypad = input_get_drvdata(input_dev);
+
+ samsung_keypad_stop(keypad);
+}
+
+static int __devinit samsung_keypad_probe(struct platform_device *pdev)
+{
+ const struct samsung_keypad_platdata *pdata;
+ const struct matrix_keymap_data *keymap_data;
+ struct samsung_keypad *keypad;
+ struct resource *res;
+ struct input_dev *input_dev;
+ unsigned int row_shift;
+ unsigned int keymap_size;
+ int error;
+
+ pdata = pdev->dev.platform_data;
+ if (!pdata) {
+ dev_err(&pdev->dev, "no platform data defined\n");
+ return -EINVAL;
+ }
+
+ keymap_data = pdata->keymap_data;
+ if (!keymap_data) {
+ dev_err(&pdev->dev, "no keymap data defined\n");
+ return -EINVAL;
+ }
+
+ if (!pdata->rows || pdata->rows > SAMSUNG_MAX_ROWS)
+ return -EINVAL;
+
+ if (!pdata->cols || pdata->cols > SAMSUNG_MAX_COLS)
+ return -EINVAL;
+
+ /* initialize the gpio */
+ if (pdata->cfg_gpio)
+ pdata->cfg_gpio(pdata->rows, pdata->cols);
+
+ row_shift = get_count_order(pdata->cols);
+ keymap_size = (pdata->rows << row_shift) * sizeof(keypad->keycodes[0]);
+
+ keypad = kzalloc(sizeof(*keypad) + keymap_size, GFP_KERNEL);
+ input_dev = input_allocate_device();
+ if (!keypad || !input_dev) {
+ error = -ENOMEM;
+ goto err_free_mem;
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ error = -ENODEV;
+ goto err_free_mem;
+ }
+
+ keypad->base = ioremap(res->start, resource_size(res));
+ if (!keypad->base) {
+ error = -EBUSY;
+ goto err_free_mem;
+ }
+
+ keypad->clk = clk_get(&pdev->dev, "keypad");
+ if (IS_ERR(keypad->clk)) {
+ dev_err(&pdev->dev, "failed to get keypad clk\n");
+ error = PTR_ERR(keypad->clk);
+ goto err_unmap_base;
+ }
+
+ keypad->input_dev = input_dev;
+ keypad->row_shift = row_shift;
+ keypad->rows = pdata->rows;
+ keypad->cols = pdata->cols;
+ init_waitqueue_head(&keypad->wait);
+
+ input_dev->name = pdev->name;
+ input_dev->id.bustype = BUS_HOST;
+ input_dev->dev.parent = &pdev->dev;
+ input_set_drvdata(input_dev, keypad);
+
+ input_dev->open = samsung_keypad_open;
+ input_dev->close = samsung_keypad_close;
+
+ input_dev->evbit[0] = BIT_MASK(EV_KEY);
+ if (!pdata->no_autorepeat)
+ input_dev->evbit[0] |= BIT_MASK(EV_REP);
+
+ input_set_capability(input_dev, EV_MSC, MSC_SCAN);
+
+ input_dev->keycode = keypad->keycodes;
+ input_dev->keycodesize = sizeof(keypad->keycodes[0]);
+ input_dev->keycodemax = pdata->rows << row_shift;
+
+ matrix_keypad_build_keymap(keymap_data, row_shift,
+ input_dev->keycode, input_dev->keybit);
+
+ keypad->irq = platform_get_irq(pdev, 0);
+ if (keypad->irq < 0) {
+ error = keypad->irq;
+ goto err_put_clk;
+ }
+
+ error = request_threaded_irq(keypad->irq, NULL, samsung_keypad_irq,
+ IRQF_ONESHOT, dev_name(&pdev->dev), keypad);
+ if (error) {
+ dev_err(&pdev->dev, "failed to register keypad interrupt\n");
+ goto err_put_clk;
+ }
+
+ error = input_register_device(keypad->input_dev);
+ if (error)
+ goto err_free_irq;
+
+ device_init_wakeup(&pdev->dev, pdata->wakeup);
+ platform_set_drvdata(pdev, keypad);
+ return 0;
+
+err_free_irq:
+ free_irq(keypad->irq, keypad);
+err_put_clk:
+ clk_put(keypad->clk);
+err_unmap_base:
+ iounmap(keypad->base);
+err_free_mem:
+ input_free_device(input_dev);
+ kfree(keypad);
+
+ return error;
+}
+
+static int __devexit samsung_keypad_remove(struct platform_device *pdev)
+{
+ struct samsung_keypad *keypad = platform_get_drvdata(pdev);
+
+ device_init_wakeup(&pdev->dev, 0);
+ platform_set_drvdata(pdev, NULL);
+
+ input_unregister_device(keypad->input_dev);
+
+ /*
+ * It is safe to free IRQ after unregistering device because
+ * samsung_keypad_close will shut off interrupts.
+ */
+ free_irq(keypad->irq, keypad);
+
+ clk_put(keypad->clk);
+
+ iounmap(keypad->base);
+ kfree(keypad);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static void samsung_keypad_toggle_wakeup(struct samsung_keypad *keypad,
+ bool enable)
+{
+ struct device *dev = keypad->input_dev->dev.parent;
+ unsigned int val;
+
+ clk_enable(keypad->clk);
+
+ val = readl(keypad->base + SAMSUNG_KEYIFCON);
+ if (enable) {
+ val |= SAMSUNG_KEYIFCON_WAKEUPEN;
+ if (device_may_wakeup(dev))
+ enable_irq_wake(keypad->irq);
+ } else {
+ val &= ~SAMSUNG_KEYIFCON_WAKEUPEN;
+ if (device_may_wakeup(dev))
+ disable_irq_wake(keypad->irq);
+ }
+ writel(val, keypad->base + SAMSUNG_KEYIFCON);
+
+ clk_disable(keypad->clk);
+}
+
+static int samsung_keypad_suspend(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct samsung_keypad *keypad = platform_get_drvdata(pdev);
+ struct input_dev *input_dev = keypad->input_dev;
+
+ mutex_lock(&input_dev->mutex);
+
+ if (input_dev->users)
+ samsung_keypad_stop(keypad);
+
+ samsung_keypad_toggle_wakeup(keypad, true);
+
+ mutex_unlock(&input_dev->mutex);
+
+ return 0;
+}
+
+static int samsung_keypad_resume(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct samsung_keypad *keypad = platform_get_drvdata(pdev);
+ struct input_dev *input_dev = keypad->input_dev;
+
+ mutex_lock(&input_dev->mutex);
+
+ samsung_keypad_toggle_wakeup(keypad, false);
+
+ if (input_dev->users)
+ samsung_keypad_start(keypad);
+
+ mutex_unlock(&input_dev->mutex);
+
+ return 0;
+}
+
+static const struct dev_pm_ops samsung_keypad_pm_ops = {
+ .suspend = samsung_keypad_suspend,
+ .resume = samsung_keypad_resume,
+};
+#endif
+
+static struct platform_device_id samsung_keypad_driver_ids[] = {
+ {
+ .name = "samsung-keypad",
+ .driver_data = KEYPAD_TYPE_SAMSUNG,
+ }, {
+ .name = "s5pv210-keypad",
+ .driver_data = KEYPAD_TYPE_S5PV210,
+ },
+ { },
+};
+MODULE_DEVICE_TABLE(platform, samsung_keypad_driver_ids);
+
+static struct platform_driver samsung_keypad_driver = {
+ .probe = samsung_keypad_probe,
+ .remove = __devexit_p(samsung_keypad_remove),
+ .driver = {
+ .name = "samsung-keypad",
+ .owner = THIS_MODULE,
+#ifdef CONFIG_PM
+ .pm = &samsung_keypad_pm_ops,
+#endif
+ },
+ .id_table = samsung_keypad_driver_ids,
+};
+
+static int __init samsung_keypad_init(void)
+{
+ return platform_driver_register(&samsung_keypad_driver);
+}
+module_init(samsung_keypad_init);
+
+static void __exit samsung_keypad_exit(void)
+{
+ platform_driver_unregister(&samsung_keypad_driver);
+}
+module_exit(samsung_keypad_exit);
+
+MODULE_DESCRIPTION("Samsung keypad driver");
+MODULE_AUTHOR("Joonyoung Shim <jy0922.shim@samsung.com>");
+MODULE_AUTHOR("Donghwa Lee <dh09.lee@samsung.com>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:samsung-keypad");
diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig
index c44b9eafc55..b49e2337972 100644
--- a/drivers/input/misc/Kconfig
+++ b/drivers/input/misc/Kconfig
@@ -327,6 +327,17 @@ config INPUT_PCF8574
To compile this driver as a module, choose M here: the
module will be called pcf8574_keypad.
+config INPUT_PWM_BEEPER
+ tristate "PWM beeper support"
+ depends on HAVE_PWM
+ help
+ Say Y here to get support for PWM based beeper devices.
+
+ If unsure, say N.
+
+ To compile this driver as a module, choose M here: the module will be
+ called pwm-beeper.
+
config INPUT_GPIO_ROTARY_ENCODER
tristate "Rotary encoders connected to GPIO pins"
depends on GPIOLIB && GENERIC_GPIO
@@ -390,4 +401,41 @@ config INPUT_PCAP
To compile this driver as a module, choose M here: the
module will be called pcap_keys.
+config INPUT_ADXL34X
+ tristate "Analog Devices ADXL34x Three-Axis Digital Accelerometer"
+ default n
+ help
+ Say Y here if you have a Accelerometer interface using the
+ ADXL345/6 controller, and your board-specific initialization
+ code includes that in its table of devices.
+
+ This driver can use either I2C or SPI communication to the
+ ADXL345/6 controller. Select the appropriate method for
+ your system.
+
+ If unsure, say N (but it's safe to say "Y").
+
+ To compile this driver as a module, choose M here: the
+ module will be called adxl34x.
+
+config INPUT_ADXL34X_I2C
+ tristate "support I2C bus connection"
+ depends on INPUT_ADXL34X && I2C
+ default y
+ help
+ Say Y here if you have ADXL345/6 hooked to an I2C bus.
+
+ To compile this driver as a module, choose M here: the
+ module will be called adxl34x-i2c.
+
+config INPUT_ADXL34X_SPI
+ tristate "support SPI bus connection"
+ depends on INPUT_ADXL34X && SPI
+ default y
+ help
+ Say Y here if you have ADXL345/6 hooked to a SPI bus.
+
+ To compile this driver as a module, choose M here: the
+ module will be called adxl34x-spi.
+
endif
diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile
index 71fe57d8023..19ccca78fa7 100644
--- a/drivers/input/misc/Makefile
+++ b/drivers/input/misc/Makefile
@@ -8,6 +8,9 @@ obj-$(CONFIG_INPUT_88PM860X_ONKEY) += 88pm860x_onkey.o
obj-$(CONFIG_INPUT_AD714X) += ad714x.o
obj-$(CONFIG_INPUT_AD714X_I2C) += ad714x-i2c.o
obj-$(CONFIG_INPUT_AD714X_SPI) += ad714x-spi.o
+obj-$(CONFIG_INPUT_ADXL34X) += adxl34x.o
+obj-$(CONFIG_INPUT_ADXL34X_I2C) += adxl34x-i2c.o
+obj-$(CONFIG_INPUT_ADXL34X_SPI) += adxl34x-spi.o
obj-$(CONFIG_INPUT_APANEL) += apanel.o
obj-$(CONFIG_INPUT_ATI_REMOTE) += ati_remote.o
obj-$(CONFIG_INPUT_ATI_REMOTE2) += ati_remote2.o
@@ -26,6 +29,7 @@ obj-$(CONFIG_INPUT_PCF50633_PMU) += pcf50633-input.o
obj-$(CONFIG_INPUT_PCF8574) += pcf8574_keypad.o
obj-$(CONFIG_INPUT_PCSPKR) += pcspkr.o
obj-$(CONFIG_INPUT_POWERMATE) += powermate.o
+obj-$(CONFIG_INPUT_PWM_BEEPER) += pwm-beeper.o
obj-$(CONFIG_INPUT_RB532_BUTTON) += rb532_button.o
obj-$(CONFIG_INPUT_GPIO_ROTARY_ENCODER) += rotary_encoder.o
obj-$(CONFIG_INPUT_SGI_BTNS) += sgi_btns.o
diff --git a/drivers/input/misc/ad714x.c b/drivers/input/misc/ad714x.c
index 0fe27baf5e7..c431d09e401 100644
--- a/drivers/input/misc/ad714x.c
+++ b/drivers/input/misc/ad714x.c
@@ -1118,7 +1118,7 @@ struct ad714x_chip *ad714x_probe(struct device *dev, u16 bus_type, int irq,
if (error)
goto err_free_mem;
- /* initilize and request sw/hw resources */
+ /* initialize and request sw/hw resources */
ad714x_hw_init(ad714x);
mutex_init(&ad714x->mutex);
diff --git a/drivers/input/misc/adxl34x-i2c.c b/drivers/input/misc/adxl34x-i2c.c
new file mode 100644
index 00000000000..0779724af7e
--- /dev/null
+++ b/drivers/input/misc/adxl34x-i2c.c
@@ -0,0 +1,163 @@
+/*
+ * ADLX345/346 Three-Axis Digital Accelerometers (I2C Interface)
+ *
+ * Enter bugs at http://blackfin.uclinux.org/
+ *
+ * Copyright (C) 2009 Michael Hennerich, Analog Devices Inc.
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/input.h> /* BUS_I2C */
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include "adxl34x.h"
+
+static int adxl34x_smbus_read(struct device *dev, unsigned char reg)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+
+ return i2c_smbus_read_byte_data(client, reg);
+}
+
+static int adxl34x_smbus_write(struct device *dev,
+ unsigned char reg, unsigned char val)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+
+ return i2c_smbus_write_byte_data(client, reg, val);
+}
+
+static int adxl34x_smbus_read_block(struct device *dev,
+ unsigned char reg, int count,
+ void *buf)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+
+ return i2c_smbus_read_i2c_block_data(client, reg, count, buf);
+}
+
+static int adxl34x_i2c_read_block(struct device *dev,
+ unsigned char reg, int count,
+ void *buf)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ int ret;
+
+ ret = i2c_master_send(client, &reg, 1);
+ if (ret < 0)
+ return ret;
+
+ ret = i2c_master_recv(client, buf, count);
+ if (ret < 0)
+ return ret;
+
+ if (ret != count)
+ return -EIO;
+
+ return 0;
+}
+
+static const struct adxl34x_bus_ops adxl34x_smbus_bops = {
+ .bustype = BUS_I2C,
+ .write = adxl34x_smbus_write,
+ .read = adxl34x_smbus_read,
+ .read_block = adxl34x_smbus_read_block,
+};
+
+static const struct adxl34x_bus_ops adxl34x_i2c_bops = {
+ .bustype = BUS_I2C,
+ .write = adxl34x_smbus_write,
+ .read = adxl34x_smbus_read,
+ .read_block = adxl34x_i2c_read_block,
+};
+
+static int __devinit adxl34x_i2c_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct adxl34x *ac;
+ int error;
+
+ error = i2c_check_functionality(client->adapter,
+ I2C_FUNC_SMBUS_BYTE_DATA);
+ if (!error) {
+ dev_err(&client->dev, "SMBUS Byte Data not Supported\n");
+ return -EIO;
+ }
+
+ ac = adxl34x_probe(&client->dev, client->irq, false,
+ i2c_check_functionality(client->adapter,
+ I2C_FUNC_SMBUS_READ_I2C_BLOCK) ?
+ &adxl34x_smbus_bops : &adxl34x_i2c_bops);
+ if (IS_ERR(ac))
+ return PTR_ERR(ac);
+
+ i2c_set_clientdata(client, ac);
+
+ return 0;
+}
+
+static int __devexit adxl34x_i2c_remove(struct i2c_client *client)
+{
+ struct adxl34x *ac = i2c_get_clientdata(client);
+
+ return adxl34x_remove(ac);
+}
+
+#ifdef CONFIG_PM
+static int adxl34x_i2c_suspend(struct i2c_client *client, pm_message_t message)
+{
+ struct adxl34x *ac = i2c_get_clientdata(client);
+
+ adxl34x_suspend(ac);
+
+ return 0;
+}
+
+static int adxl34x_i2c_resume(struct i2c_client *client)
+{
+ struct adxl34x *ac = i2c_get_clientdata(client);
+
+ adxl34x_resume(ac);
+
+ return 0;
+}
+#else
+# define adxl34x_i2c_suspend NULL
+# define adxl34x_i2c_resume NULL
+#endif
+
+static const struct i2c_device_id adxl34x_id[] = {
+ { "adxl34x", 0 },
+ { }
+};
+
+MODULE_DEVICE_TABLE(i2c, adxl34x_id);
+
+static struct i2c_driver adxl34x_driver = {
+ .driver = {
+ .name = "adxl34x",
+ .owner = THIS_MODULE,
+ },
+ .probe = adxl34x_i2c_probe,
+ .remove = __devexit_p(adxl34x_i2c_remove),
+ .suspend = adxl34x_i2c_suspend,
+ .resume = adxl34x_i2c_resume,
+ .id_table = adxl34x_id,
+};
+
+static int __init adxl34x_i2c_init(void)
+{
+ return i2c_add_driver(&adxl34x_driver);
+}
+module_init(adxl34x_i2c_init);
+
+static void __exit adxl34x_i2c_exit(void)
+{
+ i2c_del_driver(&adxl34x_driver);
+}
+module_exit(adxl34x_i2c_exit);
+
+MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
+MODULE_DESCRIPTION("ADXL345/346 Three-Axis Digital Accelerometer I2C Bus Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/input/misc/adxl34x-spi.c b/drivers/input/misc/adxl34x-spi.c
new file mode 100644
index 00000000000..782de9e8982
--- /dev/null
+++ b/drivers/input/misc/adxl34x-spi.c
@@ -0,0 +1,145 @@
+/*
+ * ADLX345/346 Three-Axis Digital Accelerometers (SPI Interface)
+ *
+ * Enter bugs at http://blackfin.uclinux.org/
+ *
+ * Copyright (C) 2009 Michael Hennerich, Analog Devices Inc.
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/input.h> /* BUS_SPI */
+#include <linux/module.h>
+#include <linux/spi/spi.h>
+#include <linux/types.h>
+#include "adxl34x.h"
+
+#define MAX_SPI_FREQ_HZ 5000000
+#define MAX_FREQ_NO_FIFODELAY 1500000
+#define ADXL34X_CMD_MULTB (1 << 6)
+#define ADXL34X_CMD_READ (1 << 7)
+#define ADXL34X_WRITECMD(reg) (reg & 0x3F)
+#define ADXL34X_READCMD(reg) (ADXL34X_CMD_READ | (reg & 0x3F))
+#define ADXL34X_READMB_CMD(reg) (ADXL34X_CMD_READ | ADXL34X_CMD_MULTB \
+ | (reg & 0x3F))
+
+static int adxl34x_spi_read(struct device *dev, unsigned char reg)
+{
+ struct spi_device *spi = to_spi_device(dev);
+ unsigned char cmd;
+
+ cmd = ADXL34X_READCMD(reg);
+
+ return spi_w8r8(spi, cmd);
+}
+
+static int adxl34x_spi_write(struct device *dev,
+ unsigned char reg, unsigned char val)
+{
+ struct spi_device *spi = to_spi_device(dev);
+ unsigned char buf[2];
+
+ buf[0] = ADXL34X_WRITECMD(reg);
+ buf[1] = val;
+
+ return spi_write(spi, buf, sizeof(buf));
+}
+
+static int adxl34x_spi_read_block(struct device *dev,
+ unsigned char reg, int count,
+ void *buf)
+{
+ struct spi_device *spi = to_spi_device(dev);
+ ssize_t status;
+
+ reg = ADXL34X_READMB_CMD(reg);
+ status = spi_write_then_read(spi, &reg, 1, buf, count);
+
+ return (status < 0) ? status : 0;
+}
+
+static const struct adxl34x_bus_ops adx134x_spi_bops = {
+ .bustype = BUS_SPI,
+ .write = adxl34x_spi_write,
+ .read = adxl34x_spi_read,
+ .read_block = adxl34x_spi_read_block,
+};
+
+static int __devinit adxl34x_spi_probe(struct spi_device *spi)
+{
+ struct adxl34x *ac;
+
+ /* don't exceed max specified SPI CLK frequency */
+ if (spi->max_speed_hz > MAX_SPI_FREQ_HZ) {
+ dev_err(&spi->dev, "SPI CLK %d Hz too fast\n", spi->max_speed_hz);
+ return -EINVAL;
+ }
+
+ ac = adxl34x_probe(&spi->dev, spi->irq,
+ spi->max_speed_hz > MAX_FREQ_NO_FIFODELAY,
+ &adx134x_spi_bops);
+
+ if (IS_ERR(ac))
+ return PTR_ERR(ac);
+
+ spi_set_drvdata(spi, ac);
+
+ return 0;
+}
+
+static int __devexit adxl34x_spi_remove(struct spi_device *spi)
+{
+ struct adxl34x *ac = dev_get_drvdata(&spi->dev);
+
+ return adxl34x_remove(ac);
+}
+
+#ifdef CONFIG_PM
+static int adxl34x_spi_suspend(struct spi_device *spi, pm_message_t message)
+{
+ struct adxl34x *ac = dev_get_drvdata(&spi->dev);
+
+ adxl34x_suspend(ac);
+
+ return 0;
+}
+
+static int adxl34x_spi_resume(struct spi_device *spi)
+{
+ struct adxl34x *ac = dev_get_drvdata(&spi->dev);
+
+ adxl34x_resume(ac);
+
+ return 0;
+}
+#else
+# define adxl34x_spi_suspend NULL
+# define adxl34x_spi_resume NULL
+#endif
+
+static struct spi_driver adxl34x_driver = {
+ .driver = {
+ .name = "adxl34x",
+ .bus = &spi_bus_type,
+ .owner = THIS_MODULE,
+ },
+ .probe = adxl34x_spi_probe,
+ .remove = __devexit_p(adxl34x_spi_remove),
+ .suspend = adxl34x_spi_suspend,
+ .resume = adxl34x_spi_resume,
+};
+
+static int __init adxl34x_spi_init(void)
+{
+ return spi_register_driver(&adxl34x_driver);
+}
+module_init(adxl34x_spi_init);
+
+static void __exit adxl34x_spi_exit(void)
+{
+ spi_unregister_driver(&adxl34x_driver);
+}
+module_exit(adxl34x_spi_exit);
+
+MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
+MODULE_DESCRIPTION("ADXL345/346 Three-Axis Digital Accelerometer SPI Bus Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/input/misc/adxl34x.c b/drivers/input/misc/adxl34x.c
new file mode 100644
index 00000000000..e2ca0170808
--- /dev/null
+++ b/drivers/input/misc/adxl34x.c
@@ -0,0 +1,915 @@
+/*
+ * ADXL345/346 Three-Axis Digital Accelerometers
+ *
+ * Enter bugs at http://blackfin.uclinux.org/
+ *
+ * Copyright (C) 2009 Michael Hennerich, Analog Devices Inc.
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/device.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/slab.h>
+#include <linux/workqueue.h>
+#include <linux/input/adxl34x.h>
+
+#include "adxl34x.h"
+
+/* ADXL345/6 Register Map */
+#define DEVID 0x00 /* R Device ID */
+#define THRESH_TAP 0x1D /* R/W Tap threshold */
+#define OFSX 0x1E /* R/W X-axis offset */
+#define OFSY 0x1F /* R/W Y-axis offset */
+#define OFSZ 0x20 /* R/W Z-axis offset */
+#define DUR 0x21 /* R/W Tap duration */
+#define LATENT 0x22 /* R/W Tap latency */
+#define WINDOW 0x23 /* R/W Tap window */
+#define THRESH_ACT 0x24 /* R/W Activity threshold */
+#define THRESH_INACT 0x25 /* R/W Inactivity threshold */
+#define TIME_INACT 0x26 /* R/W Inactivity time */
+#define ACT_INACT_CTL 0x27 /* R/W Axis enable control for activity and */
+ /* inactivity detection */
+#define THRESH_FF 0x28 /* R/W Free-fall threshold */
+#define TIME_FF 0x29 /* R/W Free-fall time */
+#define TAP_AXES 0x2A /* R/W Axis control for tap/double tap */
+#define ACT_TAP_STATUS 0x2B /* R Source of tap/double tap */
+#define BW_RATE 0x2C /* R/W Data rate and power mode control */
+#define POWER_CTL 0x2D /* R/W Power saving features control */
+#define INT_ENABLE 0x2E /* R/W Interrupt enable control */
+#define INT_MAP 0x2F /* R/W Interrupt mapping control */
+#define INT_SOURCE 0x30 /* R Source of interrupts */
+#define DATA_FORMAT 0x31 /* R/W Data format control */
+#define DATAX0 0x32 /* R X-Axis Data 0 */
+#define DATAX1 0x33 /* R X-Axis Data 1 */
+#define DATAY0 0x34 /* R Y-Axis Data 0 */
+#define DATAY1 0x35 /* R Y-Axis Data 1 */
+#define DATAZ0 0x36 /* R Z-Axis Data 0 */
+#define DATAZ1 0x37 /* R Z-Axis Data 1 */
+#define FIFO_CTL 0x38 /* R/W FIFO control */
+#define FIFO_STATUS 0x39 /* R FIFO status */
+#define TAP_SIGN 0x3A /* R Sign and source for tap/double tap */
+/* Orientation ADXL346 only */
+#define ORIENT_CONF 0x3B /* R/W Orientation configuration */
+#define ORIENT 0x3C /* R Orientation status */
+
+/* DEVIDs */
+#define ID_ADXL345 0xE5
+#define ID_ADXL346 0xE6
+
+/* INT_ENABLE/INT_MAP/INT_SOURCE Bits */
+#define DATA_READY (1 << 7)
+#define SINGLE_TAP (1 << 6)
+#define DOUBLE_TAP (1 << 5)
+#define ACTIVITY (1 << 4)
+#define INACTIVITY (1 << 3)
+#define FREE_FALL (1 << 2)
+#define WATERMARK (1 << 1)
+#define OVERRUN (1 << 0)
+
+/* ACT_INACT_CONTROL Bits */
+#define ACT_ACDC (1 << 7)
+#define ACT_X_EN (1 << 6)
+#define ACT_Y_EN (1 << 5)
+#define ACT_Z_EN (1 << 4)
+#define INACT_ACDC (1 << 3)
+#define INACT_X_EN (1 << 2)
+#define INACT_Y_EN (1 << 1)
+#define INACT_Z_EN (1 << 0)
+
+/* TAP_AXES Bits */
+#define SUPPRESS (1 << 3)
+#define TAP_X_EN (1 << 2)
+#define TAP_Y_EN (1 << 1)
+#define TAP_Z_EN (1 << 0)
+
+/* ACT_TAP_STATUS Bits */
+#define ACT_X_SRC (1 << 6)
+#define ACT_Y_SRC (1 << 5)
+#define ACT_Z_SRC (1 << 4)
+#define ASLEEP (1 << 3)
+#define TAP_X_SRC (1 << 2)
+#define TAP_Y_SRC (1 << 1)
+#define TAP_Z_SRC (1 << 0)
+
+/* BW_RATE Bits */
+#define LOW_POWER (1 << 4)
+#define RATE(x) ((x) & 0xF)
+
+/* POWER_CTL Bits */
+#define PCTL_LINK (1 << 5)
+#define PCTL_AUTO_SLEEP (1 << 4)
+#define PCTL_MEASURE (1 << 3)
+#define PCTL_SLEEP (1 << 2)
+#define PCTL_WAKEUP(x) ((x) & 0x3)
+
+/* DATA_FORMAT Bits */
+#define SELF_TEST (1 << 7)
+#define SPI (1 << 6)
+#define INT_INVERT (1 << 5)
+#define FULL_RES (1 << 3)
+#define JUSTIFY (1 << 2)
+#define RANGE(x) ((x) & 0x3)
+#define RANGE_PM_2g 0
+#define RANGE_PM_4g 1
+#define RANGE_PM_8g 2
+#define RANGE_PM_16g 3
+
+/*
+ * Maximum value our axis may get in full res mode for the input device
+ * (signed 13 bits)
+ */
+#define ADXL_FULLRES_MAX_VAL 4096
+
+/*
+ * Maximum value our axis may get in fixed res mode for the input device
+ * (signed 10 bits)
+ */
+#define ADXL_FIXEDRES_MAX_VAL 512
+
+/* FIFO_CTL Bits */
+#define FIFO_MODE(x) (((x) & 0x3) << 6)
+#define FIFO_BYPASS 0
+#define FIFO_FIFO 1
+#define FIFO_STREAM 2
+#define FIFO_TRIGGER 3
+#define TRIGGER (1 << 5)
+#define SAMPLES(x) ((x) & 0x1F)
+
+/* FIFO_STATUS Bits */
+#define FIFO_TRIG (1 << 7)
+#define ENTRIES(x) ((x) & 0x3F)
+
+/* TAP_SIGN Bits ADXL346 only */
+#define XSIGN (1 << 6)
+#define YSIGN (1 << 5)
+#define ZSIGN (1 << 4)
+#define XTAP (1 << 3)
+#define YTAP (1 << 2)
+#define ZTAP (1 << 1)
+
+/* ORIENT_CONF ADXL346 only */
+#define ORIENT_DEADZONE(x) (((x) & 0x7) << 4)
+#define ORIENT_DIVISOR(x) ((x) & 0x7)
+
+/* ORIENT ADXL346 only */
+#define ADXL346_2D_VALID (1 << 6)
+#define ADXL346_2D_ORIENT(x) (((x) & 0x3) >> 4)
+#define ADXL346_3D_VALID (1 << 3)
+#define ADXL346_3D_ORIENT(x) ((x) & 0x7)
+#define ADXL346_2D_PORTRAIT_POS 0 /* +X */
+#define ADXL346_2D_PORTRAIT_NEG 1 /* -X */
+#define ADXL346_2D_LANDSCAPE_POS 2 /* +Y */
+#define ADXL346_2D_LANDSCAPE_NEG 3 /* -Y */
+
+#define ADXL346_3D_FRONT 3 /* +X */
+#define ADXL346_3D_BACK 4 /* -X */
+#define ADXL346_3D_RIGHT 2 /* +Y */
+#define ADXL346_3D_LEFT 5 /* -Y */
+#define ADXL346_3D_TOP 1 /* +Z */
+#define ADXL346_3D_BOTTOM 6 /* -Z */
+
+#undef ADXL_DEBUG
+
+#define ADXL_X_AXIS 0
+#define ADXL_Y_AXIS 1
+#define ADXL_Z_AXIS 2
+
+#define AC_READ(ac, reg) ((ac)->bops->read((ac)->dev, reg))
+#define AC_WRITE(ac, reg, val) ((ac)->bops->write((ac)->dev, reg, val))
+
+struct axis_triple {
+ int x;
+ int y;
+ int z;
+};
+
+struct adxl34x {
+ struct device *dev;
+ struct input_dev *input;
+ struct mutex mutex; /* reentrant protection for struct */
+ struct adxl34x_platform_data pdata;
+ struct axis_triple swcal;
+ struct axis_triple hwcal;
+ struct axis_triple saved;
+ char phys[32];
+ unsigned orient2d_saved;
+ unsigned orient3d_saved;
+ bool disabled; /* P: mutex */
+ bool opened; /* P: mutex */
+ bool suspended; /* P: mutex */
+ bool fifo_delay;
+ int irq;
+ unsigned model;
+ unsigned int_mask;
+
+ const struct adxl34x_bus_ops *bops;
+};
+
+static const struct adxl34x_platform_data adxl34x_default_init = {
+ .tap_threshold = 35,
+ .tap_duration = 3,
+ .tap_latency = 20,
+ .tap_window = 20,
+ .tap_axis_control = ADXL_TAP_X_EN | ADXL_TAP_Y_EN | ADXL_TAP_Z_EN,
+ .act_axis_control = 0xFF,
+ .activity_threshold = 6,
+ .inactivity_threshold = 4,
+ .inactivity_time = 3,
+ .free_fall_threshold = 8,
+ .free_fall_time = 0x20,
+ .data_rate = 8,
+ .data_range = ADXL_FULL_RES,
+
+ .ev_type = EV_ABS,
+ .ev_code_x = ABS_X, /* EV_REL */
+ .ev_code_y = ABS_Y, /* EV_REL */
+ .ev_code_z = ABS_Z, /* EV_REL */
+
+ .ev_code_tap = {BTN_TOUCH, BTN_TOUCH, BTN_TOUCH}, /* EV_KEY {x,y,z} */
+ .power_mode = ADXL_AUTO_SLEEP | ADXL_LINK,
+ .fifo_mode = FIFO_STREAM,
+ .watermark = 0,
+};
+
+static void adxl34x_get_triple(struct adxl34x *ac, struct axis_triple *axis)
+{
+ short buf[3];
+
+ ac->bops->read_block(ac->dev, DATAX0, DATAZ1 - DATAX0 + 1, buf);
+
+ mutex_lock(&ac->mutex);
+ ac->saved.x = (s16) le16_to_cpu(buf[0]);
+ axis->x = ac->saved.x;
+
+ ac->saved.y = (s16) le16_to_cpu(buf[1]);
+ axis->y = ac->saved.y;
+
+ ac->saved.z = (s16) le16_to_cpu(buf[2]);
+ axis->z = ac->saved.z;
+ mutex_unlock(&ac->mutex);
+}
+
+static void adxl34x_service_ev_fifo(struct adxl34x *ac)
+{
+ struct adxl34x_platform_data *pdata = &ac->pdata;
+ struct axis_triple axis;
+
+ adxl34x_get_triple(ac, &axis);
+
+ input_event(ac->input, pdata->ev_type, pdata->ev_code_x,
+ axis.x - ac->swcal.x);
+ input_event(ac->input, pdata->ev_type, pdata->ev_code_y,
+ axis.y - ac->swcal.y);
+ input_event(ac->input, pdata->ev_type, pdata->ev_code_z,
+ axis.z - ac->swcal.z);
+}
+
+static void adxl34x_report_key_single(struct input_dev *input, int key)
+{
+ input_report_key(input, key, true);
+ input_sync(input);
+ input_report_key(input, key, false);
+}
+
+static void adxl34x_send_key_events(struct adxl34x *ac,
+ struct adxl34x_platform_data *pdata, int status, int press)
+{
+ int i;
+
+ for (i = ADXL_X_AXIS; i <= ADXL_Z_AXIS; i++) {
+ if (status & (1 << (ADXL_Z_AXIS - i)))
+ input_report_key(ac->input,
+ pdata->ev_code_tap[i], press);
+ }
+}
+
+static void adxl34x_do_tap(struct adxl34x *ac,
+ struct adxl34x_platform_data *pdata, int status)
+{
+ adxl34x_send_key_events(ac, pdata, status, true);
+ input_sync(ac->input);
+ adxl34x_send_key_events(ac, pdata, status, false);
+}
+
+static irqreturn_t adxl34x_irq(int irq, void *handle)
+{
+ struct adxl34x *ac = handle;
+ struct adxl34x_platform_data *pdata = &ac->pdata;
+ int int_stat, tap_stat, samples, orient, orient_code;
+
+ /*
+ * ACT_TAP_STATUS should be read before clearing the interrupt
+ * Avoid reading ACT_TAP_STATUS in case TAP detection is disabled
+ */
+
+ if (pdata->tap_axis_control & (TAP_X_EN | TAP_Y_EN | TAP_Z_EN))
+ tap_stat = AC_READ(ac, ACT_TAP_STATUS);
+ else
+ tap_stat = 0;
+
+ int_stat = AC_READ(ac, INT_SOURCE);
+
+ if (int_stat & FREE_FALL)
+ adxl34x_report_key_single(ac->input, pdata->ev_code_ff);
+
+ if (int_stat & OVERRUN)
+ dev_dbg(ac->dev, "OVERRUN\n");
+
+ if (int_stat & (SINGLE_TAP | DOUBLE_TAP)) {
+ adxl34x_do_tap(ac, pdata, tap_stat);
+
+ if (int_stat & DOUBLE_TAP)
+ adxl34x_do_tap(ac, pdata, tap_stat);
+ }
+
+ if (pdata->ev_code_act_inactivity) {
+ if (int_stat & ACTIVITY)
+ input_report_key(ac->input,
+ pdata->ev_code_act_inactivity, 1);
+ if (int_stat & INACTIVITY)
+ input_report_key(ac->input,
+ pdata->ev_code_act_inactivity, 0);
+ }
+
+ /*
+ * ORIENTATION SENSING ADXL346 only
+ */
+ if (pdata->orientation_enable) {
+ orient = AC_READ(ac, ORIENT);
+ if ((pdata->orientation_enable & ADXL_EN_ORIENTATION_2D) &&
+ (orient & ADXL346_2D_VALID)) {
+
+ orient_code = ADXL346_2D_ORIENT(orient);
+ /* Report orientation only when it changes */
+ if (ac->orient2d_saved != orient_code) {
+ ac->orient2d_saved = orient_code;
+ adxl34x_report_key_single(ac->input,
+ pdata->ev_codes_orient_2d[orient_code]);
+ }
+ }
+
+ if ((pdata->orientation_enable & ADXL_EN_ORIENTATION_3D) &&
+ (orient & ADXL346_3D_VALID)) {
+
+ orient_code = ADXL346_3D_ORIENT(orient) - 1;
+ /* Report orientation only when it changes */
+ if (ac->orient3d_saved != orient_code) {
+ ac->orient3d_saved = orient_code;
+ adxl34x_report_key_single(ac->input,
+ pdata->ev_codes_orient_3d[orient_code]);
+ }
+ }
+ }
+
+ if (int_stat & (DATA_READY | WATERMARK)) {
+
+ if (pdata->fifo_mode)
+ samples = ENTRIES(AC_READ(ac, FIFO_STATUS)) + 1;
+ else
+ samples = 1;
+
+ for (; samples > 0; samples--) {
+ adxl34x_service_ev_fifo(ac);
+ /*
+ * To ensure that the FIFO has
+ * completely popped, there must be at least 5 us between
+ * the end of reading the data registers, signified by the
+ * transition to register 0x38 from 0x37 or the CS pin
+ * going high, and the start of new reads of the FIFO or
+ * reading the FIFO_STATUS register. For SPI operation at
+ * 1.5 MHz or lower, the register addressing portion of the
+ * transmission is sufficient delay to ensure the FIFO has
+ * completely popped. It is necessary for SPI operation
+ * greater than 1.5 MHz to de-assert the CS pin to ensure a
+ * total of 5 us, which is at most 3.4 us at 5 MHz
+ * operation.
+ */
+ if (ac->fifo_delay && (samples > 1))
+ udelay(3);
+ }
+ }
+
+ input_sync(ac->input);
+
+ return IRQ_HANDLED;
+}
+
+static void __adxl34x_disable(struct adxl34x *ac)
+{
+ /*
+ * A '0' places the ADXL34x into standby mode
+ * with minimum power consumption.
+ */
+ AC_WRITE(ac, POWER_CTL, 0);
+}
+
+static void __adxl34x_enable(struct adxl34x *ac)
+{
+ AC_WRITE(ac, POWER_CTL, ac->pdata.power_mode | PCTL_MEASURE);
+}
+
+void adxl34x_suspend(struct adxl34x *ac)
+{
+ mutex_lock(&ac->mutex);
+
+ if (!ac->suspended && !ac->disabled && ac->opened)
+ __adxl34x_disable(ac);
+
+ ac->suspended = true;
+
+ mutex_unlock(&ac->mutex);
+}
+EXPORT_SYMBOL_GPL(adxl34x_suspend);
+
+void adxl34x_resume(struct adxl34x *ac)
+{
+ mutex_lock(&ac->mutex);
+
+ if (ac->suspended && !ac->disabled && ac->opened)
+ __adxl34x_enable(ac);
+
+ ac->suspended = false;
+
+ mutex_unlock(&ac->mutex);
+}
+EXPORT_SYMBOL_GPL(adxl34x_resume);
+
+static ssize_t adxl34x_disable_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct adxl34x *ac = dev_get_drvdata(dev);
+
+ return sprintf(buf, "%u\n", ac->disabled);
+}
+
+static ssize_t adxl34x_disable_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct adxl34x *ac = dev_get_drvdata(dev);
+ unsigned long val;
+ int error;
+
+ error = strict_strtoul(buf, 10, &val);
+ if (error)
+ return error;
+
+ mutex_lock(&ac->mutex);
+
+ if (!ac->suspended && ac->opened) {
+ if (val) {
+ if (!ac->disabled)
+ __adxl34x_disable(ac);
+ } else {
+ if (ac->disabled)
+ __adxl34x_enable(ac);
+ }
+ }
+
+ ac->disabled = !!val;
+
+ mutex_unlock(&ac->mutex);
+
+ return count;
+}
+
+static DEVICE_ATTR(disable, 0664, adxl34x_disable_show, adxl34x_disable_store);
+
+static ssize_t adxl34x_calibrate_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct adxl34x *ac = dev_get_drvdata(dev);
+ ssize_t count;
+
+ mutex_lock(&ac->mutex);
+ count = sprintf(buf, "%d,%d,%d\n",
+ ac->hwcal.x * 4 + ac->swcal.x,
+ ac->hwcal.y * 4 + ac->swcal.y,
+ ac->hwcal.z * 4 + ac->swcal.z);
+ mutex_unlock(&ac->mutex);
+
+ return count;
+}
+
+static ssize_t adxl34x_calibrate_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct adxl34x *ac = dev_get_drvdata(dev);
+
+ /*
+ * Hardware offset calibration has a resolution of 15.6 mg/LSB.
+ * We use HW calibration and handle the remaining bits in SW. (4mg/LSB)
+ */
+
+ mutex_lock(&ac->mutex);
+ ac->hwcal.x -= (ac->saved.x / 4);
+ ac->swcal.x = ac->saved.x % 4;
+
+ ac->hwcal.y -= (ac->saved.y / 4);
+ ac->swcal.y = ac->saved.y % 4;
+
+ ac->hwcal.z -= (ac->saved.z / 4);
+ ac->swcal.z = ac->saved.z % 4;
+
+ AC_WRITE(ac, OFSX, (s8) ac->hwcal.x);
+ AC_WRITE(ac, OFSY, (s8) ac->hwcal.y);
+ AC_WRITE(ac, OFSZ, (s8) ac->hwcal.z);
+ mutex_unlock(&ac->mutex);
+
+ return count;
+}
+
+static DEVICE_ATTR(calibrate, 0664,
+ adxl34x_calibrate_show, adxl34x_calibrate_store);
+
+static ssize_t adxl34x_rate_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct adxl34x *ac = dev_get_drvdata(dev);
+
+ return sprintf(buf, "%u\n", RATE(ac->pdata.data_rate));
+}
+
+static ssize_t adxl34x_rate_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct adxl34x *ac = dev_get_drvdata(dev);
+ unsigned long val;
+ int error;
+
+ error = strict_strtoul(buf, 10, &val);
+ if (error)
+ return error;
+
+ mutex_lock(&ac->mutex);
+
+ ac->pdata.data_rate = RATE(val);
+ AC_WRITE(ac, BW_RATE,
+ ac->pdata.data_rate |
+ (ac->pdata.low_power_mode ? LOW_POWER : 0));
+
+ mutex_unlock(&ac->mutex);
+
+ return count;
+}
+
+static DEVICE_ATTR(rate, 0664, adxl34x_rate_show, adxl34x_rate_store);
+
+static ssize_t adxl34x_autosleep_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct adxl34x *ac = dev_get_drvdata(dev);
+
+ return sprintf(buf, "%u\n",
+ ac->pdata.power_mode & (PCTL_AUTO_SLEEP | PCTL_LINK) ? 1 : 0);
+}
+
+static ssize_t adxl34x_autosleep_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct adxl34x *ac = dev_get_drvdata(dev);
+ unsigned long val;
+ int error;
+
+ error = strict_strtoul(buf, 10, &val);
+ if (error)
+ return error;
+
+ mutex_lock(&ac->mutex);
+
+ if (val)
+ ac->pdata.power_mode |= (PCTL_AUTO_SLEEP | PCTL_LINK);
+ else
+ ac->pdata.power_mode &= ~(PCTL_AUTO_SLEEP | PCTL_LINK);
+
+ if (!ac->disabled && !ac->suspended && ac->opened)
+ AC_WRITE(ac, POWER_CTL, ac->pdata.power_mode | PCTL_MEASURE);
+
+ mutex_unlock(&ac->mutex);
+
+ return count;
+}
+
+static DEVICE_ATTR(autosleep, 0664,
+ adxl34x_autosleep_show, adxl34x_autosleep_store);
+
+static ssize_t adxl34x_position_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct adxl34x *ac = dev_get_drvdata(dev);
+ ssize_t count;
+
+ mutex_lock(&ac->mutex);
+ count = sprintf(buf, "(%d, %d, %d)\n",
+ ac->saved.x, ac->saved.y, ac->saved.z);
+ mutex_unlock(&ac->mutex);
+
+ return count;
+}
+
+static DEVICE_ATTR(position, S_IRUGO, adxl34x_position_show, NULL);
+
+#ifdef ADXL_DEBUG
+static ssize_t adxl34x_write_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct adxl34x *ac = dev_get_drvdata(dev);
+ unsigned long val;
+ int error;
+
+ /*
+ * This allows basic ADXL register write access for debug purposes.
+ */
+ error = strict_strtoul(buf, 16, &val);
+ if (error)
+ return error;
+
+ mutex_lock(&ac->mutex);
+ AC_WRITE(ac, val >> 8, val & 0xFF);
+ mutex_unlock(&ac->mutex);
+
+ return count;
+}
+
+static DEVICE_ATTR(write, 0664, NULL, adxl34x_write_store);
+#endif
+
+static struct attribute *adxl34x_attributes[] = {
+ &dev_attr_disable.attr,
+ &dev_attr_calibrate.attr,
+ &dev_attr_rate.attr,
+ &dev_attr_autosleep.attr,
+ &dev_attr_position.attr,
+#ifdef ADXL_DEBUG
+ &dev_attr_write.attr,
+#endif
+ NULL
+};
+
+static const struct attribute_group adxl34x_attr_group = {
+ .attrs = adxl34x_attributes,
+};
+
+static int adxl34x_input_open(struct input_dev *input)
+{
+ struct adxl34x *ac = input_get_drvdata(input);
+
+ mutex_lock(&ac->mutex);
+
+ if (!ac->suspended && !ac->disabled)
+ __adxl34x_enable(ac);
+
+ ac->opened = true;
+
+ mutex_unlock(&ac->mutex);
+
+ return 0;
+}
+
+static void adxl34x_input_close(struct input_dev *input)
+{
+ struct adxl34x *ac = input_get_drvdata(input);
+
+ mutex_lock(&ac->mutex);
+
+ if (!ac->suspended && !ac->disabled)
+ __adxl34x_disable(ac);
+
+ ac->opened = false;
+
+ mutex_unlock(&ac->mutex);
+}
+
+struct adxl34x *adxl34x_probe(struct device *dev, int irq,
+ bool fifo_delay_default,
+ const struct adxl34x_bus_ops *bops)
+{
+ struct adxl34x *ac;
+ struct input_dev *input_dev;
+ const struct adxl34x_platform_data *pdata;
+ int err, range, i;
+ unsigned char revid;
+
+ if (!irq) {
+ dev_err(dev, "no IRQ?\n");
+ err = -ENODEV;
+ goto err_out;
+ }
+
+ ac = kzalloc(sizeof(*ac), GFP_KERNEL);
+ input_dev = input_allocate_device();
+ if (!ac || !input_dev) {
+ err = -ENOMEM;
+ goto err_free_mem;
+ }
+
+ ac->fifo_delay = fifo_delay_default;
+
+ pdata = dev->platform_data;
+ if (!pdata) {
+ dev_dbg(dev,
+ "No platfrom data: Using default initialization\n");
+ pdata = &adxl34x_default_init;
+ }
+
+ ac->pdata = *pdata;
+ pdata = &ac->pdata;
+
+ ac->input = input_dev;
+ ac->disabled = true;
+ ac->dev = dev;
+ ac->irq = irq;
+ ac->bops = bops;
+
+ mutex_init(&ac->mutex);
+
+ input_dev->name = "ADXL34x accelerometer";
+ revid = ac->bops->read(dev, DEVID);
+
+ switch (revid) {
+ case ID_ADXL345:
+ ac->model = 345;
+ break;
+ case ID_ADXL346:
+ ac->model = 346;
+ break;
+ default:
+ dev_err(dev, "Failed to probe %s\n", input_dev->name);
+ err = -ENODEV;
+ goto err_free_mem;
+ }
+
+ snprintf(ac->phys, sizeof(ac->phys), "%s/input0", dev_name(dev));
+
+ input_dev->phys = ac->phys;
+ input_dev->dev.parent = dev;
+ input_dev->id.product = ac->model;
+ input_dev->id.bustype = bops->bustype;
+ input_dev->open = adxl34x_input_open;
+ input_dev->close = adxl34x_input_close;
+
+ input_set_drvdata(input_dev, ac);
+
+ __set_bit(ac->pdata.ev_type, input_dev->evbit);
+
+ if (ac->pdata.ev_type == EV_REL) {
+ __set_bit(REL_X, input_dev->relbit);
+ __set_bit(REL_Y, input_dev->relbit);
+ __set_bit(REL_Z, input_dev->relbit);
+ } else {
+ /* EV_ABS */
+ __set_bit(ABS_X, input_dev->absbit);
+ __set_bit(ABS_Y, input_dev->absbit);
+ __set_bit(ABS_Z, input_dev->absbit);
+
+ if (pdata->data_range & FULL_RES)
+ range = ADXL_FULLRES_MAX_VAL; /* Signed 13-bit */
+ else
+ range = ADXL_FIXEDRES_MAX_VAL; /* Signed 10-bit */
+
+ input_set_abs_params(input_dev, ABS_X, -range, range, 3, 3);
+ input_set_abs_params(input_dev, ABS_Y, -range, range, 3, 3);
+ input_set_abs_params(input_dev, ABS_Z, -range, range, 3, 3);
+ }
+
+ __set_bit(EV_KEY, input_dev->evbit);
+ __set_bit(pdata->ev_code_tap[ADXL_X_AXIS], input_dev->keybit);
+ __set_bit(pdata->ev_code_tap[ADXL_Y_AXIS], input_dev->keybit);
+ __set_bit(pdata->ev_code_tap[ADXL_Z_AXIS], input_dev->keybit);
+
+ if (pdata->ev_code_ff) {
+ ac->int_mask = FREE_FALL;
+ __set_bit(pdata->ev_code_ff, input_dev->keybit);
+ }
+
+ if (pdata->ev_code_act_inactivity)
+ __set_bit(pdata->ev_code_act_inactivity, input_dev->keybit);
+
+ ac->int_mask |= ACTIVITY | INACTIVITY;
+
+ if (pdata->watermark) {
+ ac->int_mask |= WATERMARK;
+ if (!FIFO_MODE(pdata->fifo_mode))
+ ac->pdata.fifo_mode |= FIFO_STREAM;
+ } else {
+ ac->int_mask |= DATA_READY;
+ }
+
+ if (pdata->tap_axis_control & (TAP_X_EN | TAP_Y_EN | TAP_Z_EN))
+ ac->int_mask |= SINGLE_TAP | DOUBLE_TAP;
+
+ if (FIFO_MODE(pdata->fifo_mode) == FIFO_BYPASS)
+ ac->fifo_delay = false;
+
+ ac->bops->write(dev, POWER_CTL, 0);
+
+ err = request_threaded_irq(ac->irq, NULL, adxl34x_irq,
+ IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
+ dev_name(dev), ac);
+ if (err) {
+ dev_err(dev, "irq %d busy?\n", ac->irq);
+ goto err_free_mem;
+ }
+
+ err = sysfs_create_group(&dev->kobj, &adxl34x_attr_group);
+ if (err)
+ goto err_free_irq;
+
+ err = input_register_device(input_dev);
+ if (err)
+ goto err_remove_attr;
+
+ AC_WRITE(ac, THRESH_TAP, pdata->tap_threshold);
+ AC_WRITE(ac, OFSX, pdata->x_axis_offset);
+ ac->hwcal.x = pdata->x_axis_offset;
+ AC_WRITE(ac, OFSY, pdata->y_axis_offset);
+ ac->hwcal.y = pdata->y_axis_offset;
+ AC_WRITE(ac, OFSZ, pdata->z_axis_offset);
+ ac->hwcal.z = pdata->z_axis_offset;
+ AC_WRITE(ac, THRESH_TAP, pdata->tap_threshold);
+ AC_WRITE(ac, DUR, pdata->tap_duration);
+ AC_WRITE(ac, LATENT, pdata->tap_latency);
+ AC_WRITE(ac, WINDOW, pdata->tap_window);
+ AC_WRITE(ac, THRESH_ACT, pdata->activity_threshold);
+ AC_WRITE(ac, THRESH_INACT, pdata->inactivity_threshold);
+ AC_WRITE(ac, TIME_INACT, pdata->inactivity_time);
+ AC_WRITE(ac, THRESH_FF, pdata->free_fall_threshold);
+ AC_WRITE(ac, TIME_FF, pdata->free_fall_time);
+ AC_WRITE(ac, TAP_AXES, pdata->tap_axis_control);
+ AC_WRITE(ac, ACT_INACT_CTL, pdata->act_axis_control);
+ AC_WRITE(ac, BW_RATE, RATE(ac->pdata.data_rate) |
+ (pdata->low_power_mode ? LOW_POWER : 0));
+ AC_WRITE(ac, DATA_FORMAT, pdata->data_range);
+ AC_WRITE(ac, FIFO_CTL, FIFO_MODE(pdata->fifo_mode) |
+ SAMPLES(pdata->watermark));
+
+ if (pdata->use_int2) {
+ /* Map all INTs to INT2 */
+ AC_WRITE(ac, INT_MAP, ac->int_mask | OVERRUN);
+ } else {
+ /* Map all INTs to INT1 */
+ AC_WRITE(ac, INT_MAP, 0);
+ }
+
+ if (ac->model == 346 && ac->pdata.orientation_enable) {
+ AC_WRITE(ac, ORIENT_CONF,
+ ORIENT_DEADZONE(ac->pdata.deadzone_angle) |
+ ORIENT_DIVISOR(ac->pdata.divisor_length));
+
+ ac->orient2d_saved = 1234;
+ ac->orient3d_saved = 1234;
+
+ if (pdata->orientation_enable & ADXL_EN_ORIENTATION_3D)
+ for (i = 0; i < ARRAY_SIZE(pdata->ev_codes_orient_3d); i++)
+ __set_bit(pdata->ev_codes_orient_3d[i],
+ input_dev->keybit);
+
+ if (pdata->orientation_enable & ADXL_EN_ORIENTATION_2D)
+ for (i = 0; i < ARRAY_SIZE(pdata->ev_codes_orient_2d); i++)
+ __set_bit(pdata->ev_codes_orient_2d[i],
+ input_dev->keybit);
+ } else {
+ ac->pdata.orientation_enable = 0;
+ }
+
+ AC_WRITE(ac, INT_ENABLE, ac->int_mask | OVERRUN);
+
+ ac->pdata.power_mode &= (PCTL_AUTO_SLEEP | PCTL_LINK);
+
+ return ac;
+
+ err_remove_attr:
+ sysfs_remove_group(&dev->kobj, &adxl34x_attr_group);
+ err_free_irq:
+ free_irq(ac->irq, ac);
+ err_free_mem:
+ input_free_device(input_dev);
+ kfree(ac);
+ err_out:
+ return ERR_PTR(err);
+}
+EXPORT_SYMBOL_GPL(adxl34x_probe);
+
+int adxl34x_remove(struct adxl34x *ac)
+{
+ sysfs_remove_group(&ac->dev->kobj, &adxl34x_attr_group);
+ free_irq(ac->irq, ac);
+ input_unregister_device(ac->input);
+ dev_dbg(ac->dev, "unregistered accelerometer\n");
+ kfree(ac);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(adxl34x_remove);
+
+MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
+MODULE_DESCRIPTION("ADXL345/346 Three-Axis Digital Accelerometer Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/input/misc/adxl34x.h b/drivers/input/misc/adxl34x.h
new file mode 100644
index 00000000000..bbbc80fda16
--- /dev/null
+++ b/drivers/input/misc/adxl34x.h
@@ -0,0 +1,30 @@
+/*
+ * ADXL345/346 Three-Axis Digital Accelerometers (I2C/SPI Interface)
+ *
+ * Enter bugs at http://blackfin.uclinux.org/
+ *
+ * Copyright (C) 2009 Michael Hennerich, Analog Devices Inc.
+ * Licensed under the GPL-2 or later.
+ */
+
+#ifndef _ADXL34X_H_
+#define _ADXL34X_H_
+
+struct device;
+struct adxl34x;
+
+struct adxl34x_bus_ops {
+ u16 bustype;
+ int (*read)(struct device *, unsigned char);
+ int (*read_block)(struct device *, unsigned char, int, void *);
+ int (*write)(struct device *, unsigned char, unsigned char);
+};
+
+void adxl34x_suspend(struct adxl34x *ac);
+void adxl34x_resume(struct adxl34x *ac);
+struct adxl34x *adxl34x_probe(struct device *dev, int irq,
+ bool fifo_delay_default,
+ const struct adxl34x_bus_ops *bops);
+int adxl34x_remove(struct adxl34x *ac);
+
+#endif
diff --git a/drivers/input/misc/atlas_btns.c b/drivers/input/misc/atlas_btns.c
index dfaa9a045ed..601f7372f9c 100644
--- a/drivers/input/misc/atlas_btns.c
+++ b/drivers/input/misc/atlas_btns.c
@@ -21,6 +21,8 @@
*
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
@@ -60,12 +62,11 @@ static acpi_status acpi_atlas_button_handler(u32 function,
input_report_key(input_dev, atlas_keymap[code], key_down);
input_sync(input_dev);
- status = 0;
+ status = AE_OK;
} else {
- printk(KERN_WARNING "atlas: shrugged on unexpected function"
- ":function=%x,address=%lx,value=%x\n",
+ pr_warn("shrugged on unexpected function: function=%x,address=%lx,value=%x\n",
function, (unsigned long)address, (u32)*value);
- status = -EINVAL;
+ status = AE_BAD_PARAMETER;
}
return status;
@@ -79,7 +80,7 @@ static int atlas_acpi_button_add(struct acpi_device *device)
input_dev = input_allocate_device();
if (!input_dev) {
- printk(KERN_ERR "atlas: unable to allocate input device\n");
+ pr_err("unable to allocate input device\n");
return -ENOMEM;
}
@@ -102,7 +103,7 @@ static int atlas_acpi_button_add(struct acpi_device *device)
err = input_register_device(input_dev);
if (err) {
- printk(KERN_ERR "atlas: couldn't register input device\n");
+ pr_err("couldn't register input device\n");
input_free_device(input_dev);
return err;
}
@@ -112,12 +113,12 @@ static int atlas_acpi_button_add(struct acpi_device *device)
0x81, &acpi_atlas_button_handler,
&acpi_atlas_button_setup, device);
if (ACPI_FAILURE(status)) {
- printk(KERN_ERR "Atlas: Error installing addr spc handler\n");
+ pr_err("error installing addr spc handler\n");
input_unregister_device(input_dev);
- status = -EINVAL;
+ err = -EINVAL;
}
- return status;
+ return err;
}
static int atlas_acpi_button_remove(struct acpi_device *device, int type)
@@ -126,14 +127,12 @@ static int atlas_acpi_button_remove(struct acpi_device *device, int type)
status = acpi_remove_address_space_handler(device->handle,
0x81, &acpi_atlas_button_handler);
- if (ACPI_FAILURE(status)) {
- printk(KERN_ERR "Atlas: Error removing addr spc handler\n");
- status = -EINVAL;
- }
+ if (ACPI_FAILURE(status))
+ pr_err("error removing addr spc handler\n");
input_unregister_device(input_dev);
- return status;
+ return 0;
}
static const struct acpi_device_id atlas_device_ids[] = {
@@ -145,6 +144,7 @@ MODULE_DEVICE_TABLE(acpi, atlas_device_ids);
static struct acpi_driver atlas_acpi_driver = {
.name = ACPI_ATLAS_NAME,
.class = ACPI_ATLAS_CLASS,
+ .owner = THIS_MODULE,
.ids = atlas_device_ids,
.ops = {
.add = atlas_acpi_button_add,
@@ -154,18 +154,10 @@ static struct acpi_driver atlas_acpi_driver = {
static int __init atlas_acpi_init(void)
{
- int result;
-
if (acpi_disabled)
return -ENODEV;
- result = acpi_bus_register_driver(&atlas_acpi_driver);
- if (result < 0) {
- printk(KERN_ERR "Atlas ACPI: Unable to register driver\n");
- return -ENODEV;
- }
-
- return 0;
+ return acpi_bus_register_driver(&atlas_acpi_driver);
}
static void __exit atlas_acpi_exit(void)
diff --git a/drivers/input/misc/ixp4xx-beeper.c b/drivers/input/misc/ixp4xx-beeper.c
index 9946d73624b..9dfd6e5f786 100644
--- a/drivers/input/misc/ixp4xx-beeper.c
+++ b/drivers/input/misc/ixp4xx-beeper.c
@@ -115,7 +115,8 @@ static int __devinit ixp4xx_spkr_probe(struct platform_device *dev)
input_dev->event = ixp4xx_spkr_event;
err = request_irq(IRQ_IXP4XX_TIMER2, &ixp4xx_spkr_interrupt,
- IRQF_DISABLED | IRQF_TIMER, "ixp4xx-beeper", (void *) dev->id);
+ IRQF_DISABLED | IRQF_NO_SUSPEND, "ixp4xx-beeper",
+ (void *) dev->id);
if (err)
goto err_free_device;
diff --git a/drivers/input/misc/pwm-beeper.c b/drivers/input/misc/pwm-beeper.c
new file mode 100644
index 00000000000..57c294f0719
--- /dev/null
+++ b/drivers/input/misc/pwm-beeper.c
@@ -0,0 +1,199 @@
+/*
+ * Copyright (C) 2010, Lars-Peter Clausen <lars@metafoo.de>
+ * PWM beeper 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.
+ *
+ * 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/input.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/pwm.h>
+#include <linux/slab.h>
+
+struct pwm_beeper {
+ struct input_dev *input;
+ struct pwm_device *pwm;
+ unsigned long period;
+};
+
+#define HZ_TO_NANOSECONDS(x) (1000000000UL/(x))
+
+static int pwm_beeper_event(struct input_dev *input,
+ unsigned int type, unsigned int code, int value)
+{
+ int ret = 0;
+ struct pwm_beeper *beeper = input_get_drvdata(input);
+ unsigned long period;
+
+ if (type != EV_SND || value < 0)
+ return -EINVAL;
+
+ switch (code) {
+ case SND_BELL:
+ value = value ? 1000 : 0;
+ break;
+ case SND_TONE:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (value == 0) {
+ pwm_config(beeper->pwm, 0, 0);
+ pwm_disable(beeper->pwm);
+ } else {
+ period = HZ_TO_NANOSECONDS(value);
+ ret = pwm_config(beeper->pwm, period / 2, period);
+ if (ret)
+ return ret;
+ ret = pwm_enable(beeper->pwm);
+ if (ret)
+ return ret;
+ beeper->period = period;
+ }
+
+ return 0;
+}
+
+static int __devinit pwm_beeper_probe(struct platform_device *pdev)
+{
+ unsigned long pwm_id = (unsigned long)pdev->dev.platform_data;
+ struct pwm_beeper *beeper;
+ int error;
+
+ beeper = kzalloc(sizeof(*beeper), GFP_KERNEL);
+ if (!beeper)
+ return -ENOMEM;
+
+ beeper->pwm = pwm_request(pwm_id, "pwm beeper");
+
+ if (IS_ERR(beeper->pwm)) {
+ error = PTR_ERR(beeper->pwm);
+ dev_err(&pdev->dev, "Failed to request pwm device: %d\n", error);
+ goto err_free;
+ }
+
+ beeper->input = input_allocate_device();
+ if (!beeper->input) {
+ dev_err(&pdev->dev, "Failed to allocate input device\n");
+ error = -ENOMEM;
+ goto err_pwm_free;
+ }
+ beeper->input->dev.parent = &pdev->dev;
+
+ beeper->input->name = "pwm-beeper";
+ beeper->input->phys = "pwm/input0";
+ beeper->input->id.bustype = BUS_HOST;
+ beeper->input->id.vendor = 0x001f;
+ beeper->input->id.product = 0x0001;
+ beeper->input->id.version = 0x0100;
+
+ beeper->input->evbit[0] = BIT(EV_SND);
+ beeper->input->sndbit[0] = BIT(SND_TONE) | BIT(SND_BELL);
+
+ beeper->input->event = pwm_beeper_event;
+
+ input_set_drvdata(beeper->input, beeper);
+
+ error = input_register_device(beeper->input);
+ if (error) {
+ dev_err(&pdev->dev, "Failed to register input device: %d\n", error);
+ goto err_input_free;
+ }
+
+ platform_set_drvdata(pdev, beeper);
+
+ return 0;
+
+err_input_free:
+ input_free_device(beeper->input);
+err_pwm_free:
+ pwm_free(beeper->pwm);
+err_free:
+ kfree(beeper);
+
+ return error;
+}
+
+static int __devexit pwm_beeper_remove(struct platform_device *pdev)
+{
+ struct pwm_beeper *beeper = platform_get_drvdata(pdev);
+
+ platform_set_drvdata(pdev, NULL);
+ input_unregister_device(beeper->input);
+
+ pwm_disable(beeper->pwm);
+ pwm_free(beeper->pwm);
+
+ kfree(beeper);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int pwm_beeper_suspend(struct device *dev)
+{
+ struct pwm_beeper *beeper = dev_get_drvdata(dev);
+
+ if (beeper->period)
+ pwm_disable(beeper->pwm);
+
+ return 0;
+}
+
+static int pwm_beeper_resume(struct device *dev)
+{
+ struct pwm_beeper *beeper = dev_get_drvdata(dev);
+
+ if (beeper->period) {
+ pwm_config(beeper->pwm, beeper->period / 2, beeper->period);
+ pwm_enable(beeper->pwm);
+ }
+
+ return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(pwm_beeper_pm_ops,
+ pwm_beeper_suspend, pwm_beeper_resume);
+
+#define PWM_BEEPER_PM_OPS (&pwm_beeper_pm_ops)
+#else
+#define PWM_BEEPER_PM_OPS NULL
+#endif
+
+static struct platform_driver pwm_beeper_driver = {
+ .probe = pwm_beeper_probe,
+ .remove = __devexit_p(pwm_beeper_remove),
+ .driver = {
+ .name = "pwm-beeper",
+ .owner = THIS_MODULE,
+ .pm = PWM_BEEPER_PM_OPS,
+ },
+};
+
+static int __init pwm_beeper_init(void)
+{
+ return platform_driver_register(&pwm_beeper_driver);
+}
+module_init(pwm_beeper_init);
+
+static void __exit pwm_beeper_exit(void)
+{
+ platform_driver_unregister(&pwm_beeper_driver);
+}
+module_exit(pwm_beeper_exit);
+
+MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
+MODULE_DESCRIPTION("PWM beeper driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:pwm-beeper");
diff --git a/drivers/input/misc/sparcspkr.c b/drivers/input/misc/sparcspkr.c
index 1dacae4b43f..f3bb92e9755 100644
--- a/drivers/input/misc/sparcspkr.c
+++ b/drivers/input/misc/sparcspkr.c
@@ -353,14 +353,12 @@ static struct of_platform_driver grover_beep_driver = {
static int __init sparcspkr_init(void)
{
- int err = of_register_driver(&bbc_beep_driver,
- &of_platform_bus_type);
+ int err = of_register_platform_driver(&bbc_beep_driver);
if (!err) {
- err = of_register_driver(&grover_beep_driver,
- &of_platform_bus_type);
+ err = of_register_platform_driver(&grover_beep_driver);
if (err)
- of_unregister_driver(&bbc_beep_driver);
+ of_unregister_platform_driver(&bbc_beep_driver);
}
return err;
@@ -368,8 +366,8 @@ static int __init sparcspkr_init(void)
static void __exit sparcspkr_exit(void)
{
- of_unregister_driver(&bbc_beep_driver);
- of_unregister_driver(&grover_beep_driver);
+ of_unregister_platform_driver(&bbc_beep_driver);
+ of_unregister_platform_driver(&grover_beep_driver);
}
module_init(sparcspkr_init);
diff --git a/drivers/input/misc/twl4030-pwrbutton.c b/drivers/input/misc/twl4030-pwrbutton.c
index e9069b87fde..f16972bddca 100644
--- a/drivers/input/misc/twl4030-pwrbutton.c
+++ b/drivers/input/misc/twl4030-pwrbutton.c
@@ -52,7 +52,7 @@ static irqreturn_t powerbutton_irq(int irq, void *_pwr)
return IRQ_HANDLED;
}
-static int __devinit twl4030_pwrbutton_probe(struct platform_device *pdev)
+static int __init twl4030_pwrbutton_probe(struct platform_device *pdev)
{
struct input_dev *pwr;
int irq = platform_get_irq(pdev, 0);
@@ -95,7 +95,7 @@ free_input_dev:
return err;
}
-static int __devexit twl4030_pwrbutton_remove(struct platform_device *pdev)
+static int __exit twl4030_pwrbutton_remove(struct platform_device *pdev)
{
struct input_dev *pwr = platform_get_drvdata(pdev);
int irq = platform_get_irq(pdev, 0);
@@ -106,9 +106,8 @@ static int __devexit twl4030_pwrbutton_remove(struct platform_device *pdev)
return 0;
}
-struct platform_driver twl4030_pwrbutton_driver = {
- .probe = twl4030_pwrbutton_probe,
- .remove = __devexit_p(twl4030_pwrbutton_remove),
+static struct platform_driver twl4030_pwrbutton_driver = {
+ .remove = __exit_p(twl4030_pwrbutton_remove),
.driver = {
.name = "twl4030_pwrbutton",
.owner = THIS_MODULE,
@@ -117,7 +116,8 @@ struct platform_driver twl4030_pwrbutton_driver = {
static int __init twl4030_pwrbutton_init(void)
{
- return platform_driver_register(&twl4030_pwrbutton_driver);
+ return platform_driver_probe(&twl4030_pwrbutton_driver,
+ twl4030_pwrbutton_probe);
}
module_init(twl4030_pwrbutton_init);
diff --git a/drivers/input/misc/wistron_btns.c b/drivers/input/misc/wistron_btns.c
index 4dac8b79fcd..12501de0c5c 100644
--- a/drivers/input/misc/wistron_btns.c
+++ b/drivers/input/misc/wistron_btns.c
@@ -1347,7 +1347,7 @@ static int __init wb_module_init(void)
err = map_bios();
if (err)
- return err;
+ goto err_free_keymap;
err = platform_driver_register(&wistron_driver);
if (err)
@@ -1371,6 +1371,8 @@ static int __init wb_module_init(void)
platform_driver_unregister(&wistron_driver);
err_unmap_bios:
unmap_bios();
+ err_free_keymap:
+ kfree(keymap);
return err;
}
diff --git a/drivers/input/mouse/bcm5974.c b/drivers/input/mouse/bcm5974.c
index 6dedded2722..ea67c49146a 100644
--- a/drivers/input/mouse/bcm5974.c
+++ b/drivers/input/mouse/bcm5974.c
@@ -312,6 +312,8 @@ static void setup_events_to_report(struct input_dev *input_dev,
__set_bit(BTN_TOOL_TRIPLETAP, input_dev->keybit);
__set_bit(BTN_TOOL_QUADTAP, input_dev->keybit);
__set_bit(BTN_LEFT, input_dev->keybit);
+
+ input_set_events_per_packet(input_dev, 60);
}
/* report button data as logical button state */
@@ -580,23 +582,30 @@ exit:
*/
static int bcm5974_start_traffic(struct bcm5974 *dev)
{
- if (bcm5974_wellspring_mode(dev, true)) {
+ int error;
+
+ error = bcm5974_wellspring_mode(dev, true);
+ if (error) {
dprintk(1, "bcm5974: mode switch failed\n");
- goto error;
+ goto err_out;
}
- if (usb_submit_urb(dev->bt_urb, GFP_KERNEL))
- goto error;
+ error = usb_submit_urb(dev->bt_urb, GFP_KERNEL);
+ if (error)
+ goto err_reset_mode;
- if (usb_submit_urb(dev->tp_urb, GFP_KERNEL))
+ error = usb_submit_urb(dev->tp_urb, GFP_KERNEL);
+ if (error)
goto err_kill_bt;
return 0;
err_kill_bt:
usb_kill_urb(dev->bt_urb);
-error:
- return -EIO;
+err_reset_mode:
+ bcm5974_wellspring_mode(dev, false);
+err_out:
+ return error;
}
static void bcm5974_pause_traffic(struct bcm5974 *dev)
diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c
index 705589dc9ac..8c324403b9f 100644
--- a/drivers/input/mouse/synaptics.c
+++ b/drivers/input/mouse/synaptics.c
@@ -502,7 +502,9 @@ static void synaptics_process_packet(struct psmouse *psmouse)
}
input_report_abs(dev, ABS_PRESSURE, hw.z);
- input_report_abs(dev, ABS_TOOL_WIDTH, finger_width);
+ if (SYN_CAP_PALMDETECT(priv->capabilities))
+ input_report_abs(dev, ABS_TOOL_WIDTH, finger_width);
+
input_report_key(dev, BTN_TOOL_FINGER, num_fingers == 1);
input_report_key(dev, BTN_LEFT, hw.left);
input_report_key(dev, BTN_RIGHT, hw.right);
@@ -602,7 +604,9 @@ static void set_input_params(struct input_dev *dev, struct synaptics_data *priv)
input_set_abs_params(dev, ABS_Y,
YMIN_NOMINAL, priv->y_max ?: YMAX_NOMINAL, 0, 0);
input_set_abs_params(dev, ABS_PRESSURE, 0, 255, 0, 0);
- __set_bit(ABS_TOOL_WIDTH, dev->absbit);
+
+ if (SYN_CAP_PALMDETECT(priv->capabilities))
+ input_set_abs_params(dev, ABS_TOOL_WIDTH, 0, 15, 0, 0);
__set_bit(EV_KEY, dev->evbit);
__set_bit(BTN_TOUCH, dev->keybit);
diff --git a/drivers/input/mousedev.c b/drivers/input/mousedev.c
index f34b22bce4f..d8f68f77007 100644
--- a/drivers/input/mousedev.c
+++ b/drivers/input/mousedev.c
@@ -57,7 +57,6 @@ struct mousedev_hw_data {
};
struct mousedev {
- int exist;
int open;
int minor;
struct input_handle handle;
@@ -66,6 +65,7 @@ struct mousedev {
spinlock_t client_lock; /* protects client_list */
struct mutex mutex;
struct device dev;
+ bool exist;
struct list_head mixdev_node;
int mixdev_open;
@@ -765,10 +765,15 @@ static unsigned int mousedev_poll(struct file *file, poll_table *wait)
{
struct mousedev_client *client = file->private_data;
struct mousedev *mousedev = client->mousedev;
+ unsigned int mask;
poll_wait(file, &mousedev->wait, wait);
- return ((client->ready || client->buffer) ? (POLLIN | POLLRDNORM) : 0) |
- (mousedev->exist ? 0 : (POLLHUP | POLLERR));
+
+ mask = mousedev->exist ? POLLOUT | POLLWRNORM : POLLHUP | POLLERR;
+ if (client->ready || client->buffer)
+ mask |= POLLIN | POLLRDNORM;
+
+ return mask;
}
static const struct file_operations mousedev_fops = {
@@ -802,7 +807,7 @@ static void mousedev_remove_chrdev(struct mousedev *mousedev)
static void mousedev_mark_dead(struct mousedev *mousedev)
{
mutex_lock(&mousedev->mutex);
- mousedev->exist = 0;
+ mousedev->exist = false;
mutex_unlock(&mousedev->mutex);
}
@@ -862,7 +867,7 @@ static struct mousedev *mousedev_create(struct input_dev *dev,
dev_set_name(&mousedev->dev, "mouse%d", minor);
mousedev->minor = minor;
- mousedev->exist = 1;
+ mousedev->exist = true;
mousedev->handle.dev = input_get_device(dev);
mousedev->handle.name = dev_name(&mousedev->dev);
mousedev->handle.handler = handler;
diff --git a/drivers/input/serio/i8042-io.h b/drivers/input/serio/i8042-io.h
index 847f4aad7ed..5d48bb66aa7 100644
--- a/drivers/input/serio/i8042-io.h
+++ b/drivers/input/serio/i8042-io.h
@@ -27,6 +27,11 @@
#include <asm/irq.h>
#elif defined(CONFIG_SH_CAYMAN)
#include <asm/irq.h>
+#elif defined(CONFIG_PPC)
+extern int of_i8042_kbd_irq;
+extern int of_i8042_aux_irq;
+# define I8042_KBD_IRQ of_i8042_kbd_irq
+# define I8042_AUX_IRQ of_i8042_aux_irq
#else
# define I8042_KBD_IRQ 1
# define I8042_AUX_IRQ 12
diff --git a/drivers/input/serio/i8042-ppcio.h b/drivers/input/serio/i8042-ppcio.h
index 2906e1b60c0..f708c75d16f 100644
--- a/drivers/input/serio/i8042-ppcio.h
+++ b/drivers/input/serio/i8042-ppcio.h
@@ -52,81 +52,6 @@ static inline void i8042_platform_exit(void)
{
}
-#elif defined(CONFIG_SPRUCE)
-
-#define I8042_KBD_IRQ 22
-#define I8042_AUX_IRQ 21
-
-#define I8042_KBD_PHYS_DESC "spruceps2/serio0"
-#define I8042_AUX_PHYS_DESC "spruceps2/serio1"
-#define I8042_MUX_PHYS_DESC "spruceps2/serio%d"
-
-#define I8042_COMMAND_REG 0xff810000
-#define I8042_DATA_REG 0xff810001
-
-static inline int i8042_read_data(void)
-{
- unsigned long kbd_data;
-
- __raw_writel(0x00000088, 0xff500008);
- eieio();
-
- __raw_writel(0x03000000, 0xff50000c);
- eieio();
-
- asm volatile("lis 7,0xff88 \n\
- lswi 6,7,0x8 \n\
- mr %0,6"
- : "=r" (kbd_data) :: "6", "7");
-
- __raw_writel(0x00000000, 0xff50000c);
- eieio();
-
- return (unsigned char)(kbd_data >> 24);
-}
-
-static inline int i8042_read_status(void)
-{
- unsigned long kbd_status;
-
- __raw_writel(0x00000088, 0xff500008);
- eieio();
-
- __raw_writel(0x03000000, 0xff50000c);
- eieio();
-
- asm volatile("lis 7,0xff88 \n\
- ori 7,7,0x8 \n\
- lswi 6,7,0x8 \n\
- mr %0,6"
- : "=r" (kbd_status) :: "6", "7");
-
- __raw_writel(0x00000000, 0xff50000c);
- eieio();
-
- return (unsigned char)(kbd_status >> 24);
-}
-
-static inline void i8042_write_data(int val)
-{
- *((unsigned char *)0xff810000) = (char)val;
-}
-
-static inline void i8042_write_command(int val)
-{
- *((unsigned char *)0xff810001) = (char)val;
-}
-
-static inline int i8042_platform_init(void)
-{
- i8042_reset = 1;
- return 0;
-}
-
-static inline void i8042_platform_exit(void)
-{
-}
-
#else
#include "i8042-io.h"
diff --git a/drivers/input/serio/i8042-sparcio.h b/drivers/input/serio/i8042-sparcio.h
index 04e32f2d124..cb2a24b9474 100644
--- a/drivers/input/serio/i8042-sparcio.h
+++ b/drivers/input/serio/i8042-sparcio.h
@@ -58,9 +58,9 @@ static int __devinit sparc_i8042_probe(struct of_device *op, const struct of_dev
if (!strcmp(dp->name, OBP_PS2KBD_NAME1) ||
!strcmp(dp->name, OBP_PS2KBD_NAME2)) {
struct of_device *kbd = of_find_device_by_node(dp);
- unsigned int irq = kbd->irqs[0];
+ unsigned int irq = kbd->archdata.irqs[0];
if (irq == 0xffffffff)
- irq = op->irqs[0];
+ irq = op->archdata.irqs[0];
i8042_kbd_irq = irq;
kbd_iobase = of_ioremap(&kbd->resource[0],
0, 8, "kbd");
@@ -68,9 +68,9 @@ static int __devinit sparc_i8042_probe(struct of_device *op, const struct of_dev
} else if (!strcmp(dp->name, OBP_PS2MS_NAME1) ||
!strcmp(dp->name, OBP_PS2MS_NAME2)) {
struct of_device *ms = of_find_device_by_node(dp);
- unsigned int irq = ms->irqs[0];
+ unsigned int irq = ms->archdata.irqs[0];
if (irq == 0xffffffff)
- irq = op->irqs[0];
+ irq = op->archdata.irqs[0];
i8042_aux_irq = irq;
}
@@ -116,8 +116,7 @@ static int __init i8042_platform_init(void)
if (!kbd_iobase)
return -ENODEV;
} else {
- int err = of_register_driver(&sparc_i8042_driver,
- &of_bus_type);
+ int err = of_register_platform_driver(&sparc_i8042_driver);
if (err)
return err;
@@ -141,7 +140,7 @@ static inline void i8042_platform_exit(void)
struct device_node *root = of_find_node_by_path("/");
if (strcmp(root->name, "SUNW,JavaStation-1"))
- of_unregister_driver(&sparc_i8042_driver);
+ of_unregister_platform_driver(&sparc_i8042_driver);
}
#else /* !CONFIG_PCI */
diff --git a/drivers/input/serio/i8042.c b/drivers/input/serio/i8042.c
index 6440a8f5568..258b98b9d7c 100644
--- a/drivers/input/serio/i8042.c
+++ b/drivers/input/serio/i8042.c
@@ -861,9 +861,6 @@ static int i8042_controller_selftest(void)
unsigned char param;
int i = 0;
- if (!i8042_reset)
- return 0;
-
/*
* We try this 5 times; on some really fragile systems this does not
* take the first time...
@@ -1020,7 +1017,8 @@ static void i8042_controller_reset(void)
* Reset the controller if requested.
*/
- i8042_controller_selftest();
+ if (i8042_reset)
+ i8042_controller_selftest();
/*
* Restore the original control register setting.
@@ -1094,23 +1092,11 @@ static void i8042_dritek_enable(void)
#ifdef CONFIG_PM
/*
- * Here we try to restore the original BIOS settings to avoid
- * upsetting it.
- */
-
-static int i8042_pm_reset(struct device *dev)
-{
- i8042_controller_reset();
-
- return 0;
-}
-
-/*
* Here we try to reset everything back to a state we had
* before suspending.
*/
-static int i8042_pm_restore(struct device *dev)
+static int i8042_controller_resume(bool force_reset)
{
int error;
@@ -1118,9 +1104,11 @@ static int i8042_pm_restore(struct device *dev)
if (error)
return error;
- error = i8042_controller_selftest();
- if (error)
- return error;
+ if (i8042_reset || force_reset) {
+ error = i8042_controller_selftest();
+ if (error)
+ return error;
+ }
/*
* Restore original CTR value and disable all ports
@@ -1162,6 +1150,28 @@ static int i8042_pm_restore(struct device *dev)
return 0;
}
+/*
+ * Here we try to restore the original BIOS settings to avoid
+ * upsetting it.
+ */
+
+static int i8042_pm_reset(struct device *dev)
+{
+ i8042_controller_reset();
+
+ return 0;
+}
+
+static int i8042_pm_resume(struct device *dev)
+{
+ /*
+ * On resume from S2R we always try to reset the controller
+ * to bring it in a sane state. (In case of S2D we expect
+ * BIOS to reset the controller for us.)
+ */
+ return i8042_controller_resume(true);
+}
+
static int i8042_pm_thaw(struct device *dev)
{
i8042_interrupt(0, NULL);
@@ -1169,9 +1179,14 @@ static int i8042_pm_thaw(struct device *dev)
return 0;
}
+static int i8042_pm_restore(struct device *dev)
+{
+ return i8042_controller_resume(false);
+}
+
static const struct dev_pm_ops i8042_pm_ops = {
.suspend = i8042_pm_reset,
- .resume = i8042_pm_restore,
+ .resume = i8042_pm_resume,
.thaw = i8042_pm_thaw,
.poweroff = i8042_pm_reset,
.restore = i8042_pm_restore,
@@ -1389,9 +1404,11 @@ static int __init i8042_probe(struct platform_device *dev)
i8042_platform_device = dev;
- error = i8042_controller_selftest();
- if (error)
- return error;
+ if (i8042_reset) {
+ error = i8042_controller_selftest();
+ if (error)
+ return error;
+ }
error = i8042_controller_init();
if (error)
diff --git a/drivers/input/tablet/wacom_wac.c b/drivers/input/tablet/wacom_wac.c
index 415f6306105..ce0b4608dad 100644
--- a/drivers/input/tablet/wacom_wac.c
+++ b/drivers/input/tablet/wacom_wac.c
@@ -158,6 +158,39 @@ static int wacom_ptu_irq(struct wacom_wac *wacom)
return 1;
}
+static int wacom_dtu_irq(struct wacom_wac *wacom)
+{
+ struct wacom_features *features = &wacom->features;
+ char *data = wacom->data;
+ struct input_dev *input = wacom->input;
+ int prox = data[1] & 0x20, pressure;
+
+ dbg("wacom_dtu_irq: received report #%d", data[0]);
+
+ if (prox) {
+ /* Going into proximity select tool */
+ wacom->tool[0] = (data[1] & 0x0c) ? BTN_TOOL_RUBBER : BTN_TOOL_PEN;
+ if (wacom->tool[0] == BTN_TOOL_PEN)
+ wacom->id[0] = STYLUS_DEVICE_ID;
+ else
+ wacom->id[0] = ERASER_DEVICE_ID;
+ }
+ input_report_key(input, BTN_STYLUS, data[1] & 0x02);
+ input_report_key(input, BTN_STYLUS2, data[1] & 0x10);
+ input_report_abs(input, ABS_X, le16_to_cpup((__le16 *)&data[2]));
+ input_report_abs(input, ABS_Y, le16_to_cpup((__le16 *)&data[4]));
+ pressure = ((data[7] & 0x01) << 8) | data[6];
+ if (pressure < 0)
+ pressure = features->pressure_max + pressure + 1;
+ input_report_abs(input, ABS_PRESSURE, pressure);
+ input_report_key(input, BTN_TOUCH, data[1] & 0x05);
+ if (!prox) /* out-prox */
+ wacom->id[0] = 0;
+ input_report_key(input, wacom->tool[0], prox);
+ input_report_abs(input, ABS_MISC, wacom->id[0]);
+ return 1;
+}
+
static int wacom_graphire_irq(struct wacom_wac *wacom)
{
struct wacom_features *features = &wacom->features;
@@ -845,6 +878,10 @@ void wacom_wac_irq(struct wacom_wac *wacom_wac, size_t len)
sync = wacom_ptu_irq(wacom_wac);
break;
+ case DTU:
+ sync = wacom_dtu_irq(wacom_wac);
+ break;
+
case INTUOS:
case INTUOS3S:
case INTUOS3:
@@ -1030,6 +1067,7 @@ void wacom_setup_input_capabilities(struct input_dev *input_dev,
case PL:
case PTU:
+ case DTU:
__set_bit(BTN_TOOL_PEN, input_dev->keybit);
__set_bit(BTN_STYLUS, input_dev->keybit);
__set_bit(BTN_STYLUS2, input_dev->keybit);
@@ -1155,6 +1193,10 @@ static const struct wacom_features wacom_features_0xC6 =
{ "Wacom Cintiq 12WX", WACOM_PKGLEN_INTUOS, 53020, 33440, 1023, 63, WACOM_BEE };
static const struct wacom_features wacom_features_0xC7 =
{ "Wacom DTU1931", WACOM_PKGLEN_GRAPHIRE, 37832, 30305, 511, 0, PL };
+static const struct wacom_features wacom_features_0xCE =
+ { "Wacom DTU2231", WACOM_PKGLEN_GRAPHIRE, 47864, 27011, 511, 0, DTU };
+static const struct wacom_features wacom_features_0xF0 =
+ { "Wacom DTU1631", WACOM_PKGLEN_GRAPHIRE, 34623, 19553, 511, 0, DTU };
static const struct wacom_features wacom_features_0xCC =
{ "Wacom Cintiq 21UX2", WACOM_PKGLEN_INTUOS, 87200, 65600, 2047, 63, WACOM_21UX2 };
static const struct wacom_features wacom_features_0x90 =
@@ -1234,6 +1276,8 @@ const struct usb_device_id wacom_ids[] = {
{ USB_DEVICE_WACOM(0xC5) },
{ USB_DEVICE_WACOM(0xC6) },
{ USB_DEVICE_WACOM(0xC7) },
+ { USB_DEVICE_WACOM(0xCE) },
+ { USB_DEVICE_WACOM(0xF0) },
{ USB_DEVICE_WACOM(0xCC) },
{ USB_DEVICE_WACOM(0x90) },
{ USB_DEVICE_WACOM(0x93) },
diff --git a/drivers/input/tablet/wacom_wac.h b/drivers/input/tablet/wacom_wac.h
index 854b92092df..99e1a54cd30 100644
--- a/drivers/input/tablet/wacom_wac.h
+++ b/drivers/input/tablet/wacom_wac.h
@@ -43,6 +43,7 @@ enum {
WACOM_G4,
PTU,
PL,
+ DTU,
INTUOS,
INTUOS3S,
INTUOS3,
diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
index 3b9d5e2105d..61f35184f76 100644
--- a/drivers/input/touchscreen/Kconfig
+++ b/drivers/input/touchscreen/Kconfig
@@ -55,37 +55,36 @@ config TOUCHSCREEN_AD7877
To compile this driver as a module, choose M here: the
module will be called ad7877.
-config TOUCHSCREEN_AD7879_I2C
- tristate "AD7879 based touchscreens: AD7879-1 I2C Interface"
- depends on I2C
- select TOUCHSCREEN_AD7879
+config TOUCHSCREEN_AD7879
+ tristate "Analog Devices AD7879-1/AD7889-1 touchscreen interface"
help
- Say Y here if you have a touchscreen interface using the
- AD7879-1/AD7889-1 controller, and your board-specific
- initialization code includes that in its table of I2C devices.
+ Say Y here if you want to support a touchscreen interface using
+ the AD7879-1/AD7889-1 controller.
- If unsure, say N (but it's safe to say "Y").
+ You should select a bus connection too.
To compile this driver as a module, choose M here: the
module will be called ad7879.
+config TOUCHSCREEN_AD7879_I2C
+ tristate "support I2C bus connection"
+ depends on TOUCHSCREEN_AD7879 && I2C
+ help
+ Say Y here if you have AD7879-1/AD7889-1 hooked to an I2C bus.
+
+ To compile this driver as a module, choose M here: the
+ module will be called ad7879-i2c.
+
config TOUCHSCREEN_AD7879_SPI
- tristate "AD7879 based touchscreens: AD7879 SPI Interface"
- depends on SPI_MASTER && TOUCHSCREEN_AD7879_I2C = n
- select TOUCHSCREEN_AD7879
+ tristate "support SPI bus connection"
+ depends on TOUCHSCREEN_AD7879 && SPI_MASTER
help
- Say Y here if you have a touchscreen interface using the
- AD7879/AD7889 controller, and your board-specific initialization
- code includes that in its table of SPI devices.
+ Say Y here if you have AD7879-1/AD7889-1 hooked to a SPI bus.
If unsure, say N (but it's safe to say "Y").
To compile this driver as a module, choose M here: the
- module will be called ad7879.
-
-config TOUCHSCREEN_AD7879
- tristate
- default n
+ module will be called ad7879-spi.
config TOUCHSCREEN_BITSY
tristate "Compaq iPAQ H3600 (Bitsy) touchscreen"
@@ -99,6 +98,20 @@ config TOUCHSCREEN_BITSY
To compile this driver as a module, choose M here: the
module will be called h3600_ts_input.
+config TOUCHSCREEN_CY8CTMG110
+ tristate "cy8ctmg110 touchscreen"
+ depends on I2C
+ depends on GPIOLIB
+
+ help
+ Say Y here if you have a cy8ctmg110 capacitive touchscreen on
+ an AAVA device.
+
+ If unsure, say N.
+
+ To compile this driver as a module, choose M here: the
+ module will be called cy8ctmg110_ts.
+
config TOUCHSCREEN_DA9034
tristate "Touchscreen support for Dialog Semiconductor DA9034"
depends on PMIC_DA903X
@@ -292,6 +305,18 @@ config TOUCHSCREEN_PENMOUNT
To compile this driver as a module, choose M here: the
module will be called penmount.
+config TOUCHSCREEN_QT602240
+ tristate "QT602240 I2C Touchscreen"
+ depends on I2C
+ help
+ Say Y here if you have the AT42QT602240/ATMXT224 I2C touchscreen
+ connected to your system.
+
+ If unsure, say N.
+
+ To compile this driver as a module, choose M here: the
+ module will be called qt602240_ts.
+
config TOUCHSCREEN_MIGOR
tristate "Renesas MIGO-R touchscreen"
depends on SH_MIGOR && I2C
@@ -540,9 +565,9 @@ config TOUCHSCREEN_USB_ZYTRONIC
bool "Zytronic controller" if EMBEDDED
depends on TOUCHSCREEN_USB_COMPOSITE
-config TOUCHSCREEN_USB_ETT_TC5UH
+config TOUCHSCREEN_USB_ETT_TC45USB
default y
- bool "ET&T TC5UH touchscreen controler support" if EMBEDDED
+ bool "ET&T USB series TC4UM/TC5UH touchscreen controler support" if EMBEDDED
depends on TOUCHSCREEN_USB_COMPOSITE
config TOUCHSCREEN_USB_NEXIO
diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile
index 497964a7a21..bd6f30b4ff7 100644
--- a/drivers/input/touchscreen/Makefile
+++ b/drivers/input/touchscreen/Makefile
@@ -9,9 +9,13 @@ wm97xx-ts-y := wm97xx-core.o
obj-$(CONFIG_TOUCHSCREEN_88PM860X) += 88pm860x-ts.o
obj-$(CONFIG_TOUCHSCREEN_AD7877) += ad7877.o
obj-$(CONFIG_TOUCHSCREEN_AD7879) += ad7879.o
+obj-$(CONFIG_TOUCHSCREEN_AD7879_I2C) += ad7879-i2c.o
+obj-$(CONFIG_TOUCHSCREEN_AD7879_SPI) += ad7879-spi.o
obj-$(CONFIG_TOUCHSCREEN_ADS7846) += ads7846.o
obj-$(CONFIG_TOUCHSCREEN_ATMEL_TSADCC) += atmel_tsadcc.o
obj-$(CONFIG_TOUCHSCREEN_BITSY) += h3600_ts_input.o
+obj-$(CONFIG_TOUCHSCREEN_CY8CTMG110) += cy8ctmg110_ts.o
+obj-$(CONFIG_TOUCHSCREEN_DA9034) += da9034-ts.o
obj-$(CONFIG_TOUCHSCREEN_DYNAPRO) += dynapro.o
obj-$(CONFIG_TOUCHSCREEN_HAMPSHIRE) += hampshire.o
obj-$(CONFIG_TOUCHSCREEN_GUNZE) += gunze.o
@@ -30,6 +34,7 @@ obj-$(CONFIG_TOUCHSCREEN_HTCPEN) += htcpen.o
obj-$(CONFIG_TOUCHSCREEN_USB_COMPOSITE) += usbtouchscreen.o
obj-$(CONFIG_TOUCHSCREEN_PCAP) += pcap_ts.o
obj-$(CONFIG_TOUCHSCREEN_PENMOUNT) += penmount.o
+obj-$(CONFIG_TOUCHSCREEN_QT602240) += qt602240_ts.o
obj-$(CONFIG_TOUCHSCREEN_S3C2410) += s3c2410_ts.o
obj-$(CONFIG_TOUCHSCREEN_TOUCHIT213) += touchit213.o
obj-$(CONFIG_TOUCHSCREEN_TOUCHRIGHT) += touchright.o
@@ -38,7 +43,6 @@ obj-$(CONFIG_TOUCHSCREEN_TSC2007) += tsc2007.o
obj-$(CONFIG_TOUCHSCREEN_UCB1400) += ucb1400_ts.o
obj-$(CONFIG_TOUCHSCREEN_WACOM_W8001) += wacom_w8001.o
obj-$(CONFIG_TOUCHSCREEN_WM97XX) += wm97xx-ts.o
-obj-$(CONFIG_TOUCHSCREEN_DA9034) += da9034-ts.o
wm97xx-ts-$(CONFIG_TOUCHSCREEN_WM9705) += wm9705.o
wm97xx-ts-$(CONFIG_TOUCHSCREEN_WM9712) += wm9712.o
wm97xx-ts-$(CONFIG_TOUCHSCREEN_WM9713) += wm9713.o
diff --git a/drivers/input/touchscreen/ad7879-i2c.c b/drivers/input/touchscreen/ad7879-i2c.c
new file mode 100644
index 00000000000..d82a38ee9a3
--- /dev/null
+++ b/drivers/input/touchscreen/ad7879-i2c.c
@@ -0,0 +1,143 @@
+/*
+ * AD7879-1/AD7889-1 touchscreen (I2C bus)
+ *
+ * Copyright (C) 2008-2010 Michael Hennerich, Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/input.h> /* BUS_I2C */
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/types.h>
+
+#include "ad7879.h"
+
+#define AD7879_DEVID 0x79 /* AD7879-1/AD7889-1 */
+
+#ifdef CONFIG_PM
+static int ad7879_i2c_suspend(struct i2c_client *client, pm_message_t message)
+{
+ struct ad7879 *ts = i2c_get_clientdata(client);
+
+ ad7879_suspend(ts);
+
+ return 0;
+}
+
+static int ad7879_i2c_resume(struct i2c_client *client)
+{
+ struct ad7879 *ts = i2c_get_clientdata(client);
+
+ ad7879_resume(ts);
+
+ return 0;
+}
+#else
+# define ad7879_i2c_suspend NULL
+# define ad7879_i2c_resume NULL
+#endif
+
+/* All registers are word-sized.
+ * AD7879 uses a high-byte first convention.
+ */
+static int ad7879_i2c_read(struct device *dev, u8 reg)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+
+ return swab16(i2c_smbus_read_word_data(client, reg));
+}
+
+static int ad7879_i2c_multi_read(struct device *dev,
+ u8 first_reg, u8 count, u16 *buf)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ u8 idx;
+
+ i2c_smbus_read_i2c_block_data(client, first_reg, count * 2, (u8 *)buf);
+
+ for (idx = 0; idx < count; ++idx)
+ buf[idx] = swab16(buf[idx]);
+
+ return 0;
+}
+
+static int ad7879_i2c_write(struct device *dev, u8 reg, u16 val)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+
+ return i2c_smbus_write_word_data(client, reg, swab16(val));
+}
+
+static const struct ad7879_bus_ops ad7879_i2c_bus_ops = {
+ .bustype = BUS_I2C,
+ .read = ad7879_i2c_read,
+ .multi_read = ad7879_i2c_multi_read,
+ .write = ad7879_i2c_write,
+};
+
+static int __devinit ad7879_i2c_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct ad7879 *ts;
+
+ if (!i2c_check_functionality(client->adapter,
+ I2C_FUNC_SMBUS_WORD_DATA)) {
+ dev_err(&client->dev, "SMBUS Word Data not Supported\n");
+ return -EIO;
+ }
+
+ ts = ad7879_probe(&client->dev, AD7879_DEVID, client->irq,
+ &ad7879_i2c_bus_ops);
+ if (IS_ERR(ts))
+ return PTR_ERR(ts);
+
+ i2c_set_clientdata(client, ts);
+
+ return 0;
+}
+
+static int __devexit ad7879_i2c_remove(struct i2c_client *client)
+{
+ struct ad7879 *ts = i2c_get_clientdata(client);
+
+ ad7879_remove(ts);
+
+ return 0;
+}
+
+static const struct i2c_device_id ad7879_id[] = {
+ { "ad7879", 0 },
+ { "ad7889", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, ad7879_id);
+
+static struct i2c_driver ad7879_i2c_driver = {
+ .driver = {
+ .name = "ad7879",
+ .owner = THIS_MODULE,
+ },
+ .probe = ad7879_i2c_probe,
+ .remove = __devexit_p(ad7879_i2c_remove),
+ .suspend = ad7879_i2c_suspend,
+ .resume = ad7879_i2c_resume,
+ .id_table = ad7879_id,
+};
+
+static int __init ad7879_i2c_init(void)
+{
+ return i2c_add_driver(&ad7879_i2c_driver);
+}
+module_init(ad7879_i2c_init);
+
+static void __exit ad7879_i2c_exit(void)
+{
+ i2c_del_driver(&ad7879_i2c_driver);
+}
+module_exit(ad7879_i2c_exit);
+
+MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
+MODULE_DESCRIPTION("AD7879(-1) touchscreen I2C bus driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("i2c:ad7879");
diff --git a/drivers/input/touchscreen/ad7879-spi.c b/drivers/input/touchscreen/ad7879-spi.c
new file mode 100644
index 00000000000..59c6e68c432
--- /dev/null
+++ b/drivers/input/touchscreen/ad7879-spi.c
@@ -0,0 +1,198 @@
+/*
+ * AD7879/AD7889 touchscreen (SPI bus)
+ *
+ * Copyright (C) 2008-2010 Michael Hennerich, Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/input.h> /* BUS_SPI */
+#include <linux/spi/spi.h>
+
+#include "ad7879.h"
+
+#define AD7879_DEVID 0x7A /* AD7879/AD7889 */
+
+#define MAX_SPI_FREQ_HZ 5000000
+#define AD7879_CMD_MAGIC 0xE000
+#define AD7879_CMD_READ (1 << 10)
+#define AD7879_CMD(reg) (AD7879_CMD_MAGIC | ((reg) & 0xF))
+#define AD7879_WRITECMD(reg) (AD7879_CMD(reg))
+#define AD7879_READCMD(reg) (AD7879_CMD(reg) | AD7879_CMD_READ)
+
+#ifdef CONFIG_PM
+static int ad7879_spi_suspend(struct spi_device *spi, pm_message_t message)
+{
+ struct ad7879 *ts = spi_get_drvdata(spi);
+
+ ad7879_suspend(ts);
+
+ return 0;
+}
+
+static int ad7879_spi_resume(struct spi_device *spi)
+{
+ struct ad7879 *ts = spi_get_drvdata(spi);
+
+ ad7879_resume(ts);
+
+ return 0;
+}
+#else
+# define ad7879_spi_suspend NULL
+# define ad7879_spi_resume NULL
+#endif
+
+/*
+ * ad7879_read/write are only used for initial setup and for sysfs controls.
+ * The main traffic is done in ad7879_collect().
+ */
+
+static int ad7879_spi_xfer(struct spi_device *spi,
+ u16 cmd, u8 count, u16 *tx_buf, u16 *rx_buf)
+{
+ struct spi_message msg;
+ struct spi_transfer *xfers;
+ void *spi_data;
+ u16 *command;
+ u16 *_rx_buf = _rx_buf; /* shut gcc up */
+ u8 idx;
+ int ret;
+
+ xfers = spi_data = kzalloc(sizeof(*xfers) * (count + 2), GFP_KERNEL);
+ if (!spi_data)
+ return -ENOMEM;
+
+ spi_message_init(&msg);
+
+ command = spi_data;
+ command[0] = cmd;
+ if (count == 1) {
+ /* ad7879_spi_{read,write} gave us buf on stack */
+ command[1] = *tx_buf;
+ tx_buf = &command[1];
+ _rx_buf = rx_buf;
+ rx_buf = &command[2];
+ }
+
+ ++xfers;
+ xfers[0].tx_buf = command;
+ xfers[0].len = 2;
+ spi_message_add_tail(&xfers[0], &msg);
+ ++xfers;
+
+ for (idx = 0; idx < count; ++idx) {
+ if (rx_buf)
+ xfers[idx].rx_buf = &rx_buf[idx];
+ if (tx_buf)
+ xfers[idx].tx_buf = &tx_buf[idx];
+ xfers[idx].len = 2;
+ spi_message_add_tail(&xfers[idx], &msg);
+ }
+
+ ret = spi_sync(spi, &msg);
+
+ if (count == 1)
+ _rx_buf[0] = command[2];
+
+ kfree(spi_data);
+
+ return ret;
+}
+
+static int ad7879_spi_multi_read(struct device *dev,
+ u8 first_reg, u8 count, u16 *buf)
+{
+ struct spi_device *spi = to_spi_device(dev);
+
+ return ad7879_spi_xfer(spi, AD7879_READCMD(first_reg), count, NULL, buf);
+}
+
+static int ad7879_spi_read(struct device *dev, u8 reg)
+{
+ struct spi_device *spi = to_spi_device(dev);
+ u16 ret, dummy;
+
+ return ad7879_spi_xfer(spi, AD7879_READCMD(reg), 1, &dummy, &ret) ? : ret;
+}
+
+static int ad7879_spi_write(struct device *dev, u8 reg, u16 val)
+{
+ struct spi_device *spi = to_spi_device(dev);
+ u16 dummy;
+
+ return ad7879_spi_xfer(spi, AD7879_WRITECMD(reg), 1, &val, &dummy);
+}
+
+static const struct ad7879_bus_ops ad7879_spi_bus_ops = {
+ .bustype = BUS_SPI,
+ .read = ad7879_spi_read,
+ .multi_read = ad7879_spi_multi_read,
+ .write = ad7879_spi_write,
+};
+
+static int __devinit ad7879_spi_probe(struct spi_device *spi)
+{
+ struct ad7879 *ts;
+ int err;
+
+ /* don't exceed max specified SPI CLK frequency */
+ if (spi->max_speed_hz > MAX_SPI_FREQ_HZ) {
+ dev_err(&spi->dev, "SPI CLK %d Hz?\n", spi->max_speed_hz);
+ return -EINVAL;
+ }
+
+ spi->bits_per_word = 16;
+ err = spi_setup(spi);
+ if (err) {
+ dev_dbg(&spi->dev, "spi master doesn't support 16 bits/word\n");
+ return err;
+ }
+
+ ts = ad7879_probe(&spi->dev, AD7879_DEVID, spi->irq, &ad7879_spi_bus_ops);
+ if (IS_ERR(ts))
+ return PTR_ERR(ts);
+
+ spi_set_drvdata(spi, ts);
+
+ return 0;
+}
+
+static int __devexit ad7879_spi_remove(struct spi_device *spi)
+{
+ struct ad7879 *ts = spi_get_drvdata(spi);
+
+ ad7879_remove(ts);
+ spi_set_drvdata(spi, NULL);
+
+ return 0;
+}
+
+static struct spi_driver ad7879_spi_driver = {
+ .driver = {
+ .name = "ad7879",
+ .bus = &spi_bus_type,
+ .owner = THIS_MODULE,
+ },
+ .probe = ad7879_spi_probe,
+ .remove = __devexit_p(ad7879_spi_remove),
+ .suspend = ad7879_spi_suspend,
+ .resume = ad7879_spi_resume,
+};
+
+static int __init ad7879_spi_init(void)
+{
+ return spi_register_driver(&ad7879_spi_driver);
+}
+module_init(ad7879_spi_init);
+
+static void __exit ad7879_spi_exit(void)
+{
+ spi_unregister_driver(&ad7879_spi_driver);
+}
+module_exit(ad7879_spi_exit);
+
+MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
+MODULE_DESCRIPTION("AD7879(-1) touchscreen SPI bus driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("spi:ad7879");
diff --git a/drivers/input/touchscreen/ad7879.c b/drivers/input/touchscreen/ad7879.c
index 4b32fb4704c..ba6f0bd1e76 100644
--- a/drivers/input/touchscreen/ad7879.c
+++ b/drivers/input/touchscreen/ad7879.c
@@ -1,25 +1,9 @@
/*
- * Copyright (C) 2008-2009 Michael Hennerich, Analog Devices Inc.
+ * AD7879/AD7889 based touchscreen and GPIO driver
*
- * Description: AD7879/AD7889 based touchscreen, and GPIO driver
- * (I2C/SPI Interface)
+ * Copyright (C) 2008-2010 Michael Hennerich, Analog Devices Inc.
*
- * Bugs: Enter bugs at http://blackfin.uclinux.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see the file COPYING, or write
- * to the Free Software Foundation, Inc.,
- * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ * Licensed under the GPL-2 or later.
*
* History:
* Copyright (c) 2005 David Brownell
@@ -44,12 +28,12 @@
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/slab.h>
-#include <linux/workqueue.h>
#include <linux/spi/spi.h>
#include <linux/i2c.h>
#include <linux/gpio.h>
#include <linux/spi/ad7879.h>
+#include "ad7879.h"
#define AD7879_REG_ZEROS 0
#define AD7879_REG_CTRL1 1
@@ -120,30 +104,19 @@ enum {
#define MAX_12BIT ((1<<12)-1)
#define TS_PEN_UP_TIMEOUT msecs_to_jiffies(50)
-#if defined(CONFIG_TOUCHSCREEN_AD7879_SPI) || defined(CONFIG_TOUCHSCREEN_AD7879_SPI_MODULE)
-#define AD7879_DEVID 0x7A
-typedef struct spi_device bus_device;
-#elif defined(CONFIG_TOUCHSCREEN_AD7879_I2C) || defined(CONFIG_TOUCHSCREEN_AD7879_I2C_MODULE)
-#define AD7879_DEVID 0x79
-typedef struct i2c_client bus_device;
-#endif
-
struct ad7879 {
- bus_device *bus;
+ const struct ad7879_bus_ops *bops;
+
+ struct device *dev;
struct input_dev *input;
- struct work_struct work;
struct timer_list timer;
#ifdef CONFIG_GPIOLIB
struct gpio_chip gc;
-#endif
struct mutex mutex;
- unsigned disabled:1; /* P: mutex */
-
-#if defined(CONFIG_TOUCHSCREEN_AD7879_SPI) || defined(CONFIG_TOUCHSCREEN_AD7879_SPI_MODULE)
- struct spi_message msg;
- struct spi_transfer xfer[AD7879_NR_SENSE + 1];
- u16 cmd;
#endif
+ unsigned int irq;
+ bool disabled; /* P: input->mutex */
+ bool suspended; /* P: input->mutex */
u16 conversion_data[AD7879_NR_SENSE];
char phys[32];
u8 first_conversion_delay;
@@ -158,11 +131,22 @@ struct ad7879 {
u16 cmd_crtl3;
};
-static int ad7879_read(bus_device *, u8);
-static int ad7879_write(bus_device *, u8, u16);
-static void ad7879_collect(struct ad7879 *);
+static int ad7879_read(struct ad7879 *ts, u8 reg)
+{
+ return ts->bops->read(ts->dev, reg);
+}
+
+static int ad7879_multi_read(struct ad7879 *ts, u8 first_reg, u8 count, u16 *buf)
+{
+ return ts->bops->multi_read(ts->dev, first_reg, count, buf);
+}
-static void ad7879_report(struct ad7879 *ts)
+static int ad7879_write(struct ad7879 *ts, u8 reg, u16 val)
+{
+ return ts->bops->write(ts->dev, reg, val);
+}
+
+static int ad7879_report(struct ad7879 *ts)
{
struct input_dev *input_dev = ts->input;
unsigned Rt;
@@ -175,12 +159,14 @@ static void ad7879_report(struct ad7879 *ts)
/*
* The samples processed here are already preprocessed by the AD7879.
- * The preprocessing function consists of a median and an averaging filter.
- * The combination of these two techniques provides a robust solution,
- * discarding the spurious noise in the signal and keeping only the data of interest.
- * The size of both filters is programmable. (dev.platform_data, see linux/spi/ad7879.h)
- * Other user-programmable conversion controls include variable acquisition time,
- * and first conversion delay. Up to 16 averages can be taken per conversion.
+ * The preprocessing function consists of a median and an averaging
+ * filter. The combination of these two techniques provides a robust
+ * solution, discarding the spurious noise in the signal and keeping
+ * only the data of interest. The size of both filters is
+ * programmable. (dev.platform_data, see linux/spi/ad7879.h) Other
+ * user-programmable conversion controls include variable acquisition
+ * time, and first conversion delay. Up to 16 averages can be taken
+ * per conversion.
*/
if (likely(x && z1)) {
@@ -189,21 +175,17 @@ static void ad7879_report(struct ad7879 *ts)
Rt /= z1;
Rt = (Rt + 2047) >> 12;
+ if (!timer_pending(&ts->timer))
+ input_report_key(input_dev, BTN_TOUCH, 1);
+
input_report_abs(input_dev, ABS_X, x);
input_report_abs(input_dev, ABS_Y, y);
input_report_abs(input_dev, ABS_PRESSURE, Rt);
input_sync(input_dev);
+ return 0;
}
-}
-
-static void ad7879_work(struct work_struct *work)
-{
- struct ad7879 *ts = container_of(work, struct ad7879, work);
- /* use keventd context to read the result registers */
- ad7879_collect(ts);
- ad7879_report(ts);
- mod_timer(&ts->timer, jiffies + TS_PEN_UP_TIMEOUT);
+ return -EINVAL;
}
static void ad7879_ts_event_release(struct ad7879 *ts)
@@ -211,6 +193,7 @@ static void ad7879_ts_event_release(struct ad7879 *ts)
struct input_dev *input_dev = ts->input;
input_report_abs(input_dev, ABS_PRESSURE, 0);
+ input_report_key(input_dev, BTN_TOUCH, 0);
input_sync(input_dev);
}
@@ -225,56 +208,98 @@ static irqreturn_t ad7879_irq(int irq, void *handle)
{
struct ad7879 *ts = handle;
- /* The repeated conversion sequencer controlled by TMR kicked off too fast.
- * We ignore the last and process the sample sequence currently in the queue.
- * It can't be older than 9.4ms
- */
+ ad7879_multi_read(ts, AD7879_REG_XPLUS, AD7879_NR_SENSE, ts->conversion_data);
- if (!work_pending(&ts->work))
- schedule_work(&ts->work);
+ if (!ad7879_report(ts))
+ mod_timer(&ts->timer, jiffies + TS_PEN_UP_TIMEOUT);
return IRQ_HANDLED;
}
-static void ad7879_setup(struct ad7879 *ts)
+static void __ad7879_enable(struct ad7879 *ts)
{
- ad7879_write(ts->bus, AD7879_REG_CTRL2, ts->cmd_crtl2);
- ad7879_write(ts->bus, AD7879_REG_CTRL3, ts->cmd_crtl3);
- ad7879_write(ts->bus, AD7879_REG_CTRL1, ts->cmd_crtl1);
+ ad7879_write(ts, AD7879_REG_CTRL2, ts->cmd_crtl2);
+ ad7879_write(ts, AD7879_REG_CTRL3, ts->cmd_crtl3);
+ ad7879_write(ts, AD7879_REG_CTRL1, ts->cmd_crtl1);
+
+ enable_irq(ts->irq);
}
-static void ad7879_disable(struct ad7879 *ts)
+static void __ad7879_disable(struct ad7879 *ts)
{
- mutex_lock(&ts->mutex);
+ disable_irq(ts->irq);
+
+ if (del_timer_sync(&ts->timer))
+ ad7879_ts_event_release(ts);
+
+ ad7879_write(ts, AD7879_REG_CTRL2, AD7879_PM(AD7879_PM_SHUTDOWN));
+}
- if (!ts->disabled) {
- ts->disabled = 1;
- disable_irq(ts->bus->irq);
+static int ad7879_open(struct input_dev *input)
+{
+ struct ad7879 *ts = input_get_drvdata(input);
- cancel_work_sync(&ts->work);
+ /* protected by input->mutex */
+ if (!ts->disabled && !ts->suspended)
+ __ad7879_enable(ts);
- if (del_timer_sync(&ts->timer))
- ad7879_ts_event_release(ts);
+ return 0;
+}
- ad7879_write(ts->bus, AD7879_REG_CTRL2,
- AD7879_PM(AD7879_PM_SHUTDOWN));
- }
+static void ad7879_close(struct input_dev* input)
+{
+ struct ad7879 *ts = input_get_drvdata(input);
- mutex_unlock(&ts->mutex);
+ /* protected by input->mutex */
+ if (!ts->disabled && !ts->suspended)
+ __ad7879_disable(ts);
}
-static void ad7879_enable(struct ad7879 *ts)
+void ad7879_suspend(struct ad7879 *ts)
{
- mutex_lock(&ts->mutex);
+ mutex_lock(&ts->input->mutex);
+
+ if (!ts->suspended && !ts->disabled && ts->input->users)
+ __ad7879_disable(ts);
+
+ ts->suspended = true;
- if (ts->disabled) {
- ad7879_setup(ts);
- ts->disabled = 0;
- enable_irq(ts->bus->irq);
+ mutex_unlock(&ts->input->mutex);
+}
+EXPORT_SYMBOL(ad7879_suspend);
+
+void ad7879_resume(struct ad7879 *ts)
+{
+ mutex_lock(&ts->input->mutex);
+
+ if (ts->suspended && !ts->disabled && ts->input->users)
+ __ad7879_enable(ts);
+
+ ts->suspended = false;
+
+ mutex_unlock(&ts->input->mutex);
+}
+EXPORT_SYMBOL(ad7879_resume);
+
+static void ad7879_toggle(struct ad7879 *ts, bool disable)
+{
+ mutex_lock(&ts->input->mutex);
+
+ if (!ts->suspended && ts->input->users != 0) {
+
+ if (disable) {
+ if (ts->disabled)
+ __ad7879_enable(ts);
+ } else {
+ if (!ts->disabled)
+ __ad7879_disable(ts);
+ }
}
- mutex_unlock(&ts->mutex);
+ ts->disabled = disable;
+
+ mutex_unlock(&ts->input->mutex);
}
static ssize_t ad7879_disable_show(struct device *dev,
@@ -297,10 +322,7 @@ static ssize_t ad7879_disable_store(struct device *dev,
if (error)
return error;
- if (val)
- ad7879_disable(ts);
- else
- ad7879_enable(ts);
+ ad7879_toggle(ts, val);
return count;
}
@@ -325,7 +347,7 @@ static int ad7879_gpio_direction_input(struct gpio_chip *chip,
mutex_lock(&ts->mutex);
ts->cmd_crtl2 |= AD7879_GPIO_EN | AD7879_GPIODIR | AD7879_GPIOPOL;
- err = ad7879_write(ts->bus, AD7879_REG_CTRL2, ts->cmd_crtl2);
+ err = ad7879_write(ts, AD7879_REG_CTRL2, ts->cmd_crtl2);
mutex_unlock(&ts->mutex);
return err;
@@ -345,7 +367,7 @@ static int ad7879_gpio_direction_output(struct gpio_chip *chip,
else
ts->cmd_crtl2 &= ~AD7879_GPIO_DATA;
- err = ad7879_write(ts->bus, AD7879_REG_CTRL2, ts->cmd_crtl2);
+ err = ad7879_write(ts, AD7879_REG_CTRL2, ts->cmd_crtl2);
mutex_unlock(&ts->mutex);
return err;
@@ -357,7 +379,7 @@ static int ad7879_gpio_get_value(struct gpio_chip *chip, unsigned gpio)
u16 val;
mutex_lock(&ts->mutex);
- val = ad7879_read(ts->bus, AD7879_REG_CTRL2);
+ val = ad7879_read(ts, AD7879_REG_CTRL2);
mutex_unlock(&ts->mutex);
return !!(val & AD7879_GPIO_DATA);
@@ -374,16 +396,17 @@ static void ad7879_gpio_set_value(struct gpio_chip *chip,
else
ts->cmd_crtl2 &= ~AD7879_GPIO_DATA;
- ad7879_write(ts->bus, AD7879_REG_CTRL2, ts->cmd_crtl2);
+ ad7879_write(ts, AD7879_REG_CTRL2, ts->cmd_crtl2);
mutex_unlock(&ts->mutex);
}
-static int __devinit ad7879_gpio_add(struct device *dev)
+static int ad7879_gpio_add(struct ad7879 *ts,
+ const struct ad7879_platform_data *pdata)
{
- struct ad7879 *ts = dev_get_drvdata(dev);
- struct ad7879_platform_data *pdata = dev->platform_data;
int ret = 0;
+ mutex_init(&ts->mutex);
+
if (pdata->gpio_export) {
ts->gc.direction_input = ad7879_gpio_direction_input;
ts->gc.direction_output = ad7879_gpio_direction_output;
@@ -394,72 +417,75 @@ static int __devinit ad7879_gpio_add(struct device *dev)
ts->gc.ngpio = 1;
ts->gc.label = "AD7879-GPIO";
ts->gc.owner = THIS_MODULE;
- ts->gc.dev = dev;
+ ts->gc.dev = ts->dev;
ret = gpiochip_add(&ts->gc);
if (ret)
- dev_err(dev, "failed to register gpio %d\n",
+ dev_err(ts->dev, "failed to register gpio %d\n",
ts->gc.base);
}
return ret;
}
-/*
- * We mark ad7879_gpio_remove inline so there is a chance the code
- * gets discarded when not needed. We can't do __devinit/__devexit
- * markup since it is used in both probe and remove methods.
- */
-static inline void ad7879_gpio_remove(struct device *dev)
+static void ad7879_gpio_remove(struct ad7879 *ts)
{
- struct ad7879 *ts = dev_get_drvdata(dev);
- struct ad7879_platform_data *pdata = dev->platform_data;
+ const struct ad7879_platform_data *pdata = ts->dev->platform_data;
int ret;
if (pdata->gpio_export) {
ret = gpiochip_remove(&ts->gc);
if (ret)
- dev_err(dev, "failed to remove gpio %d\n",
+ dev_err(ts->dev, "failed to remove gpio %d\n",
ts->gc.base);
}
}
#else
-static inline int ad7879_gpio_add(struct device *dev)
+static inline int ad7879_gpio_add(struct ad7879 *ts,
+ const struct ad7879_platform_data *pdata)
{
return 0;
}
-static inline void ad7879_gpio_remove(struct device *dev)
+static inline void ad7879_gpio_remove(struct ad7879 *ts)
{
}
#endif
-static int __devinit ad7879_construct(bus_device *bus, struct ad7879 *ts)
+struct ad7879 *ad7879_probe(struct device *dev, u8 devid, unsigned int irq,
+ const struct ad7879_bus_ops *bops)
{
+ struct ad7879_platform_data *pdata = dev->platform_data;
+ struct ad7879 *ts;
struct input_dev *input_dev;
- struct ad7879_platform_data *pdata = bus->dev.platform_data;
int err;
u16 revid;
- if (!bus->irq) {
- dev_err(&bus->dev, "no IRQ?\n");
- return -ENODEV;
+ if (!irq) {
+ dev_err(dev, "no IRQ?\n");
+ err = -EINVAL;
+ goto err_out;
}
if (!pdata) {
- dev_err(&bus->dev, "no platform data?\n");
- return -ENODEV;
+ dev_err(dev, "no platform data?\n");
+ err = -EINVAL;
+ goto err_out;
}
+ ts = kzalloc(sizeof(*ts), GFP_KERNEL);
input_dev = input_allocate_device();
- if (!input_dev)
- return -ENOMEM;
+ if (!ts || !input_dev) {
+ err = -ENOMEM;
+ goto err_free_mem;
+ }
+ ts->bops = bops;
+ ts->dev = dev;
ts->input = input_dev;
+ ts->irq = irq;
setup_timer(&ts->timer, ad7879_timer, (unsigned long) ts);
- INIT_WORK(&ts->work, ad7879_work);
- mutex_init(&ts->mutex);
ts->x_plate_ohms = pdata->x_plate_ohms ? : 400;
ts->pressure_max = pdata->pressure_max ? : ~0;
@@ -470,17 +496,26 @@ static int __devinit ad7879_construct(bus_device *bus, struct ad7879 *ts)
ts->pen_down_acc_interval = pdata->pen_down_acc_interval;
ts->median = pdata->median;
- snprintf(ts->phys, sizeof(ts->phys), "%s/input0", dev_name(&bus->dev));
+ snprintf(ts->phys, sizeof(ts->phys), "%s/input0", dev_name(dev));
input_dev->name = "AD7879 Touchscreen";
input_dev->phys = ts->phys;
- input_dev->dev.parent = &bus->dev;
+ input_dev->dev.parent = dev;
+ input_dev->id.bustype = bops->bustype;
+
+ input_dev->open = ad7879_open;
+ input_dev->close = ad7879_close;
+
+ input_set_drvdata(input_dev, ts);
__set_bit(EV_ABS, input_dev->evbit);
__set_bit(ABS_X, input_dev->absbit);
__set_bit(ABS_Y, input_dev->absbit);
__set_bit(ABS_PRESSURE, input_dev->absbit);
+ __set_bit(EV_KEY, input_dev->evbit);
+ __set_bit(BTN_TOUCH, input_dev->keybit);
+
input_set_abs_params(input_dev, ABS_X,
pdata->x_min ? : 0,
pdata->x_max ? : MAX_12BIT,
@@ -492,17 +527,18 @@ static int __devinit ad7879_construct(bus_device *bus, struct ad7879 *ts)
input_set_abs_params(input_dev, ABS_PRESSURE,
pdata->pressure_min, pdata->pressure_max, 0, 0);
- err = ad7879_write(bus, AD7879_REG_CTRL2, AD7879_RESET);
-
+ err = ad7879_write(ts, AD7879_REG_CTRL2, AD7879_RESET);
if (err < 0) {
- dev_err(&bus->dev, "Failed to write %s\n", input_dev->name);
+ dev_err(dev, "Failed to write %s\n", input_dev->name);
goto err_free_mem;
}
- revid = ad7879_read(bus, AD7879_REG_REVID);
-
- if ((revid & 0xFF) != AD7879_DEVID) {
- dev_err(&bus->dev, "Failed to probe %s\n", input_dev->name);
+ revid = ad7879_read(ts, AD7879_REG_REVID);
+ input_dev->id.product = (revid & 0xff);
+ input_dev->id.version = revid >> 8;
+ if (input_dev->id.product != devid) {
+ dev_err(dev, "Failed to probe %s (%x vs %x)\n",
+ input_dev->name, devid, revid);
err = -ENODEV;
goto err_free_mem;
}
@@ -524,21 +560,21 @@ static int __devinit ad7879_construct(bus_device *bus, struct ad7879 *ts)
AD7879_ACQ(ts->acquisition_time) |
AD7879_TMR(ts->pen_down_acc_interval);
- ad7879_setup(ts);
-
- err = request_irq(bus->irq, ad7879_irq,
- IRQF_TRIGGER_FALLING, bus->dev.driver->name, ts);
-
+ err = request_threaded_irq(ts->irq, NULL, ad7879_irq,
+ IRQF_TRIGGER_FALLING,
+ dev_name(dev), ts);
if (err) {
- dev_err(&bus->dev, "irq %d busy?\n", bus->irq);
+ dev_err(dev, "irq %d busy?\n", ts->irq);
goto err_free_mem;
}
- err = sysfs_create_group(&bus->dev.kobj, &ad7879_attr_group);
+ __ad7879_disable(ts);
+
+ err = sysfs_create_group(&dev->kobj, &ad7879_attr_group);
if (err)
goto err_free_irq;
- err = ad7879_gpio_add(&bus->dev);
+ err = ad7879_gpio_add(ts, pdata);
if (err)
goto err_remove_attr;
@@ -546,321 +582,32 @@ static int __devinit ad7879_construct(bus_device *bus, struct ad7879 *ts)
if (err)
goto err_remove_gpio;
- dev_info(&bus->dev, "Rev.%d touchscreen, irq %d\n",
- revid >> 8, bus->irq);
-
- return 0;
+ return ts;
err_remove_gpio:
- ad7879_gpio_remove(&bus->dev);
+ ad7879_gpio_remove(ts);
err_remove_attr:
- sysfs_remove_group(&bus->dev.kobj, &ad7879_attr_group);
+ sysfs_remove_group(&dev->kobj, &ad7879_attr_group);
err_free_irq:
- free_irq(bus->irq, ts);
+ free_irq(ts->irq, ts);
err_free_mem:
input_free_device(input_dev);
-
- return err;
-}
-
-static int __devexit ad7879_destroy(bus_device *bus, struct ad7879 *ts)
-{
- ad7879_gpio_remove(&bus->dev);
- ad7879_disable(ts);
- sysfs_remove_group(&ts->bus->dev.kobj, &ad7879_attr_group);
- free_irq(ts->bus->irq, ts);
- input_unregister_device(ts->input);
- dev_dbg(&bus->dev, "unregistered touchscreen\n");
-
- return 0;
-}
-
-#ifdef CONFIG_PM
-static int ad7879_suspend(bus_device *bus, pm_message_t message)
-{
- struct ad7879 *ts = dev_get_drvdata(&bus->dev);
-
- ad7879_disable(ts);
-
- return 0;
-}
-
-static int ad7879_resume(bus_device *bus)
-{
- struct ad7879 *ts = dev_get_drvdata(&bus->dev);
-
- ad7879_enable(ts);
-
- return 0;
-}
-#else
-#define ad7879_suspend NULL
-#define ad7879_resume NULL
-#endif
-
-#if defined(CONFIG_TOUCHSCREEN_AD7879_SPI) || defined(CONFIG_TOUCHSCREEN_AD7879_SPI_MODULE)
-#define MAX_SPI_FREQ_HZ 5000000
-#define AD7879_CMD_MAGIC 0xE000
-#define AD7879_CMD_READ (1 << 10)
-#define AD7879_WRITECMD(reg) (AD7879_CMD_MAGIC | (reg & 0xF))
-#define AD7879_READCMD(reg) (AD7879_CMD_MAGIC | AD7879_CMD_READ | (reg & 0xF))
-
-struct ser_req {
- u16 command;
- u16 data;
- struct spi_message msg;
- struct spi_transfer xfer[2];
-};
-
-/*
- * ad7879_read/write are only used for initial setup and for sysfs controls.
- * The main traffic is done in ad7879_collect().
- */
-
-static int ad7879_read(struct spi_device *spi, u8 reg)
-{
- struct ser_req *req;
- int status, ret;
-
- req = kzalloc(sizeof *req, GFP_KERNEL);
- if (!req)
- return -ENOMEM;
-
- spi_message_init(&req->msg);
-
- req->command = (u16) AD7879_READCMD(reg);
- req->xfer[0].tx_buf = &req->command;
- req->xfer[0].len = 2;
-
- req->xfer[1].rx_buf = &req->data;
- req->xfer[1].len = 2;
-
- spi_message_add_tail(&req->xfer[0], &req->msg);
- spi_message_add_tail(&req->xfer[1], &req->msg);
-
- status = spi_sync(spi, &req->msg);
- ret = status ? : req->data;
-
- kfree(req);
-
- return ret;
-}
-
-static int ad7879_write(struct spi_device *spi, u8 reg, u16 val)
-{
- struct ser_req *req;
- int status;
-
- req = kzalloc(sizeof *req, GFP_KERNEL);
- if (!req)
- return -ENOMEM;
-
- spi_message_init(&req->msg);
-
- req->command = (u16) AD7879_WRITECMD(reg);
- req->xfer[0].tx_buf = &req->command;
- req->xfer[0].len = 2;
-
- req->data = val;
- req->xfer[1].tx_buf = &req->data;
- req->xfer[1].len = 2;
-
- spi_message_add_tail(&req->xfer[0], &req->msg);
- spi_message_add_tail(&req->xfer[1], &req->msg);
-
- status = spi_sync(spi, &req->msg);
-
- kfree(req);
-
- return status;
-}
-
-static void ad7879_collect(struct ad7879 *ts)
-{
- int status = spi_sync(ts->bus, &ts->msg);
-
- if (status)
- dev_err(&ts->bus->dev, "spi_sync --> %d\n", status);
-}
-
-static void ad7879_setup_ts_def_msg(struct ad7879 *ts)
-{
- struct spi_message *m;
- int i;
-
- ts->cmd = (u16) AD7879_READCMD(AD7879_REG_XPLUS);
-
- m = &ts->msg;
- spi_message_init(m);
- ts->xfer[0].tx_buf = &ts->cmd;
- ts->xfer[0].len = 2;
-
- spi_message_add_tail(&ts->xfer[0], m);
-
- for (i = 0; i < AD7879_NR_SENSE; i++) {
- ts->xfer[i + 1].rx_buf = &ts->conversion_data[i];
- ts->xfer[i + 1].len = 2;
- spi_message_add_tail(&ts->xfer[i + 1], m);
- }
-}
-
-static int __devinit ad7879_probe(struct spi_device *spi)
-{
- struct ad7879 *ts;
- int error;
-
- /* don't exceed max specified SPI CLK frequency */
- if (spi->max_speed_hz > MAX_SPI_FREQ_HZ) {
- dev_err(&spi->dev, "SPI CLK %d Hz?\n", spi->max_speed_hz);
- return -EINVAL;
- }
-
- ts = kzalloc(sizeof(struct ad7879), GFP_KERNEL);
- if (!ts)
- return -ENOMEM;
-
- dev_set_drvdata(&spi->dev, ts);
- ts->bus = spi;
-
- ad7879_setup_ts_def_msg(ts);
-
- error = ad7879_construct(spi, ts);
- if (error) {
- dev_set_drvdata(&spi->dev, NULL);
- kfree(ts);
- }
-
- return error;
-}
-
-static int __devexit ad7879_remove(struct spi_device *spi)
-{
- struct ad7879 *ts = dev_get_drvdata(&spi->dev);
-
- ad7879_destroy(spi, ts);
- dev_set_drvdata(&spi->dev, NULL);
kfree(ts);
-
- return 0;
+err_out:
+ return ERR_PTR(err);
}
+EXPORT_SYMBOL(ad7879_probe);
-static struct spi_driver ad7879_driver = {
- .driver = {
- .name = "ad7879",
- .bus = &spi_bus_type,
- .owner = THIS_MODULE,
- },
- .probe = ad7879_probe,
- .remove = __devexit_p(ad7879_remove),
- .suspend = ad7879_suspend,
- .resume = ad7879_resume,
-};
-
-static int __init ad7879_init(void)
-{
- return spi_register_driver(&ad7879_driver);
-}
-module_init(ad7879_init);
-
-static void __exit ad7879_exit(void)
-{
- spi_unregister_driver(&ad7879_driver);
-}
-module_exit(ad7879_exit);
-
-#elif defined(CONFIG_TOUCHSCREEN_AD7879_I2C) || defined(CONFIG_TOUCHSCREEN_AD7879_I2C_MODULE)
-
-/* All registers are word-sized.
- * AD7879 uses a high-byte first convention.
- */
-static int ad7879_read(struct i2c_client *client, u8 reg)
+void ad7879_remove(struct ad7879 *ts)
{
- return swab16(i2c_smbus_read_word_data(client, reg));
-}
-
-static int ad7879_write(struct i2c_client *client, u8 reg, u16 val)
-{
- return i2c_smbus_write_word_data(client, reg, swab16(val));
-}
-
-static void ad7879_collect(struct ad7879 *ts)
-{
- int i;
-
- for (i = 0; i < AD7879_NR_SENSE; i++)
- ts->conversion_data[i] = ad7879_read(ts->bus,
- AD7879_REG_XPLUS + i);
-}
-
-static int __devinit ad7879_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
-{
- struct ad7879 *ts;
- int error;
-
- if (!i2c_check_functionality(client->adapter,
- I2C_FUNC_SMBUS_WORD_DATA)) {
- dev_err(&client->dev, "SMBUS Word Data not Supported\n");
- return -EIO;
- }
-
- ts = kzalloc(sizeof(struct ad7879), GFP_KERNEL);
- if (!ts)
- return -ENOMEM;
-
- i2c_set_clientdata(client, ts);
- ts->bus = client;
-
- error = ad7879_construct(client, ts);
- if (error)
- kfree(ts);
-
- return error;
-}
-
-static int __devexit ad7879_remove(struct i2c_client *client)
-{
- struct ad7879 *ts = dev_get_drvdata(&client->dev);
-
- ad7879_destroy(client, ts);
+ ad7879_gpio_remove(ts);
+ sysfs_remove_group(&ts->dev->kobj, &ad7879_attr_group);
+ free_irq(ts->irq, ts);
+ input_unregister_device(ts->input);
kfree(ts);
-
- return 0;
-}
-
-static const struct i2c_device_id ad7879_id[] = {
- { "ad7879", 0 },
- { "ad7889", 0 },
- { }
-};
-MODULE_DEVICE_TABLE(i2c, ad7879_id);
-
-static struct i2c_driver ad7879_driver = {
- .driver = {
- .name = "ad7879",
- .owner = THIS_MODULE,
- },
- .probe = ad7879_probe,
- .remove = __devexit_p(ad7879_remove),
- .suspend = ad7879_suspend,
- .resume = ad7879_resume,
- .id_table = ad7879_id,
-};
-
-static int __init ad7879_init(void)
-{
- return i2c_add_driver(&ad7879_driver);
-}
-module_init(ad7879_init);
-
-static void __exit ad7879_exit(void)
-{
- i2c_del_driver(&ad7879_driver);
}
-module_exit(ad7879_exit);
-#endif
+EXPORT_SYMBOL(ad7879_remove);
MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
MODULE_DESCRIPTION("AD7879(-1) touchscreen Driver");
MODULE_LICENSE("GPL");
-MODULE_ALIAS("spi:ad7879");
diff --git a/drivers/input/touchscreen/ad7879.h b/drivers/input/touchscreen/ad7879.h
new file mode 100644
index 00000000000..6b45a27236c
--- /dev/null
+++ b/drivers/input/touchscreen/ad7879.h
@@ -0,0 +1,30 @@
+/*
+ * AD7879/AD7889 touchscreen (bus interfaces)
+ *
+ * Copyright (C) 2008-2010 Michael Hennerich, Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#ifndef _AD7879_H_
+#define _AD7879_H_
+
+#include <linux/types.h>
+
+struct ad7879;
+struct device;
+
+struct ad7879_bus_ops {
+ u16 bustype;
+ int (*read)(struct device *dev, u8 reg);
+ int (*multi_read)(struct device *dev, u8 first_reg, u8 count, u16 *buf);
+ int (*write)(struct device *dev, u8 reg, u16 val);
+};
+
+void ad7879_suspend(struct ad7879 *);
+void ad7879_resume(struct ad7879 *);
+struct ad7879 *ad7879_probe(struct device *dev, u8 devid, unsigned irq,
+ const struct ad7879_bus_ops *bops);
+void ad7879_remove(struct ad7879 *);
+
+#endif
diff --git a/drivers/input/touchscreen/ads7846.c b/drivers/input/touchscreen/ads7846.c
index a9fdf55c023..16031933a8f 100644
--- a/drivers/input/touchscreen/ads7846.c
+++ b/drivers/input/touchscreen/ads7846.c
@@ -68,6 +68,8 @@ struct ts_event {
u16 y;
u16 z1, z2;
int ignore;
+ u8 x_buf[3];
+ u8 y_buf[3];
};
/*
@@ -79,6 +81,8 @@ struct ads7846_packet {
u8 read_x, read_y, read_z1, read_z2, pwrdown;
u16 dummy; /* for the pwrdown read */
struct ts_event tc;
+ /* for ads7845 with mpc5121 psc spi we use 3-byte buffers */
+ u8 read_x_cmd[3], read_y_cmd[3], pwrdown_cmd[3];
};
struct ads7846 {
@@ -207,6 +211,14 @@ struct ser_req {
struct spi_transfer xfer[6];
};
+struct ads7845_ser_req {
+ u8 command[3];
+ u8 pwrdown[3];
+ u8 sample[3];
+ struct spi_message msg;
+ struct spi_transfer xfer[2];
+};
+
static void ads7846_enable(struct ads7846 *ts);
static void ads7846_disable(struct ads7846 *ts);
@@ -287,6 +299,41 @@ static int ads7846_read12_ser(struct device *dev, unsigned command)
return status;
}
+static int ads7845_read12_ser(struct device *dev, unsigned command)
+{
+ struct spi_device *spi = to_spi_device(dev);
+ struct ads7846 *ts = dev_get_drvdata(dev);
+ struct ads7845_ser_req *req = kzalloc(sizeof *req, GFP_KERNEL);
+ int status;
+
+ if (!req)
+ return -ENOMEM;
+
+ spi_message_init(&req->msg);
+
+ req->command[0] = (u8) command;
+ req->xfer[0].tx_buf = req->command;
+ req->xfer[0].rx_buf = req->sample;
+ req->xfer[0].len = 3;
+ spi_message_add_tail(&req->xfer[0], &req->msg);
+
+ ts->irq_disabled = 1;
+ disable_irq(spi->irq);
+ status = spi_sync(spi, &req->msg);
+ ts->irq_disabled = 0;
+ enable_irq(spi->irq);
+
+ if (status == 0) {
+ /* BE12 value, then padding */
+ status = be16_to_cpu(*((u16 *)&req->sample[1]));
+ status = status >> 3;
+ status &= 0x0fff;
+ }
+
+ kfree(req);
+ return status;
+}
+
#if defined(CONFIG_HWMON) || defined(CONFIG_HWMON_MODULE)
#define SHOW(name, var, adjust) static ssize_t \
@@ -540,10 +587,17 @@ static void ads7846_rx(void *ads)
/* ads7846_rx_val() did in-place conversion (including byteswap) from
* on-the-wire format as part of debouncing to get stable readings.
*/
- x = packet->tc.x;
- y = packet->tc.y;
- z1 = packet->tc.z1;
- z2 = packet->tc.z2;
+ if (ts->model == 7845) {
+ x = *(u16 *)packet->tc.x_buf;
+ y = *(u16 *)packet->tc.y_buf;
+ z1 = 0;
+ z2 = 0;
+ } else {
+ x = packet->tc.x;
+ y = packet->tc.y;
+ z1 = packet->tc.z1;
+ z2 = packet->tc.z2;
+ }
/* range filtering */
if (x == MAX_12BIT)
@@ -551,6 +605,12 @@ static void ads7846_rx(void *ads)
if (ts->model == 7843) {
Rt = ts->pressure_max / 2;
+ } else if (ts->model == 7845) {
+ if (get_pendown_state(ts))
+ Rt = ts->pressure_max / 2;
+ else
+ Rt = 0;
+ dev_vdbg(&ts->spi->dev, "x/y: %d/%d, PD %d\n", x, y, Rt);
} else if (likely(x && z1)) {
/* compute touch pressure resistance using equation #2 */
Rt = z2;
@@ -671,10 +731,14 @@ static void ads7846_rx_val(void *ads)
m = &ts->msg[ts->msg_idx];
t = list_entry(m->transfers.prev, struct spi_transfer, transfer_list);
- /* adjust: on-wire is a must-ignore bit, a BE12 value, then padding;
- * built from two 8 bit values written msb-first.
- */
- val = be16_to_cpup((__be16 *)t->rx_buf) >> 3;
+ if (ts->model == 7845) {
+ val = be16_to_cpup((__be16 *)&(((char*)t->rx_buf)[1])) >> 3;
+ } else {
+ /* adjust: on-wire is a must-ignore bit, a BE12 value, then
+ * padding; built from two 8 bit values written msb-first.
+ */
+ val = be16_to_cpup((__be16 *)t->rx_buf) >> 3;
+ }
action = ts->filter(ts->filter_data, ts->msg_idx, &val);
switch (action) {
@@ -878,14 +942,15 @@ static int __devinit setup_pendown(struct spi_device *spi, struct ads7846 *ts)
static int __devinit ads7846_probe(struct spi_device *spi)
{
- struct ads7846 *ts;
- struct ads7846_packet *packet;
- struct input_dev *input_dev;
- struct ads7846_platform_data *pdata = spi->dev.platform_data;
- struct spi_message *m;
- struct spi_transfer *x;
- int vref;
- int err;
+ struct ads7846 *ts;
+ struct ads7846_packet *packet;
+ struct input_dev *input_dev;
+ const struct ads7846_platform_data *pdata = spi->dev.platform_data;
+ struct spi_message *m;
+ struct spi_transfer *x;
+ unsigned long irq_flags;
+ int vref;
+ int err;
if (!spi->irq) {
dev_dbg(&spi->dev, "no IRQ?\n");
@@ -1008,16 +1073,26 @@ static int __devinit ads7846_probe(struct spi_device *spi)
spi_message_init(m);
- /* y- still on; turn on only y+ (and ADC) */
- packet->read_y = READ_Y(vref);
- x->tx_buf = &packet->read_y;
- x->len = 1;
- spi_message_add_tail(x, m);
+ if (ts->model == 7845) {
+ packet->read_y_cmd[0] = READ_Y(vref);
+ packet->read_y_cmd[1] = 0;
+ packet->read_y_cmd[2] = 0;
+ x->tx_buf = &packet->read_y_cmd[0];
+ x->rx_buf = &packet->tc.y_buf[0];
+ x->len = 3;
+ spi_message_add_tail(x, m);
+ } else {
+ /* y- still on; turn on only y+ (and ADC) */
+ packet->read_y = READ_Y(vref);
+ x->tx_buf = &packet->read_y;
+ x->len = 1;
+ spi_message_add_tail(x, m);
- x++;
- x->rx_buf = &packet->tc.y;
- x->len = 2;
- spi_message_add_tail(x, m);
+ x++;
+ x->rx_buf = &packet->tc.y;
+ 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
@@ -1043,17 +1118,28 @@ static int __devinit ads7846_probe(struct spi_device *spi)
m++;
spi_message_init(m);
- /* turn y- off, x+ on, then leave in lowpower */
- x++;
- packet->read_x = READ_X(vref);
- x->tx_buf = &packet->read_x;
- x->len = 1;
- spi_message_add_tail(x, m);
+ if (ts->model == 7845) {
+ x++;
+ packet->read_x_cmd[0] = READ_X(vref);
+ packet->read_x_cmd[1] = 0;
+ packet->read_x_cmd[2] = 0;
+ x->tx_buf = &packet->read_x_cmd[0];
+ x->rx_buf = &packet->tc.x_buf[0];
+ x->len = 3;
+ spi_message_add_tail(x, m);
+ } else {
+ /* turn y- off, x+ on, then leave in lowpower */
+ x++;
+ packet->read_x = READ_X(vref);
+ x->tx_buf = &packet->read_x;
+ x->len = 1;
+ spi_message_add_tail(x, m);
- x++;
- x->rx_buf = &packet->tc.x;
- x->len = 2;
- spi_message_add_tail(x, m);
+ x++;
+ x->rx_buf = &packet->tc.x;
+ x->len = 2;
+ spi_message_add_tail(x, m);
+ }
/* ... maybe discard first sample ... */
if (pdata->settle_delay_usecs) {
@@ -1144,15 +1230,25 @@ static int __devinit ads7846_probe(struct spi_device *spi)
m++;
spi_message_init(m);
- x++;
- packet->pwrdown = PWRDOWN;
- x->tx_buf = &packet->pwrdown;
- x->len = 1;
- spi_message_add_tail(x, m);
+ if (ts->model == 7845) {
+ x++;
+ packet->pwrdown_cmd[0] = PWRDOWN;
+ packet->pwrdown_cmd[1] = 0;
+ packet->pwrdown_cmd[2] = 0;
+ x->tx_buf = &packet->pwrdown_cmd[0];
+ x->len = 3;
+ } else {
+ x++;
+ packet->pwrdown = PWRDOWN;
+ x->tx_buf = &packet->pwrdown;
+ x->len = 1;
+ spi_message_add_tail(x, m);
+
+ x++;
+ x->rx_buf = &packet->dummy;
+ x->len = 2;
+ }
- x++;
- x->rx_buf = &packet->dummy;
- x->len = 2;
CS_CHANGE(*x);
spi_message_add_tail(x, m);
@@ -1174,17 +1270,22 @@ static int __devinit ads7846_probe(struct spi_device *spi)
goto err_put_regulator;
}
- if (request_irq(spi->irq, ads7846_irq, IRQF_TRIGGER_FALLING,
- spi->dev.driver->name, ts)) {
+ irq_flags = pdata->irq_flags ? : IRQF_TRIGGER_FALLING;
+
+ err = request_irq(spi->irq, ads7846_irq, irq_flags,
+ spi->dev.driver->name, ts);
+
+ if (err && !pdata->irq_flags) {
dev_info(&spi->dev,
"trying pin change workaround on irq %d\n", spi->irq);
err = request_irq(spi->irq, ads7846_irq,
IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
spi->dev.driver->name, ts);
- if (err) {
- dev_dbg(&spi->dev, "irq %d busy?\n", spi->irq);
- goto err_disable_regulator;
- }
+ }
+
+ if (err) {
+ dev_dbg(&spi->dev, "irq %d busy?\n", spi->irq);
+ goto err_disable_regulator;
}
err = ads784x_hwmon_register(spi, ts);
@@ -1196,8 +1297,11 @@ static int __devinit ads7846_probe(struct spi_device *spi)
/* take a first sample, leaving nPENIRQ active and vREF off; avoid
* the touchscreen, in case it's not connected.
*/
- (void) ads7846_read12_ser(&spi->dev,
- READ_12BIT_SER(vaux) | ADS_PD10_ALL_ON);
+ if (ts->model == 7845)
+ ads7845_read12_ser(&spi->dev, PWRDOWN);
+ else
+ (void) ads7846_read12_ser(&spi->dev,
+ READ_12BIT_SER(vaux) | ADS_PD10_ALL_ON);
err = sysfs_create_group(&spi->dev.kobj, &ads784x_attr_group);
if (err)
diff --git a/drivers/input/touchscreen/cy8ctmg110_ts.c b/drivers/input/touchscreen/cy8ctmg110_ts.c
new file mode 100644
index 00000000000..4eb7df0b7f8
--- /dev/null
+++ b/drivers/input/touchscreen/cy8ctmg110_ts.c
@@ -0,0 +1,363 @@
+/*
+ * Driver for cypress touch screen controller
+ *
+ * Copyright (c) 2009 Aava Mobile
+ *
+ * Some cleanups by Alan Cox <alan@linux.intel.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/input.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/i2c.h>
+#include <linux/gpio.h>
+#include <linux/input/cy8ctmg110_pdata.h>
+
+#define CY8CTMG110_DRIVER_NAME "cy8ctmg110"
+
+/* Touch coordinates */
+#define CY8CTMG110_X_MIN 0
+#define CY8CTMG110_Y_MIN 0
+#define CY8CTMG110_X_MAX 759
+#define CY8CTMG110_Y_MAX 465
+
+
+/* cy8ctmg110 register definitions */
+#define CY8CTMG110_TOUCH_WAKEUP_TIME 0
+#define CY8CTMG110_TOUCH_SLEEP_TIME 2
+#define CY8CTMG110_TOUCH_X1 3
+#define CY8CTMG110_TOUCH_Y1 5
+#define CY8CTMG110_TOUCH_X2 7
+#define CY8CTMG110_TOUCH_Y2 9
+#define CY8CTMG110_FINGERS 11
+#define CY8CTMG110_GESTURE 12
+#define CY8CTMG110_REG_MAX 13
+
+
+/*
+ * The touch driver structure.
+ */
+struct cy8ctmg110 {
+ struct input_dev *input;
+ char phys[32];
+ struct i2c_client *client;
+ int reset_pin;
+ int irq_pin;
+};
+
+/*
+ * cy8ctmg110_power is the routine that is called when touch hardware
+ * will powered off or on.
+ */
+static void cy8ctmg110_power(struct cy8ctmg110 *ts, bool poweron)
+{
+ if (ts->reset_pin)
+ gpio_direction_output(ts->reset_pin, 1 - poweron);
+}
+
+static int cy8ctmg110_write_regs(struct cy8ctmg110 *tsc, unsigned char reg,
+ unsigned char len, unsigned char *value)
+{
+ struct i2c_client *client = tsc->client;
+ unsigned int ret;
+ unsigned char i2c_data[6];
+
+ BUG_ON(len > 5);
+
+ i2c_data[0] = reg;
+ memcpy(i2c_data + 1, value, len);
+
+ ret = i2c_master_send(client, i2c_data, len + 1);
+ if (ret != 1) {
+ dev_err(&client->dev, "i2c write data cmd failed\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static int cy8ctmg110_read_regs(struct cy8ctmg110 *tsc,
+ unsigned char *data, unsigned char len, unsigned char cmd)
+{
+ struct i2c_client *client = tsc->client;
+ unsigned int ret;
+ struct i2c_msg msg[2] = {
+ /* first write slave position to i2c devices */
+ { client->addr, 0, 1, &cmd },
+ /* Second read data from position */
+ { client->addr, I2C_M_RD, len, data }
+ };
+
+ ret = i2c_transfer(client->adapter, msg, 2);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static int cy8ctmg110_touch_pos(struct cy8ctmg110 *tsc)
+{
+ struct input_dev *input = tsc->input;
+ unsigned char reg_p[CY8CTMG110_REG_MAX];
+ int x, y;
+
+ memset(reg_p, 0, CY8CTMG110_REG_MAX);
+
+ /* Reading coordinates */
+ if (cy8ctmg110_read_regs(tsc, reg_p, 9, CY8CTMG110_TOUCH_X1) != 0)
+ return -EIO;
+
+ y = reg_p[2] << 8 | reg_p[3];
+ x = reg_p[0] << 8 | reg_p[1];
+
+ /* Number of touch */
+ if (reg_p[8] == 0) {
+ input_report_key(input, BTN_TOUCH, 0);
+ } else {
+ input_report_key(input, BTN_TOUCH, 1);
+ input_report_abs(input, ABS_X, x);
+ input_report_abs(input, ABS_Y, y);
+ }
+
+ input_sync(input);
+
+ return 0;
+}
+
+static int cy8ctmg110_set_sleepmode(struct cy8ctmg110 *ts, bool sleep)
+{
+ unsigned char reg_p[3];
+
+ if (sleep) {
+ reg_p[0] = 0x00;
+ reg_p[1] = 0xff;
+ reg_p[2] = 5;
+ } else {
+ reg_p[0] = 0x10;
+ reg_p[1] = 0xff;
+ reg_p[2] = 0;
+ }
+
+ return cy8ctmg110_write_regs(ts, CY8CTMG110_TOUCH_WAKEUP_TIME, 3, reg_p);
+}
+
+static irqreturn_t cy8ctmg110_irq_thread(int irq, void *dev_id)
+{
+ struct cy8ctmg110 *tsc = dev_id;
+
+ cy8ctmg110_touch_pos(tsc);
+
+ return IRQ_HANDLED;
+}
+
+static int __devinit cy8ctmg110_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ const struct cy8ctmg110_pdata *pdata = client->dev.platform_data;
+ struct cy8ctmg110 *ts;
+ struct input_dev *input_dev;
+ int err;
+
+ /* No pdata no way forward */
+ if (pdata == NULL) {
+ dev_err(&client->dev, "no pdata\n");
+ return -ENODEV;
+ }
+
+ if (!i2c_check_functionality(client->adapter,
+ I2C_FUNC_SMBUS_READ_WORD_DATA))
+ return -EIO;
+
+ ts = kzalloc(sizeof(struct cy8ctmg110), GFP_KERNEL);
+ input_dev = input_allocate_device();
+ if (!ts || !input_dev) {
+ err = -ENOMEM;
+ goto err_free_mem;
+ }
+
+ ts->client = client;
+ ts->input = input_dev;
+
+ snprintf(ts->phys, sizeof(ts->phys),
+ "%s/input0", dev_name(&client->dev));
+
+ input_dev->name = CY8CTMG110_DRIVER_NAME " Touchscreen";
+ input_dev->phys = ts->phys;
+ input_dev->id.bustype = BUS_I2C;
+ input_dev->dev.parent = &client->dev;
+
+ input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
+ input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
+
+ input_set_abs_params(input_dev, ABS_X,
+ CY8CTMG110_X_MIN, CY8CTMG110_X_MAX, 0, 0);
+ input_set_abs_params(input_dev, ABS_Y,
+ CY8CTMG110_Y_MIN, CY8CTMG110_Y_MAX, 0, 0);
+
+ if (ts->reset_pin) {
+ err = gpio_request(ts->reset_pin, NULL);
+ if (err) {
+ dev_err(&client->dev,
+ "Unable to request GPIO pin %d.\n",
+ ts->reset_pin);
+ goto err_free_mem;
+ }
+ }
+
+ cy8ctmg110_power(ts, true);
+ cy8ctmg110_set_sleepmode(ts, false);
+
+ err = gpio_request(ts->irq_pin, "touch_irq_key");
+ if (err < 0) {
+ dev_err(&client->dev,
+ "Failed to request GPIO %d, error %d\n",
+ ts->irq_pin, err);
+ goto err_shutoff_device;
+ }
+
+ err = gpio_direction_input(ts->irq_pin);
+ if (err < 0) {
+ dev_err(&client->dev,
+ "Failed to configure input direction for GPIO %d, error %d\n",
+ ts->irq_pin, err);
+ goto err_free_irq_gpio;
+ }
+
+ client->irq = gpio_to_irq(ts->irq_pin);
+ if (client->irq < 0) {
+ err = client->irq;
+ dev_err(&client->dev,
+ "Unable to get irq number for GPIO %d, error %d\n",
+ ts->irq_pin, err);
+ goto err_free_irq_gpio;
+ }
+
+ err = request_threaded_irq(client->irq, NULL, cy8ctmg110_irq_thread,
+ IRQF_TRIGGER_RISING, "touch_reset_key", ts);
+ if (err < 0) {
+ dev_err(&client->dev,
+ "irq %d busy? error %d\n", client->irq, err);
+ goto err_free_irq_gpio;
+ }
+
+ err = input_register_device(input_dev);
+ if (err)
+ goto err_free_irq;
+
+ i2c_set_clientdata(client, ts);
+ device_init_wakeup(&client->dev, 1);
+ return 0;
+
+err_free_irq:
+ free_irq(client->irq, ts);
+err_free_irq_gpio:
+ gpio_free(ts->irq_pin);
+err_shutoff_device:
+ cy8ctmg110_set_sleepmode(ts, true);
+ cy8ctmg110_power(ts, false);
+ if (ts->reset_pin)
+ gpio_free(ts->reset_pin);
+err_free_mem:
+ input_free_device(input_dev);
+ kfree(ts);
+ return err;
+}
+
+#ifdef CONFIG_PM
+static int cy8ctmg110_suspend(struct i2c_client *client, pm_message_t mesg)
+{
+ struct cy8ctmg110 *ts = i2c_get_clientdata(client);
+
+ if (device_may_wakeup(&client->dev))
+ enable_irq_wake(client->irq);
+ else {
+ cy8ctmg110_set_sleepmode(ts, true);
+ cy8ctmg110_power(ts, false);
+ }
+ return 0;
+}
+
+static int cy8ctmg110_resume(struct i2c_client *client)
+{
+ struct cy8ctmg110 *ts = i2c_get_clientdata(client);
+
+ if (device_may_wakeup(&client->dev))
+ disable_irq_wake(client->irq);
+ else {
+ cy8ctmg110_power(ts, true);
+ cy8ctmg110_set_sleepmode(ts, false);
+ }
+ return 0;
+}
+#endif
+
+static int __devexit cy8ctmg110_remove(struct i2c_client *client)
+{
+ struct cy8ctmg110 *ts = i2c_get_clientdata(client);
+
+ cy8ctmg110_set_sleepmode(ts, true);
+ cy8ctmg110_power(ts, false);
+
+ free_irq(client->irq, ts);
+ input_unregister_device(ts->input);
+ gpio_free(ts->irq_pin);
+ if (ts->reset_pin)
+ gpio_free(ts->reset_pin);
+ kfree(ts);
+
+ return 0;
+}
+
+static struct i2c_device_id cy8ctmg110_idtable[] = {
+ { CY8CTMG110_DRIVER_NAME, 1 },
+ { }
+};
+
+MODULE_DEVICE_TABLE(i2c, cy8ctmg110_idtable);
+
+static struct i2c_driver cy8ctmg110_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = CY8CTMG110_DRIVER_NAME,
+ },
+ .id_table = cy8ctmg110_idtable,
+ .probe = cy8ctmg110_probe,
+ .remove = __devexit_p(cy8ctmg110_remove),
+#ifdef CONFIG_PM
+ .suspend = cy8ctmg110_suspend,
+ .resume = cy8ctmg110_resume,
+#endif
+};
+
+static int __init cy8ctmg110_init(void)
+{
+ return i2c_add_driver(&cy8ctmg110_driver);
+}
+
+static void __exit cy8ctmg110_exit(void)
+{
+ i2c_del_driver(&cy8ctmg110_driver);
+}
+
+module_init(cy8ctmg110_init);
+module_exit(cy8ctmg110_exit);
+
+MODULE_AUTHOR("Samuli Konttila <samuli.konttila@aavamobile.com>");
+MODULE_DESCRIPTION("cy8ctmg110 TouchScreen Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/input/touchscreen/mcs5000_ts.c b/drivers/input/touchscreen/mcs5000_ts.c
index 1fb0c2f06a4..6ee9940aaf5 100644
--- a/drivers/input/touchscreen/mcs5000_ts.c
+++ b/drivers/input/touchscreen/mcs5000_ts.c
@@ -16,7 +16,7 @@
#include <linux/module.h>
#include <linux/init.h>
#include <linux/i2c.h>
-#include <linux/i2c/mcs5000_ts.h>
+#include <linux/i2c/mcs.h>
#include <linux/interrupt.h>
#include <linux/input.h>
#include <linux/irq.h>
@@ -105,7 +105,7 @@ enum mcs5000_ts_read_offset {
struct mcs5000_ts_data {
struct i2c_client *client;
struct input_dev *input_dev;
- const struct mcs5000_ts_platform_data *platform_data;
+ const struct mcs_platform_data *platform_data;
};
static irqreturn_t mcs5000_ts_interrupt(int irq, void *dev_id)
@@ -164,7 +164,7 @@ static irqreturn_t mcs5000_ts_interrupt(int irq, void *dev_id)
static void mcs5000_ts_phys_init(struct mcs5000_ts_data *data)
{
- const struct mcs5000_ts_platform_data *platform_data =
+ const struct mcs_platform_data *platform_data =
data->platform_data;
struct i2c_client *client = data->client;
diff --git a/drivers/input/touchscreen/qt602240_ts.c b/drivers/input/touchscreen/qt602240_ts.c
new file mode 100644
index 00000000000..66b26ad3032
--- /dev/null
+++ b/drivers/input/touchscreen/qt602240_ts.c
@@ -0,0 +1,1401 @@
+/*
+ * AT42QT602240/ATMXT224 Touchscreen driver
+ *
+ * Copyright (C) 2010 Samsung Electronics Co.Ltd
+ * Author: Joonyoung Shim <jy0922.shim@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/firmware.h>
+#include <linux/i2c.h>
+#include <linux/i2c/qt602240_ts.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+
+/* Version */
+#define QT602240_VER_20 20
+#define QT602240_VER_21 21
+#define QT602240_VER_22 22
+
+/* Slave addresses */
+#define QT602240_APP_LOW 0x4a
+#define QT602240_APP_HIGH 0x4b
+#define QT602240_BOOT_LOW 0x24
+#define QT602240_BOOT_HIGH 0x25
+
+/* Firmware */
+#define QT602240_FW_NAME "qt602240.fw"
+
+/* Registers */
+#define QT602240_FAMILY_ID 0x00
+#define QT602240_VARIANT_ID 0x01
+#define QT602240_VERSION 0x02
+#define QT602240_BUILD 0x03
+#define QT602240_MATRIX_X_SIZE 0x04
+#define QT602240_MATRIX_Y_SIZE 0x05
+#define QT602240_OBJECT_NUM 0x06
+#define QT602240_OBJECT_START 0x07
+
+#define QT602240_OBJECT_SIZE 6
+
+/* Object types */
+#define QT602240_DEBUG_DIAGNOSTIC 37
+#define QT602240_GEN_MESSAGE 5
+#define QT602240_GEN_COMMAND 6
+#define QT602240_GEN_POWER 7
+#define QT602240_GEN_ACQUIRE 8
+#define QT602240_TOUCH_MULTI 9
+#define QT602240_TOUCH_KEYARRAY 15
+#define QT602240_TOUCH_PROXIMITY 23
+#define QT602240_PROCI_GRIPFACE 20
+#define QT602240_PROCG_NOISE 22
+#define QT602240_PROCI_ONETOUCH 24
+#define QT602240_PROCI_TWOTOUCH 27
+#define QT602240_SPT_COMMSCONFIG 18 /* firmware ver 21 over */
+#define QT602240_SPT_GPIOPWM 19
+#define QT602240_SPT_SELFTEST 25
+#define QT602240_SPT_CTECONFIG 28
+#define QT602240_SPT_USERDATA 38 /* firmware ver 21 over */
+
+/* QT602240_GEN_COMMAND field */
+#define QT602240_COMMAND_RESET 0
+#define QT602240_COMMAND_BACKUPNV 1
+#define QT602240_COMMAND_CALIBRATE 2
+#define QT602240_COMMAND_REPORTALL 3
+#define QT602240_COMMAND_DIAGNOSTIC 5
+
+/* QT602240_GEN_POWER field */
+#define QT602240_POWER_IDLEACQINT 0
+#define QT602240_POWER_ACTVACQINT 1
+#define QT602240_POWER_ACTV2IDLETO 2
+
+/* QT602240_GEN_ACQUIRE field */
+#define QT602240_ACQUIRE_CHRGTIME 0
+#define QT602240_ACQUIRE_TCHDRIFT 2
+#define QT602240_ACQUIRE_DRIFTST 3
+#define QT602240_ACQUIRE_TCHAUTOCAL 4
+#define QT602240_ACQUIRE_SYNC 5
+#define QT602240_ACQUIRE_ATCHCALST 6
+#define QT602240_ACQUIRE_ATCHCALSTHR 7
+
+/* QT602240_TOUCH_MULTI field */
+#define QT602240_TOUCH_CTRL 0
+#define QT602240_TOUCH_XORIGIN 1
+#define QT602240_TOUCH_YORIGIN 2
+#define QT602240_TOUCH_XSIZE 3
+#define QT602240_TOUCH_YSIZE 4
+#define QT602240_TOUCH_BLEN 6
+#define QT602240_TOUCH_TCHTHR 7
+#define QT602240_TOUCH_TCHDI 8
+#define QT602240_TOUCH_ORIENT 9
+#define QT602240_TOUCH_MOVHYSTI 11
+#define QT602240_TOUCH_MOVHYSTN 12
+#define QT602240_TOUCH_NUMTOUCH 14
+#define QT602240_TOUCH_MRGHYST 15
+#define QT602240_TOUCH_MRGTHR 16
+#define QT602240_TOUCH_AMPHYST 17
+#define QT602240_TOUCH_XRANGE_LSB 18
+#define QT602240_TOUCH_XRANGE_MSB 19
+#define QT602240_TOUCH_YRANGE_LSB 20
+#define QT602240_TOUCH_YRANGE_MSB 21
+#define QT602240_TOUCH_XLOCLIP 22
+#define QT602240_TOUCH_XHICLIP 23
+#define QT602240_TOUCH_YLOCLIP 24
+#define QT602240_TOUCH_YHICLIP 25
+#define QT602240_TOUCH_XEDGECTRL 26
+#define QT602240_TOUCH_XEDGEDIST 27
+#define QT602240_TOUCH_YEDGECTRL 28
+#define QT602240_TOUCH_YEDGEDIST 29
+#define QT602240_TOUCH_JUMPLIMIT 30 /* firmware ver 22 over */
+
+/* QT602240_PROCI_GRIPFACE field */
+#define QT602240_GRIPFACE_CTRL 0
+#define QT602240_GRIPFACE_XLOGRIP 1
+#define QT602240_GRIPFACE_XHIGRIP 2
+#define QT602240_GRIPFACE_YLOGRIP 3
+#define QT602240_GRIPFACE_YHIGRIP 4
+#define QT602240_GRIPFACE_MAXTCHS 5
+#define QT602240_GRIPFACE_SZTHR1 7
+#define QT602240_GRIPFACE_SZTHR2 8
+#define QT602240_GRIPFACE_SHPTHR1 9
+#define QT602240_GRIPFACE_SHPTHR2 10
+#define QT602240_GRIPFACE_SUPEXTTO 11
+
+/* QT602240_PROCI_NOISE field */
+#define QT602240_NOISE_CTRL 0
+#define QT602240_NOISE_OUTFLEN 1
+#define QT602240_NOISE_GCAFUL_LSB 3
+#define QT602240_NOISE_GCAFUL_MSB 4
+#define QT602240_NOISE_GCAFLL_LSB 5
+#define QT602240_NOISE_GCAFLL_MSB 6
+#define QT602240_NOISE_ACTVGCAFVALID 7
+#define QT602240_NOISE_NOISETHR 8
+#define QT602240_NOISE_FREQHOPSCALE 10
+#define QT602240_NOISE_FREQ0 11
+#define QT602240_NOISE_FREQ1 12
+#define QT602240_NOISE_FREQ2 13
+#define QT602240_NOISE_FREQ3 14
+#define QT602240_NOISE_FREQ4 15
+#define QT602240_NOISE_IDLEGCAFVALID 16
+
+/* QT602240_SPT_COMMSCONFIG */
+#define QT602240_COMMS_CTRL 0
+#define QT602240_COMMS_CMD 1
+
+/* QT602240_SPT_CTECONFIG field */
+#define QT602240_CTE_CTRL 0
+#define QT602240_CTE_CMD 1
+#define QT602240_CTE_MODE 2
+#define QT602240_CTE_IDLEGCAFDEPTH 3
+#define QT602240_CTE_ACTVGCAFDEPTH 4
+#define QT602240_CTE_VOLTAGE 5 /* firmware ver 21 over */
+
+#define QT602240_VOLTAGE_DEFAULT 2700000
+#define QT602240_VOLTAGE_STEP 10000
+
+/* Define for QT602240_GEN_COMMAND */
+#define QT602240_BOOT_VALUE 0xa5
+#define QT602240_BACKUP_VALUE 0x55
+#define QT602240_BACKUP_TIME 25 /* msec */
+#define QT602240_RESET_TIME 65 /* msec */
+
+#define QT602240_FWRESET_TIME 175 /* msec */
+
+/* Command to unlock bootloader */
+#define QT602240_UNLOCK_CMD_MSB 0xaa
+#define QT602240_UNLOCK_CMD_LSB 0xdc
+
+/* Bootloader mode status */
+#define QT602240_WAITING_BOOTLOAD_CMD 0xc0 /* valid 7 6 bit only */
+#define QT602240_WAITING_FRAME_DATA 0x80 /* valid 7 6 bit only */
+#define QT602240_FRAME_CRC_CHECK 0x02
+#define QT602240_FRAME_CRC_FAIL 0x03
+#define QT602240_FRAME_CRC_PASS 0x04
+#define QT602240_APP_CRC_FAIL 0x40 /* valid 7 8 bit only */
+#define QT602240_BOOT_STATUS_MASK 0x3f
+
+/* Touch status */
+#define QT602240_SUPPRESS (1 << 1)
+#define QT602240_AMP (1 << 2)
+#define QT602240_VECTOR (1 << 3)
+#define QT602240_MOVE (1 << 4)
+#define QT602240_RELEASE (1 << 5)
+#define QT602240_PRESS (1 << 6)
+#define QT602240_DETECT (1 << 7)
+
+/* Touchscreen absolute values */
+#define QT602240_MAX_XC 0x3ff
+#define QT602240_MAX_YC 0x3ff
+#define QT602240_MAX_AREA 0xff
+
+#define QT602240_MAX_FINGER 10
+
+/* Initial register values recommended from chip vendor */
+static const u8 init_vals_ver_20[] = {
+ /* QT602240_GEN_COMMAND(6) */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ /* QT602240_GEN_POWER(7) */
+ 0x20, 0xff, 0x32,
+ /* QT602240_GEN_ACQUIRE(8) */
+ 0x08, 0x05, 0x05, 0x00, 0x00, 0x00, 0x05, 0x14,
+ /* QT602240_TOUCH_MULTI(9) */
+ 0x00, 0x00, 0x00, 0x11, 0x0a, 0x00, 0x00, 0x00, 0x02, 0x00,
+ 0x00, 0x01, 0x01, 0x0e, 0x0a, 0x0a, 0x0a, 0x0a, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0x64,
+ /* QT602240_TOUCH_KEYARRAY(15) */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00,
+ /* QT602240_SPT_GPIOPWM(19) */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00,
+ /* QT602240_PROCI_GRIPFACE(20) */
+ 0x00, 0x64, 0x64, 0x64, 0x64, 0x00, 0x00, 0x1e, 0x14, 0x04,
+ 0x1e, 0x00,
+ /* QT602240_PROCG_NOISE(22) */
+ 0x05, 0x00, 0x00, 0x19, 0x00, 0xe7, 0xff, 0x04, 0x32, 0x00,
+ 0x01, 0x0a, 0x0f, 0x14, 0x00, 0x00, 0xe8,
+ /* QT602240_TOUCH_PROXIMITY(23) */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00,
+ /* QT602240_PROCI_ONETOUCH(24) */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ /* QT602240_SPT_SELFTEST(25) */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ /* QT602240_PROCI_TWOTOUCH(27) */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ /* QT602240_SPT_CTECONFIG(28) */
+ 0x00, 0x00, 0x00, 0x04, 0x08,
+};
+
+static const u8 init_vals_ver_21[] = {
+ /* QT602240_GEN_COMMAND(6) */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ /* QT602240_GEN_POWER(7) */
+ 0x20, 0xff, 0x32,
+ /* QT602240_GEN_ACQUIRE(8) */
+ 0x0a, 0x00, 0x05, 0x00, 0x00, 0x00, 0x09, 0x23,
+ /* QT602240_TOUCH_MULTI(9) */
+ 0x00, 0x00, 0x00, 0x13, 0x0b, 0x00, 0x00, 0x00, 0x02, 0x00,
+ 0x00, 0x01, 0x01, 0x0e, 0x0a, 0x0a, 0x0a, 0x0a, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ /* QT602240_TOUCH_KEYARRAY(15) */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00,
+ /* QT602240_SPT_GPIOPWM(19) */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ /* QT602240_PROCI_GRIPFACE(20) */
+ 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x28, 0x04,
+ 0x0f, 0x0a,
+ /* QT602240_PROCG_NOISE(22) */
+ 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x23, 0x00,
+ 0x00, 0x05, 0x0f, 0x19, 0x23, 0x2d, 0x03,
+ /* QT602240_TOUCH_PROXIMITY(23) */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00,
+ /* QT602240_PROCI_ONETOUCH(24) */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ /* QT602240_SPT_SELFTEST(25) */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ /* QT602240_PROCI_TWOTOUCH(27) */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ /* QT602240_SPT_CTECONFIG(28) */
+ 0x00, 0x00, 0x00, 0x08, 0x10, 0x00,
+};
+
+static const u8 init_vals_ver_22[] = {
+ /* QT602240_GEN_COMMAND(6) */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ /* QT602240_GEN_POWER(7) */
+ 0x20, 0xff, 0x32,
+ /* QT602240_GEN_ACQUIRE(8) */
+ 0x0a, 0x00, 0x05, 0x00, 0x00, 0x00, 0x09, 0x23,
+ /* QT602240_TOUCH_MULTI(9) */
+ 0x00, 0x00, 0x00, 0x13, 0x0b, 0x00, 0x00, 0x00, 0x02, 0x00,
+ 0x00, 0x01, 0x01, 0x0e, 0x0a, 0x0a, 0x0a, 0x0a, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00,
+ /* QT602240_TOUCH_KEYARRAY(15) */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00,
+ /* QT602240_SPT_GPIOPWM(19) */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ /* QT602240_PROCI_GRIPFACE(20) */
+ 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x28, 0x04,
+ 0x0f, 0x0a,
+ /* QT602240_PROCG_NOISE(22) */
+ 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x23, 0x00,
+ 0x00, 0x05, 0x0f, 0x19, 0x23, 0x2d, 0x03,
+ /* QT602240_TOUCH_PROXIMITY(23) */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00,
+ /* QT602240_PROCI_ONETOUCH(24) */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ /* QT602240_SPT_SELFTEST(25) */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ /* QT602240_PROCI_TWOTOUCH(27) */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ /* QT602240_SPT_CTECONFIG(28) */
+ 0x00, 0x00, 0x00, 0x08, 0x10, 0x00,
+};
+
+struct qt602240_info {
+ u8 family_id;
+ u8 variant_id;
+ u8 version;
+ u8 build;
+ u8 matrix_xsize;
+ u8 matrix_ysize;
+ u8 object_num;
+};
+
+struct qt602240_object {
+ u8 type;
+ u16 start_address;
+ u8 size;
+ u8 instances;
+ u8 num_report_ids;
+
+ /* to map object and message */
+ u8 max_reportid;
+};
+
+struct qt602240_message {
+ u8 reportid;
+ u8 message[7];
+ u8 checksum;
+};
+
+struct qt602240_finger {
+ int status;
+ int x;
+ int y;
+ int area;
+};
+
+/* Each client has this additional data */
+struct qt602240_data {
+ struct i2c_client *client;
+ struct input_dev *input_dev;
+ const struct qt602240_platform_data *pdata;
+ struct qt602240_object *object_table;
+ struct qt602240_info info;
+ struct qt602240_finger finger[QT602240_MAX_FINGER];
+ unsigned int irq;
+};
+
+static bool qt602240_object_readable(unsigned int type)
+{
+ switch (type) {
+ case QT602240_GEN_MESSAGE:
+ case QT602240_GEN_COMMAND:
+ case QT602240_GEN_POWER:
+ case QT602240_GEN_ACQUIRE:
+ case QT602240_TOUCH_MULTI:
+ case QT602240_TOUCH_KEYARRAY:
+ case QT602240_TOUCH_PROXIMITY:
+ case QT602240_PROCI_GRIPFACE:
+ case QT602240_PROCG_NOISE:
+ case QT602240_PROCI_ONETOUCH:
+ case QT602240_PROCI_TWOTOUCH:
+ case QT602240_SPT_COMMSCONFIG:
+ case QT602240_SPT_GPIOPWM:
+ case QT602240_SPT_SELFTEST:
+ case QT602240_SPT_CTECONFIG:
+ case QT602240_SPT_USERDATA:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool qt602240_object_writable(unsigned int type)
+{
+ switch (type) {
+ case QT602240_GEN_COMMAND:
+ case QT602240_GEN_POWER:
+ case QT602240_GEN_ACQUIRE:
+ case QT602240_TOUCH_MULTI:
+ case QT602240_TOUCH_KEYARRAY:
+ case QT602240_TOUCH_PROXIMITY:
+ case QT602240_PROCI_GRIPFACE:
+ case QT602240_PROCG_NOISE:
+ case QT602240_PROCI_ONETOUCH:
+ case QT602240_PROCI_TWOTOUCH:
+ case QT602240_SPT_GPIOPWM:
+ case QT602240_SPT_SELFTEST:
+ case QT602240_SPT_CTECONFIG:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static void qt602240_dump_message(struct device *dev,
+ struct qt602240_message *message)
+{
+ dev_dbg(dev, "reportid:\t0x%x\n", message->reportid);
+ dev_dbg(dev, "message1:\t0x%x\n", message->message[0]);
+ dev_dbg(dev, "message2:\t0x%x\n", message->message[1]);
+ dev_dbg(dev, "message3:\t0x%x\n", message->message[2]);
+ dev_dbg(dev, "message4:\t0x%x\n", message->message[3]);
+ dev_dbg(dev, "message5:\t0x%x\n", message->message[4]);
+ dev_dbg(dev, "message6:\t0x%x\n", message->message[5]);
+ dev_dbg(dev, "message7:\t0x%x\n", message->message[6]);
+ dev_dbg(dev, "checksum:\t0x%x\n", message->checksum);
+}
+
+static int qt602240_check_bootloader(struct i2c_client *client,
+ unsigned int state)
+{
+ u8 val;
+
+recheck:
+ if (i2c_master_recv(client, &val, 1) != 1) {
+ dev_err(&client->dev, "%s: i2c recv failed\n", __func__);
+ return -EIO;
+ }
+
+ switch (state) {
+ case QT602240_WAITING_BOOTLOAD_CMD:
+ case QT602240_WAITING_FRAME_DATA:
+ val &= ~QT602240_BOOT_STATUS_MASK;
+ break;
+ case QT602240_FRAME_CRC_PASS:
+ if (val == QT602240_FRAME_CRC_CHECK)
+ goto recheck;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (val != state) {
+ dev_err(&client->dev, "Unvalid bootloader mode state\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int qt602240_unlock_bootloader(struct i2c_client *client)
+{
+ u8 buf[2];
+
+ buf[0] = QT602240_UNLOCK_CMD_LSB;
+ buf[1] = QT602240_UNLOCK_CMD_MSB;
+
+ if (i2c_master_send(client, buf, 2) != 2) {
+ dev_err(&client->dev, "%s: i2c send failed\n", __func__);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int qt602240_fw_write(struct i2c_client *client,
+ const u8 *data, unsigned int frame_size)
+{
+ if (i2c_master_send(client, data, frame_size) != frame_size) {
+ dev_err(&client->dev, "%s: i2c send failed\n", __func__);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int __qt602240_read_reg(struct i2c_client *client,
+ u16 reg, u16 len, void *val)
+{
+ struct i2c_msg xfer[2];
+ u8 buf[2];
+
+ buf[0] = reg & 0xff;
+ buf[1] = (reg >> 8) & 0xff;
+
+ /* Write register */
+ xfer[0].addr = client->addr;
+ xfer[0].flags = 0;
+ xfer[0].len = 2;
+ xfer[0].buf = buf;
+
+ /* Read data */
+ xfer[1].addr = client->addr;
+ xfer[1].flags = I2C_M_RD;
+ xfer[1].len = len;
+ xfer[1].buf = val;
+
+ if (i2c_transfer(client->adapter, xfer, 2) != 2) {
+ dev_err(&client->dev, "%s: i2c transfer failed\n", __func__);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int qt602240_read_reg(struct i2c_client *client, u16 reg, u8 *val)
+{
+ return __qt602240_read_reg(client, reg, 1, val);
+}
+
+static int qt602240_write_reg(struct i2c_client *client, u16 reg, u8 val)
+{
+ u8 buf[3];
+
+ buf[0] = reg & 0xff;
+ buf[1] = (reg >> 8) & 0xff;
+ buf[2] = val;
+
+ if (i2c_master_send(client, buf, 3) != 3) {
+ dev_err(&client->dev, "%s: i2c send failed\n", __func__);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int qt602240_read_object_table(struct i2c_client *client,
+ u16 reg, u8 *object_buf)
+{
+ return __qt602240_read_reg(client, reg, QT602240_OBJECT_SIZE,
+ object_buf);
+}
+
+static struct qt602240_object *
+qt602240_get_object(struct qt602240_data *data, u8 type)
+{
+ struct qt602240_object *object;
+ int i;
+
+ for (i = 0; i < data->info.object_num; i++) {
+ object = data->object_table + i;
+ if (object->type == type)
+ return object;
+ }
+
+ dev_err(&data->client->dev, "Invalid object type\n");
+ return NULL;
+}
+
+static int qt602240_read_message(struct qt602240_data *data,
+ struct qt602240_message *message)
+{
+ struct qt602240_object *object;
+ u16 reg;
+
+ object = qt602240_get_object(data, QT602240_GEN_MESSAGE);
+ if (!object)
+ return -EINVAL;
+
+ reg = object->start_address;
+ return __qt602240_read_reg(data->client, reg,
+ sizeof(struct qt602240_message), message);
+}
+
+static int qt602240_read_object(struct qt602240_data *data,
+ u8 type, u8 offset, u8 *val)
+{
+ struct qt602240_object *object;
+ u16 reg;
+
+ object = qt602240_get_object(data, type);
+ if (!object)
+ return -EINVAL;
+
+ reg = object->start_address;
+ return __qt602240_read_reg(data->client, reg + offset, 1, val);
+}
+
+static int qt602240_write_object(struct qt602240_data *data,
+ u8 type, u8 offset, u8 val)
+{
+ struct qt602240_object *object;
+ u16 reg;
+
+ object = qt602240_get_object(data, type);
+ if (!object)
+ return -EINVAL;
+
+ reg = object->start_address;
+ return qt602240_write_reg(data->client, reg + offset, val);
+}
+
+static void qt602240_input_report(struct qt602240_data *data, int single_id)
+{
+ struct qt602240_finger *finger = data->finger;
+ struct input_dev *input_dev = data->input_dev;
+ int status = finger[single_id].status;
+ int finger_num = 0;
+ int id;
+
+ for (id = 0; id < QT602240_MAX_FINGER; id++) {
+ if (!finger[id].status)
+ continue;
+
+ input_report_abs(input_dev, ABS_MT_TOUCH_MAJOR,
+ finger[id].status != QT602240_RELEASE ?
+ finger[id].area : 0);
+ input_report_abs(input_dev, ABS_MT_POSITION_X,
+ finger[id].x);
+ input_report_abs(input_dev, ABS_MT_POSITION_Y,
+ finger[id].y);
+ input_mt_sync(input_dev);
+
+ if (finger[id].status == QT602240_RELEASE)
+ finger[id].status = 0;
+ else
+ finger_num++;
+ }
+
+ input_report_key(input_dev, BTN_TOUCH, finger_num > 0);
+
+ if (status != QT602240_RELEASE) {
+ input_report_abs(input_dev, ABS_X, finger[single_id].x);
+ input_report_abs(input_dev, ABS_Y, finger[single_id].y);
+ }
+
+ input_sync(input_dev);
+}
+
+static void qt602240_input_touchevent(struct qt602240_data *data,
+ struct qt602240_message *message, int id)
+{
+ struct qt602240_finger *finger = data->finger;
+ struct device *dev = &data->client->dev;
+ u8 status = message->message[0];
+ int x;
+ int y;
+ int area;
+
+ /* Check the touch is present on the screen */
+ if (!(status & QT602240_DETECT)) {
+ if (status & QT602240_RELEASE) {
+ dev_dbg(dev, "[%d] released\n", id);
+
+ finger[id].status = QT602240_RELEASE;
+ qt602240_input_report(data, id);
+ }
+ return;
+ }
+
+ /* Check only AMP detection */
+ if (!(status & (QT602240_PRESS | QT602240_MOVE)))
+ return;
+
+ x = (message->message[1] << 2) | ((message->message[3] & ~0x3f) >> 6);
+ y = (message->message[2] << 2) | ((message->message[3] & ~0xf3) >> 2);
+ area = message->message[4];
+
+ dev_dbg(dev, "[%d] %s x: %d, y: %d, area: %d\n", id,
+ status & QT602240_MOVE ? "moved" : "pressed",
+ x, y, area);
+
+ finger[id].status = status & QT602240_MOVE ?
+ QT602240_MOVE : QT602240_PRESS;
+ finger[id].x = x;
+ finger[id].y = y;
+ finger[id].area = area;
+
+ qt602240_input_report(data, id);
+}
+
+static irqreturn_t qt602240_interrupt(int irq, void *dev_id)
+{
+ struct qt602240_data *data = dev_id;
+ struct qt602240_message message;
+ struct qt602240_object *object;
+ struct device *dev = &data->client->dev;
+ int id;
+ u8 reportid;
+ u8 max_reportid;
+ u8 min_reportid;
+
+ do {
+ if (qt602240_read_message(data, &message)) {
+ dev_err(dev, "Failed to read message\n");
+ goto end;
+ }
+
+ reportid = message.reportid;
+
+ /* whether reportid is thing of QT602240_TOUCH_MULTI */
+ object = qt602240_get_object(data, QT602240_TOUCH_MULTI);
+ if (!object)
+ goto end;
+
+ max_reportid = object->max_reportid;
+ min_reportid = max_reportid - object->num_report_ids + 1;
+ id = reportid - min_reportid;
+
+ if (reportid >= min_reportid && reportid <= max_reportid)
+ qt602240_input_touchevent(data, &message, id);
+ else
+ qt602240_dump_message(dev, &message);
+ } while (reportid != 0xff);
+
+end:
+ return IRQ_HANDLED;
+}
+
+static int qt602240_check_reg_init(struct qt602240_data *data)
+{
+ struct qt602240_object *object;
+ struct device *dev = &data->client->dev;
+ int index = 0;
+ int i, j;
+ u8 version = data->info.version;
+ u8 *init_vals;
+
+ switch (version) {
+ case QT602240_VER_20:
+ init_vals = (u8 *)init_vals_ver_20;
+ break;
+ case QT602240_VER_21:
+ init_vals = (u8 *)init_vals_ver_21;
+ break;
+ case QT602240_VER_22:
+ init_vals = (u8 *)init_vals_ver_22;
+ break;
+ default:
+ dev_err(dev, "Firmware version %d doesn't support\n", version);
+ return -EINVAL;
+ }
+
+ for (i = 0; i < data->info.object_num; i++) {
+ object = data->object_table + i;
+
+ if (!qt602240_object_writable(object->type))
+ continue;
+
+ for (j = 0; j < object->size + 1; j++)
+ qt602240_write_object(data, object->type, j,
+ init_vals[index + j]);
+
+ index += object->size + 1;
+ }
+
+ return 0;
+}
+
+static int qt602240_check_matrix_size(struct qt602240_data *data)
+{
+ const struct qt602240_platform_data *pdata = data->pdata;
+ struct device *dev = &data->client->dev;
+ int mode = -1;
+ int error;
+ u8 val;
+
+ dev_dbg(dev, "Number of X lines: %d\n", pdata->x_line);
+ dev_dbg(dev, "Number of Y lines: %d\n", pdata->y_line);
+
+ switch (pdata->x_line) {
+ case 0 ... 15:
+ if (pdata->y_line <= 14)
+ mode = 0;
+ break;
+ case 16:
+ if (pdata->y_line <= 12)
+ mode = 1;
+ if (pdata->y_line == 13 || pdata->y_line == 14)
+ mode = 0;
+ break;
+ case 17:
+ if (pdata->y_line <= 11)
+ mode = 2;
+ if (pdata->y_line == 12 || pdata->y_line == 13)
+ mode = 1;
+ break;
+ case 18:
+ if (pdata->y_line <= 10)
+ mode = 3;
+ if (pdata->y_line == 11 || pdata->y_line == 12)
+ mode = 2;
+ break;
+ case 19:
+ if (pdata->y_line <= 9)
+ mode = 4;
+ if (pdata->y_line == 10 || pdata->y_line == 11)
+ mode = 3;
+ break;
+ case 20:
+ mode = 4;
+ }
+
+ if (mode < 0) {
+ dev_err(dev, "Invalid X/Y lines\n");
+ return -EINVAL;
+ }
+
+ error = qt602240_read_object(data, QT602240_SPT_CTECONFIG,
+ QT602240_CTE_MODE, &val);
+ if (error)
+ return error;
+
+ if (mode == val)
+ return 0;
+
+ /* Change the CTE configuration */
+ qt602240_write_object(data, QT602240_SPT_CTECONFIG,
+ QT602240_CTE_CTRL, 1);
+ qt602240_write_object(data, QT602240_SPT_CTECONFIG,
+ QT602240_CTE_MODE, mode);
+ qt602240_write_object(data, QT602240_SPT_CTECONFIG,
+ QT602240_CTE_CTRL, 0);
+
+ return 0;
+}
+
+static int qt602240_make_highchg(struct qt602240_data *data)
+{
+ struct device *dev = &data->client->dev;
+ int count = 10;
+ int error;
+ u8 val;
+
+ /* Read dummy message to make high CHG pin */
+ do {
+ error = qt602240_read_object(data, QT602240_GEN_MESSAGE, 0, &val);
+ if (error)
+ return error;
+ } while ((val != 0xff) && --count);
+
+ if (!count) {
+ dev_err(dev, "CHG pin isn't cleared\n");
+ return -EBUSY;
+ }
+
+ return 0;
+}
+
+static void qt602240_handle_pdata(struct qt602240_data *data)
+{
+ const struct qt602240_platform_data *pdata = data->pdata;
+ u8 voltage;
+
+ /* Set touchscreen lines */
+ qt602240_write_object(data, QT602240_TOUCH_MULTI, QT602240_TOUCH_XSIZE,
+ pdata->x_line);
+ qt602240_write_object(data, QT602240_TOUCH_MULTI, QT602240_TOUCH_YSIZE,
+ pdata->y_line);
+
+ /* Set touchscreen orient */
+ qt602240_write_object(data, QT602240_TOUCH_MULTI, QT602240_TOUCH_ORIENT,
+ pdata->orient);
+
+ /* Set touchscreen burst length */
+ qt602240_write_object(data, QT602240_TOUCH_MULTI,
+ QT602240_TOUCH_BLEN, pdata->blen);
+
+ /* Set touchscreen threshold */
+ qt602240_write_object(data, QT602240_TOUCH_MULTI,
+ QT602240_TOUCH_TCHTHR, pdata->threshold);
+
+ /* Set touchscreen resolution */
+ qt602240_write_object(data, QT602240_TOUCH_MULTI,
+ QT602240_TOUCH_XRANGE_LSB, (pdata->x_size - 1) & 0xff);
+ qt602240_write_object(data, QT602240_TOUCH_MULTI,
+ QT602240_TOUCH_XRANGE_MSB, (pdata->x_size - 1) >> 8);
+ qt602240_write_object(data, QT602240_TOUCH_MULTI,
+ QT602240_TOUCH_YRANGE_LSB, (pdata->y_size - 1) & 0xff);
+ qt602240_write_object(data, QT602240_TOUCH_MULTI,
+ QT602240_TOUCH_YRANGE_MSB, (pdata->y_size - 1) >> 8);
+
+ /* Set touchscreen voltage */
+ if (data->info.version >= QT602240_VER_21 && pdata->voltage) {
+ if (pdata->voltage < QT602240_VOLTAGE_DEFAULT) {
+ voltage = (QT602240_VOLTAGE_DEFAULT - pdata->voltage) /
+ QT602240_VOLTAGE_STEP;
+ voltage = 0xff - voltage + 1;
+ } else
+ voltage = (pdata->voltage - QT602240_VOLTAGE_DEFAULT) /
+ QT602240_VOLTAGE_STEP;
+
+ qt602240_write_object(data, QT602240_SPT_CTECONFIG,
+ QT602240_CTE_VOLTAGE, voltage);
+ }
+}
+
+static int qt602240_get_info(struct qt602240_data *data)
+{
+ struct i2c_client *client = data->client;
+ struct qt602240_info *info = &data->info;
+ int error;
+ u8 val;
+
+ error = qt602240_read_reg(client, QT602240_FAMILY_ID, &val);
+ if (error)
+ return error;
+ info->family_id = val;
+
+ error = qt602240_read_reg(client, QT602240_VARIANT_ID, &val);
+ if (error)
+ return error;
+ info->variant_id = val;
+
+ error = qt602240_read_reg(client, QT602240_VERSION, &val);
+ if (error)
+ return error;
+ info->version = val;
+
+ error = qt602240_read_reg(client, QT602240_BUILD, &val);
+ if (error)
+ return error;
+ info->build = val;
+
+ error = qt602240_read_reg(client, QT602240_OBJECT_NUM, &val);
+ if (error)
+ return error;
+ info->object_num = val;
+
+ return 0;
+}
+
+static int qt602240_get_object_table(struct qt602240_data *data)
+{
+ int error;
+ int i;
+ u16 reg;
+ u8 reportid = 0;
+ u8 buf[QT602240_OBJECT_SIZE];
+
+ for (i = 0; i < data->info.object_num; i++) {
+ struct qt602240_object *object = data->object_table + i;
+
+ reg = QT602240_OBJECT_START + QT602240_OBJECT_SIZE * i;
+ error = qt602240_read_object_table(data->client, reg, buf);
+ if (error)
+ return error;
+
+ object->type = buf[0];
+ object->start_address = (buf[2] << 8) | buf[1];
+ object->size = buf[3];
+ object->instances = buf[4];
+ object->num_report_ids = buf[5];
+
+ if (object->num_report_ids) {
+ reportid += object->num_report_ids *
+ (object->instances + 1);
+ object->max_reportid = reportid;
+ }
+ }
+
+ return 0;
+}
+
+static int qt602240_initialize(struct qt602240_data *data)
+{
+ struct i2c_client *client = data->client;
+ struct qt602240_info *info = &data->info;
+ int error;
+ u8 val;
+
+ error = qt602240_get_info(data);
+ if (error)
+ return error;
+
+ data->object_table = kcalloc(info->object_num,
+ sizeof(struct qt602240_data),
+ GFP_KERNEL);
+ if (!data->object_table) {
+ dev_err(&client->dev, "Failed to allocate memory\n");
+ return -ENOMEM;
+ }
+
+ /* Get object table information */
+ error = qt602240_get_object_table(data);
+ if (error)
+ return error;
+
+ /* Check register init values */
+ error = qt602240_check_reg_init(data);
+ if (error)
+ return error;
+
+ /* Check X/Y matrix size */
+ error = qt602240_check_matrix_size(data);
+ if (error)
+ return error;
+
+ error = qt602240_make_highchg(data);
+ if (error)
+ return error;
+
+ qt602240_handle_pdata(data);
+
+ /* Backup to memory */
+ qt602240_write_object(data, QT602240_GEN_COMMAND,
+ QT602240_COMMAND_BACKUPNV,
+ QT602240_BACKUP_VALUE);
+ msleep(QT602240_BACKUP_TIME);
+
+ /* Soft reset */
+ qt602240_write_object(data, QT602240_GEN_COMMAND,
+ QT602240_COMMAND_RESET, 1);
+ msleep(QT602240_RESET_TIME);
+
+ /* Update matrix size at info struct */
+ error = qt602240_read_reg(client, QT602240_MATRIX_X_SIZE, &val);
+ if (error)
+ return error;
+ info->matrix_xsize = val;
+
+ error = qt602240_read_reg(client, QT602240_MATRIX_Y_SIZE, &val);
+ if (error)
+ return error;
+ info->matrix_ysize = val;
+
+ dev_info(&client->dev,
+ "Family ID: %d Variant ID: %d Version: %d Build: %d\n",
+ info->family_id, info->variant_id, info->version,
+ info->build);
+
+ dev_info(&client->dev,
+ "Matrix X Size: %d Matrix Y Size: %d Object Num: %d\n",
+ info->matrix_xsize, info->matrix_ysize,
+ info->object_num);
+
+ return 0;
+}
+
+static ssize_t qt602240_object_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct qt602240_data *data = dev_get_drvdata(dev);
+ struct qt602240_object *object;
+ int count = 0;
+ int i, j;
+ int error;
+ u8 val;
+
+ for (i = 0; i < data->info.object_num; i++) {
+ object = data->object_table + i;
+
+ count += sprintf(buf + count,
+ "Object Table Element %d(Type %d)\n",
+ i + 1, object->type);
+
+ if (!qt602240_object_readable(object->type)) {
+ count += sprintf(buf + count, "\n");
+ continue;
+ }
+
+ for (j = 0; j < object->size + 1; j++) {
+ error = qt602240_read_object(data,
+ object->type, j, &val);
+ if (error)
+ return error;
+
+ count += sprintf(buf + count,
+ " Byte %d: 0x%x (%d)\n", j, val, val);
+ }
+
+ count += sprintf(buf + count, "\n");
+ }
+
+ return count;
+}
+
+static int qt602240_load_fw(struct device *dev, const char *fn)
+{
+ struct qt602240_data *data = dev_get_drvdata(dev);
+ struct i2c_client *client = data->client;
+ const struct firmware *fw = NULL;
+ unsigned int frame_size;
+ unsigned int pos = 0;
+ int ret;
+
+ ret = request_firmware(&fw, fn, dev);
+ if (ret) {
+ dev_err(dev, "Unable to open firmware %s\n", fn);
+ return ret;
+ }
+
+ /* Change to the bootloader mode */
+ qt602240_write_object(data, QT602240_GEN_COMMAND,
+ QT602240_COMMAND_RESET, QT602240_BOOT_VALUE);
+ msleep(QT602240_RESET_TIME);
+
+ /* Change to slave address of bootloader */
+ if (client->addr == QT602240_APP_LOW)
+ client->addr = QT602240_BOOT_LOW;
+ else
+ client->addr = QT602240_BOOT_HIGH;
+
+ ret = qt602240_check_bootloader(client, QT602240_WAITING_BOOTLOAD_CMD);
+ if (ret)
+ goto out;
+
+ /* Unlock bootloader */
+ qt602240_unlock_bootloader(client);
+
+ while (pos < fw->size) {
+ ret = qt602240_check_bootloader(client,
+ QT602240_WAITING_FRAME_DATA);
+ if (ret)
+ goto out;
+
+ frame_size = ((*(fw->data + pos) << 8) | *(fw->data + pos + 1));
+
+ /* We should add 2 at frame size as the the firmware data is not
+ * included the CRC bytes.
+ */
+ frame_size += 2;
+
+ /* Write one frame to device */
+ qt602240_fw_write(client, fw->data + pos, frame_size);
+
+ ret = qt602240_check_bootloader(client,
+ QT602240_FRAME_CRC_PASS);
+ if (ret)
+ goto out;
+
+ pos += frame_size;
+
+ dev_dbg(dev, "Updated %d bytes / %zd bytes\n", pos, fw->size);
+ }
+
+out:
+ release_firmware(fw);
+
+ /* Change to slave address of application */
+ if (client->addr == QT602240_BOOT_LOW)
+ client->addr = QT602240_APP_LOW;
+ else
+ client->addr = QT602240_APP_HIGH;
+
+ return ret;
+}
+
+static ssize_t qt602240_update_fw_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct qt602240_data *data = dev_get_drvdata(dev);
+ unsigned int version;
+ int error;
+
+ if (sscanf(buf, "%u", &version) != 1) {
+ dev_err(dev, "Invalid values\n");
+ return -EINVAL;
+ }
+
+ if (data->info.version < QT602240_VER_21 || version < QT602240_VER_21) {
+ dev_err(dev, "FW update supported starting with version 21\n");
+ return -EINVAL;
+ }
+
+ disable_irq(data->irq);
+
+ error = qt602240_load_fw(dev, QT602240_FW_NAME);
+ if (error) {
+ dev_err(dev, "The firmware update failed(%d)\n", error);
+ count = error;
+ } else {
+ dev_dbg(dev, "The firmware update succeeded\n");
+
+ /* Wait for reset */
+ msleep(QT602240_FWRESET_TIME);
+
+ kfree(data->object_table);
+ data->object_table = NULL;
+
+ qt602240_initialize(data);
+ }
+
+ enable_irq(data->irq);
+
+ return count;
+}
+
+static DEVICE_ATTR(object, 0444, qt602240_object_show, NULL);
+static DEVICE_ATTR(update_fw, 0664, NULL, qt602240_update_fw_store);
+
+static struct attribute *qt602240_attrs[] = {
+ &dev_attr_object.attr,
+ &dev_attr_update_fw.attr,
+ NULL
+};
+
+static const struct attribute_group qt602240_attr_group = {
+ .attrs = qt602240_attrs,
+};
+
+static void qt602240_start(struct qt602240_data *data)
+{
+ /* Touch enable */
+ qt602240_write_object(data,
+ QT602240_TOUCH_MULTI, QT602240_TOUCH_CTRL, 0x83);
+}
+
+static void qt602240_stop(struct qt602240_data *data)
+{
+ /* Touch disable */
+ qt602240_write_object(data,
+ QT602240_TOUCH_MULTI, QT602240_TOUCH_CTRL, 0);
+}
+
+static int qt602240_input_open(struct input_dev *dev)
+{
+ struct qt602240_data *data = input_get_drvdata(dev);
+
+ qt602240_start(data);
+
+ return 0;
+}
+
+static void qt602240_input_close(struct input_dev *dev)
+{
+ struct qt602240_data *data = input_get_drvdata(dev);
+
+ qt602240_stop(data);
+}
+
+static int __devinit qt602240_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct qt602240_data *data;
+ struct input_dev *input_dev;
+ int error;
+
+ if (!client->dev.platform_data)
+ return -EINVAL;
+
+ data = kzalloc(sizeof(struct qt602240_data), GFP_KERNEL);
+ input_dev = input_allocate_device();
+ if (!data || !input_dev) {
+ dev_err(&client->dev, "Failed to allocate memory\n");
+ error = -ENOMEM;
+ goto err_free_mem;
+ }
+
+ input_dev->name = "AT42QT602240/ATMXT224 Touchscreen";
+ input_dev->id.bustype = BUS_I2C;
+ input_dev->dev.parent = &client->dev;
+ input_dev->open = qt602240_input_open;
+ input_dev->close = qt602240_input_close;
+
+ __set_bit(EV_ABS, input_dev->evbit);
+ __set_bit(EV_KEY, input_dev->evbit);
+ __set_bit(BTN_TOUCH, input_dev->keybit);
+
+ /* For single touch */
+ input_set_abs_params(input_dev, ABS_X,
+ 0, QT602240_MAX_XC, 0, 0);
+ input_set_abs_params(input_dev, ABS_Y,
+ 0, QT602240_MAX_YC, 0, 0);
+
+ /* For multi touch */
+ input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR,
+ 0, QT602240_MAX_AREA, 0, 0);
+ input_set_abs_params(input_dev, ABS_MT_POSITION_X,
+ 0, QT602240_MAX_XC, 0, 0);
+ input_set_abs_params(input_dev, ABS_MT_POSITION_Y,
+ 0, QT602240_MAX_YC, 0, 0);
+
+ input_set_drvdata(input_dev, data);
+
+ data->client = client;
+ data->input_dev = input_dev;
+ data->pdata = client->dev.platform_data;
+ data->irq = client->irq;
+
+ i2c_set_clientdata(client, data);
+
+ error = qt602240_initialize(data);
+ if (error)
+ goto err_free_object;
+
+ error = request_threaded_irq(client->irq, NULL, qt602240_interrupt,
+ IRQF_TRIGGER_FALLING, client->dev.driver->name, data);
+ if (error) {
+ dev_err(&client->dev, "Failed to register interrupt\n");
+ goto err_free_object;
+ }
+
+ error = input_register_device(input_dev);
+ if (error)
+ goto err_free_irq;
+
+ error = sysfs_create_group(&client->dev.kobj, &qt602240_attr_group);
+ if (error)
+ goto err_unregister_device;
+
+ return 0;
+
+err_unregister_device:
+ input_unregister_device(input_dev);
+ input_dev = NULL;
+err_free_irq:
+ free_irq(client->irq, data);
+err_free_object:
+ kfree(data->object_table);
+err_free_mem:
+ input_free_device(input_dev);
+ kfree(data);
+ return error;
+}
+
+static int __devexit qt602240_remove(struct i2c_client *client)
+{
+ struct qt602240_data *data = i2c_get_clientdata(client);
+
+ sysfs_remove_group(&client->dev.kobj, &qt602240_attr_group);
+ free_irq(data->irq, data);
+ input_unregister_device(data->input_dev);
+ kfree(data->object_table);
+ kfree(data);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int qt602240_suspend(struct i2c_client *client, pm_message_t mesg)
+{
+ struct qt602240_data *data = i2c_get_clientdata(client);
+ struct input_dev *input_dev = data->input_dev;
+
+ mutex_lock(&input_dev->mutex);
+
+ if (input_dev->users)
+ qt602240_stop(data);
+
+ mutex_unlock(&input_dev->mutex);
+
+ return 0;
+}
+
+static int qt602240_resume(struct i2c_client *client)
+{
+ struct qt602240_data *data = i2c_get_clientdata(client);
+ struct input_dev *input_dev = data->input_dev;
+
+ /* Soft reset */
+ qt602240_write_object(data, QT602240_GEN_COMMAND,
+ QT602240_COMMAND_RESET, 1);
+
+ msleep(QT602240_RESET_TIME);
+
+ mutex_lock(&input_dev->mutex);
+
+ if (input_dev->users)
+ qt602240_start(data);
+
+ mutex_unlock(&input_dev->mutex);
+
+ return 0;
+}
+#else
+#define qt602240_suspend NULL
+#define qt602240_resume NULL
+#endif
+
+static const struct i2c_device_id qt602240_id[] = {
+ { "qt602240_ts", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, qt602240_id);
+
+static struct i2c_driver qt602240_driver = {
+ .driver = {
+ .name = "qt602240_ts",
+ .owner = THIS_MODULE,
+ },
+ .probe = qt602240_probe,
+ .remove = __devexit_p(qt602240_remove),
+ .suspend = qt602240_suspend,
+ .resume = qt602240_resume,
+ .id_table = qt602240_id,
+};
+
+static int __init qt602240_init(void)
+{
+ return i2c_add_driver(&qt602240_driver);
+}
+
+static void __exit qt602240_exit(void)
+{
+ i2c_del_driver(&qt602240_driver);
+}
+
+module_init(qt602240_init);
+module_exit(qt602240_exit);
+
+/* Module information */
+MODULE_AUTHOR("Joonyoung Shim <jy0922.shim@samsung.com>");
+MODULE_DESCRIPTION("AT42QT602240/ATMXT224 Touchscreen driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/input/touchscreen/tps6507x-ts.c b/drivers/input/touchscreen/tps6507x-ts.c
index 5b70a1419b4..a644d18c04d 100644
--- a/drivers/input/touchscreen/tps6507x-ts.c
+++ b/drivers/input/touchscreen/tps6507x-ts.c
@@ -355,9 +355,6 @@ static int __devexit tps6507x_ts_remove(struct platform_device *pdev)
struct tps6507x_ts *tsc = tps6507x_dev->ts;
struct input_dev *input_dev = tsc->input_dev;
- if (!tsc)
- return 0;
-
cancel_delayed_work_sync(&tsc->work);
destroy_workqueue(tsc->wq);
diff --git a/drivers/input/touchscreen/usbtouchscreen.c b/drivers/input/touchscreen/usbtouchscreen.c
index 567d57215c2..f45f80f6d33 100644
--- a/drivers/input/touchscreen/usbtouchscreen.c
+++ b/drivers/input/touchscreen/usbtouchscreen.c
@@ -95,6 +95,7 @@ struct usbtouch_device_info {
int (*get_pkt_len) (unsigned char *pkt, int len);
int (*read_data) (struct usbtouch_usb *usbtouch, unsigned char *pkt);
+ int (*alloc) (struct usbtouch_usb *usbtouch);
int (*init) (struct usbtouch_usb *usbtouch);
void (*exit) (struct usbtouch_usb *usbtouch);
};
@@ -135,7 +136,7 @@ enum {
DEVTYPE_JASTEC,
DEVTYPE_E2I,
DEVTYPE_ZYTRONIC,
- DEVTYPE_TC5UH,
+ DEVTYPE_TC45USB,
DEVTYPE_NEXIO,
};
@@ -222,8 +223,11 @@ static const struct usb_device_id usbtouch_devices[] = {
{USB_DEVICE(0x14c8, 0x0003), .driver_info = DEVTYPE_ZYTRONIC},
#endif
-#ifdef CONFIG_TOUCHSCREEN_USB_ETT_TC5UH
- {USB_DEVICE(0x0664, 0x0309), .driver_info = DEVTYPE_TC5UH},
+#ifdef CONFIG_TOUCHSCREEN_USB_ETT_TC45USB
+ /* TC5UH */
+ {USB_DEVICE(0x0664, 0x0309), .driver_info = DEVTYPE_TC45USB},
+ /* TC4UM */
+ {USB_DEVICE(0x0664, 0x0306), .driver_info = DEVTYPE_TC45USB},
#endif
#ifdef CONFIG_TOUCHSCREEN_USB_NEXIO
@@ -507,7 +511,7 @@ static int dmc_tsc10_init(struct usbtouch_usb *usbtouch)
int ret = -ENOMEM;
unsigned char *buf;
- buf = kmalloc(2, GFP_KERNEL);
+ buf = kmalloc(2, GFP_NOIO);
if (!buf)
goto err_nobuf;
/* reset */
@@ -574,10 +578,10 @@ static int irtouch_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
#endif
/*****************************************************************************
- * ET&T TC5UH part
+ * ET&T TC5UH/TC4UM part
*/
-#ifdef CONFIG_TOUCHSCREEN_USB_ETT_TC5UH
-static int tc5uh_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
+#ifdef CONFIG_TOUCHSCREEN_USB_ETT_TC45USB
+static int tc45usb_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
{
dev->x = ((pkt[2] & 0x0F) << 8) | pkt[1];
dev->y = ((pkt[4] & 0x0F) << 8) | pkt[3];
@@ -732,11 +736,43 @@ static void nexio_ack_complete(struct urb *urb)
{
}
+static int nexio_alloc(struct usbtouch_usb *usbtouch)
+{
+ struct nexio_priv *priv;
+ int ret = -ENOMEM;
+
+ usbtouch->priv = kmalloc(sizeof(struct nexio_priv), GFP_KERNEL);
+ if (!usbtouch->priv)
+ goto out_buf;
+
+ priv = usbtouch->priv;
+
+ priv->ack_buf = kmemdup(nexio_ack_pkt, sizeof(nexio_ack_pkt),
+ GFP_KERNEL);
+ if (!priv->ack_buf)
+ goto err_priv;
+
+ priv->ack = usb_alloc_urb(0, GFP_KERNEL);
+ if (!priv->ack) {
+ dbg("%s - usb_alloc_urb failed: usbtouch->ack", __func__);
+ goto err_ack_buf;
+ }
+
+ return 0;
+
+err_ack_buf:
+ kfree(priv->ack_buf);
+err_priv:
+ kfree(priv);
+out_buf:
+ return ret;
+}
+
static int nexio_init(struct usbtouch_usb *usbtouch)
{
struct usb_device *dev = interface_to_usbdev(usbtouch->interface);
struct usb_host_interface *interface = usbtouch->interface->cur_altsetting;
- struct nexio_priv *priv;
+ struct nexio_priv *priv = usbtouch->priv;
int ret = -ENOMEM;
int actual_len, i;
unsigned char *buf;
@@ -755,7 +791,7 @@ static int nexio_init(struct usbtouch_usb *usbtouch)
if (!input_ep || !output_ep)
return -ENXIO;
- buf = kmalloc(NEXIO_BUFSIZE, GFP_KERNEL);
+ buf = kmalloc(NEXIO_BUFSIZE, GFP_NOIO);
if (!buf)
goto out_buf;
@@ -787,11 +823,11 @@ static int nexio_init(struct usbtouch_usb *usbtouch)
switch (buf[0]) {
case 0x83: /* firmware version */
if (!firmware_ver)
- firmware_ver = kstrdup(&buf[2], GFP_KERNEL);
+ firmware_ver = kstrdup(&buf[2], GFP_NOIO);
break;
case 0x84: /* device name */
if (!device_name)
- device_name = kstrdup(&buf[2], GFP_KERNEL);
+ device_name = kstrdup(&buf[2], GFP_NOIO);
break;
}
}
@@ -802,36 +838,11 @@ static int nexio_init(struct usbtouch_usb *usbtouch)
kfree(firmware_ver);
kfree(device_name);
- /* prepare ACK URB */
- ret = -ENOMEM;
-
- usbtouch->priv = kmalloc(sizeof(struct nexio_priv), GFP_KERNEL);
- if (!usbtouch->priv)
- goto out_buf;
-
- priv = usbtouch->priv;
-
- priv->ack_buf = kmemdup(nexio_ack_pkt, sizeof(nexio_ack_pkt),
- GFP_KERNEL);
- if (!priv->ack_buf)
- goto err_priv;
-
- priv->ack = usb_alloc_urb(0, GFP_KERNEL);
- if (!priv->ack) {
- dbg("%s - usb_alloc_urb failed: usbtouch->ack", __func__);
- goto err_ack_buf;
- }
-
usb_fill_bulk_urb(priv->ack, dev, usb_sndbulkpipe(dev, output_ep),
priv->ack_buf, sizeof(nexio_ack_pkt),
nexio_ack_complete, usbtouch);
ret = 0;
- goto out_buf;
-err_ack_buf:
- kfree(priv->ack_buf);
-err_priv:
- kfree(priv);
out_buf:
kfree(buf);
return ret;
@@ -849,29 +860,32 @@ static void nexio_exit(struct usbtouch_usb *usbtouch)
static int nexio_read_data(struct usbtouch_usb *usbtouch, unsigned char *pkt)
{
- int x, y, begin_x, begin_y, end_x, end_y, w, h, ret;
struct nexio_touch_packet *packet = (void *) pkt;
struct nexio_priv *priv = usbtouch->priv;
+ unsigned int data_len = be16_to_cpu(packet->data_len);
+ unsigned int x_len = be16_to_cpu(packet->x_len);
+ unsigned int y_len = be16_to_cpu(packet->y_len);
+ int x, y, begin_x, begin_y, end_x, end_y, w, h, ret;
/* got touch data? */
if ((pkt[0] & 0xe0) != 0xe0)
return 0;
- if (be16_to_cpu(packet->data_len) > 0xff)
- packet->data_len = cpu_to_be16(be16_to_cpu(packet->data_len) - 0x100);
- if (be16_to_cpu(packet->x_len) > 0xff)
- packet->x_len = cpu_to_be16(be16_to_cpu(packet->x_len) - 0x80);
+ if (data_len > 0xff)
+ data_len -= 0x100;
+ if (x_len > 0xff)
+ x_len -= 0x80;
/* send ACK */
ret = usb_submit_urb(priv->ack, GFP_ATOMIC);
if (!usbtouch->type->max_xc) {
- usbtouch->type->max_xc = 2 * be16_to_cpu(packet->x_len);
- input_set_abs_params(usbtouch->input, ABS_X, 0,
- 2 * be16_to_cpu(packet->x_len), 0, 0);
- usbtouch->type->max_yc = 2 * be16_to_cpu(packet->y_len);
- input_set_abs_params(usbtouch->input, ABS_Y, 0,
- 2 * be16_to_cpu(packet->y_len), 0, 0);
+ usbtouch->type->max_xc = 2 * x_len;
+ input_set_abs_params(usbtouch->input, ABS_X,
+ 0, usbtouch->type->max_xc, 0, 0);
+ usbtouch->type->max_yc = 2 * y_len;
+ input_set_abs_params(usbtouch->input, ABS_Y,
+ 0, usbtouch->type->max_yc, 0, 0);
}
/*
* The device reports state of IR sensors on X and Y axes.
@@ -881,22 +895,21 @@ static int nexio_read_data(struct usbtouch_usb *usbtouch, unsigned char *pkt)
* it's disabled (and untested) here as there's no X driver for that.
*/
begin_x = end_x = begin_y = end_y = -1;
- for (x = 0; x < be16_to_cpu(packet->x_len); x++) {
+ for (x = 0; x < x_len; x++) {
if (begin_x == -1 && packet->data[x] > NEXIO_THRESHOLD) {
begin_x = x;
continue;
}
if (end_x == -1 && begin_x != -1 && packet->data[x] < NEXIO_THRESHOLD) {
end_x = x - 1;
- for (y = be16_to_cpu(packet->x_len);
- y < be16_to_cpu(packet->data_len); y++) {
+ for (y = x_len; y < data_len; y++) {
if (begin_y == -1 && packet->data[y] > NEXIO_THRESHOLD) {
- begin_y = y - be16_to_cpu(packet->x_len);
+ begin_y = y - x_len;
continue;
}
if (end_y == -1 &&
begin_y != -1 && packet->data[y] < NEXIO_THRESHOLD) {
- end_y = y - 1 - be16_to_cpu(packet->x_len);
+ end_y = y - 1 - x_len;
w = end_x - begin_x;
h = end_y - begin_y;
#if 0
@@ -1104,14 +1117,14 @@ static struct usbtouch_device_info usbtouch_dev_info[] = {
},
#endif
-#ifdef CONFIG_TOUCHSCREEN_USB_ETT_TC5UH
- [DEVTYPE_TC5UH] = {
+#ifdef CONFIG_TOUCHSCREEN_USB_ETT_TC45USB
+ [DEVTYPE_TC45USB] = {
.min_xc = 0x0,
.max_xc = 0x0fff,
.min_yc = 0x0,
.max_yc = 0x0fff,
.rept_size = 5,
- .read_data = tc5uh_read_data,
+ .read_data = tc45usb_read_data,
},
#endif
@@ -1120,6 +1133,7 @@ static struct usbtouch_device_info usbtouch_dev_info[] = {
.rept_size = 1024,
.irq_always = true,
.read_data = nexio_read_data,
+ .alloc = nexio_alloc,
.init = nexio_init,
.exit = nexio_exit,
},
@@ -1263,6 +1277,7 @@ static void usbtouch_irq(struct urb *urb)
usbtouch->type->process_pkt(usbtouch, usbtouch->data, urb->actual_length);
exit:
+ usb_mark_last_busy(interface_to_usbdev(usbtouch->interface));
retval = usb_submit_urb(urb, GFP_ATOMIC);
if (retval)
err("%s - usb_submit_urb failed with result: %d",
@@ -1272,25 +1287,89 @@ exit:
static int usbtouch_open(struct input_dev *input)
{
struct usbtouch_usb *usbtouch = input_get_drvdata(input);
+ int r;
usbtouch->irq->dev = interface_to_usbdev(usbtouch->interface);
+ r = usb_autopm_get_interface(usbtouch->interface) ? -EIO : 0;
+ if (r < 0)
+ goto out;
+
if (!usbtouch->type->irq_always) {
- if (usb_submit_urb(usbtouch->irq, GFP_KERNEL))
- return -EIO;
+ if (usb_submit_urb(usbtouch->irq, GFP_KERNEL)) {
+ r = -EIO;
+ goto out_put;
+ }
}
- return 0;
+ usbtouch->interface->needs_remote_wakeup = 1;
+out_put:
+ usb_autopm_put_interface(usbtouch->interface);
+out:
+ return r;
}
static void usbtouch_close(struct input_dev *input)
{
struct usbtouch_usb *usbtouch = input_get_drvdata(input);
+ int r;
if (!usbtouch->type->irq_always)
usb_kill_urb(usbtouch->irq);
+ r = usb_autopm_get_interface(usbtouch->interface);
+ usbtouch->interface->needs_remote_wakeup = 0;
+ if (!r)
+ usb_autopm_put_interface(usbtouch->interface);
}
+static int usbtouch_suspend
+(struct usb_interface *intf, pm_message_t message)
+{
+ struct usbtouch_usb *usbtouch = usb_get_intfdata(intf);
+
+ usb_kill_urb(usbtouch->irq);
+
+ return 0;
+}
+
+static int usbtouch_resume(struct usb_interface *intf)
+{
+ struct usbtouch_usb *usbtouch = usb_get_intfdata(intf);
+ struct input_dev *input = usbtouch->input;
+ int result = 0;
+
+ mutex_lock(&input->mutex);
+ if (input->users || usbtouch->type->irq_always)
+ result = usb_submit_urb(usbtouch->irq, GFP_NOIO);
+ mutex_unlock(&input->mutex);
+
+ return result;
+}
+
+static int usbtouch_reset_resume(struct usb_interface *intf)
+{
+ struct usbtouch_usb *usbtouch = usb_get_intfdata(intf);
+ struct input_dev *input = usbtouch->input;
+ int err = 0;
+
+ /* reinit the device */
+ if (usbtouch->type->init) {
+ err = usbtouch->type->init(usbtouch);
+ if (err) {
+ dbg("%s - type->init() failed, err: %d",
+ __func__, err);
+ return err;
+ }
+ }
+
+ /* restart IO if needed */
+ mutex_lock(&input->mutex);
+ if (input->users)
+ err = usb_submit_urb(usbtouch->irq, GFP_NOIO);
+ mutex_unlock(&input->mutex);
+
+ return err;
+}
static void usbtouch_free_buffers(struct usb_device *udev,
struct usbtouch_usb *usbtouch)
@@ -1411,12 +1490,21 @@ static int usbtouch_probe(struct usb_interface *intf,
usbtouch->irq->transfer_dma = usbtouch->data_dma;
usbtouch->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
- /* device specific init */
+ /* device specific allocations */
+ if (type->alloc) {
+ err = type->alloc(usbtouch);
+ if (err) {
+ dbg("%s - type->alloc() failed, err: %d", __func__, err);
+ goto out_free_urb;
+ }
+ }
+
+ /* device specific initialisation*/
if (type->init) {
err = type->init(usbtouch);
if (err) {
dbg("%s - type->init() failed, err: %d", __func__, err);
- goto out_free_urb;
+ goto out_do_exit;
}
}
@@ -1429,8 +1517,11 @@ static int usbtouch_probe(struct usb_interface *intf,
usb_set_intfdata(intf, usbtouch);
if (usbtouch->type->irq_always) {
+ /* this can't fail */
+ usb_autopm_get_interface(intf);
err = usb_submit_urb(usbtouch->irq, GFP_KERNEL);
if (err) {
+ usb_autopm_put_interface(intf);
err("%s - usb_submit_urb failed with result: %d",
__func__, err);
goto out_unregister_input;
@@ -1481,7 +1572,11 @@ static struct usb_driver usbtouch_driver = {
.name = "usbtouchscreen",
.probe = usbtouch_probe,
.disconnect = usbtouch_disconnect,
+ .suspend = usbtouch_suspend,
+ .resume = usbtouch_resume,
+ .reset_resume = usbtouch_reset_resume,
.id_table = usbtouch_devices,
+ .supports_autosuspend = 1,
};
static int __init usbtouch_init(void)
diff --git a/drivers/input/xen-kbdfront.c b/drivers/input/xen-kbdfront.c
index e14081675bb..ebb11907d40 100644
--- a/drivers/input/xen-kbdfront.c
+++ b/drivers/input/xen-kbdfront.c
@@ -339,7 +339,7 @@ static struct xenbus_driver xenkbd_driver = {
static int __init xenkbd_init(void)
{
- if (!xen_domain())
+ if (!xen_pv_domain())
return -ENODEV;
/* Nothing to do if running in dom0. */
diff --git a/drivers/isdn/capi/capi.c b/drivers/isdn/capi/capi.c
index 0cabe31f26d..f80a7c48a35 100644
--- a/drivers/isdn/capi/capi.c
+++ b/drivers/isdn/capi/capi.c
@@ -20,7 +20,6 @@
#include <linux/signal.h>
#include <linux/mutex.h>
#include <linux/mm.h>
-#include <linux/smp_lock.h>
#include <linux/timer.h>
#include <linux/wait.h>
#include <linux/tty.h>
@@ -50,6 +49,7 @@ MODULE_LICENSE("GPL");
/* -------- driver information -------------------------------------- */
+static DEFINE_MUTEX(capi_mutex);
static struct class *capi_class;
static int capi_major = 68; /* allocated */
@@ -691,7 +691,7 @@ unlock_out:
static ssize_t
capi_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
{
- struct capidev *cdev = (struct capidev *)file->private_data;
+ struct capidev *cdev = file->private_data;
struct sk_buff *skb;
size_t copied;
int err;
@@ -726,7 +726,7 @@ capi_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
static ssize_t
capi_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
{
- struct capidev *cdev = (struct capidev *)file->private_data;
+ struct capidev *cdev = file->private_data;
struct sk_buff *skb;
u16 mlen;
@@ -773,7 +773,7 @@ capi_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos
static unsigned int
capi_poll(struct file *file, poll_table * wait)
{
- struct capidev *cdev = (struct capidev *)file->private_data;
+ struct capidev *cdev = file->private_data;
unsigned int mask = 0;
if (!cdev->ap.applid)
@@ -985,9 +985,9 @@ capi_unlocked_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
int ret;
- lock_kernel();
+ mutex_lock(&capi_mutex);
ret = capi_ioctl(file, cmd, arg);
- unlock_kernel();
+ mutex_unlock(&capi_mutex);
return ret;
}
diff --git a/drivers/isdn/capi/capidrv.c b/drivers/isdn/capi/capidrv.c
index bf55ed5f38e..2978bdaa6b8 100644
--- a/drivers/isdn/capi/capidrv.c
+++ b/drivers/isdn/capi/capidrv.c
@@ -1450,12 +1450,9 @@ static void handle_dtrace_data(capidrv_contr *card,
}
for (p = data, end = data+len; p < end; p++) {
- u8 w;
PUTBYTE_TO_STATUS(card, ' ');
- w = (*p >> 4) & 0xf;
- PUTBYTE_TO_STATUS(card, (w < 10) ? '0'+w : 'A'-10+w);
- w = *p & 0xf;
- PUTBYTE_TO_STATUS(card, (w < 10) ? '0'+w : 'A'-10+w);
+ PUTBYTE_TO_STATUS(card, hex_asc_hi(*p));
+ PUTBYTE_TO_STATUS(card, hex_asc_lo(*p));
}
PUTBYTE_TO_STATUS(card, '\n');
diff --git a/drivers/isdn/divert/divert_procfs.c b/drivers/isdn/divert/divert_procfs.c
index c53e2417e7d..33ec9e46777 100644
--- a/drivers/isdn/divert/divert_procfs.c
+++ b/drivers/isdn/divert/divert_procfs.c
@@ -20,7 +20,7 @@
#include <linux/sched.h>
#include <linux/isdnif.h>
#include <net/net_namespace.h>
-#include <linux/smp_lock.h>
+#include <linux/mutex.h>
#include "isdn_divert.h"
@@ -28,6 +28,7 @@
/* Variables for interface queue */
/*********************************/
ulong if_used = 0; /* number of interface users */
+static DEFINE_MUTEX(isdn_divert_mutex);
static struct divert_info *divert_info_head = NULL; /* head of queue */
static struct divert_info *divert_info_tail = NULL; /* pointer to last entry */
static DEFINE_SPINLOCK(divert_info_lock);/* lock for queue */
@@ -261,9 +262,9 @@ static long isdn_divert_ioctl(struct file *file, uint cmd, ulong arg)
{
long ret;
- lock_kernel();
+ mutex_lock(&isdn_divert_mutex);
ret = isdn_divert_ioctl_unlocked(file, cmd, arg);
- unlock_kernel();
+ mutex_unlock(&isdn_divert_mutex);
return ret;
}
diff --git a/drivers/isdn/gigaset/Kconfig b/drivers/isdn/gigaset/Kconfig
index dcefedc7044..b18a92c3218 100644
--- a/drivers/isdn/gigaset/Kconfig
+++ b/drivers/isdn/gigaset/Kconfig
@@ -17,8 +17,7 @@ menuconfig ISDN_DRV_GIGASET
if ISDN_DRV_GIGASET
config GIGASET_CAPI
- bool "Gigaset CAPI support (EXPERIMENTAL)"
- depends on EXPERIMENTAL
+ bool "Gigaset CAPI support"
depends on ISDN_CAPI='y'||(ISDN_CAPI='m'&&ISDN_DRV_GIGASET='m')
default ISDN_I4L='n'
help
@@ -27,6 +26,7 @@ config GIGASET_CAPI
subsystem you'll have to enable the capidrv glue driver.
(select ISDN_CAPI_CAPIDRV.)
Say N to build the old native ISDN4Linux variant.
+ If unsure, say Y.
config GIGASET_I4L
bool
diff --git a/drivers/isdn/gigaset/bas-gigaset.c b/drivers/isdn/gigaset/bas-gigaset.c
index 47a5ffec55a..0ded3640b92 100644
--- a/drivers/isdn/gigaset/bas-gigaset.c
+++ b/drivers/isdn/gigaset/bas-gigaset.c
@@ -1188,24 +1188,6 @@ static void write_iso_tasklet(unsigned long data)
break;
}
}
-#ifdef CONFIG_GIGASET_DEBUG
- /* check assumption on remaining frames */
- for (; i < BAS_NUMFRAMES; i++) {
- ifd = &urb->iso_frame_desc[i];
- if (ifd->status != -EINPROGRESS
- || ifd->actual_length != 0) {
- dev_warn(cs->dev,
- "isochronous write: frame %d: %s, "
- "%d of %d bytes sent\n",
- i, get_usb_statmsg(ifd->status),
- ifd->actual_length, ifd->length);
- offset = (ifd->offset +
- ifd->actual_length)
- % BAS_OUTBUFSIZE;
- break;
- }
- }
-#endif
break;
case -EPIPE: /* stall - probably underrun */
dev_err(cs->dev, "isochronous write stalled\n");
@@ -1913,65 +1895,41 @@ static int start_cbsend(struct cardstate *cs)
* USB transmission is started if necessary.
* parameters:
* cs controller state structure
- * buf command string to send
- * len number of bytes to send (max. IF_WRITEBUF)
- * wake_tasklet tasklet to run when transmission is completed
- * (NULL if none)
+ * cb command buffer structure
* return value:
* number of bytes queued on success
* error code < 0 on error
*/
-static int gigaset_write_cmd(struct cardstate *cs,
- const unsigned char *buf, int len,
- struct tasklet_struct *wake_tasklet)
+static int gigaset_write_cmd(struct cardstate *cs, struct cmdbuf_t *cb)
{
- struct cmdbuf_t *cb;
unsigned long flags;
int rc;
gigaset_dbg_buffer(cs->mstate != MS_LOCKED ?
DEBUG_TRANSCMD : DEBUG_LOCKCMD,
- "CMD Transmit", len, buf);
-
- if (len <= 0) {
- /* nothing to do */
- rc = 0;
- goto notqueued;
- }
+ "CMD Transmit", cb->len, cb->buf);
/* translate "+++" escape sequence sent as a single separate command
* into "close AT channel" command for error recovery
* The next command will reopen the AT channel automatically.
*/
- if (len == 3 && !memcmp(buf, "+++", 3)) {
+ if (cb->len == 3 && !memcmp(cb->buf, "+++", 3)) {
+ kfree(cb);
rc = req_submit(cs->bcs, HD_CLOSE_ATCHANNEL, 0, BAS_TIMEOUT);
- goto notqueued;
+ if (cb->wake_tasklet)
+ tasklet_schedule(cb->wake_tasklet);
+ return rc < 0 ? rc : cb->len;
}
- if (len > IF_WRITEBUF)
- len = IF_WRITEBUF;
- cb = kmalloc(sizeof(struct cmdbuf_t) + len, GFP_ATOMIC);
- if (!cb) {
- dev_err(cs->dev, "%s: out of memory\n", __func__);
- rc = -ENOMEM;
- goto notqueued;
- }
-
- memcpy(cb->buf, buf, len);
- cb->len = len;
- cb->offset = 0;
- cb->next = NULL;
- cb->wake_tasklet = wake_tasklet;
-
spin_lock_irqsave(&cs->cmdlock, flags);
cb->prev = cs->lastcmdbuf;
if (cs->lastcmdbuf)
cs->lastcmdbuf->next = cb;
else {
cs->cmdbuf = cb;
- cs->curlen = len;
+ cs->curlen = cb->len;
}
- cs->cmdbytes += len;
+ cs->cmdbytes += cb->len;
cs->lastcmdbuf = cb;
spin_unlock_irqrestore(&cs->cmdlock, flags);
@@ -1988,12 +1946,7 @@ static int gigaset_write_cmd(struct cardstate *cs,
}
rc = start_cbsend(cs);
spin_unlock_irqrestore(&cs->lock, flags);
- return rc < 0 ? rc : len;
-
-notqueued: /* request handled without queuing */
- if (wake_tasklet)
- tasklet_schedule(wake_tasklet);
- return rc;
+ return rc < 0 ? rc : cb->len;
}
/* gigaset_write_room
diff --git a/drivers/isdn/gigaset/capi.c b/drivers/isdn/gigaset/capi.c
index 6fbe8999c41..e5ea344a551 100644
--- a/drivers/isdn/gigaset/capi.c
+++ b/drivers/isdn/gigaset/capi.c
@@ -45,6 +45,7 @@
#define CAPI_FACILITY_LI 0x0005
#define CAPI_SUPPSVC_GETSUPPORTED 0x0000
+#define CAPI_SUPPSVC_LISTEN 0x0001
/* missing from capiutil.h */
#define CAPIMSG_PLCI_PART(m) CAPIMSG_U8(m, 9)
@@ -270,9 +271,13 @@ static inline void dump_rawmsg(enum debuglevel level, const char *tag,
kfree(dbgline);
if (CAPIMSG_COMMAND(data) == CAPI_DATA_B3 &&
(CAPIMSG_SUBCOMMAND(data) == CAPI_REQ ||
- CAPIMSG_SUBCOMMAND(data) == CAPI_IND) &&
- CAPIMSG_DATALEN(data) > 0) {
+ CAPIMSG_SUBCOMMAND(data) == CAPI_IND)) {
l = CAPIMSG_DATALEN(data);
+ gig_dbg(level, " DataLength=%d", l);
+ if (l <= 0 || !(gigaset_debuglevel & DEBUG_LLDATA))
+ return;
+ if (l > 64)
+ l = 64; /* arbitrary limit */
dbgline = kmalloc(3*l, GFP_ATOMIC);
if (!dbgline)
return;
@@ -378,13 +383,13 @@ void gigaset_skb_sent(struct bc_state *bcs, struct sk_buff *dskb)
++bcs->trans_up;
if (!ap) {
- dev_err(cs->dev, "%s: no application\n", __func__);
+ gig_dbg(DEBUG_MCMD, "%s: application gone", __func__);
return;
}
/* don't send further B3 messages if disconnected */
if (bcs->apconnstate < APCONN_ACTIVE) {
- gig_dbg(DEBUG_LLDATA, "disconnected, discarding ack");
+ gig_dbg(DEBUG_MCMD, "%s: disconnected", __func__);
return;
}
@@ -422,13 +427,14 @@ void gigaset_skb_rcvd(struct bc_state *bcs, struct sk_buff *skb)
bcs->trans_down++;
if (!ap) {
- dev_err(cs->dev, "%s: no application\n", __func__);
+ gig_dbg(DEBUG_MCMD, "%s: application gone", __func__);
+ dev_kfree_skb_any(skb);
return;
}
/* don't send further B3 messages if disconnected */
if (bcs->apconnstate < APCONN_ACTIVE) {
- gig_dbg(DEBUG_LLDATA, "disconnected, discarding data");
+ gig_dbg(DEBUG_MCMD, "%s: disconnected", __func__);
dev_kfree_skb_any(skb);
return;
}
@@ -454,7 +460,7 @@ void gigaset_skb_rcvd(struct bc_state *bcs, struct sk_buff *skb)
/* Data64 parameter not present */
/* emit message */
- dump_rawmsg(DEBUG_LLDATA, "DATA_B3_IND", skb->data);
+ dump_rawmsg(DEBUG_MCMD, __func__, skb->data);
capi_ctr_handle_message(&iif->ctr, ap->id, skb);
}
EXPORT_SYMBOL_GPL(gigaset_skb_rcvd);
@@ -747,7 +753,7 @@ void gigaset_isdn_connD(struct bc_state *bcs)
ap = bcs->ap;
if (!ap) {
spin_unlock_irqrestore(&bcs->aplock, flags);
- dev_err(cs->dev, "%s: no application\n", __func__);
+ gig_dbg(DEBUG_CMD, "%s: application gone", __func__);
return;
}
if (bcs->apconnstate == APCONN_NONE) {
@@ -843,7 +849,7 @@ void gigaset_isdn_connB(struct bc_state *bcs)
ap = bcs->ap;
if (!ap) {
spin_unlock_irqrestore(&bcs->aplock, flags);
- dev_err(cs->dev, "%s: no application\n", __func__);
+ gig_dbg(DEBUG_CMD, "%s: application gone", __func__);
return;
}
if (!bcs->apconnstate) {
@@ -901,13 +907,12 @@ void gigaset_isdn_connB(struct bc_state *bcs)
*/
void gigaset_isdn_hupB(struct bc_state *bcs)
{
- struct cardstate *cs = bcs->cs;
struct gigaset_capi_appl *ap = bcs->ap;
/* ToDo: assure order of DISCONNECT_B3_IND and DISCONNECT_IND ? */
if (!ap) {
- dev_err(cs->dev, "%s: no application\n", __func__);
+ gig_dbg(DEBUG_CMD, "%s: application gone", __func__);
return;
}
@@ -978,6 +983,9 @@ static void gigaset_register_appl(struct capi_ctr *ctr, u16 appl,
struct cardstate *cs = ctr->driverdata;
struct gigaset_capi_appl *ap;
+ gig_dbg(DEBUG_CMD, "%s [%u] l3cnt=%u blkcnt=%u blklen=%u",
+ __func__, appl, rp->level3cnt, rp->datablkcnt, rp->datablklen);
+
list_for_each_entry(ap, &iif->appls, ctrlist)
if (ap->id == appl) {
dev_notice(cs->dev,
@@ -1062,6 +1070,8 @@ static void gigaset_release_appl(struct capi_ctr *ctr, u16 appl)
struct gigaset_capi_appl *ap, *tmp;
unsigned ch;
+ gig_dbg(DEBUG_CMD, "%s [%u]", __func__, appl);
+
list_for_each_entry_safe(ap, tmp, &iif->appls, ctrlist)
if (ap->id == appl) {
/* remove from any channels */
@@ -1142,7 +1152,7 @@ static void do_facility_req(struct gigaset_capi_ctr *iif,
case CAPI_FACILITY_SUPPSVC:
/* decode Function parameter */
pparam = cmsg->FacilityRequestParameter;
- if (pparam == NULL || *pparam < 2) {
+ if (pparam == NULL || pparam[0] < 2) {
dev_notice(cs->dev, "%s: %s missing\n", "FACILITY_REQ",
"Facility Request Parameter");
send_conf(iif, ap, skb, CapiIllMessageParmCoding);
@@ -1159,8 +1169,32 @@ static void do_facility_req(struct gigaset_capi_ctr *iif,
/* Supported Services: none */
capimsg_setu32(confparam, 6, 0);
break;
+ case CAPI_SUPPSVC_LISTEN:
+ if (pparam[0] < 7 || pparam[3] < 4) {
+ dev_notice(cs->dev, "%s: %s missing\n",
+ "FACILITY_REQ", "Notification Mask");
+ send_conf(iif, ap, skb,
+ CapiIllMessageParmCoding);
+ return;
+ }
+ if (CAPIMSG_U32(pparam, 4) != 0) {
+ dev_notice(cs->dev,
+ "%s: unsupported supplementary service notification mask 0x%x\n",
+ "FACILITY_REQ", CAPIMSG_U32(pparam, 4));
+ info = CapiFacilitySpecificFunctionNotSupported;
+ confparam[3] = 2; /* length */
+ capimsg_setu16(confparam, 4,
+ CapiSupplementaryServiceNotSupported);
+ }
+ info = CapiSuccess;
+ confparam[3] = 2; /* length */
+ capimsg_setu16(confparam, 4, CapiSuccess);
+ break;
/* ToDo: add supported services */
default:
+ dev_notice(cs->dev,
+ "%s: unsupported supplementary service function 0x%04x\n",
+ "FACILITY_REQ", function);
info = CapiFacilitySpecificFunctionNotSupported;
/* Supplementary Service specific parameter */
confparam[3] = 2; /* length */
@@ -1951,11 +1985,7 @@ static void do_data_b3_req(struct gigaset_capi_ctr *iif,
u16 handle = CAPIMSG_HANDLE_REQ(skb->data);
/* frequent message, avoid _cmsg overhead */
- dump_rawmsg(DEBUG_LLDATA, "DATA_B3_REQ", skb->data);
-
- gig_dbg(DEBUG_LLDATA,
- "Receiving data from LL (ch: %d, flg: %x, sz: %d|%d)",
- channel, flags, msglen, datalen);
+ dump_rawmsg(DEBUG_MCMD, __func__, skb->data);
/* check parameters */
if (channel == 0 || channel > cs->channels || ncci != 1) {
@@ -2064,7 +2094,7 @@ static void do_data_b3_resp(struct gigaset_capi_ctr *iif,
struct gigaset_capi_appl *ap,
struct sk_buff *skb)
{
- dump_rawmsg(DEBUG_LLDATA, __func__, skb->data);
+ dump_rawmsg(DEBUG_MCMD, __func__, skb->data);
dev_kfree_skb_any(skb);
}
diff --git a/drivers/isdn/gigaset/common.c b/drivers/isdn/gigaset/common.c
index 5d4befb8105..3ca561eccd9 100644
--- a/drivers/isdn/gigaset/common.c
+++ b/drivers/isdn/gigaset/common.c
@@ -791,8 +791,6 @@ struct cardstate *gigaset_initcs(struct gigaset_driver *drv, int channels,
spin_unlock_irqrestore(&cs->lock, flags);
setup_timer(&cs->timer, timer_tick, (unsigned long) cs);
cs->timer.expires = jiffies + msecs_to_jiffies(GIG_TICK);
- /* FIXME: can jiffies increase too much until the timer is added?
- * Same problem(?) with mod_timer() in timer_tick(). */
add_timer(&cs->timer);
gig_dbg(DEBUG_INIT, "cs initialized");
diff --git a/drivers/isdn/gigaset/ev-layer.c b/drivers/isdn/gigaset/ev-layer.c
index ceaef9a04a4..a14187605f5 100644
--- a/drivers/isdn/gigaset/ev-layer.c
+++ b/drivers/isdn/gigaset/ev-layer.c
@@ -35,53 +35,40 @@
#define RT_RING 2
#define RT_NUMBER 3
#define RT_STRING 4
-#define RT_HEX 5
#define RT_ZCAU 6
/* Possible ASCII responses */
#define RSP_OK 0
-#define RSP_BUSY 1
-#define RSP_CONNECT 2
+#define RSP_ERROR 1
#define RSP_ZGCI 3
#define RSP_RING 4
-#define RSP_ZAOC 5
-#define RSP_ZCSTR 6
-#define RSP_ZCFGT 7
-#define RSP_ZCFG 8
-#define RSP_ZCCR 9
-#define RSP_EMPTY 10
-#define RSP_ZLOG 11
-#define RSP_ZCAU 12
-#define RSP_ZMWI 13
-#define RSP_ZABINFO 14
-#define RSP_ZSMLSTCHG 15
+#define RSP_ZVLS 5
+#define RSP_ZCAU 6
+
+/* responses with values to store in at_state */
+/* - numeric */
#define RSP_VAR 100
#define RSP_ZSAU (RSP_VAR + VAR_ZSAU)
#define RSP_ZDLE (RSP_VAR + VAR_ZDLE)
-#define RSP_ZVLS (RSP_VAR + VAR_ZVLS)
#define RSP_ZCTP (RSP_VAR + VAR_ZCTP)
+/* - string */
#define RSP_STR (RSP_VAR + VAR_NUM)
#define RSP_NMBR (RSP_STR + STR_NMBR)
#define RSP_ZCPN (RSP_STR + STR_ZCPN)
#define RSP_ZCON (RSP_STR + STR_ZCON)
#define RSP_ZBC (RSP_STR + STR_ZBC)
#define RSP_ZHLC (RSP_STR + STR_ZHLC)
-#define RSP_ERROR -1 /* ERROR */
+
#define RSP_WRONG_CID -2 /* unknown cid in cmd */
-#define RSP_UNKNOWN -4 /* unknown response */
-#define RSP_FAIL -5 /* internal error */
#define RSP_INVAL -6 /* invalid response */
+#define RSP_NODEV -9 /* device not connected */
#define RSP_NONE -19
#define RSP_STRING -20
#define RSP_NULL -21
-#define RSP_RETRYFAIL -22
-#define RSP_RETRY -23
-#define RSP_SKIP -24
#define RSP_INIT -27
#define RSP_ANY -26
#define RSP_LAST -28
-#define RSP_NODEV -9
/* actions for process_response */
#define ACT_NOTHING 0
@@ -259,13 +246,6 @@ struct reply_t gigaset_tab_nocid[] =
/* misc. */
{RSP_ERROR, -1, -1, -1, -1, -1, {ACT_ERROR} },
-{RSP_ZCFGT, -1, -1, -1, -1, -1, {ACT_DEBUG} },
-{RSP_ZCFG, -1, -1, -1, -1, -1, {ACT_DEBUG} },
-{RSP_ZLOG, -1, -1, -1, -1, -1, {ACT_DEBUG} },
-{RSP_ZMWI, -1, -1, -1, -1, -1, {ACT_DEBUG} },
-{RSP_ZABINFO, -1, -1, -1, -1, -1, {ACT_DEBUG} },
-{RSP_ZSMLSTCHG, -1, -1, -1, -1, -1, {ACT_DEBUG} },
-
{RSP_ZCAU, -1, -1, -1, -1, -1, {ACT_ZCAU} },
{RSP_NONE, -1, -1, -1, -1, -1, {ACT_DEBUG} },
{RSP_ANY, -1, -1, -1, -1, -1, {ACT_WARN} },
@@ -361,10 +341,6 @@ struct reply_t gigaset_tab_cid[] =
/* misc. */
{RSP_ZCON, -1, -1, -1, -1, -1, {ACT_DEBUG} },
-{RSP_ZCCR, -1, -1, -1, -1, -1, {ACT_DEBUG} },
-{RSP_ZAOC, -1, -1, -1, -1, -1, {ACT_DEBUG} },
-{RSP_ZCSTR, -1, -1, -1, -1, -1, {ACT_DEBUG} },
-
{RSP_ZCAU, -1, -1, -1, -1, -1, {ACT_ZCAU} },
{RSP_NONE, -1, -1, -1, -1, -1, {ACT_DEBUG} },
{RSP_ANY, -1, -1, -1, -1, -1, {ACT_WARN} },
@@ -387,20 +363,11 @@ static const struct resp_type_t {
{"ZVLS", RSP_ZVLS, RT_NUMBER},
{"ZCTP", RSP_ZCTP, RT_NUMBER},
{"ZDLE", RSP_ZDLE, RT_NUMBER},
- {"ZCFGT", RSP_ZCFGT, RT_NUMBER},
- {"ZCCR", RSP_ZCCR, RT_NUMBER},
- {"ZMWI", RSP_ZMWI, RT_NUMBER},
{"ZHLC", RSP_ZHLC, RT_STRING},
{"ZBC", RSP_ZBC, RT_STRING},
{"NMBR", RSP_NMBR, RT_STRING},
{"ZCPN", RSP_ZCPN, RT_STRING},
{"ZCON", RSP_ZCON, RT_STRING},
- {"ZAOC", RSP_ZAOC, RT_STRING},
- {"ZCSTR", RSP_ZCSTR, RT_STRING},
- {"ZCFG", RSP_ZCFG, RT_HEX},
- {"ZLOG", RSP_ZLOG, RT_NOTHING},
- {"ZABINFO", RSP_ZABINFO, RT_NOTHING},
- {"ZSMLSTCHG", RSP_ZSMLSTCHG, RT_NOTHING},
{NULL, 0, 0}
};
@@ -418,64 +385,18 @@ static const struct zsau_resp_t {
{NULL, ZSAU_UNKNOWN}
};
-/*
- * Get integer from char-pointer
- */
-static int isdn_getnum(char *p)
-{
- int v = -1;
-
- gig_dbg(DEBUG_EVENT, "string: %s", p);
-
- while (*p >= '0' && *p <= '9')
- v = ((v < 0) ? 0 : (v * 10)) + (int) ((*p++) - '0');
- if (*p)
- v = -1; /* invalid Character */
- return v;
-}
-
-/*
- * Get integer from char-pointer
- */
-static int isdn_gethex(char *p)
-{
- int v = 0;
- int c;
-
- gig_dbg(DEBUG_EVENT, "string: %s", p);
-
- if (!*p)
- return -1;
-
- do {
- if (v > (INT_MAX - 15) / 16)
- return -1;
- c = *p;
- if (c >= '0' && c <= '9')
- c -= '0';
- else if (c >= 'a' && c <= 'f')
- c -= 'a' - 10;
- else if (c >= 'A' && c <= 'F')
- c -= 'A' - 10;
- else
- return -1;
- v = v * 16 + c;
- } while (*++p);
-
- return v;
-}
-
/* retrieve CID from parsed response
* returns 0 if no CID, -1 if invalid CID, or CID value 1..65535
*/
static int cid_of_response(char *s)
{
- int cid;
+ unsigned long cid;
+ int rc;
if (s[-1] != ';')
return 0; /* no CID separator */
- cid = isdn_getnum(s);
- if (cid < 0)
+ rc = strict_strtoul(s, 10, &cid);
+ if (rc)
return 0; /* CID not numeric */
if (cid < 1 || cid > 65535)
return -1; /* CID out of range */
@@ -588,10 +509,10 @@ void gigaset_handle_modem_response(struct cardstate *cs)
break;
if (!rt->response) {
- event->type = RSP_UNKNOWN;
- dev_warn(cs->dev,
- "unknown modem response: %s\n",
- argv[curarg]);
+ event->type = RSP_NONE;
+ gig_dbg(DEBUG_EVENT,
+ "unknown modem response: '%s'\n",
+ argv[curarg]);
break;
}
@@ -645,27 +566,27 @@ void gigaset_handle_modem_response(struct cardstate *cs)
case RT_ZCAU:
event->parameter = -1;
if (curarg + 1 < params) {
- i = isdn_gethex(argv[curarg]);
- j = isdn_gethex(argv[curarg + 1]);
- if (i >= 0 && i < 256 && j >= 0 && j < 256)
- event->parameter = (unsigned) i << 8
- | j;
- curarg += 2;
+ unsigned long type, value;
+
+ i = strict_strtoul(argv[curarg++], 16, &type);
+ j = strict_strtoul(argv[curarg++], 16, &value);
+
+ if (i == 0 && type < 256 &&
+ j == 0 && value < 256)
+ event->parameter = (type << 8) | value;
} else
curarg = params - 1;
break;
case RT_NUMBER:
- case RT_HEX:
+ event->parameter = -1;
if (curarg < params) {
- if (param_type == RT_HEX)
- event->parameter =
- isdn_gethex(argv[curarg]);
- else
- event->parameter =
- isdn_getnum(argv[curarg]);
- ++curarg;
- } else
- event->parameter = -1;
+ unsigned long res;
+ int rc;
+
+ rc = strict_strtoul(argv[curarg++], 10, &res);
+ if (rc == 0)
+ event->parameter = res;
+ }
gig_dbg(DEBUG_EVENT, "parameter==%d", event->parameter);
break;
}
@@ -797,48 +718,27 @@ static void schedule_init(struct cardstate *cs, int state)
static void send_command(struct cardstate *cs, const char *cmd, int cid,
int dle, gfp_t kmallocflags)
{
- size_t cmdlen, buflen;
- char *cmdpos, *cmdbuf, *cmdtail;
+ struct cmdbuf_t *cb;
+ size_t buflen;
- cmdlen = strlen(cmd);
- buflen = 11 + cmdlen;
- if (unlikely(buflen <= cmdlen)) {
- dev_err(cs->dev, "integer overflow in buflen\n");
+ buflen = strlen(cmd) + 12; /* DLE ( A T 1 2 3 4 5 <cmd> DLE ) \0 */
+ cb = kmalloc(sizeof(struct cmdbuf_t) + buflen, kmallocflags);
+ if (!cb) {
+ dev_err(cs->dev, "%s: out of memory\n", __func__);
return;
}
-
- cmdbuf = kmalloc(buflen, kmallocflags);
- if (unlikely(!cmdbuf)) {
- dev_err(cs->dev, "out of memory\n");
- return;
- }
-
- cmdpos = cmdbuf + 9;
- cmdtail = cmdpos + cmdlen;
- memcpy(cmdpos, cmd, cmdlen);
-
- if (cid > 0 && cid <= 65535) {
- do {
- *--cmdpos = '0' + cid % 10;
- cid /= 10;
- ++cmdlen;
- } while (cid);
- }
-
- cmdlen += 2;
- *--cmdpos = 'T';
- *--cmdpos = 'A';
-
- if (dle) {
- cmdlen += 4;
- *--cmdpos = '(';
- *--cmdpos = 0x10;
- *cmdtail++ = 0x10;
- *cmdtail++ = ')';
- }
-
- cs->ops->write_cmd(cs, cmdpos, cmdlen, NULL);
- kfree(cmdbuf);
+ if (cid > 0 && cid <= 65535)
+ cb->len = snprintf(cb->buf, buflen,
+ dle ? "\020(AT%d%s\020)" : "AT%d%s",
+ cid, cmd);
+ else
+ cb->len = snprintf(cb->buf, buflen,
+ dle ? "\020(AT%s\020)" : "AT%s",
+ cmd);
+ cb->offset = 0;
+ cb->next = NULL;
+ cb->wake_tasklet = NULL;
+ cs->ops->write_cmd(cs, cb);
}
static struct at_state_t *at_state_from_cid(struct cardstate *cs, int cid)
@@ -1240,8 +1140,22 @@ static void do_action(int action, struct cardstate *cs,
break;
case ACT_HUPMODEM:
/* send "+++" (hangup in unimodem mode) */
- if (cs->connected)
- cs->ops->write_cmd(cs, "+++", 3, NULL);
+ if (cs->connected) {
+ struct cmdbuf_t *cb;
+
+ cb = kmalloc(sizeof(struct cmdbuf_t) + 3, GFP_ATOMIC);
+ if (!cb) {
+ dev_err(cs->dev, "%s: out of memory\n",
+ __func__);
+ return;
+ }
+ memcpy(cb->buf, "+++", 3);
+ cb->len = 3;
+ cb->offset = 0;
+ cb->next = NULL;
+ cb->wake_tasklet = NULL;
+ cs->ops->write_cmd(cs, cb);
+ }
break;
case ACT_RING:
/* get fresh AT state structure for new CID */
@@ -1855,19 +1769,13 @@ static void process_command_flags(struct cardstate *cs)
gig_dbg(DEBUG_EVENT, "Scheduling PC_CIDMODE");
cs->commands_pending = 1;
return;
-#ifdef GIG_MAYINITONDIAL
case M_UNKNOWN:
schedule_init(cs, MS_INIT);
return;
-#endif
}
bcs->at_state.pending_commands &= ~PC_CID;
cs->curchannel = bcs->channel;
-#ifdef GIG_RETRYCID
cs->retry_count = 2;
-#else
- cs->retry_count = 1;
-#endif
schedule_sequence(cs, &cs->at_state, SEQ_CID);
return;
}
diff --git a/drivers/isdn/gigaset/gigaset.h b/drivers/isdn/gigaset/gigaset.h
index 8738b0821fc..a69512fb119 100644
--- a/drivers/isdn/gigaset/gigaset.h
+++ b/drivers/isdn/gigaset/gigaset.h
@@ -46,13 +46,6 @@
#define RBUFSIZE 8192
-/* compile time options */
-#define GIG_MAJOR 0
-
-#define GIG_MAYINITONDIAL
-#define GIG_RETRYCID
-#define GIG_X75
-
#define GIG_TICK 100 /* in milliseconds */
/* timeout values (unit: 1 sec) */
@@ -193,9 +186,8 @@ void gigaset_dbg_buffer(enum debuglevel level, const unsigned char *msg,
/* variables in struct at_state_t */
#define VAR_ZSAU 0
#define VAR_ZDLE 1
-#define VAR_ZVLS 2
-#define VAR_ZCTP 3
-#define VAR_NUM 4
+#define VAR_ZCTP 2
+#define VAR_NUM 3
#define STR_NMBR 0
#define STR_ZCPN 1
@@ -574,9 +566,7 @@ struct bas_bc_state {
struct gigaset_ops {
/* Called from ev-layer.c/interface.c for sending AT commands to the
device */
- int (*write_cmd)(struct cardstate *cs,
- const unsigned char *buf, int len,
- struct tasklet_struct *wake_tasklet);
+ int (*write_cmd)(struct cardstate *cs, struct cmdbuf_t *cb);
/* Called from interface.c for additional device control */
int (*write_room)(struct cardstate *cs);
diff --git a/drivers/isdn/gigaset/i4l.c b/drivers/isdn/gigaset/i4l.c
index f01c3c2e2e4..34bca37d65b 100644
--- a/drivers/isdn/gigaset/i4l.c
+++ b/drivers/isdn/gigaset/i4l.c
@@ -419,6 +419,8 @@ oom:
dev_err(bcs->cs->dev, "out of memory\n");
for (i = 0; i < AT_NUM; ++i)
kfree(commands[i]);
+ kfree(commands);
+ gigaset_free_channel(bcs);
return -ENOMEM;
}
@@ -643,9 +645,7 @@ int gigaset_isdn_regdev(struct cardstate *cs, const char *isdnid)
iif->maxbufsize = MAX_BUF_SIZE;
iif->features = ISDN_FEATURE_L2_TRANS |
ISDN_FEATURE_L2_HDLC |
-#ifdef GIG_X75
ISDN_FEATURE_L2_X75I |
-#endif
ISDN_FEATURE_L3_TRANS |
ISDN_FEATURE_P_EURO;
iif->hl_hdrlen = HW_HDR_LEN; /* Area for storing ack */
diff --git a/drivers/isdn/gigaset/interface.c b/drivers/isdn/gigaset/interface.c
index c9f28dd40d5..bb710d16a52 100644
--- a/drivers/isdn/gigaset/interface.c
+++ b/drivers/isdn/gigaset/interface.c
@@ -339,7 +339,8 @@ static int if_tiocmset(struct tty_struct *tty, struct file *file,
static int if_write(struct tty_struct *tty, const unsigned char *buf, int count)
{
struct cardstate *cs;
- int retval = -ENODEV;
+ struct cmdbuf_t *cb;
+ int retval;
cs = (struct cardstate *) tty->driver_data;
if (!cs) {
@@ -355,18 +356,39 @@ static int if_write(struct tty_struct *tty, const unsigned char *buf, int count)
if (!cs->connected) {
gig_dbg(DEBUG_IF, "not connected");
retval = -ENODEV;
- } else if (!cs->open_count)
+ goto done;
+ }
+ if (!cs->open_count) {
dev_warn(cs->dev, "%s: device not opened\n", __func__);
- else if (cs->mstate != MS_LOCKED) {
+ retval = -ENODEV;
+ goto done;
+ }
+ if (cs->mstate != MS_LOCKED) {
dev_warn(cs->dev, "can't write to unlocked device\n");
retval = -EBUSY;
- } else {
- retval = cs->ops->write_cmd(cs, buf, count,
- &cs->if_wake_tasklet);
+ goto done;
+ }
+ if (count <= 0) {
+ /* nothing to do */
+ retval = 0;
+ goto done;
}
- mutex_unlock(&cs->mutex);
+ cb = kmalloc(sizeof(struct cmdbuf_t) + count, GFP_KERNEL);
+ if (!cb) {
+ dev_err(cs->dev, "%s: out of memory\n", __func__);
+ retval = -ENOMEM;
+ goto done;
+ }
+ memcpy(cb->buf, buf, count);
+ cb->len = count;
+ cb->offset = 0;
+ cb->next = NULL;
+ cb->wake_tasklet = &cs->if_wake_tasklet;
+ retval = cs->ops->write_cmd(cs, cb);
+done:
+ mutex_unlock(&cs->mutex);
return retval;
}
@@ -655,7 +677,6 @@ void gigaset_if_initdriver(struct gigaset_driver *drv, const char *procname,
goto enomem;
tty->magic = TTY_DRIVER_MAGIC,
- tty->major = GIG_MAJOR,
tty->type = TTY_DRIVER_TYPE_SERIAL,
tty->subtype = SERIAL_TYPE_NORMAL,
tty->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
diff --git a/drivers/isdn/gigaset/ser-gigaset.c b/drivers/isdn/gigaset/ser-gigaset.c
index e96c0586886..d151dcbf770 100644
--- a/drivers/isdn/gigaset/ser-gigaset.c
+++ b/drivers/isdn/gigaset/ser-gigaset.c
@@ -241,30 +241,13 @@ static void flush_send_queue(struct cardstate *cs)
* return value:
* number of bytes queued, or error code < 0
*/
-static int gigaset_write_cmd(struct cardstate *cs, const unsigned char *buf,
- int len, struct tasklet_struct *wake_tasklet)
+static int gigaset_write_cmd(struct cardstate *cs, struct cmdbuf_t *cb)
{
- struct cmdbuf_t *cb;
unsigned long flags;
gigaset_dbg_buffer(cs->mstate != MS_LOCKED ?
DEBUG_TRANSCMD : DEBUG_LOCKCMD,
- "CMD Transmit", len, buf);
-
- if (len <= 0)
- return 0;
-
- cb = kmalloc(sizeof(struct cmdbuf_t) + len, GFP_ATOMIC);
- if (!cb) {
- dev_err(cs->dev, "%s: out of memory!\n", __func__);
- return -ENOMEM;
- }
-
- memcpy(cb->buf, buf, len);
- cb->len = len;
- cb->offset = 0;
- cb->next = NULL;
- cb->wake_tasklet = wake_tasklet;
+ "CMD Transmit", cb->len, cb->buf);
spin_lock_irqsave(&cs->cmdlock, flags);
cb->prev = cs->lastcmdbuf;
@@ -272,9 +255,9 @@ static int gigaset_write_cmd(struct cardstate *cs, const unsigned char *buf,
cs->lastcmdbuf->next = cb;
else {
cs->cmdbuf = cb;
- cs->curlen = len;
+ cs->curlen = cb->len;
}
- cs->cmdbytes += len;
+ cs->cmdbytes += cb->len;
cs->lastcmdbuf = cb;
spin_unlock_irqrestore(&cs->cmdlock, flags);
@@ -282,7 +265,7 @@ static int gigaset_write_cmd(struct cardstate *cs, const unsigned char *buf,
if (cs->connected)
tasklet_schedule(&cs->write_tasklet);
spin_unlock_irqrestore(&cs->lock, flags);
- return len;
+ return cb->len;
}
/*
diff --git a/drivers/isdn/gigaset/usb-gigaset.c b/drivers/isdn/gigaset/usb-gigaset.c
index 76dbb20f306..4a66338f4e7 100644
--- a/drivers/isdn/gigaset/usb-gigaset.c
+++ b/drivers/isdn/gigaset/usb-gigaset.c
@@ -39,7 +39,8 @@ MODULE_PARM_DESC(cidmode, "Call-ID mode");
#define GIGASET_MODULENAME "usb_gigaset"
#define GIGASET_DEVNAME "ttyGU"
-#define IF_WRITEBUF 2000 /* arbitrary limit */
+/* length limit according to Siemens 3070usb-protokoll.doc ch. 2.1 */
+#define IF_WRITEBUF 264
/* Values for the Gigaset M105 Data */
#define USB_M105_VENDOR_ID 0x0681
@@ -493,29 +494,13 @@ static int send_cb(struct cardstate *cs, struct cmdbuf_t *cb)
}
/* Send command to device. */
-static int gigaset_write_cmd(struct cardstate *cs, const unsigned char *buf,
- int len, struct tasklet_struct *wake_tasklet)
+static int gigaset_write_cmd(struct cardstate *cs, struct cmdbuf_t *cb)
{
- struct cmdbuf_t *cb;
unsigned long flags;
gigaset_dbg_buffer(cs->mstate != MS_LOCKED ?
DEBUG_TRANSCMD : DEBUG_LOCKCMD,
- "CMD Transmit", len, buf);
-
- if (len <= 0)
- return 0;
- cb = kmalloc(sizeof(struct cmdbuf_t) + len, GFP_ATOMIC);
- if (!cb) {
- dev_err(cs->dev, "%s: out of memory\n", __func__);
- return -ENOMEM;
- }
-
- memcpy(cb->buf, buf, len);
- cb->len = len;
- cb->offset = 0;
- cb->next = NULL;
- cb->wake_tasklet = wake_tasklet;
+ "CMD Transmit", cb->len, cb->buf);
spin_lock_irqsave(&cs->cmdlock, flags);
cb->prev = cs->lastcmdbuf;
@@ -523,9 +508,9 @@ static int gigaset_write_cmd(struct cardstate *cs, const unsigned char *buf,
cs->lastcmdbuf->next = cb;
else {
cs->cmdbuf = cb;
- cs->curlen = len;
+ cs->curlen = cb->len;
}
- cs->cmdbytes += len;
+ cs->cmdbytes += cb->len;
cs->lastcmdbuf = cb;
spin_unlock_irqrestore(&cs->cmdlock, flags);
@@ -533,7 +518,7 @@ static int gigaset_write_cmd(struct cardstate *cs, const unsigned char *buf,
if (cs->connected)
tasklet_schedule(&cs->write_tasklet);
spin_unlock_irqrestore(&cs->lock, flags);
- return len;
+ return cb->len;
}
static int gigaset_write_room(struct cardstate *cs)
diff --git a/drivers/isdn/hardware/avm/avm_cs.c b/drivers/isdn/hardware/avm/avm_cs.c
index f410d0eb2fe..09b1795516f 100644
--- a/drivers/isdn/hardware/avm/avm_cs.c
+++ b/drivers/isdn/hardware/avm/avm_cs.c
@@ -20,7 +20,6 @@
#include <asm/io.h>
#include <asm/system.h>
-#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/cistpl.h>
#include <pcmcia/ciscode.h>
@@ -76,9 +75,8 @@ static int avmcs_probe(struct pcmcia_device *p_dev)
{
/* The io structure describes IO port mapping */
- p_dev->io.NumPorts1 = 16;
- p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
- p_dev->io.NumPorts2 = 0;
+ p_dev->resource[0]->end = 16;
+ p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_8;
/* General socket configuration */
p_dev->conf.Attributes = CONF_ENABLE_IRQ;
@@ -120,13 +118,9 @@ static int avmcs_configcheck(struct pcmcia_device *p_dev,
if (cf->io.nwin <= 0)
return -ENODEV;
- p_dev->io.BasePort1 = cf->io.win[0].base;
- p_dev->io.NumPorts1 = cf->io.win[0].len;
- p_dev->io.NumPorts2 = 0;
- printk(KERN_INFO "avm_cs: testing i/o %#x-%#x\n",
- p_dev->io.BasePort1,
- p_dev->io.BasePort1+p_dev->io.NumPorts1-1);
- return pcmcia_request_io(p_dev, &p_dev->io);
+ p_dev->resource[0]->start = cf->io.win[0].base;
+ p_dev->resource[0]->end = cf->io.win[0].len;
+ return pcmcia_request_io(p_dev);
}
static int avmcs_config(struct pcmcia_device *link)
@@ -192,9 +186,10 @@ static int avmcs_config(struct pcmcia_device *link)
default:
case AVM_CARDTYPE_B1: addcard = b1pcmcia_addcard_b1; break;
}
- if ((i = (*addcard)(link->io.BasePort1, link->irq)) < 0) {
- dev_err(&link->dev, "avm_cs: failed to add AVM-Controller at i/o %#x, irq %d\n",
- link->io.BasePort1, link->irq);
+ if ((i = (*addcard)(link->resource[0]->start, link->irq)) < 0) {
+ dev_err(&link->dev,
+ "avm_cs: failed to add AVM-Controller at i/o %#x, irq %d\n",
+ (unsigned int) link->resource[0]->start, link->irq);
avmcs_release(link);
return -ENODEV;
}
@@ -212,7 +207,7 @@ static int avmcs_config(struct pcmcia_device *link)
static void avmcs_release(struct pcmcia_device *link)
{
- b1pcmcia_delcard(link->io.BasePort1, link->irq);
+ b1pcmcia_delcard(link->resource[0]->start, link->irq);
pcmcia_disable_device(link);
} /* avmcs_release */
diff --git a/drivers/isdn/hardware/eicon/divamnt.c b/drivers/isdn/hardware/eicon/divamnt.c
index 1e85f743214..f1d464f1e10 100644
--- a/drivers/isdn/hardware/eicon/divamnt.c
+++ b/drivers/isdn/hardware/eicon/divamnt.c
@@ -14,7 +14,7 @@
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/poll.h>
-#include <linux/smp_lock.h>
+#include <linux/mutex.h>
#include <asm/uaccess.h>
#include "platform.h"
@@ -22,6 +22,7 @@
#include "divasync.h"
#include "debug_if.h"
+static DEFINE_MUTEX(maint_mutex);
static char *main_revision = "$Revision: 1.32.6.10 $";
static int major;
@@ -130,7 +131,7 @@ static int maint_open(struct inode *ino, struct file *filep)
{
int ret;
- lock_kernel();
+ mutex_lock(&maint_mutex);
/* only one open is allowed, so we test
it atomically */
if (test_and_set_bit(0, &opened))
@@ -139,7 +140,7 @@ static int maint_open(struct inode *ino, struct file *filep)
filep->private_data = NULL;
ret = nonseekable_open(ino, filep);
}
- unlock_kernel();
+ mutex_unlock(&maint_mutex);
return ret;
}
diff --git a/drivers/isdn/hardware/eicon/divasi.c b/drivers/isdn/hardware/eicon/divasi.c
index f577719ab3f..42d3b834603 100644
--- a/drivers/isdn/hardware/eicon/divasi.c
+++ b/drivers/isdn/hardware/eicon/divasi.c
@@ -18,7 +18,6 @@
#include <linux/proc_fs.h>
#include <linux/skbuff.h>
#include <linux/seq_file.h>
-#include <linux/smp_lock.h>
#include <asm/uaccess.h>
#include "platform.h"
@@ -402,7 +401,6 @@ static unsigned int um_idi_poll(struct file *file, poll_table * wait)
static int um_idi_open(struct inode *inode, struct file *file)
{
- cycle_kernel_lock();
return (0);
}
diff --git a/drivers/isdn/hardware/eicon/divasmain.c b/drivers/isdn/hardware/eicon/divasmain.c
index fbbcb27fb68..ed9c5550679 100644
--- a/drivers/isdn/hardware/eicon/divasmain.c
+++ b/drivers/isdn/hardware/eicon/divasmain.c
@@ -21,7 +21,6 @@
#include <linux/list.h>
#include <linux/poll.h>
#include <linux/kmod.h>
-#include <linux/smp_lock.h>
#include "platform.h"
#undef ID_MASK
@@ -113,41 +112,40 @@ typedef struct _diva_os_thread_dpc {
This table should be sorted by PCI device ID
*/
static struct pci_device_id divas_pci_tbl[] = {
-/* Diva Server BRI-2M PCI 0xE010 */
- {PCI_VENDOR_ID_EICON, PCI_DEVICE_ID_EICON_MAESTRA,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, CARDTYPE_MAESTRA_PCI},
-/* Diva Server 4BRI-8M PCI 0xE012 */
- {PCI_VENDOR_ID_EICON, PCI_DEVICE_ID_EICON_MAESTRAQ,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, CARDTYPE_DIVASRV_Q_8M_PCI},
-/* Diva Server 4BRI-8M 2.0 PCI 0xE013 */
- {PCI_VENDOR_ID_EICON, PCI_DEVICE_ID_EICON_MAESTRAQ_U,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, CARDTYPE_DIVASRV_Q_8M_V2_PCI},
-/* Diva Server PRI-30M PCI 0xE014 */
- {PCI_VENDOR_ID_EICON, PCI_DEVICE_ID_EICON_MAESTRAP,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, CARDTYPE_DIVASRV_P_30M_PCI},
-/* Diva Server PRI 2.0 adapter 0xE015 */
- {PCI_VENDOR_ID_EICON, PCI_DEVICE_ID_EICON_MAESTRAP_2,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, CARDTYPE_DIVASRV_P_30M_V2_PCI},
-/* Diva Server Voice 4BRI-8M PCI 0xE016 */
- {PCI_VENDOR_ID_EICON, PCI_DEVICE_ID_EICON_4BRI_VOIP,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, CARDTYPE_DIVASRV_VOICE_Q_8M_PCI},
-/* Diva Server Voice 4BRI-8M 2.0 PCI 0xE017 */
- {PCI_VENDOR_ID_EICON, PCI_DEVICE_ID_EICON_4BRI_2_VOIP,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, CARDTYPE_DIVASRV_VOICE_Q_8M_V2_PCI},
-/* Diva Server BRI-2M 2.0 PCI 0xE018 */
- {PCI_VENDOR_ID_EICON, PCI_DEVICE_ID_EICON_BRI2M_2,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, CARDTYPE_DIVASRV_B_2M_V2_PCI},
-/* Diva Server Voice PRI 2.0 PCI 0xE019 */
- {PCI_VENDOR_ID_EICON, PCI_DEVICE_ID_EICON_MAESTRAP_2_VOIP,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- CARDTYPE_DIVASRV_VOICE_P_30M_V2_PCI},
-/* Diva Server 2FX 0xE01A */
- {PCI_VENDOR_ID_EICON, PCI_DEVICE_ID_EICON_2F,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, CARDTYPE_DIVASRV_B_2F_PCI},
-/* Diva Server Voice BRI-2M 2.0 PCI 0xE01B */
- {PCI_VENDOR_ID_EICON, PCI_DEVICE_ID_EICON_BRI2M_2_VOIP,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, CARDTYPE_DIVASRV_VOICE_B_2M_V2_PCI},
- {0,} /* 0 terminated list. */
+ /* Diva Server BRI-2M PCI 0xE010 */
+ { PCI_VDEVICE(EICON, PCI_DEVICE_ID_EICON_MAESTRA),
+ CARDTYPE_MAESTRA_PCI },
+ /* Diva Server 4BRI-8M PCI 0xE012 */
+ { PCI_VDEVICE(EICON, PCI_DEVICE_ID_EICON_MAESTRAQ),
+ CARDTYPE_DIVASRV_Q_8M_PCI },
+ /* Diva Server 4BRI-8M 2.0 PCI 0xE013 */
+ { PCI_VDEVICE(EICON, PCI_DEVICE_ID_EICON_MAESTRAQ_U),
+ CARDTYPE_DIVASRV_Q_8M_V2_PCI },
+ /* Diva Server PRI-30M PCI 0xE014 */
+ { PCI_VDEVICE(EICON, PCI_DEVICE_ID_EICON_MAESTRAP),
+ CARDTYPE_DIVASRV_P_30M_PCI },
+ /* Diva Server PRI 2.0 adapter 0xE015 */
+ { PCI_VDEVICE(EICON, PCI_DEVICE_ID_EICON_MAESTRAP_2),
+ CARDTYPE_DIVASRV_P_30M_V2_PCI },
+ /* Diva Server Voice 4BRI-8M PCI 0xE016 */
+ { PCI_VDEVICE(EICON, PCI_DEVICE_ID_EICON_4BRI_VOIP),
+ CARDTYPE_DIVASRV_VOICE_Q_8M_PCI },
+ /* Diva Server Voice 4BRI-8M 2.0 PCI 0xE017 */
+ { PCI_VDEVICE(EICON, PCI_DEVICE_ID_EICON_4BRI_2_VOIP),
+ CARDTYPE_DIVASRV_VOICE_Q_8M_V2_PCI },
+ /* Diva Server BRI-2M 2.0 PCI 0xE018 */
+ { PCI_VDEVICE(EICON, PCI_DEVICE_ID_EICON_BRI2M_2),
+ CARDTYPE_DIVASRV_B_2M_V2_PCI },
+ /* Diva Server Voice PRI 2.0 PCI 0xE019 */
+ { PCI_VDEVICE(EICON, PCI_DEVICE_ID_EICON_MAESTRAP_2_VOIP),
+ CARDTYPE_DIVASRV_VOICE_P_30M_V2_PCI },
+ /* Diva Server 2FX 0xE01A */
+ { PCI_VDEVICE(EICON, PCI_DEVICE_ID_EICON_2F),
+ CARDTYPE_DIVASRV_B_2F_PCI },
+ /* Diva Server Voice BRI-2M 2.0 PCI 0xE01B */
+ { PCI_VDEVICE(EICON, PCI_DEVICE_ID_EICON_BRI2M_2_VOIP),
+ CARDTYPE_DIVASRV_VOICE_B_2M_V2_PCI },
+ { 0, } /* 0 terminated list. */
};
MODULE_DEVICE_TABLE(pci, divas_pci_tbl);
@@ -581,7 +579,6 @@ xdi_copy_from_user(void *os_handle, void *dst, const void __user *src, int lengt
*/
static int divas_open(struct inode *inode, struct file *file)
{
- cycle_kernel_lock();
return (0);
}
diff --git a/drivers/isdn/hardware/mISDN/avmfritz.c b/drivers/isdn/hardware/mISDN/avmfritz.c
index d4215369bb5..472a2af7944 100644
--- a/drivers/isdn/hardware/mISDN/avmfritz.c
+++ b/drivers/isdn/hardware/mISDN/avmfritz.c
@@ -1116,7 +1116,7 @@ fritz_remove_pci(struct pci_dev *pdev)
release_card(card);
else
if (debug)
- pr_info("%s: drvdata allready removed\n", __func__);
+ pr_info("%s: drvdata already removed\n", __func__);
}
static struct pci_device_id fcpci_ids[] __devinitdata = {
diff --git a/drivers/isdn/hardware/mISDN/hfcmulti.c b/drivers/isdn/hardware/mISDN/hfcmulti.c
index 095ed76ebe8..4e3780d78ac 100644
--- a/drivers/isdn/hardware/mISDN/hfcmulti.c
+++ b/drivers/isdn/hardware/mISDN/hfcmulti.c
@@ -4268,7 +4268,7 @@ init_card(struct hfc_multi *hc)
goto error;
/*
* Finally enable IRQ output
- * this is only allowed, if an IRQ routine is allready
+ * this is only allowed, if an IRQ routine is already
* established for this HFC, so don't do that earlier
*/
spin_lock_irqsave(&hc->lock, flags);
@@ -5212,7 +5212,7 @@ static void __devexit hfc_remove_pci(struct pci_dev *pdev)
spin_unlock_irqrestore(&HFClock, flags);
} else {
if (debug)
- printk(KERN_DEBUG "%s: drvdata allready removed\n",
+ printk(KERN_DEBUG "%s: drvdata already removed\n",
__func__);
}
}
@@ -5354,12 +5354,9 @@ static struct pci_device_id hfmultipci_ids[] __devinitdata = {
{ PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFCE1, PCI_VENDOR_ID_CCD,
PCI_SUBDEVICE_ID_CCD_JHSE1, 0, 0, H(25)}, /* Junghanns E1 */
- { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC4S, PCI_ANY_ID, PCI_ANY_ID,
- 0, 0, 0},
- { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC8S, PCI_ANY_ID, PCI_ANY_ID,
- 0, 0, 0},
- { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFCE1, PCI_ANY_ID, PCI_ANY_ID,
- 0, 0, 0},
+ { PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_HFC4S), 0 },
+ { PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_HFC8S), 0 },
+ { PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_HFCE1), 0 },
{0, }
};
#undef H
diff --git a/drivers/isdn/hardware/mISDN/hfcpci.c b/drivers/isdn/hardware/mISDN/hfcpci.c
index 5940a2c1207..15d323b8be6 100644
--- a/drivers/isdn/hardware/mISDN/hfcpci.c
+++ b/drivers/isdn/hardware/mISDN/hfcpci.c
@@ -1773,7 +1773,7 @@ init_card(struct hfc_pci *hc)
inithfcpci(hc);
/*
* Finally enable IRQ output
- * this is only allowed, if an IRQ routine is allready
+ * this is only allowed, if an IRQ routine is already
* established for this HFC, so don't do that earlier
*/
enable_hwirq(hc);
@@ -2188,52 +2188,52 @@ static const struct _hfc_map hfc_map[] =
static struct pci_device_id hfc_ids[] =
{
- {PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_2BD0,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long) &hfc_map[0]},
- {PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B000,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long) &hfc_map[1]},
- {PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B006,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long) &hfc_map[2]},
- {PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B007,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long) &hfc_map[3]},
- {PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B008,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long) &hfc_map[4]},
- {PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B009,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long) &hfc_map[5]},
- {PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B00A,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long) &hfc_map[6]},
- {PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B00B,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long) &hfc_map[7]},
- {PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B00C,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long) &hfc_map[8]},
- {PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B100,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long) &hfc_map[9]},
- {PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B700,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long) &hfc_map[10]},
- {PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B701,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long) &hfc_map[11]},
- {PCI_VENDOR_ID_ABOCOM, PCI_DEVICE_ID_ABOCOM_2BD1,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long) &hfc_map[12]},
- {PCI_VENDOR_ID_ASUSTEK, PCI_DEVICE_ID_ASUSTEK_0675,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long) &hfc_map[13]},
- {PCI_VENDOR_ID_BERKOM, PCI_DEVICE_ID_BERKOM_T_CONCEPT,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long) &hfc_map[14]},
- {PCI_VENDOR_ID_BERKOM, PCI_DEVICE_ID_BERKOM_A1T,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long) &hfc_map[15]},
- {PCI_VENDOR_ID_ANIGMA, PCI_DEVICE_ID_ANIGMA_MC145575,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long) &hfc_map[16]},
- {PCI_VENDOR_ID_ZOLTRIX, PCI_DEVICE_ID_ZOLTRIX_2BD0,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long) &hfc_map[17]},
- {PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_DIGI_DF_M_IOM2_E,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long) &hfc_map[18]},
- {PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_DIGI_DF_M_E,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long) &hfc_map[19]},
- {PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_DIGI_DF_M_IOM2_A,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long) &hfc_map[20]},
- {PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_DIGI_DF_M_A,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long) &hfc_map[21]},
- {PCI_VENDOR_ID_SITECOM, PCI_DEVICE_ID_SITECOM_DC105V2,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long) &hfc_map[22]},
+ { PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_2BD0),
+ (unsigned long) &hfc_map[0] },
+ { PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_B000),
+ (unsigned long) &hfc_map[1] },
+ { PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_B006),
+ (unsigned long) &hfc_map[2] },
+ { PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_B007),
+ (unsigned long) &hfc_map[3] },
+ { PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_B008),
+ (unsigned long) &hfc_map[4] },
+ { PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_B009),
+ (unsigned long) &hfc_map[5] },
+ { PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_B00A),
+ (unsigned long) &hfc_map[6] },
+ { PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_B00B),
+ (unsigned long) &hfc_map[7] },
+ { PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_B00C),
+ (unsigned long) &hfc_map[8] },
+ { PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_B100),
+ (unsigned long) &hfc_map[9] },
+ { PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_B700),
+ (unsigned long) &hfc_map[10] },
+ { PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_B701),
+ (unsigned long) &hfc_map[11] },
+ { PCI_VDEVICE(ABOCOM, PCI_DEVICE_ID_ABOCOM_2BD1),
+ (unsigned long) &hfc_map[12] },
+ { PCI_VDEVICE(ASUSTEK, PCI_DEVICE_ID_ASUSTEK_0675),
+ (unsigned long) &hfc_map[13] },
+ { PCI_VDEVICE(BERKOM, PCI_DEVICE_ID_BERKOM_T_CONCEPT),
+ (unsigned long) &hfc_map[14] },
+ { PCI_VDEVICE(BERKOM, PCI_DEVICE_ID_BERKOM_A1T),
+ (unsigned long) &hfc_map[15] },
+ { PCI_VDEVICE(ANIGMA, PCI_DEVICE_ID_ANIGMA_MC145575),
+ (unsigned long) &hfc_map[16] },
+ { PCI_VDEVICE(ZOLTRIX, PCI_DEVICE_ID_ZOLTRIX_2BD0),
+ (unsigned long) &hfc_map[17] },
+ { PCI_VDEVICE(DIGI, PCI_DEVICE_ID_DIGI_DF_M_IOM2_E),
+ (unsigned long) &hfc_map[18] },
+ { PCI_VDEVICE(DIGI, PCI_DEVICE_ID_DIGI_DF_M_E),
+ (unsigned long) &hfc_map[19] },
+ { PCI_VDEVICE(DIGI, PCI_DEVICE_ID_DIGI_DF_M_IOM2_A),
+ (unsigned long) &hfc_map[20] },
+ { PCI_VDEVICE(DIGI, PCI_DEVICE_ID_DIGI_DF_M_A),
+ (unsigned long) &hfc_map[21] },
+ { PCI_VDEVICE(SITECOM, PCI_DEVICE_ID_SITECOM_DC105V2),
+ (unsigned long) &hfc_map[22] },
{},
};
diff --git a/drivers/isdn/hardware/mISDN/mISDNinfineon.c b/drivers/isdn/hardware/mISDN/mISDNinfineon.c
index f5b3d2b26a0..d2dd61d65d5 100644
--- a/drivers/isdn/hardware/mISDN/mISDNinfineon.c
+++ b/drivers/isdn/hardware/mISDN/mISDNinfineon.c
@@ -125,36 +125,25 @@ struct inf_hw {
#define PCI_SUB_ID_SEDLBAUER 0x01
static struct pci_device_id infineon_ids[] __devinitdata = {
- { PCI_VENDOR_ID_EICON, PCI_DEVICE_ID_EICON_DIVA20,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, INF_DIVA20},
- { PCI_VENDOR_ID_EICON, PCI_DEVICE_ID_EICON_DIVA20_U,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, INF_DIVA20U},
- { PCI_VENDOR_ID_EICON, PCI_DEVICE_ID_EICON_DIVA201,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, INF_DIVA201},
- { PCI_VENDOR_ID_EICON, PCI_DEVICE_ID_EICON_DIVA202,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, INF_DIVA202},
+ { PCI_VDEVICE(EICON, PCI_DEVICE_ID_EICON_DIVA20), INF_DIVA20 },
+ { PCI_VDEVICE(EICON, PCI_DEVICE_ID_EICON_DIVA20_U), INF_DIVA20U },
+ { PCI_VDEVICE(EICON, PCI_DEVICE_ID_EICON_DIVA201), INF_DIVA201 },
+ { PCI_VDEVICE(EICON, PCI_DEVICE_ID_EICON_DIVA202), INF_DIVA202 },
{ PCI_VENDOR_ID_TIGERJET, PCI_DEVICE_ID_TIGERJET_100,
PCI_SUBVENDOR_SEDLBAUER_PCI, PCI_SUB_ID_SEDLBAUER, 0, 0,
- INF_SPEEDWIN},
+ INF_SPEEDWIN },
{ PCI_VENDOR_ID_TIGERJET, PCI_DEVICE_ID_TIGERJET_100,
- PCI_SUBVENDOR_HST_SAPHIR3, PCI_SUB_ID_SEDLBAUER, 0, 0, INF_SAPHIR3},
- { PCI_VENDOR_ID_ELSA, PCI_DEVICE_ID_ELSA_MICROLINK,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, INF_QS1000},
- { PCI_VENDOR_ID_ELSA, PCI_DEVICE_ID_ELSA_QS3000,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, INF_QS3000},
- { PCI_VENDOR_ID_SATSAGEM, PCI_DEVICE_ID_SATSAGEM_NICCY,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, INF_NICCY},
+ PCI_SUBVENDOR_HST_SAPHIR3, PCI_SUB_ID_SEDLBAUER, 0, 0, INF_SAPHIR3 },
+ { PCI_VDEVICE(ELSA, PCI_DEVICE_ID_ELSA_MICROLINK), INF_QS1000 },
+ { PCI_VDEVICE(ELSA, PCI_DEVICE_ID_ELSA_QS3000), INF_QS3000 },
+ { PCI_VDEVICE(SATSAGEM, PCI_DEVICE_ID_SATSAGEM_NICCY), INF_NICCY },
{ PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
PCI_VENDOR_ID_BERKOM, PCI_DEVICE_ID_BERKOM_SCITEL_QUADRO, 0, 0,
- INF_SCT_1},
- { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_R685,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, INF_GAZEL_R685},
- { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_R753,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, INF_GAZEL_R753},
- { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_DJINN_ITOO,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, INF_GAZEL_R753},
- { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_OLITEC,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, INF_GAZEL_R753},
+ INF_SCT_1 },
+ { PCI_VDEVICE(PLX, PCI_DEVICE_ID_PLX_R685), INF_GAZEL_R685 },
+ { PCI_VDEVICE(PLX, PCI_DEVICE_ID_PLX_R753), INF_GAZEL_R753 },
+ { PCI_VDEVICE(PLX, PCI_DEVICE_ID_PLX_DJINN_ITOO), INF_GAZEL_R753 },
+ { PCI_VDEVICE(PLX, PCI_DEVICE_ID_PLX_OLITEC), INF_GAZEL_R753 },
{ }
};
MODULE_DEVICE_TABLE(pci, infineon_ids);
@@ -1150,7 +1139,7 @@ inf_remove(struct pci_dev *pdev)
if (card)
release_card(card);
else
- pr_debug("%s: drvdata allready removed\n", __func__);
+ pr_debug("%s: drvdata already removed\n", __func__);
}
static struct pci_driver infineon_driver = {
diff --git a/drivers/isdn/hardware/mISDN/speedfax.c b/drivers/isdn/hardware/mISDN/speedfax.c
index d097a4e40e2..9e07246bb9e 100644
--- a/drivers/isdn/hardware/mISDN/speedfax.c
+++ b/drivers/isdn/hardware/mISDN/speedfax.c
@@ -484,7 +484,7 @@ sfax_remove_pci(struct pci_dev *pdev)
if (card)
release_card(card);
else
- pr_debug("%s: drvdata allready removed\n", __func__);
+ pr_debug("%s: drvdata already removed\n", __func__);
}
static struct pci_device_id sfaxpci_ids[] __devinitdata = {
diff --git a/drivers/isdn/hardware/mISDN/w6692.c b/drivers/isdn/hardware/mISDN/w6692.c
index 31f9d71fb22..9e84870b971 100644
--- a/drivers/isdn/hardware/mISDN/w6692.c
+++ b/drivers/isdn/hardware/mISDN/w6692.c
@@ -1402,7 +1402,7 @@ w6692_remove_pci(struct pci_dev *pdev)
release_card(card);
else
if (debug)
- pr_notice("%s: drvdata allready removed\n", __func__);
+ pr_notice("%s: drvdata already removed\n", __func__);
}
static struct pci_device_id w6692_ids[] = {
diff --git a/drivers/isdn/hisax/avma1_cs.c b/drivers/isdn/hisax/avma1_cs.c
index a80a7617f16..94263c22b87 100644
--- a/drivers/isdn/hisax/avma1_cs.c
+++ b/drivers/isdn/hisax/avma1_cs.c
@@ -20,7 +20,6 @@
#include <asm/io.h>
#include <asm/system.h>
-#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/cistpl.h>
#include <pcmcia/ds.h>
@@ -79,11 +78,10 @@ static int __devinit avma1cs_probe(struct pcmcia_device *p_dev)
dev_dbg(&p_dev->dev, "avma1cs_attach()\n");
/* The io structure describes IO port mapping */
- p_dev->io.NumPorts1 = 16;
- p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
- p_dev->io.NumPorts2 = 16;
- p_dev->io.Attributes2 = IO_DATA_PATH_WIDTH_16;
- p_dev->io.IOAddrLines = 5;
+ p_dev->resource[0]->end = 16;
+ p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_8;
+ p_dev->resource[1]->end = 16;
+ p_dev->resource[1]->flags |= IO_DATA_PATH_WIDTH_16;
/* General socket configuration */
p_dev->conf.Attributes = CONF_ENABLE_IRQ;
@@ -127,13 +125,10 @@ static int avma1cs_configcheck(struct pcmcia_device *p_dev,
if (cf->io.nwin <= 0)
return -ENODEV;
- p_dev->io.BasePort1 = cf->io.win[0].base;
- p_dev->io.NumPorts1 = cf->io.win[0].len;
- p_dev->io.NumPorts2 = 0;
- printk(KERN_INFO "avma1_cs: testing i/o %#x-%#x\n",
- p_dev->io.BasePort1,
- p_dev->io.BasePort1+p_dev->io.NumPorts1-1);
- return pcmcia_request_io(p_dev, &p_dev->io);
+ p_dev->resource[0]->start = cf->io.win[0].base;
+ p_dev->resource[0]->end = cf->io.win[0].len;
+ p_dev->io_lines = 5;
+ return pcmcia_request_io(p_dev);
}
@@ -181,16 +176,18 @@ static int __devinit avma1cs_config(struct pcmcia_device *link)
}
printk(KERN_NOTICE "avma1_cs: checking at i/o %#x, irq %d\n",
- link->io.BasePort1, link->irq);
+ (unsigned int) link->resource[0]->start, link->irq);
icard.para[0] = link->irq;
- icard.para[1] = link->io.BasePort1;
+ icard.para[1] = link->resource[0]->start;
icard.protocol = isdnprot;
icard.typ = ISDN_CTYPE_A1_PCMCIA;
i = hisax_init_pcmcia(link, &busy, &icard);
if (i < 0) {
- printk(KERN_ERR "avma1_cs: failed to initialize AVM A1 PCMCIA %d at i/o %#x\n", i, link->io.BasePort1);
+ printk(KERN_ERR "avma1_cs: failed to initialize AVM A1 "
+ "PCMCIA %d at i/o %#x\n", i,
+ (unsigned int) link->resource[0]->start);
avma1cs_release(link);
return -ENODEV;
}
diff --git a/drivers/isdn/hisax/callc.c b/drivers/isdn/hisax/callc.c
index f58ded8f403..f150330b5a2 100644
--- a/drivers/isdn/hisax/callc.c
+++ b/drivers/isdn/hisax/callc.c
@@ -1172,7 +1172,7 @@ CallcFreeChan(struct IsdnCardState *csta)
kfree(csta->channel[i].b_st);
csta->channel[i].b_st = NULL;
} else
- printk(KERN_WARNING "CallcFreeChan b_st ch%d allready freed\n", i);
+ printk(KERN_WARNING "CallcFreeChan b_st ch%d already freed\n", i);
if (i || test_bit(FLG_TWO_DCHAN, &csta->HW_Flags)) {
release_d_st(csta->channel + i);
} else
diff --git a/drivers/isdn/hisax/config.c b/drivers/isdn/hisax/config.c
index 544cf4b1cce..6f9afcd5ca4 100644
--- a/drivers/isdn/hisax/config.c
+++ b/drivers/isdn/hisax/config.c
@@ -1909,68 +1909,68 @@ static void EChannel_proc_rcv(struct hisax_d_if *d_if)
static struct pci_device_id hisax_pci_tbl[] __devinitdata = {
#ifdef CONFIG_HISAX_FRITZPCI
- {PCI_VENDOR_ID_AVM, PCI_DEVICE_ID_AVM_A1, PCI_ANY_ID, PCI_ANY_ID},
+ {PCI_VDEVICE(AVM, PCI_DEVICE_ID_AVM_A1) },
#endif
#ifdef CONFIG_HISAX_DIEHLDIVA
- {PCI_VENDOR_ID_EICON, PCI_DEVICE_ID_EICON_DIVA20, PCI_ANY_ID, PCI_ANY_ID},
- {PCI_VENDOR_ID_EICON, PCI_DEVICE_ID_EICON_DIVA20_U, PCI_ANY_ID, PCI_ANY_ID},
- {PCI_VENDOR_ID_EICON, PCI_DEVICE_ID_EICON_DIVA201, PCI_ANY_ID, PCI_ANY_ID},
-//#########################################################################################
- {PCI_VENDOR_ID_EICON, PCI_DEVICE_ID_EICON_DIVA202, PCI_ANY_ID, PCI_ANY_ID},
-//#########################################################################################
+ {PCI_VDEVICE(EICON, PCI_DEVICE_ID_EICON_DIVA20) },
+ {PCI_VDEVICE(EICON, PCI_DEVICE_ID_EICON_DIVA20_U) },
+ {PCI_VDEVICE(EICON, PCI_DEVICE_ID_EICON_DIVA201) },
+/*##########################################################################*/
+ {PCI_VDEVICE(EICON, PCI_DEVICE_ID_EICON_DIVA202) },
+/*##########################################################################*/
#endif
#ifdef CONFIG_HISAX_ELSA
- {PCI_VENDOR_ID_ELSA, PCI_DEVICE_ID_ELSA_MICROLINK, PCI_ANY_ID, PCI_ANY_ID},
- {PCI_VENDOR_ID_ELSA, PCI_DEVICE_ID_ELSA_QS3000, PCI_ANY_ID, PCI_ANY_ID},
+ {PCI_VDEVICE(ELSA, PCI_DEVICE_ID_ELSA_MICROLINK) },
+ {PCI_VDEVICE(ELSA, PCI_DEVICE_ID_ELSA_QS3000) },
#endif
#ifdef CONFIG_HISAX_GAZEL
- {PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_R685, PCI_ANY_ID, PCI_ANY_ID},
- {PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_R753, PCI_ANY_ID, PCI_ANY_ID},
- {PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_DJINN_ITOO, PCI_ANY_ID, PCI_ANY_ID},
- {PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_OLITEC, PCI_ANY_ID, PCI_ANY_ID},
+ {PCI_VDEVICE(PLX, PCI_DEVICE_ID_PLX_R685) },
+ {PCI_VDEVICE(PLX, PCI_DEVICE_ID_PLX_R753) },
+ {PCI_VDEVICE(PLX, PCI_DEVICE_ID_PLX_DJINN_ITOO) },
+ {PCI_VDEVICE(PLX, PCI_DEVICE_ID_PLX_OLITEC) },
#endif
#ifdef CONFIG_HISAX_SCT_QUADRO
- {PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050, PCI_ANY_ID, PCI_ANY_ID},
+ {PCI_VDEVICE(PLX, PCI_DEVICE_ID_PLX_9050) },
#endif
#ifdef CONFIG_HISAX_NICCY
- {PCI_VENDOR_ID_SATSAGEM, PCI_DEVICE_ID_SATSAGEM_NICCY, PCI_ANY_ID,PCI_ANY_ID},
+ {PCI_VDEVICE(SATSAGEM, PCI_DEVICE_ID_SATSAGEM_NICCY) },
#endif
#ifdef CONFIG_HISAX_SEDLBAUER
- {PCI_VENDOR_ID_TIGERJET, PCI_DEVICE_ID_TIGERJET_100, PCI_ANY_ID,PCI_ANY_ID},
+ {PCI_VDEVICE(TIGERJET, PCI_DEVICE_ID_TIGERJET_100) },
#endif
#if defined(CONFIG_HISAX_NETJET) || defined(CONFIG_HISAX_NETJET_U)
- {PCI_VENDOR_ID_TIGERJET, PCI_DEVICE_ID_TIGERJET_300, PCI_ANY_ID,PCI_ANY_ID},
+ {PCI_VDEVICE(TIGERJET, PCI_DEVICE_ID_TIGERJET_300) },
#endif
#if defined(CONFIG_HISAX_TELESPCI) || defined(CONFIG_HISAX_SCT_QUADRO)
- {PCI_VENDOR_ID_ZORAN, PCI_DEVICE_ID_ZORAN_36120, PCI_ANY_ID,PCI_ANY_ID},
+ {PCI_VDEVICE(ZORAN, PCI_DEVICE_ID_ZORAN_36120) },
#endif
#ifdef CONFIG_HISAX_W6692
- {PCI_VENDOR_ID_DYNALINK, PCI_DEVICE_ID_DYNALINK_IS64PH, PCI_ANY_ID,PCI_ANY_ID},
- {PCI_VENDOR_ID_WINBOND2, PCI_DEVICE_ID_WINBOND2_6692, PCI_ANY_ID,PCI_ANY_ID},
+ {PCI_VDEVICE(DYNALINK, PCI_DEVICE_ID_DYNALINK_IS64PH) },
+ {PCI_VDEVICE(WINBOND2, PCI_DEVICE_ID_WINBOND2_6692) },
#endif
#ifdef CONFIG_HISAX_HFC_PCI
- {PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_2BD0, PCI_ANY_ID, PCI_ANY_ID},
- {PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B000, PCI_ANY_ID, PCI_ANY_ID},
- {PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B006, PCI_ANY_ID, PCI_ANY_ID},
- {PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B007, PCI_ANY_ID, PCI_ANY_ID},
- {PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B008, PCI_ANY_ID, PCI_ANY_ID},
- {PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B009, PCI_ANY_ID, PCI_ANY_ID},
- {PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B00A, PCI_ANY_ID, PCI_ANY_ID},
- {PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B00B, PCI_ANY_ID, PCI_ANY_ID},
- {PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B00C, PCI_ANY_ID, PCI_ANY_ID},
- {PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B100, PCI_ANY_ID, PCI_ANY_ID},
- {PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B700, PCI_ANY_ID, PCI_ANY_ID},
- {PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B701, PCI_ANY_ID, PCI_ANY_ID},
- {PCI_VENDOR_ID_ABOCOM, PCI_DEVICE_ID_ABOCOM_2BD1, PCI_ANY_ID, PCI_ANY_ID},
- {PCI_VENDOR_ID_ASUSTEK, PCI_DEVICE_ID_ASUSTEK_0675, PCI_ANY_ID, PCI_ANY_ID},
- {PCI_VENDOR_ID_BERKOM, PCI_DEVICE_ID_BERKOM_T_CONCEPT, PCI_ANY_ID, PCI_ANY_ID},
- {PCI_VENDOR_ID_BERKOM, PCI_DEVICE_ID_BERKOM_A1T, PCI_ANY_ID, PCI_ANY_ID},
- {PCI_VENDOR_ID_ANIGMA, PCI_DEVICE_ID_ANIGMA_MC145575, PCI_ANY_ID, PCI_ANY_ID},
- {PCI_VENDOR_ID_ZOLTRIX, PCI_DEVICE_ID_ZOLTRIX_2BD0, PCI_ANY_ID, PCI_ANY_ID},
- {PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_DIGI_DF_M_IOM2_E, PCI_ANY_ID, PCI_ANY_ID},
- {PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_DIGI_DF_M_E, PCI_ANY_ID, PCI_ANY_ID},
- {PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_DIGI_DF_M_IOM2_A, PCI_ANY_ID, PCI_ANY_ID},
- {PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_DIGI_DF_M_A, PCI_ANY_ID, PCI_ANY_ID},
+ {PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_2BD0) },
+ {PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_B000) },
+ {PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_B006) },
+ {PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_B007) },
+ {PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_B008) },
+ {PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_B009) },
+ {PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_B00A) },
+ {PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_B00B) },
+ {PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_B00C) },
+ {PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_B100) },
+ {PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_B700) },
+ {PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_B701) },
+ {PCI_VDEVICE(ABOCOM, PCI_DEVICE_ID_ABOCOM_2BD1) },
+ {PCI_VDEVICE(ASUSTEK, PCI_DEVICE_ID_ASUSTEK_0675) },
+ {PCI_VDEVICE(BERKOM, PCI_DEVICE_ID_BERKOM_T_CONCEPT) },
+ {PCI_VDEVICE(BERKOM, PCI_DEVICE_ID_BERKOM_A1T) },
+ {PCI_VDEVICE(ANIGMA, PCI_DEVICE_ID_ANIGMA_MC145575) },
+ {PCI_VDEVICE(ZOLTRIX, PCI_DEVICE_ID_ZOLTRIX_2BD0) },
+ {PCI_VDEVICE(DIGI, PCI_DEVICE_ID_DIGI_DF_M_IOM2_E) },
+ {PCI_VDEVICE(DIGI, PCI_DEVICE_ID_DIGI_DF_M_E) },
+ {PCI_VDEVICE(DIGI, PCI_DEVICE_ID_DIGI_DF_M_IOM2_A) },
+ {PCI_VDEVICE(DIGI, PCI_DEVICE_ID_DIGI_DF_M_A) },
#endif
{ } /* Terminating entry */
};
diff --git a/drivers/isdn/hisax/elsa_cs.c b/drivers/isdn/hisax/elsa_cs.c
index 218927e3a4e..b3c08aaf41c 100644
--- a/drivers/isdn/hisax/elsa_cs.c
+++ b/drivers/isdn/hisax/elsa_cs.c
@@ -46,7 +46,6 @@
#include <asm/io.h>
#include <asm/system.h>
-#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/cistpl.h>
#include <pcmcia/cisreg.h>
@@ -127,9 +126,8 @@ static int __devinit elsa_cs_probe(struct pcmcia_device *link)
and attributes of IO windows) are fixed by the nature of the
device, and can be hard-wired here.
*/
- link->io.NumPorts1 = 8;
- link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
- link->io.IOAddrLines = 3;
+ link->resource[0]->end = 8;
+ link->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO;
link->conf.Attributes = CONF_ENABLE_IRQ;
link->conf.IntType = INT_MEMORY_AND_IO;
@@ -174,16 +172,18 @@ static int elsa_cs_configcheck(struct pcmcia_device *p_dev,
{
int j;
+ p_dev->io_lines = 3;
+
if ((cf->io.nwin > 0) && cf->io.win[0].base) {
printk(KERN_INFO "(elsa_cs: looks like the 96 model)\n");
- p_dev->io.BasePort1 = cf->io.win[0].base;
- if (!pcmcia_request_io(p_dev, &p_dev->io))
+ p_dev->resource[0]->start = cf->io.win[0].base;
+ if (!pcmcia_request_io(p_dev))
return 0;
} else {
printk(KERN_INFO "(elsa_cs: looks like the 97 model)\n");
for (j = 0x2f0; j > 0x100; j -= 0x10) {
- p_dev->io.BasePort1 = j;
- if (!pcmcia_request_io(p_dev, &p_dev->io))
+ p_dev->resource[0]->start = j;
+ if (!pcmcia_request_io(p_dev))
return 0;
}
}
@@ -215,23 +215,21 @@ static int __devinit elsa_cs_config(struct pcmcia_device *link)
link->conf.ConfigIndex);
if (link->conf.Attributes & CONF_ENABLE_IRQ)
printk(", irq %d", link->irq);
- if (link->io.NumPorts1)
- printk(", io 0x%04x-0x%04x", link->io.BasePort1,
- link->io.BasePort1+link->io.NumPorts1-1);
- if (link->io.NumPorts2)
- printk(" & 0x%04x-0x%04x", link->io.BasePort2,
- link->io.BasePort2+link->io.NumPorts2-1);
+ if (link->resource[0])
+ printk(" & %pR", link->resource[0]);
+ if (link->resource[1])
+ printk(" & %pR", link->resource[1]);
printk("\n");
icard.para[0] = link->irq;
- icard.para[1] = link->io.BasePort1;
+ icard.para[1] = link->resource[0]->start;
icard.protocol = protocol;
icard.typ = ISDN_CTYPE_ELSA_PCMCIA;
i = hisax_init_pcmcia(link, &(((local_info_t*)link->priv)->busy), &icard);
if (i < 0) {
- printk(KERN_ERR "elsa_cs: failed to initialize Elsa PCMCIA %d at i/o %#x\n",
- i, link->io.BasePort1);
+ printk(KERN_ERR "elsa_cs: failed to initialize Elsa "
+ "PCMCIA %d with %pR\n", i, link->resource[0]);
elsa_cs_release(link);
} else
((local_info_t*)link->priv)->cardnr = i;
diff --git a/drivers/isdn/hisax/q931.c b/drivers/isdn/hisax/q931.c
index 8b853d58e82..c0771f98fa1 100644
--- a/drivers/isdn/hisax/q931.c
+++ b/drivers/isdn/hisax/q931.c
@@ -1152,20 +1152,11 @@ QuickHex(char *txt, u_char * p, int cnt)
{
register int i;
register char *t = txt;
- register u_char w;
for (i = 0; i < cnt; i++) {
*t++ = ' ';
- w = (p[i] >> 4) & 0x0f;
- if (w < 10)
- *t++ = '0' + w;
- else
- *t++ = 'A' - 10 + w;
- w = p[i] & 0x0f;
- if (w < 10)
- *t++ = '0' + w;
- else
- *t++ = 'A' - 10 + w;
+ *t++ = hex_asc_hi(p[i]);
+ *t++ = hex_asc_lo(p[i]);
}
*t++ = 0;
return (t - txt);
diff --git a/drivers/isdn/hisax/sedlbauer_cs.c b/drivers/isdn/hisax/sedlbauer_cs.c
index 1f4feaab21a..a024192b672 100644
--- a/drivers/isdn/hisax/sedlbauer_cs.c
+++ b/drivers/isdn/hisax/sedlbauer_cs.c
@@ -46,7 +46,6 @@
#include <asm/io.h>
#include <asm/system.h>
-#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/cistpl.h>
#include <pcmcia/cisreg.h>
@@ -130,9 +129,8 @@ static int __devinit sedlbauer_probe(struct pcmcia_device *link)
/* from old sedl_cs
*/
/* The io structure describes IO port mapping */
- link->io.NumPorts1 = 8;
- link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
- link->io.IOAddrLines = 3;
+ link->resource[0]->end = 8;
+ link->resource[0]->flags |= IO_DATA_PATH_WIDTH_8;
link->conf.Attributes = 0;
link->conf.IntType = INT_MEMORY_AND_IO;
@@ -173,8 +171,6 @@ static int sedlbauer_config_check(struct pcmcia_device *p_dev,
unsigned int vcc,
void *priv_data)
{
- win_req_t *req = priv_data;
-
if (cfg->index == 0)
return -ENODEV;
@@ -202,52 +198,25 @@ static int sedlbauer_config_check(struct pcmcia_device *p_dev,
p_dev->conf.Attributes |= CONF_ENABLE_IRQ;
/* IO window settings */
- p_dev->io.NumPorts1 = p_dev->io.NumPorts2 = 0;
+ p_dev->resource[0]->end = p_dev->resource[1]->end = 0;
if ((cfg->io.nwin > 0) || (dflt->io.nwin > 0)) {
cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt->io;
- p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
- if (!(io->flags & CISTPL_IO_8BIT))
- p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_16;
- if (!(io->flags & CISTPL_IO_16BIT))
- p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
- p_dev->io.BasePort1 = io->win[0].base;
- p_dev->io.NumPorts1 = io->win[0].len;
+ p_dev->resource[0]->start = io->win[0].base;
+ p_dev->resource[0]->end = io->win[0].len;
+ p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH;
+ p_dev->resource[0]->flags |=
+ pcmcia_io_cfg_data_width(io->flags);
if (io->nwin > 1) {
- p_dev->io.Attributes2 = p_dev->io.Attributes1;
- p_dev->io.BasePort2 = io->win[1].base;
- p_dev->io.NumPorts2 = io->win[1].len;
+ p_dev->resource[1]->flags = p_dev->resource[0]->flags;
+ p_dev->resource[1]->start = io->win[1].base;
+ p_dev->resource[1]->end = io->win[1].len;
}
/* This reserves IO space but doesn't actually enable it */
- if (pcmcia_request_io(p_dev, &p_dev->io) != 0)
+ p_dev->io_lines = 3;
+ if (pcmcia_request_io(p_dev) != 0)
return -ENODEV;
}
- /*
- Now set up a common memory window, if needed. There is room
- in the struct pcmcia_device structure for one memory window handle,
- but if the base addresses need to be saved, or if multiple
- windows are needed, the info should go in the private data
- structure for this device.
-
- Note that the memory window base is a physical address, and
- needs to be mapped to virtual space with ioremap() before it
- is used.
- */
- if ((cfg->mem.nwin > 0) || (dflt->mem.nwin > 0)) {
- cistpl_mem_t *mem = (cfg->mem.nwin) ? &cfg->mem : &dflt->mem;
- memreq_t map;
- req->Attributes = WIN_DATA_WIDTH_16|WIN_MEMORY_TYPE_CM;
- req->Attributes |= WIN_ENABLE;
- req->Base = mem->win[0].host_addr;
- req->Size = mem->win[0].len;
- req->AccessSpeed = 0;
- if (pcmcia_request_window(p_dev, req, &p_dev->win) != 0)
- return -ENODEV;
- map.Page = 0;
- map.CardOffset = mem->win[0].card_addr;
- if (pcmcia_map_mem_page(p_dev, p_dev->win, &map) != 0)
- return -ENODEV;
- }
return 0;
}
@@ -255,16 +224,11 @@ static int sedlbauer_config_check(struct pcmcia_device *p_dev,
static int __devinit sedlbauer_config(struct pcmcia_device *link)
{
- win_req_t *req;
int ret;
IsdnCard_t icard;
dev_dbg(&link->dev, "sedlbauer_config(0x%p)\n", link);
- req = kzalloc(sizeof(win_req_t), GFP_KERNEL);
- if (!req)
- return -ENOMEM;
-
/*
In this loop, we scan the CIS for configuration table entries,
each of which describes a valid card configuration, including
@@ -277,7 +241,7 @@ static int __devinit sedlbauer_config(struct pcmcia_device *link)
these things without consulting the CIS, and most client drivers
will only use the CIS to fill in implementation-defined details.
*/
- ret = pcmcia_loop_config(link, sedlbauer_config_check, req);
+ ret = pcmcia_loop_config(link, sedlbauer_config_check, NULL);
if (ret)
goto failed;
@@ -297,27 +261,22 @@ static int __devinit sedlbauer_config(struct pcmcia_device *link)
printk(", Vpp %d.%d", link->conf.Vpp/10, link->conf.Vpp%10);
if (link->conf.Attributes & CONF_ENABLE_IRQ)
printk(", irq %d", link->irq);
- if (link->io.NumPorts1)
- printk(", io 0x%04x-0x%04x", link->io.BasePort1,
- link->io.BasePort1+link->io.NumPorts1-1);
- if (link->io.NumPorts2)
- printk(" & 0x%04x-0x%04x", link->io.BasePort2,
- link->io.BasePort2+link->io.NumPorts2-1);
- if (link->win)
- printk(", mem 0x%06lx-0x%06lx", req->Base,
- req->Base+req->Size-1);
+ if (link->resource[0])
+ printk(" & %pR", link->resource[0]);
+ if (link->resource[1])
+ printk(" & %pR", link->resource[1]);
printk("\n");
icard.para[0] = link->irq;
- icard.para[1] = link->io.BasePort1;
+ icard.para[1] = link->resource[0]->start;
icard.protocol = protocol;
icard.typ = ISDN_CTYPE_SEDLBAUER_PCMCIA;
ret = hisax_init_pcmcia(link,
&(((local_info_t *)link->priv)->stop), &icard);
if (ret < 0) {
- printk(KERN_ERR "sedlbauer_cs: failed to initialize SEDLBAUER PCMCIA %d at i/o %#x\n",
- ret, link->io.BasePort1);
+ printk(KERN_ERR "sedlbauer_cs: failed to initialize SEDLBAUER PCMCIA %d with %pR\n",
+ ret, link->resource[0]);
sedlbauer_release(link);
return -ENODEV;
} else
diff --git a/drivers/isdn/hisax/tei.c b/drivers/isdn/hisax/tei.c
index f4cb178b066..842f9c9e875 100644
--- a/drivers/isdn/hisax/tei.c
+++ b/drivers/isdn/hisax/tei.c
@@ -130,7 +130,7 @@ tei_id_request(struct FsmInst *fi, int event, void *arg)
if (st->l2.tei != -1) {
st->ma.tei_m.printdebug(&st->ma.tei_m,
- "assign request for allready asigned tei %d",
+ "assign request for already asigned tei %d",
st->l2.tei);
return;
}
diff --git a/drivers/isdn/hisax/teles_cs.c b/drivers/isdn/hisax/teles_cs.c
index 5771955cc53..7296102ca25 100644
--- a/drivers/isdn/hisax/teles_cs.c
+++ b/drivers/isdn/hisax/teles_cs.c
@@ -27,7 +27,6 @@
#include <asm/io.h>
#include <asm/system.h>
-#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/cistpl.h>
#include <pcmcia/cisreg.h>
@@ -107,9 +106,8 @@ static int __devinit teles_probe(struct pcmcia_device *link)
and attributes of IO windows) are fixed by the nature of the
device, and can be hard-wired here.
*/
- link->io.NumPorts1 = 96;
- link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
- link->io.IOAddrLines = 5;
+ link->resource[0]->end = 96;
+ link->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO;
link->conf.Attributes = CONF_ENABLE_IRQ;
link->conf.IntType = INT_MEMORY_AND_IO;
@@ -154,16 +152,18 @@ static int teles_cs_configcheck(struct pcmcia_device *p_dev,
{
int j;
+ p_dev->io_lines = 5;
+
if ((cf->io.nwin > 0) && cf->io.win[0].base) {
printk(KERN_INFO "(teles_cs: looks like the 96 model)\n");
- p_dev->io.BasePort1 = cf->io.win[0].base;
- if (!pcmcia_request_io(p_dev, &p_dev->io))
+ p_dev->resource[0]->start = cf->io.win[0].base;
+ if (!pcmcia_request_io(p_dev))
return 0;
} else {
printk(KERN_INFO "(teles_cs: looks like the 97 model)\n");
for (j = 0x2f0; j > 0x100; j -= 0x10) {
- p_dev->io.BasePort1 = j;
- if (!pcmcia_request_io(p_dev, &p_dev->io))
+ p_dev->resource[0]->start = j;
+ if (!pcmcia_request_io(p_dev))
return 0;
}
}
@@ -195,23 +195,21 @@ static int __devinit teles_cs_config(struct pcmcia_device *link)
link->conf.ConfigIndex);
if (link->conf.Attributes & CONF_ENABLE_IRQ)
printk(", irq %d", link->irq);
- if (link->io.NumPorts1)
- printk(", io 0x%04x-0x%04x", link->io.BasePort1,
- link->io.BasePort1+link->io.NumPorts1-1);
- if (link->io.NumPorts2)
- printk(" & 0x%04x-0x%04x", link->io.BasePort2,
- link->io.BasePort2+link->io.NumPorts2-1);
+ if (link->resource[0])
+ printk(" & %pR", link->resource[0]);
+ if (link->resource[1])
+ printk(" & %pR", link->resource[1]);
printk("\n");
icard.para[0] = link->irq;
- icard.para[1] = link->io.BasePort1;
+ icard.para[1] = link->resource[0]->start;
icard.protocol = protocol;
icard.typ = ISDN_CTYPE_TELESPCMCIA;
i = hisax_init_pcmcia(link, &(((local_info_t*)link->priv)->busy), &icard);
if (i < 0) {
printk(KERN_ERR "teles_cs: failed to initialize Teles PCMCIA %d at i/o %#x\n",
- i, link->io.BasePort1);
+ i, (unsigned int) link->resource[0]->start);
teles_cs_release(link);
return -ENODEV;
}
diff --git a/drivers/isdn/hysdn/hysdn_procconf.c b/drivers/isdn/hysdn/hysdn_procconf.c
index 80966462d6d..96b3e39c335 100644
--- a/drivers/isdn/hysdn/hysdn_procconf.c
+++ b/drivers/isdn/hysdn/hysdn_procconf.c
@@ -17,11 +17,12 @@
#include <linux/proc_fs.h>
#include <linux/pci.h>
#include <linux/slab.h>
-#include <linux/smp_lock.h>
+#include <linux/mutex.h>
#include <net/net_namespace.h>
#include "hysdn_defs.h"
+static DEFINE_MUTEX(hysdn_conf_mutex);
static char *hysdn_procconf_revision = "$Revision: 1.8.6.4 $";
#define INFO_OUT_LEN 80 /* length of info line including lf */
@@ -234,7 +235,7 @@ hysdn_conf_open(struct inode *ino, struct file *filep)
char *cp, *tmp;
/* now search the addressed card */
- lock_kernel();
+ mutex_lock(&hysdn_conf_mutex);
card = card_root;
while (card) {
pd = card->procconf;
@@ -243,7 +244,7 @@ hysdn_conf_open(struct inode *ino, struct file *filep)
card = card->next; /* search next entry */
}
if (!card) {
- unlock_kernel();
+ mutex_unlock(&hysdn_conf_mutex);
return (-ENODEV); /* device is unknown/invalid */
}
if (card->debug_flags & (LOG_PROC_OPEN | LOG_PROC_ALL))
@@ -255,7 +256,7 @@ hysdn_conf_open(struct inode *ino, struct file *filep)
/* write only access -> write boot file or conf line */
if (!(cnf = kmalloc(sizeof(struct conf_writedata), GFP_KERNEL))) {
- unlock_kernel();
+ mutex_unlock(&hysdn_conf_mutex);
return (-EFAULT);
}
cnf->card = card;
@@ -267,7 +268,7 @@ hysdn_conf_open(struct inode *ino, struct file *filep)
/* read access -> output card info data */
if (!(tmp = kmalloc(INFO_OUT_LEN * 2 + 2, GFP_KERNEL))) {
- unlock_kernel();
+ mutex_unlock(&hysdn_conf_mutex);
return (-EFAULT); /* out of memory */
}
filep->private_data = tmp; /* start of string */
@@ -301,10 +302,10 @@ hysdn_conf_open(struct inode *ino, struct file *filep)
*cp++ = '\n';
*cp = 0; /* end of string */
} else { /* simultaneous read/write access forbidden ! */
- unlock_kernel();
+ mutex_unlock(&hysdn_conf_mutex);
return (-EPERM); /* no permission this time */
}
- unlock_kernel();
+ mutex_unlock(&hysdn_conf_mutex);
return nonseekable_open(ino, filep);
} /* hysdn_conf_open */
@@ -319,7 +320,7 @@ hysdn_conf_close(struct inode *ino, struct file *filep)
int retval = 0;
struct proc_dir_entry *pd;
- lock_kernel();
+ mutex_lock(&hysdn_conf_mutex);
/* search the addressed card */
card = card_root;
while (card) {
@@ -329,7 +330,7 @@ hysdn_conf_close(struct inode *ino, struct file *filep)
card = card->next; /* search next entry */
}
if (!card) {
- unlock_kernel();
+ mutex_unlock(&hysdn_conf_mutex);
return (-ENODEV); /* device is unknown/invalid */
}
if (card->debug_flags & (LOG_PROC_OPEN | LOG_PROC_ALL))
@@ -352,7 +353,7 @@ hysdn_conf_close(struct inode *ino, struct file *filep)
kfree(filep->private_data); /* release memory */
}
- unlock_kernel();
+ mutex_unlock(&hysdn_conf_mutex);
return (retval);
} /* hysdn_conf_close */
diff --git a/drivers/isdn/hysdn/hysdn_proclog.c b/drivers/isdn/hysdn/hysdn_proclog.c
index e83f6fda32f..2ee93d04b2d 100644
--- a/drivers/isdn/hysdn/hysdn_proclog.c
+++ b/drivers/isdn/hysdn/hysdn_proclog.c
@@ -15,13 +15,15 @@
#include <linux/proc_fs.h>
#include <linux/sched.h>
#include <linux/slab.h>
-#include <linux/smp_lock.h>
+#include <linux/mutex.h>
+#include <linux/kernel.h>
#include "hysdn_defs.h"
/* the proc subdir for the interface is defined in the procconf module */
extern struct proc_dir_entry *hysdn_proc_entry;
+static DEFINE_MUTEX(hysdn_log_mutex);
static void put_log_buffer(hysdn_card * card, char *cp);
/*************************************************/
@@ -154,10 +156,9 @@ static ssize_t
hysdn_log_write(struct file *file, const char __user *buf, size_t count, loff_t * off)
{
unsigned long u = 0;
- int found = 0;
- unsigned char *cp, valbuf[128];
- long base = 10;
- hysdn_card *card = (hysdn_card *) file->private_data;
+ int rc;
+ unsigned char valbuf[128];
+ hysdn_card *card = file->private_data;
if (count > (sizeof(valbuf) - 1))
count = sizeof(valbuf) - 1; /* limit length */
@@ -165,32 +166,10 @@ hysdn_log_write(struct file *file, const char __user *buf, size_t count, loff_t
return (-EFAULT); /* copy failed */
valbuf[count] = 0; /* terminating 0 */
- cp = valbuf;
- if ((count > 2) && (valbuf[0] == '0') && (valbuf[1] == 'x')) {
- cp += 2; /* pointer after hex modifier */
- base = 16;
- }
- /* scan the input for debug flags */
- while (*cp) {
- if ((*cp >= '0') && (*cp <= '9')) {
- found = 1;
- u *= base; /* adjust to next digit */
- u += *cp++ - '0';
- continue;
- }
- if (base != 16)
- break; /* end of number */
-
- if ((*cp >= 'a') && (*cp <= 'f')) {
- found = 1;
- u *= base; /* adjust to next digit */
- u += *cp++ - 'a' + 10;
- continue;
- }
- break; /* terminated */
- }
- if (found) {
+ rc = strict_strtoul(valbuf, 0, &u);
+
+ if (rc == 0) {
card->debug_flags = u; /* remember debug flags */
hysdn_addlog(card, "debug set to 0x%lx", card->debug_flags);
}
@@ -251,7 +230,7 @@ hysdn_log_open(struct inode *ino, struct file *filep)
struct procdata *pd = NULL;
unsigned long flags;
- lock_kernel();
+ mutex_lock(&hysdn_log_mutex);
card = card_root;
while (card) {
pd = card->proclog;
@@ -260,7 +239,7 @@ hysdn_log_open(struct inode *ino, struct file *filep)
card = card->next; /* search next entry */
}
if (!card) {
- unlock_kernel();
+ mutex_unlock(&hysdn_log_mutex);
return (-ENODEV); /* device is unknown/invalid */
}
filep->private_data = card; /* remember our own card */
@@ -278,10 +257,10 @@ hysdn_log_open(struct inode *ino, struct file *filep)
filep->private_data = &pd->log_head;
spin_unlock_irqrestore(&card->hysdn_lock, flags);
} else { /* simultaneous read/write access forbidden ! */
- unlock_kernel();
+ mutex_unlock(&hysdn_log_mutex);
return (-EPERM); /* no permission this time */
}
- unlock_kernel();
+ mutex_unlock(&hysdn_log_mutex);
return nonseekable_open(ino, filep);
} /* hysdn_log_open */
@@ -300,7 +279,7 @@ hysdn_log_close(struct inode *ino, struct file *filep)
hysdn_card *card;
int retval = 0;
- lock_kernel();
+ mutex_lock(&hysdn_log_mutex);
if ((filep->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_WRITE) {
/* write only access -> write debug level written */
retval = 0; /* success */
@@ -339,7 +318,7 @@ hysdn_log_close(struct inode *ino, struct file *filep)
kfree(inf);
}
} /* read access */
- unlock_kernel();
+ mutex_unlock(&hysdn_log_mutex);
return (retval);
} /* hysdn_log_close */
diff --git a/drivers/isdn/i4l/isdn_common.c b/drivers/isdn/i4l/isdn_common.c
index a44cdb492ea..15632bd2f64 100644
--- a/drivers/isdn/i4l/isdn_common.c
+++ b/drivers/isdn/i4l/isdn_common.c
@@ -17,7 +17,7 @@
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/isdn.h>
-#include <linux/smp_lock.h>
+#include <linux/mutex.h>
#include "isdn_common.h"
#include "isdn_tty.h"
#include "isdn_net.h"
@@ -42,6 +42,7 @@ MODULE_LICENSE("GPL");
isdn_dev *dev;
+static DEFINE_MUTEX(isdn_mutex);
static char *isdn_revision = "$Revision: 1.1.2.3 $";
extern char *isdn_net_revision;
@@ -1070,7 +1071,7 @@ isdn_read(struct file *file, char __user *buf, size_t count, loff_t * off)
int retval;
char *p;
- lock_kernel();
+ mutex_lock(&isdn_mutex);
if (minor == ISDN_MINOR_STATUS) {
if (!file->private_data) {
if (file->f_flags & O_NONBLOCK) {
@@ -1163,7 +1164,7 @@ isdn_read(struct file *file, char __user *buf, size_t count, loff_t * off)
#endif
retval = -ENODEV;
out:
- unlock_kernel();
+ mutex_unlock(&isdn_mutex);
return retval;
}
@@ -1180,7 +1181,7 @@ isdn_write(struct file *file, const char __user *buf, size_t count, loff_t * off
if (!dev->drivers)
return -ENODEV;
- lock_kernel();
+ mutex_lock(&isdn_mutex);
if (minor <= ISDN_MINOR_BMAX) {
printk(KERN_WARNING "isdn_write minor %d obsolete!\n", minor);
drvidx = isdn_minor2drv(minor);
@@ -1225,7 +1226,7 @@ isdn_write(struct file *file, const char __user *buf, size_t count, loff_t * off
#endif
retval = -ENODEV;
out:
- unlock_kernel();
+ mutex_unlock(&isdn_mutex);
return retval;
}
@@ -1236,7 +1237,7 @@ isdn_poll(struct file *file, poll_table * wait)
unsigned int minor = iminor(file->f_path.dentry->d_inode);
int drvidx = isdn_minor2drv(minor - ISDN_MINOR_CTRL);
- lock_kernel();
+ mutex_lock(&isdn_mutex);
if (minor == ISDN_MINOR_STATUS) {
poll_wait(file, &(dev->info_waitq), wait);
/* mask = POLLOUT | POLLWRNORM; */
@@ -1266,7 +1267,7 @@ isdn_poll(struct file *file, poll_table * wait)
#endif
mask = POLLERR;
out:
- unlock_kernel();
+ mutex_unlock(&isdn_mutex);
return mask;
}
@@ -1727,9 +1728,9 @@ isdn_unlocked_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
int ret;
- lock_kernel();
+ mutex_lock(&isdn_mutex);
ret = isdn_ioctl(file, cmd, arg);
- unlock_kernel();
+ mutex_unlock(&isdn_mutex);
return ret;
}
@@ -1745,7 +1746,7 @@ isdn_open(struct inode *ino, struct file *filep)
int chidx;
int retval = -ENODEV;
- lock_kernel();
+ mutex_lock(&isdn_mutex);
if (minor == ISDN_MINOR_STATUS) {
infostruct *p;
@@ -1796,7 +1797,7 @@ isdn_open(struct inode *ino, struct file *filep)
#endif
out:
nonseekable_open(ino, filep);
- unlock_kernel();
+ mutex_unlock(&isdn_mutex);
return retval;
}
@@ -1805,7 +1806,7 @@ isdn_close(struct inode *ino, struct file *filep)
{
uint minor = iminor(ino);
- lock_kernel();
+ mutex_lock(&isdn_mutex);
if (minor == ISDN_MINOR_STATUS) {
infostruct *p = dev->infochain;
infostruct *q = NULL;
@@ -1839,7 +1840,7 @@ isdn_close(struct inode *ino, struct file *filep)
#endif
out:
- unlock_kernel();
+ mutex_unlock(&isdn_mutex);
return 0;
}
diff --git a/drivers/isdn/i4l/isdn_net.c b/drivers/isdn/i4l/isdn_net.c
index 8c85d1e88cc..26d44c3ca1d 100644
--- a/drivers/isdn/i4l/isdn_net.c
+++ b/drivers/isdn/i4l/isdn_net.c
@@ -2924,16 +2924,17 @@ isdn_net_getcfg(isdn_net_ioctl_cfg * cfg)
cfg->dialtimeout = lp->dialtimeout >= 0 ? lp->dialtimeout / HZ : -1;
cfg->dialwait = lp->dialwait / HZ;
if (lp->slave) {
- if (strlen(lp->slave->name) > 8)
+ if (strlen(lp->slave->name) >= 10)
strcpy(cfg->slave, "too-long");
else
strcpy(cfg->slave, lp->slave->name);
} else
cfg->slave[0] = '\0';
if (lp->master) {
- if (strlen(lp->master->name) > 8)
+ if (strlen(lp->master->name) >= 10)
strcpy(cfg->master, "too-long");
- strcpy(cfg->master, lp->master->name);
+ else
+ strcpy(cfg->master, lp->master->name);
} else
cfg->master[0] = '\0';
return 0;
diff --git a/drivers/isdn/i4l/isdn_ppp.c b/drivers/isdn/i4l/isdn_ppp.c
index f37b8f68d0a..fe824e0cbb2 100644
--- a/drivers/isdn/i4l/isdn_ppp.c
+++ b/drivers/isdn/i4l/isdn_ppp.c
@@ -449,14 +449,9 @@ static int get_filter(void __user *arg, struct sock_filter **p)
/* uprog.len is unsigned short, so no overflow here */
len = uprog.len * sizeof(struct sock_filter);
- code = kmalloc(len, GFP_KERNEL);
- if (code == NULL)
- return -ENOMEM;
-
- if (copy_from_user(code, uprog.filter, len)) {
- kfree(code);
- return -EFAULT;
- }
+ code = memdup_user(uprog.filter, len);
+ if (IS_ERR(code))
+ return PTR_ERR(code);
err = sk_chk_filter(code, uprog.len);
if (err) {
@@ -482,7 +477,7 @@ isdn_ppp_ioctl(int min, struct file *file, unsigned int cmd, unsigned long arg)
struct isdn_ppp_comp_data data;
void __user *argp = (void __user *)arg;
- is = (struct ippp_struct *) file->private_data;
+ is = file->private_data;
lp = is->lp;
if (is->debug & 0x1)
diff --git a/drivers/isdn/i4l/isdn_tty.c b/drivers/isdn/i4l/isdn_tty.c
index fc8454d2eea..51dc60da333 100644
--- a/drivers/isdn/i4l/isdn_tty.c
+++ b/drivers/isdn/i4l/isdn_tty.c
@@ -2636,12 +2636,6 @@ isdn_tty_modem_result(int code, modem_info * info)
if ((info->flags & ISDN_ASYNC_CLOSING) || (!info->tty)) {
return;
}
-#ifdef CONFIG_ISDN_AUDIO
- if ( !info->vonline )
- tty_ldisc_flush(info->tty);
-#else
- tty_ldisc_flush(info->tty);
-#endif
if ((info->flags & ISDN_ASYNC_CHECK_CD) &&
(!((info->flags & ISDN_ASYNC_CALLOUT_ACTIVE) &&
(info->flags & ISDN_ASYNC_CALLOUT_NOHUP)))) {
diff --git a/drivers/isdn/mISDN/tei.c b/drivers/isdn/mISDN/tei.c
index 34e898fe2f4..1b85d9d2749 100644
--- a/drivers/isdn/mISDN/tei.c
+++ b/drivers/isdn/mISDN/tei.c
@@ -457,7 +457,7 @@ tei_id_request(struct FsmInst *fi, int event, void *arg)
if (tm->l2->tei != GROUP_TEI) {
tm->tei_m.printdebug(&tm->tei_m,
- "assign request for allready assigned tei %d",
+ "assign request for already assigned tei %d",
tm->l2->tei);
return;
}
diff --git a/drivers/isdn/mISDN/timerdev.c b/drivers/isdn/mISDN/timerdev.c
index 81048b8ed8a..de43c8c70ad 100644
--- a/drivers/isdn/mISDN/timerdev.c
+++ b/drivers/isdn/mISDN/timerdev.c
@@ -24,9 +24,10 @@
#include <linux/miscdevice.h>
#include <linux/module.h>
#include <linux/mISDNif.h>
-#include <linux/smp_lock.h>
+#include <linux/mutex.h>
#include "core.h"
+static DEFINE_MUTEX(mISDN_mutex);
static u_int *debug;
@@ -224,7 +225,7 @@ mISDN_ioctl(struct file *filep, unsigned int cmd, unsigned long arg)
if (*debug & DEBUG_TIMER)
printk(KERN_DEBUG "%s(%p, %x, %lx)\n", __func__,
filep, cmd, arg);
- lock_kernel();
+ mutex_lock(&mISDN_mutex);
switch (cmd) {
case IMADDTIMER:
if (get_user(tout, (int __user *)arg)) {
@@ -256,7 +257,7 @@ mISDN_ioctl(struct file *filep, unsigned int cmd, unsigned long arg)
default:
ret = -EINVAL;
}
- unlock_kernel();
+ mutex_unlock(&mISDN_mutex);
return ret;
}
diff --git a/drivers/isdn/pcbit/drv.c b/drivers/isdn/pcbit/drv.c
index 123c1d6c43b..1507d2e83fb 100644
--- a/drivers/isdn/pcbit/drv.c
+++ b/drivers/isdn/pcbit/drv.c
@@ -411,14 +411,10 @@ static int pcbit_writecmd(const u_char __user *buf, int len, int driver, int cha
return -EINVAL;
}
- cbuf = kmalloc(len, GFP_KERNEL);
- if (!cbuf)
- return -ENOMEM;
+ cbuf = memdup_user(buf, len);
+ if (IS_ERR(cbuf))
+ return PTR_ERR(cbuf);
- if (copy_from_user(cbuf, buf, len)) {
- kfree(cbuf);
- return -EFAULT;
- }
memcpy_toio(dev->sh_mem, cbuf, len);
kfree(cbuf);
return len;
diff --git a/drivers/isdn/sc/ioctl.c b/drivers/isdn/sc/ioctl.c
index 1081091bbfa..43c5dc3516e 100644
--- a/drivers/isdn/sc/ioctl.c
+++ b/drivers/isdn/sc/ioctl.c
@@ -215,19 +215,13 @@ int sc_ioctl(int card, scs_ioctl *data)
pr_debug("%s: DCBIOSETSPID: ioctl received\n",
sc_adapter[card]->devicename);
- spid = kmalloc(SCIOC_SPIDSIZE, GFP_KERNEL);
- if(!spid) {
- kfree(rcvmsg);
- return -ENOMEM;
- }
-
/*
* Get the spid from user space
*/
- if (copy_from_user(spid, data->dataptr, SCIOC_SPIDSIZE)) {
+ spid = memdup_user(data->dataptr, SCIOC_SPIDSIZE);
+ if (IS_ERR(spid)) {
kfree(rcvmsg);
- kfree(spid);
- return -EFAULT;
+ return PTR_ERR(spid);
}
pr_debug("%s: SCIOCSETSPID: setting channel %d spid to %s\n",
@@ -296,18 +290,13 @@ int sc_ioctl(int card, scs_ioctl *data)
pr_debug("%s: SCIOSETDN: ioctl received\n",
sc_adapter[card]->devicename);
- dn = kmalloc(SCIOC_DNSIZE, GFP_KERNEL);
- if (!dn) {
- kfree(rcvmsg);
- return -ENOMEM;
- }
/*
* Get the spid from user space
*/
- if (copy_from_user(dn, data->dataptr, SCIOC_DNSIZE)) {
+ dn = memdup_user(data->dataptr, SCIOC_DNSIZE);
+ if (IS_ERR(dn)) {
kfree(rcvmsg);
- kfree(dn);
- return -EFAULT;
+ return PTR_ERR(dn);
}
pr_debug("%s: SCIOCSETDN: setting channel %d dn to %s\n",
diff --git a/drivers/leds/leds-bd2802.c b/drivers/leds/leds-bd2802.c
index 5dcdf9d69b3..19dc4b61a10 100644
--- a/drivers/leds/leds-bd2802.c
+++ b/drivers/leds/leds-bd2802.c
@@ -351,7 +351,7 @@ static ssize_t bd2802_store_reg##reg_addr(struct device *dev, \
return count; \
} \
static struct device_attribute bd2802_reg##reg_addr##_attr = { \
- .attr = {.name = reg_name, .mode = 0644, .owner = THIS_MODULE}, \
+ .attr = {.name = reg_name, .mode = 0644}, \
.store = bd2802_store_reg##reg_addr, \
};
@@ -482,7 +482,6 @@ static struct device_attribute bd2802_adv_conf_attr = {
.attr = {
.name = "advanced_configuration",
.mode = 0644,
- .owner = THIS_MODULE
},
.show = bd2802_show_adv_conf,
.store = bd2802_store_adv_conf,
@@ -519,7 +518,6 @@ static struct device_attribute bd2802_##attr_name##_attr = { \
.attr = { \
.name = name_str, \
.mode = 0644, \
- .owner = THIS_MODULE \
}, \
.show = bd2802_show_##attr_name, \
.store = bd2802_store_##attr_name, \
diff --git a/drivers/macintosh/macio_sysfs.c b/drivers/macintosh/macio_sysfs.c
index 6999ce59fd1..6024038a5b9 100644
--- a/drivers/macintosh/macio_sysfs.c
+++ b/drivers/macintosh/macio_sysfs.c
@@ -41,10 +41,7 @@ compatible_show (struct device *dev, struct device_attribute *attr, char *buf)
static ssize_t modalias_show (struct device *dev, struct device_attribute *attr,
char *buf)
{
- struct of_device *ofdev = to_of_device(dev);
- int len;
-
- len = of_device_get_modalias(ofdev, buf, PAGE_SIZE - 2);
+ int len = of_device_get_modalias(dev, buf, PAGE_SIZE - 2);
buf[len] = '\n';
buf[len+1] = 0;
diff --git a/drivers/macintosh/via-pmu.c b/drivers/macintosh/via-pmu.c
index 3d4fc0f7b00..35bc2737412 100644
--- a/drivers/macintosh/via-pmu.c
+++ b/drivers/macintosh/via-pmu.c
@@ -400,11 +400,12 @@ static int __init via_pmu_start(void)
printk(KERN_ERR "via-pmu: can't map interrupt\n");
return -ENODEV;
}
- /* We set IRQF_TIMER because we don't want the interrupt to be disabled
- * between the 2 passes of driver suspend, we control our own disabling
- * for that one
+ /* We set IRQF_NO_SUSPEND because we don't want the interrupt
+ * to be disabled between the 2 passes of driver suspend, we
+ * control our own disabling for that one
*/
- if (request_irq(irq, via_pmu_interrupt, IRQF_TIMER, "VIA-PMU", (void *)0)) {
+ if (request_irq(irq, via_pmu_interrupt, IRQF_NO_SUSPEND,
+ "VIA-PMU", (void *)0)) {
printk(KERN_ERR "via-pmu: can't request irq %d\n", irq);
return -ENODEV;
}
diff --git a/drivers/media/IR/Kconfig b/drivers/media/IR/Kconfig
index d22a8ec523f..999a8250b3c 100644
--- a/drivers/media/IR/Kconfig
+++ b/drivers/media/IR/Kconfig
@@ -8,6 +8,17 @@ config VIDEO_IR
depends on IR_CORE
default IR_CORE
+config LIRC
+ tristate
+ default y
+
+ ---help---
+ Enable this option to build the Linux Infrared Remote
+ Control (LIRC) core device interface driver. The LIRC
+ interface passes raw IR to and from userspace, where the
+ LIRC daemon handles protocol decoding for IR reception ann
+ encoding for IR transmitting (aka "blasting").
+
source "drivers/media/IR/keymaps/Kconfig"
config IR_NEC_DECODER
@@ -33,6 +44,7 @@ config IR_RC5_DECODER
config IR_RC6_DECODER
tristate "Enable IR raw decoder for the RC6 protocol"
depends on IR_CORE
+ select BITREVERSE
default y
---help---
@@ -42,6 +54,7 @@ config IR_RC6_DECODER
config IR_JVC_DECODER
tristate "Enable IR raw decoder for the JVC protocol"
depends on IR_CORE
+ select BITREVERSE
default y
---help---
@@ -57,6 +70,16 @@ config IR_SONY_DECODER
Enable this option if you have an infrared remote control which
uses the Sony protocol, and you need software decoding support.
+config IR_LIRC_CODEC
+ tristate "Enable IR to LIRC bridge"
+ depends on IR_CORE
+ depends on LIRC
+ default y
+
+ ---help---
+ Enable this option to pass raw IR to and from userspace via
+ the LIRC interface.
+
config IR_IMON
tristate "SoundGraph iMON Receiver and Display"
depends on USB_ARCH_HAS_HCD
@@ -68,3 +91,15 @@ config IR_IMON
To compile this driver as a module, choose M here: the
module will be called imon.
+
+config IR_MCEUSB
+ tristate "Windows Media Center Ed. eHome Infrared Transceiver"
+ depends on USB_ARCH_HAS_HCD
+ depends on IR_CORE
+ select USB
+ ---help---
+ Say Y here if you want to use a Windows Media Center Edition
+ eHome Infrared Transceiver.
+
+ To compile this driver as a module, choose M here: the
+ module will be called mceusb.
diff --git a/drivers/media/IR/Makefile b/drivers/media/IR/Makefile
index b998fcced2e..2ae4f3abfdb 100644
--- a/drivers/media/IR/Makefile
+++ b/drivers/media/IR/Makefile
@@ -5,11 +5,14 @@ obj-y += keymaps/
obj-$(CONFIG_IR_CORE) += ir-core.o
obj-$(CONFIG_VIDEO_IR) += ir-common.o
+obj-$(CONFIG_LIRC) += lirc_dev.o
obj-$(CONFIG_IR_NEC_DECODER) += ir-nec-decoder.o
obj-$(CONFIG_IR_RC5_DECODER) += ir-rc5-decoder.o
obj-$(CONFIG_IR_RC6_DECODER) += ir-rc6-decoder.o
obj-$(CONFIG_IR_JVC_DECODER) += ir-jvc-decoder.o
obj-$(CONFIG_IR_SONY_DECODER) += ir-sony-decoder.o
+obj-$(CONFIG_IR_LIRC_CODEC) += ir-lirc-codec.o
# stand-alone IR receivers/transmitters
obj-$(CONFIG_IR_IMON) += imon.o
+obj-$(CONFIG_IR_MCEUSB) += mceusb.o
diff --git a/drivers/media/IR/imon.c b/drivers/media/IR/imon.c
index 4bbd45f4284..65c125e44e9 100644
--- a/drivers/media/IR/imon.c
+++ b/drivers/media/IR/imon.c
@@ -407,7 +407,7 @@ static int display_close(struct inode *inode, struct file *file)
struct imon_context *ictx = NULL;
int retval = 0;
- ictx = (struct imon_context *)file->private_data;
+ ictx = file->private_data;
if (!ictx) {
err("%s: no context for device", __func__);
@@ -812,7 +812,7 @@ static ssize_t vfd_write(struct file *file, const char *buf,
const unsigned char vfd_packet6[] = {
0x01, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF };
- ictx = (struct imon_context *)file->private_data;
+ ictx = file->private_data;
if (!ictx) {
err("%s: no context for device", __func__);
return -ENODEV;
@@ -896,7 +896,7 @@ static ssize_t lcd_write(struct file *file, const char *buf,
int retval = 0;
struct imon_context *ictx;
- ictx = (struct imon_context *)file->private_data;
+ ictx = file->private_data;
if (!ictx) {
err("%s: no context for device", __func__);
return -ENODEV;
@@ -1943,7 +1943,7 @@ static struct imon_context *imon_init_intf0(struct usb_interface *intf)
return ictx;
urb_submit_failed:
- input_unregister_device(ictx->idev);
+ ir_input_unregister(ictx->idev);
input_free_device(ictx->idev);
idev_setup_failed:
find_endpoint_failed:
@@ -2067,6 +2067,7 @@ static void imon_get_ffdc_type(struct imon_context *ictx)
detected_display_type = IMON_DISPLAY_TYPE_VFD;
break;
/* iMON LCD, MCE IR */
+ case 0x9e:
case 0x9f:
dev_info(ictx->dev, "0xffdc iMON LCD, MCE IR");
detected_display_type = IMON_DISPLAY_TYPE_LCD;
@@ -2306,7 +2307,7 @@ static void __devexit imon_disconnect(struct usb_interface *interface)
if (ifnum == 0) {
ictx->dev_present_intf0 = false;
usb_kill_urb(ictx->rx_urb_intf0);
- input_unregister_device(ictx->idev);
+ ir_input_unregister(ictx->idev);
if (ictx->display_supported) {
if (ictx->display_type == IMON_DISPLAY_TYPE_LCD)
usb_deregister_dev(interface, &imon_lcd_class);
diff --git a/drivers/media/IR/ir-core-priv.h b/drivers/media/IR/ir-core-priv.h
index 9a5e65a471a..babd52061bc 100644
--- a/drivers/media/IR/ir-core-priv.h
+++ b/drivers/media/IR/ir-core-priv.h
@@ -22,17 +22,62 @@
struct ir_raw_handler {
struct list_head list;
+ u64 protocols; /* which are handled by this handler */
int (*decode)(struct input_dev *input_dev, struct ir_raw_event event);
+
+ /* These two should only be used by the lirc decoder */
int (*raw_register)(struct input_dev *input_dev);
int (*raw_unregister)(struct input_dev *input_dev);
};
struct ir_raw_event_ctrl {
+ struct list_head list; /* to keep track of raw clients */
struct work_struct rx_work; /* for the rx decoding workqueue */
struct kfifo kfifo; /* fifo for the pulse/space durations */
ktime_t last_event; /* when last event occurred */
enum raw_event_type last_type; /* last event type */
struct input_dev *input_dev; /* pointer to the parent input_dev */
+ u64 enabled_protocols; /* enabled raw protocol decoders */
+
+ /* raw decoder state follows */
+ struct ir_raw_event prev_ev;
+ struct nec_dec {
+ int state;
+ unsigned count;
+ u32 bits;
+ } nec;
+ struct rc5_dec {
+ int state;
+ u32 bits;
+ unsigned count;
+ unsigned wanted_bits;
+ } rc5;
+ struct rc6_dec {
+ int state;
+ u8 header;
+ u32 body;
+ bool toggle;
+ unsigned count;
+ unsigned wanted_bits;
+ } rc6;
+ struct sony_dec {
+ int state;
+ u32 bits;
+ unsigned count;
+ } sony;
+ struct jvc_dec {
+ int state;
+ u16 bits;
+ u16 old_bits;
+ unsigned count;
+ bool first;
+ bool toggle;
+ } jvc;
+ struct lirc_codec {
+ struct ir_input_dev *ir_dev;
+ struct lirc_driver *drv;
+ int lircdata;
+ } lirc;
};
/* macros for IR decoders */
@@ -74,6 +119,7 @@ void ir_unregister_class(struct input_dev *input_dev);
/*
* Routines from ir-raw-event.c to be used internally and by decoders
*/
+u64 ir_raw_get_allowed_protocols(void);
int ir_raw_event_register(struct input_dev *input_dev);
void ir_raw_event_unregister(struct input_dev *input_dev);
int ir_raw_handler_register(struct ir_raw_handler *ir_raw_handler);
@@ -123,4 +169,12 @@ void ir_raw_init(void);
#define load_sony_decode() 0
#endif
+/* from ir-lirc-codec.c */
+#ifdef CONFIG_IR_LIRC_CODEC_MODULE
+#define load_lirc_codec() request_module("ir-lirc-codec")
+#else
+#define load_lirc_codec() 0
+#endif
+
+
#endif /* _IR_RAW_EVENT */
diff --git a/drivers/media/IR/ir-jvc-decoder.c b/drivers/media/IR/ir-jvc-decoder.c
index 0b804944cbb..8894d8b3604 100644
--- a/drivers/media/IR/ir-jvc-decoder.c
+++ b/drivers/media/IR/ir-jvc-decoder.c
@@ -25,10 +25,6 @@
#define JVC_TRAILER_PULSE (1 * JVC_UNIT)
#define JVC_TRAILER_SPACE (35 * JVC_UNIT)
-/* Used to register jvc_decoder clients */
-static LIST_HEAD(decoder_list);
-DEFINE_SPINLOCK(decoder_lock);
-
enum jvc_state {
STATE_INACTIVE,
STATE_HEADER_SPACE,
@@ -38,87 +34,6 @@ enum jvc_state {
STATE_TRAILER_SPACE,
};
-struct decoder_data {
- struct list_head list;
- struct ir_input_dev *ir_dev;
- int enabled:1;
-
- /* State machine control */
- enum jvc_state state;
- u16 jvc_bits;
- u16 jvc_old_bits;
- unsigned count;
- bool first;
- bool toggle;
-};
-
-
-/**
- * get_decoder_data() - gets decoder data
- * @input_dev: input device
- *
- * Returns the struct decoder_data that corresponds to a device
- */
-static struct decoder_data *get_decoder_data(struct ir_input_dev *ir_dev)
-{
- struct decoder_data *data = NULL;
-
- spin_lock(&decoder_lock);
- list_for_each_entry(data, &decoder_list, list) {
- if (data->ir_dev == ir_dev)
- break;
- }
- spin_unlock(&decoder_lock);
- return data;
-}
-
-static ssize_t store_enabled(struct device *d,
- struct device_attribute *mattr,
- const char *buf,
- size_t len)
-{
- unsigned long value;
- struct ir_input_dev *ir_dev = dev_get_drvdata(d);
- struct decoder_data *data = get_decoder_data(ir_dev);
-
- if (!data)
- return -EINVAL;
-
- if (strict_strtoul(buf, 10, &value) || value > 1)
- return -EINVAL;
-
- data->enabled = value;
-
- return len;
-}
-
-static ssize_t show_enabled(struct device *d,
- struct device_attribute *mattr, char *buf)
-{
- struct ir_input_dev *ir_dev = dev_get_drvdata(d);
- struct decoder_data *data = get_decoder_data(ir_dev);
-
- if (!data)
- return -EINVAL;
-
- if (data->enabled)
- return sprintf(buf, "1\n");
- else
- return sprintf(buf, "0\n");
-}
-
-static DEVICE_ATTR(enabled, S_IRUGO | S_IWUSR, show_enabled, store_enabled);
-
-static struct attribute *decoder_attributes[] = {
- &dev_attr_enabled.attr,
- NULL
-};
-
-static struct attribute_group decoder_attribute_group = {
- .name = "jvc_decoder",
- .attrs = decoder_attributes,
-};
-
/**
* ir_jvc_decode() - Decode one JVC pulse or space
* @input_dev: the struct input_dev descriptor of the device
@@ -128,14 +43,10 @@ static struct attribute_group decoder_attribute_group = {
*/
static int ir_jvc_decode(struct input_dev *input_dev, struct ir_raw_event ev)
{
- struct decoder_data *data;
struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
+ struct jvc_dec *data = &ir_dev->raw->jvc;
- data = get_decoder_data(ir_dev);
- if (!data)
- return -EINVAL;
-
- if (!data->enabled)
+ if (!(ir_dev->raw->enabled_protocols & IR_TYPE_JVC))
return 0;
if (IS_RESET(ev)) {
@@ -188,9 +99,9 @@ static int ir_jvc_decode(struct input_dev *input_dev, struct ir_raw_event ev)
if (ev.pulse)
break;
- data->jvc_bits <<= 1;
+ data->bits <<= 1;
if (eq_margin(ev.duration, JVC_BIT_1_SPACE, JVC_UNIT / 2)) {
- data->jvc_bits |= 1;
+ data->bits |= 1;
decrease_duration(&ev, JVC_BIT_1_SPACE);
} else if (eq_margin(ev.duration, JVC_BIT_0_SPACE, JVC_UNIT / 2))
decrease_duration(&ev, JVC_BIT_0_SPACE);
@@ -223,13 +134,13 @@ static int ir_jvc_decode(struct input_dev *input_dev, struct ir_raw_event ev)
if (data->first) {
u32 scancode;
- scancode = (bitrev8((data->jvc_bits >> 8) & 0xff) << 8) |
- (bitrev8((data->jvc_bits >> 0) & 0xff) << 0);
+ scancode = (bitrev8((data->bits >> 8) & 0xff) << 8) |
+ (bitrev8((data->bits >> 0) & 0xff) << 0);
IR_dprintk(1, "JVC scancode 0x%04x\n", scancode);
ir_keydown(input_dev, scancode, data->toggle);
data->first = false;
- data->jvc_old_bits = data->jvc_bits;
- } else if (data->jvc_bits == data->jvc_old_bits) {
+ data->old_bits = data->bits;
+ } else if (data->bits == data->old_bits) {
IR_dprintk(1, "JVC repeat\n");
ir_repeat(input_dev);
} else {
@@ -249,54 +160,9 @@ out:
return -EINVAL;
}
-static int ir_jvc_register(struct input_dev *input_dev)
-{
- struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
- struct decoder_data *data;
- int rc;
-
- rc = sysfs_create_group(&ir_dev->dev.kobj, &decoder_attribute_group);
- if (rc < 0)
- return rc;
-
- data = kzalloc(sizeof(*data), GFP_KERNEL);
- if (!data) {
- sysfs_remove_group(&ir_dev->dev.kobj, &decoder_attribute_group);
- return -ENOMEM;
- }
-
- data->ir_dev = ir_dev;
- data->enabled = 1;
-
- spin_lock(&decoder_lock);
- list_add_tail(&data->list, &decoder_list);
- spin_unlock(&decoder_lock);
-
- return 0;
-}
-
-static int ir_jvc_unregister(struct input_dev *input_dev)
-{
- struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
- static struct decoder_data *data;
-
- data = get_decoder_data(ir_dev);
- if (!data)
- return 0;
-
- sysfs_remove_group(&ir_dev->dev.kobj, &decoder_attribute_group);
-
- spin_lock(&decoder_lock);
- list_del(&data->list);
- spin_unlock(&decoder_lock);
-
- return 0;
-}
-
static struct ir_raw_handler jvc_handler = {
+ .protocols = IR_TYPE_JVC,
.decode = ir_jvc_decode,
- .raw_register = ir_jvc_register,
- .raw_unregister = ir_jvc_unregister,
};
static int __init ir_jvc_decode_init(void)
diff --git a/drivers/media/IR/ir-keytable.c b/drivers/media/IR/ir-keytable.c
index 94a8577e72e..15a0f192d41 100644
--- a/drivers/media/IR/ir-keytable.c
+++ b/drivers/media/IR/ir-keytable.c
@@ -497,8 +497,9 @@ int __ir_input_register(struct input_dev *input_dev,
goto out_event;
}
- IR_dprintk(1, "Registered input device on %s for %s remote.\n",
- driver_name, rc_tab->name);
+ IR_dprintk(1, "Registered input device on %s for %s remote%s.\n",
+ driver_name, rc_tab->name,
+ ir_dev->props->driver_type == RC_DRIVER_IR_RAW ? " in raw mode" : "");
return 0;
diff --git a/drivers/media/IR/ir-lirc-codec.c b/drivers/media/IR/ir-lirc-codec.c
new file mode 100644
index 00000000000..3ba482d96c4
--- /dev/null
+++ b/drivers/media/IR/ir-lirc-codec.c
@@ -0,0 +1,278 @@
+/* ir-lirc-codec.c - ir-core to classic lirc interface bridge
+ *
+ * Copyright (C) 2010 by Jarod Wilson <jarod@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 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.
+ */
+
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <media/lirc.h>
+#include <media/lirc_dev.h>
+#include <media/ir-core.h>
+#include "ir-core-priv.h"
+
+#define LIRCBUF_SIZE 256
+
+/**
+ * ir_lirc_decode() - Send raw IR data to lirc_dev to be relayed to the
+ * lircd userspace daemon for decoding.
+ * @input_dev: the struct input_dev descriptor of the device
+ * @duration: the struct ir_raw_event descriptor of the pulse/space
+ *
+ * This function returns -EINVAL if the lirc interfaces aren't wired up.
+ */
+static int ir_lirc_decode(struct input_dev *input_dev, struct ir_raw_event ev)
+{
+ struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
+
+ if (!(ir_dev->raw->enabled_protocols & IR_TYPE_LIRC))
+ return 0;
+
+ if (!ir_dev->raw->lirc.drv || !ir_dev->raw->lirc.drv->rbuf)
+ return -EINVAL;
+
+ IR_dprintk(2, "LIRC data transfer started (%uus %s)\n",
+ TO_US(ev.duration), TO_STR(ev.pulse));
+
+ ir_dev->raw->lirc.lircdata += ev.duration / 1000;
+ if (ev.pulse)
+ ir_dev->raw->lirc.lircdata |= PULSE_BIT;
+
+ lirc_buffer_write(ir_dev->raw->lirc.drv->rbuf,
+ (unsigned char *) &ir_dev->raw->lirc.lircdata);
+ wake_up(&ir_dev->raw->lirc.drv->rbuf->wait_poll);
+
+ ir_dev->raw->lirc.lircdata = 0;
+
+ return 0;
+}
+
+static ssize_t ir_lirc_transmit_ir(struct file *file, const char *buf,
+ size_t n, loff_t *ppos)
+{
+ struct lirc_codec *lirc;
+ struct ir_input_dev *ir_dev;
+ int *txbuf; /* buffer with values to transmit */
+ int ret = 0, count;
+
+ lirc = lirc_get_pdata(file);
+ if (!lirc)
+ return -EFAULT;
+
+ if (n % sizeof(int))
+ return -EINVAL;
+
+ count = n / sizeof(int);
+ if (count > LIRCBUF_SIZE || count % 2 == 0)
+ return -EINVAL;
+
+ txbuf = memdup_user(buf, n);
+ if (IS_ERR(txbuf))
+ return PTR_ERR(txbuf);
+
+ ir_dev = lirc->ir_dev;
+ if (!ir_dev) {
+ ret = -EFAULT;
+ goto out;
+ }
+
+ if (ir_dev->props && ir_dev->props->tx_ir)
+ ret = ir_dev->props->tx_ir(ir_dev->props->priv, txbuf, (u32)n);
+
+out:
+ kfree(txbuf);
+ return ret;
+}
+
+static long ir_lirc_ioctl(struct file *filep, unsigned int cmd, unsigned long arg)
+{
+ struct lirc_codec *lirc;
+ struct ir_input_dev *ir_dev;
+ int ret = 0;
+ void *drv_data;
+ unsigned long val;
+
+ lirc = lirc_get_pdata(filep);
+ if (!lirc)
+ return -EFAULT;
+
+ ir_dev = lirc->ir_dev;
+ if (!ir_dev || !ir_dev->props || !ir_dev->props->priv)
+ return -EFAULT;
+
+ drv_data = ir_dev->props->priv;
+
+ switch (cmd) {
+ case LIRC_SET_TRANSMITTER_MASK:
+ ret = get_user(val, (unsigned long *)arg);
+ if (ret)
+ return ret;
+
+ if (ir_dev->props && ir_dev->props->s_tx_mask)
+ ret = ir_dev->props->s_tx_mask(drv_data, (u32)val);
+ else
+ return -EINVAL;
+ break;
+
+ case LIRC_SET_SEND_CARRIER:
+ ret = get_user(val, (unsigned long *)arg);
+ if (ret)
+ return ret;
+
+ if (ir_dev->props && ir_dev->props->s_tx_carrier)
+ ir_dev->props->s_tx_carrier(drv_data, (u32)val);
+ else
+ return -EINVAL;
+ break;
+
+ case LIRC_GET_SEND_MODE:
+ val = LIRC_CAN_SEND_PULSE & LIRC_CAN_SEND_MASK;
+ ret = put_user(val, (unsigned long *)arg);
+ break;
+
+ case LIRC_SET_SEND_MODE:
+ ret = get_user(val, (unsigned long *)arg);
+ if (ret)
+ return ret;
+
+ if (val != (LIRC_MODE_PULSE & LIRC_CAN_SEND_MASK))
+ return -EINVAL;
+ break;
+
+ default:
+ return lirc_dev_fop_ioctl(filep, cmd, arg);
+ }
+
+ return ret;
+}
+
+static int ir_lirc_open(void *data)
+{
+ return 0;
+}
+
+static void ir_lirc_close(void *data)
+{
+ return;
+}
+
+static struct file_operations lirc_fops = {
+ .owner = THIS_MODULE,
+ .write = ir_lirc_transmit_ir,
+ .unlocked_ioctl = ir_lirc_ioctl,
+ .read = lirc_dev_fop_read,
+ .poll = lirc_dev_fop_poll,
+ .open = lirc_dev_fop_open,
+ .release = lirc_dev_fop_close,
+};
+
+static int ir_lirc_register(struct input_dev *input_dev)
+{
+ struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
+ struct lirc_driver *drv;
+ struct lirc_buffer *rbuf;
+ int rc = -ENOMEM;
+ unsigned long features;
+
+ drv = kzalloc(sizeof(struct lirc_driver), GFP_KERNEL);
+ if (!drv)
+ return rc;
+
+ rbuf = kzalloc(sizeof(struct lirc_buffer), GFP_KERNEL);
+ if (!rbuf)
+ goto rbuf_alloc_failed;
+
+ rc = lirc_buffer_init(rbuf, sizeof(int), LIRCBUF_SIZE);
+ if (rc)
+ goto rbuf_init_failed;
+
+ features = LIRC_CAN_REC_MODE2;
+ if (ir_dev->props->tx_ir) {
+ features |= LIRC_CAN_SEND_PULSE;
+ if (ir_dev->props->s_tx_mask)
+ features |= LIRC_CAN_SET_TRANSMITTER_MASK;
+ if (ir_dev->props->s_tx_carrier)
+ features |= LIRC_CAN_SET_SEND_CARRIER;
+ }
+
+ snprintf(drv->name, sizeof(drv->name), "ir-lirc-codec (%s)",
+ ir_dev->driver_name);
+ drv->minor = -1;
+ drv->features = features;
+ drv->data = &ir_dev->raw->lirc;
+ drv->rbuf = rbuf;
+ drv->set_use_inc = &ir_lirc_open;
+ drv->set_use_dec = &ir_lirc_close;
+ drv->code_length = sizeof(struct ir_raw_event) * 8;
+ drv->fops = &lirc_fops;
+ drv->dev = &ir_dev->dev;
+ drv->owner = THIS_MODULE;
+
+ drv->minor = lirc_register_driver(drv);
+ if (drv->minor < 0) {
+ rc = -ENODEV;
+ goto lirc_register_failed;
+ }
+
+ ir_dev->raw->lirc.drv = drv;
+ ir_dev->raw->lirc.ir_dev = ir_dev;
+ ir_dev->raw->lirc.lircdata = PULSE_MASK;
+
+ return 0;
+
+lirc_register_failed:
+rbuf_init_failed:
+ kfree(rbuf);
+rbuf_alloc_failed:
+ kfree(drv);
+
+ return rc;
+}
+
+static int ir_lirc_unregister(struct input_dev *input_dev)
+{
+ struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
+ struct lirc_codec *lirc = &ir_dev->raw->lirc;
+
+ lirc_unregister_driver(lirc->drv->minor);
+ lirc_buffer_free(lirc->drv->rbuf);
+ kfree(lirc->drv);
+
+ return 0;
+}
+
+static struct ir_raw_handler lirc_handler = {
+ .protocols = IR_TYPE_LIRC,
+ .decode = ir_lirc_decode,
+ .raw_register = ir_lirc_register,
+ .raw_unregister = ir_lirc_unregister,
+};
+
+static int __init ir_lirc_codec_init(void)
+{
+ ir_raw_handler_register(&lirc_handler);
+
+ printk(KERN_INFO "IR LIRC bridge handler initialized\n");
+ return 0;
+}
+
+static void __exit ir_lirc_codec_exit(void)
+{
+ ir_raw_handler_unregister(&lirc_handler);
+}
+
+module_init(ir_lirc_codec_init);
+module_exit(ir_lirc_codec_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Jarod Wilson <jarod@redhat.com>");
+MODULE_AUTHOR("Red Hat Inc. (http://www.redhat.com)");
+MODULE_DESCRIPTION("LIRC IR handler bridge");
diff --git a/drivers/media/IR/ir-nec-decoder.c b/drivers/media/IR/ir-nec-decoder.c
index ba79233112e..52e0f378ae3 100644
--- a/drivers/media/IR/ir-nec-decoder.c
+++ b/drivers/media/IR/ir-nec-decoder.c
@@ -27,10 +27,6 @@
#define NEC_TRAILER_PULSE (1 * NEC_UNIT)
#define NEC_TRAILER_SPACE (10 * NEC_UNIT) /* even longer in reality */
-/* Used to register nec_decoder clients */
-static LIST_HEAD(decoder_list);
-static DEFINE_SPINLOCK(decoder_lock);
-
enum nec_state {
STATE_INACTIVE,
STATE_HEADER_SPACE,
@@ -40,84 +36,6 @@ enum nec_state {
STATE_TRAILER_SPACE,
};
-struct decoder_data {
- struct list_head list;
- struct ir_input_dev *ir_dev;
- int enabled:1;
-
- /* State machine control */
- enum nec_state state;
- u32 nec_bits;
- unsigned count;
-};
-
-
-/**
- * get_decoder_data() - gets decoder data
- * @input_dev: input device
- *
- * Returns the struct decoder_data that corresponds to a device
- */
-static struct decoder_data *get_decoder_data(struct ir_input_dev *ir_dev)
-{
- struct decoder_data *data = NULL;
-
- spin_lock(&decoder_lock);
- list_for_each_entry(data, &decoder_list, list) {
- if (data->ir_dev == ir_dev)
- break;
- }
- spin_unlock(&decoder_lock);
- return data;
-}
-
-static ssize_t store_enabled(struct device *d,
- struct device_attribute *mattr,
- const char *buf,
- size_t len)
-{
- unsigned long value;
- struct ir_input_dev *ir_dev = dev_get_drvdata(d);
- struct decoder_data *data = get_decoder_data(ir_dev);
-
- if (!data)
- return -EINVAL;
-
- if (strict_strtoul(buf, 10, &value) || value > 1)
- return -EINVAL;
-
- data->enabled = value;
-
- return len;
-}
-
-static ssize_t show_enabled(struct device *d,
- struct device_attribute *mattr, char *buf)
-{
- struct ir_input_dev *ir_dev = dev_get_drvdata(d);
- struct decoder_data *data = get_decoder_data(ir_dev);
-
- if (!data)
- return -EINVAL;
-
- if (data->enabled)
- return sprintf(buf, "1\n");
- else
- return sprintf(buf, "0\n");
-}
-
-static DEVICE_ATTR(enabled, S_IRUGO | S_IWUSR, show_enabled, store_enabled);
-
-static struct attribute *decoder_attributes[] = {
- &dev_attr_enabled.attr,
- NULL
-};
-
-static struct attribute_group decoder_attribute_group = {
- .name = "nec_decoder",
- .attrs = decoder_attributes,
-};
-
/**
* ir_nec_decode() - Decode one NEC pulse or space
* @input_dev: the struct input_dev descriptor of the device
@@ -127,16 +45,12 @@ static struct attribute_group decoder_attribute_group = {
*/
static int ir_nec_decode(struct input_dev *input_dev, struct ir_raw_event ev)
{
- struct decoder_data *data;
struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
+ struct nec_dec *data = &ir_dev->raw->nec;
u32 scancode;
u8 address, not_address, command, not_command;
- data = get_decoder_data(ir_dev);
- if (!data)
- return -EINVAL;
-
- if (!data->enabled)
+ if (!(ir_dev->raw->enabled_protocols & IR_TYPE_NEC))
return 0;
if (IS_RESET(ev)) {
@@ -191,9 +105,9 @@ static int ir_nec_decode(struct input_dev *input_dev, struct ir_raw_event ev)
if (ev.pulse)
break;
- data->nec_bits <<= 1;
+ data->bits <<= 1;
if (eq_margin(ev.duration, NEC_BIT_1_SPACE, NEC_UNIT / 2))
- data->nec_bits |= 1;
+ data->bits |= 1;
else if (!eq_margin(ev.duration, NEC_BIT_0_SPACE, NEC_UNIT / 2))
break;
data->count++;
@@ -222,14 +136,14 @@ static int ir_nec_decode(struct input_dev *input_dev, struct ir_raw_event ev)
if (!geq_margin(ev.duration, NEC_TRAILER_SPACE, NEC_UNIT / 2))
break;
- address = bitrev8((data->nec_bits >> 24) & 0xff);
- not_address = bitrev8((data->nec_bits >> 16) & 0xff);
- command = bitrev8((data->nec_bits >> 8) & 0xff);
- not_command = bitrev8((data->nec_bits >> 0) & 0xff);
+ address = bitrev8((data->bits >> 24) & 0xff);
+ not_address = bitrev8((data->bits >> 16) & 0xff);
+ command = bitrev8((data->bits >> 8) & 0xff);
+ not_command = bitrev8((data->bits >> 0) & 0xff);
if ((command ^ not_command) != 0xff) {
IR_dprintk(1, "NEC checksum error: received 0x%08x\n",
- data->nec_bits);
+ data->bits);
break;
}
@@ -256,54 +170,9 @@ static int ir_nec_decode(struct input_dev *input_dev, struct ir_raw_event ev)
return -EINVAL;
}
-static int ir_nec_register(struct input_dev *input_dev)
-{
- struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
- struct decoder_data *data;
- int rc;
-
- rc = sysfs_create_group(&ir_dev->dev.kobj, &decoder_attribute_group);
- if (rc < 0)
- return rc;
-
- data = kzalloc(sizeof(*data), GFP_KERNEL);
- if (!data) {
- sysfs_remove_group(&ir_dev->dev.kobj, &decoder_attribute_group);
- return -ENOMEM;
- }
-
- data->ir_dev = ir_dev;
- data->enabled = 1;
-
- spin_lock(&decoder_lock);
- list_add_tail(&data->list, &decoder_list);
- spin_unlock(&decoder_lock);
-
- return 0;
-}
-
-static int ir_nec_unregister(struct input_dev *input_dev)
-{
- struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
- static struct decoder_data *data;
-
- data = get_decoder_data(ir_dev);
- if (!data)
- return 0;
-
- sysfs_remove_group(&ir_dev->dev.kobj, &decoder_attribute_group);
-
- spin_lock(&decoder_lock);
- list_del(&data->list);
- spin_unlock(&decoder_lock);
-
- return 0;
-}
-
static struct ir_raw_handler nec_handler = {
+ .protocols = IR_TYPE_NEC,
.decode = ir_nec_decode,
- .raw_register = ir_nec_register,
- .raw_unregister = ir_nec_unregister,
};
static int __init ir_nec_decode_init(void)
diff --git a/drivers/media/IR/ir-raw-event.c b/drivers/media/IR/ir-raw-event.c
index ea68a3f2eff..6f192ef31db 100644
--- a/drivers/media/IR/ir-raw-event.c
+++ b/drivers/media/IR/ir-raw-event.c
@@ -20,35 +20,13 @@
/* Define the max number of pulse/space transitions to buffer */
#define MAX_IR_EVENT_SIZE 512
+/* Used to keep track of IR raw clients, protected by ir_raw_handler_lock */
+static LIST_HEAD(ir_raw_client_list);
+
/* Used to handle IR raw handler extensions */
-static LIST_HEAD(ir_raw_handler_list);
static DEFINE_SPINLOCK(ir_raw_handler_lock);
-
-/**
- * RUN_DECODER() - runs an operation on all IR decoders
- * @ops: IR raw handler operation to be called
- * @arg: arguments to be passed to the callback
- *
- * Calls ir_raw_handler::ops for all registered IR handlers. It prevents
- * new decode addition/removal while running, by locking ir_raw_handler_lock
- * mutex. If an error occurs, it stops the ops. Otherwise, it returns a sum
- * of the return codes.
- */
-#define RUN_DECODER(ops, ...) ({ \
- struct ir_raw_handler *_ir_raw_handler; \
- int _sumrc = 0, _rc; \
- spin_lock(&ir_raw_handler_lock); \
- list_for_each_entry(_ir_raw_handler, &ir_raw_handler_list, list) { \
- if (_ir_raw_handler->ops) { \
- _rc = _ir_raw_handler->ops(__VA_ARGS__); \
- if (_rc < 0) \
- break; \
- _sumrc += _rc; \
- } \
- } \
- spin_unlock(&ir_raw_handler_lock); \
- _sumrc; \
-})
+static LIST_HEAD(ir_raw_handler_list);
+static u64 available_protocols;
#ifdef MODULE
/* Used to load the decoders */
@@ -58,57 +36,17 @@ static struct work_struct wq_load;
static void ir_raw_event_work(struct work_struct *work)
{
struct ir_raw_event ev;
+ struct ir_raw_handler *handler;
struct ir_raw_event_ctrl *raw =
container_of(work, struct ir_raw_event_ctrl, rx_work);
- while (kfifo_out(&raw->kfifo, &ev, sizeof(ev)) == sizeof(ev))
- RUN_DECODER(decode, raw->input_dev, ev);
-}
-
-int ir_raw_event_register(struct input_dev *input_dev)
-{
- struct ir_input_dev *ir = input_get_drvdata(input_dev);
- int rc;
-
- ir->raw = kzalloc(sizeof(*ir->raw), GFP_KERNEL);
- if (!ir->raw)
- return -ENOMEM;
-
- ir->raw->input_dev = input_dev;
- INIT_WORK(&ir->raw->rx_work, ir_raw_event_work);
-
- rc = kfifo_alloc(&ir->raw->kfifo, sizeof(s64) * MAX_IR_EVENT_SIZE,
- GFP_KERNEL);
- if (rc < 0) {
- kfree(ir->raw);
- ir->raw = NULL;
- return rc;
- }
-
- rc = RUN_DECODER(raw_register, input_dev);
- if (rc < 0) {
- kfifo_free(&ir->raw->kfifo);
- kfree(ir->raw);
- ir->raw = NULL;
- return rc;
+ while (kfifo_out(&raw->kfifo, &ev, sizeof(ev)) == sizeof(ev)) {
+ spin_lock(&ir_raw_handler_lock);
+ list_for_each_entry(handler, &ir_raw_handler_list, list)
+ handler->decode(raw->input_dev, ev);
+ spin_unlock(&ir_raw_handler_lock);
+ raw->prev_ev = ev;
}
-
- return rc;
-}
-
-void ir_raw_event_unregister(struct input_dev *input_dev)
-{
- struct ir_input_dev *ir = input_get_drvdata(input_dev);
-
- if (!ir->raw)
- return;
-
- cancel_work_sync(&ir->raw->rx_work);
- RUN_DECODER(raw_unregister, input_dev);
-
- kfifo_free(&ir->raw->kfifo);
- kfree(ir->raw);
- ir->raw = NULL;
}
/**
@@ -204,23 +142,103 @@ void ir_raw_event_handle(struct input_dev *input_dev)
}
EXPORT_SYMBOL_GPL(ir_raw_event_handle);
+/* used internally by the sysfs interface */
+u64
+ir_raw_get_allowed_protocols()
+{
+ u64 protocols;
+ spin_lock(&ir_raw_handler_lock);
+ protocols = available_protocols;
+ spin_unlock(&ir_raw_handler_lock);
+ return protocols;
+}
+
+/*
+ * Used to (un)register raw event clients
+ */
+int ir_raw_event_register(struct input_dev *input_dev)
+{
+ struct ir_input_dev *ir = input_get_drvdata(input_dev);
+ int rc;
+ struct ir_raw_handler *handler;
+
+ ir->raw = kzalloc(sizeof(*ir->raw), GFP_KERNEL);
+ if (!ir->raw)
+ return -ENOMEM;
+
+ ir->raw->input_dev = input_dev;
+ INIT_WORK(&ir->raw->rx_work, ir_raw_event_work);
+ ir->raw->enabled_protocols = ~0;
+ rc = kfifo_alloc(&ir->raw->kfifo, sizeof(s64) * MAX_IR_EVENT_SIZE,
+ GFP_KERNEL);
+ if (rc < 0) {
+ kfree(ir->raw);
+ ir->raw = NULL;
+ return rc;
+ }
+
+ spin_lock(&ir_raw_handler_lock);
+ list_add_tail(&ir->raw->list, &ir_raw_client_list);
+ list_for_each_entry(handler, &ir_raw_handler_list, list)
+ if (handler->raw_register)
+ handler->raw_register(ir->raw->input_dev);
+ spin_unlock(&ir_raw_handler_lock);
+
+ return 0;
+}
+
+void ir_raw_event_unregister(struct input_dev *input_dev)
+{
+ struct ir_input_dev *ir = input_get_drvdata(input_dev);
+ struct ir_raw_handler *handler;
+
+ if (!ir->raw)
+ return;
+
+ cancel_work_sync(&ir->raw->rx_work);
+
+ spin_lock(&ir_raw_handler_lock);
+ list_del(&ir->raw->list);
+ list_for_each_entry(handler, &ir_raw_handler_list, list)
+ if (handler->raw_unregister)
+ handler->raw_unregister(ir->raw->input_dev);
+ spin_unlock(&ir_raw_handler_lock);
+
+ kfifo_free(&ir->raw->kfifo);
+ kfree(ir->raw);
+ ir->raw = NULL;
+}
+
/*
* Extension interface - used to register the IR decoders
*/
int ir_raw_handler_register(struct ir_raw_handler *ir_raw_handler)
{
+ struct ir_raw_event_ctrl *raw;
+
spin_lock(&ir_raw_handler_lock);
list_add_tail(&ir_raw_handler->list, &ir_raw_handler_list);
+ if (ir_raw_handler->raw_register)
+ list_for_each_entry(raw, &ir_raw_client_list, list)
+ ir_raw_handler->raw_register(raw->input_dev);
+ available_protocols |= ir_raw_handler->protocols;
spin_unlock(&ir_raw_handler_lock);
+
return 0;
}
EXPORT_SYMBOL(ir_raw_handler_register);
void ir_raw_handler_unregister(struct ir_raw_handler *ir_raw_handler)
{
+ struct ir_raw_event_ctrl *raw;
+
spin_lock(&ir_raw_handler_lock);
list_del(&ir_raw_handler->list);
+ if (ir_raw_handler->raw_unregister)
+ list_for_each_entry(raw, &ir_raw_client_list, list)
+ ir_raw_handler->raw_unregister(raw->input_dev);
+ available_protocols &= ~ir_raw_handler->protocols;
spin_unlock(&ir_raw_handler_lock);
}
EXPORT_SYMBOL(ir_raw_handler_unregister);
@@ -235,6 +253,7 @@ static void init_decoders(struct work_struct *work)
load_rc6_decode();
load_jvc_decode();
load_sony_decode();
+ load_lirc_codec();
/* If needed, we may later add some init code. In this case,
it is needed to change the CONFIG_MODULE test at ir-core.h
diff --git a/drivers/media/IR/ir-rc5-decoder.c b/drivers/media/IR/ir-rc5-decoder.c
index 23cdb1b1a3b..df4770d978a 100644
--- a/drivers/media/IR/ir-rc5-decoder.c
+++ b/drivers/media/IR/ir-rc5-decoder.c
@@ -30,10 +30,6 @@
#define RC5_BIT_END (1 * RC5_UNIT)
#define RC5X_SPACE (4 * RC5_UNIT)
-/* Used to register rc5_decoder clients */
-static LIST_HEAD(decoder_list);
-static DEFINE_SPINLOCK(decoder_lock);
-
enum rc5_state {
STATE_INACTIVE,
STATE_BIT_START,
@@ -42,87 +38,6 @@ enum rc5_state {
STATE_FINISHED,
};
-struct decoder_data {
- struct list_head list;
- struct ir_input_dev *ir_dev;
- int enabled:1;
-
- /* State machine control */
- enum rc5_state state;
- u32 rc5_bits;
- struct ir_raw_event prev_ev;
- unsigned count;
- unsigned wanted_bits;
-};
-
-
-/**
- * get_decoder_data() - gets decoder data
- * @input_dev: input device
- *
- * Returns the struct decoder_data that corresponds to a device
- */
-
-static struct decoder_data *get_decoder_data(struct ir_input_dev *ir_dev)
-{
- struct decoder_data *data = NULL;
-
- spin_lock(&decoder_lock);
- list_for_each_entry(data, &decoder_list, list) {
- if (data->ir_dev == ir_dev)
- break;
- }
- spin_unlock(&decoder_lock);
- return data;
-}
-
-static ssize_t store_enabled(struct device *d,
- struct device_attribute *mattr,
- const char *buf,
- size_t len)
-{
- unsigned long value;
- struct ir_input_dev *ir_dev = dev_get_drvdata(d);
- struct decoder_data *data = get_decoder_data(ir_dev);
-
- if (!data)
- return -EINVAL;
-
- if (strict_strtoul(buf, 10, &value) || value > 1)
- return -EINVAL;
-
- data->enabled = value;
-
- return len;
-}
-
-static ssize_t show_enabled(struct device *d,
- struct device_attribute *mattr, char *buf)
-{
- struct ir_input_dev *ir_dev = dev_get_drvdata(d);
- struct decoder_data *data = get_decoder_data(ir_dev);
-
- if (!data)
- return -EINVAL;
-
- if (data->enabled)
- return sprintf(buf, "1\n");
- else
- return sprintf(buf, "0\n");
-}
-
-static DEVICE_ATTR(enabled, S_IRUGO | S_IWUSR, show_enabled, store_enabled);
-
-static struct attribute *decoder_attributes[] = {
- &dev_attr_enabled.attr,
- NULL
-};
-
-static struct attribute_group decoder_attribute_group = {
- .name = "rc5_decoder",
- .attrs = decoder_attributes,
-};
-
/**
* ir_rc5_decode() - Decode one RC-5 pulse or space
* @input_dev: the struct input_dev descriptor of the device
@@ -132,17 +47,13 @@ static struct attribute_group decoder_attribute_group = {
*/
static int ir_rc5_decode(struct input_dev *input_dev, struct ir_raw_event ev)
{
- struct decoder_data *data;
struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
+ struct rc5_dec *data = &ir_dev->raw->rc5;
u8 toggle;
u32 scancode;
- data = get_decoder_data(ir_dev);
- if (!data)
- return -EINVAL;
-
- if (!data->enabled)
- return 0;
+ if (!(ir_dev->raw->enabled_protocols & IR_TYPE_RC5))
+ return 0;
if (IS_RESET(ev)) {
data->state = STATE_INACTIVE;
@@ -176,16 +87,15 @@ again:
if (!eq_margin(ev.duration, RC5_BIT_START, RC5_UNIT / 2))
break;
- data->rc5_bits <<= 1;
+ data->bits <<= 1;
if (!ev.pulse)
- data->rc5_bits |= 1;
+ data->bits |= 1;
data->count++;
- data->prev_ev = ev;
data->state = STATE_BIT_END;
return 0;
case STATE_BIT_END:
- if (!is_transition(&ev, &data->prev_ev))
+ if (!is_transition(&ev, &ir_dev->raw->prev_ev))
break;
if (data->count == data->wanted_bits)
@@ -217,11 +127,11 @@ again:
if (data->wanted_bits == RC5X_NBITS) {
/* RC5X */
u8 xdata, command, system;
- xdata = (data->rc5_bits & 0x0003F) >> 0;
- command = (data->rc5_bits & 0x00FC0) >> 6;
- system = (data->rc5_bits & 0x1F000) >> 12;
- toggle = (data->rc5_bits & 0x20000) ? 1 : 0;
- command += (data->rc5_bits & 0x01000) ? 0 : 0x40;
+ xdata = (data->bits & 0x0003F) >> 0;
+ command = (data->bits & 0x00FC0) >> 6;
+ system = (data->bits & 0x1F000) >> 12;
+ toggle = (data->bits & 0x20000) ? 1 : 0;
+ command += (data->bits & 0x01000) ? 0 : 0x40;
scancode = system << 16 | command << 8 | xdata;
IR_dprintk(1, "RC5X scancode 0x%06x (toggle: %u)\n",
@@ -230,10 +140,10 @@ again:
} else {
/* RC5 */
u8 command, system;
- command = (data->rc5_bits & 0x0003F) >> 0;
- system = (data->rc5_bits & 0x007C0) >> 6;
- toggle = (data->rc5_bits & 0x00800) ? 1 : 0;
- command += (data->rc5_bits & 0x01000) ? 0 : 0x40;
+ command = (data->bits & 0x0003F) >> 0;
+ system = (data->bits & 0x007C0) >> 6;
+ toggle = (data->bits & 0x00800) ? 1 : 0;
+ command += (data->bits & 0x01000) ? 0 : 0x40;
scancode = system << 8 | command;
IR_dprintk(1, "RC5 scancode 0x%04x (toggle: %u)\n",
@@ -252,54 +162,9 @@ out:
return -EINVAL;
}
-static int ir_rc5_register(struct input_dev *input_dev)
-{
- struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
- struct decoder_data *data;
- int rc;
-
- rc = sysfs_create_group(&ir_dev->dev.kobj, &decoder_attribute_group);
- if (rc < 0)
- return rc;
-
- data = kzalloc(sizeof(*data), GFP_KERNEL);
- if (!data) {
- sysfs_remove_group(&ir_dev->dev.kobj, &decoder_attribute_group);
- return -ENOMEM;
- }
-
- data->ir_dev = ir_dev;
- data->enabled = 1;
-
- spin_lock(&decoder_lock);
- list_add_tail(&data->list, &decoder_list);
- spin_unlock(&decoder_lock);
-
- return 0;
-}
-
-static int ir_rc5_unregister(struct input_dev *input_dev)
-{
- struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
- static struct decoder_data *data;
-
- data = get_decoder_data(ir_dev);
- if (!data)
- return 0;
-
- sysfs_remove_group(&ir_dev->dev.kobj, &decoder_attribute_group);
-
- spin_lock(&decoder_lock);
- list_del(&data->list);
- spin_unlock(&decoder_lock);
-
- return 0;
-}
-
static struct ir_raw_handler rc5_handler = {
+ .protocols = IR_TYPE_RC5,
.decode = ir_rc5_decode,
- .raw_register = ir_rc5_register,
- .raw_unregister = ir_rc5_unregister,
};
static int __init ir_rc5_decode_init(void)
diff --git a/drivers/media/IR/ir-rc6-decoder.c b/drivers/media/IR/ir-rc6-decoder.c
index 2bf479f4f1b..f1624b8279b 100644
--- a/drivers/media/IR/ir-rc6-decoder.c
+++ b/drivers/media/IR/ir-rc6-decoder.c
@@ -36,10 +36,6 @@
#define RC6_STARTBIT_MASK 0x08 /* for the header bits */
#define RC6_6A_MCE_TOGGLE_MASK 0x8000 /* for the body bits */
-/* Used to register rc6_decoder clients */
-static LIST_HEAD(decoder_list);
-static DEFINE_SPINLOCK(decoder_lock);
-
enum rc6_mode {
RC6_MODE_0,
RC6_MODE_6A,
@@ -58,89 +54,8 @@ enum rc6_state {
STATE_FINISHED,
};
-struct decoder_data {
- struct list_head list;
- struct ir_input_dev *ir_dev;
- int enabled:1;
-
- /* State machine control */
- enum rc6_state state;
- u8 header;
- u32 body;
- struct ir_raw_event prev_ev;
- bool toggle;
- unsigned count;
- unsigned wanted_bits;
-};
-
-
-/**
- * get_decoder_data() - gets decoder data
- * @input_dev: input device
- *
- * Returns the struct decoder_data that corresponds to a device
- */
-static struct decoder_data *get_decoder_data(struct ir_input_dev *ir_dev)
-{
- struct decoder_data *data = NULL;
-
- spin_lock(&decoder_lock);
- list_for_each_entry(data, &decoder_list, list) {
- if (data->ir_dev == ir_dev)
- break;
- }
- spin_unlock(&decoder_lock);
- return data;
-}
-
-static ssize_t store_enabled(struct device *d,
- struct device_attribute *mattr,
- const char *buf,
- size_t len)
+static enum rc6_mode rc6_mode(struct rc6_dec *data)
{
- unsigned long value;
- struct ir_input_dev *ir_dev = dev_get_drvdata(d);
- struct decoder_data *data = get_decoder_data(ir_dev);
-
- if (!data)
- return -EINVAL;
-
- if (strict_strtoul(buf, 10, &value) || value > 1)
- return -EINVAL;
-
- data->enabled = value;
-
- return len;
-}
-
-static ssize_t show_enabled(struct device *d,
- struct device_attribute *mattr, char *buf)
-{
- struct ir_input_dev *ir_dev = dev_get_drvdata(d);
- struct decoder_data *data = get_decoder_data(ir_dev);
-
- if (!data)
- return -EINVAL;
-
- if (data->enabled)
- return sprintf(buf, "1\n");
- else
- return sprintf(buf, "0\n");
-}
-
-static DEVICE_ATTR(enabled, S_IRUGO | S_IWUSR, show_enabled, store_enabled);
-
-static struct attribute *decoder_attributes[] = {
- &dev_attr_enabled.attr,
- NULL
-};
-
-static struct attribute_group decoder_attribute_group = {
- .name = "rc6_decoder",
- .attrs = decoder_attributes,
-};
-
-static enum rc6_mode rc6_mode(struct decoder_data *data) {
switch (data->header & RC6_MODE_MASK) {
case 0:
return RC6_MODE_0;
@@ -162,16 +77,12 @@ static enum rc6_mode rc6_mode(struct decoder_data *data) {
*/
static int ir_rc6_decode(struct input_dev *input_dev, struct ir_raw_event ev)
{
- struct decoder_data *data;
struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
+ struct rc6_dec *data = &ir_dev->raw->rc6;
u32 scancode;
u8 toggle;
- data = get_decoder_data(ir_dev);
- if (!data)
- return -EINVAL;
-
- if (!data->enabled)
+ if (!(ir_dev->raw->enabled_protocols & IR_TYPE_RC6))
return 0;
if (IS_RESET(ev)) {
@@ -223,12 +134,11 @@ again:
if (ev.pulse)
data->header |= 1;
data->count++;
- data->prev_ev = ev;
data->state = STATE_HEADER_BIT_END;
return 0;
case STATE_HEADER_BIT_END:
- if (!is_transition(&ev, &data->prev_ev))
+ if (!is_transition(&ev, &ir_dev->raw->prev_ev))
break;
if (data->count == RC6_HEADER_NBITS)
@@ -244,12 +154,11 @@ again:
break;
data->toggle = ev.pulse;
- data->prev_ev = ev;
data->state = STATE_TOGGLE_END;
return 0;
case STATE_TOGGLE_END:
- if (!is_transition(&ev, &data->prev_ev) ||
+ if (!is_transition(&ev, &ir_dev->raw->prev_ev) ||
!geq_margin(ev.duration, RC6_TOGGLE_END, RC6_UNIT / 2))
break;
@@ -259,7 +168,6 @@ again:
}
data->state = STATE_BODY_BIT_START;
- data->prev_ev = ev;
decrease_duration(&ev, RC6_TOGGLE_END);
data->count = 0;
@@ -291,13 +199,11 @@ again:
if (ev.pulse)
data->body |= 1;
data->count++;
- data->prev_ev = ev;
-
data->state = STATE_BODY_BIT_END;
return 0;
case STATE_BODY_BIT_END:
- if (!is_transition(&ev, &data->prev_ev))
+ if (!is_transition(&ev, &ir_dev->raw->prev_ev))
break;
if (data->count == data->wanted_bits)
@@ -348,54 +254,9 @@ out:
return -EINVAL;
}
-static int ir_rc6_register(struct input_dev *input_dev)
-{
- struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
- struct decoder_data *data;
- int rc;
-
- rc = sysfs_create_group(&ir_dev->dev.kobj, &decoder_attribute_group);
- if (rc < 0)
- return rc;
-
- data = kzalloc(sizeof(*data), GFP_KERNEL);
- if (!data) {
- sysfs_remove_group(&ir_dev->dev.kobj, &decoder_attribute_group);
- return -ENOMEM;
- }
-
- data->ir_dev = ir_dev;
- data->enabled = 1;
-
- spin_lock(&decoder_lock);
- list_add_tail(&data->list, &decoder_list);
- spin_unlock(&decoder_lock);
-
- return 0;
-}
-
-static int ir_rc6_unregister(struct input_dev *input_dev)
-{
- struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
- static struct decoder_data *data;
-
- data = get_decoder_data(ir_dev);
- if (!data)
- return 0;
-
- sysfs_remove_group(&ir_dev->dev.kobj, &decoder_attribute_group);
-
- spin_lock(&decoder_lock);
- list_del(&data->list);
- spin_unlock(&decoder_lock);
-
- return 0;
-}
-
static struct ir_raw_handler rc6_handler = {
+ .protocols = IR_TYPE_RC6,
.decode = ir_rc6_decode,
- .raw_register = ir_rc6_register,
- .raw_unregister = ir_rc6_unregister,
};
static int __init ir_rc6_decode_init(void)
diff --git a/drivers/media/IR/ir-sony-decoder.c b/drivers/media/IR/ir-sony-decoder.c
index 9f440c5c060..b9074f07c7a 100644
--- a/drivers/media/IR/ir-sony-decoder.c
+++ b/drivers/media/IR/ir-sony-decoder.c
@@ -23,10 +23,6 @@
#define SONY_BIT_SPACE (1 * SONY_UNIT)
#define SONY_TRAILER_SPACE (10 * SONY_UNIT) /* minimum */
-/* Used to register sony_decoder clients */
-static LIST_HEAD(decoder_list);
-static DEFINE_SPINLOCK(decoder_lock);
-
enum sony_state {
STATE_INACTIVE,
STATE_HEADER_SPACE,
@@ -35,84 +31,6 @@ enum sony_state {
STATE_FINISHED,
};
-struct decoder_data {
- struct list_head list;
- struct ir_input_dev *ir_dev;
- int enabled:1;
-
- /* State machine control */
- enum sony_state state;
- u32 sony_bits;
- unsigned count;
-};
-
-
-/**
- * get_decoder_data() - gets decoder data
- * @input_dev: input device
- *
- * Returns the struct decoder_data that corresponds to a device
- */
-static struct decoder_data *get_decoder_data(struct ir_input_dev *ir_dev)
-{
- struct decoder_data *data = NULL;
-
- spin_lock(&decoder_lock);
- list_for_each_entry(data, &decoder_list, list) {
- if (data->ir_dev == ir_dev)
- break;
- }
- spin_unlock(&decoder_lock);
- return data;
-}
-
-static ssize_t store_enabled(struct device *d,
- struct device_attribute *mattr,
- const char *buf,
- size_t len)
-{
- unsigned long value;
- struct ir_input_dev *ir_dev = dev_get_drvdata(d);
- struct decoder_data *data = get_decoder_data(ir_dev);
-
- if (!data)
- return -EINVAL;
-
- if (strict_strtoul(buf, 10, &value) || value > 1)
- return -EINVAL;
-
- data->enabled = value;
-
- return len;
-}
-
-static ssize_t show_enabled(struct device *d,
- struct device_attribute *mattr, char *buf)
-{
- struct ir_input_dev *ir_dev = dev_get_drvdata(d);
- struct decoder_data *data = get_decoder_data(ir_dev);
-
- if (!data)
- return -EINVAL;
-
- if (data->enabled)
- return sprintf(buf, "1\n");
- else
- return sprintf(buf, "0\n");
-}
-
-static DEVICE_ATTR(enabled, S_IRUGO | S_IWUSR, show_enabled, store_enabled);
-
-static struct attribute *decoder_attributes[] = {
- &dev_attr_enabled.attr,
- NULL
-};
-
-static struct attribute_group decoder_attribute_group = {
- .name = "sony_decoder",
- .attrs = decoder_attributes,
-};
-
/**
* ir_sony_decode() - Decode one Sony pulse or space
* @input_dev: the struct input_dev descriptor of the device
@@ -122,16 +40,12 @@ static struct attribute_group decoder_attribute_group = {
*/
static int ir_sony_decode(struct input_dev *input_dev, struct ir_raw_event ev)
{
- struct decoder_data *data;
struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
+ struct sony_dec *data = &ir_dev->raw->sony;
u32 scancode;
u8 device, subdevice, function;
- data = get_decoder_data(ir_dev);
- if (!data)
- return -EINVAL;
-
- if (!data->enabled)
+ if (!(ir_dev->raw->enabled_protocols & IR_TYPE_SONY))
return 0;
if (IS_RESET(ev)) {
@@ -172,9 +86,9 @@ static int ir_sony_decode(struct input_dev *input_dev, struct ir_raw_event ev)
if (!ev.pulse)
break;
- data->sony_bits <<= 1;
+ data->bits <<= 1;
if (eq_margin(ev.duration, SONY_BIT_1_PULSE, SONY_UNIT / 2))
- data->sony_bits |= 1;
+ data->bits |= 1;
else if (!eq_margin(ev.duration, SONY_BIT_0_PULSE, SONY_UNIT / 2))
break;
@@ -208,19 +122,19 @@ static int ir_sony_decode(struct input_dev *input_dev, struct ir_raw_event ev)
switch (data->count) {
case 12:
- device = bitrev8((data->sony_bits << 3) & 0xF8);
+ device = bitrev8((data->bits << 3) & 0xF8);
subdevice = 0;
- function = bitrev8((data->sony_bits >> 4) & 0xFE);
+ function = bitrev8((data->bits >> 4) & 0xFE);
break;
case 15:
- device = bitrev8((data->sony_bits >> 0) & 0xFF);
+ device = bitrev8((data->bits >> 0) & 0xFF);
subdevice = 0;
- function = bitrev8((data->sony_bits >> 7) & 0xFD);
+ function = bitrev8((data->bits >> 7) & 0xFD);
break;
case 20:
- device = bitrev8((data->sony_bits >> 5) & 0xF8);
- subdevice = bitrev8((data->sony_bits >> 0) & 0xFF);
- function = bitrev8((data->sony_bits >> 12) & 0xFE);
+ device = bitrev8((data->bits >> 5) & 0xF8);
+ subdevice = bitrev8((data->bits >> 0) & 0xFF);
+ function = bitrev8((data->bits >> 12) & 0xFE);
break;
default:
IR_dprintk(1, "Sony invalid bitcount %u\n", data->count);
@@ -241,54 +155,9 @@ out:
return -EINVAL;
}
-static int ir_sony_register(struct input_dev *input_dev)
-{
- struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
- struct decoder_data *data;
- int rc;
-
- rc = sysfs_create_group(&ir_dev->dev.kobj, &decoder_attribute_group);
- if (rc < 0)
- return rc;
-
- data = kzalloc(sizeof(*data), GFP_KERNEL);
- if (!data) {
- sysfs_remove_group(&ir_dev->dev.kobj, &decoder_attribute_group);
- return -ENOMEM;
- }
-
- data->ir_dev = ir_dev;
- data->enabled = 1;
-
- spin_lock(&decoder_lock);
- list_add_tail(&data->list, &decoder_list);
- spin_unlock(&decoder_lock);
-
- return 0;
-}
-
-static int ir_sony_unregister(struct input_dev *input_dev)
-{
- struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
- static struct decoder_data *data;
-
- data = get_decoder_data(ir_dev);
- if (!data)
- return 0;
-
- sysfs_remove_group(&ir_dev->dev.kobj, &decoder_attribute_group);
-
- spin_lock(&decoder_lock);
- list_del(&data->list);
- spin_unlock(&decoder_lock);
-
- return 0;
-}
-
static struct ir_raw_handler sony_handler = {
+ .protocols = IR_TYPE_SONY,
.decode = ir_sony_decode,
- .raw_register = ir_sony_register,
- .raw_unregister = ir_sony_unregister,
};
static int __init ir_sony_decode_init(void)
diff --git a/drivers/media/IR/ir-sysfs.c b/drivers/media/IR/ir-sysfs.c
index 2098dd1488e..6273047e915 100644
--- a/drivers/media/IR/ir-sysfs.c
+++ b/drivers/media/IR/ir-sysfs.c
@@ -33,125 +33,172 @@ static struct class ir_input_class = {
.devnode = ir_devnode,
};
+static struct {
+ u64 type;
+ char *name;
+} proto_names[] = {
+ { IR_TYPE_UNKNOWN, "unknown" },
+ { IR_TYPE_RC5, "rc-5" },
+ { IR_TYPE_NEC, "nec" },
+ { IR_TYPE_RC6, "rc-6" },
+ { IR_TYPE_JVC, "jvc" },
+ { IR_TYPE_SONY, "sony" },
+ { IR_TYPE_LIRC, "lirc" },
+};
+
+#define PROTO_NONE "none"
+
/**
- * show_protocol() - shows the current IR protocol
+ * show_protocols() - shows the current IR protocol(s)
* @d: the device descriptor
* @mattr: the device attribute struct (unused)
* @buf: a pointer to the output buffer
*
- * This routine is a callback routine for input read the IR protocol type.
- * it is trigged by reading /sys/class/rc/rc?/current_protocol.
- * It returns the protocol name, as understood by the driver.
+ * This routine is a callback routine for input read the IR protocol type(s).
+ * it is trigged by reading /sys/class/rc/rc?/protocols.
+ * It returns the protocol names of supported protocols.
+ * Enabled protocols are printed in brackets.
*/
-static ssize_t show_protocol(struct device *d,
- struct device_attribute *mattr, char *buf)
+static ssize_t show_protocols(struct device *d,
+ struct device_attribute *mattr, char *buf)
{
- char *s;
struct ir_input_dev *ir_dev = dev_get_drvdata(d);
- u64 ir_type = ir_dev->rc_tab.ir_type;
-
- IR_dprintk(1, "Current protocol is %lld\n", (long long)ir_type);
-
- /* FIXME: doesn't support multiple protocols at the same time */
- if (ir_type == IR_TYPE_UNKNOWN)
- s = "Unknown";
- else if (ir_type == IR_TYPE_RC5)
- s = "rc-5";
- else if (ir_type == IR_TYPE_NEC)
- s = "nec";
- else if (ir_type == IR_TYPE_RC6)
- s = "rc6";
- else if (ir_type == IR_TYPE_JVC)
- s = "jvc";
- else if (ir_type == IR_TYPE_SONY)
- s = "sony";
- else
- s = "other";
+ u64 allowed, enabled;
+ char *tmp = buf;
+ int i;
+
+ if (ir_dev->props->driver_type == RC_DRIVER_SCANCODE) {
+ enabled = ir_dev->rc_tab.ir_type;
+ allowed = ir_dev->props->allowed_protos;
+ } else {
+ enabled = ir_dev->raw->enabled_protocols;
+ allowed = ir_raw_get_allowed_protocols();
+ }
+
+ IR_dprintk(1, "allowed - 0x%llx, enabled - 0x%llx\n",
+ (long long)allowed,
+ (long long)enabled);
- return sprintf(buf, "%s\n", s);
+ for (i = 0; i < ARRAY_SIZE(proto_names); i++) {
+ if (allowed & enabled & proto_names[i].type)
+ tmp += sprintf(tmp, "[%s] ", proto_names[i].name);
+ else if (allowed & proto_names[i].type)
+ tmp += sprintf(tmp, "%s ", proto_names[i].name);
+ }
+
+ if (tmp != buf)
+ tmp--;
+ *tmp = '\n';
+ return tmp + 1 - buf;
}
/**
- * store_protocol() - shows the current IR protocol
+ * store_protocols() - changes the current IR protocol(s)
* @d: the device descriptor
* @mattr: the device attribute struct (unused)
* @buf: a pointer to the input buffer
* @len: length of the input buffer
*
* This routine is a callback routine for changing the IR protocol type.
- * it is trigged by reading /sys/class/rc/rc?/current_protocol.
- * It changes the IR the protocol name, if the IR type is recognized
- * by the driver.
- * If an unknown protocol name is used, returns -EINVAL.
+ * It is trigged by writing to /sys/class/rc/rc?/protocols.
+ * Writing "+proto" will add a protocol to the list of enabled protocols.
+ * Writing "-proto" will remove a protocol from the list of enabled protocols.
+ * Writing "proto" will enable only "proto".
+ * Writing "none" will disable all protocols.
+ * Returns -EINVAL if an invalid protocol combination or unknown protocol name
+ * is used, otherwise @len.
*/
-static ssize_t store_protocol(struct device *d,
- struct device_attribute *mattr,
- const char *data,
- size_t len)
+static ssize_t store_protocols(struct device *d,
+ struct device_attribute *mattr,
+ const char *data,
+ size_t len)
{
struct ir_input_dev *ir_dev = dev_get_drvdata(d);
- u64 ir_type = 0;
- int rc = -EINVAL;
+ bool enable, disable;
+ const char *tmp;
+ u64 type;
+ u64 mask;
+ int rc, i, count = 0;
unsigned long flags;
- char *buf;
-
- while ((buf = strsep((char **) &data, " \n")) != NULL) {
- if (!strcasecmp(buf, "rc-5") || !strcasecmp(buf, "rc5"))
- ir_type |= IR_TYPE_RC5;
- if (!strcasecmp(buf, "nec"))
- ir_type |= IR_TYPE_NEC;
- if (!strcasecmp(buf, "jvc"))
- ir_type |= IR_TYPE_JVC;
- if (!strcasecmp(buf, "sony"))
- ir_type |= IR_TYPE_SONY;
+
+ if (ir_dev->props->driver_type == RC_DRIVER_SCANCODE)
+ type = ir_dev->rc_tab.ir_type;
+ else
+ type = ir_dev->raw->enabled_protocols;
+
+ while ((tmp = strsep((char **) &data, " \n")) != NULL) {
+ if (!*tmp)
+ break;
+
+ if (*tmp == '+') {
+ enable = true;
+ disable = false;
+ tmp++;
+ } else if (*tmp == '-') {
+ enable = false;
+ disable = true;
+ tmp++;
+ } else {
+ enable = false;
+ disable = false;
+ }
+
+ if (!enable && !disable && !strncasecmp(tmp, PROTO_NONE, sizeof(PROTO_NONE))) {
+ tmp += sizeof(PROTO_NONE);
+ mask = 0;
+ count++;
+ } else {
+ for (i = 0; i < ARRAY_SIZE(proto_names); i++) {
+ if (!strncasecmp(tmp, proto_names[i].name, strlen(proto_names[i].name))) {
+ tmp += strlen(proto_names[i].name);
+ mask = proto_names[i].type;
+ break;
+ }
+ }
+ if (i == ARRAY_SIZE(proto_names)) {
+ IR_dprintk(1, "Unknown protocol: '%s'\n", tmp);
+ return -EINVAL;
+ }
+ count++;
+ }
+
+ if (enable)
+ type |= mask;
+ else if (disable)
+ type &= ~mask;
+ else
+ type = mask;
}
- if (!ir_type) {
- IR_dprintk(1, "Unknown protocol\n");
+ if (!count) {
+ IR_dprintk(1, "Protocol not specified\n");
return -EINVAL;
}
- if (ir_dev->props && ir_dev->props->change_protocol)
+ if (ir_dev->props && ir_dev->props->change_protocol) {
rc = ir_dev->props->change_protocol(ir_dev->props->priv,
- ir_type);
-
- if (rc < 0) {
- IR_dprintk(1, "Error setting protocol to %lld\n",
- (long long)ir_type);
- return -EINVAL;
+ type);
+ if (rc < 0) {
+ IR_dprintk(1, "Error setting protocols to 0x%llx\n",
+ (long long)type);
+ return -EINVAL;
+ }
}
- spin_lock_irqsave(&ir_dev->rc_tab.lock, flags);
- ir_dev->rc_tab.ir_type = ir_type;
- spin_unlock_irqrestore(&ir_dev->rc_tab.lock, flags);
+ if (ir_dev->props->driver_type == RC_DRIVER_SCANCODE) {
+ spin_lock_irqsave(&ir_dev->rc_tab.lock, flags);
+ ir_dev->rc_tab.ir_type = type;
+ spin_unlock_irqrestore(&ir_dev->rc_tab.lock, flags);
+ } else {
+ ir_dev->raw->enabled_protocols = type;
+ }
- IR_dprintk(1, "Current protocol(s) is(are) %lld\n",
- (long long)ir_type);
+ IR_dprintk(1, "Current protocol(s): 0x%llx\n",
+ (long long)type);
return len;
}
-static ssize_t show_supported_protocols(struct device *d,
- struct device_attribute *mattr, char *buf)
-{
- char *orgbuf = buf;
- struct ir_input_dev *ir_dev = dev_get_drvdata(d);
-
- /* FIXME: doesn't support multiple protocols at the same time */
- if (ir_dev->props->allowed_protos == IR_TYPE_UNKNOWN)
- buf += sprintf(buf, "unknown ");
- if (ir_dev->props->allowed_protos & IR_TYPE_RC5)
- buf += sprintf(buf, "rc-5 ");
- if (ir_dev->props->allowed_protos & IR_TYPE_NEC)
- buf += sprintf(buf, "nec ");
- if (buf == orgbuf)
- buf += sprintf(buf, "other ");
-
- buf += sprintf(buf - 1, "\n");
-
- return buf - orgbuf;
-}
-
#define ADD_HOTPLUG_VAR(fmt, val...) \
do { \
int err = add_uevent_var(env, fmt, val); \
@@ -159,7 +206,7 @@ static ssize_t show_supported_protocols(struct device *d,
return err; \
} while (0)
-static int ir_dev_uevent(struct device *device, struct kobj_uevent_env *env)
+static int rc_dev_uevent(struct device *device, struct kobj_uevent_env *env)
{
struct ir_input_dev *ir_dev = dev_get_drvdata(device);
@@ -174,34 +221,26 @@ static int ir_dev_uevent(struct device *device, struct kobj_uevent_env *env)
/*
* Static device attribute struct with the sysfs attributes for IR's
*/
-static DEVICE_ATTR(protocol, S_IRUGO | S_IWUSR,
- show_protocol, store_protocol);
+static DEVICE_ATTR(protocols, S_IRUGO | S_IWUSR,
+ show_protocols, store_protocols);
-static DEVICE_ATTR(supported_protocols, S_IRUGO | S_IWUSR,
- show_supported_protocols, NULL);
-
-static struct attribute *ir_hw_dev_attrs[] = {
- &dev_attr_protocol.attr,
- &dev_attr_supported_protocols.attr,
+static struct attribute *rc_dev_attrs[] = {
+ &dev_attr_protocols.attr,
NULL,
};
-static struct attribute_group ir_hw_dev_attr_grp = {
- .attrs = ir_hw_dev_attrs,
+static struct attribute_group rc_dev_attr_grp = {
+ .attrs = rc_dev_attrs,
};
-static const struct attribute_group *ir_hw_dev_attr_groups[] = {
- &ir_hw_dev_attr_grp,
+static const struct attribute_group *rc_dev_attr_groups[] = {
+ &rc_dev_attr_grp,
NULL
};
static struct device_type rc_dev_type = {
- .groups = ir_hw_dev_attr_groups,
- .uevent = ir_dev_uevent,
-};
-
-static struct device_type ir_raw_dev_type = {
- .uevent = ir_dev_uevent,
+ .groups = rc_dev_attr_groups,
+ .uevent = rc_dev_uevent,
};
/**
@@ -221,11 +260,7 @@ int ir_register_class(struct input_dev *input_dev)
if (unlikely(devno < 0))
return devno;
- if (ir_dev->props) {
- if (ir_dev->props->driver_type == RC_DRIVER_SCANCODE)
- ir_dev->dev.type = &rc_dev_type;
- } else
- ir_dev->dev.type = &ir_raw_dev_type;
+ ir_dev->dev.type = &rc_dev_type;
ir_dev->dev.class = &ir_input_class;
ir_dev->dev.parent = input_dev->dev.parent;
diff --git a/drivers/media/IR/keymaps/Makefile b/drivers/media/IR/keymaps/Makefile
index aea649fbcf5..cbee06243b5 100644
--- a/drivers/media/IR/keymaps/Makefile
+++ b/drivers/media/IR/keymaps/Makefile
@@ -14,6 +14,8 @@ obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t-pci.o \
rc-budget-ci-old.o \
rc-cinergy-1400.o \
rc-cinergy.o \
+ rc-dib0700-nec.o \
+ rc-dib0700-rc5.o \
rc-dm1105-nec.o \
rc-dntv-live-dvb-t.o \
rc-dntv-live-dvbt-pro.o \
@@ -37,6 +39,7 @@ obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t-pci.o \
rc-kaiomy.o \
rc-kworld-315u.o \
rc-kworld-plus-tv-analog.o \
+ rc-lirc.o \
rc-manli.o \
rc-msi-tvanywhere.o \
rc-msi-tvanywhere-plus.o \
@@ -57,6 +60,7 @@ obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t-pci.o \
rc-pv951.o \
rc-rc5-hauppauge-new.o \
rc-rc5-tv.o \
+ rc-rc6-mce.o \
rc-real-audio-220-32-keys.o \
rc-tbs-nec.o \
rc-terratec-cinergy-xs.o \
diff --git a/drivers/media/IR/keymaps/rc-dib0700-nec.c b/drivers/media/IR/keymaps/rc-dib0700-nec.c
new file mode 100644
index 00000000000..ae1832038fb
--- /dev/null
+++ b/drivers/media/IR/keymaps/rc-dib0700-nec.c
@@ -0,0 +1,124 @@
+/* rc-dvb0700-big.c - Keytable for devices in dvb0700
+ *
+ * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ *
+ * TODO: This table is a real mess, as it merges RC codes from several
+ * devices into a big table. It also has both RC-5 and NEC codes inside.
+ * It should be broken into small tables, and the protocols should properly
+ * be indentificated.
+ *
+ * The table were imported from dib0700_devices.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.
+ */
+
+#include <media/rc-map.h>
+
+static struct ir_scancode dib0700_nec_table[] = {
+ /* Key codes for the Pixelview SBTVD remote */
+ { 0x8613, KEY_MUTE },
+ { 0x8612, KEY_POWER },
+ { 0x8601, KEY_1 },
+ { 0x8602, KEY_2 },
+ { 0x8603, KEY_3 },
+ { 0x8604, KEY_4 },
+ { 0x8605, KEY_5 },
+ { 0x8606, KEY_6 },
+ { 0x8607, KEY_7 },
+ { 0x8608, KEY_8 },
+ { 0x8609, KEY_9 },
+ { 0x8600, KEY_0 },
+ { 0x860d, KEY_CHANNELUP },
+ { 0x8619, KEY_CHANNELDOWN },
+ { 0x8610, KEY_VOLUMEUP },
+ { 0x860c, KEY_VOLUMEDOWN },
+
+ { 0x860a, KEY_CAMERA },
+ { 0x860b, KEY_ZOOM },
+ { 0x861b, KEY_BACKSPACE },
+ { 0x8615, KEY_ENTER },
+
+ { 0x861d, KEY_UP },
+ { 0x861e, KEY_DOWN },
+ { 0x860e, KEY_LEFT },
+ { 0x860f, KEY_RIGHT },
+
+ { 0x8618, KEY_RECORD },
+ { 0x861a, KEY_STOP },
+
+ /* Key codes for the EvolutePC TVWay+ remote */
+ { 0x7a00, KEY_MENU },
+ { 0x7a01, KEY_RECORD },
+ { 0x7a02, KEY_PLAY },
+ { 0x7a03, KEY_STOP },
+ { 0x7a10, KEY_CHANNELUP },
+ { 0x7a11, KEY_CHANNELDOWN },
+ { 0x7a12, KEY_VOLUMEUP },
+ { 0x7a13, KEY_VOLUMEDOWN },
+ { 0x7a40, KEY_POWER },
+ { 0x7a41, KEY_MUTE },
+
+ /* Key codes for the Elgato EyeTV Diversity silver remote */
+ { 0x4501, KEY_POWER },
+ { 0x4502, KEY_MUTE },
+ { 0x4503, KEY_1 },
+ { 0x4504, KEY_2 },
+ { 0x4505, KEY_3 },
+ { 0x4506, KEY_4 },
+ { 0x4507, KEY_5 },
+ { 0x4508, KEY_6 },
+ { 0x4509, KEY_7 },
+ { 0x450a, KEY_8 },
+ { 0x450b, KEY_9 },
+ { 0x450c, KEY_LAST },
+ { 0x450d, KEY_0 },
+ { 0x450e, KEY_ENTER },
+ { 0x450f, KEY_RED },
+ { 0x4510, KEY_CHANNELUP },
+ { 0x4511, KEY_GREEN },
+ { 0x4512, KEY_VOLUMEDOWN },
+ { 0x4513, KEY_OK },
+ { 0x4514, KEY_VOLUMEUP },
+ { 0x4515, KEY_YELLOW },
+ { 0x4516, KEY_CHANNELDOWN },
+ { 0x4517, KEY_BLUE },
+ { 0x4518, KEY_LEFT }, /* Skip backwards */
+ { 0x4519, KEY_PLAYPAUSE },
+ { 0x451a, KEY_RIGHT }, /* Skip forward */
+ { 0x451b, KEY_REWIND },
+ { 0x451c, KEY_L }, /* Live */
+ { 0x451d, KEY_FASTFORWARD },
+ { 0x451e, KEY_STOP }, /* 'Reveal' for Teletext */
+ { 0x451f, KEY_MENU }, /* KEY_TEXT for Teletext */
+ { 0x4540, KEY_RECORD }, /* Font 'Size' for Teletext */
+ { 0x4541, KEY_SCREEN }, /* Full screen toggle, 'Hold' for Teletext */
+ { 0x4542, KEY_SELECT }, /* Select video input, 'Select' for Teletext */
+};
+
+static struct rc_keymap dib0700_nec_map = {
+ .map = {
+ .scan = dib0700_nec_table,
+ .size = ARRAY_SIZE(dib0700_nec_table),
+ .ir_type = IR_TYPE_NEC,
+ .name = RC_MAP_DIB0700_NEC_TABLE,
+ }
+};
+
+static int __init init_rc_map(void)
+{
+ return ir_register_map(&dib0700_nec_map);
+}
+
+static void __exit exit_rc_map(void)
+{
+ ir_unregister_map(&dib0700_nec_map);
+}
+
+module_init(init_rc_map)
+module_exit(exit_rc_map)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
diff --git a/drivers/media/IR/keymaps/rc-dib0700-rc5.c b/drivers/media/IR/keymaps/rc-dib0700-rc5.c
new file mode 100644
index 00000000000..4a4797cfd77
--- /dev/null
+++ b/drivers/media/IR/keymaps/rc-dib0700-rc5.c
@@ -0,0 +1,235 @@
+/* rc-dvb0700-big.c - Keytable for devices in dvb0700
+ *
+ * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ *
+ * TODO: This table is a real mess, as it merges RC codes from several
+ * devices into a big table. It also has both RC-5 and NEC codes inside.
+ * It should be broken into small tables, and the protocols should properly
+ * be indentificated.
+ *
+ * The table were imported from dib0700_devices.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.
+ */
+
+#include <media/rc-map.h>
+
+static struct ir_scancode dib0700_rc5_table[] = {
+ /* Key codes for the tiny Pinnacle remote*/
+ { 0x0700, KEY_MUTE },
+ { 0x0701, KEY_MENU }, /* Pinnacle logo */
+ { 0x0739, KEY_POWER },
+ { 0x0703, KEY_VOLUMEUP },
+ { 0x0709, KEY_VOLUMEDOWN },
+ { 0x0706, KEY_CHANNELUP },
+ { 0x070c, KEY_CHANNELDOWN },
+ { 0x070f, KEY_1 },
+ { 0x0715, KEY_2 },
+ { 0x0710, KEY_3 },
+ { 0x0718, KEY_4 },
+ { 0x071b, KEY_5 },
+ { 0x071e, KEY_6 },
+ { 0x0711, KEY_7 },
+ { 0x0721, KEY_8 },
+ { 0x0712, KEY_9 },
+ { 0x0727, KEY_0 },
+ { 0x0724, KEY_SCREEN }, /* 'Square' key */
+ { 0x072a, KEY_TEXT }, /* 'T' key */
+ { 0x072d, KEY_REWIND },
+ { 0x0730, KEY_PLAY },
+ { 0x0733, KEY_FASTFORWARD },
+ { 0x0736, KEY_RECORD },
+ { 0x073c, KEY_STOP },
+ { 0x073f, KEY_CANCEL }, /* '?' key */
+
+ /* Key codes for the Terratec Cinergy DT XS Diversity, similar to cinergyT2.c */
+ { 0xeb01, KEY_POWER },
+ { 0xeb02, KEY_1 },
+ { 0xeb03, KEY_2 },
+ { 0xeb04, KEY_3 },
+ { 0xeb05, KEY_4 },
+ { 0xeb06, KEY_5 },
+ { 0xeb07, KEY_6 },
+ { 0xeb08, KEY_7 },
+ { 0xeb09, KEY_8 },
+ { 0xeb0a, KEY_9 },
+ { 0xeb0b, KEY_VIDEO },
+ { 0xeb0c, KEY_0 },
+ { 0xeb0d, KEY_REFRESH },
+ { 0xeb0f, KEY_EPG },
+ { 0xeb10, KEY_UP },
+ { 0xeb11, KEY_LEFT },
+ { 0xeb12, KEY_OK },
+ { 0xeb13, KEY_RIGHT },
+ { 0xeb14, KEY_DOWN },
+ { 0xeb16, KEY_INFO },
+ { 0xeb17, KEY_RED },
+ { 0xeb18, KEY_GREEN },
+ { 0xeb19, KEY_YELLOW },
+ { 0xeb1a, KEY_BLUE },
+ { 0xeb1b, KEY_CHANNELUP },
+ { 0xeb1c, KEY_VOLUMEUP },
+ { 0xeb1d, KEY_MUTE },
+ { 0xeb1e, KEY_VOLUMEDOWN },
+ { 0xeb1f, KEY_CHANNELDOWN },
+ { 0xeb40, KEY_PAUSE },
+ { 0xeb41, KEY_HOME },
+ { 0xeb42, KEY_MENU }, /* DVD Menu */
+ { 0xeb43, KEY_SUBTITLE },
+ { 0xeb44, KEY_TEXT }, /* Teletext */
+ { 0xeb45, KEY_DELETE },
+ { 0xeb46, KEY_TV },
+ { 0xeb47, KEY_DVD },
+ { 0xeb48, KEY_STOP },
+ { 0xeb49, KEY_VIDEO },
+ { 0xeb4a, KEY_AUDIO }, /* Music */
+ { 0xeb4b, KEY_SCREEN }, /* Pic */
+ { 0xeb4c, KEY_PLAY },
+ { 0xeb4d, KEY_BACK },
+ { 0xeb4e, KEY_REWIND },
+ { 0xeb4f, KEY_FASTFORWARD },
+ { 0xeb54, KEY_PREVIOUS },
+ { 0xeb58, KEY_RECORD },
+ { 0xeb5c, KEY_NEXT },
+
+ /* Key codes for the Haupauge WinTV Nova-TD, copied from nova-t-usb2.c (Nova-T USB2) */
+ { 0x1e00, KEY_0 },
+ { 0x1e01, KEY_1 },
+ { 0x1e02, KEY_2 },
+ { 0x1e03, KEY_3 },
+ { 0x1e04, KEY_4 },
+ { 0x1e05, KEY_5 },
+ { 0x1e06, KEY_6 },
+ { 0x1e07, KEY_7 },
+ { 0x1e08, KEY_8 },
+ { 0x1e09, KEY_9 },
+ { 0x1e0a, KEY_KPASTERISK },
+ { 0x1e0b, KEY_RED },
+ { 0x1e0c, KEY_RADIO },
+ { 0x1e0d, KEY_MENU },
+ { 0x1e0e, KEY_GRAVE }, /* # */
+ { 0x1e0f, KEY_MUTE },
+ { 0x1e10, KEY_VOLUMEUP },
+ { 0x1e11, KEY_VOLUMEDOWN },
+ { 0x1e12, KEY_CHANNEL },
+ { 0x1e14, KEY_UP },
+ { 0x1e15, KEY_DOWN },
+ { 0x1e16, KEY_LEFT },
+ { 0x1e17, KEY_RIGHT },
+ { 0x1e18, KEY_VIDEO },
+ { 0x1e19, KEY_AUDIO },
+ { 0x1e1a, KEY_MEDIA },
+ { 0x1e1b, KEY_EPG },
+ { 0x1e1c, KEY_TV },
+ { 0x1e1e, KEY_NEXT },
+ { 0x1e1f, KEY_BACK },
+ { 0x1e20, KEY_CHANNELUP },
+ { 0x1e21, KEY_CHANNELDOWN },
+ { 0x1e24, KEY_LAST }, /* Skip backwards */
+ { 0x1e25, KEY_OK },
+ { 0x1e29, KEY_BLUE},
+ { 0x1e2e, KEY_GREEN },
+ { 0x1e30, KEY_PAUSE },
+ { 0x1e32, KEY_REWIND },
+ { 0x1e34, KEY_FASTFORWARD },
+ { 0x1e35, KEY_PLAY },
+ { 0x1e36, KEY_STOP },
+ { 0x1e37, KEY_RECORD },
+ { 0x1e38, KEY_YELLOW },
+ { 0x1e3b, KEY_GOTO },
+ { 0x1e3d, KEY_POWER },
+
+ /* Key codes for the Leadtek Winfast DTV Dongle */
+ { 0x0042, KEY_POWER },
+ { 0x077c, KEY_TUNER },
+ { 0x0f4e, KEY_PRINT }, /* PREVIEW */
+ { 0x0840, KEY_SCREEN }, /* full screen toggle*/
+ { 0x0f71, KEY_DOT }, /* frequency */
+ { 0x0743, KEY_0 },
+ { 0x0c41, KEY_1 },
+ { 0x0443, KEY_2 },
+ { 0x0b7f, KEY_3 },
+ { 0x0e41, KEY_4 },
+ { 0x0643, KEY_5 },
+ { 0x097f, KEY_6 },
+ { 0x0d7e, KEY_7 },
+ { 0x057c, KEY_8 },
+ { 0x0a40, KEY_9 },
+ { 0x0e4e, KEY_CLEAR },
+ { 0x047c, KEY_CHANNEL }, /* show channel number */
+ { 0x0f41, KEY_LAST }, /* recall */
+ { 0x0342, KEY_MUTE },
+ { 0x064c, KEY_RESERVED }, /* PIP button*/
+ { 0x0172, KEY_SHUFFLE }, /* SNAPSHOT */
+ { 0x0c4e, KEY_PLAYPAUSE }, /* TIMESHIFT */
+ { 0x0b70, KEY_RECORD },
+ { 0x037d, KEY_VOLUMEUP },
+ { 0x017d, KEY_VOLUMEDOWN },
+ { 0x0242, KEY_CHANNELUP },
+ { 0x007d, KEY_CHANNELDOWN },
+
+ /* Key codes for Nova-TD "credit card" remote control. */
+ { 0x1d00, KEY_0 },
+ { 0x1d01, KEY_1 },
+ { 0x1d02, KEY_2 },
+ { 0x1d03, KEY_3 },
+ { 0x1d04, KEY_4 },
+ { 0x1d05, KEY_5 },
+ { 0x1d06, KEY_6 },
+ { 0x1d07, KEY_7 },
+ { 0x1d08, KEY_8 },
+ { 0x1d09, KEY_9 },
+ { 0x1d0a, KEY_TEXT },
+ { 0x1d0d, KEY_MENU },
+ { 0x1d0f, KEY_MUTE },
+ { 0x1d10, KEY_VOLUMEUP },
+ { 0x1d11, KEY_VOLUMEDOWN },
+ { 0x1d12, KEY_CHANNEL },
+ { 0x1d14, KEY_UP },
+ { 0x1d15, KEY_DOWN },
+ { 0x1d16, KEY_LEFT },
+ { 0x1d17, KEY_RIGHT },
+ { 0x1d1c, KEY_TV },
+ { 0x1d1e, KEY_NEXT },
+ { 0x1d1f, KEY_BACK },
+ { 0x1d20, KEY_CHANNELUP },
+ { 0x1d21, KEY_CHANNELDOWN },
+ { 0x1d24, KEY_LAST },
+ { 0x1d25, KEY_OK },
+ { 0x1d30, KEY_PAUSE },
+ { 0x1d32, KEY_REWIND },
+ { 0x1d34, KEY_FASTFORWARD },
+ { 0x1d35, KEY_PLAY },
+ { 0x1d36, KEY_STOP },
+ { 0x1d37, KEY_RECORD },
+ { 0x1d3b, KEY_GOTO },
+ { 0x1d3d, KEY_POWER },
+};
+
+static struct rc_keymap dib0700_rc5_map = {
+ .map = {
+ .scan = dib0700_rc5_table,
+ .size = ARRAY_SIZE(dib0700_rc5_table),
+ .ir_type = IR_TYPE_RC5,
+ .name = RC_MAP_DIB0700_RC5_TABLE,
+ }
+};
+
+static int __init init_rc_map(void)
+{
+ return ir_register_map(&dib0700_rc5_map);
+}
+
+static void __exit exit_rc_map(void)
+{
+ ir_unregister_map(&dib0700_rc5_map);
+}
+
+module_init(init_rc_map)
+module_exit(exit_rc_map)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
diff --git a/drivers/media/IR/keymaps/rc-lirc.c b/drivers/media/IR/keymaps/rc-lirc.c
new file mode 100644
index 00000000000..43fcf903508
--- /dev/null
+++ b/drivers/media/IR/keymaps/rc-lirc.c
@@ -0,0 +1,41 @@
+/* rc-lirc.c - Empty dummy keytable, for use when its preferred to pass
+ * all raw IR data to the lirc userspace decoder.
+ *
+ * Copyright (c) 2010 by Jarod Wilson <jarod@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 <media/ir-core.h>
+
+static struct ir_scancode lirc[] = {
+ { },
+};
+
+static struct rc_keymap lirc_map = {
+ .map = {
+ .scan = lirc,
+ .size = ARRAY_SIZE(lirc),
+ .ir_type = IR_TYPE_LIRC,
+ .name = RC_MAP_LIRC,
+ }
+};
+
+static int __init init_rc_map_lirc(void)
+{
+ return ir_register_map(&lirc_map);
+}
+
+static void __exit exit_rc_map_lirc(void)
+{
+ ir_unregister_map(&lirc_map);
+}
+
+module_init(init_rc_map_lirc)
+module_exit(exit_rc_map_lirc)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Jarod Wilson <jarod@redhat.com>");
diff --git a/drivers/media/IR/keymaps/rc-rc6-mce.c b/drivers/media/IR/keymaps/rc-rc6-mce.c
new file mode 100644
index 00000000000..c6726a8039b
--- /dev/null
+++ b/drivers/media/IR/keymaps/rc-rc6-mce.c
@@ -0,0 +1,105 @@
+/* rc-rc6-mce.c - Keytable for Windows Media Center RC-6 remotes for use
+ * with the Media Center Edition eHome Infrared Transceiver.
+ *
+ * Copyright (c) 2010 by Jarod Wilson <jarod@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 <media/rc-map.h>
+
+static struct ir_scancode rc6_mce[] = {
+ { 0x800f0415, KEY_REWIND },
+ { 0x800f0414, KEY_FASTFORWARD },
+ { 0x800f041b, KEY_PREVIOUS },
+ { 0x800f041a, KEY_NEXT },
+
+ { 0x800f0416, KEY_PLAY },
+ { 0x800f0418, KEY_PAUSE },
+ { 0x800f0419, KEY_STOP },
+ { 0x800f0417, KEY_RECORD },
+
+ { 0x800f041e, KEY_UP },
+ { 0x800f041f, KEY_DOWN },
+ { 0x800f0420, KEY_LEFT },
+ { 0x800f0421, KEY_RIGHT },
+
+ { 0x800f040b, KEY_ENTER },
+ { 0x800f0422, KEY_OK },
+ { 0x800f0423, KEY_EXIT },
+ { 0x800f040a, KEY_DELETE },
+
+ { 0x800f040e, KEY_MUTE },
+ { 0x800f0410, KEY_VOLUMEUP },
+ { 0x800f0411, KEY_VOLUMEDOWN },
+ { 0x800f0412, KEY_CHANNELUP },
+ { 0x800f0413, KEY_CHANNELDOWN },
+
+ { 0x800f0401, KEY_NUMERIC_1 },
+ { 0x800f0402, KEY_NUMERIC_2 },
+ { 0x800f0403, KEY_NUMERIC_3 },
+ { 0x800f0404, KEY_NUMERIC_4 },
+ { 0x800f0405, KEY_NUMERIC_5 },
+ { 0x800f0406, KEY_NUMERIC_6 },
+ { 0x800f0407, KEY_NUMERIC_7 },
+ { 0x800f0408, KEY_NUMERIC_8 },
+ { 0x800f0409, KEY_NUMERIC_9 },
+ { 0x800f0400, KEY_NUMERIC_0 },
+
+ { 0x800f041d, KEY_NUMERIC_STAR },
+ { 0x800f041c, KEY_NUMERIC_POUND },
+
+ { 0x800f0446, KEY_TV },
+ { 0x800f0447, KEY_AUDIO }, /* My Music */
+ { 0x800f0448, KEY_PVR }, /* RecordedTV */
+ { 0x800f0449, KEY_CAMERA },
+ { 0x800f044a, KEY_VIDEO },
+ { 0x800f0424, KEY_DVD },
+ { 0x800f0425, KEY_TUNER }, /* LiveTV */
+ { 0x800f0450, KEY_RADIO },
+
+ { 0x800f044c, KEY_LANGUAGE },
+ { 0x800f0427, KEY_ZOOM }, /* Aspect */
+
+ { 0x800f045b, KEY_RED },
+ { 0x800f045c, KEY_GREEN },
+ { 0x800f045d, KEY_YELLOW },
+ { 0x800f045e, KEY_BLUE },
+
+ { 0x800f040f, KEY_INFO },
+ { 0x800f0426, KEY_EPG }, /* Guide */
+ { 0x800f045a, KEY_SUBTITLE }, /* Caption/Teletext */
+ { 0x800f044d, KEY_TITLE },
+
+ { 0x800f040c, KEY_POWER },
+ { 0x800f040d, KEY_PROG1 }, /* Windows MCE button */
+
+};
+
+static struct rc_keymap rc6_mce_map = {
+ .map = {
+ .scan = rc6_mce,
+ .size = ARRAY_SIZE(rc6_mce),
+ .ir_type = IR_TYPE_RC6,
+ .name = RC_MAP_RC6_MCE,
+ }
+};
+
+static int __init init_rc_map_rc6_mce(void)
+{
+ return ir_register_map(&rc6_mce_map);
+}
+
+static void __exit exit_rc_map_rc6_mce(void)
+{
+ ir_unregister_map(&rc6_mce_map);
+}
+
+module_init(init_rc_map_rc6_mce)
+module_exit(exit_rc_map_rc6_mce)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Jarod Wilson <jarod@redhat.com>");
diff --git a/drivers/media/IR/lirc_dev.c b/drivers/media/IR/lirc_dev.c
new file mode 100644
index 00000000000..899891bec35
--- /dev/null
+++ b/drivers/media/IR/lirc_dev.c
@@ -0,0 +1,764 @@
+/*
+ * LIRC base driver
+ *
+ * by Artur Lipowski <alipowski@interia.pl>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * 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/sched.h>
+#include <linux/errno.h>
+#include <linux/ioctl.h>
+#include <linux/fs.h>
+#include <linux/poll.h>
+#include <linux/completion.h>
+#include <linux/errno.h>
+#include <linux/mutex.h>
+#include <linux/wait.h>
+#include <linux/unistd.h>
+#include <linux/kthread.h>
+#include <linux/bitops.h>
+#include <linux/device.h>
+#include <linux/cdev.h>
+
+#include <media/lirc.h>
+#include <media/lirc_dev.h>
+
+static int debug;
+
+#define IRCTL_DEV_NAME "BaseRemoteCtl"
+#define NOPLUG -1
+#define LOGHEAD "lirc_dev (%s[%d]): "
+
+static dev_t lirc_base_dev;
+
+struct irctl {
+ struct lirc_driver d;
+ int attached;
+ int open;
+
+ struct mutex irctl_lock;
+ struct lirc_buffer *buf;
+ unsigned int chunk_size;
+
+ struct task_struct *task;
+ long jiffies_to_wait;
+
+ struct cdev cdev;
+};
+
+static DEFINE_MUTEX(lirc_dev_lock);
+
+static struct irctl *irctls[MAX_IRCTL_DEVICES];
+
+/* Only used for sysfs but defined to void otherwise */
+static struct class *lirc_class;
+
+/* helper function
+ * initializes the irctl structure
+ */
+static void init_irctl(struct irctl *ir)
+{
+ dev_dbg(ir->d.dev, LOGHEAD "initializing irctl\n",
+ ir->d.name, ir->d.minor);
+ mutex_init(&ir->irctl_lock);
+ ir->d.minor = NOPLUG;
+}
+
+static void cleanup(struct irctl *ir)
+{
+ dev_dbg(ir->d.dev, LOGHEAD "cleaning up\n", ir->d.name, ir->d.minor);
+
+ device_destroy(lirc_class, MKDEV(MAJOR(lirc_base_dev), ir->d.minor));
+
+ if (ir->buf != ir->d.rbuf) {
+ lirc_buffer_free(ir->buf);
+ kfree(ir->buf);
+ }
+ ir->buf = NULL;
+}
+
+/* helper function
+ * reads key codes from driver and puts them into buffer
+ * returns 0 on success
+ */
+static int add_to_buf(struct irctl *ir)
+{
+ if (ir->d.add_to_buf) {
+ int res = -ENODATA;
+ int got_data = 0;
+
+ /*
+ * service the device as long as it is returning
+ * data and we have space
+ */
+get_data:
+ res = ir->d.add_to_buf(ir->d.data, ir->buf);
+ if (res == 0) {
+ got_data++;
+ goto get_data;
+ }
+
+ if (res == -ENODEV)
+ kthread_stop(ir->task);
+
+ return got_data ? 0 : res;
+ }
+
+ return 0;
+}
+
+/* main function of the polling thread
+ */
+static int lirc_thread(void *irctl)
+{
+ struct irctl *ir = irctl;
+
+ dev_dbg(ir->d.dev, LOGHEAD "poll thread started\n",
+ ir->d.name, ir->d.minor);
+
+ do {
+ if (ir->open) {
+ if (ir->jiffies_to_wait) {
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule_timeout(ir->jiffies_to_wait);
+ }
+ if (kthread_should_stop())
+ break;
+ if (!add_to_buf(ir))
+ wake_up_interruptible(&ir->buf->wait_poll);
+ } else {
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule();
+ }
+ } while (!kthread_should_stop());
+
+ dev_dbg(ir->d.dev, LOGHEAD "poll thread ended\n",
+ ir->d.name, ir->d.minor);
+
+ return 0;
+}
+
+
+static struct file_operations fops = {
+ .owner = THIS_MODULE,
+ .read = lirc_dev_fop_read,
+ .write = lirc_dev_fop_write,
+ .poll = lirc_dev_fop_poll,
+ .unlocked_ioctl = lirc_dev_fop_ioctl,
+ .open = lirc_dev_fop_open,
+ .release = lirc_dev_fop_close,
+};
+
+static int lirc_cdev_add(struct irctl *ir)
+{
+ int retval;
+ struct lirc_driver *d = &ir->d;
+
+ if (d->fops) {
+ cdev_init(&ir->cdev, d->fops);
+ ir->cdev.owner = d->owner;
+ } else {
+ cdev_init(&ir->cdev, &fops);
+ ir->cdev.owner = THIS_MODULE;
+ }
+ kobject_set_name(&ir->cdev.kobj, "lirc%d", d->minor);
+
+ retval = cdev_add(&ir->cdev, MKDEV(MAJOR(lirc_base_dev), d->minor), 1);
+ if (retval)
+ kobject_put(&ir->cdev.kobj);
+
+ return retval;
+}
+
+int lirc_register_driver(struct lirc_driver *d)
+{
+ struct irctl *ir;
+ int minor;
+ int bytes_in_key;
+ unsigned int chunk_size;
+ unsigned int buffer_size;
+ int err;
+
+ if (!d) {
+ printk(KERN_ERR "lirc_dev: lirc_register_driver: "
+ "driver pointer must be not NULL!\n");
+ err = -EBADRQC;
+ goto out;
+ }
+
+ if (MAX_IRCTL_DEVICES <= d->minor) {
+ dev_err(d->dev, "lirc_dev: lirc_register_driver: "
+ "\"minor\" must be between 0 and %d (%d)!\n",
+ MAX_IRCTL_DEVICES-1, d->minor);
+ err = -EBADRQC;
+ goto out;
+ }
+
+ if (1 > d->code_length || (BUFLEN * 8) < d->code_length) {
+ dev_err(d->dev, "lirc_dev: lirc_register_driver: "
+ "code length in bits for minor (%d) "
+ "must be less than %d!\n",
+ d->minor, BUFLEN * 8);
+ err = -EBADRQC;
+ goto out;
+ }
+
+ dev_dbg(d->dev, "lirc_dev: lirc_register_driver: sample_rate: %d\n",
+ d->sample_rate);
+ if (d->sample_rate) {
+ if (2 > d->sample_rate || HZ < d->sample_rate) {
+ dev_err(d->dev, "lirc_dev: lirc_register_driver: "
+ "sample_rate must be between 2 and %d!\n", HZ);
+ err = -EBADRQC;
+ goto out;
+ }
+ if (!d->add_to_buf) {
+ dev_err(d->dev, "lirc_dev: lirc_register_driver: "
+ "add_to_buf cannot be NULL when "
+ "sample_rate is set\n");
+ err = -EBADRQC;
+ goto out;
+ }
+ } else if (!(d->fops && d->fops->read) && !d->rbuf) {
+ dev_err(d->dev, "lirc_dev: lirc_register_driver: "
+ "fops->read and rbuf cannot all be NULL!\n");
+ err = -EBADRQC;
+ goto out;
+ } else if (!d->rbuf) {
+ if (!(d->fops && d->fops->read && d->fops->poll &&
+ d->fops->unlocked_ioctl)) {
+ dev_err(d->dev, "lirc_dev: lirc_register_driver: "
+ "neither read, poll nor unlocked_ioctl can be NULL!\n");
+ err = -EBADRQC;
+ goto out;
+ }
+ }
+
+ mutex_lock(&lirc_dev_lock);
+
+ minor = d->minor;
+
+ if (minor < 0) {
+ /* find first free slot for driver */
+ for (minor = 0; minor < MAX_IRCTL_DEVICES; minor++)
+ if (!irctls[minor])
+ break;
+ if (MAX_IRCTL_DEVICES == minor) {
+ dev_err(d->dev, "lirc_dev: lirc_register_driver: "
+ "no free slots for drivers!\n");
+ err = -ENOMEM;
+ goto out_lock;
+ }
+ } else if (irctls[minor]) {
+ dev_err(d->dev, "lirc_dev: lirc_register_driver: "
+ "minor (%d) just registered!\n", minor);
+ err = -EBUSY;
+ goto out_lock;
+ }
+
+ ir = kzalloc(sizeof(struct irctl), GFP_KERNEL);
+ if (!ir) {
+ err = -ENOMEM;
+ goto out_lock;
+ }
+ init_irctl(ir);
+ irctls[minor] = ir;
+ d->minor = minor;
+
+ if (d->sample_rate) {
+ ir->jiffies_to_wait = HZ / d->sample_rate;
+ } else {
+ /* it means - wait for external event in task queue */
+ ir->jiffies_to_wait = 0;
+ }
+
+ /* some safety check 8-) */
+ d->name[sizeof(d->name)-1] = '\0';
+
+ bytes_in_key = BITS_TO_LONGS(d->code_length) +
+ (d->code_length % 8 ? 1 : 0);
+ buffer_size = d->buffer_size ? d->buffer_size : BUFLEN / bytes_in_key;
+ chunk_size = d->chunk_size ? d->chunk_size : bytes_in_key;
+
+ if (d->rbuf) {
+ ir->buf = d->rbuf;
+ } else {
+ ir->buf = kmalloc(sizeof(struct lirc_buffer), GFP_KERNEL);
+ if (!ir->buf) {
+ err = -ENOMEM;
+ goto out_lock;
+ }
+ err = lirc_buffer_init(ir->buf, chunk_size, buffer_size);
+ if (err) {
+ kfree(ir->buf);
+ goto out_lock;
+ }
+ }
+ ir->chunk_size = ir->buf->chunk_size;
+
+ if (d->features == 0)
+ d->features = LIRC_CAN_REC_LIRCCODE;
+
+ ir->d = *d;
+ ir->d.minor = minor;
+
+ device_create(lirc_class, ir->d.dev,
+ MKDEV(MAJOR(lirc_base_dev), ir->d.minor), NULL,
+ "lirc%u", ir->d.minor);
+
+ if (d->sample_rate) {
+ /* try to fire up polling thread */
+ ir->task = kthread_run(lirc_thread, (void *)ir, "lirc_dev");
+ if (IS_ERR(ir->task)) {
+ dev_err(d->dev, "lirc_dev: lirc_register_driver: "
+ "cannot run poll thread for minor = %d\n",
+ d->minor);
+ err = -ECHILD;
+ goto out_sysfs;
+ }
+ }
+
+ err = lirc_cdev_add(ir);
+ if (err)
+ goto out_sysfs;
+
+ ir->attached = 1;
+ mutex_unlock(&lirc_dev_lock);
+
+ dev_info(ir->d.dev, "lirc_dev: driver %s registered at minor = %d\n",
+ ir->d.name, ir->d.minor);
+ return minor;
+
+out_sysfs:
+ device_destroy(lirc_class, MKDEV(MAJOR(lirc_base_dev), ir->d.minor));
+out_lock:
+ mutex_unlock(&lirc_dev_lock);
+out:
+ return err;
+}
+EXPORT_SYMBOL(lirc_register_driver);
+
+int lirc_unregister_driver(int minor)
+{
+ struct irctl *ir;
+
+ if (minor < 0 || minor >= MAX_IRCTL_DEVICES) {
+ printk(KERN_ERR "lirc_dev: lirc_unregister_driver: "
+ "\"minor (%d)\" must be between 0 and %d!\n",
+ minor, MAX_IRCTL_DEVICES-1);
+ return -EBADRQC;
+ }
+
+ ir = irctls[minor];
+
+ mutex_lock(&lirc_dev_lock);
+
+ if (ir->d.minor != minor) {
+ printk(KERN_ERR "lirc_dev: lirc_unregister_driver: "
+ "minor (%d) device not registered!", minor);
+ mutex_unlock(&lirc_dev_lock);
+ return -ENOENT;
+ }
+
+ /* end up polling thread */
+ if (ir->task)
+ kthread_stop(ir->task);
+
+ dev_dbg(ir->d.dev, "lirc_dev: driver %s unregistered from minor = %d\n",
+ ir->d.name, ir->d.minor);
+
+ ir->attached = 0;
+ if (ir->open) {
+ dev_dbg(ir->d.dev, LOGHEAD "releasing opened driver\n",
+ ir->d.name, ir->d.minor);
+ wake_up_interruptible(&ir->buf->wait_poll);
+ mutex_lock(&ir->irctl_lock);
+ ir->d.set_use_dec(ir->d.data);
+ module_put(ir->d.owner);
+ mutex_unlock(&ir->irctl_lock);
+ cdev_del(&ir->cdev);
+ } else {
+ cleanup(ir);
+ cdev_del(&ir->cdev);
+ kfree(ir);
+ irctls[minor] = NULL;
+ }
+
+ mutex_unlock(&lirc_dev_lock);
+
+ return 0;
+}
+EXPORT_SYMBOL(lirc_unregister_driver);
+
+int lirc_dev_fop_open(struct inode *inode, struct file *file)
+{
+ struct irctl *ir;
+ int retval = 0;
+
+ if (iminor(inode) >= MAX_IRCTL_DEVICES) {
+ printk(KERN_WARNING "lirc_dev [%d]: open result = -ENODEV\n",
+ iminor(inode));
+ return -ENODEV;
+ }
+
+ if (mutex_lock_interruptible(&lirc_dev_lock))
+ return -ERESTARTSYS;
+
+ ir = irctls[iminor(inode)];
+ if (!ir) {
+ retval = -ENODEV;
+ goto error;
+ }
+ file->private_data = ir;
+
+ dev_dbg(ir->d.dev, LOGHEAD "open called\n", ir->d.name, ir->d.minor);
+
+ if (ir->d.minor == NOPLUG) {
+ retval = -ENODEV;
+ goto error;
+ }
+
+ if (ir->open) {
+ retval = -EBUSY;
+ goto error;
+ }
+
+ if (try_module_get(ir->d.owner)) {
+ ++ir->open;
+ retval = ir->d.set_use_inc(ir->d.data);
+
+ if (retval) {
+ module_put(ir->d.owner);
+ --ir->open;
+ } else {
+ lirc_buffer_clear(ir->buf);
+ }
+ if (ir->task)
+ wake_up_process(ir->task);
+ }
+
+error:
+ if (ir)
+ dev_dbg(ir->d.dev, LOGHEAD "open result = %d\n",
+ ir->d.name, ir->d.minor, retval);
+
+ mutex_unlock(&lirc_dev_lock);
+
+ return retval;
+}
+EXPORT_SYMBOL(lirc_dev_fop_open);
+
+int lirc_dev_fop_close(struct inode *inode, struct file *file)
+{
+ struct irctl *ir = irctls[iminor(inode)];
+
+ dev_dbg(ir->d.dev, LOGHEAD "close called\n", ir->d.name, ir->d.minor);
+
+ WARN_ON(mutex_lock_killable(&lirc_dev_lock));
+
+ --ir->open;
+ if (ir->attached) {
+ ir->d.set_use_dec(ir->d.data);
+ module_put(ir->d.owner);
+ } else {
+ cleanup(ir);
+ irctls[ir->d.minor] = NULL;
+ kfree(ir);
+ }
+
+ mutex_unlock(&lirc_dev_lock);
+
+ return 0;
+}
+EXPORT_SYMBOL(lirc_dev_fop_close);
+
+unsigned int lirc_dev_fop_poll(struct file *file, poll_table *wait)
+{
+ struct irctl *ir = irctls[iminor(file->f_dentry->d_inode)];
+ unsigned int ret;
+
+ dev_dbg(ir->d.dev, LOGHEAD "poll called\n", ir->d.name, ir->d.minor);
+
+ if (!ir->attached) {
+ mutex_unlock(&ir->irctl_lock);
+ return POLLERR;
+ }
+
+ poll_wait(file, &ir->buf->wait_poll, wait);
+
+ if (ir->buf)
+ if (lirc_buffer_empty(ir->buf))
+ ret = 0;
+ else
+ ret = POLLIN | POLLRDNORM;
+ else
+ ret = POLLERR;
+
+ dev_dbg(ir->d.dev, LOGHEAD "poll result = %d\n",
+ ir->d.name, ir->d.minor, ret);
+
+ return ret;
+}
+EXPORT_SYMBOL(lirc_dev_fop_poll);
+
+long lirc_dev_fop_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+ unsigned long mode;
+ int result = 0;
+ struct irctl *ir = file->private_data;
+
+ dev_dbg(ir->d.dev, LOGHEAD "ioctl called (0x%x)\n",
+ ir->d.name, ir->d.minor, cmd);
+
+ if (ir->d.minor == NOPLUG || !ir->attached) {
+ dev_dbg(ir->d.dev, LOGHEAD "ioctl result = -ENODEV\n",
+ ir->d.name, ir->d.minor);
+ return -ENODEV;
+ }
+
+ mutex_lock(&ir->irctl_lock);
+
+ switch (cmd) {
+ case LIRC_GET_FEATURES:
+ result = put_user(ir->d.features, (unsigned long *)arg);
+ break;
+ case LIRC_GET_REC_MODE:
+ if (!(ir->d.features & LIRC_CAN_REC_MASK)) {
+ result = -ENOSYS;
+ break;
+ }
+
+ result = put_user(LIRC_REC2MODE
+ (ir->d.features & LIRC_CAN_REC_MASK),
+ (unsigned long *)arg);
+ break;
+ case LIRC_SET_REC_MODE:
+ if (!(ir->d.features & LIRC_CAN_REC_MASK)) {
+ result = -ENOSYS;
+ break;
+ }
+
+ result = get_user(mode, (unsigned long *)arg);
+ if (!result && !(LIRC_MODE2REC(mode) & ir->d.features))
+ result = -EINVAL;
+ /*
+ * FIXME: We should actually set the mode somehow but
+ * for now, lirc_serial doesn't support mode changing either
+ */
+ break;
+ case LIRC_GET_LENGTH:
+ result = put_user(ir->d.code_length, (unsigned long *)arg);
+ break;
+ case LIRC_GET_MIN_TIMEOUT:
+ if (!(ir->d.features & LIRC_CAN_SET_REC_TIMEOUT) ||
+ ir->d.min_timeout == 0) {
+ result = -ENOSYS;
+ break;
+ }
+
+ result = put_user(ir->d.min_timeout, (unsigned long *)arg);
+ break;
+ case LIRC_GET_MAX_TIMEOUT:
+ if (!(ir->d.features & LIRC_CAN_SET_REC_TIMEOUT) ||
+ ir->d.max_timeout == 0) {
+ result = -ENOSYS;
+ break;
+ }
+
+ result = put_user(ir->d.max_timeout, (unsigned long *)arg);
+ break;
+ default:
+ result = -EINVAL;
+ }
+
+ dev_dbg(ir->d.dev, LOGHEAD "ioctl result = %d\n",
+ ir->d.name, ir->d.minor, result);
+
+ mutex_unlock(&ir->irctl_lock);
+
+ return result;
+}
+EXPORT_SYMBOL(lirc_dev_fop_ioctl);
+
+ssize_t lirc_dev_fop_read(struct file *file,
+ char *buffer,
+ size_t length,
+ loff_t *ppos)
+{
+ struct irctl *ir = irctls[iminor(file->f_dentry->d_inode)];
+ unsigned char buf[ir->chunk_size];
+ int ret = 0, written = 0;
+ DECLARE_WAITQUEUE(wait, current);
+
+ dev_dbg(ir->d.dev, LOGHEAD "read called\n", ir->d.name, ir->d.minor);
+
+ if (mutex_lock_interruptible(&ir->irctl_lock))
+ return -ERESTARTSYS;
+ if (!ir->attached) {
+ mutex_unlock(&ir->irctl_lock);
+ return -ENODEV;
+ }
+
+ if (length % ir->chunk_size) {
+ dev_dbg(ir->d.dev, LOGHEAD "read result = -EINVAL\n",
+ ir->d.name, ir->d.minor);
+ mutex_unlock(&ir->irctl_lock);
+ return -EINVAL;
+ }
+
+ /*
+ * we add ourselves to the task queue before buffer check
+ * to avoid losing scan code (in case when queue is awaken somewhere
+ * between while condition checking and scheduling)
+ */
+ add_wait_queue(&ir->buf->wait_poll, &wait);
+ set_current_state(TASK_INTERRUPTIBLE);
+
+ /*
+ * while we didn't provide 'length' bytes, device is opened in blocking
+ * mode and 'copy_to_user' is happy, wait for data.
+ */
+ while (written < length && ret == 0) {
+ if (lirc_buffer_empty(ir->buf)) {
+ /* According to the read(2) man page, 'written' can be
+ * returned as less than 'length', instead of blocking
+ * again, returning -EWOULDBLOCK, or returning
+ * -ERESTARTSYS */
+ if (written)
+ break;
+ if (file->f_flags & O_NONBLOCK) {
+ ret = -EWOULDBLOCK;
+ break;
+ }
+ if (signal_pending(current)) {
+ ret = -ERESTARTSYS;
+ break;
+ }
+
+ mutex_unlock(&ir->irctl_lock);
+ schedule();
+ set_current_state(TASK_INTERRUPTIBLE);
+
+ if (mutex_lock_interruptible(&ir->irctl_lock)) {
+ ret = -ERESTARTSYS;
+ remove_wait_queue(&ir->buf->wait_poll, &wait);
+ set_current_state(TASK_RUNNING);
+ goto out_unlocked;
+ }
+
+ if (!ir->attached) {
+ ret = -ENODEV;
+ break;
+ }
+ } else {
+ lirc_buffer_read(ir->buf, buf);
+ ret = copy_to_user((void *)buffer+written, buf,
+ ir->buf->chunk_size);
+ written += ir->buf->chunk_size;
+ }
+ }
+
+ remove_wait_queue(&ir->buf->wait_poll, &wait);
+ set_current_state(TASK_RUNNING);
+ mutex_unlock(&ir->irctl_lock);
+
+out_unlocked:
+ dev_dbg(ir->d.dev, LOGHEAD "read result = %s (%d)\n",
+ ir->d.name, ir->d.minor, ret ? "-EFAULT" : "OK", ret);
+
+ return ret ? ret : written;
+}
+EXPORT_SYMBOL(lirc_dev_fop_read);
+
+void *lirc_get_pdata(struct file *file)
+{
+ void *data = NULL;
+
+ if (file && file->f_dentry && file->f_dentry->d_inode &&
+ file->f_dentry->d_inode->i_rdev) {
+ struct irctl *ir;
+ ir = irctls[iminor(file->f_dentry->d_inode)];
+ data = ir->d.data;
+ }
+
+ return data;
+}
+EXPORT_SYMBOL(lirc_get_pdata);
+
+
+ssize_t lirc_dev_fop_write(struct file *file, const char *buffer,
+ size_t length, loff_t *ppos)
+{
+ struct irctl *ir = irctls[iminor(file->f_dentry->d_inode)];
+
+ dev_dbg(ir->d.dev, LOGHEAD "write called\n", ir->d.name, ir->d.minor);
+
+ if (!ir->attached)
+ return -ENODEV;
+
+ return -EINVAL;
+}
+EXPORT_SYMBOL(lirc_dev_fop_write);
+
+
+static int __init lirc_dev_init(void)
+{
+ int retval;
+
+ lirc_class = class_create(THIS_MODULE, "lirc");
+ if (IS_ERR(lirc_class)) {
+ retval = PTR_ERR(lirc_class);
+ printk(KERN_ERR "lirc_dev: class_create failed\n");
+ goto error;
+ }
+
+ retval = alloc_chrdev_region(&lirc_base_dev, 0, MAX_IRCTL_DEVICES,
+ IRCTL_DEV_NAME);
+ if (retval) {
+ class_destroy(lirc_class);
+ printk(KERN_ERR "lirc_dev: alloc_chrdev_region failed\n");
+ goto error;
+ }
+
+
+ printk(KERN_INFO "lirc_dev: IR Remote Control driver registered, "
+ "major %d \n", MAJOR(lirc_base_dev));
+
+error:
+ return retval;
+}
+
+
+
+static void __exit lirc_dev_exit(void)
+{
+ class_destroy(lirc_class);
+ unregister_chrdev_region(lirc_base_dev, MAX_IRCTL_DEVICES);
+ printk(KERN_INFO "lirc_dev: module unloaded\n");
+}
+
+module_init(lirc_dev_init);
+module_exit(lirc_dev_exit);
+
+MODULE_DESCRIPTION("LIRC base driver module");
+MODULE_AUTHOR("Artur Lipowski");
+MODULE_LICENSE("GPL");
+
+module_param(debug, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug, "Enable debugging messages");
diff --git a/drivers/media/IR/mceusb.c b/drivers/media/IR/mceusb.c
new file mode 100644
index 00000000000..78bf7f77a1a
--- /dev/null
+++ b/drivers/media/IR/mceusb.c
@@ -0,0 +1,1143 @@
+/*
+ * Driver for USB Windows Media Center Ed. eHome Infrared Transceivers
+ *
+ * Copyright (c) 2010 by Jarod Wilson <jarod@redhat.com>
+ *
+ * Based on the original lirc_mceusb and lirc_mceusb2 drivers, by Dan
+ * Conti, Martin Blatter and Daniel Melander, the latter of which was
+ * in turn also based on the lirc_atiusb driver by Paul Miller. The
+ * two mce drivers were merged into one by Jarod Wilson, with transmit
+ * support for the 1st-gen device added primarily by Patrick Calhoun,
+ * with a bit of tweaks by Jarod. Debugging improvements and proper
+ * support for what appears to be 3rd-gen hardware added by Jarod.
+ * Initial port from lirc driver to ir-core drivery by Jarod, based
+ * partially on a port to an earlier proposed IR infrastructure by
+ * Jon Smirl, which included enhancements and simplifications to the
+ * incoming IR buffer parsing routines.
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * 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/device.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/usb.h>
+#include <linux/input.h>
+#include <media/ir-core.h>
+#include <media/ir-common.h>
+
+#define DRIVER_VERSION "1.91"
+#define DRIVER_AUTHOR "Jarod Wilson <jarod@wilsonet.com>"
+#define DRIVER_DESC "Windows Media Center Ed. eHome Infrared Transceiver " \
+ "device driver"
+#define DRIVER_NAME "mceusb"
+
+#define USB_BUFLEN 32 /* USB reception buffer length */
+#define USB_CTRL_MSG_SZ 2 /* Size of usb ctrl msg on gen1 hw */
+#define MCE_G1_INIT_MSGS 40 /* Init messages on gen1 hw to throw out */
+
+/* MCE constants */
+#define MCE_CMDBUF_SIZE 384 /* MCE Command buffer length */
+#define MCE_TIME_UNIT 50 /* Approx 50us resolution */
+#define MCE_CODE_LENGTH 5 /* Normal length of packet (with header) */
+#define MCE_PACKET_SIZE 4 /* Normal length of packet (without header) */
+#define MCE_PACKET_HEADER 0x84 /* Actual header format is 0x80 + num_bytes */
+#define MCE_CONTROL_HEADER 0x9F /* MCE status header */
+#define MCE_TX_HEADER_LENGTH 3 /* # of bytes in the initializing tx header */
+#define MCE_MAX_CHANNELS 2 /* Two transmitters, hardware dependent? */
+#define MCE_DEFAULT_TX_MASK 0x03 /* Val opts: TX1=0x01, TX2=0x02, ALL=0x03 */
+#define MCE_PULSE_BIT 0x80 /* Pulse bit, MSB set == PULSE else SPACE */
+#define MCE_PULSE_MASK 0x7F /* Pulse mask */
+#define MCE_MAX_PULSE_LENGTH 0x7F /* Longest transmittable pulse symbol */
+#define MCE_PACKET_LENGTH_MASK 0x1F /* Packet length mask */
+
+
+/* module parameters */
+#ifdef CONFIG_USB_DEBUG
+static int debug = 1;
+#else
+static int debug;
+#endif
+
+/* general constants */
+#define SEND_FLAG_IN_PROGRESS 1
+#define SEND_FLAG_COMPLETE 2
+#define RECV_FLAG_IN_PROGRESS 3
+#define RECV_FLAG_COMPLETE 4
+
+#define MCEUSB_RX 1
+#define MCEUSB_TX 2
+
+#define VENDOR_PHILIPS 0x0471
+#define VENDOR_SMK 0x0609
+#define VENDOR_TATUNG 0x1460
+#define VENDOR_GATEWAY 0x107b
+#define VENDOR_SHUTTLE 0x1308
+#define VENDOR_SHUTTLE2 0x051c
+#define VENDOR_MITSUMI 0x03ee
+#define VENDOR_TOPSEED 0x1784
+#define VENDOR_RICAVISION 0x179d
+#define VENDOR_ITRON 0x195d
+#define VENDOR_FIC 0x1509
+#define VENDOR_LG 0x043e
+#define VENDOR_MICROSOFT 0x045e
+#define VENDOR_FORMOSA 0x147a
+#define VENDOR_FINTEK 0x1934
+#define VENDOR_PINNACLE 0x2304
+#define VENDOR_ECS 0x1019
+#define VENDOR_WISTRON 0x0fb8
+#define VENDOR_COMPRO 0x185b
+#define VENDOR_NORTHSTAR 0x04eb
+#define VENDOR_REALTEK 0x0bda
+#define VENDOR_TIVO 0x105a
+
+static struct usb_device_id mceusb_dev_table[] = {
+ /* Original Microsoft MCE IR Transceiver (often HP-branded) */
+ { USB_DEVICE(VENDOR_MICROSOFT, 0x006d) },
+ /* Philips Infrared Transceiver - Sahara branded */
+ { USB_DEVICE(VENDOR_PHILIPS, 0x0608) },
+ /* Philips Infrared Transceiver - HP branded */
+ { USB_DEVICE(VENDOR_PHILIPS, 0x060c) },
+ /* Philips SRM5100 */
+ { USB_DEVICE(VENDOR_PHILIPS, 0x060d) },
+ /* Philips Infrared Transceiver - Omaura */
+ { USB_DEVICE(VENDOR_PHILIPS, 0x060f) },
+ /* Philips Infrared Transceiver - Spinel plus */
+ { USB_DEVICE(VENDOR_PHILIPS, 0x0613) },
+ /* Philips eHome Infrared Transceiver */
+ { USB_DEVICE(VENDOR_PHILIPS, 0x0815) },
+ /* Realtek MCE IR Receiver */
+ { USB_DEVICE(VENDOR_REALTEK, 0x0161) },
+ /* SMK/Toshiba G83C0004D410 */
+ { USB_DEVICE(VENDOR_SMK, 0x031d) },
+ /* SMK eHome Infrared Transceiver (Sony VAIO) */
+ { USB_DEVICE(VENDOR_SMK, 0x0322) },
+ /* bundled with Hauppauge PVR-150 */
+ { USB_DEVICE(VENDOR_SMK, 0x0334) },
+ /* SMK eHome Infrared Transceiver */
+ { USB_DEVICE(VENDOR_SMK, 0x0338) },
+ /* Tatung eHome Infrared Transceiver */
+ { USB_DEVICE(VENDOR_TATUNG, 0x9150) },
+ /* Shuttle eHome Infrared Transceiver */
+ { USB_DEVICE(VENDOR_SHUTTLE, 0xc001) },
+ /* Shuttle eHome Infrared Transceiver */
+ { USB_DEVICE(VENDOR_SHUTTLE2, 0xc001) },
+ /* Gateway eHome Infrared Transceiver */
+ { USB_DEVICE(VENDOR_GATEWAY, 0x3009) },
+ /* Mitsumi */
+ { USB_DEVICE(VENDOR_MITSUMI, 0x2501) },
+ /* Topseed eHome Infrared Transceiver */
+ { USB_DEVICE(VENDOR_TOPSEED, 0x0001) },
+ /* Topseed HP eHome Infrared Transceiver */
+ { USB_DEVICE(VENDOR_TOPSEED, 0x0006) },
+ /* Topseed eHome Infrared Transceiver */
+ { USB_DEVICE(VENDOR_TOPSEED, 0x0007) },
+ /* Topseed eHome Infrared Transceiver */
+ { USB_DEVICE(VENDOR_TOPSEED, 0x0008) },
+ /* Topseed eHome Infrared Transceiver */
+ { USB_DEVICE(VENDOR_TOPSEED, 0x000a) },
+ /* Topseed eHome Infrared Transceiver */
+ { USB_DEVICE(VENDOR_TOPSEED, 0x0011) },
+ /* Ricavision internal Infrared Transceiver */
+ { USB_DEVICE(VENDOR_RICAVISION, 0x0010) },
+ /* Itron ione Libra Q-11 */
+ { USB_DEVICE(VENDOR_ITRON, 0x7002) },
+ /* FIC eHome Infrared Transceiver */
+ { USB_DEVICE(VENDOR_FIC, 0x9242) },
+ /* LG eHome Infrared Transceiver */
+ { USB_DEVICE(VENDOR_LG, 0x9803) },
+ /* Microsoft MCE Infrared Transceiver */
+ { USB_DEVICE(VENDOR_MICROSOFT, 0x00a0) },
+ /* Formosa eHome Infrared Transceiver */
+ { USB_DEVICE(VENDOR_FORMOSA, 0xe015) },
+ /* Formosa21 / eHome Infrared Receiver */
+ { USB_DEVICE(VENDOR_FORMOSA, 0xe016) },
+ /* Formosa aim / Trust MCE Infrared Receiver */
+ { USB_DEVICE(VENDOR_FORMOSA, 0xe017) },
+ /* Formosa Industrial Computing / Beanbag Emulation Device */
+ { USB_DEVICE(VENDOR_FORMOSA, 0xe018) },
+ /* Formosa21 / eHome Infrared Receiver */
+ { USB_DEVICE(VENDOR_FORMOSA, 0xe03a) },
+ /* Formosa Industrial Computing AIM IR605/A */
+ { USB_DEVICE(VENDOR_FORMOSA, 0xe03c) },
+ /* Formosa Industrial Computing */
+ { USB_DEVICE(VENDOR_FORMOSA, 0xe03e) },
+ /* Fintek eHome Infrared Transceiver */
+ { USB_DEVICE(VENDOR_FINTEK, 0x0602) },
+ /* Fintek eHome Infrared Transceiver (in the AOpen MP45) */
+ { USB_DEVICE(VENDOR_FINTEK, 0x0702) },
+ /* Pinnacle Remote Kit */
+ { USB_DEVICE(VENDOR_PINNACLE, 0x0225) },
+ /* Elitegroup Computer Systems IR */
+ { USB_DEVICE(VENDOR_ECS, 0x0f38) },
+ /* Wistron Corp. eHome Infrared Receiver */
+ { USB_DEVICE(VENDOR_WISTRON, 0x0002) },
+ /* Compro K100 */
+ { USB_DEVICE(VENDOR_COMPRO, 0x3020) },
+ /* Compro K100 v2 */
+ { USB_DEVICE(VENDOR_COMPRO, 0x3082) },
+ /* Northstar Systems, Inc. eHome Infrared Transceiver */
+ { USB_DEVICE(VENDOR_NORTHSTAR, 0xe004) },
+ /* TiVo PC IR Receiver */
+ { USB_DEVICE(VENDOR_TIVO, 0x2000) },
+ /* Terminating entry */
+ { }
+};
+
+static struct usb_device_id gen3_list[] = {
+ { USB_DEVICE(VENDOR_PINNACLE, 0x0225) },
+ { USB_DEVICE(VENDOR_TOPSEED, 0x0008) },
+ {}
+};
+
+static struct usb_device_id microsoft_gen1_list[] = {
+ { USB_DEVICE(VENDOR_MICROSOFT, 0x006d) },
+ {}
+};
+
+static struct usb_device_id std_tx_mask_list[] = {
+ { USB_DEVICE(VENDOR_MICROSOFT, 0x006d) },
+ { USB_DEVICE(VENDOR_PHILIPS, 0x060c) },
+ { USB_DEVICE(VENDOR_SMK, 0x031d) },
+ { USB_DEVICE(VENDOR_SMK, 0x0322) },
+ { USB_DEVICE(VENDOR_SMK, 0x0334) },
+ { USB_DEVICE(VENDOR_TOPSEED, 0x0001) },
+ { USB_DEVICE(VENDOR_TOPSEED, 0x0006) },
+ { USB_DEVICE(VENDOR_TOPSEED, 0x0007) },
+ { USB_DEVICE(VENDOR_TOPSEED, 0x0008) },
+ { USB_DEVICE(VENDOR_TOPSEED, 0x000a) },
+ { USB_DEVICE(VENDOR_TOPSEED, 0x0011) },
+ { USB_DEVICE(VENDOR_PINNACLE, 0x0225) },
+ {}
+};
+
+/* data structure for each usb transceiver */
+struct mceusb_dev {
+ /* ir-core bits */
+ struct ir_input_dev *irdev;
+ struct ir_dev_props *props;
+ struct ir_raw_event rawir;
+
+ /* core device bits */
+ struct device *dev;
+ struct input_dev *idev;
+
+ /* usb */
+ struct usb_device *usbdev;
+ struct urb *urb_in;
+ struct usb_endpoint_descriptor *usb_ep_in;
+ struct usb_endpoint_descriptor *usb_ep_out;
+
+ /* buffers and dma */
+ unsigned char *buf_in;
+ unsigned int len_in;
+ u8 cmd; /* MCE command type */
+ u8 rem; /* Remaining IR data bytes in packet */
+ dma_addr_t dma_in;
+ dma_addr_t dma_out;
+
+ struct {
+ u32 connected:1;
+ u32 tx_mask_inverted:1;
+ u32 microsoft_gen1:1;
+ u32 reserved:29;
+ } flags;
+
+ /* transmit support */
+ int send_flags;
+ u32 carrier;
+ unsigned char tx_mask;
+
+ char name[128];
+ char phys[64];
+};
+
+/*
+ * MCE Device Command Strings
+ * Device command responses vary from device to device...
+ * - DEVICE_RESET resets the hardware to its default state
+ * - GET_REVISION fetches the hardware/software revision, common
+ * replies are ff 0b 45 ff 1b 08 and ff 0b 50 ff 1b 42
+ * - GET_CARRIER_FREQ gets the carrier mode and frequency of the
+ * device, with replies in the form of 9f 06 MM FF, where MM is 0-3,
+ * meaning clk of 10000000, 2500000, 625000 or 156250, and FF is
+ * ((clk / frequency) - 1)
+ * - GET_RX_TIMEOUT fetches the receiver timeout in units of 50us,
+ * response in the form of 9f 0c msb lsb
+ * - GET_TX_BITMASK fetches the transmitter bitmask, replies in
+ * the form of 9f 08 bm, where bm is the bitmask
+ * - GET_RX_SENSOR fetches the RX sensor setting -- long-range
+ * general use one or short-range learning one, in the form of
+ * 9f 14 ss, where ss is either 01 for long-range or 02 for short
+ * - SET_CARRIER_FREQ sets a new carrier mode and frequency
+ * - SET_TX_BITMASK sets the transmitter bitmask
+ * - SET_RX_TIMEOUT sets the receiver timeout
+ * - SET_RX_SENSOR sets which receiver sensor to use
+ */
+static char DEVICE_RESET[] = {0x00, 0xff, 0xaa};
+static char GET_REVISION[] = {0xff, 0x0b};
+static char GET_UNKNOWN[] = {0xff, 0x18};
+static char GET_UNKNOWN2[] = {0x9f, 0x05};
+static char GET_CARRIER_FREQ[] = {0x9f, 0x07};
+static char GET_RX_TIMEOUT[] = {0x9f, 0x0d};
+static char GET_TX_BITMASK[] = {0x9f, 0x13};
+static char GET_RX_SENSOR[] = {0x9f, 0x15};
+/* sub in desired values in lower byte or bytes for full command */
+/* FIXME: make use of these for transmit.
+static char SET_CARRIER_FREQ[] = {0x9f, 0x06, 0x00, 0x00};
+static char SET_TX_BITMASK[] = {0x9f, 0x08, 0x00};
+static char SET_RX_TIMEOUT[] = {0x9f, 0x0c, 0x00, 0x00};
+static char SET_RX_SENSOR[] = {0x9f, 0x14, 0x00};
+*/
+
+static void mceusb_dev_printdata(struct mceusb_dev *ir, char *buf,
+ int len, bool out)
+{
+ char codes[USB_BUFLEN * 3 + 1];
+ char inout[9];
+ int i;
+ u8 cmd, subcmd, data1, data2;
+ struct device *dev = ir->dev;
+ int idx = 0;
+
+ /* skip meaningless 0xb1 0x60 header bytes on orig receiver */
+ if (ir->flags.microsoft_gen1 && !out)
+ idx = 2;
+
+ if (len <= idx)
+ return;
+
+ for (i = 0; i < len && i < USB_BUFLEN; i++)
+ snprintf(codes + i * 3, 4, "%02x ", buf[i] & 0xFF);
+
+ dev_info(dev, "%sx data: %s (length=%d)\n",
+ (out ? "t" : "r"), codes, len);
+
+ if (out)
+ strcpy(inout, "Request\0");
+ else
+ strcpy(inout, "Got\0");
+
+ cmd = buf[idx] & 0xff;
+ subcmd = buf[idx + 1] & 0xff;
+ data1 = buf[idx + 2] & 0xff;
+ data2 = buf[idx + 3] & 0xff;
+
+ switch (cmd) {
+ case 0x00:
+ if (subcmd == 0xff && data1 == 0xaa)
+ dev_info(dev, "Device reset requested\n");
+ else
+ dev_info(dev, "Unknown command 0x%02x 0x%02x\n",
+ cmd, subcmd);
+ break;
+ case 0xff:
+ switch (subcmd) {
+ case 0x0b:
+ if (len == 2)
+ dev_info(dev, "Get hw/sw rev?\n");
+ else
+ dev_info(dev, "hw/sw rev 0x%02x 0x%02x "
+ "0x%02x 0x%02x\n", data1, data2,
+ buf[idx + 4], buf[idx + 5]);
+ break;
+ case 0xaa:
+ dev_info(dev, "Device reset requested\n");
+ break;
+ case 0xfe:
+ dev_info(dev, "Previous command not supported\n");
+ break;
+ case 0x18:
+ case 0x1b:
+ default:
+ dev_info(dev, "Unknown command 0x%02x 0x%02x\n",
+ cmd, subcmd);
+ break;
+ }
+ break;
+ case 0x9f:
+ switch (subcmd) {
+ case 0x03:
+ dev_info(dev, "Ping\n");
+ break;
+ case 0x04:
+ dev_info(dev, "Resp to 9f 05 of 0x%02x 0x%02x\n",
+ data1, data2);
+ break;
+ case 0x06:
+ dev_info(dev, "%s carrier mode and freq of "
+ "0x%02x 0x%02x\n", inout, data1, data2);
+ break;
+ case 0x07:
+ dev_info(dev, "Get carrier mode and freq\n");
+ break;
+ case 0x08:
+ dev_info(dev, "%s transmit blaster mask of 0x%02x\n",
+ inout, data1);
+ break;
+ case 0x0c:
+ /* value is in units of 50us, so x*50/100 or x/2 ms */
+ dev_info(dev, "%s receive timeout of %d ms\n",
+ inout, ((data1 << 8) | data2) / 2);
+ break;
+ case 0x0d:
+ dev_info(dev, "Get receive timeout\n");
+ break;
+ case 0x13:
+ dev_info(dev, "Get transmit blaster mask\n");
+ break;
+ case 0x14:
+ dev_info(dev, "%s %s-range receive sensor in use\n",
+ inout, data1 == 0x02 ? "short" : "long");
+ break;
+ case 0x15:
+ if (len == 2)
+ dev_info(dev, "Get receive sensor\n");
+ else
+ dev_info(dev, "Received pulse count is %d\n",
+ ((data1 << 8) | data2));
+ break;
+ case 0xfe:
+ dev_info(dev, "Error! Hardware is likely wedged...\n");
+ break;
+ case 0x05:
+ case 0x09:
+ case 0x0f:
+ default:
+ dev_info(dev, "Unknown command 0x%02x 0x%02x\n",
+ cmd, subcmd);
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+static void usb_async_callback(struct urb *urb, struct pt_regs *regs)
+{
+ struct mceusb_dev *ir;
+ int len;
+
+ if (!urb)
+ return;
+
+ ir = urb->context;
+ if (ir) {
+ len = urb->actual_length;
+
+ dev_dbg(ir->dev, "callback called (status=%d len=%d)\n",
+ urb->status, len);
+
+ if (debug)
+ mceusb_dev_printdata(ir, urb->transfer_buffer,
+ len, true);
+ }
+
+}
+
+/* request incoming or send outgoing usb packet - used to initialize remote */
+static void mce_request_packet(struct mceusb_dev *ir,
+ struct usb_endpoint_descriptor *ep,
+ unsigned char *data, int size, int urb_type)
+{
+ int res;
+ struct urb *async_urb;
+ struct device *dev = ir->dev;
+ unsigned char *async_buf;
+
+ if (urb_type == MCEUSB_TX) {
+ async_urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (unlikely(!async_urb)) {
+ dev_err(dev, "Error, couldn't allocate urb!\n");
+ return;
+ }
+
+ async_buf = kzalloc(size, GFP_KERNEL);
+ if (!async_buf) {
+ dev_err(dev, "Error, couldn't allocate buf!\n");
+ usb_free_urb(async_urb);
+ return;
+ }
+
+ /* outbound data */
+ usb_fill_int_urb(async_urb, ir->usbdev,
+ usb_sndintpipe(ir->usbdev, ep->bEndpointAddress),
+ async_buf, size, (usb_complete_t) usb_async_callback,
+ ir, ep->bInterval);
+ memcpy(async_buf, data, size);
+
+ } else if (urb_type == MCEUSB_RX) {
+ /* standard request */
+ async_urb = ir->urb_in;
+ ir->send_flags = RECV_FLAG_IN_PROGRESS;
+
+ } else {
+ dev_err(dev, "Error! Unknown urb type %d\n", urb_type);
+ return;
+ }
+
+ dev_dbg(dev, "receive request called (size=%#x)\n", size);
+
+ async_urb->transfer_buffer_length = size;
+ async_urb->dev = ir->usbdev;
+
+ res = usb_submit_urb(async_urb, GFP_ATOMIC);
+ if (res) {
+ dev_dbg(dev, "receive request FAILED! (res=%d)\n", res);
+ return;
+ }
+ dev_dbg(dev, "receive request complete (res=%d)\n", res);
+}
+
+static void mce_async_out(struct mceusb_dev *ir, unsigned char *data, int size)
+{
+ mce_request_packet(ir, ir->usb_ep_out, data, size, MCEUSB_TX);
+}
+
+static void mce_sync_in(struct mceusb_dev *ir, unsigned char *data, int size)
+{
+ mce_request_packet(ir, ir->usb_ep_in, data, size, MCEUSB_RX);
+}
+
+/* Send data out the IR blaster port(s) */
+static int mceusb_tx_ir(void *priv, int *txbuf, u32 n)
+{
+ struct mceusb_dev *ir = priv;
+ int i, ret = 0;
+ int count, cmdcount = 0;
+ unsigned char *cmdbuf; /* MCE command buffer */
+ long signal_duration = 0; /* Singnal length in us */
+ struct timeval start_time, end_time;
+
+ do_gettimeofday(&start_time);
+
+ count = n / sizeof(int);
+
+ cmdbuf = kzalloc(sizeof(int) * MCE_CMDBUF_SIZE, GFP_KERNEL);
+ if (!cmdbuf)
+ return -ENOMEM;
+
+ /* MCE tx init header */
+ cmdbuf[cmdcount++] = MCE_CONTROL_HEADER;
+ cmdbuf[cmdcount++] = 0x08;
+ cmdbuf[cmdcount++] = ir->tx_mask;
+
+ /* Generate mce packet data */
+ for (i = 0; (i < count) && (cmdcount < MCE_CMDBUF_SIZE); i++) {
+ signal_duration += txbuf[i];
+ txbuf[i] = txbuf[i] / MCE_TIME_UNIT;
+
+ do { /* loop to support long pulses/spaces > 127*50us=6.35ms */
+
+ /* Insert mce packet header every 4th entry */
+ if ((cmdcount < MCE_CMDBUF_SIZE) &&
+ (cmdcount - MCE_TX_HEADER_LENGTH) %
+ MCE_CODE_LENGTH == 0)
+ cmdbuf[cmdcount++] = MCE_PACKET_HEADER;
+
+ /* Insert mce packet data */
+ if (cmdcount < MCE_CMDBUF_SIZE)
+ cmdbuf[cmdcount++] =
+ (txbuf[i] < MCE_PULSE_BIT ?
+ txbuf[i] : MCE_MAX_PULSE_LENGTH) |
+ (i & 1 ? 0x00 : MCE_PULSE_BIT);
+ else {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ } while ((txbuf[i] > MCE_MAX_PULSE_LENGTH) &&
+ (txbuf[i] -= MCE_MAX_PULSE_LENGTH));
+ }
+
+ /* Fix packet length in last header */
+ cmdbuf[cmdcount - (cmdcount - MCE_TX_HEADER_LENGTH) % MCE_CODE_LENGTH] =
+ 0x80 + (cmdcount - MCE_TX_HEADER_LENGTH) % MCE_CODE_LENGTH - 1;
+
+ /* Check if we have room for the empty packet at the end */
+ if (cmdcount >= MCE_CMDBUF_SIZE) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ /* All mce commands end with an empty packet (0x80) */
+ cmdbuf[cmdcount++] = 0x80;
+
+ /* Transmit the command to the mce device */
+ mce_async_out(ir, cmdbuf, cmdcount);
+
+ /*
+ * The lircd gap calculation expects the write function to
+ * wait the time it takes for the ircommand to be sent before
+ * it returns.
+ */
+ do_gettimeofday(&end_time);
+ signal_duration -= (end_time.tv_usec - start_time.tv_usec) +
+ (end_time.tv_sec - start_time.tv_sec) * 1000000;
+
+ /* delay with the closest number of ticks */
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule_timeout(usecs_to_jiffies(signal_duration));
+
+out:
+ kfree(cmdbuf);
+ return ret ? ret : n;
+}
+
+/* Sets active IR outputs -- mce devices typically (all?) have two */
+static int mceusb_set_tx_mask(void *priv, u32 mask)
+{
+ struct mceusb_dev *ir = priv;
+
+ if (ir->flags.tx_mask_inverted)
+ ir->tx_mask = (mask != 0x03 ? mask ^ 0x03 : mask) << 1;
+ else
+ ir->tx_mask = mask;
+
+ return 0;
+}
+
+/* Sets the send carrier frequency and mode */
+static int mceusb_set_tx_carrier(void *priv, u32 carrier)
+{
+ struct mceusb_dev *ir = priv;
+ int clk = 10000000;
+ int prescaler = 0, divisor = 0;
+ unsigned char cmdbuf[4] = { 0x9f, 0x06, 0x00, 0x00 };
+
+ /* Carrier has changed */
+ if (ir->carrier != carrier) {
+
+ if (carrier == 0) {
+ ir->carrier = carrier;
+ cmdbuf[2] = 0x01;
+ cmdbuf[3] = 0x80;
+ dev_dbg(ir->dev, "%s: disabling carrier "
+ "modulation\n", __func__);
+ mce_async_out(ir, cmdbuf, sizeof(cmdbuf));
+ return carrier;
+ }
+
+ for (prescaler = 0; prescaler < 4; ++prescaler) {
+ divisor = (clk >> (2 * prescaler)) / carrier;
+ if (divisor <= 0xFF) {
+ ir->carrier = carrier;
+ cmdbuf[2] = prescaler;
+ cmdbuf[3] = divisor;
+ dev_dbg(ir->dev, "%s: requesting %u HZ "
+ "carrier\n", __func__, carrier);
+
+ /* Transmit new carrier to mce device */
+ mce_async_out(ir, cmdbuf, sizeof(cmdbuf));
+ return carrier;
+ }
+ }
+
+ return -EINVAL;
+
+ }
+
+ return carrier;
+}
+
+static void mceusb_process_ir_data(struct mceusb_dev *ir, int buf_len)
+{
+ struct ir_raw_event rawir = { .pulse = false, .duration = 0 };
+ int i, start_index = 0;
+ u8 hdr = MCE_CONTROL_HEADER;
+
+ /* skip meaningless 0xb1 0x60 header bytes on orig receiver */
+ if (ir->flags.microsoft_gen1)
+ start_index = 2;
+
+ for (i = start_index; i < buf_len;) {
+ if (ir->rem == 0) {
+ /* decode mce packets of the form (84),AA,BB,CC,DD */
+ /* IR data packets can span USB messages - rem */
+ hdr = ir->buf_in[i];
+ ir->rem = (hdr & MCE_PACKET_LENGTH_MASK);
+ ir->cmd = (hdr & ~MCE_PACKET_LENGTH_MASK);
+ dev_dbg(ir->dev, "New data. rem: 0x%02x, cmd: 0x%02x\n",
+ ir->rem, ir->cmd);
+ i++;
+ }
+
+ /* don't process MCE commands */
+ if (hdr == MCE_CONTROL_HEADER || hdr == 0xff) {
+ ir->rem = 0;
+ return;
+ }
+
+ for (; (ir->rem > 0) && (i < buf_len); i++) {
+ ir->rem--;
+
+ rawir.pulse = ((ir->buf_in[i] & MCE_PULSE_BIT) != 0);
+ rawir.duration = (ir->buf_in[i] & MCE_PULSE_MASK)
+ * MCE_TIME_UNIT * 1000;
+
+ if ((ir->buf_in[i] & MCE_PULSE_MASK) == 0x7f) {
+ if (ir->rawir.pulse == rawir.pulse)
+ ir->rawir.duration += rawir.duration;
+ else {
+ ir->rawir.duration = rawir.duration;
+ ir->rawir.pulse = rawir.pulse;
+ }
+ continue;
+ }
+ rawir.duration += ir->rawir.duration;
+ ir->rawir.duration = 0;
+ ir->rawir.pulse = rawir.pulse;
+
+ dev_dbg(ir->dev, "Storing %s with duration %d\n",
+ rawir.pulse ? "pulse" : "space",
+ rawir.duration);
+
+ ir_raw_event_store(ir->idev, &rawir);
+ }
+
+ if (ir->buf_in[i] == 0x80 || ir->buf_in[i] == 0x9f)
+ ir->rem = 0;
+
+ dev_dbg(ir->dev, "calling ir_raw_event_handle\n");
+ ir_raw_event_handle(ir->idev);
+ }
+}
+
+static void mceusb_dev_recv(struct urb *urb, struct pt_regs *regs)
+{
+ struct mceusb_dev *ir;
+ int buf_len;
+
+ if (!urb)
+ return;
+
+ ir = urb->context;
+ if (!ir) {
+ usb_unlink_urb(urb);
+ return;
+ }
+
+ buf_len = urb->actual_length;
+
+ if (debug)
+ mceusb_dev_printdata(ir, urb->transfer_buffer, buf_len, false);
+
+ if (ir->send_flags == RECV_FLAG_IN_PROGRESS) {
+ ir->send_flags = SEND_FLAG_COMPLETE;
+ dev_dbg(&ir->irdev->dev, "setup answer received %d bytes\n",
+ buf_len);
+ }
+
+ switch (urb->status) {
+ /* success */
+ case 0:
+ mceusb_process_ir_data(ir, buf_len);
+ break;
+
+ case -ECONNRESET:
+ case -ENOENT:
+ case -ESHUTDOWN:
+ usb_unlink_urb(urb);
+ return;
+
+ case -EPIPE:
+ default:
+ break;
+ }
+
+ usb_submit_urb(urb, GFP_ATOMIC);
+}
+
+static void mceusb_gen1_init(struct mceusb_dev *ir)
+{
+ int ret;
+ int maxp = ir->len_in;
+ struct device *dev = ir->dev;
+ char *data;
+
+ data = kzalloc(USB_CTRL_MSG_SZ, GFP_KERNEL);
+ if (!data) {
+ dev_err(dev, "%s: memory allocation failed!\n", __func__);
+ return;
+ }
+
+ /*
+ * This is a strange one. Windows issues a set address to the device
+ * on the receive control pipe and expect a certain value pair back
+ */
+ ret = usb_control_msg(ir->usbdev, usb_rcvctrlpipe(ir->usbdev, 0),
+ USB_REQ_SET_ADDRESS, USB_TYPE_VENDOR, 0, 0,
+ data, USB_CTRL_MSG_SZ, HZ * 3);
+ dev_dbg(dev, "%s - ret = %d\n", __func__, ret);
+ dev_dbg(dev, "%s - data[0] = %d, data[1] = %d\n",
+ __func__, data[0], data[1]);
+
+ /* set feature: bit rate 38400 bps */
+ ret = usb_control_msg(ir->usbdev, usb_sndctrlpipe(ir->usbdev, 0),
+ USB_REQ_SET_FEATURE, USB_TYPE_VENDOR,
+ 0xc04e, 0x0000, NULL, 0, HZ * 3);
+
+ dev_dbg(dev, "%s - ret = %d\n", __func__, ret);
+
+ /* bRequest 4: set char length to 8 bits */
+ ret = usb_control_msg(ir->usbdev, usb_sndctrlpipe(ir->usbdev, 0),
+ 4, USB_TYPE_VENDOR,
+ 0x0808, 0x0000, NULL, 0, HZ * 3);
+ dev_dbg(dev, "%s - retB = %d\n", __func__, ret);
+
+ /* bRequest 2: set handshaking to use DTR/DSR */
+ ret = usb_control_msg(ir->usbdev, usb_sndctrlpipe(ir->usbdev, 0),
+ 2, USB_TYPE_VENDOR,
+ 0x0000, 0x0100, NULL, 0, HZ * 3);
+ dev_dbg(dev, "%s - retC = %d\n", __func__, ret);
+
+ /* device reset */
+ mce_async_out(ir, DEVICE_RESET, sizeof(DEVICE_RESET));
+ mce_sync_in(ir, NULL, maxp);
+
+ /* get hw/sw revision? */
+ mce_async_out(ir, GET_REVISION, sizeof(GET_REVISION));
+ mce_sync_in(ir, NULL, maxp);
+
+ kfree(data);
+};
+
+static void mceusb_gen2_init(struct mceusb_dev *ir)
+{
+ int maxp = ir->len_in;
+
+ /* device reset */
+ mce_async_out(ir, DEVICE_RESET, sizeof(DEVICE_RESET));
+ mce_sync_in(ir, NULL, maxp);
+
+ /* get hw/sw revision? */
+ mce_async_out(ir, GET_REVISION, sizeof(GET_REVISION));
+ mce_sync_in(ir, NULL, maxp);
+
+ /* unknown what the next two actually return... */
+ mce_async_out(ir, GET_UNKNOWN, sizeof(GET_UNKNOWN));
+ mce_sync_in(ir, NULL, maxp);
+ mce_async_out(ir, GET_UNKNOWN2, sizeof(GET_UNKNOWN2));
+ mce_sync_in(ir, NULL, maxp);
+}
+
+static void mceusb_get_parameters(struct mceusb_dev *ir)
+{
+ int maxp = ir->len_in;
+
+ /* get the carrier and frequency */
+ mce_async_out(ir, GET_CARRIER_FREQ, sizeof(GET_CARRIER_FREQ));
+ mce_sync_in(ir, NULL, maxp);
+
+ /* get the transmitter bitmask */
+ mce_async_out(ir, GET_TX_BITMASK, sizeof(GET_TX_BITMASK));
+ mce_sync_in(ir, NULL, maxp);
+
+ /* get receiver timeout value */
+ mce_async_out(ir, GET_RX_TIMEOUT, sizeof(GET_RX_TIMEOUT));
+ mce_sync_in(ir, NULL, maxp);
+
+ /* get receiver sensor setting */
+ mce_async_out(ir, GET_RX_SENSOR, sizeof(GET_RX_SENSOR));
+ mce_sync_in(ir, NULL, maxp);
+}
+
+static struct input_dev *mceusb_init_input_dev(struct mceusb_dev *ir)
+{
+ struct input_dev *idev;
+ struct ir_dev_props *props;
+ struct ir_input_dev *irdev;
+ struct device *dev = ir->dev;
+ int ret = -ENODEV;
+
+ idev = input_allocate_device();
+ if (!idev) {
+ dev_err(dev, "remote input dev allocation failed\n");
+ goto idev_alloc_failed;
+ }
+
+ ret = -ENOMEM;
+ props = kzalloc(sizeof(struct ir_dev_props), GFP_KERNEL);
+ if (!props) {
+ dev_err(dev, "remote ir dev props allocation failed\n");
+ goto props_alloc_failed;
+ }
+
+ irdev = kzalloc(sizeof(struct ir_input_dev), GFP_KERNEL);
+ if (!irdev) {
+ dev_err(dev, "remote ir input dev allocation failed\n");
+ goto ir_dev_alloc_failed;
+ }
+
+ snprintf(ir->name, sizeof(ir->name), "Media Center Ed. eHome "
+ "Infrared Remote Transceiver (%04x:%04x)",
+ le16_to_cpu(ir->usbdev->descriptor.idVendor),
+ le16_to_cpu(ir->usbdev->descriptor.idProduct));
+
+ idev->name = ir->name;
+ usb_make_path(ir->usbdev, ir->phys, sizeof(ir->phys));
+ strlcat(ir->phys, "/input0", sizeof(ir->phys));
+ idev->phys = ir->phys;
+
+ props->priv = ir;
+ props->driver_type = RC_DRIVER_IR_RAW;
+ props->allowed_protos = IR_TYPE_ALL;
+ props->s_tx_mask = mceusb_set_tx_mask;
+ props->s_tx_carrier = mceusb_set_tx_carrier;
+ props->tx_ir = mceusb_tx_ir;
+
+ ir->props = props;
+ ir->irdev = irdev;
+
+ input_set_drvdata(idev, irdev);
+
+ ret = ir_input_register(idev, RC_MAP_RC6_MCE, props, DRIVER_NAME);
+ if (ret < 0) {
+ dev_err(dev, "remote input device register failed\n");
+ goto irdev_failed;
+ }
+
+ return idev;
+
+irdev_failed:
+ kfree(irdev);
+ir_dev_alloc_failed:
+ kfree(props);
+props_alloc_failed:
+ input_free_device(idev);
+idev_alloc_failed:
+ return NULL;
+}
+
+static int __devinit mceusb_dev_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+{
+ struct usb_device *dev = interface_to_usbdev(intf);
+ struct usb_host_interface *idesc;
+ struct usb_endpoint_descriptor *ep = NULL;
+ struct usb_endpoint_descriptor *ep_in = NULL;
+ struct usb_endpoint_descriptor *ep_out = NULL;
+ struct usb_host_config *config;
+ struct mceusb_dev *ir = NULL;
+ int pipe, maxp, i;
+ char buf[63], name[128] = "";
+ bool is_gen3;
+ bool is_microsoft_gen1;
+ bool tx_mask_inverted;
+
+ dev_dbg(&intf->dev, ": %s called\n", __func__);
+
+ config = dev->actconfig;
+ idesc = intf->cur_altsetting;
+
+ is_gen3 = usb_match_id(intf, gen3_list) ? 1 : 0;
+ is_microsoft_gen1 = usb_match_id(intf, microsoft_gen1_list) ? 1 : 0;
+ tx_mask_inverted = usb_match_id(intf, std_tx_mask_list) ? 0 : 1;
+
+ /* step through the endpoints to find first bulk in and out endpoint */
+ for (i = 0; i < idesc->desc.bNumEndpoints; ++i) {
+ ep = &idesc->endpoint[i].desc;
+
+ if ((ep_in == NULL)
+ && ((ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK)
+ == USB_DIR_IN)
+ && (((ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
+ == USB_ENDPOINT_XFER_BULK)
+ || ((ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
+ == USB_ENDPOINT_XFER_INT))) {
+
+ ep_in = ep;
+ ep_in->bmAttributes = USB_ENDPOINT_XFER_INT;
+ ep_in->bInterval = 1;
+ dev_dbg(&intf->dev, ": acceptable inbound endpoint "
+ "found\n");
+ }
+
+ if ((ep_out == NULL)
+ && ((ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK)
+ == USB_DIR_OUT)
+ && (((ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
+ == USB_ENDPOINT_XFER_BULK)
+ || ((ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
+ == USB_ENDPOINT_XFER_INT))) {
+
+ ep_out = ep;
+ ep_out->bmAttributes = USB_ENDPOINT_XFER_INT;
+ ep_out->bInterval = 1;
+ dev_dbg(&intf->dev, ": acceptable outbound endpoint "
+ "found\n");
+ }
+ }
+ if (ep_in == NULL) {
+ dev_dbg(&intf->dev, ": inbound and/or endpoint not found\n");
+ return -ENODEV;
+ }
+
+ pipe = usb_rcvintpipe(dev, ep_in->bEndpointAddress);
+ maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe));
+
+ ir = kzalloc(sizeof(struct mceusb_dev), GFP_KERNEL);
+ if (!ir)
+ goto mem_alloc_fail;
+
+ ir->buf_in = usb_alloc_coherent(dev, maxp, GFP_ATOMIC, &ir->dma_in);
+ if (!ir->buf_in)
+ goto buf_in_alloc_fail;
+
+ ir->urb_in = usb_alloc_urb(0, GFP_KERNEL);
+ if (!ir->urb_in)
+ goto urb_in_alloc_fail;
+
+ ir->usbdev = dev;
+ ir->dev = &intf->dev;
+ ir->len_in = maxp;
+ ir->flags.microsoft_gen1 = is_microsoft_gen1;
+ ir->flags.tx_mask_inverted = tx_mask_inverted;
+
+ /* Saving usb interface data for use by the transmitter routine */
+ ir->usb_ep_in = ep_in;
+ ir->usb_ep_out = ep_out;
+
+ if (dev->descriptor.iManufacturer
+ && usb_string(dev, dev->descriptor.iManufacturer,
+ buf, sizeof(buf)) > 0)
+ strlcpy(name, buf, sizeof(name));
+ if (dev->descriptor.iProduct
+ && usb_string(dev, dev->descriptor.iProduct,
+ buf, sizeof(buf)) > 0)
+ snprintf(name + strlen(name), sizeof(name) - strlen(name),
+ " %s", buf);
+
+ ir->idev = mceusb_init_input_dev(ir);
+ if (!ir->idev)
+ goto input_dev_fail;
+
+ /* flush buffers on the device */
+ mce_sync_in(ir, NULL, maxp);
+ mce_sync_in(ir, NULL, maxp);
+
+ /* wire up inbound data handler */
+ usb_fill_int_urb(ir->urb_in, dev, pipe, ir->buf_in,
+ maxp, (usb_complete_t) mceusb_dev_recv, ir, ep_in->bInterval);
+ ir->urb_in->transfer_dma = ir->dma_in;
+ ir->urb_in->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+
+ /* initialize device */
+ if (ir->flags.microsoft_gen1)
+ mceusb_gen1_init(ir);
+ else if (!is_gen3)
+ mceusb_gen2_init(ir);
+
+ mceusb_get_parameters(ir);
+
+ mceusb_set_tx_mask(ir, MCE_DEFAULT_TX_MASK);
+
+ usb_set_intfdata(intf, ir);
+
+ dev_info(&intf->dev, "Registered %s on usb%d:%d\n", name,
+ dev->bus->busnum, dev->devnum);
+
+ return 0;
+
+ /* Error-handling path */
+input_dev_fail:
+ usb_free_urb(ir->urb_in);
+urb_in_alloc_fail:
+ usb_free_coherent(dev, maxp, ir->buf_in, ir->dma_in);
+buf_in_alloc_fail:
+ kfree(ir);
+mem_alloc_fail:
+ dev_err(&intf->dev, "%s: device setup failed!\n", __func__);
+
+ return -ENOMEM;
+}
+
+
+static void __devexit mceusb_dev_disconnect(struct usb_interface *intf)
+{
+ struct usb_device *dev = interface_to_usbdev(intf);
+ struct mceusb_dev *ir = usb_get_intfdata(intf);
+
+ usb_set_intfdata(intf, NULL);
+
+ if (!ir)
+ return;
+
+ ir->usbdev = NULL;
+ ir_input_unregister(ir->idev);
+ usb_kill_urb(ir->urb_in);
+ usb_free_urb(ir->urb_in);
+ usb_free_coherent(dev, ir->len_in, ir->buf_in, ir->dma_in);
+
+ kfree(ir);
+}
+
+static int mceusb_dev_suspend(struct usb_interface *intf, pm_message_t message)
+{
+ struct mceusb_dev *ir = usb_get_intfdata(intf);
+ dev_info(ir->dev, "suspend\n");
+ usb_kill_urb(ir->urb_in);
+ return 0;
+}
+
+static int mceusb_dev_resume(struct usb_interface *intf)
+{
+ struct mceusb_dev *ir = usb_get_intfdata(intf);
+ dev_info(ir->dev, "resume\n");
+ if (usb_submit_urb(ir->urb_in, GFP_ATOMIC))
+ return -EIO;
+ return 0;
+}
+
+static struct usb_driver mceusb_dev_driver = {
+ .name = DRIVER_NAME,
+ .probe = mceusb_dev_probe,
+ .disconnect = mceusb_dev_disconnect,
+ .suspend = mceusb_dev_suspend,
+ .resume = mceusb_dev_resume,
+ .reset_resume = mceusb_dev_resume,
+ .id_table = mceusb_dev_table
+};
+
+static int __init mceusb_dev_init(void)
+{
+ int ret;
+
+ ret = usb_register(&mceusb_dev_driver);
+ if (ret < 0)
+ printk(KERN_ERR DRIVER_NAME
+ ": usb register failed, result = %d\n", ret);
+
+ return ret;
+}
+
+static void __exit mceusb_dev_exit(void)
+{
+ usb_deregister(&mceusb_dev_driver);
+}
+
+module_init(mceusb_dev_init);
+module_exit(mceusb_dev_exit);
+
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(usb, mceusb_dev_table);
+
+module_param(debug, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug, "Debug enabled or not");
diff --git a/drivers/media/common/saa7146_fops.c b/drivers/media/common/saa7146_fops.c
index 7364b9642d0..4da2a54cb8b 100644
--- a/drivers/media/common/saa7146_fops.c
+++ b/drivers/media/common/saa7146_fops.c
@@ -57,7 +57,7 @@ void saa7146_dma_free(struct saa7146_dev *dev,struct videobuf_queue *q,
BUG_ON(in_interrupt());
videobuf_waiton(&buf->vb,0,0);
- videobuf_dma_unmap(q, dma);
+ videobuf_dma_unmap(q->dev, dma);
videobuf_dma_free(dma);
buf->vb.state = VIDEOBUF_NEEDS_INIT;
}
diff --git a/drivers/media/common/saa7146_vbi.c b/drivers/media/common/saa7146_vbi.c
index 74e2b56ecb5..8224c301d05 100644
--- a/drivers/media/common/saa7146_vbi.c
+++ b/drivers/media/common/saa7146_vbi.c
@@ -375,7 +375,7 @@ static void vbi_init(struct saa7146_dev *dev, struct saa7146_vv *vv)
static int vbi_open(struct saa7146_dev *dev, struct file *file)
{
- struct saa7146_fh *fh = (struct saa7146_fh *)file->private_data;
+ struct saa7146_fh *fh = file->private_data;
u32 arbtr_ctrl = saa7146_read(dev, PCI_BT_V1);
int ret = 0;
@@ -437,7 +437,7 @@ static int vbi_open(struct saa7146_dev *dev, struct file *file)
static void vbi_close(struct saa7146_dev *dev, struct file *file)
{
- struct saa7146_fh *fh = (struct saa7146_fh *)file->private_data;
+ struct saa7146_fh *fh = file->private_data;
struct saa7146_vv *vv = dev->vv_data;
DEB_VBI(("dev:%p, fh:%p\n",dev,fh));
diff --git a/drivers/media/common/saa7146_video.c b/drivers/media/common/saa7146_video.c
index b8b2c551a1e..a212a91a30f 100644
--- a/drivers/media/common/saa7146_video.c
+++ b/drivers/media/common/saa7146_video.c
@@ -1370,7 +1370,7 @@ static void video_init(struct saa7146_dev *dev, struct saa7146_vv *vv)
static int video_open(struct saa7146_dev *dev, struct file *file)
{
- struct saa7146_fh *fh = (struct saa7146_fh *)file->private_data;
+ struct saa7146_fh *fh = file->private_data;
struct saa7146_format *sfmt;
fh->video_fmt.width = 384;
@@ -1394,7 +1394,7 @@ static int video_open(struct saa7146_dev *dev, struct file *file)
static void video_close(struct saa7146_dev *dev, struct file *file)
{
- struct saa7146_fh *fh = (struct saa7146_fh *)file->private_data;
+ struct saa7146_fh *fh = file->private_data;
struct saa7146_vv *vv = dev->vv_data;
struct videobuf_queue *q = &fh->video_q;
int err;
diff --git a/drivers/media/common/tuners/tda18271-fe.c b/drivers/media/common/tuners/tda18271-fe.c
index b2e15456d5f..7955e49a344 100644
--- a/drivers/media/common/tuners/tda18271-fe.c
+++ b/drivers/media/common/tuners/tda18271-fe.c
@@ -1249,7 +1249,7 @@ struct dvb_frontend *tda18271_attach(struct dvb_frontend *fe, u8 addr,
struct tda18271_config *cfg)
{
struct tda18271_priv *priv = NULL;
- int instance;
+ int instance, ret;
mutex_lock(&tda18271_list_mutex);
@@ -1268,10 +1268,12 @@ struct dvb_frontend *tda18271_attach(struct dvb_frontend *fe, u8 addr,
priv->cal_initialized = false;
mutex_init(&priv->lock);
- if (tda_fail(tda18271_get_id(fe)))
+ ret = tda18271_get_id(fe);
+ if (tda_fail(ret))
goto fail;
- if (tda_fail(tda18271_assign_map_layout(fe)))
+ ret = tda18271_assign_map_layout(fe);
+ if (tda_fail(ret))
goto fail;
mutex_lock(&priv->lock);
diff --git a/drivers/media/common/tuners/tuner-simple.c b/drivers/media/common/tuners/tuner-simple.c
index 8cf2ab609d5..f8ee29e6059 100644
--- a/drivers/media/common/tuners/tuner-simple.c
+++ b/drivers/media/common/tuners/tuner-simple.c
@@ -546,14 +546,11 @@ static int simple_set_tv_freq(struct dvb_frontend *fe,
struct tuner_simple_priv *priv = fe->tuner_priv;
u8 config, cb;
u16 div;
- struct tunertype *tun;
u8 buffer[4];
int rc, IFPCoff, i;
enum param_type desired_type;
struct tuner_params *t_params;
- tun = priv->tun;
-
/* IFPCoff = Video Intermediate Frequency - Vif:
940 =16*58.75 NTSC/J (Japan)
732 =16*45.75 M/N STD
diff --git a/drivers/media/common/tuners/xc5000.c b/drivers/media/common/tuners/xc5000.c
index 432003dded7..d2b2c12a556 100644
--- a/drivers/media/common/tuners/xc5000.c
+++ b/drivers/media/common/tuners/xc5000.c
@@ -217,6 +217,7 @@ static int xc_send_i2c_data(struct xc5000_priv *priv, u8 *buf, int len)
return XC_RESULT_SUCCESS;
}
+#if 0
/* This routine is never used because the only time we read data from the
i2c bus is when we read registers, and we want that to be an atomic i2c
transaction in case we are on a multi-master bus */
@@ -231,6 +232,27 @@ static int xc_read_i2c_data(struct xc5000_priv *priv, u8 *buf, int len)
}
return 0;
}
+#endif
+
+static int xc5000_readreg(struct xc5000_priv *priv, u16 reg, u16 *val)
+{
+ u8 buf[2] = { reg >> 8, reg & 0xff };
+ u8 bval[2] = { 0, 0 };
+ struct i2c_msg msg[2] = {
+ { .addr = priv->i2c_props.addr,
+ .flags = 0, .buf = &buf[0], .len = 2 },
+ { .addr = priv->i2c_props.addr,
+ .flags = I2C_M_RD, .buf = &bval[0], .len = 2 },
+ };
+
+ if (i2c_transfer(priv->i2c_props.adap, msg, 2) != 2) {
+ printk(KERN_WARNING "xc5000: I2C read failed\n");
+ return -EREMOTEIO;
+ }
+
+ *val = (bval[0] << 8) | bval[1];
+ return XC_RESULT_SUCCESS;
+}
static void xc_wait(int wait_ms)
{
@@ -275,20 +297,14 @@ static int xc_write_reg(struct xc5000_priv *priv, u16 regAddr, u16 i2cData)
if (result == XC_RESULT_SUCCESS) {
/* wait for busy flag to clear */
while ((WatchDogTimer > 0) && (result == XC_RESULT_SUCCESS)) {
- buf[0] = 0;
- buf[1] = XREG_BUSY;
-
- result = xc_send_i2c_data(priv, buf, 2);
+ result = xc5000_readreg(priv, XREG_BUSY, (u16 *)buf);
if (result == XC_RESULT_SUCCESS) {
- result = xc_read_i2c_data(priv, buf, 2);
- if (result == XC_RESULT_SUCCESS) {
- if ((buf[0] == 0) && (buf[1] == 0)) {
- /* busy flag cleared */
+ if ((buf[0] == 0) && (buf[1] == 0)) {
+ /* busy flag cleared */
break;
- } else {
- xc_wait(5); /* wait 5 ms */
- WatchDogTimer--;
- }
+ } else {
+ xc_wait(5); /* wait 5 ms */
+ WatchDogTimer--;
}
}
}
@@ -526,25 +542,6 @@ static int xc_tune_channel(struct xc5000_priv *priv, u32 freq_hz, int mode)
return found;
}
-static int xc5000_readreg(struct xc5000_priv *priv, u16 reg, u16 *val)
-{
- u8 buf[2] = { reg >> 8, reg & 0xff };
- u8 bval[2] = { 0, 0 };
- struct i2c_msg msg[2] = {
- { .addr = priv->i2c_props.addr,
- .flags = 0, .buf = &buf[0], .len = 2 },
- { .addr = priv->i2c_props.addr,
- .flags = I2C_M_RD, .buf = &bval[0], .len = 2 },
- };
-
- if (i2c_transfer(priv->i2c_props.adap, msg, 2) != 2) {
- printk(KERN_WARNING "xc5000: I2C read failed\n");
- return -EREMOTEIO;
- }
-
- *val = (bval[0] << 8) | bval[1];
- return XC_RESULT_SUCCESS;
-}
static int xc5000_fwupload(struct dvb_frontend *fe)
{
diff --git a/drivers/media/dvb/bt8xx/dst_ca.c b/drivers/media/dvb/bt8xx/dst_ca.c
index 770243c720d..cf870516284 100644
--- a/drivers/media/dvb/bt8xx/dst_ca.c
+++ b/drivers/media/dvb/bt8xx/dst_ca.c
@@ -565,7 +565,7 @@ static long dst_ca_ioctl(struct file *file, unsigned int cmd, unsigned long ioct
int result = 0;
lock_kernel();
- dvbdev = (struct dvb_device *)file->private_data;
+ dvbdev = file->private_data;
state = (struct dst_state *)dvbdev->priv;
p_ca_message = kmalloc(sizeof (struct ca_msg), GFP_KERNEL);
p_ca_slot_info = kmalloc(sizeof (struct ca_slot_info), GFP_KERNEL);
diff --git a/drivers/media/dvb/dvb-core/dmxdev.c b/drivers/media/dvb/dvb-core/dmxdev.c
index 425862ffb28..0042306ea11 100644
--- a/drivers/media/dvb/dvb-core/dmxdev.c
+++ b/drivers/media/dvb/dvb-core/dmxdev.c
@@ -207,7 +207,7 @@ static int dvb_dvr_release(struct inode *inode, struct file *file)
}
/* TODO */
dvbdev->users--;
- if(dvbdev->users==-1 && dmxdev->exit==1) {
+ if (dvbdev->users == 1 && dmxdev->exit == 1) {
fops_put(file->f_op);
file->f_op = NULL;
mutex_unlock(&dmxdev->mutex);
diff --git a/drivers/media/dvb/dvb-core/dvb_ca_en50221.c b/drivers/media/dvb/dvb-core/dvb_ca_en50221.c
index ef259a0718a..cb97e6b8543 100644
--- a/drivers/media/dvb/dvb-core/dvb_ca_en50221.c
+++ b/drivers/media/dvb/dvb-core/dvb_ca_en50221.c
@@ -1318,8 +1318,11 @@ static ssize_t dvb_ca_en50221_io_write(struct file *file,
fragbuf[0] = connection_id;
fragbuf[1] = ((fragpos + fraglen) < count) ? 0x80 : 0x00;
- if ((status = copy_from_user(fragbuf + 2, buf + fragpos, fraglen)) != 0)
+ status = copy_from_user(fragbuf + 2, buf + fragpos, fraglen);
+ if (status) {
+ status = -EFAULT;
goto exit;
+ }
timeout = jiffies + HZ / 2;
written = 0;
@@ -1494,8 +1497,11 @@ static ssize_t dvb_ca_en50221_io_read(struct file *file, char __user * buf,
hdr[0] = slot;
hdr[1] = connection_id;
- if ((status = copy_to_user(buf, hdr, 2)) != 0)
+ status = copy_to_user(buf, hdr, 2);
+ if (status) {
+ status = -EFAULT;
goto exit;
+ }
status = pktlen;
exit:
diff --git a/drivers/media/dvb/dvb-core/dvb_demux.c b/drivers/media/dvb/dvb-core/dvb_demux.c
index 977ddba3e23..4a88a3e4db2 100644
--- a/drivers/media/dvb/dvb-core/dvb_demux.c
+++ b/drivers/media/dvb/dvb-core/dvb_demux.c
@@ -1130,13 +1130,9 @@ static int dvbdmx_write(struct dmx_demux *demux, const char __user *buf, size_t
if ((!demux->frontend) || (demux->frontend->source != DMX_MEMORY_FE))
return -EINVAL;
- p = kmalloc(count, GFP_USER);
- if (!p)
- return -ENOMEM;
- if (copy_from_user(p, buf, count)) {
- kfree(p);
- return -EFAULT;
- }
+ p = memdup_user(buf, count);
+ if (IS_ERR(p))
+ return PTR_ERR(p);
if (mutex_lock_interruptible(&dvbdemux->mutex)) {
kfree(p);
return -ERESTARTSYS;
diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c
index 44ae89ecef9..4d45b7d6b3f 100644
--- a/drivers/media/dvb/dvb-core/dvb_frontend.c
+++ b/drivers/media/dvb/dvb-core/dvb_frontend.c
@@ -465,7 +465,7 @@ static void dvb_frontend_swzigzag(struct dvb_frontend *fe)
if ((fepriv->state & FESTATE_SEARCHING_FAST) || (fepriv->state & FESTATE_RETUNE)) {
fepriv->delay = fepriv->min_delay;
- /* peform a tune */
+ /* perform a tune */
retval = dvb_frontend_swzigzag_autotune(fe,
fepriv->check_wrapped);
if (retval < 0) {
@@ -791,7 +791,7 @@ static int dvb_frontend_start(struct dvb_frontend *fe)
return 0;
}
-static void dvb_frontend_get_frequeny_limits(struct dvb_frontend *fe,
+static void dvb_frontend_get_frequency_limits(struct dvb_frontend *fe,
u32 *freq_min, u32 *freq_max)
{
*freq_min = max(fe->ops.info.frequency_min, fe->ops.tuner_ops.info.frequency_min);
@@ -815,7 +815,7 @@ static int dvb_frontend_check_parameters(struct dvb_frontend *fe,
u32 freq_max;
/* range check: frequency */
- dvb_frontend_get_frequeny_limits(fe, &freq_min, &freq_max);
+ dvb_frontend_get_frequency_limits(fe, &freq_min, &freq_max);
if ((freq_min && parms->frequency < freq_min) ||
(freq_max && parms->frequency > freq_max)) {
printk(KERN_WARNING "DVB: adapter %i frontend %i frequency %u out of range (%u..%u)\n",
@@ -1627,7 +1627,7 @@ static int dvb_frontend_ioctl_legacy(struct file *file,
case FE_GET_INFO: {
struct dvb_frontend_info* info = parg;
memcpy(info, &fe->ops.info, sizeof(struct dvb_frontend_info));
- dvb_frontend_get_frequeny_limits(fe, &info->frequency_min, &info->frequency_max);
+ dvb_frontend_get_frequency_limits(fe, &info->frequency_min, &info->frequency_max);
/* Force the CAN_INVERSION_AUTO bit on. If the frontend doesn't
* do it, it is done for it. */
@@ -1726,7 +1726,7 @@ static int dvb_frontend_ioctl_legacy(struct file *file,
* (stv0299 for instance) take longer than 8msec to
* respond to a set_voltage command. Those switches
* need custom routines to switch properly. For all
- * other frontends, the following shoule work ok.
+ * other frontends, the following should work ok.
* Dish network legacy switches (as used by Dish500)
* are controlled by sending 9-bit command words
* spaced 8msec apart.
diff --git a/drivers/media/dvb/dvb-usb/a800.c b/drivers/media/dvb/dvb-usb/a800.c
index b6cbb1dfc5f..a5c36372713 100644
--- a/drivers/media/dvb/dvb-usb/a800.c
+++ b/drivers/media/dvb/dvb-usb/a800.c
@@ -37,7 +37,7 @@ static int a800_identify_state(struct usb_device *udev, struct dvb_usb_device_pr
return 0;
}
-static struct dvb_usb_rc_key ir_codes_a800_table[] = {
+static struct ir_scancode ir_codes_a800_table[] = {
{ 0x0201, KEY_PROG1 }, /* SOURCE */
{ 0x0200, KEY_POWER }, /* POWER */
{ 0x0205, KEY_1 }, /* 1 */
@@ -146,10 +146,12 @@ static struct dvb_usb_device_properties a800_properties = {
.power_ctrl = a800_power_ctrl,
.identify_state = a800_identify_state,
- .rc_interval = DEFAULT_RC_INTERVAL,
- .rc_key_map = ir_codes_a800_table,
- .rc_key_map_size = ARRAY_SIZE(ir_codes_a800_table),
- .rc_query = a800_rc_query,
+ .rc.legacy = {
+ .rc_interval = DEFAULT_RC_INTERVAL,
+ .rc_key_map = ir_codes_a800_table,
+ .rc_key_map_size = ARRAY_SIZE(ir_codes_a800_table),
+ .rc_query = a800_rc_query,
+ },
.i2c_algo = &dibusb_i2c_algo,
diff --git a/drivers/media/dvb/dvb-usb/af9005-remote.c b/drivers/media/dvb/dvb-usb/af9005-remote.c
index b41fa873b04..696207fe37e 100644
--- a/drivers/media/dvb/dvb-usb/af9005-remote.c
+++ b/drivers/media/dvb/dvb-usb/af9005-remote.c
@@ -33,7 +33,7 @@ MODULE_PARM_DESC(debug,
#define deb_decode(args...) dprintk(dvb_usb_af9005_remote_debug,0x01,args)
-struct dvb_usb_rc_key ir_codes_af9005_table[] = {
+struct ir_scancode ir_codes_af9005_table[] = {
{0x01b7, KEY_POWER},
{0x01a7, KEY_VOLUMEUP},
@@ -133,7 +133,7 @@ int af9005_rc_decode(struct dvb_usb_device *d, u8 * data, int len, u32 * event,
for (i = 0; i < ir_codes_af9005_table_size; i++) {
if (rc5_custom(&ir_codes_af9005_table[i]) == cust
&& rc5_data(&ir_codes_af9005_table[i]) == dat) {
- *event = ir_codes_af9005_table[i].event;
+ *event = ir_codes_af9005_table[i].keycode;
*state = REMOTE_KEY_PRESSED;
deb_decode
("key pressed, event %x\n", *event);
diff --git a/drivers/media/dvb/dvb-usb/af9005.c b/drivers/media/dvb/dvb-usb/af9005.c
index cfd6107d534..8ecba8848bc 100644
--- a/drivers/media/dvb/dvb-usb/af9005.c
+++ b/drivers/media/dvb/dvb-usb/af9005.c
@@ -54,50 +54,6 @@ struct af9005_device_state {
int led_state;
};
-static 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;
-}
-
static int af9005_generic_read_write(struct dvb_usb_device *d, u16 reg,
int readwrite, int type, u8 * values, int len)
{
@@ -146,7 +102,7 @@ static int af9005_generic_read_write(struct dvb_usb_device *d, u16 reg,
obuf[8] = values[0];
obuf[7] = command;
- ret = af9005_usb_generic_rw(d, obuf, 16, ibuf, 17, 0);
+ ret = dvb_usb_generic_rw(d, obuf, 16, ibuf, 17, 0);
if (ret)
return ret;
@@ -534,7 +490,7 @@ int af9005_send_command(struct dvb_usb_device *d, u8 command, u8 * wbuf,
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);
+ ret = dvb_usb_generic_rw(d, buf, wlen + 7, ibuf, rlen + 7, 0);
if (ret)
return ret;
if (ibuf[2] != 0x27) {
@@ -581,7 +537,7 @@ int af9005_read_eeprom(struct dvb_usb_device *d, u8 address, u8 * values,
obuf[6] = len;
obuf[7] = address;
- ret = af9005_usb_generic_rw(d, obuf, 16, ibuf, 14, 0);
+ ret = dvb_usb_generic_rw(d, obuf, 16, ibuf, 14, 0);
if (ret)
return ret;
if (ibuf[2] != 0x2b) {
@@ -882,7 +838,7 @@ static int af9005_rc_query(struct dvb_usb_device *d, u32 * event, int *state)
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);
+ ret = dvb_usb_generic_rw(d, obuf, 5, ibuf, 256, 0);
if (ret) {
err("rc query failed");
return ret;
@@ -1069,10 +1025,15 @@ static struct dvb_usb_device_properties af9005_properties = {
.i2c_algo = &af9005_i2c_algo,
- .rc_interval = 200,
- .rc_key_map = NULL,
- .rc_key_map_size = 0,
- .rc_query = af9005_rc_query,
+ .rc.legacy = {
+ .rc_interval = 200,
+ .rc_key_map = NULL,
+ .rc_key_map_size = 0,
+ .rc_query = af9005_rc_query,
+ },
+
+ .generic_bulk_ctrl_endpoint = 2,
+ .generic_bulk_ctrl_endpoint_response = 1,
.num_device_descs = 3,
.devices = {
@@ -1113,10 +1074,10 @@ static int __init af9005_usb_module_init(void)
rc_keys_size = symbol_request(ir_codes_af9005_table_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;
+ af9005_properties.rc.legacy.rc_query = NULL;
} else {
- af9005_properties.rc_key_map = rc_keys;
- af9005_properties.rc_key_map_size = *rc_keys_size;
+ af9005_properties.rc.legacy.rc_key_map = rc_keys;
+ af9005_properties.rc.legacy.rc_key_map_size = *rc_keys_size;
}
return 0;
diff --git a/drivers/media/dvb/dvb-usb/af9005.h b/drivers/media/dvb/dvb-usb/af9005.h
index 088e7083a39..3c1fbd1c5d6 100644
--- a/drivers/media/dvb/dvb-usb/af9005.h
+++ b/drivers/media/dvb/dvb-usb/af9005.h
@@ -3490,7 +3490,7 @@ 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 ir_codes_af9005_table[];
+extern struct ir_scancode ir_codes_af9005_table[];
extern int ir_codes_af9005_table_size;
#endif
diff --git a/drivers/media/dvb/dvb-usb/af9015.c b/drivers/media/dvb/dvb-usb/af9015.c
index 66c7c3ea799..ea1ed3b4592 100644
--- a/drivers/media/dvb/dvb-usb/af9015.c
+++ b/drivers/media/dvb/dvb-usb/af9015.c
@@ -735,7 +735,7 @@ error:
struct af9015_setup {
unsigned int id;
- struct dvb_usb_rc_key *rc_key_map;
+ struct ir_scancode *rc_key_map;
unsigned int rc_key_map_size;
u8 *ir_table;
unsigned int ir_table_size;
@@ -847,8 +847,8 @@ static void af9015_set_remote_config(struct usb_device *udev,
}
if (table) {
- props->rc_key_map = table->rc_key_map;
- props->rc_key_map_size = table->rc_key_map_size;
+ props->rc.legacy.rc_key_map = table->rc_key_map;
+ props->rc.legacy.rc_key_map_size = table->rc_key_map_size;
af9015_config.ir_table = table->ir_table;
af9015_config.ir_table_size = table->ir_table_size;
}
@@ -878,8 +878,8 @@ static int af9015_read_config(struct usb_device *udev)
deb_info("%s: IR mode:%d\n", __func__, val);
for (i = 0; i < af9015_properties_count; i++) {
if (val == AF9015_IR_MODE_DISABLED) {
- af9015_properties[i].rc_key_map = NULL;
- af9015_properties[i].rc_key_map_size = 0;
+ af9015_properties[i].rc.legacy.rc_key_map = NULL;
+ af9015_properties[i].rc.legacy.rc_key_map_size = 0;
} else
af9015_set_remote_config(udev, &af9015_properties[i]);
}
@@ -1063,7 +1063,7 @@ static int af9015_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
{
u8 buf[8];
struct req_t req = {GET_IR_CODE, 0, 0, 0, 0, sizeof(buf), buf};
- struct dvb_usb_rc_key *keymap = d->props.rc_key_map;
+ struct ir_scancode *keymap = d->props.rc.legacy.rc_key_map;
int i, ret;
memset(buf, 0, sizeof(buf));
@@ -1075,10 +1075,10 @@ static int af9015_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
*event = 0;
*state = REMOTE_NO_KEY_PRESSED;
- for (i = 0; i < d->props.rc_key_map_size; i++) {
+ for (i = 0; i < d->props.rc.legacy.rc_key_map_size; i++) {
if (!buf[1] && rc5_custom(&keymap[i]) == buf[0] &&
rc5_data(&keymap[i]) == buf[2]) {
- *event = keymap[i].event;
+ *event = keymap[i].keycode;
*state = REMOTE_KEY_PRESSED;
break;
}
@@ -1299,6 +1299,7 @@ static struct usb_device_id af9015_usb_table[] = {
{USB_DEVICE(USB_VID_LEADTEK, USB_PID_WINFAST_DTV2000DS)},
/* 30 */{USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_UB383_T)},
{USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_395U_4)},
+ {USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A815M)},
{0},
};
MODULE_DEVICE_TABLE(usb, af9015_usb_table);
@@ -1353,8 +1354,10 @@ static struct dvb_usb_device_properties af9015_properties[] = {
.identify_state = af9015_identify_state,
- .rc_query = af9015_rc_query,
- .rc_interval = 150,
+ .rc.legacy = {
+ .rc_query = af9015_rc_query,
+ .rc_interval = 150,
+ },
.i2c_algo = &af9015_i2c_algo,
@@ -1460,8 +1463,10 @@ static struct dvb_usb_device_properties af9015_properties[] = {
.identify_state = af9015_identify_state,
- .rc_query = af9015_rc_query,
- .rc_interval = 150,
+ .rc.legacy = {
+ .rc_query = af9015_rc_query,
+ .rc_interval = 150,
+ },
.i2c_algo = &af9015_i2c_algo,
@@ -1567,12 +1572,14 @@ static struct dvb_usb_device_properties af9015_properties[] = {
.identify_state = af9015_identify_state,
- .rc_query = af9015_rc_query,
- .rc_interval = 150,
+ .rc.legacy = {
+ .rc_query = af9015_rc_query,
+ .rc_interval = 150,
+ },
.i2c_algo = &af9015_i2c_algo,
- .num_device_descs = 8, /* max 9 */
+ .num_device_descs = 9, /* max 9 */
.devices = {
{
.name = "AverMedia AVerTV Volar GPS 805 (A805)",
@@ -1617,6 +1624,11 @@ static struct dvb_usb_device_properties af9015_properties[] = {
.cold_ids = {&af9015_usb_table[30], NULL},
.warm_ids = {NULL},
},
+ {
+ .name = "AverMedia AVerTV Volar M (A815Mac)",
+ .cold_ids = {&af9015_usb_table[32], NULL},
+ .warm_ids = {NULL},
+ },
}
},
};
diff --git a/drivers/media/dvb/dvb-usb/af9015.h b/drivers/media/dvb/dvb-usb/af9015.h
index 63b2a4907b7..c8e9349742e 100644
--- a/drivers/media/dvb/dvb-usb/af9015.h
+++ b/drivers/media/dvb/dvb-usb/af9015.h
@@ -123,7 +123,7 @@ enum af9015_remote {
/* LeadTek - Y04G0051 */
/* Leadtek WinFast DTV Dongle Gold */
-static struct dvb_usb_rc_key ir_codes_af9015_table_leadtek[] = {
+static struct ir_scancode ir_codes_af9015_table_leadtek[] = {
{ 0x001e, KEY_1 },
{ 0x001f, KEY_2 },
{ 0x0020, KEY_3 },
@@ -227,7 +227,7 @@ static u8 af9015_ir_table_leadtek[] = {
};
/* TwinHan AzureWave AD-TU700(704J) */
-static struct dvb_usb_rc_key ir_codes_af9015_table_twinhan[] = {
+static struct ir_scancode ir_codes_af9015_table_twinhan[] = {
{ 0x053f, KEY_POWER },
{ 0x0019, KEY_FAVORITES }, /* Favorite List */
{ 0x0004, KEY_TEXT }, /* Teletext */
@@ -338,7 +338,7 @@ static u8 af9015_ir_table_twinhan[] = {
};
/* A-Link DTU(m) */
-static struct dvb_usb_rc_key ir_codes_af9015_table_a_link[] = {
+static struct ir_scancode ir_codes_af9015_table_a_link[] = {
{ 0x001e, KEY_1 },
{ 0x001f, KEY_2 },
{ 0x0020, KEY_3 },
@@ -381,7 +381,7 @@ static u8 af9015_ir_table_a_link[] = {
};
/* MSI DIGIVOX mini II V3.0 */
-static struct dvb_usb_rc_key ir_codes_af9015_table_msi[] = {
+static struct ir_scancode ir_codes_af9015_table_msi[] = {
{ 0x001e, KEY_1 },
{ 0x001f, KEY_2 },
{ 0x0020, KEY_3 },
@@ -424,7 +424,7 @@ static u8 af9015_ir_table_msi[] = {
};
/* MYGICTV U718 */
-static struct dvb_usb_rc_key ir_codes_af9015_table_mygictv[] = {
+static struct ir_scancode ir_codes_af9015_table_mygictv[] = {
{ 0x003d, KEY_SWITCHVIDEOMODE },
/* TV / AV */
{ 0x0545, KEY_POWER },
@@ -550,7 +550,7 @@ static u8 af9015_ir_table_kworld[] = {
};
/* AverMedia Volar X */
-static struct dvb_usb_rc_key ir_codes_af9015_table_avermedia[] = {
+static struct ir_scancode ir_codes_af9015_table_avermedia[] = {
{ 0x053d, KEY_PROG1 }, /* SOURCE */
{ 0x0512, KEY_POWER }, /* POWER */
{ 0x051e, KEY_1 }, /* 1 */
@@ -656,7 +656,7 @@ static u8 af9015_ir_table_avermedia_ks[] = {
};
/* Digittrade DVB-T USB Stick */
-static struct dvb_usb_rc_key ir_codes_af9015_table_digittrade[] = {
+static struct ir_scancode ir_codes_af9015_table_digittrade[] = {
{ 0x010f, KEY_LAST }, /* RETURN */
{ 0x0517, KEY_TEXT }, /* TELETEXT */
{ 0x0108, KEY_EPG }, /* EPG */
@@ -719,7 +719,7 @@ static u8 af9015_ir_table_digittrade[] = {
};
/* TREKSTOR DVB-T USB Stick */
-static struct dvb_usb_rc_key ir_codes_af9015_table_trekstor[] = {
+static struct ir_scancode ir_codes_af9015_table_trekstor[] = {
{ 0x0704, KEY_AGAIN }, /* Home */
{ 0x0705, KEY_MUTE }, /* Mute */
{ 0x0706, KEY_UP }, /* Up */
@@ -782,7 +782,7 @@ static u8 af9015_ir_table_trekstor[] = {
};
/* MSI DIGIVOX mini III */
-static struct dvb_usb_rc_key ir_codes_af9015_table_msi_digivox_iii[] = {
+static struct ir_scancode ir_codes_af9015_table_msi_digivox_iii[] = {
{ 0x0713, KEY_POWER }, /* [red power button] */
{ 0x073b, KEY_VIDEO }, /* Source */
{ 0x073e, KEY_ZOOM }, /* Zoom */
diff --git a/drivers/media/dvb/dvb-usb/anysee.c b/drivers/media/dvb/dvb-usb/anysee.c
index faca1ad88a6..4685259e161 100644
--- a/drivers/media/dvb/dvb-usb/anysee.c
+++ b/drivers/media/dvb/dvb-usb/anysee.c
@@ -377,7 +377,7 @@ static int anysee_tuner_attach(struct dvb_usb_adapter *adap)
static int anysee_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
{
u8 buf[] = {CMD_GET_IR_CODE};
- struct dvb_usb_rc_key *keymap = d->props.rc_key_map;
+ struct ir_scancode *keymap = d->props.rc.legacy.rc_key_map;
u8 ircode[2];
int i, ret;
@@ -388,10 +388,10 @@ static int anysee_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
*event = 0;
*state = REMOTE_NO_KEY_PRESSED;
- for (i = 0; i < d->props.rc_key_map_size; i++) {
+ for (i = 0; i < d->props.rc.legacy.rc_key_map_size; i++) {
if (rc5_custom(&keymap[i]) == ircode[0] &&
rc5_data(&keymap[i]) == ircode[1]) {
- *event = keymap[i].event;
+ *event = keymap[i].keycode;
*state = REMOTE_KEY_PRESSED;
return 0;
}
@@ -399,7 +399,7 @@ static int anysee_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
return 0;
}
-static struct dvb_usb_rc_key ir_codes_anysee_table[] = {
+static struct ir_scancode ir_codes_anysee_table[] = {
{ 0x0100, KEY_0 },
{ 0x0101, KEY_1 },
{ 0x0102, KEY_2 },
@@ -463,6 +463,11 @@ static int anysee_probe(struct usb_interface *intf,
if (intf->num_altsetting < 1)
return -ENODEV;
+ /*
+ * Anysee is always warm (its USB-bridge, Cypress FX2, uploads
+ * firmware from eeprom). If dvb_usb_device_init() succeeds that
+ * means d is a valid pointer.
+ */
ret = dvb_usb_device_init(intf, &anysee_properties, THIS_MODULE, &d,
adapter_nr);
if (ret)
@@ -479,10 +484,7 @@ static int anysee_probe(struct usb_interface *intf,
if (ret)
return ret;
- if (d)
- ret = anysee_init(d);
-
- return ret;
+ return anysee_init(d);
}
static struct usb_device_id anysee_table[] = {
@@ -518,10 +520,12 @@ static struct dvb_usb_device_properties anysee_properties = {
}
},
- .rc_key_map = ir_codes_anysee_table,
- .rc_key_map_size = ARRAY_SIZE(ir_codes_anysee_table),
- .rc_query = anysee_rc_query,
- .rc_interval = 200, /* windows driver uses 500ms */
+ .rc.legacy = {
+ .rc_key_map = ir_codes_anysee_table,
+ .rc_key_map_size = ARRAY_SIZE(ir_codes_anysee_table),
+ .rc_query = anysee_rc_query,
+ .rc_interval = 200, /* windows driver uses 500ms */
+ },
.i2c_algo = &anysee_i2c_algo,
diff --git a/drivers/media/dvb/dvb-usb/az6027.c b/drivers/media/dvb/dvb-usb/az6027.c
index 6681ac1c56e..62c58288469 100644
--- a/drivers/media/dvb/dvb-usb/az6027.c
+++ b/drivers/media/dvb/dvb-usb/az6027.c
@@ -386,7 +386,7 @@ static int az6027_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
}
/* keys for the enclosed remote control */
-static struct dvb_usb_rc_key ir_codes_az6027_table[] = {
+static struct ir_scancode ir_codes_az6027_table[] = {
{ 0x01, KEY_1 },
{ 0x02, KEY_2 },
};
@@ -1125,10 +1125,13 @@ static struct dvb_usb_device_properties az6027_properties = {
.power_ctrl = az6027_power_ctrl,
.read_mac_address = az6027_read_mac_addr,
*/
- .rc_key_map = ir_codes_az6027_table,
- .rc_key_map_size = ARRAY_SIZE(ir_codes_az6027_table),
- .rc_interval = 400,
- .rc_query = az6027_rc_query,
+ .rc.legacy = {
+ .rc_key_map = ir_codes_az6027_table,
+ .rc_key_map_size = ARRAY_SIZE(ir_codes_az6027_table),
+ .rc_interval = 400,
+ .rc_query = az6027_rc_query,
+ },
+
.i2c_algo = &az6027_i2c_algo,
.num_device_descs = 5,
diff --git a/drivers/media/dvb/dvb-usb/cinergyT2-core.c b/drivers/media/dvb/dvb-usb/cinergyT2-core.c
index 5a9c14bdc98..4f5aa83fc1f 100644
--- a/drivers/media/dvb/dvb-usb/cinergyT2-core.c
+++ b/drivers/media/dvb/dvb-usb/cinergyT2-core.c
@@ -84,7 +84,7 @@ static int cinergyt2_frontend_attach(struct dvb_usb_adapter *adap)
return 0;
}
-static struct dvb_usb_rc_key ir_codes_cinergyt2_table[] = {
+static struct ir_scancode ir_codes_cinergyt2_table[] = {
{ 0x0401, KEY_POWER },
{ 0x0402, KEY_1 },
{ 0x0403, KEY_2 },
@@ -217,10 +217,12 @@ static struct dvb_usb_device_properties cinergyt2_properties = {
.power_ctrl = cinergyt2_power_ctrl,
- .rc_interval = 50,
- .rc_key_map = ir_codes_cinergyt2_table,
- .rc_key_map_size = ARRAY_SIZE(ir_codes_cinergyt2_table),
- .rc_query = cinergyt2_rc_query,
+ .rc.legacy = {
+ .rc_interval = 50,
+ .rc_key_map = ir_codes_cinergyt2_table,
+ .rc_key_map_size = ARRAY_SIZE(ir_codes_cinergyt2_table),
+ .rc_query = cinergyt2_rc_query,
+ },
.generic_bulk_ctrl_endpoint = 1,
diff --git a/drivers/media/dvb/dvb-usb/cxusb.c b/drivers/media/dvb/dvb-usb/cxusb.c
index 11e9e85dac8..cd9f362c37b 100644
--- a/drivers/media/dvb/dvb-usb/cxusb.c
+++ b/drivers/media/dvb/dvb-usb/cxusb.c
@@ -385,7 +385,7 @@ static int cxusb_d680_dmb_streaming_ctrl(
static int cxusb_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
{
- struct dvb_usb_rc_key *keymap = d->props.rc_key_map;
+ struct ir_scancode *keymap = d->props.rc.legacy.rc_key_map;
u8 ircode[4];
int i;
@@ -394,10 +394,10 @@ static int cxusb_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
*event = 0;
*state = REMOTE_NO_KEY_PRESSED;
- for (i = 0; i < d->props.rc_key_map_size; i++) {
+ for (i = 0; i < d->props.rc.legacy.rc_key_map_size; i++) {
if (rc5_custom(&keymap[i]) == ircode[2] &&
rc5_data(&keymap[i]) == ircode[3]) {
- *event = keymap[i].event;
+ *event = keymap[i].keycode;
*state = REMOTE_KEY_PRESSED;
return 0;
@@ -410,7 +410,7 @@ static int cxusb_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
static int cxusb_bluebird2_rc_query(struct dvb_usb_device *d, u32 *event,
int *state)
{
- struct dvb_usb_rc_key *keymap = d->props.rc_key_map;
+ struct ir_scancode *keymap = d->props.rc.legacy.rc_key_map;
u8 ircode[4];
int i;
struct i2c_msg msg = { .addr = 0x6b, .flags = I2C_M_RD,
@@ -422,10 +422,10 @@ static int cxusb_bluebird2_rc_query(struct dvb_usb_device *d, u32 *event,
if (cxusb_i2c_xfer(&d->i2c_adap, &msg, 1) != 1)
return 0;
- for (i = 0; i < d->props.rc_key_map_size; i++) {
+ for (i = 0; i < d->props.rc.legacy.rc_key_map_size; i++) {
if (rc5_custom(&keymap[i]) == ircode[1] &&
rc5_data(&keymap[i]) == ircode[2]) {
- *event = keymap[i].event;
+ *event = keymap[i].keycode;
*state = REMOTE_KEY_PRESSED;
return 0;
@@ -438,7 +438,7 @@ static int cxusb_bluebird2_rc_query(struct dvb_usb_device *d, u32 *event,
static int cxusb_d680_dmb_rc_query(struct dvb_usb_device *d, u32 *event,
int *state)
{
- struct dvb_usb_rc_key *keymap = d->props.rc_key_map;
+ struct ir_scancode *keymap = d->props.rc.legacy.rc_key_map;
u8 ircode[2];
int i;
@@ -448,10 +448,10 @@ static int cxusb_d680_dmb_rc_query(struct dvb_usb_device *d, u32 *event,
if (cxusb_ctrl_msg(d, 0x10, NULL, 0, ircode, 2) < 0)
return 0;
- for (i = 0; i < d->props.rc_key_map_size; i++) {
+ for (i = 0; i < d->props.rc.legacy.rc_key_map_size; i++) {
if (rc5_custom(&keymap[i]) == ircode[0] &&
rc5_data(&keymap[i]) == ircode[1]) {
- *event = keymap[i].event;
+ *event = keymap[i].keycode;
*state = REMOTE_KEY_PRESSED;
return 0;
@@ -461,7 +461,7 @@ static int cxusb_d680_dmb_rc_query(struct dvb_usb_device *d, u32 *event,
return 0;
}
-static struct dvb_usb_rc_key ir_codes_dvico_mce_table[] = {
+static struct ir_scancode ir_codes_dvico_mce_table[] = {
{ 0xfe02, KEY_TV },
{ 0xfe0e, KEY_MP3 },
{ 0xfe1a, KEY_DVD },
@@ -509,7 +509,7 @@ static struct dvb_usb_rc_key ir_codes_dvico_mce_table[] = {
{ 0xfe4e, KEY_POWER },
};
-static struct dvb_usb_rc_key ir_codes_dvico_portable_table[] = {
+static struct ir_scancode ir_codes_dvico_portable_table[] = {
{ 0xfc02, KEY_SETUP }, /* Profile */
{ 0xfc43, KEY_POWER2 },
{ 0xfc06, KEY_EPG },
@@ -548,7 +548,7 @@ static struct dvb_usb_rc_key ir_codes_dvico_portable_table[] = {
{ 0xfc00, KEY_UNKNOWN }, /* HD */
};
-static struct dvb_usb_rc_key ir_codes_d680_dmb_table[] = {
+static struct ir_scancode ir_codes_d680_dmb_table[] = {
{ 0x0038, KEY_UNKNOWN }, /* TV/AV */
{ 0x080c, KEY_ZOOM },
{ 0x0800, KEY_0 },
@@ -923,7 +923,7 @@ static int cxusb_dualdig4_frontend_attach(struct dvb_usb_adapter *adap)
return -EIO;
/* try to determine if there is no IR decoder on the I2C bus */
- for (i = 0; adap->dev->props.rc_key_map != NULL && i < 5; i++) {
+ for (i = 0; adap->dev->props.rc.legacy.rc_key_map != NULL && i < 5; i++) {
msleep(20);
if (cxusb_i2c_xfer(&adap->dev->i2c_adap, &msg, 1) != 1)
goto no_IR;
@@ -931,7 +931,7 @@ static int cxusb_dualdig4_frontend_attach(struct dvb_usb_adapter *adap)
continue;
if (ircode[2] + ircode[3] != 0xff) {
no_IR:
- adap->dev->props.rc_key_map = NULL;
+ adap->dev->props.rc.legacy.rc_key_map = NULL;
info("No IR receiver detected on this device.");
break;
}
@@ -1451,10 +1451,12 @@ static struct dvb_usb_device_properties cxusb_bluebird_lgh064f_properties = {
.i2c_algo = &cxusb_i2c_algo,
- .rc_interval = 100,
- .rc_key_map = ir_codes_dvico_portable_table,
- .rc_key_map_size = ARRAY_SIZE(ir_codes_dvico_portable_table),
- .rc_query = cxusb_rc_query,
+ .rc.legacy = {
+ .rc_interval = 100,
+ .rc_key_map = ir_codes_dvico_portable_table,
+ .rc_key_map_size = ARRAY_SIZE(ir_codes_dvico_portable_table),
+ .rc_query = cxusb_rc_query,
+ },
.generic_bulk_ctrl_endpoint = 0x01,
@@ -1502,10 +1504,12 @@ static struct dvb_usb_device_properties cxusb_bluebird_dee1601_properties = {
.i2c_algo = &cxusb_i2c_algo,
- .rc_interval = 150,
- .rc_key_map = ir_codes_dvico_mce_table,
- .rc_key_map_size = ARRAY_SIZE(ir_codes_dvico_mce_table),
- .rc_query = cxusb_rc_query,
+ .rc.legacy = {
+ .rc_interval = 150,
+ .rc_key_map = ir_codes_dvico_mce_table,
+ .rc_key_map_size = ARRAY_SIZE(ir_codes_dvico_mce_table),
+ .rc_query = cxusb_rc_query,
+ },
.generic_bulk_ctrl_endpoint = 0x01,
@@ -1561,10 +1565,12 @@ static struct dvb_usb_device_properties cxusb_bluebird_lgz201_properties = {
.i2c_algo = &cxusb_i2c_algo,
- .rc_interval = 100,
- .rc_key_map = ir_codes_dvico_portable_table,
- .rc_key_map_size = ARRAY_SIZE(ir_codes_dvico_portable_table),
- .rc_query = cxusb_rc_query,
+ .rc.legacy = {
+ .rc_interval = 100,
+ .rc_key_map = ir_codes_dvico_portable_table,
+ .rc_key_map_size = ARRAY_SIZE(ir_codes_dvico_portable_table),
+ .rc_query = cxusb_rc_query,
+ },
.generic_bulk_ctrl_endpoint = 0x01,
.num_device_descs = 1,
@@ -1611,10 +1617,12 @@ static struct dvb_usb_device_properties cxusb_bluebird_dtt7579_properties = {
.i2c_algo = &cxusb_i2c_algo,
- .rc_interval = 100,
- .rc_key_map = ir_codes_dvico_portable_table,
- .rc_key_map_size = ARRAY_SIZE(ir_codes_dvico_portable_table),
- .rc_query = cxusb_rc_query,
+ .rc.legacy = {
+ .rc_interval = 100,
+ .rc_key_map = ir_codes_dvico_portable_table,
+ .rc_key_map_size = ARRAY_SIZE(ir_codes_dvico_portable_table),
+ .rc_query = cxusb_rc_query,
+ },
.generic_bulk_ctrl_endpoint = 0x01,
@@ -1660,10 +1668,12 @@ static struct dvb_usb_device_properties cxusb_bluebird_dualdig4_properties = {
.generic_bulk_ctrl_endpoint = 0x01,
- .rc_interval = 100,
- .rc_key_map = ir_codes_dvico_mce_table,
- .rc_key_map_size = ARRAY_SIZE(ir_codes_dvico_mce_table),
- .rc_query = cxusb_bluebird2_rc_query,
+ .rc.legacy = {
+ .rc_interval = 100,
+ .rc_key_map = ir_codes_dvico_mce_table,
+ .rc_key_map_size = ARRAY_SIZE(ir_codes_dvico_mce_table),
+ .rc_query = cxusb_bluebird2_rc_query,
+ },
.num_device_descs = 1,
.devices = {
@@ -1708,10 +1718,12 @@ static struct dvb_usb_device_properties cxusb_bluebird_nano2_properties = {
.generic_bulk_ctrl_endpoint = 0x01,
- .rc_interval = 100,
- .rc_key_map = ir_codes_dvico_portable_table,
- .rc_key_map_size = ARRAY_SIZE(ir_codes_dvico_portable_table),
- .rc_query = cxusb_bluebird2_rc_query,
+ .rc.legacy = {
+ .rc_interval = 100,
+ .rc_key_map = ir_codes_dvico_portable_table,
+ .rc_key_map_size = ARRAY_SIZE(ir_codes_dvico_portable_table),
+ .rc_query = cxusb_bluebird2_rc_query,
+ },
.num_device_descs = 1,
.devices = {
@@ -1758,10 +1770,12 @@ static struct dvb_usb_device_properties cxusb_bluebird_nano2_needsfirmware_prope
.generic_bulk_ctrl_endpoint = 0x01,
- .rc_interval = 100,
- .rc_key_map = ir_codes_dvico_portable_table,
- .rc_key_map_size = ARRAY_SIZE(ir_codes_dvico_portable_table),
- .rc_query = cxusb_rc_query,
+ .rc.legacy = {
+ .rc_interval = 100,
+ .rc_key_map = ir_codes_dvico_portable_table,
+ .rc_key_map_size = ARRAY_SIZE(ir_codes_dvico_portable_table),
+ .rc_query = cxusb_rc_query,
+ },
.num_device_descs = 1,
.devices = {
@@ -1849,10 +1863,12 @@ struct dvb_usb_device_properties cxusb_bluebird_dualdig4_rev2_properties = {
.generic_bulk_ctrl_endpoint = 0x01,
- .rc_interval = 100,
- .rc_key_map = ir_codes_dvico_mce_table,
- .rc_key_map_size = ARRAY_SIZE(ir_codes_dvico_mce_table),
- .rc_query = cxusb_rc_query,
+ .rc.legacy = {
+ .rc_interval = 100,
+ .rc_key_map = ir_codes_dvico_mce_table,
+ .rc_key_map_size = ARRAY_SIZE(ir_codes_dvico_mce_table),
+ .rc_query = cxusb_rc_query,
+ },
.num_device_descs = 1,
.devices = {
@@ -1897,10 +1913,12 @@ static struct dvb_usb_device_properties cxusb_d680_dmb_properties = {
.generic_bulk_ctrl_endpoint = 0x01,
- .rc_interval = 100,
- .rc_key_map = ir_codes_d680_dmb_table,
- .rc_key_map_size = ARRAY_SIZE(ir_codes_d680_dmb_table),
- .rc_query = cxusb_d680_dmb_rc_query,
+ .rc.legacy = {
+ .rc_interval = 100,
+ .rc_key_map = ir_codes_d680_dmb_table,
+ .rc_key_map_size = ARRAY_SIZE(ir_codes_d680_dmb_table),
+ .rc_query = cxusb_d680_dmb_rc_query,
+ },
.num_device_descs = 1,
.devices = {
@@ -1946,10 +1964,12 @@ static struct dvb_usb_device_properties cxusb_mygica_d689_properties = {
.generic_bulk_ctrl_endpoint = 0x01,
- .rc_interval = 100,
- .rc_key_map = ir_codes_d680_dmb_table,
- .rc_key_map_size = ARRAY_SIZE(ir_codes_d680_dmb_table),
- .rc_query = cxusb_d680_dmb_rc_query,
+ .rc.legacy = {
+ .rc_interval = 100,
+ .rc_key_map = ir_codes_d680_dmb_table,
+ .rc_key_map_size = ARRAY_SIZE(ir_codes_d680_dmb_table),
+ .rc_query = cxusb_d680_dmb_rc_query,
+ },
.num_device_descs = 1,
.devices = {
diff --git a/drivers/media/dvb/dvb-usb/dib0700.h b/drivers/media/dvb/dvb-usb/dib0700.h
index 83fc24a6c31..c2c9d236ec7 100644
--- a/drivers/media/dvb/dvb-usb/dib0700.h
+++ b/drivers/media/dvb/dvb-usb/dib0700.h
@@ -60,6 +60,7 @@ extern int dib0700_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff);
extern struct i2c_algorithm dib0700_i2c_algo;
extern int dib0700_identify_state(struct usb_device *udev, struct dvb_usb_device_properties *props,
struct dvb_usb_device_description **desc, int *cold);
+extern int dib0700_change_protocol(void *priv, u64 ir_type);
extern int dib0700_device_count;
extern int dvb_usb_dib0700_ir_proto;
diff --git a/drivers/media/dvb/dvb-usb/dib0700_core.c b/drivers/media/dvb/dvb-usb/dib0700_core.c
index 4f961d2d181..fe818348b8a 100644
--- a/drivers/media/dvb/dvb-usb/dib0700_core.c
+++ b/drivers/media/dvb/dvb-usb/dib0700_core.c
@@ -13,10 +13,6 @@ int dvb_usb_dib0700_debug;
module_param_named(debug,dvb_usb_dib0700_debug, int, 0644);
MODULE_PARM_DESC(debug, "set debugging level (1=info,2=fw,4=fwdata,8=data (or-able))." DVB_USB_DEBUG_STATUS);
-int dvb_usb_dib0700_ir_proto = 1;
-module_param(dvb_usb_dib0700_ir_proto, int, 0644);
-MODULE_PARM_DESC(dvb_usb_dib0700_ir_proto, "set ir protocol (0=NEC, 1=RC5 (default), 2=RC6).");
-
static int nb_packet_buffer_size = 21;
module_param(nb_packet_buffer_size, int, 0644);
MODULE_PARM_DESC(nb_packet_buffer_size,
@@ -53,7 +49,7 @@ static int dib0700_ctrl_wr(struct dvb_usb_device *d, u8 *tx, u8 txlen)
int status;
deb_data(">>> ");
- debug_dump(tx,txlen,deb_data);
+ debug_dump(tx, txlen, deb_data);
status = usb_control_msg(d->udev, usb_sndctrlpipe(d->udev,0),
tx[0], USB_TYPE_VENDOR | USB_DIR_OUT, 0, 0, tx, txlen,
@@ -98,7 +94,7 @@ int dib0700_ctrl_rd(struct dvb_usb_device *d, u8 *tx, u8 txlen, u8 *rx, u8 rxlen
deb_info("ep 0 read error (status = %d)\n",status);
deb_data("<<< ");
- debug_dump(rx,rxlen,deb_data);
+ debug_dump(rx, rxlen, deb_data);
return status; /* length in case of success */
}
@@ -106,28 +102,29 @@ int dib0700_ctrl_rd(struct dvb_usb_device *d, u8 *tx, u8 txlen, u8 *rx, u8 rxlen
int dib0700_set_gpio(struct dvb_usb_device *d, enum dib07x0_gpios gpio, u8 gpio_dir, u8 gpio_val)
{
u8 buf[3] = { REQUEST_SET_GPIO, gpio, ((gpio_dir & 0x01) << 7) | ((gpio_val & 0x01) << 6) };
- return dib0700_ctrl_wr(d,buf,3);
+ return dib0700_ctrl_wr(d, buf, sizeof(buf));
}
static int dib0700_set_usb_xfer_len(struct dvb_usb_device *d, u16 nb_ts_packets)
{
- struct dib0700_state *st = d->priv;
- u8 b[3];
- int ret;
-
- if (st->fw_version >= 0x10201) {
- b[0] = REQUEST_SET_USB_XFER_LEN;
- b[1] = (nb_ts_packets >> 8)&0xff;
- b[2] = nb_ts_packets & 0xff;
-
- deb_info("set the USB xfer len to %i Ts packet\n", nb_ts_packets);
-
- ret = dib0700_ctrl_wr(d, b, 3);
- } else {
- deb_info("this firmware does not allow to change the USB xfer len\n");
- ret = -EIO;
- }
- return ret;
+ struct dib0700_state *st = d->priv;
+ u8 b[3];
+ int ret;
+
+ if (st->fw_version >= 0x10201) {
+ b[0] = REQUEST_SET_USB_XFER_LEN;
+ b[1] = (nb_ts_packets >> 8) & 0xff;
+ b[2] = nb_ts_packets & 0xff;
+
+ deb_info("set the USB xfer len to %i Ts packet\n", nb_ts_packets);
+
+ ret = dib0700_ctrl_wr(d, b, sizeof(b));
+ } else {
+ deb_info("this firmware does not allow to change the USB xfer len\n");
+ ret = -EIO;
+ }
+
+ return ret;
}
/*
@@ -178,7 +175,8 @@ static int dib0700_i2c_xfer_new(struct i2c_adapter *adap, struct i2c_msg *msg,
value = ((en_start << 7) | (en_stop << 6) |
(msg[i].len & 0x3F)) << 8 | i2c_dest;
/* I2C ctrl + FE bus; */
- index = ((gen_mode<<6)&0xC0) | ((bus_mode<<4)&0x30);
+ index = ((gen_mode << 6) & 0xC0) |
+ ((bus_mode << 4) & 0x30);
result = usb_control_msg(d->udev,
usb_rcvctrlpipe(d->udev, 0),
@@ -198,11 +196,12 @@ static int dib0700_i2c_xfer_new(struct i2c_adapter *adap, struct i2c_msg *msg,
} else {
/* Write request */
buf[0] = REQUEST_NEW_I2C_WRITE;
- buf[1] = (msg[i].addr << 1);
+ buf[1] = msg[i].addr << 1;
buf[2] = (en_start << 7) | (en_stop << 6) |
(msg[i].len & 0x3F);
/* I2C ctrl + FE bus; */
- buf[3] = ((gen_mode<<6)&0xC0) | ((bus_mode<<4)&0x30);
+ buf[3] = ((gen_mode << 6) & 0xC0) |
+ ((bus_mode << 4) & 0x30);
/* The Actual i2c payload */
memcpy(&buf[4], msg[i].buf, msg[i].len);
@@ -240,7 +239,7 @@ static int dib0700_i2c_xfer_legacy(struct i2c_adapter *adap,
for (i = 0; i < num; i++) {
/* fill in the address */
- buf[1] = (msg[i].addr << 1);
+ buf[1] = msg[i].addr << 1;
/* fill the buffer */
memcpy(&buf[2], msg[i].buf, msg[i].len);
@@ -368,7 +367,8 @@ int dib0700_download_firmware(struct usb_device *udev, const struct firmware *fw
u8 buf[260];
while ((ret = dvb_usb_get_hexline(fw, &hx, &pos)) > 0) {
- deb_fwdata("writing to address 0x%08x (buffer: 0x%02x %02x)\n",hx.addr, hx.len, hx.chk);
+ deb_fwdata("writing to address 0x%08x (buffer: 0x%02x %02x)\n",
+ hx.addr, hx.len, hx.chk);
buf[0] = hx.len;
buf[1] = (hx.addr >> 8) & 0xff;
@@ -408,16 +408,16 @@ int dib0700_download_firmware(struct usb_device *udev, const struct firmware *fw
REQUEST_GET_VERSION,
USB_TYPE_VENDOR | USB_DIR_IN, 0, 0,
b, sizeof(b), USB_CTRL_GET_TIMEOUT);
- fw_version = (b[8] << 24) | (b[9] << 16) | (b[10] << 8) | b[11];
+ fw_version = (b[8] << 24) | (b[9] << 16) | (b[10] << 8) | b[11];
/* set the buffer size - DVB-USB is allocating URB buffers
* only after the firwmare download was successful */
for (i = 0; i < dib0700_device_count; i++) {
for (adap_num = 0; adap_num < dib0700_devices[i].num_adapters;
adap_num++) {
- if (fw_version >= 0x10201)
+ if (fw_version >= 0x10201) {
dib0700_devices[i].adapter[adap_num].stream.u.bulk.buffersize = 188*nb_packet_buffer_size;
- else {
+ } else {
/* for fw version older than 1.20.1,
* the buffersize has to be n times 512 */
dib0700_devices[i].adapter[adap_num].stream.u.bulk.buffersize = ((188*nb_packet_buffer_size+188/2)/512)*512;
@@ -453,7 +453,7 @@ int dib0700_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
if (st->disable_streaming_master_mode == 1)
b[2] = 0x00;
else
- b[2] = (0x01 << 4); /* Master mode */
+ b[2] = 0x01 << 4; /* Master mode */
b[3] = 0x00;
@@ -466,11 +466,44 @@ int dib0700_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
b[2] |= st->channel_state;
- deb_info("data for streaming: %x %x\n",b[1],b[2]);
+ deb_info("data for streaming: %x %x\n", b[1], b[2]);
return dib0700_ctrl_wr(adap->dev, b, 4);
}
+int dib0700_change_protocol(void *priv, u64 ir_type)
+{
+ struct dvb_usb_device *d = priv;
+ struct dib0700_state *st = d->priv;
+ u8 rc_setup[3] = { REQUEST_SET_RC, 0, 0 };
+ int new_proto, ret;
+
+ /* Set the IR mode */
+ if (ir_type == IR_TYPE_RC5)
+ new_proto = 1;
+ else if (ir_type == IR_TYPE_NEC)
+ new_proto = 0;
+ else if (ir_type == IR_TYPE_RC6) {
+ if (st->fw_version < 0x10200)
+ return -EINVAL;
+
+ new_proto = 2;
+ } else
+ return -EINVAL;
+
+ rc_setup[1] = new_proto;
+
+ ret = dib0700_ctrl_wr(d, rc_setup, sizeof(rc_setup));
+ if (ret < 0) {
+ err("ir protocol setup failed");
+ return ret;
+ }
+
+ d->props.rc.core.protocol = ir_type;
+
+ return ret;
+}
+
/* Number of keypresses to ignore before start repeating */
#define RC_REPEAT_DELAY_V1_20 10
@@ -478,7 +511,13 @@ int dib0700_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
struct dib0700_rc_response {
u8 report_id;
u8 data_state;
- u16 system;
+ union {
+ u16 system16;
+ struct {
+ u8 system;
+ u8 not_system;
+ };
+ };
u8 data;
u8 not_data;
};
@@ -487,14 +526,10 @@ struct dib0700_rc_response {
static void dib0700_rc_urb_completion(struct urb *purb)
{
struct dvb_usb_device *d = purb->context;
- struct dvb_usb_rc_key *keymap;
struct dib0700_state *st;
- struct dib0700_rc_response poll_reply;
- u8 *buf;
- int found = 0;
- u32 event;
- int state;
- int i;
+ struct dib0700_rc_response *poll_reply;
+ u32 uninitialized_var(keycode);
+ u8 toggle;
deb_info("%s()\n", __func__);
if (d == NULL)
@@ -506,9 +541,8 @@ static void dib0700_rc_urb_completion(struct urb *purb)
return;
}
- keymap = d->props.rc_key_map;
st = d->priv;
- buf = (u8 *)purb->transfer_buffer;
+ poll_reply = purb->transfer_buffer;
if (purb->status < 0) {
deb_info("discontinuing polling\n");
@@ -521,104 +555,52 @@ static void dib0700_rc_urb_completion(struct urb *purb)
goto resubmit;
}
- /* Set initial results in case we exit the function early */
- event = 0;
- state = REMOTE_NO_KEY_PRESSED;
-
- deb_data("IR raw %02X %02X %02X %02X %02X %02X (len %d)\n", buf[0],
- buf[1], buf[2], buf[3], buf[4], buf[5], purb->actual_length);
+ deb_data("IR ID = %02X state = %02X System = %02X %02X Cmd = %02X %02X (len %d)\n",
+ poll_reply->report_id, poll_reply->data_state,
+ poll_reply->system, poll_reply->not_system,
+ poll_reply->data, poll_reply->not_data,
+ purb->actual_length);
- switch (dvb_usb_dib0700_ir_proto) {
- case 0:
- /* NEC Protocol */
- poll_reply.report_id = 0;
- poll_reply.data_state = 1;
- poll_reply.system = buf[2];
- poll_reply.data = buf[4];
- poll_reply.not_data = buf[5];
+ switch (d->props.rc.core.protocol) {
+ case IR_TYPE_NEC:
+ toggle = 0;
/* NEC protocol sends repeat code as 0 0 0 FF */
- if ((poll_reply.system == 0x00) && (poll_reply.data == 0x00)
- && (poll_reply.not_data == 0xff)) {
- poll_reply.data_state = 2;
+ if ((poll_reply->system == 0x00) && (poll_reply->data == 0x00)
+ && (poll_reply->not_data == 0xff)) {
+ poll_reply->data_state = 2;
break;
}
+
+ if ((poll_reply->system ^ poll_reply->not_system) != 0xff) {
+ deb_data("NEC extended protocol\n");
+ /* NEC extended code - 24 bits */
+ keycode = poll_reply->system16 << 8 | poll_reply->data;
+ } else {
+ deb_data("NEC normal protocol\n");
+ /* normal NEC code - 16 bits */
+ keycode = poll_reply->system << 8 | poll_reply->data;
+ }
+
break;
default:
+ deb_data("RC5 protocol\n");
/* RC5 Protocol */
- poll_reply.report_id = buf[0];
- poll_reply.data_state = buf[1];
- poll_reply.system = (buf[2] << 8) | buf[3];
- poll_reply.data = buf[4];
- poll_reply.not_data = buf[5];
+ toggle = poll_reply->report_id;
+ keycode = poll_reply->system16 << 8 | poll_reply->data;
+
break;
}
- if ((poll_reply.data + poll_reply.not_data) != 0xff) {
+ if ((poll_reply->data + poll_reply->not_data) != 0xff) {
/* Key failed integrity check */
err("key failed integrity check: %04x %02x %02x",
- poll_reply.system,
- poll_reply.data, poll_reply.not_data);
- goto resubmit;
- }
-
- deb_data("rid=%02x ds=%02x sm=%04x d=%02x nd=%02x\n",
- poll_reply.report_id, poll_reply.data_state,
- poll_reply.system, poll_reply.data, poll_reply.not_data);
-
- /* Find the key in the map */
- for (i = 0; i < d->props.rc_key_map_size; i++) {
- if (rc5_custom(&keymap[i]) == (poll_reply.system & 0xff) &&
- rc5_data(&keymap[i]) == poll_reply.data) {
- event = keymap[i].event;
- found = 1;
- break;
- }
- }
-
- if (found == 0) {
- err("Unknown remote controller key: %04x %02x %02x",
- poll_reply.system, poll_reply.data, poll_reply.not_data);
- d->last_event = 0;
+ poll_reply->system,
+ poll_reply->data, poll_reply->not_data);
goto resubmit;
}
- if (poll_reply.data_state == 1) {
- /* New key hit */
- st->rc_counter = 0;
- event = keymap[i].event;
- state = REMOTE_KEY_PRESSED;
- d->last_event = keymap[i].event;
- } else if (poll_reply.data_state == 2) {
- /* Key repeated */
- st->rc_counter++;
-
- /* prevents unwanted double hits */
- if (st->rc_counter > RC_REPEAT_DELAY_V1_20) {
- event = d->last_event;
- state = REMOTE_KEY_PRESSED;
- st->rc_counter = RC_REPEAT_DELAY_V1_20;
- }
- } else {
- err("Unknown data state [%d]", poll_reply.data_state);
- }
-
- switch (state) {
- case REMOTE_NO_KEY_PRESSED:
- break;
- case REMOTE_KEY_PRESSED:
- deb_info("key pressed\n");
- d->last_event = event;
- case REMOTE_KEY_REPEAT:
- deb_info("key repeated\n");
- input_event(d->rc_input_dev, EV_KEY, event, 1);
- input_sync(d->rc_input_dev);
- input_event(d->rc_input_dev, EV_KEY, d->last_event, 0);
- input_sync(d->rc_input_dev);
- break;
- default:
- break;
- }
+ ir_keydown(d->rc_input_dev, keycode, toggle);
resubmit:
/* Clean the buffer before we requeue */
@@ -631,21 +613,10 @@ resubmit:
int dib0700_rc_setup(struct dvb_usb_device *d)
{
struct dib0700_state *st = d->priv;
- u8 rc_setup[3] = {REQUEST_SET_RC, dvb_usb_dib0700_ir_proto, 0};
struct urb *purb;
int ret;
- int i;
-
- if (d->props.rc_key_map == NULL)
- return 0;
-
- /* Set the IR mode */
- i = dib0700_ctrl_wr(d, rc_setup, 3);
- if (i<0) {
- err("ir protocol setup failed");
- return -1;
- }
+ /* Poll-based. Don't initialize bulk mode */
if (st->fw_version < 0x10200)
return 0;
@@ -653,14 +624,14 @@ int dib0700_rc_setup(struct dvb_usb_device *d)
purb = usb_alloc_urb(0, GFP_KERNEL);
if (purb == NULL) {
err("rc usb alloc urb failed\n");
- return -1;
+ return -ENOMEM;
}
purb->transfer_buffer = kzalloc(RC_MSG_SIZE_V1_20, GFP_KERNEL);
if (purb->transfer_buffer == NULL) {
err("rc kzalloc failed\n");
usb_free_urb(purb);
- return -1;
+ return -ENOMEM;
}
purb->status = -EINPROGRESS;
@@ -669,12 +640,10 @@ int dib0700_rc_setup(struct dvb_usb_device *d)
dib0700_rc_urb_completion, d);
ret = usb_submit_urb(purb, GFP_ATOMIC);
- if (ret != 0) {
+ if (ret)
err("rc submit urb failed\n");
- return -1;
- }
- return 0;
+ return ret;
}
static int dib0700_probe(struct usb_interface *intf,
@@ -698,6 +667,15 @@ static int dib0700_probe(struct usb_interface *intf,
st->fw_version = fw_version;
st->nb_packet_buffer_size = (u32)nb_packet_buffer_size;
+ /* Disable polling mode on newer firmwares */
+ if (st->fw_version >= 0x10200)
+ dev->props.rc.core.bulk_mode = true;
+ else
+ dev->props.rc.core.bulk_mode = false;
+
+ /* Need a higher delay, to avoid wrong repeat */
+ dev->rc_input_dev->rep[REP_DELAY] = 500;
+
dib0700_rc_setup(dev);
return 0;
diff --git a/drivers/media/dvb/dvb-usb/dib0700_devices.c b/drivers/media/dvb/dvb-usb/dib0700_devices.c
index 800800a9649..f634d2e784b 100644
--- a/drivers/media/dvb/dvb-usb/dib0700_devices.c
+++ b/drivers/media/dvb/dvb-usb/dib0700_devices.c
@@ -473,16 +473,19 @@ static u8 rc_request[] = { REQUEST_POLL_RC, 0 };
/* Number of keypresses to ignore before start repeating */
#define RC_REPEAT_DELAY 6
-static int dib0700_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
+/*
+ * This function is used only when firmware is < 1.20 version. Newer
+ * firmwares use bulk mode, with functions implemented at dib0700_core,
+ * at dib0700_rc_urb_completion()
+ */
+static int dib0700_rc_query_old_firmware(struct dvb_usb_device *d)
{
u8 key[4];
+ u32 keycode;
+ u8 toggle;
int i;
- struct dvb_usb_rc_key *keymap = d->props.rc_key_map;
struct dib0700_state *st = d->priv;
- *event = 0;
- *state = REMOTE_NO_KEY_PRESSED;
-
if (st->fw_version >= 0x10200) {
/* For 1.20 firmware , We need to keep the RC polling
callback so we can reuse the input device setup in
@@ -491,348 +494,45 @@ static int dib0700_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
return 0;
}
- i=dib0700_ctrl_rd(d,rc_request,2,key,4);
- if (i<=0) {
+ i = dib0700_ctrl_rd(d, rc_request, 2, key, 4);
+ if (i <= 0) {
err("RC Query Failed");
return -1;
}
/* losing half of KEY_0 events from Philipps rc5 remotes.. */
- if (key[0]==0 && key[1]==0 && key[2]==0 && key[3]==0) return 0;
+ if (key[0] == 0 && key[1] == 0 && key[2] == 0 && key[3] == 0)
+ return 0;
/* info("%d: %2X %2X %2X %2X",dvb_usb_dib0700_ir_proto,(int)key[3-2],(int)key[3-3],(int)key[3-1],(int)key[3]); */
dib0700_rc_setup(d); /* reset ir sensor data to prevent false events */
- switch (dvb_usb_dib0700_ir_proto) {
- case 0: {
+ d->last_event = 0;
+ switch (d->props.rc.core.protocol) {
+ case IR_TYPE_NEC:
/* NEC protocol sends repeat code as 0 0 0 FF */
if ((key[3-2] == 0x00) && (key[3-3] == 0x00) &&
- (key[3] == 0xFF)) {
- st->rc_counter++;
- if (st->rc_counter > RC_REPEAT_DELAY) {
- *event = d->last_event;
- *state = REMOTE_KEY_PRESSED;
- st->rc_counter = RC_REPEAT_DELAY;
- }
- return 0;
- }
- for (i=0;i<d->props.rc_key_map_size; i++) {
- if (rc5_custom(&keymap[i]) == key[3-2] &&
- rc5_data(&keymap[i]) == key[3-3]) {
- st->rc_counter = 0;
- *event = keymap[i].event;
- *state = REMOTE_KEY_PRESSED;
- d->last_event = keymap[i].event;
- return 0;
- }
+ (key[3] == 0xff))
+ keycode = d->last_event;
+ else {
+ keycode = key[3-2] << 8 | key[3-3];
+ d->last_event = keycode;
}
+
+ ir_keydown(d->rc_input_dev, keycode, 0);
break;
- }
- default: {
+ default:
/* RC-5 protocol changes toggle bit on new keypress */
- for (i = 0; i < d->props.rc_key_map_size; i++) {
- if (rc5_custom(&keymap[i]) == key[3-2] &&
- rc5_data(&keymap[i]) == key[3-3]) {
- if (d->last_event == keymap[i].event &&
- key[3-1] == st->rc_toggle) {
- st->rc_counter++;
- /* prevents unwanted double hits */
- if (st->rc_counter > RC_REPEAT_DELAY) {
- *event = d->last_event;
- *state = REMOTE_KEY_PRESSED;
- st->rc_counter = RC_REPEAT_DELAY;
- }
-
- return 0;
- }
- st->rc_counter = 0;
- *event = keymap[i].event;
- *state = REMOTE_KEY_PRESSED;
- st->rc_toggle = key[3-1];
- d->last_event = keymap[i].event;
- return 0;
- }
- }
+ keycode = key[3-2] << 8 | key[3-3];
+ toggle = key[3-1];
+ ir_keydown(d->rc_input_dev, keycode, toggle);
+
break;
}
- }
- err("Unknown remote controller key: %2X %2X %2X %2X", (int) key[3-2], (int) key[3-3], (int) key[3-1], (int) key[3]);
- d->last_event = 0;
return 0;
}
-static struct dvb_usb_rc_key ir_codes_dib0700_table[] = {
- /* Key codes for the tiny Pinnacle remote*/
- { 0x0700, KEY_MUTE },
- { 0x0701, KEY_MENU }, /* Pinnacle logo */
- { 0x0739, KEY_POWER },
- { 0x0703, KEY_VOLUMEUP },
- { 0x0709, KEY_VOLUMEDOWN },
- { 0x0706, KEY_CHANNELUP },
- { 0x070c, KEY_CHANNELDOWN },
- { 0x070f, KEY_1 },
- { 0x0715, KEY_2 },
- { 0x0710, KEY_3 },
- { 0x0718, KEY_4 },
- { 0x071b, KEY_5 },
- { 0x071e, KEY_6 },
- { 0x0711, KEY_7 },
- { 0x0721, KEY_8 },
- { 0x0712, KEY_9 },
- { 0x0727, KEY_0 },
- { 0x0724, KEY_SCREEN }, /* 'Square' key */
- { 0x072a, KEY_TEXT }, /* 'T' key */
- { 0x072d, KEY_REWIND },
- { 0x0730, KEY_PLAY },
- { 0x0733, KEY_FASTFORWARD },
- { 0x0736, KEY_RECORD },
- { 0x073c, KEY_STOP },
- { 0x073f, KEY_CANCEL }, /* '?' key */
- /* Key codes for the Terratec Cinergy DT XS Diversity, similar to cinergyT2.c */
- { 0xeb01, KEY_POWER },
- { 0xeb02, KEY_1 },
- { 0xeb03, KEY_2 },
- { 0xeb04, KEY_3 },
- { 0xeb05, KEY_4 },
- { 0xeb06, KEY_5 },
- { 0xeb07, KEY_6 },
- { 0xeb08, KEY_7 },
- { 0xeb09, KEY_8 },
- { 0xeb0a, KEY_9 },
- { 0xeb0b, KEY_VIDEO },
- { 0xeb0c, KEY_0 },
- { 0xeb0d, KEY_REFRESH },
- { 0xeb0f, KEY_EPG },
- { 0xeb10, KEY_UP },
- { 0xeb11, KEY_LEFT },
- { 0xeb12, KEY_OK },
- { 0xeb13, KEY_RIGHT },
- { 0xeb14, KEY_DOWN },
- { 0xeb16, KEY_INFO },
- { 0xeb17, KEY_RED },
- { 0xeb18, KEY_GREEN },
- { 0xeb19, KEY_YELLOW },
- { 0xeb1a, KEY_BLUE },
- { 0xeb1b, KEY_CHANNELUP },
- { 0xeb1c, KEY_VOLUMEUP },
- { 0xeb1d, KEY_MUTE },
- { 0xeb1e, KEY_VOLUMEDOWN },
- { 0xeb1f, KEY_CHANNELDOWN },
- { 0xeb40, KEY_PAUSE },
- { 0xeb41, KEY_HOME },
- { 0xeb42, KEY_MENU }, /* DVD Menu */
- { 0xeb43, KEY_SUBTITLE },
- { 0xeb44, KEY_TEXT }, /* Teletext */
- { 0xeb45, KEY_DELETE },
- { 0xeb46, KEY_TV },
- { 0xeb47, KEY_DVD },
- { 0xeb48, KEY_STOP },
- { 0xeb49, KEY_VIDEO },
- { 0xeb4a, KEY_AUDIO }, /* Music */
- { 0xeb4b, KEY_SCREEN }, /* Pic */
- { 0xeb4c, KEY_PLAY },
- { 0xeb4d, KEY_BACK },
- { 0xeb4e, KEY_REWIND },
- { 0xeb4f, KEY_FASTFORWARD },
- { 0xeb54, KEY_PREVIOUS },
- { 0xeb58, KEY_RECORD },
- { 0xeb5c, KEY_NEXT },
-
- /* Key codes for the Haupauge WinTV Nova-TD, copied from nova-t-usb2.c (Nova-T USB2) */
- { 0x1e00, KEY_0 },
- { 0x1e01, KEY_1 },
- { 0x1e02, KEY_2 },
- { 0x1e03, KEY_3 },
- { 0x1e04, KEY_4 },
- { 0x1e05, KEY_5 },
- { 0x1e06, KEY_6 },
- { 0x1e07, KEY_7 },
- { 0x1e08, KEY_8 },
- { 0x1e09, KEY_9 },
- { 0x1e0a, KEY_KPASTERISK },
- { 0x1e0b, KEY_RED },
- { 0x1e0c, KEY_RADIO },
- { 0x1e0d, KEY_MENU },
- { 0x1e0e, KEY_GRAVE }, /* # */
- { 0x1e0f, KEY_MUTE },
- { 0x1e10, KEY_VOLUMEUP },
- { 0x1e11, KEY_VOLUMEDOWN },
- { 0x1e12, KEY_CHANNEL },
- { 0x1e14, KEY_UP },
- { 0x1e15, KEY_DOWN },
- { 0x1e16, KEY_LEFT },
- { 0x1e17, KEY_RIGHT },
- { 0x1e18, KEY_VIDEO },
- { 0x1e19, KEY_AUDIO },
- { 0x1e1a, KEY_MEDIA },
- { 0x1e1b, KEY_EPG },
- { 0x1e1c, KEY_TV },
- { 0x1e1e, KEY_NEXT },
- { 0x1e1f, KEY_BACK },
- { 0x1e20, KEY_CHANNELUP },
- { 0x1e21, KEY_CHANNELDOWN },
- { 0x1e24, KEY_LAST }, /* Skip backwards */
- { 0x1e25, KEY_OK },
- { 0x1e29, KEY_BLUE},
- { 0x1e2e, KEY_GREEN },
- { 0x1e30, KEY_PAUSE },
- { 0x1e32, KEY_REWIND },
- { 0x1e34, KEY_FASTFORWARD },
- { 0x1e35, KEY_PLAY },
- { 0x1e36, KEY_STOP },
- { 0x1e37, KEY_RECORD },
- { 0x1e38, KEY_YELLOW },
- { 0x1e3b, KEY_GOTO },
- { 0x1e3d, KEY_POWER },
-
- /* Key codes for the Leadtek Winfast DTV Dongle */
- { 0x0042, KEY_POWER },
- { 0x077c, KEY_TUNER },
- { 0x0f4e, KEY_PRINT }, /* PREVIEW */
- { 0x0840, KEY_SCREEN }, /* full screen toggle*/
- { 0x0f71, KEY_DOT }, /* frequency */
- { 0x0743, KEY_0 },
- { 0x0c41, KEY_1 },
- { 0x0443, KEY_2 },
- { 0x0b7f, KEY_3 },
- { 0x0e41, KEY_4 },
- { 0x0643, KEY_5 },
- { 0x097f, KEY_6 },
- { 0x0d7e, KEY_7 },
- { 0x057c, KEY_8 },
- { 0x0a40, KEY_9 },
- { 0x0e4e, KEY_CLEAR },
- { 0x047c, KEY_CHANNEL }, /* show channel number */
- { 0x0f41, KEY_LAST }, /* recall */
- { 0x0342, KEY_MUTE },
- { 0x064c, KEY_RESERVED }, /* PIP button*/
- { 0x0172, KEY_SHUFFLE }, /* SNAPSHOT */
- { 0x0c4e, KEY_PLAYPAUSE }, /* TIMESHIFT */
- { 0x0b70, KEY_RECORD },
- { 0x037d, KEY_VOLUMEUP },
- { 0x017d, KEY_VOLUMEDOWN },
- { 0x0242, KEY_CHANNELUP },
- { 0x007d, KEY_CHANNELDOWN },
-
- /* Key codes for Nova-TD "credit card" remote control. */
- { 0x1d00, KEY_0 },
- { 0x1d01, KEY_1 },
- { 0x1d02, KEY_2 },
- { 0x1d03, KEY_3 },
- { 0x1d04, KEY_4 },
- { 0x1d05, KEY_5 },
- { 0x1d06, KEY_6 },
- { 0x1d07, KEY_7 },
- { 0x1d08, KEY_8 },
- { 0x1d09, KEY_9 },
- { 0x1d0a, KEY_TEXT },
- { 0x1d0d, KEY_MENU },
- { 0x1d0f, KEY_MUTE },
- { 0x1d10, KEY_VOLUMEUP },
- { 0x1d11, KEY_VOLUMEDOWN },
- { 0x1d12, KEY_CHANNEL },
- { 0x1d14, KEY_UP },
- { 0x1d15, KEY_DOWN },
- { 0x1d16, KEY_LEFT },
- { 0x1d17, KEY_RIGHT },
- { 0x1d1c, KEY_TV },
- { 0x1d1e, KEY_NEXT },
- { 0x1d1f, KEY_BACK },
- { 0x1d20, KEY_CHANNELUP },
- { 0x1d21, KEY_CHANNELDOWN },
- { 0x1d24, KEY_LAST },
- { 0x1d25, KEY_OK },
- { 0x1d30, KEY_PAUSE },
- { 0x1d32, KEY_REWIND },
- { 0x1d34, KEY_FASTFORWARD },
- { 0x1d35, KEY_PLAY },
- { 0x1d36, KEY_STOP },
- { 0x1d37, KEY_RECORD },
- { 0x1d3b, KEY_GOTO },
- { 0x1d3d, KEY_POWER },
-
- /* Key codes for the Pixelview SBTVD remote (proto NEC) */
- { 0x8613, KEY_MUTE },
- { 0x8612, KEY_POWER },
- { 0x8601, KEY_1 },
- { 0x8602, KEY_2 },
- { 0x8603, KEY_3 },
- { 0x8604, KEY_4 },
- { 0x8605, KEY_5 },
- { 0x8606, KEY_6 },
- { 0x8607, KEY_7 },
- { 0x8608, KEY_8 },
- { 0x8609, KEY_9 },
- { 0x8600, KEY_0 },
- { 0x860d, KEY_CHANNELUP },
- { 0x8619, KEY_CHANNELDOWN },
- { 0x8610, KEY_VOLUMEUP },
- { 0x860c, KEY_VOLUMEDOWN },
-
- { 0x860a, KEY_CAMERA },
- { 0x860b, KEY_ZOOM },
- { 0x861b, KEY_BACKSPACE },
- { 0x8615, KEY_ENTER },
-
- { 0x861d, KEY_UP },
- { 0x861e, KEY_DOWN },
- { 0x860e, KEY_LEFT },
- { 0x860f, KEY_RIGHT },
-
- { 0x8618, KEY_RECORD },
- { 0x861a, KEY_STOP },
-
- /* Key codes for the EvolutePC TVWay+ remote (proto NEC) */
- { 0x7a00, KEY_MENU },
- { 0x7a01, KEY_RECORD },
- { 0x7a02, KEY_PLAY },
- { 0x7a03, KEY_STOP },
- { 0x7a10, KEY_CHANNELUP },
- { 0x7a11, KEY_CHANNELDOWN },
- { 0x7a12, KEY_VOLUMEUP },
- { 0x7a13, KEY_VOLUMEDOWN },
- { 0x7a40, KEY_POWER },
- { 0x7a41, KEY_MUTE },
-
- /* Key codes for the Elgato EyeTV Diversity silver remote,
- set dvb_usb_dib0700_ir_proto=0 */
- { 0x4501, KEY_POWER },
- { 0x4502, KEY_MUTE },
- { 0x4503, KEY_1 },
- { 0x4504, KEY_2 },
- { 0x4505, KEY_3 },
- { 0x4506, KEY_4 },
- { 0x4507, KEY_5 },
- { 0x4508, KEY_6 },
- { 0x4509, KEY_7 },
- { 0x450a, KEY_8 },
- { 0x450b, KEY_9 },
- { 0x450c, KEY_LAST },
- { 0x450d, KEY_0 },
- { 0x450e, KEY_ENTER },
- { 0x450f, KEY_RED },
- { 0x4510, KEY_CHANNELUP },
- { 0x4511, KEY_GREEN },
- { 0x4512, KEY_VOLUMEDOWN },
- { 0x4513, KEY_OK },
- { 0x4514, KEY_VOLUMEUP },
- { 0x4515, KEY_YELLOW },
- { 0x4516, KEY_CHANNELDOWN },
- { 0x4517, KEY_BLUE },
- { 0x4518, KEY_LEFT }, /* Skip backwards */
- { 0x4519, KEY_PLAYPAUSE },
- { 0x451a, KEY_RIGHT }, /* Skip forward */
- { 0x451b, KEY_REWIND },
- { 0x451c, KEY_L }, /* Live */
- { 0x451d, KEY_FASTFORWARD },
- { 0x451e, KEY_STOP }, /* 'Reveal' for Teletext */
- { 0x451f, KEY_MENU }, /* KEY_TEXT for Teletext */
- { 0x4540, KEY_RECORD }, /* Font 'Size' for Teletext */
- { 0x4541, KEY_SCREEN }, /* Full screen toggle, 'Hold' for Teletext */
- { 0x4542, KEY_SELECT }, /* Select video input, 'Select' for Teletext */
-};
-
/* STK7700P: Hauppauge Nova-T Stick, AVerMedia Volar */
static struct dibx000_agc_config stk7700p_7000m_mt2060_agc_config = {
BAND_UHF | BAND_VHF,
@@ -2168,10 +1868,17 @@ struct dvb_usb_device_properties dib0700_devices[] = {
}
},
- .rc_interval = DEFAULT_RC_INTERVAL,
- .rc_key_map = ir_codes_dib0700_table,
- .rc_key_map_size = ARRAY_SIZE(ir_codes_dib0700_table),
- .rc_query = dib0700_rc_query
+ .rc.core = {
+ .rc_interval = DEFAULT_RC_INTERVAL,
+ .rc_codes = RC_MAP_DIB0700_RC5_TABLE,
+ .rc_query = dib0700_rc_query_old_firmware,
+ .rc_props = {
+ .allowed_protos = IR_TYPE_RC5 |
+ IR_TYPE_RC6 |
+ IR_TYPE_NEC,
+ .change_protocol = dib0700_change_protocol,
+ },
+ },
}, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
.num_adapters = 2,
@@ -2197,10 +1904,17 @@ struct dvb_usb_device_properties dib0700_devices[] = {
},
},
- .rc_interval = DEFAULT_RC_INTERVAL,
- .rc_key_map = ir_codes_dib0700_table,
- .rc_key_map_size = ARRAY_SIZE(ir_codes_dib0700_table),
- .rc_query = dib0700_rc_query
+ .rc.core = {
+ .rc_interval = DEFAULT_RC_INTERVAL,
+ .rc_codes = RC_MAP_DIB0700_RC5_TABLE,
+ .rc_query = dib0700_rc_query_old_firmware,
+ .rc_props = {
+ .allowed_protos = IR_TYPE_RC5 |
+ IR_TYPE_RC6 |
+ IR_TYPE_NEC,
+ .change_protocol = dib0700_change_protocol,
+ },
+ },
}, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
.num_adapters = 2,
@@ -2251,11 +1965,17 @@ struct dvb_usb_device_properties dib0700_devices[] = {
},
- .rc_interval = DEFAULT_RC_INTERVAL,
- .rc_key_map = ir_codes_dib0700_table,
- .rc_key_map_size = ARRAY_SIZE(ir_codes_dib0700_table),
- .rc_query = dib0700_rc_query
-
+ .rc.core = {
+ .rc_interval = DEFAULT_RC_INTERVAL,
+ .rc_codes = RC_MAP_DIB0700_RC5_TABLE,
+ .rc_query = dib0700_rc_query_old_firmware,
+ .rc_props = {
+ .allowed_protos = IR_TYPE_RC5 |
+ IR_TYPE_RC6 |
+ IR_TYPE_NEC,
+ .change_protocol = dib0700_change_protocol,
+ },
+ },
}, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
.num_adapters = 1,
@@ -2288,10 +2008,18 @@ struct dvb_usb_device_properties dib0700_devices[] = {
}
},
- .rc_interval = DEFAULT_RC_INTERVAL,
- .rc_key_map = ir_codes_dib0700_table,
- .rc_key_map_size = ARRAY_SIZE(ir_codes_dib0700_table),
- .rc_query = dib0700_rc_query
+ .rc.core = {
+ .rc_interval = DEFAULT_RC_INTERVAL,
+ .rc_codes = RC_MAP_DIB0700_RC5_TABLE,
+ .module_name = "dib0700",
+ .rc_query = dib0700_rc_query_old_firmware,
+ .rc_props = {
+ .allowed_protos = IR_TYPE_RC5 |
+ IR_TYPE_RC6 |
+ IR_TYPE_NEC,
+ .change_protocol = dib0700_change_protocol,
+ },
+ },
}, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
.num_adapters = 1,
@@ -2358,11 +2086,18 @@ struct dvb_usb_device_properties dib0700_devices[] = {
},
},
- .rc_interval = DEFAULT_RC_INTERVAL,
- .rc_key_map = ir_codes_dib0700_table,
- .rc_key_map_size = ARRAY_SIZE(ir_codes_dib0700_table),
- .rc_query = dib0700_rc_query
-
+ .rc.core = {
+ .rc_interval = DEFAULT_RC_INTERVAL,
+ .rc_codes = RC_MAP_DIB0700_RC5_TABLE,
+ .module_name = "dib0700",
+ .rc_query = dib0700_rc_query_old_firmware,
+ .rc_props = {
+ .allowed_protos = IR_TYPE_RC5 |
+ IR_TYPE_RC6 |
+ IR_TYPE_NEC,
+ .change_protocol = dib0700_change_protocol,
+ },
+ },
}, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
.num_adapters = 1,
@@ -2397,11 +2132,18 @@ struct dvb_usb_device_properties dib0700_devices[] = {
},
},
- .rc_interval = DEFAULT_RC_INTERVAL,
- .rc_key_map = ir_codes_dib0700_table,
- .rc_key_map_size = ARRAY_SIZE(ir_codes_dib0700_table),
- .rc_query = dib0700_rc_query
-
+ .rc.core = {
+ .rc_interval = DEFAULT_RC_INTERVAL,
+ .rc_codes = RC_MAP_DIB0700_RC5_TABLE,
+ .module_name = "dib0700",
+ .rc_query = dib0700_rc_query_old_firmware,
+ .rc_props = {
+ .allowed_protos = IR_TYPE_RC5 |
+ IR_TYPE_RC6 |
+ IR_TYPE_NEC,
+ .change_protocol = dib0700_change_protocol,
+ },
+ },
}, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
.num_adapters = 2,
@@ -2431,7 +2173,7 @@ struct dvb_usb_device_properties dib0700_devices[] = {
}
},
- .num_device_descs = 7,
+ .num_device_descs = 6,
.devices = {
{ "DiBcom STK7070PD reference design",
{ &dib0700_usb_id_table[17], NULL },
@@ -2458,15 +2200,69 @@ struct dvb_usb_device_properties dib0700_devices[] = {
{ &dib0700_usb_id_table[44], NULL },
{ NULL },
},
+ },
+
+ .rc.core = {
+ .rc_interval = DEFAULT_RC_INTERVAL,
+ .rc_codes = RC_MAP_DIB0700_RC5_TABLE,
+ .module_name = "dib0700",
+ .rc_query = dib0700_rc_query_old_firmware,
+ .rc_props = {
+ .allowed_protos = IR_TYPE_RC5 |
+ IR_TYPE_RC6 |
+ IR_TYPE_NEC,
+ .change_protocol = dib0700_change_protocol,
+ },
+ },
+ }, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
+
+ .num_adapters = 2,
+ .adapter = {
+ {
+ .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
+ .pid_filter_count = 32,
+ .pid_filter = stk70x0p_pid_filter,
+ .pid_filter_ctrl = stk70x0p_pid_filter_ctrl,
+ .frontend_attach = stk7070pd_frontend_attach0,
+ .tuner_attach = dib7070p_tuner_attach,
+
+ DIB0700_DEFAULT_STREAMING_CONFIG(0x02),
+
+ .size_of_priv = sizeof(struct dib0700_adapter_state),
+ }, {
+ .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
+ .pid_filter_count = 32,
+ .pid_filter = stk70x0p_pid_filter,
+ .pid_filter_ctrl = stk70x0p_pid_filter_ctrl,
+ .frontend_attach = stk7070pd_frontend_attach1,
+ .tuner_attach = dib7070p_tuner_attach,
+
+ DIB0700_DEFAULT_STREAMING_CONFIG(0x03),
+
+ .size_of_priv = sizeof(struct dib0700_adapter_state),
+ }
+ },
+
+ .num_device_descs = 1,
+ .devices = {
{ "Elgato EyeTV Diversity",
{ &dib0700_usb_id_table[68], NULL },
{ NULL },
},
},
- .rc_interval = DEFAULT_RC_INTERVAL,
- .rc_key_map = ir_codes_dib0700_table,
- .rc_key_map_size = ARRAY_SIZE(ir_codes_dib0700_table),
- .rc_query = dib0700_rc_query
+
+ .rc.core = {
+ .rc_interval = DEFAULT_RC_INTERVAL,
+ .rc_codes = RC_MAP_DIB0700_NEC_TABLE,
+ .module_name = "dib0700",
+ .rc_query = dib0700_rc_query_old_firmware,
+ .rc_props = {
+ .allowed_protos = IR_TYPE_RC5 |
+ IR_TYPE_RC6 |
+ IR_TYPE_NEC,
+ .change_protocol = dib0700_change_protocol,
+ },
+ },
}, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
.num_adapters = 1,
@@ -2525,10 +2321,19 @@ struct dvb_usb_device_properties dib0700_devices[] = {
{ NULL },
},
},
- .rc_interval = DEFAULT_RC_INTERVAL,
- .rc_key_map = ir_codes_dib0700_table,
- .rc_key_map_size = ARRAY_SIZE(ir_codes_dib0700_table),
- .rc_query = dib0700_rc_query
+
+ .rc.core = {
+ .rc_interval = DEFAULT_RC_INTERVAL,
+ .rc_codes = RC_MAP_DIB0700_RC5_TABLE,
+ .module_name = "dib0700",
+ .rc_query = dib0700_rc_query_old_firmware,
+ .rc_props = {
+ .allowed_protos = IR_TYPE_RC5 |
+ IR_TYPE_RC6 |
+ IR_TYPE_NEC,
+ .change_protocol = dib0700_change_protocol,
+ },
+ },
}, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
.num_adapters = 1,
.adapter = {
@@ -2554,10 +2359,19 @@ struct dvb_usb_device_properties dib0700_devices[] = {
{ NULL },
},
},
- .rc_interval = DEFAULT_RC_INTERVAL,
- .rc_key_map = ir_codes_dib0700_table,
- .rc_key_map_size = ARRAY_SIZE(ir_codes_dib0700_table),
- .rc_query = dib0700_rc_query
+
+ .rc.core = {
+ .rc_interval = DEFAULT_RC_INTERVAL,
+ .rc_codes = RC_MAP_DIB0700_RC5_TABLE,
+ .module_name = "dib0700",
+ .rc_query = dib0700_rc_query_old_firmware,
+ .rc_props = {
+ .allowed_protos = IR_TYPE_RC5 |
+ IR_TYPE_RC6 |
+ IR_TYPE_NEC,
+ .change_protocol = dib0700_change_protocol,
+ },
+ },
}, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
.num_adapters = 1,
.adapter = {
@@ -2615,10 +2429,19 @@ struct dvb_usb_device_properties dib0700_devices[] = {
{ NULL },
},
},
- .rc_interval = DEFAULT_RC_INTERVAL,
- .rc_key_map = ir_codes_dib0700_table,
- .rc_key_map_size = ARRAY_SIZE(ir_codes_dib0700_table),
- .rc_query = dib0700_rc_query
+
+ .rc.core = {
+ .rc_interval = DEFAULT_RC_INTERVAL,
+ .rc_codes = RC_MAP_DIB0700_RC5_TABLE,
+ .module_name = "dib0700",
+ .rc_query = dib0700_rc_query_old_firmware,
+ .rc_props = {
+ .allowed_protos = IR_TYPE_RC5 |
+ IR_TYPE_RC6 |
+ IR_TYPE_NEC,
+ .change_protocol = dib0700_change_protocol,
+ },
+ },
}, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
.num_adapters = 1,
.adapter = {
@@ -2653,11 +2476,18 @@ struct dvb_usb_device_properties dib0700_devices[] = {
},
},
- .rc_interval = DEFAULT_RC_INTERVAL,
- .rc_key_map = ir_codes_dib0700_table,
- .rc_key_map_size = ARRAY_SIZE(ir_codes_dib0700_table),
- .rc_query = dib0700_rc_query
-
+ .rc.core = {
+ .rc_interval = DEFAULT_RC_INTERVAL,
+ .rc_codes = RC_MAP_DIB0700_NEC_TABLE,
+ .module_name = "dib0700",
+ .rc_query = dib0700_rc_query_old_firmware,
+ .rc_props = {
+ .allowed_protos = IR_TYPE_RC5 |
+ IR_TYPE_RC6 |
+ IR_TYPE_NEC,
+ .change_protocol = dib0700_change_protocol,
+ },
+ },
}, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
.num_adapters = 2,
.adapter = {
@@ -2697,10 +2527,18 @@ struct dvb_usb_device_properties dib0700_devices[] = {
},
},
- .rc_interval = DEFAULT_RC_INTERVAL,
- .rc_key_map = ir_codes_dib0700_table,
- .rc_key_map_size = ARRAY_SIZE(ir_codes_dib0700_table),
- .rc_query = dib0700_rc_query
+ .rc.core = {
+ .rc_interval = DEFAULT_RC_INTERVAL,
+ .rc_codes = RC_MAP_DIB0700_RC5_TABLE,
+ .module_name = "dib0700",
+ .rc_query = dib0700_rc_query_old_firmware,
+ .rc_props = {
+ .allowed_protos = IR_TYPE_RC5 |
+ IR_TYPE_RC6 |
+ IR_TYPE_NEC,
+ .change_protocol = dib0700_change_protocol,
+ },
+ },
}, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
.num_adapters = 1,
.adapter = {
@@ -2728,10 +2566,18 @@ struct dvb_usb_device_properties dib0700_devices[] = {
},
},
- .rc_interval = DEFAULT_RC_INTERVAL,
- .rc_key_map = ir_codes_dib0700_table,
- .rc_key_map_size = ARRAY_SIZE(ir_codes_dib0700_table),
- .rc_query = dib0700_rc_query
+ .rc.core = {
+ .rc_interval = DEFAULT_RC_INTERVAL,
+ .rc_codes = RC_MAP_DIB0700_RC5_TABLE,
+ .module_name = "dib0700",
+ .rc_query = dib0700_rc_query_old_firmware,
+ .rc_props = {
+ .allowed_protos = IR_TYPE_RC5 |
+ IR_TYPE_RC6 |
+ IR_TYPE_NEC,
+ .change_protocol = dib0700_change_protocol,
+ },
+ },
},
};
diff --git a/drivers/media/dvb/dvb-usb/dibusb-common.c b/drivers/media/dvb/dvb-usb/dibusb-common.c
index bc08bc0b723..ba991aa21af 100644
--- a/drivers/media/dvb/dvb-usb/dibusb-common.c
+++ b/drivers/media/dvb/dvb-usb/dibusb-common.c
@@ -327,7 +327,7 @@ EXPORT_SYMBOL(dibusb_dib3000mc_tuner_attach);
/*
* common remote control stuff
*/
-struct dvb_usb_rc_key ir_codes_dibusb_table[] = {
+struct ir_scancode ir_codes_dibusb_table[] = {
/* Key codes for the little Artec T1/Twinhan/HAMA/ remote. */
{ 0x0016, KEY_POWER },
{ 0x0010, KEY_MUTE },
diff --git a/drivers/media/dvb/dvb-usb/dibusb-mb.c b/drivers/media/dvb/dvb-usb/dibusb-mb.c
index eb2e6f050fb..8e3c0d2cce1 100644
--- a/drivers/media/dvb/dvb-usb/dibusb-mb.c
+++ b/drivers/media/dvb/dvb-usb/dibusb-mb.c
@@ -211,10 +211,12 @@ static struct dvb_usb_device_properties dibusb1_1_properties = {
.power_ctrl = dibusb_power_ctrl,
- .rc_interval = DEFAULT_RC_INTERVAL,
- .rc_key_map = ir_codes_dibusb_table,
- .rc_key_map_size = 111, /* wow, that is ugly ... I want to load it to the driver dynamically */
- .rc_query = dibusb_rc_query,
+ .rc.legacy = {
+ .rc_interval = DEFAULT_RC_INTERVAL,
+ .rc_key_map = ir_codes_dibusb_table,
+ .rc_key_map_size = 111, /* wow, that is ugly ... I want to load it to the driver dynamically */
+ .rc_query = dibusb_rc_query,
+ },
.i2c_algo = &dibusb_i2c_algo,
@@ -295,10 +297,12 @@ static struct dvb_usb_device_properties dibusb1_1_an2235_properties = {
},
.power_ctrl = dibusb_power_ctrl,
- .rc_interval = DEFAULT_RC_INTERVAL,
- .rc_key_map = ir_codes_dibusb_table,
- .rc_key_map_size = 111, /* wow, that is ugly ... I want to load it to the driver dynamically */
- .rc_query = dibusb_rc_query,
+ .rc.legacy = {
+ .rc_interval = DEFAULT_RC_INTERVAL,
+ .rc_key_map = ir_codes_dibusb_table,
+ .rc_key_map_size = 111, /* wow, that is ugly ... I want to load it to the driver dynamically */
+ .rc_query = dibusb_rc_query,
+ },
.i2c_algo = &dibusb_i2c_algo,
@@ -359,10 +363,12 @@ static struct dvb_usb_device_properties dibusb2_0b_properties = {
},
.power_ctrl = dibusb2_0_power_ctrl,
- .rc_interval = DEFAULT_RC_INTERVAL,
- .rc_key_map = ir_codes_dibusb_table,
- .rc_key_map_size = 111, /* wow, that is ugly ... I want to load it to the driver dynamically */
- .rc_query = dibusb_rc_query,
+ .rc.legacy = {
+ .rc_interval = DEFAULT_RC_INTERVAL,
+ .rc_key_map = ir_codes_dibusb_table,
+ .rc_key_map_size = 111, /* wow, that is ugly ... I want to load it to the driver dynamically */
+ .rc_query = dibusb_rc_query,
+ },
.i2c_algo = &dibusb_i2c_algo,
@@ -416,10 +422,12 @@ static struct dvb_usb_device_properties artec_t1_usb2_properties = {
},
.power_ctrl = dibusb2_0_power_ctrl,
- .rc_interval = DEFAULT_RC_INTERVAL,
- .rc_key_map = ir_codes_dibusb_table,
- .rc_key_map_size = 111, /* wow, that is ugly ... I want to load it to the driver dynamically */
- .rc_query = dibusb_rc_query,
+ .rc.legacy = {
+ .rc_interval = DEFAULT_RC_INTERVAL,
+ .rc_key_map = ir_codes_dibusb_table,
+ .rc_key_map_size = 111, /* wow, that is ugly ... I want to load it to the driver dynamically */
+ .rc_query = dibusb_rc_query,
+ },
.i2c_algo = &dibusb_i2c_algo,
diff --git a/drivers/media/dvb/dvb-usb/dibusb-mc.c b/drivers/media/dvb/dvb-usb/dibusb-mc.c
index 588308eb663..1cbc41cb4e8 100644
--- a/drivers/media/dvb/dvb-usb/dibusb-mc.c
+++ b/drivers/media/dvb/dvb-usb/dibusb-mc.c
@@ -81,10 +81,12 @@ static struct dvb_usb_device_properties dibusb_mc_properties = {
},
.power_ctrl = dibusb2_0_power_ctrl,
- .rc_interval = DEFAULT_RC_INTERVAL,
- .rc_key_map = ir_codes_dibusb_table,
- .rc_key_map_size = 111, /* FIXME */
- .rc_query = dibusb_rc_query,
+ .rc.legacy = {
+ .rc_interval = DEFAULT_RC_INTERVAL,
+ .rc_key_map = ir_codes_dibusb_table,
+ .rc_key_map_size = 111, /* FIXME */
+ .rc_query = dibusb_rc_query,
+ },
.i2c_algo = &dibusb_i2c_algo,
diff --git a/drivers/media/dvb/dvb-usb/dibusb.h b/drivers/media/dvb/dvb-usb/dibusb.h
index 3d50ac59088..61a6bf38947 100644
--- a/drivers/media/dvb/dvb-usb/dibusb.h
+++ b/drivers/media/dvb/dvb-usb/dibusb.h
@@ -124,7 +124,7 @@ extern int dibusb2_0_power_ctrl(struct dvb_usb_device *, int);
#define DEFAULT_RC_INTERVAL 150
//#define DEFAULT_RC_INTERVAL 100000
-extern struct dvb_usb_rc_key ir_codes_dibusb_table[];
+extern struct ir_scancode ir_codes_dibusb_table[];
extern int dibusb_rc_query(struct dvb_usb_device *, u32 *, int *);
extern int dibusb_read_eeprom_byte(struct dvb_usb_device *, u8, u8 *);
diff --git a/drivers/media/dvb/dvb-usb/digitv.c b/drivers/media/dvb/dvb-usb/digitv.c
index e826077094f..13d006bb19d 100644
--- a/drivers/media/dvb/dvb-usb/digitv.c
+++ b/drivers/media/dvb/dvb-usb/digitv.c
@@ -161,7 +161,7 @@ static int digitv_tuner_attach(struct dvb_usb_adapter *adap)
return 0;
}
-static struct dvb_usb_rc_key ir_codes_digitv_table[] = {
+static struct ir_scancode ir_codes_digitv_table[] = {
{ 0x5f55, KEY_0 },
{ 0x6f55, KEY_1 },
{ 0x9f55, KEY_2 },
@@ -237,10 +237,10 @@ static int digitv_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
/* if something is inside the buffer, simulate key press */
if (key[1] != 0)
{
- for (i = 0; i < d->props.rc_key_map_size; i++) {
- if (rc5_custom(&d->props.rc_key_map[i]) == key[1] &&
- rc5_data(&d->props.rc_key_map[i]) == key[2]) {
- *event = d->props.rc_key_map[i].event;
+ for (i = 0; i < d->props.rc.legacy.rc_key_map_size; i++) {
+ if (rc5_custom(&d->props.rc.legacy.rc_key_map[i]) == key[1] &&
+ rc5_data(&d->props.rc.legacy.rc_key_map[i]) == key[2]) {
+ *event = d->props.rc.legacy.rc_key_map[i].keycode;
*state = REMOTE_KEY_PRESSED;
return 0;
}
@@ -310,10 +310,12 @@ static struct dvb_usb_device_properties digitv_properties = {
},
.identify_state = digitv_identify_state,
- .rc_interval = 1000,
- .rc_key_map = ir_codes_digitv_table,
- .rc_key_map_size = ARRAY_SIZE(ir_codes_digitv_table),
- .rc_query = digitv_rc_query,
+ .rc.legacy = {
+ .rc_interval = 1000,
+ .rc_key_map = ir_codes_digitv_table,
+ .rc_key_map_size = ARRAY_SIZE(ir_codes_digitv_table),
+ .rc_query = digitv_rc_query,
+ },
.i2c_algo = &digitv_i2c_algo,
diff --git a/drivers/media/dvb/dvb-usb/dtt200u.c b/drivers/media/dvb/dvb-usb/dtt200u.c
index f57e59044d4..ca495e07f35 100644
--- a/drivers/media/dvb/dvb-usb/dtt200u.c
+++ b/drivers/media/dvb/dvb-usb/dtt200u.c
@@ -57,7 +57,7 @@ static int dtt200u_pid_filter(struct dvb_usb_adapter *adap, int index, u16 pid,
/* remote control */
/* key list for the tiny remote control (Yakumo, don't know about the others) */
-static struct dvb_usb_rc_key ir_codes_dtt200u_table[] = {
+static struct ir_scancode ir_codes_dtt200u_table[] = {
{ 0x8001, KEY_MUTE },
{ 0x8002, KEY_CHANNELDOWN },
{ 0x8003, KEY_VOLUMEDOWN },
@@ -161,10 +161,12 @@ static struct dvb_usb_device_properties dtt200u_properties = {
},
.power_ctrl = dtt200u_power_ctrl,
- .rc_interval = 300,
- .rc_key_map = ir_codes_dtt200u_table,
- .rc_key_map_size = ARRAY_SIZE(ir_codes_dtt200u_table),
- .rc_query = dtt200u_rc_query,
+ .rc.legacy = {
+ .rc_interval = 300,
+ .rc_key_map = ir_codes_dtt200u_table,
+ .rc_key_map_size = ARRAY_SIZE(ir_codes_dtt200u_table),
+ .rc_query = dtt200u_rc_query,
+ },
.generic_bulk_ctrl_endpoint = 0x01,
@@ -206,10 +208,12 @@ static struct dvb_usb_device_properties wt220u_properties = {
},
.power_ctrl = dtt200u_power_ctrl,
- .rc_interval = 300,
- .rc_key_map = ir_codes_dtt200u_table,
- .rc_key_map_size = ARRAY_SIZE(ir_codes_dtt200u_table),
- .rc_query = dtt200u_rc_query,
+ .rc.legacy = {
+ .rc_interval = 300,
+ .rc_key_map = ir_codes_dtt200u_table,
+ .rc_key_map_size = ARRAY_SIZE(ir_codes_dtt200u_table),
+ .rc_query = dtt200u_rc_query,
+ },
.generic_bulk_ctrl_endpoint = 0x01,
@@ -251,10 +255,12 @@ static struct dvb_usb_device_properties wt220u_fc_properties = {
},
.power_ctrl = dtt200u_power_ctrl,
- .rc_interval = 300,
- .rc_key_map = ir_codes_dtt200u_table,
- .rc_key_map_size = ARRAY_SIZE(ir_codes_dtt200u_table),
- .rc_query = dtt200u_rc_query,
+ .rc.legacy = {
+ .rc_interval = 300,
+ .rc_key_map = ir_codes_dtt200u_table,
+ .rc_key_map_size = ARRAY_SIZE(ir_codes_dtt200u_table),
+ .rc_query = dtt200u_rc_query,
+ },
.generic_bulk_ctrl_endpoint = 0x01,
@@ -296,10 +302,12 @@ static struct dvb_usb_device_properties wt220u_zl0353_properties = {
},
.power_ctrl = dtt200u_power_ctrl,
- .rc_interval = 300,
- .rc_key_map = ir_codes_dtt200u_table,
- .rc_key_map_size = ARRAY_SIZE(ir_codes_dtt200u_table),
- .rc_query = dtt200u_rc_query,
+ .rc.legacy = {
+ .rc_interval = 300,
+ .rc_key_map = ir_codes_dtt200u_table,
+ .rc_key_map_size = ARRAY_SIZE(ir_codes_dtt200u_table),
+ .rc_query = dtt200u_rc_query,
+ },
.generic_bulk_ctrl_endpoint = 0x01,
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
index b4afe6f8ed1..1a774d58d66 100644
--- a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
+++ b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
@@ -197,6 +197,7 @@
#define USB_PID_AVERMEDIA_A310 0xa310
#define USB_PID_AVERMEDIA_A850 0x850a
#define USB_PID_AVERMEDIA_A805 0xa805
+#define USB_PID_AVERMEDIA_A815M 0x815a
#define USB_PID_TECHNOTREND_CONNECT_S2400 0x3006
#define USB_PID_TECHNOTREND_CONNECT_CT3650 0x300d
#define USB_PID_TERRATEC_CINERGY_DT_XS_DIVERSITY 0x005a
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-init.c b/drivers/media/dvb/dvb-usb/dvb-usb-init.c
index 5d91f70d2d2..2e3ea0fa28e 100644
--- a/drivers/media/dvb/dvb-usb/dvb-usb-init.c
+++ b/drivers/media/dvb/dvb-usb/dvb-usb-init.c
@@ -15,7 +15,7 @@
/* debug */
int dvb_usb_debug;
-module_param_named(debug,dvb_usb_debug, int, 0644);
+module_param_named(debug, dvb_usb_debug, int, 0644);
MODULE_PARM_DESC(debug, "set debugging level (1=info,xfer=2,pll=4,ts=8,err=16,rc=32,fw=64,mem=128,uxfer=256 (or-able))." DVB_USB_DEBUG_STATUS);
int dvb_usb_disable_rc_polling;
@@ -29,7 +29,7 @@ MODULE_PARM_DESC(force_pid_filter_usage, "force all dvb-usb-devices to use a PID
static int dvb_usb_adapter_init(struct dvb_usb_device *d, short *adapter_nrs)
{
struct dvb_usb_adapter *adap;
- int ret,n;
+ int ret, n;
for (n = 0; n < d->props.num_adapters; n++) {
adap = &d->adapter[n];
@@ -38,7 +38,7 @@ static int dvb_usb_adapter_init(struct dvb_usb_device *d, short *adapter_nrs)
memcpy(&adap->props, &d->props.adapter[n], sizeof(struct dvb_usb_adapter_properties));
-/* speed - when running at FULL speed we need a HW PID filter */
+ /* speed - when running at FULL speed we need a HW PID filter */
if (d->udev->speed == USB_SPEED_FULL && !(adap->props.caps & DVB_USB_ADAP_HAS_PID_FILTER)) {
err("This USB2.0 device cannot be run on a USB1.1 port. (it lacks a hardware PID filter)");
return -ENODEV;
@@ -46,7 +46,7 @@ static int dvb_usb_adapter_init(struct dvb_usb_device *d, short *adapter_nrs)
if ((d->udev->speed == USB_SPEED_FULL && adap->props.caps & DVB_USB_ADAP_HAS_PID_FILTER) ||
(adap->props.caps & DVB_USB_ADAP_NEED_PID_FILTERING)) {
- info("will use the device's hardware PID filter (table count: %d).",adap->props.pid_filter_count);
+ info("will use the device's hardware PID filter (table count: %d).", adap->props.pid_filter_count);
adap->pid_filtering = 1;
adap->max_feed_count = adap->props.pid_filter_count;
} else {
@@ -64,9 +64,9 @@ static int dvb_usb_adapter_init(struct dvb_usb_device *d, short *adapter_nrs)
}
if (adap->props.size_of_priv > 0) {
- adap->priv = kzalloc(adap->props.size_of_priv,GFP_KERNEL);
+ adap->priv = kzalloc(adap->props.size_of_priv, GFP_KERNEL);
if (adap->priv == NULL) {
- err("no memory for priv for adapter %d.",n);
+ err("no memory for priv for adapter %d.", n);
return -ENOMEM;
}
}
@@ -86,8 +86,8 @@ static int dvb_usb_adapter_init(struct dvb_usb_device *d, short *adapter_nrs)
* sometimes a timeout occures, this helps
*/
if (d->props.generic_bulk_ctrl_endpoint != 0) {
- usb_clear_halt(d->udev,usb_sndbulkpipe(d->udev,d->props.generic_bulk_ctrl_endpoint));
- usb_clear_halt(d->udev,usb_rcvbulkpipe(d->udev,d->props.generic_bulk_ctrl_endpoint));
+ usb_clear_halt(d->udev, usb_sndbulkpipe(d->udev, d->props.generic_bulk_ctrl_endpoint));
+ usb_clear_halt(d->udev, usb_rcvbulkpipe(d->udev, d->props.generic_bulk_ctrl_endpoint));
}
return 0;
@@ -96,6 +96,7 @@ static int dvb_usb_adapter_init(struct dvb_usb_device *d, short *adapter_nrs)
static int dvb_usb_adapter_exit(struct dvb_usb_device *d)
{
int n;
+
for (n = 0; n < d->num_adapters_initialized; n++) {
dvb_usb_adapter_frontend_exit(&d->adapter[n]);
dvb_usb_adapter_dvb_exit(&d->adapter[n]);
@@ -111,11 +112,11 @@ static int dvb_usb_adapter_exit(struct dvb_usb_device *d)
/* general initialization functions */
static int dvb_usb_exit(struct dvb_usb_device *d)
{
- deb_info("state before exiting everything: %x\n",d->state);
+ deb_info("state before exiting everything: %x\n", d->state);
dvb_usb_remote_exit(d);
dvb_usb_adapter_exit(d);
dvb_usb_i2c_exit(d);
- deb_info("state should be zero now: %x\n",d->state);
+ deb_info("state should be zero now: %x\n", d->state);
d->state = DVB_USB_STATE_INIT;
kfree(d->priv);
kfree(d);
@@ -132,14 +133,14 @@ static int dvb_usb_init(struct dvb_usb_device *d, short *adapter_nums)
d->state = DVB_USB_STATE_INIT;
if (d->props.size_of_priv > 0) {
- d->priv = kzalloc(d->props.size_of_priv,GFP_KERNEL);
+ d->priv = kzalloc(d->props.size_of_priv, GFP_KERNEL);
if (d->priv == NULL) {
err("no memory for priv in 'struct dvb_usb_device'");
return -ENOMEM;
}
}
-/* check the capabilities and set appropriate variables */
+ /* check the capabilities and set appropriate variables */
dvb_usb_device_power_ctrl(d, 1);
if ((ret = dvb_usb_i2c_init(d)) ||
@@ -157,16 +158,17 @@ static int dvb_usb_init(struct dvb_usb_device *d, short *adapter_nums)
}
/* determine the name and the state of the just found USB device */
-static struct dvb_usb_device_description * dvb_usb_find_device(struct usb_device *udev,struct dvb_usb_device_properties *props, int *cold)
+static struct dvb_usb_device_description *dvb_usb_find_device(struct usb_device *udev, struct dvb_usb_device_properties *props, int *cold)
{
- int i,j;
+ int i, j;
struct dvb_usb_device_description *desc = NULL;
+
*cold = -1;
for (i = 0; i < props->num_device_descs; i++) {
for (j = 0; j < DVB_USB_ID_MAX_NUM && props->devices[i].cold_ids[j] != NULL; j++) {
- deb_info("check for cold %x %x\n",props->devices[i].cold_ids[j]->idVendor, props->devices[i].cold_ids[j]->idProduct);
+ deb_info("check for cold %x %x\n", props->devices[i].cold_ids[j]->idVendor, props->devices[i].cold_ids[j]->idProduct);
if (props->devices[i].cold_ids[j]->idVendor == le16_to_cpu(udev->descriptor.idVendor) &&
props->devices[i].cold_ids[j]->idProduct == le16_to_cpu(udev->descriptor.idProduct)) {
*cold = 1;
@@ -179,7 +181,7 @@ static struct dvb_usb_device_description * dvb_usb_find_device(struct usb_device
break;
for (j = 0; j < DVB_USB_ID_MAX_NUM && props->devices[i].warm_ids[j] != NULL; j++) {
- deb_info("check for warm %x %x\n",props->devices[i].warm_ids[j]->idVendor, props->devices[i].warm_ids[j]->idProduct);
+ deb_info("check for warm %x %x\n", props->devices[i].warm_ids[j]->idVendor, props->devices[i].warm_ids[j]->idProduct);
if (props->devices[i].warm_ids[j]->idVendor == le16_to_cpu(udev->descriptor.idVendor) &&
props->devices[i].warm_ids[j]->idProduct == le16_to_cpu(udev->descriptor.idProduct)) {
*cold = 0;
@@ -190,7 +192,7 @@ static struct dvb_usb_device_description * dvb_usb_find_device(struct usb_device
}
if (desc != NULL && props->identify_state != NULL)
- props->identify_state(udev,props,&desc,cold);
+ props->identify_state(udev, props, &desc, cold);
return desc;
}
@@ -202,7 +204,7 @@ int dvb_usb_device_power_ctrl(struct dvb_usb_device *d, int onoff)
else
d->powered--;
- if (d->powered == 0 || (onoff && d->powered == 1)) { // when switching from 1 to 0 or from 0 to 1
+ if (d->powered == 0 || (onoff && d->powered == 1)) { /* when switching from 1 to 0 or from 0 to 1 */
deb_info("power control: %d\n", onoff);
if (d->props.power_ctrl)
return d->props.power_ctrl(d, onoff);
@@ -222,32 +224,32 @@ int dvb_usb_device_init(struct usb_interface *intf,
struct dvb_usb_device *d = NULL;
struct dvb_usb_device_description *desc = NULL;
- int ret = -ENOMEM,cold=0;
+ int ret = -ENOMEM, cold = 0;
if (du != NULL)
*du = NULL;
- if ((desc = dvb_usb_find_device(udev,props,&cold)) == NULL) {
+ if ((desc = dvb_usb_find_device(udev, props, &cold)) == NULL) {
deb_err("something went very wrong, device was not found in current device list - let's see what comes next.\n");
return -ENODEV;
}
if (cold) {
- info("found a '%s' in cold state, will try to load a firmware",desc->name);
- ret = dvb_usb_download_firmware(udev,props);
+ info("found a '%s' in cold state, will try to load a firmware", desc->name);
+ ret = dvb_usb_download_firmware(udev, props);
if (!props->no_reconnect || ret != 0)
return ret;
}
- info("found a '%s' in warm state.",desc->name);
- d = kzalloc(sizeof(struct dvb_usb_device),GFP_KERNEL);
+ info("found a '%s' in warm state.", desc->name);
+ d = kzalloc(sizeof(struct dvb_usb_device), GFP_KERNEL);
if (d == NULL) {
err("no memory for 'struct dvb_usb_device'");
return -ENOMEM;
}
d->udev = udev;
- memcpy(&d->props,props,sizeof(struct dvb_usb_device_properties));
+ memcpy(&d->props, props, sizeof(struct dvb_usb_device_properties));
d->desc = desc;
d->owner = owner;
@@ -259,9 +261,9 @@ int dvb_usb_device_init(struct usb_interface *intf,
ret = dvb_usb_init(d, adapter_nums);
if (ret == 0)
- info("%s successfully initialized and connected.",desc->name);
+ info("%s successfully initialized and connected.", desc->name);
else
- info("%s error while loading driver (%d)",desc->name,ret);
+ info("%s error while loading driver (%d)", desc->name, ret);
return ret;
}
EXPORT_SYMBOL(dvb_usb_device_init);
@@ -271,12 +273,12 @@ void dvb_usb_device_exit(struct usb_interface *intf)
struct dvb_usb_device *d = usb_get_intfdata(intf);
const char *name = "generic DVB-USB module";
- usb_set_intfdata(intf,NULL);
+ usb_set_intfdata(intf, NULL);
if (d != NULL && d->desc != NULL) {
name = d->desc->name;
dvb_usb_exit(d);
}
- info("%s successfully deinitialized and disconnected.",name);
+ info("%s successfully deinitialized and disconnected.", name);
}
EXPORT_SYMBOL(dvb_usb_device_exit);
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-remote.c b/drivers/media/dvb/dvb-usb/dvb-usb-remote.c
index 852fe89539c..b579fed3ab3 100644
--- a/drivers/media/dvb/dvb-usb/dvb-usb-remote.c
+++ b/drivers/media/dvb/dvb-usb/dvb-usb-remote.c
@@ -8,29 +8,29 @@
#include "dvb-usb-common.h"
#include <linux/usb/input.h>
-static int dvb_usb_getkeycode(struct input_dev *dev,
+static int legacy_dvb_usb_getkeycode(struct input_dev *dev,
unsigned int scancode, unsigned int *keycode)
{
struct dvb_usb_device *d = input_get_drvdata(dev);
- struct dvb_usb_rc_key *keymap = d->props.rc_key_map;
+ struct ir_scancode *keymap = d->props.rc.legacy.rc_key_map;
int i;
/* See if we can match the raw key code. */
- for (i = 0; i < d->props.rc_key_map_size; i++)
- if (keymap[i].scan == scancode) {
- *keycode = keymap[i].event;
+ for (i = 0; i < d->props.rc.legacy.rc_key_map_size; i++)
+ if (keymap[i].scancode == scancode) {
+ *keycode = keymap[i].keycode;
return 0;
}
/*
* If is there extra space, returns KEY_RESERVED,
- * otherwise, input core won't let dvb_usb_setkeycode
+ * otherwise, input core won't let legacy_dvb_usb_setkeycode
* to work
*/
- for (i = 0; i < d->props.rc_key_map_size; i++)
- if (keymap[i].event == KEY_RESERVED ||
- keymap[i].event == KEY_UNKNOWN) {
+ for (i = 0; i < d->props.rc.legacy.rc_key_map_size; i++)
+ if (keymap[i].keycode == KEY_RESERVED ||
+ keymap[i].keycode == KEY_UNKNOWN) {
*keycode = KEY_RESERVED;
return 0;
}
@@ -38,27 +38,27 @@ static int dvb_usb_getkeycode(struct input_dev *dev,
return -EINVAL;
}
-static int dvb_usb_setkeycode(struct input_dev *dev,
+static int legacy_dvb_usb_setkeycode(struct input_dev *dev,
unsigned int scancode, unsigned int keycode)
{
struct dvb_usb_device *d = input_get_drvdata(dev);
- struct dvb_usb_rc_key *keymap = d->props.rc_key_map;
+ struct ir_scancode *keymap = d->props.rc.legacy.rc_key_map;
int i;
/* Search if it is replacing an existing keycode */
- for (i = 0; i < d->props.rc_key_map_size; i++)
- if (keymap[i].scan == scancode) {
- keymap[i].event = keycode;
+ for (i = 0; i < d->props.rc.legacy.rc_key_map_size; i++)
+ if (keymap[i].scancode == scancode) {
+ keymap[i].keycode = keycode;
return 0;
}
/* Search if is there a clean entry. If so, use it */
- for (i = 0; i < d->props.rc_key_map_size; i++)
- if (keymap[i].event == KEY_RESERVED ||
- keymap[i].event == KEY_UNKNOWN) {
- keymap[i].scan = scancode;
- keymap[i].event = keycode;
+ for (i = 0; i < d->props.rc.legacy.rc_key_map_size; i++)
+ if (keymap[i].keycode == KEY_RESERVED ||
+ keymap[i].keycode == KEY_UNKNOWN) {
+ keymap[i].scancode = scancode;
+ keymap[i].keycode = keycode;
return 0;
}
@@ -78,7 +78,7 @@ static int dvb_usb_setkeycode(struct input_dev *dev,
*
* TODO: Fix the repeat rate of the input device.
*/
-static void dvb_usb_read_remote_control(struct work_struct *work)
+static void legacy_dvb_usb_read_remote_control(struct work_struct *work)
{
struct dvb_usb_device *d =
container_of(work, struct dvb_usb_device, rc_query_work.work);
@@ -92,7 +92,7 @@ static void dvb_usb_read_remote_control(struct work_struct *work)
if (dvb_usb_disable_rc_polling)
return;
- if (d->props.rc_query(d,&event,&state)) {
+ if (d->props.rc.legacy.rc_query(d,&event,&state)) {
err("error while querying for an remote control event.");
goto schedule;
}
@@ -151,18 +151,117 @@ static void dvb_usb_read_remote_control(struct work_struct *work)
*/
schedule:
- schedule_delayed_work(&d->rc_query_work,msecs_to_jiffies(d->props.rc_interval));
+ schedule_delayed_work(&d->rc_query_work,msecs_to_jiffies(d->props.rc.legacy.rc_interval));
+}
+
+static int legacy_dvb_usb_remote_init(struct dvb_usb_device *d,
+ struct input_dev *input_dev)
+{
+ int i, err, rc_interval;
+
+ input_dev->getkeycode = legacy_dvb_usb_getkeycode;
+ input_dev->setkeycode = legacy_dvb_usb_setkeycode;
+
+ /* set the bits for the keys */
+ deb_rc("key map size: %d\n", d->props.rc.legacy.rc_key_map_size);
+ for (i = 0; i < d->props.rc.legacy.rc_key_map_size; i++) {
+ deb_rc("setting bit for event %d item %d\n",
+ d->props.rc.legacy.rc_key_map[i].keycode, i);
+ set_bit(d->props.rc.legacy.rc_key_map[i].keycode, input_dev->keybit);
+ }
+
+ /* setting these two values to non-zero, we have to manage key repeats */
+ input_dev->rep[REP_PERIOD] = d->props.rc.legacy.rc_interval;
+ input_dev->rep[REP_DELAY] = d->props.rc.legacy.rc_interval + 150;
+
+ input_set_drvdata(input_dev, d);
+
+ err = input_register_device(input_dev);
+ if (err)
+ input_free_device(input_dev);
+
+ rc_interval = d->props.rc.legacy.rc_interval;
+
+ INIT_DELAYED_WORK(&d->rc_query_work, legacy_dvb_usb_read_remote_control);
+
+ info("schedule remote query interval to %d msecs.", rc_interval);
+ schedule_delayed_work(&d->rc_query_work,
+ msecs_to_jiffies(rc_interval));
+
+ d->state |= DVB_USB_STATE_REMOTE;
+
+ return err;
+}
+
+/* Remote-control poll function - called every dib->rc_query_interval ms to see
+ * whether the remote control has received anything.
+ *
+ * TODO: Fix the repeat rate of the input device.
+ */
+static void dvb_usb_read_remote_control(struct work_struct *work)
+{
+ struct dvb_usb_device *d =
+ container_of(work, struct dvb_usb_device, rc_query_work.work);
+ int err;
+
+ /* TODO: need a lock here. We can simply skip checking for the remote control
+ if we're busy. */
+
+ /* when the parameter has been set to 1 via sysfs while the
+ * driver was running, or when bulk mode is enabled after IR init
+ */
+ if (dvb_usb_disable_rc_polling || d->props.rc.core.bulk_mode)
+ return;
+
+ err = d->props.rc.core.rc_query(d);
+ if (err)
+ err("error %d while querying for an remote control event.", err);
+
+ schedule_delayed_work(&d->rc_query_work,
+ msecs_to_jiffies(d->props.rc.core.rc_interval));
+}
+
+static int rc_core_dvb_usb_remote_init(struct dvb_usb_device *d,
+ struct input_dev *input_dev)
+{
+ int err, rc_interval;
+
+ d->props.rc.core.rc_props.priv = d;
+ err = ir_input_register(input_dev,
+ d->props.rc.core.rc_codes,
+ &d->props.rc.core.rc_props,
+ d->props.rc.core.module_name);
+ if (err < 0)
+ return err;
+
+ if (!d->props.rc.core.rc_query || d->props.rc.core.bulk_mode)
+ return 0;
+
+ /* Polling mode - initialize a work queue for handling it */
+ INIT_DELAYED_WORK(&d->rc_query_work, dvb_usb_read_remote_control);
+
+ rc_interval = d->props.rc.core.rc_interval;
+
+ info("schedule remote query interval to %d msecs.", rc_interval);
+ schedule_delayed_work(&d->rc_query_work,
+ msecs_to_jiffies(rc_interval));
+
+ return 0;
}
int dvb_usb_remote_init(struct dvb_usb_device *d)
{
struct input_dev *input_dev;
- int i;
int err;
- if (d->props.rc_key_map == NULL ||
- d->props.rc_query == NULL ||
- dvb_usb_disable_rc_polling)
+ if (dvb_usb_disable_rc_polling)
+ return 0;
+
+ if (d->props.rc.legacy.rc_key_map && d->props.rc.legacy.rc_query)
+ d->props.rc.mode = DVB_RC_LEGACY;
+ else if (d->props.rc.core.rc_codes)
+ d->props.rc.mode = DVB_RC_CORE;
+ else
return 0;
usb_make_path(d->udev, d->rc_phys, sizeof(d->rc_phys));
@@ -177,39 +276,19 @@ int dvb_usb_remote_init(struct dvb_usb_device *d)
input_dev->phys = d->rc_phys;
usb_to_input_id(d->udev, &input_dev->id);
input_dev->dev.parent = &d->udev->dev;
- input_dev->getkeycode = dvb_usb_getkeycode;
- input_dev->setkeycode = dvb_usb_setkeycode;
-
- /* set the bits for the keys */
- deb_rc("key map size: %d\n", d->props.rc_key_map_size);
- for (i = 0; i < d->props.rc_key_map_size; i++) {
- deb_rc("setting bit for event %d item %d\n",
- d->props.rc_key_map[i].event, i);
- set_bit(d->props.rc_key_map[i].event, input_dev->keybit);
- }
/* Start the remote-control polling. */
- if (d->props.rc_interval < 40)
- d->props.rc_interval = 100; /* default */
-
- /* setting these two values to non-zero, we have to manage key repeats */
- input_dev->rep[REP_PERIOD] = d->props.rc_interval;
- input_dev->rep[REP_DELAY] = d->props.rc_interval + 150;
-
- input_set_drvdata(input_dev, d);
-
- err = input_register_device(input_dev);
- if (err) {
- input_free_device(input_dev);
- return err;
- }
+ if (d->props.rc.legacy.rc_interval < 40)
+ d->props.rc.legacy.rc_interval = 100; /* default */
d->rc_input_dev = input_dev;
- INIT_DELAYED_WORK(&d->rc_query_work, dvb_usb_read_remote_control);
-
- info("schedule remote query interval to %d msecs.", d->props.rc_interval);
- schedule_delayed_work(&d->rc_query_work,msecs_to_jiffies(d->props.rc_interval));
+ if (d->props.rc.mode == DVB_RC_LEGACY)
+ err = legacy_dvb_usb_remote_init(d, input_dev);
+ else
+ err = rc_core_dvb_usb_remote_init(d, input_dev);
+ if (err)
+ return err;
d->state |= DVB_USB_STATE_REMOTE;
@@ -221,7 +300,10 @@ int dvb_usb_remote_exit(struct dvb_usb_device *d)
if (d->state & DVB_USB_STATE_REMOTE) {
cancel_rearming_delayed_work(&d->rc_query_work);
flush_scheduled_work();
- input_unregister_device(d->rc_input_dev);
+ if (d->props.rc.mode == DVB_RC_LEGACY)
+ input_unregister_device(d->rc_input_dev);
+ else
+ ir_input_unregister(d->rc_input_dev);
}
d->state &= ~DVB_USB_STATE_REMOTE;
return 0;
@@ -234,7 +316,7 @@ int dvb_usb_nec_rc_key_to_event(struct dvb_usb_device *d,
u8 keybuf[5], u32 *event, int *state)
{
int i;
- struct dvb_usb_rc_key *keymap = d->props.rc_key_map;
+ struct ir_scancode *keymap = d->props.rc.legacy.rc_key_map;
*event = 0;
*state = REMOTE_NO_KEY_PRESSED;
switch (keybuf[0]) {
@@ -247,10 +329,10 @@ int dvb_usb_nec_rc_key_to_event(struct dvb_usb_device *d,
break;
}
/* See if we can match the raw key code. */
- for (i = 0; i < d->props.rc_key_map_size; i++)
+ for (i = 0; i < d->props.rc.legacy.rc_key_map_size; i++)
if (rc5_custom(&keymap[i]) == keybuf[1] &&
rc5_data(&keymap[i]) == keybuf[3]) {
- *event = keymap[i].event;
+ *event = keymap[i].keycode;
*state = REMOTE_KEY_PRESSED;
return 0;
}
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb.h b/drivers/media/dvb/dvb-usb/dvb-usb.h
index 4a9f676087b..34f7b3ba8cc 100644
--- a/drivers/media/dvb/dvb-usb/dvb-usb.h
+++ b/drivers/media/dvb/dvb-usb/dvb-usb.h
@@ -14,6 +14,7 @@
#include <linux/usb.h>
#include <linux/firmware.h>
#include <linux/mutex.h>
+#include <media/ir-core.h>
#include "dvb_frontend.h"
#include "dvb_demux.h"
@@ -74,30 +75,19 @@ struct dvb_usb_device_description {
struct usb_device_id *warm_ids[DVB_USB_ID_MAX_NUM];
};
-/**
- * struct dvb_usb_rc_key - a remote control key and its input-event
- * @custom: the vendor/custom part of the key
- * @data: the actual key part
- * @event: the input event assigned to key identified by custom and data
- */
-struct dvb_usb_rc_key {
- u16 scan;
- u32 event;
-};
-
-static inline u8 rc5_custom(struct dvb_usb_rc_key *key)
+static inline u8 rc5_custom(struct ir_scancode *key)
{
- return (key->scan >> 8) & 0xff;
+ return (key->scancode >> 8) & 0xff;
}
-static inline u8 rc5_data(struct dvb_usb_rc_key *key)
+static inline u8 rc5_data(struct ir_scancode *key)
{
- return key->scan & 0xff;
+ return key->scancode & 0xff;
}
-static inline u8 rc5_scan(struct dvb_usb_rc_key *key)
+static inline u8 rc5_scan(struct ir_scancode *key)
{
- return key->scan & 0xffff;
+ return key->scancode & 0xffff;
}
struct dvb_usb_device;
@@ -168,6 +158,55 @@ struct dvb_usb_adapter_properties {
};
/**
+ * struct dvb_rc_legacy - old properties of remote controller
+ * @rc_key_map: a hard-wired array of struct ir_scancode (NULL to disable
+ * remote control handling).
+ * @rc_key_map_size: number of items in @rc_key_map.
+ * @rc_query: called to query an event event.
+ * @rc_interval: time in ms between two queries.
+ */
+struct dvb_rc_legacy {
+/* remote control properties */
+#define REMOTE_NO_KEY_PRESSED 0x00
+#define REMOTE_KEY_PRESSED 0x01
+#define REMOTE_KEY_REPEAT 0x02
+ struct ir_scancode *rc_key_map;
+ int rc_key_map_size;
+ int (*rc_query) (struct dvb_usb_device *, u32 *, int *);
+ int rc_interval;
+};
+
+/**
+ * struct dvb_rc properties of remote controller, using rc-core
+ * @rc_codes: name of rc codes table
+ * @protocol: type of protocol(s) currently used by the driver
+ * @rc_query: called to query an event event.
+ * @rc_interval: time in ms between two queries.
+ * @rc_props: remote controller properties
+ * @bulk_mode: device supports bulk mode for RC (disable polling mode)
+ */
+struct dvb_rc {
+ char *rc_codes;
+ u64 protocol;
+ char *module_name;
+ int (*rc_query) (struct dvb_usb_device *d);
+ int rc_interval;
+ struct ir_dev_props rc_props;
+ bool bulk_mode; /* uses bulk mode */
+};
+
+/**
+ * enum dvb_usb_mode - Specifies if it is using a legacy driver or a new one
+ * based on rc-core
+ * This is initialized/used only inside dvb-usb-remote.c.
+ * It shouldn't be set by the drivers.
+ */
+enum dvb_usb_mode {
+ DVB_RC_LEGACY,
+ DVB_RC_CORE,
+};
+
+/**
* struct dvb_usb_device_properties - properties of a dvb-usb-device
* @usb_ctrl: which USB device-side controller is in use. Needed for firmware
* download.
@@ -185,11 +224,7 @@ struct dvb_usb_adapter_properties {
* @identify_state: called to determine the state (cold or warm), when it
* is not distinguishable by the USB IDs.
*
- * @rc_key_map: a hard-wired array of struct dvb_usb_rc_key (NULL to disable
- * remote control handling).
- * @rc_key_map_size: number of items in @rc_key_map.
- * @rc_query: called to query an event event.
- * @rc_interval: time in ms between two queries.
+ * @rc: remote controller properties
*
* @i2c_algo: i2c_algorithm if the device has I2CoverUSB.
*
@@ -233,14 +268,11 @@ struct dvb_usb_device_properties {
int (*identify_state) (struct usb_device *, struct dvb_usb_device_properties *,
struct dvb_usb_device_description **, int *);
-/* remote control properties */
-#define REMOTE_NO_KEY_PRESSED 0x00
-#define REMOTE_KEY_PRESSED 0x01
-#define REMOTE_KEY_REPEAT 0x02
- struct dvb_usb_rc_key *rc_key_map;
- int rc_key_map_size;
- int (*rc_query) (struct dvb_usb_device *, u32 *, int *);
- int rc_interval;
+ struct {
+ enum dvb_usb_mode mode; /* Drivers shouldn't touch on it */
+ struct dvb_rc_legacy legacy;
+ struct dvb_rc core;
+ } rc;
struct i2c_algorithm *i2c_algo;
diff --git a/drivers/media/dvb/dvb-usb/dw2102.c b/drivers/media/dvb/dvb-usb/dw2102.c
index e8fb8538067..774df88dc6e 100644
--- a/drivers/media/dvb/dvb-usb/dw2102.c
+++ b/drivers/media/dvb/dvb-usb/dw2102.c
@@ -74,7 +74,7 @@
"on firmware-problems."
struct ir_codes_dvb_usb_table_table {
- struct dvb_usb_rc_key *rc_keys;
+ struct ir_scancode *rc_keys;
int rc_keys_size;
};
@@ -948,7 +948,7 @@ static int dw3101_tuner_attach(struct dvb_usb_adapter *adap)
return 0;
}
-static struct dvb_usb_rc_key ir_codes_dw210x_table[] = {
+static struct ir_scancode ir_codes_dw210x_table[] = {
{ 0xf80a, KEY_Q }, /*power*/
{ 0xf80c, KEY_M }, /*mute*/
{ 0xf811, KEY_1 },
@@ -982,7 +982,7 @@ static struct dvb_usb_rc_key ir_codes_dw210x_table[] = {
{ 0xf81b, KEY_B }, /*recall*/
};
-static struct dvb_usb_rc_key ir_codes_tevii_table[] = {
+static struct ir_scancode ir_codes_tevii_table[] = {
{ 0xf80a, KEY_POWER },
{ 0xf80c, KEY_MUTE },
{ 0xf811, KEY_1 },
@@ -1032,7 +1032,7 @@ static struct dvb_usb_rc_key ir_codes_tevii_table[] = {
{ 0xf858, KEY_SWITCHVIDEOMODE },
};
-static struct dvb_usb_rc_key ir_codes_tbs_table[] = {
+static struct ir_scancode ir_codes_tbs_table[] = {
{ 0xf884, KEY_POWER },
{ 0xf894, KEY_MUTE },
{ 0xf887, KEY_1 },
@@ -1075,8 +1075,8 @@ static struct ir_codes_dvb_usb_table_table keys_tables[] = {
static int dw2102_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
{
- struct dvb_usb_rc_key *keymap = d->props.rc_key_map;
- int keymap_size = d->props.rc_key_map_size;
+ struct ir_scancode *keymap = d->props.rc.legacy.rc_key_map;
+ int keymap_size = d->props.rc.legacy.rc_key_map_size;
u8 key[2];
struct i2c_msg msg = {
.addr = DW2102_RC_QUERY,
@@ -1096,7 +1096,7 @@ static int dw2102_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
for (i = 0; i < keymap_size ; i++) {
if (rc5_data(&keymap[i]) == msg.buf[0]) {
*state = REMOTE_KEY_PRESSED;
- *event = keymap[i].event;
+ *event = keymap[i].keycode;
break;
}
@@ -1185,13 +1185,13 @@ static int dw2102_load_firmware(struct usb_device *dev,
/* init registers */
switch (dev->descriptor.idProduct) {
case USB_PID_PROF_1100:
- s6x0_properties.rc_key_map = ir_codes_tbs_table;
- s6x0_properties.rc_key_map_size =
+ s6x0_properties.rc.legacy.rc_key_map = ir_codes_tbs_table;
+ s6x0_properties.rc.legacy.rc_key_map_size =
ARRAY_SIZE(ir_codes_tbs_table);
break;
case USB_PID_TEVII_S650:
- dw2104_properties.rc_key_map = ir_codes_tevii_table;
- dw2104_properties.rc_key_map_size =
+ dw2104_properties.rc.legacy.rc_key_map = ir_codes_tevii_table;
+ dw2104_properties.rc.legacy.rc_key_map_size =
ARRAY_SIZE(ir_codes_tevii_table);
case USB_PID_DW2104:
reset = 1;
@@ -1255,10 +1255,13 @@ static struct dvb_usb_device_properties dw2102_properties = {
.no_reconnect = 1,
.i2c_algo = &dw2102_serit_i2c_algo,
- .rc_key_map = ir_codes_dw210x_table,
- .rc_key_map_size = ARRAY_SIZE(ir_codes_dw210x_table),
- .rc_interval = 150,
- .rc_query = dw2102_rc_query,
+
+ .rc.legacy = {
+ .rc_key_map = ir_codes_dw210x_table,
+ .rc_key_map_size = ARRAY_SIZE(ir_codes_dw210x_table),
+ .rc_interval = 150,
+ .rc_query = dw2102_rc_query,
+ },
.generic_bulk_ctrl_endpoint = 0x81,
/* parameter for the MPEG2-data transfer */
@@ -1306,10 +1309,12 @@ static struct dvb_usb_device_properties dw2104_properties = {
.no_reconnect = 1,
.i2c_algo = &dw2104_i2c_algo,
- .rc_key_map = ir_codes_dw210x_table,
- .rc_key_map_size = ARRAY_SIZE(ir_codes_dw210x_table),
- .rc_interval = 150,
- .rc_query = dw2102_rc_query,
+ .rc.legacy = {
+ .rc_key_map = ir_codes_dw210x_table,
+ .rc_key_map_size = ARRAY_SIZE(ir_codes_dw210x_table),
+ .rc_interval = 150,
+ .rc_query = dw2102_rc_query,
+ },
.generic_bulk_ctrl_endpoint = 0x81,
/* parameter for the MPEG2-data transfer */
@@ -1353,10 +1358,12 @@ static struct dvb_usb_device_properties dw3101_properties = {
.no_reconnect = 1,
.i2c_algo = &dw3101_i2c_algo,
- .rc_key_map = ir_codes_dw210x_table,
- .rc_key_map_size = ARRAY_SIZE(ir_codes_dw210x_table),
- .rc_interval = 150,
- .rc_query = dw2102_rc_query,
+ .rc.legacy = {
+ .rc_key_map = ir_codes_dw210x_table,
+ .rc_key_map_size = ARRAY_SIZE(ir_codes_dw210x_table),
+ .rc_interval = 150,
+ .rc_query = dw2102_rc_query,
+ },
.generic_bulk_ctrl_endpoint = 0x81,
/* parameter for the MPEG2-data transfer */
@@ -1396,10 +1403,12 @@ static struct dvb_usb_device_properties s6x0_properties = {
.no_reconnect = 1,
.i2c_algo = &s6x0_i2c_algo,
- .rc_key_map = ir_codes_tevii_table,
- .rc_key_map_size = ARRAY_SIZE(ir_codes_tevii_table),
- .rc_interval = 150,
- .rc_query = dw2102_rc_query,
+ .rc.legacy = {
+ .rc_key_map = ir_codes_tevii_table,
+ .rc_key_map_size = ARRAY_SIZE(ir_codes_tevii_table),
+ .rc_interval = 150,
+ .rc_query = dw2102_rc_query,
+ },
.generic_bulk_ctrl_endpoint = 0x81,
.num_adapters = 1,
@@ -1459,8 +1468,8 @@ static int dw2102_probe(struct usb_interface *intf,
/* fill only different fields */
p7500->firmware = "dvb-usb-p7500.fw";
p7500->devices[0] = d7500;
- p7500->rc_key_map = ir_codes_tbs_table;
- p7500->rc_key_map_size = ARRAY_SIZE(ir_codes_tbs_table);
+ p7500->rc.legacy.rc_key_map = ir_codes_tbs_table;
+ p7500->rc.legacy.rc_key_map_size = ARRAY_SIZE(ir_codes_tbs_table);
p7500->adapter->frontend_attach = prof_7500_frontend_attach;
if (0 == dvb_usb_device_init(intf, &dw2102_properties,
diff --git a/drivers/media/dvb/dvb-usb/gp8psk-fe.c b/drivers/media/dvb/dvb-usb/gp8psk-fe.c
index 7a7f1b2b681..dbdb5347b2a 100644
--- a/drivers/media/dvb/dvb-usb/gp8psk-fe.c
+++ b/drivers/media/dvb/dvb-usb/gp8psk-fe.c
@@ -349,7 +349,7 @@ static struct dvb_frontend_ops gp8psk_fe_ops = {
* FE_CAN_QAM_16 is for compatibility
* (Myth incorrectly detects Turbo-QPSK as plain QAM-16)
*/
- FE_CAN_QPSK | FE_CAN_QAM_16
+ FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_TURBO_FEC
},
.release = gp8psk_fe_release,
diff --git a/drivers/media/dvb/dvb-usb/m920x.c b/drivers/media/dvb/dvb-usb/m920x.c
index c211fef45fc..bdef1a18b66 100644
--- a/drivers/media/dvb/dvb-usb/m920x.c
+++ b/drivers/media/dvb/dvb-usb/m920x.c
@@ -69,7 +69,7 @@ static int m920x_init(struct dvb_usb_device *d, struct m920x_inits *rc_seq)
int adap_enabled[M9206_MAX_ADAPTERS] = { 0 };
/* Remote controller init. */
- if (d->props.rc_query) {
+ if (d->props.rc.legacy.rc_query) {
deb("Initialising remote control\n");
while (rc_seq->address) {
if ((ret = m920x_write(d->udev, M9206_CORE,
@@ -142,9 +142,9 @@ static int m920x_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
if ((ret = m920x_read(d->udev, M9206_CORE, 0x0, M9206_RC_KEY, rc_state + 1, 1)) != 0)
goto unlock;
- for (i = 0; i < d->props.rc_key_map_size; i++)
- if (rc5_data(&d->props.rc_key_map[i]) == rc_state[1]) {
- *event = d->props.rc_key_map[i].event;
+ for (i = 0; i < d->props.rc.legacy.rc_key_map_size; i++)
+ if (rc5_data(&d->props.rc.legacy.rc_key_map[i]) == rc_state[1]) {
+ *event = d->props.rc.legacy.rc_key_map[i].keycode;
switch(rc_state[0]) {
case 0x80:
@@ -589,7 +589,7 @@ static struct m920x_inits pinnacle310e_init[] = {
};
/* ir keymaps */
-static struct dvb_usb_rc_key ir_codes_megasky_table [] = {
+static struct ir_scancode ir_codes_megasky_table[] = {
{ 0x0012, KEY_POWER },
{ 0x001e, KEY_CYCLEWINDOWS }, /* min/max */
{ 0x0002, KEY_CHANNELUP },
@@ -608,7 +608,7 @@ static struct dvb_usb_rc_key ir_codes_megasky_table [] = {
{ 0x000e, KEY_COFFEE }, /* "MTS" */
};
-static struct dvb_usb_rc_key ir_codes_tvwalkertwin_table [] = {
+static struct ir_scancode ir_codes_tvwalkertwin_table[] = {
{ 0x0001, KEY_ZOOM }, /* Full Screen */
{ 0x0002, KEY_CAMERA }, /* snapshot */
{ 0x0003, KEY_MUTE },
@@ -628,7 +628,7 @@ static struct dvb_usb_rc_key ir_codes_tvwalkertwin_table [] = {
{ 0x001e, KEY_VOLUMEUP },
};
-static struct dvb_usb_rc_key ir_codes_pinnacle310e_table[] = {
+static struct ir_scancode ir_codes_pinnacle310e_table[] = {
{ 0x16, KEY_POWER },
{ 0x17, KEY_FAVORITES },
{ 0x0f, KEY_TEXT },
@@ -784,10 +784,12 @@ static struct dvb_usb_device_properties megasky_properties = {
.firmware = "dvb-usb-megasky-02.fw",
.download_firmware = m920x_firmware_download,
- .rc_interval = 100,
- .rc_key_map = ir_codes_megasky_table,
- .rc_key_map_size = ARRAY_SIZE(ir_codes_megasky_table),
- .rc_query = m920x_rc_query,
+ .rc.legacy = {
+ .rc_interval = 100,
+ .rc_key_map = ir_codes_megasky_table,
+ .rc_key_map_size = ARRAY_SIZE(ir_codes_megasky_table),
+ .rc_query = m920x_rc_query,
+ },
.size_of_priv = sizeof(struct m920x_state),
@@ -885,10 +887,12 @@ static struct dvb_usb_device_properties tvwalkertwin_properties = {
.firmware = "dvb-usb-tvwalkert.fw",
.download_firmware = m920x_firmware_download,
- .rc_interval = 100,
- .rc_key_map = ir_codes_tvwalkertwin_table,
- .rc_key_map_size = ARRAY_SIZE(ir_codes_tvwalkertwin_table),
- .rc_query = m920x_rc_query,
+ .rc.legacy = {
+ .rc_interval = 100,
+ .rc_key_map = ir_codes_tvwalkertwin_table,
+ .rc_key_map_size = ARRAY_SIZE(ir_codes_tvwalkertwin_table),
+ .rc_query = m920x_rc_query,
+ },
.size_of_priv = sizeof(struct m920x_state),
@@ -992,10 +996,12 @@ static struct dvb_usb_device_properties pinnacle_pctv310e_properties = {
.usb_ctrl = DEVICE_SPECIFIC,
.download_firmware = NULL,
- .rc_interval = 100,
- .rc_key_map = ir_codes_pinnacle310e_table,
- .rc_key_map_size = ARRAY_SIZE(ir_codes_pinnacle310e_table),
- .rc_query = m920x_rc_query,
+ .rc.legacy = {
+ .rc_interval = 100,
+ .rc_key_map = ir_codes_pinnacle310e_table,
+ .rc_key_map_size = ARRAY_SIZE(ir_codes_pinnacle310e_table),
+ .rc_query = m920x_rc_query,
+ },
.size_of_priv = sizeof(struct m920x_state),
diff --git a/drivers/media/dvb/dvb-usb/nova-t-usb2.c b/drivers/media/dvb/dvb-usb/nova-t-usb2.c
index d195a587cc6..181f36a12e2 100644
--- a/drivers/media/dvb/dvb-usb/nova-t-usb2.c
+++ b/drivers/media/dvb/dvb-usb/nova-t-usb2.c
@@ -21,7 +21,7 @@ DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
#define deb_ee(args...) dprintk(debug,0x02,args)
/* Hauppauge NOVA-T USB2 keys */
-static struct dvb_usb_rc_key ir_codes_haupp_table [] = {
+static struct ir_scancode ir_codes_haupp_table[] = {
{ 0x1e00, KEY_0 },
{ 0x1e01, KEY_1 },
{ 0x1e02, KEY_2 },
@@ -98,7 +98,7 @@ static int nova_t_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
deb_rc("c: %x, d: %x\n", rc5_data(&ir_codes_haupp_table[i]),
rc5_custom(&ir_codes_haupp_table[i]));
- *event = ir_codes_haupp_table[i].event;
+ *event = ir_codes_haupp_table[i].keycode;
*state = REMOTE_KEY_PRESSED;
if (st->old_toggle == toggle) {
if (st->last_repeat_count++ < 2)
@@ -195,10 +195,12 @@ static struct dvb_usb_device_properties nova_t_properties = {
.power_ctrl = dibusb2_0_power_ctrl,
.read_mac_address = nova_t_read_mac_address,
- .rc_interval = 100,
- .rc_key_map = ir_codes_haupp_table,
- .rc_key_map_size = ARRAY_SIZE(ir_codes_haupp_table),
- .rc_query = nova_t_rc_query,
+ .rc.legacy = {
+ .rc_interval = 100,
+ .rc_key_map = ir_codes_haupp_table,
+ .rc_key_map_size = ARRAY_SIZE(ir_codes_haupp_table),
+ .rc_query = nova_t_rc_query,
+ },
.i2c_algo = &dibusb_i2c_algo,
diff --git a/drivers/media/dvb/dvb-usb/opera1.c b/drivers/media/dvb/dvb-usb/opera1.c
index dfb81ff1d9a..6b22ec64ab0 100644
--- a/drivers/media/dvb/dvb-usb/opera1.c
+++ b/drivers/media/dvb/dvb-usb/opera1.c
@@ -331,7 +331,7 @@ static int opera1_pid_filter_control(struct dvb_usb_adapter *adap, int onoff)
return 0;
}
-static struct dvb_usb_rc_key ir_codes_opera1_table[] = {
+static struct ir_scancode ir_codes_opera1_table[] = {
{0x5fa0, KEY_1},
{0x51af, KEY_2},
{0x5da2, KEY_3},
@@ -407,9 +407,9 @@ static int opera1_rc_query(struct dvb_usb_device *dev, u32 * event, int *state)
for (i = 0; i < ARRAY_SIZE(ir_codes_opera1_table); i++) {
if (rc5_scan(&ir_codes_opera1_table[i]) == (send_key & 0xffff)) {
*state = REMOTE_KEY_PRESSED;
- *event = ir_codes_opera1_table[i].event;
+ *event = ir_codes_opera1_table[i].keycode;
opst->last_key_pressed =
- ir_codes_opera1_table[i].event;
+ ir_codes_opera1_table[i].keycode;
break;
}
opst->last_key_pressed = 0;
@@ -498,10 +498,12 @@ static struct dvb_usb_device_properties opera1_properties = {
.power_ctrl = opera1_power_ctrl,
.i2c_algo = &opera1_i2c_algo,
- .rc_key_map = ir_codes_opera1_table,
- .rc_key_map_size = ARRAY_SIZE(ir_codes_opera1_table),
- .rc_interval = 200,
- .rc_query = opera1_rc_query,
+ .rc.legacy = {
+ .rc_key_map = ir_codes_opera1_table,
+ .rc_key_map_size = ARRAY_SIZE(ir_codes_opera1_table),
+ .rc_interval = 200,
+ .rc_query = opera1_rc_query,
+ },
.read_mac_address = opera1_read_mac_address,
.generic_bulk_ctrl_endpoint = 0x00,
/* parameter for the MPEG2-data transfer */
diff --git a/drivers/media/dvb/dvb-usb/vp702x.c b/drivers/media/dvb/dvb-usb/vp702x.c
index 4d332451653..5c9f3275aaa 100644
--- a/drivers/media/dvb/dvb-usb/vp702x.c
+++ b/drivers/media/dvb/dvb-usb/vp702x.c
@@ -174,7 +174,7 @@ static int vp702x_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
}
/* keys for the enclosed remote control */
-static struct dvb_usb_rc_key ir_codes_vp702x_table[] = {
+static struct ir_scancode ir_codes_vp702x_table[] = {
{ 0x0001, KEY_1 },
{ 0x0002, KEY_2 },
};
@@ -200,7 +200,7 @@ static int vp702x_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
for (i = 0; i < ARRAY_SIZE(ir_codes_vp702x_table); i++)
if (rc5_custom(&ir_codes_vp702x_table[i]) == key[1]) {
*state = REMOTE_KEY_PRESSED;
- *event = ir_codes_vp702x_table[i].event;
+ *event = ir_codes_vp702x_table[i].keycode;
break;
}
return 0;
@@ -283,10 +283,12 @@ static struct dvb_usb_device_properties vp702x_properties = {
},
.read_mac_address = vp702x_read_mac_addr,
- .rc_key_map = ir_codes_vp702x_table,
- .rc_key_map_size = ARRAY_SIZE(ir_codes_vp702x_table),
- .rc_interval = 400,
- .rc_query = vp702x_rc_query,
+ .rc.legacy = {
+ .rc_key_map = ir_codes_vp702x_table,
+ .rc_key_map_size = ARRAY_SIZE(ir_codes_vp702x_table),
+ .rc_interval = 400,
+ .rc_query = vp702x_rc_query,
+ },
.num_device_descs = 1,
.devices = {
diff --git a/drivers/media/dvb/dvb-usb/vp7045.c b/drivers/media/dvb/dvb-usb/vp7045.c
index 036893fa448..f13791ca599 100644
--- a/drivers/media/dvb/dvb-usb/vp7045.c
+++ b/drivers/media/dvb/dvb-usb/vp7045.c
@@ -99,7 +99,7 @@ static int vp7045_power_ctrl(struct dvb_usb_device *d, int onoff)
/* The keymapping struct. Somehow this should be loaded to the driver, but
* currently it is hardcoded. */
-static struct dvb_usb_rc_key ir_codes_vp7045_table[] = {
+static struct ir_scancode ir_codes_vp7045_table[] = {
{ 0x0016, KEY_POWER },
{ 0x0010, KEY_MUTE },
{ 0x0003, KEY_1 },
@@ -168,7 +168,7 @@ static int vp7045_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
for (i = 0; i < ARRAY_SIZE(ir_codes_vp7045_table); i++)
if (rc5_data(&ir_codes_vp7045_table[i]) == key) {
*state = REMOTE_KEY_PRESSED;
- *event = ir_codes_vp7045_table[i].event;
+ *event = ir_codes_vp7045_table[i].keycode;
break;
}
return 0;
@@ -259,10 +259,12 @@ static struct dvb_usb_device_properties vp7045_properties = {
.power_ctrl = vp7045_power_ctrl,
.read_mac_address = vp7045_read_mac_addr,
- .rc_interval = 400,
- .rc_key_map = ir_codes_vp7045_table,
- .rc_key_map_size = ARRAY_SIZE(ir_codes_vp7045_table),
- .rc_query = vp7045_rc_query,
+ .rc.legacy = {
+ .rc_interval = 400,
+ .rc_key_map = ir_codes_vp7045_table,
+ .rc_key_map_size = ARRAY_SIZE(ir_codes_vp7045_table),
+ .rc_query = vp7045_rc_query,
+ },
.num_device_descs = 2,
.devices = {
diff --git a/drivers/media/dvb/firewire/firedtv-fw.c b/drivers/media/dvb/firewire/firedtv-fw.c
index 75afe4f81e3..7424b0493f9 100644
--- a/drivers/media/dvb/firewire/firedtv-fw.c
+++ b/drivers/media/dvb/firewire/firedtv-fw.c
@@ -194,8 +194,8 @@ static const struct firedtv_backend backend = {
static void handle_fcp(struct fw_card *card, struct fw_request *request,
int tcode, int destination, int source, int generation,
- int speed, unsigned long long offset,
- void *payload, size_t length, void *callback_data)
+ unsigned long long offset, void *payload, size_t length,
+ void *callback_data)
{
struct firedtv *f, *fdtv = NULL;
struct fw_device *device;
diff --git a/drivers/media/dvb/frontends/Kconfig b/drivers/media/dvb/frontends/Kconfig
index cd7f9b7cbff..51d578a758a 100644
--- a/drivers/media/dvb/frontends/Kconfig
+++ b/drivers/media/dvb/frontends/Kconfig
@@ -584,6 +584,7 @@ config DVB_LGS8GL5
config DVB_LGS8GXX
tristate "Legend Silicon LGS8913/LGS8GL5/LGS8GXX DMB-TH demodulator"
depends on DVB_CORE && I2C
+ select FW_LOADER
default m if DVB_FE_CUSTOMISE
help
A DMB-TH tuner module. Say Y when you want to support this frontend.
diff --git a/drivers/media/dvb/frontends/af9013.c b/drivers/media/dvb/frontends/af9013.c
index 12e018b4107..dac917f7bb7 100644
--- a/drivers/media/dvb/frontends/af9013.c
+++ b/drivers/media/dvb/frontends/af9013.c
@@ -1,5 +1,5 @@
/*
- * DVB USB Linux driver for Afatech AF9015 DVB-T USB2.0 receiver
+ * Afatech AF9013 demodulator driver
*
* Copyright (C) 2007 Antti Palosaari <crope@iki.fi>
*
@@ -761,6 +761,10 @@ static int af9013_set_frontend(struct dvb_frontend *fe,
state->frequency = params->frequency;
+ /* program tuner */
+ if (fe->ops.tuner_ops.set_params)
+ fe->ops.tuner_ops.set_params(fe, params);
+
/* program CFOE coefficients */
ret = af9013_set_coeff(state, params->u.ofdm.bandwidth);
if (ret)
@@ -791,10 +795,6 @@ static int af9013_set_frontend(struct dvb_frontend *fe,
if (ret)
goto error;
- /* program tuner */
- if (fe->ops.tuner_ops.set_params)
- fe->ops.tuner_ops.set_params(fe, params);
-
/* program TPS and bandwidth, check if auto mode needed */
ret = af9013_set_ofdm_params(state, &params->u.ofdm, &auto_mode);
if (ret)
@@ -1184,45 +1184,49 @@ static int af9013_read_status(struct dvb_frontend *fe, fe_status_t *status)
u8 tmp;
*status = 0;
- /* TPS lock */
- ret = af9013_read_reg_bits(state, 0xd330, 3, 1, &tmp);
- if (ret)
- goto error;
- if (tmp)
- *status |= FE_HAS_VITERBI | FE_HAS_CARRIER | FE_HAS_SIGNAL;
-
/* MPEG2 lock */
ret = af9013_read_reg_bits(state, 0xd507, 6, 1, &tmp);
if (ret)
goto error;
if (tmp)
- *status |= FE_HAS_SYNC | FE_HAS_LOCK;
+ *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_VITERBI |
+ FE_HAS_SYNC | FE_HAS_LOCK;
- if (!(*status & FE_HAS_SIGNAL)) {
- /* AGC lock */
- ret = af9013_read_reg_bits(state, 0xd1a0, 6, 1, &tmp);
+ if (!*status) {
+ /* TPS lock */
+ ret = af9013_read_reg_bits(state, 0xd330, 3, 1, &tmp);
if (ret)
goto error;
if (tmp)
- *status |= FE_HAS_SIGNAL;
+ *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER |
+ FE_HAS_VITERBI;
}
- if (!(*status & FE_HAS_CARRIER)) {
+ if (!*status) {
/* CFO lock */
ret = af9013_read_reg_bits(state, 0xd333, 7, 1, &tmp);
if (ret)
goto error;
if (tmp)
- *status |= FE_HAS_CARRIER;
+ *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER;
}
- if (!(*status & FE_HAS_CARRIER)) {
+ if (!*status) {
/* SFOE lock */
ret = af9013_read_reg_bits(state, 0xd334, 6, 1, &tmp);
if (ret)
goto error;
if (tmp)
- *status |= FE_HAS_CARRIER;
+ *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER;
+ }
+
+ if (!*status) {
+ /* AGC lock */
+ ret = af9013_read_reg_bits(state, 0xd1a0, 6, 1, &tmp);
+ if (ret)
+ goto error;
+ if (tmp)
+ *status |= FE_HAS_SIGNAL;
}
ret = af9013_update_statistics(fe);
@@ -1574,7 +1578,7 @@ struct dvb_frontend *af9013_attach(const struct af9013_config *config,
{
int ret;
struct af9013_state *state = NULL;
- u8 buf[3], i;
+ u8 buf[4], i;
/* allocate memory for the internal state */
state = kzalloc(sizeof(struct af9013_state), GFP_KERNEL);
@@ -1607,12 +1611,12 @@ struct dvb_frontend *af9013_attach(const struct af9013_config *config,
}
/* firmware version */
- for (i = 0; i < 3; i++) {
+ for (i = 0; i < 4; i++) {
ret = af9013_read_reg(state, 0x5103 + i, &buf[i]);
if (ret)
goto error;
}
- info("firmware version:%d.%d.%d", buf[0], buf[1], buf[2]);
+ info("firmware version:%d.%d.%d.%d", buf[0], buf[1], buf[2], buf[3]);
/* settings for mp2if */
if (state->config.output_mode == AF9013_OUTPUT_MODE_USB) {
diff --git a/drivers/media/dvb/frontends/af9013.h b/drivers/media/dvb/frontends/af9013.h
index e90fa92b1c1..72c71bb5d11 100644
--- a/drivers/media/dvb/frontends/af9013.h
+++ b/drivers/media/dvb/frontends/af9013.h
@@ -1,5 +1,5 @@
/*
- * DVB USB Linux driver for Afatech AF9015 DVB-T USB2.0 receiver
+ * Afatech AF9013 demodulator driver
*
* Copyright (C) 2007 Antti Palosaari <crope@iki.fi>
*
diff --git a/drivers/media/dvb/frontends/af9013_priv.h b/drivers/media/dvb/frontends/af9013_priv.h
index 163e251d0b7..0fd42b7e248 100644
--- a/drivers/media/dvb/frontends/af9013_priv.h
+++ b/drivers/media/dvb/frontends/af9013_priv.h
@@ -1,5 +1,5 @@
/*
- * DVB USB Linux driver for Afatech AF9015 DVB-T USB2.0 receiver
+ * Afatech AF9013 demodulator driver
*
* Copyright (C) 2007 Antti Palosaari <crope@iki.fi>
*
@@ -132,6 +132,8 @@ static struct regdesc ofsm_init[] = {
{ 0xd740, 2, 1, 0x00 },
{ 0xd740, 3, 1, 0x01 },
{ 0xd3c1, 4, 1, 0x01 },
+ { 0x9124, 0, 8, 0x58 },
+ { 0x9125, 0, 2, 0x02 },
{ 0xd3a2, 0, 8, 0x00 },
{ 0xd3a3, 0, 8, 0x04 },
{ 0xd305, 0, 8, 0x32 },
@@ -143,7 +145,7 @@ static struct regdesc ofsm_init[] = {
{ 0x911b, 0, 1, 0x01 },
{ 0x9bce, 0, 4, 0x02 },
{ 0x9116, 0, 1, 0x01 },
- { 0x9bd1, 0, 1, 0x01 },
+ { 0x9122, 0, 8, 0xd0 },
{ 0xd2e0, 0, 8, 0xd0 },
{ 0xd2e9, 0, 4, 0x0d },
{ 0xd38c, 0, 8, 0xfc },
@@ -165,7 +167,6 @@ static struct regdesc ofsm_init[] = {
{ 0xd081, 4, 4, 0x09 },
{ 0xd098, 4, 4, 0x0f },
{ 0xd098, 0, 4, 0x03 },
- { 0xdbc0, 3, 1, 0x01 },
{ 0xdbc0, 4, 1, 0x01 },
{ 0xdbc7, 0, 8, 0x08 },
{ 0xdbc8, 4, 4, 0x00 },
@@ -179,6 +180,7 @@ static struct regdesc ofsm_init[] = {
{ 0xd0f0, 0, 7, 0x1a },
{ 0xd0f1, 4, 1, 0x01 },
{ 0xd0f2, 0, 8, 0x0c },
+ { 0xd101, 5, 3, 0x06 },
{ 0xd103, 0, 4, 0x08 },
{ 0xd0f8, 0, 7, 0x20 },
{ 0xd111, 5, 1, 0x00 },
diff --git a/drivers/media/dvb/frontends/dib3000mb.c b/drivers/media/dvb/frontends/dib3000mb.c
index ad4c8cfd809..e80c5979636 100644
--- a/drivers/media/dvb/frontends/dib3000mb.c
+++ b/drivers/media/dvb/frontends/dib3000mb.c
@@ -38,11 +38,10 @@
#define DRIVER_DESC "DiBcom 3000M-B DVB-T demodulator"
#define DRIVER_AUTHOR "Patrick Boettcher, patrick.boettcher@desy.de"
-#ifdef CONFIG_DVB_DIBCOM_DEBUG
static int debug;
module_param(debug, int, 0644);
MODULE_PARM_DESC(debug, "set debugging level (1=info,2=xfer,4=setfe,8=getfe (|-able)).");
-#endif
+
#define deb_info(args...) dprintk(0x01,args)
#define deb_i2c(args...) dprintk(0x02,args)
#define deb_srch(args...) dprintk(0x04,args)
@@ -51,12 +50,6 @@ MODULE_PARM_DESC(debug, "set debugging level (1=info,2=xfer,4=setfe,8=getfe (|-a
#define deb_setf(args...) dprintk(0x04,args)
#define deb_getf(args...) dprintk(0x08,args)
-#ifdef CONFIG_DVB_DIBCOM_DEBUG
-static int debug;
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "set debugging level (1=info,2=i2c,4=srch (|-able)).");
-#endif
-
static int dib3000_read_reg(struct dib3000_state *state, u16 reg)
{
u8 wb[] = { ((reg >> 8) | 0x80) & 0xff, reg & 0xff };
diff --git a/drivers/media/dvb/frontends/dib3000mb_priv.h b/drivers/media/dvb/frontends/dib3000mb_priv.h
index 1a12747fdc9..16c526591f3 100644
--- a/drivers/media/dvb/frontends/dib3000mb_priv.h
+++ b/drivers/media/dvb/frontends/dib3000mb_priv.h
@@ -37,12 +37,8 @@
/* debug */
-#ifdef CONFIG_DVB_DIBCOM_DEBUG
#define dprintk(level,args...) \
do { if ((debug & level)) { printk(args); } } while (0)
-#else
-#define dprintk(args...) do { } while (0)
-#endif
/* mask for enabling a specific pid for the pid_filter */
#define DIB3000_ACTIVATE_PID_FILTERING (0x2000)
diff --git a/drivers/media/dvb/frontends/dib3000mc.c b/drivers/media/dvb/frontends/dib3000mc.c
index afad252abf4..088e7fadbe3 100644
--- a/drivers/media/dvb/frontends/dib3000mc.c
+++ b/drivers/media/dvb/frontends/dib3000mc.c
@@ -822,7 +822,7 @@ int dib3000mc_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 defa
dmcst = kzalloc(sizeof(struct dib3000mc_state), GFP_KERNEL);
if (dmcst == NULL)
- return -ENODEV;
+ return -ENOMEM;
dmcst->i2c_adap = i2c;
diff --git a/drivers/media/dvb/frontends/lgdt3305.c b/drivers/media/dvb/frontends/lgdt3305.c
index d69c775f864..3272881cb11 100644
--- a/drivers/media/dvb/frontends/lgdt3305.c
+++ b/drivers/media/dvb/frontends/lgdt3305.c
@@ -1,7 +1,9 @@
/*
- * Support for LGDT3305 - VSB/QAM
+ * Support for LG Electronics LGDT3304 and LGDT3305 - VSB/QAM
*
- * Copyright (C) 2008, 2009 Michael Krufky <mkrufky@linuxtv.org>
+ * Copyright (C) 2008, 2009, 2010 Michael Krufky <mkrufky@linuxtv.org>
+ *
+ * LGDT3304 support by Jarod Wilson <jarod@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
@@ -65,6 +67,8 @@ struct lgdt3305_state {
/* ------------------------------------------------------------------------ */
+/* FIXME: verify & document the LGDT3304 registers */
+
#define LGDT3305_GEN_CTRL_1 0x0000
#define LGDT3305_GEN_CTRL_2 0x0001
#define LGDT3305_GEN_CTRL_3 0x0002
@@ -358,7 +362,12 @@ static int lgdt3305_rfagc_loop(struct lgdt3305_state *state,
case QAM_256:
agcdelay = 0x046b;
rfbw = 0x8889;
- ifbw = 0x8888;
+ /* FIXME: investigate optimal ifbw & rfbw values for the
+ * DT3304 and re-write this switch..case block */
+ if (state->cfg->demod_chip == LGDT3304)
+ ifbw = 0x6666;
+ else /* (state->cfg->demod_chip == LGDT3305) */
+ ifbw = 0x8888;
break;
default:
return -EINVAL;
@@ -410,8 +419,18 @@ static int lgdt3305_agc_setup(struct lgdt3305_state *state,
lg_dbg("lockdten = %d, acqen = %d\n", lockdten, acqen);
/* control agc function */
- lgdt3305_write_reg(state, LGDT3305_AGC_CTRL_4, 0xe1 | lockdten << 1);
- lgdt3305_set_reg_bit(state, LGDT3305_AGC_CTRL_1, 2, acqen);
+ switch (state->cfg->demod_chip) {
+ case LGDT3304:
+ lgdt3305_write_reg(state, 0x0314, 0xe1 | lockdten << 1);
+ lgdt3305_set_reg_bit(state, 0x030e, 2, acqen);
+ break;
+ case LGDT3305:
+ lgdt3305_write_reg(state, LGDT3305_AGC_CTRL_4, 0xe1 | lockdten << 1);
+ lgdt3305_set_reg_bit(state, LGDT3305_AGC_CTRL_1, 2, acqen);
+ break;
+ default:
+ return -EINVAL;
+ }
return lgdt3305_rfagc_loop(state, param);
}
@@ -577,61 +596,79 @@ static int lgdt3305_init(struct dvb_frontend *fe)
struct lgdt3305_state *state = fe->demodulator_priv;
int ret;
+ static struct lgdt3305_reg lgdt3304_init_data[] = {
+ { .reg = LGDT3305_GEN_CTRL_1, .val = 0x03, },
+ { .reg = 0x000d, .val = 0x02, },
+ { .reg = 0x000e, .val = 0x02, },
+ { .reg = LGDT3305_DGTL_AGC_REF_1, .val = 0x32, },
+ { .reg = LGDT3305_DGTL_AGC_REF_2, .val = 0xc4, },
+ { .reg = LGDT3305_CR_CTR_FREQ_1, .val = 0x00, },
+ { .reg = LGDT3305_CR_CTR_FREQ_2, .val = 0x00, },
+ { .reg = LGDT3305_CR_CTR_FREQ_3, .val = 0x00, },
+ { .reg = LGDT3305_CR_CTR_FREQ_4, .val = 0x00, },
+ { .reg = LGDT3305_CR_CTRL_7, .val = 0xf9, },
+ { .reg = 0x0112, .val = 0x17, },
+ { .reg = 0x0113, .val = 0x15, },
+ { .reg = 0x0114, .val = 0x18, },
+ { .reg = 0x0115, .val = 0xff, },
+ { .reg = 0x0116, .val = 0x3c, },
+ { .reg = 0x0214, .val = 0x67, },
+ { .reg = 0x0424, .val = 0x8d, },
+ { .reg = 0x0427, .val = 0x12, },
+ { .reg = 0x0428, .val = 0x4f, },
+ { .reg = LGDT3305_IFBW_1, .val = 0x80, },
+ { .reg = LGDT3305_IFBW_2, .val = 0x00, },
+ { .reg = 0x030a, .val = 0x08, },
+ { .reg = 0x030b, .val = 0x9b, },
+ { .reg = 0x030d, .val = 0x00, },
+ { .reg = 0x030e, .val = 0x1c, },
+ { .reg = 0x0314, .val = 0xe1, },
+ { .reg = 0x000d, .val = 0x82, },
+ { .reg = LGDT3305_TP_CTRL_1, .val = 0x5b, },
+ { .reg = LGDT3305_TP_CTRL_1, .val = 0x5b, },
+ };
+
static struct lgdt3305_reg lgdt3305_init_data[] = {
- { .reg = LGDT3305_GEN_CTRL_1,
- .val = 0x03, },
- { .reg = LGDT3305_GEN_CTRL_2,
- .val = 0xb0, },
- { .reg = LGDT3305_GEN_CTRL_3,
- .val = 0x01, },
- { .reg = LGDT3305_GEN_CONTROL,
- .val = 0x6f, },
- { .reg = LGDT3305_GEN_CTRL_4,
- .val = 0x03, },
- { .reg = LGDT3305_DGTL_AGC_REF_1,
- .val = 0x32, },
- { .reg = LGDT3305_DGTL_AGC_REF_2,
- .val = 0xc4, },
- { .reg = LGDT3305_CR_CTR_FREQ_1,
- .val = 0x00, },
- { .reg = LGDT3305_CR_CTR_FREQ_2,
- .val = 0x00, },
- { .reg = LGDT3305_CR_CTR_FREQ_3,
- .val = 0x00, },
- { .reg = LGDT3305_CR_CTR_FREQ_4,
- .val = 0x00, },
- { .reg = LGDT3305_CR_CTRL_7,
- .val = 0x79, },
- { .reg = LGDT3305_AGC_POWER_REF_1,
- .val = 0x32, },
- { .reg = LGDT3305_AGC_POWER_REF_2,
- .val = 0xc4, },
- { .reg = LGDT3305_AGC_DELAY_PT_1,
- .val = 0x0d, },
- { .reg = LGDT3305_AGC_DELAY_PT_2,
- .val = 0x30, },
- { .reg = LGDT3305_RFAGC_LOOP_FLTR_BW_1,
- .val = 0x80, },
- { .reg = LGDT3305_RFAGC_LOOP_FLTR_BW_2,
- .val = 0x00, },
- { .reg = LGDT3305_IFBW_1,
- .val = 0x80, },
- { .reg = LGDT3305_IFBW_2,
- .val = 0x00, },
- { .reg = LGDT3305_AGC_CTRL_1,
- .val = 0x30, },
- { .reg = LGDT3305_AGC_CTRL_4,
- .val = 0x61, },
- { .reg = LGDT3305_FEC_BLOCK_CTRL,
- .val = 0xff, },
- { .reg = LGDT3305_TP_CTRL_1,
- .val = 0x1b, },
+ { .reg = LGDT3305_GEN_CTRL_1, .val = 0x03, },
+ { .reg = LGDT3305_GEN_CTRL_2, .val = 0xb0, },
+ { .reg = LGDT3305_GEN_CTRL_3, .val = 0x01, },
+ { .reg = LGDT3305_GEN_CONTROL, .val = 0x6f, },
+ { .reg = LGDT3305_GEN_CTRL_4, .val = 0x03, },
+ { .reg = LGDT3305_DGTL_AGC_REF_1, .val = 0x32, },
+ { .reg = LGDT3305_DGTL_AGC_REF_2, .val = 0xc4, },
+ { .reg = LGDT3305_CR_CTR_FREQ_1, .val = 0x00, },
+ { .reg = LGDT3305_CR_CTR_FREQ_2, .val = 0x00, },
+ { .reg = LGDT3305_CR_CTR_FREQ_3, .val = 0x00, },
+ { .reg = LGDT3305_CR_CTR_FREQ_4, .val = 0x00, },
+ { .reg = LGDT3305_CR_CTRL_7, .val = 0x79, },
+ { .reg = LGDT3305_AGC_POWER_REF_1, .val = 0x32, },
+ { .reg = LGDT3305_AGC_POWER_REF_2, .val = 0xc4, },
+ { .reg = LGDT3305_AGC_DELAY_PT_1, .val = 0x0d, },
+ { .reg = LGDT3305_AGC_DELAY_PT_2, .val = 0x30, },
+ { .reg = LGDT3305_RFAGC_LOOP_FLTR_BW_1, .val = 0x80, },
+ { .reg = LGDT3305_RFAGC_LOOP_FLTR_BW_2, .val = 0x00, },
+ { .reg = LGDT3305_IFBW_1, .val = 0x80, },
+ { .reg = LGDT3305_IFBW_2, .val = 0x00, },
+ { .reg = LGDT3305_AGC_CTRL_1, .val = 0x30, },
+ { .reg = LGDT3305_AGC_CTRL_4, .val = 0x61, },
+ { .reg = LGDT3305_FEC_BLOCK_CTRL, .val = 0xff, },
+ { .reg = LGDT3305_TP_CTRL_1, .val = 0x1b, },
};
lg_dbg("\n");
- ret = lgdt3305_write_regs(state, lgdt3305_init_data,
- ARRAY_SIZE(lgdt3305_init_data));
+ switch (state->cfg->demod_chip) {
+ case LGDT3304:
+ ret = lgdt3305_write_regs(state, lgdt3304_init_data,
+ ARRAY_SIZE(lgdt3304_init_data));
+ break;
+ case LGDT3305:
+ ret = lgdt3305_write_regs(state, lgdt3305_init_data,
+ ARRAY_SIZE(lgdt3305_init_data));
+ break;
+ default:
+ ret = -EINVAL;
+ }
if (lg_fail(ret))
goto fail;
@@ -640,6 +677,76 @@ fail:
return ret;
}
+static int lgdt3304_set_parameters(struct dvb_frontend *fe,
+ struct dvb_frontend_parameters *param)
+{
+ struct lgdt3305_state *state = fe->demodulator_priv;
+ int ret;
+
+ lg_dbg("(%d, %d)\n", param->frequency, param->u.vsb.modulation);
+
+ if (fe->ops.tuner_ops.set_params) {
+ ret = fe->ops.tuner_ops.set_params(fe, param);
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 0);
+ if (lg_fail(ret))
+ goto fail;
+ state->current_frequency = param->frequency;
+ }
+
+ ret = lgdt3305_set_modulation(state, param);
+ if (lg_fail(ret))
+ goto fail;
+
+ ret = lgdt3305_passband_digital_agc(state, param);
+ if (lg_fail(ret))
+ goto fail;
+
+ ret = lgdt3305_agc_setup(state, param);
+ if (lg_fail(ret))
+ goto fail;
+
+ /* reg 0x030d is 3304-only... seen in vsb and qam usbsnoops... */
+ switch (param->u.vsb.modulation) {
+ case VSB_8:
+ lgdt3305_write_reg(state, 0x030d, 0x00);
+ lgdt3305_write_reg(state, LGDT3305_CR_CTR_FREQ_1, 0x4f);
+ lgdt3305_write_reg(state, LGDT3305_CR_CTR_FREQ_2, 0x0c);
+ lgdt3305_write_reg(state, LGDT3305_CR_CTR_FREQ_3, 0xac);
+ lgdt3305_write_reg(state, LGDT3305_CR_CTR_FREQ_4, 0xba);
+ break;
+ case QAM_64:
+ case QAM_256:
+ lgdt3305_write_reg(state, 0x030d, 0x14);
+ ret = lgdt3305_set_if(state, param);
+ if (lg_fail(ret))
+ goto fail;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+
+ ret = lgdt3305_spectral_inversion(state, param,
+ state->cfg->spectral_inversion
+ ? 1 : 0);
+ if (lg_fail(ret))
+ goto fail;
+
+ state->current_modulation = param->u.vsb.modulation;
+
+ ret = lgdt3305_mpeg_mode(state, state->cfg->mpeg_mode);
+ if (lg_fail(ret))
+ goto fail;
+
+ /* lgdt3305_mpeg_mode_polarity calls lgdt3305_soft_reset */
+ ret = lgdt3305_mpeg_mode_polarity(state,
+ state->cfg->tpclk_edge,
+ state->cfg->tpvalid_polarity);
+fail:
+ return ret;
+}
+
static int lgdt3305_set_parameters(struct dvb_frontend *fe,
struct dvb_frontend_parameters *param)
{
@@ -848,6 +955,10 @@ static int lgdt3305_read_status(struct dvb_frontend *fe, fe_status_t *status)
switch (state->current_modulation) {
case QAM_256:
case QAM_64:
+ /* signal bit is unreliable on the DT3304 in QAM mode */
+ if (((LGDT3304 == state->cfg->demod_chip)) && (cr_lock))
+ *status |= FE_HAS_SIGNAL;
+
ret = lgdt3305_read_fec_lock_status(state, &fec_lock);
if (lg_fail(ret))
goto fail;
@@ -993,6 +1104,7 @@ static void lgdt3305_release(struct dvb_frontend *fe)
kfree(state);
}
+static struct dvb_frontend_ops lgdt3304_ops;
static struct dvb_frontend_ops lgdt3305_ops;
struct dvb_frontend *lgdt3305_attach(const struct lgdt3305_config *config,
@@ -1013,11 +1125,21 @@ struct dvb_frontend *lgdt3305_attach(const struct lgdt3305_config *config,
state->cfg = config;
state->i2c_adap = i2c_adap;
- memcpy(&state->frontend.ops, &lgdt3305_ops,
- sizeof(struct dvb_frontend_ops));
+ switch (config->demod_chip) {
+ case LGDT3304:
+ memcpy(&state->frontend.ops, &lgdt3304_ops,
+ sizeof(struct dvb_frontend_ops));
+ break;
+ case LGDT3305:
+ memcpy(&state->frontend.ops, &lgdt3305_ops,
+ sizeof(struct dvb_frontend_ops));
+ break;
+ default:
+ goto fail;
+ }
state->frontend.demodulator_priv = state;
- /* verify that we're talking to a lg dt3305 */
+ /* verify that we're talking to a lg dt3304/5 */
ret = lgdt3305_read_reg(state, LGDT3305_GEN_CTRL_2, &val);
if ((lg_fail(ret)) | (val == 0))
goto fail;
@@ -1036,12 +1158,35 @@ struct dvb_frontend *lgdt3305_attach(const struct lgdt3305_config *config,
return &state->frontend;
fail:
- lg_warn("unable to detect LGDT3305 hardware\n");
+ lg_warn("unable to detect %s hardware\n",
+ config->demod_chip ? "LGDT3304" : "LGDT3305");
kfree(state);
return NULL;
}
EXPORT_SYMBOL(lgdt3305_attach);
+static struct dvb_frontend_ops lgdt3304_ops = {
+ .info = {
+ .name = "LG Electronics LGDT3304 VSB/QAM Frontend",
+ .type = FE_ATSC,
+ .frequency_min = 54000000,
+ .frequency_max = 858000000,
+ .frequency_stepsize = 62500,
+ .caps = FE_CAN_QAM_64 | FE_CAN_QAM_256 | FE_CAN_8VSB
+ },
+ .i2c_gate_ctrl = lgdt3305_i2c_gate_ctrl,
+ .init = lgdt3305_init,
+ .set_frontend = lgdt3304_set_parameters,
+ .get_frontend = lgdt3305_get_frontend,
+ .get_tune_settings = lgdt3305_get_tune_settings,
+ .read_status = lgdt3305_read_status,
+ .read_ber = lgdt3305_read_ber,
+ .read_signal_strength = lgdt3305_read_signal_strength,
+ .read_snr = lgdt3305_read_snr,
+ .read_ucblocks = lgdt3305_read_ucblocks,
+ .release = lgdt3305_release,
+};
+
static struct dvb_frontend_ops lgdt3305_ops = {
.info = {
.name = "LG Electronics LGDT3305 VSB/QAM Frontend",
@@ -1065,10 +1210,10 @@ static struct dvb_frontend_ops lgdt3305_ops = {
.release = lgdt3305_release,
};
-MODULE_DESCRIPTION("LG Electronics LGDT3305 ATSC/QAM-B Demodulator Driver");
+MODULE_DESCRIPTION("LG Electronics LGDT3304/5 ATSC/QAM-B Demodulator Driver");
MODULE_AUTHOR("Michael Krufky <mkrufky@linuxtv.org>");
MODULE_LICENSE("GPL");
-MODULE_VERSION("0.1");
+MODULE_VERSION("0.2");
/*
* Local variables:
diff --git a/drivers/media/dvb/frontends/lgdt3305.h b/drivers/media/dvb/frontends/lgdt3305.h
index 9cb11c9cae5..02172eca4d4 100644
--- a/drivers/media/dvb/frontends/lgdt3305.h
+++ b/drivers/media/dvb/frontends/lgdt3305.h
@@ -1,7 +1,7 @@
/*
- * Support for LGDT3305 - VSB/QAM
+ * Support for LG Electronics LGDT3304 and LGDT3305 - VSB/QAM
*
- * Copyright (C) 2008, 2009 Michael Krufky <mkrufky@linuxtv.org>
+ * Copyright (C) 2008, 2009, 2010 Michael Krufky <mkrufky@linuxtv.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
@@ -41,6 +41,11 @@ enum lgdt3305_tp_valid_polarity {
LGDT3305_TP_VALID_HIGH = 1,
};
+enum lgdt_demod_chip_type {
+ LGDT3305 = 0,
+ LGDT3304 = 1,
+};
+
struct lgdt3305_config {
u8 i2c_addr;
@@ -65,6 +70,7 @@ struct lgdt3305_config {
enum lgdt3305_mpeg_mode mpeg_mode;
enum lgdt3305_tp_clock_edge tpclk_edge;
enum lgdt3305_tp_valid_polarity tpvalid_polarity;
+ enum lgdt_demod_chip_type demod_chip;
};
#if defined(CONFIG_DVB_LGDT3305) || (defined(CONFIG_DVB_LGDT3305_MODULE) && \
diff --git a/drivers/media/dvb/frontends/lgs8gxx.c b/drivers/media/dvb/frontends/lgs8gxx.c
index dee53960e7e..5ea28ae2ba8 100644
--- a/drivers/media/dvb/frontends/lgs8gxx.c
+++ b/drivers/media/dvb/frontends/lgs8gxx.c
@@ -24,6 +24,7 @@
*/
#include <asm/div64.h>
+#include <linux/firmware.h>
#include "dvb_frontend.h"
@@ -46,42 +47,6 @@ module_param(fake_signal_str, int, 0644);
MODULE_PARM_DESC(fake_signal_str, "fake signal strength for LGS8913."
"Signal strength calculation is slow.(default:on).");
-static const u8 lgs8g75_initdat[] = {
- 0x01, 0x30, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
- 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
- 0xE4, 0xF5, 0xA8, 0xF5, 0xB8, 0xF5, 0x88, 0xF5,
- 0x89, 0xF5, 0x87, 0x75, 0xD0, 0x00, 0x11, 0x50,
- 0x11, 0x50, 0xF4, 0xF5, 0x80, 0xF5, 0x90, 0xF5,
- 0xA0, 0xF5, 0xB0, 0x75, 0x81, 0x30, 0x80, 0x01,
- 0x32, 0x90, 0x80, 0x12, 0x74, 0xFF, 0xF0, 0x90,
- 0x80, 0x13, 0x74, 0x1F, 0xF0, 0x90, 0x80, 0x23,
- 0x74, 0x01, 0xF0, 0x90, 0x80, 0x22, 0xF0, 0x90,
- 0x00, 0x48, 0x74, 0x00, 0xF0, 0x90, 0x80, 0x4D,
- 0x74, 0x05, 0xF0, 0x90, 0x80, 0x09, 0xE0, 0x60,
- 0x21, 0x12, 0x00, 0xDD, 0x14, 0x60, 0x1B, 0x12,
- 0x00, 0xDD, 0x14, 0x60, 0x15, 0x12, 0x00, 0xDD,
- 0x14, 0x60, 0x0F, 0x12, 0x00, 0xDD, 0x14, 0x60,
- 0x09, 0x12, 0x00, 0xDD, 0x14, 0x60, 0x03, 0x12,
- 0x00, 0xDD, 0x90, 0x80, 0x42, 0xE0, 0x60, 0x0B,
- 0x14, 0x60, 0x0C, 0x14, 0x60, 0x0D, 0x14, 0x60,
- 0x0E, 0x01, 0xB3, 0x74, 0x04, 0x01, 0xB9, 0x74,
- 0x05, 0x01, 0xB9, 0x74, 0x07, 0x01, 0xB9, 0x74,
- 0x0A, 0xC0, 0xE0, 0x74, 0xC8, 0x12, 0x00, 0xE2,
- 0xD0, 0xE0, 0x14, 0x70, 0xF4, 0x90, 0x80, 0x09,
- 0xE0, 0x70, 0xAE, 0x12, 0x00, 0xF6, 0x12, 0x00,
- 0xFE, 0x90, 0x00, 0x48, 0xE0, 0x04, 0xF0, 0x90,
- 0x80, 0x4E, 0xF0, 0x01, 0x73, 0x90, 0x80, 0x08,
- 0xF0, 0x22, 0xF8, 0x7A, 0x0C, 0x79, 0xFD, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD9,
- 0xF6, 0xDA, 0xF2, 0xD8, 0xEE, 0x22, 0x90, 0x80,
- 0x65, 0xE0, 0x54, 0xFD, 0xF0, 0x22, 0x90, 0x80,
- 0x65, 0xE0, 0x44, 0xC2, 0xF0, 0x22
-};
-
/* LGS8GXX internal helper functions */
static int lgs8gxx_write_reg(struct lgs8gxx_state *priv, u8 reg, u8 data)
@@ -627,9 +592,14 @@ static int lgs8913_init(struct lgs8gxx_state *priv)
static int lgs8g75_init_data(struct lgs8gxx_state *priv)
{
- const u8 *p = lgs8g75_initdat;
+ const struct firmware *fw;
+ int rc;
int i;
+ rc = request_firmware(&fw, "lgs8g75.fw", &priv->i2c->dev);
+ if (rc)
+ return rc;
+
lgs8gxx_write_reg(priv, 0xC6, 0x40);
lgs8gxx_write_reg(priv, 0x3D, 0x04);
@@ -640,16 +610,16 @@ static int lgs8g75_init_data(struct lgs8gxx_state *priv)
lgs8gxx_write_reg(priv, 0x3B, 0x00);
lgs8gxx_write_reg(priv, 0x38, 0x00);
- for (i = 0; i < sizeof(lgs8g75_initdat); i++) {
+ for (i = 0; i < fw->size; i++) {
lgs8gxx_write_reg(priv, 0x38, 0x00);
lgs8gxx_write_reg(priv, 0x3A, (u8)(i&0xff));
lgs8gxx_write_reg(priv, 0x3B, (u8)(i>>8));
- lgs8gxx_write_reg(priv, 0x3C, *p);
- p++;
+ lgs8gxx_write_reg(priv, 0x3C, fw->data[i]);
}
lgs8gxx_write_reg(priv, 0x38, 0x00);
+ release_firmware(fw);
return 0;
}
diff --git a/drivers/media/dvb/frontends/mb86a16.c b/drivers/media/dvb/frontends/mb86a16.c
index 599d1aa519a..33b63235b86 100644
--- a/drivers/media/dvb/frontends/mb86a16.c
+++ b/drivers/media/dvb/frontends/mb86a16.c
@@ -1833,7 +1833,6 @@ static struct dvb_frontend_ops mb86a16_ops = {
.get_frontend_algo = mb86a16_frontend_algo,
.search = mb86a16_search,
- .read_status = mb86a16_read_status,
.init = mb86a16_init,
.sleep = mb86a16_sleep,
.read_status = mb86a16_read_status,
diff --git a/drivers/media/dvb/frontends/tda10048.c b/drivers/media/dvb/frontends/tda10048.c
index 4e2a7c8b2f6..93f6a75c238 100644
--- a/drivers/media/dvb/frontends/tda10048.c
+++ b/drivers/media/dvb/frontends/tda10048.c
@@ -25,6 +25,7 @@
#include <linux/string.h>
#include <linux/slab.h>
#include <linux/delay.h>
+#include <linux/math64.h>
#include <asm/div64.h>
#include "dvb_frontend.h"
#include "dvb_math.h"
@@ -49,8 +50,8 @@
#define TDA10048_CONF_C4_1 0x1E
#define TDA10048_CONF_C4_2 0x1F
#define TDA10048_CODE_IN_RAM 0x20
-#define TDA10048_CHANNEL_INFO_1_R 0x22
-#define TDA10048_CHANNEL_INFO_2_R 0x23
+#define TDA10048_CHANNEL_INFO1_R 0x22
+#define TDA10048_CHANNEL_INFO2_R 0x23
#define TDA10048_CHANNEL_INFO1 0x24
#define TDA10048_CHANNEL_INFO2 0x25
#define TDA10048_TIME_ERROR_R 0x26
@@ -63,8 +64,8 @@
#define TDA10048_IT_STAT 0x32
#define TDA10048_DSP_AD_LSB 0x3C
#define TDA10048_DSP_AD_MSB 0x3D
-#define TDA10048_DSP_REF_LSB 0x3E
-#define TDA10048_DSP_REF_MSB 0x3F
+#define TDA10048_DSP_REG_LSB 0x3E
+#define TDA10048_DSP_REG_MSB 0x3F
#define TDA10048_CONF_TRISTATE1 0x44
#define TDA10048_CONF_TRISTATE2 0x45
#define TDA10048_CONF_POLARITY 0x46
@@ -112,7 +113,7 @@
#define TDA10048_FREE_REG_1 0xB2
#define TDA10048_FREE_REG_2 0xB3
#define TDA10048_CONF_C3_1 0xC0
-#define TDA10048_CYBER_CTRL 0xC2
+#define TDA10048_CVBER_CTRL 0xC2
#define TDA10048_CBER_NMAX_LSB 0xC4
#define TDA10048_CBER_NMAX_MSB 0xC5
#define TDA10048_CBER_LSB 0xC6
@@ -120,7 +121,7 @@
#define TDA10048_VBER_LSB 0xC8
#define TDA10048_VBER_MID 0xC9
#define TDA10048_VBER_MSB 0xCA
-#define TDA10048_CYBER_LUT 0xCC
+#define TDA10048_CVBER_LUT 0xCC
#define TDA10048_UNCOR_CTRL 0xCD
#define TDA10048_UNCOR_CPT_LSB 0xCE
#define TDA10048_UNCOR_CPT_MSB 0xCF
@@ -183,7 +184,7 @@ static struct init_tab {
{ TDA10048_AGC_IF_MAX, 0xff },
{ TDA10048_AGC_THRESHOLD_MSB, 0x00 },
{ TDA10048_AGC_THRESHOLD_LSB, 0x70 },
- { TDA10048_CYBER_CTRL, 0x38 },
+ { TDA10048_CVBER_CTRL, 0x38 },
{ TDA10048_AGC_GAINS, 0x12 },
{ TDA10048_CONF_XO, 0x00 },
{ TDA10048_CONF_TS1, 0x07 },
@@ -688,7 +689,7 @@ static int tda10048_get_tps(struct tda10048_state *state,
p->guard_interval = GUARD_INTERVAL_1_4;
break;
}
- switch (val & 0x02) {
+ switch (val & 0x03) {
case 0:
p->transmission_mode = TRANSMISSION_MODE_2K;
break;
@@ -765,6 +766,8 @@ static int tda10048_set_frontend(struct dvb_frontend *fe,
/* Enable demod TPS auto detection and begin acquisition */
tda10048_writereg(state, TDA10048_AUTO, 0x57);
+ /* trigger cber and vber acquisition */
+ tda10048_writereg(state, TDA10048_CVBER_CTRL, 0x3B);
return 0;
}
@@ -830,12 +833,27 @@ static int tda10048_read_status(struct dvb_frontend *fe, fe_status_t *status)
static int tda10048_read_ber(struct dvb_frontend *fe, u32 *ber)
{
struct tda10048_state *state = fe->demodulator_priv;
+ static u32 cber_current;
+ u32 cber_nmax;
+ u64 cber_tmp;
dprintk(1, "%s()\n", __func__);
- /* TODO: A reset may be required here */
- *ber = tda10048_readreg(state, TDA10048_CBER_MSB) << 8 |
- tda10048_readreg(state, TDA10048_CBER_LSB);
+ /* update cber on interrupt */
+ if (tda10048_readreg(state, TDA10048_SOFT_IT_C3) & 0x01) {
+ cber_tmp = tda10048_readreg(state, TDA10048_CBER_MSB) << 8 |
+ tda10048_readreg(state, TDA10048_CBER_LSB);
+ cber_nmax = tda10048_readreg(state, TDA10048_CBER_NMAX_MSB) << 8 |
+ tda10048_readreg(state, TDA10048_CBER_NMAX_LSB);
+ cber_tmp *= 100000000;
+ cber_tmp *= 2;
+ cber_tmp = div_u64(cber_tmp, (cber_nmax * 32) + 1);
+ cber_current = (u32)cber_tmp;
+ /* retrigger cber acquisition */
+ tda10048_writereg(state, TDA10048_CVBER_CTRL, 0x39);
+ }
+ /* actual cber is (*ber)/1e8 */
+ *ber = cber_current;
return 0;
}
@@ -1015,6 +1033,9 @@ static int tda10048_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
*ucblocks = tda10048_readreg(state, TDA10048_UNCOR_CPT_MSB) << 8 |
tda10048_readreg(state, TDA10048_UNCOR_CPT_LSB);
+ /* clear the uncorrected TS packets counter when saturated */
+ if (*ucblocks == 0xFFFF)
+ tda10048_writereg(state, TDA10048_UNCOR_CTRL, 0x80);
return 0;
}
diff --git a/drivers/media/dvb/mantis/Kconfig b/drivers/media/dvb/mantis/Kconfig
index f7b72a32adf..decdeda840d 100644
--- a/drivers/media/dvb/mantis/Kconfig
+++ b/drivers/media/dvb/mantis/Kconfig
@@ -10,9 +10,15 @@ config MANTIS_CORE
config DVB_MANTIS
tristate "MANTIS based cards"
depends on MANTIS_CORE && DVB_CORE && PCI && I2C
- select DVB_MB86A16
- select DVB_ZL10353
- select DVB_STV0299
+ select DVB_MB86A16 if !DVB_FE_CUSTOMISE
+ select DVB_ZL10353 if !DVB_FE_CUSTOMISE
+ select DVB_STV0299 if !DVB_FE_CUSTOMISE
+ select DVB_LNBP21 if !DVB_FE_CUSTOMISE
+ select DVB_STB0899 if !DVB_FE_CUSTOMISE
+ select DVB_STB6100 if !DVB_FE_CUSTOMISE
+ select DVB_TDA665x if !DVB_FE_CUSTOMISE
+ select DVB_TDA10021 if !DVB_FE_CUSTOMISE
+ select DVB_TDA10023 if !DVB_FE_CUSTOMISE
select DVB_PLL
help
Support for PCI cards based on the Mantis PCI bridge.
@@ -23,7 +29,7 @@ config DVB_MANTIS
config DVB_HOPPER
tristate "HOPPER based cards"
depends on MANTIS_CORE && DVB_CORE && PCI && I2C
- select DVB_ZL10353
+ select DVB_ZL10353 if !DVB_FE_CUSTOMISE
select DVB_PLL
help
Support for PCI cards based on the Hopper PCI bridge.
diff --git a/drivers/media/dvb/mantis/mantis_input.c b/drivers/media/dvb/mantis/mantis_input.c
index 3d4e4663220..a99489b8418 100644
--- a/drivers/media/dvb/mantis/mantis_input.c
+++ b/drivers/media/dvb/mantis/mantis_input.c
@@ -19,7 +19,7 @@
*/
#include <linux/input.h>
-#include <media/ir-common.h>
+#include <media/ir-core.h>
#include <linux/pci.h>
#include "dmxdev.h"
@@ -104,7 +104,6 @@ EXPORT_SYMBOL_GPL(ir_mantis);
int mantis_input_init(struct mantis_pci *mantis)
{
struct input_dev *rc;
- struct ir_input_state rc_state;
char name[80], dev[80];
int err;
@@ -120,8 +119,6 @@ int mantis_input_init(struct mantis_pci *mantis)
rc->name = name;
rc->phys = dev;
- ir_input_init(rc, &rc_state, IR_TYPE_OTHER);
-
rc->id.bustype = BUS_PCI;
rc->id.vendor = mantis->vendor_id;
rc->id.product = mantis->device_id;
diff --git a/drivers/media/dvb/siano/sms-cards.c b/drivers/media/dvb/siano/sms-cards.c
index cff77e2eb55..25b43e587fa 100644
--- a/drivers/media/dvb/siano/sms-cards.c
+++ b/drivers/media/dvb/siano/sms-cards.c
@@ -64,9 +64,11 @@ static struct sms_board sms_boards[] = {
.type = SMS_NOVA_B0,
.fw[DEVICE_MODE_ISDBT_BDA] = "sms1xxx-hcw-55xxx-isdbt-02.fw",
.fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-hcw-55xxx-dvbt-02.fw",
+ .rc_codes = RC_MAP_RC5_HAUPPAUGE_NEW,
.board_cfg.leds_power = 26,
.board_cfg.led0 = 27,
.board_cfg.led1 = 28,
+ .board_cfg.ir = 9,
.led_power = 26,
.led_lo = 27,
.led_hi = 28,
diff --git a/drivers/media/dvb/siano/sms-cards.h b/drivers/media/dvb/siano/sms-cards.h
index 8f19fc000b4..d8cdf756f7c 100644
--- a/drivers/media/dvb/siano/sms-cards.h
+++ b/drivers/media/dvb/siano/sms-cards.h
@@ -75,7 +75,7 @@ struct sms_board {
enum sms_device_type_st type;
char *name, *fw[DEVICE_MODE_MAX];
struct sms_board_gpio_cfg board_cfg;
- enum ir_kb_type ir_kb_type;
+ char *rc_codes; /* Name of IR codes table */
/* gpios */
int led_power, led_hi, led_lo, lna_ctrl, rf_switch;
diff --git a/drivers/media/dvb/siano/smscoreapi.c b/drivers/media/dvb/siano/smscoreapi.c
index 0c87a3c3899..7f2c94a15ab 100644
--- a/drivers/media/dvb/siano/smscoreapi.c
+++ b/drivers/media/dvb/siano/smscoreapi.c
@@ -116,9 +116,7 @@ static struct smscore_registry_entry_t *smscore_find_registry(char *devpath)
return entry;
}
}
- entry = (struct smscore_registry_entry_t *)
- kmalloc(sizeof(struct smscore_registry_entry_t),
- GFP_KERNEL);
+ entry = kmalloc(sizeof(struct smscore_registry_entry_t), GFP_KERNEL);
if (entry) {
entry->mode = default_mode;
strcpy(entry->devpath, devpath);
@@ -1297,7 +1295,7 @@ int smsclient_sendrequest(struct smscore_client_t *client,
EXPORT_SYMBOL_GPL(smsclient_sendrequest);
-/* old GPIO managments implementation */
+/* old GPIO managements implementation */
int smscore_configure_gpio(struct smscore_device_t *coredev, u32 pin,
struct smscore_config_gpio *pinconfig)
{
diff --git a/drivers/media/dvb/siano/smsir.c b/drivers/media/dvb/siano/smsir.c
index a56eac76e0f..d0e4639ee9d 100644
--- a/drivers/media/dvb/siano/smsir.c
+++ b/drivers/media/dvb/siano/smsir.c
@@ -4,6 +4,11 @@
MDTV receiver kernel modules.
Copyright (C) 2006-2009, Uri Shkolnik
+ Copyright (c) 2010 - Mauro Carvalho Chehab
+ - Ported the driver to use rc-core
+ - IR raw event decoding is now done at rc-core
+ - Code almost re-written
+
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or
@@ -27,226 +32,28 @@
#include "smsir.h"
#include "sms-cards.h"
-/* In order to add new IR remote control -
- * 1) Add it to the <enum ir_kb_type> @ smsir,h,
- * 2) Add its map to keyboard_layout_maps below
- * 3) Set your board (sms-cards sub-module) to use it
- */
-
-static struct keyboard_layout_map_t keyboard_layout_maps[] = {
- [SMS_IR_KB_DEFAULT_TV] = {
- .ir_protocol = IR_RC5,
- .rc5_kbd_address = KEYBOARD_ADDRESS_TV1,
- .keyboard_layout_map = {
- KEY_0, KEY_1, KEY_2,
- KEY_3, KEY_4, KEY_5,
- KEY_6, KEY_7, KEY_8,
- KEY_9, 0, 0, KEY_POWER,
- KEY_MUTE, 0, 0,
- KEY_VOLUMEUP, KEY_VOLUMEDOWN,
- KEY_BRIGHTNESSUP,
- KEY_BRIGHTNESSDOWN, KEY_CHANNELUP,
- KEY_CHANNELDOWN,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
- }
- },
- [SMS_IR_KB_HCW_SILVER] = {
- .ir_protocol = IR_RC5,
- .rc5_kbd_address = KEYBOARD_ADDRESS_LIGHTING1,
- .keyboard_layout_map = {
- KEY_0, KEY_1, KEY_2,
- KEY_3, KEY_4, KEY_5,
- KEY_6, KEY_7, KEY_8,
- KEY_9, KEY_TEXT, KEY_RED,
- KEY_RADIO, KEY_MENU,
- KEY_SUBTITLE,
- KEY_MUTE, KEY_VOLUMEUP,
- KEY_VOLUMEDOWN, KEY_PREVIOUS, 0,
- KEY_UP, KEY_DOWN, KEY_LEFT,
- KEY_RIGHT, KEY_VIDEO, KEY_AUDIO,
- KEY_MHP, KEY_EPG, KEY_TV,
- 0, KEY_NEXTSONG, KEY_EXIT,
- KEY_CHANNELUP, KEY_CHANNELDOWN,
- KEY_CHANNEL, 0,
- KEY_PREVIOUSSONG, KEY_ENTER,
- KEY_SLEEP, 0, 0, KEY_BLUE,
- 0, 0, 0, 0, KEY_GREEN, 0,
- KEY_PAUSE, 0, KEY_REWIND,
- 0, KEY_FASTFORWARD, KEY_PLAY,
- KEY_STOP, KEY_RECORD,
- KEY_YELLOW, 0, 0, KEY_SELECT,
- KEY_ZOOM, KEY_POWER, 0, 0
- }
- },
- { } /* Terminating entry */
-};
-
-static u32 ir_pos;
-static u32 ir_word;
-static u32 ir_toggle;
-
-#define RC5_PUSH_BIT(dst, bit, pos) \
- { dst <<= 1; dst |= bit; pos++; }
-
-
-static void sms_ir_rc5_event(struct smscore_device_t *coredev,
- u32 toggle, u32 addr, u32 cmd)
-{
- bool toggle_changed;
- u16 keycode;
-
- sms_log("IR RC5 word: address %d, command %d, toggle %d",
- addr, cmd, toggle);
-
- toggle_changed = ir_toggle != toggle;
- /* keep toggle */
- ir_toggle = toggle;
-
- if (addr !=
- keyboard_layout_maps[coredev->ir.ir_kb_type].rc5_kbd_address)
- return; /* Check for valid address */
-
- keycode =
- keyboard_layout_maps
- [coredev->ir.ir_kb_type].keyboard_layout_map[cmd];
+#define MODULE_NAME "smsmdtv"
- if (!toggle_changed &&
- (keycode != KEY_VOLUMEUP && keycode != KEY_VOLUMEDOWN))
- return; /* accept only repeated volume, reject other keys */
-
- sms_log("kernel input keycode (from ir) %d", keycode);
- input_report_key(coredev->ir.input_dev, keycode, 1);
- input_sync(coredev->ir.input_dev);
-
-}
-
-/* decode raw bit pattern to RC5 code */
-/* taken from ir-functions.c */
-static u32 ir_rc5_decode(unsigned int code)
+void sms_ir_event(struct smscore_device_t *coredev, const char *buf, int len)
{
-/* unsigned int org_code = code;*/
- unsigned int pair;
- unsigned int rc5 = 0;
int i;
+ const s32 *samples = (const void *)buf;
- for (i = 0; i < 14; ++i) {
- pair = code & 0x3;
- code >>= 2;
-
- rc5 <<= 1;
- switch (pair) {
- case 0:
- case 2:
- break;
- case 1:
- rc5 |= 1;
- break;
- case 3:
-/* dprintk(1, "ir-common: ir_rc5_decode(%x) bad code\n", org_code);*/
- sms_log("bad code");
- return 0;
- }
- }
-/*
- dprintk(1, "ir-common: code=%x, rc5=%x, start=%x,
- toggle=%x, address=%x, "
- "instr=%x\n", rc5, org_code, RC5_START(rc5),
- RC5_TOGGLE(rc5), RC5_ADDR(rc5), RC5_INSTR(rc5));
-*/
- return rc5;
-}
-
-static void sms_rc5_parse_word(struct smscore_device_t *coredev)
-{
- #define RC5_START(x) (((x)>>12)&3)
- #define RC5_TOGGLE(x) (((x)>>11)&1)
- #define RC5_ADDR(x) (((x)>>6)&0x1F)
- #define RC5_INSTR(x) ((x)&0x3F)
-
- int i, j;
- u32 rc5_word = 0;
-
- /* Reverse the IR word direction */
- for (i = 0 ; i < 28 ; i++)
- RC5_PUSH_BIT(rc5_word, (ir_word>>i)&1, j)
-
- rc5_word = ir_rc5_decode(rc5_word);
- /* sms_log("temp = 0x%x, rc5_code = 0x%x", ir_word, rc5_word); */
-
- sms_ir_rc5_event(coredev,
- RC5_TOGGLE(rc5_word),
- RC5_ADDR(rc5_word),
- RC5_INSTR(rc5_word));
-}
-
-
-static void sms_rc5_accumulate_bits(struct smscore_device_t *coredev,
- s32 ir_sample)
-{
- #define RC5_TIME_GRANULARITY 200
- #define RC5_DEF_BIT_TIME 889
- #define RC5_MAX_SAME_BIT_CONT 4
- #define RC5_WORD_LEN 27 /* 28 bit */
-
- u32 i, j;
- s32 delta_time;
- u32 time = (ir_sample > 0) ? ir_sample : (0-ir_sample);
- u32 level = (ir_sample < 0) ? 0 : 1;
-
- for (i = RC5_MAX_SAME_BIT_CONT; i > 0; i--) {
- delta_time = time - (i*RC5_DEF_BIT_TIME) + RC5_TIME_GRANULARITY;
- if (delta_time < 0)
- continue; /* not so many consecutive bits */
- if (delta_time > (2 * RC5_TIME_GRANULARITY)) {
- /* timeout */
- if (ir_pos == (RC5_WORD_LEN-1))
- /* complete last bit */
- RC5_PUSH_BIT(ir_word, level, ir_pos)
-
- if (ir_pos == RC5_WORD_LEN)
- sms_rc5_parse_word(coredev);
- else if (ir_pos) /* timeout within a word */
- sms_log("IR error parsing a word");
+ for (i = 0; i < len >> 2; i++) {
+ struct ir_raw_event ev;
- ir_pos = 0;
- ir_word = 0;
- /* sms_log("timeout %d", time); */
- break;
- }
- /* The time is within the range of this number of bits */
- for (j = 0 ; j < i ; j++)
- RC5_PUSH_BIT(ir_word, level, ir_pos)
+ ev.duration = abs(samples[i]) * 1000; /* Convert to ns */
+ ev.pulse = (samples[i] > 0) ? false : true;
- break;
+ ir_raw_event_store(coredev->ir.input_dev, &ev);
}
-}
-
-void sms_ir_event(struct smscore_device_t *coredev, const char *buf, int len)
-{
- #define IR_DATA_RECEIVE_MAX_LEN 520 /* 128*4 + 4 + 4 */
- u32 i;
- enum ir_protocol ir_protocol =
- keyboard_layout_maps[coredev->ir.ir_kb_type]
- .ir_protocol;
- s32 *samples;
- int count = len>>2;
-
- samples = (s32 *)buf;
-/* sms_log("IR buffer received, length = %d", count);*/
-
- for (i = 0; i < count; i++)
- if (ir_protocol == IR_RC5)
- sms_rc5_accumulate_bits(coredev, samples[i]);
- /* IR_RCMM not implemented */
+ ir_raw_event_handle(coredev->ir.input_dev);
}
int sms_ir_init(struct smscore_device_t *coredev)
{
struct input_dev *input_dev;
+ int board_id = smscore_get_board_id(coredev);
sms_log("Allocating input device");
input_dev = input_allocate_device();
@@ -256,33 +63,38 @@ int sms_ir_init(struct smscore_device_t *coredev)
}
coredev->ir.input_dev = input_dev;
- coredev->ir.ir_kb_type =
- sms_get_board(smscore_get_board_id(coredev))->ir_kb_type;
- coredev->ir.keyboard_layout_map =
- keyboard_layout_maps[coredev->ir.ir_kb_type].
- keyboard_layout_map;
- sms_log("IR remote keyboard type is %d", coredev->ir.ir_kb_type);
coredev->ir.controller = 0; /* Todo: vega/nova SPI number */
coredev->ir.timeout = IR_DEFAULT_TIMEOUT;
sms_log("IR port %d, timeout %d ms",
coredev->ir.controller, coredev->ir.timeout);
- snprintf(coredev->ir.name,
- IR_DEV_NAME_MAX_LEN,
- "SMS IR w/kbd type %d",
- coredev->ir.ir_kb_type);
+ snprintf(coredev->ir.name, sizeof(coredev->ir.name),
+ "SMS IR (%s)", sms_get_board(board_id)->name);
+
+ strlcpy(coredev->ir.phys, coredev->devpath, sizeof(coredev->ir.phys));
+ strlcat(coredev->ir.phys, "/ir0", sizeof(coredev->ir.phys));
+
input_dev->name = coredev->ir.name;
- input_dev->phys = coredev->ir.name;
+ input_dev->phys = coredev->ir.phys;
input_dev->dev.parent = coredev->device;
- /* Key press events only */
- input_dev->evbit[0] = BIT_MASK(EV_KEY);
- input_dev->keybit[BIT_WORD(BTN_0)] = BIT_MASK(BTN_0);
+#if 0
+ /* TODO: properly initialize the parameters bellow */
+ input_dev->id.bustype = BUS_USB;
+ input_dev->id.version = 1;
+ input_dev->id.vendor = le16_to_cpu(dev->udev->descriptor.idVendor);
+ input_dev->id.product = le16_to_cpu(dev->udev->descriptor.idProduct);
+#endif
+
+ coredev->ir.props.priv = coredev;
+ coredev->ir.props.driver_type = RC_DRIVER_IR_RAW;
+ coredev->ir.props.allowed_protos = IR_TYPE_ALL;
sms_log("Input device (IR) %s is set for key events", input_dev->name);
- if (input_register_device(input_dev)) {
+ if (ir_input_register(input_dev, sms_get_board(board_id)->rc_codes,
+ &coredev->ir.props, MODULE_NAME)) {
sms_err("Failed to register device");
input_free_device(input_dev);
return -EACCES;
@@ -294,8 +106,7 @@ int sms_ir_init(struct smscore_device_t *coredev)
void sms_ir_exit(struct smscore_device_t *coredev)
{
if (coredev->ir.input_dev)
- input_unregister_device(coredev->ir.input_dev);
+ ir_input_unregister(coredev->ir.input_dev);
sms_log("");
}
-
diff --git a/drivers/media/dvb/siano/smsir.h b/drivers/media/dvb/siano/smsir.h
index b7d703e2d33..926e247523b 100644
--- a/drivers/media/dvb/siano/smsir.h
+++ b/drivers/media/dvb/siano/smsir.h
@@ -4,6 +4,11 @@ Siano Mobile Silicon, Inc.
MDTV receiver kernel modules.
Copyright (C) 2006-2009, Uri Shkolnik
+ Copyright (c) 2010 - Mauro Carvalho Chehab
+ - Ported the driver to use rc-core
+ - IR raw event decoding is now done at rc-core
+ - Code almost re-written
+
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or
@@ -23,63 +28,21 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#define __SMS_IR_H__
#include <linux/input.h>
+#include <media/ir-core.h>
-#define IR_DEV_NAME_MAX_LEN 23 /* "SMS IR kbd type nn\0" */
-#define IR_KEYBOARD_LAYOUT_SIZE 64
#define IR_DEFAULT_TIMEOUT 100
-enum ir_kb_type {
- SMS_IR_KB_DEFAULT_TV,
- SMS_IR_KB_HCW_SILVER
-};
-
-enum rc5_keyboard_address {
- KEYBOARD_ADDRESS_TV1 = 0,
- KEYBOARD_ADDRESS_TV2 = 1,
- KEYBOARD_ADDRESS_TELETEXT = 2,
- KEYBOARD_ADDRESS_VIDEO = 3,
- KEYBOARD_ADDRESS_LV1 = 4,
- KEYBOARD_ADDRESS_VCR1 = 5,
- KEYBOARD_ADDRESS_VCR2 = 6,
- KEYBOARD_ADDRESS_EXPERIMENTAL = 7,
- KEYBOARD_ADDRESS_SAT1 = 8,
- KEYBOARD_ADDRESS_CAMERA = 9,
- KEYBOARD_ADDRESS_SAT2 = 10,
- KEYBOARD_ADDRESS_CDV = 12,
- KEYBOARD_ADDRESS_CAMCORDER = 13,
- KEYBOARD_ADDRESS_PRE_AMP = 16,
- KEYBOARD_ADDRESS_TUNER = 17,
- KEYBOARD_ADDRESS_RECORDER1 = 18,
- KEYBOARD_ADDRESS_PRE_AMP1 = 19,
- KEYBOARD_ADDRESS_CD_PLAYER = 20,
- KEYBOARD_ADDRESS_PHONO = 21,
- KEYBOARD_ADDRESS_SATA = 22,
- KEYBOARD_ADDRESS_RECORDER2 = 23,
- KEYBOARD_ADDRESS_CDR = 26,
- KEYBOARD_ADDRESS_LIGHTING = 29,
- KEYBOARD_ADDRESS_LIGHTING1 = 30, /* KEYBOARD_ADDRESS_HCW_SILVER */
- KEYBOARD_ADDRESS_PHONE = 31,
- KEYBOARD_ADDRESS_NOT_RC5 = 0xFFFF
-};
-
-enum ir_protocol {
- IR_RC5,
- IR_RCMM
-};
-
-struct keyboard_layout_map_t {
- enum ir_protocol ir_protocol;
- enum rc5_keyboard_address rc5_kbd_address;
- u16 keyboard_layout_map[IR_KEYBOARD_LAYOUT_SIZE];
-};
-
struct smscore_device_t;
struct ir_t {
struct input_dev *input_dev;
- enum ir_kb_type ir_kb_type;
- char name[IR_DEV_NAME_MAX_LEN+1];
- u16 *keyboard_layout_map;
+ char name[40];
+ char phys[32];
+
+ char *rc_codes;
+ u64 protocol;
+ struct ir_dev_props props;
+
u32 timeout;
u32 controller;
};
diff --git a/drivers/media/dvb/siano/smsusb.c b/drivers/media/dvb/siano/smsusb.c
index a9c27fb69ba..50d4338610e 100644
--- a/drivers/media/dvb/siano/smsusb.c
+++ b/drivers/media/dvb/siano/smsusb.c
@@ -352,8 +352,7 @@ static int smsusb_init_device(struct usb_interface *intf, int board_id)
params.num_buffers = MAX_BUFFERS;
params.sendrequest_handler = smsusb_sendrequest;
params.context = dev;
- snprintf(params.devpath, sizeof(params.devpath),
- "usb\\%d-%s", dev->udev->bus->busnum, dev->udev->devpath);
+ usb_make_path(dev->udev, params.devpath, sizeof(params.devpath));
/* register in smscore */
rc = smscore_register_device(&params, &dev->coredev);
diff --git a/drivers/media/radio/si470x/radio-si470x-common.c b/drivers/media/radio/si470x/radio-si470x-common.c
index 47075fc71f1..9927a595b42 100644
--- a/drivers/media/radio/si470x/radio-si470x-common.c
+++ b/drivers/media/radio/si470x/radio-si470x-common.c
@@ -748,7 +748,7 @@ static int si470x_vidioc_s_tuner(struct file *file, void *priv,
struct v4l2_tuner *tuner)
{
struct si470x_device *radio = video_drvdata(file);
- int retval = -EINVAL;
+ int retval = 0;
/* safety checks */
retval = si470x_disconnect_check(radio);
diff --git a/drivers/media/radio/si4713-i2c.c b/drivers/media/radio/si4713-i2c.c
index ab63dd5b25c..fc7f4b79464 100644
--- a/drivers/media/radio/si4713-i2c.c
+++ b/drivers/media/radio/si4713-i2c.c
@@ -1009,8 +1009,10 @@ static int si4713_write_econtrol_string(struct si4713_device *sdev,
goto exit;
}
rval = copy_from_user(ps_name, control->string, len);
- if (rval < 0)
+ if (rval) {
+ rval = -EFAULT;
goto exit;
+ }
ps_name[len] = '\0';
if (strlen(ps_name) % vqc.step) {
@@ -1031,8 +1033,10 @@ static int si4713_write_econtrol_string(struct si4713_device *sdev,
goto exit;
}
rval = copy_from_user(radio_text, control->string, len);
- if (rval < 0)
+ if (rval) {
+ rval = -EFAULT;
goto exit;
+ }
radio_text[len] = '\0';
if (strlen(radio_text) % vqc.step) {
@@ -1367,6 +1371,8 @@ static int si4713_read_econtrol_string(struct si4713_device *sdev,
}
rval = copy_to_user(control->string, sdev->rds_info.ps_name,
strlen(sdev->rds_info.ps_name) + 1);
+ if (rval)
+ rval = -EFAULT;
break;
case V4L2_CID_RDS_TX_RADIO_TEXT:
@@ -1377,6 +1383,8 @@ static int si4713_read_econtrol_string(struct si4713_device *sdev,
}
rval = copy_to_user(control->string, sdev->rds_info.radio_text,
strlen(sdev->rds_info.radio_text) + 1);
+ if (rval)
+ rval = -EFAULT;
break;
default:
diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig
index 27e2acce3c3..2e15903b976 100644
--- a/drivers/media/video/Kconfig
+++ b/drivers/media/video/Kconfig
@@ -517,19 +517,6 @@ config VIDEO_UPD64083
endmenu # encoder / decoder chips
-config DISPLAY_DAVINCI_DM646X_EVM
- tristate "DM646x EVM Video Display"
- depends on VIDEO_DEV && MACH_DAVINCI_DM6467_EVM
- select VIDEOBUF_DMA_CONTIG
- select VIDEO_DAVINCI_VPIF
- select VIDEO_ADV7343
- select VIDEO_THS7303
- help
- Support for DM6467 based display device.
-
- To compile this driver as a module, choose M here: the
- module will be called vpif_display.
-
config VIDEO_SH_VOU
tristate "SuperH VOU video output driver"
depends on VIDEO_DEV && ARCH_SHMOBILE
@@ -537,29 +524,22 @@ config VIDEO_SH_VOU
help
Support for the Video Output Unit (VOU) on SuperH SoCs.
-config CAPTURE_DAVINCI_DM646X_EVM
- tristate "DM646x EVM Video Capture"
- depends on VIDEO_DEV && MACH_DAVINCI_DM6467_EVM
+config VIDEO_VIU
+ tristate "Freescale VIU Video Driver"
+ depends on VIDEO_V4L2 && PPC_MPC512x
select VIDEOBUF_DMA_CONTIG
- select VIDEO_DAVINCI_VPIF
- help
- Support for DM6467 based capture device.
-
- To compile this driver as a module, choose M here: the
- module will be called vpif_capture.
-
-config VIDEO_DAVINCI_VPIF
- tristate "DaVinci VPIF Driver"
- depends on DISPLAY_DAVINCI_DM646X_EVM
- help
- Support for DaVinci VPIF Driver.
+ default y
+ ---help---
+ Support for Freescale VIU video driver. This device captures
+ video data, or overlays video on DIU frame buffer.
- To compile this driver as a module, choose M here: the
- module will be called vpif.
+ Say Y here if you want to enable VIU device on MPC5121e Rev2+.
+ In doubt, say N.
config VIDEO_VIVI
tristate "Virtual Video Driver"
- depends on VIDEO_DEV && VIDEO_V4L2 && !SPARC32 && !SPARC64 && FONTS
+ depends on VIDEO_DEV && VIDEO_V4L2 && !SPARC32 && !SPARC64
+ depends on (FRAMEBUFFER_CONSOLE || STI_CONSOLE) && FONTS
select FONT_8x16
select VIDEOBUF_VMALLOC
default n
@@ -570,66 +550,7 @@ config VIDEO_VIVI
Say Y here if you want to test video apps or debug V4L devices.
In doubt, say N.
-config VIDEO_VPSS_SYSTEM
- tristate "VPSS System module driver"
- depends on ARCH_DAVINCI
- help
- Support for vpss system module for video driver
-
-config VIDEO_VPFE_CAPTURE
- tristate "VPFE Video Capture Driver"
- depends on VIDEO_V4L2 && ARCH_DAVINCI
- select VIDEOBUF_DMA_CONTIG
- help
- Support for DMXXXX VPFE based frame grabber. This is the
- common V4L2 module for following DMXXX SoCs from Texas
- Instruments:- DM6446 & DM355.
-
- To compile this driver as a module, choose M here: the
- module will be called vpfe-capture.
-
-config VIDEO_DM6446_CCDC
- tristate "DM6446 CCDC HW module"
- depends on ARCH_DAVINCI_DM644x && VIDEO_VPFE_CAPTURE
- select VIDEO_VPSS_SYSTEM
- default y
- help
- Enables DaVinci CCD hw module. DaVinci CCDC hw interfaces
- with decoder modules such as TVP5146 over BT656 or
- sensor module such as MT9T001 over a raw interface. This
- module configures the interface and CCDC/ISIF to do
- video frame capture from slave decoders.
-
- To compile this driver as a module, choose M here: the
- module will be called vpfe.
-
-config VIDEO_DM355_CCDC
- tristate "DM355 CCDC HW module"
- depends on ARCH_DAVINCI_DM355 && VIDEO_VPFE_CAPTURE
- select VIDEO_VPSS_SYSTEM
- default y
- help
- Enables DM355 CCD hw module. DM355 CCDC hw interfaces
- with decoder modules such as TVP5146 over BT656 or
- sensor module such as MT9T001 over a raw interface. This
- module configures the interface and CCDC/ISIF to do
- video frame capture from a slave decoders
-
- To compile this driver as a module, choose M here: the
- module will be called vpfe.
-
-config VIDEO_ISIF
- tristate "ISIF HW module"
- depends on ARCH_DAVINCI_DM365 && VIDEO_VPFE_CAPTURE
- select VIDEO_VPSS_SYSTEM
- default y
- help
- Enables ISIF hw module. This is the hardware module for
- configuring ISIF in VPFE to capture Raw Bayer RGB data from
- a image sensor or YUV data from a YUV source.
-
- To compile this driver as a module, choose M here: the
- module will be called vpfe.
+source "drivers/media/video/davinci/Kconfig"
source "drivers/media/video/omap/Kconfig"
@@ -955,6 +876,12 @@ config VIDEO_PXA27x
---help---
This is a v4l2 driver for the PXA27x Quick Capture Interface
+config VIDEO_SH_MOBILE_CSI2
+ tristate "SuperH Mobile MIPI CSI-2 Interface driver"
+ depends on VIDEO_DEV && SOC_CAMERA && HAVE_CLK
+ ---help---
+ This is a v4l2 driver for the SuperH MIPI CSI-2 Interface
+
config VIDEO_SH_MOBILE_CEU
tristate "SuperH Mobile CEU Interface driver"
depends on VIDEO_DEV && SOC_CAMERA && HAS_DMA && HAVE_CLK
@@ -1013,61 +940,6 @@ source "drivers/media/video/usbvideo/Kconfig"
source "drivers/media/video/et61x251/Kconfig"
-config VIDEO_OVCAMCHIP
- tristate "OmniVision Camera Chip support (DEPRECATED)"
- depends on I2C && VIDEO_V4L1
- default n
- ---help---
- This driver is DEPRECATED please use the gspca ov519 module
- instead. Note that for the ov511 / ov518 support of the gspca module
- you need atleast version 0.6.0 of libv4l and for the w9968cf
- atleast version 0.6.3 of libv4l.
-
- Support for the OmniVision OV6xxx and OV7xxx series of camera chips.
- This driver is intended to be used with the ov511 and w9968cf USB
- camera drivers.
-
- To compile this driver as a module, choose M here: the
- module will be called ovcamchip.
-
-config USB_W9968CF
- tristate "USB W996[87]CF JPEG Dual Mode Camera support (DEPRECATED)"
- depends on VIDEO_V4L1 && I2C && VIDEO_OVCAMCHIP
- default n
- ---help---
- This driver is DEPRECATED please use the gspca ov519 module
- instead. Note that for the w9968cf support of the gspca module
- you need atleast version 0.6.3 of libv4l.
-
- Say Y here if you want support for cameras based on OV681 or
- Winbond W9967CF/W9968CF JPEG USB Dual Mode Camera Chips.
-
- This driver has an optional plugin, which is distributed as a
- separate module only (released under GPL). It allows to use higher
- resolutions and framerates, but cannot be included in the official
- Linux kernel for performance purposes.
-
- See <file:Documentation/video4linux/w9968cf.txt> for more info.
-
- To compile this driver as a module, choose M here: the
- module will be called w9968cf.
-
-config USB_OV511
- tristate "USB OV511 Camera support (DEPRECATED)"
- depends on VIDEO_V4L1
- default n
- ---help---
- This driver is DEPRECATED please use the gspca ov519 module
- instead. Note that for the ov511 / ov518 support of the gspca module
- you need atleast version 0.6.0 of libv4l.
-
- Say Y here if you want to connect this type of camera to your
- computer's USB port. See <file:Documentation/video4linux/ov511.txt>
- for more information and for a list of supported cameras.
-
- To compile this driver as a module, choose M here: the
- module will be called ov511.
-
config USB_SE401
tristate "USB SE401 Camera support"
depends on VIDEO_V4L1
@@ -1081,25 +953,6 @@ config USB_SE401
source "drivers/media/video/sn9c102/Kconfig"
-config USB_STV680
- tristate "USB STV680 (Pencam) Camera support (DEPRECATED)"
- depends on VIDEO_V4L1
- default n
- ---help---
- This driver is DEPRECATED please use the gspca stv0680 module
- instead. Note that for the gspca stv0680 module you need
- atleast version 0.6.3 of libv4l.
-
- Say Y here if you want to connect this type of camera to your
- computer's USB port. This includes the Pencam line of cameras.
- See <file:Documentation/video4linux/stv680.txt> for more information
- and for a list of supported cameras.
-
- To compile this driver as a module, choose M here: the
- module will be called stv680.
-
-source "drivers/media/video/zc0301/Kconfig"
-
source "drivers/media/video/pwc/Kconfig"
config USB_ZR364XX
diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile
index b08bd2b65cd..1051ecc602e 100644
--- a/drivers/media/video/Makefile
+++ b/drivers/media/video/Makefile
@@ -105,7 +105,6 @@ obj-$(CONFIG_VIDEO_TLG2300) += tlg2300/
obj-$(CONFIG_VIDEO_CX231XX) += cx231xx/
obj-$(CONFIG_VIDEO_USBVISION) += usbvision/
obj-$(CONFIG_VIDEO_PVRUSB2) += pvrusb2/
-obj-$(CONFIG_VIDEO_OVCAMCHIP) += ovcamchip/
obj-$(CONFIG_VIDEO_CPIA2) += cpia2/
obj-$(CONFIG_VIDEO_MXB) += mxb.o
obj-$(CONFIG_VIDEO_HEXIUM_ORION) += hexium_orion.o
@@ -127,17 +126,13 @@ obj-$(CONFIG_VIDEO_CX2341X) += cx2341x.o
obj-$(CONFIG_VIDEO_CAFE_CCIC) += cafe_ccic.o
obj-$(CONFIG_USB_DABUSB) += dabusb.o
-obj-$(CONFIG_USB_OV511) += ov511.o
obj-$(CONFIG_USB_SE401) += se401.o
-obj-$(CONFIG_USB_STV680) += stv680.o
-obj-$(CONFIG_USB_W9968CF) += w9968cf.o
obj-$(CONFIG_USB_ZR364XX) += zr364xx.o
obj-$(CONFIG_USB_STKWEBCAM) += stkwebcam.o
obj-$(CONFIG_USB_SN9C102) += sn9c102/
obj-$(CONFIG_USB_ET61X251) += et61x251/
obj-$(CONFIG_USB_PWC) += pwc/
-obj-$(CONFIG_USB_ZC0301) += zc0301/
obj-$(CONFIG_USB_GSPCA) += gspca/
obj-$(CONFIG_VIDEO_HDPVR) += hdpvr/
@@ -151,6 +146,7 @@ obj-$(CONFIG_USB_S2255) += s2255drv.o
obj-$(CONFIG_VIDEO_IVTV) += ivtv/
obj-$(CONFIG_VIDEO_CX18) += cx18/
+obj-$(CONFIG_VIDEO_VIU) += fsl-viu.o
obj-$(CONFIG_VIDEO_VIVI) += vivi.o
obj-$(CONFIG_VIDEO_MEM2MEM_TESTDEV) += mem2mem_testdev.o
obj-$(CONFIG_VIDEO_CX23885) += cx23885/
@@ -165,6 +161,7 @@ obj-$(CONFIG_VIDEO_MX1) += mx1_camera.o
obj-$(CONFIG_VIDEO_MX2) += mx2_camera.o
obj-$(CONFIG_VIDEO_MX3) += mx3_camera.o
obj-$(CONFIG_VIDEO_PXA27x) += pxa_camera.o
+obj-$(CONFIG_VIDEO_SH_MOBILE_CSI2) += sh_mobile_csi2.o
obj-$(CONFIG_VIDEO_SH_MOBILE_CEU) += sh_mobile_ceu_camera.o
obj-$(CONFIG_ARCH_DAVINCI) += davinci/
@@ -178,7 +175,7 @@ obj-$(CONFIG_VIDEO_SAA7164) += saa7164/
obj-$(CONFIG_VIDEO_IR_I2C) += ir-kbd-i2c.o
-obj-$(CONFIG_ARCH_DAVINCI) += davinci/
+obj-y += davinci/
obj-$(CONFIG_ARCH_OMAP) += omap/
diff --git a/drivers/media/video/ak881x.c b/drivers/media/video/ak881x.c
index 1573392f74b..b388654d48c 100644
--- a/drivers/media/video/ak881x.c
+++ b/drivers/media/video/ak881x.c
@@ -126,7 +126,7 @@ static int ak881x_try_g_mbus_fmt(struct v4l2_subdev *sd,
v4l_bound_align_image(&mf->width, 0, 720, 2,
&mf->height, 0, ak881x->lines, 1, 0);
mf->field = V4L2_FIELD_INTERLACED;
- mf->code = V4L2_MBUS_FMT_YUYV8_2X8_LE;
+ mf->code = V4L2_MBUS_FMT_YUYV8_2X8;
mf->colorspace = V4L2_COLORSPACE_SMPTE170M;
return 0;
@@ -136,7 +136,7 @@ static int ak881x_s_mbus_fmt(struct v4l2_subdev *sd,
struct v4l2_mbus_framefmt *mf)
{
if (mf->field != V4L2_FIELD_INTERLACED ||
- mf->code != V4L2_MBUS_FMT_YUYV8_2X8_LE)
+ mf->code != V4L2_MBUS_FMT_YUYV8_2X8)
return -EINVAL;
return ak881x_try_g_mbus_fmt(sd, mf);
@@ -148,7 +148,7 @@ static int ak881x_enum_mbus_fmt(struct v4l2_subdev *sd, unsigned int index,
if (index)
return -EINVAL;
- *code = V4L2_MBUS_FMT_YUYV8_2X8_LE;
+ *code = V4L2_MBUS_FMT_YUYV8_2X8;
return 0;
}
diff --git a/drivers/media/video/au0828/Makefile b/drivers/media/video/au0828/Makefile
index 4d262315818..5c7f2f7d980 100644
--- a/drivers/media/video/au0828/Makefile
+++ b/drivers/media/video/au0828/Makefile
@@ -1,4 +1,4 @@
-au0828-objs := au0828-core.o au0828-i2c.o au0828-cards.o au0828-dvb.o au0828-video.o
+au0828-objs := au0828-core.o au0828-i2c.o au0828-cards.o au0828-dvb.o au0828-video.o au0828-vbi.o
obj-$(CONFIG_VIDEO_AU0828) += au0828.o
diff --git a/drivers/media/video/au0828/au0828-vbi.c b/drivers/media/video/au0828/au0828-vbi.c
new file mode 100644
index 00000000000..63f593070ee
--- /dev/null
+++ b/drivers/media/video/au0828/au0828-vbi.c
@@ -0,0 +1,138 @@
+/*
+ au0828-vbi.c - VBI driver for au0828
+
+ Copyright (C) 2010 Devin Heitmueller <dheitmueller@kernellabs.com>
+
+ This work was sponsored by GetWellNetwork Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+
+#include "au0828.h"
+
+static unsigned int vbibufs = 5;
+module_param(vbibufs, int, 0644);
+MODULE_PARM_DESC(vbibufs, "number of vbi buffers, range 2-32");
+
+/* ------------------------------------------------------------------ */
+
+static void
+free_buffer(struct videobuf_queue *vq, struct au0828_buffer *buf)
+{
+ struct au0828_fh *fh = vq->priv_data;
+ struct au0828_dev *dev = fh->dev;
+ unsigned long flags = 0;
+ if (in_interrupt())
+ BUG();
+
+ /* We used to wait for the buffer to finish here, but this didn't work
+ because, as we were keeping the state as VIDEOBUF_QUEUED,
+ videobuf_queue_cancel marked it as finished for us.
+ (Also, it could wedge forever if the hardware was misconfigured.)
+
+ This should be safe; by the time we get here, the buffer isn't
+ queued anymore. If we ever start marking the buffers as
+ VIDEOBUF_ACTIVE, it won't be, though.
+ */
+ spin_lock_irqsave(&dev->slock, flags);
+ if (dev->isoc_ctl.vbi_buf == buf)
+ dev->isoc_ctl.vbi_buf = NULL;
+ spin_unlock_irqrestore(&dev->slock, flags);
+
+ videobuf_vmalloc_free(&buf->vb);
+ buf->vb.state = VIDEOBUF_NEEDS_INIT;
+}
+
+static int
+vbi_setup(struct videobuf_queue *q, unsigned int *count, unsigned int *size)
+{
+ struct au0828_fh *fh = q->priv_data;
+ struct au0828_dev *dev = fh->dev;
+
+ *size = dev->vbi_width * dev->vbi_height * 2;
+
+ if (0 == *count)
+ *count = vbibufs;
+ if (*count < 2)
+ *count = 2;
+ if (*count > 32)
+ *count = 32;
+ return 0;
+}
+
+static int
+vbi_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
+ enum v4l2_field field)
+{
+ struct au0828_fh *fh = q->priv_data;
+ struct au0828_dev *dev = fh->dev;
+ struct au0828_buffer *buf = container_of(vb, struct au0828_buffer, vb);
+ int rc = 0;
+
+ buf->vb.size = dev->vbi_width * dev->vbi_height * 2;
+
+ if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size)
+ return -EINVAL;
+
+ buf->vb.width = dev->vbi_width;
+ buf->vb.height = dev->vbi_height;
+ buf->vb.field = field;
+
+ if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
+ rc = videobuf_iolock(q, &buf->vb, NULL);
+ if (rc < 0)
+ goto fail;
+ }
+
+ buf->vb.state = VIDEOBUF_PREPARED;
+ return 0;
+
+fail:
+ free_buffer(q, buf);
+ return rc;
+}
+
+static void
+vbi_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
+{
+ struct au0828_buffer *buf = container_of(vb,
+ struct au0828_buffer,
+ vb);
+ struct au0828_fh *fh = vq->priv_data;
+ struct au0828_dev *dev = fh->dev;
+ struct au0828_dmaqueue *vbiq = &dev->vbiq;
+
+ buf->vb.state = VIDEOBUF_QUEUED;
+ list_add_tail(&buf->vb.queue, &vbiq->active);
+}
+
+static void vbi_release(struct videobuf_queue *q, struct videobuf_buffer *vb)
+{
+ struct au0828_buffer *buf = container_of(vb, struct au0828_buffer, vb);
+ free_buffer(q, buf);
+}
+
+struct videobuf_queue_ops au0828_vbi_qops = {
+ .buf_setup = vbi_setup,
+ .buf_prepare = vbi_prepare,
+ .buf_queue = vbi_queue,
+ .buf_release = vbi_release,
+};
diff --git a/drivers/media/video/au0828/au0828-video.c b/drivers/media/video/au0828/au0828-video.c
index 52f25aabb6d..7989a7ba7c4 100644
--- a/drivers/media/video/au0828/au0828-video.c
+++ b/drivers/media/video/au0828/au0828-video.c
@@ -314,6 +314,23 @@ static inline void buffer_filled(struct au0828_dev *dev,
wake_up(&buf->vb.done);
}
+static inline void vbi_buffer_filled(struct au0828_dev *dev,
+ struct au0828_dmaqueue *dma_q,
+ struct au0828_buffer *buf)
+{
+ /* Advice that buffer was filled */
+ au0828_isocdbg("[%p/%d] wakeup\n", buf, buf->vb.i);
+
+ buf->vb.state = VIDEOBUF_DONE;
+ buf->vb.field_count++;
+ do_gettimeofday(&buf->vb.ts);
+
+ dev->isoc_ctl.vbi_buf = NULL;
+
+ list_del(&buf->vb.queue);
+ wake_up(&buf->vb.done);
+}
+
/*
* Identify the buffer header type and properly handles
*/
@@ -327,6 +344,9 @@ static void au0828_copy_video(struct au0828_dev *dev,
int linesdone, currlinedone, offset, lencopy, remain;
int bytesperline = dev->width << 1; /* Assumes 16-bit depth @@@@ */
+ if (len == 0)
+ return;
+
if (dma_q->pos + len > buf->vb.size)
len = buf->vb.size - dma_q->pos;
@@ -414,17 +434,98 @@ static inline void get_next_buf(struct au0828_dmaqueue *dma_q,
return;
}
+static void au0828_copy_vbi(struct au0828_dev *dev,
+ struct au0828_dmaqueue *dma_q,
+ struct au0828_buffer *buf,
+ unsigned char *p,
+ unsigned char *outp, unsigned long len)
+{
+ unsigned char *startwrite, *startread;
+ int bytesperline;
+ int i, j = 0;
+
+ if (dev == NULL) {
+ au0828_isocdbg("dev is null\n");
+ return;
+ }
+
+ if (dma_q == NULL) {
+ au0828_isocdbg("dma_q is null\n");
+ return;
+ }
+ if (buf == NULL)
+ return;
+ if (p == NULL) {
+ au0828_isocdbg("p is null\n");
+ return;
+ }
+ if (outp == NULL) {
+ au0828_isocdbg("outp is null\n");
+ return;
+ }
+
+ bytesperline = dev->vbi_width;
+
+ if (dma_q->pos + len > buf->vb.size)
+ len = buf->vb.size - dma_q->pos;
+
+ startread = p;
+ startwrite = outp + (dma_q->pos / 2);
+
+ /* Make sure the bottom field populates the second half of the frame */
+ if (buf->top_field == 0)
+ startwrite += bytesperline * dev->vbi_height;
+
+ for (i = 0; i < len; i += 2)
+ startwrite[j++] = startread[i+1];
+
+ dma_q->pos += len;
+}
+
+
+/*
+ * video-buf generic routine to get the next available VBI buffer
+ */
+static inline void vbi_get_next_buf(struct au0828_dmaqueue *dma_q,
+ struct au0828_buffer **buf)
+{
+ struct au0828_dev *dev = container_of(dma_q, struct au0828_dev, vbiq);
+ char *outp;
+
+ if (list_empty(&dma_q->active)) {
+ au0828_isocdbg("No active queue to serve\n");
+ dev->isoc_ctl.vbi_buf = NULL;
+ *buf = NULL;
+ return;
+ }
+
+ /* Get the next buffer */
+ *buf = list_entry(dma_q->active.next, struct au0828_buffer, vb.queue);
+ /* Cleans up buffer - Usefull for testing for frame/URB loss */
+ outp = videobuf_to_vmalloc(&(*buf)->vb);
+ memset(outp, 0x00, (*buf)->vb.size);
+
+ dev->isoc_ctl.vbi_buf = *buf;
+
+ return;
+}
+
/*
* Controls the isoc copy of each urb packet
*/
static inline int au0828_isoc_copy(struct au0828_dev *dev, struct urb *urb)
{
struct au0828_buffer *buf;
+ struct au0828_buffer *vbi_buf;
struct au0828_dmaqueue *dma_q = urb->context;
+ struct au0828_dmaqueue *vbi_dma_q = &dev->vbiq;
unsigned char *outp = NULL;
+ unsigned char *vbioutp = NULL;
int i, len = 0, rc = 1;
unsigned char *p;
unsigned char fbyte;
+ unsigned int vbi_field_size;
+ unsigned int remain, lencopy;
if (!dev)
return 0;
@@ -443,6 +544,10 @@ static inline int au0828_isoc_copy(struct au0828_dev *dev, struct urb *urb)
if (buf != NULL)
outp = videobuf_to_vmalloc(&buf->vb);
+ vbi_buf = dev->isoc_ctl.vbi_buf;
+ if (vbi_buf != NULL)
+ vbioutp = videobuf_to_vmalloc(&vbi_buf->vb);
+
for (i = 0; i < urb->number_of_packets; i++) {
int status = urb->iso_frame_desc[i].status;
@@ -472,6 +577,19 @@ static inline int au0828_isoc_copy(struct au0828_dev *dev, struct urb *urb)
au0828_isocdbg("Video frame %s\n",
(fbyte & 0x40) ? "odd" : "even");
if (!(fbyte & 0x40)) {
+ /* VBI */
+ if (vbi_buf != NULL)
+ vbi_buffer_filled(dev,
+ vbi_dma_q,
+ vbi_buf);
+ vbi_get_next_buf(vbi_dma_q, &vbi_buf);
+ if (vbi_buf == NULL)
+ vbioutp = NULL;
+ else
+ vbioutp = videobuf_to_vmalloc(
+ &vbi_buf->vb);
+
+ /* Video */
if (buf != NULL)
buffer_filled(dev, dma_q, buf);
get_next_buf(dma_q, &buf);
@@ -488,9 +606,36 @@ static inline int au0828_isoc_copy(struct au0828_dev *dev, struct urb *urb)
buf->top_field = 0;
}
+ if (vbi_buf != NULL) {
+ if (fbyte & 0x40)
+ vbi_buf->top_field = 1;
+ else
+ vbi_buf->top_field = 0;
+ }
+
+ dev->vbi_read = 0;
+ vbi_dma_q->pos = 0;
dma_q->pos = 0;
}
- if (buf != NULL)
+
+ vbi_field_size = dev->vbi_width * dev->vbi_height * 2;
+ if (dev->vbi_read < vbi_field_size) {
+ remain = vbi_field_size - dev->vbi_read;
+ if (len < remain)
+ lencopy = len;
+ else
+ lencopy = remain;
+
+ if (vbi_buf != NULL)
+ au0828_copy_vbi(dev, vbi_dma_q, vbi_buf, p,
+ vbioutp, len);
+
+ len -= lencopy;
+ p += lencopy;
+ dev->vbi_read += lencopy;
+ }
+
+ if (dev->vbi_read >= vbi_field_size && buf != NULL)
au0828_copy_video(dev, dma_q, buf, p, outp, len);
}
return rc;
@@ -642,7 +787,7 @@ int au0828_analog_stream_enable(struct au0828_dev *d)
au0828_writereg(d, 0x114, 0xa0);
au0828_writereg(d, 0x115, 0x05);
/* set y position */
- au0828_writereg(d, 0x112, 0x02);
+ au0828_writereg(d, 0x112, 0x00);
au0828_writereg(d, 0x113, 0x00);
au0828_writereg(d, 0x116, 0xf2);
au0828_writereg(d, 0x117, 0x00);
@@ -703,47 +848,83 @@ void au0828_analog_unregister(struct au0828_dev *dev)
/* Usage lock check functions */
-static int res_get(struct au0828_fh *fh)
+static int res_get(struct au0828_fh *fh, unsigned int bit)
{
- struct au0828_dev *dev = fh->dev;
- int rc = 0;
+ struct au0828_dev *dev = fh->dev;
- /* This instance already has stream_on */
- if (fh->stream_on)
- return rc;
+ if (fh->resources & bit)
+ /* have it already allocated */
+ return 1;
- if (dev->stream_on)
- return -EBUSY;
+ /* is it free? */
+ mutex_lock(&dev->lock);
+ if (dev->resources & bit) {
+ /* no, someone else uses it */
+ mutex_unlock(&dev->lock);
+ return 0;
+ }
+ /* it's free, grab it */
+ fh->resources |= bit;
+ dev->resources |= bit;
+ dprintk(1, "res: get %d\n", bit);
+ mutex_unlock(&dev->lock);
+ return 1;
+}
- dev->stream_on = 1;
- fh->stream_on = 1;
- return rc;
+static int res_check(struct au0828_fh *fh, unsigned int bit)
+{
+ return fh->resources & bit;
}
-static int res_check(struct au0828_fh *fh)
+static int res_locked(struct au0828_dev *dev, unsigned int bit)
{
- return fh->stream_on;
+ return dev->resources & bit;
}
-static void res_free(struct au0828_fh *fh)
+static void res_free(struct au0828_fh *fh, unsigned int bits)
{
- struct au0828_dev *dev = fh->dev;
+ struct au0828_dev *dev = fh->dev;
- fh->stream_on = 0;
- dev->stream_on = 0;
+ BUG_ON((fh->resources & bits) != bits);
+
+ mutex_lock(&dev->lock);
+ fh->resources &= ~bits;
+ dev->resources &= ~bits;
+ dprintk(1, "res: put %d\n", bits);
+ mutex_unlock(&dev->lock);
+}
+
+static int get_ressource(struct au0828_fh *fh)
+{
+ switch (fh->type) {
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+ return AU0828_RESOURCE_VIDEO;
+ case V4L2_BUF_TYPE_VBI_CAPTURE:
+ return AU0828_RESOURCE_VBI;
+ default:
+ BUG();
+ return 0;
+ }
}
static int au0828_v4l2_open(struct file *filp)
{
int ret = 0;
+ struct video_device *vdev = video_devdata(filp);
struct au0828_dev *dev = video_drvdata(filp);
struct au0828_fh *fh;
- int type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ int type;
-#ifdef VBI_IS_WORKING
- if (video_devdata(filp)->vfl_type == VFL_TYPE_GRABBER)
+ switch (vdev->vfl_type) {
+ case VFL_TYPE_GRABBER:
+ type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ break;
+ case VFL_TYPE_VBI:
type = V4L2_BUF_TYPE_VBI_CAPTURE;
-#endif
+ break;
+ default:
+ return -EINVAL;
+ }
fh = kzalloc(sizeof(struct au0828_fh), GFP_KERNEL);
if (NULL == fh) {
@@ -781,10 +962,21 @@ static int au0828_v4l2_open(struct file *filp)
dev->users++;
videobuf_queue_vmalloc_init(&fh->vb_vidq, &au0828_video_qops,
- NULL, &dev->slock, fh->type,
+ NULL, &dev->slock,
+ V4L2_BUF_TYPE_VIDEO_CAPTURE,
V4L2_FIELD_INTERLACED,
sizeof(struct au0828_buffer), fh);
+ /* VBI Setup */
+ dev->vbi_width = 720;
+ dev->vbi_height = 1;
+ videobuf_queue_vmalloc_init(&fh->vb_vbiq, &au0828_vbi_qops,
+ NULL, &dev->slock,
+ V4L2_BUF_TYPE_VBI_CAPTURE,
+ V4L2_FIELD_SEQ_TB,
+ sizeof(struct au0828_buffer), fh);
+
+
return ret;
}
@@ -794,17 +986,19 @@ static int au0828_v4l2_close(struct file *filp)
struct au0828_fh *fh = filp->private_data;
struct au0828_dev *dev = fh->dev;
- mutex_lock(&dev->lock);
- if (res_check(fh))
- res_free(fh);
-
- if (dev->users == 1) {
+ if (res_check(fh, AU0828_RESOURCE_VIDEO)) {
videobuf_stop(&fh->vb_vidq);
- videobuf_mmap_free(&fh->vb_vidq);
+ res_free(fh, AU0828_RESOURCE_VIDEO);
+ }
+
+ if (res_check(fh, AU0828_RESOURCE_VBI)) {
+ videobuf_stop(&fh->vb_vbiq);
+ res_free(fh, AU0828_RESOURCE_VBI);
+ }
+ if (dev->users == 1) {
if (dev->dev_state & DEV_DISCONNECTED) {
au0828_analog_unregister(dev);
- mutex_unlock(&dev->lock);
kfree(dev);
return 0;
}
@@ -823,10 +1017,11 @@ static int au0828_v4l2_close(struct file *filp)
printk(KERN_INFO "Au0828 can't set alternate to 0!\n");
}
+ videobuf_mmap_free(&fh->vb_vidq);
+ videobuf_mmap_free(&fh->vb_vbiq);
kfree(fh);
dev->users--;
wake_up_interruptible_nr(&dev->open, 1);
- mutex_unlock(&dev->lock);
return 0;
}
@@ -842,16 +1037,21 @@ static ssize_t au0828_v4l2_read(struct file *filp, char __user *buf,
return rc;
if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
- mutex_lock(&dev->lock);
- rc = res_get(fh);
- mutex_unlock(&dev->lock);
-
- if (unlikely(rc < 0))
- return rc;
+ if (res_locked(dev, AU0828_RESOURCE_VIDEO))
+ return -EBUSY;
return videobuf_read_stream(&fh->vb_vidq, buf, count, pos, 0,
filp->f_flags & O_NONBLOCK);
}
+
+ if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
+ if (!res_get(fh, AU0828_RESOURCE_VBI))
+ return -EBUSY;
+
+ return videobuf_read_stream(&fh->vb_vbiq, buf, count, pos, 0,
+ filp->f_flags & O_NONBLOCK);
+ }
+
return 0;
}
@@ -865,17 +1065,17 @@ static unsigned int au0828_v4l2_poll(struct file *filp, poll_table *wait)
if (rc < 0)
return rc;
- mutex_lock(&dev->lock);
- rc = res_get(fh);
- mutex_unlock(&dev->lock);
-
- if (unlikely(rc < 0))
- return POLLERR;
-
- if (V4L2_BUF_TYPE_VIDEO_CAPTURE != fh->type)
+ if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+ if (!res_get(fh, AU0828_RESOURCE_VIDEO))
+ return POLLERR;
+ return videobuf_poll_stream(filp, &fh->vb_vidq, wait);
+ } else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
+ if (!res_get(fh, AU0828_RESOURCE_VBI))
+ return POLLERR;
+ return videobuf_poll_stream(filp, &fh->vb_vbiq, wait);
+ } else {
return POLLERR;
-
- return videobuf_poll_stream(filp, &fh->vb_vidq, wait);
+ }
}
static int au0828_v4l2_mmap(struct file *filp, struct vm_area_struct *vma)
@@ -888,14 +1088,10 @@ static int au0828_v4l2_mmap(struct file *filp, struct vm_area_struct *vma)
if (rc < 0)
return rc;
- mutex_lock(&dev->lock);
- rc = res_get(fh);
- mutex_unlock(&dev->lock);
-
- if (unlikely(rc < 0))
- return rc;
-
- rc = videobuf_mmap_mapper(&fh->vb_vidq, vma);
+ if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ rc = videobuf_mmap_mapper(&fh->vb_vidq, vma);
+ else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE)
+ rc = videobuf_mmap_mapper(&fh->vb_vbiq, vma);
return rc;
}
@@ -911,14 +1107,6 @@ static int au0828_set_format(struct au0828_dev *dev, unsigned int cmd,
maxwidth = 720;
maxheight = 480;
-#ifdef VBI_IS_WORKING
- if (format->type == V4L2_BUF_TYPE_SLICED_VBI_CAPTURE) {
- dprintk(1, "VBI format set: to be supported!\n");
- return 0;
- }
- if (format->type == V4L2_BUF_TYPE_VBI_CAPTURE)
- return 0;
-#endif
if (format->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
return -EINVAL;
@@ -999,9 +1187,7 @@ static int vidioc_querycap(struct file *file, void *priv,
/*set the device capabilities */
cap->capabilities = V4L2_CAP_VIDEO_CAPTURE |
-#ifdef VBI_IS_WORKING
V4L2_CAP_VBI_CAPTURE |
-#endif
V4L2_CAP_AUDIO |
V4L2_CAP_READWRITE |
V4L2_CAP_STREAMING |
@@ -1056,20 +1242,21 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
struct au0828_dev *dev = fh->dev;
int rc;
+ rc = check_dev(dev);
+ if (rc < 0)
+ return rc;
+
+ mutex_lock(&dev->lock);
+
if (videobuf_queue_is_busy(&fh->vb_vidq)) {
printk(KERN_INFO "%s queue busy\n", __func__);
rc = -EBUSY;
goto out;
}
- if (dev->stream_on && !fh->stream_on) {
- printk(KERN_INFO "%s device in use by another fh\n", __func__);
- rc = -EBUSY;
- goto out;
- }
-
- return au0828_set_format(dev, VIDIOC_S_FMT, f);
+ rc = au0828_set_format(dev, VIDIOC_S_FMT, f);
out:
+ mutex_unlock(&dev->lock);
return rc;
}
@@ -1300,6 +1487,29 @@ static int vidioc_s_frequency(struct file *file, void *priv,
return 0;
}
+
+/* RAW VBI ioctls */
+
+static int vidioc_g_fmt_vbi_cap(struct file *file, void *priv,
+ struct v4l2_format *format)
+{
+ struct au0828_fh *fh = priv;
+ struct au0828_dev *dev = fh->dev;
+
+ format->fmt.vbi.samples_per_line = dev->vbi_width;
+ format->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY;
+ format->fmt.vbi.offset = 0;
+ format->fmt.vbi.flags = 0;
+ format->fmt.vbi.sampling_rate = 6750000 * 4 / 2;
+
+ format->fmt.vbi.count[0] = dev->vbi_height;
+ format->fmt.vbi.count[1] = dev->vbi_height;
+ format->fmt.vbi.start[0] = 21;
+ format->fmt.vbi.start[1] = 284;
+
+ return 0;
+}
+
static int vidioc_g_chip_ident(struct file *file, void *priv,
struct v4l2_dbg_chip_ident *chip)
{
@@ -1345,25 +1555,32 @@ static int vidioc_cropcap(struct file *file, void *priv,
static int vidioc_streamon(struct file *file, void *priv,
enum v4l2_buf_type type)
{
- struct au0828_fh *fh = priv;
- struct au0828_dev *dev = fh->dev;
- int rc;
+ struct au0828_fh *fh = priv;
+ struct au0828_dev *dev = fh->dev;
+ int rc = -EINVAL;
rc = check_dev(dev);
if (rc < 0)
return rc;
+ if (unlikely(type != fh->type))
+ return -EINVAL;
+
+ dprintk(1, "vidioc_streamon fh=%p t=%d fh->res=%d dev->res=%d\n",
+ fh, type, fh->resources, dev->resources);
+
+ if (unlikely(!res_get(fh, get_ressource(fh))))
+ return -EBUSY;
+
if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
au0828_analog_stream_enable(dev);
v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_stream, 1);
}
- mutex_lock(&dev->lock);
- rc = res_get(fh);
-
- if (likely(rc >= 0))
+ if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
rc = videobuf_streamon(&fh->vb_vidq);
- mutex_unlock(&dev->lock);
+ else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE)
+ rc = videobuf_streamon(&fh->vb_vbiq);
return rc;
}
@@ -1371,38 +1588,42 @@ static int vidioc_streamon(struct file *file, void *priv,
static int vidioc_streamoff(struct file *file, void *priv,
enum v4l2_buf_type type)
{
- struct au0828_fh *fh = priv;
- struct au0828_dev *dev = fh->dev;
- int i;
- int ret;
- int rc;
+ struct au0828_fh *fh = priv;
+ struct au0828_dev *dev = fh->dev;
+ int rc;
+ int i;
rc = check_dev(dev);
if (rc < 0)
return rc;
- if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
+ fh->type != V4L2_BUF_TYPE_VBI_CAPTURE)
return -EINVAL;
if (type != fh->type)
return -EINVAL;
- if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+ dprintk(1, "vidioc_streamoff fh=%p t=%d fh->res=%d dev->res=%d\n",
+ fh, type, fh->resources, dev->resources);
+
+ if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_stream, 0);
- ret = au0828_stream_interrupt(dev);
- if (ret != 0)
- return ret;
- }
+ rc = au0828_stream_interrupt(dev);
+ if (rc != 0)
+ return rc;
- for (i = 0; i < AU0828_MAX_INPUT; i++) {
- if (AUVI_INPUT(i).audio_setup == NULL)
- continue;
- (AUVI_INPUT(i).audio_setup)(dev, 0);
- }
+ for (i = 0; i < AU0828_MAX_INPUT; i++) {
+ if (AUVI_INPUT(i).audio_setup == NULL)
+ continue;
+ (AUVI_INPUT(i).audio_setup)(dev, 0);
+ }
- mutex_lock(&dev->lock);
- videobuf_streamoff(&fh->vb_vidq);
- res_free(fh);
- mutex_unlock(&dev->lock);
+ videobuf_streamoff(&fh->vb_vidq);
+ res_free(fh, AU0828_RESOURCE_VIDEO);
+ } else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
+ videobuf_streamoff(&fh->vb_vbiq);
+ res_free(fh, AU0828_RESOURCE_VBI);
+ }
return 0;
}
@@ -1527,19 +1748,11 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = {
.vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap,
.vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap,
.vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
-#ifdef VBI_IS_WORKING
.vidioc_g_fmt_vbi_cap = vidioc_g_fmt_vbi_cap,
- .vidioc_try_fmt_vbi_cap = vidioc_s_fmt_vbi_cap,
- .vidioc_s_fmt_vbi_cap = vidioc_s_fmt_vbi_cap,
-#endif
+ .vidioc_s_fmt_vbi_cap = vidioc_g_fmt_vbi_cap,
.vidioc_g_audio = vidioc_g_audio,
.vidioc_s_audio = vidioc_s_audio,
.vidioc_cropcap = vidioc_cropcap,
-#ifdef VBI_IS_WORKING
- .vidioc_g_fmt_sliced_vbi_cap = vidioc_g_fmt_sliced_vbi_cap,
- .vidioc_try_fmt_sliced_vbi_cap = vidioc_try_set_sliced_vbi_cap,
- .vidioc_s_fmt_sliced_vbi_cap = vidioc_try_set_sliced_vbi_cap,
-#endif
.vidioc_reqbufs = vidioc_reqbufs,
.vidioc_querybuf = vidioc_querybuf,
.vidioc_qbuf = vidioc_qbuf,
@@ -1621,8 +1834,11 @@ int au0828_analog_register(struct au0828_dev *dev,
spin_lock_init(&dev->slock);
mutex_init(&dev->lock);
+ /* init video dma queues */
INIT_LIST_HEAD(&dev->vidq.active);
INIT_LIST_HEAD(&dev->vidq.queued);
+ INIT_LIST_HEAD(&dev->vbiq.active);
+ INIT_LIST_HEAD(&dev->vbiq.queued);
dev->width = NTSC_STD_W;
dev->height = NTSC_STD_H;
@@ -1638,26 +1854,23 @@ int au0828_analog_register(struct au0828_dev *dev,
return -ENOMEM;
}
-#ifdef VBI_IS_WORKING
+ /* allocate the VBI struct */
dev->vbi_dev = video_device_alloc();
if (NULL == dev->vbi_dev) {
dprintk(1, "Can't allocate vbi_device.\n");
kfree(dev->vdev);
return -ENOMEM;
}
-#endif
/* Fill the video capture device struct */
*dev->vdev = au0828_video_template;
dev->vdev->parent = &dev->usbdev->dev;
strcpy(dev->vdev->name, "au0828a video");
-#ifdef VBI_IS_WORKING
/* Setup the VBI device */
*dev->vbi_dev = au0828_video_template;
dev->vbi_dev->parent = &dev->usbdev->dev;
strcpy(dev->vbi_dev->name, "au0828a vbi");
-#endif
/* Register the v4l2 device */
video_set_drvdata(dev->vdev, dev);
@@ -1669,7 +1882,6 @@ int au0828_analog_register(struct au0828_dev *dev,
return -ENODEV;
}
-#ifdef VBI_IS_WORKING
/* Register the vbi device */
video_set_drvdata(dev->vbi_dev, dev);
retval = video_register_device(dev->vbi_dev, VFL_TYPE_VBI, -1);
@@ -1680,7 +1892,6 @@ int au0828_analog_register(struct au0828_dev *dev,
video_device_release(dev->vdev);
return -ENODEV;
}
-#endif
dprintk(1, "%s completed!\n", __func__);
diff --git a/drivers/media/video/au0828/au0828.h b/drivers/media/video/au0828/au0828.h
index 207f32dec6a..9905bc4f5f5 100644
--- a/drivers/media/video/au0828/au0828.h
+++ b/drivers/media/video/au0828/au0828.h
@@ -60,6 +60,10 @@
#define AU0828_MAX_INPUT 4
+/* au0828 resource types (used for res_get/res_lock etc */
+#define AU0828_RESOURCE_VIDEO 0x01
+#define AU0828_RESOURCE_VBI 0x02
+
enum au0828_itype {
AU0828_VMUX_UNDEFINED = 0,
AU0828_VMUX_COMPOSITE,
@@ -115,8 +119,10 @@ enum au0828_dev_state {
struct au0828_fh {
struct au0828_dev *dev;
- unsigned int stream_on:1; /* Locks streams */
+ unsigned int resources;
+
struct videobuf_queue vb_vidq;
+ struct videobuf_queue vb_vbiq;
enum v4l2_buf_type type;
};
@@ -145,7 +151,8 @@ struct au0828_usb_isoc_ctl {
int tmp_buf_len;
/* Stores already requested buffers */
- struct au0828_buffer *buf;
+ struct au0828_buffer *buf;
+ struct au0828_buffer *vbi_buf;
/* Stores the number of received fields */
int nfields;
@@ -194,11 +201,14 @@ struct au0828_dev {
/* Analog */
struct v4l2_device v4l2_dev;
int users;
- unsigned int stream_on:1; /* Locks streams */
+ unsigned int resources; /* resources in use */
struct video_device *vdev;
struct video_device *vbi_dev;
int width;
int height;
+ int vbi_width;
+ int vbi_height;
+ u32 vbi_read;
u32 field_size;
u32 frame_size;
u32 bytesperline;
@@ -219,6 +229,7 @@ struct au0828_dev {
/* Isoc control struct */
struct au0828_dmaqueue vidq;
+ struct au0828_dmaqueue vbiq;
struct au0828_usb_isoc_ctl isoc_ctl;
spinlock_t slock;
@@ -278,6 +289,9 @@ void au0828_analog_unregister(struct au0828_dev *dev);
extern int au0828_dvb_register(struct au0828_dev *dev);
extern void au0828_dvb_unregister(struct au0828_dev *dev);
+/* au0828-vbi.c */
+extern struct videobuf_queue_ops au0828_vbi_qops;
+
#define dprintk(level, fmt, arg...)\
do { if (au0828_debug & level)\
printk(KERN_DEBUG DRIVER_NAME "/0: " fmt, ## arg);\
diff --git a/drivers/media/video/bt8xx/bttv-risc.c b/drivers/media/video/bt8xx/bttv-risc.c
index c24b1c100e1..0fa9f39f37a 100644
--- a/drivers/media/video/bt8xx/bttv-risc.c
+++ b/drivers/media/video/bt8xx/bttv-risc.c
@@ -583,7 +583,7 @@ bttv_dma_free(struct videobuf_queue *q,struct bttv *btv, struct bttv_buffer *buf
BUG_ON(in_interrupt());
videobuf_waiton(&buf->vb,0,0);
- videobuf_dma_unmap(q, dma);
+ videobuf_dma_unmap(q->dev, dma);
videobuf_dma_free(dma);
btcx_riscmem_free(btv->c.pci,&buf->bottom);
btcx_riscmem_free(btv->c.pci,&buf->top);
diff --git a/drivers/media/video/cpia_usb.c b/drivers/media/video/cpia_usb.c
index ef1f8939998..58d193ff591 100644
--- a/drivers/media/video/cpia_usb.c
+++ b/drivers/media/video/cpia_usb.c
@@ -584,7 +584,6 @@ static void cpia_disconnect(struct usb_interface *intf)
{
struct cam_data *cam = usb_get_intfdata(intf);
struct usb_cpia *ucpia;
- struct usb_device *udev;
usb_set_intfdata(intf, NULL);
if (!cam)
@@ -606,8 +605,6 @@ static void cpia_disconnect(struct usb_interface *intf)
if (waitqueue_active(&ucpia->wq_stream))
wake_up_interruptible(&ucpia->wq_stream);
- udev = interface_to_usbdev(intf);
-
ucpia->curbuff = ucpia->workbuff = NULL;
vfree(ucpia->buffers[2]);
diff --git a/drivers/media/video/cx18/cx18-ioctl.c b/drivers/media/video/cx18/cx18-ioctl.c
index 20eaf38ba95..d6792405f8d 100644
--- a/drivers/media/video/cx18/cx18-ioctl.c
+++ b/drivers/media/video/cx18/cx18-ioctl.c
@@ -1081,7 +1081,7 @@ long cx18_v4l2_ioctl(struct file *filp, unsigned int cmd,
unsigned long arg)
{
struct video_device *vfd = video_devdata(filp);
- struct cx18_open_id *id = (struct cx18_open_id *)filp->private_data;
+ struct cx18_open_id *id = filp->private_data;
struct cx18 *cx = id->cx;
long res;
diff --git a/drivers/media/video/cx23885/cx23885-cards.c b/drivers/media/video/cx23885/cx23885-cards.c
index d639186f645..2014daedee8 100644
--- a/drivers/media/video/cx23885/cx23885-cards.c
+++ b/drivers/media/video/cx23885/cx23885-cards.c
@@ -408,10 +408,18 @@ struct cx23885_subid cx23885_subids[] = {
.card = CX23885_BOARD_HAUPPAUGE_HVR1275,
}, {
.subvendor = 0x0070,
+ .subdevice = 0x221d,
+ .card = CX23885_BOARD_HAUPPAUGE_HVR1275,
+ }, {
+ .subvendor = 0x0070,
.subdevice = 0x2251,
.card = CX23885_BOARD_HAUPPAUGE_HVR1255,
}, {
.subvendor = 0x0070,
+ .subdevice = 0x2259,
+ .card = CX23885_BOARD_HAUPPAUGE_HVR1255,
+ }, {
+ .subvendor = 0x0070,
.subdevice = 0x2291,
.card = CX23885_BOARD_HAUPPAUGE_HVR1210,
}, {
@@ -419,6 +427,38 @@ struct cx23885_subid cx23885_subids[] = {
.subdevice = 0x2295,
.card = CX23885_BOARD_HAUPPAUGE_HVR1210,
}, {
+ .subvendor = 0x0070,
+ .subdevice = 0x2299,
+ .card = CX23885_BOARD_HAUPPAUGE_HVR1210,
+ }, {
+ .subvendor = 0x0070,
+ .subdevice = 0x229d,
+ .card = CX23885_BOARD_HAUPPAUGE_HVR1210, /* HVR1215 */
+ }, {
+ .subvendor = 0x0070,
+ .subdevice = 0x22f0,
+ .card = CX23885_BOARD_HAUPPAUGE_HVR1210,
+ }, {
+ .subvendor = 0x0070,
+ .subdevice = 0x22f1,
+ .card = CX23885_BOARD_HAUPPAUGE_HVR1255,
+ }, {
+ .subvendor = 0x0070,
+ .subdevice = 0x22f2,
+ .card = CX23885_BOARD_HAUPPAUGE_HVR1275,
+ }, {
+ .subvendor = 0x0070,
+ .subdevice = 0x22f3,
+ .card = CX23885_BOARD_HAUPPAUGE_HVR1210, /* HVR1215 */
+ }, {
+ .subvendor = 0x0070,
+ .subdevice = 0x22f4,
+ .card = CX23885_BOARD_HAUPPAUGE_HVR1210,
+ }, {
+ .subvendor = 0x0070,
+ .subdevice = 0x22f5,
+ .card = CX23885_BOARD_HAUPPAUGE_HVR1210, /* HVR1215 */
+ }, {
.subvendor = 0x14f1,
.subdevice = 0x8651,
.card = CX23885_BOARD_MYGICA_X8506,
diff --git a/drivers/media/video/cx23885/cx23885-core.c b/drivers/media/video/cx23885/cx23885-core.c
index 0dde57e96d3..ff76f64edac 100644
--- a/drivers/media/video/cx23885/cx23885-core.c
+++ b/drivers/media/video/cx23885/cx23885-core.c
@@ -1142,7 +1142,7 @@ void cx23885_free_buffer(struct videobuf_queue *q, struct cx23885_buffer *buf)
BUG_ON(in_interrupt());
videobuf_waiton(&buf->vb, 0, 0);
- videobuf_dma_unmap(q, dma);
+ videobuf_dma_unmap(q->dev, dma);
videobuf_dma_free(dma);
btcx_riscmem_free(to_pci_dev(q->dev), &buf->risc);
buf->vb.state = VIDEOBUF_NEEDS_INIT;
@@ -1953,8 +1953,12 @@ static int __devinit cx23885_initdev(struct pci_dev *pci_dev,
goto fail_irq;
}
- err = request_irq(pci_dev->irq, cx23885_irq,
- IRQF_SHARED | IRQF_DISABLED, dev->name, dev);
+ if (!pci_enable_msi(pci_dev))
+ err = request_irq(pci_dev->irq, cx23885_irq,
+ IRQF_DISABLED, dev->name, dev);
+ else
+ err = request_irq(pci_dev->irq, cx23885_irq,
+ IRQF_SHARED | IRQF_DISABLED, dev->name, dev);
if (err < 0) {
printk(KERN_ERR "%s: can't get IRQ %d\n",
dev->name, pci_dev->irq);
@@ -2000,6 +2004,7 @@ static void __devexit cx23885_finidev(struct pci_dev *pci_dev)
/* unregister stuff */
free_irq(pci_dev->irq, dev);
+ pci_disable_msi(pci_dev);
cx23885_dev_unregister(dev);
v4l2_device_unregister(v4l2_dev);
diff --git a/drivers/media/video/cx23885/cx23885-dvb.c b/drivers/media/video/cx23885/cx23885-dvb.c
index 0a199d774d9..3d70af28388 100644
--- a/drivers/media/video/cx23885/cx23885-dvb.c
+++ b/drivers/media/video/cx23885/cx23885-dvb.c
@@ -991,7 +991,7 @@ static int dvb_register(struct cx23885_tsport *port)
ret = videobuf_dvb_register_bus(&port->frontends, THIS_MODULE, port,
&dev->pci->dev, adapter_nr, 0,
cx23885_dvb_fe_ioctl_override);
- if (!ret)
+ if (ret)
return ret;
/* init CI & MAC */
diff --git a/drivers/media/video/cx23885/cx23885-input.c b/drivers/media/video/cx23885/cx23885-input.c
index 5de6ba98f7a..d0b1613ede2 100644
--- a/drivers/media/video/cx23885/cx23885-input.c
+++ b/drivers/media/video/cx23885/cx23885-input.c
@@ -37,161 +37,55 @@
#include <linux/input.h>
#include <linux/slab.h>
-#include <media/ir-common.h>
+#include <media/ir-core.h>
#include <media/v4l2-subdev.h>
#include "cx23885.h"
-#define RC5_BITS 14
-#define RC5_HALF_BITS (2*RC5_BITS)
-#define RC5_HALF_BITS_MASK ((1 << RC5_HALF_BITS) - 1)
-
-#define RC5_START_BITS_NORMAL 0x3 /* Command range 0 - 63 */
-#define RC5_START_BITS_EXTENDED 0x2 /* Command range 64 - 127 */
-
-#define RC5_EXTENDED_COMMAND_OFFSET 64
-
#define MODULE_NAME "cx23885"
-static inline unsigned int rc5_command(u32 rc5_baseband)
+static void convert_measurement(u32 x, struct ir_raw_event *y)
{
- return RC5_INSTR(rc5_baseband) +
- ((RC5_START(rc5_baseband) == RC5_START_BITS_EXTENDED)
- ? RC5_EXTENDED_COMMAND_OFFSET : 0);
-}
-
-static void cx23885_input_process_raw_rc5(struct cx23885_dev *dev)
-{
- struct card_ir *ir_input = dev->ir_input;
- unsigned int code, command;
- u32 rc5;
-
- /* Ignore codes that are too short to be valid RC-5 */
- if (ir_input->last_bit < (RC5_HALF_BITS - 1))
- return;
-
- /* The library has the manchester coding backwards; XOR to adapt. */
- code = (ir_input->code & RC5_HALF_BITS_MASK) ^ RC5_HALF_BITS_MASK;
- rc5 = ir_rc5_decode(code);
-
- switch (RC5_START(rc5)) {
- case RC5_START_BITS_NORMAL:
- break;
- case RC5_START_BITS_EXTENDED:
- /* Don't allow if the remote only emits standard commands */
- if (ir_input->start == RC5_START_BITS_NORMAL)
- return;
- break;
- default:
+ if (x == V4L2_SUBDEV_IR_PULSE_RX_SEQ_END) {
+ y->pulse = false;
+ y->duration = V4L2_SUBDEV_IR_PULSE_MAX_WIDTH_NS;
return;
}
- if (ir_input->addr != RC5_ADDR(rc5))
- return;
-
- /* Don't generate a keypress for RC-5 auto-repeated keypresses */
- command = rc5_command(rc5);
- if (RC5_TOGGLE(rc5) != RC5_TOGGLE(ir_input->last_rc5) ||
- command != rc5_command(ir_input->last_rc5) ||
- /* Catch T == 0, CMD == 0 (e.g. '0') as first keypress after init */
- RC5_START(ir_input->last_rc5) == 0) {
- /* This keypress is differnet: not an auto repeat */
- ir_input_nokey(ir_input->dev, &ir_input->ir);
- ir_input_keydown(ir_input->dev, &ir_input->ir, command);
- }
- ir_input->last_rc5 = rc5;
-
- /* Schedule when we should do the key up event: ir_input_nokey() */
- mod_timer(&ir_input->timer_keyup,
- jiffies + msecs_to_jiffies(ir_input->rc5_key_timeout));
+ y->pulse = (x & V4L2_SUBDEV_IR_PULSE_LEVEL_MASK) ? true : false;
+ y->duration = x & V4L2_SUBDEV_IR_PULSE_MAX_WIDTH_NS;
}
-static void cx23885_input_next_pulse_width_rc5(struct cx23885_dev *dev,
- u32 ns_pulse)
+static void cx23885_input_process_measurements(struct cx23885_dev *dev,
+ bool overrun)
{
- const int rc5_quarterbit_ns = 444444; /* 32 cycles/36 kHz/2 = 444 us */
- struct card_ir *ir_input = dev->ir_input;
- int i, level, quarterbits, halfbits;
-
- if (!ir_input->active) {
- ir_input->active = 1;
- /* assume an initial space that we may not detect or measure */
- ir_input->code = 0;
- ir_input->last_bit = 0;
- }
+ struct cx23885_kernel_ir *kernel_ir = dev->kernel_ir;
+ struct ir_raw_event kernel_ir_event;
- if (ns_pulse == V4L2_SUBDEV_IR_PULSE_RX_SEQ_END) {
- ir_input->last_bit++; /* Account for the final space */
- ir_input->active = 0;
- cx23885_input_process_raw_rc5(dev);
- return;
- }
-
- level = (ns_pulse & V4L2_SUBDEV_IR_PULSE_LEVEL_MASK) ? 1 : 0;
-
- /* Skip any leading space to sync to the start bit */
- if (ir_input->last_bit == 0 && level == 0)
- return;
-
- /*
- * With valid RC-5 we can get up to two consecutive half-bits in a
- * single pulse measurment. Experiments have shown that the duration
- * of a half-bit can vary. Make sure we always end up with an even
- * number of quarter bits at the same level (mark or space).
- */
- ns_pulse &= V4L2_SUBDEV_IR_PULSE_MAX_WIDTH_NS;
- quarterbits = ns_pulse / rc5_quarterbit_ns;
- if (quarterbits & 1)
- quarterbits++;
- halfbits = quarterbits / 2;
-
- for (i = 0; i < halfbits; i++) {
- ir_input->last_bit++;
- ir_input->code |= (level << ir_input->last_bit);
-
- if (ir_input->last_bit >= RC5_HALF_BITS-1) {
- ir_input->active = 0;
- cx23885_input_process_raw_rc5(dev);
- /*
- * If level is 1, a leading mark is invalid for RC5.
- * If level is 0, we scan past extra intial space.
- * Either way we don't want to reactivate collecting
- * marks or spaces here with any left over half-bits.
- */
- break;
- }
- }
-}
-
-static void cx23885_input_process_pulse_widths_rc5(struct cx23885_dev *dev,
- bool add_eom)
-{
- struct card_ir *ir_input = dev->ir_input;
- struct ir_input_state *ir_input_state = &ir_input->ir;
-
- u32 ns_pulse[RC5_HALF_BITS+1];
- ssize_t num = 0;
+ u32 sd_ir_data[64];
+ ssize_t num;
int count, i;
+ bool handle = false;
do {
- v4l2_subdev_call(dev->sd_ir, ir, rx_read, (u8 *) ns_pulse,
- sizeof(ns_pulse), &num);
+ num = 0;
+ v4l2_subdev_call(dev->sd_ir, ir, rx_read, (u8 *) sd_ir_data,
+ sizeof(sd_ir_data), &num);
count = num / sizeof(u32);
- /* Append an end of Rx seq, if the caller requested */
- if (add_eom && count < ARRAY_SIZE(ns_pulse)) {
- ns_pulse[count] = V4L2_SUBDEV_IR_PULSE_RX_SEQ_END;
- count++;
+ for (i = 0; i < count; i++) {
+ convert_measurement(sd_ir_data[i], &kernel_ir_event);
+ ir_raw_event_store(kernel_ir->inp_dev,
+ &kernel_ir_event);
+ handle = true;
}
-
- /* Just drain the Rx FIFO, if we're called, but not RC-5 */
- if (ir_input_state->ir_type != IR_TYPE_RC5)
- continue;
-
- for (i = 0; i < count; i++)
- cx23885_input_next_pulse_width_rc5(dev, ns_pulse[i]);
} while (num != 0);
+
+ if (overrun)
+ ir_raw_event_reset(kernel_ir->inp_dev);
+ else if (handle)
+ ir_raw_event_handle(kernel_ir->inp_dev);
}
void cx23885_input_rx_work_handler(struct cx23885_dev *dev, u32 events)
@@ -230,7 +124,7 @@ void cx23885_input_rx_work_handler(struct cx23885_dev *dev, u32 events)
}
if (data_available)
- cx23885_input_process_pulse_widths_rc5(dev, overrun);
+ cx23885_input_process_measurements(dev, overrun);
if (overrun) {
/* If there was a FIFO overrun, clear & restart the device */
@@ -241,34 +135,15 @@ void cx23885_input_rx_work_handler(struct cx23885_dev *dev, u32 events)
}
}
-static void cx23885_input_ir_start(struct cx23885_dev *dev)
+static int cx23885_input_ir_start(struct cx23885_dev *dev)
{
- struct card_ir *ir_input = dev->ir_input;
- struct ir_input_state *ir_input_state = &ir_input->ir;
struct v4l2_subdev_ir_parameters params;
if (dev->sd_ir == NULL)
- return;
+ return -ENODEV;
atomic_set(&dev->ir_input_stopping, 0);
- /* keyup timer set up, if needed */
- switch (dev->board) {
- case CX23885_BOARD_HAUPPAUGE_HVR1850:
- case CX23885_BOARD_HAUPPAUGE_HVR1290:
- setup_timer(&ir_input->timer_keyup,
- ir_rc5_timer_keyup, /* Not actually RC-5 specific */
- (unsigned long) ir_input);
- if (ir_input_state->ir_type == IR_TYPE_RC5) {
- /*
- * RC-5 repeats a held key every
- * 64 bits * (2 * 32/36000) sec/bit = 113.778 ms
- */
- ir_input->rc5_key_timeout = 115;
- }
- break;
- }
-
v4l2_subdev_call(dev->sd_ir, ir, rx_g_parameters, &params);
switch (dev->board) {
case CX23885_BOARD_HAUPPAUGE_HVR1850:
@@ -299,11 +174,21 @@ static void cx23885_input_ir_start(struct cx23885_dev *dev)
break;
}
v4l2_subdev_call(dev->sd_ir, ir, rx_s_parameters, &params);
+ return 0;
+}
+
+static int cx23885_input_ir_open(void *priv)
+{
+ struct cx23885_kernel_ir *kernel_ir = priv;
+
+ if (kernel_ir->cx == NULL)
+ return -ENODEV;
+
+ return cx23885_input_ir_start(kernel_ir->cx);
}
static void cx23885_input_ir_stop(struct cx23885_dev *dev)
{
- struct card_ir *ir_input = dev->ir_input;
struct v4l2_subdev_ir_parameters params;
if (dev->sd_ir == NULL)
@@ -327,21 +212,26 @@ static void cx23885_input_ir_stop(struct cx23885_dev *dev)
}
flush_scheduled_work();
+}
- switch (dev->board) {
- case CX23885_BOARD_HAUPPAUGE_HVR1850:
- case CX23885_BOARD_HAUPPAUGE_HVR1290:
- del_timer_sync(&ir_input->timer_keyup);
- break;
- }
+static void cx23885_input_ir_close(void *priv)
+{
+ struct cx23885_kernel_ir *kernel_ir = priv;
+
+ if (kernel_ir->cx != NULL)
+ cx23885_input_ir_stop(kernel_ir->cx);
}
int cx23885_input_init(struct cx23885_dev *dev)
{
- struct card_ir *ir;
- struct input_dev *input_dev;
- char *ir_codes = NULL;
- int ir_type, ir_addr, ir_start;
+ struct cx23885_kernel_ir *kernel_ir;
+ struct input_dev *inp_dev;
+ struct ir_dev_props *props;
+
+ char *rc_map;
+ enum rc_driver_type driver_type;
+ unsigned long allowed_protos;
+
int ret;
/*
@@ -354,53 +244,59 @@ int cx23885_input_init(struct cx23885_dev *dev)
switch (dev->board) {
case CX23885_BOARD_HAUPPAUGE_HVR1850:
case CX23885_BOARD_HAUPPAUGE_HVR1290:
- /* Parameters for the grey Hauppauge remote for the HVR-1850 */
- ir_codes = RC_MAP_HAUPPAUGE_NEW;
- ir_type = IR_TYPE_RC5;
- ir_addr = 0x1e; /* RC-5 system bits emitted by the remote */
- ir_start = RC5_START_BITS_NORMAL; /* A basic RC-5 remote */
+ /* Integrated CX23888 IR controller */
+ driver_type = RC_DRIVER_IR_RAW;
+ allowed_protos = IR_TYPE_ALL;
+ /* The grey Hauppauge RC-5 remote */
+ rc_map = RC_MAP_RC5_HAUPPAUGE_NEW;
break;
- }
- if (ir_codes == NULL)
+ default:
return -ENODEV;
-
- ir = kzalloc(sizeof(*ir), GFP_KERNEL);
- input_dev = input_allocate_device();
- if (!ir || !input_dev) {
- ret = -ENOMEM;
- goto err_out_free;
}
- ir->dev = input_dev;
- ir->addr = ir_addr;
- ir->start = ir_start;
+ /* cx23885 board instance kernel IR state */
+ kernel_ir = kzalloc(sizeof(struct cx23885_kernel_ir), GFP_KERNEL);
+ if (kernel_ir == NULL)
+ return -ENOMEM;
- /* init input device */
- snprintf(ir->name, sizeof(ir->name), "cx23885 IR (%s)",
- cx23885_boards[dev->board].name);
- snprintf(ir->phys, sizeof(ir->phys), "pci-%s/ir0", pci_name(dev->pci));
+ kernel_ir->cx = dev;
+ kernel_ir->name = kasprintf(GFP_KERNEL, "cx23885 IR (%s)",
+ cx23885_boards[dev->board].name);
+ kernel_ir->phys = kasprintf(GFP_KERNEL, "pci-%s/ir0",
+ pci_name(dev->pci));
- ret = ir_input_init(input_dev, &ir->ir, ir_type);
- if (ret < 0)
+ /* input device */
+ inp_dev = input_allocate_device();
+ if (inp_dev == NULL) {
+ ret = -ENOMEM;
goto err_out_free;
+ }
- input_dev->name = ir->name;
- input_dev->phys = ir->phys;
- input_dev->id.bustype = BUS_PCI;
- input_dev->id.version = 1;
+ kernel_ir->inp_dev = inp_dev;
+ inp_dev->name = kernel_ir->name;
+ inp_dev->phys = kernel_ir->phys;
+ inp_dev->id.bustype = BUS_PCI;
+ inp_dev->id.version = 1;
if (dev->pci->subsystem_vendor) {
- input_dev->id.vendor = dev->pci->subsystem_vendor;
- input_dev->id.product = dev->pci->subsystem_device;
+ inp_dev->id.vendor = dev->pci->subsystem_vendor;
+ inp_dev->id.product = dev->pci->subsystem_device;
} else {
- input_dev->id.vendor = dev->pci->vendor;
- input_dev->id.product = dev->pci->device;
+ inp_dev->id.vendor = dev->pci->vendor;
+ inp_dev->id.product = dev->pci->device;
}
- input_dev->dev.parent = &dev->pci->dev;
-
- dev->ir_input = ir;
- cx23885_input_ir_start(dev);
-
- ret = ir_input_register(ir->dev, ir_codes, NULL, MODULE_NAME);
+ inp_dev->dev.parent = &dev->pci->dev;
+
+ /* kernel ir device properties */
+ props = &kernel_ir->props;
+ props->driver_type = driver_type;
+ props->allowed_protos = allowed_protos;
+ props->priv = kernel_ir;
+ props->open = cx23885_input_ir_open;
+ props->close = cx23885_input_ir_close;
+
+ /* Go */
+ dev->kernel_ir = kernel_ir;
+ ret = ir_input_register(inp_dev, rc_map, props, MODULE_NAME);
if (ret)
goto err_out_stop;
@@ -408,9 +304,12 @@ int cx23885_input_init(struct cx23885_dev *dev)
err_out_stop:
cx23885_input_ir_stop(dev);
- dev->ir_input = NULL;
+ dev->kernel_ir = NULL;
+ /* TODO: double check clean-up of kernel_ir->inp_dev */
err_out_free:
- kfree(ir);
+ kfree(kernel_ir->phys);
+ kfree(kernel_ir->name);
+ kfree(kernel_ir);
return ret;
}
@@ -419,9 +318,11 @@ void cx23885_input_fini(struct cx23885_dev *dev)
/* Always stop the IR hardware from generating interrupts */
cx23885_input_ir_stop(dev);
- if (dev->ir_input == NULL)
+ if (dev->kernel_ir == NULL)
return;
- ir_input_unregister(dev->ir_input->dev);
- kfree(dev->ir_input);
- dev->ir_input = NULL;
+ ir_input_unregister(dev->kernel_ir->inp_dev);
+ kfree(dev->kernel_ir->phys);
+ kfree(dev->kernel_ir->name);
+ kfree(dev->kernel_ir);
+ dev->kernel_ir = NULL;
}
diff --git a/drivers/media/video/cx23885/cx23885-ir.c b/drivers/media/video/cx23885/cx23885-ir.c
index 9a677eb080a..6ceabd4fba0 100644
--- a/drivers/media/video/cx23885/cx23885-ir.c
+++ b/drivers/media/video/cx23885/cx23885-ir.c
@@ -53,7 +53,7 @@ void cx23885_ir_rx_work_handler(struct work_struct *work)
if (events == 0)
return;
- if (dev->ir_input)
+ if (dev->kernel_ir)
cx23885_input_rx_work_handler(dev, events);
}
diff --git a/drivers/media/video/cx23885/cx23885.h b/drivers/media/video/cx23885/cx23885.h
index 8d6a55e54ee..a33f2b71467 100644
--- a/drivers/media/video/cx23885/cx23885.h
+++ b/drivers/media/video/cx23885/cx23885.h
@@ -30,6 +30,7 @@
#include <media/tveeprom.h>
#include <media/videobuf-dma-sg.h>
#include <media/videobuf-dvb.h>
+#include <media/ir-core.h>
#include "btcx-risc.h"
#include "cx23885-reg.h"
@@ -304,6 +305,15 @@ struct cx23885_tsport {
void *port_priv;
};
+struct cx23885_kernel_ir {
+ struct cx23885_dev *cx;
+ char *name;
+ char *phys;
+
+ struct input_dev *inp_dev;
+ struct ir_dev_props props;
+};
+
struct cx23885_dev {
atomic_t refcount;
struct v4l2_device v4l2_dev;
@@ -363,7 +373,7 @@ struct cx23885_dev {
struct work_struct ir_tx_work;
unsigned long ir_tx_notifications;
- struct card_ir *ir_input;
+ struct cx23885_kernel_ir *kernel_ir;
atomic_t ir_input_stopping;
/* V4l */
diff --git a/drivers/media/video/cx88/cx88-alsa.c b/drivers/media/video/cx88/cx88-alsa.c
index 33082c96745..4f383cdf529 100644
--- a/drivers/media/video/cx88/cx88-alsa.c
+++ b/drivers/media/video/cx88/cx88-alsa.c
@@ -54,6 +54,12 @@
Data type declarations - Can be moded to a header file later
****************************************************************************/
+struct cx88_audio_buffer {
+ unsigned int bpl;
+ struct btcx_riscmem risc;
+ struct videobuf_dmabuf dma;
+};
+
struct cx88_audio_dev {
struct cx88_core *core;
struct cx88_dmaqueue q;
@@ -75,7 +81,7 @@ struct cx88_audio_dev {
struct videobuf_dmabuf *dma_risc;
- struct cx88_buffer *buf;
+ struct cx88_audio_buffer *buf;
struct snd_pcm_substream *substream;
};
@@ -123,7 +129,7 @@ MODULE_PARM_DESC(debug,"enable debug messages");
static int _cx88_start_audio_dma(snd_cx88_card_t *chip)
{
- struct cx88_buffer *buf = chip->buf;
+ struct cx88_audio_buffer *buf = chip->buf;
struct cx88_core *core=chip->core;
struct sram_channel *audio_ch = &cx88_sram_channels[SRAM_CH25];
@@ -283,7 +289,7 @@ static int dsp_buffer_free(snd_cx88_card_t *chip)
BUG_ON(!chip->dma_size);
dprintk(2,"Freeing buffer\n");
- videobuf_sg_dma_unmap(&chip->pci->dev, chip->dma_risc);
+ videobuf_dma_unmap(&chip->pci->dev, chip->dma_risc);
videobuf_dma_free(chip->dma_risc);
btcx_riscmem_free(chip->pci,&chip->buf->risc);
kfree(chip->buf);
@@ -376,7 +382,7 @@ static int snd_cx88_hw_params(struct snd_pcm_substream * substream,
snd_cx88_card_t *chip = snd_pcm_substream_chip(substream);
struct videobuf_dmabuf *dma;
- struct cx88_buffer *buf;
+ struct cx88_audio_buffer *buf;
int ret;
if (substream->runtime->dma_area) {
@@ -391,30 +397,25 @@ static int snd_cx88_hw_params(struct snd_pcm_substream * substream,
BUG_ON(!chip->dma_size);
BUG_ON(chip->num_periods & (chip->num_periods-1));
- buf = videobuf_sg_alloc(sizeof(*buf));
+ buf = kzalloc(sizeof(*buf), GFP_KERNEL);
if (NULL == buf)
return -ENOMEM;
- buf->vb.memory = V4L2_MEMORY_MMAP;
- buf->vb.field = V4L2_FIELD_NONE;
- buf->vb.width = chip->period_size;
- buf->bpl = chip->period_size;
- buf->vb.height = chip->num_periods;
- buf->vb.size = chip->dma_size;
+ buf->bpl = chip->period_size;
- dma = videobuf_to_dma(&buf->vb);
+ dma = &buf->dma;
videobuf_dma_init(dma);
ret = videobuf_dma_init_kernel(dma, PCI_DMA_FROMDEVICE,
- (PAGE_ALIGN(buf->vb.size) >> PAGE_SHIFT));
+ (PAGE_ALIGN(chip->dma_size) >> PAGE_SHIFT));
if (ret < 0)
goto error;
- ret = videobuf_sg_dma_map(&chip->pci->dev, dma);
+ ret = videobuf_dma_map(&chip->pci->dev, dma);
if (ret < 0)
goto error;
ret = cx88_risc_databuffer(chip->pci, &buf->risc, dma->sglist,
- buf->vb.width, buf->vb.height, 1);
+ chip->period_size, chip->num_periods, 1);
if (ret < 0)
goto error;
@@ -422,12 +423,10 @@ static int snd_cx88_hw_params(struct snd_pcm_substream * substream,
buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP|RISC_IRQ1|RISC_CNT_INC);
buf->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
- buf->vb.state = VIDEOBUF_PREPARED;
-
chip->buf = buf;
chip->dma_risc = dma;
- substream->runtime->dma_area = chip->dma_risc->vmalloc;
+ substream->runtime->dma_area = chip->dma_risc->vaddr;
substream->runtime->dma_bytes = chip->dma_size;
substream->runtime->dma_addr = 0;
return 0;
@@ -740,7 +739,7 @@ static int __devinit snd_cx88_create(struct snd_card *card,
pci_set_master(pci);
- chip = (snd_cx88_card_t *) card->private_data;
+ chip = card->private_data;
core = cx88_core_get(pci);
if (NULL == core) {
diff --git a/drivers/media/video/cx88/cx88-cards.c b/drivers/media/video/cx88/cx88-cards.c
index 2918a6e38fe..e8416b76da6 100644
--- a/drivers/media/video/cx88/cx88-cards.c
+++ b/drivers/media/video/cx88/cx88-cards.c
@@ -45,6 +45,10 @@ static unsigned int latency = UNSET;
module_param(latency,int,0444);
MODULE_PARM_DESC(latency,"pci latency timer");
+static int disable_ir;
+module_param(disable_ir, int, 0444);
+MODULE_PARM_DESC(latency, "Disable IR support");
+
#define info_printk(core, fmt, arg...) \
printk(KERN_INFO "%s: " fmt, core->name , ## arg)
@@ -3498,7 +3502,10 @@ struct cx88_core *cx88_core_create(struct pci_dev *pci, int nr)
}
cx88_card_setup(core);
- cx88_ir_init(core, pci);
+ if (!disable_ir) {
+ cx88_i2c_init_ir(core);
+ cx88_ir_init(core, pci);
+ }
return core;
}
diff --git a/drivers/media/video/cx88/cx88-core.c b/drivers/media/video/cx88/cx88-core.c
index 8b21457111b..85eb266fb35 100644
--- a/drivers/media/video/cx88/cx88-core.c
+++ b/drivers/media/video/cx88/cx88-core.c
@@ -218,7 +218,7 @@ cx88_free_buffer(struct videobuf_queue *q, struct cx88_buffer *buf)
BUG_ON(in_interrupt());
videobuf_waiton(&buf->vb,0,0);
- videobuf_dma_unmap(q, dma);
+ videobuf_dma_unmap(q->dev, dma);
videobuf_dma_free(dma);
btcx_riscmem_free(to_pci_dev(q->dev), &buf->risc);
buf->vb.state = VIDEOBUF_NEEDS_INIT;
diff --git a/drivers/media/video/cx88/cx88-i2c.c b/drivers/media/video/cx88/cx88-i2c.c
index fb39f118455..375ad53f796 100644
--- a/drivers/media/video/cx88/cx88-i2c.c
+++ b/drivers/media/video/cx88/cx88-i2c.c
@@ -181,6 +181,11 @@ int cx88_i2c_init(struct cx88_core *core, struct pci_dev *pci)
} else
printk("%s: i2c register FAILED\n", core->name);
+ return core->i2c_rc;
+}
+
+void cx88_i2c_init_ir(struct cx88_core *core)
+{
/* Instantiate the IR receiver device, if present */
if (0 == core->i2c_rc) {
struct i2c_board_info info;
@@ -207,7 +212,6 @@ int cx88_i2c_init(struct cx88_core *core, struct pci_dev *pci)
}
}
}
- return core->i2c_rc;
}
/* ----------------------------------------------------------------------- */
diff --git a/drivers/media/video/cx88/cx88-input.c b/drivers/media/video/cx88/cx88-input.c
index e185289e446..eccc5e49a35 100644
--- a/drivers/media/video/cx88/cx88-input.c
+++ b/drivers/media/video/cx88/cx88-input.c
@@ -30,6 +30,7 @@
#include <linux/module.h>
#include "cx88.h"
+#include <media/ir-core.h>
#include <media/ir-common.h>
#define MODULE_NAME "cx88xx"
@@ -39,8 +40,8 @@
struct cx88_IR {
struct cx88_core *core;
struct input_dev *input;
- struct ir_input_state ir;
struct ir_dev_props props;
+ u64 ir_type;
int users;
@@ -51,7 +52,6 @@ struct cx88_IR {
u32 sampling;
u32 samples[16];
int scount;
- unsigned long release;
/* poll external decoder */
int polling;
@@ -125,29 +125,21 @@ static void cx88_ir_handle_key(struct cx88_IR *ir)
data = (data << 4) | ((gpio_key & 0xf0) >> 4);
- ir_input_keydown(ir->input, &ir->ir, data);
- ir_input_nokey(ir->input, &ir->ir);
+ ir_keydown(ir->input, data, 0);
} else if (ir->mask_keydown) {
/* bit set on keydown */
- if (gpio & ir->mask_keydown) {
- ir_input_keydown(ir->input, &ir->ir, data);
- } else {
- ir_input_nokey(ir->input, &ir->ir);
- }
+ if (gpio & ir->mask_keydown)
+ ir_keydown(ir->input, data, 0);
} else if (ir->mask_keyup) {
/* bit cleared on keydown */
- if (0 == (gpio & ir->mask_keyup)) {
- ir_input_keydown(ir->input, &ir->ir, data);
- } else {
- ir_input_nokey(ir->input, &ir->ir);
- }
+ if (0 == (gpio & ir->mask_keyup))
+ ir_keydown(ir->input, data, 0);
} else {
/* can't distinguish keydown/up :-/ */
- ir_input_keydown(ir->input, &ir->ir, data);
- ir_input_nokey(ir->input, &ir->ir);
+ ir_keydown(ir->input, data, 0);
}
}
@@ -439,9 +431,7 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci)
snprintf(ir->name, sizeof(ir->name), "cx88 IR (%s)", core->board.name);
snprintf(ir->phys, sizeof(ir->phys), "pci-%s/ir0", pci_name(pci));
- err = ir_input_init(input_dev, &ir->ir, ir_type);
- if (err < 0)
- goto err_out_free;
+ ir->ir_type = ir_type;
input_dev->name = ir->name;
input_dev->phys = ir->phys;
@@ -516,8 +506,6 @@ void cx88_ir_irq(struct cx88_core *core)
}
if (!ir->scount) {
/* nothing to sample */
- if (ir->ir.keypressed && time_after(jiffies, ir->release))
- ir_input_nokey(ir->input, &ir->ir);
return;
}
@@ -553,7 +541,7 @@ void cx88_ir_irq(struct cx88_core *core)
if (ircode == 0) { /* key still pressed */
ir_dprintk("pulse distance decoded repeat code\n");
- ir->release = jiffies + msecs_to_jiffies(120);
+ ir_repeat(ir->input);
break;
}
@@ -567,10 +555,8 @@ void cx88_ir_irq(struct cx88_core *core)
break;
}
- ir_dprintk("Key Code: %x\n", (ircode >> 16) & 0x7f);
-
- ir_input_keydown(ir->input, &ir->ir, (ircode >> 16) & 0x7f);
- ir->release = jiffies + msecs_to_jiffies(120);
+ ir_dprintk("Key Code: %x\n", (ircode >> 16) & 0xff);
+ ir_keydown(ir->input, (ircode >> 16) & 0xff, 0);
break;
case CX88_BOARD_HAUPPAUGE:
case CX88_BOARD_HAUPPAUGE_DVB_T1:
@@ -606,16 +592,16 @@ void cx88_ir_irq(struct cx88_core *core)
if ( dev != 0x1e && dev != 0x1f )
/* not a hauppauge remote */
break;
- ir_input_keydown(ir->input, &ir->ir, code);
- ir->release = jiffies + msecs_to_jiffies(120);
+ ir_keydown(ir->input, code, toggle);
break;
case CX88_BOARD_PINNACLE_PCTV_HD_800i:
ircode = ir_decode_biphase(ir->samples, ir->scount, 5, 7);
ir_dprintk("biphase decoded: %x\n", ircode);
if ((ircode & 0xfffff000) != 0x3000)
break;
- ir_input_keydown(ir->input, &ir->ir, ircode & 0x3f);
- ir->release = jiffies + msecs_to_jiffies(120);
+ /* Note: bit 0x800 being the toggle is assumed, not checked
+ with real hardware */
+ ir_keydown(ir->input, ircode & 0x3f, ircode & 0x0800 ? 1 : 0);
break;
}
diff --git a/drivers/media/video/cx88/cx88.h b/drivers/media/video/cx88/cx88.h
index bdb03d33653..33d161a1172 100644
--- a/drivers/media/video/cx88/cx88.h
+++ b/drivers/media/video/cx88/cx88.h
@@ -636,6 +636,7 @@ extern struct videobuf_queue_ops cx8800_vbi_qops;
/* cx88-i2c.c */
extern int cx88_i2c_init(struct cx88_core *core, struct pci_dev *pci);
+extern void cx88_i2c_init_ir(struct cx88_core *core);
/* ----------------------------------------------------------- */
diff --git a/drivers/media/video/dabusb.c b/drivers/media/video/dabusb.c
index 0f505086774..5b176bd7afd 100644
--- a/drivers/media/video/dabusb.c
+++ b/drivers/media/video/dabusb.c
@@ -706,16 +706,11 @@ static long dabusb_ioctl (struct file *file, unsigned int cmd, unsigned long arg
switch (cmd) {
case IOCTL_DAB_BULK:
- pbulk = kmalloc(sizeof (bulk_transfer_t), GFP_KERNEL);
+ pbulk = memdup_user((void __user *)arg,
+ sizeof(bulk_transfer_t));
- if (!pbulk) {
- ret = -ENOMEM;
- break;
- }
-
- if (copy_from_user (pbulk, (void __user *) arg, sizeof (bulk_transfer_t))) {
- ret = -EFAULT;
- kfree (pbulk);
+ if (IS_ERR(pbulk)) {
+ ret = PTR_ERR(pbulk);
break;
}
diff --git a/drivers/media/video/davinci/Kconfig b/drivers/media/video/davinci/Kconfig
new file mode 100644
index 00000000000..6b195403564
--- /dev/null
+++ b/drivers/media/video/davinci/Kconfig
@@ -0,0 +1,93 @@
+config DISPLAY_DAVINCI_DM646X_EVM
+ tristate "DM646x EVM Video Display"
+ depends on VIDEO_DEV && MACH_DAVINCI_DM6467_EVM
+ select VIDEOBUF_DMA_CONTIG
+ select VIDEO_DAVINCI_VPIF
+ select VIDEO_ADV7343
+ select VIDEO_THS7303
+ help
+ Support for DM6467 based display device.
+
+ To compile this driver as a module, choose M here: the
+ module will be called vpif_display.
+
+config CAPTURE_DAVINCI_DM646X_EVM
+ tristate "DM646x EVM Video Capture"
+ depends on VIDEO_DEV && MACH_DAVINCI_DM6467_EVM
+ select VIDEOBUF_DMA_CONTIG
+ select VIDEO_DAVINCI_VPIF
+ help
+ Support for DM6467 based capture device.
+
+ To compile this driver as a module, choose M here: the
+ module will be called vpif_capture.
+
+config VIDEO_DAVINCI_VPIF
+ tristate "DaVinci VPIF Driver"
+ depends on DISPLAY_DAVINCI_DM646X_EVM
+ help
+ Support for DaVinci VPIF Driver.
+
+ To compile this driver as a module, choose M here: the
+ module will be called vpif.
+
+config VIDEO_VPSS_SYSTEM
+ tristate "VPSS System module driver"
+ depends on ARCH_DAVINCI
+ help
+ Support for vpss system module for video driver
+
+config VIDEO_VPFE_CAPTURE
+ tristate "VPFE Video Capture Driver"
+ depends on VIDEO_V4L2 && (ARCH_DAVINCI || ARCH_OMAP3)
+ select VIDEOBUF_DMA_CONTIG
+ help
+ Support for DMx/AMx VPFE based frame grabber. This is the
+ common V4L2 module for following DMx/AMx SoCs from Texas
+ Instruments:- DM6446, DM365, DM355 & AM3517/05.
+
+ To compile this driver as a module, choose M here: the
+ module will be called vpfe-capture.
+
+config VIDEO_DM6446_CCDC
+ tristate "DM6446 CCDC HW module"
+ depends on VIDEO_VPFE_CAPTURE
+ select VIDEO_VPSS_SYSTEM
+ default y
+ help
+ Enables DaVinci CCD hw module. DaVinci CCDC hw interfaces
+ with decoder modules such as TVP5146 over BT656 or
+ sensor module such as MT9T001 over a raw interface. This
+ module configures the interface and CCDC/ISIF to do
+ video frame capture from slave decoders.
+
+ To compile this driver as a module, choose M here: the
+ module will be called vpfe.
+
+config VIDEO_DM355_CCDC
+ tristate "DM355 CCDC HW module"
+ depends on ARCH_DAVINCI_DM355 && VIDEO_VPFE_CAPTURE
+ select VIDEO_VPSS_SYSTEM
+ default y
+ help
+ Enables DM355 CCD hw module. DM355 CCDC hw interfaces
+ with decoder modules such as TVP5146 over BT656 or
+ sensor module such as MT9T001 over a raw interface. This
+ module configures the interface and CCDC/ISIF to do
+ video frame capture from a slave decoders
+
+ To compile this driver as a module, choose M here: the
+ module will be called vpfe.
+
+config VIDEO_ISIF
+ tristate "ISIF HW module"
+ depends on ARCH_DAVINCI_DM365 && VIDEO_VPFE_CAPTURE
+ select VIDEO_VPSS_SYSTEM
+ default y
+ help
+ Enables ISIF hw module. This is the hardware module for
+ configuring ISIF in VPFE to capture Raw Bayer RGB data from
+ a image sensor or YUV data from a YUV source.
+
+ To compile this driver as a module, choose M here: the
+ module will be called vpfe.
diff --git a/drivers/media/video/em28xx/em28xx-cards.c b/drivers/media/video/em28xx/em28xx-cards.c
index 3a4fd851451..ffbe544e30f 100644
--- a/drivers/media/video/em28xx/em28xx-cards.c
+++ b/drivers/media/video/em28xx/em28xx-cards.c
@@ -158,6 +158,22 @@ static struct em28xx_reg_seq evga_indtube_digital[] = {
{ -1, -1, -1, -1},
};
+/*
+ * KWorld PlusTV 340U and UB435-Q (ATSC) GPIOs map:
+ * EM_GPIO_0 - currently unknown
+ * EM_GPIO_1 - LED disable/enable (1 = off, 0 = on)
+ * EM_GPIO_2 - currently unknown
+ * EM_GPIO_3 - currently unknown
+ * EM_GPIO_4 - TDA18271HD/C1 tuner (1 = active, 0 = in reset)
+ * EM_GPIO_5 - LGDT3304 ATSC/QAM demod (1 = active, 0 = in reset)
+ * EM_GPIO_6 - currently unknown
+ * EM_GPIO_7 - currently unknown
+ */
+static struct em28xx_reg_seq kworld_a340_digital[] = {
+ {EM28XX_R08_GPIO, 0x6d, ~EM_GPIO_4, 10},
+ { -1, -1, -1, -1},
+};
+
/* Pinnacle Hybrid Pro eb1a:2881 */
static struct em28xx_reg_seq pinnacle_hybrid_pro_analog[] = {
{EM28XX_R08_GPIO, 0xfd, ~EM_GPIO_4, 10},
@@ -1667,6 +1683,16 @@ struct em28xx_board em28xx_boards[] = {
.tuner_gpio = reddo_dvb_c_usb_box,
.has_dvb = 1,
},
+ /* 1b80:a340 - Empia EM2870, NXP TDA18271HD and LG DT3304, sold
+ * initially as the KWorld PlusTV 340U, then as the UB435-Q.
+ * Early variants have a TDA18271HD/C1, later ones a TDA18271HD/C2 */
+ [EM2870_BOARD_KWORLD_A340] = {
+ .name = "KWorld PlusTV 340U or UB435-Q (ATSC)",
+ .tuner_type = TUNER_ABSENT, /* Digital-only TDA18271HD */
+ .has_dvb = 1,
+ .dvb_gpio = kworld_a340_digital,
+ .tuner_gpio = default_tuner_gpio,
+ },
};
const unsigned int em28xx_bcount = ARRAY_SIZE(em28xx_boards);
@@ -1788,6 +1814,8 @@ struct usb_device_id em28xx_id_table[] = {
.driver_info = EM2820_BOARD_IODATA_GVMVP_SZ },
{ USB_DEVICE(0xeb1a, 0x50a6),
.driver_info = EM2860_BOARD_GADMEI_UTV330 },
+ { USB_DEVICE(0x1b80, 0xa340),
+ .driver_info = EM2870_BOARD_KWORLD_A340 },
{ },
};
MODULE_DEVICE_TABLE(usb, em28xx_id_table);
diff --git a/drivers/media/video/em28xx/em28xx-dvb.c b/drivers/media/video/em28xx/em28xx-dvb.c
index cf1d8c3655f..3ac8d3025fe 100644
--- a/drivers/media/video/em28xx/em28xx-dvb.c
+++ b/drivers/media/video/em28xx/em28xx-dvb.c
@@ -30,11 +30,13 @@
#include "tuner-simple.h"
#include "lgdt330x.h"
+#include "lgdt3305.h"
#include "zl10353.h"
#include "s5h1409.h"
#include "mt352.h"
#include "mt352_priv.h" /* FIXME */
#include "tda1002x.h"
+#include "tda18271.h"
MODULE_DESCRIPTION("driver for em28xx based DVB cards");
MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@infradead.org>");
@@ -231,6 +233,18 @@ static struct lgdt330x_config em2880_lgdt3303_dev = {
.demod_chip = LGDT3303,
};
+static struct lgdt3305_config em2870_lgdt3304_dev = {
+ .i2c_addr = 0x0e,
+ .demod_chip = LGDT3304,
+ .spectral_inversion = 1,
+ .deny_i2c_rptr = 1,
+ .mpeg_mode = LGDT3305_MPEG_PARALLEL,
+ .tpclk_edge = LGDT3305_TPCLK_FALLING_EDGE,
+ .tpvalid_polarity = LGDT3305_TP_VALID_HIGH,
+ .vsb_if_khz = 3250,
+ .qam_if_khz = 4000,
+};
+
static struct zl10353_config em28xx_zl10353_with_xc3028 = {
.demod_address = (0x1e >> 1),
.no_tuner = 1,
@@ -247,6 +261,17 @@ static struct s5h1409_config em28xx_s5h1409_with_xc3028 = {
.mpeg_timing = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK
};
+static struct tda18271_std_map kworld_a340_std_map = {
+ .atsc_6 = { .if_freq = 3250, .agc_mode = 3, .std = 0,
+ .if_lvl = 1, .rfagc_top = 0x37, },
+ .qam_6 = { .if_freq = 4000, .agc_mode = 3, .std = 1,
+ .if_lvl = 1, .rfagc_top = 0x37, },
+};
+
+static struct tda18271_config kworld_a340_config = {
+ .std_map = &kworld_a340_std_map,
+};
+
static struct zl10353_config em28xx_zl10353_xc3028_no_i2c_gate = {
.demod_address = (0x1e >> 1),
.no_tuner = 1,
@@ -572,6 +597,14 @@ static int dvb_init(struct em28xx *dev)
}
}
break;
+ case EM2870_BOARD_KWORLD_A340:
+ dvb->frontend = dvb_attach(lgdt3305_attach,
+ &em2870_lgdt3304_dev,
+ &dev->i2c_adap);
+ if (dvb->frontend != NULL)
+ dvb_attach(tda18271_attach, dvb->frontend, 0x60,
+ &dev->i2c_adap, &kworld_a340_config);
+ break;
default:
em28xx_errdev("/2: The frontend of your DVB/ATSC card"
" isn't supported yet\n");
diff --git a/drivers/media/video/em28xx/em28xx-input.c b/drivers/media/video/em28xx/em28xx-input.c
index 5c3fd9411b1..6759cd5570d 100644
--- a/drivers/media/video/em28xx/em28xx-input.c
+++ b/drivers/media/video/em28xx/em28xx-input.c
@@ -65,17 +65,14 @@ struct em28xx_ir_poll_result {
struct em28xx_IR {
struct em28xx *dev;
struct input_dev *input;
- struct ir_input_state ir;
char name[32];
char phys[32];
/* poll external decoder */
int polling;
struct delayed_work work;
- unsigned int last_toggle:1;
unsigned int full_code:1;
unsigned int last_readcount;
- unsigned int repeat_interval;
int (*get_key)(struct em28xx_IR *, struct em28xx_ir_poll_result *);
@@ -291,67 +288,39 @@ static int em2874_polling_getkey(struct em28xx_IR *ir,
static void em28xx_ir_handle_key(struct em28xx_IR *ir)
{
int result;
- int do_sendkey = 0;
struct em28xx_ir_poll_result poll_result;
/* read the registers containing the IR status */
result = ir->get_key(ir, &poll_result);
- if (result < 0) {
+ if (unlikely(result < 0)) {
dprintk("ir->get_key() failed %d\n", result);
return;
}
- dprintk("ir->get_key result tb=%02x rc=%02x lr=%02x data=%02x%02x\n",
- poll_result.toggle_bit, poll_result.read_count,
- ir->last_readcount, poll_result.rc_address,
- poll_result.rc_data[0]);
-
- if (ir->dev->chip_id == CHIP_ID_EM2874) {
- /* The em2874 clears the readcount field every time the
- register is read. The em2860/2880 datasheet says that it
- is supposed to clear the readcount, but it doesn't. So with
- the em2874, we are looking for a non-zero read count as
- opposed to a readcount that is incrementing */
- ir->last_readcount = 0;
- }
-
- if (poll_result.read_count == 0) {
- /* The button has not been pressed since the last read */
- } else if (ir->last_toggle != poll_result.toggle_bit) {
- /* A button has been pressed */
- dprintk("button has been pressed\n");
- ir->last_toggle = poll_result.toggle_bit;
- ir->repeat_interval = 0;
- do_sendkey = 1;
- } else if (poll_result.toggle_bit == ir->last_toggle &&
- poll_result.read_count > 0 &&
- poll_result.read_count != ir->last_readcount) {
- /* The button is still being held down */
- dprintk("button being held down\n");
-
- /* Debouncer for first keypress */
- if (ir->repeat_interval++ > 9) {
- /* Start repeating after 1 second */
- do_sendkey = 1;
- }
- }
-
- if (do_sendkey) {
- dprintk("sending keypress\n");
-
+ if (unlikely(poll_result.read_count != ir->last_readcount)) {
+ dprintk("%s: toggle: %d, count: %d, key 0x%02x%02x\n", __func__,
+ poll_result.toggle_bit, poll_result.read_count,
+ poll_result.rc_address, poll_result.rc_data[0]);
if (ir->full_code)
- ir_input_keydown(ir->input, &ir->ir,
- poll_result.rc_address << 8 |
- poll_result.rc_data[0]);
+ ir_keydown(ir->input,
+ poll_result.rc_address << 8 |
+ poll_result.rc_data[0],
+ poll_result.toggle_bit);
else
- ir_input_keydown(ir->input, &ir->ir,
- poll_result.rc_data[0]);
-
- ir_input_nokey(ir->input, &ir->ir);
+ ir_keydown(ir->input,
+ poll_result.rc_data[0],
+ poll_result.toggle_bit);
+
+ if (ir->dev->chip_id == CHIP_ID_EM2874)
+ /* The em2874 clears the readcount field every time the
+ register is read. The em2860/2880 datasheet says that it
+ is supposed to clear the readcount, but it doesn't. So with
+ the em2874, we are looking for a non-zero read count as
+ opposed to a readcount that is incrementing */
+ ir->last_readcount = 0;
+ else
+ ir->last_readcount = poll_result.read_count;
}
-
- ir->last_readcount = poll_result.read_count;
- return;
}
static void em28xx_ir_work(struct work_struct *work)
@@ -466,11 +435,6 @@ int em28xx_ir_init(struct em28xx *dev)
usb_make_path(dev->udev, ir->phys, sizeof(ir->phys));
strlcat(ir->phys, "/input0", sizeof(ir->phys));
- /* Set IR protocol */
- err = ir_input_init(input_dev, &ir->ir, IR_TYPE_OTHER);
- if (err < 0)
- goto err_out_free;
-
input_dev->name = ir->name;
input_dev->phys = ir->phys;
input_dev->id.bustype = BUS_USB;
diff --git a/drivers/media/video/em28xx/em28xx-video.c b/drivers/media/video/em28xx/em28xx-video.c
index 20090e34173..7b9ec6e493e 100644
--- a/drivers/media/video/em28xx/em28xx-video.c
+++ b/drivers/media/video/em28xx/em28xx-video.c
@@ -654,12 +654,12 @@ static inline int em28xx_isoc_copy_vbi(struct em28xx *dev, struct urb *urb)
}
if (buf != NULL && dev->capture_type == 2) {
- if (len > 4 && p[0] == 0x88 && p[1] == 0x88 &&
+ if (len >= 4 && p[0] == 0x88 && p[1] == 0x88 &&
p[2] == 0x88 && p[3] == 0x88) {
p += 4;
len -= 4;
}
- if (len > 4 && p[0] == 0x22 && p[1] == 0x5a) {
+ if (len >= 4 && p[0] == 0x22 && p[1] == 0x5a) {
em28xx_isocdbg("Video frame %d, len=%i, %s\n",
p[2], len, (p[2] & 1) ?
"odd" : "even");
diff --git a/drivers/media/video/em28xx/em28xx.h b/drivers/media/video/em28xx/em28xx.h
index b252d1b1b2a..1c61a6b65d2 100644
--- a/drivers/media/video/em28xx/em28xx.h
+++ b/drivers/media/video/em28xx/em28xx.h
@@ -32,6 +32,7 @@
#include <linux/i2c.h>
#include <linux/mutex.h>
#include <media/ir-kbd-i2c.h>
+#include <media/ir-core.h>
#if defined(CONFIG_VIDEO_EM28XX_DVB) || defined(CONFIG_VIDEO_EM28XX_DVB_MODULE)
#include <media/videobuf-dvb.h>
#endif
@@ -113,6 +114,7 @@
#define EM2870_BOARD_REDDO_DVB_C_USB_BOX 73
#define EM2800_BOARD_VC211A 74
#define EM2882_BOARD_DIKOM_DK300 75
+#define EM2870_BOARD_KWORLD_A340 76
/* Limits minimum and default number of buffers */
#define EM28XX_MIN_BUF 4
diff --git a/drivers/media/video/fsl-viu.c b/drivers/media/video/fsl-viu.c
new file mode 100644
index 00000000000..8f1c94f7e00
--- /dev/null
+++ b/drivers/media/video/fsl-viu.c
@@ -0,0 +1,1632 @@
+/*
+ * Copyright 2008-2010 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * Freescale VIU video driver
+ *
+ * Authors: Hongjun Chen <hong-jun.chen@freescale.com>
+ * Porting to 2.6.35 by DENX Software Engineering,
+ * Anatolij Gustschin <agust@denx.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 <linux/module.h>
+#include <linux/clk.h>
+#include <linux/kernel.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/of_platform.h>
+#include <linux/version.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ioctl.h>
+#include <media/videobuf-dma-contig.h>
+
+#define DRV_NAME "fsl_viu"
+#define VIU_MAJOR_VERSION 0
+#define VIU_MINOR_VERSION 5
+#define VIU_RELEASE 0
+#define VIU_VERSION KERNEL_VERSION(VIU_MAJOR_VERSION, \
+ VIU_MINOR_VERSION, \
+ VIU_RELEASE)
+
+#define BUFFER_TIMEOUT msecs_to_jiffies(500) /* 0.5 seconds */
+
+#define VIU_VID_MEM_LIMIT 4 /* Video memory limit, in Mb */
+
+/* I2C address of video decoder chip is 0x4A */
+#define VIU_VIDEO_DECODER_ADDR 0x25
+
+/* supported controls */
+static struct v4l2_queryctrl viu_qctrl[] = {
+ {
+ .id = V4L2_CID_BRIGHTNESS,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Brightness",
+ .minimum = 0,
+ .maximum = 255,
+ .step = 1,
+ .default_value = 127,
+ .flags = 0,
+ }, {
+ .id = V4L2_CID_CONTRAST,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Contrast",
+ .minimum = 0,
+ .maximum = 255,
+ .step = 0x1,
+ .default_value = 0x10,
+ .flags = 0,
+ }, {
+ .id = V4L2_CID_SATURATION,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Saturation",
+ .minimum = 0,
+ .maximum = 255,
+ .step = 0x1,
+ .default_value = 127,
+ .flags = 0,
+ }, {
+ .id = V4L2_CID_HUE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Hue",
+ .minimum = -128,
+ .maximum = 127,
+ .step = 0x1,
+ .default_value = 0,
+ .flags = 0,
+ }
+};
+
+static int qctl_regs[ARRAY_SIZE(viu_qctrl)];
+
+static int info_level;
+
+#define dprintk(level, fmt, arg...) \
+ do { \
+ if (level <= info_level) \
+ printk(KERN_DEBUG "viu: " fmt , ## arg); \
+ } while (0)
+
+/*
+ * Basic structures
+ */
+struct viu_fmt {
+ char name[32];
+ u32 fourcc; /* v4l2 format id */
+ u32 pixelformat;
+ int depth;
+};
+
+static struct viu_fmt formats[] = {
+ {
+ .name = "RGB-16 (5/B-6/G-5/R)",
+ .fourcc = V4L2_PIX_FMT_RGB565,
+ .pixelformat = V4L2_PIX_FMT_RGB565,
+ .depth = 16,
+ }, {
+ .name = "RGB-32 (A-R-G-B)",
+ .fourcc = V4L2_PIX_FMT_RGB32,
+ .pixelformat = V4L2_PIX_FMT_RGB32,
+ .depth = 32,
+ }
+};
+
+struct viu_dev;
+struct viu_buf;
+
+/* buffer for one video frame */
+struct viu_buf {
+ /* common v4l buffer stuff -- must be first */
+ struct videobuf_buffer vb;
+ struct viu_fmt *fmt;
+};
+
+struct viu_dmaqueue {
+ struct viu_dev *dev;
+ struct list_head active;
+ struct list_head queued;
+ struct timer_list timeout;
+};
+
+struct viu_status {
+ u32 field_irq;
+ u32 vsync_irq;
+ u32 hsync_irq;
+ u32 vstart_irq;
+ u32 dma_end_irq;
+ u32 error_irq;
+};
+
+struct viu_reg {
+ u32 status_cfg;
+ u32 luminance;
+ u32 chroma_r;
+ u32 chroma_g;
+ u32 chroma_b;
+ u32 field_base_addr;
+ u32 dma_inc;
+ u32 picture_count;
+ u32 req_alarm;
+ u32 alpha;
+} __attribute__ ((packed));
+
+struct viu_dev {
+ struct v4l2_device v4l2_dev;
+ struct mutex lock;
+ spinlock_t slock;
+ int users;
+
+ struct device *dev;
+ /* various device info */
+ struct video_device *vdev;
+ struct viu_dmaqueue vidq;
+ enum v4l2_field capfield;
+ int field;
+ int first;
+ int dma_done;
+
+ /* Hardware register area */
+ struct viu_reg *vr;
+
+ /* Interrupt vector */
+ int irq;
+ struct viu_status irqs;
+
+ /* video overlay */
+ struct v4l2_framebuffer ovbuf;
+ struct viu_fmt *ovfmt;
+ unsigned int ovenable;
+ enum v4l2_field ovfield;
+
+ /* crop */
+ struct v4l2_rect crop_current;
+
+ /* clock pointer */
+ struct clk *clk;
+
+ /* decoder */
+ struct v4l2_subdev *decoder;
+};
+
+struct viu_fh {
+ struct viu_dev *dev;
+
+ /* video capture */
+ struct videobuf_queue vb_vidq;
+ spinlock_t vbq_lock; /* spinlock for the videobuf queue */
+
+ /* video overlay */
+ struct v4l2_window win;
+ struct v4l2_clip clips[1];
+
+ /* video capture */
+ struct viu_fmt *fmt;
+ int width, height, sizeimage;
+ enum v4l2_buf_type type;
+};
+
+static struct viu_reg reg_val;
+
+/*
+ * Macro definitions of VIU registers
+ */
+
+/* STATUS_CONFIG register */
+enum status_config {
+ SOFT_RST = 1 << 0,
+
+ ERR_MASK = 0x0f << 4, /* Error code mask */
+ ERR_NO = 0x00, /* No error */
+ ERR_DMA_V = 0x01 << 4, /* DMA in vertical active */
+ ERR_DMA_VB = 0x02 << 4, /* DMA in vertical blanking */
+ ERR_LINE_TOO_LONG = 0x04 << 4, /* Line too long */
+ ERR_TOO_MANG_LINES = 0x05 << 4, /* Too many lines in field */
+ ERR_LINE_TOO_SHORT = 0x06 << 4, /* Line too short */
+ ERR_NOT_ENOUGH_LINE = 0x07 << 4, /* Not enough lines in field */
+ ERR_FIFO_OVERFLOW = 0x08 << 4, /* FIFO overflow */
+ ERR_FIFO_UNDERFLOW = 0x09 << 4, /* FIFO underflow */
+ ERR_1bit_ECC = 0x0a << 4, /* One bit ECC error */
+ ERR_MORE_ECC = 0x0b << 4, /* Two/more bits ECC error */
+
+ INT_FIELD_EN = 0x01 << 8, /* Enable field interrupt */
+ INT_VSYNC_EN = 0x01 << 9, /* Enable vsync interrupt */
+ INT_HSYNC_EN = 0x01 << 10, /* Enable hsync interrupt */
+ INT_VSTART_EN = 0x01 << 11, /* Enable vstart interrupt */
+ INT_DMA_END_EN = 0x01 << 12, /* Enable DMA end interrupt */
+ INT_ERROR_EN = 0x01 << 13, /* Enable error interrupt */
+ INT_ECC_EN = 0x01 << 14, /* Enable ECC interrupt */
+
+ INT_FIELD_STATUS = 0x01 << 16, /* field interrupt status */
+ INT_VSYNC_STATUS = 0x01 << 17, /* vsync interrupt status */
+ INT_HSYNC_STATUS = 0x01 << 18, /* hsync interrupt status */
+ INT_VSTART_STATUS = 0x01 << 19, /* vstart interrupt status */
+ INT_DMA_END_STATUS = 0x01 << 20, /* DMA end interrupt status */
+ INT_ERROR_STATUS = 0x01 << 21, /* error interrupt status */
+
+ DMA_ACT = 0x01 << 27, /* Enable DMA transfer */
+ FIELD_NO = 0x01 << 28, /* Field number */
+ DITHER_ON = 0x01 << 29, /* Dithering is on */
+ ROUND_ON = 0x01 << 30, /* Round is on */
+ MODE_32BIT = 0x01 << 31, /* Data in RGBa888,
+ * 0 in RGB565
+ */
+};
+
+#define norm_maxw() 720
+#define norm_maxh() 576
+
+#define INT_ALL_STATUS (INT_FIELD_STATUS | INT_VSYNC_STATUS | \
+ INT_HSYNC_STATUS | INT_VSTART_STATUS | \
+ INT_DMA_END_STATUS | INT_ERROR_STATUS)
+
+#define NUM_FORMATS ARRAY_SIZE(formats)
+
+static irqreturn_t viu_intr(int irq, void *dev_id);
+
+struct viu_fmt *format_by_fourcc(int fourcc)
+{
+ int i;
+
+ for (i = 0; i < NUM_FORMATS; i++) {
+ if (formats[i].pixelformat == fourcc)
+ return formats + i;
+ }
+
+ dprintk(0, "unknown pixelformat:'%4.4s'\n", (char *)&fourcc);
+ return NULL;
+}
+
+void viu_start_dma(struct viu_dev *dev)
+{
+ struct viu_reg *vr = dev->vr;
+
+ dev->field = 0;
+
+ /* Enable DMA operation */
+ out_be32(&vr->status_cfg, SOFT_RST);
+ out_be32(&vr->status_cfg, INT_FIELD_EN);
+}
+
+void viu_stop_dma(struct viu_dev *dev)
+{
+ struct viu_reg *vr = dev->vr;
+ int cnt = 100;
+ u32 status_cfg;
+
+ out_be32(&vr->status_cfg, 0);
+
+ /* Clear pending interrupts */
+ status_cfg = in_be32(&vr->status_cfg);
+ if (status_cfg & 0x3f0000)
+ out_be32(&vr->status_cfg, status_cfg & 0x3f0000);
+
+ if (status_cfg & DMA_ACT) {
+ do {
+ status_cfg = in_be32(&vr->status_cfg);
+ if (status_cfg & INT_DMA_END_STATUS)
+ break;
+ } while (cnt--);
+
+ if (cnt < 0) {
+ /* timed out, issue soft reset */
+ out_be32(&vr->status_cfg, SOFT_RST);
+ out_be32(&vr->status_cfg, 0);
+ } else {
+ /* clear DMA_END and other pending irqs */
+ out_be32(&vr->status_cfg, status_cfg & 0x3f0000);
+ }
+ }
+
+ dev->field = 0;
+}
+
+static int restart_video_queue(struct viu_dmaqueue *vidq)
+{
+ struct viu_buf *buf, *prev;
+
+ dprintk(1, "%s vidq=0x%08lx\n", __func__, (unsigned long)vidq);
+ if (!list_empty(&vidq->active)) {
+ buf = list_entry(vidq->active.next, struct viu_buf, vb.queue);
+ dprintk(2, "restart_queue [%p/%d]: restart dma\n",
+ buf, buf->vb.i);
+
+ viu_stop_dma(vidq->dev);
+
+ /* cancel all outstanding capture requests */
+ list_for_each_entry_safe(buf, prev, &vidq->active, vb.queue) {
+ list_del(&buf->vb.queue);
+ buf->vb.state = VIDEOBUF_ERROR;
+ wake_up(&buf->vb.done);
+ }
+ mod_timer(&vidq->timeout, jiffies+BUFFER_TIMEOUT);
+ return 0;
+ }
+
+ prev = NULL;
+ for (;;) {
+ if (list_empty(&vidq->queued))
+ return 0;
+ buf = list_entry(vidq->queued.next, struct viu_buf, vb.queue);
+ if (prev == NULL) {
+ list_del(&buf->vb.queue);
+ list_add_tail(&buf->vb.queue, &vidq->active);
+
+ dprintk(1, "Restarting video dma\n");
+ viu_stop_dma(vidq->dev);
+ viu_start_dma(vidq->dev);
+
+ buf->vb.state = VIDEOBUF_ACTIVE;
+ mod_timer(&vidq->timeout, jiffies+BUFFER_TIMEOUT);
+ dprintk(2, "[%p/%d] restart_queue - first active\n",
+ buf, buf->vb.i);
+
+ } else if (prev->vb.width == buf->vb.width &&
+ prev->vb.height == buf->vb.height &&
+ prev->fmt == buf->fmt) {
+ list_del(&buf->vb.queue);
+ list_add_tail(&buf->vb.queue, &vidq->active);
+ buf->vb.state = VIDEOBUF_ACTIVE;
+ dprintk(2, "[%p/%d] restart_queue - move to active\n",
+ buf, buf->vb.i);
+ } else {
+ return 0;
+ }
+ prev = buf;
+ }
+}
+
+static void viu_vid_timeout(unsigned long data)
+{
+ struct viu_dev *dev = (struct viu_dev *)data;
+ struct viu_buf *buf;
+ struct viu_dmaqueue *vidq = &dev->vidq;
+
+ while (!list_empty(&vidq->active)) {
+ buf = list_entry(vidq->active.next, struct viu_buf, vb.queue);
+ list_del(&buf->vb.queue);
+ buf->vb.state = VIDEOBUF_ERROR;
+ wake_up(&buf->vb.done);
+ dprintk(1, "viu/0: [%p/%d] timeout\n", buf, buf->vb.i);
+ }
+
+ restart_video_queue(vidq);
+}
+
+/*
+ * Videobuf operations
+ */
+static int buffer_setup(struct videobuf_queue *vq, unsigned int *count,
+ unsigned int *size)
+{
+ struct viu_fh *fh = vq->priv_data;
+
+ *size = fh->width * fh->height * fh->fmt->depth >> 3;
+ if (*count == 0)
+ *count = 32;
+
+ while (*size * *count > VIU_VID_MEM_LIMIT * 1024 * 1024)
+ (*count)--;
+
+ dprintk(1, "%s, count=%d, size=%d\n", __func__, *count, *size);
+ return 0;
+}
+
+static void free_buffer(struct videobuf_queue *vq, struct viu_buf *buf)
+{
+ struct videobuf_buffer *vb = &buf->vb;
+ void *vaddr = NULL;
+
+ BUG_ON(in_interrupt());
+
+ videobuf_waiton(&buf->vb, 0, 0);
+
+ if (vq->int_ops && vq->int_ops->vaddr)
+ vaddr = vq->int_ops->vaddr(vb);
+
+ if (vaddr)
+ videobuf_dma_contig_free(vq, &buf->vb);
+
+ buf->vb.state = VIDEOBUF_NEEDS_INIT;
+}
+
+inline int buffer_activate(struct viu_dev *dev, struct viu_buf *buf)
+{
+ struct viu_reg *vr = dev->vr;
+ int bpp;
+
+ /* setup the DMA base address */
+ reg_val.field_base_addr = videobuf_to_dma_contig(&buf->vb);
+
+ dprintk(1, "buffer_activate [%p/%d]: dma addr 0x%lx\n",
+ buf, buf->vb.i, (unsigned long)reg_val.field_base_addr);
+
+ /* interlace is on by default, set horizontal DMA increment */
+ reg_val.status_cfg = 0;
+ bpp = buf->fmt->depth >> 3;
+ switch (bpp) {
+ case 2:
+ reg_val.status_cfg &= ~MODE_32BIT;
+ reg_val.dma_inc = buf->vb.width * 2;
+ break;
+ case 4:
+ reg_val.status_cfg |= MODE_32BIT;
+ reg_val.dma_inc = buf->vb.width * 4;
+ break;
+ default:
+ dprintk(0, "doesn't support color depth(%d)\n",
+ bpp * 8);
+ return -EINVAL;
+ }
+
+ /* setup picture_count register */
+ reg_val.picture_count = (buf->vb.height / 2) << 16 |
+ buf->vb.width;
+
+ reg_val.status_cfg |= DMA_ACT | INT_DMA_END_EN | INT_FIELD_EN;
+
+ buf->vb.state = VIDEOBUF_ACTIVE;
+ dev->capfield = buf->vb.field;
+
+ /* reset dma increment if needed */
+ if (!V4L2_FIELD_HAS_BOTH(buf->vb.field))
+ reg_val.dma_inc = 0;
+
+ out_be32(&vr->dma_inc, reg_val.dma_inc);
+ out_be32(&vr->picture_count, reg_val.picture_count);
+ out_be32(&vr->field_base_addr, reg_val.field_base_addr);
+ mod_timer(&dev->vidq.timeout, jiffies + BUFFER_TIMEOUT);
+ return 0;
+}
+
+static int buffer_prepare(struct videobuf_queue *vq,
+ struct videobuf_buffer *vb,
+ enum v4l2_field field)
+{
+ struct viu_fh *fh = vq->priv_data;
+ struct viu_buf *buf = container_of(vb, struct viu_buf, vb);
+ int rc;
+
+ BUG_ON(fh->fmt == NULL);
+
+ if (fh->width < 48 || fh->width > norm_maxw() ||
+ fh->height < 32 || fh->height > norm_maxh())
+ return -EINVAL;
+ buf->vb.size = (fh->width * fh->height * fh->fmt->depth) >> 3;
+ if (buf->vb.baddr != 0 && buf->vb.bsize < buf->vb.size)
+ return -EINVAL;
+
+ if (buf->fmt != fh->fmt ||
+ buf->vb.width != fh->width ||
+ buf->vb.height != fh->height ||
+ buf->vb.field != field) {
+ buf->fmt = fh->fmt;
+ buf->vb.width = fh->width;
+ buf->vb.height = fh->height;
+ buf->vb.field = field;
+ }
+
+ if (buf->vb.state == VIDEOBUF_NEEDS_INIT) {
+ rc = videobuf_iolock(vq, &buf->vb, NULL);
+ if (rc != 0)
+ goto fail;
+
+ buf->vb.width = fh->width;
+ buf->vb.height = fh->height;
+ buf->vb.field = field;
+ buf->fmt = fh->fmt;
+ }
+
+ buf->vb.state = VIDEOBUF_PREPARED;
+ return 0;
+
+fail:
+ free_buffer(vq, buf);
+ return rc;
+}
+
+static void buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
+{
+ struct viu_buf *buf = container_of(vb, struct viu_buf, vb);
+ struct viu_fh *fh = vq->priv_data;
+ struct viu_dev *dev = fh->dev;
+ struct viu_dmaqueue *vidq = &dev->vidq;
+ struct viu_buf *prev;
+
+ if (!list_empty(&vidq->queued)) {
+ dprintk(1, "adding vb queue=0x%08lx\n",
+ (unsigned long)&buf->vb.queue);
+ dprintk(1, "vidq pointer 0x%p, queued 0x%p\n",
+ vidq, &vidq->queued);
+ dprintk(1, "dev %p, queued: self %p, next %p, head %p\n",
+ dev, &vidq->queued, vidq->queued.next,
+ vidq->queued.prev);
+ list_add_tail(&buf->vb.queue, &vidq->queued);
+ buf->vb.state = VIDEOBUF_QUEUED;
+ dprintk(2, "[%p/%d] buffer_queue - append to queued\n",
+ buf, buf->vb.i);
+ } else if (list_empty(&vidq->active)) {
+ dprintk(1, "adding vb active=0x%08lx\n",
+ (unsigned long)&buf->vb.queue);
+ list_add_tail(&buf->vb.queue, &vidq->active);
+ buf->vb.state = VIDEOBUF_ACTIVE;
+ mod_timer(&vidq->timeout, jiffies+BUFFER_TIMEOUT);
+ dprintk(2, "[%p/%d] buffer_queue - first active\n",
+ buf, buf->vb.i);
+
+ buffer_activate(dev, buf);
+ } else {
+ dprintk(1, "adding vb queue2=0x%08lx\n",
+ (unsigned long)&buf->vb.queue);
+ prev = list_entry(vidq->active.prev, struct viu_buf, vb.queue);
+ if (prev->vb.width == buf->vb.width &&
+ prev->vb.height == buf->vb.height &&
+ prev->fmt == buf->fmt) {
+ list_add_tail(&buf->vb.queue, &vidq->active);
+ buf->vb.state = VIDEOBUF_ACTIVE;
+ dprintk(2, "[%p/%d] buffer_queue - append to active\n",
+ buf, buf->vb.i);
+ } else {
+ list_add_tail(&buf->vb.queue, &vidq->queued);
+ buf->vb.state = VIDEOBUF_QUEUED;
+ dprintk(2, "[%p/%d] buffer_queue - first queued\n",
+ buf, buf->vb.i);
+ }
+ }
+}
+
+static void buffer_release(struct videobuf_queue *vq,
+ struct videobuf_buffer *vb)
+{
+ struct viu_buf *buf = container_of(vb, struct viu_buf, vb);
+ struct viu_fh *fh = vq->priv_data;
+ struct viu_dev *dev = (struct viu_dev *)fh->dev;
+
+ viu_stop_dma(dev);
+ free_buffer(vq, buf);
+}
+
+static struct videobuf_queue_ops viu_video_qops = {
+ .buf_setup = buffer_setup,
+ .buf_prepare = buffer_prepare,
+ .buf_queue = buffer_queue,
+ .buf_release = buffer_release,
+};
+
+/*
+ * IOCTL vidioc handling
+ */
+static int vidioc_querycap(struct file *file, void *priv,
+ struct v4l2_capability *cap)
+{
+ strcpy(cap->driver, "viu");
+ strcpy(cap->card, "viu");
+ cap->version = VIU_VERSION;
+ cap->capabilities = V4L2_CAP_VIDEO_CAPTURE |
+ V4L2_CAP_STREAMING |
+ V4L2_CAP_VIDEO_OVERLAY |
+ V4L2_CAP_READWRITE;
+ return 0;
+}
+
+static int vidioc_enum_fmt(struct file *file, void *priv,
+ struct v4l2_fmtdesc *f)
+{
+ int index = f->index;
+
+ if (f->index > NUM_FORMATS)
+ return -EINVAL;
+
+ strlcpy(f->description, formats[index].name, sizeof(f->description));
+ f->pixelformat = formats[index].fourcc;
+ return 0;
+}
+
+static int vidioc_g_fmt_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct viu_fh *fh = priv;
+
+ f->fmt.pix.width = fh->width;
+ f->fmt.pix.height = fh->height;
+ f->fmt.pix.field = fh->vb_vidq.field;
+ f->fmt.pix.pixelformat = fh->fmt->pixelformat;
+ f->fmt.pix.bytesperline =
+ (f->fmt.pix.width * fh->fmt->depth) >> 3;
+ f->fmt.pix.sizeimage = fh->sizeimage;
+ return 0;
+}
+
+static int vidioc_try_fmt_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct viu_fmt *fmt;
+ enum v4l2_field field;
+ unsigned int maxw, maxh;
+
+ fmt = format_by_fourcc(f->fmt.pix.pixelformat);
+ if (!fmt) {
+ dprintk(1, "Fourcc format (0x%08x) invalid.",
+ f->fmt.pix.pixelformat);
+ return -EINVAL;
+ }
+
+ field = f->fmt.pix.field;
+
+ if (field == V4L2_FIELD_ANY) {
+ field = V4L2_FIELD_INTERLACED;
+ } else if (field != V4L2_FIELD_INTERLACED) {
+ dprintk(1, "Field type invalid.\n");
+ return -EINVAL;
+ }
+
+ maxw = norm_maxw();
+ maxh = norm_maxh();
+
+ f->fmt.pix.field = field;
+ if (f->fmt.pix.height < 32)
+ f->fmt.pix.height = 32;
+ if (f->fmt.pix.height > maxh)
+ f->fmt.pix.height = maxh;
+ if (f->fmt.pix.width < 48)
+ f->fmt.pix.width = 48;
+ if (f->fmt.pix.width > maxw)
+ f->fmt.pix.width = maxw;
+ f->fmt.pix.width &= ~0x03;
+ f->fmt.pix.bytesperline =
+ (f->fmt.pix.width * fmt->depth) >> 3;
+
+ return 0;
+}
+
+static int vidioc_s_fmt_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct viu_fh *fh = priv;
+ int ret;
+
+ ret = vidioc_try_fmt_cap(file, fh, f);
+ if (ret < 0)
+ return ret;
+
+ fh->fmt = format_by_fourcc(f->fmt.pix.pixelformat);
+ fh->width = f->fmt.pix.width;
+ fh->height = f->fmt.pix.height;
+ fh->sizeimage = f->fmt.pix.sizeimage;
+ fh->vb_vidq.field = f->fmt.pix.field;
+ fh->type = f->type;
+ dprintk(1, "set to pixelformat '%4.6s'\n", (char *)&fh->fmt->name);
+ return 0;
+}
+
+static int vidioc_g_fmt_overlay(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct viu_fh *fh = priv;
+
+ f->fmt.win = fh->win;
+ return 0;
+}
+
+static int verify_preview(struct viu_dev *dev, struct v4l2_window *win)
+{
+ enum v4l2_field field;
+ int maxw, maxh;
+
+ if (dev->ovbuf.base == NULL)
+ return -EINVAL;
+ if (dev->ovfmt == NULL)
+ return -EINVAL;
+ if (win->w.width < 48 || win->w.height < 32)
+ return -EINVAL;
+
+ field = win->field;
+ maxw = dev->crop_current.width;
+ maxh = dev->crop_current.height;
+
+ if (field == V4L2_FIELD_ANY) {
+ field = (win->w.height > maxh/2)
+ ? V4L2_FIELD_INTERLACED
+ : V4L2_FIELD_TOP;
+ }
+ switch (field) {
+ case V4L2_FIELD_TOP:
+ case V4L2_FIELD_BOTTOM:
+ maxh = maxh / 2;
+ break;
+ case V4L2_FIELD_INTERLACED:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ win->field = field;
+ if (win->w.width > maxw)
+ win->w.width = maxw;
+ if (win->w.height > maxh)
+ win->w.height = maxh;
+ return 0;
+}
+
+inline void viu_activate_overlay(struct viu_reg *viu_reg)
+{
+ struct viu_reg *vr = viu_reg;
+
+ out_be32(&vr->field_base_addr, reg_val.field_base_addr);
+ out_be32(&vr->dma_inc, reg_val.dma_inc);
+ out_be32(&vr->picture_count, reg_val.picture_count);
+}
+
+static int viu_start_preview(struct viu_dev *dev, struct viu_fh *fh)
+{
+ int bpp;
+
+ dprintk(1, "%s %dx%d %s\n", __func__,
+ fh->win.w.width, fh->win.w.height, dev->ovfmt->name);
+
+ reg_val.status_cfg = 0;
+
+ /* setup window */
+ reg_val.picture_count = (fh->win.w.height / 2) << 16 |
+ fh->win.w.width;
+
+ /* setup color depth and dma increment */
+ bpp = dev->ovfmt->depth / 8;
+ switch (bpp) {
+ case 2:
+ reg_val.status_cfg &= ~MODE_32BIT;
+ reg_val.dma_inc = fh->win.w.width * 2;
+ break;
+ case 4:
+ reg_val.status_cfg |= MODE_32BIT;
+ reg_val.dma_inc = fh->win.w.width * 4;
+ break;
+ default:
+ dprintk(0, "device doesn't support color depth(%d)\n",
+ bpp * 8);
+ return -EINVAL;
+ }
+
+ dev->ovfield = fh->win.field;
+ if (!V4L2_FIELD_HAS_BOTH(dev->ovfield))
+ reg_val.dma_inc = 0;
+
+ reg_val.status_cfg |= DMA_ACT | INT_DMA_END_EN | INT_FIELD_EN;
+
+ /* setup the base address of the overlay buffer */
+ reg_val.field_base_addr = (u32)dev->ovbuf.base;
+
+ dev->ovenable = 1;
+ viu_activate_overlay(dev->vr);
+
+ /* start dma */
+ viu_start_dma(dev);
+ return 0;
+}
+
+static int vidioc_s_fmt_overlay(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct viu_fh *fh = priv;
+ struct viu_dev *dev = (struct viu_dev *)fh->dev;
+ unsigned long flags;
+ int err;
+
+ err = verify_preview(dev, &f->fmt.win);
+ if (err)
+ return err;
+
+ mutex_lock(&dev->lock);
+ fh->win = f->fmt.win;
+
+ spin_lock_irqsave(&dev->slock, flags);
+ viu_start_preview(dev, fh);
+ spin_unlock_irqrestore(&dev->slock, flags);
+ mutex_unlock(&dev->lock);
+ return 0;
+}
+
+static int vidioc_try_fmt_overlay(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ return 0;
+}
+
+int vidioc_g_fbuf(struct file *file, void *priv, struct v4l2_framebuffer *arg)
+{
+ struct viu_fh *fh = priv;
+ struct viu_dev *dev = fh->dev;
+ struct v4l2_framebuffer *fb = arg;
+
+ *fb = dev->ovbuf;
+ fb->capability = V4L2_FBUF_CAP_LIST_CLIPPING;
+ return 0;
+}
+
+int vidioc_s_fbuf(struct file *file, void *priv, struct v4l2_framebuffer *arg)
+{
+ struct viu_fh *fh = priv;
+ struct viu_dev *dev = fh->dev;
+ struct v4l2_framebuffer *fb = arg;
+ struct viu_fmt *fmt;
+
+ if (!capable(CAP_SYS_ADMIN) && !capable(CAP_SYS_RAWIO))
+ return -EPERM;
+
+ /* check args */
+ fmt = format_by_fourcc(fb->fmt.pixelformat);
+ if (fmt == NULL)
+ return -EINVAL;
+
+ /* ok, accept it */
+ dev->ovbuf = *fb;
+ dev->ovfmt = fmt;
+ if (dev->ovbuf.fmt.bytesperline == 0) {
+ dev->ovbuf.fmt.bytesperline =
+ dev->ovbuf.fmt.width * fmt->depth / 8;
+ }
+ return 0;
+}
+
+static int vidioc_reqbufs(struct file *file, void *priv,
+ struct v4l2_requestbuffers *p)
+{
+ struct viu_fh *fh = priv;
+
+ return videobuf_reqbufs(&fh->vb_vidq, p);
+}
+
+static int vidioc_querybuf(struct file *file, void *priv,
+ struct v4l2_buffer *p)
+{
+ struct viu_fh *fh = priv;
+
+ return videobuf_querybuf(&fh->vb_vidq, p);
+}
+
+static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *p)
+{
+ struct viu_fh *fh = priv;
+
+ return videobuf_qbuf(&fh->vb_vidq, p);
+}
+
+static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p)
+{
+ struct viu_fh *fh = priv;
+
+ return videobuf_dqbuf(&fh->vb_vidq, p,
+ file->f_flags & O_NONBLOCK);
+}
+
+static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
+{
+ struct viu_fh *fh = priv;
+
+ if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+ if (fh->type != i)
+ return -EINVAL;
+
+ return videobuf_streamon(&fh->vb_vidq);
+}
+
+static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
+{
+ struct viu_fh *fh = priv;
+
+ if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+ if (fh->type != i)
+ return -EINVAL;
+
+ return videobuf_streamoff(&fh->vb_vidq);
+}
+
+#define decoder_call(viu, o, f, args...) \
+ v4l2_subdev_call(viu->decoder, o, f, ##args)
+
+static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *id)
+{
+ struct viu_fh *fh = priv;
+
+ decoder_call(fh->dev, core, s_std, *id);
+ return 0;
+}
+
+/* only one input in this driver */
+static int vidioc_enum_input(struct file *file, void *priv,
+ struct v4l2_input *inp)
+{
+ struct viu_fh *fh = priv;
+
+ if (inp->index != 0)
+ return -EINVAL;
+
+ inp->type = V4L2_INPUT_TYPE_CAMERA;
+ inp->std = fh->dev->vdev->tvnorms;
+ strcpy(inp->name, "Camera");
+ return 0;
+}
+
+static int vidioc_g_input(struct file *file, void *priv, unsigned int *i)
+{
+ *i = 0;
+ return 0;
+}
+
+static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
+{
+ struct viu_fh *fh = priv;
+
+ if (i > 1)
+ return -EINVAL;
+
+ decoder_call(fh->dev, video, s_routing, i, 0, 0);
+ return 0;
+}
+
+/* Controls */
+static int vidioc_queryctrl(struct file *file, void *priv,
+ struct v4l2_queryctrl *qc)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(viu_qctrl); i++) {
+ if (qc->id && qc->id == viu_qctrl[i].id) {
+ memcpy(qc, &(viu_qctrl[i]), sizeof(*qc));
+ return 0;
+ }
+ }
+ return -EINVAL;
+}
+
+static int vidioc_g_ctrl(struct file *file, void *priv,
+ struct v4l2_control *ctrl)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(viu_qctrl); i++) {
+ if (ctrl->id == viu_qctrl[i].id) {
+ ctrl->value = qctl_regs[i];
+ return 0;
+ }
+ }
+ return -EINVAL;
+}
+static int vidioc_s_ctrl(struct file *file, void *priv,
+ struct v4l2_control *ctrl)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(viu_qctrl); i++) {
+ if (ctrl->id == viu_qctrl[i].id) {
+ if (ctrl->value < viu_qctrl[i].minimum
+ || ctrl->value > viu_qctrl[i].maximum)
+ return -ERANGE;
+ qctl_regs[i] = ctrl->value;
+ return 0;
+ }
+ }
+ return -EINVAL;
+}
+
+inline void viu_activate_next_buf(struct viu_dev *dev,
+ struct viu_dmaqueue *viuq)
+{
+ struct viu_dmaqueue *vidq = viuq;
+ struct viu_buf *buf;
+
+ /* launch another DMA operation for an active/queued buffer */
+ if (!list_empty(&vidq->active)) {
+ buf = list_entry(vidq->active.next, struct viu_buf,
+ vb.queue);
+ dprintk(1, "start another queued buffer: 0x%p\n", buf);
+ buffer_activate(dev, buf);
+ } else if (!list_empty(&vidq->queued)) {
+ buf = list_entry(vidq->queued.next, struct viu_buf,
+ vb.queue);
+ list_del(&buf->vb.queue);
+
+ dprintk(1, "start another queued buffer: 0x%p\n", buf);
+ list_add_tail(&buf->vb.queue, &vidq->active);
+ buf->vb.state = VIDEOBUF_ACTIVE;
+ buffer_activate(dev, buf);
+ }
+}
+
+inline void viu_default_settings(struct viu_reg *viu_reg)
+{
+ struct viu_reg *vr = viu_reg;
+
+ out_be32(&vr->luminance, 0x9512A254);
+ out_be32(&vr->chroma_r, 0x03310000);
+ out_be32(&vr->chroma_g, 0x06600F38);
+ out_be32(&vr->chroma_b, 0x00000409);
+ out_be32(&vr->alpha, 0x000000ff);
+ out_be32(&vr->req_alarm, 0x00000090);
+ dprintk(1, "status reg: 0x%08x, field base: 0x%08x\n",
+ in_be32(&vr->status_cfg), in_be32(&vr->field_base_addr));
+}
+
+static void viu_overlay_intr(struct viu_dev *dev, u32 status)
+{
+ struct viu_reg *vr = dev->vr;
+
+ if (status & INT_DMA_END_STATUS)
+ dev->dma_done = 1;
+
+ if (status & INT_FIELD_STATUS) {
+ if (dev->dma_done) {
+ u32 addr = reg_val.field_base_addr;
+
+ dev->dma_done = 0;
+ if (status & FIELD_NO)
+ addr += reg_val.dma_inc;
+
+ out_be32(&vr->field_base_addr, addr);
+ out_be32(&vr->dma_inc, reg_val.dma_inc);
+ out_be32(&vr->status_cfg,
+ (status & 0xffc0ffff) |
+ (status & INT_ALL_STATUS) |
+ reg_val.status_cfg);
+ } else if (status & INT_VSYNC_STATUS) {
+ out_be32(&vr->status_cfg,
+ (status & 0xffc0ffff) |
+ (status & INT_ALL_STATUS) |
+ reg_val.status_cfg);
+ }
+ }
+}
+
+static void viu_capture_intr(struct viu_dev *dev, u32 status)
+{
+ struct viu_dmaqueue *vidq = &dev->vidq;
+ struct viu_reg *vr = dev->vr;
+ struct viu_buf *buf;
+ int field_num;
+ int need_two;
+ int dma_done = 0;
+
+ field_num = status & FIELD_NO;
+ need_two = V4L2_FIELD_HAS_BOTH(dev->capfield);
+
+ if (status & INT_DMA_END_STATUS) {
+ dma_done = 1;
+ if (((field_num == 0) && (dev->field == 0)) ||
+ (field_num && (dev->field == 1)))
+ dev->field++;
+ }
+
+ if (status & INT_FIELD_STATUS) {
+ dprintk(1, "irq: field %d, done %d\n",
+ !!field_num, dma_done);
+ if (unlikely(dev->first)) {
+ if (field_num == 0) {
+ dev->first = 0;
+ dprintk(1, "activate first buf\n");
+ viu_activate_next_buf(dev, vidq);
+ } else
+ dprintk(1, "wait field 0\n");
+ return;
+ }
+
+ /* setup buffer address for next dma operation */
+ if (!list_empty(&vidq->active)) {
+ u32 addr = reg_val.field_base_addr;
+
+ if (field_num && need_two) {
+ addr += reg_val.dma_inc;
+ dprintk(1, "field 1, 0x%lx, dev field %d\n",
+ (unsigned long)addr, dev->field);
+ }
+ out_be32(&vr->field_base_addr, addr);
+ out_be32(&vr->dma_inc, reg_val.dma_inc);
+ out_be32(&vr->status_cfg,
+ (status & 0xffc0ffff) |
+ (status & INT_ALL_STATUS) |
+ reg_val.status_cfg);
+ return;
+ }
+ }
+
+ if (dma_done && field_num && (dev->field == 2)) {
+ dev->field = 0;
+ buf = list_entry(vidq->active.next,
+ struct viu_buf, vb.queue);
+ dprintk(1, "viu/0: [%p/%d] 0x%lx/0x%lx: dma complete\n",
+ buf, buf->vb.i,
+ (unsigned long)videobuf_to_dma_contig(&buf->vb),
+ (unsigned long)in_be32(&vr->field_base_addr));
+
+ if (waitqueue_active(&buf->vb.done)) {
+ list_del(&buf->vb.queue);
+ do_gettimeofday(&buf->vb.ts);
+ buf->vb.state = VIDEOBUF_DONE;
+ buf->vb.field_count++;
+ wake_up(&buf->vb.done);
+ }
+ /* activate next dma buffer */
+ viu_activate_next_buf(dev, vidq);
+ }
+}
+
+static irqreturn_t viu_intr(int irq, void *dev_id)
+{
+ struct viu_dev *dev = (struct viu_dev *)dev_id;
+ struct viu_reg *vr = dev->vr;
+ u32 status;
+ u32 error;
+
+ status = in_be32(&vr->status_cfg);
+
+ if (status & INT_ERROR_STATUS) {
+ dev->irqs.error_irq++;
+ error = status & ERR_MASK;
+ if (error)
+ dprintk(1, "Err: error(%d), times:%d!\n",
+ error >> 4, dev->irqs.error_irq);
+ /* Clear interrupt error bit and error flags */
+ out_be32(&vr->status_cfg,
+ (status & 0xffc0ffff) | INT_ERROR_STATUS);
+ }
+
+ if (status & INT_DMA_END_STATUS) {
+ dev->irqs.dma_end_irq++;
+ dev->dma_done = 1;
+ dprintk(2, "VIU DMA end interrupt times: %d\n",
+ dev->irqs.dma_end_irq);
+ }
+
+ if (status & INT_HSYNC_STATUS)
+ dev->irqs.hsync_irq++;
+
+ if (status & INT_FIELD_STATUS) {
+ dev->irqs.field_irq++;
+ dprintk(2, "VIU field interrupt times: %d\n",
+ dev->irqs.field_irq);
+ }
+
+ if (status & INT_VSTART_STATUS)
+ dev->irqs.vstart_irq++;
+
+ if (status & INT_VSYNC_STATUS) {
+ dev->irqs.vsync_irq++;
+ dprintk(2, "VIU vsync interrupt times: %d\n",
+ dev->irqs.vsync_irq);
+ }
+
+ /* clear all pending irqs */
+ status = in_be32(&vr->status_cfg);
+ out_be32(&vr->status_cfg,
+ (status & 0xffc0ffff) | (status & INT_ALL_STATUS));
+
+ if (dev->ovenable) {
+ viu_overlay_intr(dev, status);
+ return IRQ_HANDLED;
+ }
+
+ /* Capture mode */
+ viu_capture_intr(dev, status);
+ return IRQ_HANDLED;
+}
+
+/*
+ * File operations for the device
+ */
+static int viu_open(struct file *file)
+{
+ struct video_device *vdev = video_devdata(file);
+ struct viu_dev *dev = video_get_drvdata(vdev);
+ struct viu_fh *fh;
+ struct viu_reg *vr;
+ int minor = vdev->minor;
+ u32 status_cfg;
+ int i;
+
+ dprintk(1, "viu: open (minor=%d)\n", minor);
+
+ dev->users++;
+ if (dev->users > 1) {
+ dev->users--;
+ return -EBUSY;
+ }
+
+ vr = dev->vr;
+
+ dprintk(1, "open minor=%d type=%s users=%d\n", minor,
+ v4l2_type_names[V4L2_BUF_TYPE_VIDEO_CAPTURE], dev->users);
+
+ /* allocate and initialize per filehandle data */
+ fh = kzalloc(sizeof(*fh), GFP_KERNEL);
+ if (!fh) {
+ dev->users--;
+ return -ENOMEM;
+ }
+
+ file->private_data = fh;
+ fh->dev = dev;
+
+ fh->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ fh->fmt = format_by_fourcc(V4L2_PIX_FMT_RGB32);
+ fh->width = norm_maxw();
+ fh->height = norm_maxh();
+ dev->crop_current.width = fh->width;
+ dev->crop_current.height = fh->height;
+
+ /* Put all controls at a sane state */
+ for (i = 0; i < ARRAY_SIZE(viu_qctrl); i++)
+ qctl_regs[i] = viu_qctrl[i].default_value;
+
+ dprintk(1, "Open: fh=0x%08lx, dev=0x%08lx, dev->vidq=0x%08lx\n",
+ (unsigned long)fh, (unsigned long)dev,
+ (unsigned long)&dev->vidq);
+ dprintk(1, "Open: list_empty queued=%d\n",
+ list_empty(&dev->vidq.queued));
+ dprintk(1, "Open: list_empty active=%d\n",
+ list_empty(&dev->vidq.active));
+
+ viu_default_settings(vr);
+
+ status_cfg = in_be32(&vr->status_cfg);
+ out_be32(&vr->status_cfg,
+ status_cfg & ~(INT_VSYNC_EN | INT_HSYNC_EN |
+ INT_FIELD_EN | INT_VSTART_EN |
+ INT_DMA_END_EN | INT_ERROR_EN | INT_ECC_EN));
+
+ status_cfg = in_be32(&vr->status_cfg);
+ out_be32(&vr->status_cfg, status_cfg | INT_ALL_STATUS);
+
+ spin_lock_init(&fh->vbq_lock);
+ videobuf_queue_dma_contig_init(&fh->vb_vidq, &viu_video_qops,
+ dev->dev, &fh->vbq_lock,
+ fh->type, V4L2_FIELD_INTERLACED,
+ sizeof(struct viu_buf), fh);
+ return 0;
+}
+
+static ssize_t viu_read(struct file *file, char __user *data, size_t count,
+ loff_t *ppos)
+{
+ struct viu_fh *fh = file->private_data;
+ struct viu_dev *dev = fh->dev;
+ int ret = 0;
+
+ dprintk(2, "%s\n", __func__);
+ if (dev->ovenable)
+ dev->ovenable = 0;
+
+ if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+ viu_start_dma(dev);
+ ret = videobuf_read_stream(&fh->vb_vidq, data, count,
+ ppos, 0, file->f_flags & O_NONBLOCK);
+ return ret;
+ }
+ return 0;
+}
+
+static unsigned int viu_poll(struct file *file, struct poll_table_struct *wait)
+{
+ struct viu_fh *fh = file->private_data;
+ struct videobuf_queue *q = &fh->vb_vidq;
+
+ if (V4L2_BUF_TYPE_VIDEO_CAPTURE != fh->type)
+ return POLLERR;
+
+ return videobuf_poll_stream(file, q, wait);
+}
+
+static int viu_release(struct file *file)
+{
+ struct viu_fh *fh = file->private_data;
+ struct viu_dev *dev = fh->dev;
+ int minor = video_devdata(file)->minor;
+
+ viu_stop_dma(dev);
+ videobuf_stop(&fh->vb_vidq);
+
+ kfree(fh);
+
+ dev->users--;
+ dprintk(1, "close (minor=%d, users=%d)\n",
+ minor, dev->users);
+ return 0;
+}
+
+void viu_reset(struct viu_reg *reg)
+{
+ out_be32(&reg->status_cfg, 0);
+ out_be32(&reg->luminance, 0x9512a254);
+ out_be32(&reg->chroma_r, 0x03310000);
+ out_be32(&reg->chroma_g, 0x06600f38);
+ out_be32(&reg->chroma_b, 0x00000409);
+ out_be32(&reg->field_base_addr, 0);
+ out_be32(&reg->dma_inc, 0);
+ out_be32(&reg->picture_count, 0x01e002d0);
+ out_be32(&reg->req_alarm, 0x00000090);
+ out_be32(&reg->alpha, 0x000000ff);
+}
+
+static int viu_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ struct viu_fh *fh = file->private_data;
+ int ret;
+
+ dprintk(1, "mmap called, vma=0x%08lx\n", (unsigned long)vma);
+
+ ret = videobuf_mmap_mapper(&fh->vb_vidq, vma);
+
+ dprintk(1, "vma start=0x%08lx, size=%ld, ret=%d\n",
+ (unsigned long)vma->vm_start,
+ (unsigned long)vma->vm_end-(unsigned long)vma->vm_start,
+ ret);
+
+ return ret;
+}
+
+static struct v4l2_file_operations viu_fops = {
+ .owner = THIS_MODULE,
+ .open = viu_open,
+ .release = viu_release,
+ .read = viu_read,
+ .poll = viu_poll,
+ .ioctl = video_ioctl2, /* V4L2 ioctl handler */
+ .mmap = viu_mmap,
+};
+
+static const struct v4l2_ioctl_ops viu_ioctl_ops = {
+ .vidioc_querycap = vidioc_querycap,
+ .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt,
+ .vidioc_g_fmt_vid_cap = vidioc_g_fmt_cap,
+ .vidioc_try_fmt_vid_cap = vidioc_try_fmt_cap,
+ .vidioc_s_fmt_vid_cap = vidioc_s_fmt_cap,
+ .vidioc_enum_fmt_vid_overlay = vidioc_enum_fmt,
+ .vidioc_g_fmt_vid_overlay = vidioc_g_fmt_overlay,
+ .vidioc_try_fmt_vid_overlay = vidioc_try_fmt_overlay,
+ .vidioc_s_fmt_vid_overlay = vidioc_s_fmt_overlay,
+ .vidioc_g_fbuf = vidioc_g_fbuf,
+ .vidioc_s_fbuf = vidioc_s_fbuf,
+ .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_ctrl = vidioc_g_ctrl,
+ .vidioc_s_ctrl = vidioc_s_ctrl,
+ .vidioc_streamon = vidioc_streamon,
+ .vidioc_streamoff = vidioc_streamoff,
+};
+
+static struct video_device viu_template = {
+ .name = "FSL viu",
+ .fops = &viu_fops,
+ .minor = -1,
+ .ioctl_ops = &viu_ioctl_ops,
+ .release = video_device_release,
+
+ .tvnorms = V4L2_STD_NTSC_M | V4L2_STD_PAL,
+ .current_norm = V4L2_STD_NTSC_M,
+};
+
+static int __devinit viu_of_probe(struct of_device *op,
+ const struct of_device_id *match)
+{
+ struct viu_dev *viu_dev;
+ struct video_device *vdev;
+ struct resource r;
+ struct viu_reg __iomem *viu_regs;
+ struct i2c_adapter *ad;
+ int ret, viu_irq;
+
+ ret = of_address_to_resource(op->dev.of_node, 0, &r);
+ if (ret) {
+ dev_err(&op->dev, "Can't parse device node resource\n");
+ return -ENODEV;
+ }
+
+ viu_irq = irq_of_parse_and_map(op->dev.of_node, 0);
+ if (viu_irq == NO_IRQ) {
+ dev_err(&op->dev, "Error while mapping the irq\n");
+ return -EINVAL;
+ }
+
+ /* request mem region */
+ if (!devm_request_mem_region(&op->dev, r.start,
+ sizeof(struct viu_reg), DRV_NAME)) {
+ dev_err(&op->dev, "Error while requesting mem region\n");
+ ret = -EBUSY;
+ goto err;
+ }
+
+ /* remap registers */
+ viu_regs = devm_ioremap(&op->dev, r.start, sizeof(struct viu_reg));
+ if (!viu_regs) {
+ dev_err(&op->dev, "Can't map register set\n");
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ /* Prepare our private structure */
+ viu_dev = devm_kzalloc(&op->dev, sizeof(struct viu_dev), GFP_ATOMIC);
+ if (!viu_dev) {
+ dev_err(&op->dev, "Can't allocate private structure\n");
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ viu_dev->vr = viu_regs;
+ viu_dev->irq = viu_irq;
+ viu_dev->dev = &op->dev;
+
+ /* init video dma queues */
+ INIT_LIST_HEAD(&viu_dev->vidq.active);
+ INIT_LIST_HEAD(&viu_dev->vidq.queued);
+
+ /* initialize locks */
+ mutex_init(&viu_dev->lock);
+
+ snprintf(viu_dev->v4l2_dev.name,
+ sizeof(viu_dev->v4l2_dev.name), "%s", "VIU");
+ ret = v4l2_device_register(viu_dev->dev, &viu_dev->v4l2_dev);
+ if (ret < 0) {
+ dev_err(&op->dev, "v4l2_device_register() failed: %d\n", ret);
+ goto err;
+ }
+
+ ad = i2c_get_adapter(0);
+ viu_dev->decoder = v4l2_i2c_new_subdev(&viu_dev->v4l2_dev, ad,
+ "saa7115", "saa7113", VIU_VIDEO_DECODER_ADDR, NULL);
+
+ viu_dev->vidq.timeout.function = viu_vid_timeout;
+ viu_dev->vidq.timeout.data = (unsigned long)viu_dev;
+ init_timer(&viu_dev->vidq.timeout);
+ viu_dev->first = 1;
+
+ /* Allocate memory for video device */
+ vdev = video_device_alloc();
+ if (vdev == NULL) {
+ ret = -ENOMEM;
+ goto err_vdev;
+ }
+
+ memcpy(vdev, &viu_template, sizeof(viu_template));
+
+ vdev->v4l2_dev = &viu_dev->v4l2_dev;
+
+ viu_dev->vdev = vdev;
+
+ video_set_drvdata(viu_dev->vdev, viu_dev);
+
+ ret = video_register_device(viu_dev->vdev, VFL_TYPE_GRABBER, -1);
+ if (ret < 0) {
+ video_device_release(viu_dev->vdev);
+ goto err_vdev;
+ }
+
+ /* enable VIU clock */
+ viu_dev->clk = clk_get(&op->dev, "viu_clk");
+ if (IS_ERR(viu_dev->clk)) {
+ dev_err(&op->dev, "failed to find the clock module!\n");
+ ret = -ENODEV;
+ goto err_clk;
+ } else {
+ clk_enable(viu_dev->clk);
+ }
+
+ /* reset VIU module */
+ viu_reset(viu_dev->vr);
+
+ /* install interrupt handler */
+ if (request_irq(viu_dev->irq, viu_intr, 0, "viu", (void *)viu_dev)) {
+ dev_err(&op->dev, "Request VIU IRQ failed.\n");
+ ret = -ENODEV;
+ goto err_irq;
+ }
+
+ dev_info(&op->dev, "Freescale VIU Video Capture Board\n");
+ return ret;
+
+err_irq:
+ clk_disable(viu_dev->clk);
+ clk_put(viu_dev->clk);
+err_clk:
+ video_unregister_device(viu_dev->vdev);
+err_vdev:
+ i2c_put_adapter(ad);
+ v4l2_device_unregister(&viu_dev->v4l2_dev);
+err:
+ irq_dispose_mapping(viu_irq);
+ return ret;
+}
+
+static int __devexit viu_of_remove(struct of_device *op)
+{
+ struct v4l2_device *v4l2_dev = dev_get_drvdata(&op->dev);
+ struct viu_dev *dev = container_of(v4l2_dev, struct viu_dev, v4l2_dev);
+ struct v4l2_subdev *sdev = list_entry(v4l2_dev->subdevs.next,
+ struct v4l2_subdev, list);
+ struct i2c_client *client = v4l2_get_subdevdata(sdev);
+
+ free_irq(dev->irq, (void *)dev);
+ irq_dispose_mapping(dev->irq);
+
+ clk_disable(dev->clk);
+ clk_put(dev->clk);
+
+ video_unregister_device(dev->vdev);
+ i2c_put_adapter(client->adapter);
+ v4l2_device_unregister(&dev->v4l2_dev);
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int viu_suspend(struct of_device *op, pm_message_t state)
+{
+ struct v4l2_device *v4l2_dev = dev_get_drvdata(&op->dev);
+ struct viu_dev *dev = container_of(v4l2_dev, struct viu_dev, v4l2_dev);
+
+ clk_disable(dev->clk);
+ return 0;
+}
+
+static int viu_resume(struct of_device *op)
+{
+ struct v4l2_device *v4l2_dev = dev_get_drvdata(&op->dev);
+ struct viu_dev *dev = container_of(v4l2_dev, struct viu_dev, v4l2_dev);
+
+ clk_enable(dev->clk);
+ return 0;
+}
+#endif
+
+/*
+ * Initialization and module stuff
+ */
+static struct of_device_id mpc512x_viu_of_match[] = {
+ {
+ .compatible = "fsl,mpc5121-viu",
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(of, mpc512x_viu_of_match);
+
+static struct of_platform_driver viu_of_platform_driver = {
+ .probe = viu_of_probe,
+ .remove = __devexit_p(viu_of_remove),
+#ifdef CONFIG_PM
+ .suspend = viu_suspend,
+ .resume = viu_resume,
+#endif
+ .driver = {
+ .name = DRV_NAME,
+ .owner = THIS_MODULE,
+ .of_match_table = mpc512x_viu_of_match,
+ },
+};
+
+static int __init viu_init(void)
+{
+ return of_register_platform_driver(&viu_of_platform_driver);
+}
+
+static void __exit viu_exit(void)
+{
+ of_unregister_platform_driver(&viu_of_platform_driver);
+}
+
+module_init(viu_init);
+module_exit(viu_exit);
+
+MODULE_DESCRIPTION("Freescale Video-In(VIU)");
+MODULE_AUTHOR("Hongjun Chen");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/video/gspca/Kconfig b/drivers/media/video/gspca/Kconfig
index 5d920e584de..23db0c29f68 100644
--- a/drivers/media/video/gspca/Kconfig
+++ b/drivers/media/video/gspca/Kconfig
@@ -246,6 +246,15 @@ config USB_GSPCA_SPCA561
To compile this driver as a module, choose M here: the
module will be called gspca_spca561.
+config USB_GSPCA_SPCA1528
+ tristate "SPCA1528 USB Camera Driver"
+ depends on VIDEO_V4L2 && USB_GSPCA
+ help
+ Say Y here if you want support for cameras based on the SPCA1528 chip.
+
+ To compile this driver as a module, choose M here: the
+ module will be called gspca_spca1528.
+
config USB_GSPCA_SQ905
tristate "SQ Technologies SQ905 based USB Camera Driver"
depends on VIDEO_V4L2 && USB_GSPCA
@@ -264,6 +273,15 @@ config USB_GSPCA_SQ905C
To compile this driver as a module, choose M here: the
module will be called gspca_sq905c.
+config USB_GSPCA_SQ930X
+ tristate "SQ Technologies SQ930X based USB Camera Driver"
+ depends on VIDEO_V4L2 && USB_GSPCA
+ help
+ Say Y here if you want support for cameras based on the SQ930X chip.
+
+ To compile this driver as a module, choose M here: the
+ module will be called gspca_sq930x.
+
config USB_GSPCA_STK014
tristate "Syntek DV4000 (STK014) USB Camera Driver"
depends on VIDEO_V4L2 && USB_GSPCA
diff --git a/drivers/media/video/gspca/Makefile b/drivers/media/video/gspca/Makefile
index 6e4cf1ce01c..f6616db0b7f 100644
--- a/drivers/media/video/gspca/Makefile
+++ b/drivers/media/video/gspca/Makefile
@@ -23,8 +23,10 @@ obj-$(CONFIG_USB_GSPCA_SPCA505) += gspca_spca505.o
obj-$(CONFIG_USB_GSPCA_SPCA506) += gspca_spca506.o
obj-$(CONFIG_USB_GSPCA_SPCA508) += gspca_spca508.o
obj-$(CONFIG_USB_GSPCA_SPCA561) += gspca_spca561.o
+obj-$(CONFIG_USB_GSPCA_SPCA1528) += gspca_spca1528.o
obj-$(CONFIG_USB_GSPCA_SQ905) += gspca_sq905.o
obj-$(CONFIG_USB_GSPCA_SQ905C) += gspca_sq905c.o
+obj-$(CONFIG_USB_GSPCA_SQ930X) += gspca_sq930x.o
obj-$(CONFIG_USB_GSPCA_SUNPLUS) += gspca_sunplus.o
obj-$(CONFIG_USB_GSPCA_STK014) += gspca_stk014.o
obj-$(CONFIG_USB_GSPCA_STV0680) += gspca_stv0680.o
@@ -58,8 +60,10 @@ gspca_spca505-objs := spca505.o
gspca_spca506-objs := spca506.o
gspca_spca508-objs := spca508.o
gspca_spca561-objs := spca561.o
+gspca_spca1528-objs := spca1528.o
gspca_sq905-objs := sq905.o
gspca_sq905c-objs := sq905c.o
+gspca_sq930x-objs := sq930x.o
gspca_stk014-objs := stk014.o
gspca_stv0680-objs := stv0680.o
gspca_sunplus-objs := sunplus.o
diff --git a/drivers/media/video/gspca/conex.c b/drivers/media/video/gspca/conex.c
index 19fe6b24c9a..d6a75772f3f 100644
--- a/drivers/media/video/gspca/conex.c
+++ b/drivers/media/video/gspca/conex.c
@@ -41,7 +41,7 @@ struct sd {
#define QUALITY_MAX 60
#define QUALITY_DEF 40
- u8 *jpeg_hdr;
+ u8 jpeg_hdr[JPEG_HDR_SZ];
};
/* V4L2 controls supported by the driver */
@@ -845,9 +845,6 @@ static int sd_start(struct gspca_dev *gspca_dev)
struct sd *sd = (struct sd *) gspca_dev;
/* create the JPEG header */
- sd->jpeg_hdr = kmalloc(JPEG_HDR_SZ, GFP_KERNEL);
- if (!sd->jpeg_hdr)
- return -ENOMEM;
jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width,
0x22); /* JPEG 411 */
jpeg_set_qual(sd->jpeg_hdr, sd->quality);
@@ -862,11 +859,8 @@ static int sd_start(struct gspca_dev *gspca_dev)
/* called on streamoff with alt 0 and on disconnect */
static void sd_stop0(struct gspca_dev *gspca_dev)
{
- struct sd *sd = (struct sd *) gspca_dev;
int retry = 50;
- kfree(sd->jpeg_hdr);
-
if (!gspca_dev->present)
return;
reg_w_val(gspca_dev, 0x0000, 0x00);
diff --git a/drivers/media/video/gspca/cpia1.c b/drivers/media/video/gspca/cpia1.c
index 58b696f455b..3747a1dcff5 100644
--- a/drivers/media/video/gspca/cpia1.c
+++ b/drivers/media/video/gspca/cpia1.c
@@ -1760,22 +1760,19 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
data[25] == sd->params.roi.colEnd &&
data[26] == sd->params.roi.rowStart &&
data[27] == sd->params.roi.rowEnd) {
- struct gspca_frame *frame = gspca_get_i_frame(gspca_dev);
+ u8 *image;
atomic_set(&sd->cam_exposure, data[39] * 2);
atomic_set(&sd->fps, data[41]);
- if (frame == NULL) {
- gspca_dev->last_packet_type = DISCARD_PACKET;
- return;
- }
-
/* Check for proper EOF for last frame */
- if ((frame->data_end - frame->data) > 4 &&
- frame->data_end[-4] == 0xff &&
- frame->data_end[-3] == 0xff &&
- frame->data_end[-2] == 0xff &&
- frame->data_end[-1] == 0xff)
+ image = gspca_dev->image;
+ if (image != NULL &&
+ gspca_dev->image_len > 4 &&
+ image[gspca_dev->image_len - 4] == 0xff &&
+ image[gspca_dev->image_len - 3] == 0xff &&
+ image[gspca_dev->image_len - 2] == 0xff &&
+ image[gspca_dev->image_len - 1] == 0xff)
gspca_frame_add(gspca_dev, LAST_PACKET,
NULL, 0);
diff --git a/drivers/media/video/gspca/gl860/gl860-mi2020.c b/drivers/media/video/gspca/gl860/gl860-mi2020.c
index 7c31b4f2abe..57782e011c9 100644
--- a/drivers/media/video/gspca/gl860/gl860-mi2020.c
+++ b/drivers/media/video/gspca/gl860/gl860-mi2020.c
@@ -1,6 +1,7 @@
/* Subdriver for the GL860 chip with the MI2020 sensor
- * Author Olivier LORIN, from Ice/Soro2005's logs(A), Fret_saw/Hulkie's
- * logs(B) and Tricid"s logs(C). With the help of Kytrix/BUGabundo/Blazercist.
+ * Author Olivier LORIN, from logs by Iceman/Soro2005 + Fret_saw/Hulkie/Tricid
+ * with the help of Kytrix/BUGabundo/Blazercist.
+ * Driver achieved thanks to a webcam gift by Kytrix.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -20,47 +21,70 @@
#include "gl860.h"
+static u8 dat_wbal1[] = {0x8c, 0xa2, 0x0c};
+
static u8 dat_bright1[] = {0x8c, 0xa2, 0x06};
static u8 dat_bright3[] = {0x8c, 0xa1, 0x02};
static u8 dat_bright4[] = {0x90, 0x00, 0x0f};
static u8 dat_bright5[] = {0x8c, 0xa1, 0x03};
static u8 dat_bright6[] = {0x90, 0x00, 0x05};
-static u8 dat_dummy1[] = {0x90, 0x00, 0x06};
-/*static u8 dummy2[] = {0x8c, 0xa1, 0x02};*/
-/*static u8 dummy3[] = {0x90, 0x00, 0x1f};*/
-
static u8 dat_hvflip1[] = {0x8c, 0x27, 0x19};
static u8 dat_hvflip3[] = {0x8c, 0x27, 0x3b};
static u8 dat_hvflip5[] = {0x8c, 0xa1, 0x03};
static u8 dat_hvflip6[] = {0x90, 0x00, 0x06};
+static struct idxdata tbl_middle_hvflip_low[] = {
+ {0x33, "\x90\x00\x06"},
+ {6, "\xff\xff\xff"},
+ {0x33, "\x90\x00\x06"},
+ {6, "\xff\xff\xff"},
+ {0x33, "\x90\x00\x06"},
+ {6, "\xff\xff\xff"},
+ {0x33, "\x90\x00\x06"},
+ {6, "\xff\xff\xff"},
+};
+
+static struct idxdata tbl_middle_hvflip_big[] = {
+ {0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x01"}, {0x33, "\x8c\xa1\x20"},
+ {0x33, "\x90\x00\x00"}, {0x33, "\x8c\xa7\x02"}, {0x33, "\x90\x00\x00"},
+ {102, "\xff\xff\xff"},
+ {0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x02"}, {0x33, "\x8c\xa1\x20"},
+ {0x33, "\x90\x00\x72"}, {0x33, "\x8c\xa7\x02"}, {0x33, "\x90\x00\x01"},
+};
+
+static struct idxdata tbl_end_hvflip[] = {
+ {0x33, "\x8c\xa1\x02"}, {0x33, "\x90\x00\x1f"},
+ {6, "\xff\xff\xff"},
+ {0x33, "\x8c\xa1\x02"}, {0x33, "\x90\x00\x1f"},
+ {6, "\xff\xff\xff"},
+ {0x33, "\x8c\xa1\x02"}, {0x33, "\x90\x00\x1f"},
+ {6, "\xff\xff\xff"},
+ {0x33, "\x8c\xa1\x02"}, {0x33, "\x90\x00\x1f"},
+};
+
static u8 dat_freq1[] = { 0x8c, 0xa4, 0x04 };
static u8 dat_multi5[] = { 0x8c, 0xa1, 0x03 };
static u8 dat_multi6[] = { 0x90, 0x00, 0x05 };
-static struct validx tbl_common1[] = {
- {0x0000, 0x0000},
- {1, 0xffff}, /* msleep(35); */
- {0x006a, 0x0007}, {0x0063, 0x0006}, {0x006a, 0x000d}, {0x0000, 0x00c0},
- {0x0010, 0x0010}, {0x0003, 0x00c1}, {0x0042, 0x00c2}, {0x0004, 0x00d8},
- {0x0000, 0x0058}, {0x0002, 0x0004}, {0x0041, 0x0000},
+static struct validx tbl_init_at_startup[] = {
+ {0x0000, 0x0000}, {0x0010, 0x0010}, {0x0008, 0x00c0}, {0x0001,0x00c1},
+ {0x0001, 0x00c2}, {0x0020, 0x0006}, {0x006a, 0x000d},
+ {53, 0xffff},
+ {0x0040, 0x0000}, {0x0063, 0x0006},
};
-static struct validx tbl_common2[] = {
- {0x006a, 0x0007},
- {35, 0xffff},
- {0x00ef, 0x0006},
- {35, 0xffff},
- {0x006a, 0x000d},
- {35, 0xffff},
- {0x0000, 0x00c0}, {0x0010, 0x0010}, {0x0003, 0x00c1}, {0x0042, 0x00c2},
+static struct validx tbl_common_0B[] = {
+ {0x0002, 0x0004}, {0x006a, 0x0007}, {0x00ef, 0x0006}, {0x006a,0x000d},
+ {0x0000, 0x00c0}, {0x0010, 0x0010}, {0x0003, 0x00c1}, {0x0042,0x00c2},
{0x0004, 0x00d8}, {0x0000, 0x0058}, {0x0041, 0x0000},
};
-static struct idxdata tbl_common3[] = {
- {0x32, "\x02\x00\x08"}, {0x33, "\xf4\x03\x1d"},
+static struct idxdata tbl_common_3B[] = {
+ {0x33, "\x86\x25\x01"}, {0x33, "\x86\x25\x00"},
+ {2, "\xff\xff\xff"},
+ {0x30, "\x1a\x0a\xcc"}, {0x32, "\x02\x00\x08"}, {0x33, "\xf4\x03\x1d"},
{6, "\xff\xff\xff"}, /* 12 */
{0x34, "\x1e\x8f\x09"}, {0x34, "\x1c\x01\x28"}, {0x34, "\x1e\x8f\x09"},
{2, "\xff\xff\xff"}, /* - */
@@ -98,85 +122,58 @@ static struct idxdata tbl_common3[] = {
{0x35, "\x50\x00\x06"}, {0x35, "\x48\x07\xff"}, {0x35, "\x60\x05\x89"},
{0x35, "\x58\x07\xff"}, {0x35, "\x40\x00\xa0"}, {0x35, "\x42\x00\x00"},
{0x32, "\x10\x01\xfc"}, {0x33, "\x8c\xa1\x18"}, {0x33, "\x90\x00\x3c"},
- {1, "\xff\xff\xff"},
{0x33, "\x78\x00\x00"},
- {1, "\xff\xff\xff"},
+ {2, "\xff\xff\xff"},
{0x35, "\xb8\x1f\x20"}, {0x33, "\x8c\xa2\x06"}, {0x33, "\x90\x00\x10"},
{0x33, "\x8c\xa2\x07"}, {0x33, "\x90\x00\x08"}, {0x33, "\x8c\xa2\x42"},
{0x33, "\x90\x00\x0b"}, {0x33, "\x8c\xa2\x4a"}, {0x33, "\x90\x00\x8c"},
{0x35, "\xba\xfa\x08"}, {0x33, "\x8c\xa2\x02"}, {0x33, "\x90\x00\x22"},
- {0x33, "\x8c\xa2\x03"}, {0x33, "\x90\x00\xbb"},
-};
-
-static struct idxdata tbl_common4[] = {
- {0x33, "\x8c\x22\x2e"}, {0x33, "\x90\x00\xa0"}, {0x33, "\x8c\xa4\x08"},
+ {0x33, "\x8c\xa2\x03"}, {0x33, "\x90\x00\xbb"}, {0x33, "\x8c\xa4\x04"},
+ {0x33, "\x90\x00\x80"}, {0x33, "\x8c\xa7\x9d"}, {0x33, "\x90\x00\x00"},
+ {0x33, "\x8c\xa7\x9e"}, {0x33, "\x90\x00\x00"}, {0x33, "\x8c\xa2\x0c"},
+ {0x33, "\x90\x00\x17"}, {0x33, "\x8c\xa2\x15"}, {0x33, "\x90\x00\x04"},
+ {0x33, "\x8c\xa2\x14"}, {0x33, "\x90\x00\x20"}, {0x33, "\x8c\xa1\x03"},
+ {0x33, "\x90\x00\x00"}, {0x33, "\x8c\x27\x17"}, {0x33, "\x90\x21\x11"},
+ {0x33, "\x8c\x27\x1b"}, {0x33, "\x90\x02\x4f"}, {0x33, "\x8c\x27\x25"},
+ {0x33, "\x90\x06\x0f"}, {0x33, "\x8c\x27\x39"}, {0x33, "\x90\x21\x11"},
+ {0x33, "\x8c\x27\x3d"}, {0x33, "\x90\x01\x20"}, {0x33, "\x8c\x27\x47"},
+ {0x33, "\x90\x09\x4c"}, {0x33, "\x8c\x27\x03"}, {0x33, "\x90\x02\x84"},
+ {0x33, "\x8c\x27\x05"}, {0x33, "\x90\x01\xe2"}, {0x33, "\x8c\x27\x07"},
+ {0x33, "\x90\x06\x40"}, {0x33, "\x8c\x27\x09"}, {0x33, "\x90\x04\xb0"},
+ {0x33, "\x8c\x27\x0d"}, {0x33, "\x90\x00\x00"}, {0x33, "\x8c\x27\x0f"},
+ {0x33, "\x90\x00\x00"}, {0x33, "\x8c\x27\x11"}, {0x33, "\x90\x04\xbd"},
+ {0x33, "\x8c\x27\x13"}, {0x33, "\x90\x06\x4d"}, {0x33, "\x8c\x27\x15"},
+ {0x33, "\x90\x00\x00"}, {0x33, "\x8c\x27\x17"}, {0x33, "\x90\x21\x11"},
+ {0x33, "\x8c\x27\x19"}, {0x33, "\x90\x04\x6c"}, {0x33, "\x8c\x27\x1b"},
+ {0x33, "\x90\x02\x4f"}, {0x33, "\x8c\x27\x1d"}, {0x33, "\x90\x01\x02"},
+ {0x33, "\x8c\x27\x1f"}, {0x33, "\x90\x02\x79"}, {0x33, "\x8c\x27\x21"},
+ {0x33, "\x90\x01\x55"}, {0x33, "\x8c\x27\x23"}, {0x33, "\x90\x02\x85"},
+ {0x33, "\x8c\x27\x25"}, {0x33, "\x90\x06\x0f"}, {0x33, "\x8c\x27\x27"},
+ {0x33, "\x90\x20\x20"}, {0x33, "\x8c\x27\x29"}, {0x33, "\x90\x20\x20"},
+ {0x33, "\x8c\x27\x2b"}, {0x33, "\x90\x10\x20"}, {0x33, "\x8c\x27\x2d"},
+ {0x33, "\x90\x20\x07"}, {0x33, "\x8c\x27\x2f"}, {0x33, "\x90\x00\x04"},
+ {0x33, "\x8c\x27\x31"}, {0x33, "\x90\x00\x04"}, {0x33, "\x8c\x27\x33"},
+ {0x33, "\x90\x04\xbb"}, {0x33, "\x8c\x27\x35"}, {0x33, "\x90\x06\x4b"},
+ {0x33, "\x8c\x27\x37"}, {0x33, "\x90\x00\x00"}, {0x33, "\x8c\x27\x39"},
+ {0x33, "\x90\x21\x11"}, {0x33, "\x8c\x27\x3b"}, {0x33, "\x90\x00\x24"},
+ {0x33, "\x8c\x27\x3d"}, {0x33, "\x90\x01\x20"}, {0x33, "\x8c\x27\x41"},
+ {0x33, "\x90\x01\x69"}, {0x33, "\x8c\x27\x45"}, {0x33, "\x90\x04\xed"},
+ {0x33, "\x8c\x27\x47"}, {0x33, "\x90\x09\x4c"}, {0x33, "\x8c\x27\x51"},
+ {0x33, "\x90\x00\x00"}, {0x33, "\x8c\x27\x53"}, {0x33, "\x90\x03\x20"},
+ {0x33, "\x8c\x27\x55"}, {0x33, "\x90\x00\x00"}, {0x33, "\x8c\x27\x57"},
+ {0x33, "\x90\x02\x58"}, {0x33, "\x8c\x27\x5f"}, {0x33, "\x90\x00\x00"},
+ {0x33, "\x8c\x27\x61"}, {0x33, "\x90\x06\x40"}, {0x33, "\x8c\x27\x63"},
+ {0x33, "\x90\x00\x00"}, {0x33, "\x8c\x27\x65"}, {0x33, "\x90\x04\xb0"},
+ {0x33, "\x8c\x22\x2e"}, {0x33, "\x90\x00\xa1"}, {0x33, "\x8c\xa4\x08"},
{0x33, "\x90\x00\x1f"}, {0x33, "\x8c\xa4\x09"}, {0x33, "\x90\x00\x21"},
{0x33, "\x8c\xa4\x0a"}, {0x33, "\x90\x00\x25"}, {0x33, "\x8c\xa4\x0b"},
- {0x33, "\x90\x00\x27"}, {0x33, "\x8c\x24\x11"}, {0x33, "\x90\x00\xa0"},
- {0x33, "\x8c\x24\x13"}, {0x33, "\x90\x00\xc0"}, {0x33, "\x8c\x24\x15"},
- {0x33, "\x90\x00\xa0"}, {0x33, "\x8c\x24\x17"}, {0x33, "\x90\x00\xc0"},
-};
-
-static struct idxdata tbl_common5[] = {
- {0x33, "\x8c\xa4\x04"}, {0x33, "\x90\x00\x80"}, {0x33, "\x8c\xa7\x9d"},
- {0x33, "\x90\x00\x00"}, {0x33, "\x8c\xa7\x9e"}, {0x33, "\x90\x00\x00"},
- {0x33, "\x8c\xa2\x0c"}, {0x33, "\x90\x00\x17"}, {0x33, "\x8c\xa2\x15"},
- {0x33, "\x90\x00\x04"}, {0x33, "\x8c\xa2\x14"}, {0x33, "\x90\x00\x20"},
- {0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x00"}, {0x33, "\x8c\x27\x17"},
- /* msleep(53); */
- {0x33, "\x90\x21\x11"}, {0x33, "\x8c\x27\x1b"}, {0x33, "\x90\x02\x4f"},
- {0x33, "\x8c\x27\x25"}, {0x33, "\x90\x06\x0f"}, {0x33, "\x8c\x27\x39"},
- {0x33, "\x90\x21\x11"}, {0x33, "\x8c\x27\x3d"}, {0x33, "\x90\x01\x20"},
- {0x33, "\x8c\x27\x47"}, {0x33, "\x90\x09\x4c"}, {0x33, "\x8c\x27\x03"},
- {0x33, "\x90\x02\x84"}, {0x33, "\x8c\x27\x05"}, {0x33, "\x90\x01\xe2"},
- {0x33, "\x8c\x27\x07"}, {0x33, "\x90\x06\x40"}, {0x33, "\x8c\x27\x09"},
- {0x33, "\x90\x04\xb0"}, {0x33, "\x8c\x27\x0d"}, {0x33, "\x90\x00\x00"},
- {0x33, "\x8c\x27\x0f"}, {0x33, "\x90\x00\x00"}, {0x33, "\x8c\x27\x11"},
- {0x33, "\x90\x04\xbd"}, {0x33, "\x8c\x27\x13"}, {0x33, "\x90\x06\x4d"},
- {0x33, "\x8c\x27\x15"}, {0x33, "\x90\x00\x00"}, {0x33, "\x8c\x27\x17"},
- {0x33, "\x90\x21\x11"}, {0x33, "\x8c\x27\x19"}, {0x33, "\x90\x04\x6c"},
- {0x33, "\x8c\x27\x1b"}, {0x33, "\x90\x02\x4f"}, {0x33, "\x8c\x27\x1d"},
- {0x33, "\x90\x01\x02"}, {0x33, "\x8c\x27\x1f"}, {0x33, "\x90\x02\x79"},
- {0x33, "\x8c\x27\x21"}, {0x33, "\x90\x01\x55"}, {0x33, "\x8c\x27\x23"},
- {0x33, "\x90\x02\x85"}, {0x33, "\x8c\x27\x25"}, {0x33, "\x90\x06\x0f"},
- {0x33, "\x8c\x27\x27"}, {0x33, "\x90\x20\x20"}, {0x33, "\x8c\x27\x29"},
- {0x33, "\x90\x20\x20"}, {0x33, "\x8c\x27\x2b"}, {0x33, "\x90\x10\x20"},
- {0x33, "\x8c\x27\x2d"}, {0x33, "\x90\x20\x07"}, {0x33, "\x8c\x27\x2f"},
- {0x33, "\x90\x00\x04"}, {0x33, "\x8c\x27\x31"}, {0x33, "\x90\x00\x04"},
- {0x33, "\x8c\x27\x33"}, {0x33, "\x90\x04\xbb"}, {0x33, "\x8c\x27\x35"},
- {0x33, "\x90\x06\x4b"}, {0x33, "\x8c\x27\x37"}, {0x33, "\x90\x00\x00"},
- {0x33, "\x8c\x27\x39"}, {0x33, "\x90\x21\x11"}, {0x33, "\x8c\x27\x3b"},
- {0x33, "\x90\x00\x24"}, {0x33, "\x8c\x27\x3d"}, {0x33, "\x90\x01\x20"},
- {0x33, "\x8c\x27\x41"}, {0x33, "\x90\x01\x69"}, {0x33, "\x8c\x27\x45"},
- {0x33, "\x90\x04\xed"}, {0x33, "\x8c\x27\x47"}, {0x33, "\x90\x09\x4c"},
- {0x33, "\x8c\x27\x51"}, {0x33, "\x90\x00\x00"}, {0x33, "\x8c\x27\x53"},
- {0x33, "\x90\x03\x20"}, {0x33, "\x8c\x27\x55"}, {0x33, "\x90\x00\x00"},
- {0x33, "\x8c\x27\x57"}, {0x33, "\x90\x02\x58"}, {0x33, "\x8c\x27\x5f"},
- {0x33, "\x90\x00\x00"}, {0x33, "\x8c\x27\x61"}, {0x33, "\x90\x06\x40"},
- {0x33, "\x8c\x27\x63"}, {0x33, "\x90\x00\x00"}, {0x33, "\x8c\x27\x65"},
- {0x33, "\x90\x04\xb0"}, {0x33, "\x8c\x22\x2e"}, {0x33, "\x90\x00\xa1"},
- {0x33, "\x8c\xa4\x08"}, {0x33, "\x90\x00\x1f"}, {0x33, "\x8c\xa4\x09"},
- {0x33, "\x90\x00\x21"}, {0x33, "\x8c\xa4\x0a"}, {0x33, "\x90\x00\x25"},
- {0x33, "\x8c\xa4\x0b"}, {0x33, "\x90\x00\x27"}, {0x33, "\x8c\x24\x11"},
- {0x33, "\x90\x00\xa1"}, {0x33, "\x8c\x24\x13"}, {0x33, "\x90\x00\xc1"},
- {0x33, "\x8c\x24\x15"},
-};
-
-static struct validx tbl_init_at_startup[] = {
- {0x0000, 0x0000},
- {53, 0xffff},
- {0x0010, 0x0010},
- {53, 0xffff},
- {0x0008, 0x00c0},
- {53, 0xffff},
- {0x0001, 0x00c1},
- {53, 0xffff},
- {0x0001, 0x00c2},
- {53, 0xffff},
- {0x0020, 0x0006},
- {53, 0xffff},
- {0x006a, 0x000d},
- {53, 0xffff},
+ {0x33, "\x90\x00\x27"}, {0x33, "\x8c\x24\x11"}, {0x33, "\x90\x00\xa1"},
+ {0x33, "\x8c\x24\x13"}, {0x33, "\x90\x00\xc1"}, {0x33, "\x8c\x24\x15"},
+ {0x33, "\x90\x00\x6a"}, {0x33, "\x8c\x24\x17"}, {0x33, "\x90\x00\x80"},
+ {0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x05"},
+ {2, "\xff\xff\xff"},
+ {0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x06"},
+ {3, "\xff\xff\xff"},
};
static struct idxdata tbl_init_post_alt_low1[] = {
@@ -209,7 +206,7 @@ static struct idxdata tbl_init_post_alt_low3[] = {
{2, "\xff\xff\xff"},
{0x33, "\x8c\xa1\x20"}, {0x33, "\x90\x00\x00"}, {0x33, "\x8c\xa1\x03"},
{0x33, "\x90\x00\x01"}, {0x33, "\x8c\xa7\x02"}, {0x33, "\x90\x00\x00"},
- {2, "\xff\xff\xff"}, /* - * */
+ {2, "\xff\xff\xff"},
{0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x05"},
{2, "\xff\xff\xff"},
{0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x06"},
@@ -217,61 +214,15 @@ static struct idxdata tbl_init_post_alt_low3[] = {
{0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x05"},
{2, "\xff\xff\xff"},
{0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x06"},
- {1, "\xff\xff\xff"},
-};
-
-static struct idxdata tbl_init_post_alt_low4[] = {
- {0x32, "\x10\x01\xf8"}, {0x34, "\xce\x01\xa8"}, {0x34, "\xd0\x66\x33"},
- {0x34, "\xd2\x31\x9a"}, {0x34, "\xd4\x94\x63"}, {0x34, "\xd6\x4b\x25"},
- {0x34, "\xd8\x26\x70"}, {0x34, "\xda\x72\x4c"}, {0x34, "\xdc\xff\x04"},
- {0x34, "\xde\x01\x5b"}, {0x34, "\xe6\x01\x13"}, {0x34, "\xee\x0b\xf0"},
- {0x34, "\xf6\x0b\xa4"}, {0x35, "\x00\xf6\xe7"}, {0x35, "\x08\x0d\xfd"},
- {0x35, "\x10\x25\x63"}, {0x35, "\x18\x35\x6c"}, {0x35, "\x20\x42\x7e"},
- {0x35, "\x28\x19\x44"}, {0x35, "\x30\x39\xd4"}, {0x35, "\x38\xf5\xa8"},
- {0x35, "\x4c\x07\x90"}, {0x35, "\x44\x07\xb8"}, {0x35, "\x5c\x06\x88"},
- {0x35, "\x54\x07\xff"}, {0x34, "\xe0\x01\x52"}, {0x34, "\xe8\x00\xcc"},
- {0x34, "\xf0\x0d\x83"}, {0x34, "\xf8\x0c\xb3"}, {0x35, "\x02\xfe\xba"},
- {0x35, "\x0a\x04\xe0"}, {0x35, "\x12\x1c\x63"}, {0x35, "\x1a\x2b\x5a"},
- {0x35, "\x22\x32\x5e"}, {0x35, "\x2a\x0d\x28"}, {0x35, "\x32\x2c\x02"},
- {0x35, "\x3a\xf4\xfa"}, {0x35, "\x4e\x07\xef"}, {0x35, "\x46\x07\x88"},
- {0x35, "\x5e\x07\xc1"}, {0x35, "\x56\x04\x64"}, {0x34, "\xe4\x01\x15"},
- {0x34, "\xec\x00\x82"}, {0x34, "\xf4\x0c\xce"}, {0x34, "\xfc\x0c\xba"},
- {0x35, "\x06\x1f\x02"}, {0x35, "\x0e\x02\xe3"}, {0x35, "\x16\x1a\x50"},
- {0x35, "\x1e\x24\x39"}, {0x35, "\x26\x23\x4c"}, {0x35, "\x2e\xf9\x1b"},
- {0x35, "\x36\x23\x19"}, {0x35, "\x3e\x12\x08"}, {0x35, "\x52\x07\x22"},
- {0x35, "\x4a\x03\xd3"}, {0x35, "\x62\x06\x54"}, {0x35, "\x5a\x04\x5d"},
- {0x34, "\xe2\x01\x04"}, {0x34, "\xea\x00\xa0"}, {0x34, "\xf2\x0c\xbc"},
- {0x34, "\xfa\x0c\x5b"}, {0x35, "\x04\x17\xf2"}, {0x35, "\x0c\x02\x08"},
- {0x35, "\x14\x28\x43"}, {0x35, "\x1c\x28\x62"}, {0x35, "\x24\x2b\x60"},
- {0x35, "\x2c\x07\x33"}, {0x35, "\x34\x1f\xb0"}, {0x35, "\x3c\xed\xcd"},
- {0x35, "\x50\x00\x06"}, {0x35, "\x48\x07\xff"}, {0x35, "\x60\x05\x89"},
- {0x35, "\x58\x07\xff"}, {0x35, "\x40\x00\xa0"}, {0x35, "\x42\x00\x00"},
- {0x32, "\x10\x01\xfc"}, {0x33, "\x8c\xa1\x18"},
- /* Flip/Mirror h/v=1 */
- {0x33, "\x90\x00\x3c"}, {0x33, "\x8c\x27\x19"}, {0x33, "\x90\x04\x6c"},
- {0x33, "\x8c\x27\x3b"}, {0x33, "\x90\x00\x24"}, {0x33, "\x8c\xa1\x03"},
- {0x33, "\x90\x00\x06"},
- {130, "\xff\xff\xff"},
- {0x33, "\x90\x00\x06"}, {0x33, "\x90\x00\x06"}, {0x33, "\x90\x00\x06"},
- {0x33, "\x90\x00\x06"}, {0x33, "\x90\x00\x06"}, {0x33, "\x90\x00\x06"},
- {100, "\xff\xff\xff"},
- /* ?? */
- {0x33, "\x8c\xa1\x02"}, {0x33, "\x90\x00\x1f"}, {0x33, "\x8c\xa1\x02"},
- {0x33, "\x90\x00\x1f"}, {0x33, "\x8c\xa1\x02"}, {0x33, "\x90\x00\x1f"},
- {0x33, "\x8c\xa1\x02"}, {0x33, "\x90\x00\x1f"},
- /* Brigthness=70 */
- {0x33, "\x8c\xa2\x06"}, {0x33, "\x90\x00\x46"}, {0x33, "\x8c\xa1\x02"},
- {0x33, "\x90\x00\x0f"}, {0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x05"},
- /* Sharpness=20 */
- {0x32, "\x6c\x14\x08"},
};
-static struct idxdata tbl_init_post_alt_big1[] = {
+static struct idxdata tbl_init_post_alt_big[] = {
{0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x05"},
{2, "\xff\xff\xff"},
{0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x06"},
{2, "\xff\xff\xff"},
{0x34, "\x1e\x8f\x09"}, {0x34, "\x1c\x01\x28"}, {0x34, "\x1e\x8f\x09"},
+ {2, "\xff\xff\xff"},
{0x34, "\x1e\x8f\x09"}, {0x32, "\x14\x06\xe6"}, {0x33, "\x8c\xa1\x03"},
{0x33, "\x90\x00\x05"},
{2, "\xff\xff\xff"},
@@ -285,9 +236,17 @@ static struct idxdata tbl_init_post_alt_big1[] = {
{0x33, "\x90\x00\x03"}, {0x33, "\x8c\xa1\x34"}, {0x33, "\x90\x00\x03"},
{0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x02"}, {0x33, "\x2e\x01\x00"},
{0x34, "\x04\x00\x2a"}, {0x33, "\x8c\xa7\x02"}, {0x33, "\x90\x00\x01"},
+ {0x33, "\x8c\x27\x97"}, {0x33, "\x90\x01\x00"},
+ {51, "\xff\xff\xff"},
+ {0x33, "\x8c\xa1\x20"}, {0x33, "\x90\x00\x00"}, {0x33, "\x8c\xa1\x03"},
+ {0x33, "\x90\x00\x01"}, {0x33, "\x8c\xa7\x02"}, {0x33, "\x90\x00\x00"},
+ {51, "\xff\xff\xff"},
+ {0x33, "\x8c\xa1\x20"}, {0x33, "\x90\x00\x72"}, {0x33, "\x8c\xa1\x03"},
+ {0x33, "\x90\x00\x02"}, {0x33, "\x8c\xa7\x02"}, {0x33, "\x90\x00\x01"},
+ {51, "\xff\xff\xff"},
};
-static struct idxdata tbl_init_post_alt_big2[] = {
+static struct idxdata tbl_init_post_alt_3B[] = {
{0x32, "\x10\x01\xf8"}, {0x34, "\xce\x01\xa8"}, {0x34, "\xd0\x66\x33"},
{0x34, "\xd2\x31\x9a"}, {0x34, "\xd4\x94\x63"}, {0x34, "\xd6\x4b\x25"},
{0x34, "\xd8\x26\x70"}, {0x34, "\xda\x72\x4c"}, {0x34, "\xdc\xff\x04"},
@@ -316,17 +275,6 @@ static struct idxdata tbl_init_post_alt_big2[] = {
{0x32, "\x10\x01\xfc"}, {0x33, "\x8c\xa1\x18"}, {0x33, "\x90\x00\x3c"},
};
-static struct idxdata tbl_init_post_alt_big3[] = {
- {0x33, "\x8c\xa1\x02"},
- {0x33, "\x90\x00\x1f"},
- {0x33, "\x8c\xa1\x02"},
- {0x33, "\x90\x00\x1f"},
- {0x33, "\x8c\xa1\x02"},
- {0x33, "\x90\x00\x1f"},
- {0x33, "\x8c\xa1\x02"},
- {0x33, "\x90\x00\x1f"},
-};
-
static u8 *dat_640 = "\xd0\x02\xd1\x08\xd2\xe1\xd3\x02\xd4\x10\xd5\x81";
static u8 *dat_800 = "\xd0\x02\xd1\x10\xd2\x57\xd3\x02\xd4\x18\xd5\x21";
static u8 *dat_1280 = "\xd0\x02\xd1\x20\xd2\x01\xd3\x02\xd4\x28\xd5\x01";
@@ -351,7 +299,7 @@ void mi2020_init_settings(struct gspca_dev *gspca_dev)
sd->vcur.gamma = 0;
sd->vcur.hue = 0;
sd->vcur.saturation = 60;
- sd->vcur.whitebal = 50;
+ sd->vcur.whitebal = 0; /* 50, not done by hardware */
sd->vcur.mirror = 0;
sd->vcur.flip = 0;
sd->vcur.AC50Hz = 1;
@@ -361,17 +309,12 @@ void mi2020_init_settings(struct gspca_dev *gspca_dev)
sd->vmax.sharpness = 40;
sd->vmax.contrast = 3;
sd->vmax.gamma = 2;
- sd->vmax.hue = 0 + 1; /* 200 */
- sd->vmax.saturation = 0; /* 100 */
- sd->vmax.whitebal = 0; /* 100 */
+ sd->vmax.hue = 0 + 1; /* 200, not done by hardware */
+ sd->vmax.saturation = 0; /* 100, not done by hardware */
+ sd->vmax.whitebal = 2; /* 100, not done by hardware */
sd->vmax.mirror = 1;
sd->vmax.flip = 1;
sd->vmax.AC50Hz = 1;
- if (_MI2020b_) {
- sd->vmax.contrast = 0;
- sd->vmax.gamma = 0;
- sd->vmax.backlight = 0;
- }
sd->dev_camera_settings = mi2020_camera_settings;
sd->dev_init_at_startup = mi2020_init_at_startup;
@@ -384,51 +327,9 @@ void mi2020_init_settings(struct gspca_dev *gspca_dev)
static void common(struct gspca_dev *gspca_dev)
{
- s32 reso = gspca_dev->cam.cam_mode[(s32) gspca_dev->curr_mode].priv;
-
- if (_MI2020b_) {
- fetch_validx(gspca_dev, tbl_common1, ARRAY_SIZE(tbl_common1));
- } else {
- if (_MI2020_)
- ctrl_out(gspca_dev, 0x40, 1, 0x0008, 0x0004, 0, NULL);
- else
- ctrl_out(gspca_dev, 0x40, 1, 0x0002, 0x0004, 0, NULL);
- msleep(35);
- fetch_validx(gspca_dev, tbl_common2, ARRAY_SIZE(tbl_common2));
- }
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x86\x25\x01");
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x86\x25\x00");
- msleep(2); /* - * */
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0030, 3, "\x1a\x0a\xcc");
- if (reso == IMAGE_1600)
- msleep(2); /* 1600 */
- fetch_idxdata(gspca_dev, tbl_common3, ARRAY_SIZE(tbl_common3));
-
- if (_MI2020b_ || _MI2020_)
- fetch_idxdata(gspca_dev, tbl_common4,
- ARRAY_SIZE(tbl_common4));
-
- fetch_idxdata(gspca_dev, tbl_common5, ARRAY_SIZE(tbl_common5));
- if (_MI2020b_ || _MI2020_) {
- /* Different from fret */
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x90\x00\x78");
- /* Same as fret */
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x8c\x24\x17");
- /* Different from fret */
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x90\x00\x90");
- } else {
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x90\x00\x6a");
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x8c\x24\x17");
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x90\x00\x80");
- }
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x8c\xa1\x03");
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x90\x00\x05");
- msleep(2);
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x8c\xa1\x03");
- if (reso == IMAGE_1600)
- msleep(14); /* 1600 */
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x90\x00\x06");
- msleep(2);
+ fetch_validx(gspca_dev, tbl_common_0B, ARRAY_SIZE(tbl_common_0B));
+ fetch_idxdata(gspca_dev, tbl_common_3B, ARRAY_SIZE(tbl_common_3B));
+ ctrl_out(gspca_dev, 0x40, 1, 0x0041, 0x0000, 0, NULL);
}
static int mi2020_init_at_startup(struct gspca_dev *gspca_dev)
@@ -441,8 +342,16 @@ static int mi2020_init_at_startup(struct gspca_dev *gspca_dev)
fetch_validx(gspca_dev, tbl_init_at_startup,
ARRAY_SIZE(tbl_init_at_startup));
+ ctrl_out(gspca_dev, 0x40, 1, 0x7a00, 0x8030, 0, NULL);
+ ctrl_in(gspca_dev, 0xc0, 2, 0x7a00, 0x8030, 1, &c);
+
common(gspca_dev);
+ msleep(61);
+/* ctrl_out(gspca_dev, 0x40, 11, 0x0000, 0x0000, 0, NULL); */
+/* msleep(36); */
+ ctrl_out(gspca_dev, 0x40, 1, 0x0001, 0x0000, 0, NULL);
+
return 0;
}
@@ -450,17 +359,17 @@ static int mi2020_init_pre_alt(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
- sd->mirrorMask = 0;
+ sd->mirrorMask = 0;
+ sd->vold.hue = -1;
- sd->vold.backlight = -1;
+ /* These controls need to be reset */
sd->vold.brightness = -1;
sd->vold.sharpness = -1;
- sd->vold.contrast = -1;
- sd->vold.gamma = -1;
- sd->vold.hue = -1;
- sd->vold.mirror = -1;
- sd->vold.flip = -1;
- sd->vold.AC50Hz = -1;
+
+ /* If not different from default, they do not need to be set */
+ sd->vold.contrast = 0;
+ sd->vold.gamma = 0;
+ sd->vold.backlight = 0;
mi2020_init_post_alt(gspca_dev);
@@ -472,10 +381,10 @@ static int mi2020_init_post_alt(struct gspca_dev *gspca_dev)
struct sd *sd = (struct sd *) gspca_dev;
s32 reso = gspca_dev->cam.cam_mode[(s32) gspca_dev->curr_mode].priv;
- s32 backlight = sd->vcur.backlight;
s32 mirror = (((sd->vcur.mirror > 0) ^ sd->mirrorMask) > 0);
s32 flip = (((sd->vcur.flip > 0) ^ sd->mirrorMask) > 0);
s32 freq = (sd->vcur.AC50Hz > 0);
+ s32 wbal = sd->vcur.whitebal;
u8 dat_freq2[] = {0x90, 0x00, 0x80};
u8 dat_multi1[] = {0x8c, 0xa7, 0x00};
@@ -484,6 +393,7 @@ static int mi2020_init_post_alt(struct gspca_dev *gspca_dev)
u8 dat_multi4[] = {0x90, 0x00, 0x00};
u8 dat_hvflip2[] = {0x90, 0x04, 0x6c};
u8 dat_hvflip4[] = {0x90, 0x00, 0x24};
+ u8 dat_wbal2[] = {0x90, 0x00, 0x00};
u8 c;
sd->nbIm = -1;
@@ -491,23 +401,26 @@ static int mi2020_init_post_alt(struct gspca_dev *gspca_dev)
dat_freq2[2] = freq ? 0xc0 : 0x80;
dat_multi1[2] = 0x9d;
dat_multi3[2] = dat_multi1[2] + 1;
- dat_multi4[2] = dat_multi2[2] = backlight;
+ if (wbal == 0) {
+ dat_multi4[2] = dat_multi2[2] = 0;
+ dat_wbal2[2] = 0x17;
+ } else if (wbal == 1) {
+ dat_multi4[2] = dat_multi2[2] = 0;
+ dat_wbal2[2] = 0x35;
+ } else if (wbal == 2) {
+ dat_multi4[2] = dat_multi2[2] = 0x20;
+ dat_wbal2[2] = 0x17;
+ }
dat_hvflip2[2] = 0x6c + 2 * (1 - flip) + (1 - mirror);
dat_hvflip4[2] = 0x24 + 2 * (1 - flip) + (1 - mirror);
msleep(200);
-
ctrl_out(gspca_dev, 0x40, 5, 0x0001, 0x0000, 0, NULL);
- msleep(3); /* 35 * */
+ msleep(2);
common(gspca_dev);
- ctrl_out(gspca_dev, 0x40, 1, 0x0041, 0x0000, 0, NULL);
- msleep(70);
-
- if (_MI2020b_)
- ctrl_out(gspca_dev, 0x40, 1, 0x0040, 0x0000, 0, NULL);
-
+ msleep(142);
ctrl_out(gspca_dev, 0x40, 1, 0x0010, 0x0010, 0, NULL);
ctrl_out(gspca_dev, 0x40, 1, 0x0003, 0x00c1, 0, NULL);
ctrl_out(gspca_dev, 0x40, 1, 0x0042, 0x00c2, 0, NULL);
@@ -523,8 +436,7 @@ static int mi2020_init_post_alt(struct gspca_dev *gspca_dev)
ctrl_out(gspca_dev, 0x40, 3, 0x0000, 0x0200,
12, dat_800);
- if (_MI2020c_)
- fetch_idxdata(gspca_dev, tbl_init_post_alt_low1,
+ fetch_idxdata(gspca_dev, tbl_init_post_alt_low1,
ARRAY_SIZE(tbl_init_post_alt_low1));
if (reso == IMAGE_800)
@@ -534,87 +446,10 @@ static int mi2020_init_post_alt(struct gspca_dev *gspca_dev)
fetch_idxdata(gspca_dev, tbl_init_post_alt_low3,
ARRAY_SIZE(tbl_init_post_alt_low3));
- if (_MI2020b_) {
- ctrl_out(gspca_dev, 0x40, 1, 0x0001, 0x0010, 0, NULL);
- ctrl_out(gspca_dev, 0x40, 1, 0x0000, 0x00c1, 0, NULL);
- ctrl_out(gspca_dev, 0x40, 1, 0x0041, 0x00c2, 0, NULL);
- msleep(150);
- } else if (_MI2020c_) {
- ctrl_out(gspca_dev, 0x40, 1, 0x0010, 0x0010, 0, NULL);
- ctrl_out(gspca_dev, 0x40, 1, 0x0000, 0x00c1, 0, NULL);
- ctrl_out(gspca_dev, 0x40, 1, 0x0041, 0x00c2, 0, NULL);
- msleep(120);
- ctrl_out(gspca_dev, 0x40, 1, 0x0040, 0x0000, 0, NULL);
- msleep(30);
- } else if (_MI2020_) {
- ctrl_out(gspca_dev, 0x40, 1, 0x0001, 0x0010, 0, NULL);
- ctrl_out(gspca_dev, 0x40, 1, 0x0000, 0x00c1, 0, NULL);
- ctrl_out(gspca_dev, 0x40, 1, 0x0041, 0x00c2, 0, NULL);
- msleep(120);
- ctrl_out(gspca_dev, 0x40, 1, 0x0040, 0x0000, 0, NULL);
- msleep(30);
- }
-
- /* AC power frequency */
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_freq1);
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_freq2);
- msleep(20);
- /* backlight */
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi1);
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi2);
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi3);
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi4);
- /* at init time but not after */
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x8c\xa2\x0c");
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x90\x00\x17");
- /* finish the backlight */
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi5);
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi6);
- msleep(5);/* " */
-
- if (_MI2020c_) {
- fetch_idxdata(gspca_dev, tbl_init_post_alt_low4,
- ARRAY_SIZE(tbl_init_post_alt_low4));
- } else {
- ctrl_in(gspca_dev, 0xc0, 2, 0x0000, 0x0000, 1, &c);
- msleep(14); /* 0xd8 */
-
- /* flip/mirror */
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033,
- 3, dat_hvflip1);
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033,
- 3, dat_hvflip2);
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033,
- 3, dat_hvflip3);
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033,
- 3, dat_hvflip4);
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033,
- 3, dat_hvflip5);
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033,
- 3, dat_hvflip6);
- msleep(21);
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033,
- 3, dat_dummy1);
- msleep(5);
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033,
- 3, dat_dummy1);
- msleep(5);
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033,
- 3, dat_dummy1);
- msleep(5);
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033,
- 3, dat_dummy1);
- msleep(5);
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033,
- 3, dat_dummy1);
- msleep(5);
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033,
- 3, dat_dummy1);
- /* end of flip/mirror main part */
- msleep(246); /* 146 */
-
- sd->nbIm = 0;
- }
+ ctrl_out(gspca_dev, 0x40, 1, 0x0010, 0x0010, 0, NULL);
+ ctrl_out(gspca_dev, 0x40, 1, 0x0000, 0x00c1, 0, NULL);
+ ctrl_out(gspca_dev, 0x40, 1, 0x0041, 0x00c2, 0, NULL);
+ msleep(120);
break;
case IMAGE_1280:
@@ -643,108 +478,62 @@ static int mi2020_init_post_alt(struct gspca_dev *gspca_dev)
3, "\x90\x04\xb0");
}
- fetch_idxdata(gspca_dev, tbl_init_post_alt_big1,
- ARRAY_SIZE(tbl_init_post_alt_big1));
-
- if (reso == IMAGE_1600)
- msleep(13); /* 1600 */
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x8c\x27\x97");
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x90\x01\x00");
- msleep(53);
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x8c\xa1\x20");
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x90\x00\x00");
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x8c\xa1\x03");
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x90\x00\x01");
- if (reso == IMAGE_1600)
- msleep(13); /* 1600 */
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x8c\xa7\x02");
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x90\x00\x00");
- msleep(53);
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x8c\xa1\x20");
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x90\x00\x72");
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x8c\xa1\x03");
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x90\x00\x02");
- if (reso == IMAGE_1600)
- msleep(13); /* 1600 */
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x8c\xa7\x02");
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x90\x00\x01");
- msleep(53);
-
- if (_MI2020b_) {
- ctrl_out(gspca_dev, 0x40, 1, 0x0001, 0x0010, 0, NULL);
- if (reso == IMAGE_1600)
- msleep(500); /* 1600 */
- ctrl_out(gspca_dev, 0x40, 1, 0x0000, 0x00c1, 0, NULL);
- ctrl_out(gspca_dev, 0x40, 1, 0x0041, 0x00c2, 0, NULL);
- msleep(1850);
- } else if (_MI2020c_ || _MI2020_) {
- ctrl_out(gspca_dev, 0x40, 1, 0x0001, 0x0010, 0, NULL);
- ctrl_out(gspca_dev, 0x40, 1, 0x0000, 0x00c1, 0, NULL);
- ctrl_out(gspca_dev, 0x40, 1, 0x0041, 0x00c2, 0, NULL);
- msleep(1850);
- ctrl_out(gspca_dev, 0x40, 1, 0x0040, 0x0000, 0, NULL);
- msleep(30);
- }
+ fetch_idxdata(gspca_dev, tbl_init_post_alt_big,
+ ARRAY_SIZE(tbl_init_post_alt_big));
- /* AC power frequency */
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_freq1);
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_freq2);
- msleep(20);
- /* backlight */
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi1);
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi2);
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi3);
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi4);
- /* at init time but not after */
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x8c\xa2\x0c");
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x90\x00\x17");
- /* finish the backlight */
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi5);
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi6);
- msleep(6); /* " */
+ ctrl_out(gspca_dev, 0x40, 1, 0x0001, 0x0010, 0, NULL);
+ ctrl_out(gspca_dev, 0x40, 1, 0x0000, 0x00c1, 0, NULL);
+ ctrl_out(gspca_dev, 0x40, 1, 0x0041, 0x00c2, 0, NULL);
+ msleep(1850);
+ }
- ctrl_in(gspca_dev, 0xc0, 2, 0x0000, 0x0000, 1, &c);
- msleep(14);
+ ctrl_out(gspca_dev, 0x40, 1, 0x0040, 0x0000, 0, NULL);
+ msleep(40);
+
+ /* AC power frequency */
+ ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_freq1);
+ ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_freq2);
+ msleep(33);
+ /* light source */
+ ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi1);
+ ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi2);
+ ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi3);
+ ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi4);
+ ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_wbal1);
+ ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_wbal2);
+ ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi5);
+ ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi6);
+ msleep(7);
+ ctrl_in(gspca_dev, 0xc0, 2, 0x0000, 0x0000, 1, &c);
+
+ fetch_idxdata(gspca_dev, tbl_init_post_alt_3B,
+ ARRAY_SIZE(tbl_init_post_alt_3B));
+
+ /* hvflip */
+ ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_hvflip1);
+ ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_hvflip2);
+ ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_hvflip3);
+ ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_hvflip4);
+ ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_hvflip5);
+ ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_hvflip6);
+ msleep(250);
+
+ if (reso == IMAGE_640 || reso == IMAGE_800)
+ fetch_idxdata(gspca_dev, tbl_middle_hvflip_low,
+ ARRAY_SIZE(tbl_middle_hvflip_low));
+ else
+ fetch_idxdata(gspca_dev, tbl_middle_hvflip_big,
+ ARRAY_SIZE(tbl_middle_hvflip_big));
- if (_MI2020c_)
- fetch_idxdata(gspca_dev, tbl_init_post_alt_big2,
- ARRAY_SIZE(tbl_init_post_alt_big2));
+ fetch_idxdata(gspca_dev, tbl_end_hvflip,
+ ARRAY_SIZE(tbl_end_hvflip));
- /* flip/mirror */
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_hvflip1);
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_hvflip2);
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_hvflip3);
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_hvflip4);
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_hvflip5);
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_hvflip6);
- /* end of flip/mirror main part */
- msleep(16);
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x8c\xa1\x03");
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x90\x00\x01");
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x8c\xa1\x20");
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x90\x00\x00");
- if (reso == IMAGE_1600)
- msleep(25); /* 1600 */
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x8c\xa7\x02");
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x90\x00\x00");
- msleep(103);
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x8c\xa1\x03");
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x90\x00\x02");
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x8c\xa1\x20");
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x90\x00\x72");
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x8c\xa7\x02");
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x90\x00\x01");
- sd->nbIm = 0;
-
- if (_MI2020c_)
- fetch_idxdata(gspca_dev, tbl_init_post_alt_big3,
- ARRAY_SIZE(tbl_init_post_alt_big3));
- }
+ sd->nbIm = 0;
sd->vold.mirror = mirror;
sd->vold.flip = flip;
sd->vold.AC50Hz = freq;
- sd->vold.backlight = backlight;
+ sd->vold.whitebal = wbal;
mi2020_camera_settings(gspca_dev);
@@ -772,6 +561,7 @@ static int mi2020_configure_alt(struct gspca_dev *gspca_dev)
static int mi2020_camera_settings(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
+ s32 reso = gspca_dev->cam.cam_mode[(s32) gspca_dev->curr_mode].priv;
s32 backlight = sd->vcur.backlight;
s32 bright = sd->vcur.brightness;
@@ -782,6 +572,7 @@ static int mi2020_camera_settings(struct gspca_dev *gspca_dev)
s32 mirror = (((sd->vcur.mirror > 0) ^ sd->mirrorMask) > 0);
s32 flip = (((sd->vcur.flip > 0) ^ sd->mirrorMask) > 0);
s32 freq = (sd->vcur.AC50Hz > 0);
+ s32 wbal = sd->vcur.whitebal;
u8 dat_sharp[] = {0x6c, 0x00, 0x08};
u8 dat_bright2[] = {0x90, 0x00, 0x00};
@@ -792,6 +583,7 @@ static int mi2020_camera_settings(struct gspca_dev *gspca_dev)
u8 dat_multi4[] = {0x90, 0x00, 0x00};
u8 dat_hvflip2[] = {0x90, 0x04, 0x6c};
u8 dat_hvflip4[] = {0x90, 0x00, 0x24};
+ u8 dat_wbal2[] = {0x90, 0x00, 0x00};
/* Less than 4 images received -> too early to set the settings */
if (sd->nbIm < 4) {
@@ -809,67 +601,89 @@ static int mi2020_camera_settings(struct gspca_dev *gspca_dev)
msleep(20);
}
+ if (wbal != sd->vold.whitebal) {
+ sd->vold.whitebal = wbal;
+ if (wbal < 0 || wbal > sd->vmax.whitebal)
+ wbal = 0;
+
+ dat_multi1[2] = 0x9d;
+ dat_multi3[2] = dat_multi1[2] + 1;
+ if (wbal == 0) {
+ dat_multi4[2] = dat_multi2[2] = 0;
+ dat_wbal2[2] = 0x17;
+ } else if (wbal == 1) {
+ dat_multi4[2] = dat_multi2[2] = 0;
+ dat_wbal2[2] = 0x35;
+ } else if (wbal == 2) {
+ dat_multi4[2] = dat_multi2[2] = 0x20;
+ dat_wbal2[2] = 0x17;
+ }
+ ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi1);
+ ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi2);
+ ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi3);
+ ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi4);
+ ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_wbal1);
+ ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_wbal2);
+ ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi5);
+ ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi6);
+ }
+
if (mirror != sd->vold.mirror || flip != sd->vold.flip) {
sd->vold.mirror = mirror;
sd->vold.flip = flip;
dat_hvflip2[2] = 0x6c + 2 * (1 - flip) + (1 - mirror);
dat_hvflip4[2] = 0x24 + 2 * (1 - flip) + (1 - mirror);
+
+ fetch_idxdata(gspca_dev, tbl_init_post_alt_3B,
+ ARRAY_SIZE(tbl_init_post_alt_3B));
+
ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_hvflip1);
ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_hvflip2);
ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_hvflip3);
ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_hvflip4);
ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_hvflip5);
ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_hvflip6);
- msleep(130);
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_dummy1);
- msleep(6);
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_dummy1);
- msleep(6);
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_dummy1);
- msleep(6);
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_dummy1);
- msleep(6);
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_dummy1);
- msleep(6);
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_dummy1);
- msleep(6);
-
- /* Sometimes present, sometimes not, useful? */
- /* ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dummy2);
- * ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dummy3);
- * ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dummy2);
- * ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dummy3);
- * ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dummy2);
- * ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dummy3);
- * ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dummy2);
- * ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dummy3);*/
+ msleep(40);
+
+ if (reso == IMAGE_640 || reso == IMAGE_800)
+ fetch_idxdata(gspca_dev, tbl_middle_hvflip_low,
+ ARRAY_SIZE(tbl_middle_hvflip_low));
+ else
+ fetch_idxdata(gspca_dev, tbl_middle_hvflip_big,
+ ARRAY_SIZE(tbl_middle_hvflip_big));
+
+ fetch_idxdata(gspca_dev, tbl_end_hvflip,
+ ARRAY_SIZE(tbl_end_hvflip));
}
- if (backlight != sd->vold.backlight) {
- sd->vold.backlight = backlight;
- if (backlight < 0 || backlight > sd->vmax.backlight)
- backlight = 0;
+ if (bright != sd->vold.brightness) {
+ sd->vold.brightness = bright;
+ if (bright < 0 || bright > sd->vmax.brightness)
+ bright = 0;
- dat_multi1[2] = 0x9d;
- dat_multi3[2] = dat_multi1[2] + 1;
- dat_multi4[2] = dat_multi2[2] = backlight;
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi1);
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi2);
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi3);
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi4);
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi5);
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi6);
+ dat_bright2[2] = bright;
+ ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_bright1);
+ ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_bright2);
+ ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_bright3);
+ ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_bright4);
+ ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_bright5);
+ ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_bright6);
}
- if (gam != sd->vold.gamma) {
+ if (cntr != sd->vold.contrast || gam != sd->vold.gamma) {
+ sd->vold.contrast = cntr;
+ if (cntr < 0 || cntr > sd->vmax.contrast)
+ cntr = 0;
sd->vold.gamma = gam;
if (gam < 0 || gam > sd->vmax.gamma)
gam = 0;
dat_multi1[2] = 0x6d;
dat_multi3[2] = dat_multi1[2] + 1;
- dat_multi4[2] = dat_multi2[2] = 0x40 + gam;
+ if (cntr == 0)
+ cntr = 4;
+ dat_multi4[2] = dat_multi2[2] = cntr * 0x10 + 2 - gam;
ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi1);
ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi2);
ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi3);
@@ -878,14 +692,14 @@ static int mi2020_camera_settings(struct gspca_dev *gspca_dev)
ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi6);
}
- if (cntr != sd->vold.contrast) {
- sd->vold.contrast = cntr;
- if (cntr < 0 || cntr > sd->vmax.contrast)
- cntr = 0;
+ if (backlight != sd->vold.backlight) {
+ sd->vold.backlight = backlight;
+ if (backlight < 0 || backlight > sd->vmax.backlight)
+ backlight = 0;
- dat_multi1[2] = 0x6d;
+ dat_multi1[2] = 0x9d;
dat_multi3[2] = dat_multi1[2] + 1;
- dat_multi4[2] = dat_multi2[2] = 0x12 + 16 * cntr;
+ dat_multi4[2] = dat_multi2[2] = backlight;
ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi1);
ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi2);
ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi3);
@@ -894,20 +708,6 @@ static int mi2020_camera_settings(struct gspca_dev *gspca_dev)
ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi6);
}
- if (bright != sd->vold.brightness) {
- sd->vold.brightness = bright;
- if (bright < 0 || bright > sd->vmax.brightness)
- bright = 0;
-
- dat_bright2[2] = bright;
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_bright1);
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_bright2);
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_bright3);
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_bright4);
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_bright5);
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_bright6);
- }
-
if (sharp != sd->vold.sharpness) {
sd->vold.sharpness = sharp;
if (sharp < 0 || sharp > sd->vmax.sharpness)
@@ -928,9 +728,6 @@ static int mi2020_camera_settings(struct gspca_dev *gspca_dev)
static void mi2020_post_unset_alt(struct gspca_dev *gspca_dev)
{
ctrl_out(gspca_dev, 0x40, 5, 0x0000, 0x0000, 0, NULL);
- msleep(20);
- if (_MI2020c_ || _MI2020_)
- ctrl_out(gspca_dev, 0x40, 1, 0x0001, 0x0000, 0, NULL);
- else
- ctrl_out(gspca_dev, 0x40, 1, 0x0041, 0x0000, 0, NULL);
+ msleep(40);
+ ctrl_out(gspca_dev, 0x40, 1, 0x0001, 0x0000, 0, NULL);
}
diff --git a/drivers/media/video/gspca/gl860/gl860-ov9655.c b/drivers/media/video/gspca/gl860/gl860-ov9655.c
index d412694c50a..5ae9619d72a 100644
--- a/drivers/media/video/gspca/gl860/gl860-ov9655.c
+++ b/drivers/media/video/gspca/gl860/gl860-ov9655.c
@@ -69,7 +69,7 @@ static u8 *tbl_640[] = {
"\xd0\x01\xd1\x08\xd2\xe0\xd3\x01" "\xd4\x10\xd5\x80"
};
-static u8 *tbl_800[] = {
+static u8 *tbl_1280[] = {
"\x00\x40\x07\x6a\x06\xf3\x0d\x6a" "\x10\x10\xc1\x01"
,
"\x12\x80\x00\x00\x01\x98\x02\x80" "\x03\x12\x04\x01\x0b\x57\x0e\x61"
@@ -217,7 +217,7 @@ static int ov9655_init_post_alt(struct gspca_dev *gspca_dev)
ctrl_out(gspca_dev, 0x40, 5, 0x0001, 0x0000, 0, NULL);
- tbl = (reso == IMAGE_640) ? tbl_640 : tbl_800;
+ tbl = (reso == IMAGE_640) ? tbl_640 : tbl_1280;
ctrl_out(gspca_dev, 0x40, 3, 0x0000, 0x0200,
tbl_length[0], tbl[0]);
diff --git a/drivers/media/video/gspca/gl860/gl860.c b/drivers/media/video/gspca/gl860/gl860.c
index 9e42476c0ea..e86eb8b4aed 100644
--- a/drivers/media/video/gspca/gl860/gl860.c
+++ b/drivers/media/video/gspca/gl860/gl860.c
@@ -63,7 +63,7 @@ static int sd_set_##thename(struct gspca_dev *gspca_dev, s32 val)\
\
sd->vcur.thename = val;\
if (gspca_dev->streaming)\
- sd->dev_camera_settings(gspca_dev);\
+ sd->waitSet = 1;\
return 0;\
} \
static int sd_get_##thename(struct gspca_dev *gspca_dev, s32 *val)\
@@ -91,7 +91,6 @@ SD_SETGET(contrast)
/* control table */
static struct ctrl sd_ctrls_mi1320[GL860_NCTRLS];
static struct ctrl sd_ctrls_mi2020[GL860_NCTRLS];
-static struct ctrl sd_ctrls_mi2020b[GL860_NCTRLS];
static struct ctrl sd_ctrls_ov2640[GL860_NCTRLS];
static struct ctrl sd_ctrls_ov9655[GL860_NCTRLS];
@@ -121,8 +120,6 @@ static int gl860_build_control_table(struct gspca_dev *gspca_dev)
sd_ctrls = sd_ctrls_mi1320;
else if (_MI2020_)
sd_ctrls = sd_ctrls_mi2020;
- else if (_MI2020b_)
- sd_ctrls = sd_ctrls_mi2020b;
else if (_OV2640_)
sd_ctrls = sd_ctrls_ov2640;
else if (_OV9655_)
@@ -187,19 +184,6 @@ static const struct sd_desc sd_desc_mi2020 = {
.dq_callback = sd_callback,
};
-static const struct sd_desc sd_desc_mi2020b = {
- .name = MODULE_NAME,
- .ctrls = sd_ctrls_mi2020b,
- .nctrls = GL860_NCTRLS,
- .config = sd_config,
- .init = sd_init,
- .isoc_init = sd_isoc_init,
- .start = sd_start,
- .stop0 = sd_stop0,
- .pkt_scan = sd_pkt_scan,
- .dq_callback = sd_callback,
-};
-
static const struct sd_desc sd_desc_ov2640 = {
.name = MODULE_NAME,
.ctrls = sd_ctrls_ov2640,
@@ -235,9 +219,9 @@ static struct v4l2_pix_format mi2020_mode[] = {
.colorspace = V4L2_COLORSPACE_SRGB,
.priv = 0
},
- { 800, 600, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE,
+ { 800, 598, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE,
.bytesperline = 800,
- .sizeimage = 800 * 600,
+ .sizeimage = 800 * 598,
.colorspace = V4L2_COLORSPACE_SRGB,
.priv = 1
},
@@ -247,9 +231,9 @@ static struct v4l2_pix_format mi2020_mode[] = {
.colorspace = V4L2_COLORSPACE_SRGB,
.priv = 2
},
- {1600, 1200, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE,
+ {1600, 1198, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE,
.bytesperline = 1600,
- .sizeimage = 1600 * 1200,
+ .sizeimage = 1600 * 1198,
.colorspace = V4L2_COLORSPACE_SRGB,
.priv = 3
},
@@ -344,8 +328,6 @@ static int sd_config(struct gspca_dev *gspca_dev,
sd->sensor = ID_OV9655;
else if (strcmp(sensor, "MI2020") == 0)
sd->sensor = ID_MI2020;
- else if (strcmp(sensor, "MI2020b") == 0)
- sd->sensor = ID_MI2020b;
/* Get sensor and set the suitable init/start/../stop functions */
if (gl860_guess_sensor(gspca_dev, vendor_id, product_id) == -1)
@@ -369,13 +351,6 @@ static int sd_config(struct gspca_dev *gspca_dev,
dev_init_settings = mi2020_init_settings;
break;
- case ID_MI2020b:
- gspca_dev->sd_desc = &sd_desc_mi2020b;
- cam->cam_mode = mi2020_mode;
- cam->nmodes = ARRAY_SIZE(mi2020_mode);
- dev_init_settings = mi2020_init_settings;
- break;
-
case ID_OV2640:
gspca_dev->sd_desc = &sd_desc_ov2640;
cam->cam_mode = ov2640_mode;
@@ -620,10 +595,7 @@ int gl860_RTx(struct gspca_dev *gspca_dev,
else if (len > 1 && r < len)
PDEBUG(D_ERR, "short ctrl transfer %d/%d", r, len);
- if ((_MI2020_ || _MI2020b_ || _MI2020c_) && (val || index))
- msleep(1);
- if (_OV2640_)
- msleep(1);
+ msleep(1);
return r;
}
@@ -767,8 +739,6 @@ static int gl860_guess_sensor(struct gspca_dev *gspca_dev,
PDEBUG(D_PROBE, "05e3:f191 sensor MI1320 (1.3M)");
} else if (_MI2020_) {
PDEBUG(D_PROBE, "05e3:0503 sensor MI2020 (2.0M)");
- } else if (_MI2020b_) {
- PDEBUG(D_PROBE, "05e3:0503 sensor MI2020 alt. driver (2.0M)");
} else if (_OV9655_) {
PDEBUG(D_PROBE, "05e3:0503 sensor OV9655 (1.3M)");
} else if (_OV2640_) {
diff --git a/drivers/media/video/gspca/gl860/gl860.h b/drivers/media/video/gspca/gl860/gl860.h
index 305061ff838..49ad4acbf60 100644
--- a/drivers/media/video/gspca/gl860/gl860.h
+++ b/drivers/media/video/gspca/gl860/gl860.h
@@ -32,19 +32,16 @@
#define ID_OV2640 2
#define ID_OV9655 4
#define ID_MI2020 8
-#define ID_MI2020b 16
#define _MI1320_ (((struct sd *) gspca_dev)->sensor == ID_MI1320)
#define _MI2020_ (((struct sd *) gspca_dev)->sensor == ID_MI2020)
-#define _MI2020b_ (((struct sd *) gspca_dev)->sensor == ID_MI2020b)
-#define _MI2020c_ 0
#define _OV2640_ (((struct sd *) gspca_dev)->sensor == ID_OV2640)
#define _OV9655_ (((struct sd *) gspca_dev)->sensor == ID_OV9655)
#define IMAGE_640 0
#define IMAGE_800 1
#define IMAGE_1280 2
-#define IMAGE_1600 3
+#define IMAGE_1600 3
struct sd_gl860 {
u16 backlight;
@@ -75,10 +72,10 @@ struct sd {
int (*dev_camera_settings)(struct gspca_dev *);
u8 swapRB;
- u8 mirrorMask;
- u8 sensor;
- s32 nbIm;
- s32 nbRightUp;
+ u8 mirrorMask;
+ u8 sensor;
+ s32 nbIm;
+ s32 nbRightUp;
u8 waitSet;
};
diff --git a/drivers/media/video/gspca/gspca.c b/drivers/media/video/gspca/gspca.c
index 678675bb365..d951b0f0e05 100644
--- a/drivers/media/video/gspca/gspca.c
+++ b/drivers/media/video/gspca/gspca.c
@@ -201,7 +201,7 @@ static int alloc_and_submit_int_urb(struct gspca_dev *gspca_dev,
buffer_len = le16_to_cpu(ep->wMaxPacketSize);
interval = ep->bInterval;
- PDEBUG(D_PROBE, "found int in endpoint: 0x%x, "
+ PDEBUG(D_CONF, "found int in endpoint: 0x%x, "
"buffer_len=%u, interval=%u",
ep->bEndpointAddress, buffer_len, interval);
@@ -226,7 +226,7 @@ static int alloc_and_submit_int_urb(struct gspca_dev *gspca_dev,
gspca_dev->int_urb = urb;
ret = usb_submit_urb(urb, GFP_KERNEL);
if (ret < 0) {
- PDEBUG(D_ERR, "submit URB failed with error %i", ret);
+ PDEBUG(D_ERR, "submit int URB failed with error %i", ret);
goto error_submit;
}
return ret;
@@ -294,19 +294,6 @@ static inline int gspca_input_connect(struct gspca_dev *dev)
}
#endif
-/* get the current input frame buffer */
-struct gspca_frame *gspca_get_i_frame(struct gspca_dev *gspca_dev)
-{
- struct gspca_frame *frame;
-
- frame = gspca_dev->cur_frame;
- if ((frame->v4l2_buf.flags & BUF_ALL_FLAGS)
- != V4L2_BUF_FLAG_QUEUED)
- return NULL;
- return frame;
-}
-EXPORT_SYMBOL(gspca_get_i_frame);
-
/*
* fill a video frame from an URB and resubmit
*/
@@ -439,20 +426,20 @@ void gspca_frame_add(struct gspca_dev *gspca_dev,
PDEBUG(D_PACK, "add t:%d l:%d", packet_type, len);
- /* check the availability of the frame buffer */
- frame = gspca_dev->cur_frame;
- if ((frame->v4l2_buf.flags & BUF_ALL_FLAGS)
- != V4L2_BUF_FLAG_QUEUED) {
- gspca_dev->last_packet_type = DISCARD_PACKET;
- return;
- }
-
- /* when start of a new frame, if the current frame buffer
- * is not queued, discard the whole frame */
if (packet_type == FIRST_PACKET) {
- frame->data_end = frame->data;
+ i = atomic_read(&gspca_dev->fr_i);
+
+ /* if there are no queued buffer, discard the whole frame */
+ if (i == atomic_read(&gspca_dev->fr_q)) {
+ gspca_dev->last_packet_type = DISCARD_PACKET;
+ return;
+ }
+ j = gspca_dev->fr_queue[i];
+ frame = &gspca_dev->frame[j];
frame->v4l2_buf.timestamp = ktime_to_timeval(ktime_get());
frame->v4l2_buf.sequence = ++gspca_dev->sequence;
+ gspca_dev->image = frame->data;
+ gspca_dev->image_len = 0;
} else if (gspca_dev->last_packet_type == DISCARD_PACKET) {
if (packet_type == LAST_PACKET)
gspca_dev->last_packet_type = packet_type;
@@ -461,34 +448,37 @@ void gspca_frame_add(struct gspca_dev *gspca_dev,
/* append the packet to the frame buffer */
if (len > 0) {
- if (frame->data_end - frame->data + len
- > frame->v4l2_buf.length) {
- PDEBUG(D_ERR|D_PACK, "frame overflow %zd > %d",
- frame->data_end - frame->data + len,
- frame->v4l2_buf.length);
+ if (gspca_dev->image_len + len > gspca_dev->frsz) {
+ PDEBUG(D_ERR|D_PACK, "frame overflow %d > %d",
+ gspca_dev->image_len + len,
+ gspca_dev->frsz);
packet_type = DISCARD_PACKET;
} else {
- memcpy(frame->data_end, data, len);
- frame->data_end += len;
+ memcpy(gspca_dev->image + gspca_dev->image_len,
+ data, len);
+ gspca_dev->image_len += len;
}
}
gspca_dev->last_packet_type = packet_type;
- /* if last packet, wake up the application and advance in the queue */
+ /* if last packet, invalidate packet concatenation until
+ * next first packet, wake up the application and advance
+ * in the queue */
if (packet_type == LAST_PACKET) {
- frame->v4l2_buf.bytesused = frame->data_end - frame->data;
- frame->v4l2_buf.flags &= ~V4L2_BUF_FLAG_QUEUED;
- frame->v4l2_buf.flags |= V4L2_BUF_FLAG_DONE;
- wake_up_interruptible(&gspca_dev->wq); /* event = new frame */
- i = (gspca_dev->fr_i + 1) % gspca_dev->nframes;
- gspca_dev->fr_i = i;
- PDEBUG(D_FRAM, "frame complete len:%d q:%d i:%d o:%d",
- frame->v4l2_buf.bytesused,
- gspca_dev->fr_q,
- i,
- gspca_dev->fr_o);
+ i = atomic_read(&gspca_dev->fr_i);
j = gspca_dev->fr_queue[i];
- gspca_dev->cur_frame = &gspca_dev->frame[j];
+ frame = &gspca_dev->frame[j];
+ frame->v4l2_buf.bytesused = gspca_dev->image_len;
+ frame->v4l2_buf.flags = (frame->v4l2_buf.flags
+ | V4L2_BUF_FLAG_DONE)
+ & ~V4L2_BUF_FLAG_QUEUED;
+ i = (i + 1) % GSPCA_MAX_FRAMES;
+ atomic_set(&gspca_dev->fr_i, i);
+ wake_up_interruptible(&gspca_dev->wq); /* event = new frame */
+ PDEBUG(D_FRAM, "frame complete len:%d",
+ frame->v4l2_buf.bytesused);
+ gspca_dev->image = NULL;
+ gspca_dev->image_len = 0;
}
}
EXPORT_SYMBOL(gspca_frame_add);
@@ -506,36 +496,6 @@ static int gspca_is_compressed(__u32 format)
return 0;
}
-static void *rvmalloc(long size)
-{
- void *mem;
- unsigned long adr;
-
- mem = vmalloc_32(size);
- if (mem != NULL) {
- adr = (unsigned long) mem;
- while (size > 0) {
- SetPageReserved(vmalloc_to_page((void *) adr));
- adr += PAGE_SIZE;
- size -= PAGE_SIZE;
- }
- }
- return mem;
-}
-
-static void rvfree(void *mem, long size)
-{
- unsigned long adr;
-
- adr = (unsigned long) mem;
- while (size > 0) {
- ClearPageReserved(vmalloc_to_page((void *) adr));
- adr += PAGE_SIZE;
- size -= PAGE_SIZE;
- }
- vfree(mem);
-}
-
static int frame_alloc(struct gspca_dev *gspca_dev,
unsigned int count)
{
@@ -548,9 +508,9 @@ static int frame_alloc(struct gspca_dev *gspca_dev,
PDEBUG(D_STREAM, "frame alloc frsz: %d", frsz);
frsz = PAGE_ALIGN(frsz);
gspca_dev->frsz = frsz;
- if (count > GSPCA_MAX_FRAMES)
- count = GSPCA_MAX_FRAMES;
- gspca_dev->frbuf = rvmalloc(frsz * count);
+ if (count >= GSPCA_MAX_FRAMES)
+ count = GSPCA_MAX_FRAMES - 1;
+ gspca_dev->frbuf = vmalloc_32(frsz * count);
if (!gspca_dev->frbuf) {
err("frame alloc failed");
return -ENOMEM;
@@ -565,14 +525,12 @@ static int frame_alloc(struct gspca_dev *gspca_dev,
frame->v4l2_buf.length = frsz;
frame->v4l2_buf.memory = gspca_dev->memory;
frame->v4l2_buf.sequence = 0;
- frame->data = frame->data_end =
- gspca_dev->frbuf + i * frsz;
+ frame->data = gspca_dev->frbuf + i * frsz;
frame->v4l2_buf.m.offset = i * frsz;
}
- gspca_dev->fr_i = gspca_dev->fr_o = gspca_dev->fr_q = 0;
- gspca_dev->cur_frame = &gspca_dev->frame[0];
- gspca_dev->last_packet_type = DISCARD_PACKET;
- gspca_dev->sequence = 0;
+ atomic_set(&gspca_dev->fr_q, 0);
+ atomic_set(&gspca_dev->fr_i, 0);
+ gspca_dev->fr_o = 0;
return 0;
}
@@ -582,8 +540,7 @@ static void frame_free(struct gspca_dev *gspca_dev)
PDEBUG(D_STREAM, "frame free");
if (gspca_dev->frbuf != NULL) {
- rvfree(gspca_dev->frbuf,
- gspca_dev->nframes * gspca_dev->frsz);
+ vfree(gspca_dev->frbuf);
gspca_dev->frbuf = NULL;
for (i = 0; i < gspca_dev->nframes; i++)
gspca_dev->frame[i].data = NULL;
@@ -683,12 +640,16 @@ static struct usb_host_endpoint *get_ep(struct gspca_dev *gspca_dev)
: USB_ENDPOINT_XFER_ISOC;
i = gspca_dev->alt; /* previous alt setting */
if (gspca_dev->cam.reverse_alts) {
+ if (gspca_dev->audio)
+ i++;
while (++i < gspca_dev->nbalt) {
ep = alt_xfer(&intf->altsetting[i], xfer);
if (ep)
break;
}
} else {
+ if (gspca_dev->audio)
+ i--;
while (--i >= 0) {
ep = alt_xfer(&intf->altsetting[i], xfer);
if (ep)
@@ -811,6 +772,12 @@ static int gspca_init_transfer(struct gspca_dev *gspca_dev)
goto out;
}
+ /* reset the streaming variables */
+ gspca_dev->image = NULL;
+ gspca_dev->image_len = 0;
+ gspca_dev->last_packet_type = DISCARD_PACKET;
+ gspca_dev->sequence = 0;
+
gspca_dev->usb_err = 0;
/* set the higher alternate setting and
@@ -1433,34 +1400,6 @@ static int vidioc_g_ctrl(struct file *file, void *priv,
return ret;
}
-/*fixme: have an audio flag in gspca_dev?*/
-static int vidioc_s_audio(struct file *file, void *priv,
- struct v4l2_audio *audio)
-{
- if (audio->index != 0)
- return -EINVAL;
- return 0;
-}
-
-static int vidioc_g_audio(struct file *file, void *priv,
- struct v4l2_audio *audio)
-{
- strcpy(audio->name, "Microphone");
- return 0;
-}
-
-static int vidioc_enumaudio(struct file *file, void *priv,
- struct v4l2_audio *audio)
-{
- if (audio->index != 0)
- return -EINVAL;
-
- strcpy(audio->name, "Microphone");
- audio->capability = 0;
- audio->mode = 0;
- return 0;
-}
-
static int vidioc_querymenu(struct file *file, void *priv,
struct v4l2_querymenu *qmenu)
{
@@ -1504,7 +1443,8 @@ static int vidioc_reqbufs(struct file *file, void *priv,
struct gspca_dev *gspca_dev = priv;
int i, ret = 0, streaming;
- switch (rb->memory) {
+ i = rb->memory; /* (avoid compilation warning) */
+ switch (i) {
case GSPCA_MEMORY_READ: /* (internal call) */
case V4L2_MEMORY_MMAP:
case V4L2_MEMORY_USERPTR:
@@ -1626,7 +1566,7 @@ static int vidioc_streamoff(struct file *file, void *priv,
enum v4l2_buf_type buf_type)
{
struct gspca_dev *gspca_dev = priv;
- int i, ret;
+ int ret;
if (buf_type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
return -EINVAL;
@@ -1650,12 +1590,10 @@ static int vidioc_streamoff(struct file *file, void *priv,
gspca_stream_off(gspca_dev);
mutex_unlock(&gspca_dev->usb_lock);
- /* empty the application queues */
- for (i = 0; i < gspca_dev->nframes; i++)
- gspca_dev->frame[i].v4l2_buf.flags &= ~BUF_ALL_FLAGS;
- gspca_dev->fr_i = gspca_dev->fr_o = gspca_dev->fr_q = 0;
- gspca_dev->last_packet_type = DISCARD_PACKET;
- gspca_dev->sequence = 0;
+ /* empty the transfer queues */
+ atomic_set(&gspca_dev->fr_q, 0);
+ atomic_set(&gspca_dev->fr_i, 0);
+ gspca_dev->fr_o = 0;
ret = 0;
out:
mutex_unlock(&gspca_dev->queue_lock);
@@ -1732,7 +1670,7 @@ static int vidioc_s_parm(struct file *filp, void *priv,
int n;
n = parm->parm.capture.readbuffers;
- if (n == 0 || n > GSPCA_MAX_FRAMES)
+ if (n == 0 || n >= GSPCA_MAX_FRAMES)
parm->parm.capture.readbuffers = gspca_dev->nbufread;
else
gspca_dev->nbufread = n;
@@ -1755,49 +1693,6 @@ static int vidioc_s_parm(struct file *filp, void *priv,
return 0;
}
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
-static int vidiocgmbuf(struct file *file, void *priv,
- struct video_mbuf *mbuf)
-{
- struct gspca_dev *gspca_dev = file->private_data;
- int i;
-
- PDEBUG(D_STREAM, "cgmbuf");
- if (gspca_dev->nframes == 0) {
- int ret;
-
- {
- struct v4l2_format fmt;
-
- fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- i = gspca_dev->cam.nmodes - 1; /* highest mode */
- fmt.fmt.pix.width = gspca_dev->cam.cam_mode[i].width;
- fmt.fmt.pix.height = gspca_dev->cam.cam_mode[i].height;
- fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_BGR24;
- ret = vidioc_s_fmt_vid_cap(file, priv, &fmt);
- if (ret != 0)
- return ret;
- }
- {
- struct v4l2_requestbuffers rb;
-
- memset(&rb, 0, sizeof rb);
- rb.count = 4;
- rb.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- rb.memory = V4L2_MEMORY_MMAP;
- ret = vidioc_reqbufs(file, priv, &rb);
- if (ret != 0)
- return ret;
- }
- }
- mbuf->frames = gspca_dev->nframes;
- mbuf->size = gspca_dev->frsz * gspca_dev->nframes;
- for (i = 0; i < mbuf->frames; i++)
- mbuf->offsets[i] = gspca_dev->frame[i].v4l2_buf.m.offset;
- return 0;
-}
-#endif
-
static int dev_mmap(struct file *file, struct vm_area_struct *vma)
{
struct gspca_dev *gspca_dev = file->private_data;
@@ -1838,12 +1733,7 @@ static int dev_mmap(struct file *file, struct vm_area_struct *vma)
ret = -EINVAL;
goto out;
}
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
- /* v4l1 maps all the buffers */
- if (i != 0
- || size != frame->v4l2_buf.length * gspca_dev->nframes)
-#endif
- if (size != frame->v4l2_buf.length) {
+ if (size != frame->v4l2_buf.length) {
PDEBUG(D_STREAM, "mmap bad size");
ret = -EINVAL;
goto out;
@@ -1883,21 +1773,17 @@ out:
static int frame_wait(struct gspca_dev *gspca_dev,
int nonblock_ing)
{
- struct gspca_frame *frame;
- int i, j, ret;
+ int i, ret;
/* check if a frame is ready */
i = gspca_dev->fr_o;
- j = gspca_dev->fr_queue[i];
- frame = &gspca_dev->frame[j];
-
- if (!(frame->v4l2_buf.flags & V4L2_BUF_FLAG_DONE)) {
+ if (i == atomic_read(&gspca_dev->fr_i)) {
if (nonblock_ing)
return -EAGAIN;
/* wait till a frame is ready */
ret = wait_event_interruptible_timeout(gspca_dev->wq,
- (frame->v4l2_buf.flags & V4L2_BUF_FLAG_DONE) ||
+ i != atomic_read(&gspca_dev->fr_i) ||
!gspca_dev->streaming || !gspca_dev->present,
msecs_to_jiffies(3000));
if (ret < 0)
@@ -1906,11 +1792,7 @@ static int frame_wait(struct gspca_dev *gspca_dev,
return -EIO;
}
- gspca_dev->fr_o = (i + 1) % gspca_dev->nframes;
- PDEBUG(D_FRAM, "frame wait q:%d i:%d o:%d",
- gspca_dev->fr_q,
- gspca_dev->fr_i,
- gspca_dev->fr_o);
+ gspca_dev->fr_o = (i + 1) % GSPCA_MAX_FRAMES;
if (gspca_dev->sd_desc->dq_callback) {
mutex_lock(&gspca_dev->usb_lock);
@@ -1919,7 +1801,7 @@ static int frame_wait(struct gspca_dev *gspca_dev,
gspca_dev->sd_desc->dq_callback(gspca_dev);
mutex_unlock(&gspca_dev->usb_lock);
}
- return j;
+ return gspca_dev->fr_queue[i];
}
/*
@@ -2024,15 +1906,9 @@ static int vidioc_qbuf(struct file *file, void *priv,
}
/* put the buffer in the 'queued' queue */
- i = gspca_dev->fr_q;
+ i = atomic_read(&gspca_dev->fr_q);
gspca_dev->fr_queue[i] = index;
- if (gspca_dev->fr_i == i)
- gspca_dev->cur_frame = frame;
- gspca_dev->fr_q = (i + 1) % gspca_dev->nframes;
- PDEBUG(D_FRAM, "qbuf q:%d i:%d o:%d",
- gspca_dev->fr_q,
- gspca_dev->fr_i,
- gspca_dev->fr_o);
+ atomic_set(&gspca_dev->fr_q, (i + 1) % GSPCA_MAX_FRAMES);
v4l2_buf->flags |= V4L2_BUF_FLAG_QUEUED;
v4l2_buf->flags &= ~V4L2_BUF_FLAG_DONE;
@@ -2088,7 +1964,7 @@ static int read_alloc(struct gspca_dev *gspca_dev,
static unsigned int dev_poll(struct file *file, poll_table *wait)
{
struct gspca_dev *gspca_dev = file->private_data;
- int i, ret;
+ int ret;
PDEBUG(D_FRAM, "poll");
@@ -2106,11 +1982,9 @@ static unsigned int dev_poll(struct file *file, poll_table *wait)
if (mutex_lock_interruptible(&gspca_dev->queue_lock) != 0)
return POLLERR;
- /* check the next incoming buffer */
- i = gspca_dev->fr_o;
- i = gspca_dev->fr_queue[i];
- if (gspca_dev->frame[i].v4l2_buf.flags & V4L2_BUF_FLAG_DONE)
- ret = POLLIN | POLLRDNORM; /* something to read */
+ /* check if an image has been received */
+ if (gspca_dev->fr_o != atomic_read(&gspca_dev->fr_i))
+ ret = POLLIN | POLLRDNORM; /* yes */
else
ret = 0;
mutex_unlock(&gspca_dev->queue_lock);
@@ -2214,9 +2088,6 @@ static const struct v4l2_ioctl_ops dev_ioctl_ops = {
.vidioc_queryctrl = vidioc_queryctrl,
.vidioc_g_ctrl = vidioc_g_ctrl,
.vidioc_s_ctrl = vidioc_s_ctrl,
- .vidioc_g_audio = vidioc_g_audio,
- .vidioc_s_audio = vidioc_s_audio,
- .vidioc_enumaudio = vidioc_enumaudio,
.vidioc_querymenu = vidioc_querymenu,
.vidioc_enum_input = vidioc_enum_input,
.vidioc_g_input = vidioc_g_input,
@@ -2235,9 +2106,6 @@ static const struct v4l2_ioctl_ops dev_ioctl_ops = {
.vidioc_s_register = vidioc_s_register,
#endif
.vidioc_g_chip_ident = vidioc_g_chip_ident,
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
- .vidiocgmbuf = vidiocgmbuf,
-#endif
};
static struct video_device gspca_template = {
@@ -2253,31 +2121,18 @@ static struct video_device gspca_template = {
* This function must be called by the sub-driver when it is
* called for probing a new device.
*/
-int gspca_dev_probe(struct usb_interface *intf,
+int gspca_dev_probe2(struct usb_interface *intf,
const struct usb_device_id *id,
const struct sd_desc *sd_desc,
int dev_size,
struct module *module)
{
- struct usb_interface_descriptor *interface;
struct gspca_dev *gspca_dev;
struct usb_device *dev = interface_to_usbdev(intf);
int ret;
PDEBUG(D_PROBE, "probing %04x:%04x", id->idVendor, id->idProduct);
- /* we don't handle multi-config cameras */
- if (dev->descriptor.bNumConfigurations != 1) {
- PDEBUG(D_ERR, "Too many config");
- return -ENODEV;
- }
-
- /* the USB video interface must be the first one */
- interface = &intf->cur_altsetting->desc;
- if (dev->config->desc.bNumInterfaces != 1 &&
- interface->bInterfaceNumber != 0)
- return -ENODEV;
-
/* create the device */
if (dev_size < sizeof *gspca_dev)
dev_size = sizeof *gspca_dev;
@@ -2293,8 +2148,26 @@ int gspca_dev_probe(struct usb_interface *intf,
goto out;
}
gspca_dev->dev = dev;
- gspca_dev->iface = interface->bInterfaceNumber;
+ gspca_dev->iface = intf->cur_altsetting->desc.bInterfaceNumber;
gspca_dev->nbalt = intf->num_altsetting;
+
+ /* check if any audio device */
+ if (dev->config->desc.bNumInterfaces != 1) {
+ int i;
+ struct usb_interface *intf2;
+
+ for (i = 0; i < dev->config->desc.bNumInterfaces; i++) {
+ intf2 = dev->config->interface[i];
+ if (intf2 != NULL
+ && intf2->altsetting != NULL
+ && intf2->altsetting->desc.bInterfaceClass ==
+ USB_CLASS_AUDIO) {
+ gspca_dev->audio = 1;
+ break;
+ }
+ }
+ }
+
gspca_dev->sd_desc = sd_desc;
gspca_dev->nbufread = 2;
gspca_dev->empty_packet = -1; /* don't check the empty packets */
@@ -2345,6 +2218,31 @@ out:
kfree(gspca_dev);
return ret;
}
+EXPORT_SYMBOL(gspca_dev_probe2);
+
+/* same function as the previous one, but check the interface */
+int gspca_dev_probe(struct usb_interface *intf,
+ const struct usb_device_id *id,
+ const struct sd_desc *sd_desc,
+ int dev_size,
+ struct module *module)
+{
+ struct usb_device *dev = interface_to_usbdev(intf);
+
+ /* we don't handle multi-config cameras */
+ if (dev->descriptor.bNumConfigurations != 1) {
+ PDEBUG(D_ERR, "%04x:%04x too many config",
+ id->idVendor, id->idProduct);
+ return -ENODEV;
+ }
+
+ /* the USB video interface must be the first one */
+ if (dev->config->desc.bNumInterfaces != 1
+ && intf->cur_altsetting->desc.bInterfaceNumber != 0)
+ return -ENODEV;
+
+ return gspca_dev_probe2(intf, id, sd_desc, dev_size, module);
+}
EXPORT_SYMBOL(gspca_dev_probe);
/*
diff --git a/drivers/media/video/gspca/gspca.h b/drivers/media/video/gspca/gspca.h
index 8b963dfae86..b749c36d9f7 100644
--- a/drivers/media/video/gspca/gspca.h
+++ b/drivers/media/video/gspca/gspca.h
@@ -7,7 +7,6 @@
#include <linux/videodev2.h>
#include <media/v4l2-common.h>
#include <linux/mutex.h>
-#include <linux/slab.h>
/* compilation option */
#define GSPCA_DEBUG 1
@@ -148,7 +147,6 @@ enum gspca_packet_type {
struct gspca_frame {
__u8 *data; /* frame buffer */
- __u8 *data_end; /* end of frame while filling */
int vma_use_count;
struct v4l2_buffer v4l2_buf;
};
@@ -177,13 +175,14 @@ struct gspca_dev {
__u8 *frbuf; /* buffer for nframes */
struct gspca_frame frame[GSPCA_MAX_FRAMES];
- struct gspca_frame *cur_frame; /* frame beeing filled */
+ u8 *image; /* image beeing filled */
__u32 frsz; /* frame size */
- char nframes; /* number of frames */
- char fr_i; /* frame being filled */
- char fr_q; /* next frame to queue */
- char fr_o; /* next frame to dequeue */
+ u32 image_len; /* current length of image */
+ atomic_t fr_q; /* next frame to queue */
+ atomic_t fr_i; /* frame being filled */
signed char fr_queue[GSPCA_MAX_FRAMES]; /* frame queue */
+ char nframes; /* number of frames */
+ u8 fr_o; /* next frame to dequeue */
__u8 last_packet_type;
__s8 empty_packet; /* if (-1) don't check empty packets */
__u8 streaming;
@@ -199,6 +198,7 @@ struct gspca_dev {
struct mutex read_lock; /* read protection */
struct mutex queue_lock; /* ISOC queue protection */
int usb_err; /* USB error - protected by usb_lock */
+ u16 pkt_size; /* ISOC packet size */
#ifdef CONFIG_PM
char frozen; /* suspend - resume */
#endif
@@ -209,7 +209,7 @@ struct gspca_dev {
__u8 iface; /* USB interface number */
__u8 alt; /* USB alternate setting */
__u8 nbalt; /* number of USB alternate settings */
- u16 pkt_size; /* ISOC packet size */
+ u8 audio; /* presence of audio device */
};
int gspca_dev_probe(struct usb_interface *intf,
@@ -217,12 +217,16 @@ int gspca_dev_probe(struct usb_interface *intf,
const struct sd_desc *sd_desc,
int dev_size,
struct module *module);
+int gspca_dev_probe2(struct usb_interface *intf,
+ const struct usb_device_id *id,
+ const struct sd_desc *sd_desc,
+ int dev_size,
+ struct module *module);
void gspca_disconnect(struct usb_interface *intf);
void gspca_frame_add(struct gspca_dev *gspca_dev,
enum gspca_packet_type packet_type,
const u8 *data,
int len);
-struct gspca_frame *gspca_get_i_frame(struct gspca_dev *gspca_dev);
#ifdef CONFIG_PM
int gspca_suspend(struct usb_interface *intf, pm_message_t message);
int gspca_resume(struct usb_interface *intf);
diff --git a/drivers/media/video/gspca/jeilinj.c b/drivers/media/video/gspca/jeilinj.c
index 84ecd56c647..12d9cf4caba 100644
--- a/drivers/media/video/gspca/jeilinj.c
+++ b/drivers/media/video/gspca/jeilinj.c
@@ -50,7 +50,7 @@ struct sd {
struct workqueue_struct *work_thread;
u8 quality; /* image quality */
u8 jpegqual; /* webcam quality */
- u8 *jpeg_hdr;
+ u8 jpeg_hdr[JPEG_HDR_SZ];
};
struct jlj_command {
@@ -282,7 +282,6 @@ static void sd_stop0(struct gspca_dev *gspca_dev)
destroy_workqueue(dev->work_thread);
dev->work_thread = NULL;
mutex_lock(&gspca_dev->usb_lock);
- kfree(dev->jpeg_hdr);
}
/* this function is called at probe and resume time */
@@ -298,9 +297,6 @@ static int sd_start(struct gspca_dev *gspca_dev)
int ret;
/* create the JPEG header */
- dev->jpeg_hdr = kmalloc(JPEG_HDR_SZ, GFP_KERNEL);
- if (dev->jpeg_hdr == NULL)
- return -ENOMEM;
jpeg_define(dev->jpeg_hdr, gspca_dev->height, gspca_dev->width,
0x21); /* JPEG 422 */
jpeg_set_qual(dev->jpeg_hdr, dev->quality);
diff --git a/drivers/media/video/gspca/m5602/m5602_bridge.h b/drivers/media/video/gspca/m5602/m5602_bridge.h
index 1127a405c9b..51af3ee3ab8 100644
--- a/drivers/media/video/gspca/m5602/m5602_bridge.h
+++ b/drivers/media/video/gspca/m5602/m5602_bridge.h
@@ -19,6 +19,7 @@
#ifndef M5602_BRIDGE_H_
#define M5602_BRIDGE_H_
+#include <linux/slab.h>
#include "gspca.h"
#define MODULE_NAME "ALi m5602"
diff --git a/drivers/media/video/gspca/m5602/m5602_core.c b/drivers/media/video/gspca/m5602/m5602_core.c
index 4294c75e3b1..b073d66acd0 100644
--- a/drivers/media/video/gspca/m5602/m5602_core.c
+++ b/drivers/media/video/gspca/m5602/m5602_core.c
@@ -305,30 +305,23 @@ static void m5602_urb_complete(struct gspca_dev *gspca_dev,
sd->frame_count);
} else {
- struct gspca_frame *frame;
int cur_frame_len;
- frame = gspca_get_i_frame(gspca_dev);
- if (frame == NULL) {
- gspca_dev->last_packet_type = DISCARD_PACKET;
- return;
- }
-
- cur_frame_len = frame->data_end - frame->data;
+ cur_frame_len = gspca_dev->image_len;
/* Remove urb header */
data += 4;
len -= 4;
- if (cur_frame_len + len <= frame->v4l2_buf.length) {
+ if (cur_frame_len + len <= gspca_dev->frsz) {
PDEBUG(D_FRAM, "Continuing frame %d copying %d bytes",
sd->frame_count, len);
gspca_frame_add(gspca_dev, INTER_PACKET,
data, len);
- } else if (frame->v4l2_buf.length - cur_frame_len > 0) {
+ } else {
/* Add the remaining data up to frame size */
gspca_frame_add(gspca_dev, INTER_PACKET, data,
- frame->v4l2_buf.length - cur_frame_len);
+ gspca_dev->frsz - cur_frame_len);
}
}
}
diff --git a/drivers/media/video/gspca/m5602/m5602_s5k83a.c b/drivers/media/video/gspca/m5602/m5602_s5k83a.c
index 6b3be4fa2c0..fbd91545497 100644
--- a/drivers/media/video/gspca/m5602/m5602_s5k83a.c
+++ b/drivers/media/video/gspca/m5602/m5602_s5k83a.c
@@ -17,7 +17,6 @@
*/
#include <linux/kthread.h>
-#include <linux/slab.h>
#include "m5602_s5k83a.h"
static int s5k83a_set_gain(struct gspca_dev *gspca_dev, __s32 val);
diff --git a/drivers/media/video/gspca/mars.c b/drivers/media/video/gspca/mars.c
index 3d9229e22b2..031f7195ce0 100644
--- a/drivers/media/video/gspca/mars.c
+++ b/drivers/media/video/gspca/mars.c
@@ -41,7 +41,7 @@ struct sd {
#define QUALITY_MAX 70
#define QUALITY_DEF 50
- u8 *jpeg_hdr;
+ u8 jpeg_hdr[JPEG_HDR_SZ];
};
/* V4L2 controls supported by the driver */
@@ -200,9 +200,6 @@ static int sd_start(struct gspca_dev *gspca_dev)
int i;
/* create the JPEG header */
- sd->jpeg_hdr = kmalloc(JPEG_HDR_SZ, GFP_KERNEL);
- if (!sd->jpeg_hdr)
- return -ENOMEM;
jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width,
0x21); /* JPEG 422 */
jpeg_set_qual(sd->jpeg_hdr, sd->quality);
@@ -317,13 +314,6 @@ static void sd_stopN(struct gspca_dev *gspca_dev)
PDEBUG(D_ERR, "Camera Stop failed");
}
-static void sd_stop0(struct gspca_dev *gspca_dev)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- kfree(sd->jpeg_hdr);
-}
-
static void sd_pkt_scan(struct gspca_dev *gspca_dev,
u8 *data, /* isoc packet */
int len) /* iso packet length */
@@ -486,7 +476,6 @@ static const struct sd_desc sd_desc = {
.init = sd_init,
.start = sd_start,
.stopN = sd_stopN,
- .stop0 = sd_stop0,
.pkt_scan = sd_pkt_scan,
.get_jcomp = sd_get_jcomp,
.set_jcomp = sd_set_jcomp,
diff --git a/drivers/media/video/gspca/ov519.c b/drivers/media/video/gspca/ov519.c
index f36e11a0458..2b2cbdbf03f 100644
--- a/drivers/media/video/gspca/ov519.c
+++ b/drivers/media/video/gspca/ov519.c
@@ -41,6 +41,11 @@
#include <linux/input.h>
#include "gspca.h"
+/* The jpeg_hdr is used by w996Xcf only */
+/* The CONEX_CAM define for jpeg.h needs renaming, now its used here too */
+#define CONEX_CAM
+#include "jpeg.h"
+
MODULE_AUTHOR("Jean-Francois Moine <http://moinejf.free.fr>");
MODULE_DESCRIPTION("OV519 USB Camera Driver");
MODULE_LICENSE("GPL");
@@ -90,6 +95,7 @@ struct sd {
#define QUALITY_DEF 50
__u8 stopped; /* Streaming is temporarily paused */
+ __u8 first_frame;
__u8 frame_rate; /* current Framerate */
__u8 clockdiv; /* clockdiv override */
@@ -115,7 +121,7 @@ struct sd {
int sensor_height;
int sensor_reg_cache[256];
- u8 *jpeg_hdr;
+ u8 jpeg_hdr[JPEG_HDR_SZ];
};
/* Note this is a bit of a hack, but the w9968cf driver needs the code for all
@@ -3147,7 +3153,7 @@ static int sd_config(struct gspca_dev *gspca_dev,
sd->autobrightness = AUTOBRIGHT_DEF;
if (sd->sensor == SEN_OV7670) {
sd->freq = OV7670_FREQ_DEF;
- gspca_dev->ctrl_dis = 1 << FREQ_IDX;
+ gspca_dev->ctrl_dis = (1 << FREQ_IDX) | (1 << COLOR_IDX);
} else {
sd->freq = FREQ_DEF;
gspca_dev->ctrl_dis = (1 << HFLIP_IDX) | (1 << VFLIP_IDX) |
@@ -3961,6 +3967,8 @@ static int sd_start(struct gspca_dev *gspca_dev)
sd_reset_snapshot(gspca_dev);
sd->snapshot_pressed = 0;
+ sd->first_frame = 3;
+
ret = ov51x_restart(sd);
if (ret < 0)
goto out;
@@ -4153,13 +4161,23 @@ static void ovfx2_pkt_scan(struct gspca_dev *gspca_dev,
u8 *data, /* isoc packet */
int len) /* iso packet length */
{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
+
/* A short read signals EOF */
if (len < OVFX2_BULK_SIZE) {
- gspca_frame_add(gspca_dev, LAST_PACKET, data, len);
+ /* If the frame is short, and it is one of the first ones
+ the sensor and bridge are still syncing, so drop it. */
+ if (sd->first_frame) {
+ sd->first_frame--;
+ if (gspca_dev->image_len <
+ sd->gspca_dev.width * sd->gspca_dev.height)
+ gspca_dev->last_packet_type = DISCARD_PACKET;
+ }
+ gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0);
gspca_frame_add(gspca_dev, FIRST_PACKET, NULL, 0);
- return;
}
- gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
}
static void sd_pkt_scan(struct gspca_dev *gspca_dev,
diff --git a/drivers/media/video/gspca/ov534.c b/drivers/media/video/gspca/ov534.c
index dc1e4efe30f..96cb3a97658 100644
--- a/drivers/media/video/gspca/ov534.c
+++ b/drivers/media/video/gspca/ov534.c
@@ -987,13 +987,8 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
data + 12, len - 12);
/* If this packet is marked as EOF, end the frame */
} else if (data[1] & UVC_STREAM_EOF) {
- struct gspca_frame *frame;
-
sd->last_pts = 0;
- frame = gspca_get_i_frame(gspca_dev);
- if (frame == NULL)
- goto discard;
- if (frame->data_end - frame->data + (len - 12) !=
+ if (gspca_dev->image_len + len - 12 !=
gspca_dev->width * gspca_dev->height * 2) {
PDEBUG(D_PACK, "wrong sized frame");
goto discard;
diff --git a/drivers/media/video/gspca/pac7302.c b/drivers/media/video/gspca/pac7302.c
index 2a68220d1ad..a66df07d762 100644
--- a/drivers/media/video/gspca/pac7302.c
+++ b/drivers/media/video/gspca/pac7302.c
@@ -402,7 +402,7 @@ static void reg_w_buf(struct gspca_dev *gspca_dev,
memcpy(gspca_dev->usb_buf, buffer, len);
ret = usb_control_msg(gspca_dev->dev,
usb_sndctrlpipe(gspca_dev->dev, 0),
- 1, /* request */
+ 0, /* request */
USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
0, /* value */
index, gspca_dev->usb_buf, len,
@@ -804,7 +804,6 @@ static const unsigned char pac_jpeg_header2[] = {
};
static void pac_start_frame(struct gspca_dev *gspca_dev,
- struct gspca_frame *frame,
__u16 lines, __u16 samples_per_line)
{
unsigned char tmpbuf[4];
@@ -829,19 +828,13 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
int len) /* iso packet length */
{
struct sd *sd = (struct sd *) gspca_dev;
- struct gspca_frame *frame;
+ u8 *image;
unsigned char *sof;
sof = pac_find_sof(&sd->sof_read, data, len);
if (sof) {
int n, lum_offset, footer_length;
- frame = gspca_get_i_frame(gspca_dev);
- if (frame == NULL) {
- gspca_dev->last_packet_type = DISCARD_PACKET;
- return;
- }
-
/* 6 bytes after the FF D9 EOF marker a number of lumination
bytes are send corresponding to different parts of the
image, the 14th and 15th byte after the EOF seem to
@@ -852,16 +845,17 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
/* Finish decoding current frame */
n = (sof - data) - (footer_length + sizeof pac_sof_marker);
if (n < 0) {
- frame->data_end += n;
+ gspca_dev->image_len += n;
n = 0;
+ } else {
+ gspca_frame_add(gspca_dev, INTER_PACKET, data, n);
}
- gspca_frame_add(gspca_dev, INTER_PACKET,
- data, n);
- if (gspca_dev->last_packet_type != DISCARD_PACKET &&
- frame->data_end[-2] == 0xff &&
- frame->data_end[-1] == 0xd9)
- gspca_frame_add(gspca_dev, LAST_PACKET,
- NULL, 0);
+
+ image = gspca_dev->image;
+ if (image != NULL
+ && image[gspca_dev->image_len - 2] == 0xff
+ && image[gspca_dev->image_len - 1] == 0xd9)
+ gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0);
n = sof - data;
len -= n;
@@ -877,7 +871,7 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
/* Start the new frame with the jpeg header */
/* The PAC7302 has the image rotated 90 degrees */
- pac_start_frame(gspca_dev, frame,
+ pac_start_frame(gspca_dev,
gspca_dev->width, gspca_dev->height);
}
gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
@@ -1200,6 +1194,7 @@ static const struct usb_device_id device_table[] __devinitconst = {
{USB_DEVICE(0x093a, 0x2621)},
{USB_DEVICE(0x093a, 0x2622), .driver_info = FL_VFLIP},
{USB_DEVICE(0x093a, 0x2624), .driver_info = FL_VFLIP},
+ {USB_DEVICE(0x093a, 0x2625)},
{USB_DEVICE(0x093a, 0x2626)},
{USB_DEVICE(0x093a, 0x2628)},
{USB_DEVICE(0x093a, 0x2629), .driver_info = FL_VFLIP},
diff --git a/drivers/media/video/gspca/pac7311.c b/drivers/media/video/gspca/pac7311.c
index 44fed968672..1cb7e99e92b 100644
--- a/drivers/media/video/gspca/pac7311.c
+++ b/drivers/media/video/gspca/pac7311.c
@@ -270,7 +270,7 @@ static void reg_w_buf(struct gspca_dev *gspca_dev,
memcpy(gspca_dev->usb_buf, buffer, len);
ret = usb_control_msg(gspca_dev->dev,
usb_sndctrlpipe(gspca_dev->dev, 0),
- 1, /* request */
+ 0, /* request */
USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
0, /* value */
index, gspca_dev->usb_buf, len,
@@ -599,7 +599,6 @@ static const unsigned char pac_jpeg_header2[] = {
};
static void pac_start_frame(struct gspca_dev *gspca_dev,
- struct gspca_frame *frame,
__u16 lines, __u16 samples_per_line)
{
unsigned char tmpbuf[4];
@@ -624,19 +623,13 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
int len) /* iso packet length */
{
struct sd *sd = (struct sd *) gspca_dev;
+ u8 *image;
unsigned char *sof;
- struct gspca_frame *frame;
sof = pac_find_sof(&sd->sof_read, data, len);
if (sof) {
int n, lum_offset, footer_length;
- frame = gspca_get_i_frame(gspca_dev);
- if (frame == NULL) {
- gspca_dev->last_packet_type = DISCARD_PACKET;
- return;
- }
-
/* 6 bytes after the FF D9 EOF marker a number of lumination
bytes are send corresponding to different parts of the
image, the 14th and 15th byte after the EOF seem to
@@ -647,16 +640,16 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
/* Finish decoding current frame */
n = (sof - data) - (footer_length + sizeof pac_sof_marker);
if (n < 0) {
- frame->data_end += n;
+ gspca_dev->image_len += n;
n = 0;
+ } else {
+ gspca_frame_add(gspca_dev, INTER_PACKET, data, n);
}
- gspca_frame_add(gspca_dev, INTER_PACKET,
- data, n);
- if (gspca_dev->last_packet_type != DISCARD_PACKET &&
- frame->data_end[-2] == 0xff &&
- frame->data_end[-1] == 0xd9)
- gspca_frame_add(gspca_dev, LAST_PACKET,
- NULL, 0);
+ image = gspca_dev->image;
+ if (image != NULL
+ && image[gspca_dev->image_len - 2] == 0xff
+ && image[gspca_dev->image_len - 1] == 0xd9)
+ gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0);
n = sof - data;
len -= n;
@@ -671,7 +664,7 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
atomic_set(&sd->avg_lum, -1);
/* Start the new frame with the jpeg header */
- pac_start_frame(gspca_dev, frame,
+ pac_start_frame(gspca_dev,
gspca_dev->height, gspca_dev->width);
}
gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
diff --git a/drivers/media/video/gspca/sn9c20x.c b/drivers/media/video/gspca/sn9c20x.c
index 644a7fd4701..83a718f0f3f 100644
--- a/drivers/media/video/gspca/sn9c20x.c
+++ b/drivers/media/video/gspca/sn9c20x.c
@@ -20,7 +20,6 @@
#ifdef CONFIG_INPUT
#include <linux/input.h>
-#include <linux/slab.h>
#endif
#include "gspca.h"
@@ -89,7 +88,7 @@ struct sd {
u8 hstart;
u8 vstart;
- u8 *jpeg_hdr;
+ u8 jpeg_hdr[JPEG_HDR_SZ];
u8 quality;
u8 flags;
@@ -2162,10 +2161,6 @@ static int sd_start(struct gspca_dev *gspca_dev)
int height = gspca_dev->height;
u8 fmt, scale = 0;
- sd->jpeg_hdr = kmalloc(JPEG_HDR_SZ, GFP_KERNEL);
- if (sd->jpeg_hdr == NULL)
- return -ENOMEM;
-
jpeg_define(sd->jpeg_hdr, height, width,
0x21);
jpeg_set_qual(sd->jpeg_hdr, sd->quality);
@@ -2197,8 +2192,8 @@ static int sd_start(struct gspca_dev *gspca_dev)
}
configure_sensor_output(gspca_dev, mode);
- reg_w(gspca_dev, 0x1100, sd->jpeg_hdr + JPEG_QT0_OFFSET, 64);
- reg_w(gspca_dev, 0x1140, sd->jpeg_hdr + JPEG_QT1_OFFSET, 64);
+ reg_w(gspca_dev, 0x1100, &sd->jpeg_hdr[JPEG_QT0_OFFSET], 64);
+ reg_w(gspca_dev, 0x1140, &sd->jpeg_hdr[JPEG_QT1_OFFSET], 64);
reg_w(gspca_dev, 0x10fb, CLR_WIN(width, height), 5);
reg_w(gspca_dev, 0x1180, HW_WIN(mode, sd->hstart, sd->vstart), 6);
reg_w1(gspca_dev, 0x1189, scale);
@@ -2226,12 +2221,6 @@ static void sd_stopN(struct gspca_dev *gspca_dev)
reg_w1(gspca_dev, 0x1061, gspca_dev->usb_buf[0] & ~0x02);
}
-static void sd_stop0(struct gspca_dev *gspca_dev)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- kfree(sd->jpeg_hdr);
-}
-
static void do_autoexposure(struct gspca_dev *gspca_dev, u16 avg_lum)
{
struct sd *sd = (struct sd *) gspca_dev;
@@ -2397,7 +2386,6 @@ static const struct sd_desc sd_desc = {
.init = sd_init,
.start = sd_start,
.stopN = sd_stopN,
- .stop0 = sd_stop0,
.pkt_scan = sd_pkt_scan,
#ifdef CONFIG_INPUT
.int_pkt_scan = sd_int_pkt_scan,
diff --git a/drivers/media/video/gspca/sonixb.c b/drivers/media/video/gspca/sonixb.c
index 95354a339e3..204bb3af455 100644
--- a/drivers/media/video/gspca/sonixb.c
+++ b/drivers/media/video/gspca/sonixb.c
@@ -1251,16 +1251,10 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
if (cam->cam_mode[gspca_dev->curr_mode].priv & MODE_RAW) {
/* In raw mode we sometimes get some garbage after the frame
ignore this */
- struct gspca_frame *frame;
int used;
int size = cam->cam_mode[gspca_dev->curr_mode].sizeimage;
- frame = gspca_get_i_frame(gspca_dev);
- if (frame == NULL) {
- gspca_dev->last_packet_type = DISCARD_PACKET;
- return;
- }
- used = frame->data_end - frame->data;
+ used = gspca_dev->image_len;
if (used + len > size)
len = size - used;
}
diff --git a/drivers/media/video/gspca/sonixj.c b/drivers/media/video/gspca/sonixj.c
index 176c5b3d5e6..ee17b034bf6 100644
--- a/drivers/media/video/gspca/sonixj.c
+++ b/drivers/media/video/gspca/sonixj.c
@@ -22,7 +22,6 @@
#define MODULE_NAME "sonixj"
#include <linux/input.h>
-#include <linux/slab.h>
#include "gspca.h"
#include "jpeg.h"
@@ -392,7 +391,7 @@ static const u8 sn_gc0307[0x1c] = {
static const u8 sn_hv7131[0x1c] = {
/* reg0 reg1 reg2 reg3 reg4 reg5 reg6 reg7 */
- 0x00, 0x03, 0x64, 0x00, 0x1a, 0x20, 0x20, 0x20,
+ 0x00, 0x03, 0x60, 0x00, 0x1a, 0x20, 0x20, 0x20,
/* reg8 reg9 rega regb regc regd rege regf */
0x81, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* reg10 reg11 reg12 reg13 reg14 reg15 reg16 reg17 */
@@ -403,7 +402,7 @@ static const u8 sn_hv7131[0x1c] = {
static const u8 sn_mi0360[0x1c] = {
/* reg0 reg1 reg2 reg3 reg4 reg5 reg6 reg7 */
- 0x00, 0x61, 0x44, 0x00, 0x1a, 0x20, 0x20, 0x20,
+ 0x00, 0x61, 0x40, 0x00, 0x1a, 0x20, 0x20, 0x20,
/* reg8 reg9 rega regb regc regd rege regf */
0x81, 0x5d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* reg10 reg11 reg12 reg13 reg14 reg15 reg16 reg17 */
@@ -1644,6 +1643,7 @@ static void bridge_init(struct gspca_dev *gspca_dev,
const u8 *sn9c1xx)
{
struct sd *sd = (struct sd *) gspca_dev;
+ u8 reg0102[2];
const u8 *reg9a;
static const u8 reg9a_def[] =
{0x00, 0x40, 0x20, 0x00, 0x00, 0x00};
@@ -1656,7 +1656,11 @@ static void bridge_init(struct gspca_dev *gspca_dev,
reg_w1(gspca_dev, 0x01, sn9c1xx[1]);
/* configure gpio */
- reg_w(gspca_dev, 0x01, &sn9c1xx[1], 2);
+ reg0102[0] = sn9c1xx[1];
+ reg0102[1] = sn9c1xx[2];
+ if (gspca_dev->audio)
+ reg0102[1] |= 0x04; /* keep the audio connection */
+ reg_w(gspca_dev, 0x01, reg0102, 2);
reg_w(gspca_dev, 0x08, &sn9c1xx[8], 2);
reg_w(gspca_dev, 0x17, &sn9c1xx[0x17], 5);
switch (sd->sensor) {
@@ -1737,13 +1741,12 @@ static void bridge_init(struct gspca_dev *gspca_dev,
reg_w1(gspca_dev, 0x01, 0x40);
break;
case SENSOR_PO2030N:
+ case SENSOR_OV7660:
reg_w1(gspca_dev, 0x01, 0x63);
reg_w1(gspca_dev, 0x17, 0x20);
reg_w1(gspca_dev, 0x01, 0x62);
reg_w1(gspca_dev, 0x01, 0x42);
break;
- case SENSOR_OV7660:
- /* fall thru */
case SENSOR_SP80708:
reg_w1(gspca_dev, 0x01, 0x63);
reg_w1(gspca_dev, 0x17, 0x20);
@@ -1816,7 +1819,7 @@ static int sd_init(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
const u8 *sn9c1xx;
- u8 regGpio[] = { 0x29, 0x74 };
+ u8 regGpio[] = { 0x29, 0x74 }; /* with audio */
u8 regF1;
/* setup a selector by bridge */
@@ -1856,7 +1859,7 @@ static int sd_init(struct gspca_dev *gspca_dev)
po2030n_probe(gspca_dev);
break;
}
- regGpio[1] = 0x70;
+ regGpio[1] = 0x70; /* no audio */
reg_w(gspca_dev, 0x01, regGpio, 2);
break;
default:
@@ -2274,7 +2277,7 @@ static int sd_start(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
int i;
- u8 reg1, reg2, reg17;
+ u8 reg1, reg17;
const u8 *sn9c1xx;
const u8 (*init)[8];
int mode;
@@ -2304,23 +2307,6 @@ static int sd_start(struct gspca_dev *gspca_dev)
/* initialize the sensor */
i2c_w_seq(gspca_dev, sensor_init[sd->sensor]);
- switch (sd->sensor) {
- case SENSOR_ADCM1700:
- reg2 = 0x60;
- break;
- case SENSOR_OM6802:
- reg2 = 0x71;
- break;
- case SENSOR_SP80708:
- reg2 = 0x62;
- break;
- default:
- reg2 = 0x40;
- break;
- }
- reg_w1(gspca_dev, 0x02, reg2);
- reg_w1(gspca_dev, 0x02, reg2);
-
reg_w1(gspca_dev, 0x15, sn9c1xx[0x15]);
reg_w1(gspca_dev, 0x16, sn9c1xx[0x16]);
reg_w1(gspca_dev, 0x12, sn9c1xx[0x12]);
diff --git a/drivers/media/video/gspca/spca1528.c b/drivers/media/video/gspca/spca1528.c
new file mode 100644
index 00000000000..3f514eb1d99
--- /dev/null
+++ b/drivers/media/video/gspca/spca1528.c
@@ -0,0 +1,605 @@
+/*
+ * spca1528 subdriver
+ *
+ * Copyright (C) 2010 Jean-Francois Moine (http://moinejf.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
+ * 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 MODULE_NAME "spca1528"
+
+#include "gspca.h"
+#include "jpeg.h"
+
+MODULE_AUTHOR("Jean-Francois Moine <http://moinejf.free.fr>");
+MODULE_DESCRIPTION("SPCA1528 USB Camera Driver");
+MODULE_LICENSE("GPL");
+
+/* specific webcam descriptor */
+struct sd {
+ struct gspca_dev gspca_dev; /* !! must be the first item */
+
+ u8 brightness;
+ u8 contrast;
+ u8 hue;
+ u8 color;
+ u8 sharpness;
+
+ u8 pkt_seq;
+
+ u8 jpeg_hdr[JPEG_HDR_SZ];
+};
+
+/* V4L2 controls supported by the driver */
+static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_sethue(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_gethue(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setcolor(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getcolor(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setsharpness(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getsharpness(struct gspca_dev *gspca_dev, __s32 *val);
+
+static const struct ctrl sd_ctrls[] = {
+ {
+ {
+ .id = V4L2_CID_BRIGHTNESS,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Brightness",
+ .minimum = 0,
+ .maximum = 255,
+ .step = 1,
+#define BRIGHTNESS_DEF 128
+ .default_value = BRIGHTNESS_DEF,
+ },
+ .set = sd_setbrightness,
+ .get = sd_getbrightness,
+ },
+ {
+ {
+ .id = V4L2_CID_CONTRAST,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Contrast",
+ .minimum = 0,
+ .maximum = 8,
+ .step = 1,
+#define CONTRAST_DEF 1
+ .default_value = CONTRAST_DEF,
+ },
+ .set = sd_setcontrast,
+ .get = sd_getcontrast,
+ },
+ {
+ {
+ .id = V4L2_CID_HUE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Hue",
+ .minimum = 0,
+ .maximum = 255,
+ .step = 1,
+#define HUE_DEF 0
+ .default_value = HUE_DEF,
+ },
+ .set = sd_sethue,
+ .get = sd_gethue,
+ },
+ {
+ {
+ .id = V4L2_CID_SATURATION,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Saturation",
+ .minimum = 0,
+ .maximum = 8,
+ .step = 1,
+#define COLOR_DEF 1
+ .default_value = COLOR_DEF,
+ },
+ .set = sd_setcolor,
+ .get = sd_getcolor,
+ },
+ {
+ {
+ .id = V4L2_CID_SHARPNESS,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Sharpness",
+ .minimum = 0,
+ .maximum = 255,
+ .step = 1,
+#define SHARPNESS_DEF 0
+ .default_value = SHARPNESS_DEF,
+ },
+ .set = sd_setsharpness,
+ .get = sd_getsharpness,
+ },
+};
+
+static const struct v4l2_pix_format vga_mode[] = {
+/* (does not work correctly)
+ {176, 144, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+ .bytesperline = 176,
+ .sizeimage = 176 * 144 * 5 / 8 + 590,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ .priv = 3},
+*/
+ {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+ .bytesperline = 320,
+ .sizeimage = 320 * 240 * 4 / 8 + 590,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ .priv = 2},
+ {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+ .bytesperline = 640,
+ .sizeimage = 640 * 480 * 3 / 8 + 590,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ .priv = 1},
+};
+
+/* read <len> bytes to gspca usb_buf */
+static void reg_r(struct gspca_dev *gspca_dev,
+ u8 req,
+ u16 index,
+ int len)
+{
+#if USB_BUF_SZ < 64
+#error "USB buffer too small"
+#endif
+ struct usb_device *dev = gspca_dev->dev;
+ int ret;
+
+ if (gspca_dev->usb_err < 0)
+ return;
+ ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
+ req,
+ USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ 0x0000, /* value */
+ index,
+ gspca_dev->usb_buf, len,
+ 500);
+ PDEBUG(D_USBI, "GET %02x 0000 %04x %02x", req, index,
+ gspca_dev->usb_buf[0]);
+ if (ret < 0) {
+ PDEBUG(D_ERR, "reg_r err %d", ret);
+ gspca_dev->usb_err = ret;
+ }
+}
+
+static void reg_w(struct gspca_dev *gspca_dev,
+ u8 req,
+ u16 value,
+ u16 index)
+{
+ struct usb_device *dev = gspca_dev->dev;
+ int ret;
+
+ if (gspca_dev->usb_err < 0)
+ return;
+ PDEBUG(D_USBO, "SET %02x %04x %04x", req, value, index);
+ ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+ req,
+ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ value, index,
+ NULL, 0, 500);
+ if (ret < 0) {
+ PDEBUG(D_ERR, "reg_w err %d", ret);
+ gspca_dev->usb_err = ret;
+ }
+}
+
+static void reg_wb(struct gspca_dev *gspca_dev,
+ u8 req,
+ u16 value,
+ u16 index,
+ u8 byte)
+{
+ struct usb_device *dev = gspca_dev->dev;
+ int ret;
+
+ if (gspca_dev->usb_err < 0)
+ return;
+ PDEBUG(D_USBO, "SET %02x %04x %04x %02x", req, value, index, byte);
+ gspca_dev->usb_buf[0] = byte;
+ ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+ req,
+ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ value, index,
+ gspca_dev->usb_buf, 1, 500);
+ if (ret < 0) {
+ PDEBUG(D_ERR, "reg_w err %d", ret);
+ gspca_dev->usb_err = ret;
+ }
+}
+
+static void wait_status_0(struct gspca_dev *gspca_dev)
+{
+ int i;
+
+ i = 20;
+ do {
+ reg_r(gspca_dev, 0x21, 0x0000, 1);
+ if (gspca_dev->usb_buf[0] == 0)
+ return;
+ msleep(30);
+ } while (--i > 0);
+ PDEBUG(D_ERR, "wait_status_0 timeout");
+ gspca_dev->usb_err = -ETIME;
+}
+
+static void wait_status_1(struct gspca_dev *gspca_dev)
+{
+ int i;
+
+ i = 10;
+ do {
+ reg_r(gspca_dev, 0x21, 0x0001, 1);
+ msleep(10);
+ if (gspca_dev->usb_buf[0] == 1) {
+ reg_wb(gspca_dev, 0x21, 0x0000, 0x0001, 0x00);
+ reg_r(gspca_dev, 0x21, 0x0001, 1);
+ return;
+ }
+ } while (--i > 0);
+ PDEBUG(D_ERR, "wait_status_1 timeout");
+ gspca_dev->usb_err = -ETIME;
+}
+
+static void setbrightness(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ reg_wb(gspca_dev, 0xc0, 0x0000, 0x00c0, sd->brightness);
+}
+
+static void setcontrast(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ reg_wb(gspca_dev, 0xc1, 0x0000, 0x00c1, sd->contrast);
+}
+
+static void sethue(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ reg_wb(gspca_dev, 0xc2, 0x0000, 0x0000, sd->hue);
+}
+
+static void setcolor(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ reg_wb(gspca_dev, 0xc3, 0x0000, 0x00c3, sd->color);
+}
+
+static void setsharpness(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ reg_wb(gspca_dev, 0xc4, 0x0000, 0x00c4, sd->sharpness);
+}
+
+/* this function is called at probe time */
+static int sd_config(struct gspca_dev *gspca_dev,
+ const struct usb_device_id *id)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ gspca_dev->cam.cam_mode = vga_mode;
+ gspca_dev->cam.nmodes = ARRAY_SIZE(vga_mode);
+ gspca_dev->cam.npkt = 128; /* number of packets per ISOC message */
+ /*fixme: 256 in ms-win traces*/
+
+ sd->brightness = BRIGHTNESS_DEF;
+ sd->contrast = CONTRAST_DEF;
+ sd->hue = HUE_DEF;
+ sd->color = COLOR_DEF;
+ sd->sharpness = SHARPNESS_DEF;
+
+ gspca_dev->nbalt = 4; /* use alternate setting 3 */
+
+ return 0;
+}
+
+/* this function is called at probe and resume time */
+static int sd_init(struct gspca_dev *gspca_dev)
+{
+ reg_w(gspca_dev, 0x00, 0x0001, 0x2067);
+ reg_w(gspca_dev, 0x00, 0x00d0, 0x206b);
+ reg_w(gspca_dev, 0x00, 0x0000, 0x206c);
+ reg_w(gspca_dev, 0x00, 0x0001, 0x2069);
+ msleep(8);
+ reg_w(gspca_dev, 0x00, 0x00c0, 0x206b);
+ reg_w(gspca_dev, 0x00, 0x0000, 0x206c);
+ reg_w(gspca_dev, 0x00, 0x0001, 0x2069);
+
+ reg_r(gspca_dev, 0x20, 0x0000, 1);
+ reg_r(gspca_dev, 0x20, 0x0000, 5);
+ reg_r(gspca_dev, 0x23, 0x0000, 64);
+ PDEBUG(D_PROBE, "%s%s", &gspca_dev->usb_buf[0x1c],
+ &gspca_dev->usb_buf[0x30]);
+ reg_r(gspca_dev, 0x23, 0x0001, 64);
+ return gspca_dev->usb_err;
+}
+
+/* function called at start time before URB creation */
+static int sd_isoc_init(struct gspca_dev *gspca_dev)
+{
+ u8 mode;
+
+ reg_r(gspca_dev, 0x00, 0x2520, 1);
+ wait_status_0(gspca_dev);
+ reg_w(gspca_dev, 0xc5, 0x0003, 0x0000);
+ wait_status_1(gspca_dev);
+
+ wait_status_0(gspca_dev);
+ mode = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv;
+ reg_wb(gspca_dev, 0x25, 0x0000, 0x0004, mode);
+ reg_r(gspca_dev, 0x25, 0x0004, 1);
+ reg_wb(gspca_dev, 0x27, 0x0000, 0x0000, 0x06);
+ reg_r(gspca_dev, 0x27, 0x0000, 1);
+ return gspca_dev->usb_err;
+}
+
+/* -- start the camera -- */
+static int sd_start(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ /* initialize the JPEG header */
+ jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width,
+ 0x22); /* JPEG 411 */
+
+ /* the JPEG quality seems to be 82% */
+ jpeg_set_qual(sd->jpeg_hdr, 82);
+
+ /* set the controls */
+ setbrightness(gspca_dev);
+ setcontrast(gspca_dev);
+ sethue(gspca_dev);
+ setcolor(gspca_dev);
+ setsharpness(gspca_dev);
+
+ msleep(5);
+ reg_r(gspca_dev, 0x00, 0x2520, 1);
+ msleep(8);
+
+ /* start the capture */
+ wait_status_0(gspca_dev);
+ reg_w(gspca_dev, 0x31, 0x0000, 0x0004);
+ wait_status_1(gspca_dev);
+ wait_status_0(gspca_dev);
+ msleep(200);
+
+ sd->pkt_seq = 0;
+ return gspca_dev->usb_err;
+}
+
+static void sd_stopN(struct gspca_dev *gspca_dev)
+{
+ /* stop the capture */
+ wait_status_0(gspca_dev);
+ reg_w(gspca_dev, 0x31, 0x0000, 0x0000);
+ wait_status_1(gspca_dev);
+ wait_status_0(gspca_dev);
+}
+
+/* move a packet adding 0x00 after 0xff */
+static void add_packet(struct gspca_dev *gspca_dev,
+ u8 *data,
+ int len)
+{
+ int i;
+
+ i = 0;
+ do {
+ if (data[i] == 0xff) {
+ gspca_frame_add(gspca_dev, INTER_PACKET,
+ data, i + 1);
+ len -= i;
+ data += i;
+ *data = 0x00;
+ i = 0;
+ }
+ } while (++i < len);
+ gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
+}
+
+static void sd_pkt_scan(struct gspca_dev *gspca_dev,
+ u8 *data, /* isoc packet */
+ int len) /* iso packet length */
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ static const u8 ffd9[] = {0xff, 0xd9};
+
+ /* image packets start with:
+ * 02 8n
+ * with <n> bit:
+ * 0x01: even (0) / odd (1) image
+ * 0x02: end of image when set
+ */
+ if (len < 3)
+ return; /* empty packet */
+ if (*data == 0x02) {
+ if (data[1] & 0x02) {
+ sd->pkt_seq = !(data[1] & 1);
+ add_packet(gspca_dev, data + 2, len - 2);
+ gspca_frame_add(gspca_dev, LAST_PACKET,
+ ffd9, 2);
+ return;
+ }
+ if ((data[1] & 1) != sd->pkt_seq)
+ goto err;
+ if (gspca_dev->last_packet_type == LAST_PACKET)
+ gspca_frame_add(gspca_dev, FIRST_PACKET,
+ sd->jpeg_hdr, JPEG_HDR_SZ);
+ add_packet(gspca_dev, data + 2, len - 2);
+ return;
+ }
+err:
+ gspca_dev->last_packet_type = DISCARD_PACKET;
+}
+
+static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->brightness = val;
+ if (gspca_dev->streaming)
+ setbrightness(gspca_dev);
+ return gspca_dev->usb_err;
+}
+
+static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ *val = sd->brightness;
+ return 0;
+}
+
+static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->contrast = val;
+ if (gspca_dev->streaming)
+ setcontrast(gspca_dev);
+ return gspca_dev->usb_err;
+}
+
+static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ *val = sd->contrast;
+ return 0;
+}
+
+static int sd_sethue(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->hue = val;
+ if (gspca_dev->streaming)
+ sethue(gspca_dev);
+ return gspca_dev->usb_err;
+}
+
+static int sd_gethue(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ *val = sd->hue;
+ return 0;
+}
+
+static int sd_setcolor(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->color = val;
+ if (gspca_dev->streaming)
+ setcolor(gspca_dev);
+ return gspca_dev->usb_err;
+}
+
+static int sd_getcolor(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ *val = sd->color;
+ return 0;
+}
+
+static int sd_setsharpness(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->sharpness = val;
+ if (gspca_dev->streaming)
+ setsharpness(gspca_dev);
+ return gspca_dev->usb_err;
+}
+
+static int sd_getsharpness(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ *val = sd->sharpness;
+ return 0;
+}
+
+/* sub-driver description */
+static const struct sd_desc sd_desc = {
+ .name = MODULE_NAME,
+ .ctrls = sd_ctrls,
+ .nctrls = ARRAY_SIZE(sd_ctrls),
+ .config = sd_config,
+ .init = sd_init,
+ .isoc_init = sd_isoc_init,
+ .start = sd_start,
+ .stopN = sd_stopN,
+ .pkt_scan = sd_pkt_scan,
+};
+
+/* -- module initialisation -- */
+static const __devinitdata struct usb_device_id device_table[] = {
+ {USB_DEVICE(0x04fc, 0x1528)},
+ {}
+};
+MODULE_DEVICE_TABLE(usb, device_table);
+
+/* -- device connect -- */
+static int sd_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+{
+ /* the video interface for isochronous transfer is 1 */
+ if (intf->cur_altsetting->desc.bInterfaceNumber != 1)
+ return -ENODEV;
+
+ return gspca_dev_probe2(intf, id, &sd_desc, sizeof(struct sd),
+ THIS_MODULE);
+}
+
+static struct usb_driver sd_driver = {
+ .name = MODULE_NAME,
+ .id_table = device_table,
+ .probe = sd_probe,
+ .disconnect = gspca_disconnect,
+#ifdef CONFIG_PM
+ .suspend = gspca_suspend,
+ .resume = gspca_resume,
+#endif
+};
+
+/* -- module insert / remove -- */
+static int __init sd_mod_init(void)
+{
+ int ret;
+
+ ret = usb_register(&sd_driver);
+ if (ret < 0)
+ return ret;
+ info("registered");
+ return 0;
+}
+static void __exit sd_mod_exit(void)
+{
+ usb_deregister(&sd_driver);
+ info("deregistered");
+}
+
+module_init(sd_mod_init);
+module_exit(sd_mod_exit);
diff --git a/drivers/media/video/gspca/spca500.c b/drivers/media/video/gspca/spca500.c
index b866c73c97d..c02beb6c1e9 100644
--- a/drivers/media/video/gspca/spca500.c
+++ b/drivers/media/video/gspca/spca500.c
@@ -57,7 +57,7 @@ struct sd {
#define PalmPixDC85 13
#define ToptroIndus 14
- u8 *jpeg_hdr;
+ u8 jpeg_hdr[JPEG_HDR_SZ];
};
/* V4L2 controls supported by the driver */
@@ -669,9 +669,6 @@ static int sd_start(struct gspca_dev *gspca_dev)
__u8 xmult, ymult;
/* create the JPEG header */
- sd->jpeg_hdr = kmalloc(JPEG_HDR_SZ, GFP_KERNEL);
- if (!sd->jpeg_hdr)
- return -ENOMEM;
jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width,
0x22); /* JPEG 411 */
jpeg_set_qual(sd->jpeg_hdr, sd->quality);
@@ -891,13 +888,6 @@ static void sd_stopN(struct gspca_dev *gspca_dev)
gspca_dev->usb_buf[0]);
}
-static void sd_stop0(struct gspca_dev *gspca_dev)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- kfree(sd->jpeg_hdr);
-}
-
static void sd_pkt_scan(struct gspca_dev *gspca_dev,
u8 *data, /* isoc packet */
int len) /* iso packet length */
@@ -1055,7 +1045,6 @@ static const struct sd_desc sd_desc = {
.init = sd_init,
.start = sd_start,
.stopN = sd_stopN,
- .stop0 = sd_stop0,
.pkt_scan = sd_pkt_scan,
.get_jcomp = sd_get_jcomp,
.set_jcomp = sd_set_jcomp,
diff --git a/drivers/media/video/gspca/sq930x.c b/drivers/media/video/gspca/sq930x.c
new file mode 100644
index 00000000000..37cee5e063c
--- /dev/null
+++ b/drivers/media/video/gspca/sq930x.c
@@ -0,0 +1,1402 @@
+/*
+ * SQ930x subdriver
+ *
+ * Copyright (C) 2010 Jean-François Moine <http://moinejf.free.fr>
+ * Copyright (C) 2006 -2008 Gerard Klaver <gerard at gkall dot hobby dot nl>
+ * Copyright (C) 2007 Sam Revitch <samr7@cs.washington.edu>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * 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 MODULE_NAME "sq930x"
+
+#include "gspca.h"
+#include "jpeg.h"
+
+MODULE_AUTHOR("Jean-Francois Moine <http://moinejf.free.fr>\n"
+ "Gerard Klaver <gerard at gkall dot hobby dot nl\n"
+ "Sam Revitch <samr7@cs.washington.edu>");
+MODULE_DESCRIPTION("GSPCA/SQ930x USB Camera Driver");
+MODULE_LICENSE("GPL");
+
+#define BULK_TRANSFER_LEN 5128
+
+/* Structure to hold all of our device specific stuff */
+struct sd {
+ struct gspca_dev gspca_dev; /* !! must be the first item */
+
+ u16 expo;
+ u8 gain;
+
+ u8 quality; /* webcam quality 0..3 */
+#define QUALITY_DEF 1
+
+ u8 gpio[2];
+
+ u8 eof_len;
+ u8 do_ctrl;
+
+ u8 sensor;
+enum {
+ SENSOR_ICX098BQ,
+ SENSOR_LZ24BP,
+ SENSOR_MI0360,
+ SENSOR_MT9V111,
+ SENSOR_OV7660,
+ SENSOR_OV9630,
+} sensors;
+ u8 type;
+#define Generic 0
+#define Creative_live_motion 1
+
+ u8 jpeg_hdr[JPEG_HDR_SZ];
+};
+
+static int sd_setexpo(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getexpo(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val);
+
+static const struct ctrl sd_ctrls[] = {
+ {
+ {
+ .id = V4L2_CID_EXPOSURE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Exposure",
+ .minimum = 0x0001,
+ .maximum = 0x0fff,
+ .step = 1,
+#define EXPO_DEF 0x027d
+ .default_value = EXPO_DEF,
+ },
+ .set = sd_setexpo,
+ .get = sd_getexpo,
+ },
+ {
+ {
+ .id = V4L2_CID_GAIN,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Gain",
+ .minimum = 0x01,
+ .maximum = 0xff,
+ .step = 1,
+#define GAIN_DEF 0x61
+ .default_value = GAIN_DEF,
+ },
+ .set = sd_setgain,
+ .get = sd_getgain,
+ },
+};
+
+static struct v4l2_pix_format vga_mode[] = {
+ {160, 120, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+ .bytesperline = 160,
+ .sizeimage = 160 * 120 * 5 / 8 + 590,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ .priv = 0},
+ {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+ .bytesperline = 320,
+ .sizeimage = 320 * 240 * 4 / 8 + 590,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ .priv = 1},
+ {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+ .bytesperline = 640,
+ .sizeimage = 640 * 480 * 3 / 8 + 590,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ .priv = 2},
+};
+
+/* JPEG quality indexed by webcam quality */
+#define QUAL_0 90
+#define QUAL_1 85
+#define QUAL_2 75
+#define QUAL_3 70
+static const u8 quality_tb[4] = { QUAL_0, QUAL_1, QUAL_2, QUAL_3 };
+
+/* sq930x registers */
+#define SQ930_CTRL_UCBUS_IO 0x0001
+#define SQ930_CTRL_I2C_IO 0x0002
+#define SQ930_CTRL_GPIO 0x0005
+#define SQ930_CTRL_CAP_START 0x0010
+#define SQ930_CTRL_CAP_STOP 0x0011
+#define SQ930_CTRL_SET_EXPOSURE 0x001d
+#define SQ930_CTRL_RESET 0x001e
+#define SQ930_CTRL_GET_DEV_INFO 0x001f
+
+/* gpio 1 (8..15) */
+#define SQ930_GPIO_DFL_I2C_SDA 0x0001
+#define SQ930_GPIO_DFL_I2C_SCL 0x0002
+#define SQ930_GPIO_RSTBAR 0x0004
+#define SQ930_GPIO_EXTRA1 0x0040
+#define SQ930_GPIO_EXTRA2 0x0080
+/* gpio 3 (24..31) */
+#define SQ930_GPIO_POWER 0x0200
+#define SQ930_GPIO_DFL_LED 0x1000
+
+struct ucbus_write_cmd {
+ u16 bw_addr;
+ u8 bw_data;
+};
+struct i2c_write_cmd {
+ u8 reg;
+ u16 val;
+};
+
+static const struct ucbus_write_cmd icx098bq_start_0[] = {
+ {0x0354, 0x00}, {0x03fa, 0x00}, {0xf800, 0x02}, {0xf801, 0xce},
+ {0xf802, 0xc1}, {0xf804, 0x00}, {0xf808, 0x00}, {0xf809, 0x0e},
+ {0xf80a, 0x01}, {0xf80b, 0xee}, {0xf807, 0x60}, {0xf80c, 0x02},
+ {0xf80d, 0xf0}, {0xf80e, 0x03}, {0xf80f, 0x0a}, {0xf81c, 0x02},
+ {0xf81d, 0xf0}, {0xf81e, 0x03}, {0xf81f, 0x0a}, {0xf83a, 0x00},
+ {0xf83b, 0x10}, {0xf83c, 0x00}, {0xf83d, 0x4e}, {0xf810, 0x04},
+ {0xf811, 0x00}, {0xf812, 0x02}, {0xf813, 0x10}, {0xf803, 0x00},
+ {0xf814, 0x01}, {0xf815, 0x18}, {0xf816, 0x00}, {0xf817, 0x48},
+ {0xf818, 0x00}, {0xf819, 0x25}, {0xf81a, 0x00}, {0xf81b, 0x3c},
+ {0xf82f, 0x03}, {0xf820, 0xff}, {0xf821, 0x0d}, {0xf822, 0xff},
+ {0xf823, 0x07}, {0xf824, 0xff}, {0xf825, 0x03}, {0xf826, 0xff},
+ {0xf827, 0x06}, {0xf828, 0xff}, {0xf829, 0x03}, {0xf82a, 0xff},
+ {0xf82b, 0x0c}, {0xf82c, 0xfd}, {0xf82d, 0x01}, {0xf82e, 0x00},
+ {0xf830, 0x00}, {0xf831, 0x47}, {0xf832, 0x00}, {0xf833, 0x00},
+ {0xf850, 0x00}, {0xf851, 0x00}, {0xf852, 0x00}, {0xf853, 0x24},
+ {0xf854, 0x00}, {0xf855, 0x18}, {0xf856, 0x00}, {0xf857, 0x3c},
+ {0xf858, 0x00}, {0xf859, 0x0c}, {0xf85a, 0x00}, {0xf85b, 0x30},
+ {0xf85c, 0x00}, {0xf85d, 0x0c}, {0xf85e, 0x00}, {0xf85f, 0x30},
+ {0xf860, 0x00}, {0xf861, 0x48}, {0xf862, 0x01}, {0xf863, 0xdc},
+ {0xf864, 0xff}, {0xf865, 0x98}, {0xf866, 0xff}, {0xf867, 0xc0},
+ {0xf868, 0xff}, {0xf869, 0x70}, {0xf86c, 0xff}, {0xf86d, 0x00},
+ {0xf86a, 0xff}, {0xf86b, 0x48}, {0xf86e, 0xff}, {0xf86f, 0x00},
+ {0xf870, 0x01}, {0xf871, 0xdb}, {0xf872, 0x01}, {0xf873, 0xfa},
+ {0xf874, 0x01}, {0xf875, 0xdb}, {0xf876, 0x01}, {0xf877, 0xfa},
+ {0xf878, 0x0f}, {0xf879, 0x0f}, {0xf87a, 0xff}, {0xf87b, 0xff},
+ {0xf800, 0x03}
+};
+static const struct ucbus_write_cmd icx098bq_start_1[] = {
+ {0xf5f0, 0x00}, {0xf5f1, 0xcd}, {0xf5f2, 0x80}, {0xf5f3, 0x80},
+ {0xf5f4, 0xc0},
+ {0xf5f0, 0x49}, {0xf5f1, 0xcd}, {0xf5f2, 0x80}, {0xf5f3, 0x80},
+ {0xf5f4, 0xc0},
+ {0xf5fa, 0x00}, {0xf5f6, 0x00}, {0xf5f7, 0x00}, {0xf5f8, 0x00},
+ {0xf5f9, 0x00}
+};
+
+static const struct ucbus_write_cmd icx098bq_start_2[] = {
+ {0xf800, 0x02}, {0xf807, 0xff}, {0xf805, 0x82}, {0xf806, 0x00},
+ {0xf807, 0x7f}, {0xf800, 0x03},
+ {0xf800, 0x02}, {0xf807, 0xff}, {0xf805, 0x40}, {0xf806, 0x00},
+ {0xf807, 0x7f}, {0xf800, 0x03},
+ {0xf800, 0x02}, {0xf807, 0xff}, {0xf805, 0xcf}, {0xf806, 0xd0},
+ {0xf807, 0x7f}, {0xf800, 0x03},
+ {0xf800, 0x02}, {0xf807, 0xff}, {0xf805, 0x00}, {0xf806, 0x00},
+ {0xf807, 0x7f}, {0xf800, 0x03}
+};
+
+static const struct ucbus_write_cmd lz24bp_start_0[] = {
+ {0x0354, 0x00}, {0x03fa, 0x00}, {0xf800, 0x02}, {0xf801, 0xbe},
+ {0xf802, 0xc6}, {0xf804, 0x00}, {0xf808, 0x00}, {0xf809, 0x06},
+ {0xf80a, 0x01}, {0xf80b, 0xfe}, {0xf807, 0x84}, {0xf80c, 0x02},
+ {0xf80d, 0xf7}, {0xf80e, 0x03}, {0xf80f, 0x0b}, {0xf81c, 0x00},
+ {0xf81d, 0x49}, {0xf81e, 0x03}, {0xf81f, 0x0b}, {0xf83a, 0x00},
+ {0xf83b, 0x01}, {0xf83c, 0x00}, {0xf83d, 0x6b}, {0xf810, 0x03},
+ {0xf811, 0x10}, {0xf812, 0x02}, {0xf813, 0x6f}, {0xf803, 0x00},
+ {0xf814, 0x00}, {0xf815, 0x44}, {0xf816, 0x00}, {0xf817, 0x48},
+ {0xf818, 0x00}, {0xf819, 0x25}, {0xf81a, 0x00}, {0xf81b, 0x3c},
+ {0xf82f, 0x03}, {0xf820, 0xff}, {0xf821, 0x0d}, {0xf822, 0xff},
+ {0xf823, 0x07}, {0xf824, 0xfd}, {0xf825, 0x07}, {0xf826, 0xf0},
+ {0xf827, 0x0c}, {0xf828, 0xff}, {0xf829, 0x03}, {0xf82a, 0xff},
+ {0xf82b, 0x0c}, {0xf82c, 0xfc}, {0xf82d, 0x01}, {0xf82e, 0x00},
+ {0xf830, 0x00}, {0xf831, 0x47}, {0xf832, 0x00}, {0xf833, 0x00},
+ {0xf850, 0x00}, {0xf851, 0x00}, {0xf852, 0x00}, {0xf853, 0x24},
+ {0xf854, 0x00}, {0xf855, 0x0c}, {0xf856, 0x00}, {0xf857, 0x30},
+ {0xf858, 0x00}, {0xf859, 0x18}, {0xf85a, 0x00}, {0xf85b, 0x3c},
+ {0xf85c, 0x00}, {0xf85d, 0x18}, {0xf85e, 0x00}, {0xf85f, 0x3c},
+ {0xf860, 0xff}, {0xf861, 0x37}, {0xf862, 0xff}, {0xf863, 0x1d},
+ {0xf864, 0xff}, {0xf865, 0x98}, {0xf866, 0xff}, {0xf867, 0xc0},
+ {0xf868, 0x00}, {0xf869, 0x37}, {0xf86c, 0x02}, {0xf86d, 0x1d},
+ {0xf86a, 0x00}, {0xf86b, 0x37}, {0xf86e, 0x02}, {0xf86f, 0x1d},
+ {0xf870, 0x01}, {0xf871, 0xc6}, {0xf872, 0x02}, {0xf873, 0x04},
+ {0xf874, 0x01}, {0xf875, 0xc6}, {0xf876, 0x02}, {0xf877, 0x04},
+ {0xf878, 0x0f}, {0xf879, 0x0f}, {0xf87a, 0xff}, {0xf87b, 0xff},
+ {0xf800, 0x03}
+};
+static const struct ucbus_write_cmd lz24bp_start_1_gen[] = {
+ {0xf5f0, 0x00}, {0xf5f1, 0xff}, {0xf5f2, 0x80}, {0xf5f3, 0x80},
+ {0xf5f4, 0xb3},
+ {0xf5f0, 0x40}, {0xf5f1, 0xff}, {0xf5f2, 0x80}, {0xf5f3, 0x80},
+ {0xf5f4, 0xb3},
+ {0xf5fa, 0x00}, {0xf5f6, 0x00}, {0xf5f7, 0x00}, {0xf5f8, 0x00},
+ {0xf5f9, 0x00}
+};
+
+static const struct ucbus_write_cmd lz24bp_start_1_clm[] = {
+ {0xf5f0, 0x00}, {0xf5f1, 0xff}, {0xf5f2, 0x88}, {0xf5f3, 0x88},
+ {0xf5f4, 0xc0},
+ {0xf5f0, 0x40}, {0xf5f1, 0xff}, {0xf5f2, 0x88}, {0xf5f3, 0x88},
+ {0xf5f4, 0xc0},
+ {0xf5fa, 0x00}, {0xf5f6, 0x00}, {0xf5f7, 0x00}, {0xf5f8, 0x00},
+ {0xf5f9, 0x00}
+};
+
+static const struct ucbus_write_cmd lz24bp_start_2[] = {
+ {0xf800, 0x02}, {0xf807, 0xff}, {0xf805, 0x80}, {0xf806, 0x00},
+ {0xf807, 0x7f}, {0xf800, 0x03},
+ {0xf800, 0x02}, {0xf807, 0xff}, {0xf805, 0x4e}, {0xf806, 0x00},
+ {0xf807, 0x7f}, {0xf800, 0x03},
+ {0xf800, 0x02}, {0xf807, 0xff}, {0xf805, 0xc0}, {0xf806, 0x48},
+ {0xf807, 0x7f}, {0xf800, 0x03},
+ {0xf800, 0x02}, {0xf807, 0xff}, {0xf805, 0x00}, {0xf806, 0x00},
+ {0xf807, 0x7f}, {0xf800, 0x03}
+};
+
+static const struct ucbus_write_cmd mi0360_start_0[] = {
+ {0x0354, 0x00}, {0x03fa, 0x00}, {0xf332, 0xcc}, {0xf333, 0xcc},
+ {0xf334, 0xcc}, {0xf335, 0xcc}, {0xf33f, 0x00}
+};
+static const struct i2c_write_cmd mi0360_init_23[] = {
+ {0x30, 0x0040}, /* reserved - def 0x0005 */
+ {0x31, 0x0000}, /* reserved - def 0x002a */
+ {0x34, 0x0100}, /* reserved - def 0x0100 */
+ {0x3d, 0x068f}, /* reserved - def 0x068f */
+};
+static const struct i2c_write_cmd mi0360_init_24[] = {
+ {0x03, 0x01e5}, /* window height */
+ {0x04, 0x0285}, /* window width */
+};
+static const struct i2c_write_cmd mi0360_init_25[] = {
+ {0x35, 0x0020}, /* global gain */
+ {0x2b, 0x0020}, /* green1 gain */
+ {0x2c, 0x002a}, /* blue gain */
+ {0x2d, 0x0028}, /* red gain */
+ {0x2e, 0x0020}, /* green2 gain */
+};
+static const struct ucbus_write_cmd mi0360_start_1[] = {
+ {0xf5f0, 0x11}, {0xf5f1, 0x99}, {0xf5f2, 0x80}, {0xf5f3, 0x80},
+ {0xf5f4, 0xa6},
+ {0xf5f0, 0x51}, {0xf5f1, 0x99}, {0xf5f2, 0x80}, {0xf5f3, 0x80},
+ {0xf5f4, 0xa6},
+ {0xf5fa, 0x00}, {0xf5f6, 0x00}, {0xf5f7, 0x00}, {0xf5f8, 0x00},
+ {0xf5f9, 0x00}
+};
+static const struct i2c_write_cmd mi0360_start_2[] = {
+ {0x62, 0x041d}, /* reserved - def 0x0418 */
+};
+static const struct i2c_write_cmd mi0360_start_3[] = {
+ {0x05, 0x007b}, /* horiz blanking */
+};
+static const struct i2c_write_cmd mi0360_start_4[] = {
+ {0x05, 0x03f5}, /* horiz blanking */
+};
+
+static const struct i2c_write_cmd mt9v111_init_0[] = {
+ {0x01, 0x0001}, /* select IFP/SOC registers */
+ {0x06, 0x300c}, /* operating mode control */
+ {0x08, 0xcc00}, /* output format control (RGB) */
+ {0x01, 0x0004}, /* select core registers */
+};
+static const struct i2c_write_cmd mt9v111_init_1[] = {
+ {0x03, 0x01e5}, /* window height */
+ {0x04, 0x0285}, /* window width */
+};
+static const struct i2c_write_cmd mt9v111_init_2[] = {
+ {0x30, 0x7800},
+ {0x31, 0x0000},
+ {0x07, 0x3002}, /* output control */
+ {0x35, 0x0020}, /* global gain */
+ {0x2b, 0x0020}, /* green1 gain */
+ {0x2c, 0x0020}, /* blue gain */
+ {0x2d, 0x0020}, /* red gain */
+ {0x2e, 0x0020}, /* green2 gain */
+};
+static const struct ucbus_write_cmd mt9v111_start_1[] = {
+ {0xf5f0, 0x11}, {0xf5f1, 0x96}, {0xf5f2, 0x80}, {0xf5f3, 0x80},
+ {0xf5f4, 0xaa},
+ {0xf5f0, 0x51}, {0xf5f1, 0x96}, {0xf5f2, 0x80}, {0xf5f3, 0x80},
+ {0xf5f4, 0xaa},
+ {0xf5fa, 0x00}, {0xf5f6, 0x0a}, {0xf5f7, 0x0a}, {0xf5f8, 0x0a},
+ {0xf5f9, 0x0a}
+};
+static const struct i2c_write_cmd mt9v111_init_3[] = {
+ {0x62, 0x0405},
+};
+static const struct i2c_write_cmd mt9v111_init_4[] = {
+ {0x05, 0x00ce}, /* horizontal blanking */
+};
+
+static const struct ucbus_write_cmd ov7660_start_0[] = {
+ {0x0354, 0x00}, {0x03fa, 0x00}, {0xf332, 0x00}, {0xf333, 0xc0},
+ {0xf334, 0x39}, {0xf335, 0xe7}, {0xf33f, 0x03}
+};
+
+static const struct ucbus_write_cmd ov9630_start_0[] = {
+ {0x0354, 0x00}, {0x03fa, 0x00}, {0xf332, 0x00}, {0xf333, 0x00},
+ {0xf334, 0x3e}, {0xf335, 0xf8}, {0xf33f, 0x03}
+};
+
+static const struct cap_s {
+ u8 cc_sizeid;
+ u8 cc_bytes[32];
+} capconfig[4][3] = {
+ [SENSOR_ICX098BQ] = {
+ {0, /* JPEG, 160x120 */
+ {0x01, 0x1f, 0x20, 0x0e, 0x00, 0x9f, 0x02, 0xee,
+ 0x01, 0x02, 0x00, 0x08, 0x18, 0x12, 0x78, 0xc8,
+ 0x02, 0x8b, 0x00, 0x8b, 0x00, 0x41, 0x01, 0x41,
+ 0x01, 0x41, 0x01, 0x05, 0x40, 0x01, 0xf0, 0x00} },
+ {2, /* JPEG, 320x240 */
+ {0x01, 0x1f, 0x20, 0x0e, 0x00, 0x9f, 0x02, 0xee,
+ 0x01, 0x02, 0x00, 0x08, 0x18, 0x12, 0x78, 0xc8,
+ 0x02, 0xdf, 0x01, 0x00, 0x00, 0x3f, 0x01, 0x3f,
+ 0x01, 0x00, 0x00, 0x05, 0x40, 0x01, 0xf0, 0x00} },
+ {4, /* JPEG, 640x480 */
+ {0x01, 0x22, 0x20, 0x0e, 0x00, 0xa2, 0x02, 0xf0,
+ 0x01, 0x02, 0x00, 0x08, 0x18, 0x12, 0x78, 0xc8,
+ 0x07, 0xe1, 0x01, 0xe1, 0x01, 0x3f, 0x01, 0x3f,
+ 0x01, 0x3f, 0x01, 0x05, 0x80, 0x02, 0xe0, 0x01} },
+ },
+ [SENSOR_LZ24BP] = {
+ {0, /* JPEG, 160x120 */
+ {0x01, 0x1f, 0x20, 0x0e, 0x00, 0x9f, 0x02, 0xee,
+ 0x01, 0x02, 0x00, 0x08, 0x18, 0x12, 0x78, 0xc8,
+ 0x02, 0x8b, 0x00, 0x8b, 0x00, 0x41, 0x01, 0x41,
+ 0x01, 0x41, 0x01, 0x05, 0x40, 0x01, 0xf0, 0x00} },
+ {2, /* JPEG, 320x240 */
+ {0x01, 0x22, 0x20, 0x0e, 0x00, 0xa2, 0x02, 0xee,
+ 0x01, 0x02, 0x00, 0x08, 0x18, 0x12, 0x78, 0xc8,
+ 0x02, 0xdf, 0x01, 0x00, 0x00, 0x3f, 0x01, 0x3f,
+ 0x01, 0x00, 0x00, 0x05, 0x40, 0x01, 0xf0, 0x00} },
+ {4, /* JPEG, 640x480 */
+ {0x01, 0x22, 0x20, 0x0e, 0x00, 0xa2, 0x02, 0xf0,
+ 0x01, 0x02, 0x00, 0x08, 0x18, 0x12, 0x78, 0xc8,
+ 0x07, 0xe1, 0x01, 0xe1, 0x01, 0x3f, 0x01, 0x3f,
+ 0x01, 0x3f, 0x01, 0x05, 0x80, 0x02, 0xe0, 0x01} },
+ },
+ [SENSOR_MI0360] = {
+ {0, /* JPEG, 160x120 */
+ {0x05, 0x3d, 0x20, 0x0b, 0x00, 0xbd, 0x02, 0x0b,
+ 0x02, 0x02, 0x00, 0x08, 0x18, 0x12, 0x78, 0xc8,
+ 0x02, 0x01, 0x01, 0x01, 0x01, 0x9f, 0x00, 0x9f,
+ 0x00, 0x9f, 0x01, 0x05, 0xa0, 0x00, 0x80, 0x00} },
+ {2, /* JPEG, 320x240 */
+ {0x01, 0x02, 0x20, 0x01, 0x20, 0x82, 0x02, 0xe1,
+/*fixme 03 e3 */
+ 0x01, 0x02, 0x00, 0x08, 0x18, 0x12, 0x78, 0xc8,
+ 0x02, 0xdf, 0x01, 0x00, 0x00, 0x3f, 0x01, 0x3f,
+ 0x01, 0x00, 0x00, 0x05, 0x40, 0x01, 0xf0, 0x00} },
+ {4, /* JPEG, 640x480 */
+ {0x01, 0x02, 0x20, 0x01, 0x20, 0x82, 0x02, 0xe3,
+ 0x01, 0x02, 0x00, 0x08, 0x18, 0x12, 0x78, 0xc8,
+ 0x07, 0xe1, 0x01, 0xe1, 0x01, 0x3f, 0x01, 0x3f,
+ 0x01, 0x3f, 0x01, 0x05, 0x80, 0x02, 0xe0, 0x01} },
+ },
+ [SENSOR_MT9V111] = {
+ {0, /* JPEG, 160x120 */
+ {0x05, 0x3d, 0x20, 0x0b, 0x00, 0xbd, 0x02, 0x0b,
+ 0x02, 0x02, 0x00, 0x08, 0x18, 0x12, 0x78, 0xc8,
+ 0x02, 0x01, 0x01, 0x01, 0x01, 0x9f, 0x00, 0x9f,
+ 0x00, 0x9f, 0x01, 0x05, 0xa0, 0x00, 0x80, 0x00} },
+ {2, /* JPEG, 320x240 */
+ {0x01, 0x02, 0x20, 0x03, 0x20, 0x82, 0x02, 0xe3,
+ 0x01, 0x02, 0x00, 0x08, 0x18, 0x12, 0x78, 0xc8,
+ 0x02, 0xdf, 0x01, 0x00, 0x00, 0x3f, 0x01, 0x3f,
+ 0x01, 0x00, 0x00, 0x05, 0x40, 0x01, 0xf0, 0x00} },
+ {4, /* JPEG, 640x480 */
+ {0x01, 0x02, 0x20, 0x03, 0x20, 0x82, 0x02, 0xe3,
+ 0x01, 0x02, 0x00, 0x08, 0x18, 0x12, 0x78, 0xc8,
+ 0x07, 0xe1, 0x01, 0xe1, 0x01, 0x3f, 0x01, 0x3f,
+ 0x01, 0x3f, 0x01, 0x05, 0x80, 0x02, 0xe0, 0x01} },
+ },
+};
+
+struct sensor_s {
+ const char *name;
+ u8 i2c_addr;
+ u8 i2c_dum;
+ u8 gpio[5];
+ u8 cmd_len;
+ const struct ucbus_write_cmd *cmd;
+};
+
+static const struct sensor_s sensor_tb[] = {
+ [SENSOR_ICX098BQ] = {
+ "icx098bp",
+ 0x00, 0x00,
+ {0,
+ SQ930_GPIO_DFL_I2C_SDA | SQ930_GPIO_DFL_I2C_SCL,
+ SQ930_GPIO_DFL_I2C_SDA,
+ 0,
+ SQ930_GPIO_RSTBAR
+ },
+ 8, icx098bq_start_0
+ },
+ [SENSOR_LZ24BP] = {
+ "lz24bp",
+ 0x00, 0x00,
+ {0,
+ SQ930_GPIO_DFL_I2C_SDA | SQ930_GPIO_DFL_I2C_SCL,
+ SQ930_GPIO_DFL_I2C_SDA,
+ 0,
+ SQ930_GPIO_RSTBAR
+ },
+ 8, lz24bp_start_0
+ },
+ [SENSOR_MI0360] = {
+ "mi0360",
+ 0x5d, 0x80,
+ {SQ930_GPIO_RSTBAR,
+ SQ930_GPIO_DFL_I2C_SDA | SQ930_GPIO_DFL_I2C_SCL,
+ SQ930_GPIO_DFL_I2C_SDA,
+ 0,
+ 0
+ },
+ 7, mi0360_start_0
+ },
+ [SENSOR_MT9V111] = {
+ "mt9v111",
+ 0x5c, 0x7f,
+ {SQ930_GPIO_RSTBAR,
+ SQ930_GPIO_DFL_I2C_SDA | SQ930_GPIO_DFL_I2C_SCL,
+ SQ930_GPIO_DFL_I2C_SDA,
+ 0,
+ 0
+ },
+ 7, mi0360_start_0
+ },
+ [SENSOR_OV7660] = {
+ "ov7660",
+ 0x21, 0x00,
+ {0,
+ SQ930_GPIO_DFL_I2C_SDA | SQ930_GPIO_DFL_I2C_SCL,
+ SQ930_GPIO_DFL_I2C_SDA,
+ 0,
+ SQ930_GPIO_RSTBAR
+ },
+ 7, ov7660_start_0
+ },
+ [SENSOR_OV9630] = {
+ "ov9630",
+ 0x30, 0x00,
+ {0,
+ SQ930_GPIO_DFL_I2C_SDA | SQ930_GPIO_DFL_I2C_SCL,
+ SQ930_GPIO_DFL_I2C_SDA,
+ 0,
+ SQ930_GPIO_RSTBAR
+ },
+ 7, ov9630_start_0
+ },
+};
+
+static void reg_r(struct gspca_dev *gspca_dev,
+ u16 value, int len)
+{
+ int ret;
+
+ if (gspca_dev->usb_err < 0)
+ return;
+ ret = usb_control_msg(gspca_dev->dev,
+ usb_rcvctrlpipe(gspca_dev->dev, 0),
+ 0x0c,
+ USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ value, 0, gspca_dev->usb_buf, len,
+ 500);
+ if (ret < 0) {
+ PDEBUG(D_ERR, "reg_r %04x failed %d", value, ret);
+ gspca_dev->usb_err = ret;
+ }
+}
+
+static void reg_w(struct gspca_dev *gspca_dev, u16 value, u16 index)
+{
+ int ret;
+
+ if (gspca_dev->usb_err < 0)
+ return;
+ PDEBUG(D_USBO, "reg_w v: %04x i: %04x", value, index);
+ ret = usb_control_msg(gspca_dev->dev,
+ usb_sndctrlpipe(gspca_dev->dev, 0),
+ 0x0c, /* request */
+ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ value, index, NULL, 0,
+ 500);
+ msleep(30);
+ if (ret < 0) {
+ PDEBUG(D_ERR, "reg_w %04x %04x failed %d", value, index, ret);
+ gspca_dev->usb_err = ret;
+ }
+}
+
+static void reg_wb(struct gspca_dev *gspca_dev, u16 value, u16 index,
+ const u8 *data, int len)
+{
+ int ret;
+
+ if (gspca_dev->usb_err < 0)
+ return;
+ PDEBUG(D_USBO, "reg_wb v: %04x i: %04x %02x...%02x",
+ value, index, *data, data[len - 1]);
+ memcpy(gspca_dev->usb_buf, data, len);
+ ret = usb_control_msg(gspca_dev->dev,
+ usb_sndctrlpipe(gspca_dev->dev, 0),
+ 0x0c, /* request */
+ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ value, index, gspca_dev->usb_buf, len,
+ 1000);
+ msleep(30);
+ if (ret < 0) {
+ PDEBUG(D_ERR, "reg_wb %04x %04x failed %d", value, index, ret);
+ gspca_dev->usb_err = ret;
+ }
+}
+
+static void i2c_write(struct sd *sd,
+ const struct i2c_write_cmd *cmd,
+ int ncmds)
+{
+ struct gspca_dev *gspca_dev = &sd->gspca_dev;
+ const struct sensor_s *sensor;
+ u16 val, idx;
+ u8 *buf;
+ int ret;
+
+ if (gspca_dev->usb_err < 0)
+ return;
+
+ sensor = &sensor_tb[sd->sensor];
+
+ val = (sensor->i2c_addr << 8) | SQ930_CTRL_I2C_IO;
+ idx = (cmd->val & 0xff00) | cmd->reg;
+
+ buf = gspca_dev->usb_buf;
+ *buf++ = sensor->i2c_dum;
+ *buf++ = cmd->val;
+
+ while (--ncmds > 0) {
+ cmd++;
+ *buf++ = cmd->reg;
+ *buf++ = cmd->val >> 8;
+ *buf++ = sensor->i2c_dum;
+ *buf++ = cmd->val;
+ }
+
+ PDEBUG(D_USBO, "i2c_w v: %04x i: %04x %02x...%02x",
+ val, idx, gspca_dev->usb_buf[0], buf[-1]);
+ ret = usb_control_msg(gspca_dev->dev,
+ usb_sndctrlpipe(gspca_dev->dev, 0),
+ 0x0c, /* request */
+ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ val, idx,
+ gspca_dev->usb_buf, buf - gspca_dev->usb_buf,
+ 500);
+ if (ret < 0) {
+ PDEBUG(D_ERR, "i2c_write failed %d", ret);
+ gspca_dev->usb_err = ret;
+ }
+}
+
+static void ucbus_write(struct gspca_dev *gspca_dev,
+ const struct ucbus_write_cmd *cmd,
+ int ncmds,
+ int batchsize)
+{
+ u8 *buf;
+ u16 val, idx;
+ int len, ret;
+
+ if (gspca_dev->usb_err < 0)
+ return;
+
+#ifdef GSPCA_DEBUG
+ if ((batchsize - 1) * 3 > USB_BUF_SZ) {
+ err("Bug: usb_buf overflow");
+ gspca_dev->usb_err = -ENOMEM;
+ return;
+ }
+#endif
+
+ for (;;) {
+ len = ncmds;
+ if (len > batchsize)
+ len = batchsize;
+ ncmds -= len;
+
+ val = (cmd->bw_addr << 8) | SQ930_CTRL_UCBUS_IO;
+ idx = (cmd->bw_data << 8) | (cmd->bw_addr >> 8);
+
+ buf = gspca_dev->usb_buf;
+ while (--len > 0) {
+ cmd++;
+ *buf++ = cmd->bw_addr;
+ *buf++ = cmd->bw_addr >> 8;
+ *buf++ = cmd->bw_data;
+ }
+ if (buf != gspca_dev->usb_buf)
+ PDEBUG(D_USBO, "ucbus v: %04x i: %04x %02x...%02x",
+ val, idx,
+ gspca_dev->usb_buf[0], buf[-1]);
+ else
+ PDEBUG(D_USBO, "ucbus v: %04x i: %04x",
+ val, idx);
+ ret = usb_control_msg(gspca_dev->dev,
+ usb_sndctrlpipe(gspca_dev->dev, 0),
+ 0x0c, /* request */
+ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ val, idx,
+ gspca_dev->usb_buf, buf - gspca_dev->usb_buf,
+ 500);
+ if (ret < 0) {
+ PDEBUG(D_ERR, "ucbus_write failed %d", ret);
+ gspca_dev->usb_err = ret;
+ return;
+ }
+ msleep(30);
+ if (ncmds <= 0)
+ break;
+ cmd++;
+ }
+}
+
+static void gpio_set(struct sd *sd, u16 val, u16 mask)
+{
+ struct gspca_dev *gspca_dev = &sd->gspca_dev;
+
+ if (mask & 0x00ff) {
+ sd->gpio[0] &= ~mask;
+ sd->gpio[0] |= val;
+ reg_w(gspca_dev, 0x0100 | SQ930_CTRL_GPIO,
+ ~sd->gpio[0] << 8);
+ }
+ mask >>= 8;
+ val >>= 8;
+ if (mask) {
+ sd->gpio[1] &= ~mask;
+ sd->gpio[1] |= val;
+ reg_w(gspca_dev, 0x0300 | SQ930_CTRL_GPIO,
+ ~sd->gpio[1] << 8);
+ }
+}
+
+static void gpio_init(struct sd *sd,
+ const u8 *gpio)
+{
+ gpio_set(sd, *gpio++, 0x000f);
+ gpio_set(sd, *gpio++, 0x000f);
+ gpio_set(sd, *gpio++, 0x000f);
+ gpio_set(sd, *gpio++, 0x000f);
+ gpio_set(sd, *gpio, 0x000f);
+}
+
+static void bridge_init(struct sd *sd)
+{
+ static const struct ucbus_write_cmd clkfreq_cmd = {
+ 0xf031, 0 /* SQ930_CLKFREQ_60MHZ */
+ };
+
+ ucbus_write(&sd->gspca_dev, &clkfreq_cmd, 1, 1);
+
+ gpio_set(sd, SQ930_GPIO_POWER, 0xff00);
+}
+
+static void cmos_probe(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ int i;
+ const struct sensor_s *sensor;
+ static const u8 probe_order[] = {
+/* SENSOR_LZ24BP, (tested as ccd) */
+ SENSOR_OV9630,
+ SENSOR_MI0360,
+ SENSOR_OV7660,
+ SENSOR_MT9V111,
+ };
+
+ for (i = 0; i < ARRAY_SIZE(probe_order); i++) {
+ sensor = &sensor_tb[probe_order[i]];
+ ucbus_write(&sd->gspca_dev, sensor->cmd, sensor->cmd_len, 8);
+ gpio_init(sd, sensor->gpio);
+ msleep(100);
+ reg_r(gspca_dev, (sensor->i2c_addr << 8) | 0x001c, 1);
+ msleep(100);
+ if (gspca_dev->usb_buf[0] != 0)
+ break;
+ }
+ if (i >= ARRAY_SIZE(probe_order))
+ PDEBUG(D_PROBE, "Unknown sensor");
+ else
+ sd->sensor = probe_order[i];
+}
+
+static void mt9v111_init(struct gspca_dev *gspca_dev)
+{
+ int i, nwait;
+ static const u8 cmd_001b[] = {
+ 0x00, 0x3b, 0xf6, 0x01, 0x03, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00
+ };
+ static const u8 cmd_011b[][7] = {
+ {0x10, 0x01, 0x66, 0x08, 0x00, 0x00, 0x00},
+ {0x01, 0x00, 0x1a, 0x04, 0x00, 0x00, 0x00},
+ {0x20, 0x00, 0x10, 0x04, 0x00, 0x00, 0x00},
+ {0x02, 0x01, 0xae, 0x01, 0x00, 0x00, 0x00},
+ };
+
+ reg_wb(gspca_dev, 0x001b, 0x0000, cmd_001b, sizeof cmd_001b);
+ for (i = 0; i < ARRAY_SIZE(cmd_011b); i++) {
+ reg_wb(gspca_dev, 0x001b, 0x0000, cmd_011b[i],
+ ARRAY_SIZE(cmd_011b[0]));
+ msleep(400);
+ nwait = 20;
+ for (;;) {
+ reg_r(gspca_dev, 0x031b, 1);
+ if (gspca_dev->usb_buf[0] == 0
+ || gspca_dev->usb_err != 0)
+ break;
+ if (--nwait < 0) {
+ PDEBUG(D_PROBE, "mt9v111_init timeout");
+ gspca_dev->usb_err = -ETIME;
+ return;
+ }
+ msleep(50);
+ }
+ }
+}
+
+static void global_init(struct sd *sd, int first_time)
+{
+ switch (sd->sensor) {
+ case SENSOR_ICX098BQ:
+ if (first_time)
+ ucbus_write(&sd->gspca_dev,
+ icx098bq_start_0,
+ 8, 8);
+ gpio_init(sd, sensor_tb[sd->sensor].gpio);
+ break;
+ case SENSOR_LZ24BP:
+ if (sd->type != Creative_live_motion)
+ gpio_set(sd, SQ930_GPIO_EXTRA1, 0x00ff);
+ else
+ gpio_set(sd, 0, 0x00ff);
+ msleep(50);
+ if (first_time)
+ ucbus_write(&sd->gspca_dev,
+ lz24bp_start_0,
+ 8, 8);
+ gpio_init(sd, sensor_tb[sd->sensor].gpio);
+ break;
+ case SENSOR_MI0360:
+ if (first_time)
+ ucbus_write(&sd->gspca_dev,
+ mi0360_start_0,
+ ARRAY_SIZE(mi0360_start_0),
+ 8);
+ gpio_init(sd, sensor_tb[sd->sensor].gpio);
+ gpio_set(sd, SQ930_GPIO_EXTRA2, SQ930_GPIO_EXTRA2);
+ break;
+ default:
+/* case SENSOR_MT9V111: */
+ if (first_time)
+ mt9v111_init(&sd->gspca_dev);
+ else
+ gpio_init(sd, sensor_tb[sd->sensor].gpio);
+ break;
+ }
+}
+
+static void lz24bp_ppl(struct sd *sd, u16 ppl)
+{
+ struct ucbus_write_cmd cmds[2] = {
+ {0xf810, ppl >> 8},
+ {0xf811, ppl}
+ };
+
+ ucbus_write(&sd->gspca_dev, cmds, ARRAY_SIZE(cmds), 2);
+}
+
+static void setexposure(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ int i, integclks, intstartclk, frameclks, min_frclk;
+ const struct sensor_s *sensor;
+ u16 cmd;
+ u8 buf[15];
+
+ integclks = sd->expo;
+ i = 0;
+ cmd = SQ930_CTRL_SET_EXPOSURE;
+
+ switch (sd->sensor) {
+ case SENSOR_ICX098BQ: /* ccd */
+ case SENSOR_LZ24BP:
+ min_frclk = sd->sensor == SENSOR_ICX098BQ ? 0x210 : 0x26f;
+ if (integclks >= min_frclk) {
+ intstartclk = 0;
+ frameclks = integclks;
+ } else {
+ intstartclk = min_frclk - integclks;
+ frameclks = min_frclk;
+ }
+ buf[i++] = intstartclk >> 8;
+ buf[i++] = intstartclk;
+ buf[i++] = frameclks >> 8;
+ buf[i++] = frameclks;
+ buf[i++] = sd->gain;
+ break;
+ default: /* cmos */
+/* case SENSOR_MI0360: */
+/* case SENSOR_MT9V111: */
+ cmd |= 0x0100;
+ sensor = &sensor_tb[sd->sensor];
+ buf[i++] = sensor->i2c_addr; /* i2c_slave_addr */
+ buf[i++] = 0x08; /* 2 * ni2c */
+ buf[i++] = 0x09; /* reg = shutter width */
+ buf[i++] = integclks >> 8; /* val H */
+ buf[i++] = sensor->i2c_dum;
+ buf[i++] = integclks; /* val L */
+ buf[i++] = 0x35; /* reg = global gain */
+ buf[i++] = 0x00; /* val H */
+ buf[i++] = sensor->i2c_dum;
+ buf[i++] = sd->gain; /* val L */
+ buf[i++] = 0x00;
+ buf[i++] = 0x00;
+ buf[i++] = 0x00;
+ buf[i++] = 0x00;
+ buf[i++] = 0x83;
+ break;
+ }
+ reg_wb(gspca_dev, cmd, 0, buf, i);
+}
+
+/* This function is called at probe time just before sd_init */
+static int sd_config(struct gspca_dev *gspca_dev,
+ const struct usb_device_id *id)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ struct cam *cam = &gspca_dev->cam;
+
+ sd->sensor = id->driver_info >> 8;
+ sd->type = id->driver_info;
+
+ cam->cam_mode = vga_mode;
+ cam->nmodes = ARRAY_SIZE(vga_mode);
+
+ cam->bulk = 1;
+ cam->bulk_size = BULK_TRANSFER_LEN;
+/* cam->bulk_nurbs = 2; fixme: if no setexpo sync */
+
+ sd->quality = QUALITY_DEF;
+ sd->gain = GAIN_DEF;
+ sd->expo = EXPO_DEF;
+
+ return 0;
+}
+
+/* this function is called at probe and resume time */
+static int sd_init(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->gpio[0] = sd->gpio[1] = 0xff; /* force gpio rewrite */
+
+/*fixme: is this needed for icx098bp and mi0360?
+ if (sd->sensor != SENSOR_LZ24BP)
+ reg_w(gspca_dev, SQ930_CTRL_RESET, 0x0000);
+ */
+
+ reg_r(gspca_dev, SQ930_CTRL_GET_DEV_INFO, 8);
+/* it returns:
+ * 03 00 12 93 0b f6 c9 00 live! ultra
+ * 03 00 07 93 0b f6 ca 00 live! ultra for notebook
+ * 03 00 12 93 0b fe c8 00 Trust WB-3500T
+ * 02 00 06 93 0b fe c8 00 Joy-IT 318S
+ * 03 00 12 93 0b f6 cf 00 icam tracer - sensor icx098bq
+ * 02 00 12 93 0b fe cf 00 ProQ Motion Webcam
+ *
+ * byte
+ * 0: 02 = usb 1.0 (12Mbit) / 03 = usb2.0 (480Mbit)
+ * 1: 00
+ * 2: 06 / 07 / 12 = mode webcam? firmware??
+ * 3: 93 chip = 930b (930b or 930c)
+ * 4: 0b
+ * 5: f6 = cdd (icx098bq, lz24bp) / fe or de = cmos (i2c) (other sensors)
+ * 6: c8 / c9 / ca / cf = mode webcam?, sensor? webcam?
+ * 7: 00
+ */
+ PDEBUG(D_PROBE, "info: %02x %02x %02x %02x %02x %02x %02x %02x",
+ gspca_dev->usb_buf[0],
+ gspca_dev->usb_buf[1],
+ gspca_dev->usb_buf[2],
+ gspca_dev->usb_buf[3],
+ gspca_dev->usb_buf[4],
+ gspca_dev->usb_buf[5],
+ gspca_dev->usb_buf[6],
+ gspca_dev->usb_buf[7]);
+
+ bridge_init(sd);
+
+ if (sd->sensor == SENSOR_MI0360) {
+
+ /* no sensor probe for icam tracer */
+ if (gspca_dev->usb_buf[5] == 0xf6) { /* if CMOS */
+ sd->sensor = SENSOR_ICX098BQ;
+ gspca_dev->cam.cam_mode = &vga_mode[1];
+ gspca_dev->cam.nmodes = 1; /* only 320x240 */
+ } else {
+ cmos_probe(gspca_dev);
+ }
+ }
+
+ PDEBUG(D_PROBE, "Sensor %s", sensor_tb[sd->sensor].name);
+
+ global_init(sd, 1);
+ return gspca_dev->usb_err;
+}
+
+/* special function to create the quantization tables of the JPEG header */
+static void sd_jpeg_set_qual(u8 *jpeg_hdr,
+ int quality)
+{
+ int i, sc1, sc2;
+
+ quality = quality_tb[quality]; /* convert to JPEG quality */
+/*
+ * approximative qualities for Y and U/V:
+ * quant = 0:94%/91% 1:91%/87% 2:82%/73% 3:69%/56%
+ * should have:
+ * quant = 0:94%/91% 1:91%/87.5% 2:81.5%/72% 3:69%/54.5%
+ */
+ sc1 = 200 - quality * 2;
+ quality = quality * 7 / 5 - 40; /* UV quality */
+ sc2 = 200 - quality * 2;
+ for (i = 0; i < 64; i++) {
+ jpeg_hdr[JPEG_QT0_OFFSET + i] =
+ (jpeg_head[JPEG_QT0_OFFSET + i] * sc1 + 50) / 100;
+ jpeg_hdr[JPEG_QT1_OFFSET + i] =
+ (jpeg_head[JPEG_QT1_OFFSET + i] * sc2 + 50) / 100;
+ }
+}
+
+/* send the start/stop commands to the webcam */
+static void send_start(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ const struct cap_s *cap;
+ int mode, quality;
+
+ mode = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv;
+ cap = &capconfig[sd->sensor][mode];
+ quality = sd->quality;
+ reg_wb(gspca_dev, (quality << 12)
+ | 0x0a00 /* 900 for Bayer */
+ | SQ930_CTRL_CAP_START,
+ 0x0500 /* a00 for Bayer */
+ | cap->cc_sizeid,
+ cap->cc_bytes, 32);
+};
+static void send_stop(struct gspca_dev *gspca_dev)
+{
+ reg_w(gspca_dev, SQ930_CTRL_CAP_STOP, 0);
+};
+
+/* function called at start time before URB creation */
+static int sd_isoc_init(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ gspca_dev->cam.bulk_nurbs = 1; /* there must be one URB only */
+ sd->do_ctrl = 0;
+ return 0;
+}
+
+/* start the capture */
+static int sd_start(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ int mode;
+
+ /* initialize the JPEG header */
+ jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width,
+ 0x21); /* JPEG 422 */
+ sd_jpeg_set_qual(sd->jpeg_hdr, sd->quality);
+
+ bridge_init(sd);
+ global_init(sd, 0);
+ msleep(100);
+
+ switch (sd->sensor) {
+ case SENSOR_ICX098BQ:
+ ucbus_write(gspca_dev, icx098bq_start_0,
+ ARRAY_SIZE(icx098bq_start_0),
+ 8);
+ ucbus_write(gspca_dev, icx098bq_start_1,
+ ARRAY_SIZE(icx098bq_start_1),
+ 5);
+ ucbus_write(gspca_dev, icx098bq_start_2,
+ ARRAY_SIZE(icx098bq_start_2),
+ 6);
+ msleep(50);
+
+ /* 1st start */
+ send_start(gspca_dev);
+ gpio_set(sd, SQ930_GPIO_EXTRA2 | SQ930_GPIO_RSTBAR, 0x00ff);
+ msleep(70);
+ reg_w(gspca_dev, SQ930_CTRL_CAP_STOP, 0x0000);
+ gpio_set(sd, 0x7f, 0x00ff);
+
+ /* 2nd start */
+ send_start(gspca_dev);
+ gpio_set(sd, SQ930_GPIO_EXTRA2 | SQ930_GPIO_RSTBAR, 0x00ff);
+ goto out;
+ case SENSOR_LZ24BP:
+ ucbus_write(gspca_dev, lz24bp_start_0,
+ ARRAY_SIZE(lz24bp_start_0),
+ 8);
+ if (sd->type != Creative_live_motion)
+ ucbus_write(gspca_dev, lz24bp_start_1_gen,
+ ARRAY_SIZE(lz24bp_start_1_gen),
+ 5);
+ else
+ ucbus_write(gspca_dev, lz24bp_start_1_clm,
+ ARRAY_SIZE(lz24bp_start_1_clm),
+ 5);
+ ucbus_write(gspca_dev, lz24bp_start_2,
+ ARRAY_SIZE(lz24bp_start_2),
+ 6);
+ mode = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv;
+ lz24bp_ppl(sd, mode == 2 ? 0x0564 : 0x0310);
+ msleep(10);
+ break;
+ case SENSOR_MI0360:
+ ucbus_write(gspca_dev, mi0360_start_0,
+ ARRAY_SIZE(mi0360_start_0),
+ 8);
+ i2c_write(sd, mi0360_init_23,
+ ARRAY_SIZE(mi0360_init_23));
+ i2c_write(sd, mi0360_init_24,
+ ARRAY_SIZE(mi0360_init_24));
+ i2c_write(sd, mi0360_init_25,
+ ARRAY_SIZE(mi0360_init_25));
+ ucbus_write(gspca_dev, mi0360_start_1,
+ ARRAY_SIZE(mi0360_start_1),
+ 5);
+ i2c_write(sd, mi0360_start_2,
+ ARRAY_SIZE(mi0360_start_2));
+ i2c_write(sd, mi0360_start_3,
+ ARRAY_SIZE(mi0360_start_3));
+
+ /* 1st start */
+ send_start(gspca_dev);
+ msleep(60);
+ reg_w(gspca_dev, SQ930_CTRL_CAP_STOP, 0x0000);
+
+ i2c_write(sd,
+ mi0360_start_4, ARRAY_SIZE(mi0360_start_4));
+ break;
+ default:
+/* case SENSOR_MT9V111: */
+ ucbus_write(gspca_dev, mi0360_start_0,
+ ARRAY_SIZE(mi0360_start_0),
+ 8);
+ i2c_write(sd, mt9v111_init_0,
+ ARRAY_SIZE(mt9v111_init_0));
+ i2c_write(sd, mt9v111_init_1,
+ ARRAY_SIZE(mt9v111_init_1));
+ i2c_write(sd, mt9v111_init_2,
+ ARRAY_SIZE(mt9v111_init_2));
+ ucbus_write(gspca_dev, mt9v111_start_1,
+ ARRAY_SIZE(mt9v111_start_1),
+ 8);
+ i2c_write(sd, mt9v111_init_3,
+ ARRAY_SIZE(mt9v111_init_3));
+ i2c_write(sd, mt9v111_init_4,
+ ARRAY_SIZE(mt9v111_init_4));
+ break;
+ }
+
+ send_start(gspca_dev);
+out:
+ msleep(1000);
+
+ sd->eof_len = 0; /* init packet scan */
+
+ if (sd->sensor == SENSOR_MT9V111)
+ gpio_set(sd, SQ930_GPIO_DFL_LED, SQ930_GPIO_DFL_LED);
+
+ sd->do_ctrl = 1; /* set the exposure */
+
+ return gspca_dev->usb_err;
+}
+
+static void sd_stopN(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ if (sd->sensor == SENSOR_MT9V111)
+ gpio_set(sd, 0, SQ930_GPIO_DFL_LED);
+ send_stop(gspca_dev);
+}
+
+/* function called when the application gets a new frame */
+/* It sets the exposure if required and restart the bulk transfer. */
+static void sd_dq_callback(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ int ret;
+
+ if (!sd->do_ctrl || gspca_dev->cam.bulk_nurbs != 0)
+ return;
+ sd->do_ctrl = 0;
+
+ setexposure(gspca_dev);
+
+ gspca_dev->cam.bulk_nurbs = 1;
+ ret = usb_submit_urb(gspca_dev->urb[0], GFP_ATOMIC);
+ if (ret < 0)
+ PDEBUG(D_ERR|D_PACK, "sd_dq_callback() err %d", ret);
+
+ /* wait a little time, otherwise the webcam crashes */
+ msleep(100);
+}
+
+/* move a packet adding 0x00 after 0xff */
+static void add_packet(struct gspca_dev *gspca_dev,
+ u8 *data,
+ int len)
+{
+ int i;
+
+ i = 0;
+ do {
+ if (data[i] == 0xff) {
+ gspca_frame_add(gspca_dev, INTER_PACKET,
+ data, i + 1);
+ len -= i;
+ data += i;
+ *data = 0x00;
+ i = 0;
+ }
+ } while (++i < len);
+ gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
+}
+
+/* end a frame and start a new one */
+static void eof_sof(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ static const u8 ffd9[] = {0xff, 0xd9};
+
+ /* if control set, stop bulk transfer */
+ if (sd->do_ctrl
+ && gspca_dev->last_packet_type == INTER_PACKET)
+ gspca_dev->cam.bulk_nurbs = 0;
+ gspca_frame_add(gspca_dev, LAST_PACKET,
+ ffd9, 2);
+ gspca_frame_add(gspca_dev, FIRST_PACKET,
+ sd->jpeg_hdr, JPEG_HDR_SZ);
+}
+
+static void sd_pkt_scan(struct gspca_dev *gspca_dev,
+ u8 *data, /* isoc packet */
+ int len) /* iso packet length */
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ u8 *p;
+ int l;
+
+ len -= 8; /* ignore last 8 bytes (00 00 55 aa 55 aa 00 00) */
+
+ /*
+ * the end/start of frame is indicated by
+ * 0x00 * 16 - 0xab * 8
+ * aligned on 8 bytes boundary
+ */
+ if (sd->eof_len != 0) { /* if 'abababab' in previous pkt */
+ if (*((u32 *) data) == 0xabababab) {
+ /*fixme: should remove previous 0000ababab*/
+ eof_sof(gspca_dev);
+ data += 4;
+ len -= 4;
+ }
+ sd->eof_len = 0;
+ }
+ p = data;
+ l = len;
+ for (;;) {
+ if (*((u32 *) p) == 0xabababab) {
+ if (l < 8) { /* (may be 4 only) */
+ sd->eof_len = 1;
+ break;
+ }
+ if (*((u32 *) p + 1) == 0xabababab) {
+ add_packet(gspca_dev, data, p - data - 16);
+ /* remove previous zeros */
+ eof_sof(gspca_dev);
+ p += 8;
+ l -= 8;
+ if (l <= 0)
+ return;
+ len = l;
+ data = p;
+ continue;
+ }
+ }
+ p += 4;
+ l -= 4;
+ if (l <= 0)
+ break;
+ }
+ add_packet(gspca_dev, data, len);
+}
+
+static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->gain = val;
+ if (gspca_dev->streaming)
+ sd->do_ctrl = 1;
+ return 0;
+}
+
+static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ *val = sd->gain;
+ return 0;
+}
+static int sd_setexpo(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->expo = val;
+ if (gspca_dev->streaming)
+ sd->do_ctrl = 1;
+ return 0;
+}
+
+static int sd_getexpo(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ *val = sd->expo;
+ return 0;
+}
+
+static int sd_set_jcomp(struct gspca_dev *gspca_dev,
+ struct v4l2_jpegcompression *jcomp)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ int quality;
+
+ if (jcomp->quality >= (QUAL_0 + QUAL_1) / 2)
+ quality = 0;
+ else if (jcomp->quality >= (QUAL_1 + QUAL_2) / 2)
+ quality = 1;
+ else if (jcomp->quality >= (QUAL_2 + QUAL_3) / 2)
+ quality = 2;
+ else
+ quality = 3;
+
+ if (quality != sd->quality) {
+ sd->quality = quality;
+ if (gspca_dev->streaming) {
+ send_stop(gspca_dev);
+ sd_jpeg_set_qual(sd->jpeg_hdr, sd->quality);
+ msleep(70);
+ send_start(gspca_dev);
+ }
+ }
+ return gspca_dev->usb_err;
+}
+
+static int sd_get_jcomp(struct gspca_dev *gspca_dev,
+ struct v4l2_jpegcompression *jcomp)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ memset(jcomp, 0, sizeof *jcomp);
+ jcomp->quality = quality_tb[sd->quality];
+ jcomp->jpeg_markers = V4L2_JPEG_MARKER_DHT
+ | V4L2_JPEG_MARKER_DQT;
+ return 0;
+}
+
+/* sub-driver description */
+static const struct sd_desc sd_desc = {
+ .name = MODULE_NAME,
+ .ctrls = sd_ctrls,
+ .nctrls = ARRAY_SIZE(sd_ctrls),
+ .config = sd_config,
+ .init = sd_init,
+ .isoc_init = sd_isoc_init,
+ .start = sd_start,
+ .stopN = sd_stopN,
+ .pkt_scan = sd_pkt_scan,
+ .dq_callback = sd_dq_callback,
+ .get_jcomp = sd_get_jcomp,
+ .set_jcomp = sd_set_jcomp,
+};
+
+/* Table of supported USB devices */
+#define ST(sensor, type) \
+ .driver_info = (SENSOR_ ## sensor << 8) \
+ | (type)
+static const __devinitdata struct usb_device_id device_table[] = {
+ {USB_DEVICE(0x041e, 0x4038), ST(MI0360, 0)},
+ {USB_DEVICE(0x041e, 0x403c), ST(LZ24BP, 0)},
+ {USB_DEVICE(0x041e, 0x403d), ST(LZ24BP, 0)},
+ {USB_DEVICE(0x041e, 0x4041), ST(LZ24BP, Creative_live_motion)},
+ {USB_DEVICE(0x2770, 0x930b), ST(MI0360, 0)},
+ {USB_DEVICE(0x2770, 0x930c), ST(MI0360, 0)},
+ {}
+};
+MODULE_DEVICE_TABLE(usb, device_table);
+
+
+/* -- device connect -- */
+static int sd_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+{
+ return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
+ THIS_MODULE);
+}
+
+static struct usb_driver sd_driver = {
+ .name = MODULE_NAME,
+ .id_table = device_table,
+ .probe = sd_probe,
+ .disconnect = gspca_disconnect,
+#ifdef CONFIG_PM
+ .suspend = gspca_suspend,
+ .resume = gspca_resume,
+#endif
+};
+
+/* -- module insert / remove -- */
+static int __init sd_mod_init(void)
+{
+ int ret;
+
+ ret = usb_register(&sd_driver);
+ if (ret < 0)
+ return ret;
+ info("registered");
+ return 0;
+}
+static void __exit sd_mod_exit(void)
+{
+ usb_deregister(&sd_driver);
+ info("deregistered");
+}
+
+module_init(sd_mod_init);
+module_exit(sd_mod_exit);
diff --git a/drivers/media/video/gspca/stk014.c b/drivers/media/video/gspca/stk014.c
index 0fb534210a2..2aedf4b1bfa 100644
--- a/drivers/media/video/gspca/stk014.c
+++ b/drivers/media/video/gspca/stk014.c
@@ -36,11 +36,11 @@ struct sd {
unsigned char colors;
unsigned char lightfreq;
u8 quality;
-#define QUALITY_MIN 60
+#define QUALITY_MIN 70
#define QUALITY_MAX 95
-#define QUALITY_DEF 80
+#define QUALITY_DEF 88
- u8 *jpeg_hdr;
+ u8 jpeg_hdr[JPEG_HDR_SZ];
};
/* V4L2 controls supported by the driver */
@@ -337,9 +337,6 @@ static int sd_start(struct gspca_dev *gspca_dev)
int ret, value;
/* create the JPEG header */
- sd->jpeg_hdr = kmalloc(JPEG_HDR_SZ, GFP_KERNEL);
- if (!sd->jpeg_hdr)
- return -ENOMEM;
jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width,
0x22); /* JPEG 411 */
jpeg_set_qual(sd->jpeg_hdr, sd->quality);
@@ -412,13 +409,6 @@ static void sd_stopN(struct gspca_dev *gspca_dev)
PDEBUG(D_STREAM, "camera stopped");
}
-static void sd_stop0(struct gspca_dev *gspca_dev)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- kfree(sd->jpeg_hdr);
-}
-
static void sd_pkt_scan(struct gspca_dev *gspca_dev,
u8 *data, /* isoc packet */
int len) /* iso packet length */
@@ -578,7 +568,6 @@ static const struct sd_desc sd_desc = {
.init = sd_init,
.start = sd_start,
.stopN = sd_stopN,
- .stop0 = sd_stop0,
.pkt_scan = sd_pkt_scan,
.querymenu = sd_querymenu,
.get_jcomp = sd_get_jcomp,
diff --git a/drivers/media/video/gspca/stv06xx/stv06xx.h b/drivers/media/video/gspca/stv06xx/stv06xx.h
index 992ce530f13..053a27e3a40 100644
--- a/drivers/media/video/gspca/stv06xx/stv06xx.h
+++ b/drivers/media/video/gspca/stv06xx/stv06xx.h
@@ -30,6 +30,7 @@
#ifndef STV06XX_H_
#define STV06XX_H_
+#include <linux/slab.h>
#include "gspca.h"
#define MODULE_NAME "STV06xx"
diff --git a/drivers/media/video/gspca/sunplus.c b/drivers/media/video/gspca/sunplus.c
index 0c786e00ebc..9494f86b9a8 100644
--- a/drivers/media/video/gspca/sunplus.c
+++ b/drivers/media/video/gspca/sunplus.c
@@ -54,7 +54,7 @@ struct sd {
#define MegapixV4 4
#define MegaImageVI 5
- u8 *jpeg_hdr;
+ u8 jpeg_hdr[JPEG_HDR_SZ];
};
/* V4L2 controls supported by the driver */
@@ -805,7 +805,7 @@ static int sd_init(struct gspca_dev *gspca_dev)
/* Set AE AWB Banding Type 3-> 50Hz 2-> 60Hz */
spca504A_acknowledged_command(gspca_dev, 0x24,
8, 3, 0x9e, 1);
- /* Twice sequencial need status 0xff->0x9e->0x9d */
+ /* Twice sequential need status 0xff->0x9e->0x9d */
spca504A_acknowledged_command(gspca_dev, 0x24,
8, 3, 0x9e, 0);
@@ -842,9 +842,6 @@ static int sd_start(struct gspca_dev *gspca_dev)
int enable;
/* create the JPEG header */
- sd->jpeg_hdr = kmalloc(JPEG_HDR_SZ, GFP_KERNEL);
- if (!sd->jpeg_hdr)
- return -ENOMEM;
jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width,
0x22); /* JPEG 411 */
jpeg_set_qual(sd->jpeg_hdr, sd->quality);
@@ -880,7 +877,7 @@ static int sd_start(struct gspca_dev *gspca_dev)
/* Set AE AWB Banding Type 3-> 50Hz 2-> 60Hz */
spca504A_acknowledged_command(gspca_dev, 0x24,
8, 3, 0x9e, 1);
- /* Twice sequencial need status 0xff->0x9e->0x9d */
+ /* Twice sequential need status 0xff->0x9e->0x9d */
spca504A_acknowledged_command(gspca_dev, 0x24,
8, 3, 0x9e, 0);
spca504A_acknowledged_command(gspca_dev, 0x24,
@@ -954,13 +951,6 @@ static void sd_stopN(struct gspca_dev *gspca_dev)
}
}
-static void sd_stop0(struct gspca_dev *gspca_dev)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- kfree(sd->jpeg_hdr);
-}
-
static void sd_pkt_scan(struct gspca_dev *gspca_dev,
u8 *data, /* isoc packet */
int len) /* iso packet length */
@@ -1162,7 +1152,6 @@ static const struct sd_desc sd_desc = {
.init = sd_init,
.start = sd_start,
.stopN = sd_stopN,
- .stop0 = sd_stop0,
.pkt_scan = sd_pkt_scan,
.get_jcomp = sd_get_jcomp,
.set_jcomp = sd_set_jcomp,
diff --git a/drivers/media/video/gspca/t613.c b/drivers/media/video/gspca/t613.c
index 63014372adb..2a0f12d55e4 100644
--- a/drivers/media/video/gspca/t613.c
+++ b/drivers/media/video/gspca/t613.c
@@ -1,5 +1,7 @@
/*
- * V4L2 by Jean-Francois Moine <http://moinejf.free.fr>
+ * T613 subdriver
+ *
+ * Copyright (C) 2010 Jean-Francois Moine (http://moinejf.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
@@ -26,6 +28,7 @@
#define MODULE_NAME "t613"
+#include <linux/slab.h>
#include "gspca.h"
#define V4L2_CID_EFFECTS (V4L2_CID_PRIVATE_BASE + 0)
@@ -44,18 +47,20 @@ struct sd {
u8 gamma;
u8 sharpness;
u8 freq;
- u8 red_balance; /* split balance */
- u8 blue_balance;
- u8 global_gain; /* aka gain */
- u8 whitebalance; /* set default r/g/b and activate */
+ u8 red_gain;
+ u8 blue_gain;
+ u8 green_gain;
+ u8 awb; /* set default r/g/b and activate */
u8 mirror;
u8 effect;
u8 sensor;
-#define SENSOR_OM6802 0
-#define SENSOR_OTHER 1
-#define SENSOR_TAS5130A 2
-#define SENSOR_LT168G 3 /* must verify if this is the actual model */
+enum {
+ SENSOR_OM6802,
+ SENSOR_OTHER,
+ SENSOR_TAS5130A,
+ SENSOR_LT168G, /* must verify if this is the actual model */
+} sensors;
};
/* V4L2 controls supported by the driver */
@@ -74,24 +79,22 @@ static int sd_getsharpness(struct gspca_dev *gspca_dev, __s32 *val);
static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val);
static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val);
-
-static int sd_setwhitebalance(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_getwhitebalance(struct gspca_dev *gspca_dev, __s32 *val);
-static int sd_setblue_balance(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_getblue_balance(struct gspca_dev *gspca_dev, __s32 *val);
-static int sd_setred_balance(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_getred_balance(struct gspca_dev *gspca_dev, __s32 *val);
-static int sd_setglobal_gain(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_getglobal_gain(struct gspca_dev *gspca_dev, __s32 *val);
-
-static int sd_setflip(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_getflip(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setawb(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getawb(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setblue_gain(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getblue_gain(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setred_gain(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getred_gain(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val);
+
+static int sd_setmirror(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getmirror(struct gspca_dev *gspca_dev, __s32 *val);
static int sd_seteffect(struct gspca_dev *gspca_dev, __s32 val);
static int sd_geteffect(struct gspca_dev *gspca_dev, __s32 *val);
static int sd_querymenu(struct gspca_dev *gspca_dev,
struct v4l2_querymenu *menu);
-
static const struct ctrl sd_ctrls[] = {
{
{
@@ -177,8 +180,8 @@ static const struct ctrl sd_ctrls[] = {
#define MIRROR_DEF 0
.default_value = MIRROR_DEF,
},
- .set = sd_setflip,
- .get = sd_getflip
+ .set = sd_setmirror,
+ .get = sd_getmirror
},
{
{
@@ -198,15 +201,15 @@ static const struct ctrl sd_ctrls[] = {
{
.id = V4L2_CID_AUTO_WHITE_BALANCE,
.type = V4L2_CTRL_TYPE_INTEGER,
- .name = "White Balance",
+ .name = "Auto White Balance",
.minimum = 0,
.maximum = 1,
.step = 1,
-#define WHITE_BALANCE_DEF 0
- .default_value = WHITE_BALANCE_DEF,
+#define AWB_DEF 0
+ .default_value = AWB_DEF,
},
- .set = sd_setwhitebalance,
- .get = sd_getwhitebalance
+ .set = sd_setawb,
+ .get = sd_getawb
},
{
{
@@ -244,11 +247,11 @@ static const struct ctrl sd_ctrls[] = {
.minimum = 0x10,
.maximum = 0x40,
.step = 1,
-#define BLUE_BALANCE_DEF 0x20
- .default_value = BLUE_BALANCE_DEF,
+#define BLUE_GAIN_DEF 0x20
+ .default_value = BLUE_GAIN_DEF,
},
- .set = sd_setblue_balance,
- .get = sd_getblue_balance,
+ .set = sd_setblue_gain,
+ .get = sd_getblue_gain,
},
{
{
@@ -258,11 +261,11 @@ static const struct ctrl sd_ctrls[] = {
.minimum = 0x10,
.maximum = 0x40,
.step = 1,
-#define RED_BALANCE_DEF 0x20
- .default_value = RED_BALANCE_DEF,
+#define RED_GAIN_DEF 0x20
+ .default_value = RED_GAIN_DEF,
},
- .set = sd_setred_balance,
- .get = sd_getred_balance,
+ .set = sd_setred_gain,
+ .get = sd_getred_gain,
},
{
{
@@ -272,24 +275,14 @@ static const struct ctrl sd_ctrls[] = {
.minimum = 0x10,
.maximum = 0x40,
.step = 1,
-#define global_gain_DEF 0x20
- .default_value = global_gain_DEF,
+#define GAIN_DEF 0x20
+ .default_value = GAIN_DEF,
},
- .set = sd_setglobal_gain,
- .get = sd_getglobal_gain,
+ .set = sd_setgain,
+ .get = sd_getgain,
},
};
-static char *effects_control[] = {
- "Normal",
- "Emboss", /* disabled */
- "Monochrome",
- "Sepia",
- "Sketch",
- "Sun Effect", /* disabled */
- "Negative",
-};
-
static const struct v4l2_pix_format vga_mode_t16[] = {
{160, 120, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
.bytesperline = 160,
@@ -327,7 +320,6 @@ struct additional_sensor_data {
const u8 data1[10];
const u8 data2[9];
const u8 data3[9];
- const u8 data4[4];
const u8 data5[6];
const u8 stream[4];
};
@@ -375,7 +367,7 @@ static const u8 n4_lt168g[] = {
};
static const struct additional_sensor_data sensor_data[] = {
- { /* 0: OM6802 */
+[SENSOR_OM6802] = {
.n3 =
{0x61, 0x68, 0x65, 0x0a, 0x60, 0x04},
.n4 = n4_om6802,
@@ -392,14 +384,12 @@ static const struct additional_sensor_data sensor_data[] = {
.data3 =
{0x80, 0xff, 0xff, 0x80, 0xff, 0xff, 0x80, 0xff,
0xff},
- .data4 = /*Freq (50/60Hz). Splitted for test purpose */
- {0x66, 0xca, 0xa8, 0xf0},
.data5 = /* this could be removed later */
{0x0c, 0x03, 0xab, 0x13, 0x81, 0x23},
.stream =
{0x0b, 0x04, 0x0a, 0x78},
},
- { /* 1: OTHER */
+[SENSOR_OTHER] = {
.n3 =
{0x61, 0xc2, 0x65, 0x88, 0x60, 0x00},
.n4 = n4_other,
@@ -416,14 +406,12 @@ static const struct additional_sensor_data sensor_data[] = {
.data3 =
{0x4e, 0x9c, 0xec, 0x40, 0x80, 0xc0, 0x48, 0x96,
0xd9},
- .data4 =
- {0x66, 0x00, 0xa8, 0xa8},
.data5 =
{0x0c, 0x03, 0xab, 0x29, 0x81, 0x69},
.stream =
{0x0b, 0x04, 0x0a, 0x00},
},
- { /* 2: TAS5130A */
+[SENSOR_TAS5130A] = {
.n3 =
{0x61, 0xc2, 0x65, 0x0d, 0x60, 0x08},
.n4 = n4_tas5130a,
@@ -440,14 +428,12 @@ static const struct additional_sensor_data sensor_data[] = {
.data3 =
{0x60, 0xa8, 0xe0, 0x60, 0xa8, 0xe0, 0x60, 0xa8,
0xe0},
- .data4 = /* Freq (50/60Hz). Splitted for test purpose */
- {0x66, 0x00, 0xa8, 0xe8},
.data5 =
{0x0c, 0x03, 0xab, 0x10, 0x81, 0x20},
.stream =
{0x0b, 0x04, 0x0a, 0x40},
},
- { /* 3: LT168G */
+[SENSOR_LT168G] = {
.n3 = {0x61, 0xc2, 0x65, 0x68, 0x60, 0x00},
.n4 = n4_lt168g,
.n4sz = sizeof n4_lt168g,
@@ -460,7 +446,6 @@ static const struct additional_sensor_data sensor_data[] = {
0xff},
.data3 = {0x40, 0x80, 0xc0, 0x50, 0xa0, 0xf0, 0x53, 0xa6,
0xff},
- .data4 = {0x66, 0x41, 0xa8, 0xf0},
.data5 = {0x0c, 0x03, 0xab, 0x4b, 0x81, 0x2b},
.stream = {0x0b, 0x04, 0x0a, 0x28},
},
@@ -469,6 +454,15 @@ static const struct additional_sensor_data sensor_data[] = {
#define MAX_EFFECTS 7
/* easily done by soft, this table could be removed,
* i keep it here just in case */
+static char *effects_control[MAX_EFFECTS] = {
+ "Normal",
+ "Emboss", /* disabled */
+ "Monochrome",
+ "Sepia",
+ "Sketch",
+ "Sun Effect", /* disabled */
+ "Negative",
+};
static const u8 effects_table[MAX_EFFECTS][6] = {
{0xa8, 0xe8, 0xc6, 0xd2, 0xc0, 0x00}, /* Normal */
{0xa8, 0xc8, 0xc6, 0x52, 0xc0, 0x04}, /* Repujar */
@@ -480,40 +474,41 @@ static const u8 effects_table[MAX_EFFECTS][6] = {
};
static const u8 gamma_table[GAMMA_MAX][17] = {
- {0x00, 0x3e, 0x69, 0x85, 0x95, 0xa1, 0xae, 0xb9, /* 0 */
- 0xc2, 0xcb, 0xd4, 0xdb, 0xe3, 0xea, 0xf1, 0xf8,
+/* gamma table from cam1690.ini */
+ {0x00, 0x00, 0x01, 0x04, 0x08, 0x0e, 0x16, 0x21, /* 0 */
+ 0x2e, 0x3d, 0x50, 0x65, 0x7d, 0x99, 0xb8, 0xdb,
0xff},
- {0x00, 0x33, 0x5a, 0x75, 0x85, 0x93, 0xa1, 0xad, /* 1 */
- 0xb7, 0xc2, 0xcb, 0xd4, 0xde, 0xe7, 0xf0, 0xf7,
+ {0x00, 0x01, 0x03, 0x08, 0x0e, 0x16, 0x21, 0x2d, /* 1 */
+ 0x3c, 0x4d, 0x60, 0x75, 0x8d, 0xa6, 0xc2, 0xe1,
0xff},
- {0x00, 0x2f, 0x51, 0x6b, 0x7c, 0x8a, 0x99, 0xa6, /* 2 */
- 0xb1, 0xbc, 0xc6, 0xd0, 0xdb, 0xe4, 0xed, 0xf6,
+ {0x00, 0x01, 0x05, 0x0b, 0x12, 0x1c, 0x28, 0x35, /* 2 */
+ 0x45, 0x56, 0x69, 0x7e, 0x95, 0xad, 0xc7, 0xe3,
0xff},
- {0x00, 0x29, 0x48, 0x60, 0x72, 0x81, 0x90, 0x9e, /* 3 */
- 0xaa, 0xb5, 0xbf, 0xcb, 0xd6, 0xe1, 0xeb, 0xf5,
+ {0x00, 0x02, 0x07, 0x0f, 0x18, 0x24, 0x30, 0x3f, /* 3 */
+ 0x4f, 0x61, 0x73, 0x88, 0x9d, 0xb4, 0xcd, 0xe6,
0xff},
- {0x00, 0x23, 0x3f, 0x55, 0x68, 0x77, 0x86, 0x95, /* 4 */
- 0xa2, 0xad, 0xb9, 0xc6, 0xd2, 0xde, 0xe9, 0xf4,
+ {0x00, 0x04, 0x0B, 0x15, 0x20, 0x2d, 0x3b, 0x4a, /* 4 */
+ 0x5b, 0x6c, 0x7f, 0x92, 0xa7, 0xbc, 0xd2, 0xe9,
0xff},
- {0x00, 0x1b, 0x33, 0x48, 0x59, 0x69, 0x79, 0x87, /* 5 */
- 0x96, 0xa3, 0xb1, 0xbe, 0xcc, 0xda, 0xe7, 0xf3,
+ {0x00, 0x07, 0x11, 0x15, 0x20, 0x2d, 0x48, 0x58, /* 5 */
+ 0x68, 0x79, 0x8b, 0x9d, 0xb0, 0xc4, 0xd7, 0xec,
0xff},
- {0x00, 0x02, 0x10, 0x20, 0x32, 0x40, 0x57, 0x67, /* 6 */
+ {0x00, 0x0c, 0x1a, 0x29, 0x38, 0x47, 0x57, 0x67, /* 6 */
0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee,
0xff},
- {0x00, 0x02, 0x14, 0x26, 0x38, 0x4a, 0x60, 0x70, /* 7 */
+ {0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, /* 7 */
0x80, 0x90, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0,
0xff},
- {0x00, 0x10, 0x22, 0x35, 0x47, 0x5a, 0x69, 0x79, /* 8 */
- 0x88, 0x97, 0xa7, 0xb6, 0xc4, 0xd3, 0xe0, 0xf0,
+ {0x00, 0x15, 0x27, 0x38, 0x49, 0x59, 0x69, 0x79, /* 8 */
+ 0x88, 0x97, 0xa7, 0xb6, 0xc4, 0xd3, 0xe2, 0xf0,
0xff},
- {0x00, 0x10, 0x26, 0x40, 0x54, 0x65, 0x75, 0x84, /* 9 */
- 0x93, 0xa1, 0xb0, 0xbd, 0xca, 0xd6, 0xe0, 0xf0,
+ {0x00, 0x1c, 0x30, 0x43, 0x54, 0x65, 0x75, 0x84, /* 9 */
+ 0x93, 0xa1, 0xb0, 0xbd, 0xca, 0xd8, 0xe5, 0xf2,
0xff},
- {0x00, 0x18, 0x2b, 0x44, 0x60, 0x70, 0x80, 0x8e, /* 10 */
- 0x9c, 0xaa, 0xb7, 0xc4, 0xd0, 0xd8, 0xe2, 0xf0,
+ {0x00, 0x24, 0x3b, 0x4f, 0x60, 0x70, 0x80, 0x8e, /* 10 */
+ 0x9c, 0xaa, 0xb7, 0xc4, 0xd0, 0xdc, 0xe8, 0xf3,
0xff},
- {0x00, 0x1a, 0x34, 0x52, 0x66, 0x7e, 0x8d, 0x9b, /* 11 */
+ {0x00, 0x2a, 0x3c, 0x5d, 0x6e, 0x7e, 0x8d, 0x9b, /* 11 */
0xa8, 0xb4, 0xc0, 0xcb, 0xd6, 0xe1, 0xeb, 0xf5,
0xff},
{0x00, 0x3f, 0x5a, 0x6e, 0x7f, 0x8e, 0x9c, 0xa8, /* 12 */
@@ -577,12 +572,11 @@ static void reg_w_buf(struct gspca_dev *gspca_dev,
} else {
u8 *tmpbuf;
- tmpbuf = kmalloc(len, GFP_KERNEL);
+ tmpbuf = kmemdup(buffer, len, GFP_KERNEL);
if (!tmpbuf) {
err("Out of memory");
return;
}
- memcpy(tmpbuf, buffer, len);
usb_control_msg(gspca_dev->dev,
usb_sndctrlpipe(gspca_dev->dev, 0),
0,
@@ -625,7 +619,6 @@ static void reg_w_ixbuf(struct gspca_dev *gspca_dev,
kfree(tmpbuf);
}
-/* Reported as OM6802*/
static void om6802_sensor_init(struct gspca_dev *gspca_dev)
{
int i;
@@ -703,12 +696,12 @@ static int sd_config(struct gspca_dev *gspca_dev,
sd->autogain = AUTOGAIN_DEF;
sd->mirror = MIRROR_DEF;
sd->freq = FREQ_DEF;
- sd->whitebalance = WHITE_BALANCE_DEF;
+ sd->awb = AWB_DEF;
sd->sharpness = SHARPNESS_DEF;
sd->effect = EFFECTS_DEF;
- sd->red_balance = RED_BALANCE_DEF;
- sd->blue_balance = BLUE_BALANCE_DEF;
- sd->global_gain = global_gain_DEF;
+ sd->red_gain = RED_GAIN_DEF;
+ sd->blue_gain = BLUE_GAIN_DEF;
+ sd->green_gain = GAIN_DEF * 3 - RED_GAIN_DEF - BLUE_GAIN_DEF;
return 0;
}
@@ -761,40 +754,59 @@ static void setgamma(struct gspca_dev *gspca_dev)
reg_w_ixbuf(gspca_dev, 0x90,
gamma_table[sd->gamma], sizeof gamma_table[0]);
}
-static void setglobalgain(struct gspca_dev *gspca_dev)
-{
+static void setRGB(struct gspca_dev *gspca_dev)
+{
struct sd *sd = (struct sd *) gspca_dev;
- reg_w(gspca_dev, (sd->red_balance << 8) + 0x87);
- reg_w(gspca_dev, (sd->blue_balance << 8) + 0x88);
- reg_w(gspca_dev, (sd->global_gain << 8) + 0x89);
+ u8 all_gain_reg[6] =
+ {0x87, 0x00, 0x88, 0x00, 0x89, 0x00};
+
+ all_gain_reg[1] = sd->red_gain;
+ all_gain_reg[3] = sd->blue_gain;
+ all_gain_reg[5] = sd->green_gain;
+ reg_w_buf(gspca_dev, all_gain_reg, sizeof all_gain_reg);
}
-/* Generic fnc for r/b balance, exposure and whitebalance */
-static void setbalance(struct gspca_dev *gspca_dev)
+/* Generic fnc for r/b balance, exposure and awb */
+static void setawb(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
+ u16 reg80;
- /* on whitebalance leave defaults values */
- if (sd->whitebalance) {
- reg_w(gspca_dev, 0x3c80);
- } else {
- reg_w(gspca_dev, 0x3880);
+ reg80 = (sensor_data[sd->sensor].reg80 << 8) | 0x80;
+
+ /* on awb leave defaults values */
+ if (!sd->awb) {
/* shoud we wait here.. */
- /* update and reset 'global gain' with webcam parameters */
- sd->red_balance = reg_r(gspca_dev, 0x0087);
- sd->blue_balance = reg_r(gspca_dev, 0x0088);
- sd->global_gain = reg_r(gspca_dev, 0x0089);
- setglobalgain(gspca_dev);
+ /* update and reset RGB gains with webcam values */
+ sd->red_gain = reg_r(gspca_dev, 0x0087);
+ sd->blue_gain = reg_r(gspca_dev, 0x0088);
+ sd->green_gain = reg_r(gspca_dev, 0x0089);
+ reg80 &= ~0x0400; /* AWB off */
}
-
+ reg_w(gspca_dev, reg80);
+ reg_w(gspca_dev, reg80);
}
-
-
-static void setwhitebalance(struct gspca_dev *gspca_dev)
+static void init_gains(struct gspca_dev *gspca_dev)
{
- setbalance(gspca_dev);
+ struct sd *sd = (struct sd *) gspca_dev;
+ u16 reg80;
+ u8 all_gain_reg[8] =
+ {0x87, 0x00, 0x88, 0x00, 0x89, 0x00, 0x80, 0x00};
+
+ all_gain_reg[1] = sd->red_gain;
+ all_gain_reg[3] = sd->blue_gain;
+ all_gain_reg[5] = sd->green_gain;
+ reg80 = sensor_data[sd->sensor].reg80;
+ if (!sd->awb)
+ reg80 &= ~0x04;
+ all_gain_reg[7] = reg80;
+ reg_w_buf(gspca_dev, all_gain_reg, sizeof all_gain_reg);
+
+ reg_w(gspca_dev, (sd->red_gain << 8) + 0x87);
+ reg_w(gspca_dev, (sd->blue_gain << 8) + 0x88);
+ reg_w(gspca_dev, (sd->green_gain << 8) + 0x89);
}
static void setsharpness(struct gspca_dev *gspca_dev)
@@ -807,6 +819,38 @@ static void setsharpness(struct gspca_dev *gspca_dev)
reg_w(gspca_dev, reg_to_write);
}
+static void setfreq(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ u8 reg66;
+ u8 freq[4] = { 0x66, 0x00, 0xa8, 0xe8 };
+
+ switch (sd->sensor) {
+ case SENSOR_LT168G:
+ if (sd->freq != 0)
+ freq[3] = 0xa8;
+ reg66 = 0x41;
+ break;
+ case SENSOR_OM6802:
+ reg66 = 0xca;
+ break;
+ default:
+ reg66 = 0x40;
+ break;
+ }
+ switch (sd->freq) {
+ case 0: /* no flicker */
+ freq[3] = 0xf0;
+ break;
+ case 2: /* 60Hz */
+ reg66 &= ~0x40;
+ break;
+ }
+ freq[1] = reg66;
+
+ reg_w_buf(gspca_dev, freq, sizeof freq);
+}
+
/* this function is called at probe and resume time */
static int sd_init(struct gspca_dev *gspca_dev)
{
@@ -901,13 +945,9 @@ static int sd_init(struct gspca_dev *gspca_dev)
setgamma(gspca_dev);
setcolors(gspca_dev);
setsharpness(gspca_dev);
- setwhitebalance(gspca_dev);
-
- reg_w(gspca_dev, 0x2087); /* tied to white balance? */
- reg_w(gspca_dev, 0x2088);
- reg_w(gspca_dev, 0x2089);
+ init_gains(gspca_dev);
+ setfreq(gspca_dev);
- reg_w_buf(gspca_dev, sensor->data4, sizeof sensor->data4);
reg_w_buf(gspca_dev, sensor->data5, sizeof sensor->data5);
reg_w_buf(gspca_dev, sensor->nset8, sizeof sensor->nset8);
reg_w_buf(gspca_dev, sensor->stream, sizeof sensor->stream);
@@ -926,16 +966,16 @@ static int sd_init(struct gspca_dev *gspca_dev)
return 0;
}
-static void setflip(struct gspca_dev *gspca_dev)
+static void setmirror(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
- u8 flipcmd[8] =
+ u8 hflipcmd[8] =
{0x62, 0x07, 0x63, 0x03, 0x64, 0x00, 0x60, 0x09};
if (sd->mirror)
- flipcmd[3] = 0x01;
+ hflipcmd[3] = 0x01;
- reg_w_buf(gspca_dev, flipcmd, sizeof flipcmd);
+ reg_w_buf(gspca_dev, hflipcmd, sizeof hflipcmd);
}
static void seteffect(struct gspca_dev *gspca_dev)
@@ -956,17 +996,6 @@ static void seteffect(struct gspca_dev *gspca_dev)
reg_w(gspca_dev, 0xfaa6);
}
-static void setlightfreq(struct gspca_dev *gspca_dev)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- u8 freq[4] = { 0x66, 0x40, 0xa8, 0xe8 };
-
- if (sd->freq == 2) /* 60hz */
- freq[1] = 0x00;
-
- reg_w_buf(gspca_dev, freq, sizeof freq);
-}
-
/* Is this really needed?
* i added some module parameters for test with some users */
static void poll_sensor(struct gspca_dev *gspca_dev)
@@ -979,9 +1008,7 @@ static void poll_sensor(struct gspca_dev *gspca_dev)
static const u8 poll2[] =
{0x67, 0x02, 0x68, 0x71, 0x69, 0x72, 0x72, 0xa9,
0x73, 0x02, 0x73, 0x02, 0x60, 0x14};
- static const u8 poll3[] =
- {0x87, 0x3f, 0x88, 0x20, 0x89, 0x2d};
- static const u8 poll4[] =
+ static const u8 noise03[] = /* (some differences / ms-drv) */
{0xa6, 0x0a, 0xea, 0xcf, 0xbe, 0x26, 0xb1, 0x5f,
0xa1, 0xb1, 0xda, 0x6b, 0xdb, 0x98, 0xdf, 0x0c,
0xc2, 0x80, 0xc3, 0x10};
@@ -989,8 +1016,7 @@ static void poll_sensor(struct gspca_dev *gspca_dev)
PDEBUG(D_STREAM, "[Sensor requires polling]");
reg_w_buf(gspca_dev, poll1, sizeof poll1);
reg_w_buf(gspca_dev, poll2, sizeof poll2);
- reg_w_buf(gspca_dev, poll3, sizeof poll3);
- reg_w_buf(gspca_dev, poll4, sizeof poll4);
+ reg_w_buf(gspca_dev, noise03, sizeof noise03);
}
static int sd_start(struct gspca_dev *gspca_dev)
@@ -1025,12 +1051,7 @@ static int sd_start(struct gspca_dev *gspca_dev)
case SENSOR_OM6802:
om6802_sensor_init(gspca_dev);
break;
- case SENSOR_LT168G:
- break;
- case SENSOR_OTHER:
- break;
- default:
-/* case SENSOR_TAS5130A: */
+ case SENSOR_TAS5130A:
i = 0;
for (;;) {
reg_w_buf(gspca_dev, tas5130a_sensor_init[i],
@@ -1047,7 +1068,7 @@ static int sd_start(struct gspca_dev *gspca_dev)
break;
}
sensor = &sensor_data[sd->sensor];
- reg_w_buf(gspca_dev, sensor->data4, sizeof sensor->data4);
+ setfreq(gspca_dev);
reg_r(gspca_dev, 0x0012);
reg_w_buf(gspca_dev, t2, sizeof t2);
reg_w_ixbuf(gspca_dev, 0xb3, t3, sizeof t3);
@@ -1080,7 +1101,7 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
u8 *data, /* isoc packet */
int len) /* iso packet length */
{
- static u8 ffd9[] = { 0xff, 0xd9 };
+ int pkt_type;
if (data[0] == 0x5a) {
/* Control Packet, after this came the header again,
@@ -1090,84 +1111,88 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
}
data += 2;
len -= 2;
- if (data[0] == 0xff && data[1] == 0xd8) {
- /* extra bytes....., could be processed too but would be
- * a waste of time, right now leave the application and
- * libjpeg do it for ourserlves.. */
- gspca_frame_add(gspca_dev, LAST_PACKET,
- ffd9, 2);
- gspca_frame_add(gspca_dev, FIRST_PACKET, data, len);
- return;
- }
-
- if (data[len - 2] == 0xff && data[len - 1] == 0xd9) {
- /* Just in case, i have seen packets with the marker,
- * other's do not include it... */
- len -= 2;
- }
- gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
+ if (data[0] == 0xff && data[1] == 0xd8)
+ pkt_type = FIRST_PACKET;
+ else if (data[len - 2] == 0xff && data[len - 1] == 0xd9)
+ pkt_type = LAST_PACKET;
+ else
+ pkt_type = INTER_PACKET;
+ gspca_frame_add(gspca_dev, pkt_type, data, len);
}
-
-static int sd_setblue_balance(struct gspca_dev *gspca_dev, __s32 val)
+static int sd_setblue_gain(struct gspca_dev *gspca_dev, __s32 val)
{
struct sd *sd = (struct sd *) gspca_dev;
- sd->blue_balance = val;
+ sd->blue_gain = val;
if (gspca_dev->streaming)
reg_w(gspca_dev, (val << 8) + 0x88);
return 0;
}
-static int sd_getblue_balance(struct gspca_dev *gspca_dev, __s32 *val)
+static int sd_getblue_gain(struct gspca_dev *gspca_dev, __s32 *val)
{
struct sd *sd = (struct sd *) gspca_dev;
- *val = sd->blue_balance;
+ *val = sd->blue_gain;
return 0;
}
-static int sd_setred_balance(struct gspca_dev *gspca_dev, __s32 val)
+static int sd_setred_gain(struct gspca_dev *gspca_dev, __s32 val)
{
struct sd *sd = (struct sd *) gspca_dev;
- sd->red_balance = val;
+ sd->red_gain = val;
if (gspca_dev->streaming)
reg_w(gspca_dev, (val << 8) + 0x87);
return 0;
}
-static int sd_getred_balance(struct gspca_dev *gspca_dev, __s32 *val)
+static int sd_getred_gain(struct gspca_dev *gspca_dev, __s32 *val)
{
struct sd *sd = (struct sd *) gspca_dev;
- *val = sd->red_balance;
+ *val = sd->red_gain;
return 0;
}
-
-
-static int sd_setglobal_gain(struct gspca_dev *gspca_dev, __s32 val)
+static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val)
{
struct sd *sd = (struct sd *) gspca_dev;
+ u16 psg, nsg;
+
+ psg = sd->red_gain + sd->blue_gain + sd->green_gain;
+ nsg = val * 3;
+ sd->red_gain = sd->red_gain * nsg / psg;
+ if (sd->red_gain > 0x40)
+ sd->red_gain = 0x40;
+ else if (sd->red_gain < 0x10)
+ sd->red_gain = 0x10;
+ sd->blue_gain = sd->blue_gain * nsg / psg;
+ if (sd->blue_gain > 0x40)
+ sd->blue_gain = 0x40;
+ else if (sd->blue_gain < 0x10)
+ sd->blue_gain = 0x10;
+ sd->green_gain = sd->green_gain * nsg / psg;
+ if (sd->green_gain > 0x40)
+ sd->green_gain = 0x40;
+ else if (sd->green_gain < 0x10)
+ sd->green_gain = 0x10;
- sd->global_gain = val;
if (gspca_dev->streaming)
- setglobalgain(gspca_dev);
-
+ setRGB(gspca_dev);
return 0;
}
-static int sd_getglobal_gain(struct gspca_dev *gspca_dev, __s32 *val)
+static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val)
{
struct sd *sd = (struct sd *) gspca_dev;
- *val = sd->global_gain;
+ *val = (sd->red_gain + sd->blue_gain + sd->green_gain) / 3;
return 0;
}
-
static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
{
struct sd *sd = (struct sd *) gspca_dev;
@@ -1186,35 +1211,35 @@ static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
return *val;
}
-static int sd_setwhitebalance(struct gspca_dev *gspca_dev, __s32 val)
+static int sd_setawb(struct gspca_dev *gspca_dev, __s32 val)
{
struct sd *sd = (struct sd *) gspca_dev;
- sd->whitebalance = val;
+ sd->awb = val;
if (gspca_dev->streaming)
- setwhitebalance(gspca_dev);
+ setawb(gspca_dev);
return 0;
}
-static int sd_getwhitebalance(struct gspca_dev *gspca_dev, __s32 *val)
+static int sd_getawb(struct gspca_dev *gspca_dev, __s32 *val)
{
struct sd *sd = (struct sd *) gspca_dev;
- *val = sd->whitebalance;
+ *val = sd->awb;
return *val;
}
-static int sd_setflip(struct gspca_dev *gspca_dev, __s32 val)
+static int sd_setmirror(struct gspca_dev *gspca_dev, __s32 val)
{
struct sd *sd = (struct sd *) gspca_dev;
sd->mirror = val;
if (gspca_dev->streaming)
- setflip(gspca_dev);
+ setmirror(gspca_dev);
return 0;
}
-static int sd_getflip(struct gspca_dev *gspca_dev, __s32 *val)
+static int sd_getmirror(struct gspca_dev *gspca_dev, __s32 *val)
{
struct sd *sd = (struct sd *) gspca_dev;
@@ -1300,7 +1325,7 @@ static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val)
sd->freq = val;
if (gspca_dev->streaming)
- setlightfreq(gspca_dev);
+ setfreq(gspca_dev);
return 0;
}
@@ -1368,7 +1393,8 @@ static int sd_querymenu(struct gspca_dev *gspca_dev,
case V4L2_CID_EFFECTS:
if ((unsigned) menu->index < ARRAY_SIZE(effects_control)) {
strncpy((char *) menu->name,
- effects_control[menu->index], 32);
+ effects_control[menu->index],
+ sizeof menu->name);
return 0;
}
break;
diff --git a/drivers/media/video/gspca/tv8532.c b/drivers/media/video/gspca/tv8532.c
index c7b6eb1e04d..d9c5bf3449d 100644
--- a/drivers/media/video/gspca/tv8532.c
+++ b/drivers/media/video/gspca/tv8532.c
@@ -30,29 +30,46 @@ MODULE_LICENSE("GPL");
struct sd {
struct gspca_dev gspca_dev; /* !! must be the first item */
- __u16 brightness;
+ __u16 exposure;
+ __u16 gain;
__u8 packet;
};
/* V4L2 controls supported by the driver */
-static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val);
static const struct ctrl sd_ctrls[] = {
{
{
- .id = V4L2_CID_BRIGHTNESS,
+ .id = V4L2_CID_EXPOSURE,
.type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Brightness",
+ .name = "Exposure",
.minimum = 1,
- .maximum = 0x15f, /* = 352 - 1 */
+ .maximum = 0x18f,
.step = 1,
-#define BRIGHTNESS_DEF 0x14c
- .default_value = BRIGHTNESS_DEF,
+#define EXPOSURE_DEF 0x18f
+ .default_value = EXPOSURE_DEF,
},
- .set = sd_setbrightness,
- .get = sd_getbrightness,
+ .set = sd_setexposure,
+ .get = sd_getexposure,
+ },
+ {
+ {
+ .id = V4L2_CID_GAIN,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Gain",
+ .minimum = 0,
+ .maximum = 0x7ff,
+ .step = 1,
+#define GAIN_DEF 0x100
+ .default_value = GAIN_DEF,
+ },
+ .set = sd_setgain,
+ .get = sd_getgain,
},
};
@@ -92,6 +109,14 @@ static const struct v4l2_pix_format sif_mode[] = {
#define R14_AD_ROW_BEGINL 0x14
#define R15_AD_ROWBEGINH 0x15
#define R1C_AD_EXPOSE_TIMEL 0x1c
+#define R20_GAIN_G1L 0x20
+#define R21_GAIN_G1H 0x21
+#define R22_GAIN_RL 0x22
+#define R23_GAIN_RH 0x23
+#define R24_GAIN_BL 0x24
+#define R25_GAIN_BH 0x25
+#define R26_GAIN_G2L 0x26
+#define R27_GAIN_G2H 0x27
#define R28_QUANT 0x28
#define R29_LINE 0x29
#define R2C_POLARITY 0x2c
@@ -129,18 +154,6 @@ static const u8 eeprom_data[][3] = {
{0x05, 0x09, 0xf1},
};
-static int reg_r(struct gspca_dev *gspca_dev,
- __u16 index)
-{
- usb_control_msg(gspca_dev->dev,
- usb_rcvctrlpipe(gspca_dev->dev, 0),
- 0x03,
- USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
- 0, /* value */
- index, gspca_dev->usb_buf, 1,
- 500);
- return gspca_dev->usb_buf[0];
-}
/* write 1 byte */
static void reg_w1(struct gspca_dev *gspca_dev,
@@ -183,7 +196,6 @@ static void tv_8532WriteEEprom(struct gspca_dev *gspca_dev)
}
reg_w1(gspca_dev, R07_TABLE_LEN, i);
reg_w1(gspca_dev, R01_TIMING_CONTROL_LOW, CMD_EEprom_Close);
- msleep(10);
}
/* this function is called at probe time */
@@ -197,53 +209,13 @@ static int sd_config(struct gspca_dev *gspca_dev,
cam->cam_mode = sif_mode;
cam->nmodes = ARRAY_SIZE(sif_mode);
- sd->brightness = BRIGHTNESS_DEF;
+ sd->exposure = EXPOSURE_DEF;
+ sd->gain = GAIN_DEF;
return 0;
}
-static void tv_8532ReadRegisters(struct gspca_dev *gspca_dev)
-{
- int i;
- static u8 reg_tb[] = {
- R0C_AD_WIDTHL,
- R0D_AD_WIDTHH,
- R28_QUANT,
- R29_LINE,
- R2C_POLARITY,
- R2D_POINT,
- R2E_POINTH,
- R2F_POINTB,
- R30_POINTBH,
- R2A_HIGH_BUDGET,
- R2B_LOW_BUDGET,
- R34_VID,
- R35_VIDH,
- R36_PID,
- R37_PIDH,
- R83_AD_IDH,
- R10_AD_COL_BEGINL,
- R11_AD_COL_BEGINH,
- R14_AD_ROW_BEGINL,
- R15_AD_ROWBEGINH,
- 0
- };
-
- i = 0;
- do {
- reg_r(gspca_dev, reg_tb[i]);
- i++;
- } while (reg_tb[i] != 0);
-}
-
static void tv_8532_setReg(struct gspca_dev *gspca_dev)
{
- reg_w1(gspca_dev, R10_AD_COL_BEGINL, 0x44);
- /* begin active line */
- reg_w1(gspca_dev, R11_AD_COL_BEGINH, 0x00);
- /* mirror and digital gain */
- reg_w1(gspca_dev, R00_PART_CONTROL, LATENT_CHANGE | EXPO_CHANGE);
- /* = 0x84 */
-
reg_w1(gspca_dev, R3B_Test3, 0x0a); /* Test0Sel = 10 */
/******************************************************/
reg_w1(gspca_dev, R0E_AD_HEIGHTL, 0x90);
@@ -255,100 +227,43 @@ static void tv_8532_setReg(struct gspca_dev *gspca_dev)
/* mirror and digital gain */
reg_w1(gspca_dev, R14_AD_ROW_BEGINL, 0x0a);
- reg_w1(gspca_dev, R91_AD_SLOPEREG, 0x00);
reg_w1(gspca_dev, R94_AD_BITCONTROL, 0x02);
-
- reg_w1(gspca_dev, R01_TIMING_CONTROL_LOW, CMD_EEprom_Close);
-
reg_w1(gspca_dev, R91_AD_SLOPEREG, 0x00);
reg_w1(gspca_dev, R00_PART_CONTROL, LATENT_CHANGE | EXPO_CHANGE);
/* = 0x84 */
}
-static void tv_8532_PollReg(struct gspca_dev *gspca_dev)
-{
- int i;
-
- /* strange polling from tgc */
- for (i = 0; i < 10; i++) {
- reg_w1(gspca_dev, R2C_POLARITY, 0x10);
- reg_w1(gspca_dev, R00_PART_CONTROL,
- LATENT_CHANGE | EXPO_CHANGE);
- reg_w1(gspca_dev, R31_UPD, 0x01);
- }
-}
-
/* this function is called at probe and resume time */
static int sd_init(struct gspca_dev *gspca_dev)
{
tv_8532WriteEEprom(gspca_dev);
- reg_w1(gspca_dev, R91_AD_SLOPEREG, 0x32); /* slope begin 1,7V,
- * slope rate 2 */
- reg_w1(gspca_dev, R94_AD_BITCONTROL, 0x00);
- tv_8532ReadRegisters(gspca_dev);
- reg_w1(gspca_dev, R3B_Test3, 0x0b);
- reg_w2(gspca_dev, R0E_AD_HEIGHTL, 0x0190);
- reg_w2(gspca_dev, R1C_AD_EXPOSE_TIMEL, 0x018f);
- reg_w1(gspca_dev, R0C_AD_WIDTHL, 0xe8);
- reg_w1(gspca_dev, R0D_AD_WIDTHH, 0x03);
-
- /*******************************************************************/
- reg_w1(gspca_dev, R28_QUANT, 0x90);
- /* no compress - fixed Q - quant 0 */
- reg_w1(gspca_dev, R29_LINE, 0x81);
- /* 0x84; // CIF | 4 packet 0x29 */
-
- /************************************************/
- reg_w1(gspca_dev, R2C_POLARITY, 0x10);
- /* 0x48; //0x08; 0x2c */
- reg_w1(gspca_dev, R2D_POINT, 0x14);
- /* 0x38; 0x2d */
- reg_w1(gspca_dev, R2E_POINTH, 0x01);
- /* 0x04; 0x2e */
- reg_w1(gspca_dev, R2F_POINTB, 0x12);
- /* 0x04; 0x2f */
- reg_w1(gspca_dev, R30_POINTBH, 0x01);
- /* 0x04; 0x30 */
- reg_w1(gspca_dev, R00_PART_CONTROL, LATENT_CHANGE | EXPO_CHANGE);
- /* 0x00<-0x84 */
- /*************************************************/
- reg_w1(gspca_dev, R31_UPD, 0x01); /* update registers */
- msleep(200);
- reg_w1(gspca_dev, R31_UPD, 0x00); /* end update */
- /*************************************************/
- tv_8532_setReg(gspca_dev);
- /*************************************************/
- reg_w1(gspca_dev, R3B_Test3, 0x0b); /* Test0Sel = 11 = GPIO */
- /*************************************************/
- tv_8532_setReg(gspca_dev);
- /*************************************************/
- tv_8532_PollReg(gspca_dev);
return 0;
}
-static void setbrightness(struct gspca_dev *gspca_dev)
+static void setexposure(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
- reg_w2(gspca_dev, R1C_AD_EXPOSE_TIMEL, sd->brightness);
+ reg_w2(gspca_dev, R1C_AD_EXPOSE_TIMEL, sd->exposure);
reg_w1(gspca_dev, R00_PART_CONTROL, LATENT_CHANGE | EXPO_CHANGE);
/* 0x84 */
}
-/* -- start the camera -- */
-static int sd_start(struct gspca_dev *gspca_dev)
+static void setgain(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
- reg_w1(gspca_dev, R91_AD_SLOPEREG, 0x32); /* slope begin 1,7V,
- * slope rate 2 */
- reg_w1(gspca_dev, R94_AD_BITCONTROL, 0x00);
- tv_8532ReadRegisters(gspca_dev);
- reg_w1(gspca_dev, R3B_Test3, 0x0b);
+ reg_w2(gspca_dev, R20_GAIN_G1L, sd->gain);
+ reg_w2(gspca_dev, R22_GAIN_RL, sd->gain);
+ reg_w2(gspca_dev, R24_GAIN_BL, sd->gain);
+ reg_w2(gspca_dev, R26_GAIN_G2L, sd->gain);
+}
- reg_w2(gspca_dev, R0E_AD_HEIGHTL, 0x0190);
- setbrightness(gspca_dev);
+/* -- start the camera -- */
+static int sd_start(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
reg_w1(gspca_dev, R0C_AD_WIDTHL, 0xe8); /* 0x20; 0x0c */
reg_w1(gspca_dev, R0D_AD_WIDTHH, 0x03);
@@ -371,19 +286,15 @@ static int sd_start(struct gspca_dev *gspca_dev)
reg_w1(gspca_dev, R2E_POINTH, 0x01);
reg_w1(gspca_dev, R2F_POINTB, 0x12);
reg_w1(gspca_dev, R30_POINTBH, 0x01);
- reg_w1(gspca_dev, R00_PART_CONTROL, LATENT_CHANGE | EXPO_CHANGE);
+
+ tv_8532_setReg(gspca_dev);
+
+ setexposure(gspca_dev);
+ setgain(gspca_dev);
+
/************************************************/
reg_w1(gspca_dev, R31_UPD, 0x01); /* update registers */
msleep(200);
- reg_w1(gspca_dev, R31_UPD, 0x00); /* end update */
- /************************************************/
- tv_8532_setReg(gspca_dev);
- /************************************************/
- reg_w1(gspca_dev, R3B_Test3, 0x0b); /* Test0Sel = 11 = GPIO */
- /************************************************/
- tv_8532_setReg(gspca_dev);
- /************************************************/
- tv_8532_PollReg(gspca_dev);
reg_w1(gspca_dev, R31_UPD, 0x00); /* end update */
gspca_dev->empty_packet = 0; /* check the empty packets */
@@ -428,21 +339,39 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
data + gspca_dev->width + 5, gspca_dev->width);
}
-static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
+static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->exposure = val;
+ if (gspca_dev->streaming)
+ setexposure(gspca_dev);
+ return 0;
+}
+
+static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ *val = sd->exposure;
+ return 0;
+}
+
+static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val)
{
struct sd *sd = (struct sd *) gspca_dev;
- sd->brightness = val;
+ sd->gain = val;
if (gspca_dev->streaming)
- setbrightness(gspca_dev);
+ setgain(gspca_dev);
return 0;
}
-static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
+static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val)
{
struct sd *sd = (struct sd *) gspca_dev;
- *val = sd->brightness;
+ *val = sd->gain;
return 0;
}
diff --git a/drivers/media/video/gspca/vc032x.c b/drivers/media/video/gspca/vc032x.c
index 732c3dfe46f..031266a4081 100644
--- a/drivers/media/video/gspca/vc032x.c
+++ b/drivers/media/video/gspca/vc032x.c
@@ -2748,11 +2748,11 @@ static const u8 poxxxx_init_common[][4] = {
{0xb3, 0x04, 0x15, 0xcc},
{0xb3, 0x20, 0x00, 0xcc},
{0xb3, 0x21, 0x00, 0xcc},
- {0xb3, 0x22, 0x04, 0xcc},
+ {0xb3, 0x22, 0x04, 0xcc}, /* sensor height = 1024 */
{0xb3, 0x23, 0x00, 0xcc},
{0xb3, 0x14, 0x00, 0xcc},
{0xb3, 0x15, 0x00, 0xcc},
- {0xb3, 0x16, 0x04, 0xcc},
+ {0xb3, 0x16, 0x04, 0xcc}, /* sensor width = 1280 */
{0xb3, 0x17, 0xff, 0xcc},
{0xb3, 0x2c, 0x03, 0xcc},
{0xb3, 0x2d, 0x56, 0xcc},
@@ -2919,7 +2919,7 @@ static const u8 poxxxx_initVGA[][4] = {
{0x00, 0x20, 0x11, 0xaa},
{0x00, 0x33, 0x38, 0xaa},
{0x00, 0xbb, 0x0d, 0xaa},
- {0xb3, 0x22, 0x01, 0xcc},
+ {0xb3, 0x22, 0x01, 0xcc}, /* change to 640x480 */
{0xb3, 0x23, 0xe0, 0xcc},
{0xb3, 0x16, 0x02, 0xcc},
{0xb3, 0x17, 0x7f, 0xcc},
@@ -2935,7 +2935,7 @@ static const u8 poxxxx_initQVGA[][4] = {
{0x00, 0x20, 0x33, 0xaa},
{0x00, 0x33, 0x38, 0xaa},
{0x00, 0xbb, 0x0d, 0xaa},
- {0xb3, 0x22, 0x00, 0xcc},
+ {0xb3, 0x22, 0x00, 0xcc}, /* change to 320x240 */
{0xb3, 0x23, 0xf0, 0xcc},
{0xb3, 0x16, 0x01, 0xcc},
{0xb3, 0x17, 0x3f, 0xcc},
@@ -3068,37 +3068,84 @@ static const struct sensor_info vc0323_probe_data[] = {
};
/* read 'len' bytes in gspca_dev->usb_buf */
-static void reg_r(struct gspca_dev *gspca_dev,
+static void reg_r_i(struct gspca_dev *gspca_dev,
u16 req,
u16 index,
u16 len)
{
- usb_control_msg(gspca_dev->dev,
+ int ret;
+
+ if (gspca_dev->usb_err < 0)
+ return;
+ ret = usb_control_msg(gspca_dev->dev,
usb_rcvctrlpipe(gspca_dev->dev, 0),
req,
USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
1, /* value */
index, gspca_dev->usb_buf, len,
500);
+ if (ret < 0) {
+ PDEBUG(D_ERR, "reg_r err %d", ret);
+ gspca_dev->usb_err = ret;
+ }
+}
+static void reg_r(struct gspca_dev *gspca_dev,
+ u16 req,
+ u16 index,
+ u16 len)
+{
+ reg_r_i(gspca_dev, req, index, len);
+#ifdef GSPCA_DEBUG
+ if (gspca_dev->usb_err < 0)
+ return;
+ if (len == 1)
+ PDEBUG(D_USBI, "GET %02x 0001 %04x %02x", req, index,
+ gspca_dev->usb_buf[0]);
+ else
+ PDEBUG(D_USBI, "GET %02x 0001 %04x %02x %02x %02x",
+ req, index,
+ gspca_dev->usb_buf[0],
+ gspca_dev->usb_buf[1],
+ gspca_dev->usb_buf[2]);
+#endif
}
-static void reg_w(struct usb_device *dev,
+static void reg_w_i(struct gspca_dev *gspca_dev,
u16 req,
u16 value,
u16 index)
{
- usb_control_msg(dev,
- usb_sndctrlpipe(dev, 0),
+ int ret;
+
+ if (gspca_dev->usb_err < 0)
+ return;
+ ret = usb_control_msg(gspca_dev->dev,
+ usb_sndctrlpipe(gspca_dev->dev, 0),
req,
USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
value, index, NULL, 0,
500);
+ if (ret < 0) {
+ PDEBUG(D_ERR, "reg_w err %d", ret);
+ gspca_dev->usb_err = ret;
+ }
+}
+static void reg_w(struct gspca_dev *gspca_dev,
+ u16 req,
+ u16 value,
+ u16 index)
+{
+#ifdef GSPCA_DEBUG
+ if (gspca_dev->usb_err < 0)
+ return;
+ PDEBUG(D_USBO, "SET %02x %04x %04x", req, value, index);
+#endif
+ reg_w_i(gspca_dev, req, value, index);
}
static u16 read_sensor_register(struct gspca_dev *gspca_dev,
u16 address)
{
- struct usb_device *dev = gspca_dev->dev;
u8 ldata, mdata, hdata;
int retry = 50;
@@ -3108,8 +3155,8 @@ static u16 read_sensor_register(struct gspca_dev *gspca_dev,
gspca_dev->usb_buf[0]);
return 0;
}
- reg_w(dev, 0xa0, address, 0xb33a);
- reg_w(dev, 0xa0, 0x02, 0xb339);
+ reg_w(gspca_dev, 0xa0, address, 0xb33a);
+ reg_w(gspca_dev, 0xa0, 0x02, 0xb339);
do {
reg_r(gspca_dev, 0xa1, 0xb33b, 1);
@@ -3136,15 +3183,15 @@ static u16 read_sensor_register(struct gspca_dev *gspca_dev,
static int vc032x_probe_sensor(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
- struct usb_device *dev = gspca_dev->dev;
int i, n;
u16 value;
const struct sensor_info *ptsensor_info;
/*fixme: should also check the other sensor (back mi1320_soc, front mc501cb)*/
if (sd->flags & FL_SAMSUNG) {
- reg_w(dev, 0xa0, 0x01, 0xb301);
- reg_w(dev, 0x89, 0xf0ff, 0xffff); /* select the back sensor */
+ reg_w(gspca_dev, 0xa0, 0x01, 0xb301);
+ reg_w(gspca_dev, 0x89, 0xf0ff, 0xffff);
+ /* select the back sensor */
}
reg_r(gspca_dev, 0xa1, 0xbfcf, 1);
@@ -3158,13 +3205,13 @@ static int vc032x_probe_sensor(struct gspca_dev *gspca_dev)
n = ARRAY_SIZE(vc0323_probe_data);
}
for (i = 0; i < n; i++) {
- reg_w(dev, 0xa0, 0x02, 0xb334);
- reg_w(dev, 0xa0, ptsensor_info->m1, 0xb300);
- reg_w(dev, 0xa0, ptsensor_info->m2, 0xb300);
- reg_w(dev, 0xa0, 0x01, 0xb308);
- reg_w(dev, 0xa0, 0x0c, 0xb309);
- reg_w(dev, 0xa0, ptsensor_info->I2cAdd, 0xb335);
- reg_w(dev, 0xa0, ptsensor_info->op, 0xb301);
+ reg_w(gspca_dev, 0xa0, 0x02, 0xb334);
+ reg_w(gspca_dev, 0xa0, ptsensor_info->m1, 0xb300);
+ reg_w(gspca_dev, 0xa0, ptsensor_info->m2, 0xb300);
+ reg_w(gspca_dev, 0xa0, 0x01, 0xb308);
+ reg_w(gspca_dev, 0xa0, 0x0c, 0xb309);
+ reg_w(gspca_dev, 0xa0, ptsensor_info->I2cAdd, 0xb335);
+ reg_w(gspca_dev, 0xa0, ptsensor_info->op, 0xb301);
value = read_sensor_register(gspca_dev, ptsensor_info->IdAdd);
if (value == 0 && ptsensor_info->IdAdd == 0x82)
value = read_sensor_register(gspca_dev, 0x83);
@@ -3192,26 +3239,33 @@ static void i2c_write(struct gspca_dev *gspca_dev,
u8 reg, const u8 *val,
u8 size) /* 1 or 2 */
{
- struct usb_device *dev = gspca_dev->dev;
int retry;
- reg_r(gspca_dev, 0xa1, 0xb33f, 1);
+#ifdef GSPCA_DEBUG
+ if (gspca_dev->usb_err < 0)
+ return;
+ if (size == 1)
+ PDEBUG(D_USBO, "i2c_w %02x %02x", reg, *val);
+ else
+ PDEBUG(D_USBO, "i2c_w %02x %02x%02x", reg, *val, val[1]);
+#endif
+ reg_r_i(gspca_dev, 0xa1, 0xb33f, 1);
/*fixme:should check if (!(gspca_dev->usb_buf[0] & 0x02)) error*/
- reg_w(dev, 0xa0, size, 0xb334);
- reg_w(dev, 0xa0, reg, 0xb33a);
- reg_w(dev, 0xa0, val[0], 0xb336);
+ reg_w_i(gspca_dev, 0xa0, size, 0xb334);
+ reg_w_i(gspca_dev, 0xa0, reg, 0xb33a);
+ reg_w_i(gspca_dev, 0xa0, val[0], 0xb336);
if (size > 1)
- reg_w(dev, 0xa0, val[1], 0xb337);
- reg_w(dev, 0xa0, 0x01, 0xb339);
+ reg_w_i(gspca_dev, 0xa0, val[1], 0xb337);
+ reg_w_i(gspca_dev, 0xa0, 0x01, 0xb339);
retry = 4;
do {
- reg_r(gspca_dev, 0xa1, 0xb33b, 1);
+ reg_r_i(gspca_dev, 0xa1, 0xb33b, 1);
if (gspca_dev->usb_buf[0] == 0)
break;
msleep(20);
} while (--retry > 0);
if (retry <= 0)
- PDEBUG(D_ERR, "i2c_write failed");
+ PDEBUG(D_ERR, "i2c_write timeout");
}
static void put_tab_to_reg(struct gspca_dev *gspca_dev,
@@ -3221,13 +3275,12 @@ static void put_tab_to_reg(struct gspca_dev *gspca_dev,
u16 ad = addr;
for (j = 0; j < tabsize; j++)
- reg_w(gspca_dev->dev, 0xa0, tab[j], ad++);
+ reg_w(gspca_dev, 0xa0, tab[j], ad++);
}
static void usb_exchange(struct gspca_dev *gspca_dev,
const u8 data[][4])
{
- struct usb_device *dev = gspca_dev->dev;
int i = 0;
for (;;) {
@@ -3235,7 +3288,7 @@ static void usb_exchange(struct gspca_dev *gspca_dev,
default:
return;
case 0xcc: /* normal write */
- reg_w(dev, 0xa0, data[i][2],
+ reg_w(gspca_dev, 0xa0, data[i][2],
(data[i][0]) << 8 | data[i][1]);
break;
case 0xaa: /* i2c op */
@@ -3259,7 +3312,6 @@ static int sd_config(struct gspca_dev *gspca_dev,
const struct usb_device_id *id)
{
struct sd *sd = (struct sd *) gspca_dev;
- struct usb_device *dev = gspca_dev->dev;
struct cam *cam;
int sensor;
static u8 npkt[] = { /* number of packets per ISOC message */
@@ -3363,13 +3415,6 @@ static int sd_config(struct gspca_dev *gspca_dev,
if (sd->sensor == SENSOR_OV7670)
sd->flags |= FL_HFLIP | FL_VFLIP;
- if (sd->bridge == BRIDGE_VC0321) {
- reg_r(gspca_dev, 0x8a, 0, 3);
- reg_w(dev, 0x87, 0x00, 0x0f0f);
-
- reg_r(gspca_dev, 0x8b, 0, 3);
- reg_w(dev, 0x88, 0x00, 0x0202);
- }
return 0;
}
@@ -3378,15 +3423,21 @@ static int sd_init(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
- if (sd->sensor == SENSOR_POxxxx) {
- reg_r(gspca_dev, 0xa1, 0xb300, 1);
- if (gspca_dev->usb_buf[0] != 0) {
- reg_w(gspca_dev->dev, 0xa0, 0x26, 0xb300);
- reg_w(gspca_dev->dev, 0xa0, 0x04, 0xb300);
- reg_w(gspca_dev->dev, 0xa0, 0x00, 0xb300);
+ if (sd->bridge == BRIDGE_VC0321) {
+ reg_r(gspca_dev, 0x8a, 0, 3);
+ reg_w(gspca_dev, 0x87, 0x00, 0x0f0f);
+ reg_r(gspca_dev, 0x8b, 0, 3);
+ reg_w(gspca_dev, 0x88, 0x00, 0x0202);
+ if (sd->sensor == SENSOR_POxxxx) {
+ reg_r(gspca_dev, 0xa1, 0xb300, 1);
+ if (gspca_dev->usb_buf[0] != 0) {
+ reg_w(gspca_dev, 0xa0, 0x26, 0xb300);
+ reg_w(gspca_dev, 0xa0, 0x04, 0xb300);
+ reg_w(gspca_dev, 0xa0, 0x00, 0xb300);
+ }
}
}
- return 0;
+ return gspca_dev->usb_err;
}
static void setbrightness(struct gspca_dev *gspca_dev)
@@ -3516,17 +3567,17 @@ static int sd_start(struct gspca_dev *gspca_dev)
/*fixme: back sensor only*/
if (sd->flags & FL_SAMSUNG) {
- reg_w(gspca_dev->dev, 0x89, 0xf0ff, 0xffff);
- reg_w(gspca_dev->dev, 0xa9, 0x8348, 0x000e);
- reg_w(gspca_dev->dev, 0xa9, 0x0000, 0x001a);
+ reg_w(gspca_dev, 0x89, 0xf0ff, 0xffff);
+ reg_w(gspca_dev, 0xa9, 0x8348, 0x000e);
+ reg_w(gspca_dev, 0xa9, 0x0000, 0x001a);
}
/* Assume start use the good resolution from gspca_dev->mode */
if (sd->bridge == BRIDGE_VC0321) {
- reg_w(gspca_dev->dev, 0xa0, 0xff, 0xbfec);
- reg_w(gspca_dev->dev, 0xa0, 0xff, 0xbfed);
- reg_w(gspca_dev->dev, 0xa0, 0xff, 0xbfee);
- reg_w(gspca_dev->dev, 0xa0, 0xff, 0xbfef);
+ reg_w(gspca_dev, 0xa0, 0xff, 0xbfec);
+ reg_w(gspca_dev, 0xa0, 0xff, 0xbfed);
+ reg_w(gspca_dev, 0xa0, 0xff, 0xbfee);
+ reg_w(gspca_dev, 0xa0, 0xff, 0xbfef);
sd->image_offset = 46;
} else {
if (gspca_dev->cam.cam_mode[gspca_dev->curr_mode].pixelformat
@@ -3617,7 +3668,7 @@ static int sd_start(struct gspca_dev *gspca_dev)
init = poxxxx_initVGA;
usb_exchange(gspca_dev, init);
reg_r(gspca_dev, 0x8c, 0x0000, 3);
- reg_w(gspca_dev->dev, 0xa0,
+ reg_w(gspca_dev, 0xa0,
gspca_dev->usb_buf[2] & 1 ? 0 : 1,
0xb35c);
msleep(300);
@@ -3635,10 +3686,10 @@ static int sd_start(struct gspca_dev *gspca_dev)
switch (sd->sensor) {
case SENSOR_PO1200:
case SENSOR_HV7131R:
- reg_w(gspca_dev->dev, 0x89, 0x0400, 0x1415);
+ reg_w(gspca_dev, 0x89, 0x0400, 0x1415);
break;
case SENSOR_MI1310_SOC:
- reg_w(gspca_dev->dev, 0x89, 0x058c, 0x0000);
+ reg_w(gspca_dev, 0x89, 0x058c, 0x0000);
break;
}
msleep(100);
@@ -3648,9 +3699,9 @@ static int sd_start(struct gspca_dev *gspca_dev)
}
switch (sd->sensor) {
case SENSOR_OV7670:
- reg_w(gspca_dev->dev, 0x87, 0xffff, 0xffff);
- reg_w(gspca_dev->dev, 0x88, 0xff00, 0xf0f1);
- reg_w(gspca_dev->dev, 0xa0, 0x0000, 0xbfff);
+ reg_w(gspca_dev, 0x87, 0xffff, 0xffff);
+ reg_w(gspca_dev, 0x88, 0xff00, 0xf0f1);
+ reg_w(gspca_dev, 0xa0, 0x0000, 0xbfff);
break;
case SENSOR_POxxxx:
setcolors(gspca_dev);
@@ -3659,51 +3710,49 @@ static int sd_start(struct gspca_dev *gspca_dev)
/* led on */
msleep(80);
- reg_w(gspca_dev->dev, 0x89, 0xffff, 0xfdff);
+ reg_w(gspca_dev, 0x89, 0xffff, 0xfdff);
usb_exchange(gspca_dev, poxxxx_init_end_2);
break;
}
- return 0;
+ return gspca_dev->usb_err;
}
static void sd_stopN(struct gspca_dev *gspca_dev)
{
- struct usb_device *dev = gspca_dev->dev;
struct sd *sd = (struct sd *) gspca_dev;
switch (sd->sensor) {
case SENSOR_MI1310_SOC:
- reg_w(dev, 0x89, 0x058c, 0x00ff);
+ reg_w(gspca_dev, 0x89, 0x058c, 0x00ff);
break;
case SENSOR_POxxxx:
return;
default:
if (!(sd->flags & FL_SAMSUNG))
- reg_w(dev, 0x89, 0xffff, 0xffff);
+ reg_w(gspca_dev, 0x89, 0xffff, 0xffff);
break;
}
- reg_w(dev, 0xa0, 0x01, 0xb301);
- reg_w(dev, 0xa0, 0x09, 0xb003);
+ reg_w(gspca_dev, 0xa0, 0x01, 0xb301);
+ reg_w(gspca_dev, 0xa0, 0x09, 0xb003);
}
/* called on streamoff with alt 0 and on disconnect */
static void sd_stop0(struct gspca_dev *gspca_dev)
{
- struct usb_device *dev = gspca_dev->dev;
struct sd *sd = (struct sd *) gspca_dev;
if (!gspca_dev->present)
return;
/*fixme: is this useful?*/
if (sd->sensor == SENSOR_MI1310_SOC)
- reg_w(dev, 0x89, 0x058c, 0x00ff);
+ reg_w(gspca_dev, 0x89, 0x058c, 0x00ff);
else if (!(sd->flags & FL_SAMSUNG))
- reg_w(dev, 0x89, 0xffff, 0xffff);
+ reg_w(gspca_dev, 0x89, 0xffff, 0xffff);
if (sd->sensor == SENSOR_POxxxx) {
- reg_w(dev, 0xa0, 0x26, 0xb300);
- reg_w(dev, 0xa0, 0x04, 0xb300);
- reg_w(dev, 0xa0, 0x00, 0xb300);
+ reg_w(gspca_dev, 0xa0, 0x26, 0xb300);
+ reg_w(gspca_dev, 0xa0, 0x04, 0xb300);
+ reg_w(gspca_dev, 0xa0, 0x00, 0xb300);
}
}
@@ -3726,17 +3775,12 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
/* The vc0321 sends some additional data after sending the complete
* frame, we ignore this. */
if (sd->bridge == BRIDGE_VC0321) {
- struct gspca_frame *frame;
- int l;
+ int size, l;
- frame = gspca_get_i_frame(gspca_dev);
- if (frame == NULL) {
- gspca_dev->last_packet_type = DISCARD_PACKET;
- return;
- }
- l = frame->data_end - frame->data;
- if (len > frame->v4l2_buf.length - l)
- len = frame->v4l2_buf.length - l;
+ l = gspca_dev->image_len;
+ size = gspca_dev->frsz;
+ if (len > size - l)
+ len = size - l;
}
gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
}
@@ -3748,7 +3792,7 @@ static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
sd->brightness = val;
if (gspca_dev->streaming)
setbrightness(gspca_dev);
- return 0;
+ return gspca_dev->usb_err;
}
static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
@@ -3766,7 +3810,7 @@ static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
sd->contrast = val;
if (gspca_dev->streaming)
setcontrast(gspca_dev);
- return 0;
+ return gspca_dev->usb_err;
}
static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
@@ -3784,7 +3828,7 @@ static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val)
sd->colors = val;
if (gspca_dev->streaming)
setcolors(gspca_dev);
- return 0;
+ return gspca_dev->usb_err;
}
static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val)
@@ -3802,7 +3846,7 @@ static int sd_sethflip(struct gspca_dev *gspca_dev, __s32 val)
sd->hflip = val;
if (gspca_dev->streaming)
sethvflip(gspca_dev);
- return 0;
+ return gspca_dev->usb_err;
}
static int sd_gethflip(struct gspca_dev *gspca_dev, __s32 *val)
@@ -3820,7 +3864,7 @@ static int sd_setvflip(struct gspca_dev *gspca_dev, __s32 val)
sd->vflip = val;
if (gspca_dev->streaming)
sethvflip(gspca_dev);
- return 0;
+ return gspca_dev->usb_err;
}
static int sd_getvflip(struct gspca_dev *gspca_dev, __s32 *val)
@@ -3838,7 +3882,7 @@ static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val)
sd->lightfreq = val;
if (gspca_dev->streaming)
setlightfreq(gspca_dev);
- return 0;
+ return gspca_dev->usb_err;
}
static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val)
@@ -3856,7 +3900,7 @@ static int sd_setsharpness(struct gspca_dev *gspca_dev, __s32 val)
sd->sharpness = val;
if (gspca_dev->streaming)
setsharpness(gspca_dev);
- return 0;
+ return gspca_dev->usb_err;
}
static int sd_getsharpness(struct gspca_dev *gspca_dev, __s32 *val)
diff --git a/drivers/media/video/gspca/w996Xcf.c b/drivers/media/video/gspca/w996Xcf.c
index 2fffe203bed..38a68591ce4 100644
--- a/drivers/media/video/gspca/w996Xcf.c
+++ b/drivers/media/video/gspca/w996Xcf.c
@@ -31,14 +31,10 @@
the sensor drivers to v4l2 sub drivers, and properly split of this
driver from ov519.c */
-/* The CONEX_CAM define for jpeg.h needs renaming, now its used here too */
-#define CONEX_CAM
-#include "jpeg.h"
-
#define W9968CF_I2C_BUS_DELAY 4 /* delay in us for I2C bit r/w operations */
-#define Y_QUANTABLE (sd->jpeg_hdr + JPEG_QT0_OFFSET)
-#define UV_QUANTABLE (sd->jpeg_hdr + JPEG_QT1_OFFSET)
+#define Y_QUANTABLE (&sd->jpeg_hdr[JPEG_QT0_OFFSET])
+#define UV_QUANTABLE (&sd->jpeg_hdr[JPEG_QT1_OFFSET])
static const struct v4l2_pix_format w9968cf_vga_mode[] = {
{160, 120, V4L2_PIX_FMT_UYVY, V4L2_FIELD_NONE,
@@ -509,11 +505,6 @@ static int w9968cf_mode_init_regs(struct sd *sd)
if (w9968cf_vga_mode[sd->gspca_dev.curr_mode].pixelformat ==
V4L2_PIX_FMT_JPEG) {
/* We may get called multiple times (usb isoc bw negotiat.) */
- if (!sd->jpeg_hdr)
- sd->jpeg_hdr = kmalloc(JPEG_HDR_SZ, GFP_KERNEL);
- if (!sd->jpeg_hdr)
- return -ENOMEM;
-
jpeg_define(sd->jpeg_hdr, sd->gspca_dev.height,
sd->gspca_dev.width, 0x22); /* JPEG 420 */
jpeg_set_qual(sd->jpeg_hdr, sd->quality);
@@ -562,9 +553,6 @@ static void w9968cf_stop0(struct sd *sd)
reg_w(sd, 0x39, 0x0000); /* disable JPEG encoder */
reg_w(sd, 0x16, 0x0000); /* stop video capture */
}
-
- kfree(sd->jpeg_hdr);
- sd->jpeg_hdr = NULL;
}
/* The w9968cf docs say that a 0 sized packet means EOF (and also SOF
diff --git a/drivers/media/video/gspca/zc3xx.c b/drivers/media/video/gspca/zc3xx.c
index d02aa5c8472..4473f0fb8b7 100644
--- a/drivers/media/video/gspca/zc3xx.c
+++ b/drivers/media/video/gspca/zc3xx.c
@@ -22,7 +22,6 @@
#define MODULE_NAME "zc3xx"
#include <linux/input.h>
-#include <linux/slab.h>
#include "gspca.h"
#include "jpeg.h"
@@ -40,15 +39,16 @@ static int force_sensor = -1;
struct sd {
struct gspca_dev gspca_dev; /* !! must be the first item */
+ u8 brightness;
u8 contrast;
u8 gamma;
u8 autogain;
u8 lightfreq;
u8 sharpness;
u8 quality; /* image quality */
-#define QUALITY_MIN 40
-#define QUALITY_MAX 60
-#define QUALITY_DEF 50
+#define QUALITY_MIN 50
+#define QUALITY_MAX 80
+#define QUALITY_DEF 70
u8 sensor; /* Type of image sensor chip */
/* !! values used in different tables */
@@ -75,10 +75,12 @@ struct sd {
#define SENSOR_MAX 19
unsigned short chip_revision;
- u8 *jpeg_hdr;
+ u8 jpeg_hdr[JPEG_HDR_SZ];
};
/* V4L2 controls supported by the driver */
+static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val);
static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val);
static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val);
@@ -93,6 +95,20 @@ static int sd_getsharpness(struct gspca_dev *gspca_dev, __s32 *val);
static const struct ctrl sd_ctrls[] = {
{
{
+ .id = V4L2_CID_BRIGHTNESS,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Brightness",
+ .minimum = 0,
+ .maximum = 255,
+ .step = 1,
+#define BRIGHTNESS_DEF 128
+ .default_value = BRIGHTNESS_DEF,
+ },
+ .set = sd_setbrightness,
+ .get = sd_getbrightness,
+ },
+ {
+ {
.id = V4L2_CID_CONTRAST,
.type = V4L2_CTRL_TYPE_INTEGER,
.name = "Contrast",
@@ -132,7 +148,7 @@ static const struct ctrl sd_ctrls[] = {
.set = sd_setautogain,
.get = sd_getautogain,
},
-#define LIGHTFREQ_IDX 3
+#define LIGHTFREQ_IDX 4
{
{
.id = V4L2_CID_POWER_LINE_FREQUENCY,
@@ -6011,9 +6027,12 @@ static void setcontrast(struct gspca_dev *gspca_dev)
struct sd *sd = (struct sd *) gspca_dev;
struct usb_device *dev = gspca_dev->dev;
const u8 *Tgamma;
- int g, i, k, adj, gp;
+ int g, i, brightness, contrast, adj, gp1, gp2;
u8 gr[16];
- static const u8 delta_tb[16] = /* delta for contrast */
+ static const u8 delta_b[16] = /* delta for brightness */
+ {0x50, 0x38, 0x2d, 0x28, 0x24, 0x21, 0x1e, 0x1d,
+ 0x1d, 0x1b, 0x1b, 0x1b, 0x19, 0x18, 0x18, 0x18};
+ static const u8 delta_c[16] = /* delta for contrast */
{0x2c, 0x1a, 0x12, 0x0c, 0x0a, 0x06, 0x06, 0x06,
0x04, 0x06, 0x04, 0x04, 0x03, 0x03, 0x02, 0x02};
static const u8 gamma_tb[6][16] = {
@@ -6033,30 +6052,30 @@ static void setcontrast(struct gspca_dev *gspca_dev)
Tgamma = gamma_tb[sd->gamma - 1];
- k = ((int) sd->contrast - 128); /* -128 / 128 */
+ contrast = ((int) sd->contrast - 128); /* -128 / 127 */
+ brightness = ((int) sd->brightness - 128); /* -128 / 92 */
adj = 0;
- gp = 0;
+ gp1 = gp2 = 0;
for (i = 0; i < 16; i++) {
- g = Tgamma[i] - delta_tb[i] * k / 256 - adj / 2;
+ g = Tgamma[i] + delta_b[i] * brightness / 256
+ - delta_c[i] * contrast / 256 - adj / 2;
if (g > 0xff)
g = 0xff;
else if (g < 0)
g = 0;
reg_w(dev, g, 0x0120 + i); /* gamma */
- if (k > 0)
+ if (contrast > 0)
adj--;
- else
+ else if (contrast < 0)
adj++;
-
- if (i != 0) {
- if (gp == 0)
- gr[i - 1] = 0;
- else
- gr[i - 1] = g - gp;
- }
- gp = g;
+ if (i > 1)
+ gr[i - 1] = (g - gp2) / 2;
+ else if (i != 0)
+ gr[0] = gp1 == 0 ? 0 : (g - gp1);
+ gp2 = gp1;
+ gp1 = g;
}
- gr[15] = gr[14] / 2;
+ gr[15] = (0xff - gp2) / 2;
for (i = 0; i < 16; i++)
reg_w(dev, gr[i], 0x0130 + i); /* gradient */
}
@@ -6744,6 +6763,7 @@ static int sd_config(struct gspca_dev *gspca_dev,
cam->nmodes = ARRAY_SIZE(broken_vga_mode);
break;
}
+ sd->brightness = BRIGHTNESS_DEF;
sd->contrast = CONTRAST_DEF;
sd->gamma = gamma[sd->sensor];
sd->autogain = AUTOGAIN_DEF;
@@ -6798,9 +6818,6 @@ static int sd_start(struct gspca_dev *gspca_dev)
};
/* create the JPEG header */
- sd->jpeg_hdr = kmalloc(JPEG_HDR_SZ, GFP_KERNEL);
- if (!sd->jpeg_hdr)
- return -ENOMEM;
jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width,
0x21); /* JPEG 422 */
jpeg_set_qual(sd->jpeg_hdr, sd->quality);
@@ -6918,10 +6935,6 @@ static int sd_start(struct gspca_dev *gspca_dev)
reg_w(dev, 0x00, 0x0007); /* (from win traces) */
reg_w(dev, 0x02, ZC3XX_R008_CLOCKSETTING);
break;
- case SENSOR_PAS202B:
- reg_w(dev, 0x32, 0x0007); /* (from win traces) */
- reg_w(dev, 0x02, ZC3XX_R008_CLOCKSETTING);
- break;
}
return 0;
}
@@ -6931,7 +6944,6 @@ static void sd_stop0(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
- kfree(sd->jpeg_hdr);
if (!gspca_dev->present)
return;
send_unknown(gspca_dev->dev, sd->sensor);
@@ -6962,6 +6974,24 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
}
+static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->brightness = val;
+ if (gspca_dev->streaming)
+ setcontrast(gspca_dev);
+ return 0;
+}
+
+static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ *val = sd->brightness;
+ return 0;
+}
+
static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
{
struct sd *sd = (struct sd *) gspca_dev;
@@ -7163,9 +7193,7 @@ static const __devinitdata struct usb_device_id device_table[] = {
{USB_DEVICE(0x046d, 0x08aa)},
{USB_DEVICE(0x046d, 0x08ac)},
{USB_DEVICE(0x046d, 0x08ad)},
-#if !defined CONFIG_USB_ZC0301 && !defined CONFIG_USB_ZC0301_MODULE
{USB_DEVICE(0x046d, 0x08ae)},
-#endif
{USB_DEVICE(0x046d, 0x08af)},
{USB_DEVICE(0x046d, 0x08b9)},
{USB_DEVICE(0x046d, 0x08d7)},
diff --git a/drivers/media/video/hdpvr/hdpvr-core.c b/drivers/media/video/hdpvr/hdpvr-core.c
index 830d47b05e1..0cae5b82e1a 100644
--- a/drivers/media/video/hdpvr/hdpvr-core.c
+++ b/drivers/media/video/hdpvr/hdpvr-core.c
@@ -286,6 +286,8 @@ static int hdpvr_probe(struct usb_interface *interface,
goto error;
}
+ dev->workqueue = 0;
+
/* register v4l2_device early so it can be used for printks */
if (v4l2_device_register(&interface->dev, &dev->v4l2_dev)) {
err("v4l2_device_register failed");
@@ -380,6 +382,9 @@ static int hdpvr_probe(struct usb_interface *interface,
error:
if (dev) {
+ /* Destroy single thread */
+ if (dev->workqueue)
+ destroy_workqueue(dev->workqueue);
/* this frees allocated memory */
hdpvr_delete(dev);
}
diff --git a/drivers/media/video/hdpvr/hdpvr-video.c b/drivers/media/video/hdpvr/hdpvr-video.c
index c338f3f62e7..4863a21b1f2 100644
--- a/drivers/media/video/hdpvr/hdpvr-video.c
+++ b/drivers/media/video/hdpvr/hdpvr-video.c
@@ -394,7 +394,7 @@ err:
static int hdpvr_release(struct file *file)
{
- struct hdpvr_fh *fh = (struct hdpvr_fh *)file->private_data;
+ struct hdpvr_fh *fh = file->private_data;
struct hdpvr_device *dev = fh->dev;
if (!dev)
@@ -518,7 +518,7 @@ err:
static unsigned int hdpvr_poll(struct file *filp, poll_table *wait)
{
struct hdpvr_buffer *buf = NULL;
- struct hdpvr_fh *fh = (struct hdpvr_fh *)filp->private_data;
+ struct hdpvr_fh *fh = filp->private_data;
struct hdpvr_device *dev = fh->dev;
unsigned int mask = 0;
diff --git a/drivers/media/video/ir-kbd-i2c.c b/drivers/media/video/ir-kbd-i2c.c
index 29d43974265..27ae8bbfb47 100644
--- a/drivers/media/video/ir-kbd-i2c.c
+++ b/drivers/media/video/ir-kbd-i2c.c
@@ -47,7 +47,7 @@
#include <linux/i2c-id.h>
#include <linux/workqueue.h>
-#include <media/ir-common.h>
+#include <media/ir-core.h>
#include <media/ir-kbd-i2c.h>
/* ----------------------------------------------------------------------- */
@@ -272,11 +272,8 @@ static void ir_key_poll(struct IR_i2c *ir)
return;
}
- if (0 == rc) {
- ir_input_nokey(ir->input, &ir->ir);
- } else {
- ir_input_keydown(ir->input, &ir->ir, ir_key);
- }
+ if (rc)
+ ir_keydown(ir->input, ir_key, 0);
}
static void ir_work(struct work_struct *work)
@@ -439,10 +436,7 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id)
dev_name(&client->dev));
/* init + register input device */
- err = ir_input_init(input_dev, &ir->ir, ir_type);
- if (err < 0)
- goto err_out_free;
-
+ ir->ir_type = ir_type;
input_dev->id.bustype = BUS_I2C;
input_dev->name = ir->name;
input_dev->phys = ir->phys;
diff --git a/drivers/media/video/ivtv/ivtv-driver.c b/drivers/media/video/ivtv/ivtv-driver.c
index 1b79475ca13..07c5c18a25c 100644
--- a/drivers/media/video/ivtv/ivtv-driver.c
+++ b/drivers/media/video/ivtv/ivtv-driver.c
@@ -130,6 +130,9 @@ static int ivtv_yuv_threshold = -1;
static int ivtv_pci_latency = 1;
int ivtv_debug;
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+int ivtv_fw_debug;
+#endif
static int tunertype = -1;
static int newi2c = -1;
@@ -141,6 +144,9 @@ module_param_string(pal, pal, sizeof(pal), 0644);
module_param_string(secam, secam, sizeof(secam), 0644);
module_param_string(ntsc, ntsc, sizeof(ntsc), 0644);
module_param_named(debug,ivtv_debug, int, 0644);
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+module_param_named(fw_debug, ivtv_fw_debug, int, 0644);
+#endif
module_param(ivtv_pci_latency, int, 0644);
module_param(ivtv_yuv_mode, int, 0644);
module_param(ivtv_yuv_threshold, int, 0644);
@@ -217,6 +223,10 @@ MODULE_PARM_DESC(debug,
"\t\t\t 256/0x0100: yuv\n"
"\t\t\t 512/0x0200: i2c\n"
"\t\t\t1024/0x0400: high volume\n");
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+MODULE_PARM_DESC(fw_debug,
+ "Enable code for debugging firmware problems. Default: 0\n");
+#endif
MODULE_PARM_DESC(ivtv_pci_latency,
"Change the PCI latency to 64 if lower: 0 = No, 1 = Yes,\n"
"\t\t\tDefault: Yes");
@@ -695,6 +705,8 @@ done:
*/
static int __devinit ivtv_init_struct1(struct ivtv *itv)
{
+ struct sched_param param = { .sched_priority = 99 };
+
itv->base_addr = pci_resource_start(itv->pdev, 0);
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) */
@@ -706,13 +718,17 @@ static int __devinit ivtv_init_struct1(struct ivtv *itv)
spin_lock_init(&itv->lock);
spin_lock_init(&itv->dma_reg_lock);
- itv->irq_work_queues = create_singlethread_workqueue(itv->v4l2_dev.name);
- if (itv->irq_work_queues == NULL) {
- IVTV_ERR("Could not create ivtv workqueue\n");
+ init_kthread_worker(&itv->irq_worker);
+ itv->irq_worker_task = kthread_run(kthread_worker_fn, &itv->irq_worker,
+ itv->v4l2_dev.name);
+ if (IS_ERR(itv->irq_worker_task)) {
+ IVTV_ERR("Could not create ivtv task\n");
return -1;
}
+ /* must use the FIFO scheduler as it is realtime sensitive */
+ sched_setscheduler(itv->irq_worker_task, SCHED_FIFO, &param);
- INIT_WORK(&itv->irq_work_queue, ivtv_irq_work_handler);
+ init_kthread_work(&itv->irq_work, ivtv_irq_work_handler);
/* start counting open_id at 1 */
itv->open_id = 1;
@@ -996,7 +1012,7 @@ static int __devinit ivtv_probe(struct pci_dev *pdev,
/* PCI Device Setup */
retval = ivtv_setup_pci(itv, pdev, pci_id);
if (retval == -EIO)
- goto free_workqueue;
+ goto free_worker;
if (retval == -ENXIO)
goto free_mem;
@@ -1208,8 +1224,8 @@ free_mem:
release_mem_region(itv->base_addr + IVTV_REG_OFFSET, IVTV_REG_SIZE);
if (itv->has_cx23415)
release_mem_region(itv->base_addr + IVTV_DECODER_OFFSET, IVTV_DECODER_SIZE);
-free_workqueue:
- destroy_workqueue(itv->irq_work_queues);
+free_worker:
+ kthread_stop(itv->irq_worker_task);
err:
if (retval == 0)
retval = -ENODEV;
@@ -1353,9 +1369,9 @@ static void ivtv_remove(struct pci_dev *pdev)
ivtv_set_irq_mask(itv, 0xffffffff);
del_timer_sync(&itv->dma_timer);
- /* Stop all Work Queues */
- flush_workqueue(itv->irq_work_queues);
- destroy_workqueue(itv->irq_work_queues);
+ /* Kill irq worker */
+ flush_kthread_worker(&itv->irq_worker);
+ kthread_stop(itv->irq_worker_task);
ivtv_streams_cleanup(itv, 1);
ivtv_udma_free(itv);
@@ -1425,12 +1441,16 @@ EXPORT_SYMBOL(ivtv_vapi);
EXPORT_SYMBOL(ivtv_vapi_result);
EXPORT_SYMBOL(ivtv_clear_irq_mask);
EXPORT_SYMBOL(ivtv_debug);
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+EXPORT_SYMBOL(ivtv_fw_debug);
+#endif
EXPORT_SYMBOL(ivtv_reset_ir_gpio);
EXPORT_SYMBOL(ivtv_udma_setup);
EXPORT_SYMBOL(ivtv_udma_unmap);
EXPORT_SYMBOL(ivtv_udma_alloc);
EXPORT_SYMBOL(ivtv_udma_prepare);
EXPORT_SYMBOL(ivtv_init_on_first_open);
+EXPORT_SYMBOL(ivtv_firmware_check);
module_init(module_start);
module_exit(module_cleanup);
diff --git a/drivers/media/video/ivtv/ivtv-driver.h b/drivers/media/video/ivtv/ivtv-driver.h
index 5b45fd2b264..10207124621 100644
--- a/drivers/media/video/ivtv/ivtv-driver.h
+++ b/drivers/media/video/ivtv/ivtv-driver.h
@@ -51,7 +51,7 @@
#include <linux/unistd.h>
#include <linux/pagemap.h>
#include <linux/scatterlist.h>
-#include <linux/workqueue.h>
+#include <linux/kthread.h>
#include <linux/mutex.h>
#include <linux/slab.h>
#include <asm/uaccess.h>
@@ -122,6 +122,9 @@
/* debugging */
extern int ivtv_debug;
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+extern int ivtv_fw_debug;
+#endif
#define IVTV_DBGFLG_WARN (1 << 0)
#define IVTV_DBGFLG_INFO (1 << 1)
@@ -257,7 +260,6 @@ struct ivtv_mailbox_data {
#define IVTV_F_I_DEC_PAUSED 20 /* the decoder is paused */
#define IVTV_F_I_INITED 21 /* set after first open */
#define IVTV_F_I_FAILED 22 /* set if first open failed */
-#define IVTV_F_I_WORK_INITED 23 /* worker thread was initialized */
/* Event notifications */
#define IVTV_F_I_EV_DEC_STOPPED 28 /* decoder stopped event */
@@ -663,8 +665,9 @@ struct ivtv {
/* Interrupts & DMA */
u32 irqmask; /* active interrupts */
u32 irq_rr_idx; /* round-robin stream index */
- struct workqueue_struct *irq_work_queues; /* workqueue for PIO/YUV/VBI actions */
- struct work_struct irq_work_queue; /* work entry */
+ struct kthread_worker irq_worker; /* kthread worker for PIO/YUV/VBI actions */
+ struct task_struct *irq_worker_task; /* task for irq_worker */
+ struct kthread_work irq_work; /* kthread work entry */
spinlock_t dma_reg_lock; /* lock access to DMA engine registers */
int cur_dma_stream; /* index of current stream doing DMA (-1 if none) */
int cur_pio_stream; /* index of current stream doing PIO (-1 if none) */
@@ -734,6 +737,7 @@ struct ivtv {
struct v4l2_rect osd_rect; /* current OSD position and size */
struct v4l2_rect main_rect; /* current Main window position and size */
struct osd_info *osd_info; /* ivtvfb private OSD info */
+ void (*ivtvfb_restore)(struct ivtv *itv); /* Used for a warm start */
};
static inline struct ivtv *to_ivtv(struct v4l2_device *v4l2_dev)
diff --git a/drivers/media/video/ivtv/ivtv-fileops.c b/drivers/media/video/ivtv/ivtv-fileops.c
index 3c2cc270ccd..a6a2cdb8156 100644
--- a/drivers/media/video/ivtv/ivtv-fileops.c
+++ b/drivers/media/video/ivtv/ivtv-fileops.c
@@ -32,6 +32,7 @@
#include "ivtv-yuv.h"
#include "ivtv-ioctl.h"
#include "ivtv-cards.h"
+#include "ivtv-firmware.h"
#include <media/v4l2-event.h>
#include <media/saa7115.h>
@@ -526,6 +527,7 @@ int ivtv_start_decoding(struct ivtv_open_id *id, int speed)
{
struct ivtv *itv = id->itv;
struct ivtv_stream *s = &itv->streams[id->type];
+ int rc;
if (atomic_read(&itv->decoding) == 0) {
if (ivtv_claim_stream(id, s->type)) {
@@ -533,7 +535,13 @@ int ivtv_start_decoding(struct ivtv_open_id *id, int speed)
IVTV_DEBUG_WARN("start decode, stream already claimed\n");
return -EBUSY;
}
- ivtv_start_v4l2_decode_stream(s, 0);
+ rc = ivtv_start_v4l2_decode_stream(s, 0);
+ if (rc < 0) {
+ if (rc == -EAGAIN)
+ rc = ivtv_start_v4l2_decode_stream(s, 0);
+ if (rc < 0)
+ return rc;
+ }
}
if (s->type == IVTV_DEC_STREAM_TYPE_MPG)
return ivtv_set_speed(itv, speed);
@@ -912,12 +920,32 @@ int ivtv_v4l2_close(struct file *filp)
static int ivtv_serialized_open(struct ivtv_stream *s, struct file *filp)
{
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+ struct video_device *vdev = video_devdata(filp);
+#endif
struct ivtv *itv = s->itv;
struct ivtv_open_id *item;
int res = 0;
IVTV_DEBUG_FILE("open %s\n", s->name);
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+ /* Unless ivtv_fw_debug is set, error out if firmware dead. */
+ if (ivtv_fw_debug) {
+ IVTV_WARN("Opening %s with dead firmware lockout disabled\n",
+ video_device_node_name(vdev));
+ IVTV_WARN("Selected firmware errors will be ignored\n");
+ } else {
+#else
+ if (1) {
+#endif
+ res = ivtv_firmware_check(itv, "ivtv_serialized_open");
+ if (res == -EAGAIN)
+ res = ivtv_firmware_check(itv, "ivtv_serialized_open");
+ if (res < 0)
+ return -EIO;
+ }
+
if (s->type == IVTV_DEC_STREAM_TYPE_MPG &&
test_bit(IVTV_F_S_CLAIMED, &itv->streams[IVTV_DEC_STREAM_TYPE_YUV].s_flags))
return -EBUSY;
diff --git a/drivers/media/video/ivtv/ivtv-firmware.c b/drivers/media/video/ivtv/ivtv-firmware.c
index a71e8ba306b..d8bf2b01729 100644
--- a/drivers/media/video/ivtv/ivtv-firmware.c
+++ b/drivers/media/video/ivtv/ivtv-firmware.c
@@ -23,7 +23,10 @@
#include "ivtv-mailbox.h"
#include "ivtv-firmware.h"
#include "ivtv-yuv.h"
+#include "ivtv-ioctl.h"
+#include "ivtv-cards.h"
#include <linux/firmware.h>
+#include <media/saa7127.h>
#define IVTV_MASK_SPU_ENABLE 0xFFFFFFFE
#define IVTV_MASK_VPU_ENABLE15 0xFFFFFFF6
@@ -271,3 +274,122 @@ void ivtv_init_mpeg_decoder(struct ivtv *itv)
}
ivtv_vapi(itv, CX2341X_DEC_STOP_PLAYBACK, 4, 0, 0, 0, 1);
}
+
+/* Try to restart the card & restore previous settings */
+int ivtv_firmware_restart(struct ivtv *itv)
+{
+ int rc = 0;
+ v4l2_std_id std;
+ struct ivtv_open_id fh;
+ fh.itv = itv;
+
+ if (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)
+ /* Display test image during restart */
+ ivtv_call_hw(itv, IVTV_HW_SAA7127, video, s_routing,
+ SAA7127_INPUT_TYPE_TEST_IMAGE,
+ itv->card->video_outputs[itv->active_output].video_output,
+ 0);
+
+ mutex_lock(&itv->udma.lock);
+
+ rc = ivtv_firmware_init(itv);
+ if (rc) {
+ mutex_unlock(&itv->udma.lock);
+ return rc;
+ }
+
+ /* Allow settings to reload */
+ ivtv_mailbox_cache_invalidate(itv);
+
+ /* Restore video standard */
+ std = itv->std;
+ itv->std = 0;
+ ivtv_s_std(NULL, &fh, &std);
+
+ if (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT) {
+ ivtv_init_mpeg_decoder(itv);
+
+ /* Restore framebuffer if active */
+ if (itv->ivtvfb_restore)
+ itv->ivtvfb_restore(itv);
+
+ /* Restore alpha settings */
+ ivtv_set_osd_alpha(itv);
+
+ /* Restore normal output */
+ ivtv_call_hw(itv, IVTV_HW_SAA7127, video, s_routing,
+ SAA7127_INPUT_TYPE_NORMAL,
+ itv->card->video_outputs[itv->active_output].video_output,
+ 0);
+ }
+
+ mutex_unlock(&itv->udma.lock);
+ return rc;
+}
+
+/* Check firmware running state. The checks fall through
+ allowing multiple failures to be logged. */
+int ivtv_firmware_check(struct ivtv *itv, char *where)
+{
+ int res = 0;
+
+ /* Check encoder is still running */
+ if (ivtv_vapi(itv, CX2341X_ENC_PING_FW, 0) < 0) {
+ IVTV_WARN("Encoder has died : %s\n", where);
+ res = -1;
+ }
+
+ /* Also check audio. Only check if not in use & encoder is okay */
+ if (!res && !atomic_read(&itv->capturing) &&
+ (!atomic_read(&itv->decoding) ||
+ (atomic_read(&itv->decoding) < 2 && test_bit(IVTV_F_I_DEC_YUV,
+ &itv->i_flags)))) {
+
+ if (ivtv_vapi(itv, CX2341X_ENC_MISC, 1, 12) < 0) {
+ IVTV_WARN("Audio has died (Encoder OK) : %s\n", where);
+ res = -2;
+ }
+ }
+
+ if (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT) {
+ /* Second audio check. Skip if audio already failed */
+ if (res != -2 && read_dec(0x100) != read_dec(0x104)) {
+ /* Wait & try again to be certain. */
+ ivtv_msleep_timeout(14, 0);
+ if (read_dec(0x100) != read_dec(0x104)) {
+ IVTV_WARN("Audio has died (Decoder) : %s\n",
+ where);
+ res = -1;
+ }
+ }
+
+ /* Check decoder is still running */
+ if (ivtv_vapi(itv, CX2341X_DEC_PING_FW, 0) < 0) {
+ IVTV_WARN("Decoder has died : %s\n", where);
+ res = -1;
+ }
+ }
+
+ /* If something failed & currently idle, try to reload */
+ if (res && !atomic_read(&itv->capturing) &&
+ !atomic_read(&itv->decoding)) {
+ IVTV_INFO("Detected in %s that firmware had failed - "
+ "Reloading\n", where);
+ res = ivtv_firmware_restart(itv);
+ /*
+ * Even if restarted ok, still signal a problem had occured.
+ * The caller can come through this function again to check
+ * if things are really ok after the restart.
+ */
+ if (!res) {
+ IVTV_INFO("Firmware restart okay\n");
+ res = -EAGAIN;
+ } else {
+ IVTV_INFO("Firmware restart failed\n");
+ }
+ } else if (res) {
+ res = -EIO;
+ }
+
+ return res;
+}
diff --git a/drivers/media/video/ivtv/ivtv-firmware.h b/drivers/media/video/ivtv/ivtv-firmware.h
index 041ba94e65b..52bb4e5598f 100644
--- a/drivers/media/video/ivtv/ivtv-firmware.h
+++ b/drivers/media/video/ivtv/ivtv-firmware.h
@@ -26,5 +26,6 @@ int ivtv_firmware_init(struct ivtv *itv);
void ivtv_firmware_versions(struct ivtv *itv);
void ivtv_halt_firmware(struct ivtv *itv);
void ivtv_init_mpeg_decoder(struct ivtv *itv);
+int ivtv_firmware_check(struct ivtv *itv, char *where);
#endif
diff --git a/drivers/media/video/ivtv/ivtv-irq.c b/drivers/media/video/ivtv/ivtv-irq.c
index fea1ec33b0d..9b4faf00919 100644
--- a/drivers/media/video/ivtv/ivtv-irq.c
+++ b/drivers/media/video/ivtv/ivtv-irq.c
@@ -71,19 +71,10 @@ static void ivtv_pio_work_handler(struct ivtv *itv)
write_reg(IVTV_IRQ_ENC_PIO_COMPLETE, 0x44);
}
-void ivtv_irq_work_handler(struct work_struct *work)
+void ivtv_irq_work_handler(struct kthread_work *work)
{
- struct ivtv *itv = container_of(work, struct ivtv, irq_work_queue);
+ struct ivtv *itv = container_of(work, struct ivtv, irq_work);
- DEFINE_WAIT(wait);
-
- if (test_and_clear_bit(IVTV_F_I_WORK_INITED, &itv->i_flags)) {
- struct sched_param param = { .sched_priority = 99 };
-
- /* This thread must use the FIFO scheduler as it
- is realtime sensitive. */
- sched_setscheduler(current, SCHED_FIFO, &param);
- }
if (test_and_clear_bit(IVTV_F_I_WORK_HANDLER_PIO, &itv->i_flags))
ivtv_pio_work_handler(itv);
@@ -975,7 +966,7 @@ irqreturn_t ivtv_irq_handler(int irq, void *dev_id)
}
if (test_and_clear_bit(IVTV_F_I_HAVE_WORK, &itv->i_flags)) {
- queue_work(itv->irq_work_queues, &itv->irq_work_queue);
+ queue_kthread_work(&itv->irq_worker, &itv->irq_work);
}
spin_unlock(&itv->dma_reg_lock);
diff --git a/drivers/media/video/ivtv/ivtv-irq.h b/drivers/media/video/ivtv/ivtv-irq.h
index f879a5822e7..1e84433737c 100644
--- a/drivers/media/video/ivtv/ivtv-irq.h
+++ b/drivers/media/video/ivtv/ivtv-irq.h
@@ -46,7 +46,7 @@
irqreturn_t ivtv_irq_handler(int irq, void *dev_id);
-void ivtv_irq_work_handler(struct work_struct *work);
+void ivtv_irq_work_handler(struct kthread_work *work);
void ivtv_dma_stream_dec_prepare(struct ivtv_stream *s, u32 offset, int lock);
void ivtv_unfinished_dma(unsigned long arg);
diff --git a/drivers/media/video/ivtv/ivtv-mailbox.c b/drivers/media/video/ivtv/ivtv-mailbox.c
index 84577f6f41a..e3ce9676378 100644
--- a/drivers/media/video/ivtv/ivtv-mailbox.c
+++ b/drivers/media/video/ivtv/ivtv-mailbox.c
@@ -377,3 +377,11 @@ void ivtv_api_get_data(struct ivtv_mailbox_data *mbdata, int mb,
for (i = 0; i < argc; i++, p++)
data[i] = readl(p);
}
+
+/* Wipe api cache */
+void ivtv_mailbox_cache_invalidate(struct ivtv *itv)
+{
+ int i;
+ for (i = 0; i < 256; i++)
+ itv->api_cache[i].last_jiffies = 0;
+}
diff --git a/drivers/media/video/ivtv/ivtv-mailbox.h b/drivers/media/video/ivtv/ivtv-mailbox.h
index 8247662c928..2c834d2cb56 100644
--- a/drivers/media/video/ivtv/ivtv-mailbox.h
+++ b/drivers/media/video/ivtv/ivtv-mailbox.h
@@ -30,5 +30,6 @@ int ivtv_api(struct ivtv *itv, int cmd, int args, u32 data[]);
int ivtv_vapi_result(struct ivtv *itv, u32 data[CX2341X_MBOX_MAX_DATA], int cmd, int args, ...);
int ivtv_vapi(struct ivtv *itv, int cmd, int args, ...);
int ivtv_api_func(void *priv, u32 cmd, int in, int out, u32 data[CX2341X_MBOX_MAX_DATA]);
+void ivtv_mailbox_cache_invalidate(struct ivtv *itv);
#endif
diff --git a/drivers/media/video/ivtv/ivtv-streams.c b/drivers/media/video/ivtv/ivtv-streams.c
index a937e2ff9b6..55df4190c28 100644
--- a/drivers/media/video/ivtv/ivtv-streams.c
+++ b/drivers/media/video/ivtv/ivtv-streams.c
@@ -42,6 +42,7 @@
#include "ivtv-yuv.h"
#include "ivtv-cards.h"
#include "ivtv-streams.h"
+#include "ivtv-firmware.h"
#include <media/v4l2-event.h>
static const struct v4l2_file_operations ivtv_v4l2_enc_fops = {
@@ -674,12 +675,14 @@ static int ivtv_setup_v4l2_decode_stream(struct ivtv_stream *s)
/* Decoder sometimes dies here, so wait a moment */
ivtv_msleep_timeout(10, 0);
- return 0;
+ /* Known failure point for firmware, so check */
+ return ivtv_firmware_check(itv, "ivtv_setup_v4l2_decode_stream");
}
int ivtv_start_v4l2_decode_stream(struct ivtv_stream *s, int gop_offset)
{
struct ivtv *itv = s->itv;
+ int rc;
if (s->vdev == NULL)
return -EINVAL;
@@ -689,7 +692,11 @@ int ivtv_start_v4l2_decode_stream(struct ivtv_stream *s, int gop_offset)
IVTV_DEBUG_INFO("Starting decode stream %s (gop_offset %d)\n", s->name, gop_offset);
- ivtv_setup_v4l2_decode_stream(s);
+ rc = ivtv_setup_v4l2_decode_stream(s);
+ if (rc < 0) {
+ clear_bit(IVTV_F_S_STREAMING, &s->s_flags);
+ return rc;
+ }
/* set dma size to 65536 bytes */
ivtv_vapi(itv, CX2341X_DEC_SET_DMA_BLOCK_SIZE, 1, 65536);
diff --git a/drivers/media/video/ivtv/ivtv-version.h b/drivers/media/video/ivtv/ivtv-version.h
index b530dec399d..b67a4048f5a 100644
--- a/drivers/media/video/ivtv/ivtv-version.h
+++ b/drivers/media/video/ivtv/ivtv-version.h
@@ -23,7 +23,7 @@
#define IVTV_DRIVER_NAME "ivtv"
#define IVTV_DRIVER_VERSION_MAJOR 1
#define IVTV_DRIVER_VERSION_MINOR 4
-#define IVTV_DRIVER_VERSION_PATCHLEVEL 1
+#define IVTV_DRIVER_VERSION_PATCHLEVEL 2
#define IVTV_VERSION __stringify(IVTV_DRIVER_VERSION_MAJOR) "." __stringify(IVTV_DRIVER_VERSION_MINOR) "." __stringify(IVTV_DRIVER_VERSION_PATCHLEVEL)
#define IVTV_DRIVER_VERSION KERNEL_VERSION(IVTV_DRIVER_VERSION_MAJOR,IVTV_DRIVER_VERSION_MINOR,IVTV_DRIVER_VERSION_PATCHLEVEL)
diff --git a/drivers/media/video/ivtv/ivtvfb.c b/drivers/media/video/ivtv/ivtvfb.c
index 9ff3425891e..be03a712731 100644
--- a/drivers/media/video/ivtv/ivtvfb.c
+++ b/drivers/media/video/ivtv/ivtvfb.c
@@ -53,6 +53,7 @@
#include "ivtv-i2c.h"
#include "ivtv-udma.h"
#include "ivtv-mailbox.h"
+#include "ivtv-firmware.h"
/* card parameters */
static int ivtvfb_card_id = -1;
@@ -178,6 +179,12 @@ struct osd_info {
struct fb_info ivtvfb_info;
struct fb_var_screeninfo ivtvfb_defined;
struct fb_fix_screeninfo ivtvfb_fix;
+
+ /* Used for a warm start */
+ struct fb_var_screeninfo fbvar_cur;
+ int blank_cur;
+ u32 palette_cur[256];
+ u32 pan_cur;
};
struct ivtv_osd_coords {
@@ -199,6 +206,7 @@ static int ivtvfb_get_framebuffer(struct ivtv *itv, u32 *fbbase,
u32 data[CX2341X_MBOX_MAX_DATA];
int rc;
+ ivtv_firmware_check(itv, "ivtvfb_get_framebuffer");
rc = ivtv_vapi_result(itv, data, CX2341X_OSD_GET_FRAMEBUFFER, 0);
*fbbase = data[0];
*fblength = data[1];
@@ -581,8 +589,10 @@ static int ivtvfb_set_var(struct ivtv *itv, struct fb_var_screeninfo *var)
ivtv_window.height = var->yres;
/* Minimum margin cannot be 0, as X won't allow such a mode */
- if (!var->upper_margin) var->upper_margin++;
- if (!var->left_margin) var->left_margin++;
+ if (!var->upper_margin)
+ var->upper_margin++;
+ if (!var->left_margin)
+ var->left_margin++;
ivtv_window.top = var->upper_margin - 1;
ivtv_window.left = var->left_margin - 1;
@@ -595,6 +605,9 @@ static int ivtvfb_set_var(struct ivtv *itv, struct fb_var_screeninfo *var)
/* Force update of yuv registers */
itv->yuv_info.yuv_forced_update = 1;
+ /* Keep a copy of these settings */
+ memcpy(&oi->fbvar_cur, var, sizeof(oi->fbvar_cur));
+
IVTVFB_DEBUG_INFO("Display size: %dx%d (virtual %dx%d) @ %dbpp\n",
var->xres, var->yres,
var->xres_virtual, var->yres_virtual,
@@ -829,6 +842,8 @@ static int ivtvfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *inf
itv->yuv_info.osd_y_pan = var->yoffset;
/* Force update of yuv registers */
itv->yuv_info.yuv_forced_update = 1;
+ /* Remember this value */
+ itv->osd_info->pan_cur = osd_pan_index;
return 0;
}
@@ -842,6 +857,7 @@ static int ivtvfb_set_par(struct fb_info *info)
rc = ivtvfb_set_var(itv, &info->var);
ivtvfb_pan_display(&info->var, info);
ivtvfb_get_fix(itv, &info->fix);
+ ivtv_firmware_check(itv, "ivtvfb_set_par");
return rc;
}
@@ -859,6 +875,7 @@ static int ivtvfb_setcolreg(unsigned regno, unsigned red, unsigned green,
if (info->var.bits_per_pixel <= 8) {
write_reg(regno, 0x02a30);
write_reg(color, 0x02a34);
+ itv->osd_info->palette_cur[regno] = color;
return 0;
}
if (regno >= 16)
@@ -911,6 +928,7 @@ static int ivtvfb_blank(int blank_mode, struct fb_info *info)
ivtv_vapi(itv, CX2341X_OSD_SET_STATE, 1, 0);
break;
}
+ itv->osd_info->blank_cur = blank_mode;
return 0;
}
@@ -929,6 +947,21 @@ static struct fb_ops ivtvfb_ops = {
.fb_blank = ivtvfb_blank,
};
+/* Restore hardware after firmware restart */
+static void ivtvfb_restore(struct ivtv *itv)
+{
+ struct osd_info *oi = itv->osd_info;
+ int i;
+
+ ivtvfb_set_var(itv, &oi->fbvar_cur);
+ ivtvfb_blank(oi->blank_cur, &oi->ivtvfb_info);
+ for (i = 0; i < 256; i++) {
+ write_reg(i, 0x02a30);
+ write_reg(oi->palette_cur[i], 0x02a34);
+ }
+ write_reg(oi->pan_cur, 0x02a0c);
+}
+
/* Initialization */
@@ -1192,6 +1225,9 @@ static int ivtvfb_init_card(struct ivtv *itv)
/* Enable the osd */
ivtvfb_blank(FB_BLANK_UNBLANK, &itv->osd_info->ivtvfb_info);
+ /* Enable restart */
+ itv->ivtvfb_restore = ivtvfb_restore;
+
/* Allocate DMA */
ivtv_udma_alloc(itv);
return 0;
@@ -1203,7 +1239,7 @@ static int __init ivtvfb_callback_init(struct device *dev, void *p)
struct v4l2_device *v4l2_dev = dev_get_drvdata(dev);
struct ivtv *itv = container_of(v4l2_dev, struct ivtv, v4l2_dev);
- if (itv && (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) {
+ if (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT) {
if (ivtvfb_init_card(itv) == 0) {
IVTVFB_INFO("Framebuffer registered on %s\n",
itv->v4l2_dev.name);
@@ -1219,13 +1255,14 @@ static int ivtvfb_callback_cleanup(struct device *dev, void *p)
struct ivtv *itv = container_of(v4l2_dev, struct ivtv, v4l2_dev);
struct osd_info *oi = itv->osd_info;
- if (itv && (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) {
+ if (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT) {
if (unregister_framebuffer(&itv->osd_info->ivtvfb_info)) {
IVTVFB_WARN("Framebuffer %d is in use, cannot unload\n",
itv->instance);
return 0;
}
IVTVFB_INFO("Unregister framebuffer %d\n", itv->instance);
+ itv->ivtvfb_restore = NULL;
ivtvfb_blank(FB_BLANK_VSYNC_SUSPEND, &oi->ivtvfb_info);
ivtvfb_release_buffers(itv);
itv->osd_video_pbase = 0;
diff --git a/drivers/media/video/mem2mem_testdev.c b/drivers/media/video/mem2mem_testdev.c
index 10ddeccc70e..4525335f9bd 100644
--- a/drivers/media/video/mem2mem_testdev.c
+++ b/drivers/media/video/mem2mem_testdev.c
@@ -903,14 +903,14 @@ static int m2mtest_release(struct file *file)
static unsigned int m2mtest_poll(struct file *file,
struct poll_table_struct *wait)
{
- struct m2mtest_ctx *ctx = (struct m2mtest_ctx *)file->private_data;
+ struct m2mtest_ctx *ctx = file->private_data;
return v4l2_m2m_poll(file, ctx->m2m_ctx, wait);
}
static int m2mtest_mmap(struct file *file, struct vm_area_struct *vma)
{
- struct m2mtest_ctx *ctx = (struct m2mtest_ctx *)file->private_data;
+ struct m2mtest_ctx *ctx = file->private_data;
return v4l2_m2m_mmap(file, ctx->m2m_ctx, vma);
}
diff --git a/drivers/media/video/mt9m111.c b/drivers/media/video/mt9m111.c
index fbd0fc79472..31cc3d04bcc 100644
--- a/drivers/media/video/mt9m111.c
+++ b/drivers/media/video/mt9m111.c
@@ -143,10 +143,10 @@ static const struct mt9m111_datafmt *mt9m111_find_datafmt(
}
static const struct mt9m111_datafmt mt9m111_colour_fmts[] = {
- {V4L2_MBUS_FMT_YUYV8_2X8_LE, V4L2_COLORSPACE_JPEG},
- {V4L2_MBUS_FMT_YVYU8_2X8_LE, V4L2_COLORSPACE_JPEG},
- {V4L2_MBUS_FMT_YUYV8_2X8_BE, V4L2_COLORSPACE_JPEG},
- {V4L2_MBUS_FMT_YVYU8_2X8_BE, V4L2_COLORSPACE_JPEG},
+ {V4L2_MBUS_FMT_YUYV8_2X8, V4L2_COLORSPACE_JPEG},
+ {V4L2_MBUS_FMT_YVYU8_2X8, V4L2_COLORSPACE_JPEG},
+ {V4L2_MBUS_FMT_UYVY8_2X8, V4L2_COLORSPACE_JPEG},
+ {V4L2_MBUS_FMT_VYUY8_2X8, V4L2_COLORSPACE_JPEG},
{V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE, V4L2_COLORSPACE_SRGB},
{V4L2_MBUS_FMT_RGB565_2X8_LE, V4L2_COLORSPACE_SRGB},
{V4L2_MBUS_FMT_SBGGR8_1X8, V4L2_COLORSPACE_SRGB},
@@ -505,22 +505,22 @@ static int mt9m111_set_pixfmt(struct i2c_client *client,
case V4L2_MBUS_FMT_RGB565_2X8_LE:
ret = mt9m111_setfmt_rgb565(client);
break;
- case V4L2_MBUS_FMT_YUYV8_2X8_BE:
+ case V4L2_MBUS_FMT_UYVY8_2X8:
mt9m111->swap_yuv_y_chromas = 0;
mt9m111->swap_yuv_cb_cr = 0;
ret = mt9m111_setfmt_yuv(client);
break;
- case V4L2_MBUS_FMT_YVYU8_2X8_BE:
+ case V4L2_MBUS_FMT_VYUY8_2X8:
mt9m111->swap_yuv_y_chromas = 0;
mt9m111->swap_yuv_cb_cr = 1;
ret = mt9m111_setfmt_yuv(client);
break;
- case V4L2_MBUS_FMT_YUYV8_2X8_LE:
+ case V4L2_MBUS_FMT_YUYV8_2X8:
mt9m111->swap_yuv_y_chromas = 1;
mt9m111->swap_yuv_cb_cr = 0;
ret = mt9m111_setfmt_yuv(client);
break;
- case V4L2_MBUS_FMT_YVYU8_2X8_LE:
+ case V4L2_MBUS_FMT_YVYU8_2X8:
mt9m111->swap_yuv_y_chromas = 1;
mt9m111->swap_yuv_cb_cr = 1;
ret = mt9m111_setfmt_yuv(client);
diff --git a/drivers/media/video/mt9t112.c b/drivers/media/video/mt9t112.c
index e4bf1db9a87..8ec47e42d4d 100644
--- a/drivers/media/video/mt9t112.c
+++ b/drivers/media/video/mt9t112.c
@@ -121,22 +121,22 @@ struct mt9t112_priv {
static const struct mt9t112_format mt9t112_cfmts[] = {
{
- .code = V4L2_MBUS_FMT_YUYV8_2X8_BE,
+ .code = V4L2_MBUS_FMT_UYVY8_2X8,
.colorspace = V4L2_COLORSPACE_JPEG,
.fmt = 1,
.order = 0,
}, {
- .code = V4L2_MBUS_FMT_YVYU8_2X8_BE,
+ .code = V4L2_MBUS_FMT_VYUY8_2X8,
.colorspace = V4L2_COLORSPACE_JPEG,
.fmt = 1,
.order = 1,
}, {
- .code = V4L2_MBUS_FMT_YUYV8_2X8_LE,
+ .code = V4L2_MBUS_FMT_YUYV8_2X8,
.colorspace = V4L2_COLORSPACE_JPEG,
.fmt = 1,
.order = 2,
}, {
- .code = V4L2_MBUS_FMT_YVYU8_2X8_LE,
+ .code = V4L2_MBUS_FMT_YVYU8_2X8,
.colorspace = V4L2_COLORSPACE_JPEG,
.fmt = 1,
.order = 3,
@@ -972,7 +972,7 @@ static int mt9t112_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
struct v4l2_rect *rect = &a->c;
return mt9t112_set_params(client, rect->width, rect->height,
- V4L2_MBUS_FMT_YUYV8_2X8_BE);
+ V4L2_MBUS_FMT_UYVY8_2X8);
}
static int mt9t112_g_fmt(struct v4l2_subdev *sd,
@@ -983,7 +983,7 @@ static int mt9t112_g_fmt(struct v4l2_subdev *sd,
if (!priv->format) {
int ret = mt9t112_set_params(client, VGA_WIDTH, VGA_HEIGHT,
- V4L2_MBUS_FMT_YUYV8_2X8_BE);
+ V4L2_MBUS_FMT_UYVY8_2X8);
if (ret < 0)
return ret;
}
diff --git a/drivers/media/video/omap/omap_vout.c b/drivers/media/video/omap/omap_vout.c
index 929073e792c..4ed51b1552e 100644
--- a/drivers/media/video/omap/omap_vout.c
+++ b/drivers/media/video/omap/omap_vout.c
@@ -2545,19 +2545,11 @@ static int __init omap_vout_probe(struct platform_device *pdev)
/* set the update mode */
if (def_display->caps &
OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE) {
-#ifdef CONFIG_FB_OMAP2_FORCE_AUTO_UPDATE
- if (dssdrv->enable_te)
- dssdrv->enable_te(def_display, 1);
- if (dssdrv->set_update_mode)
- dssdrv->set_update_mode(def_display,
- OMAP_DSS_UPDATE_AUTO);
-#else /* MANUAL_UPDATE */
if (dssdrv->enable_te)
dssdrv->enable_te(def_display, 0);
if (dssdrv->set_update_mode)
dssdrv->set_update_mode(def_display,
OMAP_DSS_UPDATE_MANUAL);
-#endif
} else {
if (dssdrv->set_update_mode)
dssdrv->set_update_mode(def_display,
diff --git a/drivers/media/video/omap24xxcam.c b/drivers/media/video/omap24xxcam.c
index f85b2ed8a2d..926a5aa6f7f 100644
--- a/drivers/media/video/omap24xxcam.c
+++ b/drivers/media/video/omap24xxcam.c
@@ -426,7 +426,7 @@ static void omap24xxcam_vbq_release(struct videobuf_queue *vbq,
dma->direction);
dma->direction = DMA_NONE;
} else {
- videobuf_dma_unmap(vbq, videobuf_to_dma(vb));
+ videobuf_dma_unmap(vbq->dev, videobuf_to_dma(vb));
videobuf_dma_free(videobuf_to_dma(vb));
}
diff --git a/drivers/media/video/ov511.c b/drivers/media/video/ov511.c
deleted file mode 100644
index a10912097b7..00000000000
--- a/drivers/media/video/ov511.c
+++ /dev/null
@@ -1,5995 +0,0 @@
-/*
- * OmniVision OV511 Camera-to-USB Bridge Driver
- *
- * Copyright (c) 1999-2003 Mark W. McClelland
- * Original decompression code Copyright 1998-2000 OmniVision Technologies
- * Many improvements by Bret Wallach <bwallac1@san.rr.com>
- * Color fixes by by Orion Sky Lawlor <olawlor@acm.org> (2/26/2000)
- * Snapshot code by Kevin Moore
- * OV7620 fixes by Charl P. Botha <cpbotha@ieee.org>
- * Changes by Claudio Matsuoka <claudio@conectiva.com>
- * Original SAA7111A code by Dave Perks <dperks@ibm.net>
- * URB error messages from pwc driver by Nemosoft
- * generic_ioctl() code from videodev.c by Gerd Knorr and Alan Cox
- * Memory management (rvmalloc) code from bttv driver, by Gerd Knorr and others
- *
- * Based on the Linux CPiA driver written by Peter Pregler,
- * Scott J. Bertin and Johannes Erdfelt.
- *
- * Please see the file: Documentation/usb/ov511.txt
- * and the website at: http://alpha.dyndns.org/ov511
- * for more info.
- *
- * This program is free software; you can redistribute it and/or modify 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/vmalloc.h>
-#include <linux/slab.h>
-#include <linux/ctype.h>
-#include <linux/pagemap.h>
-#include <asm/processor.h>
-#include <linux/mm.h>
-#include <linux/device.h>
-
-#if defined (__i386__)
- #include <asm/cpufeature.h>
-#endif
-
-#include "ov511.h"
-
-/*
- * Version Information
- */
-#define DRIVER_VERSION "v1.64 for Linux 2.5"
-#define EMAIL "mark@alpha.dyndns.org"
-#define DRIVER_AUTHOR "Mark McClelland <mark@alpha.dyndns.org> & Bret Wallach \
-& Orion Sky Lawlor <olawlor@acm.org> & Kevin Moore & Charl P. Botha \
-<cpbotha@ieee.org> & Claudio Matsuoka <claudio@conectiva.com>"
-#define DRIVER_DESC "ov511 USB Camera Driver"
-
-#define OV511_I2C_RETRIES 3
-#define ENABLE_Y_QUANTABLE 1
-#define ENABLE_UV_QUANTABLE 1
-
-#define OV511_MAX_UNIT_VIDEO 16
-
-/* Pixel count * bytes per YUV420 pixel (1.5) */
-#define MAX_FRAME_SIZE(w, h) ((w) * (h) * 3 / 2)
-
-#define MAX_DATA_SIZE(w, h) (MAX_FRAME_SIZE(w, h) + sizeof(struct timeval))
-
-/* Max size * bytes per YUV420 pixel (1.5) + one extra isoc frame for safety */
-#define MAX_RAW_DATA_SIZE(w, h) ((w) * (h) * 3 / 2 + 1024)
-
-#define FATAL_ERROR(rc) ((rc) < 0 && (rc) != -EPERM)
-
-/**********************************************************************
- * Module Parameters
- * (See ov511.txt for detailed descriptions of these)
- **********************************************************************/
-
-/* These variables (and all static globals) default to zero */
-static int autobright = 1;
-static int autogain = 1;
-static int autoexp = 1;
-static int debug;
-static int snapshot;
-static int cams = 1;
-static int compress;
-static int testpat;
-static int dumppix;
-static int led = 1;
-static int dump_bridge;
-static int dump_sensor;
-static int printph;
-static int phy = 0x1f;
-static int phuv = 0x05;
-static int pvy = 0x06;
-static int pvuv = 0x06;
-static int qhy = 0x14;
-static int qhuv = 0x03;
-static int qvy = 0x04;
-static int qvuv = 0x04;
-static int lightfreq;
-static int bandingfilter;
-static int clockdiv = -1;
-static int packetsize = -1;
-static int framedrop = -1;
-static int fastset;
-static int force_palette;
-static int backlight;
-/* Bitmask marking allocated devices from 0 to OV511_MAX_UNIT_VIDEO */
-static unsigned long ov511_devused;
-static int unit_video[OV511_MAX_UNIT_VIDEO];
-static int remove_zeros;
-static int mirror;
-static int ov518_color;
-
-module_param(autobright, int, 0);
-MODULE_PARM_DESC(autobright, "Sensor automatically changes brightness");
-module_param(autogain, int, 0);
-MODULE_PARM_DESC(autogain, "Sensor automatically changes gain");
-module_param(autoexp, int, 0);
-MODULE_PARM_DESC(autoexp, "Sensor automatically changes exposure");
-module_param(debug, int, 0);
-MODULE_PARM_DESC(debug,
- "Debug level: 0=none, 1=inits, 2=warning, 3=config, 4=functions, 5=max");
-module_param(snapshot, int, 0);
-MODULE_PARM_DESC(snapshot, "Enable snapshot mode");
-module_param(cams, int, 0);
-MODULE_PARM_DESC(cams, "Number of simultaneous cameras");
-module_param(compress, int, 0);
-MODULE_PARM_DESC(compress, "Turn on compression");
-module_param(testpat, int, 0);
-MODULE_PARM_DESC(testpat,
- "Replace image with vertical bar testpattern (only partially working)");
-module_param(dumppix, int, 0);
-MODULE_PARM_DESC(dumppix, "Dump raw pixel data");
-module_param(led, int, 0);
-MODULE_PARM_DESC(led,
- "LED policy (OV511+ or later). 0=off, 1=on (default), 2=auto (on when open)");
-module_param(dump_bridge, int, 0);
-MODULE_PARM_DESC(dump_bridge, "Dump the bridge registers");
-module_param(dump_sensor, int, 0);
-MODULE_PARM_DESC(dump_sensor, "Dump the sensor registers");
-module_param(printph, int, 0);
-MODULE_PARM_DESC(printph, "Print frame start/end headers");
-module_param(phy, int, 0);
-MODULE_PARM_DESC(phy, "Prediction range (horiz. Y)");
-module_param(phuv, int, 0);
-MODULE_PARM_DESC(phuv, "Prediction range (horiz. UV)");
-module_param(pvy, int, 0);
-MODULE_PARM_DESC(pvy, "Prediction range (vert. Y)");
-module_param(pvuv, int, 0);
-MODULE_PARM_DESC(pvuv, "Prediction range (vert. UV)");
-module_param(qhy, int, 0);
-MODULE_PARM_DESC(qhy, "Quantization threshold (horiz. Y)");
-module_param(qhuv, int, 0);
-MODULE_PARM_DESC(qhuv, "Quantization threshold (horiz. UV)");
-module_param(qvy, int, 0);
-MODULE_PARM_DESC(qvy, "Quantization threshold (vert. Y)");
-module_param(qvuv, int, 0);
-MODULE_PARM_DESC(qvuv, "Quantization threshold (vert. UV)");
-module_param(lightfreq, int, 0);
-MODULE_PARM_DESC(lightfreq,
- "Light frequency. Set to 50 or 60 Hz, or zero for default settings");
-module_param(bandingfilter, int, 0);
-MODULE_PARM_DESC(bandingfilter,
- "Enable banding filter (to reduce effects of fluorescent lighting)");
-module_param(clockdiv, int, 0);
-MODULE_PARM_DESC(clockdiv, "Force pixel clock divisor to a specific value");
-module_param(packetsize, int, 0);
-MODULE_PARM_DESC(packetsize, "Force a specific isoc packet size");
-module_param(framedrop, int, 0);
-MODULE_PARM_DESC(framedrop, "Force a specific frame drop register setting");
-module_param(fastset, int, 0);
-MODULE_PARM_DESC(fastset, "Allows picture settings to take effect immediately");
-module_param(force_palette, int, 0);
-MODULE_PARM_DESC(force_palette, "Force the palette to a specific value");
-module_param(backlight, int, 0);
-MODULE_PARM_DESC(backlight, "For objects that are lit from behind");
-static unsigned int num_uv;
-module_param_array(unit_video, int, &num_uv, 0);
-MODULE_PARM_DESC(unit_video,
- "Force use of specific minor number(s). 0 is not allowed.");
-module_param(remove_zeros, int, 0);
-MODULE_PARM_DESC(remove_zeros,
- "Remove zero-padding from uncompressed incoming data");
-module_param(mirror, int, 0);
-MODULE_PARM_DESC(mirror, "Reverse image horizontally");
-module_param(ov518_color, int, 0);
-MODULE_PARM_DESC(ov518_color, "Enable OV518 color (experimental)");
-
-MODULE_AUTHOR(DRIVER_AUTHOR);
-MODULE_DESCRIPTION(DRIVER_DESC);
-MODULE_LICENSE("GPL");
-
-/**********************************************************************
- * Miscellaneous Globals
- **********************************************************************/
-
-static struct usb_driver ov511_driver;
-
-/* Number of times to retry a failed I2C transaction. Increase this if you
- * are getting "Failed to read sensor ID..." */
-static const int i2c_detect_tries = 5;
-
-static struct usb_device_id device_table [] = {
- { USB_DEVICE(VEND_OMNIVISION, PROD_OV511) },
- { USB_DEVICE(VEND_OMNIVISION, PROD_OV511PLUS) },
- { USB_DEVICE(VEND_MATTEL, PROD_ME2CAM) },
- { } /* Terminating entry */
-};
-
-MODULE_DEVICE_TABLE (usb, device_table);
-
-static unsigned char yQuanTable511[] = OV511_YQUANTABLE;
-static unsigned char uvQuanTable511[] = OV511_UVQUANTABLE;
-static unsigned char yQuanTable518[] = OV518_YQUANTABLE;
-static unsigned char uvQuanTable518[] = OV518_UVQUANTABLE;
-
-/**********************************************************************
- * Symbolic Names
- **********************************************************************/
-
-/* Known OV511-based cameras */
-static struct symbolic_list camlist[] = {
- { 0, "Generic Camera (no ID)" },
- { 1, "Mustek WCam 3X" },
- { 3, "D-Link DSB-C300" },
- { 4, "Generic OV511/OV7610" },
- { 5, "Puretek PT-6007" },
- { 6, "Lifeview USB Life TV (NTSC)" },
- { 21, "Creative Labs WebCam 3" },
- { 22, "Lifeview USB Life TV (PAL D/K+B/G)" },
- { 36, "Koala-Cam" },
- { 38, "Lifeview USB Life TV (PAL)" },
- { 41, "Samsung Anycam MPC-M10" },
- { 43, "Mtekvision Zeca MV402" },
- { 46, "Suma eON" },
- { 70, "Lifeview USB Life TV (PAL/SECAM)" },
- { 100, "Lifeview RoboCam" },
- { 102, "AverMedia InterCam Elite" },
- { 112, "MediaForte MV300" }, /* or OV7110 evaluation kit */
- { 134, "Ezonics EZCam II" },
- { 192, "Webeye 2000B" },
- { 253, "Alpha Vision Tech. AlphaCam SE" },
- { -1, NULL }
-};
-
-/* Video4Linux1 Palettes */
-static struct symbolic_list v4l1_plist[] = {
- { VIDEO_PALETTE_GREY, "GREY" },
- { VIDEO_PALETTE_HI240, "HI240" },
- { VIDEO_PALETTE_RGB565, "RGB565" },
- { VIDEO_PALETTE_RGB24, "RGB24" },
- { VIDEO_PALETTE_RGB32, "RGB32" },
- { VIDEO_PALETTE_RGB555, "RGB555" },
- { VIDEO_PALETTE_YUV422, "YUV422" },
- { VIDEO_PALETTE_YUYV, "YUYV" },
- { VIDEO_PALETTE_UYVY, "UYVY" },
- { VIDEO_PALETTE_YUV420, "YUV420" },
- { VIDEO_PALETTE_YUV411, "YUV411" },
- { VIDEO_PALETTE_RAW, "RAW" },
- { VIDEO_PALETTE_YUV422P,"YUV422P" },
- { VIDEO_PALETTE_YUV411P,"YUV411P" },
- { VIDEO_PALETTE_YUV420P,"YUV420P" },
- { VIDEO_PALETTE_YUV410P,"YUV410P" },
- { -1, NULL }
-};
-
-static struct symbolic_list brglist[] = {
- { BRG_OV511, "OV511" },
- { BRG_OV511PLUS, "OV511+" },
- { BRG_OV518, "OV518" },
- { BRG_OV518PLUS, "OV518+" },
- { -1, NULL }
-};
-
-static struct symbolic_list senlist[] = {
- { SEN_OV76BE, "OV76BE" },
- { SEN_OV7610, "OV7610" },
- { SEN_OV7620, "OV7620" },
- { SEN_OV7620AE, "OV7620AE" },
- { SEN_OV6620, "OV6620" },
- { SEN_OV6630, "OV6630" },
- { SEN_OV6630AE, "OV6630AE" },
- { SEN_OV6630AF, "OV6630AF" },
- { SEN_OV8600, "OV8600" },
- { SEN_KS0127, "KS0127" },
- { SEN_KS0127B, "KS0127B" },
- { SEN_SAA7111A, "SAA7111A" },
- { -1, NULL }
-};
-
-/* URB error codes: */
-static struct symbolic_list urb_errlist[] = {
- { -ENOSR, "Buffer error (overrun)" },
- { -EPIPE, "Stalled (device not responding)" },
- { -EOVERFLOW, "Babble (device sends too much data)" },
- { -EPROTO, "Bit-stuff error (bad cable?)" },
- { -EILSEQ, "CRC/Timeout (bad cable?)" },
- { -ETIME, "Device does not respond to token" },
- { -ETIMEDOUT, "Device does not respond to command" },
- { -1, NULL }
-};
-
-/**********************************************************************
- * Memory management
- **********************************************************************/
-static void *
-rvmalloc(unsigned long size)
-{
- void *mem;
- unsigned long adr;
-
- size = PAGE_ALIGN(size);
- mem = vmalloc_32(size);
- if (!mem)
- return NULL;
-
- memset(mem, 0, size); /* Clear the ram out, no junk to the user */
- adr = (unsigned long) mem;
- while (size > 0) {
- SetPageReserved(vmalloc_to_page((void *)adr));
- adr += PAGE_SIZE;
- size -= PAGE_SIZE;
- }
-
- return mem;
-}
-
-static void
-rvfree(void *mem, unsigned long size)
-{
- unsigned long adr;
-
- if (!mem)
- return;
-
- adr = (unsigned long) mem;
- while ((long) size > 0) {
- ClearPageReserved(vmalloc_to_page((void *)adr));
- adr += PAGE_SIZE;
- size -= PAGE_SIZE;
- }
- vfree(mem);
-}
-
-/**********************************************************************
- *
- * Register I/O
- *
- **********************************************************************/
-
-/* Write an OV51x register */
-static int
-reg_w(struct usb_ov511 *ov, unsigned char reg, unsigned char value)
-{
- int rc;
-
- PDEBUG(5, "0x%02X:0x%02X", reg, value);
-
- mutex_lock(&ov->cbuf_lock);
- ov->cbuf[0] = value;
- rc = usb_control_msg(ov->dev,
- usb_sndctrlpipe(ov->dev, 0),
- (ov->bclass == BCL_OV518)?1:2 /* REG_IO */,
- USB_TYPE_VENDOR | USB_RECIP_DEVICE,
- 0, (__u16)reg, &ov->cbuf[0], 1, 1000);
- mutex_unlock(&ov->cbuf_lock);
-
- if (rc < 0)
- err("reg write: error %d: %s", rc, symbolic(urb_errlist, rc));
-
- return rc;
-}
-
-/* Read from an OV51x register */
-/* returns: negative is error, pos or zero is data */
-static int
-reg_r(struct usb_ov511 *ov, unsigned char reg)
-{
- int rc;
-
- mutex_lock(&ov->cbuf_lock);
- rc = usb_control_msg(ov->dev,
- usb_rcvctrlpipe(ov->dev, 0),
- (ov->bclass == BCL_OV518)?1:3 /* REG_IO */,
- USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
- 0, (__u16)reg, &ov->cbuf[0], 1, 1000);
-
- if (rc < 0) {
- err("reg read: error %d: %s", rc, symbolic(urb_errlist, rc));
- } else {
- rc = ov->cbuf[0];
- PDEBUG(5, "0x%02X:0x%02X", reg, ov->cbuf[0]);
- }
-
- mutex_unlock(&ov->cbuf_lock);
-
- return rc;
-}
-
-/*
- * Writes bits at positions specified by mask to an OV51x reg. Bits that are in
- * the same position as 1's in "mask" are cleared and set to "value". Bits
- * that are in the same position as 0's in "mask" are preserved, regardless
- * of their respective state in "value".
- */
-static int
-reg_w_mask(struct usb_ov511 *ov,
- unsigned char reg,
- unsigned char value,
- unsigned char mask)
-{
- int ret;
- unsigned char oldval, newval;
-
- ret = reg_r(ov, reg);
- if (ret < 0)
- return ret;
-
- oldval = (unsigned char) ret;
- oldval &= (~mask); /* Clear the masked bits */
- value &= mask; /* Enforce mask on value */
- newval = oldval | value; /* Set the desired bits */
-
- return (reg_w(ov, reg, newval));
-}
-
-/*
- * Writes multiple (n) byte value to a single register. Only valid with certain
- * registers (0x30 and 0xc4 - 0xce).
- */
-static int
-ov518_reg_w32(struct usb_ov511 *ov, unsigned char reg, u32 val, int n)
-{
- int rc;
-
- PDEBUG(5, "0x%02X:%7d, n=%d", reg, val, n);
-
- mutex_lock(&ov->cbuf_lock);
-
- *((__le32 *)ov->cbuf) = __cpu_to_le32(val);
-
- rc = usb_control_msg(ov->dev,
- usb_sndctrlpipe(ov->dev, 0),
- 1 /* REG_IO */,
- USB_TYPE_VENDOR | USB_RECIP_DEVICE,
- 0, (__u16)reg, ov->cbuf, n, 1000);
- mutex_unlock(&ov->cbuf_lock);
-
- if (rc < 0)
- err("reg write multiple: error %d: %s", rc,
- symbolic(urb_errlist, rc));
-
- return rc;
-}
-
-static int
-ov511_upload_quan_tables(struct usb_ov511 *ov)
-{
- unsigned char *pYTable = yQuanTable511;
- unsigned char *pUVTable = uvQuanTable511;
- unsigned char val0, val1;
- int i, rc, reg = R511_COMP_LUT_BEGIN;
-
- PDEBUG(4, "Uploading quantization tables");
-
- for (i = 0; i < OV511_QUANTABLESIZE / 2; i++) {
- if (ENABLE_Y_QUANTABLE) {
- val0 = *pYTable++;
- val1 = *pYTable++;
- val0 &= 0x0f;
- val1 &= 0x0f;
- val0 |= val1 << 4;
- rc = reg_w(ov, reg, val0);
- if (rc < 0)
- return rc;
- }
-
- if (ENABLE_UV_QUANTABLE) {
- val0 = *pUVTable++;
- val1 = *pUVTable++;
- val0 &= 0x0f;
- val1 &= 0x0f;
- val0 |= val1 << 4;
- rc = reg_w(ov, reg + OV511_QUANTABLESIZE/2, val0);
- if (rc < 0)
- return rc;
- }
-
- reg++;
- }
-
- return 0;
-}
-
-/* OV518 quantization tables are 8x4 (instead of 8x8) */
-static int
-ov518_upload_quan_tables(struct usb_ov511 *ov)
-{
- unsigned char *pYTable = yQuanTable518;
- unsigned char *pUVTable = uvQuanTable518;
- unsigned char val0, val1;
- int i, rc, reg = R511_COMP_LUT_BEGIN;
-
- PDEBUG(4, "Uploading quantization tables");
-
- for (i = 0; i < OV518_QUANTABLESIZE / 2; i++) {
- if (ENABLE_Y_QUANTABLE) {
- val0 = *pYTable++;
- val1 = *pYTable++;
- val0 &= 0x0f;
- val1 &= 0x0f;
- val0 |= val1 << 4;
- rc = reg_w(ov, reg, val0);
- if (rc < 0)
- return rc;
- }
-
- if (ENABLE_UV_QUANTABLE) {
- val0 = *pUVTable++;
- val1 = *pUVTable++;
- val0 &= 0x0f;
- val1 &= 0x0f;
- val0 |= val1 << 4;
- rc = reg_w(ov, reg + OV518_QUANTABLESIZE/2, val0);
- if (rc < 0)
- return rc;
- }
-
- reg++;
- }
-
- return 0;
-}
-
-static int
-ov51x_reset(struct usb_ov511 *ov, unsigned char reset_type)
-{
- int rc;
-
- /* Setting bit 0 not allowed on 518/518Plus */
- if (ov->bclass == BCL_OV518)
- reset_type &= 0xfe;
-
- PDEBUG(4, "Reset: type=0x%02X", reset_type);
-
- rc = reg_w(ov, R51x_SYS_RESET, reset_type);
- rc = reg_w(ov, R51x_SYS_RESET, 0);
-
- if (rc < 0)
- err("reset: command failed");
-
- return rc;
-}
-
-/**********************************************************************
- *
- * Low-level I2C I/O functions
- *
- **********************************************************************/
-
-/* NOTE: Do not call this function directly!
- * The OV518 I2C I/O procedure is different, hence, this function.
- * This is normally only called from i2c_w(). Note that this function
- * always succeeds regardless of whether the sensor is present and working.
- */
-static int
-ov518_i2c_write_internal(struct usb_ov511 *ov,
- unsigned char reg,
- unsigned char value)
-{
- int rc;
-
- PDEBUG(5, "0x%02X:0x%02X", reg, value);
-
- /* Select camera register */
- rc = reg_w(ov, R51x_I2C_SADDR_3, reg);
- if (rc < 0)
- return rc;
-
- /* Write "value" to I2C data port of OV511 */
- rc = reg_w(ov, R51x_I2C_DATA, value);
- if (rc < 0)
- return rc;
-
- /* Initiate 3-byte write cycle */
- rc = reg_w(ov, R518_I2C_CTL, 0x01);
- if (rc < 0)
- return rc;
-
- return 0;
-}
-
-/* NOTE: Do not call this function directly! */
-static int
-ov511_i2c_write_internal(struct usb_ov511 *ov,
- unsigned char reg,
- unsigned char value)
-{
- int rc, retries;
-
- PDEBUG(5, "0x%02X:0x%02X", reg, value);
-
- /* Three byte write cycle */
- for (retries = OV511_I2C_RETRIES; ; ) {
- /* Select camera register */
- rc = reg_w(ov, R51x_I2C_SADDR_3, reg);
- if (rc < 0)
- break;
-
- /* Write "value" to I2C data port of OV511 */
- rc = reg_w(ov, R51x_I2C_DATA, value);
- if (rc < 0)
- break;
-
- /* Initiate 3-byte write cycle */
- rc = reg_w(ov, R511_I2C_CTL, 0x01);
- if (rc < 0)
- break;
-
- /* Retry until idle */
- do {
- rc = reg_r(ov, R511_I2C_CTL);
- } while (rc > 0 && ((rc&1) == 0));
- if (rc < 0)
- break;
-
- /* Ack? */
- if ((rc&2) == 0) {
- rc = 0;
- break;
- }
-#if 0
- /* I2C abort */
- reg_w(ov, R511_I2C_CTL, 0x10);
-#endif
- if (--retries < 0) {
- err("i2c write retries exhausted");
- rc = -1;
- break;
- }
- }
-
- return rc;
-}
-
-/* NOTE: Do not call this function directly!
- * The OV518 I2C I/O procedure is different, hence, this function.
- * This is normally only called from i2c_r(). Note that this function
- * always succeeds regardless of whether the sensor is present and working.
- */
-static int
-ov518_i2c_read_internal(struct usb_ov511 *ov, unsigned char reg)
-{
- int rc, value;
-
- /* Select camera register */
- rc = reg_w(ov, R51x_I2C_SADDR_2, reg);
- if (rc < 0)
- return rc;
-
- /* Initiate 2-byte write cycle */
- rc = reg_w(ov, R518_I2C_CTL, 0x03);
- if (rc < 0)
- return rc;
-
- /* Initiate 2-byte read cycle */
- rc = reg_w(ov, R518_I2C_CTL, 0x05);
- if (rc < 0)
- return rc;
-
- value = reg_r(ov, R51x_I2C_DATA);
-
- PDEBUG(5, "0x%02X:0x%02X", reg, value);
-
- return value;
-}
-
-/* NOTE: Do not call this function directly!
- * returns: negative is error, pos or zero is data */
-static int
-ov511_i2c_read_internal(struct usb_ov511 *ov, unsigned char reg)
-{
- int rc, value, retries;
-
- /* Two byte write cycle */
- for (retries = OV511_I2C_RETRIES; ; ) {
- /* Select camera register */
- rc = reg_w(ov, R51x_I2C_SADDR_2, reg);
- if (rc < 0)
- return rc;
-
- /* Initiate 2-byte write cycle */
- rc = reg_w(ov, R511_I2C_CTL, 0x03);
- if (rc < 0)
- return rc;
-
- /* Retry until idle */
- do {
- rc = reg_r(ov, R511_I2C_CTL);
- } while (rc > 0 && ((rc & 1) == 0));
- if (rc < 0)
- return rc;
-
- if ((rc&2) == 0) /* Ack? */
- break;
-
- /* I2C abort */
- reg_w(ov, R511_I2C_CTL, 0x10);
-
- if (--retries < 0) {
- err("i2c write retries exhausted");
- return -1;
- }
- }
-
- /* Two byte read cycle */
- for (retries = OV511_I2C_RETRIES; ; ) {
- /* Initiate 2-byte read cycle */
- rc = reg_w(ov, R511_I2C_CTL, 0x05);
- if (rc < 0)
- return rc;
-
- /* Retry until idle */
- do {
- rc = reg_r(ov, R511_I2C_CTL);
- } while (rc > 0 && ((rc&1) == 0));
- if (rc < 0)
- return rc;
-
- if ((rc&2) == 0) /* Ack? */
- break;
-
- /* I2C abort */
- rc = reg_w(ov, R511_I2C_CTL, 0x10);
- if (rc < 0)
- return rc;
-
- if (--retries < 0) {
- err("i2c read retries exhausted");
- return -1;
- }
- }
-
- value = reg_r(ov, R51x_I2C_DATA);
-
- PDEBUG(5, "0x%02X:0x%02X", reg, value);
-
- /* This is needed to make i2c_w() work */
- rc = reg_w(ov, R511_I2C_CTL, 0x05);
- if (rc < 0)
- return rc;
-
- return value;
-}
-
-/* returns: negative is error, pos or zero is data */
-static int
-i2c_r(struct usb_ov511 *ov, unsigned char reg)
-{
- int rc;
-
- mutex_lock(&ov->i2c_lock);
-
- if (ov->bclass == BCL_OV518)
- rc = ov518_i2c_read_internal(ov, reg);
- else
- rc = ov511_i2c_read_internal(ov, reg);
-
- mutex_unlock(&ov->i2c_lock);
-
- return rc;
-}
-
-static int
-i2c_w(struct usb_ov511 *ov, unsigned char reg, unsigned char value)
-{
- int rc;
-
- mutex_lock(&ov->i2c_lock);
-
- if (ov->bclass == BCL_OV518)
- rc = ov518_i2c_write_internal(ov, reg, value);
- else
- rc = ov511_i2c_write_internal(ov, reg, value);
-
- mutex_unlock(&ov->i2c_lock);
-
- return rc;
-}
-
-/* Do not call this function directly! */
-static int
-ov51x_i2c_write_mask_internal(struct usb_ov511 *ov,
- unsigned char reg,
- unsigned char value,
- unsigned char mask)
-{
- int rc;
- unsigned char oldval, newval;
-
- if (mask == 0xff) {
- newval = value;
- } else {
- if (ov->bclass == BCL_OV518)
- rc = ov518_i2c_read_internal(ov, reg);
- else
- rc = ov511_i2c_read_internal(ov, reg);
- if (rc < 0)
- return rc;
-
- oldval = (unsigned char) rc;
- oldval &= (~mask); /* Clear the masked bits */
- value &= mask; /* Enforce mask on value */
- newval = oldval | value; /* Set the desired bits */
- }
-
- if (ov->bclass == BCL_OV518)
- return (ov518_i2c_write_internal(ov, reg, newval));
- else
- return (ov511_i2c_write_internal(ov, reg, newval));
-}
-
-/* Writes bits at positions specified by mask to an I2C reg. Bits that are in
- * the same position as 1's in "mask" are cleared and set to "value". Bits
- * that are in the same position as 0's in "mask" are preserved, regardless
- * of their respective state in "value".
- */
-static int
-i2c_w_mask(struct usb_ov511 *ov,
- unsigned char reg,
- unsigned char value,
- unsigned char mask)
-{
- int rc;
-
- mutex_lock(&ov->i2c_lock);
- rc = ov51x_i2c_write_mask_internal(ov, reg, value, mask);
- mutex_unlock(&ov->i2c_lock);
-
- return rc;
-}
-
-/* Set the read and write slave IDs. The "slave" argument is the write slave,
- * and the read slave will be set to (slave + 1). ov->i2c_lock should be held
- * when calling this. This should not be called from outside the i2c I/O
- * functions.
- */
-static int
-i2c_set_slave_internal(struct usb_ov511 *ov, unsigned char slave)
-{
- int rc;
-
- rc = reg_w(ov, R51x_I2C_W_SID, slave);
- if (rc < 0)
- return rc;
-
- rc = reg_w(ov, R51x_I2C_R_SID, slave + 1);
- if (rc < 0)
- return rc;
-
- return 0;
-}
-
-/* Write to a specific I2C slave ID and register, using the specified mask */
-static int
-i2c_w_slave(struct usb_ov511 *ov,
- unsigned char slave,
- unsigned char reg,
- unsigned char value,
- unsigned char mask)
-{
- int rc = 0;
-
- mutex_lock(&ov->i2c_lock);
-
- /* Set new slave IDs */
- rc = i2c_set_slave_internal(ov, slave);
- if (rc < 0)
- goto out;
-
- rc = ov51x_i2c_write_mask_internal(ov, reg, value, mask);
-
-out:
- /* Restore primary IDs */
- if (i2c_set_slave_internal(ov, ov->primary_i2c_slave) < 0)
- err("Couldn't restore primary I2C slave");
-
- mutex_unlock(&ov->i2c_lock);
- return rc;
-}
-
-/* Read from a specific I2C slave ID and register */
-static int
-i2c_r_slave(struct usb_ov511 *ov,
- unsigned char slave,
- unsigned char reg)
-{
- int rc;
-
- mutex_lock(&ov->i2c_lock);
-
- /* Set new slave IDs */
- rc = i2c_set_slave_internal(ov, slave);
- if (rc < 0)
- goto out;
-
- if (ov->bclass == BCL_OV518)
- rc = ov518_i2c_read_internal(ov, reg);
- else
- rc = ov511_i2c_read_internal(ov, reg);
-
-out:
- /* Restore primary IDs */
- if (i2c_set_slave_internal(ov, ov->primary_i2c_slave) < 0)
- err("Couldn't restore primary I2C slave");
-
- mutex_unlock(&ov->i2c_lock);
- return rc;
-}
-
-/* Sets I2C read and write slave IDs. Returns <0 for error */
-static int
-ov51x_set_slave_ids(struct usb_ov511 *ov, unsigned char sid)
-{
- int rc;
-
- mutex_lock(&ov->i2c_lock);
-
- rc = i2c_set_slave_internal(ov, sid);
- if (rc < 0)
- goto out;
-
- // FIXME: Is this actually necessary?
- rc = ov51x_reset(ov, OV511_RESET_NOREGS);
-out:
- mutex_unlock(&ov->i2c_lock);
- return rc;
-}
-
-static int
-write_regvals(struct usb_ov511 *ov, struct ov511_regvals * pRegvals)
-{
- int rc;
-
- while (pRegvals->bus != OV511_DONE_BUS) {
- if (pRegvals->bus == OV511_REG_BUS) {
- if ((rc = reg_w(ov, pRegvals->reg, pRegvals->val)) < 0)
- return rc;
- } else if (pRegvals->bus == OV511_I2C_BUS) {
- if ((rc = i2c_w(ov, pRegvals->reg, pRegvals->val)) < 0)
- return rc;
- } else {
- err("Bad regval array");
- return -1;
- }
- pRegvals++;
- }
- return 0;
-}
-
-#ifdef OV511_DEBUG
-static void
-dump_i2c_range(struct usb_ov511 *ov, int reg1, int regn)
-{
- int i, rc;
-
- for (i = reg1; i <= regn; i++) {
- rc = i2c_r(ov, i);
- dev_info(&ov->dev->dev, "Sensor[0x%02X] = 0x%02X\n", i, rc);
- }
-}
-
-static void
-dump_i2c_regs(struct usb_ov511 *ov)
-{
- dev_info(&ov->dev->dev, "I2C REGS\n");
- dump_i2c_range(ov, 0x00, 0x7C);
-}
-
-static void
-dump_reg_range(struct usb_ov511 *ov, int reg1, int regn)
-{
- int i, rc;
-
- for (i = reg1; i <= regn; i++) {
- rc = reg_r(ov, i);
- dev_info(&ov->dev->dev, "OV511[0x%02X] = 0x%02X\n", i, rc);
- }
-}
-
-static void
-ov511_dump_regs(struct usb_ov511 *ov)
-{
- dev_info(&ov->dev->dev, "CAMERA INTERFACE REGS\n");
- dump_reg_range(ov, 0x10, 0x1f);
- dev_info(&ov->dev->dev, "DRAM INTERFACE REGS\n");
- dump_reg_range(ov, 0x20, 0x23);
- dev_info(&ov->dev->dev, "ISO FIFO REGS\n");
- dump_reg_range(ov, 0x30, 0x31);
- dev_info(&ov->dev->dev, "PIO REGS\n");
- dump_reg_range(ov, 0x38, 0x39);
- dump_reg_range(ov, 0x3e, 0x3e);
- dev_info(&ov->dev->dev, "I2C REGS\n");
- dump_reg_range(ov, 0x40, 0x49);
- dev_info(&ov->dev->dev, "SYSTEM CONTROL REGS\n");
- dump_reg_range(ov, 0x50, 0x55);
- dump_reg_range(ov, 0x5e, 0x5f);
- dev_info(&ov->dev->dev, "OmniCE REGS\n");
- dump_reg_range(ov, 0x70, 0x79);
- /* NOTE: Quantization tables are not readable. You will get the value
- * in reg. 0x79 for every table register */
- dump_reg_range(ov, 0x80, 0x9f);
- dump_reg_range(ov, 0xa0, 0xbf);
-
-}
-
-static void
-ov518_dump_regs(struct usb_ov511 *ov)
-{
- dev_info(&ov->dev->dev, "VIDEO MODE REGS\n");
- dump_reg_range(ov, 0x20, 0x2f);
- dev_info(&ov->dev->dev, "DATA PUMP AND SNAPSHOT REGS\n");
- dump_reg_range(ov, 0x30, 0x3f);
- dev_info(&ov->dev->dev, "I2C REGS\n");
- dump_reg_range(ov, 0x40, 0x4f);
- dev_info(&ov->dev->dev, "SYSTEM CONTROL AND VENDOR REGS\n");
- dump_reg_range(ov, 0x50, 0x5f);
- dev_info(&ov->dev->dev, "60 - 6F\n");
- dump_reg_range(ov, 0x60, 0x6f);
- dev_info(&ov->dev->dev, "70 - 7F\n");
- dump_reg_range(ov, 0x70, 0x7f);
- dev_info(&ov->dev->dev, "Y QUANTIZATION TABLE\n");
- dump_reg_range(ov, 0x80, 0x8f);
- dev_info(&ov->dev->dev, "UV QUANTIZATION TABLE\n");
- dump_reg_range(ov, 0x90, 0x9f);
- dev_info(&ov->dev->dev, "A0 - BF\n");
- dump_reg_range(ov, 0xa0, 0xbf);
- dev_info(&ov->dev->dev, "CBR\n");
- dump_reg_range(ov, 0xc0, 0xcf);
-}
-#endif
-
-/*****************************************************************************/
-
-/* Temporarily stops OV511 from functioning. Must do this before changing
- * registers while the camera is streaming */
-static inline int
-ov51x_stop(struct usb_ov511 *ov)
-{
- PDEBUG(4, "stopping");
- ov->stopped = 1;
- if (ov->bclass == BCL_OV518)
- return (reg_w_mask(ov, R51x_SYS_RESET, 0x3a, 0x3a));
- else
- return (reg_w(ov, R51x_SYS_RESET, 0x3d));
-}
-
-/* Restarts OV511 after ov511_stop() is called. Has no effect if it is not
- * actually stopped (for performance). */
-static inline int
-ov51x_restart(struct usb_ov511 *ov)
-{
- if (ov->stopped) {
- PDEBUG(4, "restarting");
- ov->stopped = 0;
-
- /* Reinitialize the stream */
- if (ov->bclass == BCL_OV518)
- reg_w(ov, 0x2f, 0x80);
-
- return (reg_w(ov, R51x_SYS_RESET, 0x00));
- }
-
- return 0;
-}
-
-/* Sleeps until no frames are active. Returns !0 if got signal */
-static int
-ov51x_wait_frames_inactive(struct usb_ov511 *ov)
-{
- return wait_event_interruptible(ov->wq, ov->curframe < 0);
-}
-
-/* Resets the hardware snapshot button */
-static void
-ov51x_clear_snapshot(struct usb_ov511 *ov)
-{
- if (ov->bclass == BCL_OV511) {
- reg_w(ov, R51x_SYS_SNAP, 0x00);
- reg_w(ov, R51x_SYS_SNAP, 0x02);
- reg_w(ov, R51x_SYS_SNAP, 0x00);
- } else if (ov->bclass == BCL_OV518) {
- dev_warn(&ov->dev->dev,
- "snapshot reset not supported yet on OV518(+)\n");
- } else {
- dev_err(&ov->dev->dev, "clear snap: invalid bridge type\n");
- }
-}
-
-#if 0
-/* Checks the status of the snapshot button. Returns 1 if it was pressed since
- * it was last cleared, and zero in all other cases (including errors) */
-static int
-ov51x_check_snapshot(struct usb_ov511 *ov)
-{
- int ret, status = 0;
-
- if (ov->bclass == BCL_OV511) {
- ret = reg_r(ov, R51x_SYS_SNAP);
- if (ret < 0) {
- dev_err(&ov->dev->dev,
- "Error checking snspshot status (%d)\n", ret);
- } else if (ret & 0x08) {
- status = 1;
- }
- } else if (ov->bclass == BCL_OV518) {
- dev_warn(&ov->dev->dev,
- "snapshot check not supported yet on OV518(+)\n");
- } else {
- dev_err(&ov->dev->dev, "clear snap: invalid bridge type\n");
- }
-
- return status;
-}
-#endif
-
-/* This does an initial reset of an OmniVision sensor and ensures that I2C
- * is synchronized. Returns <0 for failure.
- */
-static int
-init_ov_sensor(struct usb_ov511 *ov)
-{
- int i, success;
-
- /* Reset the sensor */
- if (i2c_w(ov, 0x12, 0x80) < 0)
- return -EIO;
-
- /* Wait for it to initialize */
- msleep(150);
-
- for (i = 0, success = 0; i < i2c_detect_tries && !success; i++) {
- if ((i2c_r(ov, OV7610_REG_ID_HIGH) == 0x7F) &&
- (i2c_r(ov, OV7610_REG_ID_LOW) == 0xA2)) {
- success = 1;
- continue;
- }
-
- /* Reset the sensor */
- if (i2c_w(ov, 0x12, 0x80) < 0)
- return -EIO;
- /* Wait for it to initialize */
- msleep(150);
- /* Dummy read to sync I2C */
- if (i2c_r(ov, 0x00) < 0)
- return -EIO;
- }
-
- if (!success)
- return -EIO;
-
- PDEBUG(1, "I2C synced in %d attempt(s)", i);
-
- return 0;
-}
-
-static int
-ov511_set_packet_size(struct usb_ov511 *ov, int size)
-{
- int alt, mult;
-
- if (ov51x_stop(ov) < 0)
- return -EIO;
-
- mult = size >> 5;
-
- if (ov->bridge == BRG_OV511) {
- if (size == 0)
- alt = OV511_ALT_SIZE_0;
- else if (size == 257)
- alt = OV511_ALT_SIZE_257;
- else if (size == 513)
- alt = OV511_ALT_SIZE_513;
- else if (size == 769)
- alt = OV511_ALT_SIZE_769;
- else if (size == 993)
- alt = OV511_ALT_SIZE_993;
- else {
- err("Set packet size: invalid size (%d)", size);
- return -EINVAL;
- }
- } else if (ov->bridge == BRG_OV511PLUS) {
- if (size == 0)
- alt = OV511PLUS_ALT_SIZE_0;
- else if (size == 33)
- alt = OV511PLUS_ALT_SIZE_33;
- else if (size == 129)
- alt = OV511PLUS_ALT_SIZE_129;
- else if (size == 257)
- alt = OV511PLUS_ALT_SIZE_257;
- else if (size == 385)
- alt = OV511PLUS_ALT_SIZE_385;
- else if (size == 513)
- alt = OV511PLUS_ALT_SIZE_513;
- else if (size == 769)
- alt = OV511PLUS_ALT_SIZE_769;
- else if (size == 961)
- alt = OV511PLUS_ALT_SIZE_961;
- else {
- err("Set packet size: invalid size (%d)", size);
- return -EINVAL;
- }
- } else {
- err("Set packet size: Invalid bridge type");
- return -EINVAL;
- }
-
- PDEBUG(3, "%d, mult=%d, alt=%d", size, mult, alt);
-
- if (reg_w(ov, R51x_FIFO_PSIZE, mult) < 0)
- return -EIO;
-
- if (usb_set_interface(ov->dev, ov->iface, alt) < 0) {
- err("Set packet size: set interface error");
- return -EBUSY;
- }
-
- if (ov51x_reset(ov, OV511_RESET_NOREGS) < 0)
- return -EIO;
-
- ov->packet_size = size;
-
- if (ov51x_restart(ov) < 0)
- return -EIO;
-
- return 0;
-}
-
-/* Note: Unlike the OV511/OV511+, the size argument does NOT include the
- * optional packet number byte. The actual size *is* stored in ov->packet_size,
- * though. */
-static int
-ov518_set_packet_size(struct usb_ov511 *ov, int size)
-{
- int alt;
-
- if (ov51x_stop(ov) < 0)
- return -EIO;
-
- if (ov->bclass == BCL_OV518) {
- if (size == 0)
- alt = OV518_ALT_SIZE_0;
- else if (size == 128)
- alt = OV518_ALT_SIZE_128;
- else if (size == 256)
- alt = OV518_ALT_SIZE_256;
- else if (size == 384)
- alt = OV518_ALT_SIZE_384;
- else if (size == 512)
- alt = OV518_ALT_SIZE_512;
- else if (size == 640)
- alt = OV518_ALT_SIZE_640;
- else if (size == 768)
- alt = OV518_ALT_SIZE_768;
- else if (size == 896)
- alt = OV518_ALT_SIZE_896;
- else {
- err("Set packet size: invalid size (%d)", size);
- return -EINVAL;
- }
- } else {
- err("Set packet size: Invalid bridge type");
- return -EINVAL;
- }
-
- PDEBUG(3, "%d, alt=%d", size, alt);
-
- ov->packet_size = size;
- if (size > 0) {
- /* Program ISO FIFO size reg (packet number isn't included) */
- ov518_reg_w32(ov, 0x30, size, 2);
-
- if (ov->packet_numbering)
- ++ov->packet_size;
- }
-
- if (usb_set_interface(ov->dev, ov->iface, alt) < 0) {
- err("Set packet size: set interface error");
- return -EBUSY;
- }
-
- /* Initialize the stream */
- if (reg_w(ov, 0x2f, 0x80) < 0)
- return -EIO;
-
- if (ov51x_restart(ov) < 0)
- return -EIO;
-
- if (ov51x_reset(ov, OV511_RESET_NOREGS) < 0)
- return -EIO;
-
- return 0;
-}
-
-/* Upload compression params and quantization tables. Returns 0 for success. */
-static int
-ov511_init_compression(struct usb_ov511 *ov)
-{
- int rc = 0;
-
- if (!ov->compress_inited) {
- reg_w(ov, 0x70, phy);
- reg_w(ov, 0x71, phuv);
- reg_w(ov, 0x72, pvy);
- reg_w(ov, 0x73, pvuv);
- reg_w(ov, 0x74, qhy);
- reg_w(ov, 0x75, qhuv);
- reg_w(ov, 0x76, qvy);
- reg_w(ov, 0x77, qvuv);
-
- if (ov511_upload_quan_tables(ov) < 0) {
- err("Error uploading quantization tables");
- rc = -EIO;
- goto out;
- }
- }
-
- ov->compress_inited = 1;
-out:
- return rc;
-}
-
-/* Upload compression params and quantization tables. Returns 0 for success. */
-static int
-ov518_init_compression(struct usb_ov511 *ov)
-{
- int rc = 0;
-
- if (!ov->compress_inited) {
- if (ov518_upload_quan_tables(ov) < 0) {
- err("Error uploading quantization tables");
- rc = -EIO;
- goto out;
- }
- }
-
- ov->compress_inited = 1;
-out:
- return rc;
-}
-
-/* -------------------------------------------------------------------------- */
-
-/* Sets sensor's contrast setting to "val" */
-static int
-sensor_set_contrast(struct usb_ov511 *ov, unsigned short val)
-{
- int rc;
-
- PDEBUG(3, "%d", val);
-
- if (ov->stop_during_set)
- if (ov51x_stop(ov) < 0)
- return -EIO;
-
- switch (ov->sensor) {
- case SEN_OV7610:
- case SEN_OV6620:
- {
- rc = i2c_w(ov, OV7610_REG_CNT, val >> 8);
- if (rc < 0)
- goto out;
- break;
- }
- case SEN_OV6630:
- {
- rc = i2c_w_mask(ov, OV7610_REG_CNT, val >> 12, 0x0f);
- if (rc < 0)
- goto out;
- break;
- }
- case SEN_OV7620:
- {
- unsigned char ctab[] = {
- 0x01, 0x05, 0x09, 0x11, 0x15, 0x35, 0x37, 0x57,
- 0x5b, 0xa5, 0xa7, 0xc7, 0xc9, 0xcf, 0xef, 0xff
- };
-
- /* Use Y gamma control instead. Bit 0 enables it. */
- rc = i2c_w(ov, 0x64, ctab[val>>12]);
- if (rc < 0)
- goto out;
- break;
- }
- case SEN_SAA7111A:
- {
- rc = i2c_w(ov, 0x0b, val >> 9);
- if (rc < 0)
- goto out;
- break;
- }
- default:
- {
- PDEBUG(3, "Unsupported with this sensor");
- rc = -EPERM;
- goto out;
- }
- }
-
- rc = 0; /* Success */
- ov->contrast = val;
-out:
- if (ov51x_restart(ov) < 0)
- return -EIO;
-
- return rc;
-}
-
-/* Gets sensor's contrast setting */
-static int
-sensor_get_contrast(struct usb_ov511 *ov, unsigned short *val)
-{
- int rc;
-
- switch (ov->sensor) {
- case SEN_OV7610:
- case SEN_OV6620:
- rc = i2c_r(ov, OV7610_REG_CNT);
- if (rc < 0)
- return rc;
- else
- *val = rc << 8;
- break;
- case SEN_OV6630:
- rc = i2c_r(ov, OV7610_REG_CNT);
- if (rc < 0)
- return rc;
- else
- *val = rc << 12;
- break;
- case SEN_OV7620:
- /* Use Y gamma reg instead. Bit 0 is the enable bit. */
- rc = i2c_r(ov, 0x64);
- if (rc < 0)
- return rc;
- else
- *val = (rc & 0xfe) << 8;
- break;
- case SEN_SAA7111A:
- *val = ov->contrast;
- break;
- default:
- PDEBUG(3, "Unsupported with this sensor");
- return -EPERM;
- }
-
- PDEBUG(3, "%d", *val);
- ov->contrast = *val;
-
- return 0;
-}
-
-/* -------------------------------------------------------------------------- */
-
-/* Sets sensor's brightness setting to "val" */
-static int
-sensor_set_brightness(struct usb_ov511 *ov, unsigned short val)
-{
- int rc;
-
- PDEBUG(4, "%d", val);
-
- if (ov->stop_during_set)
- if (ov51x_stop(ov) < 0)
- return -EIO;
-
- switch (ov->sensor) {
- case SEN_OV7610:
- case SEN_OV76BE:
- case SEN_OV6620:
- case SEN_OV6630:
- rc = i2c_w(ov, OV7610_REG_BRT, val >> 8);
- if (rc < 0)
- goto out;
- break;
- case SEN_OV7620:
- /* 7620 doesn't like manual changes when in auto mode */
- if (!ov->auto_brt) {
- rc = i2c_w(ov, OV7610_REG_BRT, val >> 8);
- if (rc < 0)
- goto out;
- }
- break;
- case SEN_SAA7111A:
- rc = i2c_w(ov, 0x0a, val >> 8);
- if (rc < 0)
- goto out;
- break;
- default:
- PDEBUG(3, "Unsupported with this sensor");
- rc = -EPERM;
- goto out;
- }
-
- rc = 0; /* Success */
- ov->brightness = val;
-out:
- if (ov51x_restart(ov) < 0)
- return -EIO;
-
- return rc;
-}
-
-/* Gets sensor's brightness setting */
-static int
-sensor_get_brightness(struct usb_ov511 *ov, unsigned short *val)
-{
- int rc;
-
- switch (ov->sensor) {
- case SEN_OV7610:
- case SEN_OV76BE:
- case SEN_OV7620:
- case SEN_OV6620:
- case SEN_OV6630:
- rc = i2c_r(ov, OV7610_REG_BRT);
- if (rc < 0)
- return rc;
- else
- *val = rc << 8;
- break;
- case SEN_SAA7111A:
- *val = ov->brightness;
- break;
- default:
- PDEBUG(3, "Unsupported with this sensor");
- return -EPERM;
- }
-
- PDEBUG(3, "%d", *val);
- ov->brightness = *val;
-
- return 0;
-}
-
-/* -------------------------------------------------------------------------- */
-
-/* Sets sensor's saturation (color intensity) setting to "val" */
-static int
-sensor_set_saturation(struct usb_ov511 *ov, unsigned short val)
-{
- int rc;
-
- PDEBUG(3, "%d", val);
-
- if (ov->stop_during_set)
- if (ov51x_stop(ov) < 0)
- return -EIO;
-
- switch (ov->sensor) {
- case SEN_OV7610:
- case SEN_OV76BE:
- case SEN_OV6620:
- case SEN_OV6630:
- rc = i2c_w(ov, OV7610_REG_SAT, val >> 8);
- if (rc < 0)
- goto out;
- break;
- case SEN_OV7620:
-// /* Use UV gamma control instead. Bits 0 & 7 are reserved. */
-// rc = ov_i2c_write(ov->dev, 0x62, (val >> 9) & 0x7e);
-// if (rc < 0)
-// goto out;
- rc = i2c_w(ov, OV7610_REG_SAT, val >> 8);
- if (rc < 0)
- goto out;
- break;
- case SEN_SAA7111A:
- rc = i2c_w(ov, 0x0c, val >> 9);
- if (rc < 0)
- goto out;
- break;
- default:
- PDEBUG(3, "Unsupported with this sensor");
- rc = -EPERM;
- goto out;
- }
-
- rc = 0; /* Success */
- ov->colour = val;
-out:
- if (ov51x_restart(ov) < 0)
- return -EIO;
-
- return rc;
-}
-
-/* Gets sensor's saturation (color intensity) setting */
-static int
-sensor_get_saturation(struct usb_ov511 *ov, unsigned short *val)
-{
- int rc;
-
- switch (ov->sensor) {
- case SEN_OV7610:
- case SEN_OV76BE:
- case SEN_OV6620:
- case SEN_OV6630:
- rc = i2c_r(ov, OV7610_REG_SAT);
- if (rc < 0)
- return rc;
- else
- *val = rc << 8;
- break;
- case SEN_OV7620:
-// /* Use UV gamma reg instead. Bits 0 & 7 are reserved. */
-// rc = i2c_r(ov, 0x62);
-// if (rc < 0)
-// return rc;
-// else
-// *val = (rc & 0x7e) << 9;
- rc = i2c_r(ov, OV7610_REG_SAT);
- if (rc < 0)
- return rc;
- else
- *val = rc << 8;
- break;
- case SEN_SAA7111A:
- *val = ov->colour;
- break;
- default:
- PDEBUG(3, "Unsupported with this sensor");
- return -EPERM;
- }
-
- PDEBUG(3, "%d", *val);
- ov->colour = *val;
-
- return 0;
-}
-
-/* -------------------------------------------------------------------------- */
-
-/* Sets sensor's hue (red/blue balance) setting to "val" */
-static int
-sensor_set_hue(struct usb_ov511 *ov, unsigned short val)
-{
- int rc;
-
- PDEBUG(3, "%d", val);
-
- if (ov->stop_during_set)
- if (ov51x_stop(ov) < 0)
- return -EIO;
-
- switch (ov->sensor) {
- case SEN_OV7610:
- case SEN_OV6620:
- case SEN_OV6630:
- rc = i2c_w(ov, OV7610_REG_RED, 0xFF - (val >> 8));
- if (rc < 0)
- goto out;
-
- rc = i2c_w(ov, OV7610_REG_BLUE, val >> 8);
- if (rc < 0)
- goto out;
- break;
- case SEN_OV7620:
-// Hue control is causing problems. I will enable it once it's fixed.
-#if 0
- rc = i2c_w(ov, 0x7a, (unsigned char)(val >> 8) + 0xb);
- if (rc < 0)
- goto out;
-
- rc = i2c_w(ov, 0x79, (unsigned char)(val >> 8) + 0xb);
- if (rc < 0)
- goto out;
-#endif
- break;
- case SEN_SAA7111A:
- rc = i2c_w(ov, 0x0d, (val + 32768) >> 8);
- if (rc < 0)
- goto out;
- break;
- default:
- PDEBUG(3, "Unsupported with this sensor");
- rc = -EPERM;
- goto out;
- }
-
- rc = 0; /* Success */
- ov->hue = val;
-out:
- if (ov51x_restart(ov) < 0)
- return -EIO;
-
- return rc;
-}
-
-/* Gets sensor's hue (red/blue balance) setting */
-static int
-sensor_get_hue(struct usb_ov511 *ov, unsigned short *val)
-{
- int rc;
-
- switch (ov->sensor) {
- case SEN_OV7610:
- case SEN_OV6620:
- case SEN_OV6630:
- rc = i2c_r(ov, OV7610_REG_BLUE);
- if (rc < 0)
- return rc;
- else
- *val = rc << 8;
- break;
- case SEN_OV7620:
- rc = i2c_r(ov, 0x7a);
- if (rc < 0)
- return rc;
- else
- *val = rc << 8;
- break;
- case SEN_SAA7111A:
- *val = ov->hue;
- break;
- default:
- PDEBUG(3, "Unsupported with this sensor");
- return -EPERM;
- }
-
- PDEBUG(3, "%d", *val);
- ov->hue = *val;
-
- return 0;
-}
-
-/* -------------------------------------------------------------------------- */
-
-static int
-sensor_set_picture(struct usb_ov511 *ov, struct video_picture *p)
-{
- int rc;
-
- PDEBUG(4, "sensor_set_picture");
-
- ov->whiteness = p->whiteness;
-
- /* Don't return error if a setting is unsupported, or rest of settings
- * will not be performed */
-
- rc = sensor_set_contrast(ov, p->contrast);
- if (FATAL_ERROR(rc))
- return rc;
-
- rc = sensor_set_brightness(ov, p->brightness);
- if (FATAL_ERROR(rc))
- return rc;
-
- rc = sensor_set_saturation(ov, p->colour);
- if (FATAL_ERROR(rc))
- return rc;
-
- rc = sensor_set_hue(ov, p->hue);
- if (FATAL_ERROR(rc))
- return rc;
-
- return 0;
-}
-
-static int
-sensor_get_picture(struct usb_ov511 *ov, struct video_picture *p)
-{
- int rc;
-
- PDEBUG(4, "sensor_get_picture");
-
- /* Don't return error if a setting is unsupported, or rest of settings
- * will not be performed */
-
- rc = sensor_get_contrast(ov, &(p->contrast));
- if (FATAL_ERROR(rc))
- return rc;
-
- rc = sensor_get_brightness(ov, &(p->brightness));
- if (FATAL_ERROR(rc))
- return rc;
-
- rc = sensor_get_saturation(ov, &(p->colour));
- if (FATAL_ERROR(rc))
- return rc;
-
- rc = sensor_get_hue(ov, &(p->hue));
- if (FATAL_ERROR(rc))
- return rc;
-
- p->whiteness = 105 << 8;
-
- return 0;
-}
-
-#if 0
-// FIXME: Exposure range is only 0x00-0x7f in interlace mode
-/* Sets current exposure for sensor. This only has an effect if auto-exposure
- * is off */
-static inline int
-sensor_set_exposure(struct usb_ov511 *ov, unsigned char val)
-{
- int rc;
-
- PDEBUG(3, "%d", val);
-
- if (ov->stop_during_set)
- if (ov51x_stop(ov) < 0)
- return -EIO;
-
- switch (ov->sensor) {
- case SEN_OV6620:
- case SEN_OV6630:
- case SEN_OV7610:
- case SEN_OV7620:
- case SEN_OV76BE:
- case SEN_OV8600:
- rc = i2c_w(ov, 0x10, val);
- if (rc < 0)
- goto out;
-
- break;
- case SEN_KS0127:
- case SEN_KS0127B:
- case SEN_SAA7111A:
- PDEBUG(3, "Unsupported with this sensor");
- return -EPERM;
- default:
- err("Sensor not supported for set_exposure");
- return -EINVAL;
- }
-
- rc = 0; /* Success */
- ov->exposure = val;
-out:
- if (ov51x_restart(ov) < 0)
- return -EIO;
-
- return rc;
-}
-#endif
-
-/* Gets current exposure level from sensor, regardless of whether it is under
- * manual control. */
-static int
-sensor_get_exposure(struct usb_ov511 *ov, unsigned char *val)
-{
- int rc;
-
- switch (ov->sensor) {
- case SEN_OV7610:
- case SEN_OV6620:
- case SEN_OV6630:
- case SEN_OV7620:
- case SEN_OV76BE:
- case SEN_OV8600:
- rc = i2c_r(ov, 0x10);
- if (rc < 0)
- return rc;
- else
- *val = rc;
- break;
- case SEN_KS0127:
- case SEN_KS0127B:
- case SEN_SAA7111A:
- val = NULL;
- PDEBUG(3, "Unsupported with this sensor");
- return -EPERM;
- default:
- err("Sensor not supported for get_exposure");
- return -EINVAL;
- }
-
- PDEBUG(3, "%d", *val);
- ov->exposure = *val;
-
- return 0;
-}
-
-/* Turns on or off the LED. Only has an effect with OV511+/OV518(+) */
-static void
-ov51x_led_control(struct usb_ov511 *ov, int enable)
-{
- PDEBUG(4, " (%s)", enable ? "turn on" : "turn off");
-
- if (ov->bridge == BRG_OV511PLUS)
- reg_w(ov, R511_SYS_LED_CTL, enable ? 1 : 0);
- else if (ov->bclass == BCL_OV518)
- reg_w_mask(ov, R518_GPIO_OUT, enable ? 0x02 : 0x00, 0x02);
-
- return;
-}
-
-/* Matches the sensor's internal frame rate to the lighting frequency.
- * Valid frequencies are:
- * 50 - 50Hz, for European and Asian lighting
- * 60 - 60Hz, for American lighting
- *
- * Tested with: OV7610, OV7620, OV76BE, OV6620
- * Unsupported: KS0127, KS0127B, SAA7111A
- * Returns: 0 for success
- */
-static int
-sensor_set_light_freq(struct usb_ov511 *ov, int freq)
-{
- int sixty;
-
- PDEBUG(4, "%d Hz", freq);
-
- if (freq == 60)
- sixty = 1;
- else if (freq == 50)
- sixty = 0;
- else {
- err("Invalid light freq (%d Hz)", freq);
- return -EINVAL;
- }
-
- switch (ov->sensor) {
- case SEN_OV7610:
- i2c_w_mask(ov, 0x2a, sixty?0x00:0x80, 0x80);
- i2c_w(ov, 0x2b, sixty?0x00:0xac);
- i2c_w_mask(ov, 0x13, 0x10, 0x10);
- i2c_w_mask(ov, 0x13, 0x00, 0x10);
- break;
- case SEN_OV7620:
- case SEN_OV76BE:
- case SEN_OV8600:
- i2c_w_mask(ov, 0x2a, sixty?0x00:0x80, 0x80);
- i2c_w(ov, 0x2b, sixty?0x00:0xac);
- i2c_w_mask(ov, 0x76, 0x01, 0x01);
- break;
- case SEN_OV6620:
- case SEN_OV6630:
- i2c_w(ov, 0x2b, sixty?0xa8:0x28);
- i2c_w(ov, 0x2a, sixty?0x84:0xa4);
- break;
- case SEN_KS0127:
- case SEN_KS0127B:
- case SEN_SAA7111A:
- PDEBUG(5, "Unsupported with this sensor");
- return -EPERM;
- default:
- err("Sensor not supported for set_light_freq");
- return -EINVAL;
- }
-
- ov->lightfreq = freq;
-
- return 0;
-}
-
-/* If enable is true, turn on the sensor's banding filter, otherwise turn it
- * off. This filter tries to reduce the pattern of horizontal light/dark bands
- * caused by some (usually fluorescent) lighting. The light frequency must be
- * set either before or after enabling it with ov51x_set_light_freq().
- *
- * Tested with: OV7610, OV7620, OV76BE, OV6620.
- * Unsupported: KS0127, KS0127B, SAA7111A
- * Returns: 0 for success
- */
-static int
-sensor_set_banding_filter(struct usb_ov511 *ov, int enable)
-{
- int rc;
-
- PDEBUG(4, " (%s)", enable ? "turn on" : "turn off");
-
- if (ov->sensor == SEN_KS0127 || ov->sensor == SEN_KS0127B
- || ov->sensor == SEN_SAA7111A) {
- PDEBUG(5, "Unsupported with this sensor");
- return -EPERM;
- }
-
- rc = i2c_w_mask(ov, 0x2d, enable?0x04:0x00, 0x04);
- if (rc < 0)
- return rc;
-
- ov->bandfilt = enable;
-
- return 0;
-}
-
-/* If enable is true, turn on the sensor's auto brightness control, otherwise
- * turn it off.
- *
- * Unsupported: KS0127, KS0127B, SAA7111A
- * Returns: 0 for success
- */
-static int
-sensor_set_auto_brightness(struct usb_ov511 *ov, int enable)
-{
- int rc;
-
- PDEBUG(4, " (%s)", enable ? "turn on" : "turn off");
-
- if (ov->sensor == SEN_KS0127 || ov->sensor == SEN_KS0127B
- || ov->sensor == SEN_SAA7111A) {
- PDEBUG(5, "Unsupported with this sensor");
- return -EPERM;
- }
-
- rc = i2c_w_mask(ov, 0x2d, enable?0x10:0x00, 0x10);
- if (rc < 0)
- return rc;
-
- ov->auto_brt = enable;
-
- return 0;
-}
-
-/* If enable is true, turn on the sensor's auto exposure control, otherwise
- * turn it off.
- *
- * Unsupported: KS0127, KS0127B, SAA7111A
- * Returns: 0 for success
- */
-static int
-sensor_set_auto_exposure(struct usb_ov511 *ov, int enable)
-{
- PDEBUG(4, " (%s)", enable ? "turn on" : "turn off");
-
- switch (ov->sensor) {
- case SEN_OV7610:
- i2c_w_mask(ov, 0x29, enable?0x00:0x80, 0x80);
- break;
- case SEN_OV6620:
- case SEN_OV7620:
- case SEN_OV76BE:
- case SEN_OV8600:
- i2c_w_mask(ov, 0x13, enable?0x01:0x00, 0x01);
- break;
- case SEN_OV6630:
- i2c_w_mask(ov, 0x28, enable?0x00:0x10, 0x10);
- break;
- case SEN_KS0127:
- case SEN_KS0127B:
- case SEN_SAA7111A:
- PDEBUG(5, "Unsupported with this sensor");
- return -EPERM;
- default:
- err("Sensor not supported for set_auto_exposure");
- return -EINVAL;
- }
-
- ov->auto_exp = enable;
-
- return 0;
-}
-
-/* Modifies the sensor's exposure algorithm to allow proper exposure of objects
- * that are illuminated from behind.
- *
- * Tested with: OV6620, OV7620
- * Unsupported: OV7610, OV76BE, KS0127, KS0127B, SAA7111A
- * Returns: 0 for success
- */
-static int
-sensor_set_backlight(struct usb_ov511 *ov, int enable)
-{
- PDEBUG(4, " (%s)", enable ? "turn on" : "turn off");
-
- switch (ov->sensor) {
- case SEN_OV7620:
- case SEN_OV8600:
- i2c_w_mask(ov, 0x68, enable?0xe0:0xc0, 0xe0);
- i2c_w_mask(ov, 0x29, enable?0x08:0x00, 0x08);
- i2c_w_mask(ov, 0x28, enable?0x02:0x00, 0x02);
- break;
- case SEN_OV6620:
- i2c_w_mask(ov, 0x4e, enable?0xe0:0xc0, 0xe0);
- i2c_w_mask(ov, 0x29, enable?0x08:0x00, 0x08);
- i2c_w_mask(ov, 0x0e, enable?0x80:0x00, 0x80);
- break;
- case SEN_OV6630:
- i2c_w_mask(ov, 0x4e, enable?0x80:0x60, 0xe0);
- i2c_w_mask(ov, 0x29, enable?0x08:0x00, 0x08);
- i2c_w_mask(ov, 0x28, enable?0x02:0x00, 0x02);
- break;
- case SEN_OV7610:
- case SEN_OV76BE:
- case SEN_KS0127:
- case SEN_KS0127B:
- case SEN_SAA7111A:
- PDEBUG(5, "Unsupported with this sensor");
- return -EPERM;
- default:
- err("Sensor not supported for set_backlight");
- return -EINVAL;
- }
-
- ov->backlight = enable;
-
- return 0;
-}
-
-static int
-sensor_set_mirror(struct usb_ov511 *ov, int enable)
-{
- PDEBUG(4, " (%s)", enable ? "turn on" : "turn off");
-
- switch (ov->sensor) {
- case SEN_OV6620:
- case SEN_OV6630:
- case SEN_OV7610:
- case SEN_OV7620:
- case SEN_OV76BE:
- case SEN_OV8600:
- i2c_w_mask(ov, 0x12, enable?0x40:0x00, 0x40);
- break;
- case SEN_KS0127:
- case SEN_KS0127B:
- case SEN_SAA7111A:
- PDEBUG(5, "Unsupported with this sensor");
- return -EPERM;
- default:
- err("Sensor not supported for set_mirror");
- return -EINVAL;
- }
-
- ov->mirror = enable;
-
- return 0;
-}
-
-/* Returns number of bits per pixel (regardless of where they are located;
- * planar or not), or zero for unsupported format.
- */
-static inline int
-get_depth(int palette)
-{
- switch (palette) {
- case VIDEO_PALETTE_GREY: return 8;
- case VIDEO_PALETTE_YUV420: return 12;
- case VIDEO_PALETTE_YUV420P: return 12; /* Planar */
- default: return 0; /* Invalid format */
- }
-}
-
-/* Bytes per frame. Used by read(). Return of 0 indicates error */
-static inline long int
-get_frame_length(struct ov511_frame *frame)
-{
- if (!frame)
- return 0;
- else
- return ((frame->width * frame->height
- * get_depth(frame->format)) >> 3);
-}
-
-static int
-mode_init_ov_sensor_regs(struct usb_ov511 *ov, int width, int height,
- int mode, int sub_flag, int qvga)
-{
- int clock;
-
- /******** Mode (VGA/QVGA) and sensor specific regs ********/
-
- switch (ov->sensor) {
- case SEN_OV7610:
- i2c_w(ov, 0x14, qvga?0x24:0x04);
-// FIXME: Does this improve the image quality or frame rate?
-#if 0
- i2c_w_mask(ov, 0x28, qvga?0x00:0x20, 0x20);
- i2c_w(ov, 0x24, 0x10);
- i2c_w(ov, 0x25, qvga?0x40:0x8a);
- i2c_w(ov, 0x2f, qvga?0x30:0xb0);
- i2c_w(ov, 0x35, qvga?0x1c:0x9c);
-#endif
- break;
- case SEN_OV7620:
-// i2c_w(ov, 0x2b, 0x00);
- i2c_w(ov, 0x14, qvga?0xa4:0x84);
- i2c_w_mask(ov, 0x28, qvga?0x00:0x20, 0x20);
- i2c_w(ov, 0x24, qvga?0x20:0x3a);
- i2c_w(ov, 0x25, qvga?0x30:0x60);
- i2c_w_mask(ov, 0x2d, qvga?0x40:0x00, 0x40);
- i2c_w_mask(ov, 0x67, qvga?0xf0:0x90, 0xf0);
- i2c_w_mask(ov, 0x74, qvga?0x20:0x00, 0x20);
- break;
- case SEN_OV76BE:
-// i2c_w(ov, 0x2b, 0x00);
- i2c_w(ov, 0x14, qvga?0xa4:0x84);
-// FIXME: Enable this once 7620AE uses 7620 initial settings
-#if 0
- i2c_w_mask(ov, 0x28, qvga?0x00:0x20, 0x20);
- i2c_w(ov, 0x24, qvga?0x20:0x3a);
- i2c_w(ov, 0x25, qvga?0x30:0x60);
- i2c_w_mask(ov, 0x2d, qvga?0x40:0x00, 0x40);
- i2c_w_mask(ov, 0x67, qvga?0xb0:0x90, 0xf0);
- i2c_w_mask(ov, 0x74, qvga?0x20:0x00, 0x20);
-#endif
- break;
- case SEN_OV6620:
- i2c_w(ov, 0x14, qvga?0x24:0x04);
- break;
- case SEN_OV6630:
- i2c_w(ov, 0x14, qvga?0xa0:0x80);
- break;
- default:
- err("Invalid sensor");
- return -EINVAL;
- }
-
- /******** Palette-specific regs ********/
-
- if (mode == VIDEO_PALETTE_GREY) {
- if (ov->sensor == SEN_OV7610 || ov->sensor == SEN_OV76BE) {
- /* these aren't valid on the OV6620/OV7620/6630? */
- i2c_w_mask(ov, 0x0e, 0x40, 0x40);
- }
-
- if (ov->sensor == SEN_OV6630 && ov->bridge == BRG_OV518
- && ov518_color) {
- i2c_w_mask(ov, 0x12, 0x00, 0x10);
- i2c_w_mask(ov, 0x13, 0x00, 0x20);
- } else {
- i2c_w_mask(ov, 0x13, 0x20, 0x20);
- }
- } else {
- if (ov->sensor == SEN_OV7610 || ov->sensor == SEN_OV76BE) {
- /* not valid on the OV6620/OV7620/6630? */
- i2c_w_mask(ov, 0x0e, 0x00, 0x40);
- }
-
- /* The OV518 needs special treatment. Although both the OV518
- * and the OV6630 support a 16-bit video bus, only the 8 bit Y
- * bus is actually used. The UV bus is tied to ground.
- * Therefore, the OV6630 needs to be in 8-bit multiplexed
- * output mode */
-
- if (ov->sensor == SEN_OV6630 && ov->bridge == BRG_OV518
- && ov518_color) {
- i2c_w_mask(ov, 0x12, 0x10, 0x10);
- i2c_w_mask(ov, 0x13, 0x20, 0x20);
- } else {
- i2c_w_mask(ov, 0x13, 0x00, 0x20);
- }
- }
-
- /******** Clock programming ********/
-
- /* The OV6620 needs special handling. This prevents the
- * severe banding that normally occurs */
- if (ov->sensor == SEN_OV6620 || ov->sensor == SEN_OV6630)
- {
- /* Clock down */
-
- i2c_w(ov, 0x2a, 0x04);
-
- if (ov->compress) {
-// clock = 0; /* This ensures the highest frame rate */
- clock = 3;
- } else if (clockdiv == -1) { /* If user didn't override it */
- clock = 3; /* Gives better exposure time */
- } else {
- clock = clockdiv;
- }
-
- PDEBUG(4, "Setting clock divisor to %d", clock);
-
- i2c_w(ov, 0x11, clock);
-
- i2c_w(ov, 0x2a, 0x84);
- /* This next setting is critical. It seems to improve
- * the gain or the contrast. The "reserved" bits seem
- * to have some effect in this case. */
- i2c_w(ov, 0x2d, 0x85);
- }
- else
- {
- if (ov->compress) {
- clock = 1; /* This ensures the highest frame rate */
- } else if (clockdiv == -1) { /* If user didn't override it */
- /* Calculate and set the clock divisor */
- clock = ((sub_flag ? ov->subw * ov->subh
- : width * height)
- * (mode == VIDEO_PALETTE_GREY ? 2 : 3) / 2)
- / 66000;
- } else {
- clock = clockdiv;
- }
-
- PDEBUG(4, "Setting clock divisor to %d", clock);
-
- i2c_w(ov, 0x11, clock);
- }
-
- /******** Special Features ********/
-
- if (framedrop >= 0)
- i2c_w(ov, 0x16, framedrop);
-
- /* Test Pattern */
- i2c_w_mask(ov, 0x12, (testpat?0x02:0x00), 0x02);
-
- /* Enable auto white balance */
- i2c_w_mask(ov, 0x12, 0x04, 0x04);
-
- // This will go away as soon as ov51x_mode_init_sensor_regs()
- // is fully tested.
- /* 7620/6620/6630? don't have register 0x35, so play it safe */
- if (ov->sensor == SEN_OV7610 || ov->sensor == SEN_OV76BE) {
- if (width == 640 && height == 480)
- i2c_w(ov, 0x35, 0x9e);
- else
- i2c_w(ov, 0x35, 0x1e);
- }
-
- return 0;
-}
-
-static int
-set_ov_sensor_window(struct usb_ov511 *ov, int width, int height, int mode,
- int sub_flag)
-{
- int ret;
- int hwsbase, hwebase, vwsbase, vwebase, hwsize, vwsize;
- int hoffset, voffset, hwscale = 0, vwscale = 0;
-
- /* The different sensor ICs handle setting up of window differently.
- * IF YOU SET IT WRONG, YOU WILL GET ALL ZERO ISOC DATA FROM OV51x!!! */
- switch (ov->sensor) {
- case SEN_OV7610:
- case SEN_OV76BE:
- hwsbase = 0x38;
- hwebase = 0x3a;
- vwsbase = vwebase = 0x05;
- break;
- case SEN_OV6620:
- case SEN_OV6630:
- hwsbase = 0x38;
- hwebase = 0x3a;
- vwsbase = 0x05;
- vwebase = 0x06;
- break;
- case SEN_OV7620:
- hwsbase = 0x2f; /* From 7620.SET (spec is wrong) */
- hwebase = 0x2f;
- vwsbase = vwebase = 0x05;
- break;
- default:
- err("Invalid sensor");
- return -EINVAL;
- }
-
- if (ov->sensor == SEN_OV6620 || ov->sensor == SEN_OV6630) {
- /* Note: OV518(+) does downsample on its own) */
- if ((width > 176 && height > 144)
- || ov->bclass == BCL_OV518) { /* CIF */
- ret = mode_init_ov_sensor_regs(ov, width, height,
- mode, sub_flag, 0);
- if (ret < 0)
- return ret;
- hwscale = 1;
- vwscale = 1; /* The datasheet says 0; it's wrong */
- hwsize = 352;
- vwsize = 288;
- } else if (width > 176 || height > 144) {
- err("Illegal dimensions");
- return -EINVAL;
- } else { /* QCIF */
- ret = mode_init_ov_sensor_regs(ov, width, height,
- mode, sub_flag, 1);
- if (ret < 0)
- return ret;
- hwsize = 176;
- vwsize = 144;
- }
- } else {
- if (width > 320 && height > 240) { /* VGA */
- ret = mode_init_ov_sensor_regs(ov, width, height,
- mode, sub_flag, 0);
- if (ret < 0)
- return ret;
- hwscale = 2;
- vwscale = 1;
- hwsize = 640;
- vwsize = 480;
- } else if (width > 320 || height > 240) {
- err("Illegal dimensions");
- return -EINVAL;
- } else { /* QVGA */
- ret = mode_init_ov_sensor_regs(ov, width, height,
- mode, sub_flag, 1);
- if (ret < 0)
- return ret;
- hwscale = 1;
- hwsize = 320;
- vwsize = 240;
- }
- }
-
- /* Center the window */
- hoffset = ((hwsize - width) / 2) >> hwscale;
- voffset = ((vwsize - height) / 2) >> vwscale;
-
- /* FIXME! - This needs to be changed to support 160x120 and 6620!!! */
- if (sub_flag) {
- i2c_w(ov, 0x17, hwsbase+(ov->subx>>hwscale));
- i2c_w(ov, 0x18, hwebase+((ov->subx+ov->subw)>>hwscale));
- i2c_w(ov, 0x19, vwsbase+(ov->suby>>vwscale));
- i2c_w(ov, 0x1a, vwebase+((ov->suby+ov->subh)>>vwscale));
- } else {
- i2c_w(ov, 0x17, hwsbase + hoffset);
- i2c_w(ov, 0x18, hwebase + hoffset + (hwsize>>hwscale));
- i2c_w(ov, 0x19, vwsbase + voffset);
- i2c_w(ov, 0x1a, vwebase + voffset + (vwsize>>vwscale));
- }
-
-#ifdef OV511_DEBUG
- if (dump_sensor)
- dump_i2c_regs(ov);
-#endif
-
- return 0;
-}
-
-/* Set up the OV511/OV511+ with the given image parameters.
- *
- * Do not put any sensor-specific code in here (including I2C I/O functions)
- */
-static int
-ov511_mode_init_regs(struct usb_ov511 *ov,
- int width, int height, int mode, int sub_flag)
-{
- int hsegs, vsegs;
-
- if (sub_flag) {
- width = ov->subw;
- height = ov->subh;
- }
-
- PDEBUG(3, "width:%d, height:%d, mode:%d, sub:%d",
- width, height, mode, sub_flag);
-
- // FIXME: This should be moved to a 7111a-specific function once
- // subcapture is dealt with properly
- if (ov->sensor == SEN_SAA7111A) {
- if (width == 320 && height == 240) {
- /* No need to do anything special */
- } else if (width == 640 && height == 480) {
- /* Set the OV511 up as 320x480, but keep the
- * V4L resolution as 640x480 */
- width = 320;
- } else {
- err("SAA7111A only allows 320x240 or 640x480");
- return -EINVAL;
- }
- }
-
- /* Make sure width and height are a multiple of 8 */
- if (width % 8 || height % 8) {
- err("Invalid size (%d, %d) (mode = %d)", width, height, mode);
- return -EINVAL;
- }
-
- if (width < ov->minwidth || height < ov->minheight) {
- err("Requested dimensions are too small");
- return -EINVAL;
- }
-
- if (ov51x_stop(ov) < 0)
- return -EIO;
-
- if (mode == VIDEO_PALETTE_GREY) {
- reg_w(ov, R511_CAM_UV_EN, 0x00);
- reg_w(ov, R511_SNAP_UV_EN, 0x00);
- reg_w(ov, R511_SNAP_OPTS, 0x01);
- } else {
- reg_w(ov, R511_CAM_UV_EN, 0x01);
- reg_w(ov, R511_SNAP_UV_EN, 0x01);
- reg_w(ov, R511_SNAP_OPTS, 0x03);
- }
-
- /* Here I'm assuming that snapshot size == image size.
- * I hope that's always true. --claudio
- */
- hsegs = (width >> 3) - 1;
- vsegs = (height >> 3) - 1;
-
- reg_w(ov, R511_CAM_PXCNT, hsegs);
- reg_w(ov, R511_CAM_LNCNT, vsegs);
- reg_w(ov, R511_CAM_PXDIV, 0x00);
- reg_w(ov, R511_CAM_LNDIV, 0x00);
-
- /* YUV420, low pass filter on */
- reg_w(ov, R511_CAM_OPTS, 0x03);
-
- /* Snapshot additions */
- reg_w(ov, R511_SNAP_PXCNT, hsegs);
- reg_w(ov, R511_SNAP_LNCNT, vsegs);
- reg_w(ov, R511_SNAP_PXDIV, 0x00);
- reg_w(ov, R511_SNAP_LNDIV, 0x00);
-
- if (ov->compress) {
- /* Enable Y and UV quantization and compression */
- reg_w(ov, R511_COMP_EN, 0x07);
- reg_w(ov, R511_COMP_LUT_EN, 0x03);
- ov51x_reset(ov, OV511_RESET_OMNICE);
- }
-
- if (ov51x_restart(ov) < 0)
- return -EIO;
-
- return 0;
-}
-
-/* Sets up the OV518/OV518+ with the given image parameters
- *
- * OV518 needs a completely different approach, until we can figure out what
- * the individual registers do. Also, only 15 FPS is supported now.
- *
- * Do not put any sensor-specific code in here (including I2C I/O functions)
- */
-static int
-ov518_mode_init_regs(struct usb_ov511 *ov,
- int width, int height, int mode, int sub_flag)
-{
- int hsegs, vsegs, hi_res;
-
- if (sub_flag) {
- width = ov->subw;
- height = ov->subh;
- }
-
- PDEBUG(3, "width:%d, height:%d, mode:%d, sub:%d",
- width, height, mode, sub_flag);
-
- if (width % 16 || height % 8) {
- err("Invalid size (%d, %d)", width, height);
- return -EINVAL;
- }
-
- if (width < ov->minwidth || height < ov->minheight) {
- err("Requested dimensions are too small");
- return -EINVAL;
- }
-
- if (width >= 320 && height >= 240) {
- hi_res = 1;
- } else if (width >= 320 || height >= 240) {
- err("Invalid width/height combination (%d, %d)", width, height);
- return -EINVAL;
- } else {
- hi_res = 0;
- }
-
- if (ov51x_stop(ov) < 0)
- return -EIO;
-
- /******** Set the mode ********/
-
- reg_w(ov, 0x2b, 0);
- reg_w(ov, 0x2c, 0);
- reg_w(ov, 0x2d, 0);
- reg_w(ov, 0x2e, 0);
- reg_w(ov, 0x3b, 0);
- reg_w(ov, 0x3c, 0);
- reg_w(ov, 0x3d, 0);
- reg_w(ov, 0x3e, 0);
-
- if (ov->bridge == BRG_OV518 && ov518_color) {
- /* OV518 needs U and V swapped */
- i2c_w_mask(ov, 0x15, 0x00, 0x01);
-
- if (mode == VIDEO_PALETTE_GREY) {
- /* Set 16-bit input format (UV data are ignored) */
- reg_w_mask(ov, 0x20, 0x00, 0x08);
-
- /* Set 8-bit (4:0:0) output format */
- reg_w_mask(ov, 0x28, 0x00, 0xf0);
- reg_w_mask(ov, 0x38, 0x00, 0xf0);
- } else {
- /* Set 8-bit (YVYU) input format */
- reg_w_mask(ov, 0x20, 0x08, 0x08);
-
- /* Set 12-bit (4:2:0) output format */
- reg_w_mask(ov, 0x28, 0x80, 0xf0);
- reg_w_mask(ov, 0x38, 0x80, 0xf0);
- }
- } else {
- reg_w(ov, 0x28, (mode == VIDEO_PALETTE_GREY) ? 0x00:0x80);
- reg_w(ov, 0x38, (mode == VIDEO_PALETTE_GREY) ? 0x00:0x80);
- }
-
- hsegs = width / 16;
- vsegs = height / 4;
-
- reg_w(ov, 0x29, hsegs);
- reg_w(ov, 0x2a, vsegs);
-
- reg_w(ov, 0x39, hsegs);
- reg_w(ov, 0x3a, vsegs);
-
- /* Windows driver does this here; who knows why */
- reg_w(ov, 0x2f, 0x80);
-
- /******** Set the framerate (to 15 FPS) ********/
-
- /* Mode independent, but framerate dependent, regs */
- reg_w(ov, 0x51, 0x02); /* Clock divider; lower==faster */
- reg_w(ov, 0x22, 0x18);
- reg_w(ov, 0x23, 0xff);
-
- if (ov->bridge == BRG_OV518PLUS)
- reg_w(ov, 0x21, 0x19);
- else
- reg_w(ov, 0x71, 0x19); /* Compression-related? */
-
- // FIXME: Sensor-specific
- /* Bit 5 is what matters here. Of course, it is "reserved" */
- i2c_w(ov, 0x54, 0x23);
-
- reg_w(ov, 0x2f, 0x80);
-
- if (ov->bridge == BRG_OV518PLUS) {
- reg_w(ov, 0x24, 0x94);
- reg_w(ov, 0x25, 0x90);
- ov518_reg_w32(ov, 0xc4, 400, 2); /* 190h */
- ov518_reg_w32(ov, 0xc6, 540, 2); /* 21ch */
- ov518_reg_w32(ov, 0xc7, 540, 2); /* 21ch */
- ov518_reg_w32(ov, 0xc8, 108, 2); /* 6ch */
- ov518_reg_w32(ov, 0xca, 131098, 3); /* 2001ah */
- ov518_reg_w32(ov, 0xcb, 532, 2); /* 214h */
- ov518_reg_w32(ov, 0xcc, 2400, 2); /* 960h */
- ov518_reg_w32(ov, 0xcd, 32, 2); /* 20h */
- ov518_reg_w32(ov, 0xce, 608, 2); /* 260h */
- } else {
- reg_w(ov, 0x24, 0x9f);
- reg_w(ov, 0x25, 0x90);
- ov518_reg_w32(ov, 0xc4, 400, 2); /* 190h */
- ov518_reg_w32(ov, 0xc6, 500, 2); /* 1f4h */
- ov518_reg_w32(ov, 0xc7, 500, 2); /* 1f4h */
- ov518_reg_w32(ov, 0xc8, 142, 2); /* 8eh */
- ov518_reg_w32(ov, 0xca, 131098, 3); /* 2001ah */
- ov518_reg_w32(ov, 0xcb, 532, 2); /* 214h */
- ov518_reg_w32(ov, 0xcc, 2000, 2); /* 7d0h */
- ov518_reg_w32(ov, 0xcd, 32, 2); /* 20h */
- ov518_reg_w32(ov, 0xce, 608, 2); /* 260h */
- }
-
- reg_w(ov, 0x2f, 0x80);
-
- if (ov51x_restart(ov) < 0)
- return -EIO;
-
- /* Reset it just for good measure */
- if (ov51x_reset(ov, OV511_RESET_NOREGS) < 0)
- return -EIO;
-
- return 0;
-}
-
-/* This is a wrapper around the OV511, OV518, and sensor specific functions */
-static int
-mode_init_regs(struct usb_ov511 *ov,
- int width, int height, int mode, int sub_flag)
-{
- int rc = 0;
-
- if (!ov || !ov->dev)
- return -EFAULT;
-
- if (ov->bclass == BCL_OV518) {
- rc = ov518_mode_init_regs(ov, width, height, mode, sub_flag);
- } else {
- rc = ov511_mode_init_regs(ov, width, height, mode, sub_flag);
- }
-
- if (FATAL_ERROR(rc))
- return rc;
-
- switch (ov->sensor) {
- case SEN_OV7610:
- case SEN_OV7620:
- case SEN_OV76BE:
- case SEN_OV8600:
- case SEN_OV6620:
- case SEN_OV6630:
- rc = set_ov_sensor_window(ov, width, height, mode, sub_flag);
- break;
- case SEN_KS0127:
- case SEN_KS0127B:
- err("KS0127-series decoders not supported yet");
- rc = -EINVAL;
- break;
- case SEN_SAA7111A:
-// rc = mode_init_saa_sensor_regs(ov, width, height, mode,
-// sub_flag);
-
- PDEBUG(1, "SAA status = 0x%02X", i2c_r(ov, 0x1f));
- break;
- default:
- err("Unknown sensor");
- rc = -EINVAL;
- }
-
- if (FATAL_ERROR(rc))
- return rc;
-
- /* Sensor-independent settings */
- rc = sensor_set_auto_brightness(ov, ov->auto_brt);
- if (FATAL_ERROR(rc))
- return rc;
-
- rc = sensor_set_auto_exposure(ov, ov->auto_exp);
- if (FATAL_ERROR(rc))
- return rc;
-
- rc = sensor_set_banding_filter(ov, bandingfilter);
- if (FATAL_ERROR(rc))
- return rc;
-
- if (ov->lightfreq) {
- rc = sensor_set_light_freq(ov, lightfreq);
- if (FATAL_ERROR(rc))
- return rc;
- }
-
- rc = sensor_set_backlight(ov, ov->backlight);
- if (FATAL_ERROR(rc))
- return rc;
-
- rc = sensor_set_mirror(ov, ov->mirror);
- if (FATAL_ERROR(rc))
- return rc;
-
- return 0;
-}
-
-/* This sets the default image parameters. This is useful for apps that use
- * read() and do not set these.
- */
-static int
-ov51x_set_default_params(struct usb_ov511 *ov)
-{
- int i;
-
- /* Set default sizes in case IOCTL (VIDIOCMCAPTURE) is not used
- * (using read() instead). */
- for (i = 0; i < OV511_NUMFRAMES; i++) {
- ov->frame[i].width = ov->maxwidth;
- ov->frame[i].height = ov->maxheight;
- ov->frame[i].bytes_read = 0;
- if (force_palette)
- ov->frame[i].format = force_palette;
- else
- ov->frame[i].format = VIDEO_PALETTE_YUV420;
-
- ov->frame[i].depth = get_depth(ov->frame[i].format);
- }
-
- PDEBUG(3, "%dx%d, %s", ov->maxwidth, ov->maxheight,
- symbolic(v4l1_plist, ov->frame[0].format));
-
- /* Initialize to max width/height, YUV420 or RGB24 (if supported) */
- if (mode_init_regs(ov, ov->maxwidth, ov->maxheight,
- ov->frame[0].format, 0) < 0)
- return -EINVAL;
-
- return 0;
-}
-
-/**********************************************************************
- *
- * Video decoder stuff
- *
- **********************************************************************/
-
-/* Set analog input port of decoder */
-static int
-decoder_set_input(struct usb_ov511 *ov, int input)
-{
- PDEBUG(4, "port %d", input);
-
- switch (ov->sensor) {
- case SEN_SAA7111A:
- {
- /* Select mode */
- i2c_w_mask(ov, 0x02, input, 0x07);
- /* Bypass chrominance trap for modes 4..7 */
- i2c_w_mask(ov, 0x09, (input > 3) ? 0x80:0x00, 0x80);
- break;
- }
- default:
- return -EINVAL;
- }
-
- return 0;
-}
-
-/* Get ASCII name of video input */
-static int
-decoder_get_input_name(struct usb_ov511 *ov, int input, char *name)
-{
- switch (ov->sensor) {
- case SEN_SAA7111A:
- {
- if (input < 0 || input > 7)
- return -EINVAL;
- else if (input < 4)
- sprintf(name, "CVBS-%d", input);
- else // if (input < 8)
- sprintf(name, "S-Video-%d", input - 4);
- break;
- }
- default:
- sprintf(name, "%s", "Camera");
- }
-
- return 0;
-}
-
-/* Set norm (NTSC, PAL, SECAM, AUTO) */
-static int
-decoder_set_norm(struct usb_ov511 *ov, int norm)
-{
- PDEBUG(4, "%d", norm);
-
- switch (ov->sensor) {
- case SEN_SAA7111A:
- {
- int reg_8, reg_e;
-
- if (norm == VIDEO_MODE_NTSC) {
- reg_8 = 0x40; /* 60 Hz */
- reg_e = 0x00; /* NTSC M / PAL BGHI */
- } else if (norm == VIDEO_MODE_PAL) {
- reg_8 = 0x00; /* 50 Hz */
- reg_e = 0x00; /* NTSC M / PAL BGHI */
- } else if (norm == VIDEO_MODE_AUTO) {
- reg_8 = 0x80; /* Auto field detect */
- reg_e = 0x00; /* NTSC M / PAL BGHI */
- } else if (norm == VIDEO_MODE_SECAM) {
- reg_8 = 0x00; /* 50 Hz */
- reg_e = 0x50; /* SECAM / PAL 4.43 */
- } else {
- return -EINVAL;
- }
-
- i2c_w_mask(ov, 0x08, reg_8, 0xc0);
- i2c_w_mask(ov, 0x0e, reg_e, 0x70);
- break;
- }
- default:
- return -EINVAL;
- }
-
- return 0;
-}
-
-/**********************************************************************
- *
- * Raw data parsing
- *
- **********************************************************************/
-
-/* Copies a 64-byte segment at pIn to an 8x8 block at pOut. The width of the
- * image at pOut is specified by w.
- */
-static inline void
-make_8x8(unsigned char *pIn, unsigned char *pOut, int w)
-{
- unsigned char *pOut1 = pOut;
- int x, y;
-
- for (y = 0; y < 8; y++) {
- pOut1 = pOut;
- for (x = 0; x < 8; x++) {
- *pOut1++ = *pIn++;
- }
- pOut += w;
- }
-}
-
-/*
- * For RAW BW (YUV 4:0:0) images, data show up in 256 byte segments.
- * The segments represent 4 squares of 8x8 pixels as follows:
- *
- * 0 1 ... 7 64 65 ... 71 ... 192 193 ... 199
- * 8 9 ... 15 72 73 ... 79 200 201 ... 207
- * ... ... ...
- * 56 57 ... 63 120 121 ... 127 248 249 ... 255
- *
- */
-static void
-yuv400raw_to_yuv400p(struct ov511_frame *frame,
- unsigned char *pIn0, unsigned char *pOut0)
-{
- int x, y;
- unsigned char *pIn, *pOut, *pOutLine;
-
- /* Copy Y */
- pIn = pIn0;
- pOutLine = pOut0;
- for (y = 0; y < frame->rawheight - 1; y += 8) {
- pOut = pOutLine;
- for (x = 0; x < frame->rawwidth - 1; x += 8) {
- make_8x8(pIn, pOut, frame->rawwidth);
- pIn += 64;
- pOut += 8;
- }
- pOutLine += 8 * frame->rawwidth;
- }
-}
-
-/*
- * For YUV 4:2:0 images, the data show up in 384 byte segments.
- * The first 64 bytes of each segment are U, the next 64 are V. The U and
- * V are arranged as follows:
- *
- * 0 1 ... 7
- * 8 9 ... 15
- * ...
- * 56 57 ... 63
- *
- * U and V are shipped at half resolution (1 U,V sample -> one 2x2 block).
- *
- * The next 256 bytes are full resolution Y data and represent 4 squares
- * of 8x8 pixels as follows:
- *
- * 0 1 ... 7 64 65 ... 71 ... 192 193 ... 199
- * 8 9 ... 15 72 73 ... 79 200 201 ... 207
- * ... ... ...
- * 56 57 ... 63 120 121 ... 127 ... 248 249 ... 255
- *
- * Note that the U and V data in one segment represent a 16 x 16 pixel
- * area, but the Y data represent a 32 x 8 pixel area. If the width is not an
- * even multiple of 32, the extra 8x8 blocks within a 32x8 block belong to the
- * next horizontal stripe.
- *
- * If dumppix module param is set, _parse_data just dumps the incoming segments,
- * verbatim, in order, into the frame. When used with vidcat -f ppm -s 640x480
- * this puts the data on the standard output and can be analyzed with the
- * parseppm.c utility I wrote. That's a much faster way for figuring out how
- * these data are scrambled.
- */
-
-/* Converts from raw, uncompressed segments at pIn0 to a YUV420P frame at pOut0.
- *
- * FIXME: Currently only handles width and height that are multiples of 16
- */
-static void
-yuv420raw_to_yuv420p(struct ov511_frame *frame,
- unsigned char *pIn0, unsigned char *pOut0)
-{
- int k, x, y;
- unsigned char *pIn, *pOut, *pOutLine;
- const unsigned int a = frame->rawwidth * frame->rawheight;
- const unsigned int w = frame->rawwidth / 2;
-
- /* Copy U and V */
- pIn = pIn0;
- pOutLine = pOut0 + a;
- for (y = 0; y < frame->rawheight - 1; y += 16) {
- pOut = pOutLine;
- for (x = 0; x < frame->rawwidth - 1; x += 16) {
- make_8x8(pIn, pOut, w);
- make_8x8(pIn + 64, pOut + a/4, w);
- pIn += 384;
- pOut += 8;
- }
- pOutLine += 8 * w;
- }
-
- /* Copy Y */
- pIn = pIn0 + 128;
- pOutLine = pOut0;
- k = 0;
- for (y = 0; y < frame->rawheight - 1; y += 8) {
- pOut = pOutLine;
- for (x = 0; x < frame->rawwidth - 1; x += 8) {
- make_8x8(pIn, pOut, frame->rawwidth);
- pIn += 64;
- pOut += 8;
- if ((++k) > 3) {
- k = 0;
- pIn += 128;
- }
- }
- pOutLine += 8 * frame->rawwidth;
- }
-}
-
-/**********************************************************************
- *
- * Decompression
- *
- **********************************************************************/
-
-static int
-request_decompressor(struct usb_ov511 *ov)
-{
- if (ov->bclass == BCL_OV511 || ov->bclass == BCL_OV518) {
- err("No decompressor available");
- } else {
- err("Unknown bridge");
- }
-
- return -ENOSYS;
-}
-
-static void
-decompress(struct usb_ov511 *ov, struct ov511_frame *frame,
- unsigned char *pIn0, unsigned char *pOut0)
-{
- if (!ov->decomp_ops)
- if (request_decompressor(ov))
- return;
-
-}
-
-/**********************************************************************
- *
- * Format conversion
- *
- **********************************************************************/
-
-/* Fuses even and odd fields together, and doubles width.
- * INPUT: an odd field followed by an even field at pIn0, in YUV planar format
- * OUTPUT: a normal YUV planar image, with correct aspect ratio
- */
-static void
-deinterlace(struct ov511_frame *frame, int rawformat,
- unsigned char *pIn0, unsigned char *pOut0)
-{
- const int fieldheight = frame->rawheight / 2;
- const int fieldpix = fieldheight * frame->rawwidth;
- const int w = frame->width;
- int x, y;
- unsigned char *pInEven, *pInOdd, *pOut;
-
- PDEBUG(5, "fieldheight=%d", fieldheight);
-
- if (frame->rawheight != frame->height) {
- err("invalid height");
- return;
- }
-
- if ((frame->rawwidth * 2) != frame->width) {
- err("invalid width");
- return;
- }
-
- /* Y */
- pInOdd = pIn0;
- pInEven = pInOdd + fieldpix;
- pOut = pOut0;
- for (y = 0; y < fieldheight; y++) {
- for (x = 0; x < frame->rawwidth; x++) {
- *pOut = *pInEven;
- *(pOut+1) = *pInEven++;
- *(pOut+w) = *pInOdd;
- *(pOut+w+1) = *pInOdd++;
- pOut += 2;
- }
- pOut += w;
- }
-
- if (rawformat == RAWFMT_YUV420) {
- /* U */
- pInOdd = pIn0 + fieldpix * 2;
- pInEven = pInOdd + fieldpix / 4;
- for (y = 0; y < fieldheight / 2; y++) {
- for (x = 0; x < frame->rawwidth / 2; x++) {
- *pOut = *pInEven;
- *(pOut+1) = *pInEven++;
- *(pOut+w/2) = *pInOdd;
- *(pOut+w/2+1) = *pInOdd++;
- pOut += 2;
- }
- pOut += w/2;
- }
- /* V */
- pInOdd = pIn0 + fieldpix * 2 + fieldpix / 2;
- pInEven = pInOdd + fieldpix / 4;
- for (y = 0; y < fieldheight / 2; y++) {
- for (x = 0; x < frame->rawwidth / 2; x++) {
- *pOut = *pInEven;
- *(pOut+1) = *pInEven++;
- *(pOut+w/2) = *pInOdd;
- *(pOut+w/2+1) = *pInOdd++;
- pOut += 2;
- }
- pOut += w/2;
- }
- }
-}
-
-static void
-ov51x_postprocess_grey(struct usb_ov511 *ov, struct ov511_frame *frame)
-{
- /* Deinterlace frame, if necessary */
- if (ov->sensor == SEN_SAA7111A && frame->rawheight >= 480) {
- if (frame->compressed)
- decompress(ov, frame, frame->rawdata,
- frame->tempdata);
- else
- yuv400raw_to_yuv400p(frame, frame->rawdata,
- frame->tempdata);
-
- deinterlace(frame, RAWFMT_YUV400, frame->tempdata,
- frame->data);
- } else {
- if (frame->compressed)
- decompress(ov, frame, frame->rawdata,
- frame->data);
- else
- yuv400raw_to_yuv400p(frame, frame->rawdata,
- frame->data);
- }
-}
-
-/* Process raw YUV420 data into standard YUV420P */
-static void
-ov51x_postprocess_yuv420(struct usb_ov511 *ov, struct ov511_frame *frame)
-{
- /* Deinterlace frame, if necessary */
- if (ov->sensor == SEN_SAA7111A && frame->rawheight >= 480) {
- if (frame->compressed)
- decompress(ov, frame, frame->rawdata, frame->tempdata);
- else
- yuv420raw_to_yuv420p(frame, frame->rawdata,
- frame->tempdata);
-
- deinterlace(frame, RAWFMT_YUV420, frame->tempdata,
- frame->data);
- } else {
- if (frame->compressed)
- decompress(ov, frame, frame->rawdata, frame->data);
- else
- yuv420raw_to_yuv420p(frame, frame->rawdata,
- frame->data);
- }
-}
-
-/* Post-processes the specified frame. This consists of:
- * 1. Decompress frame, if necessary
- * 2. Deinterlace frame and scale to proper size, if necessary
- * 3. Convert from YUV planar to destination format, if necessary
- * 4. Fix the RGB offset, if necessary
- */
-static void
-ov51x_postprocess(struct usb_ov511 *ov, struct ov511_frame *frame)
-{
- if (dumppix) {
- memset(frame->data, 0,
- MAX_DATA_SIZE(ov->maxwidth, ov->maxheight));
- PDEBUG(4, "Dumping %d bytes", frame->bytes_recvd);
- memcpy(frame->data, frame->rawdata, frame->bytes_recvd);
- } else {
- switch (frame->format) {
- case VIDEO_PALETTE_GREY:
- ov51x_postprocess_grey(ov, frame);
- break;
- case VIDEO_PALETTE_YUV420:
- case VIDEO_PALETTE_YUV420P:
- ov51x_postprocess_yuv420(ov, frame);
- break;
- default:
- err("Cannot convert data to %s",
- symbolic(v4l1_plist, frame->format));
- }
- }
-}
-
-/**********************************************************************
- *
- * OV51x data transfer, IRQ handler
- *
- **********************************************************************/
-
-static inline void
-ov511_move_data(struct usb_ov511 *ov, unsigned char *in, int n)
-{
- int num, offset;
- int pnum = in[ov->packet_size - 1]; /* Get packet number */
- int max_raw = MAX_RAW_DATA_SIZE(ov->maxwidth, ov->maxheight);
- struct ov511_frame *frame = &ov->frame[ov->curframe];
- struct timeval *ts;
-
- /* SOF/EOF packets have 1st to 8th bytes zeroed and the 9th
- * byte non-zero. The EOF packet has image width/height in the
- * 10th and 11th bytes. The 9th byte is given as follows:
- *
- * bit 7: EOF
- * 6: compression enabled
- * 5: 422/420/400 modes
- * 4: 422/420/400 modes
- * 3: 1
- * 2: snapshot button on
- * 1: snapshot frame
- * 0: even/odd field
- */
-
- if (printph) {
- dev_info(&ov->dev->dev,
- "ph(%3d): %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x\n",
- pnum, in[0], in[1], in[2], in[3], in[4], in[5], in[6],
- in[7], in[8], in[9], in[10], in[11]);
- }
-
- /* Check for SOF/EOF packet */
- if ((in[0] | in[1] | in[2] | in[3] | in[4] | in[5] | in[6] | in[7]) ||
- (~in[8] & 0x08))
- goto check_middle;
-
- /* Frame end */
- if (in[8] & 0x80) {
- ts = (struct timeval *)(frame->data
- + MAX_FRAME_SIZE(ov->maxwidth, ov->maxheight));
- do_gettimeofday(ts);
-
- /* Get the actual frame size from the EOF header */
- frame->rawwidth = ((int)(in[9]) + 1) * 8;
- frame->rawheight = ((int)(in[10]) + 1) * 8;
-
- PDEBUG(4, "Frame end, frame=%d, pnum=%d, w=%d, h=%d, recvd=%d",
- ov->curframe, pnum, frame->rawwidth, frame->rawheight,
- frame->bytes_recvd);
-
- /* Validate the header data */
- RESTRICT_TO_RANGE(frame->rawwidth, ov->minwidth, ov->maxwidth);
- RESTRICT_TO_RANGE(frame->rawheight, ov->minheight,
- ov->maxheight);
-
- /* Don't allow byte count to exceed buffer size */
- RESTRICT_TO_RANGE(frame->bytes_recvd, 8, max_raw);
-
- if (frame->scanstate == STATE_LINES) {
- int nextf;
-
- frame->grabstate = FRAME_DONE;
- wake_up_interruptible(&frame->wq);
-
- /* If next frame is ready or grabbing,
- * point to it */
- nextf = (ov->curframe + 1) % OV511_NUMFRAMES;
- if (ov->frame[nextf].grabstate == FRAME_READY
- || ov->frame[nextf].grabstate == FRAME_GRABBING) {
- ov->curframe = nextf;
- ov->frame[nextf].scanstate = STATE_SCANNING;
- } else {
- if (frame->grabstate == FRAME_DONE) {
- PDEBUG(4, "** Frame done **");
- } else {
- PDEBUG(4, "Frame not ready? state = %d",
- ov->frame[nextf].grabstate);
- }
-
- ov->curframe = -1;
- }
- } else {
- PDEBUG(5, "Frame done, but not scanning");
- }
- /* Image corruption caused by misplaced frame->segment = 0
- * fixed by carlosf@conectiva.com.br
- */
- } else {
- /* Frame start */
- PDEBUG(4, "Frame start, framenum = %d", ov->curframe);
-
- /* Check to see if it's a snapshot frame */
- /* FIXME?? Should the snapshot reset go here? Performance? */
- if (in[8] & 0x02) {
- frame->snapshot = 1;
- PDEBUG(3, "snapshot detected");
- }
-
- frame->scanstate = STATE_LINES;
- frame->bytes_recvd = 0;
- frame->compressed = in[8] & 0x40;
- }
-
-check_middle:
- /* Are we in a frame? */
- if (frame->scanstate != STATE_LINES) {
- PDEBUG(5, "Not in a frame; packet skipped");
- return;
- }
-
- /* If frame start, skip header */
- if (frame->bytes_recvd == 0)
- offset = 9;
- else
- offset = 0;
-
- num = n - offset - 1;
-
- /* Dump all data exactly as received */
- if (dumppix == 2) {
- frame->bytes_recvd += n - 1;
- if (frame->bytes_recvd <= max_raw)
- memcpy(frame->rawdata + frame->bytes_recvd - (n - 1),
- in, n - 1);
- else
- PDEBUG(3, "Raw data buffer overrun!! (%d)",
- frame->bytes_recvd - max_raw);
- } else if (!frame->compressed && !remove_zeros) {
- frame->bytes_recvd += num;
- if (frame->bytes_recvd <= max_raw)
- memcpy(frame->rawdata + frame->bytes_recvd - num,
- in + offset, num);
- else
- PDEBUG(3, "Raw data buffer overrun!! (%d)",
- frame->bytes_recvd - max_raw);
- } else { /* Remove all-zero FIFO lines (aligned 32-byte blocks) */
- int b, read = 0, allzero, copied = 0;
- if (offset) {
- frame->bytes_recvd += 32 - offset; // Bytes out
- memcpy(frame->rawdata, in + offset, 32 - offset);
- read += 32;
- }
-
- while (read < n - 1) {
- allzero = 1;
- for (b = 0; b < 32; b++) {
- if (in[read + b]) {
- allzero = 0;
- break;
- }
- }
-
- if (allzero) {
- /* Don't copy it */
- } else {
- if (frame->bytes_recvd + copied + 32 <= max_raw)
- {
- memcpy(frame->rawdata
- + frame->bytes_recvd + copied,
- in + read, 32);
- copied += 32;
- } else {
- PDEBUG(3, "Raw data buffer overrun!!");
- }
- }
- read += 32;
- }
-
- frame->bytes_recvd += copied;
- }
-}
-
-static inline void
-ov518_move_data(struct usb_ov511 *ov, unsigned char *in, int n)
-{
- int max_raw = MAX_RAW_DATA_SIZE(ov->maxwidth, ov->maxheight);
- struct ov511_frame *frame = &ov->frame[ov->curframe];
- struct timeval *ts;
-
- /* Don't copy the packet number byte */
- if (ov->packet_numbering)
- --n;
-
- /* A false positive here is likely, until OVT gives me
- * the definitive SOF/EOF format */
- if ((!(in[0] | in[1] | in[2] | in[3] | in[5])) && in[6]) {
- if (printph) {
- dev_info(&ov->dev->dev,
- "ph: %2x %2x %2x %2x %2x %2x %2x %2x\n",
- in[0], in[1], in[2], in[3], in[4], in[5],
- in[6], in[7]);
- }
-
- if (frame->scanstate == STATE_LINES) {
- PDEBUG(4, "Detected frame end/start");
- goto eof;
- } else { //scanstate == STATE_SCANNING
- /* Frame start */
- PDEBUG(4, "Frame start, framenum = %d", ov->curframe);
- goto sof;
- }
- } else {
- goto check_middle;
- }
-
-eof:
- ts = (struct timeval *)(frame->data
- + MAX_FRAME_SIZE(ov->maxwidth, ov->maxheight));
- do_gettimeofday(ts);
-
- PDEBUG(4, "Frame end, curframe = %d, hw=%d, vw=%d, recvd=%d",
- ov->curframe,
- (int)(in[9]), (int)(in[10]), frame->bytes_recvd);
-
- // FIXME: Since we don't know the header formats yet,
- // there is no way to know what the actual image size is
- frame->rawwidth = frame->width;
- frame->rawheight = frame->height;
-
- /* Validate the header data */
- RESTRICT_TO_RANGE(frame->rawwidth, ov->minwidth, ov->maxwidth);
- RESTRICT_TO_RANGE(frame->rawheight, ov->minheight, ov->maxheight);
-
- /* Don't allow byte count to exceed buffer size */
- RESTRICT_TO_RANGE(frame->bytes_recvd, 8, max_raw);
-
- if (frame->scanstate == STATE_LINES) {
- int nextf;
-
- frame->grabstate = FRAME_DONE;
- wake_up_interruptible(&frame->wq);
-
- /* If next frame is ready or grabbing,
- * point to it */
- nextf = (ov->curframe + 1) % OV511_NUMFRAMES;
- if (ov->frame[nextf].grabstate == FRAME_READY
- || ov->frame[nextf].grabstate == FRAME_GRABBING) {
- ov->curframe = nextf;
- ov->frame[nextf].scanstate = STATE_SCANNING;
- frame = &ov->frame[nextf];
- } else {
- if (frame->grabstate == FRAME_DONE) {
- PDEBUG(4, "** Frame done **");
- } else {
- PDEBUG(4, "Frame not ready? state = %d",
- ov->frame[nextf].grabstate);
- }
-
- ov->curframe = -1;
- PDEBUG(4, "SOF dropped (no active frame)");
- return; /* Nowhere to store this frame */
- }
- }
-sof:
- PDEBUG(4, "Starting capture on frame %d", frame->framenum);
-
-// Snapshot not reverse-engineered yet.
-#if 0
- /* Check to see if it's a snapshot frame */
- /* FIXME?? Should the snapshot reset go here? Performance? */
- if (in[8] & 0x02) {
- frame->snapshot = 1;
- PDEBUG(3, "snapshot detected");
- }
-#endif
- frame->scanstate = STATE_LINES;
- frame->bytes_recvd = 0;
- frame->compressed = 1;
-
-check_middle:
- /* Are we in a frame? */
- if (frame->scanstate != STATE_LINES) {
- PDEBUG(4, "scanstate: no SOF yet");
- return;
- }
-
- /* Dump all data exactly as received */
- if (dumppix == 2) {
- frame->bytes_recvd += n;
- if (frame->bytes_recvd <= max_raw)
- memcpy(frame->rawdata + frame->bytes_recvd - n, in, n);
- else
- PDEBUG(3, "Raw data buffer overrun!! (%d)",
- frame->bytes_recvd - max_raw);
- } else {
- /* All incoming data are divided into 8-byte segments. If the
- * segment contains all zero bytes, it must be skipped. These
- * zero-segments allow the OV518 to mainain a constant data rate
- * regardless of the effectiveness of the compression. Segments
- * are aligned relative to the beginning of each isochronous
- * packet. The first segment in each image is a header (the
- * decompressor skips it later).
- */
-
- int b, read = 0, allzero, copied = 0;
-
- while (read < n) {
- allzero = 1;
- for (b = 0; b < 8; b++) {
- if (in[read + b]) {
- allzero = 0;
- break;
- }
- }
-
- if (allzero) {
- /* Don't copy it */
- } else {
- if (frame->bytes_recvd + copied + 8 <= max_raw)
- {
- memcpy(frame->rawdata
- + frame->bytes_recvd + copied,
- in + read, 8);
- copied += 8;
- } else {
- PDEBUG(3, "Raw data buffer overrun!!");
- }
- }
- read += 8;
- }
- frame->bytes_recvd += copied;
- }
-}
-
-static void
-ov51x_isoc_irq(struct urb *urb)
-{
- int i;
- struct usb_ov511 *ov;
- struct ov511_sbuf *sbuf;
-
- if (!urb->context) {
- PDEBUG(4, "no context");
- return;
- }
-
- sbuf = urb->context;
- ov = sbuf->ov;
-
- if (!ov || !ov->dev || !ov->user) {
- PDEBUG(4, "no device, or not open");
- return;
- }
-
- if (!ov->streaming) {
- PDEBUG(4, "hmmm... not streaming, but got interrupt");
- return;
- }
-
- if (urb->status == -ENOENT || urb->status == -ECONNRESET) {
- PDEBUG(4, "URB unlinked");
- return;
- }
-
- if (urb->status != -EINPROGRESS && urb->status != 0) {
- err("ERROR: urb->status=%d: %s", urb->status,
- symbolic(urb_errlist, urb->status));
- }
-
- /* Copy the data received into our frame buffer */
- PDEBUG(5, "sbuf[%d]: Moving %d packets", sbuf->n,
- urb->number_of_packets);
- for (i = 0; i < urb->number_of_packets; i++) {
- /* Warning: Don't call *_move_data() if no frame active! */
- if (ov->curframe >= 0) {
- int n = urb->iso_frame_desc[i].actual_length;
- int st = urb->iso_frame_desc[i].status;
- unsigned char *cdata;
-
- urb->iso_frame_desc[i].actual_length = 0;
- urb->iso_frame_desc[i].status = 0;
-
- cdata = urb->transfer_buffer
- + urb->iso_frame_desc[i].offset;
-
- if (!n) {
- PDEBUG(4, "Zero-length packet");
- continue;
- }
-
- if (st)
- PDEBUG(2, "data error: [%d] len=%d, status=%d",
- i, n, st);
-
- if (ov->bclass == BCL_OV511)
- ov511_move_data(ov, cdata, n);
- else if (ov->bclass == BCL_OV518)
- ov518_move_data(ov, cdata, n);
- else
- err("Unknown bridge device (%d)", ov->bridge);
-
- } else if (waitqueue_active(&ov->wq)) {
- wake_up_interruptible(&ov->wq);
- }
- }
-
- /* Resubmit this URB */
- urb->dev = ov->dev;
- if ((i = usb_submit_urb(urb, GFP_ATOMIC)) != 0)
- err("usb_submit_urb() ret %d", i);
-
- return;
-}
-
-/****************************************************************************
- *
- * Stream initialization and termination
- *
- ***************************************************************************/
-
-static int
-ov51x_init_isoc(struct usb_ov511 *ov)
-{
- struct urb *urb;
- int fx, err, n, i, size;
-
- PDEBUG(3, "*** Initializing capture ***");
-
- ov->curframe = -1;
-
- if (ov->bridge == BRG_OV511) {
- if (cams == 1)
- size = 993;
- else if (cams == 2)
- size = 513;
- else if (cams == 3 || cams == 4)
- size = 257;
- else {
- err("\"cams\" parameter too high!");
- return -1;
- }
- } else if (ov->bridge == BRG_OV511PLUS) {
- if (cams == 1)
- size = 961;
- else if (cams == 2)
- size = 513;
- else if (cams == 3 || cams == 4)
- size = 257;
- else if (cams >= 5 && cams <= 8)
- size = 129;
- else if (cams >= 9 && cams <= 31)
- size = 33;
- else {
- err("\"cams\" parameter too high!");
- return -1;
- }
- } else if (ov->bclass == BCL_OV518) {
- if (cams == 1)
- size = 896;
- else if (cams == 2)
- size = 512;
- else if (cams == 3 || cams == 4)
- size = 256;
- else if (cams >= 5 && cams <= 8)
- size = 128;
- else {
- err("\"cams\" parameter too high!");
- return -1;
- }
- } else {
- err("invalid bridge type");
- return -1;
- }
-
- // FIXME: OV518 is hardcoded to 15 FPS (alternate 5) for now
- if (ov->bclass == BCL_OV518) {
- if (packetsize == -1) {
- ov518_set_packet_size(ov, 640);
- } else {
- dev_info(&ov->dev->dev, "Forcing packet size to %d\n",
- packetsize);
- ov518_set_packet_size(ov, packetsize);
- }
- } else {
- if (packetsize == -1) {
- ov511_set_packet_size(ov, size);
- } else {
- dev_info(&ov->dev->dev, "Forcing packet size to %d\n",
- packetsize);
- ov511_set_packet_size(ov, packetsize);
- }
- }
-
- for (n = 0; n < OV511_NUMSBUF; n++) {
- urb = usb_alloc_urb(FRAMES_PER_DESC, GFP_KERNEL);
- if (!urb) {
- err("init isoc: usb_alloc_urb ret. NULL");
- for (i = 0; i < n; i++)
- usb_free_urb(ov->sbuf[i].urb);
- return -ENOMEM;
- }
- ov->sbuf[n].urb = urb;
- urb->dev = ov->dev;
- urb->context = &ov->sbuf[n];
- urb->pipe = usb_rcvisocpipe(ov->dev, OV511_ENDPOINT_ADDRESS);
- urb->transfer_flags = URB_ISO_ASAP;
- urb->transfer_buffer = ov->sbuf[n].data;
- urb->complete = ov51x_isoc_irq;
- urb->number_of_packets = FRAMES_PER_DESC;
- urb->transfer_buffer_length = ov->packet_size * FRAMES_PER_DESC;
- urb->interval = 1;
- for (fx = 0; fx < FRAMES_PER_DESC; fx++) {
- urb->iso_frame_desc[fx].offset = ov->packet_size * fx;
- urb->iso_frame_desc[fx].length = ov->packet_size;
- }
- }
-
- ov->streaming = 1;
-
- for (n = 0; n < OV511_NUMSBUF; n++) {
- ov->sbuf[n].urb->dev = ov->dev;
- err = usb_submit_urb(ov->sbuf[n].urb, GFP_KERNEL);
- if (err) {
- err("init isoc: usb_submit_urb(%d) ret %d", n, err);
- return err;
- }
- }
-
- return 0;
-}
-
-static void
-ov51x_unlink_isoc(struct usb_ov511 *ov)
-{
- int n;
-
- /* Unschedule all of the iso td's */
- for (n = OV511_NUMSBUF - 1; n >= 0; n--) {
- if (ov->sbuf[n].urb) {
- usb_kill_urb(ov->sbuf[n].urb);
- usb_free_urb(ov->sbuf[n].urb);
- ov->sbuf[n].urb = NULL;
- }
- }
-}
-
-static void
-ov51x_stop_isoc(struct usb_ov511 *ov)
-{
- if (!ov->streaming || !ov->dev)
- return;
-
- PDEBUG(3, "*** Stopping capture ***");
-
- if (ov->bclass == BCL_OV518)
- ov518_set_packet_size(ov, 0);
- else
- ov511_set_packet_size(ov, 0);
-
- ov->streaming = 0;
-
- ov51x_unlink_isoc(ov);
-}
-
-static int
-ov51x_new_frame(struct usb_ov511 *ov, int framenum)
-{
- struct ov511_frame *frame;
- int newnum;
-
- PDEBUG(4, "ov->curframe = %d, framenum = %d", ov->curframe, framenum);
-
- if (!ov->dev)
- return -1;
-
- /* If we're not grabbing a frame right now and the other frame is */
- /* ready to be grabbed into, then use it instead */
- if (ov->curframe == -1) {
- newnum = (framenum - 1 + OV511_NUMFRAMES) % OV511_NUMFRAMES;
- if (ov->frame[newnum].grabstate == FRAME_READY)
- framenum = newnum;
- } else
- return 0;
-
- frame = &ov->frame[framenum];
-
- PDEBUG(4, "framenum = %d, width = %d, height = %d", framenum,
- frame->width, frame->height);
-
- frame->grabstate = FRAME_GRABBING;
- frame->scanstate = STATE_SCANNING;
- frame->snapshot = 0;
-
- ov->curframe = framenum;
-
- /* Make sure it's not too big */
- if (frame->width > ov->maxwidth)
- frame->width = ov->maxwidth;
-
- frame->width &= ~7L; /* Multiple of 8 */
-
- if (frame->height > ov->maxheight)
- frame->height = ov->maxheight;
-
- frame->height &= ~3L; /* Multiple of 4 */
-
- return 0;
-}
-
-/****************************************************************************
- *
- * Buffer management
- *
- ***************************************************************************/
-
-/*
- * - You must acquire buf_lock before entering this function.
- * - Because this code will free any non-null pointer, you must be sure to null
- * them if you explicitly free them somewhere else!
- */
-static void
-ov51x_do_dealloc(struct usb_ov511 *ov)
-{
- int i;
- PDEBUG(4, "entered");
-
- if (ov->fbuf) {
- rvfree(ov->fbuf, OV511_NUMFRAMES
- * MAX_DATA_SIZE(ov->maxwidth, ov->maxheight));
- ov->fbuf = NULL;
- }
-
- vfree(ov->rawfbuf);
- ov->rawfbuf = NULL;
-
- vfree(ov->tempfbuf);
- ov->tempfbuf = NULL;
-
- for (i = 0; i < OV511_NUMSBUF; i++) {
- kfree(ov->sbuf[i].data);
- ov->sbuf[i].data = NULL;
- }
-
- for (i = 0; i < OV511_NUMFRAMES; i++) {
- ov->frame[i].data = NULL;
- ov->frame[i].rawdata = NULL;
- ov->frame[i].tempdata = NULL;
- if (ov->frame[i].compbuf) {
- free_page((unsigned long) ov->frame[i].compbuf);
- ov->frame[i].compbuf = NULL;
- }
- }
-
- PDEBUG(4, "buffer memory deallocated");
- ov->buf_state = BUF_NOT_ALLOCATED;
- PDEBUG(4, "leaving");
-}
-
-static int
-ov51x_alloc(struct usb_ov511 *ov)
-{
- int i;
- const int w = ov->maxwidth;
- const int h = ov->maxheight;
- const int data_bufsize = OV511_NUMFRAMES * MAX_DATA_SIZE(w, h);
- const int raw_bufsize = OV511_NUMFRAMES * MAX_RAW_DATA_SIZE(w, h);
-
- PDEBUG(4, "entered");
- mutex_lock(&ov->buf_lock);
-
- if (ov->buf_state == BUF_ALLOCATED)
- goto out;
-
- ov->fbuf = rvmalloc(data_bufsize);
- if (!ov->fbuf)
- goto error;
-
- ov->rawfbuf = vmalloc(raw_bufsize);
- if (!ov->rawfbuf)
- goto error;
-
- memset(ov->rawfbuf, 0, raw_bufsize);
-
- ov->tempfbuf = vmalloc(raw_bufsize);
- if (!ov->tempfbuf)
- goto error;
-
- memset(ov->tempfbuf, 0, raw_bufsize);
-
- for (i = 0; i < OV511_NUMSBUF; i++) {
- ov->sbuf[i].data = kmalloc(FRAMES_PER_DESC *
- MAX_FRAME_SIZE_PER_DESC, GFP_KERNEL);
- if (!ov->sbuf[i].data)
- goto error;
-
- PDEBUG(4, "sbuf[%d] @ %p", i, ov->sbuf[i].data);
- }
-
- for (i = 0; i < OV511_NUMFRAMES; i++) {
- ov->frame[i].data = ov->fbuf + i * MAX_DATA_SIZE(w, h);
- ov->frame[i].rawdata = ov->rawfbuf
- + i * MAX_RAW_DATA_SIZE(w, h);
- ov->frame[i].tempdata = ov->tempfbuf
- + i * MAX_RAW_DATA_SIZE(w, h);
-
- ov->frame[i].compbuf =
- (unsigned char *) __get_free_page(GFP_KERNEL);
- if (!ov->frame[i].compbuf)
- goto error;
-
- PDEBUG(4, "frame[%d] @ %p", i, ov->frame[i].data);
- }
-
- ov->buf_state = BUF_ALLOCATED;
-out:
- mutex_unlock(&ov->buf_lock);
- PDEBUG(4, "leaving");
- return 0;
-error:
- ov51x_do_dealloc(ov);
- mutex_unlock(&ov->buf_lock);
- PDEBUG(4, "errored");
- return -ENOMEM;
-}
-
-static void
-ov51x_dealloc(struct usb_ov511 *ov)
-{
- PDEBUG(4, "entered");
- mutex_lock(&ov->buf_lock);
- ov51x_do_dealloc(ov);
- mutex_unlock(&ov->buf_lock);
- PDEBUG(4, "leaving");
-}
-
-/****************************************************************************
- *
- * V4L 1 API
- *
- ***************************************************************************/
-
-static int
-ov51x_v4l1_open(struct file *file)
-{
- struct video_device *vdev = video_devdata(file);
- struct usb_ov511 *ov = video_get_drvdata(vdev);
- int err, i;
-
- PDEBUG(4, "opening");
-
- mutex_lock(&ov->lock);
-
- err = -EBUSY;
- if (ov->user)
- goto out;
-
- ov->sub_flag = 0;
-
- /* In case app doesn't set them... */
- err = ov51x_set_default_params(ov);
- if (err < 0)
- goto out;
-
- /* Make sure frames are reset */
- for (i = 0; i < OV511_NUMFRAMES; i++) {
- ov->frame[i].grabstate = FRAME_UNUSED;
- ov->frame[i].bytes_read = 0;
- }
-
- /* If compression is on, make sure now that a
- * decompressor can be loaded */
- if (ov->compress && !ov->decomp_ops) {
- err = request_decompressor(ov);
- if (err && !dumppix)
- goto out;
- }
-
- err = ov51x_alloc(ov);
- if (err < 0)
- goto out;
-
- err = ov51x_init_isoc(ov);
- if (err) {
- ov51x_dealloc(ov);
- goto out;
- }
-
- ov->user++;
- file->private_data = vdev;
-
- if (ov->led_policy == LED_AUTO)
- ov51x_led_control(ov, 1);
-
-out:
- mutex_unlock(&ov->lock);
- return err;
-}
-
-static int
-ov51x_v4l1_close(struct file *file)
-{
- struct video_device *vdev = file->private_data;
- struct usb_ov511 *ov = video_get_drvdata(vdev);
-
- PDEBUG(4, "ov511_close");
-
- mutex_lock(&ov->lock);
-
- ov->user--;
- ov51x_stop_isoc(ov);
-
- if (ov->led_policy == LED_AUTO)
- ov51x_led_control(ov, 0);
-
- if (ov->dev)
- ov51x_dealloc(ov);
-
- mutex_unlock(&ov->lock);
-
- /* Device unplugged while open. Only a minimum of unregistration is done
- * here; the disconnect callback already did the rest. */
- if (!ov->dev) {
- mutex_lock(&ov->cbuf_lock);
- kfree(ov->cbuf);
- ov->cbuf = NULL;
- mutex_unlock(&ov->cbuf_lock);
-
- ov51x_dealloc(ov);
- kfree(ov);
- ov = NULL;
- }
-
- file->private_data = NULL;
- return 0;
-}
-
-/* Do not call this function directly! */
-static long
-ov51x_v4l1_ioctl_internal(struct file *file, unsigned int cmd, void *arg)
-{
- struct video_device *vdev = file->private_data;
- struct usb_ov511 *ov = video_get_drvdata(vdev);
- PDEBUG(5, "IOCtl: 0x%X", cmd);
-
- if (!ov->dev)
- return -EIO;
-
- switch (cmd) {
- case VIDIOCGCAP:
- {
- struct video_capability *b = arg;
-
- PDEBUG(4, "VIDIOCGCAP");
-
- memset(b, 0, sizeof(struct video_capability));
- sprintf(b->name, "%s USB Camera",
- symbolic(brglist, ov->bridge));
- b->type = VID_TYPE_CAPTURE | VID_TYPE_SUBCAPTURE;
- b->channels = ov->num_inputs;
- b->audios = 0;
- b->maxwidth = ov->maxwidth;
- b->maxheight = ov->maxheight;
- b->minwidth = ov->minwidth;
- b->minheight = ov->minheight;
-
- return 0;
- }
- case VIDIOCGCHAN:
- {
- struct video_channel *v = arg;
-
- PDEBUG(4, "VIDIOCGCHAN");
-
- if ((unsigned)(v->channel) >= ov->num_inputs) {
- err("Invalid channel (%d)", v->channel);
- return -EINVAL;
- }
-
- v->norm = ov->norm;
- v->type = VIDEO_TYPE_CAMERA;
- v->flags = 0;
-// v->flags |= (ov->has_decoder) ? VIDEO_VC_NORM : 0;
- v->tuners = 0;
- decoder_get_input_name(ov, v->channel, v->name);
-
- return 0;
- }
- case VIDIOCSCHAN:
- {
- struct video_channel *v = arg;
- int err;
-
- PDEBUG(4, "VIDIOCSCHAN");
-
- /* Make sure it's not a camera */
- if (!ov->has_decoder) {
- if (v->channel == 0)
- return 0;
- else
- return -EINVAL;
- }
-
- if (v->norm != VIDEO_MODE_PAL &&
- v->norm != VIDEO_MODE_NTSC &&
- v->norm != VIDEO_MODE_SECAM &&
- v->norm != VIDEO_MODE_AUTO) {
- err("Invalid norm (%d)", v->norm);
- return -EINVAL;
- }
-
- if ((unsigned)(v->channel) >= ov->num_inputs) {
- err("Invalid channel (%d)", v->channel);
- return -EINVAL;
- }
-
- err = decoder_set_input(ov, v->channel);
- if (err)
- return err;
-
- err = decoder_set_norm(ov, v->norm);
- if (err)
- return err;
-
- return 0;
- }
- case VIDIOCGPICT:
- {
- struct video_picture *p = arg;
-
- PDEBUG(4, "VIDIOCGPICT");
-
- memset(p, 0, sizeof(struct video_picture));
- if (sensor_get_picture(ov, p))
- return -EIO;
-
- /* Can we get these from frame[0]? -claudio? */
- p->depth = ov->frame[0].depth;
- p->palette = ov->frame[0].format;
-
- return 0;
- }
- case VIDIOCSPICT:
- {
- struct video_picture *p = arg;
- int i, rc;
-
- PDEBUG(4, "VIDIOCSPICT");
-
- if (!get_depth(p->palette))
- return -EINVAL;
-
- if (sensor_set_picture(ov, p))
- return -EIO;
-
- if (force_palette && p->palette != force_palette) {
- dev_info(&ov->dev->dev, "Palette rejected (%s)\n",
- symbolic(v4l1_plist, p->palette));
- return -EINVAL;
- }
-
- // FIXME: Format should be independent of frames
- if (p->palette != ov->frame[0].format) {
- PDEBUG(4, "Detected format change");
-
- rc = ov51x_wait_frames_inactive(ov);
- if (rc)
- return rc;
-
- mode_init_regs(ov, ov->frame[0].width,
- ov->frame[0].height, p->palette, ov->sub_flag);
- }
-
- PDEBUG(4, "Setting depth=%d, palette=%s",
- p->depth, symbolic(v4l1_plist, p->palette));
-
- for (i = 0; i < OV511_NUMFRAMES; i++) {
- ov->frame[i].depth = p->depth;
- ov->frame[i].format = p->palette;
- }
-
- return 0;
- }
- case VIDIOCGCAPTURE:
- {
- int *vf = arg;
-
- PDEBUG(4, "VIDIOCGCAPTURE");
-
- ov->sub_flag = *vf;
- return 0;
- }
- case VIDIOCSCAPTURE:
- {
- struct video_capture *vc = arg;
-
- PDEBUG(4, "VIDIOCSCAPTURE");
-
- if (vc->flags)
- return -EINVAL;
- if (vc->decimation)
- return -EINVAL;
-
- vc->x &= ~3L;
- vc->y &= ~1L;
- vc->y &= ~31L;
-
- if (vc->width == 0)
- vc->width = 32;
-
- vc->height /= 16;
- vc->height *= 16;
- if (vc->height == 0)
- vc->height = 16;
-
- ov->subx = vc->x;
- ov->suby = vc->y;
- ov->subw = vc->width;
- ov->subh = vc->height;
-
- return 0;
- }
- case VIDIOCSWIN:
- {
- struct video_window *vw = arg;
- int i, rc;
-
- PDEBUG(4, "VIDIOCSWIN: %dx%d", vw->width, vw->height);
-
-#if 0
- if (vw->flags)
- return -EINVAL;
- if (vw->clipcount)
- return -EINVAL;
- if (vw->height != ov->maxheight)
- return -EINVAL;
- if (vw->width != ov->maxwidth)
- return -EINVAL;
-#endif
-
- rc = ov51x_wait_frames_inactive(ov);
- if (rc)
- return rc;
-
- rc = mode_init_regs(ov, vw->width, vw->height,
- ov->frame[0].format, ov->sub_flag);
- if (rc < 0)
- return rc;
-
- for (i = 0; i < OV511_NUMFRAMES; i++) {
- ov->frame[i].width = vw->width;
- ov->frame[i].height = vw->height;
- }
-
- return 0;
- }
- case VIDIOCGWIN:
- {
- struct video_window *vw = arg;
-
- memset(vw, 0, sizeof(struct video_window));
- vw->x = 0; /* FIXME */
- vw->y = 0;
- vw->width = ov->frame[0].width;
- vw->height = ov->frame[0].height;
- vw->flags = 30;
-
- PDEBUG(4, "VIDIOCGWIN: %dx%d", vw->width, vw->height);
-
- return 0;
- }
- case VIDIOCGMBUF:
- {
- struct video_mbuf *vm = arg;
- int i;
-
- PDEBUG(4, "VIDIOCGMBUF");
-
- memset(vm, 0, sizeof(struct video_mbuf));
- vm->size = OV511_NUMFRAMES
- * MAX_DATA_SIZE(ov->maxwidth, ov->maxheight);
- vm->frames = OV511_NUMFRAMES;
-
- vm->offsets[0] = 0;
- for (i = 1; i < OV511_NUMFRAMES; i++) {
- vm->offsets[i] = vm->offsets[i-1]
- + MAX_DATA_SIZE(ov->maxwidth, ov->maxheight);
- }
-
- return 0;
- }
- case VIDIOCMCAPTURE:
- {
- struct video_mmap *vm = arg;
- int rc, depth;
- unsigned int f = vm->frame;
-
- PDEBUG(4, "VIDIOCMCAPTURE: frame: %d, %dx%d, %s", f, vm->width,
- vm->height, symbolic(v4l1_plist, vm->format));
-
- depth = get_depth(vm->format);
- if (!depth) {
- PDEBUG(2, "VIDIOCMCAPTURE: invalid format (%s)",
- symbolic(v4l1_plist, vm->format));
- return -EINVAL;
- }
-
- if (f >= OV511_NUMFRAMES) {
- err("VIDIOCMCAPTURE: invalid frame (%d)", f);
- return -EINVAL;
- }
-
- if (vm->width > ov->maxwidth
- || vm->height > ov->maxheight) {
- err("VIDIOCMCAPTURE: requested dimensions too big");
- return -EINVAL;
- }
-
- if (ov->frame[f].grabstate == FRAME_GRABBING) {
- PDEBUG(4, "VIDIOCMCAPTURE: already grabbing");
- return -EBUSY;
- }
-
- if (force_palette && (vm->format != force_palette)) {
- PDEBUG(2, "palette rejected (%s)",
- symbolic(v4l1_plist, vm->format));
- return -EINVAL;
- }
-
- if ((ov->frame[f].width != vm->width) ||
- (ov->frame[f].height != vm->height) ||
- (ov->frame[f].format != vm->format) ||
- (ov->frame[f].sub_flag != ov->sub_flag) ||
- (ov->frame[f].depth != depth)) {
- PDEBUG(4, "VIDIOCMCAPTURE: change in image parameters");
-
- rc = ov51x_wait_frames_inactive(ov);
- if (rc)
- return rc;
-
- rc = mode_init_regs(ov, vm->width, vm->height,
- vm->format, ov->sub_flag);
-#if 0
- if (rc < 0) {
- PDEBUG(1, "Got error while initializing regs ");
- return ret;
- }
-#endif
- ov->frame[f].width = vm->width;
- ov->frame[f].height = vm->height;
- ov->frame[f].format = vm->format;
- ov->frame[f].sub_flag = ov->sub_flag;
- ov->frame[f].depth = depth;
- }
-
- /* Mark it as ready */
- ov->frame[f].grabstate = FRAME_READY;
-
- PDEBUG(4, "VIDIOCMCAPTURE: renewing frame %d", f);
-
- return ov51x_new_frame(ov, f);
- }
- case VIDIOCSYNC:
- {
- unsigned int fnum = *((unsigned int *) arg);
- struct ov511_frame *frame;
- int rc;
-
- if (fnum >= OV511_NUMFRAMES) {
- err("VIDIOCSYNC: invalid frame (%d)", fnum);
- return -EINVAL;
- }
-
- frame = &ov->frame[fnum];
-
- PDEBUG(4, "syncing to frame %d, grabstate = %d", fnum,
- frame->grabstate);
-
- switch (frame->grabstate) {
- case FRAME_UNUSED:
- return -EINVAL;
- case FRAME_READY:
- case FRAME_GRABBING:
- case FRAME_ERROR:
-redo:
- if (!ov->dev)
- return -EIO;
-
- rc = wait_event_interruptible(frame->wq,
- (frame->grabstate == FRAME_DONE)
- || (frame->grabstate == FRAME_ERROR));
-
- if (rc)
- return rc;
-
- if (frame->grabstate == FRAME_ERROR) {
- if ((rc = ov51x_new_frame(ov, fnum)) < 0)
- return rc;
- goto redo;
- }
- /* Fall through */
- case FRAME_DONE:
- if (ov->snap_enabled && !frame->snapshot) {
- if ((rc = ov51x_new_frame(ov, fnum)) < 0)
- return rc;
- goto redo;
- }
-
- frame->grabstate = FRAME_UNUSED;
-
- /* Reset the hardware snapshot button */
- /* FIXME - Is this the best place for this? */
- if ((ov->snap_enabled) && (frame->snapshot)) {
- frame->snapshot = 0;
- ov51x_clear_snapshot(ov);
- }
-
- /* Decompression, format conversion, etc... */
- ov51x_postprocess(ov, frame);
-
- break;
- } /* end switch */
-
- return 0;
- }
- case VIDIOCGFBUF:
- {
- struct video_buffer *vb = arg;
-
- PDEBUG(4, "VIDIOCGFBUF");
-
- memset(vb, 0, sizeof(struct video_buffer));
-
- return 0;
- }
- case VIDIOCGUNIT:
- {
- struct video_unit *vu = arg;
-
- PDEBUG(4, "VIDIOCGUNIT");
-
- memset(vu, 0, sizeof(struct video_unit));
-
- vu->video = ov->vdev->minor;
- vu->vbi = VIDEO_NO_UNIT;
- vu->radio = VIDEO_NO_UNIT;
- vu->audio = VIDEO_NO_UNIT;
- vu->teletext = VIDEO_NO_UNIT;
-
- return 0;
- }
- case OV511IOC_WI2C:
- {
- struct ov511_i2c_struct *w = arg;
-
- return i2c_w_slave(ov, w->slave, w->reg, w->value, w->mask);
- }
- case OV511IOC_RI2C:
- {
- struct ov511_i2c_struct *r = arg;
- int rc;
-
- rc = i2c_r_slave(ov, r->slave, r->reg);
- if (rc < 0)
- return rc;
-
- r->value = rc;
- return 0;
- }
- default:
- PDEBUG(3, "Unsupported IOCtl: 0x%X", cmd);
- return -ENOIOCTLCMD;
- } /* end switch */
-
- return 0;
-}
-
-static long
-ov51x_v4l1_ioctl(struct file *file,
- unsigned int cmd, unsigned long arg)
-{
- struct video_device *vdev = file->private_data;
- struct usb_ov511 *ov = video_get_drvdata(vdev);
- int rc;
-
- if (mutex_lock_interruptible(&ov->lock))
- return -EINTR;
-
- rc = video_usercopy(file, cmd, arg, ov51x_v4l1_ioctl_internal);
-
- mutex_unlock(&ov->lock);
- return rc;
-}
-
-static ssize_t
-ov51x_v4l1_read(struct file *file, char __user *buf, size_t cnt, loff_t *ppos)
-{
- struct video_device *vdev = file->private_data;
- int noblock = file->f_flags&O_NONBLOCK;
- unsigned long count = cnt;
- struct usb_ov511 *ov = video_get_drvdata(vdev);
- int i, rc = 0, frmx = -1;
- struct ov511_frame *frame;
-
- if (mutex_lock_interruptible(&ov->lock))
- return -EINTR;
-
- PDEBUG(4, "%ld bytes, noblock=%d", count, noblock);
-
- if (!vdev || !buf) {
- rc = -EFAULT;
- goto error;
- }
-
- if (!ov->dev) {
- rc = -EIO;
- goto error;
- }
-
-// FIXME: Only supports two frames
- /* See if a frame is completed, then use it. */
- if (ov->frame[0].grabstate >= FRAME_DONE) /* _DONE or _ERROR */
- frmx = 0;
- else if (ov->frame[1].grabstate >= FRAME_DONE)/* _DONE or _ERROR */
- frmx = 1;
-
- /* If nonblocking we return immediately */
- if (noblock && (frmx == -1)) {
- rc = -EAGAIN;
- goto error;
- }
-
- /* If no FRAME_DONE, look for a FRAME_GRABBING state. */
- /* See if a frame is in process (grabbing), then use it. */
- if (frmx == -1) {
- if (ov->frame[0].grabstate == FRAME_GRABBING)
- frmx = 0;
- else if (ov->frame[1].grabstate == FRAME_GRABBING)
- frmx = 1;
- }
-
- /* If no frame is active, start one. */
- if (frmx == -1) {
- if ((rc = ov51x_new_frame(ov, frmx = 0))) {
- err("read: ov51x_new_frame error");
- goto error;
- }
- }
-
- frame = &ov->frame[frmx];
-
-restart:
- if (!ov->dev) {
- rc = -EIO;
- goto error;
- }
-
- /* Wait while we're grabbing the image */
- PDEBUG(4, "Waiting image grabbing");
- rc = wait_event_interruptible(frame->wq,
- (frame->grabstate == FRAME_DONE)
- || (frame->grabstate == FRAME_ERROR));
-
- if (rc)
- goto error;
-
- PDEBUG(4, "Got image, frame->grabstate = %d", frame->grabstate);
- PDEBUG(4, "bytes_recvd = %d", frame->bytes_recvd);
-
- if (frame->grabstate == FRAME_ERROR) {
- frame->bytes_read = 0;
- err("** ick! ** Errored frame %d", ov->curframe);
- if (ov51x_new_frame(ov, frmx)) {
- err("read: ov51x_new_frame error");
- goto error;
- }
- goto restart;
- }
-
-
- /* Repeat until we get a snapshot frame */
- if (ov->snap_enabled)
- PDEBUG(4, "Waiting snapshot frame");
- if (ov->snap_enabled && !frame->snapshot) {
- frame->bytes_read = 0;
- if ((rc = ov51x_new_frame(ov, frmx))) {
- err("read: ov51x_new_frame error");
- goto error;
- }
- goto restart;
- }
-
- /* Clear the snapshot */
- if (ov->snap_enabled && frame->snapshot) {
- frame->snapshot = 0;
- ov51x_clear_snapshot(ov);
- }
-
- /* Decompression, format conversion, etc... */
- ov51x_postprocess(ov, frame);
-
- PDEBUG(4, "frmx=%d, bytes_read=%ld, length=%ld", frmx,
- frame->bytes_read,
- get_frame_length(frame));
-
- /* copy bytes to user space; we allow for partials reads */
-// if ((count + frame->bytes_read)
-// > get_frame_length((struct ov511_frame *)frame))
-// count = frame->scanlength - frame->bytes_read;
-
- /* FIXME - count hardwired to be one frame... */
- count = get_frame_length(frame);
-
- PDEBUG(4, "Copy to user space: %ld bytes", count);
- if ((i = copy_to_user(buf, frame->data + frame->bytes_read, count))) {
- PDEBUG(4, "Copy failed! %d bytes not copied", i);
- rc = -EFAULT;
- goto error;
- }
-
- frame->bytes_read += count;
- PDEBUG(4, "{copy} count used=%ld, new bytes_read=%ld",
- count, frame->bytes_read);
-
- /* If all data have been read... */
- if (frame->bytes_read
- >= get_frame_length(frame)) {
- frame->bytes_read = 0;
-
-// FIXME: Only supports two frames
- /* Mark it as available to be used again. */
- ov->frame[frmx].grabstate = FRAME_UNUSED;
- if ((rc = ov51x_new_frame(ov, !frmx))) {
- err("ov51x_new_frame returned error");
- goto error;
- }
- }
-
- PDEBUG(4, "read finished, returning %ld (sweet)", count);
-
- mutex_unlock(&ov->lock);
- return count;
-
-error:
- mutex_unlock(&ov->lock);
- return rc;
-}
-
-static int
-ov51x_v4l1_mmap(struct file *file, struct vm_area_struct *vma)
-{
- struct video_device *vdev = file->private_data;
- unsigned long start = vma->vm_start;
- unsigned long size = vma->vm_end - vma->vm_start;
- struct usb_ov511 *ov = video_get_drvdata(vdev);
- unsigned long page, pos;
-
- if (ov->dev == NULL)
- return -EIO;
-
- PDEBUG(4, "mmap: %ld (%lX) bytes", size, size);
-
- if (size > (((OV511_NUMFRAMES
- * MAX_DATA_SIZE(ov->maxwidth, ov->maxheight)
- + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1))))
- return -EINVAL;
-
- if (mutex_lock_interruptible(&ov->lock))
- return -EINTR;
-
- pos = (unsigned long)ov->fbuf;
- while (size > 0) {
- page = vmalloc_to_pfn((void *)pos);
- if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED)) {
- mutex_unlock(&ov->lock);
- return -EAGAIN;
- }
- start += PAGE_SIZE;
- pos += PAGE_SIZE;
- if (size > PAGE_SIZE)
- size -= PAGE_SIZE;
- else
- size = 0;
- }
-
- mutex_unlock(&ov->lock);
- return 0;
-}
-
-static const struct v4l2_file_operations ov511_fops = {
- .owner = THIS_MODULE,
- .open = ov51x_v4l1_open,
- .release = ov51x_v4l1_close,
- .read = ov51x_v4l1_read,
- .mmap = ov51x_v4l1_mmap,
- .ioctl = ov51x_v4l1_ioctl,
-};
-
-static struct video_device vdev_template = {
- .name = "OV511 USB Camera",
- .fops = &ov511_fops,
- .release = video_device_release,
-};
-
-/****************************************************************************
- *
- * OV511 and sensor configuration
- *
- ***************************************************************************/
-
-/* This initializes the OV7610, OV7620, or OV76BE sensor. The OV76BE uses
- * the same register settings as the OV7610, since they are very similar.
- */
-static int
-ov7xx0_configure(struct usb_ov511 *ov)
-{
- int i, success;
- int rc;
-
- /* Lawrence Glaister <lg@jfm.bc.ca> reports:
- *
- * Register 0x0f in the 7610 has the following effects:
- *
- * 0x85 (AEC method 1): Best overall, good contrast range
- * 0x45 (AEC method 2): Very overexposed
- * 0xa5 (spec sheet default): Ok, but the black level is
- * shifted resulting in loss of contrast
- * 0x05 (old driver setting): very overexposed, too much
- * contrast
- */
- static struct ov511_regvals aRegvalsNorm7610[] = {
- { OV511_I2C_BUS, 0x10, 0xff },
- { OV511_I2C_BUS, 0x16, 0x06 },
- { OV511_I2C_BUS, 0x28, 0x24 },
- { OV511_I2C_BUS, 0x2b, 0xac },
- { OV511_I2C_BUS, 0x12, 0x00 },
- { OV511_I2C_BUS, 0x38, 0x81 },
- { OV511_I2C_BUS, 0x28, 0x24 }, /* 0c */
- { OV511_I2C_BUS, 0x0f, 0x85 }, /* lg's setting */
- { OV511_I2C_BUS, 0x15, 0x01 },
- { OV511_I2C_BUS, 0x20, 0x1c },
- { OV511_I2C_BUS, 0x23, 0x2a },
- { OV511_I2C_BUS, 0x24, 0x10 },
- { OV511_I2C_BUS, 0x25, 0x8a },
- { OV511_I2C_BUS, 0x26, 0xa2 },
- { OV511_I2C_BUS, 0x27, 0xc2 },
- { OV511_I2C_BUS, 0x2a, 0x04 },
- { OV511_I2C_BUS, 0x2c, 0xfe },
- { OV511_I2C_BUS, 0x2d, 0x93 },
- { OV511_I2C_BUS, 0x30, 0x71 },
- { OV511_I2C_BUS, 0x31, 0x60 },
- { OV511_I2C_BUS, 0x32, 0x26 },
- { OV511_I2C_BUS, 0x33, 0x20 },
- { OV511_I2C_BUS, 0x34, 0x48 },
- { OV511_I2C_BUS, 0x12, 0x24 },
- { OV511_I2C_BUS, 0x11, 0x01 },
- { OV511_I2C_BUS, 0x0c, 0x24 },
- { OV511_I2C_BUS, 0x0d, 0x24 },
- { OV511_DONE_BUS, 0x0, 0x00 },
- };
-
- static struct ov511_regvals aRegvalsNorm7620[] = {
- { OV511_I2C_BUS, 0x00, 0x00 },
- { OV511_I2C_BUS, 0x01, 0x80 },
- { OV511_I2C_BUS, 0x02, 0x80 },
- { OV511_I2C_BUS, 0x03, 0xc0 },
- { OV511_I2C_BUS, 0x06, 0x60 },
- { OV511_I2C_BUS, 0x07, 0x00 },
- { OV511_I2C_BUS, 0x0c, 0x24 },
- { OV511_I2C_BUS, 0x0c, 0x24 },
- { OV511_I2C_BUS, 0x0d, 0x24 },
- { OV511_I2C_BUS, 0x11, 0x01 },
- { OV511_I2C_BUS, 0x12, 0x24 },
- { OV511_I2C_BUS, 0x13, 0x01 },
- { OV511_I2C_BUS, 0x14, 0x84 },
- { OV511_I2C_BUS, 0x15, 0x01 },
- { OV511_I2C_BUS, 0x16, 0x03 },
- { OV511_I2C_BUS, 0x17, 0x2f },
- { OV511_I2C_BUS, 0x18, 0xcf },
- { OV511_I2C_BUS, 0x19, 0x06 },
- { OV511_I2C_BUS, 0x1a, 0xf5 },
- { OV511_I2C_BUS, 0x1b, 0x00 },
- { OV511_I2C_BUS, 0x20, 0x18 },
- { OV511_I2C_BUS, 0x21, 0x80 },
- { OV511_I2C_BUS, 0x22, 0x80 },
- { OV511_I2C_BUS, 0x23, 0x00 },
- { OV511_I2C_BUS, 0x26, 0xa2 },
- { OV511_I2C_BUS, 0x27, 0xea },
- { OV511_I2C_BUS, 0x28, 0x20 },
- { OV511_I2C_BUS, 0x29, 0x00 },
- { OV511_I2C_BUS, 0x2a, 0x10 },
- { OV511_I2C_BUS, 0x2b, 0x00 },
- { OV511_I2C_BUS, 0x2c, 0x88 },
- { OV511_I2C_BUS, 0x2d, 0x91 },
- { OV511_I2C_BUS, 0x2e, 0x80 },
- { OV511_I2C_BUS, 0x2f, 0x44 },
- { OV511_I2C_BUS, 0x60, 0x27 },
- { OV511_I2C_BUS, 0x61, 0x02 },
- { OV511_I2C_BUS, 0x62, 0x5f },
- { OV511_I2C_BUS, 0x63, 0xd5 },
- { OV511_I2C_BUS, 0x64, 0x57 },
- { OV511_I2C_BUS, 0x65, 0x83 },
- { OV511_I2C_BUS, 0x66, 0x55 },
- { OV511_I2C_BUS, 0x67, 0x92 },
- { OV511_I2C_BUS, 0x68, 0xcf },
- { OV511_I2C_BUS, 0x69, 0x76 },
- { OV511_I2C_BUS, 0x6a, 0x22 },
- { OV511_I2C_BUS, 0x6b, 0x00 },
- { OV511_I2C_BUS, 0x6c, 0x02 },
- { OV511_I2C_BUS, 0x6d, 0x44 },
- { OV511_I2C_BUS, 0x6e, 0x80 },
- { OV511_I2C_BUS, 0x6f, 0x1d },
- { OV511_I2C_BUS, 0x70, 0x8b },
- { OV511_I2C_BUS, 0x71, 0x00 },
- { OV511_I2C_BUS, 0x72, 0x14 },
- { OV511_I2C_BUS, 0x73, 0x54 },
- { OV511_I2C_BUS, 0x74, 0x00 },
- { OV511_I2C_BUS, 0x75, 0x8e },
- { OV511_I2C_BUS, 0x76, 0x00 },
- { OV511_I2C_BUS, 0x77, 0xff },
- { OV511_I2C_BUS, 0x78, 0x80 },
- { OV511_I2C_BUS, 0x79, 0x80 },
- { OV511_I2C_BUS, 0x7a, 0x80 },
- { OV511_I2C_BUS, 0x7b, 0xe2 },
- { OV511_I2C_BUS, 0x7c, 0x00 },
- { OV511_DONE_BUS, 0x0, 0x00 },
- };
-
- PDEBUG(4, "starting configuration");
-
- /* This looks redundant, but is necessary for WebCam 3 */
- ov->primary_i2c_slave = OV7xx0_SID;
- if (ov51x_set_slave_ids(ov, OV7xx0_SID) < 0)
- return -1;
-
- if (init_ov_sensor(ov) >= 0) {
- PDEBUG(1, "OV7xx0 sensor initalized (method 1)");
- } else {
- /* Reset the 76xx */
- if (i2c_w(ov, 0x12, 0x80) < 0)
- return -1;
-
- /* Wait for it to initialize */
- msleep(150);
-
- i = 0;
- success = 0;
- while (i <= i2c_detect_tries) {
- if ((i2c_r(ov, OV7610_REG_ID_HIGH) == 0x7F) &&
- (i2c_r(ov, OV7610_REG_ID_LOW) == 0xA2)) {
- success = 1;
- break;
- } else {
- i++;
- }
- }
-
-// Was (i == i2c_detect_tries) previously. This obviously used to always report
-// success. Whether anyone actually depended on that bug is unknown
- if ((i >= i2c_detect_tries) && (success == 0)) {
- err("Failed to read sensor ID. You might not have an");
- err("OV7610/20, or it may be not responding. Report");
- err("this to " EMAIL);
- err("This is only a warning. You can attempt to use");
- err("your camera anyway");
-// Only issue a warning for now
-// return -1;
- } else {
- PDEBUG(1, "OV7xx0 initialized (method 2, %dx)", i+1);
- }
- }
-
- /* Detect sensor (sub)type */
- rc = i2c_r(ov, OV7610_REG_COM_I);
-
- if (rc < 0) {
- err("Error detecting sensor type");
- return -1;
- } else if ((rc & 3) == 3) {
- dev_info(&ov->dev->dev, "Sensor is an OV7610\n");
- ov->sensor = SEN_OV7610;
- } else if ((rc & 3) == 1) {
- /* I don't know what's different about the 76BE yet. */
- if (i2c_r(ov, 0x15) & 1)
- dev_info(&ov->dev->dev, "Sensor is an OV7620AE\n");
- else
- dev_info(&ov->dev->dev, "Sensor is an OV76BE\n");
-
- /* OV511+ will return all zero isoc data unless we
- * configure the sensor as a 7620. Someone needs to
- * find the exact reg. setting that causes this. */
- if (ov->bridge == BRG_OV511PLUS) {
- dev_info(&ov->dev->dev,
- "Enabling 511+/7620AE workaround\n");
- ov->sensor = SEN_OV7620;
- } else {
- ov->sensor = SEN_OV76BE;
- }
- } else if ((rc & 3) == 0) {
- dev_info(&ov->dev->dev, "Sensor is an OV7620\n");
- ov->sensor = SEN_OV7620;
- } else {
- err("Unknown image sensor version: %d", rc & 3);
- return -1;
- }
-
- if (ov->sensor == SEN_OV7620) {
- PDEBUG(4, "Writing 7620 registers");
- if (write_regvals(ov, aRegvalsNorm7620))
- return -1;
- } else {
- PDEBUG(4, "Writing 7610 registers");
- if (write_regvals(ov, aRegvalsNorm7610))
- return -1;
- }
-
- /* Set sensor-specific vars */
- ov->maxwidth = 640;
- ov->maxheight = 480;
- ov->minwidth = 64;
- ov->minheight = 48;
-
- // FIXME: These do not match the actual settings yet
- ov->brightness = 0x80 << 8;
- ov->contrast = 0x80 << 8;
- ov->colour = 0x80 << 8;
- ov->hue = 0x80 << 8;
-
- return 0;
-}
-
-/* This initializes the OV6620, OV6630, OV6630AE, or OV6630AF sensor. */
-static int
-ov6xx0_configure(struct usb_ov511 *ov)
-{
- int rc;
-
- static struct ov511_regvals aRegvalsNorm6x20[] = {
- { OV511_I2C_BUS, 0x12, 0x80 }, /* reset */
- { OV511_I2C_BUS, 0x11, 0x01 },
- { OV511_I2C_BUS, 0x03, 0x60 },
- { OV511_I2C_BUS, 0x05, 0x7f }, /* For when autoadjust is off */
- { OV511_I2C_BUS, 0x07, 0xa8 },
- /* The ratio of 0x0c and 0x0d controls the white point */
- { OV511_I2C_BUS, 0x0c, 0x24 },
- { OV511_I2C_BUS, 0x0d, 0x24 },
- { OV511_I2C_BUS, 0x0f, 0x15 }, /* COMS */
- { OV511_I2C_BUS, 0x10, 0x75 }, /* AEC Exposure time */
- { OV511_I2C_BUS, 0x12, 0x24 }, /* Enable AGC */
- { OV511_I2C_BUS, 0x14, 0x04 },
- /* 0x16: 0x06 helps frame stability with moving objects */
- { OV511_I2C_BUS, 0x16, 0x06 },
-// { OV511_I2C_BUS, 0x20, 0x30 }, /* Aperture correction enable */
- { OV511_I2C_BUS, 0x26, 0xb2 }, /* BLC enable */
- /* 0x28: 0x05 Selects RGB format if RGB on */
- { OV511_I2C_BUS, 0x28, 0x05 },
- { OV511_I2C_BUS, 0x2a, 0x04 }, /* Disable framerate adjust */
-// { OV511_I2C_BUS, 0x2b, 0xac }, /* Framerate; Set 2a[7] first */
- { OV511_I2C_BUS, 0x2d, 0x99 },
- { OV511_I2C_BUS, 0x33, 0xa0 }, /* Color Processing Parameter */
- { OV511_I2C_BUS, 0x34, 0xd2 }, /* Max A/D range */
- { OV511_I2C_BUS, 0x38, 0x8b },
- { OV511_I2C_BUS, 0x39, 0x40 },
-
- { OV511_I2C_BUS, 0x3c, 0x39 }, /* Enable AEC mode changing */
- { OV511_I2C_BUS, 0x3c, 0x3c }, /* Change AEC mode */
- { OV511_I2C_BUS, 0x3c, 0x24 }, /* Disable AEC mode changing */
-
- { OV511_I2C_BUS, 0x3d, 0x80 },
- /* These next two registers (0x4a, 0x4b) are undocumented. They
- * control the color balance */
- { OV511_I2C_BUS, 0x4a, 0x80 },
- { OV511_I2C_BUS, 0x4b, 0x80 },
- { OV511_I2C_BUS, 0x4d, 0xd2 }, /* This reduces noise a bit */
- { OV511_I2C_BUS, 0x4e, 0xc1 },
- { OV511_I2C_BUS, 0x4f, 0x04 },
-// Do 50-53 have any effect?
-// Toggle 0x12[2] off and on here?
- { OV511_DONE_BUS, 0x0, 0x00 }, /* END MARKER */
- };
-
- static struct ov511_regvals aRegvalsNorm6x30[] = {
- /*OK*/ { OV511_I2C_BUS, 0x12, 0x80 }, /* reset */
- { OV511_I2C_BUS, 0x11, 0x00 },
- /*OK*/ { OV511_I2C_BUS, 0x03, 0x60 },
- /*0A?*/ { OV511_I2C_BUS, 0x05, 0x7f }, /* For when autoadjust is off */
- { OV511_I2C_BUS, 0x07, 0xa8 },
- /* The ratio of 0x0c and 0x0d controls the white point */
- /*OK*/ { OV511_I2C_BUS, 0x0c, 0x24 },
- /*OK*/ { OV511_I2C_BUS, 0x0d, 0x24 },
- /*A*/ { OV511_I2C_BUS, 0x0e, 0x20 },
-// /*04?*/ { OV511_I2C_BUS, 0x14, 0x80 },
- { OV511_I2C_BUS, 0x16, 0x03 },
-// /*OK*/ { OV511_I2C_BUS, 0x20, 0x30 }, /* Aperture correction enable */
- // 21 & 22? The suggested values look wrong. Go with default
- /*A*/ { OV511_I2C_BUS, 0x23, 0xc0 },
- /*A*/ { OV511_I2C_BUS, 0x25, 0x9a }, // Check this against default
-// /*OK*/ { OV511_I2C_BUS, 0x26, 0xb2 }, /* BLC enable */
-
- /* 0x28: 0x05 Selects RGB format if RGB on */
-// /*04?*/ { OV511_I2C_BUS, 0x28, 0x05 },
-// /*04?*/ { OV511_I2C_BUS, 0x28, 0x45 }, // DEBUG: Tristate UV bus
-
- /*OK*/ { OV511_I2C_BUS, 0x2a, 0x04 }, /* Disable framerate adjust */
-// /*OK*/ { OV511_I2C_BUS, 0x2b, 0xac }, /* Framerate; Set 2a[7] first */
- { OV511_I2C_BUS, 0x2d, 0x99 },
-// /*A*/ { OV511_I2C_BUS, 0x33, 0x26 }, // Reserved bits on 6620
-// /*d2?*/ { OV511_I2C_BUS, 0x34, 0x03 }, /* Max A/D range */
-// /*8b?*/ { OV511_I2C_BUS, 0x38, 0x83 },
-// /*40?*/ { OV511_I2C_BUS, 0x39, 0xc0 }, // 6630 adds bit 7
-// { OV511_I2C_BUS, 0x3c, 0x39 }, /* Enable AEC mode changing */
-// { OV511_I2C_BUS, 0x3c, 0x3c }, /* Change AEC mode */
-// { OV511_I2C_BUS, 0x3c, 0x24 }, /* Disable AEC mode changing */
- { OV511_I2C_BUS, 0x3d, 0x80 },
-// /*A*/ { OV511_I2C_BUS, 0x3f, 0x0e },
-
- /* These next two registers (0x4a, 0x4b) are undocumented. They
- * control the color balance */
-// /*OK?*/ { OV511_I2C_BUS, 0x4a, 0x80 }, // Check these
-// /*OK?*/ { OV511_I2C_BUS, 0x4b, 0x80 },
- { OV511_I2C_BUS, 0x4d, 0x10 }, /* U = 0.563u, V = 0.714v */
- /*c1?*/ { OV511_I2C_BUS, 0x4e, 0x40 },
-
- /* UV average mode, color killer: strongest */
- { OV511_I2C_BUS, 0x4f, 0x07 },
-
- { OV511_I2C_BUS, 0x54, 0x23 }, /* Max AGC gain: 18dB */
- { OV511_I2C_BUS, 0x57, 0x81 }, /* (default) */
- { OV511_I2C_BUS, 0x59, 0x01 }, /* AGC dark current comp: +1 */
- { OV511_I2C_BUS, 0x5a, 0x2c }, /* (undocumented) */
- { OV511_I2C_BUS, 0x5b, 0x0f }, /* AWB chrominance levels */
-// { OV511_I2C_BUS, 0x5c, 0x10 },
- { OV511_DONE_BUS, 0x0, 0x00 }, /* END MARKER */
- };
-
- PDEBUG(4, "starting sensor configuration");
-
- if (init_ov_sensor(ov) < 0) {
- err("Failed to read sensor ID. You might not have an OV6xx0,");
- err("or it may be not responding. Report this to " EMAIL);
- return -1;
- } else {
- PDEBUG(1, "OV6xx0 sensor detected");
- }
-
- /* Detect sensor (sub)type */
- rc = i2c_r(ov, OV7610_REG_COM_I);
-
- if (rc < 0) {
- err("Error detecting sensor type");
- return -1;
- }
-
- if ((rc & 3) == 0) {
- ov->sensor = SEN_OV6630;
- dev_info(&ov->dev->dev, "Sensor is an OV6630\n");
- } else if ((rc & 3) == 1) {
- ov->sensor = SEN_OV6620;
- dev_info(&ov->dev->dev, "Sensor is an OV6620\n");
- } else if ((rc & 3) == 2) {
- ov->sensor = SEN_OV6630;
- dev_info(&ov->dev->dev, "Sensor is an OV6630AE\n");
- } else if ((rc & 3) == 3) {
- ov->sensor = SEN_OV6630;
- dev_info(&ov->dev->dev, "Sensor is an OV6630AF\n");
- }
-
- /* Set sensor-specific vars */
- ov->maxwidth = 352;
- ov->maxheight = 288;
- ov->minwidth = 64;
- ov->minheight = 48;
-
- // FIXME: These do not match the actual settings yet
- ov->brightness = 0x80 << 8;
- ov->contrast = 0x80 << 8;
- ov->colour = 0x80 << 8;
- ov->hue = 0x80 << 8;
-
- if (ov->sensor == SEN_OV6620) {
- PDEBUG(4, "Writing 6x20 registers");
- if (write_regvals(ov, aRegvalsNorm6x20))
- return -1;
- } else {
- PDEBUG(4, "Writing 6x30 registers");
- if (write_regvals(ov, aRegvalsNorm6x30))
- return -1;
- }
-
- return 0;
-}
-
-/* This initializes the KS0127 and KS0127B video decoders. */
-static int
-ks0127_configure(struct usb_ov511 *ov)
-{
- int rc;
-
-// FIXME: I don't know how to sync or reset it yet
-#if 0
- if (ov51x_init_ks_sensor(ov) < 0) {
- err("Failed to initialize the KS0127");
- return -1;
- } else {
- PDEBUG(1, "KS012x(B) sensor detected");
- }
-#endif
-
- /* Detect decoder subtype */
- rc = i2c_r(ov, 0x00);
- if (rc < 0) {
- err("Error detecting sensor type");
- return -1;
- } else if (rc & 0x08) {
- rc = i2c_r(ov, 0x3d);
- if (rc < 0) {
- err("Error detecting sensor type");
- return -1;
- } else if ((rc & 0x0f) == 0) {
- dev_info(&ov->dev->dev, "Sensor is a KS0127\n");
- ov->sensor = SEN_KS0127;
- } else if ((rc & 0x0f) == 9) {
- dev_info(&ov->dev->dev, "Sensor is a KS0127B Rev. A\n");
- ov->sensor = SEN_KS0127B;
- }
- } else {
- err("Error: Sensor is an unsupported KS0122");
- return -1;
- }
-
- /* Set sensor-specific vars */
- ov->maxwidth = 640;
- ov->maxheight = 480;
- ov->minwidth = 64;
- ov->minheight = 48;
-
- // FIXME: These do not match the actual settings yet
- ov->brightness = 0x80 << 8;
- ov->contrast = 0x80 << 8;
- ov->colour = 0x80 << 8;
- ov->hue = 0x80 << 8;
-
- /* This device is not supported yet. Bail out now... */
- err("This sensor is not supported yet.");
- return -1;
-
- return 0;
-}
-
-/* This initializes the SAA7111A video decoder. */
-static int
-saa7111a_configure(struct usb_ov511 *ov)
-{
- int rc;
-
- /* Since there is no register reset command, all registers must be
- * written, otherwise gives erratic results */
- static struct ov511_regvals aRegvalsNormSAA7111A[] = {
- { OV511_I2C_BUS, 0x06, 0xce },
- { OV511_I2C_BUS, 0x07, 0x00 },
- { OV511_I2C_BUS, 0x10, 0x44 }, /* YUV422, 240/286 lines */
- { OV511_I2C_BUS, 0x0e, 0x01 }, /* NTSC M or PAL BGHI */
- { OV511_I2C_BUS, 0x00, 0x00 },
- { OV511_I2C_BUS, 0x01, 0x00 },
- { OV511_I2C_BUS, 0x03, 0x23 },
- { OV511_I2C_BUS, 0x04, 0x00 },
- { OV511_I2C_BUS, 0x05, 0x00 },
- { OV511_I2C_BUS, 0x08, 0xc8 }, /* Auto field freq */
- { OV511_I2C_BUS, 0x09, 0x01 }, /* Chrom. trap off, APER=0.25 */
- { OV511_I2C_BUS, 0x0a, 0x80 }, /* BRIG=128 */
- { OV511_I2C_BUS, 0x0b, 0x40 }, /* CONT=1.0 */
- { OV511_I2C_BUS, 0x0c, 0x40 }, /* SATN=1.0 */
- { OV511_I2C_BUS, 0x0d, 0x00 }, /* HUE=0 */
- { OV511_I2C_BUS, 0x0f, 0x00 },
- { OV511_I2C_BUS, 0x11, 0x0c },
- { OV511_I2C_BUS, 0x12, 0x00 },
- { OV511_I2C_BUS, 0x13, 0x00 },
- { OV511_I2C_BUS, 0x14, 0x00 },
- { OV511_I2C_BUS, 0x15, 0x00 },
- { OV511_I2C_BUS, 0x16, 0x00 },
- { OV511_I2C_BUS, 0x17, 0x00 },
- { OV511_I2C_BUS, 0x02, 0xc0 }, /* Composite input 0 */
- { OV511_DONE_BUS, 0x0, 0x00 },
- };
-
-// FIXME: I don't know how to sync or reset it yet
-#if 0
- if (ov51x_init_saa_sensor(ov) < 0) {
- err("Failed to initialize the SAA7111A");
- return -1;
- } else {
- PDEBUG(1, "SAA7111A sensor detected");
- }
-#endif
-
- /* 640x480 not supported with PAL */
- if (ov->pal) {
- ov->maxwidth = 320;
- ov->maxheight = 240; /* Even field only */
- } else {
- ov->maxwidth = 640;
- ov->maxheight = 480; /* Even/Odd fields */
- }
-
- ov->minwidth = 320;
- ov->minheight = 240; /* Even field only */
-
- ov->has_decoder = 1;
- ov->num_inputs = 8;
- ov->norm = VIDEO_MODE_AUTO;
- ov->stop_during_set = 0; /* Decoder guarantees stable image */
-
- /* Decoder doesn't change these values, so we use these instead of
- * acutally reading the registers (which doesn't work) */
- ov->brightness = 0x80 << 8;
- ov->contrast = 0x40 << 9;
- ov->colour = 0x40 << 9;
- ov->hue = 32768;
-
- PDEBUG(4, "Writing SAA7111A registers");
- if (write_regvals(ov, aRegvalsNormSAA7111A))
- return -1;
-
- /* Detect version of decoder. This must be done after writing the
- * initial regs or the decoder will lock up. */
- rc = i2c_r(ov, 0x00);
-
- if (rc < 0) {
- err("Error detecting sensor version");
- return -1;
- } else {
- dev_info(&ov->dev->dev,
- "Sensor is an SAA7111A (version 0x%x)\n", rc);
- ov->sensor = SEN_SAA7111A;
- }
-
- // FIXME: Fix this for OV518(+)
- /* Latch to negative edge of clock. Otherwise, we get incorrect
- * colors and jitter in the digital signal. */
- if (ov->bclass == BCL_OV511)
- reg_w(ov, 0x11, 0x00);
- else
- dev_warn(&ov->dev->dev,
- "SAA7111A not yet supported with OV518/OV518+\n");
-
- return 0;
-}
-
-/* This initializes the OV511/OV511+ and the sensor */
-static int
-ov511_configure(struct usb_ov511 *ov)
-{
- static struct ov511_regvals aRegvalsInit511[] = {
- { OV511_REG_BUS, R51x_SYS_RESET, 0x7f },
- { OV511_REG_BUS, R51x_SYS_INIT, 0x01 },
- { OV511_REG_BUS, R51x_SYS_RESET, 0x7f },
- { OV511_REG_BUS, R51x_SYS_INIT, 0x01 },
- { OV511_REG_BUS, R51x_SYS_RESET, 0x3f },
- { OV511_REG_BUS, R51x_SYS_INIT, 0x01 },
- { OV511_REG_BUS, R51x_SYS_RESET, 0x3d },
- { OV511_DONE_BUS, 0x0, 0x00},
- };
-
- static struct ov511_regvals aRegvalsNorm511[] = {
- { OV511_REG_BUS, R511_DRAM_FLOW_CTL, 0x01 },
- { OV511_REG_BUS, R51x_SYS_SNAP, 0x00 },
- { OV511_REG_BUS, R51x_SYS_SNAP, 0x02 },
- { OV511_REG_BUS, R51x_SYS_SNAP, 0x00 },
- { OV511_REG_BUS, R511_FIFO_OPTS, 0x1f },
- { OV511_REG_BUS, R511_COMP_EN, 0x00 },
- { OV511_REG_BUS, R511_COMP_LUT_EN, 0x03 },
- { OV511_DONE_BUS, 0x0, 0x00 },
- };
-
- static struct ov511_regvals aRegvalsNorm511Plus[] = {
- { OV511_REG_BUS, R511_DRAM_FLOW_CTL, 0xff },
- { OV511_REG_BUS, R51x_SYS_SNAP, 0x00 },
- { OV511_REG_BUS, R51x_SYS_SNAP, 0x02 },
- { OV511_REG_BUS, R51x_SYS_SNAP, 0x00 },
- { OV511_REG_BUS, R511_FIFO_OPTS, 0xff },
- { OV511_REG_BUS, R511_COMP_EN, 0x00 },
- { OV511_REG_BUS, R511_COMP_LUT_EN, 0x03 },
- { OV511_DONE_BUS, 0x0, 0x00 },
- };
-
- PDEBUG(4, "");
-
- ov->customid = reg_r(ov, R511_SYS_CUST_ID);
- if (ov->customid < 0) {
- err("Unable to read camera bridge registers");
- goto error;
- }
-
- PDEBUG (1, "CustomID = %d", ov->customid);
- ov->desc = symbolic(camlist, ov->customid);
- dev_info(&ov->dev->dev, "model: %s\n", ov->desc);
-
- if (0 == strcmp(ov->desc, NOT_DEFINED_STR)) {
- err("Camera type (%d) not recognized", ov->customid);
- err("Please notify " EMAIL " of the name,");
- err("manufacturer, model, and this number of your camera.");
- err("Also include the output of the detection process.");
- }
-
- if (ov->customid == 70) /* USB Life TV (PAL/SECAM) */
- ov->pal = 1;
-
- if (write_regvals(ov, aRegvalsInit511))
- goto error;
-
- if (ov->led_policy == LED_OFF || ov->led_policy == LED_AUTO)
- ov51x_led_control(ov, 0);
-
- /* The OV511+ has undocumented bits in the flow control register.
- * Setting it to 0xff fixes the corruption with moving objects. */
- if (ov->bridge == BRG_OV511) {
- if (write_regvals(ov, aRegvalsNorm511))
- goto error;
- } else if (ov->bridge == BRG_OV511PLUS) {
- if (write_regvals(ov, aRegvalsNorm511Plus))
- goto error;
- } else {
- err("Invalid bridge");
- }
-
- if (ov511_init_compression(ov))
- goto error;
-
- ov->packet_numbering = 1;
- ov511_set_packet_size(ov, 0);
-
- ov->snap_enabled = snapshot;
-
- /* Test for 7xx0 */
- PDEBUG(3, "Testing for 0V7xx0");
- ov->primary_i2c_slave = OV7xx0_SID;
- if (ov51x_set_slave_ids(ov, OV7xx0_SID) < 0)
- goto error;
-
- if (i2c_w(ov, 0x12, 0x80) < 0) {
- /* Test for 6xx0 */
- PDEBUG(3, "Testing for 0V6xx0");
- ov->primary_i2c_slave = OV6xx0_SID;
- if (ov51x_set_slave_ids(ov, OV6xx0_SID) < 0)
- goto error;
-
- if (i2c_w(ov, 0x12, 0x80) < 0) {
- /* Test for 8xx0 */
- PDEBUG(3, "Testing for 0V8xx0");
- ov->primary_i2c_slave = OV8xx0_SID;
- if (ov51x_set_slave_ids(ov, OV8xx0_SID) < 0)
- goto error;
-
- if (i2c_w(ov, 0x12, 0x80) < 0) {
- /* Test for SAA7111A */
- PDEBUG(3, "Testing for SAA7111A");
- ov->primary_i2c_slave = SAA7111A_SID;
- if (ov51x_set_slave_ids(ov, SAA7111A_SID) < 0)
- goto error;
-
- if (i2c_w(ov, 0x0d, 0x00) < 0) {
- /* Test for KS0127 */
- PDEBUG(3, "Testing for KS0127");
- ov->primary_i2c_slave = KS0127_SID;
- if (ov51x_set_slave_ids(ov, KS0127_SID) < 0)
- goto error;
-
- if (i2c_w(ov, 0x10, 0x00) < 0) {
- err("Can't determine sensor slave IDs");
- goto error;
- } else {
- if (ks0127_configure(ov) < 0) {
- err("Failed to configure KS0127");
- goto error;
- }
- }
- } else {
- if (saa7111a_configure(ov) < 0) {
- err("Failed to configure SAA7111A");
- goto error;
- }
- }
- } else {
- err("Detected unsupported OV8xx0 sensor");
- goto error;
- }
- } else {
- if (ov6xx0_configure(ov) < 0) {
- err("Failed to configure OV6xx0");
- goto error;
- }
- }
- } else {
- if (ov7xx0_configure(ov) < 0) {
- err("Failed to configure OV7xx0");
- goto error;
- }
- }
-
- return 0;
-
-error:
- err("OV511 Config failed");
-
- return -EBUSY;
-}
-
-/* This initializes the OV518/OV518+ and the sensor */
-static int
-ov518_configure(struct usb_ov511 *ov)
-{
- /* For 518 and 518+ */
- static struct ov511_regvals aRegvalsInit518[] = {
- { OV511_REG_BUS, R51x_SYS_RESET, 0x40 },
- { OV511_REG_BUS, R51x_SYS_INIT, 0xe1 },
- { OV511_REG_BUS, R51x_SYS_RESET, 0x3e },
- { OV511_REG_BUS, R51x_SYS_INIT, 0xe1 },
- { OV511_REG_BUS, R51x_SYS_RESET, 0x00 },
- { OV511_REG_BUS, R51x_SYS_INIT, 0xe1 },
- { OV511_REG_BUS, 0x46, 0x00 },
- { OV511_REG_BUS, 0x5d, 0x03 },
- { OV511_DONE_BUS, 0x0, 0x00},
- };
-
- static struct ov511_regvals aRegvalsNorm518[] = {
- { OV511_REG_BUS, R51x_SYS_SNAP, 0x02 }, /* Reset */
- { OV511_REG_BUS, R51x_SYS_SNAP, 0x01 }, /* Enable */
- { OV511_REG_BUS, 0x31, 0x0f },
- { OV511_REG_BUS, 0x5d, 0x03 },
- { OV511_REG_BUS, 0x24, 0x9f },
- { OV511_REG_BUS, 0x25, 0x90 },
- { OV511_REG_BUS, 0x20, 0x00 },
- { OV511_REG_BUS, 0x51, 0x04 },
- { OV511_REG_BUS, 0x71, 0x19 },
- { OV511_DONE_BUS, 0x0, 0x00 },
- };
-
- static struct ov511_regvals aRegvalsNorm518Plus[] = {
- { OV511_REG_BUS, R51x_SYS_SNAP, 0x02 }, /* Reset */
- { OV511_REG_BUS, R51x_SYS_SNAP, 0x01 }, /* Enable */
- { OV511_REG_BUS, 0x31, 0x0f },
- { OV511_REG_BUS, 0x5d, 0x03 },
- { OV511_REG_BUS, 0x24, 0x9f },
- { OV511_REG_BUS, 0x25, 0x90 },
- { OV511_REG_BUS, 0x20, 0x60 },
- { OV511_REG_BUS, 0x51, 0x02 },
- { OV511_REG_BUS, 0x71, 0x19 },
- { OV511_REG_BUS, 0x40, 0xff },
- { OV511_REG_BUS, 0x41, 0x42 },
- { OV511_REG_BUS, 0x46, 0x00 },
- { OV511_REG_BUS, 0x33, 0x04 },
- { OV511_REG_BUS, 0x21, 0x19 },
- { OV511_REG_BUS, 0x3f, 0x10 },
- { OV511_DONE_BUS, 0x0, 0x00 },
- };
-
- PDEBUG(4, "");
-
- /* First 5 bits of custom ID reg are a revision ID on OV518 */
- dev_info(&ov->dev->dev, "Device revision %d\n",
- 0x1F & reg_r(ov, R511_SYS_CUST_ID));
-
- /* Give it the default description */
- ov->desc = symbolic(camlist, 0);
-
- if (write_regvals(ov, aRegvalsInit518))
- goto error;
-
- /* Set LED GPIO pin to output mode */
- if (reg_w_mask(ov, 0x57, 0x00, 0x02) < 0)
- goto error;
-
- /* LED is off by default with OV518; have to explicitly turn it on */
- if (ov->led_policy == LED_OFF || ov->led_policy == LED_AUTO)
- ov51x_led_control(ov, 0);
- else
- ov51x_led_control(ov, 1);
-
- /* Don't require compression if dumppix is enabled; otherwise it's
- * required. OV518 has no uncompressed mode, to save RAM. */
- if (!dumppix && !ov->compress) {
- ov->compress = 1;
- dev_warn(&ov->dev->dev,
- "Compression required with OV518...enabling\n");
- }
-
- if (ov->bridge == BRG_OV518) {
- if (write_regvals(ov, aRegvalsNorm518))
- goto error;
- } else if (ov->bridge == BRG_OV518PLUS) {
- if (write_regvals(ov, aRegvalsNorm518Plus))
- goto error;
- } else {
- err("Invalid bridge");
- }
-
- if (reg_w(ov, 0x2f, 0x80) < 0)
- goto error;
-
- if (ov518_init_compression(ov))
- goto error;
-
- if (ov->bridge == BRG_OV518)
- {
- struct usb_interface *ifp;
- struct usb_host_interface *alt;
- __u16 mxps = 0;
-
- ifp = usb_ifnum_to_if(ov->dev, 0);
- if (ifp) {
- alt = usb_altnum_to_altsetting(ifp, 7);
- if (alt)
- mxps = le16_to_cpu(alt->endpoint[0].desc.wMaxPacketSize);
- }
-
- /* Some OV518s have packet numbering by default, some don't */
- if (mxps == 897)
- ov->packet_numbering = 1;
- else
- ov->packet_numbering = 0;
- } else {
- /* OV518+ has packet numbering turned on by default */
- ov->packet_numbering = 1;
- }
-
- ov518_set_packet_size(ov, 0);
-
- ov->snap_enabled = snapshot;
-
- /* Test for 76xx */
- ov->primary_i2c_slave = OV7xx0_SID;
- if (ov51x_set_slave_ids(ov, OV7xx0_SID) < 0)
- goto error;
-
- /* The OV518 must be more aggressive about sensor detection since
- * I2C write will never fail if the sensor is not present. We have
- * to try to initialize the sensor to detect its presence */
-
- if (init_ov_sensor(ov) < 0) {
- /* Test for 6xx0 */
- ov->primary_i2c_slave = OV6xx0_SID;
- if (ov51x_set_slave_ids(ov, OV6xx0_SID) < 0)
- goto error;
-
- if (init_ov_sensor(ov) < 0) {
- /* Test for 8xx0 */
- ov->primary_i2c_slave = OV8xx0_SID;
- if (ov51x_set_slave_ids(ov, OV8xx0_SID) < 0)
- goto error;
-
- if (init_ov_sensor(ov) < 0) {
- err("Can't determine sensor slave IDs");
- goto error;
- } else {
- err("Detected unsupported OV8xx0 sensor");
- goto error;
- }
- } else {
- if (ov6xx0_configure(ov) < 0) {
- err("Failed to configure OV6xx0");
- goto error;
- }
- }
- } else {
- if (ov7xx0_configure(ov) < 0) {
- err("Failed to configure OV7xx0");
- goto error;
- }
- }
-
- ov->maxwidth = 352;
- ov->maxheight = 288;
-
- // The OV518 cannot go as low as the sensor can
- ov->minwidth = 160;
- ov->minheight = 120;
-
- return 0;
-
-error:
- err("OV518 Config failed");
-
- return -EBUSY;
-}
-
-/****************************************************************************
- * sysfs
- ***************************************************************************/
-
-static inline struct usb_ov511 *cd_to_ov(struct device *cd)
-{
- struct video_device *vdev = to_video_device(cd);
- return video_get_drvdata(vdev);
-}
-
-static ssize_t show_custom_id(struct device *cd,
- struct device_attribute *attr, char *buf)
-{
- struct usb_ov511 *ov = cd_to_ov(cd);
- return sprintf(buf, "%d\n", ov->customid);
-}
-static DEVICE_ATTR(custom_id, S_IRUGO, show_custom_id, NULL);
-
-static ssize_t show_model(struct device *cd,
- struct device_attribute *attr, char *buf)
-{
- struct usb_ov511 *ov = cd_to_ov(cd);
- return sprintf(buf, "%s\n", ov->desc);
-}
-static DEVICE_ATTR(model, S_IRUGO, show_model, NULL);
-
-static ssize_t show_bridge(struct device *cd,
- struct device_attribute *attr, char *buf)
-{
- struct usb_ov511 *ov = cd_to_ov(cd);
- return sprintf(buf, "%s\n", symbolic(brglist, ov->bridge));
-}
-static DEVICE_ATTR(bridge, S_IRUGO, show_bridge, NULL);
-
-static ssize_t show_sensor(struct device *cd,
- struct device_attribute *attr, char *buf)
-{
- struct usb_ov511 *ov = cd_to_ov(cd);
- return sprintf(buf, "%s\n", symbolic(senlist, ov->sensor));
-}
-static DEVICE_ATTR(sensor, S_IRUGO, show_sensor, NULL);
-
-static ssize_t show_brightness(struct device *cd,
- struct device_attribute *attr, char *buf)
-{
- struct usb_ov511 *ov = cd_to_ov(cd);
- unsigned short x;
-
- if (!ov->dev)
- return -ENODEV;
- sensor_get_brightness(ov, &x);
- return sprintf(buf, "%d\n", x >> 8);
-}
-static DEVICE_ATTR(brightness, S_IRUGO, show_brightness, NULL);
-
-static ssize_t show_saturation(struct device *cd,
- struct device_attribute *attr, char *buf)
-{
- struct usb_ov511 *ov = cd_to_ov(cd);
- unsigned short x;
-
- if (!ov->dev)
- return -ENODEV;
- sensor_get_saturation(ov, &x);
- return sprintf(buf, "%d\n", x >> 8);
-}
-static DEVICE_ATTR(saturation, S_IRUGO, show_saturation, NULL);
-
-static ssize_t show_contrast(struct device *cd,
- struct device_attribute *attr, char *buf)
-{
- struct usb_ov511 *ov = cd_to_ov(cd);
- unsigned short x;
-
- if (!ov->dev)
- return -ENODEV;
- sensor_get_contrast(ov, &x);
- return sprintf(buf, "%d\n", x >> 8);
-}
-static DEVICE_ATTR(contrast, S_IRUGO, show_contrast, NULL);
-
-static ssize_t show_hue(struct device *cd,
- struct device_attribute *attr, char *buf)
-{
- struct usb_ov511 *ov = cd_to_ov(cd);
- unsigned short x;
-
- if (!ov->dev)
- return -ENODEV;
- sensor_get_hue(ov, &x);
- return sprintf(buf, "%d\n", x >> 8);
-}
-static DEVICE_ATTR(hue, S_IRUGO, show_hue, NULL);
-
-static ssize_t show_exposure(struct device *cd,
- struct device_attribute *attr, char *buf)
-{
- struct usb_ov511 *ov = cd_to_ov(cd);
- unsigned char exp = 0;
-
- if (!ov->dev)
- return -ENODEV;
- sensor_get_exposure(ov, &exp);
- return sprintf(buf, "%d\n", exp);
-}
-static DEVICE_ATTR(exposure, S_IRUGO, show_exposure, NULL);
-
-static int ov_create_sysfs(struct video_device *vdev)
-{
- int rc;
-
- rc = device_create_file(&vdev->dev, &dev_attr_custom_id);
- if (rc) goto err;
- rc = device_create_file(&vdev->dev, &dev_attr_model);
- if (rc) goto err_id;
- rc = device_create_file(&vdev->dev, &dev_attr_bridge);
- if (rc) goto err_model;
- rc = device_create_file(&vdev->dev, &dev_attr_sensor);
- if (rc) goto err_bridge;
- rc = device_create_file(&vdev->dev, &dev_attr_brightness);
- if (rc) goto err_sensor;
- rc = device_create_file(&vdev->dev, &dev_attr_saturation);
- if (rc) goto err_bright;
- rc = device_create_file(&vdev->dev, &dev_attr_contrast);
- if (rc) goto err_sat;
- rc = device_create_file(&vdev->dev, &dev_attr_hue);
- if (rc) goto err_contrast;
- rc = device_create_file(&vdev->dev, &dev_attr_exposure);
- if (rc) goto err_hue;
-
- return 0;
-
-err_hue:
- device_remove_file(&vdev->dev, &dev_attr_hue);
-err_contrast:
- device_remove_file(&vdev->dev, &dev_attr_contrast);
-err_sat:
- device_remove_file(&vdev->dev, &dev_attr_saturation);
-err_bright:
- device_remove_file(&vdev->dev, &dev_attr_brightness);
-err_sensor:
- device_remove_file(&vdev->dev, &dev_attr_sensor);
-err_bridge:
- device_remove_file(&vdev->dev, &dev_attr_bridge);
-err_model:
- device_remove_file(&vdev->dev, &dev_attr_model);
-err_id:
- device_remove_file(&vdev->dev, &dev_attr_custom_id);
-err:
- return rc;
-}
-
-/****************************************************************************
- * USB routines
- ***************************************************************************/
-
-static int
-ov51x_probe(struct usb_interface *intf, const struct usb_device_id *id)
-{
- struct usb_device *dev = interface_to_usbdev(intf);
- struct usb_interface_descriptor *idesc;
- struct usb_ov511 *ov;
- int i, rc, nr;
-
- PDEBUG(1, "probing for device...");
-
- /* We don't handle multi-config cameras */
- if (dev->descriptor.bNumConfigurations != 1)
- return -ENODEV;
-
- idesc = &intf->cur_altsetting->desc;
-
- if (idesc->bInterfaceClass != 0xFF)
- return -ENODEV;
- if (idesc->bInterfaceSubClass != 0x00)
- return -ENODEV;
-
- if ((ov = kzalloc(sizeof(*ov), GFP_KERNEL)) == NULL) {
- err("couldn't kmalloc ov struct");
- goto error_out;
- }
-
- ov->dev = dev;
- ov->iface = idesc->bInterfaceNumber;
- ov->led_policy = led;
- ov->compress = compress;
- ov->lightfreq = lightfreq;
- ov->num_inputs = 1; /* Video decoder init functs. change this */
- ov->stop_during_set = !fastset;
- ov->backlight = backlight;
- ov->mirror = mirror;
- ov->auto_brt = autobright;
- ov->auto_gain = autogain;
- ov->auto_exp = autoexp;
-
- switch (le16_to_cpu(dev->descriptor.idProduct)) {
- case PROD_OV511:
- ov->bridge = BRG_OV511;
- ov->bclass = BCL_OV511;
- break;
- case PROD_OV511PLUS:
- ov->bridge = BRG_OV511PLUS;
- ov->bclass = BCL_OV511;
- break;
- case PROD_OV518:
- ov->bridge = BRG_OV518;
- ov->bclass = BCL_OV518;
- break;
- case PROD_OV518PLUS:
- ov->bridge = BRG_OV518PLUS;
- ov->bclass = BCL_OV518;
- break;
- case PROD_ME2CAM:
- if (le16_to_cpu(dev->descriptor.idVendor) != VEND_MATTEL)
- goto error;
- ov->bridge = BRG_OV511PLUS;
- ov->bclass = BCL_OV511;
- break;
- default:
- err("Unknown product ID 0x%04x", le16_to_cpu(dev->descriptor.idProduct));
- goto error;
- }
-
- dev_info(&intf->dev, "USB %s video device found\n",
- symbolic(brglist, ov->bridge));
-
- init_waitqueue_head(&ov->wq);
-
- mutex_init(&ov->lock); /* to 1 == available */
- mutex_init(&ov->buf_lock);
- mutex_init(&ov->i2c_lock);
- mutex_init(&ov->cbuf_lock);
-
- ov->buf_state = BUF_NOT_ALLOCATED;
-
- if (usb_make_path(dev, ov->usb_path, OV511_USB_PATH_LEN) < 0) {
- err("usb_make_path error");
- goto error;
- }
-
- /* Allocate control transfer buffer. */
- /* Must be kmalloc()'ed, for DMA compatibility */
- ov->cbuf = kmalloc(OV511_CBUF_SIZE, GFP_KERNEL);
- if (!ov->cbuf)
- goto error;
-
- if (ov->bclass == BCL_OV518) {
- if (ov518_configure(ov) < 0)
- goto error;
- } else {
- if (ov511_configure(ov) < 0)
- goto error;
- }
-
- for (i = 0; i < OV511_NUMFRAMES; i++) {
- ov->frame[i].framenum = i;
- init_waitqueue_head(&ov->frame[i].wq);
- }
-
- for (i = 0; i < OV511_NUMSBUF; i++) {
- ov->sbuf[i].ov = ov;
- spin_lock_init(&ov->sbuf[i].lock);
- ov->sbuf[i].n = i;
- }
-
- /* Unnecessary? (This is done on open(). Need to make sure variables
- * are properly initialized without this before removing it, though). */
- if (ov51x_set_default_params(ov) < 0)
- goto error;
-
-#ifdef OV511_DEBUG
- if (dump_bridge) {
- if (ov->bclass == BCL_OV511)
- ov511_dump_regs(ov);
- else
- ov518_dump_regs(ov);
- }
-#endif
-
- ov->vdev = video_device_alloc();
- if (!ov->vdev)
- goto error;
-
- memcpy(ov->vdev, &vdev_template, sizeof(*ov->vdev));
- ov->vdev->parent = &intf->dev;
- video_set_drvdata(ov->vdev, ov);
-
- mutex_lock(&ov->lock);
-
- /* Check to see next free device and mark as used */
- nr = find_first_zero_bit(&ov511_devused, OV511_MAX_UNIT_VIDEO);
-
- /* Registers device */
- if (unit_video[nr] != 0)
- rc = video_register_device(ov->vdev, VFL_TYPE_GRABBER,
- unit_video[nr]);
- else
- rc = video_register_device(ov->vdev, VFL_TYPE_GRABBER, -1);
-
- if (rc < 0) {
- err("video_register_device failed");
- mutex_unlock(&ov->lock);
- goto error;
- }
-
- /* Mark device as used */
- ov511_devused |= 1 << nr;
- ov->nr = nr;
-
- dev_info(&intf->dev, "Device at %s registered to %s\n",
- ov->usb_path, video_device_node_name(ov->vdev));
-
- usb_set_intfdata(intf, ov);
- if (ov_create_sysfs(ov->vdev)) {
- err("ov_create_sysfs failed");
- ov511_devused &= ~(1 << nr);
- mutex_unlock(&ov->lock);
- goto error;
- }
-
- mutex_unlock(&ov->lock);
-
- return 0;
-
-error:
- if (ov->vdev) {
- if (!video_is_registered(ov->vdev))
- video_device_release(ov->vdev);
- else
- video_unregister_device(ov->vdev);
- ov->vdev = NULL;
- }
-
- if (ov->cbuf) {
- mutex_lock(&ov->cbuf_lock);
- kfree(ov->cbuf);
- ov->cbuf = NULL;
- mutex_unlock(&ov->cbuf_lock);
- }
-
- kfree(ov);
- ov = NULL;
-
-error_out:
- err("Camera initialization failed");
- return -EIO;
-}
-
-static void
-ov51x_disconnect(struct usb_interface *intf)
-{
- struct usb_ov511 *ov = usb_get_intfdata(intf);
- int n;
-
- PDEBUG(3, "");
-
- mutex_lock(&ov->lock);
- usb_set_intfdata (intf, NULL);
-
- /* Free device number */
- ov511_devused &= ~(1 << ov->nr);
-
- if (ov->vdev)
- video_unregister_device(ov->vdev);
-
- for (n = 0; n < OV511_NUMFRAMES; n++)
- ov->frame[n].grabstate = FRAME_ERROR;
-
- ov->curframe = -1;
-
- /* This will cause the process to request another frame */
- for (n = 0; n < OV511_NUMFRAMES; n++)
- wake_up_interruptible(&ov->frame[n].wq);
-
- wake_up_interruptible(&ov->wq);
-
- ov->streaming = 0;
- ov51x_unlink_isoc(ov);
- mutex_unlock(&ov->lock);
-
- ov->dev = NULL;
-
- /* Free the memory */
- if (!ov->user) {
- mutex_lock(&ov->cbuf_lock);
- kfree(ov->cbuf);
- ov->cbuf = NULL;
- mutex_unlock(&ov->cbuf_lock);
-
- ov51x_dealloc(ov);
- kfree(ov);
- ov = NULL;
- }
-
- PDEBUG(3, "Disconnect complete");
-}
-
-static struct usb_driver ov511_driver = {
- .name = "ov511",
- .id_table = device_table,
- .probe = ov51x_probe,
- .disconnect = ov51x_disconnect
-};
-
-/****************************************************************************
- *
- * Module routines
- *
- ***************************************************************************/
-
-static int __init
-usb_ov511_init(void)
-{
- int retval;
-
- retval = usb_register(&ov511_driver);
- if (retval)
- goto out;
-
- printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
- DRIVER_DESC "\n");
-
-out:
- return retval;
-}
-
-static void __exit
-usb_ov511_exit(void)
-{
- usb_deregister(&ov511_driver);
- printk(KERN_INFO KBUILD_MODNAME ": driver deregistered\n");
-}
-
-module_init(usb_ov511_init);
-module_exit(usb_ov511_exit);
-
diff --git a/drivers/media/video/ov511.h b/drivers/media/video/ov511.h
deleted file mode 100644
index c450c92468d..00000000000
--- a/drivers/media/video/ov511.h
+++ /dev/null
@@ -1,573 +0,0 @@
-#ifndef __LINUX_OV511_H
-#define __LINUX_OV511_H
-
-#include <asm/uaccess.h>
-#include <linux/videodev.h>
-#include <media/v4l2-common.h>
-#include <media/v4l2-ioctl.h>
-#include <linux/usb.h>
-#include <linux/mutex.h>
-
-#define OV511_DEBUG /* Turn on debug messages */
-
-#ifdef OV511_DEBUG
- #define PDEBUG(level, fmt, args...) \
- if (debug >= (level)) \
- printk(KERN_INFO KBUILD_MODNAME "[%s:%d] \n" fmt, \
- __func__, __LINE__ , ## args)
-#else
- #define PDEBUG(level, fmt, args...) do {} while(0)
-#endif
-
-/* This macro restricts an int variable to an inclusive range */
-#define RESTRICT_TO_RANGE(v,mi,ma) { \
- if ((v) < (mi)) (v) = (mi); \
- else if ((v) > (ma)) (v) = (ma); \
-}
-
-/* --------------------------------- */
-/* DEFINES FOR OV511 AND OTHER CHIPS */
-/* --------------------------------- */
-
-/* USB IDs */
-#define VEND_OMNIVISION 0x05A9
-#define PROD_OV511 0x0511
-#define PROD_OV511PLUS 0xA511
-#define PROD_OV518 0x0518
-#define PROD_OV518PLUS 0xA518
-
-#define VEND_MATTEL 0x0813
-#define PROD_ME2CAM 0x0002
-
-/* --------------------------------- */
-/* OV51x REGISTER MNEMONICS */
-/* --------------------------------- */
-
-/* Camera interface register numbers */
-#define R511_CAM_DELAY 0x10
-#define R511_CAM_EDGE 0x11
-#define R511_CAM_PXCNT 0x12
-#define R511_CAM_LNCNT 0x13
-#define R511_CAM_PXDIV 0x14
-#define R511_CAM_LNDIV 0x15
-#define R511_CAM_UV_EN 0x16
-#define R511_CAM_LINE_MODE 0x17
-#define R511_CAM_OPTS 0x18
-
-/* Snapshot mode camera interface register numbers */
-#define R511_SNAP_FRAME 0x19
-#define R511_SNAP_PXCNT 0x1A
-#define R511_SNAP_LNCNT 0x1B
-#define R511_SNAP_PXDIV 0x1C
-#define R511_SNAP_LNDIV 0x1D
-#define R511_SNAP_UV_EN 0x1E
-#define R511_SNAP_OPTS 0x1F
-
-/* DRAM register numbers */
-#define R511_DRAM_FLOW_CTL 0x20
-#define R511_DRAM_ARCP 0x21
-#define R511_DRAM_MRC 0x22
-#define R511_DRAM_RFC 0x23
-
-/* ISO FIFO register numbers */
-#define R51x_FIFO_PSIZE 0x30 /* 2 bytes wide w/ OV518(+) */
-#define R511_FIFO_OPTS 0x31
-
-/* Parallel IO register numbers */
-#define R511_PIO_OPTS 0x38
-#define R511_PIO_DATA 0x39
-#define R511_PIO_BIST 0x3E
-#define R518_GPIO_IN 0x55 /* OV518(+) only */
-#define R518_GPIO_OUT 0x56 /* OV518(+) only */
-#define R518_GPIO_CTL 0x57 /* OV518(+) only */
-#define R518_GPIO_PULSE_IN 0x58 /* OV518(+) only */
-#define R518_GPIO_PULSE_CLEAR 0x59 /* OV518(+) only */
-#define R518_GPIO_PULSE_POL 0x5a /* OV518(+) only */
-#define R518_GPIO_PULSE_EN 0x5b /* OV518(+) only */
-#define R518_GPIO_RESET 0x5c /* OV518(+) only */
-
-/* I2C registers */
-#define R511_I2C_CTL 0x40
-#define R518_I2C_CTL 0x47 /* OV518(+) only */
-#define R51x_I2C_W_SID 0x41
-#define R51x_I2C_SADDR_3 0x42
-#define R51x_I2C_SADDR_2 0x43
-#define R51x_I2C_R_SID 0x44
-#define R51x_I2C_DATA 0x45
-#define R51x_I2C_CLOCK 0x46
-#define R51x_I2C_TIMEOUT 0x47
-
-/* I2C snapshot registers */
-#define R511_SI2C_SADDR_3 0x48
-#define R511_SI2C_DATA 0x49
-
-/* System control registers */
-#define R51x_SYS_RESET 0x50
- /* Reset type definitions */
-#define OV511_RESET_UDC 0x01
-#define OV511_RESET_I2C 0x02
-#define OV511_RESET_FIFO 0x04
-#define OV511_RESET_OMNICE 0x08
-#define OV511_RESET_DRAM 0x10
-#define OV511_RESET_CAM_INT 0x20
-#define OV511_RESET_OV511 0x40
-#define OV511_RESET_NOREGS 0x3F /* All but OV511 & regs */
-#define OV511_RESET_ALL 0x7F
-
-#define R511_SYS_CLOCK_DIV 0x51
-#define R51x_SYS_SNAP 0x52
-#define R51x_SYS_INIT 0x53
-#define R511_SYS_PWR_CLK 0x54 /* OV511+/OV518(+) only */
-#define R511_SYS_LED_CTL 0x55 /* OV511+ only */
-#define R511_SYS_USER 0x5E
-#define R511_SYS_CUST_ID 0x5F
-
-/* OmniCE (compression) registers */
-#define R511_COMP_PHY 0x70
-#define R511_COMP_PHUV 0x71
-#define R511_COMP_PVY 0x72
-#define R511_COMP_PVUV 0x73
-#define R511_COMP_QHY 0x74
-#define R511_COMP_QHUV 0x75
-#define R511_COMP_QVY 0x76
-#define R511_COMP_QVUV 0x77
-#define R511_COMP_EN 0x78
-#define R511_COMP_LUT_EN 0x79
-#define R511_COMP_LUT_BEGIN 0x80
-
-/* --------------------------------- */
-/* ALTERNATE NUMBERS */
-/* --------------------------------- */
-
-/* Alternate numbers for various max packet sizes (OV511 only) */
-#define OV511_ALT_SIZE_992 0
-#define OV511_ALT_SIZE_993 1
-#define OV511_ALT_SIZE_768 2
-#define OV511_ALT_SIZE_769 3
-#define OV511_ALT_SIZE_512 4
-#define OV511_ALT_SIZE_513 5
-#define OV511_ALT_SIZE_257 6
-#define OV511_ALT_SIZE_0 7
-
-/* Alternate numbers for various max packet sizes (OV511+ only) */
-#define OV511PLUS_ALT_SIZE_0 0
-#define OV511PLUS_ALT_SIZE_33 1
-#define OV511PLUS_ALT_SIZE_129 2
-#define OV511PLUS_ALT_SIZE_257 3
-#define OV511PLUS_ALT_SIZE_385 4
-#define OV511PLUS_ALT_SIZE_513 5
-#define OV511PLUS_ALT_SIZE_769 6
-#define OV511PLUS_ALT_SIZE_961 7
-
-/* Alternate numbers for various max packet sizes (OV518(+) only) */
-#define OV518_ALT_SIZE_0 0
-#define OV518_ALT_SIZE_128 1
-#define OV518_ALT_SIZE_256 2
-#define OV518_ALT_SIZE_384 3
-#define OV518_ALT_SIZE_512 4
-#define OV518_ALT_SIZE_640 5
-#define OV518_ALT_SIZE_768 6
-#define OV518_ALT_SIZE_896 7
-
-/* --------------------------------- */
-/* OV7610 REGISTER MNEMONICS */
-/* --------------------------------- */
-
-/* OV7610 registers */
-#define OV7610_REG_GAIN 0x00 /* gain setting (5:0) */
-#define OV7610_REG_BLUE 0x01 /* blue channel balance */
-#define OV7610_REG_RED 0x02 /* red channel balance */
-#define OV7610_REG_SAT 0x03 /* saturation */
- /* 04 reserved */
-#define OV7610_REG_CNT 0x05 /* Y contrast */
-#define OV7610_REG_BRT 0x06 /* Y brightness */
- /* 08-0b reserved */
-#define OV7610_REG_BLUE_BIAS 0x0C /* blue channel bias (5:0) */
-#define OV7610_REG_RED_BIAS 0x0D /* read channel bias (5:0) */
-#define OV7610_REG_GAMMA_COEFF 0x0E /* gamma settings */
-#define OV7610_REG_WB_RANGE 0x0F /* AEC/ALC/S-AWB settings */
-#define OV7610_REG_EXP 0x10 /* manual exposure setting */
-#define OV7610_REG_CLOCK 0x11 /* polarity/clock prescaler */
-#define OV7610_REG_COM_A 0x12 /* misc common regs */
-#define OV7610_REG_COM_B 0x13 /* misc common regs */
-#define OV7610_REG_COM_C 0x14 /* misc common regs */
-#define OV7610_REG_COM_D 0x15 /* misc common regs */
-#define OV7610_REG_FIELD_DIVIDE 0x16 /* field interval/mode settings */
-#define OV7610_REG_HWIN_START 0x17 /* horizontal window start */
-#define OV7610_REG_HWIN_END 0x18 /* horizontal window end */
-#define OV7610_REG_VWIN_START 0x19 /* vertical window start */
-#define OV7610_REG_VWIN_END 0x1A /* vertical window end */
-#define OV7610_REG_PIXEL_SHIFT 0x1B /* pixel shift */
-#define OV7610_REG_ID_HIGH 0x1C /* manufacturer ID MSB */
-#define OV7610_REG_ID_LOW 0x1D /* manufacturer ID LSB */
- /* 0e-0f reserved */
-#define OV7610_REG_COM_E 0x20 /* misc common regs */
-#define OV7610_REG_YOFFSET 0x21 /* Y channel offset */
-#define OV7610_REG_UOFFSET 0x22 /* U channel offset */
- /* 23 reserved */
-#define OV7610_REG_ECW 0x24 /* Exposure white level for AEC */
-#define OV7610_REG_ECB 0x25 /* Exposure black level for AEC */
-#define OV7610_REG_COM_F 0x26 /* misc settings */
-#define OV7610_REG_COM_G 0x27 /* misc settings */
-#define OV7610_REG_COM_H 0x28 /* misc settings */
-#define OV7610_REG_COM_I 0x29 /* misc settings */
-#define OV7610_REG_FRAMERATE_H 0x2A /* frame rate MSB + misc */
-#define OV7610_REG_FRAMERATE_L 0x2B /* frame rate LSB */
-#define OV7610_REG_ALC 0x2C /* Auto Level Control settings */
-#define OV7610_REG_COM_J 0x2D /* misc settings */
-#define OV7610_REG_VOFFSET 0x2E /* V channel offset adjustment */
-#define OV7610_REG_ARRAY_BIAS 0x2F /* Array bias -- don't change */
- /* 30-32 reserved */
-#define OV7610_REG_YGAMMA 0x33 /* misc gamma settings (7:6) */
-#define OV7610_REG_BIAS_ADJUST 0x34 /* misc bias settings */
-#define OV7610_REG_COM_L 0x35 /* misc settings */
- /* 36-37 reserved */
-#define OV7610_REG_COM_K 0x38 /* misc registers */
-
-/* --------------------------------- */
-/* I2C ADDRESSES */
-/* --------------------------------- */
-
-#define OV7xx0_SID 0x42
-#define OV6xx0_SID 0xC0
-#define OV8xx0_SID 0xA0
-#define KS0127_SID 0xD8
-#define SAA7111A_SID 0x48
-
-/* --------------------------------- */
-/* MISCELLANEOUS DEFINES */
-/* --------------------------------- */
-
-#define I2C_CLOCK_PRESCALER 0x03
-
-#define FRAMES_PER_DESC 10 /* FIXME - What should this be? */
-#define MAX_FRAME_SIZE_PER_DESC 993 /* For statically allocated stuff */
-#define PIXELS_PER_SEG 256 /* Pixels per segment */
-
-#define OV511_ENDPOINT_ADDRESS 1 /* Isoc endpoint number */
-
-#define OV511_NUMFRAMES 2
-#if OV511_NUMFRAMES > VIDEO_MAX_FRAME
- #error "OV511_NUMFRAMES is too high"
-#endif
-
-#define OV511_NUMSBUF 2
-
-/* Control transfers use up to 4 bytes */
-#define OV511_CBUF_SIZE 4
-
-/* Size of usb_make_path() buffer */
-#define OV511_USB_PATH_LEN 64
-
-/* Bridge types */
-enum {
- BRG_UNKNOWN,
- BRG_OV511,
- BRG_OV511PLUS,
- BRG_OV518,
- BRG_OV518PLUS,
-};
-
-/* Bridge classes */
-enum {
- BCL_UNKNOWN,
- BCL_OV511,
- BCL_OV518,
-};
-
-/* Sensor types */
-enum {
- SEN_UNKNOWN,
- SEN_OV76BE,
- SEN_OV7610,
- SEN_OV7620,
- SEN_OV7620AE,
- SEN_OV6620,
- SEN_OV6630,
- SEN_OV6630AE,
- SEN_OV6630AF,
- SEN_OV8600,
- SEN_KS0127,
- SEN_KS0127B,
- SEN_SAA7111A,
-};
-
-enum {
- STATE_SCANNING, /* Scanning for start */
- STATE_HEADER, /* Parsing header */
- STATE_LINES, /* Parsing lines */
-};
-
-/* Buffer states */
-enum {
- BUF_NOT_ALLOCATED,
- BUF_ALLOCATED,
-};
-
-/* --------- Definition of ioctl interface --------- */
-
-#define OV511_INTERFACE_VER 101
-
-/* LED options */
-enum {
- LED_OFF,
- LED_ON,
- LED_AUTO,
-};
-
-/* Raw frame formats */
-enum {
- RAWFMT_INVALID,
- RAWFMT_YUV400,
- RAWFMT_YUV420,
- RAWFMT_YUV422,
- RAWFMT_GBR422,
-};
-
-struct ov511_i2c_struct {
- unsigned char slave; /* Write slave ID (read ID - 1) */
- unsigned char reg; /* Index of register */
- unsigned char value; /* User sets this w/ write, driver does w/ read */
- unsigned char mask; /* Bits to be changed. Not used with read ops */
-};
-
-/* ioctls */
-#define OV511IOC_WI2C _IOW('v', BASE_VIDIOCPRIVATE + 5, \
- struct ov511_i2c_struct)
-#define OV511IOC_RI2C _IOWR('v', BASE_VIDIOCPRIVATE + 6, \
- struct ov511_i2c_struct)
-/* ------------- End IOCTL interface -------------- */
-
-struct usb_ov511; /* Forward declaration */
-
-struct ov511_sbuf {
- struct usb_ov511 *ov;
- unsigned char *data;
- struct urb *urb;
- spinlock_t lock;
- int n;
-};
-
-enum {
- FRAME_UNUSED, /* Unused (no MCAPTURE) */
- FRAME_READY, /* Ready to start grabbing */
- FRAME_GRABBING, /* In the process of being grabbed into */
- FRAME_DONE, /* Finished grabbing, but not been synced yet */
- FRAME_ERROR, /* Something bad happened while processing */
-};
-
-struct ov511_regvals {
- enum {
- OV511_DONE_BUS,
- OV511_REG_BUS,
- OV511_I2C_BUS,
- } bus;
- unsigned char reg;
- unsigned char val;
-};
-
-struct ov511_frame {
- int framenum; /* Index of this frame */
- unsigned char *data; /* Frame buffer */
- unsigned char *tempdata; /* Temp buffer for multi-stage conversions */
- unsigned char *rawdata; /* Raw camera data buffer */
- unsigned char *compbuf; /* Temp buffer for decompressor */
-
- int depth; /* Bytes per pixel */
- int width; /* Width application is expecting */
- int height; /* Height application is expecting */
-
- int rawwidth; /* Actual width of frame sent from camera */
- int rawheight; /* Actual height of frame sent from camera */
-
- int sub_flag; /* Sub-capture mode for this frame? */
- unsigned int format; /* Format for this frame */
- int compressed; /* Is frame compressed? */
-
- volatile int grabstate; /* State of grabbing */
- int scanstate; /* State of scanning */
-
- int bytes_recvd; /* Number of image bytes received from camera */
-
- long bytes_read; /* Amount that has been read() */
-
- wait_queue_head_t wq; /* Processes waiting */
-
- int snapshot; /* True if frame was a snapshot */
-};
-
-#define DECOMP_INTERFACE_VER 4
-
-/* Compression module operations */
-struct ov51x_decomp_ops {
- int (*decomp_400)(unsigned char *, unsigned char *, unsigned char *,
- int, int, int);
- int (*decomp_420)(unsigned char *, unsigned char *, unsigned char *,
- int, int, int);
- int (*decomp_422)(unsigned char *, unsigned char *, unsigned char *,
- int, int, int);
- struct module *owner;
-};
-
-struct usb_ov511 {
- struct video_device *vdev;
- struct usb_device *dev;
-
- int customid;
- char *desc;
- unsigned char iface;
- char usb_path[OV511_USB_PATH_LEN];
-
- /* Determined by sensor type */
- int maxwidth;
- int maxheight;
- int minwidth;
- int minheight;
-
- int brightness;
- int colour;
- int contrast;
- int hue;
- int whiteness;
- int exposure;
- int auto_brt; /* Auto brightness enabled flag */
- int auto_gain; /* Auto gain control enabled flag */
- int auto_exp; /* Auto exposure enabled flag */
- int backlight; /* Backlight exposure algorithm flag */
- int mirror; /* Image is reversed horizontally */
-
- int led_policy; /* LED: off|on|auto; OV511+ only */
-
- struct mutex lock; /* Serializes user-accessible operations */
- int user; /* user count for exclusive use */
-
- int streaming; /* Are we streaming Isochronous? */
- int grabbing; /* Are we grabbing? */
-
- int compress; /* Should the next frame be compressed? */
- int compress_inited; /* Are compression params uploaded? */
-
- int lightfreq; /* Power (lighting) frequency */
- int bandfilt; /* Banding filter enabled flag */
-
- unsigned char *fbuf; /* Videodev buffer area */
- unsigned char *tempfbuf; /* Temporary (intermediate) buffer area */
- unsigned char *rawfbuf; /* Raw camera data buffer area */
-
- int sub_flag; /* Pix Array subcapture on flag */
- int subx; /* Pix Array subcapture x offset */
- int suby; /* Pix Array subcapture y offset */
- int subw; /* Pix Array subcapture width */
- int subh; /* Pix Array subcapture height */
-
- int curframe; /* Current receiving sbuf */
- struct ov511_frame frame[OV511_NUMFRAMES];
-
- struct ov511_sbuf sbuf[OV511_NUMSBUF];
-
- wait_queue_head_t wq; /* Processes waiting */
-
- int snap_enabled; /* Snapshot mode enabled */
-
- int bridge; /* Type of bridge (BRG_*) */
- int bclass; /* Class of bridge (BCL_*) */
- int sensor; /* Type of image sensor chip (SEN_*) */
-
- int packet_size; /* Frame size per isoc desc */
- int packet_numbering; /* Is ISO frame numbering enabled? */
-
- /* Framebuffer/sbuf management */
- int buf_state;
- struct mutex buf_lock;
-
- struct ov51x_decomp_ops *decomp_ops;
-
- /* Stop streaming while changing picture settings */
- int stop_during_set;
-
- int stopped; /* Streaming is temporarily paused */
-
- /* Video decoder stuff */
- int input; /* Composite, S-VIDEO, etc... */
- int num_inputs; /* Number of inputs */
- int norm; /* NTSC / PAL / SECAM */
- int has_decoder; /* Device has a video decoder */
- int pal; /* Device is designed for PAL resolution */
-
- /* ov511 device number ID */
- int nr; /* Stores a device number */
-
- /* I2C interface */
- struct mutex i2c_lock; /* Protect I2C controller regs */
- unsigned char primary_i2c_slave; /* I2C write id of sensor */
-
- /* Control transaction stuff */
- unsigned char *cbuf; /* Buffer for payload */
- struct mutex cbuf_lock;
-};
-
-/* Used to represent a list of values and their respective symbolic names */
-struct symbolic_list {
- int num;
- char *name;
-};
-
-#define NOT_DEFINED_STR "Unknown"
-
-/* Returns the name of the matching element in the symbolic_list array. The
- * end of the list must be marked with an element that has a NULL name.
- */
-static inline char *
-symbolic(struct symbolic_list list[], int num)
-{
- int i;
-
- for (i = 0; list[i].name != NULL; i++)
- if (list[i].num == num)
- return (list[i].name);
-
- return (NOT_DEFINED_STR);
-}
-
-/* Compression stuff */
-
-#define OV511_QUANTABLESIZE 64
-#define OV518_QUANTABLESIZE 32
-
-#define OV511_YQUANTABLE { \
- 0, 1, 1, 2, 2, 3, 3, 4, \
- 1, 1, 1, 2, 2, 3, 4, 4, \
- 1, 1, 2, 2, 3, 4, 4, 4, \
- 2, 2, 2, 3, 4, 4, 4, 4, \
- 2, 2, 3, 4, 4, 5, 5, 5, \
- 3, 3, 4, 4, 5, 5, 5, 5, \
- 3, 4, 4, 4, 5, 5, 5, 5, \
- 4, 4, 4, 4, 5, 5, 5, 5 \
-}
-
-#define OV511_UVQUANTABLE { \
- 0, 2, 2, 3, 4, 4, 4, 4, \
- 2, 2, 2, 4, 4, 4, 4, 4, \
- 2, 2, 3, 4, 4, 4, 4, 4, \
- 3, 4, 4, 4, 4, 4, 4, 4, \
- 4, 4, 4, 4, 4, 4, 4, 4, \
- 4, 4, 4, 4, 4, 4, 4, 4, \
- 4, 4, 4, 4, 4, 4, 4, 4, \
- 4, 4, 4, 4, 4, 4, 4, 4 \
-}
-
-#define OV518_YQUANTABLE { \
- 5, 4, 5, 6, 6, 7, 7, 7, \
- 5, 5, 5, 5, 6, 7, 7, 7, \
- 6, 6, 6, 6, 7, 7, 7, 8, \
- 7, 7, 6, 7, 7, 7, 8, 8 \
-}
-
-#define OV518_UVQUANTABLE { \
- 6, 6, 6, 7, 7, 7, 7, 7, \
- 6, 6, 6, 7, 7, 7, 7, 7, \
- 6, 6, 6, 7, 7, 7, 7, 8, \
- 7, 7, 7, 7, 7, 7, 8, 8 \
-}
-
-#endif
diff --git a/drivers/media/video/ov772x.c b/drivers/media/video/ov772x.c
index 34034a71021..25eb5d637ee 100644
--- a/drivers/media/video/ov772x.c
+++ b/drivers/media/video/ov772x.c
@@ -440,21 +440,21 @@ static const struct regval_list ov772x_vga_regs[] = {
*/
static const struct ov772x_color_format ov772x_cfmts[] = {
{
- .code = V4L2_MBUS_FMT_YUYV8_2X8_LE,
+ .code = V4L2_MBUS_FMT_YUYV8_2X8,
.colorspace = V4L2_COLORSPACE_JPEG,
.dsp3 = 0x0,
.com3 = SWAP_YUV,
.com7 = OFMT_YUV,
},
{
- .code = V4L2_MBUS_FMT_YVYU8_2X8_LE,
+ .code = V4L2_MBUS_FMT_YVYU8_2X8,
.colorspace = V4L2_COLORSPACE_JPEG,
.dsp3 = UV_ON,
.com3 = SWAP_YUV,
.com7 = OFMT_YUV,
},
{
- .code = V4L2_MBUS_FMT_YUYV8_2X8_BE,
+ .code = V4L2_MBUS_FMT_UYVY8_2X8,
.colorspace = V4L2_COLORSPACE_JPEG,
.dsp3 = 0x0,
.com3 = 0x0,
@@ -960,7 +960,7 @@ static int ov772x_g_fmt(struct v4l2_subdev *sd,
if (!priv->win || !priv->cfmt) {
u32 width = VGA_WIDTH, height = VGA_HEIGHT;
int ret = ov772x_set_params(client, &width, &height,
- V4L2_MBUS_FMT_YUYV8_2X8_LE);
+ V4L2_MBUS_FMT_YUYV8_2X8);
if (ret < 0)
return ret;
}
diff --git a/drivers/media/video/ov9640.c b/drivers/media/video/ov9640.c
index 7ce9e05b478..40cdfab74cc 100644
--- a/drivers/media/video/ov9640.c
+++ b/drivers/media/video/ov9640.c
@@ -155,7 +155,7 @@ static const struct ov9640_reg ov9640_regs_rgb[] = {
};
static enum v4l2_mbus_pixelcode ov9640_codes[] = {
- V4L2_MBUS_FMT_YUYV8_2X8_BE,
+ V4L2_MBUS_FMT_UYVY8_2X8,
V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE,
V4L2_MBUS_FMT_RGB565_2X8_LE,
};
@@ -430,7 +430,7 @@ static void ov9640_alter_regs(enum v4l2_mbus_pixelcode code,
{
switch (code) {
default:
- case V4L2_MBUS_FMT_YUYV8_2X8_BE:
+ case V4L2_MBUS_FMT_UYVY8_2X8:
alt->com12 = OV9640_COM12_YUV_AVG;
alt->com13 = OV9640_COM13_Y_DELAY_EN |
OV9640_COM13_YUV_DLY(0x01);
@@ -493,7 +493,7 @@ static int ov9640_write_regs(struct i2c_client *client, u32 width,
}
/* select color matrix configuration for given color encoding */
- if (code == V4L2_MBUS_FMT_YUYV8_2X8_BE) {
+ if (code == V4L2_MBUS_FMT_UYVY8_2X8) {
matrix_regs = ov9640_regs_yuv;
matrix_regs_len = ARRAY_SIZE(ov9640_regs_yuv);
} else {
@@ -579,8 +579,8 @@ static int ov9640_s_fmt(struct v4l2_subdev *sd,
cspace = V4L2_COLORSPACE_SRGB;
break;
default:
- code = V4L2_MBUS_FMT_YUYV8_2X8_BE;
- case V4L2_MBUS_FMT_YUYV8_2X8_BE:
+ code = V4L2_MBUS_FMT_UYVY8_2X8;
+ case V4L2_MBUS_FMT_UYVY8_2X8:
cspace = V4L2_COLORSPACE_JPEG;
}
@@ -606,8 +606,8 @@ static int ov9640_try_fmt(struct v4l2_subdev *sd,
mf->colorspace = V4L2_COLORSPACE_SRGB;
break;
default:
- mf->code = V4L2_MBUS_FMT_YUYV8_2X8_BE;
- case V4L2_MBUS_FMT_YUYV8_2X8_BE:
+ mf->code = V4L2_MBUS_FMT_UYVY8_2X8;
+ case V4L2_MBUS_FMT_UYVY8_2X8:
mf->colorspace = V4L2_COLORSPACE_JPEG;
}
diff --git a/drivers/media/video/ovcamchip/Makefile b/drivers/media/video/ovcamchip/Makefile
deleted file mode 100644
index cba4cdf20f4..00000000000
--- a/drivers/media/video/ovcamchip/Makefile
+++ /dev/null
@@ -1,4 +0,0 @@
-ovcamchip-objs := ovcamchip_core.o ov6x20.o ov6x30.o ov7x10.o ov7x20.o \
- ov76be.o
-
-obj-$(CONFIG_VIDEO_OVCAMCHIP) += ovcamchip.o
diff --git a/drivers/media/video/ovcamchip/ov6x20.c b/drivers/media/video/ovcamchip/ov6x20.c
deleted file mode 100644
index c04130dab12..00000000000
--- a/drivers/media/video/ovcamchip/ov6x20.c
+++ /dev/null
@@ -1,414 +0,0 @@
-/* OmniVision OV6620/OV6120 Camera Chip Support Code
- *
- * Copyright (c) 1999-2004 Mark McClelland <mark@alpha.dyndns.org>
- * http://alpha.dyndns.org/ov511/
- *
- * This program is free software; you can redistribute it and/or modify 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. NO WARRANTY OF ANY KIND is expressed or implied.
- */
-
-#define DEBUG
-
-#include <linux/slab.h>
-#include "ovcamchip_priv.h"
-
-/* Registers */
-#define REG_GAIN 0x00 /* gain [5:0] */
-#define REG_BLUE 0x01 /* blue gain */
-#define REG_RED 0x02 /* red gain */
-#define REG_SAT 0x03 /* saturation */
-#define REG_CNT 0x05 /* Y contrast */
-#define REG_BRT 0x06 /* Y brightness */
-#define REG_WB_BLUE 0x0C /* WB blue ratio [5:0] */
-#define REG_WB_RED 0x0D /* WB red ratio [5:0] */
-#define REG_EXP 0x10 /* exposure */
-
-/* Window parameters */
-#define HWSBASE 0x38
-#define HWEBASE 0x3A
-#define VWSBASE 0x05
-#define VWEBASE 0x06
-
-struct ov6x20 {
- int auto_brt;
- int auto_exp;
- int backlight;
- int bandfilt;
- int mirror;
-};
-
-/* Initial values for use with OV511/OV511+ cameras */
-static struct ovcamchip_regvals regvals_init_6x20_511[] = {
- { 0x12, 0x80 }, /* reset */
- { 0x11, 0x01 },
- { 0x03, 0x60 },
- { 0x05, 0x7f }, /* For when autoadjust is off */
- { 0x07, 0xa8 },
- { 0x0c, 0x24 },
- { 0x0d, 0x24 },
- { 0x0f, 0x15 }, /* COMS */
- { 0x10, 0x75 }, /* AEC Exposure time */
- { 0x12, 0x24 }, /* Enable AGC and AWB */
- { 0x14, 0x04 },
- { 0x16, 0x03 },
- { 0x26, 0xb2 }, /* BLC enable */
- /* 0x28: 0x05 Selects RGB format if RGB on */
- { 0x28, 0x05 },
- { 0x2a, 0x04 }, /* Disable framerate adjust */
- { 0x2d, 0x99 },
- { 0x33, 0xa0 }, /* Color Processing Parameter */
- { 0x34, 0xd2 }, /* Max A/D range */
- { 0x38, 0x8b },
- { 0x39, 0x40 },
-
- { 0x3c, 0x39 }, /* Enable AEC mode changing */
- { 0x3c, 0x3c }, /* Change AEC mode */
- { 0x3c, 0x24 }, /* Disable AEC mode changing */
-
- { 0x3d, 0x80 },
- /* These next two registers (0x4a, 0x4b) are undocumented. They
- * control the color balance */
- { 0x4a, 0x80 },
- { 0x4b, 0x80 },
- { 0x4d, 0xd2 }, /* This reduces noise a bit */
- { 0x4e, 0xc1 },
- { 0x4f, 0x04 },
- { 0xff, 0xff }, /* END MARKER */
-};
-
-/* Initial values for use with OV518 cameras */
-static struct ovcamchip_regvals regvals_init_6x20_518[] = {
- { 0x12, 0x80 }, /* Do a reset */
- { 0x03, 0xc0 }, /* Saturation */
- { 0x05, 0x8a }, /* Contrast */
- { 0x0c, 0x24 }, /* AWB blue */
- { 0x0d, 0x24 }, /* AWB red */
- { 0x0e, 0x8d }, /* Additional 2x gain */
- { 0x0f, 0x25 }, /* Black expanding level = 1.3V */
- { 0x11, 0x01 }, /* Clock div. */
- { 0x12, 0x24 }, /* Enable AGC and AWB */
- { 0x13, 0x01 }, /* (default) */
- { 0x14, 0x80 }, /* Set reserved bit 7 */
- { 0x15, 0x01 }, /* (default) */
- { 0x16, 0x03 }, /* (default) */
- { 0x17, 0x38 }, /* (default) */
- { 0x18, 0xea }, /* (default) */
- { 0x19, 0x04 },
- { 0x1a, 0x93 },
- { 0x1b, 0x00 }, /* (default) */
- { 0x1e, 0xc4 }, /* (default) */
- { 0x1f, 0x04 }, /* (default) */
- { 0x20, 0x20 }, /* Enable 1st stage aperture correction */
- { 0x21, 0x10 }, /* Y offset */
- { 0x22, 0x88 }, /* U offset */
- { 0x23, 0xc0 }, /* Set XTAL power level */
- { 0x24, 0x53 }, /* AEC bright ratio */
- { 0x25, 0x7a }, /* AEC black ratio */
- { 0x26, 0xb2 }, /* BLC enable */
- { 0x27, 0xa2 }, /* Full output range */
- { 0x28, 0x01 }, /* (default) */
- { 0x29, 0x00 }, /* (default) */
- { 0x2a, 0x84 }, /* (default) */
- { 0x2b, 0xa8 }, /* Set custom frame rate */
- { 0x2c, 0xa0 }, /* (reserved) */
- { 0x2d, 0x95 }, /* Enable banding filter */
- { 0x2e, 0x88 }, /* V offset */
- { 0x33, 0x22 }, /* Luminance gamma on */
- { 0x34, 0xc7 }, /* A/D bias */
- { 0x36, 0x12 }, /* (reserved) */
- { 0x37, 0x63 }, /* (reserved) */
- { 0x38, 0x8b }, /* Quick AEC/AEB */
- { 0x39, 0x00 }, /* (default) */
- { 0x3a, 0x0f }, /* (default) */
- { 0x3b, 0x3c }, /* (default) */
- { 0x3c, 0x5c }, /* AEC controls */
- { 0x3d, 0x80 }, /* Drop 1 (bad) frame when AEC change */
- { 0x3e, 0x80 }, /* (default) */
- { 0x3f, 0x02 }, /* (default) */
- { 0x40, 0x10 }, /* (reserved) */
- { 0x41, 0x10 }, /* (reserved) */
- { 0x42, 0x00 }, /* (reserved) */
- { 0x43, 0x7f }, /* (reserved) */
- { 0x44, 0x80 }, /* (reserved) */
- { 0x45, 0x1c }, /* (reserved) */
- { 0x46, 0x1c }, /* (reserved) */
- { 0x47, 0x80 }, /* (reserved) */
- { 0x48, 0x5f }, /* (reserved) */
- { 0x49, 0x00 }, /* (reserved) */
- { 0x4a, 0x00 }, /* Color balance (undocumented) */
- { 0x4b, 0x80 }, /* Color balance (undocumented) */
- { 0x4c, 0x58 }, /* (reserved) */
- { 0x4d, 0xd2 }, /* U *= .938, V *= .838 */
- { 0x4e, 0xa0 }, /* (default) */
- { 0x4f, 0x04 }, /* UV 3-point average */
- { 0x50, 0xff }, /* (reserved) */
- { 0x51, 0x58 }, /* (reserved) */
- { 0x52, 0xc0 }, /* (reserved) */
- { 0x53, 0x42 }, /* (reserved) */
- { 0x27, 0xa6 }, /* Enable manual offset adj. (reg 21 & 22) */
- { 0x12, 0x20 },
- { 0x12, 0x24 },
-
- { 0xff, 0xff }, /* END MARKER */
-};
-
-/* This initializes the OV6x20 camera chip and relevant variables. */
-static int ov6x20_init(struct i2c_client *c)
-{
- struct ovcamchip *ov = i2c_get_clientdata(c);
- struct ov6x20 *s;
- int rc;
-
- DDEBUG(4, &c->dev, "entered");
-
- switch (c->adapter->id) {
- case I2C_HW_SMBUS_OV511:
- rc = ov_write_regvals(c, regvals_init_6x20_511);
- break;
- case I2C_HW_SMBUS_OV518:
- rc = ov_write_regvals(c, regvals_init_6x20_518);
- break;
- default:
- dev_err(&c->dev, "ov6x20: Unsupported adapter\n");
- rc = -ENODEV;
- }
-
- if (rc < 0)
- return rc;
-
- ov->spriv = s = kzalloc(sizeof *s, GFP_KERNEL);
- if (!s)
- return -ENOMEM;
-
- s->auto_brt = 1;
- s->auto_exp = 1;
-
- return rc;
-}
-
-static int ov6x20_free(struct i2c_client *c)
-{
- struct ovcamchip *ov = i2c_get_clientdata(c);
-
- kfree(ov->spriv);
- return 0;
-}
-
-static int ov6x20_set_control(struct i2c_client *c,
- struct ovcamchip_control *ctl)
-{
- struct ovcamchip *ov = i2c_get_clientdata(c);
- struct ov6x20 *s = ov->spriv;
- int rc;
- int v = ctl->value;
-
- switch (ctl->id) {
- case OVCAMCHIP_CID_CONT:
- rc = ov_write(c, REG_CNT, v >> 8);
- break;
- case OVCAMCHIP_CID_BRIGHT:
- rc = ov_write(c, REG_BRT, v >> 8);
- break;
- case OVCAMCHIP_CID_SAT:
- rc = ov_write(c, REG_SAT, v >> 8);
- break;
- case OVCAMCHIP_CID_HUE:
- rc = ov_write(c, REG_RED, 0xFF - (v >> 8));
- if (rc < 0)
- goto out;
-
- rc = ov_write(c, REG_BLUE, v >> 8);
- break;
- case OVCAMCHIP_CID_EXP:
- rc = ov_write(c, REG_EXP, v);
- break;
- case OVCAMCHIP_CID_FREQ:
- {
- int sixty = (v == 60);
-
- rc = ov_write(c, 0x2b, sixty?0xa8:0x28);
- if (rc < 0)
- goto out;
-
- rc = ov_write(c, 0x2a, sixty?0x84:0xa4);
- break;
- }
- case OVCAMCHIP_CID_BANDFILT:
- rc = ov_write_mask(c, 0x2d, v?0x04:0x00, 0x04);
- s->bandfilt = v;
- break;
- case OVCAMCHIP_CID_AUTOBRIGHT:
- rc = ov_write_mask(c, 0x2d, v?0x10:0x00, 0x10);
- s->auto_brt = v;
- break;
- case OVCAMCHIP_CID_AUTOEXP:
- rc = ov_write_mask(c, 0x13, v?0x01:0x00, 0x01);
- s->auto_exp = v;
- break;
- case OVCAMCHIP_CID_BACKLIGHT:
- {
- rc = ov_write_mask(c, 0x4e, v?0xe0:0xc0, 0xe0);
- if (rc < 0)
- goto out;
-
- rc = ov_write_mask(c, 0x29, v?0x08:0x00, 0x08);
- if (rc < 0)
- goto out;
-
- rc = ov_write_mask(c, 0x0e, v?0x80:0x00, 0x80);
- s->backlight = v;
- break;
- }
- case OVCAMCHIP_CID_MIRROR:
- rc = ov_write_mask(c, 0x12, v?0x40:0x00, 0x40);
- s->mirror = v;
- break;
- default:
- DDEBUG(2, &c->dev, "control not supported: %d", ctl->id);
- return -EPERM;
- }
-
-out:
- DDEBUG(3, &c->dev, "id=%d, arg=%d, rc=%d", ctl->id, v, rc);
- return rc;
-}
-
-static int ov6x20_get_control(struct i2c_client *c,
- struct ovcamchip_control *ctl)
-{
- struct ovcamchip *ov = i2c_get_clientdata(c);
- struct ov6x20 *s = ov->spriv;
- int rc = 0;
- unsigned char val = 0;
-
- switch (ctl->id) {
- case OVCAMCHIP_CID_CONT:
- rc = ov_read(c, REG_CNT, &val);
- ctl->value = val << 8;
- break;
- case OVCAMCHIP_CID_BRIGHT:
- rc = ov_read(c, REG_BRT, &val);
- ctl->value = val << 8;
- break;
- case OVCAMCHIP_CID_SAT:
- rc = ov_read(c, REG_SAT, &val);
- ctl->value = val << 8;
- break;
- case OVCAMCHIP_CID_HUE:
- rc = ov_read(c, REG_BLUE, &val);
- ctl->value = val << 8;
- break;
- case OVCAMCHIP_CID_EXP:
- rc = ov_read(c, REG_EXP, &val);
- ctl->value = val;
- break;
- case OVCAMCHIP_CID_BANDFILT:
- ctl->value = s->bandfilt;
- break;
- case OVCAMCHIP_CID_AUTOBRIGHT:
- ctl->value = s->auto_brt;
- break;
- case OVCAMCHIP_CID_AUTOEXP:
- ctl->value = s->auto_exp;
- break;
- case OVCAMCHIP_CID_BACKLIGHT:
- ctl->value = s->backlight;
- break;
- case OVCAMCHIP_CID_MIRROR:
- ctl->value = s->mirror;
- break;
- default:
- DDEBUG(2, &c->dev, "control not supported: %d", ctl->id);
- return -EPERM;
- }
-
- DDEBUG(3, &c->dev, "id=%d, arg=%d, rc=%d", ctl->id, ctl->value, rc);
- return rc;
-}
-
-static int ov6x20_mode_init(struct i2c_client *c, struct ovcamchip_window *win)
-{
- /******** QCIF-specific regs ********/
-
- ov_write(c, 0x14, win->quarter?0x24:0x04);
-
- /******** Palette-specific regs ********/
-
- /* OV518 needs 8 bit multiplexed in color mode, and 16 bit in B&W */
- if (c->adapter->id == I2C_HW_SMBUS_OV518) {
- if (win->format == VIDEO_PALETTE_GREY)
- ov_write_mask(c, 0x13, 0x00, 0x20);
- else
- ov_write_mask(c, 0x13, 0x20, 0x20);
- } else {
- if (win->format == VIDEO_PALETTE_GREY)
- ov_write_mask(c, 0x13, 0x20, 0x20);
- else
- ov_write_mask(c, 0x13, 0x00, 0x20);
- }
-
- /******** Clock programming ********/
-
- /* The OV6620 needs special handling. This prevents the
- * severe banding that normally occurs */
-
- /* Clock down */
- ov_write(c, 0x2a, 0x04);
-
- ov_write(c, 0x11, win->clockdiv);
-
- ov_write(c, 0x2a, 0x84);
- /* This next setting is critical. It seems to improve
- * the gain or the contrast. The "reserved" bits seem
- * to have some effect in this case. */
- ov_write(c, 0x2d, 0x85); /* FIXME: This messes up banding filter */
-
- return 0;
-}
-
-static int ov6x20_set_window(struct i2c_client *c, struct ovcamchip_window *win)
-{
- int ret, hwscale, vwscale;
-
- ret = ov6x20_mode_init(c, win);
- if (ret < 0)
- return ret;
-
- if (win->quarter) {
- hwscale = 0;
- vwscale = 0;
- } else {
- hwscale = 1;
- vwscale = 1; /* The datasheet says 0; it's wrong */
- }
-
- ov_write(c, 0x17, HWSBASE + (win->x >> hwscale));
- ov_write(c, 0x18, HWEBASE + ((win->x + win->width) >> hwscale));
- ov_write(c, 0x19, VWSBASE + (win->y >> vwscale));
- ov_write(c, 0x1a, VWEBASE + ((win->y + win->height) >> vwscale));
-
- return 0;
-}
-
-static int ov6x20_command(struct i2c_client *c, unsigned int cmd, void *arg)
-{
- switch (cmd) {
- case OVCAMCHIP_CMD_S_CTRL:
- return ov6x20_set_control(c, arg);
- case OVCAMCHIP_CMD_G_CTRL:
- return ov6x20_get_control(c, arg);
- case OVCAMCHIP_CMD_S_MODE:
- return ov6x20_set_window(c, arg);
- default:
- DDEBUG(2, &c->dev, "command not supported: %d", cmd);
- return -ENOIOCTLCMD;
- }
-}
-
-struct ovcamchip_ops ov6x20_ops = {
- .init = ov6x20_init,
- .free = ov6x20_free,
- .command = ov6x20_command,
-};
diff --git a/drivers/media/video/ovcamchip/ov6x30.c b/drivers/media/video/ovcamchip/ov6x30.c
deleted file mode 100644
index 73b94f51a85..00000000000
--- a/drivers/media/video/ovcamchip/ov6x30.c
+++ /dev/null
@@ -1,373 +0,0 @@
-/* OmniVision OV6630/OV6130 Camera Chip Support Code
- *
- * Copyright (c) 1999-2004 Mark McClelland <mark@alpha.dyndns.org>
- * http://alpha.dyndns.org/ov511/
- *
- * This program is free software; you can redistribute it and/or modify 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. NO WARRANTY OF ANY KIND is expressed or implied.
- */
-
-#define DEBUG
-
-#include <linux/slab.h>
-#include "ovcamchip_priv.h"
-
-/* Registers */
-#define REG_GAIN 0x00 /* gain [5:0] */
-#define REG_BLUE 0x01 /* blue gain */
-#define REG_RED 0x02 /* red gain */
-#define REG_SAT 0x03 /* saturation [7:3] */
-#define REG_CNT 0x05 /* Y contrast [3:0] */
-#define REG_BRT 0x06 /* Y brightness */
-#define REG_SHARP 0x07 /* sharpness */
-#define REG_WB_BLUE 0x0C /* WB blue ratio [5:0] */
-#define REG_WB_RED 0x0D /* WB red ratio [5:0] */
-#define REG_EXP 0x10 /* exposure */
-
-/* Window parameters */
-#define HWSBASE 0x38
-#define HWEBASE 0x3A
-#define VWSBASE 0x05
-#define VWEBASE 0x06
-
-struct ov6x30 {
- int auto_brt;
- int auto_exp;
- int backlight;
- int bandfilt;
- int mirror;
-};
-
-static struct ovcamchip_regvals regvals_init_6x30[] = {
- { 0x12, 0x80 }, /* reset */
- { 0x00, 0x1f }, /* Gain */
- { 0x01, 0x99 }, /* Blue gain */
- { 0x02, 0x7c }, /* Red gain */
- { 0x03, 0xc0 }, /* Saturation */
- { 0x05, 0x0a }, /* Contrast */
- { 0x06, 0x95 }, /* Brightness */
- { 0x07, 0x2d }, /* Sharpness */
- { 0x0c, 0x20 },
- { 0x0d, 0x20 },
- { 0x0e, 0x20 },
- { 0x0f, 0x05 },
- { 0x10, 0x9a }, /* "exposure check" */
- { 0x11, 0x00 }, /* Pixel clock = fastest */
- { 0x12, 0x24 }, /* Enable AGC and AWB */
- { 0x13, 0x21 },
- { 0x14, 0x80 },
- { 0x15, 0x01 },
- { 0x16, 0x03 },
- { 0x17, 0x38 },
- { 0x18, 0xea },
- { 0x19, 0x04 },
- { 0x1a, 0x93 },
- { 0x1b, 0x00 },
- { 0x1e, 0xc4 },
- { 0x1f, 0x04 },
- { 0x20, 0x20 },
- { 0x21, 0x10 },
- { 0x22, 0x88 },
- { 0x23, 0xc0 }, /* Crystal circuit power level */
- { 0x25, 0x9a }, /* Increase AEC black pixel ratio */
- { 0x26, 0xb2 }, /* BLC enable */
- { 0x27, 0xa2 },
- { 0x28, 0x00 },
- { 0x29, 0x00 },
- { 0x2a, 0x84 }, /* (keep) */
- { 0x2b, 0xa8 }, /* (keep) */
- { 0x2c, 0xa0 },
- { 0x2d, 0x95 }, /* Enable auto-brightness */
- { 0x2e, 0x88 },
- { 0x33, 0x26 },
- { 0x34, 0x03 },
- { 0x36, 0x8f },
- { 0x37, 0x80 },
- { 0x38, 0x83 },
- { 0x39, 0x80 },
- { 0x3a, 0x0f },
- { 0x3b, 0x3c },
- { 0x3c, 0x1a },
- { 0x3d, 0x80 },
- { 0x3e, 0x80 },
- { 0x3f, 0x0e },
- { 0x40, 0x00 }, /* White bal */
- { 0x41, 0x00 }, /* White bal */
- { 0x42, 0x80 },
- { 0x43, 0x3f }, /* White bal */
- { 0x44, 0x80 },
- { 0x45, 0x20 },
- { 0x46, 0x20 },
- { 0x47, 0x80 },
- { 0x48, 0x7f },
- { 0x49, 0x00 },
- { 0x4a, 0x00 },
- { 0x4b, 0x80 },
- { 0x4c, 0xd0 },
- { 0x4d, 0x10 }, /* U = 0.563u, V = 0.714v */
- { 0x4e, 0x40 },
- { 0x4f, 0x07 }, /* UV average mode, color killer: strongest */
- { 0x50, 0xff },
- { 0x54, 0x23 }, /* Max AGC gain: 18dB */
- { 0x55, 0xff },
- { 0x56, 0x12 },
- { 0x57, 0x81 }, /* (default) */
- { 0x58, 0x75 },
- { 0x59, 0x01 }, /* AGC dark current compensation: +1 */
- { 0x5a, 0x2c },
- { 0x5b, 0x0f }, /* AWB chrominance levels */
- { 0x5c, 0x10 },
- { 0x3d, 0x80 },
- { 0x27, 0xa6 },
- /* Toggle AWB off and on */
- { 0x12, 0x20 },
- { 0x12, 0x24 },
-
- { 0xff, 0xff }, /* END MARKER */
-};
-
-/* This initializes the OV6x30 camera chip and relevant variables. */
-static int ov6x30_init(struct i2c_client *c)
-{
- struct ovcamchip *ov = i2c_get_clientdata(c);
- struct ov6x30 *s;
- int rc;
-
- DDEBUG(4, &c->dev, "entered");
-
- rc = ov_write_regvals(c, regvals_init_6x30);
- if (rc < 0)
- return rc;
-
- ov->spriv = s = kzalloc(sizeof *s, GFP_KERNEL);
- if (!s)
- return -ENOMEM;
-
- s->auto_brt = 1;
- s->auto_exp = 1;
-
- return rc;
-}
-
-static int ov6x30_free(struct i2c_client *c)
-{
- struct ovcamchip *ov = i2c_get_clientdata(c);
-
- kfree(ov->spriv);
- return 0;
-}
-
-static int ov6x30_set_control(struct i2c_client *c,
- struct ovcamchip_control *ctl)
-{
- struct ovcamchip *ov = i2c_get_clientdata(c);
- struct ov6x30 *s = ov->spriv;
- int rc;
- int v = ctl->value;
-
- switch (ctl->id) {
- case OVCAMCHIP_CID_CONT:
- rc = ov_write_mask(c, REG_CNT, v >> 12, 0x0f);
- break;
- case OVCAMCHIP_CID_BRIGHT:
- rc = ov_write(c, REG_BRT, v >> 8);
- break;
- case OVCAMCHIP_CID_SAT:
- rc = ov_write(c, REG_SAT, v >> 8);
- break;
- case OVCAMCHIP_CID_HUE:
- rc = ov_write(c, REG_RED, 0xFF - (v >> 8));
- if (rc < 0)
- goto out;
-
- rc = ov_write(c, REG_BLUE, v >> 8);
- break;
- case OVCAMCHIP_CID_EXP:
- rc = ov_write(c, REG_EXP, v);
- break;
- case OVCAMCHIP_CID_FREQ:
- {
- int sixty = (v == 60);
-
- rc = ov_write(c, 0x2b, sixty?0xa8:0x28);
- if (rc < 0)
- goto out;
-
- rc = ov_write(c, 0x2a, sixty?0x84:0xa4);
- break;
- }
- case OVCAMCHIP_CID_BANDFILT:
- rc = ov_write_mask(c, 0x2d, v?0x04:0x00, 0x04);
- s->bandfilt = v;
- break;
- case OVCAMCHIP_CID_AUTOBRIGHT:
- rc = ov_write_mask(c, 0x2d, v?0x10:0x00, 0x10);
- s->auto_brt = v;
- break;
- case OVCAMCHIP_CID_AUTOEXP:
- rc = ov_write_mask(c, 0x28, v?0x00:0x10, 0x10);
- s->auto_exp = v;
- break;
- case OVCAMCHIP_CID_BACKLIGHT:
- {
- rc = ov_write_mask(c, 0x4e, v?0x80:0x60, 0xe0);
- if (rc < 0)
- goto out;
-
- rc = ov_write_mask(c, 0x29, v?0x08:0x00, 0x08);
- if (rc < 0)
- goto out;
-
- rc = ov_write_mask(c, 0x28, v?0x02:0x00, 0x02);
- s->backlight = v;
- break;
- }
- case OVCAMCHIP_CID_MIRROR:
- rc = ov_write_mask(c, 0x12, v?0x40:0x00, 0x40);
- s->mirror = v;
- break;
- default:
- DDEBUG(2, &c->dev, "control not supported: %d", ctl->id);
- return -EPERM;
- }
-
-out:
- DDEBUG(3, &c->dev, "id=%d, arg=%d, rc=%d", ctl->id, v, rc);
- return rc;
-}
-
-static int ov6x30_get_control(struct i2c_client *c,
- struct ovcamchip_control *ctl)
-{
- struct ovcamchip *ov = i2c_get_clientdata(c);
- struct ov6x30 *s = ov->spriv;
- int rc = 0;
- unsigned char val = 0;
-
- switch (ctl->id) {
- case OVCAMCHIP_CID_CONT:
- rc = ov_read(c, REG_CNT, &val);
- ctl->value = (val & 0x0f) << 12;
- break;
- case OVCAMCHIP_CID_BRIGHT:
- rc = ov_read(c, REG_BRT, &val);
- ctl->value = val << 8;
- break;
- case OVCAMCHIP_CID_SAT:
- rc = ov_read(c, REG_SAT, &val);
- ctl->value = val << 8;
- break;
- case OVCAMCHIP_CID_HUE:
- rc = ov_read(c, REG_BLUE, &val);
- ctl->value = val << 8;
- break;
- case OVCAMCHIP_CID_EXP:
- rc = ov_read(c, REG_EXP, &val);
- ctl->value = val;
- break;
- case OVCAMCHIP_CID_BANDFILT:
- ctl->value = s->bandfilt;
- break;
- case OVCAMCHIP_CID_AUTOBRIGHT:
- ctl->value = s->auto_brt;
- break;
- case OVCAMCHIP_CID_AUTOEXP:
- ctl->value = s->auto_exp;
- break;
- case OVCAMCHIP_CID_BACKLIGHT:
- ctl->value = s->backlight;
- break;
- case OVCAMCHIP_CID_MIRROR:
- ctl->value = s->mirror;
- break;
- default:
- DDEBUG(2, &c->dev, "control not supported: %d", ctl->id);
- return -EPERM;
- }
-
- DDEBUG(3, &c->dev, "id=%d, arg=%d, rc=%d", ctl->id, ctl->value, rc);
- return rc;
-}
-
-static int ov6x30_mode_init(struct i2c_client *c, struct ovcamchip_window *win)
-{
- /******** QCIF-specific regs ********/
-
- ov_write_mask(c, 0x14, win->quarter?0x20:0x00, 0x20);
-
- /******** Palette-specific regs ********/
-
- if (win->format == VIDEO_PALETTE_GREY) {
- if (c->adapter->id == I2C_HW_SMBUS_OV518) {
- /* Do nothing - we're already in 8-bit mode */
- } else {
- ov_write_mask(c, 0x13, 0x20, 0x20);
- }
- } else {
- /* The OV518 needs special treatment. Although both the OV518
- * and the OV6630 support a 16-bit video bus, only the 8 bit Y
- * bus is actually used. The UV bus is tied to ground.
- * Therefore, the OV6630 needs to be in 8-bit multiplexed
- * output mode */
-
- if (c->adapter->id == I2C_HW_SMBUS_OV518) {
- /* Do nothing - we want to stay in 8-bit mode */
- /* Warning: Messing with reg 0x13 breaks OV518 color */
- } else {
- ov_write_mask(c, 0x13, 0x00, 0x20);
- }
- }
-
- /******** Clock programming ********/
-
- ov_write(c, 0x11, win->clockdiv);
-
- return 0;
-}
-
-static int ov6x30_set_window(struct i2c_client *c, struct ovcamchip_window *win)
-{
- int ret, hwscale, vwscale;
-
- ret = ov6x30_mode_init(c, win);
- if (ret < 0)
- return ret;
-
- if (win->quarter) {
- hwscale = 0;
- vwscale = 0;
- } else {
- hwscale = 1;
- vwscale = 1; /* The datasheet says 0; it's wrong */
- }
-
- ov_write(c, 0x17, HWSBASE + (win->x >> hwscale));
- ov_write(c, 0x18, HWEBASE + ((win->x + win->width) >> hwscale));
- ov_write(c, 0x19, VWSBASE + (win->y >> vwscale));
- ov_write(c, 0x1a, VWEBASE + ((win->y + win->height) >> vwscale));
-
- return 0;
-}
-
-static int ov6x30_command(struct i2c_client *c, unsigned int cmd, void *arg)
-{
- switch (cmd) {
- case OVCAMCHIP_CMD_S_CTRL:
- return ov6x30_set_control(c, arg);
- case OVCAMCHIP_CMD_G_CTRL:
- return ov6x30_get_control(c, arg);
- case OVCAMCHIP_CMD_S_MODE:
- return ov6x30_set_window(c, arg);
- default:
- DDEBUG(2, &c->dev, "command not supported: %d", cmd);
- return -ENOIOCTLCMD;
- }
-}
-
-struct ovcamchip_ops ov6x30_ops = {
- .init = ov6x30_init,
- .free = ov6x30_free,
- .command = ov6x30_command,
-};
diff --git a/drivers/media/video/ovcamchip/ov76be.c b/drivers/media/video/ovcamchip/ov76be.c
deleted file mode 100644
index 11f6be924d8..00000000000
--- a/drivers/media/video/ovcamchip/ov76be.c
+++ /dev/null
@@ -1,302 +0,0 @@
-/* OmniVision OV76BE Camera Chip Support Code
- *
- * Copyright (c) 1999-2004 Mark McClelland <mark@alpha.dyndns.org>
- * http://alpha.dyndns.org/ov511/
- *
- * This program is free software; you can redistribute it and/or modify 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. NO WARRANTY OF ANY KIND is expressed or implied.
- */
-
-#define DEBUG
-
-#include <linux/slab.h>
-#include "ovcamchip_priv.h"
-
-/* OV7610 registers: Since the OV76BE is undocumented, we'll settle for these
- * for now. */
-#define REG_GAIN 0x00 /* gain [5:0] */
-#define REG_BLUE 0x01 /* blue channel balance */
-#define REG_RED 0x02 /* red channel balance */
-#define REG_SAT 0x03 /* saturation */
-#define REG_CNT 0x05 /* Y contrast */
-#define REG_BRT 0x06 /* Y brightness */
-#define REG_BLUE_BIAS 0x0C /* blue channel bias [5:0] */
-#define REG_RED_BIAS 0x0D /* red channel bias [5:0] */
-#define REG_GAMMA_COEFF 0x0E /* gamma settings */
-#define REG_WB_RANGE 0x0F /* AEC/ALC/S-AWB settings */
-#define REG_EXP 0x10 /* manual exposure setting */
-#define REG_CLOCK 0x11 /* polarity/clock prescaler */
-#define REG_FIELD_DIVIDE 0x16 /* field interval/mode settings */
-#define REG_HWIN_START 0x17 /* horizontal window start */
-#define REG_HWIN_END 0x18 /* horizontal window end */
-#define REG_VWIN_START 0x19 /* vertical window start */
-#define REG_VWIN_END 0x1A /* vertical window end */
-#define REG_PIXEL_SHIFT 0x1B /* pixel shift */
-#define REG_YOFFSET 0x21 /* Y channel offset */
-#define REG_UOFFSET 0x22 /* U channel offset */
-#define REG_ECW 0x24 /* exposure white level for AEC */
-#define REG_ECB 0x25 /* exposure black level for AEC */
-#define REG_FRAMERATE_H 0x2A /* frame rate MSB + misc */
-#define REG_FRAMERATE_L 0x2B /* frame rate LSB */
-#define REG_ALC 0x2C /* Auto Level Control settings */
-#define REG_VOFFSET 0x2E /* V channel offset adjustment */
-#define REG_ARRAY_BIAS 0x2F /* array bias -- don't change */
-#define REG_YGAMMA 0x33 /* misc gamma settings [7:6] */
-#define REG_BIAS_ADJUST 0x34 /* misc bias settings */
-
-/* Window parameters */
-#define HWSBASE 0x38
-#define HWEBASE 0x3a
-#define VWSBASE 0x05
-#define VWEBASE 0x05
-
-struct ov76be {
- int auto_brt;
- int auto_exp;
- int bandfilt;
- int mirror;
-};
-
-/* NOTE: These are the same as the 7x10 settings, but should eventually be
- * optimized for the OV76BE */
-static struct ovcamchip_regvals regvals_init_76be[] = {
- { 0x10, 0xff },
- { 0x16, 0x03 },
- { 0x28, 0x24 },
- { 0x2b, 0xac },
- { 0x12, 0x00 },
- { 0x38, 0x81 },
- { 0x28, 0x24 }, /* 0c */
- { 0x0f, 0x85 }, /* lg's setting */
- { 0x15, 0x01 },
- { 0x20, 0x1c },
- { 0x23, 0x2a },
- { 0x24, 0x10 },
- { 0x25, 0x8a },
- { 0x26, 0xa2 },
- { 0x27, 0xc2 },
- { 0x2a, 0x04 },
- { 0x2c, 0xfe },
- { 0x2d, 0x93 },
- { 0x30, 0x71 },
- { 0x31, 0x60 },
- { 0x32, 0x26 },
- { 0x33, 0x20 },
- { 0x34, 0x48 },
- { 0x12, 0x24 },
- { 0x11, 0x01 },
- { 0x0c, 0x24 },
- { 0x0d, 0x24 },
- { 0xff, 0xff }, /* END MARKER */
-};
-
-/* This initializes the OV76be camera chip and relevant variables. */
-static int ov76be_init(struct i2c_client *c)
-{
- struct ovcamchip *ov = i2c_get_clientdata(c);
- struct ov76be *s;
- int rc;
-
- DDEBUG(4, &c->dev, "entered");
-
- rc = ov_write_regvals(c, regvals_init_76be);
- if (rc < 0)
- return rc;
-
- ov->spriv = s = kzalloc(sizeof *s, GFP_KERNEL);
- if (!s)
- return -ENOMEM;
-
- s->auto_brt = 1;
- s->auto_exp = 1;
-
- return rc;
-}
-
-static int ov76be_free(struct i2c_client *c)
-{
- struct ovcamchip *ov = i2c_get_clientdata(c);
-
- kfree(ov->spriv);
- return 0;
-}
-
-static int ov76be_set_control(struct i2c_client *c,
- struct ovcamchip_control *ctl)
-{
- struct ovcamchip *ov = i2c_get_clientdata(c);
- struct ov76be *s = ov->spriv;
- int rc;
- int v = ctl->value;
-
- switch (ctl->id) {
- case OVCAMCHIP_CID_BRIGHT:
- rc = ov_write(c, REG_BRT, v >> 8);
- break;
- case OVCAMCHIP_CID_SAT:
- rc = ov_write(c, REG_SAT, v >> 8);
- break;
- case OVCAMCHIP_CID_EXP:
- rc = ov_write(c, REG_EXP, v);
- break;
- case OVCAMCHIP_CID_FREQ:
- {
- int sixty = (v == 60);
-
- rc = ov_write_mask(c, 0x2a, sixty?0x00:0x80, 0x80);
- if (rc < 0)
- goto out;
-
- rc = ov_write(c, 0x2b, sixty?0x00:0xac);
- if (rc < 0)
- goto out;
-
- rc = ov_write_mask(c, 0x76, 0x01, 0x01);
- break;
- }
- case OVCAMCHIP_CID_BANDFILT:
- rc = ov_write_mask(c, 0x2d, v?0x04:0x00, 0x04);
- s->bandfilt = v;
- break;
- case OVCAMCHIP_CID_AUTOBRIGHT:
- rc = ov_write_mask(c, 0x2d, v?0x10:0x00, 0x10);
- s->auto_brt = v;
- break;
- case OVCAMCHIP_CID_AUTOEXP:
- rc = ov_write_mask(c, 0x13, v?0x01:0x00, 0x01);
- s->auto_exp = v;
- break;
- case OVCAMCHIP_CID_MIRROR:
- rc = ov_write_mask(c, 0x12, v?0x40:0x00, 0x40);
- s->mirror = v;
- break;
- default:
- DDEBUG(2, &c->dev, "control not supported: %d", ctl->id);
- return -EPERM;
- }
-
-out:
- DDEBUG(3, &c->dev, "id=%d, arg=%d, rc=%d", ctl->id, v, rc);
- return rc;
-}
-
-static int ov76be_get_control(struct i2c_client *c,
- struct ovcamchip_control *ctl)
-{
- struct ovcamchip *ov = i2c_get_clientdata(c);
- struct ov76be *s = ov->spriv;
- int rc = 0;
- unsigned char val = 0;
-
- switch (ctl->id) {
- case OVCAMCHIP_CID_BRIGHT:
- rc = ov_read(c, REG_BRT, &val);
- ctl->value = val << 8;
- break;
- case OVCAMCHIP_CID_SAT:
- rc = ov_read(c, REG_SAT, &val);
- ctl->value = val << 8;
- break;
- case OVCAMCHIP_CID_EXP:
- rc = ov_read(c, REG_EXP, &val);
- ctl->value = val;
- break;
- case OVCAMCHIP_CID_BANDFILT:
- ctl->value = s->bandfilt;
- break;
- case OVCAMCHIP_CID_AUTOBRIGHT:
- ctl->value = s->auto_brt;
- break;
- case OVCAMCHIP_CID_AUTOEXP:
- ctl->value = s->auto_exp;
- break;
- case OVCAMCHIP_CID_MIRROR:
- ctl->value = s->mirror;
- break;
- default:
- DDEBUG(2, &c->dev, "control not supported: %d", ctl->id);
- return -EPERM;
- }
-
- DDEBUG(3, &c->dev, "id=%d, arg=%d, rc=%d", ctl->id, ctl->value, rc);
- return rc;
-}
-
-static int ov76be_mode_init(struct i2c_client *c, struct ovcamchip_window *win)
-{
- int qvga = win->quarter;
-
- /******** QVGA-specific regs ********/
-
- ov_write(c, 0x14, qvga?0xa4:0x84);
-
- /******** Palette-specific regs ********/
-
- if (win->format == VIDEO_PALETTE_GREY) {
- ov_write_mask(c, 0x0e, 0x40, 0x40);
- ov_write_mask(c, 0x13, 0x20, 0x20);
- } else {
- ov_write_mask(c, 0x0e, 0x00, 0x40);
- ov_write_mask(c, 0x13, 0x00, 0x20);
- }
-
- /******** Clock programming ********/
-
- ov_write(c, 0x11, win->clockdiv);
-
- /******** Resolution-specific ********/
-
- if (win->width == 640 && win->height == 480)
- ov_write(c, 0x35, 0x9e);
- else
- ov_write(c, 0x35, 0x1e);
-
- return 0;
-}
-
-static int ov76be_set_window(struct i2c_client *c, struct ovcamchip_window *win)
-{
- int ret, hwscale, vwscale;
-
- ret = ov76be_mode_init(c, win);
- if (ret < 0)
- return ret;
-
- if (win->quarter) {
- hwscale = 1;
- vwscale = 0;
- } else {
- hwscale = 2;
- vwscale = 1;
- }
-
- ov_write(c, 0x17, HWSBASE + (win->x >> hwscale));
- ov_write(c, 0x18, HWEBASE + ((win->x + win->width) >> hwscale));
- ov_write(c, 0x19, VWSBASE + (win->y >> vwscale));
- ov_write(c, 0x1a, VWEBASE + ((win->y + win->height) >> vwscale));
-
- return 0;
-}
-
-static int ov76be_command(struct i2c_client *c, unsigned int cmd, void *arg)
-{
- switch (cmd) {
- case OVCAMCHIP_CMD_S_CTRL:
- return ov76be_set_control(c, arg);
- case OVCAMCHIP_CMD_G_CTRL:
- return ov76be_get_control(c, arg);
- case OVCAMCHIP_CMD_S_MODE:
- return ov76be_set_window(c, arg);
- default:
- DDEBUG(2, &c->dev, "command not supported: %d", cmd);
- return -ENOIOCTLCMD;
- }
-}
-
-struct ovcamchip_ops ov76be_ops = {
- .init = ov76be_init,
- .free = ov76be_free,
- .command = ov76be_command,
-};
diff --git a/drivers/media/video/ovcamchip/ov7x10.c b/drivers/media/video/ovcamchip/ov7x10.c
deleted file mode 100644
index 5206e791392..00000000000
--- a/drivers/media/video/ovcamchip/ov7x10.c
+++ /dev/null
@@ -1,334 +0,0 @@
-/* OmniVision OV7610/OV7110 Camera Chip Support Code
- *
- * Copyright (c) 1999-2004 Mark McClelland <mark@alpha.dyndns.org>
- * http://alpha.dyndns.org/ov511/
- *
- * Color fixes by by Orion Sky Lawlor <olawlor@acm.org> (2/26/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. NO WARRANTY OF ANY KIND is expressed or implied.
- */
-
-#define DEBUG
-
-#include <linux/slab.h>
-#include "ovcamchip_priv.h"
-
-/* Registers */
-#define REG_GAIN 0x00 /* gain [5:0] */
-#define REG_BLUE 0x01 /* blue channel balance */
-#define REG_RED 0x02 /* red channel balance */
-#define REG_SAT 0x03 /* saturation */
-#define REG_CNT 0x05 /* Y contrast */
-#define REG_BRT 0x06 /* Y brightness */
-#define REG_BLUE_BIAS 0x0C /* blue channel bias [5:0] */
-#define REG_RED_BIAS 0x0D /* red channel bias [5:0] */
-#define REG_GAMMA_COEFF 0x0E /* gamma settings */
-#define REG_WB_RANGE 0x0F /* AEC/ALC/S-AWB settings */
-#define REG_EXP 0x10 /* manual exposure setting */
-#define REG_CLOCK 0x11 /* polarity/clock prescaler */
-#define REG_FIELD_DIVIDE 0x16 /* field interval/mode settings */
-#define REG_HWIN_START 0x17 /* horizontal window start */
-#define REG_HWIN_END 0x18 /* horizontal window end */
-#define REG_VWIN_START 0x19 /* vertical window start */
-#define REG_VWIN_END 0x1A /* vertical window end */
-#define REG_PIXEL_SHIFT 0x1B /* pixel shift */
-#define REG_YOFFSET 0x21 /* Y channel offset */
-#define REG_UOFFSET 0x22 /* U channel offset */
-#define REG_ECW 0x24 /* exposure white level for AEC */
-#define REG_ECB 0x25 /* exposure black level for AEC */
-#define REG_FRAMERATE_H 0x2A /* frame rate MSB + misc */
-#define REG_FRAMERATE_L 0x2B /* frame rate LSB */
-#define REG_ALC 0x2C /* Auto Level Control settings */
-#define REG_VOFFSET 0x2E /* V channel offset adjustment */
-#define REG_ARRAY_BIAS 0x2F /* array bias -- don't change */
-#define REG_YGAMMA 0x33 /* misc gamma settings [7:6] */
-#define REG_BIAS_ADJUST 0x34 /* misc bias settings */
-
-/* Window parameters */
-#define HWSBASE 0x38
-#define HWEBASE 0x3a
-#define VWSBASE 0x05
-#define VWEBASE 0x05
-
-struct ov7x10 {
- int auto_brt;
- int auto_exp;
- int bandfilt;
- int mirror;
-};
-
-/* Lawrence Glaister <lg@jfm.bc.ca> reports:
- *
- * Register 0x0f in the 7610 has the following effects:
- *
- * 0x85 (AEC method 1): Best overall, good contrast range
- * 0x45 (AEC method 2): Very overexposed
- * 0xa5 (spec sheet default): Ok, but the black level is
- * shifted resulting in loss of contrast
- * 0x05 (old driver setting): very overexposed, too much
- * contrast
- */
-static struct ovcamchip_regvals regvals_init_7x10[] = {
- { 0x10, 0xff },
- { 0x16, 0x03 },
- { 0x28, 0x24 },
- { 0x2b, 0xac },
- { 0x12, 0x00 },
- { 0x38, 0x81 },
- { 0x28, 0x24 }, /* 0c */
- { 0x0f, 0x85 }, /* lg's setting */
- { 0x15, 0x01 },
- { 0x20, 0x1c },
- { 0x23, 0x2a },
- { 0x24, 0x10 },
- { 0x25, 0x8a },
- { 0x26, 0xa2 },
- { 0x27, 0xc2 },
- { 0x2a, 0x04 },
- { 0x2c, 0xfe },
- { 0x2d, 0x93 },
- { 0x30, 0x71 },
- { 0x31, 0x60 },
- { 0x32, 0x26 },
- { 0x33, 0x20 },
- { 0x34, 0x48 },
- { 0x12, 0x24 },
- { 0x11, 0x01 },
- { 0x0c, 0x24 },
- { 0x0d, 0x24 },
- { 0xff, 0xff }, /* END MARKER */
-};
-
-/* This initializes the OV7x10 camera chip and relevant variables. */
-static int ov7x10_init(struct i2c_client *c)
-{
- struct ovcamchip *ov = i2c_get_clientdata(c);
- struct ov7x10 *s;
- int rc;
-
- DDEBUG(4, &c->dev, "entered");
-
- rc = ov_write_regvals(c, regvals_init_7x10);
- if (rc < 0)
- return rc;
-
- ov->spriv = s = kzalloc(sizeof *s, GFP_KERNEL);
- if (!s)
- return -ENOMEM;
-
- s->auto_brt = 1;
- s->auto_exp = 1;
-
- return rc;
-}
-
-static int ov7x10_free(struct i2c_client *c)
-{
- struct ovcamchip *ov = i2c_get_clientdata(c);
-
- kfree(ov->spriv);
- return 0;
-}
-
-static int ov7x10_set_control(struct i2c_client *c,
- struct ovcamchip_control *ctl)
-{
- struct ovcamchip *ov = i2c_get_clientdata(c);
- struct ov7x10 *s = ov->spriv;
- int rc;
- int v = ctl->value;
-
- switch (ctl->id) {
- case OVCAMCHIP_CID_CONT:
- rc = ov_write(c, REG_CNT, v >> 8);
- break;
- case OVCAMCHIP_CID_BRIGHT:
- rc = ov_write(c, REG_BRT, v >> 8);
- break;
- case OVCAMCHIP_CID_SAT:
- rc = ov_write(c, REG_SAT, v >> 8);
- break;
- case OVCAMCHIP_CID_HUE:
- rc = ov_write(c, REG_RED, 0xFF - (v >> 8));
- if (rc < 0)
- goto out;
-
- rc = ov_write(c, REG_BLUE, v >> 8);
- break;
- case OVCAMCHIP_CID_EXP:
- rc = ov_write(c, REG_EXP, v);
- break;
- case OVCAMCHIP_CID_FREQ:
- {
- int sixty = (v == 60);
-
- rc = ov_write_mask(c, 0x2a, sixty?0x00:0x80, 0x80);
- if (rc < 0)
- goto out;
-
- rc = ov_write(c, 0x2b, sixty?0x00:0xac);
- if (rc < 0)
- goto out;
-
- rc = ov_write_mask(c, 0x13, 0x10, 0x10);
- if (rc < 0)
- goto out;
-
- rc = ov_write_mask(c, 0x13, 0x00, 0x10);
- break;
- }
- case OVCAMCHIP_CID_BANDFILT:
- rc = ov_write_mask(c, 0x2d, v?0x04:0x00, 0x04);
- s->bandfilt = v;
- break;
- case OVCAMCHIP_CID_AUTOBRIGHT:
- rc = ov_write_mask(c, 0x2d, v?0x10:0x00, 0x10);
- s->auto_brt = v;
- break;
- case OVCAMCHIP_CID_AUTOEXP:
- rc = ov_write_mask(c, 0x29, v?0x00:0x80, 0x80);
- s->auto_exp = v;
- break;
- case OVCAMCHIP_CID_MIRROR:
- rc = ov_write_mask(c, 0x12, v?0x40:0x00, 0x40);
- s->mirror = v;
- break;
- default:
- DDEBUG(2, &c->dev, "control not supported: %d", ctl->id);
- return -EPERM;
- }
-
-out:
- DDEBUG(3, &c->dev, "id=%d, arg=%d, rc=%d", ctl->id, v, rc);
- return rc;
-}
-
-static int ov7x10_get_control(struct i2c_client *c,
- struct ovcamchip_control *ctl)
-{
- struct ovcamchip *ov = i2c_get_clientdata(c);
- struct ov7x10 *s = ov->spriv;
- int rc = 0;
- unsigned char val = 0;
-
- switch (ctl->id) {
- case OVCAMCHIP_CID_CONT:
- rc = ov_read(c, REG_CNT, &val);
- ctl->value = val << 8;
- break;
- case OVCAMCHIP_CID_BRIGHT:
- rc = ov_read(c, REG_BRT, &val);
- ctl->value = val << 8;
- break;
- case OVCAMCHIP_CID_SAT:
- rc = ov_read(c, REG_SAT, &val);
- ctl->value = val << 8;
- break;
- case OVCAMCHIP_CID_HUE:
- rc = ov_read(c, REG_BLUE, &val);
- ctl->value = val << 8;
- break;
- case OVCAMCHIP_CID_EXP:
- rc = ov_read(c, REG_EXP, &val);
- ctl->value = val;
- break;
- case OVCAMCHIP_CID_BANDFILT:
- ctl->value = s->bandfilt;
- break;
- case OVCAMCHIP_CID_AUTOBRIGHT:
- ctl->value = s->auto_brt;
- break;
- case OVCAMCHIP_CID_AUTOEXP:
- ctl->value = s->auto_exp;
- break;
- case OVCAMCHIP_CID_MIRROR:
- ctl->value = s->mirror;
- break;
- default:
- DDEBUG(2, &c->dev, "control not supported: %d", ctl->id);
- return -EPERM;
- }
-
- DDEBUG(3, &c->dev, "id=%d, arg=%d, rc=%d", ctl->id, ctl->value, rc);
- return rc;
-}
-
-static int ov7x10_mode_init(struct i2c_client *c, struct ovcamchip_window *win)
-{
- int qvga = win->quarter;
-
- /******** QVGA-specific regs ********/
-
- ov_write(c, 0x14, qvga?0x24:0x04);
-
- /******** Palette-specific regs ********/
-
- if (win->format == VIDEO_PALETTE_GREY) {
- ov_write_mask(c, 0x0e, 0x40, 0x40);
- ov_write_mask(c, 0x13, 0x20, 0x20);
- } else {
- ov_write_mask(c, 0x0e, 0x00, 0x40);
- ov_write_mask(c, 0x13, 0x00, 0x20);
- }
-
- /******** Clock programming ********/
-
- ov_write(c, 0x11, win->clockdiv);
-
- /******** Resolution-specific ********/
-
- if (win->width == 640 && win->height == 480)
- ov_write(c, 0x35, 0x9e);
- else
- ov_write(c, 0x35, 0x1e);
-
- return 0;
-}
-
-static int ov7x10_set_window(struct i2c_client *c, struct ovcamchip_window *win)
-{
- int ret, hwscale, vwscale;
-
- ret = ov7x10_mode_init(c, win);
- if (ret < 0)
- return ret;
-
- if (win->quarter) {
- hwscale = 1;
- vwscale = 0;
- } else {
- hwscale = 2;
- vwscale = 1;
- }
-
- ov_write(c, 0x17, HWSBASE + (win->x >> hwscale));
- ov_write(c, 0x18, HWEBASE + ((win->x + win->width) >> hwscale));
- ov_write(c, 0x19, VWSBASE + (win->y >> vwscale));
- ov_write(c, 0x1a, VWEBASE + ((win->y + win->height) >> vwscale));
-
- return 0;
-}
-
-static int ov7x10_command(struct i2c_client *c, unsigned int cmd, void *arg)
-{
- switch (cmd) {
- case OVCAMCHIP_CMD_S_CTRL:
- return ov7x10_set_control(c, arg);
- case OVCAMCHIP_CMD_G_CTRL:
- return ov7x10_get_control(c, arg);
- case OVCAMCHIP_CMD_S_MODE:
- return ov7x10_set_window(c, arg);
- default:
- DDEBUG(2, &c->dev, "command not supported: %d", cmd);
- return -ENOIOCTLCMD;
- }
-}
-
-struct ovcamchip_ops ov7x10_ops = {
- .init = ov7x10_init,
- .free = ov7x10_free,
- .command = ov7x10_command,
-};
diff --git a/drivers/media/video/ovcamchip/ov7x20.c b/drivers/media/video/ovcamchip/ov7x20.c
deleted file mode 100644
index 8e26ae338f3..00000000000
--- a/drivers/media/video/ovcamchip/ov7x20.c
+++ /dev/null
@@ -1,454 +0,0 @@
-/* OmniVision OV7620/OV7120 Camera Chip Support Code
- *
- * Copyright (c) 1999-2004 Mark McClelland <mark@alpha.dyndns.org>
- * http://alpha.dyndns.org/ov511/
- *
- * OV7620 fixes by Charl P. Botha <cpbotha@ieee.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. NO WARRANTY OF ANY KIND is expressed or implied.
- */
-
-#define DEBUG
-
-#include <linux/slab.h>
-#include "ovcamchip_priv.h"
-
-/* Registers */
-#define REG_GAIN 0x00 /* gain [5:0] */
-#define REG_BLUE 0x01 /* blue gain */
-#define REG_RED 0x02 /* red gain */
-#define REG_SAT 0x03 /* saturation */
-#define REG_BRT 0x06 /* Y brightness */
-#define REG_SHARP 0x07 /* analog sharpness */
-#define REG_BLUE_BIAS 0x0C /* WB blue ratio [5:0] */
-#define REG_RED_BIAS 0x0D /* WB red ratio [5:0] */
-#define REG_EXP 0x10 /* exposure */
-
-/* Default control settings. Values are in terms of V4L2 controls. */
-#define OV7120_DFL_BRIGHT 0x60
-#define OV7620_DFL_BRIGHT 0x60
-#define OV7120_DFL_SAT 0xb0
-#define OV7620_DFL_SAT 0xc0
-#define DFL_AUTO_EXP 1
-#define DFL_AUTO_GAIN 1
-#define OV7120_DFL_GAIN 0x00
-#define OV7620_DFL_GAIN 0x00
-/* NOTE: Since autoexposure is the default, these aren't programmed into the
- * OV7x20 chip. They are just here because V4L2 expects a default */
-#define OV7120_DFL_EXP 0x7f
-#define OV7620_DFL_EXP 0x7f
-
-/* Window parameters */
-#define HWSBASE 0x2F /* From 7620.SET (spec is wrong) */
-#define HWEBASE 0x2F
-#define VWSBASE 0x05
-#define VWEBASE 0x05
-
-struct ov7x20 {
- int auto_brt;
- int auto_exp;
- int auto_gain;
- int backlight;
- int bandfilt;
- int mirror;
-};
-
-/* Contrast look-up table */
-static unsigned char ctab[] = {
- 0x01, 0x05, 0x09, 0x11, 0x15, 0x35, 0x37, 0x57,
- 0x5b, 0xa5, 0xa7, 0xc7, 0xc9, 0xcf, 0xef, 0xff
-};
-
-/* Settings for (Black & White) OV7120 camera chip */
-static struct ovcamchip_regvals regvals_init_7120[] = {
- { 0x12, 0x80 }, /* reset */
- { 0x13, 0x00 }, /* Autoadjust off */
- { 0x12, 0x20 }, /* Disable AWB */
- { 0x13, DFL_AUTO_GAIN?0x01:0x00 }, /* Autoadjust on (if desired) */
- { 0x00, OV7120_DFL_GAIN },
- { 0x01, 0x80 },
- { 0x02, 0x80 },
- { 0x03, OV7120_DFL_SAT },
- { 0x06, OV7120_DFL_BRIGHT },
- { 0x07, 0x00 },
- { 0x0c, 0x20 },
- { 0x0d, 0x20 },
- { 0x11, 0x01 },
- { 0x14, 0x84 },
- { 0x15, 0x01 },
- { 0x16, 0x03 },
- { 0x17, 0x2f },
- { 0x18, 0xcf },
- { 0x19, 0x06 },
- { 0x1a, 0xf5 },
- { 0x1b, 0x00 },
- { 0x20, 0x08 },
- { 0x21, 0x80 },
- { 0x22, 0x80 },
- { 0x23, 0x00 },
- { 0x26, 0xa0 },
- { 0x27, 0xfa },
- { 0x28, 0x20 }, /* DON'T set bit 6. It is for the OV7620 only */
- { 0x29, DFL_AUTO_EXP?0x00:0x80 },
- { 0x2a, 0x10 },
- { 0x2b, 0x00 },
- { 0x2c, 0x88 },
- { 0x2d, 0x95 },
- { 0x2e, 0x80 },
- { 0x2f, 0x44 },
- { 0x60, 0x20 },
- { 0x61, 0x02 },
- { 0x62, 0x5f },
- { 0x63, 0xd5 },
- { 0x64, 0x57 },
- { 0x65, 0x83 }, /* OV says "don't change this value" */
- { 0x66, 0x55 },
- { 0x67, 0x92 },
- { 0x68, 0xcf },
- { 0x69, 0x76 },
- { 0x6a, 0x22 },
- { 0x6b, 0xe2 },
- { 0x6c, 0x40 },
- { 0x6d, 0x48 },
- { 0x6e, 0x80 },
- { 0x6f, 0x0d },
- { 0x70, 0x89 },
- { 0x71, 0x00 },
- { 0x72, 0x14 },
- { 0x73, 0x54 },
- { 0x74, 0xa0 },
- { 0x75, 0x8e },
- { 0x76, 0x00 },
- { 0x77, 0xff },
- { 0x78, 0x80 },
- { 0x79, 0x80 },
- { 0x7a, 0x80 },
- { 0x7b, 0xe6 },
- { 0x7c, 0x00 },
- { 0x24, 0x3a },
- { 0x25, 0x60 },
- { 0xff, 0xff }, /* END MARKER */
-};
-
-/* Settings for (color) OV7620 camera chip */
-static struct ovcamchip_regvals regvals_init_7620[] = {
- { 0x12, 0x80 }, /* reset */
- { 0x00, OV7620_DFL_GAIN },
- { 0x01, 0x80 },
- { 0x02, 0x80 },
- { 0x03, OV7620_DFL_SAT },
- { 0x06, OV7620_DFL_BRIGHT },
- { 0x07, 0x00 },
- { 0x0c, 0x24 },
- { 0x0c, 0x24 },
- { 0x0d, 0x24 },
- { 0x11, 0x01 },
- { 0x12, 0x24 },
- { 0x13, DFL_AUTO_GAIN?0x01:0x00 },
- { 0x14, 0x84 },
- { 0x15, 0x01 },
- { 0x16, 0x03 },
- { 0x17, 0x2f },
- { 0x18, 0xcf },
- { 0x19, 0x06 },
- { 0x1a, 0xf5 },
- { 0x1b, 0x00 },
- { 0x20, 0x18 },
- { 0x21, 0x80 },
- { 0x22, 0x80 },
- { 0x23, 0x00 },
- { 0x26, 0xa2 },
- { 0x27, 0xea },
- { 0x28, 0x20 },
- { 0x29, DFL_AUTO_EXP?0x00:0x80 },
- { 0x2a, 0x10 },
- { 0x2b, 0x00 },
- { 0x2c, 0x88 },
- { 0x2d, 0x91 },
- { 0x2e, 0x80 },
- { 0x2f, 0x44 },
- { 0x60, 0x27 },
- { 0x61, 0x02 },
- { 0x62, 0x5f },
- { 0x63, 0xd5 },
- { 0x64, 0x57 },
- { 0x65, 0x83 },
- { 0x66, 0x55 },
- { 0x67, 0x92 },
- { 0x68, 0xcf },
- { 0x69, 0x76 },
- { 0x6a, 0x22 },
- { 0x6b, 0x00 },
- { 0x6c, 0x02 },
- { 0x6d, 0x44 },
- { 0x6e, 0x80 },
- { 0x6f, 0x1d },
- { 0x70, 0x8b },
- { 0x71, 0x00 },
- { 0x72, 0x14 },
- { 0x73, 0x54 },
- { 0x74, 0x00 },
- { 0x75, 0x8e },
- { 0x76, 0x00 },
- { 0x77, 0xff },
- { 0x78, 0x80 },
- { 0x79, 0x80 },
- { 0x7a, 0x80 },
- { 0x7b, 0xe2 },
- { 0x7c, 0x00 },
- { 0xff, 0xff }, /* END MARKER */
-};
-
-/* Returns index into the specified look-up table, with 'n' elements, for which
- * the value is greater than or equal to "val". If a match isn't found, (n-1)
- * is returned. The entries in the table must be in ascending order. */
-static inline int ov7x20_lut_find(unsigned char lut[], int n, unsigned char val)
-{
- int i = 0;
-
- while (lut[i] < val && i < n)
- i++;
-
- return i;
-}
-
-/* This initializes the OV7x20 camera chip and relevant variables. */
-static int ov7x20_init(struct i2c_client *c)
-{
- struct ovcamchip *ov = i2c_get_clientdata(c);
- struct ov7x20 *s;
- int rc;
-
- DDEBUG(4, &c->dev, "entered");
-
- if (ov->mono)
- rc = ov_write_regvals(c, regvals_init_7120);
- else
- rc = ov_write_regvals(c, regvals_init_7620);
-
- if (rc < 0)
- return rc;
-
- ov->spriv = s = kzalloc(sizeof *s, GFP_KERNEL);
- if (!s)
- return -ENOMEM;
-
- s->auto_brt = 1;
- s->auto_exp = DFL_AUTO_EXP;
- s->auto_gain = DFL_AUTO_GAIN;
-
- return 0;
-}
-
-static int ov7x20_free(struct i2c_client *c)
-{
- struct ovcamchip *ov = i2c_get_clientdata(c);
-
- kfree(ov->spriv);
- return 0;
-}
-
-static int ov7x20_set_v4l1_control(struct i2c_client *c,
- struct ovcamchip_control *ctl)
-{
- struct ovcamchip *ov = i2c_get_clientdata(c);
- struct ov7x20 *s = ov->spriv;
- int rc;
- int v = ctl->value;
-
- switch (ctl->id) {
- case OVCAMCHIP_CID_CONT:
- {
- /* Use Y gamma control instead. Bit 0 enables it. */
- rc = ov_write(c, 0x64, ctab[v >> 12]);
- break;
- }
- case OVCAMCHIP_CID_BRIGHT:
- /* 7620 doesn't like manual changes when in auto mode */
- if (!s->auto_brt)
- rc = ov_write(c, REG_BRT, v >> 8);
- else
- rc = 0;
- break;
- case OVCAMCHIP_CID_SAT:
- rc = ov_write(c, REG_SAT, v >> 8);
- break;
- case OVCAMCHIP_CID_EXP:
- if (!s->auto_exp)
- rc = ov_write(c, REG_EXP, v);
- else
- rc = -EBUSY;
- break;
- case OVCAMCHIP_CID_FREQ:
- {
- int sixty = (v == 60);
-
- rc = ov_write_mask(c, 0x2a, sixty?0x00:0x80, 0x80);
- if (rc < 0)
- goto out;
-
- rc = ov_write(c, 0x2b, sixty?0x00:0xac);
- if (rc < 0)
- goto out;
-
- rc = ov_write_mask(c, 0x76, 0x01, 0x01);
- break;
- }
- case OVCAMCHIP_CID_BANDFILT:
- rc = ov_write_mask(c, 0x2d, v?0x04:0x00, 0x04);
- s->bandfilt = v;
- break;
- case OVCAMCHIP_CID_AUTOBRIGHT:
- rc = ov_write_mask(c, 0x2d, v?0x10:0x00, 0x10);
- s->auto_brt = v;
- break;
- case OVCAMCHIP_CID_AUTOEXP:
- rc = ov_write_mask(c, 0x13, v?0x01:0x00, 0x01);
- s->auto_exp = v;
- break;
- case OVCAMCHIP_CID_BACKLIGHT:
- {
- rc = ov_write_mask(c, 0x68, v?0xe0:0xc0, 0xe0);
- if (rc < 0)
- goto out;
-
- rc = ov_write_mask(c, 0x29, v?0x08:0x00, 0x08);
- if (rc < 0)
- goto out;
-
- rc = ov_write_mask(c, 0x28, v?0x02:0x00, 0x02);
- s->backlight = v;
- break;
- }
- case OVCAMCHIP_CID_MIRROR:
- rc = ov_write_mask(c, 0x12, v?0x40:0x00, 0x40);
- s->mirror = v;
- break;
- default:
- DDEBUG(2, &c->dev, "control not supported: %d", ctl->id);
- return -EPERM;
- }
-
-out:
- DDEBUG(3, &c->dev, "id=%d, arg=%d, rc=%d", ctl->id, v, rc);
- return rc;
-}
-
-static int ov7x20_get_v4l1_control(struct i2c_client *c,
- struct ovcamchip_control *ctl)
-{
- struct ovcamchip *ov = i2c_get_clientdata(c);
- struct ov7x20 *s = ov->spriv;
- int rc = 0;
- unsigned char val = 0;
-
- switch (ctl->id) {
- case OVCAMCHIP_CID_CONT:
- rc = ov_read(c, 0x64, &val);
- ctl->value = ov7x20_lut_find(ctab, 16, val) << 12;
- break;
- case OVCAMCHIP_CID_BRIGHT:
- rc = ov_read(c, REG_BRT, &val);
- ctl->value = val << 8;
- break;
- case OVCAMCHIP_CID_SAT:
- rc = ov_read(c, REG_SAT, &val);
- ctl->value = val << 8;
- break;
- case OVCAMCHIP_CID_EXP:
- rc = ov_read(c, REG_EXP, &val);
- ctl->value = val;
- break;
- case OVCAMCHIP_CID_BANDFILT:
- ctl->value = s->bandfilt;
- break;
- case OVCAMCHIP_CID_AUTOBRIGHT:
- ctl->value = s->auto_brt;
- break;
- case OVCAMCHIP_CID_AUTOEXP:
- ctl->value = s->auto_exp;
- break;
- case OVCAMCHIP_CID_BACKLIGHT:
- ctl->value = s->backlight;
- break;
- case OVCAMCHIP_CID_MIRROR:
- ctl->value = s->mirror;
- break;
- default:
- DDEBUG(2, &c->dev, "control not supported: %d", ctl->id);
- return -EPERM;
- }
-
- DDEBUG(3, &c->dev, "id=%d, arg=%d, rc=%d", ctl->id, ctl->value, rc);
- return rc;
-}
-
-static int ov7x20_mode_init(struct i2c_client *c, struct ovcamchip_window *win)
-{
- struct ovcamchip *ov = i2c_get_clientdata(c);
- int qvga = win->quarter;
-
- /******** QVGA-specific regs ********/
- ov_write_mask(c, 0x14, qvga?0x20:0x00, 0x20);
- ov_write_mask(c, 0x28, qvga?0x00:0x20, 0x20);
- ov_write(c, 0x24, qvga?0x20:0x3a);
- ov_write(c, 0x25, qvga?0x30:0x60);
- ov_write_mask(c, 0x2d, qvga?0x40:0x00, 0x40);
- if (!ov->mono)
- ov_write_mask(c, 0x67, qvga?0xf0:0x90, 0xf0);
- ov_write_mask(c, 0x74, qvga?0x20:0x00, 0x20);
-
- /******** Clock programming ********/
-
- ov_write(c, 0x11, win->clockdiv);
-
- return 0;
-}
-
-static int ov7x20_set_window(struct i2c_client *c, struct ovcamchip_window *win)
-{
- int ret, hwscale, vwscale;
-
- ret = ov7x20_mode_init(c, win);
- if (ret < 0)
- return ret;
-
- if (win->quarter) {
- hwscale = 1;
- vwscale = 0;
- } else {
- hwscale = 2;
- vwscale = 1;
- }
-
- ov_write(c, 0x17, HWSBASE + (win->x >> hwscale));
- ov_write(c, 0x18, HWEBASE + ((win->x + win->width) >> hwscale));
- ov_write(c, 0x19, VWSBASE + (win->y >> vwscale));
- ov_write(c, 0x1a, VWEBASE + ((win->y + win->height) >> vwscale));
-
- return 0;
-}
-
-static int ov7x20_command(struct i2c_client *c, unsigned int cmd, void *arg)
-{
- switch (cmd) {
- case OVCAMCHIP_CMD_S_CTRL:
- return ov7x20_set_v4l1_control(c, arg);
- case OVCAMCHIP_CMD_G_CTRL:
- return ov7x20_get_v4l1_control(c, arg);
- case OVCAMCHIP_CMD_S_MODE:
- return ov7x20_set_window(c, arg);
- default:
- DDEBUG(2, &c->dev, "command not supported: %d", cmd);
- return -ENOIOCTLCMD;
- }
-}
-
-struct ovcamchip_ops ov7x20_ops = {
- .init = ov7x20_init,
- .free = ov7x20_free,
- .command = ov7x20_command,
-};
diff --git a/drivers/media/video/ovcamchip/ovcamchip_core.c b/drivers/media/video/ovcamchip/ovcamchip_core.c
deleted file mode 100644
index d573d842899..00000000000
--- a/drivers/media/video/ovcamchip/ovcamchip_core.c
+++ /dev/null
@@ -1,395 +0,0 @@
-/* Shared Code for OmniVision Camera Chip Drivers
- *
- * Copyright (c) 2004 Mark McClelland <mark@alpha.dyndns.org>
- * http://alpha.dyndns.org/ov511/
- *
- * This program is free software; you can redistribute it and/or modify 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. NO WARRANTY OF ANY KIND is expressed or implied.
- */
-
-#define DEBUG
-
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/delay.h>
-#include <linux/i2c.h>
-#include <media/v4l2-device.h>
-#include <media/v4l2-i2c-drv.h>
-#include "ovcamchip_priv.h"
-
-#define DRIVER_VERSION "v2.27 for Linux 2.6"
-#define DRIVER_AUTHOR "Mark McClelland <mark@alpha.dyndns.org>"
-#define DRIVER_DESC "OV camera chip I2C driver"
-
-#define PINFO(fmt, args...) printk(KERN_INFO "ovcamchip: " fmt "\n" , ## args);
-#define PERROR(fmt, args...) printk(KERN_ERR "ovcamchip: " fmt "\n" , ## args);
-
-#ifdef DEBUG
-int ovcamchip_debug = 0;
-static int debug;
-module_param(debug, int, 0);
-MODULE_PARM_DESC(debug,
- "Debug level: 0=none, 1=inits, 2=warning, 3=config, 4=functions, 5=all");
-#endif
-
-/* By default, let bridge driver tell us if chip is monochrome. mono=0
- * will ignore that and always treat chips as color. mono=1 will force
- * monochrome mode for all chips. */
-static int mono = -1;
-module_param(mono, int, 0);
-MODULE_PARM_DESC(mono,
- "1=chips are monochrome (OVx1xx), 0=force color, -1=autodetect (default)");
-
-MODULE_AUTHOR(DRIVER_AUTHOR);
-MODULE_DESCRIPTION(DRIVER_DESC);
-MODULE_LICENSE("GPL");
-
-
-/* Registers common to all chips, that are needed for detection */
-#define GENERIC_REG_ID_HIGH 0x1C /* manufacturer ID MSB */
-#define GENERIC_REG_ID_LOW 0x1D /* manufacturer ID LSB */
-#define GENERIC_REG_COM_I 0x29 /* misc ID bits */
-
-static char *chip_names[NUM_CC_TYPES] = {
- [CC_UNKNOWN] = "Unknown chip",
- [CC_OV76BE] = "OV76BE",
- [CC_OV7610] = "OV7610",
- [CC_OV7620] = "OV7620",
- [CC_OV7620AE] = "OV7620AE",
- [CC_OV6620] = "OV6620",
- [CC_OV6630] = "OV6630",
- [CC_OV6630AE] = "OV6630AE",
- [CC_OV6630AF] = "OV6630AF",
-};
-
-/* ----------------------------------------------------------------------- */
-
-int ov_write_regvals(struct i2c_client *c, struct ovcamchip_regvals *rvals)
-{
- int rc;
-
- while (rvals->reg != 0xff) {
- rc = ov_write(c, rvals->reg, rvals->val);
- if (rc < 0)
- return rc;
- rvals++;
- }
-
- return 0;
-}
-
-/* Writes bits at positions specified by mask to an I2C reg. Bits that are in
- * the same position as 1's in "mask" are cleared and set to "value". Bits
- * that are in the same position as 0's in "mask" are preserved, regardless
- * of their respective state in "value".
- */
-int ov_write_mask(struct i2c_client *c,
- unsigned char reg,
- unsigned char value,
- unsigned char mask)
-{
- int rc;
- unsigned char oldval, newval;
-
- if (mask == 0xff) {
- newval = value;
- } else {
- rc = ov_read(c, reg, &oldval);
- if (rc < 0)
- return rc;
-
- oldval &= (~mask); /* Clear the masked bits */
- value &= mask; /* Enforce mask on value */
- newval = oldval | value; /* Set the desired bits */
- }
-
- return ov_write(c, reg, newval);
-}
-
-/* ----------------------------------------------------------------------- */
-
-/* Reset the chip and ensure that I2C is synchronized. Returns <0 if failure.
- */
-static int init_camchip(struct i2c_client *c)
-{
- int i, success;
- unsigned char high, low;
-
- /* Reset the chip */
- ov_write(c, 0x12, 0x80);
-
- /* Wait for it to initialize */
- msleep(150);
-
- for (i = 0, success = 0; i < I2C_DETECT_RETRIES && !success; i++) {
- if (ov_read(c, GENERIC_REG_ID_HIGH, &high) >= 0) {
- if (ov_read(c, GENERIC_REG_ID_LOW, &low) >= 0) {
- if (high == 0x7F && low == 0xA2) {
- success = 1;
- continue;
- }
- }
- }
-
- /* Reset the chip */
- ov_write(c, 0x12, 0x80);
-
- /* Wait for it to initialize */
- msleep(150);
-
- /* Dummy read to sync I2C */
- ov_read(c, 0x00, &low);
- }
-
- if (!success)
- return -EIO;
-
- PDEBUG(1, "I2C synced in %d attempt(s)", i);
-
- return 0;
-}
-
-/* This detects the OV7610, OV7620, or OV76BE chip. */
-static int ov7xx0_detect(struct i2c_client *c)
-{
- struct ovcamchip *ov = i2c_get_clientdata(c);
- int rc;
- unsigned char val;
-
- PDEBUG(4, "");
-
- /* Detect chip (sub)type */
- rc = ov_read(c, GENERIC_REG_COM_I, &val);
- if (rc < 0) {
- PERROR("Error detecting ov7xx0 type");
- return rc;
- }
-
- if ((val & 3) == 3) {
- PINFO("Camera chip is an OV7610");
- ov->subtype = CC_OV7610;
- } else if ((val & 3) == 1) {
- rc = ov_read(c, 0x15, &val);
- if (rc < 0) {
- PERROR("Error detecting ov7xx0 type");
- return rc;
- }
-
- if (val & 1) {
- PINFO("Camera chip is an OV7620AE");
- /* OV7620 is a close enough match for now. There are
- * some definite differences though, so this should be
- * fixed */
- ov->subtype = CC_OV7620;
- } else {
- PINFO("Camera chip is an OV76BE");
- ov->subtype = CC_OV76BE;
- }
- } else if ((val & 3) == 0) {
- PINFO("Camera chip is an OV7620");
- ov->subtype = CC_OV7620;
- } else {
- PERROR("Unknown camera chip version: %d", val & 3);
- return -ENOSYS;
- }
-
- if (ov->subtype == CC_OV76BE)
- ov->sops = &ov76be_ops;
- else if (ov->subtype == CC_OV7620)
- ov->sops = &ov7x20_ops;
- else
- ov->sops = &ov7x10_ops;
-
- return 0;
-}
-
-/* This detects the OV6620, OV6630, OV6630AE, or OV6630AF chip. */
-static int ov6xx0_detect(struct i2c_client *c)
-{
- struct ovcamchip *ov = i2c_get_clientdata(c);
- int rc;
- unsigned char val;
-
- PDEBUG(4, "");
-
- /* Detect chip (sub)type */
- rc = ov_read(c, GENERIC_REG_COM_I, &val);
- if (rc < 0) {
- PERROR("Error detecting ov6xx0 type");
- return -1;
- }
-
- if ((val & 3) == 0) {
- ov->subtype = CC_OV6630;
- PINFO("Camera chip is an OV6630");
- } else if ((val & 3) == 1) {
- ov->subtype = CC_OV6620;
- PINFO("Camera chip is an OV6620");
- } else if ((val & 3) == 2) {
- ov->subtype = CC_OV6630;
- PINFO("Camera chip is an OV6630AE");
- } else if ((val & 3) == 3) {
- ov->subtype = CC_OV6630;
- PINFO("Camera chip is an OV6630AF");
- }
-
- if (ov->subtype == CC_OV6620)
- ov->sops = &ov6x20_ops;
- else
- ov->sops = &ov6x30_ops;
-
- return 0;
-}
-
-static int ovcamchip_detect(struct i2c_client *c)
-{
- /* Ideally we would just try a single register write and see if it NAKs.
- * That isn't possible since the OV518 can't report I2C transaction
- * failures. So, we have to try to initialize the chip (i.e. reset it
- * and check the ID registers) to detect its presence. */
-
- /* Test for 7xx0 */
- PDEBUG(3, "Testing for 0V7xx0");
- if (init_camchip(c) < 0)
- return -ENODEV;
- /* 7-bit addresses with bit 0 set are for the OV7xx0 */
- if (c->addr & 1) {
- if (ov7xx0_detect(c) < 0) {
- PERROR("Failed to init OV7xx0");
- return -EIO;
- }
- return 0;
- }
- /* Test for 6xx0 */
- PDEBUG(3, "Testing for 0V6xx0");
- if (ov6xx0_detect(c) < 0) {
- PERROR("Failed to init OV6xx0");
- return -EIO;
- }
- return 0;
-}
-
-/* ----------------------------------------------------------------------- */
-
-static long ovcamchip_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
-{
- struct ovcamchip *ov = to_ovcamchip(sd);
- struct i2c_client *c = v4l2_get_subdevdata(sd);
-
- if (!ov->initialized &&
- cmd != OVCAMCHIP_CMD_Q_SUBTYPE &&
- cmd != OVCAMCHIP_CMD_INITIALIZE) {
- v4l2_err(sd, "Camera chip not initialized yet!\n");
- return -EPERM;
- }
-
- switch (cmd) {
- case OVCAMCHIP_CMD_Q_SUBTYPE:
- {
- *(int *)arg = ov->subtype;
- return 0;
- }
- case OVCAMCHIP_CMD_INITIALIZE:
- {
- int rc;
-
- if (mono == -1)
- ov->mono = *(int *)arg;
- else
- ov->mono = mono;
-
- if (ov->mono) {
- if (ov->subtype != CC_OV7620)
- v4l2_warn(sd, "Monochrome not "
- "implemented for this chip\n");
- else
- v4l2_info(sd, "Initializing chip as "
- "monochrome\n");
- }
-
- rc = ov->sops->init(c);
- if (rc < 0)
- return rc;
-
- ov->initialized = 1;
- return 0;
- }
- default:
- return ov->sops->command(c, cmd, arg);
- }
-}
-
-/* ----------------------------------------------------------------------- */
-
-static const struct v4l2_subdev_core_ops ovcamchip_core_ops = {
- .ioctl = ovcamchip_ioctl,
-};
-
-static const struct v4l2_subdev_ops ovcamchip_ops = {
- .core = &ovcamchip_core_ops,
-};
-
-static int ovcamchip_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
-{
- struct ovcamchip *ov;
- struct v4l2_subdev *sd;
- int rc = 0;
-
- ov = kzalloc(sizeof *ov, GFP_KERNEL);
- if (!ov) {
- rc = -ENOMEM;
- goto no_ov;
- }
- sd = &ov->sd;
- v4l2_i2c_subdev_init(sd, client, &ovcamchip_ops);
-
- rc = ovcamchip_detect(client);
- if (rc < 0)
- goto error;
-
- v4l_info(client, "%s found @ 0x%02x (%s)\n",
- chip_names[ov->subtype], client->addr << 1, client->adapter->name);
-
- PDEBUG(1, "Camera chip detection complete");
-
- return rc;
-error:
- kfree(ov);
-no_ov:
- PDEBUG(1, "returning %d", rc);
- return rc;
-}
-
-static int ovcamchip_remove(struct i2c_client *client)
-{
- struct v4l2_subdev *sd = i2c_get_clientdata(client);
- struct ovcamchip *ov = to_ovcamchip(sd);
- int rc;
-
- v4l2_device_unregister_subdev(sd);
- rc = ov->sops->free(client);
- if (rc < 0)
- return rc;
-
- kfree(ov);
- return 0;
-}
-
-/* ----------------------------------------------------------------------- */
-
-static const struct i2c_device_id ovcamchip_id[] = {
- { "ovcamchip", 0 },
- { }
-};
-MODULE_DEVICE_TABLE(i2c, ovcamchip_id);
-
-static struct v4l2_i2c_driver_data v4l2_i2c_data = {
- .name = "ovcamchip",
- .probe = ovcamchip_probe,
- .remove = ovcamchip_remove,
- .id_table = ovcamchip_id,
-};
diff --git a/drivers/media/video/ovcamchip/ovcamchip_priv.h b/drivers/media/video/ovcamchip/ovcamchip_priv.h
deleted file mode 100644
index 4f07b78c88b..00000000000
--- a/drivers/media/video/ovcamchip/ovcamchip_priv.h
+++ /dev/null
@@ -1,101 +0,0 @@
-/* OmniVision* camera chip driver private definitions for core code and
- * chip-specific code
- *
- * Copyright (c) 1999-2004 Mark McClelland
- *
- * This program is free software; you can redistribute it and/or modify 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. NO WARRANTY OF ANY KIND is expressed or implied.
- *
- * * OmniVision is a trademark of OmniVision Technologies, Inc. This driver
- * is not sponsored or developed by them.
- */
-
-#ifndef __LINUX_OVCAMCHIP_PRIV_H
-#define __LINUX_OVCAMCHIP_PRIV_H
-
-#include <linux/i2c.h>
-#include <media/v4l2-subdev.h>
-#include <media/ovcamchip.h>
-
-#ifdef DEBUG
-extern int ovcamchip_debug;
-#endif
-
-#define PDEBUG(level, fmt, args...) \
- if (ovcamchip_debug >= (level)) pr_debug("[%s:%d] " fmt "\n", \
- __func__, __LINE__ , ## args)
-
-#define DDEBUG(level, dev, fmt, args...) \
- if (ovcamchip_debug >= (level)) dev_dbg(dev, "[%s:%d] " fmt "\n", \
- __func__, __LINE__ , ## args)
-
-/* Number of times to retry chip detection. Increase this if you are getting
- * "Failed to init camera chip" */
-#define I2C_DETECT_RETRIES 10
-
-struct ovcamchip_regvals {
- unsigned char reg;
- unsigned char val;
-};
-
-struct ovcamchip_ops {
- int (*init)(struct i2c_client *);
- int (*free)(struct i2c_client *);
- int (*command)(struct i2c_client *, unsigned int, void *);
-};
-
-struct ovcamchip {
- struct v4l2_subdev sd;
- struct ovcamchip_ops *sops;
- void *spriv; /* Private data for OV7x10.c etc... */
- int subtype; /* = SEN_OV7610 etc... */
- int mono; /* Monochrome chip? (invalid until init) */
- int initialized; /* OVCAMCHIP_CMD_INITIALIZE was successful */
-};
-
-static inline struct ovcamchip *to_ovcamchip(struct v4l2_subdev *sd)
-{
- return container_of(sd, struct ovcamchip, sd);
-}
-
-extern struct ovcamchip_ops ov6x20_ops;
-extern struct ovcamchip_ops ov6x30_ops;
-extern struct ovcamchip_ops ov7x10_ops;
-extern struct ovcamchip_ops ov7x20_ops;
-extern struct ovcamchip_ops ov76be_ops;
-
-/* --------------------------------- */
-/* I2C I/O */
-/* --------------------------------- */
-
-static inline int ov_read(struct i2c_client *c, unsigned char reg,
- unsigned char *value)
-{
- int rc;
-
- rc = i2c_smbus_read_byte_data(c, reg);
- *value = (unsigned char) rc;
- return rc;
-}
-
-static inline int ov_write(struct i2c_client *c, unsigned char reg,
- unsigned char value )
-{
- return i2c_smbus_write_byte_data(c, reg, value);
-}
-
-/* --------------------------------- */
-/* FUNCTION PROTOTYPES */
-/* --------------------------------- */
-
-/* Functions in ovcamchip_core.c */
-
-extern int ov_write_regvals(struct i2c_client *c,
- struct ovcamchip_regvals *rvals);
-
-extern int ov_write_mask(struct i2c_client *c, unsigned char reg,
- unsigned char value, unsigned char mask);
-
-#endif
diff --git a/drivers/media/video/pvrusb2/pvrusb2-ioread.c b/drivers/media/video/pvrusb2/pvrusb2-ioread.c
index b4824782d85..bba6115c9ae 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-ioread.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-ioread.c
@@ -223,7 +223,10 @@ int pvr2_ioread_setup(struct pvr2_ioread *cp,struct pvr2_stream *sp)
" pvr2_ioread_setup (setup) id=%p",cp);
pvr2_stream_kill(sp);
ret = pvr2_stream_set_buffer_count(sp,BUFFER_COUNT);
- if (ret < 0) return ret;
+ if (ret < 0) {
+ mutex_unlock(&cp->mutex);
+ return ret;
+ }
for (idx = 0; idx < BUFFER_COUNT; idx++) {
bp = pvr2_stream_get_buffer(sp,idx);
pvr2_buffer_set_buffer(bp,
diff --git a/drivers/media/video/pxa_camera.c b/drivers/media/video/pxa_camera.c
index fb242f6cfb1..9de7d59916b 100644
--- a/drivers/media/video/pxa_camera.c
+++ b/drivers/media/video/pxa_camera.c
@@ -276,7 +276,7 @@ static void free_buffer(struct videobuf_queue *vq, struct pxa_buffer *buf)
* longer in STATE_QUEUED or STATE_ACTIVE
*/
videobuf_waiton(&buf->vb, 0, 0);
- videobuf_dma_unmap(vq, dma);
+ videobuf_dma_unmap(vq->dev, dma);
videobuf_dma_free(dma);
for (i = 0; i < ARRAY_SIZE(buf->dmas); i++) {
@@ -1284,7 +1284,7 @@ static int pxa_camera_get_formats(struct soc_camera_device *icd, unsigned int id
}
switch (code) {
- case V4L2_MBUS_FMT_YUYV8_2X8_BE:
+ case V4L2_MBUS_FMT_UYVY8_2X8:
formats++;
if (xlate) {
xlate->host_fmt = &pxa_camera_formats[0];
@@ -1293,9 +1293,9 @@ static int pxa_camera_get_formats(struct soc_camera_device *icd, unsigned int id
dev_dbg(dev, "Providing format %s using code %d\n",
pxa_camera_formats[0].name, code);
}
- case V4L2_MBUS_FMT_YVYU8_2X8_BE:
- case V4L2_MBUS_FMT_YUYV8_2X8_LE:
- case V4L2_MBUS_FMT_YVYU8_2X8_LE:
+ case V4L2_MBUS_FMT_VYUY8_2X8:
+ case V4L2_MBUS_FMT_YUYV8_2X8:
+ case V4L2_MBUS_FMT_YVYU8_2X8:
case V4L2_MBUS_FMT_RGB565_2X8_LE:
case V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE:
if (xlate)
diff --git a/drivers/media/video/rj54n1cb0c.c b/drivers/media/video/rj54n1cb0c.c
index 47fd207ba3b..ce78fff2342 100644
--- a/drivers/media/video/rj54n1cb0c.c
+++ b/drivers/media/video/rj54n1cb0c.c
@@ -1,5 +1,5 @@
/*
- * Driver for RJ54N1CB0C CMOS Image Sensor from Micron
+ * Driver for RJ54N1CB0C CMOS Image Sensor from Sharp
*
* Copyright (C) 2009, Guennadi Liakhovetski <g.liakhovetski@gmx.de>
*
@@ -127,8 +127,8 @@ static const struct rj54n1_datafmt *rj54n1_find_datafmt(
}
static const struct rj54n1_datafmt rj54n1_colour_fmts[] = {
- {V4L2_MBUS_FMT_YUYV8_2X8_LE, V4L2_COLORSPACE_JPEG},
- {V4L2_MBUS_FMT_YVYU8_2X8_LE, V4L2_COLORSPACE_JPEG},
+ {V4L2_MBUS_FMT_YUYV8_2X8, V4L2_COLORSPACE_JPEG},
+ {V4L2_MBUS_FMT_YVYU8_2X8, V4L2_COLORSPACE_JPEG},
{V4L2_MBUS_FMT_RGB565_2X8_LE, V4L2_COLORSPACE_SRGB},
{V4L2_MBUS_FMT_RGB565_2X8_BE, V4L2_COLORSPACE_SRGB},
{V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE, V4L2_COLORSPACE_SRGB},
@@ -1046,12 +1046,12 @@ static int rj54n1_s_fmt(struct v4l2_subdev *sd,
/* RA_SEL_UL is only relevant for raw modes, ignored otherwise. */
switch (mf->code) {
- case V4L2_MBUS_FMT_YUYV8_2X8_LE:
+ case V4L2_MBUS_FMT_YUYV8_2X8:
ret = reg_write(client, RJ54N1_OUT_SEL, 0);
if (!ret)
ret = reg_set(client, RJ54N1_BYTE_SWAP, 8, 8);
break;
- case V4L2_MBUS_FMT_YVYU8_2X8_LE:
+ case V4L2_MBUS_FMT_YVYU8_2X8:
ret = reg_write(client, RJ54N1_OUT_SEL, 0);
if (!ret)
ret = reg_set(client, RJ54N1_BYTE_SWAP, 0, 8);
diff --git a/drivers/media/video/s2255drv.c b/drivers/media/video/s2255drv.c
index 3c7a79f3812..8ec7c9a45a1 100644
--- a/drivers/media/video/s2255drv.c
+++ b/drivers/media/video/s2255drv.c
@@ -191,7 +191,6 @@ struct s2255_bufferi {
struct s2255_dmaqueue {
struct list_head active;
struct s2255_dev *dev;
- int channel;
};
/* for firmware loading, fw_state */
@@ -226,51 +225,60 @@ struct s2255_pipeinfo {
};
struct s2255_fmt; /*forward declaration */
+struct s2255_dev;
+
+struct s2255_channel {
+ struct video_device vdev;
+ int resources;
+ struct s2255_dmaqueue vidq;
+ struct s2255_bufferi buffer;
+ struct s2255_mode mode;
+ /* jpeg compression */
+ struct v4l2_jpegcompression jc;
+ /* capture parameters (for high quality mode full size) */
+ struct v4l2_captureparm cap_parm;
+ int cur_frame;
+ int last_frame;
+
+ int b_acquire;
+ /* allocated image size */
+ unsigned long req_image_size;
+ /* received packet size */
+ unsigned long pkt_size;
+ int bad_payload;
+ unsigned long frame_count;
+ /* if JPEG image */
+ int jpg_size;
+ /* if channel configured to default state */
+ int configured;
+ wait_queue_head_t wait_setmode;
+ int setmode_ready;
+ /* video status items */
+ int vidstatus;
+ wait_queue_head_t wait_vidstatus;
+ int vidstatus_ready;
+ unsigned int width;
+ unsigned int height;
+ const struct s2255_fmt *fmt;
+ int idx; /* channel number on device, 0-3 */
+};
+
struct s2255_dev {
- struct video_device vdev[MAX_CHANNELS];
+ struct s2255_channel channel[MAX_CHANNELS];
struct v4l2_device v4l2_dev;
- atomic_t channels; /* number of channels registered */
+ atomic_t num_channels;
int frames;
struct mutex lock;
struct mutex open_lock;
- int resources[MAX_CHANNELS];
struct usb_device *udev;
struct usb_interface *interface;
u8 read_endpoint;
-
- struct s2255_dmaqueue vidq[MAX_CHANNELS];
struct timer_list timer;
struct s2255_fw *fw_data;
struct s2255_pipeinfo pipe;
- struct s2255_bufferi buffer[MAX_CHANNELS];
- struct s2255_mode mode[MAX_CHANNELS];
- /* jpeg compression */
- struct v4l2_jpegcompression jc[MAX_CHANNELS];
- /* capture parameters (for high quality mode full size) */
- struct v4l2_captureparm cap_parm[MAX_CHANNELS];
- const struct s2255_fmt *cur_fmt[MAX_CHANNELS];
- int cur_frame[MAX_CHANNELS];
- int last_frame[MAX_CHANNELS];
u32 cc; /* current channel */
- int b_acquire[MAX_CHANNELS];
- /* allocated image size */
- unsigned long req_image_size[MAX_CHANNELS];
- /* received packet size */
- unsigned long pkt_size[MAX_CHANNELS];
- int bad_payload[MAX_CHANNELS];
- unsigned long frame_count[MAX_CHANNELS];
int frame_ready;
- /* if JPEG image */
- int jpg_size[MAX_CHANNELS];
- /* if channel configured to default state */
- int chn_configured[MAX_CHANNELS];
- wait_queue_head_t wait_setmode[MAX_CHANNELS];
- int setmode_ready[MAX_CHANNELS];
- /* video status items */
- int vidstatus[MAX_CHANNELS];
- wait_queue_head_t wait_vidstatus[MAX_CHANNELS];
- int vidstatus_ready[MAX_CHANNELS];
int chn_ready;
spinlock_t slock;
/* dsp firmware version (f2255usb.bin) */
@@ -298,16 +306,10 @@ struct s2255_buffer {
struct s2255_fh {
struct s2255_dev *dev;
- const struct s2255_fmt *fmt;
- unsigned int width;
- unsigned int height;
struct videobuf_queue vb_vidq;
enum v4l2_buf_type type;
- int channel;
- /* mode below is the desired mode.
- mode in s2255_dev is the current mode that was last set */
- struct s2255_mode mode;
- int resources[MAX_CHANNELS];
+ struct s2255_channel *channel;
+ int resources;
};
/* current cypress EEPROM firmware version */
@@ -360,12 +362,11 @@ static int *s2255_debug = &debug;
static int s2255_start_readpipe(struct s2255_dev *dev);
static void s2255_stop_readpipe(struct s2255_dev *dev);
-static int s2255_start_acquire(struct s2255_dev *dev, unsigned long chn);
-static int s2255_stop_acquire(struct s2255_dev *dev, unsigned long chn);
-static void s2255_fillbuff(struct s2255_dev *dev, struct s2255_buffer *buf,
- int chn, int jpgsize);
-static int s2255_set_mode(struct s2255_dev *dev, unsigned long chn,
- struct s2255_mode *mode);
+static int s2255_start_acquire(struct s2255_channel *channel);
+static int s2255_stop_acquire(struct s2255_channel *channel);
+static void s2255_fillbuff(struct s2255_channel *chn, struct s2255_buffer *buf,
+ int jpgsize);
+static int s2255_set_mode(struct s2255_channel *chan, struct s2255_mode *mode);
static int s2255_board_shutdown(struct s2255_dev *dev);
static void s2255_fwload_start(struct s2255_dev *dev, int reset);
static void s2255_destroy(struct s2255_dev *dev);
@@ -577,10 +578,11 @@ static void s2255_fwchunk_complete(struct urb *urb)
}
-static int s2255_got_frame(struct s2255_dev *dev, int chn, int jpgsize)
+static int s2255_got_frame(struct s2255_channel *channel, int jpgsize)
{
- struct s2255_dmaqueue *dma_q = &dev->vidq[chn];
+ struct s2255_dmaqueue *dma_q = &channel->vidq;
struct s2255_buffer *buf;
+ struct s2255_dev *dev = to_s2255_dev(channel->vdev.v4l2_dev);
unsigned long flags = 0;
int rc = 0;
spin_lock_irqsave(&dev->slock, flags);
@@ -593,7 +595,7 @@ static int s2255_got_frame(struct s2255_dev *dev, int chn, int jpgsize)
struct s2255_buffer, vb.queue);
list_del(&buf->vb.queue);
do_gettimeofday(&buf->vb.ts);
- s2255_fillbuff(dev, buf, dma_q->channel, jpgsize);
+ s2255_fillbuff(channel, buf, jpgsize);
wake_up(&buf->vb.done);
dprintk(2, "%s: [buf/i] [%p/%d]\n", __func__, buf, buf->vb.i);
unlock:
@@ -621,8 +623,8 @@ static const struct s2255_fmt *format_by_fourcc(int fourcc)
* http://v4l.videotechnology.com/
*
*/
-static void s2255_fillbuff(struct s2255_dev *dev, struct s2255_buffer *buf,
- int chn, int jpgsize)
+static void s2255_fillbuff(struct s2255_channel *channel,
+ struct s2255_buffer *buf, int jpgsize)
{
int pos = 0;
struct timeval ts;
@@ -633,12 +635,11 @@ static void s2255_fillbuff(struct s2255_dev *dev, struct s2255_buffer *buf,
if (!vbuf)
return;
-
- last_frame = dev->last_frame[chn];
+ last_frame = channel->last_frame;
if (last_frame != -1) {
- frm = &dev->buffer[chn].frame[last_frame];
+ frm = &channel->buffer.frame[last_frame];
tmpbuf =
- (const char *)dev->buffer[chn].frame[last_frame].lpvbits;
+ (const char *)channel->buffer.frame[last_frame].lpvbits;
switch (buf->fmt->fourcc) {
case V4L2_PIX_FMT_YUYV:
case V4L2_PIX_FMT_UYVY:
@@ -661,7 +662,7 @@ static void s2255_fillbuff(struct s2255_dev *dev, struct s2255_buffer *buf,
default:
printk(KERN_DEBUG "s2255: unknown format?\n");
}
- dev->last_frame[chn] = -1;
+ channel->last_frame = -1;
} else {
printk(KERN_ERR "s2255: =======no frame\n");
return;
@@ -671,7 +672,7 @@ static void s2255_fillbuff(struct s2255_dev *dev, struct s2255_buffer *buf,
(unsigned long)vbuf, pos);
/* tell v4l buffer was filled */
- buf->vb.field_count = dev->frame_count[chn] * 2;
+ buf->vb.field_count = channel->frame_count * 2;
do_gettimeofday(&ts);
buf->vb.ts = ts;
buf->vb.state = VIDEOBUF_DONE;
@@ -686,8 +687,8 @@ static int buffer_setup(struct videobuf_queue *vq, unsigned int *count,
unsigned int *size)
{
struct s2255_fh *fh = vq->priv_data;
-
- *size = fh->width * fh->height * (fh->fmt->depth >> 3);
+ struct s2255_channel *channel = fh->channel;
+ *size = channel->width * channel->height * (channel->fmt->depth >> 3);
if (0 == *count)
*count = S2255_DEF_BUFS;
@@ -710,30 +711,31 @@ static int buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb,
enum v4l2_field field)
{
struct s2255_fh *fh = vq->priv_data;
+ struct s2255_channel *channel = fh->channel;
struct s2255_buffer *buf = container_of(vb, struct s2255_buffer, vb);
int rc;
+ int w = channel->width;
+ int h = channel->height;
dprintk(4, "%s, field=%d\n", __func__, field);
- if (fh->fmt == NULL)
+ if (channel->fmt == NULL)
return -EINVAL;
- if ((fh->width < norm_minw(&fh->dev->vdev[fh->channel])) ||
- (fh->width > norm_maxw(&fh->dev->vdev[fh->channel])) ||
- (fh->height < norm_minh(&fh->dev->vdev[fh->channel])) ||
- (fh->height > norm_maxh(&fh->dev->vdev[fh->channel]))) {
+ if ((w < norm_minw(&channel->vdev)) ||
+ (w > norm_maxw(&channel->vdev)) ||
+ (h < norm_minh(&channel->vdev)) ||
+ (h > norm_maxh(&channel->vdev))) {
dprintk(4, "invalid buffer prepare\n");
return -EINVAL;
}
-
- buf->vb.size = fh->width * fh->height * (fh->fmt->depth >> 3);
-
+ buf->vb.size = w * h * (channel->fmt->depth >> 3);
if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size) {
dprintk(4, "invalid buffer prepare\n");
return -EINVAL;
}
- buf->fmt = fh->fmt;
- buf->vb.width = fh->width;
- buf->vb.height = fh->height;
+ buf->fmt = channel->fmt;
+ buf->vb.width = w;
+ buf->vb.height = h;
buf->vb.field = field;
if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
@@ -753,8 +755,8 @@ static void buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
{
struct s2255_buffer *buf = container_of(vb, struct s2255_buffer, vb);
struct s2255_fh *fh = vq->priv_data;
- struct s2255_dev *dev = fh->dev;
- struct s2255_dmaqueue *vidq = &dev->vidq[fh->channel];
+ struct s2255_channel *channel = fh->channel;
+ struct s2255_dmaqueue *vidq = &channel->vidq;
dprintk(1, "%s\n", __func__);
buf->vb.state = VIDEOBUF_QUEUED;
list_add_tail(&buf->vb.queue, &vidq->active);
@@ -765,7 +767,7 @@ static void buffer_release(struct videobuf_queue *vq,
{
struct s2255_buffer *buf = container_of(vb, struct s2255_buffer, vb);
struct s2255_fh *fh = vq->priv_data;
- dprintk(4, "%s %d\n", __func__, fh->channel);
+ dprintk(4, "%s %d\n", __func__, fh->channel->idx);
free_buffer(vq, buf);
}
@@ -777,39 +779,43 @@ static struct videobuf_queue_ops s2255_video_qops = {
};
-static int res_get(struct s2255_dev *dev, struct s2255_fh *fh)
+static int res_get(struct s2255_fh *fh)
{
+ struct s2255_dev *dev = fh->dev;
/* is it free? */
+ struct s2255_channel *channel = fh->channel;
mutex_lock(&dev->lock);
- if (dev->resources[fh->channel]) {
+ if (channel->resources) {
/* no, someone else uses it */
mutex_unlock(&dev->lock);
return 0;
}
/* it's free, grab it */
- dev->resources[fh->channel] = 1;
- fh->resources[fh->channel] = 1;
+ channel->resources = 1;
+ fh->resources = 1;
dprintk(1, "s2255: res: get\n");
mutex_unlock(&dev->lock);
return 1;
}
-static int res_locked(struct s2255_dev *dev, struct s2255_fh *fh)
+static int res_locked(struct s2255_fh *fh)
{
- return dev->resources[fh->channel];
+ return fh->channel->resources;
}
static int res_check(struct s2255_fh *fh)
{
- return fh->resources[fh->channel];
+ return fh->resources;
}
-static void res_free(struct s2255_dev *dev, struct s2255_fh *fh)
+static void res_free(struct s2255_fh *fh)
{
+ struct s2255_channel *channel = fh->channel;
+ struct s2255_dev *dev = fh->dev;
mutex_lock(&dev->lock);
- dev->resources[fh->channel] = 0;
- fh->resources[fh->channel] = 0;
+ channel->resources = 0;
+ fh->resources = 0;
mutex_unlock(&dev->lock);
dprintk(1, "res: put\n");
}
@@ -869,12 +875,13 @@ static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
struct s2255_fh *fh = priv;
+ struct s2255_channel *channel = fh->channel;
- f->fmt.pix.width = fh->width;
- f->fmt.pix.height = fh->height;
+ f->fmt.pix.width = channel->width;
+ f->fmt.pix.height = channel->height;
f->fmt.pix.field = fh->vb_vidq.field;
- f->fmt.pix.pixelformat = fh->fmt->fourcc;
- f->fmt.pix.bytesperline = f->fmt.pix.width * (fh->fmt->depth >> 3);
+ f->fmt.pix.pixelformat = channel->fmt->fourcc;
+ f->fmt.pix.bytesperline = f->fmt.pix.width * (channel->fmt->depth >> 3);
f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline;
return 0;
}
@@ -886,11 +893,10 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
enum v4l2_field field;
int b_any_field = 0;
struct s2255_fh *fh = priv;
- struct s2255_dev *dev = fh->dev;
+ struct s2255_channel *channel = fh->channel;
int is_ntsc;
-
is_ntsc =
- (dev->vdev[fh->channel].current_norm & V4L2_STD_NTSC) ? 1 : 0;
+ (channel->vdev.current_norm & V4L2_STD_NTSC) ? 1 : 0;
fmt = format_by_fourcc(f->fmt.pix.pixelformat);
@@ -982,8 +988,10 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
struct s2255_fh *fh = priv;
+ struct s2255_channel *channel = fh->channel;
const struct s2255_fmt *fmt;
struct videobuf_queue *q = &fh->vb_vidq;
+ struct s2255_mode mode;
int ret;
int norm;
@@ -1005,54 +1013,61 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
goto out_s_fmt;
}
- if (res_locked(fh->dev, fh)) {
+ if (res_locked(fh)) {
dprintk(1, "%s: channel busy\n", __func__);
ret = -EBUSY;
goto out_s_fmt;
}
-
- fh->fmt = fmt;
- fh->width = f->fmt.pix.width;
- fh->height = f->fmt.pix.height;
+ mode = channel->mode;
+ channel->fmt = fmt;
+ channel->width = f->fmt.pix.width;
+ channel->height = f->fmt.pix.height;
fh->vb_vidq.field = f->fmt.pix.field;
fh->type = f->type;
- norm = norm_minw(&fh->dev->vdev[fh->channel]);
- if (fh->width > norm_minw(&fh->dev->vdev[fh->channel])) {
- if (fh->height > norm_minh(&fh->dev->vdev[fh->channel])) {
- if (fh->dev->cap_parm[fh->channel].capturemode &
+ norm = norm_minw(&channel->vdev);
+ if (channel->width > norm_minw(&channel->vdev)) {
+ if (channel->height > norm_minh(&channel->vdev)) {
+ if (channel->cap_parm.capturemode &
V4L2_MODE_HIGHQUALITY)
- fh->mode.scale = SCALE_4CIFSI;
+ mode.scale = SCALE_4CIFSI;
else
- fh->mode.scale = SCALE_4CIFS;
+ mode.scale = SCALE_4CIFS;
} else
- fh->mode.scale = SCALE_2CIFS;
+ mode.scale = SCALE_2CIFS;
} else {
- fh->mode.scale = SCALE_1CIFS;
+ mode.scale = SCALE_1CIFS;
}
-
/* color mode */
- switch (fh->fmt->fourcc) {
+ switch (channel->fmt->fourcc) {
case V4L2_PIX_FMT_GREY:
- fh->mode.color &= ~MASK_COLOR;
- fh->mode.color |= COLOR_Y8;
+ mode.color &= ~MASK_COLOR;
+ mode.color |= COLOR_Y8;
break;
case V4L2_PIX_FMT_JPEG:
- fh->mode.color &= ~MASK_COLOR;
- fh->mode.color |= COLOR_JPG;
- fh->mode.color |= (fh->dev->jc[fh->channel].quality << 8);
+ mode.color &= ~MASK_COLOR;
+ mode.color |= COLOR_JPG;
+ mode.color |= (channel->jc.quality << 8);
break;
case V4L2_PIX_FMT_YUV422P:
- fh->mode.color &= ~MASK_COLOR;
- fh->mode.color |= COLOR_YUVPL;
+ mode.color &= ~MASK_COLOR;
+ mode.color |= COLOR_YUVPL;
break;
case V4L2_PIX_FMT_YUYV:
case V4L2_PIX_FMT_UYVY:
default:
- fh->mode.color &= ~MASK_COLOR;
- fh->mode.color |= COLOR_YUVPK;
+ mode.color &= ~MASK_COLOR;
+ mode.color |= COLOR_YUVPK;
break;
}
+ if ((mode.color & MASK_COLOR) != (channel->mode.color & MASK_COLOR))
+ mode.restart = 1;
+ else if (mode.scale != channel->mode.scale)
+ mode.restart = 1;
+ else if (mode.format != channel->mode.format)
+ mode.restart = 1;
+ channel->mode = mode;
+ (void) s2255_set_mode(channel, &mode);
ret = 0;
out_s_fmt:
mutex_unlock(&q->vb_lock);
@@ -1197,26 +1212,27 @@ static void s2255_print_cfg(struct s2255_dev *sdev, struct s2255_mode *mode)
* When the restart parameter is set, we sleep for ONE frame to allow the
* DSP time to get the new frame
*/
-static int s2255_set_mode(struct s2255_dev *dev, unsigned long chn,
+static int s2255_set_mode(struct s2255_channel *channel,
struct s2255_mode *mode)
{
int res;
__le32 *buffer;
unsigned long chn_rev;
+ struct s2255_dev *dev = to_s2255_dev(channel->vdev.v4l2_dev);
mutex_lock(&dev->lock);
- chn_rev = G_chnmap[chn];
- dprintk(3, "%s channel %lu\n", __func__, chn);
+ chn_rev = G_chnmap[channel->idx];
+ dprintk(3, "%s channel: %d\n", __func__, channel->idx);
/* if JPEG, set the quality */
if ((mode->color & MASK_COLOR) == COLOR_JPG) {
mode->color &= ~MASK_COLOR;
mode->color |= COLOR_JPG;
mode->color &= ~MASK_JPG_QUALITY;
- mode->color |= (dev->jc[chn].quality << 8);
+ mode->color |= (channel->jc.quality << 8);
}
/* save the mode */
- dev->mode[chn] = *mode;
- dev->req_image_size[chn] = get_transfer_size(mode);
- dprintk(1, "%s: reqsize %ld\n", __func__, dev->req_image_size[chn]);
+ channel->mode = *mode;
+ channel->req_image_size = get_transfer_size(mode);
+ dprintk(1, "%s: reqsize %ld\n", __func__, channel->req_image_size);
buffer = kzalloc(512, GFP_KERNEL);
if (buffer == NULL) {
dev_err(&dev->udev->dev, "out of mem\n");
@@ -1227,38 +1243,38 @@ static int s2255_set_mode(struct s2255_dev *dev, unsigned long chn,
buffer[0] = IN_DATA_TOKEN;
buffer[1] = (__le32) cpu_to_le32(chn_rev);
buffer[2] = CMD_SET_MODE;
- memcpy(&buffer[3], &dev->mode[chn], sizeof(struct s2255_mode));
- dev->setmode_ready[chn] = 0;
+ memcpy(&buffer[3], &channel->mode, sizeof(struct s2255_mode));
+ channel->setmode_ready = 0;
res = s2255_write_config(dev->udev, (unsigned char *)buffer, 512);
if (debug)
s2255_print_cfg(dev, mode);
kfree(buffer);
/* wait at least 3 frames before continuing */
if (mode->restart) {
- wait_event_timeout(dev->wait_setmode[chn],
- (dev->setmode_ready[chn] != 0),
+ wait_event_timeout(channel->wait_setmode,
+ (channel->setmode_ready != 0),
msecs_to_jiffies(S2255_SETMODE_TIMEOUT));
- if (dev->setmode_ready[chn] != 1) {
+ if (channel->setmode_ready != 1) {
printk(KERN_DEBUG "s2255: no set mode response\n");
res = -EFAULT;
}
}
/* clear the restart flag */
- dev->mode[chn].restart = 0;
+ channel->mode.restart = 0;
mutex_unlock(&dev->lock);
- dprintk(1, "%s chn %lu, result: %d\n", __func__, chn, res);
+ dprintk(1, "%s chn %d, result: %d\n", __func__, channel->idx, res);
return res;
}
-static int s2255_cmd_status(struct s2255_dev *dev, unsigned long chn,
- u32 *pstatus)
+static int s2255_cmd_status(struct s2255_channel *channel, u32 *pstatus)
{
int res;
__le32 *buffer;
u32 chn_rev;
+ struct s2255_dev *dev = to_s2255_dev(channel->vdev.v4l2_dev);
mutex_lock(&dev->lock);
- chn_rev = G_chnmap[chn];
- dprintk(4, "%s chan %lu\n", __func__, chn);
+ chn_rev = G_chnmap[channel->idx];
+ dprintk(4, "%s chan %d\n", __func__, channel->idx);
buffer = kzalloc(512, GFP_KERNEL);
if (buffer == NULL) {
dev_err(&dev->udev->dev, "out of mem\n");
@@ -1270,17 +1286,17 @@ static int s2255_cmd_status(struct s2255_dev *dev, unsigned long chn,
buffer[1] = (__le32) cpu_to_le32(chn_rev);
buffer[2] = CMD_STATUS;
*pstatus = 0;
- dev->vidstatus_ready[chn] = 0;
+ channel->vidstatus_ready = 0;
res = s2255_write_config(dev->udev, (unsigned char *)buffer, 512);
kfree(buffer);
- wait_event_timeout(dev->wait_vidstatus[chn],
- (dev->vidstatus_ready[chn] != 0),
+ wait_event_timeout(channel->wait_vidstatus,
+ (channel->vidstatus_ready != 0),
msecs_to_jiffies(S2255_VIDSTATUS_TIMEOUT));
- if (dev->vidstatus_ready[chn] != 1) {
+ if (channel->vidstatus_ready != 1) {
printk(KERN_DEBUG "s2255: no vidstatus response\n");
res = -EFAULT;
}
- *pstatus = dev->vidstatus[chn];
+ *pstatus = channel->vidstatus;
dprintk(4, "%s, vid status %d\n", __func__, *pstatus);
mutex_unlock(&dev->lock);
return res;
@@ -1291,9 +1307,7 @@ static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
int res;
struct s2255_fh *fh = priv;
struct s2255_dev *dev = fh->dev;
- struct s2255_mode *new_mode;
- struct s2255_mode *old_mode;
- int chn;
+ struct s2255_channel *channel = fh->channel;
int j;
dprintk(4, "%s\n", __func__);
if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
@@ -1305,51 +1319,32 @@ static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
return -EINVAL;
}
- if (!res_get(dev, fh)) {
+ if (!res_get(fh)) {
s2255_dev_err(&dev->udev->dev, "stream busy\n");
return -EBUSY;
}
-
- /* send a set mode command everytime with restart.
- in case we switch resolutions or other parameters */
- chn = fh->channel;
- new_mode = &fh->mode;
- old_mode = &fh->dev->mode[chn];
-
- if ((new_mode->color & MASK_COLOR) != (old_mode->color & MASK_COLOR))
- new_mode->restart = 1;
- else if (new_mode->scale != old_mode->scale)
- new_mode->restart = 1;
- else if (new_mode->format != old_mode->format)
- new_mode->restart = 1;
-
- s2255_set_mode(dev, chn, new_mode);
- new_mode->restart = 0;
- *old_mode = *new_mode;
- dev->cur_fmt[chn] = fh->fmt;
- dev->last_frame[chn] = -1;
- dev->bad_payload[chn] = 0;
- dev->cur_frame[chn] = 0;
- dev->frame_count[chn] = 0;
+ channel->last_frame = -1;
+ channel->bad_payload = 0;
+ channel->cur_frame = 0;
+ channel->frame_count = 0;
for (j = 0; j < SYS_FRAMES; j++) {
- dev->buffer[chn].frame[j].ulState = S2255_READ_IDLE;
- dev->buffer[chn].frame[j].cur_size = 0;
+ channel->buffer.frame[j].ulState = S2255_READ_IDLE;
+ channel->buffer.frame[j].cur_size = 0;
}
res = videobuf_streamon(&fh->vb_vidq);
if (res == 0) {
- s2255_start_acquire(dev, chn);
- dev->b_acquire[chn] = 1;
- } else {
- res_free(dev, fh);
- }
+ s2255_start_acquire(channel);
+ channel->b_acquire = 1;
+ } else
+ res_free(fh);
+
return res;
}
static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
{
struct s2255_fh *fh = priv;
- struct s2255_dev *dev = fh->dev;
- dprintk(4, "%s\n, channel: %d", __func__, fh->channel);
+ dprintk(4, "%s\n, channel: %d", __func__, fh->channel->idx);
if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
printk(KERN_ERR "invalid fh type0\n");
return -EINVAL;
@@ -1358,16 +1353,16 @@ static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
printk(KERN_ERR "invalid type i\n");
return -EINVAL;
}
- s2255_stop_acquire(dev, fh->channel);
+ s2255_stop_acquire(fh->channel);
videobuf_streamoff(&fh->vb_vidq);
- res_free(dev, fh);
+ res_free(fh);
return 0;
}
static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *i)
{
struct s2255_fh *fh = priv;
- struct s2255_mode *mode;
+ struct s2255_mode mode;
struct videobuf_queue *q = &fh->vb_vidq;
int ret = 0;
mutex_lock(&q->vb_lock);
@@ -1376,29 +1371,32 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *i)
ret = -EBUSY;
goto out_s_std;
}
- if (res_locked(fh->dev, fh)) {
+ if (res_locked(fh)) {
dprintk(1, "can't change standard after started\n");
ret = -EBUSY;
goto out_s_std;
}
- mode = &fh->mode;
+ mode = fh->channel->mode;
if (*i & V4L2_STD_NTSC) {
dprintk(4, "%s NTSC\n", __func__);
/* if changing format, reset frame decimation/intervals */
- if (mode->format != FORMAT_NTSC) {
- mode->format = FORMAT_NTSC;
- mode->fdec = FDEC_1;
+ if (mode.format != FORMAT_NTSC) {
+ mode.restart = 1;
+ mode.format = FORMAT_NTSC;
+ mode.fdec = FDEC_1;
}
} else if (*i & V4L2_STD_PAL) {
dprintk(4, "%s PAL\n", __func__);
- mode->format = FORMAT_PAL;
- if (mode->format != FORMAT_PAL) {
- mode->format = FORMAT_PAL;
- mode->fdec = FDEC_1;
+ if (mode.format != FORMAT_PAL) {
+ mode.restart = 1;
+ mode.format = FORMAT_PAL;
+ mode.fdec = FDEC_1;
}
} else {
ret = -EINVAL;
}
+ if (mode.restart)
+ s2255_set_mode(fh->channel, &mode);
out_s_std:
mutex_unlock(&q->vb_lock);
return ret;
@@ -1416,6 +1414,7 @@ static int vidioc_enum_input(struct file *file, void *priv,
{
struct s2255_fh *fh = priv;
struct s2255_dev *dev = fh->dev;
+ struct s2255_channel *channel = fh->channel;
u32 status = 0;
if (inp->index != 0)
return -EINVAL;
@@ -1424,7 +1423,7 @@ static int vidioc_enum_input(struct file *file, void *priv,
inp->status = 0;
if (dev->dsp_fw_ver >= S2255_MIN_DSP_STATUS) {
int rc;
- rc = s2255_cmd_status(dev, fh->channel, &status);
+ rc = s2255_cmd_status(fh->channel, &status);
dprintk(4, "s2255_cmd_status rc: %d status %x\n", rc, status);
if (rc == 0)
inp->status = (status & 0x01) ? 0
@@ -1436,7 +1435,7 @@ static int vidioc_enum_input(struct file *file, void *priv,
strlcpy(inp->name, "Composite", sizeof(inp->name));
break;
case 0x2257:
- strlcpy(inp->name, (fh->channel < 2) ? "Composite" : "S-Video",
+ strlcpy(inp->name, (channel->idx < 2) ? "Composite" : "S-Video",
sizeof(inp->name));
break;
}
@@ -1460,6 +1459,7 @@ static int vidioc_queryctrl(struct file *file, void *priv,
struct v4l2_queryctrl *qc)
{
struct s2255_fh *fh = priv;
+ struct s2255_channel *channel = fh->channel;
struct s2255_dev *dev = fh->dev;
switch (qc->id) {
case V4L2_CID_BRIGHTNESS:
@@ -1477,7 +1477,7 @@ static int vidioc_queryctrl(struct file *file, void *priv,
case V4L2_CID_PRIVATE_COLORFILTER:
if (dev->dsp_fw_ver < S2255_MIN_DSP_COLORFILTER)
return -EINVAL;
- if ((dev->pid == 0x2257) && (fh->channel > 1))
+ if ((dev->pid == 0x2257) && (channel->idx > 1))
return -EINVAL;
strlcpy(qc->name, "Color Filter", sizeof(qc->name));
qc->type = V4L2_CTRL_TYPE_MENU;
@@ -1499,25 +1499,26 @@ static int vidioc_g_ctrl(struct file *file, void *priv,
{
struct s2255_fh *fh = priv;
struct s2255_dev *dev = fh->dev;
+ struct s2255_channel *channel = fh->channel;
switch (ctrl->id) {
case V4L2_CID_BRIGHTNESS:
- ctrl->value = fh->mode.bright;
+ ctrl->value = channel->mode.bright;
break;
case V4L2_CID_CONTRAST:
- ctrl->value = fh->mode.contrast;
+ ctrl->value = channel->mode.contrast;
break;
case V4L2_CID_SATURATION:
- ctrl->value = fh->mode.saturation;
+ ctrl->value = channel->mode.saturation;
break;
case V4L2_CID_HUE:
- ctrl->value = fh->mode.hue;
+ ctrl->value = channel->mode.hue;
break;
case V4L2_CID_PRIVATE_COLORFILTER:
if (dev->dsp_fw_ver < S2255_MIN_DSP_COLORFILTER)
return -EINVAL;
- if ((dev->pid == 0x2257) && (fh->channel > 1))
+ if ((dev->pid == 0x2257) && (channel->idx > 1))
return -EINVAL;
- ctrl->value = !((fh->mode.color & MASK_INPUT_TYPE) >> 16);
+ ctrl->value = !((channel->mode.color & MASK_INPUT_TYPE) >> 16);
break;
default:
return -EINVAL;
@@ -1530,41 +1531,42 @@ static int vidioc_s_ctrl(struct file *file, void *priv,
struct v4l2_control *ctrl)
{
struct s2255_fh *fh = priv;
- struct s2255_dev *dev = fh->dev;
- struct s2255_mode *mode;
- mode = &fh->mode;
+ struct s2255_channel *channel = fh->channel;
+ struct s2255_dev *dev = to_s2255_dev(channel->vdev.v4l2_dev);
+ struct s2255_mode mode;
+ mode = channel->mode;
dprintk(4, "%s\n", __func__);
/* update the mode to the corresponding value */
switch (ctrl->id) {
case V4L2_CID_BRIGHTNESS:
- mode->bright = ctrl->value;
+ mode.bright = ctrl->value;
break;
case V4L2_CID_CONTRAST:
- mode->contrast = ctrl->value;
+ mode.contrast = ctrl->value;
break;
case V4L2_CID_HUE:
- mode->hue = ctrl->value;
+ mode.hue = ctrl->value;
break;
case V4L2_CID_SATURATION:
- mode->saturation = ctrl->value;
+ mode.saturation = ctrl->value;
break;
case V4L2_CID_PRIVATE_COLORFILTER:
if (dev->dsp_fw_ver < S2255_MIN_DSP_COLORFILTER)
return -EINVAL;
- if ((dev->pid == 0x2257) && (fh->channel > 1))
+ if ((dev->pid == 0x2257) && (channel->idx > 1))
return -EINVAL;
- mode->color &= ~MASK_INPUT_TYPE;
- mode->color |= ((ctrl->value ? 0 : 1) << 16);
+ mode.color &= ~MASK_INPUT_TYPE;
+ mode.color |= ((ctrl->value ? 0 : 1) << 16);
break;
default:
return -EINVAL;
}
- mode->restart = 0;
+ mode.restart = 0;
/* set mode here. Note: stream does not need restarted.
some V4L programs restart stream unnecessarily
after a s_crtl.
*/
- s2255_set_mode(dev, fh->channel, mode);
+ s2255_set_mode(fh->channel, &mode);
return 0;
}
@@ -1572,8 +1574,8 @@ static int vidioc_g_jpegcomp(struct file *file, void *priv,
struct v4l2_jpegcompression *jc)
{
struct s2255_fh *fh = priv;
- struct s2255_dev *dev = fh->dev;
- *jc = dev->jc[fh->channel];
+ struct s2255_channel *channel = fh->channel;
+ *jc = channel->jc;
dprintk(2, "%s: quality %d\n", __func__, jc->quality);
return 0;
}
@@ -1582,10 +1584,10 @@ static int vidioc_s_jpegcomp(struct file *file, void *priv,
struct v4l2_jpegcompression *jc)
{
struct s2255_fh *fh = priv;
- struct s2255_dev *dev = fh->dev;
+ struct s2255_channel *channel = fh->channel;
if (jc->quality < 0 || jc->quality > 100)
return -EINVAL;
- dev->jc[fh->channel].quality = jc->quality;
+ channel->jc.quality = jc->quality;
dprintk(2, "%s: quality %d\n", __func__, jc->quality);
return 0;
}
@@ -1594,17 +1596,17 @@ static int vidioc_g_parm(struct file *file, void *priv,
struct v4l2_streamparm *sp)
{
struct s2255_fh *fh = priv;
- struct s2255_dev *dev = fh->dev;
__u32 def_num, def_dem;
+ struct s2255_channel *channel = fh->channel;
if (sp->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
return -EINVAL;
memset(sp, 0, sizeof(struct v4l2_streamparm));
sp->parm.capture.capability = V4L2_CAP_TIMEPERFRAME;
- sp->parm.capture.capturemode = dev->cap_parm[fh->channel].capturemode;
- def_num = (fh->mode.format == FORMAT_NTSC) ? 1001 : 1000;
- def_dem = (fh->mode.format == FORMAT_NTSC) ? 30000 : 25000;
+ sp->parm.capture.capturemode = channel->cap_parm.capturemode;
+ def_num = (channel->mode.format == FORMAT_NTSC) ? 1001 : 1000;
+ def_dem = (channel->mode.format == FORMAT_NTSC) ? 30000 : 25000;
sp->parm.capture.timeperframe.denominator = def_dem;
- switch (fh->mode.fdec) {
+ switch (channel->mode.fdec) {
default:
case FDEC_1:
sp->parm.capture.timeperframe.numerator = def_num;
@@ -1630,17 +1632,19 @@ static int vidioc_s_parm(struct file *file, void *priv,
struct v4l2_streamparm *sp)
{
struct s2255_fh *fh = priv;
- struct s2255_dev *dev = fh->dev;
+ struct s2255_channel *channel = fh->channel;
+ struct s2255_mode mode;
int fdec = FDEC_1;
__u32 def_num, def_dem;
if (sp->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
return -EINVAL;
+ mode = channel->mode;
/* high quality capture mode requires a stream restart */
- if (dev->cap_parm[fh->channel].capturemode
- != sp->parm.capture.capturemode && res_locked(fh->dev, fh))
+ if (channel->cap_parm.capturemode
+ != sp->parm.capture.capturemode && res_locked(fh))
return -EBUSY;
- def_num = (fh->mode.format == FORMAT_NTSC) ? 1001 : 1000;
- def_dem = (fh->mode.format == FORMAT_NTSC) ? 30000 : 25000;
+ def_num = (mode.format == FORMAT_NTSC) ? 1001 : 1000;
+ def_dem = (mode.format == FORMAT_NTSC) ? 30000 : 25000;
if (def_dem != sp->parm.capture.timeperframe.denominator)
sp->parm.capture.timeperframe.numerator = def_num;
else if (sp->parm.capture.timeperframe.numerator <= def_num)
@@ -1655,9 +1659,9 @@ static int vidioc_s_parm(struct file *file, void *priv,
sp->parm.capture.timeperframe.numerator = def_num * 5;
fdec = FDEC_5;
}
- fh->mode.fdec = fdec;
+ mode.fdec = fdec;
sp->parm.capture.timeperframe.denominator = def_dem;
- s2255_set_mode(dev, fh->channel, &fh->mode);
+ s2255_set_mode(channel, &mode);
dprintk(4, "%s capture mode, %d timeperframe %d/%d, fdec %d\n",
__func__,
sp->parm.capture.capturemode,
@@ -1707,24 +1711,13 @@ static int vidioc_enum_frameintervals(struct file *file, void *priv,
static int s2255_open(struct file *file)
{
struct video_device *vdev = video_devdata(file);
- struct s2255_dev *dev = video_drvdata(file);
+ struct s2255_channel *channel = video_drvdata(file);
+ struct s2255_dev *dev = to_s2255_dev(vdev->v4l2_dev);
struct s2255_fh *fh;
enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- int i = 0;
- int cur_channel = -1;
int state;
dprintk(1, "s2255: open called (dev=%s)\n",
video_device_node_name(vdev));
-
- for (i = 0; i < MAX_CHANNELS; i++) {
- if (&dev->vdev[i] == vdev) {
- cur_channel = i;
- break;
- }
- }
- if (i == MAX_CHANNELS)
- return -ENODEV;
-
/*
* open lock necessary to prevent multiple instances
* of v4l-conf (or other programs) from simultaneously
@@ -1806,24 +1799,20 @@ static int s2255_open(struct file *file)
file->private_data = fh;
fh->dev = dev;
fh->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- fh->mode = dev->mode[cur_channel];
- fh->fmt = dev->cur_fmt[cur_channel];
- /* default 4CIF NTSC */
- fh->width = LINE_SZ_4CIFS_NTSC;
- fh->height = NUM_LINES_4CIFS_NTSC * 2;
- fh->channel = cur_channel;
- /* configure channel to default state */
- if (!dev->chn_configured[cur_channel]) {
- s2255_set_mode(dev, cur_channel, &fh->mode);
- dev->chn_configured[cur_channel] = 1;
+ fh->channel = channel;
+ if (!channel->configured) {
+ /* configure channel to default state */
+ channel->fmt = &formats[0];
+ s2255_set_mode(channel, &channel->mode);
+ channel->configured = 1;
}
dprintk(1, "%s: dev=%s type=%s\n", __func__,
video_device_node_name(vdev), v4l2_type_names[type]);
dprintk(2, "%s: fh=0x%08lx, dev=0x%08lx, vidq=0x%08lx\n", __func__,
(unsigned long)fh, (unsigned long)dev,
- (unsigned long)&dev->vidq[cur_channel]);
+ (unsigned long)&channel->vidq);
dprintk(4, "%s: list_empty active=%d\n", __func__,
- list_empty(&dev->vidq[cur_channel].active));
+ list_empty(&channel->vidq.active));
videobuf_queue_vmalloc_init(&fh->vb_vidq, &s2255_video_qops,
NULL, &dev->slock,
fh->type,
@@ -1865,6 +1854,7 @@ static void s2255_destroy(struct s2255_dev *dev)
mutex_destroy(&dev->open_lock);
mutex_destroy(&dev->lock);
usb_put_dev(dev->udev);
+ v4l2_device_unregister(&dev->v4l2_dev);
dprintk(1, "%s", __func__);
kfree(dev);
}
@@ -1874,14 +1864,15 @@ static int s2255_release(struct file *file)
struct s2255_fh *fh = file->private_data;
struct s2255_dev *dev = fh->dev;
struct video_device *vdev = video_devdata(file);
+ struct s2255_channel *channel = fh->channel;
if (!dev)
return -ENODEV;
/* turn off stream */
if (res_check(fh)) {
- if (dev->b_acquire[fh->channel])
- s2255_stop_acquire(dev, fh->channel);
+ if (channel->b_acquire)
+ s2255_stop_acquire(fh->channel);
videobuf_streamoff(&fh->vb_vidq);
- res_free(dev, fh);
+ res_free(fh);
}
videobuf_mmap_free(&fh->vb_vidq);
dprintk(1, "%s (dev=%s)\n", __func__, video_device_node_name(vdev));
@@ -1945,9 +1936,10 @@ static const struct v4l2_ioctl_ops s2255_ioctl_ops = {
static void s2255_video_device_release(struct video_device *vdev)
{
- struct s2255_dev *dev = video_get_drvdata(vdev);
- dprintk(4, "%s, chnls: %d \n", __func__, atomic_read(&dev->channels));
- if (atomic_dec_and_test(&dev->channels))
+ struct s2255_dev *dev = to_s2255_dev(vdev->v4l2_dev);
+ dprintk(4, "%s, chnls: %d \n", __func__,
+ atomic_read(&dev->num_channels));
+ if (atomic_dec_and_test(&dev->num_channels))
s2255_destroy(dev);
return;
}
@@ -1966,47 +1958,48 @@ static int s2255_probe_v4l(struct s2255_dev *dev)
int ret;
int i;
int cur_nr = video_nr;
+ struct s2255_channel *channel;
ret = v4l2_device_register(&dev->interface->dev, &dev->v4l2_dev);
if (ret)
return ret;
/* initialize all video 4 linux */
/* register 4 video devices */
for (i = 0; i < MAX_CHANNELS; i++) {
- INIT_LIST_HEAD(&dev->vidq[i].active);
- dev->vidq[i].dev = dev;
- dev->vidq[i].channel = i;
+ channel = &dev->channel[i];
+ INIT_LIST_HEAD(&channel->vidq.active);
+ channel->vidq.dev = dev;
/* register 4 video devices */
- memcpy(&dev->vdev[i], &template, sizeof(struct video_device));
- dev->vdev[i].v4l2_dev = &dev->v4l2_dev;
- video_set_drvdata(&dev->vdev[i], dev);
+ channel->vdev = template;
+ channel->vdev.v4l2_dev = &dev->v4l2_dev;
+ video_set_drvdata(&channel->vdev, channel);
if (video_nr == -1)
- ret = video_register_device(&dev->vdev[i],
+ ret = video_register_device(&channel->vdev,
VFL_TYPE_GRABBER,
video_nr);
else
- ret = video_register_device(&dev->vdev[i],
+ ret = video_register_device(&channel->vdev,
VFL_TYPE_GRABBER,
cur_nr + i);
+
if (ret) {
dev_err(&dev->udev->dev,
"failed to register video device!\n");
break;
}
- atomic_inc(&dev->channels);
+ atomic_inc(&dev->num_channels);
v4l2_info(&dev->v4l2_dev, "V4L2 device registered as %s\n",
- video_device_node_name(&dev->vdev[i]));
+ video_device_node_name(&channel->vdev));
}
-
printk(KERN_INFO "Sensoray 2255 V4L driver Revision: %d.%d\n",
S2255_MAJOR_VERSION,
S2255_MINOR_VERSION);
/* if no channels registered, return error and probe will fail*/
- if (atomic_read(&dev->channels) == 0) {
+ if (atomic_read(&dev->num_channels) == 0) {
v4l2_device_unregister(&dev->v4l2_dev);
return ret;
}
- if (atomic_read(&dev->channels) != MAX_CHANNELS)
+ if (atomic_read(&dev->num_channels) != MAX_CHANNELS)
printk(KERN_WARNING "s2255: Not all channels available.\n");
return 0;
}
@@ -2033,12 +2026,11 @@ static int save_frame(struct s2255_dev *dev, struct s2255_pipeinfo *pipe_info)
s32 idx = -1;
struct s2255_framei *frm;
unsigned char *pdata;
-
+ struct s2255_channel *channel;
dprintk(100, "buffer to user\n");
-
- idx = dev->cur_frame[dev->cc];
- frm = &dev->buffer[dev->cc].frame[idx];
-
+ channel = &dev->channel[dev->cc];
+ idx = channel->cur_frame;
+ frm = &channel->buffer.frame[idx];
if (frm->ulState == S2255_READ_IDLE) {
int jj;
unsigned int cc;
@@ -2063,16 +2055,18 @@ static int save_frame(struct s2255_dev *dev, struct s2255_pipeinfo *pipe_info)
}
/* reverse it */
dev->cc = G_chnmap[cc];
+ channel = &dev->channel[dev->cc];
payload = pdword[3];
- if (payload > dev->req_image_size[dev->cc]) {
- dev->bad_payload[dev->cc]++;
+ if (payload > channel->req_image_size) {
+ channel->bad_payload++;
/* discard the bad frame */
return -EINVAL;
}
- dev->pkt_size[dev->cc] = payload;
- dev->jpg_size[dev->cc] = pdword[4];
+ channel->pkt_size = payload;
+ channel->jpg_size = pdword[4];
break;
case S2255_MARKER_RESPONSE:
+
pdata += DEF_USB_BLOCK;
jj += DEF_USB_BLOCK;
if (pdword[1] >= MAX_CHANNELS)
@@ -2080,12 +2074,13 @@ static int save_frame(struct s2255_dev *dev, struct s2255_pipeinfo *pipe_info)
cc = G_chnmap[pdword[1]];
if (cc >= MAX_CHANNELS)
break;
+ channel = &dev->channel[cc];
switch (pdword[2]) {
case S2255_RESPONSE_SETMODE:
/* check if channel valid */
/* set mode ready */
- dev->setmode_ready[cc] = 1;
- wake_up(&dev->wait_setmode[cc]);
+ channel->setmode_ready = 1;
+ wake_up(&channel->wait_setmode);
dprintk(5, "setmode ready %d\n", cc);
break;
case S2255_RESPONSE_FW:
@@ -2099,9 +2094,9 @@ static int save_frame(struct s2255_dev *dev, struct s2255_pipeinfo *pipe_info)
wake_up(&dev->fw_data->wait_fw);
break;
case S2255_RESPONSE_STATUS:
- dev->vidstatus[cc] = pdword[3];
- dev->vidstatus_ready[cc] = 1;
- wake_up(&dev->wait_vidstatus[cc]);
+ channel->vidstatus = pdword[3];
+ channel->vidstatus_ready = 1;
+ wake_up(&channel->wait_vidstatus);
dprintk(5, "got vidstatus %x chan %d\n",
pdword[3], cc);
break;
@@ -2118,13 +2113,11 @@ static int save_frame(struct s2255_dev *dev, struct s2255_pipeinfo *pipe_info)
if (!bframe)
return -EINVAL;
}
-
-
- idx = dev->cur_frame[dev->cc];
- frm = &dev->buffer[dev->cc].frame[idx];
-
+ channel = &dev->channel[dev->cc];
+ idx = channel->cur_frame;
+ frm = &channel->buffer.frame[idx];
/* search done. now find out if should be acquiring on this channel */
- if (!dev->b_acquire[dev->cc]) {
+ if (!channel->b_acquire) {
/* we found a frame, but this channel is turned off */
frm->ulState = S2255_READ_IDLE;
return -EINVAL;
@@ -2149,30 +2142,28 @@ static int save_frame(struct s2255_dev *dev, struct s2255_pipeinfo *pipe_info)
copy_size = (pipe_info->cur_transfer_size - offset);
- size = dev->pkt_size[dev->cc] - PREFIX_SIZE;
+ size = channel->pkt_size - PREFIX_SIZE;
/* sanity check on pdest */
- if ((copy_size + frm->cur_size) < dev->req_image_size[dev->cc])
+ if ((copy_size + frm->cur_size) < channel->req_image_size)
memcpy(pdest, psrc, copy_size);
frm->cur_size += copy_size;
dprintk(4, "cur_size size %lu size %lu \n", frm->cur_size, size);
if (frm->cur_size >= size) {
-
- u32 cc = dev->cc;
dprintk(2, "****************[%d]Buffer[%d]full*************\n",
- cc, idx);
- dev->last_frame[cc] = dev->cur_frame[cc];
- dev->cur_frame[cc]++;
+ dev->cc, idx);
+ channel->last_frame = channel->cur_frame;
+ channel->cur_frame++;
/* end of system frame ring buffer, start at zero */
- if ((dev->cur_frame[cc] == SYS_FRAMES) ||
- (dev->cur_frame[cc] == dev->buffer[cc].dwFrames))
- dev->cur_frame[cc] = 0;
+ if ((channel->cur_frame == SYS_FRAMES) ||
+ (channel->cur_frame == channel->buffer.dwFrames))
+ channel->cur_frame = 0;
/* frame ready */
- if (dev->b_acquire[cc])
- s2255_got_frame(dev, cc, dev->jpg_size[cc]);
- dev->frame_count[cc]++;
+ if (channel->b_acquire)
+ s2255_got_frame(channel, channel->jpg_size);
+ channel->frame_count++;
frm->ulState = S2255_READ_IDLE;
frm->cur_size = 0;
@@ -2245,16 +2236,12 @@ static int s2255_get_fx2fw(struct s2255_dev *dev)
* Create the system ring buffer to copy frames into from the
* usb read pipe.
*/
-static int s2255_create_sys_buffers(struct s2255_dev *dev, unsigned long chn)
+static int s2255_create_sys_buffers(struct s2255_channel *channel)
{
unsigned long i;
unsigned long reqsize;
dprintk(1, "create sys buffers\n");
- if (chn >= MAX_CHANNELS)
- return -1;
-
- dev->buffer[chn].dwFrames = SYS_FRAMES;
-
+ channel->buffer.dwFrames = SYS_FRAMES;
/* always allocate maximum size(PAL) for system buffers */
reqsize = SYS_FRAMES_MAXSIZE;
@@ -2263,42 +2250,40 @@ static int s2255_create_sys_buffers(struct s2255_dev *dev, unsigned long chn)
for (i = 0; i < SYS_FRAMES; i++) {
/* allocate the frames */
- dev->buffer[chn].frame[i].lpvbits = vmalloc(reqsize);
-
- dprintk(1, "valloc %p chan %lu, idx %lu, pdata %p\n",
- &dev->buffer[chn].frame[i], chn, i,
- dev->buffer[chn].frame[i].lpvbits);
- dev->buffer[chn].frame[i].size = reqsize;
- if (dev->buffer[chn].frame[i].lpvbits == NULL) {
+ channel->buffer.frame[i].lpvbits = vmalloc(reqsize);
+ dprintk(1, "valloc %p chan %d, idx %lu, pdata %p\n",
+ &channel->buffer.frame[i], channel->idx, i,
+ channel->buffer.frame[i].lpvbits);
+ channel->buffer.frame[i].size = reqsize;
+ if (channel->buffer.frame[i].lpvbits == NULL) {
printk(KERN_INFO "out of memory. using less frames\n");
- dev->buffer[chn].dwFrames = i;
+ channel->buffer.dwFrames = i;
break;
}
}
/* make sure internal states are set */
for (i = 0; i < SYS_FRAMES; i++) {
- dev->buffer[chn].frame[i].ulState = 0;
- dev->buffer[chn].frame[i].cur_size = 0;
+ channel->buffer.frame[i].ulState = 0;
+ channel->buffer.frame[i].cur_size = 0;
}
- dev->cur_frame[chn] = 0;
- dev->last_frame[chn] = -1;
+ channel->cur_frame = 0;
+ channel->last_frame = -1;
return 0;
}
-static int s2255_release_sys_buffers(struct s2255_dev *dev,
- unsigned long channel)
+static int s2255_release_sys_buffers(struct s2255_channel *channel)
{
unsigned long i;
dprintk(1, "release sys buffers\n");
for (i = 0; i < SYS_FRAMES; i++) {
- if (dev->buffer[channel].frame[i].lpvbits) {
+ if (channel->buffer.frame[i].lpvbits) {
dprintk(1, "vfree %p\n",
- dev->buffer[channel].frame[i].lpvbits);
- vfree(dev->buffer[channel].frame[i].lpvbits);
+ channel->buffer.frame[i].lpvbits);
+ vfree(channel->buffer.frame[i].lpvbits);
}
- dev->buffer[channel].frame[i].lpvbits = NULL;
+ channel->buffer.frame[i].lpvbits = NULL;
}
return 0;
}
@@ -2335,17 +2320,20 @@ static int s2255_board_init(struct s2255_dev *dev)
fw_ver & 0xff);
for (j = 0; j < MAX_CHANNELS; j++) {
- dev->b_acquire[j] = 0;
- dev->mode[j] = mode_def;
+ struct s2255_channel *channel = &dev->channel[j];
+ channel->b_acquire = 0;
+ channel->mode = mode_def;
if (dev->pid == 0x2257 && j > 1)
- dev->mode[j].color |= (1 << 16);
- dev->jc[j].quality = S2255_DEF_JPEG_QUAL;
- dev->cur_fmt[j] = &formats[0];
- dev->mode[j].restart = 1;
- dev->req_image_size[j] = get_transfer_size(&mode_def);
- dev->frame_count[j] = 0;
+ channel->mode.color |= (1 << 16);
+ channel->jc.quality = S2255_DEF_JPEG_QUAL;
+ channel->width = LINE_SZ_4CIFS_NTSC;
+ channel->height = NUM_LINES_4CIFS_NTSC * 2;
+ channel->fmt = &formats[0];
+ channel->mode.restart = 1;
+ channel->req_image_size = get_transfer_size(&mode_def);
+ channel->frame_count = 0;
/* create the system buffers */
- s2255_create_sys_buffers(dev, j);
+ s2255_create_sys_buffers(channel);
}
/* start read pipe */
s2255_start_readpipe(dev);
@@ -2359,14 +2347,12 @@ static int s2255_board_shutdown(struct s2255_dev *dev)
dprintk(1, "%s: dev: %p", __func__, dev);
for (i = 0; i < MAX_CHANNELS; i++) {
- if (dev->b_acquire[i])
- s2255_stop_acquire(dev, i);
+ if (dev->channel[i].b_acquire)
+ s2255_stop_acquire(&dev->channel[i]);
}
-
s2255_stop_readpipe(dev);
-
for (i = 0; i < MAX_CHANNELS; i++)
- s2255_release_sys_buffers(dev, i);
+ s2255_release_sys_buffers(&dev->channel[i]);
/* release transfer buffer */
kfree(dev->pipe.transfer_buffer);
return 0;
@@ -2459,29 +2445,26 @@ static int s2255_start_readpipe(struct s2255_dev *dev)
}
/* starts acquisition process */
-static int s2255_start_acquire(struct s2255_dev *dev, unsigned long chn)
+static int s2255_start_acquire(struct s2255_channel *channel)
{
unsigned char *buffer;
int res;
unsigned long chn_rev;
int j;
- if (chn >= MAX_CHANNELS) {
- dprintk(2, "start acquire failed, bad channel %lu\n", chn);
- return -1;
- }
- chn_rev = G_chnmap[chn];
+ struct s2255_dev *dev = to_s2255_dev(channel->vdev.v4l2_dev);
+ chn_rev = G_chnmap[channel->idx];
buffer = kzalloc(512, GFP_KERNEL);
if (buffer == NULL) {
dev_err(&dev->udev->dev, "out of mem\n");
return -ENOMEM;
}
- dev->last_frame[chn] = -1;
- dev->bad_payload[chn] = 0;
- dev->cur_frame[chn] = 0;
+ channel->last_frame = -1;
+ channel->bad_payload = 0;
+ channel->cur_frame = 0;
for (j = 0; j < SYS_FRAMES; j++) {
- dev->buffer[chn].frame[j].ulState = 0;
- dev->buffer[chn].frame[j].cur_size = 0;
+ channel->buffer.frame[j].ulState = 0;
+ channel->buffer.frame[j].cur_size = 0;
}
/* send the start command */
@@ -2492,21 +2475,18 @@ static int s2255_start_acquire(struct s2255_dev *dev, unsigned long chn)
if (res != 0)
dev_err(&dev->udev->dev, "CMD_START error\n");
- dprintk(2, "start acquire exit[%lu] %d \n", chn, res);
+ dprintk(2, "start acquire exit[%d] %d \n", channel->idx, res);
kfree(buffer);
return 0;
}
-static int s2255_stop_acquire(struct s2255_dev *dev, unsigned long chn)
+static int s2255_stop_acquire(struct s2255_channel *channel)
{
unsigned char *buffer;
int res;
unsigned long chn_rev;
- if (chn >= MAX_CHANNELS) {
- dprintk(2, "stop acquire failed, bad channel %lu\n", chn);
- return -1;
- }
- chn_rev = G_chnmap[chn];
+ struct s2255_dev *dev = to_s2255_dev(channel->vdev.v4l2_dev);
+ chn_rev = G_chnmap[channel->idx];
buffer = kzalloc(512, GFP_KERNEL);
if (buffer == NULL) {
dev_err(&dev->udev->dev, "out of mem\n");
@@ -2520,8 +2500,8 @@ static int s2255_stop_acquire(struct s2255_dev *dev, unsigned long chn)
if (res != 0)
dev_err(&dev->udev->dev, "CMD_STOP error\n");
kfree(buffer);
- dev->b_acquire[chn] = 0;
- dprintk(4, "%s: chn %lu, res %d\n", __func__, chn, res);
+ channel->b_acquire = 0;
+ dprintk(4, "%s: chn %d, res %d\n", __func__, channel->idx, res);
return res;
}
@@ -2575,7 +2555,7 @@ static int s2255_probe(struct usb_interface *interface,
s2255_dev_err(&interface->dev, "out of memory\n");
return -ENOMEM;
}
- atomic_set(&dev->channels, 0);
+ atomic_set(&dev->num_channels, 0);
dev->pid = id->idProduct;
dev->fw_data = kzalloc(sizeof(struct s2255_fw), GFP_KERNEL);
if (!dev->fw_data)
@@ -2612,8 +2592,10 @@ static int s2255_probe(struct usb_interface *interface,
dev->timer.data = (unsigned long)dev->fw_data;
init_waitqueue_head(&dev->fw_data->wait_fw);
for (i = 0; i < MAX_CHANNELS; i++) {
- init_waitqueue_head(&dev->wait_setmode[i]);
- init_waitqueue_head(&dev->wait_vidstatus[i]);
+ struct s2255_channel *channel = &dev->channel[i];
+ dev->channel[i].idx = i;
+ init_waitqueue_head(&channel->wait_setmode);
+ init_waitqueue_head(&channel->wait_vidstatus);
}
dev->fw_data->fw_urb = usb_alloc_urb(0, GFP_KERNEL);
@@ -2651,7 +2633,7 @@ static int s2255_probe(struct usb_interface *interface,
printk(KERN_INFO "s2255: f2255usb.bin out of date.\n");
if (dev->pid == 0x2257 && *pRel < S2255_MIN_DSP_COLORFILTER)
printk(KERN_WARNING "s2255: 2257 requires firmware %d"
- "or above.\n", S2255_MIN_DSP_COLORFILTER);
+ " or above.\n", S2255_MIN_DSP_COLORFILTER);
}
usb_reset_device(dev->udev);
/* load 2255 board specific */
@@ -2693,25 +2675,23 @@ static void s2255_disconnect(struct usb_interface *interface)
{
struct s2255_dev *dev = to_s2255_dev(usb_get_intfdata(interface));
int i;
- int channels = atomic_read(&dev->channels);
- v4l2_device_unregister(&dev->v4l2_dev);
+ int channels = atomic_read(&dev->num_channels);
+ v4l2_device_disconnect(&dev->v4l2_dev);
/*see comments in the uvc_driver.c usb disconnect function */
- atomic_inc(&dev->channels);
+ atomic_inc(&dev->num_channels);
/* unregister each video device. */
- for (i = 0; i < channels; i++) {
- if (video_is_registered(&dev->vdev[i]))
- video_unregister_device(&dev->vdev[i]);
- }
+ for (i = 0; i < channels; i++)
+ video_unregister_device(&dev->channel[i].vdev);
/* wake up any of our timers */
atomic_set(&dev->fw_data->fw_state, S2255_FW_DISCONNECTING);
wake_up(&dev->fw_data->wait_fw);
for (i = 0; i < MAX_CHANNELS; i++) {
- dev->setmode_ready[i] = 1;
- wake_up(&dev->wait_setmode[i]);
- dev->vidstatus_ready[i] = 1;
- wake_up(&dev->wait_vidstatus[i]);
+ dev->channel[i].setmode_ready = 1;
+ wake_up(&dev->channel[i].wait_setmode);
+ dev->channel[i].vidstatus_ready = 1;
+ wake_up(&dev->channel[i].wait_vidstatus);
}
- if (atomic_dec_and_test(&dev->channels))
+ if (atomic_dec_and_test(&dev->num_channels))
s2255_destroy(dev);
dev_info(&interface->dev, "%s\n", __func__);
}
diff --git a/drivers/media/video/saa7134/saa7134-alsa.c b/drivers/media/video/saa7134/saa7134-alsa.c
index d3bd82ad010..10460fd3ce3 100644
--- a/drivers/media/video/saa7134/saa7134-alsa.c
+++ b/drivers/media/video/saa7134/saa7134-alsa.c
@@ -630,7 +630,7 @@ static int snd_card_saa7134_hw_params(struct snd_pcm_substream * substream,
/* release the old buffer */
if (substream->runtime->dma_area) {
saa7134_pgtable_free(dev->pci, &dev->dmasound.pt);
- videobuf_sg_dma_unmap(&dev->pci->dev, &dev->dmasound.dma);
+ videobuf_dma_unmap(&dev->pci->dev, &dev->dmasound.dma);
dsp_buffer_free(dev);
substream->runtime->dma_area = NULL;
}
@@ -646,12 +646,12 @@ static int snd_card_saa7134_hw_params(struct snd_pcm_substream * substream,
return err;
}
- if (0 != (err = videobuf_sg_dma_map(&dev->pci->dev, &dev->dmasound.dma))) {
+ if (0 != (err = videobuf_dma_map(&dev->pci->dev, &dev->dmasound.dma))) {
dsp_buffer_free(dev);
return err;
}
if (0 != (err = saa7134_pgtable_alloc(dev->pci,&dev->dmasound.pt))) {
- videobuf_sg_dma_unmap(&dev->pci->dev, &dev->dmasound.dma);
+ videobuf_dma_unmap(&dev->pci->dev, &dev->dmasound.dma);
dsp_buffer_free(dev);
return err;
}
@@ -660,7 +660,7 @@ static int snd_card_saa7134_hw_params(struct snd_pcm_substream * substream,
dev->dmasound.dma.sglen,
0))) {
saa7134_pgtable_free(dev->pci, &dev->dmasound.pt);
- videobuf_sg_dma_unmap(&dev->pci->dev, &dev->dmasound.dma);
+ videobuf_dma_unmap(&dev->pci->dev, &dev->dmasound.dma);
dsp_buffer_free(dev);
return err;
}
@@ -669,7 +669,7 @@ static int snd_card_saa7134_hw_params(struct snd_pcm_substream * substream,
byte, but it doesn't work. So I allocate the DMA using the
V4L functions, and force ALSA to use that as the DMA area */
- substream->runtime->dma_area = dev->dmasound.dma.vmalloc;
+ substream->runtime->dma_area = dev->dmasound.dma.vaddr;
substream->runtime->dma_bytes = dev->dmasound.bufsize;
substream->runtime->dma_addr = 0;
@@ -696,7 +696,7 @@ static int snd_card_saa7134_hw_free(struct snd_pcm_substream * substream)
if (substream->runtime->dma_area) {
saa7134_pgtable_free(dev->pci, &dev->dmasound.pt);
- videobuf_sg_dma_unmap(&dev->pci->dev, &dev->dmasound.dma);
+ videobuf_dma_unmap(&dev->pci->dev, &dev->dmasound.dma);
dsp_buffer_free(dev);
substream->runtime->dma_area = NULL;
}
@@ -1080,7 +1080,7 @@ static int alsa_card_saa7134_create(struct saa7134_dev *dev, int devnum)
/* Card "creation" */
card->private_free = snd_saa7134_free;
- chip = (snd_card_saa7134_t *) card->private_data;
+ chip = card->private_data;
spin_lock_init(&chip->lock);
spin_lock_init(&chip->mixer_lock);
diff --git a/drivers/media/video/saa7134/saa7134-cards.c b/drivers/media/video/saa7134/saa7134-cards.c
index 07f6bb8ef9d..ec697fcd406 100644
--- a/drivers/media/video/saa7134/saa7134-cards.c
+++ b/drivers/media/video/saa7134/saa7134-cards.c
@@ -5462,6 +5462,30 @@ struct saa7134_board saa7134_boards[] = {
.amux = TV,
},
},
+ [SAA7134_BOARD_TECHNOTREND_BUDGET_T3000] = {
+ .name = "TechoTrend TT-budget T-3000",
+ .tuner_type = TUNER_PHILIPS_TD1316,
+ .audio_clock = 0x00187de7,
+ .radio_type = UNSET,
+ .tuner_addr = 0x63,
+ .radio_addr = ADDR_UNSET,
+ .tda9887_conf = TDA9887_PRESENT | TDA9887_PORT1_ACTIVE,
+ .mpeg = SAA7134_MPEG_DVB,
+ .inputs = {{
+ .name = name_tv,
+ .vmux = 3,
+ .amux = TV,
+ .tv = 1,
+ }, {
+ .name = name_comp1,
+ .vmux = 0,
+ .amux = LINE2,
+ }, {
+ .name = name_svideo,
+ .vmux = 8,
+ .amux = LINE2,
+ } },
+ },
};
@@ -6631,6 +6655,12 @@ struct pci_device_id saa7134_pci_tbl[] = {
.subdevice = 0x6655,
.driver_data = SAA7134_BOARD_LEADTEK_WINFAST_DTV1000S,
}, {
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x13c2,
+ .subdevice = 0x2804,
+ .driver_data = SAA7134_BOARD_TECHNOTREND_BUDGET_T3000,
+ }, {
/* --- boards without eeprom + subsystem ID --- */
.vendor = PCI_VENDOR_ID_PHILIPS,
.device = PCI_DEVICE_ID_PHILIPS_SAA7134,
@@ -7320,6 +7350,7 @@ int saa7134_board_init2(struct saa7134_dev *dev)
case SAA7134_BOARD_VIDEOMATE_DVBT_300:
case SAA7134_BOARD_ASUS_EUROPA2_HYBRID:
case SAA7134_BOARD_ASUS_EUROPA_HYBRID:
+ case SAA7134_BOARD_TECHNOTREND_BUDGET_T3000:
{
/* The Philips EUROPA based hybrid boards have the tuner
diff --git a/drivers/media/video/saa7134/saa7134-core.c b/drivers/media/video/saa7134/saa7134-core.c
index 90f23188129..40bc635e8a3 100644
--- a/drivers/media/video/saa7134/saa7134-core.c
+++ b/drivers/media/video/saa7134/saa7134-core.c
@@ -256,7 +256,7 @@ void saa7134_dma_free(struct videobuf_queue *q,struct saa7134_buf *buf)
BUG_ON(in_interrupt());
videobuf_waiton(&buf->vb,0,0);
- videobuf_dma_unmap(q, dma);
+ videobuf_dma_unmap(q->dev, dma);
videobuf_dma_free(dma);
buf->vb.state = VIDEOBUF_NEEDS_INIT;
}
diff --git a/drivers/media/video/saa7134/saa7134-dvb.c b/drivers/media/video/saa7134/saa7134-dvb.c
index 31e82be1b7e..f26fe7661a1 100644
--- a/drivers/media/video/saa7134/saa7134-dvb.c
+++ b/drivers/media/video/saa7134/saa7134-dvb.c
@@ -481,6 +481,17 @@ static struct tda1004x_config medion_cardbus = {
.request_firmware = philips_tda1004x_request_firmware
};
+static struct tda1004x_config technotrend_budget_t3000_config = {
+ .demod_address = 0x8,
+ .invert = 1,
+ .invert_oclk = 0,
+ .xtal_freq = TDA10046_XTAL_4M,
+ .agc_config = TDA10046_AGC_DEFAULT,
+ .if_freq = TDA10046_FREQ_3617,
+ .tuner_address = 0x63,
+ .request_firmware = philips_tda1004x_request_firmware
+};
+
/* ------------------------------------------------------------------
* tda 1004x based cards with philips silicon tuner
*/
@@ -1168,6 +1179,18 @@ static int dvb_init(struct saa7134_dev *dev)
fe0->dvb.frontend->ops.tuner_ops.set_params = philips_td1316_tuner_set_params;
}
break;
+ case SAA7134_BOARD_TECHNOTREND_BUDGET_T3000:
+ fe0->dvb.frontend = dvb_attach(tda10046_attach,
+ &technotrend_budget_t3000_config,
+ &dev->i2c_adap);
+ if (fe0->dvb.frontend) {
+ dev->original_demod_sleep = fe0->dvb.frontend->ops.sleep;
+ fe0->dvb.frontend->ops.sleep = philips_europa_demod_sleep;
+ fe0->dvb.frontend->ops.tuner_ops.init = philips_europa_tuner_init;
+ fe0->dvb.frontend->ops.tuner_ops.sleep = philips_europa_tuner_sleep;
+ fe0->dvb.frontend->ops.tuner_ops.set_params = philips_td1316_tuner_set_params;
+ }
+ break;
case SAA7134_BOARD_VIDEOMATE_DVBT_200:
fe0->dvb.frontend = dvb_attach(tda10046_attach,
&philips_tu1216_61_config,
diff --git a/drivers/media/video/saa7134/saa7134.h b/drivers/media/video/saa7134/saa7134.h
index 756a1ca8833..c040a180854 100644
--- a/drivers/media/video/saa7134/saa7134.h
+++ b/drivers/media/video/saa7134/saa7134.h
@@ -304,6 +304,7 @@ struct saa7134_format {
#define SAA7134_BOARD_BEHOLD_H7 178
#define SAA7134_BOARD_BEHOLD_A7 179
#define SAA7134_BOARD_AVERMEDIA_M733A 180
+#define SAA7134_BOARD_TECHNOTREND_BUDGET_T3000 181
#define SAA7134_MAXBOARDS 32
#define SAA7134_INPUT_MAX 8
diff --git a/drivers/media/video/sh_mobile_ceu_camera.c b/drivers/media/video/sh_mobile_ceu_camera.c
index 961bfa2fea9..2b24bd0de3a 100644
--- a/drivers/media/video/sh_mobile_ceu_camera.c
+++ b/drivers/media/video/sh_mobile_ceu_camera.c
@@ -633,6 +633,12 @@ static void sh_mobile_ceu_set_rect(struct soc_camera_device *icd)
cdwdr_width *= 2;
}
+ /* CSI2 special configuration */
+ if (pcdev->pdata->csi2_dev) {
+ in_width = ((in_width - 2) * 2);
+ left_offset *= 2;
+ }
+
/* Set CAMOR, CAPWR, CFSZR, take care of CDWDR */
camor = left_offset | (top_offset << 16);
@@ -743,16 +749,16 @@ static int sh_mobile_ceu_set_bus_param(struct soc_camera_device *icd,
case V4L2_PIX_FMT_NV16:
case V4L2_PIX_FMT_NV61:
switch (cam->code) {
- case V4L2_MBUS_FMT_YUYV8_2X8_BE:
+ case V4L2_MBUS_FMT_UYVY8_2X8:
value = 0x00000000; /* Cb0, Y0, Cr0, Y1 */
break;
- case V4L2_MBUS_FMT_YVYU8_2X8_BE:
+ case V4L2_MBUS_FMT_VYUY8_2X8:
value = 0x00000100; /* Cr0, Y0, Cb0, Y1 */
break;
- case V4L2_MBUS_FMT_YUYV8_2X8_LE:
+ case V4L2_MBUS_FMT_YUYV8_2X8:
value = 0x00000200; /* Y0, Cb0, Y1, Cr0 */
break;
- case V4L2_MBUS_FMT_YVYU8_2X8_LE:
+ case V4L2_MBUS_FMT_YVYU8_2X8:
value = 0x00000300; /* Y0, Cr0, Y1, Cb0 */
break;
default:
@@ -767,6 +773,11 @@ static int sh_mobile_ceu_set_bus_param(struct soc_camera_device *icd,
value |= common_flags & SOCAM_VSYNC_ACTIVE_LOW ? 1 << 1 : 0;
value |= common_flags & SOCAM_HSYNC_ACTIVE_LOW ? 1 << 0 : 0;
value |= pcdev->is_16bit ? 1 << 12 : 0;
+
+ /* CSI2 mode */
+ if (pcdev->pdata->csi2_dev)
+ value |= 3 << 12;
+
ceu_write(pcdev, CAMCR, value);
ceu_write(pcdev, CAPCR, 0x00300000);
@@ -883,6 +894,8 @@ static int sh_mobile_ceu_get_formats(struct soc_camera_device *icd, unsigned int
{
struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
struct device *dev = icd->dev.parent;
+ struct soc_camera_host *ici = to_soc_camera_host(dev);
+ struct sh_mobile_ceu_dev *pcdev = ici->priv;
int ret, k, n;
int formats = 0;
struct sh_mobile_ceu_cam *cam;
@@ -896,19 +909,19 @@ static int sh_mobile_ceu_get_formats(struct soc_camera_device *icd, unsigned int
fmt = soc_mbus_get_fmtdesc(code);
if (!fmt) {
- dev_err(icd->dev.parent,
- "Invalid format code #%u: %d\n", idx, code);
+ dev_err(dev, "Invalid format code #%u: %d\n", idx, code);
return -EINVAL;
}
- ret = sh_mobile_ceu_try_bus_param(icd, fmt->bits_per_sample);
- if (ret < 0)
- return 0;
+ if (!pcdev->pdata->csi2_dev) {
+ ret = sh_mobile_ceu_try_bus_param(icd, fmt->bits_per_sample);
+ if (ret < 0)
+ return 0;
+ }
if (!icd->host_priv) {
struct v4l2_mbus_framefmt mf;
struct v4l2_rect rect;
- struct device *dev = icd->dev.parent;
int shift = 0;
/* FIXME: subwindow is lost between close / open */
@@ -927,7 +940,8 @@ static int sh_mobile_ceu_get_formats(struct soc_camera_device *icd, unsigned int
/* Try 2560x1920, 1280x960, 640x480, 320x240 */
mf.width = 2560 >> shift;
mf.height = 1920 >> shift;
- ret = v4l2_subdev_call(sd, video, s_mbus_fmt, &mf);
+ ret = v4l2_device_call_until_err(sd->v4l2_dev, 0, video,
+ s_mbus_fmt, &mf);
if (ret < 0)
return ret;
shift++;
@@ -965,10 +979,10 @@ static int sh_mobile_ceu_get_formats(struct soc_camera_device *icd, unsigned int
cam->extra_fmt = NULL;
switch (code) {
- case V4L2_MBUS_FMT_YUYV8_2X8_BE:
- case V4L2_MBUS_FMT_YVYU8_2X8_BE:
- case V4L2_MBUS_FMT_YUYV8_2X8_LE:
- case V4L2_MBUS_FMT_YVYU8_2X8_LE:
+ case V4L2_MBUS_FMT_UYVY8_2X8:
+ case V4L2_MBUS_FMT_VYUY8_2X8:
+ case V4L2_MBUS_FMT_YUYV8_2X8:
+ case V4L2_MBUS_FMT_YVYU8_2X8:
if (cam->extra_fmt)
break;
@@ -1005,7 +1019,7 @@ static int sh_mobile_ceu_get_formats(struct soc_camera_device *icd, unsigned int
xlate->code = code;
xlate++;
dev_dbg(dev, "Providing format %s in pass-through mode\n",
- xlate->host_fmt->name);
+ fmt->name);
}
return formats;
@@ -1228,7 +1242,8 @@ static int client_s_fmt(struct soc_camera_device *icd,
struct v4l2_cropcap cap;
int ret;
- ret = v4l2_subdev_call(sd, video, s_mbus_fmt, mf);
+ ret = v4l2_device_call_until_err(sd->v4l2_dev, 0, video,
+ s_mbus_fmt, mf);
if (ret < 0)
return ret;
@@ -1257,7 +1272,8 @@ static int client_s_fmt(struct soc_camera_device *icd,
tmp_h = min(2 * tmp_h, max_height);
mf->width = tmp_w;
mf->height = tmp_h;
- ret = v4l2_subdev_call(sd, video, s_mbus_fmt, mf);
+ ret = v4l2_device_call_until_err(sd->v4l2_dev, 0, video,
+ s_mbus_fmt, mf);
dev_geo(dev, "Camera scaled to %ux%u\n",
mf->width, mf->height);
if (ret < 0) {
@@ -1514,7 +1530,8 @@ static int sh_mobile_ceu_set_fmt(struct soc_camera_device *icd,
struct device *dev = icd->dev.parent;
__u32 pixfmt = pix->pixelformat;
const struct soc_camera_format_xlate *xlate;
- unsigned int ceu_sub_width, ceu_sub_height;
+ /* Keep Compiler Happy */
+ unsigned int ceu_sub_width = 0, ceu_sub_height = 0;
u16 scale_v, scale_h;
int ret;
bool image_mode;
@@ -1569,8 +1586,8 @@ static int sh_mobile_ceu_set_fmt(struct soc_camera_device *icd,
/* Done with the camera. Now see if we can improve the result */
- dev_geo(dev, "Camera %d fmt %ux%u, requested %ux%u\n",
- ret, mf.width, mf.height, pix->width, pix->height);
+ dev_geo(dev, "fmt %ux%u, requested %ux%u\n",
+ mf.width, mf.height, pix->width, pix->height);
if (ret < 0)
return ret;
@@ -1634,6 +1651,9 @@ static int sh_mobile_ceu_try_fmt(struct soc_camera_device *icd,
int width, height;
int ret;
+ dev_geo(icd->dev.parent, "TRY_FMT(pix=0x%x, %ux%u)\n",
+ pixfmt, pix->width, pix->height);
+
xlate = soc_camera_xlate_by_fourcc(icd, pixfmt);
if (!xlate) {
dev_warn(icd->dev.parent, "Format %x not found\n", pixfmt);
@@ -1660,7 +1680,7 @@ static int sh_mobile_ceu_try_fmt(struct soc_camera_device *icd,
mf.code = xlate->code;
mf.colorspace = pix->colorspace;
- ret = v4l2_subdev_call(sd, video, try_mbus_fmt, &mf);
+ ret = v4l2_device_call_until_err(sd->v4l2_dev, 0, video, try_mbus_fmt, &mf);
if (ret < 0)
return ret;
@@ -1684,7 +1704,8 @@ static int sh_mobile_ceu_try_fmt(struct soc_camera_device *icd,
*/
mf.width = 2560;
mf.height = 1920;
- ret = v4l2_subdev_call(sd, video, try_mbus_fmt, &mf);
+ ret = v4l2_device_call_until_err(sd->v4l2_dev, 0, video,
+ try_mbus_fmt, &mf);
if (ret < 0) {
/* Shouldn't actually happen... */
dev_err(icd->dev.parent,
@@ -1699,6 +1720,9 @@ static int sh_mobile_ceu_try_fmt(struct soc_camera_device *icd,
pix->height = height;
}
+ dev_geo(icd->dev.parent, "%s(): return %d, fmt 0x%x, %ux%u\n",
+ __func__, ret, pix->pixelformat, pix->width, pix->height);
+
return ret;
}
@@ -1853,6 +1877,30 @@ static struct soc_camera_host_ops sh_mobile_ceu_host_ops = {
.num_controls = ARRAY_SIZE(sh_mobile_ceu_controls),
};
+struct bus_wait {
+ struct notifier_block notifier;
+ struct completion completion;
+ struct device *dev;
+};
+
+static int bus_notify(struct notifier_block *nb,
+ unsigned long action, void *data)
+{
+ struct device *dev = data;
+ struct bus_wait *wait = container_of(nb, struct bus_wait, notifier);
+
+ if (wait->dev != dev)
+ return NOTIFY_DONE;
+
+ switch (action) {
+ case BUS_NOTIFY_UNBOUND_DRIVER:
+ /* Protect from module unloading */
+ wait_for_completion(&wait->completion);
+ return NOTIFY_OK;
+ }
+ return NOTIFY_DONE;
+}
+
static int __devinit sh_mobile_ceu_probe(struct platform_device *pdev)
{
struct sh_mobile_ceu_dev *pcdev;
@@ -1860,6 +1908,11 @@ static int __devinit sh_mobile_ceu_probe(struct platform_device *pdev)
void __iomem *base;
unsigned int irq;
int err = 0;
+ struct bus_wait wait = {
+ .completion = COMPLETION_INITIALIZER_ONSTACK(wait.completion),
+ .notifier.notifier_call = bus_notify,
+ };
+ struct device *csi2;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
irq = platform_get_irq(pdev, 0);
@@ -1931,12 +1984,54 @@ static int __devinit sh_mobile_ceu_probe(struct platform_device *pdev)
pcdev->ici.drv_name = dev_name(&pdev->dev);
pcdev->ici.ops = &sh_mobile_ceu_host_ops;
+ /* CSI2 interfacing */
+ csi2 = pcdev->pdata->csi2_dev;
+ if (csi2) {
+ wait.dev = csi2;
+
+ err = bus_register_notifier(&platform_bus_type, &wait.notifier);
+ if (err < 0)
+ goto exit_free_clk;
+
+ /*
+ * From this point the driver module will not unload, until
+ * we complete the completion.
+ */
+
+ if (!csi2->driver || !csi2->driver->owner) {
+ complete(&wait.completion);
+ /* Either too late, or probing failed */
+ bus_unregister_notifier(&platform_bus_type, &wait.notifier);
+ err = -ENXIO;
+ goto exit_free_clk;
+ }
+
+ /*
+ * The module is still loaded, in the worst case it is hanging
+ * in device release on our completion. So, _now_ dereferencing
+ * the "owner" is safe!
+ */
+
+ err = try_module_get(csi2->driver->owner);
+
+ /* Let notifier complete, if it has been locked */
+ complete(&wait.completion);
+ bus_unregister_notifier(&platform_bus_type, &wait.notifier);
+ if (!err) {
+ err = -ENODEV;
+ goto exit_free_clk;
+ }
+ }
+
err = soc_camera_host_register(&pcdev->ici);
if (err)
- goto exit_free_clk;
+ goto exit_module_put;
return 0;
+exit_module_put:
+ if (csi2 && csi2->driver)
+ module_put(csi2->driver->owner);
exit_free_clk:
pm_runtime_disable(&pdev->dev);
free_irq(pcdev->irq, pcdev);
@@ -1956,6 +2051,7 @@ static int __devexit sh_mobile_ceu_remove(struct platform_device *pdev)
struct soc_camera_host *soc_host = to_soc_camera_host(&pdev->dev);
struct sh_mobile_ceu_dev *pcdev = container_of(soc_host,
struct sh_mobile_ceu_dev, ici);
+ struct device *csi2 = pcdev->pdata->csi2_dev;
soc_camera_host_unregister(soc_host);
pm_runtime_disable(&pdev->dev);
@@ -1963,7 +2059,10 @@ static int __devexit sh_mobile_ceu_remove(struct platform_device *pdev)
if (platform_get_resource(pdev, IORESOURCE_MEM, 1))
dma_release_declared_memory(&pdev->dev);
iounmap(pcdev->base);
+ if (csi2 && csi2->driver)
+ module_put(csi2->driver->owner);
kfree(pcdev);
+
return 0;
}
@@ -1995,6 +2094,8 @@ static struct platform_driver sh_mobile_ceu_driver = {
static int __init sh_mobile_ceu_init(void)
{
+ /* Whatever return code */
+ request_module("sh_mobile_csi2");
return platform_driver_register(&sh_mobile_ceu_driver);
}
diff --git a/drivers/media/video/sh_mobile_csi2.c b/drivers/media/video/sh_mobile_csi2.c
new file mode 100644
index 00000000000..84a64681931
--- /dev/null
+++ b/drivers/media/video/sh_mobile_csi2.c
@@ -0,0 +1,354 @@
+/*
+ * Driver for the SH-Mobile MIPI CSI-2 unit
+ *
+ * Copyright (C) 2010, Guennadi Liakhovetski <g.liakhovetski@gmx.de>
+ *
+ * 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/delay.h>
+#include <linux/i2c.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/slab.h>
+#include <linux/videodev2.h>
+
+#include <media/sh_mobile_csi2.h>
+#include <media/soc_camera.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-dev.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-mediabus.h>
+#include <media/v4l2-subdev.h>
+
+#define SH_CSI2_TREF 0x00
+#define SH_CSI2_SRST 0x04
+#define SH_CSI2_PHYCNT 0x08
+#define SH_CSI2_CHKSUM 0x0C
+#define SH_CSI2_VCDT 0x10
+
+struct sh_csi2 {
+ struct v4l2_subdev subdev;
+ struct list_head list;
+ struct notifier_block notifier;
+ unsigned int irq;
+ void __iomem *base;
+ struct platform_device *pdev;
+ struct sh_csi2_client_config *client;
+};
+
+static int sh_csi2_try_fmt(struct v4l2_subdev *sd,
+ struct v4l2_mbus_framefmt *mf)
+{
+ struct sh_csi2 *priv = container_of(sd, struct sh_csi2, subdev);
+ struct sh_csi2_pdata *pdata = priv->pdev->dev.platform_data;
+
+ if (mf->width > 8188)
+ mf->width = 8188;
+ else if (mf->width & 1)
+ mf->width &= ~1;
+
+ switch (pdata->type) {
+ case SH_CSI2C:
+ switch (mf->code) {
+ case V4L2_MBUS_FMT_UYVY8_2X8: /* YUV422 */
+ case V4L2_MBUS_FMT_YUYV8_1_5X8: /* YUV420 */
+ case V4L2_MBUS_FMT_GREY8_1X8: /* RAW8 */
+ case V4L2_MBUS_FMT_SBGGR8_1X8:
+ case V4L2_MBUS_FMT_SGRBG8_1X8:
+ break;
+ default:
+ /* All MIPI CSI-2 devices must support one of primary formats */
+ mf->code = V4L2_MBUS_FMT_YUYV8_2X8;
+ }
+ break;
+ case SH_CSI2I:
+ switch (mf->code) {
+ case V4L2_MBUS_FMT_GREY8_1X8: /* RAW8 */
+ case V4L2_MBUS_FMT_SBGGR8_1X8:
+ case V4L2_MBUS_FMT_SGRBG8_1X8:
+ case V4L2_MBUS_FMT_SBGGR10_1X10: /* RAW10 */
+ case V4L2_MBUS_FMT_SBGGR12_1X12: /* RAW12 */
+ break;
+ default:
+ /* All MIPI CSI-2 devices must support one of primary formats */
+ mf->code = V4L2_MBUS_FMT_SBGGR8_1X8;
+ }
+ break;
+ }
+
+ return 0;
+}
+
+/*
+ * We have done our best in try_fmt to try and tell the sensor, which formats
+ * we support. If now the configuration is unsuitable for us we can only
+ * error out.
+ */
+static int sh_csi2_s_fmt(struct v4l2_subdev *sd,
+ struct v4l2_mbus_framefmt *mf)
+{
+ struct sh_csi2 *priv = container_of(sd, struct sh_csi2, subdev);
+ u32 tmp = (priv->client->channel & 3) << 8;
+
+ dev_dbg(sd->v4l2_dev->dev, "%s(%u)\n", __func__, mf->code);
+ if (mf->width > 8188 || mf->width & 1)
+ return -EINVAL;
+
+ switch (mf->code) {
+ case V4L2_MBUS_FMT_UYVY8_2X8:
+ tmp |= 0x1e; /* YUV422 8 bit */
+ break;
+ case V4L2_MBUS_FMT_YUYV8_1_5X8:
+ tmp |= 0x18; /* YUV420 8 bit */
+ break;
+ case V4L2_MBUS_FMT_RGB555_2X8_PADHI_BE:
+ tmp |= 0x21; /* RGB555 */
+ break;
+ case V4L2_MBUS_FMT_RGB565_2X8_BE:
+ tmp |= 0x22; /* RGB565 */
+ break;
+ case V4L2_MBUS_FMT_GREY8_1X8:
+ case V4L2_MBUS_FMT_SBGGR8_1X8:
+ case V4L2_MBUS_FMT_SGRBG8_1X8:
+ tmp |= 0x2a; /* RAW8 */
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ iowrite32(tmp, priv->base + SH_CSI2_VCDT);
+
+ return 0;
+}
+
+static struct v4l2_subdev_video_ops sh_csi2_subdev_video_ops = {
+ .s_mbus_fmt = sh_csi2_s_fmt,
+ .try_mbus_fmt = sh_csi2_try_fmt,
+};
+
+static struct v4l2_subdev_core_ops sh_csi2_subdev_core_ops;
+
+static struct v4l2_subdev_ops sh_csi2_subdev_ops = {
+ .core = &sh_csi2_subdev_core_ops,
+ .video = &sh_csi2_subdev_video_ops,
+};
+
+static void sh_csi2_hwinit(struct sh_csi2 *priv)
+{
+ struct sh_csi2_pdata *pdata = priv->pdev->dev.platform_data;
+ __u32 tmp = 0x10; /* Enable MIPI CSI clock lane */
+
+ /* Reflect registers immediately */
+ iowrite32(0x00000001, priv->base + SH_CSI2_TREF);
+ /* reset CSI2 harware */
+ iowrite32(0x00000001, priv->base + SH_CSI2_SRST);
+ udelay(5);
+ iowrite32(0x00000000, priv->base + SH_CSI2_SRST);
+
+ if (priv->client->lanes & 3)
+ tmp |= priv->client->lanes & 3;
+ else
+ /* Default - both lanes */
+ tmp |= 3;
+
+ if (priv->client->phy == SH_CSI2_PHY_MAIN)
+ tmp |= 0x8000;
+
+ iowrite32(tmp, priv->base + SH_CSI2_PHYCNT);
+
+ tmp = 0;
+ if (pdata->flags & SH_CSI2_ECC)
+ tmp |= 2;
+ if (pdata->flags & SH_CSI2_CRC)
+ tmp |= 1;
+ iowrite32(tmp, priv->base + SH_CSI2_CHKSUM);
+}
+
+static int sh_csi2_set_bus_param(struct soc_camera_device *icd,
+ unsigned long flags)
+{
+ return 0;
+}
+
+static unsigned long sh_csi2_query_bus_param(struct soc_camera_device *icd)
+{
+ struct soc_camera_link *icl = to_soc_camera_link(icd);
+ const unsigned long flags = SOCAM_PCLK_SAMPLE_RISING |
+ SOCAM_HSYNC_ACTIVE_HIGH | SOCAM_VSYNC_ACTIVE_HIGH |
+ SOCAM_MASTER | SOCAM_DATAWIDTH_8 | SOCAM_DATA_ACTIVE_HIGH;
+
+ return soc_camera_apply_sensor_flags(icl, flags);
+}
+
+static int sh_csi2_notify(struct notifier_block *nb,
+ unsigned long action, void *data)
+{
+ struct device *dev = data;
+ struct soc_camera_device *icd = to_soc_camera_dev(dev);
+ struct v4l2_device *v4l2_dev = dev_get_drvdata(dev->parent);
+ struct sh_csi2 *priv =
+ container_of(nb, struct sh_csi2, notifier);
+ struct sh_csi2_pdata *pdata = priv->pdev->dev.platform_data;
+ int ret, i;
+
+ for (i = 0; i < pdata->num_clients; i++)
+ if (&pdata->clients[i].pdev->dev == icd->pdev)
+ break;
+
+ dev_dbg(dev, "%s(%p): action = %lu, found #%d\n", __func__, dev, action, i);
+
+ if (i == pdata->num_clients)
+ return NOTIFY_DONE;
+
+ switch (action) {
+ case BUS_NOTIFY_BOUND_DRIVER:
+ snprintf(priv->subdev.name, V4L2_SUBDEV_NAME_SIZE, "%s%s",
+ dev_name(v4l2_dev->dev), ".mipi-csi");
+ ret = v4l2_device_register_subdev(v4l2_dev, &priv->subdev);
+ dev_dbg(dev, "%s(%p): ret(register_subdev) = %d\n", __func__, priv, ret);
+ if (ret < 0)
+ return NOTIFY_DONE;
+
+ priv->client = pdata->clients + i;
+
+ icd->ops->set_bus_param = sh_csi2_set_bus_param;
+ icd->ops->query_bus_param = sh_csi2_query_bus_param;
+
+ pm_runtime_get_sync(v4l2_get_subdevdata(&priv->subdev));
+
+ sh_csi2_hwinit(priv);
+ break;
+ case BUS_NOTIFY_UNBIND_DRIVER:
+ priv->client = NULL;
+
+ /* Driver is about to be unbound */
+ icd->ops->set_bus_param = NULL;
+ icd->ops->query_bus_param = NULL;
+
+ v4l2_device_unregister_subdev(&priv->subdev);
+
+ pm_runtime_put(v4l2_get_subdevdata(&priv->subdev));
+ break;
+ }
+
+ return NOTIFY_OK;
+}
+
+static __devinit int sh_csi2_probe(struct platform_device *pdev)
+{
+ struct resource *res;
+ unsigned int irq;
+ int ret;
+ struct sh_csi2 *priv;
+ /* Platform data specify the PHY, lanes, ECC, CRC */
+ struct sh_csi2_pdata *pdata = pdev->dev.platform_data;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ /* Interrupt unused so far */
+ irq = platform_get_irq(pdev, 0);
+
+ if (!res || (int)irq <= 0 || !pdata) {
+ dev_err(&pdev->dev, "Not enough CSI2 platform resources.\n");
+ return -ENODEV;
+ }
+
+ /* TODO: Add support for CSI2I. Careful: different register layout! */
+ if (pdata->type != SH_CSI2C) {
+ dev_err(&pdev->dev, "Only CSI2C supported ATM.\n");
+ return -EINVAL;
+ }
+
+ priv = kzalloc(sizeof(struct sh_csi2), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->irq = irq;
+ priv->notifier.notifier_call = sh_csi2_notify;
+
+ /* We MUST attach after the MIPI sensor */
+ ret = bus_register_notifier(&soc_camera_bus_type, &priv->notifier);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "CSI2 cannot register notifier\n");
+ goto ernotify;
+ }
+
+ if (!request_mem_region(res->start, resource_size(res), pdev->name)) {
+ dev_err(&pdev->dev, "CSI2 register region already claimed\n");
+ ret = -EBUSY;
+ goto ereqreg;
+ }
+
+ priv->base = ioremap(res->start, resource_size(res));
+ if (!priv->base) {
+ ret = -ENXIO;
+ dev_err(&pdev->dev, "Unable to ioremap CSI2 registers.\n");
+ goto eremap;
+ }
+
+ priv->pdev = pdev;
+
+ v4l2_subdev_init(&priv->subdev, &sh_csi2_subdev_ops);
+ v4l2_set_subdevdata(&priv->subdev, &pdev->dev);
+
+ platform_set_drvdata(pdev, priv);
+
+ pm_runtime_enable(&pdev->dev);
+
+ dev_dbg(&pdev->dev, "CSI2 probed.\n");
+
+ return 0;
+
+eremap:
+ release_mem_region(res->start, resource_size(res));
+ereqreg:
+ bus_unregister_notifier(&soc_camera_bus_type, &priv->notifier);
+ernotify:
+ kfree(priv);
+
+ return ret;
+}
+
+static __devexit int sh_csi2_remove(struct platform_device *pdev)
+{
+ struct sh_csi2 *priv = platform_get_drvdata(pdev);
+ struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+ bus_unregister_notifier(&soc_camera_bus_type, &priv->notifier);
+ pm_runtime_disable(&pdev->dev);
+ iounmap(priv->base);
+ release_mem_region(res->start, resource_size(res));
+ platform_set_drvdata(pdev, NULL);
+ kfree(priv);
+
+ return 0;
+}
+
+static struct platform_driver __refdata sh_csi2_pdrv = {
+ .remove = __devexit_p(sh_csi2_remove),
+ .driver = {
+ .name = "sh-mobile-csi2",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init sh_csi2_init(void)
+{
+ return platform_driver_probe(&sh_csi2_pdrv, sh_csi2_probe);
+}
+
+static void __exit sh_csi2_exit(void)
+{
+ platform_driver_unregister(&sh_csi2_pdrv);
+}
+
+module_init(sh_csi2_init);
+module_exit(sh_csi2_exit);
+
+MODULE_DESCRIPTION("SH-Mobile MIPI CSI-2 driver");
+MODULE_AUTHOR("Guennadi Liakhovetski <g.liakhovetski@gmx.de>");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:sh-mobile-csi2");
diff --git a/drivers/media/video/sh_vou.c b/drivers/media/video/sh_vou.c
index f5b892a2a8e..d394187eb70 100644
--- a/drivers/media/video/sh_vou.c
+++ b/drivers/media/video/sh_vou.c
@@ -18,6 +18,7 @@
#include <linux/kernel.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
+#include <linux/slab.h>
#include <linux/version.h>
#include <linux/videodev2.h>
@@ -57,7 +58,7 @@ enum sh_vou_status {
};
#define VOU_MAX_IMAGE_WIDTH 720
-#define VOU_MAX_IMAGE_HEIGHT 480
+#define VOU_MAX_IMAGE_HEIGHT 576
struct sh_vou_device {
struct v4l2_device v4l2_dev;
@@ -527,20 +528,17 @@ struct sh_vou_geometry {
static void vou_adjust_input(struct sh_vou_geometry *geo, v4l2_std_id std)
{
/* The compiler cannot know, that best and idx will indeed be set */
- unsigned int best_err = UINT_MAX, best = 0, width_max, height_max;
+ unsigned int best_err = UINT_MAX, best = 0, img_height_max;
int i, idx = 0;
- if (std & V4L2_STD_525_60) {
- width_max = 858;
- height_max = 262;
- } else {
- width_max = 864;
- height_max = 312;
- }
+ if (std & V4L2_STD_525_60)
+ img_height_max = 480;
+ else
+ img_height_max = 576;
/* Image width must be a multiple of 4 */
v4l_bound_align_image(&geo->in_width, 0, VOU_MAX_IMAGE_WIDTH, 2,
- &geo->in_height, 0, VOU_MAX_IMAGE_HEIGHT, 1, 0);
+ &geo->in_height, 0, img_height_max, 1, 0);
/* Select scales to come as close as possible to the output image */
for (i = ARRAY_SIZE(vou_scale_h_num) - 1; i >= 0; i--) {
@@ -573,7 +571,7 @@ static void vou_adjust_input(struct sh_vou_geometry *geo, v4l2_std_id std)
unsigned int found = geo->output.height * vou_scale_v_den[i] /
vou_scale_v_num[i];
- if (found > VOU_MAX_IMAGE_HEIGHT)
+ if (found > img_height_max)
/* scales increase */
break;
@@ -597,15 +595,18 @@ static void vou_adjust_input(struct sh_vou_geometry *geo, v4l2_std_id std)
*/
static void vou_adjust_output(struct sh_vou_geometry *geo, v4l2_std_id std)
{
- unsigned int best_err = UINT_MAX, best, width_max, height_max;
+ unsigned int best_err = UINT_MAX, best, width_max, height_max,
+ img_height_max;
int i, idx;
if (std & V4L2_STD_525_60) {
width_max = 858;
height_max = 262 * 2;
+ img_height_max = 480;
} else {
width_max = 864;
height_max = 312 * 2;
+ img_height_max = 576;
}
/* Select scales to come as close as possible to the output image */
@@ -644,7 +645,7 @@ static void vou_adjust_output(struct sh_vou_geometry *geo, v4l2_std_id std)
unsigned int found = geo->in_height * vou_scale_v_num[i] /
vou_scale_v_den[i];
- if (found > VOU_MAX_IMAGE_HEIGHT)
+ if (found > img_height_max)
/* scales increase */
break;
@@ -673,11 +674,12 @@ static int sh_vou_s_fmt_vid_out(struct file *file, void *priv,
struct video_device *vdev = video_devdata(file);
struct sh_vou_device *vou_dev = video_get_drvdata(vdev);
struct v4l2_pix_format *pix = &fmt->fmt.pix;
+ unsigned int img_height_max;
int pix_idx;
struct sh_vou_geometry geo;
struct v4l2_mbus_framefmt mbfmt = {
/* Revisit: is this the correct code? */
- .code = V4L2_MBUS_FMT_YUYV8_2X8_LE,
+ .code = V4L2_MBUS_FMT_YUYV8_2X8,
.field = V4L2_FIELD_INTERLACED,
.colorspace = V4L2_COLORSPACE_SMPTE170M,
};
@@ -701,9 +703,14 @@ static int sh_vou_s_fmt_vid_out(struct file *file, void *priv,
if (pix_idx == ARRAY_SIZE(vou_fmt))
return -EINVAL;
+ if (vou_dev->std & V4L2_STD_525_60)
+ img_height_max = 480;
+ else
+ img_height_max = 576;
+
/* Image width must be a multiple of 4 */
v4l_bound_align_image(&pix->width, 0, VOU_MAX_IMAGE_WIDTH, 2,
- &pix->height, 0, VOU_MAX_IMAGE_HEIGHT, 1, 0);
+ &pix->height, 0, img_height_max, 1, 0);
geo.in_width = pix->width;
geo.in_height = pix->height;
@@ -724,8 +731,8 @@ static int sh_vou_s_fmt_vid_out(struct file *file, void *priv,
/* Sanity checks */
if ((unsigned)mbfmt.width > VOU_MAX_IMAGE_WIDTH ||
- (unsigned)mbfmt.height > VOU_MAX_IMAGE_HEIGHT ||
- mbfmt.code != V4L2_MBUS_FMT_YUYV8_2X8_LE)
+ (unsigned)mbfmt.height > img_height_max ||
+ mbfmt.code != V4L2_MBUS_FMT_YUYV8_2X8)
return -EIO;
if (mbfmt.width != geo.output.width ||
@@ -936,10 +943,11 @@ static int sh_vou_s_crop(struct file *file, void *fh, struct v4l2_crop *a)
struct sh_vou_geometry geo;
struct v4l2_mbus_framefmt mbfmt = {
/* Revisit: is this the correct code? */
- .code = V4L2_MBUS_FMT_YUYV8_2X8_LE,
+ .code = V4L2_MBUS_FMT_YUYV8_2X8,
.field = V4L2_FIELD_INTERLACED,
.colorspace = V4L2_COLORSPACE_SMPTE170M,
};
+ unsigned int img_height_max;
int ret;
dev_dbg(vou_dev->v4l2_dev.dev, "%s(): %ux%u@%u:%u\n", __func__,
@@ -948,14 +956,19 @@ static int sh_vou_s_crop(struct file *file, void *fh, struct v4l2_crop *a)
if (a->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
return -EINVAL;
+ if (vou_dev->std & V4L2_STD_525_60)
+ img_height_max = 480;
+ else
+ img_height_max = 576;
+
v4l_bound_align_image(&rect->width, 0, VOU_MAX_IMAGE_WIDTH, 1,
- &rect->height, 0, VOU_MAX_IMAGE_HEIGHT, 1, 0);
+ &rect->height, 0, img_height_max, 1, 0);
if (rect->width + rect->left > VOU_MAX_IMAGE_WIDTH)
rect->left = VOU_MAX_IMAGE_WIDTH - rect->width;
- if (rect->height + rect->top > VOU_MAX_IMAGE_HEIGHT)
- rect->top = VOU_MAX_IMAGE_HEIGHT - rect->height;
+ if (rect->height + rect->top > img_height_max)
+ rect->top = img_height_max - rect->height;
geo.output = *rect;
geo.in_width = pix->width;
@@ -980,8 +993,8 @@ static int sh_vou_s_crop(struct file *file, void *fh, struct v4l2_crop *a)
/* Sanity checks */
if ((unsigned)mbfmt.width > VOU_MAX_IMAGE_WIDTH ||
- (unsigned)mbfmt.height > VOU_MAX_IMAGE_HEIGHT ||
- mbfmt.code != V4L2_MBUS_FMT_YUYV8_2X8_LE)
+ (unsigned)mbfmt.height > img_height_max ||
+ mbfmt.code != V4L2_MBUS_FMT_YUYV8_2X8)
return -EIO;
geo.output.width = mbfmt.width;
@@ -1329,13 +1342,13 @@ static int __devinit sh_vou_probe(struct platform_device *pdev)
rect->left = 0;
rect->top = 0;
rect->width = VOU_MAX_IMAGE_WIDTH;
- rect->height = VOU_MAX_IMAGE_HEIGHT;
+ rect->height = 480;
pix->width = VOU_MAX_IMAGE_WIDTH;
- pix->height = VOU_MAX_IMAGE_HEIGHT;
+ pix->height = 480;
pix->pixelformat = V4L2_PIX_FMT_YVYU;
pix->field = V4L2_FIELD_NONE;
pix->bytesperline = VOU_MAX_IMAGE_WIDTH * 2;
- pix->sizeimage = VOU_MAX_IMAGE_WIDTH * 2 * VOU_MAX_IMAGE_HEIGHT;
+ pix->sizeimage = VOU_MAX_IMAGE_WIDTH * 2 * 480;
pix->colorspace = V4L2_COLORSPACE_SMPTE170M;
region = request_mem_region(reg_res->start, resource_size(reg_res),
diff --git a/drivers/media/video/soc_camera.c b/drivers/media/video/soc_camera.c
index 475757bfd7b..f2032939fd4 100644
--- a/drivers/media/video/soc_camera.c
+++ b/drivers/media/video/soc_camera.c
@@ -1107,13 +1107,14 @@ static int soc_camera_resume(struct device *dev)
return ret;
}
-static struct bus_type soc_camera_bus_type = {
+struct bus_type soc_camera_bus_type = {
.name = "soc-camera",
.probe = soc_camera_probe,
.remove = soc_camera_remove,
.suspend = soc_camera_suspend,
.resume = soc_camera_resume,
};
+EXPORT_SYMBOL_GPL(soc_camera_bus_type);
static struct device_driver ic_drv = {
.name = "camera",
diff --git a/drivers/media/video/soc_camera_platform.c b/drivers/media/video/soc_camera_platform.c
index 248c986f098..bf406e89c99 100644
--- a/drivers/media/video/soc_camera_platform.c
+++ b/drivers/media/video/soc_camera_platform.c
@@ -56,8 +56,8 @@ soc_camera_platform_query_bus_param(struct soc_camera_device *icd)
return p->bus_param;
}
-static int soc_camera_platform_try_fmt(struct v4l2_subdev *sd,
- struct v4l2_mbus_framefmt *mf)
+static int soc_camera_platform_fill_fmt(struct v4l2_subdev *sd,
+ struct v4l2_mbus_framefmt *mf)
{
struct soc_camera_platform_info *p = v4l2_get_subdevdata(sd);
@@ -65,6 +65,7 @@ static int soc_camera_platform_try_fmt(struct v4l2_subdev *sd,
mf->height = p->format.height;
mf->code = p->format.code;
mf->colorspace = p->format.colorspace;
+ mf->field = p->format.field;
return 0;
}
@@ -83,10 +84,45 @@ static int soc_camera_platform_enum_fmt(struct v4l2_subdev *sd, unsigned int ind
return 0;
}
+static int soc_camera_platform_g_crop(struct v4l2_subdev *sd,
+ struct v4l2_crop *a)
+{
+ struct soc_camera_platform_info *p = v4l2_get_subdevdata(sd);
+
+ a->c.left = 0;
+ a->c.top = 0;
+ a->c.width = p->format.width;
+ a->c.height = p->format.height;
+ a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+ return 0;
+}
+
+static int soc_camera_platform_cropcap(struct v4l2_subdev *sd,
+ struct v4l2_cropcap *a)
+{
+ struct soc_camera_platform_info *p = v4l2_get_subdevdata(sd);
+
+ a->bounds.left = 0;
+ a->bounds.top = 0;
+ a->bounds.width = p->format.width;
+ a->bounds.height = p->format.height;
+ a->defrect = a->bounds;
+ a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ a->pixelaspect.numerator = 1;
+ a->pixelaspect.denominator = 1;
+
+ return 0;
+}
+
static struct v4l2_subdev_video_ops platform_subdev_video_ops = {
.s_stream = soc_camera_platform_s_stream,
- .try_mbus_fmt = soc_camera_platform_try_fmt,
.enum_mbus_fmt = soc_camera_platform_enum_fmt,
+ .cropcap = soc_camera_platform_cropcap,
+ .g_crop = soc_camera_platform_g_crop,
+ .try_mbus_fmt = soc_camera_platform_fill_fmt,
+ .g_mbus_fmt = soc_camera_platform_fill_fmt,
+ .s_mbus_fmt = soc_camera_platform_fill_fmt,
};
static struct v4l2_subdev_ops platform_subdev_ops = {
diff --git a/drivers/media/video/soc_mediabus.c b/drivers/media/video/soc_mediabus.c
index 8b63b6545e7..91391214c68 100644
--- a/drivers/media/video/soc_mediabus.c
+++ b/drivers/media/video/soc_mediabus.c
@@ -18,28 +18,28 @@
#define MBUS_IDX(f) (V4L2_MBUS_FMT_ ## f - V4L2_MBUS_FMT_FIXED - 1)
static const struct soc_mbus_pixelfmt mbus_fmt[] = {
- [MBUS_IDX(YUYV8_2X8_LE)] = {
+ [MBUS_IDX(YUYV8_2X8)] = {
.fourcc = V4L2_PIX_FMT_YUYV,
.name = "YUYV",
.bits_per_sample = 8,
.packing = SOC_MBUS_PACKING_2X8_PADHI,
.order = SOC_MBUS_ORDER_LE,
},
- [MBUS_IDX(YVYU8_2X8_LE)] = {
+ [MBUS_IDX(YVYU8_2X8)] = {
.fourcc = V4L2_PIX_FMT_YVYU,
.name = "YVYU",
.bits_per_sample = 8,
.packing = SOC_MBUS_PACKING_2X8_PADHI,
.order = SOC_MBUS_ORDER_LE,
},
- [MBUS_IDX(YUYV8_2X8_BE)] = {
+ [MBUS_IDX(UYVY8_2X8)] = {
.fourcc = V4L2_PIX_FMT_UYVY,
.name = "UYVY",
.bits_per_sample = 8,
.packing = SOC_MBUS_PACKING_2X8_PADHI,
.order = SOC_MBUS_ORDER_LE,
},
- [MBUS_IDX(YVYU8_2X8_BE)] = {
+ [MBUS_IDX(VYUY8_2X8)] = {
.fourcc = V4L2_PIX_FMT_VYUY,
.name = "VYUY",
.bits_per_sample = 8,
diff --git a/drivers/media/video/stv680.c b/drivers/media/video/stv680.c
deleted file mode 100644
index 5938ad8702e..00000000000
--- a/drivers/media/video/stv680.c
+++ /dev/null
@@ -1,1565 +0,0 @@
-/*
- * STV0680 USB Camera Driver, by Kevin Sisson (kjsisson@bellsouth.net)
- *
- * Thanks to STMicroelectronics for information on the usb commands, and
- * to Steve Miller at STM for his help and encouragement while I was
- * writing this driver.
- *
- * This driver is based heavily on the
- * Endpoints (formerly known as AOX) se401 USB Camera Driver
- * Copyright (c) 2000 Jeroen B. Vreeken (pe1rxq@amsat.org)
- *
- * Still somewhat based on the Linux ov511 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 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.
- *
- * History:
- * ver 0.1 October, 2001. Initial attempt.
- *
- * ver 0.2 November, 2001. Fixed asbility to resize, added brightness
- * function, made more stable (?)
- *
- * ver 0.21 Nov, 2001. Added gamma correction and white balance,
- * due to Alexander Schwartz. Still trying to
- * improve stablility. Moved stuff into stv680.h
- *
- * ver 0.22 Nov, 2001. Added sharpen function (by Michael Sweet,
- * mike@easysw.com) from GIMP, also used in pencam.
- * Simple, fast, good integer math routine.
- *
- * ver 0.23 Dec, 2001 (gkh)
- * Took out sharpen function, ran code through
- * Lindent, and did other minor tweaks to get
- * things to work properly with 2.5.1
- *
- * ver 0.24 Jan, 2002 (kjs)
- * Fixed the problem with webcam crashing after
- * two pictures. Changed the way pic is halved to
- * improve quality. Got rid of green line around
- * frame. Fix brightness reset when changing size
- * bug. Adjusted gamma filters slightly.
- *
- * ver 0.25 Jan, 2002 (kjs)
- * Fixed a bug in which the driver sometimes attempted
- * to set to a non-supported size. This allowed
- * gnomemeeting to work.
- * Fixed proc entry removal bug.
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/vmalloc.h>
-#include <linux/slab.h>
-#include <linux/smp_lock.h>
-#include <linux/pagemap.h>
-#include <linux/errno.h>
-#include <linux/videodev.h>
-#include <media/v4l2-common.h>
-#include <media/v4l2-ioctl.h>
-#include <linux/usb.h>
-#include <linux/mutex.h>
-
-#include "stv680.h"
-
-static int video_nr = -1;
-
-static int swapRGB; /* 0 = default for auto select */
-
-/* 0 = default to allow auto select; -1 = swap never, +1 = swap always */
-static int swapRGB_on;
-
-static unsigned int debug;
-
-#define PDEBUG(level, fmt, args...) \
- do { \
- if (debug >= level) \
- printk(KERN_INFO KBUILD_MODNAME " [%s:%d] \n" fmt, \
- __func__, __LINE__ , ## args); \
- } while (0)
-
-
-/*
- * Version Information
- */
-#define DRIVER_VERSION "v0.25"
-#define DRIVER_AUTHOR "Kevin Sisson <kjsisson@bellsouth.net>"
-#define DRIVER_DESC "STV0680 USB Camera Driver"
-
-MODULE_AUTHOR (DRIVER_AUTHOR);
-MODULE_DESCRIPTION (DRIVER_DESC);
-MODULE_LICENSE ("GPL");
-module_param(debug, int, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC (debug, "Debug enabled or not");
-module_param(swapRGB_on, int, 0);
-MODULE_PARM_DESC (swapRGB_on, "Red/blue swap: 1=always, 0=auto, -1=never");
-module_param(video_nr, int, 0);
-
-/********************************************************************
- *
- * Memory management
- *
- * This is a shameless copy from the USB-cpia driver (linux kernel
- * version 2.3.29 or so, I have no idea what this code actually does ;).
- * Actually it seems to be a copy of a shameless copy of the bttv-driver.
- * Or that is a copy of a shameless copy of ... (To the powers: is there
- * no generic kernel-function to do this sort of stuff?)
- *
- * Yes, it was a shameless copy from the bttv-driver. IIRC, Alan says
- * there will be one, but apparentely not yet -jerdfelt
- *
- * So I copied it again for the ov511 driver -claudio
- *
- * Same for the se401 driver -Jeroen
- *
- * And the STV0680 driver - Kevin
- ********************************************************************/
-static void *rvmalloc (unsigned long size)
-{
- void *mem;
- unsigned long adr;
-
- size = PAGE_ALIGN(size);
- mem = vmalloc_32 (size);
- if (!mem)
- return NULL;
-
- memset (mem, 0, size); /* Clear the ram out, no junk to the user */
- adr = (unsigned long) mem;
- while (size > 0) {
- SetPageReserved(vmalloc_to_page((void *)adr));
- adr += PAGE_SIZE;
- size -= PAGE_SIZE;
- }
- return mem;
-}
-
-static void rvfree (void *mem, unsigned long size)
-{
- unsigned long adr;
-
- if (!mem)
- return;
-
- adr = (unsigned long) mem;
- while ((long) size > 0) {
- ClearPageReserved(vmalloc_to_page((void *)adr));
- adr += PAGE_SIZE;
- size -= PAGE_SIZE;
- }
- vfree (mem);
-}
-
-
-/*********************************************************************
- * pencam read/write functions
- ********************************************************************/
-
-static int stv_sndctrl (int set, struct usb_stv *stv680, unsigned short req, unsigned short value, unsigned char *buffer, int size)
-{
- int ret = -1;
-
- switch (set) {
- case 0: /* 0xc1 */
- ret = usb_control_msg (stv680->udev,
- usb_rcvctrlpipe (stv680->udev, 0),
- req,
- (USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_ENDPOINT),
- value, 0, buffer, size, PENCAM_TIMEOUT);
- break;
-
- case 1: /* 0x41 */
- ret = usb_control_msg (stv680->udev,
- usb_sndctrlpipe (stv680->udev, 0),
- req,
- (USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_ENDPOINT),
- value, 0, buffer, size, PENCAM_TIMEOUT);
- break;
-
- case 2: /* 0x80 */
- ret = usb_control_msg (stv680->udev,
- usb_rcvctrlpipe (stv680->udev, 0),
- req,
- (USB_DIR_IN | USB_RECIP_DEVICE),
- value, 0, buffer, size, PENCAM_TIMEOUT);
- break;
-
- case 3: /* 0x40 */
- ret = usb_control_msg (stv680->udev,
- usb_sndctrlpipe (stv680->udev, 0),
- req,
- (USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE),
- value, 0, buffer, size, PENCAM_TIMEOUT);
- break;
-
- }
- if ((ret < 0) && (req != 0x0a)) {
- PDEBUG (1, "STV(e): usb_control_msg error %i, request = 0x%x, error = %i", set, req, ret);
- }
- return ret;
-}
-
-static int stv_set_config (struct usb_stv *dev, int configuration, int interface, int alternate)
-{
-
- if (configuration != dev->udev->actconfig->desc.bConfigurationValue
- || usb_reset_configuration (dev->udev) < 0) {
- PDEBUG (1, "STV(e): FAILED to reset configuration %i", configuration);
- return -1;
- }
- if (usb_set_interface (dev->udev, interface, alternate) < 0) {
- PDEBUG (1, "STV(e): FAILED to set alternate interface %i", alternate);
- return -1;
- }
- return 0;
-}
-
-static int stv_stop_video (struct usb_stv *dev)
-{
- int i;
- unsigned char *buf;
-
- buf = kmalloc (40, GFP_KERNEL);
- if (buf == NULL) {
- PDEBUG (0, "STV(e): Out of (small buf) memory");
- return -1;
- }
-
- /* this is a high priority command; it stops all lower order commands */
- if ((i = stv_sndctrl (1, dev, 0x04, 0x0000, buf, 0x0)) < 0) {
- i = stv_sndctrl (0, dev, 0x80, 0, buf, 0x02); /* Get Last Error; 2 = busy */
- PDEBUG (1, "STV(i): last error: %i, command = 0x%x", buf[0], buf[1]);
- } else {
- PDEBUG (1, "STV(i): Camera reset to idle mode.");
- }
-
- if ((i = stv_set_config (dev, 1, 0, 0)) < 0)
- PDEBUG (1, "STV(e): Reset config during exit failed");
-
- /* get current mode */
- buf[0] = 0xf0;
- if ((i = stv_sndctrl (0, dev, 0x87, 0, buf, 0x08)) != 0x08) /* get mode */
- PDEBUG (0, "STV(e): Stop_video: problem setting original mode");
- if (dev->origMode != buf[0]) {
- memset (buf, 0, 8);
- buf[0] = (unsigned char) dev->origMode;
- if ((i = stv_sndctrl (3, dev, 0x07, 0x0100, buf, 0x08)) != 0x08) {
- PDEBUG (0, "STV(e): Stop_video: Set_Camera_Mode failed");
- i = -1;
- }
- buf[0] = 0xf0;
- i = stv_sndctrl (0, dev, 0x87, 0, buf, 0x08);
- if ((i != 0x08) || (buf[0] != dev->origMode)) {
- PDEBUG (0, "STV(e): camera NOT set to original resolution.");
- i = -1;
- } else
- PDEBUG (0, "STV(i): Camera set to original resolution");
- }
- /* origMode */
- kfree(buf);
- return i;
-}
-
-static int stv_set_video_mode (struct usb_stv *dev)
-{
- int i, stop_video = 1;
- unsigned char *buf;
-
- buf = kmalloc (40, GFP_KERNEL);
- if (buf == NULL) {
- PDEBUG (0, "STV(e): Out of (small buf) memory");
- return -1;
- }
-
- if ((i = stv_set_config (dev, 1, 0, 0)) < 0) {
- kfree(buf);
- return i;
- }
-
- i = stv_sndctrl (2, dev, 0x06, 0x0100, buf, 0x12);
- if (!(i > 0) && (buf[8] == 0x53) && (buf[9] == 0x05)) {
- PDEBUG (1, "STV(e): Could not get descriptor 0100.");
- goto error;
- }
-
- /* set alternate interface 1 */
- if ((i = stv_set_config (dev, 1, 0, 1)) < 0)
- goto error;
-
- if ((i = stv_sndctrl (0, dev, 0x85, 0, buf, 0x10)) != 0x10)
- goto error;
- PDEBUG (1, "STV(i): Setting video mode.");
- /* Switch to Video mode: 0x0100 = VGA (640x480), 0x0000 = CIF (352x288) 0x0300 = QVGA (320x240) */
- if ((i = stv_sndctrl (1, dev, 0x09, dev->VideoMode, buf, 0x0)) < 0) {
- stop_video = 0;
- goto error;
- }
- goto exit;
-
-error:
- kfree(buf);
- if (stop_video == 1)
- stv_stop_video (dev);
- return -1;
-
-exit:
- kfree(buf);
- return 0;
-}
-
-static int stv_init (struct usb_stv *stv680)
-{
- int i = 0;
- unsigned char *buffer;
- unsigned long int bufsize;
-
- buffer = kzalloc (40, GFP_KERNEL);
- if (buffer == NULL) {
- PDEBUG (0, "STV(e): Out of (small buf) memory");
- return -1;
- }
- udelay (100);
-
- /* set config 1, interface 0, alternate 0 */
- if ((i = stv_set_config (stv680, 1, 0, 0)) < 0) {
- kfree(buffer);
- PDEBUG (0, "STV(e): set config 1,0,0 failed");
- return -1;
- }
- /* ping camera to be sure STV0680 is present */
- if ((i = stv_sndctrl (0, stv680, 0x88, 0x5678, buffer, 0x02)) != 0x02)
- goto error;
- if ((buffer[0] != 0x56) || (buffer[1] != 0x78)) {
- PDEBUG (1, "STV(e): camera ping failed!!");
- goto error;
- }
-
- /* get camera descriptor */
- if ((i = stv_sndctrl (2, stv680, 0x06, 0x0200, buffer, 0x09)) != 0x09)
- goto error;
- i = stv_sndctrl (2, stv680, 0x06, 0x0200, buffer, 0x22);
- if (!(i >= 0) && (buffer[7] == 0xa0) && (buffer[8] == 0x23)) {
- PDEBUG (1, "STV(e): Could not get descriptor 0200.");
- goto error;
- }
- if ((i = stv_sndctrl (0, stv680, 0x8a, 0, buffer, 0x02)) != 0x02)
- goto error;
- if ((i = stv_sndctrl (0, stv680, 0x8b, 0, buffer, 0x24)) != 0x24)
- goto error;
- if ((i = stv_sndctrl (0, stv680, 0x85, 0, buffer, 0x10)) != 0x10)
- goto error;
-
- stv680->SupportedModes = buffer[7];
- i = stv680->SupportedModes;
- stv680->CIF = 0;
- stv680->VGA = 0;
- stv680->QVGA = 0;
- if (i & 1)
- stv680->CIF = 1;
- if (i & 2)
- stv680->VGA = 1;
- if (i & 8)
- stv680->QVGA = 1;
- if (stv680->SupportedModes == 0) {
- PDEBUG (0, "STV(e): There are NO supported STV680 modes!!");
- i = -1;
- goto error;
- } else {
- if (stv680->CIF)
- PDEBUG (0, "STV(i): CIF is supported");
- if (stv680->QVGA)
- PDEBUG (0, "STV(i): QVGA is supported");
- }
- /* FW rev, ASIC rev, sensor ID */
- PDEBUG (1, "STV(i): Firmware rev is %i.%i", buffer[0], buffer[1]);
- PDEBUG (1, "STV(i): ASIC rev is %i.%i", buffer[2], buffer[3]);
- PDEBUG (1, "STV(i): Sensor ID is %i", (buffer[4]*16) + (buffer[5]>>4));
-
- /* set alternate interface 1 */
- if ((i = stv_set_config (stv680, 1, 0, 1)) < 0)
- goto error;
-
- if ((i = stv_sndctrl (0, stv680, 0x85, 0, buffer, 0x10)) != 0x10)
- goto error;
- if ((i = stv_sndctrl (0, stv680, 0x8d, 0, buffer, 0x08)) != 0x08)
- goto error;
- i = buffer[3];
- PDEBUG (0, "STV(i): Camera has %i pictures.", i);
-
- /* get current mode */
- if ((i = stv_sndctrl (0, stv680, 0x87, 0, buffer, 0x08)) != 0x08)
- goto error;
- stv680->origMode = buffer[0]; /* 01 = VGA, 03 = QVGA, 00 = CIF */
-
- /* This will attemp CIF mode, if supported. If not, set to QVGA */
- memset (buffer, 0, 8);
- if (stv680->CIF)
- buffer[0] = 0x00;
- else if (stv680->QVGA)
- buffer[0] = 0x03;
- if ((i = stv_sndctrl (3, stv680, 0x07, 0x0100, buffer, 0x08)) != 0x08) {
- PDEBUG (0, "STV(i): Set_Camera_Mode failed");
- i = -1;
- goto error;
- }
- buffer[0] = 0xf0;
- stv_sndctrl (0, stv680, 0x87, 0, buffer, 0x08);
- if (((stv680->CIF == 1) && (buffer[0] != 0x00)) || ((stv680->QVGA == 1) && (buffer[0] != 0x03))) {
- PDEBUG (0, "STV(e): Error setting camera video mode!");
- i = -1;
- goto error;
- } else {
- if (buffer[0] == 0) {
- stv680->VideoMode = 0x0000;
- PDEBUG (0, "STV(i): Video Mode set to CIF");
- }
- if (buffer[0] == 0x03) {
- stv680->VideoMode = 0x0300;
- PDEBUG (0, "STV(i): Video Mode set to QVGA");
- }
- }
- if ((i = stv_sndctrl (0, stv680, 0x8f, 0, buffer, 0x10)) != 0x10)
- goto error;
- bufsize = (buffer[0] << 24) | (buffer[1] << 16) | (buffer[2] << 8) | (buffer[3]);
- stv680->cwidth = (buffer[4] << 8) | (buffer[5]); /* ->camera = 322, 356, 644 */
- stv680->cheight = (buffer[6] << 8) | (buffer[7]); /* ->camera = 242, 292, 484 */
- stv680->origGain = buffer[12];
-
- goto exit;
-
-error:
- i = stv_sndctrl (0, stv680, 0x80, 0, buffer, 0x02); /* Get Last Error */
- PDEBUG (1, "STV(i): last error: %i, command = 0x%x", buffer[0], buffer[1]);
- kfree(buffer);
- return -1;
-
-exit:
- kfree(buffer);
-
- /* video = 320x240, 352x288 */
- if (stv680->CIF == 1) {
- stv680->maxwidth = 352;
- stv680->maxheight = 288;
- stv680->vwidth = 352;
- stv680->vheight = 288;
- }
- if (stv680->QVGA == 1) {
- stv680->maxwidth = 320;
- stv680->maxheight = 240;
- stv680->vwidth = 320;
- stv680->vheight = 240;
- }
-
- stv680->rawbufsize = bufsize; /* must be ./. by 8 */
- stv680->maxframesize = bufsize * 3; /* RGB size */
- PDEBUG (2, "STV(i): cwidth = %i, cheight = %i", stv680->cwidth, stv680->cheight);
- PDEBUG (1, "STV(i): width = %i, height = %i, rawbufsize = %li", stv680->vwidth, stv680->vheight, stv680->rawbufsize);
-
- /* some default values */
- stv680->bulk_in_endpointAddr = 0x82;
- stv680->dropped = 0;
- stv680->error = 0;
- stv680->framecount = 0;
- stv680->readcount = 0;
- stv680->streaming = 0;
- /* bright, white, colour, hue, contrast are set by software, not in stv0680 */
- stv680->brightness = 32767;
- stv680->chgbright = 0;
- stv680->whiteness = 0; /* only for greyscale */
- stv680->colour = 32767;
- stv680->contrast = 32767;
- stv680->hue = 32767;
- stv680->palette = STV_VIDEO_PALETTE;
- stv680->depth = 24; /* rgb24 bits */
- if ((swapRGB_on == 0) && (swapRGB == 0))
- PDEBUG (1, "STV(i): swapRGB is (auto) OFF");
- else if ((swapRGB_on == 0) && (swapRGB == 1))
- PDEBUG (1, "STV(i): swapRGB is (auto) ON");
- else if (swapRGB_on == 1)
- PDEBUG (1, "STV(i): swapRGB is (forced) ON");
- else if (swapRGB_on == -1)
- PDEBUG (1, "STV(i): swapRGB is (forced) OFF");
-
- if (stv_set_video_mode (stv680) < 0) {
- PDEBUG (0, "STV(e): Could not set video mode in stv_init");
- return -1;
- }
-
- return 0;
-}
-
-/***************** last of pencam routines *******************/
-
-/****************************************************************************
- * sysfs
- ***************************************************************************/
-#define stv680_file(name, variable, field) \
-static ssize_t show_##name(struct device *class_dev, \
- struct device_attribute *attr, char *buf) \
-{ \
- struct video_device *vdev = to_video_device(class_dev); \
- struct usb_stv *stv = video_get_drvdata(vdev); \
- return sprintf(buf, field, stv->variable); \
-} \
-static DEVICE_ATTR(name, S_IRUGO, show_##name, NULL);
-
-stv680_file(model, camera_name, "%s\n");
-stv680_file(in_use, user, "%d\n");
-stv680_file(streaming, streaming, "%d\n");
-stv680_file(palette, palette, "%i\n");
-stv680_file(frames_total, readcount, "%d\n");
-stv680_file(frames_read, framecount, "%d\n");
-stv680_file(packets_dropped, dropped, "%d\n");
-stv680_file(decoding_errors, error, "%d\n");
-
-static int stv680_create_sysfs_files(struct video_device *vdev)
-{
- int rc;
-
- rc = device_create_file(&vdev->dev, &dev_attr_model);
- if (rc) goto err;
- rc = device_create_file(&vdev->dev, &dev_attr_in_use);
- if (rc) goto err_model;
- rc = device_create_file(&vdev->dev, &dev_attr_streaming);
- if (rc) goto err_inuse;
- rc = device_create_file(&vdev->dev, &dev_attr_palette);
- if (rc) goto err_stream;
- rc = device_create_file(&vdev->dev, &dev_attr_frames_total);
- if (rc) goto err_pal;
- rc = device_create_file(&vdev->dev, &dev_attr_frames_read);
- if (rc) goto err_framtot;
- rc = device_create_file(&vdev->dev, &dev_attr_packets_dropped);
- if (rc) goto err_framread;
- rc = device_create_file(&vdev->dev, &dev_attr_decoding_errors);
- if (rc) goto err_dropped;
-
- return 0;
-
-err_dropped:
- device_remove_file(&vdev->dev, &dev_attr_packets_dropped);
-err_framread:
- device_remove_file(&vdev->dev, &dev_attr_frames_read);
-err_framtot:
- device_remove_file(&vdev->dev, &dev_attr_frames_total);
-err_pal:
- device_remove_file(&vdev->dev, &dev_attr_palette);
-err_stream:
- device_remove_file(&vdev->dev, &dev_attr_streaming);
-err_inuse:
- device_remove_file(&vdev->dev, &dev_attr_in_use);
-err_model:
- device_remove_file(&vdev->dev, &dev_attr_model);
-err:
- PDEBUG(0, "STV(e): Could not create sysfs files");
- return rc;
-}
-
-static void stv680_remove_sysfs_files(struct video_device *vdev)
-{
- device_remove_file(&vdev->dev, &dev_attr_model);
- device_remove_file(&vdev->dev, &dev_attr_in_use);
- device_remove_file(&vdev->dev, &dev_attr_streaming);
- device_remove_file(&vdev->dev, &dev_attr_palette);
- device_remove_file(&vdev->dev, &dev_attr_frames_total);
- device_remove_file(&vdev->dev, &dev_attr_frames_read);
- device_remove_file(&vdev->dev, &dev_attr_packets_dropped);
- device_remove_file(&vdev->dev, &dev_attr_decoding_errors);
-}
-
-/********************************************************************
- * Camera control
- *******************************************************************/
-
-static int stv680_get_pict (struct usb_stv *stv680, struct video_picture *p)
-{
- /* This sets values for v4l interface. max/min = 65535/0 */
-
- p->brightness = stv680->brightness;
- p->whiteness = stv680->whiteness; /* greyscale */
- p->colour = stv680->colour;
- p->contrast = stv680->contrast;
- p->hue = stv680->hue;
- p->palette = stv680->palette;
- p->depth = stv680->depth;
- return 0;
-}
-
-static int stv680_set_pict (struct usb_stv *stv680, struct video_picture *p)
-{
- /* See above stv680_get_pict */
-
- if (p->palette != STV_VIDEO_PALETTE) {
- PDEBUG (2, "STV(e): Palette set error in _set_pic");
- return 1;
- }
-
- if (stv680->brightness != p->brightness) {
- stv680->chgbright = 1;
- stv680->brightness = p->brightness;
- }
-
- stv680->whiteness = p->whiteness; /* greyscale */
- stv680->colour = p->colour;
- stv680->contrast = p->contrast;
- stv680->hue = p->hue;
- stv680->palette = p->palette;
- stv680->depth = p->depth;
-
- return 0;
-}
-
-static void stv680_video_irq (struct urb *urb)
-{
- struct usb_stv *stv680 = urb->context;
- int length = urb->actual_length;
-
- if (length < stv680->rawbufsize)
- PDEBUG (2, "STV(i): Lost data in transfer: exp %li, got %i", stv680->rawbufsize, length);
-
- /* ohoh... */
- if (!stv680->streaming)
- return;
-
- if (!stv680->udev) {
- PDEBUG (0, "STV(e): device vapourished in video_irq");
- return;
- }
-
- /* 0 sized packets happen if we are to fast, but sometimes the camera
- keeps sending them forever...
- */
- if (length && !urb->status) {
- stv680->nullpackets = 0;
- switch (stv680->scratch[stv680->scratch_next].state) {
- case BUFFER_READY:
- case BUFFER_BUSY:
- stv680->dropped++;
- break;
-
- case BUFFER_UNUSED:
- memcpy (stv680->scratch[stv680->scratch_next].data,
- (unsigned char *) urb->transfer_buffer, length);
- stv680->scratch[stv680->scratch_next].state = BUFFER_READY;
- stv680->scratch[stv680->scratch_next].length = length;
- if (waitqueue_active (&stv680->wq)) {
- wake_up_interruptible (&stv680->wq);
- }
- stv680->scratch_overflow = 0;
- stv680->scratch_next++;
- if (stv680->scratch_next >= STV680_NUMSCRATCH)
- stv680->scratch_next = 0;
- break;
- } /* switch */
- } else {
- stv680->nullpackets++;
- if (stv680->nullpackets > STV680_MAX_NULLPACKETS) {
- if (waitqueue_active (&stv680->wq)) {
- wake_up_interruptible (&stv680->wq);
- }
- }
- } /* if - else */
-
- /* Resubmit urb for new data */
- urb->status = 0;
- urb->dev = stv680->udev;
- if (usb_submit_urb (urb, GFP_ATOMIC))
- PDEBUG (0, "STV(e): urb burned down in video irq");
- return;
-} /* _video_irq */
-
-static int stv680_start_stream (struct usb_stv *stv680)
-{
- struct urb *urb;
- int err = 0, i;
-
- stv680->streaming = 1;
-
- /* Do some memory allocation */
- for (i = 0; i < STV680_NUMFRAMES; i++) {
- stv680->frame[i].data = stv680->fbuf + i * stv680->maxframesize;
- stv680->frame[i].curpix = 0;
- }
- /* packet size = 4096 */
- for (i = 0; i < STV680_NUMSBUF; i++) {
- stv680->sbuf[i].data = kmalloc (stv680->rawbufsize, GFP_KERNEL);
- if (stv680->sbuf[i].data == NULL) {
- PDEBUG (0, "STV(e): Could not kmalloc raw data buffer %i", i);
- goto nomem_err;
- }
- }
-
- stv680->scratch_next = 0;
- stv680->scratch_use = 0;
- stv680->scratch_overflow = 0;
- for (i = 0; i < STV680_NUMSCRATCH; i++) {
- stv680->scratch[i].data = kmalloc (stv680->rawbufsize, GFP_KERNEL);
- if (stv680->scratch[i].data == NULL) {
- PDEBUG (0, "STV(e): Could not kmalloc raw scratch buffer %i", i);
- goto nomem_err;
- }
- stv680->scratch[i].state = BUFFER_UNUSED;
- }
-
- for (i = 0; i < STV680_NUMSBUF; i++) {
- urb = usb_alloc_urb (0, GFP_KERNEL);
- if (!urb)
- goto nomem_err;
-
- /* sbuf is urb->transfer_buffer, later gets memcpyed to scratch */
- usb_fill_bulk_urb (urb, stv680->udev,
- usb_rcvbulkpipe (stv680->udev, stv680->bulk_in_endpointAddr),
- stv680->sbuf[i].data, stv680->rawbufsize,
- 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 with err "
- "%d in start stream %d", err, i);
- goto nomem_err;
- }
- } /* i STV680_NUMSBUF */
-
- stv680->framecount = 0;
- return 0;
-
- nomem_err:
- for (i = 0; i < STV680_NUMSBUF; i++) {
- usb_kill_urb(stv680->urb[i]);
- usb_free_urb(stv680->urb[i]);
- stv680->urb[i] = NULL;
- kfree(stv680->sbuf[i].data);
- stv680->sbuf[i].data = NULL;
- }
- /* used in irq, free only as all URBs are dead */
- for (i = 0; i < STV680_NUMSCRATCH; i++) {
- kfree(stv680->scratch[i].data);
- stv680->scratch[i].data = NULL;
- }
- return -ENOMEM;
-
-}
-
-static int stv680_stop_stream (struct usb_stv *stv680)
-{
- int i;
-
- if (!stv680->streaming || !stv680->udev)
- return 1;
-
- stv680->streaming = 0;
-
- for (i = 0; i < STV680_NUMSBUF; i++)
- if (stv680->urb[i]) {
- usb_kill_urb (stv680->urb[i]);
- usb_free_urb (stv680->urb[i]);
- stv680->urb[i] = NULL;
- kfree(stv680->sbuf[i].data);
- }
- for (i = 0; i < STV680_NUMSCRATCH; i++) {
- kfree(stv680->scratch[i].data);
- stv680->scratch[i].data = NULL;
- }
-
- return 0;
-}
-
-static int stv680_set_size (struct usb_stv *stv680, int width, int height)
-{
- int wasstreaming = stv680->streaming;
-
- /* Check to see if we need to change */
- if ((stv680->vwidth == width) && (stv680->vheight == height))
- return 0;
-
- PDEBUG (1, "STV(i): size request for %i x %i", width, height);
- /* Check for a valid mode */
- if ((!width || !height) || ((width & 1) || (height & 1))) {
- PDEBUG (1, "STV(e): set_size error: request: v.width = %i, v.height = %i actual: stv.width = %i, stv.height = %i", width, height, stv680->vwidth, stv680->vheight);
- return 1;
- }
-
- if ((width < (stv680->maxwidth / 2)) || (height < (stv680->maxheight / 2))) {
- width = stv680->maxwidth / 2;
- height = stv680->maxheight / 2;
- } else if ((width >= 158) && (width <= 166) && (stv680->QVGA == 1)) {
- width = 160;
- height = 120;
- } else if ((width >= 172) && (width <= 180) && (stv680->CIF == 1)) {
- width = 176;
- height = 144;
- } else if ((width >= 318) && (width <= 350) && (stv680->QVGA == 1)) {
- width = 320;
- height = 240;
- } else if ((width >= 350) && (width <= 358) && (stv680->CIF == 1)) {
- width = 352;
- height = 288;
- } else {
- PDEBUG (1, "STV(e): request for non-supported size: request: v.width = %i, v.height = %i actual: stv.width = %i, stv.height = %i", width, height, stv680->vwidth, stv680->vheight);
- return 1;
- }
-
- /* Stop a current stream and start it again at the new size */
- if (wasstreaming)
- stv680_stop_stream (stv680);
- stv680->vwidth = width;
- stv680->vheight = height;
- PDEBUG (1, "STV(i): size set to %i x %i", stv680->vwidth, stv680->vheight);
- if (wasstreaming)
- stv680_start_stream (stv680);
-
- return 0;
-}
-
-/**********************************************************************
- * Video Decoding
- **********************************************************************/
-
-/******* routines from the pencam program; hey, they work! ********/
-
-/*
- * STV0680 Vision Camera Chipset Driver
- * Copyright (C) 2000 Adam Harrison <adam@antispin.org>
-*/
-
-#define RED 0
-#define GREEN 1
-#define BLUE 2
-#define AD(x, y, w) (((y)*(w)+(x))*3)
-
-static void bayer_unshuffle (struct usb_stv *stv680, struct stv680_scratch *buffer)
-{
- int x, y, i;
- int w = stv680->cwidth;
- int vw = stv680->cwidth, vh = stv680->cheight;
- unsigned int p = 0;
- int colour = 0, bayer = 0;
- unsigned char *raw = buffer->data;
- struct stv680_frame *frame = &stv680->frame[stv680->curframe];
- unsigned char *output = frame->data;
- unsigned char *temp = frame->data;
- int offset = buffer->offset;
-
- if (frame->curpix == 0) {
- if (frame->grabstate == FRAME_READY) {
- frame->grabstate = FRAME_GRABBING;
- }
- }
- if (offset != frame->curpix) { /* Regard frame as lost :( */
- frame->curpix = 0;
- stv680->error++;
- return;
- }
-
- if ((stv680->vwidth == 320) || (stv680->vwidth == 160)) {
- vw = 320;
- vh = 240;
- }
- if ((stv680->vwidth == 352) || (stv680->vwidth == 176)) {
- vw = 352;
- vh = 288;
- }
-
- memset (output, 0, 3 * vw * vh); /* clear output matrix. */
-
- for (y = 0; y < vh; y++) {
- for (x = 0; x < vw; x++) {
- if (x & 1)
- p = *(raw + y * w + (x >> 1));
- else
- p = *(raw + y * w + (x >> 1) + (w >> 1));
-
- if (y & 1)
- bayer = 2;
- else
- bayer = 0;
- if (x & 1)
- bayer++;
-
- switch (bayer) {
- case 0:
- case 3:
- colour = 1;
- break;
- case 1:
- colour = 0;
- break;
- case 2:
- colour = 2;
- break;
- }
- i = (y * vw + x) * 3;
- *(output + i + colour) = (unsigned char) p;
- } /* for x */
-
- } /* for y */
-
- /****** gamma correction plus hardcoded white balance */
- /* Thanks to Alexander Schwartx <alexander.schwartx@gmx.net> for this code.
- Correction values red[], green[], blue[], are generated by
- (pow(i/256.0, GAMMA)*255.0)*white balanceRGB where GAMMA=0.55, 1<i<255.
- White balance (RGB)= 1.0, 1.17, 1.48. Values are calculated as double float and
- converted to unsigned char. Values are in stv680.h */
-
- for (y = 0; y < vh; y++) {
- for (x = 0; x < vw; x++) {
- i = (y * vw + x) * 3;
- *(output + i) = red[*(output + i)];
- *(output + i + 1) = green[*(output + i + 1)];
- *(output + i + 2) = blue[*(output + i + 2)];
- }
- }
-
- /****** bayer demosaic ******/
- for (y = 1; y < (vh - 1); y++) {
- for (x = 1; x < (vw - 1); x++) { /* work out pixel type */
- if (y & 1)
- bayer = 0;
- else
- bayer = 2;
- if (!(x & 1))
- bayer++;
-
- switch (bayer) {
- case 0: /* green. blue lr, red tb */
- *(output + AD (x, y, vw) + BLUE) = ((int) *(output + AD (x - 1, y, vw) + BLUE) + (int) *(output + AD (x + 1, y, vw) + BLUE)) >> 1;
- *(output + AD (x, y, vw) + RED) = ((int) *(output + AD (x, y - 1, vw) + RED) + (int) *(output + AD (x, y + 1, vw) + RED)) >> 1;
- break;
-
- case 1: /* blue. green lrtb, red diagonals */
- *(output + AD (x, y, vw) + GREEN) = ((int) *(output + AD (x - 1, y, vw) + GREEN) + (int) *(output + AD (x + 1, y, vw) + GREEN) + (int) *(output + AD (x, y - 1, vw) + GREEN) + (int) *(output + AD (x, y + 1, vw) + GREEN)) >> 2;
- *(output + AD (x, y, vw) + RED) = ((int) *(output + AD (x - 1, y - 1, vw) + RED) + (int) *(output + AD (x - 1, y + 1, vw) + RED) + (int) *(output + AD (x + 1, y - 1, vw) + RED) + (int) *(output + AD (x + 1, y + 1, vw) + RED)) >> 2;
- break;
-
- case 2: /* red. green lrtb, blue diagonals */
- *(output + AD (x, y, vw) + GREEN) = ((int) *(output + AD (x - 1, y, vw) + GREEN) + (int) *(output + AD (x + 1, y, vw) + GREEN) + (int) *(output + AD (x, y - 1, vw) + GREEN) + (int) *(output + AD (x, y + 1, vw) + GREEN)) >> 2;
- *(output + AD (x, y, vw) + BLUE) = ((int) *(output + AD (x - 1, y - 1, vw) + BLUE) + (int) *(output + AD (x + 1, y - 1, vw) + BLUE) + (int) *(output + AD (x - 1, y + 1, vw) + BLUE) + (int) *(output + AD (x + 1, y + 1, vw) + BLUE)) >> 2;
- break;
-
- case 3: /* green. red lr, blue tb */
- *(output + AD (x, y, vw) + RED) = ((int) *(output + AD (x - 1, y, vw) + RED) + (int) *(output + AD (x + 1, y, vw) + RED)) >> 1;
- *(output + AD (x, y, vw) + BLUE) = ((int) *(output + AD (x, y - 1, vw) + BLUE) + (int) *(output + AD (x, y + 1, vw) + BLUE)) >> 1;
- break;
- } /* switch */
- } /* for x */
- } /* for y - end demosaic */
-
- /* fix top and bottom row, left and right side */
- i = vw * 3;
- memcpy (output, (output + i), i);
- memcpy ((output + (vh * i)), (output + ((vh - 1) * i)), i);
- for (y = 0; y < vh; y++) {
- i = y * vw * 3;
- memcpy ((output + i), (output + i + 3), 3);
- memcpy ((output + i + (vw * 3)), (output + i + (vw - 1) * 3), 3);
- }
-
- /* process all raw data, then trim to size if necessary */
- if ((stv680->vwidth == 160) || (stv680->vwidth == 176)) {
- i = 0;
- for (y = 0; y < vh; y++) {
- if (!(y & 1)) {
- for (x = 0; x < vw; x++) {
- p = (y * vw + x) * 3;
- if (!(x & 1)) {
- *(output + i) = *(output + p);
- *(output + i + 1) = *(output + p + 1);
- *(output + i + 2) = *(output + p + 2);
- i += 3;
- }
- } /* for x */
- }
- } /* for y */
- }
- /* reset to proper width */
- if ((stv680->vwidth == 160)) {
- vw = 160;
- vh = 120;
- }
- if ((stv680->vwidth == 176)) {
- vw = 176;
- vh = 144;
- }
-
- /* output is RGB; some programs want BGR */
- /* swapRGB_on=0 -> program decides; swapRGB_on=1, always swap */
- /* swapRGB_on=-1, never swap */
- if (((swapRGB == 1) && (swapRGB_on != -1)) || (swapRGB_on == 1)) {
- for (y = 0; y < vh; y++) {
- for (x = 0; x < vw; x++) {
- i = (y * vw + x) * 3;
- *(temp) = *(output + i);
- *(output + i) = *(output + i + 2);
- *(output + i + 2) = *(temp);
- }
- }
- }
- /* brightness */
- if (stv680->chgbright == 1) {
- if (stv680->brightness >= 32767) {
- p = (stv680->brightness - 32767) / 256;
- for (x = 0; x < (vw * vh * 3); x++) {
- if ((*(output + x) + (unsigned char) p) > 255)
- *(output + x) = 255;
- else
- *(output + x) += (unsigned char) p;
- } /* for */
- } else {
- p = (32767 - stv680->brightness) / 256;
- for (x = 0; x < (vw * vh * 3); x++) {
- if ((unsigned char) p > *(output + x))
- *(output + x) = 0;
- else
- *(output + x) -= (unsigned char) p;
- } /* for */
- } /* else */
- }
- /* if */
- frame->curpix = 0;
- frame->curlinepix = 0;
- frame->grabstate = FRAME_DONE;
- stv680->framecount++;
- stv680->readcount++;
- if (stv680->frame[(stv680->curframe + 1) & (STV680_NUMFRAMES - 1)].grabstate == FRAME_READY) {
- stv680->curframe = (stv680->curframe + 1) & (STV680_NUMFRAMES - 1);
- }
-
-} /* bayer_unshuffle */
-
-/******* end routines from the pencam program *********/
-
-static int stv680_newframe (struct usb_stv *stv680, int framenr)
-{
- int errors = 0;
-
- while (stv680->streaming && (stv680->frame[framenr].grabstate == FRAME_READY || stv680->frame[framenr].grabstate == FRAME_GRABBING)) {
- if (!stv680->frame[framenr].curpix) {
- errors++;
- }
- wait_event_interruptible (stv680->wq, (stv680->scratch[stv680->scratch_use].state == BUFFER_READY));
-
- if (stv680->nullpackets > STV680_MAX_NULLPACKETS) {
- stv680->nullpackets = 0;
- PDEBUG (2, "STV(i): too many null length packets, restarting capture");
- stv680_stop_stream (stv680);
- stv680_start_stream (stv680);
- } else {
- if (stv680->scratch[stv680->scratch_use].state != BUFFER_READY) {
- stv680->frame[framenr].grabstate = FRAME_ERROR;
- PDEBUG (2, "STV(e): FRAME_ERROR in _newframe");
- return -EIO;
- }
- stv680->scratch[stv680->scratch_use].state = BUFFER_BUSY;
-
- bayer_unshuffle (stv680, &stv680->scratch[stv680->scratch_use]);
-
- stv680->scratch[stv680->scratch_use].state = BUFFER_UNUSED;
- stv680->scratch_use++;
- if (stv680->scratch_use >= STV680_NUMSCRATCH)
- stv680->scratch_use = 0;
- if (errors > STV680_MAX_ERRORS) {
- errors = 0;
- PDEBUG (2, "STV(i): too many errors, restarting capture");
- stv680_stop_stream (stv680);
- stv680_start_stream (stv680);
- }
- } /* else */
- } /* while */
- return 0;
-}
-
-/*********************************************************************
- * Video4Linux
- *********************************************************************/
-
-static int stv_open(struct file *file)
-{
- struct video_device *dev = video_devdata(file);
- struct usb_stv *stv680 = video_get_drvdata(dev);
- int err = 0;
-
- /* we are called with the BKL held */
- lock_kernel();
- stv680->user = 1;
- err = stv_init (stv680); /* main initialization routine for camera */
-
- if (err >= 0) {
- stv680->fbuf = rvmalloc (stv680->maxframesize * STV680_NUMFRAMES);
- if (!stv680->fbuf) {
- PDEBUG (0, "STV(e): Could not rvmalloc frame bufer");
- err = -ENOMEM;
- }
- file->private_data = dev;
- }
- if (err)
- stv680->user = 0;
- unlock_kernel();
-
- return err;
-}
-
-static int stv_close(struct file *file)
-{
- struct video_device *dev = file->private_data;
- struct usb_stv *stv680 = video_get_drvdata(dev);
- int i;
-
- for (i = 0; i < STV680_NUMFRAMES; i++)
- stv680->frame[i].grabstate = FRAME_UNUSED;
- if (stv680->streaming)
- stv680_stop_stream (stv680);
-
- if ((i = stv_stop_video (stv680)) < 0)
- PDEBUG (1, "STV(e): stop_video failed in stv_close");
-
- rvfree (stv680->fbuf, stv680->maxframesize * STV680_NUMFRAMES);
- stv680->user = 0;
-
- if (stv680->removed) {
- kfree(stv680);
- stv680 = NULL;
- PDEBUG (0, "STV(i): device unregistered");
- }
- file->private_data = NULL;
- return 0;
-}
-
-static long stv680_do_ioctl(struct file *file, unsigned int cmd, void *arg)
-{
- struct video_device *vdev = file->private_data;
- struct usb_stv *stv680 = video_get_drvdata(vdev);
-
- if (!stv680->udev)
- return -EIO;
-
- switch (cmd) {
- case VIDIOCGCAP:{
- struct video_capability *b = arg;
-
- strcpy (b->name, stv680->camera_name);
- b->type = VID_TYPE_CAPTURE;
- b->channels = 1;
- b->audios = 0;
- b->maxwidth = stv680->maxwidth;
- b->maxheight = stv680->maxheight;
- b->minwidth = stv680->maxwidth / 2;
- b->minheight = stv680->maxheight / 2;
- return 0;
- }
- case VIDIOCGCHAN:{
- struct video_channel *v = arg;
-
- if (v->channel != 0)
- return -EINVAL;
- v->flags = 0;
- v->tuners = 0;
- v->type = VIDEO_TYPE_CAMERA;
- strcpy (v->name, "STV Camera");
- return 0;
- }
- case VIDIOCSCHAN:{
- struct video_channel *v = arg;
- if (v->channel != 0)
- return -EINVAL;
- return 0;
- }
- case VIDIOCGPICT:{
- struct video_picture *p = arg;
-
- stv680_get_pict (stv680, p);
- return 0;
- }
- case VIDIOCSPICT:{
- struct video_picture *p = arg;
-
- if (stv680_set_pict (stv680, p))
- return -EINVAL;
- return 0;
- }
- case VIDIOCSWIN:{
- struct video_window *vw = arg;
-
- if (vw->flags)
- return -EINVAL;
- if (vw->clipcount)
- return -EINVAL;
- if (vw->width != stv680->vwidth) {
- if (stv680_set_size (stv680, vw->width, vw->height)) {
- PDEBUG (2, "STV(e): failed (from user) set size in VIDIOCSWIN");
- return -EINVAL;
- }
- }
- return 0;
- }
- case VIDIOCGWIN:{
- struct video_window *vw = arg;
-
- vw->x = 0; /* FIXME */
- vw->y = 0;
- vw->chromakey = 0;
- vw->flags = 0;
- vw->clipcount = 0;
- vw->width = stv680->vwidth;
- vw->height = stv680->vheight;
- return 0;
- }
- case VIDIOCGMBUF:{
- struct video_mbuf *vm = arg;
- int i;
-
- memset (vm, 0, sizeof (*vm));
- vm->size = STV680_NUMFRAMES * stv680->maxframesize;
- vm->frames = STV680_NUMFRAMES;
- for (i = 0; i < STV680_NUMFRAMES; i++)
- vm->offsets[i] = stv680->maxframesize * i;
- return 0;
- }
- case VIDIOCMCAPTURE:{
- struct video_mmap *vm = arg;
-
- if (vm->format != STV_VIDEO_PALETTE) {
- PDEBUG (2, "STV(i): VIDIOCMCAPTURE vm.format (%i) != VIDEO_PALETTE (%i)",
- vm->format, STV_VIDEO_PALETTE);
- if ((vm->format == 3) && (swapRGB_on == 0)) {
- PDEBUG (2, "STV(i): VIDIOCMCAPTURE swapRGB is (auto) ON");
- /* this may fix those apps (e.g., xawtv) that want BGR */
- swapRGB = 1;
- }
- return -EINVAL;
- }
- if (vm->frame >= STV680_NUMFRAMES) {
- PDEBUG (2, "STV(e): VIDIOCMCAPTURE vm.frame > NUMFRAMES");
- return -EINVAL;
- }
- if ((stv680->frame[vm->frame].grabstate == FRAME_ERROR)
- || (stv680->frame[vm->frame].grabstate == FRAME_GRABBING)) {
- PDEBUG (2, "STV(e): VIDIOCMCAPTURE grabstate (%i) error",
- stv680->frame[vm->frame].grabstate);
- return -EBUSY;
- }
- /* Is this according to the v4l spec??? */
- if (stv680->vwidth != vm->width) {
- if (stv680_set_size (stv680, vm->width, vm->height)) {
- PDEBUG (2, "STV(e): VIDIOCMCAPTURE set_size failed");
- return -EINVAL;
- }
- }
- stv680->frame[vm->frame].grabstate = FRAME_READY;
-
- if (!stv680->streaming)
- stv680_start_stream (stv680);
-
- return 0;
- }
- case VIDIOCSYNC:{
- int *frame = arg;
- int ret = 0;
-
- if (*frame < 0 || *frame >= STV680_NUMFRAMES) {
- PDEBUG (2, "STV(e): Bad frame # in VIDIOCSYNC");
- return -EINVAL;
- }
- ret = stv680_newframe (stv680, *frame);
- stv680->frame[*frame].grabstate = FRAME_UNUSED;
- return ret;
- }
- case VIDIOCGFBUF:{
- struct video_buffer *vb = arg;
-
- memset (vb, 0, sizeof (*vb));
- return 0;
- }
- case VIDIOCKEY:
- return 0;
- case VIDIOCCAPTURE:
- {
- PDEBUG (2, "STV(e): VIDIOCCAPTURE failed");
- return -EINVAL;
- }
- case VIDIOCSFBUF:
- case VIDIOCGTUNER:
- case VIDIOCSTUNER:
- case VIDIOCGFREQ:
- case VIDIOCSFREQ:
- case VIDIOCGAUDIO:
- case VIDIOCSAUDIO:
- return -EINVAL;
- default:
- return -ENOIOCTLCMD;
- } /* end switch */
-
- return 0;
-}
-
-static long stv680_ioctl(struct file *file,
- unsigned int cmd, unsigned long arg)
-{
- return video_usercopy(file, cmd, arg, stv680_do_ioctl);
-}
-
-static int stv680_mmap (struct file *file, struct vm_area_struct *vma)
-{
- struct video_device *dev = file->private_data;
- struct usb_stv *stv680 = video_get_drvdata(dev);
- unsigned long start = vma->vm_start;
- unsigned long size = vma->vm_end-vma->vm_start;
- unsigned long page, pos;
-
- mutex_lock(&stv680->lock);
-
- if (stv680->udev == NULL) {
- mutex_unlock(&stv680->lock);
- return -EIO;
- }
- if (size > (((STV680_NUMFRAMES * stv680->maxframesize) + PAGE_SIZE - 1)
- & ~(PAGE_SIZE - 1))) {
- mutex_unlock(&stv680->lock);
- return -EINVAL;
- }
- pos = (unsigned long) stv680->fbuf;
- while (size > 0) {
- page = vmalloc_to_pfn((void *)pos);
- if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED)) {
- mutex_unlock(&stv680->lock);
- return -EAGAIN;
- }
- start += PAGE_SIZE;
- pos += PAGE_SIZE;
- if (size > PAGE_SIZE)
- size -= PAGE_SIZE;
- else
- size = 0;
- }
- mutex_unlock(&stv680->lock);
-
- return 0;
-}
-
-static ssize_t stv680_read (struct file *file, char __user *buf,
- size_t count, loff_t *ppos)
-{
- struct video_device *dev = file->private_data;
- unsigned long int realcount = count;
- int ret = 0;
- struct usb_stv *stv680 = video_get_drvdata(dev);
- unsigned long int i;
-
- if (STV680_NUMFRAMES != 2) {
- PDEBUG (0, "STV(e): STV680_NUMFRAMES needs to be 2!");
- return -1;
- }
- if (stv680->udev == NULL)
- return -EIO;
- if (realcount > (stv680->vwidth * stv680->vheight * 3))
- realcount = stv680->vwidth * stv680->vheight * 3;
-
- /* Shouldn't happen: */
- if (stv680->frame[0].grabstate == FRAME_GRABBING) {
- PDEBUG (2, "STV(e): FRAME_GRABBING in stv680_read");
- return -EBUSY;
- }
- stv680->frame[0].grabstate = FRAME_READY;
- stv680->frame[1].grabstate = FRAME_UNUSED;
- stv680->curframe = 0;
-
- if (!stv680->streaming)
- stv680_start_stream (stv680);
-
- if (!stv680->streaming) {
- ret = stv680_newframe (stv680, 0); /* ret should = 0 */
- }
-
- ret = stv680_newframe (stv680, 0);
-
- if (!ret) {
- if ((i = copy_to_user (buf, stv680->frame[0].data, realcount)) != 0) {
- PDEBUG (2, "STV(e): copy_to_user frame 0 failed, ret count = %li", i);
- return -EFAULT;
- }
- } else {
- realcount = ret;
- }
- stv680->frame[0].grabstate = FRAME_UNUSED;
- return realcount;
-} /* stv680_read */
-
-static const struct v4l2_file_operations stv680_fops = {
- .owner = THIS_MODULE,
- .open = stv_open,
- .release = stv_close,
- .read = stv680_read,
- .mmap = stv680_mmap,
- .ioctl = stv680_ioctl,
-};
-static struct video_device stv680_template = {
- .name = "STV0680 USB camera",
- .fops = &stv680_fops,
- .release = video_device_release,
-};
-
-static int stv680_probe (struct usb_interface *intf, const struct usb_device_id *id)
-{
- struct usb_device *dev = interface_to_usbdev(intf);
- struct usb_host_interface *interface;
- struct usb_stv *stv680 = NULL;
- char *camera_name = NULL;
- int retval = 0;
-
- /* We don't handle multi-config cameras */
- if (dev->descriptor.bNumConfigurations != 1) {
- PDEBUG (0, "STV(e): Number of Configurations != 1");
- return -ENODEV;
- }
-
- interface = &intf->altsetting[0];
- /* Is it a STV680? */
- if ((le16_to_cpu(dev->descriptor.idVendor) == USB_PENCAM_VENDOR_ID) &&
- (le16_to_cpu(dev->descriptor.idProduct) == USB_PENCAM_PRODUCT_ID)) {
- camera_name = "STV0680";
- PDEBUG (0, "STV(i): STV0680 camera found.");
- } else if ((le16_to_cpu(dev->descriptor.idVendor) == USB_CREATIVEGOMINI_VENDOR_ID) &&
- (le16_to_cpu(dev->descriptor.idProduct) == USB_CREATIVEGOMINI_PRODUCT_ID)) {
- camera_name = "Creative WebCam Go Mini";
- PDEBUG (0, "STV(i): Creative WebCam Go Mini found.");
- } else {
- PDEBUG (0, "STV(e): Vendor/Product ID do not match STV0680 or Creative WebCam Go Mini values.");
- PDEBUG (0, "STV(e): Check that the STV0680 or Creative WebCam Go Mini camera is connected to the computer.");
- retval = -ENODEV;
- goto error;
- }
- /* We found one */
- if ((stv680 = kzalloc (sizeof (*stv680), GFP_KERNEL)) == NULL) {
- PDEBUG (0, "STV(e): couldn't kmalloc stv680 struct.");
- retval = -ENOMEM;
- goto error;
- }
-
- stv680->udev = dev;
- stv680->camera_name = camera_name;
-
- stv680->vdev = video_device_alloc();
- if (!stv680->vdev) {
- retval = -ENOMEM;
- goto error;
- }
- memcpy(stv680->vdev, &stv680_template, sizeof(stv680_template));
- stv680->vdev->parent = &intf->dev;
- video_set_drvdata(stv680->vdev, stv680);
-
- memcpy (stv680->vdev->name, stv680->camera_name, strlen (stv680->camera_name));
- init_waitqueue_head (&stv680->wq);
- mutex_init (&stv680->lock);
- wmb ();
-
- if (video_register_device(stv680->vdev, VFL_TYPE_GRABBER, video_nr) < 0) {
- PDEBUG (0, "STV(e): video_register_device failed");
- retval = -EIO;
- goto error_vdev;
- }
- PDEBUG(0, "STV(i): registered new video device: %s",
- video_device_node_name(stv680->vdev));
-
- usb_set_intfdata (intf, stv680);
- retval = stv680_create_sysfs_files(stv680->vdev);
- if (retval)
- goto error_unreg;
- return 0;
-
-error_unreg:
- video_unregister_device(stv680->vdev);
-error_vdev:
- video_device_release(stv680->vdev);
-error:
- kfree(stv680);
- return retval;
-}
-
-static inline void usb_stv680_remove_disconnected (struct usb_stv *stv680)
-{
- int i;
-
- stv680->udev = NULL;
- stv680->frame[0].grabstate = FRAME_ERROR;
- stv680->frame[1].grabstate = FRAME_ERROR;
- stv680->streaming = 0;
-
- wake_up_interruptible (&stv680->wq);
-
- for (i = 0; i < STV680_NUMSBUF; i++)
- if (stv680->urb[i]) {
- usb_kill_urb (stv680->urb[i]);
- usb_free_urb (stv680->urb[i]);
- stv680->urb[i] = NULL;
- kfree(stv680->sbuf[i].data);
- }
- for (i = 0; i < STV680_NUMSCRATCH; i++)
- kfree(stv680->scratch[i].data);
- PDEBUG (0, "STV(i): %s disconnected", stv680->camera_name);
-
- /* Free the memory */
- kfree(stv680);
-}
-
-static void stv680_disconnect (struct usb_interface *intf)
-{
- struct usb_stv *stv680 = usb_get_intfdata (intf);
-
- usb_set_intfdata (intf, NULL);
-
- if (stv680) {
- /* We don't want people trying to open up the device */
- if (stv680->vdev) {
- stv680_remove_sysfs_files(stv680->vdev);
- video_unregister_device(stv680->vdev);
- stv680->vdev = NULL;
- }
- if (!stv680->user) {
- usb_stv680_remove_disconnected (stv680);
- } else {
- stv680->removed = 1;
- }
- }
-}
-
-static struct usb_driver stv680_driver = {
- .name = "stv680",
- .probe = stv680_probe,
- .disconnect = stv680_disconnect,
- .id_table = device_table
-};
-
-/********************************************************************
- * Module routines
- ********************************************************************/
-
-static int __init usb_stv680_init (void)
-{
- if (usb_register (&stv680_driver) < 0) {
- PDEBUG (0, "STV(e): Could not setup STV0680 driver");
- return -1;
- }
- PDEBUG (0, "STV(i): usb camera driver version %s registering", DRIVER_VERSION);
-
- printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
- DRIVER_DESC "\n");
- return 0;
-}
-
-static void __exit usb_stv680_exit (void)
-{
- usb_deregister (&stv680_driver);
- PDEBUG (0, "STV(i): driver deregistered");
-}
-
-module_init (usb_stv680_init);
-module_exit (usb_stv680_exit);
diff --git a/drivers/media/video/stv680.h b/drivers/media/video/stv680.h
deleted file mode 100644
index a08f1b08a4b..00000000000
--- a/drivers/media/video/stv680.h
+++ /dev/null
@@ -1,227 +0,0 @@
-/****************************************************************************
- *
- * Filename: stv680.h
- *
- * Description:
- * This is a USB driver for STV0680 based usb video cameras.
- *
- * This program is free software; you can redistribute it and/or modify
- * 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.
- *
- ****************************************************************************/
-
-/* size of usb transfers */
-#define STV680_PACKETSIZE 4096
-
-/* number of queued bulk transfers to use, may have problems if > 1 */
-#define STV680_NUMSBUF 1
-
-/* number of frames supported by the v4l part */
-#define STV680_NUMFRAMES 2
-
-/* scratch buffers for passing data to the decoders: 2 or 4 are good */
-#define STV680_NUMSCRATCH 2
-
-/* number of nul sized packets to receive before kicking the camera */
-#define STV680_MAX_NULLPACKETS 200
-
-/* number of decoding errors before kicking the camera */
-#define STV680_MAX_ERRORS 100
-
-#define USB_PENCAM_VENDOR_ID 0x0553
-#define USB_PENCAM_PRODUCT_ID 0x0202
-
-#define USB_CREATIVEGOMINI_VENDOR_ID 0x041e
-#define USB_CREATIVEGOMINI_PRODUCT_ID 0x4007
-
-#define PENCAM_TIMEOUT 1000
-/* fmt 4 */
-#define STV_VIDEO_PALETTE VIDEO_PALETTE_RGB24
-
-static struct usb_device_id device_table[] = {
- {USB_DEVICE (USB_PENCAM_VENDOR_ID, USB_PENCAM_PRODUCT_ID)},
- {USB_DEVICE (USB_CREATIVEGOMINI_VENDOR_ID, USB_CREATIVEGOMINI_PRODUCT_ID)},
- {}
-};
-MODULE_DEVICE_TABLE (usb, device_table);
-
-struct stv680_sbuf {
- unsigned char *data;
-};
-
-enum {
- FRAME_UNUSED, /* Unused (no MCAPTURE) */
- FRAME_READY, /* Ready to start grabbing */
- FRAME_GRABBING, /* In the process of being grabbed into */
- FRAME_DONE, /* Finished grabbing, but not been synced yet */
- FRAME_ERROR, /* Something bad happened while processing */
-};
-
-enum {
- BUFFER_UNUSED,
- BUFFER_READY,
- BUFFER_BUSY,
- BUFFER_DONE,
-};
-
-/* raw camera data <- sbuf (urb transfer buf) */
-struct stv680_scratch {
- unsigned char *data;
- volatile int state;
- int offset;
- int length;
-};
-
-/* processed data for display ends up here, after bayer */
-struct stv680_frame {
- unsigned char *data; /* Frame buffer */
- volatile int grabstate; /* State of grabbing */
- unsigned char *curline;
- int curlinepix;
- int curpix;
-};
-
-/* this is almost the video structure uvd_t, with extra parameters for stv */
-struct usb_stv {
- struct video_device *vdev;
-
- struct usb_device *udev;
-
- unsigned char bulk_in_endpointAddr; /* __u8 the address of the bulk in endpoint */
- char *camera_name;
-
- unsigned int VideoMode; /* 0x0100 = VGA, 0x0000 = CIF, 0x0300 = QVGA */
- int SupportedModes;
- int CIF;
- int VGA;
- int QVGA;
- int cwidth; /* camera width */
- int cheight; /* camera height */
- int maxwidth; /* max video width */
- int maxheight; /* max video height */
- int vwidth; /* current width for video window */
- int vheight; /* current height for video window */
- unsigned long int rawbufsize;
- unsigned long int maxframesize; /* rawbufsize * 3 for RGB */
-
- int origGain;
- int origMode; /* original camera mode */
-
- struct mutex lock; /* to lock the structure */
- int user; /* user count for exclusive use */
- int removed; /* device disconnected */
- int streaming; /* Are we streaming video? */
- char *fbuf; /* Videodev buffer area */
- struct urb *urb[STV680_NUMSBUF]; /* # of queued bulk transfers */
- int curframe; /* Current receiving frame */
- struct stv680_frame frame[STV680_NUMFRAMES]; /* # frames supported by v4l part */
- int readcount;
- int framecount;
- int error;
- int dropped;
- int scratch_next;
- int scratch_use;
- int scratch_overflow;
- struct stv680_scratch scratch[STV680_NUMSCRATCH]; /* for decoders */
- struct stv680_sbuf sbuf[STV680_NUMSBUF];
-
- unsigned int brightness;
- unsigned int chgbright;
- unsigned int whiteness;
- unsigned int colour;
- unsigned int contrast;
- unsigned int hue;
- unsigned int palette;
- unsigned int depth; /* rgb24 in bits */
-
- wait_queue_head_t wq; /* Processes waiting */
-
- int nullpackets;
-};
-
-
-static const unsigned char red[256] = {
- 0, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18,
- 18, 18, 18, 18, 18, 18, 18, 25, 30, 35, 38, 42,
- 44, 47, 50, 53, 54, 57, 59, 61, 63, 65, 67, 69,
- 71, 71, 73, 75, 77, 78, 80, 81, 82, 84, 85, 87,
- 88, 89, 90, 91, 93, 94, 95, 97, 98, 98, 99, 101,
- 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113,
- 114, 115, 116, 116, 117, 118, 119, 120, 121, 122, 123, 124,
- 125, 125, 126, 127, 128, 129, 129, 130, 131, 132, 133, 134,
- 134, 135, 135, 136, 137, 138, 139, 140, 140, 141, 142, 143,
- 143, 143, 144, 145, 146, 147, 147, 148, 149, 150, 150, 151,
- 152, 152, 152, 153, 154, 154, 155, 156, 157, 157, 158, 159,
- 159, 160, 161, 161, 161, 162, 163, 163, 164, 165, 165, 166,
- 167, 167, 168, 168, 169, 170, 170, 170, 171, 171, 172, 173,
- 173, 174, 174, 175, 176, 176, 177, 178, 178, 179, 179, 179,
- 180, 180, 181, 181, 182, 183, 183, 184, 184, 185, 185, 186,
- 187, 187, 188, 188, 188, 188, 189, 190, 190, 191, 191, 192,
- 192, 193, 193, 194, 195, 195, 196, 196, 197, 197, 197, 197,
- 198, 198, 199, 199, 200, 201, 201, 202, 202, 203, 203, 204,
- 204, 205, 205, 206, 206, 206, 206, 207, 207, 208, 208, 209,
- 209, 210, 210, 211, 211, 212, 212, 213, 213, 214, 214, 215,
- 215, 215, 215, 216, 216, 217, 217, 218, 218, 218, 219, 219,
- 220, 220, 221, 221
-};
-
-static const unsigned char green[256] = {
- 0, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
- 21, 21, 21, 21, 21, 21, 21, 28, 34, 39, 43, 47,
- 50, 53, 56, 59, 61, 64, 66, 68, 71, 73, 75, 77,
- 79, 80, 82, 84, 86, 87, 89, 91, 92, 94, 95, 97,
- 98, 100, 101, 102, 104, 105, 106, 108, 109, 110, 111, 113,
- 114, 115, 116, 117, 118, 120, 121, 122, 123, 124, 125, 126,
- 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138,
- 139, 140, 141, 142, 143, 144, 144, 145, 146, 147, 148, 149,
- 150, 151, 151, 152, 153, 154, 155, 156, 156, 157, 158, 159,
- 160, 160, 161, 162, 163, 164, 164, 165, 166, 167, 167, 168,
- 169, 170, 170, 171, 172, 172, 173, 174, 175, 175, 176, 177,
- 177, 178, 179, 179, 180, 181, 182, 182, 183, 184, 184, 185,
- 186, 186, 187, 187, 188, 189, 189, 190, 191, 191, 192, 193,
- 193, 194, 194, 195, 196, 196, 197, 198, 198, 199, 199, 200,
- 201, 201, 202, 202, 203, 204, 204, 205, 205, 206, 206, 207,
- 208, 208, 209, 209, 210, 210, 211, 212, 212, 213, 213, 214,
- 214, 215, 215, 216, 217, 217, 218, 218, 219, 219, 220, 220,
- 221, 221, 222, 222, 223, 224, 224, 225, 225, 226, 226, 227,
- 227, 228, 228, 229, 229, 230, 230, 231, 231, 232, 232, 233,
- 233, 234, 234, 235, 235, 236, 236, 237, 237, 238, 238, 239,
- 239, 240, 240, 241, 241, 242, 242, 243, 243, 243, 244, 244,
- 245, 245, 246, 246
-};
-
-static const unsigned char blue[256] = {
- 0, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
- 23, 23, 23, 23, 23, 23, 23, 30, 37, 42, 47, 51,
- 55, 58, 61, 64, 67, 70, 72, 74, 78, 80, 82, 84,
- 86, 88, 90, 92, 94, 95, 97, 100, 101, 103, 104, 106,
- 107, 110, 111, 112, 114, 115, 116, 118, 119, 121, 122, 124,
- 125, 126, 127, 128, 129, 132, 133, 134, 135, 136, 137, 138,
- 139, 140, 141, 143, 144, 145, 146, 147, 148, 149, 150, 151,
- 152, 154, 155, 156, 157, 158, 158, 159, 160, 161, 162, 163,
- 165, 166, 166, 167, 168, 169, 170, 171, 171, 172, 173, 174,
- 176, 176, 177, 178, 179, 180, 180, 181, 182, 183, 183, 184,
- 185, 187, 187, 188, 189, 189, 190, 191, 192, 192, 193, 194,
- 194, 195, 196, 196, 198, 199, 200, 200, 201, 202, 202, 203,
- 204, 204, 205, 205, 206, 207, 207, 209, 210, 210, 211, 212,
- 212, 213, 213, 214, 215, 215, 216, 217, 217, 218, 218, 220,
- 221, 221, 222, 222, 223, 224, 224, 225, 225, 226, 226, 227,
- 228, 228, 229, 229, 231, 231, 232, 233, 233, 234, 234, 235,
- 235, 236, 236, 237, 238, 238, 239, 239, 240, 240, 242, 242,
- 243, 243, 244, 244, 245, 246, 246, 247, 247, 248, 248, 249,
- 249, 250, 250, 251, 251, 253, 253, 254, 254, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255
-};
diff --git a/drivers/media/video/tlg2300/pd-main.c b/drivers/media/video/tlg2300/pd-main.c
index 256cc558ba1..4555f4a5f4c 100644
--- a/drivers/media/video/tlg2300/pd-main.c
+++ b/drivers/media/video/tlg2300/pd-main.c
@@ -227,12 +227,11 @@ static int firmware_download(struct usb_device *udev)
fwlength = fw->size;
- fwbuf = kzalloc(fwlength, GFP_KERNEL);
+ fwbuf = kmemdup(fw->data, fwlength, GFP_KERNEL);
if (!fwbuf) {
ret = -ENOMEM;
goto out;
}
- memcpy(fwbuf, fw->data, fwlength);
max_packet_size = udev->ep_out[0x1]->desc.wMaxPacketSize;
log("\t\t download size : %d", (int)max_packet_size);
diff --git a/drivers/media/video/tw9910.c b/drivers/media/video/tw9910.c
index 445dc93413e..a727962781a 100644
--- a/drivers/media/video/tw9910.c
+++ b/drivers/media/video/tw9910.c
@@ -768,7 +768,7 @@ static int tw9910_g_fmt(struct v4l2_subdev *sd,
mf->width = priv->scale->width;
mf->height = priv->scale->height;
- mf->code = V4L2_MBUS_FMT_YUYV8_2X8_BE;
+ mf->code = V4L2_MBUS_FMT_UYVY8_2X8;
mf->colorspace = V4L2_COLORSPACE_JPEG;
mf->field = V4L2_FIELD_INTERLACED_BT;
@@ -797,7 +797,7 @@ static int tw9910_s_fmt(struct v4l2_subdev *sd,
/*
* check color format
*/
- if (mf->code != V4L2_MBUS_FMT_YUYV8_2X8_BE)
+ if (mf->code != V4L2_MBUS_FMT_UYVY8_2X8)
return -EINVAL;
mf->colorspace = V4L2_COLORSPACE_JPEG;
@@ -824,7 +824,7 @@ static int tw9910_try_fmt(struct v4l2_subdev *sd,
return -EINVAL;
}
- mf->code = V4L2_MBUS_FMT_YUYV8_2X8_BE;
+ mf->code = V4L2_MBUS_FMT_UYVY8_2X8;
mf->colorspace = V4L2_COLORSPACE_JPEG;
/*
@@ -909,7 +909,7 @@ static int tw9910_enum_fmt(struct v4l2_subdev *sd, unsigned int index,
if (index)
return -EINVAL;
- *code = V4L2_MBUS_FMT_YUYV8_2X8_BE;
+ *code = V4L2_MBUS_FMT_UYVY8_2X8;
return 0;
}
diff --git a/drivers/media/video/usbvideo/Kconfig b/drivers/media/video/usbvideo/Kconfig
index adb1c044ad7..d6e16959f78 100644
--- a/drivers/media/video/usbvideo/Kconfig
+++ b/drivers/media/video/usbvideo/Kconfig
@@ -37,17 +37,3 @@ config USB_KONICAWC
To compile this driver as a module, choose M here: the
module will be called konicawc.
-config USB_QUICKCAM_MESSENGER
- tristate "USB Logitech Quickcam Messenger (DEPRECATED)"
- depends on VIDEO_V4L1
- select VIDEO_USBVIDEO
- ---help---
- This driver is DEPRECATED please use the gspca stv06xx module
- instead.
-
- Say Y or M here to enable support for the USB Logitech Quickcam
- Messenger webcam.
-
- To compile this driver as a module, choose M here: the
- module will be called quickcam_messenger.
-
diff --git a/drivers/media/video/usbvideo/Makefile b/drivers/media/video/usbvideo/Makefile
index 4a1b144bee4..bb52eb8dc2f 100644
--- a/drivers/media/video/usbvideo/Makefile
+++ b/drivers/media/video/usbvideo/Makefile
@@ -2,4 +2,3 @@ obj-$(CONFIG_VIDEO_USBVIDEO) += usbvideo.o
obj-$(CONFIG_USB_IBMCAM) += ibmcam.o ultracam.o
obj-$(CONFIG_USB_KONICAWC) += konicawc.o
obj-$(CONFIG_USB_VICAM) += vicam.o
-obj-$(CONFIG_USB_QUICKCAM_MESSENGER) += quickcam_messenger.o
diff --git a/drivers/media/video/usbvideo/quickcam_messenger.c b/drivers/media/video/usbvideo/quickcam_messenger.c
deleted file mode 100644
index fbd665fa197..00000000000
--- a/drivers/media/video/usbvideo/quickcam_messenger.c
+++ /dev/null
@@ -1,1126 +0,0 @@
-/*
- * Driver for Logitech Quickcam Messenger usb video camera
- * Copyright (C) Jaya Kumar
- *
- * This work was sponsored by CIS(M) Sdn Bhd.
- * History:
- * 05/08/2006 - Jaya Kumar
- * I wrote this based on the konicawc by Simon Evans.
- * -
- * Full credit for reverse engineering and creating an initial
- * working linux driver for the VV6422 goes to the qce-ga project by
- * Tuukka Toivonen, Jochen Hoenicke, Peter McConnell,
- * Cristiano De Michele, Georg Acher, Jean-Frederic Clere as well as
- * others.
- * ---
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/input.h>
-#include <linux/usb/input.h>
-#include <linux/slab.h>
-
-#include "usbvideo.h"
-#include "quickcam_messenger.h"
-
-/*
- * Version Information
- */
-
-#ifdef CONFIG_USB_DEBUG
-static int debug;
-#define DEBUG(n, format, arg...) \
- if (n <= debug) { \
- printk(KERN_DEBUG __FILE__ ":%s(): " format "\n", __func__ , ## arg); \
- }
-#else
-#define DEBUG(n, arg...)
-static const int debug;
-#endif
-
-#define DRIVER_VERSION "v0.01"
-#define DRIVER_DESC "Logitech Quickcam Messenger USB"
-
-#define USB_LOGITECH_VENDOR_ID 0x046D
-#define USB_QCM_PRODUCT_ID 0x08F0
-
-#define MAX_CAMERAS 1
-
-#define MAX_COLOUR 32768
-#define MAX_HUE 32768
-#define MAX_BRIGHTNESS 32768
-#define MAX_CONTRAST 32768
-#define MAX_WHITENESS 32768
-
-static int size = SIZE_320X240;
-static int colour = MAX_COLOUR;
-static int hue = MAX_HUE;
-static int brightness = MAX_BRIGHTNESS;
-static int contrast = MAX_CONTRAST;
-static int whiteness = MAX_WHITENESS;
-
-static struct usbvideo *cams;
-
-static struct usb_device_id qcm_table [] = {
- { USB_DEVICE(USB_LOGITECH_VENDOR_ID, USB_QCM_PRODUCT_ID) },
- { }
-};
-MODULE_DEVICE_TABLE(usb, qcm_table);
-
-#ifdef CONFIG_INPUT
-static void qcm_register_input(struct qcm *cam, struct usb_device *dev)
-{
- struct input_dev *input_dev;
- int error;
-
- usb_make_path(dev, cam->input_physname, sizeof(cam->input_physname));
- strlcat(cam->input_physname, "/input0", sizeof(cam->input_physname));
-
- cam->input = input_dev = input_allocate_device();
- if (!input_dev) {
- dev_warn(&dev->dev, "insufficient mem for cam input device\n");
- return;
- }
-
- input_dev->name = "QCM button";
- input_dev->phys = cam->input_physname;
- usb_to_input_id(dev, &input_dev->id);
- input_dev->dev.parent = &dev->dev;
-
- input_dev->evbit[0] = BIT_MASK(EV_KEY);
- input_dev->keybit[BIT_WORD(KEY_CAMERA)] = BIT_MASK(KEY_CAMERA);
-
- error = input_register_device(cam->input);
- if (error) {
- dev_warn(&dev->dev,
- "Failed to register camera's input device, err: %d\n",
- error);
- input_free_device(cam->input);
- cam->input = NULL;
- }
-}
-
-static void qcm_unregister_input(struct qcm *cam)
-{
- if (cam->input) {
- input_unregister_device(cam->input);
- cam->input = NULL;
- }
-}
-
-static void qcm_report_buttonstat(struct qcm *cam)
-{
- if (cam->input) {
- input_report_key(cam->input, KEY_CAMERA, cam->button_sts);
- input_sync(cam->input);
- }
-}
-
-static void qcm_int_irq(struct urb *urb)
-{
- int ret;
- struct uvd *uvd = urb->context;
- struct qcm *cam;
-
- if (!CAMERA_IS_OPERATIONAL(uvd))
- return;
-
- if (!uvd->streaming)
- return;
-
- uvd->stats.urb_count++;
-
- if (urb->status < 0)
- uvd->stats.iso_err_count++;
- else {
- if (urb->actual_length > 0 ) {
- cam = (struct qcm *) uvd->user_data;
- if (cam->button_sts_buf == 0x88)
- cam->button_sts = 0x0;
- else if (cam->button_sts_buf == 0x80)
- cam->button_sts = 0x1;
- qcm_report_buttonstat(cam);
- }
- }
-
- ret = usb_submit_urb(urb, GFP_ATOMIC);
- if (ret < 0)
- err("usb_submit_urb error (%d)", ret);
-}
-
-static int qcm_setup_input_int(struct qcm *cam, struct uvd *uvd)
-{
- int errflag;
- usb_fill_int_urb(cam->button_urb, uvd->dev,
- usb_rcvintpipe(uvd->dev, uvd->video_endp + 1),
- &cam->button_sts_buf,
- 1,
- qcm_int_irq,
- uvd, 16);
-
- errflag = usb_submit_urb(cam->button_urb, GFP_KERNEL);
- if (errflag)
- err ("usb_submit_int ret %d", errflag);
- return errflag;
-}
-
-static void qcm_stop_int_data(struct qcm *cam)
-{
- usb_kill_urb(cam->button_urb);
-}
-
-static int qcm_alloc_int_urb(struct qcm *cam)
-{
- cam->button_urb = usb_alloc_urb(0, GFP_KERNEL);
-
- if (!cam->button_urb)
- return -ENOMEM;
-
- return 0;
-}
-
-static void qcm_free_int(struct qcm *cam)
-{
- usb_free_urb(cam->button_urb);
-}
-#endif /* CONFIG_INPUT */
-
-static int qcm_stv_setb(struct usb_device *dev, u16 reg, u8 val)
-{
- int ret;
-
- /* we'll wait up to 3 slices but no more */
- ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
- 0x04, USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE,
- reg, 0, &val, 1, 3*HZ);
- return ret;
-}
-
-static int qcm_stv_setw(struct usb_device *dev, u16 reg, __le16 val)
-{
- int ret;
-
- /* we'll wait up to 3 slices but no more */
- ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
- 0x04, USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE,
- reg, 0, &val, 2, 3*HZ);
- return ret;
-}
-
-static int qcm_stv_getw(struct usb_device *dev, unsigned short reg,
- __le16 *val)
-{
- int ret;
-
- /* we'll wait up to 3 slices but no more */
- ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
- 0x04, USB_TYPE_VENDOR | USB_DIR_IN | USB_RECIP_DEVICE,
- reg, 0, val, 2, 3*HZ);
- return ret;
-}
-
-static int qcm_camera_on(struct uvd *uvd)
-{
- int ret;
- CHECK_RET(ret, qcm_stv_setb(uvd->dev, STV_ISO_ENABLE, 0x01));
- return 0;
-}
-
-static int qcm_camera_off(struct uvd *uvd)
-{
- int ret;
- CHECK_RET(ret, qcm_stv_setb(uvd->dev, STV_ISO_ENABLE, 0x00));
- return 0;
-}
-
-static void qcm_hsv2rgb(u16 hue, u16 sat, u16 val, u16 *r, u16 *g, u16 *b)
-{
- unsigned int segment, valsat;
- signed int h = (signed int) hue;
- unsigned int s = (sat - 32768) * 2; /* rescale */
- unsigned int v = val;
- unsigned int p;
-
- /*
- the registers controlling gain are 8 bit of which
- we affect only the last 4 bits with our gain.
- we know that if saturation is 0, (unsaturated) then
- we're grayscale (center axis of the colour cone) so
- we set rgb=value. we use a formula obtained from
- wikipedia to map the cone to the RGB plane. it's
- as follows for the human value case of h=0..360,
- s=0..1, v=0..1
- h_i = h/60 % 6 , f = h/60 - h_i , p = v(1-s)
- q = v(1 - f*s) , t = v(1 - (1-f)s)
- h_i==0 => r=v , g=t, b=p
- h_i==1 => r=q , g=v, b=p
- h_i==2 => r=p , g=v, b=t
- h_i==3 => r=p , g=q, b=v
- h_i==4 => r=t , g=p, b=v
- h_i==5 => r=v , g=p, b=q
- the bottom side (the point) and the stuff just up
- of that is black so we simplify those two cases.
- */
- if (sat < 32768) {
- /* anything less than this is unsaturated */
- *r = val;
- *g = val;
- *b = val;
- return;
- }
- if (val <= (0xFFFF/8)) {
- /* anything less than this is black */
- *r = 0;
- *g = 0;
- *b = 0;
- return;
- }
-
- /* the rest of this code is copying tukkat's
- implementation of the hsv2rgb conversion as taken
- from qc-usb-messenger code. the 10923 is 0xFFFF/6
- to divide the cone into 6 sectors. */
-
- segment = (h + 10923) & 0xFFFF;
- segment = segment*3 >> 16; /* 0..2: 0=R, 1=G, 2=B */
- hue -= segment * 21845; /* -10923..10923 */
- h = hue;
- h *= 3;
- valsat = v*s >> 16; /* 0..65534 */
- p = v - valsat;
- if (h >= 0) {
- unsigned int t = v - (valsat * (32769 - h) >> 15);
- switch (segment) {
- case 0: /* R-> */
- *r = v;
- *g = t;
- *b = p;
- break;
- case 1: /* G-> */
- *r = p;
- *g = v;
- *b = t;
- break;
- case 2: /* B-> */
- *r = t;
- *g = p;
- *b = v;
- break;
- }
- } else {
- unsigned int q = v - (valsat * (32769 + h) >> 15);
- switch (segment) {
- case 0: /* ->R */
- *r = v;
- *g = p;
- *b = q;
- break;
- case 1: /* ->G */
- *r = q;
- *g = v;
- *b = p;
- break;
- case 2: /* ->B */
- *r = p;
- *g = q;
- *b = v;
- break;
- }
- }
-}
-
-static int qcm_sensor_set_gains(struct uvd *uvd, u16 hue,
- u16 saturation, u16 value)
-{
- int ret;
- u16 r=0,g=0,b=0;
-
- /* this code is based on qc-usb-messenger */
- qcm_hsv2rgb(hue, saturation, value, &r, &g, &b);
-
- r >>= 12;
- g >>= 12;
- b >>= 12;
-
- /* min val is 8 */
- r = max((u16) 8, r);
- g = max((u16) 8, g);
- b = max((u16) 8, b);
-
- r |= 0x30;
- g |= 0x30;
- b |= 0x30;
-
- /* set the r,g,b gain registers */
- CHECK_RET(ret, qcm_stv_setb(uvd->dev, 0x0509, r));
- CHECK_RET(ret, qcm_stv_setb(uvd->dev, 0x050A, g));
- CHECK_RET(ret, qcm_stv_setb(uvd->dev, 0x050B, b));
-
- /* doing as qc-usb did */
- CHECK_RET(ret, qcm_stv_setb(uvd->dev, 0x050C, 0x2A));
- CHECK_RET(ret, qcm_stv_setb(uvd->dev, 0x050D, 0x01));
- CHECK_RET(ret, qcm_stv_setb(uvd->dev, 0x143F, 0x01));
-
- return 0;
-}
-
-static int qcm_sensor_set_exposure(struct uvd *uvd, int exposure)
-{
- int ret;
- int formedval;
-
- /* calculation was from qc-usb-messenger driver */
- formedval = ( exposure >> 12 );
-
- /* max value for formedval is 14 */
- formedval = min(formedval, 14);
-
- CHECK_RET(ret, qcm_stv_setb(uvd->dev,
- 0x143A, 0xF0 | formedval));
- CHECK_RET(ret, qcm_stv_setb(uvd->dev, 0x143F, 0x01));
- return 0;
-}
-
-static int qcm_sensor_setlevels(struct uvd *uvd, int brightness, int contrast,
- int hue, int colour)
-{
- int ret;
- /* brightness is exposure, contrast is gain, colour is saturation */
- CHECK_RET(ret,
- qcm_sensor_set_exposure(uvd, brightness));
- CHECK_RET(ret, qcm_sensor_set_gains(uvd, hue, colour, contrast));
-
- return 0;
-}
-
-static int qcm_sensor_setsize(struct uvd *uvd, u8 size)
-{
- int ret;
-
- CHECK_RET(ret, qcm_stv_setb(uvd->dev, 0x1505, size));
- return 0;
-}
-
-static int qcm_sensor_set_shutter(struct uvd *uvd, int whiteness)
-{
- int ret;
- /* some rescaling as done by the qc-usb-messenger code */
- if (whiteness > 0xC000)
- whiteness = 0xC000 + (whiteness & 0x3FFF)*8;
-
- CHECK_RET(ret, qcm_stv_setb(uvd->dev, 0x143D,
- (whiteness >> 8) & 0xFF));
- CHECK_RET(ret, qcm_stv_setb(uvd->dev, 0x143E,
- (whiteness >> 16) & 0x03));
- CHECK_RET(ret, qcm_stv_setb(uvd->dev, 0x143F, 0x01));
-
- return 0;
-}
-
-static int qcm_sensor_init(struct uvd *uvd)
-{
- struct qcm *cam = (struct qcm *) uvd->user_data;
- int ret;
- int 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));
- }
-
- CHECK_RET(ret, qcm_stv_setw(uvd->dev, 0x15c1,
- cpu_to_le16(ISOC_PACKET_SIZE)));
- CHECK_RET(ret, qcm_stv_setb(uvd->dev, 0x15c3, 0x08));
- CHECK_RET(ret, qcm_stv_setb(uvd->dev, 0x143f, 0x01));
-
- CHECK_RET(ret, qcm_stv_setb(uvd->dev, STV_ISO_ENABLE, 0x00));
-
- CHECK_RET(ret, qcm_sensor_setsize(uvd, camera_sizes[cam->size].cmd));
-
- CHECK_RET(ret, qcm_sensor_setlevels(uvd, uvd->vpic.brightness,
- uvd->vpic.contrast, uvd->vpic.hue, uvd->vpic.colour));
-
- CHECK_RET(ret, qcm_sensor_set_shutter(uvd, uvd->vpic.whiteness));
- CHECK_RET(ret, qcm_sensor_setsize(uvd, camera_sizes[cam->size].cmd));
-
- return 0;
-}
-
-static int qcm_set_camera_size(struct uvd *uvd)
-{
- int ret;
- struct qcm *cam = (struct qcm *) uvd->user_data;
-
- CHECK_RET(ret, qcm_sensor_setsize(uvd, camera_sizes[cam->size].cmd));
- cam->width = camera_sizes[cam->size].width;
- cam->height = camera_sizes[cam->size].height;
- uvd->videosize = VIDEOSIZE(cam->width, cam->height);
-
- return 0;
-}
-
-static int qcm_setup_on_open(struct uvd *uvd)
-{
- int ret;
-
- CHECK_RET(ret, qcm_sensor_set_gains(uvd, uvd->vpic.hue,
- uvd->vpic.colour, uvd->vpic.contrast));
- CHECK_RET(ret, qcm_sensor_set_exposure(uvd, uvd->vpic.brightness));
- CHECK_RET(ret, qcm_sensor_set_shutter(uvd, uvd->vpic.whiteness));
- CHECK_RET(ret, qcm_set_camera_size(uvd));
- CHECK_RET(ret, qcm_camera_on(uvd));
- return 0;
-}
-
-static void qcm_adjust_picture(struct uvd *uvd)
-{
- int ret;
- struct qcm *cam = (struct qcm *) uvd->user_data;
-
- ret = qcm_camera_off(uvd);
- if (ret) {
- err("can't turn camera off. abandoning pic adjustment");
- return;
- }
-
- /* if there's been a change in contrast, hue, or
- colour then we need to recalculate hsv in order
- to update gains */
- if ((cam->contrast != uvd->vpic.contrast) ||
- (cam->hue != uvd->vpic.hue) ||
- (cam->colour != uvd->vpic.colour)) {
- cam->contrast = uvd->vpic.contrast;
- cam->hue = uvd->vpic.hue;
- cam->colour = uvd->vpic.colour;
- ret = qcm_sensor_set_gains(uvd, cam->hue, cam->colour,
- cam->contrast);
- if (ret) {
- err("can't set gains. abandoning pic adjustment");
- return;
- }
- }
-
- if (cam->brightness != uvd->vpic.brightness) {
- cam->brightness = uvd->vpic.brightness;
- ret = qcm_sensor_set_exposure(uvd, cam->brightness);
- if (ret) {
- err("can't set exposure. abandoning pic adjustment");
- return;
- }
- }
-
- if (cam->whiteness != uvd->vpic.whiteness) {
- cam->whiteness = uvd->vpic.whiteness;
- qcm_sensor_set_shutter(uvd, cam->whiteness);
- if (ret) {
- err("can't set shutter. abandoning pic adjustment");
- return;
- }
- }
-
- ret = qcm_camera_on(uvd);
- if (ret) {
- err("can't reenable camera. pic adjustment failed");
- return;
- }
-}
-
-static int qcm_process_frame(struct uvd *uvd, u8 *cdata, int framelen)
-{
- int datalen;
- int totaldata;
- struct framehdr {
- __be16 id;
- __be16 len;
- };
- struct framehdr *fhdr;
-
- totaldata = 0;
- while (framelen) {
- fhdr = (struct framehdr *) cdata;
- datalen = be16_to_cpu(fhdr->len);
- framelen -= 4;
- cdata += 4;
-
- if ((fhdr->id) == cpu_to_be16(0x8001)) {
- RingQueue_Enqueue(&uvd->dp, marker, 4);
- totaldata += 4;
- continue;
- }
- if ((fhdr->id & cpu_to_be16(0xFF00)) == cpu_to_be16(0x0200)) {
- RingQueue_Enqueue(&uvd->dp, cdata, datalen);
- totaldata += datalen;
- }
- framelen -= datalen;
- cdata += datalen;
- }
- return totaldata;
-}
-
-static int qcm_compress_iso(struct uvd *uvd, struct urb *dataurb)
-{
- int totlen;
- int i;
- unsigned char *cdata;
-
- totlen=0;
- for (i = 0; i < dataurb->number_of_packets; i++) {
- int n = dataurb->iso_frame_desc[i].actual_length;
- int st = dataurb->iso_frame_desc[i].status;
-
- cdata = dataurb->transfer_buffer +
- dataurb->iso_frame_desc[i].offset;
-
- if (st < 0) {
- dev_warn(&uvd->dev->dev,
- "Data error: packet=%d. len=%d. status=%d.\n",
- i, n, st);
- uvd->stats.iso_err_count++;
- continue;
- }
- if (!n)
- continue;
-
- totlen += qcm_process_frame(uvd, cdata, n);
- }
- return totlen;
-}
-
-static void resubmit_urb(struct uvd *uvd, struct urb *urb)
-{
- int ret;
-
- urb->dev = uvd->dev;
- ret = usb_submit_urb(urb, GFP_ATOMIC);
- if (ret)
- err("usb_submit_urb error (%d)", ret);
-}
-
-static void qcm_isoc_irq(struct urb *urb)
-{
- int len;
- struct uvd *uvd = urb->context;
-
- if (!CAMERA_IS_OPERATIONAL(uvd))
- return;
-
- if (!uvd->streaming)
- return;
-
- uvd->stats.urb_count++;
-
- if (!urb->actual_length) {
- resubmit_urb(uvd, urb);
- return;
- }
-
- len = qcm_compress_iso(uvd, urb);
- resubmit_urb(uvd, urb);
- uvd->stats.urb_length = len;
- uvd->stats.data_count += len;
- if (len)
- RingQueue_WakeUpInterruptible(&uvd->dp);
-}
-
-static int qcm_start_data(struct uvd *uvd)
-{
- struct qcm *cam = (struct qcm *) uvd->user_data;
- int i;
- int errflag;
- int pktsz;
- int err;
-
- pktsz = uvd->iso_packet_len;
- if (!CAMERA_IS_OPERATIONAL(uvd)) {
- err("Camera is not operational");
- return -EFAULT;
- }
-
- err = usb_set_interface(uvd->dev, uvd->iface, uvd->ifaceAltActive);
- if (err < 0) {
- err("usb_set_interface error");
- uvd->last_error = err;
- return -EBUSY;
- }
-
- for (i=0; i < USBVIDEO_NUMSBUF; i++) {
- int j, k;
- struct urb *urb = uvd->sbuf[i].urb;
- urb->dev = uvd->dev;
- urb->context = uvd;
- urb->pipe = usb_rcvisocpipe(uvd->dev, uvd->video_endp);
- urb->interval = 1;
- urb->transfer_flags = URB_ISO_ASAP;
- urb->transfer_buffer = uvd->sbuf[i].data;
- urb->complete = qcm_isoc_irq;
- urb->number_of_packets = FRAMES_PER_DESC;
- urb->transfer_buffer_length = pktsz * FRAMES_PER_DESC;
- for (j=k=0; j < FRAMES_PER_DESC; j++, k += pktsz) {
- urb->iso_frame_desc[j].offset = k;
- urb->iso_frame_desc[j].length = pktsz;
- }
- }
-
- uvd->streaming = 1;
- uvd->curframe = -1;
- for (i=0; i < USBVIDEO_NUMSBUF; i++) {
- errflag = usb_submit_urb(uvd->sbuf[i].urb, GFP_KERNEL);
- if (errflag)
- err ("usb_submit_isoc(%d) ret %d", i, errflag);
- }
-
- CHECK_RET(err, qcm_setup_input_int(cam, uvd));
- CHECK_RET(err, qcm_camera_on(uvd));
- return 0;
-}
-
-static void qcm_stop_data(struct uvd *uvd)
-{
- struct qcm *cam;
- int i, j;
- int ret;
-
- if ((uvd == NULL) || (!uvd->streaming) || (uvd->dev == NULL))
- return;
- cam = (struct qcm *) uvd->user_data;
-
- ret = qcm_camera_off(uvd);
- if (ret)
- dev_warn(&uvd->dev->dev, "couldn't turn the cam off.\n");
-
- uvd->streaming = 0;
-
- /* Unschedule all of the iso td's */
- for (i=0; i < USBVIDEO_NUMSBUF; i++)
- usb_kill_urb(uvd->sbuf[i].urb);
-
- qcm_stop_int_data(cam);
-
- if (!uvd->remove_pending) {
- /* Set packet size to 0 */
- j = usb_set_interface(uvd->dev, uvd->iface,
- uvd->ifaceAltInactive);
- if (j < 0) {
- err("usb_set_interface() error %d.", j);
- uvd->last_error = j;
- }
- }
-}
-
-static void qcm_process_isoc(struct uvd *uvd, struct usbvideo_frame *frame)
-{
- struct qcm *cam = (struct qcm *) uvd->user_data;
- int x;
- struct rgb *rgbL0;
- struct rgb *rgbL1;
- struct bayL0 *bayL0;
- struct bayL1 *bayL1;
- int hor,ver,hordel,verdel;
- assert(frame != NULL);
-
- switch (cam->size) {
- case SIZE_160X120:
- hor = 162; ver = 124; hordel = 1; verdel = 2;
- break;
- case SIZE_320X240:
- default:
- hor = 324; ver = 248; hordel = 2; verdel = 4;
- break;
- }
-
- if (frame->scanstate == ScanState_Scanning) {
- while (RingQueue_GetLength(&uvd->dp) >=
- 4 + (hor*verdel + hordel)) {
- if ((RING_QUEUE_PEEK(&uvd->dp, 0) == 0x00) &&
- (RING_QUEUE_PEEK(&uvd->dp, 1) == 0xff) &&
- (RING_QUEUE_PEEK(&uvd->dp, 2) == 0x00) &&
- (RING_QUEUE_PEEK(&uvd->dp, 3) == 0xff)) {
- frame->curline = 0;
- frame->scanstate = ScanState_Lines;
- frame->frameState = FrameState_Grabbing;
- RING_QUEUE_DEQUEUE_BYTES(&uvd->dp, 4);
- /*
- * if we're starting, we need to discard the first
- * 4 lines of y bayer data
- * and the first 2 gr elements of x bayer data
- */
- RING_QUEUE_DEQUEUE_BYTES(&uvd->dp,
- (hor*verdel + hordel));
- break;
- }
- RING_QUEUE_DEQUEUE_BYTES(&uvd->dp, 1);
- }
- }
-
- if (frame->scanstate == ScanState_Scanning)
- return;
-
- /* now we can start processing bayer data so long as we have at least
- * 2 lines worth of data. this is the simplest demosaicing method that
- * I could think of. I use each 2x2 bayer element without interpolation
- * to generate 4 rgb pixels.
- */
- while ( frame->curline < cam->height &&
- (RingQueue_GetLength(&uvd->dp) >= hor*2)) {
- /* get 2 lines of bayer for demosaicing
- * into 2 lines of RGB */
- RingQueue_Dequeue(&uvd->dp, cam->scratch, hor*2);
- bayL0 = (struct bayL0 *) cam->scratch;
- bayL1 = (struct bayL1 *) (cam->scratch + hor);
- /* frame->curline is the rgb y line */
- rgbL0 = (struct rgb *)
- ( frame->data + (cam->width*3*frame->curline));
- /* w/2 because we're already doing 2 pixels */
- rgbL1 = rgbL0 + (cam->width/2);
-
- for (x=0; x < cam->width; x+=2) {
- rgbL0->r = bayL0->r;
- rgbL0->g = bayL0->g;
- rgbL0->b = bayL1->b;
-
- rgbL0->r2 = bayL0->r;
- rgbL0->g2 = bayL1->g;
- rgbL0->b2 = bayL1->b;
-
- rgbL1->r = bayL0->r;
- rgbL1->g = bayL1->g;
- rgbL1->b = bayL1->b;
-
- rgbL1->r2 = bayL0->r;
- rgbL1->g2 = bayL1->g;
- rgbL1->b2 = bayL1->b;
-
- rgbL0++;
- rgbL1++;
-
- bayL0++;
- bayL1++;
- }
-
- frame->seqRead_Length += cam->width*3*2;
- frame->curline += 2;
- }
- /* See if we filled the frame */
- if (frame->curline == cam->height) {
- frame->frameState = FrameState_Done_Hold;
- frame->curline = 0;
- uvd->curframe = -1;
- uvd->stats.frame_num++;
- }
-}
-
-/* taken from konicawc */
-static int qcm_set_video_mode(struct uvd *uvd, struct video_window *vw)
-{
- int ret;
- int newsize;
- int oldsize;
- int x = vw->width;
- int y = vw->height;
- struct qcm *cam = (struct qcm *) uvd->user_data;
-
- if (x > 0 && y > 0) {
- DEBUG(2, "trying to find size %d,%d", x, y);
- for (newsize = 0; newsize <= MAX_FRAME_SIZE; newsize++) {
- if ((camera_sizes[newsize].width == x) &&
- (camera_sizes[newsize].height == y))
- break;
- }
- } else
- newsize = cam->size;
-
- if (newsize > MAX_FRAME_SIZE) {
- DEBUG(1, "couldn't find size %d,%d", x, y);
- return -EINVAL;
- }
-
- if (newsize == cam->size) {
- DEBUG(1, "Nothing to do");
- return 0;
- }
-
- qcm_stop_data(uvd);
-
- if (cam->size != newsize) {
- oldsize = cam->size;
- cam->size = newsize;
- ret = qcm_set_camera_size(uvd);
- if (ret) {
- err("Couldn't set camera size, err=%d",ret);
- /* restore the original size */
- cam->size = oldsize;
- return ret;
- }
- }
-
- /* Flush the input queue and clear any current frame in progress */
-
- RingQueue_Flush(&uvd->dp);
- if (uvd->curframe != -1) {
- uvd->frame[uvd->curframe].curline = 0;
- uvd->frame[uvd->curframe].seqRead_Length = 0;
- uvd->frame[uvd->curframe].seqRead_Index = 0;
- }
-
- CHECK_RET(ret, qcm_start_data(uvd));
- return 0;
-}
-
-static int qcm_configure_video(struct uvd *uvd)
-{
- int ret;
- memset(&uvd->vpic, 0, sizeof(uvd->vpic));
- memset(&uvd->vpic_old, 0x55, sizeof(uvd->vpic_old));
-
- uvd->vpic.colour = colour;
- uvd->vpic.hue = hue;
- uvd->vpic.brightness = brightness;
- uvd->vpic.contrast = contrast;
- uvd->vpic.whiteness = whiteness;
- uvd->vpic.depth = 24;
- uvd->vpic.palette = VIDEO_PALETTE_RGB24;
-
- memset(&uvd->vcap, 0, sizeof(uvd->vcap));
- strcpy(uvd->vcap.name, "QCM USB Camera");
- uvd->vcap.type = VID_TYPE_CAPTURE;
- uvd->vcap.channels = 1;
- uvd->vcap.audios = 0;
-
- uvd->vcap.minwidth = camera_sizes[SIZE_160X120].width;
- uvd->vcap.minheight = camera_sizes[SIZE_160X120].height;
- uvd->vcap.maxwidth = camera_sizes[SIZE_320X240].width;
- uvd->vcap.maxheight = camera_sizes[SIZE_320X240].height;
-
- memset(&uvd->vchan, 0, sizeof(uvd->vchan));
- uvd->vchan.flags = 0 ;
- uvd->vchan.tuners = 0;
- uvd->vchan.channel = 0;
- uvd->vchan.type = VIDEO_TYPE_CAMERA;
- strcpy(uvd->vchan.name, "Camera");
-
- CHECK_RET(ret, qcm_sensor_init(uvd));
- return 0;
-}
-
-static int qcm_probe(struct usb_interface *intf,
- const struct usb_device_id *devid)
-{
- int err;
- struct uvd *uvd;
- struct usb_device *dev = interface_to_usbdev(intf);
- struct qcm *cam;
- size_t buffer_size;
- unsigned char video_ep;
- struct usb_host_interface *interface;
- struct usb_endpoint_descriptor *endpoint;
- int i,j;
- unsigned int ifacenum, ifacenum_inact=0;
- __le16 sensor_id;
-
- /* we don't support multiconfig cams */
- if (dev->descriptor.bNumConfigurations != 1)
- return -ENODEV;
-
- /* first check for the video interface and not
- * the audio interface */
- interface = &intf->cur_altsetting[0];
- if ((interface->desc.bInterfaceClass != USB_CLASS_VENDOR_SPEC)
- || (interface->desc.bInterfaceSubClass !=
- USB_CLASS_VENDOR_SPEC))
- return -ENODEV;
-
- /*
- walk through each endpoint in each setting in the interface
- stop when we find the one that's an isochronous IN endpoint.
- */
- for (i=0; i < intf->num_altsetting; i++) {
- interface = &intf->cur_altsetting[i];
- ifacenum = interface->desc.bAlternateSetting;
- /* walk the end points */
- for (j=0; j < interface->desc.bNumEndpoints; j++) {
- endpoint = &interface->endpoint[j].desc;
-
- if (usb_endpoint_dir_out(endpoint))
- continue; /* not input then not good */
-
- buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
- if (!buffer_size) {
- ifacenum_inact = ifacenum;
- continue; /* 0 pkt size is not what we want */
- }
-
- if (usb_endpoint_xfer_isoc(endpoint)) {
- video_ep = endpoint->bEndpointAddress;
- /* break out of the search */
- goto good_videoep;
- }
- }
- }
- /* failed out since nothing useful was found */
- err("No suitable endpoint was found\n");
- return -ENODEV;
-
-good_videoep:
- /* disable isochronous stream before doing anything else */
- err = qcm_stv_setb(dev, STV_ISO_ENABLE, 0);
- if (err < 0) {
- err("Failed to disable sensor stream");
- return -EIO;
- }
-
- /*
- Check that this is the same unknown sensor that is known to work. This
- sensor is suspected to be the ST VV6422C001. I'll check the same value
- that the qc-usb driver checks. This value is probably not even the
- sensor ID since it matches the USB dev ID. Oh well. If it doesn't
- match, it's probably a diff sensor so exit and apologize.
- */
- err = qcm_stv_getw(dev, CMOS_SENSOR_IDREV, &sensor_id);
- if (err < 0) {
- err("Couldn't read sensor values. Err %d\n",err);
- return err;
- }
- if (sensor_id != cpu_to_le16(0x08F0)) {
- err("Sensor ID %x != %x. Unsupported. Sorry\n",
- le16_to_cpu(sensor_id), (0x08F0));
- return -ENODEV;
- }
-
- uvd = usbvideo_AllocateDevice(cams);
- if (!uvd)
- return -ENOMEM;
-
- cam = (struct qcm *) uvd->user_data;
-
- /* buf for doing demosaicing */
- cam->scratch = kmalloc(324*2, GFP_KERNEL);
- if (!cam->scratch) /* uvd freed in dereg */
- return -ENOMEM;
-
- /* yes, if we fail after here, cam->scratch gets freed
- by qcm_free_uvd */
-
- err = qcm_alloc_int_urb(cam);
- if (err < 0)
- return err;
-
- /* yes, if we fail after here, int urb gets freed
- by qcm_free_uvd */
-
- RESTRICT_TO_RANGE(size, SIZE_160X120, SIZE_320X240);
- cam->width = camera_sizes[size].width;
- cam->height = camera_sizes[size].height;
- cam->size = size;
-
- uvd->debug = debug;
- uvd->flags = 0;
- uvd->dev = dev;
- uvd->iface = intf->altsetting->desc.bInterfaceNumber;
- uvd->ifaceAltActive = ifacenum;
- uvd->ifaceAltInactive = ifacenum_inact;
- uvd->video_endp = video_ep;
- uvd->iso_packet_len = buffer_size;
- uvd->paletteBits = 1L << VIDEO_PALETTE_RGB24;
- uvd->defaultPalette = VIDEO_PALETTE_RGB24;
- uvd->canvas = VIDEOSIZE(320, 240);
- uvd->videosize = VIDEOSIZE(cam->width, cam->height);
- err = qcm_configure_video(uvd);
- if (err) {
- err("failed to configure video settings");
- return err;
- }
-
- err = usbvideo_RegisterVideoDevice(uvd);
- if (err) { /* the uvd gets freed in Deregister */
- err("usbvideo_RegisterVideoDevice() failed.");
- return err;
- }
-
- uvd->max_frame_size = (320 * 240 * 3);
- qcm_register_input(cam, dev);
- usb_set_intfdata(intf, uvd);
- return 0;
-}
-
-static void qcm_free_uvd(struct uvd *uvd)
-{
- struct qcm *cam = (struct qcm *) uvd->user_data;
-
- kfree(cam->scratch);
- qcm_unregister_input(cam);
- qcm_free_int(cam);
-}
-
-static struct usbvideo_cb qcm_driver = {
- .probe = qcm_probe,
- .setupOnOpen = qcm_setup_on_open,
- .processData = qcm_process_isoc,
- .setVideoMode = qcm_set_video_mode,
- .startDataPump = qcm_start_data,
- .stopDataPump = qcm_stop_data,
- .adjustPicture = qcm_adjust_picture,
- .userFree = qcm_free_uvd
-};
-
-static int __init qcm_init(void)
-{
- printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
- DRIVER_DESC "\n");
-
- return usbvideo_register(
- &cams,
- MAX_CAMERAS,
- sizeof(struct qcm),
- "QCM",
- &qcm_driver,
- THIS_MODULE,
- qcm_table);
-}
-
-static void __exit qcm_exit(void)
-{
- usbvideo_Deregister(&cams);
-}
-
-module_param(size, int, 0);
-MODULE_PARM_DESC(size, "Initial Size 0: 160x120 1: 320x240");
-module_param(colour, int, 0);
-MODULE_PARM_DESC(colour, "Initial colour");
-module_param(hue, int, 0);
-MODULE_PARM_DESC(hue, "Initial hue");
-module_param(brightness, int, 0);
-MODULE_PARM_DESC(brightness, "Initial brightness");
-module_param(contrast, int, 0);
-MODULE_PARM_DESC(contrast, "Initial contrast");
-module_param(whiteness, int, 0);
-MODULE_PARM_DESC(whiteness, "Initial whiteness");
-
-#ifdef CONFIG_USB_DEBUG
-module_param(debug, int, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(debug, "Debug level: 0-9 (default=0)");
-#endif
-
-module_init(qcm_init);
-module_exit(qcm_exit);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Jaya Kumar");
-MODULE_DESCRIPTION("QCM USB Camera");
-MODULE_SUPPORTED_DEVICE("QCM USB Camera");
diff --git a/drivers/media/video/usbvideo/quickcam_messenger.h b/drivers/media/video/usbvideo/quickcam_messenger.h
deleted file mode 100644
index 17ace394d98..00000000000
--- a/drivers/media/video/usbvideo/quickcam_messenger.h
+++ /dev/null
@@ -1,112 +0,0 @@
-#ifndef quickcam_messenger_h
-#define quickcam_messenger_h
-
-#ifndef CONFIG_INPUT
-/* if we're not using input we dummy out these functions */
-#define qcm_register_input(...)
-#define qcm_unregister_input(...)
-#define qcm_report_buttonstat(...)
-#define qcm_setup_input_int(...) 0
-#define qcm_stop_int_data(...)
-#define qcm_alloc_int_urb(...) 0
-#define qcm_free_int(...)
-#endif
-
-
-#define CHECK_RET(ret, expr) \
- if ((ret = expr) < 0) return ret
-
-/* Control Registers for the STVV6422 ASIC
- * - this define is taken from the qc-usb-messenger code
- */
-#define STV_ISO_ENABLE 0x1440
-#define ISOC_PACKET_SIZE 1023
-
-/* Chip identification number including revision indicator */
-#define CMOS_SENSOR_IDREV 0xE00A
-
-struct rgb {
- u8 b;
- u8 g;
- u8 r;
- u8 b2;
- u8 g2;
- u8 r2;
-};
-
-struct bayL0 {
- u8 g;
- u8 r;
-};
-
-struct bayL1 {
- u8 b;
- u8 g;
-};
-
-struct cam_size {
- u16 width;
- u16 height;
- u8 cmd;
-};
-
-static const struct cam_size camera_sizes[] = {
- { 160, 120, 0xf },
- { 320, 240, 0x2 },
-};
-
-enum frame_sizes {
- SIZE_160X120 = 0,
- SIZE_320X240 = 1,
-};
-
-#define MAX_FRAME_SIZE SIZE_320X240
-
-struct qcm {
- u16 colour;
- u16 hue;
- u16 brightness;
- u16 contrast;
- u16 whiteness;
-
- u8 size;
- int height;
- int width;
- u8 *scratch;
- struct urb *button_urb;
- u8 button_sts;
- u8 button_sts_buf;
-
-#ifdef CONFIG_INPUT
- struct input_dev *input;
- char input_physname[64];
-#endif
-};
-
-struct regval {
- u16 reg;
- u8 val;
-};
-/* this table is derived from the
-qc-usb-messenger code */
-static const struct regval regval_table[] = {
- { STV_ISO_ENABLE, 0x00 },
- { 0x1436, 0x00 }, { 0x1432, 0x03 },
- { 0x143a, 0xF9 }, { 0x0509, 0x38 },
- { 0x050a, 0x38 }, { 0x050b, 0x38 },
- { 0x050c, 0x2A }, { 0x050d, 0x01 },
- { 0x1431, 0x00 }, { 0x1433, 0x34 },
- { 0x1438, 0x18 }, { 0x1439, 0x00 },
- { 0x143b, 0x05 }, { 0x143c, 0x00 },
- { 0x143e, 0x01 }, { 0x143d, 0x00 },
- { 0x1442, 0xe2 }, { 0x1500, 0xd0 },
- { 0x1500, 0xd0 }, { 0x1500, 0x50 },
- { 0x1501, 0xaf }, { 0x1502, 0xc2 },
- { 0x1503, 0x45 }, { 0x1505, 0x02 },
- { 0x150e, 0x8e }, { 0x150f, 0x37 },
- { 0x15c0, 0x00 },
-};
-
-static const unsigned char marker[] = { 0x00, 0xff, 0x00, 0xFF };
-
-#endif /* quickcam_messenger_h */
diff --git a/drivers/media/video/usbvideo/vicam.c b/drivers/media/video/usbvideo/vicam.c
index 6030410c667..5d6fd01f918 100644
--- a/drivers/media/video/usbvideo/vicam.c
+++ b/drivers/media/video/usbvideo/vicam.c
@@ -2,7 +2,7 @@
* USB ViCam WebCam driver
* Copyright (c) 2002 Joe Burks (jburks@wavicle.org),
* Christopher L Cheney (ccheney@cheney.cx),
- * Pavel Machek (pavel@suse.cz),
+ * Pavel Machek (pavel@ucw.cz),
* John Tyner (jtyner@cs.ucr.edu),
* Monroe Williams (monroe@pobox.com)
*
diff --git a/drivers/media/video/uvc/uvc_ctrl.c b/drivers/media/video/uvc/uvc_ctrl.c
index 27a79f087b1..a350fad0db4 100644
--- a/drivers/media/video/uvc/uvc_ctrl.c
+++ b/drivers/media/video/uvc/uvc_ctrl.c
@@ -606,6 +606,26 @@ static struct uvc_control_mapping uvc_ctrl_mappings[] = {
.set = uvc_ctrl_set_zoom,
},
{
+ .id = V4L2_CID_PAN_ABSOLUTE,
+ .name = "Pan (Absolute)",
+ .entity = UVC_GUID_UVC_CAMERA,
+ .selector = UVC_CT_PANTILT_ABSOLUTE_CONTROL,
+ .size = 32,
+ .offset = 0,
+ .v4l2_type = V4L2_CTRL_TYPE_INTEGER,
+ .data_type = UVC_CTRL_DATA_TYPE_UNSIGNED,
+ },
+ {
+ .id = V4L2_CID_TILT_ABSOLUTE,
+ .name = "Tilt (Absolute)",
+ .entity = UVC_GUID_UVC_CAMERA,
+ .selector = UVC_CT_PANTILT_ABSOLUTE_CONTROL,
+ .size = 32,
+ .offset = 32,
+ .v4l2_type = V4L2_CTRL_TYPE_INTEGER,
+ .data_type = UVC_CTRL_DATA_TYPE_UNSIGNED,
+ },
+ {
.id = V4L2_CID_PRIVACY,
.name = "Privacy",
.entity = UVC_GUID_UVC_CAMERA,
@@ -623,7 +643,7 @@ static struct uvc_control_mapping uvc_ctrl_mappings[] = {
static inline __u8 *uvc_ctrl_data(struct uvc_control *ctrl, int id)
{
- return ctrl->data + id * ctrl->info->size;
+ return ctrl->uvc_data + id * ctrl->info->size;
}
static inline int uvc_test_bit(const __u8 *data, int bit)
@@ -678,6 +698,14 @@ static void uvc_set_le_value(struct uvc_control_mapping *mapping,
int offset = mapping->offset;
__u8 mask;
+ /* According to the v4l2 spec, writing any value to a button control
+ * should result in the action belonging to the button control being
+ * triggered. UVC devices however want to see a 1 written -> override
+ * value.
+ */
+ if (mapping->v4l2_type == V4L2_CTRL_TYPE_BUTTON)
+ value = -1;
+
data += offset / 8;
offset &= 7;
@@ -1265,13 +1293,15 @@ int uvc_ctrl_resume_device(struct uvc_device *dev)
* Control and mapping handling
*/
-static void uvc_ctrl_add_ctrl(struct uvc_device *dev,
+static int uvc_ctrl_add_ctrl(struct uvc_device *dev,
struct uvc_control_info *info)
{
struct uvc_entity *entity;
struct uvc_control *ctrl = NULL;
- int ret, found = 0;
+ int ret = 0, found = 0;
unsigned int i;
+ u8 *uvc_info;
+ u8 *uvc_data;
list_for_each_entry(entity, &dev->entities, list) {
if (!uvc_entity_match_guid(entity, info->entity))
@@ -1290,56 +1320,69 @@ static void uvc_ctrl_add_ctrl(struct uvc_device *dev,
}
if (!found)
- return;
+ return 0;
+
+ uvc_data = kmalloc(info->size * UVC_CTRL_DATA_LAST + 1, GFP_KERNEL);
+ if (uvc_data == NULL)
+ return -ENOMEM;
+
+ uvc_info = uvc_data + info->size * UVC_CTRL_DATA_LAST;
if (UVC_ENTITY_TYPE(entity) == UVC_VC_EXTENSION_UNIT) {
/* Check if the device control information and length match
* the user supplied information.
*/
- __u32 flags;
- __le16 size;
- __u8 inf;
-
ret = uvc_query_ctrl(dev, UVC_GET_LEN, ctrl->entity->id,
- dev->intfnum, info->selector, (__u8 *)&size, 2);
+ dev->intfnum, info->selector, uvc_data, 2);
if (ret < 0) {
uvc_trace(UVC_TRACE_CONTROL,
"GET_LEN failed on control %pUl/%u (%d).\n",
info->entity, info->selector, ret);
- return;
+ goto done;
}
- if (info->size != le16_to_cpu(size)) {
+ if (info->size != le16_to_cpu(*(__le16 *)uvc_data)) {
uvc_trace(UVC_TRACE_CONTROL, "Control %pUl/%u size "
"doesn't match user supplied value.\n",
info->entity, info->selector);
- return;
+ ret = -EINVAL;
+ goto done;
}
ret = uvc_query_ctrl(dev, UVC_GET_INFO, ctrl->entity->id,
- dev->intfnum, info->selector, &inf, 1);
+ dev->intfnum, info->selector, uvc_info, 1);
if (ret < 0) {
uvc_trace(UVC_TRACE_CONTROL,
"GET_INFO failed on control %pUl/%u (%d).\n",
info->entity, info->selector, ret);
- return;
+ goto done;
}
- flags = info->flags;
- if (((flags & UVC_CONTROL_GET_CUR) && !(inf & (1 << 0))) ||
- ((flags & UVC_CONTROL_SET_CUR) && !(inf & (1 << 1)))) {
+ if (((info->flags & UVC_CONTROL_GET_CUR) &&
+ !(*uvc_info & UVC_CONTROL_CAP_GET)) ||
+ ((info->flags & UVC_CONTROL_SET_CUR) &&
+ !(*uvc_info & UVC_CONTROL_CAP_SET))) {
uvc_trace(UVC_TRACE_CONTROL, "Control %pUl/%u flags "
"don't match supported operations.\n",
info->entity, info->selector);
- return;
+ ret = -EINVAL;
+ goto done;
}
}
ctrl->info = info;
- ctrl->data = kmalloc(ctrl->info->size * UVC_CTRL_DATA_LAST, GFP_KERNEL);
+ ctrl->uvc_data = uvc_data;
+ ctrl->uvc_info = uvc_info;
+
uvc_trace(UVC_TRACE_CONTROL, "Added control %pUl/%u to device %s "
"entity %u\n", ctrl->info->entity, ctrl->info->selector,
dev->udev->devpath, entity->id);
+
+done:
+ if (ret < 0)
+ kfree(uvc_data);
+
+ return ret;
}
/*
@@ -1572,12 +1615,34 @@ void uvc_ctrl_cleanup_device(struct uvc_device *dev)
list_for_each_entry(entity, &dev->entities, list) {
for (i = 0; i < entity->ncontrols; ++i)
- kfree(entity->controls[i].data);
+ kfree(entity->controls[i].uvc_data);
kfree(entity->controls);
}
}
+void uvc_ctrl_cleanup(void)
+{
+ struct uvc_control_info *info;
+ struct uvc_control_info *ni;
+ struct uvc_control_mapping *mapping;
+ struct uvc_control_mapping *nm;
+
+ list_for_each_entry_safe(info, ni, &uvc_driver.controls, list) {
+ if (!(info->flags & UVC_CONTROL_EXTENSION))
+ continue;
+
+ list_for_each_entry_safe(mapping, nm, &info->mappings, list) {
+ list_del(&mapping->list);
+ kfree(mapping->menu_info);
+ kfree(mapping);
+ }
+
+ list_del(&info->list);
+ kfree(info);
+ }
+}
+
void uvc_ctrl_init(void)
{
struct uvc_control_info *ctrl = uvc_ctrls;
diff --git a/drivers/media/video/uvc/uvc_driver.c b/drivers/media/video/uvc/uvc_driver.c
index 838b56f097c..7eaf99b22a4 100644
--- a/drivers/media/video/uvc/uvc_driver.c
+++ b/drivers/media/video/uvc/uvc_driver.c
@@ -637,14 +637,13 @@ static int uvc_parse_streaming(struct uvc_device *dev,
}
streaming->header.bControlSize = n;
- streaming->header.bmaControls = kmalloc(p*n, GFP_KERNEL);
+ streaming->header.bmaControls = kmemdup(&buffer[size], p * n,
+ GFP_KERNEL);
if (streaming->header.bmaControls == NULL) {
ret = -ENOMEM;
goto error;
}
- memcpy(streaming->header.bmaControls, &buffer[size], p*n);
-
buflen -= buffer[0];
buffer += buffer[0];
@@ -2174,6 +2173,15 @@ static struct usb_device_id uvc_ids[] = {
.bInterfaceSubClass = 1,
.bInterfaceProtocol = 0,
.driver_info = UVC_QUIRK_PROBE_EXTRAFIELDS },
+ /* Manta MM-353 Plako */
+ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
+ | USB_DEVICE_ID_MATCH_INT_INFO,
+ .idVendor = 0x18ec,
+ .idProduct = 0x3188,
+ .bInterfaceClass = USB_CLASS_VIDEO,
+ .bInterfaceSubClass = 1,
+ .bInterfaceProtocol = 0,
+ .driver_info = UVC_QUIRK_PROBE_MINMAX },
/* FSC WebCam V30S */
{ .match_flags = USB_DEVICE_ID_MATCH_DEVICE
| USB_DEVICE_ID_MATCH_INT_INFO,
@@ -2261,6 +2269,7 @@ static int __init uvc_init(void)
static void __exit uvc_cleanup(void)
{
usb_deregister(&uvc_driver.driver);
+ uvc_ctrl_cleanup();
}
module_init(uvc_init);
diff --git a/drivers/media/video/uvc/uvc_v4l2.c b/drivers/media/video/uvc/uvc_v4l2.c
index 7c9ab293349..86db32697b8 100644
--- a/drivers/media/video/uvc/uvc_v4l2.c
+++ b/drivers/media/video/uvc/uvc_v4l2.c
@@ -29,6 +29,71 @@
#include "uvcvideo.h"
/* ------------------------------------------------------------------------
+ * UVC ioctls
+ */
+static int uvc_ioctl_ctrl_map(struct uvc_xu_control_mapping *xmap, int old)
+{
+ struct uvc_control_mapping *map;
+ unsigned int size;
+ int ret;
+
+ map = kzalloc(sizeof *map, GFP_KERNEL);
+ if (map == NULL)
+ return -ENOMEM;
+
+ map->id = xmap->id;
+ memcpy(map->name, xmap->name, sizeof map->name);
+ memcpy(map->entity, xmap->entity, sizeof map->entity);
+ map->selector = xmap->selector;
+ map->size = xmap->size;
+ map->offset = xmap->offset;
+ map->v4l2_type = xmap->v4l2_type;
+ map->data_type = xmap->data_type;
+
+ switch (xmap->v4l2_type) {
+ case V4L2_CTRL_TYPE_INTEGER:
+ case V4L2_CTRL_TYPE_BOOLEAN:
+ case V4L2_CTRL_TYPE_BUTTON:
+ break;
+
+ case V4L2_CTRL_TYPE_MENU:
+ if (old) {
+ ret = -EINVAL;
+ goto done;
+ }
+
+ size = xmap->menu_count * sizeof(*map->menu_info);
+ map->menu_info = kmalloc(size, GFP_KERNEL);
+ if (map->menu_info == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ if (copy_from_user(map->menu_info, xmap->menu_info, size)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ map->menu_count = xmap->menu_count;
+ break;
+
+ default:
+ ret = -EINVAL;
+ goto done;
+ }
+
+ ret = uvc_ctrl_add_mapping(map);
+
+done:
+ if (ret < 0) {
+ kfree(map->menu_info);
+ kfree(map);
+ }
+
+ return ret;
+}
+
+/* ------------------------------------------------------------------------
* V4L2 interface
*/
@@ -451,7 +516,7 @@ static int uvc_v4l2_open(struct file *file)
static int uvc_v4l2_release(struct file *file)
{
- struct uvc_fh *handle = (struct uvc_fh *)file->private_data;
+ struct uvc_fh *handle = file->private_data;
struct uvc_streaming *stream = handle->stream;
uvc_trace(UVC_TRACE_CALLS, "uvc_v4l2_release\n");
@@ -482,7 +547,7 @@ static int uvc_v4l2_release(struct file *file)
static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
{
struct video_device *vdev = video_devdata(file);
- struct uvc_fh *handle = (struct uvc_fh *)file->private_data;
+ struct uvc_fh *handle = file->private_data;
struct uvc_video_chain *chain = handle->chain;
struct uvc_streaming *stream = handle->stream;
long ret = 0;
@@ -963,6 +1028,9 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
+ if (xinfo->size == 0)
+ return -EINVAL;
+
info = kzalloc(sizeof *info, GFP_KERNEL);
if (info == NULL)
return -ENOMEM;
@@ -974,7 +1042,8 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
info->flags = xinfo->flags;
info->flags |= UVC_CONTROL_GET_MIN | UVC_CONTROL_GET_MAX |
- UVC_CONTROL_GET_RES | UVC_CONTROL_GET_DEF;
+ UVC_CONTROL_GET_RES | UVC_CONTROL_GET_DEF |
+ UVC_CONTROL_EXTENSION;
ret = uvc_ctrl_add_info(info);
if (ret < 0)
@@ -982,32 +1051,12 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
break;
}
+ case UVCIOC_CTRL_MAP_OLD:
case UVCIOC_CTRL_MAP:
- {
- struct uvc_xu_control_mapping *xmap = arg;
- struct uvc_control_mapping *map;
-
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
- map = kzalloc(sizeof *map, GFP_KERNEL);
- if (map == NULL)
- return -ENOMEM;
-
- map->id = xmap->id;
- memcpy(map->name, xmap->name, sizeof map->name);
- memcpy(map->entity, xmap->entity, sizeof map->entity);
- map->selector = xmap->selector;
- map->size = xmap->size;
- map->offset = xmap->offset;
- map->v4l2_type = xmap->v4l2_type;
- map->data_type = xmap->data_type;
-
- ret = uvc_ctrl_add_mapping(map);
- if (ret < 0)
- kfree(map);
- break;
- }
+ return uvc_ioctl_ctrl_map(arg, cmd == UVCIOC_CTRL_MAP_OLD);
case UVCIOC_CTRL_GET:
return uvc_xu_ctrl_query(chain, arg, 0);
@@ -1067,7 +1116,7 @@ static const struct vm_operations_struct uvc_vm_ops = {
static int uvc_v4l2_mmap(struct file *file, struct vm_area_struct *vma)
{
- struct uvc_fh *handle = (struct uvc_fh *)file->private_data;
+ struct uvc_fh *handle = file->private_data;
struct uvc_streaming *stream = handle->stream;
struct uvc_video_queue *queue = &stream->queue;
struct uvc_buffer *uninitialized_var(buffer);
@@ -1122,7 +1171,7 @@ done:
static unsigned int uvc_v4l2_poll(struct file *file, poll_table *wait)
{
- struct uvc_fh *handle = (struct uvc_fh *)file->private_data;
+ struct uvc_fh *handle = file->private_data;
struct uvc_streaming *stream = handle->stream;
uvc_trace(UVC_TRACE_CALLS, "uvc_v4l2_poll\n");
diff --git a/drivers/media/video/uvc/uvcvideo.h b/drivers/media/video/uvc/uvcvideo.h
index d1f88406a5e..ac272456fbf 100644
--- a/drivers/media/video/uvc/uvcvideo.h
+++ b/drivers/media/video/uvc/uvcvideo.h
@@ -27,6 +27,8 @@
#define UVC_CONTROL_RESTORE (1 << 6)
/* Control can be updated by the camera. */
#define UVC_CONTROL_AUTO_UPDATE (1 << 7)
+/* Control is an extension unit control. */
+#define UVC_CONTROL_EXTENSION (1 << 8)
#define UVC_CONTROL_GET_RANGE (UVC_CONTROL_GET_CUR | UVC_CONTROL_GET_MIN | \
UVC_CONTROL_GET_MAX | UVC_CONTROL_GET_RES | \
@@ -40,6 +42,15 @@ struct uvc_xu_control_info {
__u32 flags;
};
+struct uvc_menu_info {
+ __u32 value;
+ __u8 name[32];
+};
+
+struct uvc_xu_control_mapping_old {
+ __u8 reserved[64];
+};
+
struct uvc_xu_control_mapping {
__u32 id;
__u8 name[32];
@@ -50,6 +61,11 @@ struct uvc_xu_control_mapping {
__u8 offset;
enum v4l2_ctrl_type v4l2_type;
__u32 data_type;
+
+ struct uvc_menu_info __user *menu_info;
+ __u32 menu_count;
+
+ __u32 reserved[4];
};
struct uvc_xu_control {
@@ -60,6 +76,7 @@ struct uvc_xu_control {
};
#define UVCIOC_CTRL_ADD _IOW('U', 1, struct uvc_xu_control_info)
+#define UVCIOC_CTRL_MAP_OLD _IOWR('U', 2, struct uvc_xu_control_mapping_old)
#define UVCIOC_CTRL_MAP _IOWR('U', 2, struct uvc_xu_control_mapping)
#define UVCIOC_CTRL_GET _IOWR('U', 3, struct uvc_xu_control)
#define UVCIOC_CTRL_SET _IOW('U', 4, struct uvc_xu_control)
@@ -179,30 +196,6 @@ struct uvc_device;
/* TODO: Put the most frequently accessed fields at the beginning of
* structures to maximize cache efficiency.
*/
-struct uvc_streaming_control {
- __u16 bmHint;
- __u8 bFormatIndex;
- __u8 bFrameIndex;
- __u32 dwFrameInterval;
- __u16 wKeyFrameRate;
- __u16 wPFrameRate;
- __u16 wCompQuality;
- __u16 wCompWindowSize;
- __u16 wDelay;
- __u32 dwMaxVideoFrameSize;
- __u32 dwMaxPayloadTransferSize;
- __u32 dwClockFrequency;
- __u8 bmFramingInfo;
- __u8 bPreferedVersion;
- __u8 bMinVersion;
- __u8 bMaxVersion;
-};
-
-struct uvc_menu_info {
- __u32 value;
- __u8 name[32];
-};
-
struct uvc_control_info {
struct list_head list;
struct list_head mappings;
@@ -250,7 +243,8 @@ struct uvc_control {
modified : 1,
cached : 1;
- __u8 *data;
+ __u8 *uvc_data;
+ __u8 *uvc_info;
};
struct uvc_format_desc {
@@ -625,6 +619,7 @@ extern int uvc_ctrl_init_device(struct uvc_device *dev);
extern void uvc_ctrl_cleanup_device(struct uvc_device *dev);
extern int uvc_ctrl_resume_device(struct uvc_device *dev);
extern void uvc_ctrl_init(void);
+extern void uvc_ctrl_cleanup(void);
extern int uvc_ctrl_begin(struct uvc_video_chain *chain);
extern int __uvc_ctrl_commit(struct uvc_video_chain *chain, int rollback);
diff --git a/drivers/media/video/v4l2-compat-ioctl32.c b/drivers/media/video/v4l2-compat-ioctl32.c
index 9004a5fe764..d2f20c2acae 100644
--- a/drivers/media/video/v4l2-compat-ioctl32.c
+++ b/drivers/media/video/v4l2-compat-ioctl32.c
@@ -5,7 +5,7 @@
* Copyright (C) 1997-2000 Jakub Jelinek (jakub@redhat.com)
* Copyright (C) 1998 Eddie C. Dost (ecd@skynet.be)
* Copyright (C) 2001,2002 Andi Kleen, SuSE Labs
- * Copyright (C) 2003 Pavel Machek (pavel@suse.cz)
+ * Copyright (C) 2003 Pavel Machek (pavel@ucw.cz)
* Copyright (C) 2005 Philippe De Muyter (phdm@macqel.be)
* Copyright (C) 2008 Hans Verkuil <hverkuil@xs4all.nl>
*
diff --git a/drivers/media/video/v4l2-dev.c b/drivers/media/video/v4l2-dev.c
index 0ca7ec9ca90..9e89bf61779 100644
--- a/drivers/media/video/v4l2-dev.c
+++ b/drivers/media/video/v4l2-dev.c
@@ -410,7 +410,7 @@ static int __video_register_device(struct video_device *vdev, int type, int nr,
int minor_offset = 0;
int minor_cnt = VIDEO_NUM_DEVICES;
const char *name_base;
- void *priv = video_get_drvdata(vdev);
+ void *priv = vdev->dev.p;
/* A minor value of -1 marks this video device as never
having been registered */
@@ -536,9 +536,9 @@ static int __video_register_device(struct video_device *vdev, int type, int nr,
/* Part 4: register the device with sysfs */
memset(&vdev->dev, 0, sizeof(vdev->dev));
- /* The memset above cleared the device's drvdata, so
+ /* The memset above cleared the device's device_private, so
put back the copy we made earlier. */
- video_set_drvdata(vdev, priv);
+ vdev->dev.p = priv;
vdev->dev.class = &video_class;
vdev->dev.devt = MKDEV(VIDEO_MAJOR, vdev->minor);
if (vdev->parent)
diff --git a/drivers/media/video/videobuf-core.c b/drivers/media/video/videobuf-core.c
index 7d3378437de..ce1595bef62 100644
--- a/drivers/media/video/videobuf-core.c
+++ b/drivers/media/video/videobuf-core.c
@@ -52,18 +52,18 @@ MODULE_LICENSE("GPL");
#define CALL(q, f, arg...) \
((q->int_ops->f) ? q->int_ops->f(arg) : 0)
-struct videobuf_buffer *videobuf_alloc(struct videobuf_queue *q)
+struct videobuf_buffer *videobuf_alloc_vb(struct videobuf_queue *q)
{
struct videobuf_buffer *vb;
BUG_ON(q->msize < sizeof(*vb));
- if (!q->int_ops || !q->int_ops->alloc) {
+ if (!q->int_ops || !q->int_ops->alloc_vb) {
printk(KERN_ERR "No specific ops defined!\n");
BUG();
}
- vb = q->int_ops->alloc(q->msize);
+ vb = q->int_ops->alloc_vb(q->msize);
if (NULL != vb) {
init_waitqueue_head(&vb->done);
vb->magic = MAGIC_BUFFER;
@@ -71,7 +71,7 @@ struct videobuf_buffer *videobuf_alloc(struct videobuf_queue *q)
return vb;
}
-EXPORT_SYMBOL_GPL(videobuf_alloc);
+EXPORT_SYMBOL_GPL(videobuf_alloc_vb);
#define WAITON_CONDITION (vb->state != VIDEOBUF_ACTIVE &&\
vb->state != VIDEOBUF_QUEUED)
@@ -195,6 +195,45 @@ int videobuf_queue_is_busy(struct videobuf_queue *q)
}
EXPORT_SYMBOL_GPL(videobuf_queue_is_busy);
+/**
+ * __videobuf_free() - free all the buffers and their control structures
+ *
+ * This function can only be called if streaming/reading is off, i.e. no buffers
+ * are under control of the driver.
+ */
+/* Locking: Caller holds q->vb_lock */
+static int __videobuf_free(struct videobuf_queue *q)
+{
+ int i;
+
+ dprintk(1, "%s\n", __func__);
+ if (!q)
+ return 0;
+
+ if (q->streaming || q->reading) {
+ dprintk(1, "Cannot free buffers when streaming or reading\n");
+ return -EBUSY;
+ }
+
+ MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS);
+
+ for (i = 0; i < VIDEO_MAX_FRAME; i++)
+ if (q->bufs[i] && q->bufs[i]->map) {
+ dprintk(1, "Cannot free mmapped buffers\n");
+ return -EBUSY;
+ }
+
+ for (i = 0; i < VIDEO_MAX_FRAME; i++) {
+ if (NULL == q->bufs[i])
+ continue;
+ q->ops->buf_release(q, q->bufs[i]);
+ kfree(q->bufs[i]);
+ q->bufs[i] = NULL;
+ }
+
+ return 0;
+}
+
/* Locking: Caller holds q->vb_lock */
void videobuf_queue_cancel(struct videobuf_queue *q)
{
@@ -308,36 +347,11 @@ static void videobuf_status(struct videobuf_queue *q, struct v4l2_buffer *b,
b->sequence = vb->field_count >> 1;
}
-/* Locking: Caller holds q->vb_lock */
-static int __videobuf_mmap_free(struct videobuf_queue *q)
-{
- int i;
-
- if (!q)
- return 0;
-
- MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS);
-
- for (i = 0; i < VIDEO_MAX_FRAME; i++)
- if (q->bufs[i] && q->bufs[i]->map)
- return -EBUSY;
-
- for (i = 0; i < VIDEO_MAX_FRAME; i++) {
- if (NULL == q->bufs[i])
- continue;
- q->ops->buf_release(q, q->bufs[i]);
- kfree(q->bufs[i]);
- q->bufs[i] = NULL;
- }
-
- return 0;
-}
-
int videobuf_mmap_free(struct videobuf_queue *q)
{
int ret;
mutex_lock(&q->vb_lock);
- ret = __videobuf_mmap_free(q);
+ ret = __videobuf_free(q);
mutex_unlock(&q->vb_lock);
return ret;
}
@@ -353,13 +367,13 @@ int __videobuf_mmap_setup(struct videobuf_queue *q,
MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS);
- err = __videobuf_mmap_free(q);
+ err = __videobuf_free(q);
if (0 != err)
return err;
/* Allocate and initialize buffers */
for (i = 0; i < bcount; i++) {
- q->bufs[i] = videobuf_alloc(q);
+ q->bufs[i] = videobuf_alloc_vb(q);
if (NULL == q->bufs[i])
break;
@@ -766,7 +780,7 @@ static ssize_t videobuf_read_zerocopy(struct videobuf_queue *q,
MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS);
/* setup stuff */
- q->read_buf = videobuf_alloc(q);
+ q->read_buf = videobuf_alloc_vb(q);
if (NULL == q->read_buf)
return -ENOMEM;
@@ -871,7 +885,7 @@ ssize_t videobuf_read_one(struct videobuf_queue *q,
if (NULL == q->read_buf) {
/* need to capture a new frame */
retval = -ENOMEM;
- q->read_buf = videobuf_alloc(q);
+ q->read_buf = videobuf_alloc_vb(q);
dprintk(1, "video alloc=0x%p\n", q->read_buf);
if (NULL == q->read_buf)
@@ -970,7 +984,7 @@ static void __videobuf_read_stop(struct videobuf_queue *q)
int i;
videobuf_queue_cancel(q);
- __videobuf_mmap_free(q);
+ __videobuf_free(q);
INIT_LIST_HEAD(&q->stream);
for (i = 0; i < VIDEO_MAX_FRAME; i++) {
if (NULL == q->bufs[i])
diff --git a/drivers/media/video/videobuf-dma-contig.c b/drivers/media/video/videobuf-dma-contig.c
index 74730c624cf..372b87efcd0 100644
--- a/drivers/media/video/videobuf-dma-contig.c
+++ b/drivers/media/video/videobuf-dma-contig.c
@@ -190,7 +190,7 @@ static int videobuf_dma_contig_user_get(struct videobuf_dma_contig_memory *mem,
return ret;
}
-static struct videobuf_buffer *__videobuf_alloc(size_t size)
+static struct videobuf_buffer *__videobuf_alloc_vb(size_t size)
{
struct videobuf_dma_contig_memory *mem;
struct videobuf_buffer *vb;
@@ -280,8 +280,6 @@ static int __videobuf_mmap_mapper(struct videobuf_queue *q,
return -ENOMEM;
buf->map = map;
- map->start = vma->vm_start;
- map->end = vma->vm_end;
map->q = q;
buf->baddr = vma->vm_start;
@@ -338,7 +336,7 @@ error:
static struct videobuf_qtype_ops qops = {
.magic = MAGIC_QTYPE_OPS,
- .alloc = __videobuf_alloc,
+ .alloc_vb = __videobuf_alloc_vb,
.iolock = __videobuf_iolock,
.mmap_mapper = __videobuf_mmap_mapper,
.vaddr = __videobuf_to_vaddr,
diff --git a/drivers/media/video/videobuf-dma-sg.c b/drivers/media/video/videobuf-dma-sg.c
index 8359e6badd3..06f9a9c2a39 100644
--- a/drivers/media/video/videobuf-dma-sg.c
+++ b/drivers/media/video/videobuf-dma-sg.c
@@ -57,7 +57,13 @@ MODULE_LICENSE("GPL");
/* --------------------------------------------------------------------- */
-struct scatterlist *videobuf_vmalloc_to_sg(unsigned char *virt, int nr_pages)
+/*
+ * Return a scatterlist for some page-aligned vmalloc()'ed memory
+ * block (NULL on errors). Memory for the scatterlist is allocated
+ * using kmalloc. The caller must free the memory.
+ */
+static struct scatterlist *videobuf_vmalloc_to_sg(unsigned char *virt,
+ int nr_pages)
{
struct scatterlist *sglist;
struct page *pg;
@@ -81,10 +87,14 @@ err:
vfree(sglist);
return NULL;
}
-EXPORT_SYMBOL_GPL(videobuf_vmalloc_to_sg);
-struct scatterlist *videobuf_pages_to_sg(struct page **pages, int nr_pages,
- int offset)
+/*
+ * Return a scatterlist for a an array of userpages (NULL on errors).
+ * Memory for the scatterlist is allocated using kmalloc. The caller
+ * must free the memory.
+ */
+static struct scatterlist *videobuf_pages_to_sg(struct page **pages,
+ int nr_pages, int offset)
{
struct scatterlist *sglist;
int i;
@@ -201,17 +211,17 @@ int videobuf_dma_init_kernel(struct videobuf_dmabuf *dma, int direction,
dprintk(1, "init kernel [%d pages]\n", nr_pages);
dma->direction = direction;
- dma->vmalloc = vmalloc_32(nr_pages << PAGE_SHIFT);
- if (NULL == dma->vmalloc) {
+ dma->vaddr = vmalloc_32(nr_pages << PAGE_SHIFT);
+ if (NULL == dma->vaddr) {
dprintk(1, "vmalloc_32(%d pages) failed\n", nr_pages);
return -ENOMEM;
}
dprintk(1, "vmalloc is at addr 0x%08lx, size=%d\n",
- (unsigned long)dma->vmalloc,
+ (unsigned long)dma->vaddr,
nr_pages << PAGE_SHIFT);
- memset(dma->vmalloc, 0, nr_pages << PAGE_SHIFT);
+ memset(dma->vaddr, 0, nr_pages << PAGE_SHIFT);
dma->nr_pages = nr_pages;
return 0;
@@ -235,7 +245,7 @@ int videobuf_dma_init_overlay(struct videobuf_dmabuf *dma, int direction,
}
EXPORT_SYMBOL_GPL(videobuf_dma_init_overlay);
-int videobuf_dma_map(struct videobuf_queue *q, struct videobuf_dmabuf *dma)
+int videobuf_dma_map(struct device *dev, struct videobuf_dmabuf *dma)
{
MAGIC_CHECK(dma->magic, MAGIC_DMABUF);
BUG_ON(0 == dma->nr_pages);
@@ -244,8 +254,8 @@ int videobuf_dma_map(struct videobuf_queue *q, struct videobuf_dmabuf *dma)
dma->sglist = videobuf_pages_to_sg(dma->pages, dma->nr_pages,
dma->offset);
}
- if (dma->vmalloc) {
- dma->sglist = videobuf_vmalloc_to_sg(dma->vmalloc,
+ if (dma->vaddr) {
+ dma->sglist = videobuf_vmalloc_to_sg(dma->vaddr,
dma->nr_pages);
}
if (dma->bus_addr) {
@@ -263,7 +273,7 @@ int videobuf_dma_map(struct videobuf_queue *q, struct videobuf_dmabuf *dma)
return -ENOMEM;
}
if (!dma->bus_addr) {
- dma->sglen = dma_map_sg(q->dev, dma->sglist,
+ dma->sglen = dma_map_sg(dev, dma->sglist,
dma->nr_pages, dma->direction);
if (0 == dma->sglen) {
printk(KERN_WARNING
@@ -279,14 +289,14 @@ int videobuf_dma_map(struct videobuf_queue *q, struct videobuf_dmabuf *dma)
}
EXPORT_SYMBOL_GPL(videobuf_dma_map);
-int videobuf_dma_unmap(struct videobuf_queue *q, struct videobuf_dmabuf *dma)
+int videobuf_dma_unmap(struct device *dev, struct videobuf_dmabuf *dma)
{
MAGIC_CHECK(dma->magic, MAGIC_DMABUF);
if (!dma->sglen)
return 0;
- dma_unmap_sg(q->dev, dma->sglist, dma->sglen, dma->direction);
+ dma_unmap_sg(dev, dma->sglist, dma->sglen, dma->direction);
vfree(dma->sglist);
dma->sglist = NULL;
@@ -309,8 +319,8 @@ int videobuf_dma_free(struct videobuf_dmabuf *dma)
dma->pages = NULL;
}
- vfree(dma->vmalloc);
- dma->vmalloc = NULL;
+ vfree(dma->vaddr);
+ dma->vaddr = NULL;
if (dma->bus_addr)
dma->bus_addr = 0;
@@ -322,28 +332,6 @@ EXPORT_SYMBOL_GPL(videobuf_dma_free);
/* --------------------------------------------------------------------- */
-int videobuf_sg_dma_map(struct device *dev, struct videobuf_dmabuf *dma)
-{
- struct videobuf_queue q;
-
- q.dev = dev;
-
- return videobuf_dma_map(&q, dma);
-}
-EXPORT_SYMBOL_GPL(videobuf_sg_dma_map);
-
-int videobuf_sg_dma_unmap(struct device *dev, struct videobuf_dmabuf *dma)
-{
- struct videobuf_queue q;
-
- q.dev = dev;
-
- return videobuf_dma_unmap(&q, dma);
-}
-EXPORT_SYMBOL_GPL(videobuf_sg_dma_unmap);
-
-/* --------------------------------------------------------------------- */
-
static void videobuf_vm_open(struct vm_area_struct *vma)
{
struct videobuf_mapping *map = vma->vm_private_data;
@@ -428,7 +416,7 @@ static const struct vm_operations_struct videobuf_vm_ops = {
struct videobuf_dma_sg_memory
*/
-static struct videobuf_buffer *__videobuf_alloc(size_t size)
+static struct videobuf_buffer *__videobuf_alloc_vb(size_t size)
{
struct videobuf_dma_sg_memory *mem;
struct videobuf_buffer *vb;
@@ -456,7 +444,7 @@ static void *__videobuf_to_vaddr(struct videobuf_buffer *buf)
MAGIC_CHECK(mem->magic, MAGIC_SG_MEM);
- return mem->dma.vmalloc;
+ return mem->dma.vaddr;
}
static int __videobuf_iolock(struct videobuf_queue *q,
@@ -520,7 +508,7 @@ static int __videobuf_iolock(struct videobuf_queue *q,
default:
BUG();
}
- err = videobuf_dma_map(q, &mem->dma);
+ err = videobuf_dma_map(q->dev, &mem->dma);
if (0 != err)
return err;
@@ -620,8 +608,6 @@ static int __videobuf_mmap_mapper(struct videobuf_queue *q,
}
map->count = 1;
- map->start = vma->vm_start;
- map->end = vma->vm_end;
map->q = q;
vma->vm_ops = &videobuf_vm_ops;
vma->vm_flags |= VM_DONTEXPAND | VM_RESERVED;
@@ -638,7 +624,7 @@ done:
static struct videobuf_qtype_ops sg_ops = {
.magic = MAGIC_QTYPE_OPS,
- .alloc = __videobuf_alloc,
+ .alloc_vb = __videobuf_alloc_vb,
.iolock = __videobuf_iolock,
.sync = __videobuf_sync,
.mmap_mapper = __videobuf_mmap_mapper,
@@ -654,7 +640,7 @@ void *videobuf_sg_alloc(size_t size)
q.msize = size;
- return videobuf_alloc(&q);
+ return videobuf_alloc_vb(&q);
}
EXPORT_SYMBOL_GPL(videobuf_sg_alloc);
diff --git a/drivers/media/video/videobuf-vmalloc.c b/drivers/media/video/videobuf-vmalloc.c
index 583728f4c22..e7fe31d54f0 100644
--- a/drivers/media/video/videobuf-vmalloc.c
+++ b/drivers/media/video/videobuf-vmalloc.c
@@ -102,10 +102,10 @@ static void videobuf_vm_close(struct vm_area_struct *vma)
called with IRQ's disabled
*/
dprintk(1, "%s: buf[%d] freeing (%p)\n",
- __func__, i, mem->vmalloc);
+ __func__, i, mem->vaddr);
- vfree(mem->vmalloc);
- mem->vmalloc = NULL;
+ vfree(mem->vaddr);
+ mem->vaddr = NULL;
}
q->bufs[i]->map = NULL;
@@ -135,7 +135,7 @@ static const struct vm_operations_struct videobuf_vm_ops = {
struct videobuf_dma_sg_memory
*/
-static struct videobuf_buffer *__videobuf_alloc(size_t size)
+static struct videobuf_buffer *__videobuf_alloc_vb(size_t size)
{
struct videobuf_vmalloc_memory *mem;
struct videobuf_buffer *vb;
@@ -170,7 +170,7 @@ static int __videobuf_iolock(struct videobuf_queue *q,
dprintk(1, "%s memory method MMAP\n", __func__);
/* All handling should be done by __videobuf_mmap_mapper() */
- if (!mem->vmalloc) {
+ if (!mem->vaddr) {
printk(KERN_ERR "memory is not alloced/mmapped.\n");
return -EINVAL;
}
@@ -189,13 +189,13 @@ static int __videobuf_iolock(struct videobuf_queue *q,
* read() method.
*/
- mem->vmalloc = vmalloc_user(pages);
- if (!mem->vmalloc) {
+ mem->vaddr = vmalloc_user(pages);
+ if (!mem->vaddr) {
printk(KERN_ERR "vmalloc (%d pages) failed\n", pages);
return -ENOMEM;
}
dprintk(1, "vmalloc is at addr %p (%d pages)\n",
- mem->vmalloc, pages);
+ mem->vaddr, pages);
#if 0
int rc;
@@ -245,8 +245,6 @@ static int __videobuf_mmap_mapper(struct videobuf_queue *q,
return -ENOMEM;
buf->map = map;
- map->start = vma->vm_start;
- map->end = vma->vm_end;
map->q = q;
buf->baddr = vma->vm_start;
@@ -256,18 +254,18 @@ static int __videobuf_mmap_mapper(struct videobuf_queue *q,
MAGIC_CHECK(mem->magic, MAGIC_VMAL_MEM);
pages = PAGE_ALIGN(vma->vm_end - vma->vm_start);
- mem->vmalloc = vmalloc_user(pages);
- if (!mem->vmalloc) {
+ mem->vaddr = vmalloc_user(pages);
+ if (!mem->vaddr) {
printk(KERN_ERR "vmalloc (%d pages) failed\n", pages);
goto error;
}
- dprintk(1, "vmalloc is at addr %p (%d pages)\n", mem->vmalloc, pages);
+ dprintk(1, "vmalloc is at addr %p (%d pages)\n", mem->vaddr, pages);
/* Try to remap memory */
- retval = remap_vmalloc_range(vma, mem->vmalloc, 0);
+ retval = remap_vmalloc_range(vma, mem->vaddr, 0);
if (retval < 0) {
printk(KERN_ERR "mmap: remap failed with error %d. ", retval);
- vfree(mem->vmalloc);
+ vfree(mem->vaddr);
goto error;
}
@@ -293,7 +291,7 @@ error:
static struct videobuf_qtype_ops qops = {
.magic = MAGIC_QTYPE_OPS,
- .alloc = __videobuf_alloc,
+ .alloc_vb = __videobuf_alloc_vb,
.iolock = __videobuf_iolock,
.mmap_mapper = __videobuf_mmap_mapper,
.vaddr = videobuf_to_vmalloc,
@@ -319,7 +317,7 @@ void *videobuf_to_vmalloc(struct videobuf_buffer *buf)
BUG_ON(!mem);
MAGIC_CHECK(mem->magic, MAGIC_VMAL_MEM);
- return mem->vmalloc;
+ return mem->vaddr;
}
EXPORT_SYMBOL_GPL(videobuf_to_vmalloc);
@@ -341,8 +339,8 @@ void videobuf_vmalloc_free(struct videobuf_buffer *buf)
MAGIC_CHECK(mem->magic, MAGIC_VMAL_MEM);
- vfree(mem->vmalloc);
- mem->vmalloc = NULL;
+ vfree(mem->vaddr);
+ mem->vaddr = NULL;
return;
}
diff --git a/drivers/media/video/w9968cf.c b/drivers/media/video/w9968cf.c
deleted file mode 100644
index d807eea9175..00000000000
--- a/drivers/media/video/w9968cf.c
+++ /dev/null
@@ -1,3620 +0,0 @@
-/***************************************************************************
- * Video4Linux driver for W996[87]CF JPEG USB Dual Mode Camera Chip. *
- * *
- * Copyright (C) 2002-2004 by Luca Risolia <luca.risolia@studio.unibo.it> *
- * *
- * - Memory management code from bttv driver by Ralph Metzler, *
- * Marcus Metzler and Gerd Knorr. *
- * - I2C interface to kernel, high-level image sensor control routines and *
- * some symbolic names from OV511 driver by Mark W. McClelland. *
- * - Low-level I2C fast write function by Piotr Czerczak. *
- * - Low-level I2C read function by Frederic Jouault. *
- * *
- * This program is free software; you can redistribute it and/or modify *
- * 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/kernel.h>
-#include <linux/kmod.h>
-#include <linux/init.h>
-#include <linux/fs.h>
-#include <linux/vmalloc.h>
-#include <linux/slab.h>
-#include <linux/mm.h>
-#include <linux/string.h>
-#include <linux/errno.h>
-#include <linux/sched.h>
-#include <linux/ioctl.h>
-#include <linux/delay.h>
-#include <linux/stddef.h>
-#include <asm/page.h>
-#include <asm/uaccess.h>
-#include <linux/page-flags.h>
-#include <linux/videodev.h>
-#include <media/v4l2-ioctl.h>
-
-#include "w9968cf.h"
-#include "w9968cf_decoder.h"
-
-static struct w9968cf_vpp_t* w9968cf_vpp;
-static DECLARE_WAIT_QUEUE_HEAD(w9968cf_vppmod_wait);
-
-static LIST_HEAD(w9968cf_dev_list); /* head of V4L registered cameras list */
-static DEFINE_MUTEX(w9968cf_devlist_mutex); /* semaphore for list traversal */
-
-static DECLARE_RWSEM(w9968cf_disconnect); /* prevent races with open() */
-
-
-/****************************************************************************
- * Module macros and parameters *
- ****************************************************************************/
-
-MODULE_DEVICE_TABLE(usb, winbond_id_table);
-
-MODULE_AUTHOR(W9968CF_MODULE_AUTHOR" "W9968CF_AUTHOR_EMAIL);
-MODULE_DESCRIPTION(W9968CF_MODULE_NAME);
-MODULE_VERSION(W9968CF_MODULE_VERSION);
-MODULE_LICENSE(W9968CF_MODULE_LICENSE);
-MODULE_SUPPORTED_DEVICE("Video");
-
-static unsigned short simcams = W9968CF_SIMCAMS;
-static short video_nr[]={[0 ... W9968CF_MAX_DEVICES-1] = -1}; /*-1=first free*/
-static unsigned int packet_size[] = {[0 ... W9968CF_MAX_DEVICES-1] =
- W9968CF_PACKET_SIZE};
-static unsigned short max_buffers[] = {[0 ... W9968CF_MAX_DEVICES-1] =
- W9968CF_BUFFERS};
-static int double_buffer[] = {[0 ... W9968CF_MAX_DEVICES-1] =
- W9968CF_DOUBLE_BUFFER};
-static int clamping[] = {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_CLAMPING};
-static unsigned short filter_type[]= {[0 ... W9968CF_MAX_DEVICES-1] =
- W9968CF_FILTER_TYPE};
-static int largeview[]= {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_LARGEVIEW};
-static unsigned short decompression[] = {[0 ... W9968CF_MAX_DEVICES-1] =
- W9968CF_DECOMPRESSION};
-static int upscaling[]= {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_UPSCALING};
-static unsigned short force_palette[] = {[0 ... W9968CF_MAX_DEVICES-1] = 0};
-static int force_rgb[] = {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_FORCE_RGB};
-static int autobright[] = {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_AUTOBRIGHT};
-static int autoexp[] = {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_AUTOEXP};
-static unsigned short lightfreq[] = {[0 ... W9968CF_MAX_DEVICES-1] =
- W9968CF_LIGHTFREQ};
-static int bandingfilter[] = {[0 ... W9968CF_MAX_DEVICES-1]=
- W9968CF_BANDINGFILTER};
-static short clockdiv[] = {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_CLOCKDIV};
-static int backlight[] = {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_BACKLIGHT};
-static int mirror[] = {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_MIRROR};
-static int monochrome[] = {[0 ... W9968CF_MAX_DEVICES-1]=W9968CF_MONOCHROME};
-static unsigned int brightness[] = {[0 ... W9968CF_MAX_DEVICES-1] =
- W9968CF_BRIGHTNESS};
-static unsigned int hue[] = {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_HUE};
-static unsigned int colour[]={[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_COLOUR};
-static unsigned int contrast[] = {[0 ... W9968CF_MAX_DEVICES-1] =
- W9968CF_CONTRAST};
-static unsigned int whiteness[] = {[0 ... W9968CF_MAX_DEVICES-1] =
- W9968CF_WHITENESS};
-#ifdef W9968CF_DEBUG
-static unsigned short debug = W9968CF_DEBUG_LEVEL;
-static int specific_debug = W9968CF_SPECIFIC_DEBUG;
-#endif
-
-static unsigned int param_nv[24]; /* number of values per parameter */
-
-module_param(simcams, ushort, 0644);
-module_param_array(video_nr, short, &param_nv[0], 0444);
-module_param_array(packet_size, uint, &param_nv[1], 0444);
-module_param_array(max_buffers, ushort, &param_nv[2], 0444);
-module_param_array(double_buffer, bool, &param_nv[3], 0444);
-module_param_array(clamping, bool, &param_nv[4], 0444);
-module_param_array(filter_type, ushort, &param_nv[5], 0444);
-module_param_array(largeview, bool, &param_nv[6], 0444);
-module_param_array(decompression, ushort, &param_nv[7], 0444);
-module_param_array(upscaling, bool, &param_nv[8], 0444);
-module_param_array(force_palette, ushort, &param_nv[9], 0444);
-module_param_array(force_rgb, ushort, &param_nv[10], 0444);
-module_param_array(autobright, bool, &param_nv[11], 0444);
-module_param_array(autoexp, bool, &param_nv[12], 0444);
-module_param_array(lightfreq, ushort, &param_nv[13], 0444);
-module_param_array(bandingfilter, bool, &param_nv[14], 0444);
-module_param_array(clockdiv, short, &param_nv[15], 0444);
-module_param_array(backlight, bool, &param_nv[16], 0444);
-module_param_array(mirror, bool, &param_nv[17], 0444);
-module_param_array(monochrome, bool, &param_nv[18], 0444);
-module_param_array(brightness, uint, &param_nv[19], 0444);
-module_param_array(hue, uint, &param_nv[20], 0444);
-module_param_array(colour, uint, &param_nv[21], 0444);
-module_param_array(contrast, uint, &param_nv[22], 0444);
-module_param_array(whiteness, uint, &param_nv[23], 0444);
-#ifdef W9968CF_DEBUG
-module_param(debug, ushort, 0644);
-module_param(specific_debug, bool, 0644);
-#endif
-
-MODULE_PARM_DESC(simcams,
- "\n<n> Number of cameras allowed to stream simultaneously."
- "\nn may vary from 0 to "
- __MODULE_STRING(W9968CF_MAX_DEVICES)"."
- "\nDefault value is "__MODULE_STRING(W9968CF_SIMCAMS)"."
- "\n");
-MODULE_PARM_DESC(video_nr,
- "\n<-1|n[,...]> Specify V4L minor mode number."
- "\n -1 = use next available (default)"
- "\n n = use minor number n (integer >= 0)"
- "\nYou can specify up to "__MODULE_STRING(W9968CF_MAX_DEVICES)
- " cameras this way."
- "\nFor example:"
- "\nvideo_nr=-1,2,-1 would assign minor number 2 to"
- "\nthe second camera and use auto for the first"
- "\none and for every other camera."
- "\n");
-MODULE_PARM_DESC(packet_size,
- "\n<n[,...]> Specify the maximum data payload"
- "\nsize in bytes for alternate settings, for each device."
- "\nn is scaled between 63 and 1023 "
- "(default is "__MODULE_STRING(W9968CF_PACKET_SIZE)")."
- "\n");
-MODULE_PARM_DESC(max_buffers,
- "\n<n[,...]> For advanced users."
- "\nSpecify the maximum number of video frame buffers"
- "\nto allocate for each device, from 2 to "
- __MODULE_STRING(W9968CF_MAX_BUFFERS)
- ". (default is "__MODULE_STRING(W9968CF_BUFFERS)")."
- "\n");
-MODULE_PARM_DESC(double_buffer,
- "\n<0|1[,...]> "
- "Hardware double buffering: 0 disabled, 1 enabled."
- "\nIt should be enabled if you want smooth video output: if"
- "\nyou obtain out of sync. video, disable it, or try to"
- "\ndecrease the 'clockdiv' module parameter value."
- "\nDefault value is "__MODULE_STRING(W9968CF_DOUBLE_BUFFER)
- " for every device."
- "\n");
-MODULE_PARM_DESC(clamping,
- "\n<0|1[,...]> Video data clamping: 0 disabled, 1 enabled."
- "\nDefault value is "__MODULE_STRING(W9968CF_CLAMPING)
- " for every device."
- "\n");
-MODULE_PARM_DESC(filter_type,
- "\n<0|1|2[,...]> Video filter type."
- "\n0 none, 1 (1-2-1) 3-tap filter, "
- "2 (2-3-6-3-2) 5-tap filter."
- "\nDefault value is "__MODULE_STRING(W9968CF_FILTER_TYPE)
- " for every device."
- "\nThe filter is used to reduce noise and aliasing artifacts"
- "\nproduced by the CCD or CMOS image sensor, and the scaling"
- " process."
- "\n");
-MODULE_PARM_DESC(largeview,
- "\n<0|1[,...]> Large view: 0 disabled, 1 enabled."
- "\nDefault value is "__MODULE_STRING(W9968CF_LARGEVIEW)
- " for every device."
- "\n");
-MODULE_PARM_DESC(upscaling,
- "\n<0|1[,...]> Software scaling (for non-compressed video):"
- "\n0 disabled, 1 enabled."
- "\nDisable it if you have a slow CPU or you don't have"
- " enough memory."
- "\nDefault value is "__MODULE_STRING(W9968CF_UPSCALING)
- " for every device."
- "\nIf 'w9968cf-vpp' is not present, this parameter is"
- " set to 0."
- "\n");
-MODULE_PARM_DESC(decompression,
- "\n<0|1|2[,...]> Software video decompression:"
- "\n- 0 disables decompression (doesn't allow formats needing"
- " decompression)"
- "\n- 1 forces decompression (allows formats needing"
- " decompression only);"
- "\n- 2 allows any permitted formats."
- "\nFormats supporting compressed video are YUV422P and"
- " YUV420P/YUV420 "
- "\nin any resolutions where both width and height are "
- "a multiple of 16."
- "\nDefault value is "__MODULE_STRING(W9968CF_DECOMPRESSION)
- " for every device."
- "\nIf 'w9968cf-vpp' is not present, forcing decompression is "
- "\nnot allowed; in this case this parameter is set to 2."
- "\n");
-MODULE_PARM_DESC(force_palette,
- "\n<0"
- "|" __MODULE_STRING(VIDEO_PALETTE_UYVY)
- "|" __MODULE_STRING(VIDEO_PALETTE_YUV420)
- "|" __MODULE_STRING(VIDEO_PALETTE_YUV422P)
- "|" __MODULE_STRING(VIDEO_PALETTE_YUV420P)
- "|" __MODULE_STRING(VIDEO_PALETTE_YUYV)
- "|" __MODULE_STRING(VIDEO_PALETTE_YUV422)
- "|" __MODULE_STRING(VIDEO_PALETTE_GREY)
- "|" __MODULE_STRING(VIDEO_PALETTE_RGB555)
- "|" __MODULE_STRING(VIDEO_PALETTE_RGB565)
- "|" __MODULE_STRING(VIDEO_PALETTE_RGB24)
- "|" __MODULE_STRING(VIDEO_PALETTE_RGB32)
- "[,...]>"
- " Force picture palette."
- "\nIn order:"
- "\n- 0 allows any of the following formats:"
- "\n- UYVY 16 bpp - Original video, compression disabled"
- "\n- YUV420 12 bpp - Original video, compression enabled"
- "\n- YUV422P 16 bpp - Original video, compression enabled"
- "\n- YUV420P 12 bpp - Original video, compression enabled"
- "\n- YUVY 16 bpp - Software conversion from UYVY"
- "\n- YUV422 16 bpp - Software conversion from UYVY"
- "\n- GREY 8 bpp - Software conversion from UYVY"
- "\n- RGB555 16 bpp - Software conversion from UYVY"
- "\n- RGB565 16 bpp - Software conversion from UYVY"
- "\n- RGB24 24 bpp - Software conversion from UYVY"
- "\n- RGB32 32 bpp - Software conversion from UYVY"
- "\nWhen not 0, this parameter will override 'decompression'."
- "\nDefault value is 0 for every device."
- "\nInitial palette is "
- __MODULE_STRING(W9968CF_PALETTE_DECOMP_ON)"."
- "\nIf 'w9968cf-vpp' is not present, this parameter is"
- " set to 9 (UYVY)."
- "\n");
-MODULE_PARM_DESC(force_rgb,
- "\n<0|1[,...]> Read RGB video data instead of BGR:"
- "\n 1 = use RGB component ordering."
- "\n 0 = use BGR component ordering."
- "\nThis parameter has effect when using RGBX palettes only."
- "\nDefault value is "__MODULE_STRING(W9968CF_FORCE_RGB)
- " for every device."
- "\n");
-MODULE_PARM_DESC(autobright,
- "\n<0|1[,...]> Image sensor automatically changes brightness:"
- "\n 0 = no, 1 = yes"
- "\nDefault value is "__MODULE_STRING(W9968CF_AUTOBRIGHT)
- " for every device."
- "\n");
-MODULE_PARM_DESC(autoexp,
- "\n<0|1[,...]> Image sensor automatically changes exposure:"
- "\n 0 = no, 1 = yes"
- "\nDefault value is "__MODULE_STRING(W9968CF_AUTOEXP)
- " for every device."
- "\n");
-MODULE_PARM_DESC(lightfreq,
- "\n<50|60[,...]> Light frequency in Hz:"
- "\n 50 for European and Asian lighting,"
- " 60 for American lighting."
- "\nDefault value is "__MODULE_STRING(W9968CF_LIGHTFREQ)
- " for every device."
- "\n");
-MODULE_PARM_DESC(bandingfilter,
- "\n<0|1[,...]> Banding filter to reduce effects of"
- " fluorescent lighting:"
- "\n 0 disabled, 1 enabled."
- "\nThis filter tries to reduce the pattern of horizontal"
- "\nlight/dark bands caused by some (usually fluorescent)"
- " lighting."
- "\nDefault value is "__MODULE_STRING(W9968CF_BANDINGFILTER)
- " for every device."
- "\n");
-MODULE_PARM_DESC(clockdiv,
- "\n<-1|n[,...]> "
- "Force pixel clock divisor to a specific value (for experts):"
- "\n n may vary from 0 to 127."
- "\n -1 for automatic value."
- "\nSee also the 'double_buffer' module parameter."
- "\nDefault value is "__MODULE_STRING(W9968CF_CLOCKDIV)
- " for every device."
- "\n");
-MODULE_PARM_DESC(backlight,
- "\n<0|1[,...]> Objects are lit from behind:"
- "\n 0 = no, 1 = yes"
- "\nDefault value is "__MODULE_STRING(W9968CF_BACKLIGHT)
- " for every device."
- "\n");
-MODULE_PARM_DESC(mirror,
- "\n<0|1[,...]> Reverse image horizontally:"
- "\n 0 = no, 1 = yes"
- "\nDefault value is "__MODULE_STRING(W9968CF_MIRROR)
- " for every device."
- "\n");
-MODULE_PARM_DESC(monochrome,
- "\n<0|1[,...]> Use image sensor as monochrome sensor:"
- "\n 0 = no, 1 = yes"
- "\nNot all the sensors support monochrome color."
- "\nDefault value is "__MODULE_STRING(W9968CF_MONOCHROME)
- " for every device."
- "\n");
-MODULE_PARM_DESC(brightness,
- "\n<n[,...]> Set picture brightness (0-65535)."
- "\nDefault value is "__MODULE_STRING(W9968CF_BRIGHTNESS)
- " for every device."
- "\nThis parameter has no effect if 'autobright' is enabled."
- "\n");
-MODULE_PARM_DESC(hue,
- "\n<n[,...]> Set picture hue (0-65535)."
- "\nDefault value is "__MODULE_STRING(W9968CF_HUE)
- " for every device."
- "\n");
-MODULE_PARM_DESC(colour,
- "\n<n[,...]> Set picture saturation (0-65535)."
- "\nDefault value is "__MODULE_STRING(W9968CF_COLOUR)
- " for every device."
- "\n");
-MODULE_PARM_DESC(contrast,
- "\n<n[,...]> Set picture contrast (0-65535)."
- "\nDefault value is "__MODULE_STRING(W9968CF_CONTRAST)
- " for every device."
- "\n");
-MODULE_PARM_DESC(whiteness,
- "\n<n[,...]> Set picture whiteness (0-65535)."
- "\nDefault value is "__MODULE_STRING(W9968CF_WHITENESS)
- " for every device."
- "\n");
-#ifdef W9968CF_DEBUG
-MODULE_PARM_DESC(debug,
- "\n<n> Debugging information level, from 0 to 6:"
- "\n0 = none (use carefully)"
- "\n1 = critical errors"
- "\n2 = significant informations"
- "\n3 = configuration or general messages"
- "\n4 = warnings"
- "\n5 = called functions"
- "\n6 = function internals"
- "\nLevel 5 and 6 are useful for testing only, when only "
- "one device is used."
- "\nDefault value is "__MODULE_STRING(W9968CF_DEBUG_LEVEL)"."
- "\n");
-MODULE_PARM_DESC(specific_debug,
- "\n<0|1> Enable or disable specific debugging messages:"
- "\n0 = print messages concerning every level"
- " <= 'debug' level."
- "\n1 = print messages concerning the level"
- " indicated by 'debug'."
- "\nDefault value is "
- __MODULE_STRING(W9968CF_SPECIFIC_DEBUG)"."
- "\n");
-#endif /* W9968CF_DEBUG */
-
-
-
-/****************************************************************************
- * Some prototypes *
- ****************************************************************************/
-
-/* Video4linux interface */
-static const struct v4l2_file_operations w9968cf_fops;
-static int w9968cf_open(struct file *);
-static int w9968cf_release(struct file *);
-static int w9968cf_mmap(struct file *, struct vm_area_struct *);
-static long w9968cf_ioctl(struct file *, unsigned, unsigned long);
-static ssize_t w9968cf_read(struct file *, char __user *, size_t, loff_t *);
-static long w9968cf_v4l_ioctl(struct file *, unsigned int,
- void __user *);
-
-/* USB-specific */
-static int w9968cf_start_transfer(struct w9968cf_device*);
-static int w9968cf_stop_transfer(struct w9968cf_device*);
-static int w9968cf_write_reg(struct w9968cf_device*, u16 value, u16 index);
-static int w9968cf_read_reg(struct w9968cf_device*, u16 index);
-static int w9968cf_write_fsb(struct w9968cf_device*, u16* data);
-static int w9968cf_write_sb(struct w9968cf_device*, u16 value);
-static int w9968cf_read_sb(struct w9968cf_device*);
-static int w9968cf_upload_quantizationtables(struct w9968cf_device*);
-static void w9968cf_urb_complete(struct urb *urb);
-
-/* Low-level I2C (SMBus) I/O */
-static int w9968cf_smbus_start(struct w9968cf_device*);
-static int w9968cf_smbus_stop(struct w9968cf_device*);
-static int w9968cf_smbus_write_byte(struct w9968cf_device*, u8 v);
-static int w9968cf_smbus_read_byte(struct w9968cf_device*, u8* v);
-static int w9968cf_smbus_write_ack(struct w9968cf_device*);
-static int w9968cf_smbus_read_ack(struct w9968cf_device*);
-static int w9968cf_smbus_refresh_bus(struct w9968cf_device*);
-static int w9968cf_i2c_adap_read_byte(struct w9968cf_device* cam,
- u16 address, u8* value);
-static int w9968cf_i2c_adap_read_byte_data(struct w9968cf_device*, u16 address,
- u8 subaddress, u8* value);
-static int w9968cf_i2c_adap_write_byte(struct w9968cf_device*,
- u16 address, u8 subaddress);
-static int w9968cf_i2c_adap_fastwrite_byte_data(struct w9968cf_device*,
- u16 address, u8 subaddress,
- u8 value);
-
-/* I2C interface to kernel */
-static int w9968cf_i2c_init(struct w9968cf_device*);
-static int w9968cf_i2c_smbus_xfer(struct i2c_adapter*, u16 addr,
- unsigned short flags, char read_write,
- u8 command, int size, union i2c_smbus_data*);
-static u32 w9968cf_i2c_func(struct i2c_adapter*);
-
-/* Memory management */
-static void* rvmalloc(unsigned long size);
-static void rvfree(void *mem, unsigned long size);
-static void w9968cf_deallocate_memory(struct w9968cf_device*);
-static int w9968cf_allocate_memory(struct w9968cf_device*);
-
-/* High-level image sensor control functions */
-static int w9968cf_sensor_set_control(struct w9968cf_device*,int cid,int val);
-static int w9968cf_sensor_get_control(struct w9968cf_device*,int cid,int *val);
-static int w9968cf_sensor_cmd(struct w9968cf_device*,
- unsigned int cmd, void *arg);
-static int w9968cf_sensor_init(struct w9968cf_device*);
-static int w9968cf_sensor_update_settings(struct w9968cf_device*);
-static int w9968cf_sensor_get_picture(struct w9968cf_device*);
-static int w9968cf_sensor_update_picture(struct w9968cf_device*,
- struct video_picture pict);
-
-/* Other helper functions */
-static void w9968cf_configure_camera(struct w9968cf_device*,struct usb_device*,
- enum w9968cf_model_id,
- const unsigned short dev_nr);
-static void w9968cf_adjust_configuration(struct w9968cf_device*);
-static int w9968cf_turn_on_led(struct w9968cf_device*);
-static int w9968cf_init_chip(struct w9968cf_device*);
-static inline u16 w9968cf_valid_palette(u16 palette);
-static inline u16 w9968cf_valid_depth(u16 palette);
-static inline u8 w9968cf_need_decompression(u16 palette);
-static int w9968cf_set_picture(struct w9968cf_device*, struct video_picture);
-static int w9968cf_set_window(struct w9968cf_device*, struct video_window);
-static int w9968cf_postprocess_frame(struct w9968cf_device*,
- struct w9968cf_frame_t*);
-static int w9968cf_adjust_window_size(struct w9968cf_device*, u32 *w, u32 *h);
-static void w9968cf_init_framelist(struct w9968cf_device*);
-static void w9968cf_push_frame(struct w9968cf_device*, u8 f_num);
-static void w9968cf_pop_frame(struct w9968cf_device*,struct w9968cf_frame_t**);
-static void w9968cf_release_resources(struct w9968cf_device*);
-
-
-
-/****************************************************************************
- * Symbolic names *
- ****************************************************************************/
-
-/* Used to represent a list of values and their respective symbolic names */
-struct w9968cf_symbolic_list {
- const int num;
- const char *name;
-};
-
-/*--------------------------------------------------------------------------
- Returns the name of the matching element in the symbolic_list array. The
- end of the list must be marked with an element that has a NULL name.
- --------------------------------------------------------------------------*/
-static inline const char *
-symbolic(struct w9968cf_symbolic_list list[], const int num)
-{
- int i;
-
- for (i = 0; list[i].name != NULL; i++)
- if (list[i].num == num)
- return (list[i].name);
-
- return "Unknown";
-}
-
-static struct w9968cf_symbolic_list camlist[] = {
- { W9968CF_MOD_GENERIC, "W996[87]CF JPEG USB Dual Mode Camera" },
- { W9968CF_MOD_CLVBWGP, "Creative Labs Video Blaster WebCam Go Plus" },
-
- /* Other cameras (having the same descriptors as Generic W996[87]CF) */
- { W9968CF_MOD_ADPVDMA, "Aroma Digi Pen VGA Dual Mode ADG-5000" },
- { W9986CF_MOD_AAU, "AVerMedia AVerTV USB" },
- { W9968CF_MOD_CLVBWG, "Creative Labs Video Blaster WebCam Go" },
- { W9968CF_MOD_LL, "Lebon LDC-035A" },
- { W9968CF_MOD_EEEMC, "Ezonics EZ-802 EZMega Cam" },
- { W9968CF_MOD_OOE, "OmniVision OV8610-EDE" },
- { W9968CF_MOD_ODPVDMPC, "OPCOM Digi Pen VGA Dual Mode Pen Camera" },
- { W9968CF_MOD_PDPII, "Pretec Digi Pen-II" },
- { W9968CF_MOD_PDP480, "Pretec DigiPen-480" },
-
- { -1, NULL }
-};
-
-static struct w9968cf_symbolic_list senlist[] = {
- { CC_OV76BE, "OV76BE" },
- { CC_OV7610, "OV7610" },
- { CC_OV7620, "OV7620" },
- { CC_OV7620AE, "OV7620AE" },
- { CC_OV6620, "OV6620" },
- { CC_OV6630, "OV6630" },
- { CC_OV6630AE, "OV6630AE" },
- { CC_OV6630AF, "OV6630AF" },
- { -1, NULL }
-};
-
-/* Video4Linux1 palettes */
-static struct w9968cf_symbolic_list v4l1_plist[] = {
- { VIDEO_PALETTE_GREY, "GREY" },
- { VIDEO_PALETTE_HI240, "HI240" },
- { VIDEO_PALETTE_RGB565, "RGB565" },
- { VIDEO_PALETTE_RGB24, "RGB24" },
- { VIDEO_PALETTE_RGB32, "RGB32" },
- { VIDEO_PALETTE_RGB555, "RGB555" },
- { VIDEO_PALETTE_YUV422, "YUV422" },
- { VIDEO_PALETTE_YUYV, "YUYV" },
- { VIDEO_PALETTE_UYVY, "UYVY" },
- { VIDEO_PALETTE_YUV420, "YUV420" },
- { VIDEO_PALETTE_YUV411, "YUV411" },
- { VIDEO_PALETTE_RAW, "RAW" },
- { VIDEO_PALETTE_YUV422P, "YUV422P" },
- { VIDEO_PALETTE_YUV411P, "YUV411P" },
- { VIDEO_PALETTE_YUV420P, "YUV420P" },
- { VIDEO_PALETTE_YUV410P, "YUV410P" },
- { -1, NULL }
-};
-
-/* Decoder error codes: */
-static struct w9968cf_symbolic_list decoder_errlist[] = {
- { W9968CF_DEC_ERR_CORRUPTED_DATA, "Corrupted data" },
- { W9968CF_DEC_ERR_BUF_OVERFLOW, "Buffer overflow" },
- { W9968CF_DEC_ERR_NO_SOI, "SOI marker not found" },
- { W9968CF_DEC_ERR_NO_SOF0, "SOF0 marker not found" },
- { W9968CF_DEC_ERR_NO_SOS, "SOS marker not found" },
- { W9968CF_DEC_ERR_NO_EOI, "EOI marker not found" },
- { -1, NULL }
-};
-
-/* URB error codes: */
-static struct w9968cf_symbolic_list urb_errlist[] = {
- { -ENOMEM, "No memory for allocation of internal structures" },
- { -ENOSPC, "The host controller's bandwidth is already consumed" },
- { -ENOENT, "URB was canceled by unlink_urb" },
- { -EXDEV, "ISO transfer only partially completed" },
- { -EAGAIN, "Too match scheduled for the future" },
- { -ENXIO, "URB already queued" },
- { -EFBIG, "Too much ISO frames requested" },
- { -ENOSR, "Buffer error (overrun)" },
- { -EPIPE, "Specified endpoint is stalled (device not responding)"},
- { -EOVERFLOW, "Babble (too much data)" },
- { -EPROTO, "Bit-stuff error (bad cable?)" },
- { -EILSEQ, "CRC/Timeout" },
- { -ETIME, "Device does not respond to token" },
- { -ETIMEDOUT, "Device does not respond to command" },
- { -1, NULL }
-};
-
-/****************************************************************************
- * Memory management functions *
- ****************************************************************************/
-static void* rvmalloc(unsigned long size)
-{
- void* mem;
- unsigned long adr;
-
- size = PAGE_ALIGN(size);
- mem = vmalloc_32(size);
- if (!mem)
- return NULL;
-
- memset(mem, 0, size); /* Clear the ram out, no junk to the user */
- adr = (unsigned long) mem;
- while (size > 0) {
- SetPageReserved(vmalloc_to_page((void *)adr));
- adr += PAGE_SIZE;
- size -= PAGE_SIZE;
- }
-
- return mem;
-}
-
-
-static void rvfree(void* mem, unsigned long size)
-{
- unsigned long adr;
-
- if (!mem)
- return;
-
- adr = (unsigned long) mem;
- while ((long) size > 0) {
- ClearPageReserved(vmalloc_to_page((void *)adr));
- adr += PAGE_SIZE;
- size -= PAGE_SIZE;
- }
- vfree(mem);
-}
-
-
-/*--------------------------------------------------------------------------
- Deallocate previously allocated memory.
- --------------------------------------------------------------------------*/
-static void w9968cf_deallocate_memory(struct w9968cf_device* cam)
-{
- u8 i;
-
- /* Free the isochronous transfer buffers */
- for (i = 0; i < W9968CF_URBS; i++) {
- kfree(cam->transfer_buffer[i]);
- cam->transfer_buffer[i] = NULL;
- }
-
- /* Free temporary frame buffer */
- if (cam->frame_tmp.buffer) {
- rvfree(cam->frame_tmp.buffer, cam->frame_tmp.size);
- cam->frame_tmp.buffer = NULL;
- }
-
- /* Free helper buffer */
- if (cam->frame_vpp.buffer) {
- rvfree(cam->frame_vpp.buffer, cam->frame_vpp.size);
- cam->frame_vpp.buffer = NULL;
- }
-
- /* Free video frame buffers */
- if (cam->frame[0].buffer) {
- rvfree(cam->frame[0].buffer, cam->nbuffers*cam->frame[0].size);
- cam->frame[0].buffer = NULL;
- }
-
- cam->nbuffers = 0;
-
- DBG(5, "Memory successfully deallocated")
-}
-
-
-/*--------------------------------------------------------------------------
- Allocate memory buffers for USB transfers and video frames.
- This function is called by open() only.
- Return 0 on success, a negative number otherwise.
- --------------------------------------------------------------------------*/
-static int w9968cf_allocate_memory(struct w9968cf_device* cam)
-{
- const u16 p_size = wMaxPacketSize[cam->altsetting-1];
- void* buff = NULL;
- unsigned long hw_bufsize, vpp_bufsize;
- u8 i, bpp;
-
- /* NOTE: Deallocation is done elsewhere in case of error */
-
- /* Calculate the max amount of raw data per frame from the device */
- hw_bufsize = cam->maxwidth*cam->maxheight*2;
-
- /* Calculate the max buf. size needed for post-processing routines */
- bpp = (w9968cf_vpp) ? 4 : 2;
- if (cam->upscaling)
- vpp_bufsize = max(W9968CF_MAX_WIDTH*W9968CF_MAX_HEIGHT*bpp,
- cam->maxwidth*cam->maxheight*bpp);
- else
- vpp_bufsize = cam->maxwidth*cam->maxheight*bpp;
-
- /* Allocate memory for the isochronous transfer buffers */
- for (i = 0; i < W9968CF_URBS; i++) {
- if (!(cam->transfer_buffer[i] =
- kzalloc(W9968CF_ISO_PACKETS*p_size, GFP_KERNEL))) {
- DBG(1, "Couldn't allocate memory for the isochronous "
- "transfer buffers (%u bytes)",
- p_size * W9968CF_ISO_PACKETS)
- return -ENOMEM;
- }
- }
-
- /* Allocate memory for the temporary frame buffer */
- if (!(cam->frame_tmp.buffer = rvmalloc(hw_bufsize))) {
- DBG(1, "Couldn't allocate memory for the temporary "
- "video frame buffer (%lu bytes)", hw_bufsize)
- return -ENOMEM;
- }
- cam->frame_tmp.size = hw_bufsize;
- cam->frame_tmp.number = -1;
-
- /* Allocate memory for the helper buffer */
- if (w9968cf_vpp) {
- if (!(cam->frame_vpp.buffer = rvmalloc(vpp_bufsize))) {
- DBG(1, "Couldn't allocate memory for the helper buffer"
- " (%lu bytes)", vpp_bufsize)
- return -ENOMEM;
- }
- cam->frame_vpp.size = vpp_bufsize;
- } else
- cam->frame_vpp.buffer = NULL;
-
- /* Allocate memory for video frame buffers */
- cam->nbuffers = cam->max_buffers;
- while (cam->nbuffers >= 2) {
- if ((buff = rvmalloc(cam->nbuffers * vpp_bufsize)))
- break;
- else
- cam->nbuffers--;
- }
-
- if (!buff) {
- DBG(1, "Couldn't allocate memory for the video frame buffers")
- cam->nbuffers = 0;
- return -ENOMEM;
- }
-
- if (cam->nbuffers != cam->max_buffers)
- DBG(2, "Couldn't allocate memory for %u video frame buffers. "
- "Only memory for %u buffers has been allocated",
- cam->max_buffers, cam->nbuffers)
-
- for (i = 0; i < cam->nbuffers; i++) {
- cam->frame[i].buffer = buff + i*vpp_bufsize;
- cam->frame[i].size = vpp_bufsize;
- cam->frame[i].number = i;
- /* Circular list */
- if (i != cam->nbuffers-1)
- cam->frame[i].next = &cam->frame[i+1];
- else
- cam->frame[i].next = &cam->frame[0];
- cam->frame[i].status = F_UNUSED;
- }
-
- DBG(5, "Memory successfully allocated")
- return 0;
-}
-
-
-
-/****************************************************************************
- * USB-specific functions *
- ****************************************************************************/
-
-/*--------------------------------------------------------------------------
- This is an handler function which is called after the URBs are completed.
- It collects multiple data packets coming from the camera by putting them
- into frame buffers: one or more zero data length data packets are used to
- mark the end of a video frame; the first non-zero data packet is the start
- of the next video frame; if an error is encountered in a packet, the entire
- video frame is discarded and grabbed again.
- If there are no requested frames in the FIFO list, packets are collected into
- a temporary buffer.
- --------------------------------------------------------------------------*/
-static void w9968cf_urb_complete(struct urb *urb)
-{
- struct w9968cf_device* cam = (struct w9968cf_device*)urb->context;
- struct w9968cf_frame_t** f;
- unsigned int len, status;
- void* pos;
- u8 i;
- int err = 0;
-
- if ((!cam->streaming) || cam->disconnected) {
- DBG(4, "Got interrupt, but not streaming")
- return;
- }
-
- /* "(*f)" will be used instead of "cam->frame_current" */
- f = &cam->frame_current;
-
- /* If a frame has been requested and we are grabbing into
- the temporary frame, we'll switch to that requested frame */
- if ((*f) == &cam->frame_tmp && *cam->requested_frame) {
- if (cam->frame_tmp.status == F_GRABBING) {
- w9968cf_pop_frame(cam, &cam->frame_current);
- (*f)->status = F_GRABBING;
- (*f)->length = cam->frame_tmp.length;
- memcpy((*f)->buffer, cam->frame_tmp.buffer,
- (*f)->length);
- DBG(6, "Switched from temp. frame to frame #%d",
- (*f)->number)
- }
- }
-
- for (i = 0; i < urb->number_of_packets; i++) {
- len = urb->iso_frame_desc[i].actual_length;
- status = urb->iso_frame_desc[i].status;
- pos = urb->iso_frame_desc[i].offset + urb->transfer_buffer;
-
- if (status && len != 0) {
- DBG(4, "URB failed, error in data packet "
- "(error #%u, %s)",
- status, symbolic(urb_errlist, status))
- (*f)->status = F_ERROR;
- continue;
- }
-
- if (len) { /* start of frame */
-
- if ((*f)->status == F_UNUSED) {
- (*f)->status = F_GRABBING;
- (*f)->length = 0;
- }
-
- /* Buffer overflows shouldn't happen, however...*/
- if ((*f)->length + len > (*f)->size) {
- DBG(4, "Buffer overflow: bad data packets")
- (*f)->status = F_ERROR;
- }
-
- if ((*f)->status == F_GRABBING) {
- memcpy((*f)->buffer + (*f)->length, pos, len);
- (*f)->length += len;
- }
-
- } else if ((*f)->status == F_GRABBING) { /* end of frame */
-
- DBG(6, "Frame #%d successfully grabbed", (*f)->number)
-
- if (cam->vpp_flag & VPP_DECOMPRESSION) {
- err = w9968cf_vpp->check_headers((*f)->buffer,
- (*f)->length);
- if (err) {
- DBG(4, "Skip corrupted frame: %s",
- symbolic(decoder_errlist, err))
- (*f)->status = F_UNUSED;
- continue; /* grab this frame again */
- }
- }
-
- (*f)->status = F_READY;
- (*f)->queued = 0;
-
- /* Take a pointer to the new frame from the FIFO list.
- If the list is empty,we'll use the temporary frame*/
- if (*cam->requested_frame)
- w9968cf_pop_frame(cam, &cam->frame_current);
- else {
- cam->frame_current = &cam->frame_tmp;
- (*f)->status = F_UNUSED;
- }
-
- } else if ((*f)->status == F_ERROR)
- (*f)->status = F_UNUSED; /* grab it again */
-
- PDBGG("Frame length %lu | pack.#%u | pack.len. %u | state %d",
- (unsigned long)(*f)->length, i, len, (*f)->status)
-
- } /* end for */
-
- /* Resubmit this URB */
- urb->dev = cam->usbdev;
- urb->status = 0;
- spin_lock(&cam->urb_lock);
- if (cam->streaming)
- if ((err = usb_submit_urb(urb, GFP_ATOMIC))) {
- cam->misconfigured = 1;
- DBG(1, "Couldn't resubmit the URB: error %d, %s",
- err, symbolic(urb_errlist, err))
- }
- spin_unlock(&cam->urb_lock);
-
- /* Wake up the user process */
- wake_up_interruptible(&cam->wait_queue);
-}
-
-
-/*---------------------------------------------------------------------------
- Setup the URB structures for the isochronous transfer.
- Submit the URBs so that the data transfer begins.
- Return 0 on success, a negative number otherwise.
- ---------------------------------------------------------------------------*/
-static int w9968cf_start_transfer(struct w9968cf_device* cam)
-{
- struct usb_device *udev = cam->usbdev;
- struct urb* urb;
- const u16 p_size = wMaxPacketSize[cam->altsetting-1];
- u16 w, h, d;
- int vidcapt;
- u32 t_size;
- int err = 0;
- s8 i, j;
-
- for (i = 0; i < W9968CF_URBS; i++) {
- urb = usb_alloc_urb(W9968CF_ISO_PACKETS, GFP_KERNEL);
- if (!urb) {
- for (j = 0; j < i; j++)
- usb_free_urb(cam->urb[j]);
- DBG(1, "Couldn't allocate the URB structures")
- return -ENOMEM;
- }
-
- cam->urb[i] = urb;
- urb->dev = udev;
- urb->context = (void*)cam;
- urb->pipe = usb_rcvisocpipe(udev, 1);
- urb->transfer_flags = URB_ISO_ASAP;
- urb->number_of_packets = W9968CF_ISO_PACKETS;
- urb->complete = w9968cf_urb_complete;
- urb->transfer_buffer = cam->transfer_buffer[i];
- urb->transfer_buffer_length = p_size*W9968CF_ISO_PACKETS;
- urb->interval = 1;
- for (j = 0; j < W9968CF_ISO_PACKETS; j++) {
- urb->iso_frame_desc[j].offset = p_size*j;
- urb->iso_frame_desc[j].length = p_size;
- }
- }
-
- /* Transfer size per frame, in WORD ! */
- d = cam->hw_depth;
- w = cam->hw_width;
- h = cam->hw_height;
-
- t_size = (w*h*d)/16;
-
- err = w9968cf_write_reg(cam, 0xbf17, 0x00); /* reset everything */
- err += w9968cf_write_reg(cam, 0xbf10, 0x00); /* normal operation */
-
- /* Transfer size */
- err += w9968cf_write_reg(cam, t_size & 0xffff, 0x3d); /* low bits */
- err += w9968cf_write_reg(cam, t_size >> 16, 0x3e); /* high bits */
-
- if (cam->vpp_flag & VPP_DECOMPRESSION)
- err += w9968cf_upload_quantizationtables(cam);
-
- vidcapt = w9968cf_read_reg(cam, 0x16); /* read picture settings */
- err += w9968cf_write_reg(cam, vidcapt|0x8000, 0x16); /* capt. enable */
-
- err += usb_set_interface(udev, 0, cam->altsetting);
- err += w9968cf_write_reg(cam, 0x8a05, 0x3c); /* USB FIFO enable */
-
- if (err || (vidcapt < 0)) {
- for (i = 0; i < W9968CF_URBS; i++)
- usb_free_urb(cam->urb[i]);
- DBG(1, "Couldn't tell the camera to start the data transfer")
- return err;
- }
-
- w9968cf_init_framelist(cam);
-
- /* Begin to grab into the temporary buffer */
- cam->frame_tmp.status = F_UNUSED;
- cam->frame_tmp.queued = 0;
- cam->frame_current = &cam->frame_tmp;
-
- if (!(cam->vpp_flag & VPP_DECOMPRESSION))
- DBG(5, "Isochronous transfer size: %lu bytes/frame",
- (unsigned long)t_size*2)
-
- DBG(5, "Starting the isochronous transfer...")
-
- cam->streaming = 1;
-
- /* Submit the URBs */
- for (i = 0; i < W9968CF_URBS; i++) {
- err = usb_submit_urb(cam->urb[i], GFP_KERNEL);
- if (err) {
- cam->streaming = 0;
- for (j = i-1; j >= 0; j--) {
- usb_kill_urb(cam->urb[j]);
- usb_free_urb(cam->urb[j]);
- }
- DBG(1, "Couldn't send a transfer request to the "
- "USB core (error #%d, %s)", err,
- symbolic(urb_errlist, err))
- return err;
- }
- }
-
- return 0;
-}
-
-
-/*--------------------------------------------------------------------------
- Stop the isochronous transfer and set alternate setting to 0 (0Mb/s).
- Return 0 on success, a negative number otherwise.
- --------------------------------------------------------------------------*/
-static int w9968cf_stop_transfer(struct w9968cf_device* cam)
-{
- struct usb_device *udev = cam->usbdev;
- unsigned long lock_flags;
- int err = 0;
- s8 i;
-
- if (!cam->streaming)
- return 0;
-
- /* This avoids race conditions with usb_submit_urb()
- in the URB completition handler */
- spin_lock_irqsave(&cam->urb_lock, lock_flags);
- cam->streaming = 0;
- spin_unlock_irqrestore(&cam->urb_lock, lock_flags);
-
- for (i = W9968CF_URBS-1; i >= 0; i--)
- if (cam->urb[i]) {
- usb_kill_urb(cam->urb[i]);
- usb_free_urb(cam->urb[i]);
- cam->urb[i] = NULL;
- }
-
- if (cam->disconnected)
- goto exit;
-
- err = w9968cf_write_reg(cam, 0x0a05, 0x3c); /* stop USB transfer */
- err += usb_set_interface(udev, 0, 0); /* 0 Mb/s */
- err += w9968cf_write_reg(cam, 0x0000, 0x39); /* disable JPEG encoder */
- err += w9968cf_write_reg(cam, 0x0000, 0x16); /* stop video capture */
-
- if (err) {
- DBG(2, "Failed to tell the camera to stop the isochronous "
- "transfer. However this is not a critical error.")
- return -EIO;
- }
-
-exit:
- DBG(5, "Isochronous transfer stopped")
- return 0;
-}
-
-
-/*--------------------------------------------------------------------------
- Write a W9968CF register.
- Return 0 on success, -1 otherwise.
- --------------------------------------------------------------------------*/
-static int w9968cf_write_reg(struct w9968cf_device* cam, u16 value, u16 index)
-{
- struct usb_device* udev = cam->usbdev;
- int res;
-
- res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0,
- USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE,
- value, index, NULL, 0, W9968CF_USB_CTRL_TIMEOUT);
-
- if (res < 0)
- DBG(4, "Failed to write a register "
- "(value 0x%04X, index 0x%02X, error #%d, %s)",
- value, index, res, symbolic(urb_errlist, res))
-
- return (res >= 0) ? 0 : -1;
-}
-
-
-/*--------------------------------------------------------------------------
- Read a W9968CF register.
- Return the register value on success, -1 otherwise.
- --------------------------------------------------------------------------*/
-static int w9968cf_read_reg(struct w9968cf_device* cam, u16 index)
-{
- struct usb_device* udev = cam->usbdev;
- u16* buff = cam->control_buffer;
- int res;
-
- res = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 1,
- USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
- 0, index, buff, 2, W9968CF_USB_CTRL_TIMEOUT);
-
- if (res < 0)
- DBG(4, "Failed to read a register "
- "(index 0x%02X, error #%d, %s)",
- index, res, symbolic(urb_errlist, res))
-
- return (res >= 0) ? (int)(*buff) : -1;
-}
-
-
-/*--------------------------------------------------------------------------
- Write 64-bit data to the fast serial bus registers.
- Return 0 on success, -1 otherwise.
- --------------------------------------------------------------------------*/
-static int w9968cf_write_fsb(struct w9968cf_device* cam, u16* data)
-{
- struct usb_device* udev = cam->usbdev;
- u16 value;
- int res;
-
- value = *data++;
-
- res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0,
- USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE,
- value, 0x06, data, 6, W9968CF_USB_CTRL_TIMEOUT);
-
- if (res < 0)
- DBG(4, "Failed to write the FSB registers "
- "(error #%d, %s)", res, symbolic(urb_errlist, res))
-
- return (res >= 0) ? 0 : -1;
-}
-
-
-/*--------------------------------------------------------------------------
- Write data to the serial bus control register.
- Return 0 on success, a negative number otherwise.
- --------------------------------------------------------------------------*/
-static int w9968cf_write_sb(struct w9968cf_device* cam, u16 value)
-{
- int err = 0;
-
- err = w9968cf_write_reg(cam, value, 0x01);
- udelay(W9968CF_I2C_BUS_DELAY);
-
- return err;
-}
-
-
-/*--------------------------------------------------------------------------
- Read data from the serial bus control register.
- Return 0 on success, a negative number otherwise.
- --------------------------------------------------------------------------*/
-static int w9968cf_read_sb(struct w9968cf_device* cam)
-{
- int v = 0;
-
- v = w9968cf_read_reg(cam, 0x01);
- udelay(W9968CF_I2C_BUS_DELAY);
-
- return v;
-}
-
-
-/*--------------------------------------------------------------------------
- Upload quantization tables for the JPEG compression.
- This function is called by w9968cf_start_transfer().
- Return 0 on success, a negative number otherwise.
- --------------------------------------------------------------------------*/
-static int w9968cf_upload_quantizationtables(struct w9968cf_device* cam)
-{
- u16 a, b;
- int err = 0, i, j;
-
- err += w9968cf_write_reg(cam, 0x0010, 0x39); /* JPEG clock enable */
-
- for (i = 0, j = 0; i < 32; i++, j += 2) {
- a = Y_QUANTABLE[j] | ((unsigned)(Y_QUANTABLE[j+1]) << 8);
- b = UV_QUANTABLE[j] | ((unsigned)(UV_QUANTABLE[j+1]) << 8);
- err += w9968cf_write_reg(cam, a, 0x40+i);
- err += w9968cf_write_reg(cam, b, 0x60+i);
- }
- err += w9968cf_write_reg(cam, 0x0012, 0x39); /* JPEG encoder enable */
-
- return err;
-}
-
-
-
-/****************************************************************************
- * Low-level I2C I/O functions. *
- * The adapter supports the following I2C transfer functions: *
- * i2c_adap_fastwrite_byte_data() (at 400 kHz bit frequency only) *
- * i2c_adap_read_byte_data() *
- * i2c_adap_read_byte() *
- ****************************************************************************/
-
-static int w9968cf_smbus_start(struct w9968cf_device* cam)
-{
- int err = 0;
-
- err += w9968cf_write_sb(cam, 0x0011); /* SDE=1, SDA=0, SCL=1 */
- err += w9968cf_write_sb(cam, 0x0010); /* SDE=1, SDA=0, SCL=0 */
-
- return err;
-}
-
-
-static int w9968cf_smbus_stop(struct w9968cf_device* cam)
-{
- int err = 0;
-
- err += w9968cf_write_sb(cam, 0x0011); /* SDE=1, SDA=0, SCL=1 */
- err += w9968cf_write_sb(cam, 0x0013); /* SDE=1, SDA=1, SCL=1 */
-
- return err;
-}
-
-
-static int w9968cf_smbus_write_byte(struct w9968cf_device* cam, u8 v)
-{
- u8 bit;
- int err = 0, sda;
-
- for (bit = 0 ; bit < 8 ; bit++) {
- sda = (v & 0x80) ? 2 : 0;
- v <<= 1;
- /* SDE=1, SDA=sda, SCL=0 */
- err += w9968cf_write_sb(cam, 0x10 | sda);
- /* SDE=1, SDA=sda, SCL=1 */
- err += w9968cf_write_sb(cam, 0x11 | sda);
- /* SDE=1, SDA=sda, SCL=0 */
- err += w9968cf_write_sb(cam, 0x10 | sda);
- }
-
- return err;
-}
-
-
-static int w9968cf_smbus_read_byte(struct w9968cf_device* cam, u8* v)
-{
- u8 bit;
- int err = 0;
-
- *v = 0;
- for (bit = 0 ; bit < 8 ; bit++) {
- *v <<= 1;
- err += w9968cf_write_sb(cam, 0x0013);
- *v |= (w9968cf_read_sb(cam) & 0x0008) ? 1 : 0;
- err += w9968cf_write_sb(cam, 0x0012);
- }
-
- return err;
-}
-
-
-static int w9968cf_smbus_write_ack(struct w9968cf_device* cam)
-{
- int err = 0;
-
- err += w9968cf_write_sb(cam, 0x0010); /* SDE=1, SDA=0, SCL=0 */
- err += w9968cf_write_sb(cam, 0x0011); /* SDE=1, SDA=0, SCL=1 */
- err += w9968cf_write_sb(cam, 0x0010); /* SDE=1, SDA=0, SCL=0 */
-
- return err;
-}
-
-
-static int w9968cf_smbus_read_ack(struct w9968cf_device* cam)
-{
- int err = 0, sda;
-
- err += w9968cf_write_sb(cam, 0x0013); /* SDE=1, SDA=1, SCL=1 */
- sda = (w9968cf_read_sb(cam) & 0x08) ? 1 : 0; /* sda = SDA */
- err += w9968cf_write_sb(cam, 0x0012); /* SDE=1, SDA=1, SCL=0 */
- if (sda < 0)
- err += sda;
- if (sda == 1) {
- DBG(6, "Couldn't receive the ACK")
- err += -1;
- }
-
- return err;
-}
-
-
-/* This seems to refresh the communication through the serial bus */
-static int w9968cf_smbus_refresh_bus(struct w9968cf_device* cam)
-{
- int err = 0, j;
-
- for (j = 1; j <= 10; j++) {
- err = w9968cf_write_reg(cam, 0x0020, 0x01);
- err += w9968cf_write_reg(cam, 0x0000, 0x01);
- if (err)
- break;
- }
-
- return err;
-}
-
-
-/* SMBus protocol: S Addr Wr [A] Subaddr [A] Value [A] P */
-static int
-w9968cf_i2c_adap_fastwrite_byte_data(struct w9968cf_device* cam,
- u16 address, u8 subaddress,u8 value)
-{
- u16* data = cam->data_buffer;
- int err = 0;
-
- err += w9968cf_smbus_refresh_bus(cam);
-
- /* Enable SBUS outputs */
- err += w9968cf_write_sb(cam, 0x0020);
-
- data[0] = 0x082f | ((address & 0x80) ? 0x1500 : 0x0);
- data[0] |= (address & 0x40) ? 0x4000 : 0x0;
- data[1] = 0x2082 | ((address & 0x40) ? 0x0005 : 0x0);
- data[1] |= (address & 0x20) ? 0x0150 : 0x0;
- data[1] |= (address & 0x10) ? 0x5400 : 0x0;
- data[2] = 0x8208 | ((address & 0x08) ? 0x0015 : 0x0);
- data[2] |= (address & 0x04) ? 0x0540 : 0x0;
- data[2] |= (address & 0x02) ? 0x5000 : 0x0;
- data[3] = 0x1d20 | ((address & 0x02) ? 0x0001 : 0x0);
- data[3] |= (address & 0x01) ? 0x0054 : 0x0;
-
- err += w9968cf_write_fsb(cam, data);
-
- data[0] = 0x8208 | ((subaddress & 0x80) ? 0x0015 : 0x0);
- data[0] |= (subaddress & 0x40) ? 0x0540 : 0x0;
- data[0] |= (subaddress & 0x20) ? 0x5000 : 0x0;
- data[1] = 0x0820 | ((subaddress & 0x20) ? 0x0001 : 0x0);
- data[1] |= (subaddress & 0x10) ? 0x0054 : 0x0;
- data[1] |= (subaddress & 0x08) ? 0x1500 : 0x0;
- data[1] |= (subaddress & 0x04) ? 0x4000 : 0x0;
- data[2] = 0x2082 | ((subaddress & 0x04) ? 0x0005 : 0x0);
- data[2] |= (subaddress & 0x02) ? 0x0150 : 0x0;
- data[2] |= (subaddress & 0x01) ? 0x5400 : 0x0;
- data[3] = 0x001d;
-
- err += w9968cf_write_fsb(cam, data);
-
- data[0] = 0x8208 | ((value & 0x80) ? 0x0015 : 0x0);
- data[0] |= (value & 0x40) ? 0x0540 : 0x0;
- data[0] |= (value & 0x20) ? 0x5000 : 0x0;
- data[1] = 0x0820 | ((value & 0x20) ? 0x0001 : 0x0);
- data[1] |= (value & 0x10) ? 0x0054 : 0x0;
- data[1] |= (value & 0x08) ? 0x1500 : 0x0;
- data[1] |= (value & 0x04) ? 0x4000 : 0x0;
- data[2] = 0x2082 | ((value & 0x04) ? 0x0005 : 0x0);
- data[2] |= (value & 0x02) ? 0x0150 : 0x0;
- data[2] |= (value & 0x01) ? 0x5400 : 0x0;
- data[3] = 0xfe1d;
-
- err += w9968cf_write_fsb(cam, data);
-
- /* Disable SBUS outputs */
- err += w9968cf_write_sb(cam, 0x0000);
-
- if (!err)
- DBG(5, "I2C write byte data done, addr.0x%04X, subaddr.0x%02X "
- "value 0x%02X", address, subaddress, value)
- else
- DBG(5, "I2C write byte data failed, addr.0x%04X, "
- "subaddr.0x%02X, value 0x%02X",
- address, subaddress, value)
-
- return err;
-}
-
-
-/* SMBus protocol: S Addr Wr [A] Subaddr [A] P S Addr+1 Rd [A] [Value] NA P */
-static int
-w9968cf_i2c_adap_read_byte_data(struct w9968cf_device* cam,
- u16 address, u8 subaddress,
- u8* value)
-{
- int err = 0;
-
- /* Serial data enable */
- err += w9968cf_write_sb(cam, 0x0013); /* don't change ! */
-
- err += w9968cf_smbus_start(cam);
- err += w9968cf_smbus_write_byte(cam, address);
- err += w9968cf_smbus_read_ack(cam);
- err += w9968cf_smbus_write_byte(cam, subaddress);
- err += w9968cf_smbus_read_ack(cam);
- err += w9968cf_smbus_stop(cam);
- err += w9968cf_smbus_start(cam);
- err += w9968cf_smbus_write_byte(cam, address + 1);
- err += w9968cf_smbus_read_ack(cam);
- err += w9968cf_smbus_read_byte(cam, value);
- err += w9968cf_smbus_write_ack(cam);
- err += w9968cf_smbus_stop(cam);
-
- /* Serial data disable */
- err += w9968cf_write_sb(cam, 0x0000);
-
- if (!err)
- DBG(5, "I2C read byte data done, addr.0x%04X, "
- "subaddr.0x%02X, value 0x%02X",
- address, subaddress, *value)
- else
- DBG(5, "I2C read byte data failed, addr.0x%04X, "
- "subaddr.0x%02X, wrong value 0x%02X",
- address, subaddress, *value)
-
- return err;
-}
-
-
-/* SMBus protocol: S Addr+1 Rd [A] [Value] NA P */
-static int
-w9968cf_i2c_adap_read_byte(struct w9968cf_device* cam,
- u16 address, u8* value)
-{
- int err = 0;
-
- /* Serial data enable */
- err += w9968cf_write_sb(cam, 0x0013);
-
- err += w9968cf_smbus_start(cam);
- err += w9968cf_smbus_write_byte(cam, address + 1);
- err += w9968cf_smbus_read_ack(cam);
- err += w9968cf_smbus_read_byte(cam, value);
- err += w9968cf_smbus_write_ack(cam);
- err += w9968cf_smbus_stop(cam);
-
- /* Serial data disable */
- err += w9968cf_write_sb(cam, 0x0000);
-
- if (!err)
- DBG(5, "I2C read byte done, addr.0x%04X, "
- "value 0x%02X", address, *value)
- else
- DBG(5, "I2C read byte failed, addr.0x%04X, "
- "wrong value 0x%02X", address, *value)
-
- return err;
-}
-
-
-/* SMBus protocol: S Addr Wr [A] Value [A] P */
-static int
-w9968cf_i2c_adap_write_byte(struct w9968cf_device* cam,
- u16 address, u8 value)
-{
- DBG(4, "i2c_write_byte() is an unsupported transfer mode")
- return -EINVAL;
-}
-
-
-
-/****************************************************************************
- * I2C interface to kernel *
- ****************************************************************************/
-
-static int
-w9968cf_i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr,
- unsigned short flags, char read_write, u8 command,
- int size, union i2c_smbus_data *data)
-{
- struct v4l2_device *v4l2_dev = i2c_get_adapdata(adapter);
- struct w9968cf_device *cam = to_cam(v4l2_dev);
- u8 i;
- int err = 0;
-
- if (size == I2C_SMBUS_BYTE) {
- /* Why addr <<= 1? See OVXXX0_SID defines in ovcamchip.h */
- addr <<= 1;
-
- if (read_write == I2C_SMBUS_WRITE)
- err = w9968cf_i2c_adap_write_byte(cam, addr, command);
- else if (read_write == I2C_SMBUS_READ)
- for (i = 1; i <= W9968CF_I2C_RW_RETRIES; i++) {
- err = w9968cf_i2c_adap_read_byte(cam, addr,
- &data->byte);
- if (err) {
- if (w9968cf_smbus_refresh_bus(cam)) {
- err = -EIO;
- break;
- }
- } else
- break;
- }
- } else if (size == I2C_SMBUS_BYTE_DATA) {
- addr <<= 1;
-
- if (read_write == I2C_SMBUS_WRITE)
- err = w9968cf_i2c_adap_fastwrite_byte_data(cam, addr,
- command, data->byte);
- else if (read_write == I2C_SMBUS_READ) {
- for (i = 1; i <= W9968CF_I2C_RW_RETRIES; i++) {
- err = w9968cf_i2c_adap_read_byte_data(cam,addr,
- command, &data->byte);
- if (err) {
- if (w9968cf_smbus_refresh_bus(cam)) {
- err = -EIO;
- break;
- }
- } else
- break;
- }
-
- } else
- return -EINVAL;
-
- } else {
- DBG(4, "Unsupported I2C transfer mode (%d)", size)
- return -EINVAL;
- }
- return err;
-}
-
-
-static u32 w9968cf_i2c_func(struct i2c_adapter* adap)
-{
- return I2C_FUNC_SMBUS_READ_BYTE |
- I2C_FUNC_SMBUS_READ_BYTE_DATA |
- I2C_FUNC_SMBUS_WRITE_BYTE_DATA;
-}
-
-
-static int w9968cf_i2c_init(struct w9968cf_device* cam)
-{
- int err = 0;
-
- static struct i2c_algorithm algo = {
- .smbus_xfer = w9968cf_i2c_smbus_xfer,
- .functionality = w9968cf_i2c_func,
- };
-
- static struct i2c_adapter adap = {
- .owner = THIS_MODULE,
- .algo = &algo,
- };
-
- memcpy(&cam->i2c_adapter, &adap, sizeof(struct i2c_adapter));
- strcpy(cam->i2c_adapter.name, "w9968cf");
- cam->i2c_adapter.dev.parent = &cam->usbdev->dev;
- i2c_set_adapdata(&cam->i2c_adapter, &cam->v4l2_dev);
-
- DBG(6, "Registering I2C adapter with kernel...")
-
- err = i2c_add_adapter(&cam->i2c_adapter);
- if (err)
- DBG(1, "Failed to register the I2C adapter")
- else
- DBG(5, "I2C adapter registered")
-
- return err;
-}
-
-
-
-/****************************************************************************
- * Helper functions *
- ****************************************************************************/
-
-/*--------------------------------------------------------------------------
- Turn on the LED on some webcams. A beep should be heard too.
- Return 0 on success, a negative number otherwise.
- --------------------------------------------------------------------------*/
-static int w9968cf_turn_on_led(struct w9968cf_device* cam)
-{
- int err = 0;
-
- err += w9968cf_write_reg(cam, 0xff00, 0x00); /* power-down */
- err += w9968cf_write_reg(cam, 0xbf17, 0x00); /* reset everything */
- err += w9968cf_write_reg(cam, 0xbf10, 0x00); /* normal operation */
- err += w9968cf_write_reg(cam, 0x0010, 0x01); /* serial bus, SDS high */
- err += w9968cf_write_reg(cam, 0x0000, 0x01); /* serial bus, SDS low */
- err += w9968cf_write_reg(cam, 0x0010, 0x01); /* ..high 'beep-beep' */
-
- if (err)
- DBG(2, "Couldn't turn on the LED")
-
- DBG(5, "LED turned on")
-
- return err;
-}
-
-
-/*--------------------------------------------------------------------------
- Write some registers for the device initialization.
- This function is called once on open().
- Return 0 on success, a negative number otherwise.
- --------------------------------------------------------------------------*/
-static int w9968cf_init_chip(struct w9968cf_device* cam)
-{
- unsigned long hw_bufsize = cam->maxwidth*cam->maxheight*2,
- y0 = 0x0000,
- u0 = y0 + hw_bufsize/2,
- v0 = u0 + hw_bufsize/4,
- y1 = v0 + hw_bufsize/4,
- u1 = y1 + hw_bufsize/2,
- v1 = u1 + hw_bufsize/4;
- int err = 0;
-
- err += w9968cf_write_reg(cam, 0xff00, 0x00); /* power off */
- err += w9968cf_write_reg(cam, 0xbf10, 0x00); /* power on */
-
- err += w9968cf_write_reg(cam, 0x405d, 0x03); /* DRAM timings */
- err += w9968cf_write_reg(cam, 0x0030, 0x04); /* SDRAM timings */
-
- err += w9968cf_write_reg(cam, y0 & 0xffff, 0x20); /* Y buf.0, low */
- err += w9968cf_write_reg(cam, y0 >> 16, 0x21); /* Y buf.0, high */
- err += w9968cf_write_reg(cam, u0 & 0xffff, 0x24); /* U buf.0, low */
- err += w9968cf_write_reg(cam, u0 >> 16, 0x25); /* U buf.0, high */
- err += w9968cf_write_reg(cam, v0 & 0xffff, 0x28); /* V buf.0, low */
- err += w9968cf_write_reg(cam, v0 >> 16, 0x29); /* V buf.0, high */
-
- err += w9968cf_write_reg(cam, y1 & 0xffff, 0x22); /* Y buf.1, low */
- err += w9968cf_write_reg(cam, y1 >> 16, 0x23); /* Y buf.1, high */
- err += w9968cf_write_reg(cam, u1 & 0xffff, 0x26); /* U buf.1, low */
- err += w9968cf_write_reg(cam, u1 >> 16, 0x27); /* U buf.1, high */
- err += w9968cf_write_reg(cam, v1 & 0xffff, 0x2a); /* V buf.1, low */
- err += w9968cf_write_reg(cam, v1 >> 16, 0x2b); /* V buf.1, high */
-
- err += w9968cf_write_reg(cam, y1 & 0xffff, 0x32); /* JPEG buf 0 low */
- err += w9968cf_write_reg(cam, y1 >> 16, 0x33); /* JPEG buf 0 high */
-
- err += w9968cf_write_reg(cam, y1 & 0xffff, 0x34); /* JPEG buf 1 low */
- err += w9968cf_write_reg(cam, y1 >> 16, 0x35); /* JPEG bug 1 high */
-
- err += w9968cf_write_reg(cam, 0x0000, 0x36);/* JPEG restart interval */
- err += w9968cf_write_reg(cam, 0x0804, 0x37);/*JPEG VLE FIFO threshold*/
- err += w9968cf_write_reg(cam, 0x0000, 0x38);/* disable hw up-scaling */
- err += w9968cf_write_reg(cam, 0x0000, 0x3f); /* JPEG/MCTL test data */
-
- err += w9968cf_set_picture(cam, cam->picture); /* this before */
- err += w9968cf_set_window(cam, cam->window);
-
- if (err)
- DBG(1, "Chip initialization failed")
- else
- DBG(5, "Chip successfully initialized")
-
- return err;
-}
-
-
-/*--------------------------------------------------------------------------
- Return non-zero if the palette is supported, 0 otherwise.
- --------------------------------------------------------------------------*/
-static inline u16 w9968cf_valid_palette(u16 palette)
-{
- u8 i = 0;
- while (w9968cf_formatlist[i].palette != 0) {
- if (palette == w9968cf_formatlist[i].palette)
- return palette;
- i++;
- }
- return 0;
-}
-
-
-/*--------------------------------------------------------------------------
- Return the depth corresponding to the given palette.
- Palette _must_ be supported !
- --------------------------------------------------------------------------*/
-static inline u16 w9968cf_valid_depth(u16 palette)
-{
- u8 i=0;
- while (w9968cf_formatlist[i].palette != palette)
- i++;
-
- return w9968cf_formatlist[i].depth;
-}
-
-
-/*--------------------------------------------------------------------------
- Return non-zero if the format requires decompression, 0 otherwise.
- --------------------------------------------------------------------------*/
-static inline u8 w9968cf_need_decompression(u16 palette)
-{
- u8 i = 0;
- while (w9968cf_formatlist[i].palette != 0) {
- if (palette == w9968cf_formatlist[i].palette)
- return w9968cf_formatlist[i].compression;
- i++;
- }
- return 0;
-}
-
-
-/*--------------------------------------------------------------------------
- Change the picture settings of the camera.
- Return 0 on success, a negative number otherwise.
- --------------------------------------------------------------------------*/
-static int
-w9968cf_set_picture(struct w9968cf_device* cam, struct video_picture pict)
-{
- u16 fmt, hw_depth, hw_palette, reg_v = 0x0000;
- int err = 0;
-
- /* Make sure we are using a valid depth */
- pict.depth = w9968cf_valid_depth(pict.palette);
-
- fmt = pict.palette;
-
- hw_depth = pict.depth; /* depth used by the winbond chip */
- hw_palette = pict.palette; /* palette used by the winbond chip */
-
- /* VS & HS polarities */
- reg_v = (cam->vs_polarity << 12) | (cam->hs_polarity << 11);
-
- switch (fmt)
- {
- case VIDEO_PALETTE_UYVY:
- reg_v |= 0x0000;
- cam->vpp_flag = VPP_NONE;
- break;
- case VIDEO_PALETTE_YUV422P:
- reg_v |= 0x0002;
- cam->vpp_flag = VPP_DECOMPRESSION;
- break;
- case VIDEO_PALETTE_YUV420:
- case VIDEO_PALETTE_YUV420P:
- reg_v |= 0x0003;
- cam->vpp_flag = VPP_DECOMPRESSION;
- break;
- case VIDEO_PALETTE_YUYV:
- case VIDEO_PALETTE_YUV422:
- reg_v |= 0x0000;
- cam->vpp_flag = VPP_SWAP_YUV_BYTES;
- hw_palette = VIDEO_PALETTE_UYVY;
- break;
- /* Original video is used instead of RGBX palettes.
- Software conversion later. */
- case VIDEO_PALETTE_GREY:
- case VIDEO_PALETTE_RGB555:
- case VIDEO_PALETTE_RGB565:
- case VIDEO_PALETTE_RGB24:
- case VIDEO_PALETTE_RGB32:
- reg_v |= 0x0000; /* UYVY 16 bit is used */
- hw_depth = 16;
- hw_palette = VIDEO_PALETTE_UYVY;
- cam->vpp_flag = VPP_UYVY_TO_RGBX;
- break;
- }
-
- /* NOTE: due to memory issues, it is better to disable the hardware
- double buffering during compression */
- if (cam->double_buffer && !(cam->vpp_flag & VPP_DECOMPRESSION))
- reg_v |= 0x0080;
-
- if (cam->clamping)
- reg_v |= 0x0020;
-
- if (cam->filter_type == 1)
- reg_v |= 0x0008;
- else if (cam->filter_type == 2)
- reg_v |= 0x000c;
-
- if ((err = w9968cf_write_reg(cam, reg_v, 0x16)))
- goto error;
-
- if ((err = w9968cf_sensor_update_picture(cam, pict)))
- goto error;
-
- /* If all went well, update the device data structure */
- memcpy(&cam->picture, &pict, sizeof(pict));
- cam->hw_depth = hw_depth;
- cam->hw_palette = hw_palette;
-
- /* Settings changed, so we clear the frame buffers */
- memset(cam->frame[0].buffer, 0, cam->nbuffers*cam->frame[0].size);
-
- DBG(4, "Palette is %s, depth is %u bpp",
- symbolic(v4l1_plist, pict.palette), pict.depth)
-
- return 0;
-
-error:
- DBG(1, "Failed to change picture settings")
- return err;
-}
-
-
-/*--------------------------------------------------------------------------
- Change the capture area size of the camera.
- This function _must_ be called _after_ w9968cf_set_picture().
- Return 0 on success, a negative number otherwise.
- --------------------------------------------------------------------------*/
-static int
-w9968cf_set_window(struct w9968cf_device* cam, struct video_window win)
-{
- u16 x, y, w, h, scx, scy, cw, ch, ax, ay;
- unsigned long fw, fh;
- struct ovcamchip_window s_win;
- int err = 0;
-
- /* Work around to avoid FP arithmetics */
- #define SC(x) ((x) << 10)
- #define UNSC(x) ((x) >> 10)
-
- /* Make sure we are using a supported resolution */
- if ((err = w9968cf_adjust_window_size(cam, &win.width, &win.height)))
- goto error;
-
- /* Scaling factors */
- fw = SC(win.width) / cam->maxwidth;
- fh = SC(win.height) / cam->maxheight;
-
- /* Set up the width and height values used by the chip */
- if ((win.width > cam->maxwidth) || (win.height > cam->maxheight)) {
- cam->vpp_flag |= VPP_UPSCALE;
- /* Calculate largest w,h mantaining the same w/h ratio */
- w = (fw >= fh) ? cam->maxwidth : SC(win.width)/fh;
- h = (fw >= fh) ? SC(win.height)/fw : cam->maxheight;
- if (w < cam->minwidth) /* just in case */
- w = cam->minwidth;
- if (h < cam->minheight) /* just in case */
- h = cam->minheight;
- } else {
- cam->vpp_flag &= ~VPP_UPSCALE;
- w = win.width;
- h = win.height;
- }
-
- /* x,y offsets of the cropped area */
- scx = cam->start_cropx;
- scy = cam->start_cropy;
-
- /* Calculate cropped area manteining the right w/h ratio */
- if (cam->largeview && !(cam->vpp_flag & VPP_UPSCALE)) {
- cw = (fw >= fh) ? cam->maxwidth : SC(win.width)/fh;
- ch = (fw >= fh) ? SC(win.height)/fw : cam->maxheight;
- } else {
- cw = w;
- ch = h;
- }
-
- /* Setup the window of the sensor */
- s_win.format = VIDEO_PALETTE_UYVY;
- s_win.width = cam->maxwidth;
- s_win.height = cam->maxheight;
- s_win.quarter = 0; /* full progressive video */
-
- /* Center it */
- s_win.x = (s_win.width - cw) / 2;
- s_win.y = (s_win.height - ch) / 2;
-
- /* Clock divisor */
- if (cam->clockdiv >= 0)
- s_win.clockdiv = cam->clockdiv; /* manual override */
- else
- switch (cam->sensor) {
- case CC_OV6620:
- s_win.clockdiv = 0;
- break;
- case CC_OV6630:
- s_win.clockdiv = 0;
- break;
- case CC_OV76BE:
- case CC_OV7610:
- case CC_OV7620:
- s_win.clockdiv = 0;
- break;
- default:
- s_win.clockdiv = W9968CF_DEF_CLOCKDIVISOR;
- }
-
- /* We have to scale win.x and win.y offsets */
- if ( (cam->largeview && !(cam->vpp_flag & VPP_UPSCALE))
- || (cam->vpp_flag & VPP_UPSCALE) ) {
- ax = SC(win.x)/fw;
- ay = SC(win.y)/fh;
- } else {
- ax = win.x;
- ay = win.y;
- }
-
- if ((ax + cw) > cam->maxwidth)
- ax = cam->maxwidth - cw;
-
- if ((ay + ch) > cam->maxheight)
- ay = cam->maxheight - ch;
-
- /* Adjust win.x, win.y */
- if ( (cam->largeview && !(cam->vpp_flag & VPP_UPSCALE))
- || (cam->vpp_flag & VPP_UPSCALE) ) {
- win.x = UNSC(ax*fw);
- win.y = UNSC(ay*fh);
- } else {
- win.x = ax;
- win.y = ay;
- }
-
- /* Offsets used by the chip */
- x = ax + s_win.x;
- y = ay + s_win.y;
-
- /* Go ! */
- if ((err = w9968cf_sensor_cmd(cam, OVCAMCHIP_CMD_S_MODE, &s_win)))
- goto error;
-
- err += w9968cf_write_reg(cam, scx + x, 0x10);
- err += w9968cf_write_reg(cam, scy + y, 0x11);
- err += w9968cf_write_reg(cam, scx + x + cw, 0x12);
- err += w9968cf_write_reg(cam, scy + y + ch, 0x13);
- err += w9968cf_write_reg(cam, w, 0x14);
- err += w9968cf_write_reg(cam, h, 0x15);
-
- /* JPEG width & height */
- err += w9968cf_write_reg(cam, w, 0x30);
- err += w9968cf_write_reg(cam, h, 0x31);
-
- /* Y & UV frame buffer strides (in WORD) */
- if (cam->vpp_flag & VPP_DECOMPRESSION) {
- err += w9968cf_write_reg(cam, w/2, 0x2c);
- err += w9968cf_write_reg(cam, w/4, 0x2d);
- } else
- err += w9968cf_write_reg(cam, w, 0x2c);
-
- if (err)
- goto error;
-
- /* If all went well, update the device data structure */
- memcpy(&cam->window, &win, sizeof(win));
- cam->hw_width = w;
- cam->hw_height = h;
-
- /* Settings changed, so we clear the frame buffers */
- memset(cam->frame[0].buffer, 0, cam->nbuffers*cam->frame[0].size);
-
- DBG(4, "The capture area is %dx%d, Offset (x,y)=(%u,%u)",
- win.width, win.height, win.x, win.y)
-
- PDBGG("x=%u ,y=%u, w=%u, h=%u, ax=%u, ay=%u, s_win.x=%u, s_win.y=%u, "
- "cw=%u, ch=%u, win.x=%u, win.y=%u, win.width=%u, win.height=%u",
- x, y, w, h, ax, ay, s_win.x, s_win.y, cw, ch, win.x, win.y,
- win.width, win.height)
-
- return 0;
-
-error:
- DBG(1, "Failed to change the capture area size")
- return err;
-}
-
-
-/*--------------------------------------------------------------------------
- Adjust the asked values for window width and height.
- Return 0 on success, -1 otherwise.
- --------------------------------------------------------------------------*/
-static int
-w9968cf_adjust_window_size(struct w9968cf_device *cam, u32 *width, u32 *height)
-{
- unsigned int maxw, maxh, align;
-
- maxw = cam->upscaling && !(cam->vpp_flag & VPP_DECOMPRESSION) &&
- w9968cf_vpp ? max((u16)W9968CF_MAX_WIDTH, cam->maxwidth)
- : cam->maxwidth;
- maxh = cam->upscaling && !(cam->vpp_flag & VPP_DECOMPRESSION) &&
- w9968cf_vpp ? max((u16)W9968CF_MAX_HEIGHT, cam->maxheight)
- : cam->maxheight;
- align = (cam->vpp_flag & VPP_DECOMPRESSION) ? 4 : 0;
-
- v4l_bound_align_image(width, cam->minwidth, maxw, align,
- height, cam->minheight, maxh, align, 0);
-
- PDBGG("Window size adjusted w=%u, h=%u ", *width, *height)
-
- return 0;
-}
-
-
-/*--------------------------------------------------------------------------
- Initialize the FIFO list of requested frames.
- --------------------------------------------------------------------------*/
-static void w9968cf_init_framelist(struct w9968cf_device* cam)
-{
- u8 i;
-
- for (i = 0; i < cam->nbuffers; i++) {
- cam->requested_frame[i] = NULL;
- cam->frame[i].queued = 0;
- cam->frame[i].status = F_UNUSED;
- }
-}
-
-
-/*--------------------------------------------------------------------------
- Add a frame in the FIFO list of requested frames.
- This function is called in process context.
- --------------------------------------------------------------------------*/
-static void w9968cf_push_frame(struct w9968cf_device* cam, u8 f_num)
-{
- u8 f;
- unsigned long lock_flags;
-
- spin_lock_irqsave(&cam->flist_lock, lock_flags);
-
- for (f=0; cam->requested_frame[f] != NULL; f++);
- cam->requested_frame[f] = &cam->frame[f_num];
- cam->frame[f_num].queued = 1;
- cam->frame[f_num].status = F_UNUSED; /* clear the status */
-
- spin_unlock_irqrestore(&cam->flist_lock, lock_flags);
-
- DBG(6, "Frame #%u pushed into the FIFO list. Position %u", f_num, f)
-}
-
-
-/*--------------------------------------------------------------------------
- Read, store and remove the first pointer in the FIFO list of requested
- frames. This function is called in interrupt context.
- --------------------------------------------------------------------------*/
-static void
-w9968cf_pop_frame(struct w9968cf_device* cam, struct w9968cf_frame_t** framep)
-{
- u8 i;
-
- spin_lock(&cam->flist_lock);
-
- *framep = cam->requested_frame[0];
-
- /* Shift the list of pointers */
- for (i = 0; i < cam->nbuffers-1; i++)
- cam->requested_frame[i] = cam->requested_frame[i+1];
- cam->requested_frame[i] = NULL;
-
- spin_unlock(&cam->flist_lock);
-
- DBG(6,"Popped frame #%d from the list", (*framep)->number)
-}
-
-
-/*--------------------------------------------------------------------------
- High-level video post-processing routine on grabbed frames.
- Return 0 on success, a negative number otherwise.
- --------------------------------------------------------------------------*/
-static int
-w9968cf_postprocess_frame(struct w9968cf_device* cam,
- struct w9968cf_frame_t* fr)
-{
- void *pIn = fr->buffer, *pOut = cam->frame_vpp.buffer, *tmp;
- u16 w = cam->window.width,
- h = cam->window.height,
- d = cam->picture.depth,
- fmt = cam->picture.palette,
- rgb = cam->force_rgb,
- hw_w = cam->hw_width,
- hw_h = cam->hw_height,
- hw_d = cam->hw_depth;
- int err = 0;
-
- #define _PSWAP(pIn, pOut) {tmp = (pIn); (pIn) = (pOut); (pOut) = tmp;}
-
- if (cam->vpp_flag & VPP_DECOMPRESSION) {
- memcpy(pOut, pIn, fr->length);
- _PSWAP(pIn, pOut)
- err = w9968cf_vpp->decode(pIn, fr->length, hw_w, hw_h, pOut);
- PDBGG("Compressed frame length: %lu",(unsigned long)fr->length)
- fr->length = (hw_w*hw_h*hw_d)/8;
- _PSWAP(pIn, pOut)
- if (err) {
- DBG(4, "An error occurred while decoding the frame: "
- "%s", symbolic(decoder_errlist, err))
- return err;
- } else
- DBG(6, "Frame decoded")
- }
-
- if (cam->vpp_flag & VPP_SWAP_YUV_BYTES) {
- w9968cf_vpp->swap_yuvbytes(pIn, fr->length);
- DBG(6, "Original UYVY component ordering changed")
- }
-
- if (cam->vpp_flag & VPP_UPSCALE) {
- w9968cf_vpp->scale_up(pIn, pOut, hw_w, hw_h, hw_d, w, h);
- fr->length = (w*h*hw_d)/8;
- _PSWAP(pIn, pOut)
- DBG(6, "Vertical up-scaling done: %u,%u,%ubpp->%u,%u",
- hw_w, hw_h, hw_d, w, h)
- }
-
- if (cam->vpp_flag & VPP_UYVY_TO_RGBX) {
- w9968cf_vpp->uyvy_to_rgbx(pIn, fr->length, pOut, fmt, rgb);
- fr->length = (w*h*d)/8;
- _PSWAP(pIn, pOut)
- DBG(6, "UYVY-16bit to %s conversion done",
- symbolic(v4l1_plist, fmt))
- }
-
- if (pOut == fr->buffer)
- memcpy(fr->buffer, cam->frame_vpp.buffer, fr->length);
-
- return 0;
-}
-
-
-
-/****************************************************************************
- * Image sensor control routines *
- ****************************************************************************/
-
-static int
-w9968cf_sensor_set_control(struct w9968cf_device* cam, int cid, int val)
-{
- struct ovcamchip_control ctl;
- int err;
-
- ctl.id = cid;
- ctl.value = val;
-
- err = w9968cf_sensor_cmd(cam, OVCAMCHIP_CMD_S_CTRL, &ctl);
-
- return err;
-}
-
-
-static int
-w9968cf_sensor_get_control(struct w9968cf_device* cam, int cid, int* val)
-{
- struct ovcamchip_control ctl;
- int err;
-
- ctl.id = cid;
-
- err = w9968cf_sensor_cmd(cam, OVCAMCHIP_CMD_G_CTRL, &ctl);
- if (!err)
- *val = ctl.value;
-
- return err;
-}
-
-
-static int
-w9968cf_sensor_cmd(struct w9968cf_device* cam, unsigned int cmd, void* arg)
-{
- int rc;
-
- rc = v4l2_subdev_call(cam->sensor_sd, core, ioctl, cmd, arg);
- /* The I2C driver returns -EPERM on non-supported controls */
- return (rc < 0 && rc != -EPERM) ? rc : 0;
-}
-
-
-/*--------------------------------------------------------------------------
- Update some settings of the image sensor.
- Returns: 0 on success, a negative number otherwise.
- --------------------------------------------------------------------------*/
-static int w9968cf_sensor_update_settings(struct w9968cf_device* cam)
-{
- int err = 0;
-
- /* Auto brightness */
- err = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_AUTOBRIGHT,
- cam->auto_brt);
- if (err)
- return err;
-
- /* Auto exposure */
- err = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_AUTOEXP,
- cam->auto_exp);
- if (err)
- return err;
-
- /* Banding filter */
- err = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_BANDFILT,
- cam->bandfilt);
- if (err)
- return err;
-
- /* Light frequency */
- err = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_FREQ,
- cam->lightfreq);
- if (err)
- return err;
-
- /* Back light */
- err = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_BACKLIGHT,
- cam->backlight);
- if (err)
- return err;
-
- /* Mirror */
- err = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_MIRROR,
- cam->mirror);
- if (err)
- return err;
-
- return 0;
-}
-
-
-/*--------------------------------------------------------------------------
- Get some current picture settings from the image sensor and update the
- internal 'picture' structure of the camera.
- Returns: 0 on success, a negative number otherwise.
- --------------------------------------------------------------------------*/
-static int w9968cf_sensor_get_picture(struct w9968cf_device* cam)
-{
- int err, v;
-
- err = w9968cf_sensor_get_control(cam, OVCAMCHIP_CID_CONT, &v);
- if (err)
- return err;
- cam->picture.contrast = v;
-
- err = w9968cf_sensor_get_control(cam, OVCAMCHIP_CID_BRIGHT, &v);
- if (err)
- return err;
- cam->picture.brightness = v;
-
- err = w9968cf_sensor_get_control(cam, OVCAMCHIP_CID_SAT, &v);
- if (err)
- return err;
- cam->picture.colour = v;
-
- err = w9968cf_sensor_get_control(cam, OVCAMCHIP_CID_HUE, &v);
- if (err)
- return err;
- cam->picture.hue = v;
-
- DBG(5, "Got picture settings from the image sensor")
-
- PDBGG("Brightness, contrast, hue, colour, whiteness are "
- "%u,%u,%u,%u,%u", cam->picture.brightness,cam->picture.contrast,
- cam->picture.hue, cam->picture.colour, cam->picture.whiteness)
-
- return 0;
-}
-
-
-/*--------------------------------------------------------------------------
- Update picture settings of the image sensor.
- Returns: 0 on success, a negative number otherwise.
- --------------------------------------------------------------------------*/
-static int
-w9968cf_sensor_update_picture(struct w9968cf_device* cam,
- struct video_picture pict)
-{
- int err = 0;
-
- if ((!cam->sensor_initialized)
- || pict.contrast != cam->picture.contrast) {
- err = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_CONT,
- pict.contrast);
- if (err)
- goto fail;
- DBG(4, "Contrast changed from %u to %u",
- cam->picture.contrast, pict.contrast)
- cam->picture.contrast = pict.contrast;
- }
-
- if (((!cam->sensor_initialized) ||
- pict.brightness != cam->picture.brightness) && (!cam->auto_brt)) {
- err = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_BRIGHT,
- pict.brightness);
- if (err)
- goto fail;
- DBG(4, "Brightness changed from %u to %u",
- cam->picture.brightness, pict.brightness)
- cam->picture.brightness = pict.brightness;
- }
-
- if ((!cam->sensor_initialized) || pict.colour != cam->picture.colour) {
- err = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_SAT,
- pict.colour);
- if (err)
- goto fail;
- DBG(4, "Colour changed from %u to %u",
- cam->picture.colour, pict.colour)
- cam->picture.colour = pict.colour;
- }
-
- if ((!cam->sensor_initialized) || pict.hue != cam->picture.hue) {
- err = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_HUE,
- pict.hue);
- if (err)
- goto fail;
- DBG(4, "Hue changed from %u to %u",
- cam->picture.hue, pict.hue)
- cam->picture.hue = pict.hue;
- }
-
- return 0;
-
-fail:
- DBG(4, "Failed to change sensor picture setting")
- return err;
-}
-
-
-
-/****************************************************************************
- * Camera configuration *
- ****************************************************************************/
-
-/*--------------------------------------------------------------------------
- This function is called when a supported image sensor is detected.
- Return 0 if the initialization succeeds, a negative number otherwise.
- --------------------------------------------------------------------------*/
-static int w9968cf_sensor_init(struct w9968cf_device* cam)
-{
- int err = 0;
-
- if ((err = w9968cf_sensor_cmd(cam, OVCAMCHIP_CMD_INITIALIZE,
- &cam->monochrome)))
- goto error;
-
- if ((err = w9968cf_sensor_cmd(cam, OVCAMCHIP_CMD_Q_SUBTYPE,
- &cam->sensor)))
- goto error;
-
- /* NOTE: Make sure width and height are a multiple of 16 */
- switch (v4l2_i2c_subdev_addr(cam->sensor_sd)) {
- case OV6xx0_SID:
- cam->maxwidth = 352;
- cam->maxheight = 288;
- cam->minwidth = 64;
- cam->minheight = 48;
- break;
- case OV7xx0_SID:
- cam->maxwidth = 640;
- cam->maxheight = 480;
- cam->minwidth = 64;
- cam->minheight = 48;
- break;
- default:
- DBG(1, "Not supported image sensor detected for %s",
- symbolic(camlist, cam->id))
- return -EINVAL;
- }
-
- /* These values depend on the ones in the ovxxx0.c sources */
- switch (cam->sensor) {
- case CC_OV7620:
- cam->start_cropx = 287;
- cam->start_cropy = 35;
- /* Seems to work around a bug in the image sensor */
- cam->vs_polarity = 1;
- cam->hs_polarity = 1;
- break;
- default:
- cam->start_cropx = 320;
- cam->start_cropy = 35;
- cam->vs_polarity = 1;
- cam->hs_polarity = 0;
- }
-
- if ((err = w9968cf_sensor_update_settings(cam)))
- goto error;
-
- if ((err = w9968cf_sensor_update_picture(cam, cam->picture)))
- goto error;
-
- cam->sensor_initialized = 1;
-
- DBG(2, "%s image sensor initialized", symbolic(senlist, cam->sensor))
- return 0;
-
-error:
- cam->sensor_initialized = 0;
- cam->sensor = CC_UNKNOWN;
- DBG(1, "Image sensor initialization failed for %s (%s). "
- "Try to detach and attach this device again",
- symbolic(camlist, cam->id), video_device_node_name(cam->v4ldev))
- return err;
-}
-
-
-/*--------------------------------------------------------------------------
- Fill some basic fields in the main device data structure.
- This function is called once on w9968cf_usb_probe() for each recognized
- camera.
- --------------------------------------------------------------------------*/
-static void
-w9968cf_configure_camera(struct w9968cf_device* cam,
- struct usb_device* udev,
- enum w9968cf_model_id mod_id,
- const unsigned short dev_nr)
-{
- mutex_init(&cam->fileop_mutex);
- init_waitqueue_head(&cam->open);
- spin_lock_init(&cam->urb_lock);
- spin_lock_init(&cam->flist_lock);
-
- cam->users = 0;
- cam->disconnected = 0;
- cam->id = mod_id;
- cam->sensor = CC_UNKNOWN;
- cam->sensor_initialized = 0;
-
- /* Calculate the alternate setting number (from 1 to 16)
- according to the 'packet_size' module parameter */
- if (packet_size[dev_nr] < W9968CF_MIN_PACKET_SIZE)
- packet_size[dev_nr] = W9968CF_MIN_PACKET_SIZE;
- for (cam->altsetting = 1;
- packet_size[dev_nr] < wMaxPacketSize[cam->altsetting-1];
- cam->altsetting++);
-
- cam->max_buffers = (max_buffers[dev_nr] < 2 ||
- max_buffers[dev_nr] > W9968CF_MAX_BUFFERS)
- ? W9968CF_BUFFERS : (u8)max_buffers[dev_nr];
-
- cam->double_buffer = (double_buffer[dev_nr] == 0 ||
- double_buffer[dev_nr] == 1)
- ? (u8)double_buffer[dev_nr]:W9968CF_DOUBLE_BUFFER;
-
- cam->clamping = (clamping[dev_nr] == 0 || clamping[dev_nr] == 1)
- ? (u8)clamping[dev_nr] : W9968CF_CLAMPING;
-
- cam->filter_type = (filter_type[dev_nr] == 0 ||
- filter_type[dev_nr] == 1 ||
- filter_type[dev_nr] == 2)
- ? (u8)filter_type[dev_nr] : W9968CF_FILTER_TYPE;
-
- cam->capture = 1;
-
- cam->largeview = (largeview[dev_nr] == 0 || largeview[dev_nr] == 1)
- ? (u8)largeview[dev_nr] : W9968CF_LARGEVIEW;
-
- cam->decompression = (decompression[dev_nr] == 0 ||
- decompression[dev_nr] == 1 ||
- decompression[dev_nr] == 2)
- ? (u8)decompression[dev_nr]:W9968CF_DECOMPRESSION;
-
- cam->upscaling = (upscaling[dev_nr] == 0 ||
- upscaling[dev_nr] == 1)
- ? (u8)upscaling[dev_nr] : W9968CF_UPSCALING;
-
- cam->auto_brt = (autobright[dev_nr] == 0 || autobright[dev_nr] == 1)
- ? (u8)autobright[dev_nr] : W9968CF_AUTOBRIGHT;
-
- cam->auto_exp = (autoexp[dev_nr] == 0 || autoexp[dev_nr] == 1)
- ? (u8)autoexp[dev_nr] : W9968CF_AUTOEXP;
-
- cam->lightfreq = (lightfreq[dev_nr] == 50 || lightfreq[dev_nr] == 60)
- ? (u8)lightfreq[dev_nr] : W9968CF_LIGHTFREQ;
-
- cam->bandfilt = (bandingfilter[dev_nr] == 0 ||
- bandingfilter[dev_nr] == 1)
- ? (u8)bandingfilter[dev_nr] : W9968CF_BANDINGFILTER;
-
- cam->backlight = (backlight[dev_nr] == 0 || backlight[dev_nr] == 1)
- ? (u8)backlight[dev_nr] : W9968CF_BACKLIGHT;
-
- cam->clockdiv = (clockdiv[dev_nr] == -1 || clockdiv[dev_nr] >= 0)
- ? (s8)clockdiv[dev_nr] : W9968CF_CLOCKDIV;
-
- cam->mirror = (mirror[dev_nr] == 0 || mirror[dev_nr] == 1)
- ? (u8)mirror[dev_nr] : W9968CF_MIRROR;
-
- cam->monochrome = (monochrome[dev_nr] == 0 || monochrome[dev_nr] == 1)
- ? monochrome[dev_nr] : W9968CF_MONOCHROME;
-
- cam->picture.brightness = (u16)brightness[dev_nr];
- cam->picture.hue = (u16)hue[dev_nr];
- cam->picture.colour = (u16)colour[dev_nr];
- cam->picture.contrast = (u16)contrast[dev_nr];
- cam->picture.whiteness = (u16)whiteness[dev_nr];
- if (w9968cf_valid_palette((u16)force_palette[dev_nr])) {
- cam->picture.palette = (u16)force_palette[dev_nr];
- cam->force_palette = 1;
- } else {
- cam->force_palette = 0;
- if (cam->decompression == 0)
- cam->picture.palette = W9968CF_PALETTE_DECOMP_OFF;
- else if (cam->decompression == 1)
- cam->picture.palette = W9968CF_PALETTE_DECOMP_FORCE;
- else
- cam->picture.palette = W9968CF_PALETTE_DECOMP_ON;
- }
- cam->picture.depth = w9968cf_valid_depth(cam->picture.palette);
-
- cam->force_rgb = (force_rgb[dev_nr] == 0 || force_rgb[dev_nr] == 1)
- ? (u8)force_rgb[dev_nr] : W9968CF_FORCE_RGB;
-
- cam->window.x = 0;
- cam->window.y = 0;
- cam->window.width = W9968CF_WIDTH;
- cam->window.height = W9968CF_HEIGHT;
- cam->window.chromakey = 0;
- cam->window.clipcount = 0;
- cam->window.flags = 0;
-
- DBG(3, "%s configured with settings #%u:",
- symbolic(camlist, cam->id), dev_nr)
-
- DBG(3, "- Data packet size for USB isochrnous transfer: %u bytes",
- wMaxPacketSize[cam->altsetting-1])
-
- DBG(3, "- Number of requested video frame buffers: %u",
- cam->max_buffers)
-
- if (cam->double_buffer)
- DBG(3, "- Hardware double buffering enabled")
- else
- DBG(3, "- Hardware double buffering disabled")
-
- if (cam->filter_type == 0)
- DBG(3, "- Video filtering disabled")
- else if (cam->filter_type == 1)
- DBG(3, "- Video filtering enabled: type 1-2-1")
- else if (cam->filter_type == 2)
- DBG(3, "- Video filtering enabled: type 2-3-6-3-2")
-
- if (cam->clamping)
- DBG(3, "- Video data clamping (CCIR-601 format) enabled")
- else
- DBG(3, "- Video data clamping (CCIR-601 format) disabled")
-
- if (cam->largeview)
- DBG(3, "- Large view enabled")
- else
- DBG(3, "- Large view disabled")
-
- if ((cam->decompression) == 0 && (!cam->force_palette))
- DBG(3, "- Decompression disabled")
- else if ((cam->decompression) == 1 && (!cam->force_palette))
- DBG(3, "- Decompression forced")
- else if ((cam->decompression) == 2 && (!cam->force_palette))
- DBG(3, "- Decompression allowed")
-
- if (cam->upscaling)
- DBG(3, "- Software image scaling enabled")
- else
- DBG(3, "- Software image scaling disabled")
-
- if (cam->force_palette)
- DBG(3, "- Image palette forced to %s",
- symbolic(v4l1_plist, cam->picture.palette))
-
- if (cam->force_rgb)
- DBG(3, "- RGB component ordering will be used instead of BGR")
-
- if (cam->auto_brt)
- DBG(3, "- Auto brightness enabled")
- else
- DBG(3, "- Auto brightness disabled")
-
- if (cam->auto_exp)
- DBG(3, "- Auto exposure enabled")
- else
- DBG(3, "- Auto exposure disabled")
-
- if (cam->backlight)
- DBG(3, "- Backlight exposure algorithm enabled")
- else
- DBG(3, "- Backlight exposure algorithm disabled")
-
- if (cam->mirror)
- DBG(3, "- Mirror enabled")
- else
- DBG(3, "- Mirror disabled")
-
- if (cam->bandfilt)
- DBG(3, "- Banding filter enabled")
- else
- DBG(3, "- Banding filter disabled")
-
- DBG(3, "- Power lighting frequency: %u", cam->lightfreq)
-
- if (cam->clockdiv == -1)
- DBG(3, "- Automatic clock divisor enabled")
- else
- DBG(3, "- Clock divisor: %d", cam->clockdiv)
-
- if (cam->monochrome)
- DBG(3, "- Image sensor used as monochrome")
- else
- DBG(3, "- Image sensor not used as monochrome")
-}
-
-
-/*--------------------------------------------------------------------------
- If the video post-processing module is not loaded, some parameters
- must be overridden.
- --------------------------------------------------------------------------*/
-static void w9968cf_adjust_configuration(struct w9968cf_device* cam)
-{
- if (!w9968cf_vpp) {
- if (cam->decompression == 1) {
- cam->decompression = 2;
- DBG(2, "Video post-processing module not found: "
- "'decompression' parameter forced to 2")
- }
- if (cam->upscaling) {
- cam->upscaling = 0;
- DBG(2, "Video post-processing module not found: "
- "'upscaling' parameter forced to 0")
- }
- if (cam->picture.palette != VIDEO_PALETTE_UYVY) {
- cam->force_palette = 0;
- DBG(2, "Video post-processing module not found: "
- "'force_palette' parameter forced to 0")
- }
- cam->picture.palette = VIDEO_PALETTE_UYVY;
- cam->picture.depth = w9968cf_valid_depth(cam->picture.palette);
- }
-}
-
-
-/*--------------------------------------------------------------------------
- Release the resources used by the driver.
- This function is called on disconnect
- (or on close if deallocation has been deferred)
- --------------------------------------------------------------------------*/
-static void w9968cf_release_resources(struct w9968cf_device* cam)
-{
- mutex_lock(&w9968cf_devlist_mutex);
-
- DBG(2, "V4L device deregistered: %s",
- video_device_node_name(cam->v4ldev))
-
- video_unregister_device(cam->v4ldev);
- list_del(&cam->v4llist);
- i2c_del_adapter(&cam->i2c_adapter);
- w9968cf_deallocate_memory(cam);
- kfree(cam->control_buffer);
- kfree(cam->data_buffer);
- v4l2_device_unregister(&cam->v4l2_dev);
-
- mutex_unlock(&w9968cf_devlist_mutex);
-}
-
-
-
-/****************************************************************************
- * Video4Linux interface *
- ****************************************************************************/
-
-static int w9968cf_open(struct file *filp)
-{
- struct w9968cf_device* cam;
- int err;
-
- /* This the only safe way to prevent race conditions with disconnect */
- if (!down_read_trylock(&w9968cf_disconnect))
- return -EAGAIN;
-
- cam = (struct w9968cf_device*)video_get_drvdata(video_devdata(filp));
-
- mutex_lock(&cam->dev_mutex);
-
- if (cam->sensor == CC_UNKNOWN) {
- DBG(2, "No supported image sensor has been detected by the "
- "'ovcamchip' module for the %s (%s). Make sure "
- "it is loaded *before* (re)connecting the camera.",
- symbolic(camlist, cam->id),
- video_device_node_name(cam->v4ldev))
- mutex_unlock(&cam->dev_mutex);
- up_read(&w9968cf_disconnect);
- return -ENODEV;
- }
-
- if (cam->users) {
- DBG(2, "%s (%s) has been already occupied by '%s'",
- symbolic(camlist, cam->id),
- video_device_node_name(cam->v4ldev), cam->command)
- if ((filp->f_flags & O_NONBLOCK)||(filp->f_flags & O_NDELAY)) {
- mutex_unlock(&cam->dev_mutex);
- up_read(&w9968cf_disconnect);
- return -EWOULDBLOCK;
- }
- mutex_unlock(&cam->dev_mutex);
- err = wait_event_interruptible_exclusive(cam->open,
- cam->disconnected ||
- !cam->users);
- if (err) {
- up_read(&w9968cf_disconnect);
- return err;
- }
- if (cam->disconnected) {
- up_read(&w9968cf_disconnect);
- return -ENODEV;
- }
- mutex_lock(&cam->dev_mutex);
- }
-
- DBG(5, "Opening '%s', %s ...",
- symbolic(camlist, cam->id), video_device_node_name(cam->v4ldev))
-
- cam->streaming = 0;
- cam->misconfigured = 0;
-
- w9968cf_adjust_configuration(cam);
-
- if ((err = w9968cf_allocate_memory(cam)))
- goto deallocate_memory;
-
- if ((err = w9968cf_init_chip(cam)))
- goto deallocate_memory;
-
- if ((err = w9968cf_start_transfer(cam)))
- goto deallocate_memory;
-
- filp->private_data = cam;
-
- cam->users++;
- strcpy(cam->command, current->comm);
-
- init_waitqueue_head(&cam->wait_queue);
-
- DBG(5, "Video device is open")
-
- mutex_unlock(&cam->dev_mutex);
- up_read(&w9968cf_disconnect);
-
- return 0;
-
-deallocate_memory:
- w9968cf_deallocate_memory(cam);
- DBG(2, "Failed to open the video device")
- mutex_unlock(&cam->dev_mutex);
- up_read(&w9968cf_disconnect);
- return err;
-}
-
-
-static int w9968cf_release(struct file *filp)
-{
- struct w9968cf_device* cam;
-
- cam = (struct w9968cf_device*)video_get_drvdata(video_devdata(filp));
-
- mutex_lock(&cam->dev_mutex); /* prevent disconnect() to be called */
-
- w9968cf_stop_transfer(cam);
-
- if (cam->disconnected) {
- w9968cf_release_resources(cam);
- mutex_unlock(&cam->dev_mutex);
- kfree(cam);
- return 0;
- }
-
- cam->users--;
- w9968cf_deallocate_memory(cam);
- wake_up_interruptible_nr(&cam->open, 1);
-
- DBG(5, "Video device closed")
- mutex_unlock(&cam->dev_mutex);
- return 0;
-}
-
-
-static ssize_t
-w9968cf_read(struct file* filp, char __user * buf, size_t count, loff_t* f_pos)
-{
- struct w9968cf_device* cam;
- struct w9968cf_frame_t* fr;
- int err = 0;
-
- cam = (struct w9968cf_device*)video_get_drvdata(video_devdata(filp));
-
- if (filp->f_flags & O_NONBLOCK)
- return -EWOULDBLOCK;
-
- if (mutex_lock_interruptible(&cam->fileop_mutex))
- return -ERESTARTSYS;
-
- if (cam->disconnected) {
- DBG(2, "Device not present")
- mutex_unlock(&cam->fileop_mutex);
- return -ENODEV;
- }
-
- if (cam->misconfigured) {
- DBG(2, "The camera is misconfigured. Close and open it again.")
- mutex_unlock(&cam->fileop_mutex);
- return -EIO;
- }
-
- if (!cam->frame[0].queued)
- w9968cf_push_frame(cam, 0);
-
- if (!cam->frame[1].queued)
- w9968cf_push_frame(cam, 1);
-
- err = wait_event_interruptible(cam->wait_queue,
- cam->frame[0].status == F_READY ||
- cam->frame[1].status == F_READY ||
- cam->disconnected);
- if (err) {
- mutex_unlock(&cam->fileop_mutex);
- return err;
- }
- if (cam->disconnected) {
- mutex_unlock(&cam->fileop_mutex);
- return -ENODEV;
- }
-
- fr = (cam->frame[0].status == F_READY) ? &cam->frame[0]:&cam->frame[1];
-
- if (w9968cf_vpp)
- w9968cf_postprocess_frame(cam, fr);
-
- if (count > fr->length)
- count = fr->length;
-
- if (copy_to_user(buf, fr->buffer, count)) {
- fr->status = F_UNUSED;
- mutex_unlock(&cam->fileop_mutex);
- return -EFAULT;
- }
- *f_pos += count;
-
- fr->status = F_UNUSED;
-
- DBG(5, "%zu bytes read", count)
-
- mutex_unlock(&cam->fileop_mutex);
- return count;
-}
-
-
-static int w9968cf_mmap(struct file* filp, struct vm_area_struct *vma)
-{
- struct w9968cf_device* cam = (struct w9968cf_device*)
- video_get_drvdata(video_devdata(filp));
- unsigned long vsize = vma->vm_end - vma->vm_start,
- psize = cam->nbuffers * cam->frame[0].size,
- start = vma->vm_start,
- pos = (unsigned long)cam->frame[0].buffer,
- page;
-
- if (cam->disconnected) {
- DBG(2, "Device not present")
- return -ENODEV;
- }
-
- if (cam->misconfigured) {
- DBG(2, "The camera is misconfigured. Close and open it again")
- return -EIO;
- }
-
- PDBGG("mmapping %lu bytes...", vsize)
-
- if (vsize > psize - (vma->vm_pgoff << PAGE_SHIFT))
- return -EINVAL;
-
- while (vsize > 0) {
- page = vmalloc_to_pfn((void *)pos);
- if (remap_pfn_range(vma, start, page + vma->vm_pgoff,
- PAGE_SIZE, vma->vm_page_prot))
- return -EAGAIN;
- start += PAGE_SIZE;
- pos += PAGE_SIZE;
- vsize -= PAGE_SIZE;
- }
-
- DBG(5, "mmap method successfully called")
- return 0;
-}
-
-
-static long
-w9968cf_ioctl(struct file *filp,
- unsigned int cmd, unsigned long arg)
-{
- struct w9968cf_device* cam;
- long err;
-
- cam = (struct w9968cf_device*)video_get_drvdata(video_devdata(filp));
-
- if (mutex_lock_interruptible(&cam->fileop_mutex))
- return -ERESTARTSYS;
-
- if (cam->disconnected) {
- DBG(2, "Device not present")
- mutex_unlock(&cam->fileop_mutex);
- return -ENODEV;
- }
-
- if (cam->misconfigured) {
- DBG(2, "The camera is misconfigured. Close and open it again.")
- mutex_unlock(&cam->fileop_mutex);
- return -EIO;
- }
-
- err = w9968cf_v4l_ioctl(filp, cmd, (void __user *)arg);
-
- mutex_unlock(&cam->fileop_mutex);
- return err;
-}
-
-
-static long w9968cf_v4l_ioctl(struct file *filp,
- unsigned int cmd, void __user *arg)
-{
- struct w9968cf_device* cam;
- const char* v4l1_ioctls[] = {
- "?", "CGAP", "GCHAN", "SCHAN", "GTUNER", "STUNER",
- "GPICT", "SPICT", "CCAPTURE", "GWIN", "SWIN", "GFBUF",
- "SFBUF", "KEY", "GFREQ", "SFREQ", "GAUDIO", "SAUDIO",
- "SYNC", "MCAPTURE", "GMBUF", "GUNIT", "GCAPTURE", "SCAPTURE",
- "SPLAYMODE", "SWRITEMODE", "GPLAYINFO", "SMICROCODE",
- "GVBIFMT", "SVBIFMT"
- };
-
- #define V4L1_IOCTL(cmd) \
- ((_IOC_NR((cmd)) < ARRAY_SIZE(v4l1_ioctls)) ? \
- v4l1_ioctls[_IOC_NR((cmd))] : "?")
-
- cam = (struct w9968cf_device*)video_get_drvdata(video_devdata(filp));
-
- switch (cmd) {
-
- case VIDIOCGCAP: /* get video capability */
- {
- struct video_capability cap = {
- .type = VID_TYPE_CAPTURE | VID_TYPE_SCALES,
- .channels = 1,
- .audios = 0,
- .minwidth = cam->minwidth,
- .minheight = cam->minheight,
- };
- sprintf(cap.name, "W996[87]CF USB Camera");
- cap.maxwidth = (cam->upscaling && w9968cf_vpp)
- ? max((u16)W9968CF_MAX_WIDTH, cam->maxwidth)
- : cam->maxwidth;
- cap.maxheight = (cam->upscaling && w9968cf_vpp)
- ? max((u16)W9968CF_MAX_HEIGHT, cam->maxheight)
- : cam->maxheight;
-
- if (copy_to_user(arg, &cap, sizeof(cap)))
- return -EFAULT;
-
- DBG(5, "VIDIOCGCAP successfully called")
- return 0;
- }
-
- case VIDIOCGCHAN: /* get video channel informations */
- {
- struct video_channel chan;
- if (copy_from_user(&chan, arg, sizeof(chan)))
- return -EFAULT;
-
- if (chan.channel != 0)
- return -EINVAL;
-
- strcpy(chan.name, "Camera");
- chan.tuners = 0;
- chan.flags = 0;
- chan.type = VIDEO_TYPE_CAMERA;
- chan.norm = VIDEO_MODE_AUTO;
-
- if (copy_to_user(arg, &chan, sizeof(chan)))
- return -EFAULT;
-
- DBG(5, "VIDIOCGCHAN successfully called")
- return 0;
- }
-
- case VIDIOCSCHAN: /* set active channel */
- {
- struct video_channel chan;
-
- if (copy_from_user(&chan, arg, sizeof(chan)))
- return -EFAULT;
-
- if (chan.channel != 0)
- return -EINVAL;
-
- DBG(5, "VIDIOCSCHAN successfully called")
- return 0;
- }
-
- case VIDIOCGPICT: /* get image properties of the picture */
- {
- if (w9968cf_sensor_get_picture(cam))
- return -EIO;
-
- if (copy_to_user(arg, &cam->picture, sizeof(cam->picture)))
- return -EFAULT;
-
- DBG(5, "VIDIOCGPICT successfully called")
- return 0;
- }
-
- case VIDIOCSPICT: /* change picture settings */
- {
- struct video_picture pict;
- int err = 0;
-
- if (copy_from_user(&pict, arg, sizeof(pict)))
- return -EFAULT;
-
- if ( (cam->force_palette || !w9968cf_vpp)
- && pict.palette != cam->picture.palette ) {
- DBG(4, "Palette %s rejected: only %s is allowed",
- symbolic(v4l1_plist, pict.palette),
- symbolic(v4l1_plist, cam->picture.palette))
- return -EINVAL;
- }
-
- if (!w9968cf_valid_palette(pict.palette)) {
- DBG(4, "Palette %s not supported. VIDIOCSPICT failed",
- symbolic(v4l1_plist, pict.palette))
- return -EINVAL;
- }
-
- if (!cam->force_palette) {
- if (cam->decompression == 0) {
- if (w9968cf_need_decompression(pict.palette)) {
- DBG(4, "Decompression disabled: palette %s is not "
- "allowed. VIDIOCSPICT failed",
- symbolic(v4l1_plist, pict.palette))
- return -EINVAL;
- }
- } else if (cam->decompression == 1) {
- if (!w9968cf_need_decompression(pict.palette)) {
- DBG(4, "Decompression forced: palette %s is not "
- "allowed. VIDIOCSPICT failed",
- symbolic(v4l1_plist, pict.palette))
- return -EINVAL;
- }
- }
- }
-
- if (pict.depth != w9968cf_valid_depth(pict.palette)) {
- DBG(4, "Requested depth %u bpp is not valid for %s "
- "palette: ignored and changed to %u bpp",
- pict.depth, symbolic(v4l1_plist, pict.palette),
- w9968cf_valid_depth(pict.palette))
- pict.depth = w9968cf_valid_depth(pict.palette);
- }
-
- if (pict.palette != cam->picture.palette) {
- if(*cam->requested_frame
- || cam->frame_current->queued) {
- err = wait_event_interruptible
- ( cam->wait_queue,
- cam->disconnected ||
- (!*cam->requested_frame &&
- !cam->frame_current->queued) );
- if (err)
- return err;
- if (cam->disconnected)
- return -ENODEV;
- }
-
- if (w9968cf_stop_transfer(cam))
- goto ioctl_fail;
-
- if (w9968cf_set_picture(cam, pict))
- goto ioctl_fail;
-
- if (w9968cf_start_transfer(cam))
- goto ioctl_fail;
-
- } else if (w9968cf_sensor_update_picture(cam, pict))
- return -EIO;
-
-
- DBG(5, "VIDIOCSPICT successfully called")
- return 0;
- }
-
- case VIDIOCSWIN: /* set capture area */
- {
- struct video_window win;
- int err = 0;
-
- if (copy_from_user(&win, arg, sizeof(win)))
- return -EFAULT;
-
- DBG(6, "VIDIOCSWIN called: clipcount=%d, flags=%u, "
- "x=%u, y=%u, %ux%u", win.clipcount, win.flags,
- win.x, win.y, win.width, win.height)
-
- if (win.clipcount != 0 || win.flags != 0)
- return -EINVAL;
-
- if ((err = w9968cf_adjust_window_size(cam, &win.width,
- &win.height))) {
- DBG(4, "Resolution not supported (%ux%u). "
- "VIDIOCSWIN failed", win.width, win.height)
- return err;
- }
-
- if (win.x != cam->window.x ||
- win.y != cam->window.y ||
- win.width != cam->window.width ||
- win.height != cam->window.height) {
- if(*cam->requested_frame
- || cam->frame_current->queued) {
- err = wait_event_interruptible
- ( cam->wait_queue,
- cam->disconnected ||
- (!*cam->requested_frame &&
- !cam->frame_current->queued) );
- if (err)
- return err;
- if (cam->disconnected)
- return -ENODEV;
- }
-
- if (w9968cf_stop_transfer(cam))
- goto ioctl_fail;
-
- /* This _must_ be called before set_window() */
- if (w9968cf_set_picture(cam, cam->picture))
- goto ioctl_fail;
-
- if (w9968cf_set_window(cam, win))
- goto ioctl_fail;
-
- if (w9968cf_start_transfer(cam))
- goto ioctl_fail;
- }
-
- DBG(5, "VIDIOCSWIN successfully called. ")
- return 0;
- }
-
- case VIDIOCGWIN: /* get current window properties */
- {
- if (copy_to_user(arg,&cam->window,sizeof(struct video_window)))
- return -EFAULT;
-
- DBG(5, "VIDIOCGWIN successfully called")
- return 0;
- }
-
- case VIDIOCGMBUF: /* request for memory (mapped) buffer */
- {
- struct video_mbuf mbuf;
- u8 i;
-
- mbuf.size = cam->nbuffers * cam->frame[0].size;
- mbuf.frames = cam->nbuffers;
- for (i = 0; i < cam->nbuffers; i++)
- mbuf.offsets[i] = (unsigned long)cam->frame[i].buffer -
- (unsigned long)cam->frame[0].buffer;
-
- if (copy_to_user(arg, &mbuf, sizeof(mbuf)))
- return -EFAULT;
-
- DBG(5, "VIDIOCGMBUF successfully called")
- return 0;
- }
-
- case VIDIOCMCAPTURE: /* start the capture to a frame */
- {
- struct video_mmap mmap;
- struct w9968cf_frame_t* fr;
- u32 w, h;
- int err = 0;
-
- if (copy_from_user(&mmap, arg, sizeof(mmap)))
- return -EFAULT;
-
- DBG(6, "VIDIOCMCAPTURE called: frame #%u, format=%s, %dx%d",
- mmap.frame, symbolic(v4l1_plist, mmap.format),
- mmap.width, mmap.height)
-
- if (mmap.frame >= cam->nbuffers) {
- DBG(4, "Invalid frame number (%u). "
- "VIDIOCMCAPTURE failed", mmap.frame)
- return -EINVAL;
- }
-
- if (mmap.format!=cam->picture.palette &&
- (cam->force_palette || !w9968cf_vpp)) {
- DBG(4, "Palette %s rejected: only %s is allowed",
- symbolic(v4l1_plist, mmap.format),
- symbolic(v4l1_plist, cam->picture.palette))
- return -EINVAL;
- }
-
- if (!w9968cf_valid_palette(mmap.format)) {
- DBG(4, "Palette %s not supported. "
- "VIDIOCMCAPTURE failed",
- symbolic(v4l1_plist, mmap.format))
- return -EINVAL;
- }
-
- if (!cam->force_palette) {
- if (cam->decompression == 0) {
- if (w9968cf_need_decompression(mmap.format)) {
- DBG(4, "Decompression disabled: palette %s is not "
- "allowed. VIDIOCSPICT failed",
- symbolic(v4l1_plist, mmap.format))
- return -EINVAL;
- }
- } else if (cam->decompression == 1) {
- if (!w9968cf_need_decompression(mmap.format)) {
- DBG(4, "Decompression forced: palette %s is not "
- "allowed. VIDIOCSPICT failed",
- symbolic(v4l1_plist, mmap.format))
- return -EINVAL;
- }
- }
- }
-
- w = mmap.width; h = mmap.height;
- err = w9968cf_adjust_window_size(cam, &w, &h);
- mmap.width = w; mmap.height = h;
- if (err) {
- DBG(4, "Resolution not supported (%dx%d). "
- "VIDIOCMCAPTURE failed",
- mmap.width, mmap.height)
- return err;
- }
-
- fr = &cam->frame[mmap.frame];
-
- if (mmap.width != cam->window.width ||
- mmap.height != cam->window.height ||
- mmap.format != cam->picture.palette) {
-
- struct video_window win;
- struct video_picture pict;
-
- if(*cam->requested_frame
- || cam->frame_current->queued) {
- DBG(6, "VIDIOCMCAPTURE. Change settings for "
- "frame #%u: %dx%d, format %s. Wait...",
- mmap.frame, mmap.width, mmap.height,
- symbolic(v4l1_plist, mmap.format))
- err = wait_event_interruptible
- ( cam->wait_queue,
- cam->disconnected ||
- (!*cam->requested_frame &&
- !cam->frame_current->queued) );
- if (err)
- return err;
- if (cam->disconnected)
- return -ENODEV;
- }
-
- memcpy(&win, &cam->window, sizeof(win));
- memcpy(&pict, &cam->picture, sizeof(pict));
- win.width = mmap.width;
- win.height = mmap.height;
- pict.palette = mmap.format;
-
- if (w9968cf_stop_transfer(cam))
- goto ioctl_fail;
-
- /* This before set_window */
- if (w9968cf_set_picture(cam, pict))
- goto ioctl_fail;
-
- if (w9968cf_set_window(cam, win))
- goto ioctl_fail;
-
- if (w9968cf_start_transfer(cam))
- goto ioctl_fail;
-
- } else if (fr->queued) {
-
- DBG(6, "Wait until frame #%u is free", mmap.frame)
-
- err = wait_event_interruptible(cam->wait_queue,
- cam->disconnected ||
- (!fr->queued));
- if (err)
- return err;
- if (cam->disconnected)
- return -ENODEV;
- }
-
- w9968cf_push_frame(cam, mmap.frame);
- DBG(5, "VIDIOCMCAPTURE(%u): successfully called", mmap.frame)
- return 0;
- }
-
- case VIDIOCSYNC: /* wait until the capture of a frame is finished */
- {
- unsigned int f_num;
- struct w9968cf_frame_t* fr;
- int err = 0;
-
- if (copy_from_user(&f_num, arg, sizeof(f_num)))
- return -EFAULT;
-
- if (f_num >= cam->nbuffers) {
- DBG(4, "Invalid frame number (%u). "
- "VIDIOCMCAPTURE failed", f_num)
- return -EINVAL;
- }
-
- DBG(6, "VIDIOCSYNC called for frame #%u", f_num)
-
- fr = &cam->frame[f_num];
-
- switch (fr->status) {
- case F_UNUSED:
- if (!fr->queued) {
- DBG(4, "VIDIOSYNC: Frame #%u not requested!",
- f_num)
- return -EFAULT;
- }
- case F_ERROR:
- case F_GRABBING:
- err = wait_event_interruptible(cam->wait_queue,
- (fr->status == F_READY)
- || cam->disconnected);
- if (err)
- return err;
- if (cam->disconnected)
- return -ENODEV;
- break;
- case F_READY:
- break;
- }
-
- if (w9968cf_vpp)
- w9968cf_postprocess_frame(cam, fr);
-
- fr->status = F_UNUSED;
-
- DBG(5, "VIDIOCSYNC(%u) successfully called", f_num)
- return 0;
- }
-
- case VIDIOCGUNIT:/* report the unit numbers of the associated devices*/
- {
- struct video_unit unit = {
- .video = cam->v4ldev->minor,
- .vbi = VIDEO_NO_UNIT,
- .radio = VIDEO_NO_UNIT,
- .audio = VIDEO_NO_UNIT,
- .teletext = VIDEO_NO_UNIT,
- };
-
- if (copy_to_user(arg, &unit, sizeof(unit)))
- return -EFAULT;
-
- DBG(5, "VIDIOCGUNIT successfully called")
- return 0;
- }
-
- case VIDIOCKEY:
- return 0;
-
- case VIDIOCGFBUF:
- {
- if (clear_user(arg, sizeof(struct video_buffer)))
- return -EFAULT;
-
- DBG(5, "VIDIOCGFBUF successfully called")
- return 0;
- }
-
- case VIDIOCGTUNER:
- {
- struct video_tuner tuner;
- if (copy_from_user(&tuner, arg, sizeof(tuner)))
- return -EFAULT;
-
- if (tuner.tuner != 0)
- return -EINVAL;
-
- strcpy(tuner.name, "no_tuner");
- tuner.rangelow = 0;
- tuner.rangehigh = 0;
- tuner.flags = VIDEO_TUNER_NORM;
- tuner.mode = VIDEO_MODE_AUTO;
- tuner.signal = 0xffff;
-
- if (copy_to_user(arg, &tuner, sizeof(tuner)))
- return -EFAULT;
-
- DBG(5, "VIDIOCGTUNER successfully called")
- return 0;
- }
-
- case VIDIOCSTUNER:
- {
- struct video_tuner tuner;
- if (copy_from_user(&tuner, arg, sizeof(tuner)))
- return -EFAULT;
-
- if (tuner.tuner != 0)
- return -EINVAL;
-
- if (tuner.mode != VIDEO_MODE_AUTO)
- return -EINVAL;
-
- DBG(5, "VIDIOCSTUNER successfully called")
- return 0;
- }
-
- case VIDIOCSFBUF:
- case VIDIOCCAPTURE:
- case VIDIOCGFREQ:
- case VIDIOCSFREQ:
- case VIDIOCGAUDIO:
- case VIDIOCSAUDIO:
- case VIDIOCSPLAYMODE:
- case VIDIOCSWRITEMODE:
- case VIDIOCGPLAYINFO:
- case VIDIOCSMICROCODE:
- case VIDIOCGVBIFMT:
- case VIDIOCSVBIFMT:
- DBG(4, "Unsupported V4L1 IOCtl: VIDIOC%s "
- "(type 0x%01X, "
- "n. 0x%01X, "
- "dir. 0x%01X, "
- "size 0x%02X)",
- V4L1_IOCTL(cmd),
- _IOC_TYPE(cmd),_IOC_NR(cmd),_IOC_DIR(cmd),_IOC_SIZE(cmd))
-
- return -EINVAL;
-
- default:
- DBG(4, "Invalid V4L1 IOCtl: VIDIOC%s "
- "type 0x%01X, "
- "n. 0x%01X, "
- "dir. 0x%01X, "
- "size 0x%02X",
- V4L1_IOCTL(cmd),
- _IOC_TYPE(cmd),_IOC_NR(cmd),_IOC_DIR(cmd),_IOC_SIZE(cmd))
-
- return -ENOIOCTLCMD;
-
- } /* end of switch */
-
-ioctl_fail:
- cam->misconfigured = 1;
- DBG(1, "VIDIOC%s failed because of hardware problems. "
- "To use the camera, close and open it again.", V4L1_IOCTL(cmd))
- return -EFAULT;
-}
-
-
-static const struct v4l2_file_operations w9968cf_fops = {
- .owner = THIS_MODULE,
- .open = w9968cf_open,
- .release = w9968cf_release,
- .read = w9968cf_read,
- .ioctl = w9968cf_ioctl,
- .mmap = w9968cf_mmap,
-};
-
-
-
-/****************************************************************************
- * USB probe and V4L registration, disconnect and id_table[] definition *
- ****************************************************************************/
-
-static int
-w9968cf_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
-{
- struct usb_device *udev = interface_to_usbdev(intf);
- struct w9968cf_device* cam;
- int err = 0;
- enum w9968cf_model_id mod_id;
- struct list_head* ptr;
- u8 sc = 0; /* number of simultaneous cameras */
- static unsigned short dev_nr; /* 0 - we are handling device number n */
- static unsigned short addrs[] = {
- OV7xx0_SID,
- OV6xx0_SID,
- I2C_CLIENT_END
- };
-
- if (le16_to_cpu(udev->descriptor.idVendor) == winbond_id_table[0].idVendor &&
- le16_to_cpu(udev->descriptor.idProduct) == winbond_id_table[0].idProduct)
- mod_id = W9968CF_MOD_CLVBWGP; /* see camlist[] table */
- else if (le16_to_cpu(udev->descriptor.idVendor) == winbond_id_table[1].idVendor &&
- le16_to_cpu(udev->descriptor.idProduct) == winbond_id_table[1].idProduct)
- mod_id = W9968CF_MOD_GENERIC; /* see camlist[] table */
- else
- return -ENODEV;
-
- cam = (struct w9968cf_device*)
- kzalloc(sizeof(struct w9968cf_device), GFP_KERNEL);
- if (!cam)
- return -ENOMEM;
-
- err = v4l2_device_register(&intf->dev, &cam->v4l2_dev);
- if (err)
- goto fail0;
-
- mutex_init(&cam->dev_mutex);
- mutex_lock(&cam->dev_mutex);
-
- cam->usbdev = udev;
-
- DBG(2, "%s detected", symbolic(camlist, mod_id))
-
- if (simcams > W9968CF_MAX_DEVICES)
- simcams = W9968CF_SIMCAMS;
-
- /* How many cameras are connected ? */
- mutex_lock(&w9968cf_devlist_mutex);
- list_for_each(ptr, &w9968cf_dev_list)
- sc++;
- mutex_unlock(&w9968cf_devlist_mutex);
-
- if (sc >= simcams) {
- DBG(2, "Device rejected: too many connected cameras "
- "(max. %u)", simcams)
- err = -EPERM;
- goto fail;
- }
-
-
- /* Allocate 2 bytes of memory for camera control USB transfers */
- if (!(cam->control_buffer = kzalloc(2, GFP_KERNEL))) {
- DBG(1,"Couldn't allocate memory for camera control transfers")
- err = -ENOMEM;
- goto fail;
- }
-
- /* Allocate 8 bytes of memory for USB data transfers to the FSB */
- if (!(cam->data_buffer = kzalloc(8, GFP_KERNEL))) {
- DBG(1, "Couldn't allocate memory for data "
- "transfers to the FSB")
- err = -ENOMEM;
- goto fail;
- }
-
- /* Register the V4L device */
- cam->v4ldev = video_device_alloc();
- if (!cam->v4ldev) {
- DBG(1, "Could not allocate memory for a V4L structure")
- err = -ENOMEM;
- goto fail;
- }
-
- strcpy(cam->v4ldev->name, symbolic(camlist, mod_id));
- cam->v4ldev->fops = &w9968cf_fops;
- cam->v4ldev->release = video_device_release;
- video_set_drvdata(cam->v4ldev, cam);
- cam->v4ldev->v4l2_dev = &cam->v4l2_dev;
-
- err = video_register_device(cam->v4ldev, VFL_TYPE_GRABBER,
- video_nr[dev_nr]);
- if (err) {
- DBG(1, "V4L device registration failed")
- if (err == -ENFILE && video_nr[dev_nr] == -1)
- DBG(2, "Couldn't find a free /dev/videoX node")
- video_nr[dev_nr] = -1;
- dev_nr = (dev_nr < W9968CF_MAX_DEVICES-1) ? dev_nr+1 : 0;
- goto fail;
- }
-
- DBG(2, "V4L device registered as %s",
- video_device_node_name(cam->v4ldev))
-
- /* Set some basic constants */
- w9968cf_configure_camera(cam, udev, mod_id, dev_nr);
-
- /* Add a new entry into the list of V4L registered devices */
- mutex_lock(&w9968cf_devlist_mutex);
- list_add(&cam->v4llist, &w9968cf_dev_list);
- mutex_unlock(&w9968cf_devlist_mutex);
- dev_nr = (dev_nr < W9968CF_MAX_DEVICES-1) ? dev_nr+1 : 0;
-
- w9968cf_turn_on_led(cam);
-
- w9968cf_i2c_init(cam);
- cam->sensor_sd = v4l2_i2c_new_subdev(&cam->v4l2_dev,
- &cam->i2c_adapter,
- "ovcamchip", "ovcamchip", 0, addrs);
-
- usb_set_intfdata(intf, cam);
- mutex_unlock(&cam->dev_mutex);
-
- err = w9968cf_sensor_init(cam);
- return 0;
-
-fail: /* Free unused memory */
- kfree(cam->control_buffer);
- kfree(cam->data_buffer);
- if (cam->v4ldev)
- video_device_release(cam->v4ldev);
- mutex_unlock(&cam->dev_mutex);
- v4l2_device_unregister(&cam->v4l2_dev);
-fail0:
- kfree(cam);
- return err;
-}
-
-
-static void w9968cf_usb_disconnect(struct usb_interface* intf)
-{
- struct w9968cf_device* cam =
- (struct w9968cf_device*)usb_get_intfdata(intf);
-
- if (cam) {
- down_write(&w9968cf_disconnect);
- /* Prevent concurrent accesses to data */
- mutex_lock(&cam->dev_mutex);
-
- cam->disconnected = 1;
-
- DBG(2, "Disconnecting %s...", symbolic(camlist, cam->id));
-
- v4l2_device_disconnect(&cam->v4l2_dev);
-
- wake_up_interruptible_all(&cam->open);
-
- if (cam->users) {
- DBG(2, "The device is open (%s)! "
- "Process name: %s. Deregistration and memory "
- "deallocation are deferred on close.",
- video_device_node_name(cam->v4ldev), cam->command)
- cam->misconfigured = 1;
- w9968cf_stop_transfer(cam);
- wake_up_interruptible(&cam->wait_queue);
- } else
- w9968cf_release_resources(cam);
-
- mutex_unlock(&cam->dev_mutex);
- up_write(&w9968cf_disconnect);
-
- if (!cam->users) {
- kfree(cam);
- }
- }
-}
-
-
-static struct usb_driver w9968cf_usb_driver = {
- .name = "w9968cf",
- .id_table = winbond_id_table,
- .probe = w9968cf_usb_probe,
- .disconnect = w9968cf_usb_disconnect,
-};
-
-
-
-/****************************************************************************
- * Module init, exit and intermodule communication *
- ****************************************************************************/
-
-static int __init w9968cf_module_init(void)
-{
- int err;
-
- KDBG(2, W9968CF_MODULE_NAME" "W9968CF_MODULE_VERSION)
- KDBG(3, W9968CF_MODULE_AUTHOR)
-
- if ((err = usb_register(&w9968cf_usb_driver)))
- return err;
-
- return 0;
-}
-
-
-static void __exit w9968cf_module_exit(void)
-{
- /* w9968cf_usb_disconnect() will be called */
- usb_deregister(&w9968cf_usb_driver);
-
- KDBG(2, W9968CF_MODULE_NAME" deregistered")
-}
-
-
-module_init(w9968cf_module_init);
-module_exit(w9968cf_module_exit);
-
diff --git a/drivers/media/video/w9968cf.h b/drivers/media/video/w9968cf.h
deleted file mode 100644
index 73ad864b484..00000000000
--- a/drivers/media/video/w9968cf.h
+++ /dev/null
@@ -1,333 +0,0 @@
-/***************************************************************************
- * Video4Linux driver for W996[87]CF JPEG USB Dual Mode Camera Chip. *
- * *
- * Copyright (C) 2002-2004 by Luca Risolia <luca.risolia@studio.unibo.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. *
- ***************************************************************************/
-
-#ifndef _W9968CF_H_
-#define _W9968CF_H_
-
-#include <linux/videodev2.h>
-#include <linux/usb.h>
-#include <linux/i2c.h>
-#include <linux/device.h>
-#include <linux/spinlock.h>
-#include <linux/list.h>
-#include <linux/wait.h>
-#include <linux/param.h>
-#include <linux/types.h>
-#include <linux/rwsem.h>
-#include <linux/mutex.h>
-
-#include <media/v4l2-device.h>
-#include <media/ovcamchip.h>
-
-#include "w9968cf_vpp.h"
-
-
-/****************************************************************************
- * Default values *
- ****************************************************************************/
-
-#define W9968CF_VPPMOD_LOAD 1 /* automatic 'w9968cf-vpp' module loading */
-
-/* Comment/uncomment the following line to enable/disable debugging messages */
-#define W9968CF_DEBUG
-
-/* These have effect only if W9968CF_DEBUG is defined */
-#define W9968CF_DEBUG_LEVEL 2 /* from 0 to 6. 0 for no debug informations */
-#define W9968CF_SPECIFIC_DEBUG 0 /* 0 or 1 */
-
-#define W9968CF_MAX_DEVICES 32
-#define W9968CF_SIMCAMS W9968CF_MAX_DEVICES /* simultaneous cameras */
-
-#define W9968CF_MAX_BUFFERS 32
-#define W9968CF_BUFFERS 2 /* n. of frame buffers from 2 to MAX_BUFFERS */
-
-/* Maximum data payload sizes in bytes for alternate settings */
-static const u16 wMaxPacketSize[] = {1023, 959, 895, 831, 767, 703, 639, 575,
- 511, 447, 383, 319, 255, 191, 127, 63};
-#define W9968CF_PACKET_SIZE 1023 /* according to wMaxPacketSizes[] */
-#define W9968CF_MIN_PACKET_SIZE 63 /* minimum value */
-#define W9968CF_ISO_PACKETS 5 /* n.of packets for isochronous transfers */
-#define W9968CF_USB_CTRL_TIMEOUT 1000 /* timeout (ms) for usb control commands */
-#define W9968CF_URBS 2 /* n. of scheduled URBs for ISO transfer */
-
-#define W9968CF_I2C_BUS_DELAY 4 /* delay in us for I2C bit r/w operations */
-#define W9968CF_I2C_RW_RETRIES 15 /* number of max I2C r/w retries */
-
-/* Available video formats */
-struct w9968cf_format {
- const u16 palette;
- const u16 depth;
- const u8 compression;
-};
-
-static const struct w9968cf_format w9968cf_formatlist[] = {
- { VIDEO_PALETTE_UYVY, 16, 0 }, /* original video */
- { VIDEO_PALETTE_YUV422P, 16, 1 }, /* with JPEG compression */
- { VIDEO_PALETTE_YUV420P, 12, 1 }, /* with JPEG compression */
- { VIDEO_PALETTE_YUV420, 12, 1 }, /* same as YUV420P */
- { VIDEO_PALETTE_YUYV, 16, 0 }, /* software conversion */
- { VIDEO_PALETTE_YUV422, 16, 0 }, /* software conversion */
- { VIDEO_PALETTE_GREY, 8, 0 }, /* software conversion */
- { VIDEO_PALETTE_RGB555, 16, 0 }, /* software conversion */
- { VIDEO_PALETTE_RGB565, 16, 0 }, /* software conversion */
- { VIDEO_PALETTE_RGB24, 24, 0 }, /* software conversion */
- { VIDEO_PALETTE_RGB32, 32, 0 }, /* software conversion */
- { 0, 0, 0 } /* 0 is a terminating entry */
-};
-
-#define W9968CF_DECOMPRESSION 2 /* decomp:0=disable,1=force,2=any formats */
-#define W9968CF_PALETTE_DECOMP_OFF VIDEO_PALETTE_UYVY /* when decomp=0 */
-#define W9968CF_PALETTE_DECOMP_FORCE VIDEO_PALETTE_YUV420P /* when decomp=1 */
-#define W9968CF_PALETTE_DECOMP_ON VIDEO_PALETTE_UYVY /* when decomp=2 */
-
-#define W9968CF_FORCE_RGB 0 /* read RGB instead of BGR, yes=1/no=0 */
-
-#define W9968CF_MAX_WIDTH 800 /* Has effect if up-scaling is on */
-#define W9968CF_MAX_HEIGHT 600 /* Has effect if up-scaling is on */
-#define W9968CF_WIDTH 320 /* from 128 to 352, multiple of 16 */
-#define W9968CF_HEIGHT 240 /* from 96 to 288, multiple of 16 */
-
-#define W9968CF_CLAMPING 0 /* 0 disable, 1 enable video data clamping */
-#define W9968CF_FILTER_TYPE 0 /* 0 disable 1 (1-2-1), 2 (2-3-6-3-2) */
-#define W9968CF_DOUBLE_BUFFER 1 /* 0 disable, 1 enable double buffer */
-#define W9968CF_LARGEVIEW 1 /* 0 disable, 1 enable */
-#define W9968CF_UPSCALING 0 /* 0 disable, 1 enable */
-
-#define W9968CF_MONOCHROME 0 /* 0 not monochrome, 1 monochrome sensor */
-#define W9968CF_BRIGHTNESS 31000 /* from 0 to 65535 */
-#define W9968CF_HUE 32768 /* from 0 to 65535 */
-#define W9968CF_COLOUR 32768 /* from 0 to 65535 */
-#define W9968CF_CONTRAST 50000 /* from 0 to 65535 */
-#define W9968CF_WHITENESS 32768 /* from 0 to 65535 */
-
-#define W9968CF_AUTOBRIGHT 0 /* 0 disable, 1 enable automatic brightness */
-#define W9968CF_AUTOEXP 1 /* 0 disable, 1 enable automatic exposure */
-#define W9968CF_LIGHTFREQ 50 /* light frequency. 50Hz (Europe) or 60Hz */
-#define W9968CF_BANDINGFILTER 0 /* 0 disable, 1 enable banding filter */
-#define W9968CF_BACKLIGHT 0 /* 0 or 1, 1=object is lit from behind */
-#define W9968CF_MIRROR 0 /* 0 or 1 [don't] reverse image horizontally*/
-
-#define W9968CF_CLOCKDIV -1 /* -1 = automatic clock divisor */
-#define W9968CF_DEF_CLOCKDIVISOR 0 /* default sensor clock divisor value */
-
-
-/****************************************************************************
- * Globals *
- ****************************************************************************/
-
-#define W9968CF_MODULE_NAME "V4L driver for W996[87]CF JPEG USB " \
- "Dual Mode Camera Chip"
-#define W9968CF_MODULE_VERSION "1:1.34-basic"
-#define W9968CF_MODULE_AUTHOR "(C) 2002-2004 Luca Risolia"
-#define W9968CF_AUTHOR_EMAIL "<luca.risolia@studio.unibo.it>"
-#define W9968CF_MODULE_LICENSE "GPL"
-
-static const struct usb_device_id winbond_id_table[] = {
- {
- /* Creative Labs Video Blaster WebCam Go Plus */
- USB_DEVICE(0x041e, 0x4003),
- .driver_info = (unsigned long)"w9968cf",
- },
- {
- /* Generic W996[87]CF JPEG USB Dual Mode Camera */
- USB_DEVICE(0x1046, 0x9967),
- .driver_info = (unsigned long)"w9968cf",
- },
- { } /* terminating entry */
-};
-
-/* W996[87]CF camera models, internal ids: */
-enum w9968cf_model_id {
- W9968CF_MOD_GENERIC = 1, /* Generic W996[87]CF based device */
- W9968CF_MOD_CLVBWGP = 11,/*Creative Labs Video Blaster WebCam Go Plus*/
- W9968CF_MOD_ADPVDMA = 21, /* Aroma Digi Pen VGA Dual Mode ADG-5000 */
- W9986CF_MOD_AAU = 31, /* AVerMedia AVerTV USB */
- W9968CF_MOD_CLVBWG = 34, /* Creative Labs Video Blaster WebCam Go */
- W9968CF_MOD_LL = 37, /* Lebon LDC-035A */
- W9968CF_MOD_EEEMC = 40, /* Ezonics EZ-802 EZMega Cam */
- W9968CF_MOD_OOE = 42, /* OmniVision OV8610-EDE */
- W9968CF_MOD_ODPVDMPC = 43,/* OPCOM Digi Pen VGA Dual Mode Pen Camera */
- W9968CF_MOD_PDPII = 46, /* Pretec Digi Pen-II */
- W9968CF_MOD_PDP480 = 49, /* Pretec DigiPen-480 */
-};
-
-enum w9968cf_frame_status {
- F_READY, /* finished grabbing & ready to be read/synced */
- F_GRABBING, /* in the process of being grabbed into */
- F_ERROR, /* something bad happened while processing */
- F_UNUSED /* unused (no VIDIOCMCAPTURE) */
-};
-
-struct w9968cf_frame_t {
- void* buffer;
- unsigned long size;
- u32 length;
- int number;
- enum w9968cf_frame_status status;
- struct w9968cf_frame_t* next;
- u8 queued;
-};
-
-enum w9968cf_vpp_flag {
- VPP_NONE = 0x00,
- VPP_UPSCALE = 0x01,
- VPP_SWAP_YUV_BYTES = 0x02,
- VPP_DECOMPRESSION = 0x04,
- VPP_UYVY_TO_RGBX = 0x08,
-};
-
-/* Main device driver structure */
-struct w9968cf_device {
- enum w9968cf_model_id id; /* private device identifier */
-
- struct v4l2_device v4l2_dev;
- struct video_device* v4ldev; /* -> V4L structure */
- struct list_head v4llist; /* entry of the list of V4L cameras */
-
- struct usb_device* usbdev; /* -> main USB structure */
- struct urb* urb[W9968CF_URBS]; /* -> USB request block structs */
- void* transfer_buffer[W9968CF_URBS]; /* -> ISO transfer buffers */
- u16* control_buffer; /* -> buffer for control req.*/
- u16* data_buffer; /* -> data to send to the FSB */
-
- struct w9968cf_frame_t frame[W9968CF_MAX_BUFFERS];
- struct w9968cf_frame_t frame_tmp; /* temporary frame */
- struct w9968cf_frame_t frame_vpp; /* helper frame.*/
- struct w9968cf_frame_t* frame_current; /* -> frame being grabbed */
- struct w9968cf_frame_t* requested_frame[W9968CF_MAX_BUFFERS];
-
- u8 max_buffers, /* number of requested buffers */
- force_palette, /* yes=1/no=0 */
- force_rgb, /* read RGB instead of BGR, yes=1, no=0 */
- double_buffer, /* hardware double buffering yes=1/no=0 */
- clamping, /* video data clamping yes=1/no=0 */
- filter_type, /* 0=disabled, 1=3 tap, 2=5 tap filter */
- capture, /* 0=disabled, 1=enabled */
- largeview, /* 0=disabled, 1=enabled */
- decompression, /* 0=disabled, 1=forced, 2=allowed */
- upscaling; /* software image scaling, 0=enabled, 1=disabled */
-
- struct video_picture picture; /* current picture settings */
- struct video_window window; /* current window settings */
-
- u16 hw_depth, /* depth (used by the chip) */
- hw_palette, /* palette (used by the chip) */
- hw_width, /* width (used by the chip) */
- hw_height, /* height (used by the chip) */
- hs_polarity, /* 0=negative sync pulse, 1=positive sync pulse */
- vs_polarity, /* 0=negative sync pulse, 1=positive sync pulse */
- start_cropx, /* pixels from HS inactive edge to 1st cropped pixel*/
- start_cropy; /* pixels from VS inactive edge to 1st cropped pixel*/
-
- enum w9968cf_vpp_flag vpp_flag; /* post-processing routines in use */
-
- u8 nbuffers, /* number of allocated frame buffers */
- altsetting, /* camera alternate setting */
- disconnected, /* flag: yes=1, no=0 */
- misconfigured, /* flag: yes=1, no=0 */
- users, /* flag: number of users holding the device */
- streaming; /* flag: yes=1, no=0 */
-
- u8 sensor_initialized; /* flag: yes=1, no=0 */
-
- /* Determined by the image sensor type: */
- int sensor, /* type of image sensor chip (CC_*) */
- monochrome; /* image sensor is (probably) monochrome */
- u16 maxwidth, /* maximum width supported by the image sensor */
- maxheight, /* maximum height supported by the image sensor */
- minwidth, /* minimum width supported by the image sensor */
- minheight; /* minimum height supported by the image sensor */
- u8 auto_brt, /* auto brightness enabled flag */
- auto_exp, /* auto exposure enabled flag */
- backlight, /* backlight exposure algorithm flag */
- mirror, /* image is reversed horizontally */
- lightfreq, /* power (lighting) frequency */
- bandfilt; /* banding filter enabled flag */
- s8 clockdiv; /* clock divisor */
-
- /* I2C interface to kernel */
- struct i2c_adapter i2c_adapter;
- struct v4l2_subdev *sensor_sd;
-
- /* Locks */
- struct mutex dev_mutex, /* for probe, disconnect,open and close */
- fileop_mutex; /* for read and ioctl */
- spinlock_t urb_lock, /* for submit_urb() and unlink_urb() */
- flist_lock; /* for requested frame list accesses */
- wait_queue_head_t open, wait_queue;
-
- char command[16]; /* name of the program holding the device */
-};
-
-static inline struct w9968cf_device *to_cam(struct v4l2_device *v4l2_dev)
-{
- return container_of(v4l2_dev, struct w9968cf_device, v4l2_dev);
-}
-
-
-/****************************************************************************
- * Macros for debugging *
- ****************************************************************************/
-
-#undef DBG
-#undef KDBG
-#ifdef W9968CF_DEBUG
-/* For device specific debugging messages */
-# define DBG(level, fmt, args...) \
-{ \
- if ( ((specific_debug) && (debug == (level))) || \
- ((!specific_debug) && (debug >= (level))) ) { \
- if ((level) == 1) \
- v4l2_err(&cam->v4l2_dev, fmt "\n", ## args); \
- else if ((level) == 2 || (level) == 3) \
- v4l2_info(&cam->v4l2_dev, fmt "\n", ## args); \
- else if ((level) == 4) \
- v4l2_warn(&cam->v4l2_dev, fmt "\n", ## args); \
- else if ((level) >= 5) \
- v4l2_info(&cam->v4l2_dev, "[%s:%d] " fmt "\n", \
- __func__, __LINE__ , ## args); \
- } \
-}
-/* For generic kernel (not device specific) messages */
-# define KDBG(level, fmt, args...) \
-{ \
- if ( ((specific_debug) && (debug == (level))) || \
- ((!specific_debug) && (debug >= (level))) ) { \
- if ((level) >= 1 && (level) <= 4) \
- pr_info("w9968cf: " fmt "\n", ## args); \
- else if ((level) >= 5) \
- pr_debug("w9968cf: [%s:%d] " fmt "\n", __func__, \
- __LINE__ , ## args); \
- } \
-}
-#else
- /* Not debugging: nothing */
-# define DBG(level, fmt, args...) do {;} while(0);
-# define KDBG(level, fmt, args...) do {;} while(0);
-#endif
-
-#undef PDBG
-#define PDBG(fmt, args...) \
-v4l2_info(&cam->v4l2_dev, "[%s:%d] " fmt "\n", __func__, __LINE__ , ## args);
-
-#undef PDBGG
-#define PDBGG(fmt, args...) do {;} while(0); /* nothing: it's a placeholder */
-
-#endif /* _W9968CF_H_ */
diff --git a/drivers/media/video/w9968cf_decoder.h b/drivers/media/video/w9968cf_decoder.h
deleted file mode 100644
index 59decbfc540..00000000000
--- a/drivers/media/video/w9968cf_decoder.h
+++ /dev/null
@@ -1,86 +0,0 @@
-/***************************************************************************
- * Video decoder for the W996[87]CF driver for Linux. *
- * *
- * Copyright (C) 2003 2004 by Luca Risolia <luca.risolia@studio.unibo.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. *
- ***************************************************************************/
-
-#ifndef _W9968CF_DECODER_H_
-#define _W9968CF_DECODER_H_
-
-/* Comment/uncomment this for high/low quality of compressed video */
-#define W9968CF_DEC_FAST_LOWQUALITY_VIDEO
-
-#ifdef W9968CF_DEC_FAST_LOWQUALITY_VIDEO
-static const unsigned char Y_QUANTABLE[64] = {
- 16, 11, 10, 16, 24, 40, 51, 61,
- 12, 12, 14, 19, 26, 58, 60, 55,
- 14, 13, 16, 24, 40, 57, 69, 56,
- 14, 17, 22, 29, 51, 87, 80, 62,
- 18, 22, 37, 56, 68, 109, 103, 77,
- 24, 35, 55, 64, 81, 104, 113, 92,
- 49, 64, 78, 87, 103, 121, 120, 101,
- 72, 92, 95, 98, 112, 100, 103, 99
-};
-
-static const unsigned char UV_QUANTABLE[64] = {
- 17, 18, 24, 47, 99, 99, 99, 99,
- 18, 21, 26, 66, 99, 99, 99, 99,
- 24, 26, 56, 99, 99, 99, 99, 99,
- 47, 66, 99, 99, 99, 99, 99, 99,
- 99, 99, 99, 99, 99, 99, 99, 99,
- 99, 99, 99, 99, 99, 99, 99, 99,
- 99, 99, 99, 99, 99, 99, 99, 99,
- 99, 99, 99, 99, 99, 99, 99, 99
-};
-#else
-static const unsigned char Y_QUANTABLE[64] = {
- 8, 5, 5, 8, 12, 20, 25, 30,
- 6, 6, 7, 9, 13, 29, 30, 27,
- 7, 6, 8, 12, 20, 28, 34, 28,
- 7, 8, 11, 14, 25, 43, 40, 31,
- 9, 11, 18, 28, 34, 54, 51, 38,
- 12, 17, 27, 32, 40, 52, 56, 46,
- 24, 32, 39, 43, 51, 60, 60, 50,
- 36, 46, 47, 49, 56, 50, 51, 49
-};
-
-static const unsigned char UV_QUANTABLE[64] = {
- 8, 9, 12, 23, 49, 49, 49, 49,
- 9, 10, 13, 33, 49, 49, 49, 49,
- 12, 13, 28, 49, 49, 49, 49, 49,
- 23, 33, 49, 49, 49, 49, 49, 49,
- 49, 49, 49, 49, 49, 49, 49, 49,
- 49, 49, 49, 49, 49, 49, 49, 49,
- 49, 49, 49, 49, 49, 49, 49, 49,
- 49, 49, 49, 49, 49, 49, 49, 49
-};
-#endif
-
-#define W9968CF_DEC_ERR_CORRUPTED_DATA -1
-#define W9968CF_DEC_ERR_BUF_OVERFLOW -2
-#define W9968CF_DEC_ERR_NO_SOI -3
-#define W9968CF_DEC_ERR_NO_SOF0 -4
-#define W9968CF_DEC_ERR_NO_SOS -5
-#define W9968CF_DEC_ERR_NO_EOI -6
-
-extern void w9968cf_init_decoder(void);
-extern int w9968cf_check_headers(const unsigned char* Pin,
- const unsigned long BUF_SIZE);
-extern int w9968cf_decode(const char* Pin, const unsigned long BUF_SIZE,
- const unsigned W, const unsigned H, char* Pout);
-
-#endif /* _W9968CF_DECODER_H_ */
diff --git a/drivers/media/video/w9968cf_vpp.h b/drivers/media/video/w9968cf_vpp.h
deleted file mode 100644
index 88c9b6c0cc3..00000000000
--- a/drivers/media/video/w9968cf_vpp.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/***************************************************************************
- * Interface for video post-processing functions for the W996[87]CF driver *
- * for Linux. *
- * *
- * Copyright (C) 2002-2004 by Luca Risolia <luca.risolia@studio.unibo.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. *
- ***************************************************************************/
-
-#ifndef _W9968CF_VPP_H_
-#define _W9968CF_VPP_H_
-
-#include <linux/module.h>
-#include <asm/types.h>
-
-struct w9968cf_vpp_t {
- struct module* owner;
- int (*check_headers)(const unsigned char*, const unsigned long);
- int (*decode)(const char*, const unsigned long, const unsigned,
- const unsigned, char*);
- void (*swap_yuvbytes)(void*, unsigned long);
- void (*uyvy_to_rgbx)(u8*, unsigned long, u8*, u16, u8);
- void (*scale_up)(u8*, u8*, u16, u16, u16, u16, u16);
-
- u8 busy; /* read-only flag: module is/is not in use */
-};
-
-#endif /* _W9968CF_VPP_H_ */
diff --git a/drivers/media/video/zc0301/Kconfig b/drivers/media/video/zc0301/Kconfig
deleted file mode 100644
index a7e610e0be9..00000000000
--- a/drivers/media/video/zc0301/Kconfig
+++ /dev/null
@@ -1,15 +0,0 @@
-config USB_ZC0301
- tristate "USB ZC0301[P] webcam support (DEPRECATED)"
- depends on VIDEO_V4L2
- default n
- ---help---
- This driver is DEPRECATED please use the gspca zc3xx module
- instead.
-
- Say Y here if you want support for cameras based on the ZC0301 or
- ZC0301P Image Processors and Control Chips.
-
- See <file:Documentation/video4linux/zc0301.txt> for more info.
-
- To compile this driver as a module, choose M here: the
- module will be called zc0301.
diff --git a/drivers/media/video/zc0301/Makefile b/drivers/media/video/zc0301/Makefile
deleted file mode 100644
index d9e6d97fade..00000000000
--- a/drivers/media/video/zc0301/Makefile
+++ /dev/null
@@ -1,3 +0,0 @@
-zc0301-objs := zc0301_core.o zc0301_pb0330.o zc0301_pas202bcb.o
-
-obj-$(CONFIG_USB_ZC0301) += zc0301.o
diff --git a/drivers/media/video/zc0301/zc0301.h b/drivers/media/video/zc0301/zc0301.h
deleted file mode 100644
index b1b5cceb4ba..00000000000
--- a/drivers/media/video/zc0301/zc0301.h
+++ /dev/null
@@ -1,196 +0,0 @@
-/***************************************************************************
- * V4L2 driver for ZC0301[P] Image Processor and Control Chip *
- * *
- * Copyright (C) 2006-2007 by Luca Risolia <luca.risolia@studio.unibo.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. *
- ***************************************************************************/
-
-#ifndef _ZC0301_H_
-#define _ZC0301_H_
-
-#include <linux/version.h>
-#include <linux/usb.h>
-#include <linux/videodev2.h>
-#include <media/v4l2-common.h>
-#include <media/v4l2-ioctl.h>
-#include <linux/device.h>
-#include <linux/list.h>
-#include <linux/spinlock.h>
-#include <linux/time.h>
-#include <linux/wait.h>
-#include <linux/types.h>
-#include <linux/param.h>
-#include <linux/mutex.h>
-#include <linux/rwsem.h>
-#include <linux/stddef.h>
-#include <linux/string.h>
-#include <linux/kref.h>
-
-#include "zc0301_sensor.h"
-
-/*****************************************************************************/
-
-#define ZC0301_DEBUG
-#define ZC0301_DEBUG_LEVEL 2
-#define ZC0301_MAX_DEVICES 64
-#define ZC0301_FORCE_MUNMAP 0
-#define ZC0301_MAX_FRAMES 32
-#define ZC0301_COMPRESSION_QUALITY 0
-#define ZC0301_URBS 2
-#define ZC0301_ISO_PACKETS 7
-#define ZC0301_ALTERNATE_SETTING 7
-#define ZC0301_URB_TIMEOUT msecs_to_jiffies(2 * ZC0301_ISO_PACKETS)
-#define ZC0301_CTRL_TIMEOUT 100
-#define ZC0301_FRAME_TIMEOUT 2
-
-/*****************************************************************************/
-
-ZC0301_ID_TABLE
-ZC0301_SENSOR_TABLE
-
-enum zc0301_frame_state {
- F_UNUSED,
- F_QUEUED,
- F_GRABBING,
- F_DONE,
- F_ERROR,
-};
-
-struct zc0301_frame_t {
- void* bufmem;
- struct v4l2_buffer buf;
- enum zc0301_frame_state state;
- struct list_head frame;
- unsigned long vma_use_count;
-};
-
-enum zc0301_dev_state {
- DEV_INITIALIZED = 0x01,
- DEV_DISCONNECTED = 0x02,
- DEV_MISCONFIGURED = 0x04,
-};
-
-enum zc0301_io_method {
- IO_NONE,
- IO_READ,
- IO_MMAP,
-};
-
-enum zc0301_stream_state {
- STREAM_OFF,
- STREAM_INTERRUPT,
- STREAM_ON,
-};
-
-struct zc0301_module_param {
- u8 force_munmap;
- u16 frame_timeout;
-};
-
-static DECLARE_RWSEM(zc0301_dev_lock);
-
-struct zc0301_device {
- struct video_device* v4ldev;
-
- struct zc0301_sensor sensor;
-
- struct usb_device* usbdev;
- struct urb* urb[ZC0301_URBS];
- void* transfer_buffer[ZC0301_URBS];
- u8* control_buffer;
-
- struct zc0301_frame_t *frame_current, frame[ZC0301_MAX_FRAMES];
- struct list_head inqueue, outqueue;
- u32 frame_count, nbuffers, nreadbuffers;
-
- enum zc0301_io_method io;
- enum zc0301_stream_state stream;
-
- struct v4l2_jpegcompression compression;
-
- struct zc0301_module_param module_param;
-
- struct kref kref;
- enum zc0301_dev_state state;
- u8 users;
-
- struct completion probe;
- struct mutex open_mutex, fileop_mutex;
- spinlock_t queue_lock;
- wait_queue_head_t wait_open, wait_frame, wait_stream;
-};
-
-/*****************************************************************************/
-
-struct zc0301_device*
-zc0301_match_id(struct zc0301_device* cam, const struct usb_device_id *id)
-{
- return usb_match_id(usb_ifnum_to_if(cam->usbdev, 0), id) ? cam : NULL;
-}
-
-void
-zc0301_attach_sensor(struct zc0301_device* cam, struct zc0301_sensor* sensor)
-{
- memcpy(&cam->sensor, sensor, sizeof(struct zc0301_sensor));
-}
-
-/*****************************************************************************/
-
-#undef DBG
-#undef KDBG
-#ifdef ZC0301_DEBUG
-# define DBG(level, fmt, args...) \
-do { \
- if (debug >= (level)) { \
- if ((level) == 1) \
- dev_err(&cam->usbdev->dev, fmt "\n", ## args); \
- else if ((level) == 2) \
- dev_info(&cam->usbdev->dev, fmt "\n", ## args); \
- else if ((level) >= 3) \
- dev_info(&cam->usbdev->dev, "[%s:%s:%d] " fmt "\n", \
- __FILE__, __func__, __LINE__ , ## args); \
- } \
-} while (0)
-# define KDBG(level, fmt, args...) \
-do { \
- if (debug >= (level)) { \
- if ((level) == 1 || (level) == 2) \
- pr_info("zc0301: " fmt "\n", ## args); \
- else if ((level) == 3) \
- pr_debug("sn9c102: [%s:%s:%d] " fmt "\n", __FILE__, \
- __func__, __LINE__ , ## args); \
- } \
-} while (0)
-# define V4LDBG(level, name, cmd) \
-do { \
- if (debug >= (level)) \
- v4l_print_ioctl(name, cmd); \
-} while (0)
-#else
-# define DBG(level, fmt, args...) do {;} while(0)
-# define KDBG(level, fmt, args...) do {;} while(0)
-# define V4LDBG(level, name, cmd) do {;} while(0)
-#endif
-
-#undef PDBG
-#define PDBG(fmt, args...) \
-dev_info(&cam->usbdev->dev, "[%s:%s:%d] " fmt "\n", __FILE__, __func__, \
- __LINE__ , ## args)
-
-#undef PDBGG
-#define PDBGG(fmt, args...) do {;} while(0) /* placeholder */
-
-#endif /* _ZC0301_H_ */
diff --git a/drivers/media/video/zc0301/zc0301_core.c b/drivers/media/video/zc0301/zc0301_core.c
deleted file mode 100644
index bb51cfb0c64..00000000000
--- a/drivers/media/video/zc0301/zc0301_core.c
+++ /dev/null
@@ -1,2098 +0,0 @@
-/***************************************************************************
- * Video4Linux2 driver for ZC0301[P] Image Processor and Control Chip *
- * *
- * Copyright (C) 2006-2007 by Luca Risolia <luca.risolia@studio.unibo.it> *
- * *
- * Informations about the chip internals needed to enable the I2C protocol *
- * have been taken from the documentation of the ZC030x Video4Linux1 *
- * driver written by Andrew Birkett <andy@nobugs.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. *
- ***************************************************************************/
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/param.h>
-#include <linux/errno.h>
-#include <linux/slab.h>
-#include <linux/device.h>
-#include <linux/fs.h>
-#include <linux/delay.h>
-#include <linux/compiler.h>
-#include <linux/ioctl.h>
-#include <linux/poll.h>
-#include <linux/stat.h>
-#include <linux/mm.h>
-#include <linux/vmalloc.h>
-#include <linux/page-flags.h>
-#include <asm/byteorder.h>
-#include <asm/page.h>
-#include <asm/uaccess.h>
-
-#include "zc0301.h"
-
-/*****************************************************************************/
-
-#define ZC0301_MODULE_NAME "V4L2 driver for ZC0301[P] " \
- "Image Processor and Control Chip"
-#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.10"
-#define ZC0301_MODULE_VERSION_CODE KERNEL_VERSION(1, 1, 10)
-
-/*****************************************************************************/
-
-MODULE_DEVICE_TABLE(usb, zc0301_id_table);
-
-MODULE_AUTHOR(ZC0301_MODULE_AUTHOR " " ZC0301_AUTHOR_EMAIL);
-MODULE_DESCRIPTION(ZC0301_MODULE_NAME);
-MODULE_VERSION(ZC0301_MODULE_VERSION);
-MODULE_LICENSE(ZC0301_MODULE_LICENSE);
-
-static short video_nr[] = {[0 ... ZC0301_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)"
- "\nYou can specify up to "
- __MODULE_STRING(ZC0301_MAX_DEVICES) " cameras this way."
- "\nFor example:"
- "\nvideo_nr=-1,2,-1 would assign minor number 2 to"
- "\nthe second registered camera and use auto for the first"
- "\none and for every other camera."
- "\n");
-
-static short force_munmap[] = {[0 ... ZC0301_MAX_DEVICES-1] =
- ZC0301_FORCE_MUNMAP};
-module_param_array(force_munmap, bool, NULL, 0444);
-MODULE_PARM_DESC(force_munmap,
- "\n<0|1[,...]> Force 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)"
- "\nDefault value is "__MODULE_STRING(ZC0301_FORCE_MUNMAP)"."
- "\n");
-
-static unsigned int frame_timeout[] = {[0 ... ZC0301_MAX_DEVICES-1] =
- ZC0301_FRAME_TIMEOUT};
-module_param_array(frame_timeout, uint, NULL, 0644);
-MODULE_PARM_DESC(frame_timeout,
- "\n<n[,...]> Timeout for a video frame in seconds."
- "\nThis parameter is specific for each detected camera."
- "\nDefault value is "__MODULE_STRING(ZC0301_FRAME_TIMEOUT)"."
- "\n");
-
-#ifdef ZC0301_DEBUG
-static unsigned short debug = ZC0301_DEBUG_LEVEL;
-module_param(debug, ushort, 0644);
-MODULE_PARM_DESC(debug,
- "\n<n> Debugging information level, from 0 to 3:"
- "\n0 = none (use carefully)"
- "\n1 = critical errors"
- "\n2 = significant informations"
- "\n3 = more verbose messages"
- "\nLevel 3 is useful for testing only, when only "
- "one device is used."
- "\nDefault value is "__MODULE_STRING(ZC0301_DEBUG_LEVEL)"."
- "\n");
-#endif
-
-/*****************************************************************************/
-
-static u32
-zc0301_request_buffers(struct zc0301_device* cam, u32 count,
- enum zc0301_io_method io)
-{
- struct v4l2_pix_format* p = &(cam->sensor.pix_format);
- struct v4l2_rect* r = &(cam->sensor.cropcap.bounds);
- const size_t imagesize = cam->module_param.force_munmap ||
- io == IO_READ ?
- (p->width * p->height * p->priv) / 8 :
- (r->width * r->height * p->priv) / 8;
- void* buff = NULL;
- u32 i;
-
- if (count > ZC0301_MAX_FRAMES)
- count = ZC0301_MAX_FRAMES;
-
- cam->nbuffers = count;
- while (cam->nbuffers > 0) {
- if ((buff = vmalloc_32_user(cam->nbuffers *
- PAGE_ALIGN(imagesize))))
- break;
- cam->nbuffers--;
- }
-
- for (i = 0; i < cam->nbuffers; i++) {
- cam->frame[i].bufmem = buff + i*PAGE_ALIGN(imagesize);
- cam->frame[i].buf.index = i;
- cam->frame[i].buf.m.offset = i*PAGE_ALIGN(imagesize);
- cam->frame[i].buf.length = imagesize;
- cam->frame[i].buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- cam->frame[i].buf.sequence = 0;
- cam->frame[i].buf.field = V4L2_FIELD_NONE;
- cam->frame[i].buf.memory = V4L2_MEMORY_MMAP;
- cam->frame[i].buf.flags = 0;
- }
-
- return cam->nbuffers;
-}
-
-
-static void zc0301_release_buffers(struct zc0301_device* cam)
-{
- if (cam->nbuffers) {
- vfree(cam->frame[0].bufmem);
- cam->nbuffers = 0;
- }
- cam->frame_current = NULL;
-}
-
-
-static void zc0301_empty_framequeues(struct zc0301_device* cam)
-{
- u32 i;
-
- INIT_LIST_HEAD(&cam->inqueue);
- INIT_LIST_HEAD(&cam->outqueue);
-
- for (i = 0; i < ZC0301_MAX_FRAMES; i++) {
- cam->frame[i].state = F_UNUSED;
- cam->frame[i].buf.bytesused = 0;
- }
-}
-
-
-static void zc0301_requeue_outqueue(struct zc0301_device* cam)
-{
- struct zc0301_frame_t *i;
-
- list_for_each_entry(i, &cam->outqueue, frame) {
- i->state = F_QUEUED;
- list_add(&i->frame, &cam->inqueue);
- }
-
- INIT_LIST_HEAD(&cam->outqueue);
-}
-
-
-static void zc0301_queue_unusedframes(struct zc0301_device* cam)
-{
- unsigned long lock_flags;
- u32 i;
-
- for (i = 0; i < cam->nbuffers; i++)
- if (cam->frame[i].state == F_UNUSED) {
- cam->frame[i].state = F_QUEUED;
- spin_lock_irqsave(&cam->queue_lock, lock_flags);
- list_add_tail(&cam->frame[i].frame, &cam->inqueue);
- spin_unlock_irqrestore(&cam->queue_lock, lock_flags);
- }
-}
-
-/*****************************************************************************/
-
-int zc0301_write_reg(struct zc0301_device* cam, u16 index, u16 value)
-{
- struct usb_device* udev = cam->usbdev;
- int res;
-
- res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0xa0, 0x40,
- value, index, NULL, 0, ZC0301_CTRL_TIMEOUT);
- if (res < 0) {
- DBG(3, "Failed to write a register (index 0x%04X, "
- "value 0x%02X, error %d)",index, value, res);
- return -1;
- }
-
- return 0;
-}
-
-
-int zc0301_read_reg(struct zc0301_device* cam, u16 index)
-{
- struct usb_device* udev = cam->usbdev;
- u8* buff = cam->control_buffer;
- int res;
-
- res = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 0xa1, 0xc0,
- 0x0001, index, buff, 1, ZC0301_CTRL_TIMEOUT);
- if (res < 0)
- DBG(3, "Failed to read a register (index 0x%04X, error %d)",
- index, res);
-
- PDBGG("Read: index 0x%04X, value: 0x%04X", index, (int)(*buff));
-
- return (res >= 0) ? (int)(*buff) : -1;
-}
-
-
-int zc0301_i2c_read(struct zc0301_device* cam, u16 address, u8 length)
-{
- int err = 0, res, r0, r1;
-
- err += zc0301_write_reg(cam, 0x0092, address);
- err += zc0301_write_reg(cam, 0x0090, 0x02);
-
- msleep(1);
-
- res = zc0301_read_reg(cam, 0x0091);
- if (res < 0)
- err += res;
- r0 = zc0301_read_reg(cam, 0x0095);
- if (r0 < 0)
- err += r0;
- r1 = zc0301_read_reg(cam, 0x0096);
- if (r1 < 0)
- err += r1;
-
- res = (length <= 1) ? r0 : r0 | (r1 << 8);
-
- if (err)
- DBG(3, "I2C read failed at address 0x%04X, value: 0x%04X",
- address, res);
-
-
- PDBGG("I2C read: address 0x%04X, value: 0x%04X", address, res);
-
- return err ? -1 : res;
-}
-
-
-int zc0301_i2c_write(struct zc0301_device* cam, u16 address, u16 value)
-{
- int err = 0, res;
-
- err += zc0301_write_reg(cam, 0x0092, address);
- err += zc0301_write_reg(cam, 0x0093, value & 0xff);
- err += zc0301_write_reg(cam, 0x0094, value >> 8);
- err += zc0301_write_reg(cam, 0x0090, 0x01);
-
- msleep(1);
-
- res = zc0301_read_reg(cam, 0x0091);
- if (res < 0)
- err += res;
-
- if (err)
- DBG(3, "I2C write failed at address 0x%04X, value: 0x%04X",
- address, value);
-
- PDBGG("I2C write: address 0x%04X, value: 0x%04X", address, value);
-
- return err ? -1 : 0;
-}
-
-/*****************************************************************************/
-
-static void zc0301_urb_complete(struct urb *urb)
-{
- struct zc0301_device* cam = urb->context;
- struct zc0301_frame_t** f;
- size_t imagesize;
- u8 i;
- int err = 0;
-
- if (urb->status == -ENOENT)
- return;
-
- f = &cam->frame_current;
-
- if (cam->stream == STREAM_INTERRUPT) {
- cam->stream = STREAM_OFF;
- if ((*f))
- (*f)->state = F_QUEUED;
- DBG(3, "Stream interrupted");
- wake_up(&cam->wait_stream);
- }
-
- if (cam->state & DEV_DISCONNECTED)
- return;
-
- if (cam->state & DEV_MISCONFIGURED) {
- wake_up_interruptible(&cam->wait_frame);
- return;
- }
-
- if (cam->stream == STREAM_OFF || list_empty(&cam->inqueue))
- goto resubmit_urb;
-
- if (!(*f))
- (*f) = list_entry(cam->inqueue.next, struct zc0301_frame_t,
- frame);
-
- imagesize = (cam->sensor.pix_format.width *
- cam->sensor.pix_format.height *
- cam->sensor.pix_format.priv) / 8;
-
- for (i = 0; i < urb->number_of_packets; i++) {
- unsigned int len, status;
- void *pos;
- u16* soi;
- u8 sof;
-
- len = urb->iso_frame_desc[i].actual_length;
- status = urb->iso_frame_desc[i].status;
- pos = urb->iso_frame_desc[i].offset + urb->transfer_buffer;
-
- if (status) {
- DBG(3, "Error in isochronous frame");
- (*f)->state = F_ERROR;
- continue;
- }
-
- sof = (*(soi = pos) == 0xd8ff);
-
- PDBGG("Isochrnous frame: length %u, #%u i,", len, i);
-
- if ((*f)->state == F_QUEUED || (*f)->state == F_ERROR)
-start_of_frame:
- if (sof) {
- (*f)->state = F_GRABBING;
- (*f)->buf.bytesused = 0;
- do_gettimeofday(&(*f)->buf.timestamp);
- DBG(3, "SOF detected: new video frame");
- }
-
- if ((*f)->state == F_GRABBING) {
- if (sof && (*f)->buf.bytesused)
- goto end_of_frame;
-
- if ((*f)->buf.bytesused + len > imagesize) {
- DBG(3, "Video frame size exceeded");
- (*f)->state = F_ERROR;
- continue;
- }
-
- memcpy((*f)->bufmem+(*f)->buf.bytesused, pos, len);
- (*f)->buf.bytesused += len;
-
- if ((*f)->buf.bytesused == imagesize) {
- u32 b;
-end_of_frame:
- b = (*f)->buf.bytesused;
- (*f)->state = F_DONE;
- (*f)->buf.sequence= ++cam->frame_count;
- spin_lock(&cam->queue_lock);
- list_move_tail(&(*f)->frame, &cam->outqueue);
- if (!list_empty(&cam->inqueue))
- (*f) = list_entry(cam->inqueue.next,
- struct zc0301_frame_t,
- frame);
- else
- (*f) = NULL;
- spin_unlock(&cam->queue_lock);
- DBG(3, "Video frame captured: : %lu bytes",
- (unsigned long)(b));
-
- if (!(*f))
- goto resubmit_urb;
-
- if (sof)
- goto start_of_frame;
- }
- }
- }
-
-resubmit_urb:
- urb->dev = cam->usbdev;
- err = usb_submit_urb(urb, GFP_ATOMIC);
- if (err < 0 && err != -EPERM) {
- cam->state |= DEV_MISCONFIGURED;
- DBG(1, "usb_submit_urb() failed");
- }
-
- wake_up_interruptible(&cam->wait_frame);
-}
-
-
-static int zc0301_start_transfer(struct zc0301_device* cam)
-{
- struct usb_device *udev = cam->usbdev;
- struct usb_host_interface* altsetting = usb_altnum_to_altsetting(
- usb_ifnum_to_if(udev, 0),
- ZC0301_ALTERNATE_SETTING);
- const unsigned int psz = le16_to_cpu(altsetting->
- endpoint[0].desc.wMaxPacketSize);
- struct urb* urb;
- s8 i, j;
- int err = 0;
-
- for (i = 0; i < ZC0301_URBS; i++) {
- cam->transfer_buffer[i] = kzalloc(ZC0301_ISO_PACKETS * psz,
- GFP_KERNEL);
- if (!cam->transfer_buffer[i]) {
- err = -ENOMEM;
- DBG(1, "Not enough memory");
- goto free_buffers;
- }
- }
-
- for (i = 0; i < ZC0301_URBS; i++) {
- urb = usb_alloc_urb(ZC0301_ISO_PACKETS, GFP_KERNEL);
- cam->urb[i] = urb;
- if (!urb) {
- err = -ENOMEM;
- DBG(1, "usb_alloc_urb() failed");
- goto free_urbs;
- }
- urb->dev = udev;
- urb->context = cam;
- urb->pipe = usb_rcvisocpipe(udev, 1);
- urb->transfer_flags = URB_ISO_ASAP;
- urb->number_of_packets = ZC0301_ISO_PACKETS;
- urb->complete = zc0301_urb_complete;
- urb->transfer_buffer = cam->transfer_buffer[i];
- urb->transfer_buffer_length = psz * ZC0301_ISO_PACKETS;
- urb->interval = 1;
- for (j = 0; j < ZC0301_ISO_PACKETS; j++) {
- urb->iso_frame_desc[j].offset = psz * j;
- urb->iso_frame_desc[j].length = psz;
- }
- }
-
- err = usb_set_interface(udev, 0, ZC0301_ALTERNATE_SETTING);
- if (err) {
- DBG(1, "usb_set_interface() failed");
- goto free_urbs;
- }
-
- cam->frame_current = NULL;
-
- for (i = 0; i < ZC0301_URBS; i++) {
- err = usb_submit_urb(cam->urb[i], GFP_KERNEL);
- if (err) {
- for (j = i-1; j >= 0; j--)
- usb_kill_urb(cam->urb[j]);
- DBG(1, "usb_submit_urb() failed, error %d", err);
- goto free_urbs;
- }
- }
-
- return 0;
-
-free_urbs:
- for (i = 0; (i < ZC0301_URBS) && cam->urb[i]; i++)
- usb_free_urb(cam->urb[i]);
-
-free_buffers:
- for (i = 0; (i < ZC0301_URBS) && cam->transfer_buffer[i]; i++)
- kfree(cam->transfer_buffer[i]);
-
- return err;
-}
-
-
-static int zc0301_stop_transfer(struct zc0301_device* cam)
-{
- struct usb_device *udev = cam->usbdev;
- s8 i;
- int err = 0;
-
- if (cam->state & DEV_DISCONNECTED)
- return 0;
-
- for (i = ZC0301_URBS-1; i >= 0; i--) {
- usb_kill_urb(cam->urb[i]);
- usb_free_urb(cam->urb[i]);
- kfree(cam->transfer_buffer[i]);
- }
-
- err = usb_set_interface(udev, 0, 0); /* 0 Mb/s */
- if (err)
- DBG(3, "usb_set_interface() failed");
-
- return err;
-}
-
-
-static int zc0301_stream_interrupt(struct zc0301_device* cam)
-{
- long timeout;
-
- cam->stream = STREAM_INTERRUPT;
- timeout = wait_event_timeout(cam->wait_stream,
- (cam->stream == STREAM_OFF) ||
- (cam->state & DEV_DISCONNECTED),
- ZC0301_URB_TIMEOUT);
- if (cam->state & DEV_DISCONNECTED)
- return -ENODEV;
- else if (cam->stream != STREAM_OFF) {
- cam->state |= DEV_MISCONFIGURED;
- DBG(1, "URB timeout reached. The camera is misconfigured. To "
- "use it, close and open %s again.",
- video_device_node_name(cam->v4ldev));
- return -EIO;
- }
-
- return 0;
-}
-
-/*****************************************************************************/
-
-static int
-zc0301_set_compression(struct zc0301_device* cam,
- struct v4l2_jpegcompression* compression)
-{
- int r, err = 0;
-
- if ((r = zc0301_read_reg(cam, 0x0008)) < 0)
- err += r;
- err += zc0301_write_reg(cam, 0x0008, r | 0x11 | compression->quality);
-
- return err ? -EIO : 0;
-}
-
-
-static int zc0301_init(struct zc0301_device* cam)
-{
- struct zc0301_sensor* s = &cam->sensor;
- struct v4l2_control ctrl;
- struct v4l2_queryctrl *qctrl;
- struct v4l2_rect* rect;
- u8 i = 0;
- int err = 0;
-
- if (!(cam->state & DEV_INITIALIZED)) {
- mutex_init(&cam->open_mutex);
- init_waitqueue_head(&cam->wait_open);
- qctrl = s->qctrl;
- rect = &(s->cropcap.defrect);
- cam->compression.quality = ZC0301_COMPRESSION_QUALITY;
- } else { /* use current values */
- qctrl = s->_qctrl;
- rect = &(s->_rect);
- }
-
- if (s->init) {
- err = s->init(cam);
- if (err) {
- DBG(3, "Sensor initialization failed");
- return err;
- }
- }
-
- if ((err = zc0301_set_compression(cam, &cam->compression))) {
- DBG(3, "set_compression() failed");
- return err;
- }
-
- if (s->set_crop)
- if ((err = s->set_crop(cam, rect))) {
- DBG(3, "set_crop() failed");
- return err;
- }
-
- if (s->set_ctrl) {
- for (i = 0; i < ARRAY_SIZE(s->qctrl); i++)
- if (s->qctrl[i].id != 0 &&
- !(s->qctrl[i].flags & V4L2_CTRL_FLAG_DISABLED)) {
- ctrl.id = s->qctrl[i].id;
- ctrl.value = qctrl[i].default_value;
- err = s->set_ctrl(cam, &ctrl);
- if (err) {
- DBG(3, "Set %s control failed",
- s->qctrl[i].name);
- return err;
- }
- DBG(3, "Image sensor supports '%s' control",
- s->qctrl[i].name);
- }
- }
-
- if (!(cam->state & DEV_INITIALIZED)) {
- mutex_init(&cam->fileop_mutex);
- spin_lock_init(&cam->queue_lock);
- init_waitqueue_head(&cam->wait_frame);
- init_waitqueue_head(&cam->wait_stream);
- cam->nreadbuffers = 2;
- memcpy(s->_qctrl, s->qctrl, sizeof(s->qctrl));
- memcpy(&(s->_rect), &(s->cropcap.defrect),
- sizeof(struct v4l2_rect));
- cam->state |= DEV_INITIALIZED;
- }
-
- DBG(2, "Initialization succeeded");
- return 0;
-}
-
-/*****************************************************************************/
-
-static void zc0301_release_resources(struct kref *kref)
-{
- struct zc0301_device *cam = container_of(kref, struct zc0301_device,
- kref);
- DBG(2, "V4L2 device %s deregistered",
- video_device_node_name(cam->v4ldev));
- 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 file *filp)
-{
- struct zc0301_device* cam;
- int err = 0;
-
- if (!down_read_trylock(&zc0301_dev_lock))
- return -EAGAIN;
-
- cam = video_drvdata(filp);
-
- 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 %s is busy...",
- video_device_node_name(cam->v4ldev));
- DBG(3, "Simultaneous opens are not supported");
- if ((filp->f_flags & O_NONBLOCK) ||
- (filp->f_flags & O_NDELAY)) {
- err = -EWOULDBLOCK;
- goto out;
- }
- 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);
- down_read(&zc0301_dev_lock);
- if (err)
- goto out;
- if (cam->state & DEV_DISCONNECTED) {
- err = -ENODEV;
- goto out;
- }
- }
-
- if (cam->state & DEV_MISCONFIGURED) {
- err = zc0301_init(cam);
- if (err) {
- DBG(1, "Initialization failed again. "
- "I will retry on next open().");
- goto out;
- }
- cam->state &= ~DEV_MISCONFIGURED;
- }
-
- if ((err = zc0301_start_transfer(cam)))
- goto out;
-
- filp->private_data = cam;
- cam->users++;
- cam->io = IO_NONE;
- cam->stream = STREAM_OFF;
- cam->nbuffers = 0;
- cam->frame_count = 0;
- zc0301_empty_framequeues(cam);
-
- DBG(3, "Video device %s is open",
- video_device_node_name(cam->v4ldev));
-
-out:
- 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 file *filp)
-{
- struct zc0301_device* cam;
-
- down_write(&zc0301_dev_lock);
-
- cam = video_drvdata(filp);
-
- zc0301_stop_transfer(cam);
- zc0301_release_buffers(cam);
- cam->users--;
- wake_up_interruptible_nr(&cam->wait_open, 1);
-
- DBG(3, "Video device %s closed",
- video_device_node_name(cam->v4ldev));
-
- kref_put(&cam->kref, zc0301_release_resources);
-
- up_write(&zc0301_dev_lock);
-
- return 0;
-}
-
-
-static ssize_t
-zc0301_read(struct file* filp, char __user * buf, size_t count, loff_t* f_pos)
-{
- struct zc0301_device *cam = video_drvdata(filp);
- struct zc0301_frame_t* f, * i;
- unsigned long lock_flags;
- long timeout;
- int err = 0;
-
- if (mutex_lock_interruptible(&cam->fileop_mutex))
- return -ERESTARTSYS;
-
- if (cam->state & DEV_DISCONNECTED) {
- DBG(1, "Device not present");
- mutex_unlock(&cam->fileop_mutex);
- return -ENODEV;
- }
-
- if (cam->state & DEV_MISCONFIGURED) {
- DBG(1, "The camera is misconfigured. Close and open it "
- "again.");
- mutex_unlock(&cam->fileop_mutex);
- return -EIO;
- }
-
- if (cam->io == IO_MMAP) {
- DBG(3, "Close and open the device again to choose the read "
- "method");
- mutex_unlock(&cam->fileop_mutex);
- return -EBUSY;
- }
-
- if (cam->io == IO_NONE) {
- if (!zc0301_request_buffers(cam, cam->nreadbuffers, IO_READ)) {
- DBG(1, "read() failed, not enough memory");
- mutex_unlock(&cam->fileop_mutex);
- return -ENOMEM;
- }
- cam->io = IO_READ;
- cam->stream = STREAM_ON;
- }
-
- if (list_empty(&cam->inqueue)) {
- if (!list_empty(&cam->outqueue))
- zc0301_empty_framequeues(cam);
- zc0301_queue_unusedframes(cam);
- }
-
- if (!count) {
- mutex_unlock(&cam->fileop_mutex);
- return 0;
- }
-
- if (list_empty(&cam->outqueue)) {
- if (filp->f_flags & O_NONBLOCK) {
- mutex_unlock(&cam->fileop_mutex);
- return -EAGAIN;
- }
- timeout = wait_event_interruptible_timeout
- ( cam->wait_frame,
- (!list_empty(&cam->outqueue)) ||
- (cam->state & DEV_DISCONNECTED) ||
- (cam->state & DEV_MISCONFIGURED),
- msecs_to_jiffies(
- cam->module_param.frame_timeout * 1000
- )
- );
- if (timeout < 0) {
- mutex_unlock(&cam->fileop_mutex);
- return timeout;
- }
- if (cam->state & DEV_DISCONNECTED) {
- mutex_unlock(&cam->fileop_mutex);
- return -ENODEV;
- }
- if (!timeout || (cam->state & DEV_MISCONFIGURED)) {
- mutex_unlock(&cam->fileop_mutex);
- return -EIO;
- }
- }
-
- f = list_entry(cam->outqueue.prev, struct zc0301_frame_t, frame);
-
- if (count > f->buf.bytesused)
- count = f->buf.bytesused;
-
- if (copy_to_user(buf, f->bufmem, count)) {
- err = -EFAULT;
- goto exit;
- }
- *f_pos += count;
-
-exit:
- spin_lock_irqsave(&cam->queue_lock, lock_flags);
- list_for_each_entry(i, &cam->outqueue, frame)
- i->state = F_UNUSED;
- INIT_LIST_HEAD(&cam->outqueue);
- spin_unlock_irqrestore(&cam->queue_lock, lock_flags);
-
- zc0301_queue_unusedframes(cam);
-
- PDBGG("Frame #%lu, bytes read: %zu",
- (unsigned long)f->buf.index, count);
-
- mutex_unlock(&cam->fileop_mutex);
-
- return err ? err : count;
-}
-
-
-static unsigned int zc0301_poll(struct file *filp, poll_table *wait)
-{
- struct zc0301_device *cam = video_drvdata(filp);
- struct zc0301_frame_t* f;
- unsigned long lock_flags;
- unsigned int mask = 0;
-
- if (mutex_lock_interruptible(&cam->fileop_mutex))
- return POLLERR;
-
- if (cam->state & DEV_DISCONNECTED) {
- DBG(1, "Device not present");
- goto error;
- }
-
- if (cam->state & DEV_MISCONFIGURED) {
- DBG(1, "The camera is misconfigured. Close and open it "
- "again.");
- goto error;
- }
-
- if (cam->io == IO_NONE) {
- if (!zc0301_request_buffers(cam, cam->nreadbuffers, IO_READ)) {
- DBG(1, "poll() failed, not enough memory");
- goto error;
- }
- cam->io = IO_READ;
- cam->stream = STREAM_ON;
- }
-
- if (cam->io == IO_READ) {
- spin_lock_irqsave(&cam->queue_lock, lock_flags);
- list_for_each_entry(f, &cam->outqueue, frame)
- f->state = F_UNUSED;
- INIT_LIST_HEAD(&cam->outqueue);
- spin_unlock_irqrestore(&cam->queue_lock, lock_flags);
- zc0301_queue_unusedframes(cam);
- }
-
- poll_wait(filp, &cam->wait_frame, wait);
-
- if (!list_empty(&cam->outqueue))
- mask |= POLLIN | POLLRDNORM;
-
- mutex_unlock(&cam->fileop_mutex);
-
- return mask;
-
-error:
- mutex_unlock(&cam->fileop_mutex);
- return POLLERR;
-}
-
-
-static void zc0301_vm_open(struct vm_area_struct* vma)
-{
- struct zc0301_frame_t* f = vma->vm_private_data;
- f->vma_use_count++;
-}
-
-
-static void zc0301_vm_close(struct vm_area_struct* vma)
-{
- /* NOTE: buffers are not freed here */
- struct zc0301_frame_t* f = vma->vm_private_data;
- f->vma_use_count--;
-}
-
-
-static const struct vm_operations_struct zc0301_vm_ops = {
- .open = zc0301_vm_open,
- .close = zc0301_vm_close,
-};
-
-
-static int zc0301_mmap(struct file* filp, struct vm_area_struct *vma)
-{
- struct zc0301_device *cam = video_drvdata(filp);
- unsigned long size = vma->vm_end - vma->vm_start,
- start = vma->vm_start;
- void *pos;
- u32 i;
-
- if (mutex_lock_interruptible(&cam->fileop_mutex))
- return -ERESTARTSYS;
-
- if (cam->state & DEV_DISCONNECTED) {
- DBG(1, "Device not present");
- mutex_unlock(&cam->fileop_mutex);
- return -ENODEV;
- }
-
- if (cam->state & DEV_MISCONFIGURED) {
- DBG(1, "The camera is misconfigured. Close and open it "
- "again.");
- mutex_unlock(&cam->fileop_mutex);
- return -EIO;
- }
-
- 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;
- }
-
- for (i = 0; i < cam->nbuffers; i++) {
- if ((cam->frame[i].buf.m.offset>>PAGE_SHIFT) == vma->vm_pgoff)
- break;
- }
- if (i == cam->nbuffers) {
- mutex_unlock(&cam->fileop_mutex);
- return -EINVAL;
- }
-
- vma->vm_flags |= VM_IO;
- vma->vm_flags |= VM_RESERVED;
-
- pos = cam->frame[i].bufmem;
- while (size > 0) { /* size is page-aligned */
- if (vm_insert_page(vma, start, vmalloc_to_page(pos))) {
- mutex_unlock(&cam->fileop_mutex);
- return -EAGAIN;
- }
- start += PAGE_SIZE;
- pos += PAGE_SIZE;
- size -= PAGE_SIZE;
- }
-
- vma->vm_ops = &zc0301_vm_ops;
- vma->vm_private_data = &cam->frame[i];
- zc0301_vm_open(vma);
-
- mutex_unlock(&cam->fileop_mutex);
-
- return 0;
-}
-
-/*****************************************************************************/
-
-static int
-zc0301_vidioc_querycap(struct zc0301_device* cam, void __user * arg)
-{
- struct v4l2_capability cap = {
- .driver = "zc0301",
- .version = ZC0301_MODULE_VERSION_CODE,
- .capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE |
- V4L2_CAP_STREAMING,
- };
-
- strlcpy(cap.card, cam->v4ldev->name, sizeof(cap.card));
- if (usb_make_path(cam->usbdev, cap.bus_info, sizeof(cap.bus_info)) < 0)
- strlcpy(cap.bus_info, dev_name(&cam->usbdev->dev),
- sizeof(cap.bus_info));
-
- if (copy_to_user(arg, &cap, sizeof(cap)))
- return -EFAULT;
-
- return 0;
-}
-
-
-static int
-zc0301_vidioc_enuminput(struct zc0301_device* cam, void __user * arg)
-{
- struct v4l2_input i;
-
- if (copy_from_user(&i, arg, sizeof(i)))
- return -EFAULT;
-
- if (i.index)
- return -EINVAL;
-
- memset(&i, 0, sizeof(i));
- strcpy(i.name, "Camera");
- i.type = V4L2_INPUT_TYPE_CAMERA;
-
- if (copy_to_user(arg, &i, sizeof(i)))
- return -EFAULT;
-
- return 0;
-}
-
-
-static int
-zc0301_vidioc_g_input(struct zc0301_device* cam, void __user * arg)
-{
- int index = 0;
-
- if (copy_to_user(arg, &index, sizeof(index)))
- return -EFAULT;
-
- return 0;
-}
-
-
-static int
-zc0301_vidioc_s_input(struct zc0301_device* cam, void __user * arg)
-{
- int index;
-
- if (copy_from_user(&index, arg, sizeof(index)))
- return -EFAULT;
-
- if (index != 0)
- return -EINVAL;
-
- return 0;
-}
-
-
-static int
-zc0301_vidioc_query_ctrl(struct zc0301_device* cam, void __user * arg)
-{
- struct zc0301_sensor* s = &cam->sensor;
- struct v4l2_queryctrl qc;
- u8 i;
-
- if (copy_from_user(&qc, arg, sizeof(qc)))
- return -EFAULT;
-
- for (i = 0; i < ARRAY_SIZE(s->qctrl); i++)
- if (qc.id && qc.id == s->qctrl[i].id) {
- memcpy(&qc, &(s->qctrl[i]), sizeof(qc));
- if (copy_to_user(arg, &qc, sizeof(qc)))
- return -EFAULT;
- return 0;
- }
-
- return -EINVAL;
-}
-
-
-static int
-zc0301_vidioc_g_ctrl(struct zc0301_device* cam, void __user * arg)
-{
- struct zc0301_sensor* s = &cam->sensor;
- struct v4l2_control ctrl;
- int err = 0;
- u8 i;
-
- if (!s->get_ctrl && !s->set_ctrl)
- return -EINVAL;
-
- if (copy_from_user(&ctrl, arg, sizeof(ctrl)))
- return -EFAULT;
-
- if (!s->get_ctrl) {
- for (i = 0; i < ARRAY_SIZE(s->qctrl); i++)
- if (ctrl.id == s->qctrl[i].id) {
- ctrl.value = s->_qctrl[i].default_value;
- goto exit;
- }
- return -EINVAL;
- } else
- err = s->get_ctrl(cam, &ctrl);
-
-exit:
- if (copy_to_user(arg, &ctrl, sizeof(ctrl)))
- return -EFAULT;
-
- return err;
-}
-
-
-static int
-zc0301_vidioc_s_ctrl(struct zc0301_device* cam, void __user * arg)
-{
- struct zc0301_sensor* s = &cam->sensor;
- struct v4l2_control ctrl;
- u8 i;
- int err = 0;
-
- if (!s->set_ctrl)
- return -EINVAL;
-
- if (copy_from_user(&ctrl, arg, sizeof(ctrl)))
- return -EFAULT;
-
- for (i = 0; i < ARRAY_SIZE(s->qctrl); i++) {
- if (ctrl.id == s->qctrl[i].id) {
- if (s->qctrl[i].flags & V4L2_CTRL_FLAG_DISABLED)
- return -EINVAL;
- if (ctrl.value < s->qctrl[i].minimum ||
- ctrl.value > s->qctrl[i].maximum)
- return -ERANGE;
- ctrl.value -= ctrl.value % s->qctrl[i].step;
- break;
- }
- }
- if (i == ARRAY_SIZE(s->qctrl))
- return -EINVAL;
- if ((err = s->set_ctrl(cam, &ctrl)))
- return err;
-
- s->_qctrl[i].default_value = ctrl.value;
-
- return 0;
-}
-
-
-static int
-zc0301_vidioc_cropcap(struct zc0301_device* cam, void __user * arg)
-{
- struct v4l2_cropcap* cc = &(cam->sensor.cropcap);
-
- cc->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- cc->pixelaspect.numerator = 1;
- cc->pixelaspect.denominator = 1;
-
- if (copy_to_user(arg, cc, sizeof(*cc)))
- return -EFAULT;
-
- return 0;
-}
-
-
-static int
-zc0301_vidioc_g_crop(struct zc0301_device* cam, void __user * arg)
-{
- struct zc0301_sensor* s = &cam->sensor;
- struct v4l2_crop crop = {
- .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
- };
-
- memcpy(&(crop.c), &(s->_rect), sizeof(struct v4l2_rect));
-
- if (copy_to_user(arg, &crop, sizeof(crop)))
- return -EFAULT;
-
- return 0;
-}
-
-
-static int
-zc0301_vidioc_s_crop(struct zc0301_device* cam, void __user * arg)
-{
- struct zc0301_sensor* s = &cam->sensor;
- struct v4l2_crop crop;
- struct v4l2_rect* rect;
- struct v4l2_rect* bounds = &(s->cropcap.bounds);
- const enum zc0301_stream_state stream = cam->stream;
- const u32 nbuffers = cam->nbuffers;
- u32 i;
- int err = 0;
-
- if (copy_from_user(&crop, arg, sizeof(crop)))
- return -EFAULT;
-
- rect = &(crop.c);
-
- if (crop.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
-
- if (cam->module_param.force_munmap)
- for (i = 0; i < cam->nbuffers; i++)
- if (cam->frame[i].vma_use_count) {
- DBG(3, "VIDIOC_S_CROP failed. "
- "Unmap the buffers first.");
- return -EBUSY;
- }
-
- if (!s->set_crop) {
- memcpy(rect, &(s->_rect), sizeof(*rect));
- if (copy_to_user(arg, &crop, sizeof(crop)))
- return -EFAULT;
- return 0;
- }
-
- rect->left &= ~7L;
- rect->top &= ~7L;
- if (rect->width < 8)
- rect->width = 8;
- if (rect->height < 8)
- rect->height = 8;
- if (rect->width > bounds->width)
- rect->width = bounds->width;
- if (rect->height > bounds->height)
- rect->height = bounds->height;
- if (rect->left < bounds->left)
- rect->left = bounds->left;
- if (rect->top < bounds->top)
- rect->top = bounds->top;
- if (rect->left + rect->width > bounds->left + bounds->width)
- rect->left = bounds->left+bounds->width - rect->width;
- if (rect->top + rect->height > bounds->top + bounds->height)
- rect->top = bounds->top+bounds->height - rect->height;
- rect->width &= ~7L;
- rect->height &= ~7L;
-
- if (cam->stream == STREAM_ON)
- if ((err = zc0301_stream_interrupt(cam)))
- return err;
-
- if (copy_to_user(arg, &crop, sizeof(crop))) {
- cam->stream = stream;
- return -EFAULT;
- }
-
- if (cam->module_param.force_munmap || cam->io == IO_READ)
- zc0301_release_buffers(cam);
-
- if (s->set_crop)
- err += s->set_crop(cam, rect);
-
- if (err) { /* atomic, no rollback in ioctl() */
- cam->state |= DEV_MISCONFIGURED;
- DBG(1, "VIDIOC_S_CROP failed because of hardware problems. To "
- "use the camera, close and open %s again.",
- video_device_node_name(cam->v4ldev));
- return -EIO;
- }
-
- s->pix_format.width = rect->width;
- s->pix_format.height = rect->height;
- memcpy(&(s->_rect), rect, sizeof(*rect));
-
- if ((cam->module_param.force_munmap || cam->io == IO_READ) &&
- nbuffers != zc0301_request_buffers(cam, nbuffers, cam->io)) {
- cam->state |= DEV_MISCONFIGURED;
- DBG(1, "VIDIOC_S_CROP failed because of not enough memory. To "
- "use the camera, close and open %s again.",
- video_device_node_name(cam->v4ldev));
- return -ENOMEM;
- }
-
- if (cam->io == IO_READ)
- zc0301_empty_framequeues(cam);
- else if (cam->module_param.force_munmap)
- zc0301_requeue_outqueue(cam);
-
- cam->stream = stream;
-
- return 0;
-}
-
-
-static int
-zc0301_vidioc_enum_framesizes(struct zc0301_device* cam, void __user * arg)
-{
- struct v4l2_frmsizeenum frmsize;
-
- if (copy_from_user(&frmsize, arg, sizeof(frmsize)))
- return -EFAULT;
-
- if (frmsize.index != 0 && frmsize.index != 1)
- return -EINVAL;
-
- if (frmsize.pixel_format != V4L2_PIX_FMT_JPEG)
- return -EINVAL;
-
- frmsize.type = V4L2_FRMSIZE_TYPE_DISCRETE;
-
- if (frmsize.index == 1) {
- frmsize.discrete.width = cam->sensor.cropcap.defrect.width;
- frmsize.discrete.height = cam->sensor.cropcap.defrect.height;
- }
- memset(&frmsize.reserved, 0, sizeof(frmsize.reserved));
-
- if (copy_to_user(arg, &frmsize, sizeof(frmsize)))
- return -EFAULT;
-
- return 0;
-}
-
-
-static int
-zc0301_vidioc_enum_fmt(struct zc0301_device* cam, void __user * arg)
-{
- struct v4l2_fmtdesc fmtd;
-
- if (copy_from_user(&fmtd, arg, sizeof(fmtd)))
- return -EFAULT;
-
- if (fmtd.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
-
- if (fmtd.index == 0) {
- strcpy(fmtd.description, "JPEG");
- fmtd.pixelformat = V4L2_PIX_FMT_JPEG;
- fmtd.flags = V4L2_FMT_FLAG_COMPRESSED;
- } else
- return -EINVAL;
-
- fmtd.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- memset(&fmtd.reserved, 0, sizeof(fmtd.reserved));
-
- if (copy_to_user(arg, &fmtd, sizeof(fmtd)))
- return -EFAULT;
-
- return 0;
-}
-
-
-static int
-zc0301_vidioc_g_fmt(struct zc0301_device* cam, void __user * arg)
-{
- struct v4l2_format format;
- struct v4l2_pix_format* pfmt = &(cam->sensor.pix_format);
-
- if (copy_from_user(&format, arg, sizeof(format)))
- return -EFAULT;
-
- if (format.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
-
- pfmt->bytesperline = 0;
- pfmt->sizeimage = pfmt->height * ((pfmt->width*pfmt->priv)/8);
- pfmt->field = V4L2_FIELD_NONE;
- memcpy(&(format.fmt.pix), pfmt, sizeof(*pfmt));
-
- if (copy_to_user(arg, &format, sizeof(format)))
- return -EFAULT;
-
- return 0;
-}
-
-
-static int
-zc0301_vidioc_try_s_fmt(struct zc0301_device* cam, unsigned int cmd,
- void __user * arg)
-{
- struct zc0301_sensor* s = &cam->sensor;
- struct v4l2_format format;
- struct v4l2_pix_format* pix;
- struct v4l2_pix_format* pfmt = &(s->pix_format);
- struct v4l2_rect* bounds = &(s->cropcap.bounds);
- struct v4l2_rect rect;
- const enum zc0301_stream_state stream = cam->stream;
- const u32 nbuffers = cam->nbuffers;
- u32 i;
- int err = 0;
-
- if (copy_from_user(&format, arg, sizeof(format)))
- return -EFAULT;
-
- pix = &(format.fmt.pix);
-
- if (format.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
-
- memcpy(&rect, &(s->_rect), sizeof(rect));
-
- if (!s->set_crop) {
- pix->width = rect.width;
- pix->height = rect.height;
- } else {
- rect.width = pix->width;
- rect.height = pix->height;
- }
-
- if (rect.width < 8)
- rect.width = 8;
- if (rect.height < 8)
- rect.height = 8;
- if (rect.width > bounds->left + bounds->width - rect.left)
- rect.width = bounds->left + bounds->width - rect.left;
- if (rect.height > bounds->top + bounds->height - rect.top)
- rect.height = bounds->top + bounds->height - rect.top;
- rect.width &= ~7L;
- rect.height &= ~7L;
-
- pix->width = rect.width;
- pix->height = rect.height;
- pix->pixelformat = pfmt->pixelformat;
- pix->priv = pfmt->priv;
- pix->colorspace = pfmt->colorspace;
- pix->bytesperline = 0;
- pix->sizeimage = pix->height * ((pix->width * pix->priv) / 8);
- pix->field = V4L2_FIELD_NONE;
-
- if (cmd == VIDIOC_TRY_FMT) {
- if (copy_to_user(arg, &format, sizeof(format)))
- return -EFAULT;
- return 0;
- }
-
- if (cam->module_param.force_munmap)
- for (i = 0; i < cam->nbuffers; i++)
- if (cam->frame[i].vma_use_count) {
- DBG(3, "VIDIOC_S_FMT failed. "
- "Unmap the buffers first.");
- return -EBUSY;
- }
-
- if (cam->stream == STREAM_ON)
- if ((err = zc0301_stream_interrupt(cam)))
- return err;
-
- if (copy_to_user(arg, &format, sizeof(format))) {
- cam->stream = stream;
- return -EFAULT;
- }
-
- if (cam->module_param.force_munmap || cam->io == IO_READ)
- zc0301_release_buffers(cam);
-
- if (s->set_crop)
- err += s->set_crop(cam, &rect);
-
- if (err) { /* atomic, no rollback in ioctl() */
- cam->state |= DEV_MISCONFIGURED;
- DBG(1, "VIDIOC_S_FMT failed because of hardware problems. To "
- "use the camera, close and open %s again.",
- video_device_node_name(cam->v4ldev));
- return -EIO;
- }
-
- memcpy(pfmt, pix, sizeof(*pix));
- memcpy(&(s->_rect), &rect, sizeof(rect));
-
- if ((cam->module_param.force_munmap || cam->io == IO_READ) &&
- nbuffers != zc0301_request_buffers(cam, nbuffers, cam->io)) {
- cam->state |= DEV_MISCONFIGURED;
- DBG(1, "VIDIOC_S_FMT failed because of not enough memory. To "
- "use the camera, close and open %s again.",
- video_device_node_name(cam->v4ldev));
- return -ENOMEM;
- }
-
- if (cam->io == IO_READ)
- zc0301_empty_framequeues(cam);
- else if (cam->module_param.force_munmap)
- zc0301_requeue_outqueue(cam);
-
- cam->stream = stream;
-
- return 0;
-}
-
-
-static int
-zc0301_vidioc_g_jpegcomp(struct zc0301_device* cam, void __user * arg)
-{
- if (copy_to_user(arg, &cam->compression, sizeof(cam->compression)))
- return -EFAULT;
-
- return 0;
-}
-
-
-static int
-zc0301_vidioc_s_jpegcomp(struct zc0301_device* cam, void __user * arg)
-{
- struct v4l2_jpegcompression jc;
- const enum zc0301_stream_state stream = cam->stream;
- int err = 0;
-
- if (copy_from_user(&jc, arg, sizeof(jc)))
- return -EFAULT;
-
- if (jc.quality != 0)
- return -EINVAL;
-
- if (cam->stream == STREAM_ON)
- if ((err = zc0301_stream_interrupt(cam)))
- return err;
-
- err += zc0301_set_compression(cam, &jc);
- if (err) { /* atomic, no rollback in ioctl() */
- cam->state |= DEV_MISCONFIGURED;
- DBG(1, "VIDIOC_S_JPEGCOMP failed because of hardware "
- "problems. To use the camera, close and open %s again.",
- video_device_node_name(cam->v4ldev));
- return -EIO;
- }
-
- cam->compression.quality = jc.quality;
-
- cam->stream = stream;
-
- return 0;
-}
-
-
-static int
-zc0301_vidioc_reqbufs(struct zc0301_device* cam, void __user * arg)
-{
- struct v4l2_requestbuffers rb;
- u32 i;
- int err;
-
- if (copy_from_user(&rb, arg, sizeof(rb)))
- return -EFAULT;
-
- if (rb.type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
- rb.memory != V4L2_MEMORY_MMAP)
- return -EINVAL;
-
- if (cam->io == IO_READ) {
- DBG(3, "Close and open the device again to choose the mmap "
- "I/O method");
- 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 -EBUSY;
- }
-
- if (cam->stream == STREAM_ON)
- if ((err = zc0301_stream_interrupt(cam)))
- return err;
-
- zc0301_empty_framequeues(cam);
-
- zc0301_release_buffers(cam);
- if (rb.count)
- rb.count = zc0301_request_buffers(cam, rb.count, IO_MMAP);
-
- if (copy_to_user(arg, &rb, sizeof(rb))) {
- zc0301_release_buffers(cam);
- cam->io = IO_NONE;
- return -EFAULT;
- }
-
- cam->io = rb.count ? IO_MMAP : IO_NONE;
-
- return 0;
-}
-
-
-static int
-zc0301_vidioc_querybuf(struct zc0301_device* cam, void __user * arg)
-{
- struct v4l2_buffer b;
-
- if (copy_from_user(&b, arg, sizeof(b)))
- return -EFAULT;
-
- if (b.type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
- b.index >= cam->nbuffers || cam->io != IO_MMAP)
- return -EINVAL;
-
- memcpy(&b, &cam->frame[b.index].buf, sizeof(b));
-
- if (cam->frame[b.index].vma_use_count)
- b.flags |= V4L2_BUF_FLAG_MAPPED;
-
- if (cam->frame[b.index].state == F_DONE)
- b.flags |= V4L2_BUF_FLAG_DONE;
- else if (cam->frame[b.index].state != F_UNUSED)
- b.flags |= V4L2_BUF_FLAG_QUEUED;
-
- if (copy_to_user(arg, &b, sizeof(b)))
- return -EFAULT;
-
- return 0;
-}
-
-
-static int
-zc0301_vidioc_qbuf(struct zc0301_device* cam, void __user * arg)
-{
- struct v4l2_buffer b;
- unsigned long lock_flags;
-
- if (copy_from_user(&b, arg, sizeof(b)))
- return -EFAULT;
-
- if (b.type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
- b.index >= cam->nbuffers || cam->io != IO_MMAP)
- return -EINVAL;
-
- if (cam->frame[b.index].state != F_UNUSED)
- return -EINVAL;
-
- cam->frame[b.index].state = F_QUEUED;
-
- spin_lock_irqsave(&cam->queue_lock, lock_flags);
- list_add_tail(&cam->frame[b.index].frame, &cam->inqueue);
- spin_unlock_irqrestore(&cam->queue_lock, lock_flags);
-
- PDBGG("Frame #%lu queued", (unsigned long)b.index);
-
- return 0;
-}
-
-
-static int
-zc0301_vidioc_dqbuf(struct zc0301_device* cam, struct file* filp,
- void __user * arg)
-{
- struct v4l2_buffer b;
- struct zc0301_frame_t *f;
- unsigned long lock_flags;
- long timeout;
-
- if (copy_from_user(&b, arg, sizeof(b)))
- return -EFAULT;
-
- if (b.type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io!= IO_MMAP)
- return -EINVAL;
-
- if (list_empty(&cam->outqueue)) {
- if (cam->stream == STREAM_OFF)
- return -EINVAL;
- if (filp->f_flags & O_NONBLOCK)
- return -EAGAIN;
- timeout = wait_event_interruptible_timeout
- ( cam->wait_frame,
- (!list_empty(&cam->outqueue)) ||
- (cam->state & DEV_DISCONNECTED) ||
- (cam->state & DEV_MISCONFIGURED),
- cam->module_param.frame_timeout *
- 1000 * msecs_to_jiffies(1) );
- if (timeout < 0)
- return timeout;
- if (cam->state & DEV_DISCONNECTED)
- return -ENODEV;
- if (!timeout || (cam->state & DEV_MISCONFIGURED))
- return -EIO;
- }
-
- spin_lock_irqsave(&cam->queue_lock, lock_flags);
- f = list_entry(cam->outqueue.next, struct zc0301_frame_t, frame);
- list_del(cam->outqueue.next);
- spin_unlock_irqrestore(&cam->queue_lock, lock_flags);
-
- f->state = F_UNUSED;
-
- memcpy(&b, &f->buf, sizeof(b));
- if (f->vma_use_count)
- b.flags |= V4L2_BUF_FLAG_MAPPED;
-
- if (copy_to_user(arg, &b, sizeof(b)))
- return -EFAULT;
-
- PDBGG("Frame #%lu dequeued", (unsigned long)f->buf.index);
-
- return 0;
-}
-
-
-static int
-zc0301_vidioc_streamon(struct zc0301_device* cam, void __user * arg)
-{
- int type;
-
- if (copy_from_user(&type, arg, sizeof(type)))
- return -EFAULT;
-
- if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io != IO_MMAP)
- return -EINVAL;
-
- cam->stream = STREAM_ON;
-
- DBG(3, "Stream on");
-
- return 0;
-}
-
-
-static int
-zc0301_vidioc_streamoff(struct zc0301_device* cam, void __user * arg)
-{
- int type, err;
-
- if (copy_from_user(&type, arg, sizeof(type)))
- return -EFAULT;
-
- if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io != IO_MMAP)
- return -EINVAL;
-
- if (cam->stream == STREAM_ON)
- if ((err = zc0301_stream_interrupt(cam)))
- return err;
-
- zc0301_empty_framequeues(cam);
-
- DBG(3, "Stream off");
-
- return 0;
-}
-
-
-static int
-zc0301_vidioc_g_parm(struct zc0301_device* cam, void __user * arg)
-{
- struct v4l2_streamparm sp;
-
- if (copy_from_user(&sp, arg, sizeof(sp)))
- return -EFAULT;
-
- if (sp.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
-
- sp.parm.capture.extendedmode = 0;
- sp.parm.capture.readbuffers = cam->nreadbuffers;
-
- if (copy_to_user(arg, &sp, sizeof(sp)))
- return -EFAULT;
-
- return 0;
-}
-
-
-static int
-zc0301_vidioc_s_parm(struct zc0301_device* cam, void __user * arg)
-{
- struct v4l2_streamparm sp;
-
- if (copy_from_user(&sp, arg, sizeof(sp)))
- return -EFAULT;
-
- if (sp.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
-
- sp.parm.capture.extendedmode = 0;
-
- if (sp.parm.capture.readbuffers == 0)
- sp.parm.capture.readbuffers = cam->nreadbuffers;
-
- if (sp.parm.capture.readbuffers > ZC0301_MAX_FRAMES)
- sp.parm.capture.readbuffers = ZC0301_MAX_FRAMES;
-
- if (copy_to_user(arg, &sp, sizeof(sp)))
- return -EFAULT;
-
- cam->nreadbuffers = sp.parm.capture.readbuffers;
-
- return 0;
-}
-
-
-static long zc0301_ioctl_v4l2(struct file *filp,
- unsigned int cmd, void __user *arg)
-{
- struct zc0301_device *cam = video_drvdata(filp);
-
- switch (cmd) {
-
- case VIDIOC_QUERYCAP:
- return zc0301_vidioc_querycap(cam, arg);
-
- case VIDIOC_ENUMINPUT:
- return zc0301_vidioc_enuminput(cam, arg);
-
- case VIDIOC_G_INPUT:
- return zc0301_vidioc_g_input(cam, arg);
-
- case VIDIOC_S_INPUT:
- return zc0301_vidioc_s_input(cam, arg);
-
- case VIDIOC_QUERYCTRL:
- return zc0301_vidioc_query_ctrl(cam, arg);
-
- case VIDIOC_G_CTRL:
- return zc0301_vidioc_g_ctrl(cam, arg);
-
- case VIDIOC_S_CTRL:
- return zc0301_vidioc_s_ctrl(cam, arg);
-
- case VIDIOC_CROPCAP:
- return zc0301_vidioc_cropcap(cam, arg);
-
- case VIDIOC_G_CROP:
- return zc0301_vidioc_g_crop(cam, arg);
-
- case VIDIOC_S_CROP:
- return zc0301_vidioc_s_crop(cam, arg);
-
- case VIDIOC_ENUM_FMT:
- return zc0301_vidioc_enum_fmt(cam, arg);
-
- case VIDIOC_G_FMT:
- return zc0301_vidioc_g_fmt(cam, arg);
-
- case VIDIOC_TRY_FMT:
- case VIDIOC_S_FMT:
- return zc0301_vidioc_try_s_fmt(cam, cmd, arg);
-
- case VIDIOC_ENUM_FRAMESIZES:
- return zc0301_vidioc_enum_framesizes(cam, arg);
-
- case VIDIOC_G_JPEGCOMP:
- return zc0301_vidioc_g_jpegcomp(cam, arg);
-
- case VIDIOC_S_JPEGCOMP:
- return zc0301_vidioc_s_jpegcomp(cam, arg);
-
- case VIDIOC_REQBUFS:
- return zc0301_vidioc_reqbufs(cam, arg);
-
- case VIDIOC_QUERYBUF:
- return zc0301_vidioc_querybuf(cam, arg);
-
- case VIDIOC_QBUF:
- return zc0301_vidioc_qbuf(cam, arg);
-
- case VIDIOC_DQBUF:
- return zc0301_vidioc_dqbuf(cam, filp, arg);
-
- case VIDIOC_STREAMON:
- return zc0301_vidioc_streamon(cam, arg);
-
- case VIDIOC_STREAMOFF:
- return zc0301_vidioc_streamoff(cam, arg);
-
- case VIDIOC_G_PARM:
- return zc0301_vidioc_g_parm(cam, arg);
-
- case VIDIOC_S_PARM:
- return zc0301_vidioc_s_parm(cam, arg);
-
- case VIDIOC_G_STD:
- case VIDIOC_S_STD:
- case VIDIOC_QUERYSTD:
- case VIDIOC_ENUMSTD:
- case VIDIOC_QUERYMENU:
- case VIDIOC_ENUM_FRAMEINTERVALS:
- return -EINVAL;
-
- default:
- return -EINVAL;
-
- }
-}
-
-
-static long zc0301_ioctl(struct file *filp,
- unsigned int cmd, unsigned long arg)
-{
- struct zc0301_device *cam = video_drvdata(filp);
- int err = 0;
-
- if (mutex_lock_interruptible(&cam->fileop_mutex))
- return -ERESTARTSYS;
-
- if (cam->state & DEV_DISCONNECTED) {
- DBG(1, "Device not present");
- mutex_unlock(&cam->fileop_mutex);
- return -ENODEV;
- }
-
- if (cam->state & DEV_MISCONFIGURED) {
- DBG(1, "The camera is misconfigured. Close and open it "
- "again.");
- mutex_unlock(&cam->fileop_mutex);
- return -EIO;
- }
-
- V4LDBG(3, "zc0301", cmd);
-
- err = zc0301_ioctl_v4l2(filp, cmd, (void __user *)arg);
-
- mutex_unlock(&cam->fileop_mutex);
-
- return err;
-}
-
-
-static const struct v4l2_file_operations zc0301_fops = {
- .owner = THIS_MODULE,
- .open = zc0301_open,
- .release = zc0301_release,
- .ioctl = zc0301_ioctl,
- .read = zc0301_read,
- .poll = zc0301_poll,
- .mmap = zc0301_mmap,
-};
-
-/*****************************************************************************/
-
-static int
-zc0301_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
-{
- struct usb_device *udev = interface_to_usbdev(intf);
- struct zc0301_device* cam;
- static unsigned int dev_nr;
- unsigned int i;
- int err = 0;
-
- if (!(cam = kzalloc(sizeof(struct zc0301_device), GFP_KERNEL)))
- return -ENOMEM;
-
- cam->usbdev = udev;
-
- if (!(cam->control_buffer = kzalloc(4, GFP_KERNEL))) {
- DBG(1, "kmalloc() failed");
- err = -ENOMEM;
- goto fail;
- }
-
- if (!(cam->v4ldev = video_device_alloc())) {
- DBG(1, "video_device_alloc() failed");
- err = -ENOMEM;
- goto fail;
- }
-
- DBG(2, "ZC0301[P] Image Processor and Control Chip detected "
- "(vid/pid 0x%04X:0x%04X)",id->idVendor, id->idProduct);
-
- for (i = 0; zc0301_sensor_table[i]; i++) {
- err = zc0301_sensor_table[i](cam);
- if (!err)
- break;
- }
-
- if (!err)
- DBG(2, "%s image sensor detected", cam->sensor.name);
- else {
- DBG(1, "No supported image sensor detected");
- err = -ENODEV;
- goto fail;
- }
-
- if (zc0301_init(cam)) {
- DBG(1, "Initialization failed. I will retry on open().");
- cam->state |= DEV_MISCONFIGURED;
- }
-
- strcpy(cam->v4ldev->name, "ZC0301[P] PC Camera");
- cam->v4ldev->fops = &zc0301_fops;
- cam->v4ldev->release = video_device_release;
- cam->v4ldev->parent = &udev->dev;
- video_set_drvdata(cam->v4ldev, cam);
-
- init_completion(&cam->probe);
-
- err = video_register_device(cam->v4ldev, VFL_TYPE_GRABBER,
- video_nr[dev_nr]);
- if (err) {
- DBG(1, "V4L2 device registration failed");
- if (err == -ENFILE && video_nr[dev_nr] == -1)
- 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;
- complete_all(&cam->probe);
- goto fail;
- }
-
- DBG(2, "V4L2 device registered as %s",
- video_device_node_name(cam->v4ldev));
-
- cam->module_param.force_munmap = force_munmap[dev_nr];
- cam->module_param.frame_timeout = frame_timeout[dev_nr];
-
- 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);
-
- complete_all(&cam->probe);
-
- return 0;
-
-fail:
- if (cam) {
- kfree(cam->control_buffer);
- if (cam->v4ldev)
- video_device_release(cam->v4ldev);
- kfree(cam);
- }
- return err;
-}
-
-
-static void zc0301_usb_disconnect(struct usb_interface* intf)
-{
- struct zc0301_device* cam;
-
- down_write(&zc0301_dev_lock);
-
- cam = usb_get_intfdata(intf);
-
- DBG(2, "Disconnecting %s...", cam->v4ldev->name);
-
- if (cam->users) {
- DBG(2, "Device %s is open! Deregistration and "
- "memory deallocation are deferred.",
- video_device_node_name(cam->v4ldev));
- cam->state |= DEV_MISCONFIGURED;
- zc0301_stop_transfer(cam);
- cam->state |= DEV_DISCONNECTED;
- wake_up_interruptible(&cam->wait_frame);
- wake_up(&cam->wait_stream);
- } else
- cam->state |= DEV_DISCONNECTED;
-
- wake_up_interruptible_all(&cam->wait_open);
-
- kref_put(&cam->kref, zc0301_release_resources);
-
- up_write(&zc0301_dev_lock);
-}
-
-
-static struct usb_driver zc0301_usb_driver = {
- .name = "zc0301",
- .id_table = zc0301_id_table,
- .probe = zc0301_usb_probe,
- .disconnect = zc0301_usb_disconnect,
-};
-
-/*****************************************************************************/
-
-static int __init zc0301_module_init(void)
-{
- int err = 0;
-
- KDBG(2, ZC0301_MODULE_NAME " v" ZC0301_MODULE_VERSION);
- KDBG(3, ZC0301_MODULE_AUTHOR);
-
- if ((err = usb_register(&zc0301_usb_driver)))
- KDBG(1, "usb_register() failed");
-
- return err;
-}
-
-
-static void __exit zc0301_module_exit(void)
-{
- usb_deregister(&zc0301_usb_driver);
-}
-
-
-module_init(zc0301_module_init);
-module_exit(zc0301_module_exit);
diff --git a/drivers/media/video/zc0301/zc0301_pas202bcb.c b/drivers/media/video/zc0301/zc0301_pas202bcb.c
deleted file mode 100644
index 24b0dfba357..00000000000
--- a/drivers/media/video/zc0301/zc0301_pas202bcb.c
+++ /dev/null
@@ -1,362 +0,0 @@
-/***************************************************************************
- * Plug-in for PAS202BCB image sensor connected to the ZC0301 Image *
- * Processor and Control Chip *
- * *
- * Copyright (C) 2006-2007 by Luca Risolia <luca.risolia@studio.unibo.it> *
- * *
- * Initialization values of the ZC0301[P] have been taken from the SPCA5XX *
- * driver maintained by Michel Xhaard <mxhaard@magic.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., 675 Mass Ave, Cambridge, MA 02139, USA. *
- ***************************************************************************/
-
-/*
- NOTE: Sensor controls are disabled for now, becouse changing them while
- streaming sometimes results in out-of-sync video frames. We'll use
- the default initialization, until we know how to stop and start video
- in the chip. However, the image quality still looks good under various
- light conditions.
-*/
-
-#include <linux/delay.h>
-#include "zc0301_sensor.h"
-
-
-static struct zc0301_sensor pas202bcb;
-
-
-static int pas202bcb_init(struct zc0301_device* cam)
-{
- int err = 0;
-
- err += zc0301_write_reg(cam, 0x0002, 0x00);
- err += zc0301_write_reg(cam, 0x0003, 0x02);
- err += zc0301_write_reg(cam, 0x0004, 0x80);
- err += zc0301_write_reg(cam, 0x0005, 0x01);
- err += zc0301_write_reg(cam, 0x0006, 0xE0);
- err += zc0301_write_reg(cam, 0x0098, 0x00);
- err += zc0301_write_reg(cam, 0x009A, 0x03);
- err += zc0301_write_reg(cam, 0x011A, 0x00);
- err += zc0301_write_reg(cam, 0x011C, 0x03);
- err += zc0301_write_reg(cam, 0x009B, 0x01);
- err += zc0301_write_reg(cam, 0x009C, 0xE6);
- err += zc0301_write_reg(cam, 0x009D, 0x02);
- err += zc0301_write_reg(cam, 0x009E, 0x86);
-
- err += zc0301_i2c_write(cam, 0x02, 0x02);
- err += zc0301_i2c_write(cam, 0x0A, 0x01);
- err += zc0301_i2c_write(cam, 0x0B, 0x01);
- err += zc0301_i2c_write(cam, 0x0D, 0x00);
- err += zc0301_i2c_write(cam, 0x12, 0x05);
- err += zc0301_i2c_write(cam, 0x13, 0x63);
- err += zc0301_i2c_write(cam, 0x15, 0x70);
-
- err += zc0301_write_reg(cam, 0x0101, 0xB7);
- err += zc0301_write_reg(cam, 0x0100, 0x0D);
- err += zc0301_write_reg(cam, 0x0189, 0x06);
- err += zc0301_write_reg(cam, 0x01AD, 0x00);
- err += zc0301_write_reg(cam, 0x01C5, 0x03);
- err += zc0301_write_reg(cam, 0x01CB, 0x13);
- err += zc0301_write_reg(cam, 0x0250, 0x08);
- err += zc0301_write_reg(cam, 0x0301, 0x08);
- err += zc0301_write_reg(cam, 0x018D, 0x70);
- err += zc0301_write_reg(cam, 0x0008, 0x03);
- err += zc0301_write_reg(cam, 0x01C6, 0x04);
- err += zc0301_write_reg(cam, 0x01CB, 0x07);
- err += zc0301_write_reg(cam, 0x0120, 0x11);
- err += zc0301_write_reg(cam, 0x0121, 0x37);
- err += zc0301_write_reg(cam, 0x0122, 0x58);
- err += zc0301_write_reg(cam, 0x0123, 0x79);
- err += zc0301_write_reg(cam, 0x0124, 0x91);
- err += zc0301_write_reg(cam, 0x0125, 0xA6);
- err += zc0301_write_reg(cam, 0x0126, 0xB8);
- err += zc0301_write_reg(cam, 0x0127, 0xC7);
- err += zc0301_write_reg(cam, 0x0128, 0xD3);
- err += zc0301_write_reg(cam, 0x0129, 0xDE);
- err += zc0301_write_reg(cam, 0x012A, 0xE6);
- err += zc0301_write_reg(cam, 0x012B, 0xED);
- err += zc0301_write_reg(cam, 0x012C, 0xF3);
- err += zc0301_write_reg(cam, 0x012D, 0xF8);
- err += zc0301_write_reg(cam, 0x012E, 0xFB);
- err += zc0301_write_reg(cam, 0x012F, 0xFF);
- err += zc0301_write_reg(cam, 0x0130, 0x26);
- err += zc0301_write_reg(cam, 0x0131, 0x23);
- err += zc0301_write_reg(cam, 0x0132, 0x20);
- err += zc0301_write_reg(cam, 0x0133, 0x1C);
- err += zc0301_write_reg(cam, 0x0134, 0x16);
- err += zc0301_write_reg(cam, 0x0135, 0x13);
- err += zc0301_write_reg(cam, 0x0136, 0x10);
- err += zc0301_write_reg(cam, 0x0137, 0x0D);
- err += zc0301_write_reg(cam, 0x0138, 0x0B);
- err += zc0301_write_reg(cam, 0x0139, 0x09);
- err += zc0301_write_reg(cam, 0x013A, 0x07);
- err += zc0301_write_reg(cam, 0x013B, 0x06);
- err += zc0301_write_reg(cam, 0x013C, 0x05);
- err += zc0301_write_reg(cam, 0x013D, 0x04);
- err += zc0301_write_reg(cam, 0x013E, 0x03);
- err += zc0301_write_reg(cam, 0x013F, 0x02);
- err += zc0301_write_reg(cam, 0x010A, 0x4C);
- err += zc0301_write_reg(cam, 0x010B, 0xF5);
- err += zc0301_write_reg(cam, 0x010C, 0xFF);
- err += zc0301_write_reg(cam, 0x010D, 0xF9);
- err += zc0301_write_reg(cam, 0x010E, 0x51);
- err += zc0301_write_reg(cam, 0x010F, 0xF5);
- err += zc0301_write_reg(cam, 0x0110, 0xFB);
- err += zc0301_write_reg(cam, 0x0111, 0xED);
- err += zc0301_write_reg(cam, 0x0112, 0x5F);
- err += zc0301_write_reg(cam, 0x0180, 0x00);
- err += zc0301_write_reg(cam, 0x0019, 0x00);
- err += zc0301_write_reg(cam, 0x0087, 0x20);
- err += zc0301_write_reg(cam, 0x0088, 0x21);
-
- err += zc0301_i2c_write(cam, 0x20, 0x02);
- err += zc0301_i2c_write(cam, 0x21, 0x1B);
- err += zc0301_i2c_write(cam, 0x03, 0x44);
- err += zc0301_i2c_write(cam, 0x0E, 0x01);
- err += zc0301_i2c_write(cam, 0x0F, 0x00);
-
- err += zc0301_write_reg(cam, 0x01A9, 0x14);
- err += zc0301_write_reg(cam, 0x01AA, 0x24);
- err += zc0301_write_reg(cam, 0x0190, 0x00);
- err += zc0301_write_reg(cam, 0x0191, 0x02);
- err += zc0301_write_reg(cam, 0x0192, 0x1B);
- err += zc0301_write_reg(cam, 0x0195, 0x00);
- err += zc0301_write_reg(cam, 0x0196, 0x00);
- err += zc0301_write_reg(cam, 0x0197, 0x4D);
- err += zc0301_write_reg(cam, 0x018C, 0x10);
- err += zc0301_write_reg(cam, 0x018F, 0x20);
- err += zc0301_write_reg(cam, 0x001D, 0x44);
- err += zc0301_write_reg(cam, 0x001E, 0x6F);
- err += zc0301_write_reg(cam, 0x001F, 0xAD);
- err += zc0301_write_reg(cam, 0x0020, 0xEB);
- err += zc0301_write_reg(cam, 0x0087, 0x0F);
- err += zc0301_write_reg(cam, 0x0088, 0x0E);
- err += zc0301_write_reg(cam, 0x0180, 0x40);
- err += zc0301_write_reg(cam, 0x0192, 0x1B);
- err += zc0301_write_reg(cam, 0x0191, 0x02);
- err += zc0301_write_reg(cam, 0x0190, 0x00);
- err += zc0301_write_reg(cam, 0x0116, 0x1D);
- err += zc0301_write_reg(cam, 0x0117, 0x40);
- err += zc0301_write_reg(cam, 0x0118, 0x99);
- err += zc0301_write_reg(cam, 0x0180, 0x42);
- err += zc0301_write_reg(cam, 0x0116, 0x1D);
- err += zc0301_write_reg(cam, 0x0117, 0x40);
- err += zc0301_write_reg(cam, 0x0118, 0x99);
- err += zc0301_write_reg(cam, 0x0007, 0x00);
-
- err += zc0301_i2c_write(cam, 0x11, 0x01);
-
- msleep(100);
-
- return err;
-}
-
-
-static int pas202bcb_get_ctrl(struct zc0301_device* cam,
- struct v4l2_control* ctrl)
-{
- switch (ctrl->id) {
- case V4L2_CID_EXPOSURE:
- {
- int r1 = zc0301_i2c_read(cam, 0x04, 1),
- r2 = zc0301_i2c_read(cam, 0x05, 1);
- if (r1 < 0 || r2 < 0)
- return -EIO;
- ctrl->value = (r1 << 6) | (r2 & 0x3f);
- }
- return 0;
- case V4L2_CID_RED_BALANCE:
- if ((ctrl->value = zc0301_i2c_read(cam, 0x09, 1)) < 0)
- return -EIO;
- ctrl->value &= 0x0f;
- return 0;
- case V4L2_CID_BLUE_BALANCE:
- if ((ctrl->value = zc0301_i2c_read(cam, 0x07, 1)) < 0)
- return -EIO;
- ctrl->value &= 0x0f;
- return 0;
- case V4L2_CID_GAIN:
- if ((ctrl->value = zc0301_i2c_read(cam, 0x10, 1)) < 0)
- return -EIO;
- ctrl->value &= 0x1f;
- return 0;
- case ZC0301_V4L2_CID_GREEN_BALANCE:
- if ((ctrl->value = zc0301_i2c_read(cam, 0x08, 1)) < 0)
- return -EIO;
- ctrl->value &= 0x0f;
- return 0;
- case ZC0301_V4L2_CID_DAC_MAGNITUDE:
- if ((ctrl->value = zc0301_i2c_read(cam, 0x0c, 1)) < 0)
- return -EIO;
- return 0;
- default:
- return -EINVAL;
- }
-}
-
-
-static int pas202bcb_set_ctrl(struct zc0301_device* cam,
- const struct v4l2_control* ctrl)
-{
- int err = 0;
-
- switch (ctrl->id) {
- case V4L2_CID_EXPOSURE:
- err += zc0301_i2c_write(cam, 0x04, ctrl->value >> 6);
- err += zc0301_i2c_write(cam, 0x05, ctrl->value & 0x3f);
- break;
- case V4L2_CID_RED_BALANCE:
- err += zc0301_i2c_write(cam, 0x09, ctrl->value);
- break;
- case V4L2_CID_BLUE_BALANCE:
- err += zc0301_i2c_write(cam, 0x07, ctrl->value);
- break;
- case V4L2_CID_GAIN:
- err += zc0301_i2c_write(cam, 0x10, ctrl->value);
- break;
- case ZC0301_V4L2_CID_GREEN_BALANCE:
- err += zc0301_i2c_write(cam, 0x08, ctrl->value);
- break;
- case ZC0301_V4L2_CID_DAC_MAGNITUDE:
- err += zc0301_i2c_write(cam, 0x0c, ctrl->value);
- break;
- default:
- return -EINVAL;
- }
- err += zc0301_i2c_write(cam, 0x11, 0x01);
-
- return err ? -EIO : 0;
-}
-
-
-static struct zc0301_sensor pas202bcb = {
- .name = "PAS202BCB",
- .init = &pas202bcb_init,
- .qctrl = {
- {
- .id = V4L2_CID_EXPOSURE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "exposure",
- .minimum = 0x01e5,
- .maximum = 0x3fff,
- .step = 0x0001,
- .default_value = 0x01e5,
- .flags = V4L2_CTRL_FLAG_DISABLED,
- },
- {
- .id = V4L2_CID_GAIN,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "global gain",
- .minimum = 0x00,
- .maximum = 0x1f,
- .step = 0x01,
- .default_value = 0x0c,
- .flags = V4L2_CTRL_FLAG_DISABLED,
- },
- {
- .id = ZC0301_V4L2_CID_DAC_MAGNITUDE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "DAC magnitude",
- .minimum = 0x00,
- .maximum = 0xff,
- .step = 0x01,
- .default_value = 0x00,
- .flags = V4L2_CTRL_FLAG_DISABLED,
- },
- {
- .id = V4L2_CID_RED_BALANCE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "red balance",
- .minimum = 0x00,
- .maximum = 0x0f,
- .step = 0x01,
- .default_value = 0x01,
- .flags = V4L2_CTRL_FLAG_DISABLED,
- },
- {
- .id = V4L2_CID_BLUE_BALANCE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "blue balance",
- .minimum = 0x00,
- .maximum = 0x0f,
- .step = 0x01,
- .default_value = 0x05,
- .flags = V4L2_CTRL_FLAG_DISABLED,
- },
- {
- .id = ZC0301_V4L2_CID_GREEN_BALANCE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "green balance",
- .minimum = 0x00,
- .maximum = 0x0f,
- .step = 0x01,
- .default_value = 0x00,
- .flags = V4L2_CTRL_FLAG_DISABLED,
- },
- },
- .get_ctrl = &pas202bcb_get_ctrl,
- .set_ctrl = &pas202bcb_set_ctrl,
- .cropcap = {
- .bounds = {
- .left = 0,
- .top = 0,
- .width = 640,
- .height = 480,
- },
- .defrect = {
- .left = 0,
- .top = 0,
- .width = 640,
- .height = 480,
- },
- },
- .pix_format = {
- .width = 640,
- .height = 480,
- .pixelformat = V4L2_PIX_FMT_JPEG,
- .priv = 8,
- .colorspace = V4L2_COLORSPACE_JPEG,
- },
-};
-
-
-int zc0301_probe_pas202bcb(struct zc0301_device* cam)
-{
- int r0 = 0, r1 = 0, err = 0;
- unsigned int pid = 0;
-
- err += zc0301_write_reg(cam, 0x0000, 0x01);
- err += zc0301_write_reg(cam, 0x0010, 0x0e);
- err += zc0301_write_reg(cam, 0x0001, 0x01);
- err += zc0301_write_reg(cam, 0x0012, 0x03);
- err += zc0301_write_reg(cam, 0x0012, 0x01);
- err += zc0301_write_reg(cam, 0x008d, 0x08);
-
- msleep(10);
-
- r0 = zc0301_i2c_read(cam, 0x00, 1);
- r1 = zc0301_i2c_read(cam, 0x01, 1);
-
- if (r0 < 0 || r1 < 0 || err)
- return -EIO;
-
- pid = (r0 << 4) | ((r1 & 0xf0) >> 4);
- if (pid != 0x017)
- return -ENODEV;
-
- zc0301_attach_sensor(cam, &pas202bcb);
-
- return 0;
-}
diff --git a/drivers/media/video/zc0301/zc0301_pb0330.c b/drivers/media/video/zc0301/zc0301_pb0330.c
deleted file mode 100644
index 9519aba3612..00000000000
--- a/drivers/media/video/zc0301/zc0301_pb0330.c
+++ /dev/null
@@ -1,188 +0,0 @@
-/***************************************************************************
- * Plug-in for PB-0330 image sensor connected to the ZC0301P Image *
- * Processor and Control Chip *
- * *
- * Copyright (C) 2006-2007 by Luca Risolia <luca.risolia@studio.unibo.it> *
- * *
- * Initialization values of the ZC0301[P] have been taken from the SPCA5XX *
- * driver maintained by Michel Xhaard <mxhaard@magic.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., 675 Mass Ave, Cambridge, MA 02139, USA. *
- ***************************************************************************/
-
-#include <linux/delay.h>
-#include "zc0301_sensor.h"
-
-
-static struct zc0301_sensor pb0330;
-
-
-static int pb0330_init(struct zc0301_device* cam)
-{
- int err = 0;
-
- err += zc0301_write_reg(cam, 0x0000, 0x01);
- err += zc0301_write_reg(cam, 0x0008, 0x03);
- err += zc0301_write_reg(cam, 0x0010, 0x0A);
- err += zc0301_write_reg(cam, 0x0002, 0x00);
- err += zc0301_write_reg(cam, 0x0003, 0x02);
- err += zc0301_write_reg(cam, 0x0004, 0x80);
- err += zc0301_write_reg(cam, 0x0005, 0x01);
- err += zc0301_write_reg(cam, 0x0006, 0xE0);
- err += zc0301_write_reg(cam, 0x0001, 0x01);
- err += zc0301_write_reg(cam, 0x0012, 0x05);
- err += zc0301_write_reg(cam, 0x0012, 0x07);
- err += zc0301_write_reg(cam, 0x0098, 0x00);
- err += zc0301_write_reg(cam, 0x009A, 0x00);
- err += zc0301_write_reg(cam, 0x011A, 0x00);
- err += zc0301_write_reg(cam, 0x011C, 0x00);
- err += zc0301_write_reg(cam, 0x0012, 0x05);
-
- err += zc0301_i2c_write(cam, 0x01, 0x0006);
- err += zc0301_i2c_write(cam, 0x02, 0x0011);
- err += zc0301_i2c_write(cam, 0x03, 0x01E7);
- err += zc0301_i2c_write(cam, 0x04, 0x0287);
- err += zc0301_i2c_write(cam, 0x06, 0x0003);
- err += zc0301_i2c_write(cam, 0x07, 0x3002);
- err += zc0301_i2c_write(cam, 0x20, 0x1100);
- err += zc0301_i2c_write(cam, 0x2F, 0xF7B0);
- err += zc0301_i2c_write(cam, 0x30, 0x0005);
- err += zc0301_i2c_write(cam, 0x31, 0x0000);
- err += zc0301_i2c_write(cam, 0x34, 0x0100);
- err += zc0301_i2c_write(cam, 0x35, 0x0060);
- err += zc0301_i2c_write(cam, 0x3D, 0x068F);
- err += zc0301_i2c_write(cam, 0x40, 0x01E0);
- err += zc0301_i2c_write(cam, 0x58, 0x0078);
- err += zc0301_i2c_write(cam, 0x62, 0x0411);
-
- err += zc0301_write_reg(cam, 0x0087, 0x10);
- err += zc0301_write_reg(cam, 0x0101, 0x37);
- err += zc0301_write_reg(cam, 0x0012, 0x05);
- err += zc0301_write_reg(cam, 0x0100, 0x0D);
- err += zc0301_write_reg(cam, 0x0189, 0x06);
- err += zc0301_write_reg(cam, 0x01AD, 0x00);
- err += zc0301_write_reg(cam, 0x01C5, 0x03);
- err += zc0301_write_reg(cam, 0x01CB, 0x13);
- err += zc0301_write_reg(cam, 0x0250, 0x08);
- err += zc0301_write_reg(cam, 0x0301, 0x08);
- err += zc0301_write_reg(cam, 0x01A8, 0x60);
- err += zc0301_write_reg(cam, 0x018D, 0x6C);
- err += zc0301_write_reg(cam, 0x01AD, 0x09);
- err += zc0301_write_reg(cam, 0x01AE, 0x15);
- err += zc0301_write_reg(cam, 0x010A, 0x50);
- err += zc0301_write_reg(cam, 0x010B, 0xF8);
- err += zc0301_write_reg(cam, 0x010C, 0xF8);
- err += zc0301_write_reg(cam, 0x010D, 0xF8);
- err += zc0301_write_reg(cam, 0x010E, 0x50);
- err += zc0301_write_reg(cam, 0x010F, 0xF8);
- err += zc0301_write_reg(cam, 0x0110, 0xF8);
- err += zc0301_write_reg(cam, 0x0111, 0xF8);
- err += zc0301_write_reg(cam, 0x0112, 0x50);
- err += zc0301_write_reg(cam, 0x0008, 0x03);
- err += zc0301_write_reg(cam, 0x01C6, 0x08);
- err += zc0301_write_reg(cam, 0x01CB, 0x0F);
- err += zc0301_write_reg(cam, 0x010A, 0x50);
- err += zc0301_write_reg(cam, 0x010B, 0xF8);
- err += zc0301_write_reg(cam, 0x010C, 0xF8);
- err += zc0301_write_reg(cam, 0x010D, 0xF8);
- err += zc0301_write_reg(cam, 0x010E, 0x50);
- err += zc0301_write_reg(cam, 0x010F, 0xF8);
- err += zc0301_write_reg(cam, 0x0110, 0xF8);
- err += zc0301_write_reg(cam, 0x0111, 0xF8);
- err += zc0301_write_reg(cam, 0x0112, 0x50);
- err += zc0301_write_reg(cam, 0x0180, 0x00);
- err += zc0301_write_reg(cam, 0x0019, 0x00);
-
- err += zc0301_i2c_write(cam, 0x05, 0x0066);
- err += zc0301_i2c_write(cam, 0x09, 0x02B2);
- err += zc0301_i2c_write(cam, 0x10, 0x0002);
-
- err += zc0301_write_reg(cam, 0x011D, 0x60);
- err += zc0301_write_reg(cam, 0x0190, 0x00);
- err += zc0301_write_reg(cam, 0x0191, 0x07);
- err += zc0301_write_reg(cam, 0x0192, 0x8C);
- err += zc0301_write_reg(cam, 0x0195, 0x00);
- err += zc0301_write_reg(cam, 0x0196, 0x00);
- err += zc0301_write_reg(cam, 0x0197, 0x8A);
- err += zc0301_write_reg(cam, 0x018C, 0x10);
- err += zc0301_write_reg(cam, 0x018F, 0x20);
- err += zc0301_write_reg(cam, 0x01A9, 0x14);
- err += zc0301_write_reg(cam, 0x01AA, 0x24);
- err += zc0301_write_reg(cam, 0x001D, 0xD7);
- err += zc0301_write_reg(cam, 0x001E, 0xF0);
- err += zc0301_write_reg(cam, 0x001F, 0xF8);
- err += zc0301_write_reg(cam, 0x0020, 0xFF);
- err += zc0301_write_reg(cam, 0x01AD, 0x09);
- err += zc0301_write_reg(cam, 0x01AE, 0x15);
- err += zc0301_write_reg(cam, 0x0180, 0x40);
- err += zc0301_write_reg(cam, 0x0180, 0x42);
-
- msleep(100);
-
- return err;
-}
-
-
-static struct zc0301_sensor pb0330 = {
- .name = "PB-0330",
- .init = &pb0330_init,
- .cropcap = {
- .bounds = {
- .left = 0,
- .top = 0,
- .width = 640,
- .height = 480,
- },
- .defrect = {
- .left = 0,
- .top = 0,
- .width = 640,
- .height = 480,
- },
- },
- .pix_format = {
- .width = 640,
- .height = 480,
- .pixelformat = V4L2_PIX_FMT_JPEG,
- .priv = 8,
- .colorspace = V4L2_COLORSPACE_JPEG,
- },
-};
-
-
-int zc0301_probe_pb0330(struct zc0301_device* cam)
-{
- int r0, err = 0;
-
- err += zc0301_write_reg(cam, 0x0000, 0x01);
- err += zc0301_write_reg(cam, 0x0010, 0x0a);
- err += zc0301_write_reg(cam, 0x0001, 0x01);
- err += zc0301_write_reg(cam, 0x0012, 0x03);
- err += zc0301_write_reg(cam, 0x0012, 0x01);
-
- msleep(10);
-
- r0 = zc0301_i2c_read(cam, 0x00, 2);
-
- if (r0 < 0 || err)
- return -EIO;
-
- if (r0 != 0x8243)
- return -ENODEV;
-
- zc0301_attach_sensor(cam, &pb0330);
-
- return 0;
-}
diff --git a/drivers/media/video/zc0301/zc0301_sensor.h b/drivers/media/video/zc0301/zc0301_sensor.h
deleted file mode 100644
index 0be783c203f..00000000000
--- a/drivers/media/video/zc0301/zc0301_sensor.h
+++ /dev/null
@@ -1,107 +0,0 @@
-/***************************************************************************
- * API for image sensors connected to the ZC0301[P] Image Processor and *
- * Control Chip *
- * *
- * Copyright (C) 2006-2007 by Luca Risolia <luca.risolia@studio.unibo.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. *
- ***************************************************************************/
-
-#ifndef _ZC0301_SENSOR_H_
-#define _ZC0301_SENSOR_H_
-
-#include <linux/usb.h>
-#include <linux/videodev2.h>
-#include <linux/device.h>
-#include <linux/stddef.h>
-#include <linux/errno.h>
-#include <asm/types.h>
-
-struct zc0301_device;
-struct zc0301_sensor;
-
-/*****************************************************************************/
-
-extern int zc0301_probe_pas202bcb(struct zc0301_device* cam);
-extern int zc0301_probe_pb0330(struct zc0301_device* cam);
-
-#define ZC0301_SENSOR_TABLE \
-/* Weak detections must go at the end of the list */ \
-static int (*zc0301_sensor_table[])(struct zc0301_device*) = { \
- &zc0301_probe_pas202bcb, \
- &zc0301_probe_pb0330, \
- NULL, \
-};
-
-extern struct zc0301_device*
-zc0301_match_id(struct zc0301_device* cam, const struct usb_device_id *id);
-
-extern void
-zc0301_attach_sensor(struct zc0301_device* cam, struct zc0301_sensor* sensor);
-
-#define ZC0301_USB_DEVICE(vend, prod, intclass) \
- .match_flags = USB_DEVICE_ID_MATCH_DEVICE | \
- USB_DEVICE_ID_MATCH_INT_CLASS, \
- .idVendor = (vend), \
- .idProduct = (prod), \
- .bInterfaceClass = (intclass)
-
-#if !defined CONFIG_USB_GSPCA_ZC3XX && !defined CONFIG_USB_GSPCA_ZC3XX_MODULE
-#define ZC0301_ID_TABLE \
-static const struct usb_device_id zc0301_id_table[] = { \
- { ZC0301_USB_DEVICE(0x046d, 0x08ae, 0xff), }, /* PAS202 */ \
- { ZC0301_USB_DEVICE(0x0ac8, 0x303b, 0xff), }, /* PB-0330 */ \
- { } \
-};
-#else
-#define ZC0301_ID_TABLE \
-static const struct usb_device_id zc0301_id_table[] = { \
- { ZC0301_USB_DEVICE(0x046d, 0x08ae, 0xff), }, /* PAS202 */ \
- { } \
-};
-#endif
-
-/*****************************************************************************/
-
-extern int zc0301_write_reg(struct zc0301_device*, u16 index, u16 value);
-extern int zc0301_read_reg(struct zc0301_device*, u16 index);
-extern int zc0301_i2c_write(struct zc0301_device*, u16 address, u16 value);
-extern int zc0301_i2c_read(struct zc0301_device*, u16 address, u8 length);
-
-/*****************************************************************************/
-
-#define ZC0301_MAX_CTRLS (V4L2_CID_LASTP1 - V4L2_CID_BASE + 10)
-#define ZC0301_V4L2_CID_DAC_MAGNITUDE (V4L2_CID_PRIVATE_BASE + 0)
-#define ZC0301_V4L2_CID_GREEN_BALANCE (V4L2_CID_PRIVATE_BASE + 1)
-
-struct zc0301_sensor {
- char name[32];
-
- struct v4l2_queryctrl qctrl[ZC0301_MAX_CTRLS];
- struct v4l2_cropcap cropcap;
- struct v4l2_pix_format pix_format;
-
- int (*init)(struct zc0301_device*);
- int (*get_ctrl)(struct zc0301_device*, struct v4l2_control* ctrl);
- int (*set_ctrl)(struct zc0301_device*,
- const struct v4l2_control* ctrl);
- int (*set_crop)(struct zc0301_device*, const struct v4l2_rect* rect);
-
- /* Private */
- struct v4l2_queryctrl _qctrl[ZC0301_MAX_CTRLS];
- struct v4l2_rect _rect;
-};
-
-#endif /* _ZC0301_SENSOR_H_ */
diff --git a/drivers/media/video/zoran/videocodec.c b/drivers/media/video/zoran/videocodec.c
index cf24956f320..c0107163529 100644
--- a/drivers/media/video/zoran/videocodec.c
+++ b/drivers/media/video/zoran/videocodec.c
@@ -107,15 +107,14 @@ videocodec_attach (struct videocodec_master *master)
if (!try_module_get(h->codec->owner))
return NULL;
- codec =
- kmalloc(sizeof(struct videocodec), GFP_KERNEL);
+ codec = kmemdup(h->codec, sizeof(struct videocodec),
+ GFP_KERNEL);
if (!codec) {
dprintk(1,
KERN_ERR
"videocodec_attach: no mem\n");
goto out_module_put;
}
- memcpy(codec, h->codec, sizeof(struct videocodec));
snprintf(codec->name, sizeof(codec->name),
"%s[%d]", codec->name, h->attached);
diff --git a/drivers/media/video/zoran/zoran.h b/drivers/media/video/zoran/zoran.h
index 8997add1248..307e847fe1c 100644
--- a/drivers/media/video/zoran/zoran.h
+++ b/drivers/media/video/zoran/zoran.h
@@ -391,7 +391,7 @@ struct zoran {
struct mutex resource_lock; /* prevent evil stuff */
- u8 initialized; /* flag if zoran has been correctly initalized */
+ u8 initialized; /* flag if zoran has been correctly initialized */
int user; /* number of current users */
struct card_info card;
struct tvnorm *timing;
diff --git a/drivers/media/video/zoran/zoran_device.c b/drivers/media/video/zoran/zoran_device.c
index e6ad4b20561..6f846abee3e 100644
--- a/drivers/media/video/zoran/zoran_device.c
+++ b/drivers/media/video/zoran/zoran_device.c
@@ -484,7 +484,7 @@ zr36057_overlay (struct zoran *zr,
zr->overlay_settings.format);
/* Start and length of each line MUST be 4-byte aligned.
- * This should be allready checked before the call to this routine.
+ * This should be already checked before the call to this routine.
* All error messages are internal driver checking only! */
/* video display top and bottom registers */
diff --git a/drivers/media/video/zoran/zr36050.c b/drivers/media/video/zoran/zr36050.c
index 639dd87c663..e1985609af4 100644
--- a/drivers/media/video/zoran/zr36050.c
+++ b/drivers/media/video/zoran/zr36050.c
@@ -236,7 +236,7 @@ zr36050_pushit (struct zr36050 *ptr,
Could be variable, but until it's not needed it they are just fixed to save
memory. Otherwise expand zr36050 structure with arrays, push the values to
- it and initalize from there, as e.g. the linux zr36057/60 driver does it.
+ it and initialize from there, as e.g. the linux zr36057/60 driver does it.
========================================================================= */
static const char zr36050_dqt[0x86] = {
diff --git a/drivers/media/video/zoran/zr36060.c b/drivers/media/video/zoran/zr36060.c
index 008746ff774..5e4f57cbf31 100644
--- a/drivers/media/video/zoran/zr36060.c
+++ b/drivers/media/video/zoran/zr36060.c
@@ -227,7 +227,7 @@ zr36060_pushit (struct zr36060 *ptr,
Could be variable, but until it's not needed it they are just fixed to save
memory. Otherwise expand zr36060 structure with arrays, push the values to
- it and initalize from there, as e.g. the linux zr36057/60 driver does it.
+ it and initialize from there, as e.g. the linux zr36057/60 driver does it.
========================================================================= */
static const char zr36060_dqt[0x86] = {
diff --git a/drivers/message/fusion/mptbase.c b/drivers/message/fusion/mptbase.c
index a6a57011ba6..b88a244a1ed 100644
--- a/drivers/message/fusion/mptbase.c
+++ b/drivers/message/fusion/mptbase.c
@@ -115,6 +115,7 @@ MODULE_PARM_DESC(mpt_fwfault_debug, "Enable detection of Firmware fault"
" and halt Firmware on fault - (default=0)");
+static char MptCallbacksName[MPT_MAX_PROTOCOL_DRIVERS][50];
#ifdef MFCNT
static int mfcounter = 0;
@@ -213,7 +214,7 @@ static int ProcessEventNotification(MPT_ADAPTER *ioc,
static void mpt_iocstatus_info(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf);
static void mpt_fc_log_info(MPT_ADAPTER *ioc, u32 log_info);
static void mpt_spi_log_info(MPT_ADAPTER *ioc, u32 log_info);
-static void mpt_sas_log_info(MPT_ADAPTER *ioc, u32 log_info);
+static void mpt_sas_log_info(MPT_ADAPTER *ioc, u32 log_info , u8 cb_idx);
static int mpt_read_ioc_pg_3(MPT_ADAPTER *ioc);
static void mpt_inactive_raid_list_free(MPT_ADAPTER *ioc);
@@ -490,7 +491,7 @@ mpt_reply(MPT_ADAPTER *ioc, u32 pa)
else if (ioc->bus_type == SPI)
mpt_spi_log_info(ioc, log_info);
else if (ioc->bus_type == SAS)
- mpt_sas_log_info(ioc, log_info);
+ mpt_sas_log_info(ioc, log_info, cb_idx);
}
if (ioc_stat & MPI_IOCSTATUS_MASK)
@@ -644,7 +645,7 @@ mptbase_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req, MPT_FRAME_HDR *reply)
* considered an error by the caller.
*/
u8
-mpt_register(MPT_CALLBACK cbfunc, MPT_DRIVER_CLASS dclass)
+mpt_register(MPT_CALLBACK cbfunc, MPT_DRIVER_CLASS dclass, char *func_name)
{
u8 cb_idx;
last_drv_idx = MPT_MAX_PROTOCOL_DRIVERS;
@@ -659,6 +660,8 @@ mpt_register(MPT_CALLBACK cbfunc, MPT_DRIVER_CLASS dclass)
MptDriverClass[cb_idx] = dclass;
MptEvHandlers[cb_idx] = NULL;
last_drv_idx = cb_idx;
+ memcpy(MptCallbacksName[cb_idx], func_name,
+ strlen(func_name) > 50 ? 50 : strlen(func_name));
break;
}
}
@@ -1632,6 +1635,7 @@ mpt_mapresources(MPT_ADAPTER *ioc)
} else {
printk(MYIOC_s_WARN_FMT "no suitable DMA mask for %s\n",
ioc->name, pci_name(pdev));
+ pci_release_selected_regions(pdev, ioc->bars);
return r;
}
} else {
@@ -1645,6 +1649,7 @@ mpt_mapresources(MPT_ADAPTER *ioc)
} else {
printk(MYIOC_s_WARN_FMT "no suitable DMA mask for %s\n",
ioc->name, pci_name(pdev));
+ pci_release_selected_regions(pdev, ioc->bars);
return r;
}
}
@@ -1675,6 +1680,7 @@ mpt_mapresources(MPT_ADAPTER *ioc)
if (mem == NULL) {
printk(MYIOC_s_ERR_FMT ": ERROR - Unable to map adapter"
" memory!\n", ioc->name);
+ pci_release_selected_regions(pdev, ioc->bars);
return -EINVAL;
}
ioc->memmap = mem;
@@ -1770,7 +1776,6 @@ mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id)
ioc->req_sz = MPT_DEFAULT_FRAME_SIZE; /* avoid div by zero! */
ioc->reply_sz = MPT_REPLY_FRAME_SIZE;
- ioc->pcidev = pdev;
spin_lock_init(&ioc->taskmgmt_lock);
mutex_init(&ioc->internal_cmds.mutex);
@@ -1794,7 +1799,7 @@ mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id)
ioc->sh = NULL;
ioc->cached_fw = NULL;
- /* Initilize SCSI Config Data structure
+ /* Initialize SCSI Config Data structure
*/
memset(&ioc->spi_data, 0, sizeof(SpiCfgData));
@@ -1913,6 +1918,9 @@ mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id)
ioc->msi_enable = 0;
break;
}
+
+ ioc->fw_events_off = 1;
+
if (ioc->errata_flag_1064)
pci_disable_io_access(pdev);
@@ -2051,7 +2059,6 @@ mpt_detach(struct pci_dev *pdev)
mpt_adapter_dispose(ioc);
- pci_set_drvdata(pdev, NULL);
}
/**************************************************************************
@@ -2471,7 +2478,7 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP)) {
/*
- * Initalize link list for inactive raid volumes.
+ * Initialize link list for inactive raid volumes.
*/
mutex_init(&ioc->raid_data.inactive_list_mutex);
INIT_LIST_HEAD(&ioc->raid_data.inactive_list);
@@ -5062,8 +5069,9 @@ mptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode)
if (ioc->mptbase_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET)
goto out;
if (!timeleft) {
- printk(KERN_DEBUG "%s: Issuing Reset from %s!!\n",
- ioc->name, __func__);
+ printk(MYIOC_s_WARN_FMT
+ "Issuing Reset from %s!!, doorbell=0x%08x\n",
+ ioc->name, __func__, mpt_GetIocState(ioc, 0));
mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP);
mpt_free_msg_frame(ioc, mf);
}
@@ -6454,8 +6462,9 @@ out:
mutex_unlock(&ioc->mptbase_cmds.mutex);
if (issue_hard_reset) {
issue_hard_reset = 0;
- printk(MYIOC_s_WARN_FMT "Issuing Reset from %s!!\n",
- ioc->name, __func__);
+ printk(MYIOC_s_WARN_FMT
+ "Issuing Reset from %s!!, doorbell=0x%08x\n",
+ ioc->name, __func__, mpt_GetIocState(ioc, 0));
if (retry_count == 0) {
if (mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP) != 0)
retry_count++;
@@ -6971,6 +6980,7 @@ mpt_SoftResetHandler(MPT_ADAPTER *ioc, int sleepFlag)
spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
if (ioc->taskmgmt_in_progress) {
+ ioc->ioc_reset_in_progress = 0;
spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
return -1;
}
@@ -7144,7 +7154,8 @@ mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag)
rc = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_RECOVER, sleepFlag);
if (rc != 0) {
printk(KERN_WARNING MYNAM
- ": WARNING - (%d) Cannot recover %s\n", rc, ioc->name);
+ ": WARNING - (%d) Cannot recover %s, doorbell=0x%08x\n",
+ rc, ioc->name, mpt_GetIocState(ioc, 0));
} else {
if (ioc->hard_resets < -1)
ioc->hard_resets++;
@@ -7997,7 +8008,7 @@ mpt_spi_log_info(MPT_ADAPTER *ioc, u32 log_info)
* Refer to lsi/mpi_log_sas.h.
**/
static void
-mpt_sas_log_info(MPT_ADAPTER *ioc, u32 log_info)
+mpt_sas_log_info(MPT_ADAPTER *ioc, u32 log_info, u8 cb_idx)
{
union loginfo_type {
u32 loginfo;
@@ -8051,21 +8062,22 @@ union loginfo_type {
if (sub_code_desc != NULL)
printk(MYIOC_s_INFO_FMT
"LogInfo(0x%08x): Originator={%s}, Code={%s},"
- " SubCode={%s}\n",
+ " SubCode={%s} cb_idx %s\n",
ioc->name, log_info, originator_desc, code_desc,
- sub_code_desc);
+ sub_code_desc, MptCallbacksName[cb_idx]);
else if (code_desc != NULL)
printk(MYIOC_s_INFO_FMT
"LogInfo(0x%08x): Originator={%s}, Code={%s},"
- " SubCode(0x%04x)\n",
+ " SubCode(0x%04x) cb_idx %s\n",
ioc->name, log_info, originator_desc, code_desc,
- sas_loginfo.dw.subcode);
+ sas_loginfo.dw.subcode, MptCallbacksName[cb_idx]);
else
printk(MYIOC_s_INFO_FMT
"LogInfo(0x%08x): Originator={%s}, Code=(0x%02x),"
- " SubCode(0x%04x)\n",
+ " SubCode(0x%04x) cb_idx %s\n",
ioc->name, log_info, originator_desc,
- sas_loginfo.dw.code, sas_loginfo.dw.subcode);
+ sas_loginfo.dw.code, sas_loginfo.dw.subcode,
+ MptCallbacksName[cb_idx]);
}
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
@@ -8430,7 +8442,8 @@ fusion_init(void)
/* Register ourselves (mptbase) in order to facilitate
* EventNotification handling.
*/
- mpt_base_index = mpt_register(mptbase_reply, MPTBASE_DRIVER);
+ mpt_base_index = mpt_register(mptbase_reply, MPTBASE_DRIVER,
+ "mptbase_reply");
/* Register for hard reset handling callbacks.
*/
diff --git a/drivers/message/fusion/mptbase.h b/drivers/message/fusion/mptbase.h
index b613eb3d470..23ed3dec72a 100644
--- a/drivers/message/fusion/mptbase.h
+++ b/drivers/message/fusion/mptbase.h
@@ -76,8 +76,8 @@
#define COPYRIGHT "Copyright (c) 1999-2008 " MODULEAUTHOR
#endif
-#define MPT_LINUX_VERSION_COMMON "3.04.15"
-#define MPT_LINUX_PACKAGE_NAME "@(#)mptlinux-3.04.15"
+#define MPT_LINUX_VERSION_COMMON "3.04.17"
+#define MPT_LINUX_PACKAGE_NAME "@(#)mptlinux-3.04.17"
#define WHAT_MAGIC_STRING "@" "(" "#" ")"
#define show_mptmod_ver(s,ver) \
@@ -396,6 +396,8 @@ typedef struct _VirtTarget {
u8 raidVolume; /* set, if RAID Volume */
u8 type; /* byte 0 of Inquiry data */
u8 deleted; /* target in process of being removed */
+ u8 inDMD; /* currently in the device
+ removal delay timer */
u32 num_luns;
} VirtTarget;
@@ -580,6 +582,7 @@ struct mptfc_rport_info
typedef void (*MPT_ADD_SGE)(void *pAddr, u32 flagslength, dma_addr_t dma_addr);
typedef void (*MPT_ADD_CHAIN)(void *pAddr, u8 next, u16 length,
dma_addr_t dma_addr);
+typedef void (*MPT_SCHEDULE_TARGET_RESET)(void *ioc);
/*
* Adapter Structure - pci_dev specific. Maximum: MPT_MAX_ADAPTERS
@@ -601,7 +604,7 @@ typedef struct _MPT_ADAPTER
u16 nvdata_version_default;
int debug_level;
u8 io_missing_delay;
- u8 device_missing_delay;
+ u16 device_missing_delay;
SYSIF_REGS __iomem *chip; /* == c8817000 (mmap) */
SYSIF_REGS __iomem *pio_chip; /* Programmed IO (downloadboot) */
u8 bus_type;
@@ -738,6 +741,7 @@ typedef struct _MPT_ADAPTER
int taskmgmt_in_progress;
u8 taskmgmt_quiesce_io;
u8 ioc_reset_in_progress;
+ MPT_SCHEDULE_TARGET_RESET schedule_target_reset;
struct work_struct sas_persist_task;
struct work_struct fc_setup_reset_work;
@@ -922,7 +926,8 @@ extern void mpt_detach(struct pci_dev *pdev);
extern int mpt_suspend(struct pci_dev *pdev, pm_message_t state);
extern int mpt_resume(struct pci_dev *pdev);
#endif
-extern u8 mpt_register(MPT_CALLBACK cbfunc, MPT_DRIVER_CLASS dclass);
+extern u8 mpt_register(MPT_CALLBACK cbfunc, MPT_DRIVER_CLASS dclass,
+ char *func_name);
extern void mpt_deregister(u8 cb_idx);
extern int mpt_event_register(u8 cb_idx, MPT_EVHANDLER ev_cbfunc);
extern void mpt_event_deregister(u8 cb_idx);
diff --git a/drivers/message/fusion/mptctl.c b/drivers/message/fusion/mptctl.c
index f06b29193b4..d8ddfdf8be1 100644
--- a/drivers/message/fusion/mptctl.c
+++ b/drivers/message/fusion/mptctl.c
@@ -261,10 +261,16 @@ mptctl_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req, MPT_FRAME_HDR *reply)
/* We are done, issue wake up
*/
if (ioc->ioctl_cmds.status & MPT_MGMT_STATUS_PENDING) {
- if (req->u.hdr.Function == MPI_FUNCTION_SCSI_TASK_MGMT)
+ if (req->u.hdr.Function == MPI_FUNCTION_SCSI_TASK_MGMT) {
mpt_clear_taskmgmt_in_progress_flag(ioc);
- ioc->ioctl_cmds.status &= ~MPT_MGMT_STATUS_PENDING;
- complete(&ioc->ioctl_cmds.done);
+ ioc->ioctl_cmds.status &= ~MPT_MGMT_STATUS_PENDING;
+ complete(&ioc->ioctl_cmds.done);
+ if (ioc->bus_type == SAS)
+ ioc->schedule_target_reset(ioc);
+ } else {
+ ioc->ioctl_cmds.status &= ~MPT_MGMT_STATUS_PENDING;
+ complete(&ioc->ioctl_cmds.done);
+ }
}
out_continuation:
@@ -298,6 +304,8 @@ mptctl_taskmgmt_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
mpt_clear_taskmgmt_in_progress_flag(ioc);
ioc->taskmgmt_cmds.status &= ~MPT_MGMT_STATUS_PENDING;
complete(&ioc->taskmgmt_cmds.done);
+ if (ioc->bus_type == SAS)
+ ioc->schedule_target_reset(ioc);
return 1;
}
return 0;
@@ -946,9 +954,12 @@ retry_wait:
mpt_free_msg_frame(iocp, mf);
goto fwdl_out;
}
- if (!timeleft)
+ if (!timeleft) {
+ printk(MYIOC_s_WARN_FMT
+ "FW download timeout, doorbell=0x%08x\n",
+ iocp->name, mpt_GetIocState(iocp, 0));
mptctl_timeout_expired(iocp, mf);
- else
+ } else
goto retry_wait;
goto fwdl_out;
}
@@ -2293,6 +2304,10 @@ retry_wait:
goto done_free_mem;
}
if (!timeleft) {
+ printk(MYIOC_s_WARN_FMT
+ "mpt cmd timeout, doorbell=0x%08x"
+ " function=0x%x\n",
+ ioc->name, mpt_GetIocState(ioc, 0), function);
if (function == MPI_FUNCTION_SCSI_TASK_MGMT)
mutex_unlock(&ioc->taskmgmt_cmds.mutex);
mptctl_timeout_expired(ioc, mf);
@@ -2600,9 +2615,12 @@ retry_wait:
mpt_free_msg_frame(ioc, mf);
goto out;
}
- if (!timeleft)
+ if (!timeleft) {
+ printk(MYIOC_s_WARN_FMT
+ "HOST INFO command timeout, doorbell=0x%08x\n",
+ ioc->name, mpt_GetIocState(ioc, 0));
mptctl_timeout_expired(ioc, mf);
- else
+ } else
goto retry_wait;
goto out;
}
@@ -3000,7 +3018,8 @@ static int __init mptctl_init(void)
* Install our handler
*/
++where;
- mptctl_id = mpt_register(mptctl_reply, MPTCTL_DRIVER);
+ mptctl_id = mpt_register(mptctl_reply, MPTCTL_DRIVER,
+ "mptctl_reply");
if (!mptctl_id || mptctl_id >= MPT_MAX_PROTOCOL_DRIVERS) {
printk(KERN_ERR MYNAM ": ERROR: Failed to register with Fusion MPT base driver\n");
misc_deregister(&mptctl_miscdev);
@@ -3008,7 +3027,8 @@ static int __init mptctl_init(void)
goto out_fail;
}
- mptctl_taskmgmt_id = mpt_register(mptctl_taskmgmt_reply, MPTCTL_DRIVER);
+ mptctl_taskmgmt_id = mpt_register(mptctl_taskmgmt_reply, MPTCTL_DRIVER,
+ "mptctl_taskmgmt_reply");
if (!mptctl_taskmgmt_id || mptctl_taskmgmt_id >= MPT_MAX_PROTOCOL_DRIVERS) {
printk(KERN_ERR MYNAM ": ERROR: Failed to register with Fusion MPT base driver\n");
mpt_deregister(mptctl_id);
diff --git a/drivers/message/fusion/mptfc.c b/drivers/message/fusion/mptfc.c
index b5f03ad8156..e15220ff52f 100644
--- a/drivers/message/fusion/mptfc.c
+++ b/drivers/message/fusion/mptfc.c
@@ -1472,9 +1472,12 @@ mptfc_init(void)
if (!mptfc_transport_template)
return -ENODEV;
- mptfcDoneCtx = mpt_register(mptscsih_io_done, MPTFC_DRIVER);
- mptfcTaskCtx = mpt_register(mptscsih_taskmgmt_complete, MPTFC_DRIVER);
- mptfcInternalCtx = mpt_register(mptscsih_scandv_complete, MPTFC_DRIVER);
+ mptfcDoneCtx = mpt_register(mptscsih_io_done, MPTFC_DRIVER,
+ "mptscsih_scandv_complete");
+ mptfcTaskCtx = mpt_register(mptscsih_taskmgmt_complete, MPTFC_DRIVER,
+ "mptscsih_scandv_complete");
+ mptfcInternalCtx = mpt_register(mptscsih_scandv_complete, MPTFC_DRIVER,
+ "mptscsih_scandv_complete");
mpt_event_register(mptfcDoneCtx, mptfc_event_process);
mpt_reset_register(mptfcDoneCtx, mptfc_ioc_reset);
diff --git a/drivers/message/fusion/mptlan.c b/drivers/message/fusion/mptlan.c
index 4fa9665cbe9..cbe96072a6c 100644
--- a/drivers/message/fusion/mptlan.c
+++ b/drivers/message/fusion/mptlan.c
@@ -1452,7 +1452,9 @@ static int __init mpt_lan_init (void)
{
show_mptmod_ver(LANAME, LANVER);
- if ((LanCtx = mpt_register(lan_reply, MPTLAN_DRIVER)) <= 0) {
+ LanCtx = mpt_register(lan_reply, MPTLAN_DRIVER,
+ "lan_reply");
+ if (LanCtx <= 0) {
printk (KERN_ERR MYNAM ": Failed to register with MPT base driver\n");
return -EBUSY;
}
diff --git a/drivers/message/fusion/mptsas.c b/drivers/message/fusion/mptsas.c
index ac000e83db0..83a5115f025 100644
--- a/drivers/message/fusion/mptsas.c
+++ b/drivers/message/fusion/mptsas.c
@@ -57,6 +57,7 @@
#include <scsi/scsi_device.h>
#include <scsi/scsi_host.h>
#include <scsi/scsi_transport_sas.h>
+#include <scsi/scsi_transport.h>
#include <scsi/scsi_dbg.h>
#include "mptbase.h"
@@ -126,6 +127,7 @@ static void mptsas_scan_sas_topology(MPT_ADAPTER *ioc);
static void mptsas_broadcast_primative_work(struct fw_event_work *fw_event);
static void mptsas_handle_queue_full_event(struct fw_event_work *fw_event);
static void mptsas_volume_delete(MPT_ADAPTER *ioc, u8 id);
+void mptsas_schedule_target_reset(void *ioc);
static void mptsas_print_phy_data(MPT_ADAPTER *ioc,
MPI_SAS_IO_UNIT0_PHY_DATA *phy_data)
@@ -1139,6 +1141,44 @@ mptsas_target_reset_queue(MPT_ADAPTER *ioc,
}
/**
+ * mptsas_schedule_target_reset- send pending target reset
+ * @iocp: per adapter object
+ *
+ * This function will delete scheduled target reset from the list and
+ * try to send next target reset. This will be called from completion
+ * context of any Task managment command.
+ */
+
+void
+mptsas_schedule_target_reset(void *iocp)
+{
+ MPT_ADAPTER *ioc = (MPT_ADAPTER *)(iocp);
+ MPT_SCSI_HOST *hd = shost_priv(ioc->sh);
+ struct list_head *head = &hd->target_reset_list;
+ struct mptsas_target_reset_event *target_reset_list;
+ u8 id, channel;
+ /*
+ * issue target reset to next device in the queue
+ */
+
+ head = &hd->target_reset_list;
+ if (list_empty(head))
+ return;
+
+ target_reset_list = list_entry(head->next,
+ struct mptsas_target_reset_event, list);
+
+ id = target_reset_list->sas_event_data.TargetID;
+ channel = target_reset_list->sas_event_data.Bus;
+ target_reset_list->time_count = jiffies;
+
+ if (mptsas_target_reset(ioc, channel, id))
+ target_reset_list->target_reset_issued = 1;
+ return;
+}
+
+
+/**
* mptsas_taskmgmt_complete - complete SAS task management function
* @ioc: Pointer to MPT_ADAPTER structure
*
@@ -1222,28 +1262,12 @@ mptsas_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
* enable work queue to remove device from upper layers
*/
list_del(&target_reset_list->list);
- if ((mptsas_find_vtarget(ioc, channel, id)) && !ioc->fw_events_off)
+ if (!ioc->fw_events_off)
mptsas_queue_device_delete(ioc,
&target_reset_list->sas_event_data);
- /*
- * issue target reset to next device in the queue
- */
-
- head = &hd->target_reset_list;
- if (list_empty(head))
- return 1;
-
- target_reset_list = list_entry(head->next, struct mptsas_target_reset_event,
- list);
-
- id = target_reset_list->sas_event_data.TargetID;
- channel = target_reset_list->sas_event_data.Bus;
- target_reset_list->time_count = jiffies;
-
- if (mptsas_target_reset(ioc, channel, id))
- target_reset_list->target_reset_issued = 1;
+ ioc->schedule_target_reset(ioc);
return 1;
}
@@ -1889,6 +1913,48 @@ mptsas_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
return mptscsih_qcmd(SCpnt,done);
}
+/**
+ * mptsas_mptsas_eh_timed_out - resets the scsi_cmnd timeout
+ * if the device under question is currently in the
+ * device removal delay.
+ * @sc: scsi command that the midlayer is about to time out
+ *
+ **/
+static enum blk_eh_timer_return mptsas_eh_timed_out(struct scsi_cmnd *sc)
+{
+ MPT_SCSI_HOST *hd;
+ MPT_ADAPTER *ioc;
+ VirtDevice *vdevice;
+ enum blk_eh_timer_return rc = BLK_EH_NOT_HANDLED;
+
+ hd = shost_priv(sc->device->host);
+ if (hd == NULL) {
+ printk(KERN_ERR MYNAM ": %s: Can't locate host! (sc=%p)\n",
+ __func__, sc);
+ goto done;
+ }
+
+ ioc = hd->ioc;
+ if (ioc->bus_type != SAS) {
+ printk(KERN_ERR MYNAM ": %s: Wrong bus type (sc=%p)\n",
+ __func__, sc);
+ goto done;
+ }
+
+ vdevice = sc->device->hostdata;
+ if (vdevice && vdevice->vtarget && (vdevice->vtarget->inDMD
+ || vdevice->vtarget->deleted)) {
+ dtmprintk(ioc, printk(MYIOC_s_WARN_FMT ": %s: target removed "
+ "or in device removal delay (sc=%p)\n",
+ ioc->name, __func__, sc));
+ rc = BLK_EH_RESET_TIMER;
+ goto done;
+ }
+
+done:
+ return rc;
+}
+
static struct scsi_host_template mptsas_driver_template = {
.module = THIS_MODULE,
@@ -2364,7 +2430,7 @@ mptsas_sas_io_unit_pg1(MPT_ADAPTER *ioc)
SasIOUnitPage1_t *buffer;
dma_addr_t dma_handle;
int error;
- u16 device_missing_delay;
+ u8 device_missing_delay;
memset(&hdr, 0, sizeof(ConfigExtendedPageHeader_t));
memset(&cfg, 0, sizeof(CONFIGPARMS));
@@ -2401,7 +2467,7 @@ mptsas_sas_io_unit_pg1(MPT_ADAPTER *ioc)
ioc->io_missing_delay =
le16_to_cpu(buffer->IODeviceMissingDelay);
- device_missing_delay = le16_to_cpu(buffer->ReportDeviceMissingDelay);
+ device_missing_delay = 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;
@@ -2549,6 +2615,7 @@ mptsas_sas_device_pg0(MPT_ADAPTER *ioc, struct mptsas_devinfo *device_info,
device_info->sas_address = le64_to_cpu(sas_address);
device_info->device_info =
le32_to_cpu(buffer->DeviceInfo);
+ device_info->flags = le16_to_cpu(buffer->Flags);
out_free_consistent:
pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
@@ -2960,6 +3027,7 @@ static int mptsas_probe_one_phy(struct device *dev,
struct sas_phy *phy;
struct sas_port *port;
int error = 0;
+ VirtTarget *vtarget;
if (!dev) {
error = -ENODEV;
@@ -3182,6 +3250,16 @@ static int mptsas_probe_one_phy(struct device *dev,
rphy_to_expander_device(rphy));
}
+ /* If the device exists,verify it wasn't previously flagged
+ as a missing device. If so, clear it */
+ vtarget = mptsas_find_vtarget(ioc,
+ phy_info->attached.channel,
+ phy_info->attached.id);
+ if (vtarget && vtarget->inDMD) {
+ printk(KERN_INFO "Device returned, unsetting inDMD\n");
+ vtarget->inDMD = 0;
+ }
+
out:
return error;
}
@@ -3635,9 +3713,42 @@ mptsas_send_link_status_event(struct fw_event_work *fw_event)
MPI_SAS_IOUNIT0_RATE_FAILED_SPEED_NEGOTIATION)
phy_info->phy->negotiated_linkrate =
SAS_LINK_RATE_FAILED;
- else
+ else {
phy_info->phy->negotiated_linkrate =
SAS_LINK_RATE_UNKNOWN;
+ if (ioc->device_missing_delay &&
+ mptsas_is_end_device(&phy_info->attached)) {
+ struct scsi_device *sdev;
+ VirtDevice *vdevice;
+ u8 channel, id;
+ id = phy_info->attached.id;
+ channel = phy_info->attached.channel;
+ devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+ "Link down for fw_id %d:fw_channel %d\n",
+ ioc->name, phy_info->attached.id,
+ phy_info->attached.channel));
+
+ shost_for_each_device(sdev, ioc->sh) {
+ vdevice = sdev->hostdata;
+ if ((vdevice == NULL) ||
+ (vdevice->vtarget == NULL))
+ continue;
+ if ((vdevice->vtarget->tflags &
+ MPT_TARGET_FLAGS_RAID_COMPONENT ||
+ vdevice->vtarget->raidVolume))
+ continue;
+ if (vdevice->vtarget->id == id &&
+ vdevice->vtarget->channel ==
+ channel)
+ devtprintk(ioc,
+ printk(MYIOC_s_DEBUG_FMT
+ "SDEV OUTSTANDING CMDS"
+ "%d\n", ioc->name,
+ sdev->device_busy));
+ }
+
+ }
+ }
}
out:
mptsas_free_fw_event(ioc, fw_event);
@@ -3840,6 +3951,13 @@ mptsas_probe_devices(MPT_ADAPTER *ioc)
MPI_SAS_DEVICE_INFO_SATA_DEVICE)) == 0)
continue;
+ /* If there is no FW B_T mapping for this device then continue
+ * */
+ if (!(sas_device.flags & MPI_SAS_DEVICE0_FLAGS_DEVICE_PRESENT)
+ || !(sas_device.flags &
+ MPI_SAS_DEVICE0_FLAGS_DEVICE_MAPPED))
+ continue;
+
phy_info = mptsas_refreshing_device_handles(ioc, &sas_device);
if (!phy_info)
continue;
@@ -4149,6 +4267,14 @@ mptsas_adding_inactive_raid_components(MPT_ADAPTER *ioc, u8 channel, u8 id)
phys_disk.PhysDiskID))
continue;
+ /* If there is no FW B_T mapping for this device then continue
+ * */
+ if (!(sas_device.flags & MPI_SAS_DEVICE0_FLAGS_DEVICE_PRESENT)
+ || !(sas_device.flags &
+ MPI_SAS_DEVICE0_FLAGS_DEVICE_MAPPED))
+ continue;
+
+
phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
sas_device.sas_address);
mptsas_add_end_device(ioc, phy_info);
@@ -4171,6 +4297,7 @@ mptsas_hotplug_work(MPT_ADAPTER *ioc, struct fw_event_work *fw_event,
struct mptsas_devinfo sas_device;
VirtTarget *vtarget;
int i;
+ struct mptsas_portinfo *port_info;
switch (hot_plug_info->event_type) {
@@ -4199,12 +4326,47 @@ mptsas_hotplug_work(MPT_ADAPTER *ioc, struct fw_event_work *fw_event,
(hot_plug_info->channel << 8) +
hot_plug_info->id);
+ /* If there is no FW B_T mapping for this device then break
+ * */
+ if (!(sas_device.flags & MPI_SAS_DEVICE0_FLAGS_DEVICE_PRESENT)
+ || !(sas_device.flags &
+ MPI_SAS_DEVICE0_FLAGS_DEVICE_MAPPED))
+ break;
+
if (!sas_device.handle)
return;
phy_info = mptsas_refreshing_device_handles(ioc, &sas_device);
- if (!phy_info)
+ /* Only For SATA Device ADD */
+ if (!phy_info && (sas_device.device_info &
+ MPI_SAS_DEVICE_INFO_SATA_DEVICE)) {
+ devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+ "%s %d SATA HOT PLUG: "
+ "parent handle of device %x\n", ioc->name,
+ __func__, __LINE__, sas_device.handle_parent));
+ port_info = mptsas_find_portinfo_by_handle(ioc,
+ sas_device.handle_parent);
+
+ if (port_info == ioc->hba_port_info)
+ mptsas_probe_hba_phys(ioc);
+ else if (port_info)
+ mptsas_expander_refresh(ioc, port_info);
+ else {
+ dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
+ "%s %d port info is NULL\n",
+ ioc->name, __func__, __LINE__));
+ break;
+ }
+ phy_info = mptsas_refreshing_device_handles
+ (ioc, &sas_device);
+ }
+
+ if (!phy_info) {
+ dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
+ "%s %d phy info is NULL\n",
+ ioc->name, __func__, __LINE__));
break;
+ }
if (mptsas_get_rphy(phy_info))
break;
@@ -4241,6 +4403,13 @@ mptsas_hotplug_work(MPT_ADAPTER *ioc, struct fw_event_work *fw_event,
break;
}
+ /* If there is no FW B_T mapping for this device then break
+ * */
+ if (!(sas_device.flags & MPI_SAS_DEVICE0_FLAGS_DEVICE_PRESENT)
+ || !(sas_device.flags &
+ MPI_SAS_DEVICE0_FLAGS_DEVICE_MAPPED))
+ break;
+
phy_info = mptsas_find_phyinfo_by_sas_address(
ioc, sas_device.sas_address);
@@ -4294,6 +4463,13 @@ mptsas_hotplug_work(MPT_ADAPTER *ioc, struct fw_event_work *fw_event,
break;
}
+ /* If there is no FW B_T mapping for this device then break
+ * */
+ if (!(sas_device.flags & MPI_SAS_DEVICE0_FLAGS_DEVICE_PRESENT)
+ || !(sas_device.flags &
+ MPI_SAS_DEVICE0_FLAGS_DEVICE_MAPPED))
+ break;
+
phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
sas_device.sas_address);
if (!phy_info) {
@@ -4727,8 +4903,9 @@ mptsas_broadcast_primative_work(struct fw_event_work *fw_event)
mutex_unlock(&ioc->taskmgmt_cmds.mutex);
if (issue_reset) {
- printk(MYIOC_s_WARN_FMT "Issuing Reset from %s!!\n",
- ioc->name, __func__);
+ printk(MYIOC_s_WARN_FMT
+ "Issuing Reset from %s!! doorbell=0x%08x\n",
+ ioc->name, __func__, mpt_GetIocState(ioc, 0));
mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP);
}
mptsas_free_fw_event(ioc, fw_event);
@@ -4816,12 +4993,47 @@ mptsas_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *reply)
{
EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data =
(EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *)reply->Data;
+ u16 ioc_stat;
+ ioc_stat = le16_to_cpu(reply->IOCStatus);
if (sas_event_data->ReasonCode ==
MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING) {
mptsas_target_reset_queue(ioc, sas_event_data);
return 0;
}
+ if (sas_event_data->ReasonCode ==
+ MPI_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET &&
+ ioc->device_missing_delay &&
+ (ioc_stat & MPI_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE)) {
+ VirtTarget *vtarget = NULL;
+ u8 id, channel;
+ u32 log_info = le32_to_cpu(reply->IOCLogInfo);
+
+ id = sas_event_data->TargetID;
+ channel = sas_event_data->Bus;
+
+ vtarget = mptsas_find_vtarget(ioc, channel, id);
+ if (vtarget) {
+ devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+ "LogInfo (0x%x) available for "
+ "INTERNAL_DEVICE_RESET"
+ "fw_id %d fw_channel %d\n", ioc->name,
+ log_info, id, channel));
+ if (vtarget->raidVolume) {
+ devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+ "Skipping Raid Volume for inDMD\n",
+ ioc->name));
+ } else {
+ devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+ "Setting device flag inDMD\n",
+ ioc->name));
+ vtarget->inDMD = 1;
+ }
+
+ }
+
+ }
+
break;
}
case MPI_EVENT_SAS_EXPANDER_STATUS_CHANGE:
@@ -4924,7 +5136,7 @@ mptsas_probe(struct pci_dev *pdev, const struct pci_device_id *id)
ioc->DoneCtx = mptsasDoneCtx;
ioc->TaskCtx = mptsasTaskCtx;
ioc->InternalCtx = mptsasInternalCtx;
-
+ ioc->schedule_target_reset = &mptsas_schedule_target_reset;
/* Added sanity check on readiness of the MPT adapter.
*/
if (ioc->last_state != MPI_IOC_STATE_OPERATIONAL) {
@@ -5154,14 +5366,20 @@ mptsas_init(void)
sas_attach_transport(&mptsas_transport_functions);
if (!mptsas_transport_template)
return -ENODEV;
+ mptsas_transport_template->eh_timed_out = mptsas_eh_timed_out;
- mptsasDoneCtx = mpt_register(mptscsih_io_done, MPTSAS_DRIVER);
- mptsasTaskCtx = mpt_register(mptscsih_taskmgmt_complete, MPTSAS_DRIVER);
+ mptsasDoneCtx = mpt_register(mptscsih_io_done, MPTSAS_DRIVER,
+ "mptscsih_io_done");
+ mptsasTaskCtx = mpt_register(mptscsih_taskmgmt_complete, MPTSAS_DRIVER,
+ "mptscsih_taskmgmt_complete");
mptsasInternalCtx =
- mpt_register(mptscsih_scandv_complete, MPTSAS_DRIVER);
- mptsasMgmtCtx = mpt_register(mptsas_mgmt_done, MPTSAS_DRIVER);
+ mpt_register(mptscsih_scandv_complete, MPTSAS_DRIVER,
+ "mptscsih_scandv_complete");
+ mptsasMgmtCtx = mpt_register(mptsas_mgmt_done, MPTSAS_DRIVER,
+ "mptsas_mgmt_done");
mptsasDeviceResetCtx =
- mpt_register(mptsas_taskmgmt_complete, MPTSAS_DRIVER);
+ mpt_register(mptsas_taskmgmt_complete, MPTSAS_DRIVER,
+ "mptsas_taskmgmt_complete");
mpt_event_register(mptsasDoneCtx, mptsas_event_process);
mpt_reset_register(mptsasDoneCtx, mptsas_ioc_reset);
diff --git a/drivers/message/fusion/mptsas.h b/drivers/message/fusion/mptsas.h
index 7b249edbda7..57e86ab7766 100644
--- a/drivers/message/fusion/mptsas.h
+++ b/drivers/message/fusion/mptsas.h
@@ -140,6 +140,7 @@ struct mptsas_devinfo {
u64 sas_address; /* WWN of this device,
SATA is assigned by HBA,expander */
u32 device_info; /* bitfield detailed info about this device */
+ u16 flags; /* sas device pg0 flags */
};
/*
diff --git a/drivers/message/fusion/mptscsih.c b/drivers/message/fusion/mptscsih.c
index 5c53624e0e8..59b8f53d1ec 100644
--- a/drivers/message/fusion/mptscsih.c
+++ b/drivers/message/fusion/mptscsih.c
@@ -664,6 +664,7 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
u32 log_info;
status = le16_to_cpu(pScsiReply->IOCStatus) & MPI_IOCSTATUS_MASK;
+
scsi_state = pScsiReply->SCSIState;
scsi_status = pScsiReply->SCSIStatus;
xfer_cnt = le32_to_cpu(pScsiReply->TransferCount);
@@ -738,13 +739,36 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */
if ( ioc->bus_type == SAS ) {
- u16 ioc_status = le16_to_cpu(pScsiReply->IOCStatus);
- if (ioc_status & MPI_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE) {
- if ((log_info & SAS_LOGINFO_MASK)
- == SAS_LOGINFO_NEXUS_LOSS) {
- sc->result = (DID_BUS_BUSY << 16);
- break;
- }
+ u16 ioc_status =
+ le16_to_cpu(pScsiReply->IOCStatus);
+ if ((ioc_status &
+ MPI_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE)
+ &&
+ ((log_info & SAS_LOGINFO_MASK) ==
+ SAS_LOGINFO_NEXUS_LOSS)) {
+ VirtDevice *vdevice =
+ sc->device->hostdata;
+
+ /* flag the device as being in
+ * device removal delay so we can
+ * notify the midlayer to hold off
+ * on timeout eh */
+ if (vdevice && vdevice->
+ vtarget &&
+ vdevice->vtarget->
+ raidVolume)
+ printk(KERN_INFO
+ "Skipping Raid Volume"
+ "for inDMD\n");
+ else if (vdevice &&
+ vdevice->vtarget)
+ vdevice->vtarget->
+ inDMD = 1;
+
+ sc->result =
+ (DID_TRANSPORT_DISRUPTED
+ << 16);
+ break;
}
} else if (ioc->bus_type == FC) {
/*
@@ -1704,8 +1728,9 @@ mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id, int lun,
CLEAR_MGMT_STATUS(ioc->taskmgmt_cmds.status)
if (issue_hard_reset) {
- printk(MYIOC_s_WARN_FMT "Issuing Reset from %s!!\n",
- ioc->name, __func__);
+ printk(MYIOC_s_WARN_FMT
+ "Issuing Reset from %s!! doorbell=0x%08x\n",
+ ioc->name, __func__, mpt_GetIocState(ioc, 0));
retval = mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP);
mpt_free_msg_frame(ioc, mf);
}
@@ -2132,6 +2157,8 @@ mptscsih_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf,
mpt_clear_taskmgmt_in_progress_flag(ioc);
ioc->taskmgmt_cmds.status &= ~MPT_MGMT_STATUS_PENDING;
complete(&ioc->taskmgmt_cmds.done);
+ if (ioc->bus_type == SAS)
+ ioc->schedule_target_reset(ioc);
return 1;
}
return 0;
@@ -2459,6 +2486,8 @@ mptscsih_slave_configure(struct scsi_device *sdev)
ioc->name,sdev->tagged_supported, sdev->simple_tags,
sdev->ordered_tags));
+ blk_queue_dma_alignment (sdev->request_queue, 512 - 1);
+
return 0;
}
@@ -3045,8 +3074,11 @@ mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *io)
goto out;
}
if (!timeleft) {
- printk(MYIOC_s_WARN_FMT "Issuing Reset from %s!!\n",
- ioc->name, __func__);
+ printk(MYIOC_s_WARN_FMT
+ "Issuing Reset from %s!! doorbell=0x%08xh"
+ " cmd=0x%02x\n",
+ ioc->name, __func__, mpt_GetIocState(ioc, 0),
+ cmd);
mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP);
mpt_free_msg_frame(ioc, mf);
}
diff --git a/drivers/message/fusion/mptspi.c b/drivers/message/fusion/mptspi.c
index 1abaa5d01ae..0e2803155ae 100644
--- a/drivers/message/fusion/mptspi.c
+++ b/drivers/message/fusion/mptspi.c
@@ -1551,9 +1551,12 @@ mptspi_init(void)
if (!mptspi_transport_template)
return -ENODEV;
- mptspiDoneCtx = mpt_register(mptscsih_io_done, MPTSPI_DRIVER);
- mptspiTaskCtx = mpt_register(mptscsih_taskmgmt_complete, MPTSPI_DRIVER);
- mptspiInternalCtx = mpt_register(mptscsih_scandv_complete, MPTSPI_DRIVER);
+ mptspiDoneCtx = mpt_register(mptscsih_io_done, MPTSPI_DRIVER,
+ "mptscsih_io_done");
+ mptspiTaskCtx = mpt_register(mptscsih_taskmgmt_complete, MPTSPI_DRIVER,
+ "mptscsih_taskmgmt_complete");
+ mptspiInternalCtx = mpt_register(mptscsih_scandv_complete,
+ MPTSPI_DRIVER, "mptscsih_scandv_complete");
mpt_event_register(mptspiDoneCtx, mptspi_event_process);
mpt_reset_register(mptspiDoneCtx, mptspi_ioc_reset);
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index 9b089dfb173..488f2547229 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -72,7 +72,7 @@ config ATMEL_TCLIB
config ATMEL_TCB_CLKSRC
bool "TC Block Clocksource"
- depends on ATMEL_TCLIB && GENERIC_TIME
+ depends on ATMEL_TCLIB
default y
help
Select this to get a high precision clocksource based on a
@@ -240,7 +240,7 @@ config CS5535_MFGPT_DEFAULT_IRQ
config CS5535_CLOCK_EVENT_SRC
tristate "CS5535/CS5536 high-res timer (MFGPT) events"
- depends on GENERIC_TIME && GENERIC_CLOCKEVENTS && CS5535_MFGPT
+ depends on GENERIC_CLOCKEVENTS && CS5535_MFGPT
help
This driver provides a clock event source based on the MFGPT
timer(s) in the CS5535 and CS5536 companion chips.
diff --git a/drivers/misc/enclosure.c b/drivers/misc/enclosure.c
index 48c84a58163..00e5fcac8fd 100644
--- a/drivers/misc/enclosure.c
+++ b/drivers/misc/enclosure.c
@@ -285,8 +285,11 @@ enclosure_component_register(struct enclosure_device *edev,
cdev->groups = enclosure_groups;
err = device_register(cdev);
- if (err)
- ERR_PTR(err);
+ if (err) {
+ ecomp->number = -1;
+ put_device(cdev);
+ return ERR_PTR(err);
+ }
return ecomp;
}
diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
index f06d06e7fdf..d25e22cee4c 100644
--- a/drivers/mmc/host/Kconfig
+++ b/drivers/mmc/host/Kconfig
@@ -432,3 +432,12 @@ config MMC_SH_MMCIF
This selects the MMC Host Interface controler (MMCIF).
This driver supports MMCIF in sh7724/sh7757/sh7372.
+
+config MMC_JZ4740
+ tristate "JZ4740 SD/Multimedia Card Interface support"
+ depends on MACH_JZ4740
+ help
+ This selects support for the SD/MMC controller on Ingenic JZ4740
+ SoCs.
+ If you have a board based on such a SoC and with a SD/MMC slot,
+ say Y or M here.
diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile
index e30c2ee4889..f4e53c98d94 100644
--- a/drivers/mmc/host/Makefile
+++ b/drivers/mmc/host/Makefile
@@ -36,6 +36,7 @@ obj-$(CONFIG_MMC_CB710) += cb710-mmc.o
obj-$(CONFIG_MMC_VIA_SDMMC) += via-sdmmc.o
obj-$(CONFIG_SDH_BFIN) += bfin_sdh.o
obj-$(CONFIG_MMC_SH_MMCIF) += sh_mmcif.o
+obj-$(CONFIG_MMC_JZ4740) += jz4740_mmc.o
obj-$(CONFIG_MMC_SDHCI_OF) += sdhci-of.o
sdhci-of-y := sdhci-of-core.o
diff --git a/drivers/mmc/host/jz4740_mmc.c b/drivers/mmc/host/jz4740_mmc.c
new file mode 100644
index 00000000000..ad4f9870e3c
--- /dev/null
+++ b/drivers/mmc/host/jz4740_mmc.c
@@ -0,0 +1,1029 @@
+/*
+ * Copyright (C) 2009-2010, Lars-Peter Clausen <lars@metafoo.de>
+ * JZ4740 SD/MMC controller 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.
+ *
+ * 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/mmc/host.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/scatterlist.h>
+#include <linux/clk.h>
+
+#include <linux/bitops.h>
+#include <linux/gpio.h>
+#include <asm/mach-jz4740/gpio.h>
+#include <asm/cacheflush.h>
+#include <linux/dma-mapping.h>
+
+#include <asm/mach-jz4740/jz4740_mmc.h>
+
+#define JZ_REG_MMC_STRPCL 0x00
+#define JZ_REG_MMC_STATUS 0x04
+#define JZ_REG_MMC_CLKRT 0x08
+#define JZ_REG_MMC_CMDAT 0x0C
+#define JZ_REG_MMC_RESTO 0x10
+#define JZ_REG_MMC_RDTO 0x14
+#define JZ_REG_MMC_BLKLEN 0x18
+#define JZ_REG_MMC_NOB 0x1C
+#define JZ_REG_MMC_SNOB 0x20
+#define JZ_REG_MMC_IMASK 0x24
+#define JZ_REG_MMC_IREG 0x28
+#define JZ_REG_MMC_CMD 0x2C
+#define JZ_REG_MMC_ARG 0x30
+#define JZ_REG_MMC_RESP_FIFO 0x34
+#define JZ_REG_MMC_RXFIFO 0x38
+#define JZ_REG_MMC_TXFIFO 0x3C
+
+#define JZ_MMC_STRPCL_EXIT_MULTIPLE BIT(7)
+#define JZ_MMC_STRPCL_EXIT_TRANSFER BIT(6)
+#define JZ_MMC_STRPCL_START_READWAIT BIT(5)
+#define JZ_MMC_STRPCL_STOP_READWAIT BIT(4)
+#define JZ_MMC_STRPCL_RESET BIT(3)
+#define JZ_MMC_STRPCL_START_OP BIT(2)
+#define JZ_MMC_STRPCL_CLOCK_CONTROL (BIT(1) | BIT(0))
+#define JZ_MMC_STRPCL_CLOCK_STOP BIT(0)
+#define JZ_MMC_STRPCL_CLOCK_START BIT(1)
+
+
+#define JZ_MMC_STATUS_IS_RESETTING BIT(15)
+#define JZ_MMC_STATUS_SDIO_INT_ACTIVE BIT(14)
+#define JZ_MMC_STATUS_PRG_DONE BIT(13)
+#define JZ_MMC_STATUS_DATA_TRAN_DONE BIT(12)
+#define JZ_MMC_STATUS_END_CMD_RES BIT(11)
+#define JZ_MMC_STATUS_DATA_FIFO_AFULL BIT(10)
+#define JZ_MMC_STATUS_IS_READWAIT BIT(9)
+#define JZ_MMC_STATUS_CLK_EN BIT(8)
+#define JZ_MMC_STATUS_DATA_FIFO_FULL BIT(7)
+#define JZ_MMC_STATUS_DATA_FIFO_EMPTY BIT(6)
+#define JZ_MMC_STATUS_CRC_RES_ERR BIT(5)
+#define JZ_MMC_STATUS_CRC_READ_ERROR BIT(4)
+#define JZ_MMC_STATUS_TIMEOUT_WRITE BIT(3)
+#define JZ_MMC_STATUS_CRC_WRITE_ERROR BIT(2)
+#define JZ_MMC_STATUS_TIMEOUT_RES BIT(1)
+#define JZ_MMC_STATUS_TIMEOUT_READ BIT(0)
+
+#define JZ_MMC_STATUS_READ_ERROR_MASK (BIT(4) | BIT(0))
+#define JZ_MMC_STATUS_WRITE_ERROR_MASK (BIT(3) | BIT(2))
+
+
+#define JZ_MMC_CMDAT_IO_ABORT BIT(11)
+#define JZ_MMC_CMDAT_BUS_WIDTH_4BIT BIT(10)
+#define JZ_MMC_CMDAT_DMA_EN BIT(8)
+#define JZ_MMC_CMDAT_INIT BIT(7)
+#define JZ_MMC_CMDAT_BUSY BIT(6)
+#define JZ_MMC_CMDAT_STREAM BIT(5)
+#define JZ_MMC_CMDAT_WRITE BIT(4)
+#define JZ_MMC_CMDAT_DATA_EN BIT(3)
+#define JZ_MMC_CMDAT_RESPONSE_FORMAT (BIT(2) | BIT(1) | BIT(0))
+#define JZ_MMC_CMDAT_RSP_R1 1
+#define JZ_MMC_CMDAT_RSP_R2 2
+#define JZ_MMC_CMDAT_RSP_R3 3
+
+#define JZ_MMC_IRQ_SDIO BIT(7)
+#define JZ_MMC_IRQ_TXFIFO_WR_REQ BIT(6)
+#define JZ_MMC_IRQ_RXFIFO_RD_REQ BIT(5)
+#define JZ_MMC_IRQ_END_CMD_RES BIT(2)
+#define JZ_MMC_IRQ_PRG_DONE BIT(1)
+#define JZ_MMC_IRQ_DATA_TRAN_DONE BIT(0)
+
+
+#define JZ_MMC_CLK_RATE 24000000
+
+enum jz4740_mmc_state {
+ JZ4740_MMC_STATE_READ_RESPONSE,
+ JZ4740_MMC_STATE_TRANSFER_DATA,
+ JZ4740_MMC_STATE_SEND_STOP,
+ JZ4740_MMC_STATE_DONE,
+};
+
+struct jz4740_mmc_host {
+ struct mmc_host *mmc;
+ struct platform_device *pdev;
+ struct jz4740_mmc_platform_data *pdata;
+ struct clk *clk;
+
+ int irq;
+ int card_detect_irq;
+
+ struct resource *mem;
+ void __iomem *base;
+ struct mmc_request *req;
+ struct mmc_command *cmd;
+
+ unsigned long waiting;
+
+ uint32_t cmdat;
+
+ uint16_t irq_mask;
+
+ spinlock_t lock;
+
+ struct timer_list timeout_timer;
+ struct sg_mapping_iter miter;
+ enum jz4740_mmc_state state;
+};
+
+static void jz4740_mmc_set_irq_enabled(struct jz4740_mmc_host *host,
+ unsigned int irq, bool enabled)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&host->lock, flags);
+ if (enabled)
+ host->irq_mask &= ~irq;
+ else
+ host->irq_mask |= irq;
+ spin_unlock_irqrestore(&host->lock, flags);
+
+ writew(host->irq_mask, host->base + JZ_REG_MMC_IMASK);
+}
+
+static void jz4740_mmc_clock_enable(struct jz4740_mmc_host *host,
+ bool start_transfer)
+{
+ uint16_t val = JZ_MMC_STRPCL_CLOCK_START;
+
+ if (start_transfer)
+ val |= JZ_MMC_STRPCL_START_OP;
+
+ writew(val, host->base + JZ_REG_MMC_STRPCL);
+}
+
+static void jz4740_mmc_clock_disable(struct jz4740_mmc_host *host)
+{
+ uint32_t status;
+ unsigned int timeout = 1000;
+
+ writew(JZ_MMC_STRPCL_CLOCK_STOP, host->base + JZ_REG_MMC_STRPCL);
+ do {
+ status = readl(host->base + JZ_REG_MMC_STATUS);
+ } while (status & JZ_MMC_STATUS_CLK_EN && --timeout);
+}
+
+static void jz4740_mmc_reset(struct jz4740_mmc_host *host)
+{
+ uint32_t status;
+ unsigned int timeout = 1000;
+
+ writew(JZ_MMC_STRPCL_RESET, host->base + JZ_REG_MMC_STRPCL);
+ udelay(10);
+ do {
+ status = readl(host->base + JZ_REG_MMC_STATUS);
+ } while (status & JZ_MMC_STATUS_IS_RESETTING && --timeout);
+}
+
+static void jz4740_mmc_request_done(struct jz4740_mmc_host *host)
+{
+ struct mmc_request *req;
+
+ req = host->req;
+ host->req = NULL;
+
+ mmc_request_done(host->mmc, req);
+}
+
+static unsigned int jz4740_mmc_poll_irq(struct jz4740_mmc_host *host,
+ unsigned int irq)
+{
+ unsigned int timeout = 0x800;
+ uint16_t status;
+
+ do {
+ status = readw(host->base + JZ_REG_MMC_IREG);
+ } while (!(status & irq) && --timeout);
+
+ if (timeout == 0) {
+ set_bit(0, &host->waiting);
+ mod_timer(&host->timeout_timer, jiffies + 5*HZ);
+ jz4740_mmc_set_irq_enabled(host, irq, true);
+ return true;
+ }
+
+ return false;
+}
+
+static void jz4740_mmc_transfer_check_state(struct jz4740_mmc_host *host,
+ struct mmc_data *data)
+{
+ int status;
+
+ status = readl(host->base + JZ_REG_MMC_STATUS);
+ if (status & JZ_MMC_STATUS_WRITE_ERROR_MASK) {
+ if (status & (JZ_MMC_STATUS_TIMEOUT_WRITE)) {
+ host->req->cmd->error = -ETIMEDOUT;
+ data->error = -ETIMEDOUT;
+ } else {
+ host->req->cmd->error = -EIO;
+ data->error = -EIO;
+ }
+ }
+}
+
+static bool jz4740_mmc_write_data(struct jz4740_mmc_host *host,
+ struct mmc_data *data)
+{
+ struct sg_mapping_iter *miter = &host->miter;
+ void __iomem *fifo_addr = host->base + JZ_REG_MMC_TXFIFO;
+ uint32_t *buf;
+ bool timeout;
+ size_t i, j;
+
+ while (sg_miter_next(miter)) {
+ buf = miter->addr;
+ i = miter->length / 4;
+ j = i / 8;
+ i = i & 0x7;
+ while (j) {
+ timeout = jz4740_mmc_poll_irq(host, JZ_MMC_IRQ_TXFIFO_WR_REQ);
+ if (unlikely(timeout))
+ goto poll_timeout;
+
+ writel(buf[0], fifo_addr);
+ writel(buf[1], fifo_addr);
+ writel(buf[2], fifo_addr);
+ writel(buf[3], fifo_addr);
+ writel(buf[4], fifo_addr);
+ writel(buf[5], fifo_addr);
+ writel(buf[6], fifo_addr);
+ writel(buf[7], fifo_addr);
+ buf += 8;
+ --j;
+ }
+ if (unlikely(i)) {
+ timeout = jz4740_mmc_poll_irq(host, JZ_MMC_IRQ_TXFIFO_WR_REQ);
+ if (unlikely(timeout))
+ goto poll_timeout;
+
+ while (i) {
+ writel(*buf, fifo_addr);
+ ++buf;
+ --i;
+ }
+ }
+ data->bytes_xfered += miter->length;
+ }
+ sg_miter_stop(miter);
+
+ return false;
+
+poll_timeout:
+ miter->consumed = (void *)buf - miter->addr;
+ data->bytes_xfered += miter->consumed;
+ sg_miter_stop(miter);
+
+ return true;
+}
+
+static bool jz4740_mmc_read_data(struct jz4740_mmc_host *host,
+ struct mmc_data *data)
+{
+ struct sg_mapping_iter *miter = &host->miter;
+ void __iomem *fifo_addr = host->base + JZ_REG_MMC_RXFIFO;
+ uint32_t *buf;
+ uint32_t d;
+ uint16_t status;
+ size_t i, j;
+ unsigned int timeout;
+
+ while (sg_miter_next(miter)) {
+ buf = miter->addr;
+ i = miter->length;
+ j = i / 32;
+ i = i & 0x1f;
+ while (j) {
+ timeout = jz4740_mmc_poll_irq(host, JZ_MMC_IRQ_RXFIFO_RD_REQ);
+ if (unlikely(timeout))
+ goto poll_timeout;
+
+ buf[0] = readl(fifo_addr);
+ buf[1] = readl(fifo_addr);
+ buf[2] = readl(fifo_addr);
+ buf[3] = readl(fifo_addr);
+ buf[4] = readl(fifo_addr);
+ buf[5] = readl(fifo_addr);
+ buf[6] = readl(fifo_addr);
+ buf[7] = readl(fifo_addr);
+
+ buf += 8;
+ --j;
+ }
+
+ if (unlikely(i)) {
+ timeout = jz4740_mmc_poll_irq(host, JZ_MMC_IRQ_RXFIFO_RD_REQ);
+ if (unlikely(timeout))
+ goto poll_timeout;
+
+ while (i >= 4) {
+ *buf++ = readl(fifo_addr);
+ i -= 4;
+ }
+ if (unlikely(i > 0)) {
+ d = readl(fifo_addr);
+ memcpy(buf, &d, i);
+ }
+ }
+ data->bytes_xfered += miter->length;
+
+ /* This can go away once MIPS implements
+ * flush_kernel_dcache_page */
+ flush_dcache_page(miter->page);
+ }
+ sg_miter_stop(miter);
+
+ /* For whatever reason there is sometime one word more in the fifo then
+ * requested */
+ timeout = 1000;
+ status = readl(host->base + JZ_REG_MMC_STATUS);
+ while (!(status & JZ_MMC_STATUS_DATA_FIFO_EMPTY) && --timeout) {
+ d = readl(fifo_addr);
+ status = readl(host->base + JZ_REG_MMC_STATUS);
+ }
+
+ return false;
+
+poll_timeout:
+ miter->consumed = (void *)buf - miter->addr;
+ data->bytes_xfered += miter->consumed;
+ sg_miter_stop(miter);
+
+ return true;
+}
+
+static void jz4740_mmc_timeout(unsigned long data)
+{
+ struct jz4740_mmc_host *host = (struct jz4740_mmc_host *)data;
+
+ if (!test_and_clear_bit(0, &host->waiting))
+ return;
+
+ jz4740_mmc_set_irq_enabled(host, JZ_MMC_IRQ_END_CMD_RES, false);
+
+ host->req->cmd->error = -ETIMEDOUT;
+ jz4740_mmc_request_done(host);
+}
+
+static void jz4740_mmc_read_response(struct jz4740_mmc_host *host,
+ struct mmc_command *cmd)
+{
+ int i;
+ uint16_t tmp;
+ void __iomem *fifo_addr = host->base + JZ_REG_MMC_RESP_FIFO;
+
+ if (cmd->flags & MMC_RSP_136) {
+ tmp = readw(fifo_addr);
+ for (i = 0; i < 4; ++i) {
+ cmd->resp[i] = tmp << 24;
+ tmp = readw(fifo_addr);
+ cmd->resp[i] |= tmp << 8;
+ tmp = readw(fifo_addr);
+ cmd->resp[i] |= tmp >> 8;
+ }
+ } else {
+ cmd->resp[0] = readw(fifo_addr) << 24;
+ cmd->resp[0] |= readw(fifo_addr) << 8;
+ cmd->resp[0] |= readw(fifo_addr) & 0xff;
+ }
+}
+
+static void jz4740_mmc_send_command(struct jz4740_mmc_host *host,
+ struct mmc_command *cmd)
+{
+ uint32_t cmdat = host->cmdat;
+
+ host->cmdat &= ~JZ_MMC_CMDAT_INIT;
+ jz4740_mmc_clock_disable(host);
+
+ host->cmd = cmd;
+
+ if (cmd->flags & MMC_RSP_BUSY)
+ cmdat |= JZ_MMC_CMDAT_BUSY;
+
+ switch (mmc_resp_type(cmd)) {
+ case MMC_RSP_R1B:
+ case MMC_RSP_R1:
+ cmdat |= JZ_MMC_CMDAT_RSP_R1;
+ break;
+ case MMC_RSP_R2:
+ cmdat |= JZ_MMC_CMDAT_RSP_R2;
+ break;
+ case MMC_RSP_R3:
+ cmdat |= JZ_MMC_CMDAT_RSP_R3;
+ break;
+ default:
+ break;
+ }
+
+ if (cmd->data) {
+ cmdat |= JZ_MMC_CMDAT_DATA_EN;
+ if (cmd->data->flags & MMC_DATA_WRITE)
+ cmdat |= JZ_MMC_CMDAT_WRITE;
+ if (cmd->data->flags & MMC_DATA_STREAM)
+ cmdat |= JZ_MMC_CMDAT_STREAM;
+
+ writew(cmd->data->blksz, host->base + JZ_REG_MMC_BLKLEN);
+ writew(cmd->data->blocks, host->base + JZ_REG_MMC_NOB);
+ }
+
+ writeb(cmd->opcode, host->base + JZ_REG_MMC_CMD);
+ writel(cmd->arg, host->base + JZ_REG_MMC_ARG);
+ writel(cmdat, host->base + JZ_REG_MMC_CMDAT);
+
+ jz4740_mmc_clock_enable(host, 1);
+}
+
+static void jz_mmc_prepare_data_transfer(struct jz4740_mmc_host *host)
+{
+ struct mmc_command *cmd = host->req->cmd;
+ struct mmc_data *data = cmd->data;
+ int direction;
+
+ if (data->flags & MMC_DATA_READ)
+ direction = SG_MITER_TO_SG;
+ else
+ direction = SG_MITER_FROM_SG;
+
+ sg_miter_start(&host->miter, data->sg, data->sg_len, direction);
+}
+
+
+static irqreturn_t jz_mmc_irq_worker(int irq, void *devid)
+{
+ struct jz4740_mmc_host *host = (struct jz4740_mmc_host *)devid;
+ struct mmc_command *cmd = host->req->cmd;
+ struct mmc_request *req = host->req;
+ bool timeout = false;
+
+ if (cmd->error)
+ host->state = JZ4740_MMC_STATE_DONE;
+
+ switch (host->state) {
+ case JZ4740_MMC_STATE_READ_RESPONSE:
+ if (cmd->flags & MMC_RSP_PRESENT)
+ jz4740_mmc_read_response(host, cmd);
+
+ if (!cmd->data)
+ break;
+
+ jz_mmc_prepare_data_transfer(host);
+
+ case JZ4740_MMC_STATE_TRANSFER_DATA:
+ if (cmd->data->flags & MMC_DATA_READ)
+ timeout = jz4740_mmc_read_data(host, cmd->data);
+ else
+ timeout = jz4740_mmc_write_data(host, cmd->data);
+
+ if (unlikely(timeout)) {
+ host->state = JZ4740_MMC_STATE_TRANSFER_DATA;
+ break;
+ }
+
+ jz4740_mmc_transfer_check_state(host, cmd->data);
+
+ timeout = jz4740_mmc_poll_irq(host, JZ_MMC_IRQ_DATA_TRAN_DONE);
+ if (unlikely(timeout)) {
+ host->state = JZ4740_MMC_STATE_SEND_STOP;
+ break;
+ }
+ writew(JZ_MMC_IRQ_DATA_TRAN_DONE, host->base + JZ_REG_MMC_IREG);
+
+ case JZ4740_MMC_STATE_SEND_STOP:
+ if (!req->stop)
+ break;
+
+ jz4740_mmc_send_command(host, req->stop);
+
+ timeout = jz4740_mmc_poll_irq(host, JZ_MMC_IRQ_PRG_DONE);
+ if (timeout) {
+ host->state = JZ4740_MMC_STATE_DONE;
+ break;
+ }
+ case JZ4740_MMC_STATE_DONE:
+ break;
+ }
+
+ if (!timeout)
+ jz4740_mmc_request_done(host);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t jz_mmc_irq(int irq, void *devid)
+{
+ struct jz4740_mmc_host *host = devid;
+ struct mmc_command *cmd = host->cmd;
+ uint16_t irq_reg, status, tmp;
+
+ irq_reg = readw(host->base + JZ_REG_MMC_IREG);
+
+ tmp = irq_reg;
+ irq_reg &= ~host->irq_mask;
+
+ tmp &= ~(JZ_MMC_IRQ_TXFIFO_WR_REQ | JZ_MMC_IRQ_RXFIFO_RD_REQ |
+ JZ_MMC_IRQ_PRG_DONE | JZ_MMC_IRQ_DATA_TRAN_DONE);
+
+ if (tmp != irq_reg)
+ writew(tmp & ~irq_reg, host->base + JZ_REG_MMC_IREG);
+
+ if (irq_reg & JZ_MMC_IRQ_SDIO) {
+ writew(JZ_MMC_IRQ_SDIO, host->base + JZ_REG_MMC_IREG);
+ mmc_signal_sdio_irq(host->mmc);
+ irq_reg &= ~JZ_MMC_IRQ_SDIO;
+ }
+
+ if (host->req && cmd && irq_reg) {
+ if (test_and_clear_bit(0, &host->waiting)) {
+ del_timer(&host->timeout_timer);
+
+ status = readl(host->base + JZ_REG_MMC_STATUS);
+
+ if (status & JZ_MMC_STATUS_TIMEOUT_RES) {
+ cmd->error = -ETIMEDOUT;
+ } else if (status & JZ_MMC_STATUS_CRC_RES_ERR) {
+ cmd->error = -EIO;
+ } else if (status & (JZ_MMC_STATUS_CRC_READ_ERROR |
+ JZ_MMC_STATUS_CRC_WRITE_ERROR)) {
+ if (cmd->data)
+ cmd->data->error = -EIO;
+ cmd->error = -EIO;
+ } else if (status & (JZ_MMC_STATUS_CRC_READ_ERROR |
+ JZ_MMC_STATUS_CRC_WRITE_ERROR)) {
+ if (cmd->data)
+ cmd->data->error = -EIO;
+ cmd->error = -EIO;
+ }
+
+ jz4740_mmc_set_irq_enabled(host, irq_reg, false);
+ writew(irq_reg, host->base + JZ_REG_MMC_IREG);
+
+ return IRQ_WAKE_THREAD;
+ }
+ }
+
+ return IRQ_HANDLED;
+}
+
+static int jz4740_mmc_set_clock_rate(struct jz4740_mmc_host *host, int rate)
+{
+ int div = 0;
+ int real_rate;
+
+ jz4740_mmc_clock_disable(host);
+ clk_set_rate(host->clk, JZ_MMC_CLK_RATE);
+
+ real_rate = clk_get_rate(host->clk);
+
+ while (real_rate > rate && div < 7) {
+ ++div;
+ real_rate >>= 1;
+ }
+
+ writew(div, host->base + JZ_REG_MMC_CLKRT);
+ return real_rate;
+}
+
+static void jz4740_mmc_request(struct mmc_host *mmc, struct mmc_request *req)
+{
+ struct jz4740_mmc_host *host = mmc_priv(mmc);
+
+ host->req = req;
+
+ writew(0xffff, host->base + JZ_REG_MMC_IREG);
+
+ writew(JZ_MMC_IRQ_END_CMD_RES, host->base + JZ_REG_MMC_IREG);
+ jz4740_mmc_set_irq_enabled(host, JZ_MMC_IRQ_END_CMD_RES, true);
+
+ host->state = JZ4740_MMC_STATE_READ_RESPONSE;
+ set_bit(0, &host->waiting);
+ mod_timer(&host->timeout_timer, jiffies + 5*HZ);
+ jz4740_mmc_send_command(host, req->cmd);
+}
+
+static void jz4740_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
+{
+ struct jz4740_mmc_host *host = mmc_priv(mmc);
+ if (ios->clock)
+ jz4740_mmc_set_clock_rate(host, ios->clock);
+
+ switch (ios->power_mode) {
+ case MMC_POWER_UP:
+ jz4740_mmc_reset(host);
+ if (gpio_is_valid(host->pdata->gpio_power))
+ gpio_set_value(host->pdata->gpio_power,
+ !host->pdata->power_active_low);
+ host->cmdat |= JZ_MMC_CMDAT_INIT;
+ clk_enable(host->clk);
+ break;
+ case MMC_POWER_ON:
+ break;
+ default:
+ if (gpio_is_valid(host->pdata->gpio_power))
+ gpio_set_value(host->pdata->gpio_power,
+ host->pdata->power_active_low);
+ clk_disable(host->clk);
+ break;
+ }
+
+ switch (ios->bus_width) {
+ case MMC_BUS_WIDTH_1:
+ host->cmdat &= ~JZ_MMC_CMDAT_BUS_WIDTH_4BIT;
+ break;
+ case MMC_BUS_WIDTH_4:
+ host->cmdat |= JZ_MMC_CMDAT_BUS_WIDTH_4BIT;
+ break;
+ default:
+ break;
+ }
+}
+
+static int jz4740_mmc_get_ro(struct mmc_host *mmc)
+{
+ struct jz4740_mmc_host *host = mmc_priv(mmc);
+ if (!gpio_is_valid(host->pdata->gpio_read_only))
+ return -ENOSYS;
+
+ return gpio_get_value(host->pdata->gpio_read_only) ^
+ host->pdata->read_only_active_low;
+}
+
+static int jz4740_mmc_get_cd(struct mmc_host *mmc)
+{
+ struct jz4740_mmc_host *host = mmc_priv(mmc);
+ if (!gpio_is_valid(host->pdata->gpio_card_detect))
+ return -ENOSYS;
+
+ return gpio_get_value(host->pdata->gpio_card_detect) ^
+ host->pdata->card_detect_active_low;
+}
+
+static irqreturn_t jz4740_mmc_card_detect_irq(int irq, void *devid)
+{
+ struct jz4740_mmc_host *host = devid;
+
+ mmc_detect_change(host->mmc, HZ / 2);
+
+ return IRQ_HANDLED;
+}
+
+static void jz4740_mmc_enable_sdio_irq(struct mmc_host *mmc, int enable)
+{
+ struct jz4740_mmc_host *host = mmc_priv(mmc);
+ jz4740_mmc_set_irq_enabled(host, JZ_MMC_IRQ_SDIO, enable);
+}
+
+static const struct mmc_host_ops jz4740_mmc_ops = {
+ .request = jz4740_mmc_request,
+ .set_ios = jz4740_mmc_set_ios,
+ .get_ro = jz4740_mmc_get_ro,
+ .get_cd = jz4740_mmc_get_cd,
+ .enable_sdio_irq = jz4740_mmc_enable_sdio_irq,
+};
+
+static const struct jz_gpio_bulk_request jz4740_mmc_pins[] = {
+ JZ_GPIO_BULK_PIN(MSC_CMD),
+ JZ_GPIO_BULK_PIN(MSC_CLK),
+ JZ_GPIO_BULK_PIN(MSC_DATA0),
+ JZ_GPIO_BULK_PIN(MSC_DATA1),
+ JZ_GPIO_BULK_PIN(MSC_DATA2),
+ JZ_GPIO_BULK_PIN(MSC_DATA3),
+};
+
+static int __devinit jz4740_mmc_request_gpio(struct device *dev, int gpio,
+ const char *name, bool output, int value)
+{
+ int ret;
+
+ if (!gpio_is_valid(gpio))
+ return 0;
+
+ ret = gpio_request(gpio, name);
+ if (ret) {
+ dev_err(dev, "Failed to request %s gpio: %d\n", name, ret);
+ return ret;
+ }
+
+ if (output)
+ gpio_direction_output(gpio, value);
+ else
+ gpio_direction_input(gpio);
+
+ return 0;
+}
+
+static int __devinit jz4740_mmc_request_gpios(struct platform_device *pdev)
+{
+ int ret;
+ struct jz4740_mmc_platform_data *pdata = pdev->dev.platform_data;
+
+ if (!pdata)
+ return 0;
+
+ ret = jz4740_mmc_request_gpio(&pdev->dev, pdata->gpio_card_detect,
+ "MMC detect change", false, 0);
+ if (ret)
+ goto err;
+
+ ret = jz4740_mmc_request_gpio(&pdev->dev, pdata->gpio_read_only,
+ "MMC read only", false, 0);
+ if (ret)
+ goto err_free_gpio_card_detect;
+
+ ret = jz4740_mmc_request_gpio(&pdev->dev, pdata->gpio_power,
+ "MMC read only", true, pdata->power_active_low);
+ if (ret)
+ goto err_free_gpio_read_only;
+
+ return 0;
+
+err_free_gpio_read_only:
+ if (gpio_is_valid(pdata->gpio_read_only))
+ gpio_free(pdata->gpio_read_only);
+err_free_gpio_card_detect:
+ if (gpio_is_valid(pdata->gpio_card_detect))
+ gpio_free(pdata->gpio_card_detect);
+err:
+ return ret;
+}
+
+static int __devinit jz4740_mmc_request_cd_irq(struct platform_device *pdev,
+ struct jz4740_mmc_host *host)
+{
+ struct jz4740_mmc_platform_data *pdata = pdev->dev.platform_data;
+
+ if (!gpio_is_valid(pdata->gpio_card_detect))
+ return 0;
+
+ host->card_detect_irq = gpio_to_irq(pdata->gpio_card_detect);
+ if (host->card_detect_irq < 0) {
+ dev_warn(&pdev->dev, "Failed to get card detect irq\n");
+ return 0;
+ }
+
+ return request_irq(host->card_detect_irq, jz4740_mmc_card_detect_irq,
+ IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
+ "MMC card detect", host);
+}
+
+static void jz4740_mmc_free_gpios(struct platform_device *pdev)
+{
+ struct jz4740_mmc_platform_data *pdata = pdev->dev.platform_data;
+
+ if (!pdata)
+ return;
+
+ if (gpio_is_valid(pdata->gpio_power))
+ gpio_free(pdata->gpio_power);
+ if (gpio_is_valid(pdata->gpio_read_only))
+ gpio_free(pdata->gpio_read_only);
+ if (gpio_is_valid(pdata->gpio_card_detect))
+ gpio_free(pdata->gpio_card_detect);
+}
+
+static inline size_t jz4740_mmc_num_pins(struct jz4740_mmc_host *host)
+{
+ size_t num_pins = ARRAY_SIZE(jz4740_mmc_pins);
+ if (host->pdata && host->pdata->data_1bit)
+ num_pins -= 3;
+
+ return num_pins;
+}
+
+static int __devinit jz4740_mmc_probe(struct platform_device* pdev)
+{
+ int ret;
+ struct mmc_host *mmc;
+ struct jz4740_mmc_host *host;
+ struct jz4740_mmc_platform_data *pdata;
+
+ pdata = pdev->dev.platform_data;
+
+ mmc = mmc_alloc_host(sizeof(struct jz4740_mmc_host), &pdev->dev);
+ if (!mmc) {
+ dev_err(&pdev->dev, "Failed to alloc mmc host structure\n");
+ return -ENOMEM;
+ }
+
+ host = mmc_priv(mmc);
+ host->pdata = pdata;
+
+ host->irq = platform_get_irq(pdev, 0);
+ if (host->irq < 0) {
+ ret = host->irq;
+ dev_err(&pdev->dev, "Failed to get platform irq: %d\n", ret);
+ goto err_free_host;
+ }
+
+ host->clk = clk_get(&pdev->dev, "mmc");
+ if (!host->clk) {
+ ret = -ENOENT;
+ dev_err(&pdev->dev, "Failed to get mmc clock\n");
+ goto err_free_host;
+ }
+
+ host->mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!host->mem) {
+ ret = -ENOENT;
+ dev_err(&pdev->dev, "Failed to get base platform memory\n");
+ goto err_clk_put;
+ }
+
+ host->mem = request_mem_region(host->mem->start,
+ resource_size(host->mem), pdev->name);
+ if (!host->mem) {
+ ret = -EBUSY;
+ dev_err(&pdev->dev, "Failed to request base memory region\n");
+ goto err_clk_put;
+ }
+
+ host->base = ioremap_nocache(host->mem->start, resource_size(host->mem));
+ if (!host->base) {
+ ret = -EBUSY;
+ dev_err(&pdev->dev, "Failed to ioremap base memory\n");
+ goto err_release_mem_region;
+ }
+
+ ret = jz_gpio_bulk_request(jz4740_mmc_pins, jz4740_mmc_num_pins(host));
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to request mmc pins: %d\n", ret);
+ goto err_iounmap;
+ }
+
+ ret = jz4740_mmc_request_gpios(pdev);
+ if (ret)
+ goto err_gpio_bulk_free;
+
+ mmc->ops = &jz4740_mmc_ops;
+ mmc->f_min = JZ_MMC_CLK_RATE / 128;
+ mmc->f_max = JZ_MMC_CLK_RATE;
+ mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
+ mmc->caps = (pdata && pdata->data_1bit) ? 0 : MMC_CAP_4_BIT_DATA;
+ mmc->caps |= MMC_CAP_SDIO_IRQ;
+
+ mmc->max_blk_size = (1 << 10) - 1;
+ mmc->max_blk_count = (1 << 15) - 1;
+ mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count;
+
+ mmc->max_phys_segs = 128;
+ mmc->max_hw_segs = 128;
+ mmc->max_seg_size = mmc->max_req_size;
+
+ host->mmc = mmc;
+ host->pdev = pdev;
+ spin_lock_init(&host->lock);
+ host->irq_mask = 0xffff;
+
+ ret = jz4740_mmc_request_cd_irq(pdev, host);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to request card detect irq\n");
+ goto err_free_gpios;
+ }
+
+ ret = request_threaded_irq(host->irq, jz_mmc_irq, jz_mmc_irq_worker, 0,
+ dev_name(&pdev->dev), host);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to request irq: %d\n", ret);
+ goto err_free_card_detect_irq;
+ }
+
+ jz4740_mmc_reset(host);
+ jz4740_mmc_clock_disable(host);
+ setup_timer(&host->timeout_timer, jz4740_mmc_timeout,
+ (unsigned long)host);
+ /* It is not important when it times out, it just needs to timeout. */
+ set_timer_slack(&host->timeout_timer, HZ);
+
+ platform_set_drvdata(pdev, host);
+ ret = mmc_add_host(mmc);
+
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to add mmc host: %d\n", ret);
+ goto err_free_irq;
+ }
+ dev_info(&pdev->dev, "JZ SD/MMC card driver registered\n");
+
+ return 0;
+
+err_free_irq:
+ free_irq(host->irq, host);
+err_free_card_detect_irq:
+ if (host->card_detect_irq >= 0)
+ free_irq(host->card_detect_irq, host);
+err_free_gpios:
+ jz4740_mmc_free_gpios(pdev);
+err_gpio_bulk_free:
+ jz_gpio_bulk_free(jz4740_mmc_pins, jz4740_mmc_num_pins(host));
+err_iounmap:
+ iounmap(host->base);
+err_release_mem_region:
+ release_mem_region(host->mem->start, resource_size(host->mem));
+err_clk_put:
+ clk_put(host->clk);
+err_free_host:
+ platform_set_drvdata(pdev, NULL);
+ mmc_free_host(mmc);
+
+ return ret;
+}
+
+static int __devexit jz4740_mmc_remove(struct platform_device *pdev)
+{
+ struct jz4740_mmc_host *host = platform_get_drvdata(pdev);
+
+ del_timer_sync(&host->timeout_timer);
+ jz4740_mmc_set_irq_enabled(host, 0xff, false);
+ jz4740_mmc_reset(host);
+
+ mmc_remove_host(host->mmc);
+
+ free_irq(host->irq, host);
+ if (host->card_detect_irq >= 0)
+ free_irq(host->card_detect_irq, host);
+
+ jz4740_mmc_free_gpios(pdev);
+ jz_gpio_bulk_free(jz4740_mmc_pins, jz4740_mmc_num_pins(host));
+
+ iounmap(host->base);
+ release_mem_region(host->mem->start, resource_size(host->mem));
+
+ clk_put(host->clk);
+
+ platform_set_drvdata(pdev, NULL);
+ mmc_free_host(host->mmc);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+
+static int jz4740_mmc_suspend(struct device *dev)
+{
+ struct jz4740_mmc_host *host = dev_get_drvdata(dev);
+
+ mmc_suspend_host(host->mmc);
+
+ jz_gpio_bulk_suspend(jz4740_mmc_pins, jz4740_mmc_num_pins(host));
+
+ return 0;
+}
+
+static int jz4740_mmc_resume(struct device *dev)
+{
+ struct jz4740_mmc_host *host = dev_get_drvdata(dev);
+
+ jz_gpio_bulk_resume(jz4740_mmc_pins, jz4740_mmc_num_pins(host));
+
+ mmc_resume_host(host->mmc);
+
+ return 0;
+}
+
+const struct dev_pm_ops jz4740_mmc_pm_ops = {
+ .suspend = jz4740_mmc_suspend,
+ .resume = jz4740_mmc_resume,
+ .poweroff = jz4740_mmc_suspend,
+ .restore = jz4740_mmc_resume,
+};
+
+#define JZ4740_MMC_PM_OPS (&jz4740_mmc_pm_ops)
+#else
+#define JZ4740_MMC_PM_OPS NULL
+#endif
+
+static struct platform_driver jz4740_mmc_driver = {
+ .probe = jz4740_mmc_probe,
+ .remove = __devexit_p(jz4740_mmc_remove),
+ .driver = {
+ .name = "jz4740-mmc",
+ .owner = THIS_MODULE,
+ .pm = JZ4740_MMC_PM_OPS,
+ },
+};
+
+static int __init jz4740_mmc_init(void)
+{
+ return platform_driver_register(&jz4740_mmc_driver);
+}
+module_init(jz4740_mmc_init);
+
+static void __exit jz4740_mmc_exit(void)
+{
+ platform_driver_unregister(&jz4740_mmc_driver);
+}
+module_exit(jz4740_mmc_exit);
+
+MODULE_DESCRIPTION("JZ4740 SD/MMC controller driver");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
diff --git a/drivers/mmc/host/mmc_spi.c b/drivers/mmc/host/mmc_spi.c
index ad847a24a67..7b0f3ef50f9 100644
--- a/drivers/mmc/host/mmc_spi.c
+++ b/drivers/mmc/host/mmc_spi.c
@@ -1533,12 +1533,20 @@ static int __devexit mmc_spi_remove(struct spi_device *spi)
return 0;
}
+#if defined(CONFIG_OF)
+static struct of_device_id mmc_spi_of_match_table[] __devinitdata = {
+ { .compatible = "mmc-spi-slot", },
+};
+#endif
static struct spi_driver mmc_spi_driver = {
.driver = {
.name = "mmc_spi",
.bus = &spi_bus_type,
.owner = THIS_MODULE,
+#if defined(CONFIG_OF)
+ .of_match_table = mmc_spi_of_match_table,
+#endif
},
.probe = mmc_spi_probe,
.remove = __devexit_p(mmc_spi_remove),
diff --git a/drivers/mmc/host/sdricoh_cs.c b/drivers/mmc/host/sdricoh_cs.c
index e7507af3856..7aa65bb2af4 100644
--- a/drivers/mmc/host/sdricoh_cs.c
+++ b/drivers/mmc/host/sdricoh_cs.c
@@ -30,7 +30,6 @@
#include <linux/ioport.h>
#include <linux/scatterlist.h>
-#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/cistpl.h>
#include <pcmcia/ds.h>
diff --git a/drivers/mtd/maps/Kconfig b/drivers/mtd/maps/Kconfig
index f22bc9f05dd..6629d09f3b3 100644
--- a/drivers/mtd/maps/Kconfig
+++ b/drivers/mtd/maps/Kconfig
@@ -321,7 +321,7 @@ config MTD_CFI_FLAGADM
config MTD_REDWOOD
tristate "CFI Flash devices mapped on IBM Redwood"
- depends on MTD_CFI && ( REDWOOD_4 || REDWOOD_5 || REDWOOD_6 )
+ depends on MTD_CFI
help
This enables access routines for the flash chips on the IBM
Redwood board. If you have one of these boards and would like to
diff --git a/drivers/mtd/maps/pcmciamtd.c b/drivers/mtd/maps/pcmciamtd.c
index e699e6ac23d..e9ca5ba7d9d 100644
--- a/drivers/mtd/maps/pcmciamtd.c
+++ b/drivers/mtd/maps/pcmciamtd.c
@@ -16,7 +16,6 @@
#include <asm/io.h>
#include <asm/system.h>
-#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/cistpl.h>
#include <pcmcia/ds.h>
@@ -103,7 +102,7 @@ static caddr_t remap_window(struct map_info *map, unsigned long to)
{
struct pcmciamtd_dev *dev = (struct pcmciamtd_dev *)map->map_priv_1;
window_handle_t win = (window_handle_t)map->map_priv_2;
- memreq_t mrq;
+ unsigned int offset;
int ret;
if (!pcmcia_dev_present(dev->p_dev)) {
@@ -111,15 +110,14 @@ static caddr_t remap_window(struct map_info *map, unsigned long to)
return 0;
}
- mrq.CardOffset = to & ~(dev->win_size-1);
- if(mrq.CardOffset != dev->offset) {
+ offset = to & ~(dev->win_size-1);
+ if (offset != dev->offset) {
DEBUG(2, "Remapping window from 0x%8.8x to 0x%8.8x",
- dev->offset, mrq.CardOffset);
- mrq.Page = 0;
- ret = pcmcia_map_mem_page(dev->p_dev, win, &mrq);
+ dev->offset, offset);
+ ret = pcmcia_map_mem_page(dev->p_dev, win, offset);
if (ret != 0)
return NULL;
- dev->offset = mrq.CardOffset;
+ dev->offset = offset;
}
return dev->win_base + (to & (dev->win_size-1));
}
@@ -346,7 +344,6 @@ static void pcmciamtd_release(struct pcmcia_device *link)
iounmap(dev->win_base);
dev->win_base = NULL;
}
- pcmcia_release_window(link, link->win);
}
pcmcia_disable_device(link);
}
diff --git a/drivers/mtd/maps/redwood.c b/drivers/mtd/maps/redwood.c
index 933c0b63b01..d2c9db00db0 100644
--- a/drivers/mtd/maps/redwood.c
+++ b/drivers/mtd/maps/redwood.c
@@ -22,8 +22,6 @@
#include <asm/io.h>
-#if !defined (CONFIG_REDWOOD_6)
-
#define WINDOW_ADDR 0xffc00000
#define WINDOW_SIZE 0x00400000
@@ -69,47 +67,6 @@ static struct mtd_partition redwood_flash_partitions[] = {
}
};
-#else /* CONFIG_REDWOOD_6 */
-/* FIXME: the window is bigger - armin */
-#define WINDOW_ADDR 0xff800000
-#define WINDOW_SIZE 0x00800000
-
-#define RW_PART0_OF 0
-#define RW_PART0_SZ 0x400000 /* 4 MiB data */
-#define RW_PART1_OF RW_PART0_OF + RW_PART0_SZ
-#define RW_PART1_SZ 0x10000 /* 64K VPD */
-#define RW_PART2_OF RW_PART1_OF + RW_PART1_SZ
-#define RW_PART2_SZ 0x400000 - (0x10000 + 0x20000)
-#define RW_PART3_OF RW_PART2_OF + RW_PART2_SZ
-#define RW_PART3_SZ 0x20000
-
-static struct mtd_partition redwood_flash_partitions[] = {
- {
- .name = "Redwood filesystem",
- .offset = RW_PART0_OF,
- .size = RW_PART0_SZ
- },
- {
- .name = "Redwood OpenBIOS Vital Product Data",
- .offset = RW_PART1_OF,
- .size = RW_PART1_SZ,
- .mask_flags = MTD_WRITEABLE /* force read-only */
- },
- {
- .name = "Redwood kernel",
- .offset = RW_PART2_OF,
- .size = RW_PART2_SZ
- },
- {
- .name = "Redwood OpenBIOS",
- .offset = RW_PART3_OF,
- .size = RW_PART3_SZ,
- .mask_flags = MTD_WRITEABLE /* force read-only */
- }
-};
-
-#endif /* CONFIG_REDWOOD_6 */
-
struct map_info redwood_flash_map = {
.name = "IBM Redwood",
.size = WINDOW_SIZE,
diff --git a/drivers/mtd/maps/sun_uflash.c b/drivers/mtd/maps/sun_uflash.c
index 0391c2527bd..8984236a8d0 100644
--- a/drivers/mtd/maps/sun_uflash.c
+++ b/drivers/mtd/maps/sun_uflash.c
@@ -160,12 +160,12 @@ static struct of_platform_driver uflash_driver = {
static int __init uflash_init(void)
{
- return of_register_driver(&uflash_driver, &of_bus_type);
+ return of_register_platform_driver(&uflash_driver);
}
static void __exit uflash_exit(void)
{
- of_unregister_driver(&uflash_driver);
+ of_unregister_platform_driver(&uflash_driver);
}
module_init(uflash_init);
diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig
index ffc3720929f..362d177efe1 100644
--- a/drivers/mtd/nand/Kconfig
+++ b/drivers/mtd/nand/Kconfig
@@ -526,4 +526,10 @@ config MTD_NAND_NUC900
This enables the driver for the NAND Flash on evaluation board based
on w90p910 / NUC9xx.
+config MTD_NAND_JZ4740
+ tristate "Support for JZ4740 SoC NAND controller"
+ depends on MACH_JZ4740
+ help
+ Enables support for NAND Flash on JZ4740 SoC based boards.
+
endif # MTD_NAND
diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile
index e8ab884ba47..ac83dcdac5d 100644
--- a/drivers/mtd/nand/Makefile
+++ b/drivers/mtd/nand/Makefile
@@ -46,5 +46,6 @@ obj-$(CONFIG_MTD_NAND_NOMADIK) += nomadik_nand.o
obj-$(CONFIG_MTD_NAND_BCM_UMI) += bcm_umi_nand.o nand_bcm_umi.o
obj-$(CONFIG_MTD_NAND_MPC5121_NFC) += mpc5121_nfc.o
obj-$(CONFIG_MTD_NAND_RICOH) += r852.o
+obj-$(CONFIG_MTD_NAND_JZ4740) += jz4740_nand.o
nand-objs := nand_base.o nand_bbt.o
diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c
index ca03428b59c..3dfda9cc677 100644
--- a/drivers/mtd/nand/denali.c
+++ b/drivers/mtd/nand/denali.c
@@ -1836,7 +1836,7 @@ static struct nand_bbt_descr bbt_mirror_descr = {
.pattern = mirror_pattern,
};
-/* initalize driver data structures */
+/* initialize driver data structures */
void denali_drv_init(struct denali_nand_info *denali)
{
denali->idx = 0;
diff --git a/drivers/mtd/nand/jz4740_nand.c b/drivers/mtd/nand/jz4740_nand.c
new file mode 100644
index 00000000000..67343fc31bd
--- /dev/null
+++ b/drivers/mtd/nand/jz4740_nand.c
@@ -0,0 +1,516 @@
+/*
+ * Copyright (C) 2009-2010, Lars-Peter Clausen <lars@metafoo.de>
+ * JZ4740 SoC NAND controller 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.
+ *
+ * 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/ioport.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/partitions.h>
+
+#include <linux/gpio.h>
+
+#include <asm/mach-jz4740/jz4740_nand.h>
+
+#define JZ_REG_NAND_CTRL 0x50
+#define JZ_REG_NAND_ECC_CTRL 0x100
+#define JZ_REG_NAND_DATA 0x104
+#define JZ_REG_NAND_PAR0 0x108
+#define JZ_REG_NAND_PAR1 0x10C
+#define JZ_REG_NAND_PAR2 0x110
+#define JZ_REG_NAND_IRQ_STAT 0x114
+#define JZ_REG_NAND_IRQ_CTRL 0x118
+#define JZ_REG_NAND_ERR(x) (0x11C + ((x) << 2))
+
+#define JZ_NAND_ECC_CTRL_PAR_READY BIT(4)
+#define JZ_NAND_ECC_CTRL_ENCODING BIT(3)
+#define JZ_NAND_ECC_CTRL_RS BIT(2)
+#define JZ_NAND_ECC_CTRL_RESET BIT(1)
+#define JZ_NAND_ECC_CTRL_ENABLE BIT(0)
+
+#define JZ_NAND_STATUS_ERR_COUNT (BIT(31) | BIT(30) | BIT(29))
+#define JZ_NAND_STATUS_PAD_FINISH BIT(4)
+#define JZ_NAND_STATUS_DEC_FINISH BIT(3)
+#define JZ_NAND_STATUS_ENC_FINISH BIT(2)
+#define JZ_NAND_STATUS_UNCOR_ERROR BIT(1)
+#define JZ_NAND_STATUS_ERROR BIT(0)
+
+#define JZ_NAND_CTRL_ENABLE_CHIP(x) BIT((x) << 1)
+#define JZ_NAND_CTRL_ASSERT_CHIP(x) BIT(((x) << 1) + 1)
+
+#define JZ_NAND_MEM_ADDR_OFFSET 0x10000
+#define JZ_NAND_MEM_CMD_OFFSET 0x08000
+
+struct jz_nand {
+ struct mtd_info mtd;
+ struct nand_chip chip;
+ void __iomem *base;
+ struct resource *mem;
+
+ void __iomem *bank_base;
+ struct resource *bank_mem;
+
+ struct jz_nand_platform_data *pdata;
+ bool is_reading;
+};
+
+static inline struct jz_nand *mtd_to_jz_nand(struct mtd_info *mtd)
+{
+ return container_of(mtd, struct jz_nand, mtd);
+}
+
+static void jz_nand_cmd_ctrl(struct mtd_info *mtd, int dat, unsigned int ctrl)
+{
+ struct jz_nand *nand = mtd_to_jz_nand(mtd);
+ struct nand_chip *chip = mtd->priv;
+ uint32_t reg;
+
+ if (ctrl & NAND_CTRL_CHANGE) {
+ BUG_ON((ctrl & NAND_ALE) && (ctrl & NAND_CLE));
+ if (ctrl & NAND_ALE)
+ chip->IO_ADDR_W = nand->bank_base + JZ_NAND_MEM_ADDR_OFFSET;
+ else if (ctrl & NAND_CLE)
+ chip->IO_ADDR_W = nand->bank_base + JZ_NAND_MEM_CMD_OFFSET;
+ else
+ chip->IO_ADDR_W = nand->bank_base;
+
+ reg = readl(nand->base + JZ_REG_NAND_CTRL);
+ if (ctrl & NAND_NCE)
+ reg |= JZ_NAND_CTRL_ASSERT_CHIP(0);
+ else
+ reg &= ~JZ_NAND_CTRL_ASSERT_CHIP(0);
+ writel(reg, nand->base + JZ_REG_NAND_CTRL);
+ }
+ if (dat != NAND_CMD_NONE)
+ writeb(dat, chip->IO_ADDR_W);
+}
+
+static int jz_nand_dev_ready(struct mtd_info *mtd)
+{
+ struct jz_nand *nand = mtd_to_jz_nand(mtd);
+ return gpio_get_value_cansleep(nand->pdata->busy_gpio);
+}
+
+static void jz_nand_hwctl(struct mtd_info *mtd, int mode)
+{
+ struct jz_nand *nand = mtd_to_jz_nand(mtd);
+ uint32_t reg;
+
+ writel(0, nand->base + JZ_REG_NAND_IRQ_STAT);
+ reg = readl(nand->base + JZ_REG_NAND_ECC_CTRL);
+
+ reg |= JZ_NAND_ECC_CTRL_RESET;
+ reg |= JZ_NAND_ECC_CTRL_ENABLE;
+ reg |= JZ_NAND_ECC_CTRL_RS;
+
+ switch (mode) {
+ case NAND_ECC_READ:
+ reg &= ~JZ_NAND_ECC_CTRL_ENCODING;
+ nand->is_reading = true;
+ break;
+ case NAND_ECC_WRITE:
+ reg |= JZ_NAND_ECC_CTRL_ENCODING;
+ nand->is_reading = false;
+ break;
+ default:
+ break;
+ }
+
+ writel(reg, nand->base + JZ_REG_NAND_ECC_CTRL);
+}
+
+static int jz_nand_calculate_ecc_rs(struct mtd_info *mtd, const uint8_t *dat,
+ uint8_t *ecc_code)
+{
+ struct jz_nand *nand = mtd_to_jz_nand(mtd);
+ uint32_t reg, status;
+ int i;
+ unsigned int timeout = 1000;
+ static uint8_t empty_block_ecc[] = {0xcd, 0x9d, 0x90, 0x58, 0xf4,
+ 0x8b, 0xff, 0xb7, 0x6f};
+
+ if (nand->is_reading)
+ return 0;
+
+ do {
+ status = readl(nand->base + JZ_REG_NAND_IRQ_STAT);
+ } while (!(status & JZ_NAND_STATUS_ENC_FINISH) && --timeout);
+
+ if (timeout == 0)
+ return -1;
+
+ reg = readl(nand->base + JZ_REG_NAND_ECC_CTRL);
+ reg &= ~JZ_NAND_ECC_CTRL_ENABLE;
+ writel(reg, nand->base + JZ_REG_NAND_ECC_CTRL);
+
+ for (i = 0; i < 9; ++i)
+ ecc_code[i] = readb(nand->base + JZ_REG_NAND_PAR0 + i);
+
+ /* If the written data is completly 0xff, we also want to write 0xff as
+ * ecc, otherwise we will get in trouble when doing subpage writes. */
+ if (memcmp(ecc_code, empty_block_ecc, 9) == 0)
+ memset(ecc_code, 0xff, 9);
+
+ return 0;
+}
+
+static void jz_nand_correct_data(uint8_t *dat, int index, int mask)
+{
+ int offset = index & 0x7;
+ uint16_t data;
+
+ index += (index >> 3);
+
+ data = dat[index];
+ data |= dat[index+1] << 8;
+
+ mask ^= (data >> offset) & 0x1ff;
+ data &= ~(0x1ff << offset);
+ data |= (mask << offset);
+
+ dat[index] = data & 0xff;
+ dat[index+1] = (data >> 8) & 0xff;
+}
+
+static int jz_nand_correct_ecc_rs(struct mtd_info *mtd, uint8_t *dat,
+ uint8_t *read_ecc, uint8_t *calc_ecc)
+{
+ struct jz_nand *nand = mtd_to_jz_nand(mtd);
+ int i, error_count, index;
+ uint32_t reg, status, error;
+ uint32_t t;
+ unsigned int timeout = 1000;
+
+ t = read_ecc[0];
+
+ if (t == 0xff) {
+ for (i = 1; i < 9; ++i)
+ t &= read_ecc[i];
+
+ t &= dat[0];
+ t &= dat[nand->chip.ecc.size / 2];
+ t &= dat[nand->chip.ecc.size - 1];
+
+ if (t == 0xff) {
+ for (i = 1; i < nand->chip.ecc.size - 1; ++i)
+ t &= dat[i];
+ if (t == 0xff)
+ return 0;
+ }
+ }
+
+ for (i = 0; i < 9; ++i)
+ writeb(read_ecc[i], nand->base + JZ_REG_NAND_PAR0 + i);
+
+ reg = readl(nand->base + JZ_REG_NAND_ECC_CTRL);
+ reg |= JZ_NAND_ECC_CTRL_PAR_READY;
+ writel(reg, nand->base + JZ_REG_NAND_ECC_CTRL);
+
+ do {
+ status = readl(nand->base + JZ_REG_NAND_IRQ_STAT);
+ } while (!(status & JZ_NAND_STATUS_DEC_FINISH) && --timeout);
+
+ if (timeout == 0)
+ return -1;
+
+ reg = readl(nand->base + JZ_REG_NAND_ECC_CTRL);
+ reg &= ~JZ_NAND_ECC_CTRL_ENABLE;
+ writel(reg, nand->base + JZ_REG_NAND_ECC_CTRL);
+
+ if (status & JZ_NAND_STATUS_ERROR) {
+ if (status & JZ_NAND_STATUS_UNCOR_ERROR)
+ return -1;
+
+ error_count = (status & JZ_NAND_STATUS_ERR_COUNT) >> 29;
+
+ for (i = 0; i < error_count; ++i) {
+ error = readl(nand->base + JZ_REG_NAND_ERR(i));
+ index = ((error >> 16) & 0x1ff) - 1;
+ if (index >= 0 && index < 512)
+ jz_nand_correct_data(dat, index, error & 0x1ff);
+ }
+
+ return error_count;
+ }
+
+ return 0;
+}
+
+
+/* Copy paste of nand_read_page_hwecc_oob_first except for different eccpos
+ * handling. The ecc area is for 4k chips 72 bytes long and thus does not fit
+ * into the eccpos array. */
+static int jz_nand_read_page_hwecc_oob_first(struct mtd_info *mtd,
+ struct nand_chip *chip, uint8_t *buf, int page)
+{
+ int i, eccsize = chip->ecc.size;
+ int eccbytes = chip->ecc.bytes;
+ int eccsteps = chip->ecc.steps;
+ uint8_t *p = buf;
+ unsigned int ecc_offset = chip->page_shift;
+
+ /* Read the OOB area first */
+ chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page);
+ chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
+ chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page);
+
+ for (i = ecc_offset; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
+ int stat;
+
+ chip->ecc.hwctl(mtd, NAND_ECC_READ);
+ chip->read_buf(mtd, p, eccsize);
+
+ stat = chip->ecc.correct(mtd, p, &chip->oob_poi[i], NULL);
+ if (stat < 0)
+ mtd->ecc_stats.failed++;
+ else
+ mtd->ecc_stats.corrected += stat;
+ }
+ return 0;
+}
+
+/* Copy-and-paste of nand_write_page_hwecc with different eccpos handling. */
+static void jz_nand_write_page_hwecc(struct mtd_info *mtd,
+ struct nand_chip *chip, const uint8_t *buf)
+{
+ int i, eccsize = chip->ecc.size;
+ int eccbytes = chip->ecc.bytes;
+ int eccsteps = chip->ecc.steps;
+ const uint8_t *p = buf;
+ unsigned int ecc_offset = chip->page_shift;
+
+ for (i = ecc_offset; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
+ chip->ecc.hwctl(mtd, NAND_ECC_WRITE);
+ chip->write_buf(mtd, p, eccsize);
+ chip->ecc.calculate(mtd, p, &chip->oob_poi[i]);
+ }
+
+ chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
+}
+
+#ifdef CONFIG_MTD_CMDLINE_PARTS
+static const char *part_probes[] = {"cmdline", NULL};
+#endif
+
+static int jz_nand_ioremap_resource(struct platform_device *pdev,
+ const char *name, struct resource **res, void __iomem **base)
+{
+ int ret;
+
+ *res = platform_get_resource_byname(pdev, IORESOURCE_MEM, name);
+ if (!*res) {
+ dev_err(&pdev->dev, "Failed to get platform %s memory\n", name);
+ ret = -ENXIO;
+ goto err;
+ }
+
+ *res = request_mem_region((*res)->start, resource_size(*res),
+ pdev->name);
+ if (!*res) {
+ dev_err(&pdev->dev, "Failed to request %s memory region\n", name);
+ ret = -EBUSY;
+ goto err;
+ }
+
+ *base = ioremap((*res)->start, resource_size(*res));
+ if (!*base) {
+ dev_err(&pdev->dev, "Failed to ioremap %s memory region\n", name);
+ ret = -EBUSY;
+ goto err_release_mem;
+ }
+
+ return 0;
+
+err_release_mem:
+ release_mem_region((*res)->start, resource_size(*res));
+err:
+ *res = NULL;
+ *base = NULL;
+ return ret;
+}
+
+static int __devinit jz_nand_probe(struct platform_device *pdev)
+{
+ int ret;
+ struct jz_nand *nand;
+ struct nand_chip *chip;
+ struct mtd_info *mtd;
+ struct jz_nand_platform_data *pdata = pdev->dev.platform_data;
+#ifdef CONFIG_MTD_PARTITIONS
+ struct mtd_partition *partition_info;
+ int num_partitions = 0;
+#endif
+
+ nand = kzalloc(sizeof(*nand), GFP_KERNEL);
+ if (!nand) {
+ dev_err(&pdev->dev, "Failed to allocate device structure.\n");
+ return -ENOMEM;
+ }
+
+ ret = jz_nand_ioremap_resource(pdev, "mmio", &nand->mem, &nand->base);
+ if (ret)
+ goto err_free;
+ ret = jz_nand_ioremap_resource(pdev, "bank", &nand->bank_mem,
+ &nand->bank_base);
+ if (ret)
+ goto err_iounmap_mmio;
+
+ if (pdata && gpio_is_valid(pdata->busy_gpio)) {
+ ret = gpio_request(pdata->busy_gpio, "NAND busy pin");
+ if (ret) {
+ dev_err(&pdev->dev,
+ "Failed to request busy gpio %d: %d\n",
+ pdata->busy_gpio, ret);
+ goto err_iounmap_mem;
+ }
+ }
+
+ mtd = &nand->mtd;
+ chip = &nand->chip;
+ mtd->priv = chip;
+ mtd->owner = THIS_MODULE;
+ mtd->name = "jz4740-nand";
+
+ chip->ecc.hwctl = jz_nand_hwctl;
+ chip->ecc.calculate = jz_nand_calculate_ecc_rs;
+ chip->ecc.correct = jz_nand_correct_ecc_rs;
+ chip->ecc.mode = NAND_ECC_HW_OOB_FIRST;
+ chip->ecc.size = 512;
+ chip->ecc.bytes = 9;
+
+ chip->ecc.read_page = jz_nand_read_page_hwecc_oob_first;
+ chip->ecc.write_page = jz_nand_write_page_hwecc;
+
+ if (pdata)
+ chip->ecc.layout = pdata->ecc_layout;
+
+ chip->chip_delay = 50;
+ chip->cmd_ctrl = jz_nand_cmd_ctrl;
+
+ if (pdata && gpio_is_valid(pdata->busy_gpio))
+ chip->dev_ready = jz_nand_dev_ready;
+
+ chip->IO_ADDR_R = nand->bank_base;
+ chip->IO_ADDR_W = nand->bank_base;
+
+ nand->pdata = pdata;
+ platform_set_drvdata(pdev, nand);
+
+ writel(JZ_NAND_CTRL_ENABLE_CHIP(0), nand->base + JZ_REG_NAND_CTRL);
+
+ ret = nand_scan_ident(mtd, 1, NULL);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to scan nand\n");
+ goto err_gpio_free;
+ }
+
+ if (pdata && pdata->ident_callback) {
+ pdata->ident_callback(pdev, chip, &pdata->partitions,
+ &pdata->num_partitions);
+ }
+
+ ret = nand_scan_tail(mtd);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to scan nand\n");
+ goto err_gpio_free;
+ }
+
+#ifdef CONFIG_MTD_PARTITIONS
+#ifdef CONFIG_MTD_CMDLINE_PARTS
+ num_partitions = parse_mtd_partitions(mtd, part_probes,
+ &partition_info, 0);
+#endif
+ if (num_partitions <= 0 && pdata) {
+ num_partitions = pdata->num_partitions;
+ partition_info = pdata->partitions;
+ }
+
+ if (num_partitions > 0)
+ ret = add_mtd_partitions(mtd, partition_info, num_partitions);
+ else
+#endif
+ ret = add_mtd_device(mtd);
+
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to add mtd device\n");
+ goto err_nand_release;
+ }
+
+ dev_info(&pdev->dev, "Successfully registered JZ4740 NAND driver\n");
+
+ return 0;
+
+err_nand_release:
+ nand_release(&nand->mtd);
+err_gpio_free:
+ platform_set_drvdata(pdev, NULL);
+ gpio_free(pdata->busy_gpio);
+err_iounmap_mem:
+ iounmap(nand->bank_base);
+err_iounmap_mmio:
+ iounmap(nand->base);
+err_free:
+ kfree(nand);
+ return ret;
+}
+
+static int __devexit jz_nand_remove(struct platform_device *pdev)
+{
+ struct jz_nand *nand = platform_get_drvdata(pdev);
+
+ nand_release(&nand->mtd);
+
+ /* Deassert and disable all chips */
+ writel(0, nand->base + JZ_REG_NAND_CTRL);
+
+ iounmap(nand->bank_base);
+ release_mem_region(nand->bank_mem->start, resource_size(nand->bank_mem));
+ iounmap(nand->base);
+ release_mem_region(nand->mem->start, resource_size(nand->mem));
+
+ platform_set_drvdata(pdev, NULL);
+ kfree(nand);
+
+ return 0;
+}
+
+struct platform_driver jz_nand_driver = {
+ .probe = jz_nand_probe,
+ .remove = __devexit_p(jz_nand_remove),
+ .driver = {
+ .name = "jz4740-nand",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init jz_nand_init(void)
+{
+ return platform_driver_register(&jz_nand_driver);
+}
+module_init(jz_nand_init);
+
+static void __exit jz_nand_exit(void)
+{
+ platform_driver_unregister(&jz_nand_driver);
+}
+module_exit(jz_nand_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
+MODULE_DESCRIPTION("NAND controller driver for JZ4740 SoC");
+MODULE_ALIAS("platform:jz4740-nand");
diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c
index 13b05cb33b0..78ae89488a4 100644
--- a/drivers/mtd/ubi/build.c
+++ b/drivers/mtd/ubi/build.c
@@ -593,6 +593,7 @@ static int attach_by_scanning(struct ubi_device *ubi)
ubi->good_peb_count = ubi->peb_count - ubi->bad_peb_count;
ubi->max_ec = si->max_ec;
ubi->mean_ec = si->mean_ec;
+ ubi_msg("max. sequence number: %llu", si->max_sqnum);
err = ubi_read_volume_table(ubi, si);
if (err)
@@ -981,7 +982,7 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, int vid_hdr_offset)
ubi_msg("number of PEBs reserved for bad PEB handling: %d",
ubi->beb_rsvd_pebs);
ubi_msg("max/mean erase counter: %d/%d", ubi->max_ec, ubi->mean_ec);
- ubi_msg("image sequence number: %d", ubi->image_seq);
+ ubi_msg("image sequence number: %d", ubi->image_seq);
/*
* The below lock makes sure we do not race with 'ubi_thread()' which
diff --git a/drivers/mtd/ubi/eba.c b/drivers/mtd/ubi/eba.c
index 9f87c99189a..fe74749e0da 100644
--- a/drivers/mtd/ubi/eba.c
+++ b/drivers/mtd/ubi/eba.c
@@ -418,7 +418,8 @@ retry:
* may try to recover data. FIXME: but this is
* not implemented.
*/
- if (err == UBI_IO_BAD_VID_HDR) {
+ if (err == UBI_IO_BAD_HDR_READ ||
+ err == UBI_IO_BAD_HDR) {
ubi_warn("corrupted VID header at PEB "
"%d, LEB %d:%d", pnum, vol_id,
lnum);
@@ -961,8 +962,8 @@ write_error:
*/
static int is_error_sane(int err)
{
- if (err == -EIO || err == -ENOMEM || err == UBI_IO_BAD_VID_HDR ||
- err == -ETIMEDOUT)
+ if (err == -EIO || err == -ENOMEM || err == UBI_IO_BAD_HDR ||
+ err == UBI_IO_BAD_HDR_READ || err == -ETIMEDOUT)
return 0;
return 1;
}
@@ -1165,6 +1166,44 @@ out_unlock_leb:
}
/**
+ * print_rsvd_warning - warn about not having enough reserved PEBs.
+ * @ubi: UBI device description object
+ *
+ * This is a helper function for 'ubi_eba_init_scan()' which is called when UBI
+ * cannot reserve enough PEBs for bad block handling. This function makes a
+ * decision whether we have to print a warning or not. The algorithm is as
+ * follows:
+ * o if this is a new UBI image, then just print the warning
+ * o if this is an UBI image which has already been used for some time, print
+ * a warning only if we can reserve less than 10% of the expected amount of
+ * the reserved PEB.
+ *
+ * The idea is that when UBI is used, PEBs become bad, and the reserved pool
+ * of PEBs becomes smaller, which is normal and we do not want to scare users
+ * with a warning every time they attach the MTD device. This was an issue
+ * reported by real users.
+ */
+static void print_rsvd_warning(struct ubi_device *ubi,
+ struct ubi_scan_info *si)
+{
+ /*
+ * The 1 << 18 (256KiB) number is picked randomly, just a reasonably
+ * large number to distinguish between newly flashed and used images.
+ */
+ if (si->max_sqnum > (1 << 18)) {
+ int min = ubi->beb_rsvd_level / 10;
+
+ if (!min)
+ min = 1;
+ if (ubi->beb_rsvd_pebs > min)
+ return;
+ }
+
+ ubi_warn("cannot reserve enough PEBs for bad PEB handling, reserved %d,"
+ " need %d", ubi->beb_rsvd_pebs, ubi->beb_rsvd_level);
+}
+
+/**
* ubi_eba_init_scan - initialize the EBA sub-system using scanning information.
* @ubi: UBI device description object
* @si: scanning information
@@ -1236,9 +1275,7 @@ int ubi_eba_init_scan(struct ubi_device *ubi, struct ubi_scan_info *si)
if (ubi->avail_pebs < ubi->beb_rsvd_level) {
/* No enough free physical eraseblocks */
ubi->beb_rsvd_pebs = ubi->avail_pebs;
- ubi_warn("cannot reserve enough PEBs for bad PEB "
- "handling, reserved %d, need %d",
- ubi->beb_rsvd_pebs, ubi->beb_rsvd_level);
+ print_rsvd_warning(ubi, si);
} else
ubi->beb_rsvd_pebs = ubi->beb_rsvd_level;
diff --git a/drivers/mtd/ubi/io.c b/drivers/mtd/ubi/io.c
index 4b979e34b15..332f992f13d 100644
--- a/drivers/mtd/ubi/io.c
+++ b/drivers/mtd/ubi/io.c
@@ -150,6 +150,8 @@ int ubi_io_read(const struct ubi_device *ubi, void *buf, int pnum, int offset,
retry:
err = ubi->mtd->read(ubi->mtd, addr, len, &read, buf);
if (err) {
+ const char *errstr = (err == -EBADMSG) ? " (ECC error)" : "";
+
if (err == -EUCLEAN) {
/*
* -EUCLEAN is reported if there was a bit-flip which
@@ -165,15 +167,15 @@ retry:
}
if (read != len && retries++ < UBI_IO_RETRIES) {
- dbg_io("error %d while reading %d bytes from PEB %d:%d,"
+ dbg_io("error %d%s while reading %d bytes from PEB %d:%d,"
" read only %zd bytes, retry",
- err, len, pnum, offset, read);
+ err, errstr, len, pnum, offset, read);
yield();
goto retry;
}
- ubi_err("error %d while reading %d bytes from PEB %d:%d, "
- "read %zd bytes", err, len, pnum, offset, read);
+ ubi_err("error %d%s while reading %d bytes from PEB %d:%d, "
+ "read %zd bytes", err, errstr, len, pnum, offset, read);
ubi_dbg_dump_stack();
/*
@@ -515,7 +517,7 @@ static int nor_erase_prepare(struct ubi_device *ubi, int pnum)
* In this case we probably anyway have garbage in this PEB.
*/
err1 = ubi_io_read_vid_hdr(ubi, pnum, &vid_hdr, 0);
- if (err1 == UBI_IO_BAD_VID_HDR)
+ if (err1 == UBI_IO_BAD_HDR_READ || err1 == UBI_IO_BAD_HDR)
/*
* The VID header is corrupted, so we can safely erase this
* PEB and not afraid that it will be treated as a valid PEB in
@@ -709,7 +711,7 @@ bad:
* o %UBI_IO_BITFLIPS if the CRC is correct, but bit-flips were detected
* and corrected by the flash driver; this is harmless but may indicate that
* this eraseblock may become bad soon (but may be not);
- * o %UBI_IO_BAD_EC_HDR if the erase counter header is corrupted (a CRC error);
+ * o %UBI_IO_BAD_HDR if the erase counter header is corrupted (a CRC error);
* o %UBI_IO_PEB_EMPTY if the physical eraseblock is empty;
* o a negative error code in case of failure.
*/
@@ -736,23 +738,21 @@ int ubi_io_read_ec_hdr(struct ubi_device *ubi, int pnum,
* header is still OK, we just report this as there was a
* bit-flip.
*/
- read_err = err;
+ if (err == -EBADMSG)
+ read_err = UBI_IO_BAD_HDR_READ;
}
magic = be32_to_cpu(ec_hdr->magic);
if (magic != UBI_EC_HDR_MAGIC) {
+ if (read_err)
+ return read_err;
+
/*
* The magic field is wrong. Let's check if we have read all
* 0xFF. If yes, this physical eraseblock is assumed to be
* empty.
- *
- * But if there was a read error, we do not test it for all
- * 0xFFs. Even if it does contain all 0xFFs, this error
- * indicates that something is still wrong with this physical
- * eraseblock and we anyway cannot treat it as empty.
*/
- if (read_err != -EBADMSG &&
- check_pattern(ec_hdr, 0xFF, UBI_EC_HDR_SIZE)) {
+ if (check_pattern(ec_hdr, 0xFF, UBI_EC_HDR_SIZE)) {
/* The physical eraseblock is supposedly empty */
if (verbose)
ubi_warn("no EC header found at PEB %d, "
@@ -774,7 +774,7 @@ int ubi_io_read_ec_hdr(struct ubi_device *ubi, int pnum,
} else if (UBI_IO_DEBUG)
dbg_msg("bad magic number at PEB %d: %08x instead of "
"%08x", pnum, magic, UBI_EC_HDR_MAGIC);
- return UBI_IO_BAD_EC_HDR;
+ return UBI_IO_BAD_HDR;
}
crc = crc32(UBI_CRC32_INIT, ec_hdr, UBI_EC_HDR_SIZE_CRC);
@@ -788,7 +788,7 @@ int ubi_io_read_ec_hdr(struct ubi_device *ubi, int pnum,
} else if (UBI_IO_DEBUG)
dbg_msg("bad EC header CRC at PEB %d, calculated "
"%#08x, read %#08x", pnum, crc, hdr_crc);
- return UBI_IO_BAD_EC_HDR;
+ return read_err ?: UBI_IO_BAD_HDR;
}
/* And of course validate what has just been read from the media */
@@ -798,6 +798,10 @@ int ubi_io_read_ec_hdr(struct ubi_device *ubi, int pnum,
return -EINVAL;
}
+ /*
+ * If there was %-EBADMSG, but the header CRC is still OK, report about
+ * a bit-flip to force scrubbing on this PEB.
+ */
return read_err ? UBI_IO_BITFLIPS : 0;
}
@@ -977,7 +981,7 @@ bad:
* o %UBI_IO_BITFLIPS if the CRC is correct, but bit-flips were detected
* and corrected by the flash driver; this is harmless but may indicate that
* this eraseblock may become bad soon;
- * o %UBI_IO_BAD_VID_HDR if the volume identifier header is corrupted (a CRC
+ * o %UBI_IO_BAD_HDR if the volume identifier header is corrupted (a CRC
* error detected);
* o %UBI_IO_PEB_FREE if the physical eraseblock is free (i.e., there is no VID
* header there);
@@ -1008,22 +1012,20 @@ int ubi_io_read_vid_hdr(struct ubi_device *ubi, int pnum,
* CRC check-sum and we will identify this. If the VID header is
* still OK, we just report this as there was a bit-flip.
*/
- read_err = err;
+ if (err == -EBADMSG)
+ read_err = UBI_IO_BAD_HDR_READ;
}
magic = be32_to_cpu(vid_hdr->magic);
if (magic != UBI_VID_HDR_MAGIC) {
+ if (read_err)
+ return read_err;
+
/*
* If we have read all 0xFF bytes, the VID header probably does
* not exist and the physical eraseblock is assumed to be free.
- *
- * But if there was a read error, we do not test the data for
- * 0xFFs. Even if it does contain all 0xFFs, this error
- * indicates that something is still wrong with this physical
- * eraseblock and it cannot be regarded as free.
*/
- if (read_err != -EBADMSG &&
- check_pattern(vid_hdr, 0xFF, UBI_VID_HDR_SIZE)) {
+ if (check_pattern(vid_hdr, 0xFF, UBI_VID_HDR_SIZE)) {
/* The physical eraseblock is supposedly free */
if (verbose)
ubi_warn("no VID header found at PEB %d, "
@@ -1045,7 +1047,7 @@ int ubi_io_read_vid_hdr(struct ubi_device *ubi, int pnum,
} else if (UBI_IO_DEBUG)
dbg_msg("bad magic number at PEB %d: %08x instead of "
"%08x", pnum, magic, UBI_VID_HDR_MAGIC);
- return UBI_IO_BAD_VID_HDR;
+ return UBI_IO_BAD_HDR;
}
crc = crc32(UBI_CRC32_INIT, vid_hdr, UBI_VID_HDR_SIZE_CRC);
@@ -1059,7 +1061,7 @@ int ubi_io_read_vid_hdr(struct ubi_device *ubi, int pnum,
} else if (UBI_IO_DEBUG)
dbg_msg("bad CRC at PEB %d, calculated %#08x, "
"read %#08x", pnum, crc, hdr_crc);
- return UBI_IO_BAD_VID_HDR;
+ return read_err ?: UBI_IO_BAD_HDR;
}
/* Validate the VID header that we have just read */
@@ -1069,6 +1071,10 @@ int ubi_io_read_vid_hdr(struct ubi_device *ubi, int pnum,
return -EINVAL;
}
+ /*
+ * If there was a read error (%-EBADMSG), but the header CRC is still
+ * OK, report about a bit-flip to force scrubbing on this PEB.
+ */
return read_err ? UBI_IO_BITFLIPS : 0;
}
diff --git a/drivers/mtd/ubi/scan.c b/drivers/mtd/ubi/scan.c
index aed19f33b8f..372a15ac999 100644
--- a/drivers/mtd/ubi/scan.c
+++ b/drivers/mtd/ubi/scan.c
@@ -44,6 +44,7 @@
#include <linux/slab.h>
#include <linux/crc32.h>
#include <linux/math64.h>
+#include <linux/random.h>
#include "ubi.h"
#ifdef CONFIG_MTD_UBI_DEBUG_PARANOID
@@ -72,16 +73,19 @@ static int add_to_list(struct ubi_scan_info *si, int pnum, int ec,
{
struct ubi_scan_leb *seb;
- if (list == &si->free)
+ if (list == &si->free) {
dbg_bld("add to free: PEB %d, EC %d", pnum, ec);
- else if (list == &si->erase)
+ si->free_peb_count += 1;
+ } else if (list == &si->erase) {
dbg_bld("add to erase: PEB %d, EC %d", pnum, ec);
- else if (list == &si->corr) {
+ si->erase_peb_count += 1;
+ } else if (list == &si->corr) {
dbg_bld("add to corrupted: PEB %d, EC %d", pnum, ec);
- si->corr_count += 1;
- } else if (list == &si->alien)
+ si->corr_peb_count += 1;
+ } else if (list == &si->alien) {
dbg_bld("add to alien: PEB %d, EC %d", pnum, ec);
- else
+ si->alien_peb_count += 1;
+ } else
BUG();
seb = kmalloc(sizeof(struct ubi_scan_leb), GFP_KERNEL);
@@ -517,6 +521,7 @@ int ubi_scan_add_used(struct ubi_device *ubi, struct ubi_scan_info *si,
sv->leb_count += 1;
rb_link_node(&seb->u.rb, parent, p);
rb_insert_color(&seb->u.rb, &sv->root);
+ si->used_peb_count += 1;
return 0;
}
@@ -745,19 +750,17 @@ static int process_eb(struct ubi_device *ubi, struct ubi_scan_info *si,
bitflips = 1;
else if (err == UBI_IO_PEB_EMPTY)
return add_to_list(si, pnum, UBI_SCAN_UNKNOWN_EC, &si->erase);
- else if (err == UBI_IO_BAD_EC_HDR) {
+ else if (err == UBI_IO_BAD_HDR_READ || err == UBI_IO_BAD_HDR) {
/*
* We have to also look at the VID header, possibly it is not
* corrupted. Set %bitflips flag in order to make this PEB be
* moved and EC be re-created.
*/
- ec_corr = 1;
+ ec_corr = err;
ec = UBI_SCAN_UNKNOWN_EC;
bitflips = 1;
}
- si->is_empty = 0;
-
if (!ec_corr) {
int image_seq;
@@ -813,9 +816,12 @@ static int process_eb(struct ubi_device *ubi, struct ubi_scan_info *si,
return err;
else if (err == UBI_IO_BITFLIPS)
bitflips = 1;
- else if (err == UBI_IO_BAD_VID_HDR ||
+ else if (err == UBI_IO_BAD_HDR_READ || err == UBI_IO_BAD_HDR ||
(err == UBI_IO_PEB_FREE && ec_corr)) {
/* VID header is corrupted */
+ if (err == UBI_IO_BAD_HDR_READ ||
+ ec_corr == UBI_IO_BAD_HDR_READ)
+ si->read_err_count += 1;
err = add_to_list(si, pnum, ec, &si->corr);
if (err)
return err;
@@ -836,11 +842,11 @@ static int process_eb(struct ubi_device *ubi, struct ubi_scan_info *si,
switch (vidh->compat) {
case UBI_COMPAT_DELETE:
ubi_msg("\"delete\" compatible internal volume %d:%d"
- " found, remove it", vol_id, lnum);
+ " found, will remove it", vol_id, lnum);
err = add_to_list(si, pnum, ec, &si->corr);
if (err)
return err;
- break;
+ return 0;
case UBI_COMPAT_RO:
ubi_msg("read-only compatible internal volume %d:%d"
@@ -855,7 +861,6 @@ static int process_eb(struct ubi_device *ubi, struct ubi_scan_info *si,
err = add_to_list(si, pnum, ec, &si->alien);
if (err)
return err;
- si->alien_peb_count += 1;
return 0;
case UBI_COMPAT_REJECT:
@@ -886,6 +891,85 @@ adjust_mean_ec:
}
/**
+ * check_what_we_have - check what PEB were found by scanning.
+ * @ubi: UBI device description object
+ * @si: scanning information
+ *
+ * This is a helper function which takes a look what PEBs were found by
+ * scanning, and decides whether the flash is empty and should be formatted and
+ * whether there are too many corrupted PEBs and we should not attach this
+ * MTD device. Returns zero if we should proceed with attaching the MTD device,
+ * and %-EINVAL if we should not.
+ */
+static int check_what_we_have(struct ubi_device *ubi, struct ubi_scan_info *si)
+{
+ struct ubi_scan_leb *seb;
+ int max_corr;
+
+ max_corr = ubi->peb_count - si->bad_peb_count - si->alien_peb_count;
+ max_corr = max_corr / 20 ?: 8;
+
+ /*
+ * Few corrupted PEBs are not a problem and may be just a result of
+ * unclean reboots. However, many of them may indicate some problems
+ * with the flash HW or driver.
+ */
+ if (si->corr_peb_count >= 8) {
+ ubi_warn("%d PEBs are corrupted", si->corr_peb_count);
+ printk(KERN_WARNING "corrupted PEBs are:");
+ list_for_each_entry(seb, &si->corr, u.list)
+ printk(KERN_CONT " %d", seb->pnum);
+ printk(KERN_CONT "\n");
+
+ /*
+ * If too many PEBs are corrupted, we refuse attaching,
+ * otherwise, only print a warning.
+ */
+ if (si->corr_peb_count >= max_corr) {
+ ubi_err("too many corrupted PEBs, refusing this device");
+ return -EINVAL;
+ }
+ }
+
+ if (si->free_peb_count + si->used_peb_count +
+ si->alien_peb_count == 0) {
+ /* No UBI-formatted eraseblocks were found */
+ if (si->corr_peb_count == si->read_err_count &&
+ si->corr_peb_count < 8) {
+ /* No or just few corrupted PEBs, and all of them had a
+ * read error. We assume that those are bad PEBs, which
+ * were just not marked as bad so far.
+ *
+ * This piece of code basically tries to distinguish
+ * between the following 2 situations:
+ *
+ * 1. Flash is empty, but there are few bad PEBs, which
+ * are not marked as bad so far, and which were read
+ * with error. We want to go ahead and format this
+ * flash. While formating, the faulty PEBs will
+ * probably be marked as bad.
+ *
+ * 2. Flash probably contains non-UBI data and we do
+ * not want to format it and destroy possibly needed
+ * data (e.g., consider the case when the bootloader
+ * MTD partition was accidentally fed to UBI).
+ */
+ si->is_empty = 1;
+ ubi_msg("empty MTD device detected");
+ get_random_bytes(&ubi->image_seq, sizeof(ubi->image_seq));
+ } else {
+ ubi_err("MTD device possibly contains non-UBI data, "
+ "refusing it");
+ return -EINVAL;
+ }
+ }
+
+ if (si->corr_peb_count > 0)
+ ubi_msg("corrupted PEBs will be formatted");
+ return 0;
+}
+
+/**
* ubi_scan - scan an MTD device.
* @ubi: UBI device description object
*
@@ -909,7 +993,6 @@ struct ubi_scan_info *ubi_scan(struct ubi_device *ubi)
INIT_LIST_HEAD(&si->erase);
INIT_LIST_HEAD(&si->alien);
si->volumes = RB_ROOT;
- si->is_empty = 1;
err = -ENOMEM;
ech = kzalloc(ubi->ec_hdr_alsize, GFP_KERNEL);
@@ -935,21 +1018,9 @@ struct ubi_scan_info *ubi_scan(struct ubi_device *ubi)
if (si->ec_count)
si->mean_ec = div_u64(si->ec_sum, si->ec_count);
- if (si->is_empty)
- ubi_msg("empty MTD device detected");
-
- /*
- * Few corrupted PEBs are not a problem and may be just a result of
- * unclean reboots. However, many of them may indicate some problems
- * with the flash HW or driver. Print a warning in this case.
- */
- if (si->corr_count >= 8 || si->corr_count >= ubi->peb_count / 4) {
- ubi_warn("%d PEBs are corrupted", si->corr_count);
- printk(KERN_WARNING "corrupted PEBs are:");
- list_for_each_entry(seb, &si->corr, u.list)
- printk(KERN_CONT " %d", seb->pnum);
- printk(KERN_CONT "\n");
- }
+ err = check_what_we_have(ubi, si);
+ if (err)
+ goto out_vidh;
/*
* In case of unknown erase counter we use the mean erase counter
diff --git a/drivers/mtd/ubi/scan.h b/drivers/mtd/ubi/scan.h
index ff179ad7ca5..2576a8d1532 100644
--- a/drivers/mtd/ubi/scan.h
+++ b/drivers/mtd/ubi/scan.h
@@ -91,10 +91,16 @@ struct ubi_scan_volume {
* @erase: list of physical eraseblocks which have to be erased
* @alien: list of physical eraseblocks which should not be used by UBI (e.g.,
* those belonging to "preserve"-compatible internal volumes)
+ * @used_peb_count: count of used PEBs
+ * @corr_peb_count: count of PEBs in the @corr list
+ * @read_err_count: count of PEBs read with error (%UBI_IO_BAD_HDR_READ was
+ * returned)
+ * @free_peb_count: count of PEBs in the @free list
+ * @erase_peb_count: count of PEBs in the @erase list
+ * @alien_peb_count: count of PEBs in the @alien list
* @bad_peb_count: count of bad physical eraseblocks
* @vols_found: number of volumes found during scanning
* @highest_vol_id: highest volume ID
- * @alien_peb_count: count of physical eraseblocks in the @alien list
* @is_empty: flag indicating whether the MTD device is empty or not
* @min_ec: lowest erase counter value
* @max_ec: highest erase counter value
@@ -102,7 +108,6 @@ struct ubi_scan_volume {
* @mean_ec: mean erase counter value
* @ec_sum: a temporary variable used when calculating @mean_ec
* @ec_count: a temporary variable used when calculating @mean_ec
- * @corr_count: count of corrupted PEBs
*
* This data structure contains the result of scanning and may be used by other
* UBI sub-systems to build final UBI data structures, further error-recovery
@@ -114,10 +119,15 @@ struct ubi_scan_info {
struct list_head free;
struct list_head erase;
struct list_head alien;
+ int used_peb_count;
+ int corr_peb_count;
+ int read_err_count;
+ int free_peb_count;
+ int erase_peb_count;
+ int alien_peb_count;
int bad_peb_count;
int vols_found;
int highest_vol_id;
- int alien_peb_count;
int is_empty;
int min_ec;
int max_ec;
@@ -125,7 +135,6 @@ struct ubi_scan_info {
int mean_ec;
uint64_t ec_sum;
int ec_count;
- int corr_count;
};
struct ubi_device;
@@ -135,7 +144,7 @@ struct ubi_vid_hdr;
* ubi_scan_move_to_list - move a PEB from the volume tree to a list.
*
* @sv: volume scanning information
- * @seb: scanning eraseblock infprmation
+ * @seb: scanning eraseblock information
* @list: the list to move to
*/
static inline void ubi_scan_move_to_list(struct ubi_scan_volume *sv,
diff --git a/drivers/mtd/ubi/ubi.h b/drivers/mtd/ubi/ubi.h
index a637f0283ad..0359e0cce48 100644
--- a/drivers/mtd/ubi/ubi.h
+++ b/drivers/mtd/ubi/ubi.h
@@ -89,16 +89,16 @@
* %0xFF bytes
* UBI_IO_PEB_FREE: the physical eraseblock is free, i.e. it contains only a
* valid erase counter header, and the rest are %0xFF bytes
- * UBI_IO_BAD_EC_HDR: the erase counter header is corrupted (bad magic or CRC)
- * UBI_IO_BAD_VID_HDR: the volume identifier header is corrupted (bad magic or
- * CRC)
+ * UBI_IO_BAD_HDR: the EC or VID header is corrupted (bad magic or CRC)
+ * UBI_IO_BAD_HDR_READ: the same as %UBI_IO_BAD_HDR, but also there was a read
+ * error reported by the flash driver
* UBI_IO_BITFLIPS: bit-flips were detected and corrected
*/
enum {
UBI_IO_PEB_EMPTY = 1,
UBI_IO_PEB_FREE,
- UBI_IO_BAD_EC_HDR,
- UBI_IO_BAD_VID_HDR,
+ UBI_IO_BAD_HDR,
+ UBI_IO_BAD_HDR_READ,
UBI_IO_BITFLIPS
};
diff --git a/drivers/net/3c527.c b/drivers/net/3c527.c
index 38395dfa496..70705d1306b 100644
--- a/drivers/net/3c527.c
+++ b/drivers/net/3c527.c
@@ -729,14 +729,14 @@ static void mc32_halt_transceiver(struct net_device *dev)
* mc32_load_rx_ring - load the ring of receive buffers
* @dev: 3c527 to build the ring for
*
- * This initalises the on-card and driver datastructures to
+ * This initialises the on-card and driver datastructures to
* the point where mc32_start_transceiver() can be called.
*
* The card sets up the receive ring for us. We are required to use the
* ring it provides, although the size of the ring is configurable.
*
* We allocate an sk_buff for each ring entry in turn and
- * initalise its house-keeping info. At the same time, we read
+ * initialise its house-keeping info. At the same time, we read
* each 'next' pointer in our rx_ring array. This reduces slow
* shared-memory reads and makes it easy to access predecessor
* descriptors.
diff --git a/drivers/net/3c527.h b/drivers/net/3c527.h
index 75e28fef797..d693b8d15cd 100644
--- a/drivers/net/3c527.h
+++ b/drivers/net/3c527.h
@@ -34,7 +34,7 @@ struct mc32_mailbox
{
u16 mbox;
u16 data[1];
-} __attribute((packed));
+} __packed;
struct skb_header
{
@@ -43,7 +43,7 @@ struct skb_header
u16 next; /* Do not change! */
u16 length;
u32 data;
-} __attribute((packed));
+} __packed;
struct mc32_stats
{
@@ -68,7 +68,7 @@ struct mc32_stats
u32 dataA[6];
u16 dataB[5];
u32 dataC[14];
-} __attribute((packed));
+} __packed;
#define STATUS_MASK 0x0F
#define COMPLETED (1<<7)
diff --git a/drivers/net/3c59x.c b/drivers/net/3c59x.c
index d75803e6e52..c754d88e5ec 100644
--- a/drivers/net/3c59x.c
+++ b/drivers/net/3c59x.c
@@ -435,7 +435,6 @@ MODULE_DEVICE_TABLE(pci, vortex_pci_tbl);
First the windows. There are eight register windows, with the command
and status registers available in each.
*/
-#define EL3WINDOW(win_num) iowrite16(SelectWindow + (win_num), ioaddr + EL3_CMD)
#define EL3_CMD 0x0e
#define EL3_STATUS 0x0e
@@ -645,10 +644,51 @@ struct vortex_private {
u16 deferred; /* Resend these interrupts when we
* bale from the ISR */
u16 io_size; /* Size of PCI region (for release_region) */
- spinlock_t lock; /* Serialise access to device & its vortex_private */
- struct mii_if_info mii; /* MII lib hooks/info */
+
+ /* Serialises access to hardware other than MII and variables below.
+ * The lock hierarchy is rtnl_lock > lock > mii_lock > window_lock. */
+ spinlock_t lock;
+
+ spinlock_t mii_lock; /* Serialises access to MII */
+ struct mii_if_info mii; /* MII lib hooks/info */
+ spinlock_t window_lock; /* Serialises access to windowed regs */
+ int window; /* Register window */
};
+static void window_set(struct vortex_private *vp, int window)
+{
+ if (window != vp->window) {
+ iowrite16(SelectWindow + window, vp->ioaddr + EL3_CMD);
+ vp->window = window;
+ }
+}
+
+#define DEFINE_WINDOW_IO(size) \
+static u ## size \
+window_read ## size(struct vortex_private *vp, int window, int addr) \
+{ \
+ unsigned long flags; \
+ u ## size ret; \
+ spin_lock_irqsave(&vp->window_lock, flags); \
+ window_set(vp, window); \
+ ret = ioread ## size(vp->ioaddr + addr); \
+ spin_unlock_irqrestore(&vp->window_lock, flags); \
+ return ret; \
+} \
+static void \
+window_write ## size(struct vortex_private *vp, u ## size value, \
+ int window, int addr) \
+{ \
+ unsigned long flags; \
+ spin_lock_irqsave(&vp->window_lock, flags); \
+ window_set(vp, window); \
+ iowrite ## size(value, vp->ioaddr + addr); \
+ spin_unlock_irqrestore(&vp->window_lock, flags); \
+}
+DEFINE_WINDOW_IO(8)
+DEFINE_WINDOW_IO(16)
+DEFINE_WINDOW_IO(32)
+
#ifdef CONFIG_PCI
#define DEVICE_PCI(dev) (((dev)->bus == &pci_bus_type) ? to_pci_dev((dev)) : NULL)
#else
@@ -711,7 +751,7 @@ static int vortex_probe1(struct device *gendev, void __iomem *ioaddr, int irq,
static int vortex_up(struct net_device *dev);
static void vortex_down(struct net_device *dev, int final);
static int vortex_open(struct net_device *dev);
-static void mdio_sync(void __iomem *ioaddr, int bits);
+static void mdio_sync(struct vortex_private *vp, int bits);
static int mdio_read(struct net_device *dev, int phy_id, int location);
static void mdio_write(struct net_device *vp, int phy_id, int location, int value);
static void vortex_timer(unsigned long arg);
@@ -980,10 +1020,16 @@ static int __devinit vortex_init_one(struct pci_dev *pdev,
ioaddr = pci_iomap(pdev, pci_bar, 0);
if (!ioaddr) /* If mapping fails, fall-back to BAR 0... */
ioaddr = pci_iomap(pdev, 0, 0);
+ if (!ioaddr) {
+ pci_disable_device(pdev);
+ rc = -ENOMEM;
+ goto out;
+ }
rc = vortex_probe1(&pdev->dev, ioaddr, pdev->irq,
ent->driver_data, unit);
if (rc < 0) {
+ pci_iounmap(pdev, ioaddr);
pci_disable_device(pdev);
goto out;
}
@@ -1119,6 +1165,7 @@ static int __devinit vortex_probe1(struct device *gendev,
vp->has_nway = (vci->drv_flags & HAS_NWAY) ? 1 : 0;
vp->io_size = vci->io_size;
vp->card_idx = card_idx;
+ vp->window = -1;
/* module list only for Compaq device */
if (gendev == NULL) {
@@ -1154,6 +1201,8 @@ static int __devinit vortex_probe1(struct device *gendev,
}
spin_lock_init(&vp->lock);
+ spin_lock_init(&vp->mii_lock);
+ spin_lock_init(&vp->window_lock);
vp->gendev = gendev;
vp->mii.dev = dev;
vp->mii.mdio_read = mdio_read;
@@ -1205,7 +1254,6 @@ static int __devinit vortex_probe1(struct device *gendev,
vp->mii.force_media = vp->full_duplex;
vp->options = option;
/* Read the station address from the EEPROM. */
- EL3WINDOW(0);
{
int base;
@@ -1218,14 +1266,15 @@ static int __devinit vortex_probe1(struct device *gendev,
for (i = 0; i < 0x40; i++) {
int timer;
- iowrite16(base + i, ioaddr + Wn0EepromCmd);
+ window_write16(vp, base + i, 0, Wn0EepromCmd);
/* Pause for at least 162 us. for the read to take place. */
for (timer = 10; timer >= 0; timer--) {
udelay(162);
- if ((ioread16(ioaddr + Wn0EepromCmd) & 0x8000) == 0)
+ if ((window_read16(vp, 0, Wn0EepromCmd) &
+ 0x8000) == 0)
break;
}
- eeprom[i] = ioread16(ioaddr + Wn0EepromData);
+ eeprom[i] = window_read16(vp, 0, Wn0EepromData);
}
}
for (i = 0; i < 0x18; i++)
@@ -1250,9 +1299,8 @@ static int __devinit vortex_probe1(struct device *gendev,
pr_err("*** EEPROM MAC address is invalid.\n");
goto free_ring; /* With every pack */
}
- EL3WINDOW(2);
for (i = 0; i < 6; i++)
- iowrite8(dev->dev_addr[i], ioaddr + i);
+ window_write8(vp, dev->dev_addr[i], 2, i);
if (print_info)
pr_cont(", IRQ %d\n", dev->irq);
@@ -1261,8 +1309,7 @@ static int __devinit vortex_probe1(struct device *gendev,
pr_warning(" *** Warning: IRQ %d is unlikely to work! ***\n",
dev->irq);
- EL3WINDOW(4);
- step = (ioread8(ioaddr + Wn4_NetDiag) & 0x1e) >> 1;
+ step = (window_read8(vp, 4, Wn4_NetDiag) & 0x1e) >> 1;
if (print_info) {
pr_info(" product code %02x%02x rev %02x.%d date %02d-%02d-%02d\n",
eeprom[6]&0xff, eeprom[6]>>8, eeprom[0x14],
@@ -1285,17 +1332,15 @@ static int __devinit vortex_probe1(struct device *gendev,
(unsigned long long)pci_resource_start(pdev, 2),
vp->cb_fn_base);
}
- EL3WINDOW(2);
- n = ioread16(ioaddr + Wn2_ResetOptions) & ~0x4010;
+ n = window_read16(vp, 2, Wn2_ResetOptions) & ~0x4010;
if (vp->drv_flags & INVERT_LED_PWR)
n |= 0x10;
if (vp->drv_flags & INVERT_MII_PWR)
n |= 0x4000;
- iowrite16(n, ioaddr + Wn2_ResetOptions);
+ window_write16(vp, n, 2, Wn2_ResetOptions);
if (vp->drv_flags & WNO_XCVR_PWR) {
- EL3WINDOW(0);
- iowrite16(0x0800, ioaddr);
+ window_write16(vp, 0x0800, 0, 0);
}
}
@@ -1313,14 +1358,13 @@ static int __devinit vortex_probe1(struct device *gendev,
{
static const char * const ram_split[] = {"5:3", "3:1", "1:1", "3:5"};
unsigned int config;
- EL3WINDOW(3);
- vp->available_media = ioread16(ioaddr + Wn3_Options);
+ vp->available_media = window_read16(vp, 3, Wn3_Options);
if ((vp->available_media & 0xff) == 0) /* Broken 3c916 */
vp->available_media = 0x40;
- config = ioread32(ioaddr + Wn3_Config);
+ config = window_read32(vp, 3, Wn3_Config);
if (print_info) {
pr_debug(" Internal config register is %4.4x, transceivers %#x.\n",
- config, ioread16(ioaddr + Wn3_Options));
+ config, window_read16(vp, 3, Wn3_Options));
pr_info(" %dK %s-wide RAM %s Rx:Tx split, %s%s interface.\n",
8 << RAM_SIZE(config),
RAM_WIDTH(config) ? "word" : "byte",
@@ -1346,11 +1390,10 @@ static int __devinit vortex_probe1(struct device *gendev,
if ((vp->available_media & 0x40) || (vci->drv_flags & HAS_NWAY) ||
dev->if_port == XCVR_MII || dev->if_port == XCVR_NWAY) {
int phy, phy_idx = 0;
- EL3WINDOW(4);
mii_preamble_required++;
if (vp->drv_flags & EXTRA_PREAMBLE)
mii_preamble_required++;
- mdio_sync(ioaddr, 32);
+ mdio_sync(vp, 32);
mdio_read(dev, 24, MII_BMSR);
for (phy = 0; phy < 32 && phy_idx < 1; phy++) {
int mii_status, phyx;
@@ -1478,18 +1521,17 @@ static void
vortex_set_duplex(struct net_device *dev)
{
struct vortex_private *vp = netdev_priv(dev);
- void __iomem *ioaddr = vp->ioaddr;
pr_info("%s: setting %s-duplex.\n",
dev->name, (vp->full_duplex) ? "full" : "half");
- EL3WINDOW(3);
/* Set the full-duplex bit. */
- iowrite16(((vp->info1 & 0x8000) || vp->full_duplex ? 0x20 : 0) |
- (vp->large_frames ? 0x40 : 0) |
- ((vp->full_duplex && vp->flow_ctrl && vp->partner_flow_ctrl) ?
- 0x100 : 0),
- ioaddr + Wn3_MAC_Ctrl);
+ window_write16(vp,
+ ((vp->info1 & 0x8000) || vp->full_duplex ? 0x20 : 0) |
+ (vp->large_frames ? 0x40 : 0) |
+ ((vp->full_duplex && vp->flow_ctrl && vp->partner_flow_ctrl) ?
+ 0x100 : 0),
+ 3, Wn3_MAC_Ctrl);
}
static void vortex_check_media(struct net_device *dev, unsigned int init)
@@ -1529,8 +1571,7 @@ vortex_up(struct net_device *dev)
}
/* Before initializing select the active media port. */
- EL3WINDOW(3);
- config = ioread32(ioaddr + Wn3_Config);
+ config = window_read32(vp, 3, Wn3_Config);
if (vp->media_override != 7) {
pr_info("%s: Media override to transceiver %d (%s).\n",
@@ -1577,10 +1618,9 @@ vortex_up(struct net_device *dev)
config = BFINS(config, dev->if_port, 20, 4);
if (vortex_debug > 6)
pr_debug("vortex_up(): writing 0x%x to InternalConfig\n", config);
- iowrite32(config, ioaddr + Wn3_Config);
+ window_write32(vp, config, 3, Wn3_Config);
if (dev->if_port == XCVR_MII || dev->if_port == XCVR_NWAY) {
- EL3WINDOW(4);
mii_reg1 = mdio_read(dev, vp->phys[0], MII_BMSR);
mii_reg5 = mdio_read(dev, vp->phys[0], MII_LPA);
vp->partner_flow_ctrl = ((mii_reg5 & 0x0400) != 0);
@@ -1601,51 +1641,46 @@ vortex_up(struct net_device *dev)
iowrite16(SetStatusEnb | 0x00, ioaddr + EL3_CMD);
if (vortex_debug > 1) {
- EL3WINDOW(4);
pr_debug("%s: vortex_up() irq %d media status %4.4x.\n",
- dev->name, dev->irq, ioread16(ioaddr + Wn4_Media));
+ dev->name, dev->irq, window_read16(vp, 4, Wn4_Media));
}
/* Set the station address and mask in window 2 each time opened. */
- EL3WINDOW(2);
for (i = 0; i < 6; i++)
- iowrite8(dev->dev_addr[i], ioaddr + i);
+ window_write8(vp, dev->dev_addr[i], 2, i);
for (; i < 12; i+=2)
- iowrite16(0, ioaddr + i);
+ window_write16(vp, 0, 2, i);
if (vp->cb_fn_base) {
- unsigned short n = ioread16(ioaddr + Wn2_ResetOptions) & ~0x4010;
+ unsigned short n = window_read16(vp, 2, Wn2_ResetOptions) & ~0x4010;
if (vp->drv_flags & INVERT_LED_PWR)
n |= 0x10;
if (vp->drv_flags & INVERT_MII_PWR)
n |= 0x4000;
- iowrite16(n, ioaddr + Wn2_ResetOptions);
+ window_write16(vp, n, 2, Wn2_ResetOptions);
}
if (dev->if_port == XCVR_10base2)
/* Start the thinnet transceiver. We should really wait 50ms...*/
iowrite16(StartCoax, ioaddr + EL3_CMD);
if (dev->if_port != XCVR_NWAY) {
- EL3WINDOW(4);
- iowrite16((ioread16(ioaddr + Wn4_Media) & ~(Media_10TP|Media_SQE)) |
- media_tbl[dev->if_port].media_bits, ioaddr + Wn4_Media);
+ window_write16(vp,
+ (window_read16(vp, 4, Wn4_Media) &
+ ~(Media_10TP|Media_SQE)) |
+ media_tbl[dev->if_port].media_bits,
+ 4, Wn4_Media);
}
/* Switch to the stats window, and clear all stats by reading. */
iowrite16(StatsDisable, ioaddr + EL3_CMD);
- EL3WINDOW(6);
for (i = 0; i < 10; i++)
- ioread8(ioaddr + i);
- ioread16(ioaddr + 10);
- ioread16(ioaddr + 12);
+ window_read8(vp, 6, i);
+ window_read16(vp, 6, 10);
+ window_read16(vp, 6, 12);
/* New: On the Vortex we must also clear the BadSSD counter. */
- EL3WINDOW(4);
- ioread8(ioaddr + 12);
+ window_read8(vp, 4, 12);
/* ..and on the Boomerang we enable the extra statistics bits. */
- iowrite16(0x0040, ioaddr + Wn4_NetDiag);
-
- /* Switch to register set 7 for normal use. */
- EL3WINDOW(7);
+ window_write16(vp, 0x0040, 4, Wn4_NetDiag);
if (vp->full_bus_master_rx) { /* Boomerang bus master. */
vp->cur_rx = vp->dirty_rx = 0;
@@ -1763,7 +1798,7 @@ vortex_timer(unsigned long data)
void __iomem *ioaddr = vp->ioaddr;
int next_tick = 60*HZ;
int ok = 0;
- int media_status, old_window;
+ int media_status;
if (vortex_debug > 2) {
pr_debug("%s: Media selection timer tick happened, %s.\n",
@@ -1771,10 +1806,7 @@ vortex_timer(unsigned long data)
pr_debug("dev->watchdog_timeo=%d\n", dev->watchdog_timeo);
}
- disable_irq_lockdep(dev->irq);
- old_window = ioread16(ioaddr + EL3_CMD) >> 13;
- EL3WINDOW(4);
- media_status = ioread16(ioaddr + Wn4_Media);
+ media_status = window_read16(vp, 4, Wn4_Media);
switch (dev->if_port) {
case XCVR_10baseT: case XCVR_100baseTx: case XCVR_100baseFx:
if (media_status & Media_LnkBeat) {
@@ -1794,10 +1826,7 @@ vortex_timer(unsigned long data)
case XCVR_MII: case XCVR_NWAY:
{
ok = 1;
- /* Interrupts are already disabled */
- spin_lock(&vp->lock);
vortex_check_media(dev, 0);
- spin_unlock(&vp->lock);
}
break;
default: /* Other media types handled by Tx timeouts. */
@@ -1816,6 +1845,8 @@ vortex_timer(unsigned long data)
if (!ok) {
unsigned int config;
+ spin_lock_irq(&vp->lock);
+
do {
dev->if_port = media_tbl[dev->if_port].next;
} while ( ! (vp->available_media & media_tbl[dev->if_port].mask));
@@ -1830,19 +1861,22 @@ vortex_timer(unsigned long data)
dev->name, media_tbl[dev->if_port].name);
next_tick = media_tbl[dev->if_port].wait;
}
- iowrite16((media_status & ~(Media_10TP|Media_SQE)) |
- media_tbl[dev->if_port].media_bits, ioaddr + Wn4_Media);
+ window_write16(vp,
+ (media_status & ~(Media_10TP|Media_SQE)) |
+ media_tbl[dev->if_port].media_bits,
+ 4, Wn4_Media);
- EL3WINDOW(3);
- config = ioread32(ioaddr + Wn3_Config);
+ config = window_read32(vp, 3, Wn3_Config);
config = BFINS(config, dev->if_port, 20, 4);
- iowrite32(config, ioaddr + Wn3_Config);
+ window_write32(vp, config, 3, Wn3_Config);
iowrite16(dev->if_port == XCVR_10base2 ? StartCoax : StopCoax,
ioaddr + EL3_CMD);
if (vortex_debug > 1)
pr_debug("wrote 0x%08x to Wn3_Config\n", config);
/* AKPM: FIXME: Should reset Rx & Tx here. P60 of 3c90xc.pdf */
+
+ spin_unlock_irq(&vp->lock);
}
leave_media_alone:
@@ -1850,8 +1884,6 @@ leave_media_alone:
pr_debug("%s: Media selection timer finished, %s.\n",
dev->name, media_tbl[dev->if_port].name);
- EL3WINDOW(old_window);
- enable_irq_lockdep(dev->irq);
mod_timer(&vp->timer, RUN_AT(next_tick));
if (vp->deferred)
iowrite16(FakeIntr, ioaddr + EL3_CMD);
@@ -1865,12 +1897,11 @@ static void vortex_tx_timeout(struct net_device *dev)
pr_err("%s: transmit timed out, tx_status %2.2x status %4.4x.\n",
dev->name, ioread8(ioaddr + TxStatus),
ioread16(ioaddr + EL3_STATUS));
- EL3WINDOW(4);
pr_err(" diagnostics: net %04x media %04x dma %08x fifo %04x\n",
- ioread16(ioaddr + Wn4_NetDiag),
- ioread16(ioaddr + Wn4_Media),
+ window_read16(vp, 4, Wn4_NetDiag),
+ window_read16(vp, 4, Wn4_Media),
ioread32(ioaddr + PktStatus),
- ioread16(ioaddr + Wn4_FIFODiag));
+ window_read16(vp, 4, Wn4_FIFODiag));
/* Slight code bloat to be user friendly. */
if ((ioread8(ioaddr + TxStatus) & 0x88) == 0x88)
pr_err("%s: Transmitter encountered 16 collisions --"
@@ -1917,9 +1948,6 @@ static void vortex_tx_timeout(struct net_device *dev)
/* Issue Tx Enable */
iowrite16(TxEnable, ioaddr + EL3_CMD);
dev->trans_start = jiffies; /* prevent tx timeout */
-
- /* Switch to register set 7 for normal use. */
- EL3WINDOW(7);
}
/*
@@ -1980,10 +2008,10 @@ vortex_error(struct net_device *dev, int status)
ioread16(ioaddr + EL3_STATUS) & StatsFull) {
pr_warning("%s: Updating statistics failed, disabling "
"stats as an interrupt source.\n", dev->name);
- EL3WINDOW(5);
- iowrite16(SetIntrEnb | (ioread16(ioaddr + 10) & ~StatsFull), ioaddr + EL3_CMD);
+ iowrite16(SetIntrEnb |
+ (window_read16(vp, 5, 10) & ~StatsFull),
+ ioaddr + EL3_CMD);
vp->intr_enable &= ~StatsFull;
- EL3WINDOW(7);
DoneDidThat++;
}
}
@@ -1993,8 +2021,7 @@ vortex_error(struct net_device *dev, int status)
}
if (status & HostError) {
u16 fifo_diag;
- EL3WINDOW(4);
- fifo_diag = ioread16(ioaddr + Wn4_FIFODiag);
+ fifo_diag = window_read16(vp, 4, Wn4_FIFODiag);
pr_err("%s: Host error, FIFO diagnostic register %4.4x.\n",
dev->name, fifo_diag);
/* Adapter failure requires Tx/Rx reset and reinit. */
@@ -2043,9 +2070,13 @@ vortex_start_xmit(struct sk_buff *skb, struct net_device *dev)
if (vp->bus_master) {
/* Set the bus-master controller to transfer the packet. */
int len = (skb->len + 3) & ~3;
- iowrite32(vp->tx_skb_dma = pci_map_single(VORTEX_PCI(vp), skb->data, len, PCI_DMA_TODEVICE),
- ioaddr + Wn7_MasterAddr);
+ vp->tx_skb_dma = pci_map_single(VORTEX_PCI(vp), skb->data, len,
+ PCI_DMA_TODEVICE);
+ spin_lock_irq(&vp->window_lock);
+ window_set(vp, 7);
+ iowrite32(vp->tx_skb_dma, ioaddr + Wn7_MasterAddr);
iowrite16(len, ioaddr + Wn7_MasterLen);
+ spin_unlock_irq(&vp->window_lock);
vp->tx_skb = skb;
iowrite16(StartDMADown, ioaddr + EL3_CMD);
/* netif_wake_queue() will be called at the DMADone interrupt. */
@@ -2217,6 +2248,9 @@ vortex_interrupt(int irq, void *dev_id)
pr_debug("%s: interrupt, status %4.4x, latency %d ticks.\n",
dev->name, status, ioread8(ioaddr + Timer));
+ spin_lock(&vp->window_lock);
+ window_set(vp, 7);
+
do {
if (vortex_debug > 5)
pr_debug("%s: In interrupt loop, status %4.4x.\n",
@@ -2275,6 +2309,8 @@ vortex_interrupt(int irq, void *dev_id)
iowrite16(AckIntr | IntReq | IntLatch, ioaddr + EL3_CMD);
} while ((status = ioread16(ioaddr + EL3_STATUS)) & (IntLatch | RxComplete));
+ spin_unlock(&vp->window_lock);
+
if (vortex_debug > 4)
pr_debug("%s: exiting interrupt, status %4.4x.\n",
dev->name, status);
@@ -2760,85 +2796,58 @@ static struct net_device_stats *vortex_get_stats(struct net_device *dev)
static void update_stats(void __iomem *ioaddr, struct net_device *dev)
{
struct vortex_private *vp = netdev_priv(dev);
- int old_window = ioread16(ioaddr + EL3_CMD);
- if (old_window == 0xffff) /* Chip suspended or ejected. */
- return;
/* Unlike the 3c5x9 we need not turn off stats updates while reading. */
/* Switch to the stats window, and read everything. */
- EL3WINDOW(6);
- dev->stats.tx_carrier_errors += ioread8(ioaddr + 0);
- dev->stats.tx_heartbeat_errors += ioread8(ioaddr + 1);
- dev->stats.tx_window_errors += ioread8(ioaddr + 4);
- dev->stats.rx_fifo_errors += ioread8(ioaddr + 5);
- dev->stats.tx_packets += ioread8(ioaddr + 6);
- dev->stats.tx_packets += (ioread8(ioaddr + 9)&0x30) << 4;
- /* Rx packets */ ioread8(ioaddr + 7); /* Must read to clear */
+ dev->stats.tx_carrier_errors += window_read8(vp, 6, 0);
+ dev->stats.tx_heartbeat_errors += window_read8(vp, 6, 1);
+ dev->stats.tx_window_errors += window_read8(vp, 6, 4);
+ dev->stats.rx_fifo_errors += window_read8(vp, 6, 5);
+ dev->stats.tx_packets += window_read8(vp, 6, 6);
+ dev->stats.tx_packets += (window_read8(vp, 6, 9) &
+ 0x30) << 4;
+ /* Rx packets */ window_read8(vp, 6, 7); /* Must read to clear */
/* Don't bother with register 9, an extension of registers 6&7.
If we do use the 6&7 values the atomic update assumption above
is invalid. */
- dev->stats.rx_bytes += ioread16(ioaddr + 10);
- dev->stats.tx_bytes += ioread16(ioaddr + 12);
+ dev->stats.rx_bytes += window_read16(vp, 6, 10);
+ dev->stats.tx_bytes += window_read16(vp, 6, 12);
/* Extra stats for get_ethtool_stats() */
- vp->xstats.tx_multiple_collisions += ioread8(ioaddr + 2);
- vp->xstats.tx_single_collisions += ioread8(ioaddr + 3);
- vp->xstats.tx_deferred += ioread8(ioaddr + 8);
- EL3WINDOW(4);
- vp->xstats.rx_bad_ssd += ioread8(ioaddr + 12);
+ vp->xstats.tx_multiple_collisions += window_read8(vp, 6, 2);
+ vp->xstats.tx_single_collisions += window_read8(vp, 6, 3);
+ vp->xstats.tx_deferred += window_read8(vp, 6, 8);
+ vp->xstats.rx_bad_ssd += window_read8(vp, 4, 12);
dev->stats.collisions = vp->xstats.tx_multiple_collisions
+ vp->xstats.tx_single_collisions
+ vp->xstats.tx_max_collisions;
{
- u8 up = ioread8(ioaddr + 13);
+ u8 up = window_read8(vp, 4, 13);
dev->stats.rx_bytes += (up & 0x0f) << 16;
dev->stats.tx_bytes += (up & 0xf0) << 12;
}
-
- EL3WINDOW(old_window >> 13);
}
static int vortex_nway_reset(struct net_device *dev)
{
struct vortex_private *vp = netdev_priv(dev);
- void __iomem *ioaddr = vp->ioaddr;
- unsigned long flags;
- int rc;
- spin_lock_irqsave(&vp->lock, flags);
- EL3WINDOW(4);
- rc = mii_nway_restart(&vp->mii);
- spin_unlock_irqrestore(&vp->lock, flags);
- return rc;
+ return mii_nway_restart(&vp->mii);
}
static int vortex_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
{
struct vortex_private *vp = netdev_priv(dev);
- void __iomem *ioaddr = vp->ioaddr;
- unsigned long flags;
- int rc;
- spin_lock_irqsave(&vp->lock, flags);
- EL3WINDOW(4);
- rc = mii_ethtool_gset(&vp->mii, cmd);
- spin_unlock_irqrestore(&vp->lock, flags);
- return rc;
+ return mii_ethtool_gset(&vp->mii, cmd);
}
static int vortex_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
{
struct vortex_private *vp = netdev_priv(dev);
- void __iomem *ioaddr = vp->ioaddr;
- unsigned long flags;
- int rc;
- spin_lock_irqsave(&vp->lock, flags);
- EL3WINDOW(4);
- rc = mii_ethtool_sset(&vp->mii, cmd);
- spin_unlock_irqrestore(&vp->lock, flags);
- return rc;
+ return mii_ethtool_sset(&vp->mii, cmd);
}
static u32 vortex_get_msglevel(struct net_device *dev)
@@ -2909,6 +2918,36 @@ static void vortex_get_drvinfo(struct net_device *dev,
}
}
+static void vortex_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
+{
+ struct vortex_private *vp = netdev_priv(dev);
+
+ spin_lock_irq(&vp->lock);
+ wol->supported = WAKE_MAGIC;
+
+ wol->wolopts = 0;
+ if (vp->enable_wol)
+ wol->wolopts |= WAKE_MAGIC;
+ spin_unlock_irq(&vp->lock);
+}
+
+static int vortex_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
+{
+ struct vortex_private *vp = netdev_priv(dev);
+ if (wol->wolopts & ~WAKE_MAGIC)
+ return -EINVAL;
+
+ spin_lock_irq(&vp->lock);
+ if (wol->wolopts & WAKE_MAGIC)
+ vp->enable_wol = 1;
+ else
+ vp->enable_wol = 0;
+ acpi_set_WOL(dev);
+ spin_unlock_irq(&vp->lock);
+
+ return 0;
+}
+
static const struct ethtool_ops vortex_ethtool_ops = {
.get_drvinfo = vortex_get_drvinfo,
.get_strings = vortex_get_strings,
@@ -2920,6 +2959,8 @@ static const struct ethtool_ops vortex_ethtool_ops = {
.set_settings = vortex_set_settings,
.get_link = ethtool_op_get_link,
.nway_reset = vortex_nway_reset,
+ .get_wol = vortex_get_wol,
+ .set_wol = vortex_set_wol,
};
#ifdef CONFIG_PCI
@@ -2930,7 +2971,6 @@ static int vortex_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
{
int err;
struct vortex_private *vp = netdev_priv(dev);
- void __iomem *ioaddr = vp->ioaddr;
unsigned long flags;
pci_power_t state = 0;
@@ -2942,7 +2982,6 @@ static int vortex_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
if(state != 0)
pci_set_power_state(VORTEX_PCI(vp), PCI_D0);
spin_lock_irqsave(&vp->lock, flags);
- EL3WINDOW(4);
err = generic_mii_ioctl(&vp->mii, if_mii(rq), cmd, NULL);
spin_unlock_irqrestore(&vp->lock, flags);
if(state != 0)
@@ -2985,8 +3024,6 @@ static void set_rx_mode(struct net_device *dev)
static void set_8021q_mode(struct net_device *dev, int enable)
{
struct vortex_private *vp = netdev_priv(dev);
- void __iomem *ioaddr = vp->ioaddr;
- int old_window = ioread16(ioaddr + EL3_CMD);
int mac_ctrl;
if ((vp->drv_flags&IS_CYCLONE) || (vp->drv_flags&IS_TORNADO)) {
@@ -2997,28 +3034,23 @@ static void set_8021q_mode(struct net_device *dev, int enable)
if (enable)
max_pkt_size += 4; /* 802.1Q VLAN tag */
- EL3WINDOW(3);
- iowrite16(max_pkt_size, ioaddr+Wn3_MaxPktSize);
+ window_write16(vp, max_pkt_size, 3, Wn3_MaxPktSize);
/* set VlanEtherType to let the hardware checksumming
treat tagged frames correctly */
- EL3WINDOW(7);
- iowrite16(VLAN_ETHER_TYPE, ioaddr+Wn7_VlanEtherType);
+ window_write16(vp, VLAN_ETHER_TYPE, 7, Wn7_VlanEtherType);
} else {
/* on older cards we have to enable large frames */
vp->large_frames = dev->mtu > 1500 || enable;
- EL3WINDOW(3);
- mac_ctrl = ioread16(ioaddr+Wn3_MAC_Ctrl);
+ mac_ctrl = window_read16(vp, 3, Wn3_MAC_Ctrl);
if (vp->large_frames)
mac_ctrl |= 0x40;
else
mac_ctrl &= ~0x40;
- iowrite16(mac_ctrl, ioaddr+Wn3_MAC_Ctrl);
+ window_write16(vp, mac_ctrl, 3, Wn3_MAC_Ctrl);
}
-
- EL3WINDOW(old_window);
}
#else
@@ -3037,7 +3069,10 @@ static void set_8021q_mode(struct net_device *dev, int enable)
/* The maximum data clock rate is 2.5 Mhz. The minimum timing is usually
met by back-to-back PCI I/O cycles, but we insert a delay to avoid
"overclocking" issues. */
-#define mdio_delay() ioread32(mdio_addr)
+static void mdio_delay(struct vortex_private *vp)
+{
+ window_read32(vp, 4, Wn4_PhysicalMgmt);
+}
#define MDIO_SHIFT_CLK 0x01
#define MDIO_DIR_WRITE 0x04
@@ -3048,16 +3083,15 @@ static void set_8021q_mode(struct net_device *dev, int enable)
/* Generate the preamble required for initial synchronization and
a few older transceivers. */
-static void mdio_sync(void __iomem *ioaddr, int bits)
+static void mdio_sync(struct vortex_private *vp, int bits)
{
- void __iomem *mdio_addr = ioaddr + Wn4_PhysicalMgmt;
-
/* Establish sync by sending at least 32 logic ones. */
while (-- bits >= 0) {
- iowrite16(MDIO_DATA_WRITE1, mdio_addr);
- mdio_delay();
- iowrite16(MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK, mdio_addr);
- mdio_delay();
+ window_write16(vp, MDIO_DATA_WRITE1, 4, Wn4_PhysicalMgmt);
+ mdio_delay(vp);
+ window_write16(vp, MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK,
+ 4, Wn4_PhysicalMgmt);
+ mdio_delay(vp);
}
}
@@ -3065,59 +3099,70 @@ static int mdio_read(struct net_device *dev, int phy_id, int location)
{
int i;
struct vortex_private *vp = netdev_priv(dev);
- void __iomem *ioaddr = vp->ioaddr;
int read_cmd = (0xf6 << 10) | (phy_id << 5) | location;
unsigned int retval = 0;
- void __iomem *mdio_addr = ioaddr + Wn4_PhysicalMgmt;
+
+ spin_lock_bh(&vp->mii_lock);
if (mii_preamble_required)
- mdio_sync(ioaddr, 32);
+ mdio_sync(vp, 32);
/* Shift the read command bits out. */
for (i = 14; i >= 0; i--) {
int dataval = (read_cmd&(1<<i)) ? MDIO_DATA_WRITE1 : MDIO_DATA_WRITE0;
- iowrite16(dataval, mdio_addr);
- mdio_delay();
- iowrite16(dataval | MDIO_SHIFT_CLK, mdio_addr);
- mdio_delay();
+ window_write16(vp, dataval, 4, Wn4_PhysicalMgmt);
+ mdio_delay(vp);
+ window_write16(vp, dataval | MDIO_SHIFT_CLK,
+ 4, Wn4_PhysicalMgmt);
+ mdio_delay(vp);
}
/* Read the two transition, 16 data, and wire-idle bits. */
for (i = 19; i > 0; i--) {
- iowrite16(MDIO_ENB_IN, mdio_addr);
- mdio_delay();
- retval = (retval << 1) | ((ioread16(mdio_addr) & MDIO_DATA_READ) ? 1 : 0);
- iowrite16(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr);
- mdio_delay();
+ window_write16(vp, MDIO_ENB_IN, 4, Wn4_PhysicalMgmt);
+ mdio_delay(vp);
+ retval = (retval << 1) |
+ ((window_read16(vp, 4, Wn4_PhysicalMgmt) &
+ MDIO_DATA_READ) ? 1 : 0);
+ window_write16(vp, MDIO_ENB_IN | MDIO_SHIFT_CLK,
+ 4, Wn4_PhysicalMgmt);
+ mdio_delay(vp);
}
+
+ spin_unlock_bh(&vp->mii_lock);
+
return retval & 0x20000 ? 0xffff : retval>>1 & 0xffff;
}
static void mdio_write(struct net_device *dev, int phy_id, int location, int value)
{
struct vortex_private *vp = netdev_priv(dev);
- void __iomem *ioaddr = vp->ioaddr;
int write_cmd = 0x50020000 | (phy_id << 23) | (location << 18) | value;
- void __iomem *mdio_addr = ioaddr + Wn4_PhysicalMgmt;
int i;
+ spin_lock_bh(&vp->mii_lock);
+
if (mii_preamble_required)
- mdio_sync(ioaddr, 32);
+ mdio_sync(vp, 32);
/* Shift the command bits out. */
for (i = 31; i >= 0; i--) {
int dataval = (write_cmd&(1<<i)) ? MDIO_DATA_WRITE1 : MDIO_DATA_WRITE0;
- iowrite16(dataval, mdio_addr);
- mdio_delay();
- iowrite16(dataval | MDIO_SHIFT_CLK, mdio_addr);
- mdio_delay();
+ window_write16(vp, dataval, 4, Wn4_PhysicalMgmt);
+ mdio_delay(vp);
+ window_write16(vp, dataval | MDIO_SHIFT_CLK,
+ 4, Wn4_PhysicalMgmt);
+ mdio_delay(vp);
}
/* Leave the interface idle. */
for (i = 1; i >= 0; i--) {
- iowrite16(MDIO_ENB_IN, mdio_addr);
- mdio_delay();
- iowrite16(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr);
- mdio_delay();
+ window_write16(vp, MDIO_ENB_IN, 4, Wn4_PhysicalMgmt);
+ mdio_delay(vp);
+ window_write16(vp, MDIO_ENB_IN | MDIO_SHIFT_CLK,
+ 4, Wn4_PhysicalMgmt);
+ mdio_delay(vp);
}
+
+ spin_unlock_bh(&vp->mii_lock);
}
/* ACPI: Advanced Configuration and Power Interface. */
@@ -3131,8 +3176,7 @@ static void acpi_set_WOL(struct net_device *dev)
if (vp->enable_wol) {
/* Power up on: 1==Downloaded Filter, 2==Magic Packets, 4==Link Status. */
- EL3WINDOW(7);
- iowrite16(2, ioaddr + 0x0c);
+ window_write16(vp, 2, 7, 0x0c);
/* The RxFilter must accept the WOL frames. */
iowrite16(SetRxFilter|RxStation|RxMulticast|RxBroadcast, ioaddr + EL3_CMD);
iowrite16(RxEnable, ioaddr + EL3_CMD);
diff --git a/drivers/net/8139cp.c b/drivers/net/8139cp.c
index 284a5f4a63a..4a4f6b81e32 100644
--- a/drivers/net/8139cp.c
+++ b/drivers/net/8139cp.c
@@ -322,7 +322,7 @@ struct cp_dma_stats {
__le32 rx_ok_mcast;
__le16 tx_abort;
__le16 tx_underrun;
-} __attribute__((packed));
+} __packed;
struct cp_extra_stats {
unsigned long rx_frags;
diff --git a/drivers/net/8139too.c b/drivers/net/8139too.c
index 97d8068b372..f5166dccd8d 100644
--- a/drivers/net/8139too.c
+++ b/drivers/net/8139too.c
@@ -662,7 +662,7 @@ static const struct ethtool_ops rtl8139_ethtool_ops;
/* read MMIO register */
#define RTL_R8(reg) ioread8 (ioaddr + (reg))
#define RTL_R16(reg) ioread16 (ioaddr + (reg))
-#define RTL_R32(reg) ((unsigned long) ioread32 (ioaddr + (reg)))
+#define RTL_R32(reg) ioread32 (ioaddr + (reg))
static const u16 rtl8139_intr_mask =
@@ -862,7 +862,7 @@ retry:
/* if unknown chip, assume array element #0, original RTL-8139 in this case */
i = 0;
dev_dbg(&pdev->dev, "unknown chip version, assuming RTL-8139\n");
- dev_dbg(&pdev->dev, "TxConfig = 0x%lx\n", RTL_R32 (TxConfig));
+ dev_dbg(&pdev->dev, "TxConfig = 0x%x\n", RTL_R32 (TxConfig));
tp->chipset = 0;
match:
@@ -1643,7 +1643,7 @@ static void rtl8139_tx_timeout_task (struct work_struct *work)
netdev_dbg(dev, "Tx queue start entry %ld dirty entry %ld\n",
tp->cur_tx, tp->dirty_tx);
for (i = 0; i < NUM_TX_DESC; i++)
- netdev_dbg(dev, "Tx descriptor %d is %08lx%s\n",
+ netdev_dbg(dev, "Tx descriptor %d is %08x%s\n",
i, RTL_R32(TxStatus0 + (i * 4)),
i == tp->dirty_tx % NUM_TX_DESC ?
" (queue head)" : "");
@@ -2487,7 +2487,7 @@ static void __set_rx_mode (struct net_device *dev)
int rx_mode;
u32 tmp;
- netdev_dbg(dev, "rtl8139_set_rx_mode(%04x) done -- Rx config %08lx\n",
+ netdev_dbg(dev, "rtl8139_set_rx_mode(%04x) done -- Rx config %08x\n",
dev->flags, RTL_R32(RxConfig));
/* Note: do not reorder, GCC is clever about common statements. */
diff --git a/drivers/net/82596.c b/drivers/net/82596.c
index dd8dc15556c..e2c9c5b949f 100644
--- a/drivers/net/82596.c
+++ b/drivers/net/82596.c
@@ -525,7 +525,21 @@ static irqreturn_t i596_error(int irq, void *dev_id)
}
#endif
-static inline void init_rx_bufs(struct net_device *dev)
+static inline void remove_rx_bufs(struct net_device *dev)
+{
+ struct i596_private *lp = dev->ml_priv;
+ struct i596_rbd *rbd;
+ int i;
+
+ for (i = 0, rbd = lp->rbds; i < rx_ring_size; i++, rbd++) {
+ if (rbd->skb == NULL)
+ break;
+ dev_kfree_skb(rbd->skb);
+ rbd->skb = NULL;
+ }
+}
+
+static inline int init_rx_bufs(struct net_device *dev)
{
struct i596_private *lp = dev->ml_priv;
int i;
@@ -537,8 +551,11 @@ static inline void init_rx_bufs(struct net_device *dev)
for (i = 0, rbd = lp->rbds; i < rx_ring_size; i++, rbd++) {
struct sk_buff *skb = dev_alloc_skb(PKT_BUF_SZ);
- if (skb == NULL)
- panic("82596: alloc_skb() failed");
+ if (skb == NULL) {
+ remove_rx_bufs(dev);
+ return -ENOMEM;
+ }
+
skb->dev = dev;
rbd->v_next = rbd+1;
rbd->b_next = WSWAPrbd(virt_to_bus(rbd+1));
@@ -574,19 +591,8 @@ static inline void init_rx_bufs(struct net_device *dev)
rfd->v_next = lp->rfds;
rfd->b_next = WSWAPrfd(virt_to_bus(lp->rfds));
rfd->cmd = CMD_EOL|CMD_FLEX;
-}
-static inline void remove_rx_bufs(struct net_device *dev)
-{
- struct i596_private *lp = dev->ml_priv;
- struct i596_rbd *rbd;
- int i;
-
- for (i = 0, rbd = lp->rbds; i < rx_ring_size; i++, rbd++) {
- if (rbd->skb == NULL)
- break;
- dev_kfree_skb(rbd->skb);
- }
+ return 0;
}
@@ -1009,20 +1015,35 @@ static int i596_open(struct net_device *dev)
}
#ifdef ENABLE_MVME16x_NET
if (MACH_IS_MVME16x) {
- if (request_irq(0x56, i596_error, 0, "i82596_error", dev))
- return -EAGAIN;
+ if (request_irq(0x56, i596_error, 0, "i82596_error", dev)) {
+ res = -EAGAIN;
+ goto err_irq_dev;
+ }
}
#endif
- init_rx_bufs(dev);
+ res = init_rx_bufs(dev);
+ if (res)
+ goto err_irq_56;
netif_start_queue(dev);
- /* Initialize the 82596 memory */
if (init_i596_mem(dev)) {
res = -EAGAIN;
- free_irq(dev->irq, dev);
+ goto err_queue;
}
+ return 0;
+
+err_queue:
+ netif_stop_queue(dev);
+ remove_rx_bufs(dev);
+err_irq_56:
+#ifdef ENABLE_MVME16x_NET
+ free_irq(0x56, dev);
+err_irq_dev:
+#endif
+ free_irq(dev->irq, dev);
+
return res;
}
@@ -1488,6 +1509,9 @@ static int i596_close(struct net_device *dev)
}
#endif
+#ifdef ENABLE_MVME16x_NET
+ free_irq(0x56, dev);
+#endif
free_irq(dev->irq, dev);
remove_rx_bufs(dev);
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index ce2fcdd4ab9..5a6895320b4 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -484,7 +484,7 @@ config XTENSA_XT2000_SONIC
config MIPS_AU1X00_ENET
tristate "MIPS AU1000 Ethernet support"
- depends on SOC_AU1X00
+ depends on MIPS_ALCHEMY
select PHYLIB
select CRC32
help
@@ -530,14 +530,15 @@ config SH_ETH
depends on SUPERH && \
(CPU_SUBTYPE_SH7710 || CPU_SUBTYPE_SH7712 || \
CPU_SUBTYPE_SH7763 || CPU_SUBTYPE_SH7619 || \
- CPU_SUBTYPE_SH7724)
+ CPU_SUBTYPE_SH7724 || CPU_SUBTYPE_SH7757)
select CRC32
select MII
select MDIO_BITBANG
select PHYLIB
help
Renesas SuperH Ethernet device driver.
- This driver support SH7710, SH7712, SH7763, SH7619, and SH7724.
+ This driver supporting CPUs are:
+ - SH7710, SH7712, SH7763, SH7619, SH7724, and SH7757.
config SUNLANCE
tristate "Sun LANCE support"
@@ -913,7 +914,7 @@ config SMC91X
tristate "SMC 91C9x/91C1xxx support"
select CRC32
select MII
- depends on ARM || REDWOOD_5 || REDWOOD_6 || M32R || SUPERH || \
+ depends on ARM || M32R || SUPERH || \
MIPS || BLACKFIN || MN10300 || COLDFIRE
help
This is a driver for SMC's 91x series of Ethernet chipsets,
@@ -1463,7 +1464,7 @@ config FORCEDETH
config CS89x0
tristate "CS89x0 support"
depends on NET_ETHERNET && (ISA || EISA || MACH_IXDP2351 \
- || ARCH_IXDP2X01 || ARCH_PNX010X || MACH_MX31ADS)
+ || ARCH_IXDP2X01 || MACH_MX31ADS)
---help---
Support for CS89x0 chipset based Ethernet cards. If you have a
network (Ethernet) card of this type, say Y and read the
@@ -1477,7 +1478,7 @@ config CS89x0
config CS89x0_NONISA_IRQ
def_bool y
depends on CS89x0 != n
- depends on MACH_IXDP2351 || ARCH_IXDP2X01 || ARCH_PNX010X || MACH_MX31ADS
+ depends on MACH_IXDP2351 || ARCH_IXDP2X01 || MACH_MX31ADS
config TC35815
tristate "TOSHIBA TC35815 Ethernet support"
@@ -1659,6 +1660,7 @@ config R6040
depends on NET_PCI && PCI
select CRC32
select MII
+ select PHYLIB
help
This is a driver for the R6040 Fast Ethernet MACs found in the
the RDC R-321x System-on-chips.
@@ -1748,11 +1750,12 @@ config TLAN
Please email feedback to <torben.mathiasen@compaq.com>.
config KS8842
- tristate "Micrel KSZ8842"
- depends on HAS_IOMEM
+ tristate "Micrel KSZ8841/42 with generic bus interface"
+ depends on HAS_IOMEM && DMA_ENGINE
help
- This platform driver is for Micrel KSZ8842 / KS8842
- 2-port ethernet switch chip (managed, VLAN, QoS).
+ This platform driver is for KSZ8841(1-port) / KS8842(2-port)
+ ethernet switch chip (managed, VLAN, QoS) from Micrel or
+ Timberdale(FPGA).
config KS8851
tristate "Micrel KS8851 SPI"
@@ -2601,6 +2604,29 @@ config CHELSIO_T4
To compile this driver as a module choose M here; the module
will be called cxgb4.
+config CHELSIO_T4VF_DEPENDS
+ tristate
+ depends on PCI && INET
+ default y
+
+config CHELSIO_T4VF
+ tristate "Chelsio Communications T4 Virtual Function Ethernet support"
+ depends on CHELSIO_T4VF_DEPENDS
+ help
+ This driver supports Chelsio T4-based gigabit and 10Gb Ethernet
+ adapters with PCI-E SR-IOV Virtual Functions.
+
+ For general information about Chelsio and our products, visit
+ our website at <http://www.chelsio.com>.
+
+ For customer support, please visit our customer support page at
+ <http://www.chelsio.com/support.htm>.
+
+ Please send feedback to <linux-bugs@chelsio.com>.
+
+ To compile this driver as a module choose M here; the module
+ will be called cxgb4vf.
+
config EHEA
tristate "eHEA Ethernet support"
depends on IBMEBUS && INET && SPARSEMEM
@@ -2614,7 +2640,6 @@ config EHEA
config ENIC
tristate "Cisco VIC Ethernet NIC Support"
depends on PCI && INET
- select INET_LRO
help
This enables the support for the Cisco VIC Ethernet card.
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index 0a0512ae77d..56e8c27f77c 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -20,6 +20,7 @@ obj-$(CONFIG_IP1000) += ipg.o
obj-$(CONFIG_CHELSIO_T1) += chelsio/
obj-$(CONFIG_CHELSIO_T3) += cxgb3/
obj-$(CONFIG_CHELSIO_T4) += cxgb4/
+obj-$(CONFIG_CHELSIO_T4VF) += cxgb4vf/
obj-$(CONFIG_EHEA) += ehea/
obj-$(CONFIG_CAN) += can/
obj-$(CONFIG_BONDING) += bonding/
@@ -83,8 +84,7 @@ obj-$(CONFIG_FEALNX) += fealnx.o
obj-$(CONFIG_TIGON3) += tg3.o
obj-$(CONFIG_BNX2) += bnx2.o
obj-$(CONFIG_CNIC) += cnic.o
-obj-$(CONFIG_BNX2X) += bnx2x.o
-bnx2x-objs := bnx2x_main.o bnx2x_link.o
+obj-$(CONFIG_BNX2X) += bnx2x/
spidernet-y += spider_net.o spider_net_ethtool.o
obj-$(CONFIG_SPIDER_NET) += spidernet.o sungem_phy.o
obj-$(CONFIG_GELIC_NET) += ps3_gelic.o
@@ -275,7 +275,7 @@ obj-$(CONFIG_USB_USBNET) += usb/
obj-$(CONFIG_USB_ZD1201) += usb/
obj-$(CONFIG_USB_IPHETH) += usb/
-obj-y += wireless/
+obj-$(CONFIG_WLAN) += wireless/
obj-$(CONFIG_NET_TULIP) += tulip/
obj-$(CONFIG_HAMRADIO) += hamradio/
obj-$(CONFIG_IRDA) += irda/
diff --git a/drivers/net/Space.c b/drivers/net/Space.c
index 3b79c6cf21a..9bb405bd664 100644
--- a/drivers/net/Space.c
+++ b/drivers/net/Space.c
@@ -218,12 +218,6 @@ static struct devprobe2 isa_probes[] __initdata = {
#ifdef CONFIG_EL1 /* 3c501 */
{el1_probe, 0},
#endif
-#ifdef CONFIG_WAVELAN /* WaveLAN */
- {wavelan_probe, 0},
-#endif
-#ifdef CONFIG_ARLAN /* Aironet */
- {arlan_probe, 0},
-#endif
#ifdef CONFIG_EL16 /* 3c507 */
{el16_probe, 0},
#endif
diff --git a/drivers/net/ac3200.c b/drivers/net/ac3200.c
index b9115a776fd..5181e932211 100644
--- a/drivers/net/ac3200.c
+++ b/drivers/net/ac3200.c
@@ -211,7 +211,7 @@ static int __init ac_probe1(int ioaddr, struct net_device *dev)
retval = request_irq(dev->irq, ei_interrupt, 0, DRV_NAME, dev);
if (retval) {
printk (" nothing! Unable to get IRQ %d.\n", dev->irq);
- goto out1;
+ goto out;
}
printk(" IRQ %d, %s port\n", dev->irq, port_name[dev->if_port]);
diff --git a/drivers/net/appletalk/ipddp.c b/drivers/net/appletalk/ipddp.c
index 79636ee3582..0362c8d31a0 100644
--- a/drivers/net/appletalk/ipddp.c
+++ b/drivers/net/appletalk/ipddp.c
@@ -80,7 +80,7 @@ static struct net_device * __init ipddp_init(void)
if (version_printed++ == 0)
printk(version);
- /* Initalize the device structure. */
+ /* Initialize the device structure. */
dev->netdev_ops = &ipddp_netdev_ops;
dev->type = ARPHRD_IPDDP; /* IP over DDP tunnel */
diff --git a/drivers/net/arcnet/capmode.c b/drivers/net/arcnet/capmode.c
index 355797f7004..42fce91b71f 100644
--- a/drivers/net/arcnet/capmode.c
+++ b/drivers/net/arcnet/capmode.c
@@ -37,69 +37,6 @@
#define VERSION "arcnet: cap mode (`c') encapsulation support loaded.\n"
-
-static void rx(struct net_device *dev, int bufnum,
- struct archdr *pkthdr, int length);
-static int build_header(struct sk_buff *skb,
- struct net_device *dev,
- unsigned short type,
- uint8_t daddr);
-static int prepare_tx(struct net_device *dev, struct archdr *pkt, int length,
- int bufnum);
-static int ack_tx(struct net_device *dev, int acked);
-
-
-static struct ArcProto capmode_proto =
-{
- 'r',
- XMTU,
- 0,
- rx,
- build_header,
- prepare_tx,
- NULL,
- ack_tx
-};
-
-
-static void arcnet_cap_init(void)
-{
- int count;
-
- for (count = 1; count <= 8; count++)
- if (arc_proto_map[count] == arc_proto_default)
- arc_proto_map[count] = &capmode_proto;
-
- /* for cap mode, we only set the bcast proto if there's no better one */
- if (arc_bcast_proto == arc_proto_default)
- arc_bcast_proto = &capmode_proto;
-
- arc_proto_default = &capmode_proto;
- arc_raw_proto = &capmode_proto;
-}
-
-
-#ifdef MODULE
-
-static int __init capmode_module_init(void)
-{
- printk(VERSION);
- arcnet_cap_init();
- return 0;
-}
-
-static void __exit capmode_module_exit(void)
-{
- arcnet_unregister_proto(&capmode_proto);
-}
-module_init(capmode_module_init);
-module_exit(capmode_module_exit);
-
-MODULE_LICENSE("GPL");
-#endif /* MODULE */
-
-
-
/* packet receiver */
static void rx(struct net_device *dev, int bufnum,
struct archdr *pkthdr, int length)
@@ -231,65 +168,107 @@ static int prepare_tx(struct net_device *dev, struct archdr *pkt, int length,
BUGMSG(D_DURING, "prepare_tx: length=%d ofs=%d\n",
length,ofs);
- // Copy the arcnet-header + the protocol byte down:
+ /* Copy the arcnet-header + the protocol byte down: */
lp->hw.copy_to_card(dev, bufnum, 0, hard, ARC_HDR_SIZE);
lp->hw.copy_to_card(dev, bufnum, ofs, &pkt->soft.cap.proto,
sizeof(pkt->soft.cap.proto));
- // Skip the extra integer we have written into it as a cookie
- // but write the rest of the message:
+ /* Skip the extra integer we have written into it as a cookie
+ but write the rest of the message: */
lp->hw.copy_to_card(dev, bufnum, ofs+1,
((unsigned char*)&pkt->soft.cap.mes),length-1);
lp->lastload_dest = hard->dest;
- return 1; /* done */
+ return 1; /* done */
}
-
static int ack_tx(struct net_device *dev, int acked)
{
- struct arcnet_local *lp = netdev_priv(dev);
- struct sk_buff *ackskb;
- struct archdr *ackpkt;
- int length=sizeof(struct arc_cap);
+ struct arcnet_local *lp = netdev_priv(dev);
+ struct sk_buff *ackskb;
+ struct archdr *ackpkt;
+ int length=sizeof(struct arc_cap);
- BUGMSG(D_DURING, "capmode: ack_tx: protocol: %x: result: %d\n",
- lp->outgoing.skb->protocol, acked);
+ BUGMSG(D_DURING, "capmode: ack_tx: protocol: %x: result: %d\n",
+ lp->outgoing.skb->protocol, acked);
- BUGLVL(D_SKB) arcnet_dump_skb(dev, lp->outgoing.skb, "ack_tx");
+ BUGLVL(D_SKB) arcnet_dump_skb(dev, lp->outgoing.skb, "ack_tx");
- /* Now alloc a skb to send back up through the layers: */
- ackskb = alloc_skb(length + ARC_HDR_SIZE , GFP_ATOMIC);
- if (ackskb == NULL) {
- BUGMSG(D_NORMAL, "Memory squeeze, can't acknowledge.\n");
- goto free_outskb;
- }
+ /* Now alloc a skb to send back up through the layers: */
+ ackskb = alloc_skb(length + ARC_HDR_SIZE , GFP_ATOMIC);
+ if (ackskb == NULL) {
+ BUGMSG(D_NORMAL, "Memory squeeze, can't acknowledge.\n");
+ goto free_outskb;
+ }
+
+ skb_put(ackskb, length + ARC_HDR_SIZE );
+ ackskb->dev = dev;
+
+ skb_reset_mac_header(ackskb);
+ ackpkt = (struct archdr *)skb_mac_header(ackskb);
+ /* skb_pull(ackskb, ARC_HDR_SIZE); */
- skb_put(ackskb, length + ARC_HDR_SIZE );
- ackskb->dev = dev;
+ skb_copy_from_linear_data(lp->outgoing.skb, ackpkt,
+ ARC_HDR_SIZE + sizeof(struct arc_cap));
+ ackpkt->soft.cap.proto = 0; /* using protocol 0 for acknowledge */
+ ackpkt->soft.cap.mes.ack=acked;
- skb_reset_mac_header(ackskb);
- ackpkt = (struct archdr *)skb_mac_header(ackskb);
- /* skb_pull(ackskb, ARC_HDR_SIZE); */
+ BUGMSG(D_PROTO, "Ackknowledge for cap packet %x.\n",
+ *((int*)&ackpkt->soft.cap.cookie[0]));
+ ackskb->protocol = cpu_to_be16(ETH_P_ARCNET);
- skb_copy_from_linear_data(lp->outgoing.skb, ackpkt,
- ARC_HDR_SIZE + sizeof(struct arc_cap));
- ackpkt->soft.cap.proto=0; /* using protocol 0 for acknowledge */
- ackpkt->soft.cap.mes.ack=acked;
+ BUGLVL(D_SKB) arcnet_dump_skb(dev, ackskb, "ack_tx_recv");
+ netif_rx(ackskb);
- BUGMSG(D_PROTO, "Ackknowledge for cap packet %x.\n",
- *((int*)&ackpkt->soft.cap.cookie[0]));
+free_outskb:
+ dev_kfree_skb_irq(lp->outgoing.skb);
+ lp->outgoing.proto = NULL; /* We are always finished when in this protocol */
- ackskb->protocol = cpu_to_be16(ETH_P_ARCNET);
+ return 0;
+}
- BUGLVL(D_SKB) arcnet_dump_skb(dev, ackskb, "ack_tx_recv");
- netif_rx(ackskb);
+static struct ArcProto capmode_proto =
+{
+ 'r',
+ XMTU,
+ 0,
+ rx,
+ build_header,
+ prepare_tx,
+ NULL,
+ ack_tx
+};
- free_outskb:
- dev_kfree_skb_irq(lp->outgoing.skb);
- lp->outgoing.proto = NULL; /* We are always finished when in this protocol */
+static void arcnet_cap_init(void)
+{
+ int count;
- return 0;
+ for (count = 1; count <= 8; count++)
+ if (arc_proto_map[count] == arc_proto_default)
+ arc_proto_map[count] = &capmode_proto;
+
+ /* for cap mode, we only set the bcast proto if there's no better one */
+ if (arc_bcast_proto == arc_proto_default)
+ arc_bcast_proto = &capmode_proto;
+
+ arc_proto_default = &capmode_proto;
+ arc_raw_proto = &capmode_proto;
}
+
+static int __init capmode_module_init(void)
+{
+ printk(VERSION);
+ arcnet_cap_init();
+ return 0;
+}
+
+static void __exit capmode_module_exit(void)
+{
+ arcnet_unregister_proto(&capmode_proto);
+}
+module_init(capmode_module_init);
+module_exit(capmode_module_exit);
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/arcnet/com20020-isa.c b/drivers/net/arcnet/com20020-isa.c
index 0402da30a4e..37272827ee5 100644
--- a/drivers/net/arcnet/com20020-isa.c
+++ b/drivers/net/arcnet/com20020-isa.c
@@ -90,14 +90,14 @@ static int __init com20020isa_probe(struct net_device *dev)
outb(0, _INTMASK);
dev->irq = probe_irq_off(airqmask);
- if (dev->irq <= 0) {
+ if ((int)dev->irq <= 0) {
BUGMSG(D_INIT_REASONS, "Autoprobe IRQ failed first time\n");
airqmask = probe_irq_on();
outb(NORXflag, _INTMASK);
udelay(5);
outb(0, _INTMASK);
dev->irq = probe_irq_off(airqmask);
- if (dev->irq <= 0) {
+ if ((int)dev->irq <= 0) {
BUGMSG(D_NORMAL, "Autoprobe IRQ failed.\n");
err = -ENODEV;
goto out;
diff --git a/drivers/net/arcnet/com90io.c b/drivers/net/arcnet/com90io.c
index 4cb401813b7..eb27976dab3 100644
--- a/drivers/net/arcnet/com90io.c
+++ b/drivers/net/arcnet/com90io.c
@@ -213,7 +213,7 @@ static int __init com90io_probe(struct net_device *dev)
outb(0, _INTMASK);
dev->irq = probe_irq_off(airqmask);
- if (dev->irq <= 0) {
+ if ((int)dev->irq <= 0) {
BUGMSG(D_INIT_REASONS, "Autoprobe IRQ failed\n");
goto err_out;
}
diff --git a/drivers/net/arm/ixp4xx_eth.c b/drivers/net/arm/ixp4xx_eth.c
index 24df0325090..4f1cc7164ad 100644
--- a/drivers/net/arm/ixp4xx_eth.c
+++ b/drivers/net/arm/ixp4xx_eth.c
@@ -738,6 +738,17 @@ static void eth_set_mcast_list(struct net_device *dev)
struct netdev_hw_addr *ha;
u8 diffs[ETH_ALEN], *addr;
int i;
+ static const u8 allmulti[] = { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00 };
+
+ if (dev->flags & IFF_ALLMULTI) {
+ for (i = 0; i < ETH_ALEN; i++) {
+ __raw_writel(allmulti[i], &port->regs->mcast_addr[i]);
+ __raw_writel(allmulti[i], &port->regs->mcast_mask[i]);
+ }
+ __raw_writel(DEFAULT_RX_CNTRL0 | RX_CNTRL0_ADDR_FLTR_EN,
+ &port->regs->rx_control[0]);
+ return;
+ }
if ((dev->flags & IFF_PROMISC) || netdev_mc_empty(dev)) {
__raw_writel(DEFAULT_RX_CNTRL0 & ~RX_CNTRL0_ADDR_FLTR_EN,
@@ -771,7 +782,8 @@ static int eth_ioctl(struct net_device *dev, struct ifreq *req, int cmd)
if (!netif_running(dev))
return -EINVAL;
- return phy_mii_ioctl(port->phydev, if_mii(req), cmd);
+
+ return phy_mii_ioctl(port->phydev, req, cmd);
}
/* ethtool support */
diff --git a/drivers/net/arm/w90p910_ether.c b/drivers/net/arm/w90p910_ether.c
index 2e852463382..4545d5a06c2 100644
--- a/drivers/net/arm/w90p910_ether.c
+++ b/drivers/net/arm/w90p910_ether.c
@@ -822,6 +822,9 @@ static int w90p910_ether_open(struct net_device *dev)
w90p910_set_global_maccmd(dev);
w90p910_enable_rx(dev, 1);
+ clk_enable(ether->rmiiclk);
+ clk_enable(ether->clk);
+
ether->rx_packets = 0x0;
ether->rx_bytes = 0x0;
diff --git a/drivers/net/at1700.c b/drivers/net/at1700.c
index 93185f5f09a..89876897a6f 100644
--- a/drivers/net/at1700.c
+++ b/drivers/net/at1700.c
@@ -811,10 +811,8 @@ static int net_close(struct net_device *dev)
/* No statistic counters on the chip to update. */
/* Disable the IRQ on boards of fmv18x where it is feasible. */
- if (lp->jumpered) {
+ if (lp->jumpered)
outb(0x00, ioaddr + IOCONFIG1);
- free_irq(dev->irq, dev);
- }
/* Power-down the chip. Green, green, green! */
outb(0x00, ioaddr + CONFIG_1);
diff --git a/drivers/net/atl1c/atl1c.h b/drivers/net/atl1c/atl1c.h
index 84ae905bf73..52abbbdf8a0 100644
--- a/drivers/net/atl1c/atl1c.h
+++ b/drivers/net/atl1c/atl1c.h
@@ -73,7 +73,8 @@
#define FULL_DUPLEX 2
#define AT_RX_BUF_SIZE (ETH_FRAME_LEN + VLAN_HLEN + ETH_FCS_LEN)
-#define MAX_JUMBO_FRAME_SIZE (9*1024)
+#define MAX_JUMBO_FRAME_SIZE (6*1024)
+#define MAX_TSO_FRAME_SIZE (7*1024)
#define MAX_TX_OFFLOAD_THRESH (9*1024)
#define AT_MAX_RECEIVE_QUEUE 4
@@ -87,10 +88,11 @@
#define AT_MAX_INT_WORK 5
#define AT_TWSI_EEPROM_TIMEOUT 100
#define AT_HW_MAX_IDLE_DELAY 10
-#define AT_SUSPEND_LINK_TIMEOUT 28
+#define AT_SUSPEND_LINK_TIMEOUT 100
#define AT_ASPM_L0S_TIMER 6
#define AT_ASPM_L1_TIMER 12
+#define AT_LCKDET_TIMER 12
#define ATL1C_PCIE_L0S_L1_DISABLE 0x01
#define ATL1C_PCIE_PHY_RESET 0x02
@@ -316,6 +318,7 @@ enum atl1c_nic_type {
athr_l2c_b,
athr_l2c_b2,
athr_l1d,
+ athr_l1d_2,
};
enum atl1c_trans_queue {
@@ -392,6 +395,8 @@ struct atl1c_hw {
u16 subsystem_id;
u16 subsystem_vendor_id;
u8 revision_id;
+ u16 phy_id1;
+ u16 phy_id2;
u32 intr_mask;
u8 dmaw_dly_cnt;
diff --git a/drivers/net/atl1c/atl1c_hw.c b/drivers/net/atl1c/atl1c_hw.c
index f1389d664a2..d8501f06095 100644
--- a/drivers/net/atl1c/atl1c_hw.c
+++ b/drivers/net/atl1c/atl1c_hw.c
@@ -37,6 +37,9 @@ int atl1c_check_eeprom_exist(struct atl1c_hw *hw)
if (data & TWSI_DEBUG_DEV_EXIST)
return 1;
+ AT_READ_REG(hw, REG_MASTER_CTRL, &data);
+ if (data & MASTER_CTRL_OTP_SEL)
+ return 1;
return 0;
}
@@ -69,6 +72,8 @@ static int atl1c_get_permanent_address(struct atl1c_hw *hw)
u32 i;
u32 otp_ctrl_data;
u32 twsi_ctrl_data;
+ u32 ltssm_ctrl_data;
+ u32 wol_data;
u8 eth_addr[ETH_ALEN];
u16 phy_data;
bool raise_vol = false;
@@ -104,6 +109,15 @@ static int atl1c_get_permanent_address(struct atl1c_hw *hw)
udelay(20);
raise_vol = true;
}
+ /* close open bit of ReadOnly*/
+ AT_READ_REG(hw, REG_LTSSM_ID_CTRL, &ltssm_ctrl_data);
+ ltssm_ctrl_data &= ~LTSSM_ID_EN_WRO;
+ AT_WRITE_REG(hw, REG_LTSSM_ID_CTRL, ltssm_ctrl_data);
+
+ /* clear any WOL settings */
+ AT_WRITE_REG(hw, REG_WOL_CTRL, 0);
+ AT_READ_REG(hw, REG_WOL_CTRL, &wol_data);
+
AT_READ_REG(hw, REG_TWSI_CTRL, &twsi_ctrl_data);
twsi_ctrl_data |= TWSI_CTRL_SW_LDSTART;
@@ -119,17 +133,15 @@ static int atl1c_get_permanent_address(struct atl1c_hw *hw)
}
/* Disable OTP_CLK */
if ((hw->nic_type == athr_l1c || hw->nic_type == athr_l2c)) {
- if (otp_ctrl_data & OTP_CTRL_CLK_EN) {
- otp_ctrl_data &= ~OTP_CTRL_CLK_EN;
- AT_WRITE_REG(hw, REG_OTP_CTRL, otp_ctrl_data);
- AT_WRITE_FLUSH(hw);
- msleep(1);
- }
+ otp_ctrl_data &= ~OTP_CTRL_CLK_EN;
+ AT_WRITE_REG(hw, REG_OTP_CTRL, otp_ctrl_data);
+ msleep(1);
}
if (raise_vol) {
if (hw->nic_type == athr_l2c_b ||
hw->nic_type == athr_l2c_b2 ||
- hw->nic_type == athr_l1d) {
+ hw->nic_type == athr_l1d ||
+ hw->nic_type == athr_l1d_2) {
atl1c_write_phy_reg(hw, MII_DBG_ADDR, 0x00);
if (atl1c_read_phy_reg(hw, MII_DBG_DATA, &phy_data))
goto out;
@@ -456,14 +468,22 @@ int atl1c_phy_reset(struct atl1c_hw *hw)
if (hw->nic_type == athr_l2c_b ||
hw->nic_type == athr_l2c_b2 ||
- hw->nic_type == athr_l1d) {
+ hw->nic_type == athr_l1d ||
+ hw->nic_type == athr_l1d_2) {
atl1c_write_phy_reg(hw, MII_DBG_ADDR, 0x3B);
atl1c_read_phy_reg(hw, MII_DBG_DATA, &phy_data);
atl1c_write_phy_reg(hw, MII_DBG_DATA, phy_data & 0xFFF7);
msleep(20);
}
-
- /*Enable PHY LinkChange Interrupt */
+ if (hw->nic_type == athr_l1d) {
+ atl1c_write_phy_reg(hw, MII_DBG_ADDR, 0x29);
+ atl1c_write_phy_reg(hw, MII_DBG_DATA, 0x929D);
+ }
+ if (hw->nic_type == athr_l1c || hw->nic_type == athr_l2c_b2
+ || hw->nic_type == athr_l2c || hw->nic_type == athr_l2c) {
+ atl1c_write_phy_reg(hw, MII_DBG_ADDR, 0x29);
+ atl1c_write_phy_reg(hw, MII_DBG_DATA, 0xB6DD);
+ }
err = atl1c_write_phy_reg(hw, MII_IER, mii_ier_data);
if (err) {
if (netif_msg_hw(adapter))
@@ -482,12 +502,10 @@ int atl1c_phy_init(struct atl1c_hw *hw)
struct pci_dev *pdev = adapter->pdev;
int ret_val;
u16 mii_bmcr_data = BMCR_RESET;
- u16 phy_id1, phy_id2;
- if ((atl1c_read_phy_reg(hw, MII_PHYSID1, &phy_id1) != 0) ||
- (atl1c_read_phy_reg(hw, MII_PHYSID2, &phy_id2) != 0)) {
- if (netif_msg_link(adapter))
- dev_err(&pdev->dev, "Error get phy ID\n");
+ if ((atl1c_read_phy_reg(hw, MII_PHYSID1, &hw->phy_id1) != 0) ||
+ (atl1c_read_phy_reg(hw, MII_PHYSID2, &hw->phy_id2) != 0)) {
+ dev_err(&pdev->dev, "Error get phy ID\n");
return -1;
}
switch (hw->media_type) {
@@ -572,6 +590,65 @@ int atl1c_get_speed_and_duplex(struct atl1c_hw *hw, u16 *speed, u16 *duplex)
return 0;
}
+int atl1c_phy_power_saving(struct atl1c_hw *hw)
+{
+ struct atl1c_adapter *adapter = (struct atl1c_adapter *)hw->adapter;
+ struct pci_dev *pdev = adapter->pdev;
+ int ret = 0;
+ u16 autoneg_advertised = ADVERTISED_10baseT_Half;
+ u16 save_autoneg_advertised;
+ u16 phy_data;
+ u16 mii_lpa_data;
+ u16 speed = SPEED_0;
+ u16 duplex = FULL_DUPLEX;
+ int i;
+
+ atl1c_read_phy_reg(hw, MII_BMSR, &phy_data);
+ atl1c_read_phy_reg(hw, MII_BMSR, &phy_data);
+ if (phy_data & BMSR_LSTATUS) {
+ atl1c_read_phy_reg(hw, MII_LPA, &mii_lpa_data);
+ if (mii_lpa_data & LPA_10FULL)
+ autoneg_advertised = ADVERTISED_10baseT_Full;
+ else if (mii_lpa_data & LPA_10HALF)
+ autoneg_advertised = ADVERTISED_10baseT_Half;
+ else if (mii_lpa_data & LPA_100HALF)
+ autoneg_advertised = ADVERTISED_100baseT_Half;
+ else if (mii_lpa_data & LPA_100FULL)
+ autoneg_advertised = ADVERTISED_100baseT_Full;
+
+ save_autoneg_advertised = hw->autoneg_advertised;
+ hw->phy_configured = false;
+ hw->autoneg_advertised = autoneg_advertised;
+ if (atl1c_restart_autoneg(hw) != 0) {
+ dev_dbg(&pdev->dev, "phy autoneg failed\n");
+ ret = -1;
+ }
+ hw->autoneg_advertised = save_autoneg_advertised;
+
+ if (mii_lpa_data) {
+ for (i = 0; i < AT_SUSPEND_LINK_TIMEOUT; i++) {
+ mdelay(100);
+ atl1c_read_phy_reg(hw, MII_BMSR, &phy_data);
+ atl1c_read_phy_reg(hw, MII_BMSR, &phy_data);
+ if (phy_data & BMSR_LSTATUS) {
+ if (atl1c_get_speed_and_duplex(hw, &speed,
+ &duplex) != 0)
+ dev_dbg(&pdev->dev,
+ "get speed and duplex failed\n");
+ break;
+ }
+ }
+ }
+ } else {
+ speed = SPEED_10;
+ duplex = HALF_DUPLEX;
+ }
+ adapter->link_speed = speed;
+ adapter->link_duplex = duplex;
+
+ return ret;
+}
+
int atl1c_restart_autoneg(struct atl1c_hw *hw)
{
int err = 0;
diff --git a/drivers/net/atl1c/atl1c_hw.h b/drivers/net/atl1c/atl1c_hw.h
index 1eeb3ed9f0c..3dd675979aa 100644
--- a/drivers/net/atl1c/atl1c_hw.h
+++ b/drivers/net/atl1c/atl1c_hw.h
@@ -42,7 +42,7 @@ bool atl1c_read_eeprom(struct atl1c_hw *hw, u32 offset, u32 *p_value);
int atl1c_phy_init(struct atl1c_hw *hw);
int atl1c_check_eeprom_exist(struct atl1c_hw *hw);
int atl1c_restart_autoneg(struct atl1c_hw *hw);
-
+int atl1c_phy_power_saving(struct atl1c_hw *hw);
/* register definition */
#define REG_DEVICE_CAP 0x5C
#define DEVICE_CAP_MAX_PAYLOAD_MASK 0x7
@@ -120,6 +120,12 @@ int atl1c_restart_autoneg(struct atl1c_hw *hw);
#define REG_PCIE_PHYMISC 0x1000
#define PCIE_PHYMISC_FORCE_RCV_DET 0x4
+#define REG_PCIE_PHYMISC2 0x1004
+#define PCIE_PHYMISC2_SERDES_CDR_MASK 0x3
+#define PCIE_PHYMISC2_SERDES_CDR_SHIFT 16
+#define PCIE_PHYMISC2_SERDES_TH_MASK 0x3
+#define PCIE_PHYMISC2_SERDES_TH_SHIFT 18
+
#define REG_TWSI_DEBUG 0x1108
#define TWSI_DEBUG_DEV_EXIST 0x20000000
@@ -150,24 +156,28 @@ int atl1c_restart_autoneg(struct atl1c_hw *hw);
#define PM_CTRL_ASPM_L0S_EN 0x00001000
#define PM_CTRL_CLK_SWH_L1 0x00002000
#define PM_CTRL_CLK_PWM_VER1_1 0x00004000
-#define PM_CTRL_PCIE_RECV 0x00008000
+#define PM_CTRL_RCVR_WT_TIMER 0x00008000
#define PM_CTRL_L1_ENTRY_TIMER_MASK 0xF
#define PM_CTRL_L1_ENTRY_TIMER_SHIFT 16
#define PM_CTRL_PM_REQ_TIMER_MASK 0xF
#define PM_CTRL_PM_REQ_TIMER_SHIFT 20
-#define PM_CTRL_LCKDET_TIMER_MASK 0x3F
+#define PM_CTRL_LCKDET_TIMER_MASK 0xF
#define PM_CTRL_LCKDET_TIMER_SHIFT 24
#define PM_CTRL_EN_BUFS_RX_L0S 0x10000000
#define PM_CTRL_SA_DLY_EN 0x20000000
#define PM_CTRL_MAC_ASPM_CHK 0x40000000
#define PM_CTRL_HOTRST 0x80000000
+#define REG_LTSSM_ID_CTRL 0x12FC
+#define LTSSM_ID_EN_WRO 0x1000
/* Selene Master Control Register */
#define REG_MASTER_CTRL 0x1400
#define MASTER_CTRL_SOFT_RST 0x1
#define MASTER_CTRL_TEST_MODE_MASK 0x3
#define MASTER_CTRL_TEST_MODE_SHIFT 2
#define MASTER_CTRL_BERT_START 0x10
+#define MASTER_CTRL_OOB_DIS_OFF 0x40
+#define MASTER_CTRL_SA_TIMER_EN 0x80
#define MASTER_CTRL_MTIMER_EN 0x100
#define MASTER_CTRL_MANUAL_INT 0x200
#define MASTER_CTRL_TX_ITIMER_EN 0x400
@@ -220,6 +230,12 @@ int atl1c_restart_autoneg(struct atl1c_hw *hw);
GPHY_CTRL_PWDOWN_HW |\
GPHY_CTRL_PHY_IDDQ)
+#define GPHY_CTRL_POWER_SAVING ( \
+ GPHY_CTRL_SEL_ANA_RST |\
+ GPHY_CTRL_HIB_EN |\
+ GPHY_CTRL_HIB_PULSE |\
+ GPHY_CTRL_PWDOWN_HW |\
+ GPHY_CTRL_PHY_IDDQ)
/* Block IDLE Status Register */
#define REG_IDLE_STATUS 0x1410
#define IDLE_STATUS_MASK 0x00FF
@@ -287,6 +303,14 @@ int atl1c_restart_autoneg(struct atl1c_hw *hw);
#define SERDES_LOCK_DETECT 0x1 /* SerDes lock detected. This signal
* comes from Analog SerDes */
#define SERDES_LOCK_DETECT_EN 0x2 /* 1: Enable SerDes Lock detect function */
+#define SERDES_LOCK_STS_SELFB_PLL_SHIFT 0xE
+#define SERDES_LOCK_STS_SELFB_PLL_MASK 0x3
+#define SERDES_OVCLK_18_25 0x0
+#define SERDES_OVCLK_12_18 0x1
+#define SERDES_OVCLK_0_4 0x2
+#define SERDES_OVCLK_4_12 0x3
+#define SERDES_MAC_CLK_SLOWDOWN 0x20000
+#define SERDES_PYH_CLK_SLOWDOWN 0x40000
/* MAC Control Register */
#define REG_MAC_CTRL 0x1480
@@ -693,6 +717,21 @@ int atl1c_restart_autoneg(struct atl1c_hw *hw);
#define REG_MAC_TX_STATUS_BIN 0x1760
#define REG_MAC_TX_STATUS_END 0x17c0
+#define REG_CLK_GATING_CTRL 0x1814
+#define CLK_GATING_DMAW_EN 0x0001
+#define CLK_GATING_DMAR_EN 0x0002
+#define CLK_GATING_TXQ_EN 0x0004
+#define CLK_GATING_RXQ_EN 0x0008
+#define CLK_GATING_TXMAC_EN 0x0010
+#define CLK_GATING_RXMAC_EN 0x0020
+
+#define CLK_GATING_EN_ALL (CLK_GATING_DMAW_EN |\
+ CLK_GATING_DMAR_EN |\
+ CLK_GATING_TXQ_EN |\
+ CLK_GATING_RXQ_EN |\
+ CLK_GATING_TXMAC_EN|\
+ CLK_GATING_RXMAC_EN)
+
/* DEBUG ADDR */
#define REG_DEBUG_DATA0 0x1900
#define REG_DEBUG_DATA1 0x1904
@@ -734,6 +773,10 @@ int atl1c_restart_autoneg(struct atl1c_hw *hw);
#define MII_PHYSID1 0x02
#define MII_PHYSID2 0x03
+#define L1D_MPW_PHYID1 0xD01C /* V7 */
+#define L1D_MPW_PHYID2 0xD01D /* V1-V6 */
+#define L1D_MPW_PHYID3 0xD01E /* V8 */
+
/* Autoneg Advertisement Register */
#define MII_ADVERTISE 0x04
diff --git a/drivers/net/atl1c/atl1c_main.c b/drivers/net/atl1c/atl1c_main.c
index 1c3c046d5f3..c7b8ef507eb 100644
--- a/drivers/net/atl1c/atl1c_main.c
+++ b/drivers/net/atl1c/atl1c_main.c
@@ -21,7 +21,7 @@
#include "atl1c.h"
-#define ATL1C_DRV_VERSION "1.0.0.2-NAPI"
+#define ATL1C_DRV_VERSION "1.0.1.0-NAPI"
char atl1c_driver_name[] = "atl1c";
char atl1c_driver_version[] = ATL1C_DRV_VERSION;
#define PCI_DEVICE_ID_ATTANSIC_L2C 0x1062
@@ -29,7 +29,7 @@ char atl1c_driver_version[] = ATL1C_DRV_VERSION;
#define PCI_DEVICE_ID_ATHEROS_L2C_B 0x2060 /* AR8152 v1.1 Fast 10/100 */
#define PCI_DEVICE_ID_ATHEROS_L2C_B2 0x2062 /* AR8152 v2.0 Fast 10/100 */
#define PCI_DEVICE_ID_ATHEROS_L1D 0x1073 /* AR8151 v1.0 Gigabit 1000 */
-
+#define PCI_DEVICE_ID_ATHEROS_L1D_2_0 0x1083 /* AR8151 v2.0 Gigabit 1000 */
#define L2CB_V10 0xc0
#define L2CB_V11 0xc1
@@ -97,7 +97,28 @@ static const u16 atl1c_rrd_addr_lo_regs[AT_MAX_RECEIVE_QUEUE] =
static const u32 atl1c_default_msg = NETIF_MSG_DRV | NETIF_MSG_PROBE |
NETIF_MSG_LINK | NETIF_MSG_TIMER | NETIF_MSG_IFDOWN | NETIF_MSG_IFUP;
+static void atl1c_pcie_patch(struct atl1c_hw *hw)
+{
+ u32 data;
+ AT_READ_REG(hw, REG_PCIE_PHYMISC, &data);
+ data |= PCIE_PHYMISC_FORCE_RCV_DET;
+ AT_WRITE_REG(hw, REG_PCIE_PHYMISC, data);
+
+ if (hw->nic_type == athr_l2c_b && hw->revision_id == L2CB_V10) {
+ AT_READ_REG(hw, REG_PCIE_PHYMISC2, &data);
+
+ data &= ~(PCIE_PHYMISC2_SERDES_CDR_MASK <<
+ PCIE_PHYMISC2_SERDES_CDR_SHIFT);
+ data |= 3 << PCIE_PHYMISC2_SERDES_CDR_SHIFT;
+ data &= ~(PCIE_PHYMISC2_SERDES_TH_MASK <<
+ PCIE_PHYMISC2_SERDES_TH_SHIFT);
+ data |= 3 << PCIE_PHYMISC2_SERDES_TH_SHIFT;
+ AT_WRITE_REG(hw, REG_PCIE_PHYMISC2, data);
+ }
+}
+
+/* FIXME: no need any more ? */
/*
* atl1c_init_pcie - init PCIE module
*/
@@ -127,6 +148,11 @@ static void atl1c_reset_pcie(struct atl1c_hw *hw, u32 flag)
data &= ~PCIE_UC_SERVRITY_FCP;
AT_WRITE_REG(hw, REG_PCIE_UC_SEVERITY, data);
+ AT_READ_REG(hw, REG_LTSSM_ID_CTRL, &data);
+ data &= ~LTSSM_ID_EN_WRO;
+ AT_WRITE_REG(hw, REG_LTSSM_ID_CTRL, data);
+
+ atl1c_pcie_patch(hw);
if (flag & ATL1C_PCIE_L0S_L1_DISABLE)
atl1c_disable_l0s_l1(hw);
if (flag & ATL1C_PCIE_PHY_RESET)
@@ -135,7 +161,7 @@ static void atl1c_reset_pcie(struct atl1c_hw *hw, u32 flag)
AT_WRITE_REG(hw, REG_GPHY_CTRL,
GPHY_CTRL_DEFAULT | GPHY_CTRL_EXT_RESET);
- msleep(1);
+ msleep(5);
}
/*
@@ -159,6 +185,7 @@ static inline void atl1c_irq_disable(struct atl1c_adapter *adapter)
{
atomic_inc(&adapter->irq_sem);
AT_WRITE_REG(&adapter->hw, REG_IMR, 0);
+ AT_WRITE_REG(&adapter->hw, REG_ISR, ISR_DIS_INT);
AT_WRITE_FLUSH(&adapter->hw);
synchronize_irq(adapter->pdev->irq);
}
@@ -231,15 +258,15 @@ static void atl1c_check_link_status(struct atl1c_adapter *adapter)
if ((phy_data & BMSR_LSTATUS) == 0) {
/* link down */
- if (netif_carrier_ok(netdev)) {
- hw->hibernate = true;
- if (atl1c_stop_mac(hw) != 0)
- if (netif_msg_hw(adapter))
- dev_warn(&pdev->dev,
- "stop mac failed\n");
- atl1c_set_aspm(hw, false);
- }
+ hw->hibernate = true;
+ if (atl1c_stop_mac(hw) != 0)
+ if (netif_msg_hw(adapter))
+ dev_warn(&pdev->dev, "stop mac failed\n");
+ atl1c_set_aspm(hw, false);
netif_carrier_off(netdev);
+ netif_stop_queue(netdev);
+ atl1c_phy_reset(hw);
+ atl1c_phy_init(&adapter->hw);
} else {
/* Link Up */
hw->hibernate = false;
@@ -308,6 +335,7 @@ static void atl1c_common_task(struct work_struct *work)
netdev = adapter->netdev;
if (adapter->work_event & ATL1C_WORK_EVENT_RESET) {
+ adapter->work_event &= ~ATL1C_WORK_EVENT_RESET;
netif_device_detach(netdev);
atl1c_down(adapter);
atl1c_up(adapter);
@@ -315,8 +343,11 @@ static void atl1c_common_task(struct work_struct *work)
return;
}
- if (adapter->work_event & ATL1C_WORK_EVENT_LINK_CHANGE)
+ if (adapter->work_event & ATL1C_WORK_EVENT_LINK_CHANGE) {
+ adapter->work_event &= ~ATL1C_WORK_EVENT_LINK_CHANGE;
atl1c_check_link_status(adapter);
+ }
+ return;
}
@@ -476,6 +507,13 @@ static int atl1c_change_mtu(struct net_device *netdev, int new_mtu)
netdev->mtu = new_mtu;
adapter->hw.max_frame_size = new_mtu;
atl1c_set_rxbufsize(adapter, netdev);
+ if (new_mtu > MAX_TSO_FRAME_SIZE) {
+ adapter->netdev->features &= ~NETIF_F_TSO;
+ adapter->netdev->features &= ~NETIF_F_TSO6;
+ } else {
+ adapter->netdev->features |= NETIF_F_TSO;
+ adapter->netdev->features |= NETIF_F_TSO6;
+ }
atl1c_down(adapter);
atl1c_up(adapter);
clear_bit(__AT_RESETTING, &adapter->flags);
@@ -613,6 +651,9 @@ static void atl1c_set_mac_type(struct atl1c_hw *hw)
case PCI_DEVICE_ID_ATHEROS_L1D:
hw->nic_type = athr_l1d;
break;
+ case PCI_DEVICE_ID_ATHEROS_L1D_2_0:
+ hw->nic_type = athr_l1d_2;
+ break;
default:
break;
}
@@ -627,9 +668,7 @@ static int atl1c_setup_mac_funcs(struct atl1c_hw *hw)
AT_READ_REG(hw, REG_PHY_STATUS, &phy_status_data);
AT_READ_REG(hw, REG_LINK_CTRL, &link_ctrl_data);
- hw->ctrl_flags = ATL1C_INTR_CLEAR_ON_READ |
- ATL1C_INTR_MODRT_ENABLE |
- ATL1C_RX_IPV6_CHKSUM |
+ hw->ctrl_flags = ATL1C_INTR_MODRT_ENABLE |
ATL1C_TXQ_MODE_ENHANCE;
if (link_ctrl_data & LINK_CTRL_L0S_EN)
hw->ctrl_flags |= ATL1C_ASPM_L0S_SUPPORT;
@@ -637,12 +676,12 @@ static int atl1c_setup_mac_funcs(struct atl1c_hw *hw)
hw->ctrl_flags |= ATL1C_ASPM_L1_SUPPORT;
if (link_ctrl_data & LINK_CTRL_EXT_SYNC)
hw->ctrl_flags |= ATL1C_LINK_EXT_SYNC;
+ hw->ctrl_flags |= ATL1C_ASPM_CTRL_MON;
if (hw->nic_type == athr_l1c ||
- hw->nic_type == athr_l1d) {
- hw->ctrl_flags |= ATL1C_ASPM_CTRL_MON;
+ hw->nic_type == athr_l1d ||
+ hw->nic_type == athr_l1d_2)
hw->link_cap_flags |= ATL1C_LINK_CAP_1000M;
- }
return 0;
}
/*
@@ -657,6 +696,8 @@ static int __devinit atl1c_sw_init(struct atl1c_adapter *adapter)
{
struct atl1c_hw *hw = &adapter->hw;
struct pci_dev *pdev = adapter->pdev;
+ u32 revision;
+
adapter->wol = 0;
adapter->link_speed = SPEED_0;
@@ -669,7 +710,8 @@ static int __devinit atl1c_sw_init(struct atl1c_adapter *adapter)
hw->device_id = pdev->device;
hw->subsystem_vendor_id = pdev->subsystem_vendor;
hw->subsystem_id = pdev->subsystem_device;
-
+ AT_READ_REG(hw, PCI_CLASS_REVISION, &revision);
+ hw->revision_id = revision & 0xFF;
/* before link up, we assume hibernate is true */
hw->hibernate = true;
hw->media_type = MEDIA_TYPE_AUTO_SENSOR;
@@ -974,6 +1016,7 @@ static void atl1c_configure_des_ring(struct atl1c_adapter *adapter)
struct atl1c_cmb *cmb = (struct atl1c_cmb *) &adapter->cmb;
struct atl1c_smb *smb = (struct atl1c_smb *) &adapter->smb;
int i;
+ u32 data;
/* TPD */
AT_WRITE_REG(hw, REG_TX_BASE_ADDR_HI,
@@ -1017,6 +1060,23 @@ static void atl1c_configure_des_ring(struct atl1c_adapter *adapter)
(u32)((smb->dma & AT_DMA_HI_ADDR_MASK) >> 32));
AT_WRITE_REG(hw, REG_SMB_BASE_ADDR_LO,
(u32)(smb->dma & AT_DMA_LO_ADDR_MASK));
+ if (hw->nic_type == athr_l2c_b) {
+ AT_WRITE_REG(hw, REG_SRAM_RXF_LEN, 0x02a0L);
+ AT_WRITE_REG(hw, REG_SRAM_TXF_LEN, 0x0100L);
+ AT_WRITE_REG(hw, REG_SRAM_RXF_ADDR, 0x029f0000L);
+ AT_WRITE_REG(hw, REG_SRAM_RFD0_INFO, 0x02bf02a0L);
+ AT_WRITE_REG(hw, REG_SRAM_TXF_ADDR, 0x03bf02c0L);
+ AT_WRITE_REG(hw, REG_SRAM_TRD_ADDR, 0x03df03c0L);
+ AT_WRITE_REG(hw, REG_TXF_WATER_MARK, 0); /* TX watermark, to enter l1 state.*/
+ AT_WRITE_REG(hw, REG_RXD_DMA_CTRL, 0); /* RXD threshold.*/
+ }
+ if (hw->nic_type == athr_l2c_b || hw->nic_type == athr_l1d_2) {
+ /* Power Saving for L2c_B */
+ AT_READ_REG(hw, REG_SERDES_LOCK, &data);
+ data |= SERDES_MAC_CLK_SLOWDOWN;
+ data |= SERDES_PYH_CLK_SLOWDOWN;
+ AT_WRITE_REG(hw, REG_SERDES_LOCK, data);
+ }
/* Load all of base address above */
AT_WRITE_REG(hw, REG_LOAD_PTR, 1);
}
@@ -1029,6 +1089,7 @@ static void atl1c_configure_tx(struct atl1c_adapter *adapter)
u16 tx_offload_thresh;
u32 txq_ctrl_data;
u32 extra_size = 0; /* Jumbo frame threshold in QWORD unit */
+ u32 max_pay_load_data;
extra_size = ETH_HLEN + VLAN_HLEN + ETH_FCS_LEN;
tx_offload_thresh = MAX_TX_OFFLOAD_THRESH;
@@ -1046,8 +1107,11 @@ static void atl1c_configure_tx(struct atl1c_adapter *adapter)
TXQ_NUM_TPD_BURST_SHIFT;
if (hw->ctrl_flags & ATL1C_TXQ_MODE_ENHANCE)
txq_ctrl_data |= TXQ_CTRL_ENH_MODE;
- txq_ctrl_data |= (atl1c_pay_load_size[hw->dmar_block] &
+ max_pay_load_data = (atl1c_pay_load_size[hw->dmar_block] &
TXQ_TXF_BURST_NUM_MASK) << TXQ_TXF_BURST_NUM_SHIFT;
+ if (hw->nic_type == athr_l2c_b || hw->nic_type == athr_l2c_b2)
+ max_pay_load_data >>= 1;
+ txq_ctrl_data |= max_pay_load_data;
AT_WRITE_REG(hw, REG_TXQ_CTRL, txq_ctrl_data);
}
@@ -1078,7 +1142,7 @@ static void atl1c_configure_rx(struct atl1c_adapter *adapter)
rxq_ctrl_data |= (hw->rss_hash_bits & RSS_HASH_BITS_MASK) <<
RSS_HASH_BITS_SHIFT;
if (hw->ctrl_flags & ATL1C_ASPM_CTRL_MON)
- rxq_ctrl_data |= (ASPM_THRUPUT_LIMIT_100M &
+ rxq_ctrl_data |= (ASPM_THRUPUT_LIMIT_1M &
ASPM_THRUPUT_LIMIT_MASK) << ASPM_THRUPUT_LIMIT_SHIFT;
AT_WRITE_REG(hw, REG_RXQ_CTRL, rxq_ctrl_data);
@@ -1198,21 +1262,23 @@ static int atl1c_reset_mac(struct atl1c_hw *hw)
{
struct atl1c_adapter *adapter = (struct atl1c_adapter *)hw->adapter;
struct pci_dev *pdev = adapter->pdev;
- int ret;
+ u32 master_ctrl_data = 0;
AT_WRITE_REG(hw, REG_IMR, 0);
AT_WRITE_REG(hw, REG_ISR, ISR_DIS_INT);
- ret = atl1c_stop_mac(hw);
- if (ret)
- return ret;
+ atl1c_stop_mac(hw);
/*
* Issue Soft Reset to the MAC. This will reset the chip's
* transmit, receive, DMA. It will not effect
* the current PCI configuration. The global reset bit is self-
* clearing, and should clear within a microsecond.
*/
- AT_WRITE_REGW(hw, REG_MASTER_CTRL, MASTER_CTRL_SOFT_RST);
+ AT_READ_REG(hw, REG_MASTER_CTRL, &master_ctrl_data);
+ master_ctrl_data |= MASTER_CTRL_OOB_DIS_OFF;
+ AT_WRITE_REGW(hw, REG_MASTER_CTRL, ((master_ctrl_data | MASTER_CTRL_SOFT_RST)
+ & 0xFFFF));
+
AT_WRITE_FLUSH(hw);
msleep(10);
/* Wait at least 10ms for All module to be Idle */
@@ -1253,42 +1319,39 @@ static void atl1c_set_aspm(struct atl1c_hw *hw, bool linkup)
{
u32 pm_ctrl_data;
u32 link_ctrl_data;
+ u32 link_l1_timer = 0xF;
AT_READ_REG(hw, REG_PM_CTRL, &pm_ctrl_data);
AT_READ_REG(hw, REG_LINK_CTRL, &link_ctrl_data);
- pm_ctrl_data &= ~PM_CTRL_SERDES_PD_EX_L1;
+ pm_ctrl_data &= ~PM_CTRL_SERDES_PD_EX_L1;
pm_ctrl_data &= ~(PM_CTRL_L1_ENTRY_TIMER_MASK <<
PM_CTRL_L1_ENTRY_TIMER_SHIFT);
pm_ctrl_data &= ~(PM_CTRL_LCKDET_TIMER_MASK <<
- PM_CTRL_LCKDET_TIMER_SHIFT);
-
- pm_ctrl_data |= PM_CTRL_MAC_ASPM_CHK;
- pm_ctrl_data &= ~PM_CTRL_ASPM_L1_EN;
- pm_ctrl_data |= PM_CTRL_RBER_EN;
- pm_ctrl_data |= PM_CTRL_SDES_EN;
+ PM_CTRL_LCKDET_TIMER_SHIFT);
+ pm_ctrl_data |= AT_LCKDET_TIMER << PM_CTRL_LCKDET_TIMER_SHIFT;
- if (hw->nic_type == athr_l2c_b ||
- hw->nic_type == athr_l1d ||
- hw->nic_type == athr_l2c_b2) {
+ if (hw->nic_type == athr_l2c_b || hw->nic_type == athr_l1d ||
+ hw->nic_type == athr_l2c_b2 || hw->nic_type == athr_l1d_2) {
link_ctrl_data &= ~LINK_CTRL_EXT_SYNC;
if (!(hw->ctrl_flags & ATL1C_APS_MODE_ENABLE)) {
- if (hw->nic_type == athr_l2c_b &&
- hw->revision_id == L2CB_V10)
+ if (hw->nic_type == athr_l2c_b && hw->revision_id == L2CB_V10)
link_ctrl_data |= LINK_CTRL_EXT_SYNC;
}
AT_WRITE_REG(hw, REG_LINK_CTRL, link_ctrl_data);
- pm_ctrl_data |= PM_CTRL_PCIE_RECV;
- pm_ctrl_data |= AT_ASPM_L1_TIMER << PM_CTRL_PM_REQ_TIMER_SHIFT;
- pm_ctrl_data &= ~PM_CTRL_EN_BUFS_RX_L0S;
+ pm_ctrl_data |= PM_CTRL_RCVR_WT_TIMER;
+ pm_ctrl_data &= ~(PM_CTRL_PM_REQ_TIMER_MASK <<
+ PM_CTRL_PM_REQ_TIMER_SHIFT);
+ pm_ctrl_data |= AT_ASPM_L1_TIMER <<
+ PM_CTRL_PM_REQ_TIMER_SHIFT;
pm_ctrl_data &= ~PM_CTRL_SA_DLY_EN;
pm_ctrl_data &= ~PM_CTRL_HOTRST;
pm_ctrl_data |= 1 << PM_CTRL_L1_ENTRY_TIMER_SHIFT;
pm_ctrl_data |= PM_CTRL_SERDES_PD_EX_L1;
}
-
+ pm_ctrl_data |= PM_CTRL_MAC_ASPM_CHK;
if (linkup) {
pm_ctrl_data &= ~PM_CTRL_ASPM_L1_EN;
pm_ctrl_data &= ~PM_CTRL_ASPM_L0S_EN;
@@ -1297,27 +1360,26 @@ static void atl1c_set_aspm(struct atl1c_hw *hw, bool linkup)
if (hw->ctrl_flags & ATL1C_ASPM_L0S_SUPPORT)
pm_ctrl_data |= PM_CTRL_ASPM_L0S_EN;
- if (hw->nic_type == athr_l2c_b ||
- hw->nic_type == athr_l1d ||
- hw->nic_type == athr_l2c_b2) {
+ if (hw->nic_type == athr_l2c_b || hw->nic_type == athr_l1d ||
+ hw->nic_type == athr_l2c_b2 || hw->nic_type == athr_l1d_2) {
if (hw->nic_type == athr_l2c_b)
if (!(hw->ctrl_flags & ATL1C_APS_MODE_ENABLE))
- pm_ctrl_data &= PM_CTRL_ASPM_L0S_EN;
+ pm_ctrl_data &= ~PM_CTRL_ASPM_L0S_EN;
pm_ctrl_data &= ~PM_CTRL_SERDES_L1_EN;
pm_ctrl_data &= ~PM_CTRL_SERDES_PLL_L1_EN;
pm_ctrl_data &= ~PM_CTRL_SERDES_BUDS_RX_L1_EN;
pm_ctrl_data |= PM_CTRL_CLK_SWH_L1;
- if (hw->adapter->link_speed == SPEED_100 ||
- hw->adapter->link_speed == SPEED_1000) {
- pm_ctrl_data &=
- ~(PM_CTRL_L1_ENTRY_TIMER_MASK <<
- PM_CTRL_L1_ENTRY_TIMER_SHIFT);
- if (hw->nic_type == athr_l1d)
- pm_ctrl_data |= 0xF <<
- PM_CTRL_L1_ENTRY_TIMER_SHIFT;
- else
- pm_ctrl_data |= 7 <<
- PM_CTRL_L1_ENTRY_TIMER_SHIFT;
+ if (hw->adapter->link_speed == SPEED_100 ||
+ hw->adapter->link_speed == SPEED_1000) {
+ pm_ctrl_data &= ~(PM_CTRL_L1_ENTRY_TIMER_MASK <<
+ PM_CTRL_L1_ENTRY_TIMER_SHIFT);
+ if (hw->nic_type == athr_l2c_b)
+ link_l1_timer = 7;
+ else if (hw->nic_type == athr_l2c_b2 ||
+ hw->nic_type == athr_l1d_2)
+ link_l1_timer = 4;
+ pm_ctrl_data |= link_l1_timer <<
+ PM_CTRL_L1_ENTRY_TIMER_SHIFT;
}
} else {
pm_ctrl_data |= PM_CTRL_SERDES_L1_EN;
@@ -1326,24 +1388,12 @@ static void atl1c_set_aspm(struct atl1c_hw *hw, bool linkup)
pm_ctrl_data &= ~PM_CTRL_CLK_SWH_L1;
pm_ctrl_data &= ~PM_CTRL_ASPM_L0S_EN;
pm_ctrl_data &= ~PM_CTRL_ASPM_L1_EN;
- }
- atl1c_write_phy_reg(hw, MII_DBG_ADDR, 0x29);
- if (hw->adapter->link_speed == SPEED_10)
- if (hw->nic_type == athr_l1d)
- atl1c_write_phy_reg(hw, MII_DBG_ADDR, 0xB69D);
- else
- atl1c_write_phy_reg(hw, MII_DBG_DATA, 0xB6DD);
- else if (hw->adapter->link_speed == SPEED_100)
- atl1c_write_phy_reg(hw, MII_DBG_DATA, 0xB2DD);
- else
- atl1c_write_phy_reg(hw, MII_DBG_DATA, 0x96DD);
+ }
} else {
- pm_ctrl_data &= ~PM_CTRL_SERDES_BUDS_RX_L1_EN;
pm_ctrl_data &= ~PM_CTRL_SERDES_L1_EN;
pm_ctrl_data &= ~PM_CTRL_ASPM_L0S_EN;
pm_ctrl_data &= ~PM_CTRL_SERDES_PLL_L1_EN;
-
pm_ctrl_data |= PM_CTRL_CLK_SWH_L1;
if (hw->ctrl_flags & ATL1C_ASPM_L1_SUPPORT)
@@ -1351,8 +1401,9 @@ static void atl1c_set_aspm(struct atl1c_hw *hw, bool linkup)
else
pm_ctrl_data &= ~PM_CTRL_ASPM_L1_EN;
}
-
AT_WRITE_REG(hw, REG_PM_CTRL, pm_ctrl_data);
+
+ return;
}
static void atl1c_setup_mac_ctrl(struct atl1c_adapter *adapter)
@@ -1391,7 +1442,8 @@ static void atl1c_setup_mac_ctrl(struct atl1c_adapter *adapter)
mac_ctrl_data |= MAC_CTRL_MC_ALL_EN;
mac_ctrl_data |= MAC_CTRL_SINGLE_PAUSE_EN;
- if (hw->nic_type == athr_l1d || hw->nic_type == athr_l2c_b2) {
+ if (hw->nic_type == athr_l1d || hw->nic_type == athr_l2c_b2 ||
+ hw->nic_type == athr_l1d_2) {
mac_ctrl_data |= MAC_CTRL_SPEED_MODE_SW;
mac_ctrl_data |= MAC_CTRL_HASH_ALG_CRC32;
}
@@ -1409,6 +1461,7 @@ static int atl1c_configure(struct atl1c_adapter *adapter)
struct atl1c_hw *hw = &adapter->hw;
u32 master_ctrl_data = 0;
u32 intr_modrt_data;
+ u32 data;
/* clear interrupt status */
AT_WRITE_REG(hw, REG_ISR, 0xFFFFFFFF);
@@ -1418,6 +1471,15 @@ static int atl1c_configure(struct atl1c_adapter *adapter)
* HW will enable self to assert interrupt event to system after
* waiting x-time for software to notify it accept interrupt.
*/
+
+ data = CLK_GATING_EN_ALL;
+ if (hw->ctrl_flags & ATL1C_CLK_GATING_EN) {
+ if (hw->nic_type == athr_l2c_b)
+ data &= ~CLK_GATING_RXMAC_EN;
+ } else
+ data = 0;
+ AT_WRITE_REG(hw, REG_CLK_GATING_CTRL, data);
+
AT_WRITE_REG(hw, REG_INT_RETRIG_TIMER,
hw->ict & INT_RETRIG_TIMER_MASK);
@@ -1436,6 +1498,7 @@ static int atl1c_configure(struct atl1c_adapter *adapter)
if (hw->ctrl_flags & ATL1C_INTR_CLEAR_ON_READ)
master_ctrl_data |= MASTER_CTRL_INT_RDCLR;
+ master_ctrl_data |= MASTER_CTRL_SA_TIMER_EN;
AT_WRITE_REG(hw, REG_MASTER_CTRL, master_ctrl_data);
if (hw->ctrl_flags & ATL1C_CMB_ENABLE) {
@@ -1624,11 +1687,9 @@ static irqreturn_t atl1c_intr(int irq, void *data)
"atl1c hardware error (status = 0x%x)\n",
status & ISR_ERROR);
/* reset MAC */
- hw->intr_mask &= ~ISR_ERROR;
- AT_WRITE_REG(hw, REG_IMR, hw->intr_mask);
adapter->work_event |= ATL1C_WORK_EVENT_RESET;
schedule_work(&adapter->common_task);
- break;
+ return IRQ_HANDLED;
}
if (status & ISR_OVER)
@@ -2303,7 +2364,6 @@ void atl1c_down(struct atl1c_adapter *adapter)
napi_disable(&adapter->napi);
atl1c_irq_disable(adapter);
atl1c_free_irq(adapter);
- AT_WRITE_REG(&adapter->hw, REG_ISR, ISR_DIS_INT);
/* reset MAC to disable all RX/TX */
atl1c_reset_mac(&adapter->hw);
msleep(1);
@@ -2387,79 +2447,68 @@ static int atl1c_suspend(struct pci_dev *pdev, pm_message_t state)
struct net_device *netdev = pci_get_drvdata(pdev);
struct atl1c_adapter *adapter = netdev_priv(netdev);
struct atl1c_hw *hw = &adapter->hw;
- u32 ctrl;
- u32 mac_ctrl_data;
- u32 master_ctrl_data;
+ u32 mac_ctrl_data = 0;
+ u32 master_ctrl_data = 0;
u32 wol_ctrl_data = 0;
- u16 mii_bmsr_data;
- u16 save_autoneg_advertised;
- u16 mii_intr_status_data;
+ u16 mii_intr_status_data = 0;
u32 wufc = adapter->wol;
- u32 i;
int retval = 0;
+ atl1c_disable_l0s_l1(hw);
if (netif_running(netdev)) {
WARN_ON(test_bit(__AT_RESETTING, &adapter->flags));
atl1c_down(adapter);
}
netif_device_detach(netdev);
- atl1c_disable_l0s_l1(hw);
retval = pci_save_state(pdev);
if (retval)
return retval;
+
+ if (wufc)
+ if (atl1c_phy_power_saving(hw) != 0)
+ dev_dbg(&pdev->dev, "phy power saving failed");
+
+ AT_READ_REG(hw, REG_MASTER_CTRL, &master_ctrl_data);
+ AT_READ_REG(hw, REG_MAC_CTRL, &mac_ctrl_data);
+
+ master_ctrl_data &= ~MASTER_CTRL_CLK_SEL_DIS;
+ mac_ctrl_data &= ~(MAC_CTRL_PRMLEN_MASK << MAC_CTRL_PRMLEN_SHIFT);
+ mac_ctrl_data |= (((u32)adapter->hw.preamble_len &
+ MAC_CTRL_PRMLEN_MASK) <<
+ MAC_CTRL_PRMLEN_SHIFT);
+ mac_ctrl_data &= ~(MAC_CTRL_SPEED_MASK << MAC_CTRL_SPEED_SHIFT);
+ mac_ctrl_data &= ~MAC_CTRL_DUPLX;
+
if (wufc) {
- AT_READ_REG(hw, REG_MASTER_CTRL, &master_ctrl_data);
- master_ctrl_data &= ~MASTER_CTRL_CLK_SEL_DIS;
-
- /* get link status */
- atl1c_read_phy_reg(hw, MII_BMSR, (u16 *)&mii_bmsr_data);
- atl1c_read_phy_reg(hw, MII_BMSR, (u16 *)&mii_bmsr_data);
- save_autoneg_advertised = hw->autoneg_advertised;
- hw->autoneg_advertised = ADVERTISED_10baseT_Half;
- if (atl1c_restart_autoneg(hw) != 0)
- if (netif_msg_link(adapter))
- dev_warn(&pdev->dev, "phy autoneg failed\n");
- hw->phy_configured = false; /* re-init PHY when resume */
- hw->autoneg_advertised = save_autoneg_advertised;
+ mac_ctrl_data |= MAC_CTRL_RX_EN;
+ if (adapter->link_speed == SPEED_1000 ||
+ adapter->link_speed == SPEED_0) {
+ mac_ctrl_data |= atl1c_mac_speed_1000 <<
+ MAC_CTRL_SPEED_SHIFT;
+ mac_ctrl_data |= MAC_CTRL_DUPLX;
+ } else
+ mac_ctrl_data |= atl1c_mac_speed_10_100 <<
+ MAC_CTRL_SPEED_SHIFT;
+
+ if (adapter->link_duplex == DUPLEX_FULL)
+ mac_ctrl_data |= MAC_CTRL_DUPLX;
+
/* turn on magic packet wol */
if (wufc & AT_WUFC_MAG)
- wol_ctrl_data = WOL_MAGIC_EN | WOL_MAGIC_PME_EN;
+ wol_ctrl_data |= WOL_MAGIC_EN | WOL_MAGIC_PME_EN;
if (wufc & AT_WUFC_LNKC) {
- for (i = 0; i < AT_SUSPEND_LINK_TIMEOUT; i++) {
- msleep(100);
- atl1c_read_phy_reg(hw, MII_BMSR,
- (u16 *)&mii_bmsr_data);
- if (mii_bmsr_data & BMSR_LSTATUS)
- break;
- }
- if ((mii_bmsr_data & BMSR_LSTATUS) == 0)
- if (netif_msg_link(adapter))
- dev_warn(&pdev->dev,
- "%s: Link may change"
- "when suspend\n",
- atl1c_driver_name);
wol_ctrl_data |= WOL_LINK_CHG_EN | WOL_LINK_CHG_PME_EN;
/* only link up can wake up */
if (atl1c_write_phy_reg(hw, MII_IER, IER_LINK_UP) != 0) {
- if (netif_msg_link(adapter))
- dev_err(&pdev->dev,
- "%s: read write phy "
- "register failed.\n",
- atl1c_driver_name);
- goto wol_dis;
+ dev_dbg(&pdev->dev, "%s: read write phy "
+ "register failed.\n",
+ atl1c_driver_name);
}
}
/* clear phy interrupt */
atl1c_read_phy_reg(hw, MII_ISR, &mii_intr_status_data);
/* Config MAC Ctrl register */
- mac_ctrl_data = MAC_CTRL_RX_EN;
- /* set to 10/100M halt duplex */
- mac_ctrl_data |= atl1c_mac_speed_10_100 << MAC_CTRL_SPEED_SHIFT;
- mac_ctrl_data |= (((u32)adapter->hw.preamble_len &
- MAC_CTRL_PRMLEN_MASK) <<
- MAC_CTRL_PRMLEN_SHIFT);
-
if (adapter->vlgrp)
mac_ctrl_data |= MAC_CTRL_RMV_VLAN;
@@ -2467,37 +2516,30 @@ static int atl1c_suspend(struct pci_dev *pdev, pm_message_t state)
if (wufc & AT_WUFC_MAG)
mac_ctrl_data |= MAC_CTRL_BC_EN;
- if (netif_msg_hw(adapter))
- dev_dbg(&pdev->dev,
- "%s: suspend MAC=0x%x\n",
- atl1c_driver_name, mac_ctrl_data);
+ dev_dbg(&pdev->dev,
+ "%s: suspend MAC=0x%x\n",
+ atl1c_driver_name, mac_ctrl_data);
AT_WRITE_REG(hw, REG_MASTER_CTRL, master_ctrl_data);
AT_WRITE_REG(hw, REG_WOL_CTRL, wol_ctrl_data);
AT_WRITE_REG(hw, REG_MAC_CTRL, mac_ctrl_data);
/* pcie patch */
- AT_READ_REG(hw, REG_PCIE_PHYMISC, &ctrl);
- ctrl |= PCIE_PHYMISC_FORCE_RCV_DET;
- AT_WRITE_REG(hw, REG_PCIE_PHYMISC, ctrl);
+ device_set_wakeup_enable(&pdev->dev, 1);
- pci_enable_wake(pdev, pci_choose_state(pdev, state), 1);
- goto suspend_exit;
+ AT_WRITE_REG(hw, REG_GPHY_CTRL, GPHY_CTRL_DEFAULT |
+ GPHY_CTRL_EXT_RESET);
+ pci_prepare_to_sleep(pdev);
+ } else {
+ AT_WRITE_REG(hw, REG_GPHY_CTRL, GPHY_CTRL_POWER_SAVING);
+ master_ctrl_data |= MASTER_CTRL_CLK_SEL_DIS;
+ mac_ctrl_data |= atl1c_mac_speed_10_100 << MAC_CTRL_SPEED_SHIFT;
+ mac_ctrl_data |= MAC_CTRL_DUPLX;
+ AT_WRITE_REG(hw, REG_MASTER_CTRL, master_ctrl_data);
+ AT_WRITE_REG(hw, REG_MAC_CTRL, mac_ctrl_data);
+ AT_WRITE_REG(hw, REG_WOL_CTRL, 0);
+ hw->phy_configured = false; /* re-init PHY when resume */
+ pci_enable_wake(pdev, pci_choose_state(pdev, state), 0);
}
-wol_dis:
-
- /* WOL disabled */
- AT_WRITE_REG(hw, REG_WOL_CTRL, 0);
-
- /* pcie patch */
- AT_READ_REG(hw, REG_PCIE_PHYMISC, &ctrl);
- ctrl |= PCIE_PHYMISC_FORCE_RCV_DET;
- AT_WRITE_REG(hw, REG_PCIE_PHYMISC, ctrl);
-
- atl1c_phy_disable(hw);
- hw->phy_configured = false; /* re-init PHY when resume */
-
- pci_enable_wake(pdev, pci_choose_state(pdev, state), 0);
-suspend_exit:
pci_disable_device(pdev);
pci_set_power_state(pdev, pci_choose_state(pdev, state));
@@ -2516,9 +2558,19 @@ static int atl1c_resume(struct pci_dev *pdev)
pci_enable_wake(pdev, PCI_D3cold, 0);
AT_WRITE_REG(&adapter->hw, REG_WOL_CTRL, 0);
+ atl1c_reset_pcie(&adapter->hw, ATL1C_PCIE_L0S_L1_DISABLE |
+ ATL1C_PCIE_PHY_RESET);
atl1c_phy_reset(&adapter->hw);
atl1c_reset_mac(&adapter->hw);
+ atl1c_phy_init(&adapter->hw);
+
+#if 0
+ AT_READ_REG(&adapter->hw, REG_PM_CTRLSTAT, &pm_data);
+ pm_data &= ~PM_CTRLSTAT_PME_EN;
+ AT_WRITE_REG(&adapter->hw, REG_PM_CTRLSTAT, pm_data);
+#endif
+
netif_device_attach(netdev);
if (netif_running(netdev))
atl1c_up(adapter);
diff --git a/drivers/net/atlx/atl1.h b/drivers/net/atlx/atl1.h
index 146372fd668..9c0ddb273ac 100644
--- a/drivers/net/atlx/atl1.h
+++ b/drivers/net/atlx/atl1.h
@@ -436,8 +436,8 @@ struct rx_free_desc {
__le16 buf_len; /* Size of the receive buffer in host memory */
u16 coalese; /* Update consumer index to host after the
* reception of this frame */
- /* __attribute__ ((packed)) is required */
-} __attribute__ ((packed));
+ /* __packed is required */
+} __packed;
/*
* The L1 transmit packet descriptor is comprised of four 32-bit words.
diff --git a/drivers/net/au1000_eth.c b/drivers/net/au1000_eth.c
index ece6128bef1..15ae6df2ff0 100644
--- a/drivers/net/au1000_eth.c
+++ b/drivers/net/au1000_eth.c
@@ -104,14 +104,6 @@ MODULE_VERSION(DRV_VERSION);
* complete immediately.
*/
-/* These addresses are only used if yamon doesn't tell us what
- * the mac address is, and the mac address is not passed on the
- * command line.
- */
-static unsigned char au1000_mac_addr[6] __devinitdata = {
- 0x00, 0x50, 0xc2, 0x0c, 0x30, 0x00
-};
-
struct au1000_private *au_macs[NUM_ETH_INTERFACES];
/*
@@ -978,7 +970,7 @@ static int au1000_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
if (!aup->phy_dev)
return -EINVAL; /* PHY not controllable */
- return phy_mii_ioctl(aup->phy_dev, if_mii(rq), cmd);
+ return phy_mii_ioctl(aup->phy_dev, rq, cmd);
}
static const struct net_device_ops au1000_netdev_ops = {
@@ -1002,7 +994,6 @@ static int __devinit au1000_probe(struct platform_device *pdev)
db_dest_t *pDB, *pDBfree;
int irq, i, err = 0;
struct resource *base, *macen;
- char ethaddr[6];
base = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!base) {
@@ -1079,24 +1070,13 @@ static int __devinit au1000_probe(struct platform_device *pdev)
}
aup->mac_id = pdev->id;
- if (pdev->id == 0) {
- if (prom_get_ethernet_addr(ethaddr) == 0)
- memcpy(au1000_mac_addr, ethaddr, sizeof(au1000_mac_addr));
- else {
- netdev_info(dev, "No MAC address found\n");
- /* Use the hard coded MAC addresses */
- }
-
+ if (pdev->id == 0)
au1000_setup_hw_rings(aup, MAC0_RX_DMA_ADDR, MAC0_TX_DMA_ADDR);
- } else if (pdev->id == 1)
+ else if (pdev->id == 1)
au1000_setup_hw_rings(aup, MAC1_RX_DMA_ADDR, MAC1_TX_DMA_ADDR);
- /*
- * Assign to the Ethernet ports two consecutive MAC addresses
- * to match those that are printed on their stickers
- */
- memcpy(dev->dev_addr, au1000_mac_addr, sizeof(au1000_mac_addr));
- dev->dev_addr[5] += pdev->id;
+ /* set a random MAC now in case platform_data doesn't provide one */
+ random_ether_addr(dev->dev_addr);
*aup->enable = 0;
aup->mac_enabled = 0;
@@ -1106,6 +1086,9 @@ static int __devinit au1000_probe(struct platform_device *pdev)
dev_info(&pdev->dev, "no platform_data passed, PHY search on MAC0\n");
aup->phy1_search_mac0 = 1;
} else {
+ if (is_valid_ether_addr(pd->mac))
+ memcpy(dev->dev_addr, pd->mac, 6);
+
aup->phy_static_config = pd->phy_static_config;
aup->phy_search_highest_addr = pd->phy_search_highest_addr;
aup->phy1_search_mac0 = pd->phy1_search_mac0;
diff --git a/drivers/net/ax88796.c b/drivers/net/ax88796.c
index 55c9958043c..20e946b1e74 100644
--- a/drivers/net/ax88796.c
+++ b/drivers/net/ax88796.c
@@ -481,8 +481,10 @@ static int ax_open(struct net_device *dev)
return ret;
ret = ax_ei_open(dev);
- if (ret)
+ if (ret) {
+ free_irq(dev->irq, dev);
return ret;
+ }
/* turn the phy on (if turned off) */
diff --git a/drivers/net/b44.c b/drivers/net/b44.c
index 293f9c16e78..37617abc164 100644
--- a/drivers/net/b44.c
+++ b/drivers/net/b44.c
@@ -135,7 +135,6 @@ static void b44_init_rings(struct b44 *);
static void b44_init_hw(struct b44 *, int);
-static int dma_desc_align_mask;
static int dma_desc_sync_size;
static int instance;
@@ -150,9 +149,8 @@ static inline void b44_sync_dma_desc_for_device(struct ssb_device *sdev,
unsigned long offset,
enum dma_data_direction dir)
{
- ssb_dma_sync_single_range_for_device(sdev, dma_base,
- offset & dma_desc_align_mask,
- dma_desc_sync_size, dir);
+ dma_sync_single_for_device(sdev->dma_dev, dma_base + offset,
+ dma_desc_sync_size, dir);
}
static inline void b44_sync_dma_desc_for_cpu(struct ssb_device *sdev,
@@ -160,9 +158,8 @@ static inline void b44_sync_dma_desc_for_cpu(struct ssb_device *sdev,
unsigned long offset,
enum dma_data_direction dir)
{
- ssb_dma_sync_single_range_for_cpu(sdev, dma_base,
- offset & dma_desc_align_mask,
- dma_desc_sync_size, dir);
+ dma_sync_single_for_cpu(sdev->dma_dev, dma_base + offset,
+ dma_desc_sync_size, dir);
}
static inline unsigned long br32(const struct b44 *bp, unsigned long reg)
@@ -608,10 +605,10 @@ static void b44_tx(struct b44 *bp)
BUG_ON(skb == NULL);
- ssb_dma_unmap_single(bp->sdev,
- rp->mapping,
- skb->len,
- DMA_TO_DEVICE);
+ dma_unmap_single(bp->sdev->dma_dev,
+ rp->mapping,
+ skb->len,
+ DMA_TO_DEVICE);
rp->skb = NULL;
dev_kfree_skb_irq(skb);
}
@@ -648,29 +645,29 @@ static int b44_alloc_rx_skb(struct b44 *bp, int src_idx, u32 dest_idx_unmasked)
if (skb == NULL)
return -ENOMEM;
- mapping = ssb_dma_map_single(bp->sdev, skb->data,
- RX_PKT_BUF_SZ,
- DMA_FROM_DEVICE);
+ mapping = dma_map_single(bp->sdev->dma_dev, skb->data,
+ RX_PKT_BUF_SZ,
+ DMA_FROM_DEVICE);
/* Hardware bug work-around, the chip is unable to do PCI DMA
to/from anything above 1GB :-( */
- if (ssb_dma_mapping_error(bp->sdev, mapping) ||
+ if (dma_mapping_error(bp->sdev->dma_dev, mapping) ||
mapping + RX_PKT_BUF_SZ > DMA_BIT_MASK(30)) {
/* Sigh... */
- if (!ssb_dma_mapping_error(bp->sdev, mapping))
- ssb_dma_unmap_single(bp->sdev, mapping,
+ if (!dma_mapping_error(bp->sdev->dma_dev, mapping))
+ dma_unmap_single(bp->sdev->dma_dev, mapping,
RX_PKT_BUF_SZ, DMA_FROM_DEVICE);
dev_kfree_skb_any(skb);
skb = __netdev_alloc_skb(bp->dev, RX_PKT_BUF_SZ, GFP_ATOMIC|GFP_DMA);
if (skb == NULL)
return -ENOMEM;
- mapping = ssb_dma_map_single(bp->sdev, skb->data,
- RX_PKT_BUF_SZ,
- DMA_FROM_DEVICE);
- if (ssb_dma_mapping_error(bp->sdev, mapping) ||
- mapping + RX_PKT_BUF_SZ > DMA_BIT_MASK(30)) {
- if (!ssb_dma_mapping_error(bp->sdev, mapping))
- ssb_dma_unmap_single(bp->sdev, mapping, RX_PKT_BUF_SZ,DMA_FROM_DEVICE);
+ mapping = dma_map_single(bp->sdev->dma_dev, skb->data,
+ RX_PKT_BUF_SZ,
+ DMA_FROM_DEVICE);
+ if (dma_mapping_error(bp->sdev->dma_dev, mapping) ||
+ mapping + RX_PKT_BUF_SZ > DMA_BIT_MASK(30)) {
+ if (!dma_mapping_error(bp->sdev->dma_dev, mapping))
+ dma_unmap_single(bp->sdev->dma_dev, mapping, RX_PKT_BUF_SZ,DMA_FROM_DEVICE);
dev_kfree_skb_any(skb);
return -ENOMEM;
}
@@ -745,9 +742,9 @@ static void b44_recycle_rx(struct b44 *bp, int src_idx, u32 dest_idx_unmasked)
dest_idx * sizeof(*dest_desc),
DMA_BIDIRECTIONAL);
- ssb_dma_sync_single_for_device(bp->sdev, dest_map->mapping,
- RX_PKT_BUF_SZ,
- DMA_FROM_DEVICE);
+ dma_sync_single_for_device(bp->sdev->dma_dev, dest_map->mapping,
+ RX_PKT_BUF_SZ,
+ DMA_FROM_DEVICE);
}
static int b44_rx(struct b44 *bp, int budget)
@@ -767,9 +764,9 @@ static int b44_rx(struct b44 *bp, int budget)
struct rx_header *rh;
u16 len;
- ssb_dma_sync_single_for_cpu(bp->sdev, map,
- RX_PKT_BUF_SZ,
- DMA_FROM_DEVICE);
+ dma_sync_single_for_cpu(bp->sdev->dma_dev, map,
+ RX_PKT_BUF_SZ,
+ DMA_FROM_DEVICE);
rh = (struct rx_header *) skb->data;
len = le16_to_cpu(rh->len);
if ((len > (RX_PKT_BUF_SZ - RX_PKT_OFFSET)) ||
@@ -801,8 +798,8 @@ static int b44_rx(struct b44 *bp, int budget)
skb_size = b44_alloc_rx_skb(bp, cons, bp->rx_prod);
if (skb_size < 0)
goto drop_it;
- ssb_dma_unmap_single(bp->sdev, map,
- skb_size, DMA_FROM_DEVICE);
+ dma_unmap_single(bp->sdev->dma_dev, map,
+ skb_size, DMA_FROM_DEVICE);
/* Leave out rx_header */
skb_put(skb, len + RX_PKT_OFFSET);
skb_pull(skb, RX_PKT_OFFSET);
@@ -954,24 +951,24 @@ static netdev_tx_t b44_start_xmit(struct sk_buff *skb, struct net_device *dev)
goto err_out;
}
- mapping = ssb_dma_map_single(bp->sdev, skb->data, len, DMA_TO_DEVICE);
- if (ssb_dma_mapping_error(bp->sdev, mapping) || mapping + len > DMA_BIT_MASK(30)) {
+ mapping = dma_map_single(bp->sdev->dma_dev, skb->data, len, DMA_TO_DEVICE);
+ if (dma_mapping_error(bp->sdev->dma_dev, mapping) || mapping + len > DMA_BIT_MASK(30)) {
struct sk_buff *bounce_skb;
/* Chip can't handle DMA to/from >1GB, use bounce buffer */
- if (!ssb_dma_mapping_error(bp->sdev, mapping))
- ssb_dma_unmap_single(bp->sdev, mapping, len,
+ if (!dma_mapping_error(bp->sdev->dma_dev, mapping))
+ dma_unmap_single(bp->sdev->dma_dev, mapping, len,
DMA_TO_DEVICE);
bounce_skb = __netdev_alloc_skb(dev, len, GFP_ATOMIC | GFP_DMA);
if (!bounce_skb)
goto err_out;
- mapping = ssb_dma_map_single(bp->sdev, bounce_skb->data,
- len, DMA_TO_DEVICE);
- if (ssb_dma_mapping_error(bp->sdev, mapping) || mapping + len > DMA_BIT_MASK(30)) {
- if (!ssb_dma_mapping_error(bp->sdev, mapping))
- ssb_dma_unmap_single(bp->sdev, mapping,
+ mapping = dma_map_single(bp->sdev->dma_dev, bounce_skb->data,
+ len, DMA_TO_DEVICE);
+ if (dma_mapping_error(bp->sdev->dma_dev, mapping) || mapping + len > DMA_BIT_MASK(30)) {
+ if (!dma_mapping_error(bp->sdev->dma_dev, mapping))
+ dma_unmap_single(bp->sdev->dma_dev, mapping,
len, DMA_TO_DEVICE);
dev_kfree_skb_any(bounce_skb);
goto err_out;
@@ -1068,8 +1065,8 @@ static void b44_free_rings(struct b44 *bp)
if (rp->skb == NULL)
continue;
- ssb_dma_unmap_single(bp->sdev, rp->mapping, RX_PKT_BUF_SZ,
- DMA_FROM_DEVICE);
+ dma_unmap_single(bp->sdev->dma_dev, rp->mapping, RX_PKT_BUF_SZ,
+ DMA_FROM_DEVICE);
dev_kfree_skb_any(rp->skb);
rp->skb = NULL;
}
@@ -1080,8 +1077,8 @@ static void b44_free_rings(struct b44 *bp)
if (rp->skb == NULL)
continue;
- ssb_dma_unmap_single(bp->sdev, rp->mapping, rp->skb->len,
- DMA_TO_DEVICE);
+ dma_unmap_single(bp->sdev->dma_dev, rp->mapping, rp->skb->len,
+ DMA_TO_DEVICE);
dev_kfree_skb_any(rp->skb);
rp->skb = NULL;
}
@@ -1103,14 +1100,12 @@ static void b44_init_rings(struct b44 *bp)
memset(bp->tx_ring, 0, B44_TX_RING_BYTES);
if (bp->flags & B44_FLAG_RX_RING_HACK)
- ssb_dma_sync_single_for_device(bp->sdev, bp->rx_ring_dma,
- DMA_TABLE_BYTES,
- DMA_BIDIRECTIONAL);
+ dma_sync_single_for_device(bp->sdev->dma_dev, bp->rx_ring_dma,
+ DMA_TABLE_BYTES, DMA_BIDIRECTIONAL);
if (bp->flags & B44_FLAG_TX_RING_HACK)
- ssb_dma_sync_single_for_device(bp->sdev, bp->tx_ring_dma,
- DMA_TABLE_BYTES,
- DMA_TO_DEVICE);
+ dma_sync_single_for_device(bp->sdev->dma_dev, bp->tx_ring_dma,
+ DMA_TABLE_BYTES, DMA_TO_DEVICE);
for (i = 0; i < bp->rx_pending; i++) {
if (b44_alloc_rx_skb(bp, -1, i) < 0)
@@ -1130,27 +1125,23 @@ static void b44_free_consistent(struct b44 *bp)
bp->tx_buffers = NULL;
if (bp->rx_ring) {
if (bp->flags & B44_FLAG_RX_RING_HACK) {
- ssb_dma_unmap_single(bp->sdev, bp->rx_ring_dma,
- DMA_TABLE_BYTES,
- DMA_BIDIRECTIONAL);
+ dma_unmap_single(bp->sdev->dma_dev, bp->rx_ring_dma,
+ DMA_TABLE_BYTES, DMA_BIDIRECTIONAL);
kfree(bp->rx_ring);
} else
- ssb_dma_free_consistent(bp->sdev, DMA_TABLE_BYTES,
- bp->rx_ring, bp->rx_ring_dma,
- GFP_KERNEL);
+ dma_free_coherent(bp->sdev->dma_dev, DMA_TABLE_BYTES,
+ bp->rx_ring, bp->rx_ring_dma);
bp->rx_ring = NULL;
bp->flags &= ~B44_FLAG_RX_RING_HACK;
}
if (bp->tx_ring) {
if (bp->flags & B44_FLAG_TX_RING_HACK) {
- ssb_dma_unmap_single(bp->sdev, bp->tx_ring_dma,
- DMA_TABLE_BYTES,
- DMA_TO_DEVICE);
+ dma_unmap_single(bp->sdev->dma_dev, bp->tx_ring_dma,
+ DMA_TABLE_BYTES, DMA_TO_DEVICE);
kfree(bp->tx_ring);
} else
- ssb_dma_free_consistent(bp->sdev, DMA_TABLE_BYTES,
- bp->tx_ring, bp->tx_ring_dma,
- GFP_KERNEL);
+ dma_free_coherent(bp->sdev->dma_dev, DMA_TABLE_BYTES,
+ bp->tx_ring, bp->tx_ring_dma);
bp->tx_ring = NULL;
bp->flags &= ~B44_FLAG_TX_RING_HACK;
}
@@ -1175,7 +1166,8 @@ static int b44_alloc_consistent(struct b44 *bp, gfp_t gfp)
goto out_err;
size = DMA_TABLE_BYTES;
- bp->rx_ring = ssb_dma_alloc_consistent(bp->sdev, size, &bp->rx_ring_dma, gfp);
+ bp->rx_ring = dma_alloc_coherent(bp->sdev->dma_dev, size,
+ &bp->rx_ring_dma, gfp);
if (!bp->rx_ring) {
/* Allocation may have failed due to pci_alloc_consistent
insisting on use of GFP_DMA, which is more restrictive
@@ -1187,11 +1179,11 @@ static int b44_alloc_consistent(struct b44 *bp, gfp_t gfp)
if (!rx_ring)
goto out_err;
- rx_ring_dma = ssb_dma_map_single(bp->sdev, rx_ring,
- DMA_TABLE_BYTES,
- DMA_BIDIRECTIONAL);
+ rx_ring_dma = dma_map_single(bp->sdev->dma_dev, rx_ring,
+ DMA_TABLE_BYTES,
+ DMA_BIDIRECTIONAL);
- if (ssb_dma_mapping_error(bp->sdev, rx_ring_dma) ||
+ if (dma_mapping_error(bp->sdev->dma_dev, rx_ring_dma) ||
rx_ring_dma + size > DMA_BIT_MASK(30)) {
kfree(rx_ring);
goto out_err;
@@ -1202,7 +1194,8 @@ static int b44_alloc_consistent(struct b44 *bp, gfp_t gfp)
bp->flags |= B44_FLAG_RX_RING_HACK;
}
- bp->tx_ring = ssb_dma_alloc_consistent(bp->sdev, size, &bp->tx_ring_dma, gfp);
+ bp->tx_ring = dma_alloc_coherent(bp->sdev->dma_dev, size,
+ &bp->tx_ring_dma, gfp);
if (!bp->tx_ring) {
/* Allocation may have failed due to ssb_dma_alloc_consistent
insisting on use of GFP_DMA, which is more restrictive
@@ -1214,11 +1207,11 @@ static int b44_alloc_consistent(struct b44 *bp, gfp_t gfp)
if (!tx_ring)
goto out_err;
- tx_ring_dma = ssb_dma_map_single(bp->sdev, tx_ring,
- DMA_TABLE_BYTES,
- DMA_TO_DEVICE);
+ tx_ring_dma = dma_map_single(bp->sdev->dma_dev, tx_ring,
+ DMA_TABLE_BYTES,
+ DMA_TO_DEVICE);
- if (ssb_dma_mapping_error(bp->sdev, tx_ring_dma) ||
+ if (dma_mapping_error(bp->sdev->dma_dev, tx_ring_dma) ||
tx_ring_dma + size > DMA_BIT_MASK(30)) {
kfree(tx_ring);
goto out_err;
@@ -2176,12 +2169,14 @@ static int __devinit b44_init_one(struct ssb_device *sdev,
"Failed to powerup the bus\n");
goto err_out_free_dev;
}
- err = ssb_dma_set_mask(sdev, DMA_BIT_MASK(30));
- if (err) {
+
+ if (dma_set_mask(sdev->dma_dev, DMA_BIT_MASK(30)) ||
+ dma_set_coherent_mask(sdev->dma_dev, DMA_BIT_MASK(30))) {
dev_err(sdev->dev,
"Required 30BIT DMA mask unsupported by the system\n");
goto err_out_powerdown;
}
+
err = b44_get_invariants(bp);
if (err) {
dev_err(sdev->dev,
@@ -2344,7 +2339,6 @@ static int __init b44_init(void)
int err;
/* Setup paramaters for syncing RX/TX DMA descriptors */
- dma_desc_align_mask = ~(dma_desc_align_size - 1);
dma_desc_sync_size = max_t(unsigned int, dma_desc_align_size, sizeof(struct dma_desc));
err = b44_pci_init();
diff --git a/drivers/net/bcm63xx_enet.c b/drivers/net/bcm63xx_enet.c
index faf5add894d..0d2c5da0893 100644
--- a/drivers/net/bcm63xx_enet.c
+++ b/drivers/net/bcm63xx_enet.c
@@ -1496,7 +1496,7 @@ static int bcm_enet_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
if (priv->has_phy) {
if (!priv->phydev)
return -ENODEV;
- return phy_mii_ioctl(priv->phydev, if_mii(rq), cmd);
+ return phy_mii_ioctl(priv->phydev, rq, cmd);
} else {
struct mii_if_info mii;
diff --git a/drivers/net/benet/be.h b/drivers/net/benet/be.h
index b46be490cd2..99197bd54da 100644
--- a/drivers/net/benet/be.h
+++ b/drivers/net/benet/be.h
@@ -33,7 +33,7 @@
#include "be_hw.h"
-#define DRV_VER "2.102.147u"
+#define DRV_VER "2.103.175u"
#define DRV_NAME "be2net"
#define BE_NAME "ServerEngines BladeEngine2 10Gbps NIC"
#define BE3_NAME "ServerEngines BladeEngine3 10Gbps NIC"
@@ -220,7 +220,16 @@ struct be_rx_obj {
struct be_rx_page_info page_info_tbl[RX_Q_LEN];
};
+struct be_vf_cfg {
+ unsigned char vf_mac_addr[ETH_ALEN];
+ u32 vf_if_handle;
+ u32 vf_pmac_id;
+ u16 vf_vlan_tag;
+ u32 vf_tx_rate;
+};
+
#define BE_NUM_MSIX_VECTORS 2 /* 1 each for Tx and Rx */
+#define BE_INVALID_PMAC_ID 0xffffffff
struct be_adapter {
struct pci_dev *pdev;
struct net_device *netdev;
@@ -276,23 +285,26 @@ struct be_adapter {
u32 port_num;
bool promiscuous;
bool wol;
- u32 cap;
+ u32 function_mode;
u32 rx_fc; /* Rx flow control */
u32 tx_fc; /* Tx flow control */
+ bool ue_detected;
+ bool stats_ioctl_sent;
int link_speed;
u8 port_type;
u8 transceiver;
+ u8 autoneg;
u8 generation; /* BladeEngine ASIC generation */
u32 flash_status;
struct completion flash_compl;
bool sriov_enabled;
- u32 vf_if_handle[BE_MAX_VF];
- u32 vf_pmac_id[BE_MAX_VF];
+ struct be_vf_cfg vf_cfg[BE_MAX_VF];
u8 base_eq_id;
+ u8 is_virtfn;
};
-#define be_physfn(adapter) (!adapter->pdev->is_virtfn)
+#define be_physfn(adapter) (!adapter->is_virtfn)
/* BladeEngine Generation numbers */
#define BE_GEN2 2
@@ -392,6 +404,15 @@ static inline u8 is_udp_pkt(struct sk_buff *skb)
return val;
}
+static inline void be_check_sriov_fn_type(struct be_adapter *adapter)
+{
+ u8 data;
+
+ pci_write_config_byte(adapter->pdev, 0xFE, 0xAA);
+ pci_read_config_byte(adapter->pdev, 0xFE, &data);
+ adapter->is_virtfn = (data != 0xAA);
+}
+
extern void be_cq_notify(struct be_adapter *adapter, u16 qid, bool arm,
u16 num_popped);
extern void be_link_status_update(struct be_adapter *adapter, bool link_up);
diff --git a/drivers/net/benet/be_cmds.c b/drivers/net/benet/be_cmds.c
index b9ad799c719..3d305494a60 100644
--- a/drivers/net/benet/be_cmds.c
+++ b/drivers/net/benet/be_cmds.c
@@ -25,6 +25,8 @@ static void be_mcc_notify(struct be_adapter *adapter)
val |= mccq->id & DB_MCCQ_RING_ID_MASK;
val |= 1 << DB_MCCQ_NUM_POSTED_SHIFT;
+
+ wmb();
iowrite32(val, adapter->db + DB_MCCQ_OFFSET);
}
@@ -73,8 +75,10 @@ static int be_mcc_compl_process(struct be_adapter *adapter,
be_dws_le_to_cpu(&resp->hw_stats,
sizeof(resp->hw_stats));
netdev_stats_update(adapter);
+ adapter->stats_ioctl_sent = false;
}
- } else if (compl_status != MCC_STATUS_NOT_SUPPORTED) {
+ } else if ((compl_status != MCC_STATUS_NOT_SUPPORTED) &&
+ (compl->tag0 != OPCODE_COMMON_NTWK_MAC_QUERY)) {
extd_status = (compl->status >> CQE_STATUS_EXTD_SHIFT) &
CQE_STATUS_EXTD_MASK;
dev_warn(&adapter->pdev->dev,
@@ -186,7 +190,7 @@ static int be_mcc_notify_wait(struct be_adapter *adapter)
static int be_mbox_db_ready_wait(struct be_adapter *adapter, void __iomem *db)
{
- int cnt = 0, wait = 5;
+ int msecs = 0;
u32 ready;
do {
@@ -201,15 +205,15 @@ static int be_mbox_db_ready_wait(struct be_adapter *adapter, void __iomem *db)
if (ready)
break;
- if (cnt > 4000000) {
+ if (msecs > 4000) {
dev_err(&adapter->pdev->dev, "mbox poll timed out\n");
+ be_dump_ue(adapter);
return -1;
}
- if (cnt > 50)
- wait = 200;
- cnt += wait;
- udelay(wait);
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule_timeout(msecs_to_jiffies(1));
+ msecs++;
} while (true);
return 0;
@@ -948,6 +952,7 @@ int be_cmd_get_stats(struct be_adapter *adapter, struct be_dma_mem *nonemb_cmd)
sge->len = cpu_to_le32(nonemb_cmd->size);
be_mcc_notify(adapter);
+ adapter->stats_ioctl_sent = true;
err:
spin_unlock_bh(&adapter->mcc_lock);
@@ -1256,7 +1261,7 @@ err:
}
/* Uses mbox */
-int be_cmd_query_fw_cfg(struct be_adapter *adapter, u32 *port_num, u32 *cap)
+int be_cmd_query_fw_cfg(struct be_adapter *adapter, u32 *port_num, u32 *mode)
{
struct be_mcc_wrb *wrb;
struct be_cmd_req_query_fw_cfg *req;
@@ -1277,7 +1282,7 @@ int be_cmd_query_fw_cfg(struct be_adapter *adapter, u32 *port_num, u32 *cap)
if (!status) {
struct be_cmd_resp_query_fw_cfg *resp = embedded_payload(wrb);
*port_num = le32_to_cpu(resp->phys_port);
- *cap = le32_to_cpu(resp->function_cap);
+ *mode = le32_to_cpu(resp->function_mode);
}
spin_unlock(&adapter->mbox_lock);
@@ -1694,3 +1699,71 @@ int be_cmd_get_seeprom_data(struct be_adapter *adapter,
spin_unlock_bh(&adapter->mcc_lock);
return status;
}
+
+int be_cmd_get_phy_info(struct be_adapter *adapter, struct be_dma_mem *cmd)
+{
+ struct be_mcc_wrb *wrb;
+ struct be_cmd_req_get_phy_info *req;
+ struct be_sge *sge;
+ int status;
+
+ spin_lock_bh(&adapter->mcc_lock);
+
+ wrb = wrb_from_mccq(adapter);
+ if (!wrb) {
+ status = -EBUSY;
+ goto err;
+ }
+
+ req = cmd->va;
+ sge = nonembedded_sgl(wrb);
+
+ be_wrb_hdr_prepare(wrb, sizeof(*req), false, 1,
+ OPCODE_COMMON_GET_PHY_DETAILS);
+
+ be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
+ OPCODE_COMMON_GET_PHY_DETAILS,
+ sizeof(*req));
+
+ sge->pa_hi = cpu_to_le32(upper_32_bits(cmd->dma));
+ sge->pa_lo = cpu_to_le32(cmd->dma & 0xFFFFFFFF);
+ sge->len = cpu_to_le32(cmd->size);
+
+ status = be_mcc_notify_wait(adapter);
+err:
+ spin_unlock_bh(&adapter->mcc_lock);
+ return status;
+}
+
+int be_cmd_set_qos(struct be_adapter *adapter, u32 bps, u32 domain)
+{
+ struct be_mcc_wrb *wrb;
+ struct be_cmd_req_set_qos *req;
+ int status;
+
+ spin_lock_bh(&adapter->mcc_lock);
+
+ wrb = wrb_from_mccq(adapter);
+ if (!wrb) {
+ status = -EBUSY;
+ goto err;
+ }
+
+ req = embedded_payload(wrb);
+
+ be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0,
+ OPCODE_COMMON_SET_QOS);
+
+ be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
+ OPCODE_COMMON_SET_QOS, sizeof(*req));
+
+ req->hdr.domain = domain;
+ req->valid_bits = BE_QOS_BITS_NIC;
+ req->max_bps_nic = bps;
+
+ status = be_mcc_notify_wait(adapter);
+
+err:
+ spin_unlock_bh(&adapter->mcc_lock);
+ return status;
+}
diff --git a/drivers/net/benet/be_cmds.h b/drivers/net/benet/be_cmds.h
index 763dc199e33..bdc10a28cfd 100644
--- a/drivers/net/benet/be_cmds.h
+++ b/drivers/net/benet/be_cmds.h
@@ -124,6 +124,7 @@ struct be_mcc_mailbox {
#define OPCODE_COMMON_CQ_CREATE 12
#define OPCODE_COMMON_EQ_CREATE 13
#define OPCODE_COMMON_MCC_CREATE 21
+#define OPCODE_COMMON_SET_QOS 28
#define OPCODE_COMMON_SEEPROM_READ 30
#define OPCODE_COMMON_NTWK_RX_FILTER 34
#define OPCODE_COMMON_GET_FW_VERSION 35
@@ -144,6 +145,7 @@ struct be_mcc_mailbox {
#define OPCODE_COMMON_ENABLE_DISABLE_BEACON 69
#define OPCODE_COMMON_GET_BEACON_STATE 70
#define OPCODE_COMMON_READ_TRANSRECV_DATA 73
+#define OPCODE_COMMON_GET_PHY_DETAILS 102
#define OPCODE_ETH_ACPI_CONFIG 2
#define OPCODE_ETH_PROMISCUOUS 3
@@ -747,7 +749,7 @@ struct be_cmd_resp_query_fw_cfg {
u32 be_config_number;
u32 asic_revision;
u32 phys_port;
- u32 function_cap;
+ u32 function_mode;
u32 rsvd[26];
};
@@ -869,6 +871,46 @@ struct be_cmd_resp_seeprom_read {
u8 seeprom_data[BE_READ_SEEPROM_LEN];
};
+enum {
+ PHY_TYPE_CX4_10GB = 0,
+ PHY_TYPE_XFP_10GB,
+ PHY_TYPE_SFP_1GB,
+ PHY_TYPE_SFP_PLUS_10GB,
+ PHY_TYPE_KR_10GB,
+ PHY_TYPE_KX4_10GB,
+ PHY_TYPE_BASET_10GB,
+ PHY_TYPE_BASET_1GB,
+ PHY_TYPE_DISABLED = 255
+};
+
+struct be_cmd_req_get_phy_info {
+ struct be_cmd_req_hdr hdr;
+ u8 rsvd0[24];
+};
+struct be_cmd_resp_get_phy_info {
+ struct be_cmd_req_hdr hdr;
+ u16 phy_type;
+ u16 interface_type;
+ u32 misc_params;
+ u32 future_use[4];
+};
+
+/*********************** Set QOS ***********************/
+
+#define BE_QOS_BITS_NIC 1
+
+struct be_cmd_req_set_qos {
+ struct be_cmd_req_hdr hdr;
+ u32 valid_bits;
+ u32 max_bps_nic;
+ u32 rsvd[7];
+};
+
+struct be_cmd_resp_set_qos {
+ struct be_cmd_resp_hdr hdr;
+ u32 rsvd;
+};
+
extern int be_pci_fnum_get(struct be_adapter *adapter);
extern int be_cmd_POST(struct be_adapter *adapter);
extern int be_cmd_mac_addr_query(struct be_adapter *adapter, u8 *mac_addr,
@@ -947,4 +989,8 @@ extern int be_cmd_get_seeprom_data(struct be_adapter *adapter,
struct be_dma_mem *nonemb_cmd);
extern int be_cmd_set_loopback(struct be_adapter *adapter, u8 port_num,
u8 loopback_type, u8 enable);
+extern int be_cmd_get_phy_info(struct be_adapter *adapter,
+ struct be_dma_mem *cmd);
+extern int be_cmd_set_qos(struct be_adapter *adapter, u32 bps, u32 domain);
+extern void be_dump_ue(struct be_adapter *adapter);
diff --git a/drivers/net/benet/be_ethtool.c b/drivers/net/benet/be_ethtool.c
index 200e9851590..cd16243c7c3 100644
--- a/drivers/net/benet/be_ethtool.c
+++ b/drivers/net/benet/be_ethtool.c
@@ -314,15 +314,19 @@ static int be_get_sset_count(struct net_device *netdev, int stringset)
static int be_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd)
{
struct be_adapter *adapter = netdev_priv(netdev);
- u8 mac_speed = 0, connector = 0;
+ struct be_dma_mem phy_cmd;
+ struct be_cmd_resp_get_phy_info *resp;
+ u8 mac_speed = 0;
u16 link_speed = 0;
bool link_up = false;
int status;
+ u16 intf_type;
- if (adapter->link_speed < 0) {
+ if ((adapter->link_speed < 0) || (!(netdev->flags & IFF_UP))) {
status = be_cmd_link_status_query(adapter, &link_up,
&mac_speed, &link_speed);
+ be_link_status_update(adapter, link_up);
/* link_speed is in units of 10 Mbps */
if (link_speed) {
ecmd->speed = link_speed*10;
@@ -337,40 +341,57 @@ static int be_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd)
}
}
- status = be_cmd_read_port_type(adapter, adapter->port_num,
- &connector);
+ phy_cmd.size = sizeof(struct be_cmd_req_get_phy_info);
+ phy_cmd.va = pci_alloc_consistent(adapter->pdev, phy_cmd.size,
+ &phy_cmd.dma);
+ if (!phy_cmd.va) {
+ dev_err(&adapter->pdev->dev, "Memory alloc failure\n");
+ return -ENOMEM;
+ }
+ status = be_cmd_get_phy_info(adapter, &phy_cmd);
if (!status) {
- switch (connector) {
- case 7:
+ resp = (struct be_cmd_resp_get_phy_info *) phy_cmd.va;
+ intf_type = le16_to_cpu(resp->interface_type);
+
+ switch (intf_type) {
+ case PHY_TYPE_XFP_10GB:
+ case PHY_TYPE_SFP_1GB:
+ case PHY_TYPE_SFP_PLUS_10GB:
ecmd->port = PORT_FIBRE;
- ecmd->transceiver = XCVR_EXTERNAL;
- break;
- case 0:
- ecmd->port = PORT_TP;
- ecmd->transceiver = XCVR_EXTERNAL;
break;
default:
ecmd->port = PORT_TP;
- ecmd->transceiver = XCVR_INTERNAL;
break;
}
- } else {
- ecmd->port = PORT_AUI;
+
+ switch (intf_type) {
+ case PHY_TYPE_KR_10GB:
+ case PHY_TYPE_KX4_10GB:
+ ecmd->autoneg = AUTONEG_ENABLE;
ecmd->transceiver = XCVR_INTERNAL;
+ break;
+ default:
+ ecmd->autoneg = AUTONEG_DISABLE;
+ ecmd->transceiver = XCVR_EXTERNAL;
+ break;
+ }
}
/* Save for future use */
adapter->link_speed = ecmd->speed;
adapter->port_type = ecmd->port;
adapter->transceiver = ecmd->transceiver;
+ adapter->autoneg = ecmd->autoneg;
+ pci_free_consistent(adapter->pdev, phy_cmd.size,
+ phy_cmd.va, phy_cmd.dma);
} else {
ecmd->speed = adapter->link_speed;
ecmd->port = adapter->port_type;
ecmd->transceiver = adapter->transceiver;
+ ecmd->autoneg = adapter->autoneg;
}
ecmd->duplex = DUPLEX_FULL;
- ecmd->autoneg = AUTONEG_DISABLE;
ecmd->phy_address = adapter->port_num;
switch (ecmd->port) {
case PORT_FIBRE:
@@ -384,6 +405,13 @@ static int be_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd)
break;
}
+ if (ecmd->autoneg) {
+ ecmd->supported |= SUPPORTED_1000baseT_Full;
+ ecmd->supported |= SUPPORTED_Autoneg;
+ ecmd->advertising |= (ADVERTISED_10000baseT_Full |
+ ADVERTISED_1000baseT_Full);
+ }
+
return 0;
}
diff --git a/drivers/net/benet/be_hw.h b/drivers/net/benet/be_hw.h
index 063026de495..5d38046402b 100644
--- a/drivers/net/benet/be_hw.h
+++ b/drivers/net/benet/be_hw.h
@@ -52,10 +52,20 @@
*/
#define MEMBAR_CTRL_INT_CTRL_HOSTINTR_MASK (1 << 29) /* bit 29 */
-/********* Power managment (WOL) **********/
+/********* Power management (WOL) **********/
#define PCICFG_PM_CONTROL_OFFSET 0x44
#define PCICFG_PM_CONTROL_MASK 0x108 /* bits 3 & 8 */
+/********* Online Control Registers *******/
+#define PCICFG_ONLINE0 0xB0
+#define PCICFG_ONLINE1 0xB4
+
+/********* UE Status and Mask Registers ***/
+#define PCICFG_UE_STATUS_LOW 0xA0
+#define PCICFG_UE_STATUS_HIGH 0xA4
+#define PCICFG_UE_STATUS_LOW_MASK 0xA8
+#define PCICFG_UE_STATUS_HI_MASK 0xAC
+
/********* ISR0 Register offset **********/
#define CEV_ISR0_OFFSET 0xC18
#define CEV_ISR_SIZE 4
@@ -192,7 +202,7 @@ struct amap_eth_hdr_wrb {
u8 event;
u8 crc;
u8 forward;
- u8 ipsec;
+ u8 lso6;
u8 mgmt;
u8 ipcs;
u8 udpcs;
diff --git a/drivers/net/benet/be_main.c b/drivers/net/benet/be_main.c
index 54b14272f33..74e146f470c 100644
--- a/drivers/net/benet/be_main.c
+++ b/drivers/net/benet/be_main.c
@@ -40,6 +40,76 @@ static DEFINE_PCI_DEVICE_TABLE(be_dev_ids) = {
{ 0 }
};
MODULE_DEVICE_TABLE(pci, be_dev_ids);
+/* UE Status Low CSR */
+static char *ue_status_low_desc[] = {
+ "CEV",
+ "CTX",
+ "DBUF",
+ "ERX",
+ "Host",
+ "MPU",
+ "NDMA",
+ "PTC ",
+ "RDMA ",
+ "RXF ",
+ "RXIPS ",
+ "RXULP0 ",
+ "RXULP1 ",
+ "RXULP2 ",
+ "TIM ",
+ "TPOST ",
+ "TPRE ",
+ "TXIPS ",
+ "TXULP0 ",
+ "TXULP1 ",
+ "UC ",
+ "WDMA ",
+ "TXULP2 ",
+ "HOST1 ",
+ "P0_OB_LINK ",
+ "P1_OB_LINK ",
+ "HOST_GPIO ",
+ "MBOX ",
+ "AXGMAC0",
+ "AXGMAC1",
+ "JTAG",
+ "MPU_INTPEND"
+};
+/* UE Status High CSR */
+static char *ue_status_hi_desc[] = {
+ "LPCMEMHOST",
+ "MGMT_MAC",
+ "PCS0ONLINE",
+ "MPU_IRAM",
+ "PCS1ONLINE",
+ "PCTL0",
+ "PCTL1",
+ "PMEM",
+ "RR",
+ "TXPB",
+ "RXPP",
+ "XAUI",
+ "TXP",
+ "ARM",
+ "IPC",
+ "HOST2",
+ "HOST3",
+ "HOST4",
+ "HOST5",
+ "HOST6",
+ "HOST7",
+ "HOST8",
+ "HOST9",
+ "NETC"
+ "Unknown",
+ "Unknown",
+ "Unknown",
+ "Unknown",
+ "Unknown",
+ "Unknown",
+ "Unknown",
+ "Unknown"
+};
static void be_queue_free(struct be_adapter *adapter, struct be_queue_info *q)
{
@@ -89,6 +159,8 @@ static void be_rxq_notify(struct be_adapter *adapter, u16 qid, u16 posted)
u32 val = 0;
val |= qid & DB_RQ_RING_ID_MASK;
val |= posted << DB_RQ_NUM_POSTED_SHIFT;
+
+ wmb();
iowrite32(val, adapter->db + DB_RQ_OFFSET);
}
@@ -97,6 +169,8 @@ static void be_txq_notify(struct be_adapter *adapter, u16 qid, u16 posted)
u32 val = 0;
val |= qid & DB_TXULP_RING_ID_MASK;
val |= (posted & DB_TXULP_NUM_POSTED_MASK) << DB_TXULP_NUM_POSTED_SHIFT;
+
+ wmb();
iowrite32(val, adapter->db + DB_TXULP1_OFFSET);
}
@@ -373,10 +447,12 @@ static void wrb_fill_hdr(struct be_eth_hdr_wrb *hdr, struct sk_buff *skb,
AMAP_SET_BITS(struct amap_eth_hdr_wrb, crc, hdr, 1);
- if (skb_shinfo(skb)->gso_segs > 1 && skb_shinfo(skb)->gso_size) {
+ if (skb_is_gso(skb)) {
AMAP_SET_BITS(struct amap_eth_hdr_wrb, lso, hdr, 1);
AMAP_SET_BITS(struct amap_eth_hdr_wrb, lso_mss,
hdr, skb_shinfo(skb)->gso_size);
+ if (skb_is_gso_v6(skb))
+ AMAP_SET_BITS(struct amap_eth_hdr_wrb, lso6, hdr, 1);
} else if (skb->ip_summed == CHECKSUM_PARTIAL) {
if (is_tcp_pkt(skb))
AMAP_SET_BITS(struct amap_eth_hdr_wrb, tcpcs, hdr, 1);
@@ -546,11 +622,18 @@ static int be_change_mtu(struct net_device *netdev, int new_mtu)
* A max of 64 (BE_NUM_VLANS_SUPPORTED) vlans can be configured in BE.
* If the user configures more, place BE in vlan promiscuous mode.
*/
-static int be_vid_config(struct be_adapter *adapter)
+static int be_vid_config(struct be_adapter *adapter, bool vf, u32 vf_num)
{
u16 vtag[BE_NUM_VLANS_SUPPORTED];
u16 ntags = 0, i;
int status = 0;
+ u32 if_handle;
+
+ if (vf) {
+ if_handle = adapter->vf_cfg[vf_num].vf_if_handle;
+ vtag[0] = cpu_to_le16(adapter->vf_cfg[vf_num].vf_vlan_tag);
+ status = be_cmd_vlan_config(adapter, if_handle, vtag, 1, 1, 0);
+ }
if (adapter->vlans_added <= adapter->max_vlans) {
/* Construct VLAN Table to give to HW */
@@ -566,6 +649,7 @@ static int be_vid_config(struct be_adapter *adapter)
status = be_cmd_vlan_config(adapter, adapter->if_handle,
NULL, 0, 1, 1);
}
+
return status;
}
@@ -586,27 +670,28 @@ static void be_vlan_add_vid(struct net_device *netdev, u16 vid)
{
struct be_adapter *adapter = netdev_priv(netdev);
+ adapter->vlans_added++;
if (!be_physfn(adapter))
return;
adapter->vlan_tag[vid] = 1;
- adapter->vlans_added++;
if (adapter->vlans_added <= (adapter->max_vlans + 1))
- be_vid_config(adapter);
+ be_vid_config(adapter, false, 0);
}
static void be_vlan_rem_vid(struct net_device *netdev, u16 vid)
{
struct be_adapter *adapter = netdev_priv(netdev);
+ adapter->vlans_added--;
+ vlan_group_set_device(adapter->vlan_grp, vid, NULL);
+
if (!be_physfn(adapter))
return;
adapter->vlan_tag[vid] = 0;
- vlan_group_set_device(adapter->vlan_grp, vid, NULL);
- adapter->vlans_added--;
if (adapter->vlans_added <= adapter->max_vlans)
- be_vid_config(adapter);
+ be_vid_config(adapter, false, 0);
}
static void be_set_multicast_list(struct net_device *netdev)
@@ -650,14 +735,93 @@ static int be_set_vf_mac(struct net_device *netdev, int vf, u8 *mac)
if (!is_valid_ether_addr(mac) || (vf >= num_vfs))
return -EINVAL;
- status = be_cmd_pmac_del(adapter, adapter->vf_if_handle[vf],
- adapter->vf_pmac_id[vf]);
+ if (adapter->vf_cfg[vf].vf_pmac_id != BE_INVALID_PMAC_ID)
+ status = be_cmd_pmac_del(adapter,
+ adapter->vf_cfg[vf].vf_if_handle,
+ adapter->vf_cfg[vf].vf_pmac_id);
- status = be_cmd_pmac_add(adapter, mac, adapter->vf_if_handle[vf],
- &adapter->vf_pmac_id[vf]);
- if (!status)
+ status = be_cmd_pmac_add(adapter, mac,
+ adapter->vf_cfg[vf].vf_if_handle,
+ &adapter->vf_cfg[vf].vf_pmac_id);
+
+ if (status)
dev_err(&adapter->pdev->dev, "MAC %pM set on VF %d Failed\n",
mac, vf);
+ else
+ memcpy(adapter->vf_cfg[vf].vf_mac_addr, mac, ETH_ALEN);
+
+ return status;
+}
+
+static int be_get_vf_config(struct net_device *netdev, int vf,
+ struct ifla_vf_info *vi)
+{
+ struct be_adapter *adapter = netdev_priv(netdev);
+
+ if (!adapter->sriov_enabled)
+ return -EPERM;
+
+ if (vf >= num_vfs)
+ return -EINVAL;
+
+ vi->vf = vf;
+ vi->tx_rate = adapter->vf_cfg[vf].vf_tx_rate;
+ vi->vlan = adapter->vf_cfg[vf].vf_vlan_tag;
+ vi->qos = 0;
+ memcpy(&vi->mac, adapter->vf_cfg[vf].vf_mac_addr, ETH_ALEN);
+
+ return 0;
+}
+
+static int be_set_vf_vlan(struct net_device *netdev,
+ int vf, u16 vlan, u8 qos)
+{
+ struct be_adapter *adapter = netdev_priv(netdev);
+ int status = 0;
+
+ if (!adapter->sriov_enabled)
+ return -EPERM;
+
+ if ((vf >= num_vfs) || (vlan > 4095))
+ return -EINVAL;
+
+ if (vlan) {
+ adapter->vf_cfg[vf].vf_vlan_tag = vlan;
+ adapter->vlans_added++;
+ } else {
+ adapter->vf_cfg[vf].vf_vlan_tag = 0;
+ adapter->vlans_added--;
+ }
+
+ status = be_vid_config(adapter, true, vf);
+
+ if (status)
+ dev_info(&adapter->pdev->dev,
+ "VLAN %d config on VF %d failed\n", vlan, vf);
+ return status;
+}
+
+static int be_set_vf_tx_rate(struct net_device *netdev,
+ int vf, int rate)
+{
+ struct be_adapter *adapter = netdev_priv(netdev);
+ int status = 0;
+
+ if (!adapter->sriov_enabled)
+ return -EPERM;
+
+ if ((vf >= num_vfs) || (rate < 0))
+ return -EINVAL;
+
+ if (rate > 10000)
+ rate = 10000;
+
+ adapter->vf_cfg[vf].vf_tx_rate = rate;
+ status = be_cmd_set_qos(adapter, rate / 10, vf);
+
+ if (status)
+ dev_info(&adapter->pdev->dev,
+ "tx rate %d on VF %d failed\n", rate, vf);
return status;
}
@@ -869,7 +1033,7 @@ static void be_rx_compl_process(struct be_adapter *adapter,
/* vlanf could be wrongly set in some cards.
* ignore if vtm is not set */
- if ((adapter->cap & 0x400) && !vtm)
+ if ((adapter->function_mode & 0x400) && !vtm)
vlanf = 0;
if (unlikely(vlanf)) {
@@ -909,7 +1073,7 @@ static void be_rx_compl_process_gro(struct be_adapter *adapter,
/* vlanf could be wrongly set in some cards.
* ignore if vtm is not set */
- if ((adapter->cap & 0x400) && !vtm)
+ if ((adapter->function_mode & 0x400) && !vtm)
vlanf = 0;
skb = napi_get_frags(&eq_obj->napi);
@@ -971,6 +1135,7 @@ static struct be_eth_rx_compl *be_rx_compl_get(struct be_adapter *adapter)
if (rxcp->dw[offsetof(struct amap_eth_rx_compl, valid) / 32] == 0)
return NULL;
+ rmb();
be_dws_le_to_cpu(rxcp, sizeof(*rxcp));
queue_tail_inc(&adapter->rx_obj.cq);
@@ -1064,6 +1229,7 @@ static struct be_eth_tx_compl *be_tx_compl_get(struct be_queue_info *tx_cq)
if (txcp->dw[offsetof(struct amap_eth_tx_compl, valid) / 32] == 0)
return NULL;
+ rmb();
be_dws_le_to_cpu(txcp, sizeof(*txcp));
txcp->dw[offsetof(struct amap_eth_tx_compl, valid) / 32] = 0;
@@ -1111,6 +1277,7 @@ static inline struct be_eq_entry *event_get(struct be_eq_obj *eq_obj)
if (!eqe->evt)
return NULL;
+ rmb();
eqe->evt = le32_to_cpu(eqe->evt);
queue_tail_inc(&eq_obj->q);
return eqe;
@@ -1576,12 +1743,66 @@ static int be_poll_tx_mcc(struct napi_struct *napi, int budget)
return 1;
}
+static inline bool be_detect_ue(struct be_adapter *adapter)
+{
+ u32 online0 = 0, online1 = 0;
+
+ pci_read_config_dword(adapter->pdev, PCICFG_ONLINE0, &online0);
+
+ pci_read_config_dword(adapter->pdev, PCICFG_ONLINE1, &online1);
+
+ if (!online0 || !online1) {
+ adapter->ue_detected = true;
+ dev_err(&adapter->pdev->dev,
+ "UE Detected!! online0=%d online1=%d\n",
+ online0, online1);
+ return true;
+ }
+
+ return false;
+}
+
+void be_dump_ue(struct be_adapter *adapter)
+{
+ u32 ue_status_lo, ue_status_hi, ue_status_lo_mask, ue_status_hi_mask;
+ u32 i;
+
+ pci_read_config_dword(adapter->pdev,
+ PCICFG_UE_STATUS_LOW, &ue_status_lo);
+ pci_read_config_dword(adapter->pdev,
+ PCICFG_UE_STATUS_HIGH, &ue_status_hi);
+ pci_read_config_dword(adapter->pdev,
+ PCICFG_UE_STATUS_LOW_MASK, &ue_status_lo_mask);
+ pci_read_config_dword(adapter->pdev,
+ PCICFG_UE_STATUS_HI_MASK, &ue_status_hi_mask);
+
+ ue_status_lo = (ue_status_lo & (~ue_status_lo_mask));
+ ue_status_hi = (ue_status_hi & (~ue_status_hi_mask));
+
+ if (ue_status_lo) {
+ for (i = 0; ue_status_lo; ue_status_lo >>= 1, i++) {
+ if (ue_status_lo & 1)
+ dev_err(&adapter->pdev->dev,
+ "UE: %s bit set\n", ue_status_low_desc[i]);
+ }
+ }
+ if (ue_status_hi) {
+ for (i = 0; ue_status_hi; ue_status_hi >>= 1, i++) {
+ if (ue_status_hi & 1)
+ dev_err(&adapter->pdev->dev,
+ "UE: %s bit set\n", ue_status_hi_desc[i]);
+ }
+ }
+
+}
+
static void be_worker(struct work_struct *work)
{
struct be_adapter *adapter =
container_of(work, struct be_adapter, work.work);
- be_cmd_get_stats(adapter, &adapter->stats.cmd);
+ if (!adapter->stats_ioctl_sent)
+ be_cmd_get_stats(adapter, &adapter->stats.cmd);
/* Set EQ delay */
be_rx_eqd_update(adapter);
@@ -1593,6 +1814,10 @@ static void be_worker(struct work_struct *work)
adapter->rx_post_starved = false;
be_post_rx_frags(adapter);
}
+ if (!adapter->ue_detected) {
+ if (be_detect_ue(adapter))
+ be_dump_ue(adapter);
+ }
schedule_delayed_work(&adapter->work, msecs_to_jiffies(1000));
}
@@ -1620,9 +1845,11 @@ static void be_msix_enable(struct be_adapter *adapter)
static void be_sriov_enable(struct be_adapter *adapter)
{
+ be_check_sriov_fn_type(adapter);
#ifdef CONFIG_PCI_IOV
- int status;
if (be_physfn(adapter) && num_vfs) {
+ int status;
+
status = pci_enable_sriov(adapter->pdev, num_vfs);
adapter->sriov_enabled = status ? false : true;
}
@@ -1735,6 +1962,44 @@ done:
adapter->isr_registered = false;
}
+static int be_close(struct net_device *netdev)
+{
+ struct be_adapter *adapter = netdev_priv(netdev);
+ struct be_eq_obj *rx_eq = &adapter->rx_eq;
+ struct be_eq_obj *tx_eq = &adapter->tx_eq;
+ int vec;
+
+ cancel_delayed_work_sync(&adapter->work);
+
+ be_async_mcc_disable(adapter);
+
+ netif_stop_queue(netdev);
+ netif_carrier_off(netdev);
+ adapter->link_up = false;
+
+ be_intr_set(adapter, false);
+
+ if (adapter->msix_enabled) {
+ vec = be_msix_vec_get(adapter, tx_eq->q.id);
+ synchronize_irq(vec);
+ vec = be_msix_vec_get(adapter, rx_eq->q.id);
+ synchronize_irq(vec);
+ } else {
+ synchronize_irq(netdev->irq);
+ }
+ be_irq_unregister(adapter);
+
+ napi_disable(&rx_eq->napi);
+ napi_disable(&tx_eq->napi);
+
+ /* Wait for all pending tx completions to arrive so that
+ * all tx skbs are freed.
+ */
+ be_tx_compl_clean(adapter);
+
+ return 0;
+}
+
static int be_open(struct net_device *netdev)
{
struct be_adapter *adapter = netdev_priv(netdev);
@@ -1765,27 +2030,29 @@ static int be_open(struct net_device *netdev)
/* Now that interrupts are on we can process async mcc */
be_async_mcc_enable(adapter);
+ schedule_delayed_work(&adapter->work, msecs_to_jiffies(100));
+
status = be_cmd_link_status_query(adapter, &link_up, &mac_speed,
&link_speed);
if (status)
- goto ret_sts;
+ goto err;
be_link_status_update(adapter, link_up);
- if (be_physfn(adapter))
- status = be_vid_config(adapter);
- if (status)
- goto ret_sts;
-
if (be_physfn(adapter)) {
+ status = be_vid_config(adapter, false, 0);
+ if (status)
+ goto err;
+
status = be_cmd_set_flow_control(adapter,
adapter->tx_fc, adapter->rx_fc);
if (status)
- goto ret_sts;
+ goto err;
}
- schedule_delayed_work(&adapter->work, msecs_to_jiffies(100));
-ret_sts:
- return status;
+ return 0;
+err:
+ be_close(adapter->netdev);
+ return -EIO;
}
static int be_setup_wol(struct be_adapter *adapter, bool enable)
@@ -1853,13 +2120,15 @@ static int be_setup(struct be_adapter *adapter)
cap_flags = en_flags = BE_IF_FLAGS_UNTAGGED
| BE_IF_FLAGS_BROADCAST;
status = be_cmd_if_create(adapter, cap_flags, en_flags,
- mac, true, &adapter->vf_if_handle[vf],
+ mac, true,
+ &adapter->vf_cfg[vf].vf_if_handle,
NULL, vf+1);
if (status) {
dev_err(&adapter->pdev->dev,
"Interface Create failed for VF %d\n", vf);
goto if_destroy;
}
+ adapter->vf_cfg[vf].vf_pmac_id = BE_INVALID_PMAC_ID;
vf++;
}
} else if (!be_physfn(adapter)) {
@@ -1893,8 +2162,9 @@ tx_qs_destroy:
be_tx_queues_destroy(adapter);
if_destroy:
for (vf = 0; vf < num_vfs; vf++)
- if (adapter->vf_if_handle[vf])
- be_cmd_if_destroy(adapter, adapter->vf_if_handle[vf]);
+ if (adapter->vf_cfg[vf].vf_if_handle)
+ be_cmd_if_destroy(adapter,
+ adapter->vf_cfg[vf].vf_if_handle);
be_cmd_if_destroy(adapter, adapter->if_handle);
do_none:
return status;
@@ -1913,43 +2183,6 @@ static int be_clear(struct be_adapter *adapter)
return 0;
}
-static int be_close(struct net_device *netdev)
-{
- struct be_adapter *adapter = netdev_priv(netdev);
- struct be_eq_obj *rx_eq = &adapter->rx_eq;
- struct be_eq_obj *tx_eq = &adapter->tx_eq;
- int vec;
-
- cancel_delayed_work_sync(&adapter->work);
-
- be_async_mcc_disable(adapter);
-
- netif_stop_queue(netdev);
- netif_carrier_off(netdev);
- adapter->link_up = false;
-
- be_intr_set(adapter, false);
-
- if (adapter->msix_enabled) {
- vec = be_msix_vec_get(adapter, tx_eq->q.id);
- synchronize_irq(vec);
- vec = be_msix_vec_get(adapter, rx_eq->q.id);
- synchronize_irq(vec);
- } else {
- synchronize_irq(netdev->irq);
- }
- be_irq_unregister(adapter);
-
- napi_disable(&rx_eq->napi);
- napi_disable(&tx_eq->napi);
-
- /* Wait for all pending tx completions to arrive so that
- * all tx skbs are freed.
- */
- be_tx_compl_clean(adapter);
-
- return 0;
-}
#define FW_FILE_HDR_SIGN "ServerEngines Corp. "
char flash_cookie[2][16] = {"*** SE FLAS",
@@ -2174,7 +2407,10 @@ static struct net_device_ops be_netdev_ops = {
.ndo_vlan_rx_register = be_vlan_register,
.ndo_vlan_rx_add_vid = be_vlan_add_vid,
.ndo_vlan_rx_kill_vid = be_vlan_rem_vid,
- .ndo_set_vf_mac = be_set_vf_mac
+ .ndo_set_vf_mac = be_set_vf_mac,
+ .ndo_set_vf_vlan = be_set_vf_vlan,
+ .ndo_set_vf_tx_rate = be_set_vf_tx_rate,
+ .ndo_get_vf_config = be_get_vf_config
};
static void be_netdev_init(struct net_device *netdev)
@@ -2183,7 +2419,7 @@ static void be_netdev_init(struct net_device *netdev)
netdev->features |= NETIF_F_SG | NETIF_F_HW_VLAN_RX | NETIF_F_TSO |
NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_FILTER | NETIF_F_HW_CSUM |
- NETIF_F_GRO;
+ NETIF_F_GRO | NETIF_F_TSO6;
netdev->vlan_features |= NETIF_F_SG | NETIF_F_TSO | NETIF_F_HW_CSUM;
@@ -2393,7 +2629,7 @@ static int be_get_config(struct be_adapter *adapter)
return status;
status = be_cmd_query_fw_cfg(adapter,
- &adapter->port_num, &adapter->cap);
+ &adapter->port_num, &adapter->function_mode);
if (status)
return status;
@@ -2413,7 +2649,7 @@ static int be_get_config(struct be_adapter *adapter)
memcpy(adapter->netdev->perm_addr, mac, ETH_ALEN);
}
- if (adapter->cap & 0x400)
+ if (adapter->function_mode & 0x400)
adapter->max_vlans = BE_NUM_VLANS_SUPPORTED/4;
else
adapter->max_vlans = BE_NUM_VLANS_SUPPORTED;
diff --git a/drivers/net/bfin_mac.c b/drivers/net/bfin_mac.c
index 368f33313fb..012613fde3f 100644
--- a/drivers/net/bfin_mac.c
+++ b/drivers/net/bfin_mac.c
@@ -922,61 +922,73 @@ static void bfin_mac_hwtstamp_init(struct net_device *netdev)
# define bfin_tx_hwtstamp(dev, skb)
#endif
-static void adjust_tx_list(void)
+static inline void _tx_reclaim_skb(void)
+{
+ 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;
+ }
+ tx_list_head = tx_list_head->next;
+
+ } while (tx_list_head->status.status_word != 0);
+}
+
+static void tx_reclaim_skb(struct bfin_mac_local *lp)
{
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 (tx_list_head->status.status_word != 0)
+ _tx_reclaim_skb();
- /*
- * 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) {
+ if (current_tx_ptr->next == tx_list_head) {
while (tx_list_head->status.status_word == 0) {
+ /* slow down polling to avoid too many queue stop. */
udelay(10);
- if (tx_list_head->status.status_word != 0 ||
- !(bfin_read_DMA2_IRQ_STATUS() & DMA_RUN)) {
- goto adjust_head;
- }
- if (timeout_cnt-- < 0) {
- printk(KERN_ERR DRV_NAME
- ": wait for adjust tx list head timeout\n");
+ /* reclaim skb if DMA is not running. */
+ if (!(bfin_read_DMA2_IRQ_STATUS() & DMA_RUN))
+ break;
+ if (timeout_cnt-- < 0)
break;
- }
- }
- if (tx_list_head->status.status_word != 0) {
- goto adjust_head;
}
+
+ if (timeout_cnt >= 0)
+ _tx_reclaim_skb();
+ else
+ netif_stop_queue(lp->ndev);
}
- return;
+ if (current_tx_ptr->next != tx_list_head &&
+ netif_queue_stopped(lp->ndev))
+ netif_wake_queue(lp->ndev);
+
+ if (tx_list_head != current_tx_ptr) {
+ /* shorten the timer interval if tx queue is stopped */
+ if (netif_queue_stopped(lp->ndev))
+ lp->tx_reclaim_timer.expires =
+ jiffies + (TX_RECLAIM_JIFFIES >> 4);
+ else
+ lp->tx_reclaim_timer.expires =
+ jiffies + TX_RECLAIM_JIFFIES;
+
+ mod_timer(&lp->tx_reclaim_timer,
+ lp->tx_reclaim_timer.expires);
+ }
-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 void tx_reclaim_skb_timeout(unsigned long lp)
+{
+ tx_reclaim_skb((struct bfin_mac_local *)lp);
}
static int bfin_mac_hard_start_xmit(struct sk_buff *skb,
struct net_device *dev)
{
+ struct bfin_mac_local *lp = netdev_priv(dev);
u16 *data;
u32 data_align = (unsigned long)(skb->data) & 0x3;
union skb_shared_tx *shtx = skb_tx(skb);
@@ -1009,8 +1021,6 @@ static int bfin_mac_hard_start_xmit(struct sk_buff *skb,
skb->len);
current_tx_ptr->desc_a.start_addr =
(u32)current_tx_ptr->packet;
- if (current_tx_ptr->status.status_word != 0)
- current_tx_ptr->status.status_word = 0;
blackfin_dcache_flush_range(
(u32)current_tx_ptr->packet,
(u32)(current_tx_ptr->packet + skb->len + 2));
@@ -1022,6 +1032,9 @@ static int bfin_mac_hard_start_xmit(struct sk_buff *skb,
*/
SSYNC();
+ /* always clear status buffer before start tx dma */
+ current_tx_ptr->status.status_word = 0;
+
/* enable this packet's dma */
current_tx_ptr->desc_a.config |= DMAEN;
@@ -1037,13 +1050,14 @@ static int bfin_mac_hard_start_xmit(struct sk_buff *skb,
bfin_write_EMAC_OPMODE(bfin_read_EMAC_OPMODE() | TE);
out:
- adjust_tx_list();
-
bfin_tx_hwtstamp(dev, skb);
current_tx_ptr = current_tx_ptr->next;
dev->stats.tx_packets++;
dev->stats.tx_bytes += (skb->len);
+
+ tx_reclaim_skb(lp);
+
return NETDEV_TX_OK;
}
@@ -1167,8 +1181,11 @@ real_rx:
#ifdef CONFIG_NET_POLL_CONTROLLER
static void bfin_mac_poll(struct net_device *dev)
{
+ struct bfin_mac_local *lp = netdev_priv(dev);
+
disable_irq(IRQ_MAC_RX);
bfin_mac_interrupt(IRQ_MAC_RX, dev);
+ tx_reclaim_skb(lp);
enable_irq(IRQ_MAC_RX);
}
#endif /* CONFIG_NET_POLL_CONTROLLER */
@@ -1232,12 +1249,27 @@ static int bfin_mac_enable(void)
/* Our watchdog timed out. Called by the networking layer */
static void bfin_mac_timeout(struct net_device *dev)
{
+ struct bfin_mac_local *lp = netdev_priv(dev);
+
pr_debug("%s: %s\n", dev->name, __func__);
bfin_mac_disable();
- /* reset tx queue */
- tx_list_tail = tx_list_head->next;
+ del_timer(&lp->tx_reclaim_timer);
+
+ /* reset tx queue and free skb */
+ while (tx_list_head != current_tx_ptr) {
+ 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;
+ }
+ tx_list_head = tx_list_head->next;
+ }
+
+ if (netif_queue_stopped(lp->ndev))
+ netif_wake_queue(lp->ndev);
bfin_mac_enable();
@@ -1430,6 +1462,7 @@ static int __devinit bfin_mac_probe(struct platform_device *pdev)
SET_NETDEV_DEV(ndev, &pdev->dev);
platform_set_drvdata(pdev, ndev);
lp = netdev_priv(ndev);
+ lp->ndev = ndev;
/* Grab the MAC address in the MAC */
*(__le32 *) (&(ndev->dev_addr[0])) = cpu_to_le32(bfin_read_EMAC_ADDRLO());
@@ -1485,6 +1518,10 @@ static int __devinit bfin_mac_probe(struct platform_device *pdev)
ndev->netdev_ops = &bfin_mac_netdev_ops;
ndev->ethtool_ops = &bfin_mac_ethtool_ops;
+ init_timer(&lp->tx_reclaim_timer);
+ lp->tx_reclaim_timer.data = (unsigned long)lp;
+ lp->tx_reclaim_timer.function = tx_reclaim_skb_timeout;
+
spin_lock_init(&lp->lock);
/* now, enable interrupts */
diff --git a/drivers/net/bfin_mac.h b/drivers/net/bfin_mac.h
index 1ae7b82ceee..04e4050df18 100644
--- a/drivers/net/bfin_mac.h
+++ b/drivers/net/bfin_mac.h
@@ -13,9 +13,12 @@
#include <linux/net_tstamp.h>
#include <linux/clocksource.h>
#include <linux/timecompare.h>
+#include <linux/timer.h>
#define BFIN_MAC_CSUM_OFFLOAD
+#define TX_RECLAIM_JIFFIES (HZ / 5)
+
struct dma_descriptor {
struct dma_descriptor *next_dma_desc;
unsigned long start_addr;
@@ -68,6 +71,8 @@ struct bfin_mac_local {
int wol; /* Wake On Lan */
int irq_wake_requested;
+ struct timer_list tx_reclaim_timer;
+ struct net_device *ndev;
/* MII and PHY stuffs */
int old_link; /* used by bf537_adjust_link */
diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c
index 117432222a0..e6a803f1c50 100644
--- a/drivers/net/bnx2.c
+++ b/drivers/net/bnx2.c
@@ -58,8 +58,8 @@
#include "bnx2_fw.h"
#define DRV_MODULE_NAME "bnx2"
-#define DRV_MODULE_VERSION "2.0.15"
-#define DRV_MODULE_RELDATE "May 4, 2010"
+#define DRV_MODULE_VERSION "2.0.17"
+#define DRV_MODULE_RELDATE "July 18, 2010"
#define FW_MIPS_FILE_06 "bnx2/bnx2-mips-06-5.0.0.j6.fw"
#define FW_RV2P_FILE_06 "bnx2/bnx2-rv2p-06-5.0.0.j3.fw"
#define FW_MIPS_FILE_09 "bnx2/bnx2-mips-09-5.0.0.j15.fw"
@@ -253,7 +253,8 @@ static inline u32 bnx2_tx_avail(struct bnx2 *bp, struct bnx2_tx_ring_info *txr)
{
u32 diff;
- smp_mb();
+ /* Tell compiler to fetch tx_prod and tx_cons from memory. */
+ barrier();
/* The ring uses 256 indices for 255 entries, one of them
* needs to be skipped.
@@ -692,9 +693,9 @@ bnx2_free_tx_mem(struct bnx2 *bp)
struct bnx2_tx_ring_info *txr = &bnapi->tx_ring;
if (txr->tx_desc_ring) {
- pci_free_consistent(bp->pdev, TXBD_RING_SIZE,
- txr->tx_desc_ring,
- txr->tx_desc_mapping);
+ dma_free_coherent(&bp->pdev->dev, TXBD_RING_SIZE,
+ txr->tx_desc_ring,
+ txr->tx_desc_mapping);
txr->tx_desc_ring = NULL;
}
kfree(txr->tx_buf_ring);
@@ -714,9 +715,9 @@ bnx2_free_rx_mem(struct bnx2 *bp)
for (j = 0; j < bp->rx_max_ring; j++) {
if (rxr->rx_desc_ring[j])
- pci_free_consistent(bp->pdev, RXBD_RING_SIZE,
- rxr->rx_desc_ring[j],
- rxr->rx_desc_mapping[j]);
+ dma_free_coherent(&bp->pdev->dev, RXBD_RING_SIZE,
+ rxr->rx_desc_ring[j],
+ rxr->rx_desc_mapping[j]);
rxr->rx_desc_ring[j] = NULL;
}
vfree(rxr->rx_buf_ring);
@@ -724,9 +725,9 @@ bnx2_free_rx_mem(struct bnx2 *bp)
for (j = 0; j < bp->rx_max_pg_ring; j++) {
if (rxr->rx_pg_desc_ring[j])
- pci_free_consistent(bp->pdev, RXBD_RING_SIZE,
- rxr->rx_pg_desc_ring[j],
- rxr->rx_pg_desc_mapping[j]);
+ dma_free_coherent(&bp->pdev->dev, RXBD_RING_SIZE,
+ rxr->rx_pg_desc_ring[j],
+ rxr->rx_pg_desc_mapping[j]);
rxr->rx_pg_desc_ring[j] = NULL;
}
vfree(rxr->rx_pg_ring);
@@ -748,8 +749,8 @@ bnx2_alloc_tx_mem(struct bnx2 *bp)
return -ENOMEM;
txr->tx_desc_ring =
- pci_alloc_consistent(bp->pdev, TXBD_RING_SIZE,
- &txr->tx_desc_mapping);
+ dma_alloc_coherent(&bp->pdev->dev, TXBD_RING_SIZE,
+ &txr->tx_desc_mapping, GFP_KERNEL);
if (txr->tx_desc_ring == NULL)
return -ENOMEM;
}
@@ -776,8 +777,10 @@ bnx2_alloc_rx_mem(struct bnx2 *bp)
for (j = 0; j < bp->rx_max_ring; j++) {
rxr->rx_desc_ring[j] =
- pci_alloc_consistent(bp->pdev, RXBD_RING_SIZE,
- &rxr->rx_desc_mapping[j]);
+ dma_alloc_coherent(&bp->pdev->dev,
+ RXBD_RING_SIZE,
+ &rxr->rx_desc_mapping[j],
+ GFP_KERNEL);
if (rxr->rx_desc_ring[j] == NULL)
return -ENOMEM;
@@ -795,8 +798,10 @@ bnx2_alloc_rx_mem(struct bnx2 *bp)
for (j = 0; j < bp->rx_max_pg_ring; j++) {
rxr->rx_pg_desc_ring[j] =
- pci_alloc_consistent(bp->pdev, RXBD_RING_SIZE,
- &rxr->rx_pg_desc_mapping[j]);
+ dma_alloc_coherent(&bp->pdev->dev,
+ RXBD_RING_SIZE,
+ &rxr->rx_pg_desc_mapping[j],
+ GFP_KERNEL);
if (rxr->rx_pg_desc_ring[j] == NULL)
return -ENOMEM;
@@ -816,16 +821,16 @@ bnx2_free_mem(struct bnx2 *bp)
for (i = 0; i < bp->ctx_pages; i++) {
if (bp->ctx_blk[i]) {
- pci_free_consistent(bp->pdev, BCM_PAGE_SIZE,
- bp->ctx_blk[i],
- bp->ctx_blk_mapping[i]);
+ dma_free_coherent(&bp->pdev->dev, BCM_PAGE_SIZE,
+ bp->ctx_blk[i],
+ bp->ctx_blk_mapping[i]);
bp->ctx_blk[i] = NULL;
}
}
if (bnapi->status_blk.msi) {
- pci_free_consistent(bp->pdev, bp->status_stats_size,
- bnapi->status_blk.msi,
- bp->status_blk_mapping);
+ dma_free_coherent(&bp->pdev->dev, bp->status_stats_size,
+ bnapi->status_blk.msi,
+ bp->status_blk_mapping);
bnapi->status_blk.msi = NULL;
bp->stats_blk = NULL;
}
@@ -846,8 +851,8 @@ bnx2_alloc_mem(struct bnx2 *bp)
bp->status_stats_size = status_blk_size +
sizeof(struct statistics_block);
- status_blk = pci_alloc_consistent(bp->pdev, bp->status_stats_size,
- &bp->status_blk_mapping);
+ status_blk = dma_alloc_coherent(&bp->pdev->dev, bp->status_stats_size,
+ &bp->status_blk_mapping, GFP_KERNEL);
if (status_blk == NULL)
goto alloc_mem_err;
@@ -860,7 +865,7 @@ bnx2_alloc_mem(struct bnx2 *bp)
bnapi->hw_rx_cons_ptr =
&bnapi->status_blk.msi->status_rx_quick_consumer_index0;
if (bp->flags & BNX2_FLAG_MSIX_CAP) {
- for (i = 1; i < BNX2_MAX_MSIX_VEC; i++) {
+ for (i = 1; i < bp->irq_nvecs; i++) {
struct status_block_msix *sblk;
bnapi = &bp->bnx2_napi[i];
@@ -885,9 +890,10 @@ bnx2_alloc_mem(struct bnx2 *bp)
if (bp->ctx_pages == 0)
bp->ctx_pages = 1;
for (i = 0; i < bp->ctx_pages; i++) {
- bp->ctx_blk[i] = pci_alloc_consistent(bp->pdev,
+ bp->ctx_blk[i] = dma_alloc_coherent(&bp->pdev->dev,
BCM_PAGE_SIZE,
- &bp->ctx_blk_mapping[i]);
+ &bp->ctx_blk_mapping[i],
+ GFP_KERNEL);
if (bp->ctx_blk[i] == NULL)
goto alloc_mem_err;
}
@@ -1446,7 +1452,8 @@ bnx2_test_and_disable_2g5(struct bnx2 *bp)
static void
bnx2_enable_forced_2g5(struct bnx2 *bp)
{
- u32 bmcr;
+ u32 uninitialized_var(bmcr);
+ int err;
if (!(bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE))
return;
@@ -1456,22 +1463,28 @@ bnx2_enable_forced_2g5(struct bnx2 *bp)
bnx2_write_phy(bp, MII_BNX2_BLK_ADDR,
MII_BNX2_BLK_ADDR_SERDES_DIG);
- bnx2_read_phy(bp, MII_BNX2_SERDES_DIG_MISC1, &val);
- val &= ~MII_BNX2_SD_MISC1_FORCE_MSK;
- val |= MII_BNX2_SD_MISC1_FORCE | MII_BNX2_SD_MISC1_FORCE_2_5G;
- bnx2_write_phy(bp, MII_BNX2_SERDES_DIG_MISC1, val);
+ if (!bnx2_read_phy(bp, MII_BNX2_SERDES_DIG_MISC1, &val)) {
+ val &= ~MII_BNX2_SD_MISC1_FORCE_MSK;
+ val |= MII_BNX2_SD_MISC1_FORCE |
+ MII_BNX2_SD_MISC1_FORCE_2_5G;
+ bnx2_write_phy(bp, MII_BNX2_SERDES_DIG_MISC1, val);
+ }
bnx2_write_phy(bp, MII_BNX2_BLK_ADDR,
MII_BNX2_BLK_ADDR_COMBO_IEEEB0);
- bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
+ err = bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
} else if (CHIP_NUM(bp) == CHIP_NUM_5708) {
- bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
- bmcr |= BCM5708S_BMCR_FORCE_2500;
+ err = bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
+ if (!err)
+ bmcr |= BCM5708S_BMCR_FORCE_2500;
} else {
return;
}
+ if (err)
+ return;
+
if (bp->autoneg & AUTONEG_SPEED) {
bmcr &= ~BMCR_ANENABLE;
if (bp->req_duplex == DUPLEX_FULL)
@@ -1483,7 +1496,8 @@ bnx2_enable_forced_2g5(struct bnx2 *bp)
static void
bnx2_disable_forced_2g5(struct bnx2 *bp)
{
- u32 bmcr;
+ u32 uninitialized_var(bmcr);
+ int err;
if (!(bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE))
return;
@@ -1493,21 +1507,26 @@ bnx2_disable_forced_2g5(struct bnx2 *bp)
bnx2_write_phy(bp, MII_BNX2_BLK_ADDR,
MII_BNX2_BLK_ADDR_SERDES_DIG);
- bnx2_read_phy(bp, MII_BNX2_SERDES_DIG_MISC1, &val);
- val &= ~MII_BNX2_SD_MISC1_FORCE;
- bnx2_write_phy(bp, MII_BNX2_SERDES_DIG_MISC1, val);
+ if (!bnx2_read_phy(bp, MII_BNX2_SERDES_DIG_MISC1, &val)) {
+ val &= ~MII_BNX2_SD_MISC1_FORCE;
+ bnx2_write_phy(bp, MII_BNX2_SERDES_DIG_MISC1, val);
+ }
bnx2_write_phy(bp, MII_BNX2_BLK_ADDR,
MII_BNX2_BLK_ADDR_COMBO_IEEEB0);
- bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
+ err = bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
} else if (CHIP_NUM(bp) == CHIP_NUM_5708) {
- bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
- bmcr &= ~BCM5708S_BMCR_FORCE_2500;
+ err = bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
+ if (!err)
+ bmcr &= ~BCM5708S_BMCR_FORCE_2500;
} else {
return;
}
+ if (err)
+ return;
+
if (bp->autoneg & AUTONEG_SPEED)
bmcr |= BMCR_SPEED1000 | BMCR_ANENABLE | BMCR_ANRESTART;
bnx2_write_phy(bp, bp->mii_bmcr, bmcr);
@@ -2651,19 +2670,19 @@ bnx2_set_mac_addr(struct bnx2 *bp, u8 *mac_addr, u32 pos)
}
static inline int
-bnx2_alloc_rx_page(struct bnx2 *bp, struct bnx2_rx_ring_info *rxr, u16 index)
+bnx2_alloc_rx_page(struct bnx2 *bp, struct bnx2_rx_ring_info *rxr, u16 index, gfp_t gfp)
{
dma_addr_t mapping;
struct sw_pg *rx_pg = &rxr->rx_pg_ring[index];
struct rx_bd *rxbd =
&rxr->rx_pg_desc_ring[RX_RING(index)][RX_IDX(index)];
- struct page *page = alloc_page(GFP_ATOMIC);
+ struct page *page = alloc_page(gfp);
if (!page)
return -ENOMEM;
- mapping = pci_map_page(bp->pdev, page, 0, PAGE_SIZE,
+ mapping = dma_map_page(&bp->pdev->dev, page, 0, PAGE_SIZE,
PCI_DMA_FROMDEVICE);
- if (pci_dma_mapping_error(bp->pdev, mapping)) {
+ if (dma_mapping_error(&bp->pdev->dev, mapping)) {
__free_page(page);
return -EIO;
}
@@ -2684,15 +2703,15 @@ bnx2_free_rx_page(struct bnx2 *bp, struct bnx2_rx_ring_info *rxr, u16 index)
if (!page)
return;
- pci_unmap_page(bp->pdev, dma_unmap_addr(rx_pg, mapping), PAGE_SIZE,
- PCI_DMA_FROMDEVICE);
+ dma_unmap_page(&bp->pdev->dev, dma_unmap_addr(rx_pg, mapping),
+ PAGE_SIZE, PCI_DMA_FROMDEVICE);
__free_page(page);
rx_pg->page = NULL;
}
static inline int
-bnx2_alloc_rx_skb(struct bnx2 *bp, struct bnx2_rx_ring_info *rxr, u16 index)
+bnx2_alloc_rx_skb(struct bnx2 *bp, struct bnx2_rx_ring_info *rxr, u16 index, gfp_t gfp)
{
struct sk_buff *skb;
struct sw_bd *rx_buf = &rxr->rx_buf_ring[index];
@@ -2700,7 +2719,7 @@ bnx2_alloc_rx_skb(struct bnx2 *bp, struct bnx2_rx_ring_info *rxr, u16 index)
struct rx_bd *rxbd = &rxr->rx_desc_ring[RX_RING(index)][RX_IDX(index)];
unsigned long align;
- skb = netdev_alloc_skb(bp->dev, bp->rx_buf_size);
+ skb = __netdev_alloc_skb(bp->dev, bp->rx_buf_size, gfp);
if (skb == NULL) {
return -ENOMEM;
}
@@ -2708,9 +2727,9 @@ bnx2_alloc_rx_skb(struct bnx2 *bp, struct bnx2_rx_ring_info *rxr, u16 index)
if (unlikely((align = (unsigned long) skb->data & (BNX2_RX_ALIGN - 1))))
skb_reserve(skb, BNX2_RX_ALIGN - align);
- mapping = pci_map_single(bp->pdev, skb->data, bp->rx_buf_use_size,
- PCI_DMA_FROMDEVICE);
- if (pci_dma_mapping_error(bp->pdev, mapping)) {
+ mapping = dma_map_single(&bp->pdev->dev, skb->data, bp->rx_buf_use_size,
+ PCI_DMA_FROMDEVICE);
+ if (dma_mapping_error(&bp->pdev->dev, mapping)) {
dev_kfree_skb(skb);
return -EIO;
}
@@ -2816,7 +2835,7 @@ bnx2_tx_int(struct bnx2 *bp, struct bnx2_napi *bnapi, int budget)
}
}
- pci_unmap_single(bp->pdev, dma_unmap_addr(tx_buf, mapping),
+ dma_unmap_single(&bp->pdev->dev, dma_unmap_addr(tx_buf, mapping),
skb_headlen(skb), PCI_DMA_TODEVICE);
tx_buf->skb = NULL;
@@ -2825,7 +2844,7 @@ bnx2_tx_int(struct bnx2 *bp, struct bnx2_napi *bnapi, int budget)
for (i = 0; i < last; i++) {
sw_cons = NEXT_TX_BD(sw_cons);
- pci_unmap_page(bp->pdev,
+ dma_unmap_page(&bp->pdev->dev,
dma_unmap_addr(
&txr->tx_buf_ring[TX_RING_IDX(sw_cons)],
mapping),
@@ -2932,7 +2951,7 @@ bnx2_reuse_rx_skb(struct bnx2 *bp, struct bnx2_rx_ring_info *rxr,
cons_rx_buf = &rxr->rx_buf_ring[cons];
prod_rx_buf = &rxr->rx_buf_ring[prod];
- pci_dma_sync_single_for_device(bp->pdev,
+ dma_sync_single_for_device(&bp->pdev->dev,
dma_unmap_addr(cons_rx_buf, mapping),
BNX2_RX_OFFSET + BNX2_RX_COPY_THRESH, PCI_DMA_FROMDEVICE);
@@ -2961,7 +2980,7 @@ bnx2_rx_skb(struct bnx2 *bp, struct bnx2_rx_ring_info *rxr, struct sk_buff *skb,
int err;
u16 prod = ring_idx & 0xffff;
- err = bnx2_alloc_rx_skb(bp, rxr, prod);
+ err = bnx2_alloc_rx_skb(bp, rxr, prod, GFP_ATOMIC);
if (unlikely(err)) {
bnx2_reuse_rx_skb(bp, rxr, skb, (u16) (ring_idx >> 16), prod);
if (hdr_len) {
@@ -2974,7 +2993,7 @@ bnx2_rx_skb(struct bnx2 *bp, struct bnx2_rx_ring_info *rxr, struct sk_buff *skb,
}
skb_reserve(skb, BNX2_RX_OFFSET);
- pci_unmap_single(bp->pdev, dma_addr, bp->rx_buf_use_size,
+ dma_unmap_single(&bp->pdev->dev, dma_addr, bp->rx_buf_use_size,
PCI_DMA_FROMDEVICE);
if (hdr_len == 0) {
@@ -3026,7 +3045,8 @@ bnx2_rx_skb(struct bnx2 *bp, struct bnx2_rx_ring_info *rxr, struct sk_buff *skb,
rx_pg->page = NULL;
err = bnx2_alloc_rx_page(bp, rxr,
- RX_PG_RING_IDX(pg_prod));
+ RX_PG_RING_IDX(pg_prod),
+ GFP_ATOMIC);
if (unlikely(err)) {
rxr->rx_pg_cons = pg_cons;
rxr->rx_pg_prod = pg_prod;
@@ -3035,7 +3055,7 @@ bnx2_rx_skb(struct bnx2 *bp, struct bnx2_rx_ring_info *rxr, struct sk_buff *skb,
return err;
}
- pci_unmap_page(bp->pdev, mapping_old,
+ dma_unmap_page(&bp->pdev->dev, mapping_old,
PAGE_SIZE, PCI_DMA_FROMDEVICE);
frag_size -= frag_len;
@@ -3106,7 +3126,7 @@ bnx2_rx_int(struct bnx2 *bp, struct bnx2_napi *bnapi, int budget)
dma_addr = dma_unmap_addr(rx_buf, mapping);
- pci_dma_sync_single_for_cpu(bp->pdev, dma_addr,
+ dma_sync_single_for_cpu(&bp->pdev->dev, dma_addr,
BNX2_RX_OFFSET + BNX2_RX_COPY_THRESH,
PCI_DMA_FROMDEVICE);
@@ -3206,6 +3226,10 @@ bnx2_rx_int(struct bnx2 *bp, struct bnx2_napi *bnapi, int budget)
L2_FHDR_ERRORS_UDP_XSUM)) == 0))
skb->ip_summed = CHECKSUM_UNNECESSARY;
}
+ if ((bp->dev->features & NETIF_F_RXHASH) &&
+ ((status & L2_FHDR_STATUS_USE_RXHASH) ==
+ L2_FHDR_STATUS_USE_RXHASH))
+ skb->rxhash = rx_hdr->l2_fhdr_hash;
skb_record_rx_queue(skb, bnapi - &bp->bnx2_napi[0]);
@@ -5162,7 +5186,7 @@ bnx2_init_rx_ring(struct bnx2 *bp, int ring_num)
ring_prod = prod = rxr->rx_pg_prod;
for (i = 0; i < bp->rx_pg_ring_size; i++) {
- if (bnx2_alloc_rx_page(bp, rxr, ring_prod) < 0) {
+ if (bnx2_alloc_rx_page(bp, rxr, ring_prod, GFP_KERNEL) < 0) {
netdev_warn(bp->dev, "init'ed rx page ring %d with %d/%d pages only\n",
ring_num, i, bp->rx_pg_ring_size);
break;
@@ -5174,7 +5198,7 @@ bnx2_init_rx_ring(struct bnx2 *bp, int ring_num)
ring_prod = prod = rxr->rx_prod;
for (i = 0; i < bp->rx_ring_size; i++) {
- if (bnx2_alloc_rx_skb(bp, rxr, ring_prod) < 0) {
+ if (bnx2_alloc_rx_skb(bp, rxr, ring_prod, GFP_KERNEL) < 0) {
netdev_warn(bp->dev, "init'ed rx ring %d with %d/%d skbs only\n",
ring_num, i, bp->rx_ring_size);
break;
@@ -5320,7 +5344,7 @@ bnx2_free_tx_skbs(struct bnx2 *bp)
continue;
}
- pci_unmap_single(bp->pdev,
+ dma_unmap_single(&bp->pdev->dev,
dma_unmap_addr(tx_buf, mapping),
skb_headlen(skb),
PCI_DMA_TODEVICE);
@@ -5331,7 +5355,7 @@ bnx2_free_tx_skbs(struct bnx2 *bp)
j++;
for (k = 0; k < last; k++, j++) {
tx_buf = &txr->tx_buf_ring[TX_RING_IDX(j)];
- pci_unmap_page(bp->pdev,
+ dma_unmap_page(&bp->pdev->dev,
dma_unmap_addr(tx_buf, mapping),
skb_shinfo(skb)->frags[k].size,
PCI_DMA_TODEVICE);
@@ -5361,7 +5385,7 @@ bnx2_free_rx_skbs(struct bnx2 *bp)
if (skb == NULL)
continue;
- pci_unmap_single(bp->pdev,
+ dma_unmap_single(&bp->pdev->dev,
dma_unmap_addr(rx_buf, mapping),
bp->rx_buf_use_size,
PCI_DMA_FROMDEVICE);
@@ -5714,9 +5738,9 @@ bnx2_run_loopback(struct bnx2 *bp, int loopback_mode)
for (i = 14; i < pkt_size; i++)
packet[i] = (unsigned char) (i & 0xff);
- map = pci_map_single(bp->pdev, skb->data, pkt_size,
- PCI_DMA_TODEVICE);
- if (pci_dma_mapping_error(bp->pdev, map)) {
+ map = dma_map_single(&bp->pdev->dev, skb->data, pkt_size,
+ PCI_DMA_TODEVICE);
+ if (dma_mapping_error(&bp->pdev->dev, map)) {
dev_kfree_skb(skb);
return -EIO;
}
@@ -5754,7 +5778,7 @@ bnx2_run_loopback(struct bnx2 *bp, int loopback_mode)
udelay(5);
- pci_unmap_single(bp->pdev, map, pkt_size, PCI_DMA_TODEVICE);
+ dma_unmap_single(&bp->pdev->dev, map, pkt_size, PCI_DMA_TODEVICE);
dev_kfree_skb(skb);
if (bnx2_get_hw_tx_cons(tx_napi) != txr->tx_prod)
@@ -5771,7 +5795,7 @@ bnx2_run_loopback(struct bnx2 *bp, int loopback_mode)
rx_hdr = rx_buf->desc;
skb_reserve(rx_skb, BNX2_RX_OFFSET);
- pci_dma_sync_single_for_cpu(bp->pdev,
+ dma_sync_single_for_cpu(&bp->pdev->dev,
dma_unmap_addr(rx_buf, mapping),
bp->rx_buf_size, PCI_DMA_FROMDEVICE);
@@ -6129,7 +6153,7 @@ bnx2_free_irq(struct bnx2 *bp)
static void
bnx2_enable_msix(struct bnx2 *bp, int msix_vecs)
{
- int i, rc;
+ int i, total_vecs, rc;
struct msix_entry msix_ent[BNX2_MAX_MSIX_VEC];
struct net_device *dev = bp->dev;
const int len = sizeof(bp->irq_tbl[0].name);
@@ -6148,13 +6172,29 @@ bnx2_enable_msix(struct bnx2 *bp, int msix_vecs)
msix_ent[i].vector = 0;
}
- rc = pci_enable_msix(bp->pdev, msix_ent, BNX2_MAX_MSIX_VEC);
+ total_vecs = msix_vecs;
+#ifdef BCM_CNIC
+ total_vecs++;
+#endif
+ rc = -ENOSPC;
+ while (total_vecs >= BNX2_MIN_MSIX_VEC) {
+ rc = pci_enable_msix(bp->pdev, msix_ent, total_vecs);
+ if (rc <= 0)
+ break;
+ if (rc > 0)
+ total_vecs = rc;
+ }
+
if (rc != 0)
return;
+ msix_vecs = total_vecs;
+#ifdef BCM_CNIC
+ msix_vecs--;
+#endif
bp->irq_nvecs = msix_vecs;
bp->flags |= BNX2_FLAG_USING_MSIX | BNX2_FLAG_ONE_SHOT_MSI;
- for (i = 0; i < BNX2_MAX_MSIX_VEC; i++) {
+ for (i = 0; i < total_vecs; i++) {
bp->irq_tbl[i].vector = msix_ent[i].vector;
snprintf(bp->irq_tbl[i].name, len, "%s-%d", dev->name, i);
bp->irq_tbl[i].handler = bnx2_msi_1shot;
@@ -6172,7 +6212,7 @@ bnx2_setup_int_mode(struct bnx2 *bp, int dis_msi)
bp->irq_nvecs = 1;
bp->irq_tbl[0].vector = bp->pdev->irq;
- if ((bp->flags & BNX2_FLAG_MSIX_CAP) && !dis_msi && cpus > 1)
+ if ((bp->flags & BNX2_FLAG_MSIX_CAP) && !dis_msi)
bnx2_enable_msix(bp, msix_vecs);
if ((bp->flags & BNX2_FLAG_MSI_CAP) && !dis_msi &&
@@ -6296,9 +6336,14 @@ static void
bnx2_dump_state(struct bnx2 *bp)
{
struct net_device *dev = bp->dev;
- u32 mcp_p0, mcp_p1;
-
- netdev_err(dev, "DEBUG: intr_sem[%x]\n", atomic_read(&bp->intr_sem));
+ u32 mcp_p0, mcp_p1, val1, val2;
+
+ pci_read_config_dword(bp->pdev, PCI_COMMAND, &val1);
+ netdev_err(dev, "DEBUG: intr_sem[%x] PCI_CMD[%08x]\n",
+ atomic_read(&bp->intr_sem), val1);
+ pci_read_config_dword(bp->pdev, bp->pm_cap + PCI_PM_CTRL, &val1);
+ pci_read_config_dword(bp->pdev, BNX2_PCICFG_MISC_CONFIG, &val2);
+ netdev_err(dev, "DEBUG: PCI_PM[%08x] PCI_MISC_CFG[%08x]\n", val1, val2);
netdev_err(dev, "DEBUG: EMAC_TX_STATUS[%08x] EMAC_RX_STATUS[%08x]\n",
REG_RD(bp, BNX2_EMAC_TX_STATUS),
REG_RD(bp, BNX2_EMAC_RX_STATUS));
@@ -6434,8 +6479,8 @@ bnx2_start_xmit(struct sk_buff *skb, struct net_device *dev)
} else
mss = 0;
- mapping = pci_map_single(bp->pdev, skb->data, len, PCI_DMA_TODEVICE);
- if (pci_dma_mapping_error(bp->pdev, mapping)) {
+ mapping = dma_map_single(&bp->pdev->dev, skb->data, len, PCI_DMA_TODEVICE);
+ if (dma_mapping_error(&bp->pdev->dev, mapping)) {
dev_kfree_skb(skb);
return NETDEV_TX_OK;
}
@@ -6463,9 +6508,9 @@ bnx2_start_xmit(struct sk_buff *skb, struct net_device *dev)
txbd = &txr->tx_desc_ring[ring_prod];
len = frag->size;
- mapping = pci_map_page(bp->pdev, frag->page, frag->page_offset,
- len, PCI_DMA_TODEVICE);
- if (pci_dma_mapping_error(bp->pdev, mapping))
+ mapping = dma_map_page(&bp->pdev->dev, frag->page, frag->page_offset,
+ len, PCI_DMA_TODEVICE);
+ if (dma_mapping_error(&bp->pdev->dev, mapping))
goto dma_error;
dma_unmap_addr_set(&txr->tx_buf_ring[ring_prod], mapping,
mapping);
@@ -6490,6 +6535,13 @@ bnx2_start_xmit(struct sk_buff *skb, struct net_device *dev)
if (unlikely(bnx2_tx_avail(bp, txr) <= MAX_SKB_FRAGS)) {
netif_tx_stop_queue(txq);
+
+ /* netif_tx_stop_queue() must be done before checking
+ * tx index in bnx2_tx_avail() below, because in
+ * bnx2_tx_int(), we update tx index before checking for
+ * netif_tx_queue_stopped().
+ */
+ smp_mb();
if (bnx2_tx_avail(bp, txr) > bp->tx_wake_thresh)
netif_tx_wake_queue(txq);
}
@@ -6504,7 +6556,7 @@ dma_error:
ring_prod = TX_RING_IDX(prod);
tx_buf = &txr->tx_buf_ring[ring_prod];
tx_buf->skb = NULL;
- pci_unmap_single(bp->pdev, dma_unmap_addr(tx_buf, mapping),
+ dma_unmap_single(&bp->pdev->dev, dma_unmap_addr(tx_buf, mapping),
skb_headlen(skb), PCI_DMA_TODEVICE);
/* unmap remaining mapped pages */
@@ -6512,7 +6564,7 @@ dma_error:
prod = NEXT_TX_BD(prod);
ring_prod = TX_RING_IDX(prod);
tx_buf = &txr->tx_buf_ring[ring_prod];
- pci_unmap_page(bp->pdev, dma_unmap_addr(tx_buf, mapping),
+ dma_unmap_page(&bp->pdev->dev, dma_unmap_addr(tx_buf, mapping),
skb_shinfo(skb)->frags[i].size,
PCI_DMA_TODEVICE);
}
@@ -6567,36 +6619,25 @@ bnx2_save_stats(struct bnx2 *bp)
temp_stats[i] += hw_stats[i];
}
-#define GET_64BIT_NET_STATS64(ctr) \
- (unsigned long) ((unsigned long) (ctr##_hi) << 32) + \
- (unsigned long) (ctr##_lo)
-
-#define GET_64BIT_NET_STATS32(ctr) \
- (ctr##_lo)
+#define GET_64BIT_NET_STATS64(ctr) \
+ (((u64) (ctr##_hi) << 32) + (u64) (ctr##_lo))
-#if (BITS_PER_LONG == 64)
#define GET_64BIT_NET_STATS(ctr) \
GET_64BIT_NET_STATS64(bp->stats_blk->ctr) + \
GET_64BIT_NET_STATS64(bp->temp_stats_blk->ctr)
-#else
-#define GET_64BIT_NET_STATS(ctr) \
- GET_64BIT_NET_STATS32(bp->stats_blk->ctr) + \
- GET_64BIT_NET_STATS32(bp->temp_stats_blk->ctr)
-#endif
#define GET_32BIT_NET_STATS(ctr) \
(unsigned long) (bp->stats_blk->ctr + \
bp->temp_stats_blk->ctr)
-static struct net_device_stats *
-bnx2_get_stats(struct net_device *dev)
+static struct rtnl_link_stats64 *
+bnx2_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *net_stats)
{
struct bnx2 *bp = netdev_priv(dev);
- struct net_device_stats *net_stats = &dev->stats;
- if (bp->stats_blk == NULL) {
+ if (bp->stats_blk == NULL)
return net_stats;
- }
+
net_stats->rx_packets =
GET_64BIT_NET_STATS(stat_IfHCInUcastPkts) +
GET_64BIT_NET_STATS(stat_IfHCInMulticastPkts) +
@@ -6614,7 +6655,7 @@ bnx2_get_stats(struct net_device *dev)
GET_64BIT_NET_STATS(stat_IfHCOutOctets);
net_stats->multicast =
- GET_64BIT_NET_STATS(stat_IfHCOutMulticastPkts);
+ GET_64BIT_NET_STATS(stat_IfHCInMulticastPkts);
net_stats->collisions =
GET_32BIT_NET_STATS(stat_EtherStatsCollisions);
@@ -7545,6 +7586,12 @@ bnx2_set_tx_csum(struct net_device *dev, u32 data)
return (ethtool_op_set_tx_csum(dev, data));
}
+static int
+bnx2_set_flags(struct net_device *dev, u32 data)
+{
+ return ethtool_op_set_flags(dev, data, ETH_FLAG_RXHASH);
+}
+
static const struct ethtool_ops bnx2_ethtool_ops = {
.get_settings = bnx2_get_settings,
.set_settings = bnx2_set_settings,
@@ -7574,6 +7621,8 @@ static const struct ethtool_ops bnx2_ethtool_ops = {
.phys_id = bnx2_phys_id,
.get_ethtool_stats = bnx2_get_ethtool_stats,
.get_sset_count = bnx2_get_sset_count,
+ .set_flags = bnx2_set_flags,
+ .get_flags = ethtool_op_get_flags,
};
/* Called with rtnl_lock */
@@ -8259,7 +8308,7 @@ static const struct net_device_ops bnx2_netdev_ops = {
.ndo_open = bnx2_open,
.ndo_start_xmit = bnx2_start_xmit,
.ndo_stop = bnx2_close,
- .ndo_get_stats = bnx2_get_stats,
+ .ndo_get_stats64 = bnx2_get_stats64,
.ndo_set_rx_mode = bnx2_set_rx_mode,
.ndo_do_ioctl = bnx2_ioctl,
.ndo_validate_addr = eth_validate_addr,
@@ -8320,7 +8369,8 @@ bnx2_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
memcpy(dev->dev_addr, bp->mac_addr, 6);
memcpy(dev->perm_addr, bp->mac_addr, 6);
- dev->features |= NETIF_F_IP_CSUM | NETIF_F_SG | NETIF_F_GRO;
+ dev->features |= NETIF_F_IP_CSUM | NETIF_F_SG | NETIF_F_GRO |
+ NETIF_F_RXHASH;
vlan_features_add(dev, NETIF_F_IP_CSUM | NETIF_F_SG);
if (CHIP_NUM(bp) == CHIP_NUM_5709) {
dev->features |= NETIF_F_IPV6_CSUM;
diff --git a/drivers/net/bnx2.h b/drivers/net/bnx2.h
index ddaa3fc9987..2104c1005d0 100644
--- a/drivers/net/bnx2.h
+++ b/drivers/net/bnx2.h
@@ -295,6 +295,9 @@ struct l2_fhdr {
#define L2_FHDR_ERRORS_TCP_XSUM (1<<28)
#define L2_FHDR_ERRORS_UDP_XSUM (1<<31)
+ #define L2_FHDR_STATUS_USE_RXHASH \
+ (L2_FHDR_STATUS_TCP_SEGMENT | L2_FHDR_STATUS_RSS_HASH)
+
u32 l2_fhdr_hash;
#if defined(__BIG_ENDIAN)
u16 l2_fhdr_pkt_len;
@@ -6634,9 +6637,12 @@ struct flash_spec {
#define BNX2_MAX_MSIX_HW_VEC 9
#define BNX2_MAX_MSIX_VEC 9
-#define BNX2_BASE_VEC 0
-#define BNX2_TX_VEC 1
-#define BNX2_TX_INT_NUM (BNX2_TX_VEC << BNX2_PCICFG_INT_ACK_CMD_INT_NUM_SHIFT)
+#ifdef BCM_CNIC
+#define BNX2_MIN_MSIX_VEC 2
+#else
+#define BNX2_MIN_MSIX_VEC 1
+#endif
+
struct bnx2_irq {
irq_handler_t handler;
diff --git a/drivers/net/bnx2x/Makefile b/drivers/net/bnx2x/Makefile
new file mode 100644
index 00000000000..084afce89ae
--- /dev/null
+++ b/drivers/net/bnx2x/Makefile
@@ -0,0 +1,7 @@
+#
+# Makefile for Broadcom 10-Gigabit ethernet driver
+#
+
+obj-$(CONFIG_BNX2X) += bnx2x.o
+
+bnx2x-objs := bnx2x_main.o bnx2x_link.o bnx2x_cmn.o bnx2x_ethtool.o bnx2x_stats.o
diff --git a/drivers/net/bnx2x.h b/drivers/net/bnx2x/bnx2x.h
index bb0872a6331..53af9c93e75 100644
--- a/drivers/net/bnx2x.h
+++ b/drivers/net/bnx2x/bnx2x.h
@@ -20,6 +20,10 @@
* (you will need to reboot afterwards) */
/* #define BNX2X_STOP_ON_ERROR */
+#define DRV_MODULE_VERSION "1.52.53-3"
+#define DRV_MODULE_RELDATE "2010/18/04"
+#define BNX2X_BC_VER 0x040200
+
#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)
#define BCM_VLAN 1
#endif
@@ -32,7 +36,7 @@
#if defined(CONFIG_CNIC) || defined(CONFIG_CNIC_MODULE)
#define BCM_CNIC 1
-#include "cnic_if.h"
+#include "../cnic_if.h"
#endif
@@ -45,10 +49,12 @@
#endif
#include <linux/mdio.h>
+#include <linux/pci.h>
#include "bnx2x_reg.h"
#include "bnx2x_fw_defs.h"
#include "bnx2x_hsi.h"
#include "bnx2x_link.h"
+#include "bnx2x_stats.h"
/* error/debug prints */
@@ -106,6 +112,7 @@ do { \
dev_info(&bp->pdev->dev, __fmt, ##__args); \
} while (0)
+void bnx2x_panic_dump(struct bnx2x *bp);
#ifdef BNX2X_STOP_ON_ERROR
#define bnx2x_panic() do { \
@@ -248,43 +255,6 @@ union db_prod {
#define NEXT_SGE_MASK_ELEM(el) (((el) + 1) & RX_SGE_MASK_LEN_MASK)
-struct bnx2x_eth_q_stats {
- u32 total_bytes_received_hi;
- u32 total_bytes_received_lo;
- u32 total_bytes_transmitted_hi;
- u32 total_bytes_transmitted_lo;
- u32 total_unicast_packets_received_hi;
- u32 total_unicast_packets_received_lo;
- u32 total_multicast_packets_received_hi;
- u32 total_multicast_packets_received_lo;
- u32 total_broadcast_packets_received_hi;
- u32 total_broadcast_packets_received_lo;
- u32 total_unicast_packets_transmitted_hi;
- u32 total_unicast_packets_transmitted_lo;
- u32 total_multicast_packets_transmitted_hi;
- u32 total_multicast_packets_transmitted_lo;
- u32 total_broadcast_packets_transmitted_hi;
- u32 total_broadcast_packets_transmitted_lo;
- u32 valid_bytes_received_hi;
- u32 valid_bytes_received_lo;
-
- u32 error_bytes_received_hi;
- u32 error_bytes_received_lo;
- u32 etherstatsoverrsizepkts_hi;
- u32 etherstatsoverrsizepkts_lo;
- u32 no_buff_discard_hi;
- u32 no_buff_discard_lo;
-
- u32 driver_xoff;
- u32 rx_err_discard_pkt;
- u32 rx_skb_alloc_failed;
- u32 hw_csum_err;
-};
-
-#define BNX2X_NUM_Q_STATS 13
-#define Q_STATS_OFFSET32(stat_name) \
- (offsetof(struct bnx2x_eth_q_stats, stat_name) / 4)
-
struct bnx2x_fastpath {
struct napi_struct napi;
@@ -593,27 +563,6 @@ struct bnx2x_common {
/* port */
-struct nig_stats {
- u32 brb_discard;
- u32 brb_packet;
- u32 brb_truncate;
- u32 flow_ctrl_discard;
- u32 flow_ctrl_octets;
- u32 flow_ctrl_packet;
- u32 mng_discard;
- u32 mng_octet_inp;
- u32 mng_octet_out;
- u32 mng_packet_inp;
- u32 mng_packet_out;
- u32 pbf_octets;
- u32 pbf_packet;
- u32 safc_inp;
- u32 egress_mac_pkt0_lo;
- u32 egress_mac_pkt0_hi;
- u32 egress_mac_pkt1_lo;
- u32 egress_mac_pkt1_hi;
-};
-
struct bnx2x_port {
u32 pmf;
@@ -641,156 +590,6 @@ struct bnx2x_port {
/* end of port */
-enum bnx2x_stats_event {
- STATS_EVENT_PMF = 0,
- STATS_EVENT_LINK_UP,
- STATS_EVENT_UPDATE,
- STATS_EVENT_STOP,
- STATS_EVENT_MAX
-};
-
-enum bnx2x_stats_state {
- STATS_STATE_DISABLED = 0,
- STATS_STATE_ENABLED,
- STATS_STATE_MAX
-};
-
-struct bnx2x_eth_stats {
- u32 total_bytes_received_hi;
- u32 total_bytes_received_lo;
- u32 total_bytes_transmitted_hi;
- u32 total_bytes_transmitted_lo;
- u32 total_unicast_packets_received_hi;
- u32 total_unicast_packets_received_lo;
- u32 total_multicast_packets_received_hi;
- u32 total_multicast_packets_received_lo;
- u32 total_broadcast_packets_received_hi;
- u32 total_broadcast_packets_received_lo;
- u32 total_unicast_packets_transmitted_hi;
- u32 total_unicast_packets_transmitted_lo;
- u32 total_multicast_packets_transmitted_hi;
- u32 total_multicast_packets_transmitted_lo;
- u32 total_broadcast_packets_transmitted_hi;
- u32 total_broadcast_packets_transmitted_lo;
- u32 valid_bytes_received_hi;
- u32 valid_bytes_received_lo;
-
- u32 error_bytes_received_hi;
- u32 error_bytes_received_lo;
- u32 etherstatsoverrsizepkts_hi;
- u32 etherstatsoverrsizepkts_lo;
- u32 no_buff_discard_hi;
- u32 no_buff_discard_lo;
-
- u32 rx_stat_ifhcinbadoctets_hi;
- u32 rx_stat_ifhcinbadoctets_lo;
- u32 tx_stat_ifhcoutbadoctets_hi;
- u32 tx_stat_ifhcoutbadoctets_lo;
- u32 rx_stat_dot3statsfcserrors_hi;
- u32 rx_stat_dot3statsfcserrors_lo;
- u32 rx_stat_dot3statsalignmenterrors_hi;
- u32 rx_stat_dot3statsalignmenterrors_lo;
- u32 rx_stat_dot3statscarriersenseerrors_hi;
- u32 rx_stat_dot3statscarriersenseerrors_lo;
- u32 rx_stat_falsecarriererrors_hi;
- u32 rx_stat_falsecarriererrors_lo;
- u32 rx_stat_etherstatsundersizepkts_hi;
- u32 rx_stat_etherstatsundersizepkts_lo;
- u32 rx_stat_dot3statsframestoolong_hi;
- u32 rx_stat_dot3statsframestoolong_lo;
- u32 rx_stat_etherstatsfragments_hi;
- u32 rx_stat_etherstatsfragments_lo;
- u32 rx_stat_etherstatsjabbers_hi;
- u32 rx_stat_etherstatsjabbers_lo;
- u32 rx_stat_maccontrolframesreceived_hi;
- u32 rx_stat_maccontrolframesreceived_lo;
- u32 rx_stat_bmac_xpf_hi;
- u32 rx_stat_bmac_xpf_lo;
- u32 rx_stat_bmac_xcf_hi;
- u32 rx_stat_bmac_xcf_lo;
- u32 rx_stat_xoffstateentered_hi;
- u32 rx_stat_xoffstateentered_lo;
- u32 rx_stat_xonpauseframesreceived_hi;
- u32 rx_stat_xonpauseframesreceived_lo;
- u32 rx_stat_xoffpauseframesreceived_hi;
- u32 rx_stat_xoffpauseframesreceived_lo;
- u32 tx_stat_outxonsent_hi;
- u32 tx_stat_outxonsent_lo;
- u32 tx_stat_outxoffsent_hi;
- u32 tx_stat_outxoffsent_lo;
- u32 tx_stat_flowcontroldone_hi;
- u32 tx_stat_flowcontroldone_lo;
- u32 tx_stat_etherstatscollisions_hi;
- u32 tx_stat_etherstatscollisions_lo;
- u32 tx_stat_dot3statssinglecollisionframes_hi;
- u32 tx_stat_dot3statssinglecollisionframes_lo;
- u32 tx_stat_dot3statsmultiplecollisionframes_hi;
- u32 tx_stat_dot3statsmultiplecollisionframes_lo;
- u32 tx_stat_dot3statsdeferredtransmissions_hi;
- u32 tx_stat_dot3statsdeferredtransmissions_lo;
- u32 tx_stat_dot3statsexcessivecollisions_hi;
- u32 tx_stat_dot3statsexcessivecollisions_lo;
- u32 tx_stat_dot3statslatecollisions_hi;
- u32 tx_stat_dot3statslatecollisions_lo;
- u32 tx_stat_etherstatspkts64octets_hi;
- u32 tx_stat_etherstatspkts64octets_lo;
- u32 tx_stat_etherstatspkts65octetsto127octets_hi;
- u32 tx_stat_etherstatspkts65octetsto127octets_lo;
- u32 tx_stat_etherstatspkts128octetsto255octets_hi;
- u32 tx_stat_etherstatspkts128octetsto255octets_lo;
- u32 tx_stat_etherstatspkts256octetsto511octets_hi;
- u32 tx_stat_etherstatspkts256octetsto511octets_lo;
- u32 tx_stat_etherstatspkts512octetsto1023octets_hi;
- u32 tx_stat_etherstatspkts512octetsto1023octets_lo;
- u32 tx_stat_etherstatspkts1024octetsto1522octets_hi;
- u32 tx_stat_etherstatspkts1024octetsto1522octets_lo;
- u32 tx_stat_etherstatspktsover1522octets_hi;
- u32 tx_stat_etherstatspktsover1522octets_lo;
- u32 tx_stat_bmac_2047_hi;
- u32 tx_stat_bmac_2047_lo;
- u32 tx_stat_bmac_4095_hi;
- u32 tx_stat_bmac_4095_lo;
- u32 tx_stat_bmac_9216_hi;
- u32 tx_stat_bmac_9216_lo;
- u32 tx_stat_bmac_16383_hi;
- u32 tx_stat_bmac_16383_lo;
- u32 tx_stat_dot3statsinternalmactransmiterrors_hi;
- u32 tx_stat_dot3statsinternalmactransmiterrors_lo;
- u32 tx_stat_bmac_ufl_hi;
- u32 tx_stat_bmac_ufl_lo;
-
- u32 pause_frames_received_hi;
- u32 pause_frames_received_lo;
- u32 pause_frames_sent_hi;
- u32 pause_frames_sent_lo;
-
- u32 etherstatspkts1024octetsto1522octets_hi;
- u32 etherstatspkts1024octetsto1522octets_lo;
- u32 etherstatspktsover1522octets_hi;
- u32 etherstatspktsover1522octets_lo;
-
- u32 brb_drop_hi;
- u32 brb_drop_lo;
- u32 brb_truncate_hi;
- u32 brb_truncate_lo;
-
- u32 mac_filter_discard;
- u32 xxoverflow_discard;
- u32 brb_truncate_discard;
- u32 mac_discard;
-
- u32 driver_xoff;
- u32 rx_err_discard_pkt;
- u32 rx_skb_alloc_failed;
- u32 hw_csum_err;
-
- u32 nig_timer_max;
-};
-
-#define BNX2X_NUM_STATS 43
-#define STATS_OFFSET32(stat_name) \
- (offsetof(struct bnx2x_eth_stats, stat_name) / 4)
-
#ifdef BCM_CNIC
#define MAX_CONTEXT 15
@@ -1006,6 +805,8 @@ struct bnx2x {
int multi_mode;
int num_queues;
+ int disable_tpa;
+ int int_mode;
u32 rx_mode;
#define BNX2X_RX_MODE_NONE 0
@@ -1134,6 +935,10 @@ u32 bnx2x_fw_command(struct bnx2x *bp, u32 command);
void bnx2x_reg_wr_ind(struct bnx2x *bp, u32 addr, u32 val);
void bnx2x_write_dmae_phys_len(struct bnx2x *bp, dma_addr_t phys_addr,
u32 addr, u32 len);
+void bnx2x_calc_fc_adv(struct bnx2x *bp);
+int bnx2x_sp_post(struct bnx2x *bp, int command, int cid,
+ u32 data_hi, u32 data_lo, int common);
+void bnx2x_update_coalesce(struct bnx2x *bp);
static inline u32 reg_poll(struct bnx2x *bp, u32 reg, u32 expected, int ms,
int wait)
@@ -1375,6 +1180,18 @@ static inline u32 reg_poll(struct bnx2x *bp, u32 reg, u32 expected, int ms,
#define BNX2X_VPD_LEN 128
#define VENDOR_ID_LEN 4
+#ifdef BNX2X_MAIN
+#define BNX2X_EXTERN
+#else
+#define BNX2X_EXTERN extern
+#endif
+
+BNX2X_EXTERN int load_count[3]; /* 0-common, 1-port0, 2-port1 */
+
/* MISC_REG_RESET_REG - this is here for the hsi to work don't touch */
+extern void bnx2x_set_ethtool_ops(struct net_device *netdev);
+
+void bnx2x_post_dmae(struct bnx2x *bp, struct dmae_command *dmae, int idx);
+
#endif /* bnx2x.h */
diff --git a/drivers/net/bnx2x/bnx2x_cmn.c b/drivers/net/bnx2x/bnx2x_cmn.c
new file mode 100644
index 00000000000..02bf710629a
--- /dev/null
+++ b/drivers/net/bnx2x/bnx2x_cmn.c
@@ -0,0 +1,2252 @@
+/* bnx2x_cmn.c: Broadcom Everest network driver.
+ *
+ * Copyright (c) 2007-2010 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.
+ *
+ * Maintained by: Eilon Greenstein <eilong@broadcom.com>
+ * Written by: Eliezer Tamir
+ * Based on code from Michael Chan's bnx2 driver
+ * UDP CSUM errata workaround by Arik Gendelman
+ * Slowpath and fastpath rework by Vladislav Zolotarov
+ * Statistics and Link management by Yitchak Gertner
+ *
+ */
+
+
+#include <linux/etherdevice.h>
+#include <linux/ip.h>
+#include <linux/ipv6.h>
+#include <net/ip6_checksum.h>
+#include "bnx2x_cmn.h"
+
+#ifdef BCM_VLAN
+#include <linux/if_vlan.h>
+#endif
+
+static int bnx2x_poll(struct napi_struct *napi, int budget);
+
+/* free skb in the packet ring at pos idx
+ * return idx of last bd freed
+ */
+static u16 bnx2x_free_tx_pkt(struct bnx2x *bp, struct bnx2x_fastpath *fp,
+ u16 idx)
+{
+ struct sw_tx_bd *tx_buf = &fp->tx_buf_ring[idx];
+ struct eth_tx_start_bd *tx_start_bd;
+ struct eth_tx_bd *tx_data_bd;
+ struct sk_buff *skb = tx_buf->skb;
+ u16 bd_idx = TX_BD(tx_buf->first_bd), new_cons;
+ int nbd;
+
+ /* prefetch skb end pointer to speedup dev_kfree_skb() */
+ prefetch(&skb->end);
+
+ DP(BNX2X_MSG_OFF, "pkt_idx %d buff @(%p)->skb %p\n",
+ idx, tx_buf, skb);
+
+ /* unmap first bd */
+ DP(BNX2X_MSG_OFF, "free bd_idx %d\n", bd_idx);
+ tx_start_bd = &fp->tx_desc_ring[bd_idx].start_bd;
+ dma_unmap_single(&bp->pdev->dev, BD_UNMAP_ADDR(tx_start_bd),
+ BD_UNMAP_LEN(tx_start_bd), PCI_DMA_TODEVICE);
+
+ nbd = le16_to_cpu(tx_start_bd->nbd) - 1;
+#ifdef BNX2X_STOP_ON_ERROR
+ if ((nbd - 1) > (MAX_SKB_FRAGS + 2)) {
+ BNX2X_ERR("BAD nbd!\n");
+ bnx2x_panic();
+ }
+#endif
+ new_cons = nbd + tx_buf->first_bd;
+
+ /* Get the next bd */
+ bd_idx = TX_BD(NEXT_TX_IDX(bd_idx));
+
+ /* Skip a parse bd... */
+ --nbd;
+ bd_idx = TX_BD(NEXT_TX_IDX(bd_idx));
+
+ /* ...and the TSO split header bd since they have no mapping */
+ if (tx_buf->flags & BNX2X_TSO_SPLIT_BD) {
+ --nbd;
+ bd_idx = TX_BD(NEXT_TX_IDX(bd_idx));
+ }
+
+ /* now free frags */
+ while (nbd > 0) {
+
+ DP(BNX2X_MSG_OFF, "free frag bd_idx %d\n", bd_idx);
+ tx_data_bd = &fp->tx_desc_ring[bd_idx].reg_bd;
+ dma_unmap_page(&bp->pdev->dev, BD_UNMAP_ADDR(tx_data_bd),
+ BD_UNMAP_LEN(tx_data_bd), DMA_TO_DEVICE);
+ if (--nbd)
+ bd_idx = TX_BD(NEXT_TX_IDX(bd_idx));
+ }
+
+ /* release skb */
+ WARN_ON(!skb);
+ dev_kfree_skb(skb);
+ tx_buf->first_bd = 0;
+ tx_buf->skb = NULL;
+
+ return new_cons;
+}
+
+int bnx2x_tx_int(struct bnx2x_fastpath *fp)
+{
+ struct bnx2x *bp = fp->bp;
+ struct netdev_queue *txq;
+ u16 hw_cons, sw_cons, bd_cons = fp->tx_bd_cons;
+
+#ifdef BNX2X_STOP_ON_ERROR
+ if (unlikely(bp->panic))
+ return -1;
+#endif
+
+ txq = netdev_get_tx_queue(bp->dev, fp->index);
+ hw_cons = le16_to_cpu(*fp->tx_cons_sb);
+ sw_cons = fp->tx_pkt_cons;
+
+ while (sw_cons != hw_cons) {
+ u16 pkt_cons;
+
+ pkt_cons = TX_BD(sw_cons);
+
+ /* prefetch(bp->tx_buf_ring[pkt_cons].skb); */
+
+ DP(NETIF_MSG_TX_DONE, "hw_cons %u sw_cons %u pkt_cons %u\n",
+ hw_cons, sw_cons, pkt_cons);
+
+/* if (NEXT_TX_IDX(sw_cons) != hw_cons) {
+ rmb();
+ prefetch(fp->tx_buf_ring[NEXT_TX_IDX(sw_cons)].skb);
+ }
+*/
+ bd_cons = bnx2x_free_tx_pkt(bp, fp, pkt_cons);
+ sw_cons++;
+ }
+
+ fp->tx_pkt_cons = sw_cons;
+ fp->tx_bd_cons = bd_cons;
+
+ /* Need to make the tx_bd_cons update visible to start_xmit()
+ * before checking for netif_tx_queue_stopped(). Without the
+ * memory barrier, there is a small possibility that
+ * start_xmit() will miss it and cause the queue to be stopped
+ * forever.
+ */
+ smp_mb();
+
+ /* TBD need a thresh? */
+ if (unlikely(netif_tx_queue_stopped(txq))) {
+ /* Taking tx_lock() is needed to prevent reenabling the queue
+ * while it's empty. This could have happen if rx_action() gets
+ * suspended in bnx2x_tx_int() after the condition before
+ * netif_tx_wake_queue(), while tx_action (bnx2x_start_xmit()):
+ *
+ * stops the queue->sees fresh tx_bd_cons->releases the queue->
+ * sends some packets consuming the whole queue again->
+ * stops the queue
+ */
+
+ __netif_tx_lock(txq, smp_processor_id());
+
+ if ((netif_tx_queue_stopped(txq)) &&
+ (bp->state == BNX2X_STATE_OPEN) &&
+ (bnx2x_tx_avail(fp) >= MAX_SKB_FRAGS + 3))
+ netif_tx_wake_queue(txq);
+
+ __netif_tx_unlock(txq);
+ }
+ return 0;
+}
+
+static inline void bnx2x_update_last_max_sge(struct bnx2x_fastpath *fp,
+ u16 idx)
+{
+ u16 last_max = fp->last_max_sge;
+
+ if (SUB_S16(idx, last_max) > 0)
+ fp->last_max_sge = idx;
+}
+
+static void bnx2x_update_sge_prod(struct bnx2x_fastpath *fp,
+ struct eth_fast_path_rx_cqe *fp_cqe)
+{
+ struct bnx2x *bp = fp->bp;
+ u16 sge_len = SGE_PAGE_ALIGN(le16_to_cpu(fp_cqe->pkt_len) -
+ le16_to_cpu(fp_cqe->len_on_bd)) >>
+ SGE_PAGE_SHIFT;
+ u16 last_max, last_elem, first_elem;
+ u16 delta = 0;
+ u16 i;
+
+ if (!sge_len)
+ return;
+
+ /* First mark all used pages */
+ for (i = 0; i < sge_len; i++)
+ SGE_MASK_CLEAR_BIT(fp, RX_SGE(le16_to_cpu(fp_cqe->sgl[i])));
+
+ DP(NETIF_MSG_RX_STATUS, "fp_cqe->sgl[%d] = %d\n",
+ sge_len - 1, le16_to_cpu(fp_cqe->sgl[sge_len - 1]));
+
+ /* Here we assume that the last SGE index is the biggest */
+ prefetch((void *)(fp->sge_mask));
+ bnx2x_update_last_max_sge(fp, le16_to_cpu(fp_cqe->sgl[sge_len - 1]));
+
+ last_max = RX_SGE(fp->last_max_sge);
+ last_elem = last_max >> RX_SGE_MASK_ELEM_SHIFT;
+ first_elem = RX_SGE(fp->rx_sge_prod) >> RX_SGE_MASK_ELEM_SHIFT;
+
+ /* If ring is not full */
+ if (last_elem + 1 != first_elem)
+ last_elem++;
+
+ /* Now update the prod */
+ for (i = first_elem; i != last_elem; i = NEXT_SGE_MASK_ELEM(i)) {
+ if (likely(fp->sge_mask[i]))
+ break;
+
+ fp->sge_mask[i] = RX_SGE_MASK_ELEM_ONE_MASK;
+ delta += RX_SGE_MASK_ELEM_SZ;
+ }
+
+ if (delta > 0) {
+ fp->rx_sge_prod += delta;
+ /* clear page-end entries */
+ bnx2x_clear_sge_mask_next_elems(fp);
+ }
+
+ DP(NETIF_MSG_RX_STATUS,
+ "fp->last_max_sge = %d fp->rx_sge_prod = %d\n",
+ fp->last_max_sge, fp->rx_sge_prod);
+}
+
+static void bnx2x_tpa_start(struct bnx2x_fastpath *fp, u16 queue,
+ struct sk_buff *skb, u16 cons, u16 prod)
+{
+ struct bnx2x *bp = fp->bp;
+ struct sw_rx_bd *cons_rx_buf = &fp->rx_buf_ring[cons];
+ struct sw_rx_bd *prod_rx_buf = &fp->rx_buf_ring[prod];
+ struct eth_rx_bd *prod_bd = &fp->rx_desc_ring[prod];
+ dma_addr_t mapping;
+
+ /* move empty skb from pool to prod and map it */
+ prod_rx_buf->skb = fp->tpa_pool[queue].skb;
+ mapping = dma_map_single(&bp->pdev->dev, fp->tpa_pool[queue].skb->data,
+ bp->rx_buf_size, DMA_FROM_DEVICE);
+ dma_unmap_addr_set(prod_rx_buf, mapping, mapping);
+
+ /* move partial skb from cons to pool (don't unmap yet) */
+ fp->tpa_pool[queue] = *cons_rx_buf;
+
+ /* mark bin state as start - print error if current state != stop */
+ if (fp->tpa_state[queue] != BNX2X_TPA_STOP)
+ BNX2X_ERR("start of bin not in stop [%d]\n", queue);
+
+ fp->tpa_state[queue] = BNX2X_TPA_START;
+
+ /* point prod_bd to new skb */
+ prod_bd->addr_hi = cpu_to_le32(U64_HI(mapping));
+ prod_bd->addr_lo = cpu_to_le32(U64_LO(mapping));
+
+#ifdef BNX2X_STOP_ON_ERROR
+ fp->tpa_queue_used |= (1 << queue);
+#ifdef _ASM_GENERIC_INT_L64_H
+ DP(NETIF_MSG_RX_STATUS, "fp->tpa_queue_used = 0x%lx\n",
+#else
+ DP(NETIF_MSG_RX_STATUS, "fp->tpa_queue_used = 0x%llx\n",
+#endif
+ fp->tpa_queue_used);
+#endif
+}
+
+static int bnx2x_fill_frag_skb(struct bnx2x *bp, struct bnx2x_fastpath *fp,
+ struct sk_buff *skb,
+ struct eth_fast_path_rx_cqe *fp_cqe,
+ u16 cqe_idx)
+{
+ struct sw_rx_page *rx_pg, old_rx_pg;
+ u16 len_on_bd = le16_to_cpu(fp_cqe->len_on_bd);
+ u32 i, frag_len, frag_size, pages;
+ int err;
+ int j;
+
+ frag_size = le16_to_cpu(fp_cqe->pkt_len) - len_on_bd;
+ pages = SGE_PAGE_ALIGN(frag_size) >> SGE_PAGE_SHIFT;
+
+ /* This is needed in order to enable forwarding support */
+ if (frag_size)
+ skb_shinfo(skb)->gso_size = min((u32)SGE_PAGE_SIZE,
+ max(frag_size, (u32)len_on_bd));
+
+#ifdef BNX2X_STOP_ON_ERROR
+ if (pages > min_t(u32, 8, MAX_SKB_FRAGS)*SGE_PAGE_SIZE*PAGES_PER_SGE) {
+ BNX2X_ERR("SGL length is too long: %d. CQE index is %d\n",
+ pages, cqe_idx);
+ BNX2X_ERR("fp_cqe->pkt_len = %d fp_cqe->len_on_bd = %d\n",
+ fp_cqe->pkt_len, len_on_bd);
+ bnx2x_panic();
+ return -EINVAL;
+ }
+#endif
+
+ /* Run through the SGL and compose the fragmented skb */
+ for (i = 0, j = 0; i < pages; i += PAGES_PER_SGE, j++) {
+ u16 sge_idx = RX_SGE(le16_to_cpu(fp_cqe->sgl[j]));
+
+ /* FW gives the indices of the SGE as if the ring is an array
+ (meaning that "next" element will consume 2 indices) */
+ frag_len = min(frag_size, (u32)(SGE_PAGE_SIZE*PAGES_PER_SGE));
+ rx_pg = &fp->rx_page_ring[sge_idx];
+ old_rx_pg = *rx_pg;
+
+ /* If we fail to allocate a substitute page, we simply stop
+ where we are and drop the whole packet */
+ err = bnx2x_alloc_rx_sge(bp, fp, sge_idx);
+ if (unlikely(err)) {
+ fp->eth_q_stats.rx_skb_alloc_failed++;
+ return err;
+ }
+
+ /* Unmap the page as we r going to pass it to the stack */
+ dma_unmap_page(&bp->pdev->dev,
+ dma_unmap_addr(&old_rx_pg, mapping),
+ SGE_PAGE_SIZE*PAGES_PER_SGE, DMA_FROM_DEVICE);
+
+ /* Add one frag and update the appropriate fields in the skb */
+ skb_fill_page_desc(skb, j, old_rx_pg.page, 0, frag_len);
+
+ skb->data_len += frag_len;
+ skb->truesize += frag_len;
+ skb->len += frag_len;
+
+ frag_size -= frag_len;
+ }
+
+ return 0;
+}
+
+static void bnx2x_tpa_stop(struct bnx2x *bp, struct bnx2x_fastpath *fp,
+ u16 queue, int pad, int len, union eth_rx_cqe *cqe,
+ u16 cqe_idx)
+{
+ struct sw_rx_bd *rx_buf = &fp->tpa_pool[queue];
+ struct sk_buff *skb = rx_buf->skb;
+ /* alloc new skb */
+ struct sk_buff *new_skb = netdev_alloc_skb(bp->dev, bp->rx_buf_size);
+
+ /* Unmap skb in the pool anyway, as we are going to change
+ pool entry status to BNX2X_TPA_STOP even if new skb allocation
+ fails. */
+ dma_unmap_single(&bp->pdev->dev, dma_unmap_addr(rx_buf, mapping),
+ bp->rx_buf_size, DMA_FROM_DEVICE);
+
+ if (likely(new_skb)) {
+ /* fix ip xsum and give it to the stack */
+ /* (no need to map the new skb) */
+#ifdef BCM_VLAN
+ int is_vlan_cqe =
+ (le16_to_cpu(cqe->fast_path_cqe.pars_flags.flags) &
+ PARSING_FLAGS_VLAN);
+ int is_not_hwaccel_vlan_cqe =
+ (is_vlan_cqe && (!(bp->flags & HW_VLAN_RX_FLAG)));
+#endif
+
+ prefetch(skb);
+ prefetch(((char *)(skb)) + 128);
+
+#ifdef BNX2X_STOP_ON_ERROR
+ if (pad + len > bp->rx_buf_size) {
+ BNX2X_ERR("skb_put is about to fail... "
+ "pad %d len %d rx_buf_size %d\n",
+ pad, len, bp->rx_buf_size);
+ bnx2x_panic();
+ return;
+ }
+#endif
+
+ skb_reserve(skb, pad);
+ skb_put(skb, len);
+
+ skb->protocol = eth_type_trans(skb, bp->dev);
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+
+ {
+ struct iphdr *iph;
+
+ iph = (struct iphdr *)skb->data;
+#ifdef BCM_VLAN
+ /* If there is no Rx VLAN offloading -
+ take VLAN tag into an account */
+ if (unlikely(is_not_hwaccel_vlan_cqe))
+ iph = (struct iphdr *)((u8 *)iph + VLAN_HLEN);
+#endif
+ iph->check = 0;
+ iph->check = ip_fast_csum((u8 *)iph, iph->ihl);
+ }
+
+ if (!bnx2x_fill_frag_skb(bp, fp, skb,
+ &cqe->fast_path_cqe, cqe_idx)) {
+#ifdef BCM_VLAN
+ if ((bp->vlgrp != NULL) && is_vlan_cqe &&
+ (!is_not_hwaccel_vlan_cqe))
+ vlan_gro_receive(&fp->napi, bp->vlgrp,
+ le16_to_cpu(cqe->fast_path_cqe.
+ vlan_tag), skb);
+ else
+#endif
+ napi_gro_receive(&fp->napi, skb);
+ } else {
+ DP(NETIF_MSG_RX_STATUS, "Failed to allocate new pages"
+ " - dropping packet!\n");
+ dev_kfree_skb(skb);
+ }
+
+
+ /* put new skb in bin */
+ fp->tpa_pool[queue].skb = new_skb;
+
+ } else {
+ /* else drop the packet and keep the buffer in the bin */
+ DP(NETIF_MSG_RX_STATUS,
+ "Failed to allocate new skb - dropping packet!\n");
+ fp->eth_q_stats.rx_skb_alloc_failed++;
+ }
+
+ fp->tpa_state[queue] = BNX2X_TPA_STOP;
+}
+
+/* Set Toeplitz hash value in the skb using the value from the
+ * CQE (calculated by HW).
+ */
+static inline void bnx2x_set_skb_rxhash(struct bnx2x *bp, union eth_rx_cqe *cqe,
+ struct sk_buff *skb)
+{
+ /* Set Toeplitz hash from CQE */
+ if ((bp->dev->features & NETIF_F_RXHASH) &&
+ (cqe->fast_path_cqe.status_flags &
+ ETH_FAST_PATH_RX_CQE_RSS_HASH_FLG))
+ skb->rxhash =
+ le32_to_cpu(cqe->fast_path_cqe.rss_hash_result);
+}
+
+int bnx2x_rx_int(struct bnx2x_fastpath *fp, int budget)
+{
+ struct bnx2x *bp = fp->bp;
+ u16 bd_cons, bd_prod, bd_prod_fw, comp_ring_cons;
+ u16 hw_comp_cons, sw_comp_cons, sw_comp_prod;
+ int rx_pkt = 0;
+
+#ifdef BNX2X_STOP_ON_ERROR
+ if (unlikely(bp->panic))
+ return 0;
+#endif
+
+ /* CQ "next element" is of the size of the regular element,
+ that's why it's ok here */
+ hw_comp_cons = le16_to_cpu(*fp->rx_cons_sb);
+ if ((hw_comp_cons & MAX_RCQ_DESC_CNT) == MAX_RCQ_DESC_CNT)
+ hw_comp_cons++;
+
+ bd_cons = fp->rx_bd_cons;
+ bd_prod = fp->rx_bd_prod;
+ bd_prod_fw = bd_prod;
+ sw_comp_cons = fp->rx_comp_cons;
+ sw_comp_prod = fp->rx_comp_prod;
+
+ /* Memory barrier necessary as speculative reads of the rx
+ * buffer can be ahead of the index in the status block
+ */
+ rmb();
+
+ DP(NETIF_MSG_RX_STATUS,
+ "queue[%d]: hw_comp_cons %u sw_comp_cons %u\n",
+ fp->index, hw_comp_cons, sw_comp_cons);
+
+ while (sw_comp_cons != hw_comp_cons) {
+ struct sw_rx_bd *rx_buf = NULL;
+ struct sk_buff *skb;
+ union eth_rx_cqe *cqe;
+ u8 cqe_fp_flags;
+ u16 len, pad;
+
+ comp_ring_cons = RCQ_BD(sw_comp_cons);
+ bd_prod = RX_BD(bd_prod);
+ bd_cons = RX_BD(bd_cons);
+
+ /* Prefetch the page containing the BD descriptor
+ at producer's index. It will be needed when new skb is
+ allocated */
+ prefetch((void *)(PAGE_ALIGN((unsigned long)
+ (&fp->rx_desc_ring[bd_prod])) -
+ PAGE_SIZE + 1));
+
+ cqe = &fp->rx_comp_ring[comp_ring_cons];
+ cqe_fp_flags = cqe->fast_path_cqe.type_error_flags;
+
+ DP(NETIF_MSG_RX_STATUS, "CQE type %x err %x status %x"
+ " queue %x vlan %x len %u\n", CQE_TYPE(cqe_fp_flags),
+ cqe_fp_flags, cqe->fast_path_cqe.status_flags,
+ le32_to_cpu(cqe->fast_path_cqe.rss_hash_result),
+ le16_to_cpu(cqe->fast_path_cqe.vlan_tag),
+ le16_to_cpu(cqe->fast_path_cqe.pkt_len));
+
+ /* is this a slowpath msg? */
+ if (unlikely(CQE_TYPE(cqe_fp_flags))) {
+ bnx2x_sp_event(fp, cqe);
+ goto next_cqe;
+
+ /* this is an rx packet */
+ } else {
+ rx_buf = &fp->rx_buf_ring[bd_cons];
+ skb = rx_buf->skb;
+ prefetch(skb);
+ len = le16_to_cpu(cqe->fast_path_cqe.pkt_len);
+ pad = cqe->fast_path_cqe.placement_offset;
+
+ /* If CQE is marked both TPA_START and TPA_END
+ it is a non-TPA CQE */
+ if ((!fp->disable_tpa) &&
+ (TPA_TYPE(cqe_fp_flags) !=
+ (TPA_TYPE_START | TPA_TYPE_END))) {
+ u16 queue = cqe->fast_path_cqe.queue_index;
+
+ if (TPA_TYPE(cqe_fp_flags) == TPA_TYPE_START) {
+ DP(NETIF_MSG_RX_STATUS,
+ "calling tpa_start on queue %d\n",
+ queue);
+
+ bnx2x_tpa_start(fp, queue, skb,
+ bd_cons, bd_prod);
+
+ /* Set Toeplitz hash for an LRO skb */
+ bnx2x_set_skb_rxhash(bp, cqe, skb);
+
+ goto next_rx;
+ }
+
+ if (TPA_TYPE(cqe_fp_flags) == TPA_TYPE_END) {
+ DP(NETIF_MSG_RX_STATUS,
+ "calling tpa_stop on queue %d\n",
+ queue);
+
+ if (!BNX2X_RX_SUM_FIX(cqe))
+ BNX2X_ERR("STOP on none TCP "
+ "data\n");
+
+ /* This is a size of the linear data
+ on this skb */
+ len = le16_to_cpu(cqe->fast_path_cqe.
+ len_on_bd);
+ bnx2x_tpa_stop(bp, fp, queue, pad,
+ len, cqe, comp_ring_cons);
+#ifdef BNX2X_STOP_ON_ERROR
+ if (bp->panic)
+ return 0;
+#endif
+
+ bnx2x_update_sge_prod(fp,
+ &cqe->fast_path_cqe);
+ goto next_cqe;
+ }
+ }
+
+ dma_sync_single_for_device(&bp->pdev->dev,
+ dma_unmap_addr(rx_buf, mapping),
+ pad + RX_COPY_THRESH,
+ DMA_FROM_DEVICE);
+ prefetch(((char *)(skb)) + 128);
+
+ /* is this an error packet? */
+ if (unlikely(cqe_fp_flags & ETH_RX_ERROR_FALGS)) {
+ DP(NETIF_MSG_RX_ERR,
+ "ERROR flags %x rx packet %u\n",
+ cqe_fp_flags, sw_comp_cons);
+ fp->eth_q_stats.rx_err_discard_pkt++;
+ goto reuse_rx;
+ }
+
+ /* Since we don't have a jumbo ring
+ * copy small packets if mtu > 1500
+ */
+ if ((bp->dev->mtu > ETH_MAX_PACKET_SIZE) &&
+ (len <= RX_COPY_THRESH)) {
+ struct sk_buff *new_skb;
+
+ new_skb = netdev_alloc_skb(bp->dev,
+ len + pad);
+ if (new_skb == NULL) {
+ DP(NETIF_MSG_RX_ERR,
+ "ERROR packet dropped "
+ "because of alloc failure\n");
+ fp->eth_q_stats.rx_skb_alloc_failed++;
+ goto reuse_rx;
+ }
+
+ /* aligned copy */
+ skb_copy_from_linear_data_offset(skb, pad,
+ new_skb->data + pad, len);
+ skb_reserve(new_skb, pad);
+ skb_put(new_skb, len);
+
+ bnx2x_reuse_rx_skb(fp, skb, bd_cons, bd_prod);
+
+ skb = new_skb;
+
+ } else
+ if (likely(bnx2x_alloc_rx_skb(bp, fp, bd_prod) == 0)) {
+ dma_unmap_single(&bp->pdev->dev,
+ dma_unmap_addr(rx_buf, mapping),
+ bp->rx_buf_size,
+ DMA_FROM_DEVICE);
+ skb_reserve(skb, pad);
+ skb_put(skb, len);
+
+ } else {
+ DP(NETIF_MSG_RX_ERR,
+ "ERROR packet dropped because "
+ "of alloc failure\n");
+ fp->eth_q_stats.rx_skb_alloc_failed++;
+reuse_rx:
+ bnx2x_reuse_rx_skb(fp, skb, bd_cons, bd_prod);
+ goto next_rx;
+ }
+
+ skb->protocol = eth_type_trans(skb, bp->dev);
+
+ /* Set Toeplitz hash for a none-LRO skb */
+ bnx2x_set_skb_rxhash(bp, cqe, skb);
+
+ skb->ip_summed = CHECKSUM_NONE;
+ if (bp->rx_csum) {
+ if (likely(BNX2X_RX_CSUM_OK(cqe)))
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+ else
+ fp->eth_q_stats.hw_csum_err++;
+ }
+ }
+
+ skb_record_rx_queue(skb, fp->index);
+
+#ifdef BCM_VLAN
+ if ((bp->vlgrp != NULL) && (bp->flags & HW_VLAN_RX_FLAG) &&
+ (le16_to_cpu(cqe->fast_path_cqe.pars_flags.flags) &
+ PARSING_FLAGS_VLAN))
+ vlan_gro_receive(&fp->napi, bp->vlgrp,
+ le16_to_cpu(cqe->fast_path_cqe.vlan_tag), skb);
+ else
+#endif
+ napi_gro_receive(&fp->napi, skb);
+
+
+next_rx:
+ rx_buf->skb = NULL;
+
+ bd_cons = NEXT_RX_IDX(bd_cons);
+ bd_prod = NEXT_RX_IDX(bd_prod);
+ bd_prod_fw = NEXT_RX_IDX(bd_prod_fw);
+ rx_pkt++;
+next_cqe:
+ sw_comp_prod = NEXT_RCQ_IDX(sw_comp_prod);
+ sw_comp_cons = NEXT_RCQ_IDX(sw_comp_cons);
+
+ if (rx_pkt == budget)
+ break;
+ } /* while */
+
+ fp->rx_bd_cons = bd_cons;
+ fp->rx_bd_prod = bd_prod_fw;
+ fp->rx_comp_cons = sw_comp_cons;
+ fp->rx_comp_prod = sw_comp_prod;
+
+ /* Update producers */
+ bnx2x_update_rx_prod(bp, fp, bd_prod_fw, sw_comp_prod,
+ fp->rx_sge_prod);
+
+ fp->rx_pkt += rx_pkt;
+ fp->rx_calls++;
+
+ return rx_pkt;
+}
+
+static irqreturn_t bnx2x_msix_fp_int(int irq, void *fp_cookie)
+{
+ struct bnx2x_fastpath *fp = fp_cookie;
+ struct bnx2x *bp = fp->bp;
+
+ /* Return here if interrupt is disabled */
+ if (unlikely(atomic_read(&bp->intr_sem) != 0)) {
+ DP(NETIF_MSG_INTR, "called but intr_sem not 0, returning\n");
+ return IRQ_HANDLED;
+ }
+
+ DP(BNX2X_MSG_FP, "got an MSI-X interrupt on IDX:SB [%d:%d]\n",
+ fp->index, fp->sb_id);
+ bnx2x_ack_sb(bp, fp->sb_id, USTORM_ID, 0, IGU_INT_DISABLE, 0);
+
+#ifdef BNX2X_STOP_ON_ERROR
+ if (unlikely(bp->panic))
+ return IRQ_HANDLED;
+#endif
+
+ /* Handle Rx and Tx according to MSI-X vector */
+ prefetch(fp->rx_cons_sb);
+ prefetch(fp->tx_cons_sb);
+ prefetch(&fp->status_blk->u_status_block.status_block_index);
+ prefetch(&fp->status_blk->c_status_block.status_block_index);
+ napi_schedule(&bnx2x_fp(bp, fp->index, napi));
+
+ return IRQ_HANDLED;
+}
+
+
+/* HW Lock for shared dual port PHYs */
+void bnx2x_acquire_phy_lock(struct bnx2x *bp)
+{
+ mutex_lock(&bp->port.phy_mutex);
+
+ if (bp->port.need_hw_lock)
+ bnx2x_acquire_hw_lock(bp, HW_LOCK_RESOURCE_MDIO);
+}
+
+void bnx2x_release_phy_lock(struct bnx2x *bp)
+{
+ if (bp->port.need_hw_lock)
+ bnx2x_release_hw_lock(bp, HW_LOCK_RESOURCE_MDIO);
+
+ mutex_unlock(&bp->port.phy_mutex);
+}
+
+void bnx2x_link_report(struct bnx2x *bp)
+{
+ if (bp->flags & MF_FUNC_DIS) {
+ netif_carrier_off(bp->dev);
+ netdev_err(bp->dev, "NIC Link is Down\n");
+ return;
+ }
+
+ if (bp->link_vars.link_up) {
+ u16 line_speed;
+
+ if (bp->state == BNX2X_STATE_OPEN)
+ netif_carrier_on(bp->dev);
+ netdev_info(bp->dev, "NIC Link is Up, ");
+
+ line_speed = bp->link_vars.line_speed;
+ if (IS_E1HMF(bp)) {
+ u16 vn_max_rate;
+
+ vn_max_rate =
+ ((bp->mf_config & FUNC_MF_CFG_MAX_BW_MASK) >>
+ FUNC_MF_CFG_MAX_BW_SHIFT) * 100;
+ if (vn_max_rate < line_speed)
+ line_speed = vn_max_rate;
+ }
+ pr_cont("%d Mbps ", line_speed);
+
+ if (bp->link_vars.duplex == DUPLEX_FULL)
+ pr_cont("full duplex");
+ else
+ pr_cont("half duplex");
+
+ if (bp->link_vars.flow_ctrl != BNX2X_FLOW_CTRL_NONE) {
+ if (bp->link_vars.flow_ctrl & BNX2X_FLOW_CTRL_RX) {
+ pr_cont(", receive ");
+ if (bp->link_vars.flow_ctrl &
+ BNX2X_FLOW_CTRL_TX)
+ pr_cont("& transmit ");
+ } else {
+ pr_cont(", transmit ");
+ }
+ pr_cont("flow control ON");
+ }
+ pr_cont("\n");
+
+ } else { /* link_down */
+ netif_carrier_off(bp->dev);
+ netdev_err(bp->dev, "NIC Link is Down\n");
+ }
+}
+
+void bnx2x_init_rx_rings(struct bnx2x *bp)
+{
+ int func = BP_FUNC(bp);
+ int max_agg_queues = CHIP_IS_E1(bp) ? ETH_MAX_AGGREGATION_QUEUES_E1 :
+ ETH_MAX_AGGREGATION_QUEUES_E1H;
+ u16 ring_prod, cqe_ring_prod;
+ int i, j;
+
+ bp->rx_buf_size = bp->dev->mtu + ETH_OVREHEAD + BNX2X_RX_ALIGN;
+ DP(NETIF_MSG_IFUP,
+ "mtu %d rx_buf_size %d\n", bp->dev->mtu, bp->rx_buf_size);
+
+ if (bp->flags & TPA_ENABLE_FLAG) {
+
+ for_each_queue(bp, j) {
+ struct bnx2x_fastpath *fp = &bp->fp[j];
+
+ for (i = 0; i < max_agg_queues; i++) {
+ fp->tpa_pool[i].skb =
+ netdev_alloc_skb(bp->dev, bp->rx_buf_size);
+ if (!fp->tpa_pool[i].skb) {
+ BNX2X_ERR("Failed to allocate TPA "
+ "skb pool for queue[%d] - "
+ "disabling TPA on this "
+ "queue!\n", j);
+ bnx2x_free_tpa_pool(bp, fp, i);
+ fp->disable_tpa = 1;
+ break;
+ }
+ dma_unmap_addr_set((struct sw_rx_bd *)
+ &bp->fp->tpa_pool[i],
+ mapping, 0);
+ fp->tpa_state[i] = BNX2X_TPA_STOP;
+ }
+ }
+ }
+
+ for_each_queue(bp, j) {
+ struct bnx2x_fastpath *fp = &bp->fp[j];
+
+ fp->rx_bd_cons = 0;
+ fp->rx_cons_sb = BNX2X_RX_SB_INDEX;
+ fp->rx_bd_cons_sb = BNX2X_RX_SB_BD_INDEX;
+
+ /* "next page" elements initialization */
+ /* SGE ring */
+ for (i = 1; i <= NUM_RX_SGE_PAGES; i++) {
+ struct eth_rx_sge *sge;
+
+ sge = &fp->rx_sge_ring[RX_SGE_CNT * i - 2];
+ sge->addr_hi =
+ cpu_to_le32(U64_HI(fp->rx_sge_mapping +
+ BCM_PAGE_SIZE*(i % NUM_RX_SGE_PAGES)));
+ sge->addr_lo =
+ cpu_to_le32(U64_LO(fp->rx_sge_mapping +
+ BCM_PAGE_SIZE*(i % NUM_RX_SGE_PAGES)));
+ }
+
+ bnx2x_init_sge_ring_bit_mask(fp);
+
+ /* RX BD ring */
+ for (i = 1; i <= NUM_RX_RINGS; i++) {
+ struct eth_rx_bd *rx_bd;
+
+ rx_bd = &fp->rx_desc_ring[RX_DESC_CNT * i - 2];
+ rx_bd->addr_hi =
+ cpu_to_le32(U64_HI(fp->rx_desc_mapping +
+ BCM_PAGE_SIZE*(i % NUM_RX_RINGS)));
+ rx_bd->addr_lo =
+ cpu_to_le32(U64_LO(fp->rx_desc_mapping +
+ BCM_PAGE_SIZE*(i % NUM_RX_RINGS)));
+ }
+
+ /* CQ ring */
+ for (i = 1; i <= NUM_RCQ_RINGS; i++) {
+ struct eth_rx_cqe_next_page *nextpg;
+
+ nextpg = (struct eth_rx_cqe_next_page *)
+ &fp->rx_comp_ring[RCQ_DESC_CNT * i - 1];
+ nextpg->addr_hi =
+ cpu_to_le32(U64_HI(fp->rx_comp_mapping +
+ BCM_PAGE_SIZE*(i % NUM_RCQ_RINGS)));
+ nextpg->addr_lo =
+ cpu_to_le32(U64_LO(fp->rx_comp_mapping +
+ BCM_PAGE_SIZE*(i % NUM_RCQ_RINGS)));
+ }
+
+ /* Allocate SGEs and initialize the ring elements */
+ for (i = 0, ring_prod = 0;
+ i < MAX_RX_SGE_CNT*NUM_RX_SGE_PAGES; i++) {
+
+ if (bnx2x_alloc_rx_sge(bp, fp, ring_prod) < 0) {
+ BNX2X_ERR("was only able to allocate "
+ "%d rx sges\n", i);
+ BNX2X_ERR("disabling TPA for queue[%d]\n", j);
+ /* Cleanup already allocated elements */
+ bnx2x_free_rx_sge_range(bp, fp, ring_prod);
+ bnx2x_free_tpa_pool(bp, fp, max_agg_queues);
+ fp->disable_tpa = 1;
+ ring_prod = 0;
+ break;
+ }
+ ring_prod = NEXT_SGE_IDX(ring_prod);
+ }
+ fp->rx_sge_prod = ring_prod;
+
+ /* Allocate BDs and initialize BD ring */
+ fp->rx_comp_cons = 0;
+ cqe_ring_prod = ring_prod = 0;
+ for (i = 0; i < bp->rx_ring_size; i++) {
+ if (bnx2x_alloc_rx_skb(bp, fp, ring_prod) < 0) {
+ BNX2X_ERR("was only able to allocate "
+ "%d rx skbs on queue[%d]\n", i, j);
+ fp->eth_q_stats.rx_skb_alloc_failed++;
+ break;
+ }
+ ring_prod = NEXT_RX_IDX(ring_prod);
+ cqe_ring_prod = NEXT_RCQ_IDX(cqe_ring_prod);
+ WARN_ON(ring_prod <= i);
+ }
+
+ fp->rx_bd_prod = ring_prod;
+ /* must not have more available CQEs than BDs */
+ fp->rx_comp_prod = min_t(u16, NUM_RCQ_RINGS*RCQ_DESC_CNT,
+ cqe_ring_prod);
+ fp->rx_pkt = fp->rx_calls = 0;
+
+ /* Warning!
+ * this will generate an interrupt (to the TSTORM)
+ * must only be done after chip is initialized
+ */
+ bnx2x_update_rx_prod(bp, fp, ring_prod, fp->rx_comp_prod,
+ fp->rx_sge_prod);
+ if (j != 0)
+ continue;
+
+ REG_WR(bp, BAR_USTRORM_INTMEM +
+ USTORM_MEM_WORKAROUND_ADDRESS_OFFSET(func),
+ U64_LO(fp->rx_comp_mapping));
+ REG_WR(bp, BAR_USTRORM_INTMEM +
+ USTORM_MEM_WORKAROUND_ADDRESS_OFFSET(func) + 4,
+ U64_HI(fp->rx_comp_mapping));
+ }
+}
+static void bnx2x_free_tx_skbs(struct bnx2x *bp)
+{
+ int i;
+
+ for_each_queue(bp, i) {
+ struct bnx2x_fastpath *fp = &bp->fp[i];
+
+ u16 bd_cons = fp->tx_bd_cons;
+ u16 sw_prod = fp->tx_pkt_prod;
+ u16 sw_cons = fp->tx_pkt_cons;
+
+ while (sw_cons != sw_prod) {
+ bd_cons = bnx2x_free_tx_pkt(bp, fp, TX_BD(sw_cons));
+ sw_cons++;
+ }
+ }
+}
+
+static void bnx2x_free_rx_skbs(struct bnx2x *bp)
+{
+ int i, j;
+
+ for_each_queue(bp, j) {
+ struct bnx2x_fastpath *fp = &bp->fp[j];
+
+ for (i = 0; i < NUM_RX_BD; i++) {
+ struct sw_rx_bd *rx_buf = &fp->rx_buf_ring[i];
+ struct sk_buff *skb = rx_buf->skb;
+
+ if (skb == NULL)
+ continue;
+
+ dma_unmap_single(&bp->pdev->dev,
+ dma_unmap_addr(rx_buf, mapping),
+ bp->rx_buf_size, DMA_FROM_DEVICE);
+
+ rx_buf->skb = NULL;
+ dev_kfree_skb(skb);
+ }
+ if (!fp->disable_tpa)
+ bnx2x_free_tpa_pool(bp, fp, CHIP_IS_E1(bp) ?
+ ETH_MAX_AGGREGATION_QUEUES_E1 :
+ ETH_MAX_AGGREGATION_QUEUES_E1H);
+ }
+}
+
+void bnx2x_free_skbs(struct bnx2x *bp)
+{
+ bnx2x_free_tx_skbs(bp);
+ bnx2x_free_rx_skbs(bp);
+}
+
+static void bnx2x_free_msix_irqs(struct bnx2x *bp)
+{
+ int i, offset = 1;
+
+ free_irq(bp->msix_table[0].vector, bp->dev);
+ DP(NETIF_MSG_IFDOWN, "released sp irq (%d)\n",
+ bp->msix_table[0].vector);
+
+#ifdef BCM_CNIC
+ offset++;
+#endif
+ for_each_queue(bp, i) {
+ DP(NETIF_MSG_IFDOWN, "about to release fp #%d->%d irq "
+ "state %x\n", i, bp->msix_table[i + offset].vector,
+ bnx2x_fp(bp, i, state));
+
+ free_irq(bp->msix_table[i + offset].vector, &bp->fp[i]);
+ }
+}
+
+void bnx2x_free_irq(struct bnx2x *bp, bool disable_only)
+{
+ if (bp->flags & USING_MSIX_FLAG) {
+ if (!disable_only)
+ bnx2x_free_msix_irqs(bp);
+ pci_disable_msix(bp->pdev);
+ bp->flags &= ~USING_MSIX_FLAG;
+
+ } else if (bp->flags & USING_MSI_FLAG) {
+ if (!disable_only)
+ free_irq(bp->pdev->irq, bp->dev);
+ pci_disable_msi(bp->pdev);
+ bp->flags &= ~USING_MSI_FLAG;
+
+ } else if (!disable_only)
+ free_irq(bp->pdev->irq, bp->dev);
+}
+
+static int bnx2x_enable_msix(struct bnx2x *bp)
+{
+ int i, rc, offset = 1;
+ int igu_vec = 0;
+
+ bp->msix_table[0].entry = igu_vec;
+ DP(NETIF_MSG_IFUP, "msix_table[0].entry = %d (slowpath)\n", igu_vec);
+
+#ifdef BCM_CNIC
+ igu_vec = BP_L_ID(bp) + offset;
+ bp->msix_table[1].entry = igu_vec;
+ DP(NETIF_MSG_IFUP, "msix_table[1].entry = %d (CNIC)\n", igu_vec);
+ offset++;
+#endif
+ for_each_queue(bp, i) {
+ igu_vec = BP_L_ID(bp) + offset + i;
+ bp->msix_table[i + offset].entry = igu_vec;
+ DP(NETIF_MSG_IFUP, "msix_table[%d].entry = %d "
+ "(fastpath #%u)\n", i + offset, igu_vec, i);
+ }
+
+ rc = pci_enable_msix(bp->pdev, &bp->msix_table[0],
+ BNX2X_NUM_QUEUES(bp) + offset);
+
+ /*
+ * reconfigure number of tx/rx queues according to available
+ * MSI-X vectors
+ */
+ if (rc >= BNX2X_MIN_MSIX_VEC_CNT) {
+ /* vectors available for FP */
+ int fp_vec = rc - BNX2X_MSIX_VEC_FP_START;
+
+ DP(NETIF_MSG_IFUP,
+ "Trying to use less MSI-X vectors: %d\n", rc);
+
+ rc = pci_enable_msix(bp->pdev, &bp->msix_table[0], rc);
+
+ if (rc) {
+ DP(NETIF_MSG_IFUP,
+ "MSI-X is not attainable rc %d\n", rc);
+ return rc;
+ }
+
+ bp->num_queues = min(bp->num_queues, fp_vec);
+
+ DP(NETIF_MSG_IFUP, "New queue configuration set: %d\n",
+ bp->num_queues);
+ } else if (rc) {
+ DP(NETIF_MSG_IFUP, "MSI-X is not attainable rc %d\n", rc);
+ return rc;
+ }
+
+ bp->flags |= USING_MSIX_FLAG;
+
+ return 0;
+}
+
+static int bnx2x_req_msix_irqs(struct bnx2x *bp)
+{
+ int i, rc, offset = 1;
+
+ rc = request_irq(bp->msix_table[0].vector, bnx2x_msix_sp_int, 0,
+ bp->dev->name, bp->dev);
+ if (rc) {
+ BNX2X_ERR("request sp irq failed\n");
+ return -EBUSY;
+ }
+
+#ifdef BCM_CNIC
+ offset++;
+#endif
+ for_each_queue(bp, i) {
+ struct bnx2x_fastpath *fp = &bp->fp[i];
+ snprintf(fp->name, sizeof(fp->name), "%s-fp-%d",
+ bp->dev->name, i);
+
+ rc = request_irq(bp->msix_table[i + offset].vector,
+ bnx2x_msix_fp_int, 0, fp->name, fp);
+ if (rc) {
+ BNX2X_ERR("request fp #%d irq failed rc %d\n", i, rc);
+ bnx2x_free_msix_irqs(bp);
+ return -EBUSY;
+ }
+
+ fp->state = BNX2X_FP_STATE_IRQ;
+ }
+
+ i = BNX2X_NUM_QUEUES(bp);
+ netdev_info(bp->dev, "using MSI-X IRQs: sp %d fp[%d] %d"
+ " ... fp[%d] %d\n",
+ bp->msix_table[0].vector,
+ 0, bp->msix_table[offset].vector,
+ i - 1, bp->msix_table[offset + i - 1].vector);
+
+ return 0;
+}
+
+static int bnx2x_enable_msi(struct bnx2x *bp)
+{
+ int rc;
+
+ rc = pci_enable_msi(bp->pdev);
+ if (rc) {
+ DP(NETIF_MSG_IFUP, "MSI is not attainable\n");
+ return -1;
+ }
+ bp->flags |= USING_MSI_FLAG;
+
+ return 0;
+}
+
+static int bnx2x_req_irq(struct bnx2x *bp)
+{
+ unsigned long flags;
+ int rc;
+
+ if (bp->flags & USING_MSI_FLAG)
+ flags = 0;
+ else
+ flags = IRQF_SHARED;
+
+ rc = request_irq(bp->pdev->irq, bnx2x_interrupt, flags,
+ bp->dev->name, bp->dev);
+ if (!rc)
+ bnx2x_fp(bp, 0, state) = BNX2X_FP_STATE_IRQ;
+
+ return rc;
+}
+
+static void bnx2x_napi_enable(struct bnx2x *bp)
+{
+ int i;
+
+ for_each_queue(bp, i)
+ napi_enable(&bnx2x_fp(bp, i, napi));
+}
+
+static void bnx2x_napi_disable(struct bnx2x *bp)
+{
+ int i;
+
+ for_each_queue(bp, i)
+ napi_disable(&bnx2x_fp(bp, i, napi));
+}
+
+void bnx2x_netif_start(struct bnx2x *bp)
+{
+ int intr_sem;
+
+ intr_sem = atomic_dec_and_test(&bp->intr_sem);
+ smp_wmb(); /* Ensure that bp->intr_sem update is SMP-safe */
+
+ if (intr_sem) {
+ if (netif_running(bp->dev)) {
+ bnx2x_napi_enable(bp);
+ bnx2x_int_enable(bp);
+ if (bp->state == BNX2X_STATE_OPEN)
+ netif_tx_wake_all_queues(bp->dev);
+ }
+ }
+}
+
+void bnx2x_netif_stop(struct bnx2x *bp, int disable_hw)
+{
+ bnx2x_int_disable_sync(bp, disable_hw);
+ bnx2x_napi_disable(bp);
+ netif_tx_disable(bp->dev);
+}
+static int bnx2x_set_num_queues(struct bnx2x *bp)
+{
+ int rc = 0;
+
+ switch (bp->int_mode) {
+ case INT_MODE_INTx:
+ case INT_MODE_MSI:
+ bp->num_queues = 1;
+ DP(NETIF_MSG_IFUP, "set number of queues to 1\n");
+ break;
+ default:
+ /* Set number of queues according to bp->multi_mode value */
+ bnx2x_set_num_queues_msix(bp);
+
+ DP(NETIF_MSG_IFUP, "set number of queues to %d\n",
+ bp->num_queues);
+
+ /* if we can't use MSI-X we only need one fp,
+ * so try to enable MSI-X with the requested number of fp's
+ * and fallback to MSI or legacy INTx with one fp
+ */
+ rc = bnx2x_enable_msix(bp);
+ if (rc)
+ /* failed to enable MSI-X */
+ bp->num_queues = 1;
+ break;
+ }
+ bp->dev->real_num_tx_queues = bp->num_queues;
+ return rc;
+}
+
+/* must be called with rtnl_lock */
+int bnx2x_nic_load(struct bnx2x *bp, int load_mode)
+{
+ u32 load_code;
+ int i, rc;
+
+#ifdef BNX2X_STOP_ON_ERROR
+ if (unlikely(bp->panic))
+ return -EPERM;
+#endif
+
+ bp->state = BNX2X_STATE_OPENING_WAIT4_LOAD;
+
+ rc = bnx2x_set_num_queues(bp);
+
+ if (bnx2x_alloc_mem(bp)) {
+ bnx2x_free_irq(bp, true);
+ return -ENOMEM;
+ }
+
+ for_each_queue(bp, i)
+ bnx2x_fp(bp, i, disable_tpa) =
+ ((bp->flags & TPA_ENABLE_FLAG) == 0);
+
+ for_each_queue(bp, i)
+ netif_napi_add(bp->dev, &bnx2x_fp(bp, i, napi),
+ bnx2x_poll, 128);
+
+ bnx2x_napi_enable(bp);
+
+ if (bp->flags & USING_MSIX_FLAG) {
+ rc = bnx2x_req_msix_irqs(bp);
+ if (rc) {
+ bnx2x_free_irq(bp, true);
+ goto load_error1;
+ }
+ } else {
+ /* Fall to INTx if failed to enable MSI-X due to lack of
+ memory (in bnx2x_set_num_queues()) */
+ if ((rc != -ENOMEM) && (bp->int_mode != INT_MODE_INTx))
+ bnx2x_enable_msi(bp);
+ bnx2x_ack_int(bp);
+ rc = bnx2x_req_irq(bp);
+ if (rc) {
+ BNX2X_ERR("IRQ request failed rc %d, aborting\n", rc);
+ bnx2x_free_irq(bp, true);
+ goto load_error1;
+ }
+ if (bp->flags & USING_MSI_FLAG) {
+ bp->dev->irq = bp->pdev->irq;
+ netdev_info(bp->dev, "using MSI IRQ %d\n",
+ bp->pdev->irq);
+ }
+ }
+
+ /* Send LOAD_REQUEST command to MCP
+ Returns the type of LOAD command:
+ if it is the first port to be initialized
+ common blocks should be initialized, otherwise - not
+ */
+ if (!BP_NOMCP(bp)) {
+ load_code = bnx2x_fw_command(bp, DRV_MSG_CODE_LOAD_REQ);
+ if (!load_code) {
+ BNX2X_ERR("MCP response failure, aborting\n");
+ rc = -EBUSY;
+ goto load_error2;
+ }
+ if (load_code == FW_MSG_CODE_DRV_LOAD_REFUSED) {
+ rc = -EBUSY; /* other port in diagnostic mode */
+ goto load_error2;
+ }
+
+ } else {
+ int port = BP_PORT(bp);
+
+ DP(NETIF_MSG_IFUP, "NO MCP - load counts %d, %d, %d\n",
+ load_count[0], load_count[1], load_count[2]);
+ load_count[0]++;
+ load_count[1 + port]++;
+ DP(NETIF_MSG_IFUP, "NO MCP - new load counts %d, %d, %d\n",
+ load_count[0], load_count[1], load_count[2]);
+ if (load_count[0] == 1)
+ load_code = FW_MSG_CODE_DRV_LOAD_COMMON;
+ else if (load_count[1 + port] == 1)
+ load_code = FW_MSG_CODE_DRV_LOAD_PORT;
+ else
+ load_code = FW_MSG_CODE_DRV_LOAD_FUNCTION;
+ }
+
+ if ((load_code == FW_MSG_CODE_DRV_LOAD_COMMON) ||
+ (load_code == FW_MSG_CODE_DRV_LOAD_PORT))
+ bp->port.pmf = 1;
+ else
+ bp->port.pmf = 0;
+ DP(NETIF_MSG_LINK, "pmf %d\n", bp->port.pmf);
+
+ /* Initialize HW */
+ rc = bnx2x_init_hw(bp, load_code);
+ if (rc) {
+ BNX2X_ERR("HW init failed, aborting\n");
+ bnx2x_fw_command(bp, DRV_MSG_CODE_LOAD_DONE);
+ bnx2x_fw_command(bp, DRV_MSG_CODE_UNLOAD_REQ_WOL_MCP);
+ bnx2x_fw_command(bp, DRV_MSG_CODE_UNLOAD_DONE);
+ goto load_error2;
+ }
+
+ /* Setup NIC internals and enable interrupts */
+ bnx2x_nic_init(bp, load_code);
+
+ if ((load_code == FW_MSG_CODE_DRV_LOAD_COMMON) &&
+ (bp->common.shmem2_base))
+ SHMEM2_WR(bp, dcc_support,
+ (SHMEM_DCC_SUPPORT_DISABLE_ENABLE_PF_TLV |
+ SHMEM_DCC_SUPPORT_BANDWIDTH_ALLOCATION_TLV));
+
+ /* Send LOAD_DONE command to MCP */
+ if (!BP_NOMCP(bp)) {
+ load_code = bnx2x_fw_command(bp, DRV_MSG_CODE_LOAD_DONE);
+ if (!load_code) {
+ BNX2X_ERR("MCP response failure, aborting\n");
+ rc = -EBUSY;
+ goto load_error3;
+ }
+ }
+
+ bp->state = BNX2X_STATE_OPENING_WAIT4_PORT;
+
+ rc = bnx2x_setup_leading(bp);
+ if (rc) {
+ BNX2X_ERR("Setup leading failed!\n");
+#ifndef BNX2X_STOP_ON_ERROR
+ goto load_error3;
+#else
+ bp->panic = 1;
+ return -EBUSY;
+#endif
+ }
+
+ if (CHIP_IS_E1H(bp))
+ if (bp->mf_config & FUNC_MF_CFG_FUNC_DISABLED) {
+ DP(NETIF_MSG_IFUP, "mf_cfg function disabled\n");
+ bp->flags |= MF_FUNC_DIS;
+ }
+
+ if (bp->state == BNX2X_STATE_OPEN) {
+#ifdef BCM_CNIC
+ /* Enable Timer scan */
+ REG_WR(bp, TM_REG_EN_LINEAR0_TIMER + BP_PORT(bp)*4, 1);
+#endif
+ for_each_nondefault_queue(bp, i) {
+ rc = bnx2x_setup_multi(bp, i);
+ if (rc)
+#ifdef BCM_CNIC
+ goto load_error4;
+#else
+ goto load_error3;
+#endif
+ }
+
+ if (CHIP_IS_E1(bp))
+ bnx2x_set_eth_mac_addr_e1(bp, 1);
+ else
+ bnx2x_set_eth_mac_addr_e1h(bp, 1);
+#ifdef BCM_CNIC
+ /* Set iSCSI L2 MAC */
+ mutex_lock(&bp->cnic_mutex);
+ if (bp->cnic_eth_dev.drv_state & CNIC_DRV_STATE_REGD) {
+ bnx2x_set_iscsi_eth_mac_addr(bp, 1);
+ bp->cnic_flags |= BNX2X_CNIC_FLAG_MAC_SET;
+ bnx2x_init_sb(bp, bp->cnic_sb, bp->cnic_sb_mapping,
+ CNIC_SB_ID(bp));
+ }
+ mutex_unlock(&bp->cnic_mutex);
+#endif
+ }
+
+ if (bp->port.pmf)
+ bnx2x_initial_phy_init(bp, load_mode);
+
+ /* Start fast path */
+ switch (load_mode) {
+ case LOAD_NORMAL:
+ if (bp->state == BNX2X_STATE_OPEN) {
+ /* Tx queue should be only reenabled */
+ netif_tx_wake_all_queues(bp->dev);
+ }
+ /* Initialize the receive filter. */
+ bnx2x_set_rx_mode(bp->dev);
+ break;
+
+ case LOAD_OPEN:
+ netif_tx_start_all_queues(bp->dev);
+ if (bp->state != BNX2X_STATE_OPEN)
+ netif_tx_disable(bp->dev);
+ /* Initialize the receive filter. */
+ bnx2x_set_rx_mode(bp->dev);
+ break;
+
+ case LOAD_DIAG:
+ /* Initialize the receive filter. */
+ bnx2x_set_rx_mode(bp->dev);
+ bp->state = BNX2X_STATE_DIAG;
+ break;
+
+ default:
+ break;
+ }
+
+ if (!bp->port.pmf)
+ bnx2x__link_status_update(bp);
+
+ /* start the timer */
+ mod_timer(&bp->timer, jiffies + bp->current_interval);
+
+#ifdef BCM_CNIC
+ bnx2x_setup_cnic_irq_info(bp);
+ if (bp->state == BNX2X_STATE_OPEN)
+ bnx2x_cnic_notify(bp, CNIC_CTL_START_CMD);
+#endif
+ bnx2x_inc_load_cnt(bp);
+
+ return 0;
+
+#ifdef BCM_CNIC
+load_error4:
+ /* Disable Timer scan */
+ REG_WR(bp, TM_REG_EN_LINEAR0_TIMER + BP_PORT(bp)*4, 0);
+#endif
+load_error3:
+ bnx2x_int_disable_sync(bp, 1);
+ if (!BP_NOMCP(bp)) {
+ bnx2x_fw_command(bp, DRV_MSG_CODE_UNLOAD_REQ_WOL_MCP);
+ bnx2x_fw_command(bp, DRV_MSG_CODE_UNLOAD_DONE);
+ }
+ bp->port.pmf = 0;
+ /* Free SKBs, SGEs, TPA pool and driver internals */
+ bnx2x_free_skbs(bp);
+ for_each_queue(bp, i)
+ bnx2x_free_rx_sge_range(bp, bp->fp + i, NUM_RX_SGE);
+load_error2:
+ /* Release IRQs */
+ bnx2x_free_irq(bp, false);
+load_error1:
+ bnx2x_napi_disable(bp);
+ for_each_queue(bp, i)
+ netif_napi_del(&bnx2x_fp(bp, i, napi));
+ bnx2x_free_mem(bp);
+
+ return rc;
+}
+
+/* must be called with rtnl_lock */
+int bnx2x_nic_unload(struct bnx2x *bp, int unload_mode)
+{
+ int i;
+
+ if (bp->state == BNX2X_STATE_CLOSED) {
+ /* Interface has been removed - nothing to recover */
+ bp->recovery_state = BNX2X_RECOVERY_DONE;
+ bp->is_leader = 0;
+ bnx2x_release_hw_lock(bp, HW_LOCK_RESOURCE_RESERVED_08);
+ smp_wmb();
+
+ return -EINVAL;
+ }
+
+#ifdef BCM_CNIC
+ bnx2x_cnic_notify(bp, CNIC_CTL_STOP_CMD);
+#endif
+ bp->state = BNX2X_STATE_CLOSING_WAIT4_HALT;
+
+ /* Set "drop all" */
+ bp->rx_mode = BNX2X_RX_MODE_NONE;
+ bnx2x_set_storm_rx_mode(bp);
+
+ /* Disable HW interrupts, NAPI and Tx */
+ bnx2x_netif_stop(bp, 1);
+ netif_carrier_off(bp->dev);
+
+ del_timer_sync(&bp->timer);
+ SHMEM_WR(bp, func_mb[BP_FUNC(bp)].drv_pulse_mb,
+ (DRV_PULSE_ALWAYS_ALIVE | bp->fw_drv_pulse_wr_seq));
+ bnx2x_stats_handle(bp, STATS_EVENT_STOP);
+
+ /* Release IRQs */
+ bnx2x_free_irq(bp, false);
+
+ /* Cleanup the chip if needed */
+ if (unload_mode != UNLOAD_RECOVERY)
+ bnx2x_chip_cleanup(bp, unload_mode);
+
+ bp->port.pmf = 0;
+
+ /* Free SKBs, SGEs, TPA pool and driver internals */
+ bnx2x_free_skbs(bp);
+ for_each_queue(bp, i)
+ bnx2x_free_rx_sge_range(bp, bp->fp + i, NUM_RX_SGE);
+ for_each_queue(bp, i)
+ netif_napi_del(&bnx2x_fp(bp, i, napi));
+ bnx2x_free_mem(bp);
+
+ bp->state = BNX2X_STATE_CLOSED;
+
+ /* The last driver must disable a "close the gate" if there is no
+ * parity attention or "process kill" pending.
+ */
+ if ((!bnx2x_dec_load_cnt(bp)) && (!bnx2x_chk_parity_attn(bp)) &&
+ bnx2x_reset_is_done(bp))
+ bnx2x_disable_close_the_gate(bp);
+
+ /* Reset MCP mail box sequence if there is on going recovery */
+ if (unload_mode == UNLOAD_RECOVERY)
+ bp->fw_seq = 0;
+
+ return 0;
+}
+int bnx2x_set_power_state(struct bnx2x *bp, pci_power_t state)
+{
+ u16 pmcsr;
+
+ pci_read_config_word(bp->pdev, bp->pm_cap + PCI_PM_CTRL, &pmcsr);
+
+ switch (state) {
+ case PCI_D0:
+ pci_write_config_word(bp->pdev, bp->pm_cap + PCI_PM_CTRL,
+ ((pmcsr & ~PCI_PM_CTRL_STATE_MASK) |
+ PCI_PM_CTRL_PME_STATUS));
+
+ if (pmcsr & PCI_PM_CTRL_STATE_MASK)
+ /* delay required during transition out of D3hot */
+ msleep(20);
+ break;
+
+ case PCI_D3hot:
+ /* If there are other clients above don't
+ shut down the power */
+ if (atomic_read(&bp->pdev->enable_cnt) != 1)
+ return 0;
+ /* Don't shut down the power for emulation and FPGA */
+ if (CHIP_REV_IS_SLOW(bp))
+ return 0;
+
+ pmcsr &= ~PCI_PM_CTRL_STATE_MASK;
+ pmcsr |= 3;
+
+ if (bp->wol)
+ pmcsr |= PCI_PM_CTRL_PME_ENABLE;
+
+ pci_write_config_word(bp->pdev, bp->pm_cap + PCI_PM_CTRL,
+ pmcsr);
+
+ /* No more memory access after this point until
+ * device is brought back to D0.
+ */
+ break;
+
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+
+
+/*
+ * net_device service functions
+ */
+
+static int bnx2x_poll(struct napi_struct *napi, int budget)
+{
+ int work_done = 0;
+ struct bnx2x_fastpath *fp = container_of(napi, struct bnx2x_fastpath,
+ napi);
+ struct bnx2x *bp = fp->bp;
+
+ while (1) {
+#ifdef BNX2X_STOP_ON_ERROR
+ if (unlikely(bp->panic)) {
+ napi_complete(napi);
+ return 0;
+ }
+#endif
+
+ if (bnx2x_has_tx_work(fp))
+ bnx2x_tx_int(fp);
+
+ if (bnx2x_has_rx_work(fp)) {
+ work_done += bnx2x_rx_int(fp, budget - work_done);
+
+ /* must not complete if we consumed full budget */
+ if (work_done >= budget)
+ break;
+ }
+
+ /* Fall out from the NAPI loop if needed */
+ if (!(bnx2x_has_rx_work(fp) || bnx2x_has_tx_work(fp))) {
+ bnx2x_update_fpsb_idx(fp);
+ /* bnx2x_has_rx_work() reads the status block, thus we need
+ * to ensure that status block indices have been actually read
+ * (bnx2x_update_fpsb_idx) prior to this check
+ * (bnx2x_has_rx_work) so that we won't write the "newer"
+ * value of the status block to IGU (if there was a DMA right
+ * after bnx2x_has_rx_work and if there is no rmb, the memory
+ * reading (bnx2x_update_fpsb_idx) may be postponed to right
+ * before bnx2x_ack_sb). In this case there will never be
+ * another interrupt until there is another update of the
+ * status block, while there is still unhandled work.
+ */
+ rmb();
+
+ if (!(bnx2x_has_rx_work(fp) || bnx2x_has_tx_work(fp))) {
+ napi_complete(napi);
+ /* Re-enable interrupts */
+ bnx2x_ack_sb(bp, fp->sb_id, CSTORM_ID,
+ le16_to_cpu(fp->fp_c_idx),
+ IGU_INT_NOP, 1);
+ bnx2x_ack_sb(bp, fp->sb_id, USTORM_ID,
+ le16_to_cpu(fp->fp_u_idx),
+ IGU_INT_ENABLE, 1);
+ break;
+ }
+ }
+ }
+
+ return work_done;
+}
+
+
+/* we split the first BD into headers and data BDs
+ * to ease the pain of our fellow microcode engineers
+ * we use one mapping for both BDs
+ * So far this has only been observed to happen
+ * in Other Operating Systems(TM)
+ */
+static noinline u16 bnx2x_tx_split(struct bnx2x *bp,
+ struct bnx2x_fastpath *fp,
+ struct sw_tx_bd *tx_buf,
+ struct eth_tx_start_bd **tx_bd, u16 hlen,
+ u16 bd_prod, int nbd)
+{
+ struct eth_tx_start_bd *h_tx_bd = *tx_bd;
+ struct eth_tx_bd *d_tx_bd;
+ dma_addr_t mapping;
+ int old_len = le16_to_cpu(h_tx_bd->nbytes);
+
+ /* first fix first BD */
+ h_tx_bd->nbd = cpu_to_le16(nbd);
+ h_tx_bd->nbytes = cpu_to_le16(hlen);
+
+ DP(NETIF_MSG_TX_QUEUED, "TSO split header size is %d "
+ "(%x:%x) nbd %d\n", h_tx_bd->nbytes, h_tx_bd->addr_hi,
+ h_tx_bd->addr_lo, h_tx_bd->nbd);
+
+ /* now get a new data BD
+ * (after the pbd) and fill it */
+ bd_prod = TX_BD(NEXT_TX_IDX(bd_prod));
+ d_tx_bd = &fp->tx_desc_ring[bd_prod].reg_bd;
+
+ mapping = HILO_U64(le32_to_cpu(h_tx_bd->addr_hi),
+ le32_to_cpu(h_tx_bd->addr_lo)) + hlen;
+
+ d_tx_bd->addr_hi = cpu_to_le32(U64_HI(mapping));
+ d_tx_bd->addr_lo = cpu_to_le32(U64_LO(mapping));
+ d_tx_bd->nbytes = cpu_to_le16(old_len - hlen);
+
+ /* this marks the BD as one that has no individual mapping */
+ tx_buf->flags |= BNX2X_TSO_SPLIT_BD;
+
+ DP(NETIF_MSG_TX_QUEUED,
+ "TSO split data size is %d (%x:%x)\n",
+ d_tx_bd->nbytes, d_tx_bd->addr_hi, d_tx_bd->addr_lo);
+
+ /* update tx_bd */
+ *tx_bd = (struct eth_tx_start_bd *)d_tx_bd;
+
+ return bd_prod;
+}
+
+static inline u16 bnx2x_csum_fix(unsigned char *t_header, u16 csum, s8 fix)
+{
+ if (fix > 0)
+ csum = (u16) ~csum_fold(csum_sub(csum,
+ csum_partial(t_header - fix, fix, 0)));
+
+ else if (fix < 0)
+ csum = (u16) ~csum_fold(csum_add(csum,
+ csum_partial(t_header, -fix, 0)));
+
+ return swab16(csum);
+}
+
+static inline u32 bnx2x_xmit_type(struct bnx2x *bp, struct sk_buff *skb)
+{
+ u32 rc;
+
+ if (skb->ip_summed != CHECKSUM_PARTIAL)
+ rc = XMIT_PLAIN;
+
+ else {
+ if (skb->protocol == htons(ETH_P_IPV6)) {
+ rc = XMIT_CSUM_V6;
+ if (ipv6_hdr(skb)->nexthdr == IPPROTO_TCP)
+ rc |= XMIT_CSUM_TCP;
+
+ } else {
+ rc = XMIT_CSUM_V4;
+ if (ip_hdr(skb)->protocol == IPPROTO_TCP)
+ rc |= XMIT_CSUM_TCP;
+ }
+ }
+
+ if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV4)
+ rc |= (XMIT_GSO_V4 | XMIT_CSUM_V4 | XMIT_CSUM_TCP);
+
+ else if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV6)
+ rc |= (XMIT_GSO_V6 | XMIT_CSUM_TCP | XMIT_CSUM_V6);
+
+ return rc;
+}
+
+#if (MAX_SKB_FRAGS >= MAX_FETCH_BD - 3)
+/* check if packet requires linearization (packet is too fragmented)
+ no need to check fragmentation if page size > 8K (there will be no
+ violation to FW restrictions) */
+static int bnx2x_pkt_req_lin(struct bnx2x *bp, struct sk_buff *skb,
+ u32 xmit_type)
+{
+ int to_copy = 0;
+ int hlen = 0;
+ int first_bd_sz = 0;
+
+ /* 3 = 1 (for linear data BD) + 2 (for PBD and last BD) */
+ if (skb_shinfo(skb)->nr_frags >= (MAX_FETCH_BD - 3)) {
+
+ if (xmit_type & XMIT_GSO) {
+ unsigned short lso_mss = skb_shinfo(skb)->gso_size;
+ /* Check if LSO packet needs to be copied:
+ 3 = 1 (for headers BD) + 2 (for PBD and last BD) */
+ int wnd_size = MAX_FETCH_BD - 3;
+ /* Number of windows to check */
+ int num_wnds = skb_shinfo(skb)->nr_frags - wnd_size;
+ int wnd_idx = 0;
+ int frag_idx = 0;
+ u32 wnd_sum = 0;
+
+ /* Headers length */
+ hlen = (int)(skb_transport_header(skb) - skb->data) +
+ tcp_hdrlen(skb);
+
+ /* Amount of data (w/o headers) on linear part of SKB*/
+ first_bd_sz = skb_headlen(skb) - hlen;
+
+ wnd_sum = first_bd_sz;
+
+ /* Calculate the first sum - it's special */
+ for (frag_idx = 0; frag_idx < wnd_size - 1; frag_idx++)
+ wnd_sum +=
+ skb_shinfo(skb)->frags[frag_idx].size;
+
+ /* If there was data on linear skb data - check it */
+ if (first_bd_sz > 0) {
+ if (unlikely(wnd_sum < lso_mss)) {
+ to_copy = 1;
+ goto exit_lbl;
+ }
+
+ wnd_sum -= first_bd_sz;
+ }
+
+ /* Others are easier: run through the frag list and
+ check all windows */
+ for (wnd_idx = 0; wnd_idx <= num_wnds; wnd_idx++) {
+ wnd_sum +=
+ skb_shinfo(skb)->frags[wnd_idx + wnd_size - 1].size;
+
+ if (unlikely(wnd_sum < lso_mss)) {
+ to_copy = 1;
+ break;
+ }
+ wnd_sum -=
+ skb_shinfo(skb)->frags[wnd_idx].size;
+ }
+ } else {
+ /* in non-LSO too fragmented packet should always
+ be linearized */
+ to_copy = 1;
+ }
+ }
+
+exit_lbl:
+ if (unlikely(to_copy))
+ DP(NETIF_MSG_TX_QUEUED,
+ "Linearization IS REQUIRED for %s packet. "
+ "num_frags %d hlen %d first_bd_sz %d\n",
+ (xmit_type & XMIT_GSO) ? "LSO" : "non-LSO",
+ skb_shinfo(skb)->nr_frags, hlen, first_bd_sz);
+
+ return to_copy;
+}
+#endif
+
+/* called with netif_tx_lock
+ * bnx2x_tx_int() runs without netif_tx_lock unless it needs to call
+ * netif_wake_queue()
+ */
+netdev_tx_t bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+ struct bnx2x *bp = netdev_priv(dev);
+ struct bnx2x_fastpath *fp;
+ struct netdev_queue *txq;
+ struct sw_tx_bd *tx_buf;
+ struct eth_tx_start_bd *tx_start_bd;
+ struct eth_tx_bd *tx_data_bd, *total_pkt_bd = NULL;
+ struct eth_tx_parse_bd *pbd = NULL;
+ u16 pkt_prod, bd_prod;
+ int nbd, fp_index;
+ dma_addr_t mapping;
+ u32 xmit_type = bnx2x_xmit_type(bp, skb);
+ int i;
+ u8 hlen = 0;
+ __le16 pkt_size = 0;
+ struct ethhdr *eth;
+ u8 mac_type = UNICAST_ADDRESS;
+
+#ifdef BNX2X_STOP_ON_ERROR
+ if (unlikely(bp->panic))
+ return NETDEV_TX_BUSY;
+#endif
+
+ fp_index = skb_get_queue_mapping(skb);
+ txq = netdev_get_tx_queue(dev, fp_index);
+
+ fp = &bp->fp[fp_index];
+
+ if (unlikely(bnx2x_tx_avail(fp) < (skb_shinfo(skb)->nr_frags + 3))) {
+ fp->eth_q_stats.driver_xoff++;
+ netif_tx_stop_queue(txq);
+ BNX2X_ERR("BUG! Tx ring full when queue awake!\n");
+ return NETDEV_TX_BUSY;
+ }
+
+ DP(NETIF_MSG_TX_QUEUED, "SKB: summed %x protocol %x protocol(%x,%x)"
+ " gso type %x xmit_type %x\n",
+ skb->ip_summed, skb->protocol, ipv6_hdr(skb)->nexthdr,
+ ip_hdr(skb)->protocol, skb_shinfo(skb)->gso_type, xmit_type);
+
+ eth = (struct ethhdr *)skb->data;
+
+ /* set flag according to packet type (UNICAST_ADDRESS is default)*/
+ if (unlikely(is_multicast_ether_addr(eth->h_dest))) {
+ if (is_broadcast_ether_addr(eth->h_dest))
+ mac_type = BROADCAST_ADDRESS;
+ else
+ mac_type = MULTICAST_ADDRESS;
+ }
+
+#if (MAX_SKB_FRAGS >= MAX_FETCH_BD - 3)
+ /* First, check if we need to linearize the skb (due to FW
+ restrictions). No need to check fragmentation if page size > 8K
+ (there will be no violation to FW restrictions) */
+ if (bnx2x_pkt_req_lin(bp, skb, xmit_type)) {
+ /* Statistics of linearization */
+ bp->lin_cnt++;
+ if (skb_linearize(skb) != 0) {
+ DP(NETIF_MSG_TX_QUEUED, "SKB linearization failed - "
+ "silently dropping this SKB\n");
+ dev_kfree_skb_any(skb);
+ return NETDEV_TX_OK;
+ }
+ }
+#endif
+
+ /*
+ Please read carefully. First we use one BD which we mark as start,
+ then we have a parsing info BD (used for TSO or xsum),
+ and only then we have the rest of the TSO BDs.
+ (don't forget to mark the last one as last,
+ and to unmap only AFTER you write to the BD ...)
+ And above all, all pdb sizes are in words - NOT DWORDS!
+ */
+
+ pkt_prod = fp->tx_pkt_prod++;
+ bd_prod = TX_BD(fp->tx_bd_prod);
+
+ /* get a tx_buf and first BD */
+ tx_buf = &fp->tx_buf_ring[TX_BD(pkt_prod)];
+ tx_start_bd = &fp->tx_desc_ring[bd_prod].start_bd;
+
+ tx_start_bd->bd_flags.as_bitfield = ETH_TX_BD_FLAGS_START_BD;
+ tx_start_bd->general_data = (mac_type <<
+ ETH_TX_START_BD_ETH_ADDR_TYPE_SHIFT);
+ /* header nbd */
+ tx_start_bd->general_data |= (1 << ETH_TX_START_BD_HDR_NBDS_SHIFT);
+
+ /* remember the first BD of the packet */
+ tx_buf->first_bd = fp->tx_bd_prod;
+ tx_buf->skb = skb;
+ tx_buf->flags = 0;
+
+ DP(NETIF_MSG_TX_QUEUED,
+ "sending pkt %u @%p next_idx %u bd %u @%p\n",
+ pkt_prod, tx_buf, fp->tx_pkt_prod, bd_prod, tx_start_bd);
+
+#ifdef BCM_VLAN
+ if ((bp->vlgrp != NULL) && vlan_tx_tag_present(skb) &&
+ (bp->flags & HW_VLAN_TX_FLAG)) {
+ tx_start_bd->vlan = cpu_to_le16(vlan_tx_tag_get(skb));
+ tx_start_bd->bd_flags.as_bitfield |= ETH_TX_BD_FLAGS_VLAN_TAG;
+ } else
+#endif
+ tx_start_bd->vlan = cpu_to_le16(pkt_prod);
+
+ /* turn on parsing and get a BD */
+ bd_prod = TX_BD(NEXT_TX_IDX(bd_prod));
+ pbd = &fp->tx_desc_ring[bd_prod].parse_bd;
+
+ memset(pbd, 0, sizeof(struct eth_tx_parse_bd));
+
+ if (xmit_type & XMIT_CSUM) {
+ hlen = (skb_network_header(skb) - skb->data) / 2;
+
+ /* for now NS flag is not used in Linux */
+ pbd->global_data =
+ (hlen | ((skb->protocol == cpu_to_be16(ETH_P_8021Q)) <<
+ ETH_TX_PARSE_BD_LLC_SNAP_EN_SHIFT));
+
+ pbd->ip_hlen = (skb_transport_header(skb) -
+ skb_network_header(skb)) / 2;
+
+ hlen += pbd->ip_hlen + tcp_hdrlen(skb) / 2;
+
+ pbd->total_hlen = cpu_to_le16(hlen);
+ hlen = hlen*2;
+
+ tx_start_bd->bd_flags.as_bitfield |= ETH_TX_BD_FLAGS_L4_CSUM;
+
+ if (xmit_type & XMIT_CSUM_V4)
+ tx_start_bd->bd_flags.as_bitfield |=
+ ETH_TX_BD_FLAGS_IP_CSUM;
+ else
+ tx_start_bd->bd_flags.as_bitfield |=
+ ETH_TX_BD_FLAGS_IPV6;
+
+ if (xmit_type & XMIT_CSUM_TCP) {
+ pbd->tcp_pseudo_csum = swab16(tcp_hdr(skb)->check);
+
+ } else {
+ s8 fix = SKB_CS_OFF(skb); /* signed! */
+
+ pbd->global_data |= ETH_TX_PARSE_BD_UDP_CS_FLG;
+
+ DP(NETIF_MSG_TX_QUEUED,
+ "hlen %d fix %d csum before fix %x\n",
+ le16_to_cpu(pbd->total_hlen), fix, SKB_CS(skb));
+
+ /* HW bug: fixup the CSUM */
+ pbd->tcp_pseudo_csum =
+ bnx2x_csum_fix(skb_transport_header(skb),
+ SKB_CS(skb), fix);
+
+ DP(NETIF_MSG_TX_QUEUED, "csum after fix %x\n",
+ pbd->tcp_pseudo_csum);
+ }
+ }
+
+ mapping = dma_map_single(&bp->pdev->dev, skb->data,
+ skb_headlen(skb), DMA_TO_DEVICE);
+
+ tx_start_bd->addr_hi = cpu_to_le32(U64_HI(mapping));
+ tx_start_bd->addr_lo = cpu_to_le32(U64_LO(mapping));
+ nbd = skb_shinfo(skb)->nr_frags + 2; /* start_bd + pbd + frags */
+ tx_start_bd->nbd = cpu_to_le16(nbd);
+ tx_start_bd->nbytes = cpu_to_le16(skb_headlen(skb));
+ pkt_size = tx_start_bd->nbytes;
+
+ DP(NETIF_MSG_TX_QUEUED, "first bd @%p addr (%x:%x) nbd %d"
+ " nbytes %d flags %x vlan %x\n",
+ tx_start_bd, tx_start_bd->addr_hi, tx_start_bd->addr_lo,
+ le16_to_cpu(tx_start_bd->nbd), le16_to_cpu(tx_start_bd->nbytes),
+ tx_start_bd->bd_flags.as_bitfield, le16_to_cpu(tx_start_bd->vlan));
+
+ if (xmit_type & XMIT_GSO) {
+
+ DP(NETIF_MSG_TX_QUEUED,
+ "TSO packet len %d hlen %d total len %d tso size %d\n",
+ skb->len, hlen, skb_headlen(skb),
+ skb_shinfo(skb)->gso_size);
+
+ tx_start_bd->bd_flags.as_bitfield |= ETH_TX_BD_FLAGS_SW_LSO;
+
+ if (unlikely(skb_headlen(skb) > hlen))
+ bd_prod = bnx2x_tx_split(bp, fp, tx_buf, &tx_start_bd,
+ hlen, bd_prod, ++nbd);
+
+ pbd->lso_mss = cpu_to_le16(skb_shinfo(skb)->gso_size);
+ pbd->tcp_send_seq = swab32(tcp_hdr(skb)->seq);
+ pbd->tcp_flags = pbd_tcp_flags(skb);
+
+ if (xmit_type & XMIT_GSO_V4) {
+ pbd->ip_id = swab16(ip_hdr(skb)->id);
+ pbd->tcp_pseudo_csum =
+ swab16(~csum_tcpudp_magic(ip_hdr(skb)->saddr,
+ ip_hdr(skb)->daddr,
+ 0, IPPROTO_TCP, 0));
+
+ } else
+ pbd->tcp_pseudo_csum =
+ swab16(~csum_ipv6_magic(&ipv6_hdr(skb)->saddr,
+ &ipv6_hdr(skb)->daddr,
+ 0, IPPROTO_TCP, 0));
+
+ pbd->global_data |= ETH_TX_PARSE_BD_PSEUDO_CS_WITHOUT_LEN;
+ }
+ tx_data_bd = (struct eth_tx_bd *)tx_start_bd;
+
+ for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
+ skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
+
+ bd_prod = TX_BD(NEXT_TX_IDX(bd_prod));
+ tx_data_bd = &fp->tx_desc_ring[bd_prod].reg_bd;
+ if (total_pkt_bd == NULL)
+ total_pkt_bd = &fp->tx_desc_ring[bd_prod].reg_bd;
+
+ mapping = dma_map_page(&bp->pdev->dev, frag->page,
+ frag->page_offset,
+ frag->size, DMA_TO_DEVICE);
+
+ tx_data_bd->addr_hi = cpu_to_le32(U64_HI(mapping));
+ tx_data_bd->addr_lo = cpu_to_le32(U64_LO(mapping));
+ tx_data_bd->nbytes = cpu_to_le16(frag->size);
+ le16_add_cpu(&pkt_size, frag->size);
+
+ DP(NETIF_MSG_TX_QUEUED,
+ "frag %d bd @%p addr (%x:%x) nbytes %d\n",
+ i, tx_data_bd, tx_data_bd->addr_hi, tx_data_bd->addr_lo,
+ le16_to_cpu(tx_data_bd->nbytes));
+ }
+
+ DP(NETIF_MSG_TX_QUEUED, "last bd @%p\n", tx_data_bd);
+
+ bd_prod = TX_BD(NEXT_TX_IDX(bd_prod));
+
+ /* now send a tx doorbell, counting the next BD
+ * if the packet contains or ends with it
+ */
+ if (TX_BD_POFF(bd_prod) < nbd)
+ nbd++;
+
+ if (total_pkt_bd != NULL)
+ total_pkt_bd->total_pkt_bytes = pkt_size;
+
+ if (pbd)
+ DP(NETIF_MSG_TX_QUEUED,
+ "PBD @%p ip_data %x ip_hlen %u ip_id %u lso_mss %u"
+ " tcp_flags %x xsum %x seq %u hlen %u\n",
+ pbd, pbd->global_data, pbd->ip_hlen, pbd->ip_id,
+ pbd->lso_mss, pbd->tcp_flags, pbd->tcp_pseudo_csum,
+ pbd->tcp_send_seq, le16_to_cpu(pbd->total_hlen));
+
+ DP(NETIF_MSG_TX_QUEUED, "doorbell: nbd %d bd %u\n", nbd, bd_prod);
+
+ /*
+ * Make sure that the BD data is updated before updating the producer
+ * since FW might read the BD right after the producer is updated.
+ * This is only applicable for weak-ordered memory model archs such
+ * as IA-64. The following barrier is also mandatory since FW will
+ * assumes packets must have BDs.
+ */
+ wmb();
+
+ fp->tx_db.data.prod += nbd;
+ barrier();
+ DOORBELL(bp, fp->index, fp->tx_db.raw);
+
+ mmiowb();
+
+ fp->tx_bd_prod += nbd;
+
+ if (unlikely(bnx2x_tx_avail(fp) < MAX_SKB_FRAGS + 3)) {
+ netif_tx_stop_queue(txq);
+
+ /* paired memory barrier is in bnx2x_tx_int(), we have to keep
+ * ordering of set_bit() in netif_tx_stop_queue() and read of
+ * fp->bd_tx_cons */
+ smp_mb();
+
+ fp->eth_q_stats.driver_xoff++;
+ if (bnx2x_tx_avail(fp) >= MAX_SKB_FRAGS + 3)
+ netif_tx_wake_queue(txq);
+ }
+ fp->tx_pkt++;
+
+ return NETDEV_TX_OK;
+}
+/* called with rtnl_lock */
+int bnx2x_change_mac_addr(struct net_device *dev, void *p)
+{
+ struct sockaddr *addr = p;
+ struct bnx2x *bp = netdev_priv(dev);
+
+ if (!is_valid_ether_addr((u8 *)(addr->sa_data)))
+ return -EINVAL;
+
+ memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
+ if (netif_running(dev)) {
+ if (CHIP_IS_E1(bp))
+ bnx2x_set_eth_mac_addr_e1(bp, 1);
+ else
+ bnx2x_set_eth_mac_addr_e1h(bp, 1);
+ }
+
+ return 0;
+}
+
+/* called with rtnl_lock */
+int bnx2x_change_mtu(struct net_device *dev, int new_mtu)
+{
+ struct bnx2x *bp = netdev_priv(dev);
+ int rc = 0;
+
+ if (bp->recovery_state != BNX2X_RECOVERY_DONE) {
+ printk(KERN_ERR "Handling parity error recovery. Try again later\n");
+ return -EAGAIN;
+ }
+
+ if ((new_mtu > ETH_MAX_JUMBO_PACKET_SIZE) ||
+ ((new_mtu + ETH_HLEN) < ETH_MIN_PACKET_SIZE))
+ return -EINVAL;
+
+ /* This does not race with packet allocation
+ * because the actual alloc size is
+ * only updated as part of load
+ */
+ dev->mtu = new_mtu;
+
+ if (netif_running(dev)) {
+ bnx2x_nic_unload(bp, UNLOAD_NORMAL);
+ rc = bnx2x_nic_load(bp, LOAD_NORMAL);
+ }
+
+ return rc;
+}
+
+void bnx2x_tx_timeout(struct net_device *dev)
+{
+ struct bnx2x *bp = netdev_priv(dev);
+
+#ifdef BNX2X_STOP_ON_ERROR
+ if (!bp->panic)
+ bnx2x_panic();
+#endif
+ /* This allows the netif to be shutdown gracefully before resetting */
+ schedule_delayed_work(&bp->reset_task, 0);
+}
+
+#ifdef BCM_VLAN
+/* called with rtnl_lock */
+void bnx2x_vlan_rx_register(struct net_device *dev,
+ struct vlan_group *vlgrp)
+{
+ struct bnx2x *bp = netdev_priv(dev);
+
+ bp->vlgrp = vlgrp;
+
+ /* Set flags according to the required capabilities */
+ bp->flags &= ~(HW_VLAN_RX_FLAG | HW_VLAN_TX_FLAG);
+
+ if (dev->features & NETIF_F_HW_VLAN_TX)
+ bp->flags |= HW_VLAN_TX_FLAG;
+
+ if (dev->features & NETIF_F_HW_VLAN_RX)
+ bp->flags |= HW_VLAN_RX_FLAG;
+
+ if (netif_running(dev))
+ bnx2x_set_client_config(bp);
+}
+
+#endif
+int bnx2x_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+ struct net_device *dev = pci_get_drvdata(pdev);
+ struct bnx2x *bp;
+
+ if (!dev) {
+ dev_err(&pdev->dev, "BAD net device from bnx2x_init_one\n");
+ return -ENODEV;
+ }
+ bp = netdev_priv(dev);
+
+ rtnl_lock();
+
+ pci_save_state(pdev);
+
+ if (!netif_running(dev)) {
+ rtnl_unlock();
+ return 0;
+ }
+
+ netif_device_detach(dev);
+
+ bnx2x_nic_unload(bp, UNLOAD_CLOSE);
+
+ bnx2x_set_power_state(bp, pci_choose_state(pdev, state));
+
+ rtnl_unlock();
+
+ return 0;
+}
+
+int bnx2x_resume(struct pci_dev *pdev)
+{
+ struct net_device *dev = pci_get_drvdata(pdev);
+ struct bnx2x *bp;
+ int rc;
+
+ if (!dev) {
+ dev_err(&pdev->dev, "BAD net device from bnx2x_init_one\n");
+ return -ENODEV;
+ }
+ bp = netdev_priv(dev);
+
+ if (bp->recovery_state != BNX2X_RECOVERY_DONE) {
+ printk(KERN_ERR "Handling parity error recovery. Try again later\n");
+ return -EAGAIN;
+ }
+
+ rtnl_lock();
+
+ pci_restore_state(pdev);
+
+ if (!netif_running(dev)) {
+ rtnl_unlock();
+ return 0;
+ }
+
+ bnx2x_set_power_state(bp, PCI_D0);
+ netif_device_attach(dev);
+
+ rc = bnx2x_nic_load(bp, LOAD_OPEN);
+
+ rtnl_unlock();
+
+ return rc;
+}
diff --git a/drivers/net/bnx2x/bnx2x_cmn.h b/drivers/net/bnx2x/bnx2x_cmn.h
new file mode 100644
index 00000000000..d1979b1a7ed
--- /dev/null
+++ b/drivers/net/bnx2x/bnx2x_cmn.h
@@ -0,0 +1,652 @@
+/* bnx2x_cmn.h: Broadcom Everest network driver.
+ *
+ * Copyright (c) 2007-2010 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.
+ *
+ * Maintained by: Eilon Greenstein <eilong@broadcom.com>
+ * Written by: Eliezer Tamir
+ * Based on code from Michael Chan's bnx2 driver
+ * UDP CSUM errata workaround by Arik Gendelman
+ * Slowpath and fastpath rework by Vladislav Zolotarov
+ * Statistics and Link management by Yitchak Gertner
+ *
+ */
+#ifndef BNX2X_CMN_H
+#define BNX2X_CMN_H
+
+#include <linux/types.h>
+#include <linux/netdevice.h>
+
+
+#include "bnx2x.h"
+
+
+/*********************** Interfaces ****************************
+ * Functions that need to be implemented by each driver version
+ */
+
+/**
+ * Initialize link parameters structure variables.
+ *
+ * @param bp
+ * @param load_mode
+ *
+ * @return u8
+ */
+u8 bnx2x_initial_phy_init(struct bnx2x *bp, int load_mode);
+
+/**
+ * Configure hw according to link parameters structure.
+ *
+ * @param bp
+ */
+void bnx2x_link_set(struct bnx2x *bp);
+
+/**
+ * Query link status
+ *
+ * @param bp
+ *
+ * @return 0 - link is UP
+ */
+u8 bnx2x_link_test(struct bnx2x *bp);
+
+/**
+ * Handles link status change
+ *
+ * @param bp
+ */
+void bnx2x__link_status_update(struct bnx2x *bp);
+
+/**
+ * MSI-X slowpath interrupt handler
+ *
+ * @param irq
+ * @param dev_instance
+ *
+ * @return irqreturn_t
+ */
+irqreturn_t bnx2x_msix_sp_int(int irq, void *dev_instance);
+
+/**
+ * non MSI-X interrupt handler
+ *
+ * @param irq
+ * @param dev_instance
+ *
+ * @return irqreturn_t
+ */
+irqreturn_t bnx2x_interrupt(int irq, void *dev_instance);
+#ifdef BCM_CNIC
+
+/**
+ * Send command to cnic driver
+ *
+ * @param bp
+ * @param cmd
+ */
+int bnx2x_cnic_notify(struct bnx2x *bp, int cmd);
+
+/**
+ * Provides cnic information for proper interrupt handling
+ *
+ * @param bp
+ */
+void bnx2x_setup_cnic_irq_info(struct bnx2x *bp);
+#endif
+
+/**
+ * Enable HW interrupts.
+ *
+ * @param bp
+ */
+void bnx2x_int_enable(struct bnx2x *bp);
+
+/**
+ * Disable interrupts. This function ensures that there are no
+ * ISRs or SP DPCs (sp_task) are running after it returns.
+ *
+ * @param bp
+ * @param disable_hw if true, disable HW interrupts.
+ */
+void bnx2x_int_disable_sync(struct bnx2x *bp, int disable_hw);
+
+/**
+ * Init HW blocks according to current initialization stage:
+ * COMMON, PORT or FUNCTION.
+ *
+ * @param bp
+ * @param load_code: COMMON, PORT or FUNCTION
+ *
+ * @return int
+ */
+int bnx2x_init_hw(struct bnx2x *bp, u32 load_code);
+
+/**
+ * Init driver internals:
+ * - rings
+ * - status blocks
+ * - etc.
+ *
+ * @param bp
+ * @param load_code COMMON, PORT or FUNCTION
+ */
+void bnx2x_nic_init(struct bnx2x *bp, u32 load_code);
+
+/**
+ * Allocate driver's memory.
+ *
+ * @param bp
+ *
+ * @return int
+ */
+int bnx2x_alloc_mem(struct bnx2x *bp);
+
+/**
+ * Release driver's memory.
+ *
+ * @param bp
+ */
+void bnx2x_free_mem(struct bnx2x *bp);
+
+/**
+ * Bring up a leading (the first) eth Client.
+ *
+ * @param bp
+ *
+ * @return int
+ */
+int bnx2x_setup_leading(struct bnx2x *bp);
+
+/**
+ * Setup non-leading eth Client.
+ *
+ * @param bp
+ * @param fp
+ *
+ * @return int
+ */
+int bnx2x_setup_multi(struct bnx2x *bp, int index);
+
+/**
+ * Set number of quueus according to mode and number of available
+ * msi-x vectors
+ *
+ * @param bp
+ *
+ */
+void bnx2x_set_num_queues_msix(struct bnx2x *bp);
+
+/**
+ * Cleanup chip internals:
+ * - Cleanup MAC configuration.
+ * - Close clients.
+ * - etc.
+ *
+ * @param bp
+ * @param unload_mode
+ */
+void bnx2x_chip_cleanup(struct bnx2x *bp, int unload_mode);
+
+/**
+ * Acquire HW lock.
+ *
+ * @param bp
+ * @param resource Resource bit which was locked
+ *
+ * @return int
+ */
+int bnx2x_acquire_hw_lock(struct bnx2x *bp, u32 resource);
+
+/**
+ * Release HW lock.
+ *
+ * @param bp driver handle
+ * @param resource Resource bit which was locked
+ *
+ * @return int
+ */
+int bnx2x_release_hw_lock(struct bnx2x *bp, u32 resource);
+
+/**
+ * Configure eth MAC address in the HW according to the value in
+ * netdev->dev_addr for 57711
+ *
+ * @param bp driver handle
+ * @param set
+ */
+void bnx2x_set_eth_mac_addr_e1h(struct bnx2x *bp, int set);
+
+/**
+ * Configure eth MAC address in the HW according to the value in
+ * netdev->dev_addr for 57710
+ *
+ * @param bp driver handle
+ * @param set
+ */
+void bnx2x_set_eth_mac_addr_e1(struct bnx2x *bp, int set);
+
+#ifdef BCM_CNIC
+/**
+ * Set iSCSI MAC(s) at the next enties in the CAM after the ETH
+ * MAC(s). The function will wait until the ramrod completion
+ * returns.
+ *
+ * @param bp driver handle
+ * @param set set or clear the CAM entry
+ *
+ * @return 0 if cussess, -ENODEV if ramrod doesn't return.
+ */
+int bnx2x_set_iscsi_eth_mac_addr(struct bnx2x *bp, int set);
+#endif
+
+/**
+ * Initialize status block in FW and HW
+ *
+ * @param bp driver handle
+ * @param sb host_status_block
+ * @param dma_addr_t mapping
+ * @param int sb_id
+ */
+void bnx2x_init_sb(struct bnx2x *bp, struct host_status_block *sb,
+ dma_addr_t mapping, int sb_id);
+
+/**
+ * Reconfigure FW/HW according to dev->flags rx mode
+ *
+ * @param dev net_device
+ *
+ */
+void bnx2x_set_rx_mode(struct net_device *dev);
+
+/**
+ * Configure MAC filtering rules in a FW.
+ *
+ * @param bp driver handle
+ */
+void bnx2x_set_storm_rx_mode(struct bnx2x *bp);
+
+/* Parity errors related */
+void bnx2x_inc_load_cnt(struct bnx2x *bp);
+u32 bnx2x_dec_load_cnt(struct bnx2x *bp);
+bool bnx2x_chk_parity_attn(struct bnx2x *bp);
+bool bnx2x_reset_is_done(struct bnx2x *bp);
+void bnx2x_disable_close_the_gate(struct bnx2x *bp);
+
+/**
+ * Perform statistics handling according to event
+ *
+ * @param bp driver handle
+ * @param even tbnx2x_stats_event
+ */
+void bnx2x_stats_handle(struct bnx2x *bp, enum bnx2x_stats_event event);
+
+/**
+ * Configures FW with client paramteres (like HW VLAN removal)
+ * for each active client.
+ *
+ * @param bp
+ */
+void bnx2x_set_client_config(struct bnx2x *bp);
+
+/**
+ * Handle sp events
+ *
+ * @param fp fastpath handle for the event
+ * @param rr_cqe eth_rx_cqe
+ */
+void bnx2x_sp_event(struct bnx2x_fastpath *fp, union eth_rx_cqe *rr_cqe);
+
+
+static inline void bnx2x_update_fpsb_idx(struct bnx2x_fastpath *fp)
+{
+ struct host_status_block *fpsb = fp->status_blk;
+
+ barrier(); /* status block is written to by the chip */
+ fp->fp_c_idx = fpsb->c_status_block.status_block_index;
+ fp->fp_u_idx = fpsb->u_status_block.status_block_index;
+}
+
+static inline void bnx2x_update_rx_prod(struct bnx2x *bp,
+ struct bnx2x_fastpath *fp,
+ u16 bd_prod, u16 rx_comp_prod,
+ u16 rx_sge_prod)
+{
+ struct ustorm_eth_rx_producers rx_prods = {0};
+ int i;
+
+ /* Update producers */
+ rx_prods.bd_prod = bd_prod;
+ rx_prods.cqe_prod = rx_comp_prod;
+ rx_prods.sge_prod = rx_sge_prod;
+
+ /*
+ * Make sure that the BD and SGE data is updated before updating the
+ * producers since FW might read the BD/SGE right after the producer
+ * is updated.
+ * This is only applicable for weak-ordered memory model archs such
+ * as IA-64. The following barrier is also mandatory since FW will
+ * assumes BDs must have buffers.
+ */
+ wmb();
+
+ for (i = 0; i < sizeof(struct ustorm_eth_rx_producers)/4; i++)
+ REG_WR(bp, BAR_USTRORM_INTMEM +
+ USTORM_RX_PRODS_OFFSET(BP_PORT(bp), fp->cl_id) + i*4,
+ ((u32 *)&rx_prods)[i]);
+
+ mmiowb(); /* keep prod updates ordered */
+
+ DP(NETIF_MSG_RX_STATUS,
+ "queue[%d]: wrote bd_prod %u cqe_prod %u sge_prod %u\n",
+ fp->index, bd_prod, rx_comp_prod, rx_sge_prod);
+}
+
+
+
+static inline void bnx2x_ack_sb(struct bnx2x *bp, u8 sb_id,
+ u8 storm, u16 index, u8 op, u8 update)
+{
+ u32 hc_addr = (HC_REG_COMMAND_REG + BP_PORT(bp)*32 +
+ COMMAND_REG_INT_ACK);
+ struct igu_ack_register igu_ack;
+
+ igu_ack.status_block_index = index;
+ igu_ack.sb_id_and_flags =
+ ((sb_id << IGU_ACK_REGISTER_STATUS_BLOCK_ID_SHIFT) |
+ (storm << IGU_ACK_REGISTER_STORM_ID_SHIFT) |
+ (update << IGU_ACK_REGISTER_UPDATE_INDEX_SHIFT) |
+ (op << IGU_ACK_REGISTER_INTERRUPT_MODE_SHIFT));
+
+ DP(BNX2X_MSG_OFF, "write 0x%08x to HC addr 0x%x\n",
+ (*(u32 *)&igu_ack), hc_addr);
+ REG_WR(bp, hc_addr, (*(u32 *)&igu_ack));
+
+ /* Make sure that ACK is written */
+ mmiowb();
+ barrier();
+}
+static inline u16 bnx2x_ack_int(struct bnx2x *bp)
+{
+ u32 hc_addr = (HC_REG_COMMAND_REG + BP_PORT(bp)*32 +
+ COMMAND_REG_SIMD_MASK);
+ u32 result = REG_RD(bp, hc_addr);
+
+ DP(BNX2X_MSG_OFF, "read 0x%08x from HC addr 0x%x\n",
+ result, hc_addr);
+
+ return result;
+}
+
+/*
+ * fast path service functions
+ */
+
+static inline int bnx2x_has_tx_work_unload(struct bnx2x_fastpath *fp)
+{
+ /* Tell compiler that consumer and producer can change */
+ barrier();
+ return (fp->tx_pkt_prod != fp->tx_pkt_cons);
+}
+
+static inline u16 bnx2x_tx_avail(struct bnx2x_fastpath *fp)
+{
+ s16 used;
+ u16 prod;
+ u16 cons;
+
+ prod = fp->tx_bd_prod;
+ cons = fp->tx_bd_cons;
+
+ /* NUM_TX_RINGS = number of "next-page" entries
+ It will be used as a threshold */
+ used = SUB_S16(prod, cons) + (s16)NUM_TX_RINGS;
+
+#ifdef BNX2X_STOP_ON_ERROR
+ WARN_ON(used < 0);
+ WARN_ON(used > fp->bp->tx_ring_size);
+ WARN_ON((fp->bp->tx_ring_size - used) > MAX_TX_AVAIL);
+#endif
+
+ return (s16)(fp->bp->tx_ring_size) - used;
+}
+
+static inline int bnx2x_has_tx_work(struct bnx2x_fastpath *fp)
+{
+ u16 hw_cons;
+
+ /* Tell compiler that status block fields can change */
+ barrier();
+ hw_cons = le16_to_cpu(*fp->tx_cons_sb);
+ return hw_cons != fp->tx_pkt_cons;
+}
+
+static inline void bnx2x_free_rx_sge(struct bnx2x *bp,
+ struct bnx2x_fastpath *fp, u16 index)
+{
+ struct sw_rx_page *sw_buf = &fp->rx_page_ring[index];
+ struct page *page = sw_buf->page;
+ struct eth_rx_sge *sge = &fp->rx_sge_ring[index];
+
+ /* Skip "next page" elements */
+ if (!page)
+ return;
+
+ dma_unmap_page(&bp->pdev->dev, dma_unmap_addr(sw_buf, mapping),
+ SGE_PAGE_SIZE*PAGES_PER_SGE, PCI_DMA_FROMDEVICE);
+ __free_pages(page, PAGES_PER_SGE_SHIFT);
+
+ sw_buf->page = NULL;
+ sge->addr_hi = 0;
+ sge->addr_lo = 0;
+}
+
+static inline void bnx2x_free_rx_sge_range(struct bnx2x *bp,
+ struct bnx2x_fastpath *fp, int last)
+{
+ int i;
+
+ for (i = 0; i < last; i++)
+ bnx2x_free_rx_sge(bp, fp, i);
+}
+
+static inline int bnx2x_alloc_rx_sge(struct bnx2x *bp,
+ struct bnx2x_fastpath *fp, u16 index)
+{
+ struct page *page = alloc_pages(GFP_ATOMIC, PAGES_PER_SGE_SHIFT);
+ struct sw_rx_page *sw_buf = &fp->rx_page_ring[index];
+ struct eth_rx_sge *sge = &fp->rx_sge_ring[index];
+ dma_addr_t mapping;
+
+ if (unlikely(page == NULL))
+ return -ENOMEM;
+
+ mapping = dma_map_page(&bp->pdev->dev, page, 0,
+ SGE_PAGE_SIZE*PAGES_PER_SGE, DMA_FROM_DEVICE);
+ if (unlikely(dma_mapping_error(&bp->pdev->dev, mapping))) {
+ __free_pages(page, PAGES_PER_SGE_SHIFT);
+ return -ENOMEM;
+ }
+
+ sw_buf->page = page;
+ dma_unmap_addr_set(sw_buf, mapping, mapping);
+
+ sge->addr_hi = cpu_to_le32(U64_HI(mapping));
+ sge->addr_lo = cpu_to_le32(U64_LO(mapping));
+
+ return 0;
+}
+static inline int bnx2x_alloc_rx_skb(struct bnx2x *bp,
+ struct bnx2x_fastpath *fp, u16 index)
+{
+ struct sk_buff *skb;
+ struct sw_rx_bd *rx_buf = &fp->rx_buf_ring[index];
+ struct eth_rx_bd *rx_bd = &fp->rx_desc_ring[index];
+ dma_addr_t mapping;
+
+ skb = netdev_alloc_skb(bp->dev, bp->rx_buf_size);
+ if (unlikely(skb == NULL))
+ return -ENOMEM;
+
+ mapping = dma_map_single(&bp->pdev->dev, skb->data, bp->rx_buf_size,
+ DMA_FROM_DEVICE);
+ if (unlikely(dma_mapping_error(&bp->pdev->dev, mapping))) {
+ dev_kfree_skb(skb);
+ return -ENOMEM;
+ }
+
+ rx_buf->skb = skb;
+ dma_unmap_addr_set(rx_buf, mapping, mapping);
+
+ rx_bd->addr_hi = cpu_to_le32(U64_HI(mapping));
+ rx_bd->addr_lo = cpu_to_le32(U64_LO(mapping));
+
+ return 0;
+}
+
+/* note that we are not allocating a new skb,
+ * we are just moving one from cons to prod
+ * we are not creating a new mapping,
+ * so there is no need to check for dma_mapping_error().
+ */
+static inline void bnx2x_reuse_rx_skb(struct bnx2x_fastpath *fp,
+ struct sk_buff *skb, u16 cons, u16 prod)
+{
+ struct bnx2x *bp = fp->bp;
+ struct sw_rx_bd *cons_rx_buf = &fp->rx_buf_ring[cons];
+ struct sw_rx_bd *prod_rx_buf = &fp->rx_buf_ring[prod];
+ struct eth_rx_bd *cons_bd = &fp->rx_desc_ring[cons];
+ struct eth_rx_bd *prod_bd = &fp->rx_desc_ring[prod];
+
+ dma_sync_single_for_device(&bp->pdev->dev,
+ dma_unmap_addr(cons_rx_buf, mapping),
+ RX_COPY_THRESH, DMA_FROM_DEVICE);
+
+ prod_rx_buf->skb = cons_rx_buf->skb;
+ dma_unmap_addr_set(prod_rx_buf, mapping,
+ dma_unmap_addr(cons_rx_buf, mapping));
+ *prod_bd = *cons_bd;
+}
+
+static inline void bnx2x_clear_sge_mask_next_elems(struct bnx2x_fastpath *fp)
+{
+ int i, j;
+
+ for (i = 1; i <= NUM_RX_SGE_PAGES; i++) {
+ int idx = RX_SGE_CNT * i - 1;
+
+ for (j = 0; j < 2; j++) {
+ SGE_MASK_CLEAR_BIT(fp, idx);
+ idx--;
+ }
+ }
+}
+
+static inline void bnx2x_init_sge_ring_bit_mask(struct bnx2x_fastpath *fp)
+{
+ /* Set the mask to all 1-s: it's faster to compare to 0 than to 0xf-s */
+ memset(fp->sge_mask, 0xff,
+ (NUM_RX_SGE >> RX_SGE_MASK_ELEM_SHIFT)*sizeof(u64));
+
+ /* Clear the two last indices in the page to 1:
+ these are the indices that correspond to the "next" element,
+ hence will never be indicated and should be removed from
+ the calculations. */
+ bnx2x_clear_sge_mask_next_elems(fp);
+}
+static inline void bnx2x_free_tpa_pool(struct bnx2x *bp,
+ struct bnx2x_fastpath *fp, int last)
+{
+ int i;
+
+ for (i = 0; i < last; i++) {
+ struct sw_rx_bd *rx_buf = &(fp->tpa_pool[i]);
+ struct sk_buff *skb = rx_buf->skb;
+
+ if (skb == NULL) {
+ DP(NETIF_MSG_IFDOWN, "tpa bin %d empty on free\n", i);
+ continue;
+ }
+
+ if (fp->tpa_state[i] == BNX2X_TPA_START)
+ dma_unmap_single(&bp->pdev->dev,
+ dma_unmap_addr(rx_buf, mapping),
+ bp->rx_buf_size, DMA_FROM_DEVICE);
+
+ dev_kfree_skb(skb);
+ rx_buf->skb = NULL;
+ }
+}
+
+
+static inline void bnx2x_init_tx_ring(struct bnx2x *bp)
+{
+ int i, j;
+
+ for_each_queue(bp, j) {
+ struct bnx2x_fastpath *fp = &bp->fp[j];
+
+ for (i = 1; i <= NUM_TX_RINGS; i++) {
+ struct eth_tx_next_bd *tx_next_bd =
+ &fp->tx_desc_ring[TX_DESC_CNT * i - 1].next_bd;
+
+ tx_next_bd->addr_hi =
+ cpu_to_le32(U64_HI(fp->tx_desc_mapping +
+ BCM_PAGE_SIZE*(i % NUM_TX_RINGS)));
+ tx_next_bd->addr_lo =
+ cpu_to_le32(U64_LO(fp->tx_desc_mapping +
+ BCM_PAGE_SIZE*(i % NUM_TX_RINGS)));
+ }
+
+ fp->tx_db.data.header.header = DOORBELL_HDR_DB_TYPE;
+ fp->tx_db.data.zero_fill1 = 0;
+ fp->tx_db.data.prod = 0;
+
+ fp->tx_pkt_prod = 0;
+ fp->tx_pkt_cons = 0;
+ fp->tx_bd_prod = 0;
+ fp->tx_bd_cons = 0;
+ fp->tx_cons_sb = BNX2X_TX_SB_INDEX;
+ fp->tx_pkt = 0;
+ }
+}
+static inline int bnx2x_has_rx_work(struct bnx2x_fastpath *fp)
+{
+ u16 rx_cons_sb;
+
+ /* Tell compiler that status block fields can change */
+ barrier();
+ rx_cons_sb = le16_to_cpu(*fp->rx_cons_sb);
+ if ((rx_cons_sb & MAX_RCQ_DESC_CNT) == MAX_RCQ_DESC_CNT)
+ rx_cons_sb++;
+ return (fp->rx_comp_cons != rx_cons_sb);
+}
+
+/* HW Lock for shared dual port PHYs */
+void bnx2x_acquire_phy_lock(struct bnx2x *bp);
+void bnx2x_release_phy_lock(struct bnx2x *bp);
+
+void bnx2x_link_report(struct bnx2x *bp);
+int bnx2x_rx_int(struct bnx2x_fastpath *fp, int budget);
+int bnx2x_tx_int(struct bnx2x_fastpath *fp);
+void bnx2x_init_rx_rings(struct bnx2x *bp);
+netdev_tx_t bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev);
+
+int bnx2x_change_mac_addr(struct net_device *dev, void *p);
+void bnx2x_tx_timeout(struct net_device *dev);
+void bnx2x_vlan_rx_register(struct net_device *dev, struct vlan_group *vlgrp);
+void bnx2x_netif_start(struct bnx2x *bp);
+void bnx2x_netif_stop(struct bnx2x *bp, int disable_hw);
+void bnx2x_free_irq(struct bnx2x *bp, bool disable_only);
+int bnx2x_suspend(struct pci_dev *pdev, pm_message_t state);
+int bnx2x_resume(struct pci_dev *pdev);
+void bnx2x_free_skbs(struct bnx2x *bp);
+int bnx2x_change_mtu(struct net_device *dev, int new_mtu);
+int bnx2x_nic_unload(struct bnx2x *bp, int unload_mode);
+int bnx2x_nic_load(struct bnx2x *bp, int load_mode);
+int bnx2x_set_power_state(struct bnx2x *bp, pci_power_t state);
+
+#endif /* BNX2X_CMN_H */
diff --git a/drivers/net/bnx2x_dump.h b/drivers/net/bnx2x/bnx2x_dump.h
index 3bb9a91bb3f..3bb9a91bb3f 100644
--- a/drivers/net/bnx2x_dump.h
+++ b/drivers/net/bnx2x/bnx2x_dump.h
diff --git a/drivers/net/bnx2x/bnx2x_ethtool.c b/drivers/net/bnx2x/bnx2x_ethtool.c
new file mode 100644
index 00000000000..8b75b05e34c
--- /dev/null
+++ b/drivers/net/bnx2x/bnx2x_ethtool.c
@@ -0,0 +1,1971 @@
+/* bnx2x_ethtool.c: Broadcom Everest network driver.
+ *
+ * Copyright (c) 2007-2010 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.
+ *
+ * Maintained by: Eilon Greenstein <eilong@broadcom.com>
+ * Written by: Eliezer Tamir
+ * Based on code from Michael Chan's bnx2 driver
+ * UDP CSUM errata workaround by Arik Gendelman
+ * Slowpath and fastpath rework by Vladislav Zolotarov
+ * Statistics and Link management by Yitchak Gertner
+ *
+ */
+#include <linux/ethtool.h>
+#include <linux/netdevice.h>
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/crc32.h>
+
+
+#include "bnx2x.h"
+#include "bnx2x_cmn.h"
+#include "bnx2x_dump.h"
+
+
+static int bnx2x_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+ struct bnx2x *bp = netdev_priv(dev);
+
+ cmd->supported = bp->port.supported;
+ cmd->advertising = bp->port.advertising;
+
+ if ((bp->state == BNX2X_STATE_OPEN) &&
+ !(bp->flags & MF_FUNC_DIS) &&
+ (bp->link_vars.link_up)) {
+ cmd->speed = bp->link_vars.line_speed;
+ cmd->duplex = bp->link_vars.duplex;
+ if (IS_E1HMF(bp)) {
+ u16 vn_max_rate;
+
+ vn_max_rate =
+ ((bp->mf_config & FUNC_MF_CFG_MAX_BW_MASK) >>
+ FUNC_MF_CFG_MAX_BW_SHIFT) * 100;
+ if (vn_max_rate < cmd->speed)
+ cmd->speed = vn_max_rate;
+ }
+ } else {
+ cmd->speed = -1;
+ cmd->duplex = -1;
+ }
+
+ if (bp->link_params.switch_cfg == SWITCH_CFG_10G) {
+ u32 ext_phy_type =
+ XGXS_EXT_PHY_TYPE(bp->link_params.ext_phy_config);
+
+ switch (ext_phy_type) {
+ case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT:
+ case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072:
+ case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
+ case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705:
+ case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706:
+ case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
+ case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
+ cmd->port = PORT_FIBRE;
+ break;
+
+ case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101:
+ case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481:
+ cmd->port = PORT_TP;
+ break;
+
+ case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE:
+ BNX2X_ERR("XGXS PHY Failure detected 0x%x\n",
+ bp->link_params.ext_phy_config);
+ break;
+
+ default:
+ DP(NETIF_MSG_LINK, "BAD XGXS ext_phy_config 0x%x\n",
+ bp->link_params.ext_phy_config);
+ break;
+ }
+ } else
+ cmd->port = PORT_TP;
+
+ cmd->phy_address = bp->mdio.prtad;
+ cmd->transceiver = XCVR_INTERNAL;
+
+ if (bp->link_params.req_line_speed == SPEED_AUTO_NEG)
+ cmd->autoneg = AUTONEG_ENABLE;
+ else
+ cmd->autoneg = AUTONEG_DISABLE;
+
+ cmd->maxtxpkt = 0;
+ cmd->maxrxpkt = 0;
+
+ DP(NETIF_MSG_LINK, "ethtool_cmd: cmd %d\n"
+ DP_LEVEL " supported 0x%x advertising 0x%x speed %d\n"
+ DP_LEVEL " duplex %d port %d phy_address %d transceiver %d\n"
+ DP_LEVEL " autoneg %d maxtxpkt %d maxrxpkt %d\n",
+ cmd->cmd, cmd->supported, cmd->advertising, cmd->speed,
+ cmd->duplex, cmd->port, cmd->phy_address, cmd->transceiver,
+ cmd->autoneg, cmd->maxtxpkt, cmd->maxrxpkt);
+
+ return 0;
+}
+
+static int bnx2x_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+ struct bnx2x *bp = netdev_priv(dev);
+ u32 advertising;
+
+ if (IS_E1HMF(bp))
+ return 0;
+
+ DP(NETIF_MSG_LINK, "ethtool_cmd: cmd %d\n"
+ DP_LEVEL " supported 0x%x advertising 0x%x speed %d\n"
+ DP_LEVEL " duplex %d port %d phy_address %d transceiver %d\n"
+ DP_LEVEL " autoneg %d maxtxpkt %d maxrxpkt %d\n",
+ cmd->cmd, cmd->supported, cmd->advertising, cmd->speed,
+ cmd->duplex, cmd->port, cmd->phy_address, cmd->transceiver,
+ cmd->autoneg, cmd->maxtxpkt, cmd->maxrxpkt);
+
+ if (cmd->autoneg == AUTONEG_ENABLE) {
+ if (!(bp->port.supported & SUPPORTED_Autoneg)) {
+ DP(NETIF_MSG_LINK, "Autoneg not supported\n");
+ return -EINVAL;
+ }
+
+ /* advertise the requested speed and duplex if supported */
+ cmd->advertising &= bp->port.supported;
+
+ bp->link_params.req_line_speed = SPEED_AUTO_NEG;
+ bp->link_params.req_duplex = DUPLEX_FULL;
+ bp->port.advertising |= (ADVERTISED_Autoneg |
+ cmd->advertising);
+
+ } else { /* forced speed */
+ /* advertise the requested speed and duplex if supported */
+ switch (cmd->speed) {
+ case SPEED_10:
+ if (cmd->duplex == DUPLEX_FULL) {
+ if (!(bp->port.supported &
+ SUPPORTED_10baseT_Full)) {
+ DP(NETIF_MSG_LINK,
+ "10M full not supported\n");
+ return -EINVAL;
+ }
+
+ advertising = (ADVERTISED_10baseT_Full |
+ ADVERTISED_TP);
+ } else {
+ if (!(bp->port.supported &
+ SUPPORTED_10baseT_Half)) {
+ DP(NETIF_MSG_LINK,
+ "10M half not supported\n");
+ return -EINVAL;
+ }
+
+ advertising = (ADVERTISED_10baseT_Half |
+ ADVERTISED_TP);
+ }
+ break;
+
+ case SPEED_100:
+ if (cmd->duplex == DUPLEX_FULL) {
+ if (!(bp->port.supported &
+ SUPPORTED_100baseT_Full)) {
+ DP(NETIF_MSG_LINK,
+ "100M full not supported\n");
+ return -EINVAL;
+ }
+
+ advertising = (ADVERTISED_100baseT_Full |
+ ADVERTISED_TP);
+ } else {
+ if (!(bp->port.supported &
+ SUPPORTED_100baseT_Half)) {
+ DP(NETIF_MSG_LINK,
+ "100M half not supported\n");
+ return -EINVAL;
+ }
+
+ advertising = (ADVERTISED_100baseT_Half |
+ ADVERTISED_TP);
+ }
+ break;
+
+ case SPEED_1000:
+ if (cmd->duplex != DUPLEX_FULL) {
+ DP(NETIF_MSG_LINK, "1G half not supported\n");
+ return -EINVAL;
+ }
+
+ if (!(bp->port.supported & SUPPORTED_1000baseT_Full)) {
+ DP(NETIF_MSG_LINK, "1G full not supported\n");
+ return -EINVAL;
+ }
+
+ advertising = (ADVERTISED_1000baseT_Full |
+ ADVERTISED_TP);
+ break;
+
+ case SPEED_2500:
+ if (cmd->duplex != DUPLEX_FULL) {
+ DP(NETIF_MSG_LINK,
+ "2.5G half not supported\n");
+ return -EINVAL;
+ }
+
+ if (!(bp->port.supported & SUPPORTED_2500baseX_Full)) {
+ DP(NETIF_MSG_LINK,
+ "2.5G full not supported\n");
+ return -EINVAL;
+ }
+
+ advertising = (ADVERTISED_2500baseX_Full |
+ ADVERTISED_TP);
+ break;
+
+ case SPEED_10000:
+ if (cmd->duplex != DUPLEX_FULL) {
+ DP(NETIF_MSG_LINK, "10G half not supported\n");
+ return -EINVAL;
+ }
+
+ if (!(bp->port.supported & SUPPORTED_10000baseT_Full)) {
+ DP(NETIF_MSG_LINK, "10G full not supported\n");
+ return -EINVAL;
+ }
+
+ advertising = (ADVERTISED_10000baseT_Full |
+ ADVERTISED_FIBRE);
+ break;
+
+ default:
+ DP(NETIF_MSG_LINK, "Unsupported speed\n");
+ return -EINVAL;
+ }
+
+ bp->link_params.req_line_speed = cmd->speed;
+ bp->link_params.req_duplex = cmd->duplex;
+ bp->port.advertising = advertising;
+ }
+
+ DP(NETIF_MSG_LINK, "req_line_speed %d\n"
+ DP_LEVEL " req_duplex %d advertising 0x%x\n",
+ bp->link_params.req_line_speed, bp->link_params.req_duplex,
+ bp->port.advertising);
+
+ if (netif_running(dev)) {
+ bnx2x_stats_handle(bp, STATS_EVENT_STOP);
+ bnx2x_link_set(bp);
+ }
+
+ return 0;
+}
+
+#define IS_E1_ONLINE(info) (((info) & RI_E1_ONLINE) == RI_E1_ONLINE)
+#define IS_E1H_ONLINE(info) (((info) & RI_E1H_ONLINE) == RI_E1H_ONLINE)
+
+static int bnx2x_get_regs_len(struct net_device *dev)
+{
+ struct bnx2x *bp = netdev_priv(dev);
+ int regdump_len = 0;
+ int i;
+
+ if (CHIP_IS_E1(bp)) {
+ for (i = 0; i < REGS_COUNT; i++)
+ if (IS_E1_ONLINE(reg_addrs[i].info))
+ regdump_len += reg_addrs[i].size;
+
+ for (i = 0; i < WREGS_COUNT_E1; i++)
+ if (IS_E1_ONLINE(wreg_addrs_e1[i].info))
+ regdump_len += wreg_addrs_e1[i].size *
+ (1 + wreg_addrs_e1[i].read_regs_count);
+
+ } else { /* E1H */
+ for (i = 0; i < REGS_COUNT; i++)
+ if (IS_E1H_ONLINE(reg_addrs[i].info))
+ regdump_len += reg_addrs[i].size;
+
+ for (i = 0; i < WREGS_COUNT_E1H; i++)
+ if (IS_E1H_ONLINE(wreg_addrs_e1h[i].info))
+ regdump_len += wreg_addrs_e1h[i].size *
+ (1 + wreg_addrs_e1h[i].read_regs_count);
+ }
+ regdump_len *= 4;
+ regdump_len += sizeof(struct dump_hdr);
+
+ return regdump_len;
+}
+
+static void bnx2x_get_regs(struct net_device *dev,
+ struct ethtool_regs *regs, void *_p)
+{
+ u32 *p = _p, i, j;
+ struct bnx2x *bp = netdev_priv(dev);
+ struct dump_hdr dump_hdr = {0};
+
+ regs->version = 0;
+ memset(p, 0, regs->len);
+
+ if (!netif_running(bp->dev))
+ return;
+
+ dump_hdr.hdr_size = (sizeof(struct dump_hdr) / 4) - 1;
+ dump_hdr.dump_sign = dump_sign_all;
+ dump_hdr.xstorm_waitp = REG_RD(bp, XSTORM_WAITP_ADDR);
+ dump_hdr.tstorm_waitp = REG_RD(bp, TSTORM_WAITP_ADDR);
+ dump_hdr.ustorm_waitp = REG_RD(bp, USTORM_WAITP_ADDR);
+ dump_hdr.cstorm_waitp = REG_RD(bp, CSTORM_WAITP_ADDR);
+ dump_hdr.info = CHIP_IS_E1(bp) ? RI_E1_ONLINE : RI_E1H_ONLINE;
+
+ memcpy(p, &dump_hdr, sizeof(struct dump_hdr));
+ p += dump_hdr.hdr_size + 1;
+
+ if (CHIP_IS_E1(bp)) {
+ for (i = 0; i < REGS_COUNT; i++)
+ if (IS_E1_ONLINE(reg_addrs[i].info))
+ for (j = 0; j < reg_addrs[i].size; j++)
+ *p++ = REG_RD(bp,
+ reg_addrs[i].addr + j*4);
+
+ } else { /* E1H */
+ for (i = 0; i < REGS_COUNT; i++)
+ if (IS_E1H_ONLINE(reg_addrs[i].info))
+ for (j = 0; j < reg_addrs[i].size; j++)
+ *p++ = REG_RD(bp,
+ reg_addrs[i].addr + j*4);
+ }
+}
+
+#define PHY_FW_VER_LEN 10
+
+static void bnx2x_get_drvinfo(struct net_device *dev,
+ struct ethtool_drvinfo *info)
+{
+ struct bnx2x *bp = netdev_priv(dev);
+ u8 phy_fw_ver[PHY_FW_VER_LEN];
+
+ strcpy(info->driver, DRV_MODULE_NAME);
+ strcpy(info->version, DRV_MODULE_VERSION);
+
+ phy_fw_ver[0] = '\0';
+ if (bp->port.pmf) {
+ bnx2x_acquire_phy_lock(bp);
+ bnx2x_get_ext_phy_fw_version(&bp->link_params,
+ (bp->state != BNX2X_STATE_CLOSED),
+ phy_fw_ver, PHY_FW_VER_LEN);
+ bnx2x_release_phy_lock(bp);
+ }
+
+ strncpy(info->fw_version, bp->fw_ver, 32);
+ snprintf(info->fw_version + strlen(bp->fw_ver), 32 - strlen(bp->fw_ver),
+ "bc %d.%d.%d%s%s",
+ (bp->common.bc_ver & 0xff0000) >> 16,
+ (bp->common.bc_ver & 0xff00) >> 8,
+ (bp->common.bc_ver & 0xff),
+ ((phy_fw_ver[0] != '\0') ? " phy " : ""), phy_fw_ver);
+ strcpy(info->bus_info, pci_name(bp->pdev));
+ info->n_stats = BNX2X_NUM_STATS;
+ info->testinfo_len = BNX2X_NUM_TESTS;
+ info->eedump_len = bp->common.flash_size;
+ info->regdump_len = bnx2x_get_regs_len(dev);
+}
+
+static void bnx2x_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
+{
+ struct bnx2x *bp = netdev_priv(dev);
+
+ if (bp->flags & NO_WOL_FLAG) {
+ wol->supported = 0;
+ wol->wolopts = 0;
+ } else {
+ wol->supported = WAKE_MAGIC;
+ if (bp->wol)
+ wol->wolopts = WAKE_MAGIC;
+ else
+ wol->wolopts = 0;
+ }
+ memset(&wol->sopass, 0, sizeof(wol->sopass));
+}
+
+static int bnx2x_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
+{
+ struct bnx2x *bp = netdev_priv(dev);
+
+ if (wol->wolopts & ~WAKE_MAGIC)
+ return -EINVAL;
+
+ if (wol->wolopts & WAKE_MAGIC) {
+ if (bp->flags & NO_WOL_FLAG)
+ return -EINVAL;
+
+ bp->wol = 1;
+ } else
+ bp->wol = 0;
+
+ return 0;
+}
+
+static u32 bnx2x_get_msglevel(struct net_device *dev)
+{
+ struct bnx2x *bp = netdev_priv(dev);
+
+ return bp->msg_enable;
+}
+
+static void bnx2x_set_msglevel(struct net_device *dev, u32 level)
+{
+ struct bnx2x *bp = netdev_priv(dev);
+
+ if (capable(CAP_NET_ADMIN))
+ bp->msg_enable = level;
+}
+
+static int bnx2x_nway_reset(struct net_device *dev)
+{
+ struct bnx2x *bp = netdev_priv(dev);
+
+ if (!bp->port.pmf)
+ return 0;
+
+ if (netif_running(dev)) {
+ bnx2x_stats_handle(bp, STATS_EVENT_STOP);
+ bnx2x_link_set(bp);
+ }
+
+ return 0;
+}
+
+static u32 bnx2x_get_link(struct net_device *dev)
+{
+ struct bnx2x *bp = netdev_priv(dev);
+
+ if (bp->flags & MF_FUNC_DIS)
+ return 0;
+
+ return bp->link_vars.link_up;
+}
+
+static int bnx2x_get_eeprom_len(struct net_device *dev)
+{
+ struct bnx2x *bp = netdev_priv(dev);
+
+ return bp->common.flash_size;
+}
+
+static int bnx2x_acquire_nvram_lock(struct bnx2x *bp)
+{
+ int port = BP_PORT(bp);
+ int count, i;
+ u32 val = 0;
+
+ /* adjust timeout for emulation/FPGA */
+ count = NVRAM_TIMEOUT_COUNT;
+ if (CHIP_REV_IS_SLOW(bp))
+ count *= 100;
+
+ /* request access to nvram interface */
+ REG_WR(bp, MCP_REG_MCPR_NVM_SW_ARB,
+ (MCPR_NVM_SW_ARB_ARB_REQ_SET1 << port));
+
+ for (i = 0; i < count*10; i++) {
+ val = REG_RD(bp, MCP_REG_MCPR_NVM_SW_ARB);
+ if (val & (MCPR_NVM_SW_ARB_ARB_ARB1 << port))
+ break;
+
+ udelay(5);
+ }
+
+ if (!(val & (MCPR_NVM_SW_ARB_ARB_ARB1 << port))) {
+ DP(BNX2X_MSG_NVM, "cannot get access to nvram interface\n");
+ return -EBUSY;
+ }
+
+ return 0;
+}
+
+static int bnx2x_release_nvram_lock(struct bnx2x *bp)
+{
+ int port = BP_PORT(bp);
+ int count, i;
+ u32 val = 0;
+
+ /* adjust timeout for emulation/FPGA */
+ count = NVRAM_TIMEOUT_COUNT;
+ if (CHIP_REV_IS_SLOW(bp))
+ count *= 100;
+
+ /* relinquish nvram interface */
+ REG_WR(bp, MCP_REG_MCPR_NVM_SW_ARB,
+ (MCPR_NVM_SW_ARB_ARB_REQ_CLR1 << port));
+
+ for (i = 0; i < count*10; i++) {
+ val = REG_RD(bp, MCP_REG_MCPR_NVM_SW_ARB);
+ if (!(val & (MCPR_NVM_SW_ARB_ARB_ARB1 << port)))
+ break;
+
+ udelay(5);
+ }
+
+ if (val & (MCPR_NVM_SW_ARB_ARB_ARB1 << port)) {
+ DP(BNX2X_MSG_NVM, "cannot free access to nvram interface\n");
+ return -EBUSY;
+ }
+
+ return 0;
+}
+
+static void bnx2x_enable_nvram_access(struct bnx2x *bp)
+{
+ u32 val;
+
+ val = REG_RD(bp, MCP_REG_MCPR_NVM_ACCESS_ENABLE);
+
+ /* enable both bits, even on read */
+ REG_WR(bp, MCP_REG_MCPR_NVM_ACCESS_ENABLE,
+ (val | MCPR_NVM_ACCESS_ENABLE_EN |
+ MCPR_NVM_ACCESS_ENABLE_WR_EN));
+}
+
+static void bnx2x_disable_nvram_access(struct bnx2x *bp)
+{
+ u32 val;
+
+ val = REG_RD(bp, MCP_REG_MCPR_NVM_ACCESS_ENABLE);
+
+ /* disable both bits, even after read */
+ REG_WR(bp, MCP_REG_MCPR_NVM_ACCESS_ENABLE,
+ (val & ~(MCPR_NVM_ACCESS_ENABLE_EN |
+ MCPR_NVM_ACCESS_ENABLE_WR_EN)));
+}
+
+static int bnx2x_nvram_read_dword(struct bnx2x *bp, u32 offset, __be32 *ret_val,
+ u32 cmd_flags)
+{
+ int count, i, rc;
+ u32 val;
+
+ /* build the command word */
+ cmd_flags |= MCPR_NVM_COMMAND_DOIT;
+
+ /* need to clear DONE bit separately */
+ REG_WR(bp, MCP_REG_MCPR_NVM_COMMAND, MCPR_NVM_COMMAND_DONE);
+
+ /* address of the NVRAM to read from */
+ REG_WR(bp, MCP_REG_MCPR_NVM_ADDR,
+ (offset & MCPR_NVM_ADDR_NVM_ADDR_VALUE));
+
+ /* issue a read command */
+ REG_WR(bp, MCP_REG_MCPR_NVM_COMMAND, cmd_flags);
+
+ /* adjust timeout for emulation/FPGA */
+ count = NVRAM_TIMEOUT_COUNT;
+ if (CHIP_REV_IS_SLOW(bp))
+ count *= 100;
+
+ /* wait for completion */
+ *ret_val = 0;
+ rc = -EBUSY;
+ for (i = 0; i < count; i++) {
+ udelay(5);
+ val = REG_RD(bp, MCP_REG_MCPR_NVM_COMMAND);
+
+ if (val & MCPR_NVM_COMMAND_DONE) {
+ val = REG_RD(bp, MCP_REG_MCPR_NVM_READ);
+ /* we read nvram data in cpu order
+ * but ethtool sees it as an array of bytes
+ * converting to big-endian will do the work */
+ *ret_val = cpu_to_be32(val);
+ rc = 0;
+ break;
+ }
+ }
+
+ return rc;
+}
+
+static int bnx2x_nvram_read(struct bnx2x *bp, u32 offset, u8 *ret_buf,
+ int buf_size)
+{
+ int rc;
+ u32 cmd_flags;
+ __be32 val;
+
+ if ((offset & 0x03) || (buf_size & 0x03) || (buf_size == 0)) {
+ DP(BNX2X_MSG_NVM,
+ "Invalid parameter: offset 0x%x buf_size 0x%x\n",
+ offset, buf_size);
+ return -EINVAL;
+ }
+
+ if (offset + buf_size > bp->common.flash_size) {
+ DP(BNX2X_MSG_NVM, "Invalid parameter: offset (0x%x) +"
+ " buf_size (0x%x) > flash_size (0x%x)\n",
+ offset, buf_size, bp->common.flash_size);
+ return -EINVAL;
+ }
+
+ /* request access to nvram interface */
+ rc = bnx2x_acquire_nvram_lock(bp);
+ if (rc)
+ return rc;
+
+ /* enable access to nvram interface */
+ bnx2x_enable_nvram_access(bp);
+
+ /* read the first word(s) */
+ cmd_flags = MCPR_NVM_COMMAND_FIRST;
+ while ((buf_size > sizeof(u32)) && (rc == 0)) {
+ rc = bnx2x_nvram_read_dword(bp, offset, &val, cmd_flags);
+ memcpy(ret_buf, &val, 4);
+
+ /* advance to the next dword */
+ offset += sizeof(u32);
+ ret_buf += sizeof(u32);
+ buf_size -= sizeof(u32);
+ cmd_flags = 0;
+ }
+
+ if (rc == 0) {
+ cmd_flags |= MCPR_NVM_COMMAND_LAST;
+ rc = bnx2x_nvram_read_dword(bp, offset, &val, cmd_flags);
+ memcpy(ret_buf, &val, 4);
+ }
+
+ /* disable access to nvram interface */
+ bnx2x_disable_nvram_access(bp);
+ bnx2x_release_nvram_lock(bp);
+
+ return rc;
+}
+
+static int bnx2x_get_eeprom(struct net_device *dev,
+ struct ethtool_eeprom *eeprom, u8 *eebuf)
+{
+ struct bnx2x *bp = netdev_priv(dev);
+ int rc;
+
+ if (!netif_running(dev))
+ return -EAGAIN;
+
+ DP(BNX2X_MSG_NVM, "ethtool_eeprom: cmd %d\n"
+ DP_LEVEL " magic 0x%x offset 0x%x (%d) len 0x%x (%d)\n",
+ eeprom->cmd, eeprom->magic, eeprom->offset, eeprom->offset,
+ eeprom->len, eeprom->len);
+
+ /* parameters already validated in ethtool_get_eeprom */
+
+ rc = bnx2x_nvram_read(bp, eeprom->offset, eebuf, eeprom->len);
+
+ return rc;
+}
+
+static int bnx2x_nvram_write_dword(struct bnx2x *bp, u32 offset, u32 val,
+ u32 cmd_flags)
+{
+ int count, i, rc;
+
+ /* build the command word */
+ cmd_flags |= MCPR_NVM_COMMAND_DOIT | MCPR_NVM_COMMAND_WR;
+
+ /* need to clear DONE bit separately */
+ REG_WR(bp, MCP_REG_MCPR_NVM_COMMAND, MCPR_NVM_COMMAND_DONE);
+
+ /* write the data */
+ REG_WR(bp, MCP_REG_MCPR_NVM_WRITE, val);
+
+ /* address of the NVRAM to write to */
+ REG_WR(bp, MCP_REG_MCPR_NVM_ADDR,
+ (offset & MCPR_NVM_ADDR_NVM_ADDR_VALUE));
+
+ /* issue the write command */
+ REG_WR(bp, MCP_REG_MCPR_NVM_COMMAND, cmd_flags);
+
+ /* adjust timeout for emulation/FPGA */
+ count = NVRAM_TIMEOUT_COUNT;
+ if (CHIP_REV_IS_SLOW(bp))
+ count *= 100;
+
+ /* wait for completion */
+ rc = -EBUSY;
+ for (i = 0; i < count; i++) {
+ udelay(5);
+ val = REG_RD(bp, MCP_REG_MCPR_NVM_COMMAND);
+ if (val & MCPR_NVM_COMMAND_DONE) {
+ rc = 0;
+ break;
+ }
+ }
+
+ return rc;
+}
+
+#define BYTE_OFFSET(offset) (8 * (offset & 0x03))
+
+static int bnx2x_nvram_write1(struct bnx2x *bp, u32 offset, u8 *data_buf,
+ int buf_size)
+{
+ int rc;
+ u32 cmd_flags;
+ u32 align_offset;
+ __be32 val;
+
+ if (offset + buf_size > bp->common.flash_size) {
+ DP(BNX2X_MSG_NVM, "Invalid parameter: offset (0x%x) +"
+ " buf_size (0x%x) > flash_size (0x%x)\n",
+ offset, buf_size, bp->common.flash_size);
+ return -EINVAL;
+ }
+
+ /* request access to nvram interface */
+ rc = bnx2x_acquire_nvram_lock(bp);
+ if (rc)
+ return rc;
+
+ /* enable access to nvram interface */
+ bnx2x_enable_nvram_access(bp);
+
+ cmd_flags = (MCPR_NVM_COMMAND_FIRST | MCPR_NVM_COMMAND_LAST);
+ align_offset = (offset & ~0x03);
+ rc = bnx2x_nvram_read_dword(bp, align_offset, &val, cmd_flags);
+
+ if (rc == 0) {
+ val &= ~(0xff << BYTE_OFFSET(offset));
+ val |= (*data_buf << BYTE_OFFSET(offset));
+
+ /* nvram data is returned as an array of bytes
+ * convert it back to cpu order */
+ val = be32_to_cpu(val);
+
+ rc = bnx2x_nvram_write_dword(bp, align_offset, val,
+ cmd_flags);
+ }
+
+ /* disable access to nvram interface */
+ bnx2x_disable_nvram_access(bp);
+ bnx2x_release_nvram_lock(bp);
+
+ return rc;
+}
+
+static int bnx2x_nvram_write(struct bnx2x *bp, u32 offset, u8 *data_buf,
+ int buf_size)
+{
+ int rc;
+ u32 cmd_flags;
+ u32 val;
+ u32 written_so_far;
+
+ if (buf_size == 1) /* ethtool */
+ return bnx2x_nvram_write1(bp, offset, data_buf, buf_size);
+
+ if ((offset & 0x03) || (buf_size & 0x03) || (buf_size == 0)) {
+ DP(BNX2X_MSG_NVM,
+ "Invalid parameter: offset 0x%x buf_size 0x%x\n",
+ offset, buf_size);
+ return -EINVAL;
+ }
+
+ if (offset + buf_size > bp->common.flash_size) {
+ DP(BNX2X_MSG_NVM, "Invalid parameter: offset (0x%x) +"
+ " buf_size (0x%x) > flash_size (0x%x)\n",
+ offset, buf_size, bp->common.flash_size);
+ return -EINVAL;
+ }
+
+ /* request access to nvram interface */
+ rc = bnx2x_acquire_nvram_lock(bp);
+ if (rc)
+ return rc;
+
+ /* enable access to nvram interface */
+ bnx2x_enable_nvram_access(bp);
+
+ written_so_far = 0;
+ cmd_flags = MCPR_NVM_COMMAND_FIRST;
+ while ((written_so_far < buf_size) && (rc == 0)) {
+ if (written_so_far == (buf_size - sizeof(u32)))
+ cmd_flags |= MCPR_NVM_COMMAND_LAST;
+ else if (((offset + 4) % NVRAM_PAGE_SIZE) == 0)
+ cmd_flags |= MCPR_NVM_COMMAND_LAST;
+ else if ((offset % NVRAM_PAGE_SIZE) == 0)
+ cmd_flags |= MCPR_NVM_COMMAND_FIRST;
+
+ memcpy(&val, data_buf, 4);
+
+ rc = bnx2x_nvram_write_dword(bp, offset, val, cmd_flags);
+
+ /* advance to the next dword */
+ offset += sizeof(u32);
+ data_buf += sizeof(u32);
+ written_so_far += sizeof(u32);
+ cmd_flags = 0;
+ }
+
+ /* disable access to nvram interface */
+ bnx2x_disable_nvram_access(bp);
+ bnx2x_release_nvram_lock(bp);
+
+ return rc;
+}
+
+static int bnx2x_set_eeprom(struct net_device *dev,
+ struct ethtool_eeprom *eeprom, u8 *eebuf)
+{
+ struct bnx2x *bp = netdev_priv(dev);
+ int port = BP_PORT(bp);
+ int rc = 0;
+
+ if (!netif_running(dev))
+ return -EAGAIN;
+
+ DP(BNX2X_MSG_NVM, "ethtool_eeprom: cmd %d\n"
+ DP_LEVEL " magic 0x%x offset 0x%x (%d) len 0x%x (%d)\n",
+ eeprom->cmd, eeprom->magic, eeprom->offset, eeprom->offset,
+ eeprom->len, eeprom->len);
+
+ /* parameters already validated in ethtool_set_eeprom */
+
+ /* PHY eeprom can be accessed only by the PMF */
+ if ((eeprom->magic >= 0x50485900) && (eeprom->magic <= 0x504859FF) &&
+ !bp->port.pmf)
+ return -EINVAL;
+
+ if (eeprom->magic == 0x50485950) {
+ /* 'PHYP' (0x50485950): prepare phy for FW upgrade */
+ bnx2x_stats_handle(bp, STATS_EVENT_STOP);
+
+ bnx2x_acquire_phy_lock(bp);
+ rc |= bnx2x_link_reset(&bp->link_params,
+ &bp->link_vars, 0);
+ if (XGXS_EXT_PHY_TYPE(bp->link_params.ext_phy_config) ==
+ PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101)
+ bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_0,
+ MISC_REGISTERS_GPIO_HIGH, port);
+ bnx2x_release_phy_lock(bp);
+ bnx2x_link_report(bp);
+
+ } else if (eeprom->magic == 0x50485952) {
+ /* 'PHYR' (0x50485952): re-init link after FW upgrade */
+ if (bp->state == BNX2X_STATE_OPEN) {
+ bnx2x_acquire_phy_lock(bp);
+ rc |= bnx2x_link_reset(&bp->link_params,
+ &bp->link_vars, 1);
+
+ rc |= bnx2x_phy_init(&bp->link_params,
+ &bp->link_vars);
+ bnx2x_release_phy_lock(bp);
+ bnx2x_calc_fc_adv(bp);
+ }
+ } else if (eeprom->magic == 0x53985943) {
+ /* 'PHYC' (0x53985943): PHY FW upgrade completed */
+ if (XGXS_EXT_PHY_TYPE(bp->link_params.ext_phy_config) ==
+ PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101) {
+ u8 ext_phy_addr =
+ XGXS_EXT_PHY_ADDR(bp->link_params.ext_phy_config);
+
+ /* DSP Remove Download Mode */
+ bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_0,
+ MISC_REGISTERS_GPIO_LOW, port);
+
+ bnx2x_acquire_phy_lock(bp);
+
+ bnx2x_sfx7101_sp_sw_reset(bp, port, ext_phy_addr);
+
+ /* wait 0.5 sec to allow it to run */
+ msleep(500);
+ bnx2x_ext_phy_hw_reset(bp, port);
+ msleep(500);
+ bnx2x_release_phy_lock(bp);
+ }
+ } else
+ rc = bnx2x_nvram_write(bp, eeprom->offset, eebuf, eeprom->len);
+
+ return rc;
+}
+static int bnx2x_get_coalesce(struct net_device *dev,
+ struct ethtool_coalesce *coal)
+{
+ struct bnx2x *bp = netdev_priv(dev);
+
+ memset(coal, 0, sizeof(struct ethtool_coalesce));
+
+ coal->rx_coalesce_usecs = bp->rx_ticks;
+ coal->tx_coalesce_usecs = bp->tx_ticks;
+
+ return 0;
+}
+
+static int bnx2x_set_coalesce(struct net_device *dev,
+ struct ethtool_coalesce *coal)
+{
+ struct bnx2x *bp = netdev_priv(dev);
+
+ bp->rx_ticks = (u16)coal->rx_coalesce_usecs;
+ if (bp->rx_ticks > BNX2X_MAX_COALESCE_TOUT)
+ bp->rx_ticks = BNX2X_MAX_COALESCE_TOUT;
+
+ bp->tx_ticks = (u16)coal->tx_coalesce_usecs;
+ if (bp->tx_ticks > BNX2X_MAX_COALESCE_TOUT)
+ bp->tx_ticks = BNX2X_MAX_COALESCE_TOUT;
+
+ if (netif_running(dev))
+ bnx2x_update_coalesce(bp);
+
+ return 0;
+}
+
+static void bnx2x_get_ringparam(struct net_device *dev,
+ struct ethtool_ringparam *ering)
+{
+ struct bnx2x *bp = netdev_priv(dev);
+
+ ering->rx_max_pending = MAX_RX_AVAIL;
+ ering->rx_mini_max_pending = 0;
+ ering->rx_jumbo_max_pending = 0;
+
+ ering->rx_pending = bp->rx_ring_size;
+ ering->rx_mini_pending = 0;
+ ering->rx_jumbo_pending = 0;
+
+ ering->tx_max_pending = MAX_TX_AVAIL;
+ ering->tx_pending = bp->tx_ring_size;
+}
+
+static int bnx2x_set_ringparam(struct net_device *dev,
+ struct ethtool_ringparam *ering)
+{
+ struct bnx2x *bp = netdev_priv(dev);
+ int rc = 0;
+
+ if (bp->recovery_state != BNX2X_RECOVERY_DONE) {
+ printk(KERN_ERR "Handling parity error recovery. Try again later\n");
+ return -EAGAIN;
+ }
+
+ if ((ering->rx_pending > MAX_RX_AVAIL) ||
+ (ering->tx_pending > MAX_TX_AVAIL) ||
+ (ering->tx_pending <= MAX_SKB_FRAGS + 4))
+ return -EINVAL;
+
+ bp->rx_ring_size = ering->rx_pending;
+ bp->tx_ring_size = ering->tx_pending;
+
+ if (netif_running(dev)) {
+ bnx2x_nic_unload(bp, UNLOAD_NORMAL);
+ rc = bnx2x_nic_load(bp, LOAD_NORMAL);
+ }
+
+ return rc;
+}
+
+static void bnx2x_get_pauseparam(struct net_device *dev,
+ struct ethtool_pauseparam *epause)
+{
+ struct bnx2x *bp = netdev_priv(dev);
+
+ epause->autoneg = (bp->link_params.req_flow_ctrl ==
+ BNX2X_FLOW_CTRL_AUTO) &&
+ (bp->link_params.req_line_speed == SPEED_AUTO_NEG);
+
+ epause->rx_pause = ((bp->link_vars.flow_ctrl & BNX2X_FLOW_CTRL_RX) ==
+ BNX2X_FLOW_CTRL_RX);
+ epause->tx_pause = ((bp->link_vars.flow_ctrl & BNX2X_FLOW_CTRL_TX) ==
+ BNX2X_FLOW_CTRL_TX);
+
+ DP(NETIF_MSG_LINK, "ethtool_pauseparam: cmd %d\n"
+ DP_LEVEL " autoneg %d rx_pause %d tx_pause %d\n",
+ epause->cmd, epause->autoneg, epause->rx_pause, epause->tx_pause);
+}
+
+static int bnx2x_set_pauseparam(struct net_device *dev,
+ struct ethtool_pauseparam *epause)
+{
+ struct bnx2x *bp = netdev_priv(dev);
+
+ if (IS_E1HMF(bp))
+ return 0;
+
+ DP(NETIF_MSG_LINK, "ethtool_pauseparam: cmd %d\n"
+ DP_LEVEL " autoneg %d rx_pause %d tx_pause %d\n",
+ epause->cmd, epause->autoneg, epause->rx_pause, epause->tx_pause);
+
+ bp->link_params.req_flow_ctrl = BNX2X_FLOW_CTRL_AUTO;
+
+ if (epause->rx_pause)
+ bp->link_params.req_flow_ctrl |= BNX2X_FLOW_CTRL_RX;
+
+ if (epause->tx_pause)
+ bp->link_params.req_flow_ctrl |= BNX2X_FLOW_CTRL_TX;
+
+ if (bp->link_params.req_flow_ctrl == BNX2X_FLOW_CTRL_AUTO)
+ bp->link_params.req_flow_ctrl = BNX2X_FLOW_CTRL_NONE;
+
+ if (epause->autoneg) {
+ if (!(bp->port.supported & SUPPORTED_Autoneg)) {
+ DP(NETIF_MSG_LINK, "autoneg not supported\n");
+ return -EINVAL;
+ }
+
+ if (bp->link_params.req_line_speed == SPEED_AUTO_NEG)
+ bp->link_params.req_flow_ctrl = BNX2X_FLOW_CTRL_AUTO;
+ }
+
+ DP(NETIF_MSG_LINK,
+ "req_flow_ctrl 0x%x\n", bp->link_params.req_flow_ctrl);
+
+ if (netif_running(dev)) {
+ bnx2x_stats_handle(bp, STATS_EVENT_STOP);
+ bnx2x_link_set(bp);
+ }
+
+ return 0;
+}
+
+static int bnx2x_set_flags(struct net_device *dev, u32 data)
+{
+ struct bnx2x *bp = netdev_priv(dev);
+ int changed = 0;
+ int rc = 0;
+
+ if (data & ~(ETH_FLAG_LRO | ETH_FLAG_RXHASH))
+ return -EINVAL;
+
+ if (bp->recovery_state != BNX2X_RECOVERY_DONE) {
+ printk(KERN_ERR "Handling parity error recovery. Try again later\n");
+ return -EAGAIN;
+ }
+
+ /* TPA requires Rx CSUM offloading */
+ if ((data & ETH_FLAG_LRO) && bp->rx_csum) {
+ if (!bp->disable_tpa) {
+ if (!(dev->features & NETIF_F_LRO)) {
+ dev->features |= NETIF_F_LRO;
+ bp->flags |= TPA_ENABLE_FLAG;
+ changed = 1;
+ }
+ } else
+ rc = -EINVAL;
+ } else if (dev->features & NETIF_F_LRO) {
+ dev->features &= ~NETIF_F_LRO;
+ bp->flags &= ~TPA_ENABLE_FLAG;
+ changed = 1;
+ }
+
+ if (data & ETH_FLAG_RXHASH)
+ dev->features |= NETIF_F_RXHASH;
+ else
+ dev->features &= ~NETIF_F_RXHASH;
+
+ if (changed && netif_running(dev)) {
+ bnx2x_nic_unload(bp, UNLOAD_NORMAL);
+ rc = bnx2x_nic_load(bp, LOAD_NORMAL);
+ }
+
+ return rc;
+}
+
+static u32 bnx2x_get_rx_csum(struct net_device *dev)
+{
+ struct bnx2x *bp = netdev_priv(dev);
+
+ return bp->rx_csum;
+}
+
+static int bnx2x_set_rx_csum(struct net_device *dev, u32 data)
+{
+ struct bnx2x *bp = netdev_priv(dev);
+ int rc = 0;
+
+ if (bp->recovery_state != BNX2X_RECOVERY_DONE) {
+ printk(KERN_ERR "Handling parity error recovery. Try again later\n");
+ return -EAGAIN;
+ }
+
+ bp->rx_csum = data;
+
+ /* Disable TPA, when Rx CSUM is disabled. Otherwise all
+ TPA'ed packets will be discarded due to wrong TCP CSUM */
+ if (!data) {
+ u32 flags = ethtool_op_get_flags(dev);
+
+ rc = bnx2x_set_flags(dev, (flags & ~ETH_FLAG_LRO));
+ }
+
+ return rc;
+}
+
+static int bnx2x_set_tso(struct net_device *dev, u32 data)
+{
+ if (data) {
+ dev->features |= (NETIF_F_TSO | NETIF_F_TSO_ECN);
+ dev->features |= NETIF_F_TSO6;
+ } else {
+ dev->features &= ~(NETIF_F_TSO | NETIF_F_TSO_ECN);
+ dev->features &= ~NETIF_F_TSO6;
+ }
+
+ return 0;
+}
+
+static const struct {
+ char string[ETH_GSTRING_LEN];
+} bnx2x_tests_str_arr[BNX2X_NUM_TESTS] = {
+ { "register_test (offline)" },
+ { "memory_test (offline)" },
+ { "loopback_test (offline)" },
+ { "nvram_test (online)" },
+ { "interrupt_test (online)" },
+ { "link_test (online)" },
+ { "idle check (online)" }
+};
+
+static int bnx2x_test_registers(struct bnx2x *bp)
+{
+ int idx, i, rc = -ENODEV;
+ u32 wr_val = 0;
+ int port = BP_PORT(bp);
+ static const struct {
+ u32 offset0;
+ u32 offset1;
+ u32 mask;
+ } reg_tbl[] = {
+/* 0 */ { BRB1_REG_PAUSE_LOW_THRESHOLD_0, 4, 0x000003ff },
+ { DORQ_REG_DB_ADDR0, 4, 0xffffffff },
+ { HC_REG_AGG_INT_0, 4, 0x000003ff },
+ { PBF_REG_MAC_IF0_ENABLE, 4, 0x00000001 },
+ { PBF_REG_P0_INIT_CRD, 4, 0x000007ff },
+ { PRS_REG_CID_PORT_0, 4, 0x00ffffff },
+ { PXP2_REG_PSWRQ_CDU0_L2P, 4, 0x000fffff },
+ { PXP2_REG_RQ_CDU0_EFIRST_MEM_ADDR, 8, 0x0003ffff },
+ { PXP2_REG_PSWRQ_TM0_L2P, 4, 0x000fffff },
+ { PXP2_REG_RQ_USDM0_EFIRST_MEM_ADDR, 8, 0x0003ffff },
+/* 10 */ { PXP2_REG_PSWRQ_TSDM0_L2P, 4, 0x000fffff },
+ { QM_REG_CONNNUM_0, 4, 0x000fffff },
+ { TM_REG_LIN0_MAX_ACTIVE_CID, 4, 0x0003ffff },
+ { SRC_REG_KEYRSS0_0, 40, 0xffffffff },
+ { SRC_REG_KEYRSS0_7, 40, 0xffffffff },
+ { XCM_REG_WU_DA_SET_TMR_CNT_FLG_CMD00, 4, 0x00000001 },
+ { XCM_REG_WU_DA_CNT_CMD00, 4, 0x00000003 },
+ { XCM_REG_GLB_DEL_ACK_MAX_CNT_0, 4, 0x000000ff },
+ { NIG_REG_LLH0_T_BIT, 4, 0x00000001 },
+ { NIG_REG_EMAC0_IN_EN, 4, 0x00000001 },
+/* 20 */ { NIG_REG_BMAC0_IN_EN, 4, 0x00000001 },
+ { NIG_REG_XCM0_OUT_EN, 4, 0x00000001 },
+ { NIG_REG_BRB0_OUT_EN, 4, 0x00000001 },
+ { NIG_REG_LLH0_XCM_MASK, 4, 0x00000007 },
+ { NIG_REG_LLH0_ACPI_PAT_6_LEN, 68, 0x000000ff },
+ { NIG_REG_LLH0_ACPI_PAT_0_CRC, 68, 0xffffffff },
+ { NIG_REG_LLH0_DEST_MAC_0_0, 160, 0xffffffff },
+ { NIG_REG_LLH0_DEST_IP_0_1, 160, 0xffffffff },
+ { NIG_REG_LLH0_IPV4_IPV6_0, 160, 0x00000001 },
+ { NIG_REG_LLH0_DEST_UDP_0, 160, 0x0000ffff },
+/* 30 */ { NIG_REG_LLH0_DEST_TCP_0, 160, 0x0000ffff },
+ { NIG_REG_LLH0_VLAN_ID_0, 160, 0x00000fff },
+ { NIG_REG_XGXS_SERDES0_MODE_SEL, 4, 0x00000001 },
+ { NIG_REG_LED_CONTROL_OVERRIDE_TRAFFIC_P0, 4, 0x00000001 },
+ { NIG_REG_STATUS_INTERRUPT_PORT0, 4, 0x07ffffff },
+ { NIG_REG_XGXS0_CTRL_EXTREMOTEMDIOST, 24, 0x00000001 },
+ { NIG_REG_SERDES0_CTRL_PHY_ADDR, 16, 0x0000001f },
+
+ { 0xffffffff, 0, 0x00000000 }
+ };
+
+ if (!netif_running(bp->dev))
+ return rc;
+
+ /* Repeat the test twice:
+ First by writing 0x00000000, second by writing 0xffffffff */
+ for (idx = 0; idx < 2; idx++) {
+
+ switch (idx) {
+ case 0:
+ wr_val = 0;
+ break;
+ case 1:
+ wr_val = 0xffffffff;
+ break;
+ }
+
+ for (i = 0; reg_tbl[i].offset0 != 0xffffffff; i++) {
+ u32 offset, mask, save_val, val;
+
+ offset = reg_tbl[i].offset0 + port*reg_tbl[i].offset1;
+ mask = reg_tbl[i].mask;
+
+ save_val = REG_RD(bp, offset);
+
+ REG_WR(bp, offset, (wr_val & mask));
+ val = REG_RD(bp, offset);
+
+ /* Restore the original register's value */
+ REG_WR(bp, offset, save_val);
+
+ /* verify value is as expected */
+ if ((val & mask) != (wr_val & mask)) {
+ DP(NETIF_MSG_PROBE,
+ "offset 0x%x: val 0x%x != 0x%x mask 0x%x\n",
+ offset, val, wr_val, mask);
+ goto test_reg_exit;
+ }
+ }
+ }
+
+ rc = 0;
+
+test_reg_exit:
+ return rc;
+}
+
+static int bnx2x_test_memory(struct bnx2x *bp)
+{
+ int i, j, rc = -ENODEV;
+ u32 val;
+ static const struct {
+ u32 offset;
+ int size;
+ } mem_tbl[] = {
+ { CCM_REG_XX_DESCR_TABLE, CCM_REG_XX_DESCR_TABLE_SIZE },
+ { CFC_REG_ACTIVITY_COUNTER, CFC_REG_ACTIVITY_COUNTER_SIZE },
+ { CFC_REG_LINK_LIST, CFC_REG_LINK_LIST_SIZE },
+ { DMAE_REG_CMD_MEM, DMAE_REG_CMD_MEM_SIZE },
+ { TCM_REG_XX_DESCR_TABLE, TCM_REG_XX_DESCR_TABLE_SIZE },
+ { UCM_REG_XX_DESCR_TABLE, UCM_REG_XX_DESCR_TABLE_SIZE },
+ { XCM_REG_XX_DESCR_TABLE, XCM_REG_XX_DESCR_TABLE_SIZE },
+
+ { 0xffffffff, 0 }
+ };
+ static const struct {
+ char *name;
+ u32 offset;
+ u32 e1_mask;
+ u32 e1h_mask;
+ } prty_tbl[] = {
+ { "CCM_PRTY_STS", CCM_REG_CCM_PRTY_STS, 0x3ffc0, 0 },
+ { "CFC_PRTY_STS", CFC_REG_CFC_PRTY_STS, 0x2, 0x2 },
+ { "DMAE_PRTY_STS", DMAE_REG_DMAE_PRTY_STS, 0, 0 },
+ { "TCM_PRTY_STS", TCM_REG_TCM_PRTY_STS, 0x3ffc0, 0 },
+ { "UCM_PRTY_STS", UCM_REG_UCM_PRTY_STS, 0x3ffc0, 0 },
+ { "XCM_PRTY_STS", XCM_REG_XCM_PRTY_STS, 0x3ffc1, 0 },
+
+ { NULL, 0xffffffff, 0, 0 }
+ };
+
+ if (!netif_running(bp->dev))
+ return rc;
+
+ /* Go through all the memories */
+ for (i = 0; mem_tbl[i].offset != 0xffffffff; i++)
+ for (j = 0; j < mem_tbl[i].size; j++)
+ REG_RD(bp, mem_tbl[i].offset + j*4);
+
+ /* Check the parity status */
+ for (i = 0; prty_tbl[i].offset != 0xffffffff; i++) {
+ val = REG_RD(bp, prty_tbl[i].offset);
+ if ((CHIP_IS_E1(bp) && (val & ~(prty_tbl[i].e1_mask))) ||
+ (CHIP_IS_E1H(bp) && (val & ~(prty_tbl[i].e1h_mask)))) {
+ DP(NETIF_MSG_HW,
+ "%s is 0x%x\n", prty_tbl[i].name, val);
+ goto test_mem_exit;
+ }
+ }
+
+ rc = 0;
+
+test_mem_exit:
+ return rc;
+}
+
+static void bnx2x_wait_for_link(struct bnx2x *bp, u8 link_up)
+{
+ int cnt = 1000;
+
+ if (link_up)
+ while (bnx2x_link_test(bp) && cnt--)
+ msleep(10);
+}
+
+static int bnx2x_run_loopback(struct bnx2x *bp, int loopback_mode, u8 link_up)
+{
+ unsigned int pkt_size, num_pkts, i;
+ struct sk_buff *skb;
+ unsigned char *packet;
+ struct bnx2x_fastpath *fp_rx = &bp->fp[0];
+ struct bnx2x_fastpath *fp_tx = &bp->fp[0];
+ u16 tx_start_idx, tx_idx;
+ u16 rx_start_idx, rx_idx;
+ u16 pkt_prod, bd_prod;
+ struct sw_tx_bd *tx_buf;
+ struct eth_tx_start_bd *tx_start_bd;
+ struct eth_tx_parse_bd *pbd = NULL;
+ dma_addr_t mapping;
+ union eth_rx_cqe *cqe;
+ u8 cqe_fp_flags;
+ struct sw_rx_bd *rx_buf;
+ u16 len;
+ int rc = -ENODEV;
+
+ /* check the loopback mode */
+ switch (loopback_mode) {
+ case BNX2X_PHY_LOOPBACK:
+ if (bp->link_params.loopback_mode != LOOPBACK_XGXS_10)
+ return -EINVAL;
+ break;
+ case BNX2X_MAC_LOOPBACK:
+ bp->link_params.loopback_mode = LOOPBACK_BMAC;
+ bnx2x_phy_init(&bp->link_params, &bp->link_vars);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* prepare the loopback packet */
+ pkt_size = (((bp->dev->mtu < ETH_MAX_PACKET_SIZE) ?
+ bp->dev->mtu : ETH_MAX_PACKET_SIZE) + ETH_HLEN);
+ skb = netdev_alloc_skb(bp->dev, bp->rx_buf_size);
+ if (!skb) {
+ rc = -ENOMEM;
+ goto test_loopback_exit;
+ }
+ packet = skb_put(skb, pkt_size);
+ memcpy(packet, bp->dev->dev_addr, ETH_ALEN);
+ memset(packet + ETH_ALEN, 0, ETH_ALEN);
+ memset(packet + 2*ETH_ALEN, 0x77, (ETH_HLEN - 2*ETH_ALEN));
+ for (i = ETH_HLEN; i < pkt_size; i++)
+ packet[i] = (unsigned char) (i & 0xff);
+
+ /* send the loopback packet */
+ num_pkts = 0;
+ tx_start_idx = le16_to_cpu(*fp_tx->tx_cons_sb);
+ rx_start_idx = le16_to_cpu(*fp_rx->rx_cons_sb);
+
+ pkt_prod = fp_tx->tx_pkt_prod++;
+ tx_buf = &fp_tx->tx_buf_ring[TX_BD(pkt_prod)];
+ tx_buf->first_bd = fp_tx->tx_bd_prod;
+ tx_buf->skb = skb;
+ tx_buf->flags = 0;
+
+ bd_prod = TX_BD(fp_tx->tx_bd_prod);
+ tx_start_bd = &fp_tx->tx_desc_ring[bd_prod].start_bd;
+ mapping = dma_map_single(&bp->pdev->dev, skb->data,
+ skb_headlen(skb), DMA_TO_DEVICE);
+ tx_start_bd->addr_hi = cpu_to_le32(U64_HI(mapping));
+ tx_start_bd->addr_lo = cpu_to_le32(U64_LO(mapping));
+ tx_start_bd->nbd = cpu_to_le16(2); /* start + pbd */
+ tx_start_bd->nbytes = cpu_to_le16(skb_headlen(skb));
+ tx_start_bd->vlan = cpu_to_le16(pkt_prod);
+ tx_start_bd->bd_flags.as_bitfield = ETH_TX_BD_FLAGS_START_BD;
+ tx_start_bd->general_data = ((UNICAST_ADDRESS <<
+ ETH_TX_START_BD_ETH_ADDR_TYPE_SHIFT) | 1);
+
+ /* turn on parsing and get a BD */
+ bd_prod = TX_BD(NEXT_TX_IDX(bd_prod));
+ pbd = &fp_tx->tx_desc_ring[bd_prod].parse_bd;
+
+ memset(pbd, 0, sizeof(struct eth_tx_parse_bd));
+
+ wmb();
+
+ fp_tx->tx_db.data.prod += 2;
+ barrier();
+ DOORBELL(bp, fp_tx->index, fp_tx->tx_db.raw);
+
+ mmiowb();
+
+ num_pkts++;
+ fp_tx->tx_bd_prod += 2; /* start + pbd */
+
+ udelay(100);
+
+ tx_idx = le16_to_cpu(*fp_tx->tx_cons_sb);
+ if (tx_idx != tx_start_idx + num_pkts)
+ goto test_loopback_exit;
+
+ rx_idx = le16_to_cpu(*fp_rx->rx_cons_sb);
+ if (rx_idx != rx_start_idx + num_pkts)
+ goto test_loopback_exit;
+
+ cqe = &fp_rx->rx_comp_ring[RCQ_BD(fp_rx->rx_comp_cons)];
+ cqe_fp_flags = cqe->fast_path_cqe.type_error_flags;
+ if (CQE_TYPE(cqe_fp_flags) || (cqe_fp_flags & ETH_RX_ERROR_FALGS))
+ goto test_loopback_rx_exit;
+
+ len = le16_to_cpu(cqe->fast_path_cqe.pkt_len);
+ if (len != pkt_size)
+ goto test_loopback_rx_exit;
+
+ rx_buf = &fp_rx->rx_buf_ring[RX_BD(fp_rx->rx_bd_cons)];
+ skb = rx_buf->skb;
+ skb_reserve(skb, cqe->fast_path_cqe.placement_offset);
+ for (i = ETH_HLEN; i < pkt_size; i++)
+ if (*(skb->data + i) != (unsigned char) (i & 0xff))
+ goto test_loopback_rx_exit;
+
+ rc = 0;
+
+test_loopback_rx_exit:
+
+ fp_rx->rx_bd_cons = NEXT_RX_IDX(fp_rx->rx_bd_cons);
+ fp_rx->rx_bd_prod = NEXT_RX_IDX(fp_rx->rx_bd_prod);
+ fp_rx->rx_comp_cons = NEXT_RCQ_IDX(fp_rx->rx_comp_cons);
+ fp_rx->rx_comp_prod = NEXT_RCQ_IDX(fp_rx->rx_comp_prod);
+
+ /* Update producers */
+ bnx2x_update_rx_prod(bp, fp_rx, fp_rx->rx_bd_prod, fp_rx->rx_comp_prod,
+ fp_rx->rx_sge_prod);
+
+test_loopback_exit:
+ bp->link_params.loopback_mode = LOOPBACK_NONE;
+
+ return rc;
+}
+
+static int bnx2x_test_loopback(struct bnx2x *bp, u8 link_up)
+{
+ int rc = 0, res;
+
+ if (BP_NOMCP(bp))
+ return rc;
+
+ if (!netif_running(bp->dev))
+ return BNX2X_LOOPBACK_FAILED;
+
+ bnx2x_netif_stop(bp, 1);
+ bnx2x_acquire_phy_lock(bp);
+
+ res = bnx2x_run_loopback(bp, BNX2X_PHY_LOOPBACK, link_up);
+ if (res) {
+ DP(NETIF_MSG_PROBE, " PHY loopback failed (res %d)\n", res);
+ rc |= BNX2X_PHY_LOOPBACK_FAILED;
+ }
+
+ res = bnx2x_run_loopback(bp, BNX2X_MAC_LOOPBACK, link_up);
+ if (res) {
+ DP(NETIF_MSG_PROBE, " MAC loopback failed (res %d)\n", res);
+ rc |= BNX2X_MAC_LOOPBACK_FAILED;
+ }
+
+ bnx2x_release_phy_lock(bp);
+ bnx2x_netif_start(bp);
+
+ return rc;
+}
+
+#define CRC32_RESIDUAL 0xdebb20e3
+
+static int bnx2x_test_nvram(struct bnx2x *bp)
+{
+ static const struct {
+ int offset;
+ int size;
+ } nvram_tbl[] = {
+ { 0, 0x14 }, /* bootstrap */
+ { 0x14, 0xec }, /* dir */
+ { 0x100, 0x350 }, /* manuf_info */
+ { 0x450, 0xf0 }, /* feature_info */
+ { 0x640, 0x64 }, /* upgrade_key_info */
+ { 0x6a4, 0x64 },
+ { 0x708, 0x70 }, /* manuf_key_info */
+ { 0x778, 0x70 },
+ { 0, 0 }
+ };
+ __be32 buf[0x350 / 4];
+ u8 *data = (u8 *)buf;
+ int i, rc;
+ u32 magic, crc;
+
+ if (BP_NOMCP(bp))
+ return 0;
+
+ rc = bnx2x_nvram_read(bp, 0, data, 4);
+ if (rc) {
+ DP(NETIF_MSG_PROBE, "magic value read (rc %d)\n", rc);
+ goto test_nvram_exit;
+ }
+
+ magic = be32_to_cpu(buf[0]);
+ if (magic != 0x669955aa) {
+ DP(NETIF_MSG_PROBE, "magic value (0x%08x)\n", magic);
+ rc = -ENODEV;
+ goto test_nvram_exit;
+ }
+
+ for (i = 0; nvram_tbl[i].size; i++) {
+
+ rc = bnx2x_nvram_read(bp, nvram_tbl[i].offset, data,
+ nvram_tbl[i].size);
+ if (rc) {
+ DP(NETIF_MSG_PROBE,
+ "nvram_tbl[%d] read data (rc %d)\n", i, rc);
+ goto test_nvram_exit;
+ }
+
+ crc = ether_crc_le(nvram_tbl[i].size, data);
+ if (crc != CRC32_RESIDUAL) {
+ DP(NETIF_MSG_PROBE,
+ "nvram_tbl[%d] crc value (0x%08x)\n", i, crc);
+ rc = -ENODEV;
+ goto test_nvram_exit;
+ }
+ }
+
+test_nvram_exit:
+ return rc;
+}
+
+static int bnx2x_test_intr(struct bnx2x *bp)
+{
+ struct mac_configuration_cmd *config = bnx2x_sp(bp, mac_config);
+ int i, rc;
+
+ if (!netif_running(bp->dev))
+ return -ENODEV;
+
+ config->hdr.length = 0;
+ if (CHIP_IS_E1(bp))
+ /* use last unicast entries */
+ config->hdr.offset = (BP_PORT(bp) ? 63 : 31);
+ else
+ config->hdr.offset = BP_FUNC(bp);
+ config->hdr.client_id = bp->fp->cl_id;
+ config->hdr.reserved1 = 0;
+
+ bp->set_mac_pending++;
+ smp_wmb();
+ rc = bnx2x_sp_post(bp, RAMROD_CMD_ID_ETH_SET_MAC, 0,
+ U64_HI(bnx2x_sp_mapping(bp, mac_config)),
+ U64_LO(bnx2x_sp_mapping(bp, mac_config)), 0);
+ if (rc == 0) {
+ for (i = 0; i < 10; i++) {
+ if (!bp->set_mac_pending)
+ break;
+ smp_rmb();
+ msleep_interruptible(10);
+ }
+ if (i == 10)
+ rc = -ENODEV;
+ }
+
+ return rc;
+}
+
+static void bnx2x_self_test(struct net_device *dev,
+ struct ethtool_test *etest, u64 *buf)
+{
+ struct bnx2x *bp = netdev_priv(dev);
+
+ if (bp->recovery_state != BNX2X_RECOVERY_DONE) {
+ printk(KERN_ERR "Handling parity error recovery. Try again later\n");
+ etest->flags |= ETH_TEST_FL_FAILED;
+ return;
+ }
+
+ memset(buf, 0, sizeof(u64) * BNX2X_NUM_TESTS);
+
+ if (!netif_running(dev))
+ return;
+
+ /* offline tests are not supported in MF mode */
+ if (IS_E1HMF(bp))
+ etest->flags &= ~ETH_TEST_FL_OFFLINE;
+
+ if (etest->flags & ETH_TEST_FL_OFFLINE) {
+ int port = BP_PORT(bp);
+ u32 val;
+ u8 link_up;
+
+ /* save current value of input enable for TX port IF */
+ val = REG_RD(bp, NIG_REG_EGRESS_UMP0_IN_EN + port*4);
+ /* disable input for TX port IF */
+ REG_WR(bp, NIG_REG_EGRESS_UMP0_IN_EN + port*4, 0);
+
+ link_up = (bnx2x_link_test(bp) == 0);
+ bnx2x_nic_unload(bp, UNLOAD_NORMAL);
+ bnx2x_nic_load(bp, LOAD_DIAG);
+ /* wait until link state is restored */
+ bnx2x_wait_for_link(bp, link_up);
+
+ if (bnx2x_test_registers(bp) != 0) {
+ buf[0] = 1;
+ etest->flags |= ETH_TEST_FL_FAILED;
+ }
+ if (bnx2x_test_memory(bp) != 0) {
+ buf[1] = 1;
+ etest->flags |= ETH_TEST_FL_FAILED;
+ }
+ buf[2] = bnx2x_test_loopback(bp, link_up);
+ if (buf[2] != 0)
+ etest->flags |= ETH_TEST_FL_FAILED;
+
+ bnx2x_nic_unload(bp, UNLOAD_NORMAL);
+
+ /* restore input for TX port IF */
+ REG_WR(bp, NIG_REG_EGRESS_UMP0_IN_EN + port*4, val);
+
+ bnx2x_nic_load(bp, LOAD_NORMAL);
+ /* wait until link state is restored */
+ bnx2x_wait_for_link(bp, link_up);
+ }
+ if (bnx2x_test_nvram(bp) != 0) {
+ buf[3] = 1;
+ etest->flags |= ETH_TEST_FL_FAILED;
+ }
+ if (bnx2x_test_intr(bp) != 0) {
+ buf[4] = 1;
+ etest->flags |= ETH_TEST_FL_FAILED;
+ }
+ if (bp->port.pmf)
+ if (bnx2x_link_test(bp) != 0) {
+ buf[5] = 1;
+ etest->flags |= ETH_TEST_FL_FAILED;
+ }
+
+#ifdef BNX2X_EXTRA_DEBUG
+ bnx2x_panic_dump(bp);
+#endif
+}
+
+static const struct {
+ long offset;
+ int size;
+ u8 string[ETH_GSTRING_LEN];
+} bnx2x_q_stats_arr[BNX2X_NUM_Q_STATS] = {
+/* 1 */ { Q_STATS_OFFSET32(total_bytes_received_hi), 8, "[%d]: rx_bytes" },
+ { Q_STATS_OFFSET32(error_bytes_received_hi),
+ 8, "[%d]: rx_error_bytes" },
+ { Q_STATS_OFFSET32(total_unicast_packets_received_hi),
+ 8, "[%d]: rx_ucast_packets" },
+ { Q_STATS_OFFSET32(total_multicast_packets_received_hi),
+ 8, "[%d]: rx_mcast_packets" },
+ { Q_STATS_OFFSET32(total_broadcast_packets_received_hi),
+ 8, "[%d]: rx_bcast_packets" },
+ { Q_STATS_OFFSET32(no_buff_discard_hi), 8, "[%d]: rx_discards" },
+ { Q_STATS_OFFSET32(rx_err_discard_pkt),
+ 4, "[%d]: rx_phy_ip_err_discards"},
+ { Q_STATS_OFFSET32(rx_skb_alloc_failed),
+ 4, "[%d]: rx_skb_alloc_discard" },
+ { Q_STATS_OFFSET32(hw_csum_err), 4, "[%d]: rx_csum_offload_errors" },
+
+/* 10 */{ Q_STATS_OFFSET32(total_bytes_transmitted_hi), 8, "[%d]: tx_bytes" },
+ { Q_STATS_OFFSET32(total_unicast_packets_transmitted_hi),
+ 8, "[%d]: tx_ucast_packets" },
+ { Q_STATS_OFFSET32(total_multicast_packets_transmitted_hi),
+ 8, "[%d]: tx_mcast_packets" },
+ { Q_STATS_OFFSET32(total_broadcast_packets_transmitted_hi),
+ 8, "[%d]: tx_bcast_packets" }
+};
+
+static const struct {
+ long offset;
+ int size;
+ u32 flags;
+#define STATS_FLAGS_PORT 1
+#define STATS_FLAGS_FUNC 2
+#define STATS_FLAGS_BOTH (STATS_FLAGS_FUNC | STATS_FLAGS_PORT)
+ u8 string[ETH_GSTRING_LEN];
+} bnx2x_stats_arr[BNX2X_NUM_STATS] = {
+/* 1 */ { STATS_OFFSET32(total_bytes_received_hi),
+ 8, STATS_FLAGS_BOTH, "rx_bytes" },
+ { STATS_OFFSET32(error_bytes_received_hi),
+ 8, STATS_FLAGS_BOTH, "rx_error_bytes" },
+ { STATS_OFFSET32(total_unicast_packets_received_hi),
+ 8, STATS_FLAGS_BOTH, "rx_ucast_packets" },
+ { STATS_OFFSET32(total_multicast_packets_received_hi),
+ 8, STATS_FLAGS_BOTH, "rx_mcast_packets" },
+ { STATS_OFFSET32(total_broadcast_packets_received_hi),
+ 8, STATS_FLAGS_BOTH, "rx_bcast_packets" },
+ { STATS_OFFSET32(rx_stat_dot3statsfcserrors_hi),
+ 8, STATS_FLAGS_PORT, "rx_crc_errors" },
+ { STATS_OFFSET32(rx_stat_dot3statsalignmenterrors_hi),
+ 8, STATS_FLAGS_PORT, "rx_align_errors" },
+ { STATS_OFFSET32(rx_stat_etherstatsundersizepkts_hi),
+ 8, STATS_FLAGS_PORT, "rx_undersize_packets" },
+ { STATS_OFFSET32(etherstatsoverrsizepkts_hi),
+ 8, STATS_FLAGS_PORT, "rx_oversize_packets" },
+/* 10 */{ STATS_OFFSET32(rx_stat_etherstatsfragments_hi),
+ 8, STATS_FLAGS_PORT, "rx_fragments" },
+ { STATS_OFFSET32(rx_stat_etherstatsjabbers_hi),
+ 8, STATS_FLAGS_PORT, "rx_jabbers" },
+ { STATS_OFFSET32(no_buff_discard_hi),
+ 8, STATS_FLAGS_BOTH, "rx_discards" },
+ { STATS_OFFSET32(mac_filter_discard),
+ 4, STATS_FLAGS_PORT, "rx_filtered_packets" },
+ { STATS_OFFSET32(xxoverflow_discard),
+ 4, STATS_FLAGS_PORT, "rx_fw_discards" },
+ { STATS_OFFSET32(brb_drop_hi),
+ 8, STATS_FLAGS_PORT, "rx_brb_discard" },
+ { STATS_OFFSET32(brb_truncate_hi),
+ 8, STATS_FLAGS_PORT, "rx_brb_truncate" },
+ { STATS_OFFSET32(pause_frames_received_hi),
+ 8, STATS_FLAGS_PORT, "rx_pause_frames" },
+ { STATS_OFFSET32(rx_stat_maccontrolframesreceived_hi),
+ 8, STATS_FLAGS_PORT, "rx_mac_ctrl_frames" },
+ { STATS_OFFSET32(nig_timer_max),
+ 4, STATS_FLAGS_PORT, "rx_constant_pause_events" },
+/* 20 */{ STATS_OFFSET32(rx_err_discard_pkt),
+ 4, STATS_FLAGS_BOTH, "rx_phy_ip_err_discards"},
+ { STATS_OFFSET32(rx_skb_alloc_failed),
+ 4, STATS_FLAGS_BOTH, "rx_skb_alloc_discard" },
+ { STATS_OFFSET32(hw_csum_err),
+ 4, STATS_FLAGS_BOTH, "rx_csum_offload_errors" },
+
+ { STATS_OFFSET32(total_bytes_transmitted_hi),
+ 8, STATS_FLAGS_BOTH, "tx_bytes" },
+ { STATS_OFFSET32(tx_stat_ifhcoutbadoctets_hi),
+ 8, STATS_FLAGS_PORT, "tx_error_bytes" },
+ { STATS_OFFSET32(total_unicast_packets_transmitted_hi),
+ 8, STATS_FLAGS_BOTH, "tx_ucast_packets" },
+ { STATS_OFFSET32(total_multicast_packets_transmitted_hi),
+ 8, STATS_FLAGS_BOTH, "tx_mcast_packets" },
+ { STATS_OFFSET32(total_broadcast_packets_transmitted_hi),
+ 8, STATS_FLAGS_BOTH, "tx_bcast_packets" },
+ { STATS_OFFSET32(tx_stat_dot3statsinternalmactransmiterrors_hi),
+ 8, STATS_FLAGS_PORT, "tx_mac_errors" },
+ { STATS_OFFSET32(rx_stat_dot3statscarriersenseerrors_hi),
+ 8, STATS_FLAGS_PORT, "tx_carrier_errors" },
+/* 30 */{ STATS_OFFSET32(tx_stat_dot3statssinglecollisionframes_hi),
+ 8, STATS_FLAGS_PORT, "tx_single_collisions" },
+ { STATS_OFFSET32(tx_stat_dot3statsmultiplecollisionframes_hi),
+ 8, STATS_FLAGS_PORT, "tx_multi_collisions" },
+ { STATS_OFFSET32(tx_stat_dot3statsdeferredtransmissions_hi),
+ 8, STATS_FLAGS_PORT, "tx_deferred" },
+ { STATS_OFFSET32(tx_stat_dot3statsexcessivecollisions_hi),
+ 8, STATS_FLAGS_PORT, "tx_excess_collisions" },
+ { STATS_OFFSET32(tx_stat_dot3statslatecollisions_hi),
+ 8, STATS_FLAGS_PORT, "tx_late_collisions" },
+ { STATS_OFFSET32(tx_stat_etherstatscollisions_hi),
+ 8, STATS_FLAGS_PORT, "tx_total_collisions" },
+ { STATS_OFFSET32(tx_stat_etherstatspkts64octets_hi),
+ 8, STATS_FLAGS_PORT, "tx_64_byte_packets" },
+ { STATS_OFFSET32(tx_stat_etherstatspkts65octetsto127octets_hi),
+ 8, STATS_FLAGS_PORT, "tx_65_to_127_byte_packets" },
+ { STATS_OFFSET32(tx_stat_etherstatspkts128octetsto255octets_hi),
+ 8, STATS_FLAGS_PORT, "tx_128_to_255_byte_packets" },
+ { STATS_OFFSET32(tx_stat_etherstatspkts256octetsto511octets_hi),
+ 8, STATS_FLAGS_PORT, "tx_256_to_511_byte_packets" },
+/* 40 */{ STATS_OFFSET32(tx_stat_etherstatspkts512octetsto1023octets_hi),
+ 8, STATS_FLAGS_PORT, "tx_512_to_1023_byte_packets" },
+ { STATS_OFFSET32(etherstatspkts1024octetsto1522octets_hi),
+ 8, STATS_FLAGS_PORT, "tx_1024_to_1522_byte_packets" },
+ { STATS_OFFSET32(etherstatspktsover1522octets_hi),
+ 8, STATS_FLAGS_PORT, "tx_1523_to_9022_byte_packets" },
+ { STATS_OFFSET32(pause_frames_sent_hi),
+ 8, STATS_FLAGS_PORT, "tx_pause_frames" }
+};
+
+#define IS_PORT_STAT(i) \
+ ((bnx2x_stats_arr[i].flags & STATS_FLAGS_BOTH) == STATS_FLAGS_PORT)
+#define IS_FUNC_STAT(i) (bnx2x_stats_arr[i].flags & STATS_FLAGS_FUNC)
+#define IS_E1HMF_MODE_STAT(bp) \
+ (IS_E1HMF(bp) && !(bp->msg_enable & BNX2X_MSG_STATS))
+
+static int bnx2x_get_sset_count(struct net_device *dev, int stringset)
+{
+ struct bnx2x *bp = netdev_priv(dev);
+ int i, num_stats;
+
+ switch (stringset) {
+ case ETH_SS_STATS:
+ if (is_multi(bp)) {
+ num_stats = BNX2X_NUM_Q_STATS * bp->num_queues;
+ if (!IS_E1HMF_MODE_STAT(bp))
+ num_stats += BNX2X_NUM_STATS;
+ } else {
+ if (IS_E1HMF_MODE_STAT(bp)) {
+ num_stats = 0;
+ for (i = 0; i < BNX2X_NUM_STATS; i++)
+ if (IS_FUNC_STAT(i))
+ num_stats++;
+ } else
+ num_stats = BNX2X_NUM_STATS;
+ }
+ return num_stats;
+
+ case ETH_SS_TEST:
+ return BNX2X_NUM_TESTS;
+
+ default:
+ return -EINVAL;
+ }
+}
+
+static void bnx2x_get_strings(struct net_device *dev, u32 stringset, u8 *buf)
+{
+ struct bnx2x *bp = netdev_priv(dev);
+ int i, j, k;
+
+ switch (stringset) {
+ case ETH_SS_STATS:
+ if (is_multi(bp)) {
+ k = 0;
+ for_each_queue(bp, i) {
+ for (j = 0; j < BNX2X_NUM_Q_STATS; j++)
+ sprintf(buf + (k + j)*ETH_GSTRING_LEN,
+ bnx2x_q_stats_arr[j].string, i);
+ k += BNX2X_NUM_Q_STATS;
+ }
+ if (IS_E1HMF_MODE_STAT(bp))
+ break;
+ for (j = 0; j < BNX2X_NUM_STATS; j++)
+ strcpy(buf + (k + j)*ETH_GSTRING_LEN,
+ bnx2x_stats_arr[j].string);
+ } else {
+ for (i = 0, j = 0; i < BNX2X_NUM_STATS; i++) {
+ if (IS_E1HMF_MODE_STAT(bp) && IS_PORT_STAT(i))
+ continue;
+ strcpy(buf + j*ETH_GSTRING_LEN,
+ bnx2x_stats_arr[i].string);
+ j++;
+ }
+ }
+ break;
+
+ case ETH_SS_TEST:
+ memcpy(buf, bnx2x_tests_str_arr, sizeof(bnx2x_tests_str_arr));
+ break;
+ }
+}
+
+static void bnx2x_get_ethtool_stats(struct net_device *dev,
+ struct ethtool_stats *stats, u64 *buf)
+{
+ struct bnx2x *bp = netdev_priv(dev);
+ u32 *hw_stats, *offset;
+ int i, j, k;
+
+ if (is_multi(bp)) {
+ k = 0;
+ for_each_queue(bp, i) {
+ hw_stats = (u32 *)&bp->fp[i].eth_q_stats;
+ for (j = 0; j < BNX2X_NUM_Q_STATS; j++) {
+ if (bnx2x_q_stats_arr[j].size == 0) {
+ /* skip this counter */
+ buf[k + j] = 0;
+ continue;
+ }
+ offset = (hw_stats +
+ bnx2x_q_stats_arr[j].offset);
+ if (bnx2x_q_stats_arr[j].size == 4) {
+ /* 4-byte counter */
+ buf[k + j] = (u64) *offset;
+ continue;
+ }
+ /* 8-byte counter */
+ buf[k + j] = HILO_U64(*offset, *(offset + 1));
+ }
+ k += BNX2X_NUM_Q_STATS;
+ }
+ if (IS_E1HMF_MODE_STAT(bp))
+ return;
+ hw_stats = (u32 *)&bp->eth_stats;
+ for (j = 0; j < BNX2X_NUM_STATS; j++) {
+ if (bnx2x_stats_arr[j].size == 0) {
+ /* skip this counter */
+ buf[k + j] = 0;
+ continue;
+ }
+ offset = (hw_stats + bnx2x_stats_arr[j].offset);
+ if (bnx2x_stats_arr[j].size == 4) {
+ /* 4-byte counter */
+ buf[k + j] = (u64) *offset;
+ continue;
+ }
+ /* 8-byte counter */
+ buf[k + j] = HILO_U64(*offset, *(offset + 1));
+ }
+ } else {
+ hw_stats = (u32 *)&bp->eth_stats;
+ for (i = 0, j = 0; i < BNX2X_NUM_STATS; i++) {
+ if (IS_E1HMF_MODE_STAT(bp) && IS_PORT_STAT(i))
+ continue;
+ if (bnx2x_stats_arr[i].size == 0) {
+ /* skip this counter */
+ buf[j] = 0;
+ j++;
+ continue;
+ }
+ offset = (hw_stats + bnx2x_stats_arr[i].offset);
+ if (bnx2x_stats_arr[i].size == 4) {
+ /* 4-byte counter */
+ buf[j] = (u64) *offset;
+ j++;
+ continue;
+ }
+ /* 8-byte counter */
+ buf[j] = HILO_U64(*offset, *(offset + 1));
+ j++;
+ }
+ }
+}
+
+static int bnx2x_phys_id(struct net_device *dev, u32 data)
+{
+ struct bnx2x *bp = netdev_priv(dev);
+ int i;
+
+ if (!netif_running(dev))
+ return 0;
+
+ if (!bp->port.pmf)
+ return 0;
+
+ if (data == 0)
+ data = 2;
+
+ for (i = 0; i < (data * 2); i++) {
+ if ((i % 2) == 0)
+ bnx2x_set_led(&bp->link_params, LED_MODE_OPER,
+ SPEED_1000);
+ else
+ bnx2x_set_led(&bp->link_params, LED_MODE_OFF, 0);
+
+ msleep_interruptible(500);
+ if (signal_pending(current))
+ break;
+ }
+
+ if (bp->link_vars.link_up)
+ bnx2x_set_led(&bp->link_params, LED_MODE_OPER,
+ bp->link_vars.line_speed);
+
+ return 0;
+}
+
+static const struct ethtool_ops bnx2x_ethtool_ops = {
+ .get_settings = bnx2x_get_settings,
+ .set_settings = bnx2x_set_settings,
+ .get_drvinfo = bnx2x_get_drvinfo,
+ .get_regs_len = bnx2x_get_regs_len,
+ .get_regs = bnx2x_get_regs,
+ .get_wol = bnx2x_get_wol,
+ .set_wol = bnx2x_set_wol,
+ .get_msglevel = bnx2x_get_msglevel,
+ .set_msglevel = bnx2x_set_msglevel,
+ .nway_reset = bnx2x_nway_reset,
+ .get_link = bnx2x_get_link,
+ .get_eeprom_len = bnx2x_get_eeprom_len,
+ .get_eeprom = bnx2x_get_eeprom,
+ .set_eeprom = bnx2x_set_eeprom,
+ .get_coalesce = bnx2x_get_coalesce,
+ .set_coalesce = bnx2x_set_coalesce,
+ .get_ringparam = bnx2x_get_ringparam,
+ .set_ringparam = bnx2x_set_ringparam,
+ .get_pauseparam = bnx2x_get_pauseparam,
+ .set_pauseparam = bnx2x_set_pauseparam,
+ .get_rx_csum = bnx2x_get_rx_csum,
+ .set_rx_csum = bnx2x_set_rx_csum,
+ .get_tx_csum = ethtool_op_get_tx_csum,
+ .set_tx_csum = ethtool_op_set_tx_hw_csum,
+ .set_flags = bnx2x_set_flags,
+ .get_flags = ethtool_op_get_flags,
+ .get_sg = ethtool_op_get_sg,
+ .set_sg = ethtool_op_set_sg,
+ .get_tso = ethtool_op_get_tso,
+ .set_tso = bnx2x_set_tso,
+ .self_test = bnx2x_self_test,
+ .get_sset_count = bnx2x_get_sset_count,
+ .get_strings = bnx2x_get_strings,
+ .phys_id = bnx2x_phys_id,
+ .get_ethtool_stats = bnx2x_get_ethtool_stats,
+};
+
+void bnx2x_set_ethtool_ops(struct net_device *netdev)
+{
+ SET_ETHTOOL_OPS(netdev, &bnx2x_ethtool_ops);
+}
diff --git a/drivers/net/bnx2x_fw_defs.h b/drivers/net/bnx2x/bnx2x_fw_defs.h
index 08d71bf438d..08d71bf438d 100644
--- a/drivers/net/bnx2x_fw_defs.h
+++ b/drivers/net/bnx2x/bnx2x_fw_defs.h
diff --git a/drivers/net/bnx2x_fw_file_hdr.h b/drivers/net/bnx2x/bnx2x_fw_file_hdr.h
index 3f5ee5d7cc2..3f5ee5d7cc2 100644
--- a/drivers/net/bnx2x_fw_file_hdr.h
+++ b/drivers/net/bnx2x/bnx2x_fw_file_hdr.h
diff --git a/drivers/net/bnx2x_hsi.h b/drivers/net/bnx2x/bnx2x_hsi.h
index fd1f29e0317..fd1f29e0317 100644
--- a/drivers/net/bnx2x_hsi.h
+++ b/drivers/net/bnx2x/bnx2x_hsi.h
diff --git a/drivers/net/bnx2x_init.h b/drivers/net/bnx2x/bnx2x_init.h
index 65b26cbfe3e..65b26cbfe3e 100644
--- a/drivers/net/bnx2x_init.h
+++ b/drivers/net/bnx2x/bnx2x_init.h
diff --git a/drivers/net/bnx2x_init_ops.h b/drivers/net/bnx2x/bnx2x_init_ops.h
index 2b1363a6fe7..2b1363a6fe7 100644
--- a/drivers/net/bnx2x_init_ops.h
+++ b/drivers/net/bnx2x/bnx2x_init_ops.h
diff --git a/drivers/net/bnx2x_link.c b/drivers/net/bnx2x/bnx2x_link.c
index ff70be89876..0383e306631 100644
--- a/drivers/net/bnx2x_link.c
+++ b/drivers/net/bnx2x/bnx2x_link.c
@@ -4266,14 +4266,16 @@ static u8 bnx2x_ext_phy_init(struct link_params *params, struct link_vars *vars)
MDIO_PMA_REG_10G_CTRL2, 0x0008);
}
- /* Set 2-wire transfer rate to 400Khz since 100Khz
- is not operational */
+ /* Set 2-wire transfer rate of SFP+ module EEPROM
+ * to 100Khz since some DACs(direct attached cables) do
+ * not work at 400Khz.
+ */
bnx2x_cl45_write(bp, params->port,
ext_phy_type,
ext_phy_addr,
MDIO_PMA_DEVAD,
MDIO_PMA_REG_8727_TWO_WIRE_SLAVE_ADDR,
- 0xa101);
+ 0xa001);
/* Set TX PreEmphasis if needed */
if ((params->feature_config_flags &
diff --git a/drivers/net/bnx2x_link.h b/drivers/net/bnx2x/bnx2x_link.h
index 40c2981de8e..40c2981de8e 100644
--- a/drivers/net/bnx2x_link.h
+++ b/drivers/net/bnx2x/bnx2x_link.h
diff --git a/drivers/net/bnx2x_main.c b/drivers/net/bnx2x/bnx2x_main.c
index 46167c08172..b4ec2b02a46 100644
--- a/drivers/net/bnx2x_main.c
+++ b/drivers/net/bnx2x/bnx2x_main.c
@@ -51,15 +51,12 @@
#include <linux/io.h>
#include <linux/stringify.h>
-
+#define BNX2X_MAIN
#include "bnx2x.h"
#include "bnx2x_init.h"
#include "bnx2x_init_ops.h"
-#include "bnx2x_dump.h"
+#include "bnx2x_cmn.h"
-#define DRV_MODULE_VERSION "1.52.53-2"
-#define DRV_MODULE_RELDATE "2010/21/07"
-#define BNX2X_BC_VER 0x040200
#include <linux/firmware.h>
#include "bnx2x_fw_file_hdr.h"
@@ -121,8 +118,6 @@ static int debug;
module_param(debug, int, 0);
MODULE_PARM_DESC(debug, " Default debug msglevel");
-static int load_count[3]; /* 0-common, 1-port0, 2-port1 */
-
static struct workqueue_struct *bnx2x_wq;
enum bnx2x_board_type {
@@ -177,7 +172,7 @@ static u32 bnx2x_reg_rd_ind(struct bnx2x *bp, u32 addr)
return val;
}
-static const u32 dmae_reg_go_c[] = {
+const u32 dmae_reg_go_c[] = {
DMAE_REG_GO_C0, DMAE_REG_GO_C1, DMAE_REG_GO_C2, DMAE_REG_GO_C3,
DMAE_REG_GO_C4, DMAE_REG_GO_C5, DMAE_REG_GO_C6, DMAE_REG_GO_C7,
DMAE_REG_GO_C8, DMAE_REG_GO_C9, DMAE_REG_GO_C10, DMAE_REG_GO_C11,
@@ -185,8 +180,7 @@ static const u32 dmae_reg_go_c[] = {
};
/* copy command into DMAE command memory and set DMAE command go */
-static void bnx2x_post_dmae(struct bnx2x *bp, struct dmae_command *dmae,
- int idx)
+void bnx2x_post_dmae(struct bnx2x *bp, struct dmae_command *dmae, int idx)
{
u32 cmd_offset;
int i;
@@ -541,7 +535,7 @@ static void bnx2x_fw_dump(struct bnx2x *bp)
pr_err("end of fw dump\n");
}
-static void bnx2x_panic_dump(struct bnx2x *bp)
+void bnx2x_panic_dump(struct bnx2x *bp)
{
int i;
u16 j, start, end;
@@ -654,7 +648,7 @@ static void bnx2x_panic_dump(struct bnx2x *bp)
BNX2X_ERR("end crash dump -----------------\n");
}
-static void bnx2x_int_enable(struct bnx2x *bp)
+void bnx2x_int_enable(struct bnx2x *bp)
{
int port = BP_PORT(bp);
u32 addr = port ? HC_REG_CONFIG_1 : HC_REG_CONFIG_0;
@@ -736,7 +730,7 @@ static void bnx2x_int_disable(struct bnx2x *bp)
BNX2X_ERR("BUG! proper val not read from IGU!\n");
}
-static void bnx2x_int_disable_sync(struct bnx2x *bp, int disable_hw)
+void bnx2x_int_disable_sync(struct bnx2x *bp, int disable_hw)
{
int msix = (bp->flags & USING_MSIX_FLAG) ? 1 : 0;
int i, offset;
@@ -806,235 +800,12 @@ static bool bnx2x_trylock_hw_lock(struct bnx2x *bp, u32 resource)
return false;
}
-static inline void bnx2x_ack_sb(struct bnx2x *bp, u8 sb_id,
- u8 storm, u16 index, u8 op, u8 update)
-{
- u32 hc_addr = (HC_REG_COMMAND_REG + BP_PORT(bp)*32 +
- COMMAND_REG_INT_ACK);
- struct igu_ack_register igu_ack;
-
- igu_ack.status_block_index = index;
- igu_ack.sb_id_and_flags =
- ((sb_id << IGU_ACK_REGISTER_STATUS_BLOCK_ID_SHIFT) |
- (storm << IGU_ACK_REGISTER_STORM_ID_SHIFT) |
- (update << IGU_ACK_REGISTER_UPDATE_INDEX_SHIFT) |
- (op << IGU_ACK_REGISTER_INTERRUPT_MODE_SHIFT));
-
- DP(BNX2X_MSG_OFF, "write 0x%08x to HC addr 0x%x\n",
- (*(u32 *)&igu_ack), hc_addr);
- REG_WR(bp, hc_addr, (*(u32 *)&igu_ack));
-
- /* Make sure that ACK is written */
- mmiowb();
- barrier();
-}
-
-static inline void bnx2x_update_fpsb_idx(struct bnx2x_fastpath *fp)
-{
- struct host_status_block *fpsb = fp->status_blk;
-
- barrier(); /* status block is written to by the chip */
- fp->fp_c_idx = fpsb->c_status_block.status_block_index;
- fp->fp_u_idx = fpsb->u_status_block.status_block_index;
-}
-
-static u16 bnx2x_ack_int(struct bnx2x *bp)
-{
- u32 hc_addr = (HC_REG_COMMAND_REG + BP_PORT(bp)*32 +
- COMMAND_REG_SIMD_MASK);
- u32 result = REG_RD(bp, hc_addr);
-
- DP(BNX2X_MSG_OFF, "read 0x%08x from HC addr 0x%x\n",
- result, hc_addr);
-
- return result;
-}
-
-
-/*
- * fast path service functions
- */
-
-static inline int bnx2x_has_tx_work_unload(struct bnx2x_fastpath *fp)
-{
- /* Tell compiler that consumer and producer can change */
- barrier();
- return (fp->tx_pkt_prod != fp->tx_pkt_cons);
-}
-
-/* free skb in the packet ring at pos idx
- * return idx of last bd freed
- */
-static u16 bnx2x_free_tx_pkt(struct bnx2x *bp, struct bnx2x_fastpath *fp,
- u16 idx)
-{
- struct sw_tx_bd *tx_buf = &fp->tx_buf_ring[idx];
- struct eth_tx_start_bd *tx_start_bd;
- struct eth_tx_bd *tx_data_bd;
- struct sk_buff *skb = tx_buf->skb;
- u16 bd_idx = TX_BD(tx_buf->first_bd), new_cons;
- int nbd;
-
- /* prefetch skb end pointer to speedup dev_kfree_skb() */
- prefetch(&skb->end);
-
- DP(BNX2X_MSG_OFF, "pkt_idx %d buff @(%p)->skb %p\n",
- idx, tx_buf, skb);
-
- /* unmap first bd */
- DP(BNX2X_MSG_OFF, "free bd_idx %d\n", bd_idx);
- tx_start_bd = &fp->tx_desc_ring[bd_idx].start_bd;
- dma_unmap_single(&bp->pdev->dev, BD_UNMAP_ADDR(tx_start_bd),
- BD_UNMAP_LEN(tx_start_bd), PCI_DMA_TODEVICE);
-
- nbd = le16_to_cpu(tx_start_bd->nbd) - 1;
-#ifdef BNX2X_STOP_ON_ERROR
- if ((nbd - 1) > (MAX_SKB_FRAGS + 2)) {
- BNX2X_ERR("BAD nbd!\n");
- bnx2x_panic();
- }
-#endif
- new_cons = nbd + tx_buf->first_bd;
-
- /* Get the next bd */
- bd_idx = TX_BD(NEXT_TX_IDX(bd_idx));
-
- /* Skip a parse bd... */
- --nbd;
- bd_idx = TX_BD(NEXT_TX_IDX(bd_idx));
-
- /* ...and the TSO split header bd since they have no mapping */
- if (tx_buf->flags & BNX2X_TSO_SPLIT_BD) {
- --nbd;
- bd_idx = TX_BD(NEXT_TX_IDX(bd_idx));
- }
-
- /* now free frags */
- while (nbd > 0) {
-
- DP(BNX2X_MSG_OFF, "free frag bd_idx %d\n", bd_idx);
- tx_data_bd = &fp->tx_desc_ring[bd_idx].reg_bd;
- dma_unmap_page(&bp->pdev->dev, BD_UNMAP_ADDR(tx_data_bd),
- BD_UNMAP_LEN(tx_data_bd), DMA_TO_DEVICE);
- if (--nbd)
- bd_idx = TX_BD(NEXT_TX_IDX(bd_idx));
- }
-
- /* release skb */
- WARN_ON(!skb);
- dev_kfree_skb(skb);
- tx_buf->first_bd = 0;
- tx_buf->skb = NULL;
-
- return new_cons;
-}
-
-static inline u16 bnx2x_tx_avail(struct bnx2x_fastpath *fp)
-{
- s16 used;
- u16 prod;
- u16 cons;
-
- prod = fp->tx_bd_prod;
- cons = fp->tx_bd_cons;
-
- /* NUM_TX_RINGS = number of "next-page" entries
- It will be used as a threshold */
- used = SUB_S16(prod, cons) + (s16)NUM_TX_RINGS;
-
-#ifdef BNX2X_STOP_ON_ERROR
- WARN_ON(used < 0);
- WARN_ON(used > fp->bp->tx_ring_size);
- WARN_ON((fp->bp->tx_ring_size - used) > MAX_TX_AVAIL);
-#endif
-
- return (s16)(fp->bp->tx_ring_size) - used;
-}
-
-static inline int bnx2x_has_tx_work(struct bnx2x_fastpath *fp)
-{
- u16 hw_cons;
-
- /* Tell compiler that status block fields can change */
- barrier();
- hw_cons = le16_to_cpu(*fp->tx_cons_sb);
- return hw_cons != fp->tx_pkt_cons;
-}
-
-static int bnx2x_tx_int(struct bnx2x_fastpath *fp)
-{
- struct bnx2x *bp = fp->bp;
- struct netdev_queue *txq;
- u16 hw_cons, sw_cons, bd_cons = fp->tx_bd_cons;
-
-#ifdef BNX2X_STOP_ON_ERROR
- if (unlikely(bp->panic))
- return -1;
-#endif
-
- txq = netdev_get_tx_queue(bp->dev, fp->index);
- hw_cons = le16_to_cpu(*fp->tx_cons_sb);
- sw_cons = fp->tx_pkt_cons;
-
- while (sw_cons != hw_cons) {
- u16 pkt_cons;
-
- pkt_cons = TX_BD(sw_cons);
-
- /* prefetch(bp->tx_buf_ring[pkt_cons].skb); */
-
- DP(NETIF_MSG_TX_DONE, "hw_cons %u sw_cons %u pkt_cons %u\n",
- hw_cons, sw_cons, pkt_cons);
-
-/* if (NEXT_TX_IDX(sw_cons) != hw_cons) {
- rmb();
- prefetch(fp->tx_buf_ring[NEXT_TX_IDX(sw_cons)].skb);
- }
-*/
- bd_cons = bnx2x_free_tx_pkt(bp, fp, pkt_cons);
- sw_cons++;
- }
-
- fp->tx_pkt_cons = sw_cons;
- fp->tx_bd_cons = bd_cons;
-
- /* Need to make the tx_bd_cons update visible to start_xmit()
- * before checking for netif_tx_queue_stopped(). Without the
- * memory barrier, there is a small possibility that
- * start_xmit() will miss it and cause the queue to be stopped
- * forever.
- */
- smp_mb();
-
- /* TBD need a thresh? */
- if (unlikely(netif_tx_queue_stopped(txq))) {
- /* Taking tx_lock() is needed to prevent reenabling the queue
- * while it's empty. This could have happen if rx_action() gets
- * suspended in bnx2x_tx_int() after the condition before
- * netif_tx_wake_queue(), while tx_action (bnx2x_start_xmit()):
- *
- * stops the queue->sees fresh tx_bd_cons->releases the queue->
- * sends some packets consuming the whole queue again->
- * stops the queue
- */
-
- __netif_tx_lock(txq, smp_processor_id());
-
- if ((netif_tx_queue_stopped(txq)) &&
- (bp->state == BNX2X_STATE_OPEN) &&
- (bnx2x_tx_avail(fp) >= MAX_SKB_FRAGS + 3))
- netif_tx_wake_queue(txq);
-
- __netif_tx_unlock(txq);
- }
- return 0;
-}
#ifdef BCM_CNIC
static void bnx2x_cnic_cfc_comp(struct bnx2x *bp, int cid);
#endif
-static void bnx2x_sp_event(struct bnx2x_fastpath *fp,
+void bnx2x_sp_event(struct bnx2x_fastpath *fp,
union eth_rx_cqe *rr_cqe)
{
struct bnx2x *bp = fp->bp;
@@ -1118,703 +889,7 @@ static void bnx2x_sp_event(struct bnx2x_fastpath *fp,
mb(); /* force bnx2x_wait_ramrod() to see the change */
}
-static inline void bnx2x_free_rx_sge(struct bnx2x *bp,
- struct bnx2x_fastpath *fp, u16 index)
-{
- struct sw_rx_page *sw_buf = &fp->rx_page_ring[index];
- struct page *page = sw_buf->page;
- struct eth_rx_sge *sge = &fp->rx_sge_ring[index];
-
- /* Skip "next page" elements */
- if (!page)
- return;
-
- dma_unmap_page(&bp->pdev->dev, dma_unmap_addr(sw_buf, mapping),
- SGE_PAGE_SIZE*PAGES_PER_SGE, PCI_DMA_FROMDEVICE);
- __free_pages(page, PAGES_PER_SGE_SHIFT);
-
- sw_buf->page = NULL;
- sge->addr_hi = 0;
- sge->addr_lo = 0;
-}
-
-static inline void bnx2x_free_rx_sge_range(struct bnx2x *bp,
- struct bnx2x_fastpath *fp, int last)
-{
- int i;
-
- for (i = 0; i < last; i++)
- bnx2x_free_rx_sge(bp, fp, i);
-}
-
-static inline int bnx2x_alloc_rx_sge(struct bnx2x *bp,
- struct bnx2x_fastpath *fp, u16 index)
-{
- struct page *page = alloc_pages(GFP_ATOMIC, PAGES_PER_SGE_SHIFT);
- struct sw_rx_page *sw_buf = &fp->rx_page_ring[index];
- struct eth_rx_sge *sge = &fp->rx_sge_ring[index];
- dma_addr_t mapping;
-
- if (unlikely(page == NULL))
- return -ENOMEM;
-
- mapping = dma_map_page(&bp->pdev->dev, page, 0,
- SGE_PAGE_SIZE*PAGES_PER_SGE, DMA_FROM_DEVICE);
- if (unlikely(dma_mapping_error(&bp->pdev->dev, mapping))) {
- __free_pages(page, PAGES_PER_SGE_SHIFT);
- return -ENOMEM;
- }
-
- sw_buf->page = page;
- dma_unmap_addr_set(sw_buf, mapping, mapping);
-
- sge->addr_hi = cpu_to_le32(U64_HI(mapping));
- sge->addr_lo = cpu_to_le32(U64_LO(mapping));
-
- return 0;
-}
-
-static inline int bnx2x_alloc_rx_skb(struct bnx2x *bp,
- struct bnx2x_fastpath *fp, u16 index)
-{
- struct sk_buff *skb;
- struct sw_rx_bd *rx_buf = &fp->rx_buf_ring[index];
- struct eth_rx_bd *rx_bd = &fp->rx_desc_ring[index];
- dma_addr_t mapping;
-
- skb = netdev_alloc_skb(bp->dev, bp->rx_buf_size);
- if (unlikely(skb == NULL))
- return -ENOMEM;
-
- mapping = dma_map_single(&bp->pdev->dev, skb->data, bp->rx_buf_size,
- DMA_FROM_DEVICE);
- if (unlikely(dma_mapping_error(&bp->pdev->dev, mapping))) {
- dev_kfree_skb(skb);
- return -ENOMEM;
- }
-
- rx_buf->skb = skb;
- dma_unmap_addr_set(rx_buf, mapping, mapping);
-
- rx_bd->addr_hi = cpu_to_le32(U64_HI(mapping));
- rx_bd->addr_lo = cpu_to_le32(U64_LO(mapping));
-
- return 0;
-}
-
-/* note that we are not allocating a new skb,
- * we are just moving one from cons to prod
- * we are not creating a new mapping,
- * so there is no need to check for dma_mapping_error().
- */
-static void bnx2x_reuse_rx_skb(struct bnx2x_fastpath *fp,
- struct sk_buff *skb, u16 cons, u16 prod)
-{
- struct bnx2x *bp = fp->bp;
- struct sw_rx_bd *cons_rx_buf = &fp->rx_buf_ring[cons];
- struct sw_rx_bd *prod_rx_buf = &fp->rx_buf_ring[prod];
- struct eth_rx_bd *cons_bd = &fp->rx_desc_ring[cons];
- struct eth_rx_bd *prod_bd = &fp->rx_desc_ring[prod];
-
- dma_sync_single_for_device(&bp->pdev->dev,
- dma_unmap_addr(cons_rx_buf, mapping),
- RX_COPY_THRESH, DMA_FROM_DEVICE);
-
- prod_rx_buf->skb = cons_rx_buf->skb;
- dma_unmap_addr_set(prod_rx_buf, mapping,
- dma_unmap_addr(cons_rx_buf, mapping));
- *prod_bd = *cons_bd;
-}
-
-static inline void bnx2x_update_last_max_sge(struct bnx2x_fastpath *fp,
- u16 idx)
-{
- u16 last_max = fp->last_max_sge;
-
- if (SUB_S16(idx, last_max) > 0)
- fp->last_max_sge = idx;
-}
-
-static void bnx2x_clear_sge_mask_next_elems(struct bnx2x_fastpath *fp)
-{
- int i, j;
-
- for (i = 1; i <= NUM_RX_SGE_PAGES; i++) {
- int idx = RX_SGE_CNT * i - 1;
-
- for (j = 0; j < 2; j++) {
- SGE_MASK_CLEAR_BIT(fp, idx);
- idx--;
- }
- }
-}
-
-static void bnx2x_update_sge_prod(struct bnx2x_fastpath *fp,
- struct eth_fast_path_rx_cqe *fp_cqe)
-{
- struct bnx2x *bp = fp->bp;
- u16 sge_len = SGE_PAGE_ALIGN(le16_to_cpu(fp_cqe->pkt_len) -
- le16_to_cpu(fp_cqe->len_on_bd)) >>
- SGE_PAGE_SHIFT;
- u16 last_max, last_elem, first_elem;
- u16 delta = 0;
- u16 i;
-
- if (!sge_len)
- return;
-
- /* First mark all used pages */
- for (i = 0; i < sge_len; i++)
- SGE_MASK_CLEAR_BIT(fp, RX_SGE(le16_to_cpu(fp_cqe->sgl[i])));
-
- DP(NETIF_MSG_RX_STATUS, "fp_cqe->sgl[%d] = %d\n",
- sge_len - 1, le16_to_cpu(fp_cqe->sgl[sge_len - 1]));
-
- /* Here we assume that the last SGE index is the biggest */
- prefetch((void *)(fp->sge_mask));
- bnx2x_update_last_max_sge(fp, le16_to_cpu(fp_cqe->sgl[sge_len - 1]));
-
- last_max = RX_SGE(fp->last_max_sge);
- last_elem = last_max >> RX_SGE_MASK_ELEM_SHIFT;
- first_elem = RX_SGE(fp->rx_sge_prod) >> RX_SGE_MASK_ELEM_SHIFT;
-
- /* If ring is not full */
- if (last_elem + 1 != first_elem)
- last_elem++;
-
- /* Now update the prod */
- for (i = first_elem; i != last_elem; i = NEXT_SGE_MASK_ELEM(i)) {
- if (likely(fp->sge_mask[i]))
- break;
-
- fp->sge_mask[i] = RX_SGE_MASK_ELEM_ONE_MASK;
- delta += RX_SGE_MASK_ELEM_SZ;
- }
-
- if (delta > 0) {
- fp->rx_sge_prod += delta;
- /* clear page-end entries */
- bnx2x_clear_sge_mask_next_elems(fp);
- }
-
- DP(NETIF_MSG_RX_STATUS,
- "fp->last_max_sge = %d fp->rx_sge_prod = %d\n",
- fp->last_max_sge, fp->rx_sge_prod);
-}
-
-static inline void bnx2x_init_sge_ring_bit_mask(struct bnx2x_fastpath *fp)
-{
- /* Set the mask to all 1-s: it's faster to compare to 0 than to 0xf-s */
- memset(fp->sge_mask, 0xff,
- (NUM_RX_SGE >> RX_SGE_MASK_ELEM_SHIFT)*sizeof(u64));
-
- /* Clear the two last indices in the page to 1:
- these are the indices that correspond to the "next" element,
- hence will never be indicated and should be removed from
- the calculations. */
- bnx2x_clear_sge_mask_next_elems(fp);
-}
-
-static void bnx2x_tpa_start(struct bnx2x_fastpath *fp, u16 queue,
- struct sk_buff *skb, u16 cons, u16 prod)
-{
- struct bnx2x *bp = fp->bp;
- struct sw_rx_bd *cons_rx_buf = &fp->rx_buf_ring[cons];
- struct sw_rx_bd *prod_rx_buf = &fp->rx_buf_ring[prod];
- struct eth_rx_bd *prod_bd = &fp->rx_desc_ring[prod];
- dma_addr_t mapping;
-
- /* move empty skb from pool to prod and map it */
- prod_rx_buf->skb = fp->tpa_pool[queue].skb;
- mapping = dma_map_single(&bp->pdev->dev, fp->tpa_pool[queue].skb->data,
- bp->rx_buf_size, DMA_FROM_DEVICE);
- dma_unmap_addr_set(prod_rx_buf, mapping, mapping);
-
- /* move partial skb from cons to pool (don't unmap yet) */
- fp->tpa_pool[queue] = *cons_rx_buf;
-
- /* mark bin state as start - print error if current state != stop */
- if (fp->tpa_state[queue] != BNX2X_TPA_STOP)
- BNX2X_ERR("start of bin not in stop [%d]\n", queue);
-
- fp->tpa_state[queue] = BNX2X_TPA_START;
-
- /* point prod_bd to new skb */
- prod_bd->addr_hi = cpu_to_le32(U64_HI(mapping));
- prod_bd->addr_lo = cpu_to_le32(U64_LO(mapping));
-
-#ifdef BNX2X_STOP_ON_ERROR
- fp->tpa_queue_used |= (1 << queue);
-#ifdef _ASM_GENERIC_INT_L64_H
- DP(NETIF_MSG_RX_STATUS, "fp->tpa_queue_used = 0x%lx\n",
-#else
- DP(NETIF_MSG_RX_STATUS, "fp->tpa_queue_used = 0x%llx\n",
-#endif
- fp->tpa_queue_used);
-#endif
-}
-
-static int bnx2x_fill_frag_skb(struct bnx2x *bp, struct bnx2x_fastpath *fp,
- struct sk_buff *skb,
- struct eth_fast_path_rx_cqe *fp_cqe,
- u16 cqe_idx)
-{
- struct sw_rx_page *rx_pg, old_rx_pg;
- u16 len_on_bd = le16_to_cpu(fp_cqe->len_on_bd);
- u32 i, frag_len, frag_size, pages;
- int err;
- int j;
-
- frag_size = le16_to_cpu(fp_cqe->pkt_len) - len_on_bd;
- pages = SGE_PAGE_ALIGN(frag_size) >> SGE_PAGE_SHIFT;
-
- /* This is needed in order to enable forwarding support */
- if (frag_size)
- skb_shinfo(skb)->gso_size = min((u32)SGE_PAGE_SIZE,
- max(frag_size, (u32)len_on_bd));
-
-#ifdef BNX2X_STOP_ON_ERROR
- if (pages > min_t(u32, 8, MAX_SKB_FRAGS)*SGE_PAGE_SIZE*PAGES_PER_SGE) {
- BNX2X_ERR("SGL length is too long: %d. CQE index is %d\n",
- pages, cqe_idx);
- BNX2X_ERR("fp_cqe->pkt_len = %d fp_cqe->len_on_bd = %d\n",
- fp_cqe->pkt_len, len_on_bd);
- bnx2x_panic();
- return -EINVAL;
- }
-#endif
-
- /* Run through the SGL and compose the fragmented skb */
- for (i = 0, j = 0; i < pages; i += PAGES_PER_SGE, j++) {
- u16 sge_idx = RX_SGE(le16_to_cpu(fp_cqe->sgl[j]));
-
- /* FW gives the indices of the SGE as if the ring is an array
- (meaning that "next" element will consume 2 indices) */
- frag_len = min(frag_size, (u32)(SGE_PAGE_SIZE*PAGES_PER_SGE));
- rx_pg = &fp->rx_page_ring[sge_idx];
- old_rx_pg = *rx_pg;
-
- /* If we fail to allocate a substitute page, we simply stop
- where we are and drop the whole packet */
- err = bnx2x_alloc_rx_sge(bp, fp, sge_idx);
- if (unlikely(err)) {
- fp->eth_q_stats.rx_skb_alloc_failed++;
- return err;
- }
-
- /* Unmap the page as we r going to pass it to the stack */
- dma_unmap_page(&bp->pdev->dev,
- dma_unmap_addr(&old_rx_pg, mapping),
- SGE_PAGE_SIZE*PAGES_PER_SGE, DMA_FROM_DEVICE);
-
- /* Add one frag and update the appropriate fields in the skb */
- skb_fill_page_desc(skb, j, old_rx_pg.page, 0, frag_len);
-
- skb->data_len += frag_len;
- skb->truesize += frag_len;
- skb->len += frag_len;
-
- frag_size -= frag_len;
- }
-
- return 0;
-}
-
-static void bnx2x_tpa_stop(struct bnx2x *bp, struct bnx2x_fastpath *fp,
- u16 queue, int pad, int len, union eth_rx_cqe *cqe,
- u16 cqe_idx)
-{
- struct sw_rx_bd *rx_buf = &fp->tpa_pool[queue];
- struct sk_buff *skb = rx_buf->skb;
- /* alloc new skb */
- struct sk_buff *new_skb = netdev_alloc_skb(bp->dev, bp->rx_buf_size);
-
- /* Unmap skb in the pool anyway, as we are going to change
- pool entry status to BNX2X_TPA_STOP even if new skb allocation
- fails. */
- dma_unmap_single(&bp->pdev->dev, dma_unmap_addr(rx_buf, mapping),
- bp->rx_buf_size, DMA_FROM_DEVICE);
-
- if (likely(new_skb)) {
- /* fix ip xsum and give it to the stack */
- /* (no need to map the new skb) */
-#ifdef BCM_VLAN
- int is_vlan_cqe =
- (le16_to_cpu(cqe->fast_path_cqe.pars_flags.flags) &
- PARSING_FLAGS_VLAN);
- int is_not_hwaccel_vlan_cqe =
- (is_vlan_cqe && (!(bp->flags & HW_VLAN_RX_FLAG)));
-#endif
-
- prefetch(skb);
- prefetch(((char *)(skb)) + 128);
-
-#ifdef BNX2X_STOP_ON_ERROR
- if (pad + len > bp->rx_buf_size) {
- BNX2X_ERR("skb_put is about to fail... "
- "pad %d len %d rx_buf_size %d\n",
- pad, len, bp->rx_buf_size);
- bnx2x_panic();
- return;
- }
-#endif
-
- skb_reserve(skb, pad);
- skb_put(skb, len);
-
- skb->protocol = eth_type_trans(skb, bp->dev);
- skb->ip_summed = CHECKSUM_UNNECESSARY;
-
- {
- struct iphdr *iph;
-
- iph = (struct iphdr *)skb->data;
-#ifdef BCM_VLAN
- /* If there is no Rx VLAN offloading -
- take VLAN tag into an account */
- if (unlikely(is_not_hwaccel_vlan_cqe))
- iph = (struct iphdr *)((u8 *)iph + VLAN_HLEN);
-#endif
- iph->check = 0;
- iph->check = ip_fast_csum((u8 *)iph, iph->ihl);
- }
-
- if (!bnx2x_fill_frag_skb(bp, fp, skb,
- &cqe->fast_path_cqe, cqe_idx)) {
-#ifdef BCM_VLAN
- if ((bp->vlgrp != NULL) && is_vlan_cqe &&
- (!is_not_hwaccel_vlan_cqe))
- vlan_gro_receive(&fp->napi, bp->vlgrp,
- le16_to_cpu(cqe->fast_path_cqe.
- vlan_tag), skb);
- else
-#endif
- napi_gro_receive(&fp->napi, skb);
- } else {
- DP(NETIF_MSG_RX_STATUS, "Failed to allocate new pages"
- " - dropping packet!\n");
- dev_kfree_skb(skb);
- }
-
-
- /* put new skb in bin */
- fp->tpa_pool[queue].skb = new_skb;
-
- } else {
- /* else drop the packet and keep the buffer in the bin */
- DP(NETIF_MSG_RX_STATUS,
- "Failed to allocate new skb - dropping packet!\n");
- fp->eth_q_stats.rx_skb_alloc_failed++;
- }
-
- fp->tpa_state[queue] = BNX2X_TPA_STOP;
-}
-
-static inline void bnx2x_update_rx_prod(struct bnx2x *bp,
- struct bnx2x_fastpath *fp,
- u16 bd_prod, u16 rx_comp_prod,
- u16 rx_sge_prod)
-{
- struct ustorm_eth_rx_producers rx_prods = {0};
- int i;
-
- /* Update producers */
- rx_prods.bd_prod = bd_prod;
- rx_prods.cqe_prod = rx_comp_prod;
- rx_prods.sge_prod = rx_sge_prod;
-
- /*
- * Make sure that the BD and SGE data is updated before updating the
- * producers since FW might read the BD/SGE right after the producer
- * is updated.
- * This is only applicable for weak-ordered memory model archs such
- * as IA-64. The following barrier is also mandatory since FW will
- * assumes BDs must have buffers.
- */
- wmb();
-
- for (i = 0; i < sizeof(struct ustorm_eth_rx_producers)/4; i++)
- REG_WR(bp, BAR_USTRORM_INTMEM +
- USTORM_RX_PRODS_OFFSET(BP_PORT(bp), fp->cl_id) + i*4,
- ((u32 *)&rx_prods)[i]);
-
- mmiowb(); /* keep prod updates ordered */
-
- DP(NETIF_MSG_RX_STATUS,
- "queue[%d]: wrote bd_prod %u cqe_prod %u sge_prod %u\n",
- fp->index, bd_prod, rx_comp_prod, rx_sge_prod);
-}
-
-static int bnx2x_rx_int(struct bnx2x_fastpath *fp, int budget)
-{
- struct bnx2x *bp = fp->bp;
- u16 bd_cons, bd_prod, bd_prod_fw, comp_ring_cons;
- u16 hw_comp_cons, sw_comp_cons, sw_comp_prod;
- int rx_pkt = 0;
-
-#ifdef BNX2X_STOP_ON_ERROR
- if (unlikely(bp->panic))
- return 0;
-#endif
-
- /* CQ "next element" is of the size of the regular element,
- that's why it's ok here */
- hw_comp_cons = le16_to_cpu(*fp->rx_cons_sb);
- if ((hw_comp_cons & MAX_RCQ_DESC_CNT) == MAX_RCQ_DESC_CNT)
- hw_comp_cons++;
-
- bd_cons = fp->rx_bd_cons;
- bd_prod = fp->rx_bd_prod;
- bd_prod_fw = bd_prod;
- sw_comp_cons = fp->rx_comp_cons;
- sw_comp_prod = fp->rx_comp_prod;
-
- /* Memory barrier necessary as speculative reads of the rx
- * buffer can be ahead of the index in the status block
- */
- rmb();
-
- DP(NETIF_MSG_RX_STATUS,
- "queue[%d]: hw_comp_cons %u sw_comp_cons %u\n",
- fp->index, hw_comp_cons, sw_comp_cons);
-
- while (sw_comp_cons != hw_comp_cons) {
- struct sw_rx_bd *rx_buf = NULL;
- struct sk_buff *skb;
- union eth_rx_cqe *cqe;
- u8 cqe_fp_flags, cqe_fp_status_flags;
- u16 len, pad;
-
- comp_ring_cons = RCQ_BD(sw_comp_cons);
- bd_prod = RX_BD(bd_prod);
- bd_cons = RX_BD(bd_cons);
-
- /* Prefetch the page containing the BD descriptor
- at producer's index. It will be needed when new skb is
- allocated */
- prefetch((void *)(PAGE_ALIGN((unsigned long)
- (&fp->rx_desc_ring[bd_prod])) -
- PAGE_SIZE + 1));
-
- cqe = &fp->rx_comp_ring[comp_ring_cons];
- cqe_fp_flags = cqe->fast_path_cqe.type_error_flags;
- cqe_fp_status_flags = cqe->fast_path_cqe.status_flags;
-
- DP(NETIF_MSG_RX_STATUS, "CQE type %x err %x status %x"
- " queue %x vlan %x len %u\n", CQE_TYPE(cqe_fp_flags),
- cqe_fp_flags, cqe->fast_path_cqe.status_flags,
- le32_to_cpu(cqe->fast_path_cqe.rss_hash_result),
- le16_to_cpu(cqe->fast_path_cqe.vlan_tag),
- le16_to_cpu(cqe->fast_path_cqe.pkt_len));
-
- /* is this a slowpath msg? */
- if (unlikely(CQE_TYPE(cqe_fp_flags))) {
- bnx2x_sp_event(fp, cqe);
- goto next_cqe;
-
- /* this is an rx packet */
- } else {
- rx_buf = &fp->rx_buf_ring[bd_cons];
- skb = rx_buf->skb;
- prefetch(skb);
- len = le16_to_cpu(cqe->fast_path_cqe.pkt_len);
- pad = cqe->fast_path_cqe.placement_offset;
-
- /* If CQE is marked both TPA_START and TPA_END
- it is a non-TPA CQE */
- if ((!fp->disable_tpa) &&
- (TPA_TYPE(cqe_fp_flags) !=
- (TPA_TYPE_START | TPA_TYPE_END))) {
- u16 queue = cqe->fast_path_cqe.queue_index;
-
- if (TPA_TYPE(cqe_fp_flags) == TPA_TYPE_START) {
- DP(NETIF_MSG_RX_STATUS,
- "calling tpa_start on queue %d\n",
- queue);
-
- bnx2x_tpa_start(fp, queue, skb,
- bd_cons, bd_prod);
- goto next_rx;
- }
-
- if (TPA_TYPE(cqe_fp_flags) == TPA_TYPE_END) {
- DP(NETIF_MSG_RX_STATUS,
- "calling tpa_stop on queue %d\n",
- queue);
-
- if (!BNX2X_RX_SUM_FIX(cqe))
- BNX2X_ERR("STOP on none TCP "
- "data\n");
-
- /* This is a size of the linear data
- on this skb */
- len = le16_to_cpu(cqe->fast_path_cqe.
- len_on_bd);
- bnx2x_tpa_stop(bp, fp, queue, pad,
- len, cqe, comp_ring_cons);
-#ifdef BNX2X_STOP_ON_ERROR
- if (bp->panic)
- return 0;
-#endif
-
- bnx2x_update_sge_prod(fp,
- &cqe->fast_path_cqe);
- goto next_cqe;
- }
- }
-
- dma_sync_single_for_device(&bp->pdev->dev,
- dma_unmap_addr(rx_buf, mapping),
- pad + RX_COPY_THRESH,
- DMA_FROM_DEVICE);
- prefetch(((char *)(skb)) + 128);
-
- /* is this an error packet? */
- if (unlikely(cqe_fp_flags & ETH_RX_ERROR_FALGS)) {
- DP(NETIF_MSG_RX_ERR,
- "ERROR flags %x rx packet %u\n",
- cqe_fp_flags, sw_comp_cons);
- fp->eth_q_stats.rx_err_discard_pkt++;
- goto reuse_rx;
- }
-
- /* Since we don't have a jumbo ring
- * copy small packets if mtu > 1500
- */
- if ((bp->dev->mtu > ETH_MAX_PACKET_SIZE) &&
- (len <= RX_COPY_THRESH)) {
- struct sk_buff *new_skb;
-
- new_skb = netdev_alloc_skb(bp->dev,
- len + pad);
- if (new_skb == NULL) {
- DP(NETIF_MSG_RX_ERR,
- "ERROR packet dropped "
- "because of alloc failure\n");
- fp->eth_q_stats.rx_skb_alloc_failed++;
- goto reuse_rx;
- }
-
- /* aligned copy */
- skb_copy_from_linear_data_offset(skb, pad,
- new_skb->data + pad, len);
- skb_reserve(new_skb, pad);
- skb_put(new_skb, len);
-
- bnx2x_reuse_rx_skb(fp, skb, bd_cons, bd_prod);
-
- skb = new_skb;
-
- } else
- if (likely(bnx2x_alloc_rx_skb(bp, fp, bd_prod) == 0)) {
- dma_unmap_single(&bp->pdev->dev,
- dma_unmap_addr(rx_buf, mapping),
- bp->rx_buf_size,
- DMA_FROM_DEVICE);
- skb_reserve(skb, pad);
- skb_put(skb, len);
-
- } else {
- DP(NETIF_MSG_RX_ERR,
- "ERROR packet dropped because "
- "of alloc failure\n");
- fp->eth_q_stats.rx_skb_alloc_failed++;
-reuse_rx:
- bnx2x_reuse_rx_skb(fp, skb, bd_cons, bd_prod);
- goto next_rx;
- }
-
- skb->protocol = eth_type_trans(skb, bp->dev);
-
- if ((bp->dev->features & NETIF_F_RXHASH) &&
- (cqe_fp_status_flags &
- ETH_FAST_PATH_RX_CQE_RSS_HASH_FLG))
- skb->rxhash = le32_to_cpu(
- cqe->fast_path_cqe.rss_hash_result);
-
- skb->ip_summed = CHECKSUM_NONE;
- if (bp->rx_csum) {
- if (likely(BNX2X_RX_CSUM_OK(cqe)))
- skb->ip_summed = CHECKSUM_UNNECESSARY;
- else
- fp->eth_q_stats.hw_csum_err++;
- }
- }
-
- skb_record_rx_queue(skb, fp->index);
-
-#ifdef BCM_VLAN
- if ((bp->vlgrp != NULL) && (bp->flags & HW_VLAN_RX_FLAG) &&
- (le16_to_cpu(cqe->fast_path_cqe.pars_flags.flags) &
- PARSING_FLAGS_VLAN))
- vlan_gro_receive(&fp->napi, bp->vlgrp,
- le16_to_cpu(cqe->fast_path_cqe.vlan_tag), skb);
- else
-#endif
- napi_gro_receive(&fp->napi, skb);
-
-
-next_rx:
- rx_buf->skb = NULL;
-
- bd_cons = NEXT_RX_IDX(bd_cons);
- bd_prod = NEXT_RX_IDX(bd_prod);
- bd_prod_fw = NEXT_RX_IDX(bd_prod_fw);
- rx_pkt++;
-next_cqe:
- sw_comp_prod = NEXT_RCQ_IDX(sw_comp_prod);
- sw_comp_cons = NEXT_RCQ_IDX(sw_comp_cons);
-
- if (rx_pkt == budget)
- break;
- } /* while */
-
- fp->rx_bd_cons = bd_cons;
- fp->rx_bd_prod = bd_prod_fw;
- fp->rx_comp_cons = sw_comp_cons;
- fp->rx_comp_prod = sw_comp_prod;
-
- /* Update producers */
- bnx2x_update_rx_prod(bp, fp, bd_prod_fw, sw_comp_prod,
- fp->rx_sge_prod);
-
- fp->rx_pkt += rx_pkt;
- fp->rx_calls++;
-
- return rx_pkt;
-}
-
-static irqreturn_t bnx2x_msix_fp_int(int irq, void *fp_cookie)
-{
- struct bnx2x_fastpath *fp = fp_cookie;
- struct bnx2x *bp = fp->bp;
-
- /* Return here if interrupt is disabled */
- if (unlikely(atomic_read(&bp->intr_sem) != 0)) {
- DP(NETIF_MSG_INTR, "called but intr_sem not 0, returning\n");
- return IRQ_HANDLED;
- }
-
- DP(BNX2X_MSG_FP, "got an MSI-X interrupt on IDX:SB [%d:%d]\n",
- fp->index, fp->sb_id);
- bnx2x_ack_sb(bp, fp->sb_id, USTORM_ID, 0, IGU_INT_DISABLE, 0);
-
-#ifdef BNX2X_STOP_ON_ERROR
- if (unlikely(bp->panic))
- return IRQ_HANDLED;
-#endif
-
- /* Handle Rx and Tx according to MSI-X vector */
- prefetch(fp->rx_cons_sb);
- prefetch(fp->tx_cons_sb);
- prefetch(&fp->status_blk->u_status_block.status_block_index);
- prefetch(&fp->status_blk->c_status_block.status_block_index);
- napi_schedule(&bnx2x_fp(bp, fp->index, napi));
-
- return IRQ_HANDLED;
-}
-
-static irqreturn_t bnx2x_interrupt(int irq, void *dev_instance)
+irqreturn_t bnx2x_interrupt(int irq, void *dev_instance)
{
struct bnx2x *bp = netdev_priv(dev_instance);
u16 status = bnx2x_ack_int(bp);
@@ -1888,7 +963,6 @@ static irqreturn_t bnx2x_interrupt(int irq, void *dev_instance)
/* end of fast path */
-static void bnx2x_stats_handle(struct bnx2x *bp, enum bnx2x_stats_event event);
/* Link */
@@ -1896,7 +970,7 @@ static void bnx2x_stats_handle(struct bnx2x *bp, enum bnx2x_stats_event event);
* General service functions
*/
-static int bnx2x_acquire_hw_lock(struct bnx2x *bp, u32 resource)
+int bnx2x_acquire_hw_lock(struct bnx2x *bp, u32 resource)
{
u32 lock_status;
u32 resource_bit = (1 << resource);
@@ -1941,7 +1015,7 @@ static int bnx2x_acquire_hw_lock(struct bnx2x *bp, u32 resource)
return -EAGAIN;
}
-static int bnx2x_release_hw_lock(struct bnx2x *bp, u32 resource)
+int bnx2x_release_hw_lock(struct bnx2x *bp, u32 resource)
{
u32 lock_status;
u32 resource_bit = (1 << resource);
@@ -1977,22 +1051,6 @@ static int bnx2x_release_hw_lock(struct bnx2x *bp, u32 resource)
return 0;
}
-/* HW Lock for shared dual port PHYs */
-static void bnx2x_acquire_phy_lock(struct bnx2x *bp)
-{
- mutex_lock(&bp->port.phy_mutex);
-
- if (bp->port.need_hw_lock)
- bnx2x_acquire_hw_lock(bp, HW_LOCK_RESOURCE_MDIO);
-}
-
-static void bnx2x_release_phy_lock(struct bnx2x *bp)
-{
- if (bp->port.need_hw_lock)
- bnx2x_release_hw_lock(bp, HW_LOCK_RESOURCE_MDIO);
-
- mutex_unlock(&bp->port.phy_mutex);
-}
int bnx2x_get_gpio(struct bnx2x *bp, int gpio_num, u8 port)
{
@@ -2169,7 +1227,7 @@ static int bnx2x_set_spio(struct bnx2x *bp, int spio_num, u32 mode)
return 0;
}
-static void bnx2x_calc_fc_adv(struct bnx2x *bp)
+void bnx2x_calc_fc_adv(struct bnx2x *bp)
{
switch (bp->link_vars.ieee_fc &
MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_MASK) {
@@ -2194,58 +1252,8 @@ static void bnx2x_calc_fc_adv(struct bnx2x *bp)
}
}
-static void bnx2x_link_report(struct bnx2x *bp)
-{
- if (bp->flags & MF_FUNC_DIS) {
- netif_carrier_off(bp->dev);
- netdev_err(bp->dev, "NIC Link is Down\n");
- return;
- }
- if (bp->link_vars.link_up) {
- u16 line_speed;
-
- if (bp->state == BNX2X_STATE_OPEN)
- netif_carrier_on(bp->dev);
- netdev_info(bp->dev, "NIC Link is Up, ");
-
- line_speed = bp->link_vars.line_speed;
- if (IS_E1HMF(bp)) {
- u16 vn_max_rate;
-
- vn_max_rate =
- ((bp->mf_config & FUNC_MF_CFG_MAX_BW_MASK) >>
- FUNC_MF_CFG_MAX_BW_SHIFT) * 100;
- if (vn_max_rate < line_speed)
- line_speed = vn_max_rate;
- }
- pr_cont("%d Mbps ", line_speed);
-
- if (bp->link_vars.duplex == DUPLEX_FULL)
- pr_cont("full duplex");
- else
- pr_cont("half duplex");
-
- if (bp->link_vars.flow_ctrl != BNX2X_FLOW_CTRL_NONE) {
- if (bp->link_vars.flow_ctrl & BNX2X_FLOW_CTRL_RX) {
- pr_cont(", receive ");
- if (bp->link_vars.flow_ctrl &
- BNX2X_FLOW_CTRL_TX)
- pr_cont("& transmit ");
- } else {
- pr_cont(", transmit ");
- }
- pr_cont("flow control ON");
- }
- pr_cont("\n");
-
- } else { /* link_down */
- netif_carrier_off(bp->dev);
- netdev_err(bp->dev, "NIC Link is Down\n");
- }
-}
-
-static u8 bnx2x_initial_phy_init(struct bnx2x *bp, int load_mode)
+u8 bnx2x_initial_phy_init(struct bnx2x *bp, int load_mode)
{
if (!BP_NOMCP(bp)) {
u8 rc;
@@ -2280,7 +1288,7 @@ static u8 bnx2x_initial_phy_init(struct bnx2x *bp, int load_mode)
return -EINVAL;
}
-static void bnx2x_link_set(struct bnx2x *bp)
+void bnx2x_link_set(struct bnx2x *bp)
{
if (!BP_NOMCP(bp)) {
bnx2x_acquire_phy_lock(bp);
@@ -2302,7 +1310,7 @@ static void bnx2x__link_reset(struct bnx2x *bp)
BNX2X_ERR("Bootcode is missing - can not reset link\n");
}
-static u8 bnx2x_link_test(struct bnx2x *bp)
+u8 bnx2x_link_test(struct bnx2x *bp)
{
u8 rc = 0;
@@ -2534,7 +1542,7 @@ static void bnx2x_link_attn(struct bnx2x *bp)
}
}
-static void bnx2x__link_status_update(struct bnx2x *bp)
+void bnx2x__link_status_update(struct bnx2x *bp)
{
if ((bp->state != BNX2X_STATE_OPEN) || (bp->flags & MF_FUNC_DIS))
return;
@@ -2615,9 +1623,6 @@ u32 bnx2x_fw_command(struct bnx2x *bp, u32 command)
return rc;
}
-static void bnx2x_set_eth_mac_addr_e1h(struct bnx2x *bp, int set);
-static void bnx2x_set_rx_mode(struct net_device *dev);
-
static void bnx2x_e1h_disable(struct bnx2x *bp)
{
int port = BP_PORT(bp);
@@ -2745,7 +1750,7 @@ static inline void bnx2x_sp_prod_update(struct bnx2x *bp)
}
/* the slow path queue is odd since completions arrive on the fastpath ring */
-static int bnx2x_sp_post(struct bnx2x *bp, int command, int cid,
+int bnx2x_sp_post(struct bnx2x *bp, int command, int cid,
u32 data_hi, u32 data_lo, int common)
{
struct eth_spe *spe;
@@ -3157,10 +2162,6 @@ static inline void bnx2x_attn_int_deasserted3(struct bnx2x *bp, u32 attn)
}
}
-static int bnx2x_nic_unload(struct bnx2x *bp, int unload_mode);
-static int bnx2x_nic_load(struct bnx2x *bp, int load_mode);
-
-
#define BNX2X_MISC_GEN_REG MISC_REG_GENERIC_POR_1
#define LOAD_COUNTER_BITS 16 /* Number of bits for load counter */
#define LOAD_COUNTER_MASK (((u32)0x1 << LOAD_COUNTER_BITS) - 1)
@@ -3194,7 +2195,7 @@ static inline void bnx2x_set_reset_in_progress(struct bnx2x *bp)
/*
* should be run under rtnl lock
*/
-static inline bool bnx2x_reset_is_done(struct bnx2x *bp)
+bool bnx2x_reset_is_done(struct bnx2x *bp)
{
u32 val = REG_RD(bp, BNX2X_MISC_GEN_REG);
DP(NETIF_MSG_HW, "GEN_REG_VAL=0x%08x\n", val);
@@ -3204,7 +2205,7 @@ static inline bool bnx2x_reset_is_done(struct bnx2x *bp)
/*
* should be run under rtnl lock
*/
-static inline void bnx2x_inc_load_cnt(struct bnx2x *bp)
+inline void bnx2x_inc_load_cnt(struct bnx2x *bp)
{
u32 val1, val = REG_RD(bp, BNX2X_MISC_GEN_REG);
@@ -3219,7 +2220,7 @@ static inline void bnx2x_inc_load_cnt(struct bnx2x *bp)
/*
* should be run under rtnl lock
*/
-static inline u32 bnx2x_dec_load_cnt(struct bnx2x *bp)
+u32 bnx2x_dec_load_cnt(struct bnx2x *bp)
{
u32 val1, val = REG_RD(bp, BNX2X_MISC_GEN_REG);
@@ -3437,7 +2438,7 @@ static inline bool bnx2x_parity_attn(struct bnx2x *bp, u32 sig0, u32 sig1,
return false;
}
-static bool bnx2x_chk_parity_attn(struct bnx2x *bp)
+bool bnx2x_chk_parity_attn(struct bnx2x *bp)
{
struct attn_route attn;
int port = BP_PORT(bp);
@@ -3615,7 +2616,7 @@ static void bnx2x_sp_task(struct work_struct *work)
IGU_INT_ENABLE, 1);
}
-static irqreturn_t bnx2x_msix_sp_int(int irq, void *dev_instance)
+irqreturn_t bnx2x_msix_sp_int(int irq, void *dev_instance)
{
struct net_device *dev = dev_instance;
struct bnx2x *bp = netdev_priv(dev);
@@ -3651,1398 +2652,6 @@ static irqreturn_t bnx2x_msix_sp_int(int irq, void *dev_instance)
/* end of slow path */
-/* Statistics */
-
-/****************************************************************************
-* Macros
-****************************************************************************/
-
-/* sum[hi:lo] += add[hi:lo] */
-#define ADD_64(s_hi, a_hi, s_lo, a_lo) \
- do { \
- s_lo += a_lo; \
- s_hi += a_hi + ((s_lo < a_lo) ? 1 : 0); \
- } while (0)
-
-/* difference = minuend - subtrahend */
-#define DIFF_64(d_hi, m_hi, s_hi, d_lo, m_lo, s_lo) \
- do { \
- if (m_lo < s_lo) { \
- /* underflow */ \
- d_hi = m_hi - s_hi; \
- if (d_hi > 0) { \
- /* we can 'loan' 1 */ \
- d_hi--; \
- d_lo = m_lo + (UINT_MAX - s_lo) + 1; \
- } else { \
- /* m_hi <= s_hi */ \
- d_hi = 0; \
- d_lo = 0; \
- } \
- } else { \
- /* m_lo >= s_lo */ \
- if (m_hi < s_hi) { \
- d_hi = 0; \
- d_lo = 0; \
- } else { \
- /* m_hi >= s_hi */ \
- d_hi = m_hi - s_hi; \
- d_lo = m_lo - s_lo; \
- } \
- } \
- } while (0)
-
-#define UPDATE_STAT64(s, t) \
- do { \
- DIFF_64(diff.hi, new->s##_hi, pstats->mac_stx[0].t##_hi, \
- diff.lo, new->s##_lo, pstats->mac_stx[0].t##_lo); \
- pstats->mac_stx[0].t##_hi = new->s##_hi; \
- pstats->mac_stx[0].t##_lo = new->s##_lo; \
- ADD_64(pstats->mac_stx[1].t##_hi, diff.hi, \
- pstats->mac_stx[1].t##_lo, diff.lo); \
- } while (0)
-
-#define UPDATE_STAT64_NIG(s, t) \
- do { \
- DIFF_64(diff.hi, new->s##_hi, old->s##_hi, \
- diff.lo, new->s##_lo, old->s##_lo); \
- ADD_64(estats->t##_hi, diff.hi, \
- estats->t##_lo, diff.lo); \
- } while (0)
-
-/* sum[hi:lo] += add */
-#define ADD_EXTEND_64(s_hi, s_lo, a) \
- do { \
- s_lo += a; \
- s_hi += (s_lo < a) ? 1 : 0; \
- } while (0)
-
-#define UPDATE_EXTEND_STAT(s) \
- do { \
- ADD_EXTEND_64(pstats->mac_stx[1].s##_hi, \
- pstats->mac_stx[1].s##_lo, \
- new->s); \
- } while (0)
-
-#define UPDATE_EXTEND_TSTAT(s, t) \
- do { \
- diff = le32_to_cpu(tclient->s) - le32_to_cpu(old_tclient->s); \
- old_tclient->s = tclient->s; \
- ADD_EXTEND_64(qstats->t##_hi, qstats->t##_lo, diff); \
- } while (0)
-
-#define UPDATE_EXTEND_USTAT(s, t) \
- do { \
- diff = le32_to_cpu(uclient->s) - le32_to_cpu(old_uclient->s); \
- old_uclient->s = uclient->s; \
- ADD_EXTEND_64(qstats->t##_hi, qstats->t##_lo, diff); \
- } while (0)
-
-#define UPDATE_EXTEND_XSTAT(s, t) \
- do { \
- diff = le32_to_cpu(xclient->s) - le32_to_cpu(old_xclient->s); \
- old_xclient->s = xclient->s; \
- ADD_EXTEND_64(qstats->t##_hi, qstats->t##_lo, diff); \
- } while (0)
-
-/* minuend -= subtrahend */
-#define SUB_64(m_hi, s_hi, m_lo, s_lo) \
- do { \
- DIFF_64(m_hi, m_hi, s_hi, m_lo, m_lo, s_lo); \
- } while (0)
-
-/* minuend[hi:lo] -= subtrahend */
-#define SUB_EXTEND_64(m_hi, m_lo, s) \
- do { \
- SUB_64(m_hi, 0, m_lo, s); \
- } while (0)
-
-#define SUB_EXTEND_USTAT(s, t) \
- do { \
- diff = le32_to_cpu(uclient->s) - le32_to_cpu(old_uclient->s); \
- SUB_EXTEND_64(qstats->t##_hi, qstats->t##_lo, diff); \
- } while (0)
-
-/*
- * General service functions
- */
-
-static inline long bnx2x_hilo(u32 *hiref)
-{
- u32 lo = *(hiref + 1);
-#if (BITS_PER_LONG == 64)
- u32 hi = *hiref;
-
- return HILO_U64(hi, lo);
-#else
- return lo;
-#endif
-}
-
-/*
- * Init service functions
- */
-
-static void bnx2x_storm_stats_post(struct bnx2x *bp)
-{
- if (!bp->stats_pending) {
- struct eth_query_ramrod_data ramrod_data = {0};
- int i, rc;
-
- spin_lock_bh(&bp->stats_lock);
-
- ramrod_data.drv_counter = bp->stats_counter++;
- ramrod_data.collect_port = bp->port.pmf ? 1 : 0;
- for_each_queue(bp, i)
- ramrod_data.ctr_id_vector |= (1 << bp->fp[i].cl_id);
-
- rc = bnx2x_sp_post(bp, RAMROD_CMD_ID_ETH_STAT_QUERY, 0,
- ((u32 *)&ramrod_data)[1],
- ((u32 *)&ramrod_data)[0], 0);
- if (rc == 0) {
- /* stats ramrod has it's own slot on the spq */
- bp->spq_left++;
- bp->stats_pending = 1;
- }
-
- spin_unlock_bh(&bp->stats_lock);
- }
-}
-
-static void bnx2x_hw_stats_post(struct bnx2x *bp)
-{
- struct dmae_command *dmae = &bp->stats_dmae;
- u32 *stats_comp = bnx2x_sp(bp, stats_comp);
-
- *stats_comp = DMAE_COMP_VAL;
- if (CHIP_REV_IS_SLOW(bp))
- return;
-
- /* loader */
- if (bp->executer_idx) {
- int loader_idx = PMF_DMAE_C(bp);
-
- memset(dmae, 0, sizeof(struct dmae_command));
-
- dmae->opcode = (DMAE_CMD_SRC_PCI | DMAE_CMD_DST_GRC |
- DMAE_CMD_C_DST_GRC | DMAE_CMD_C_ENABLE |
- DMAE_CMD_DST_RESET |
-#ifdef __BIG_ENDIAN
- DMAE_CMD_ENDIANITY_B_DW_SWAP |
-#else
- DMAE_CMD_ENDIANITY_DW_SWAP |
-#endif
- (BP_PORT(bp) ? DMAE_CMD_PORT_1 :
- DMAE_CMD_PORT_0) |
- (BP_E1HVN(bp) << DMAE_CMD_E1HVN_SHIFT));
- dmae->src_addr_lo = U64_LO(bnx2x_sp_mapping(bp, dmae[0]));
- dmae->src_addr_hi = U64_HI(bnx2x_sp_mapping(bp, dmae[0]));
- dmae->dst_addr_lo = (DMAE_REG_CMD_MEM +
- sizeof(struct dmae_command) *
- (loader_idx + 1)) >> 2;
- dmae->dst_addr_hi = 0;
- dmae->len = sizeof(struct dmae_command) >> 2;
- if (CHIP_IS_E1(bp))
- dmae->len--;
- dmae->comp_addr_lo = dmae_reg_go_c[loader_idx + 1] >> 2;
- dmae->comp_addr_hi = 0;
- dmae->comp_val = 1;
-
- *stats_comp = 0;
- bnx2x_post_dmae(bp, dmae, loader_idx);
-
- } else if (bp->func_stx) {
- *stats_comp = 0;
- bnx2x_post_dmae(bp, dmae, INIT_DMAE_C(bp));
- }
-}
-
-static int bnx2x_stats_comp(struct bnx2x *bp)
-{
- u32 *stats_comp = bnx2x_sp(bp, stats_comp);
- int cnt = 10;
-
- might_sleep();
- while (*stats_comp != DMAE_COMP_VAL) {
- if (!cnt) {
- BNX2X_ERR("timeout waiting for stats finished\n");
- break;
- }
- cnt--;
- msleep(1);
- }
- return 1;
-}
-
-/*
- * Statistics service functions
- */
-
-static void bnx2x_stats_pmf_update(struct bnx2x *bp)
-{
- struct dmae_command *dmae;
- u32 opcode;
- int loader_idx = PMF_DMAE_C(bp);
- u32 *stats_comp = bnx2x_sp(bp, stats_comp);
-
- /* sanity */
- if (!IS_E1HMF(bp) || !bp->port.pmf || !bp->port.port_stx) {
- BNX2X_ERR("BUG!\n");
- return;
- }
-
- bp->executer_idx = 0;
-
- opcode = (DMAE_CMD_SRC_GRC | DMAE_CMD_DST_PCI |
- DMAE_CMD_C_ENABLE |
- DMAE_CMD_SRC_RESET | DMAE_CMD_DST_RESET |
-#ifdef __BIG_ENDIAN
- DMAE_CMD_ENDIANITY_B_DW_SWAP |
-#else
- DMAE_CMD_ENDIANITY_DW_SWAP |
-#endif
- (BP_PORT(bp) ? DMAE_CMD_PORT_1 : DMAE_CMD_PORT_0) |
- (BP_E1HVN(bp) << DMAE_CMD_E1HVN_SHIFT));
-
- dmae = bnx2x_sp(bp, dmae[bp->executer_idx++]);
- dmae->opcode = (opcode | DMAE_CMD_C_DST_GRC);
- dmae->src_addr_lo = bp->port.port_stx >> 2;
- dmae->src_addr_hi = 0;
- dmae->dst_addr_lo = U64_LO(bnx2x_sp_mapping(bp, port_stats));
- dmae->dst_addr_hi = U64_HI(bnx2x_sp_mapping(bp, port_stats));
- dmae->len = DMAE_LEN32_RD_MAX;
- dmae->comp_addr_lo = dmae_reg_go_c[loader_idx] >> 2;
- dmae->comp_addr_hi = 0;
- dmae->comp_val = 1;
-
- dmae = bnx2x_sp(bp, dmae[bp->executer_idx++]);
- dmae->opcode = (opcode | DMAE_CMD_C_DST_PCI);
- dmae->src_addr_lo = (bp->port.port_stx >> 2) + DMAE_LEN32_RD_MAX;
- dmae->src_addr_hi = 0;
- dmae->dst_addr_lo = U64_LO(bnx2x_sp_mapping(bp, port_stats) +
- DMAE_LEN32_RD_MAX * 4);
- dmae->dst_addr_hi = U64_HI(bnx2x_sp_mapping(bp, port_stats) +
- DMAE_LEN32_RD_MAX * 4);
- dmae->len = (sizeof(struct host_port_stats) >> 2) - DMAE_LEN32_RD_MAX;
- dmae->comp_addr_lo = U64_LO(bnx2x_sp_mapping(bp, stats_comp));
- dmae->comp_addr_hi = U64_HI(bnx2x_sp_mapping(bp, stats_comp));
- dmae->comp_val = DMAE_COMP_VAL;
-
- *stats_comp = 0;
- bnx2x_hw_stats_post(bp);
- bnx2x_stats_comp(bp);
-}
-
-static void bnx2x_port_stats_init(struct bnx2x *bp)
-{
- struct dmae_command *dmae;
- int port = BP_PORT(bp);
- int vn = BP_E1HVN(bp);
- u32 opcode;
- int loader_idx = PMF_DMAE_C(bp);
- u32 mac_addr;
- u32 *stats_comp = bnx2x_sp(bp, stats_comp);
-
- /* sanity */
- if (!bp->link_vars.link_up || !bp->port.pmf) {
- BNX2X_ERR("BUG!\n");
- return;
- }
-
- bp->executer_idx = 0;
-
- /* MCP */
- opcode = (DMAE_CMD_SRC_PCI | DMAE_CMD_DST_GRC |
- DMAE_CMD_C_DST_GRC | DMAE_CMD_C_ENABLE |
- DMAE_CMD_SRC_RESET | DMAE_CMD_DST_RESET |
-#ifdef __BIG_ENDIAN
- DMAE_CMD_ENDIANITY_B_DW_SWAP |
-#else
- DMAE_CMD_ENDIANITY_DW_SWAP |
-#endif
- (port ? DMAE_CMD_PORT_1 : DMAE_CMD_PORT_0) |
- (vn << DMAE_CMD_E1HVN_SHIFT));
-
- if (bp->port.port_stx) {
-
- dmae = bnx2x_sp(bp, dmae[bp->executer_idx++]);
- dmae->opcode = opcode;
- dmae->src_addr_lo = U64_LO(bnx2x_sp_mapping(bp, port_stats));
- dmae->src_addr_hi = U64_HI(bnx2x_sp_mapping(bp, port_stats));
- dmae->dst_addr_lo = bp->port.port_stx >> 2;
- dmae->dst_addr_hi = 0;
- dmae->len = sizeof(struct host_port_stats) >> 2;
- dmae->comp_addr_lo = dmae_reg_go_c[loader_idx] >> 2;
- dmae->comp_addr_hi = 0;
- dmae->comp_val = 1;
- }
-
- if (bp->func_stx) {
-
- dmae = bnx2x_sp(bp, dmae[bp->executer_idx++]);
- dmae->opcode = opcode;
- dmae->src_addr_lo = U64_LO(bnx2x_sp_mapping(bp, func_stats));
- dmae->src_addr_hi = U64_HI(bnx2x_sp_mapping(bp, func_stats));
- dmae->dst_addr_lo = bp->func_stx >> 2;
- dmae->dst_addr_hi = 0;
- dmae->len = sizeof(struct host_func_stats) >> 2;
- dmae->comp_addr_lo = dmae_reg_go_c[loader_idx] >> 2;
- dmae->comp_addr_hi = 0;
- dmae->comp_val = 1;
- }
-
- /* MAC */
- opcode = (DMAE_CMD_SRC_GRC | DMAE_CMD_DST_PCI |
- DMAE_CMD_C_DST_GRC | DMAE_CMD_C_ENABLE |
- DMAE_CMD_SRC_RESET | DMAE_CMD_DST_RESET |
-#ifdef __BIG_ENDIAN
- DMAE_CMD_ENDIANITY_B_DW_SWAP |
-#else
- DMAE_CMD_ENDIANITY_DW_SWAP |
-#endif
- (port ? DMAE_CMD_PORT_1 : DMAE_CMD_PORT_0) |
- (vn << DMAE_CMD_E1HVN_SHIFT));
-
- if (bp->link_vars.mac_type == MAC_TYPE_BMAC) {
-
- mac_addr = (port ? NIG_REG_INGRESS_BMAC1_MEM :
- NIG_REG_INGRESS_BMAC0_MEM);
-
- /* BIGMAC_REGISTER_TX_STAT_GTPKT ..
- BIGMAC_REGISTER_TX_STAT_GTBYT */
- dmae = bnx2x_sp(bp, dmae[bp->executer_idx++]);
- dmae->opcode = opcode;
- dmae->src_addr_lo = (mac_addr +
- BIGMAC_REGISTER_TX_STAT_GTPKT) >> 2;
- dmae->src_addr_hi = 0;
- dmae->dst_addr_lo = U64_LO(bnx2x_sp_mapping(bp, mac_stats));
- dmae->dst_addr_hi = U64_HI(bnx2x_sp_mapping(bp, mac_stats));
- dmae->len = (8 + BIGMAC_REGISTER_TX_STAT_GTBYT -
- BIGMAC_REGISTER_TX_STAT_GTPKT) >> 2;
- dmae->comp_addr_lo = dmae_reg_go_c[loader_idx] >> 2;
- dmae->comp_addr_hi = 0;
- dmae->comp_val = 1;
-
- /* BIGMAC_REGISTER_RX_STAT_GR64 ..
- BIGMAC_REGISTER_RX_STAT_GRIPJ */
- dmae = bnx2x_sp(bp, dmae[bp->executer_idx++]);
- dmae->opcode = opcode;
- dmae->src_addr_lo = (mac_addr +
- BIGMAC_REGISTER_RX_STAT_GR64) >> 2;
- dmae->src_addr_hi = 0;
- dmae->dst_addr_lo = U64_LO(bnx2x_sp_mapping(bp, mac_stats) +
- offsetof(struct bmac_stats, rx_stat_gr64_lo));
- dmae->dst_addr_hi = U64_HI(bnx2x_sp_mapping(bp, mac_stats) +
- offsetof(struct bmac_stats, rx_stat_gr64_lo));
- dmae->len = (8 + BIGMAC_REGISTER_RX_STAT_GRIPJ -
- BIGMAC_REGISTER_RX_STAT_GR64) >> 2;
- dmae->comp_addr_lo = dmae_reg_go_c[loader_idx] >> 2;
- dmae->comp_addr_hi = 0;
- dmae->comp_val = 1;
-
- } else if (bp->link_vars.mac_type == MAC_TYPE_EMAC) {
-
- mac_addr = (port ? GRCBASE_EMAC1 : GRCBASE_EMAC0);
-
- /* EMAC_REG_EMAC_RX_STAT_AC (EMAC_REG_EMAC_RX_STAT_AC_COUNT)*/
- dmae = bnx2x_sp(bp, dmae[bp->executer_idx++]);
- dmae->opcode = opcode;
- dmae->src_addr_lo = (mac_addr +
- EMAC_REG_EMAC_RX_STAT_AC) >> 2;
- dmae->src_addr_hi = 0;
- dmae->dst_addr_lo = U64_LO(bnx2x_sp_mapping(bp, mac_stats));
- dmae->dst_addr_hi = U64_HI(bnx2x_sp_mapping(bp, mac_stats));
- dmae->len = EMAC_REG_EMAC_RX_STAT_AC_COUNT;
- dmae->comp_addr_lo = dmae_reg_go_c[loader_idx] >> 2;
- dmae->comp_addr_hi = 0;
- dmae->comp_val = 1;
-
- /* EMAC_REG_EMAC_RX_STAT_AC_28 */
- dmae = bnx2x_sp(bp, dmae[bp->executer_idx++]);
- dmae->opcode = opcode;
- dmae->src_addr_lo = (mac_addr +
- EMAC_REG_EMAC_RX_STAT_AC_28) >> 2;
- dmae->src_addr_hi = 0;
- dmae->dst_addr_lo = U64_LO(bnx2x_sp_mapping(bp, mac_stats) +
- offsetof(struct emac_stats, rx_stat_falsecarriererrors));
- dmae->dst_addr_hi = U64_HI(bnx2x_sp_mapping(bp, mac_stats) +
- offsetof(struct emac_stats, rx_stat_falsecarriererrors));
- dmae->len = 1;
- dmae->comp_addr_lo = dmae_reg_go_c[loader_idx] >> 2;
- dmae->comp_addr_hi = 0;
- dmae->comp_val = 1;
-
- /* EMAC_REG_EMAC_TX_STAT_AC (EMAC_REG_EMAC_TX_STAT_AC_COUNT)*/
- dmae = bnx2x_sp(bp, dmae[bp->executer_idx++]);
- dmae->opcode = opcode;
- dmae->src_addr_lo = (mac_addr +
- EMAC_REG_EMAC_TX_STAT_AC) >> 2;
- dmae->src_addr_hi = 0;
- dmae->dst_addr_lo = U64_LO(bnx2x_sp_mapping(bp, mac_stats) +
- offsetof(struct emac_stats, tx_stat_ifhcoutoctets));
- dmae->dst_addr_hi = U64_HI(bnx2x_sp_mapping(bp, mac_stats) +
- offsetof(struct emac_stats, tx_stat_ifhcoutoctets));
- dmae->len = EMAC_REG_EMAC_TX_STAT_AC_COUNT;
- dmae->comp_addr_lo = dmae_reg_go_c[loader_idx] >> 2;
- dmae->comp_addr_hi = 0;
- dmae->comp_val = 1;
- }
-
- /* NIG */
- dmae = bnx2x_sp(bp, dmae[bp->executer_idx++]);
- dmae->opcode = opcode;
- dmae->src_addr_lo = (port ? NIG_REG_STAT1_BRB_DISCARD :
- NIG_REG_STAT0_BRB_DISCARD) >> 2;
- dmae->src_addr_hi = 0;
- dmae->dst_addr_lo = U64_LO(bnx2x_sp_mapping(bp, nig_stats));
- dmae->dst_addr_hi = U64_HI(bnx2x_sp_mapping(bp, nig_stats));
- dmae->len = (sizeof(struct nig_stats) - 4*sizeof(u32)) >> 2;
- dmae->comp_addr_lo = dmae_reg_go_c[loader_idx] >> 2;
- dmae->comp_addr_hi = 0;
- dmae->comp_val = 1;
-
- dmae = bnx2x_sp(bp, dmae[bp->executer_idx++]);
- dmae->opcode = opcode;
- dmae->src_addr_lo = (port ? NIG_REG_STAT1_EGRESS_MAC_PKT0 :
- NIG_REG_STAT0_EGRESS_MAC_PKT0) >> 2;
- dmae->src_addr_hi = 0;
- dmae->dst_addr_lo = U64_LO(bnx2x_sp_mapping(bp, nig_stats) +
- offsetof(struct nig_stats, egress_mac_pkt0_lo));
- dmae->dst_addr_hi = U64_HI(bnx2x_sp_mapping(bp, nig_stats) +
- offsetof(struct nig_stats, egress_mac_pkt0_lo));
- dmae->len = (2*sizeof(u32)) >> 2;
- dmae->comp_addr_lo = dmae_reg_go_c[loader_idx] >> 2;
- dmae->comp_addr_hi = 0;
- dmae->comp_val = 1;
-
- dmae = bnx2x_sp(bp, dmae[bp->executer_idx++]);
- dmae->opcode = (DMAE_CMD_SRC_GRC | DMAE_CMD_DST_PCI |
- DMAE_CMD_C_DST_PCI | DMAE_CMD_C_ENABLE |
- DMAE_CMD_SRC_RESET | DMAE_CMD_DST_RESET |
-#ifdef __BIG_ENDIAN
- DMAE_CMD_ENDIANITY_B_DW_SWAP |
-#else
- DMAE_CMD_ENDIANITY_DW_SWAP |
-#endif
- (port ? DMAE_CMD_PORT_1 : DMAE_CMD_PORT_0) |
- (vn << DMAE_CMD_E1HVN_SHIFT));
- dmae->src_addr_lo = (port ? NIG_REG_STAT1_EGRESS_MAC_PKT1 :
- NIG_REG_STAT0_EGRESS_MAC_PKT1) >> 2;
- dmae->src_addr_hi = 0;
- dmae->dst_addr_lo = U64_LO(bnx2x_sp_mapping(bp, nig_stats) +
- offsetof(struct nig_stats, egress_mac_pkt1_lo));
- dmae->dst_addr_hi = U64_HI(bnx2x_sp_mapping(bp, nig_stats) +
- offsetof(struct nig_stats, egress_mac_pkt1_lo));
- dmae->len = (2*sizeof(u32)) >> 2;
- dmae->comp_addr_lo = U64_LO(bnx2x_sp_mapping(bp, stats_comp));
- dmae->comp_addr_hi = U64_HI(bnx2x_sp_mapping(bp, stats_comp));
- dmae->comp_val = DMAE_COMP_VAL;
-
- *stats_comp = 0;
-}
-
-static void bnx2x_func_stats_init(struct bnx2x *bp)
-{
- struct dmae_command *dmae = &bp->stats_dmae;
- u32 *stats_comp = bnx2x_sp(bp, stats_comp);
-
- /* sanity */
- if (!bp->func_stx) {
- BNX2X_ERR("BUG!\n");
- return;
- }
-
- bp->executer_idx = 0;
- memset(dmae, 0, sizeof(struct dmae_command));
-
- dmae->opcode = (DMAE_CMD_SRC_PCI | DMAE_CMD_DST_GRC |
- DMAE_CMD_C_DST_PCI | DMAE_CMD_C_ENABLE |
- DMAE_CMD_SRC_RESET | DMAE_CMD_DST_RESET |
-#ifdef __BIG_ENDIAN
- DMAE_CMD_ENDIANITY_B_DW_SWAP |
-#else
- DMAE_CMD_ENDIANITY_DW_SWAP |
-#endif
- (BP_PORT(bp) ? DMAE_CMD_PORT_1 : DMAE_CMD_PORT_0) |
- (BP_E1HVN(bp) << DMAE_CMD_E1HVN_SHIFT));
- dmae->src_addr_lo = U64_LO(bnx2x_sp_mapping(bp, func_stats));
- dmae->src_addr_hi = U64_HI(bnx2x_sp_mapping(bp, func_stats));
- dmae->dst_addr_lo = bp->func_stx >> 2;
- dmae->dst_addr_hi = 0;
- dmae->len = sizeof(struct host_func_stats) >> 2;
- dmae->comp_addr_lo = U64_LO(bnx2x_sp_mapping(bp, stats_comp));
- dmae->comp_addr_hi = U64_HI(bnx2x_sp_mapping(bp, stats_comp));
- dmae->comp_val = DMAE_COMP_VAL;
-
- *stats_comp = 0;
-}
-
-static void bnx2x_stats_start(struct bnx2x *bp)
-{
- if (bp->port.pmf)
- bnx2x_port_stats_init(bp);
-
- else if (bp->func_stx)
- bnx2x_func_stats_init(bp);
-
- bnx2x_hw_stats_post(bp);
- bnx2x_storm_stats_post(bp);
-}
-
-static void bnx2x_stats_pmf_start(struct bnx2x *bp)
-{
- bnx2x_stats_comp(bp);
- bnx2x_stats_pmf_update(bp);
- bnx2x_stats_start(bp);
-}
-
-static void bnx2x_stats_restart(struct bnx2x *bp)
-{
- bnx2x_stats_comp(bp);
- bnx2x_stats_start(bp);
-}
-
-static void bnx2x_bmac_stats_update(struct bnx2x *bp)
-{
- struct bmac_stats *new = bnx2x_sp(bp, mac_stats.bmac_stats);
- struct host_port_stats *pstats = bnx2x_sp(bp, port_stats);
- struct bnx2x_eth_stats *estats = &bp->eth_stats;
- struct {
- u32 lo;
- u32 hi;
- } diff;
-
- UPDATE_STAT64(rx_stat_grerb, rx_stat_ifhcinbadoctets);
- UPDATE_STAT64(rx_stat_grfcs, rx_stat_dot3statsfcserrors);
- UPDATE_STAT64(rx_stat_grund, rx_stat_etherstatsundersizepkts);
- UPDATE_STAT64(rx_stat_grovr, rx_stat_dot3statsframestoolong);
- UPDATE_STAT64(rx_stat_grfrg, rx_stat_etherstatsfragments);
- UPDATE_STAT64(rx_stat_grjbr, rx_stat_etherstatsjabbers);
- UPDATE_STAT64(rx_stat_grxcf, rx_stat_maccontrolframesreceived);
- UPDATE_STAT64(rx_stat_grxpf, rx_stat_xoffstateentered);
- UPDATE_STAT64(rx_stat_grxpf, rx_stat_bmac_xpf);
- UPDATE_STAT64(tx_stat_gtxpf, tx_stat_outxoffsent);
- UPDATE_STAT64(tx_stat_gtxpf, tx_stat_flowcontroldone);
- UPDATE_STAT64(tx_stat_gt64, tx_stat_etherstatspkts64octets);
- UPDATE_STAT64(tx_stat_gt127,
- tx_stat_etherstatspkts65octetsto127octets);
- UPDATE_STAT64(tx_stat_gt255,
- tx_stat_etherstatspkts128octetsto255octets);
- UPDATE_STAT64(tx_stat_gt511,
- tx_stat_etherstatspkts256octetsto511octets);
- UPDATE_STAT64(tx_stat_gt1023,
- tx_stat_etherstatspkts512octetsto1023octets);
- UPDATE_STAT64(tx_stat_gt1518,
- tx_stat_etherstatspkts1024octetsto1522octets);
- UPDATE_STAT64(tx_stat_gt2047, tx_stat_bmac_2047);
- UPDATE_STAT64(tx_stat_gt4095, tx_stat_bmac_4095);
- UPDATE_STAT64(tx_stat_gt9216, tx_stat_bmac_9216);
- UPDATE_STAT64(tx_stat_gt16383, tx_stat_bmac_16383);
- UPDATE_STAT64(tx_stat_gterr,
- tx_stat_dot3statsinternalmactransmiterrors);
- UPDATE_STAT64(tx_stat_gtufl, tx_stat_bmac_ufl);
-
- estats->pause_frames_received_hi =
- pstats->mac_stx[1].rx_stat_bmac_xpf_hi;
- estats->pause_frames_received_lo =
- pstats->mac_stx[1].rx_stat_bmac_xpf_lo;
-
- estats->pause_frames_sent_hi =
- pstats->mac_stx[1].tx_stat_outxoffsent_hi;
- estats->pause_frames_sent_lo =
- pstats->mac_stx[1].tx_stat_outxoffsent_lo;
-}
-
-static void bnx2x_emac_stats_update(struct bnx2x *bp)
-{
- struct emac_stats *new = bnx2x_sp(bp, mac_stats.emac_stats);
- struct host_port_stats *pstats = bnx2x_sp(bp, port_stats);
- struct bnx2x_eth_stats *estats = &bp->eth_stats;
-
- UPDATE_EXTEND_STAT(rx_stat_ifhcinbadoctets);
- UPDATE_EXTEND_STAT(tx_stat_ifhcoutbadoctets);
- UPDATE_EXTEND_STAT(rx_stat_dot3statsfcserrors);
- UPDATE_EXTEND_STAT(rx_stat_dot3statsalignmenterrors);
- UPDATE_EXTEND_STAT(rx_stat_dot3statscarriersenseerrors);
- UPDATE_EXTEND_STAT(rx_stat_falsecarriererrors);
- UPDATE_EXTEND_STAT(rx_stat_etherstatsundersizepkts);
- UPDATE_EXTEND_STAT(rx_stat_dot3statsframestoolong);
- UPDATE_EXTEND_STAT(rx_stat_etherstatsfragments);
- UPDATE_EXTEND_STAT(rx_stat_etherstatsjabbers);
- UPDATE_EXTEND_STAT(rx_stat_maccontrolframesreceived);
- UPDATE_EXTEND_STAT(rx_stat_xoffstateentered);
- UPDATE_EXTEND_STAT(rx_stat_xonpauseframesreceived);
- UPDATE_EXTEND_STAT(rx_stat_xoffpauseframesreceived);
- UPDATE_EXTEND_STAT(tx_stat_outxonsent);
- UPDATE_EXTEND_STAT(tx_stat_outxoffsent);
- UPDATE_EXTEND_STAT(tx_stat_flowcontroldone);
- UPDATE_EXTEND_STAT(tx_stat_etherstatscollisions);
- UPDATE_EXTEND_STAT(tx_stat_dot3statssinglecollisionframes);
- UPDATE_EXTEND_STAT(tx_stat_dot3statsmultiplecollisionframes);
- UPDATE_EXTEND_STAT(tx_stat_dot3statsdeferredtransmissions);
- UPDATE_EXTEND_STAT(tx_stat_dot3statsexcessivecollisions);
- UPDATE_EXTEND_STAT(tx_stat_dot3statslatecollisions);
- UPDATE_EXTEND_STAT(tx_stat_etherstatspkts64octets);
- UPDATE_EXTEND_STAT(tx_stat_etherstatspkts65octetsto127octets);
- UPDATE_EXTEND_STAT(tx_stat_etherstatspkts128octetsto255octets);
- UPDATE_EXTEND_STAT(tx_stat_etherstatspkts256octetsto511octets);
- UPDATE_EXTEND_STAT(tx_stat_etherstatspkts512octetsto1023octets);
- UPDATE_EXTEND_STAT(tx_stat_etherstatspkts1024octetsto1522octets);
- UPDATE_EXTEND_STAT(tx_stat_etherstatspktsover1522octets);
- UPDATE_EXTEND_STAT(tx_stat_dot3statsinternalmactransmiterrors);
-
- estats->pause_frames_received_hi =
- pstats->mac_stx[1].rx_stat_xonpauseframesreceived_hi;
- estats->pause_frames_received_lo =
- pstats->mac_stx[1].rx_stat_xonpauseframesreceived_lo;
- ADD_64(estats->pause_frames_received_hi,
- pstats->mac_stx[1].rx_stat_xoffpauseframesreceived_hi,
- estats->pause_frames_received_lo,
- pstats->mac_stx[1].rx_stat_xoffpauseframesreceived_lo);
-
- estats->pause_frames_sent_hi =
- pstats->mac_stx[1].tx_stat_outxonsent_hi;
- estats->pause_frames_sent_lo =
- pstats->mac_stx[1].tx_stat_outxonsent_lo;
- ADD_64(estats->pause_frames_sent_hi,
- pstats->mac_stx[1].tx_stat_outxoffsent_hi,
- estats->pause_frames_sent_lo,
- pstats->mac_stx[1].tx_stat_outxoffsent_lo);
-}
-
-static int bnx2x_hw_stats_update(struct bnx2x *bp)
-{
- struct nig_stats *new = bnx2x_sp(bp, nig_stats);
- struct nig_stats *old = &(bp->port.old_nig_stats);
- struct host_port_stats *pstats = bnx2x_sp(bp, port_stats);
- struct bnx2x_eth_stats *estats = &bp->eth_stats;
- struct {
- u32 lo;
- u32 hi;
- } diff;
-
- if (bp->link_vars.mac_type == MAC_TYPE_BMAC)
- bnx2x_bmac_stats_update(bp);
-
- else if (bp->link_vars.mac_type == MAC_TYPE_EMAC)
- bnx2x_emac_stats_update(bp);
-
- else { /* unreached */
- BNX2X_ERR("stats updated by DMAE but no MAC active\n");
- return -1;
- }
-
- ADD_EXTEND_64(pstats->brb_drop_hi, pstats->brb_drop_lo,
- new->brb_discard - old->brb_discard);
- ADD_EXTEND_64(estats->brb_truncate_hi, estats->brb_truncate_lo,
- new->brb_truncate - old->brb_truncate);
-
- UPDATE_STAT64_NIG(egress_mac_pkt0,
- etherstatspkts1024octetsto1522octets);
- UPDATE_STAT64_NIG(egress_mac_pkt1, etherstatspktsover1522octets);
-
- memcpy(old, new, sizeof(struct nig_stats));
-
- memcpy(&(estats->rx_stat_ifhcinbadoctets_hi), &(pstats->mac_stx[1]),
- sizeof(struct mac_stx));
- estats->brb_drop_hi = pstats->brb_drop_hi;
- estats->brb_drop_lo = pstats->brb_drop_lo;
-
- pstats->host_port_stats_start = ++pstats->host_port_stats_end;
-
- if (!BP_NOMCP(bp)) {
- u32 nig_timer_max =
- SHMEM_RD(bp, port_mb[BP_PORT(bp)].stat_nig_timer);
- if (nig_timer_max != estats->nig_timer_max) {
- estats->nig_timer_max = nig_timer_max;
- BNX2X_ERR("NIG timer max (%u)\n",
- estats->nig_timer_max);
- }
- }
-
- return 0;
-}
-
-static int bnx2x_storm_stats_update(struct bnx2x *bp)
-{
- struct eth_stats_query *stats = bnx2x_sp(bp, fw_stats);
- struct tstorm_per_port_stats *tport =
- &stats->tstorm_common.port_statistics;
- struct host_func_stats *fstats = bnx2x_sp(bp, func_stats);
- struct bnx2x_eth_stats *estats = &bp->eth_stats;
- int i;
- u16 cur_stats_counter;
-
- /* Make sure we use the value of the counter
- * used for sending the last stats ramrod.
- */
- spin_lock_bh(&bp->stats_lock);
- cur_stats_counter = bp->stats_counter - 1;
- spin_unlock_bh(&bp->stats_lock);
-
- memcpy(&(fstats->total_bytes_received_hi),
- &(bnx2x_sp(bp, func_stats_base)->total_bytes_received_hi),
- sizeof(struct host_func_stats) - 2*sizeof(u32));
- estats->error_bytes_received_hi = 0;
- estats->error_bytes_received_lo = 0;
- estats->etherstatsoverrsizepkts_hi = 0;
- estats->etherstatsoverrsizepkts_lo = 0;
- estats->no_buff_discard_hi = 0;
- estats->no_buff_discard_lo = 0;
-
- for_each_queue(bp, i) {
- struct bnx2x_fastpath *fp = &bp->fp[i];
- int cl_id = fp->cl_id;
- struct tstorm_per_client_stats *tclient =
- &stats->tstorm_common.client_statistics[cl_id];
- struct tstorm_per_client_stats *old_tclient = &fp->old_tclient;
- struct ustorm_per_client_stats *uclient =
- &stats->ustorm_common.client_statistics[cl_id];
- struct ustorm_per_client_stats *old_uclient = &fp->old_uclient;
- struct xstorm_per_client_stats *xclient =
- &stats->xstorm_common.client_statistics[cl_id];
- struct xstorm_per_client_stats *old_xclient = &fp->old_xclient;
- struct bnx2x_eth_q_stats *qstats = &fp->eth_q_stats;
- u32 diff;
-
- /* are storm stats valid? */
- if (le16_to_cpu(xclient->stats_counter) != cur_stats_counter) {
- DP(BNX2X_MSG_STATS, "[%d] stats not updated by xstorm"
- " xstorm counter (0x%x) != stats_counter (0x%x)\n",
- i, xclient->stats_counter, cur_stats_counter + 1);
- return -1;
- }
- if (le16_to_cpu(tclient->stats_counter) != cur_stats_counter) {
- DP(BNX2X_MSG_STATS, "[%d] stats not updated by tstorm"
- " tstorm counter (0x%x) != stats_counter (0x%x)\n",
- i, tclient->stats_counter, cur_stats_counter + 1);
- return -2;
- }
- if (le16_to_cpu(uclient->stats_counter) != cur_stats_counter) {
- DP(BNX2X_MSG_STATS, "[%d] stats not updated by ustorm"
- " ustorm counter (0x%x) != stats_counter (0x%x)\n",
- i, uclient->stats_counter, cur_stats_counter + 1);
- return -4;
- }
-
- qstats->total_bytes_received_hi =
- le32_to_cpu(tclient->rcv_broadcast_bytes.hi);
- qstats->total_bytes_received_lo =
- le32_to_cpu(tclient->rcv_broadcast_bytes.lo);
-
- ADD_64(qstats->total_bytes_received_hi,
- le32_to_cpu(tclient->rcv_multicast_bytes.hi),
- qstats->total_bytes_received_lo,
- le32_to_cpu(tclient->rcv_multicast_bytes.lo));
-
- ADD_64(qstats->total_bytes_received_hi,
- le32_to_cpu(tclient->rcv_unicast_bytes.hi),
- qstats->total_bytes_received_lo,
- le32_to_cpu(tclient->rcv_unicast_bytes.lo));
-
- SUB_64(qstats->total_bytes_received_hi,
- le32_to_cpu(uclient->bcast_no_buff_bytes.hi),
- qstats->total_bytes_received_lo,
- le32_to_cpu(uclient->bcast_no_buff_bytes.lo));
-
- SUB_64(qstats->total_bytes_received_hi,
- le32_to_cpu(uclient->mcast_no_buff_bytes.hi),
- qstats->total_bytes_received_lo,
- le32_to_cpu(uclient->mcast_no_buff_bytes.lo));
-
- SUB_64(qstats->total_bytes_received_hi,
- le32_to_cpu(uclient->ucast_no_buff_bytes.hi),
- qstats->total_bytes_received_lo,
- le32_to_cpu(uclient->ucast_no_buff_bytes.lo));
-
- qstats->valid_bytes_received_hi =
- qstats->total_bytes_received_hi;
- qstats->valid_bytes_received_lo =
- qstats->total_bytes_received_lo;
-
- qstats->error_bytes_received_hi =
- le32_to_cpu(tclient->rcv_error_bytes.hi);
- qstats->error_bytes_received_lo =
- le32_to_cpu(tclient->rcv_error_bytes.lo);
-
- ADD_64(qstats->total_bytes_received_hi,
- qstats->error_bytes_received_hi,
- qstats->total_bytes_received_lo,
- qstats->error_bytes_received_lo);
-
- UPDATE_EXTEND_TSTAT(rcv_unicast_pkts,
- total_unicast_packets_received);
- UPDATE_EXTEND_TSTAT(rcv_multicast_pkts,
- total_multicast_packets_received);
- UPDATE_EXTEND_TSTAT(rcv_broadcast_pkts,
- total_broadcast_packets_received);
- UPDATE_EXTEND_TSTAT(packets_too_big_discard,
- etherstatsoverrsizepkts);
- UPDATE_EXTEND_TSTAT(no_buff_discard, no_buff_discard);
-
- SUB_EXTEND_USTAT(ucast_no_buff_pkts,
- total_unicast_packets_received);
- SUB_EXTEND_USTAT(mcast_no_buff_pkts,
- total_multicast_packets_received);
- SUB_EXTEND_USTAT(bcast_no_buff_pkts,
- total_broadcast_packets_received);
- UPDATE_EXTEND_USTAT(ucast_no_buff_pkts, no_buff_discard);
- UPDATE_EXTEND_USTAT(mcast_no_buff_pkts, no_buff_discard);
- UPDATE_EXTEND_USTAT(bcast_no_buff_pkts, no_buff_discard);
-
- qstats->total_bytes_transmitted_hi =
- le32_to_cpu(xclient->unicast_bytes_sent.hi);
- qstats->total_bytes_transmitted_lo =
- le32_to_cpu(xclient->unicast_bytes_sent.lo);
-
- ADD_64(qstats->total_bytes_transmitted_hi,
- le32_to_cpu(xclient->multicast_bytes_sent.hi),
- qstats->total_bytes_transmitted_lo,
- le32_to_cpu(xclient->multicast_bytes_sent.lo));
-
- ADD_64(qstats->total_bytes_transmitted_hi,
- le32_to_cpu(xclient->broadcast_bytes_sent.hi),
- qstats->total_bytes_transmitted_lo,
- le32_to_cpu(xclient->broadcast_bytes_sent.lo));
-
- UPDATE_EXTEND_XSTAT(unicast_pkts_sent,
- total_unicast_packets_transmitted);
- UPDATE_EXTEND_XSTAT(multicast_pkts_sent,
- total_multicast_packets_transmitted);
- UPDATE_EXTEND_XSTAT(broadcast_pkts_sent,
- total_broadcast_packets_transmitted);
-
- old_tclient->checksum_discard = tclient->checksum_discard;
- old_tclient->ttl0_discard = tclient->ttl0_discard;
-
- ADD_64(fstats->total_bytes_received_hi,
- qstats->total_bytes_received_hi,
- fstats->total_bytes_received_lo,
- qstats->total_bytes_received_lo);
- ADD_64(fstats->total_bytes_transmitted_hi,
- qstats->total_bytes_transmitted_hi,
- fstats->total_bytes_transmitted_lo,
- qstats->total_bytes_transmitted_lo);
- ADD_64(fstats->total_unicast_packets_received_hi,
- qstats->total_unicast_packets_received_hi,
- fstats->total_unicast_packets_received_lo,
- qstats->total_unicast_packets_received_lo);
- ADD_64(fstats->total_multicast_packets_received_hi,
- qstats->total_multicast_packets_received_hi,
- fstats->total_multicast_packets_received_lo,
- qstats->total_multicast_packets_received_lo);
- ADD_64(fstats->total_broadcast_packets_received_hi,
- qstats->total_broadcast_packets_received_hi,
- fstats->total_broadcast_packets_received_lo,
- qstats->total_broadcast_packets_received_lo);
- ADD_64(fstats->total_unicast_packets_transmitted_hi,
- qstats->total_unicast_packets_transmitted_hi,
- fstats->total_unicast_packets_transmitted_lo,
- qstats->total_unicast_packets_transmitted_lo);
- ADD_64(fstats->total_multicast_packets_transmitted_hi,
- qstats->total_multicast_packets_transmitted_hi,
- fstats->total_multicast_packets_transmitted_lo,
- qstats->total_multicast_packets_transmitted_lo);
- ADD_64(fstats->total_broadcast_packets_transmitted_hi,
- qstats->total_broadcast_packets_transmitted_hi,
- fstats->total_broadcast_packets_transmitted_lo,
- qstats->total_broadcast_packets_transmitted_lo);
- ADD_64(fstats->valid_bytes_received_hi,
- qstats->valid_bytes_received_hi,
- fstats->valid_bytes_received_lo,
- qstats->valid_bytes_received_lo);
-
- ADD_64(estats->error_bytes_received_hi,
- qstats->error_bytes_received_hi,
- estats->error_bytes_received_lo,
- qstats->error_bytes_received_lo);
- ADD_64(estats->etherstatsoverrsizepkts_hi,
- qstats->etherstatsoverrsizepkts_hi,
- estats->etherstatsoverrsizepkts_lo,
- qstats->etherstatsoverrsizepkts_lo);
- ADD_64(estats->no_buff_discard_hi, qstats->no_buff_discard_hi,
- estats->no_buff_discard_lo, qstats->no_buff_discard_lo);
- }
-
- ADD_64(fstats->total_bytes_received_hi,
- estats->rx_stat_ifhcinbadoctets_hi,
- fstats->total_bytes_received_lo,
- estats->rx_stat_ifhcinbadoctets_lo);
-
- memcpy(estats, &(fstats->total_bytes_received_hi),
- sizeof(struct host_func_stats) - 2*sizeof(u32));
-
- ADD_64(estats->etherstatsoverrsizepkts_hi,
- estats->rx_stat_dot3statsframestoolong_hi,
- estats->etherstatsoverrsizepkts_lo,
- estats->rx_stat_dot3statsframestoolong_lo);
- ADD_64(estats->error_bytes_received_hi,
- estats->rx_stat_ifhcinbadoctets_hi,
- estats->error_bytes_received_lo,
- estats->rx_stat_ifhcinbadoctets_lo);
-
- if (bp->port.pmf) {
- estats->mac_filter_discard =
- le32_to_cpu(tport->mac_filter_discard);
- estats->xxoverflow_discard =
- le32_to_cpu(tport->xxoverflow_discard);
- estats->brb_truncate_discard =
- le32_to_cpu(tport->brb_truncate_discard);
- estats->mac_discard = le32_to_cpu(tport->mac_discard);
- }
-
- fstats->host_func_stats_start = ++fstats->host_func_stats_end;
-
- bp->stats_pending = 0;
-
- return 0;
-}
-
-static void bnx2x_net_stats_update(struct bnx2x *bp)
-{
- struct bnx2x_eth_stats *estats = &bp->eth_stats;
- struct net_device_stats *nstats = &bp->dev->stats;
- int i;
-
- nstats->rx_packets =
- bnx2x_hilo(&estats->total_unicast_packets_received_hi) +
- bnx2x_hilo(&estats->total_multicast_packets_received_hi) +
- bnx2x_hilo(&estats->total_broadcast_packets_received_hi);
-
- nstats->tx_packets =
- bnx2x_hilo(&estats->total_unicast_packets_transmitted_hi) +
- bnx2x_hilo(&estats->total_multicast_packets_transmitted_hi) +
- bnx2x_hilo(&estats->total_broadcast_packets_transmitted_hi);
-
- nstats->rx_bytes = bnx2x_hilo(&estats->total_bytes_received_hi);
-
- nstats->tx_bytes = bnx2x_hilo(&estats->total_bytes_transmitted_hi);
-
- nstats->rx_dropped = estats->mac_discard;
- for_each_queue(bp, i)
- nstats->rx_dropped +=
- le32_to_cpu(bp->fp[i].old_tclient.checksum_discard);
-
- nstats->tx_dropped = 0;
-
- nstats->multicast =
- bnx2x_hilo(&estats->total_multicast_packets_received_hi);
-
- nstats->collisions =
- bnx2x_hilo(&estats->tx_stat_etherstatscollisions_hi);
-
- nstats->rx_length_errors =
- bnx2x_hilo(&estats->rx_stat_etherstatsundersizepkts_hi) +
- bnx2x_hilo(&estats->etherstatsoverrsizepkts_hi);
- nstats->rx_over_errors = bnx2x_hilo(&estats->brb_drop_hi) +
- bnx2x_hilo(&estats->brb_truncate_hi);
- nstats->rx_crc_errors =
- bnx2x_hilo(&estats->rx_stat_dot3statsfcserrors_hi);
- nstats->rx_frame_errors =
- bnx2x_hilo(&estats->rx_stat_dot3statsalignmenterrors_hi);
- nstats->rx_fifo_errors = bnx2x_hilo(&estats->no_buff_discard_hi);
- nstats->rx_missed_errors = estats->xxoverflow_discard;
-
- nstats->rx_errors = nstats->rx_length_errors +
- nstats->rx_over_errors +
- nstats->rx_crc_errors +
- nstats->rx_frame_errors +
- nstats->rx_fifo_errors +
- nstats->rx_missed_errors;
-
- nstats->tx_aborted_errors =
- bnx2x_hilo(&estats->tx_stat_dot3statslatecollisions_hi) +
- bnx2x_hilo(&estats->tx_stat_dot3statsexcessivecollisions_hi);
- nstats->tx_carrier_errors =
- bnx2x_hilo(&estats->rx_stat_dot3statscarriersenseerrors_hi);
- nstats->tx_fifo_errors = 0;
- nstats->tx_heartbeat_errors = 0;
- nstats->tx_window_errors = 0;
-
- nstats->tx_errors = nstats->tx_aborted_errors +
- nstats->tx_carrier_errors +
- bnx2x_hilo(&estats->tx_stat_dot3statsinternalmactransmiterrors_hi);
-}
-
-static void bnx2x_drv_stats_update(struct bnx2x *bp)
-{
- struct bnx2x_eth_stats *estats = &bp->eth_stats;
- int i;
-
- estats->driver_xoff = 0;
- estats->rx_err_discard_pkt = 0;
- estats->rx_skb_alloc_failed = 0;
- estats->hw_csum_err = 0;
- for_each_queue(bp, i) {
- struct bnx2x_eth_q_stats *qstats = &bp->fp[i].eth_q_stats;
-
- estats->driver_xoff += qstats->driver_xoff;
- estats->rx_err_discard_pkt += qstats->rx_err_discard_pkt;
- estats->rx_skb_alloc_failed += qstats->rx_skb_alloc_failed;
- estats->hw_csum_err += qstats->hw_csum_err;
- }
-}
-
-static void bnx2x_stats_update(struct bnx2x *bp)
-{
- u32 *stats_comp = bnx2x_sp(bp, stats_comp);
-
- if (*stats_comp != DMAE_COMP_VAL)
- return;
-
- if (bp->port.pmf)
- bnx2x_hw_stats_update(bp);
-
- if (bnx2x_storm_stats_update(bp) && (bp->stats_pending++ == 3)) {
- BNX2X_ERR("storm stats were not updated for 3 times\n");
- bnx2x_panic();
- return;
- }
-
- bnx2x_net_stats_update(bp);
- bnx2x_drv_stats_update(bp);
-
- if (netif_msg_timer(bp)) {
- struct bnx2x_eth_stats *estats = &bp->eth_stats;
- int i;
-
- printk(KERN_DEBUG "%s: brb drops %u brb truncate %u\n",
- bp->dev->name,
- estats->brb_drop_lo, estats->brb_truncate_lo);
-
- for_each_queue(bp, i) {
- struct bnx2x_fastpath *fp = &bp->fp[i];
- struct bnx2x_eth_q_stats *qstats = &fp->eth_q_stats;
-
- printk(KERN_DEBUG "%s: rx usage(%4u) *rx_cons_sb(%u)"
- " rx pkt(%lu) rx calls(%lu %lu)\n",
- fp->name, (le16_to_cpu(*fp->rx_cons_sb) -
- fp->rx_comp_cons),
- le16_to_cpu(*fp->rx_cons_sb),
- bnx2x_hilo(&qstats->
- total_unicast_packets_received_hi),
- fp->rx_calls, fp->rx_pkt);
- }
-
- for_each_queue(bp, i) {
- struct bnx2x_fastpath *fp = &bp->fp[i];
- struct bnx2x_eth_q_stats *qstats = &fp->eth_q_stats;
- struct netdev_queue *txq =
- netdev_get_tx_queue(bp->dev, i);
-
- printk(KERN_DEBUG "%s: tx avail(%4u) *tx_cons_sb(%u)"
- " tx pkt(%lu) tx calls (%lu)"
- " %s (Xoff events %u)\n",
- fp->name, bnx2x_tx_avail(fp),
- le16_to_cpu(*fp->tx_cons_sb),
- bnx2x_hilo(&qstats->
- total_unicast_packets_transmitted_hi),
- fp->tx_pkt,
- (netif_tx_queue_stopped(txq) ? "Xoff" : "Xon"),
- qstats->driver_xoff);
- }
- }
-
- bnx2x_hw_stats_post(bp);
- bnx2x_storm_stats_post(bp);
-}
-
-static void bnx2x_port_stats_stop(struct bnx2x *bp)
-{
- struct dmae_command *dmae;
- u32 opcode;
- int loader_idx = PMF_DMAE_C(bp);
- u32 *stats_comp = bnx2x_sp(bp, stats_comp);
-
- bp->executer_idx = 0;
-
- opcode = (DMAE_CMD_SRC_PCI | DMAE_CMD_DST_GRC |
- DMAE_CMD_C_ENABLE |
- DMAE_CMD_SRC_RESET | DMAE_CMD_DST_RESET |
-#ifdef __BIG_ENDIAN
- DMAE_CMD_ENDIANITY_B_DW_SWAP |
-#else
- DMAE_CMD_ENDIANITY_DW_SWAP |
-#endif
- (BP_PORT(bp) ? DMAE_CMD_PORT_1 : DMAE_CMD_PORT_0) |
- (BP_E1HVN(bp) << DMAE_CMD_E1HVN_SHIFT));
-
- if (bp->port.port_stx) {
-
- dmae = bnx2x_sp(bp, dmae[bp->executer_idx++]);
- if (bp->func_stx)
- dmae->opcode = (opcode | DMAE_CMD_C_DST_GRC);
- else
- dmae->opcode = (opcode | DMAE_CMD_C_DST_PCI);
- dmae->src_addr_lo = U64_LO(bnx2x_sp_mapping(bp, port_stats));
- dmae->src_addr_hi = U64_HI(bnx2x_sp_mapping(bp, port_stats));
- dmae->dst_addr_lo = bp->port.port_stx >> 2;
- dmae->dst_addr_hi = 0;
- dmae->len = sizeof(struct host_port_stats) >> 2;
- if (bp->func_stx) {
- dmae->comp_addr_lo = dmae_reg_go_c[loader_idx] >> 2;
- dmae->comp_addr_hi = 0;
- dmae->comp_val = 1;
- } else {
- dmae->comp_addr_lo =
- U64_LO(bnx2x_sp_mapping(bp, stats_comp));
- dmae->comp_addr_hi =
- U64_HI(bnx2x_sp_mapping(bp, stats_comp));
- dmae->comp_val = DMAE_COMP_VAL;
-
- *stats_comp = 0;
- }
- }
-
- if (bp->func_stx) {
-
- dmae = bnx2x_sp(bp, dmae[bp->executer_idx++]);
- dmae->opcode = (opcode | DMAE_CMD_C_DST_PCI);
- dmae->src_addr_lo = U64_LO(bnx2x_sp_mapping(bp, func_stats));
- dmae->src_addr_hi = U64_HI(bnx2x_sp_mapping(bp, func_stats));
- dmae->dst_addr_lo = bp->func_stx >> 2;
- dmae->dst_addr_hi = 0;
- dmae->len = sizeof(struct host_func_stats) >> 2;
- dmae->comp_addr_lo = U64_LO(bnx2x_sp_mapping(bp, stats_comp));
- dmae->comp_addr_hi = U64_HI(bnx2x_sp_mapping(bp, stats_comp));
- dmae->comp_val = DMAE_COMP_VAL;
-
- *stats_comp = 0;
- }
-}
-
-static void bnx2x_stats_stop(struct bnx2x *bp)
-{
- int update = 0;
-
- bnx2x_stats_comp(bp);
-
- if (bp->port.pmf)
- update = (bnx2x_hw_stats_update(bp) == 0);
-
- update |= (bnx2x_storm_stats_update(bp) == 0);
-
- if (update) {
- bnx2x_net_stats_update(bp);
-
- if (bp->port.pmf)
- bnx2x_port_stats_stop(bp);
-
- bnx2x_hw_stats_post(bp);
- bnx2x_stats_comp(bp);
- }
-}
-
-static void bnx2x_stats_do_nothing(struct bnx2x *bp)
-{
-}
-
-static const struct {
- void (*action)(struct bnx2x *bp);
- enum bnx2x_stats_state next_state;
-} bnx2x_stats_stm[STATS_STATE_MAX][STATS_EVENT_MAX] = {
-/* state event */
-{
-/* DISABLED PMF */ {bnx2x_stats_pmf_update, STATS_STATE_DISABLED},
-/* LINK_UP */ {bnx2x_stats_start, STATS_STATE_ENABLED},
-/* UPDATE */ {bnx2x_stats_do_nothing, STATS_STATE_DISABLED},
-/* STOP */ {bnx2x_stats_do_nothing, STATS_STATE_DISABLED}
-},
-{
-/* ENABLED PMF */ {bnx2x_stats_pmf_start, STATS_STATE_ENABLED},
-/* LINK_UP */ {bnx2x_stats_restart, STATS_STATE_ENABLED},
-/* UPDATE */ {bnx2x_stats_update, STATS_STATE_ENABLED},
-/* STOP */ {bnx2x_stats_stop, STATS_STATE_DISABLED}
-}
-};
-
-static void bnx2x_stats_handle(struct bnx2x *bp, enum bnx2x_stats_event event)
-{
- enum bnx2x_stats_state state;
-
- if (unlikely(bp->panic))
- return;
-
- /* Protect a state change flow */
- spin_lock_bh(&bp->stats_lock);
- state = bp->stats_state;
- bp->stats_state = bnx2x_stats_stm[state][event].next_state;
- spin_unlock_bh(&bp->stats_lock);
-
- bnx2x_stats_stm[state][event].action(bp);
-
- if ((event != STATS_EVENT_UPDATE) || netif_msg_timer(bp))
- DP(BNX2X_MSG_STATS, "state %d -> event %d -> state %d\n",
- state, event, bp->stats_state);
-}
-
-static void bnx2x_port_stats_base_init(struct bnx2x *bp)
-{
- struct dmae_command *dmae;
- u32 *stats_comp = bnx2x_sp(bp, stats_comp);
-
- /* sanity */
- if (!bp->port.pmf || !bp->port.port_stx) {
- BNX2X_ERR("BUG!\n");
- return;
- }
-
- bp->executer_idx = 0;
-
- dmae = bnx2x_sp(bp, dmae[bp->executer_idx++]);
- dmae->opcode = (DMAE_CMD_SRC_PCI | DMAE_CMD_DST_GRC |
- DMAE_CMD_C_DST_PCI | DMAE_CMD_C_ENABLE |
- DMAE_CMD_SRC_RESET | DMAE_CMD_DST_RESET |
-#ifdef __BIG_ENDIAN
- DMAE_CMD_ENDIANITY_B_DW_SWAP |
-#else
- DMAE_CMD_ENDIANITY_DW_SWAP |
-#endif
- (BP_PORT(bp) ? DMAE_CMD_PORT_1 : DMAE_CMD_PORT_0) |
- (BP_E1HVN(bp) << DMAE_CMD_E1HVN_SHIFT));
- dmae->src_addr_lo = U64_LO(bnx2x_sp_mapping(bp, port_stats));
- dmae->src_addr_hi = U64_HI(bnx2x_sp_mapping(bp, port_stats));
- dmae->dst_addr_lo = bp->port.port_stx >> 2;
- dmae->dst_addr_hi = 0;
- dmae->len = sizeof(struct host_port_stats) >> 2;
- dmae->comp_addr_lo = U64_LO(bnx2x_sp_mapping(bp, stats_comp));
- dmae->comp_addr_hi = U64_HI(bnx2x_sp_mapping(bp, stats_comp));
- dmae->comp_val = DMAE_COMP_VAL;
-
- *stats_comp = 0;
- bnx2x_hw_stats_post(bp);
- bnx2x_stats_comp(bp);
-}
-
-static void bnx2x_func_stats_base_init(struct bnx2x *bp)
-{
- int vn, vn_max = IS_E1HMF(bp) ? E1HVN_MAX : E1VN_MAX;
- int port = BP_PORT(bp);
- int func;
- u32 func_stx;
-
- /* sanity */
- if (!bp->port.pmf || !bp->func_stx) {
- BNX2X_ERR("BUG!\n");
- return;
- }
-
- /* save our func_stx */
- func_stx = bp->func_stx;
-
- for (vn = VN_0; vn < vn_max; vn++) {
- func = 2*vn + port;
-
- bp->func_stx = SHMEM_RD(bp, func_mb[func].fw_mb_param);
- bnx2x_func_stats_init(bp);
- bnx2x_hw_stats_post(bp);
- bnx2x_stats_comp(bp);
- }
-
- /* restore our func_stx */
- bp->func_stx = func_stx;
-}
-
-static void bnx2x_func_stats_base_update(struct bnx2x *bp)
-{
- struct dmae_command *dmae = &bp->stats_dmae;
- u32 *stats_comp = bnx2x_sp(bp, stats_comp);
-
- /* sanity */
- if (!bp->func_stx) {
- BNX2X_ERR("BUG!\n");
- return;
- }
-
- bp->executer_idx = 0;
- memset(dmae, 0, sizeof(struct dmae_command));
-
- dmae->opcode = (DMAE_CMD_SRC_GRC | DMAE_CMD_DST_PCI |
- DMAE_CMD_C_DST_PCI | DMAE_CMD_C_ENABLE |
- DMAE_CMD_SRC_RESET | DMAE_CMD_DST_RESET |
-#ifdef __BIG_ENDIAN
- DMAE_CMD_ENDIANITY_B_DW_SWAP |
-#else
- DMAE_CMD_ENDIANITY_DW_SWAP |
-#endif
- (BP_PORT(bp) ? DMAE_CMD_PORT_1 : DMAE_CMD_PORT_0) |
- (BP_E1HVN(bp) << DMAE_CMD_E1HVN_SHIFT));
- dmae->src_addr_lo = bp->func_stx >> 2;
- dmae->src_addr_hi = 0;
- dmae->dst_addr_lo = U64_LO(bnx2x_sp_mapping(bp, func_stats_base));
- dmae->dst_addr_hi = U64_HI(bnx2x_sp_mapping(bp, func_stats_base));
- dmae->len = sizeof(struct host_func_stats) >> 2;
- dmae->comp_addr_lo = U64_LO(bnx2x_sp_mapping(bp, stats_comp));
- dmae->comp_addr_hi = U64_HI(bnx2x_sp_mapping(bp, stats_comp));
- dmae->comp_val = DMAE_COMP_VAL;
-
- *stats_comp = 0;
- bnx2x_hw_stats_post(bp);
- bnx2x_stats_comp(bp);
-}
-
-static void bnx2x_stats_init(struct bnx2x *bp)
-{
- int port = BP_PORT(bp);
- int func = BP_FUNC(bp);
- int i;
-
- bp->stats_pending = 0;
- bp->executer_idx = 0;
- bp->stats_counter = 0;
-
- /* port and func stats for management */
- if (!BP_NOMCP(bp)) {
- bp->port.port_stx = SHMEM_RD(bp, port_mb[port].port_stx);
- bp->func_stx = SHMEM_RD(bp, func_mb[func].fw_mb_param);
-
- } else {
- bp->port.port_stx = 0;
- bp->func_stx = 0;
- }
- DP(BNX2X_MSG_STATS, "port_stx 0x%x func_stx 0x%x\n",
- bp->port.port_stx, bp->func_stx);
-
- /* port stats */
- memset(&(bp->port.old_nig_stats), 0, sizeof(struct nig_stats));
- bp->port.old_nig_stats.brb_discard =
- REG_RD(bp, NIG_REG_STAT0_BRB_DISCARD + port*0x38);
- bp->port.old_nig_stats.brb_truncate =
- REG_RD(bp, NIG_REG_STAT0_BRB_TRUNCATE + port*0x38);
- REG_RD_DMAE(bp, NIG_REG_STAT0_EGRESS_MAC_PKT0 + port*0x50,
- &(bp->port.old_nig_stats.egress_mac_pkt0_lo), 2);
- REG_RD_DMAE(bp, NIG_REG_STAT0_EGRESS_MAC_PKT1 + port*0x50,
- &(bp->port.old_nig_stats.egress_mac_pkt1_lo), 2);
-
- /* function stats */
- for_each_queue(bp, i) {
- struct bnx2x_fastpath *fp = &bp->fp[i];
-
- memset(&fp->old_tclient, 0,
- sizeof(struct tstorm_per_client_stats));
- memset(&fp->old_uclient, 0,
- sizeof(struct ustorm_per_client_stats));
- memset(&fp->old_xclient, 0,
- sizeof(struct xstorm_per_client_stats));
- memset(&fp->eth_q_stats, 0, sizeof(struct bnx2x_eth_q_stats));
- }
-
- memset(&bp->dev->stats, 0, sizeof(struct net_device_stats));
- memset(&bp->eth_stats, 0, sizeof(struct bnx2x_eth_stats));
-
- bp->stats_state = STATS_STATE_DISABLED;
-
- if (bp->port.pmf) {
- if (bp->port.port_stx)
- bnx2x_port_stats_base_init(bp);
-
- if (bp->func_stx)
- bnx2x_func_stats_base_init(bp);
-
- } else if (bp->func_stx)
- bnx2x_func_stats_base_update(bp);
-}
-
static void bnx2x_timer(unsigned long data)
{
struct bnx2x *bp = (struct bnx2x *) data;
@@ -5113,7 +2722,7 @@ static void bnx2x_zero_sb(struct bnx2x *bp, int sb_id)
CSTORM_SB_STATUS_BLOCK_C_SIZE / 4);
}
-static void bnx2x_init_sb(struct bnx2x *bp, struct host_status_block *sb,
+void bnx2x_init_sb(struct bnx2x *bp, struct host_status_block *sb,
dma_addr_t mapping, int sb_id)
{
int port = BP_PORT(bp);
@@ -5292,7 +2901,7 @@ static void bnx2x_init_def_sb(struct bnx2x *bp,
bnx2x_ack_sb(bp, sb_id, CSTORM_ID, 0, IGU_INT_ENABLE, 0);
}
-static void bnx2x_update_coalesce(struct bnx2x *bp)
+void bnx2x_update_coalesce(struct bnx2x *bp)
{
int port = BP_PORT(bp);
int i;
@@ -5322,207 +2931,6 @@ static void bnx2x_update_coalesce(struct bnx2x *bp)
}
}
-static inline void bnx2x_free_tpa_pool(struct bnx2x *bp,
- struct bnx2x_fastpath *fp, int last)
-{
- int i;
-
- for (i = 0; i < last; i++) {
- struct sw_rx_bd *rx_buf = &(fp->tpa_pool[i]);
- struct sk_buff *skb = rx_buf->skb;
-
- if (skb == NULL) {
- DP(NETIF_MSG_IFDOWN, "tpa bin %d empty on free\n", i);
- continue;
- }
-
- if (fp->tpa_state[i] == BNX2X_TPA_START)
- dma_unmap_single(&bp->pdev->dev,
- dma_unmap_addr(rx_buf, mapping),
- bp->rx_buf_size, DMA_FROM_DEVICE);
-
- dev_kfree_skb(skb);
- rx_buf->skb = NULL;
- }
-}
-
-static void bnx2x_init_rx_rings(struct bnx2x *bp)
-{
- int func = BP_FUNC(bp);
- int max_agg_queues = CHIP_IS_E1(bp) ? ETH_MAX_AGGREGATION_QUEUES_E1 :
- ETH_MAX_AGGREGATION_QUEUES_E1H;
- u16 ring_prod, cqe_ring_prod;
- int i, j;
-
- bp->rx_buf_size = bp->dev->mtu + ETH_OVREHEAD + BNX2X_RX_ALIGN;
- DP(NETIF_MSG_IFUP,
- "mtu %d rx_buf_size %d\n", bp->dev->mtu, bp->rx_buf_size);
-
- if (bp->flags & TPA_ENABLE_FLAG) {
-
- for_each_queue(bp, j) {
- struct bnx2x_fastpath *fp = &bp->fp[j];
-
- for (i = 0; i < max_agg_queues; i++) {
- fp->tpa_pool[i].skb =
- netdev_alloc_skb(bp->dev, bp->rx_buf_size);
- if (!fp->tpa_pool[i].skb) {
- BNX2X_ERR("Failed to allocate TPA "
- "skb pool for queue[%d] - "
- "disabling TPA on this "
- "queue!\n", j);
- bnx2x_free_tpa_pool(bp, fp, i);
- fp->disable_tpa = 1;
- break;
- }
- dma_unmap_addr_set((struct sw_rx_bd *)
- &bp->fp->tpa_pool[i],
- mapping, 0);
- fp->tpa_state[i] = BNX2X_TPA_STOP;
- }
- }
- }
-
- for_each_queue(bp, j) {
- struct bnx2x_fastpath *fp = &bp->fp[j];
-
- fp->rx_bd_cons = 0;
- fp->rx_cons_sb = BNX2X_RX_SB_INDEX;
- fp->rx_bd_cons_sb = BNX2X_RX_SB_BD_INDEX;
-
- /* "next page" elements initialization */
- /* SGE ring */
- for (i = 1; i <= NUM_RX_SGE_PAGES; i++) {
- struct eth_rx_sge *sge;
-
- sge = &fp->rx_sge_ring[RX_SGE_CNT * i - 2];
- sge->addr_hi =
- cpu_to_le32(U64_HI(fp->rx_sge_mapping +
- BCM_PAGE_SIZE*(i % NUM_RX_SGE_PAGES)));
- sge->addr_lo =
- cpu_to_le32(U64_LO(fp->rx_sge_mapping +
- BCM_PAGE_SIZE*(i % NUM_RX_SGE_PAGES)));
- }
-
- bnx2x_init_sge_ring_bit_mask(fp);
-
- /* RX BD ring */
- for (i = 1; i <= NUM_RX_RINGS; i++) {
- struct eth_rx_bd *rx_bd;
-
- rx_bd = &fp->rx_desc_ring[RX_DESC_CNT * i - 2];
- rx_bd->addr_hi =
- cpu_to_le32(U64_HI(fp->rx_desc_mapping +
- BCM_PAGE_SIZE*(i % NUM_RX_RINGS)));
- rx_bd->addr_lo =
- cpu_to_le32(U64_LO(fp->rx_desc_mapping +
- BCM_PAGE_SIZE*(i % NUM_RX_RINGS)));
- }
-
- /* CQ ring */
- for (i = 1; i <= NUM_RCQ_RINGS; i++) {
- struct eth_rx_cqe_next_page *nextpg;
-
- nextpg = (struct eth_rx_cqe_next_page *)
- &fp->rx_comp_ring[RCQ_DESC_CNT * i - 1];
- nextpg->addr_hi =
- cpu_to_le32(U64_HI(fp->rx_comp_mapping +
- BCM_PAGE_SIZE*(i % NUM_RCQ_RINGS)));
- nextpg->addr_lo =
- cpu_to_le32(U64_LO(fp->rx_comp_mapping +
- BCM_PAGE_SIZE*(i % NUM_RCQ_RINGS)));
- }
-
- /* Allocate SGEs and initialize the ring elements */
- for (i = 0, ring_prod = 0;
- i < MAX_RX_SGE_CNT*NUM_RX_SGE_PAGES; i++) {
-
- if (bnx2x_alloc_rx_sge(bp, fp, ring_prod) < 0) {
- BNX2X_ERR("was only able to allocate "
- "%d rx sges\n", i);
- BNX2X_ERR("disabling TPA for queue[%d]\n", j);
- /* Cleanup already allocated elements */
- bnx2x_free_rx_sge_range(bp, fp, ring_prod);
- bnx2x_free_tpa_pool(bp, fp, max_agg_queues);
- fp->disable_tpa = 1;
- ring_prod = 0;
- break;
- }
- ring_prod = NEXT_SGE_IDX(ring_prod);
- }
- fp->rx_sge_prod = ring_prod;
-
- /* Allocate BDs and initialize BD ring */
- fp->rx_comp_cons = 0;
- cqe_ring_prod = ring_prod = 0;
- for (i = 0; i < bp->rx_ring_size; i++) {
- if (bnx2x_alloc_rx_skb(bp, fp, ring_prod) < 0) {
- BNX2X_ERR("was only able to allocate "
- "%d rx skbs on queue[%d]\n", i, j);
- fp->eth_q_stats.rx_skb_alloc_failed++;
- break;
- }
- ring_prod = NEXT_RX_IDX(ring_prod);
- cqe_ring_prod = NEXT_RCQ_IDX(cqe_ring_prod);
- WARN_ON(ring_prod <= i);
- }
-
- fp->rx_bd_prod = ring_prod;
- /* must not have more available CQEs than BDs */
- fp->rx_comp_prod = min_t(u16, NUM_RCQ_RINGS*RCQ_DESC_CNT,
- cqe_ring_prod);
- fp->rx_pkt = fp->rx_calls = 0;
-
- /* Warning!
- * this will generate an interrupt (to the TSTORM)
- * must only be done after chip is initialized
- */
- bnx2x_update_rx_prod(bp, fp, ring_prod, fp->rx_comp_prod,
- fp->rx_sge_prod);
- if (j != 0)
- continue;
-
- REG_WR(bp, BAR_USTRORM_INTMEM +
- USTORM_MEM_WORKAROUND_ADDRESS_OFFSET(func),
- U64_LO(fp->rx_comp_mapping));
- REG_WR(bp, BAR_USTRORM_INTMEM +
- USTORM_MEM_WORKAROUND_ADDRESS_OFFSET(func) + 4,
- U64_HI(fp->rx_comp_mapping));
- }
-}
-
-static void bnx2x_init_tx_ring(struct bnx2x *bp)
-{
- int i, j;
-
- for_each_queue(bp, j) {
- struct bnx2x_fastpath *fp = &bp->fp[j];
-
- for (i = 1; i <= NUM_TX_RINGS; i++) {
- struct eth_tx_next_bd *tx_next_bd =
- &fp->tx_desc_ring[TX_DESC_CNT * i - 1].next_bd;
-
- tx_next_bd->addr_hi =
- cpu_to_le32(U64_HI(fp->tx_desc_mapping +
- BCM_PAGE_SIZE*(i % NUM_TX_RINGS)));
- tx_next_bd->addr_lo =
- cpu_to_le32(U64_LO(fp->tx_desc_mapping +
- BCM_PAGE_SIZE*(i % NUM_TX_RINGS)));
- }
-
- fp->tx_db.data.header.header = DOORBELL_HDR_DB_TYPE;
- fp->tx_db.data.zero_fill1 = 0;
- fp->tx_db.data.prod = 0;
-
- fp->tx_pkt_prod = 0;
- fp->tx_pkt_cons = 0;
- fp->tx_bd_prod = 0;
- fp->tx_bd_cons = 0;
- fp->tx_cons_sb = BNX2X_TX_SB_INDEX;
- fp->tx_pkt = 0;
- }
-}
-
static void bnx2x_init_sp_ring(struct bnx2x *bp)
{
int func = BP_FUNC(bp);
@@ -5637,7 +3045,7 @@ static void bnx2x_init_ind_table(struct bnx2x *bp)
bp->fp->cl_id + (i % bp->num_queues));
}
-static void bnx2x_set_client_config(struct bnx2x *bp)
+void bnx2x_set_client_config(struct bnx2x *bp)
{
struct tstorm_eth_client_config tstorm_client = {0};
int port = BP_PORT(bp);
@@ -5670,7 +3078,7 @@ static void bnx2x_set_client_config(struct bnx2x *bp)
((u32 *)&tstorm_client)[0], ((u32 *)&tstorm_client)[1]);
}
-static void bnx2x_set_storm_rx_mode(struct bnx2x *bp)
+void bnx2x_set_storm_rx_mode(struct bnx2x *bp)
{
struct tstorm_eth_mac_filter_config tstorm_mac_filter = {0};
int mode = bp->rx_mode;
@@ -5990,7 +3398,7 @@ static void bnx2x_init_internal(struct bnx2x *bp, u32 load_code)
}
}
-static void bnx2x_nic_init(struct bnx2x *bp, u32 load_code)
+void bnx2x_nic_init(struct bnx2x *bp, u32 load_code)
{
int i;
@@ -7071,7 +4479,7 @@ static int bnx2x_init_func(struct bnx2x *bp)
return 0;
}
-static int bnx2x_init_hw(struct bnx2x *bp, u32 load_code)
+int bnx2x_init_hw(struct bnx2x *bp, u32 load_code)
{
int i, rc = 0;
@@ -7133,7 +4541,7 @@ init_hw_err:
return rc;
}
-static void bnx2x_free_mem(struct bnx2x *bp)
+void bnx2x_free_mem(struct bnx2x *bp)
{
#define BNX2X_PCI_FREE(x, y, size) \
@@ -7215,7 +4623,7 @@ static void bnx2x_free_mem(struct bnx2x *bp)
#undef BNX2X_KFREE
}
-static int bnx2x_alloc_mem(struct bnx2x *bp)
+int bnx2x_alloc_mem(struct bnx2x *bp)
{
#define BNX2X_PCI_ALLOC(x, y, size) \
@@ -7321,264 +4729,6 @@ alloc_mem_err:
#undef BNX2X_ALLOC
}
-static void bnx2x_free_tx_skbs(struct bnx2x *bp)
-{
- int i;
-
- for_each_queue(bp, i) {
- struct bnx2x_fastpath *fp = &bp->fp[i];
-
- u16 bd_cons = fp->tx_bd_cons;
- u16 sw_prod = fp->tx_pkt_prod;
- u16 sw_cons = fp->tx_pkt_cons;
-
- while (sw_cons != sw_prod) {
- bd_cons = bnx2x_free_tx_pkt(bp, fp, TX_BD(sw_cons));
- sw_cons++;
- }
- }
-}
-
-static void bnx2x_free_rx_skbs(struct bnx2x *bp)
-{
- int i, j;
-
- for_each_queue(bp, j) {
- struct bnx2x_fastpath *fp = &bp->fp[j];
-
- for (i = 0; i < NUM_RX_BD; i++) {
- struct sw_rx_bd *rx_buf = &fp->rx_buf_ring[i];
- struct sk_buff *skb = rx_buf->skb;
-
- if (skb == NULL)
- continue;
-
- dma_unmap_single(&bp->pdev->dev,
- dma_unmap_addr(rx_buf, mapping),
- bp->rx_buf_size, DMA_FROM_DEVICE);
-
- rx_buf->skb = NULL;
- dev_kfree_skb(skb);
- }
- if (!fp->disable_tpa)
- bnx2x_free_tpa_pool(bp, fp, CHIP_IS_E1(bp) ?
- ETH_MAX_AGGREGATION_QUEUES_E1 :
- ETH_MAX_AGGREGATION_QUEUES_E1H);
- }
-}
-
-static void bnx2x_free_skbs(struct bnx2x *bp)
-{
- bnx2x_free_tx_skbs(bp);
- bnx2x_free_rx_skbs(bp);
-}
-
-static void bnx2x_free_msix_irqs(struct bnx2x *bp)
-{
- int i, offset = 1;
-
- free_irq(bp->msix_table[0].vector, bp->dev);
- DP(NETIF_MSG_IFDOWN, "released sp irq (%d)\n",
- bp->msix_table[0].vector);
-
-#ifdef BCM_CNIC
- offset++;
-#endif
- for_each_queue(bp, i) {
- DP(NETIF_MSG_IFDOWN, "about to release fp #%d->%d irq "
- "state %x\n", i, bp->msix_table[i + offset].vector,
- bnx2x_fp(bp, i, state));
-
- free_irq(bp->msix_table[i + offset].vector, &bp->fp[i]);
- }
-}
-
-static void bnx2x_free_irq(struct bnx2x *bp, bool disable_only)
-{
- if (bp->flags & USING_MSIX_FLAG) {
- if (!disable_only)
- bnx2x_free_msix_irqs(bp);
- pci_disable_msix(bp->pdev);
- bp->flags &= ~USING_MSIX_FLAG;
-
- } else if (bp->flags & USING_MSI_FLAG) {
- if (!disable_only)
- free_irq(bp->pdev->irq, bp->dev);
- pci_disable_msi(bp->pdev);
- bp->flags &= ~USING_MSI_FLAG;
-
- } else if (!disable_only)
- free_irq(bp->pdev->irq, bp->dev);
-}
-
-static int bnx2x_enable_msix(struct bnx2x *bp)
-{
- int i, rc, offset = 1;
- int igu_vec = 0;
-
- bp->msix_table[0].entry = igu_vec;
- DP(NETIF_MSG_IFUP, "msix_table[0].entry = %d (slowpath)\n", igu_vec);
-
-#ifdef BCM_CNIC
- igu_vec = BP_L_ID(bp) + offset;
- bp->msix_table[1].entry = igu_vec;
- DP(NETIF_MSG_IFUP, "msix_table[1].entry = %d (CNIC)\n", igu_vec);
- offset++;
-#endif
- for_each_queue(bp, i) {
- igu_vec = BP_L_ID(bp) + offset + i;
- bp->msix_table[i + offset].entry = igu_vec;
- DP(NETIF_MSG_IFUP, "msix_table[%d].entry = %d "
- "(fastpath #%u)\n", i + offset, igu_vec, i);
- }
-
- rc = pci_enable_msix(bp->pdev, &bp->msix_table[0],
- BNX2X_NUM_QUEUES(bp) + offset);
-
- /*
- * reconfigure number of tx/rx queues according to available
- * MSI-X vectors
- */
- if (rc >= BNX2X_MIN_MSIX_VEC_CNT) {
- /* vectors available for FP */
- int fp_vec = rc - BNX2X_MSIX_VEC_FP_START;
-
- DP(NETIF_MSG_IFUP,
- "Trying to use less MSI-X vectors: %d\n", rc);
-
- rc = pci_enable_msix(bp->pdev, &bp->msix_table[0], rc);
-
- if (rc) {
- DP(NETIF_MSG_IFUP,
- "MSI-X is not attainable rc %d\n", rc);
- return rc;
- }
-
- bp->num_queues = min(bp->num_queues, fp_vec);
-
- DP(NETIF_MSG_IFUP, "New queue configuration set: %d\n",
- bp->num_queues);
- } else if (rc) {
- DP(NETIF_MSG_IFUP, "MSI-X is not attainable rc %d\n", rc);
- return rc;
- }
-
- bp->flags |= USING_MSIX_FLAG;
-
- return 0;
-}
-
-static int bnx2x_req_msix_irqs(struct bnx2x *bp)
-{
- int i, rc, offset = 1;
-
- rc = request_irq(bp->msix_table[0].vector, bnx2x_msix_sp_int, 0,
- bp->dev->name, bp->dev);
- if (rc) {
- BNX2X_ERR("request sp irq failed\n");
- return -EBUSY;
- }
-
-#ifdef BCM_CNIC
- offset++;
-#endif
- for_each_queue(bp, i) {
- struct bnx2x_fastpath *fp = &bp->fp[i];
- snprintf(fp->name, sizeof(fp->name), "%s-fp-%d",
- bp->dev->name, i);
-
- rc = request_irq(bp->msix_table[i + offset].vector,
- bnx2x_msix_fp_int, 0, fp->name, fp);
- if (rc) {
- BNX2X_ERR("request fp #%d irq failed rc %d\n", i, rc);
- bnx2x_free_msix_irqs(bp);
- return -EBUSY;
- }
-
- fp->state = BNX2X_FP_STATE_IRQ;
- }
-
- i = BNX2X_NUM_QUEUES(bp);
- netdev_info(bp->dev, "using MSI-X IRQs: sp %d fp[%d] %d"
- " ... fp[%d] %d\n",
- bp->msix_table[0].vector,
- 0, bp->msix_table[offset].vector,
- i - 1, bp->msix_table[offset + i - 1].vector);
-
- return 0;
-}
-
-static int bnx2x_enable_msi(struct bnx2x *bp)
-{
- int rc;
-
- rc = pci_enable_msi(bp->pdev);
- if (rc) {
- DP(NETIF_MSG_IFUP, "MSI is not attainable\n");
- return -1;
- }
- bp->flags |= USING_MSI_FLAG;
-
- return 0;
-}
-
-static int bnx2x_req_irq(struct bnx2x *bp)
-{
- unsigned long flags;
- int rc;
-
- if (bp->flags & USING_MSI_FLAG)
- flags = 0;
- else
- flags = IRQF_SHARED;
-
- rc = request_irq(bp->pdev->irq, bnx2x_interrupt, flags,
- bp->dev->name, bp->dev);
- if (!rc)
- bnx2x_fp(bp, 0, state) = BNX2X_FP_STATE_IRQ;
-
- return rc;
-}
-
-static void bnx2x_napi_enable(struct bnx2x *bp)
-{
- int i;
-
- for_each_queue(bp, i)
- napi_enable(&bnx2x_fp(bp, i, napi));
-}
-
-static void bnx2x_napi_disable(struct bnx2x *bp)
-{
- int i;
-
- for_each_queue(bp, i)
- napi_disable(&bnx2x_fp(bp, i, napi));
-}
-
-static void bnx2x_netif_start(struct bnx2x *bp)
-{
- int intr_sem;
-
- intr_sem = atomic_dec_and_test(&bp->intr_sem);
- smp_wmb(); /* Ensure that bp->intr_sem update is SMP-safe */
-
- if (intr_sem) {
- if (netif_running(bp->dev)) {
- bnx2x_napi_enable(bp);
- bnx2x_int_enable(bp);
- if (bp->state == BNX2X_STATE_OPEN)
- netif_tx_wake_all_queues(bp->dev);
- }
- }
-}
-
-static void bnx2x_netif_stop(struct bnx2x *bp, int disable_hw)
-{
- bnx2x_int_disable_sync(bp, disable_hw);
- bnx2x_napi_disable(bp);
- netif_tx_disable(bp->dev);
-}
/*
* Init service functions
@@ -7749,7 +4899,7 @@ static int bnx2x_wait_ramrod(struct bnx2x *bp, int state, int idx,
return -EBUSY;
}
-static void bnx2x_set_eth_mac_addr_e1h(struct bnx2x *bp, int set)
+void bnx2x_set_eth_mac_addr_e1h(struct bnx2x *bp, int set)
{
bp->set_mac_pending++;
smp_wmb();
@@ -7761,7 +4911,7 @@ static void bnx2x_set_eth_mac_addr_e1h(struct bnx2x *bp, int set)
bnx2x_wait_ramrod(bp, 0, 0, &bp->set_mac_pending, set ? 0 : 1);
}
-static void bnx2x_set_eth_mac_addr_e1(struct bnx2x *bp, int set)
+void bnx2x_set_eth_mac_addr_e1(struct bnx2x *bp, int set)
{
bp->set_mac_pending++;
smp_wmb();
@@ -7785,7 +4935,7 @@ static void bnx2x_set_eth_mac_addr_e1(struct bnx2x *bp, int set)
*
* @return 0 if cussess, -ENODEV if ramrod doesn't return.
*/
-static int bnx2x_set_iscsi_eth_mac_addr(struct bnx2x *bp, int set)
+int bnx2x_set_iscsi_eth_mac_addr(struct bnx2x *bp, int set)
{
u32 cl_bit_vec = (1 << BCM_ISCSI_ETH_CL_ID);
@@ -7812,7 +4962,7 @@ static int bnx2x_set_iscsi_eth_mac_addr(struct bnx2x *bp, int set)
}
#endif
-static int bnx2x_setup_leading(struct bnx2x *bp)
+int bnx2x_setup_leading(struct bnx2x *bp)
{
int rc;
@@ -7828,7 +4978,7 @@ static int bnx2x_setup_leading(struct bnx2x *bp)
return rc;
}
-static int bnx2x_setup_multi(struct bnx2x *bp, int index)
+int bnx2x_setup_multi(struct bnx2x *bp, int index)
{
struct bnx2x_fastpath *fp = &bp->fp[index];
@@ -7845,9 +4995,8 @@ static int bnx2x_setup_multi(struct bnx2x *bp, int index)
&(fp->state), 0);
}
-static int bnx2x_poll(struct napi_struct *napi, int budget);
-static void bnx2x_set_num_queues_msix(struct bnx2x *bp)
+void bnx2x_set_num_queues_msix(struct bnx2x *bp)
{
switch (bp->multi_mode) {
@@ -7871,292 +5020,7 @@ static void bnx2x_set_num_queues_msix(struct bnx2x *bp)
}
}
-static int bnx2x_set_num_queues(struct bnx2x *bp)
-{
- int rc = 0;
-
- switch (int_mode) {
- case INT_MODE_INTx:
- case INT_MODE_MSI:
- bp->num_queues = 1;
- DP(NETIF_MSG_IFUP, "set number of queues to 1\n");
- break;
- default:
- /* Set number of queues according to bp->multi_mode value */
- bnx2x_set_num_queues_msix(bp);
-
- DP(NETIF_MSG_IFUP, "set number of queues to %d\n",
- bp->num_queues);
-
- /* if we can't use MSI-X we only need one fp,
- * so try to enable MSI-X with the requested number of fp's
- * and fallback to MSI or legacy INTx with one fp
- */
- rc = bnx2x_enable_msix(bp);
- if (rc)
- /* failed to enable MSI-X */
- bp->num_queues = 1;
- break;
- }
- bp->dev->real_num_tx_queues = bp->num_queues;
- return rc;
-}
-
-#ifdef BCM_CNIC
-static int bnx2x_cnic_notify(struct bnx2x *bp, int cmd);
-static void bnx2x_setup_cnic_irq_info(struct bnx2x *bp);
-#endif
-
-/* must be called with rtnl_lock */
-static int bnx2x_nic_load(struct bnx2x *bp, int load_mode)
-{
- u32 load_code;
- int i, rc;
-
-#ifdef BNX2X_STOP_ON_ERROR
- if (unlikely(bp->panic))
- return -EPERM;
-#endif
-
- bp->state = BNX2X_STATE_OPENING_WAIT4_LOAD;
-
- rc = bnx2x_set_num_queues(bp);
-
- if (bnx2x_alloc_mem(bp)) {
- bnx2x_free_irq(bp, true);
- return -ENOMEM;
- }
-
- for_each_queue(bp, i)
- bnx2x_fp(bp, i, disable_tpa) =
- ((bp->flags & TPA_ENABLE_FLAG) == 0);
-
- for_each_queue(bp, i)
- netif_napi_add(bp->dev, &bnx2x_fp(bp, i, napi),
- bnx2x_poll, 128);
- bnx2x_napi_enable(bp);
-
- if (bp->flags & USING_MSIX_FLAG) {
- rc = bnx2x_req_msix_irqs(bp);
- if (rc) {
- bnx2x_free_irq(bp, true);
- goto load_error1;
- }
- } else {
- /* Fall to INTx if failed to enable MSI-X due to lack of
- memory (in bnx2x_set_num_queues()) */
- if ((rc != -ENOMEM) && (int_mode != INT_MODE_INTx))
- bnx2x_enable_msi(bp);
- bnx2x_ack_int(bp);
- rc = bnx2x_req_irq(bp);
- if (rc) {
- BNX2X_ERR("IRQ request failed rc %d, aborting\n", rc);
- bnx2x_free_irq(bp, true);
- goto load_error1;
- }
- if (bp->flags & USING_MSI_FLAG) {
- bp->dev->irq = bp->pdev->irq;
- netdev_info(bp->dev, "using MSI IRQ %d\n",
- bp->pdev->irq);
- }
- }
-
- /* Send LOAD_REQUEST command to MCP
- Returns the type of LOAD command:
- if it is the first port to be initialized
- common blocks should be initialized, otherwise - not
- */
- if (!BP_NOMCP(bp)) {
- load_code = bnx2x_fw_command(bp, DRV_MSG_CODE_LOAD_REQ);
- if (!load_code) {
- BNX2X_ERR("MCP response failure, aborting\n");
- rc = -EBUSY;
- goto load_error2;
- }
- if (load_code == FW_MSG_CODE_DRV_LOAD_REFUSED) {
- rc = -EBUSY; /* other port in diagnostic mode */
- goto load_error2;
- }
-
- } else {
- int port = BP_PORT(bp);
-
- DP(NETIF_MSG_IFUP, "NO MCP - load counts %d, %d, %d\n",
- load_count[0], load_count[1], load_count[2]);
- load_count[0]++;
- load_count[1 + port]++;
- DP(NETIF_MSG_IFUP, "NO MCP - new load counts %d, %d, %d\n",
- load_count[0], load_count[1], load_count[2]);
- if (load_count[0] == 1)
- load_code = FW_MSG_CODE_DRV_LOAD_COMMON;
- else if (load_count[1 + port] == 1)
- load_code = FW_MSG_CODE_DRV_LOAD_PORT;
- else
- load_code = FW_MSG_CODE_DRV_LOAD_FUNCTION;
- }
-
- if ((load_code == FW_MSG_CODE_DRV_LOAD_COMMON) ||
- (load_code == FW_MSG_CODE_DRV_LOAD_PORT))
- bp->port.pmf = 1;
- else
- bp->port.pmf = 0;
- DP(NETIF_MSG_LINK, "pmf %d\n", bp->port.pmf);
-
- /* Initialize HW */
- rc = bnx2x_init_hw(bp, load_code);
- if (rc) {
- BNX2X_ERR("HW init failed, aborting\n");
- bnx2x_fw_command(bp, DRV_MSG_CODE_LOAD_DONE);
- bnx2x_fw_command(bp, DRV_MSG_CODE_UNLOAD_REQ_WOL_MCP);
- bnx2x_fw_command(bp, DRV_MSG_CODE_UNLOAD_DONE);
- goto load_error2;
- }
-
- /* Setup NIC internals and enable interrupts */
- bnx2x_nic_init(bp, load_code);
-
- if ((load_code == FW_MSG_CODE_DRV_LOAD_COMMON) &&
- (bp->common.shmem2_base))
- SHMEM2_WR(bp, dcc_support,
- (SHMEM_DCC_SUPPORT_DISABLE_ENABLE_PF_TLV |
- SHMEM_DCC_SUPPORT_BANDWIDTH_ALLOCATION_TLV));
-
- /* Send LOAD_DONE command to MCP */
- if (!BP_NOMCP(bp)) {
- load_code = bnx2x_fw_command(bp, DRV_MSG_CODE_LOAD_DONE);
- if (!load_code) {
- BNX2X_ERR("MCP response failure, aborting\n");
- rc = -EBUSY;
- goto load_error3;
- }
- }
-
- bp->state = BNX2X_STATE_OPENING_WAIT4_PORT;
-
- rc = bnx2x_setup_leading(bp);
- if (rc) {
- BNX2X_ERR("Setup leading failed!\n");
-#ifndef BNX2X_STOP_ON_ERROR
- goto load_error3;
-#else
- bp->panic = 1;
- return -EBUSY;
-#endif
- }
-
- if (CHIP_IS_E1H(bp))
- if (bp->mf_config & FUNC_MF_CFG_FUNC_DISABLED) {
- DP(NETIF_MSG_IFUP, "mf_cfg function disabled\n");
- bp->flags |= MF_FUNC_DIS;
- }
-
- if (bp->state == BNX2X_STATE_OPEN) {
-#ifdef BCM_CNIC
- /* Enable Timer scan */
- REG_WR(bp, TM_REG_EN_LINEAR0_TIMER + BP_PORT(bp)*4, 1);
-#endif
- for_each_nondefault_queue(bp, i) {
- rc = bnx2x_setup_multi(bp, i);
- if (rc)
-#ifdef BCM_CNIC
- goto load_error4;
-#else
- goto load_error3;
-#endif
- }
-
- if (CHIP_IS_E1(bp))
- bnx2x_set_eth_mac_addr_e1(bp, 1);
- else
- bnx2x_set_eth_mac_addr_e1h(bp, 1);
-#ifdef BCM_CNIC
- /* Set iSCSI L2 MAC */
- mutex_lock(&bp->cnic_mutex);
- if (bp->cnic_eth_dev.drv_state & CNIC_DRV_STATE_REGD) {
- bnx2x_set_iscsi_eth_mac_addr(bp, 1);
- bp->cnic_flags |= BNX2X_CNIC_FLAG_MAC_SET;
- bnx2x_init_sb(bp, bp->cnic_sb, bp->cnic_sb_mapping,
- CNIC_SB_ID(bp));
- }
- mutex_unlock(&bp->cnic_mutex);
-#endif
- }
-
- if (bp->port.pmf)
- bnx2x_initial_phy_init(bp, load_mode);
-
- /* Start fast path */
- switch (load_mode) {
- case LOAD_NORMAL:
- if (bp->state == BNX2X_STATE_OPEN) {
- /* Tx queue should be only reenabled */
- netif_tx_wake_all_queues(bp->dev);
- }
- /* Initialize the receive filter. */
- bnx2x_set_rx_mode(bp->dev);
- break;
-
- case LOAD_OPEN:
- netif_tx_start_all_queues(bp->dev);
- if (bp->state != BNX2X_STATE_OPEN)
- netif_tx_disable(bp->dev);
- /* Initialize the receive filter. */
- bnx2x_set_rx_mode(bp->dev);
- break;
-
- case LOAD_DIAG:
- /* Initialize the receive filter. */
- bnx2x_set_rx_mode(bp->dev);
- bp->state = BNX2X_STATE_DIAG;
- break;
-
- default:
- break;
- }
-
- if (!bp->port.pmf)
- bnx2x__link_status_update(bp);
-
- /* start the timer */
- mod_timer(&bp->timer, jiffies + bp->current_interval);
-
-#ifdef BCM_CNIC
- bnx2x_setup_cnic_irq_info(bp);
- if (bp->state == BNX2X_STATE_OPEN)
- bnx2x_cnic_notify(bp, CNIC_CTL_START_CMD);
-#endif
- bnx2x_inc_load_cnt(bp);
-
- return 0;
-
-#ifdef BCM_CNIC
-load_error4:
- /* Disable Timer scan */
- REG_WR(bp, TM_REG_EN_LINEAR0_TIMER + BP_PORT(bp)*4, 0);
-#endif
-load_error3:
- bnx2x_int_disable_sync(bp, 1);
- if (!BP_NOMCP(bp)) {
- bnx2x_fw_command(bp, DRV_MSG_CODE_UNLOAD_REQ_WOL_MCP);
- bnx2x_fw_command(bp, DRV_MSG_CODE_UNLOAD_DONE);
- }
- bp->port.pmf = 0;
- /* Free SKBs, SGEs, TPA pool and driver internals */
- bnx2x_free_skbs(bp);
- for_each_queue(bp, i)
- bnx2x_free_rx_sge_range(bp, bp->fp + i, NUM_RX_SGE);
-load_error2:
- /* Release IRQs */
- bnx2x_free_irq(bp, false);
-load_error1:
- bnx2x_napi_disable(bp);
- for_each_queue(bp, i)
- netif_napi_del(&bnx2x_fp(bp, i, napi));
- bnx2x_free_mem(bp);
-
- return rc;
-}
static int bnx2x_stop_multi(struct bnx2x *bp, int index)
{
@@ -8314,7 +5178,7 @@ static void bnx2x_reset_chip(struct bnx2x *bp, u32 reset_code)
}
}
-static void bnx2x_chip_cleanup(struct bnx2x *bp, int unload_mode)
+void bnx2x_chip_cleanup(struct bnx2x *bp, int unload_mode)
{
int port = BP_PORT(bp);
u32 reset_code = 0;
@@ -8462,7 +5326,7 @@ unload_error:
}
-static inline void bnx2x_disable_close_the_gate(struct bnx2x *bp)
+void bnx2x_disable_close_the_gate(struct bnx2x *bp)
{
u32 val;
@@ -8484,71 +5348,6 @@ static inline void bnx2x_disable_close_the_gate(struct bnx2x *bp)
}
}
-/* must be called with rtnl_lock */
-static int bnx2x_nic_unload(struct bnx2x *bp, int unload_mode)
-{
- int i;
-
- if (bp->state == BNX2X_STATE_CLOSED) {
- /* Interface has been removed - nothing to recover */
- bp->recovery_state = BNX2X_RECOVERY_DONE;
- bp->is_leader = 0;
- bnx2x_release_hw_lock(bp, HW_LOCK_RESOURCE_RESERVED_08);
- smp_wmb();
-
- return -EINVAL;
- }
-
-#ifdef BCM_CNIC
- bnx2x_cnic_notify(bp, CNIC_CTL_STOP_CMD);
-#endif
- bp->state = BNX2X_STATE_CLOSING_WAIT4_HALT;
-
- /* Set "drop all" */
- bp->rx_mode = BNX2X_RX_MODE_NONE;
- bnx2x_set_storm_rx_mode(bp);
-
- /* Disable HW interrupts, NAPI and Tx */
- bnx2x_netif_stop(bp, 1);
- netif_carrier_off(bp->dev);
-
- del_timer_sync(&bp->timer);
- SHMEM_WR(bp, func_mb[BP_FUNC(bp)].drv_pulse_mb,
- (DRV_PULSE_ALWAYS_ALIVE | bp->fw_drv_pulse_wr_seq));
- bnx2x_stats_handle(bp, STATS_EVENT_STOP);
-
- /* Release IRQs */
- bnx2x_free_irq(bp, false);
-
- /* Cleanup the chip if needed */
- if (unload_mode != UNLOAD_RECOVERY)
- bnx2x_chip_cleanup(bp, unload_mode);
-
- bp->port.pmf = 0;
-
- /* Free SKBs, SGEs, TPA pool and driver internals */
- bnx2x_free_skbs(bp);
- for_each_queue(bp, i)
- bnx2x_free_rx_sge_range(bp, bp->fp + i, NUM_RX_SGE);
- for_each_queue(bp, i)
- netif_napi_del(&bnx2x_fp(bp, i, napi));
- bnx2x_free_mem(bp);
-
- bp->state = BNX2X_STATE_CLOSED;
-
- /* The last driver must disable a "close the gate" if there is no
- * parity attention or "process kill" pending.
- */
- if ((!bnx2x_dec_load_cnt(bp)) && (!bnx2x_chk_parity_attn(bp)) &&
- bnx2x_reset_is_done(bp))
- bnx2x_disable_close_the_gate(bp);
-
- /* Reset MCP mail box sequence if there is on going recovery */
- if (unload_mode == UNLOAD_RECOVERY)
- bp->fw_seq = 0;
-
- return 0;
-}
/* Close gates #2, #3 and #4: */
static void bnx2x_set_234_gates(struct bnx2x *bp, bool close)
@@ -8861,8 +5660,6 @@ exit_leader_reset:
return rc;
}
-static int bnx2x_set_power_state(struct bnx2x *bp, pci_power_t state);
-
/* Assumption: runs under rtnl lock. This together with the fact
* that it's called only from bnx2x_reset_task() ensure that it
* will never be called when netif_running(bp->dev) is false.
@@ -8999,8 +5796,6 @@ reset_task_exit:
/* end of nic load/unload */
-/* ethtool_ops */
-
/*
* Init service functions
*/
@@ -9949,7 +6744,7 @@ static int __devinit bnx2x_init_bp(struct bnx2x *bp)
multi_mode = ETH_RSS_MODE_DISABLED;
}
bp->multi_mode = multi_mode;
-
+ bp->int_mode = int_mode;
bp->dev->features |= NETIF_F_GRO;
@@ -9961,6 +6756,7 @@ static int __devinit bnx2x_init_bp(struct bnx2x *bp)
bp->flags |= TPA_ENABLE_FLAG;
bp->dev->features |= NETIF_F_LRO;
}
+ bp->disable_tpa = disable_tpa;
if (CHIP_IS_E1(bp))
bp->dropless_fc = 0;
@@ -9989,2544 +6785,11 @@ static int __devinit bnx2x_init_bp(struct bnx2x *bp)
return rc;
}
-/*
- * ethtool service functions
- */
-
-/* All ethtool functions called with rtnl_lock */
-
-static int bnx2x_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
-{
- struct bnx2x *bp = netdev_priv(dev);
-
- cmd->supported = bp->port.supported;
- cmd->advertising = bp->port.advertising;
-
- if ((bp->state == BNX2X_STATE_OPEN) &&
- !(bp->flags & MF_FUNC_DIS) &&
- (bp->link_vars.link_up)) {
- cmd->speed = bp->link_vars.line_speed;
- cmd->duplex = bp->link_vars.duplex;
- if (IS_E1HMF(bp)) {
- u16 vn_max_rate;
-
- vn_max_rate =
- ((bp->mf_config & FUNC_MF_CFG_MAX_BW_MASK) >>
- FUNC_MF_CFG_MAX_BW_SHIFT) * 100;
- if (vn_max_rate < cmd->speed)
- cmd->speed = vn_max_rate;
- }
- } else {
- cmd->speed = -1;
- cmd->duplex = -1;
- }
-
- if (bp->link_params.switch_cfg == SWITCH_CFG_10G) {
- u32 ext_phy_type =
- XGXS_EXT_PHY_TYPE(bp->link_params.ext_phy_config);
-
- switch (ext_phy_type) {
- case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT:
- case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072:
- case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
- case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705:
- case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706:
- case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
- case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
- cmd->port = PORT_FIBRE;
- break;
-
- case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101:
- case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481:
- cmd->port = PORT_TP;
- break;
-
- case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE:
- BNX2X_ERR("XGXS PHY Failure detected 0x%x\n",
- bp->link_params.ext_phy_config);
- break;
-
- default:
- DP(NETIF_MSG_LINK, "BAD XGXS ext_phy_config 0x%x\n",
- bp->link_params.ext_phy_config);
- break;
- }
- } else
- cmd->port = PORT_TP;
-
- cmd->phy_address = bp->mdio.prtad;
- cmd->transceiver = XCVR_INTERNAL;
-
- if (bp->link_params.req_line_speed == SPEED_AUTO_NEG)
- cmd->autoneg = AUTONEG_ENABLE;
- else
- cmd->autoneg = AUTONEG_DISABLE;
-
- cmd->maxtxpkt = 0;
- cmd->maxrxpkt = 0;
-
- DP(NETIF_MSG_LINK, "ethtool_cmd: cmd %d\n"
- DP_LEVEL " supported 0x%x advertising 0x%x speed %d\n"
- DP_LEVEL " duplex %d port %d phy_address %d transceiver %d\n"
- DP_LEVEL " autoneg %d maxtxpkt %d maxrxpkt %d\n",
- cmd->cmd, cmd->supported, cmd->advertising, cmd->speed,
- cmd->duplex, cmd->port, cmd->phy_address, cmd->transceiver,
- cmd->autoneg, cmd->maxtxpkt, cmd->maxrxpkt);
-
- return 0;
-}
-
-static int bnx2x_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
-{
- struct bnx2x *bp = netdev_priv(dev);
- u32 advertising;
-
- if (IS_E1HMF(bp))
- return 0;
-
- DP(NETIF_MSG_LINK, "ethtool_cmd: cmd %d\n"
- DP_LEVEL " supported 0x%x advertising 0x%x speed %d\n"
- DP_LEVEL " duplex %d port %d phy_address %d transceiver %d\n"
- DP_LEVEL " autoneg %d maxtxpkt %d maxrxpkt %d\n",
- cmd->cmd, cmd->supported, cmd->advertising, cmd->speed,
- cmd->duplex, cmd->port, cmd->phy_address, cmd->transceiver,
- cmd->autoneg, cmd->maxtxpkt, cmd->maxrxpkt);
-
- if (cmd->autoneg == AUTONEG_ENABLE) {
- if (!(bp->port.supported & SUPPORTED_Autoneg)) {
- DP(NETIF_MSG_LINK, "Autoneg not supported\n");
- return -EINVAL;
- }
-
- /* advertise the requested speed and duplex if supported */
- cmd->advertising &= bp->port.supported;
-
- bp->link_params.req_line_speed = SPEED_AUTO_NEG;
- bp->link_params.req_duplex = DUPLEX_FULL;
- bp->port.advertising |= (ADVERTISED_Autoneg |
- cmd->advertising);
-
- } else { /* forced speed */
- /* advertise the requested speed and duplex if supported */
- switch (cmd->speed) {
- case SPEED_10:
- if (cmd->duplex == DUPLEX_FULL) {
- if (!(bp->port.supported &
- SUPPORTED_10baseT_Full)) {
- DP(NETIF_MSG_LINK,
- "10M full not supported\n");
- return -EINVAL;
- }
-
- advertising = (ADVERTISED_10baseT_Full |
- ADVERTISED_TP);
- } else {
- if (!(bp->port.supported &
- SUPPORTED_10baseT_Half)) {
- DP(NETIF_MSG_LINK,
- "10M half not supported\n");
- return -EINVAL;
- }
-
- advertising = (ADVERTISED_10baseT_Half |
- ADVERTISED_TP);
- }
- break;
-
- case SPEED_100:
- if (cmd->duplex == DUPLEX_FULL) {
- if (!(bp->port.supported &
- SUPPORTED_100baseT_Full)) {
- DP(NETIF_MSG_LINK,
- "100M full not supported\n");
- return -EINVAL;
- }
-
- advertising = (ADVERTISED_100baseT_Full |
- ADVERTISED_TP);
- } else {
- if (!(bp->port.supported &
- SUPPORTED_100baseT_Half)) {
- DP(NETIF_MSG_LINK,
- "100M half not supported\n");
- return -EINVAL;
- }
-
- advertising = (ADVERTISED_100baseT_Half |
- ADVERTISED_TP);
- }
- break;
-
- case SPEED_1000:
- if (cmd->duplex != DUPLEX_FULL) {
- DP(NETIF_MSG_LINK, "1G half not supported\n");
- return -EINVAL;
- }
-
- if (!(bp->port.supported & SUPPORTED_1000baseT_Full)) {
- DP(NETIF_MSG_LINK, "1G full not supported\n");
- return -EINVAL;
- }
-
- advertising = (ADVERTISED_1000baseT_Full |
- ADVERTISED_TP);
- break;
-
- case SPEED_2500:
- if (cmd->duplex != DUPLEX_FULL) {
- DP(NETIF_MSG_LINK,
- "2.5G half not supported\n");
- return -EINVAL;
- }
-
- if (!(bp->port.supported & SUPPORTED_2500baseX_Full)) {
- DP(NETIF_MSG_LINK,
- "2.5G full not supported\n");
- return -EINVAL;
- }
-
- advertising = (ADVERTISED_2500baseX_Full |
- ADVERTISED_TP);
- break;
-
- case SPEED_10000:
- if (cmd->duplex != DUPLEX_FULL) {
- DP(NETIF_MSG_LINK, "10G half not supported\n");
- return -EINVAL;
- }
-
- if (!(bp->port.supported & SUPPORTED_10000baseT_Full)) {
- DP(NETIF_MSG_LINK, "10G full not supported\n");
- return -EINVAL;
- }
-
- advertising = (ADVERTISED_10000baseT_Full |
- ADVERTISED_FIBRE);
- break;
-
- default:
- DP(NETIF_MSG_LINK, "Unsupported speed\n");
- return -EINVAL;
- }
-
- bp->link_params.req_line_speed = cmd->speed;
- bp->link_params.req_duplex = cmd->duplex;
- bp->port.advertising = advertising;
- }
-
- DP(NETIF_MSG_LINK, "req_line_speed %d\n"
- DP_LEVEL " req_duplex %d advertising 0x%x\n",
- bp->link_params.req_line_speed, bp->link_params.req_duplex,
- bp->port.advertising);
-
- if (netif_running(dev)) {
- bnx2x_stats_handle(bp, STATS_EVENT_STOP);
- bnx2x_link_set(bp);
- }
-
- return 0;
-}
-
-#define IS_E1_ONLINE(info) (((info) & RI_E1_ONLINE) == RI_E1_ONLINE)
-#define IS_E1H_ONLINE(info) (((info) & RI_E1H_ONLINE) == RI_E1H_ONLINE)
-
-static int bnx2x_get_regs_len(struct net_device *dev)
-{
- struct bnx2x *bp = netdev_priv(dev);
- int regdump_len = 0;
- int i;
-
- if (CHIP_IS_E1(bp)) {
- for (i = 0; i < REGS_COUNT; i++)
- if (IS_E1_ONLINE(reg_addrs[i].info))
- regdump_len += reg_addrs[i].size;
-
- for (i = 0; i < WREGS_COUNT_E1; i++)
- if (IS_E1_ONLINE(wreg_addrs_e1[i].info))
- regdump_len += wreg_addrs_e1[i].size *
- (1 + wreg_addrs_e1[i].read_regs_count);
-
- } else { /* E1H */
- for (i = 0; i < REGS_COUNT; i++)
- if (IS_E1H_ONLINE(reg_addrs[i].info))
- regdump_len += reg_addrs[i].size;
-
- for (i = 0; i < WREGS_COUNT_E1H; i++)
- if (IS_E1H_ONLINE(wreg_addrs_e1h[i].info))
- regdump_len += wreg_addrs_e1h[i].size *
- (1 + wreg_addrs_e1h[i].read_regs_count);
- }
- regdump_len *= 4;
- regdump_len += sizeof(struct dump_hdr);
-
- return regdump_len;
-}
-
-static void bnx2x_get_regs(struct net_device *dev,
- struct ethtool_regs *regs, void *_p)
-{
- u32 *p = _p, i, j;
- struct bnx2x *bp = netdev_priv(dev);
- struct dump_hdr dump_hdr = {0};
-
- regs->version = 0;
- memset(p, 0, regs->len);
-
- if (!netif_running(bp->dev))
- return;
-
- dump_hdr.hdr_size = (sizeof(struct dump_hdr) / 4) - 1;
- dump_hdr.dump_sign = dump_sign_all;
- dump_hdr.xstorm_waitp = REG_RD(bp, XSTORM_WAITP_ADDR);
- dump_hdr.tstorm_waitp = REG_RD(bp, TSTORM_WAITP_ADDR);
- dump_hdr.ustorm_waitp = REG_RD(bp, USTORM_WAITP_ADDR);
- dump_hdr.cstorm_waitp = REG_RD(bp, CSTORM_WAITP_ADDR);
- dump_hdr.info = CHIP_IS_E1(bp) ? RI_E1_ONLINE : RI_E1H_ONLINE;
-
- memcpy(p, &dump_hdr, sizeof(struct dump_hdr));
- p += dump_hdr.hdr_size + 1;
-
- if (CHIP_IS_E1(bp)) {
- for (i = 0; i < REGS_COUNT; i++)
- if (IS_E1_ONLINE(reg_addrs[i].info))
- for (j = 0; j < reg_addrs[i].size; j++)
- *p++ = REG_RD(bp,
- reg_addrs[i].addr + j*4);
-
- } else { /* E1H */
- for (i = 0; i < REGS_COUNT; i++)
- if (IS_E1H_ONLINE(reg_addrs[i].info))
- for (j = 0; j < reg_addrs[i].size; j++)
- *p++ = REG_RD(bp,
- reg_addrs[i].addr + j*4);
- }
-}
-
-#define PHY_FW_VER_LEN 10
-
-static void bnx2x_get_drvinfo(struct net_device *dev,
- struct ethtool_drvinfo *info)
-{
- struct bnx2x *bp = netdev_priv(dev);
- u8 phy_fw_ver[PHY_FW_VER_LEN];
-
- strcpy(info->driver, DRV_MODULE_NAME);
- strcpy(info->version, DRV_MODULE_VERSION);
-
- phy_fw_ver[0] = '\0';
- if (bp->port.pmf) {
- bnx2x_acquire_phy_lock(bp);
- bnx2x_get_ext_phy_fw_version(&bp->link_params,
- (bp->state != BNX2X_STATE_CLOSED),
- phy_fw_ver, PHY_FW_VER_LEN);
- bnx2x_release_phy_lock(bp);
- }
-
- strncpy(info->fw_version, bp->fw_ver, 32);
- snprintf(info->fw_version + strlen(bp->fw_ver), 32 - strlen(bp->fw_ver),
- "bc %d.%d.%d%s%s",
- (bp->common.bc_ver & 0xff0000) >> 16,
- (bp->common.bc_ver & 0xff00) >> 8,
- (bp->common.bc_ver & 0xff),
- ((phy_fw_ver[0] != '\0') ? " phy " : ""), phy_fw_ver);
- strcpy(info->bus_info, pci_name(bp->pdev));
- info->n_stats = BNX2X_NUM_STATS;
- info->testinfo_len = BNX2X_NUM_TESTS;
- info->eedump_len = bp->common.flash_size;
- info->regdump_len = bnx2x_get_regs_len(dev);
-}
-
-static void bnx2x_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
-{
- struct bnx2x *bp = netdev_priv(dev);
-
- if (bp->flags & NO_WOL_FLAG) {
- wol->supported = 0;
- wol->wolopts = 0;
- } else {
- wol->supported = WAKE_MAGIC;
- if (bp->wol)
- wol->wolopts = WAKE_MAGIC;
- else
- wol->wolopts = 0;
- }
- memset(&wol->sopass, 0, sizeof(wol->sopass));
-}
-
-static int bnx2x_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
-{
- struct bnx2x *bp = netdev_priv(dev);
-
- if (wol->wolopts & ~WAKE_MAGIC)
- return -EINVAL;
-
- if (wol->wolopts & WAKE_MAGIC) {
- if (bp->flags & NO_WOL_FLAG)
- return -EINVAL;
-
- bp->wol = 1;
- } else
- bp->wol = 0;
-
- return 0;
-}
-
-static u32 bnx2x_get_msglevel(struct net_device *dev)
-{
- struct bnx2x *bp = netdev_priv(dev);
-
- return bp->msg_enable;
-}
-
-static void bnx2x_set_msglevel(struct net_device *dev, u32 level)
-{
- struct bnx2x *bp = netdev_priv(dev);
-
- if (capable(CAP_NET_ADMIN))
- bp->msg_enable = level;
-}
-
-static int bnx2x_nway_reset(struct net_device *dev)
-{
- struct bnx2x *bp = netdev_priv(dev);
-
- if (!bp->port.pmf)
- return 0;
-
- if (netif_running(dev)) {
- bnx2x_stats_handle(bp, STATS_EVENT_STOP);
- bnx2x_link_set(bp);
- }
-
- return 0;
-}
-
-static u32 bnx2x_get_link(struct net_device *dev)
-{
- struct bnx2x *bp = netdev_priv(dev);
-
- if (bp->flags & MF_FUNC_DIS)
- return 0;
-
- return bp->link_vars.link_up;
-}
-
-static int bnx2x_get_eeprom_len(struct net_device *dev)
-{
- struct bnx2x *bp = netdev_priv(dev);
-
- return bp->common.flash_size;
-}
-
-static int bnx2x_acquire_nvram_lock(struct bnx2x *bp)
-{
- int port = BP_PORT(bp);
- int count, i;
- u32 val = 0;
-
- /* adjust timeout for emulation/FPGA */
- count = NVRAM_TIMEOUT_COUNT;
- if (CHIP_REV_IS_SLOW(bp))
- count *= 100;
-
- /* request access to nvram interface */
- REG_WR(bp, MCP_REG_MCPR_NVM_SW_ARB,
- (MCPR_NVM_SW_ARB_ARB_REQ_SET1 << port));
-
- for (i = 0; i < count*10; i++) {
- val = REG_RD(bp, MCP_REG_MCPR_NVM_SW_ARB);
- if (val & (MCPR_NVM_SW_ARB_ARB_ARB1 << port))
- break;
-
- udelay(5);
- }
-
- if (!(val & (MCPR_NVM_SW_ARB_ARB_ARB1 << port))) {
- DP(BNX2X_MSG_NVM, "cannot get access to nvram interface\n");
- return -EBUSY;
- }
-
- return 0;
-}
-
-static int bnx2x_release_nvram_lock(struct bnx2x *bp)
-{
- int port = BP_PORT(bp);
- int count, i;
- u32 val = 0;
-
- /* adjust timeout for emulation/FPGA */
- count = NVRAM_TIMEOUT_COUNT;
- if (CHIP_REV_IS_SLOW(bp))
- count *= 100;
-
- /* relinquish nvram interface */
- REG_WR(bp, MCP_REG_MCPR_NVM_SW_ARB,
- (MCPR_NVM_SW_ARB_ARB_REQ_CLR1 << port));
-
- for (i = 0; i < count*10; i++) {
- val = REG_RD(bp, MCP_REG_MCPR_NVM_SW_ARB);
- if (!(val & (MCPR_NVM_SW_ARB_ARB_ARB1 << port)))
- break;
-
- udelay(5);
- }
-
- if (val & (MCPR_NVM_SW_ARB_ARB_ARB1 << port)) {
- DP(BNX2X_MSG_NVM, "cannot free access to nvram interface\n");
- return -EBUSY;
- }
-
- return 0;
-}
-
-static void bnx2x_enable_nvram_access(struct bnx2x *bp)
-{
- u32 val;
-
- val = REG_RD(bp, MCP_REG_MCPR_NVM_ACCESS_ENABLE);
-
- /* enable both bits, even on read */
- REG_WR(bp, MCP_REG_MCPR_NVM_ACCESS_ENABLE,
- (val | MCPR_NVM_ACCESS_ENABLE_EN |
- MCPR_NVM_ACCESS_ENABLE_WR_EN));
-}
-
-static void bnx2x_disable_nvram_access(struct bnx2x *bp)
-{
- u32 val;
-
- val = REG_RD(bp, MCP_REG_MCPR_NVM_ACCESS_ENABLE);
-
- /* disable both bits, even after read */
- REG_WR(bp, MCP_REG_MCPR_NVM_ACCESS_ENABLE,
- (val & ~(MCPR_NVM_ACCESS_ENABLE_EN |
- MCPR_NVM_ACCESS_ENABLE_WR_EN)));
-}
-
-static int bnx2x_nvram_read_dword(struct bnx2x *bp, u32 offset, __be32 *ret_val,
- u32 cmd_flags)
-{
- int count, i, rc;
- u32 val;
-
- /* build the command word */
- cmd_flags |= MCPR_NVM_COMMAND_DOIT;
-
- /* need to clear DONE bit separately */
- REG_WR(bp, MCP_REG_MCPR_NVM_COMMAND, MCPR_NVM_COMMAND_DONE);
-
- /* address of the NVRAM to read from */
- REG_WR(bp, MCP_REG_MCPR_NVM_ADDR,
- (offset & MCPR_NVM_ADDR_NVM_ADDR_VALUE));
-
- /* issue a read command */
- REG_WR(bp, MCP_REG_MCPR_NVM_COMMAND, cmd_flags);
-
- /* adjust timeout for emulation/FPGA */
- count = NVRAM_TIMEOUT_COUNT;
- if (CHIP_REV_IS_SLOW(bp))
- count *= 100;
-
- /* wait for completion */
- *ret_val = 0;
- rc = -EBUSY;
- for (i = 0; i < count; i++) {
- udelay(5);
- val = REG_RD(bp, MCP_REG_MCPR_NVM_COMMAND);
-
- if (val & MCPR_NVM_COMMAND_DONE) {
- val = REG_RD(bp, MCP_REG_MCPR_NVM_READ);
- /* we read nvram data in cpu order
- * but ethtool sees it as an array of bytes
- * converting to big-endian will do the work */
- *ret_val = cpu_to_be32(val);
- rc = 0;
- break;
- }
- }
-
- return rc;
-}
-
-static int bnx2x_nvram_read(struct bnx2x *bp, u32 offset, u8 *ret_buf,
- int buf_size)
-{
- int rc;
- u32 cmd_flags;
- __be32 val;
-
- if ((offset & 0x03) || (buf_size & 0x03) || (buf_size == 0)) {
- DP(BNX2X_MSG_NVM,
- "Invalid parameter: offset 0x%x buf_size 0x%x\n",
- offset, buf_size);
- return -EINVAL;
- }
-
- if (offset + buf_size > bp->common.flash_size) {
- DP(BNX2X_MSG_NVM, "Invalid parameter: offset (0x%x) +"
- " buf_size (0x%x) > flash_size (0x%x)\n",
- offset, buf_size, bp->common.flash_size);
- return -EINVAL;
- }
-
- /* request access to nvram interface */
- rc = bnx2x_acquire_nvram_lock(bp);
- if (rc)
- return rc;
-
- /* enable access to nvram interface */
- bnx2x_enable_nvram_access(bp);
-
- /* read the first word(s) */
- cmd_flags = MCPR_NVM_COMMAND_FIRST;
- while ((buf_size > sizeof(u32)) && (rc == 0)) {
- rc = bnx2x_nvram_read_dword(bp, offset, &val, cmd_flags);
- memcpy(ret_buf, &val, 4);
-
- /* advance to the next dword */
- offset += sizeof(u32);
- ret_buf += sizeof(u32);
- buf_size -= sizeof(u32);
- cmd_flags = 0;
- }
-
- if (rc == 0) {
- cmd_flags |= MCPR_NVM_COMMAND_LAST;
- rc = bnx2x_nvram_read_dword(bp, offset, &val, cmd_flags);
- memcpy(ret_buf, &val, 4);
- }
-
- /* disable access to nvram interface */
- bnx2x_disable_nvram_access(bp);
- bnx2x_release_nvram_lock(bp);
-
- return rc;
-}
-
-static int bnx2x_get_eeprom(struct net_device *dev,
- struct ethtool_eeprom *eeprom, u8 *eebuf)
-{
- struct bnx2x *bp = netdev_priv(dev);
- int rc;
-
- if (!netif_running(dev))
- return -EAGAIN;
-
- DP(BNX2X_MSG_NVM, "ethtool_eeprom: cmd %d\n"
- DP_LEVEL " magic 0x%x offset 0x%x (%d) len 0x%x (%d)\n",
- eeprom->cmd, eeprom->magic, eeprom->offset, eeprom->offset,
- eeprom->len, eeprom->len);
-
- /* parameters already validated in ethtool_get_eeprom */
-
- rc = bnx2x_nvram_read(bp, eeprom->offset, eebuf, eeprom->len);
-
- return rc;
-}
-
-static int bnx2x_nvram_write_dword(struct bnx2x *bp, u32 offset, u32 val,
- u32 cmd_flags)
-{
- int count, i, rc;
-
- /* build the command word */
- cmd_flags |= MCPR_NVM_COMMAND_DOIT | MCPR_NVM_COMMAND_WR;
-
- /* need to clear DONE bit separately */
- REG_WR(bp, MCP_REG_MCPR_NVM_COMMAND, MCPR_NVM_COMMAND_DONE);
-
- /* write the data */
- REG_WR(bp, MCP_REG_MCPR_NVM_WRITE, val);
-
- /* address of the NVRAM to write to */
- REG_WR(bp, MCP_REG_MCPR_NVM_ADDR,
- (offset & MCPR_NVM_ADDR_NVM_ADDR_VALUE));
-
- /* issue the write command */
- REG_WR(bp, MCP_REG_MCPR_NVM_COMMAND, cmd_flags);
-
- /* adjust timeout for emulation/FPGA */
- count = NVRAM_TIMEOUT_COUNT;
- if (CHIP_REV_IS_SLOW(bp))
- count *= 100;
-
- /* wait for completion */
- rc = -EBUSY;
- for (i = 0; i < count; i++) {
- udelay(5);
- val = REG_RD(bp, MCP_REG_MCPR_NVM_COMMAND);
- if (val & MCPR_NVM_COMMAND_DONE) {
- rc = 0;
- break;
- }
- }
-
- return rc;
-}
-
-#define BYTE_OFFSET(offset) (8 * (offset & 0x03))
-
-static int bnx2x_nvram_write1(struct bnx2x *bp, u32 offset, u8 *data_buf,
- int buf_size)
-{
- int rc;
- u32 cmd_flags;
- u32 align_offset;
- __be32 val;
-
- if (offset + buf_size > bp->common.flash_size) {
- DP(BNX2X_MSG_NVM, "Invalid parameter: offset (0x%x) +"
- " buf_size (0x%x) > flash_size (0x%x)\n",
- offset, buf_size, bp->common.flash_size);
- return -EINVAL;
- }
-
- /* request access to nvram interface */
- rc = bnx2x_acquire_nvram_lock(bp);
- if (rc)
- return rc;
-
- /* enable access to nvram interface */
- bnx2x_enable_nvram_access(bp);
-
- cmd_flags = (MCPR_NVM_COMMAND_FIRST | MCPR_NVM_COMMAND_LAST);
- align_offset = (offset & ~0x03);
- rc = bnx2x_nvram_read_dword(bp, align_offset, &val, cmd_flags);
-
- if (rc == 0) {
- val &= ~(0xff << BYTE_OFFSET(offset));
- val |= (*data_buf << BYTE_OFFSET(offset));
-
- /* nvram data is returned as an array of bytes
- * convert it back to cpu order */
- val = be32_to_cpu(val);
-
- rc = bnx2x_nvram_write_dword(bp, align_offset, val,
- cmd_flags);
- }
-
- /* disable access to nvram interface */
- bnx2x_disable_nvram_access(bp);
- bnx2x_release_nvram_lock(bp);
-
- return rc;
-}
-
-static int bnx2x_nvram_write(struct bnx2x *bp, u32 offset, u8 *data_buf,
- int buf_size)
-{
- int rc;
- u32 cmd_flags;
- u32 val;
- u32 written_so_far;
-
- if (buf_size == 1) /* ethtool */
- return bnx2x_nvram_write1(bp, offset, data_buf, buf_size);
-
- if ((offset & 0x03) || (buf_size & 0x03) || (buf_size == 0)) {
- DP(BNX2X_MSG_NVM,
- "Invalid parameter: offset 0x%x buf_size 0x%x\n",
- offset, buf_size);
- return -EINVAL;
- }
-
- if (offset + buf_size > bp->common.flash_size) {
- DP(BNX2X_MSG_NVM, "Invalid parameter: offset (0x%x) +"
- " buf_size (0x%x) > flash_size (0x%x)\n",
- offset, buf_size, bp->common.flash_size);
- return -EINVAL;
- }
-
- /* request access to nvram interface */
- rc = bnx2x_acquire_nvram_lock(bp);
- if (rc)
- return rc;
-
- /* enable access to nvram interface */
- bnx2x_enable_nvram_access(bp);
-
- written_so_far = 0;
- cmd_flags = MCPR_NVM_COMMAND_FIRST;
- while ((written_so_far < buf_size) && (rc == 0)) {
- if (written_so_far == (buf_size - sizeof(u32)))
- cmd_flags |= MCPR_NVM_COMMAND_LAST;
- else if (((offset + 4) % NVRAM_PAGE_SIZE) == 0)
- cmd_flags |= MCPR_NVM_COMMAND_LAST;
- else if ((offset % NVRAM_PAGE_SIZE) == 0)
- cmd_flags |= MCPR_NVM_COMMAND_FIRST;
-
- memcpy(&val, data_buf, 4);
-
- rc = bnx2x_nvram_write_dword(bp, offset, val, cmd_flags);
-
- /* advance to the next dword */
- offset += sizeof(u32);
- data_buf += sizeof(u32);
- written_so_far += sizeof(u32);
- cmd_flags = 0;
- }
-
- /* disable access to nvram interface */
- bnx2x_disable_nvram_access(bp);
- bnx2x_release_nvram_lock(bp);
-
- return rc;
-}
-
-static int bnx2x_set_eeprom(struct net_device *dev,
- struct ethtool_eeprom *eeprom, u8 *eebuf)
-{
- struct bnx2x *bp = netdev_priv(dev);
- int port = BP_PORT(bp);
- int rc = 0;
-
- if (!netif_running(dev))
- return -EAGAIN;
-
- DP(BNX2X_MSG_NVM, "ethtool_eeprom: cmd %d\n"
- DP_LEVEL " magic 0x%x offset 0x%x (%d) len 0x%x (%d)\n",
- eeprom->cmd, eeprom->magic, eeprom->offset, eeprom->offset,
- eeprom->len, eeprom->len);
-
- /* parameters already validated in ethtool_set_eeprom */
-
- /* PHY eeprom can be accessed only by the PMF */
- if ((eeprom->magic >= 0x50485900) && (eeprom->magic <= 0x504859FF) &&
- !bp->port.pmf)
- return -EINVAL;
-
- if (eeprom->magic == 0x50485950) {
- /* 'PHYP' (0x50485950): prepare phy for FW upgrade */
- bnx2x_stats_handle(bp, STATS_EVENT_STOP);
-
- bnx2x_acquire_phy_lock(bp);
- rc |= bnx2x_link_reset(&bp->link_params,
- &bp->link_vars, 0);
- if (XGXS_EXT_PHY_TYPE(bp->link_params.ext_phy_config) ==
- PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101)
- bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_0,
- MISC_REGISTERS_GPIO_HIGH, port);
- bnx2x_release_phy_lock(bp);
- bnx2x_link_report(bp);
-
- } else if (eeprom->magic == 0x50485952) {
- /* 'PHYR' (0x50485952): re-init link after FW upgrade */
- if (bp->state == BNX2X_STATE_OPEN) {
- bnx2x_acquire_phy_lock(bp);
- rc |= bnx2x_link_reset(&bp->link_params,
- &bp->link_vars, 1);
-
- rc |= bnx2x_phy_init(&bp->link_params,
- &bp->link_vars);
- bnx2x_release_phy_lock(bp);
- bnx2x_calc_fc_adv(bp);
- }
- } else if (eeprom->magic == 0x53985943) {
- /* 'PHYC' (0x53985943): PHY FW upgrade completed */
- if (XGXS_EXT_PHY_TYPE(bp->link_params.ext_phy_config) ==
- PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101) {
- u8 ext_phy_addr =
- XGXS_EXT_PHY_ADDR(bp->link_params.ext_phy_config);
-
- /* DSP Remove Download Mode */
- bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_0,
- MISC_REGISTERS_GPIO_LOW, port);
-
- bnx2x_acquire_phy_lock(bp);
-
- bnx2x_sfx7101_sp_sw_reset(bp, port, ext_phy_addr);
-
- /* wait 0.5 sec to allow it to run */
- msleep(500);
- bnx2x_ext_phy_hw_reset(bp, port);
- msleep(500);
- bnx2x_release_phy_lock(bp);
- }
- } else
- rc = bnx2x_nvram_write(bp, eeprom->offset, eebuf, eeprom->len);
-
- return rc;
-}
-
-static int bnx2x_get_coalesce(struct net_device *dev,
- struct ethtool_coalesce *coal)
-{
- struct bnx2x *bp = netdev_priv(dev);
-
- memset(coal, 0, sizeof(struct ethtool_coalesce));
-
- coal->rx_coalesce_usecs = bp->rx_ticks;
- coal->tx_coalesce_usecs = bp->tx_ticks;
-
- return 0;
-}
-
-static int bnx2x_set_coalesce(struct net_device *dev,
- struct ethtool_coalesce *coal)
-{
- struct bnx2x *bp = netdev_priv(dev);
-
- bp->rx_ticks = (u16)coal->rx_coalesce_usecs;
- if (bp->rx_ticks > BNX2X_MAX_COALESCE_TOUT)
- bp->rx_ticks = BNX2X_MAX_COALESCE_TOUT;
-
- bp->tx_ticks = (u16)coal->tx_coalesce_usecs;
- if (bp->tx_ticks > BNX2X_MAX_COALESCE_TOUT)
- bp->tx_ticks = BNX2X_MAX_COALESCE_TOUT;
-
- if (netif_running(dev))
- bnx2x_update_coalesce(bp);
-
- return 0;
-}
-
-static void bnx2x_get_ringparam(struct net_device *dev,
- struct ethtool_ringparam *ering)
-{
- struct bnx2x *bp = netdev_priv(dev);
-
- ering->rx_max_pending = MAX_RX_AVAIL;
- ering->rx_mini_max_pending = 0;
- ering->rx_jumbo_max_pending = 0;
-
- ering->rx_pending = bp->rx_ring_size;
- ering->rx_mini_pending = 0;
- ering->rx_jumbo_pending = 0;
-
- ering->tx_max_pending = MAX_TX_AVAIL;
- ering->tx_pending = bp->tx_ring_size;
-}
-
-static int bnx2x_set_ringparam(struct net_device *dev,
- struct ethtool_ringparam *ering)
-{
- struct bnx2x *bp = netdev_priv(dev);
- int rc = 0;
-
- if (bp->recovery_state != BNX2X_RECOVERY_DONE) {
- printk(KERN_ERR "Handling parity error recovery. Try again later\n");
- return -EAGAIN;
- }
-
- if ((ering->rx_pending > MAX_RX_AVAIL) ||
- (ering->tx_pending > MAX_TX_AVAIL) ||
- (ering->tx_pending <= MAX_SKB_FRAGS + 4))
- return -EINVAL;
-
- bp->rx_ring_size = ering->rx_pending;
- bp->tx_ring_size = ering->tx_pending;
-
- if (netif_running(dev)) {
- bnx2x_nic_unload(bp, UNLOAD_NORMAL);
- rc = bnx2x_nic_load(bp, LOAD_NORMAL);
- }
-
- return rc;
-}
-
-static void bnx2x_get_pauseparam(struct net_device *dev,
- struct ethtool_pauseparam *epause)
-{
- struct bnx2x *bp = netdev_priv(dev);
-
- epause->autoneg = (bp->link_params.req_flow_ctrl ==
- BNX2X_FLOW_CTRL_AUTO) &&
- (bp->link_params.req_line_speed == SPEED_AUTO_NEG);
-
- epause->rx_pause = ((bp->link_vars.flow_ctrl & BNX2X_FLOW_CTRL_RX) ==
- BNX2X_FLOW_CTRL_RX);
- epause->tx_pause = ((bp->link_vars.flow_ctrl & BNX2X_FLOW_CTRL_TX) ==
- BNX2X_FLOW_CTRL_TX);
-
- DP(NETIF_MSG_LINK, "ethtool_pauseparam: cmd %d\n"
- DP_LEVEL " autoneg %d rx_pause %d tx_pause %d\n",
- epause->cmd, epause->autoneg, epause->rx_pause, epause->tx_pause);
-}
-
-static int bnx2x_set_pauseparam(struct net_device *dev,
- struct ethtool_pauseparam *epause)
-{
- struct bnx2x *bp = netdev_priv(dev);
-
- if (IS_E1HMF(bp))
- return 0;
-
- DP(NETIF_MSG_LINK, "ethtool_pauseparam: cmd %d\n"
- DP_LEVEL " autoneg %d rx_pause %d tx_pause %d\n",
- epause->cmd, epause->autoneg, epause->rx_pause, epause->tx_pause);
-
- bp->link_params.req_flow_ctrl = BNX2X_FLOW_CTRL_AUTO;
-
- if (epause->rx_pause)
- bp->link_params.req_flow_ctrl |= BNX2X_FLOW_CTRL_RX;
-
- if (epause->tx_pause)
- bp->link_params.req_flow_ctrl |= BNX2X_FLOW_CTRL_TX;
-
- if (bp->link_params.req_flow_ctrl == BNX2X_FLOW_CTRL_AUTO)
- bp->link_params.req_flow_ctrl = BNX2X_FLOW_CTRL_NONE;
-
- if (epause->autoneg) {
- if (!(bp->port.supported & SUPPORTED_Autoneg)) {
- DP(NETIF_MSG_LINK, "autoneg not supported\n");
- return -EINVAL;
- }
-
- if (bp->link_params.req_line_speed == SPEED_AUTO_NEG)
- bp->link_params.req_flow_ctrl = BNX2X_FLOW_CTRL_AUTO;
- }
-
- DP(NETIF_MSG_LINK,
- "req_flow_ctrl 0x%x\n", bp->link_params.req_flow_ctrl);
-
- if (netif_running(dev)) {
- bnx2x_stats_handle(bp, STATS_EVENT_STOP);
- bnx2x_link_set(bp);
- }
-
- return 0;
-}
-
-static int bnx2x_set_flags(struct net_device *dev, u32 data)
-{
- struct bnx2x *bp = netdev_priv(dev);
- int changed = 0;
- int rc = 0;
-
- if (bp->recovery_state != BNX2X_RECOVERY_DONE) {
- printk(KERN_ERR "Handling parity error recovery. Try again later\n");
- return -EAGAIN;
- }
-
- /* TPA requires Rx CSUM offloading */
- if ((data & ETH_FLAG_LRO) && bp->rx_csum) {
- if (!disable_tpa) {
- if (!(dev->features & NETIF_F_LRO)) {
- dev->features |= NETIF_F_LRO;
- bp->flags |= TPA_ENABLE_FLAG;
- changed = 1;
- }
- } else
- rc = -EINVAL;
- } else if (dev->features & NETIF_F_LRO) {
- dev->features &= ~NETIF_F_LRO;
- bp->flags &= ~TPA_ENABLE_FLAG;
- changed = 1;
- }
-
- if (data & ETH_FLAG_RXHASH)
- dev->features |= NETIF_F_RXHASH;
- else
- dev->features &= ~NETIF_F_RXHASH;
-
- if (changed && netif_running(dev)) {
- bnx2x_nic_unload(bp, UNLOAD_NORMAL);
- rc = bnx2x_nic_load(bp, LOAD_NORMAL);
- }
-
- return rc;
-}
-
-static u32 bnx2x_get_rx_csum(struct net_device *dev)
-{
- struct bnx2x *bp = netdev_priv(dev);
-
- return bp->rx_csum;
-}
-
-static int bnx2x_set_rx_csum(struct net_device *dev, u32 data)
-{
- struct bnx2x *bp = netdev_priv(dev);
- int rc = 0;
-
- if (bp->recovery_state != BNX2X_RECOVERY_DONE) {
- printk(KERN_ERR "Handling parity error recovery. Try again later\n");
- return -EAGAIN;
- }
-
- bp->rx_csum = data;
-
- /* Disable TPA, when Rx CSUM is disabled. Otherwise all
- TPA'ed packets will be discarded due to wrong TCP CSUM */
- if (!data) {
- u32 flags = ethtool_op_get_flags(dev);
-
- rc = bnx2x_set_flags(dev, (flags & ~ETH_FLAG_LRO));
- }
-
- return rc;
-}
-
-static int bnx2x_set_tso(struct net_device *dev, u32 data)
-{
- if (data) {
- dev->features |= (NETIF_F_TSO | NETIF_F_TSO_ECN);
- dev->features |= NETIF_F_TSO6;
- } else {
- dev->features &= ~(NETIF_F_TSO | NETIF_F_TSO_ECN);
- dev->features &= ~NETIF_F_TSO6;
- }
-
- return 0;
-}
-
-static const struct {
- char string[ETH_GSTRING_LEN];
-} bnx2x_tests_str_arr[BNX2X_NUM_TESTS] = {
- { "register_test (offline)" },
- { "memory_test (offline)" },
- { "loopback_test (offline)" },
- { "nvram_test (online)" },
- { "interrupt_test (online)" },
- { "link_test (online)" },
- { "idle check (online)" }
-};
-
-static int bnx2x_test_registers(struct bnx2x *bp)
-{
- int idx, i, rc = -ENODEV;
- u32 wr_val = 0;
- int port = BP_PORT(bp);
- static const struct {
- u32 offset0;
- u32 offset1;
- u32 mask;
- } reg_tbl[] = {
-/* 0 */ { BRB1_REG_PAUSE_LOW_THRESHOLD_0, 4, 0x000003ff },
- { DORQ_REG_DB_ADDR0, 4, 0xffffffff },
- { HC_REG_AGG_INT_0, 4, 0x000003ff },
- { PBF_REG_MAC_IF0_ENABLE, 4, 0x00000001 },
- { PBF_REG_P0_INIT_CRD, 4, 0x000007ff },
- { PRS_REG_CID_PORT_0, 4, 0x00ffffff },
- { PXP2_REG_PSWRQ_CDU0_L2P, 4, 0x000fffff },
- { PXP2_REG_RQ_CDU0_EFIRST_MEM_ADDR, 8, 0x0003ffff },
- { PXP2_REG_PSWRQ_TM0_L2P, 4, 0x000fffff },
- { PXP2_REG_RQ_USDM0_EFIRST_MEM_ADDR, 8, 0x0003ffff },
-/* 10 */ { PXP2_REG_PSWRQ_TSDM0_L2P, 4, 0x000fffff },
- { QM_REG_CONNNUM_0, 4, 0x000fffff },
- { TM_REG_LIN0_MAX_ACTIVE_CID, 4, 0x0003ffff },
- { SRC_REG_KEYRSS0_0, 40, 0xffffffff },
- { SRC_REG_KEYRSS0_7, 40, 0xffffffff },
- { XCM_REG_WU_DA_SET_TMR_CNT_FLG_CMD00, 4, 0x00000001 },
- { XCM_REG_WU_DA_CNT_CMD00, 4, 0x00000003 },
- { XCM_REG_GLB_DEL_ACK_MAX_CNT_0, 4, 0x000000ff },
- { NIG_REG_LLH0_T_BIT, 4, 0x00000001 },
- { NIG_REG_EMAC0_IN_EN, 4, 0x00000001 },
-/* 20 */ { NIG_REG_BMAC0_IN_EN, 4, 0x00000001 },
- { NIG_REG_XCM0_OUT_EN, 4, 0x00000001 },
- { NIG_REG_BRB0_OUT_EN, 4, 0x00000001 },
- { NIG_REG_LLH0_XCM_MASK, 4, 0x00000007 },
- { NIG_REG_LLH0_ACPI_PAT_6_LEN, 68, 0x000000ff },
- { NIG_REG_LLH0_ACPI_PAT_0_CRC, 68, 0xffffffff },
- { NIG_REG_LLH0_DEST_MAC_0_0, 160, 0xffffffff },
- { NIG_REG_LLH0_DEST_IP_0_1, 160, 0xffffffff },
- { NIG_REG_LLH0_IPV4_IPV6_0, 160, 0x00000001 },
- { NIG_REG_LLH0_DEST_UDP_0, 160, 0x0000ffff },
-/* 30 */ { NIG_REG_LLH0_DEST_TCP_0, 160, 0x0000ffff },
- { NIG_REG_LLH0_VLAN_ID_0, 160, 0x00000fff },
- { NIG_REG_XGXS_SERDES0_MODE_SEL, 4, 0x00000001 },
- { NIG_REG_LED_CONTROL_OVERRIDE_TRAFFIC_P0, 4, 0x00000001 },
- { NIG_REG_STATUS_INTERRUPT_PORT0, 4, 0x07ffffff },
- { NIG_REG_XGXS0_CTRL_EXTREMOTEMDIOST, 24, 0x00000001 },
- { NIG_REG_SERDES0_CTRL_PHY_ADDR, 16, 0x0000001f },
-
- { 0xffffffff, 0, 0x00000000 }
- };
-
- if (!netif_running(bp->dev))
- return rc;
-
- /* Repeat the test twice:
- First by writing 0x00000000, second by writing 0xffffffff */
- for (idx = 0; idx < 2; idx++) {
-
- switch (idx) {
- case 0:
- wr_val = 0;
- break;
- case 1:
- wr_val = 0xffffffff;
- break;
- }
-
- for (i = 0; reg_tbl[i].offset0 != 0xffffffff; i++) {
- u32 offset, mask, save_val, val;
-
- offset = reg_tbl[i].offset0 + port*reg_tbl[i].offset1;
- mask = reg_tbl[i].mask;
-
- save_val = REG_RD(bp, offset);
-
- REG_WR(bp, offset, (wr_val & mask));
- val = REG_RD(bp, offset);
-
- /* Restore the original register's value */
- REG_WR(bp, offset, save_val);
-
- /* verify value is as expected */
- if ((val & mask) != (wr_val & mask)) {
- DP(NETIF_MSG_PROBE,
- "offset 0x%x: val 0x%x != 0x%x mask 0x%x\n",
- offset, val, wr_val, mask);
- goto test_reg_exit;
- }
- }
- }
-
- rc = 0;
-
-test_reg_exit:
- return rc;
-}
-
-static int bnx2x_test_memory(struct bnx2x *bp)
-{
- int i, j, rc = -ENODEV;
- u32 val;
- static const struct {
- u32 offset;
- int size;
- } mem_tbl[] = {
- { CCM_REG_XX_DESCR_TABLE, CCM_REG_XX_DESCR_TABLE_SIZE },
- { CFC_REG_ACTIVITY_COUNTER, CFC_REG_ACTIVITY_COUNTER_SIZE },
- { CFC_REG_LINK_LIST, CFC_REG_LINK_LIST_SIZE },
- { DMAE_REG_CMD_MEM, DMAE_REG_CMD_MEM_SIZE },
- { TCM_REG_XX_DESCR_TABLE, TCM_REG_XX_DESCR_TABLE_SIZE },
- { UCM_REG_XX_DESCR_TABLE, UCM_REG_XX_DESCR_TABLE_SIZE },
- { XCM_REG_XX_DESCR_TABLE, XCM_REG_XX_DESCR_TABLE_SIZE },
-
- { 0xffffffff, 0 }
- };
- static const struct {
- char *name;
- u32 offset;
- u32 e1_mask;
- u32 e1h_mask;
- } prty_tbl[] = {
- { "CCM_PRTY_STS", CCM_REG_CCM_PRTY_STS, 0x3ffc0, 0 },
- { "CFC_PRTY_STS", CFC_REG_CFC_PRTY_STS, 0x2, 0x2 },
- { "DMAE_PRTY_STS", DMAE_REG_DMAE_PRTY_STS, 0, 0 },
- { "TCM_PRTY_STS", TCM_REG_TCM_PRTY_STS, 0x3ffc0, 0 },
- { "UCM_PRTY_STS", UCM_REG_UCM_PRTY_STS, 0x3ffc0, 0 },
- { "XCM_PRTY_STS", XCM_REG_XCM_PRTY_STS, 0x3ffc1, 0 },
-
- { NULL, 0xffffffff, 0, 0 }
- };
-
- if (!netif_running(bp->dev))
- return rc;
-
- /* Go through all the memories */
- for (i = 0; mem_tbl[i].offset != 0xffffffff; i++)
- for (j = 0; j < mem_tbl[i].size; j++)
- REG_RD(bp, mem_tbl[i].offset + j*4);
-
- /* Check the parity status */
- for (i = 0; prty_tbl[i].offset != 0xffffffff; i++) {
- val = REG_RD(bp, prty_tbl[i].offset);
- if ((CHIP_IS_E1(bp) && (val & ~(prty_tbl[i].e1_mask))) ||
- (CHIP_IS_E1H(bp) && (val & ~(prty_tbl[i].e1h_mask)))) {
- DP(NETIF_MSG_HW,
- "%s is 0x%x\n", prty_tbl[i].name, val);
- goto test_mem_exit;
- }
- }
-
- rc = 0;
-
-test_mem_exit:
- return rc;
-}
-
-static void bnx2x_wait_for_link(struct bnx2x *bp, u8 link_up)
-{
- int cnt = 1000;
-
- if (link_up)
- while (bnx2x_link_test(bp) && cnt--)
- msleep(10);
-}
-
-static int bnx2x_run_loopback(struct bnx2x *bp, int loopback_mode, u8 link_up)
-{
- unsigned int pkt_size, num_pkts, i;
- struct sk_buff *skb;
- unsigned char *packet;
- struct bnx2x_fastpath *fp_rx = &bp->fp[0];
- struct bnx2x_fastpath *fp_tx = &bp->fp[0];
- u16 tx_start_idx, tx_idx;
- u16 rx_start_idx, rx_idx;
- u16 pkt_prod, bd_prod;
- struct sw_tx_bd *tx_buf;
- struct eth_tx_start_bd *tx_start_bd;
- struct eth_tx_parse_bd *pbd = NULL;
- dma_addr_t mapping;
- union eth_rx_cqe *cqe;
- u8 cqe_fp_flags;
- struct sw_rx_bd *rx_buf;
- u16 len;
- int rc = -ENODEV;
-
- /* check the loopback mode */
- switch (loopback_mode) {
- case BNX2X_PHY_LOOPBACK:
- if (bp->link_params.loopback_mode != LOOPBACK_XGXS_10)
- return -EINVAL;
- break;
- case BNX2X_MAC_LOOPBACK:
- bp->link_params.loopback_mode = LOOPBACK_BMAC;
- bnx2x_phy_init(&bp->link_params, &bp->link_vars);
- break;
- default:
- return -EINVAL;
- }
-
- /* prepare the loopback packet */
- pkt_size = (((bp->dev->mtu < ETH_MAX_PACKET_SIZE) ?
- bp->dev->mtu : ETH_MAX_PACKET_SIZE) + ETH_HLEN);
- skb = netdev_alloc_skb(bp->dev, bp->rx_buf_size);
- if (!skb) {
- rc = -ENOMEM;
- goto test_loopback_exit;
- }
- packet = skb_put(skb, pkt_size);
- memcpy(packet, bp->dev->dev_addr, ETH_ALEN);
- memset(packet + ETH_ALEN, 0, ETH_ALEN);
- memset(packet + 2*ETH_ALEN, 0x77, (ETH_HLEN - 2*ETH_ALEN));
- for (i = ETH_HLEN; i < pkt_size; i++)
- packet[i] = (unsigned char) (i & 0xff);
-
- /* send the loopback packet */
- num_pkts = 0;
- tx_start_idx = le16_to_cpu(*fp_tx->tx_cons_sb);
- rx_start_idx = le16_to_cpu(*fp_rx->rx_cons_sb);
-
- pkt_prod = fp_tx->tx_pkt_prod++;
- tx_buf = &fp_tx->tx_buf_ring[TX_BD(pkt_prod)];
- tx_buf->first_bd = fp_tx->tx_bd_prod;
- tx_buf->skb = skb;
- tx_buf->flags = 0;
-
- bd_prod = TX_BD(fp_tx->tx_bd_prod);
- tx_start_bd = &fp_tx->tx_desc_ring[bd_prod].start_bd;
- mapping = dma_map_single(&bp->pdev->dev, skb->data,
- skb_headlen(skb), DMA_TO_DEVICE);
- tx_start_bd->addr_hi = cpu_to_le32(U64_HI(mapping));
- tx_start_bd->addr_lo = cpu_to_le32(U64_LO(mapping));
- tx_start_bd->nbd = cpu_to_le16(2); /* start + pbd */
- tx_start_bd->nbytes = cpu_to_le16(skb_headlen(skb));
- tx_start_bd->vlan = cpu_to_le16(pkt_prod);
- tx_start_bd->bd_flags.as_bitfield = ETH_TX_BD_FLAGS_START_BD;
- tx_start_bd->general_data = ((UNICAST_ADDRESS <<
- ETH_TX_START_BD_ETH_ADDR_TYPE_SHIFT) | 1);
-
- /* turn on parsing and get a BD */
- bd_prod = TX_BD(NEXT_TX_IDX(bd_prod));
- pbd = &fp_tx->tx_desc_ring[bd_prod].parse_bd;
-
- memset(pbd, 0, sizeof(struct eth_tx_parse_bd));
-
- wmb();
-
- fp_tx->tx_db.data.prod += 2;
- barrier();
- DOORBELL(bp, fp_tx->index, fp_tx->tx_db.raw);
-
- mmiowb();
-
- num_pkts++;
- fp_tx->tx_bd_prod += 2; /* start + pbd */
-
- udelay(100);
-
- tx_idx = le16_to_cpu(*fp_tx->tx_cons_sb);
- if (tx_idx != tx_start_idx + num_pkts)
- goto test_loopback_exit;
-
- rx_idx = le16_to_cpu(*fp_rx->rx_cons_sb);
- if (rx_idx != rx_start_idx + num_pkts)
- goto test_loopback_exit;
-
- cqe = &fp_rx->rx_comp_ring[RCQ_BD(fp_rx->rx_comp_cons)];
- cqe_fp_flags = cqe->fast_path_cqe.type_error_flags;
- if (CQE_TYPE(cqe_fp_flags) || (cqe_fp_flags & ETH_RX_ERROR_FALGS))
- goto test_loopback_rx_exit;
-
- len = le16_to_cpu(cqe->fast_path_cqe.pkt_len);
- if (len != pkt_size)
- goto test_loopback_rx_exit;
-
- rx_buf = &fp_rx->rx_buf_ring[RX_BD(fp_rx->rx_bd_cons)];
- skb = rx_buf->skb;
- skb_reserve(skb, cqe->fast_path_cqe.placement_offset);
- for (i = ETH_HLEN; i < pkt_size; i++)
- if (*(skb->data + i) != (unsigned char) (i & 0xff))
- goto test_loopback_rx_exit;
-
- rc = 0;
-
-test_loopback_rx_exit:
-
- fp_rx->rx_bd_cons = NEXT_RX_IDX(fp_rx->rx_bd_cons);
- fp_rx->rx_bd_prod = NEXT_RX_IDX(fp_rx->rx_bd_prod);
- fp_rx->rx_comp_cons = NEXT_RCQ_IDX(fp_rx->rx_comp_cons);
- fp_rx->rx_comp_prod = NEXT_RCQ_IDX(fp_rx->rx_comp_prod);
-
- /* Update producers */
- bnx2x_update_rx_prod(bp, fp_rx, fp_rx->rx_bd_prod, fp_rx->rx_comp_prod,
- fp_rx->rx_sge_prod);
-
-test_loopback_exit:
- bp->link_params.loopback_mode = LOOPBACK_NONE;
-
- return rc;
-}
-
-static int bnx2x_test_loopback(struct bnx2x *bp, u8 link_up)
-{
- int rc = 0, res;
-
- if (BP_NOMCP(bp))
- return rc;
-
- if (!netif_running(bp->dev))
- return BNX2X_LOOPBACK_FAILED;
-
- bnx2x_netif_stop(bp, 1);
- bnx2x_acquire_phy_lock(bp);
-
- res = bnx2x_run_loopback(bp, BNX2X_PHY_LOOPBACK, link_up);
- if (res) {
- DP(NETIF_MSG_PROBE, " PHY loopback failed (res %d)\n", res);
- rc |= BNX2X_PHY_LOOPBACK_FAILED;
- }
-
- res = bnx2x_run_loopback(bp, BNX2X_MAC_LOOPBACK, link_up);
- if (res) {
- DP(NETIF_MSG_PROBE, " MAC loopback failed (res %d)\n", res);
- rc |= BNX2X_MAC_LOOPBACK_FAILED;
- }
-
- bnx2x_release_phy_lock(bp);
- bnx2x_netif_start(bp);
-
- return rc;
-}
-
-#define CRC32_RESIDUAL 0xdebb20e3
-
-static int bnx2x_test_nvram(struct bnx2x *bp)
-{
- static const struct {
- int offset;
- int size;
- } nvram_tbl[] = {
- { 0, 0x14 }, /* bootstrap */
- { 0x14, 0xec }, /* dir */
- { 0x100, 0x350 }, /* manuf_info */
- { 0x450, 0xf0 }, /* feature_info */
- { 0x640, 0x64 }, /* upgrade_key_info */
- { 0x6a4, 0x64 },
- { 0x708, 0x70 }, /* manuf_key_info */
- { 0x778, 0x70 },
- { 0, 0 }
- };
- __be32 buf[0x350 / 4];
- u8 *data = (u8 *)buf;
- int i, rc;
- u32 magic, crc;
-
- if (BP_NOMCP(bp))
- return 0;
-
- rc = bnx2x_nvram_read(bp, 0, data, 4);
- if (rc) {
- DP(NETIF_MSG_PROBE, "magic value read (rc %d)\n", rc);
- goto test_nvram_exit;
- }
-
- magic = be32_to_cpu(buf[0]);
- if (magic != 0x669955aa) {
- DP(NETIF_MSG_PROBE, "magic value (0x%08x)\n", magic);
- rc = -ENODEV;
- goto test_nvram_exit;
- }
-
- for (i = 0; nvram_tbl[i].size; i++) {
-
- rc = bnx2x_nvram_read(bp, nvram_tbl[i].offset, data,
- nvram_tbl[i].size);
- if (rc) {
- DP(NETIF_MSG_PROBE,
- "nvram_tbl[%d] read data (rc %d)\n", i, rc);
- goto test_nvram_exit;
- }
-
- crc = ether_crc_le(nvram_tbl[i].size, data);
- if (crc != CRC32_RESIDUAL) {
- DP(NETIF_MSG_PROBE,
- "nvram_tbl[%d] crc value (0x%08x)\n", i, crc);
- rc = -ENODEV;
- goto test_nvram_exit;
- }
- }
-
-test_nvram_exit:
- return rc;
-}
-
-static int bnx2x_test_intr(struct bnx2x *bp)
-{
- struct mac_configuration_cmd *config = bnx2x_sp(bp, mac_config);
- int i, rc;
-
- if (!netif_running(bp->dev))
- return -ENODEV;
-
- config->hdr.length = 0;
- if (CHIP_IS_E1(bp))
- /* use last unicast entries */
- config->hdr.offset = (BP_PORT(bp) ? 63 : 31);
- else
- config->hdr.offset = BP_FUNC(bp);
- config->hdr.client_id = bp->fp->cl_id;
- config->hdr.reserved1 = 0;
-
- bp->set_mac_pending++;
- smp_wmb();
- rc = bnx2x_sp_post(bp, RAMROD_CMD_ID_ETH_SET_MAC, 0,
- U64_HI(bnx2x_sp_mapping(bp, mac_config)),
- U64_LO(bnx2x_sp_mapping(bp, mac_config)), 0);
- if (rc == 0) {
- for (i = 0; i < 10; i++) {
- if (!bp->set_mac_pending)
- break;
- smp_rmb();
- msleep_interruptible(10);
- }
- if (i == 10)
- rc = -ENODEV;
- }
-
- return rc;
-}
-
-static void bnx2x_self_test(struct net_device *dev,
- struct ethtool_test *etest, u64 *buf)
-{
- struct bnx2x *bp = netdev_priv(dev);
-
- if (bp->recovery_state != BNX2X_RECOVERY_DONE) {
- printk(KERN_ERR "Handling parity error recovery. Try again later\n");
- etest->flags |= ETH_TEST_FL_FAILED;
- return;
- }
-
- memset(buf, 0, sizeof(u64) * BNX2X_NUM_TESTS);
-
- if (!netif_running(dev))
- return;
-
- /* offline tests are not supported in MF mode */
- if (IS_E1HMF(bp))
- etest->flags &= ~ETH_TEST_FL_OFFLINE;
-
- if (etest->flags & ETH_TEST_FL_OFFLINE) {
- int port = BP_PORT(bp);
- u32 val;
- u8 link_up;
-
- /* save current value of input enable for TX port IF */
- val = REG_RD(bp, NIG_REG_EGRESS_UMP0_IN_EN + port*4);
- /* disable input for TX port IF */
- REG_WR(bp, NIG_REG_EGRESS_UMP0_IN_EN + port*4, 0);
-
- link_up = (bnx2x_link_test(bp) == 0);
- bnx2x_nic_unload(bp, UNLOAD_NORMAL);
- bnx2x_nic_load(bp, LOAD_DIAG);
- /* wait until link state is restored */
- bnx2x_wait_for_link(bp, link_up);
-
- if (bnx2x_test_registers(bp) != 0) {
- buf[0] = 1;
- etest->flags |= ETH_TEST_FL_FAILED;
- }
- if (bnx2x_test_memory(bp) != 0) {
- buf[1] = 1;
- etest->flags |= ETH_TEST_FL_FAILED;
- }
- buf[2] = bnx2x_test_loopback(bp, link_up);
- if (buf[2] != 0)
- etest->flags |= ETH_TEST_FL_FAILED;
-
- bnx2x_nic_unload(bp, UNLOAD_NORMAL);
-
- /* restore input for TX port IF */
- REG_WR(bp, NIG_REG_EGRESS_UMP0_IN_EN + port*4, val);
-
- bnx2x_nic_load(bp, LOAD_NORMAL);
- /* wait until link state is restored */
- bnx2x_wait_for_link(bp, link_up);
- }
- if (bnx2x_test_nvram(bp) != 0) {
- buf[3] = 1;
- etest->flags |= ETH_TEST_FL_FAILED;
- }
- if (bnx2x_test_intr(bp) != 0) {
- buf[4] = 1;
- etest->flags |= ETH_TEST_FL_FAILED;
- }
- if (bp->port.pmf)
- if (bnx2x_link_test(bp) != 0) {
- buf[5] = 1;
- etest->flags |= ETH_TEST_FL_FAILED;
- }
-
-#ifdef BNX2X_EXTRA_DEBUG
- bnx2x_panic_dump(bp);
-#endif
-}
-
-static const struct {
- long offset;
- int size;
- u8 string[ETH_GSTRING_LEN];
-} bnx2x_q_stats_arr[BNX2X_NUM_Q_STATS] = {
-/* 1 */ { Q_STATS_OFFSET32(total_bytes_received_hi), 8, "[%d]: rx_bytes" },
- { Q_STATS_OFFSET32(error_bytes_received_hi),
- 8, "[%d]: rx_error_bytes" },
- { Q_STATS_OFFSET32(total_unicast_packets_received_hi),
- 8, "[%d]: rx_ucast_packets" },
- { Q_STATS_OFFSET32(total_multicast_packets_received_hi),
- 8, "[%d]: rx_mcast_packets" },
- { Q_STATS_OFFSET32(total_broadcast_packets_received_hi),
- 8, "[%d]: rx_bcast_packets" },
- { Q_STATS_OFFSET32(no_buff_discard_hi), 8, "[%d]: rx_discards" },
- { Q_STATS_OFFSET32(rx_err_discard_pkt),
- 4, "[%d]: rx_phy_ip_err_discards"},
- { Q_STATS_OFFSET32(rx_skb_alloc_failed),
- 4, "[%d]: rx_skb_alloc_discard" },
- { Q_STATS_OFFSET32(hw_csum_err), 4, "[%d]: rx_csum_offload_errors" },
-
-/* 10 */{ Q_STATS_OFFSET32(total_bytes_transmitted_hi), 8, "[%d]: tx_bytes" },
- { Q_STATS_OFFSET32(total_unicast_packets_transmitted_hi),
- 8, "[%d]: tx_ucast_packets" },
- { Q_STATS_OFFSET32(total_multicast_packets_transmitted_hi),
- 8, "[%d]: tx_mcast_packets" },
- { Q_STATS_OFFSET32(total_broadcast_packets_transmitted_hi),
- 8, "[%d]: tx_bcast_packets" }
-};
-
-static const struct {
- long offset;
- int size;
- u32 flags;
-#define STATS_FLAGS_PORT 1
-#define STATS_FLAGS_FUNC 2
-#define STATS_FLAGS_BOTH (STATS_FLAGS_FUNC | STATS_FLAGS_PORT)
- u8 string[ETH_GSTRING_LEN];
-} bnx2x_stats_arr[BNX2X_NUM_STATS] = {
-/* 1 */ { STATS_OFFSET32(total_bytes_received_hi),
- 8, STATS_FLAGS_BOTH, "rx_bytes" },
- { STATS_OFFSET32(error_bytes_received_hi),
- 8, STATS_FLAGS_BOTH, "rx_error_bytes" },
- { STATS_OFFSET32(total_unicast_packets_received_hi),
- 8, STATS_FLAGS_BOTH, "rx_ucast_packets" },
- { STATS_OFFSET32(total_multicast_packets_received_hi),
- 8, STATS_FLAGS_BOTH, "rx_mcast_packets" },
- { STATS_OFFSET32(total_broadcast_packets_received_hi),
- 8, STATS_FLAGS_BOTH, "rx_bcast_packets" },
- { STATS_OFFSET32(rx_stat_dot3statsfcserrors_hi),
- 8, STATS_FLAGS_PORT, "rx_crc_errors" },
- { STATS_OFFSET32(rx_stat_dot3statsalignmenterrors_hi),
- 8, STATS_FLAGS_PORT, "rx_align_errors" },
- { STATS_OFFSET32(rx_stat_etherstatsundersizepkts_hi),
- 8, STATS_FLAGS_PORT, "rx_undersize_packets" },
- { STATS_OFFSET32(etherstatsoverrsizepkts_hi),
- 8, STATS_FLAGS_PORT, "rx_oversize_packets" },
-/* 10 */{ STATS_OFFSET32(rx_stat_etherstatsfragments_hi),
- 8, STATS_FLAGS_PORT, "rx_fragments" },
- { STATS_OFFSET32(rx_stat_etherstatsjabbers_hi),
- 8, STATS_FLAGS_PORT, "rx_jabbers" },
- { STATS_OFFSET32(no_buff_discard_hi),
- 8, STATS_FLAGS_BOTH, "rx_discards" },
- { STATS_OFFSET32(mac_filter_discard),
- 4, STATS_FLAGS_PORT, "rx_filtered_packets" },
- { STATS_OFFSET32(xxoverflow_discard),
- 4, STATS_FLAGS_PORT, "rx_fw_discards" },
- { STATS_OFFSET32(brb_drop_hi),
- 8, STATS_FLAGS_PORT, "rx_brb_discard" },
- { STATS_OFFSET32(brb_truncate_hi),
- 8, STATS_FLAGS_PORT, "rx_brb_truncate" },
- { STATS_OFFSET32(pause_frames_received_hi),
- 8, STATS_FLAGS_PORT, "rx_pause_frames" },
- { STATS_OFFSET32(rx_stat_maccontrolframesreceived_hi),
- 8, STATS_FLAGS_PORT, "rx_mac_ctrl_frames" },
- { STATS_OFFSET32(nig_timer_max),
- 4, STATS_FLAGS_PORT, "rx_constant_pause_events" },
-/* 20 */{ STATS_OFFSET32(rx_err_discard_pkt),
- 4, STATS_FLAGS_BOTH, "rx_phy_ip_err_discards"},
- { STATS_OFFSET32(rx_skb_alloc_failed),
- 4, STATS_FLAGS_BOTH, "rx_skb_alloc_discard" },
- { STATS_OFFSET32(hw_csum_err),
- 4, STATS_FLAGS_BOTH, "rx_csum_offload_errors" },
-
- { STATS_OFFSET32(total_bytes_transmitted_hi),
- 8, STATS_FLAGS_BOTH, "tx_bytes" },
- { STATS_OFFSET32(tx_stat_ifhcoutbadoctets_hi),
- 8, STATS_FLAGS_PORT, "tx_error_bytes" },
- { STATS_OFFSET32(total_unicast_packets_transmitted_hi),
- 8, STATS_FLAGS_BOTH, "tx_ucast_packets" },
- { STATS_OFFSET32(total_multicast_packets_transmitted_hi),
- 8, STATS_FLAGS_BOTH, "tx_mcast_packets" },
- { STATS_OFFSET32(total_broadcast_packets_transmitted_hi),
- 8, STATS_FLAGS_BOTH, "tx_bcast_packets" },
- { STATS_OFFSET32(tx_stat_dot3statsinternalmactransmiterrors_hi),
- 8, STATS_FLAGS_PORT, "tx_mac_errors" },
- { STATS_OFFSET32(rx_stat_dot3statscarriersenseerrors_hi),
- 8, STATS_FLAGS_PORT, "tx_carrier_errors" },
-/* 30 */{ STATS_OFFSET32(tx_stat_dot3statssinglecollisionframes_hi),
- 8, STATS_FLAGS_PORT, "tx_single_collisions" },
- { STATS_OFFSET32(tx_stat_dot3statsmultiplecollisionframes_hi),
- 8, STATS_FLAGS_PORT, "tx_multi_collisions" },
- { STATS_OFFSET32(tx_stat_dot3statsdeferredtransmissions_hi),
- 8, STATS_FLAGS_PORT, "tx_deferred" },
- { STATS_OFFSET32(tx_stat_dot3statsexcessivecollisions_hi),
- 8, STATS_FLAGS_PORT, "tx_excess_collisions" },
- { STATS_OFFSET32(tx_stat_dot3statslatecollisions_hi),
- 8, STATS_FLAGS_PORT, "tx_late_collisions" },
- { STATS_OFFSET32(tx_stat_etherstatscollisions_hi),
- 8, STATS_FLAGS_PORT, "tx_total_collisions" },
- { STATS_OFFSET32(tx_stat_etherstatspkts64octets_hi),
- 8, STATS_FLAGS_PORT, "tx_64_byte_packets" },
- { STATS_OFFSET32(tx_stat_etherstatspkts65octetsto127octets_hi),
- 8, STATS_FLAGS_PORT, "tx_65_to_127_byte_packets" },
- { STATS_OFFSET32(tx_stat_etherstatspkts128octetsto255octets_hi),
- 8, STATS_FLAGS_PORT, "tx_128_to_255_byte_packets" },
- { STATS_OFFSET32(tx_stat_etherstatspkts256octetsto511octets_hi),
- 8, STATS_FLAGS_PORT, "tx_256_to_511_byte_packets" },
-/* 40 */{ STATS_OFFSET32(tx_stat_etherstatspkts512octetsto1023octets_hi),
- 8, STATS_FLAGS_PORT, "tx_512_to_1023_byte_packets" },
- { STATS_OFFSET32(etherstatspkts1024octetsto1522octets_hi),
- 8, STATS_FLAGS_PORT, "tx_1024_to_1522_byte_packets" },
- { STATS_OFFSET32(etherstatspktsover1522octets_hi),
- 8, STATS_FLAGS_PORT, "tx_1523_to_9022_byte_packets" },
- { STATS_OFFSET32(pause_frames_sent_hi),
- 8, STATS_FLAGS_PORT, "tx_pause_frames" }
-};
-
-#define IS_PORT_STAT(i) \
- ((bnx2x_stats_arr[i].flags & STATS_FLAGS_BOTH) == STATS_FLAGS_PORT)
-#define IS_FUNC_STAT(i) (bnx2x_stats_arr[i].flags & STATS_FLAGS_FUNC)
-#define IS_E1HMF_MODE_STAT(bp) \
- (IS_E1HMF(bp) && !(bp->msg_enable & BNX2X_MSG_STATS))
-
-static int bnx2x_get_sset_count(struct net_device *dev, int stringset)
-{
- struct bnx2x *bp = netdev_priv(dev);
- int i, num_stats;
-
- switch (stringset) {
- case ETH_SS_STATS:
- if (is_multi(bp)) {
- num_stats = BNX2X_NUM_Q_STATS * bp->num_queues;
- if (!IS_E1HMF_MODE_STAT(bp))
- num_stats += BNX2X_NUM_STATS;
- } else {
- if (IS_E1HMF_MODE_STAT(bp)) {
- num_stats = 0;
- for (i = 0; i < BNX2X_NUM_STATS; i++)
- if (IS_FUNC_STAT(i))
- num_stats++;
- } else
- num_stats = BNX2X_NUM_STATS;
- }
- return num_stats;
-
- case ETH_SS_TEST:
- return BNX2X_NUM_TESTS;
-
- default:
- return -EINVAL;
- }
-}
-
-static void bnx2x_get_strings(struct net_device *dev, u32 stringset, u8 *buf)
-{
- struct bnx2x *bp = netdev_priv(dev);
- int i, j, k;
-
- switch (stringset) {
- case ETH_SS_STATS:
- if (is_multi(bp)) {
- k = 0;
- for_each_queue(bp, i) {
- for (j = 0; j < BNX2X_NUM_Q_STATS; j++)
- sprintf(buf + (k + j)*ETH_GSTRING_LEN,
- bnx2x_q_stats_arr[j].string, i);
- k += BNX2X_NUM_Q_STATS;
- }
- if (IS_E1HMF_MODE_STAT(bp))
- break;
- for (j = 0; j < BNX2X_NUM_STATS; j++)
- strcpy(buf + (k + j)*ETH_GSTRING_LEN,
- bnx2x_stats_arr[j].string);
- } else {
- for (i = 0, j = 0; i < BNX2X_NUM_STATS; i++) {
- if (IS_E1HMF_MODE_STAT(bp) && IS_PORT_STAT(i))
- continue;
- strcpy(buf + j*ETH_GSTRING_LEN,
- bnx2x_stats_arr[i].string);
- j++;
- }
- }
- break;
-
- case ETH_SS_TEST:
- memcpy(buf, bnx2x_tests_str_arr, sizeof(bnx2x_tests_str_arr));
- break;
- }
-}
-
-static void bnx2x_get_ethtool_stats(struct net_device *dev,
- struct ethtool_stats *stats, u64 *buf)
-{
- struct bnx2x *bp = netdev_priv(dev);
- u32 *hw_stats, *offset;
- int i, j, k;
-
- if (is_multi(bp)) {
- k = 0;
- for_each_queue(bp, i) {
- hw_stats = (u32 *)&bp->fp[i].eth_q_stats;
- for (j = 0; j < BNX2X_NUM_Q_STATS; j++) {
- if (bnx2x_q_stats_arr[j].size == 0) {
- /* skip this counter */
- buf[k + j] = 0;
- continue;
- }
- offset = (hw_stats +
- bnx2x_q_stats_arr[j].offset);
- if (bnx2x_q_stats_arr[j].size == 4) {
- /* 4-byte counter */
- buf[k + j] = (u64) *offset;
- continue;
- }
- /* 8-byte counter */
- buf[k + j] = HILO_U64(*offset, *(offset + 1));
- }
- k += BNX2X_NUM_Q_STATS;
- }
- if (IS_E1HMF_MODE_STAT(bp))
- return;
- hw_stats = (u32 *)&bp->eth_stats;
- for (j = 0; j < BNX2X_NUM_STATS; j++) {
- if (bnx2x_stats_arr[j].size == 0) {
- /* skip this counter */
- buf[k + j] = 0;
- continue;
- }
- offset = (hw_stats + bnx2x_stats_arr[j].offset);
- if (bnx2x_stats_arr[j].size == 4) {
- /* 4-byte counter */
- buf[k + j] = (u64) *offset;
- continue;
- }
- /* 8-byte counter */
- buf[k + j] = HILO_U64(*offset, *(offset + 1));
- }
- } else {
- hw_stats = (u32 *)&bp->eth_stats;
- for (i = 0, j = 0; i < BNX2X_NUM_STATS; i++) {
- if (IS_E1HMF_MODE_STAT(bp) && IS_PORT_STAT(i))
- continue;
- if (bnx2x_stats_arr[i].size == 0) {
- /* skip this counter */
- buf[j] = 0;
- j++;
- continue;
- }
- offset = (hw_stats + bnx2x_stats_arr[i].offset);
- if (bnx2x_stats_arr[i].size == 4) {
- /* 4-byte counter */
- buf[j] = (u64) *offset;
- j++;
- continue;
- }
- /* 8-byte counter */
- buf[j] = HILO_U64(*offset, *(offset + 1));
- j++;
- }
- }
-}
-
-static int bnx2x_phys_id(struct net_device *dev, u32 data)
-{
- struct bnx2x *bp = netdev_priv(dev);
- int i;
-
- if (!netif_running(dev))
- return 0;
-
- if (!bp->port.pmf)
- return 0;
-
- if (data == 0)
- data = 2;
-
- for (i = 0; i < (data * 2); i++) {
- if ((i % 2) == 0)
- bnx2x_set_led(&bp->link_params, LED_MODE_OPER,
- SPEED_1000);
- else
- bnx2x_set_led(&bp->link_params, LED_MODE_OFF, 0);
-
- msleep_interruptible(500);
- if (signal_pending(current))
- break;
- }
-
- if (bp->link_vars.link_up)
- bnx2x_set_led(&bp->link_params, LED_MODE_OPER,
- bp->link_vars.line_speed);
-
- return 0;
-}
-
-static const struct ethtool_ops bnx2x_ethtool_ops = {
- .get_settings = bnx2x_get_settings,
- .set_settings = bnx2x_set_settings,
- .get_drvinfo = bnx2x_get_drvinfo,
- .get_regs_len = bnx2x_get_regs_len,
- .get_regs = bnx2x_get_regs,
- .get_wol = bnx2x_get_wol,
- .set_wol = bnx2x_set_wol,
- .get_msglevel = bnx2x_get_msglevel,
- .set_msglevel = bnx2x_set_msglevel,
- .nway_reset = bnx2x_nway_reset,
- .get_link = bnx2x_get_link,
- .get_eeprom_len = bnx2x_get_eeprom_len,
- .get_eeprom = bnx2x_get_eeprom,
- .set_eeprom = bnx2x_set_eeprom,
- .get_coalesce = bnx2x_get_coalesce,
- .set_coalesce = bnx2x_set_coalesce,
- .get_ringparam = bnx2x_get_ringparam,
- .set_ringparam = bnx2x_set_ringparam,
- .get_pauseparam = bnx2x_get_pauseparam,
- .set_pauseparam = bnx2x_set_pauseparam,
- .get_rx_csum = bnx2x_get_rx_csum,
- .set_rx_csum = bnx2x_set_rx_csum,
- .get_tx_csum = ethtool_op_get_tx_csum,
- .set_tx_csum = ethtool_op_set_tx_hw_csum,
- .set_flags = bnx2x_set_flags,
- .get_flags = ethtool_op_get_flags,
- .get_sg = ethtool_op_get_sg,
- .set_sg = ethtool_op_set_sg,
- .get_tso = ethtool_op_get_tso,
- .set_tso = bnx2x_set_tso,
- .self_test = bnx2x_self_test,
- .get_sset_count = bnx2x_get_sset_count,
- .get_strings = bnx2x_get_strings,
- .phys_id = bnx2x_phys_id,
- .get_ethtool_stats = bnx2x_get_ethtool_stats,
-};
-
-/* end of ethtool_ops */
/****************************************************************************
* General service functions
****************************************************************************/
-static int bnx2x_set_power_state(struct bnx2x *bp, pci_power_t state)
-{
- u16 pmcsr;
-
- pci_read_config_word(bp->pdev, bp->pm_cap + PCI_PM_CTRL, &pmcsr);
-
- switch (state) {
- case PCI_D0:
- pci_write_config_word(bp->pdev, bp->pm_cap + PCI_PM_CTRL,
- ((pmcsr & ~PCI_PM_CTRL_STATE_MASK) |
- PCI_PM_CTRL_PME_STATUS));
-
- if (pmcsr & PCI_PM_CTRL_STATE_MASK)
- /* delay required during transition out of D3hot */
- msleep(20);
- break;
-
- case PCI_D3hot:
- /* If there are other clients above don't
- shut down the power */
- if (atomic_read(&bp->pdev->enable_cnt) != 1)
- return 0;
- /* Don't shut down the power for emulation and FPGA */
- if (CHIP_REV_IS_SLOW(bp))
- return 0;
-
- pmcsr &= ~PCI_PM_CTRL_STATE_MASK;
- pmcsr |= 3;
-
- if (bp->wol)
- pmcsr |= PCI_PM_CTRL_PME_ENABLE;
-
- pci_write_config_word(bp->pdev, bp->pm_cap + PCI_PM_CTRL,
- pmcsr);
-
- /* No more memory access after this point until
- * device is brought back to D0.
- */
- break;
-
- default:
- return -EINVAL;
- }
- return 0;
-}
-
-static inline int bnx2x_has_rx_work(struct bnx2x_fastpath *fp)
-{
- u16 rx_cons_sb;
-
- /* Tell compiler that status block fields can change */
- barrier();
- rx_cons_sb = le16_to_cpu(*fp->rx_cons_sb);
- if ((rx_cons_sb & MAX_RCQ_DESC_CNT) == MAX_RCQ_DESC_CNT)
- rx_cons_sb++;
- return (fp->rx_comp_cons != rx_cons_sb);
-}
-
-/*
- * net_device service functions
- */
-
-static int bnx2x_poll(struct napi_struct *napi, int budget)
-{
- int work_done = 0;
- struct bnx2x_fastpath *fp = container_of(napi, struct bnx2x_fastpath,
- napi);
- struct bnx2x *bp = fp->bp;
-
- while (1) {
-#ifdef BNX2X_STOP_ON_ERROR
- if (unlikely(bp->panic)) {
- napi_complete(napi);
- return 0;
- }
-#endif
-
- if (bnx2x_has_tx_work(fp))
- bnx2x_tx_int(fp);
-
- if (bnx2x_has_rx_work(fp)) {
- work_done += bnx2x_rx_int(fp, budget - work_done);
-
- /* must not complete if we consumed full budget */
- if (work_done >= budget)
- break;
- }
-
- /* Fall out from the NAPI loop if needed */
- if (!(bnx2x_has_rx_work(fp) || bnx2x_has_tx_work(fp))) {
- bnx2x_update_fpsb_idx(fp);
- /* bnx2x_has_rx_work() reads the status block, thus we need
- * to ensure that status block indices have been actually read
- * (bnx2x_update_fpsb_idx) prior to this check
- * (bnx2x_has_rx_work) so that we won't write the "newer"
- * value of the status block to IGU (if there was a DMA right
- * after bnx2x_has_rx_work and if there is no rmb, the memory
- * reading (bnx2x_update_fpsb_idx) may be postponed to right
- * before bnx2x_ack_sb). In this case there will never be
- * another interrupt until there is another update of the
- * status block, while there is still unhandled work.
- */
- rmb();
-
- if (!(bnx2x_has_rx_work(fp) || bnx2x_has_tx_work(fp))) {
- napi_complete(napi);
- /* Re-enable interrupts */
- bnx2x_ack_sb(bp, fp->sb_id, CSTORM_ID,
- le16_to_cpu(fp->fp_c_idx),
- IGU_INT_NOP, 1);
- bnx2x_ack_sb(bp, fp->sb_id, USTORM_ID,
- le16_to_cpu(fp->fp_u_idx),
- IGU_INT_ENABLE, 1);
- break;
- }
- }
- }
-
- return work_done;
-}
-
-
-/* we split the first BD into headers and data BDs
- * to ease the pain of our fellow microcode engineers
- * we use one mapping for both BDs
- * So far this has only been observed to happen
- * in Other Operating Systems(TM)
- */
-static noinline u16 bnx2x_tx_split(struct bnx2x *bp,
- struct bnx2x_fastpath *fp,
- struct sw_tx_bd *tx_buf,
- struct eth_tx_start_bd **tx_bd, u16 hlen,
- u16 bd_prod, int nbd)
-{
- struct eth_tx_start_bd *h_tx_bd = *tx_bd;
- struct eth_tx_bd *d_tx_bd;
- dma_addr_t mapping;
- int old_len = le16_to_cpu(h_tx_bd->nbytes);
-
- /* first fix first BD */
- h_tx_bd->nbd = cpu_to_le16(nbd);
- h_tx_bd->nbytes = cpu_to_le16(hlen);
-
- DP(NETIF_MSG_TX_QUEUED, "TSO split header size is %d "
- "(%x:%x) nbd %d\n", h_tx_bd->nbytes, h_tx_bd->addr_hi,
- h_tx_bd->addr_lo, h_tx_bd->nbd);
-
- /* now get a new data BD
- * (after the pbd) and fill it */
- bd_prod = TX_BD(NEXT_TX_IDX(bd_prod));
- d_tx_bd = &fp->tx_desc_ring[bd_prod].reg_bd;
-
- mapping = HILO_U64(le32_to_cpu(h_tx_bd->addr_hi),
- le32_to_cpu(h_tx_bd->addr_lo)) + hlen;
-
- d_tx_bd->addr_hi = cpu_to_le32(U64_HI(mapping));
- d_tx_bd->addr_lo = cpu_to_le32(U64_LO(mapping));
- d_tx_bd->nbytes = cpu_to_le16(old_len - hlen);
-
- /* this marks the BD as one that has no individual mapping */
- tx_buf->flags |= BNX2X_TSO_SPLIT_BD;
-
- DP(NETIF_MSG_TX_QUEUED,
- "TSO split data size is %d (%x:%x)\n",
- d_tx_bd->nbytes, d_tx_bd->addr_hi, d_tx_bd->addr_lo);
-
- /* update tx_bd */
- *tx_bd = (struct eth_tx_start_bd *)d_tx_bd;
-
- return bd_prod;
-}
-
-static inline u16 bnx2x_csum_fix(unsigned char *t_header, u16 csum, s8 fix)
-{
- if (fix > 0)
- csum = (u16) ~csum_fold(csum_sub(csum,
- csum_partial(t_header - fix, fix, 0)));
-
- else if (fix < 0)
- csum = (u16) ~csum_fold(csum_add(csum,
- csum_partial(t_header, -fix, 0)));
-
- return swab16(csum);
-}
-
-static inline u32 bnx2x_xmit_type(struct bnx2x *bp, struct sk_buff *skb)
-{
- u32 rc;
-
- if (skb->ip_summed != CHECKSUM_PARTIAL)
- rc = XMIT_PLAIN;
-
- else {
- if (skb->protocol == htons(ETH_P_IPV6)) {
- rc = XMIT_CSUM_V6;
- if (ipv6_hdr(skb)->nexthdr == IPPROTO_TCP)
- rc |= XMIT_CSUM_TCP;
-
- } else {
- rc = XMIT_CSUM_V4;
- if (ip_hdr(skb)->protocol == IPPROTO_TCP)
- rc |= XMIT_CSUM_TCP;
- }
- }
-
- if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV4)
- rc |= (XMIT_GSO_V4 | XMIT_CSUM_V4 | XMIT_CSUM_TCP);
-
- else if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV6)
- rc |= (XMIT_GSO_V6 | XMIT_CSUM_TCP | XMIT_CSUM_V6);
-
- return rc;
-}
-
-#if (MAX_SKB_FRAGS >= MAX_FETCH_BD - 3)
-/* check if packet requires linearization (packet is too fragmented)
- no need to check fragmentation if page size > 8K (there will be no
- violation to FW restrictions) */
-static int bnx2x_pkt_req_lin(struct bnx2x *bp, struct sk_buff *skb,
- u32 xmit_type)
-{
- int to_copy = 0;
- int hlen = 0;
- int first_bd_sz = 0;
-
- /* 3 = 1 (for linear data BD) + 2 (for PBD and last BD) */
- if (skb_shinfo(skb)->nr_frags >= (MAX_FETCH_BD - 3)) {
-
- if (xmit_type & XMIT_GSO) {
- unsigned short lso_mss = skb_shinfo(skb)->gso_size;
- /* Check if LSO packet needs to be copied:
- 3 = 1 (for headers BD) + 2 (for PBD and last BD) */
- int wnd_size = MAX_FETCH_BD - 3;
- /* Number of windows to check */
- int num_wnds = skb_shinfo(skb)->nr_frags - wnd_size;
- int wnd_idx = 0;
- int frag_idx = 0;
- u32 wnd_sum = 0;
-
- /* Headers length */
- hlen = (int)(skb_transport_header(skb) - skb->data) +
- tcp_hdrlen(skb);
-
- /* Amount of data (w/o headers) on linear part of SKB*/
- first_bd_sz = skb_headlen(skb) - hlen;
-
- wnd_sum = first_bd_sz;
-
- /* Calculate the first sum - it's special */
- for (frag_idx = 0; frag_idx < wnd_size - 1; frag_idx++)
- wnd_sum +=
- skb_shinfo(skb)->frags[frag_idx].size;
-
- /* If there was data on linear skb data - check it */
- if (first_bd_sz > 0) {
- if (unlikely(wnd_sum < lso_mss)) {
- to_copy = 1;
- goto exit_lbl;
- }
-
- wnd_sum -= first_bd_sz;
- }
-
- /* Others are easier: run through the frag list and
- check all windows */
- for (wnd_idx = 0; wnd_idx <= num_wnds; wnd_idx++) {
- wnd_sum +=
- skb_shinfo(skb)->frags[wnd_idx + wnd_size - 1].size;
-
- if (unlikely(wnd_sum < lso_mss)) {
- to_copy = 1;
- break;
- }
- wnd_sum -=
- skb_shinfo(skb)->frags[wnd_idx].size;
- }
- } else {
- /* in non-LSO too fragmented packet should always
- be linearized */
- to_copy = 1;
- }
- }
-
-exit_lbl:
- if (unlikely(to_copy))
- DP(NETIF_MSG_TX_QUEUED,
- "Linearization IS REQUIRED for %s packet. "
- "num_frags %d hlen %d first_bd_sz %d\n",
- (xmit_type & XMIT_GSO) ? "LSO" : "non-LSO",
- skb_shinfo(skb)->nr_frags, hlen, first_bd_sz);
-
- return to_copy;
-}
-#endif
-
-/* called with netif_tx_lock
- * bnx2x_tx_int() runs without netif_tx_lock unless it needs to call
- * netif_wake_queue()
- */
-static netdev_tx_t bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev)
-{
- struct bnx2x *bp = netdev_priv(dev);
- struct bnx2x_fastpath *fp;
- struct netdev_queue *txq;
- struct sw_tx_bd *tx_buf;
- struct eth_tx_start_bd *tx_start_bd;
- struct eth_tx_bd *tx_data_bd, *total_pkt_bd = NULL;
- struct eth_tx_parse_bd *pbd = NULL;
- u16 pkt_prod, bd_prod;
- int nbd, fp_index;
- dma_addr_t mapping;
- u32 xmit_type = bnx2x_xmit_type(bp, skb);
- int i;
- u8 hlen = 0;
- __le16 pkt_size = 0;
- struct ethhdr *eth;
- u8 mac_type = UNICAST_ADDRESS;
-
-#ifdef BNX2X_STOP_ON_ERROR
- if (unlikely(bp->panic))
- return NETDEV_TX_BUSY;
-#endif
-
- fp_index = skb_get_queue_mapping(skb);
- txq = netdev_get_tx_queue(dev, fp_index);
-
- fp = &bp->fp[fp_index];
-
- if (unlikely(bnx2x_tx_avail(fp) < (skb_shinfo(skb)->nr_frags + 3))) {
- fp->eth_q_stats.driver_xoff++;
- netif_tx_stop_queue(txq);
- BNX2X_ERR("BUG! Tx ring full when queue awake!\n");
- return NETDEV_TX_BUSY;
- }
-
- DP(NETIF_MSG_TX_QUEUED, "SKB: summed %x protocol %x protocol(%x,%x)"
- " gso type %x xmit_type %x\n",
- skb->ip_summed, skb->protocol, ipv6_hdr(skb)->nexthdr,
- ip_hdr(skb)->protocol, skb_shinfo(skb)->gso_type, xmit_type);
-
- eth = (struct ethhdr *)skb->data;
-
- /* set flag according to packet type (UNICAST_ADDRESS is default)*/
- if (unlikely(is_multicast_ether_addr(eth->h_dest))) {
- if (is_broadcast_ether_addr(eth->h_dest))
- mac_type = BROADCAST_ADDRESS;
- else
- mac_type = MULTICAST_ADDRESS;
- }
-
-#if (MAX_SKB_FRAGS >= MAX_FETCH_BD - 3)
- /* First, check if we need to linearize the skb (due to FW
- restrictions). No need to check fragmentation if page size > 8K
- (there will be no violation to FW restrictions) */
- if (bnx2x_pkt_req_lin(bp, skb, xmit_type)) {
- /* Statistics of linearization */
- bp->lin_cnt++;
- if (skb_linearize(skb) != 0) {
- DP(NETIF_MSG_TX_QUEUED, "SKB linearization failed - "
- "silently dropping this SKB\n");
- dev_kfree_skb_any(skb);
- return NETDEV_TX_OK;
- }
- }
-#endif
-
- /*
- Please read carefully. First we use one BD which we mark as start,
- then we have a parsing info BD (used for TSO or xsum),
- and only then we have the rest of the TSO BDs.
- (don't forget to mark the last one as last,
- and to unmap only AFTER you write to the BD ...)
- And above all, all pdb sizes are in words - NOT DWORDS!
- */
-
- pkt_prod = fp->tx_pkt_prod++;
- bd_prod = TX_BD(fp->tx_bd_prod);
-
- /* get a tx_buf and first BD */
- tx_buf = &fp->tx_buf_ring[TX_BD(pkt_prod)];
- tx_start_bd = &fp->tx_desc_ring[bd_prod].start_bd;
-
- tx_start_bd->bd_flags.as_bitfield = ETH_TX_BD_FLAGS_START_BD;
- tx_start_bd->general_data = (mac_type <<
- ETH_TX_START_BD_ETH_ADDR_TYPE_SHIFT);
- /* header nbd */
- tx_start_bd->general_data |= (1 << ETH_TX_START_BD_HDR_NBDS_SHIFT);
-
- /* remember the first BD of the packet */
- tx_buf->first_bd = fp->tx_bd_prod;
- tx_buf->skb = skb;
- tx_buf->flags = 0;
-
- DP(NETIF_MSG_TX_QUEUED,
- "sending pkt %u @%p next_idx %u bd %u @%p\n",
- pkt_prod, tx_buf, fp->tx_pkt_prod, bd_prod, tx_start_bd);
-
-#ifdef BCM_VLAN
- if ((bp->vlgrp != NULL) && vlan_tx_tag_present(skb) &&
- (bp->flags & HW_VLAN_TX_FLAG)) {
- tx_start_bd->vlan = cpu_to_le16(vlan_tx_tag_get(skb));
- tx_start_bd->bd_flags.as_bitfield |= ETH_TX_BD_FLAGS_VLAN_TAG;
- } else
-#endif
- tx_start_bd->vlan = cpu_to_le16(pkt_prod);
-
- /* turn on parsing and get a BD */
- bd_prod = TX_BD(NEXT_TX_IDX(bd_prod));
- pbd = &fp->tx_desc_ring[bd_prod].parse_bd;
-
- memset(pbd, 0, sizeof(struct eth_tx_parse_bd));
-
- if (xmit_type & XMIT_CSUM) {
- hlen = (skb_network_header(skb) - skb->data) / 2;
-
- /* for now NS flag is not used in Linux */
- pbd->global_data =
- (hlen | ((skb->protocol == cpu_to_be16(ETH_P_8021Q)) <<
- ETH_TX_PARSE_BD_LLC_SNAP_EN_SHIFT));
-
- pbd->ip_hlen = (skb_transport_header(skb) -
- skb_network_header(skb)) / 2;
-
- hlen += pbd->ip_hlen + tcp_hdrlen(skb) / 2;
-
- pbd->total_hlen = cpu_to_le16(hlen);
- hlen = hlen*2;
-
- tx_start_bd->bd_flags.as_bitfield |= ETH_TX_BD_FLAGS_L4_CSUM;
-
- if (xmit_type & XMIT_CSUM_V4)
- tx_start_bd->bd_flags.as_bitfield |=
- ETH_TX_BD_FLAGS_IP_CSUM;
- else
- tx_start_bd->bd_flags.as_bitfield |=
- ETH_TX_BD_FLAGS_IPV6;
-
- if (xmit_type & XMIT_CSUM_TCP) {
- pbd->tcp_pseudo_csum = swab16(tcp_hdr(skb)->check);
-
- } else {
- s8 fix = SKB_CS_OFF(skb); /* signed! */
-
- pbd->global_data |= ETH_TX_PARSE_BD_UDP_CS_FLG;
-
- DP(NETIF_MSG_TX_QUEUED,
- "hlen %d fix %d csum before fix %x\n",
- le16_to_cpu(pbd->total_hlen), fix, SKB_CS(skb));
-
- /* HW bug: fixup the CSUM */
- pbd->tcp_pseudo_csum =
- bnx2x_csum_fix(skb_transport_header(skb),
- SKB_CS(skb), fix);
-
- DP(NETIF_MSG_TX_QUEUED, "csum after fix %x\n",
- pbd->tcp_pseudo_csum);
- }
- }
-
- mapping = dma_map_single(&bp->pdev->dev, skb->data,
- skb_headlen(skb), DMA_TO_DEVICE);
-
- tx_start_bd->addr_hi = cpu_to_le32(U64_HI(mapping));
- tx_start_bd->addr_lo = cpu_to_le32(U64_LO(mapping));
- nbd = skb_shinfo(skb)->nr_frags + 2; /* start_bd + pbd + frags */
- tx_start_bd->nbd = cpu_to_le16(nbd);
- tx_start_bd->nbytes = cpu_to_le16(skb_headlen(skb));
- pkt_size = tx_start_bd->nbytes;
-
- DP(NETIF_MSG_TX_QUEUED, "first bd @%p addr (%x:%x) nbd %d"
- " nbytes %d flags %x vlan %x\n",
- tx_start_bd, tx_start_bd->addr_hi, tx_start_bd->addr_lo,
- le16_to_cpu(tx_start_bd->nbd), le16_to_cpu(tx_start_bd->nbytes),
- tx_start_bd->bd_flags.as_bitfield, le16_to_cpu(tx_start_bd->vlan));
-
- if (xmit_type & XMIT_GSO) {
-
- DP(NETIF_MSG_TX_QUEUED,
- "TSO packet len %d hlen %d total len %d tso size %d\n",
- skb->len, hlen, skb_headlen(skb),
- skb_shinfo(skb)->gso_size);
-
- tx_start_bd->bd_flags.as_bitfield |= ETH_TX_BD_FLAGS_SW_LSO;
-
- if (unlikely(skb_headlen(skb) > hlen))
- bd_prod = bnx2x_tx_split(bp, fp, tx_buf, &tx_start_bd,
- hlen, bd_prod, ++nbd);
-
- pbd->lso_mss = cpu_to_le16(skb_shinfo(skb)->gso_size);
- pbd->tcp_send_seq = swab32(tcp_hdr(skb)->seq);
- pbd->tcp_flags = pbd_tcp_flags(skb);
-
- if (xmit_type & XMIT_GSO_V4) {
- pbd->ip_id = swab16(ip_hdr(skb)->id);
- pbd->tcp_pseudo_csum =
- swab16(~csum_tcpudp_magic(ip_hdr(skb)->saddr,
- ip_hdr(skb)->daddr,
- 0, IPPROTO_TCP, 0));
-
- } else
- pbd->tcp_pseudo_csum =
- swab16(~csum_ipv6_magic(&ipv6_hdr(skb)->saddr,
- &ipv6_hdr(skb)->daddr,
- 0, IPPROTO_TCP, 0));
-
- pbd->global_data |= ETH_TX_PARSE_BD_PSEUDO_CS_WITHOUT_LEN;
- }
- tx_data_bd = (struct eth_tx_bd *)tx_start_bd;
-
- for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
- skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
-
- bd_prod = TX_BD(NEXT_TX_IDX(bd_prod));
- tx_data_bd = &fp->tx_desc_ring[bd_prod].reg_bd;
- if (total_pkt_bd == NULL)
- total_pkt_bd = &fp->tx_desc_ring[bd_prod].reg_bd;
-
- mapping = dma_map_page(&bp->pdev->dev, frag->page,
- frag->page_offset,
- frag->size, DMA_TO_DEVICE);
-
- tx_data_bd->addr_hi = cpu_to_le32(U64_HI(mapping));
- tx_data_bd->addr_lo = cpu_to_le32(U64_LO(mapping));
- tx_data_bd->nbytes = cpu_to_le16(frag->size);
- le16_add_cpu(&pkt_size, frag->size);
-
- DP(NETIF_MSG_TX_QUEUED,
- "frag %d bd @%p addr (%x:%x) nbytes %d\n",
- i, tx_data_bd, tx_data_bd->addr_hi, tx_data_bd->addr_lo,
- le16_to_cpu(tx_data_bd->nbytes));
- }
-
- DP(NETIF_MSG_TX_QUEUED, "last bd @%p\n", tx_data_bd);
-
- bd_prod = TX_BD(NEXT_TX_IDX(bd_prod));
-
- /* now send a tx doorbell, counting the next BD
- * if the packet contains or ends with it
- */
- if (TX_BD_POFF(bd_prod) < nbd)
- nbd++;
-
- if (total_pkt_bd != NULL)
- total_pkt_bd->total_pkt_bytes = pkt_size;
-
- if (pbd)
- DP(NETIF_MSG_TX_QUEUED,
- "PBD @%p ip_data %x ip_hlen %u ip_id %u lso_mss %u"
- " tcp_flags %x xsum %x seq %u hlen %u\n",
- pbd, pbd->global_data, pbd->ip_hlen, pbd->ip_id,
- pbd->lso_mss, pbd->tcp_flags, pbd->tcp_pseudo_csum,
- pbd->tcp_send_seq, le16_to_cpu(pbd->total_hlen));
-
- DP(NETIF_MSG_TX_QUEUED, "doorbell: nbd %d bd %u\n", nbd, bd_prod);
-
- /*
- * Make sure that the BD data is updated before updating the producer
- * since FW might read the BD right after the producer is updated.
- * This is only applicable for weak-ordered memory model archs such
- * as IA-64. The following barrier is also mandatory since FW will
- * assumes packets must have BDs.
- */
- wmb();
-
- fp->tx_db.data.prod += nbd;
- barrier();
- DOORBELL(bp, fp->index, fp->tx_db.raw);
-
- mmiowb();
-
- fp->tx_bd_prod += nbd;
-
- if (unlikely(bnx2x_tx_avail(fp) < MAX_SKB_FRAGS + 3)) {
- netif_tx_stop_queue(txq);
-
- /* paired memory barrier is in bnx2x_tx_int(), we have to keep
- * ordering of set_bit() in netif_tx_stop_queue() and read of
- * fp->bd_tx_cons */
- smp_mb();
-
- fp->eth_q_stats.driver_xoff++;
- if (bnx2x_tx_avail(fp) >= MAX_SKB_FRAGS + 3)
- netif_tx_wake_queue(txq);
- }
- fp->tx_pkt++;
-
- return NETDEV_TX_OK;
-}
-
/* called with rtnl_lock */
static int bnx2x_open(struct net_device *dev)
{
@@ -12586,7 +6849,7 @@ static int bnx2x_close(struct net_device *dev)
}
/* called with netif_tx_lock from dev_mcast.c */
-static void bnx2x_set_rx_mode(struct net_device *dev)
+void bnx2x_set_rx_mode(struct net_device *dev)
{
struct bnx2x *bp = netdev_priv(dev);
u32 rx_mode = BNX2X_RX_MODE_NORMAL;
@@ -12706,25 +6969,6 @@ static void bnx2x_set_rx_mode(struct net_device *dev)
bnx2x_set_storm_rx_mode(bp);
}
-/* called with rtnl_lock */
-static int bnx2x_change_mac_addr(struct net_device *dev, void *p)
-{
- struct sockaddr *addr = p;
- struct bnx2x *bp = netdev_priv(dev);
-
- if (!is_valid_ether_addr((u8 *)(addr->sa_data)))
- return -EINVAL;
-
- memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
- if (netif_running(dev)) {
- if (CHIP_IS_E1(bp))
- bnx2x_set_eth_mac_addr_e1(bp, 1);
- else
- bnx2x_set_eth_mac_addr_e1h(bp, 1);
- }
-
- return 0;
-}
/* called with rtnl_lock */
static int bnx2x_mdio_read(struct net_device *netdev, int prtad,
@@ -12800,71 +7044,6 @@ static int bnx2x_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
return mdio_mii_ioctl(&bp->mdio, mdio, cmd);
}
-/* called with rtnl_lock */
-static int bnx2x_change_mtu(struct net_device *dev, int new_mtu)
-{
- struct bnx2x *bp = netdev_priv(dev);
- int rc = 0;
-
- if (bp->recovery_state != BNX2X_RECOVERY_DONE) {
- printk(KERN_ERR "Handling parity error recovery. Try again later\n");
- return -EAGAIN;
- }
-
- if ((new_mtu > ETH_MAX_JUMBO_PACKET_SIZE) ||
- ((new_mtu + ETH_HLEN) < ETH_MIN_PACKET_SIZE))
- return -EINVAL;
-
- /* This does not race with packet allocation
- * because the actual alloc size is
- * only updated as part of load
- */
- dev->mtu = new_mtu;
-
- if (netif_running(dev)) {
- bnx2x_nic_unload(bp, UNLOAD_NORMAL);
- rc = bnx2x_nic_load(bp, LOAD_NORMAL);
- }
-
- return rc;
-}
-
-static void bnx2x_tx_timeout(struct net_device *dev)
-{
- struct bnx2x *bp = netdev_priv(dev);
-
-#ifdef BNX2X_STOP_ON_ERROR
- if (!bp->panic)
- bnx2x_panic();
-#endif
- /* This allows the netif to be shutdown gracefully before resetting */
- schedule_delayed_work(&bp->reset_task, 0);
-}
-
-#ifdef BCM_VLAN
-/* called with rtnl_lock */
-static void bnx2x_vlan_rx_register(struct net_device *dev,
- struct vlan_group *vlgrp)
-{
- struct bnx2x *bp = netdev_priv(dev);
-
- bp->vlgrp = vlgrp;
-
- /* Set flags according to the required capabilities */
- bp->flags &= ~(HW_VLAN_RX_FLAG | HW_VLAN_TX_FLAG);
-
- if (dev->features & NETIF_F_HW_VLAN_TX)
- bp->flags |= HW_VLAN_TX_FLAG;
-
- if (dev->features & NETIF_F_HW_VLAN_RX)
- bp->flags |= HW_VLAN_RX_FLAG;
-
- if (netif_running(dev))
- bnx2x_set_client_config(bp);
-}
-
-#endif
-
#ifdef CONFIG_NET_POLL_CONTROLLER
static void poll_bnx2x(struct net_device *dev)
{
@@ -13013,7 +7192,7 @@ static int __devinit bnx2x_init_dev(struct pci_dev *pdev,
dev->watchdog_timeo = TX_TIMEOUT;
dev->netdev_ops = &bnx2x_netdev_ops;
- dev->ethtool_ops = &bnx2x_ethtool_ops;
+ bnx2x_set_ethtool_ops(dev);
dev->features |= NETIF_F_SG;
dev->features |= NETIF_F_HW_CSUM;
if (bp->flags & USING_DAC_FLAG)
@@ -13366,73 +7545,6 @@ static void __devexit bnx2x_remove_one(struct pci_dev *pdev)
pci_set_drvdata(pdev, NULL);
}
-static int bnx2x_suspend(struct pci_dev *pdev, pm_message_t state)
-{
- struct net_device *dev = pci_get_drvdata(pdev);
- struct bnx2x *bp;
-
- if (!dev) {
- dev_err(&pdev->dev, "BAD net device from bnx2x_init_one\n");
- return -ENODEV;
- }
- bp = netdev_priv(dev);
-
- rtnl_lock();
-
- pci_save_state(pdev);
-
- if (!netif_running(dev)) {
- rtnl_unlock();
- return 0;
- }
-
- netif_device_detach(dev);
-
- bnx2x_nic_unload(bp, UNLOAD_CLOSE);
-
- bnx2x_set_power_state(bp, pci_choose_state(pdev, state));
-
- rtnl_unlock();
-
- return 0;
-}
-
-static int bnx2x_resume(struct pci_dev *pdev)
-{
- struct net_device *dev = pci_get_drvdata(pdev);
- struct bnx2x *bp;
- int rc;
-
- if (!dev) {
- dev_err(&pdev->dev, "BAD net device from bnx2x_init_one\n");
- return -ENODEV;
- }
- bp = netdev_priv(dev);
-
- if (bp->recovery_state != BNX2X_RECOVERY_DONE) {
- printk(KERN_ERR "Handling parity error recovery. Try again later\n");
- return -EAGAIN;
- }
-
- rtnl_lock();
-
- pci_restore_state(pdev);
-
- if (!netif_running(dev)) {
- rtnl_unlock();
- return 0;
- }
-
- bnx2x_set_power_state(bp, PCI_D0);
- netif_device_attach(dev);
-
- rc = bnx2x_nic_load(bp, LOAD_OPEN);
-
- rtnl_unlock();
-
- return rc;
-}
-
static int bnx2x_eeh_nic_unload(struct bnx2x *bp)
{
int i;
@@ -13754,7 +7866,7 @@ static int bnx2x_cnic_ctl_send_bh(struct bnx2x *bp, struct cnic_ctl_info *ctl)
/*
* for commands that have no data
*/
-static int bnx2x_cnic_notify(struct bnx2x *bp, int cmd)
+int bnx2x_cnic_notify(struct bnx2x *bp, int cmd)
{
struct cnic_ctl_info ctl = {0};
@@ -13822,7 +7934,7 @@ static int bnx2x_drv_ctl(struct net_device *dev, struct drv_ctl_info *ctl)
return rc;
}
-static void bnx2x_setup_cnic_irq_info(struct bnx2x *bp)
+void bnx2x_setup_cnic_irq_info(struct bnx2x *bp)
{
struct cnic_eth_dev *cp = &bp->cnic_eth_dev;
diff --git a/drivers/net/bnx2x_reg.h b/drivers/net/bnx2x/bnx2x_reg.h
index a1f3bf0cd63..a1f3bf0cd63 100644
--- a/drivers/net/bnx2x_reg.h
+++ b/drivers/net/bnx2x/bnx2x_reg.h
diff --git a/drivers/net/bnx2x/bnx2x_stats.c b/drivers/net/bnx2x/bnx2x_stats.c
new file mode 100644
index 00000000000..c7472446102
--- /dev/null
+++ b/drivers/net/bnx2x/bnx2x_stats.c
@@ -0,0 +1,1411 @@
+/* bnx2x_stats.c: Broadcom Everest network driver.
+ *
+ * Copyright (c) 2007-2010 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.
+ *
+ * Maintained by: Eilon Greenstein <eilong@broadcom.com>
+ * Written by: Eliezer Tamir
+ * Based on code from Michael Chan's bnx2 driver
+ * UDP CSUM errata workaround by Arik Gendelman
+ * Slowpath and fastpath rework by Vladislav Zolotarov
+ * Statistics and Link management by Yitchak Gertner
+ *
+ */
+ #include "bnx2x_cmn.h"
+ #include "bnx2x_stats.h"
+
+/* Statistics */
+
+/****************************************************************************
+* Macros
+****************************************************************************/
+
+/* sum[hi:lo] += add[hi:lo] */
+#define ADD_64(s_hi, a_hi, s_lo, a_lo) \
+ do { \
+ s_lo += a_lo; \
+ s_hi += a_hi + ((s_lo < a_lo) ? 1 : 0); \
+ } while (0)
+
+/* difference = minuend - subtrahend */
+#define DIFF_64(d_hi, m_hi, s_hi, d_lo, m_lo, s_lo) \
+ do { \
+ if (m_lo < s_lo) { \
+ /* underflow */ \
+ d_hi = m_hi - s_hi; \
+ if (d_hi > 0) { \
+ /* we can 'loan' 1 */ \
+ d_hi--; \
+ d_lo = m_lo + (UINT_MAX - s_lo) + 1; \
+ } else { \
+ /* m_hi <= s_hi */ \
+ d_hi = 0; \
+ d_lo = 0; \
+ } \
+ } else { \
+ /* m_lo >= s_lo */ \
+ if (m_hi < s_hi) { \
+ d_hi = 0; \
+ d_lo = 0; \
+ } else { \
+ /* m_hi >= s_hi */ \
+ d_hi = m_hi - s_hi; \
+ d_lo = m_lo - s_lo; \
+ } \
+ } \
+ } while (0)
+
+#define UPDATE_STAT64(s, t) \
+ do { \
+ DIFF_64(diff.hi, new->s##_hi, pstats->mac_stx[0].t##_hi, \
+ diff.lo, new->s##_lo, pstats->mac_stx[0].t##_lo); \
+ pstats->mac_stx[0].t##_hi = new->s##_hi; \
+ pstats->mac_stx[0].t##_lo = new->s##_lo; \
+ ADD_64(pstats->mac_stx[1].t##_hi, diff.hi, \
+ pstats->mac_stx[1].t##_lo, diff.lo); \
+ } while (0)
+
+#define UPDATE_STAT64_NIG(s, t) \
+ do { \
+ DIFF_64(diff.hi, new->s##_hi, old->s##_hi, \
+ diff.lo, new->s##_lo, old->s##_lo); \
+ ADD_64(estats->t##_hi, diff.hi, \
+ estats->t##_lo, diff.lo); \
+ } while (0)
+
+/* sum[hi:lo] += add */
+#define ADD_EXTEND_64(s_hi, s_lo, a) \
+ do { \
+ s_lo += a; \
+ s_hi += (s_lo < a) ? 1 : 0; \
+ } while (0)
+
+#define UPDATE_EXTEND_STAT(s) \
+ do { \
+ ADD_EXTEND_64(pstats->mac_stx[1].s##_hi, \
+ pstats->mac_stx[1].s##_lo, \
+ new->s); \
+ } while (0)
+
+#define UPDATE_EXTEND_TSTAT(s, t) \
+ do { \
+ diff = le32_to_cpu(tclient->s) - le32_to_cpu(old_tclient->s); \
+ old_tclient->s = tclient->s; \
+ ADD_EXTEND_64(qstats->t##_hi, qstats->t##_lo, diff); \
+ } while (0)
+
+#define UPDATE_EXTEND_USTAT(s, t) \
+ do { \
+ diff = le32_to_cpu(uclient->s) - le32_to_cpu(old_uclient->s); \
+ old_uclient->s = uclient->s; \
+ ADD_EXTEND_64(qstats->t##_hi, qstats->t##_lo, diff); \
+ } while (0)
+
+#define UPDATE_EXTEND_XSTAT(s, t) \
+ do { \
+ diff = le32_to_cpu(xclient->s) - le32_to_cpu(old_xclient->s); \
+ old_xclient->s = xclient->s; \
+ ADD_EXTEND_64(qstats->t##_hi, qstats->t##_lo, diff); \
+ } while (0)
+
+/* minuend -= subtrahend */
+#define SUB_64(m_hi, s_hi, m_lo, s_lo) \
+ do { \
+ DIFF_64(m_hi, m_hi, s_hi, m_lo, m_lo, s_lo); \
+ } while (0)
+
+/* minuend[hi:lo] -= subtrahend */
+#define SUB_EXTEND_64(m_hi, m_lo, s) \
+ do { \
+ SUB_64(m_hi, 0, m_lo, s); \
+ } while (0)
+
+#define SUB_EXTEND_USTAT(s, t) \
+ do { \
+ diff = le32_to_cpu(uclient->s) - le32_to_cpu(old_uclient->s); \
+ SUB_EXTEND_64(qstats->t##_hi, qstats->t##_lo, diff); \
+ } while (0)
+
+/*
+ * General service functions
+ */
+
+static inline long bnx2x_hilo(u32 *hiref)
+{
+ u32 lo = *(hiref + 1);
+#if (BITS_PER_LONG == 64)
+ u32 hi = *hiref;
+
+ return HILO_U64(hi, lo);
+#else
+ return lo;
+#endif
+}
+
+/*
+ * Init service functions
+ */
+
+
+static void bnx2x_storm_stats_post(struct bnx2x *bp)
+{
+ if (!bp->stats_pending) {
+ struct eth_query_ramrod_data ramrod_data = {0};
+ int i, rc;
+
+ spin_lock_bh(&bp->stats_lock);
+
+ ramrod_data.drv_counter = bp->stats_counter++;
+ ramrod_data.collect_port = bp->port.pmf ? 1 : 0;
+ for_each_queue(bp, i)
+ ramrod_data.ctr_id_vector |= (1 << bp->fp[i].cl_id);
+
+ rc = bnx2x_sp_post(bp, RAMROD_CMD_ID_ETH_STAT_QUERY, 0,
+ ((u32 *)&ramrod_data)[1],
+ ((u32 *)&ramrod_data)[0], 0);
+ if (rc == 0) {
+ /* stats ramrod has it's own slot on the spq */
+ bp->spq_left++;
+ bp->stats_pending = 1;
+ }
+
+ spin_unlock_bh(&bp->stats_lock);
+ }
+}
+
+static void bnx2x_hw_stats_post(struct bnx2x *bp)
+{
+ struct dmae_command *dmae = &bp->stats_dmae;
+ u32 *stats_comp = bnx2x_sp(bp, stats_comp);
+
+ *stats_comp = DMAE_COMP_VAL;
+ if (CHIP_REV_IS_SLOW(bp))
+ return;
+
+ /* loader */
+ if (bp->executer_idx) {
+ int loader_idx = PMF_DMAE_C(bp);
+
+ memset(dmae, 0, sizeof(struct dmae_command));
+
+ dmae->opcode = (DMAE_CMD_SRC_PCI | DMAE_CMD_DST_GRC |
+ DMAE_CMD_C_DST_GRC | DMAE_CMD_C_ENABLE |
+ DMAE_CMD_DST_RESET |
+#ifdef __BIG_ENDIAN
+ DMAE_CMD_ENDIANITY_B_DW_SWAP |
+#else
+ DMAE_CMD_ENDIANITY_DW_SWAP |
+#endif
+ (BP_PORT(bp) ? DMAE_CMD_PORT_1 :
+ DMAE_CMD_PORT_0) |
+ (BP_E1HVN(bp) << DMAE_CMD_E1HVN_SHIFT));
+ dmae->src_addr_lo = U64_LO(bnx2x_sp_mapping(bp, dmae[0]));
+ dmae->src_addr_hi = U64_HI(bnx2x_sp_mapping(bp, dmae[0]));
+ dmae->dst_addr_lo = (DMAE_REG_CMD_MEM +
+ sizeof(struct dmae_command) *
+ (loader_idx + 1)) >> 2;
+ dmae->dst_addr_hi = 0;
+ dmae->len = sizeof(struct dmae_command) >> 2;
+ if (CHIP_IS_E1(bp))
+ dmae->len--;
+ dmae->comp_addr_lo = dmae_reg_go_c[loader_idx + 1] >> 2;
+ dmae->comp_addr_hi = 0;
+ dmae->comp_val = 1;
+
+ *stats_comp = 0;
+ bnx2x_post_dmae(bp, dmae, loader_idx);
+
+ } else if (bp->func_stx) {
+ *stats_comp = 0;
+ bnx2x_post_dmae(bp, dmae, INIT_DMAE_C(bp));
+ }
+}
+
+static int bnx2x_stats_comp(struct bnx2x *bp)
+{
+ u32 *stats_comp = bnx2x_sp(bp, stats_comp);
+ int cnt = 10;
+
+ might_sleep();
+ while (*stats_comp != DMAE_COMP_VAL) {
+ if (!cnt) {
+ BNX2X_ERR("timeout waiting for stats finished\n");
+ break;
+ }
+ cnt--;
+ msleep(1);
+ }
+ return 1;
+}
+
+/*
+ * Statistics service functions
+ */
+
+static void bnx2x_stats_pmf_update(struct bnx2x *bp)
+{
+ struct dmae_command *dmae;
+ u32 opcode;
+ int loader_idx = PMF_DMAE_C(bp);
+ u32 *stats_comp = bnx2x_sp(bp, stats_comp);
+
+ /* sanity */
+ if (!IS_E1HMF(bp) || !bp->port.pmf || !bp->port.port_stx) {
+ BNX2X_ERR("BUG!\n");
+ return;
+ }
+
+ bp->executer_idx = 0;
+
+ opcode = (DMAE_CMD_SRC_GRC | DMAE_CMD_DST_PCI |
+ DMAE_CMD_C_ENABLE |
+ DMAE_CMD_SRC_RESET | DMAE_CMD_DST_RESET |
+#ifdef __BIG_ENDIAN
+ DMAE_CMD_ENDIANITY_B_DW_SWAP |
+#else
+ DMAE_CMD_ENDIANITY_DW_SWAP |
+#endif
+ (BP_PORT(bp) ? DMAE_CMD_PORT_1 : DMAE_CMD_PORT_0) |
+ (BP_E1HVN(bp) << DMAE_CMD_E1HVN_SHIFT));
+
+ dmae = bnx2x_sp(bp, dmae[bp->executer_idx++]);
+ dmae->opcode = (opcode | DMAE_CMD_C_DST_GRC);
+ dmae->src_addr_lo = bp->port.port_stx >> 2;
+ dmae->src_addr_hi = 0;
+ dmae->dst_addr_lo = U64_LO(bnx2x_sp_mapping(bp, port_stats));
+ dmae->dst_addr_hi = U64_HI(bnx2x_sp_mapping(bp, port_stats));
+ dmae->len = DMAE_LEN32_RD_MAX;
+ dmae->comp_addr_lo = dmae_reg_go_c[loader_idx] >> 2;
+ dmae->comp_addr_hi = 0;
+ dmae->comp_val = 1;
+
+ dmae = bnx2x_sp(bp, dmae[bp->executer_idx++]);
+ dmae->opcode = (opcode | DMAE_CMD_C_DST_PCI);
+ dmae->src_addr_lo = (bp->port.port_stx >> 2) + DMAE_LEN32_RD_MAX;
+ dmae->src_addr_hi = 0;
+ dmae->dst_addr_lo = U64_LO(bnx2x_sp_mapping(bp, port_stats) +
+ DMAE_LEN32_RD_MAX * 4);
+ dmae->dst_addr_hi = U64_HI(bnx2x_sp_mapping(bp, port_stats) +
+ DMAE_LEN32_RD_MAX * 4);
+ dmae->len = (sizeof(struct host_port_stats) >> 2) - DMAE_LEN32_RD_MAX;
+ dmae->comp_addr_lo = U64_LO(bnx2x_sp_mapping(bp, stats_comp));
+ dmae->comp_addr_hi = U64_HI(bnx2x_sp_mapping(bp, stats_comp));
+ dmae->comp_val = DMAE_COMP_VAL;
+
+ *stats_comp = 0;
+ bnx2x_hw_stats_post(bp);
+ bnx2x_stats_comp(bp);
+}
+
+static void bnx2x_port_stats_init(struct bnx2x *bp)
+{
+ struct dmae_command *dmae;
+ int port = BP_PORT(bp);
+ int vn = BP_E1HVN(bp);
+ u32 opcode;
+ int loader_idx = PMF_DMAE_C(bp);
+ u32 mac_addr;
+ u32 *stats_comp = bnx2x_sp(bp, stats_comp);
+
+ /* sanity */
+ if (!bp->link_vars.link_up || !bp->port.pmf) {
+ BNX2X_ERR("BUG!\n");
+ return;
+ }
+
+ bp->executer_idx = 0;
+
+ /* MCP */
+ opcode = (DMAE_CMD_SRC_PCI | DMAE_CMD_DST_GRC |
+ DMAE_CMD_C_DST_GRC | DMAE_CMD_C_ENABLE |
+ DMAE_CMD_SRC_RESET | DMAE_CMD_DST_RESET |
+#ifdef __BIG_ENDIAN
+ DMAE_CMD_ENDIANITY_B_DW_SWAP |
+#else
+ DMAE_CMD_ENDIANITY_DW_SWAP |
+#endif
+ (port ? DMAE_CMD_PORT_1 : DMAE_CMD_PORT_0) |
+ (vn << DMAE_CMD_E1HVN_SHIFT));
+
+ if (bp->port.port_stx) {
+
+ dmae = bnx2x_sp(bp, dmae[bp->executer_idx++]);
+ dmae->opcode = opcode;
+ dmae->src_addr_lo = U64_LO(bnx2x_sp_mapping(bp, port_stats));
+ dmae->src_addr_hi = U64_HI(bnx2x_sp_mapping(bp, port_stats));
+ dmae->dst_addr_lo = bp->port.port_stx >> 2;
+ dmae->dst_addr_hi = 0;
+ dmae->len = sizeof(struct host_port_stats) >> 2;
+ dmae->comp_addr_lo = dmae_reg_go_c[loader_idx] >> 2;
+ dmae->comp_addr_hi = 0;
+ dmae->comp_val = 1;
+ }
+
+ if (bp->func_stx) {
+
+ dmae = bnx2x_sp(bp, dmae[bp->executer_idx++]);
+ dmae->opcode = opcode;
+ dmae->src_addr_lo = U64_LO(bnx2x_sp_mapping(bp, func_stats));
+ dmae->src_addr_hi = U64_HI(bnx2x_sp_mapping(bp, func_stats));
+ dmae->dst_addr_lo = bp->func_stx >> 2;
+ dmae->dst_addr_hi = 0;
+ dmae->len = sizeof(struct host_func_stats) >> 2;
+ dmae->comp_addr_lo = dmae_reg_go_c[loader_idx] >> 2;
+ dmae->comp_addr_hi = 0;
+ dmae->comp_val = 1;
+ }
+
+ /* MAC */
+ opcode = (DMAE_CMD_SRC_GRC | DMAE_CMD_DST_PCI |
+ DMAE_CMD_C_DST_GRC | DMAE_CMD_C_ENABLE |
+ DMAE_CMD_SRC_RESET | DMAE_CMD_DST_RESET |
+#ifdef __BIG_ENDIAN
+ DMAE_CMD_ENDIANITY_B_DW_SWAP |
+#else
+ DMAE_CMD_ENDIANITY_DW_SWAP |
+#endif
+ (port ? DMAE_CMD_PORT_1 : DMAE_CMD_PORT_0) |
+ (vn << DMAE_CMD_E1HVN_SHIFT));
+
+ if (bp->link_vars.mac_type == MAC_TYPE_BMAC) {
+
+ mac_addr = (port ? NIG_REG_INGRESS_BMAC1_MEM :
+ NIG_REG_INGRESS_BMAC0_MEM);
+
+ /* BIGMAC_REGISTER_TX_STAT_GTPKT ..
+ BIGMAC_REGISTER_TX_STAT_GTBYT */
+ dmae = bnx2x_sp(bp, dmae[bp->executer_idx++]);
+ dmae->opcode = opcode;
+ dmae->src_addr_lo = (mac_addr +
+ BIGMAC_REGISTER_TX_STAT_GTPKT) >> 2;
+ dmae->src_addr_hi = 0;
+ dmae->dst_addr_lo = U64_LO(bnx2x_sp_mapping(bp, mac_stats));
+ dmae->dst_addr_hi = U64_HI(bnx2x_sp_mapping(bp, mac_stats));
+ dmae->len = (8 + BIGMAC_REGISTER_TX_STAT_GTBYT -
+ BIGMAC_REGISTER_TX_STAT_GTPKT) >> 2;
+ dmae->comp_addr_lo = dmae_reg_go_c[loader_idx] >> 2;
+ dmae->comp_addr_hi = 0;
+ dmae->comp_val = 1;
+
+ /* BIGMAC_REGISTER_RX_STAT_GR64 ..
+ BIGMAC_REGISTER_RX_STAT_GRIPJ */
+ dmae = bnx2x_sp(bp, dmae[bp->executer_idx++]);
+ dmae->opcode = opcode;
+ dmae->src_addr_lo = (mac_addr +
+ BIGMAC_REGISTER_RX_STAT_GR64) >> 2;
+ dmae->src_addr_hi = 0;
+ dmae->dst_addr_lo = U64_LO(bnx2x_sp_mapping(bp, mac_stats) +
+ offsetof(struct bmac_stats, rx_stat_gr64_lo));
+ dmae->dst_addr_hi = U64_HI(bnx2x_sp_mapping(bp, mac_stats) +
+ offsetof(struct bmac_stats, rx_stat_gr64_lo));
+ dmae->len = (8 + BIGMAC_REGISTER_RX_STAT_GRIPJ -
+ BIGMAC_REGISTER_RX_STAT_GR64) >> 2;
+ dmae->comp_addr_lo = dmae_reg_go_c[loader_idx] >> 2;
+ dmae->comp_addr_hi = 0;
+ dmae->comp_val = 1;
+
+ } else if (bp->link_vars.mac_type == MAC_TYPE_EMAC) {
+
+ mac_addr = (port ? GRCBASE_EMAC1 : GRCBASE_EMAC0);
+
+ /* EMAC_REG_EMAC_RX_STAT_AC (EMAC_REG_EMAC_RX_STAT_AC_COUNT)*/
+ dmae = bnx2x_sp(bp, dmae[bp->executer_idx++]);
+ dmae->opcode = opcode;
+ dmae->src_addr_lo = (mac_addr +
+ EMAC_REG_EMAC_RX_STAT_AC) >> 2;
+ dmae->src_addr_hi = 0;
+ dmae->dst_addr_lo = U64_LO(bnx2x_sp_mapping(bp, mac_stats));
+ dmae->dst_addr_hi = U64_HI(bnx2x_sp_mapping(bp, mac_stats));
+ dmae->len = EMAC_REG_EMAC_RX_STAT_AC_COUNT;
+ dmae->comp_addr_lo = dmae_reg_go_c[loader_idx] >> 2;
+ dmae->comp_addr_hi = 0;
+ dmae->comp_val = 1;
+
+ /* EMAC_REG_EMAC_RX_STAT_AC_28 */
+ dmae = bnx2x_sp(bp, dmae[bp->executer_idx++]);
+ dmae->opcode = opcode;
+ dmae->src_addr_lo = (mac_addr +
+ EMAC_REG_EMAC_RX_STAT_AC_28) >> 2;
+ dmae->src_addr_hi = 0;
+ dmae->dst_addr_lo = U64_LO(bnx2x_sp_mapping(bp, mac_stats) +
+ offsetof(struct emac_stats, rx_stat_falsecarriererrors));
+ dmae->dst_addr_hi = U64_HI(bnx2x_sp_mapping(bp, mac_stats) +
+ offsetof(struct emac_stats, rx_stat_falsecarriererrors));
+ dmae->len = 1;
+ dmae->comp_addr_lo = dmae_reg_go_c[loader_idx] >> 2;
+ dmae->comp_addr_hi = 0;
+ dmae->comp_val = 1;
+
+ /* EMAC_REG_EMAC_TX_STAT_AC (EMAC_REG_EMAC_TX_STAT_AC_COUNT)*/
+ dmae = bnx2x_sp(bp, dmae[bp->executer_idx++]);
+ dmae->opcode = opcode;
+ dmae->src_addr_lo = (mac_addr +
+ EMAC_REG_EMAC_TX_STAT_AC) >> 2;
+ dmae->src_addr_hi = 0;
+ dmae->dst_addr_lo = U64_LO(bnx2x_sp_mapping(bp, mac_stats) +
+ offsetof(struct emac_stats, tx_stat_ifhcoutoctets));
+ dmae->dst_addr_hi = U64_HI(bnx2x_sp_mapping(bp, mac_stats) +
+ offsetof(struct emac_stats, tx_stat_ifhcoutoctets));
+ dmae->len = EMAC_REG_EMAC_TX_STAT_AC_COUNT;
+ dmae->comp_addr_lo = dmae_reg_go_c[loader_idx] >> 2;
+ dmae->comp_addr_hi = 0;
+ dmae->comp_val = 1;
+ }
+
+ /* NIG */
+ dmae = bnx2x_sp(bp, dmae[bp->executer_idx++]);
+ dmae->opcode = opcode;
+ dmae->src_addr_lo = (port ? NIG_REG_STAT1_BRB_DISCARD :
+ NIG_REG_STAT0_BRB_DISCARD) >> 2;
+ dmae->src_addr_hi = 0;
+ dmae->dst_addr_lo = U64_LO(bnx2x_sp_mapping(bp, nig_stats));
+ dmae->dst_addr_hi = U64_HI(bnx2x_sp_mapping(bp, nig_stats));
+ dmae->len = (sizeof(struct nig_stats) - 4*sizeof(u32)) >> 2;
+ dmae->comp_addr_lo = dmae_reg_go_c[loader_idx] >> 2;
+ dmae->comp_addr_hi = 0;
+ dmae->comp_val = 1;
+
+ dmae = bnx2x_sp(bp, dmae[bp->executer_idx++]);
+ dmae->opcode = opcode;
+ dmae->src_addr_lo = (port ? NIG_REG_STAT1_EGRESS_MAC_PKT0 :
+ NIG_REG_STAT0_EGRESS_MAC_PKT0) >> 2;
+ dmae->src_addr_hi = 0;
+ dmae->dst_addr_lo = U64_LO(bnx2x_sp_mapping(bp, nig_stats) +
+ offsetof(struct nig_stats, egress_mac_pkt0_lo));
+ dmae->dst_addr_hi = U64_HI(bnx2x_sp_mapping(bp, nig_stats) +
+ offsetof(struct nig_stats, egress_mac_pkt0_lo));
+ dmae->len = (2*sizeof(u32)) >> 2;
+ dmae->comp_addr_lo = dmae_reg_go_c[loader_idx] >> 2;
+ dmae->comp_addr_hi = 0;
+ dmae->comp_val = 1;
+
+ dmae = bnx2x_sp(bp, dmae[bp->executer_idx++]);
+ dmae->opcode = (DMAE_CMD_SRC_GRC | DMAE_CMD_DST_PCI |
+ DMAE_CMD_C_DST_PCI | DMAE_CMD_C_ENABLE |
+ DMAE_CMD_SRC_RESET | DMAE_CMD_DST_RESET |
+#ifdef __BIG_ENDIAN
+ DMAE_CMD_ENDIANITY_B_DW_SWAP |
+#else
+ DMAE_CMD_ENDIANITY_DW_SWAP |
+#endif
+ (port ? DMAE_CMD_PORT_1 : DMAE_CMD_PORT_0) |
+ (vn << DMAE_CMD_E1HVN_SHIFT));
+ dmae->src_addr_lo = (port ? NIG_REG_STAT1_EGRESS_MAC_PKT1 :
+ NIG_REG_STAT0_EGRESS_MAC_PKT1) >> 2;
+ dmae->src_addr_hi = 0;
+ dmae->dst_addr_lo = U64_LO(bnx2x_sp_mapping(bp, nig_stats) +
+ offsetof(struct nig_stats, egress_mac_pkt1_lo));
+ dmae->dst_addr_hi = U64_HI(bnx2x_sp_mapping(bp, nig_stats) +
+ offsetof(struct nig_stats, egress_mac_pkt1_lo));
+ dmae->len = (2*sizeof(u32)) >> 2;
+ dmae->comp_addr_lo = U64_LO(bnx2x_sp_mapping(bp, stats_comp));
+ dmae->comp_addr_hi = U64_HI(bnx2x_sp_mapping(bp, stats_comp));
+ dmae->comp_val = DMAE_COMP_VAL;
+
+ *stats_comp = 0;
+}
+
+static void bnx2x_func_stats_init(struct bnx2x *bp)
+{
+ struct dmae_command *dmae = &bp->stats_dmae;
+ u32 *stats_comp = bnx2x_sp(bp, stats_comp);
+
+ /* sanity */
+ if (!bp->func_stx) {
+ BNX2X_ERR("BUG!\n");
+ return;
+ }
+
+ bp->executer_idx = 0;
+ memset(dmae, 0, sizeof(struct dmae_command));
+
+ dmae->opcode = (DMAE_CMD_SRC_PCI | DMAE_CMD_DST_GRC |
+ DMAE_CMD_C_DST_PCI | DMAE_CMD_C_ENABLE |
+ DMAE_CMD_SRC_RESET | DMAE_CMD_DST_RESET |
+#ifdef __BIG_ENDIAN
+ DMAE_CMD_ENDIANITY_B_DW_SWAP |
+#else
+ DMAE_CMD_ENDIANITY_DW_SWAP |
+#endif
+ (BP_PORT(bp) ? DMAE_CMD_PORT_1 : DMAE_CMD_PORT_0) |
+ (BP_E1HVN(bp) << DMAE_CMD_E1HVN_SHIFT));
+ dmae->src_addr_lo = U64_LO(bnx2x_sp_mapping(bp, func_stats));
+ dmae->src_addr_hi = U64_HI(bnx2x_sp_mapping(bp, func_stats));
+ dmae->dst_addr_lo = bp->func_stx >> 2;
+ dmae->dst_addr_hi = 0;
+ dmae->len = sizeof(struct host_func_stats) >> 2;
+ dmae->comp_addr_lo = U64_LO(bnx2x_sp_mapping(bp, stats_comp));
+ dmae->comp_addr_hi = U64_HI(bnx2x_sp_mapping(bp, stats_comp));
+ dmae->comp_val = DMAE_COMP_VAL;
+
+ *stats_comp = 0;
+}
+
+static void bnx2x_stats_start(struct bnx2x *bp)
+{
+ if (bp->port.pmf)
+ bnx2x_port_stats_init(bp);
+
+ else if (bp->func_stx)
+ bnx2x_func_stats_init(bp);
+
+ bnx2x_hw_stats_post(bp);
+ bnx2x_storm_stats_post(bp);
+}
+
+static void bnx2x_stats_pmf_start(struct bnx2x *bp)
+{
+ bnx2x_stats_comp(bp);
+ bnx2x_stats_pmf_update(bp);
+ bnx2x_stats_start(bp);
+}
+
+static void bnx2x_stats_restart(struct bnx2x *bp)
+{
+ bnx2x_stats_comp(bp);
+ bnx2x_stats_start(bp);
+}
+
+static void bnx2x_bmac_stats_update(struct bnx2x *bp)
+{
+ struct bmac_stats *new = bnx2x_sp(bp, mac_stats.bmac_stats);
+ struct host_port_stats *pstats = bnx2x_sp(bp, port_stats);
+ struct bnx2x_eth_stats *estats = &bp->eth_stats;
+ struct {
+ u32 lo;
+ u32 hi;
+ } diff;
+
+ UPDATE_STAT64(rx_stat_grerb, rx_stat_ifhcinbadoctets);
+ UPDATE_STAT64(rx_stat_grfcs, rx_stat_dot3statsfcserrors);
+ UPDATE_STAT64(rx_stat_grund, rx_stat_etherstatsundersizepkts);
+ UPDATE_STAT64(rx_stat_grovr, rx_stat_dot3statsframestoolong);
+ UPDATE_STAT64(rx_stat_grfrg, rx_stat_etherstatsfragments);
+ UPDATE_STAT64(rx_stat_grjbr, rx_stat_etherstatsjabbers);
+ UPDATE_STAT64(rx_stat_grxcf, rx_stat_maccontrolframesreceived);
+ UPDATE_STAT64(rx_stat_grxpf, rx_stat_xoffstateentered);
+ UPDATE_STAT64(rx_stat_grxpf, rx_stat_bmac_xpf);
+ UPDATE_STAT64(tx_stat_gtxpf, tx_stat_outxoffsent);
+ UPDATE_STAT64(tx_stat_gtxpf, tx_stat_flowcontroldone);
+ UPDATE_STAT64(tx_stat_gt64, tx_stat_etherstatspkts64octets);
+ UPDATE_STAT64(tx_stat_gt127,
+ tx_stat_etherstatspkts65octetsto127octets);
+ UPDATE_STAT64(tx_stat_gt255,
+ tx_stat_etherstatspkts128octetsto255octets);
+ UPDATE_STAT64(tx_stat_gt511,
+ tx_stat_etherstatspkts256octetsto511octets);
+ UPDATE_STAT64(tx_stat_gt1023,
+ tx_stat_etherstatspkts512octetsto1023octets);
+ UPDATE_STAT64(tx_stat_gt1518,
+ tx_stat_etherstatspkts1024octetsto1522octets);
+ UPDATE_STAT64(tx_stat_gt2047, tx_stat_bmac_2047);
+ UPDATE_STAT64(tx_stat_gt4095, tx_stat_bmac_4095);
+ UPDATE_STAT64(tx_stat_gt9216, tx_stat_bmac_9216);
+ UPDATE_STAT64(tx_stat_gt16383, tx_stat_bmac_16383);
+ UPDATE_STAT64(tx_stat_gterr,
+ tx_stat_dot3statsinternalmactransmiterrors);
+ UPDATE_STAT64(tx_stat_gtufl, tx_stat_bmac_ufl);
+
+ estats->pause_frames_received_hi =
+ pstats->mac_stx[1].rx_stat_bmac_xpf_hi;
+ estats->pause_frames_received_lo =
+ pstats->mac_stx[1].rx_stat_bmac_xpf_lo;
+
+ estats->pause_frames_sent_hi =
+ pstats->mac_stx[1].tx_stat_outxoffsent_hi;
+ estats->pause_frames_sent_lo =
+ pstats->mac_stx[1].tx_stat_outxoffsent_lo;
+}
+
+static void bnx2x_emac_stats_update(struct bnx2x *bp)
+{
+ struct emac_stats *new = bnx2x_sp(bp, mac_stats.emac_stats);
+ struct host_port_stats *pstats = bnx2x_sp(bp, port_stats);
+ struct bnx2x_eth_stats *estats = &bp->eth_stats;
+
+ UPDATE_EXTEND_STAT(rx_stat_ifhcinbadoctets);
+ UPDATE_EXTEND_STAT(tx_stat_ifhcoutbadoctets);
+ UPDATE_EXTEND_STAT(rx_stat_dot3statsfcserrors);
+ UPDATE_EXTEND_STAT(rx_stat_dot3statsalignmenterrors);
+ UPDATE_EXTEND_STAT(rx_stat_dot3statscarriersenseerrors);
+ UPDATE_EXTEND_STAT(rx_stat_falsecarriererrors);
+ UPDATE_EXTEND_STAT(rx_stat_etherstatsundersizepkts);
+ UPDATE_EXTEND_STAT(rx_stat_dot3statsframestoolong);
+ UPDATE_EXTEND_STAT(rx_stat_etherstatsfragments);
+ UPDATE_EXTEND_STAT(rx_stat_etherstatsjabbers);
+ UPDATE_EXTEND_STAT(rx_stat_maccontrolframesreceived);
+ UPDATE_EXTEND_STAT(rx_stat_xoffstateentered);
+ UPDATE_EXTEND_STAT(rx_stat_xonpauseframesreceived);
+ UPDATE_EXTEND_STAT(rx_stat_xoffpauseframesreceived);
+ UPDATE_EXTEND_STAT(tx_stat_outxonsent);
+ UPDATE_EXTEND_STAT(tx_stat_outxoffsent);
+ UPDATE_EXTEND_STAT(tx_stat_flowcontroldone);
+ UPDATE_EXTEND_STAT(tx_stat_etherstatscollisions);
+ UPDATE_EXTEND_STAT(tx_stat_dot3statssinglecollisionframes);
+ UPDATE_EXTEND_STAT(tx_stat_dot3statsmultiplecollisionframes);
+ UPDATE_EXTEND_STAT(tx_stat_dot3statsdeferredtransmissions);
+ UPDATE_EXTEND_STAT(tx_stat_dot3statsexcessivecollisions);
+ UPDATE_EXTEND_STAT(tx_stat_dot3statslatecollisions);
+ UPDATE_EXTEND_STAT(tx_stat_etherstatspkts64octets);
+ UPDATE_EXTEND_STAT(tx_stat_etherstatspkts65octetsto127octets);
+ UPDATE_EXTEND_STAT(tx_stat_etherstatspkts128octetsto255octets);
+ UPDATE_EXTEND_STAT(tx_stat_etherstatspkts256octetsto511octets);
+ UPDATE_EXTEND_STAT(tx_stat_etherstatspkts512octetsto1023octets);
+ UPDATE_EXTEND_STAT(tx_stat_etherstatspkts1024octetsto1522octets);
+ UPDATE_EXTEND_STAT(tx_stat_etherstatspktsover1522octets);
+ UPDATE_EXTEND_STAT(tx_stat_dot3statsinternalmactransmiterrors);
+
+ estats->pause_frames_received_hi =
+ pstats->mac_stx[1].rx_stat_xonpauseframesreceived_hi;
+ estats->pause_frames_received_lo =
+ pstats->mac_stx[1].rx_stat_xonpauseframesreceived_lo;
+ ADD_64(estats->pause_frames_received_hi,
+ pstats->mac_stx[1].rx_stat_xoffpauseframesreceived_hi,
+ estats->pause_frames_received_lo,
+ pstats->mac_stx[1].rx_stat_xoffpauseframesreceived_lo);
+
+ estats->pause_frames_sent_hi =
+ pstats->mac_stx[1].tx_stat_outxonsent_hi;
+ estats->pause_frames_sent_lo =
+ pstats->mac_stx[1].tx_stat_outxonsent_lo;
+ ADD_64(estats->pause_frames_sent_hi,
+ pstats->mac_stx[1].tx_stat_outxoffsent_hi,
+ estats->pause_frames_sent_lo,
+ pstats->mac_stx[1].tx_stat_outxoffsent_lo);
+}
+
+static int bnx2x_hw_stats_update(struct bnx2x *bp)
+{
+ struct nig_stats *new = bnx2x_sp(bp, nig_stats);
+ struct nig_stats *old = &(bp->port.old_nig_stats);
+ struct host_port_stats *pstats = bnx2x_sp(bp, port_stats);
+ struct bnx2x_eth_stats *estats = &bp->eth_stats;
+ struct {
+ u32 lo;
+ u32 hi;
+ } diff;
+
+ if (bp->link_vars.mac_type == MAC_TYPE_BMAC)
+ bnx2x_bmac_stats_update(bp);
+
+ else if (bp->link_vars.mac_type == MAC_TYPE_EMAC)
+ bnx2x_emac_stats_update(bp);
+
+ else { /* unreached */
+ BNX2X_ERR("stats updated by DMAE but no MAC active\n");
+ return -1;
+ }
+
+ ADD_EXTEND_64(pstats->brb_drop_hi, pstats->brb_drop_lo,
+ new->brb_discard - old->brb_discard);
+ ADD_EXTEND_64(estats->brb_truncate_hi, estats->brb_truncate_lo,
+ new->brb_truncate - old->brb_truncate);
+
+ UPDATE_STAT64_NIG(egress_mac_pkt0,
+ etherstatspkts1024octetsto1522octets);
+ UPDATE_STAT64_NIG(egress_mac_pkt1, etherstatspktsover1522octets);
+
+ memcpy(old, new, sizeof(struct nig_stats));
+
+ memcpy(&(estats->rx_stat_ifhcinbadoctets_hi), &(pstats->mac_stx[1]),
+ sizeof(struct mac_stx));
+ estats->brb_drop_hi = pstats->brb_drop_hi;
+ estats->brb_drop_lo = pstats->brb_drop_lo;
+
+ pstats->host_port_stats_start = ++pstats->host_port_stats_end;
+
+ if (!BP_NOMCP(bp)) {
+ u32 nig_timer_max =
+ SHMEM_RD(bp, port_mb[BP_PORT(bp)].stat_nig_timer);
+ if (nig_timer_max != estats->nig_timer_max) {
+ estats->nig_timer_max = nig_timer_max;
+ BNX2X_ERR("NIG timer max (%u)\n",
+ estats->nig_timer_max);
+ }
+ }
+
+ return 0;
+}
+
+static int bnx2x_storm_stats_update(struct bnx2x *bp)
+{
+ struct eth_stats_query *stats = bnx2x_sp(bp, fw_stats);
+ struct tstorm_per_port_stats *tport =
+ &stats->tstorm_common.port_statistics;
+ struct host_func_stats *fstats = bnx2x_sp(bp, func_stats);
+ struct bnx2x_eth_stats *estats = &bp->eth_stats;
+ int i;
+ u16 cur_stats_counter;
+
+ /* Make sure we use the value of the counter
+ * used for sending the last stats ramrod.
+ */
+ spin_lock_bh(&bp->stats_lock);
+ cur_stats_counter = bp->stats_counter - 1;
+ spin_unlock_bh(&bp->stats_lock);
+
+ memcpy(&(fstats->total_bytes_received_hi),
+ &(bnx2x_sp(bp, func_stats_base)->total_bytes_received_hi),
+ sizeof(struct host_func_stats) - 2*sizeof(u32));
+ estats->error_bytes_received_hi = 0;
+ estats->error_bytes_received_lo = 0;
+ estats->etherstatsoverrsizepkts_hi = 0;
+ estats->etherstatsoverrsizepkts_lo = 0;
+ estats->no_buff_discard_hi = 0;
+ estats->no_buff_discard_lo = 0;
+
+ for_each_queue(bp, i) {
+ struct bnx2x_fastpath *fp = &bp->fp[i];
+ int cl_id = fp->cl_id;
+ struct tstorm_per_client_stats *tclient =
+ &stats->tstorm_common.client_statistics[cl_id];
+ struct tstorm_per_client_stats *old_tclient = &fp->old_tclient;
+ struct ustorm_per_client_stats *uclient =
+ &stats->ustorm_common.client_statistics[cl_id];
+ struct ustorm_per_client_stats *old_uclient = &fp->old_uclient;
+ struct xstorm_per_client_stats *xclient =
+ &stats->xstorm_common.client_statistics[cl_id];
+ struct xstorm_per_client_stats *old_xclient = &fp->old_xclient;
+ struct bnx2x_eth_q_stats *qstats = &fp->eth_q_stats;
+ u32 diff;
+
+ /* are storm stats valid? */
+ if (le16_to_cpu(xclient->stats_counter) != cur_stats_counter) {
+ DP(BNX2X_MSG_STATS, "[%d] stats not updated by xstorm"
+ " xstorm counter (0x%x) != stats_counter (0x%x)\n",
+ i, xclient->stats_counter, cur_stats_counter + 1);
+ return -1;
+ }
+ if (le16_to_cpu(tclient->stats_counter) != cur_stats_counter) {
+ DP(BNX2X_MSG_STATS, "[%d] stats not updated by tstorm"
+ " tstorm counter (0x%x) != stats_counter (0x%x)\n",
+ i, tclient->stats_counter, cur_stats_counter + 1);
+ return -2;
+ }
+ if (le16_to_cpu(uclient->stats_counter) != cur_stats_counter) {
+ DP(BNX2X_MSG_STATS, "[%d] stats not updated by ustorm"
+ " ustorm counter (0x%x) != stats_counter (0x%x)\n",
+ i, uclient->stats_counter, cur_stats_counter + 1);
+ return -4;
+ }
+
+ qstats->total_bytes_received_hi =
+ le32_to_cpu(tclient->rcv_broadcast_bytes.hi);
+ qstats->total_bytes_received_lo =
+ le32_to_cpu(tclient->rcv_broadcast_bytes.lo);
+
+ ADD_64(qstats->total_bytes_received_hi,
+ le32_to_cpu(tclient->rcv_multicast_bytes.hi),
+ qstats->total_bytes_received_lo,
+ le32_to_cpu(tclient->rcv_multicast_bytes.lo));
+
+ ADD_64(qstats->total_bytes_received_hi,
+ le32_to_cpu(tclient->rcv_unicast_bytes.hi),
+ qstats->total_bytes_received_lo,
+ le32_to_cpu(tclient->rcv_unicast_bytes.lo));
+
+ SUB_64(qstats->total_bytes_received_hi,
+ le32_to_cpu(uclient->bcast_no_buff_bytes.hi),
+ qstats->total_bytes_received_lo,
+ le32_to_cpu(uclient->bcast_no_buff_bytes.lo));
+
+ SUB_64(qstats->total_bytes_received_hi,
+ le32_to_cpu(uclient->mcast_no_buff_bytes.hi),
+ qstats->total_bytes_received_lo,
+ le32_to_cpu(uclient->mcast_no_buff_bytes.lo));
+
+ SUB_64(qstats->total_bytes_received_hi,
+ le32_to_cpu(uclient->ucast_no_buff_bytes.hi),
+ qstats->total_bytes_received_lo,
+ le32_to_cpu(uclient->ucast_no_buff_bytes.lo));
+
+ qstats->valid_bytes_received_hi =
+ qstats->total_bytes_received_hi;
+ qstats->valid_bytes_received_lo =
+ qstats->total_bytes_received_lo;
+
+ qstats->error_bytes_received_hi =
+ le32_to_cpu(tclient->rcv_error_bytes.hi);
+ qstats->error_bytes_received_lo =
+ le32_to_cpu(tclient->rcv_error_bytes.lo);
+
+ ADD_64(qstats->total_bytes_received_hi,
+ qstats->error_bytes_received_hi,
+ qstats->total_bytes_received_lo,
+ qstats->error_bytes_received_lo);
+
+ UPDATE_EXTEND_TSTAT(rcv_unicast_pkts,
+ total_unicast_packets_received);
+ UPDATE_EXTEND_TSTAT(rcv_multicast_pkts,
+ total_multicast_packets_received);
+ UPDATE_EXTEND_TSTAT(rcv_broadcast_pkts,
+ total_broadcast_packets_received);
+ UPDATE_EXTEND_TSTAT(packets_too_big_discard,
+ etherstatsoverrsizepkts);
+ UPDATE_EXTEND_TSTAT(no_buff_discard, no_buff_discard);
+
+ SUB_EXTEND_USTAT(ucast_no_buff_pkts,
+ total_unicast_packets_received);
+ SUB_EXTEND_USTAT(mcast_no_buff_pkts,
+ total_multicast_packets_received);
+ SUB_EXTEND_USTAT(bcast_no_buff_pkts,
+ total_broadcast_packets_received);
+ UPDATE_EXTEND_USTAT(ucast_no_buff_pkts, no_buff_discard);
+ UPDATE_EXTEND_USTAT(mcast_no_buff_pkts, no_buff_discard);
+ UPDATE_EXTEND_USTAT(bcast_no_buff_pkts, no_buff_discard);
+
+ qstats->total_bytes_transmitted_hi =
+ le32_to_cpu(xclient->unicast_bytes_sent.hi);
+ qstats->total_bytes_transmitted_lo =
+ le32_to_cpu(xclient->unicast_bytes_sent.lo);
+
+ ADD_64(qstats->total_bytes_transmitted_hi,
+ le32_to_cpu(xclient->multicast_bytes_sent.hi),
+ qstats->total_bytes_transmitted_lo,
+ le32_to_cpu(xclient->multicast_bytes_sent.lo));
+
+ ADD_64(qstats->total_bytes_transmitted_hi,
+ le32_to_cpu(xclient->broadcast_bytes_sent.hi),
+ qstats->total_bytes_transmitted_lo,
+ le32_to_cpu(xclient->broadcast_bytes_sent.lo));
+
+ UPDATE_EXTEND_XSTAT(unicast_pkts_sent,
+ total_unicast_packets_transmitted);
+ UPDATE_EXTEND_XSTAT(multicast_pkts_sent,
+ total_multicast_packets_transmitted);
+ UPDATE_EXTEND_XSTAT(broadcast_pkts_sent,
+ total_broadcast_packets_transmitted);
+
+ old_tclient->checksum_discard = tclient->checksum_discard;
+ old_tclient->ttl0_discard = tclient->ttl0_discard;
+
+ ADD_64(fstats->total_bytes_received_hi,
+ qstats->total_bytes_received_hi,
+ fstats->total_bytes_received_lo,
+ qstats->total_bytes_received_lo);
+ ADD_64(fstats->total_bytes_transmitted_hi,
+ qstats->total_bytes_transmitted_hi,
+ fstats->total_bytes_transmitted_lo,
+ qstats->total_bytes_transmitted_lo);
+ ADD_64(fstats->total_unicast_packets_received_hi,
+ qstats->total_unicast_packets_received_hi,
+ fstats->total_unicast_packets_received_lo,
+ qstats->total_unicast_packets_received_lo);
+ ADD_64(fstats->total_multicast_packets_received_hi,
+ qstats->total_multicast_packets_received_hi,
+ fstats->total_multicast_packets_received_lo,
+ qstats->total_multicast_packets_received_lo);
+ ADD_64(fstats->total_broadcast_packets_received_hi,
+ qstats->total_broadcast_packets_received_hi,
+ fstats->total_broadcast_packets_received_lo,
+ qstats->total_broadcast_packets_received_lo);
+ ADD_64(fstats->total_unicast_packets_transmitted_hi,
+ qstats->total_unicast_packets_transmitted_hi,
+ fstats->total_unicast_packets_transmitted_lo,
+ qstats->total_unicast_packets_transmitted_lo);
+ ADD_64(fstats->total_multicast_packets_transmitted_hi,
+ qstats->total_multicast_packets_transmitted_hi,
+ fstats->total_multicast_packets_transmitted_lo,
+ qstats->total_multicast_packets_transmitted_lo);
+ ADD_64(fstats->total_broadcast_packets_transmitted_hi,
+ qstats->total_broadcast_packets_transmitted_hi,
+ fstats->total_broadcast_packets_transmitted_lo,
+ qstats->total_broadcast_packets_transmitted_lo);
+ ADD_64(fstats->valid_bytes_received_hi,
+ qstats->valid_bytes_received_hi,
+ fstats->valid_bytes_received_lo,
+ qstats->valid_bytes_received_lo);
+
+ ADD_64(estats->error_bytes_received_hi,
+ qstats->error_bytes_received_hi,
+ estats->error_bytes_received_lo,
+ qstats->error_bytes_received_lo);
+ ADD_64(estats->etherstatsoverrsizepkts_hi,
+ qstats->etherstatsoverrsizepkts_hi,
+ estats->etherstatsoverrsizepkts_lo,
+ qstats->etherstatsoverrsizepkts_lo);
+ ADD_64(estats->no_buff_discard_hi, qstats->no_buff_discard_hi,
+ estats->no_buff_discard_lo, qstats->no_buff_discard_lo);
+ }
+
+ ADD_64(fstats->total_bytes_received_hi,
+ estats->rx_stat_ifhcinbadoctets_hi,
+ fstats->total_bytes_received_lo,
+ estats->rx_stat_ifhcinbadoctets_lo);
+
+ memcpy(estats, &(fstats->total_bytes_received_hi),
+ sizeof(struct host_func_stats) - 2*sizeof(u32));
+
+ ADD_64(estats->etherstatsoverrsizepkts_hi,
+ estats->rx_stat_dot3statsframestoolong_hi,
+ estats->etherstatsoverrsizepkts_lo,
+ estats->rx_stat_dot3statsframestoolong_lo);
+ ADD_64(estats->error_bytes_received_hi,
+ estats->rx_stat_ifhcinbadoctets_hi,
+ estats->error_bytes_received_lo,
+ estats->rx_stat_ifhcinbadoctets_lo);
+
+ if (bp->port.pmf) {
+ estats->mac_filter_discard =
+ le32_to_cpu(tport->mac_filter_discard);
+ estats->xxoverflow_discard =
+ le32_to_cpu(tport->xxoverflow_discard);
+ estats->brb_truncate_discard =
+ le32_to_cpu(tport->brb_truncate_discard);
+ estats->mac_discard = le32_to_cpu(tport->mac_discard);
+ }
+
+ fstats->host_func_stats_start = ++fstats->host_func_stats_end;
+
+ bp->stats_pending = 0;
+
+ return 0;
+}
+
+static void bnx2x_net_stats_update(struct bnx2x *bp)
+{
+ struct bnx2x_eth_stats *estats = &bp->eth_stats;
+ struct net_device_stats *nstats = &bp->dev->stats;
+ int i;
+
+ nstats->rx_packets =
+ bnx2x_hilo(&estats->total_unicast_packets_received_hi) +
+ bnx2x_hilo(&estats->total_multicast_packets_received_hi) +
+ bnx2x_hilo(&estats->total_broadcast_packets_received_hi);
+
+ nstats->tx_packets =
+ bnx2x_hilo(&estats->total_unicast_packets_transmitted_hi) +
+ bnx2x_hilo(&estats->total_multicast_packets_transmitted_hi) +
+ bnx2x_hilo(&estats->total_broadcast_packets_transmitted_hi);
+
+ nstats->rx_bytes = bnx2x_hilo(&estats->total_bytes_received_hi);
+
+ nstats->tx_bytes = bnx2x_hilo(&estats->total_bytes_transmitted_hi);
+
+ nstats->rx_dropped = estats->mac_discard;
+ for_each_queue(bp, i)
+ nstats->rx_dropped +=
+ le32_to_cpu(bp->fp[i].old_tclient.checksum_discard);
+
+ nstats->tx_dropped = 0;
+
+ nstats->multicast =
+ bnx2x_hilo(&estats->total_multicast_packets_received_hi);
+
+ nstats->collisions =
+ bnx2x_hilo(&estats->tx_stat_etherstatscollisions_hi);
+
+ nstats->rx_length_errors =
+ bnx2x_hilo(&estats->rx_stat_etherstatsundersizepkts_hi) +
+ bnx2x_hilo(&estats->etherstatsoverrsizepkts_hi);
+ nstats->rx_over_errors = bnx2x_hilo(&estats->brb_drop_hi) +
+ bnx2x_hilo(&estats->brb_truncate_hi);
+ nstats->rx_crc_errors =
+ bnx2x_hilo(&estats->rx_stat_dot3statsfcserrors_hi);
+ nstats->rx_frame_errors =
+ bnx2x_hilo(&estats->rx_stat_dot3statsalignmenterrors_hi);
+ nstats->rx_fifo_errors = bnx2x_hilo(&estats->no_buff_discard_hi);
+ nstats->rx_missed_errors = estats->xxoverflow_discard;
+
+ nstats->rx_errors = nstats->rx_length_errors +
+ nstats->rx_over_errors +
+ nstats->rx_crc_errors +
+ nstats->rx_frame_errors +
+ nstats->rx_fifo_errors +
+ nstats->rx_missed_errors;
+
+ nstats->tx_aborted_errors =
+ bnx2x_hilo(&estats->tx_stat_dot3statslatecollisions_hi) +
+ bnx2x_hilo(&estats->tx_stat_dot3statsexcessivecollisions_hi);
+ nstats->tx_carrier_errors =
+ bnx2x_hilo(&estats->rx_stat_dot3statscarriersenseerrors_hi);
+ nstats->tx_fifo_errors = 0;
+ nstats->tx_heartbeat_errors = 0;
+ nstats->tx_window_errors = 0;
+
+ nstats->tx_errors = nstats->tx_aborted_errors +
+ nstats->tx_carrier_errors +
+ bnx2x_hilo(&estats->tx_stat_dot3statsinternalmactransmiterrors_hi);
+}
+
+static void bnx2x_drv_stats_update(struct bnx2x *bp)
+{
+ struct bnx2x_eth_stats *estats = &bp->eth_stats;
+ int i;
+
+ estats->driver_xoff = 0;
+ estats->rx_err_discard_pkt = 0;
+ estats->rx_skb_alloc_failed = 0;
+ estats->hw_csum_err = 0;
+ for_each_queue(bp, i) {
+ struct bnx2x_eth_q_stats *qstats = &bp->fp[i].eth_q_stats;
+
+ estats->driver_xoff += qstats->driver_xoff;
+ estats->rx_err_discard_pkt += qstats->rx_err_discard_pkt;
+ estats->rx_skb_alloc_failed += qstats->rx_skb_alloc_failed;
+ estats->hw_csum_err += qstats->hw_csum_err;
+ }
+}
+
+static void bnx2x_stats_update(struct bnx2x *bp)
+{
+ u32 *stats_comp = bnx2x_sp(bp, stats_comp);
+
+ if (*stats_comp != DMAE_COMP_VAL)
+ return;
+
+ if (bp->port.pmf)
+ bnx2x_hw_stats_update(bp);
+
+ if (bnx2x_storm_stats_update(bp) && (bp->stats_pending++ == 3)) {
+ BNX2X_ERR("storm stats were not updated for 3 times\n");
+ bnx2x_panic();
+ return;
+ }
+
+ bnx2x_net_stats_update(bp);
+ bnx2x_drv_stats_update(bp);
+
+ if (netif_msg_timer(bp)) {
+ struct bnx2x_eth_stats *estats = &bp->eth_stats;
+ int i;
+
+ printk(KERN_DEBUG "%s: brb drops %u brb truncate %u\n",
+ bp->dev->name,
+ estats->brb_drop_lo, estats->brb_truncate_lo);
+
+ for_each_queue(bp, i) {
+ struct bnx2x_fastpath *fp = &bp->fp[i];
+ struct bnx2x_eth_q_stats *qstats = &fp->eth_q_stats;
+
+ printk(KERN_DEBUG "%s: rx usage(%4u) *rx_cons_sb(%u)"
+ " rx pkt(%lu) rx calls(%lu %lu)\n",
+ fp->name, (le16_to_cpu(*fp->rx_cons_sb) -
+ fp->rx_comp_cons),
+ le16_to_cpu(*fp->rx_cons_sb),
+ bnx2x_hilo(&qstats->
+ total_unicast_packets_received_hi),
+ fp->rx_calls, fp->rx_pkt);
+ }
+
+ for_each_queue(bp, i) {
+ struct bnx2x_fastpath *fp = &bp->fp[i];
+ struct bnx2x_eth_q_stats *qstats = &fp->eth_q_stats;
+ struct netdev_queue *txq =
+ netdev_get_tx_queue(bp->dev, i);
+
+ printk(KERN_DEBUG "%s: tx avail(%4u) *tx_cons_sb(%u)"
+ " tx pkt(%lu) tx calls (%lu)"
+ " %s (Xoff events %u)\n",
+ fp->name, bnx2x_tx_avail(fp),
+ le16_to_cpu(*fp->tx_cons_sb),
+ bnx2x_hilo(&qstats->
+ total_unicast_packets_transmitted_hi),
+ fp->tx_pkt,
+ (netif_tx_queue_stopped(txq) ? "Xoff" : "Xon"),
+ qstats->driver_xoff);
+ }
+ }
+
+ bnx2x_hw_stats_post(bp);
+ bnx2x_storm_stats_post(bp);
+}
+
+static void bnx2x_port_stats_stop(struct bnx2x *bp)
+{
+ struct dmae_command *dmae;
+ u32 opcode;
+ int loader_idx = PMF_DMAE_C(bp);
+ u32 *stats_comp = bnx2x_sp(bp, stats_comp);
+
+ bp->executer_idx = 0;
+
+ opcode = (DMAE_CMD_SRC_PCI | DMAE_CMD_DST_GRC |
+ DMAE_CMD_C_ENABLE |
+ DMAE_CMD_SRC_RESET | DMAE_CMD_DST_RESET |
+#ifdef __BIG_ENDIAN
+ DMAE_CMD_ENDIANITY_B_DW_SWAP |
+#else
+ DMAE_CMD_ENDIANITY_DW_SWAP |
+#endif
+ (BP_PORT(bp) ? DMAE_CMD_PORT_1 : DMAE_CMD_PORT_0) |
+ (BP_E1HVN(bp) << DMAE_CMD_E1HVN_SHIFT));
+
+ if (bp->port.port_stx) {
+
+ dmae = bnx2x_sp(bp, dmae[bp->executer_idx++]);
+ if (bp->func_stx)
+ dmae->opcode = (opcode | DMAE_CMD_C_DST_GRC);
+ else
+ dmae->opcode = (opcode | DMAE_CMD_C_DST_PCI);
+ dmae->src_addr_lo = U64_LO(bnx2x_sp_mapping(bp, port_stats));
+ dmae->src_addr_hi = U64_HI(bnx2x_sp_mapping(bp, port_stats));
+ dmae->dst_addr_lo = bp->port.port_stx >> 2;
+ dmae->dst_addr_hi = 0;
+ dmae->len = sizeof(struct host_port_stats) >> 2;
+ if (bp->func_stx) {
+ dmae->comp_addr_lo = dmae_reg_go_c[loader_idx] >> 2;
+ dmae->comp_addr_hi = 0;
+ dmae->comp_val = 1;
+ } else {
+ dmae->comp_addr_lo =
+ U64_LO(bnx2x_sp_mapping(bp, stats_comp));
+ dmae->comp_addr_hi =
+ U64_HI(bnx2x_sp_mapping(bp, stats_comp));
+ dmae->comp_val = DMAE_COMP_VAL;
+
+ *stats_comp = 0;
+ }
+ }
+
+ if (bp->func_stx) {
+
+ dmae = bnx2x_sp(bp, dmae[bp->executer_idx++]);
+ dmae->opcode = (opcode | DMAE_CMD_C_DST_PCI);
+ dmae->src_addr_lo = U64_LO(bnx2x_sp_mapping(bp, func_stats));
+ dmae->src_addr_hi = U64_HI(bnx2x_sp_mapping(bp, func_stats));
+ dmae->dst_addr_lo = bp->func_stx >> 2;
+ dmae->dst_addr_hi = 0;
+ dmae->len = sizeof(struct host_func_stats) >> 2;
+ dmae->comp_addr_lo = U64_LO(bnx2x_sp_mapping(bp, stats_comp));
+ dmae->comp_addr_hi = U64_HI(bnx2x_sp_mapping(bp, stats_comp));
+ dmae->comp_val = DMAE_COMP_VAL;
+
+ *stats_comp = 0;
+ }
+}
+
+static void bnx2x_stats_stop(struct bnx2x *bp)
+{
+ int update = 0;
+
+ bnx2x_stats_comp(bp);
+
+ if (bp->port.pmf)
+ update = (bnx2x_hw_stats_update(bp) == 0);
+
+ update |= (bnx2x_storm_stats_update(bp) == 0);
+
+ if (update) {
+ bnx2x_net_stats_update(bp);
+
+ if (bp->port.pmf)
+ bnx2x_port_stats_stop(bp);
+
+ bnx2x_hw_stats_post(bp);
+ bnx2x_stats_comp(bp);
+ }
+}
+
+static void bnx2x_stats_do_nothing(struct bnx2x *bp)
+{
+}
+
+static const struct {
+ void (*action)(struct bnx2x *bp);
+ enum bnx2x_stats_state next_state;
+} bnx2x_stats_stm[STATS_STATE_MAX][STATS_EVENT_MAX] = {
+/* state event */
+{
+/* DISABLED PMF */ {bnx2x_stats_pmf_update, STATS_STATE_DISABLED},
+/* LINK_UP */ {bnx2x_stats_start, STATS_STATE_ENABLED},
+/* UPDATE */ {bnx2x_stats_do_nothing, STATS_STATE_DISABLED},
+/* STOP */ {bnx2x_stats_do_nothing, STATS_STATE_DISABLED}
+},
+{
+/* ENABLED PMF */ {bnx2x_stats_pmf_start, STATS_STATE_ENABLED},
+/* LINK_UP */ {bnx2x_stats_restart, STATS_STATE_ENABLED},
+/* UPDATE */ {bnx2x_stats_update, STATS_STATE_ENABLED},
+/* STOP */ {bnx2x_stats_stop, STATS_STATE_DISABLED}
+}
+};
+
+void bnx2x_stats_handle(struct bnx2x *bp, enum bnx2x_stats_event event)
+{
+ enum bnx2x_stats_state state;
+
+ if (unlikely(bp->panic))
+ return;
+
+ /* Protect a state change flow */
+ spin_lock_bh(&bp->stats_lock);
+ state = bp->stats_state;
+ bp->stats_state = bnx2x_stats_stm[state][event].next_state;
+ spin_unlock_bh(&bp->stats_lock);
+
+ bnx2x_stats_stm[state][event].action(bp);
+
+ if ((event != STATS_EVENT_UPDATE) || netif_msg_timer(bp))
+ DP(BNX2X_MSG_STATS, "state %d -> event %d -> state %d\n",
+ state, event, bp->stats_state);
+}
+
+static void bnx2x_port_stats_base_init(struct bnx2x *bp)
+{
+ struct dmae_command *dmae;
+ u32 *stats_comp = bnx2x_sp(bp, stats_comp);
+
+ /* sanity */
+ if (!bp->port.pmf || !bp->port.port_stx) {
+ BNX2X_ERR("BUG!\n");
+ return;
+ }
+
+ bp->executer_idx = 0;
+
+ dmae = bnx2x_sp(bp, dmae[bp->executer_idx++]);
+ dmae->opcode = (DMAE_CMD_SRC_PCI | DMAE_CMD_DST_GRC |
+ DMAE_CMD_C_DST_PCI | DMAE_CMD_C_ENABLE |
+ DMAE_CMD_SRC_RESET | DMAE_CMD_DST_RESET |
+#ifdef __BIG_ENDIAN
+ DMAE_CMD_ENDIANITY_B_DW_SWAP |
+#else
+ DMAE_CMD_ENDIANITY_DW_SWAP |
+#endif
+ (BP_PORT(bp) ? DMAE_CMD_PORT_1 : DMAE_CMD_PORT_0) |
+ (BP_E1HVN(bp) << DMAE_CMD_E1HVN_SHIFT));
+ dmae->src_addr_lo = U64_LO(bnx2x_sp_mapping(bp, port_stats));
+ dmae->src_addr_hi = U64_HI(bnx2x_sp_mapping(bp, port_stats));
+ dmae->dst_addr_lo = bp->port.port_stx >> 2;
+ dmae->dst_addr_hi = 0;
+ dmae->len = sizeof(struct host_port_stats) >> 2;
+ dmae->comp_addr_lo = U64_LO(bnx2x_sp_mapping(bp, stats_comp));
+ dmae->comp_addr_hi = U64_HI(bnx2x_sp_mapping(bp, stats_comp));
+ dmae->comp_val = DMAE_COMP_VAL;
+
+ *stats_comp = 0;
+ bnx2x_hw_stats_post(bp);
+ bnx2x_stats_comp(bp);
+}
+
+static void bnx2x_func_stats_base_init(struct bnx2x *bp)
+{
+ int vn, vn_max = IS_E1HMF(bp) ? E1HVN_MAX : E1VN_MAX;
+ int port = BP_PORT(bp);
+ int func;
+ u32 func_stx;
+
+ /* sanity */
+ if (!bp->port.pmf || !bp->func_stx) {
+ BNX2X_ERR("BUG!\n");
+ return;
+ }
+
+ /* save our func_stx */
+ func_stx = bp->func_stx;
+
+ for (vn = VN_0; vn < vn_max; vn++) {
+ func = 2*vn + port;
+
+ bp->func_stx = SHMEM_RD(bp, func_mb[func].fw_mb_param);
+ bnx2x_func_stats_init(bp);
+ bnx2x_hw_stats_post(bp);
+ bnx2x_stats_comp(bp);
+ }
+
+ /* restore our func_stx */
+ bp->func_stx = func_stx;
+}
+
+static void bnx2x_func_stats_base_update(struct bnx2x *bp)
+{
+ struct dmae_command *dmae = &bp->stats_dmae;
+ u32 *stats_comp = bnx2x_sp(bp, stats_comp);
+
+ /* sanity */
+ if (!bp->func_stx) {
+ BNX2X_ERR("BUG!\n");
+ return;
+ }
+
+ bp->executer_idx = 0;
+ memset(dmae, 0, sizeof(struct dmae_command));
+
+ dmae->opcode = (DMAE_CMD_SRC_GRC | DMAE_CMD_DST_PCI |
+ DMAE_CMD_C_DST_PCI | DMAE_CMD_C_ENABLE |
+ DMAE_CMD_SRC_RESET | DMAE_CMD_DST_RESET |
+#ifdef __BIG_ENDIAN
+ DMAE_CMD_ENDIANITY_B_DW_SWAP |
+#else
+ DMAE_CMD_ENDIANITY_DW_SWAP |
+#endif
+ (BP_PORT(bp) ? DMAE_CMD_PORT_1 : DMAE_CMD_PORT_0) |
+ (BP_E1HVN(bp) << DMAE_CMD_E1HVN_SHIFT));
+ dmae->src_addr_lo = bp->func_stx >> 2;
+ dmae->src_addr_hi = 0;
+ dmae->dst_addr_lo = U64_LO(bnx2x_sp_mapping(bp, func_stats_base));
+ dmae->dst_addr_hi = U64_HI(bnx2x_sp_mapping(bp, func_stats_base));
+ dmae->len = sizeof(struct host_func_stats) >> 2;
+ dmae->comp_addr_lo = U64_LO(bnx2x_sp_mapping(bp, stats_comp));
+ dmae->comp_addr_hi = U64_HI(bnx2x_sp_mapping(bp, stats_comp));
+ dmae->comp_val = DMAE_COMP_VAL;
+
+ *stats_comp = 0;
+ bnx2x_hw_stats_post(bp);
+ bnx2x_stats_comp(bp);
+}
+
+void bnx2x_stats_init(struct bnx2x *bp)
+{
+ int port = BP_PORT(bp);
+ int func = BP_FUNC(bp);
+ int i;
+
+ bp->stats_pending = 0;
+ bp->executer_idx = 0;
+ bp->stats_counter = 0;
+
+ /* port and func stats for management */
+ if (!BP_NOMCP(bp)) {
+ bp->port.port_stx = SHMEM_RD(bp, port_mb[port].port_stx);
+ bp->func_stx = SHMEM_RD(bp, func_mb[func].fw_mb_param);
+
+ } else {
+ bp->port.port_stx = 0;
+ bp->func_stx = 0;
+ }
+ DP(BNX2X_MSG_STATS, "port_stx 0x%x func_stx 0x%x\n",
+ bp->port.port_stx, bp->func_stx);
+
+ /* port stats */
+ memset(&(bp->port.old_nig_stats), 0, sizeof(struct nig_stats));
+ bp->port.old_nig_stats.brb_discard =
+ REG_RD(bp, NIG_REG_STAT0_BRB_DISCARD + port*0x38);
+ bp->port.old_nig_stats.brb_truncate =
+ REG_RD(bp, NIG_REG_STAT0_BRB_TRUNCATE + port*0x38);
+ REG_RD_DMAE(bp, NIG_REG_STAT0_EGRESS_MAC_PKT0 + port*0x50,
+ &(bp->port.old_nig_stats.egress_mac_pkt0_lo), 2);
+ REG_RD_DMAE(bp, NIG_REG_STAT0_EGRESS_MAC_PKT1 + port*0x50,
+ &(bp->port.old_nig_stats.egress_mac_pkt1_lo), 2);
+
+ /* function stats */
+ for_each_queue(bp, i) {
+ struct bnx2x_fastpath *fp = &bp->fp[i];
+
+ memset(&fp->old_tclient, 0,
+ sizeof(struct tstorm_per_client_stats));
+ memset(&fp->old_uclient, 0,
+ sizeof(struct ustorm_per_client_stats));
+ memset(&fp->old_xclient, 0,
+ sizeof(struct xstorm_per_client_stats));
+ memset(&fp->eth_q_stats, 0, sizeof(struct bnx2x_eth_q_stats));
+ }
+
+ memset(&bp->dev->stats, 0, sizeof(struct net_device_stats));
+ memset(&bp->eth_stats, 0, sizeof(struct bnx2x_eth_stats));
+
+ bp->stats_state = STATS_STATE_DISABLED;
+
+ if (bp->port.pmf) {
+ if (bp->port.port_stx)
+ bnx2x_port_stats_base_init(bp);
+
+ if (bp->func_stx)
+ bnx2x_func_stats_base_init(bp);
+
+ } else if (bp->func_stx)
+ bnx2x_func_stats_base_update(bp);
+}
diff --git a/drivers/net/bnx2x/bnx2x_stats.h b/drivers/net/bnx2x/bnx2x_stats.h
new file mode 100644
index 00000000000..38a4e908f4f
--- /dev/null
+++ b/drivers/net/bnx2x/bnx2x_stats.h
@@ -0,0 +1,239 @@
+/* bnx2x_stats.h: Broadcom Everest network driver.
+ *
+ * Copyright (c) 2007-2010 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.
+ *
+ * Maintained by: Eilon Greenstein <eilong@broadcom.com>
+ * Written by: Eliezer Tamir
+ * Based on code from Michael Chan's bnx2 driver
+ */
+
+#ifndef BNX2X_STATS_H
+#define BNX2X_STATS_H
+
+#include <linux/types.h>
+
+struct bnx2x_eth_q_stats {
+ u32 total_bytes_received_hi;
+ u32 total_bytes_received_lo;
+ u32 total_bytes_transmitted_hi;
+ u32 total_bytes_transmitted_lo;
+ u32 total_unicast_packets_received_hi;
+ u32 total_unicast_packets_received_lo;
+ u32 total_multicast_packets_received_hi;
+ u32 total_multicast_packets_received_lo;
+ u32 total_broadcast_packets_received_hi;
+ u32 total_broadcast_packets_received_lo;
+ u32 total_unicast_packets_transmitted_hi;
+ u32 total_unicast_packets_transmitted_lo;
+ u32 total_multicast_packets_transmitted_hi;
+ u32 total_multicast_packets_transmitted_lo;
+ u32 total_broadcast_packets_transmitted_hi;
+ u32 total_broadcast_packets_transmitted_lo;
+ u32 valid_bytes_received_hi;
+ u32 valid_bytes_received_lo;
+
+ u32 error_bytes_received_hi;
+ u32 error_bytes_received_lo;
+ u32 etherstatsoverrsizepkts_hi;
+ u32 etherstatsoverrsizepkts_lo;
+ u32 no_buff_discard_hi;
+ u32 no_buff_discard_lo;
+
+ u32 driver_xoff;
+ u32 rx_err_discard_pkt;
+ u32 rx_skb_alloc_failed;
+ u32 hw_csum_err;
+};
+
+#define BNX2X_NUM_Q_STATS 13
+#define Q_STATS_OFFSET32(stat_name) \
+ (offsetof(struct bnx2x_eth_q_stats, stat_name) / 4)
+
+struct nig_stats {
+ u32 brb_discard;
+ u32 brb_packet;
+ u32 brb_truncate;
+ u32 flow_ctrl_discard;
+ u32 flow_ctrl_octets;
+ u32 flow_ctrl_packet;
+ u32 mng_discard;
+ u32 mng_octet_inp;
+ u32 mng_octet_out;
+ u32 mng_packet_inp;
+ u32 mng_packet_out;
+ u32 pbf_octets;
+ u32 pbf_packet;
+ u32 safc_inp;
+ u32 egress_mac_pkt0_lo;
+ u32 egress_mac_pkt0_hi;
+ u32 egress_mac_pkt1_lo;
+ u32 egress_mac_pkt1_hi;
+};
+
+
+enum bnx2x_stats_event {
+ STATS_EVENT_PMF = 0,
+ STATS_EVENT_LINK_UP,
+ STATS_EVENT_UPDATE,
+ STATS_EVENT_STOP,
+ STATS_EVENT_MAX
+};
+
+enum bnx2x_stats_state {
+ STATS_STATE_DISABLED = 0,
+ STATS_STATE_ENABLED,
+ STATS_STATE_MAX
+};
+
+struct bnx2x_eth_stats {
+ u32 total_bytes_received_hi;
+ u32 total_bytes_received_lo;
+ u32 total_bytes_transmitted_hi;
+ u32 total_bytes_transmitted_lo;
+ u32 total_unicast_packets_received_hi;
+ u32 total_unicast_packets_received_lo;
+ u32 total_multicast_packets_received_hi;
+ u32 total_multicast_packets_received_lo;
+ u32 total_broadcast_packets_received_hi;
+ u32 total_broadcast_packets_received_lo;
+ u32 total_unicast_packets_transmitted_hi;
+ u32 total_unicast_packets_transmitted_lo;
+ u32 total_multicast_packets_transmitted_hi;
+ u32 total_multicast_packets_transmitted_lo;
+ u32 total_broadcast_packets_transmitted_hi;
+ u32 total_broadcast_packets_transmitted_lo;
+ u32 valid_bytes_received_hi;
+ u32 valid_bytes_received_lo;
+
+ u32 error_bytes_received_hi;
+ u32 error_bytes_received_lo;
+ u32 etherstatsoverrsizepkts_hi;
+ u32 etherstatsoverrsizepkts_lo;
+ u32 no_buff_discard_hi;
+ u32 no_buff_discard_lo;
+
+ u32 rx_stat_ifhcinbadoctets_hi;
+ u32 rx_stat_ifhcinbadoctets_lo;
+ u32 tx_stat_ifhcoutbadoctets_hi;
+ u32 tx_stat_ifhcoutbadoctets_lo;
+ u32 rx_stat_dot3statsfcserrors_hi;
+ u32 rx_stat_dot3statsfcserrors_lo;
+ u32 rx_stat_dot3statsalignmenterrors_hi;
+ u32 rx_stat_dot3statsalignmenterrors_lo;
+ u32 rx_stat_dot3statscarriersenseerrors_hi;
+ u32 rx_stat_dot3statscarriersenseerrors_lo;
+ u32 rx_stat_falsecarriererrors_hi;
+ u32 rx_stat_falsecarriererrors_lo;
+ u32 rx_stat_etherstatsundersizepkts_hi;
+ u32 rx_stat_etherstatsundersizepkts_lo;
+ u32 rx_stat_dot3statsframestoolong_hi;
+ u32 rx_stat_dot3statsframestoolong_lo;
+ u32 rx_stat_etherstatsfragments_hi;
+ u32 rx_stat_etherstatsfragments_lo;
+ u32 rx_stat_etherstatsjabbers_hi;
+ u32 rx_stat_etherstatsjabbers_lo;
+ u32 rx_stat_maccontrolframesreceived_hi;
+ u32 rx_stat_maccontrolframesreceived_lo;
+ u32 rx_stat_bmac_xpf_hi;
+ u32 rx_stat_bmac_xpf_lo;
+ u32 rx_stat_bmac_xcf_hi;
+ u32 rx_stat_bmac_xcf_lo;
+ u32 rx_stat_xoffstateentered_hi;
+ u32 rx_stat_xoffstateentered_lo;
+ u32 rx_stat_xonpauseframesreceived_hi;
+ u32 rx_stat_xonpauseframesreceived_lo;
+ u32 rx_stat_xoffpauseframesreceived_hi;
+ u32 rx_stat_xoffpauseframesreceived_lo;
+ u32 tx_stat_outxonsent_hi;
+ u32 tx_stat_outxonsent_lo;
+ u32 tx_stat_outxoffsent_hi;
+ u32 tx_stat_outxoffsent_lo;
+ u32 tx_stat_flowcontroldone_hi;
+ u32 tx_stat_flowcontroldone_lo;
+ u32 tx_stat_etherstatscollisions_hi;
+ u32 tx_stat_etherstatscollisions_lo;
+ u32 tx_stat_dot3statssinglecollisionframes_hi;
+ u32 tx_stat_dot3statssinglecollisionframes_lo;
+ u32 tx_stat_dot3statsmultiplecollisionframes_hi;
+ u32 tx_stat_dot3statsmultiplecollisionframes_lo;
+ u32 tx_stat_dot3statsdeferredtransmissions_hi;
+ u32 tx_stat_dot3statsdeferredtransmissions_lo;
+ u32 tx_stat_dot3statsexcessivecollisions_hi;
+ u32 tx_stat_dot3statsexcessivecollisions_lo;
+ u32 tx_stat_dot3statslatecollisions_hi;
+ u32 tx_stat_dot3statslatecollisions_lo;
+ u32 tx_stat_etherstatspkts64octets_hi;
+ u32 tx_stat_etherstatspkts64octets_lo;
+ u32 tx_stat_etherstatspkts65octetsto127octets_hi;
+ u32 tx_stat_etherstatspkts65octetsto127octets_lo;
+ u32 tx_stat_etherstatspkts128octetsto255octets_hi;
+ u32 tx_stat_etherstatspkts128octetsto255octets_lo;
+ u32 tx_stat_etherstatspkts256octetsto511octets_hi;
+ u32 tx_stat_etherstatspkts256octetsto511octets_lo;
+ u32 tx_stat_etherstatspkts512octetsto1023octets_hi;
+ u32 tx_stat_etherstatspkts512octetsto1023octets_lo;
+ u32 tx_stat_etherstatspkts1024octetsto1522octets_hi;
+ u32 tx_stat_etherstatspkts1024octetsto1522octets_lo;
+ u32 tx_stat_etherstatspktsover1522octets_hi;
+ u32 tx_stat_etherstatspktsover1522octets_lo;
+ u32 tx_stat_bmac_2047_hi;
+ u32 tx_stat_bmac_2047_lo;
+ u32 tx_stat_bmac_4095_hi;
+ u32 tx_stat_bmac_4095_lo;
+ u32 tx_stat_bmac_9216_hi;
+ u32 tx_stat_bmac_9216_lo;
+ u32 tx_stat_bmac_16383_hi;
+ u32 tx_stat_bmac_16383_lo;
+ u32 tx_stat_dot3statsinternalmactransmiterrors_hi;
+ u32 tx_stat_dot3statsinternalmactransmiterrors_lo;
+ u32 tx_stat_bmac_ufl_hi;
+ u32 tx_stat_bmac_ufl_lo;
+
+ u32 pause_frames_received_hi;
+ u32 pause_frames_received_lo;
+ u32 pause_frames_sent_hi;
+ u32 pause_frames_sent_lo;
+
+ u32 etherstatspkts1024octetsto1522octets_hi;
+ u32 etherstatspkts1024octetsto1522octets_lo;
+ u32 etherstatspktsover1522octets_hi;
+ u32 etherstatspktsover1522octets_lo;
+
+ u32 brb_drop_hi;
+ u32 brb_drop_lo;
+ u32 brb_truncate_hi;
+ u32 brb_truncate_lo;
+
+ u32 mac_filter_discard;
+ u32 xxoverflow_discard;
+ u32 brb_truncate_discard;
+ u32 mac_discard;
+
+ u32 driver_xoff;
+ u32 rx_err_discard_pkt;
+ u32 rx_skb_alloc_failed;
+ u32 hw_csum_err;
+
+ u32 nig_timer_max;
+};
+
+#define BNX2X_NUM_STATS 43
+#define STATS_OFFSET32(stat_name) \
+ (offsetof(struct bnx2x_eth_stats, stat_name) / 4)
+
+/* Forward declaration */
+struct bnx2x;
+
+
+void bnx2x_stats_init(struct bnx2x *bp);
+
+extern const u32 dmae_reg_go_c[];
+extern int bnx2x_sp_post(struct bnx2x *bp, int command, int cid,
+ u32 data_hi, u32 data_lo, int common);
+
+
+#endif /* BNX2X_STATS_H */
diff --git a/drivers/net/bonding/bond_alb.c b/drivers/net/bonding/bond_alb.c
index 8d7dfd2f1e9..c746b331771 100644
--- a/drivers/net/bonding/bond_alb.c
+++ b/drivers/net/bonding/bond_alb.c
@@ -233,34 +233,27 @@ static void tlb_deinitialize(struct bonding *bond)
_unlock_tx_hashtbl(bond);
}
+static long long compute_gap(struct slave *slave)
+{
+ return (s64) (slave->speed << 20) - /* Convert to Megabit per sec */
+ (s64) (SLAVE_TLB_INFO(slave).load << 3); /* Bytes to bits */
+}
+
/* Caller must hold bond lock for read */
static struct slave *tlb_get_least_loaded_slave(struct bonding *bond)
{
struct slave *slave, *least_loaded;
- s64 max_gap;
- int i, found = 0;
-
- /* Find the first enabled slave */
- bond_for_each_slave(bond, slave, i) {
- if (SLAVE_IS_OK(slave)) {
- found = 1;
- break;
- }
- }
-
- if (!found) {
- return NULL;
- }
+ long long max_gap;
+ int i;
- least_loaded = slave;
- max_gap = (s64)(slave->speed << 20) - /* Convert to Megabit per sec */
- (s64)(SLAVE_TLB_INFO(slave).load << 3); /* Bytes to bits */
+ least_loaded = NULL;
+ max_gap = LLONG_MIN;
/* Find the slave with the largest gap */
- bond_for_each_slave_from(bond, slave, i, least_loaded) {
+ bond_for_each_slave(bond, slave, i) {
if (SLAVE_IS_OK(slave)) {
- s64 gap = (s64)(slave->speed << 20) -
- (s64)(SLAVE_TLB_INFO(slave).load << 3);
+ long long gap = compute_gap(slave);
+
if (max_gap < gap) {
least_loaded = slave;
max_gap = gap;
@@ -689,7 +682,7 @@ static struct slave *rlb_choose_channel(struct sk_buff *skb, struct bonding *bon
client_info->ntt = 0;
}
- if (!list_empty(&bond->vlan_list)) {
+ if (bond->vlgrp) {
if (!vlan_get_tag(skb, &client_info->vlan_id))
client_info->tag = 1;
}
@@ -911,7 +904,7 @@ static void alb_send_learning_packets(struct slave *slave, u8 mac_addr[])
skb->priority = TC_PRIO_CONTROL;
skb->dev = slave->dev;
- if (!list_empty(&bond->vlan_list)) {
+ if (bond->vlgrp) {
struct vlan_entry *vlan;
vlan = bond_next_vlan(bond,
diff --git a/drivers/net/bonding/bond_ipv6.c b/drivers/net/bonding/bond_ipv6.c
index 969ffed86b9..121b073a6c3 100644
--- a/drivers/net/bonding/bond_ipv6.c
+++ b/drivers/net/bonding/bond_ipv6.c
@@ -178,6 +178,8 @@ static int bond_inet6addr_event(struct notifier_block *this,
}
list_for_each_entry(vlan, &bond->vlan_list, vlan_list) {
+ if (!bond->vlgrp)
+ continue;
vlan_dev = vlan_group_get_device(bond->vlgrp,
vlan->vlan_id);
if (vlan_dev == event_dev) {
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index c3d98dde2f8..2cc4cfc3189 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -90,6 +90,7 @@
#define BOND_LINK_ARP_INTERV 0
static int max_bonds = BOND_DEFAULT_MAX_BONDS;
+static int tx_queues = BOND_DEFAULT_TX_QUEUES;
static int num_grat_arp = 1;
static int num_unsol_na = 1;
static int miimon = BOND_LINK_MON_INTERV;
@@ -106,10 +107,13 @@ static int arp_interval = BOND_LINK_ARP_INTERV;
static char *arp_ip_target[BOND_MAX_ARP_TARGETS];
static char *arp_validate;
static char *fail_over_mac;
+static int all_slaves_active = 0;
static struct bond_params bonding_defaults;
module_param(max_bonds, int, 0);
MODULE_PARM_DESC(max_bonds, "Max number of bonded devices");
+module_param(tx_queues, int, 0);
+MODULE_PARM_DESC(tx_queues, "Max number of transmit queues (default = 16)");
module_param(num_grat_arp, int, 0644);
MODULE_PARM_DESC(num_grat_arp, "Number of gratuitous ARP packets to send on failover event");
module_param(num_unsol_na, int, 0644);
@@ -155,6 +159,10 @@ module_param(arp_validate, charp, 0);
MODULE_PARM_DESC(arp_validate, "validate src/dst of ARP probes: none (default), active, backup or all");
module_param(fail_over_mac, charp, 0);
MODULE_PARM_DESC(fail_over_mac, "For active-backup, do not set all slaves to the same MAC. none (default), active or follow");
+module_param(all_slaves_active, int, 0);
+MODULE_PARM_DESC(all_slaves_active, "Keep all frames received on an interface"
+ "by setting active flag for all slaves. "
+ "0 for never (default), 1 for always.");
/*----------------------------- Global variables ----------------------------*/
@@ -168,7 +176,9 @@ static int arp_ip_count;
static int bond_mode = BOND_MODE_ROUNDROBIN;
static int xmit_hashtype = BOND_XMIT_POLICY_LAYER2;
static int lacp_fast;
+#ifdef CONFIG_NET_POLL_CONTROLLER
static int disable_netpoll = 1;
+#endif
const struct bond_parm_tbl bond_lacp_tbl[] = {
{ "slow", AD_LACP_SLOW},
@@ -414,6 +424,7 @@ int bond_dev_queue_xmit(struct bonding *bond, struct sk_buff *skb,
{
unsigned short uninitialized_var(vlan_id);
+ /* Test vlan_list not vlgrp to catch and handle 802.1p tags */
if (!list_empty(&bond->vlan_list) &&
!(slave_dev->features & NETIF_F_HW_VLAN_TX) &&
vlan_get_tag(skb, &vlan_id) == 0) {
@@ -477,7 +488,9 @@ static void bond_vlan_rx_register(struct net_device *bond_dev,
struct slave *slave;
int i;
+ write_lock(&bond->lock);
bond->vlgrp = grp;
+ write_unlock(&bond->lock);
bond_for_each_slave(bond, slave, i) {
struct net_device *slave_dev = slave->dev;
@@ -557,10 +570,8 @@ static void bond_add_vlans_on_slave(struct bonding *bond, struct net_device *sla
struct vlan_entry *vlan;
const struct net_device_ops *slave_ops = slave_dev->netdev_ops;
- write_lock_bh(&bond->lock);
-
- if (list_empty(&bond->vlan_list))
- goto out;
+ if (!bond->vlgrp)
+ return;
if ((slave_dev->features & NETIF_F_HW_VLAN_RX) &&
slave_ops->ndo_vlan_rx_register)
@@ -568,13 +579,10 @@ static void bond_add_vlans_on_slave(struct bonding *bond, struct net_device *sla
if (!(slave_dev->features & NETIF_F_HW_VLAN_FILTER) ||
!(slave_ops->ndo_vlan_rx_add_vid))
- goto out;
+ return;
list_for_each_entry(vlan, &bond->vlan_list, vlan_list)
slave_ops->ndo_vlan_rx_add_vid(slave_dev, vlan->vlan_id);
-
-out:
- write_unlock_bh(&bond->lock);
}
static void bond_del_vlans_from_slave(struct bonding *bond,
@@ -584,16 +592,16 @@ static void bond_del_vlans_from_slave(struct bonding *bond,
struct vlan_entry *vlan;
struct net_device *vlan_dev;
- write_lock_bh(&bond->lock);
-
- if (list_empty(&bond->vlan_list))
- goto out;
+ if (!bond->vlgrp)
+ return;
if (!(slave_dev->features & NETIF_F_HW_VLAN_FILTER) ||
!(slave_ops->ndo_vlan_rx_kill_vid))
goto unreg;
list_for_each_entry(vlan, &bond->vlan_list, vlan_list) {
+ if (!vlan->vlan_id)
+ continue;
/* Save and then restore vlan_dev in the grp array,
* since the slave's driver might clear it.
*/
@@ -606,9 +614,6 @@ unreg:
if ((slave_dev->features & NETIF_F_HW_VLAN_RX) &&
slave_ops->ndo_vlan_rx_register)
slave_ops->ndo_vlan_rx_register(slave_dev, NULL);
-
-out:
- write_unlock_bh(&bond->lock);
}
/*------------------------------- Link status -------------------------------*/
@@ -1433,7 +1438,7 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
/* no need to lock since we're protected by rtnl_lock */
if (slave_dev->features & NETIF_F_VLAN_CHALLENGED) {
pr_debug("%s: NETIF_F_VLAN_CHALLENGED\n", slave_dev->name);
- if (!list_empty(&bond->vlan_list)) {
+ if (bond->vlgrp) {
pr_err("%s: Error: cannot enslave VLAN challenged slave %s on VLAN enabled bond %s\n",
bond_dev->name, slave_dev->name, bond_dev->name);
return -EPERM;
@@ -1522,16 +1527,32 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
}
}
+ /* If this is the first slave, then we need to set the master's hardware
+ * address to be the same as the slave's. */
+ if (bond->slave_cnt == 0)
+ memcpy(bond->dev->dev_addr, slave_dev->dev_addr,
+ slave_dev->addr_len);
+
+
new_slave = kzalloc(sizeof(struct slave), GFP_KERNEL);
if (!new_slave) {
res = -ENOMEM;
goto err_undo_flags;
}
- /* save slave's original flags before calling
- * netdev_set_master and dev_open
+ /*
+ * Set the new_slave's queue_id to be zero. Queue ID mapping
+ * is set via sysfs or module option if desired.
*/
- new_slave->original_flags = slave_dev->flags;
+ new_slave->queue_id = 0;
+
+ /* Save slave's original mtu and then set it to match the bond */
+ new_slave->original_mtu = slave_dev->mtu;
+ res = dev_set_mtu(slave_dev, bond->dev->mtu);
+ if (res) {
+ pr_debug("Error %d calling dev_set_mtu\n", res);
+ goto err_free;
+ }
/*
* Save slave's original ("permanent") mac address for modes
@@ -1550,7 +1571,7 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
res = dev_set_mac_address(slave_dev, &addr);
if (res) {
pr_debug("Error %d calling set_mac_address\n", res);
- goto err_free;
+ goto err_restore_mtu;
}
}
@@ -1793,6 +1814,9 @@ err_restore_mac:
dev_set_mac_address(slave_dev, &addr);
}
+err_restore_mtu:
+ dev_set_mtu(slave_dev, new_slave->original_mtu);
+
err_free:
kfree(new_slave);
@@ -1913,7 +1937,7 @@ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev)
*/
memset(bond_dev->dev_addr, 0, bond_dev->addr_len);
- if (list_empty(&bond->vlan_list)) {
+ if (!bond->vlgrp) {
bond_dev->features |= NETIF_F_VLAN_CHALLENGED;
} else {
pr_warning("%s: Warning: clearing HW address of %s while it still has VLANs.\n",
@@ -1980,6 +2004,8 @@ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev)
dev_set_mac_address(slave_dev, &addr);
}
+ dev_set_mtu(slave_dev, slave->original_mtu);
+
slave_dev->priv_flags &= ~(IFF_MASTER_8023AD | IFF_MASTER_ALB |
IFF_SLAVE_INACTIVE | IFF_BONDING |
IFF_SLAVE_NEEDARP);
@@ -2103,9 +2129,9 @@ static int bond_release_all(struct net_device *bond_dev)
*/
memset(bond_dev->dev_addr, 0, bond_dev->addr_len);
- if (list_empty(&bond->vlan_list))
+ if (!bond->vlgrp) {
bond_dev->features |= NETIF_F_VLAN_CHALLENGED;
- else {
+ } else {
pr_warning("%s: Warning: clearing HW address of %s while it still has VLANs.\n",
bond_dev->name, bond_dev->name);
pr_warning("%s: When re-adding slaves, make sure the bond's HW address matches its VLANs'.\n",
@@ -2538,7 +2564,7 @@ static void bond_arp_send_all(struct bonding *bond, struct slave *slave)
if (!targets[i])
break;
pr_debug("basa: target %x\n", targets[i]);
- if (list_empty(&bond->vlan_list)) {
+ if (!bond->vlgrp) {
pr_debug("basa: empty vlan: arp_send\n");
bond_arp_send(slave->dev, ARPOP_REQUEST, targets[i],
bond->master_ip, 0);
@@ -2566,7 +2592,7 @@ static void bond_arp_send_all(struct bonding *bond, struct slave *slave)
/*
* This target is not on a VLAN
*/
- if (rt->u.dst.dev == bond->dev) {
+ if (rt->dst.dev == bond->dev) {
ip_rt_put(rt);
pr_debug("basa: rtdev == bond->dev: arp_send\n");
bond_arp_send(slave->dev, ARPOP_REQUEST, targets[i],
@@ -2577,7 +2603,7 @@ static void bond_arp_send_all(struct bonding *bond, struct slave *slave)
vlan_id = 0;
list_for_each_entry(vlan, &bond->vlan_list, vlan_list) {
vlan_dev = vlan_group_get_device(bond->vlgrp, vlan->vlan_id);
- if (vlan_dev == rt->u.dst.dev) {
+ if (vlan_dev == rt->dst.dev) {
vlan_id = vlan->vlan_id;
pr_debug("basa: vlan match on %s %d\n",
vlan_dev->name, vlan_id);
@@ -2595,7 +2621,7 @@ static void bond_arp_send_all(struct bonding *bond, struct slave *slave)
if (net_ratelimit()) {
pr_warning("%s: no path to arp_ip_target %pI4 via rt.dev %s\n",
bond->dev->name, &fl.fl4_dst,
- rt->u.dst.dev ? rt->u.dst.dev->name : "NULL");
+ rt->dst.dev ? rt->dst.dev->name : "NULL");
}
ip_rt_put(rt);
}
@@ -2627,6 +2653,9 @@ static void bond_send_gratuitous_arp(struct bonding *bond)
bond->master_ip, 0);
}
+ if (!bond->vlgrp)
+ return;
+
list_for_each_entry(vlan, &bond->vlan_list, vlan_list) {
vlan_dev = vlan_group_get_device(bond->vlgrp, vlan->vlan_id);
if (vlan->vlan_ip) {
@@ -3276,6 +3305,7 @@ static void bond_info_show_slave(struct seq_file *seq,
else
seq_puts(seq, "Aggregator ID: N/A\n");
}
+ seq_printf(seq, "Slave queue ID: %d\n", slave->queue_id);
}
static int bond_info_seq_show(struct seq_file *seq, void *v)
@@ -3558,6 +3588,8 @@ static int bond_inetaddr_event(struct notifier_block *this, unsigned long event,
}
list_for_each_entry(vlan, &bond->vlan_list, vlan_list) {
+ if (!bond->vlgrp)
+ continue;
vlan_dev = vlan_group_get_device(bond->vlgrp, vlan->vlan_id);
if (vlan_dev == event_dev) {
switch (event) {
@@ -3785,50 +3817,49 @@ static int bond_close(struct net_device *bond_dev)
return 0;
}
-static struct net_device_stats *bond_get_stats(struct net_device *bond_dev)
+static struct rtnl_link_stats64 *bond_get_stats(struct net_device *bond_dev,
+ struct rtnl_link_stats64 *stats)
{
struct bonding *bond = netdev_priv(bond_dev);
- struct net_device_stats *stats = &bond_dev->stats;
- struct net_device_stats local_stats;
+ struct rtnl_link_stats64 temp;
struct slave *slave;
int i;
- memset(&local_stats, 0, sizeof(struct net_device_stats));
+ memset(stats, 0, sizeof(*stats));
read_lock_bh(&bond->lock);
bond_for_each_slave(bond, slave, i) {
- const struct net_device_stats *sstats = dev_get_stats(slave->dev);
+ const struct rtnl_link_stats64 *sstats =
+ dev_get_stats(slave->dev, &temp);
- local_stats.rx_packets += sstats->rx_packets;
- local_stats.rx_bytes += sstats->rx_bytes;
- local_stats.rx_errors += sstats->rx_errors;
- local_stats.rx_dropped += sstats->rx_dropped;
+ stats->rx_packets += sstats->rx_packets;
+ stats->rx_bytes += sstats->rx_bytes;
+ stats->rx_errors += sstats->rx_errors;
+ stats->rx_dropped += sstats->rx_dropped;
- local_stats.tx_packets += sstats->tx_packets;
- local_stats.tx_bytes += sstats->tx_bytes;
- local_stats.tx_errors += sstats->tx_errors;
- local_stats.tx_dropped += sstats->tx_dropped;
+ stats->tx_packets += sstats->tx_packets;
+ stats->tx_bytes += sstats->tx_bytes;
+ stats->tx_errors += sstats->tx_errors;
+ stats->tx_dropped += sstats->tx_dropped;
- local_stats.multicast += sstats->multicast;
- local_stats.collisions += sstats->collisions;
+ stats->multicast += sstats->multicast;
+ stats->collisions += sstats->collisions;
- local_stats.rx_length_errors += sstats->rx_length_errors;
- local_stats.rx_over_errors += sstats->rx_over_errors;
- local_stats.rx_crc_errors += sstats->rx_crc_errors;
- local_stats.rx_frame_errors += sstats->rx_frame_errors;
- local_stats.rx_fifo_errors += sstats->rx_fifo_errors;
- local_stats.rx_missed_errors += sstats->rx_missed_errors;
+ stats->rx_length_errors += sstats->rx_length_errors;
+ stats->rx_over_errors += sstats->rx_over_errors;
+ stats->rx_crc_errors += sstats->rx_crc_errors;
+ stats->rx_frame_errors += sstats->rx_frame_errors;
+ stats->rx_fifo_errors += sstats->rx_fifo_errors;
+ stats->rx_missed_errors += sstats->rx_missed_errors;
- local_stats.tx_aborted_errors += sstats->tx_aborted_errors;
- local_stats.tx_carrier_errors += sstats->tx_carrier_errors;
- local_stats.tx_fifo_errors += sstats->tx_fifo_errors;
- local_stats.tx_heartbeat_errors += sstats->tx_heartbeat_errors;
- local_stats.tx_window_errors += sstats->tx_window_errors;
+ stats->tx_aborted_errors += sstats->tx_aborted_errors;
+ stats->tx_carrier_errors += sstats->tx_carrier_errors;
+ stats->tx_fifo_errors += sstats->tx_fifo_errors;
+ stats->tx_heartbeat_errors += sstats->tx_heartbeat_errors;
+ stats->tx_window_errors += sstats->tx_window_errors;
}
- memcpy(stats, &local_stats, sizeof(struct net_device_stats));
-
read_unlock_bh(&bond->lock);
return stats;
@@ -4412,9 +4443,59 @@ static void bond_set_xmit_hash_policy(struct bonding *bond)
}
}
+/*
+ * Lookup the slave that corresponds to a qid
+ */
+static inline int bond_slave_override(struct bonding *bond,
+ struct sk_buff *skb)
+{
+ int i, res = 1;
+ struct slave *slave = NULL;
+ struct slave *check_slave;
+
+ read_lock(&bond->lock);
+
+ if (!BOND_IS_OK(bond) || !skb->queue_mapping)
+ goto out;
+
+ /* Find out if any slaves have the same mapping as this skb. */
+ bond_for_each_slave(bond, check_slave, i) {
+ if (check_slave->queue_id == skb->queue_mapping) {
+ slave = check_slave;
+ break;
+ }
+ }
+
+ /* If the slave isn't UP, use default transmit policy. */
+ if (slave && slave->queue_id && IS_UP(slave->dev) &&
+ (slave->link == BOND_LINK_UP)) {
+ res = bond_dev_queue_xmit(bond, skb, slave->dev);
+ }
+
+out:
+ read_unlock(&bond->lock);
+ return res;
+}
+
+static u16 bond_select_queue(struct net_device *dev, struct sk_buff *skb)
+{
+ /*
+ * This helper function exists to help dev_pick_tx get the correct
+ * destination queue. Using a helper function skips the a call to
+ * skb_tx_hash and will put the skbs in the queue we expect on their
+ * way down to the bonding driver.
+ */
+ return skb->queue_mapping;
+}
+
static netdev_tx_t bond_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
- const struct bonding *bond = netdev_priv(dev);
+ struct bonding *bond = netdev_priv(dev);
+
+ if (TX_QUEUE_OVERRIDE(bond->params.mode)) {
+ if (!bond_slave_override(bond, skb))
+ return NETDEV_TX_OK;
+ }
switch (bond->params.mode) {
case BOND_MODE_ROUNDROBIN:
@@ -4499,7 +4580,8 @@ static const struct net_device_ops bond_netdev_ops = {
.ndo_open = bond_open,
.ndo_stop = bond_close,
.ndo_start_xmit = bond_start_xmit,
- .ndo_get_stats = bond_get_stats,
+ .ndo_select_queue = bond_select_queue,
+ .ndo_get_stats64 = bond_get_stats,
.ndo_do_ioctl = bond_do_ioctl,
.ndo_set_multicast_list = bond_set_multicast_list,
.ndo_change_mtu = bond_change_mtu,
@@ -4604,6 +4686,7 @@ static void bond_work_cancel_all(struct bonding *bond)
static void bond_uninit(struct net_device *bond_dev)
{
struct bonding *bond = netdev_priv(bond_dev);
+ struct vlan_entry *vlan, *tmp;
bond_netpoll_cleanup(bond_dev);
@@ -4617,6 +4700,11 @@ static void bond_uninit(struct net_device *bond_dev)
bond_remove_proc_entry(bond);
__hw_addr_flush(&bond->mc_list);
+
+ list_for_each_entry_safe(vlan, tmp, &bond->vlan_list, vlan_list) {
+ list_del(&vlan->vlan_list);
+ kfree(vlan);
+ }
}
/*------------------------- Module initialization ---------------------------*/
@@ -4767,6 +4855,20 @@ static int bond_check_params(struct bond_params *params)
}
}
+ if (tx_queues < 1 || tx_queues > 255) {
+ pr_warning("Warning: tx_queues (%d) should be between "
+ "1 and 255, resetting to %d\n",
+ tx_queues, BOND_DEFAULT_TX_QUEUES);
+ tx_queues = BOND_DEFAULT_TX_QUEUES;
+ }
+
+ if ((all_slaves_active != 0) && (all_slaves_active != 1)) {
+ pr_warning("Warning: all_slaves_active module parameter (%d), "
+ "not of valid value (0/1), so it was set to "
+ "0\n", all_slaves_active);
+ all_slaves_active = 0;
+ }
+
/* reset values for TLB/ALB */
if ((bond_mode == BOND_MODE_TLB) ||
(bond_mode == BOND_MODE_ALB)) {
@@ -4937,6 +5039,8 @@ static int bond_check_params(struct bond_params *params)
params->primary[0] = 0;
params->primary_reselect = primary_reselect_value;
params->fail_over_mac = fail_over_mac_value;
+ params->tx_queues = tx_queues;
+ params->all_slaves_active = all_slaves_active;
if (primary) {
strncpy(params->primary, primary, IFNAMSIZ);
@@ -5023,8 +5127,8 @@ int bond_create(struct net *net, const char *name)
rtnl_lock();
- bond_dev = alloc_netdev(sizeof(struct bonding), name ? name : "",
- bond_setup);
+ bond_dev = alloc_netdev_mq(sizeof(struct bonding), name ? name : "",
+ bond_setup, tx_queues);
if (!bond_dev) {
pr_err("%s: eek! can't alloc netdev!\n", name);
rtnl_unlock();
diff --git a/drivers/net/bonding/bond_sysfs.c b/drivers/net/bonding/bond_sysfs.c
index b8bec086daa..c311aed9bd0 100644
--- a/drivers/net/bonding/bond_sysfs.c
+++ b/drivers/net/bonding/bond_sysfs.c
@@ -211,7 +211,8 @@ static ssize_t bonding_show_slaves(struct device *d,
/*
* Set the slaves in the current bond. The bond interface must be
* up for this to succeed.
- * This function is largely the same flow as bonding_update_bonds().
+ * This is supposed to be only thin wrapper for bond_enslave and bond_release.
+ * All hard work should be done there.
*/
static ssize_t bonding_store_slaves(struct device *d,
struct device_attribute *attr,
@@ -219,10 +220,8 @@ static ssize_t bonding_store_slaves(struct device *d,
{
char command[IFNAMSIZ + 1] = { 0, };
char *ifname;
- int i, res, found, ret = count;
- u32 original_mtu;
- struct slave *slave;
- struct net_device *dev = NULL;
+ int res, ret = count;
+ struct net_device *dev;
struct bonding *bond = to_bond(d);
/* Quick sanity check -- is the bond interface up? */
@@ -231,8 +230,6 @@ static ssize_t bonding_store_slaves(struct device *d,
bond->dev->name);
}
- /* Note: We can't hold bond->lock here, as bond_create grabs it. */
-
if (!rtnl_trylock())
return restart_syscall();
@@ -242,91 +239,33 @@ static ssize_t bonding_store_slaves(struct device *d,
!dev_valid_name(ifname))
goto err_no_cmd;
- if (command[0] == '+') {
-
- /* Got a slave name in ifname. Is it already in the list? */
- found = 0;
-
- dev = __dev_get_by_name(dev_net(bond->dev), ifname);
- if (!dev) {
- pr_info("%s: Interface %s does not exist!\n",
- bond->dev->name, ifname);
- ret = -ENODEV;
- goto out;
- }
-
- if (dev->flags & IFF_UP) {
- pr_err("%s: Error: Unable to enslave %s because it is already up.\n",
- bond->dev->name, dev->name);
- ret = -EPERM;
- goto out;
- }
-
- read_lock(&bond->lock);
- bond_for_each_slave(bond, slave, i)
- if (slave->dev == dev) {
- pr_err("%s: Interface %s is already enslaved!\n",
- bond->dev->name, ifname);
- ret = -EPERM;
- read_unlock(&bond->lock);
- goto out;
- }
- read_unlock(&bond->lock);
-
- pr_info("%s: Adding slave %s.\n", bond->dev->name, ifname);
-
- /* If this is the first slave, then we need to set
- the master's hardware address to be the same as the
- slave's. */
- if (is_zero_ether_addr(bond->dev->dev_addr))
- memcpy(bond->dev->dev_addr, dev->dev_addr,
- dev->addr_len);
-
- /* Set the slave's MTU to match the bond */
- original_mtu = dev->mtu;
- res = dev_set_mtu(dev, bond->dev->mtu);
- if (res) {
- ret = res;
- goto out;
- }
+ dev = __dev_get_by_name(dev_net(bond->dev), ifname);
+ if (!dev) {
+ pr_info("%s: Interface %s does not exist!\n",
+ bond->dev->name, ifname);
+ ret = -ENODEV;
+ goto out;
+ }
+ switch (command[0]) {
+ case '+':
+ pr_info("%s: Adding slave %s.\n", bond->dev->name, dev->name);
res = bond_enslave(bond->dev, dev);
- bond_for_each_slave(bond, slave, i)
- if (strnicmp(slave->dev->name, ifname, IFNAMSIZ) == 0)
- slave->original_mtu = original_mtu;
- if (res)
- ret = res;
+ break;
- goto out;
- }
+ case '-':
+ pr_info("%s: Removing slave %s.\n", bond->dev->name, dev->name);
+ res = bond_release(bond->dev, dev);
+ break;
- if (command[0] == '-') {
- dev = NULL;
- original_mtu = 0;
- bond_for_each_slave(bond, slave, i)
- if (strnicmp(slave->dev->name, ifname, IFNAMSIZ) == 0) {
- dev = slave->dev;
- original_mtu = slave->original_mtu;
- break;
- }
- if (dev) {
- pr_info("%s: Removing slave %s\n",
- bond->dev->name, dev->name);
- res = bond_release(bond->dev, dev);
- if (res) {
- ret = res;
- goto out;
- }
- /* set the slave MTU to the default */
- dev_set_mtu(dev, original_mtu);
- } else {
- pr_err("unable to remove non-existent slave %s for bond %s.\n",
- ifname, bond->dev->name);
- ret = -ENODEV;
- }
- goto out;
+ default:
+ goto err_no_cmd;
}
+ if (res)
+ ret = res;
+ goto out;
+
err_no_cmd:
pr_err("no command found in slaves file for bond %s. Use +ifname or -ifname.\n",
bond->dev->name);
@@ -374,19 +313,26 @@ static ssize_t bonding_store_mode(struct device *d,
bond->dev->name, (int)strlen(buf) - 1, buf);
ret = -EINVAL;
goto out;
- } else {
- if (bond->params.mode == BOND_MODE_8023AD)
- bond_unset_master_3ad_flags(bond);
+ }
+ if ((new_value == BOND_MODE_ALB ||
+ new_value == BOND_MODE_TLB) &&
+ bond->params.arp_interval) {
+ pr_err("%s: %s mode is incompatible with arp monitoring.\n",
+ bond->dev->name, bond_mode_tbl[new_value].modename);
+ ret = -EINVAL;
+ goto out;
+ }
+ if (bond->params.mode == BOND_MODE_8023AD)
+ bond_unset_master_3ad_flags(bond);
- if (bond->params.mode == BOND_MODE_ALB)
- bond_unset_master_alb_flags(bond);
+ if (bond->params.mode == BOND_MODE_ALB)
+ bond_unset_master_alb_flags(bond);
- bond->params.mode = new_value;
- bond_set_mode_ops(bond, bond->params.mode);
- pr_info("%s: setting mode to %s (%d).\n",
- bond->dev->name, bond_mode_tbl[new_value].modename,
- new_value);
- }
+ bond->params.mode = new_value;
+ bond_set_mode_ops(bond, bond->params.mode);
+ pr_info("%s: setting mode to %s (%d).\n",
+ bond->dev->name, bond_mode_tbl[new_value].modename,
+ new_value);
out:
return ret;
}
@@ -571,7 +517,13 @@ static ssize_t bonding_store_arp_interval(struct device *d,
ret = -EINVAL;
goto out;
}
-
+ if (bond->params.mode == BOND_MODE_ALB ||
+ bond->params.mode == BOND_MODE_TLB) {
+ pr_info("%s: ARP monitoring cannot be used with ALB/TLB. Only MII monitoring is supported on %s.\n",
+ bond->dev->name, bond->dev->name);
+ ret = -EINVAL;
+ goto out;
+ }
pr_info("%s: Setting ARP monitoring interval to %d.\n",
bond->dev->name, new_value);
bond->params.arp_interval = new_value;
@@ -1472,7 +1424,173 @@ static ssize_t bonding_show_ad_partner_mac(struct device *d,
}
static DEVICE_ATTR(ad_partner_mac, S_IRUGO, bonding_show_ad_partner_mac, NULL);
+/*
+ * Show the queue_ids of the slaves in the current bond.
+ */
+static ssize_t bonding_show_queue_id(struct device *d,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct slave *slave;
+ int i, res = 0;
+ struct bonding *bond = to_bond(d);
+
+ if (!rtnl_trylock())
+ return restart_syscall();
+
+ read_lock(&bond->lock);
+ bond_for_each_slave(bond, slave, i) {
+ if (res > (PAGE_SIZE - IFNAMSIZ - 6)) {
+ /* not enough space for another interface_name:queue_id pair */
+ if ((PAGE_SIZE - res) > 10)
+ res = PAGE_SIZE - 10;
+ res += sprintf(buf + res, "++more++ ");
+ break;
+ }
+ res += sprintf(buf + res, "%s:%d ",
+ slave->dev->name, slave->queue_id);
+ }
+ read_unlock(&bond->lock);
+ if (res)
+ buf[res-1] = '\n'; /* eat the leftover space */
+ rtnl_unlock();
+ return res;
+}
+
+/*
+ * Set the queue_ids of the slaves in the current bond. The bond
+ * interface must be enslaved for this to work.
+ */
+static ssize_t bonding_store_queue_id(struct device *d,
+ struct device_attribute *attr,
+ const char *buffer, size_t count)
+{
+ struct slave *slave, *update_slave;
+ struct bonding *bond = to_bond(d);
+ u16 qid;
+ int i, ret = count;
+ char *delim;
+ struct net_device *sdev = NULL;
+ if (!rtnl_trylock())
+ return restart_syscall();
+
+ /* delim will point to queue id if successful */
+ delim = strchr(buffer, ':');
+ if (!delim)
+ goto err_no_cmd;
+
+ /*
+ * Terminate string that points to device name and bump it
+ * up one, so we can read the queue id there.
+ */
+ *delim = '\0';
+ if (sscanf(++delim, "%hd\n", &qid) != 1)
+ goto err_no_cmd;
+
+ /* Check buffer length, valid ifname and queue id */
+ if (strlen(buffer) > IFNAMSIZ ||
+ !dev_valid_name(buffer) ||
+ qid > bond->params.tx_queues)
+ goto err_no_cmd;
+
+ /* Get the pointer to that interface if it exists */
+ sdev = __dev_get_by_name(dev_net(bond->dev), buffer);
+ if (!sdev)
+ goto err_no_cmd;
+
+ read_lock(&bond->lock);
+
+ /* Search for thes slave and check for duplicate qids */
+ update_slave = NULL;
+ bond_for_each_slave(bond, slave, i) {
+ if (sdev == slave->dev)
+ /*
+ * We don't need to check the matching
+ * slave for dups, since we're overwriting it
+ */
+ update_slave = slave;
+ else if (qid && qid == slave->queue_id) {
+ goto err_no_cmd_unlock;
+ }
+ }
+
+ if (!update_slave)
+ goto err_no_cmd_unlock;
+
+ /* Actually set the qids for the slave */
+ update_slave->queue_id = qid;
+
+ read_unlock(&bond->lock);
+out:
+ rtnl_unlock();
+ return ret;
+
+err_no_cmd_unlock:
+ read_unlock(&bond->lock);
+err_no_cmd:
+ pr_info("invalid input for queue_id set for %s.\n",
+ bond->dev->name);
+ ret = -EPERM;
+ goto out;
+}
+
+static DEVICE_ATTR(queue_id, S_IRUGO | S_IWUSR, bonding_show_queue_id,
+ bonding_store_queue_id);
+
+
+/*
+ * Show and set the all_slaves_active flag.
+ */
+static ssize_t bonding_show_slaves_active(struct device *d,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct bonding *bond = to_bond(d);
+
+ return sprintf(buf, "%d\n", bond->params.all_slaves_active);
+}
+
+static ssize_t bonding_store_slaves_active(struct device *d,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int i, new_value, ret = count;
+ struct bonding *bond = to_bond(d);
+ struct slave *slave;
+
+ if (sscanf(buf, "%d", &new_value) != 1) {
+ pr_err("%s: no all_slaves_active value specified.\n",
+ bond->dev->name);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ if (new_value == bond->params.all_slaves_active)
+ goto out;
+
+ if ((new_value == 0) || (new_value == 1)) {
+ bond->params.all_slaves_active = new_value;
+ } else {
+ pr_info("%s: Ignoring invalid all_slaves_active value %d.\n",
+ bond->dev->name, new_value);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ bond_for_each_slave(bond, slave, i) {
+ if (slave->state == BOND_STATE_BACKUP) {
+ if (new_value)
+ slave->dev->priv_flags &= ~IFF_SLAVE_INACTIVE;
+ else
+ slave->dev->priv_flags |= IFF_SLAVE_INACTIVE;
+ }
+ }
+out:
+ return count;
+}
+static DEVICE_ATTR(all_slaves_active, S_IRUGO | S_IWUSR,
+ bonding_show_slaves_active, bonding_store_slaves_active);
static struct attribute *per_bond_attrs[] = {
&dev_attr_slaves.attr,
@@ -1499,6 +1617,8 @@ static struct attribute *per_bond_attrs[] = {
&dev_attr_ad_actor_key.attr,
&dev_attr_ad_partner_key.attr,
&dev_attr_ad_partner_mac.attr,
+ &dev_attr_queue_id.attr,
+ &dev_attr_all_slaves_active.attr,
NULL,
};
diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h
index 2aa33672059..c6fdd851579 100644
--- a/drivers/net/bonding/bonding.h
+++ b/drivers/net/bonding/bonding.h
@@ -23,8 +23,8 @@
#include "bond_3ad.h"
#include "bond_alb.h"
-#define DRV_VERSION "3.6.0"
-#define DRV_RELDATE "September 26, 2009"
+#define DRV_VERSION "3.7.0"
+#define DRV_RELDATE "June 2, 2010"
#define DRV_NAME "bonding"
#define DRV_DESCRIPTION "Ethernet Channel Bonding Driver"
@@ -60,6 +60,9 @@
((mode) == BOND_MODE_TLB) || \
((mode) == BOND_MODE_ALB))
+#define TX_QUEUE_OVERRIDE(mode) \
+ (((mode) == BOND_MODE_ACTIVEBACKUP) || \
+ ((mode) == BOND_MODE_ROUNDROBIN))
/*
* Less bad way to call ioctl from within the kernel; this needs to be
* done some other way to get the call out of interrupt context.
@@ -131,6 +134,8 @@ struct bond_params {
char primary[IFNAMSIZ];
int primary_reselect;
__be32 arp_targets[BOND_MAX_ARP_TARGETS];
+ int tx_queues;
+ int all_slaves_active;
};
struct bond_parm_tbl {
@@ -159,12 +164,12 @@ struct slave {
s8 link; /* one of BOND_LINK_XXXX */
s8 new_link;
s8 state; /* one of BOND_STATE_XXXX */
- u32 original_flags;
u32 original_mtu;
u32 link_failure_count;
u8 perm_hwaddr[ETH_ALEN];
u16 speed;
u8 duplex;
+ u16 queue_id;
struct ad_slave_info ad_info; /* HUGE - better to dynamically alloc */
struct tlb_slave_info tlb_info;
};
@@ -291,7 +296,8 @@ static inline void bond_set_slave_inactive_flags(struct slave *slave)
struct bonding *bond = netdev_priv(slave->dev->master);
if (!bond_is_lb(bond))
slave->state = BOND_STATE_BACKUP;
- slave->dev->priv_flags |= IFF_SLAVE_INACTIVE;
+ if (!bond->params.all_slaves_active)
+ slave->dev->priv_flags |= IFF_SLAVE_INACTIVE;
if (slave_do_arp_validate(bond, slave))
slave->dev->priv_flags |= IFF_SLAVE_NEEDARP;
}
diff --git a/drivers/net/caif/Kconfig b/drivers/net/caif/Kconfig
index 0b28e010769..631a6242b01 100644
--- a/drivers/net/caif/Kconfig
+++ b/drivers/net/caif/Kconfig
@@ -2,16 +2,32 @@
# CAIF physical drivers
#
-if CAIF
-
comment "CAIF transport drivers"
config CAIF_TTY
tristate "CAIF TTY transport driver"
+ depends on CAIF
default n
---help---
The CAIF TTY transport driver is a Line Discipline (ldisc)
identified as N_CAIF. When this ldisc is opened from user space
it will redirect the TTY's traffic into the CAIF stack.
-endif # CAIF
+config CAIF_SPI_SLAVE
+ tristate "CAIF SPI transport driver for slave interface"
+ depends on CAIF
+ default n
+ ---help---
+ The CAIF Link layer SPI Protocol driver for Slave SPI interface.
+ This driver implements a platform driver to accommodate for a
+ platform specific SPI device. A sample CAIF SPI Platform device is
+ provided in Documentation/networking/caif/spi_porting.txt
+
+config CAIF_SPI_SYNC
+ bool "Next command and length in start of frame"
+ depends on CAIF_SPI_SLAVE
+ default n
+ ---help---
+ Putting the next command and length in the start of the frame can
+ help to synchronize to the next transfer in case of over or under-runs.
+ This option also needs to be enabled on the modem.
diff --git a/drivers/net/caif/Makefile b/drivers/net/caif/Makefile
index 52b6d1f826f..3a11d619452 100644
--- a/drivers/net/caif/Makefile
+++ b/drivers/net/caif/Makefile
@@ -1,12 +1,10 @@
-ifeq ($(CONFIG_CAIF_DEBUG),1)
-CAIF_DBG_FLAGS := -DDEBUG
+ifeq ($(CONFIG_CAIF_DEBUG),y)
+EXTRA_CFLAGS += -DDEBUG
endif
-KBUILD_EXTRA_SYMBOLS=net/caif/Module.symvers
-
-ccflags-y := $(CAIF_FLAGS) $(CAIF_DBG_FLAGS)
-clean-dirs:= .tmp_versions
-clean-files:= Module.symvers modules.order *.cmd *~ \
-
# Serial interface
obj-$(CONFIG_CAIF_TTY) += caif_serial.o
+
+# SPI slave physical interfaces module
+cfspi_slave-objs := caif_spi.o caif_spi_slave.o
+obj-$(CONFIG_CAIF_SPI_SLAVE) += cfspi_slave.o
diff --git a/drivers/net/caif/caif_serial.c b/drivers/net/caif/caif_serial.c
index 09257ca8f56..3df0c0f8b8b 100644
--- a/drivers/net/caif/caif_serial.c
+++ b/drivers/net/caif/caif_serial.c
@@ -174,6 +174,7 @@ static void ldisc_receive(struct tty_struct *tty, const u8 *data,
struct ser_device *ser;
int ret;
u8 *p;
+
ser = tty->disc_data;
/*
@@ -221,6 +222,7 @@ static int handle_tx(struct ser_device *ser)
struct tty_struct *tty;
struct sk_buff *skb;
int tty_wr, len, room;
+
tty = ser->tty;
ser->tx_started = true;
@@ -281,6 +283,7 @@ error:
static int caif_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct ser_device *ser;
+
BUG_ON(dev == NULL);
ser = netdev_priv(dev);
@@ -299,6 +302,7 @@ static int caif_xmit(struct sk_buff *skb, struct net_device *dev)
static void ldisc_tx_wakeup(struct tty_struct *tty)
{
struct ser_device *ser;
+
ser = tty->disc_data;
BUG_ON(ser == NULL);
BUG_ON(ser->tty != tty);
@@ -348,6 +352,7 @@ static void ldisc_close(struct tty_struct *tty)
struct ser_device *ser = tty->disc_data;
/* Remove may be called inside or outside of rtnl_lock */
int islocked = rtnl_is_locked();
+
if (!islocked)
rtnl_lock();
/* device is freed automagically by net-sysfs */
@@ -374,6 +379,7 @@ static struct tty_ldisc_ops caif_ldisc = {
static int register_ldisc(void)
{
int result;
+
result = tty_register_ldisc(N_CAIF, &caif_ldisc);
if (result < 0) {
pr_err("cannot register CAIF ldisc=%d err=%d\n", N_CAIF,
@@ -391,12 +397,12 @@ static const struct net_device_ops netdev_ops = {
static void caifdev_setup(struct net_device *dev)
{
struct ser_device *serdev = netdev_priv(dev);
+
dev->features = 0;
dev->netdev_ops = &netdev_ops;
dev->type = ARPHRD_CAIF;
dev->flags = IFF_POINTOPOINT | IFF_NOARP;
dev->mtu = CAIF_MAX_MTU;
- dev->hard_header_len = CAIF_NEEDED_HEADROOM;
dev->tx_queue_len = 0;
dev->destructor = free_netdev;
skb_queue_head_init(&serdev->head);
@@ -410,8 +416,6 @@ static void caifdev_setup(struct net_device *dev)
static int caif_net_open(struct net_device *dev)
{
- struct ser_device *ser;
- ser = netdev_priv(dev);
netif_wake_queue(dev);
return 0;
}
@@ -425,6 +429,7 @@ static int caif_net_close(struct net_device *dev)
static int __init caif_ser_init(void)
{
int ret;
+
ret = register_ldisc();
debugfsdir = debugfs_create_dir("caif_serial", NULL);
return ret;
@@ -435,6 +440,7 @@ static void __exit caif_ser_exit(void)
struct ser_device *ser = NULL;
struct list_head *node;
struct list_head *_tmp;
+
list_for_each_safe(node, _tmp, &ser_list) {
ser = list_entry(node, struct ser_device, node);
dev_close(ser->dev);
diff --git a/drivers/net/caif/caif_spi.c b/drivers/net/caif/caif_spi.c
new file mode 100644
index 00000000000..f5058ff2b21
--- /dev/null
+++ b/drivers/net/caif/caif_spi.c
@@ -0,0 +1,850 @@
+/*
+ * Copyright (C) ST-Ericsson AB 2010
+ * Contact: Sjur Brendeland / sjur.brandeland@stericsson.com
+ * Author: Daniel Martensson / Daniel.Martensson@stericsson.com
+ * License terms: GNU General Public License (GPL) version 2.
+ */
+
+#include <linux/version.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/string.h>
+#include <linux/workqueue.h>
+#include <linux/completion.h>
+#include <linux/list.h>
+#include <linux/interrupt.h>
+#include <linux/dma-mapping.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <linux/debugfs.h>
+#include <linux/if_arp.h>
+#include <net/caif/caif_layer.h>
+#include <net/caif/caif_spi.h>
+
+#ifndef CONFIG_CAIF_SPI_SYNC
+#define FLAVOR "Flavour: Vanilla.\n"
+#else
+#define FLAVOR "Flavour: Master CMD&LEN at start.\n"
+#endif /* CONFIG_CAIF_SPI_SYNC */
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Daniel Martensson<daniel.martensson@stericsson.com>");
+MODULE_DESCRIPTION("CAIF SPI driver");
+
+static int spi_loop;
+module_param(spi_loop, bool, S_IRUGO);
+MODULE_PARM_DESC(spi_loop, "SPI running in loopback mode.");
+
+/* SPI frame alignment. */
+module_param(spi_frm_align, int, S_IRUGO);
+MODULE_PARM_DESC(spi_frm_align, "SPI frame alignment.");
+
+/* SPI padding options. */
+module_param(spi_up_head_align, int, S_IRUGO);
+MODULE_PARM_DESC(spi_up_head_align, "SPI uplink head alignment.");
+
+module_param(spi_up_tail_align, int, S_IRUGO);
+MODULE_PARM_DESC(spi_up_tail_align, "SPI uplink tail alignment.");
+
+module_param(spi_down_head_align, int, S_IRUGO);
+MODULE_PARM_DESC(spi_down_head_align, "SPI downlink head alignment.");
+
+module_param(spi_down_tail_align, int, S_IRUGO);
+MODULE_PARM_DESC(spi_down_tail_align, "SPI downlink tail alignment.");
+
+#ifdef CONFIG_ARM
+#define BYTE_HEX_FMT "%02X"
+#else
+#define BYTE_HEX_FMT "%02hhX"
+#endif
+
+#define SPI_MAX_PAYLOAD_SIZE 4096
+/*
+ * Threshold values for the SPI packet queue. Flowcontrol will be asserted
+ * when the number of packets exceeds HIGH_WATER_MARK. It will not be
+ * deasserted before the number of packets drops below LOW_WATER_MARK.
+ */
+#define LOW_WATER_MARK 100
+#define HIGH_WATER_MARK (LOW_WATER_MARK*5)
+
+#ifdef CONFIG_UML
+
+/*
+ * We sometimes use UML for debugging, but it cannot handle
+ * dma_alloc_coherent so we have to wrap it.
+ */
+static inline void *dma_alloc(dma_addr_t *daddr)
+{
+ return kmalloc(SPI_DMA_BUF_LEN, GFP_KERNEL);
+}
+
+static inline void dma_free(void *cpu_addr, dma_addr_t handle)
+{
+ kfree(cpu_addr);
+}
+
+#else
+
+static inline void *dma_alloc(dma_addr_t *daddr)
+{
+ return dma_alloc_coherent(NULL, SPI_DMA_BUF_LEN, daddr,
+ GFP_KERNEL);
+}
+
+static inline void dma_free(void *cpu_addr, dma_addr_t handle)
+{
+ dma_free_coherent(NULL, SPI_DMA_BUF_LEN, cpu_addr, handle);
+}
+#endif /* CONFIG_UML */
+
+#ifdef CONFIG_DEBUG_FS
+
+#define DEBUGFS_BUF_SIZE 4096
+
+static struct dentry *dbgfs_root;
+
+static inline void driver_debugfs_create(void)
+{
+ dbgfs_root = debugfs_create_dir(cfspi_spi_driver.driver.name, NULL);
+}
+
+static inline void driver_debugfs_remove(void)
+{
+ debugfs_remove(dbgfs_root);
+}
+
+static inline void dev_debugfs_rem(struct cfspi *cfspi)
+{
+ debugfs_remove(cfspi->dbgfs_frame);
+ debugfs_remove(cfspi->dbgfs_state);
+ debugfs_remove(cfspi->dbgfs_dir);
+}
+
+static int dbgfs_open(struct inode *inode, struct file *file)
+{
+ file->private_data = inode->i_private;
+ return 0;
+}
+
+static ssize_t dbgfs_state(struct file *file, char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ char *buf;
+ int len = 0;
+ ssize_t size;
+ struct cfspi *cfspi = file->private_data;
+
+ buf = kzalloc(DEBUGFS_BUF_SIZE, GFP_KERNEL);
+ if (!buf)
+ return 0;
+
+ /* Print out debug information. */
+ len += snprintf((buf + len), (DEBUGFS_BUF_SIZE - len),
+ "CAIF SPI debug information:\n");
+
+ len += snprintf((buf + len), (DEBUGFS_BUF_SIZE - len), FLAVOR);
+
+ len += snprintf((buf + len), (DEBUGFS_BUF_SIZE - len),
+ "STATE: %d\n", cfspi->dbg_state);
+ len += snprintf((buf + len), (DEBUGFS_BUF_SIZE - len),
+ "Previous CMD: 0x%x\n", cfspi->pcmd);
+ len += snprintf((buf + len), (DEBUGFS_BUF_SIZE - len),
+ "Current CMD: 0x%x\n", cfspi->cmd);
+ len += snprintf((buf + len), (DEBUGFS_BUF_SIZE - len),
+ "Previous TX len: %d\n", cfspi->tx_ppck_len);
+ len += snprintf((buf + len), (DEBUGFS_BUF_SIZE - len),
+ "Previous RX len: %d\n", cfspi->rx_ppck_len);
+ len += snprintf((buf + len), (DEBUGFS_BUF_SIZE - len),
+ "Current TX len: %d\n", cfspi->tx_cpck_len);
+ len += snprintf((buf + len), (DEBUGFS_BUF_SIZE - len),
+ "Current RX len: %d\n", cfspi->rx_cpck_len);
+ len += snprintf((buf + len), (DEBUGFS_BUF_SIZE - len),
+ "Next TX len: %d\n", cfspi->tx_npck_len);
+ len += snprintf((buf + len), (DEBUGFS_BUF_SIZE - len),
+ "Next RX len: %d\n", cfspi->rx_npck_len);
+
+ if (len > DEBUGFS_BUF_SIZE)
+ len = DEBUGFS_BUF_SIZE;
+
+ size = simple_read_from_buffer(user_buf, count, ppos, buf, len);
+ kfree(buf);
+
+ return size;
+}
+
+static ssize_t print_frame(char *buf, size_t size, char *frm,
+ size_t count, size_t cut)
+{
+ int len = 0;
+ int i;
+ for (i = 0; i < count; i++) {
+ len += snprintf((buf + len), (size - len),
+ "[0x" BYTE_HEX_FMT "]",
+ frm[i]);
+ if ((i == cut) && (count > (cut * 2))) {
+ /* Fast forward. */
+ i = count - cut;
+ len += snprintf((buf + len), (size - len),
+ "--- %u bytes skipped ---\n",
+ (int)(count - (cut * 2)));
+ }
+
+ if ((!(i % 10)) && i) {
+ len += snprintf((buf + len), (DEBUGFS_BUF_SIZE - len),
+ "\n");
+ }
+ }
+ len += snprintf((buf + len), (DEBUGFS_BUF_SIZE - len), "\n");
+ return len;
+}
+
+static ssize_t dbgfs_frame(struct file *file, char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ char *buf;
+ int len = 0;
+ ssize_t size;
+ struct cfspi *cfspi;
+
+ cfspi = file->private_data;
+ buf = kzalloc(DEBUGFS_BUF_SIZE, GFP_KERNEL);
+ if (!buf)
+ return 0;
+
+ /* Print out debug information. */
+ len += snprintf((buf + len), (DEBUGFS_BUF_SIZE - len),
+ "Current frame:\n");
+
+ len += snprintf((buf + len), (DEBUGFS_BUF_SIZE - len),
+ "Tx data (Len: %d):\n", cfspi->tx_cpck_len);
+
+ len += print_frame((buf + len), (DEBUGFS_BUF_SIZE - len),
+ cfspi->xfer.va_tx,
+ (cfspi->tx_cpck_len + SPI_CMD_SZ), 100);
+
+ len += snprintf((buf + len), (DEBUGFS_BUF_SIZE - len),
+ "Rx data (Len: %d):\n", cfspi->rx_cpck_len);
+
+ len += print_frame((buf + len), (DEBUGFS_BUF_SIZE - len),
+ cfspi->xfer.va_rx,
+ (cfspi->rx_cpck_len + SPI_CMD_SZ), 100);
+
+ size = simple_read_from_buffer(user_buf, count, ppos, buf, len);
+ kfree(buf);
+
+ return size;
+}
+
+static const struct file_operations dbgfs_state_fops = {
+ .open = dbgfs_open,
+ .read = dbgfs_state,
+ .owner = THIS_MODULE
+};
+
+static const struct file_operations dbgfs_frame_fops = {
+ .open = dbgfs_open,
+ .read = dbgfs_frame,
+ .owner = THIS_MODULE
+};
+
+static inline void dev_debugfs_add(struct cfspi *cfspi)
+{
+ cfspi->dbgfs_dir = debugfs_create_dir(cfspi->pdev->name, dbgfs_root);
+ cfspi->dbgfs_state = debugfs_create_file("state", S_IRUGO,
+ cfspi->dbgfs_dir, cfspi,
+ &dbgfs_state_fops);
+ cfspi->dbgfs_frame = debugfs_create_file("frame", S_IRUGO,
+ cfspi->dbgfs_dir, cfspi,
+ &dbgfs_frame_fops);
+}
+
+inline void cfspi_dbg_state(struct cfspi *cfspi, int state)
+{
+ cfspi->dbg_state = state;
+};
+#else
+
+static inline void driver_debugfs_create(void)
+{
+}
+
+static inline void driver_debugfs_remove(void)
+{
+}
+
+static inline void dev_debugfs_add(struct cfspi *cfspi)
+{
+}
+
+static inline void dev_debugfs_rem(struct cfspi *cfspi)
+{
+}
+
+inline void cfspi_dbg_state(struct cfspi *cfspi, int state)
+{
+}
+#endif /* CONFIG_DEBUG_FS */
+
+static LIST_HEAD(cfspi_list);
+static spinlock_t cfspi_list_lock;
+
+/* SPI uplink head alignment. */
+static ssize_t show_up_head_align(struct device_driver *driver, char *buf)
+{
+ return sprintf(buf, "%d\n", spi_up_head_align);
+}
+
+static DRIVER_ATTR(up_head_align, S_IRUSR, show_up_head_align, NULL);
+
+/* SPI uplink tail alignment. */
+static ssize_t show_up_tail_align(struct device_driver *driver, char *buf)
+{
+ return sprintf(buf, "%d\n", spi_up_tail_align);
+}
+
+static DRIVER_ATTR(up_tail_align, S_IRUSR, show_up_tail_align, NULL);
+
+/* SPI downlink head alignment. */
+static ssize_t show_down_head_align(struct device_driver *driver, char *buf)
+{
+ return sprintf(buf, "%d\n", spi_down_head_align);
+}
+
+static DRIVER_ATTR(down_head_align, S_IRUSR, show_down_head_align, NULL);
+
+/* SPI downlink tail alignment. */
+static ssize_t show_down_tail_align(struct device_driver *driver, char *buf)
+{
+ return sprintf(buf, "%d\n", spi_down_tail_align);
+}
+
+static DRIVER_ATTR(down_tail_align, S_IRUSR, show_down_tail_align, NULL);
+
+/* SPI frame alignment. */
+static ssize_t show_frame_align(struct device_driver *driver, char *buf)
+{
+ return sprintf(buf, "%d\n", spi_frm_align);
+}
+
+static DRIVER_ATTR(frame_align, S_IRUSR, show_frame_align, NULL);
+
+int cfspi_xmitfrm(struct cfspi *cfspi, u8 *buf, size_t len)
+{
+ u8 *dst = buf;
+ caif_assert(buf);
+
+ do {
+ struct sk_buff *skb;
+ struct caif_payload_info *info;
+ int spad = 0;
+ int epad;
+
+ skb = skb_dequeue(&cfspi->chead);
+ if (!skb)
+ break;
+
+ /*
+ * Calculate length of frame including SPI padding.
+ * The payload position is found in the control buffer.
+ */
+ info = (struct caif_payload_info *)&skb->cb;
+
+ /*
+ * Compute head offset i.e. number of bytes to add to
+ * get the start of the payload aligned.
+ */
+ if (spi_up_head_align) {
+ spad = 1 + ((info->hdr_len + 1) & spi_up_head_align);
+ *dst = (u8)(spad - 1);
+ dst += spad;
+ }
+
+ /* Copy in CAIF frame. */
+ skb_copy_bits(skb, 0, dst, skb->len);
+ dst += skb->len;
+ cfspi->ndev->stats.tx_packets++;
+ cfspi->ndev->stats.tx_bytes += skb->len;
+
+ /*
+ * Compute tail offset i.e. number of bytes to add to
+ * get the complete CAIF frame aligned.
+ */
+ epad = (skb->len + spad) & spi_up_tail_align;
+ dst += epad;
+
+ dev_kfree_skb(skb);
+
+ } while ((dst - buf) < len);
+
+ return dst - buf;
+}
+
+int cfspi_xmitlen(struct cfspi *cfspi)
+{
+ struct sk_buff *skb = NULL;
+ int frm_len = 0;
+ int pkts = 0;
+
+ /*
+ * Decommit previously commited frames.
+ * skb_queue_splice_tail(&cfspi->chead,&cfspi->qhead)
+ */
+ while (skb_peek(&cfspi->chead)) {
+ skb = skb_dequeue_tail(&cfspi->chead);
+ skb_queue_head(&cfspi->qhead, skb);
+ }
+
+ do {
+ struct caif_payload_info *info = NULL;
+ int spad = 0;
+ int epad = 0;
+
+ skb = skb_dequeue(&cfspi->qhead);
+ if (!skb)
+ break;
+
+ /*
+ * Calculate length of frame including SPI padding.
+ * The payload position is found in the control buffer.
+ */
+ info = (struct caif_payload_info *)&skb->cb;
+
+ /*
+ * Compute head offset i.e. number of bytes to add to
+ * get the start of the payload aligned.
+ */
+ if (spi_up_head_align)
+ spad = 1 + ((info->hdr_len + 1) & spi_up_head_align);
+
+ /*
+ * Compute tail offset i.e. number of bytes to add to
+ * get the complete CAIF frame aligned.
+ */
+ epad = (skb->len + spad) & spi_up_tail_align;
+
+ if ((skb->len + spad + epad + frm_len) <= CAIF_MAX_SPI_FRAME) {
+ skb_queue_tail(&cfspi->chead, skb);
+ pkts++;
+ frm_len += skb->len + spad + epad;
+ } else {
+ /* Put back packet. */
+ skb_queue_head(&cfspi->qhead, skb);
+ }
+ } while (pkts <= CAIF_MAX_SPI_PKTS);
+
+ /*
+ * Send flow on if previously sent flow off
+ * and now go below the low water mark
+ */
+ if (cfspi->flow_off_sent && cfspi->qhead.qlen < cfspi->qd_low_mark &&
+ cfspi->cfdev.flowctrl) {
+ cfspi->flow_off_sent = 0;
+ cfspi->cfdev.flowctrl(cfspi->ndev, 1);
+ }
+
+ return frm_len;
+}
+
+static void cfspi_ss_cb(bool assert, struct cfspi_ifc *ifc)
+{
+ struct cfspi *cfspi = (struct cfspi *)ifc->priv;
+
+ if (!in_interrupt())
+ spin_lock(&cfspi->lock);
+ if (assert) {
+ set_bit(SPI_SS_ON, &cfspi->state);
+ set_bit(SPI_XFER, &cfspi->state);
+ } else {
+ set_bit(SPI_SS_OFF, &cfspi->state);
+ }
+ if (!in_interrupt())
+ spin_unlock(&cfspi->lock);
+
+ /* Wake up the xfer thread. */
+ wake_up_interruptible(&cfspi->wait);
+}
+
+static void cfspi_xfer_done_cb(struct cfspi_ifc *ifc)
+{
+ struct cfspi *cfspi = (struct cfspi *)ifc->priv;
+
+ /* Transfer done, complete work queue */
+ complete(&cfspi->comp);
+}
+
+static int cfspi_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+ struct cfspi *cfspi = NULL;
+ unsigned long flags;
+ if (!dev)
+ return -EINVAL;
+
+ cfspi = netdev_priv(dev);
+
+ skb_queue_tail(&cfspi->qhead, skb);
+
+ spin_lock_irqsave(&cfspi->lock, flags);
+ if (!test_and_set_bit(SPI_XFER, &cfspi->state)) {
+ /* Wake up xfer thread. */
+ wake_up_interruptible(&cfspi->wait);
+ }
+ spin_unlock_irqrestore(&cfspi->lock, flags);
+
+ /* Send flow off if number of bytes is above high water mark */
+ if (!cfspi->flow_off_sent &&
+ cfspi->qhead.qlen > cfspi->qd_high_mark &&
+ cfspi->cfdev.flowctrl) {
+ cfspi->flow_off_sent = 1;
+ cfspi->cfdev.flowctrl(cfspi->ndev, 0);
+ }
+
+ return 0;
+}
+
+int cfspi_rxfrm(struct cfspi *cfspi, u8 *buf, size_t len)
+{
+ u8 *src = buf;
+
+ caif_assert(buf != NULL);
+
+ do {
+ int res;
+ struct sk_buff *skb = NULL;
+ int spad = 0;
+ int epad = 0;
+ u8 *dst = NULL;
+ int pkt_len = 0;
+
+ /*
+ * Compute head offset i.e. number of bytes added to
+ * get the start of the payload aligned.
+ */
+ if (spi_down_head_align) {
+ spad = 1 + *src;
+ src += spad;
+ }
+
+ /* Read length of CAIF frame (little endian). */
+ pkt_len = *src;
+ pkt_len |= ((*(src+1)) << 8) & 0xFF00;
+ pkt_len += 2; /* Add FCS fields. */
+
+ /* Get a suitable caif packet and copy in data. */
+
+ skb = netdev_alloc_skb(cfspi->ndev, pkt_len + 1);
+ caif_assert(skb != NULL);
+
+ dst = skb_put(skb, pkt_len);
+ memcpy(dst, src, pkt_len);
+ src += pkt_len;
+
+ skb->protocol = htons(ETH_P_CAIF);
+ skb_reset_mac_header(skb);
+ skb->dev = cfspi->ndev;
+
+ /*
+ * Push received packet up the stack.
+ */
+ if (!spi_loop)
+ res = netif_rx_ni(skb);
+ else
+ res = cfspi_xmit(skb, cfspi->ndev);
+
+ if (!res) {
+ cfspi->ndev->stats.rx_packets++;
+ cfspi->ndev->stats.rx_bytes += pkt_len;
+ } else
+ cfspi->ndev->stats.rx_dropped++;
+
+ /*
+ * Compute tail offset i.e. number of bytes added to
+ * get the complete CAIF frame aligned.
+ */
+ epad = (pkt_len + spad) & spi_down_tail_align;
+ src += epad;
+ } while ((src - buf) < len);
+
+ return src - buf;
+}
+
+static int cfspi_open(struct net_device *dev)
+{
+ netif_wake_queue(dev);
+ return 0;
+}
+
+static int cfspi_close(struct net_device *dev)
+{
+ netif_stop_queue(dev);
+ return 0;
+}
+static const struct net_device_ops cfspi_ops = {
+ .ndo_open = cfspi_open,
+ .ndo_stop = cfspi_close,
+ .ndo_start_xmit = cfspi_xmit
+};
+
+static void cfspi_setup(struct net_device *dev)
+{
+ struct cfspi *cfspi = netdev_priv(dev);
+ dev->features = 0;
+ dev->netdev_ops = &cfspi_ops;
+ dev->type = ARPHRD_CAIF;
+ dev->flags = IFF_NOARP | IFF_POINTOPOINT;
+ dev->tx_queue_len = 0;
+ dev->mtu = SPI_MAX_PAYLOAD_SIZE;
+ dev->destructor = free_netdev;
+ skb_queue_head_init(&cfspi->qhead);
+ skb_queue_head_init(&cfspi->chead);
+ cfspi->cfdev.link_select = CAIF_LINK_HIGH_BANDW;
+ cfspi->cfdev.use_frag = false;
+ cfspi->cfdev.use_stx = false;
+ cfspi->cfdev.use_fcs = false;
+ cfspi->ndev = dev;
+}
+
+int cfspi_spi_probe(struct platform_device *pdev)
+{
+ struct cfspi *cfspi = NULL;
+ struct net_device *ndev;
+ struct cfspi_dev *dev;
+ int res;
+ dev = (struct cfspi_dev *)pdev->dev.platform_data;
+
+ ndev = alloc_netdev(sizeof(struct cfspi),
+ "cfspi%d", cfspi_setup);
+ if (!dev)
+ return -ENODEV;
+
+ cfspi = netdev_priv(ndev);
+ netif_stop_queue(ndev);
+ cfspi->ndev = ndev;
+ cfspi->pdev = pdev;
+
+ /* Set flow info */
+ cfspi->flow_off_sent = 0;
+ cfspi->qd_low_mark = LOW_WATER_MARK;
+ cfspi->qd_high_mark = HIGH_WATER_MARK;
+
+ /* Assign the SPI device. */
+ cfspi->dev = dev;
+ /* Assign the device ifc to this SPI interface. */
+ dev->ifc = &cfspi->ifc;
+
+ /* Allocate DMA buffers. */
+ cfspi->xfer.va_tx = dma_alloc(&cfspi->xfer.pa_tx);
+ if (!cfspi->xfer.va_tx) {
+ printk(KERN_WARNING
+ "CFSPI: failed to allocate dma TX buffer.\n");
+ res = -ENODEV;
+ goto err_dma_alloc_tx;
+ }
+
+ cfspi->xfer.va_rx = dma_alloc(&cfspi->xfer.pa_rx);
+
+ if (!cfspi->xfer.va_rx) {
+ printk(KERN_WARNING
+ "CFSPI: failed to allocate dma TX buffer.\n");
+ res = -ENODEV;
+ goto err_dma_alloc_rx;
+ }
+
+ /* Initialize the work queue. */
+ INIT_WORK(&cfspi->work, cfspi_xfer);
+
+ /* Initialize spin locks. */
+ spin_lock_init(&cfspi->lock);
+
+ /* Initialize flow control state. */
+ cfspi->flow_stop = false;
+
+ /* Initialize wait queue. */
+ init_waitqueue_head(&cfspi->wait);
+
+ /* Create work thread. */
+ cfspi->wq = create_singlethread_workqueue(dev->name);
+ if (!cfspi->wq) {
+ printk(KERN_WARNING "CFSPI: failed to create work queue.\n");
+ res = -ENODEV;
+ goto err_create_wq;
+ }
+
+ /* Initialize work queue. */
+ init_completion(&cfspi->comp);
+
+ /* Create debugfs entries. */
+ dev_debugfs_add(cfspi);
+
+ /* Set up the ifc. */
+ cfspi->ifc.ss_cb = cfspi_ss_cb;
+ cfspi->ifc.xfer_done_cb = cfspi_xfer_done_cb;
+ cfspi->ifc.priv = cfspi;
+
+ /* Add CAIF SPI device to list. */
+ spin_lock(&cfspi_list_lock);
+ list_add_tail(&cfspi->list, &cfspi_list);
+ spin_unlock(&cfspi_list_lock);
+
+ /* Schedule the work queue. */
+ queue_work(cfspi->wq, &cfspi->work);
+
+ /* Register network device. */
+ res = register_netdev(ndev);
+ if (res) {
+ printk(KERN_ERR "CFSPI: Reg. error: %d.\n", res);
+ goto err_net_reg;
+ }
+ return res;
+
+ err_net_reg:
+ dev_debugfs_rem(cfspi);
+ set_bit(SPI_TERMINATE, &cfspi->state);
+ wake_up_interruptible(&cfspi->wait);
+ destroy_workqueue(cfspi->wq);
+ err_create_wq:
+ dma_free(cfspi->xfer.va_rx, cfspi->xfer.pa_rx);
+ err_dma_alloc_rx:
+ dma_free(cfspi->xfer.va_tx, cfspi->xfer.pa_tx);
+ err_dma_alloc_tx:
+ free_netdev(ndev);
+
+ return res;
+}
+
+int cfspi_spi_remove(struct platform_device *pdev)
+{
+ struct list_head *list_node;
+ struct list_head *n;
+ struct cfspi *cfspi = NULL;
+ struct cfspi_dev *dev;
+
+ dev = (struct cfspi_dev *)pdev->dev.platform_data;
+ spin_lock(&cfspi_list_lock);
+ list_for_each_safe(list_node, n, &cfspi_list) {
+ cfspi = list_entry(list_node, struct cfspi, list);
+ /* Find the corresponding device. */
+ if (cfspi->dev == dev) {
+ /* Remove from list. */
+ list_del(list_node);
+ /* Free DMA buffers. */
+ dma_free(cfspi->xfer.va_rx, cfspi->xfer.pa_rx);
+ dma_free(cfspi->xfer.va_tx, cfspi->xfer.pa_tx);
+ set_bit(SPI_TERMINATE, &cfspi->state);
+ wake_up_interruptible(&cfspi->wait);
+ destroy_workqueue(cfspi->wq);
+ /* Destroy debugfs directory and files. */
+ dev_debugfs_rem(cfspi);
+ unregister_netdev(cfspi->ndev);
+ spin_unlock(&cfspi_list_lock);
+ return 0;
+ }
+ }
+ spin_unlock(&cfspi_list_lock);
+ return -ENODEV;
+}
+
+static void __exit cfspi_exit_module(void)
+{
+ struct list_head *list_node;
+ struct list_head *n;
+ struct cfspi *cfspi = NULL;
+
+ list_for_each_safe(list_node, n, &cfspi_list) {
+ cfspi = list_entry(list_node, struct cfspi, list);
+ platform_device_unregister(cfspi->pdev);
+ }
+
+ /* Destroy sysfs files. */
+ driver_remove_file(&cfspi_spi_driver.driver,
+ &driver_attr_up_head_align);
+ driver_remove_file(&cfspi_spi_driver.driver,
+ &driver_attr_up_tail_align);
+ driver_remove_file(&cfspi_spi_driver.driver,
+ &driver_attr_down_head_align);
+ driver_remove_file(&cfspi_spi_driver.driver,
+ &driver_attr_down_tail_align);
+ driver_remove_file(&cfspi_spi_driver.driver, &driver_attr_frame_align);
+ /* Unregister platform driver. */
+ platform_driver_unregister(&cfspi_spi_driver);
+ /* Destroy debugfs root directory. */
+ driver_debugfs_remove();
+}
+
+static int __init cfspi_init_module(void)
+{
+ int result;
+
+ /* Initialize spin lock. */
+ spin_lock_init(&cfspi_list_lock);
+
+ /* Register platform driver. */
+ result = platform_driver_register(&cfspi_spi_driver);
+ if (result) {
+ printk(KERN_ERR "Could not register platform SPI driver.\n");
+ goto err_dev_register;
+ }
+
+ /* Create sysfs files. */
+ result =
+ driver_create_file(&cfspi_spi_driver.driver,
+ &driver_attr_up_head_align);
+ if (result) {
+ printk(KERN_ERR "Sysfs creation failed 1.\n");
+ goto err_create_up_head_align;
+ }
+
+ result =
+ driver_create_file(&cfspi_spi_driver.driver,
+ &driver_attr_up_tail_align);
+ if (result) {
+ printk(KERN_ERR "Sysfs creation failed 2.\n");
+ goto err_create_up_tail_align;
+ }
+
+ result =
+ driver_create_file(&cfspi_spi_driver.driver,
+ &driver_attr_down_head_align);
+ if (result) {
+ printk(KERN_ERR "Sysfs creation failed 3.\n");
+ goto err_create_down_head_align;
+ }
+
+ result =
+ driver_create_file(&cfspi_spi_driver.driver,
+ &driver_attr_down_tail_align);
+ if (result) {
+ printk(KERN_ERR "Sysfs creation failed 4.\n");
+ goto err_create_down_tail_align;
+ }
+
+ result =
+ driver_create_file(&cfspi_spi_driver.driver,
+ &driver_attr_frame_align);
+ if (result) {
+ printk(KERN_ERR "Sysfs creation failed 5.\n");
+ goto err_create_frame_align;
+ }
+ driver_debugfs_create();
+ return result;
+
+ err_create_frame_align:
+ driver_remove_file(&cfspi_spi_driver.driver,
+ &driver_attr_down_tail_align);
+ err_create_down_tail_align:
+ driver_remove_file(&cfspi_spi_driver.driver,
+ &driver_attr_down_head_align);
+ err_create_down_head_align:
+ driver_remove_file(&cfspi_spi_driver.driver,
+ &driver_attr_up_tail_align);
+ err_create_up_tail_align:
+ driver_remove_file(&cfspi_spi_driver.driver,
+ &driver_attr_up_head_align);
+ err_create_up_head_align:
+ err_dev_register:
+ return result;
+}
+
+module_init(cfspi_init_module);
+module_exit(cfspi_exit_module);
diff --git a/drivers/net/caif/caif_spi_slave.c b/drivers/net/caif/caif_spi_slave.c
new file mode 100644
index 00000000000..077ccf840ed
--- /dev/null
+++ b/drivers/net/caif/caif_spi_slave.c
@@ -0,0 +1,252 @@
+/*
+ * Copyright (C) ST-Ericsson AB 2010
+ * Contact: Sjur Brendeland / sjur.brandeland@stericsson.com
+ * Author: Daniel Martensson / Daniel.Martensson@stericsson.com
+ * License terms: GNU General Public License (GPL) version 2.
+ */
+#include <linux/version.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/string.h>
+#include <linux/semaphore.h>
+#include <linux/workqueue.h>
+#include <linux/completion.h>
+#include <linux/list.h>
+#include <linux/interrupt.h>
+#include <linux/dma-mapping.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <linux/debugfs.h>
+#include <net/caif/caif_spi.h>
+
+#ifndef CONFIG_CAIF_SPI_SYNC
+#define SPI_DATA_POS SPI_CMD_SZ
+static inline int forward_to_spi_cmd(struct cfspi *cfspi)
+{
+ return cfspi->rx_cpck_len;
+}
+#else
+#define SPI_DATA_POS 0
+static inline int forward_to_spi_cmd(struct cfspi *cfspi)
+{
+ return 0;
+}
+#endif
+
+int spi_frm_align = 2;
+int spi_up_head_align = 1;
+int spi_up_tail_align;
+int spi_down_head_align = 3;
+int spi_down_tail_align = 1;
+
+#ifdef CONFIG_DEBUG_FS
+static inline void debugfs_store_prev(struct cfspi *cfspi)
+{
+ /* Store previous command for debugging reasons.*/
+ cfspi->pcmd = cfspi->cmd;
+ /* Store previous transfer. */
+ cfspi->tx_ppck_len = cfspi->tx_cpck_len;
+ cfspi->rx_ppck_len = cfspi->rx_cpck_len;
+}
+#else
+static inline void debugfs_store_prev(struct cfspi *cfspi)
+{
+}
+#endif
+
+void cfspi_xfer(struct work_struct *work)
+{
+ struct cfspi *cfspi;
+ u8 *ptr = NULL;
+ unsigned long flags;
+ int ret;
+ cfspi = container_of(work, struct cfspi, work);
+
+ /* Initialize state. */
+ cfspi->cmd = SPI_CMD_EOT;
+
+ for (;;) {
+
+ cfspi_dbg_state(cfspi, CFSPI_STATE_WAITING);
+
+ /* Wait for master talk or transmit event. */
+ wait_event_interruptible(cfspi->wait,
+ test_bit(SPI_XFER, &cfspi->state) ||
+ test_bit(SPI_TERMINATE, &cfspi->state));
+
+ if (test_bit(SPI_TERMINATE, &cfspi->state))
+ return;
+
+#if CFSPI_DBG_PREFILL
+ /* Prefill buffers for easier debugging. */
+ memset(cfspi->xfer.va_tx, 0xFF, SPI_DMA_BUF_LEN);
+ memset(cfspi->xfer.va_rx, 0xFF, SPI_DMA_BUF_LEN);
+#endif /* CFSPI_DBG_PREFILL */
+
+ cfspi_dbg_state(cfspi, CFSPI_STATE_AWAKE);
+
+ /* Check whether we have a committed frame. */
+ if (cfspi->tx_cpck_len) {
+ int len;
+
+ cfspi_dbg_state(cfspi, CFSPI_STATE_FETCH_PKT);
+
+ /* Copy commited SPI frames after the SPI indication. */
+ ptr = (u8 *) cfspi->xfer.va_tx;
+ ptr += SPI_IND_SZ;
+ len = cfspi_xmitfrm(cfspi, ptr, cfspi->tx_cpck_len);
+ WARN_ON(len != cfspi->tx_cpck_len);
+ }
+
+ cfspi_dbg_state(cfspi, CFSPI_STATE_GET_NEXT);
+
+ /* Get length of next frame to commit. */
+ cfspi->tx_npck_len = cfspi_xmitlen(cfspi);
+
+ WARN_ON(cfspi->tx_npck_len > SPI_DMA_BUF_LEN);
+
+ /*
+ * Add indication and length at the beginning of the frame,
+ * using little endian.
+ */
+ ptr = (u8 *) cfspi->xfer.va_tx;
+ *ptr++ = SPI_CMD_IND;
+ *ptr++ = (SPI_CMD_IND & 0xFF00) >> 8;
+ *ptr++ = cfspi->tx_npck_len & 0x00FF;
+ *ptr++ = (cfspi->tx_npck_len & 0xFF00) >> 8;
+
+ /* Calculate length of DMAs. */
+ cfspi->xfer.tx_dma_len = cfspi->tx_cpck_len + SPI_IND_SZ;
+ cfspi->xfer.rx_dma_len = cfspi->rx_cpck_len + SPI_CMD_SZ;
+
+ /* Add SPI TX frame alignment padding, if necessary. */
+ if (cfspi->tx_cpck_len &&
+ (cfspi->xfer.tx_dma_len % spi_frm_align)) {
+
+ cfspi->xfer.tx_dma_len += spi_frm_align -
+ (cfspi->xfer.tx_dma_len % spi_frm_align);
+ }
+
+ /* Add SPI RX frame alignment padding, if necessary. */
+ if (cfspi->rx_cpck_len &&
+ (cfspi->xfer.rx_dma_len % spi_frm_align)) {
+
+ cfspi->xfer.rx_dma_len += spi_frm_align -
+ (cfspi->xfer.rx_dma_len % spi_frm_align);
+ }
+
+ cfspi_dbg_state(cfspi, CFSPI_STATE_INIT_XFER);
+
+ /* Start transfer. */
+ ret = cfspi->dev->init_xfer(&cfspi->xfer, cfspi->dev);
+ WARN_ON(ret);
+
+ cfspi_dbg_state(cfspi, CFSPI_STATE_WAIT_ACTIVE);
+
+ /*
+ * TODO: We might be able to make an assumption if this is the
+ * first loop. Make sure that minimum toggle time is respected.
+ */
+ udelay(MIN_TRANSITION_TIME_USEC);
+
+ cfspi_dbg_state(cfspi, CFSPI_STATE_SIG_ACTIVE);
+
+ /* Signal that we are ready to recieve data. */
+ cfspi->dev->sig_xfer(true, cfspi->dev);
+
+ cfspi_dbg_state(cfspi, CFSPI_STATE_WAIT_XFER_DONE);
+
+ /* Wait for transfer completion. */
+ wait_for_completion(&cfspi->comp);
+
+ cfspi_dbg_state(cfspi, CFSPI_STATE_XFER_DONE);
+
+ if (cfspi->cmd == SPI_CMD_EOT) {
+ /*
+ * Clear the master talk bit. A xfer is always at
+ * least two bursts.
+ */
+ clear_bit(SPI_SS_ON, &cfspi->state);
+ }
+
+ cfspi_dbg_state(cfspi, CFSPI_STATE_WAIT_INACTIVE);
+
+ /* Make sure that the minimum toggle time is respected. */
+ if (SPI_XFER_TIME_USEC(cfspi->xfer.tx_dma_len,
+ cfspi->dev->clk_mhz) <
+ MIN_TRANSITION_TIME_USEC) {
+
+ udelay(MIN_TRANSITION_TIME_USEC -
+ SPI_XFER_TIME_USEC
+ (cfspi->xfer.tx_dma_len, cfspi->dev->clk_mhz));
+ }
+
+ cfspi_dbg_state(cfspi, CFSPI_STATE_SIG_INACTIVE);
+
+ /* De-assert transfer signal. */
+ cfspi->dev->sig_xfer(false, cfspi->dev);
+
+ /* Check whether we received a CAIF packet. */
+ if (cfspi->rx_cpck_len) {
+ int len;
+
+ cfspi_dbg_state(cfspi, CFSPI_STATE_DELIVER_PKT);
+
+ /* Parse SPI frame. */
+ ptr = ((u8 *)(cfspi->xfer.va_rx + SPI_DATA_POS));
+
+ len = cfspi_rxfrm(cfspi, ptr, cfspi->rx_cpck_len);
+ WARN_ON(len != cfspi->rx_cpck_len);
+ }
+
+ /* Check the next SPI command and length. */
+ ptr = (u8 *) cfspi->xfer.va_rx;
+
+ ptr += forward_to_spi_cmd(cfspi);
+
+ cfspi->cmd = *ptr++;
+ cfspi->cmd |= ((*ptr++) << 8) & 0xFF00;
+ cfspi->rx_npck_len = *ptr++;
+ cfspi->rx_npck_len |= ((*ptr++) << 8) & 0xFF00;
+
+ WARN_ON(cfspi->rx_npck_len > SPI_DMA_BUF_LEN);
+ WARN_ON(cfspi->cmd > SPI_CMD_EOT);
+
+ debugfs_store_prev(cfspi);
+
+ /* Check whether the master issued an EOT command. */
+ if (cfspi->cmd == SPI_CMD_EOT) {
+ /* Reset state. */
+ cfspi->tx_cpck_len = 0;
+ cfspi->rx_cpck_len = 0;
+ } else {
+ /* Update state. */
+ cfspi->tx_cpck_len = cfspi->tx_npck_len;
+ cfspi->rx_cpck_len = cfspi->rx_npck_len;
+ }
+
+ /*
+ * Check whether we need to clear the xfer bit.
+ * Spin lock needed for packet insertion.
+ * Test and clear of different bits
+ * are not supported.
+ */
+ spin_lock_irqsave(&cfspi->lock, flags);
+ if (cfspi->cmd == SPI_CMD_EOT && !cfspi_xmitlen(cfspi)
+ && !test_bit(SPI_SS_ON, &cfspi->state))
+ clear_bit(SPI_XFER, &cfspi->state);
+
+ spin_unlock_irqrestore(&cfspi->lock, flags);
+ }
+}
+
+struct platform_driver cfspi_spi_driver = {
+ .probe = cfspi_spi_probe,
+ .remove = cfspi_spi_remove,
+ .driver = {
+ .name = "cfspi_sspi",
+ .owner = THIS_MODULE,
+ },
+};
diff --git a/drivers/net/can/Kconfig b/drivers/net/can/Kconfig
index 2c5227c02fa..9d9e4539443 100644
--- a/drivers/net/can/Kconfig
+++ b/drivers/net/can/Kconfig
@@ -73,6 +73,15 @@ config CAN_JANZ_ICAN3
This driver can also be built as a module. If so, the module will be
called janz-ican3.ko.
+config HAVE_CAN_FLEXCAN
+ bool
+
+config CAN_FLEXCAN
+ tristate "Support for Freescale FLEXCAN based chips"
+ depends on CAN_DEV && HAVE_CAN_FLEXCAN
+ ---help---
+ Say Y here if you want to support for Freescale FlexCAN.
+
source "drivers/net/can/mscan/Kconfig"
source "drivers/net/can/sja1000/Kconfig"
diff --git a/drivers/net/can/Makefile b/drivers/net/can/Makefile
index 9047cd066fe..00575373bbd 100644
--- a/drivers/net/can/Makefile
+++ b/drivers/net/can/Makefile
@@ -16,5 +16,6 @@ obj-$(CONFIG_CAN_TI_HECC) += ti_hecc.o
obj-$(CONFIG_CAN_MCP251X) += mcp251x.o
obj-$(CONFIG_CAN_BFIN) += bfin_can.o
obj-$(CONFIG_CAN_JANZ_ICAN3) += janz-ican3.o
+obj-$(CONFIG_CAN_FLEXCAN) += flexcan.o
ccflags-$(CONFIG_CAN_DEBUG_DEVICES) := -DDEBUG
diff --git a/drivers/net/can/flexcan.c b/drivers/net/can/flexcan.c
new file mode 100644
index 00000000000..ef443a090ba
--- /dev/null
+++ b/drivers/net/can/flexcan.c
@@ -0,0 +1,1030 @@
+/*
+ * flexcan.c - FLEXCAN CAN controller driver
+ *
+ * Copyright (c) 2005-2006 Varma Electronics Oy
+ * Copyright (c) 2009 Sascha Hauer, Pengutronix
+ * Copyright (c) 2010 Marc Kleine-Budde, Pengutronix
+ *
+ * Based on code originally by Andrey Volkov <avolkov@varma-el.com>
+ *
+ * LICENCE:
+ * This program is free software; 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/netdevice.h>
+#include <linux/can.h>
+#include <linux/can/dev.h>
+#include <linux/can/error.h>
+#include <linux/can/platform/flexcan.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/if_arp.h>
+#include <linux/if_ether.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+
+#include <mach/clock.h>
+
+#define DRV_NAME "flexcan"
+
+/* 8 for RX fifo and 2 error handling */
+#define FLEXCAN_NAPI_WEIGHT (8 + 2)
+
+/* FLEXCAN module configuration register (CANMCR) bits */
+#define FLEXCAN_MCR_MDIS BIT(31)
+#define FLEXCAN_MCR_FRZ BIT(30)
+#define FLEXCAN_MCR_FEN BIT(29)
+#define FLEXCAN_MCR_HALT BIT(28)
+#define FLEXCAN_MCR_NOT_RDY BIT(27)
+#define FLEXCAN_MCR_WAK_MSK BIT(26)
+#define FLEXCAN_MCR_SOFTRST BIT(25)
+#define FLEXCAN_MCR_FRZ_ACK BIT(24)
+#define FLEXCAN_MCR_SUPV BIT(23)
+#define FLEXCAN_MCR_SLF_WAK BIT(22)
+#define FLEXCAN_MCR_WRN_EN BIT(21)
+#define FLEXCAN_MCR_LPM_ACK BIT(20)
+#define FLEXCAN_MCR_WAK_SRC BIT(19)
+#define FLEXCAN_MCR_DOZE BIT(18)
+#define FLEXCAN_MCR_SRX_DIS BIT(17)
+#define FLEXCAN_MCR_BCC BIT(16)
+#define FLEXCAN_MCR_LPRIO_EN BIT(13)
+#define FLEXCAN_MCR_AEN BIT(12)
+#define FLEXCAN_MCR_MAXMB(x) ((x) & 0xf)
+#define FLEXCAN_MCR_IDAM_A (0 << 8)
+#define FLEXCAN_MCR_IDAM_B (1 << 8)
+#define FLEXCAN_MCR_IDAM_C (2 << 8)
+#define FLEXCAN_MCR_IDAM_D (3 << 8)
+
+/* FLEXCAN control register (CANCTRL) bits */
+#define FLEXCAN_CTRL_PRESDIV(x) (((x) & 0xff) << 24)
+#define FLEXCAN_CTRL_RJW(x) (((x) & 0x03) << 22)
+#define FLEXCAN_CTRL_PSEG1(x) (((x) & 0x07) << 19)
+#define FLEXCAN_CTRL_PSEG2(x) (((x) & 0x07) << 16)
+#define FLEXCAN_CTRL_BOFF_MSK BIT(15)
+#define FLEXCAN_CTRL_ERR_MSK BIT(14)
+#define FLEXCAN_CTRL_CLK_SRC BIT(13)
+#define FLEXCAN_CTRL_LPB BIT(12)
+#define FLEXCAN_CTRL_TWRN_MSK BIT(11)
+#define FLEXCAN_CTRL_RWRN_MSK BIT(10)
+#define FLEXCAN_CTRL_SMP BIT(7)
+#define FLEXCAN_CTRL_BOFF_REC BIT(6)
+#define FLEXCAN_CTRL_TSYN BIT(5)
+#define FLEXCAN_CTRL_LBUF BIT(4)
+#define FLEXCAN_CTRL_LOM BIT(3)
+#define FLEXCAN_CTRL_PROPSEG(x) ((x) & 0x07)
+#define FLEXCAN_CTRL_ERR_BUS (FLEXCAN_CTRL_ERR_MSK)
+#define FLEXCAN_CTRL_ERR_STATE \
+ (FLEXCAN_CTRL_TWRN_MSK | FLEXCAN_CTRL_RWRN_MSK | \
+ FLEXCAN_CTRL_BOFF_MSK)
+#define FLEXCAN_CTRL_ERR_ALL \
+ (FLEXCAN_CTRL_ERR_BUS | FLEXCAN_CTRL_ERR_STATE)
+
+/* FLEXCAN error and status register (ESR) bits */
+#define FLEXCAN_ESR_TWRN_INT BIT(17)
+#define FLEXCAN_ESR_RWRN_INT BIT(16)
+#define FLEXCAN_ESR_BIT1_ERR BIT(15)
+#define FLEXCAN_ESR_BIT0_ERR BIT(14)
+#define FLEXCAN_ESR_ACK_ERR BIT(13)
+#define FLEXCAN_ESR_CRC_ERR BIT(12)
+#define FLEXCAN_ESR_FRM_ERR BIT(11)
+#define FLEXCAN_ESR_STF_ERR BIT(10)
+#define FLEXCAN_ESR_TX_WRN BIT(9)
+#define FLEXCAN_ESR_RX_WRN BIT(8)
+#define FLEXCAN_ESR_IDLE BIT(7)
+#define FLEXCAN_ESR_TXRX BIT(6)
+#define FLEXCAN_EST_FLT_CONF_SHIFT (4)
+#define FLEXCAN_ESR_FLT_CONF_MASK (0x3 << FLEXCAN_EST_FLT_CONF_SHIFT)
+#define FLEXCAN_ESR_FLT_CONF_ACTIVE (0x0 << FLEXCAN_EST_FLT_CONF_SHIFT)
+#define FLEXCAN_ESR_FLT_CONF_PASSIVE (0x1 << FLEXCAN_EST_FLT_CONF_SHIFT)
+#define FLEXCAN_ESR_BOFF_INT BIT(2)
+#define FLEXCAN_ESR_ERR_INT BIT(1)
+#define FLEXCAN_ESR_WAK_INT BIT(0)
+#define FLEXCAN_ESR_ERR_BUS \
+ (FLEXCAN_ESR_BIT1_ERR | FLEXCAN_ESR_BIT0_ERR | \
+ FLEXCAN_ESR_ACK_ERR | FLEXCAN_ESR_CRC_ERR | \
+ FLEXCAN_ESR_FRM_ERR | FLEXCAN_ESR_STF_ERR)
+#define FLEXCAN_ESR_ERR_STATE \
+ (FLEXCAN_ESR_TWRN_INT | FLEXCAN_ESR_RWRN_INT | FLEXCAN_ESR_BOFF_INT)
+#define FLEXCAN_ESR_ERR_ALL \
+ (FLEXCAN_ESR_ERR_BUS | FLEXCAN_ESR_ERR_STATE)
+
+/* FLEXCAN interrupt flag register (IFLAG) bits */
+#define FLEXCAN_TX_BUF_ID 8
+#define FLEXCAN_IFLAG_BUF(x) BIT(x)
+#define FLEXCAN_IFLAG_RX_FIFO_OVERFLOW BIT(7)
+#define FLEXCAN_IFLAG_RX_FIFO_WARN BIT(6)
+#define FLEXCAN_IFLAG_RX_FIFO_AVAILABLE BIT(5)
+#define FLEXCAN_IFLAG_DEFAULT \
+ (FLEXCAN_IFLAG_RX_FIFO_OVERFLOW | FLEXCAN_IFLAG_RX_FIFO_AVAILABLE | \
+ FLEXCAN_IFLAG_BUF(FLEXCAN_TX_BUF_ID))
+
+/* FLEXCAN message buffers */
+#define FLEXCAN_MB_CNT_CODE(x) (((x) & 0xf) << 24)
+#define FLEXCAN_MB_CNT_SRR BIT(22)
+#define FLEXCAN_MB_CNT_IDE BIT(21)
+#define FLEXCAN_MB_CNT_RTR BIT(20)
+#define FLEXCAN_MB_CNT_LENGTH(x) (((x) & 0xf) << 16)
+#define FLEXCAN_MB_CNT_TIMESTAMP(x) ((x) & 0xffff)
+
+#define FLEXCAN_MB_CODE_MASK (0xf0ffffff)
+
+/* Structure of the message buffer */
+struct flexcan_mb {
+ u32 can_ctrl;
+ u32 can_id;
+ u32 data[2];
+};
+
+/* Structure of the hardware registers */
+struct flexcan_regs {
+ u32 mcr; /* 0x00 */
+ u32 ctrl; /* 0x04 */
+ u32 timer; /* 0x08 */
+ u32 _reserved1; /* 0x0c */
+ u32 rxgmask; /* 0x10 */
+ u32 rx14mask; /* 0x14 */
+ u32 rx15mask; /* 0x18 */
+ u32 ecr; /* 0x1c */
+ u32 esr; /* 0x20 */
+ u32 imask2; /* 0x24 */
+ u32 imask1; /* 0x28 */
+ u32 iflag2; /* 0x2c */
+ u32 iflag1; /* 0x30 */
+ u32 _reserved2[19];
+ struct flexcan_mb cantxfg[64];
+};
+
+struct flexcan_priv {
+ struct can_priv can;
+ struct net_device *dev;
+ struct napi_struct napi;
+
+ void __iomem *base;
+ u32 reg_esr;
+ u32 reg_ctrl_default;
+
+ struct clk *clk;
+ struct flexcan_platform_data *pdata;
+};
+
+static struct can_bittiming_const flexcan_bittiming_const = {
+ .name = DRV_NAME,
+ .tseg1_min = 4,
+ .tseg1_max = 16,
+ .tseg2_min = 2,
+ .tseg2_max = 8,
+ .sjw_max = 4,
+ .brp_min = 1,
+ .brp_max = 256,
+ .brp_inc = 1,
+};
+
+/*
+ * Swtich transceiver on or off
+ */
+static void flexcan_transceiver_switch(const struct flexcan_priv *priv, int on)
+{
+ if (priv->pdata && priv->pdata->transceiver_switch)
+ priv->pdata->transceiver_switch(on);
+}
+
+static inline int flexcan_has_and_handle_berr(const struct flexcan_priv *priv,
+ u32 reg_esr)
+{
+ return (priv->can.ctrlmode & CAN_CTRLMODE_BERR_REPORTING) &&
+ (reg_esr & FLEXCAN_ESR_ERR_BUS);
+}
+
+static inline void flexcan_chip_enable(struct flexcan_priv *priv)
+{
+ struct flexcan_regs __iomem *regs = priv->base;
+ u32 reg;
+
+ reg = readl(&regs->mcr);
+ reg &= ~FLEXCAN_MCR_MDIS;
+ writel(reg, &regs->mcr);
+
+ udelay(10);
+}
+
+static inline void flexcan_chip_disable(struct flexcan_priv *priv)
+{
+ struct flexcan_regs __iomem *regs = priv->base;
+ u32 reg;
+
+ reg = readl(&regs->mcr);
+ reg |= FLEXCAN_MCR_MDIS;
+ writel(reg, &regs->mcr);
+}
+
+static int flexcan_get_berr_counter(const struct net_device *dev,
+ struct can_berr_counter *bec)
+{
+ const struct flexcan_priv *priv = netdev_priv(dev);
+ struct flexcan_regs __iomem *regs = priv->base;
+ u32 reg = readl(&regs->ecr);
+
+ bec->txerr = (reg >> 0) & 0xff;
+ bec->rxerr = (reg >> 8) & 0xff;
+
+ return 0;
+}
+
+static int flexcan_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+ const struct flexcan_priv *priv = netdev_priv(dev);
+ struct net_device_stats *stats = &dev->stats;
+ struct flexcan_regs __iomem *regs = priv->base;
+ struct can_frame *cf = (struct can_frame *)skb->data;
+ u32 can_id;
+ u32 ctrl = FLEXCAN_MB_CNT_CODE(0xc) | (cf->can_dlc << 16);
+
+ if (can_dropped_invalid_skb(dev, skb))
+ return NETDEV_TX_OK;
+
+ netif_stop_queue(dev);
+
+ if (cf->can_id & CAN_EFF_FLAG) {
+ can_id = cf->can_id & CAN_EFF_MASK;
+ ctrl |= FLEXCAN_MB_CNT_IDE | FLEXCAN_MB_CNT_SRR;
+ } else {
+ can_id = (cf->can_id & CAN_SFF_MASK) << 18;
+ }
+
+ if (cf->can_id & CAN_RTR_FLAG)
+ ctrl |= FLEXCAN_MB_CNT_RTR;
+
+ if (cf->can_dlc > 0) {
+ u32 data = be32_to_cpup((__be32 *)&cf->data[0]);
+ writel(data, &regs->cantxfg[FLEXCAN_TX_BUF_ID].data[0]);
+ }
+ if (cf->can_dlc > 3) {
+ u32 data = be32_to_cpup((__be32 *)&cf->data[4]);
+ writel(data, &regs->cantxfg[FLEXCAN_TX_BUF_ID].data[1]);
+ }
+
+ writel(can_id, &regs->cantxfg[FLEXCAN_TX_BUF_ID].can_id);
+ writel(ctrl, &regs->cantxfg[FLEXCAN_TX_BUF_ID].can_ctrl);
+
+ kfree_skb(skb);
+
+ /* tx_packets is incremented in flexcan_irq */
+ stats->tx_bytes += cf->can_dlc;
+
+ return NETDEV_TX_OK;
+}
+
+static void do_bus_err(struct net_device *dev,
+ struct can_frame *cf, u32 reg_esr)
+{
+ struct flexcan_priv *priv = netdev_priv(dev);
+ int rx_errors = 0, tx_errors = 0;
+
+ cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR;
+
+ if (reg_esr & FLEXCAN_ESR_BIT1_ERR) {
+ dev_dbg(dev->dev.parent, "BIT1_ERR irq\n");
+ cf->data[2] |= CAN_ERR_PROT_BIT1;
+ tx_errors = 1;
+ }
+ if (reg_esr & FLEXCAN_ESR_BIT0_ERR) {
+ dev_dbg(dev->dev.parent, "BIT0_ERR irq\n");
+ cf->data[2] |= CAN_ERR_PROT_BIT0;
+ tx_errors = 1;
+ }
+ if (reg_esr & FLEXCAN_ESR_ACK_ERR) {
+ dev_dbg(dev->dev.parent, "ACK_ERR irq\n");
+ cf->can_id |= CAN_ERR_ACK;
+ cf->data[3] |= CAN_ERR_PROT_LOC_ACK;
+ tx_errors = 1;
+ }
+ if (reg_esr & FLEXCAN_ESR_CRC_ERR) {
+ dev_dbg(dev->dev.parent, "CRC_ERR irq\n");
+ cf->data[2] |= CAN_ERR_PROT_BIT;
+ cf->data[3] |= CAN_ERR_PROT_LOC_CRC_SEQ;
+ rx_errors = 1;
+ }
+ if (reg_esr & FLEXCAN_ESR_FRM_ERR) {
+ dev_dbg(dev->dev.parent, "FRM_ERR irq\n");
+ cf->data[2] |= CAN_ERR_PROT_FORM;
+ rx_errors = 1;
+ }
+ if (reg_esr & FLEXCAN_ESR_STF_ERR) {
+ dev_dbg(dev->dev.parent, "STF_ERR irq\n");
+ cf->data[2] |= CAN_ERR_PROT_STUFF;
+ rx_errors = 1;
+ }
+
+ priv->can.can_stats.bus_error++;
+ if (rx_errors)
+ dev->stats.rx_errors++;
+ if (tx_errors)
+ dev->stats.tx_errors++;
+}
+
+static int flexcan_poll_bus_err(struct net_device *dev, u32 reg_esr)
+{
+ struct sk_buff *skb;
+ struct can_frame *cf;
+
+ skb = alloc_can_err_skb(dev, &cf);
+ if (unlikely(!skb))
+ return 0;
+
+ do_bus_err(dev, cf, reg_esr);
+ netif_receive_skb(skb);
+
+ dev->stats.rx_packets++;
+ dev->stats.rx_bytes += cf->can_dlc;
+
+ return 1;
+}
+
+static void do_state(struct net_device *dev,
+ struct can_frame *cf, enum can_state new_state)
+{
+ struct flexcan_priv *priv = netdev_priv(dev);
+ struct can_berr_counter bec;
+
+ flexcan_get_berr_counter(dev, &bec);
+
+ switch (priv->can.state) {
+ case CAN_STATE_ERROR_ACTIVE:
+ /*
+ * from: ERROR_ACTIVE
+ * to : ERROR_WARNING, ERROR_PASSIVE, BUS_OFF
+ * => : there was a warning int
+ */
+ if (new_state >= CAN_STATE_ERROR_WARNING &&
+ new_state <= CAN_STATE_BUS_OFF) {
+ dev_dbg(dev->dev.parent, "Error Warning IRQ\n");
+ priv->can.can_stats.error_warning++;
+
+ cf->can_id |= CAN_ERR_CRTL;
+ cf->data[1] = (bec.txerr > bec.rxerr) ?
+ CAN_ERR_CRTL_TX_WARNING :
+ CAN_ERR_CRTL_RX_WARNING;
+ }
+ case CAN_STATE_ERROR_WARNING: /* fallthrough */
+ /*
+ * from: ERROR_ACTIVE, ERROR_WARNING
+ * to : ERROR_PASSIVE, BUS_OFF
+ * => : error passive int
+ */
+ if (new_state >= CAN_STATE_ERROR_PASSIVE &&
+ new_state <= CAN_STATE_BUS_OFF) {
+ dev_dbg(dev->dev.parent, "Error Passive IRQ\n");
+ priv->can.can_stats.error_passive++;
+
+ cf->can_id |= CAN_ERR_CRTL;
+ cf->data[1] = (bec.txerr > bec.rxerr) ?
+ CAN_ERR_CRTL_TX_PASSIVE :
+ CAN_ERR_CRTL_RX_PASSIVE;
+ }
+ break;
+ case CAN_STATE_BUS_OFF:
+ dev_err(dev->dev.parent,
+ "BUG! hardware recovered automatically from BUS_OFF\n");
+ break;
+ default:
+ break;
+ }
+
+ /* process state changes depending on the new state */
+ switch (new_state) {
+ case CAN_STATE_ERROR_ACTIVE:
+ dev_dbg(dev->dev.parent, "Error Active\n");
+ cf->can_id |= CAN_ERR_PROT;
+ cf->data[2] = CAN_ERR_PROT_ACTIVE;
+ break;
+ case CAN_STATE_BUS_OFF:
+ cf->can_id |= CAN_ERR_BUSOFF;
+ can_bus_off(dev);
+ break;
+ default:
+ break;
+ }
+}
+
+static int flexcan_poll_state(struct net_device *dev, u32 reg_esr)
+{
+ struct flexcan_priv *priv = netdev_priv(dev);
+ struct sk_buff *skb;
+ struct can_frame *cf;
+ enum can_state new_state;
+ int flt;
+
+ flt = reg_esr & FLEXCAN_ESR_FLT_CONF_MASK;
+ if (likely(flt == FLEXCAN_ESR_FLT_CONF_ACTIVE)) {
+ if (likely(!(reg_esr & (FLEXCAN_ESR_TX_WRN |
+ FLEXCAN_ESR_RX_WRN))))
+ new_state = CAN_STATE_ERROR_ACTIVE;
+ else
+ new_state = CAN_STATE_ERROR_WARNING;
+ } else if (unlikely(flt == FLEXCAN_ESR_FLT_CONF_PASSIVE))
+ new_state = CAN_STATE_ERROR_PASSIVE;
+ else
+ new_state = CAN_STATE_BUS_OFF;
+
+ /* state hasn't changed */
+ if (likely(new_state == priv->can.state))
+ return 0;
+
+ skb = alloc_can_err_skb(dev, &cf);
+ if (unlikely(!skb))
+ return 0;
+
+ do_state(dev, cf, new_state);
+ priv->can.state = new_state;
+ netif_receive_skb(skb);
+
+ dev->stats.rx_packets++;
+ dev->stats.rx_bytes += cf->can_dlc;
+
+ return 1;
+}
+
+static void flexcan_read_fifo(const struct net_device *dev,
+ struct can_frame *cf)
+{
+ const struct flexcan_priv *priv = netdev_priv(dev);
+ struct flexcan_regs __iomem *regs = priv->base;
+ struct flexcan_mb __iomem *mb = &regs->cantxfg[0];
+ u32 reg_ctrl, reg_id;
+
+ reg_ctrl = readl(&mb->can_ctrl);
+ reg_id = readl(&mb->can_id);
+ if (reg_ctrl & FLEXCAN_MB_CNT_IDE)
+ cf->can_id = ((reg_id >> 0) & CAN_EFF_MASK) | CAN_EFF_FLAG;
+ else
+ cf->can_id = (reg_id >> 18) & CAN_SFF_MASK;
+
+ if (reg_ctrl & FLEXCAN_MB_CNT_RTR)
+ cf->can_id |= CAN_RTR_FLAG;
+ cf->can_dlc = get_can_dlc((reg_ctrl >> 16) & 0xf);
+
+ *(__be32 *)(cf->data + 0) = cpu_to_be32(readl(&mb->data[0]));
+ *(__be32 *)(cf->data + 4) = cpu_to_be32(readl(&mb->data[1]));
+
+ /* mark as read */
+ writel(FLEXCAN_IFLAG_RX_FIFO_AVAILABLE, &regs->iflag1);
+ readl(&regs->timer);
+}
+
+static int flexcan_read_frame(struct net_device *dev)
+{
+ struct net_device_stats *stats = &dev->stats;
+ struct can_frame *cf;
+ struct sk_buff *skb;
+
+ skb = alloc_can_skb(dev, &cf);
+ if (unlikely(!skb)) {
+ stats->rx_dropped++;
+ return 0;
+ }
+
+ flexcan_read_fifo(dev, cf);
+ netif_receive_skb(skb);
+
+ stats->rx_packets++;
+ stats->rx_bytes += cf->can_dlc;
+
+ return 1;
+}
+
+static int flexcan_poll(struct napi_struct *napi, int quota)
+{
+ struct net_device *dev = napi->dev;
+ const struct flexcan_priv *priv = netdev_priv(dev);
+ struct flexcan_regs __iomem *regs = priv->base;
+ u32 reg_iflag1, reg_esr;
+ int work_done = 0;
+
+ /*
+ * The error bits are cleared on read,
+ * use saved value from irq handler.
+ */
+ reg_esr = readl(&regs->esr) | priv->reg_esr;
+
+ /* handle state changes */
+ work_done += flexcan_poll_state(dev, reg_esr);
+
+ /* handle RX-FIFO */
+ reg_iflag1 = readl(&regs->iflag1);
+ while (reg_iflag1 & FLEXCAN_IFLAG_RX_FIFO_AVAILABLE &&
+ work_done < quota) {
+ work_done += flexcan_read_frame(dev);
+ reg_iflag1 = readl(&regs->iflag1);
+ }
+
+ /* report bus errors */
+ if (flexcan_has_and_handle_berr(priv, reg_esr) && work_done < quota)
+ work_done += flexcan_poll_bus_err(dev, reg_esr);
+
+ if (work_done < quota) {
+ napi_complete(napi);
+ /* enable IRQs */
+ writel(FLEXCAN_IFLAG_DEFAULT, &regs->imask1);
+ writel(priv->reg_ctrl_default, &regs->ctrl);
+ }
+
+ return work_done;
+}
+
+static irqreturn_t flexcan_irq(int irq, void *dev_id)
+{
+ struct net_device *dev = dev_id;
+ struct net_device_stats *stats = &dev->stats;
+ struct flexcan_priv *priv = netdev_priv(dev);
+ struct flexcan_regs __iomem *regs = priv->base;
+ u32 reg_iflag1, reg_esr;
+
+ reg_iflag1 = readl(&regs->iflag1);
+ reg_esr = readl(&regs->esr);
+ writel(FLEXCAN_ESR_ERR_INT, &regs->esr); /* ACK err IRQ */
+
+ /*
+ * schedule NAPI in case of:
+ * - rx IRQ
+ * - state change IRQ
+ * - bus error IRQ and bus error reporting is activated
+ */
+ if ((reg_iflag1 & FLEXCAN_IFLAG_RX_FIFO_AVAILABLE) ||
+ (reg_esr & FLEXCAN_ESR_ERR_STATE) ||
+ flexcan_has_and_handle_berr(priv, reg_esr)) {
+ /*
+ * The error bits are cleared on read,
+ * save them for later use.
+ */
+ priv->reg_esr = reg_esr & FLEXCAN_ESR_ERR_BUS;
+ writel(FLEXCAN_IFLAG_DEFAULT & ~FLEXCAN_IFLAG_RX_FIFO_AVAILABLE,
+ &regs->imask1);
+ writel(priv->reg_ctrl_default & ~FLEXCAN_CTRL_ERR_ALL,
+ &regs->ctrl);
+ napi_schedule(&priv->napi);
+ }
+
+ /* FIFO overflow */
+ if (reg_iflag1 & FLEXCAN_IFLAG_RX_FIFO_OVERFLOW) {
+ writel(FLEXCAN_IFLAG_RX_FIFO_OVERFLOW, &regs->iflag1);
+ dev->stats.rx_over_errors++;
+ dev->stats.rx_errors++;
+ }
+
+ /* transmission complete interrupt */
+ if (reg_iflag1 & (1 << FLEXCAN_TX_BUF_ID)) {
+ /* tx_bytes is incremented in flexcan_start_xmit */
+ stats->tx_packets++;
+ writel((1 << FLEXCAN_TX_BUF_ID), &regs->iflag1);
+ netif_wake_queue(dev);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static void flexcan_set_bittiming(struct net_device *dev)
+{
+ const struct flexcan_priv *priv = netdev_priv(dev);
+ const struct can_bittiming *bt = &priv->can.bittiming;
+ struct flexcan_regs __iomem *regs = priv->base;
+ u32 reg;
+
+ reg = readl(&regs->ctrl);
+ reg &= ~(FLEXCAN_CTRL_PRESDIV(0xff) |
+ FLEXCAN_CTRL_RJW(0x3) |
+ FLEXCAN_CTRL_PSEG1(0x7) |
+ FLEXCAN_CTRL_PSEG2(0x7) |
+ FLEXCAN_CTRL_PROPSEG(0x7) |
+ FLEXCAN_CTRL_LPB |
+ FLEXCAN_CTRL_SMP |
+ FLEXCAN_CTRL_LOM);
+
+ reg |= FLEXCAN_CTRL_PRESDIV(bt->brp - 1) |
+ FLEXCAN_CTRL_PSEG1(bt->phase_seg1 - 1) |
+ FLEXCAN_CTRL_PSEG2(bt->phase_seg2 - 1) |
+ FLEXCAN_CTRL_RJW(bt->sjw - 1) |
+ FLEXCAN_CTRL_PROPSEG(bt->prop_seg - 1);
+
+ if (priv->can.ctrlmode & CAN_CTRLMODE_LOOPBACK)
+ reg |= FLEXCAN_CTRL_LPB;
+ if (priv->can.ctrlmode & CAN_CTRLMODE_LISTENONLY)
+ reg |= FLEXCAN_CTRL_LOM;
+ if (priv->can.ctrlmode & CAN_CTRLMODE_3_SAMPLES)
+ reg |= FLEXCAN_CTRL_SMP;
+
+ dev_info(dev->dev.parent, "writing ctrl=0x%08x\n", reg);
+ writel(reg, &regs->ctrl);
+
+ /* print chip status */
+ dev_dbg(dev->dev.parent, "%s: mcr=0x%08x ctrl=0x%08x\n", __func__,
+ readl(&regs->mcr), readl(&regs->ctrl));
+}
+
+/*
+ * flexcan_chip_start
+ *
+ * this functions is entered with clocks enabled
+ *
+ */
+static int flexcan_chip_start(struct net_device *dev)
+{
+ struct flexcan_priv *priv = netdev_priv(dev);
+ struct flexcan_regs __iomem *regs = priv->base;
+ unsigned int i;
+ int err;
+ u32 reg_mcr, reg_ctrl;
+
+ /* enable module */
+ flexcan_chip_enable(priv);
+
+ /* soft reset */
+ writel(FLEXCAN_MCR_SOFTRST, &regs->mcr);
+ udelay(10);
+
+ reg_mcr = readl(&regs->mcr);
+ if (reg_mcr & FLEXCAN_MCR_SOFTRST) {
+ dev_err(dev->dev.parent,
+ "Failed to softreset can module (mcr=0x%08x)\n",
+ reg_mcr);
+ err = -ENODEV;
+ goto out;
+ }
+
+ flexcan_set_bittiming(dev);
+
+ /*
+ * MCR
+ *
+ * enable freeze
+ * enable fifo
+ * halt now
+ * only supervisor access
+ * enable warning int
+ * choose format C
+ *
+ */
+ reg_mcr = readl(&regs->mcr);
+ reg_mcr |= FLEXCAN_MCR_FRZ | FLEXCAN_MCR_FEN | FLEXCAN_MCR_HALT |
+ FLEXCAN_MCR_SUPV | FLEXCAN_MCR_WRN_EN |
+ FLEXCAN_MCR_IDAM_C;
+ dev_dbg(dev->dev.parent, "%s: writing mcr=0x%08x", __func__, reg_mcr);
+ writel(reg_mcr, &regs->mcr);
+
+ /*
+ * CTRL
+ *
+ * disable timer sync feature
+ *
+ * disable auto busoff recovery
+ * transmit lowest buffer first
+ *
+ * enable tx and rx warning interrupt
+ * enable bus off interrupt
+ * (== FLEXCAN_CTRL_ERR_STATE)
+ *
+ * _note_: we enable the "error interrupt"
+ * (FLEXCAN_CTRL_ERR_MSK), too. Otherwise we don't get any
+ * warning or bus passive interrupts.
+ */
+ reg_ctrl = readl(&regs->ctrl);
+ reg_ctrl &= ~FLEXCAN_CTRL_TSYN;
+ reg_ctrl |= FLEXCAN_CTRL_BOFF_REC | FLEXCAN_CTRL_LBUF |
+ FLEXCAN_CTRL_ERR_STATE | FLEXCAN_CTRL_ERR_MSK;
+
+ /* save for later use */
+ priv->reg_ctrl_default = reg_ctrl;
+ dev_dbg(dev->dev.parent, "%s: writing ctrl=0x%08x", __func__, reg_ctrl);
+ writel(reg_ctrl, &regs->ctrl);
+
+ for (i = 0; i < ARRAY_SIZE(regs->cantxfg); i++) {
+ writel(0, &regs->cantxfg[i].can_ctrl);
+ writel(0, &regs->cantxfg[i].can_id);
+ writel(0, &regs->cantxfg[i].data[0]);
+ writel(0, &regs->cantxfg[i].data[1]);
+
+ /* put MB into rx queue */
+ writel(FLEXCAN_MB_CNT_CODE(0x4), &regs->cantxfg[i].can_ctrl);
+ }
+
+ /* acceptance mask/acceptance code (accept everything) */
+ writel(0x0, &regs->rxgmask);
+ writel(0x0, &regs->rx14mask);
+ writel(0x0, &regs->rx15mask);
+
+ flexcan_transceiver_switch(priv, 1);
+
+ /* synchronize with the can bus */
+ reg_mcr = readl(&regs->mcr);
+ reg_mcr &= ~FLEXCAN_MCR_HALT;
+ writel(reg_mcr, &regs->mcr);
+
+ priv->can.state = CAN_STATE_ERROR_ACTIVE;
+
+ /* enable FIFO interrupts */
+ writel(FLEXCAN_IFLAG_DEFAULT, &regs->imask1);
+
+ /* print chip status */
+ dev_dbg(dev->dev.parent, "%s: reading mcr=0x%08x ctrl=0x%08x\n",
+ __func__, readl(&regs->mcr), readl(&regs->ctrl));
+
+ return 0;
+
+ out:
+ flexcan_chip_disable(priv);
+ return err;
+}
+
+/*
+ * flexcan_chip_stop
+ *
+ * this functions is entered with clocks enabled
+ *
+ */
+static void flexcan_chip_stop(struct net_device *dev)
+{
+ struct flexcan_priv *priv = netdev_priv(dev);
+ struct flexcan_regs __iomem *regs = priv->base;
+ u32 reg;
+
+ /* Disable all interrupts */
+ writel(0, &regs->imask1);
+
+ /* Disable + halt module */
+ reg = readl(&regs->mcr);
+ reg |= FLEXCAN_MCR_MDIS | FLEXCAN_MCR_HALT;
+ writel(reg, &regs->mcr);
+
+ flexcan_transceiver_switch(priv, 0);
+ priv->can.state = CAN_STATE_STOPPED;
+
+ return;
+}
+
+static int flexcan_open(struct net_device *dev)
+{
+ struct flexcan_priv *priv = netdev_priv(dev);
+ int err;
+
+ clk_enable(priv->clk);
+
+ err = open_candev(dev);
+ if (err)
+ goto out;
+
+ err = request_irq(dev->irq, flexcan_irq, IRQF_SHARED, dev->name, dev);
+ if (err)
+ goto out_close;
+
+ /* start chip and queuing */
+ err = flexcan_chip_start(dev);
+ if (err)
+ goto out_close;
+ napi_enable(&priv->napi);
+ netif_start_queue(dev);
+
+ return 0;
+
+ out_close:
+ close_candev(dev);
+ out:
+ clk_disable(priv->clk);
+
+ return err;
+}
+
+static int flexcan_close(struct net_device *dev)
+{
+ struct flexcan_priv *priv = netdev_priv(dev);
+
+ netif_stop_queue(dev);
+ napi_disable(&priv->napi);
+ flexcan_chip_stop(dev);
+
+ free_irq(dev->irq, dev);
+ clk_disable(priv->clk);
+
+ close_candev(dev);
+
+ return 0;
+}
+
+static int flexcan_set_mode(struct net_device *dev, enum can_mode mode)
+{
+ int err;
+
+ switch (mode) {
+ case CAN_MODE_START:
+ err = flexcan_chip_start(dev);
+ if (err)
+ return err;
+
+ netif_wake_queue(dev);
+ break;
+
+ default:
+ return -EOPNOTSUPP;
+ }
+
+ return 0;
+}
+
+static const struct net_device_ops flexcan_netdev_ops = {
+ .ndo_open = flexcan_open,
+ .ndo_stop = flexcan_close,
+ .ndo_start_xmit = flexcan_start_xmit,
+};
+
+static int __devinit register_flexcandev(struct net_device *dev)
+{
+ struct flexcan_priv *priv = netdev_priv(dev);
+ struct flexcan_regs __iomem *regs = priv->base;
+ u32 reg, err;
+
+ clk_enable(priv->clk);
+
+ /* select "bus clock", chip must be disabled */
+ flexcan_chip_disable(priv);
+ reg = readl(&regs->ctrl);
+ reg |= FLEXCAN_CTRL_CLK_SRC;
+ writel(reg, &regs->ctrl);
+
+ flexcan_chip_enable(priv);
+
+ /* set freeze, halt and activate FIFO, restrict register access */
+ reg = readl(&regs->mcr);
+ reg |= FLEXCAN_MCR_FRZ | FLEXCAN_MCR_HALT |
+ FLEXCAN_MCR_FEN | FLEXCAN_MCR_SUPV;
+ writel(reg, &regs->mcr);
+
+ /*
+ * Currently we only support newer versions of this core
+ * featuring a RX FIFO. Older cores found on some Coldfire
+ * derivates are not yet supported.
+ */
+ reg = readl(&regs->mcr);
+ if (!(reg & FLEXCAN_MCR_FEN)) {
+ dev_err(dev->dev.parent,
+ "Could not enable RX FIFO, unsupported core\n");
+ err = -ENODEV;
+ goto out;
+ }
+
+ err = register_candev(dev);
+
+ out:
+ /* disable core and turn off clocks */
+ flexcan_chip_disable(priv);
+ clk_disable(priv->clk);
+
+ return err;
+}
+
+static void __devexit unregister_flexcandev(struct net_device *dev)
+{
+ unregister_candev(dev);
+}
+
+static int __devinit flexcan_probe(struct platform_device *pdev)
+{
+ struct net_device *dev;
+ struct flexcan_priv *priv;
+ struct resource *mem;
+ struct clk *clk;
+ void __iomem *base;
+ resource_size_t mem_size;
+ int err, irq;
+
+ clk = clk_get(&pdev->dev, NULL);
+ if (IS_ERR(clk)) {
+ dev_err(&pdev->dev, "no clock defined\n");
+ err = PTR_ERR(clk);
+ goto failed_clock;
+ }
+
+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ irq = platform_get_irq(pdev, 0);
+ if (!mem || irq <= 0) {
+ err = -ENODEV;
+ goto failed_get;
+ }
+
+ mem_size = resource_size(mem);
+ if (!request_mem_region(mem->start, mem_size, pdev->name)) {
+ err = -EBUSY;
+ goto failed_req;
+ }
+
+ base = ioremap(mem->start, mem_size);
+ if (!base) {
+ err = -ENOMEM;
+ goto failed_map;
+ }
+
+ dev = alloc_candev(sizeof(struct flexcan_priv), 0);
+ if (!dev) {
+ err = -ENOMEM;
+ goto failed_alloc;
+ }
+
+ dev->netdev_ops = &flexcan_netdev_ops;
+ dev->irq = irq;
+ dev->flags |= IFF_ECHO; /* we support local echo in hardware */
+
+ priv = netdev_priv(dev);
+ priv->can.clock.freq = clk_get_rate(clk);
+ priv->can.bittiming_const = &flexcan_bittiming_const;
+ priv->can.do_set_mode = flexcan_set_mode;
+ priv->can.do_get_berr_counter = flexcan_get_berr_counter;
+ priv->can.ctrlmode_supported = CAN_CTRLMODE_LOOPBACK |
+ CAN_CTRLMODE_LISTENONLY | CAN_CTRLMODE_3_SAMPLES |
+ CAN_CTRLMODE_BERR_REPORTING;
+ priv->base = base;
+ priv->dev = dev;
+ priv->clk = clk;
+ priv->pdata = pdev->dev.platform_data;
+
+ netif_napi_add(dev, &priv->napi, flexcan_poll, FLEXCAN_NAPI_WEIGHT);
+
+ dev_set_drvdata(&pdev->dev, dev);
+ SET_NETDEV_DEV(dev, &pdev->dev);
+
+ err = register_flexcandev(dev);
+ if (err) {
+ dev_err(&pdev->dev, "registering netdev failed\n");
+ goto failed_register;
+ }
+
+ dev_info(&pdev->dev, "device registered (reg_base=%p, irq=%d)\n",
+ priv->base, dev->irq);
+
+ return 0;
+
+ failed_register:
+ free_candev(dev);
+ failed_alloc:
+ iounmap(base);
+ failed_map:
+ release_mem_region(mem->start, mem_size);
+ failed_req:
+ clk_put(clk);
+ failed_get:
+ failed_clock:
+ return err;
+}
+
+static int __devexit flexcan_remove(struct platform_device *pdev)
+{
+ struct net_device *dev = platform_get_drvdata(pdev);
+ struct flexcan_priv *priv = netdev_priv(dev);
+ struct resource *mem;
+
+ unregister_flexcandev(dev);
+ platform_set_drvdata(pdev, NULL);
+ free_candev(dev);
+ iounmap(priv->base);
+
+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ release_mem_region(mem->start, resource_size(mem));
+
+ clk_put(priv->clk);
+
+ return 0;
+}
+
+static struct platform_driver flexcan_driver = {
+ .driver.name = DRV_NAME,
+ .probe = flexcan_probe,
+ .remove = __devexit_p(flexcan_remove),
+};
+
+static int __init flexcan_init(void)
+{
+ pr_info("%s netdevice driver\n", DRV_NAME);
+ return platform_driver_register(&flexcan_driver);
+}
+
+static void __exit flexcan_exit(void)
+{
+ platform_driver_unregister(&flexcan_driver);
+ pr_info("%s: driver removed\n", DRV_NAME);
+}
+
+module_init(flexcan_init);
+module_exit(flexcan_exit);
+
+MODULE_AUTHOR("Sascha Hauer <kernel@pengutronix.de>, "
+ "Marc Kleine-Budde <kernel@pengutronix.de>");
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("CAN port driver for flexcan based chip");
diff --git a/drivers/net/can/mscan/mscan.h b/drivers/net/can/mscan/mscan.h
index 4ff966473bc..b43e9f5d326 100644
--- a/drivers/net/can/mscan/mscan.h
+++ b/drivers/net/can/mscan/mscan.h
@@ -227,7 +227,7 @@ struct mscan_regs {
u16 time; /* + 0x7c 0x3e */
} tx;
_MSCAN_RESERVED_(32, 2); /* + 0x7e */
-} __attribute__ ((packed));
+} __packed;
#undef _MSCAN_RESERVED_
#define MSCAN_REGION sizeof(struct mscan)
diff --git a/drivers/net/can/usb/Kconfig b/drivers/net/can/usb/Kconfig
index 97ff6febad6..04525495b15 100644
--- a/drivers/net/can/usb/Kconfig
+++ b/drivers/net/can/usb/Kconfig
@@ -7,4 +7,10 @@ config CAN_EMS_USB
This driver is for the one channel CPC-USB/ARM7 CAN/USB interface
from EMS Dr. Thomas Wuensche (http://www.ems-wuensche.de).
+config CAN_ESD_USB2
+ tristate "ESD USB/2 CAN/USB interface"
+ ---help---
+ This driver supports the CAN-USB/2 interface
+ from esd electronic system design gmbh (http://www.esd.eu).
+
endmenu
diff --git a/drivers/net/can/usb/Makefile b/drivers/net/can/usb/Makefile
index 0afd51d4c7a..fce3cf11719 100644
--- a/drivers/net/can/usb/Makefile
+++ b/drivers/net/can/usb/Makefile
@@ -3,5 +3,6 @@
#
obj-$(CONFIG_CAN_EMS_USB) += ems_usb.o
+obj-$(CONFIG_CAN_ESD_USB2) += esd_usb2.o
ccflags-$(CONFIG_CAN_DEBUG_DEVICES) := -DDEBUG
diff --git a/drivers/net/can/usb/ems_usb.c b/drivers/net/can/usb/ems_usb.c
index 1fc0871d2ef..e75f1a87697 100644
--- a/drivers/net/can/usb/ems_usb.c
+++ b/drivers/net/can/usb/ems_usb.c
@@ -197,7 +197,7 @@ struct cpc_can_err_counter {
};
/* Main message type used between library and application */
-struct __attribute__ ((packed)) ems_cpc_msg {
+struct __packed ems_cpc_msg {
u8 type; /* type of message */
u8 length; /* length of data within union 'msg' */
u8 msgid; /* confirmation handle */
diff --git a/drivers/net/can/usb/esd_usb2.c b/drivers/net/can/usb/esd_usb2.c
new file mode 100644
index 00000000000..05a52754f48
--- /dev/null
+++ b/drivers/net/can/usb/esd_usb2.c
@@ -0,0 +1,1132 @@
+/*
+ * CAN driver for esd CAN-USB/2
+ *
+ * Copyright (C) 2010 Matthias Fuchs <matthias.fuchs@esd.eu>, esd 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; 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/init.h>
+#include <linux/signal.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/netdevice.h>
+#include <linux/usb.h>
+
+#include <linux/can.h>
+#include <linux/can/dev.h>
+#include <linux/can/error.h>
+
+MODULE_AUTHOR("Matthias Fuchs <matthias.fuchs@esd.eu>");
+MODULE_DESCRIPTION("CAN driver for esd CAN-USB/2 interfaces");
+MODULE_LICENSE("GPL v2");
+
+/* Define these values to match your devices */
+#define USB_ESDGMBH_VENDOR_ID 0x0ab4
+#define USB_CANUSB2_PRODUCT_ID 0x0010
+
+#define ESD_USB2_CAN_CLOCK 60000000
+#define ESD_USB2_MAX_NETS 2
+
+/* USB2 commands */
+#define CMD_VERSION 1 /* also used for VERSION_REPLY */
+#define CMD_CAN_RX 2 /* device to host only */
+#define CMD_CAN_TX 3 /* also used for TX_DONE */
+#define CMD_SETBAUD 4 /* also used for SETBAUD_REPLY */
+#define CMD_TS 5 /* also used for TS_REPLY */
+#define CMD_IDADD 6 /* also used for IDADD_REPLY */
+
+/* esd CAN message flags - dlc field */
+#define ESD_RTR 0x10
+
+/* esd CAN message flags - id field */
+#define ESD_EXTID 0x20000000
+#define ESD_EVENT 0x40000000
+#define ESD_IDMASK 0x1fffffff
+
+/* esd CAN event ids used by this driver */
+#define ESD_EV_CAN_ERROR_EXT 2
+
+/* baudrate message flags */
+#define ESD_USB2_UBR 0x80000000
+#define ESD_USB2_LOM 0x40000000
+#define ESD_USB2_NO_BAUDRATE 0x7fffffff
+#define ESD_USB2_TSEG1_MIN 1
+#define ESD_USB2_TSEG1_MAX 16
+#define ESD_USB2_TSEG1_SHIFT 16
+#define ESD_USB2_TSEG2_MIN 1
+#define ESD_USB2_TSEG2_MAX 8
+#define ESD_USB2_TSEG2_SHIFT 20
+#define ESD_USB2_SJW_MAX 4
+#define ESD_USB2_SJW_SHIFT 14
+#define ESD_USB2_BRP_MIN 1
+#define ESD_USB2_BRP_MAX 1024
+#define ESD_USB2_BRP_INC 1
+#define ESD_USB2_3_SAMPLES 0x00800000
+
+/* esd IDADD message */
+#define ESD_ID_ENABLE 0x80
+#define ESD_MAX_ID_SEGMENT 64
+
+/* SJA1000 ECC register (emulated by usb2 firmware) */
+#define SJA1000_ECC_SEG 0x1F
+#define SJA1000_ECC_DIR 0x20
+#define SJA1000_ECC_ERR 0x06
+#define SJA1000_ECC_BIT 0x00
+#define SJA1000_ECC_FORM 0x40
+#define SJA1000_ECC_STUFF 0x80
+#define SJA1000_ECC_MASK 0xc0
+
+/* esd bus state event codes */
+#define ESD_BUSSTATE_MASK 0xc0
+#define ESD_BUSSTATE_WARN 0x40
+#define ESD_BUSSTATE_ERRPASSIVE 0x80
+#define ESD_BUSSTATE_BUSOFF 0xc0
+
+#define RX_BUFFER_SIZE 1024
+#define MAX_RX_URBS 4
+#define MAX_TX_URBS 16 /* must be power of 2 */
+
+struct header_msg {
+ u8 len; /* len is always the total message length in 32bit words */
+ u8 cmd;
+ u8 rsvd[2];
+};
+
+struct version_msg {
+ u8 len;
+ u8 cmd;
+ u8 rsvd;
+ u8 flags;
+ __le32 drv_version;
+};
+
+struct version_reply_msg {
+ u8 len;
+ u8 cmd;
+ u8 nets;
+ u8 features;
+ __le32 version;
+ u8 name[16];
+ __le32 rsvd;
+ __le32 ts;
+};
+
+struct rx_msg {
+ u8 len;
+ u8 cmd;
+ u8 net;
+ u8 dlc;
+ __le32 ts;
+ __le32 id; /* upper 3 bits contain flags */
+ u8 data[8];
+};
+
+struct tx_msg {
+ u8 len;
+ u8 cmd;
+ u8 net;
+ u8 dlc;
+ __le32 hnd;
+ __le32 id; /* upper 3 bits contain flags */
+ u8 data[8];
+};
+
+struct tx_done_msg {
+ u8 len;
+ u8 cmd;
+ u8 net;
+ u8 status;
+ __le32 hnd;
+ __le32 ts;
+};
+
+struct id_filter_msg {
+ u8 len;
+ u8 cmd;
+ u8 net;
+ u8 option;
+ __le32 mask[ESD_MAX_ID_SEGMENT + 1];
+};
+
+struct set_baudrate_msg {
+ u8 len;
+ u8 cmd;
+ u8 net;
+ u8 rsvd;
+ __le32 baud;
+};
+
+/* Main message type used between library and application */
+struct __attribute__ ((packed)) esd_usb2_msg {
+ union {
+ struct header_msg hdr;
+ struct version_msg version;
+ struct version_reply_msg version_reply;
+ struct rx_msg rx;
+ struct tx_msg tx;
+ struct tx_done_msg txdone;
+ struct set_baudrate_msg setbaud;
+ struct id_filter_msg filter;
+ } msg;
+};
+
+static struct usb_device_id esd_usb2_table[] = {
+ {USB_DEVICE(USB_ESDGMBH_VENDOR_ID, USB_CANUSB2_PRODUCT_ID)},
+ {}
+};
+MODULE_DEVICE_TABLE(usb, esd_usb2_table);
+
+struct esd_usb2_net_priv;
+
+struct esd_tx_urb_context {
+ struct esd_usb2_net_priv *priv;
+ u32 echo_index;
+ int dlc;
+};
+
+struct esd_usb2 {
+ struct usb_device *udev;
+ struct esd_usb2_net_priv *nets[ESD_USB2_MAX_NETS];
+
+ struct usb_anchor rx_submitted;
+
+ int net_count;
+ u32 version;
+ int rxinitdone;
+};
+
+struct esd_usb2_net_priv {
+ struct can_priv can; /* must be the first member */
+
+ atomic_t active_tx_jobs;
+ struct usb_anchor tx_submitted;
+ struct esd_tx_urb_context tx_contexts[MAX_TX_URBS];
+
+ int open_time;
+ struct esd_usb2 *usb2;
+ struct net_device *netdev;
+ int index;
+ u8 old_state;
+ struct can_berr_counter bec;
+};
+
+static void esd_usb2_rx_event(struct esd_usb2_net_priv *priv,
+ struct esd_usb2_msg *msg)
+{
+ struct net_device_stats *stats = &priv->netdev->stats;
+ struct can_frame *cf;
+ struct sk_buff *skb;
+ u32 id = le32_to_cpu(msg->msg.rx.id) & ESD_IDMASK;
+
+ if (id == ESD_EV_CAN_ERROR_EXT) {
+ u8 state = msg->msg.rx.data[0];
+ u8 ecc = msg->msg.rx.data[1];
+ u8 txerr = msg->msg.rx.data[2];
+ u8 rxerr = msg->msg.rx.data[3];
+
+ skb = alloc_can_err_skb(priv->netdev, &cf);
+ if (skb == NULL) {
+ stats->rx_dropped++;
+ return;
+ }
+
+ if (state != priv->old_state) {
+ priv->old_state = state;
+
+ switch (state & ESD_BUSSTATE_MASK) {
+ case ESD_BUSSTATE_BUSOFF:
+ priv->can.state = CAN_STATE_BUS_OFF;
+ cf->can_id |= CAN_ERR_BUSOFF;
+ can_bus_off(priv->netdev);
+ break;
+ case ESD_BUSSTATE_WARN:
+ priv->can.state = CAN_STATE_ERROR_WARNING;
+ priv->can.can_stats.error_warning++;
+ break;
+ case ESD_BUSSTATE_ERRPASSIVE:
+ priv->can.state = CAN_STATE_ERROR_PASSIVE;
+ priv->can.can_stats.error_passive++;
+ break;
+ default:
+ priv->can.state = CAN_STATE_ERROR_ACTIVE;
+ break;
+ }
+ } else {
+ priv->can.can_stats.bus_error++;
+ stats->rx_errors++;
+
+ cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR;
+
+ switch (ecc & SJA1000_ECC_MASK) {
+ case SJA1000_ECC_BIT:
+ cf->data[2] |= CAN_ERR_PROT_BIT;
+ break;
+ case SJA1000_ECC_FORM:
+ cf->data[2] |= CAN_ERR_PROT_FORM;
+ break;
+ case SJA1000_ECC_STUFF:
+ cf->data[2] |= CAN_ERR_PROT_STUFF;
+ break;
+ default:
+ cf->data[2] |= CAN_ERR_PROT_UNSPEC;
+ cf->data[3] = ecc & SJA1000_ECC_SEG;
+ break;
+ }
+
+ /* Error occured during transmission? */
+ if (!(ecc & SJA1000_ECC_DIR))
+ cf->data[2] |= CAN_ERR_PROT_TX;
+
+ if (priv->can.state == CAN_STATE_ERROR_WARNING ||
+ priv->can.state == CAN_STATE_ERROR_PASSIVE) {
+ cf->data[1] = (txerr > rxerr) ?
+ CAN_ERR_CRTL_TX_PASSIVE :
+ CAN_ERR_CRTL_RX_PASSIVE;
+ }
+ cf->data[6] = txerr;
+ cf->data[7] = rxerr;
+ }
+
+ netif_rx(skb);
+
+ priv->bec.txerr = txerr;
+ priv->bec.rxerr = rxerr;
+
+ stats->rx_packets++;
+ stats->rx_bytes += cf->can_dlc;
+ }
+}
+
+static void esd_usb2_rx_can_msg(struct esd_usb2_net_priv *priv,
+ struct esd_usb2_msg *msg)
+{
+ struct net_device_stats *stats = &priv->netdev->stats;
+ struct can_frame *cf;
+ struct sk_buff *skb;
+ int i;
+ u32 id;
+
+ if (!netif_device_present(priv->netdev))
+ return;
+
+ id = le32_to_cpu(msg->msg.rx.id);
+
+ if (id & ESD_EVENT) {
+ esd_usb2_rx_event(priv, msg);
+ } else {
+ skb = alloc_can_skb(priv->netdev, &cf);
+ if (skb == NULL) {
+ stats->rx_dropped++;
+ return;
+ }
+
+ cf->can_id = id & ESD_IDMASK;
+ cf->can_dlc = get_can_dlc(msg->msg.rx.dlc);
+
+ if (id & ESD_EXTID)
+ cf->can_id |= CAN_EFF_FLAG;
+
+ if (msg->msg.rx.dlc & ESD_RTR) {
+ cf->can_id |= CAN_RTR_FLAG;
+ } else {
+ for (i = 0; i < cf->can_dlc; i++)
+ cf->data[i] = msg->msg.rx.data[i];
+ }
+
+ netif_rx(skb);
+
+ stats->rx_packets++;
+ stats->rx_bytes += cf->can_dlc;
+ }
+
+ return;
+}
+
+static void esd_usb2_tx_done_msg(struct esd_usb2_net_priv *priv,
+ struct esd_usb2_msg *msg)
+{
+ struct net_device_stats *stats = &priv->netdev->stats;
+ struct net_device *netdev = priv->netdev;
+ struct esd_tx_urb_context *context;
+
+ if (!netif_device_present(netdev))
+ return;
+
+ context = &priv->tx_contexts[msg->msg.txdone.hnd & (MAX_TX_URBS - 1)];
+
+ if (!msg->msg.txdone.status) {
+ stats->tx_packets++;
+ stats->tx_bytes += context->dlc;
+ can_get_echo_skb(netdev, context->echo_index);
+ } else {
+ stats->tx_errors++;
+ can_free_echo_skb(netdev, context->echo_index);
+ }
+
+ /* Release context */
+ context->echo_index = MAX_TX_URBS;
+ atomic_dec(&priv->active_tx_jobs);
+
+ netif_wake_queue(netdev);
+}
+
+static void esd_usb2_read_bulk_callback(struct urb *urb)
+{
+ struct esd_usb2 *dev = urb->context;
+ int retval;
+ int pos = 0;
+ int i;
+
+ switch (urb->status) {
+ case 0: /* success */
+ break;
+
+ case -ENOENT:
+ case -ESHUTDOWN:
+ return;
+
+ default:
+ dev_info(dev->udev->dev.parent,
+ "Rx URB aborted (%d)\n", urb->status);
+ goto resubmit_urb;
+ }
+
+ while (pos < urb->actual_length) {
+ struct esd_usb2_msg *msg;
+
+ msg = (struct esd_usb2_msg *)(urb->transfer_buffer + pos);
+
+ switch (msg->msg.hdr.cmd) {
+ case CMD_CAN_RX:
+ esd_usb2_rx_can_msg(dev->nets[msg->msg.rx.net], msg);
+ break;
+
+ case CMD_CAN_TX:
+ esd_usb2_tx_done_msg(dev->nets[msg->msg.txdone.net],
+ msg);
+ break;
+ }
+
+ pos += msg->msg.hdr.len << 2;
+
+ if (pos > urb->actual_length) {
+ dev_err(dev->udev->dev.parent, "format error\n");
+ break;
+ }
+ }
+
+resubmit_urb:
+ usb_fill_bulk_urb(urb, dev->udev, usb_rcvbulkpipe(dev->udev, 1),
+ urb->transfer_buffer, RX_BUFFER_SIZE,
+ esd_usb2_read_bulk_callback, dev);
+
+ retval = usb_submit_urb(urb, GFP_ATOMIC);
+ if (retval == -ENODEV) {
+ for (i = 0; i < dev->net_count; i++) {
+ if (dev->nets[i])
+ netif_device_detach(dev->nets[i]->netdev);
+ }
+ } else if (retval) {
+ dev_err(dev->udev->dev.parent,
+ "failed resubmitting read bulk urb: %d\n", retval);
+ }
+
+ return;
+}
+
+/*
+ * callback for bulk IN urb
+ */
+static void esd_usb2_write_bulk_callback(struct urb *urb)
+{
+ struct esd_tx_urb_context *context = urb->context;
+ struct esd_usb2_net_priv *priv;
+ struct esd_usb2 *dev;
+ struct net_device *netdev;
+ size_t size = sizeof(struct esd_usb2_msg);
+
+ WARN_ON(!context);
+
+ priv = context->priv;
+ netdev = priv->netdev;
+ dev = priv->usb2;
+
+ /* free up our allocated buffer */
+ usb_free_coherent(urb->dev, size,
+ urb->transfer_buffer, urb->transfer_dma);
+
+ if (!netif_device_present(netdev))
+ return;
+
+ if (urb->status)
+ dev_info(netdev->dev.parent, "Tx URB aborted (%d)\n",
+ urb->status);
+
+ netdev->trans_start = jiffies;
+}
+
+static ssize_t show_firmware(struct device *d,
+ struct device_attribute *attr, char *buf)
+{
+ struct usb_interface *intf = to_usb_interface(d);
+ struct esd_usb2 *dev = usb_get_intfdata(intf);
+
+ return sprintf(buf, "%d.%d.%d\n",
+ (dev->version >> 12) & 0xf,
+ (dev->version >> 8) & 0xf,
+ dev->version & 0xff);
+}
+static DEVICE_ATTR(firmware, S_IRUGO, show_firmware, NULL);
+
+static ssize_t show_hardware(struct device *d,
+ struct device_attribute *attr, char *buf)
+{
+ struct usb_interface *intf = to_usb_interface(d);
+ struct esd_usb2 *dev = usb_get_intfdata(intf);
+
+ return sprintf(buf, "%d.%d.%d\n",
+ (dev->version >> 28) & 0xf,
+ (dev->version >> 24) & 0xf,
+ (dev->version >> 16) & 0xff);
+}
+static DEVICE_ATTR(hardware, S_IRUGO, show_hardware, NULL);
+
+static ssize_t show_nets(struct device *d,
+ struct device_attribute *attr, char *buf)
+{
+ struct usb_interface *intf = to_usb_interface(d);
+ struct esd_usb2 *dev = usb_get_intfdata(intf);
+
+ return sprintf(buf, "%d", dev->net_count);
+}
+static DEVICE_ATTR(nets, S_IRUGO, show_nets, NULL);
+
+static int esd_usb2_send_msg(struct esd_usb2 *dev, struct esd_usb2_msg *msg)
+{
+ int actual_length;
+
+ return usb_bulk_msg(dev->udev,
+ usb_sndbulkpipe(dev->udev, 2),
+ msg,
+ msg->msg.hdr.len << 2,
+ &actual_length,
+ 1000);
+}
+
+static int esd_usb2_wait_msg(struct esd_usb2 *dev,
+ struct esd_usb2_msg *msg)
+{
+ int actual_length;
+
+ return usb_bulk_msg(dev->udev,
+ usb_rcvbulkpipe(dev->udev, 1),
+ msg,
+ sizeof(*msg),
+ &actual_length,
+ 1000);
+}
+
+static int esd_usb2_setup_rx_urbs(struct esd_usb2 *dev)
+{
+ int i, err = 0;
+
+ if (dev->rxinitdone)
+ return 0;
+
+ for (i = 0; i < MAX_RX_URBS; i++) {
+ struct urb *urb = NULL;
+ u8 *buf = NULL;
+
+ /* create a URB, and a buffer for it */
+ urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!urb) {
+ dev_warn(dev->udev->dev.parent,
+ "No memory left for URBs\n");
+ err = -ENOMEM;
+ break;
+ }
+
+ buf = usb_alloc_coherent(dev->udev, RX_BUFFER_SIZE, GFP_KERNEL,
+ &urb->transfer_dma);
+ if (!buf) {
+ dev_warn(dev->udev->dev.parent,
+ "No memory left for USB buffer\n");
+ err = -ENOMEM;
+ goto freeurb;
+ }
+
+ usb_fill_bulk_urb(urb, dev->udev,
+ usb_rcvbulkpipe(dev->udev, 1),
+ buf, RX_BUFFER_SIZE,
+ esd_usb2_read_bulk_callback, dev);
+ urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+ usb_anchor_urb(urb, &dev->rx_submitted);
+
+ err = usb_submit_urb(urb, GFP_KERNEL);
+ if (err) {
+ usb_unanchor_urb(urb);
+ usb_free_coherent(dev->udev, RX_BUFFER_SIZE, buf,
+ urb->transfer_dma);
+ }
+
+freeurb:
+ /* Drop reference, USB core will take care of freeing it */
+ usb_free_urb(urb);
+ if (err)
+ break;
+ }
+
+ /* Did we submit any URBs */
+ if (i == 0) {
+ dev_err(dev->udev->dev.parent, "couldn't setup read URBs\n");
+ return err;
+ }
+
+ /* Warn if we've couldn't transmit all the URBs */
+ if (i < MAX_RX_URBS) {
+ dev_warn(dev->udev->dev.parent,
+ "rx performance may be slow\n");
+ }
+
+ dev->rxinitdone = 1;
+ return 0;
+}
+
+/*
+ * Start interface
+ */
+static int esd_usb2_start(struct esd_usb2_net_priv *priv)
+{
+ struct esd_usb2 *dev = priv->usb2;
+ struct net_device *netdev = priv->netdev;
+ struct esd_usb2_msg msg;
+ int err, i;
+
+ /*
+ * Enable all IDs
+ * The IDADD message takes up to 64 32 bit bitmasks (2048 bits).
+ * Each bit represents one 11 bit CAN identifier. A set bit
+ * enables reception of the corresponding CAN identifier. A cleared
+ * bit disabled this identifier. An additional bitmask value
+ * following the CAN 2.0A bits is used to enable reception of
+ * extended CAN frames. Only the LSB of this final mask is checked
+ * for the complete 29 bit ID range. The IDADD message also allows
+ * filter configuration for an ID subset. In this case you can add
+ * the number of the starting bitmask (0..64) to the filter.option
+ * field followed by only some bitmasks.
+ */
+ msg.msg.hdr.cmd = CMD_IDADD;
+ msg.msg.hdr.len = 2 + ESD_MAX_ID_SEGMENT;
+ msg.msg.filter.net = priv->index;
+ msg.msg.filter.option = ESD_ID_ENABLE; /* start with segment 0 */
+ for (i = 0; i < ESD_MAX_ID_SEGMENT; i++)
+ msg.msg.filter.mask[i] = cpu_to_le32(0xffffffff);
+ /* enable 29bit extended IDs */
+ msg.msg.filter.mask[ESD_MAX_ID_SEGMENT] = cpu_to_le32(0x00000001);
+
+ err = esd_usb2_send_msg(dev, &msg);
+ if (err)
+ goto failed;
+
+ err = esd_usb2_setup_rx_urbs(dev);
+ if (err)
+ goto failed;
+
+ priv->can.state = CAN_STATE_ERROR_ACTIVE;
+
+ return 0;
+
+failed:
+ if (err == -ENODEV)
+ netif_device_detach(netdev);
+
+ dev_err(netdev->dev.parent, "couldn't start device: %d\n", err);
+
+ return err;
+}
+
+static void unlink_all_urbs(struct esd_usb2 *dev)
+{
+ struct esd_usb2_net_priv *priv;
+ int i;
+
+ usb_kill_anchored_urbs(&dev->rx_submitted);
+ for (i = 0; i < dev->net_count; i++) {
+ priv = dev->nets[i];
+ if (priv) {
+ usb_kill_anchored_urbs(&priv->tx_submitted);
+ atomic_set(&priv->active_tx_jobs, 0);
+
+ for (i = 0; i < MAX_TX_URBS; i++)
+ priv->tx_contexts[i].echo_index = MAX_TX_URBS;
+ }
+ }
+}
+
+static int esd_usb2_open(struct net_device *netdev)
+{
+ struct esd_usb2_net_priv *priv = netdev_priv(netdev);
+ int err;
+
+ /* common open */
+ err = open_candev(netdev);
+ if (err)
+ return err;
+
+ /* finally start device */
+ err = esd_usb2_start(priv);
+ if (err) {
+ dev_warn(netdev->dev.parent,
+ "couldn't start device: %d\n", err);
+ close_candev(netdev);
+ return err;
+ }
+
+ priv->open_time = jiffies;
+
+ netif_start_queue(netdev);
+
+ return 0;
+}
+
+static netdev_tx_t esd_usb2_start_xmit(struct sk_buff *skb,
+ struct net_device *netdev)
+{
+ struct esd_usb2_net_priv *priv = netdev_priv(netdev);
+ struct esd_usb2 *dev = priv->usb2;
+ struct esd_tx_urb_context *context = NULL;
+ struct net_device_stats *stats = &netdev->stats;
+ struct can_frame *cf = (struct can_frame *)skb->data;
+ struct esd_usb2_msg *msg;
+ struct urb *urb;
+ u8 *buf;
+ int i, err;
+ int ret = NETDEV_TX_OK;
+ size_t size = sizeof(struct esd_usb2_msg);
+
+ if (can_dropped_invalid_skb(netdev, skb))
+ return NETDEV_TX_OK;
+
+ /* create a URB, and a buffer for it, and copy the data to the URB */
+ urb = usb_alloc_urb(0, GFP_ATOMIC);
+ if (!urb) {
+ dev_err(netdev->dev.parent, "No memory left for URBs\n");
+ stats->tx_dropped++;
+ dev_kfree_skb(skb);
+ goto nourbmem;
+ }
+
+ buf = usb_alloc_coherent(dev->udev, size, GFP_ATOMIC,
+ &urb->transfer_dma);
+ if (!buf) {
+ dev_err(netdev->dev.parent, "No memory left for USB buffer\n");
+ stats->tx_dropped++;
+ dev_kfree_skb(skb);
+ goto nobufmem;
+ }
+
+ msg = (struct esd_usb2_msg *)buf;
+
+ msg->msg.hdr.len = 3; /* minimal length */
+ msg->msg.hdr.cmd = CMD_CAN_TX;
+ msg->msg.tx.net = priv->index;
+ msg->msg.tx.dlc = cf->can_dlc;
+ msg->msg.tx.id = cpu_to_le32(cf->can_id & CAN_ERR_MASK);
+
+ if (cf->can_id & CAN_RTR_FLAG)
+ msg->msg.tx.dlc |= ESD_RTR;
+
+ if (cf->can_id & CAN_EFF_FLAG)
+ msg->msg.tx.id |= cpu_to_le32(ESD_EXTID);
+
+ for (i = 0; i < cf->can_dlc; i++)
+ msg->msg.tx.data[i] = cf->data[i];
+
+ msg->msg.hdr.len += (cf->can_dlc + 3) >> 2;
+
+ for (i = 0; i < MAX_TX_URBS; i++) {
+ if (priv->tx_contexts[i].echo_index == MAX_TX_URBS) {
+ context = &priv->tx_contexts[i];
+ break;
+ }
+ }
+
+ /*
+ * This may never happen.
+ */
+ if (!context) {
+ dev_warn(netdev->dev.parent, "couldn't find free context\n");
+ ret = NETDEV_TX_BUSY;
+ goto releasebuf;
+ }
+
+ context->priv = priv;
+ context->echo_index = i;
+ context->dlc = cf->can_dlc;
+
+ /* hnd must not be 0 - MSB is stripped in txdone handling */
+ msg->msg.tx.hnd = 0x80000000 | i; /* returned in TX done message */
+
+ usb_fill_bulk_urb(urb, dev->udev, usb_sndbulkpipe(dev->udev, 2), buf,
+ msg->msg.hdr.len << 2,
+ esd_usb2_write_bulk_callback, context);
+
+ urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+
+ usb_anchor_urb(urb, &priv->tx_submitted);
+
+ can_put_echo_skb(skb, netdev, context->echo_index);
+
+ atomic_inc(&priv->active_tx_jobs);
+
+ /* Slow down tx path */
+ if (atomic_read(&priv->active_tx_jobs) >= MAX_TX_URBS)
+ netif_stop_queue(netdev);
+
+ err = usb_submit_urb(urb, GFP_ATOMIC);
+ if (err) {
+ can_free_echo_skb(netdev, context->echo_index);
+
+ atomic_dec(&priv->active_tx_jobs);
+ usb_unanchor_urb(urb);
+
+ stats->tx_dropped++;
+
+ if (err == -ENODEV)
+ netif_device_detach(netdev);
+ else
+ dev_warn(netdev->dev.parent, "failed tx_urb %d\n", err);
+
+ goto releasebuf;
+ }
+
+ netdev->trans_start = jiffies;
+
+ /*
+ * Release our reference to this URB, the USB core will eventually free
+ * it entirely.
+ */
+ usb_free_urb(urb);
+
+ return NETDEV_TX_OK;
+
+releasebuf:
+ usb_free_coherent(dev->udev, size, buf, urb->transfer_dma);
+
+nobufmem:
+ usb_free_urb(urb);
+
+nourbmem:
+ return ret;
+}
+
+static int esd_usb2_close(struct net_device *netdev)
+{
+ struct esd_usb2_net_priv *priv = netdev_priv(netdev);
+ struct esd_usb2_msg msg;
+ int i;
+
+ /* Disable all IDs (see esd_usb2_start()) */
+ msg.msg.hdr.cmd = CMD_IDADD;
+ msg.msg.hdr.len = 2 + ESD_MAX_ID_SEGMENT;
+ msg.msg.filter.net = priv->index;
+ msg.msg.filter.option = ESD_ID_ENABLE; /* start with segment 0 */
+ for (i = 0; i <= ESD_MAX_ID_SEGMENT; i++)
+ msg.msg.filter.mask[i] = 0;
+ if (esd_usb2_send_msg(priv->usb2, &msg) < 0)
+ dev_err(netdev->dev.parent, "sending idadd message failed\n");
+
+ /* set CAN controller to reset mode */
+ msg.msg.hdr.len = 2;
+ msg.msg.hdr.cmd = CMD_SETBAUD;
+ msg.msg.setbaud.net = priv->index;
+ msg.msg.setbaud.rsvd = 0;
+ msg.msg.setbaud.baud = cpu_to_le32(ESD_USB2_NO_BAUDRATE);
+ if (esd_usb2_send_msg(priv->usb2, &msg) < 0)
+ dev_err(netdev->dev.parent, "sending setbaud message failed\n");
+
+ priv->can.state = CAN_STATE_STOPPED;
+
+ netif_stop_queue(netdev);
+
+ close_candev(netdev);
+
+ priv->open_time = 0;
+
+ return 0;
+}
+
+static const struct net_device_ops esd_usb2_netdev_ops = {
+ .ndo_open = esd_usb2_open,
+ .ndo_stop = esd_usb2_close,
+ .ndo_start_xmit = esd_usb2_start_xmit,
+};
+
+static struct can_bittiming_const esd_usb2_bittiming_const = {
+ .name = "esd_usb2",
+ .tseg1_min = ESD_USB2_TSEG1_MIN,
+ .tseg1_max = ESD_USB2_TSEG1_MAX,
+ .tseg2_min = ESD_USB2_TSEG2_MIN,
+ .tseg2_max = ESD_USB2_TSEG2_MAX,
+ .sjw_max = ESD_USB2_SJW_MAX,
+ .brp_min = ESD_USB2_BRP_MIN,
+ .brp_max = ESD_USB2_BRP_MAX,
+ .brp_inc = ESD_USB2_BRP_INC,
+};
+
+static int esd_usb2_set_bittiming(struct net_device *netdev)
+{
+ struct esd_usb2_net_priv *priv = netdev_priv(netdev);
+ struct can_bittiming *bt = &priv->can.bittiming;
+ struct esd_usb2_msg msg;
+ u32 canbtr;
+
+ canbtr = ESD_USB2_UBR;
+ canbtr |= (bt->brp - 1) & (ESD_USB2_BRP_MAX - 1);
+ canbtr |= ((bt->sjw - 1) & (ESD_USB2_SJW_MAX - 1))
+ << ESD_USB2_SJW_SHIFT;
+ canbtr |= ((bt->prop_seg + bt->phase_seg1 - 1)
+ & (ESD_USB2_TSEG1_MAX - 1))
+ << ESD_USB2_TSEG1_SHIFT;
+ canbtr |= ((bt->phase_seg2 - 1) & (ESD_USB2_TSEG2_MAX - 1))
+ << ESD_USB2_TSEG2_SHIFT;
+ if (priv->can.ctrlmode & CAN_CTRLMODE_3_SAMPLES)
+ canbtr |= ESD_USB2_3_SAMPLES;
+
+ msg.msg.hdr.len = 2;
+ msg.msg.hdr.cmd = CMD_SETBAUD;
+ msg.msg.setbaud.net = priv->index;
+ msg.msg.setbaud.rsvd = 0;
+ msg.msg.setbaud.baud = cpu_to_le32(canbtr);
+
+ dev_info(netdev->dev.parent, "setting BTR=%#x\n", canbtr);
+
+ return esd_usb2_send_msg(priv->usb2, &msg);
+}
+
+static int esd_usb2_get_berr_counter(const struct net_device *netdev,
+ struct can_berr_counter *bec)
+{
+ struct esd_usb2_net_priv *priv = netdev_priv(netdev);
+
+ bec->txerr = priv->bec.txerr;
+ bec->rxerr = priv->bec.rxerr;
+
+ return 0;
+}
+
+static int esd_usb2_set_mode(struct net_device *netdev, enum can_mode mode)
+{
+ struct esd_usb2_net_priv *priv = netdev_priv(netdev);
+
+ if (!priv->open_time)
+ return -EINVAL;
+
+ switch (mode) {
+ case CAN_MODE_START:
+ netif_wake_queue(netdev);
+ break;
+
+ default:
+ return -EOPNOTSUPP;
+ }
+
+ return 0;
+}
+
+static int esd_usb2_probe_one_net(struct usb_interface *intf, int index)
+{
+ struct esd_usb2 *dev = usb_get_intfdata(intf);
+ struct net_device *netdev;
+ struct esd_usb2_net_priv *priv;
+ int err = 0;
+ int i;
+
+ netdev = alloc_candev(sizeof(*priv), MAX_TX_URBS);
+ if (!netdev) {
+ dev_err(&intf->dev, "couldn't alloc candev\n");
+ err = -ENOMEM;
+ goto done;
+ }
+
+ priv = netdev_priv(netdev);
+
+ init_usb_anchor(&priv->tx_submitted);
+ atomic_set(&priv->active_tx_jobs, 0);
+
+ for (i = 0; i < MAX_TX_URBS; i++)
+ priv->tx_contexts[i].echo_index = MAX_TX_URBS;
+
+ priv->usb2 = dev;
+ priv->netdev = netdev;
+ priv->index = index;
+
+ priv->can.state = CAN_STATE_STOPPED;
+ priv->can.clock.freq = ESD_USB2_CAN_CLOCK;
+ priv->can.bittiming_const = &esd_usb2_bittiming_const;
+ priv->can.do_set_bittiming = esd_usb2_set_bittiming;
+ priv->can.do_set_mode = esd_usb2_set_mode;
+ priv->can.do_get_berr_counter = esd_usb2_get_berr_counter;
+ priv->can.ctrlmode_supported = CAN_CTRLMODE_3_SAMPLES;
+
+ netdev->flags |= IFF_ECHO; /* we support local echo */
+
+ netdev->netdev_ops = &esd_usb2_netdev_ops;
+
+ SET_NETDEV_DEV(netdev, &intf->dev);
+
+ err = register_candev(netdev);
+ if (err) {
+ dev_err(&intf->dev,
+ "couldn't register CAN device: %d\n", err);
+ free_candev(netdev);
+ err = -ENOMEM;
+ goto done;
+ }
+
+ dev->nets[index] = priv;
+ dev_info(netdev->dev.parent, "device %s registered\n", netdev->name);
+
+done:
+ return err;
+}
+
+/*
+ * probe function for new USB2 devices
+ *
+ * check version information and number of available
+ * CAN interfaces
+ */
+static int esd_usb2_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+{
+ struct esd_usb2 *dev;
+ struct esd_usb2_msg msg;
+ int i, err;
+
+ dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+ if (!dev) {
+ err = -ENOMEM;
+ goto done;
+ }
+
+ dev->udev = interface_to_usbdev(intf);
+
+ init_usb_anchor(&dev->rx_submitted);
+
+ usb_set_intfdata(intf, dev);
+
+ /* query number of CAN interfaces (nets) */
+ msg.msg.hdr.cmd = CMD_VERSION;
+ msg.msg.hdr.len = 2;
+ msg.msg.version.rsvd = 0;
+ msg.msg.version.flags = 0;
+ msg.msg.version.drv_version = 0;
+
+ err = esd_usb2_send_msg(dev, &msg);
+ if (err < 0) {
+ dev_err(&intf->dev, "sending version message failed\n");
+ goto free_dev;
+ }
+
+ err = esd_usb2_wait_msg(dev, &msg);
+ if (err < 0) {
+ dev_err(&intf->dev, "no version message answer\n");
+ goto free_dev;
+ }
+
+ dev->net_count = (int)msg.msg.version_reply.nets;
+ dev->version = le32_to_cpu(msg.msg.version_reply.version);
+
+ if (device_create_file(&intf->dev, &dev_attr_firmware))
+ dev_err(&intf->dev,
+ "Couldn't create device file for firmware\n");
+
+ if (device_create_file(&intf->dev, &dev_attr_hardware))
+ dev_err(&intf->dev,
+ "Couldn't create device file for hardware\n");
+
+ if (device_create_file(&intf->dev, &dev_attr_nets))
+ dev_err(&intf->dev,
+ "Couldn't create device file for nets\n");
+
+ /* do per device probing */
+ for (i = 0; i < dev->net_count; i++)
+ esd_usb2_probe_one_net(intf, i);
+
+ return 0;
+
+free_dev:
+ kfree(dev);
+done:
+ return err;
+}
+
+/*
+ * called by the usb core when the device is removed from the system
+ */
+static void esd_usb2_disconnect(struct usb_interface *intf)
+{
+ struct esd_usb2 *dev = usb_get_intfdata(intf);
+ struct net_device *netdev;
+ int i;
+
+ device_remove_file(&intf->dev, &dev_attr_firmware);
+ device_remove_file(&intf->dev, &dev_attr_hardware);
+ device_remove_file(&intf->dev, &dev_attr_nets);
+
+ usb_set_intfdata(intf, NULL);
+
+ if (dev) {
+ for (i = 0; i < dev->net_count; i++) {
+ if (dev->nets[i]) {
+ netdev = dev->nets[i]->netdev;
+ unregister_netdev(netdev);
+ free_candev(netdev);
+ }
+ }
+ unlink_all_urbs(dev);
+ }
+}
+
+/* usb specific object needed to register this driver with the usb subsystem */
+static struct usb_driver esd_usb2_driver = {
+ .name = "esd_usb2",
+ .probe = esd_usb2_probe,
+ .disconnect = esd_usb2_disconnect,
+ .id_table = esd_usb2_table,
+};
+
+static int __init esd_usb2_init(void)
+{
+ int err;
+
+ /* register this driver with the USB subsystem */
+ err = usb_register(&esd_usb2_driver);
+
+ if (err) {
+ err("usb_register failed. Error number %d\n", err);
+ return err;
+ }
+
+ return 0;
+}
+module_init(esd_usb2_init);
+
+static void __exit esd_usb2_exit(void)
+{
+ /* deregister this driver with the USB subsystem */
+ usb_deregister(&esd_usb2_driver);
+}
+module_exit(esd_usb2_exit);
diff --git a/drivers/net/cassini.c b/drivers/net/cassini.c
index 04a03f7003a..28c88eeec75 100644
--- a/drivers/net/cassini.c
+++ b/drivers/net/cassini.c
@@ -107,12 +107,7 @@
#define cas_page_unmap(x) kunmap_atomic((x), KM_SKB_DATA_SOFTIRQ)
#define CAS_NCPUS num_online_cpus()
-#ifdef CONFIG_CASSINI_NAPI
-#define USE_NAPI
-#define cas_skb_release(x) netif_receive_skb(x)
-#else
#define cas_skb_release(x) netif_rx(x)
-#endif
/* select which firmware to use */
#define USE_HP_WORKAROUND
@@ -3063,9 +3058,6 @@ static void cas_init_mac(struct cas *cp)
{
unsigned char *e = &cp->dev->dev_addr[0];
int i;
-#ifdef CONFIG_CASSINI_MULTICAST_REG_WRITE
- u32 rxcfg;
-#endif
cas_mac_reset(cp);
/* setup core arbitration weight register */
@@ -3133,23 +3125,8 @@ static void cas_init_mac(struct cas *cp)
writel(0xc200, cp->regs + REG_MAC_ADDRN(43));
writel(0x0180, cp->regs + REG_MAC_ADDRN(44));
-#ifndef CONFIG_CASSINI_MULTICAST_REG_WRITE
cp->mac_rx_cfg = cas_setup_multicast(cp);
-#else
- /* WTZ: Do what Adrian did in cas_set_multicast. Doing
- * a writel does not seem to be necessary because Cassini
- * seems to preserve the configuration when we do the reset.
- * If the chip is in trouble, though, it is not clear if we
- * can really count on this behavior. cas_set_multicast uses
- * spin_lock_irqsave, but we are called only in cas_init_hw and
- * cas_init_hw is protected by cas_lock_all, which calls
- * spin_lock_irq (so it doesn't need to save the flags, and
- * we should be OK for the writel, as that is the only
- * difference).
- */
- cp->mac_rx_cfg = rxcfg = cas_setup_multicast(cp);
- writel(rxcfg, cp->regs + REG_MAC_RX_CFG);
-#endif
+
spin_lock(&cp->stat_lock[N_TX_RINGS]);
cas_clear_mac_err(cp);
spin_unlock(&cp->stat_lock[N_TX_RINGS]);
diff --git a/drivers/net/cassini.h b/drivers/net/cassini.h
index fd17a002b45..dbc47878d83 100644
--- a/drivers/net/cassini.h
+++ b/drivers/net/cassini.h
@@ -2844,10 +2844,6 @@ struct cas {
atomic_t reset_task_pending_all;
#endif
-#ifdef CONFIG_CASSINI_QGE_DEBUG
- atomic_t interrupt_seen; /* 1 if any interrupts are getting through */
-#endif
-
/* Link-down problem workaround */
#define LINK_TRANSITION_UNKNOWN 0
#define LINK_TRANSITION_ON_FAILURE 1
diff --git a/drivers/net/chelsio/common.h b/drivers/net/chelsio/common.h
index 036b2dfb1d4..092f31a126e 100644
--- a/drivers/net/chelsio/common.h
+++ b/drivers/net/chelsio/common.h
@@ -286,7 +286,6 @@ struct board_info {
unsigned int clock_mc3;
unsigned int clock_mc4;
unsigned int espi_nports;
- unsigned int clock_cspi;
unsigned int clock_elmer0;
unsigned char mdio_mdien;
unsigned char mdio_mdiinv;
diff --git a/drivers/net/chelsio/subr.c b/drivers/net/chelsio/subr.c
index 53bde15fc94..599d178df62 100644
--- a/drivers/net/chelsio/subr.c
+++ b/drivers/net/chelsio/subr.c
@@ -185,9 +185,6 @@ static int t1_pci_intr_handler(adapter_t *adapter)
return 0;
}
-#ifdef CONFIG_CHELSIO_T1_COUGAR
-#include "cspi.h"
-#endif
#ifdef CONFIG_CHELSIO_T1_1G
#include "fpga_defs.h"
@@ -280,7 +277,7 @@ static void mi1_mdio_init(adapter_t *adapter, const struct board_info *bi)
t1_tpi_write(adapter, A_ELMER0_PORT0_MI1_CFG, val);
}
-#if defined(CONFIG_CHELSIO_T1_1G) || defined(CONFIG_CHELSIO_T1_COUGAR)
+#if defined(CONFIG_CHELSIO_T1_1G)
/*
* Elmer MI1 MDIO read/write operations.
*/
@@ -317,7 +314,7 @@ static int mi1_mdio_write(struct net_device *dev, int phy_addr, int mmd_addr,
return 0;
}
-#if defined(CONFIG_CHELSIO_T1_1G) || defined(CONFIG_CHELSIO_T1_COUGAR)
+#if defined(CONFIG_CHELSIO_T1_1G)
static const struct mdio_ops mi1_mdio_ops = {
.init = mi1_mdio_init,
.read = mi1_mdio_read,
@@ -752,31 +749,6 @@ int t1_elmer0_ext_intr_handler(adapter_t *adapter)
mod_detect ? "removed" : "inserted");
}
break;
-#ifdef CONFIG_CHELSIO_T1_COUGAR
- case CHBT_BOARD_COUGAR:
- if (adapter->params.nports == 1) {
- if (cause & ELMER0_GP_BIT1) { /* Vitesse MAC */
- struct cmac *mac = adapter->port[0].mac;
- mac->ops->interrupt_handler(mac);
- }
- if (cause & ELMER0_GP_BIT5) { /* XPAK MOD_DETECT */
- }
- } else {
- int i, port_bit;
-
- for_each_port(adapter, i) {
- port_bit = i ? i + 1 : 0;
- if (!(cause & (1 << port_bit)))
- continue;
-
- phy = adapter->port[i].phy;
- phy_cause = phy->ops->interrupt_handler(phy);
- if (phy_cause & cphy_cause_link_change)
- t1_link_changed(adapter, i);
- }
- }
- break;
-#endif
}
t1_tpi_write(adapter, A_ELMER0_INT_CAUSE, cause);
return 0;
@@ -955,7 +927,6 @@ static int board_init(adapter_t *adapter, const struct board_info *bi)
case CHBT_BOARD_N110:
case CHBT_BOARD_N210:
case CHBT_BOARD_CHT210:
- case CHBT_BOARD_COUGAR:
t1_tpi_par(adapter, 0xf);
t1_tpi_write(adapter, A_ELMER0_GPO, 0x800);
break;
@@ -1004,10 +975,6 @@ int t1_init_hw_modules(adapter_t *adapter)
adapter->regs + A_MC5_CONFIG);
}
-#ifdef CONFIG_CHELSIO_T1_COUGAR
- if (adapter->cspi && t1_cspi_init(adapter->cspi))
- goto out_err;
-#endif
if (adapter->espi && t1_espi_init(adapter->espi, bi->chip_mac,
bi->espi_nports))
goto out_err;
@@ -1061,10 +1028,6 @@ void t1_free_sw_modules(adapter_t *adapter)
t1_tp_destroy(adapter->tp);
if (adapter->espi)
t1_espi_destroy(adapter->espi);
-#ifdef CONFIG_CHELSIO_T1_COUGAR
- if (adapter->cspi)
- t1_cspi_destroy(adapter->cspi);
-#endif
}
static void __devinit init_link_config(struct link_config *lc,
@@ -1084,14 +1047,6 @@ static void __devinit init_link_config(struct link_config *lc,
}
}
-#ifdef CONFIG_CHELSIO_T1_COUGAR
- if (bi->clock_cspi && !(adapter->cspi = t1_cspi_create(adapter))) {
- pr_err("%s: CSPI initialization failed\n",
- adapter->name);
- goto error;
- }
-#endif
-
/*
* Allocate and initialize the data structures that hold the SW state of
* the Terminator HW modules.
diff --git a/drivers/net/cnic.c b/drivers/net/cnic.c
index 80471269977..09610323a94 100644
--- a/drivers/net/cnic.c
+++ b/drivers/net/cnic.c
@@ -40,9 +40,9 @@
#include "cnic_if.h"
#include "bnx2.h"
-#include "bnx2x_reg.h"
-#include "bnx2x_fw_defs.h"
-#include "bnx2x_hsi.h"
+#include "bnx2x/bnx2x_reg.h"
+#include "bnx2x/bnx2x_fw_defs.h"
+#include "bnx2x/bnx2x_hsi.h"
#include "../scsi/bnx2i/57xx_iscsi_constants.h"
#include "../scsi/bnx2i/57xx_iscsi_hsi.h"
#include "cnic.h"
@@ -257,7 +257,7 @@ static int cnic_get_l5_cid(struct cnic_local *cp, u32 cid, u32 *l5_cid)
{
u32 i;
- for (i = 0; i < MAX_ISCSI_TBL_SZ; i++) {
+ for (i = 0; i < cp->max_cid_space; i++) {
if (cp->ctx_tbl[i].cid == cid) {
*l5_cid = i;
return 0;
@@ -804,7 +804,7 @@ static void cnic_free_resc(struct cnic_dev *dev)
cnic_free_dma(dev, &cp->conn_buf_info);
cnic_free_dma(dev, &cp->kwq_info);
cnic_free_dma(dev, &cp->kwq_16_data_info);
- cnic_free_dma(dev, &cp->kcq_info);
+ cnic_free_dma(dev, &cp->kcq1.dma);
kfree(cp->iscsi_tbl);
cp->iscsi_tbl = NULL;
kfree(cp->ctx_tbl);
@@ -863,6 +863,37 @@ static int cnic_alloc_context(struct cnic_dev *dev)
return 0;
}
+static int cnic_alloc_kcq(struct cnic_dev *dev, struct kcq_info *info)
+{
+ int err, i, is_bnx2 = 0;
+ struct kcqe **kcq;
+
+ if (test_bit(CNIC_F_BNX2_CLASS, &dev->flags))
+ is_bnx2 = 1;
+
+ err = cnic_alloc_dma(dev, &info->dma, KCQ_PAGE_CNT, is_bnx2);
+ if (err)
+ return err;
+
+ kcq = (struct kcqe **) info->dma.pg_arr;
+ info->kcq = kcq;
+
+ if (is_bnx2)
+ return 0;
+
+ for (i = 0; i < KCQ_PAGE_CNT; i++) {
+ struct bnx2x_bd_chain_next *next =
+ (struct bnx2x_bd_chain_next *) &kcq[i][MAX_KCQE_CNT];
+ int j = i + 1;
+
+ if (j >= KCQ_PAGE_CNT)
+ j = 0;
+ next->addr_hi = (u64) info->dma.pg_map_arr[j] >> 32;
+ next->addr_lo = info->dma.pg_map_arr[j] & 0xffffffff;
+ }
+ return 0;
+}
+
static int cnic_alloc_l2_rings(struct cnic_dev *dev, int pages)
{
struct cnic_local *cp = dev->cnic_priv;
@@ -954,10 +985,9 @@ static int cnic_alloc_bnx2_resc(struct cnic_dev *dev)
goto error;
cp->kwq = (struct kwqe **) cp->kwq_info.pg_arr;
- ret = cnic_alloc_dma(dev, &cp->kcq_info, KCQ_PAGE_CNT, 1);
+ ret = cnic_alloc_kcq(dev, &cp->kcq1);
if (ret)
goto error;
- cp->kcq = (struct kcqe **) cp->kcq_info.pg_arr;
ret = cnic_alloc_context(dev);
if (ret)
@@ -981,17 +1011,10 @@ error:
static int cnic_alloc_bnx2x_context(struct cnic_dev *dev)
{
struct cnic_local *cp = dev->cnic_priv;
- struct cnic_eth_dev *ethdev = cp->ethdev;
int ctx_blk_size = cp->ethdev->ctx_blk_size;
- int total_mem, blks, i, cid_space;
-
- if (BNX2X_ISCSI_START_CID < ethdev->starting_cid)
- return -EINVAL;
-
- cid_space = MAX_ISCSI_TBL_SZ +
- (BNX2X_ISCSI_START_CID - ethdev->starting_cid);
+ int total_mem, blks, i;
- total_mem = BNX2X_CONTEXT_MEM_SIZE * cid_space;
+ total_mem = BNX2X_CONTEXT_MEM_SIZE * cp->max_cid_space;
blks = total_mem / ctx_blk_size;
if (total_mem % ctx_blk_size)
blks++;
@@ -1035,16 +1058,27 @@ static int cnic_alloc_bnx2x_context(struct cnic_dev *dev)
static int cnic_alloc_bnx2x_resc(struct cnic_dev *dev)
{
struct cnic_local *cp = dev->cnic_priv;
+ struct cnic_eth_dev *ethdev = cp->ethdev;
+ u32 start_cid = ethdev->starting_cid;
int i, j, n, ret, pages;
struct cnic_dma *kwq_16_dma = &cp->kwq_16_data_info;
+ cp->max_cid_space = MAX_ISCSI_TBL_SZ;
+ cp->iscsi_start_cid = start_cid;
+ if (start_cid < BNX2X_ISCSI_START_CID) {
+ u32 delta = BNX2X_ISCSI_START_CID - start_cid;
+
+ cp->iscsi_start_cid = BNX2X_ISCSI_START_CID;
+ cp->max_cid_space += delta;
+ }
+
cp->iscsi_tbl = kzalloc(sizeof(struct cnic_iscsi) * MAX_ISCSI_TBL_SZ,
GFP_KERNEL);
if (!cp->iscsi_tbl)
goto error;
cp->ctx_tbl = kzalloc(sizeof(struct cnic_context) *
- MAX_CNIC_L5_CONTEXT, GFP_KERNEL);
+ cp->max_cid_space, GFP_KERNEL);
if (!cp->ctx_tbl)
goto error;
@@ -1053,7 +1087,7 @@ static int cnic_alloc_bnx2x_resc(struct cnic_dev *dev)
cp->ctx_tbl[i].ulp_proto_id = CNIC_ULP_ISCSI;
}
- pages = PAGE_ALIGN(MAX_CNIC_L5_CONTEXT * CNIC_KWQ16_DATA_SIZE) /
+ pages = PAGE_ALIGN(cp->max_cid_space * CNIC_KWQ16_DATA_SIZE) /
PAGE_SIZE;
ret = cnic_alloc_dma(dev, kwq_16_dma, pages, 0);
@@ -1061,7 +1095,7 @@ static int cnic_alloc_bnx2x_resc(struct cnic_dev *dev)
return -ENOMEM;
n = PAGE_SIZE / CNIC_KWQ16_DATA_SIZE;
- for (i = 0, j = 0; i < MAX_ISCSI_TBL_SZ; i++) {
+ for (i = 0, j = 0; i < cp->max_cid_space; i++) {
long off = CNIC_KWQ16_DATA_SIZE * (i % n);
cp->ctx_tbl[i].kwqe_data = kwq_16_dma->pg_arr[j] + off;
@@ -1072,22 +1106,9 @@ static int cnic_alloc_bnx2x_resc(struct cnic_dev *dev)
j++;
}
- ret = cnic_alloc_dma(dev, &cp->kcq_info, KCQ_PAGE_CNT, 0);
+ ret = cnic_alloc_kcq(dev, &cp->kcq1);
if (ret)
goto error;
- cp->kcq = (struct kcqe **) cp->kcq_info.pg_arr;
-
- for (i = 0; i < KCQ_PAGE_CNT; i++) {
- struct bnx2x_bd_chain_next *next =
- (struct bnx2x_bd_chain_next *)
- &cp->kcq[i][MAX_KCQE_CNT];
- int j = i + 1;
-
- if (j >= KCQ_PAGE_CNT)
- j = 0;
- next->addr_hi = (u64) cp->kcq_info.pg_map_arr[j] >> 32;
- next->addr_lo = cp->kcq_info.pg_map_arr[j] & 0xffffffff;
- }
pages = PAGE_ALIGN(BNX2X_ISCSI_NUM_CONNECTIONS *
BNX2X_ISCSI_CONN_BUF_SIZE) / PAGE_SIZE;
@@ -2120,18 +2141,20 @@ static u16 cnic_bnx2x_hw_idx(u16 idx)
return idx;
}
-static int cnic_get_kcqes(struct cnic_dev *dev, u16 hw_prod, u16 *sw_prod)
+static int cnic_get_kcqes(struct cnic_dev *dev, struct kcq_info *info)
{
struct cnic_local *cp = dev->cnic_priv;
- u16 i, ri, last;
+ u16 i, ri, hw_prod, last;
struct kcqe *kcqe;
int kcqe_cnt = 0, last_cnt = 0;
- i = ri = last = *sw_prod;
+ i = ri = last = info->sw_prod_idx;
ri &= MAX_KCQ_IDX;
+ hw_prod = *info->hw_prod_idx_ptr;
+ hw_prod = cp->hw_idx(hw_prod);
while ((i != hw_prod) && (kcqe_cnt < MAX_COMPLETED_KCQE)) {
- kcqe = &cp->kcq[KCQ_PG(ri)][KCQ_IDX(ri)];
+ kcqe = &info->kcq[KCQ_PG(ri)][KCQ_IDX(ri)];
cp->completed_kcq[kcqe_cnt++] = kcqe;
i = cp->next_idx(i);
ri = i & MAX_KCQ_IDX;
@@ -2141,7 +2164,7 @@ static int cnic_get_kcqes(struct cnic_dev *dev, u16 hw_prod, u16 *sw_prod)
}
}
- *sw_prod = last;
+ info->sw_prod_idx = last;
return last_cnt;
}
@@ -2184,6 +2207,9 @@ static void cnic_chk_pkt_rings(struct cnic_local *cp)
u16 tx_cons = *cp->tx_cons_ptr;
int comp = 0;
+ if (!test_bit(CNIC_F_CNIC_UP, &cp->dev->flags))
+ return;
+
if (cp->tx_cons != tx_cons || cp->rx_cons != rx_cons) {
if (test_bit(CNIC_LCL_FL_L2_WAIT, &cp->cnic_local_flags))
comp = cnic_l2_completion(cp);
@@ -2197,103 +2223,79 @@ static void cnic_chk_pkt_rings(struct cnic_local *cp)
clear_bit(CNIC_LCL_FL_L2_WAIT, &cp->cnic_local_flags);
}
-static int cnic_service_bnx2(void *data, void *status_blk)
+static u32 cnic_service_bnx2_queues(struct cnic_dev *dev)
{
- struct cnic_dev *dev = data;
- struct status_block *sblk = status_blk;
struct cnic_local *cp = dev->cnic_priv;
- u32 status_idx = sblk->status_idx;
- u16 hw_prod, sw_prod;
+ u32 status_idx = (u16) *cp->kcq1.status_idx_ptr;
int kcqe_cnt;
- if (unlikely(!test_bit(CNIC_F_CNIC_UP, &dev->flags)))
- return status_idx;
-
cp->kwq_con_idx = *cp->kwq_con_idx_ptr;
- hw_prod = sblk->status_completion_producer_index;
- sw_prod = cp->kcq_prod_idx;
- while (sw_prod != hw_prod) {
- kcqe_cnt = cnic_get_kcqes(dev, hw_prod, &sw_prod);
- if (kcqe_cnt == 0)
- goto done;
+ while ((kcqe_cnt = cnic_get_kcqes(dev, &cp->kcq1))) {
service_kcqes(dev, kcqe_cnt);
/* Tell compiler that status_blk fields can change. */
barrier();
- if (status_idx != sblk->status_idx) {
- status_idx = sblk->status_idx;
+ if (status_idx != *cp->kcq1.status_idx_ptr) {
+ status_idx = (u16) *cp->kcq1.status_idx_ptr;
cp->kwq_con_idx = *cp->kwq_con_idx_ptr;
- hw_prod = sblk->status_completion_producer_index;
} else
break;
}
-done:
- CNIC_WR16(dev, cp->kcq_io_addr, sw_prod);
-
- cp->kcq_prod_idx = sw_prod;
+ CNIC_WR16(dev, cp->kcq1.io_addr, cp->kcq1.sw_prod_idx);
cnic_chk_pkt_rings(cp);
+
return status_idx;
}
-static void cnic_service_bnx2_msix(unsigned long data)
+static int cnic_service_bnx2(void *data, void *status_blk)
{
- struct cnic_dev *dev = (struct cnic_dev *) data;
+ struct cnic_dev *dev = data;
struct cnic_local *cp = dev->cnic_priv;
- struct status_block_msix *status_blk = cp->status_blk.bnx2;
- u32 status_idx = status_blk->status_idx;
- u16 hw_prod, sw_prod;
- int kcqe_cnt;
+ u32 status_idx = *cp->kcq1.status_idx_ptr;
- cp->kwq_con_idx = status_blk->status_cmd_consumer_index;
-
- hw_prod = status_blk->status_completion_producer_index;
- sw_prod = cp->kcq_prod_idx;
- while (sw_prod != hw_prod) {
- kcqe_cnt = cnic_get_kcqes(dev, hw_prod, &sw_prod);
- if (kcqe_cnt == 0)
- goto done;
-
- service_kcqes(dev, kcqe_cnt);
+ if (unlikely(!test_bit(CNIC_F_CNIC_UP, &dev->flags)))
+ return status_idx;
- /* Tell compiler that status_blk fields can change. */
- barrier();
- if (status_idx != status_blk->status_idx) {
- status_idx = status_blk->status_idx;
- cp->kwq_con_idx = status_blk->status_cmd_consumer_index;
- hw_prod = status_blk->status_completion_producer_index;
- } else
- break;
- }
+ return cnic_service_bnx2_queues(dev);
+}
-done:
- CNIC_WR16(dev, cp->kcq_io_addr, sw_prod);
- cp->kcq_prod_idx = sw_prod;
+static void cnic_service_bnx2_msix(unsigned long data)
+{
+ struct cnic_dev *dev = (struct cnic_dev *) data;
+ struct cnic_local *cp = dev->cnic_priv;
- cnic_chk_pkt_rings(cp);
+ cp->last_status_idx = cnic_service_bnx2_queues(dev);
- cp->last_status_idx = status_idx;
CNIC_WR(dev, BNX2_PCICFG_INT_ACK_CMD, cp->int_num |
BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID | cp->last_status_idx);
}
+static void cnic_doirq(struct cnic_dev *dev)
+{
+ struct cnic_local *cp = dev->cnic_priv;
+ u16 prod = cp->kcq1.sw_prod_idx & MAX_KCQ_IDX;
+
+ if (likely(test_bit(CNIC_F_CNIC_UP, &dev->flags))) {
+ prefetch(cp->status_blk.gen);
+ prefetch(&cp->kcq1.kcq[KCQ_PG(prod)][KCQ_IDX(prod)]);
+
+ tasklet_schedule(&cp->cnic_irq_task);
+ }
+}
+
static irqreturn_t cnic_irq(int irq, void *dev_instance)
{
struct cnic_dev *dev = dev_instance;
struct cnic_local *cp = dev->cnic_priv;
- u16 prod = cp->kcq_prod_idx & MAX_KCQ_IDX;
if (cp->ack_int)
cp->ack_int(dev);
- prefetch(cp->status_blk.gen);
- prefetch(&cp->kcq[KCQ_PG(prod)][KCQ_IDX(prod)]);
-
- if (likely(test_bit(CNIC_F_CNIC_UP, &dev->flags)))
- tasklet_schedule(&cp->cnic_irq_task);
+ cnic_doirq(dev);
return IRQ_HANDLED;
}
@@ -2324,60 +2326,50 @@ static void cnic_ack_bnx2x_msix(struct cnic_dev *dev)
IGU_INT_DISABLE, 0);
}
-static void cnic_service_bnx2x_bh(unsigned long data)
+static u32 cnic_service_bnx2x_kcq(struct cnic_dev *dev, struct kcq_info *info)
{
- struct cnic_dev *dev = (struct cnic_dev *) data;
- struct cnic_local *cp = dev->cnic_priv;
- u16 hw_prod, sw_prod;
- struct cstorm_status_block_c *sblk =
- &cp->status_blk.bnx2x->c_status_block;
- u32 status_idx = sblk->status_block_index;
+ u32 last_status = *info->status_idx_ptr;
int kcqe_cnt;
- if (unlikely(!test_bit(CNIC_F_CNIC_UP, &dev->flags)))
- return;
-
- hw_prod = sblk->index_values[HC_INDEX_C_ISCSI_EQ_CONS];
- hw_prod = cp->hw_idx(hw_prod);
- sw_prod = cp->kcq_prod_idx;
- while (sw_prod != hw_prod) {
- kcqe_cnt = cnic_get_kcqes(dev, hw_prod, &sw_prod);
- if (kcqe_cnt == 0)
- goto done;
+ while ((kcqe_cnt = cnic_get_kcqes(dev, info))) {
service_kcqes(dev, kcqe_cnt);
/* Tell compiler that sblk fields can change. */
barrier();
- if (status_idx == sblk->status_block_index)
+ if (last_status == *info->status_idx_ptr)
break;
- status_idx = sblk->status_block_index;
- hw_prod = sblk->index_values[HC_INDEX_C_ISCSI_EQ_CONS];
- hw_prod = cp->hw_idx(hw_prod);
+ last_status = *info->status_idx_ptr;
}
+ return last_status;
+}
-done:
- CNIC_WR16(dev, cp->kcq_io_addr, sw_prod + MAX_KCQ_IDX);
+static void cnic_service_bnx2x_bh(unsigned long data)
+{
+ struct cnic_dev *dev = (struct cnic_dev *) data;
+ struct cnic_local *cp = dev->cnic_priv;
+ u32 status_idx;
+
+ if (unlikely(!test_bit(CNIC_F_CNIC_UP, &dev->flags)))
+ return;
+
+ status_idx = cnic_service_bnx2x_kcq(dev, &cp->kcq1);
+
+ CNIC_WR16(dev, cp->kcq1.io_addr, cp->kcq1.sw_prod_idx + MAX_KCQ_IDX);
cnic_ack_bnx2x_int(dev, cp->status_blk_num, CSTORM_ID,
status_idx, IGU_INT_ENABLE, 1);
-
- cp->kcq_prod_idx = sw_prod;
}
static int cnic_service_bnx2x(void *data, void *status_blk)
{
struct cnic_dev *dev = data;
struct cnic_local *cp = dev->cnic_priv;
- u16 prod = cp->kcq_prod_idx & MAX_KCQ_IDX;
- if (likely(test_bit(CNIC_F_CNIC_UP, &dev->flags))) {
- prefetch(cp->status_blk.bnx2x);
- prefetch(&cp->kcq[KCQ_PG(prod)][KCQ_IDX(prod)]);
+ if (!(cp->ethdev->drv_state & CNIC_DRV_STATE_USING_MSIX))
+ cnic_doirq(dev);
- tasklet_schedule(&cp->cnic_irq_task);
- cnic_chk_pkt_rings(cp);
- }
+ cnic_chk_pkt_rings(cp);
return 0;
}
@@ -2824,7 +2816,7 @@ static int cnic_get_v4_route(struct sockaddr_in *dst_addr,
err = ip_route_output_key(&init_net, &rt, &fl);
if (!err)
- *dst = &rt->u.dst;
+ *dst = &rt->dst;
return err;
#else
return -ENETUNREACH;
@@ -2996,7 +2988,7 @@ err_out:
static int cnic_cm_abort(struct cnic_sock *csk)
{
struct cnic_local *cp = csk->dev->cnic_priv;
- u32 opcode;
+ u32 opcode = L4_KCQE_OPCODE_VALUE_RESET_COMP;
if (!cnic_in_use(csk))
return -EINVAL;
@@ -3008,12 +3000,9 @@ static int cnic_cm_abort(struct cnic_sock *csk)
* connect was not successful.
*/
- csk->state = L4_KCQE_OPCODE_VALUE_RESET_COMP;
- if (test_bit(SK_F_PG_OFFLD_COMPLETE, &csk->flags))
- opcode = csk->state;
- else
- opcode = L5CM_RAMROD_CMD_ID_TERMINATE_OFFLOAD;
cp->close_conn(csk, opcode);
+ if (csk->state != opcode)
+ return -EALREADY;
return 0;
}
@@ -3026,6 +3015,8 @@ static int cnic_cm_close(struct cnic_sock *csk)
if (cnic_close_prep(csk)) {
csk->state = L4_KCQE_OPCODE_VALUE_CLOSE_COMP;
return cnic_cm_close_req(csk);
+ } else {
+ return -EALREADY;
}
return 0;
}
@@ -3141,12 +3132,6 @@ static void cnic_cm_process_kcqe(struct cnic_dev *dev, struct kcqe *kcqe)
break;
case L4_KCQE_OPCODE_VALUE_RESET_RECEIVED:
- if (test_bit(CNIC_F_BNX2_CLASS, &dev->flags)) {
- cnic_cm_upcall(cp, csk, opcode);
- break;
- } else if (test_and_clear_bit(SK_F_OFFLD_COMPLETE, &csk->flags))
- csk->state = opcode;
- /* fall through */
case L4_KCQE_OPCODE_VALUE_CLOSE_COMP:
case L4_KCQE_OPCODE_VALUE_RESET_COMP:
case L5CM_RAMROD_CMD_ID_SEARCHER_DELETE:
@@ -3202,19 +3187,22 @@ static int cnic_cm_alloc_mem(struct cnic_dev *dev)
static int cnic_ready_to_close(struct cnic_sock *csk, u32 opcode)
{
- if ((opcode == csk->state) ||
- (opcode == L4_KCQE_OPCODE_VALUE_RESET_RECEIVED &&
- csk->state == L4_KCQE_OPCODE_VALUE_CLOSE_COMP)) {
- if (!test_and_set_bit(SK_F_CLOSING, &csk->flags))
- return 1;
+ if (test_and_clear_bit(SK_F_OFFLD_COMPLETE, &csk->flags)) {
+ /* Unsolicited RESET_COMP or RESET_RECEIVED */
+ opcode = L4_KCQE_OPCODE_VALUE_RESET_RECEIVED;
+ csk->state = opcode;
}
- /* 57710+ only workaround to handle unsolicited RESET_COMP
- * which will be treated like a RESET RCVD notification
- * which triggers the clean up procedure
+
+ /* 1. If event opcode matches the expected event in csk->state
+ * 2. If the expected event is CLOSE_COMP, we accept any event
+ * 3. If the expected event is 0, meaning the connection was never
+ * never established, we accept the opcode from cm_abort.
*/
- else if (opcode == L4_KCQE_OPCODE_VALUE_RESET_COMP) {
+ if (opcode == csk->state || csk->state == 0 ||
+ csk->state == L4_KCQE_OPCODE_VALUE_CLOSE_COMP) {
if (!test_and_set_bit(SK_F_CLOSING, &csk->flags)) {
- csk->state = L4_KCQE_OPCODE_VALUE_RESET_RECEIVED;
+ if (csk->state == 0)
+ csk->state = opcode;
return 1;
}
}
@@ -3226,8 +3214,14 @@ static void cnic_close_bnx2_conn(struct cnic_sock *csk, u32 opcode)
struct cnic_dev *dev = csk->dev;
struct cnic_local *cp = dev->cnic_priv;
+ if (opcode == L4_KCQE_OPCODE_VALUE_RESET_RECEIVED) {
+ cnic_cm_upcall(cp, csk, opcode);
+ return;
+ }
+
clear_bit(SK_F_CONNECT_START, &csk->flags);
cnic_close_conn(csk);
+ csk->state = opcode;
cnic_cm_upcall(cp, csk, opcode);
}
@@ -3257,8 +3251,12 @@ static void cnic_close_bnx2x_conn(struct cnic_sock *csk, u32 opcode)
case L4_KCQE_OPCODE_VALUE_RESET_RECEIVED:
case L4_KCQE_OPCODE_VALUE_CLOSE_COMP:
case L4_KCQE_OPCODE_VALUE_RESET_COMP:
- if (cnic_ready_to_close(csk, opcode))
- cmd = L5CM_RAMROD_CMD_ID_SEARCHER_DELETE;
+ if (cnic_ready_to_close(csk, opcode)) {
+ if (test_bit(SK_F_PG_OFFLD_COMPLETE, &csk->flags))
+ cmd = L5CM_RAMROD_CMD_ID_SEARCHER_DELETE;
+ else
+ close_complete = 1;
+ }
break;
case L5CM_RAMROD_CMD_ID_SEARCHER_DELETE:
cmd = L5CM_RAMROD_CMD_ID_TERMINATE_OFFLOAD;
@@ -3694,7 +3692,7 @@ static int cnic_start_bnx2_hw(struct cnic_dev *dev)
struct cnic_local *cp = dev->cnic_priv;
struct cnic_eth_dev *ethdev = cp->ethdev;
struct status_block *sblk = cp->status_blk.gen;
- u32 val;
+ u32 val, kcq_cid_addr, kwq_cid_addr;
int err;
cnic_set_bnx2_mac(dev);
@@ -3719,7 +3717,7 @@ static int cnic_start_bnx2_hw(struct cnic_dev *dev)
cnic_init_context(dev, KWQ_CID);
cnic_init_context(dev, KCQ_CID);
- cp->kwq_cid_addr = GET_CID_ADDR(KWQ_CID);
+ kwq_cid_addr = GET_CID_ADDR(KWQ_CID);
cp->kwq_io_addr = MB_GET_CID_ADDR(KWQ_CID) + L5_KRNLQ_HOST_QIDX;
cp->max_kwq_idx = MAX_KWQ_IDX;
@@ -3735,50 +3733,59 @@ static int cnic_start_bnx2_hw(struct cnic_dev *dev)
/* Initialize the kernel work queue context. */
val = KRNLQ_TYPE_TYPE_KRNLQ | KRNLQ_SIZE_TYPE_SIZE |
(BCM_PAGE_BITS - 8) | KRNLQ_FLAGS_QE_SELF_SEQ;
- cnic_ctx_wr(dev, cp->kwq_cid_addr, L5_KRNLQ_TYPE, val);
+ cnic_ctx_wr(dev, kwq_cid_addr, L5_KRNLQ_TYPE, val);
val = (BCM_PAGE_SIZE / sizeof(struct kwqe) - 1) << 16;
- cnic_ctx_wr(dev, cp->kwq_cid_addr, L5_KRNLQ_QE_SELF_SEQ_MAX, val);
+ cnic_ctx_wr(dev, kwq_cid_addr, L5_KRNLQ_QE_SELF_SEQ_MAX, val);
val = ((BCM_PAGE_SIZE / sizeof(struct kwqe)) << 16) | KWQ_PAGE_CNT;
- cnic_ctx_wr(dev, cp->kwq_cid_addr, L5_KRNLQ_PGTBL_NPAGES, val);
+ cnic_ctx_wr(dev, kwq_cid_addr, L5_KRNLQ_PGTBL_NPAGES, val);
val = (u32) ((u64) cp->kwq_info.pgtbl_map >> 32);
- cnic_ctx_wr(dev, cp->kwq_cid_addr, L5_KRNLQ_PGTBL_HADDR_HI, val);
+ cnic_ctx_wr(dev, kwq_cid_addr, L5_KRNLQ_PGTBL_HADDR_HI, val);
val = (u32) cp->kwq_info.pgtbl_map;
- cnic_ctx_wr(dev, cp->kwq_cid_addr, L5_KRNLQ_PGTBL_HADDR_LO, val);
+ cnic_ctx_wr(dev, kwq_cid_addr, L5_KRNLQ_PGTBL_HADDR_LO, val);
+
+ kcq_cid_addr = GET_CID_ADDR(KCQ_CID);
+ cp->kcq1.io_addr = MB_GET_CID_ADDR(KCQ_CID) + L5_KRNLQ_HOST_QIDX;
- cp->kcq_cid_addr = GET_CID_ADDR(KCQ_CID);
- cp->kcq_io_addr = MB_GET_CID_ADDR(KCQ_CID) + L5_KRNLQ_HOST_QIDX;
+ cp->kcq1.sw_prod_idx = 0;
+ cp->kcq1.hw_prod_idx_ptr =
+ (u16 *) &sblk->status_completion_producer_index;
- cp->kcq_prod_idx = 0;
+ cp->kcq1.status_idx_ptr = (u16 *) &sblk->status_idx;
/* Initialize the kernel complete queue context. */
val = KRNLQ_TYPE_TYPE_KRNLQ | KRNLQ_SIZE_TYPE_SIZE |
(BCM_PAGE_BITS - 8) | KRNLQ_FLAGS_QE_SELF_SEQ;
- cnic_ctx_wr(dev, cp->kcq_cid_addr, L5_KRNLQ_TYPE, val);
+ cnic_ctx_wr(dev, kcq_cid_addr, L5_KRNLQ_TYPE, val);
val = (BCM_PAGE_SIZE / sizeof(struct kcqe) - 1) << 16;
- cnic_ctx_wr(dev, cp->kcq_cid_addr, L5_KRNLQ_QE_SELF_SEQ_MAX, val);
+ cnic_ctx_wr(dev, kcq_cid_addr, L5_KRNLQ_QE_SELF_SEQ_MAX, val);
val = ((BCM_PAGE_SIZE / sizeof(struct kcqe)) << 16) | KCQ_PAGE_CNT;
- cnic_ctx_wr(dev, cp->kcq_cid_addr, L5_KRNLQ_PGTBL_NPAGES, val);
+ cnic_ctx_wr(dev, kcq_cid_addr, L5_KRNLQ_PGTBL_NPAGES, val);
- val = (u32) ((u64) cp->kcq_info.pgtbl_map >> 32);
- cnic_ctx_wr(dev, cp->kcq_cid_addr, L5_KRNLQ_PGTBL_HADDR_HI, val);
+ val = (u32) ((u64) cp->kcq1.dma.pgtbl_map >> 32);
+ cnic_ctx_wr(dev, kcq_cid_addr, L5_KRNLQ_PGTBL_HADDR_HI, val);
- val = (u32) cp->kcq_info.pgtbl_map;
- cnic_ctx_wr(dev, cp->kcq_cid_addr, L5_KRNLQ_PGTBL_HADDR_LO, val);
+ val = (u32) cp->kcq1.dma.pgtbl_map;
+ cnic_ctx_wr(dev, kcq_cid_addr, L5_KRNLQ_PGTBL_HADDR_LO, val);
cp->int_num = 0;
if (ethdev->drv_state & CNIC_DRV_STATE_USING_MSIX) {
+ struct status_block_msix *msblk = cp->status_blk.bnx2;
u32 sb_id = cp->status_blk_num;
u32 sb = BNX2_L2CTX_L5_STATUSB_NUM(sb_id);
+ cp->kcq1.hw_prod_idx_ptr =
+ (u16 *) &msblk->status_completion_producer_index;
+ cp->kcq1.status_idx_ptr = (u16 *) &msblk->status_idx;
+ cp->kwq_con_idx_ptr = (u16 *) &msblk->status_cmd_consumer_index;
cp->int_num = sb_id << BNX2_PCICFG_INT_ACK_CMD_INT_NUM_SHIFT;
- cnic_ctx_wr(dev, cp->kwq_cid_addr, L5_KRNLQ_HOST_QIDX, sb);
- cnic_ctx_wr(dev, cp->kcq_cid_addr, L5_KRNLQ_HOST_QIDX, sb);
+ cnic_ctx_wr(dev, kwq_cid_addr, L5_KRNLQ_HOST_QIDX, sb);
+ cnic_ctx_wr(dev, kcq_cid_addr, L5_KRNLQ_HOST_QIDX, sb);
}
/* Enable Commnad Scheduler notification when we write to the
@@ -4123,33 +4130,39 @@ static int cnic_start_bnx2x_hw(struct cnic_dev *dev)
u8 sb_id = cp->status_blk_num;
ret = cnic_init_id_tbl(&cp->cid_tbl, MAX_ISCSI_TBL_SZ,
- BNX2X_ISCSI_START_CID);
+ cp->iscsi_start_cid);
if (ret)
return -ENOMEM;
- cp->kcq_io_addr = BAR_CSTRORM_INTMEM +
+ cp->kcq1.io_addr = BAR_CSTRORM_INTMEM +
CSTORM_ISCSI_EQ_PROD_OFFSET(func, 0);
- cp->kcq_prod_idx = 0;
+ cp->kcq1.sw_prod_idx = 0;
+
+ cp->kcq1.hw_prod_idx_ptr =
+ &cp->status_blk.bnx2x->c_status_block.index_values[
+ HC_INDEX_C_ISCSI_EQ_CONS];
+ cp->kcq1.status_idx_ptr =
+ &cp->status_blk.bnx2x->c_status_block.status_block_index;
cnic_get_bnx2x_iscsi_info(dev);
/* Only 1 EQ */
- CNIC_WR16(dev, cp->kcq_io_addr, MAX_KCQ_IDX);
+ CNIC_WR16(dev, cp->kcq1.io_addr, MAX_KCQ_IDX);
CNIC_WR(dev, BAR_CSTRORM_INTMEM +
CSTORM_ISCSI_EQ_CONS_OFFSET(func, 0), 0);
CNIC_WR(dev, BAR_CSTRORM_INTMEM +
CSTORM_ISCSI_EQ_NEXT_PAGE_ADDR_OFFSET(func, 0),
- cp->kcq_info.pg_map_arr[1] & 0xffffffff);
+ cp->kcq1.dma.pg_map_arr[1] & 0xffffffff);
CNIC_WR(dev, BAR_CSTRORM_INTMEM +
CSTORM_ISCSI_EQ_NEXT_PAGE_ADDR_OFFSET(func, 0) + 4,
- (u64) cp->kcq_info.pg_map_arr[1] >> 32);
+ (u64) cp->kcq1.dma.pg_map_arr[1] >> 32);
CNIC_WR(dev, BAR_CSTRORM_INTMEM +
CSTORM_ISCSI_EQ_NEXT_EQE_ADDR_OFFSET(func, 0),
- cp->kcq_info.pg_map_arr[0] & 0xffffffff);
+ cp->kcq1.dma.pg_map_arr[0] & 0xffffffff);
CNIC_WR(dev, BAR_CSTRORM_INTMEM +
CSTORM_ISCSI_EQ_NEXT_EQE_ADDR_OFFSET(func, 0) + 4,
- (u64) cp->kcq_info.pg_map_arr[0] >> 32);
+ (u64) cp->kcq1.dma.pg_map_arr[0] >> 32);
CNIC_WR8(dev, BAR_CSTRORM_INTMEM +
CSTORM_ISCSI_EQ_NEXT_PAGE_ADDR_VALID_OFFSET(func, 0), 1);
CNIC_WR16(dev, BAR_CSTRORM_INTMEM +
@@ -4377,7 +4390,7 @@ static void cnic_stop_bnx2x_hw(struct cnic_dev *dev)
0);
CNIC_WR(dev, BAR_CSTRORM_INTMEM +
CSTORM_ISCSI_EQ_CONS_OFFSET(cp->func, 0), 0);
- CNIC_WR16(dev, cp->kcq_io_addr, 0);
+ CNIC_WR16(dev, cp->kcq1.io_addr, 0);
cnic_free_resc(dev);
}
diff --git a/drivers/net/cnic.h b/drivers/net/cnic.h
index 08b1235d987..275c36114d8 100644
--- a/drivers/net/cnic.h
+++ b/drivers/net/cnic.h
@@ -169,6 +169,16 @@ struct cnic_context {
} proto;
};
+struct kcq_info {
+ struct cnic_dma dma;
+ struct kcqe **kcq;
+
+ u16 *hw_prod_idx_ptr;
+ u16 sw_prod_idx;
+ u16 *status_idx_ptr;
+ u32 io_addr;
+};
+
struct cnic_local {
spinlock_t cnic_ulp_lock;
@@ -202,9 +212,6 @@ struct cnic_local {
u16 rx_cons;
u16 tx_cons;
- u32 kwq_cid_addr;
- u32 kcq_cid_addr;
-
struct cnic_dma kwq_info;
struct kwqe **kwq;
@@ -218,11 +225,7 @@ struct cnic_local {
u16 *kwq_con_idx_ptr;
u16 kwq_con_idx;
- struct cnic_dma kcq_info;
- struct kcqe **kcq;
-
- u16 kcq_prod_idx;
- u32 kcq_io_addr;
+ struct kcq_info kcq1;
union {
void *gen;
@@ -248,8 +251,10 @@ struct cnic_local {
struct cnic_iscsi *iscsi_tbl;
struct cnic_context *ctx_tbl;
struct cnic_id_tbl cid_tbl;
- int max_iscsi_conn;
atomic_t iscsi_conn;
+ u32 iscsi_start_cid;
+
+ u32 max_cid_space;
/* per connection parameters */
int num_iscsi_tasks;
diff --git a/drivers/net/cnic_if.h b/drivers/net/cnic_if.h
index 0c55177db04..344c842d55a 100644
--- a/drivers/net/cnic_if.h
+++ b/drivers/net/cnic_if.h
@@ -12,8 +12,8 @@
#ifndef CNIC_IF_H
#define CNIC_IF_H
-#define CNIC_MODULE_VERSION "2.1.2"
-#define CNIC_MODULE_RELDATE "May 26, 2010"
+#define CNIC_MODULE_VERSION "2.1.3"
+#define CNIC_MODULE_RELDATE "June 24, 2010"
#define CNIC_ULP_RDMA 0
#define CNIC_ULP_ISCSI 1
diff --git a/drivers/net/cpmac.c b/drivers/net/cpmac.c
index 23786ee34be..e1f6156b371 100644
--- a/drivers/net/cpmac.c
+++ b/drivers/net/cpmac.c
@@ -846,11 +846,8 @@ static int cpmac_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
return -EINVAL;
if (!priv->phy)
return -EINVAL;
- if ((cmd == SIOCGMIIPHY) || (cmd == SIOCGMIIREG) ||
- (cmd == SIOCSMIIREG))
- return phy_mii_ioctl(priv->phy, if_mii(ifr), cmd);
- return -EOPNOTSUPP;
+ return phy_mii_ioctl(priv->phy, ifr, cmd);
}
static int cpmac_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
@@ -964,7 +961,7 @@ static int cpmac_open(struct net_device *dev)
struct sk_buff *skb;
mem = platform_get_resource_byname(priv->pdev, IORESOURCE_MEM, "regs");
- if (!request_mem_region(mem->start, mem->end - mem->start, dev->name)) {
+ if (!request_mem_region(mem->start, resource_size(mem), dev->name)) {
if (netif_msg_drv(priv))
printk(KERN_ERR "%s: failed to request registers\n",
dev->name);
@@ -972,7 +969,7 @@ static int cpmac_open(struct net_device *dev)
goto fail_reserve;
}
- priv->regs = ioremap(mem->start, mem->end - mem->start);
+ priv->regs = ioremap(mem->start, resource_size(mem));
if (!priv->regs) {
if (netif_msg_drv(priv))
printk(KERN_ERR "%s: failed to remap registers\n",
@@ -1049,7 +1046,7 @@ fail_alloc:
iounmap(priv->regs);
fail_remap:
- release_mem_region(mem->start, mem->end - mem->start);
+ release_mem_region(mem->start, resource_size(mem));
fail_reserve:
return res;
@@ -1077,7 +1074,7 @@ static int cpmac_stop(struct net_device *dev)
free_irq(dev->irq, dev);
iounmap(priv->regs);
mem = platform_get_resource_byname(priv->pdev, IORESOURCE_MEM, "regs");
- release_mem_region(mem->start, mem->end - mem->start);
+ release_mem_region(mem->start, resource_size(mem));
priv->rx_head = &priv->desc_ring[CPMAC_QUEUES];
for (i = 0; i < priv->ring_size; i++) {
if (priv->rx_head[i].skb) {
diff --git a/drivers/net/cris/eth_v10.c b/drivers/net/cris/eth_v10.c
index 7e00027b9f8..81475cc80e1 100644
--- a/drivers/net/cris/eth_v10.c
+++ b/drivers/net/cris/eth_v10.c
@@ -1702,11 +1702,7 @@ e100_set_network_leds(int active)
if (!current_speed) {
/* Make LED red, link is down */
-#if defined(CONFIG_ETRAX_NETWORK_RED_ON_NO_CONNECTION)
- CRIS_LED_NETWORK_SET(CRIS_LED_RED);
-#else
CRIS_LED_NETWORK_SET(CRIS_LED_OFF);
-#endif
} else if (light_leds) {
if (current_speed == 10) {
CRIS_LED_NETWORK_SET(CRIS_LED_ORANGE);
diff --git a/drivers/net/cs89x0.c b/drivers/net/cs89x0.c
index 2ccb9f12805..d325e01a53e 100644
--- a/drivers/net/cs89x0.c
+++ b/drivers/net/cs89x0.c
@@ -170,22 +170,12 @@ static char version[] __initdata =
/* The cs8900 has 4 IRQ pins, software selectable. cs8900_irq_map maps
them to system IRQ numbers. This mapping is card specific and is set to
the configuration of the Cirrus Eval board for this chip. */
-#if defined(CONFIG_SH_HICOSH4)
-static unsigned int netcard_portlist[] __used __initdata =
- { 0x0300, 0};
-static unsigned int cs8900_irq_map[] = {1,0,0,0};
-#elif defined(CONFIG_MACH_IXDP2351)
+#if defined(CONFIG_MACH_IXDP2351)
static unsigned int netcard_portlist[] __used __initdata = {IXDP2351_VIRT_CS8900_BASE, 0};
static unsigned int cs8900_irq_map[] = {IRQ_IXDP2351_CS8900, 0, 0, 0};
#elif defined(CONFIG_ARCH_IXDP2X01)
static unsigned int netcard_portlist[] __used __initdata = {IXDP2X01_CS8900_VIRT_BASE, 0};
static unsigned int cs8900_irq_map[] = {IRQ_IXDP2X01_CS8900, 0, 0, 0};
-#elif defined(CONFIG_ARCH_PNX010X)
-#include <mach/gpio.h>
-#define CIRRUS_DEFAULT_BASE IO_ADDRESS(EXT_STATIC2_s0_BASE + 0x200000) /* = Physical address 0x48200000 */
-#define CIRRUS_DEFAULT_IRQ VH_INTC_INT_NUM_CASCADED_INTERRUPT_1 /* Event inputs bank 1 - ID 35/bit 3 */
-static unsigned int netcard_portlist[] __used __initdata = {CIRRUS_DEFAULT_BASE, 0};
-static unsigned int cs8900_irq_map[] = {CIRRUS_DEFAULT_IRQ, 0, 0, 0};
#elif defined(CONFIG_MACH_MX31ADS)
#include <mach/board-mx31ads.h>
static unsigned int netcard_portlist[] __used __initdata = {
@@ -218,7 +208,6 @@ static unsigned int net_debug = DEBUGGING;
/* Information that need to be kept for each board. */
struct net_local {
- struct net_device_stats stats;
int chip_type; /* one of: CS8900, CS8920, CS8920M */
char chip_revision; /* revision letter of the chip ('A'...) */
int send_cmd; /* the proper send command: TX_NOW, TX_AFTER_381, or TX_AFTER_ALL */
@@ -257,7 +246,7 @@ static void reset_chip(struct net_device *dev);
static int get_eeprom_data(struct net_device *dev, int off, int len, int *buffer);
static int get_eeprom_cksum(int off, int len, int *buffer);
static int set_mac_address(struct net_device *dev, void *addr);
-static void count_rx_errors(int status, struct net_local *lp);
+static void count_rx_errors(int status, struct net_device *dev);
#ifdef CONFIG_NET_POLL_CONTROLLER
static void net_poll_controller(struct net_device *dev);
#endif
@@ -372,18 +361,6 @@ writeword(unsigned long base_addr, int portno, u16 value)
{
__raw_writel(value, base_addr + (portno << 1));
}
-#elif defined(CONFIG_ARCH_PNX010X)
-static u16
-readword(unsigned long base_addr, int portno)
-{
- return inw(base_addr + (portno << 1));
-}
-
-static void
-writeword(unsigned long base_addr, int portno, u16 value)
-{
- outw(value, base_addr + (portno << 1));
-}
#else
static u16
readword(unsigned long base_addr, int portno)
@@ -546,30 +523,6 @@ cs89x0_probe1(struct net_device *dev, int ioaddr, int modular)
#endif
}
-#ifdef CONFIG_ARCH_PNX010X
- initialize_ebi();
-
- /* Map GPIO registers for the pins connected to the CS8900a. */
- if (map_cirrus_gpio() < 0)
- return -ENODEV;
-
- reset_cirrus();
-
- /* Map event-router registers. */
- if (map_event_router() < 0)
- return -ENODEV;
-
- enable_cirrus_irq();
-
- unmap_cirrus_gpio();
- unmap_event_router();
-
- dev->base_addr = ioaddr;
-
- for (i = 0 ; i < 3 ; i++)
- readreg(dev, 0);
-#endif
-
/* Grab the region so we can find another board if autoIRQ fails. */
/* WTF is going on here? */
if (!request_region(ioaddr & ~3, NETCARD_IO_EXTENT, DRV_NAME)) {
@@ -579,12 +532,6 @@ cs89x0_probe1(struct net_device *dev, int ioaddr, int modular)
goto out1;
}
-#ifdef CONFIG_SH_HICOSH4
- /* truly reset the chip */
- writeword(ioaddr, ADD_PORT, 0x0114);
- writeword(ioaddr, DATA_PORT, 0x0040);
-#endif
-
/* if they give us an odd I/O address, then do ONE write to
the address port, to get it back to address zero, where we
expect to find the EISA signature word. An IO with a base of 0x3
@@ -650,37 +597,6 @@ cs89x0_probe1(struct net_device *dev, int ioaddr, int modular)
the driver will always do *something* instead of complain that
adapter_cnf is 0. */
-#ifdef CONFIG_SH_HICOSH4
- if (1) {
- /* For the HiCO.SH4 board, things are different: we don't
- have EEPROM, but there is some data in flash, so we go
- get it there directly (MAC). */
- __u16 *confd;
- short cnt;
- if (((* (volatile __u32 *) 0xa0013ff0) & 0x00ffffff)
- == 0x006c3000) {
- confd = (__u16*) 0xa0013fc0;
- } else {
- confd = (__u16*) 0xa001ffc0;
- }
- cnt = (*confd++ & 0x00ff) >> 1;
- while (--cnt > 0) {
- __u16 j = *confd++;
-
- switch (j & 0x0fff) {
- case PP_IA:
- for (i = 0; i < ETH_ALEN/2; i++) {
- dev->dev_addr[i*2] = confd[i] & 0xFF;
- dev->dev_addr[i*2+1] = confd[i] >> 8;
- }
- break;
- }
- j = (j >> 12) + 1;
- confd += j;
- cnt -= j;
- }
- } else
-#endif
if ((readreg(dev, PP_SelfST) & (EEPROM_OK | EEPROM_PRESENT)) ==
(EEPROM_OK|EEPROM_PRESENT)) {
@@ -735,11 +651,7 @@ cs89x0_probe1(struct net_device *dev, int ioaddr, int modular)
printk("\n");
/* First check to see if an EEPROM is attached. */
-#ifdef CONFIG_SH_HICOSH4 /* no EEPROM on HiCO, don't hazzle with it here */
- if (1) {
- printk(KERN_NOTICE "cs89x0: No EEPROM on HiCO.SH4\n");
- } else
-#endif
+
if ((readreg(dev, PP_SelfST) & EEPROM_PRESENT) == 0)
printk(KERN_WARNING "cs89x0: No EEPROM, relying on command line....\n");
else if (get_eeprom_data(dev, START_EEPROM_DATA,CHKSUM_LEN,eeprom_buff) < 0) {
@@ -983,7 +895,7 @@ dma_rx(struct net_device *dev)
dev->name, (unsigned long)bp, status, length);
}
if ((status & RX_OK) == 0) {
- count_rx_errors(status, lp);
+ count_rx_errors(status, dev);
goto skip_this_frame;
}
@@ -992,7 +904,7 @@ dma_rx(struct net_device *dev)
if (skb == NULL) {
if (net_debug) /* I don't think we want to do this to a stressed system */
printk("%s: Memory squeeze, dropping packet.\n", dev->name);
- lp->stats.rx_dropped++;
+ dev->stats.rx_dropped++;
/* AKPM: advance bp to the next frame */
skip_this_frame:
@@ -1022,8 +934,8 @@ skip_this_frame:
}
skb->protocol=eth_type_trans(skb,dev);
netif_rx(skb);
- lp->stats.rx_packets++;
- lp->stats.rx_bytes += length;
+ dev->stats.rx_packets++;
+ dev->stats.rx_bytes += length;
}
#endif /* ALLOW_DMA */
@@ -1276,7 +1188,6 @@ net_open(struct net_device *dev)
int i;
int ret;
-#if !defined(CONFIG_SH_HICOSH4) && !defined(CONFIG_ARCH_PNX010X) /* uses irq#1, so this won't work */
if (dev->irq < 2) {
/* Allow interrupts to be generated by the chip */
/* Cirrus' release had this: */
@@ -1305,7 +1216,6 @@ net_open(struct net_device *dev)
}
}
else
-#endif
{
#ifndef CONFIG_CS89x0_NONISA_IRQ
if (((1 << dev->irq) & lp->irq_map) == 0) {
@@ -1391,9 +1301,6 @@ net_open(struct net_device *dev)
case A_CNF_MEDIA_10B_2: result = lp->adapter_cnf & A_CNF_10B_2; break;
default: result = lp->adapter_cnf & (A_CNF_10B_T | A_CNF_AUI | A_CNF_10B_2);
}
-#ifdef CONFIG_ARCH_PNX010X
- result = A_CNF_10B_T;
-#endif
if (!result) {
printk(KERN_ERR "%s: EEPROM is configured for unavailable media\n", dev->name);
release_dma:
@@ -1552,7 +1459,7 @@ static netdev_tx_t net_send_packet(struct sk_buff *skb,struct net_device *dev)
/* Write the contents of the packet */
writewords(dev->base_addr, TX_FRAME_PORT,skb->data,(skb->len+1) >>1);
spin_unlock_irqrestore(&lp->lock, flags);
- lp->stats.tx_bytes += skb->len;
+ dev->stats.tx_bytes += skb->len;
dev_kfree_skb (skb);
/*
@@ -1598,18 +1505,23 @@ static irqreturn_t net_interrupt(int irq, void *dev_id)
net_rx(dev);
break;
case ISQ_TRANSMITTER_EVENT:
- lp->stats.tx_packets++;
+ dev->stats.tx_packets++;
netif_wake_queue(dev); /* Inform upper layers. */
if ((status & ( TX_OK |
TX_LOST_CRS |
TX_SQE_ERROR |
TX_LATE_COL |
TX_16_COL)) != TX_OK) {
- if ((status & TX_OK) == 0) lp->stats.tx_errors++;
- if (status & TX_LOST_CRS) lp->stats.tx_carrier_errors++;
- if (status & TX_SQE_ERROR) lp->stats.tx_heartbeat_errors++;
- if (status & TX_LATE_COL) lp->stats.tx_window_errors++;
- if (status & TX_16_COL) lp->stats.tx_aborted_errors++;
+ if ((status & TX_OK) == 0)
+ dev->stats.tx_errors++;
+ if (status & TX_LOST_CRS)
+ dev->stats.tx_carrier_errors++;
+ if (status & TX_SQE_ERROR)
+ dev->stats.tx_heartbeat_errors++;
+ if (status & TX_LATE_COL)
+ dev->stats.tx_window_errors++;
+ if (status & TX_16_COL)
+ dev->stats.tx_aborted_errors++;
}
break;
case ISQ_BUFFER_EVENT:
@@ -1651,10 +1563,10 @@ static irqreturn_t net_interrupt(int irq, void *dev_id)
#endif
break;
case ISQ_RX_MISS_EVENT:
- lp->stats.rx_missed_errors += (status >>6);
+ dev->stats.rx_missed_errors += (status >> 6);
break;
case ISQ_TX_COL_EVENT:
- lp->stats.collisions += (status >>6);
+ dev->stats.collisions += (status >> 6);
break;
}
}
@@ -1662,22 +1574,24 @@ static irqreturn_t net_interrupt(int irq, void *dev_id)
}
static void
-count_rx_errors(int status, struct net_local *lp)
+count_rx_errors(int status, struct net_device *dev)
{
- lp->stats.rx_errors++;
- if (status & RX_RUNT) lp->stats.rx_length_errors++;
- if (status & RX_EXTRA_DATA) lp->stats.rx_length_errors++;
- if (status & RX_CRC_ERROR) if (!(status & (RX_EXTRA_DATA|RX_RUNT)))
+ dev->stats.rx_errors++;
+ if (status & RX_RUNT)
+ dev->stats.rx_length_errors++;
+ if (status & RX_EXTRA_DATA)
+ dev->stats.rx_length_errors++;
+ if ((status & RX_CRC_ERROR) && !(status & (RX_EXTRA_DATA|RX_RUNT)))
/* per str 172 */
- lp->stats.rx_crc_errors++;
- if (status & RX_DRIBBLE) lp->stats.rx_frame_errors++;
+ dev->stats.rx_crc_errors++;
+ if (status & RX_DRIBBLE)
+ dev->stats.rx_frame_errors++;
}
/* We have a good packet(s), get it/them out of the buffers. */
static void
net_rx(struct net_device *dev)
{
- struct net_local *lp = netdev_priv(dev);
struct sk_buff *skb;
int status, length;
@@ -1686,7 +1600,7 @@ net_rx(struct net_device *dev)
length = readword(ioaddr, RX_FRAME_PORT);
if ((status & RX_OK) == 0) {
- count_rx_errors(status, lp);
+ count_rx_errors(status, dev);
return;
}
@@ -1696,7 +1610,7 @@ net_rx(struct net_device *dev)
#if 0 /* Again, this seems a cruel thing to do */
printk(KERN_WARNING "%s: Memory squeeze, dropping packet.\n", dev->name);
#endif
- lp->stats.rx_dropped++;
+ dev->stats.rx_dropped++;
return;
}
skb_reserve(skb, 2); /* longword align L3 header */
@@ -1713,8 +1627,8 @@ net_rx(struct net_device *dev)
skb->protocol=eth_type_trans(skb,dev);
netif_rx(skb);
- lp->stats.rx_packets++;
- lp->stats.rx_bytes += length;
+ dev->stats.rx_packets++;
+ dev->stats.rx_bytes += length;
}
#if ALLOW_DMA
@@ -1765,11 +1679,11 @@ net_get_stats(struct net_device *dev)
spin_lock_irqsave(&lp->lock, flags);
/* Update the statistics from the device registers. */
- lp->stats.rx_missed_errors += (readreg(dev, PP_RxMiss) >> 6);
- lp->stats.collisions += (readreg(dev, PP_TxCol) >> 6);
+ dev->stats.rx_missed_errors += (readreg(dev, PP_RxMiss) >> 6);
+ dev->stats.collisions += (readreg(dev, PP_TxCol) >> 6);
spin_unlock_irqrestore(&lp->lock, flags);
- return &lp->stats;
+ return &dev->stats;
}
static void set_multicast_list(struct net_device *dev)
diff --git a/drivers/net/cs89x0.h b/drivers/net/cs89x0.h
index 204ed37fa9d..91423b70bb4 100644
--- a/drivers/net/cs89x0.h
+++ b/drivers/net/cs89x0.h
@@ -437,11 +437,7 @@
#define IRQ_MAP_EEPROM_DATA 0x0046 /* Offset into eeprom for the IRQ map */
#define IRQ_MAP_LEN 0x0004 /* No of bytes to read for the IRQ map */
#define PNP_IRQ_FRMT 0x0022 /* PNP small item IRQ format */
-#ifdef CONFIG_SH_HICOSH4
-#define CS8900_IRQ_MAP 0x0002 /* HiCO-SH4 board has its IRQ on #1 */
-#else
#define CS8900_IRQ_MAP 0x1c20 /* This IRQ map is fixed */
-#endif
#define CS8920_NO_INTS 0x0F /* Max CS8920 interrupt select # */
diff --git a/drivers/net/cxgb3/cxgb3_main.c b/drivers/net/cxgb3/cxgb3_main.c
index e3f1b856649..066fd5b09fd 100644
--- a/drivers/net/cxgb3/cxgb3_main.c
+++ b/drivers/net/cxgb3/cxgb3_main.c
@@ -2311,15 +2311,9 @@ static int cxgb_extension_ioctl(struct net_device *dev, void __user *useraddr)
if (copy_from_user(&t, useraddr, sizeof(t)))
return -EFAULT;
/* Check t.len sanity ? */
- fw_data = kmalloc(t.len, GFP_KERNEL);
- if (!fw_data)
- return -ENOMEM;
-
- if (copy_from_user
- (fw_data, useraddr + sizeof(t), t.len)) {
- kfree(fw_data);
- return -EFAULT;
- }
+ fw_data = memdup_user(useraddr + sizeof(t), t.len);
+ if (IS_ERR(fw_data))
+ return PTR_ERR(fw_data);
ret = t3_load_fw(adapter, fw_data, t.len);
kfree(fw_data);
diff --git a/drivers/net/cxgb3/sge.c b/drivers/net/cxgb3/sge.c
index 5962b911b5b..8ff96c6f6de 100644
--- a/drivers/net/cxgb3/sge.c
+++ b/drivers/net/cxgb3/sge.c
@@ -203,15 +203,11 @@ static inline void refill_rspq(struct adapter *adapter,
*/
static inline int need_skb_unmap(void)
{
- /*
- * This structure is used to tell if the platform needs buffer
- * unmapping by checking if DECLARE_PCI_UNMAP_ADDR defines anything.
- */
- struct dummy {
- DEFINE_DMA_UNMAP_ADDR(addr);
- };
-
- return sizeof(struct dummy) != 0;
+#ifdef CONFIG_NEED_DMA_MAP_STATE
+ return 1;
+#else
+ return 0;
+#endif
}
/**
diff --git a/drivers/net/cxgb3/t3_hw.c b/drivers/net/cxgb3/t3_hw.c
index 95a8ba0759f..427c451be1a 100644
--- a/drivers/net/cxgb3/t3_hw.c
+++ b/drivers/net/cxgb3/t3_hw.c
@@ -679,14 +679,6 @@ int t3_seeprom_wp(struct adapter *adapter, int enable)
return t3_seeprom_write(adapter, EEPROM_STAT_ADDR, enable ? 0xc : 0);
}
-/*
- * Convert a character holding a hex digit to a number.
- */
-static unsigned int hex2int(unsigned char c)
-{
- return isdigit(c) ? c - '0' : toupper(c) - 'A' + 10;
-}
-
/**
* get_vpd_params - read VPD parameters from VPD EEPROM
* @adapter: adapter to read
@@ -727,15 +719,15 @@ static int get_vpd_params(struct adapter *adapter, struct vpd_params *p)
p->port_type[0] = uses_xaui(adapter) ? 1 : 2;
p->port_type[1] = uses_xaui(adapter) ? 6 : 2;
} else {
- p->port_type[0] = hex2int(vpd.port0_data[0]);
- p->port_type[1] = hex2int(vpd.port1_data[0]);
+ p->port_type[0] = hex_to_bin(vpd.port0_data[0]);
+ p->port_type[1] = hex_to_bin(vpd.port1_data[0]);
p->xauicfg[0] = simple_strtoul(vpd.xaui0cfg_data, NULL, 16);
p->xauicfg[1] = simple_strtoul(vpd.xaui1cfg_data, NULL, 16);
}
for (i = 0; i < 6; i++)
- p->eth_base[i] = hex2int(vpd.na_data[2 * i]) * 16 +
- hex2int(vpd.na_data[2 * i + 1]);
+ p->eth_base[i] = hex_to_bin(vpd.na_data[2 * i]) * 16 +
+ hex_to_bin(vpd.na_data[2 * i + 1]);
return 0;
}
diff --git a/drivers/net/cxgb3/version.h b/drivers/net/cxgb3/version.h
index 9d0bd9dd9ab..8bda06e366c 100644
--- a/drivers/net/cxgb3/version.h
+++ b/drivers/net/cxgb3/version.h
@@ -35,10 +35,10 @@
#define DRV_DESC "Chelsio T3 Network Driver"
#define DRV_NAME "cxgb3"
/* Driver version */
-#define DRV_VERSION "1.1.3-ko"
+#define DRV_VERSION "1.1.4-ko"
/* Firmware version */
#define FW_VERSION_MAJOR 7
-#define FW_VERSION_MINOR 4
+#define FW_VERSION_MINOR 10
#define FW_VERSION_MICRO 0
#endif /* __CHELSIO_VERSION_H */
diff --git a/drivers/net/cxgb4/cxgb4.h b/drivers/net/cxgb4/cxgb4.h
index dd1770e075e..6e562c0dad7 100644
--- a/drivers/net/cxgb4/cxgb4.h
+++ b/drivers/net/cxgb4/cxgb4.h
@@ -219,6 +219,10 @@ struct adapter_params {
struct vpd_params vpd;
struct pci_params pci;
+ unsigned int sf_size; /* serial flash size in bytes */
+ unsigned int sf_nsec; /* # of flash sectors */
+ unsigned int sf_fw_start; /* start of FW image in flash */
+
unsigned int fw_vers;
unsigned int tp_vers;
u8 api_vers[7];
@@ -290,7 +294,9 @@ struct port_info {
u8 rx_offload; /* CSO, etc */
u8 nqsets; /* # of qsets */
u8 first_qset; /* index of first qset */
+ u8 rss_mode;
struct link_config link_cfg;
+ u16 *rss;
};
/* port_info.rx_offload flags */
@@ -305,7 +311,6 @@ enum { /* adapter flags */
FULL_INIT_DONE = (1 << 0),
USING_MSI = (1 << 1),
USING_MSIX = (1 << 2),
- QUEUES_BOUND = (1 << 3),
FW_OK = (1 << 4),
};
@@ -477,7 +482,8 @@ struct adapter {
struct pci_dev *pdev;
struct device *pdev_dev;
unsigned long registered_device_map;
- unsigned long flags;
+ unsigned int fn;
+ unsigned int flags;
const char *name;
int msg_enable;
@@ -646,6 +652,7 @@ void t4_intr_disable(struct adapter *adapter);
void t4_intr_clear(struct adapter *adapter);
int t4_slow_intr_handler(struct adapter *adapter);
+int t4_wait_dev_ready(struct adapter *adap);
int t4_link_start(struct adapter *adap, unsigned int mbox, unsigned int port,
struct link_config *lc);
int t4_restart_aneg(struct adapter *adap, unsigned int mbox, unsigned int port);
diff --git a/drivers/net/cxgb4/cxgb4_main.c b/drivers/net/cxgb4/cxgb4_main.c
index 58045b00cf4..c327527fbbc 100644
--- a/drivers/net/cxgb4/cxgb4_main.c
+++ b/drivers/net/cxgb4/cxgb4_main.c
@@ -67,7 +67,7 @@
#include "t4fw_api.h"
#include "l2t.h"
-#define DRV_VERSION "1.0.0-ko"
+#define DRV_VERSION "1.3.0-ko"
#define DRV_DESC "Chelsio T4 Network Driver"
/*
@@ -77,6 +77,76 @@
*/
#define MAX_SGE_TIMERVAL 200U
+#ifdef CONFIG_PCI_IOV
+/*
+ * Virtual Function provisioning constants. We need two extra Ingress Queues
+ * with Interrupt capability to serve as the VF's Firmware Event Queue and
+ * Forwarded Interrupt Queue (when using MSI mode) -- neither will have Free
+ * Lists associated with them). For each Ethernet/Control Egress Queue and
+ * for each Free List, we need an Egress Context.
+ */
+enum {
+ VFRES_NPORTS = 1, /* # of "ports" per VF */
+ VFRES_NQSETS = 2, /* # of "Queue Sets" per VF */
+
+ VFRES_NVI = VFRES_NPORTS, /* # of Virtual Interfaces */
+ VFRES_NETHCTRL = VFRES_NQSETS, /* # of EQs used for ETH or CTRL Qs */
+ VFRES_NIQFLINT = VFRES_NQSETS+2,/* # of ingress Qs/w Free List(s)/intr */
+ VFRES_NIQ = 0, /* # of non-fl/int ingress queues */
+ VFRES_NEQ = VFRES_NQSETS*2, /* # of egress queues */
+ VFRES_TC = 0, /* PCI-E traffic class */
+ VFRES_NEXACTF = 16, /* # of exact MPS filters */
+
+ VFRES_R_CAPS = FW_CMD_CAP_DMAQ|FW_CMD_CAP_VF|FW_CMD_CAP_PORT,
+ VFRES_WX_CAPS = FW_CMD_CAP_DMAQ|FW_CMD_CAP_VF,
+};
+
+/*
+ * Provide a Port Access Rights Mask for the specified PF/VF. This is very
+ * static and likely not to be useful in the long run. We really need to
+ * implement some form of persistent configuration which the firmware
+ * controls.
+ */
+static unsigned int pfvfres_pmask(struct adapter *adapter,
+ unsigned int pf, unsigned int vf)
+{
+ unsigned int portn, portvec;
+
+ /*
+ * Give PF's access to all of the ports.
+ */
+ if (vf == 0)
+ return FW_PFVF_CMD_PMASK_MASK;
+
+ /*
+ * For VFs, we'll assign them access to the ports based purely on the
+ * PF. We assign active ports in order, wrapping around if there are
+ * fewer active ports than PFs: e.g. active port[pf % nports].
+ * Unfortunately the adapter's port_info structs haven't been
+ * initialized yet so we have to compute this.
+ */
+ if (adapter->params.nports == 0)
+ return 0;
+
+ portn = pf % adapter->params.nports;
+ portvec = adapter->params.portvec;
+ for (;;) {
+ /*
+ * Isolate the lowest set bit in the port vector. If we're at
+ * the port number that we want, return that as the pmask.
+ * otherwise mask that bit out of the port vector and
+ * decrement our port number ...
+ */
+ unsigned int pmask = portvec ^ (portvec & (portvec-1));
+ if (portn == 0)
+ return pmask;
+ portn--;
+ portvec &= ~pmask;
+ }
+ /*NOTREACHED*/
+}
+#endif
+
enum {
MEMWIN0_APERTURE = 65536,
MEMWIN0_BASE = 0x30000,
@@ -101,10 +171,20 @@ enum {
NETIF_MSG_TIMER | NETIF_MSG_IFDOWN | NETIF_MSG_IFUP |\
NETIF_MSG_RX_ERR | NETIF_MSG_TX_ERR)
-#define CH_DEVICE(devid) { PCI_VDEVICE(CHELSIO, devid), 0 }
+#define CH_DEVICE(devid, data) { PCI_VDEVICE(CHELSIO, devid), (data) }
static DEFINE_PCI_DEVICE_TABLE(cxgb4_pci_tbl) = {
- CH_DEVICE(0xa000), /* PE10K */
+ CH_DEVICE(0xa000, 0), /* PE10K */
+ CH_DEVICE(0x4001, 0),
+ CH_DEVICE(0x4002, 0),
+ CH_DEVICE(0x4003, 0),
+ CH_DEVICE(0x4004, 0),
+ CH_DEVICE(0x4005, 0),
+ CH_DEVICE(0x4006, 0),
+ CH_DEVICE(0x4007, 0),
+ CH_DEVICE(0x4008, 0),
+ CH_DEVICE(0x4009, 0),
+ CH_DEVICE(0x400a, 0),
{ 0, }
};
@@ -216,7 +296,7 @@ void t4_os_link_changed(struct adapter *adapter, int port_id, int link_stat)
void t4_os_portmod_changed(const struct adapter *adap, int port_id)
{
static const char *mod_str[] = {
- NULL, "LR", "SR", "ER", "passive DA", "active DA"
+ NULL, "LR", "SR", "ER", "passive DA", "active DA", "LRM"
};
const struct net_device *dev = adap->port[port_id];
@@ -224,7 +304,7 @@ void t4_os_portmod_changed(const struct adapter *adap, int port_id)
if (pi->mod_type == FW_PORT_MOD_TYPE_NONE)
netdev_info(dev, "port module unplugged\n");
- else
+ else if (pi->mod_type < ARRAY_SIZE(mod_str))
netdev_info(dev, "%s module inserted\n", mod_str[pi->mod_type]);
}
@@ -244,12 +324,13 @@ static int set_addr_filters(const struct net_device *dev, bool sleep)
int uc_cnt = netdev_uc_count(dev);
int mc_cnt = netdev_mc_count(dev);
const struct port_info *pi = netdev_priv(dev);
+ unsigned int mb = pi->adapter->fn;
/* first do the secondary unicast addresses */
netdev_for_each_uc_addr(ha, dev) {
addr[naddr++] = ha->addr;
if (--uc_cnt == 0 || naddr >= ARRAY_SIZE(addr)) {
- ret = t4_alloc_mac_filt(pi->adapter, 0, pi->viid, free,
+ ret = t4_alloc_mac_filt(pi->adapter, mb, pi->viid, free,
naddr, addr, filt_idx, &uhash, sleep);
if (ret < 0)
return ret;
@@ -263,7 +344,7 @@ static int set_addr_filters(const struct net_device *dev, bool sleep)
netdev_for_each_mc_addr(ha, dev) {
addr[naddr++] = ha->addr;
if (--mc_cnt == 0 || naddr >= ARRAY_SIZE(addr)) {
- ret = t4_alloc_mac_filt(pi->adapter, 0, pi->viid, free,
+ ret = t4_alloc_mac_filt(pi->adapter, mb, pi->viid, free,
naddr, addr, filt_idx, &mhash, sleep);
if (ret < 0)
return ret;
@@ -273,7 +354,7 @@ static int set_addr_filters(const struct net_device *dev, bool sleep)
}
}
- return t4_set_addr_hash(pi->adapter, 0, pi->viid, uhash != 0,
+ return t4_set_addr_hash(pi->adapter, mb, pi->viid, uhash != 0,
uhash | mhash, sleep);
}
@@ -288,7 +369,7 @@ static int set_rxmode(struct net_device *dev, int mtu, bool sleep_ok)
ret = set_addr_filters(dev, sleep_ok);
if (ret == 0)
- ret = t4_set_rxmode(pi->adapter, 0, pi->viid, mtu,
+ ret = t4_set_rxmode(pi->adapter, pi->adapter->fn, pi->viid, mtu,
(dev->flags & IFF_PROMISC) ? 1 : 0,
(dev->flags & IFF_ALLMULTI) ? 1 : 0, 1, -1,
sleep_ok);
@@ -305,15 +386,16 @@ static int link_start(struct net_device *dev)
{
int ret;
struct port_info *pi = netdev_priv(dev);
+ unsigned int mb = pi->adapter->fn;
/*
* We do not set address filters and promiscuity here, the stack does
* that step explicitly.
*/
- ret = t4_set_rxmode(pi->adapter, 0, pi->viid, dev->mtu, -1, -1, -1,
+ ret = t4_set_rxmode(pi->adapter, mb, pi->viid, dev->mtu, -1, -1, -1,
pi->vlan_grp != NULL, true);
if (ret == 0) {
- ret = t4_change_mac(pi->adapter, 0, pi->viid,
+ ret = t4_change_mac(pi->adapter, mb, pi->viid,
pi->xact_addr_filt, dev->dev_addr, true,
true);
if (ret >= 0) {
@@ -322,9 +404,10 @@ static int link_start(struct net_device *dev)
}
}
if (ret == 0)
- ret = t4_link_start(pi->adapter, 0, pi->tx_chan, &pi->link_cfg);
+ ret = t4_link_start(pi->adapter, mb, pi->tx_chan,
+ &pi->link_cfg);
if (ret == 0)
- ret = t4_enable_vi(pi->adapter, 0, pi->viid, true, true);
+ ret = t4_enable_vi(pi->adapter, mb, pi->viid, true, true);
return ret;
}
@@ -527,30 +610,47 @@ static void free_msix_queue_irqs(struct adapter *adap)
}
/**
+ * write_rss - write the RSS table for a given port
+ * @pi: the port
+ * @queues: array of queue indices for RSS
+ *
+ * Sets up the portion of the HW RSS table for the port's VI to distribute
+ * packets to the Rx queues in @queues.
+ */
+static int write_rss(const struct port_info *pi, const u16 *queues)
+{
+ u16 *rss;
+ int i, err;
+ const struct sge_eth_rxq *q = &pi->adapter->sge.ethrxq[pi->first_qset];
+
+ rss = kmalloc(pi->rss_size * sizeof(u16), GFP_KERNEL);
+ if (!rss)
+ return -ENOMEM;
+
+ /* map the queue indices to queue ids */
+ for (i = 0; i < pi->rss_size; i++, queues++)
+ rss[i] = q[*queues].rspq.abs_id;
+
+ err = t4_config_rss_range(pi->adapter, pi->adapter->fn, pi->viid, 0,
+ pi->rss_size, rss, pi->rss_size);
+ kfree(rss);
+ return err;
+}
+
+/**
* setup_rss - configure RSS
* @adap: the adapter
*
- * Sets up RSS to distribute packets to multiple receive queues. We
- * configure the RSS CPU lookup table to distribute to the number of HW
- * receive queues, and the response queue lookup table to narrow that
- * down to the response queues actually configured for each port.
- * We always configure the RSS mapping for all ports since the mapping
- * table has plenty of entries.
+ * Sets up RSS for each port.
*/
static int setup_rss(struct adapter *adap)
{
- int i, j, err;
- u16 rss[MAX_ETH_QSETS];
+ int i, err;
for_each_port(adap, i) {
const struct port_info *pi = adap2pinfo(adap, i);
- const struct sge_eth_rxq *q = &adap->sge.ethrxq[pi->first_qset];
-
- for (j = 0; j < pi->nqsets; j++)
- rss[j] = q[j].rspq.abs_id;
- err = t4_config_rss_range(adap, 0, pi->viid, 0, pi->rss_size,
- rss, pi->nqsets);
+ err = write_rss(pi, pi->rss);
if (err)
return err;
}
@@ -963,10 +1063,11 @@ static void get_stats(struct net_device *dev, struct ethtool_stats *stats,
* Return a version number to identify the type of adapter. The scheme is:
* - bits 0..9: chip version
* - bits 10..15: chip revision
+ * - bits 16..23: register dump version
*/
static inline unsigned int mk_adap_vers(const struct adapter *ap)
{
- return 4 | (ap->params.rev << 10);
+ return 4 | (ap->params.rev << 10) | (1 << 16);
}
static void reg_block_dump(struct adapter *ap, void *buf, unsigned int start,
@@ -1041,7 +1142,9 @@ static void get_regs(struct net_device *dev, struct ethtool_regs *regs,
0xdfc0, 0xdfe0,
0xe000, 0xea7c,
0xf000, 0x11190,
- 0x19040, 0x19124,
+ 0x19040, 0x1906c,
+ 0x19078, 0x19080,
+ 0x1908c, 0x19124,
0x19150, 0x191b0,
0x191d0, 0x191e8,
0x19238, 0x1924c,
@@ -1054,49 +1157,49 @@ static void get_regs(struct net_device *dev, struct ethtool_regs *regs,
0x1a190, 0x1a1c4,
0x1a1fc, 0x1a1fc,
0x1e040, 0x1e04c,
- 0x1e240, 0x1e28c,
+ 0x1e284, 0x1e28c,
0x1e2c0, 0x1e2c0,
0x1e2e0, 0x1e2e0,
0x1e300, 0x1e384,
0x1e3c0, 0x1e3c8,
0x1e440, 0x1e44c,
- 0x1e640, 0x1e68c,
+ 0x1e684, 0x1e68c,
0x1e6c0, 0x1e6c0,
0x1e6e0, 0x1e6e0,
0x1e700, 0x1e784,
0x1e7c0, 0x1e7c8,
0x1e840, 0x1e84c,
- 0x1ea40, 0x1ea8c,
+ 0x1ea84, 0x1ea8c,
0x1eac0, 0x1eac0,
0x1eae0, 0x1eae0,
0x1eb00, 0x1eb84,
0x1ebc0, 0x1ebc8,
0x1ec40, 0x1ec4c,
- 0x1ee40, 0x1ee8c,
+ 0x1ee84, 0x1ee8c,
0x1eec0, 0x1eec0,
0x1eee0, 0x1eee0,
0x1ef00, 0x1ef84,
0x1efc0, 0x1efc8,
0x1f040, 0x1f04c,
- 0x1f240, 0x1f28c,
+ 0x1f284, 0x1f28c,
0x1f2c0, 0x1f2c0,
0x1f2e0, 0x1f2e0,
0x1f300, 0x1f384,
0x1f3c0, 0x1f3c8,
0x1f440, 0x1f44c,
- 0x1f640, 0x1f68c,
+ 0x1f684, 0x1f68c,
0x1f6c0, 0x1f6c0,
0x1f6e0, 0x1f6e0,
0x1f700, 0x1f784,
0x1f7c0, 0x1f7c8,
0x1f840, 0x1f84c,
- 0x1fa40, 0x1fa8c,
+ 0x1fa84, 0x1fa8c,
0x1fac0, 0x1fac0,
0x1fae0, 0x1fae0,
0x1fb00, 0x1fb84,
0x1fbc0, 0x1fbc8,
0x1fc40, 0x1fc4c,
- 0x1fe40, 0x1fe8c,
+ 0x1fe84, 0x1fe8c,
0x1fec0, 0x1fec0,
0x1fee0, 0x1fee0,
0x1ff00, 0x1ff84,
@@ -1217,16 +1320,18 @@ static int restart_autoneg(struct net_device *dev)
return -EAGAIN;
if (p->link_cfg.autoneg != AUTONEG_ENABLE)
return -EINVAL;
- t4_restart_aneg(p->adapter, 0, p->tx_chan);
+ t4_restart_aneg(p->adapter, p->adapter->fn, p->tx_chan);
return 0;
}
static int identify_port(struct net_device *dev, u32 data)
{
+ struct adapter *adap = netdev2adap(dev);
+
if (data == 0)
data = 2; /* default to 2 seconds */
- return t4_identify_port(netdev2adap(dev), 0, netdev2pinfo(dev)->viid,
+ return t4_identify_port(adap, adap->fn, netdev2pinfo(dev)->viid,
data * 5);
}
@@ -1234,7 +1339,8 @@ static unsigned int from_fw_linkcaps(unsigned int type, unsigned int caps)
{
unsigned int v = 0;
- if (type == FW_PORT_TYPE_BT_SGMII || type == FW_PORT_TYPE_BT_XAUI) {
+ if (type == FW_PORT_TYPE_BT_SGMII || type == FW_PORT_TYPE_BT_XFI ||
+ type == FW_PORT_TYPE_BT_XAUI) {
v |= SUPPORTED_TP;
if (caps & FW_PORT_CAP_SPEED_100M)
v |= SUPPORTED_100baseT_Full;
@@ -1250,7 +1356,10 @@ static unsigned int from_fw_linkcaps(unsigned int type, unsigned int caps)
v |= SUPPORTED_10000baseKX4_Full;
} else if (type == FW_PORT_TYPE_KR)
v |= SUPPORTED_Backplane | SUPPORTED_10000baseKR_Full;
- else if (type == FW_PORT_TYPE_FIBER)
+ else if (type == FW_PORT_TYPE_BP_AP)
+ v |= SUPPORTED_Backplane | SUPPORTED_10000baseR_FEC;
+ else if (type == FW_PORT_TYPE_FIBER_XFI ||
+ type == FW_PORT_TYPE_FIBER_XAUI || type == FW_PORT_TYPE_SFP)
v |= SUPPORTED_FIBRE;
if (caps & FW_PORT_CAP_ANEG)
@@ -1276,13 +1385,19 @@ static int get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
const struct port_info *p = netdev_priv(dev);
if (p->port_type == FW_PORT_TYPE_BT_SGMII ||
+ p->port_type == FW_PORT_TYPE_BT_XFI ||
p->port_type == FW_PORT_TYPE_BT_XAUI)
cmd->port = PORT_TP;
- else if (p->port_type == FW_PORT_TYPE_FIBER)
+ else if (p->port_type == FW_PORT_TYPE_FIBER_XFI ||
+ p->port_type == FW_PORT_TYPE_FIBER_XAUI)
cmd->port = PORT_FIBRE;
- else if (p->port_type == FW_PORT_TYPE_TWINAX)
- cmd->port = PORT_DA;
- else
+ else if (p->port_type == FW_PORT_TYPE_SFP) {
+ if (p->mod_type == FW_PORT_MOD_TYPE_TWINAX_PASSIVE ||
+ p->mod_type == FW_PORT_MOD_TYPE_TWINAX_ACTIVE)
+ cmd->port = PORT_DA;
+ else
+ cmd->port = PORT_FIBRE;
+ } else
cmd->port = PORT_OTHER;
if (p->mdio_addr >= 0) {
@@ -1356,7 +1471,8 @@ static int set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
lc->autoneg = cmd->autoneg;
if (netif_running(dev))
- return t4_link_start(p->adapter, 0, p->tx_chan, lc);
+ return t4_link_start(p->adapter, p->adapter->fn, p->tx_chan,
+ lc);
return 0;
}
@@ -1388,7 +1504,8 @@ static int set_pauseparam(struct net_device *dev,
if (epause->tx_pause)
lc->requested_fc |= PAUSE_TX;
if (netif_running(dev))
- return t4_link_start(p->adapter, 0, p->tx_chan, lc);
+ return t4_link_start(p->adapter, p->adapter->fn, p->tx_chan,
+ lc);
return 0;
}
@@ -1520,7 +1637,8 @@ static int set_rxq_intr_params(struct adapter *adap, struct sge_rspq *q,
v = FW_PARAMS_MNEM(FW_PARAMS_MNEM_DMAQ) |
FW_PARAMS_PARAM_X(FW_PARAMS_PARAM_DMAQ_IQ_INTCNTTHRESH) |
FW_PARAMS_PARAM_YZ(q->cntxt_id);
- err = t4_set_params(adap, 0, 0, 0, 1, &v, &new_idx);
+ err = t4_set_params(adap, adap->fn, adap->fn, 0, 1, &v,
+ &new_idx);
if (err)
return err;
}
@@ -1708,27 +1826,114 @@ static int set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
return err;
}
+#define TSO_FLAGS (NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_TSO_ECN)
+
static int set_tso(struct net_device *dev, u32 value)
{
if (value)
- dev->features |= NETIF_F_TSO | NETIF_F_TSO6;
+ dev->features |= TSO_FLAGS;
else
- dev->features &= ~(NETIF_F_TSO | NETIF_F_TSO6);
+ dev->features &= ~TSO_FLAGS;
return 0;
}
static int set_flags(struct net_device *dev, u32 flags)
{
- if (flags & ~ETH_FLAG_RXHASH)
- return -EOPNOTSUPP;
+ return ethtool_op_set_flags(dev, flags, ETH_FLAG_RXHASH);
+}
- if (flags & ETH_FLAG_RXHASH)
- dev->features |= NETIF_F_RXHASH;
- else
- dev->features &= ~NETIF_F_RXHASH;
+static int get_rss_table(struct net_device *dev, struct ethtool_rxfh_indir *p)
+{
+ const struct port_info *pi = netdev_priv(dev);
+ unsigned int n = min_t(unsigned int, p->size, pi->rss_size);
+
+ p->size = pi->rss_size;
+ while (n--)
+ p->ring_index[n] = pi->rss[n];
return 0;
}
+static int set_rss_table(struct net_device *dev,
+ const struct ethtool_rxfh_indir *p)
+{
+ unsigned int i;
+ struct port_info *pi = netdev_priv(dev);
+
+ if (p->size != pi->rss_size)
+ return -EINVAL;
+ for (i = 0; i < p->size; i++)
+ if (p->ring_index[i] >= pi->nqsets)
+ return -EINVAL;
+ for (i = 0; i < p->size; i++)
+ pi->rss[i] = p->ring_index[i];
+ if (pi->adapter->flags & FULL_INIT_DONE)
+ return write_rss(pi, pi->rss);
+ return 0;
+}
+
+static int get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *info,
+ void *rules)
+{
+ const struct port_info *pi = netdev_priv(dev);
+
+ switch (info->cmd) {
+ case ETHTOOL_GRXFH: {
+ unsigned int v = pi->rss_mode;
+
+ info->data = 0;
+ switch (info->flow_type) {
+ case TCP_V4_FLOW:
+ if (v & FW_RSS_VI_CONFIG_CMD_IP4FOURTUPEN)
+ info->data = RXH_IP_SRC | RXH_IP_DST |
+ RXH_L4_B_0_1 | RXH_L4_B_2_3;
+ else if (v & FW_RSS_VI_CONFIG_CMD_IP4TWOTUPEN)
+ info->data = RXH_IP_SRC | RXH_IP_DST;
+ break;
+ case UDP_V4_FLOW:
+ if ((v & FW_RSS_VI_CONFIG_CMD_IP4FOURTUPEN) &&
+ (v & FW_RSS_VI_CONFIG_CMD_UDPEN))
+ info->data = RXH_IP_SRC | RXH_IP_DST |
+ RXH_L4_B_0_1 | RXH_L4_B_2_3;
+ else if (v & FW_RSS_VI_CONFIG_CMD_IP4TWOTUPEN)
+ info->data = RXH_IP_SRC | RXH_IP_DST;
+ break;
+ case SCTP_V4_FLOW:
+ case AH_ESP_V4_FLOW:
+ case IPV4_FLOW:
+ if (v & FW_RSS_VI_CONFIG_CMD_IP4TWOTUPEN)
+ info->data = RXH_IP_SRC | RXH_IP_DST;
+ break;
+ case TCP_V6_FLOW:
+ if (v & FW_RSS_VI_CONFIG_CMD_IP6FOURTUPEN)
+ info->data = RXH_IP_SRC | RXH_IP_DST |
+ RXH_L4_B_0_1 | RXH_L4_B_2_3;
+ else if (v & FW_RSS_VI_CONFIG_CMD_IP6TWOTUPEN)
+ info->data = RXH_IP_SRC | RXH_IP_DST;
+ break;
+ case UDP_V6_FLOW:
+ if ((v & FW_RSS_VI_CONFIG_CMD_IP6FOURTUPEN) &&
+ (v & FW_RSS_VI_CONFIG_CMD_UDPEN))
+ info->data = RXH_IP_SRC | RXH_IP_DST |
+ RXH_L4_B_0_1 | RXH_L4_B_2_3;
+ else if (v & FW_RSS_VI_CONFIG_CMD_IP6TWOTUPEN)
+ info->data = RXH_IP_SRC | RXH_IP_DST;
+ break;
+ case SCTP_V6_FLOW:
+ case AH_ESP_V6_FLOW:
+ case IPV6_FLOW:
+ if (v & FW_RSS_VI_CONFIG_CMD_IP6TWOTUPEN)
+ info->data = RXH_IP_SRC | RXH_IP_DST;
+ break;
+ }
+ return 0;
+ }
+ case ETHTOOL_GRXRINGS:
+ info->data = pi->nqsets;
+ return 0;
+ }
+ return -EOPNOTSUPP;
+}
+
static struct ethtool_ops cxgb_ethtool_ops = {
.get_settings = get_settings,
.set_settings = set_settings,
@@ -1760,6 +1965,9 @@ static struct ethtool_ops cxgb_ethtool_ops = {
.set_wol = set_wol,
.set_tso = set_tso,
.set_flags = set_flags,
+ .get_rxnfc = get_rxnfc,
+ .get_rxfh_indir = get_rss_table,
+ .set_rxfh_indir = set_rss_table,
.flash_device = set_flash,
};
@@ -2306,9 +2514,11 @@ static void uld_attach(struct adapter *adap, unsigned int uld)
lli.adapter_type = adap->params.rev;
lli.iscsi_iolen = MAXRXDATA_GET(t4_read_reg(adap, TP_PARA_REG2));
lli.udb_density = 1 << QUEUESPERPAGEPF0_GET(
- t4_read_reg(adap, SGE_EGRESS_QUEUES_PER_PAGE_PF));
+ t4_read_reg(adap, SGE_EGRESS_QUEUES_PER_PAGE_PF) >>
+ (adap->fn * 4));
lli.ucq_density = 1 << QUEUESPERPAGEPF0_GET(
- t4_read_reg(adap, SGE_INGRESS_QUEUES_PER_PAGE_PF));
+ t4_read_reg(adap, SGE_INGRESS_QUEUES_PER_PAGE_PF) >>
+ (adap->fn * 4));
lli.gts_reg = adap->regs + MYPF_REG(SGE_PF_GTS);
lli.db_reg = adap->regs + MYPF_REG(SGE_PF_KDOORBELL);
lli.fw_vers = adap->params.fw_vers;
@@ -2483,6 +2693,7 @@ static void cxgb_down(struct adapter *adapter)
t4_intr_disable(adapter);
cancel_work_sync(&adapter->tid_release_task);
adapter->tid_release_task_busy = false;
+ adapter->tid_release_head = NULL;
if (adapter->flags & USING_MSIX) {
free_msix_queue_irqs(adapter);
@@ -2511,9 +2722,10 @@ static int cxgb_open(struct net_device *dev)
}
dev->real_num_tx_queues = pi->nqsets;
- link_start(dev);
- netif_tx_start_all_queues(dev);
- return 0;
+ err = link_start(dev);
+ if (!err)
+ netif_tx_start_all_queues(dev);
+ return err;
}
static int cxgb_close(struct net_device *dev)
@@ -2523,15 +2735,15 @@ static int cxgb_close(struct net_device *dev)
netif_tx_stop_all_queues(dev);
netif_carrier_off(dev);
- return t4_enable_vi(adapter, 0, pi->viid, false, false);
+ return t4_enable_vi(adapter, adapter->fn, pi->viid, false, false);
}
-static struct net_device_stats *cxgb_get_stats(struct net_device *dev)
+static struct rtnl_link_stats64 *cxgb_get_stats(struct net_device *dev,
+ struct rtnl_link_stats64 *ns)
{
struct port_stats stats;
struct port_info *p = netdev_priv(dev);
struct adapter *adapter = p->adapter;
- struct net_device_stats *ns = &dev->stats;
spin_lock(&adapter->stats_lock);
t4_get_port_stats(adapter, p->tx_chan, &stats);
@@ -2570,6 +2782,7 @@ static struct net_device_stats *cxgb_get_stats(struct net_device *dev)
static int cxgb_ioctl(struct net_device *dev, struct ifreq *req, int cmd)
{
+ unsigned int mbox;
int ret = 0, prtad, devad;
struct port_info *pi = netdev_priv(dev);
struct mii_ioctl_data *data = (struct mii_ioctl_data *)&req->ifr_data;
@@ -2592,11 +2805,12 @@ static int cxgb_ioctl(struct net_device *dev, struct ifreq *req, int cmd)
} else
return -EINVAL;
+ mbox = pi->adapter->fn;
if (cmd == SIOCGMIIREG)
- ret = t4_mdio_rd(pi->adapter, 0, prtad, devad,
+ ret = t4_mdio_rd(pi->adapter, mbox, prtad, devad,
data->reg_num, &data->val_out);
else
- ret = t4_mdio_wr(pi->adapter, 0, prtad, devad,
+ ret = t4_mdio_wr(pi->adapter, mbox, prtad, devad,
data->reg_num, data->val_in);
break;
default:
@@ -2618,8 +2832,8 @@ static int cxgb_change_mtu(struct net_device *dev, int new_mtu)
if (new_mtu < 81 || new_mtu > MAX_MTU) /* accommodate SACK */
return -EINVAL;
- ret = t4_set_rxmode(pi->adapter, 0, pi->viid, new_mtu, -1, -1, -1, -1,
- true);
+ ret = t4_set_rxmode(pi->adapter, pi->adapter->fn, pi->viid, new_mtu, -1,
+ -1, -1, -1, true);
if (!ret)
dev->mtu = new_mtu;
return ret;
@@ -2634,8 +2848,8 @@ static int cxgb_set_mac_addr(struct net_device *dev, void *p)
if (!is_valid_ether_addr(addr->sa_data))
return -EINVAL;
- ret = t4_change_mac(pi->adapter, 0, pi->viid, pi->xact_addr_filt,
- addr->sa_data, true, true);
+ ret = t4_change_mac(pi->adapter, pi->adapter->fn, pi->viid,
+ pi->xact_addr_filt, addr->sa_data, true, true);
if (ret < 0)
return ret;
@@ -2649,8 +2863,8 @@ static void vlan_rx_register(struct net_device *dev, struct vlan_group *grp)
struct port_info *pi = netdev_priv(dev);
pi->vlan_grp = grp;
- t4_set_rxmode(pi->adapter, 0, pi->viid, -1, -1, -1, -1, grp != NULL,
- true);
+ t4_set_rxmode(pi->adapter, pi->adapter->fn, pi->viid, -1, -1, -1, -1,
+ grp != NULL, true);
}
#ifdef CONFIG_NET_POLL_CONTROLLER
@@ -2674,7 +2888,7 @@ static const struct net_device_ops cxgb4_netdev_ops = {
.ndo_open = cxgb_open,
.ndo_stop = cxgb_close,
.ndo_start_xmit = t4_eth_xmit,
- .ndo_get_stats = cxgb_get_stats,
+ .ndo_get_stats64 = cxgb_get_stats,
.ndo_set_rx_mode = cxgb_set_rxmode,
.ndo_set_mac_address = cxgb_set_mac_addr,
.ndo_validate_addr = eth_validate_addr,
@@ -2707,6 +2921,76 @@ static void setup_memwin(struct adapter *adap)
t4_write_reg(adap, PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_BASE_WIN, 2),
(bar0 + MEMWIN2_BASE) | BIR(0) |
WINDOW(ilog2(MEMWIN2_APERTURE) - 10));
+ if (adap->vres.ocq.size) {
+ unsigned int start, sz_kb;
+
+ start = pci_resource_start(adap->pdev, 2) +
+ OCQ_WIN_OFFSET(adap->pdev, &adap->vres);
+ sz_kb = roundup_pow_of_two(adap->vres.ocq.size) >> 10;
+ t4_write_reg(adap,
+ PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_BASE_WIN, 3),
+ start | BIR(1) | WINDOW(ilog2(sz_kb)));
+ t4_write_reg(adap,
+ PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_OFFSET, 3),
+ adap->vres.ocq.start);
+ t4_read_reg(adap,
+ PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_OFFSET, 3));
+ }
+}
+
+static int adap_init1(struct adapter *adap, struct fw_caps_config_cmd *c)
+{
+ u32 v;
+ int ret;
+
+ /* get device capabilities */
+ memset(c, 0, sizeof(*c));
+ c->op_to_write = htonl(FW_CMD_OP(FW_CAPS_CONFIG_CMD) |
+ FW_CMD_REQUEST | FW_CMD_READ);
+ c->retval_len16 = htonl(FW_LEN16(*c));
+ ret = t4_wr_mbox(adap, adap->fn, c, sizeof(*c), c);
+ if (ret < 0)
+ return ret;
+
+ /* select capabilities we'll be using */
+ if (c->niccaps & htons(FW_CAPS_CONFIG_NIC_VM)) {
+ if (!vf_acls)
+ c->niccaps ^= htons(FW_CAPS_CONFIG_NIC_VM);
+ else
+ c->niccaps = htons(FW_CAPS_CONFIG_NIC_VM);
+ } else if (vf_acls) {
+ dev_err(adap->pdev_dev, "virtualization ACLs not supported");
+ return ret;
+ }
+ c->op_to_write = htonl(FW_CMD_OP(FW_CAPS_CONFIG_CMD) |
+ FW_CMD_REQUEST | FW_CMD_WRITE);
+ ret = t4_wr_mbox(adap, adap->fn, c, sizeof(*c), NULL);
+ if (ret < 0)
+ return ret;
+
+ ret = t4_config_glbl_rss(adap, adap->fn,
+ FW_RSS_GLB_CONFIG_CMD_MODE_BASICVIRTUAL,
+ FW_RSS_GLB_CONFIG_CMD_TNLMAPEN |
+ FW_RSS_GLB_CONFIG_CMD_TNLALLLKP);
+ if (ret < 0)
+ return ret;
+
+ ret = t4_cfg_pfvf(adap, adap->fn, adap->fn, 0, MAX_EGRQ, 64, MAX_INGQ,
+ 0, 0, 4, 0xf, 0xf, 16, FW_CMD_CAP_PF, FW_CMD_CAP_PF);
+ if (ret < 0)
+ return ret;
+
+ t4_sge_init(adap);
+
+ /* tweak some settings */
+ t4_write_reg(adap, TP_SHIFT_CNT, 0x64f8849);
+ t4_write_reg(adap, ULP_RX_TDDP_PSZ, HPZ0(PAGE_SHIFT - 12));
+ t4_write_reg(adap, TP_PIO_ADDR, TP_INGRESS_CONFIG);
+ v = t4_read_reg(adap, TP_PIO_DATA);
+ t4_write_reg(adap, TP_PIO_DATA, v & ~CSUM_HAS_PSEUDO_HDR);
+
+ /* get basic stuff going */
+ return t4_early_init(adap, adap->fn);
}
/*
@@ -2734,7 +3018,7 @@ static int adap_init0(struct adapter *adap)
return ret;
/* contact FW, request master */
- ret = t4_fw_hello(adap, 0, 0, MASTER_MUST, &state);
+ ret = t4_fw_hello(adap, adap->fn, adap->fn, MASTER_MUST, &state);
if (ret < 0) {
dev_err(adap->pdev_dev, "could not connect to FW, error %d\n",
ret);
@@ -2742,44 +3026,7 @@ static int adap_init0(struct adapter *adap)
}
/* reset device */
- ret = t4_fw_reset(adap, 0, PIORSTMODE | PIORST);
- if (ret < 0)
- goto bye;
-
- /* get device capabilities */
- memset(&c, 0, sizeof(c));
- c.op_to_write = htonl(FW_CMD_OP(FW_CAPS_CONFIG_CMD) |
- FW_CMD_REQUEST | FW_CMD_READ);
- c.retval_len16 = htonl(FW_LEN16(c));
- ret = t4_wr_mbox(adap, 0, &c, sizeof(c), &c);
- if (ret < 0)
- goto bye;
-
- /* select capabilities we'll be using */
- if (c.niccaps & htons(FW_CAPS_CONFIG_NIC_VM)) {
- if (!vf_acls)
- c.niccaps ^= htons(FW_CAPS_CONFIG_NIC_VM);
- else
- c.niccaps = htons(FW_CAPS_CONFIG_NIC_VM);
- } else if (vf_acls) {
- dev_err(adap->pdev_dev, "virtualization ACLs not supported");
- goto bye;
- }
- c.op_to_write = htonl(FW_CMD_OP(FW_CAPS_CONFIG_CMD) |
- FW_CMD_REQUEST | FW_CMD_WRITE);
- ret = t4_wr_mbox(adap, 0, &c, sizeof(c), NULL);
- if (ret < 0)
- goto bye;
-
- ret = t4_config_glbl_rss(adap, 0,
- FW_RSS_GLB_CONFIG_CMD_MODE_BASICVIRTUAL,
- FW_RSS_GLB_CONFIG_CMD_TNLMAPEN |
- FW_RSS_GLB_CONFIG_CMD_TNLALLLKP);
- if (ret < 0)
- goto bye;
-
- ret = t4_cfg_pfvf(adap, 0, 0, 0, 64, 64, 64, 0, 0, 4, 0xf, 0xf, 16,
- FW_CMD_CAP_PF, FW_CMD_CAP_PF);
+ ret = t4_fw_reset(adap, adap->fn, PIORSTMODE | PIORST);
if (ret < 0)
goto bye;
@@ -2790,27 +3037,31 @@ static int adap_init0(struct adapter *adap)
for (v = 1; v < SGE_NCOUNTERS; v++)
adap->sge.counter_val[v] = min(intr_cnt[v - 1],
THRESHOLD_3_MASK);
- t4_sge_init(adap);
+#define FW_PARAM_DEV(param) \
+ (FW_PARAMS_MNEM(FW_PARAMS_MNEM_DEV) | \
+ FW_PARAMS_PARAM_X(FW_PARAMS_PARAM_DEV_##param))
- /* get basic stuff going */
- ret = t4_early_init(adap, 0);
+ params[0] = FW_PARAM_DEV(CCLK);
+ ret = t4_query_params(adap, adap->fn, adap->fn, 0, 1, params, val);
if (ret < 0)
goto bye;
+ adap->params.vpd.cclk = val[0];
-#define FW_PARAM_DEV(param) \
- (FW_PARAMS_MNEM(FW_PARAMS_MNEM_DEV) | \
- FW_PARAMS_PARAM_X(FW_PARAMS_PARAM_DEV_##param))
+ ret = adap_init1(adap, &c);
+ if (ret < 0)
+ goto bye;
#define FW_PARAM_PFVF(param) \
(FW_PARAMS_MNEM(FW_PARAMS_MNEM_PFVF) | \
- FW_PARAMS_PARAM_X(FW_PARAMS_PARAM_PFVF_##param))
+ FW_PARAMS_PARAM_X(FW_PARAMS_PARAM_PFVF_##param) | \
+ FW_PARAMS_PARAM_Y(adap->fn))
params[0] = FW_PARAM_DEV(PORTVEC);
params[1] = FW_PARAM_PFVF(L2T_START);
params[2] = FW_PARAM_PFVF(L2T_END);
params[3] = FW_PARAM_PFVF(FILTER_START);
params[4] = FW_PARAM_PFVF(FILTER_END);
- ret = t4_query_params(adap, 0, 0, 0, 5, params, val);
+ ret = t4_query_params(adap, adap->fn, adap->fn, 0, 5, params, val);
if (ret < 0)
goto bye;
port_vec = val[0];
@@ -2825,7 +3076,8 @@ static int adap_init0(struct adapter *adap)
params[3] = FW_PARAM_PFVF(TDDP_START);
params[4] = FW_PARAM_PFVF(TDDP_END);
params[5] = FW_PARAM_DEV(FLOWC_BUFFIFO_SZ);
- ret = t4_query_params(adap, 0, 0, 0, 6, params, val);
+ ret = t4_query_params(adap, adap->fn, adap->fn, 0, 6, params,
+ val);
if (ret < 0)
goto bye;
adap->tids.ntids = val[0];
@@ -2844,7 +3096,8 @@ static int adap_init0(struct adapter *adap)
params[3] = FW_PARAM_PFVF(RQ_END);
params[4] = FW_PARAM_PFVF(PBL_START);
params[5] = FW_PARAM_PFVF(PBL_END);
- ret = t4_query_params(adap, 0, 0, 0, 6, params, val);
+ ret = t4_query_params(adap, adap->fn, adap->fn, 0, 6, params,
+ val);
if (ret < 0)
goto bye;
adap->vres.stag.start = val[0];
@@ -2853,11 +3106,29 @@ static int adap_init0(struct adapter *adap)
adap->vres.rq.size = val[3] - val[2] + 1;
adap->vres.pbl.start = val[4];
adap->vres.pbl.size = val[5] - val[4] + 1;
+
+ params[0] = FW_PARAM_PFVF(SQRQ_START);
+ params[1] = FW_PARAM_PFVF(SQRQ_END);
+ params[2] = FW_PARAM_PFVF(CQ_START);
+ params[3] = FW_PARAM_PFVF(CQ_END);
+ params[4] = FW_PARAM_PFVF(OCQ_START);
+ params[5] = FW_PARAM_PFVF(OCQ_END);
+ ret = t4_query_params(adap, adap->fn, adap->fn, 0, 6, params,
+ val);
+ if (ret < 0)
+ goto bye;
+ adap->vres.qp.start = val[0];
+ adap->vres.qp.size = val[1] - val[0] + 1;
+ adap->vres.cq.start = val[2];
+ adap->vres.cq.size = val[3] - val[2] + 1;
+ adap->vres.ocq.start = val[4];
+ adap->vres.ocq.size = val[5] - val[4] + 1;
}
if (c.iscsicaps) {
params[0] = FW_PARAM_PFVF(ISCSI_START);
params[1] = FW_PARAM_PFVF(ISCSI_END);
- ret = t4_query_params(adap, 0, 0, 0, 2, params, val);
+ ret = t4_query_params(adap, adap->fn, adap->fn, 0, 2, params,
+ val);
if (ret < 0)
goto bye;
adap->vres.iscsi.start = val[0];
@@ -2877,12 +3148,41 @@ static int adap_init0(struct adapter *adap)
t4_load_mtus(adap, adap->params.mtus, adap->params.a_wnd,
adap->params.b_wnd);
- /* tweak some settings */
- t4_write_reg(adap, TP_SHIFT_CNT, 0x64f8849);
- t4_write_reg(adap, ULP_RX_TDDP_PSZ, HPZ0(PAGE_SHIFT - 12));
- t4_write_reg(adap, TP_PIO_ADDR, TP_INGRESS_CONFIG);
- v = t4_read_reg(adap, TP_PIO_DATA);
- t4_write_reg(adap, TP_PIO_DATA, v & ~CSUM_HAS_PSEUDO_HDR);
+#ifdef CONFIG_PCI_IOV
+ /*
+ * Provision resource limits for Virtual Functions. We currently
+ * grant them all the same static resource limits except for the Port
+ * Access Rights Mask which we're assigning based on the PF. All of
+ * the static provisioning stuff for both the PF and VF really needs
+ * to be managed in a persistent manner for each device which the
+ * firmware controls.
+ */
+ {
+ int pf, vf;
+
+ for (pf = 0; pf < ARRAY_SIZE(num_vf); pf++) {
+ if (num_vf[pf] <= 0)
+ continue;
+
+ /* VF numbering starts at 1! */
+ for (vf = 1; vf <= num_vf[pf]; vf++) {
+ ret = t4_cfg_pfvf(adap, adap->fn, pf, vf,
+ VFRES_NEQ, VFRES_NETHCTRL,
+ VFRES_NIQFLINT, VFRES_NIQ,
+ VFRES_TC, VFRES_NVI,
+ FW_PFVF_CMD_CMASK_MASK,
+ pfvfres_pmask(adap, pf, vf),
+ VFRES_NEXACTF,
+ VFRES_R_CAPS, VFRES_WX_CAPS);
+ if (ret < 0)
+ dev_warn(adap->pdev_dev, "failed to "
+ "provision pf/vf=%d/%d; "
+ "err=%d\n", pf, vf, ret);
+ }
+ }
+ }
+#endif
+
setup_memwin(adap);
return 0;
@@ -2892,10 +3192,114 @@ static int adap_init0(struct adapter *adap)
* commands.
*/
bye: if (ret != -ETIMEDOUT && ret != -EIO)
- t4_fw_bye(adap, 0);
+ t4_fw_bye(adap, adap->fn);
return ret;
}
+/* EEH callbacks */
+
+static pci_ers_result_t eeh_err_detected(struct pci_dev *pdev,
+ pci_channel_state_t state)
+{
+ int i;
+ struct adapter *adap = pci_get_drvdata(pdev);
+
+ if (!adap)
+ goto out;
+
+ rtnl_lock();
+ adap->flags &= ~FW_OK;
+ notify_ulds(adap, CXGB4_STATE_START_RECOVERY);
+ for_each_port(adap, i) {
+ struct net_device *dev = adap->port[i];
+
+ netif_device_detach(dev);
+ netif_carrier_off(dev);
+ }
+ if (adap->flags & FULL_INIT_DONE)
+ cxgb_down(adap);
+ rtnl_unlock();
+ pci_disable_device(pdev);
+out: return state == pci_channel_io_perm_failure ?
+ PCI_ERS_RESULT_DISCONNECT : PCI_ERS_RESULT_NEED_RESET;
+}
+
+static pci_ers_result_t eeh_slot_reset(struct pci_dev *pdev)
+{
+ int i, ret;
+ struct fw_caps_config_cmd c;
+ struct adapter *adap = pci_get_drvdata(pdev);
+
+ if (!adap) {
+ pci_restore_state(pdev);
+ pci_save_state(pdev);
+ return PCI_ERS_RESULT_RECOVERED;
+ }
+
+ if (pci_enable_device(pdev)) {
+ dev_err(&pdev->dev, "cannot reenable PCI device after reset\n");
+ return PCI_ERS_RESULT_DISCONNECT;
+ }
+
+ pci_set_master(pdev);
+ pci_restore_state(pdev);
+ pci_save_state(pdev);
+ pci_cleanup_aer_uncorrect_error_status(pdev);
+
+ if (t4_wait_dev_ready(adap) < 0)
+ return PCI_ERS_RESULT_DISCONNECT;
+ if (t4_fw_hello(adap, adap->fn, adap->fn, MASTER_MUST, NULL))
+ return PCI_ERS_RESULT_DISCONNECT;
+ adap->flags |= FW_OK;
+ if (adap_init1(adap, &c))
+ return PCI_ERS_RESULT_DISCONNECT;
+
+ for_each_port(adap, i) {
+ struct port_info *p = adap2pinfo(adap, i);
+
+ ret = t4_alloc_vi(adap, adap->fn, p->tx_chan, adap->fn, 0, 1,
+ NULL, NULL);
+ if (ret < 0)
+ return PCI_ERS_RESULT_DISCONNECT;
+ p->viid = ret;
+ p->xact_addr_filt = -1;
+ }
+
+ t4_load_mtus(adap, adap->params.mtus, adap->params.a_wnd,
+ adap->params.b_wnd);
+ setup_memwin(adap);
+ if (cxgb_up(adap))
+ return PCI_ERS_RESULT_DISCONNECT;
+ return PCI_ERS_RESULT_RECOVERED;
+}
+
+static void eeh_resume(struct pci_dev *pdev)
+{
+ int i;
+ struct adapter *adap = pci_get_drvdata(pdev);
+
+ if (!adap)
+ return;
+
+ rtnl_lock();
+ for_each_port(adap, i) {
+ struct net_device *dev = adap->port[i];
+
+ if (netif_running(dev)) {
+ link_start(dev);
+ cxgb_set_rxmode(dev);
+ }
+ netif_device_attach(dev);
+ }
+ rtnl_unlock();
+}
+
+static struct pci_error_handlers cxgb4_eeh = {
+ .error_detected = eeh_err_detected,
+ .slot_reset = eeh_slot_reset,
+ .resume = eeh_resume,
+};
+
static inline bool is_10g_port(const struct link_config *lc)
{
return (lc->supported & FW_PORT_CAP_SPEED_10G) != 0;
@@ -3076,10 +3480,27 @@ static int __devinit enable_msix(struct adapter *adap)
#undef EXTRA_VECS
+static int __devinit init_rss(struct adapter *adap)
+{
+ unsigned int i, j;
+
+ for_each_port(adap, i) {
+ struct port_info *pi = adap2pinfo(adap, i);
+
+ pi->rss = kcalloc(pi->rss_size, sizeof(u16), GFP_KERNEL);
+ if (!pi->rss)
+ return -ENOMEM;
+ for (j = 0; j < pi->rss_size; j++)
+ pi->rss[j] = j % pi->nqsets;
+ }
+ return 0;
+}
+
static void __devinit print_port_info(struct adapter *adap)
{
static const char *base[] = {
- "R", "KX4", "T", "KX", "T", "KR", "CX4"
+ "R XFI", "R XAUI", "T SGMII", "T XFI", "T XAUI", "KX4", "CX4",
+ "KX", "KR", "KR SFP+", "KR FEC"
};
int i;
@@ -3121,7 +3542,31 @@ static void __devinit print_port_info(struct adapter *adap)
}
}
-#define VLAN_FEAT (NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO | NETIF_F_TSO6 |\
+/*
+ * Free the following resources:
+ * - memory used for tables
+ * - MSI/MSI-X
+ * - net devices
+ * - resources FW is holding for us
+ */
+static void free_some_resources(struct adapter *adapter)
+{
+ unsigned int i;
+
+ t4_free_mem(adapter->l2t);
+ t4_free_mem(adapter->tids.tid_tab);
+ disable_msi(adapter);
+
+ for_each_port(adapter, i)
+ if (adapter->port[i]) {
+ kfree(adap2pinfo(adapter, i)->rss);
+ free_netdev(adapter->port[i]);
+ }
+ if (adapter->flags & FW_OK)
+ t4_fw_bye(adapter, adapter->fn);
+}
+
+#define VLAN_FEAT (NETIF_F_SG | NETIF_F_IP_CSUM | TSO_FLAGS | \
NETIF_F_IPV6_CSUM | NETIF_F_HIGHDMA)
static int __devinit init_one(struct pci_dev *pdev,
@@ -3141,10 +3586,12 @@ static int __devinit init_one(struct pci_dev *pdev,
return err;
}
- /* We control everything through PF 0 */
+ /* We control everything through one PF */
func = PCI_FUNC(pdev->devfn);
- if (func > 0)
+ if (func != ent->driver_data) {
+ pci_save_state(pdev); /* to restore SR-IOV later */
goto sriov;
+ }
err = pci_enable_device(pdev);
if (err) {
@@ -3187,6 +3634,7 @@ static int __devinit init_one(struct pci_dev *pdev,
adapter->pdev = pdev;
adapter->pdev_dev = &pdev->dev;
+ adapter->fn = func;
adapter->name = pci_name(pdev);
adapter->msg_enable = dflt_msg_enable;
memset(adapter->chan_map, 0xff, sizeof(adapter->chan_map));
@@ -3225,7 +3673,7 @@ static int __devinit init_one(struct pci_dev *pdev,
netif_tx_stop_all_queues(netdev);
netdev->irq = pdev->irq;
- netdev->features |= NETIF_F_SG | NETIF_F_TSO | NETIF_F_TSO6;
+ netdev->features |= NETIF_F_SG | TSO_FLAGS;
netdev->features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM;
netdev->features |= NETIF_F_GRO | NETIF_F_RXHASH | highdma;
netdev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
@@ -3238,7 +3686,7 @@ static int __devinit init_one(struct pci_dev *pdev,
pci_set_drvdata(pdev, adapter);
if (adapter->flags & FW_OK) {
- err = t4_port_init(adapter, 0, 0, 0);
+ err = t4_port_init(adapter, func, func, 0);
if (err)
goto out_free_dev;
}
@@ -3262,6 +3710,16 @@ static int __devinit init_one(struct pci_dev *pdev,
adapter->params.offload = 0;
}
+ /* See what interrupts we'll be using */
+ if (msi > 1 && enable_msix(adapter) == 0)
+ adapter->flags |= USING_MSIX;
+ else if (msi > 0 && pci_enable_msi(pdev) == 0)
+ adapter->flags |= USING_MSI;
+
+ err = init_rss(adapter);
+ if (err)
+ goto out_free_dev;
+
/*
* The card is now ready to go. If any errors occur during device
* registration we do not fail the whole card but rather proceed only
@@ -3297,12 +3755,6 @@ static int __devinit init_one(struct pci_dev *pdev,
setup_debugfs(adapter);
}
- /* See what interrupts we'll be using */
- if (msi > 1 && enable_msix(adapter) == 0)
- adapter->flags |= USING_MSIX;
- else if (msi > 0 && pci_enable_msi(pdev) == 0)
- adapter->flags |= USING_MSI;
-
if (is_offload(adapter))
attach_ulds(adapter);
@@ -3319,13 +3771,7 @@ sriov:
return 0;
out_free_dev:
- t4_free_mem(adapter->tids.tid_tab);
- t4_free_mem(adapter->l2t);
- for_each_port(adapter, i)
- if (adapter->port[i])
- free_netdev(adapter->port[i]);
- if (adapter->flags & FW_OK)
- t4_fw_bye(adapter, 0);
+ free_some_resources(adapter);
out_unmap_bar:
iounmap(adapter->regs);
out_free_adapter:
@@ -3360,16 +3806,8 @@ static void __devexit remove_one(struct pci_dev *pdev)
if (adapter->flags & FULL_INIT_DONE)
cxgb_down(adapter);
- t4_free_mem(adapter->l2t);
- t4_free_mem(adapter->tids.tid_tab);
- disable_msi(adapter);
-
- for_each_port(adapter, i)
- if (adapter->port[i])
- free_netdev(adapter->port[i]);
- if (adapter->flags & FW_OK)
- t4_fw_bye(adapter, 0);
+ free_some_resources(adapter);
iounmap(adapter->regs);
kfree(adapter);
pci_disable_pcie_error_reporting(pdev);
@@ -3385,6 +3823,7 @@ static struct pci_driver cxgb4_driver = {
.id_table = cxgb4_pci_tbl,
.probe = init_one,
.remove = __devexit_p(remove_one),
+ .err_handler = &cxgb4_eeh,
};
static int __init cxgb4_init_module(void)
diff --git a/drivers/net/cxgb4/cxgb4_uld.h b/drivers/net/cxgb4/cxgb4_uld.h
index 5b98546ac92..85d74e751ce 100644
--- a/drivers/net/cxgb4/cxgb4_uld.h
+++ b/drivers/net/cxgb4/cxgb4_uld.h
@@ -185,8 +185,14 @@ struct cxgb4_virt_res { /* virtualized HW resources */
struct cxgb4_range stag;
struct cxgb4_range rq;
struct cxgb4_range pbl;
+ struct cxgb4_range qp;
+ struct cxgb4_range cq;
+ struct cxgb4_range ocq;
};
+#define OCQ_WIN_OFFSET(pdev, vres) \
+ (pci_resource_len((pdev), 2) - roundup_pow_of_two((vres)->ocq.size))
+
/*
* Block of information the LLD provides to ULDs attaching to a device.
*/
diff --git a/drivers/net/cxgb4/l2t.c b/drivers/net/cxgb4/l2t.c
index 9f96724a133..e8f0f55e9d0 100644
--- a/drivers/net/cxgb4/l2t.c
+++ b/drivers/net/cxgb4/l2t.c
@@ -310,6 +310,13 @@ static void t4_l2e_free(struct l2t_entry *e)
neigh_release(e->neigh);
e->neigh = NULL;
}
+ while (e->arpq_head) {
+ struct sk_buff *skb = e->arpq_head;
+
+ e->arpq_head = skb->next;
+ kfree_skb(skb);
+ }
+ e->arpq_tail = NULL;
}
spin_unlock_bh(&e->lock);
diff --git a/drivers/net/cxgb4/sge.c b/drivers/net/cxgb4/sge.c
index d1f8f225e45..bf38cfc5756 100644
--- a/drivers/net/cxgb4/sge.c
+++ b/drivers/net/cxgb4/sge.c
@@ -938,16 +938,16 @@ out_free: dev_kfree_skb(skb);
wr->op_immdlen = htonl(FW_WR_OP(FW_ETH_TX_PKT_WR) |
FW_WR_IMMDLEN(sizeof(*lso)));
- lso->lso_ctrl = htonl(LSO_OPCODE(CPL_TX_PKT_LSO) |
- LSO_FIRST_SLICE | LSO_LAST_SLICE |
- LSO_IPV6(v6) |
- LSO_ETHHDR_LEN(eth_xtra_len / 4) |
- LSO_IPHDR_LEN(l3hdr_len / 4) |
- LSO_TCPHDR_LEN(tcp_hdr(skb)->doff));
- lso->ipid_ofst = htons(0);
- lso->mss = htons(ssi->gso_size);
- lso->seqno_offset = htonl(0);
- lso->len = htonl(skb->len);
+ lso->c.lso_ctrl = htonl(LSO_OPCODE(CPL_TX_PKT_LSO) |
+ LSO_FIRST_SLICE | LSO_LAST_SLICE |
+ LSO_IPV6(v6) |
+ LSO_ETHHDR_LEN(eth_xtra_len / 4) |
+ LSO_IPHDR_LEN(l3hdr_len / 4) |
+ LSO_TCPHDR_LEN(tcp_hdr(skb)->doff));
+ lso->c.ipid_ofst = htons(0);
+ lso->c.mss = htons(ssi->gso_size);
+ lso->c.seqno_offset = htonl(0);
+ lso->c.len = htonl(skb->len);
cpl = (void *)(lso + 1);
cntrl = TXPKT_CSUM_TYPE(v6 ? TX_CSUM_TCPIP6 : TX_CSUM_TCPIP) |
TXPKT_IPHDR_LEN(l3hdr_len) |
@@ -1593,14 +1593,15 @@ int t4_ethrx_handler(struct sge_rspq *q, const __be64 *rsp,
if (csum_ok && (pi->rx_offload & RX_CSO) &&
(pkt->l2info & htonl(RXF_UDP | RXF_TCP))) {
- if (!pkt->ip_frag)
+ if (!pkt->ip_frag) {
skb->ip_summed = CHECKSUM_UNNECESSARY;
- else {
+ rxq->stats.rx_cso++;
+ } else if (pkt->l2info & htonl(RXF_IP)) {
__sum16 c = (__force __sum16)pkt->csum;
skb->csum = csum_unfold(c);
skb->ip_summed = CHECKSUM_COMPLETE;
+ rxq->stats.rx_cso++;
}
- rxq->stats.rx_cso++;
} else
skb->ip_summed = CHECKSUM_NONE;
@@ -1718,7 +1719,7 @@ static int process_responses(struct sge_rspq *q, int budget)
free_rx_bufs(q->adap, &rxq->fl, 1);
q->offset = 0;
}
- len &= RSPD_LEN;
+ len = RSPD_LEN(len);
}
si.tot_len = len;
@@ -1998,7 +1999,7 @@ int t4_sge_alloc_rxq(struct adapter *adap, struct sge_rspq *iq, bool fwevtq,
memset(&c, 0, sizeof(c));
c.op_to_vfn = htonl(FW_CMD_OP(FW_IQ_CMD) | FW_CMD_REQUEST |
FW_CMD_WRITE | FW_CMD_EXEC |
- FW_IQ_CMD_PFN(0) | FW_IQ_CMD_VFN(0));
+ FW_IQ_CMD_PFN(adap->fn) | FW_IQ_CMD_VFN(0));
c.alloc_to_len16 = htonl(FW_IQ_CMD_ALLOC | FW_IQ_CMD_IQSTART(1) |
FW_LEN16(c));
c.type_to_iqandstindex = htonl(FW_IQ_CMD_TYPE(FW_IQ_TYPE_FL_INT_CAP) |
@@ -2030,7 +2031,7 @@ int t4_sge_alloc_rxq(struct adapter *adap, struct sge_rspq *iq, bool fwevtq,
c.fl0addr = cpu_to_be64(fl->addr);
}
- ret = t4_wr_mbox(adap, 0, &c, sizeof(c), &c);
+ ret = t4_wr_mbox(adap, adap->fn, &c, sizeof(c), &c);
if (ret)
goto err;
@@ -2109,7 +2110,7 @@ int t4_sge_alloc_eth_txq(struct adapter *adap, struct sge_eth_txq *txq,
memset(&c, 0, sizeof(c));
c.op_to_vfn = htonl(FW_CMD_OP(FW_EQ_ETH_CMD) | FW_CMD_REQUEST |
FW_CMD_WRITE | FW_CMD_EXEC |
- FW_EQ_ETH_CMD_PFN(0) | FW_EQ_ETH_CMD_VFN(0));
+ FW_EQ_ETH_CMD_PFN(adap->fn) | FW_EQ_ETH_CMD_VFN(0));
c.alloc_to_len16 = htonl(FW_EQ_ETH_CMD_ALLOC |
FW_EQ_ETH_CMD_EQSTART | FW_LEN16(c));
c.viid_pkd = htonl(FW_EQ_ETH_CMD_VIID(pi->viid));
@@ -2122,7 +2123,7 @@ int t4_sge_alloc_eth_txq(struct adapter *adap, struct sge_eth_txq *txq,
FW_EQ_ETH_CMD_EQSIZE(nentries));
c.eqaddr = cpu_to_be64(txq->q.phys_addr);
- ret = t4_wr_mbox(adap, 0, &c, sizeof(c), &c);
+ ret = t4_wr_mbox(adap, adap->fn, &c, sizeof(c), &c);
if (ret) {
kfree(txq->q.sdesc);
txq->q.sdesc = NULL;
@@ -2159,7 +2160,8 @@ int t4_sge_alloc_ctrl_txq(struct adapter *adap, struct sge_ctrl_txq *txq,
c.op_to_vfn = htonl(FW_CMD_OP(FW_EQ_CTRL_CMD) | FW_CMD_REQUEST |
FW_CMD_WRITE | FW_CMD_EXEC |
- FW_EQ_CTRL_CMD_PFN(0) | FW_EQ_CTRL_CMD_VFN(0));
+ FW_EQ_CTRL_CMD_PFN(adap->fn) |
+ FW_EQ_CTRL_CMD_VFN(0));
c.alloc_to_len16 = htonl(FW_EQ_CTRL_CMD_ALLOC |
FW_EQ_CTRL_CMD_EQSTART | FW_LEN16(c));
c.cmpliqid_eqid = htonl(FW_EQ_CTRL_CMD_CMPLIQID(cmplqid));
@@ -2173,7 +2175,7 @@ int t4_sge_alloc_ctrl_txq(struct adapter *adap, struct sge_ctrl_txq *txq,
FW_EQ_CTRL_CMD_EQSIZE(nentries));
c.eqaddr = cpu_to_be64(txq->q.phys_addr);
- ret = t4_wr_mbox(adap, 0, &c, sizeof(c), &c);
+ ret = t4_wr_mbox(adap, adap->fn, &c, sizeof(c), &c);
if (ret) {
dma_free_coherent(adap->pdev_dev,
nentries * sizeof(struct tx_desc),
@@ -2209,7 +2211,8 @@ int t4_sge_alloc_ofld_txq(struct adapter *adap, struct sge_ofld_txq *txq,
memset(&c, 0, sizeof(c));
c.op_to_vfn = htonl(FW_CMD_OP(FW_EQ_OFLD_CMD) | FW_CMD_REQUEST |
FW_CMD_WRITE | FW_CMD_EXEC |
- FW_EQ_OFLD_CMD_PFN(0) | FW_EQ_OFLD_CMD_VFN(0));
+ FW_EQ_OFLD_CMD_PFN(adap->fn) |
+ FW_EQ_OFLD_CMD_VFN(0));
c.alloc_to_len16 = htonl(FW_EQ_OFLD_CMD_ALLOC |
FW_EQ_OFLD_CMD_EQSTART | FW_LEN16(c));
c.fetchszm_to_iqid = htonl(FW_EQ_OFLD_CMD_HOSTFCMODE(2) |
@@ -2221,7 +2224,7 @@ int t4_sge_alloc_ofld_txq(struct adapter *adap, struct sge_ofld_txq *txq,
FW_EQ_OFLD_CMD_EQSIZE(nentries));
c.eqaddr = cpu_to_be64(txq->q.phys_addr);
- ret = t4_wr_mbox(adap, 0, &c, sizeof(c), &c);
+ ret = t4_wr_mbox(adap, adap->fn, &c, sizeof(c), &c);
if (ret) {
kfree(txq->q.sdesc);
txq->q.sdesc = NULL;
@@ -2257,8 +2260,8 @@ static void free_rspq_fl(struct adapter *adap, struct sge_rspq *rq,
unsigned int fl_id = fl ? fl->cntxt_id : 0xffff;
adap->sge.ingr_map[rq->cntxt_id] = NULL;
- t4_iq_free(adap, 0, 0, 0, FW_IQ_TYPE_FL_INT_CAP, rq->cntxt_id, fl_id,
- 0xffff);
+ t4_iq_free(adap, adap->fn, adap->fn, 0, FW_IQ_TYPE_FL_INT_CAP,
+ rq->cntxt_id, fl_id, 0xffff);
dma_free_coherent(adap->pdev_dev, (rq->size + 1) * rq->iqe_len,
rq->desc, rq->phys_addr);
netif_napi_del(&rq->napi);
@@ -2295,7 +2298,8 @@ void t4_free_sge_resources(struct adapter *adap)
if (eq->rspq.desc)
free_rspq_fl(adap, &eq->rspq, &eq->fl);
if (etq->q.desc) {
- t4_eth_eq_free(adap, 0, 0, 0, etq->q.cntxt_id);
+ t4_eth_eq_free(adap, adap->fn, adap->fn, 0,
+ etq->q.cntxt_id);
free_tx_desc(adap, &etq->q, etq->q.in_use, true);
kfree(etq->q.sdesc);
free_txq(adap, &etq->q);
@@ -2318,7 +2322,8 @@ void t4_free_sge_resources(struct adapter *adap)
if (q->q.desc) {
tasklet_kill(&q->qresume_tsk);
- t4_ofld_eq_free(adap, 0, 0, 0, q->q.cntxt_id);
+ t4_ofld_eq_free(adap, adap->fn, adap->fn, 0,
+ q->q.cntxt_id);
free_tx_desc(adap, &q->q, q->q.in_use, false);
kfree(q->q.sdesc);
__skb_queue_purge(&q->sendq);
@@ -2332,7 +2337,8 @@ void t4_free_sge_resources(struct adapter *adap)
if (cq->q.desc) {
tasklet_kill(&cq->qresume_tsk);
- t4_ctrl_eq_free(adap, 0, 0, 0, cq->q.cntxt_id);
+ t4_ctrl_eq_free(adap, adap->fn, adap->fn, 0,
+ cq->q.cntxt_id);
__skb_queue_purge(&cq->sendq);
free_txq(adap, &cq->q);
}
@@ -2400,6 +2406,7 @@ void t4_sge_stop(struct adapter *adap)
*/
void t4_sge_init(struct adapter *adap)
{
+ unsigned int i, v;
struct sge *s = &adap->sge;
unsigned int fl_align_log = ilog2(FL_ALIGN);
@@ -2408,8 +2415,10 @@ void t4_sge_init(struct adapter *adap)
INGPADBOUNDARY(fl_align_log - 5) | PKTSHIFT(2) |
RXPKTCPLMODE |
(STAT_LEN == 128 ? EGRSTATUSPAGESIZE : 0));
- t4_set_reg_field(adap, SGE_HOST_PAGE_SIZE, HOSTPAGESIZEPF0_MASK,
- HOSTPAGESIZEPF0(PAGE_SHIFT - 10));
+
+ for (i = v = 0; i < 32; i += 4)
+ v |= (PAGE_SHIFT - 10) << i;
+ t4_write_reg(adap, SGE_HOST_PAGE_SIZE, v);
t4_write_reg(adap, SGE_FL_BUFFER_SIZE0, PAGE_SIZE);
#if FL_PG_ORDER > 0
t4_write_reg(adap, SGE_FL_BUFFER_SIZE1, PAGE_SIZE << FL_PG_ORDER);
diff --git a/drivers/net/cxgb4/t4_hw.c b/drivers/net/cxgb4/t4_hw.c
index da272a98fdb..9e1a4b49b47 100644
--- a/drivers/net/cxgb4/t4_hw.c
+++ b/drivers/net/cxgb4/t4_hw.c
@@ -221,6 +221,13 @@ int t4_wr_mbox_meat(struct adapter *adap, int mbox, const void *cmd, int size,
if ((size & 15) || size > MBOX_LEN)
return -EINVAL;
+ /*
+ * If the device is off-line, as in EEH, commands will time out.
+ * Fail them early so we don't waste time waiting.
+ */
+ if (adap->pdev->error_state != pci_channel_io_normal)
+ return -EIO;
+
v = MBOWNER_GET(t4_read_reg(adap, ctl_reg));
for (i = 0; v == MBOX_OWNER_NONE && i < 3; i++)
v = MBOWNER_GET(t4_read_reg(adap, ctl_reg));
@@ -449,12 +456,10 @@ enum {
SF_RD_STATUS = 5, /* read status register */
SF_WR_ENABLE = 6, /* enable writes */
SF_RD_DATA_FAST = 0xb, /* read flash */
+ SF_RD_ID = 0x9f, /* read ID */
SF_ERASE_SECTOR = 0xd8, /* erase sector */
- FW_START_SEC = 8, /* first flash sector for FW */
- FW_END_SEC = 15, /* last flash sector for FW */
- FW_IMG_START = FW_START_SEC * SF_SEC_SIZE,
- FW_MAX_SIZE = (FW_END_SEC - FW_START_SEC + 1) * SF_SEC_SIZE,
+ FW_MAX_SIZE = 512 * 1024,
};
/**
@@ -558,7 +563,7 @@ static int t4_read_flash(struct adapter *adapter, unsigned int addr,
{
int ret;
- if (addr + nwords * sizeof(u32) > SF_SIZE || (addr & 3))
+ if (addr + nwords * sizeof(u32) > adapter->params.sf_size || (addr & 3))
return -EINVAL;
addr = swab32(addr) | SF_RD_DATA_FAST;
@@ -596,7 +601,7 @@ static int t4_write_flash(struct adapter *adapter, unsigned int addr,
u32 buf[64];
unsigned int i, c, left, val, offset = addr & 0xff;
- if (addr >= SF_SIZE || offset + n > SF_PAGE_SIZE)
+ if (addr >= adapter->params.sf_size || offset + n > SF_PAGE_SIZE)
return -EINVAL;
val = swab32(addr) | SF_PROG_PAGE;
@@ -614,7 +619,7 @@ static int t4_write_flash(struct adapter *adapter, unsigned int addr,
if (ret)
goto unlock;
}
- ret = flash_wait_op(adapter, 5, 1);
+ ret = flash_wait_op(adapter, 8, 1);
if (ret)
goto unlock;
@@ -647,9 +652,8 @@ unlock:
*/
static int get_fw_version(struct adapter *adapter, u32 *vers)
{
- return t4_read_flash(adapter,
- FW_IMG_START + offsetof(struct fw_hdr, fw_ver), 1,
- vers, 0);
+ return t4_read_flash(adapter, adapter->params.sf_fw_start +
+ offsetof(struct fw_hdr, fw_ver), 1, vers, 0);
}
/**
@@ -661,8 +665,8 @@ static int get_fw_version(struct adapter *adapter, u32 *vers)
*/
static int get_tp_version(struct adapter *adapter, u32 *vers)
{
- return t4_read_flash(adapter, FW_IMG_START + offsetof(struct fw_hdr,
- tp_microcode_ver),
+ return t4_read_flash(adapter, adapter->params.sf_fw_start +
+ offsetof(struct fw_hdr, tp_microcode_ver),
1, vers, 0);
}
@@ -684,9 +688,9 @@ int t4_check_fw_version(struct adapter *adapter)
if (!ret)
ret = get_tp_version(adapter, &adapter->params.tp_vers);
if (!ret)
- ret = t4_read_flash(adapter,
- FW_IMG_START + offsetof(struct fw_hdr, intfver_nic),
- 2, api_vers, 1);
+ ret = t4_read_flash(adapter, adapter->params.sf_fw_start +
+ offsetof(struct fw_hdr, intfver_nic),
+ 2, api_vers, 1);
if (ret)
return ret;
@@ -726,7 +730,7 @@ static int t4_flash_erase_sectors(struct adapter *adapter, int start, int end)
if ((ret = sf1_write(adapter, 1, 0, 1, SF_WR_ENABLE)) != 0 ||
(ret = sf1_write(adapter, 4, 0, 1,
SF_ERASE_SECTOR | (start << 8))) != 0 ||
- (ret = flash_wait_op(adapter, 5, 500)) != 0) {
+ (ret = flash_wait_op(adapter, 14, 500)) != 0) {
dev_err(adapter->pdev_dev,
"erase of flash sector %d failed, error %d\n",
start, ret);
@@ -754,6 +758,9 @@ int t4_load_fw(struct adapter *adap, const u8 *fw_data, unsigned int size)
u8 first_page[SF_PAGE_SIZE];
const u32 *p = (const u32 *)fw_data;
const struct fw_hdr *hdr = (const struct fw_hdr *)fw_data;
+ unsigned int sf_sec_size = adap->params.sf_size / adap->params.sf_nsec;
+ unsigned int fw_img_start = adap->params.sf_fw_start;
+ unsigned int fw_start_sec = fw_img_start / sf_sec_size;
if (!size) {
dev_err(adap->pdev_dev, "FW image has no data\n");
@@ -784,8 +791,8 @@ int t4_load_fw(struct adapter *adap, const u8 *fw_data, unsigned int size)
return -EINVAL;
}
- i = DIV_ROUND_UP(size, SF_SEC_SIZE); /* # of sectors spanned */
- ret = t4_flash_erase_sectors(adap, FW_START_SEC, FW_START_SEC + i - 1);
+ i = DIV_ROUND_UP(size, sf_sec_size); /* # of sectors spanned */
+ ret = t4_flash_erase_sectors(adap, fw_start_sec, fw_start_sec + i - 1);
if (ret)
goto out;
@@ -796,11 +803,11 @@ int t4_load_fw(struct adapter *adap, const u8 *fw_data, unsigned int size)
*/
memcpy(first_page, fw_data, SF_PAGE_SIZE);
((struct fw_hdr *)first_page)->fw_ver = htonl(0xffffffff);
- ret = t4_write_flash(adap, FW_IMG_START, SF_PAGE_SIZE, first_page);
+ ret = t4_write_flash(adap, fw_img_start, SF_PAGE_SIZE, first_page);
if (ret)
goto out;
- addr = FW_IMG_START;
+ addr = fw_img_start;
for (size -= SF_PAGE_SIZE; size; size -= SF_PAGE_SIZE) {
addr += SF_PAGE_SIZE;
fw_data += SF_PAGE_SIZE;
@@ -810,7 +817,7 @@ int t4_load_fw(struct adapter *adap, const u8 *fw_data, unsigned int size)
}
ret = t4_write_flash(adap,
- FW_IMG_START + offsetof(struct fw_hdr, fw_ver),
+ fw_img_start + offsetof(struct fw_hdr, fw_ver),
sizeof(hdr->fw_ver), (const u8 *)&hdr->fw_ver);
out:
if (ret)
@@ -1128,6 +1135,7 @@ static void cim_intr_handler(struct adapter *adapter)
static void ulprx_intr_handler(struct adapter *adapter)
{
static struct intr_info ulprx_intr_info[] = {
+ { 0x1800000, "ULPRX context error", -1, 1 },
{ 0x7fffff, "ULPRX parity error", -1, 1 },
{ 0 }
};
@@ -1436,7 +1444,7 @@ static void pl_intr_handler(struct adapter *adap)
t4_fatal_err(adap);
}
-#define PF_INTR_MASK (PFSW | PFCIM)
+#define PF_INTR_MASK (PFSW)
#define GLBL_INTR_MASK (CIM | MPS | PL | PCIE | MC | EDC0 | \
EDC1 | LE | TP | MA | PM_TX | PM_RX | ULP_RX | \
CPL_SWITCH | SGE | ULP_TX)
@@ -2510,7 +2518,7 @@ int t4_cfg_pfvf(struct adapter *adap, unsigned int mbox, unsigned int pf,
c.retval_len16 = htonl(FW_LEN16(c));
c.niqflint_niq = htonl(FW_PFVF_CMD_NIQFLINT(rxqi) |
FW_PFVF_CMD_NIQ(rxq));
- c.cmask_to_neq = htonl(FW_PFVF_CMD_CMASK(cmask) |
+ c.type_to_neq = htonl(FW_PFVF_CMD_CMASK(cmask) |
FW_PFVF_CMD_PMASK(pmask) |
FW_PFVF_CMD_NEQ(txq));
c.tc_to_nexactf = htonl(FW_PFVF_CMD_TC(tc) | FW_PFVF_CMD_NVI(vi) |
@@ -2572,7 +2580,7 @@ int t4_alloc_vi(struct adapter *adap, unsigned int mbox, unsigned int port,
}
if (rss_size)
*rss_size = FW_VI_CMD_RSSSIZE_GET(ntohs(c.rsssize_pkd));
- return ntohs(c.viid_pkd);
+ return FW_VI_CMD_VIID_GET(ntohs(c.type_viid));
}
/**
@@ -2595,7 +2603,7 @@ int t4_free_vi(struct adapter *adap, unsigned int mbox, unsigned int pf,
FW_CMD_EXEC | FW_VI_CMD_PFN(pf) |
FW_VI_CMD_VFN(vf));
c.alloc_to_len16 = htonl(FW_VI_CMD_FREE | FW_LEN16(c));
- c.viid_pkd = htons(FW_VI_CMD_VIID(viid));
+ c.type_viid = htons(FW_VI_CMD_VIID(viid));
return t4_wr_mbox(adap, mbox, &c, sizeof(c), &c);
}
@@ -3045,7 +3053,7 @@ static void __devinit init_link_config(struct link_config *lc,
}
}
-static int __devinit wait_dev_ready(struct adapter *adap)
+int t4_wait_dev_ready(struct adapter *adap)
{
if (t4_read_reg(adap, PL_WHOAMI) != 0xffffffff)
return 0;
@@ -3053,6 +3061,33 @@ static int __devinit wait_dev_ready(struct adapter *adap)
return t4_read_reg(adap, PL_WHOAMI) != 0xffffffff ? 0 : -EIO;
}
+static int __devinit get_flash_params(struct adapter *adap)
+{
+ int ret;
+ u32 info;
+
+ ret = sf1_write(adap, 1, 1, 0, SF_RD_ID);
+ if (!ret)
+ ret = sf1_read(adap, 3, 0, 1, &info);
+ t4_write_reg(adap, SF_OP, 0); /* unlock SF */
+ if (ret)
+ return ret;
+
+ if ((info & 0xff) != 0x20) /* not a Numonix flash */
+ return -EINVAL;
+ info >>= 16; /* log2 of size */
+ if (info >= 0x14 && info < 0x18)
+ adap->params.sf_nsec = 1 << (info - 16);
+ else if (info == 0x18)
+ adap->params.sf_nsec = 64;
+ else
+ return -EINVAL;
+ adap->params.sf_size = 1 << info;
+ adap->params.sf_fw_start =
+ t4_read_reg(adap, CIM_BOOT_CFG) & BOOTADDR_MASK;
+ return 0;
+}
+
/**
* t4_prep_adapter - prepare SW and HW for operation
* @adapter: the adapter
@@ -3066,13 +3101,19 @@ int __devinit t4_prep_adapter(struct adapter *adapter)
{
int ret;
- ret = wait_dev_ready(adapter);
+ ret = t4_wait_dev_ready(adapter);
if (ret < 0)
return ret;
get_pci_mode(adapter, &adapter->params.pci);
adapter->params.rev = t4_read_reg(adapter, PL_REV);
+ ret = get_flash_params(adapter);
+ if (ret < 0) {
+ dev_err(adapter->pdev_dev, "error %d identifying flash\n", ret);
+ return ret;
+ }
+
ret = get_vpd_params(adapter, &adapter->params.vpd);
if (ret < 0)
return ret;
@@ -3092,8 +3133,10 @@ int __devinit t4_port_init(struct adapter *adap, int mbox, int pf, int vf)
u8 addr[6];
int ret, i, j = 0;
struct fw_port_cmd c;
+ struct fw_rss_vi_config_cmd rvc;
memset(&c, 0, sizeof(c));
+ memset(&rvc, 0, sizeof(rvc));
for_each_port(adap, i) {
unsigned int rss_size;
@@ -3122,12 +3165,22 @@ int __devinit t4_port_init(struct adapter *adap, int mbox, int pf, int vf)
p->rss_size = rss_size;
memcpy(adap->port[i]->dev_addr, addr, ETH_ALEN);
memcpy(adap->port[i]->perm_addr, addr, ETH_ALEN);
+ adap->port[i]->dev_id = j;
ret = ntohl(c.u.info.lstatus_to_modtype);
p->mdio_addr = (ret & FW_PORT_CMD_MDIOCAP) ?
FW_PORT_CMD_MDIOADDR_GET(ret) : -1;
p->port_type = FW_PORT_CMD_PTYPE_GET(ret);
- p->mod_type = FW_PORT_CMD_MODTYPE_GET(ret);
+ p->mod_type = FW_PORT_MOD_TYPE_NA;
+
+ rvc.op_to_viid = htonl(FW_CMD_OP(FW_RSS_VI_CONFIG_CMD) |
+ FW_CMD_REQUEST | FW_CMD_READ |
+ FW_RSS_VI_CONFIG_CMD_VIID(p->viid));
+ rvc.retval_len16 = htonl(FW_LEN16(rvc));
+ ret = t4_wr_mbox(adap, mbox, &rvc, sizeof(rvc), &rvc);
+ if (ret)
+ return ret;
+ p->rss_mode = ntohl(rvc.u.basicvirtual.defaultq_to_udpen);
init_link_config(&p->link_cfg, ntohs(c.u.info.pcap));
j++;
diff --git a/drivers/net/cxgb4/t4_hw.h b/drivers/net/cxgb4/t4_hw.h
index 025623285c9..10a05556577 100644
--- a/drivers/net/cxgb4/t4_hw.h
+++ b/drivers/net/cxgb4/t4_hw.h
@@ -57,8 +57,6 @@ enum {
enum {
SF_PAGE_SIZE = 256, /* serial flash page size */
- SF_SEC_SIZE = 64 * 1024, /* serial flash sector size */
- SF_SIZE = SF_SEC_SIZE * 16, /* serial flash size */
};
enum { RSP_TYPE_FLBUF, RSP_TYPE_CPL, RSP_TYPE_INTR }; /* response entry types */
@@ -69,6 +67,45 @@ enum {
SGE_MAX_WR_LEN = 512, /* max WR size in bytes */
SGE_NTIMERS = 6, /* # of interrupt holdoff timer values */
SGE_NCOUNTERS = 4, /* # of interrupt packet counter values */
+
+ SGE_TIMER_RSTRT_CNTR = 6, /* restart RX packet threshold counter */
+ SGE_TIMER_UPD_CIDX = 7, /* update cidx only */
+
+ SGE_EQ_IDXSIZE = 64, /* egress queue pidx/cidx unit size */
+
+ SGE_INTRDST_PCI = 0, /* interrupt destination is PCI-E */
+ SGE_INTRDST_IQ = 1, /* destination is an ingress queue */
+
+ SGE_UPDATEDEL_NONE = 0, /* ingress queue pidx update delivery */
+ SGE_UPDATEDEL_INTR = 1, /* interrupt */
+ SGE_UPDATEDEL_STPG = 2, /* status page */
+ SGE_UPDATEDEL_BOTH = 3, /* interrupt and status page */
+
+ SGE_HOSTFCMODE_NONE = 0, /* egress queue cidx updates */
+ SGE_HOSTFCMODE_IQ = 1, /* sent to ingress queue */
+ SGE_HOSTFCMODE_STPG = 2, /* sent to status page */
+ SGE_HOSTFCMODE_BOTH = 3, /* ingress queue and status page */
+
+ SGE_FETCHBURSTMIN_16B = 0,/* egress queue descriptor fetch minimum */
+ SGE_FETCHBURSTMIN_32B = 1,
+ SGE_FETCHBURSTMIN_64B = 2,
+ SGE_FETCHBURSTMIN_128B = 3,
+
+ SGE_FETCHBURSTMAX_64B = 0,/* egress queue descriptor fetch maximum */
+ SGE_FETCHBURSTMAX_128B = 1,
+ SGE_FETCHBURSTMAX_256B = 2,
+ SGE_FETCHBURSTMAX_512B = 3,
+
+ SGE_CIDXFLUSHTHRESH_1 = 0,/* egress queue cidx flush threshold */
+ SGE_CIDXFLUSHTHRESH_2 = 1,
+ SGE_CIDXFLUSHTHRESH_4 = 2,
+ SGE_CIDXFLUSHTHRESH_8 = 3,
+ SGE_CIDXFLUSHTHRESH_16 = 4,
+ SGE_CIDXFLUSHTHRESH_32 = 5,
+ SGE_CIDXFLUSHTHRESH_64 = 6,
+ SGE_CIDXFLUSHTHRESH_128 = 7,
+
+ SGE_INGPADBOUNDARY_SHIFT = 5,/* ingress queue pad boundary */
};
struct sge_qstat { /* data written to SGE queue status entries */
@@ -90,11 +127,13 @@ struct rsp_ctrl {
};
#define RSPD_NEWBUF 0x80000000U
-#define RSPD_LEN 0x7fffffffU
+#define RSPD_LEN(x) (((x) >> 0) & 0x7fffffffU)
+#define RSPD_QID(x) RSPD_LEN(x)
#define RSPD_GEN(x) ((x) >> 7)
#define RSPD_TYPE(x) (((x) >> 4) & 3)
#define QINTR_CNT_EN 0x1
#define QINTR_TIMER_IDX(x) ((x) << 1)
+#define QINTR_TIMER_IDX_GET(x) (((x) >> 1) & 0x7)
#endif /* __T4_HW_H */
diff --git a/drivers/net/cxgb4/t4_msg.h b/drivers/net/cxgb4/t4_msg.h
index 7a981b81afa..a550d0c706f 100644
--- a/drivers/net/cxgb4/t4_msg.h
+++ b/drivers/net/cxgb4/t4_msg.h
@@ -443,8 +443,7 @@ struct cpl_tx_pkt {
#define cpl_tx_pkt_xt cpl_tx_pkt
-struct cpl_tx_pkt_lso {
- WR_HDR;
+struct cpl_tx_pkt_lso_core {
__be32 lso_ctrl;
#define LSO_TCPHDR_LEN(x) ((x) << 0)
#define LSO_IPHDR_LEN(x) ((x) << 4)
@@ -460,6 +459,12 @@ struct cpl_tx_pkt_lso {
/* encapsulated CPL (TX_PKT, TX_PKT_XT or TX_DATA) follows here */
};
+struct cpl_tx_pkt_lso {
+ WR_HDR;
+ struct cpl_tx_pkt_lso_core c;
+ /* encapsulated CPL (TX_PKT, TX_PKT_XT or TX_DATA) follows here */
+};
+
struct cpl_iscsi_hdr {
union opcode_tid ot;
__be16 pdu_len_ddp;
@@ -524,6 +529,8 @@ struct cpl_rx_pkt {
__be32 l2info;
#define RXF_UDP (1 << 22)
#define RXF_TCP (1 << 23)
+#define RXF_IP (1 << 24)
+#define RXF_IP6 (1 << 25)
__be16 hdr_len;
__be16 err_vec;
};
@@ -623,6 +630,11 @@ struct cpl_fw6_msg {
__be64 data[4];
};
+/* cpl_fw6_msg.type values */
+enum {
+ FW6_TYPE_CMD_RPL = 0,
+};
+
enum {
ULP_TX_MEM_READ = 2,
ULP_TX_MEM_WRITE = 3,
diff --git a/drivers/net/cxgb4/t4_regs.h b/drivers/net/cxgb4/t4_regs.h
index 5ed56483cbc..0adc5bcec7c 100644
--- a/drivers/net/cxgb4/t4_regs.h
+++ b/drivers/net/cxgb4/t4_regs.h
@@ -93,12 +93,15 @@
#define PKTSHIFT_MASK 0x00001c00U
#define PKTSHIFT_SHIFT 10
#define PKTSHIFT(x) ((x) << PKTSHIFT_SHIFT)
+#define PKTSHIFT_GET(x) (((x) & PKTSHIFT_MASK) >> PKTSHIFT_SHIFT)
#define INGPCIEBOUNDARY_MASK 0x00000380U
#define INGPCIEBOUNDARY_SHIFT 7
#define INGPCIEBOUNDARY(x) ((x) << INGPCIEBOUNDARY_SHIFT)
#define INGPADBOUNDARY_MASK 0x00000070U
#define INGPADBOUNDARY_SHIFT 4
#define INGPADBOUNDARY(x) ((x) << INGPADBOUNDARY_SHIFT)
+#define INGPADBOUNDARY_GET(x) (((x) & INGPADBOUNDARY_MASK) \
+ >> INGPADBOUNDARY_SHIFT)
#define EGRPCIEBOUNDARY_MASK 0x0000000eU
#define EGRPCIEBOUNDARY_SHIFT 1
#define EGRPCIEBOUNDARY(x) ((x) << EGRPCIEBOUNDARY_SHIFT)
@@ -229,6 +232,7 @@
#define WINDOW_MASK 0x000000ffU
#define WINDOW_SHIFT 0
#define WINDOW(x) ((x) << WINDOW_SHIFT)
+#define PCIE_MEM_ACCESS_OFFSET 0x306c
#define PCIE_CORE_UTL_SYSTEM_BUS_AGENT_STATUS 0x5908
#define RNPP 0x80000000U
@@ -326,6 +330,9 @@
#define EDC_1_BASE_ADDR 0x7980
+#define CIM_BOOT_CFG 0x7b00
+#define BOOTADDR_MASK 0xffffff00U
+
#define CIM_PF_MAILBOX_DATA 0x240
#define CIM_PF_MAILBOX_CTRL 0x280
#define MBMSGVALID 0x00000008U
diff --git a/drivers/net/cxgb4/t4fw_api.h b/drivers/net/cxgb4/t4fw_api.h
index 63991d68950..0969f2fbc1b 100644
--- a/drivers/net/cxgb4/t4fw_api.h
+++ b/drivers/net/cxgb4/t4fw_api.h
@@ -71,6 +71,7 @@ struct fw_wr_hdr {
#define FW_WR_ATOMIC(x) ((x) << 23)
#define FW_WR_FLUSH(x) ((x) << 22)
#define FW_WR_COMPL(x) ((x) << 21)
+#define FW_WR_IMMDLEN_MASK 0xff
#define FW_WR_IMMDLEN(x) ((x) << 0)
#define FW_WR_EQUIQ (1U << 31)
@@ -447,7 +448,9 @@ enum fw_params_param_dev {
FW_PARAMS_PARAM_DEV_INTVER_RI = 0x07,
FW_PARAMS_PARAM_DEV_INTVER_ISCSIPDU = 0x08,
FW_PARAMS_PARAM_DEV_INTVER_ISCSI = 0x09,
- FW_PARAMS_PARAM_DEV_INTVER_FCOE = 0x0A
+ FW_PARAMS_PARAM_DEV_INTVER_FCOE = 0x0A,
+ FW_PARAMS_PARAM_DEV_FWREV = 0x0B,
+ FW_PARAMS_PARAM_DEV_TPREV = 0x0C,
};
/*
@@ -475,7 +478,15 @@ enum fw_params_param_pfvf {
FW_PARAMS_PARAM_PFVF_PBL_END = 0x12,
FW_PARAMS_PARAM_PFVF_L2T_START = 0x13,
FW_PARAMS_PARAM_PFVF_L2T_END = 0x14,
+ FW_PARAMS_PARAM_PFVF_SQRQ_START = 0x15,
+ FW_PARAMS_PARAM_PFVF_SQRQ_END = 0x16,
+ FW_PARAMS_PARAM_PFVF_CQ_START = 0x17,
+ FW_PARAMS_PARAM_PFVF_CQ_END = 0x18,
FW_PARAMS_PARAM_PFVF_SCHEDCLASS_ETH = 0x20,
+ FW_PARAMS_PARAM_PFVF_VIID = 0x24,
+ FW_PARAMS_PARAM_PFVF_CPMASK = 0x25,
+ FW_PARAMS_PARAM_PFVF_OCQ_START = 0x26,
+ FW_PARAMS_PARAM_PFVF_OCQ_END = 0x27,
};
/*
@@ -512,7 +523,7 @@ struct fw_pfvf_cmd {
__be32 op_to_vfn;
__be32 retval_len16;
__be32 niqflint_niq;
- __be32 cmask_to_neq;
+ __be32 type_to_neq;
__be32 tc_to_nexactf;
__be32 r_caps_to_nethctrl;
__be16 nricq;
@@ -529,11 +540,16 @@ struct fw_pfvf_cmd {
#define FW_PFVF_CMD_NIQ(x) ((x) << 0)
#define FW_PFVF_CMD_NIQ_GET(x) (((x) >> 0) & 0xfffff)
+#define FW_PFVF_CMD_TYPE (1 << 31)
+#define FW_PFVF_CMD_TYPE_GET(x) (((x) >> 31) & 0x1)
+
#define FW_PFVF_CMD_CMASK(x) ((x) << 24)
-#define FW_PFVF_CMD_CMASK_GET(x) (((x) >> 24) & 0xf)
+#define FW_PFVF_CMD_CMASK_MASK 0xf
+#define FW_PFVF_CMD_CMASK_GET(x) (((x) >> 24) & FW_PFVF_CMD_CMASK_MASK)
#define FW_PFVF_CMD_PMASK(x) ((x) << 20)
-#define FW_PFVF_CMD_PMASK_GET(x) (((x) >> 20) & 0xf)
+#define FW_PFVF_CMD_PMASK_MASK 0xf
+#define FW_PFVF_CMD_PMASK_GET(x) (((x) >> 20) & FW_PFVF_CMD_PMASK_MASK)
#define FW_PFVF_CMD_NEQ(x) ((x) << 0)
#define FW_PFVF_CMD_NEQ_GET(x) (((x) >> 0) & 0xfffff)
@@ -686,6 +702,7 @@ struct fw_eq_eth_cmd {
#define FW_EQ_ETH_CMD_EQID(x) ((x) << 0)
#define FW_EQ_ETH_CMD_EQID_GET(x) (((x) >> 0) & 0xfffff)
#define FW_EQ_ETH_CMD_PHYSEQID(x) ((x) << 0)
+#define FW_EQ_ETH_CMD_PHYSEQID_GET(x) (((x) >> 0) & 0xfffff)
#define FW_EQ_ETH_CMD_FETCHSZM(x) ((x) << 26)
#define FW_EQ_ETH_CMD_STATUSPGNS(x) ((x) << 25)
@@ -804,16 +821,16 @@ struct fw_eq_ofld_cmd {
struct fw_vi_cmd {
__be32 op_to_vfn;
__be32 alloc_to_len16;
- __be16 viid_pkd;
+ __be16 type_viid;
u8 mac[6];
u8 portid_pkd;
u8 nmac;
u8 nmac0[6];
__be16 rsssize_pkd;
u8 nmac1[6];
- __be16 r7;
+ __be16 idsiiq_pkd;
u8 nmac2[6];
- __be16 r8;
+ __be16 idseiq_pkd;
u8 nmac3[6];
__be64 r9;
__be64 r10;
@@ -824,13 +841,16 @@ struct fw_vi_cmd {
#define FW_VI_CMD_ALLOC (1U << 31)
#define FW_VI_CMD_FREE (1U << 30)
#define FW_VI_CMD_VIID(x) ((x) << 0)
+#define FW_VI_CMD_VIID_GET(x) ((x) & 0xfff)
#define FW_VI_CMD_PORTID(x) ((x) << 4)
+#define FW_VI_CMD_PORTID_GET(x) (((x) >> 4) & 0xf)
#define FW_VI_CMD_RSSSIZE_GET(x) (((x) >> 0) & 0x7ff)
/* Special VI_MAC command index ids */
#define FW_VI_MAC_ADD_MAC 0x3FF
#define FW_VI_MAC_ADD_PERSIST_MAC 0x3FE
#define FW_VI_MAC_MAC_BASED_FREE 0x3FD
+#define FW_CLS_TCAM_NUM_ENTRIES 336
enum fw_vi_mac_smac {
FW_VI_MAC_MPS_TCAM_ENTRY,
@@ -881,6 +901,7 @@ struct fw_vi_rxmode_cmd {
};
#define FW_VI_RXMODE_CMD_VIID(x) ((x) << 0)
+#define FW_VI_RXMODE_CMD_MTU_MASK 0xffff
#define FW_VI_RXMODE_CMD_MTU(x) ((x) << 16)
#define FW_VI_RXMODE_CMD_PROMISCEN_MASK 0x3
#define FW_VI_RXMODE_CMD_PROMISCEN(x) ((x) << 14)
@@ -1136,6 +1157,11 @@ struct fw_port_cmd {
__be32 lstatus_to_modtype;
__be16 pcap;
__be16 acap;
+ __be16 mtu;
+ __u8 cbllen;
+ __u8 r9;
+ __be32 r10;
+ __be64 r11;
} info;
struct fw_port_ppp {
__be32 pppen_to_ncsich;
@@ -1161,6 +1187,7 @@ struct fw_port_cmd {
#define FW_PORT_CMD_PORTID_GET(x) (((x) >> 0) & 0xf)
#define FW_PORT_CMD_ACTION(x) ((x) << 16)
+#define FW_PORT_CMD_ACTION_GET(x) (((x) >> 16) & 0xffff)
#define FW_PORT_CMD_CTLBF(x) ((x) << 10)
#define FW_PORT_CMD_OVLAN3(x) ((x) << 7)
@@ -1196,14 +1223,17 @@ struct fw_port_cmd {
#define FW_PORT_CMD_NCSICH(x) ((x) << 4)
enum fw_port_type {
- FW_PORT_TYPE_FIBER,
- FW_PORT_TYPE_KX4,
+ FW_PORT_TYPE_FIBER_XFI,
+ FW_PORT_TYPE_FIBER_XAUI,
FW_PORT_TYPE_BT_SGMII,
- FW_PORT_TYPE_KX,
+ FW_PORT_TYPE_BT_XFI,
FW_PORT_TYPE_BT_XAUI,
- FW_PORT_TYPE_KR,
+ FW_PORT_TYPE_KX4,
FW_PORT_TYPE_CX4,
- FW_PORT_TYPE_TWINAX,
+ FW_PORT_TYPE_KX,
+ FW_PORT_TYPE_KR,
+ FW_PORT_TYPE_SFP,
+ FW_PORT_TYPE_BP_AP,
FW_PORT_TYPE_NONE = FW_PORT_CMD_PTYPE_MASK
};
@@ -1213,6 +1243,9 @@ enum fw_port_module_type {
FW_PORT_MOD_TYPE_LR,
FW_PORT_MOD_TYPE_SR,
FW_PORT_MOD_TYPE_ER,
+ FW_PORT_MOD_TYPE_TWINAX_PASSIVE,
+ FW_PORT_MOD_TYPE_TWINAX_ACTIVE,
+ FW_PORT_MOD_TYPE_LRM,
FW_PORT_MOD_TYPE_NONE = FW_PORT_CMD_MODTYPE_MASK
};
@@ -1469,6 +1502,7 @@ struct fw_rss_glb_config_cmd {
};
#define FW_RSS_GLB_CONFIG_CMD_MODE(x) ((x) << 28)
+#define FW_RSS_GLB_CONFIG_CMD_MODE_GET(x) (((x) >> 28) & 0xf)
#define FW_RSS_GLB_CONFIG_CMD_MODE_MANUAL 0
#define FW_RSS_GLB_CONFIG_CMD_MODE_BASICVIRTUAL 1
@@ -1485,13 +1519,14 @@ struct fw_rss_vi_config_cmd {
} manual;
struct fw_rss_vi_config_basicvirtual {
__be32 r6;
- __be32 defaultq_to_ip4udpen;
+ __be32 defaultq_to_udpen;
#define FW_RSS_VI_CONFIG_CMD_DEFAULTQ(x) ((x) << 16)
+#define FW_RSS_VI_CONFIG_CMD_DEFAULTQ_GET(x) (((x) >> 16) & 0x3ff)
#define FW_RSS_VI_CONFIG_CMD_IP6FOURTUPEN (1U << 4)
#define FW_RSS_VI_CONFIG_CMD_IP6TWOTUPEN (1U << 3)
#define FW_RSS_VI_CONFIG_CMD_IP4FOURTUPEN (1U << 2)
#define FW_RSS_VI_CONFIG_CMD_IP4TWOTUPEN (1U << 1)
-#define FW_RSS_VI_CONFIG_CMD_IP4UDPEN (1U << 0)
+#define FW_RSS_VI_CONFIG_CMD_UDPEN (1U << 0)
__be64 r9;
__be64 r10;
} basicvirtual;
diff --git a/drivers/net/cxgb4vf/Makefile b/drivers/net/cxgb4vf/Makefile
new file mode 100644
index 00000000000..d72ee26cb4c
--- /dev/null
+++ b/drivers/net/cxgb4vf/Makefile
@@ -0,0 +1,7 @@
+#
+# Chelsio T4 SR-IOV Virtual Function Driver
+#
+
+obj-$(CONFIG_CHELSIO_T4VF) += cxgb4vf.o
+
+cxgb4vf-objs := cxgb4vf_main.o t4vf_hw.o sge.o
diff --git a/drivers/net/cxgb4vf/adapter.h b/drivers/net/cxgb4vf/adapter.h
new file mode 100644
index 00000000000..8ea01962e04
--- /dev/null
+++ b/drivers/net/cxgb4vf/adapter.h
@@ -0,0 +1,540 @@
+/*
+ * This file is part of the Chelsio T4 PCI-E SR-IOV Virtual Function Ethernet
+ * driver for Linux.
+ *
+ * Copyright (c) 2009-2010 Chelsio Communications, 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.
+ */
+
+/*
+ * This file should not be included directly. Include t4vf_common.h instead.
+ */
+
+#ifndef __CXGB4VF_ADAPTER_H__
+#define __CXGB4VF_ADAPTER_H__
+
+#include <linux/pci.h>
+#include <linux/spinlock.h>
+#include <linux/skbuff.h>
+#include <linux/if_ether.h>
+#include <linux/netdevice.h>
+
+#include "../cxgb4/t4_hw.h"
+
+/*
+ * Constants of the implementation.
+ */
+enum {
+ MAX_NPORTS = 1, /* max # of "ports" */
+ MAX_PORT_QSETS = 8, /* max # of Queue Sets / "port" */
+ MAX_ETH_QSETS = MAX_NPORTS*MAX_PORT_QSETS,
+
+ /*
+ * MSI-X interrupt index usage.
+ */
+ MSIX_FW = 0, /* MSI-X index for firmware Q */
+ MSIX_NIQFLINT = 1, /* MSI-X index base for Ingress Qs */
+ MSIX_EXTRAS = 1,
+ MSIX_ENTRIES = MAX_ETH_QSETS + MSIX_EXTRAS,
+
+ /*
+ * The maximum number of Ingress and Egress Queues is determined by
+ * the maximum number of "Queue Sets" which we support plus any
+ * ancillary queues. Each "Queue Set" requires one Ingress Queue
+ * for RX Packet Ingress Event notifications and two Egress Queues for
+ * a Free List and an Ethernet TX list.
+ */
+ INGQ_EXTRAS = 2, /* firmware event queue and */
+ /* forwarded interrupts */
+ MAX_INGQ = MAX_ETH_QSETS+INGQ_EXTRAS,
+ MAX_EGRQ = MAX_ETH_QSETS*2,
+};
+
+/*
+ * Forward structure definition references.
+ */
+struct adapter;
+struct sge_eth_rxq;
+struct sge_rspq;
+
+/*
+ * Per-"port" information. This is really per-Virtual Interface information
+ * but the use of the "port" nomanclature makes it easier to go back and forth
+ * between the PF and VF drivers ...
+ */
+struct port_info {
+ struct adapter *adapter; /* our adapter */
+ struct vlan_group *vlan_grp; /* out VLAN group */
+ u16 viid; /* virtual interface ID */
+ s16 xact_addr_filt; /* index of our MAC address filter */
+ u16 rss_size; /* size of VI's RSS table slice */
+ u8 pidx; /* index into adapter port[] */
+ u8 port_id; /* physical port ID */
+ u8 rx_offload; /* CSO, etc. */
+ u8 nqsets; /* # of "Queue Sets" */
+ u8 first_qset; /* index of first "Queue Set" */
+ struct link_config link_cfg; /* physical port configuration */
+};
+
+/* port_info.rx_offload flags */
+enum {
+ RX_CSO = 1 << 0,
+};
+
+/*
+ * Scatter Gather Engine resources for the "adapter". Our ingress and egress
+ * queues are organized into "Queue Sets" with one ingress and one egress
+ * queue per Queue Set. These Queue Sets are aportionable between the "ports"
+ * (Virtual Interfaces). One extra ingress queue is used to receive
+ * asynchronous messages from the firmware. Note that the "Queue IDs" that we
+ * use here are really "Relative Queue IDs" which are returned as part of the
+ * firmware command to allocate queues. These queue IDs are relative to the
+ * absolute Queue ID base of the section of the Queue ID space allocated to
+ * the PF/VF.
+ */
+
+/*
+ * SGE free-list queue state.
+ */
+struct rx_sw_desc;
+struct sge_fl {
+ unsigned int avail; /* # of available RX buffers */
+ unsigned int pend_cred; /* new buffers since last FL DB ring */
+ unsigned int cidx; /* consumer index */
+ unsigned int pidx; /* producer index */
+ unsigned long alloc_failed; /* # of buffer allocation failures */
+ unsigned long large_alloc_failed;
+ unsigned long starving; /* # of times FL was found starving */
+
+ /*
+ * Write-once/infrequently fields.
+ * -------------------------------
+ */
+
+ unsigned int cntxt_id; /* SGE relative QID for the free list */
+ unsigned int abs_id; /* SGE absolute QID for the free list */
+ unsigned int size; /* capacity of free list */
+ struct rx_sw_desc *sdesc; /* address of SW RX descriptor ring */
+ __be64 *desc; /* address of HW RX descriptor ring */
+ dma_addr_t addr; /* PCI bus address of hardware ring */
+};
+
+/*
+ * An ingress packet gather list.
+ */
+struct pkt_gl {
+ skb_frag_t frags[MAX_SKB_FRAGS];
+ void *va; /* virtual address of first byte */
+ unsigned int nfrags; /* # of fragments */
+ unsigned int tot_len; /* total length of fragments */
+};
+
+typedef int (*rspq_handler_t)(struct sge_rspq *, const __be64 *,
+ const struct pkt_gl *);
+
+/*
+ * State for an SGE Response Queue.
+ */
+struct sge_rspq {
+ struct napi_struct napi; /* NAPI scheduling control */
+ const __be64 *cur_desc; /* current descriptor in queue */
+ unsigned int cidx; /* consumer index */
+ u8 gen; /* current generation bit */
+ u8 next_intr_params; /* holdoff params for next interrupt */
+ int offset; /* offset into current FL buffer */
+
+ unsigned int unhandled_irqs; /* bogus interrupts */
+
+ /*
+ * Write-once/infrequently fields.
+ * -------------------------------
+ */
+
+ u8 intr_params; /* interrupt holdoff parameters */
+ u8 pktcnt_idx; /* interrupt packet threshold */
+ u8 idx; /* queue index within its group */
+ u16 cntxt_id; /* SGE rel QID for the response Q */
+ u16 abs_id; /* SGE abs QID for the response Q */
+ __be64 *desc; /* address of hardware response ring */
+ dma_addr_t phys_addr; /* PCI bus address of ring */
+ unsigned int iqe_len; /* entry size */
+ unsigned int size; /* capcity of response Q */
+ struct adapter *adapter; /* our adapter */
+ struct net_device *netdev; /* associated net device */
+ rspq_handler_t handler; /* the handler for this response Q */
+};
+
+/*
+ * Ethernet queue statistics
+ */
+struct sge_eth_stats {
+ unsigned long pkts; /* # of ethernet packets */
+ unsigned long lro_pkts; /* # of LRO super packets */
+ unsigned long lro_merged; /* # of wire packets merged by LRO */
+ unsigned long rx_cso; /* # of Rx checksum offloads */
+ unsigned long vlan_ex; /* # of Rx VLAN extractions */
+ unsigned long rx_drops; /* # of packets dropped due to no mem */
+};
+
+/*
+ * State for an Ethernet Receive Queue.
+ */
+struct sge_eth_rxq {
+ struct sge_rspq rspq; /* Response Queue */
+ struct sge_fl fl; /* Free List */
+ struct sge_eth_stats stats; /* receive statistics */
+};
+
+/*
+ * SGE Transmit Queue state. This contains all of the resources associated
+ * with the hardware status of a TX Queue which is a circular ring of hardware
+ * TX Descriptors. For convenience, it also contains a pointer to a parallel
+ * "Software Descriptor" array but we don't know anything about it here other
+ * than its type name.
+ */
+struct tx_desc {
+ /*
+ * Egress Queues are measured in units of SGE_EQ_IDXSIZE by the
+ * hardware: Sizes, Producer and Consumer indices, etc.
+ */
+ __be64 flit[SGE_EQ_IDXSIZE/sizeof(__be64)];
+};
+struct tx_sw_desc;
+struct sge_txq {
+ unsigned int in_use; /* # of in-use TX descriptors */
+ unsigned int size; /* # of descriptors */
+ unsigned int cidx; /* SW consumer index */
+ unsigned int pidx; /* producer index */
+ unsigned long stops; /* # of times queue has been stopped */
+ unsigned long restarts; /* # of queue restarts */
+
+ /*
+ * Write-once/infrequently fields.
+ * -------------------------------
+ */
+
+ unsigned int cntxt_id; /* SGE relative QID for the TX Q */
+ unsigned int abs_id; /* SGE absolute QID for the TX Q */
+ struct tx_desc *desc; /* address of HW TX descriptor ring */
+ struct tx_sw_desc *sdesc; /* address of SW TX descriptor ring */
+ struct sge_qstat *stat; /* queue status entry */
+ dma_addr_t phys_addr; /* PCI bus address of hardware ring */
+};
+
+/*
+ * State for an Ethernet Transmit Queue.
+ */
+struct sge_eth_txq {
+ struct sge_txq q; /* SGE TX Queue */
+ struct netdev_queue *txq; /* associated netdev TX queue */
+ unsigned long tso; /* # of TSO requests */
+ unsigned long tx_cso; /* # of TX checksum offloads */
+ unsigned long vlan_ins; /* # of TX VLAN insertions */
+ unsigned long mapping_err; /* # of I/O MMU packet mapping errors */
+};
+
+/*
+ * The complete set of Scatter/Gather Engine resources.
+ */
+struct sge {
+ /*
+ * Our "Queue Sets" ...
+ */
+ struct sge_eth_txq ethtxq[MAX_ETH_QSETS];
+ struct sge_eth_rxq ethrxq[MAX_ETH_QSETS];
+
+ /*
+ * Extra ingress queues for asynchronous firmware events and
+ * forwarded interrupts (when in MSI mode).
+ */
+ struct sge_rspq fw_evtq ____cacheline_aligned_in_smp;
+
+ struct sge_rspq intrq ____cacheline_aligned_in_smp;
+ spinlock_t intrq_lock;
+
+ /*
+ * State for managing "starving Free Lists" -- Free Lists which have
+ * fallen below a certain threshold of buffers available to the
+ * hardware and attempts to refill them up to that threshold have
+ * failed. We have a regular "slow tick" timer process which will
+ * make periodic attempts to refill these starving Free Lists ...
+ */
+ DECLARE_BITMAP(starving_fl, MAX_EGRQ);
+ struct timer_list rx_timer;
+
+ /*
+ * State for cleaning up completed TX descriptors.
+ */
+ struct timer_list tx_timer;
+
+ /*
+ * Write-once/infrequently fields.
+ * -------------------------------
+ */
+
+ u16 max_ethqsets; /* # of available Ethernet queue sets */
+ u16 ethqsets; /* # of active Ethernet queue sets */
+ u16 ethtxq_rover; /* Tx queue to clean up next */
+ u16 timer_val[SGE_NTIMERS]; /* interrupt holdoff timer array */
+ u8 counter_val[SGE_NCOUNTERS]; /* interrupt RX threshold array */
+
+ /*
+ * Reverse maps from Absolute Queue IDs to associated queue pointers.
+ * The absolute Queue IDs are in a compact range which start at a
+ * [potentially large] Base Queue ID. We perform the reverse map by
+ * first converting the Absolute Queue ID into a Relative Queue ID by
+ * subtracting off the Base Queue ID and then use a Relative Queue ID
+ * indexed table to get the pointer to the corresponding software
+ * queue structure.
+ */
+ unsigned int egr_base;
+ unsigned int ingr_base;
+ void *egr_map[MAX_EGRQ];
+ struct sge_rspq *ingr_map[MAX_INGQ];
+};
+
+/*
+ * Utility macros to convert Absolute- to Relative-Queue indices and Egress-
+ * and Ingress-Queues. The EQ_MAP() and IQ_MAP() macros which provide
+ * pointers to Ingress- and Egress-Queues can be used as both L- and R-values
+ */
+#define EQ_IDX(s, abs_id) ((unsigned int)((abs_id) - (s)->egr_base))
+#define IQ_IDX(s, abs_id) ((unsigned int)((abs_id) - (s)->ingr_base))
+
+#define EQ_MAP(s, abs_id) ((s)->egr_map[EQ_IDX(s, abs_id)])
+#define IQ_MAP(s, abs_id) ((s)->ingr_map[IQ_IDX(s, abs_id)])
+
+/*
+ * Macro to iterate across Queue Sets ("rxq" is a historic misnomer).
+ */
+#define for_each_ethrxq(sge, iter) \
+ for (iter = 0; iter < (sge)->ethqsets; iter++)
+
+/*
+ * Per-"adapter" (Virtual Function) information.
+ */
+struct adapter {
+ /* PCI resources */
+ void __iomem *regs;
+ struct pci_dev *pdev;
+ struct device *pdev_dev;
+
+ /* "adapter" resources */
+ unsigned long registered_device_map;
+ unsigned long open_device_map;
+ unsigned long flags;
+ struct adapter_params params;
+
+ /* queue and interrupt resources */
+ struct {
+ unsigned short vec;
+ char desc[22];
+ } msix_info[MSIX_ENTRIES];
+ struct sge sge;
+
+ /* Linux network device resources */
+ struct net_device *port[MAX_NPORTS];
+ const char *name;
+ unsigned int msg_enable;
+
+ /* debugfs resources */
+ struct dentry *debugfs_root;
+
+ /* various locks */
+ spinlock_t stats_lock;
+};
+
+enum { /* adapter flags */
+ FULL_INIT_DONE = (1UL << 0),
+ USING_MSI = (1UL << 1),
+ USING_MSIX = (1UL << 2),
+ QUEUES_BOUND = (1UL << 3),
+};
+
+/*
+ * The following register read/write routine definitions are required by
+ * the common code.
+ */
+
+/**
+ * t4_read_reg - read a HW register
+ * @adapter: the adapter
+ * @reg_addr: the register address
+ *
+ * Returns the 32-bit value of the given HW register.
+ */
+static inline u32 t4_read_reg(struct adapter *adapter, u32 reg_addr)
+{
+ return readl(adapter->regs + reg_addr);
+}
+
+/**
+ * t4_write_reg - write a HW register
+ * @adapter: the adapter
+ * @reg_addr: the register address
+ * @val: the value to write
+ *
+ * Write a 32-bit value into the given HW register.
+ */
+static inline void t4_write_reg(struct adapter *adapter, u32 reg_addr, u32 val)
+{
+ writel(val, adapter->regs + reg_addr);
+}
+
+#ifndef readq
+static inline u64 readq(const volatile void __iomem *addr)
+{
+ return readl(addr) + ((u64)readl(addr + 4) << 32);
+}
+
+static inline void writeq(u64 val, volatile void __iomem *addr)
+{
+ writel(val, addr);
+ writel(val >> 32, addr + 4);
+}
+#endif
+
+/**
+ * t4_read_reg64 - read a 64-bit HW register
+ * @adapter: the adapter
+ * @reg_addr: the register address
+ *
+ * Returns the 64-bit value of the given HW register.
+ */
+static inline u64 t4_read_reg64(struct adapter *adapter, u32 reg_addr)
+{
+ return readq(adapter->regs + reg_addr);
+}
+
+/**
+ * t4_write_reg64 - write a 64-bit HW register
+ * @adapter: the adapter
+ * @reg_addr: the register address
+ * @val: the value to write
+ *
+ * Write a 64-bit value into the given HW register.
+ */
+static inline void t4_write_reg64(struct adapter *adapter, u32 reg_addr,
+ u64 val)
+{
+ writeq(val, adapter->regs + reg_addr);
+}
+
+/**
+ * port_name - return the string name of a port
+ * @adapter: the adapter
+ * @pidx: the port index
+ *
+ * Return the string name of the selected port.
+ */
+static inline const char *port_name(struct adapter *adapter, int pidx)
+{
+ return adapter->port[pidx]->name;
+}
+
+/**
+ * t4_os_set_hw_addr - store a port's MAC address in SW
+ * @adapter: the adapter
+ * @pidx: the port index
+ * @hw_addr: the Ethernet address
+ *
+ * Store the Ethernet address of the given port in SW. Called by the common
+ * code when it retrieves a port's Ethernet address from EEPROM.
+ */
+static inline void t4_os_set_hw_addr(struct adapter *adapter, int pidx,
+ u8 hw_addr[])
+{
+ memcpy(adapter->port[pidx]->dev_addr, hw_addr, ETH_ALEN);
+ memcpy(adapter->port[pidx]->perm_addr, hw_addr, ETH_ALEN);
+}
+
+/**
+ * netdev2pinfo - return the port_info structure associated with a net_device
+ * @dev: the netdev
+ *
+ * Return the struct port_info associated with a net_device
+ */
+static inline struct port_info *netdev2pinfo(const struct net_device *dev)
+{
+ return netdev_priv(dev);
+}
+
+/**
+ * adap2pinfo - return the port_info of a port
+ * @adap: the adapter
+ * @pidx: the port index
+ *
+ * Return the port_info structure for the adapter.
+ */
+static inline struct port_info *adap2pinfo(struct adapter *adapter, int pidx)
+{
+ return netdev_priv(adapter->port[pidx]);
+}
+
+/**
+ * netdev2adap - return the adapter structure associated with a net_device
+ * @dev: the netdev
+ *
+ * Return the struct adapter associated with a net_device
+ */
+static inline struct adapter *netdev2adap(const struct net_device *dev)
+{
+ return netdev2pinfo(dev)->adapter;
+}
+
+/*
+ * OS "Callback" function declarations. These are functions that the OS code
+ * is "contracted" to provide for the common code.
+ */
+void t4vf_os_link_changed(struct adapter *, int, int);
+
+/*
+ * SGE function prototype declarations.
+ */
+int t4vf_sge_alloc_rxq(struct adapter *, struct sge_rspq *, bool,
+ struct net_device *, int,
+ struct sge_fl *, rspq_handler_t);
+int t4vf_sge_alloc_eth_txq(struct adapter *, struct sge_eth_txq *,
+ struct net_device *, struct netdev_queue *,
+ unsigned int);
+void t4vf_free_sge_resources(struct adapter *);
+
+int t4vf_eth_xmit(struct sk_buff *, struct net_device *);
+int t4vf_ethrx_handler(struct sge_rspq *, const __be64 *,
+ const struct pkt_gl *);
+
+irq_handler_t t4vf_intr_handler(struct adapter *);
+irqreturn_t t4vf_sge_intr_msix(int, void *);
+
+int t4vf_sge_init(struct adapter *);
+void t4vf_sge_start(struct adapter *);
+void t4vf_sge_stop(struct adapter *);
+
+#endif /* __CXGB4VF_ADAPTER_H__ */
diff --git a/drivers/net/cxgb4vf/cxgb4vf_main.c b/drivers/net/cxgb4vf/cxgb4vf_main.c
new file mode 100644
index 00000000000..a16563219ac
--- /dev/null
+++ b/drivers/net/cxgb4vf/cxgb4vf_main.c
@@ -0,0 +1,2888 @@
+/*
+ * This file is part of the Chelsio T4 PCI-E SR-IOV Virtual Function Ethernet
+ * driver for Linux.
+ *
+ * Copyright (c) 2009-2010 Chelsio Communications, 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.
+ */
+
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/dma-mapping.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/debugfs.h>
+#include <linux/ethtool.h>
+
+#include "t4vf_common.h"
+#include "t4vf_defs.h"
+
+#include "../cxgb4/t4_regs.h"
+#include "../cxgb4/t4_msg.h"
+
+/*
+ * Generic information about the driver.
+ */
+#define DRV_VERSION "1.0.0"
+#define DRV_DESC "Chelsio T4 Virtual Function (VF) Network Driver"
+
+/*
+ * Module Parameters.
+ * ==================
+ */
+
+/*
+ * Default ethtool "message level" for adapters.
+ */
+#define DFLT_MSG_ENABLE (NETIF_MSG_DRV | NETIF_MSG_PROBE | NETIF_MSG_LINK | \
+ NETIF_MSG_TIMER | NETIF_MSG_IFDOWN | NETIF_MSG_IFUP |\
+ NETIF_MSG_RX_ERR | NETIF_MSG_TX_ERR)
+
+static int dflt_msg_enable = DFLT_MSG_ENABLE;
+
+module_param(dflt_msg_enable, int, 0644);
+MODULE_PARM_DESC(dflt_msg_enable,
+ "default adapter ethtool message level bitmap");
+
+/*
+ * The driver uses the best interrupt scheme available on a platform in the
+ * order MSI-X then MSI. This parameter determines which of these schemes the
+ * driver may consider as follows:
+ *
+ * msi = 2: choose from among MSI-X and MSI
+ * msi = 1: only consider MSI interrupts
+ *
+ * Note that unlike the Physical Function driver, this Virtual Function driver
+ * does _not_ support legacy INTx interrupts (this limitation is mandated by
+ * the PCI-E SR-IOV standard).
+ */
+#define MSI_MSIX 2
+#define MSI_MSI 1
+#define MSI_DEFAULT MSI_MSIX
+
+static int msi = MSI_DEFAULT;
+
+module_param(msi, int, 0644);
+MODULE_PARM_DESC(msi, "whether to use MSI-X or MSI");
+
+/*
+ * Fundamental constants.
+ * ======================
+ */
+
+enum {
+ MAX_TXQ_ENTRIES = 16384,
+ MAX_RSPQ_ENTRIES = 16384,
+ MAX_RX_BUFFERS = 16384,
+
+ MIN_TXQ_ENTRIES = 32,
+ MIN_RSPQ_ENTRIES = 128,
+ MIN_FL_ENTRIES = 16,
+
+ /*
+ * For purposes of manipulating the Free List size we need to
+ * recognize that Free Lists are actually Egress Queues (the host
+ * produces free buffers which the hardware consumes), Egress Queues
+ * indices are all in units of Egress Context Units bytes, and free
+ * list entries are 64-bit PCI DMA addresses. And since the state of
+ * the Producer Index == the Consumer Index implies an EMPTY list, we
+ * always have at least one Egress Unit's worth of Free List entries
+ * unused. See sge.c for more details ...
+ */
+ EQ_UNIT = SGE_EQ_IDXSIZE,
+ FL_PER_EQ_UNIT = EQ_UNIT / sizeof(__be64),
+ MIN_FL_RESID = FL_PER_EQ_UNIT,
+};
+
+/*
+ * Global driver state.
+ * ====================
+ */
+
+static struct dentry *cxgb4vf_debugfs_root;
+
+/*
+ * OS "Callback" functions.
+ * ========================
+ */
+
+/*
+ * The link status has changed on the indicated "port" (Virtual Interface).
+ */
+void t4vf_os_link_changed(struct adapter *adapter, int pidx, int link_ok)
+{
+ struct net_device *dev = adapter->port[pidx];
+
+ /*
+ * If the port is disabled or the current recorded "link up"
+ * status matches the new status, just return.
+ */
+ if (!netif_running(dev) || link_ok == netif_carrier_ok(dev))
+ return;
+
+ /*
+ * Tell the OS that the link status has changed and print a short
+ * informative message on the console about the event.
+ */
+ if (link_ok) {
+ const char *s;
+ const char *fc;
+ const struct port_info *pi = netdev_priv(dev);
+
+ netif_carrier_on(dev);
+
+ switch (pi->link_cfg.speed) {
+ case SPEED_10000:
+ s = "10Gbps";
+ break;
+
+ case SPEED_1000:
+ s = "1000Mbps";
+ break;
+
+ case SPEED_100:
+ s = "100Mbps";
+ break;
+
+ default:
+ s = "unknown";
+ break;
+ }
+
+ switch (pi->link_cfg.fc) {
+ case PAUSE_RX:
+ fc = "RX";
+ break;
+
+ case PAUSE_TX:
+ fc = "TX";
+ break;
+
+ case PAUSE_RX|PAUSE_TX:
+ fc = "RX/TX";
+ break;
+
+ default:
+ fc = "no";
+ break;
+ }
+
+ printk(KERN_INFO "%s: link up, %s, full-duplex, %s PAUSE\n",
+ dev->name, s, fc);
+ } else {
+ netif_carrier_off(dev);
+ printk(KERN_INFO "%s: link down\n", dev->name);
+ }
+}
+
+/*
+ * Net device operations.
+ * ======================
+ */
+
+/*
+ * Record our new VLAN Group and enable/disable hardware VLAN Tag extraction
+ * based on whether the specified VLAN Group pointer is NULL or not.
+ */
+static void cxgb4vf_vlan_rx_register(struct net_device *dev,
+ struct vlan_group *grp)
+{
+ struct port_info *pi = netdev_priv(dev);
+
+ pi->vlan_grp = grp;
+ t4vf_set_rxmode(pi->adapter, pi->viid, -1, -1, -1, -1, grp != NULL, 0);
+}
+
+/*
+ * Perform the MAC and PHY actions needed to enable a "port" (Virtual
+ * Interface).
+ */
+static int link_start(struct net_device *dev)
+{
+ int ret;
+ struct port_info *pi = netdev_priv(dev);
+
+ /*
+ * We do not set address filters and promiscuity here, the stack does
+ * that step explicitly.
+ */
+ ret = t4vf_set_rxmode(pi->adapter, pi->viid, dev->mtu, -1, -1, -1, -1,
+ true);
+ if (ret == 0) {
+ ret = t4vf_change_mac(pi->adapter, pi->viid,
+ pi->xact_addr_filt, dev->dev_addr, true);
+ if (ret >= 0) {
+ pi->xact_addr_filt = ret;
+ ret = 0;
+ }
+ }
+
+ /*
+ * We don't need to actually "start the link" itself since the
+ * firmware will do that for us when the first Virtual Interface
+ * is enabled on a port.
+ */
+ if (ret == 0)
+ ret = t4vf_enable_vi(pi->adapter, pi->viid, true, true);
+ return ret;
+}
+
+/*
+ * Name the MSI-X interrupts.
+ */
+static void name_msix_vecs(struct adapter *adapter)
+{
+ int namelen = sizeof(adapter->msix_info[0].desc) - 1;
+ int pidx;
+
+ /*
+ * Firmware events.
+ */
+ snprintf(adapter->msix_info[MSIX_FW].desc, namelen,
+ "%s-FWeventq", adapter->name);
+ adapter->msix_info[MSIX_FW].desc[namelen] = 0;
+
+ /*
+ * Ethernet queues.
+ */
+ for_each_port(adapter, pidx) {
+ struct net_device *dev = adapter->port[pidx];
+ const struct port_info *pi = netdev_priv(dev);
+ int qs, msi;
+
+ for (qs = 0, msi = MSIX_NIQFLINT;
+ qs < pi->nqsets;
+ qs++, msi++) {
+ snprintf(adapter->msix_info[msi].desc, namelen,
+ "%s-%d", dev->name, qs);
+ adapter->msix_info[msi].desc[namelen] = 0;
+ }
+ }
+}
+
+/*
+ * Request all of our MSI-X resources.
+ */
+static int request_msix_queue_irqs(struct adapter *adapter)
+{
+ struct sge *s = &adapter->sge;
+ int rxq, msi, err;
+
+ /*
+ * Firmware events.
+ */
+ err = request_irq(adapter->msix_info[MSIX_FW].vec, t4vf_sge_intr_msix,
+ 0, adapter->msix_info[MSIX_FW].desc, &s->fw_evtq);
+ if (err)
+ return err;
+
+ /*
+ * Ethernet queues.
+ */
+ msi = MSIX_NIQFLINT;
+ for_each_ethrxq(s, rxq) {
+ err = request_irq(adapter->msix_info[msi].vec,
+ t4vf_sge_intr_msix, 0,
+ adapter->msix_info[msi].desc,
+ &s->ethrxq[rxq].rspq);
+ if (err)
+ goto err_free_irqs;
+ msi++;
+ }
+ return 0;
+
+err_free_irqs:
+ while (--rxq >= 0)
+ free_irq(adapter->msix_info[--msi].vec, &s->ethrxq[rxq].rspq);
+ free_irq(adapter->msix_info[MSIX_FW].vec, &s->fw_evtq);
+ return err;
+}
+
+/*
+ * Free our MSI-X resources.
+ */
+static void free_msix_queue_irqs(struct adapter *adapter)
+{
+ struct sge *s = &adapter->sge;
+ int rxq, msi;
+
+ free_irq(adapter->msix_info[MSIX_FW].vec, &s->fw_evtq);
+ msi = MSIX_NIQFLINT;
+ for_each_ethrxq(s, rxq)
+ free_irq(adapter->msix_info[msi++].vec,
+ &s->ethrxq[rxq].rspq);
+}
+
+/*
+ * Turn on NAPI and start up interrupts on a response queue.
+ */
+static void qenable(struct sge_rspq *rspq)
+{
+ napi_enable(&rspq->napi);
+
+ /*
+ * 0-increment the Going To Sleep register to start the timer and
+ * enable interrupts.
+ */
+ t4_write_reg(rspq->adapter, T4VF_SGE_BASE_ADDR + SGE_VF_GTS,
+ CIDXINC(0) |
+ SEINTARM(rspq->intr_params) |
+ INGRESSQID(rspq->cntxt_id));
+}
+
+/*
+ * Enable NAPI scheduling and interrupt generation for all Receive Queues.
+ */
+static void enable_rx(struct adapter *adapter)
+{
+ int rxq;
+ struct sge *s = &adapter->sge;
+
+ for_each_ethrxq(s, rxq)
+ qenable(&s->ethrxq[rxq].rspq);
+ qenable(&s->fw_evtq);
+
+ /*
+ * The interrupt queue doesn't use NAPI so we do the 0-increment of
+ * its Going To Sleep register here to get it started.
+ */
+ if (adapter->flags & USING_MSI)
+ t4_write_reg(adapter, T4VF_SGE_BASE_ADDR + SGE_VF_GTS,
+ CIDXINC(0) |
+ SEINTARM(s->intrq.intr_params) |
+ INGRESSQID(s->intrq.cntxt_id));
+
+}
+
+/*
+ * Wait until all NAPI handlers are descheduled.
+ */
+static void quiesce_rx(struct adapter *adapter)
+{
+ struct sge *s = &adapter->sge;
+ int rxq;
+
+ for_each_ethrxq(s, rxq)
+ napi_disable(&s->ethrxq[rxq].rspq.napi);
+ napi_disable(&s->fw_evtq.napi);
+}
+
+/*
+ * Response queue handler for the firmware event queue.
+ */
+static int fwevtq_handler(struct sge_rspq *rspq, const __be64 *rsp,
+ const struct pkt_gl *gl)
+{
+ /*
+ * Extract response opcode and get pointer to CPL message body.
+ */
+ struct adapter *adapter = rspq->adapter;
+ u8 opcode = ((const struct rss_header *)rsp)->opcode;
+ void *cpl = (void *)(rsp + 1);
+
+ switch (opcode) {
+ case CPL_FW6_MSG: {
+ /*
+ * We've received an asynchronous message from the firmware.
+ */
+ const struct cpl_fw6_msg *fw_msg = cpl;
+ if (fw_msg->type == FW6_TYPE_CMD_RPL)
+ t4vf_handle_fw_rpl(adapter, fw_msg->data);
+ break;
+ }
+
+ case CPL_SGE_EGR_UPDATE: {
+ /*
+ * We've received an Egress Queue Status Update message. We
+ * get these, if the SGE is configured to send these when the
+ * firmware passes certain points in processing our TX
+ * Ethernet Queue or if we make an explicit request for one.
+ * We use these updates to determine when we may need to
+ * restart a TX Ethernet Queue which was stopped for lack of
+ * free TX Queue Descriptors ...
+ */
+ const struct cpl_sge_egr_update *p = (void *)cpl;
+ unsigned int qid = EGR_QID(be32_to_cpu(p->opcode_qid));
+ struct sge *s = &adapter->sge;
+ struct sge_txq *tq;
+ struct sge_eth_txq *txq;
+ unsigned int eq_idx;
+
+ /*
+ * Perform sanity checking on the Queue ID to make sure it
+ * really refers to one of our TX Ethernet Egress Queues which
+ * is active and matches the queue's ID. None of these error
+ * conditions should ever happen so we may want to either make
+ * them fatal and/or conditionalized under DEBUG.
+ */
+ eq_idx = EQ_IDX(s, qid);
+ if (unlikely(eq_idx >= MAX_EGRQ)) {
+ dev_err(adapter->pdev_dev,
+ "Egress Update QID %d out of range\n", qid);
+ break;
+ }
+ tq = s->egr_map[eq_idx];
+ if (unlikely(tq == NULL)) {
+ dev_err(adapter->pdev_dev,
+ "Egress Update QID %d TXQ=NULL\n", qid);
+ break;
+ }
+ txq = container_of(tq, struct sge_eth_txq, q);
+ if (unlikely(tq->abs_id != qid)) {
+ dev_err(adapter->pdev_dev,
+ "Egress Update QID %d refers to TXQ %d\n",
+ qid, tq->abs_id);
+ break;
+ }
+
+ /*
+ * Restart a stopped TX Queue which has less than half of its
+ * TX ring in use ...
+ */
+ txq->q.restarts++;
+ netif_tx_wake_queue(txq->txq);
+ break;
+ }
+
+ default:
+ dev_err(adapter->pdev_dev,
+ "unexpected CPL %#x on FW event queue\n", opcode);
+ }
+
+ return 0;
+}
+
+/*
+ * Allocate SGE TX/RX response queues. Determine how many sets of SGE queues
+ * to use and initializes them. We support multiple "Queue Sets" per port if
+ * we have MSI-X, otherwise just one queue set per port.
+ */
+static int setup_sge_queues(struct adapter *adapter)
+{
+ struct sge *s = &adapter->sge;
+ int err, pidx, msix;
+
+ /*
+ * Clear "Queue Set" Free List Starving and TX Queue Mapping Error
+ * state.
+ */
+ bitmap_zero(s->starving_fl, MAX_EGRQ);
+
+ /*
+ * If we're using MSI interrupt mode we need to set up a "forwarded
+ * interrupt" queue which we'll set up with our MSI vector. The rest
+ * of the ingress queues will be set up to forward their interrupts to
+ * this queue ... This must be first since t4vf_sge_alloc_rxq() uses
+ * the intrq's queue ID as the interrupt forwarding queue for the
+ * subsequent calls ...
+ */
+ if (adapter->flags & USING_MSI) {
+ err = t4vf_sge_alloc_rxq(adapter, &s->intrq, false,
+ adapter->port[0], 0, NULL, NULL);
+ if (err)
+ goto err_free_queues;
+ }
+
+ /*
+ * Allocate our ingress queue for asynchronous firmware messages.
+ */
+ err = t4vf_sge_alloc_rxq(adapter, &s->fw_evtq, true, adapter->port[0],
+ MSIX_FW, NULL, fwevtq_handler);
+ if (err)
+ goto err_free_queues;
+
+ /*
+ * Allocate each "port"'s initial Queue Sets. These can be changed
+ * later on ... up to the point where any interface on the adapter is
+ * brought up at which point lots of things get nailed down
+ * permanently ...
+ */
+ msix = MSIX_NIQFLINT;
+ for_each_port(adapter, pidx) {
+ struct net_device *dev = adapter->port[pidx];
+ struct port_info *pi = netdev_priv(dev);
+ struct sge_eth_rxq *rxq = &s->ethrxq[pi->first_qset];
+ struct sge_eth_txq *txq = &s->ethtxq[pi->first_qset];
+ int qs;
+
+ for (qs = 0; qs < pi->nqsets; qs++, rxq++, txq++) {
+ err = t4vf_sge_alloc_rxq(adapter, &rxq->rspq, false,
+ dev, msix++,
+ &rxq->fl, t4vf_ethrx_handler);
+ if (err)
+ goto err_free_queues;
+
+ err = t4vf_sge_alloc_eth_txq(adapter, txq, dev,
+ netdev_get_tx_queue(dev, qs),
+ s->fw_evtq.cntxt_id);
+ if (err)
+ goto err_free_queues;
+
+ rxq->rspq.idx = qs;
+ memset(&rxq->stats, 0, sizeof(rxq->stats));
+ }
+ }
+
+ /*
+ * Create the reverse mappings for the queues.
+ */
+ s->egr_base = s->ethtxq[0].q.abs_id - s->ethtxq[0].q.cntxt_id;
+ s->ingr_base = s->ethrxq[0].rspq.abs_id - s->ethrxq[0].rspq.cntxt_id;
+ IQ_MAP(s, s->fw_evtq.abs_id) = &s->fw_evtq;
+ for_each_port(adapter, pidx) {
+ struct net_device *dev = adapter->port[pidx];
+ struct port_info *pi = netdev_priv(dev);
+ struct sge_eth_rxq *rxq = &s->ethrxq[pi->first_qset];
+ struct sge_eth_txq *txq = &s->ethtxq[pi->first_qset];
+ int qs;
+
+ for (qs = 0; qs < pi->nqsets; qs++, rxq++, txq++) {
+ IQ_MAP(s, rxq->rspq.abs_id) = &rxq->rspq;
+ EQ_MAP(s, txq->q.abs_id) = &txq->q;
+
+ /*
+ * The FW_IQ_CMD doesn't return the Absolute Queue IDs
+ * for Free Lists but since all of the Egress Queues
+ * (including Free Lists) have Relative Queue IDs
+ * which are computed as Absolute - Base Queue ID, we
+ * can synthesize the Absolute Queue IDs for the Free
+ * Lists. This is useful for debugging purposes when
+ * we want to dump Queue Contexts via the PF Driver.
+ */
+ rxq->fl.abs_id = rxq->fl.cntxt_id + s->egr_base;
+ EQ_MAP(s, rxq->fl.abs_id) = &rxq->fl;
+ }
+ }
+ return 0;
+
+err_free_queues:
+ t4vf_free_sge_resources(adapter);
+ return err;
+}
+
+/*
+ * Set up Receive Side Scaling (RSS) to distribute packets to multiple receive
+ * queues. We configure the RSS CPU lookup table to distribute to the number
+ * of HW receive queues, and the response queue lookup table to narrow that
+ * down to the response queues actually configured for each "port" (Virtual
+ * Interface). We always configure the RSS mapping for all ports since the
+ * mapping table has plenty of entries.
+ */
+static int setup_rss(struct adapter *adapter)
+{
+ int pidx;
+
+ for_each_port(adapter, pidx) {
+ struct port_info *pi = adap2pinfo(adapter, pidx);
+ struct sge_eth_rxq *rxq = &adapter->sge.ethrxq[pi->first_qset];
+ u16 rss[MAX_PORT_QSETS];
+ int qs, err;
+
+ for (qs = 0; qs < pi->nqsets; qs++)
+ rss[qs] = rxq[qs].rspq.abs_id;
+
+ err = t4vf_config_rss_range(adapter, pi->viid,
+ 0, pi->rss_size, rss, pi->nqsets);
+ if (err)
+ return err;
+
+ /*
+ * Perform Global RSS Mode-specific initialization.
+ */
+ switch (adapter->params.rss.mode) {
+ case FW_RSS_GLB_CONFIG_CMD_MODE_BASICVIRTUAL:
+ /*
+ * If Tunnel All Lookup isn't specified in the global
+ * RSS Configuration, then we need to specify a
+ * default Ingress Queue for any ingress packets which
+ * aren't hashed. We'll use our first ingress queue
+ * ...
+ */
+ if (!adapter->params.rss.u.basicvirtual.tnlalllookup) {
+ union rss_vi_config config;
+ err = t4vf_read_rss_vi_config(adapter,
+ pi->viid,
+ &config);
+ if (err)
+ return err;
+ config.basicvirtual.defaultq =
+ rxq[0].rspq.abs_id;
+ err = t4vf_write_rss_vi_config(adapter,
+ pi->viid,
+ &config);
+ if (err)
+ return err;
+ }
+ break;
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * Bring the adapter up. Called whenever we go from no "ports" open to having
+ * one open. This function performs the actions necessary to make an adapter
+ * operational, such as completing the initialization of HW modules, and
+ * enabling interrupts. Must be called with the rtnl lock held. (Note that
+ * this is called "cxgb_up" in the PF Driver.)
+ */
+static int adapter_up(struct adapter *adapter)
+{
+ int err;
+
+ /*
+ * If this is the first time we've been called, perform basic
+ * adapter setup. Once we've done this, many of our adapter
+ * parameters can no longer be changed ...
+ */
+ if ((adapter->flags & FULL_INIT_DONE) == 0) {
+ err = setup_sge_queues(adapter);
+ if (err)
+ return err;
+ err = setup_rss(adapter);
+ if (err) {
+ t4vf_free_sge_resources(adapter);
+ return err;
+ }
+
+ if (adapter->flags & USING_MSIX)
+ name_msix_vecs(adapter);
+ adapter->flags |= FULL_INIT_DONE;
+ }
+
+ /*
+ * Acquire our interrupt resources. We only support MSI-X and MSI.
+ */
+ BUG_ON((adapter->flags & (USING_MSIX|USING_MSI)) == 0);
+ if (adapter->flags & USING_MSIX)
+ err = request_msix_queue_irqs(adapter);
+ else
+ err = request_irq(adapter->pdev->irq,
+ t4vf_intr_handler(adapter), 0,
+ adapter->name, adapter);
+ if (err) {
+ dev_err(adapter->pdev_dev, "request_irq failed, err %d\n",
+ err);
+ return err;
+ }
+
+ /*
+ * Enable NAPI ingress processing and return success.
+ */
+ enable_rx(adapter);
+ t4vf_sge_start(adapter);
+ return 0;
+}
+
+/*
+ * Bring the adapter down. Called whenever the last "port" (Virtual
+ * Interface) closed. (Note that this routine is called "cxgb_down" in the PF
+ * Driver.)
+ */
+static void adapter_down(struct adapter *adapter)
+{
+ /*
+ * Free interrupt resources.
+ */
+ if (adapter->flags & USING_MSIX)
+ free_msix_queue_irqs(adapter);
+ else
+ free_irq(adapter->pdev->irq, adapter);
+
+ /*
+ * Wait for NAPI handlers to finish.
+ */
+ quiesce_rx(adapter);
+}
+
+/*
+ * Start up a net device.
+ */
+static int cxgb4vf_open(struct net_device *dev)
+{
+ int err;
+ struct port_info *pi = netdev_priv(dev);
+ struct adapter *adapter = pi->adapter;
+
+ /*
+ * If this is the first interface that we're opening on the "adapter",
+ * bring the "adapter" up now.
+ */
+ if (adapter->open_device_map == 0) {
+ err = adapter_up(adapter);
+ if (err)
+ return err;
+ }
+
+ /*
+ * Note that this interface is up and start everything up ...
+ */
+ dev->real_num_tx_queues = pi->nqsets;
+ set_bit(pi->port_id, &adapter->open_device_map);
+ link_start(dev);
+ netif_tx_start_all_queues(dev);
+ return 0;
+}
+
+/*
+ * Shut down a net device. This routine is called "cxgb_close" in the PF
+ * Driver ...
+ */
+static int cxgb4vf_stop(struct net_device *dev)
+{
+ int ret;
+ struct port_info *pi = netdev_priv(dev);
+ struct adapter *adapter = pi->adapter;
+
+ netif_tx_stop_all_queues(dev);
+ netif_carrier_off(dev);
+ ret = t4vf_enable_vi(adapter, pi->viid, false, false);
+ pi->link_cfg.link_ok = 0;
+
+ clear_bit(pi->port_id, &adapter->open_device_map);
+ if (adapter->open_device_map == 0)
+ adapter_down(adapter);
+ return 0;
+}
+
+/*
+ * Translate our basic statistics into the standard "ifconfig" statistics.
+ */
+static struct net_device_stats *cxgb4vf_get_stats(struct net_device *dev)
+{
+ struct t4vf_port_stats stats;
+ struct port_info *pi = netdev2pinfo(dev);
+ struct adapter *adapter = pi->adapter;
+ struct net_device_stats *ns = &dev->stats;
+ int err;
+
+ spin_lock(&adapter->stats_lock);
+ err = t4vf_get_port_stats(adapter, pi->pidx, &stats);
+ spin_unlock(&adapter->stats_lock);
+
+ memset(ns, 0, sizeof(*ns));
+ if (err)
+ return ns;
+
+ ns->tx_bytes = (stats.tx_bcast_bytes + stats.tx_mcast_bytes +
+ stats.tx_ucast_bytes + stats.tx_offload_bytes);
+ ns->tx_packets = (stats.tx_bcast_frames + stats.tx_mcast_frames +
+ stats.tx_ucast_frames + stats.tx_offload_frames);
+ ns->rx_bytes = (stats.rx_bcast_bytes + stats.rx_mcast_bytes +
+ stats.rx_ucast_bytes);
+ ns->rx_packets = (stats.rx_bcast_frames + stats.rx_mcast_frames +
+ stats.rx_ucast_frames);
+ ns->multicast = stats.rx_mcast_frames;
+ ns->tx_errors = stats.tx_drop_frames;
+ ns->rx_errors = stats.rx_err_frames;
+
+ return ns;
+}
+
+/*
+ * Collect up to maxaddrs worth of a netdevice's unicast addresses into an
+ * array of addrss pointers and return the number collected.
+ */
+static inline int collect_netdev_uc_list_addrs(const struct net_device *dev,
+ const u8 **addr,
+ unsigned int maxaddrs)
+{
+ unsigned int naddr = 0;
+ const struct netdev_hw_addr *ha;
+
+ for_each_dev_addr(dev, ha) {
+ addr[naddr++] = ha->addr;
+ if (naddr >= maxaddrs)
+ break;
+ }
+ return naddr;
+}
+
+/*
+ * Collect up to maxaddrs worth of a netdevice's multicast addresses into an
+ * array of addrss pointers and return the number collected.
+ */
+static inline int collect_netdev_mc_list_addrs(const struct net_device *dev,
+ const u8 **addr,
+ unsigned int maxaddrs)
+{
+ unsigned int naddr = 0;
+ const struct netdev_hw_addr *ha;
+
+ netdev_for_each_mc_addr(ha, dev) {
+ addr[naddr++] = ha->addr;
+ if (naddr >= maxaddrs)
+ break;
+ }
+ return naddr;
+}
+
+/*
+ * Configure the exact and hash address filters to handle a port's multicast
+ * and secondary unicast MAC addresses.
+ */
+static int set_addr_filters(const struct net_device *dev, bool sleep)
+{
+ u64 mhash = 0;
+ u64 uhash = 0;
+ bool free = true;
+ u16 filt_idx[7];
+ const u8 *addr[7];
+ int ret, naddr = 0;
+ const struct port_info *pi = netdev_priv(dev);
+
+ /* first do the secondary unicast addresses */
+ naddr = collect_netdev_uc_list_addrs(dev, addr, ARRAY_SIZE(addr));
+ if (naddr > 0) {
+ ret = t4vf_alloc_mac_filt(pi->adapter, pi->viid, free,
+ naddr, addr, filt_idx, &uhash, sleep);
+ if (ret < 0)
+ return ret;
+
+ free = false;
+ }
+
+ /* next set up the multicast addresses */
+ naddr = collect_netdev_mc_list_addrs(dev, addr, ARRAY_SIZE(addr));
+ if (naddr > 0) {
+ ret = t4vf_alloc_mac_filt(pi->adapter, pi->viid, free,
+ naddr, addr, filt_idx, &mhash, sleep);
+ if (ret < 0)
+ return ret;
+ }
+
+ return t4vf_set_addr_hash(pi->adapter, pi->viid, uhash != 0,
+ uhash | mhash, sleep);
+}
+
+/*
+ * Set RX properties of a port, such as promiscruity, address filters, and MTU.
+ * If @mtu is -1 it is left unchanged.
+ */
+static int set_rxmode(struct net_device *dev, int mtu, bool sleep_ok)
+{
+ int ret;
+ struct port_info *pi = netdev_priv(dev);
+
+ ret = set_addr_filters(dev, sleep_ok);
+ if (ret == 0)
+ ret = t4vf_set_rxmode(pi->adapter, pi->viid, -1,
+ (dev->flags & IFF_PROMISC) != 0,
+ (dev->flags & IFF_ALLMULTI) != 0,
+ 1, -1, sleep_ok);
+ return ret;
+}
+
+/*
+ * Set the current receive modes on the device.
+ */
+static void cxgb4vf_set_rxmode(struct net_device *dev)
+{
+ /* unfortunately we can't return errors to the stack */
+ set_rxmode(dev, -1, false);
+}
+
+/*
+ * Find the entry in the interrupt holdoff timer value array which comes
+ * closest to the specified interrupt holdoff value.
+ */
+static int closest_timer(const struct sge *s, int us)
+{
+ int i, timer_idx = 0, min_delta = INT_MAX;
+
+ for (i = 0; i < ARRAY_SIZE(s->timer_val); i++) {
+ int delta = us - s->timer_val[i];
+ if (delta < 0)
+ delta = -delta;
+ if (delta < min_delta) {
+ min_delta = delta;
+ timer_idx = i;
+ }
+ }
+ return timer_idx;
+}
+
+static int closest_thres(const struct sge *s, int thres)
+{
+ int i, delta, pktcnt_idx = 0, min_delta = INT_MAX;
+
+ for (i = 0; i < ARRAY_SIZE(s->counter_val); i++) {
+ delta = thres - s->counter_val[i];
+ if (delta < 0)
+ delta = -delta;
+ if (delta < min_delta) {
+ min_delta = delta;
+ pktcnt_idx = i;
+ }
+ }
+ return pktcnt_idx;
+}
+
+/*
+ * Return a queue's interrupt hold-off time in us. 0 means no timer.
+ */
+static unsigned int qtimer_val(const struct adapter *adapter,
+ const struct sge_rspq *rspq)
+{
+ unsigned int timer_idx = QINTR_TIMER_IDX_GET(rspq->intr_params);
+
+ return timer_idx < SGE_NTIMERS
+ ? adapter->sge.timer_val[timer_idx]
+ : 0;
+}
+
+/**
+ * set_rxq_intr_params - set a queue's interrupt holdoff parameters
+ * @adapter: the adapter
+ * @rspq: the RX response queue
+ * @us: the hold-off time in us, or 0 to disable timer
+ * @cnt: the hold-off packet count, or 0 to disable counter
+ *
+ * Sets an RX response queue's interrupt hold-off time and packet count.
+ * At least one of the two needs to be enabled for the queue to generate
+ * interrupts.
+ */
+static int set_rxq_intr_params(struct adapter *adapter, struct sge_rspq *rspq,
+ unsigned int us, unsigned int cnt)
+{
+ unsigned int timer_idx;
+
+ /*
+ * If both the interrupt holdoff timer and count are specified as
+ * zero, default to a holdoff count of 1 ...
+ */
+ if ((us | cnt) == 0)
+ cnt = 1;
+
+ /*
+ * If an interrupt holdoff count has been specified, then find the
+ * closest configured holdoff count and use that. If the response
+ * queue has already been created, then update its queue context
+ * parameters ...
+ */
+ if (cnt) {
+ int err;
+ u32 v, pktcnt_idx;
+
+ pktcnt_idx = closest_thres(&adapter->sge, cnt);
+ if (rspq->desc && rspq->pktcnt_idx != pktcnt_idx) {
+ v = FW_PARAMS_MNEM(FW_PARAMS_MNEM_DMAQ) |
+ FW_PARAMS_PARAM_X(
+ FW_PARAMS_PARAM_DMAQ_IQ_INTCNTTHRESH) |
+ FW_PARAMS_PARAM_YZ(rspq->cntxt_id);
+ err = t4vf_set_params(adapter, 1, &v, &pktcnt_idx);
+ if (err)
+ return err;
+ }
+ rspq->pktcnt_idx = pktcnt_idx;
+ }
+
+ /*
+ * Compute the closest holdoff timer index from the supplied holdoff
+ * timer value.
+ */
+ timer_idx = (us == 0
+ ? SGE_TIMER_RSTRT_CNTR
+ : closest_timer(&adapter->sge, us));
+
+ /*
+ * Update the response queue's interrupt coalescing parameters and
+ * return success.
+ */
+ rspq->intr_params = (QINTR_TIMER_IDX(timer_idx) |
+ (cnt > 0 ? QINTR_CNT_EN : 0));
+ return 0;
+}
+
+/*
+ * Return a version number to identify the type of adapter. The scheme is:
+ * - bits 0..9: chip version
+ * - bits 10..15: chip revision
+ */
+static inline unsigned int mk_adap_vers(const struct adapter *adapter)
+{
+ /*
+ * Chip version 4, revision 0x3f (cxgb4vf).
+ */
+ return 4 | (0x3f << 10);
+}
+
+/*
+ * Execute the specified ioctl command.
+ */
+static int cxgb4vf_do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+{
+ int ret = 0;
+
+ switch (cmd) {
+ /*
+ * The VF Driver doesn't have access to any of the other
+ * common Ethernet device ioctl()'s (like reading/writing
+ * PHY registers, etc.
+ */
+
+ default:
+ ret = -EOPNOTSUPP;
+ break;
+ }
+ return ret;
+}
+
+/*
+ * Change the device's MTU.
+ */
+static int cxgb4vf_change_mtu(struct net_device *dev, int new_mtu)
+{
+ int ret;
+ struct port_info *pi = netdev_priv(dev);
+
+ /* accommodate SACK */
+ if (new_mtu < 81)
+ return -EINVAL;
+
+ ret = t4vf_set_rxmode(pi->adapter, pi->viid, new_mtu,
+ -1, -1, -1, -1, true);
+ if (!ret)
+ dev->mtu = new_mtu;
+ return ret;
+}
+
+/*
+ * Change the devices MAC address.
+ */
+static int cxgb4vf_set_mac_addr(struct net_device *dev, void *_addr)
+{
+ int ret;
+ struct sockaddr *addr = _addr;
+ struct port_info *pi = netdev_priv(dev);
+
+ if (!is_valid_ether_addr(addr->sa_data))
+ return -EINVAL;
+
+ ret = t4vf_change_mac(pi->adapter, pi->viid, pi->xact_addr_filt,
+ addr->sa_data, true);
+ if (ret < 0)
+ return ret;
+
+ memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
+ pi->xact_addr_filt = ret;
+ return 0;
+}
+
+/*
+ * Return a TX Queue on which to send the specified skb.
+ */
+static u16 cxgb4vf_select_queue(struct net_device *dev, struct sk_buff *skb)
+{
+ /*
+ * XXX For now just use the default hash but we probably want to
+ * XXX look at other possibilities ...
+ */
+ return skb_tx_hash(dev, skb);
+}
+
+#ifdef CONFIG_NET_POLL_CONTROLLER
+/*
+ * Poll all of our receive queues. This is called outside of normal interrupt
+ * context.
+ */
+static void cxgb4vf_poll_controller(struct net_device *dev)
+{
+ struct port_info *pi = netdev_priv(dev);
+ struct adapter *adapter = pi->adapter;
+
+ if (adapter->flags & USING_MSIX) {
+ struct sge_eth_rxq *rxq;
+ int nqsets;
+
+ rxq = &adapter->sge.ethrxq[pi->first_qset];
+ for (nqsets = pi->nqsets; nqsets; nqsets--) {
+ t4vf_sge_intr_msix(0, &rxq->rspq);
+ rxq++;
+ }
+ } else
+ t4vf_intr_handler(adapter)(0, adapter);
+}
+#endif
+
+/*
+ * Ethtool operations.
+ * ===================
+ *
+ * Note that we don't support any ethtool operations which change the physical
+ * state of the port to which we're linked.
+ */
+
+/*
+ * Return current port link settings.
+ */
+static int cxgb4vf_get_settings(struct net_device *dev,
+ struct ethtool_cmd *cmd)
+{
+ const struct port_info *pi = netdev_priv(dev);
+
+ cmd->supported = pi->link_cfg.supported;
+ cmd->advertising = pi->link_cfg.advertising;
+ cmd->speed = netif_carrier_ok(dev) ? pi->link_cfg.speed : -1;
+ cmd->duplex = DUPLEX_FULL;
+
+ cmd->port = (cmd->supported & SUPPORTED_TP) ? PORT_TP : PORT_FIBRE;
+ cmd->phy_address = pi->port_id;
+ cmd->transceiver = XCVR_EXTERNAL;
+ cmd->autoneg = pi->link_cfg.autoneg;
+ cmd->maxtxpkt = 0;
+ cmd->maxrxpkt = 0;
+ return 0;
+}
+
+/*
+ * Return our driver information.
+ */
+static void cxgb4vf_get_drvinfo(struct net_device *dev,
+ struct ethtool_drvinfo *drvinfo)
+{
+ struct adapter *adapter = netdev2adap(dev);
+
+ strcpy(drvinfo->driver, KBUILD_MODNAME);
+ strcpy(drvinfo->version, DRV_VERSION);
+ strcpy(drvinfo->bus_info, pci_name(to_pci_dev(dev->dev.parent)));
+ snprintf(drvinfo->fw_version, sizeof(drvinfo->fw_version),
+ "%u.%u.%u.%u, TP %u.%u.%u.%u",
+ FW_HDR_FW_VER_MAJOR_GET(adapter->params.dev.fwrev),
+ FW_HDR_FW_VER_MINOR_GET(adapter->params.dev.fwrev),
+ FW_HDR_FW_VER_MICRO_GET(adapter->params.dev.fwrev),
+ FW_HDR_FW_VER_BUILD_GET(adapter->params.dev.fwrev),
+ FW_HDR_FW_VER_MAJOR_GET(adapter->params.dev.tprev),
+ FW_HDR_FW_VER_MINOR_GET(adapter->params.dev.tprev),
+ FW_HDR_FW_VER_MICRO_GET(adapter->params.dev.tprev),
+ FW_HDR_FW_VER_BUILD_GET(adapter->params.dev.tprev));
+}
+
+/*
+ * Return current adapter message level.
+ */
+static u32 cxgb4vf_get_msglevel(struct net_device *dev)
+{
+ return netdev2adap(dev)->msg_enable;
+}
+
+/*
+ * Set current adapter message level.
+ */
+static void cxgb4vf_set_msglevel(struct net_device *dev, u32 msglevel)
+{
+ netdev2adap(dev)->msg_enable = msglevel;
+}
+
+/*
+ * Return the device's current Queue Set ring size parameters along with the
+ * allowed maximum values. Since ethtool doesn't understand the concept of
+ * multi-queue devices, we just return the current values associated with the
+ * first Queue Set.
+ */
+static void cxgb4vf_get_ringparam(struct net_device *dev,
+ struct ethtool_ringparam *rp)
+{
+ const struct port_info *pi = netdev_priv(dev);
+ const struct sge *s = &pi->adapter->sge;
+
+ rp->rx_max_pending = MAX_RX_BUFFERS;
+ rp->rx_mini_max_pending = MAX_RSPQ_ENTRIES;
+ rp->rx_jumbo_max_pending = 0;
+ rp->tx_max_pending = MAX_TXQ_ENTRIES;
+
+ rp->rx_pending = s->ethrxq[pi->first_qset].fl.size - MIN_FL_RESID;
+ rp->rx_mini_pending = s->ethrxq[pi->first_qset].rspq.size;
+ rp->rx_jumbo_pending = 0;
+ rp->tx_pending = s->ethtxq[pi->first_qset].q.size;
+}
+
+/*
+ * Set the Queue Set ring size parameters for the device. Again, since
+ * ethtool doesn't allow for the concept of multiple queues per device, we'll
+ * apply these new values across all of the Queue Sets associated with the
+ * device -- after vetting them of course!
+ */
+static int cxgb4vf_set_ringparam(struct net_device *dev,
+ struct ethtool_ringparam *rp)
+{
+ const struct port_info *pi = netdev_priv(dev);
+ struct adapter *adapter = pi->adapter;
+ struct sge *s = &adapter->sge;
+ int qs;
+
+ if (rp->rx_pending > MAX_RX_BUFFERS ||
+ rp->rx_jumbo_pending ||
+ rp->tx_pending > MAX_TXQ_ENTRIES ||
+ rp->rx_mini_pending > MAX_RSPQ_ENTRIES ||
+ rp->rx_mini_pending < MIN_RSPQ_ENTRIES ||
+ rp->rx_pending < MIN_FL_ENTRIES ||
+ rp->tx_pending < MIN_TXQ_ENTRIES)
+ return -EINVAL;
+
+ if (adapter->flags & FULL_INIT_DONE)
+ return -EBUSY;
+
+ for (qs = pi->first_qset; qs < pi->first_qset + pi->nqsets; qs++) {
+ s->ethrxq[qs].fl.size = rp->rx_pending + MIN_FL_RESID;
+ s->ethrxq[qs].rspq.size = rp->rx_mini_pending;
+ s->ethtxq[qs].q.size = rp->tx_pending;
+ }
+ return 0;
+}
+
+/*
+ * Return the interrupt holdoff timer and count for the first Queue Set on the
+ * device. Our extension ioctl() (the cxgbtool interface) allows the
+ * interrupt holdoff timer to be read on all of the device's Queue Sets.
+ */
+static int cxgb4vf_get_coalesce(struct net_device *dev,
+ struct ethtool_coalesce *coalesce)
+{
+ const struct port_info *pi = netdev_priv(dev);
+ const struct adapter *adapter = pi->adapter;
+ const struct sge_rspq *rspq = &adapter->sge.ethrxq[pi->first_qset].rspq;
+
+ coalesce->rx_coalesce_usecs = qtimer_val(adapter, rspq);
+ coalesce->rx_max_coalesced_frames =
+ ((rspq->intr_params & QINTR_CNT_EN)
+ ? adapter->sge.counter_val[rspq->pktcnt_idx]
+ : 0);
+ return 0;
+}
+
+/*
+ * Set the RX interrupt holdoff timer and count for the first Queue Set on the
+ * interface. Our extension ioctl() (the cxgbtool interface) allows us to set
+ * the interrupt holdoff timer on any of the device's Queue Sets.
+ */
+static int cxgb4vf_set_coalesce(struct net_device *dev,
+ struct ethtool_coalesce *coalesce)
+{
+ const struct port_info *pi = netdev_priv(dev);
+ struct adapter *adapter = pi->adapter;
+
+ return set_rxq_intr_params(adapter,
+ &adapter->sge.ethrxq[pi->first_qset].rspq,
+ coalesce->rx_coalesce_usecs,
+ coalesce->rx_max_coalesced_frames);
+}
+
+/*
+ * Report current port link pause parameter settings.
+ */
+static void cxgb4vf_get_pauseparam(struct net_device *dev,
+ struct ethtool_pauseparam *pauseparam)
+{
+ struct port_info *pi = netdev_priv(dev);
+
+ pauseparam->autoneg = (pi->link_cfg.requested_fc & PAUSE_AUTONEG) != 0;
+ pauseparam->rx_pause = (pi->link_cfg.fc & PAUSE_RX) != 0;
+ pauseparam->tx_pause = (pi->link_cfg.fc & PAUSE_TX) != 0;
+}
+
+/*
+ * Return whether RX Checksum Offloading is currently enabled for the device.
+ */
+static u32 cxgb4vf_get_rx_csum(struct net_device *dev)
+{
+ struct port_info *pi = netdev_priv(dev);
+
+ return (pi->rx_offload & RX_CSO) != 0;
+}
+
+/*
+ * Turn RX Checksum Offloading on or off for the device.
+ */
+static int cxgb4vf_set_rx_csum(struct net_device *dev, u32 csum)
+{
+ struct port_info *pi = netdev_priv(dev);
+
+ if (csum)
+ pi->rx_offload |= RX_CSO;
+ else
+ pi->rx_offload &= ~RX_CSO;
+ return 0;
+}
+
+/*
+ * Identify the port by blinking the port's LED.
+ */
+static int cxgb4vf_phys_id(struct net_device *dev, u32 id)
+{
+ struct port_info *pi = netdev_priv(dev);
+
+ return t4vf_identify_port(pi->adapter, pi->viid, 5);
+}
+
+/*
+ * Port stats maintained per queue of the port.
+ */
+struct queue_port_stats {
+ u64 tso;
+ u64 tx_csum;
+ u64 rx_csum;
+ u64 vlan_ex;
+ u64 vlan_ins;
+};
+
+/*
+ * Strings for the ETH_SS_STATS statistics set ("ethtool -S"). Note that
+ * these need to match the order of statistics returned by
+ * t4vf_get_port_stats().
+ */
+static const char stats_strings[][ETH_GSTRING_LEN] = {
+ /*
+ * These must match the layout of the t4vf_port_stats structure.
+ */
+ "TxBroadcastBytes ",
+ "TxBroadcastFrames ",
+ "TxMulticastBytes ",
+ "TxMulticastFrames ",
+ "TxUnicastBytes ",
+ "TxUnicastFrames ",
+ "TxDroppedFrames ",
+ "TxOffloadBytes ",
+ "TxOffloadFrames ",
+ "RxBroadcastBytes ",
+ "RxBroadcastFrames ",
+ "RxMulticastBytes ",
+ "RxMulticastFrames ",
+ "RxUnicastBytes ",
+ "RxUnicastFrames ",
+ "RxErrorFrames ",
+
+ /*
+ * These are accumulated per-queue statistics and must match the
+ * order of the fields in the queue_port_stats structure.
+ */
+ "TSO ",
+ "TxCsumOffload ",
+ "RxCsumGood ",
+ "VLANextractions ",
+ "VLANinsertions ",
+};
+
+/*
+ * Return the number of statistics in the specified statistics set.
+ */
+static int cxgb4vf_get_sset_count(struct net_device *dev, int sset)
+{
+ switch (sset) {
+ case ETH_SS_STATS:
+ return ARRAY_SIZE(stats_strings);
+ default:
+ return -EOPNOTSUPP;
+ }
+ /*NOTREACHED*/
+}
+
+/*
+ * Return the strings for the specified statistics set.
+ */
+static void cxgb4vf_get_strings(struct net_device *dev,
+ u32 sset,
+ u8 *data)
+{
+ switch (sset) {
+ case ETH_SS_STATS:
+ memcpy(data, stats_strings, sizeof(stats_strings));
+ break;
+ }
+}
+
+/*
+ * Small utility routine to accumulate queue statistics across the queues of
+ * a "port".
+ */
+static void collect_sge_port_stats(const struct adapter *adapter,
+ const struct port_info *pi,
+ struct queue_port_stats *stats)
+{
+ const struct sge_eth_txq *txq = &adapter->sge.ethtxq[pi->first_qset];
+ const struct sge_eth_rxq *rxq = &adapter->sge.ethrxq[pi->first_qset];
+ int qs;
+
+ memset(stats, 0, sizeof(*stats));
+ for (qs = 0; qs < pi->nqsets; qs++, rxq++, txq++) {
+ stats->tso += txq->tso;
+ stats->tx_csum += txq->tx_cso;
+ stats->rx_csum += rxq->stats.rx_cso;
+ stats->vlan_ex += rxq->stats.vlan_ex;
+ stats->vlan_ins += txq->vlan_ins;
+ }
+}
+
+/*
+ * Return the ETH_SS_STATS statistics set.
+ */
+static void cxgb4vf_get_ethtool_stats(struct net_device *dev,
+ struct ethtool_stats *stats,
+ u64 *data)
+{
+ struct port_info *pi = netdev2pinfo(dev);
+ struct adapter *adapter = pi->adapter;
+ int err = t4vf_get_port_stats(adapter, pi->pidx,
+ (struct t4vf_port_stats *)data);
+ if (err)
+ memset(data, 0, sizeof(struct t4vf_port_stats));
+
+ data += sizeof(struct t4vf_port_stats) / sizeof(u64);
+ collect_sge_port_stats(adapter, pi, (struct queue_port_stats *)data);
+}
+
+/*
+ * Return the size of our register map.
+ */
+static int cxgb4vf_get_regs_len(struct net_device *dev)
+{
+ return T4VF_REGMAP_SIZE;
+}
+
+/*
+ * Dump a block of registers, start to end inclusive, into a buffer.
+ */
+static void reg_block_dump(struct adapter *adapter, void *regbuf,
+ unsigned int start, unsigned int end)
+{
+ u32 *bp = regbuf + start - T4VF_REGMAP_START;
+
+ for ( ; start <= end; start += sizeof(u32)) {
+ /*
+ * Avoid reading the Mailbox Control register since that
+ * can trigger a Mailbox Ownership Arbitration cycle and
+ * interfere with communication with the firmware.
+ */
+ if (start == T4VF_CIM_BASE_ADDR + CIM_VF_EXT_MAILBOX_CTRL)
+ *bp++ = 0xffff;
+ else
+ *bp++ = t4_read_reg(adapter, start);
+ }
+}
+
+/*
+ * Copy our entire register map into the provided buffer.
+ */
+static void cxgb4vf_get_regs(struct net_device *dev,
+ struct ethtool_regs *regs,
+ void *regbuf)
+{
+ struct adapter *adapter = netdev2adap(dev);
+
+ regs->version = mk_adap_vers(adapter);
+
+ /*
+ * Fill in register buffer with our register map.
+ */
+ memset(regbuf, 0, T4VF_REGMAP_SIZE);
+
+ reg_block_dump(adapter, regbuf,
+ T4VF_SGE_BASE_ADDR + T4VF_MOD_MAP_SGE_FIRST,
+ T4VF_SGE_BASE_ADDR + T4VF_MOD_MAP_SGE_LAST);
+ reg_block_dump(adapter, regbuf,
+ T4VF_MPS_BASE_ADDR + T4VF_MOD_MAP_MPS_FIRST,
+ T4VF_MPS_BASE_ADDR + T4VF_MOD_MAP_MPS_LAST);
+ reg_block_dump(adapter, regbuf,
+ T4VF_PL_BASE_ADDR + T4VF_MOD_MAP_PL_FIRST,
+ T4VF_PL_BASE_ADDR + T4VF_MOD_MAP_PL_LAST);
+ reg_block_dump(adapter, regbuf,
+ T4VF_CIM_BASE_ADDR + T4VF_MOD_MAP_CIM_FIRST,
+ T4VF_CIM_BASE_ADDR + T4VF_MOD_MAP_CIM_LAST);
+
+ reg_block_dump(adapter, regbuf,
+ T4VF_MBDATA_BASE_ADDR + T4VF_MBDATA_FIRST,
+ T4VF_MBDATA_BASE_ADDR + T4VF_MBDATA_LAST);
+}
+
+/*
+ * Report current Wake On LAN settings.
+ */
+static void cxgb4vf_get_wol(struct net_device *dev,
+ struct ethtool_wolinfo *wol)
+{
+ wol->supported = 0;
+ wol->wolopts = 0;
+ memset(&wol->sopass, 0, sizeof(wol->sopass));
+}
+
+/*
+ * Set TCP Segmentation Offloading feature capabilities.
+ */
+static int cxgb4vf_set_tso(struct net_device *dev, u32 tso)
+{
+ if (tso)
+ dev->features |= NETIF_F_TSO | NETIF_F_TSO6;
+ else
+ dev->features &= ~(NETIF_F_TSO | NETIF_F_TSO6);
+ return 0;
+}
+
+static struct ethtool_ops cxgb4vf_ethtool_ops = {
+ .get_settings = cxgb4vf_get_settings,
+ .get_drvinfo = cxgb4vf_get_drvinfo,
+ .get_msglevel = cxgb4vf_get_msglevel,
+ .set_msglevel = cxgb4vf_set_msglevel,
+ .get_ringparam = cxgb4vf_get_ringparam,
+ .set_ringparam = cxgb4vf_set_ringparam,
+ .get_coalesce = cxgb4vf_get_coalesce,
+ .set_coalesce = cxgb4vf_set_coalesce,
+ .get_pauseparam = cxgb4vf_get_pauseparam,
+ .get_rx_csum = cxgb4vf_get_rx_csum,
+ .set_rx_csum = cxgb4vf_set_rx_csum,
+ .set_tx_csum = ethtool_op_set_tx_ipv6_csum,
+ .set_sg = ethtool_op_set_sg,
+ .get_link = ethtool_op_get_link,
+ .get_strings = cxgb4vf_get_strings,
+ .phys_id = cxgb4vf_phys_id,
+ .get_sset_count = cxgb4vf_get_sset_count,
+ .get_ethtool_stats = cxgb4vf_get_ethtool_stats,
+ .get_regs_len = cxgb4vf_get_regs_len,
+ .get_regs = cxgb4vf_get_regs,
+ .get_wol = cxgb4vf_get_wol,
+ .set_tso = cxgb4vf_set_tso,
+};
+
+/*
+ * /sys/kernel/debug/cxgb4vf support code and data.
+ * ================================================
+ */
+
+/*
+ * Show SGE Queue Set information. We display QPL Queues Sets per line.
+ */
+#define QPL 4
+
+static int sge_qinfo_show(struct seq_file *seq, void *v)
+{
+ struct adapter *adapter = seq->private;
+ int eth_entries = DIV_ROUND_UP(adapter->sge.ethqsets, QPL);
+ int qs, r = (uintptr_t)v - 1;
+
+ if (r)
+ seq_putc(seq, '\n');
+
+ #define S3(fmt_spec, s, v) \
+ do {\
+ seq_printf(seq, "%-12s", s); \
+ for (qs = 0; qs < n; ++qs) \
+ seq_printf(seq, " %16" fmt_spec, v); \
+ seq_putc(seq, '\n'); \
+ } while (0)
+ #define S(s, v) S3("s", s, v)
+ #define T(s, v) S3("u", s, txq[qs].v)
+ #define R(s, v) S3("u", s, rxq[qs].v)
+
+ if (r < eth_entries) {
+ const struct sge_eth_rxq *rxq = &adapter->sge.ethrxq[r * QPL];
+ const struct sge_eth_txq *txq = &adapter->sge.ethtxq[r * QPL];
+ int n = min(QPL, adapter->sge.ethqsets - QPL * r);
+
+ S("QType:", "Ethernet");
+ S("Interface:",
+ (rxq[qs].rspq.netdev
+ ? rxq[qs].rspq.netdev->name
+ : "N/A"));
+ S3("d", "Port:",
+ (rxq[qs].rspq.netdev
+ ? ((struct port_info *)
+ netdev_priv(rxq[qs].rspq.netdev))->port_id
+ : -1));
+ T("TxQ ID:", q.abs_id);
+ T("TxQ size:", q.size);
+ T("TxQ inuse:", q.in_use);
+ T("TxQ PIdx:", q.pidx);
+ T("TxQ CIdx:", q.cidx);
+ R("RspQ ID:", rspq.abs_id);
+ R("RspQ size:", rspq.size);
+ R("RspQE size:", rspq.iqe_len);
+ S3("u", "Intr delay:", qtimer_val(adapter, &rxq[qs].rspq));
+ S3("u", "Intr pktcnt:",
+ adapter->sge.counter_val[rxq[qs].rspq.pktcnt_idx]);
+ R("RspQ CIdx:", rspq.cidx);
+ R("RspQ Gen:", rspq.gen);
+ R("FL ID:", fl.abs_id);
+ R("FL size:", fl.size - MIN_FL_RESID);
+ R("FL avail:", fl.avail);
+ R("FL PIdx:", fl.pidx);
+ R("FL CIdx:", fl.cidx);
+ return 0;
+ }
+
+ r -= eth_entries;
+ if (r == 0) {
+ const struct sge_rspq *evtq = &adapter->sge.fw_evtq;
+
+ seq_printf(seq, "%-12s %16s\n", "QType:", "FW event queue");
+ seq_printf(seq, "%-12s %16u\n", "RspQ ID:", evtq->abs_id);
+ seq_printf(seq, "%-12s %16u\n", "Intr delay:",
+ qtimer_val(adapter, evtq));
+ seq_printf(seq, "%-12s %16u\n", "Intr pktcnt:",
+ adapter->sge.counter_val[evtq->pktcnt_idx]);
+ seq_printf(seq, "%-12s %16u\n", "RspQ Cidx:", evtq->cidx);
+ seq_printf(seq, "%-12s %16u\n", "RspQ Gen:", evtq->gen);
+ } else if (r == 1) {
+ const struct sge_rspq *intrq = &adapter->sge.intrq;
+
+ seq_printf(seq, "%-12s %16s\n", "QType:", "Interrupt Queue");
+ seq_printf(seq, "%-12s %16u\n", "RspQ ID:", intrq->abs_id);
+ seq_printf(seq, "%-12s %16u\n", "Intr delay:",
+ qtimer_val(adapter, intrq));
+ seq_printf(seq, "%-12s %16u\n", "Intr pktcnt:",
+ adapter->sge.counter_val[intrq->pktcnt_idx]);
+ seq_printf(seq, "%-12s %16u\n", "RspQ Cidx:", intrq->cidx);
+ seq_printf(seq, "%-12s %16u\n", "RspQ Gen:", intrq->gen);
+ }
+
+ #undef R
+ #undef T
+ #undef S
+ #undef S3
+
+ return 0;
+}
+
+/*
+ * Return the number of "entries" in our "file". We group the multi-Queue
+ * sections with QPL Queue Sets per "entry". The sections of the output are:
+ *
+ * Ethernet RX/TX Queue Sets
+ * Firmware Event Queue
+ * Forwarded Interrupt Queue (if in MSI mode)
+ */
+static int sge_queue_entries(const struct adapter *adapter)
+{
+ return DIV_ROUND_UP(adapter->sge.ethqsets, QPL) + 1 +
+ ((adapter->flags & USING_MSI) != 0);
+}
+
+static void *sge_queue_start(struct seq_file *seq, loff_t *pos)
+{
+ int entries = sge_queue_entries(seq->private);
+
+ return *pos < entries ? (void *)((uintptr_t)*pos + 1) : NULL;
+}
+
+static void sge_queue_stop(struct seq_file *seq, void *v)
+{
+}
+
+static void *sge_queue_next(struct seq_file *seq, void *v, loff_t *pos)
+{
+ int entries = sge_queue_entries(seq->private);
+
+ ++*pos;
+ return *pos < entries ? (void *)((uintptr_t)*pos + 1) : NULL;
+}
+
+static const struct seq_operations sge_qinfo_seq_ops = {
+ .start = sge_queue_start,
+ .next = sge_queue_next,
+ .stop = sge_queue_stop,
+ .show = sge_qinfo_show
+};
+
+static int sge_qinfo_open(struct inode *inode, struct file *file)
+{
+ int res = seq_open(file, &sge_qinfo_seq_ops);
+
+ if (!res) {
+ struct seq_file *seq = file->private_data;
+ seq->private = inode->i_private;
+ }
+ return res;
+}
+
+static const struct file_operations sge_qinfo_debugfs_fops = {
+ .owner = THIS_MODULE,
+ .open = sge_qinfo_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = seq_release,
+};
+
+/*
+ * Show SGE Queue Set statistics. We display QPL Queues Sets per line.
+ */
+#define QPL 4
+
+static int sge_qstats_show(struct seq_file *seq, void *v)
+{
+ struct adapter *adapter = seq->private;
+ int eth_entries = DIV_ROUND_UP(adapter->sge.ethqsets, QPL);
+ int qs, r = (uintptr_t)v - 1;
+
+ if (r)
+ seq_putc(seq, '\n');
+
+ #define S3(fmt, s, v) \
+ do { \
+ seq_printf(seq, "%-16s", s); \
+ for (qs = 0; qs < n; ++qs) \
+ seq_printf(seq, " %8" fmt, v); \
+ seq_putc(seq, '\n'); \
+ } while (0)
+ #define S(s, v) S3("s", s, v)
+
+ #define T3(fmt, s, v) S3(fmt, s, txq[qs].v)
+ #define T(s, v) T3("lu", s, v)
+
+ #define R3(fmt, s, v) S3(fmt, s, rxq[qs].v)
+ #define R(s, v) R3("lu", s, v)
+
+ if (r < eth_entries) {
+ const struct sge_eth_rxq *rxq = &adapter->sge.ethrxq[r * QPL];
+ const struct sge_eth_txq *txq = &adapter->sge.ethtxq[r * QPL];
+ int n = min(QPL, adapter->sge.ethqsets - QPL * r);
+
+ S("QType:", "Ethernet");
+ S("Interface:",
+ (rxq[qs].rspq.netdev
+ ? rxq[qs].rspq.netdev->name
+ : "N/A"));
+ R3("u", "RspQNullInts:", rspq.unhandled_irqs);
+ R("RxPackets:", stats.pkts);
+ R("RxCSO:", stats.rx_cso);
+ R("VLANxtract:", stats.vlan_ex);
+ R("LROmerged:", stats.lro_merged);
+ R("LROpackets:", stats.lro_pkts);
+ R("RxDrops:", stats.rx_drops);
+ T("TSO:", tso);
+ T("TxCSO:", tx_cso);
+ T("VLANins:", vlan_ins);
+ T("TxQFull:", q.stops);
+ T("TxQRestarts:", q.restarts);
+ T("TxMapErr:", mapping_err);
+ R("FLAllocErr:", fl.alloc_failed);
+ R("FLLrgAlcErr:", fl.large_alloc_failed);
+ R("FLStarving:", fl.starving);
+ return 0;
+ }
+
+ r -= eth_entries;
+ if (r == 0) {
+ const struct sge_rspq *evtq = &adapter->sge.fw_evtq;
+
+ seq_printf(seq, "%-8s %16s\n", "QType:", "FW event queue");
+ seq_printf(seq, "%-16s %8u\n", "RspQNullInts:",
+ evtq->unhandled_irqs);
+ seq_printf(seq, "%-16s %8u\n", "RspQ CIdx:", evtq->cidx);
+ seq_printf(seq, "%-16s %8u\n", "RspQ Gen:", evtq->gen);
+ } else if (r == 1) {
+ const struct sge_rspq *intrq = &adapter->sge.intrq;
+
+ seq_printf(seq, "%-8s %16s\n", "QType:", "Interrupt Queue");
+ seq_printf(seq, "%-16s %8u\n", "RspQNullInts:",
+ intrq->unhandled_irqs);
+ seq_printf(seq, "%-16s %8u\n", "RspQ CIdx:", intrq->cidx);
+ seq_printf(seq, "%-16s %8u\n", "RspQ Gen:", intrq->gen);
+ }
+
+ #undef R
+ #undef T
+ #undef S
+ #undef R3
+ #undef T3
+ #undef S3
+
+ return 0;
+}
+
+/*
+ * Return the number of "entries" in our "file". We group the multi-Queue
+ * sections with QPL Queue Sets per "entry". The sections of the output are:
+ *
+ * Ethernet RX/TX Queue Sets
+ * Firmware Event Queue
+ * Forwarded Interrupt Queue (if in MSI mode)
+ */
+static int sge_qstats_entries(const struct adapter *adapter)
+{
+ return DIV_ROUND_UP(adapter->sge.ethqsets, QPL) + 1 +
+ ((adapter->flags & USING_MSI) != 0);
+}
+
+static void *sge_qstats_start(struct seq_file *seq, loff_t *pos)
+{
+ int entries = sge_qstats_entries(seq->private);
+
+ return *pos < entries ? (void *)((uintptr_t)*pos + 1) : NULL;
+}
+
+static void sge_qstats_stop(struct seq_file *seq, void *v)
+{
+}
+
+static void *sge_qstats_next(struct seq_file *seq, void *v, loff_t *pos)
+{
+ int entries = sge_qstats_entries(seq->private);
+
+ (*pos)++;
+ return *pos < entries ? (void *)((uintptr_t)*pos + 1) : NULL;
+}
+
+static const struct seq_operations sge_qstats_seq_ops = {
+ .start = sge_qstats_start,
+ .next = sge_qstats_next,
+ .stop = sge_qstats_stop,
+ .show = sge_qstats_show
+};
+
+static int sge_qstats_open(struct inode *inode, struct file *file)
+{
+ int res = seq_open(file, &sge_qstats_seq_ops);
+
+ if (res == 0) {
+ struct seq_file *seq = file->private_data;
+ seq->private = inode->i_private;
+ }
+ return res;
+}
+
+static const struct file_operations sge_qstats_proc_fops = {
+ .owner = THIS_MODULE,
+ .open = sge_qstats_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = seq_release,
+};
+
+/*
+ * Show PCI-E SR-IOV Virtual Function Resource Limits.
+ */
+static int resources_show(struct seq_file *seq, void *v)
+{
+ struct adapter *adapter = seq->private;
+ struct vf_resources *vfres = &adapter->params.vfres;
+
+ #define S(desc, fmt, var) \
+ seq_printf(seq, "%-60s " fmt "\n", \
+ desc " (" #var "):", vfres->var)
+
+ S("Virtual Interfaces", "%d", nvi);
+ S("Egress Queues", "%d", neq);
+ S("Ethernet Control", "%d", nethctrl);
+ S("Ingress Queues/w Free Lists/Interrupts", "%d", niqflint);
+ S("Ingress Queues", "%d", niq);
+ S("Traffic Class", "%d", tc);
+ S("Port Access Rights Mask", "%#x", pmask);
+ S("MAC Address Filters", "%d", nexactf);
+ S("Firmware Command Read Capabilities", "%#x", r_caps);
+ S("Firmware Command Write/Execute Capabilities", "%#x", wx_caps);
+
+ #undef S
+
+ return 0;
+}
+
+static int resources_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, resources_show, inode->i_private);
+}
+
+static const struct file_operations resources_proc_fops = {
+ .owner = THIS_MODULE,
+ .open = resources_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+/*
+ * Show Virtual Interfaces.
+ */
+static int interfaces_show(struct seq_file *seq, void *v)
+{
+ if (v == SEQ_START_TOKEN) {
+ seq_puts(seq, "Interface Port VIID\n");
+ } else {
+ struct adapter *adapter = seq->private;
+ int pidx = (uintptr_t)v - 2;
+ struct net_device *dev = adapter->port[pidx];
+ struct port_info *pi = netdev_priv(dev);
+
+ seq_printf(seq, "%9s %4d %#5x\n",
+ dev->name, pi->port_id, pi->viid);
+ }
+ return 0;
+}
+
+static inline void *interfaces_get_idx(struct adapter *adapter, loff_t pos)
+{
+ return pos <= adapter->params.nports
+ ? (void *)(uintptr_t)(pos + 1)
+ : NULL;
+}
+
+static void *interfaces_start(struct seq_file *seq, loff_t *pos)
+{
+ return *pos
+ ? interfaces_get_idx(seq->private, *pos)
+ : SEQ_START_TOKEN;
+}
+
+static void *interfaces_next(struct seq_file *seq, void *v, loff_t *pos)
+{
+ (*pos)++;
+ return interfaces_get_idx(seq->private, *pos);
+}
+
+static void interfaces_stop(struct seq_file *seq, void *v)
+{
+}
+
+static const struct seq_operations interfaces_seq_ops = {
+ .start = interfaces_start,
+ .next = interfaces_next,
+ .stop = interfaces_stop,
+ .show = interfaces_show
+};
+
+static int interfaces_open(struct inode *inode, struct file *file)
+{
+ int res = seq_open(file, &interfaces_seq_ops);
+
+ if (res == 0) {
+ struct seq_file *seq = file->private_data;
+ seq->private = inode->i_private;
+ }
+ return res;
+}
+
+static const struct file_operations interfaces_proc_fops = {
+ .owner = THIS_MODULE,
+ .open = interfaces_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = seq_release,
+};
+
+/*
+ * /sys/kernel/debugfs/cxgb4vf/ files list.
+ */
+struct cxgb4vf_debugfs_entry {
+ const char *name; /* name of debugfs node */
+ mode_t mode; /* file system mode */
+ const struct file_operations *fops;
+};
+
+static struct cxgb4vf_debugfs_entry debugfs_files[] = {
+ { "sge_qinfo", S_IRUGO, &sge_qinfo_debugfs_fops },
+ { "sge_qstats", S_IRUGO, &sge_qstats_proc_fops },
+ { "resources", S_IRUGO, &resources_proc_fops },
+ { "interfaces", S_IRUGO, &interfaces_proc_fops },
+};
+
+/*
+ * Module and device initialization and cleanup code.
+ * ==================================================
+ */
+
+/*
+ * Set up out /sys/kernel/debug/cxgb4vf sub-nodes. We assume that the
+ * directory (debugfs_root) has already been set up.
+ */
+static int __devinit setup_debugfs(struct adapter *adapter)
+{
+ int i;
+
+ BUG_ON(adapter->debugfs_root == NULL);
+
+ /*
+ * Debugfs support is best effort.
+ */
+ for (i = 0; i < ARRAY_SIZE(debugfs_files); i++)
+ (void)debugfs_create_file(debugfs_files[i].name,
+ debugfs_files[i].mode,
+ adapter->debugfs_root,
+ (void *)adapter,
+ debugfs_files[i].fops);
+
+ return 0;
+}
+
+/*
+ * Tear down the /sys/kernel/debug/cxgb4vf sub-nodes created above. We leave
+ * it to our caller to tear down the directory (debugfs_root).
+ */
+static void __devexit cleanup_debugfs(struct adapter *adapter)
+{
+ BUG_ON(adapter->debugfs_root == NULL);
+
+ /*
+ * Unlike our sister routine cleanup_proc(), we don't need to remove
+ * individual entries because a call will be made to
+ * debugfs_remove_recursive(). We just need to clean up any ancillary
+ * persistent state.
+ */
+ /* nothing to do */
+}
+
+/*
+ * Perform early "adapter" initialization. This is where we discover what
+ * adapter parameters we're going to be using and initialize basic adapter
+ * hardware support.
+ */
+static int adap_init0(struct adapter *adapter)
+{
+ struct vf_resources *vfres = &adapter->params.vfres;
+ struct sge_params *sge_params = &adapter->params.sge;
+ struct sge *s = &adapter->sge;
+ unsigned int ethqsets;
+ int err;
+
+ /*
+ * Wait for the device to become ready before proceeding ...
+ */
+ err = t4vf_wait_dev_ready(adapter);
+ if (err) {
+ dev_err(adapter->pdev_dev, "device didn't become ready:"
+ " err=%d\n", err);
+ return err;
+ }
+
+ /*
+ * Grab basic operational parameters. These will predominantly have
+ * been set up by the Physical Function Driver or will be hard coded
+ * into the adapter. We just have to live with them ... Note that
+ * we _must_ get our VPD parameters before our SGE parameters because
+ * we need to know the adapter's core clock from the VPD in order to
+ * properly decode the SGE Timer Values.
+ */
+ err = t4vf_get_dev_params(adapter);
+ if (err) {
+ dev_err(adapter->pdev_dev, "unable to retrieve adapter"
+ " device parameters: err=%d\n", err);
+ return err;
+ }
+ err = t4vf_get_vpd_params(adapter);
+ if (err) {
+ dev_err(adapter->pdev_dev, "unable to retrieve adapter"
+ " VPD parameters: err=%d\n", err);
+ return err;
+ }
+ err = t4vf_get_sge_params(adapter);
+ if (err) {
+ dev_err(adapter->pdev_dev, "unable to retrieve adapter"
+ " SGE parameters: err=%d\n", err);
+ return err;
+ }
+ err = t4vf_get_rss_glb_config(adapter);
+ if (err) {
+ dev_err(adapter->pdev_dev, "unable to retrieve adapter"
+ " RSS parameters: err=%d\n", err);
+ return err;
+ }
+ if (adapter->params.rss.mode !=
+ FW_RSS_GLB_CONFIG_CMD_MODE_BASICVIRTUAL) {
+ dev_err(adapter->pdev_dev, "unable to operate with global RSS"
+ " mode %d\n", adapter->params.rss.mode);
+ return -EINVAL;
+ }
+ err = t4vf_sge_init(adapter);
+ if (err) {
+ dev_err(adapter->pdev_dev, "unable to use adapter parameters:"
+ " err=%d\n", err);
+ return err;
+ }
+
+ /*
+ * Retrieve our RX interrupt holdoff timer values and counter
+ * threshold values from the SGE parameters.
+ */
+ s->timer_val[0] = core_ticks_to_us(adapter,
+ TIMERVALUE0_GET(sge_params->sge_timer_value_0_and_1));
+ s->timer_val[1] = core_ticks_to_us(adapter,
+ TIMERVALUE1_GET(sge_params->sge_timer_value_0_and_1));
+ s->timer_val[2] = core_ticks_to_us(adapter,
+ TIMERVALUE0_GET(sge_params->sge_timer_value_2_and_3));
+ s->timer_val[3] = core_ticks_to_us(adapter,
+ TIMERVALUE1_GET(sge_params->sge_timer_value_2_and_3));
+ s->timer_val[4] = core_ticks_to_us(adapter,
+ TIMERVALUE0_GET(sge_params->sge_timer_value_4_and_5));
+ s->timer_val[5] = core_ticks_to_us(adapter,
+ TIMERVALUE1_GET(sge_params->sge_timer_value_4_and_5));
+
+ s->counter_val[0] =
+ THRESHOLD_0_GET(sge_params->sge_ingress_rx_threshold);
+ s->counter_val[1] =
+ THRESHOLD_1_GET(sge_params->sge_ingress_rx_threshold);
+ s->counter_val[2] =
+ THRESHOLD_2_GET(sge_params->sge_ingress_rx_threshold);
+ s->counter_val[3] =
+ THRESHOLD_3_GET(sge_params->sge_ingress_rx_threshold);
+
+ /*
+ * Grab our Virtual Interface resource allocation, extract the
+ * features that we're interested in and do a bit of sanity testing on
+ * what we discover.
+ */
+ err = t4vf_get_vfres(adapter);
+ if (err) {
+ dev_err(adapter->pdev_dev, "unable to get virtual interface"
+ " resources: err=%d\n", err);
+ return err;
+ }
+
+ /*
+ * The number of "ports" which we support is equal to the number of
+ * Virtual Interfaces with which we've been provisioned.
+ */
+ adapter->params.nports = vfres->nvi;
+ if (adapter->params.nports > MAX_NPORTS) {
+ dev_warn(adapter->pdev_dev, "only using %d of %d allowed"
+ " virtual interfaces\n", MAX_NPORTS,
+ adapter->params.nports);
+ adapter->params.nports = MAX_NPORTS;
+ }
+
+ /*
+ * We need to reserve a number of the ingress queues with Free List
+ * and Interrupt capabilities for special interrupt purposes (like
+ * asynchronous firmware messages, or forwarded interrupts if we're
+ * using MSI). The rest of the FL/Intr-capable ingress queues will be
+ * matched up one-for-one with Ethernet/Control egress queues in order
+ * to form "Queue Sets" which will be aportioned between the "ports".
+ * For each Queue Set, we'll need the ability to allocate two Egress
+ * Contexts -- one for the Ingress Queue Free List and one for the TX
+ * Ethernet Queue.
+ */
+ ethqsets = vfres->niqflint - INGQ_EXTRAS;
+ if (vfres->nethctrl != ethqsets) {
+ dev_warn(adapter->pdev_dev, "unequal number of [available]"
+ " ingress/egress queues (%d/%d); using minimum for"
+ " number of Queue Sets\n", ethqsets, vfres->nethctrl);
+ ethqsets = min(vfres->nethctrl, ethqsets);
+ }
+ if (vfres->neq < ethqsets*2) {
+ dev_warn(adapter->pdev_dev, "Not enough Egress Contexts (%d)"
+ " to support Queue Sets (%d); reducing allowed Queue"
+ " Sets\n", vfres->neq, ethqsets);
+ ethqsets = vfres->neq/2;
+ }
+ if (ethqsets > MAX_ETH_QSETS) {
+ dev_warn(adapter->pdev_dev, "only using %d of %d allowed Queue"
+ " Sets\n", MAX_ETH_QSETS, adapter->sge.max_ethqsets);
+ ethqsets = MAX_ETH_QSETS;
+ }
+ if (vfres->niq != 0 || vfres->neq > ethqsets*2) {
+ dev_warn(adapter->pdev_dev, "unused resources niq/neq (%d/%d)"
+ " ignored\n", vfres->niq, vfres->neq - ethqsets*2);
+ }
+ adapter->sge.max_ethqsets = ethqsets;
+
+ /*
+ * Check for various parameter sanity issues. Most checks simply
+ * result in us using fewer resources than our provissioning but we
+ * do need at least one "port" with which to work ...
+ */
+ if (adapter->sge.max_ethqsets < adapter->params.nports) {
+ dev_warn(adapter->pdev_dev, "only using %d of %d available"
+ " virtual interfaces (too few Queue Sets)\n",
+ adapter->sge.max_ethqsets, adapter->params.nports);
+ adapter->params.nports = adapter->sge.max_ethqsets;
+ }
+ if (adapter->params.nports == 0) {
+ dev_err(adapter->pdev_dev, "no virtual interfaces configured/"
+ "usable!\n");
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static inline void init_rspq(struct sge_rspq *rspq, u8 timer_idx,
+ u8 pkt_cnt_idx, unsigned int size,
+ unsigned int iqe_size)
+{
+ rspq->intr_params = (QINTR_TIMER_IDX(timer_idx) |
+ (pkt_cnt_idx < SGE_NCOUNTERS ? QINTR_CNT_EN : 0));
+ rspq->pktcnt_idx = (pkt_cnt_idx < SGE_NCOUNTERS
+ ? pkt_cnt_idx
+ : 0);
+ rspq->iqe_len = iqe_size;
+ rspq->size = size;
+}
+
+/*
+ * Perform default configuration of DMA queues depending on the number and
+ * type of ports we found and the number of available CPUs. Most settings can
+ * be modified by the admin via ethtool and cxgbtool prior to the adapter
+ * being brought up for the first time.
+ */
+static void __devinit cfg_queues(struct adapter *adapter)
+{
+ struct sge *s = &adapter->sge;
+ int q10g, n10g, qidx, pidx, qs;
+
+ /*
+ * We should not be called till we know how many Queue Sets we can
+ * support. In particular, this means that we need to know what kind
+ * of interrupts we'll be using ...
+ */
+ BUG_ON((adapter->flags & (USING_MSIX|USING_MSI)) == 0);
+
+ /*
+ * Count the number of 10GbE Virtual Interfaces that we have.
+ */
+ n10g = 0;
+ for_each_port(adapter, pidx)
+ n10g += is_10g_port(&adap2pinfo(adapter, pidx)->link_cfg);
+
+ /*
+ * We default to 1 queue per non-10G port and up to # of cores queues
+ * per 10G port.
+ */
+ if (n10g == 0)
+ q10g = 0;
+ else {
+ int n1g = (adapter->params.nports - n10g);
+ q10g = (adapter->sge.max_ethqsets - n1g) / n10g;
+ if (q10g > num_online_cpus())
+ q10g = num_online_cpus();
+ }
+
+ /*
+ * Allocate the "Queue Sets" to the various Virtual Interfaces.
+ * The layout will be established in setup_sge_queues() when the
+ * adapter is brough up for the first time.
+ */
+ qidx = 0;
+ for_each_port(adapter, pidx) {
+ struct port_info *pi = adap2pinfo(adapter, pidx);
+
+ pi->first_qset = qidx;
+ pi->nqsets = is_10g_port(&pi->link_cfg) ? q10g : 1;
+ qidx += pi->nqsets;
+ }
+ s->ethqsets = qidx;
+
+ /*
+ * Set up default Queue Set parameters ... Start off with the
+ * shortest interrupt holdoff timer.
+ */
+ for (qs = 0; qs < s->max_ethqsets; qs++) {
+ struct sge_eth_rxq *rxq = &s->ethrxq[qs];
+ struct sge_eth_txq *txq = &s->ethtxq[qs];
+
+ init_rspq(&rxq->rspq, 0, 0, 1024, L1_CACHE_BYTES);
+ rxq->fl.size = 72;
+ txq->q.size = 1024;
+ }
+
+ /*
+ * The firmware event queue is used for link state changes and
+ * notifications of TX DMA completions.
+ */
+ init_rspq(&s->fw_evtq, SGE_TIMER_RSTRT_CNTR, 0, 512,
+ L1_CACHE_BYTES);
+
+ /*
+ * The forwarded interrupt queue is used when we're in MSI interrupt
+ * mode. In this mode all interrupts associated with RX queues will
+ * be forwarded to a single queue which we'll associate with our MSI
+ * interrupt vector. The messages dropped in the forwarded interrupt
+ * queue will indicate which ingress queue needs servicing ... This
+ * queue needs to be large enough to accommodate all of the ingress
+ * queues which are forwarding their interrupt (+1 to prevent the PIDX
+ * from equalling the CIDX if every ingress queue has an outstanding
+ * interrupt). The queue doesn't need to be any larger because no
+ * ingress queue will ever have more than one outstanding interrupt at
+ * any time ...
+ */
+ init_rspq(&s->intrq, SGE_TIMER_RSTRT_CNTR, 0, MSIX_ENTRIES + 1,
+ L1_CACHE_BYTES);
+}
+
+/*
+ * Reduce the number of Ethernet queues across all ports to at most n.
+ * n provides at least one queue per port.
+ */
+static void __devinit reduce_ethqs(struct adapter *adapter, int n)
+{
+ int i;
+ struct port_info *pi;
+
+ /*
+ * While we have too many active Ether Queue Sets, interate across the
+ * "ports" and reduce their individual Queue Set allocations.
+ */
+ BUG_ON(n < adapter->params.nports);
+ while (n < adapter->sge.ethqsets)
+ for_each_port(adapter, i) {
+ pi = adap2pinfo(adapter, i);
+ if (pi->nqsets > 1) {
+ pi->nqsets--;
+ adapter->sge.ethqsets--;
+ if (adapter->sge.ethqsets <= n)
+ break;
+ }
+ }
+
+ /*
+ * Reassign the starting Queue Sets for each of the "ports" ...
+ */
+ n = 0;
+ for_each_port(adapter, i) {
+ pi = adap2pinfo(adapter, i);
+ pi->first_qset = n;
+ n += pi->nqsets;
+ }
+}
+
+/*
+ * We need to grab enough MSI-X vectors to cover our interrupt needs. Ideally
+ * we get a separate MSI-X vector for every "Queue Set" plus any extras we
+ * need. Minimally we need one for every Virtual Interface plus those needed
+ * for our "extras". Note that this process may lower the maximum number of
+ * allowed Queue Sets ...
+ */
+static int __devinit enable_msix(struct adapter *adapter)
+{
+ int i, err, want, need;
+ struct msix_entry entries[MSIX_ENTRIES];
+ struct sge *s = &adapter->sge;
+
+ for (i = 0; i < MSIX_ENTRIES; ++i)
+ entries[i].entry = i;
+
+ /*
+ * We _want_ enough MSI-X interrupts to cover all of our "Queue Sets"
+ * plus those needed for our "extras" (for example, the firmware
+ * message queue). We _need_ at least one "Queue Set" per Virtual
+ * Interface plus those needed for our "extras". So now we get to see
+ * if the song is right ...
+ */
+ want = s->max_ethqsets + MSIX_EXTRAS;
+ need = adapter->params.nports + MSIX_EXTRAS;
+ while ((err = pci_enable_msix(adapter->pdev, entries, want)) >= need)
+ want = err;
+
+ if (err == 0) {
+ int nqsets = want - MSIX_EXTRAS;
+ if (nqsets < s->max_ethqsets) {
+ dev_warn(adapter->pdev_dev, "only enough MSI-X vectors"
+ " for %d Queue Sets\n", nqsets);
+ s->max_ethqsets = nqsets;
+ if (nqsets < s->ethqsets)
+ reduce_ethqs(adapter, nqsets);
+ }
+ for (i = 0; i < want; ++i)
+ adapter->msix_info[i].vec = entries[i].vector;
+ } else if (err > 0) {
+ pci_disable_msix(adapter->pdev);
+ dev_info(adapter->pdev_dev, "only %d MSI-X vectors left,"
+ " not using MSI-X\n", err);
+ }
+ return err;
+}
+
+#ifdef HAVE_NET_DEVICE_OPS
+static const struct net_device_ops cxgb4vf_netdev_ops = {
+ .ndo_open = cxgb4vf_open,
+ .ndo_stop = cxgb4vf_stop,
+ .ndo_start_xmit = t4vf_eth_xmit,
+ .ndo_get_stats = cxgb4vf_get_stats,
+ .ndo_set_rx_mode = cxgb4vf_set_rxmode,
+ .ndo_set_mac_address = cxgb4vf_set_mac_addr,
+ .ndo_select_queue = cxgb4vf_select_queue,
+ .ndo_validate_addr = eth_validate_addr,
+ .ndo_do_ioctl = cxgb4vf_do_ioctl,
+ .ndo_change_mtu = cxgb4vf_change_mtu,
+ .ndo_vlan_rx_register = cxgb4vf_vlan_rx_register,
+#ifdef CONFIG_NET_POLL_CONTROLLER
+ .ndo_poll_controller = cxgb4vf_poll_controller,
+#endif
+};
+#endif
+
+/*
+ * "Probe" a device: initialize a device and construct all kernel and driver
+ * state needed to manage the device. This routine is called "init_one" in
+ * the PF Driver ...
+ */
+static int __devinit cxgb4vf_pci_probe(struct pci_dev *pdev,
+ const struct pci_device_id *ent)
+{
+ static int version_printed;
+
+ int pci_using_dac;
+ int err, pidx;
+ unsigned int pmask;
+ struct adapter *adapter;
+ struct port_info *pi;
+ struct net_device *netdev;
+
+ /*
+ * Vet our module parameters.
+ */
+ if (msi != MSI_MSIX && msi != MSI_MSI) {
+ dev_err(&pdev->dev, "bad module parameter msi=%d; must be %d"
+ " (MSI-X or MSI) or %d (MSI)\n", msi, MSI_MSIX,
+ MSI_MSI);
+ err = -EINVAL;
+ goto err_out;
+ }
+
+ /*
+ * Print our driver banner the first time we're called to initialize a
+ * device.
+ */
+ if (version_printed == 0) {
+ printk(KERN_INFO "%s - version %s\n", DRV_DESC, DRV_VERSION);
+ version_printed = 1;
+ }
+
+ /*
+ * Reserve PCI resources for the device. If we can't get them some
+ * other driver may have already claimed the device ...
+ */
+ err = pci_request_regions(pdev, KBUILD_MODNAME);
+ if (err) {
+ dev_err(&pdev->dev, "cannot obtain PCI resources\n");
+ return err;
+ }
+
+ /*
+ * Initialize generic PCI device state.
+ */
+ err = pci_enable_device(pdev);
+ if (err) {
+ dev_err(&pdev->dev, "cannot enable PCI device\n");
+ goto err_release_regions;
+ }
+
+ /*
+ * Set up our DMA mask: try for 64-bit address masking first and
+ * fall back to 32-bit if we can't get 64 bits ...
+ */
+ err = pci_set_dma_mask(pdev, DMA_BIT_MASK(64));
+ if (err == 0) {
+ err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64));
+ if (err) {
+ dev_err(&pdev->dev, "unable to obtain 64-bit DMA for"
+ " coherent allocations\n");
+ goto err_disable_device;
+ }
+ pci_using_dac = 1;
+ } else {
+ err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
+ if (err != 0) {
+ dev_err(&pdev->dev, "no usable DMA configuration\n");
+ goto err_disable_device;
+ }
+ pci_using_dac = 0;
+ }
+
+ /*
+ * Enable bus mastering for the device ...
+ */
+ pci_set_master(pdev);
+
+ /*
+ * Allocate our adapter data structure and attach it to the device.
+ */
+ adapter = kzalloc(sizeof(*adapter), GFP_KERNEL);
+ if (!adapter) {
+ err = -ENOMEM;
+ goto err_disable_device;
+ }
+ pci_set_drvdata(pdev, adapter);
+ adapter->pdev = pdev;
+ adapter->pdev_dev = &pdev->dev;
+
+ /*
+ * Initialize SMP data synchronization resources.
+ */
+ spin_lock_init(&adapter->stats_lock);
+
+ /*
+ * Map our I/O registers in BAR0.
+ */
+ adapter->regs = pci_ioremap_bar(pdev, 0);
+ if (!adapter->regs) {
+ dev_err(&pdev->dev, "cannot map device registers\n");
+ err = -ENOMEM;
+ goto err_free_adapter;
+ }
+
+ /*
+ * Initialize adapter level features.
+ */
+ adapter->name = pci_name(pdev);
+ adapter->msg_enable = dflt_msg_enable;
+ err = adap_init0(adapter);
+ if (err)
+ goto err_unmap_bar;
+
+ /*
+ * Allocate our "adapter ports" and stitch everything together.
+ */
+ pmask = adapter->params.vfres.pmask;
+ for_each_port(adapter, pidx) {
+ int port_id, viid;
+
+ /*
+ * We simplistically allocate our virtual interfaces
+ * sequentially across the port numbers to which we have
+ * access rights. This should be configurable in some manner
+ * ...
+ */
+ if (pmask == 0)
+ break;
+ port_id = ffs(pmask) - 1;
+ pmask &= ~(1 << port_id);
+ viid = t4vf_alloc_vi(adapter, port_id);
+ if (viid < 0) {
+ dev_err(&pdev->dev, "cannot allocate VI for port %d:"
+ " err=%d\n", port_id, viid);
+ err = viid;
+ goto err_free_dev;
+ }
+
+ /*
+ * Allocate our network device and stitch things together.
+ */
+ netdev = alloc_etherdev_mq(sizeof(struct port_info),
+ MAX_PORT_QSETS);
+ if (netdev == NULL) {
+ dev_err(&pdev->dev, "cannot allocate netdev for"
+ " port %d\n", port_id);
+ t4vf_free_vi(adapter, viid);
+ err = -ENOMEM;
+ goto err_free_dev;
+ }
+ adapter->port[pidx] = netdev;
+ SET_NETDEV_DEV(netdev, &pdev->dev);
+ pi = netdev_priv(netdev);
+ pi->adapter = adapter;
+ pi->pidx = pidx;
+ pi->port_id = port_id;
+ pi->viid = viid;
+
+ /*
+ * Initialize the starting state of our "port" and register
+ * it.
+ */
+ pi->xact_addr_filt = -1;
+ pi->rx_offload = RX_CSO;
+ netif_carrier_off(netdev);
+ netif_tx_stop_all_queues(netdev);
+ netdev->irq = pdev->irq;
+
+ netdev->features = (NETIF_F_SG | NETIF_F_TSO | NETIF_F_TSO6 |
+ NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
+ NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX |
+ NETIF_F_GRO);
+ if (pci_using_dac)
+ netdev->features |= NETIF_F_HIGHDMA;
+ netdev->vlan_features =
+ (netdev->features &
+ ~(NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX));
+
+#ifdef HAVE_NET_DEVICE_OPS
+ netdev->netdev_ops = &cxgb4vf_netdev_ops;
+#else
+ netdev->vlan_rx_register = cxgb4vf_vlan_rx_register;
+ netdev->open = cxgb4vf_open;
+ netdev->stop = cxgb4vf_stop;
+ netdev->hard_start_xmit = t4vf_eth_xmit;
+ netdev->get_stats = cxgb4vf_get_stats;
+ netdev->set_rx_mode = cxgb4vf_set_rxmode;
+ netdev->do_ioctl = cxgb4vf_do_ioctl;
+ netdev->change_mtu = cxgb4vf_change_mtu;
+ netdev->set_mac_address = cxgb4vf_set_mac_addr;
+ netdev->select_queue = cxgb4vf_select_queue;
+#ifdef CONFIG_NET_POLL_CONTROLLER
+ netdev->poll_controller = cxgb4vf_poll_controller;
+#endif
+#endif
+ SET_ETHTOOL_OPS(netdev, &cxgb4vf_ethtool_ops);
+
+ /*
+ * Initialize the hardware/software state for the port.
+ */
+ err = t4vf_port_init(adapter, pidx);
+ if (err) {
+ dev_err(&pdev->dev, "cannot initialize port %d\n",
+ pidx);
+ goto err_free_dev;
+ }
+ }
+
+ /*
+ * The "card" is now ready to go. If any errors occur during device
+ * registration we do not fail the whole "card" but rather proceed
+ * only with the ports we manage to register successfully. However we
+ * must register at least one net device.
+ */
+ for_each_port(adapter, pidx) {
+ netdev = adapter->port[pidx];
+ if (netdev == NULL)
+ continue;
+
+ err = register_netdev(netdev);
+ if (err) {
+ dev_warn(&pdev->dev, "cannot register net device %s,"
+ " skipping\n", netdev->name);
+ continue;
+ }
+
+ set_bit(pidx, &adapter->registered_device_map);
+ }
+ if (adapter->registered_device_map == 0) {
+ dev_err(&pdev->dev, "could not register any net devices\n");
+ goto err_free_dev;
+ }
+
+ /*
+ * Set up our debugfs entries.
+ */
+ if (cxgb4vf_debugfs_root) {
+ adapter->debugfs_root =
+ debugfs_create_dir(pci_name(pdev),
+ cxgb4vf_debugfs_root);
+ if (adapter->debugfs_root == NULL)
+ dev_warn(&pdev->dev, "could not create debugfs"
+ " directory");
+ else
+ setup_debugfs(adapter);
+ }
+
+ /*
+ * See what interrupts we'll be using. If we've been configured to
+ * use MSI-X interrupts, try to enable them but fall back to using
+ * MSI interrupts if we can't enable MSI-X interrupts. If we can't
+ * get MSI interrupts we bail with the error.
+ */
+ if (msi == MSI_MSIX && enable_msix(adapter) == 0)
+ adapter->flags |= USING_MSIX;
+ else {
+ err = pci_enable_msi(pdev);
+ if (err) {
+ dev_err(&pdev->dev, "Unable to allocate %s interrupts;"
+ " err=%d\n",
+ msi == MSI_MSIX ? "MSI-X or MSI" : "MSI", err);
+ goto err_free_debugfs;
+ }
+ adapter->flags |= USING_MSI;
+ }
+
+ /*
+ * Now that we know how many "ports" we have and what their types are,
+ * and how many Queue Sets we can support, we can configure our queue
+ * resources.
+ */
+ cfg_queues(adapter);
+
+ /*
+ * Print a short notice on the existance and configuration of the new
+ * VF network device ...
+ */
+ for_each_port(adapter, pidx) {
+ dev_info(adapter->pdev_dev, "%s: Chelsio VF NIC PCIe %s\n",
+ adapter->port[pidx]->name,
+ (adapter->flags & USING_MSIX) ? "MSI-X" :
+ (adapter->flags & USING_MSI) ? "MSI" : "");
+ }
+
+ /*
+ * Return success!
+ */
+ return 0;
+
+ /*
+ * Error recovery and exit code. Unwind state that's been created
+ * so far and return the error.
+ */
+
+err_free_debugfs:
+ if (adapter->debugfs_root) {
+ cleanup_debugfs(adapter);
+ debugfs_remove_recursive(adapter->debugfs_root);
+ }
+
+err_free_dev:
+ for_each_port(adapter, pidx) {
+ netdev = adapter->port[pidx];
+ if (netdev == NULL)
+ continue;
+ pi = netdev_priv(netdev);
+ t4vf_free_vi(adapter, pi->viid);
+ if (test_bit(pidx, &adapter->registered_device_map))
+ unregister_netdev(netdev);
+ free_netdev(netdev);
+ }
+
+err_unmap_bar:
+ iounmap(adapter->regs);
+
+err_free_adapter:
+ kfree(adapter);
+ pci_set_drvdata(pdev, NULL);
+
+err_disable_device:
+ pci_disable_device(pdev);
+ pci_clear_master(pdev);
+
+err_release_regions:
+ pci_release_regions(pdev);
+ pci_set_drvdata(pdev, NULL);
+
+err_out:
+ return err;
+}
+
+/*
+ * "Remove" a device: tear down all kernel and driver state created in the
+ * "probe" routine and quiesce the device (disable interrupts, etc.). (Note
+ * that this is called "remove_one" in the PF Driver.)
+ */
+static void __devexit cxgb4vf_pci_remove(struct pci_dev *pdev)
+{
+ struct adapter *adapter = pci_get_drvdata(pdev);
+
+ /*
+ * Tear down driver state associated with device.
+ */
+ if (adapter) {
+ int pidx;
+
+ /*
+ * Stop all of our activity. Unregister network port,
+ * disable interrupts, etc.
+ */
+ for_each_port(adapter, pidx)
+ if (test_bit(pidx, &adapter->registered_device_map))
+ unregister_netdev(adapter->port[pidx]);
+ t4vf_sge_stop(adapter);
+ if (adapter->flags & USING_MSIX) {
+ pci_disable_msix(adapter->pdev);
+ adapter->flags &= ~USING_MSIX;
+ } else if (adapter->flags & USING_MSI) {
+ pci_disable_msi(adapter->pdev);
+ adapter->flags &= ~USING_MSI;
+ }
+
+ /*
+ * Tear down our debugfs entries.
+ */
+ if (adapter->debugfs_root) {
+ cleanup_debugfs(adapter);
+ debugfs_remove_recursive(adapter->debugfs_root);
+ }
+
+ /*
+ * Free all of the various resources which we've acquired ...
+ */
+ t4vf_free_sge_resources(adapter);
+ for_each_port(adapter, pidx) {
+ struct net_device *netdev = adapter->port[pidx];
+ struct port_info *pi;
+
+ if (netdev == NULL)
+ continue;
+
+ pi = netdev_priv(netdev);
+ t4vf_free_vi(adapter, pi->viid);
+ free_netdev(netdev);
+ }
+ iounmap(adapter->regs);
+ kfree(adapter);
+ pci_set_drvdata(pdev, NULL);
+ }
+
+ /*
+ * Disable the device and release its PCI resources.
+ */
+ pci_disable_device(pdev);
+ pci_clear_master(pdev);
+ pci_release_regions(pdev);
+}
+
+/*
+ * PCI Device registration data structures.
+ */
+#define CH_DEVICE(devid, idx) \
+ { PCI_VENDOR_ID_CHELSIO, devid, PCI_ANY_ID, PCI_ANY_ID, 0, 0, idx }
+
+static struct pci_device_id cxgb4vf_pci_tbl[] = {
+ CH_DEVICE(0xb000, 0), /* PE10K FPGA */
+ CH_DEVICE(0x4800, 0), /* T440-dbg */
+ CH_DEVICE(0x4801, 0), /* T420-cr */
+ CH_DEVICE(0x4802, 0), /* T422-cr */
+ { 0, }
+};
+
+MODULE_DESCRIPTION(DRV_DESC);
+MODULE_AUTHOR("Chelsio Communications");
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_VERSION(DRV_VERSION);
+MODULE_DEVICE_TABLE(pci, cxgb4vf_pci_tbl);
+
+static struct pci_driver cxgb4vf_driver = {
+ .name = KBUILD_MODNAME,
+ .id_table = cxgb4vf_pci_tbl,
+ .probe = cxgb4vf_pci_probe,
+ .remove = __devexit_p(cxgb4vf_pci_remove),
+};
+
+/*
+ * Initialize global driver state.
+ */
+static int __init cxgb4vf_module_init(void)
+{
+ int ret;
+
+ /* Debugfs support is optional, just warn if this fails */
+ cxgb4vf_debugfs_root = debugfs_create_dir(KBUILD_MODNAME, NULL);
+ if (!cxgb4vf_debugfs_root)
+ printk(KERN_WARNING KBUILD_MODNAME ": could not create"
+ " debugfs entry, continuing\n");
+
+ ret = pci_register_driver(&cxgb4vf_driver);
+ if (ret < 0)
+ debugfs_remove(cxgb4vf_debugfs_root);
+ return ret;
+}
+
+/*
+ * Tear down global driver state.
+ */
+static void __exit cxgb4vf_module_exit(void)
+{
+ pci_unregister_driver(&cxgb4vf_driver);
+ debugfs_remove(cxgb4vf_debugfs_root);
+}
+
+module_init(cxgb4vf_module_init);
+module_exit(cxgb4vf_module_exit);
diff --git a/drivers/net/cxgb4vf/sge.c b/drivers/net/cxgb4vf/sge.c
new file mode 100644
index 00000000000..eb5a1c9cb2d
--- /dev/null
+++ b/drivers/net/cxgb4vf/sge.c
@@ -0,0 +1,2454 @@
+/*
+ * This file is part of the Chelsio T4 PCI-E SR-IOV Virtual Function Ethernet
+ * driver for Linux.
+ *
+ * Copyright (c) 2009-2010 Chelsio Communications, 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.
+ */
+
+#include <linux/skbuff.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/if_vlan.h>
+#include <linux/ip.h>
+#include <net/ipv6.h>
+#include <net/tcp.h>
+#include <linux/dma-mapping.h>
+
+#include "t4vf_common.h"
+#include "t4vf_defs.h"
+
+#include "../cxgb4/t4_regs.h"
+#include "../cxgb4/t4fw_api.h"
+#include "../cxgb4/t4_msg.h"
+
+/*
+ * Decoded Adapter Parameters.
+ */
+static u32 FL_PG_ORDER; /* large page allocation size */
+static u32 STAT_LEN; /* length of status page at ring end */
+static u32 PKTSHIFT; /* padding between CPL and packet data */
+static u32 FL_ALIGN; /* response queue message alignment */
+
+/*
+ * Constants ...
+ */
+enum {
+ /*
+ * Egress Queue sizes, producer and consumer indices are all in units
+ * of Egress Context Units bytes. Note that as far as the hardware is
+ * concerned, the free list is an Egress Queue (the host produces free
+ * buffers which the hardware consumes) and free list entries are
+ * 64-bit PCI DMA addresses.
+ */
+ EQ_UNIT = SGE_EQ_IDXSIZE,
+ FL_PER_EQ_UNIT = EQ_UNIT / sizeof(__be64),
+ TXD_PER_EQ_UNIT = EQ_UNIT / sizeof(__be64),
+
+ /*
+ * Max number of TX descriptors we clean up at a time. Should be
+ * modest as freeing skbs isn't cheap and it happens while holding
+ * locks. We just need to free packets faster than they arrive, we
+ * eventually catch up and keep the amortized cost reasonable.
+ */
+ MAX_TX_RECLAIM = 16,
+
+ /*
+ * Max number of Rx buffers we replenish at a time. Again keep this
+ * modest, allocating buffers isn't cheap either.
+ */
+ MAX_RX_REFILL = 16,
+
+ /*
+ * Period of the Rx queue check timer. This timer is infrequent as it
+ * has something to do only when the system experiences severe memory
+ * shortage.
+ */
+ RX_QCHECK_PERIOD = (HZ / 2),
+
+ /*
+ * Period of the TX queue check timer and the maximum number of TX
+ * descriptors to be reclaimed by the TX timer.
+ */
+ TX_QCHECK_PERIOD = (HZ / 2),
+ MAX_TIMER_TX_RECLAIM = 100,
+
+ /*
+ * An FL with <= FL_STARVE_THRES buffers is starving and a periodic
+ * timer will attempt to refill it.
+ */
+ FL_STARVE_THRES = 4,
+
+ /*
+ * Suspend an Ethernet TX queue with fewer available descriptors than
+ * this. We always want to have room for a maximum sized packet:
+ * inline immediate data + MAX_SKB_FRAGS. This is the same as
+ * calc_tx_flits() for a TSO packet with nr_frags == MAX_SKB_FRAGS
+ * (see that function and its helpers for a description of the
+ * calculation).
+ */
+ ETHTXQ_MAX_FRAGS = MAX_SKB_FRAGS + 1,
+ ETHTXQ_MAX_SGL_LEN = ((3 * (ETHTXQ_MAX_FRAGS-1))/2 +
+ ((ETHTXQ_MAX_FRAGS-1) & 1) +
+ 2),
+ ETHTXQ_MAX_HDR = (sizeof(struct fw_eth_tx_pkt_vm_wr) +
+ sizeof(struct cpl_tx_pkt_lso_core) +
+ sizeof(struct cpl_tx_pkt_core)) / sizeof(__be64),
+ ETHTXQ_MAX_FLITS = ETHTXQ_MAX_SGL_LEN + ETHTXQ_MAX_HDR,
+
+ ETHTXQ_STOP_THRES = 1 + DIV_ROUND_UP(ETHTXQ_MAX_FLITS, TXD_PER_EQ_UNIT),
+
+ /*
+ * Max TX descriptor space we allow for an Ethernet packet to be
+ * inlined into a WR. This is limited by the maximum value which
+ * we can specify for immediate data in the firmware Ethernet TX
+ * Work Request.
+ */
+ MAX_IMM_TX_PKT_LEN = FW_WR_IMMDLEN_MASK,
+
+ /*
+ * Max size of a WR sent through a control TX queue.
+ */
+ MAX_CTRL_WR_LEN = 256,
+
+ /*
+ * Maximum amount of data which we'll ever need to inline into a
+ * TX ring: max(MAX_IMM_TX_PKT_LEN, MAX_CTRL_WR_LEN).
+ */
+ MAX_IMM_TX_LEN = (MAX_IMM_TX_PKT_LEN > MAX_CTRL_WR_LEN
+ ? MAX_IMM_TX_PKT_LEN
+ : MAX_CTRL_WR_LEN),
+
+ /*
+ * For incoming packets less than RX_COPY_THRES, we copy the data into
+ * an skb rather than referencing the data. We allocate enough
+ * in-line room in skb's to accommodate pulling in RX_PULL_LEN bytes
+ * of the data (header).
+ */
+ RX_COPY_THRES = 256,
+ RX_PULL_LEN = 128,
+};
+
+/*
+ * Can't define this in the above enum because PKTSHIFT isn't a constant in
+ * the VF Driver ...
+ */
+#define RX_PKT_PULL_LEN (RX_PULL_LEN + PKTSHIFT)
+
+/*
+ * Software state per TX descriptor.
+ */
+struct tx_sw_desc {
+ struct sk_buff *skb; /* socket buffer of TX data source */
+ struct ulptx_sgl *sgl; /* scatter/gather list in TX Queue */
+};
+
+/*
+ * Software state per RX Free List descriptor. We keep track of the allocated
+ * FL page, its size, and its PCI DMA address (if the page is mapped). The FL
+ * page size and its PCI DMA mapped state are stored in the low bits of the
+ * PCI DMA address as per below.
+ */
+struct rx_sw_desc {
+ struct page *page; /* Free List page buffer */
+ dma_addr_t dma_addr; /* PCI DMA address (if mapped) */
+ /* and flags (see below) */
+};
+
+/*
+ * The low bits of rx_sw_desc.dma_addr have special meaning. Note that the
+ * SGE also uses the low 4 bits to determine the size of the buffer. It uses
+ * those bits to index into the SGE_FL_BUFFER_SIZE[index] register array.
+ * Since we only use SGE_FL_BUFFER_SIZE0 and SGE_FL_BUFFER_SIZE1, these low 4
+ * bits can only contain a 0 or a 1 to indicate which size buffer we're giving
+ * to the SGE. Thus, our software state of "is the buffer mapped for DMA" is
+ * maintained in an inverse sense so the hardware never sees that bit high.
+ */
+enum {
+ RX_LARGE_BUF = 1 << 0, /* buffer is SGE_FL_BUFFER_SIZE[1] */
+ RX_UNMAPPED_BUF = 1 << 1, /* buffer is not mapped */
+};
+
+/**
+ * get_buf_addr - return DMA buffer address of software descriptor
+ * @sdesc: pointer to the software buffer descriptor
+ *
+ * Return the DMA buffer address of a software descriptor (stripping out
+ * our low-order flag bits).
+ */
+static inline dma_addr_t get_buf_addr(const struct rx_sw_desc *sdesc)
+{
+ return sdesc->dma_addr & ~(dma_addr_t)(RX_LARGE_BUF | RX_UNMAPPED_BUF);
+}
+
+/**
+ * is_buf_mapped - is buffer mapped for DMA?
+ * @sdesc: pointer to the software buffer descriptor
+ *
+ * Determine whether the buffer associated with a software descriptor in
+ * mapped for DMA or not.
+ */
+static inline bool is_buf_mapped(const struct rx_sw_desc *sdesc)
+{
+ return !(sdesc->dma_addr & RX_UNMAPPED_BUF);
+}
+
+/**
+ * need_skb_unmap - does the platform need unmapping of sk_buffs?
+ *
+ * Returns true if the platfrom needs sk_buff unmapping. The compiler
+ * optimizes away unecessary code if this returns true.
+ */
+static inline int need_skb_unmap(void)
+{
+#ifdef CONFIG_NEED_DMA_MAP_STATE
+ return 1;
+#else
+ return 0;
+#endif
+}
+
+/**
+ * txq_avail - return the number of available slots in a TX queue
+ * @tq: the TX queue
+ *
+ * Returns the number of available descriptors in a TX queue.
+ */
+static inline unsigned int txq_avail(const struct sge_txq *tq)
+{
+ return tq->size - 1 - tq->in_use;
+}
+
+/**
+ * fl_cap - return the capacity of a Free List
+ * @fl: the Free List
+ *
+ * Returns the capacity of a Free List. The capacity is less than the
+ * size because an Egress Queue Index Unit worth of descriptors needs to
+ * be left unpopulated, otherwise the Producer and Consumer indices PIDX
+ * and CIDX will match and the hardware will think the FL is empty.
+ */
+static inline unsigned int fl_cap(const struct sge_fl *fl)
+{
+ return fl->size - FL_PER_EQ_UNIT;
+}
+
+/**
+ * fl_starving - return whether a Free List is starving.
+ * @fl: the Free List
+ *
+ * Tests specified Free List to see whether the number of buffers
+ * available to the hardware has falled below our "starvation"
+ * threshhold.
+ */
+static inline bool fl_starving(const struct sge_fl *fl)
+{
+ return fl->avail - fl->pend_cred <= FL_STARVE_THRES;
+}
+
+/**
+ * map_skb - map an skb for DMA to the device
+ * @dev: the egress net device
+ * @skb: the packet to map
+ * @addr: a pointer to the base of the DMA mapping array
+ *
+ * Map an skb for DMA to the device and return an array of DMA addresses.
+ */
+static int map_skb(struct device *dev, const struct sk_buff *skb,
+ dma_addr_t *addr)
+{
+ const skb_frag_t *fp, *end;
+ const struct skb_shared_info *si;
+
+ *addr = dma_map_single(dev, skb->data, skb_headlen(skb), DMA_TO_DEVICE);
+ if (dma_mapping_error(dev, *addr))
+ goto out_err;
+
+ si = skb_shinfo(skb);
+ end = &si->frags[si->nr_frags];
+ for (fp = si->frags; fp < end; fp++) {
+ *++addr = dma_map_page(dev, fp->page, fp->page_offset, fp->size,
+ DMA_TO_DEVICE);
+ if (dma_mapping_error(dev, *addr))
+ goto unwind;
+ }
+ return 0;
+
+unwind:
+ while (fp-- > si->frags)
+ dma_unmap_page(dev, *--addr, fp->size, DMA_TO_DEVICE);
+ dma_unmap_single(dev, addr[-1], skb_headlen(skb), DMA_TO_DEVICE);
+
+out_err:
+ return -ENOMEM;
+}
+
+static void unmap_sgl(struct device *dev, const struct sk_buff *skb,
+ const struct ulptx_sgl *sgl, const struct sge_txq *tq)
+{
+ const struct ulptx_sge_pair *p;
+ unsigned int nfrags = skb_shinfo(skb)->nr_frags;
+
+ if (likely(skb_headlen(skb)))
+ dma_unmap_single(dev, be64_to_cpu(sgl->addr0),
+ be32_to_cpu(sgl->len0), DMA_TO_DEVICE);
+ else {
+ dma_unmap_page(dev, be64_to_cpu(sgl->addr0),
+ be32_to_cpu(sgl->len0), DMA_TO_DEVICE);
+ nfrags--;
+ }
+
+ /*
+ * the complexity below is because of the possibility of a wrap-around
+ * in the middle of an SGL
+ */
+ for (p = sgl->sge; nfrags >= 2; nfrags -= 2) {
+ if (likely((u8 *)(p + 1) <= (u8 *)tq->stat)) {
+unmap:
+ dma_unmap_page(dev, be64_to_cpu(p->addr[0]),
+ be32_to_cpu(p->len[0]), DMA_TO_DEVICE);
+ dma_unmap_page(dev, be64_to_cpu(p->addr[1]),
+ be32_to_cpu(p->len[1]), DMA_TO_DEVICE);
+ p++;
+ } else if ((u8 *)p == (u8 *)tq->stat) {
+ p = (const struct ulptx_sge_pair *)tq->desc;
+ goto unmap;
+ } else if ((u8 *)p + 8 == (u8 *)tq->stat) {
+ const __be64 *addr = (const __be64 *)tq->desc;
+
+ dma_unmap_page(dev, be64_to_cpu(addr[0]),
+ be32_to_cpu(p->len[0]), DMA_TO_DEVICE);
+ dma_unmap_page(dev, be64_to_cpu(addr[1]),
+ be32_to_cpu(p->len[1]), DMA_TO_DEVICE);
+ p = (const struct ulptx_sge_pair *)&addr[2];
+ } else {
+ const __be64 *addr = (const __be64 *)tq->desc;
+
+ dma_unmap_page(dev, be64_to_cpu(p->addr[0]),
+ be32_to_cpu(p->len[0]), DMA_TO_DEVICE);
+ dma_unmap_page(dev, be64_to_cpu(addr[0]),
+ be32_to_cpu(p->len[1]), DMA_TO_DEVICE);
+ p = (const struct ulptx_sge_pair *)&addr[1];
+ }
+ }
+ if (nfrags) {
+ __be64 addr;
+
+ if ((u8 *)p == (u8 *)tq->stat)
+ p = (const struct ulptx_sge_pair *)tq->desc;
+ addr = ((u8 *)p + 16 <= (u8 *)tq->stat
+ ? p->addr[0]
+ : *(const __be64 *)tq->desc);
+ dma_unmap_page(dev, be64_to_cpu(addr), be32_to_cpu(p->len[0]),
+ DMA_TO_DEVICE);
+ }
+}
+
+/**
+ * free_tx_desc - reclaims TX descriptors and their buffers
+ * @adapter: the adapter
+ * @tq: the TX queue to reclaim descriptors from
+ * @n: the number of descriptors to reclaim
+ * @unmap: whether the buffers should be unmapped for DMA
+ *
+ * Reclaims TX descriptors from an SGE TX queue and frees the associated
+ * TX buffers. Called with the TX queue lock held.
+ */
+static void free_tx_desc(struct adapter *adapter, struct sge_txq *tq,
+ unsigned int n, bool unmap)
+{
+ struct tx_sw_desc *sdesc;
+ unsigned int cidx = tq->cidx;
+ struct device *dev = adapter->pdev_dev;
+
+ const int need_unmap = need_skb_unmap() && unmap;
+
+ sdesc = &tq->sdesc[cidx];
+ while (n--) {
+ /*
+ * If we kept a reference to the original TX skb, we need to
+ * unmap it from PCI DMA space (if required) and free it.
+ */
+ if (sdesc->skb) {
+ if (need_unmap)
+ unmap_sgl(dev, sdesc->skb, sdesc->sgl, tq);
+ kfree_skb(sdesc->skb);
+ sdesc->skb = NULL;
+ }
+
+ sdesc++;
+ if (++cidx == tq->size) {
+ cidx = 0;
+ sdesc = tq->sdesc;
+ }
+ }
+ tq->cidx = cidx;
+}
+
+/*
+ * Return the number of reclaimable descriptors in a TX queue.
+ */
+static inline int reclaimable(const struct sge_txq *tq)
+{
+ int hw_cidx = be16_to_cpu(tq->stat->cidx);
+ int reclaimable = hw_cidx - tq->cidx;
+ if (reclaimable < 0)
+ reclaimable += tq->size;
+ return reclaimable;
+}
+
+/**
+ * reclaim_completed_tx - reclaims completed TX descriptors
+ * @adapter: the adapter
+ * @tq: the TX queue to reclaim completed descriptors from
+ * @unmap: whether the buffers should be unmapped for DMA
+ *
+ * Reclaims TX descriptors that the SGE has indicated it has processed,
+ * and frees the associated buffers if possible. Called with the TX
+ * queue locked.
+ */
+static inline void reclaim_completed_tx(struct adapter *adapter,
+ struct sge_txq *tq,
+ bool unmap)
+{
+ int avail = reclaimable(tq);
+
+ if (avail) {
+ /*
+ * Limit the amount of clean up work we do at a time to keep
+ * the TX lock hold time O(1).
+ */
+ if (avail > MAX_TX_RECLAIM)
+ avail = MAX_TX_RECLAIM;
+
+ free_tx_desc(adapter, tq, avail, unmap);
+ tq->in_use -= avail;
+ }
+}
+
+/**
+ * get_buf_size - return the size of an RX Free List buffer.
+ * @sdesc: pointer to the software buffer descriptor
+ */
+static inline int get_buf_size(const struct rx_sw_desc *sdesc)
+{
+ return FL_PG_ORDER > 0 && (sdesc->dma_addr & RX_LARGE_BUF)
+ ? (PAGE_SIZE << FL_PG_ORDER)
+ : PAGE_SIZE;
+}
+
+/**
+ * free_rx_bufs - free RX buffers on an SGE Free List
+ * @adapter: the adapter
+ * @fl: the SGE Free List to free buffers from
+ * @n: how many buffers to free
+ *
+ * Release the next @n buffers on an SGE Free List RX queue. The
+ * buffers must be made inaccessible to hardware before calling this
+ * function.
+ */
+static void free_rx_bufs(struct adapter *adapter, struct sge_fl *fl, int n)
+{
+ while (n--) {
+ struct rx_sw_desc *sdesc = &fl->sdesc[fl->cidx];
+
+ if (is_buf_mapped(sdesc))
+ dma_unmap_page(adapter->pdev_dev, get_buf_addr(sdesc),
+ get_buf_size(sdesc), PCI_DMA_FROMDEVICE);
+ put_page(sdesc->page);
+ sdesc->page = NULL;
+ if (++fl->cidx == fl->size)
+ fl->cidx = 0;
+ fl->avail--;
+ }
+}
+
+/**
+ * unmap_rx_buf - unmap the current RX buffer on an SGE Free List
+ * @adapter: the adapter
+ * @fl: the SGE Free List
+ *
+ * Unmap the current buffer on an SGE Free List RX queue. The
+ * buffer must be made inaccessible to HW before calling this function.
+ *
+ * This is similar to @free_rx_bufs above but does not free the buffer.
+ * Do note that the FL still loses any further access to the buffer.
+ * This is used predominantly to "transfer ownership" of an FL buffer
+ * to another entity (typically an skb's fragment list).
+ */
+static void unmap_rx_buf(struct adapter *adapter, struct sge_fl *fl)
+{
+ struct rx_sw_desc *sdesc = &fl->sdesc[fl->cidx];
+
+ if (is_buf_mapped(sdesc))
+ dma_unmap_page(adapter->pdev_dev, get_buf_addr(sdesc),
+ get_buf_size(sdesc), PCI_DMA_FROMDEVICE);
+ sdesc->page = NULL;
+ if (++fl->cidx == fl->size)
+ fl->cidx = 0;
+ fl->avail--;
+}
+
+/**
+ * ring_fl_db - righ doorbell on free list
+ * @adapter: the adapter
+ * @fl: the Free List whose doorbell should be rung ...
+ *
+ * Tell the Scatter Gather Engine that there are new free list entries
+ * available.
+ */
+static inline void ring_fl_db(struct adapter *adapter, struct sge_fl *fl)
+{
+ /*
+ * The SGE keeps track of its Producer and Consumer Indices in terms
+ * of Egress Queue Units so we can only tell it about integral numbers
+ * of multiples of Free List Entries per Egress Queue Units ...
+ */
+ if (fl->pend_cred >= FL_PER_EQ_UNIT) {
+ wmb();
+ t4_write_reg(adapter, T4VF_SGE_BASE_ADDR + SGE_VF_KDOORBELL,
+ DBPRIO |
+ QID(fl->cntxt_id) |
+ PIDX(fl->pend_cred / FL_PER_EQ_UNIT));
+ fl->pend_cred %= FL_PER_EQ_UNIT;
+ }
+}
+
+/**
+ * set_rx_sw_desc - initialize software RX buffer descriptor
+ * @sdesc: pointer to the softwore RX buffer descriptor
+ * @page: pointer to the page data structure backing the RX buffer
+ * @dma_addr: PCI DMA address (possibly with low-bit flags)
+ */
+static inline void set_rx_sw_desc(struct rx_sw_desc *sdesc, struct page *page,
+ dma_addr_t dma_addr)
+{
+ sdesc->page = page;
+ sdesc->dma_addr = dma_addr;
+}
+
+/*
+ * Support for poisoning RX buffers ...
+ */
+#define POISON_BUF_VAL -1
+
+static inline void poison_buf(struct page *page, size_t sz)
+{
+#if POISON_BUF_VAL >= 0
+ memset(page_address(page), POISON_BUF_VAL, sz);
+#endif
+}
+
+/**
+ * refill_fl - refill an SGE RX buffer ring
+ * @adapter: the adapter
+ * @fl: the Free List ring to refill
+ * @n: the number of new buffers to allocate
+ * @gfp: the gfp flags for the allocations
+ *
+ * (Re)populate an SGE free-buffer queue with up to @n new packet buffers,
+ * allocated with the supplied gfp flags. The caller must assure that
+ * @n does not exceed the queue's capacity -- i.e. (cidx == pidx) _IN
+ * EGRESS QUEUE UNITS_ indicates an empty Free List! Returns the number
+ * of buffers allocated. If afterwards the queue is found critically low,
+ * mark it as starving in the bitmap of starving FLs.
+ */
+static unsigned int refill_fl(struct adapter *adapter, struct sge_fl *fl,
+ int n, gfp_t gfp)
+{
+ struct page *page;
+ dma_addr_t dma_addr;
+ unsigned int cred = fl->avail;
+ __be64 *d = &fl->desc[fl->pidx];
+ struct rx_sw_desc *sdesc = &fl->sdesc[fl->pidx];
+
+ /*
+ * Sanity: ensure that the result of adding n Free List buffers
+ * won't result in wrapping the SGE's Producer Index around to
+ * it's Consumer Index thereby indicating an empty Free List ...
+ */
+ BUG_ON(fl->avail + n > fl->size - FL_PER_EQ_UNIT);
+
+ /*
+ * If we support large pages, prefer large buffers and fail over to
+ * small pages if we can't allocate large pages to satisfy the refill.
+ * If we don't support large pages, drop directly into the small page
+ * allocation code.
+ */
+ if (FL_PG_ORDER == 0)
+ goto alloc_small_pages;
+
+ while (n) {
+ page = alloc_pages(gfp | __GFP_COMP | __GFP_NOWARN,
+ FL_PG_ORDER);
+ if (unlikely(!page)) {
+ /*
+ * We've failed inour attempt to allocate a "large
+ * page". Fail over to the "small page" allocation
+ * below.
+ */
+ fl->large_alloc_failed++;
+ break;
+ }
+ poison_buf(page, PAGE_SIZE << FL_PG_ORDER);
+
+ dma_addr = dma_map_page(adapter->pdev_dev, page, 0,
+ PAGE_SIZE << FL_PG_ORDER,
+ PCI_DMA_FROMDEVICE);
+ if (unlikely(dma_mapping_error(adapter->pdev_dev, dma_addr))) {
+ /*
+ * We've run out of DMA mapping space. Free up the
+ * buffer and return with what we've managed to put
+ * into the free list. We don't want to fail over to
+ * the small page allocation below in this case
+ * because DMA mapping resources are typically
+ * critical resources once they become scarse.
+ */
+ __free_pages(page, FL_PG_ORDER);
+ goto out;
+ }
+ dma_addr |= RX_LARGE_BUF;
+ *d++ = cpu_to_be64(dma_addr);
+
+ set_rx_sw_desc(sdesc, page, dma_addr);
+ sdesc++;
+
+ fl->avail++;
+ if (++fl->pidx == fl->size) {
+ fl->pidx = 0;
+ sdesc = fl->sdesc;
+ d = fl->desc;
+ }
+ n--;
+ }
+
+alloc_small_pages:
+ while (n--) {
+ page = __netdev_alloc_page(adapter->port[0],
+ gfp | __GFP_NOWARN);
+ if (unlikely(!page)) {
+ fl->alloc_failed++;
+ break;
+ }
+ poison_buf(page, PAGE_SIZE);
+
+ dma_addr = dma_map_page(adapter->pdev_dev, page, 0, PAGE_SIZE,
+ PCI_DMA_FROMDEVICE);
+ if (unlikely(dma_mapping_error(adapter->pdev_dev, dma_addr))) {
+ netdev_free_page(adapter->port[0], page);
+ break;
+ }
+ *d++ = cpu_to_be64(dma_addr);
+
+ set_rx_sw_desc(sdesc, page, dma_addr);
+ sdesc++;
+
+ fl->avail++;
+ if (++fl->pidx == fl->size) {
+ fl->pidx = 0;
+ sdesc = fl->sdesc;
+ d = fl->desc;
+ }
+ }
+
+out:
+ /*
+ * Update our accounting state to incorporate the new Free List
+ * buffers, tell the hardware about them and return the number of
+ * bufers which we were able to allocate.
+ */
+ cred = fl->avail - cred;
+ fl->pend_cred += cred;
+ ring_fl_db(adapter, fl);
+
+ if (unlikely(fl_starving(fl))) {
+ smp_wmb();
+ set_bit(fl->cntxt_id, adapter->sge.starving_fl);
+ }
+
+ return cred;
+}
+
+/*
+ * Refill a Free List to its capacity or the Maximum Refill Increment,
+ * whichever is smaller ...
+ */
+static inline void __refill_fl(struct adapter *adapter, struct sge_fl *fl)
+{
+ refill_fl(adapter, fl,
+ min((unsigned int)MAX_RX_REFILL, fl_cap(fl) - fl->avail),
+ GFP_ATOMIC);
+}
+
+/**
+ * alloc_ring - allocate resources for an SGE descriptor ring
+ * @dev: the PCI device's core device
+ * @nelem: the number of descriptors
+ * @hwsize: the size of each hardware descriptor
+ * @swsize: the size of each software descriptor
+ * @busaddrp: the physical PCI bus address of the allocated ring
+ * @swringp: return address pointer for software ring
+ * @stat_size: extra space in hardware ring for status information
+ *
+ * Allocates resources for an SGE descriptor ring, such as TX queues,
+ * free buffer lists, response queues, etc. Each SGE ring requires
+ * space for its hardware descriptors plus, optionally, space for software
+ * state associated with each hardware entry (the metadata). The function
+ * returns three values: the virtual address for the hardware ring (the
+ * return value of the function), the PCI bus address of the hardware
+ * ring (in *busaddrp), and the address of the software ring (in swringp).
+ * Both the hardware and software rings are returned zeroed out.
+ */
+static void *alloc_ring(struct device *dev, size_t nelem, size_t hwsize,
+ size_t swsize, dma_addr_t *busaddrp, void *swringp,
+ size_t stat_size)
+{
+ /*
+ * Allocate the hardware ring and PCI DMA bus address space for said.
+ */
+ size_t hwlen = nelem * hwsize + stat_size;
+ void *hwring = dma_alloc_coherent(dev, hwlen, busaddrp, GFP_KERNEL);
+
+ if (!hwring)
+ return NULL;
+
+ /*
+ * If the caller wants a software ring, allocate it and return a
+ * pointer to it in *swringp.
+ */
+ BUG_ON((swsize != 0) != (swringp != NULL));
+ if (swsize) {
+ void *swring = kcalloc(nelem, swsize, GFP_KERNEL);
+
+ if (!swring) {
+ dma_free_coherent(dev, hwlen, hwring, *busaddrp);
+ return NULL;
+ }
+ *(void **)swringp = swring;
+ }
+
+ /*
+ * Zero out the hardware ring and return its address as our function
+ * value.
+ */
+ memset(hwring, 0, hwlen);
+ return hwring;
+}
+
+/**
+ * sgl_len - calculates the size of an SGL of the given capacity
+ * @n: the number of SGL entries
+ *
+ * Calculates the number of flits (8-byte units) needed for a Direct
+ * Scatter/Gather List that can hold the given number of entries.
+ */
+static inline unsigned int sgl_len(unsigned int n)
+{
+ /*
+ * A Direct Scatter Gather List uses 32-bit lengths and 64-bit PCI DMA
+ * addresses. The DSGL Work Request starts off with a 32-bit DSGL
+ * ULPTX header, then Length0, then Address0, then, for 1 <= i <= N,
+ * repeated sequences of { Length[i], Length[i+1], Address[i],
+ * Address[i+1] } (this ensures that all addresses are on 64-bit
+ * boundaries). If N is even, then Length[N+1] should be set to 0 and
+ * Address[N+1] is omitted.
+ *
+ * The following calculation incorporates all of the above. It's
+ * somewhat hard to follow but, briefly: the "+2" accounts for the
+ * first two flits which include the DSGL header, Length0 and
+ * Address0; the "(3*(n-1))/2" covers the main body of list entries (3
+ * flits for every pair of the remaining N) +1 if (n-1) is odd; and
+ * finally the "+((n-1)&1)" adds the one remaining flit needed if
+ * (n-1) is odd ...
+ */
+ n--;
+ return (3 * n) / 2 + (n & 1) + 2;
+}
+
+/**
+ * flits_to_desc - returns the num of TX descriptors for the given flits
+ * @flits: the number of flits
+ *
+ * Returns the number of TX descriptors needed for the supplied number
+ * of flits.
+ */
+static inline unsigned int flits_to_desc(unsigned int flits)
+{
+ BUG_ON(flits > SGE_MAX_WR_LEN / sizeof(__be64));
+ return DIV_ROUND_UP(flits, TXD_PER_EQ_UNIT);
+}
+
+/**
+ * is_eth_imm - can an Ethernet packet be sent as immediate data?
+ * @skb: the packet
+ *
+ * Returns whether an Ethernet packet is small enough to fit completely as
+ * immediate data.
+ */
+static inline int is_eth_imm(const struct sk_buff *skb)
+{
+ /*
+ * The VF Driver uses the FW_ETH_TX_PKT_VM_WR firmware Work Request
+ * which does not accommodate immediate data. We could dike out all
+ * of the support code for immediate data but that would tie our hands
+ * too much if we ever want to enhace the firmware. It would also
+ * create more differences between the PF and VF Drivers.
+ */
+ return false;
+}
+
+/**
+ * calc_tx_flits - calculate the number of flits for a packet TX WR
+ * @skb: the packet
+ *
+ * Returns the number of flits needed for a TX Work Request for the
+ * given Ethernet packet, including the needed WR and CPL headers.
+ */
+static inline unsigned int calc_tx_flits(const struct sk_buff *skb)
+{
+ unsigned int flits;
+
+ /*
+ * If the skb is small enough, we can pump it out as a work request
+ * with only immediate data. In that case we just have to have the
+ * TX Packet header plus the skb data in the Work Request.
+ */
+ if (is_eth_imm(skb))
+ return DIV_ROUND_UP(skb->len + sizeof(struct cpl_tx_pkt),
+ sizeof(__be64));
+
+ /*
+ * Otherwise, we're going to have to construct a Scatter gather list
+ * of the skb body and fragments. We also include the flits necessary
+ * for the TX Packet Work Request and CPL. We always have a firmware
+ * Write Header (incorporated as part of the cpl_tx_pkt_lso and
+ * cpl_tx_pkt structures), followed by either a TX Packet Write CPL
+ * message or, if we're doing a Large Send Offload, an LSO CPL message
+ * with an embeded TX Packet Write CPL message.
+ */
+ flits = sgl_len(skb_shinfo(skb)->nr_frags + 1);
+ if (skb_shinfo(skb)->gso_size)
+ flits += (sizeof(struct fw_eth_tx_pkt_vm_wr) +
+ sizeof(struct cpl_tx_pkt_lso_core) +
+ sizeof(struct cpl_tx_pkt_core)) / sizeof(__be64);
+ else
+ flits += (sizeof(struct fw_eth_tx_pkt_vm_wr) +
+ sizeof(struct cpl_tx_pkt_core)) / sizeof(__be64);
+ return flits;
+}
+
+/**
+ * write_sgl - populate a Scatter/Gather List for a packet
+ * @skb: the packet
+ * @tq: the TX queue we are writing into
+ * @sgl: starting location for writing the SGL
+ * @end: points right after the end of the SGL
+ * @start: start offset into skb main-body data to include in the SGL
+ * @addr: the list of DMA bus addresses for the SGL elements
+ *
+ * Generates a Scatter/Gather List for the buffers that make up a packet.
+ * The caller must provide adequate space for the SGL that will be written.
+ * The SGL includes all of the packet's page fragments and the data in its
+ * main body except for the first @start bytes. @pos must be 16-byte
+ * aligned and within a TX descriptor with available space. @end points
+ * write after the end of the SGL but does not account for any potential
+ * wrap around, i.e., @end > @tq->stat.
+ */
+static void write_sgl(const struct sk_buff *skb, struct sge_txq *tq,
+ struct ulptx_sgl *sgl, u64 *end, unsigned int start,
+ const dma_addr_t *addr)
+{
+ unsigned int i, len;
+ struct ulptx_sge_pair *to;
+ const struct skb_shared_info *si = skb_shinfo(skb);
+ unsigned int nfrags = si->nr_frags;
+ struct ulptx_sge_pair buf[MAX_SKB_FRAGS / 2 + 1];
+
+ len = skb_headlen(skb) - start;
+ if (likely(len)) {
+ sgl->len0 = htonl(len);
+ sgl->addr0 = cpu_to_be64(addr[0] + start);
+ nfrags++;
+ } else {
+ sgl->len0 = htonl(si->frags[0].size);
+ sgl->addr0 = cpu_to_be64(addr[1]);
+ }
+
+ sgl->cmd_nsge = htonl(ULPTX_CMD(ULP_TX_SC_DSGL) |
+ ULPTX_NSGE(nfrags));
+ if (likely(--nfrags == 0))
+ return;
+ /*
+ * Most of the complexity below deals with the possibility we hit the
+ * end of the queue in the middle of writing the SGL. For this case
+ * only we create the SGL in a temporary buffer and then copy it.
+ */
+ to = (u8 *)end > (u8 *)tq->stat ? buf : sgl->sge;
+
+ for (i = (nfrags != si->nr_frags); nfrags >= 2; nfrags -= 2, to++) {
+ to->len[0] = cpu_to_be32(si->frags[i].size);
+ to->len[1] = cpu_to_be32(si->frags[++i].size);
+ to->addr[0] = cpu_to_be64(addr[i]);
+ to->addr[1] = cpu_to_be64(addr[++i]);
+ }
+ if (nfrags) {
+ to->len[0] = cpu_to_be32(si->frags[i].size);
+ to->len[1] = cpu_to_be32(0);
+ to->addr[0] = cpu_to_be64(addr[i + 1]);
+ }
+ if (unlikely((u8 *)end > (u8 *)tq->stat)) {
+ unsigned int part0 = (u8 *)tq->stat - (u8 *)sgl->sge, part1;
+
+ if (likely(part0))
+ memcpy(sgl->sge, buf, part0);
+ part1 = (u8 *)end - (u8 *)tq->stat;
+ memcpy(tq->desc, (u8 *)buf + part0, part1);
+ end = (void *)tq->desc + part1;
+ }
+ if ((uintptr_t)end & 8) /* 0-pad to multiple of 16 */
+ *(u64 *)end = 0;
+}
+
+/**
+ * check_ring_tx_db - check and potentially ring a TX queue's doorbell
+ * @adapter: the adapter
+ * @tq: the TX queue
+ * @n: number of new descriptors to give to HW
+ *
+ * Ring the doorbel for a TX queue.
+ */
+static inline void ring_tx_db(struct adapter *adapter, struct sge_txq *tq,
+ int n)
+{
+ /*
+ * Warn if we write doorbells with the wrong priority and write
+ * descriptors before telling HW.
+ */
+ WARN_ON((QID(tq->cntxt_id) | PIDX(n)) & DBPRIO);
+ wmb();
+ t4_write_reg(adapter, T4VF_SGE_BASE_ADDR + SGE_VF_KDOORBELL,
+ QID(tq->cntxt_id) | PIDX(n));
+}
+
+/**
+ * inline_tx_skb - inline a packet's data into TX descriptors
+ * @skb: the packet
+ * @tq: the TX queue where the packet will be inlined
+ * @pos: starting position in the TX queue to inline the packet
+ *
+ * Inline a packet's contents directly into TX descriptors, starting at
+ * the given position within the TX DMA ring.
+ * Most of the complexity of this operation is dealing with wrap arounds
+ * in the middle of the packet we want to inline.
+ */
+static void inline_tx_skb(const struct sk_buff *skb, const struct sge_txq *tq,
+ void *pos)
+{
+ u64 *p;
+ int left = (void *)tq->stat - pos;
+
+ if (likely(skb->len <= left)) {
+ if (likely(!skb->data_len))
+ skb_copy_from_linear_data(skb, pos, skb->len);
+ else
+ skb_copy_bits(skb, 0, pos, skb->len);
+ pos += skb->len;
+ } else {
+ skb_copy_bits(skb, 0, pos, left);
+ skb_copy_bits(skb, left, tq->desc, skb->len - left);
+ pos = (void *)tq->desc + (skb->len - left);
+ }
+
+ /* 0-pad to multiple of 16 */
+ p = PTR_ALIGN(pos, 8);
+ if ((uintptr_t)p & 8)
+ *p = 0;
+}
+
+/*
+ * Figure out what HW csum a packet wants and return the appropriate control
+ * bits.
+ */
+static u64 hwcsum(const struct sk_buff *skb)
+{
+ int csum_type;
+ const struct iphdr *iph = ip_hdr(skb);
+
+ if (iph->version == 4) {
+ if (iph->protocol == IPPROTO_TCP)
+ csum_type = TX_CSUM_TCPIP;
+ else if (iph->protocol == IPPROTO_UDP)
+ csum_type = TX_CSUM_UDPIP;
+ else {
+nocsum:
+ /*
+ * unknown protocol, disable HW csum
+ * and hope a bad packet is detected
+ */
+ return TXPKT_L4CSUM_DIS;
+ }
+ } else {
+ /*
+ * this doesn't work with extension headers
+ */
+ const struct ipv6hdr *ip6h = (const struct ipv6hdr *)iph;
+
+ if (ip6h->nexthdr == IPPROTO_TCP)
+ csum_type = TX_CSUM_TCPIP6;
+ else if (ip6h->nexthdr == IPPROTO_UDP)
+ csum_type = TX_CSUM_UDPIP6;
+ else
+ goto nocsum;
+ }
+
+ if (likely(csum_type >= TX_CSUM_TCPIP))
+ return TXPKT_CSUM_TYPE(csum_type) |
+ TXPKT_IPHDR_LEN(skb_network_header_len(skb)) |
+ TXPKT_ETHHDR_LEN(skb_network_offset(skb) - ETH_HLEN);
+ else {
+ int start = skb_transport_offset(skb);
+
+ return TXPKT_CSUM_TYPE(csum_type) |
+ TXPKT_CSUM_START(start) |
+ TXPKT_CSUM_LOC(start + skb->csum_offset);
+ }
+}
+
+/*
+ * Stop an Ethernet TX queue and record that state change.
+ */
+static void txq_stop(struct sge_eth_txq *txq)
+{
+ netif_tx_stop_queue(txq->txq);
+ txq->q.stops++;
+}
+
+/*
+ * Advance our software state for a TX queue by adding n in use descriptors.
+ */
+static inline void txq_advance(struct sge_txq *tq, unsigned int n)
+{
+ tq->in_use += n;
+ tq->pidx += n;
+ if (tq->pidx >= tq->size)
+ tq->pidx -= tq->size;
+}
+
+/**
+ * t4vf_eth_xmit - add a packet to an Ethernet TX queue
+ * @skb: the packet
+ * @dev: the egress net device
+ *
+ * Add a packet to an SGE Ethernet TX queue. Runs with softirqs disabled.
+ */
+int t4vf_eth_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+ u32 wr_mid;
+ u64 cntrl, *end;
+ int qidx, credits;
+ unsigned int flits, ndesc;
+ struct adapter *adapter;
+ struct sge_eth_txq *txq;
+ const struct port_info *pi;
+ struct fw_eth_tx_pkt_vm_wr *wr;
+ struct cpl_tx_pkt_core *cpl;
+ const struct skb_shared_info *ssi;
+ dma_addr_t addr[MAX_SKB_FRAGS + 1];
+ const size_t fw_hdr_copy_len = (sizeof(wr->ethmacdst) +
+ sizeof(wr->ethmacsrc) +
+ sizeof(wr->ethtype) +
+ sizeof(wr->vlantci));
+
+ /*
+ * The chip minimum packet length is 10 octets but the firmware
+ * command that we are using requires that we copy the Ethernet header
+ * (including the VLAN tag) into the header so we reject anything
+ * smaller than that ...
+ */
+ if (unlikely(skb->len < fw_hdr_copy_len))
+ goto out_free;
+
+ /*
+ * Figure out which TX Queue we're going to use.
+ */
+ pi = netdev_priv(dev);
+ adapter = pi->adapter;
+ qidx = skb_get_queue_mapping(skb);
+ BUG_ON(qidx >= pi->nqsets);
+ txq = &adapter->sge.ethtxq[pi->first_qset + qidx];
+
+ /*
+ * Take this opportunity to reclaim any TX Descriptors whose DMA
+ * transfers have completed.
+ */
+ reclaim_completed_tx(adapter, &txq->q, true);
+
+ /*
+ * Calculate the number of flits and TX Descriptors we're going to
+ * need along with how many TX Descriptors will be left over after
+ * we inject our Work Request.
+ */
+ flits = calc_tx_flits(skb);
+ ndesc = flits_to_desc(flits);
+ credits = txq_avail(&txq->q) - ndesc;
+
+ if (unlikely(credits < 0)) {
+ /*
+ * Not enough room for this packet's Work Request. Stop the
+ * TX Queue and return a "busy" condition. The queue will get
+ * started later on when the firmware informs us that space
+ * has opened up.
+ */
+ txq_stop(txq);
+ dev_err(adapter->pdev_dev,
+ "%s: TX ring %u full while queue awake!\n",
+ dev->name, qidx);
+ return NETDEV_TX_BUSY;
+ }
+
+ if (!is_eth_imm(skb) &&
+ unlikely(map_skb(adapter->pdev_dev, skb, addr) < 0)) {
+ /*
+ * We need to map the skb into PCI DMA space (because it can't
+ * be in-lined directly into the Work Request) and the mapping
+ * operation failed. Record the error and drop the packet.
+ */
+ txq->mapping_err++;
+ goto out_free;
+ }
+
+ wr_mid = FW_WR_LEN16(DIV_ROUND_UP(flits, 2));
+ if (unlikely(credits < ETHTXQ_STOP_THRES)) {
+ /*
+ * After we're done injecting the Work Request for this
+ * packet, we'll be below our "stop threshhold" so stop the TX
+ * Queue now and schedule a request for an SGE Egress Queue
+ * Update message. The queue will get started later on when
+ * the firmware processes this Work Request and sends us an
+ * Egress Queue Status Update message indicating that space
+ * has opened up.
+ */
+ txq_stop(txq);
+ wr_mid |= FW_WR_EQUEQ | FW_WR_EQUIQ;
+ }
+
+ /*
+ * Start filling in our Work Request. Note that we do _not_ handle
+ * the WR Header wrapping around the TX Descriptor Ring. If our
+ * maximum header size ever exceeds one TX Descriptor, we'll need to
+ * do something else here.
+ */
+ BUG_ON(DIV_ROUND_UP(ETHTXQ_MAX_HDR, TXD_PER_EQ_UNIT) > 1);
+ wr = (void *)&txq->q.desc[txq->q.pidx];
+ wr->equiq_to_len16 = cpu_to_be32(wr_mid);
+ wr->r3[0] = cpu_to_be64(0);
+ wr->r3[1] = cpu_to_be64(0);
+ skb_copy_from_linear_data(skb, (void *)wr->ethmacdst, fw_hdr_copy_len);
+ end = (u64 *)wr + flits;
+
+ /*
+ * If this is a Large Send Offload packet we'll put in an LSO CPL
+ * message with an encapsulated TX Packet CPL message. Otherwise we
+ * just use a TX Packet CPL message.
+ */
+ ssi = skb_shinfo(skb);
+ if (ssi->gso_size) {
+ struct cpl_tx_pkt_lso_core *lso = (void *)(wr + 1);
+ bool v6 = (ssi->gso_type & SKB_GSO_TCPV6) != 0;
+ int l3hdr_len = skb_network_header_len(skb);
+ int eth_xtra_len = skb_network_offset(skb) - ETH_HLEN;
+
+ wr->op_immdlen =
+ cpu_to_be32(FW_WR_OP(FW_ETH_TX_PKT_VM_WR) |
+ FW_WR_IMMDLEN(sizeof(*lso) +
+ sizeof(*cpl)));
+ /*
+ * Fill in the LSO CPL message.
+ */
+ lso->lso_ctrl =
+ cpu_to_be32(LSO_OPCODE(CPL_TX_PKT_LSO) |
+ LSO_FIRST_SLICE |
+ LSO_LAST_SLICE |
+ LSO_IPV6(v6) |
+ LSO_ETHHDR_LEN(eth_xtra_len/4) |
+ LSO_IPHDR_LEN(l3hdr_len/4) |
+ LSO_TCPHDR_LEN(tcp_hdr(skb)->doff));
+ lso->ipid_ofst = cpu_to_be16(0);
+ lso->mss = cpu_to_be16(ssi->gso_size);
+ lso->seqno_offset = cpu_to_be32(0);
+ lso->len = cpu_to_be32(skb->len);
+
+ /*
+ * Set up TX Packet CPL pointer, control word and perform
+ * accounting.
+ */
+ cpl = (void *)(lso + 1);
+ cntrl = (TXPKT_CSUM_TYPE(v6 ? TX_CSUM_TCPIP6 : TX_CSUM_TCPIP) |
+ TXPKT_IPHDR_LEN(l3hdr_len) |
+ TXPKT_ETHHDR_LEN(eth_xtra_len));
+ txq->tso++;
+ txq->tx_cso += ssi->gso_segs;
+ } else {
+ int len;
+
+ len = is_eth_imm(skb) ? skb->len + sizeof(*cpl) : sizeof(*cpl);
+ wr->op_immdlen =
+ cpu_to_be32(FW_WR_OP(FW_ETH_TX_PKT_VM_WR) |
+ FW_WR_IMMDLEN(len));
+
+ /*
+ * Set up TX Packet CPL pointer, control word and perform
+ * accounting.
+ */
+ cpl = (void *)(wr + 1);
+ if (skb->ip_summed == CHECKSUM_PARTIAL) {
+ cntrl = hwcsum(skb) | TXPKT_IPCSUM_DIS;
+ txq->tx_cso++;
+ } else
+ cntrl = TXPKT_L4CSUM_DIS | TXPKT_IPCSUM_DIS;
+ }
+
+ /*
+ * If there's a VLAN tag present, add that to the list of things to
+ * do in this Work Request.
+ */
+ if (vlan_tx_tag_present(skb)) {
+ txq->vlan_ins++;
+ cntrl |= TXPKT_VLAN_VLD | TXPKT_VLAN(vlan_tx_tag_get(skb));
+ }
+
+ /*
+ * Fill in the TX Packet CPL message header.
+ */
+ cpl->ctrl0 = cpu_to_be32(TXPKT_OPCODE(CPL_TX_PKT_XT) |
+ TXPKT_INTF(pi->port_id) |
+ TXPKT_PF(0));
+ cpl->pack = cpu_to_be16(0);
+ cpl->len = cpu_to_be16(skb->len);
+ cpl->ctrl1 = cpu_to_be64(cntrl);
+
+#ifdef T4_TRACE
+ T4_TRACE5(adapter->tb[txq->q.cntxt_id & 7],
+ "eth_xmit: ndesc %u, credits %u, pidx %u, len %u, frags %u",
+ ndesc, credits, txq->q.pidx, skb->len, ssi->nr_frags);
+#endif
+
+ /*
+ * Fill in the body of the TX Packet CPL message with either in-lined
+ * data or a Scatter/Gather List.
+ */
+ if (is_eth_imm(skb)) {
+ /*
+ * In-line the packet's data and free the skb since we don't
+ * need it any longer.
+ */
+ inline_tx_skb(skb, &txq->q, cpl + 1);
+ dev_kfree_skb(skb);
+ } else {
+ /*
+ * Write the skb's Scatter/Gather list into the TX Packet CPL
+ * message and retain a pointer to the skb so we can free it
+ * later when its DMA completes. (We store the skb pointer
+ * in the Software Descriptor corresponding to the last TX
+ * Descriptor used by the Work Request.)
+ *
+ * The retained skb will be freed when the corresponding TX
+ * Descriptors are reclaimed after their DMAs complete.
+ * However, this could take quite a while since, in general,
+ * the hardware is set up to be lazy about sending DMA
+ * completion notifications to us and we mostly perform TX
+ * reclaims in the transmit routine.
+ *
+ * This is good for performamce but means that we rely on new
+ * TX packets arriving to run the destructors of completed
+ * packets, which open up space in their sockets' send queues.
+ * Sometimes we do not get such new packets causing TX to
+ * stall. A single UDP transmitter is a good example of this
+ * situation. We have a clean up timer that periodically
+ * reclaims completed packets but it doesn't run often enough
+ * (nor do we want it to) to prevent lengthy stalls. A
+ * solution to this problem is to run the destructor early,
+ * after the packet is queued but before it's DMAd. A con is
+ * that we lie to socket memory accounting, but the amount of
+ * extra memory is reasonable (limited by the number of TX
+ * descriptors), the packets do actually get freed quickly by
+ * new packets almost always, and for protocols like TCP that
+ * wait for acks to really free up the data the extra memory
+ * is even less. On the positive side we run the destructors
+ * on the sending CPU rather than on a potentially different
+ * completing CPU, usually a good thing.
+ *
+ * Run the destructor before telling the DMA engine about the
+ * packet to make sure it doesn't complete and get freed
+ * prematurely.
+ */
+ struct ulptx_sgl *sgl = (struct ulptx_sgl *)(cpl + 1);
+ struct sge_txq *tq = &txq->q;
+ int last_desc;
+
+ /*
+ * If the Work Request header was an exact multiple of our TX
+ * Descriptor length, then it's possible that the starting SGL
+ * pointer lines up exactly with the end of our TX Descriptor
+ * ring. If that's the case, wrap around to the beginning
+ * here ...
+ */
+ if (unlikely((void *)sgl == (void *)tq->stat)) {
+ sgl = (void *)tq->desc;
+ end = (void *)((void *)tq->desc +
+ ((void *)end - (void *)tq->stat));
+ }
+
+ write_sgl(skb, tq, sgl, end, 0, addr);
+ skb_orphan(skb);
+
+ last_desc = tq->pidx + ndesc - 1;
+ if (last_desc >= tq->size)
+ last_desc -= tq->size;
+ tq->sdesc[last_desc].skb = skb;
+ tq->sdesc[last_desc].sgl = sgl;
+ }
+
+ /*
+ * Advance our internal TX Queue state, tell the hardware about
+ * the new TX descriptors and return success.
+ */
+ txq_advance(&txq->q, ndesc);
+ dev->trans_start = jiffies;
+ ring_tx_db(adapter, &txq->q, ndesc);
+ return NETDEV_TX_OK;
+
+out_free:
+ /*
+ * An error of some sort happened. Free the TX skb and tell the
+ * OS that we've "dealt" with the packet ...
+ */
+ dev_kfree_skb(skb);
+ return NETDEV_TX_OK;
+}
+
+/**
+ * t4vf_pktgl_free - free a packet gather list
+ * @gl: the gather list
+ *
+ * Releases the pages of a packet gather list. We do not own the last
+ * page on the list and do not free it.
+ */
+void t4vf_pktgl_free(const struct pkt_gl *gl)
+{
+ int frag;
+
+ frag = gl->nfrags - 1;
+ while (frag--)
+ put_page(gl->frags[frag].page);
+}
+
+/**
+ * copy_frags - copy fragments from gather list into skb_shared_info
+ * @si: destination skb shared info structure
+ * @gl: source internal packet gather list
+ * @offset: packet start offset in first page
+ *
+ * Copy an internal packet gather list into a Linux skb_shared_info
+ * structure.
+ */
+static inline void copy_frags(struct skb_shared_info *si,
+ const struct pkt_gl *gl,
+ unsigned int offset)
+{
+ unsigned int n;
+
+ /* usually there's just one frag */
+ si->frags[0].page = gl->frags[0].page;
+ si->frags[0].page_offset = gl->frags[0].page_offset + offset;
+ si->frags[0].size = gl->frags[0].size - offset;
+ si->nr_frags = gl->nfrags;
+
+ n = gl->nfrags - 1;
+ if (n)
+ memcpy(&si->frags[1], &gl->frags[1], n * sizeof(skb_frag_t));
+
+ /* get a reference to the last page, we don't own it */
+ get_page(gl->frags[n].page);
+}
+
+/**
+ * do_gro - perform Generic Receive Offload ingress packet processing
+ * @rxq: ingress RX Ethernet Queue
+ * @gl: gather list for ingress packet
+ * @pkt: CPL header for last packet fragment
+ *
+ * Perform Generic Receive Offload (GRO) ingress packet processing.
+ * We use the standard Linux GRO interfaces for this.
+ */
+static void do_gro(struct sge_eth_rxq *rxq, const struct pkt_gl *gl,
+ const struct cpl_rx_pkt *pkt)
+{
+ int ret;
+ struct sk_buff *skb;
+
+ skb = napi_get_frags(&rxq->rspq.napi);
+ if (unlikely(!skb)) {
+ t4vf_pktgl_free(gl);
+ rxq->stats.rx_drops++;
+ return;
+ }
+
+ copy_frags(skb_shinfo(skb), gl, PKTSHIFT);
+ skb->len = gl->tot_len - PKTSHIFT;
+ skb->data_len = skb->len;
+ skb->truesize += skb->data_len;
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+ skb_record_rx_queue(skb, rxq->rspq.idx);
+
+ if (unlikely(pkt->vlan_ex)) {
+ struct port_info *pi = netdev_priv(rxq->rspq.netdev);
+ struct vlan_group *grp = pi->vlan_grp;
+
+ rxq->stats.vlan_ex++;
+ if (likely(grp)) {
+ ret = vlan_gro_frags(&rxq->rspq.napi, grp,
+ be16_to_cpu(pkt->vlan));
+ goto stats;
+ }
+ }
+ ret = napi_gro_frags(&rxq->rspq.napi);
+
+stats:
+ if (ret == GRO_HELD)
+ rxq->stats.lro_pkts++;
+ else if (ret == GRO_MERGED || ret == GRO_MERGED_FREE)
+ rxq->stats.lro_merged++;
+ rxq->stats.pkts++;
+ rxq->stats.rx_cso++;
+}
+
+/**
+ * t4vf_ethrx_handler - process an ingress ethernet packet
+ * @rspq: the response queue that received the packet
+ * @rsp: the response queue descriptor holding the RX_PKT message
+ * @gl: the gather list of packet fragments
+ *
+ * Process an ingress ethernet packet and deliver it to the stack.
+ */
+int t4vf_ethrx_handler(struct sge_rspq *rspq, const __be64 *rsp,
+ const struct pkt_gl *gl)
+{
+ struct sk_buff *skb;
+ struct port_info *pi;
+ struct skb_shared_info *ssi;
+ const struct cpl_rx_pkt *pkt = (void *)&rsp[1];
+ bool csum_ok = pkt->csum_calc && !pkt->err_vec;
+ unsigned int len = be16_to_cpu(pkt->len);
+ struct sge_eth_rxq *rxq = container_of(rspq, struct sge_eth_rxq, rspq);
+
+ /*
+ * If this is a good TCP packet and we have Generic Receive Offload
+ * enabled, handle the packet in the GRO path.
+ */
+ if ((pkt->l2info & cpu_to_be32(RXF_TCP)) &&
+ (rspq->netdev->features & NETIF_F_GRO) && csum_ok &&
+ !pkt->ip_frag) {
+ do_gro(rxq, gl, pkt);
+ return 0;
+ }
+
+ /*
+ * If the ingress packet is small enough, allocate an skb large enough
+ * for all of the data and copy it inline. Otherwise, allocate an skb
+ * with enough room to pull in the header and reference the rest of
+ * the data via the skb fragment list.
+ */
+ if (len <= RX_COPY_THRES) {
+ /* small packets have only one fragment */
+ skb = alloc_skb(gl->frags[0].size, GFP_ATOMIC);
+ if (!skb)
+ goto nomem;
+ __skb_put(skb, gl->frags[0].size);
+ skb_copy_to_linear_data(skb, gl->va, gl->frags[0].size);
+ } else {
+ skb = alloc_skb(RX_PKT_PULL_LEN, GFP_ATOMIC);
+ if (!skb)
+ goto nomem;
+ __skb_put(skb, RX_PKT_PULL_LEN);
+ skb_copy_to_linear_data(skb, gl->va, RX_PKT_PULL_LEN);
+
+ ssi = skb_shinfo(skb);
+ ssi->frags[0].page = gl->frags[0].page;
+ ssi->frags[0].page_offset = (gl->frags[0].page_offset +
+ RX_PKT_PULL_LEN);
+ ssi->frags[0].size = gl->frags[0].size - RX_PKT_PULL_LEN;
+ if (gl->nfrags > 1)
+ memcpy(&ssi->frags[1], &gl->frags[1],
+ (gl->nfrags-1) * sizeof(skb_frag_t));
+ ssi->nr_frags = gl->nfrags;
+ skb->len = len + PKTSHIFT;
+ skb->data_len = skb->len - RX_PKT_PULL_LEN;
+ skb->truesize += skb->data_len;
+
+ /* Get a reference for the last page, we don't own it */
+ get_page(gl->frags[gl->nfrags - 1].page);
+ }
+
+ __skb_pull(skb, PKTSHIFT);
+ skb->protocol = eth_type_trans(skb, rspq->netdev);
+ skb_record_rx_queue(skb, rspq->idx);
+ skb->dev->last_rx = jiffies; /* XXX removed 2.6.29 */
+ pi = netdev_priv(skb->dev);
+ rxq->stats.pkts++;
+
+ if (csum_ok && (pi->rx_offload & RX_CSO) && !pkt->err_vec &&
+ (be32_to_cpu(pkt->l2info) & (RXF_UDP|RXF_TCP))) {
+ if (!pkt->ip_frag)
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+ else {
+ __sum16 c = (__force __sum16)pkt->csum;
+ skb->csum = csum_unfold(c);
+ skb->ip_summed = CHECKSUM_COMPLETE;
+ }
+ rxq->stats.rx_cso++;
+ } else
+ skb->ip_summed = CHECKSUM_NONE;
+
+ if (unlikely(pkt->vlan_ex)) {
+ struct vlan_group *grp = pi->vlan_grp;
+
+ rxq->stats.vlan_ex++;
+ if (likely(grp))
+ vlan_hwaccel_receive_skb(skb, grp,
+ be16_to_cpu(pkt->vlan));
+ else
+ dev_kfree_skb_any(skb);
+ } else
+ netif_receive_skb(skb);
+
+ return 0;
+
+nomem:
+ t4vf_pktgl_free(gl);
+ rxq->stats.rx_drops++;
+ return 0;
+}
+
+/**
+ * is_new_response - check if a response is newly written
+ * @rc: the response control descriptor
+ * @rspq: the response queue
+ *
+ * Returns true if a response descriptor contains a yet unprocessed
+ * response.
+ */
+static inline bool is_new_response(const struct rsp_ctrl *rc,
+ const struct sge_rspq *rspq)
+{
+ return RSPD_GEN(rc->type_gen) == rspq->gen;
+}
+
+/**
+ * restore_rx_bufs - put back a packet's RX buffers
+ * @gl: the packet gather list
+ * @fl: the SGE Free List
+ * @nfrags: how many fragments in @si
+ *
+ * Called when we find out that the current packet, @si, can't be
+ * processed right away for some reason. This is a very rare event and
+ * there's no effort to make this suspension/resumption process
+ * particularly efficient.
+ *
+ * We implement the suspension by putting all of the RX buffers associated
+ * with the current packet back on the original Free List. The buffers
+ * have already been unmapped and are left unmapped, we mark them as
+ * unmapped in order to prevent further unmapping attempts. (Effectively
+ * this function undoes the series of @unmap_rx_buf calls which were done
+ * to create the current packet's gather list.) This leaves us ready to
+ * restart processing of the packet the next time we start processing the
+ * RX Queue ...
+ */
+static void restore_rx_bufs(const struct pkt_gl *gl, struct sge_fl *fl,
+ int frags)
+{
+ struct rx_sw_desc *sdesc;
+
+ while (frags--) {
+ if (fl->cidx == 0)
+ fl->cidx = fl->size - 1;
+ else
+ fl->cidx--;
+ sdesc = &fl->sdesc[fl->cidx];
+ sdesc->page = gl->frags[frags].page;
+ sdesc->dma_addr |= RX_UNMAPPED_BUF;
+ fl->avail++;
+ }
+}
+
+/**
+ * rspq_next - advance to the next entry in a response queue
+ * @rspq: the queue
+ *
+ * Updates the state of a response queue to advance it to the next entry.
+ */
+static inline void rspq_next(struct sge_rspq *rspq)
+{
+ rspq->cur_desc = (void *)rspq->cur_desc + rspq->iqe_len;
+ if (unlikely(++rspq->cidx == rspq->size)) {
+ rspq->cidx = 0;
+ rspq->gen ^= 1;
+ rspq->cur_desc = rspq->desc;
+ }
+}
+
+/**
+ * process_responses - process responses from an SGE response queue
+ * @rspq: the ingress response queue to process
+ * @budget: how many responses can be processed in this round
+ *
+ * Process responses from a Scatter Gather Engine response queue up to
+ * the supplied budget. Responses include received packets as well as
+ * control messages from firmware or hardware.
+ *
+ * Additionally choose the interrupt holdoff time for the next interrupt
+ * on this queue. If the system is under memory shortage use a fairly
+ * long delay to help recovery.
+ */
+int process_responses(struct sge_rspq *rspq, int budget)
+{
+ struct sge_eth_rxq *rxq = container_of(rspq, struct sge_eth_rxq, rspq);
+ int budget_left = budget;
+
+ while (likely(budget_left)) {
+ int ret, rsp_type;
+ const struct rsp_ctrl *rc;
+
+ rc = (void *)rspq->cur_desc + (rspq->iqe_len - sizeof(*rc));
+ if (!is_new_response(rc, rspq))
+ break;
+
+ /*
+ * Figure out what kind of response we've received from the
+ * SGE.
+ */
+ rmb();
+ rsp_type = RSPD_TYPE(rc->type_gen);
+ if (likely(rsp_type == RSP_TYPE_FLBUF)) {
+ skb_frag_t *fp;
+ struct pkt_gl gl;
+ const struct rx_sw_desc *sdesc;
+ u32 bufsz, frag;
+ u32 len = be32_to_cpu(rc->pldbuflen_qid);
+
+ /*
+ * If we get a "new buffer" message from the SGE we
+ * need to move on to the next Free List buffer.
+ */
+ if (len & RSPD_NEWBUF) {
+ /*
+ * We get one "new buffer" message when we
+ * first start up a queue so we need to ignore
+ * it when our offset into the buffer is 0.
+ */
+ if (likely(rspq->offset > 0)) {
+ free_rx_bufs(rspq->adapter, &rxq->fl,
+ 1);
+ rspq->offset = 0;
+ }
+ len = RSPD_LEN(len);
+ }
+
+ /*
+ * Gather packet fragments.
+ */
+ for (frag = 0, fp = gl.frags; /**/; frag++, fp++) {
+ BUG_ON(frag >= MAX_SKB_FRAGS);
+ BUG_ON(rxq->fl.avail == 0);
+ sdesc = &rxq->fl.sdesc[rxq->fl.cidx];
+ bufsz = get_buf_size(sdesc);
+ fp->page = sdesc->page;
+ fp->page_offset = rspq->offset;
+ fp->size = min(bufsz, len);
+ len -= fp->size;
+ if (!len)
+ break;
+ unmap_rx_buf(rspq->adapter, &rxq->fl);
+ }
+ gl.nfrags = frag+1;
+
+ /*
+ * Last buffer remains mapped so explicitly make it
+ * coherent for CPU access and start preloading first
+ * cache line ...
+ */
+ dma_sync_single_for_cpu(rspq->adapter->pdev_dev,
+ get_buf_addr(sdesc),
+ fp->size, DMA_FROM_DEVICE);
+ gl.va = (page_address(gl.frags[0].page) +
+ gl.frags[0].page_offset);
+ prefetch(gl.va);
+
+ /*
+ * Hand the new ingress packet to the handler for
+ * this Response Queue.
+ */
+ ret = rspq->handler(rspq, rspq->cur_desc, &gl);
+ if (likely(ret == 0))
+ rspq->offset += ALIGN(fp->size, FL_ALIGN);
+ else
+ restore_rx_bufs(&gl, &rxq->fl, frag);
+ } else if (likely(rsp_type == RSP_TYPE_CPL)) {
+ ret = rspq->handler(rspq, rspq->cur_desc, NULL);
+ } else {
+ WARN_ON(rsp_type > RSP_TYPE_CPL);
+ ret = 0;
+ }
+
+ if (unlikely(ret)) {
+ /*
+ * Couldn't process descriptor, back off for recovery.
+ * We use the SGE's last timer which has the longest
+ * interrupt coalescing value ...
+ */
+ const int NOMEM_TIMER_IDX = SGE_NTIMERS-1;
+ rspq->next_intr_params =
+ QINTR_TIMER_IDX(NOMEM_TIMER_IDX);
+ break;
+ }
+
+ rspq_next(rspq);
+ budget_left--;
+ }
+
+ /*
+ * If this is a Response Queue with an associated Free List and
+ * at least two Egress Queue units available in the Free List
+ * for new buffer pointers, refill the Free List.
+ */
+ if (rspq->offset >= 0 &&
+ rxq->fl.size - rxq->fl.avail >= 2*FL_PER_EQ_UNIT)
+ __refill_fl(rspq->adapter, &rxq->fl);
+ return budget - budget_left;
+}
+
+/**
+ * napi_rx_handler - the NAPI handler for RX processing
+ * @napi: the napi instance
+ * @budget: how many packets we can process in this round
+ *
+ * Handler for new data events when using NAPI. This does not need any
+ * locking or protection from interrupts as data interrupts are off at
+ * this point and other adapter interrupts do not interfere (the latter
+ * in not a concern at all with MSI-X as non-data interrupts then have
+ * a separate handler).
+ */
+static int napi_rx_handler(struct napi_struct *napi, int budget)
+{
+ unsigned int intr_params;
+ struct sge_rspq *rspq = container_of(napi, struct sge_rspq, napi);
+ int work_done = process_responses(rspq, budget);
+
+ if (likely(work_done < budget)) {
+ napi_complete(napi);
+ intr_params = rspq->next_intr_params;
+ rspq->next_intr_params = rspq->intr_params;
+ } else
+ intr_params = QINTR_TIMER_IDX(SGE_TIMER_UPD_CIDX);
+
+ if (unlikely(work_done == 0))
+ rspq->unhandled_irqs++;
+
+ t4_write_reg(rspq->adapter,
+ T4VF_SGE_BASE_ADDR + SGE_VF_GTS,
+ CIDXINC(work_done) |
+ INGRESSQID((u32)rspq->cntxt_id) |
+ SEINTARM(intr_params));
+ return work_done;
+}
+
+/*
+ * The MSI-X interrupt handler for an SGE response queue for the NAPI case
+ * (i.e., response queue serviced by NAPI polling).
+ */
+irqreturn_t t4vf_sge_intr_msix(int irq, void *cookie)
+{
+ struct sge_rspq *rspq = cookie;
+
+ napi_schedule(&rspq->napi);
+ return IRQ_HANDLED;
+}
+
+/*
+ * Process the indirect interrupt entries in the interrupt queue and kick off
+ * NAPI for each queue that has generated an entry.
+ */
+static unsigned int process_intrq(struct adapter *adapter)
+{
+ struct sge *s = &adapter->sge;
+ struct sge_rspq *intrq = &s->intrq;
+ unsigned int work_done;
+
+ spin_lock(&adapter->sge.intrq_lock);
+ for (work_done = 0; ; work_done++) {
+ const struct rsp_ctrl *rc;
+ unsigned int qid, iq_idx;
+ struct sge_rspq *rspq;
+
+ /*
+ * Grab the next response from the interrupt queue and bail
+ * out if it's not a new response.
+ */
+ rc = (void *)intrq->cur_desc + (intrq->iqe_len - sizeof(*rc));
+ if (!is_new_response(rc, intrq))
+ break;
+
+ /*
+ * If the response isn't a forwarded interrupt message issue a
+ * error and go on to the next response message. This should
+ * never happen ...
+ */
+ rmb();
+ if (unlikely(RSPD_TYPE(rc->type_gen) != RSP_TYPE_INTR)) {
+ dev_err(adapter->pdev_dev,
+ "Unexpected INTRQ response type %d\n",
+ RSPD_TYPE(rc->type_gen));
+ continue;
+ }
+
+ /*
+ * Extract the Queue ID from the interrupt message and perform
+ * sanity checking to make sure it really refers to one of our
+ * Ingress Queues which is active and matches the queue's ID.
+ * None of these error conditions should ever happen so we may
+ * want to either make them fatal and/or conditionalized under
+ * DEBUG.
+ */
+ qid = RSPD_QID(be32_to_cpu(rc->pldbuflen_qid));
+ iq_idx = IQ_IDX(s, qid);
+ if (unlikely(iq_idx >= MAX_INGQ)) {
+ dev_err(adapter->pdev_dev,
+ "Ingress QID %d out of range\n", qid);
+ continue;
+ }
+ rspq = s->ingr_map[iq_idx];
+ if (unlikely(rspq == NULL)) {
+ dev_err(adapter->pdev_dev,
+ "Ingress QID %d RSPQ=NULL\n", qid);
+ continue;
+ }
+ if (unlikely(rspq->abs_id != qid)) {
+ dev_err(adapter->pdev_dev,
+ "Ingress QID %d refers to RSPQ %d\n",
+ qid, rspq->abs_id);
+ continue;
+ }
+
+ /*
+ * Schedule NAPI processing on the indicated Response Queue
+ * and move on to the next entry in the Forwarded Interrupt
+ * Queue.
+ */
+ napi_schedule(&rspq->napi);
+ rspq_next(intrq);
+ }
+
+ t4_write_reg(adapter, T4VF_SGE_BASE_ADDR + SGE_VF_GTS,
+ CIDXINC(work_done) |
+ INGRESSQID(intrq->cntxt_id) |
+ SEINTARM(intrq->intr_params));
+
+ spin_unlock(&adapter->sge.intrq_lock);
+
+ return work_done;
+}
+
+/*
+ * The MSI interrupt handler handles data events from SGE response queues as
+ * well as error and other async events as they all use the same MSI vector.
+ */
+irqreturn_t t4vf_intr_msi(int irq, void *cookie)
+{
+ struct adapter *adapter = cookie;
+
+ process_intrq(adapter);
+ return IRQ_HANDLED;
+}
+
+/**
+ * t4vf_intr_handler - select the top-level interrupt handler
+ * @adapter: the adapter
+ *
+ * Selects the top-level interrupt handler based on the type of interrupts
+ * (MSI-X or MSI).
+ */
+irq_handler_t t4vf_intr_handler(struct adapter *adapter)
+{
+ BUG_ON((adapter->flags & (USING_MSIX|USING_MSI)) == 0);
+ if (adapter->flags & USING_MSIX)
+ return t4vf_sge_intr_msix;
+ else
+ return t4vf_intr_msi;
+}
+
+/**
+ * sge_rx_timer_cb - perform periodic maintenance of SGE RX queues
+ * @data: the adapter
+ *
+ * Runs periodically from a timer to perform maintenance of SGE RX queues.
+ *
+ * a) Replenishes RX queues that have run out due to memory shortage.
+ * Normally new RX buffers are added when existing ones are consumed but
+ * when out of memory a queue can become empty. We schedule NAPI to do
+ * the actual refill.
+ */
+static void sge_rx_timer_cb(unsigned long data)
+{
+ struct adapter *adapter = (struct adapter *)data;
+ struct sge *s = &adapter->sge;
+ unsigned int i;
+
+ /*
+ * Scan the "Starving Free Lists" flag array looking for any Free
+ * Lists in need of more free buffers. If we find one and it's not
+ * being actively polled, then bump its "starving" counter and attempt
+ * to refill it. If we're successful in adding enough buffers to push
+ * the Free List over the starving threshold, then we can clear its
+ * "starving" status.
+ */
+ for (i = 0; i < ARRAY_SIZE(s->starving_fl); i++) {
+ unsigned long m;
+
+ for (m = s->starving_fl[i]; m; m &= m - 1) {
+ unsigned int id = __ffs(m) + i * BITS_PER_LONG;
+ struct sge_fl *fl = s->egr_map[id];
+
+ clear_bit(id, s->starving_fl);
+ smp_mb__after_clear_bit();
+
+ /*
+ * Since we are accessing fl without a lock there's a
+ * small probability of a false positive where we
+ * schedule napi but the FL is no longer starving.
+ * No biggie.
+ */
+ if (fl_starving(fl)) {
+ struct sge_eth_rxq *rxq;
+
+ rxq = container_of(fl, struct sge_eth_rxq, fl);
+ if (napi_reschedule(&rxq->rspq.napi))
+ fl->starving++;
+ else
+ set_bit(id, s->starving_fl);
+ }
+ }
+ }
+
+ /*
+ * Reschedule the next scan for starving Free Lists ...
+ */
+ mod_timer(&s->rx_timer, jiffies + RX_QCHECK_PERIOD);
+}
+
+/**
+ * sge_tx_timer_cb - perform periodic maintenance of SGE Tx queues
+ * @data: the adapter
+ *
+ * Runs periodically from a timer to perform maintenance of SGE TX queues.
+ *
+ * b) Reclaims completed Tx packets for the Ethernet queues. Normally
+ * packets are cleaned up by new Tx packets, this timer cleans up packets
+ * when no new packets are being submitted. This is essential for pktgen,
+ * at least.
+ */
+static void sge_tx_timer_cb(unsigned long data)
+{
+ struct adapter *adapter = (struct adapter *)data;
+ struct sge *s = &adapter->sge;
+ unsigned int i, budget;
+
+ budget = MAX_TIMER_TX_RECLAIM;
+ i = s->ethtxq_rover;
+ do {
+ struct sge_eth_txq *txq = &s->ethtxq[i];
+
+ if (reclaimable(&txq->q) && __netif_tx_trylock(txq->txq)) {
+ int avail = reclaimable(&txq->q);
+
+ if (avail > budget)
+ avail = budget;
+
+ free_tx_desc(adapter, &txq->q, avail, true);
+ txq->q.in_use -= avail;
+ __netif_tx_unlock(txq->txq);
+
+ budget -= avail;
+ if (!budget)
+ break;
+ }
+
+ i++;
+ if (i >= s->ethqsets)
+ i = 0;
+ } while (i != s->ethtxq_rover);
+ s->ethtxq_rover = i;
+
+ /*
+ * If we found too many reclaimable packets schedule a timer in the
+ * near future to continue where we left off. Otherwise the next timer
+ * will be at its normal interval.
+ */
+ mod_timer(&s->tx_timer, jiffies + (budget ? TX_QCHECK_PERIOD : 2));
+}
+
+/**
+ * t4vf_sge_alloc_rxq - allocate an SGE RX Queue
+ * @adapter: the adapter
+ * @rspq: pointer to to the new rxq's Response Queue to be filled in
+ * @iqasynch: if 0, a normal rspq; if 1, an asynchronous event queue
+ * @dev: the network device associated with the new rspq
+ * @intr_dest: MSI-X vector index (overriden in MSI mode)
+ * @fl: pointer to the new rxq's Free List to be filled in
+ * @hnd: the interrupt handler to invoke for the rspq
+ */
+int t4vf_sge_alloc_rxq(struct adapter *adapter, struct sge_rspq *rspq,
+ bool iqasynch, struct net_device *dev,
+ int intr_dest,
+ struct sge_fl *fl, rspq_handler_t hnd)
+{
+ struct port_info *pi = netdev_priv(dev);
+ struct fw_iq_cmd cmd, rpl;
+ int ret, iqandst, flsz = 0;
+
+ /*
+ * If we're using MSI interrupts and we're not initializing the
+ * Forwarded Interrupt Queue itself, then set up this queue for
+ * indirect interrupts to the Forwarded Interrupt Queue. Obviously
+ * the Forwarded Interrupt Queue must be set up before any other
+ * ingress queue ...
+ */
+ if ((adapter->flags & USING_MSI) && rspq != &adapter->sge.intrq) {
+ iqandst = SGE_INTRDST_IQ;
+ intr_dest = adapter->sge.intrq.abs_id;
+ } else
+ iqandst = SGE_INTRDST_PCI;
+
+ /*
+ * Allocate the hardware ring for the Response Queue. The size needs
+ * to be a multiple of 16 which includes the mandatory status entry
+ * (regardless of whether the Status Page capabilities are enabled or
+ * not).
+ */
+ rspq->size = roundup(rspq->size, 16);
+ rspq->desc = alloc_ring(adapter->pdev_dev, rspq->size, rspq->iqe_len,
+ 0, &rspq->phys_addr, NULL, 0);
+ if (!rspq->desc)
+ return -ENOMEM;
+
+ /*
+ * Fill in the Ingress Queue Command. Note: Ideally this code would
+ * be in t4vf_hw.c but there are so many parameters and dependencies
+ * on our Linux SGE state that we would end up having to pass tons of
+ * parameters. We'll have to think about how this might be migrated
+ * into OS-independent common code ...
+ */
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.op_to_vfn = cpu_to_be32(FW_CMD_OP(FW_IQ_CMD) |
+ FW_CMD_REQUEST |
+ FW_CMD_WRITE |
+ FW_CMD_EXEC);
+ cmd.alloc_to_len16 = cpu_to_be32(FW_IQ_CMD_ALLOC |
+ FW_IQ_CMD_IQSTART(1) |
+ FW_LEN16(cmd));
+ cmd.type_to_iqandstindex =
+ cpu_to_be32(FW_IQ_CMD_TYPE(FW_IQ_TYPE_FL_INT_CAP) |
+ FW_IQ_CMD_IQASYNCH(iqasynch) |
+ FW_IQ_CMD_VIID(pi->viid) |
+ FW_IQ_CMD_IQANDST(iqandst) |
+ FW_IQ_CMD_IQANUS(1) |
+ FW_IQ_CMD_IQANUD(SGE_UPDATEDEL_INTR) |
+ FW_IQ_CMD_IQANDSTINDEX(intr_dest));
+ cmd.iqdroprss_to_iqesize =
+ cpu_to_be16(FW_IQ_CMD_IQPCIECH(pi->port_id) |
+ FW_IQ_CMD_IQGTSMODE |
+ FW_IQ_CMD_IQINTCNTTHRESH(rspq->pktcnt_idx) |
+ FW_IQ_CMD_IQESIZE(ilog2(rspq->iqe_len) - 4));
+ cmd.iqsize = cpu_to_be16(rspq->size);
+ cmd.iqaddr = cpu_to_be64(rspq->phys_addr);
+
+ if (fl) {
+ /*
+ * Allocate the ring for the hardware free list (with space
+ * for its status page) along with the associated software
+ * descriptor ring. The free list size needs to be a multiple
+ * of the Egress Queue Unit.
+ */
+ fl->size = roundup(fl->size, FL_PER_EQ_UNIT);
+ fl->desc = alloc_ring(adapter->pdev_dev, fl->size,
+ sizeof(__be64), sizeof(struct rx_sw_desc),
+ &fl->addr, &fl->sdesc, STAT_LEN);
+ if (!fl->desc) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ /*
+ * Calculate the size of the hardware free list ring plus
+ * status page (which the SGE will place at the end of the
+ * free list ring) in Egress Queue Units.
+ */
+ flsz = (fl->size / FL_PER_EQ_UNIT +
+ STAT_LEN / EQ_UNIT);
+
+ /*
+ * Fill in all the relevant firmware Ingress Queue Command
+ * fields for the free list.
+ */
+ cmd.iqns_to_fl0congen =
+ cpu_to_be32(
+ FW_IQ_CMD_FL0HOSTFCMODE(SGE_HOSTFCMODE_NONE) |
+ FW_IQ_CMD_FL0PACKEN |
+ FW_IQ_CMD_FL0PADEN);
+ cmd.fl0dcaen_to_fl0cidxfthresh =
+ cpu_to_be16(
+ FW_IQ_CMD_FL0FBMIN(SGE_FETCHBURSTMIN_64B) |
+ FW_IQ_CMD_FL0FBMAX(SGE_FETCHBURSTMAX_512B));
+ cmd.fl0size = cpu_to_be16(flsz);
+ cmd.fl0addr = cpu_to_be64(fl->addr);
+ }
+
+ /*
+ * Issue the firmware Ingress Queue Command and extract the results if
+ * it completes successfully.
+ */
+ ret = t4vf_wr_mbox(adapter, &cmd, sizeof(cmd), &rpl);
+ if (ret)
+ goto err;
+
+ netif_napi_add(dev, &rspq->napi, napi_rx_handler, 64);
+ rspq->cur_desc = rspq->desc;
+ rspq->cidx = 0;
+ rspq->gen = 1;
+ rspq->next_intr_params = rspq->intr_params;
+ rspq->cntxt_id = be16_to_cpu(rpl.iqid);
+ rspq->abs_id = be16_to_cpu(rpl.physiqid);
+ rspq->size--; /* subtract status entry */
+ rspq->adapter = adapter;
+ rspq->netdev = dev;
+ rspq->handler = hnd;
+
+ /* set offset to -1 to distinguish ingress queues without FL */
+ rspq->offset = fl ? 0 : -1;
+
+ if (fl) {
+ fl->cntxt_id = be16_to_cpu(rpl.fl0id);
+ fl->avail = 0;
+ fl->pend_cred = 0;
+ fl->pidx = 0;
+ fl->cidx = 0;
+ fl->alloc_failed = 0;
+ fl->large_alloc_failed = 0;
+ fl->starving = 0;
+ refill_fl(adapter, fl, fl_cap(fl), GFP_KERNEL);
+ }
+
+ return 0;
+
+err:
+ /*
+ * An error occurred. Clean up our partial allocation state and
+ * return the error.
+ */
+ if (rspq->desc) {
+ dma_free_coherent(adapter->pdev_dev, rspq->size * rspq->iqe_len,
+ rspq->desc, rspq->phys_addr);
+ rspq->desc = NULL;
+ }
+ if (fl && fl->desc) {
+ kfree(fl->sdesc);
+ fl->sdesc = NULL;
+ dma_free_coherent(adapter->pdev_dev, flsz * EQ_UNIT,
+ fl->desc, fl->addr);
+ fl->desc = NULL;
+ }
+ return ret;
+}
+
+/**
+ * t4vf_sge_alloc_eth_txq - allocate an SGE Ethernet TX Queue
+ * @adapter: the adapter
+ * @txq: pointer to the new txq to be filled in
+ * @devq: the network TX queue associated with the new txq
+ * @iqid: the relative ingress queue ID to which events relating to
+ * the new txq should be directed
+ */
+int t4vf_sge_alloc_eth_txq(struct adapter *adapter, struct sge_eth_txq *txq,
+ struct net_device *dev, struct netdev_queue *devq,
+ unsigned int iqid)
+{
+ int ret, nentries;
+ struct fw_eq_eth_cmd cmd, rpl;
+ struct port_info *pi = netdev_priv(dev);
+
+ /*
+ * Calculate the size of the hardware TX Queue (including the
+ * status age on the end) in units of TX Descriptors.
+ */
+ nentries = txq->q.size + STAT_LEN / sizeof(struct tx_desc);
+
+ /*
+ * Allocate the hardware ring for the TX ring (with space for its
+ * status page) along with the associated software descriptor ring.
+ */
+ txq->q.desc = alloc_ring(adapter->pdev_dev, txq->q.size,
+ sizeof(struct tx_desc),
+ sizeof(struct tx_sw_desc),
+ &txq->q.phys_addr, &txq->q.sdesc, STAT_LEN);
+ if (!txq->q.desc)
+ return -ENOMEM;
+
+ /*
+ * Fill in the Egress Queue Command. Note: As with the direct use of
+ * the firmware Ingress Queue COmmand above in our RXQ allocation
+ * routine, ideally, this code would be in t4vf_hw.c. Again, we'll
+ * have to see if there's some reasonable way to parameterize it
+ * into the common code ...
+ */
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.op_to_vfn = cpu_to_be32(FW_CMD_OP(FW_EQ_ETH_CMD) |
+ FW_CMD_REQUEST |
+ FW_CMD_WRITE |
+ FW_CMD_EXEC);
+ cmd.alloc_to_len16 = cpu_to_be32(FW_EQ_ETH_CMD_ALLOC |
+ FW_EQ_ETH_CMD_EQSTART |
+ FW_LEN16(cmd));
+ cmd.viid_pkd = cpu_to_be32(FW_EQ_ETH_CMD_VIID(pi->viid));
+ cmd.fetchszm_to_iqid =
+ cpu_to_be32(FW_EQ_ETH_CMD_HOSTFCMODE(SGE_HOSTFCMODE_STPG) |
+ FW_EQ_ETH_CMD_PCIECHN(pi->port_id) |
+ FW_EQ_ETH_CMD_IQID(iqid));
+ cmd.dcaen_to_eqsize =
+ cpu_to_be32(FW_EQ_ETH_CMD_FBMIN(SGE_FETCHBURSTMIN_64B) |
+ FW_EQ_ETH_CMD_FBMAX(SGE_FETCHBURSTMAX_512B) |
+ FW_EQ_ETH_CMD_CIDXFTHRESH(SGE_CIDXFLUSHTHRESH_32) |
+ FW_EQ_ETH_CMD_EQSIZE(nentries));
+ cmd.eqaddr = cpu_to_be64(txq->q.phys_addr);
+
+ /*
+ * Issue the firmware Egress Queue Command and extract the results if
+ * it completes successfully.
+ */
+ ret = t4vf_wr_mbox(adapter, &cmd, sizeof(cmd), &rpl);
+ if (ret) {
+ /*
+ * The girmware Ingress Queue Command failed for some reason.
+ * Free up our partial allocation state and return the error.
+ */
+ kfree(txq->q.sdesc);
+ txq->q.sdesc = NULL;
+ dma_free_coherent(adapter->pdev_dev,
+ nentries * sizeof(struct tx_desc),
+ txq->q.desc, txq->q.phys_addr);
+ txq->q.desc = NULL;
+ return ret;
+ }
+
+ txq->q.in_use = 0;
+ txq->q.cidx = 0;
+ txq->q.pidx = 0;
+ txq->q.stat = (void *)&txq->q.desc[txq->q.size];
+ txq->q.cntxt_id = FW_EQ_ETH_CMD_EQID_GET(be32_to_cpu(rpl.eqid_pkd));
+ txq->q.abs_id =
+ FW_EQ_ETH_CMD_PHYSEQID_GET(be32_to_cpu(rpl.physeqid_pkd));
+ txq->txq = devq;
+ txq->tso = 0;
+ txq->tx_cso = 0;
+ txq->vlan_ins = 0;
+ txq->q.stops = 0;
+ txq->q.restarts = 0;
+ txq->mapping_err = 0;
+ return 0;
+}
+
+/*
+ * Free the DMA map resources associated with a TX queue.
+ */
+static void free_txq(struct adapter *adapter, struct sge_txq *tq)
+{
+ dma_free_coherent(adapter->pdev_dev,
+ tq->size * sizeof(*tq->desc) + STAT_LEN,
+ tq->desc, tq->phys_addr);
+ tq->cntxt_id = 0;
+ tq->sdesc = NULL;
+ tq->desc = NULL;
+}
+
+/*
+ * Free the resources associated with a response queue (possibly including a
+ * free list).
+ */
+static void free_rspq_fl(struct adapter *adapter, struct sge_rspq *rspq,
+ struct sge_fl *fl)
+{
+ unsigned int flid = fl ? fl->cntxt_id : 0xffff;
+
+ t4vf_iq_free(adapter, FW_IQ_TYPE_FL_INT_CAP,
+ rspq->cntxt_id, flid, 0xffff);
+ dma_free_coherent(adapter->pdev_dev, (rspq->size + 1) * rspq->iqe_len,
+ rspq->desc, rspq->phys_addr);
+ netif_napi_del(&rspq->napi);
+ rspq->netdev = NULL;
+ rspq->cntxt_id = 0;
+ rspq->abs_id = 0;
+ rspq->desc = NULL;
+
+ if (fl) {
+ free_rx_bufs(adapter, fl, fl->avail);
+ dma_free_coherent(adapter->pdev_dev,
+ fl->size * sizeof(*fl->desc) + STAT_LEN,
+ fl->desc, fl->addr);
+ kfree(fl->sdesc);
+ fl->sdesc = NULL;
+ fl->cntxt_id = 0;
+ fl->desc = NULL;
+ }
+}
+
+/**
+ * t4vf_free_sge_resources - free SGE resources
+ * @adapter: the adapter
+ *
+ * Frees resources used by the SGE queue sets.
+ */
+void t4vf_free_sge_resources(struct adapter *adapter)
+{
+ struct sge *s = &adapter->sge;
+ struct sge_eth_rxq *rxq = s->ethrxq;
+ struct sge_eth_txq *txq = s->ethtxq;
+ struct sge_rspq *evtq = &s->fw_evtq;
+ struct sge_rspq *intrq = &s->intrq;
+ int qs;
+
+ for (qs = 0; qs < adapter->sge.ethqsets; qs++, rxq++, txq++) {
+ if (rxq->rspq.desc)
+ free_rspq_fl(adapter, &rxq->rspq, &rxq->fl);
+ if (txq->q.desc) {
+ t4vf_eth_eq_free(adapter, txq->q.cntxt_id);
+ free_tx_desc(adapter, &txq->q, txq->q.in_use, true);
+ kfree(txq->q.sdesc);
+ free_txq(adapter, &txq->q);
+ }
+ }
+ if (evtq->desc)
+ free_rspq_fl(adapter, evtq, NULL);
+ if (intrq->desc)
+ free_rspq_fl(adapter, intrq, NULL);
+}
+
+/**
+ * t4vf_sge_start - enable SGE operation
+ * @adapter: the adapter
+ *
+ * Start tasklets and timers associated with the DMA engine.
+ */
+void t4vf_sge_start(struct adapter *adapter)
+{
+ adapter->sge.ethtxq_rover = 0;
+ mod_timer(&adapter->sge.rx_timer, jiffies + RX_QCHECK_PERIOD);
+ mod_timer(&adapter->sge.tx_timer, jiffies + TX_QCHECK_PERIOD);
+}
+
+/**
+ * t4vf_sge_stop - disable SGE operation
+ * @adapter: the adapter
+ *
+ * Stop tasklets and timers associated with the DMA engine. Note that
+ * this is effective only if measures have been taken to disable any HW
+ * events that may restart them.
+ */
+void t4vf_sge_stop(struct adapter *adapter)
+{
+ struct sge *s = &adapter->sge;
+
+ if (s->rx_timer.function)
+ del_timer_sync(&s->rx_timer);
+ if (s->tx_timer.function)
+ del_timer_sync(&s->tx_timer);
+}
+
+/**
+ * t4vf_sge_init - initialize SGE
+ * @adapter: the adapter
+ *
+ * Performs SGE initialization needed every time after a chip reset.
+ * We do not initialize any of the queue sets here, instead the driver
+ * top-level must request those individually. We also do not enable DMA
+ * here, that should be done after the queues have been set up.
+ */
+int t4vf_sge_init(struct adapter *adapter)
+{
+ struct sge_params *sge_params = &adapter->params.sge;
+ u32 fl0 = sge_params->sge_fl_buffer_size[0];
+ u32 fl1 = sge_params->sge_fl_buffer_size[1];
+ struct sge *s = &adapter->sge;
+
+ /*
+ * Start by vetting the basic SGE parameters which have been set up by
+ * the Physical Function Driver. Ideally we should be able to deal
+ * with _any_ configuration. Practice is different ...
+ */
+ if (fl0 != PAGE_SIZE || (fl1 != 0 && fl1 <= fl0)) {
+ dev_err(adapter->pdev_dev, "bad SGE FL buffer sizes [%d, %d]\n",
+ fl0, fl1);
+ return -EINVAL;
+ }
+ if ((sge_params->sge_control & RXPKTCPLMODE) == 0) {
+ dev_err(adapter->pdev_dev, "bad SGE CPL MODE\n");
+ return -EINVAL;
+ }
+
+ /*
+ * Now translate the adapter parameters into our internal forms.
+ */
+ if (fl1)
+ FL_PG_ORDER = ilog2(fl1) - PAGE_SHIFT;
+ STAT_LEN = ((sge_params->sge_control & EGRSTATUSPAGESIZE) ? 128 : 64);
+ PKTSHIFT = PKTSHIFT_GET(sge_params->sge_control);
+ FL_ALIGN = 1 << (INGPADBOUNDARY_GET(sge_params->sge_control) +
+ SGE_INGPADBOUNDARY_SHIFT);
+
+ /*
+ * Set up tasklet timers.
+ */
+ setup_timer(&s->rx_timer, sge_rx_timer_cb, (unsigned long)adapter);
+ setup_timer(&s->tx_timer, sge_tx_timer_cb, (unsigned long)adapter);
+
+ /*
+ * Initialize Forwarded Interrupt Queue lock.
+ */
+ spin_lock_init(&s->intrq_lock);
+
+ return 0;
+}
diff --git a/drivers/net/cxgb4vf/t4vf_common.h b/drivers/net/cxgb4vf/t4vf_common.h
new file mode 100644
index 00000000000..5c7bde7f9ba
--- /dev/null
+++ b/drivers/net/cxgb4vf/t4vf_common.h
@@ -0,0 +1,273 @@
+/*
+ * This file is part of the Chelsio T4 PCI-E SR-IOV Virtual Function Ethernet
+ * driver for Linux.
+ *
+ * Copyright (c) 2009-2010 Chelsio Communications, 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 __T4VF_COMMON_H__
+#define __T4VF_COMMON_H__
+
+#include "../cxgb4/t4fw_api.h"
+
+/*
+ * The "len16" field of a Firmware Command Structure ...
+ */
+#define FW_LEN16(fw_struct) FW_CMD_LEN16(sizeof(fw_struct) / 16)
+
+/*
+ * Per-VF statistics.
+ */
+struct t4vf_port_stats {
+ /*
+ * TX statistics.
+ */
+ u64 tx_bcast_bytes; /* broadcast */
+ u64 tx_bcast_frames;
+ u64 tx_mcast_bytes; /* multicast */
+ u64 tx_mcast_frames;
+ u64 tx_ucast_bytes; /* unicast */
+ u64 tx_ucast_frames;
+ u64 tx_drop_frames; /* TX dropped frames */
+ u64 tx_offload_bytes; /* offload */
+ u64 tx_offload_frames;
+
+ /*
+ * RX statistics.
+ */
+ u64 rx_bcast_bytes; /* broadcast */
+ u64 rx_bcast_frames;
+ u64 rx_mcast_bytes; /* multicast */
+ u64 rx_mcast_frames;
+ u64 rx_ucast_bytes;
+ u64 rx_ucast_frames; /* unicast */
+
+ u64 rx_err_frames; /* RX error frames */
+};
+
+/*
+ * Per-"port" (Virtual Interface) link configuration ...
+ */
+struct link_config {
+ unsigned int supported; /* link capabilities */
+ unsigned int advertising; /* advertised capabilities */
+ unsigned short requested_speed; /* speed user has requested */
+ unsigned short speed; /* actual link speed */
+ unsigned char requested_fc; /* flow control user has requested */
+ unsigned char fc; /* actual link flow control */
+ unsigned char autoneg; /* autonegotiating? */
+ unsigned char link_ok; /* link up? */
+};
+
+enum {
+ PAUSE_RX = 1 << 0,
+ PAUSE_TX = 1 << 1,
+ PAUSE_AUTONEG = 1 << 2
+};
+
+/*
+ * General device parameters ...
+ */
+struct dev_params {
+ u32 fwrev; /* firmware version */
+ u32 tprev; /* TP Microcode Version */
+};
+
+/*
+ * Scatter Gather Engine parameters. These are almost all determined by the
+ * Physical Function Driver. We just need to grab them to see within which
+ * environment we're playing ...
+ */
+struct sge_params {
+ u32 sge_control; /* padding, boundaries, lengths, etc. */
+ u32 sge_host_page_size; /* RDMA page sizes */
+ u32 sge_queues_per_page; /* RDMA queues/page */
+ u32 sge_user_mode_limits; /* limits for BAR2 user mode accesses */
+ u32 sge_fl_buffer_size[16]; /* free list buffer sizes */
+ u32 sge_ingress_rx_threshold; /* RX counter interrupt threshold[4] */
+ u32 sge_timer_value_0_and_1; /* interrupt coalescing timer values */
+ u32 sge_timer_value_2_and_3;
+ u32 sge_timer_value_4_and_5;
+};
+
+/*
+ * Vital Product Data parameters.
+ */
+struct vpd_params {
+ u32 cclk; /* Core Clock (KHz) */
+};
+
+/*
+ * Global Receive Side Scaling (RSS) parameters in host-native format.
+ */
+struct rss_params {
+ unsigned int mode; /* RSS mode */
+ union {
+ struct {
+ int synmapen:1; /* SYN Map Enable */
+ int syn4tupenipv6:1; /* enable hashing 4-tuple IPv6 SYNs */
+ int syn2tupenipv6:1; /* enable hashing 2-tuple IPv6 SYNs */
+ int syn4tupenipv4:1; /* enable hashing 4-tuple IPv4 SYNs */
+ int syn2tupenipv4:1; /* enable hashing 2-tuple IPv4 SYNs */
+ int ofdmapen:1; /* Offload Map Enable */
+ int tnlmapen:1; /* Tunnel Map Enable */
+ int tnlalllookup:1; /* Tunnel All Lookup */
+ int hashtoeplitz:1; /* use Toeplitz hash */
+ } basicvirtual;
+ } u;
+};
+
+/*
+ * Virtual Interface RSS Configuration in host-native format.
+ */
+union rss_vi_config {
+ struct {
+ u16 defaultq; /* Ingress Queue ID for !tnlalllookup */
+ int ip6fourtupen:1; /* hash 4-tuple IPv6 ingress packets */
+ int ip6twotupen:1; /* hash 2-tuple IPv6 ingress packets */
+ int ip4fourtupen:1; /* hash 4-tuple IPv4 ingress packets */
+ int ip4twotupen:1; /* hash 2-tuple IPv4 ingress packets */
+ int udpen; /* hash 4-tuple UDP ingress packets */
+ } basicvirtual;
+};
+
+/*
+ * Maximum resources provisioned for a PCI VF.
+ */
+struct vf_resources {
+ unsigned int nvi; /* N virtual interfaces */
+ unsigned int neq; /* N egress Qs */
+ unsigned int nethctrl; /* N egress ETH or CTRL Qs */
+ unsigned int niqflint; /* N ingress Qs/w free list(s) & intr */
+ unsigned int niq; /* N ingress Qs */
+ unsigned int tc; /* PCI-E traffic class */
+ unsigned int pmask; /* port access rights mask */
+ unsigned int nexactf; /* N exact MPS filters */
+ unsigned int r_caps; /* read capabilities */
+ unsigned int wx_caps; /* write/execute capabilities */
+};
+
+/*
+ * Per-"adapter" (Virtual Function) parameters.
+ */
+struct adapter_params {
+ struct dev_params dev; /* general device parameters */
+ struct sge_params sge; /* Scatter Gather Engine */
+ struct vpd_params vpd; /* Vital Product Data */
+ struct rss_params rss; /* Receive Side Scaling */
+ struct vf_resources vfres; /* Virtual Function Resource limits */
+ u8 nports; /* # of Ethernet "ports" */
+};
+
+#include "adapter.h"
+
+#ifndef PCI_VENDOR_ID_CHELSIO
+# define PCI_VENDOR_ID_CHELSIO 0x1425
+#endif
+
+#define for_each_port(adapter, iter) \
+ for (iter = 0; iter < (adapter)->params.nports; iter++)
+
+static inline bool is_10g_port(const struct link_config *lc)
+{
+ return (lc->supported & SUPPORTED_10000baseT_Full) != 0;
+}
+
+static inline unsigned int core_ticks_per_usec(const struct adapter *adapter)
+{
+ return adapter->params.vpd.cclk / 1000;
+}
+
+static inline unsigned int us_to_core_ticks(const struct adapter *adapter,
+ unsigned int us)
+{
+ return (us * adapter->params.vpd.cclk) / 1000;
+}
+
+static inline unsigned int core_ticks_to_us(const struct adapter *adapter,
+ unsigned int ticks)
+{
+ return (ticks * 1000) / adapter->params.vpd.cclk;
+}
+
+int t4vf_wr_mbox_core(struct adapter *, const void *, int, void *, bool);
+
+static inline int t4vf_wr_mbox(struct adapter *adapter, const void *cmd,
+ int size, void *rpl)
+{
+ return t4vf_wr_mbox_core(adapter, cmd, size, rpl, true);
+}
+
+static inline int t4vf_wr_mbox_ns(struct adapter *adapter, const void *cmd,
+ int size, void *rpl)
+{
+ return t4vf_wr_mbox_core(adapter, cmd, size, rpl, false);
+}
+
+int __devinit t4vf_wait_dev_ready(struct adapter *);
+int __devinit t4vf_port_init(struct adapter *, int);
+
+int t4vf_query_params(struct adapter *, unsigned int, const u32 *, u32 *);
+int t4vf_set_params(struct adapter *, unsigned int, const u32 *, const u32 *);
+
+int t4vf_get_sge_params(struct adapter *);
+int t4vf_get_vpd_params(struct adapter *);
+int t4vf_get_dev_params(struct adapter *);
+int t4vf_get_rss_glb_config(struct adapter *);
+int t4vf_get_vfres(struct adapter *);
+
+int t4vf_read_rss_vi_config(struct adapter *, unsigned int,
+ union rss_vi_config *);
+int t4vf_write_rss_vi_config(struct adapter *, unsigned int,
+ union rss_vi_config *);
+int t4vf_config_rss_range(struct adapter *, unsigned int, int, int,
+ const u16 *, int);
+
+int t4vf_alloc_vi(struct adapter *, int);
+int t4vf_free_vi(struct adapter *, int);
+int t4vf_enable_vi(struct adapter *, unsigned int, bool, bool);
+int t4vf_identify_port(struct adapter *, unsigned int, unsigned int);
+
+int t4vf_set_rxmode(struct adapter *, unsigned int, int, int, int, int, int,
+ bool);
+int t4vf_alloc_mac_filt(struct adapter *, unsigned int, bool, unsigned int,
+ const u8 **, u16 *, u64 *, bool);
+int t4vf_change_mac(struct adapter *, unsigned int, int, const u8 *, bool);
+int t4vf_set_addr_hash(struct adapter *, unsigned int, bool, u64, bool);
+int t4vf_get_port_stats(struct adapter *, int, struct t4vf_port_stats *);
+
+int t4vf_iq_free(struct adapter *, unsigned int, unsigned int, unsigned int,
+ unsigned int);
+int t4vf_eth_eq_free(struct adapter *, unsigned int);
+
+int t4vf_handle_fw_rpl(struct adapter *, const __be64 *);
+
+#endif /* __T4VF_COMMON_H__ */
diff --git a/drivers/net/cxgb4vf/t4vf_defs.h b/drivers/net/cxgb4vf/t4vf_defs.h
new file mode 100644
index 00000000000..c7b127d9376
--- /dev/null
+++ b/drivers/net/cxgb4vf/t4vf_defs.h
@@ -0,0 +1,121 @@
+/*
+ * This file is part of the Chelsio T4 PCI-E SR-IOV Virtual Function Ethernet
+ * driver for Linux.
+ *
+ * Copyright (c) 2009-2010 Chelsio Communications, 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 __T4VF_DEFS_H__
+#define __T4VF_DEFS_H__
+
+#include "../cxgb4/t4_regs.h"
+
+/*
+ * The VF Register Map.
+ *
+ * The Scatter Gather Engine (SGE), Multiport Support module (MPS), PIO Local
+ * bus module (PL) and CPU Interface Module (CIM) components are mapped via
+ * the Slice to Module Map Table (see below) in the Physical Function Register
+ * Map. The Mail Box Data (MBDATA) range is mapped via the PCI-E Mailbox Base
+ * and Offset registers in the PF Register Map. The MBDATA base address is
+ * quite constrained as it determines the Mailbox Data addresses for both PFs
+ * and VFs, and therefore must fit in both the VF and PF Register Maps without
+ * overlapping other registers.
+ */
+#define T4VF_SGE_BASE_ADDR 0x0000
+#define T4VF_MPS_BASE_ADDR 0x0100
+#define T4VF_PL_BASE_ADDR 0x0200
+#define T4VF_MBDATA_BASE_ADDR 0x0240
+#define T4VF_CIM_BASE_ADDR 0x0300
+
+#define T4VF_REGMAP_START 0x0000
+#define T4VF_REGMAP_SIZE 0x0400
+
+/*
+ * There's no hardware limitation which requires that the addresses of the
+ * Mailbox Data in the fixed CIM PF map and the programmable VF map must
+ * match. However, it's a useful convention ...
+ */
+#if T4VF_MBDATA_BASE_ADDR != CIM_PF_MAILBOX_DATA
+#error T4VF_MBDATA_BASE_ADDR must match CIM_PF_MAILBOX_DATA!
+#endif
+
+/*
+ * Virtual Function "Slice to Module Map Table" definitions.
+ *
+ * This table allows us to map subsets of the various module register sets
+ * into the T4VF Register Map. Each table entry identifies the index of the
+ * module whose registers are being mapped, the offset within the module's
+ * register set that the mapping should start at, the limit of the mapping,
+ * and the offset within the T4VF Register Map to which the module's registers
+ * are being mapped. All addresses and qualtities are in terms of 32-bit
+ * words. The "limit" value is also in terms of 32-bit words and is equal to
+ * the last address mapped in the T4VF Register Map 1 (i.e. it's a "<="
+ * relation rather than a "<").
+ */
+#define T4VF_MOD_MAP(module, index, first, last) \
+ T4VF_MOD_MAP_##module##_INDEX = (index), \
+ T4VF_MOD_MAP_##module##_FIRST = (first), \
+ T4VF_MOD_MAP_##module##_LAST = (last), \
+ T4VF_MOD_MAP_##module##_OFFSET = ((first)/4), \
+ T4VF_MOD_MAP_##module##_BASE = \
+ (T4VF_##module##_BASE_ADDR/4 + (first)/4), \
+ T4VF_MOD_MAP_##module##_LIMIT = \
+ (T4VF_##module##_BASE_ADDR/4 + (last)/4),
+
+#define SGE_VF_KDOORBELL 0x0
+#define SGE_VF_GTS 0x4
+#define MPS_VF_CTL 0x0
+#define MPS_VF_STAT_RX_VF_ERR_FRAMES_H 0xfc
+#define PL_VF_WHOAMI 0x0
+#define CIM_VF_EXT_MAILBOX_CTRL 0x0
+#define CIM_VF_EXT_MAILBOX_STATUS 0x4
+
+enum {
+ T4VF_MOD_MAP(SGE, 2, SGE_VF_KDOORBELL, SGE_VF_GTS)
+ T4VF_MOD_MAP(MPS, 0, MPS_VF_CTL, MPS_VF_STAT_RX_VF_ERR_FRAMES_H)
+ T4VF_MOD_MAP(PL, 3, PL_VF_WHOAMI, PL_VF_WHOAMI)
+ T4VF_MOD_MAP(CIM, 1, CIM_VF_EXT_MAILBOX_CTRL, CIM_VF_EXT_MAILBOX_STATUS)
+};
+
+/*
+ * There isn't a Slice to Module Map Table entry for the Mailbox Data
+ * registers, but it's convenient to use similar names as above. There are 8
+ * little-endian 64-bit Mailbox Data registers. Note that the "instances"
+ * value below is in terms of 32-bit words which matches the "word" addressing
+ * space we use above for the Slice to Module Map Space.
+ */
+#define NUM_CIM_VF_MAILBOX_DATA_INSTANCES 16
+
+#define T4VF_MBDATA_FIRST 0
+#define T4VF_MBDATA_LAST ((NUM_CIM_VF_MAILBOX_DATA_INSTANCES-1)*4)
+
+#endif /* __T4T4VF_DEFS_H__ */
diff --git a/drivers/net/cxgb4vf/t4vf_hw.c b/drivers/net/cxgb4vf/t4vf_hw.c
new file mode 100644
index 00000000000..ea1c123f0cb
--- /dev/null
+++ b/drivers/net/cxgb4vf/t4vf_hw.c
@@ -0,0 +1,1333 @@
+/*
+ * This file is part of the Chelsio T4 PCI-E SR-IOV Virtual Function Ethernet
+ * driver for Linux.
+ *
+ * Copyright (c) 2009-2010 Chelsio Communications, 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.
+ */
+
+#include <linux/version.h>
+#include <linux/pci.h>
+
+#include "t4vf_common.h"
+#include "t4vf_defs.h"
+
+#include "../cxgb4/t4_regs.h"
+#include "../cxgb4/t4fw_api.h"
+
+/*
+ * Wait for the device to become ready (signified by our "who am I" register
+ * returning a value other than all 1's). Return an error if it doesn't
+ * become ready ...
+ */
+int __devinit t4vf_wait_dev_ready(struct adapter *adapter)
+{
+ const u32 whoami = T4VF_PL_BASE_ADDR + PL_VF_WHOAMI;
+ const u32 notready1 = 0xffffffff;
+ const u32 notready2 = 0xeeeeeeee;
+ u32 val;
+
+ val = t4_read_reg(adapter, whoami);
+ if (val != notready1 && val != notready2)
+ return 0;
+ msleep(500);
+ val = t4_read_reg(adapter, whoami);
+ if (val != notready1 && val != notready2)
+ return 0;
+ else
+ return -EIO;
+}
+
+/*
+ * Get the reply to a mailbox command and store it in @rpl in big-endian order
+ * (since the firmware data structures are specified in a big-endian layout).
+ */
+static void get_mbox_rpl(struct adapter *adapter, __be64 *rpl, int size,
+ u32 mbox_data)
+{
+ for ( ; size; size -= 8, mbox_data += 8)
+ *rpl++ = cpu_to_be64(t4_read_reg64(adapter, mbox_data));
+}
+
+/*
+ * Dump contents of mailbox with a leading tag.
+ */
+static void dump_mbox(struct adapter *adapter, const char *tag, u32 mbox_data)
+{
+ dev_err(adapter->pdev_dev,
+ "mbox %s: %llx %llx %llx %llx %llx %llx %llx %llx\n", tag,
+ (unsigned long long)t4_read_reg64(adapter, mbox_data + 0),
+ (unsigned long long)t4_read_reg64(adapter, mbox_data + 8),
+ (unsigned long long)t4_read_reg64(adapter, mbox_data + 16),
+ (unsigned long long)t4_read_reg64(adapter, mbox_data + 24),
+ (unsigned long long)t4_read_reg64(adapter, mbox_data + 32),
+ (unsigned long long)t4_read_reg64(adapter, mbox_data + 40),
+ (unsigned long long)t4_read_reg64(adapter, mbox_data + 48),
+ (unsigned long long)t4_read_reg64(adapter, mbox_data + 56));
+}
+
+/**
+ * t4vf_wr_mbox_core - send a command to FW through the mailbox
+ * @adapter: the adapter
+ * @cmd: the command to write
+ * @size: command length in bytes
+ * @rpl: where to optionally store the reply
+ * @sleep_ok: if true we may sleep while awaiting command completion
+ *
+ * Sends the given command to FW through the mailbox and waits for the
+ * FW to execute the command. If @rpl is not %NULL it is used to store
+ * the FW's reply to the command. The command and its optional reply
+ * are of the same length. FW can take up to 500 ms to respond.
+ * @sleep_ok determines whether we may sleep while awaiting the response.
+ * If sleeping is allowed we use progressive backoff otherwise we spin.
+ *
+ * The return value is 0 on success or a negative errno on failure. A
+ * failure can happen either because we are not able to execute the
+ * command or FW executes it but signals an error. In the latter case
+ * the return value is the error code indicated by FW (negated).
+ */
+int t4vf_wr_mbox_core(struct adapter *adapter, const void *cmd, int size,
+ void *rpl, bool sleep_ok)
+{
+ static int delay[] = {
+ 1, 1, 3, 5, 10, 10, 20, 50, 100
+ };
+
+ u32 v;
+ int i, ms, delay_idx;
+ const __be64 *p;
+ u32 mbox_data = T4VF_MBDATA_BASE_ADDR;
+ u32 mbox_ctl = T4VF_CIM_BASE_ADDR + CIM_VF_EXT_MAILBOX_CTRL;
+
+ /*
+ * Commands must be multiples of 16 bytes in length and may not be
+ * larger than the size of the Mailbox Data register array.
+ */
+ if ((size % 16) != 0 ||
+ size > NUM_CIM_VF_MAILBOX_DATA_INSTANCES * 4)
+ return -EINVAL;
+
+ /*
+ * Loop trying to get ownership of the mailbox. Return an error
+ * if we can't gain ownership.
+ */
+ v = MBOWNER_GET(t4_read_reg(adapter, mbox_ctl));
+ for (i = 0; v == MBOX_OWNER_NONE && i < 3; i++)
+ v = MBOWNER_GET(t4_read_reg(adapter, mbox_ctl));
+ if (v != MBOX_OWNER_DRV)
+ return v == MBOX_OWNER_FW ? -EBUSY : -ETIMEDOUT;
+
+ /*
+ * Write the command array into the Mailbox Data register array and
+ * transfer ownership of the mailbox to the firmware.
+ */
+ for (i = 0, p = cmd; i < size; i += 8)
+ t4_write_reg64(adapter, mbox_data + i, be64_to_cpu(*p++));
+ t4_write_reg(adapter, mbox_ctl,
+ MBMSGVALID | MBOWNER(MBOX_OWNER_FW));
+ t4_read_reg(adapter, mbox_ctl); /* flush write */
+
+ /*
+ * Spin waiting for firmware to acknowledge processing our command.
+ */
+ delay_idx = 0;
+ ms = delay[0];
+
+ for (i = 0; i < 500; i += ms) {
+ if (sleep_ok) {
+ ms = delay[delay_idx];
+ if (delay_idx < ARRAY_SIZE(delay) - 1)
+ delay_idx++;
+ msleep(ms);
+ } else
+ mdelay(ms);
+
+ /*
+ * If we're the owner, see if this is the reply we wanted.
+ */
+ v = t4_read_reg(adapter, mbox_ctl);
+ if (MBOWNER_GET(v) == MBOX_OWNER_DRV) {
+ /*
+ * If the Message Valid bit isn't on, revoke ownership
+ * of the mailbox and continue waiting for our reply.
+ */
+ if ((v & MBMSGVALID) == 0) {
+ t4_write_reg(adapter, mbox_ctl,
+ MBOWNER(MBOX_OWNER_NONE));
+ continue;
+ }
+
+ /*
+ * We now have our reply. Extract the command return
+ * value, copy the reply back to our caller's buffer
+ * (if specified) and revoke ownership of the mailbox.
+ * We return the (negated) firmware command return
+ * code (this depends on FW_SUCCESS == 0).
+ */
+
+ /* return value in low-order little-endian word */
+ v = t4_read_reg(adapter, mbox_data);
+ if (FW_CMD_RETVAL_GET(v))
+ dump_mbox(adapter, "FW Error", mbox_data);
+
+ if (rpl) {
+ /* request bit in high-order BE word */
+ WARN_ON((be32_to_cpu(*(const u32 *)cmd)
+ & FW_CMD_REQUEST) == 0);
+ get_mbox_rpl(adapter, rpl, size, mbox_data);
+ WARN_ON((be32_to_cpu(*(u32 *)rpl)
+ & FW_CMD_REQUEST) != 0);
+ }
+ t4_write_reg(adapter, mbox_ctl,
+ MBOWNER(MBOX_OWNER_NONE));
+ return -FW_CMD_RETVAL_GET(v);
+ }
+ }
+
+ /*
+ * We timed out. Return the error ...
+ */
+ dump_mbox(adapter, "FW Timeout", mbox_data);
+ return -ETIMEDOUT;
+}
+
+/**
+ * hash_mac_addr - return the hash value of a MAC address
+ * @addr: the 48-bit Ethernet MAC address
+ *
+ * Hashes a MAC address according to the hash function used by hardware
+ * inexact (hash) address matching.
+ */
+static int hash_mac_addr(const u8 *addr)
+{
+ u32 a = ((u32)addr[0] << 16) | ((u32)addr[1] << 8) | addr[2];
+ u32 b = ((u32)addr[3] << 16) | ((u32)addr[4] << 8) | addr[5];
+ a ^= b;
+ a ^= (a >> 12);
+ a ^= (a >> 6);
+ return a & 0x3f;
+}
+
+/**
+ * init_link_config - initialize a link's SW state
+ * @lc: structure holding the link state
+ * @caps: link capabilities
+ *
+ * Initializes the SW state maintained for each link, including the link's
+ * capabilities and default speed/flow-control/autonegotiation settings.
+ */
+static void __devinit init_link_config(struct link_config *lc,
+ unsigned int caps)
+{
+ lc->supported = caps;
+ lc->requested_speed = 0;
+ lc->speed = 0;
+ lc->requested_fc = lc->fc = PAUSE_RX | PAUSE_TX;
+ if (lc->supported & SUPPORTED_Autoneg) {
+ lc->advertising = lc->supported;
+ lc->autoneg = AUTONEG_ENABLE;
+ lc->requested_fc |= PAUSE_AUTONEG;
+ } else {
+ lc->advertising = 0;
+ lc->autoneg = AUTONEG_DISABLE;
+ }
+}
+
+/**
+ * t4vf_port_init - initialize port hardware/software state
+ * @adapter: the adapter
+ * @pidx: the adapter port index
+ */
+int __devinit t4vf_port_init(struct adapter *adapter, int pidx)
+{
+ struct port_info *pi = adap2pinfo(adapter, pidx);
+ struct fw_vi_cmd vi_cmd, vi_rpl;
+ struct fw_port_cmd port_cmd, port_rpl;
+ int v;
+ u32 word;
+
+ /*
+ * Execute a VI Read command to get our Virtual Interface information
+ * like MAC address, etc.
+ */
+ memset(&vi_cmd, 0, sizeof(vi_cmd));
+ vi_cmd.op_to_vfn = cpu_to_be32(FW_CMD_OP(FW_VI_CMD) |
+ FW_CMD_REQUEST |
+ FW_CMD_READ);
+ vi_cmd.alloc_to_len16 = cpu_to_be32(FW_LEN16(vi_cmd));
+ vi_cmd.type_viid = cpu_to_be16(FW_VI_CMD_VIID(pi->viid));
+ v = t4vf_wr_mbox(adapter, &vi_cmd, sizeof(vi_cmd), &vi_rpl);
+ if (v)
+ return v;
+
+ BUG_ON(pi->port_id != FW_VI_CMD_PORTID_GET(vi_rpl.portid_pkd));
+ pi->rss_size = FW_VI_CMD_RSSSIZE_GET(be16_to_cpu(vi_rpl.rsssize_pkd));
+ t4_os_set_hw_addr(adapter, pidx, vi_rpl.mac);
+
+ /*
+ * If we don't have read access to our port information, we're done
+ * now. Otherwise, execute a PORT Read command to get it ...
+ */
+ if (!(adapter->params.vfres.r_caps & FW_CMD_CAP_PORT))
+ return 0;
+
+ memset(&port_cmd, 0, sizeof(port_cmd));
+ port_cmd.op_to_portid = cpu_to_be32(FW_CMD_OP(FW_PORT_CMD) |
+ FW_CMD_REQUEST |
+ FW_CMD_READ |
+ FW_PORT_CMD_PORTID(pi->port_id));
+ port_cmd.action_to_len16 =
+ cpu_to_be32(FW_PORT_CMD_ACTION(FW_PORT_ACTION_GET_PORT_INFO) |
+ FW_LEN16(port_cmd));
+ v = t4vf_wr_mbox(adapter, &port_cmd, sizeof(port_cmd), &port_rpl);
+ if (v)
+ return v;
+
+ v = 0;
+ word = be16_to_cpu(port_rpl.u.info.pcap);
+ if (word & FW_PORT_CAP_SPEED_100M)
+ v |= SUPPORTED_100baseT_Full;
+ if (word & FW_PORT_CAP_SPEED_1G)
+ v |= SUPPORTED_1000baseT_Full;
+ if (word & FW_PORT_CAP_SPEED_10G)
+ v |= SUPPORTED_10000baseT_Full;
+ if (word & FW_PORT_CAP_ANEG)
+ v |= SUPPORTED_Autoneg;
+ init_link_config(&pi->link_cfg, v);
+
+ return 0;
+}
+
+/**
+ * t4vf_query_params - query FW or device parameters
+ * @adapter: the adapter
+ * @nparams: the number of parameters
+ * @params: the parameter names
+ * @vals: the parameter values
+ *
+ * Reads the values of firmware or device parameters. Up to 7 parameters
+ * can be queried at once.
+ */
+int t4vf_query_params(struct adapter *adapter, unsigned int nparams,
+ const u32 *params, u32 *vals)
+{
+ int i, ret;
+ struct fw_params_cmd cmd, rpl;
+ struct fw_params_param *p;
+ size_t len16;
+
+ if (nparams > 7)
+ return -EINVAL;
+
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.op_to_vfn = cpu_to_be32(FW_CMD_OP(FW_PARAMS_CMD) |
+ FW_CMD_REQUEST |
+ FW_CMD_READ);
+ len16 = DIV_ROUND_UP(offsetof(struct fw_params_cmd,
+ param[nparams].mnem), 16);
+ cmd.retval_len16 = cpu_to_be32(FW_CMD_LEN16(len16));
+ for (i = 0, p = &cmd.param[0]; i < nparams; i++, p++)
+ p->mnem = htonl(*params++);
+
+ ret = t4vf_wr_mbox(adapter, &cmd, sizeof(cmd), &rpl);
+ if (ret == 0)
+ for (i = 0, p = &rpl.param[0]; i < nparams; i++, p++)
+ *vals++ = be32_to_cpu(p->val);
+ return ret;
+}
+
+/**
+ * t4vf_set_params - sets FW or device parameters
+ * @adapter: the adapter
+ * @nparams: the number of parameters
+ * @params: the parameter names
+ * @vals: the parameter values
+ *
+ * Sets the values of firmware or device parameters. Up to 7 parameters
+ * can be specified at once.
+ */
+int t4vf_set_params(struct adapter *adapter, unsigned int nparams,
+ const u32 *params, const u32 *vals)
+{
+ int i;
+ struct fw_params_cmd cmd;
+ struct fw_params_param *p;
+ size_t len16;
+
+ if (nparams > 7)
+ return -EINVAL;
+
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.op_to_vfn = cpu_to_be32(FW_CMD_OP(FW_PARAMS_CMD) |
+ FW_CMD_REQUEST |
+ FW_CMD_WRITE);
+ len16 = DIV_ROUND_UP(offsetof(struct fw_params_cmd,
+ param[nparams]), 16);
+ cmd.retval_len16 = cpu_to_be32(FW_CMD_LEN16(len16));
+ for (i = 0, p = &cmd.param[0]; i < nparams; i++, p++) {
+ p->mnem = cpu_to_be32(*params++);
+ p->val = cpu_to_be32(*vals++);
+ }
+
+ return t4vf_wr_mbox(adapter, &cmd, sizeof(cmd), NULL);
+}
+
+/**
+ * t4vf_get_sge_params - retrieve adapter Scatter gather Engine parameters
+ * @adapter: the adapter
+ *
+ * Retrieves various core SGE parameters in the form of hardware SGE
+ * register values. The caller is responsible for decoding these as
+ * needed. The SGE parameters are stored in @adapter->params.sge.
+ */
+int t4vf_get_sge_params(struct adapter *adapter)
+{
+ struct sge_params *sge_params = &adapter->params.sge;
+ u32 params[7], vals[7];
+ int v;
+
+ params[0] = (FW_PARAMS_MNEM(FW_PARAMS_MNEM_REG) |
+ FW_PARAMS_PARAM_XYZ(SGE_CONTROL));
+ params[1] = (FW_PARAMS_MNEM(FW_PARAMS_MNEM_REG) |
+ FW_PARAMS_PARAM_XYZ(SGE_HOST_PAGE_SIZE));
+ params[2] = (FW_PARAMS_MNEM(FW_PARAMS_MNEM_REG) |
+ FW_PARAMS_PARAM_XYZ(SGE_FL_BUFFER_SIZE0));
+ params[3] = (FW_PARAMS_MNEM(FW_PARAMS_MNEM_REG) |
+ FW_PARAMS_PARAM_XYZ(SGE_FL_BUFFER_SIZE1));
+ params[4] = (FW_PARAMS_MNEM(FW_PARAMS_MNEM_REG) |
+ FW_PARAMS_PARAM_XYZ(SGE_TIMER_VALUE_0_AND_1));
+ params[5] = (FW_PARAMS_MNEM(FW_PARAMS_MNEM_REG) |
+ FW_PARAMS_PARAM_XYZ(SGE_TIMER_VALUE_2_AND_3));
+ params[6] = (FW_PARAMS_MNEM(FW_PARAMS_MNEM_REG) |
+ FW_PARAMS_PARAM_XYZ(SGE_TIMER_VALUE_4_AND_5));
+ v = t4vf_query_params(adapter, 7, params, vals);
+ if (v)
+ return v;
+ sge_params->sge_control = vals[0];
+ sge_params->sge_host_page_size = vals[1];
+ sge_params->sge_fl_buffer_size[0] = vals[2];
+ sge_params->sge_fl_buffer_size[1] = vals[3];
+ sge_params->sge_timer_value_0_and_1 = vals[4];
+ sge_params->sge_timer_value_2_and_3 = vals[5];
+ sge_params->sge_timer_value_4_and_5 = vals[6];
+
+ params[0] = (FW_PARAMS_MNEM(FW_PARAMS_MNEM_REG) |
+ FW_PARAMS_PARAM_XYZ(SGE_INGRESS_RX_THRESHOLD));
+ v = t4vf_query_params(adapter, 1, params, vals);
+ if (v)
+ return v;
+ sge_params->sge_ingress_rx_threshold = vals[0];
+
+ return 0;
+}
+
+/**
+ * t4vf_get_vpd_params - retrieve device VPD paremeters
+ * @adapter: the adapter
+ *
+ * Retrives various device Vital Product Data parameters. The parameters
+ * are stored in @adapter->params.vpd.
+ */
+int t4vf_get_vpd_params(struct adapter *adapter)
+{
+ struct vpd_params *vpd_params = &adapter->params.vpd;
+ u32 params[7], vals[7];
+ int v;
+
+ params[0] = (FW_PARAMS_MNEM(FW_PARAMS_MNEM_DEV) |
+ FW_PARAMS_PARAM_X(FW_PARAMS_PARAM_DEV_CCLK));
+ v = t4vf_query_params(adapter, 1, params, vals);
+ if (v)
+ return v;
+ vpd_params->cclk = vals[0];
+
+ return 0;
+}
+
+/**
+ * t4vf_get_dev_params - retrieve device paremeters
+ * @adapter: the adapter
+ *
+ * Retrives various device parameters. The parameters are stored in
+ * @adapter->params.dev.
+ */
+int t4vf_get_dev_params(struct adapter *adapter)
+{
+ struct dev_params *dev_params = &adapter->params.dev;
+ u32 params[7], vals[7];
+ int v;
+
+ params[0] = (FW_PARAMS_MNEM(FW_PARAMS_MNEM_DEV) |
+ FW_PARAMS_PARAM_X(FW_PARAMS_PARAM_DEV_FWREV));
+ params[1] = (FW_PARAMS_MNEM(FW_PARAMS_MNEM_DEV) |
+ FW_PARAMS_PARAM_X(FW_PARAMS_PARAM_DEV_TPREV));
+ v = t4vf_query_params(adapter, 2, params, vals);
+ if (v)
+ return v;
+ dev_params->fwrev = vals[0];
+ dev_params->tprev = vals[1];
+
+ return 0;
+}
+
+/**
+ * t4vf_get_rss_glb_config - retrieve adapter RSS Global Configuration
+ * @adapter: the adapter
+ *
+ * Retrieves global RSS mode and parameters with which we have to live
+ * and stores them in the @adapter's RSS parameters.
+ */
+int t4vf_get_rss_glb_config(struct adapter *adapter)
+{
+ struct rss_params *rss = &adapter->params.rss;
+ struct fw_rss_glb_config_cmd cmd, rpl;
+ int v;
+
+ /*
+ * Execute an RSS Global Configuration read command to retrieve
+ * our RSS configuration.
+ */
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.op_to_write = cpu_to_be32(FW_CMD_OP(FW_RSS_GLB_CONFIG_CMD) |
+ FW_CMD_REQUEST |
+ FW_CMD_READ);
+ cmd.retval_len16 = cpu_to_be32(FW_LEN16(cmd));
+ v = t4vf_wr_mbox(adapter, &cmd, sizeof(cmd), &rpl);
+ if (v)
+ return v;
+
+ /*
+ * Transate the big-endian RSS Global Configuration into our
+ * cpu-endian format based on the RSS mode. We also do first level
+ * filtering at this point to weed out modes which don't support
+ * VF Drivers ...
+ */
+ rss->mode = FW_RSS_GLB_CONFIG_CMD_MODE_GET(
+ be32_to_cpu(rpl.u.manual.mode_pkd));
+ switch (rss->mode) {
+ case FW_RSS_GLB_CONFIG_CMD_MODE_BASICVIRTUAL: {
+ u32 word = be32_to_cpu(
+ rpl.u.basicvirtual.synmapen_to_hashtoeplitz);
+
+ rss->u.basicvirtual.synmapen =
+ ((word & FW_RSS_GLB_CONFIG_CMD_SYNMAPEN) != 0);
+ rss->u.basicvirtual.syn4tupenipv6 =
+ ((word & FW_RSS_GLB_CONFIG_CMD_SYN4TUPENIPV6) != 0);
+ rss->u.basicvirtual.syn2tupenipv6 =
+ ((word & FW_RSS_GLB_CONFIG_CMD_SYN2TUPENIPV6) != 0);
+ rss->u.basicvirtual.syn4tupenipv4 =
+ ((word & FW_RSS_GLB_CONFIG_CMD_SYN4TUPENIPV4) != 0);
+ rss->u.basicvirtual.syn2tupenipv4 =
+ ((word & FW_RSS_GLB_CONFIG_CMD_SYN2TUPENIPV4) != 0);
+
+ rss->u.basicvirtual.ofdmapen =
+ ((word & FW_RSS_GLB_CONFIG_CMD_OFDMAPEN) != 0);
+
+ rss->u.basicvirtual.tnlmapen =
+ ((word & FW_RSS_GLB_CONFIG_CMD_TNLMAPEN) != 0);
+ rss->u.basicvirtual.tnlalllookup =
+ ((word & FW_RSS_GLB_CONFIG_CMD_TNLALLLKP) != 0);
+
+ rss->u.basicvirtual.hashtoeplitz =
+ ((word & FW_RSS_GLB_CONFIG_CMD_HASHTOEPLITZ) != 0);
+
+ /* we need at least Tunnel Map Enable to be set */
+ if (!rss->u.basicvirtual.tnlmapen)
+ return -EINVAL;
+ break;
+ }
+
+ default:
+ /* all unknown/unsupported RSS modes result in an error */
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/**
+ * t4vf_get_vfres - retrieve VF resource limits
+ * @adapter: the adapter
+ *
+ * Retrieves configured resource limits and capabilities for a virtual
+ * function. The results are stored in @adapter->vfres.
+ */
+int t4vf_get_vfres(struct adapter *adapter)
+{
+ struct vf_resources *vfres = &adapter->params.vfres;
+ struct fw_pfvf_cmd cmd, rpl;
+ int v;
+ u32 word;
+
+ /*
+ * Execute PFVF Read command to get VF resource limits; bail out early
+ * with error on command failure.
+ */
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.op_to_vfn = cpu_to_be32(FW_CMD_OP(FW_PFVF_CMD) |
+ FW_CMD_REQUEST |
+ FW_CMD_READ);
+ cmd.retval_len16 = cpu_to_be32(FW_LEN16(cmd));
+ v = t4vf_wr_mbox(adapter, &cmd, sizeof(cmd), &rpl);
+ if (v)
+ return v;
+
+ /*
+ * Extract VF resource limits and return success.
+ */
+ word = be32_to_cpu(rpl.niqflint_niq);
+ vfres->niqflint = FW_PFVF_CMD_NIQFLINT_GET(word);
+ vfres->niq = FW_PFVF_CMD_NIQ_GET(word);
+
+ word = be32_to_cpu(rpl.type_to_neq);
+ vfres->neq = FW_PFVF_CMD_NEQ_GET(word);
+ vfres->pmask = FW_PFVF_CMD_PMASK_GET(word);
+
+ word = be32_to_cpu(rpl.tc_to_nexactf);
+ vfres->tc = FW_PFVF_CMD_TC_GET(word);
+ vfres->nvi = FW_PFVF_CMD_NVI_GET(word);
+ vfres->nexactf = FW_PFVF_CMD_NEXACTF_GET(word);
+
+ word = be32_to_cpu(rpl.r_caps_to_nethctrl);
+ vfres->r_caps = FW_PFVF_CMD_R_CAPS_GET(word);
+ vfres->wx_caps = FW_PFVF_CMD_WX_CAPS_GET(word);
+ vfres->nethctrl = FW_PFVF_CMD_NETHCTRL_GET(word);
+
+ return 0;
+}
+
+/**
+ * t4vf_read_rss_vi_config - read a VI's RSS configuration
+ * @adapter: the adapter
+ * @viid: Virtual Interface ID
+ * @config: pointer to host-native VI RSS Configuration buffer
+ *
+ * Reads the Virtual Interface's RSS configuration information and
+ * translates it into CPU-native format.
+ */
+int t4vf_read_rss_vi_config(struct adapter *adapter, unsigned int viid,
+ union rss_vi_config *config)
+{
+ struct fw_rss_vi_config_cmd cmd, rpl;
+ int v;
+
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.op_to_viid = cpu_to_be32(FW_CMD_OP(FW_RSS_VI_CONFIG_CMD) |
+ FW_CMD_REQUEST |
+ FW_CMD_READ |
+ FW_RSS_VI_CONFIG_CMD_VIID(viid));
+ cmd.retval_len16 = cpu_to_be32(FW_LEN16(cmd));
+ v = t4vf_wr_mbox(adapter, &cmd, sizeof(cmd), &rpl);
+ if (v)
+ return v;
+
+ switch (adapter->params.rss.mode) {
+ case FW_RSS_GLB_CONFIG_CMD_MODE_BASICVIRTUAL: {
+ u32 word = be32_to_cpu(rpl.u.basicvirtual.defaultq_to_udpen);
+
+ config->basicvirtual.ip6fourtupen =
+ ((word & FW_RSS_VI_CONFIG_CMD_IP6FOURTUPEN) != 0);
+ config->basicvirtual.ip6twotupen =
+ ((word & FW_RSS_VI_CONFIG_CMD_IP6TWOTUPEN) != 0);
+ config->basicvirtual.ip4fourtupen =
+ ((word & FW_RSS_VI_CONFIG_CMD_IP4FOURTUPEN) != 0);
+ config->basicvirtual.ip4twotupen =
+ ((word & FW_RSS_VI_CONFIG_CMD_IP4TWOTUPEN) != 0);
+ config->basicvirtual.udpen =
+ ((word & FW_RSS_VI_CONFIG_CMD_UDPEN) != 0);
+ config->basicvirtual.defaultq =
+ FW_RSS_VI_CONFIG_CMD_DEFAULTQ_GET(word);
+ break;
+ }
+
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/**
+ * t4vf_write_rss_vi_config - write a VI's RSS configuration
+ * @adapter: the adapter
+ * @viid: Virtual Interface ID
+ * @config: pointer to host-native VI RSS Configuration buffer
+ *
+ * Write the Virtual Interface's RSS configuration information
+ * (translating it into firmware-native format before writing).
+ */
+int t4vf_write_rss_vi_config(struct adapter *adapter, unsigned int viid,
+ union rss_vi_config *config)
+{
+ struct fw_rss_vi_config_cmd cmd, rpl;
+
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.op_to_viid = cpu_to_be32(FW_CMD_OP(FW_RSS_VI_CONFIG_CMD) |
+ FW_CMD_REQUEST |
+ FW_CMD_WRITE |
+ FW_RSS_VI_CONFIG_CMD_VIID(viid));
+ cmd.retval_len16 = cpu_to_be32(FW_LEN16(cmd));
+ switch (adapter->params.rss.mode) {
+ case FW_RSS_GLB_CONFIG_CMD_MODE_BASICVIRTUAL: {
+ u32 word = 0;
+
+ if (config->basicvirtual.ip6fourtupen)
+ word |= FW_RSS_VI_CONFIG_CMD_IP6FOURTUPEN;
+ if (config->basicvirtual.ip6twotupen)
+ word |= FW_RSS_VI_CONFIG_CMD_IP6TWOTUPEN;
+ if (config->basicvirtual.ip4fourtupen)
+ word |= FW_RSS_VI_CONFIG_CMD_IP4FOURTUPEN;
+ if (config->basicvirtual.ip4twotupen)
+ word |= FW_RSS_VI_CONFIG_CMD_IP4TWOTUPEN;
+ if (config->basicvirtual.udpen)
+ word |= FW_RSS_VI_CONFIG_CMD_UDPEN;
+ word |= FW_RSS_VI_CONFIG_CMD_DEFAULTQ(
+ config->basicvirtual.defaultq);
+ cmd.u.basicvirtual.defaultq_to_udpen = cpu_to_be32(word);
+ break;
+ }
+
+ default:
+ return -EINVAL;
+ }
+
+ return t4vf_wr_mbox(adapter, &cmd, sizeof(cmd), &rpl);
+}
+
+/**
+ * t4vf_config_rss_range - configure a portion of the RSS mapping table
+ * @adapter: the adapter
+ * @viid: Virtual Interface of RSS Table Slice
+ * @start: starting entry in the table to write
+ * @n: how many table entries to write
+ * @rspq: values for the "Response Queue" (Ingress Queue) lookup table
+ * @nrspq: number of values in @rspq
+ *
+ * Programs the selected part of the VI's RSS mapping table with the
+ * provided values. If @nrspq < @n the supplied values are used repeatedly
+ * until the full table range is populated.
+ *
+ * The caller must ensure the values in @rspq are in the range 0..1023.
+ */
+int t4vf_config_rss_range(struct adapter *adapter, unsigned int viid,
+ int start, int n, const u16 *rspq, int nrspq)
+{
+ const u16 *rsp = rspq;
+ const u16 *rsp_end = rspq+nrspq;
+ struct fw_rss_ind_tbl_cmd cmd;
+
+ /*
+ * Initialize firmware command template to write the RSS table.
+ */
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.op_to_viid = cpu_to_be32(FW_CMD_OP(FW_RSS_IND_TBL_CMD) |
+ FW_CMD_REQUEST |
+ FW_CMD_WRITE |
+ FW_RSS_IND_TBL_CMD_VIID(viid));
+ cmd.retval_len16 = cpu_to_be32(FW_LEN16(cmd));
+
+ /*
+ * Each firmware RSS command can accommodate up to 32 RSS Ingress
+ * Queue Identifiers. These Ingress Queue IDs are packed three to
+ * a 32-bit word as 10-bit values with the upper remaining 2 bits
+ * reserved.
+ */
+ while (n > 0) {
+ __be32 *qp = &cmd.iq0_to_iq2;
+ int nq = min(n, 32);
+ int ret;
+
+ /*
+ * Set up the firmware RSS command header to send the next
+ * "nq" Ingress Queue IDs to the firmware.
+ */
+ cmd.niqid = cpu_to_be16(nq);
+ cmd.startidx = cpu_to_be16(start);
+
+ /*
+ * "nq" more done for the start of the next loop.
+ */
+ start += nq;
+ n -= nq;
+
+ /*
+ * While there are still Ingress Queue IDs to stuff into the
+ * current firmware RSS command, retrieve them from the
+ * Ingress Queue ID array and insert them into the command.
+ */
+ while (nq > 0) {
+ /*
+ * Grab up to the next 3 Ingress Queue IDs (wrapping
+ * around the Ingress Queue ID array if necessary) and
+ * insert them into the firmware RSS command at the
+ * current 3-tuple position within the commad.
+ */
+ u16 qbuf[3];
+ u16 *qbp = qbuf;
+ int nqbuf = min(3, nq);
+
+ nq -= nqbuf;
+ qbuf[0] = qbuf[1] = qbuf[2] = 0;
+ while (nqbuf) {
+ nqbuf--;
+ *qbp++ = *rsp++;
+ if (rsp >= rsp_end)
+ rsp = rspq;
+ }
+ *qp++ = cpu_to_be32(FW_RSS_IND_TBL_CMD_IQ0(qbuf[0]) |
+ FW_RSS_IND_TBL_CMD_IQ1(qbuf[1]) |
+ FW_RSS_IND_TBL_CMD_IQ2(qbuf[2]));
+ }
+
+ /*
+ * Send this portion of the RRS table update to the firmware;
+ * bail out on any errors.
+ */
+ ret = t4vf_wr_mbox(adapter, &cmd, sizeof(cmd), NULL);
+ if (ret)
+ return ret;
+ }
+ return 0;
+}
+
+/**
+ * t4vf_alloc_vi - allocate a virtual interface on a port
+ * @adapter: the adapter
+ * @port_id: physical port associated with the VI
+ *
+ * Allocate a new Virtual Interface and bind it to the indicated
+ * physical port. Return the new Virtual Interface Identifier on
+ * success, or a [negative] error number on failure.
+ */
+int t4vf_alloc_vi(struct adapter *adapter, int port_id)
+{
+ struct fw_vi_cmd cmd, rpl;
+ int v;
+
+ /*
+ * Execute a VI command to allocate Virtual Interface and return its
+ * VIID.
+ */
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.op_to_vfn = cpu_to_be32(FW_CMD_OP(FW_VI_CMD) |
+ FW_CMD_REQUEST |
+ FW_CMD_WRITE |
+ FW_CMD_EXEC);
+ cmd.alloc_to_len16 = cpu_to_be32(FW_LEN16(cmd) |
+ FW_VI_CMD_ALLOC);
+ cmd.portid_pkd = FW_VI_CMD_PORTID(port_id);
+ v = t4vf_wr_mbox(adapter, &cmd, sizeof(cmd), &rpl);
+ if (v)
+ return v;
+
+ return FW_VI_CMD_VIID_GET(be16_to_cpu(rpl.type_viid));
+}
+
+/**
+ * t4vf_free_vi -- free a virtual interface
+ * @adapter: the adapter
+ * @viid: the virtual interface identifier
+ *
+ * Free a previously allocated Virtual Interface. Return an error on
+ * failure.
+ */
+int t4vf_free_vi(struct adapter *adapter, int viid)
+{
+ struct fw_vi_cmd cmd;
+
+ /*
+ * Execute a VI command to free the Virtual Interface.
+ */
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.op_to_vfn = cpu_to_be32(FW_CMD_OP(FW_VI_CMD) |
+ FW_CMD_REQUEST |
+ FW_CMD_EXEC);
+ cmd.alloc_to_len16 = cpu_to_be32(FW_LEN16(cmd) |
+ FW_VI_CMD_FREE);
+ cmd.type_viid = cpu_to_be16(FW_VI_CMD_VIID(viid));
+ return t4vf_wr_mbox(adapter, &cmd, sizeof(cmd), NULL);
+}
+
+/**
+ * t4vf_enable_vi - enable/disable a virtual interface
+ * @adapter: the adapter
+ * @viid: the Virtual Interface ID
+ * @rx_en: 1=enable Rx, 0=disable Rx
+ * @tx_en: 1=enable Tx, 0=disable Tx
+ *
+ * Enables/disables a virtual interface.
+ */
+int t4vf_enable_vi(struct adapter *adapter, unsigned int viid,
+ bool rx_en, bool tx_en)
+{
+ struct fw_vi_enable_cmd cmd;
+
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.op_to_viid = cpu_to_be32(FW_CMD_OP(FW_VI_ENABLE_CMD) |
+ FW_CMD_REQUEST |
+ FW_CMD_EXEC |
+ FW_VI_ENABLE_CMD_VIID(viid));
+ cmd.ien_to_len16 = cpu_to_be32(FW_VI_ENABLE_CMD_IEN(rx_en) |
+ FW_VI_ENABLE_CMD_EEN(tx_en) |
+ FW_LEN16(cmd));
+ return t4vf_wr_mbox(adapter, &cmd, sizeof(cmd), NULL);
+}
+
+/**
+ * t4vf_identify_port - identify a VI's port by blinking its LED
+ * @adapter: the adapter
+ * @viid: the Virtual Interface ID
+ * @nblinks: how many times to blink LED at 2.5 Hz
+ *
+ * Identifies a VI's port by blinking its LED.
+ */
+int t4vf_identify_port(struct adapter *adapter, unsigned int viid,
+ unsigned int nblinks)
+{
+ struct fw_vi_enable_cmd cmd;
+
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.op_to_viid = cpu_to_be32(FW_CMD_OP(FW_VI_ENABLE_CMD) |
+ FW_CMD_REQUEST |
+ FW_CMD_EXEC |
+ FW_VI_ENABLE_CMD_VIID(viid));
+ cmd.ien_to_len16 = cpu_to_be32(FW_VI_ENABLE_CMD_LED |
+ FW_LEN16(cmd));
+ cmd.blinkdur = cpu_to_be16(nblinks);
+ return t4vf_wr_mbox(adapter, &cmd, sizeof(cmd), NULL);
+}
+
+/**
+ * t4vf_set_rxmode - set Rx properties of a virtual interface
+ * @adapter: the adapter
+ * @viid: the VI id
+ * @mtu: the new MTU or -1 for no change
+ * @promisc: 1 to enable promiscuous mode, 0 to disable it, -1 no change
+ * @all_multi: 1 to enable all-multi mode, 0 to disable it, -1 no change
+ * @bcast: 1 to enable broadcast Rx, 0 to disable it, -1 no change
+ * @vlanex: 1 to enable hardware VLAN Tag extraction, 0 to disable it,
+ * -1 no change
+ *
+ * Sets Rx properties of a virtual interface.
+ */
+int t4vf_set_rxmode(struct adapter *adapter, unsigned int viid,
+ int mtu, int promisc, int all_multi, int bcast, int vlanex,
+ bool sleep_ok)
+{
+ struct fw_vi_rxmode_cmd cmd;
+
+ /* convert to FW values */
+ if (mtu < 0)
+ mtu = FW_VI_RXMODE_CMD_MTU_MASK;
+ if (promisc < 0)
+ promisc = FW_VI_RXMODE_CMD_PROMISCEN_MASK;
+ if (all_multi < 0)
+ all_multi = FW_VI_RXMODE_CMD_ALLMULTIEN_MASK;
+ if (bcast < 0)
+ bcast = FW_VI_RXMODE_CMD_BROADCASTEN_MASK;
+ if (vlanex < 0)
+ vlanex = FW_VI_RXMODE_CMD_VLANEXEN_MASK;
+
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.op_to_viid = cpu_to_be32(FW_CMD_OP(FW_VI_RXMODE_CMD) |
+ FW_CMD_REQUEST |
+ FW_CMD_WRITE |
+ FW_VI_RXMODE_CMD_VIID(viid));
+ cmd.retval_len16 = cpu_to_be32(FW_LEN16(cmd));
+ cmd.mtu_to_vlanexen =
+ cpu_to_be32(FW_VI_RXMODE_CMD_MTU(mtu) |
+ FW_VI_RXMODE_CMD_PROMISCEN(promisc) |
+ FW_VI_RXMODE_CMD_ALLMULTIEN(all_multi) |
+ FW_VI_RXMODE_CMD_BROADCASTEN(bcast) |
+ FW_VI_RXMODE_CMD_VLANEXEN(vlanex));
+ return t4vf_wr_mbox_core(adapter, &cmd, sizeof(cmd), NULL, sleep_ok);
+}
+
+/**
+ * t4vf_alloc_mac_filt - allocates exact-match filters for MAC addresses
+ * @adapter: the adapter
+ * @viid: the Virtual Interface Identifier
+ * @free: if true any existing filters for this VI id are first removed
+ * @naddr: the number of MAC addresses to allocate filters for (up to 7)
+ * @addr: the MAC address(es)
+ * @idx: where to store the index of each allocated filter
+ * @hash: pointer to hash address filter bitmap
+ * @sleep_ok: call is allowed to sleep
+ *
+ * Allocates an exact-match filter for each of the supplied addresses and
+ * sets it to the corresponding address. If @idx is not %NULL it should
+ * have at least @naddr entries, each of which will be set to the index of
+ * the filter allocated for the corresponding MAC address. If a filter
+ * could not be allocated for an address its index is set to 0xffff.
+ * If @hash is not %NULL addresses that fail to allocate an exact filter
+ * are hashed and update the hash filter bitmap pointed at by @hash.
+ *
+ * Returns a negative error number or the number of filters allocated.
+ */
+int t4vf_alloc_mac_filt(struct adapter *adapter, unsigned int viid, bool free,
+ unsigned int naddr, const u8 **addr, u16 *idx,
+ u64 *hash, bool sleep_ok)
+{
+ int i, ret;
+ struct fw_vi_mac_cmd cmd, rpl;
+ struct fw_vi_mac_exact *p;
+ size_t len16;
+
+ if (naddr > ARRAY_SIZE(cmd.u.exact))
+ return -EINVAL;
+ len16 = DIV_ROUND_UP(offsetof(struct fw_vi_mac_cmd,
+ u.exact[naddr]), 16);
+
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.op_to_viid = cpu_to_be32(FW_CMD_OP(FW_VI_MAC_CMD) |
+ FW_CMD_REQUEST |
+ FW_CMD_WRITE |
+ (free ? FW_CMD_EXEC : 0) |
+ FW_VI_MAC_CMD_VIID(viid));
+ cmd.freemacs_to_len16 = cpu_to_be32(FW_VI_MAC_CMD_FREEMACS(free) |
+ FW_CMD_LEN16(len16));
+
+ for (i = 0, p = cmd.u.exact; i < naddr; i++, p++) {
+ p->valid_to_idx =
+ cpu_to_be16(FW_VI_MAC_CMD_VALID |
+ FW_VI_MAC_CMD_IDX(FW_VI_MAC_ADD_MAC));
+ memcpy(p->macaddr, addr[i], sizeof(p->macaddr));
+ }
+
+ ret = t4vf_wr_mbox_core(adapter, &cmd, sizeof(cmd), &rpl, sleep_ok);
+ if (ret)
+ return ret;
+
+ for (i = 0, p = rpl.u.exact; i < naddr; i++, p++) {
+ u16 index = FW_VI_MAC_CMD_IDX_GET(be16_to_cpu(p->valid_to_idx));
+
+ if (idx)
+ idx[i] = (index >= FW_CLS_TCAM_NUM_ENTRIES
+ ? 0xffff
+ : index);
+ if (index < FW_CLS_TCAM_NUM_ENTRIES)
+ ret++;
+ else if (hash)
+ *hash |= (1 << hash_mac_addr(addr[i]));
+ }
+ return ret;
+}
+
+/**
+ * t4vf_change_mac - modifies the exact-match filter for a MAC address
+ * @adapter: the adapter
+ * @viid: the Virtual Interface ID
+ * @idx: index of existing filter for old value of MAC address, or -1
+ * @addr: the new MAC address value
+ * @persist: if idx < 0, the new MAC allocation should be persistent
+ *
+ * Modifies an exact-match filter and sets it to the new MAC address.
+ * Note that in general it is not possible to modify the value of a given
+ * filter so the generic way to modify an address filter is to free the
+ * one being used by the old address value and allocate a new filter for
+ * the new address value. @idx can be -1 if the address is a new
+ * addition.
+ *
+ * Returns a negative error number or the index of the filter with the new
+ * MAC value.
+ */
+int t4vf_change_mac(struct adapter *adapter, unsigned int viid,
+ int idx, const u8 *addr, bool persist)
+{
+ int ret;
+ struct fw_vi_mac_cmd cmd, rpl;
+ struct fw_vi_mac_exact *p = &cmd.u.exact[0];
+ size_t len16 = DIV_ROUND_UP(offsetof(struct fw_vi_mac_cmd,
+ u.exact[1]), 16);
+
+ /*
+ * If this is a new allocation, determine whether it should be
+ * persistent (across a "freemacs" operation) or not.
+ */
+ if (idx < 0)
+ idx = persist ? FW_VI_MAC_ADD_PERSIST_MAC : FW_VI_MAC_ADD_MAC;
+
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.op_to_viid = cpu_to_be32(FW_CMD_OP(FW_VI_MAC_CMD) |
+ FW_CMD_REQUEST |
+ FW_CMD_WRITE |
+ FW_VI_MAC_CMD_VIID(viid));
+ cmd.freemacs_to_len16 = cpu_to_be32(FW_CMD_LEN16(len16));
+ p->valid_to_idx = cpu_to_be16(FW_VI_MAC_CMD_VALID |
+ FW_VI_MAC_CMD_IDX(idx));
+ memcpy(p->macaddr, addr, sizeof(p->macaddr));
+
+ ret = t4vf_wr_mbox(adapter, &cmd, sizeof(cmd), &rpl);
+ if (ret == 0) {
+ p = &rpl.u.exact[0];
+ ret = FW_VI_MAC_CMD_IDX_GET(be16_to_cpu(p->valid_to_idx));
+ if (ret >= FW_CLS_TCAM_NUM_ENTRIES)
+ ret = -ENOMEM;
+ }
+ return ret;
+}
+
+/**
+ * t4vf_set_addr_hash - program the MAC inexact-match hash filter
+ * @adapter: the adapter
+ * @viid: the Virtual Interface Identifier
+ * @ucast: whether the hash filter should also match unicast addresses
+ * @vec: the value to be written to the hash filter
+ * @sleep_ok: call is allowed to sleep
+ *
+ * Sets the 64-bit inexact-match hash filter for a virtual interface.
+ */
+int t4vf_set_addr_hash(struct adapter *adapter, unsigned int viid,
+ bool ucast, u64 vec, bool sleep_ok)
+{
+ struct fw_vi_mac_cmd cmd;
+ size_t len16 = DIV_ROUND_UP(offsetof(struct fw_vi_mac_cmd,
+ u.exact[0]), 16);
+
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.op_to_viid = cpu_to_be32(FW_CMD_OP(FW_VI_MAC_CMD) |
+ FW_CMD_REQUEST |
+ FW_CMD_WRITE |
+ FW_VI_ENABLE_CMD_VIID(viid));
+ cmd.freemacs_to_len16 = cpu_to_be32(FW_VI_MAC_CMD_HASHVECEN |
+ FW_VI_MAC_CMD_HASHUNIEN(ucast) |
+ FW_CMD_LEN16(len16));
+ cmd.u.hash.hashvec = cpu_to_be64(vec);
+ return t4vf_wr_mbox_core(adapter, &cmd, sizeof(cmd), NULL, sleep_ok);
+}
+
+/**
+ * t4vf_get_port_stats - collect "port" statistics
+ * @adapter: the adapter
+ * @pidx: the port index
+ * @s: the stats structure to fill
+ *
+ * Collect statistics for the "port"'s Virtual Interface.
+ */
+int t4vf_get_port_stats(struct adapter *adapter, int pidx,
+ struct t4vf_port_stats *s)
+{
+ struct port_info *pi = adap2pinfo(adapter, pidx);
+ struct fw_vi_stats_vf fwstats;
+ unsigned int rem = VI_VF_NUM_STATS;
+ __be64 *fwsp = (__be64 *)&fwstats;
+
+ /*
+ * Grab the Virtual Interface statistics a chunk at a time via mailbox
+ * commands. We could use a Work Request and get all of them at once
+ * but that's an asynchronous interface which is awkward to use.
+ */
+ while (rem) {
+ unsigned int ix = VI_VF_NUM_STATS - rem;
+ unsigned int nstats = min(6U, rem);
+ struct fw_vi_stats_cmd cmd, rpl;
+ size_t len = (offsetof(struct fw_vi_stats_cmd, u) +
+ sizeof(struct fw_vi_stats_ctl));
+ size_t len16 = DIV_ROUND_UP(len, 16);
+ int ret;
+
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.op_to_viid = cpu_to_be32(FW_CMD_OP(FW_VI_STATS_CMD) |
+ FW_VI_STATS_CMD_VIID(pi->viid) |
+ FW_CMD_REQUEST |
+ FW_CMD_READ);
+ cmd.retval_len16 = cpu_to_be32(FW_CMD_LEN16(len16));
+ cmd.u.ctl.nstats_ix =
+ cpu_to_be16(FW_VI_STATS_CMD_IX(ix) |
+ FW_VI_STATS_CMD_NSTATS(nstats));
+ ret = t4vf_wr_mbox_ns(adapter, &cmd, len, &rpl);
+ if (ret)
+ return ret;
+
+ memcpy(fwsp, &rpl.u.ctl.stat0, sizeof(__be64) * nstats);
+
+ rem -= nstats;
+ fwsp += nstats;
+ }
+
+ /*
+ * Translate firmware statistics into host native statistics.
+ */
+ s->tx_bcast_bytes = be64_to_cpu(fwstats.tx_bcast_bytes);
+ s->tx_bcast_frames = be64_to_cpu(fwstats.tx_bcast_frames);
+ s->tx_mcast_bytes = be64_to_cpu(fwstats.tx_mcast_bytes);
+ s->tx_mcast_frames = be64_to_cpu(fwstats.tx_mcast_frames);
+ s->tx_ucast_bytes = be64_to_cpu(fwstats.tx_ucast_bytes);
+ s->tx_ucast_frames = be64_to_cpu(fwstats.tx_ucast_frames);
+ s->tx_drop_frames = be64_to_cpu(fwstats.tx_drop_frames);
+ s->tx_offload_bytes = be64_to_cpu(fwstats.tx_offload_bytes);
+ s->tx_offload_frames = be64_to_cpu(fwstats.tx_offload_frames);
+
+ s->rx_bcast_bytes = be64_to_cpu(fwstats.rx_bcast_bytes);
+ s->rx_bcast_frames = be64_to_cpu(fwstats.rx_bcast_frames);
+ s->rx_mcast_bytes = be64_to_cpu(fwstats.rx_mcast_bytes);
+ s->rx_mcast_frames = be64_to_cpu(fwstats.rx_mcast_frames);
+ s->rx_ucast_bytes = be64_to_cpu(fwstats.rx_ucast_bytes);
+ s->rx_ucast_frames = be64_to_cpu(fwstats.rx_ucast_frames);
+
+ s->rx_err_frames = be64_to_cpu(fwstats.rx_err_frames);
+
+ return 0;
+}
+
+/**
+ * t4vf_iq_free - free an ingress queue and its free lists
+ * @adapter: the adapter
+ * @iqtype: the ingress queue type (FW_IQ_TYPE_FL_INT_CAP, etc.)
+ * @iqid: ingress queue ID
+ * @fl0id: FL0 queue ID or 0xffff if no attached FL0
+ * @fl1id: FL1 queue ID or 0xffff if no attached FL1
+ *
+ * Frees an ingress queue and its associated free lists, if any.
+ */
+int t4vf_iq_free(struct adapter *adapter, unsigned int iqtype,
+ unsigned int iqid, unsigned int fl0id, unsigned int fl1id)
+{
+ struct fw_iq_cmd cmd;
+
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.op_to_vfn = cpu_to_be32(FW_CMD_OP(FW_IQ_CMD) |
+ FW_CMD_REQUEST |
+ FW_CMD_EXEC);
+ cmd.alloc_to_len16 = cpu_to_be32(FW_IQ_CMD_FREE |
+ FW_LEN16(cmd));
+ cmd.type_to_iqandstindex =
+ cpu_to_be32(FW_IQ_CMD_TYPE(iqtype));
+
+ cmd.iqid = cpu_to_be16(iqid);
+ cmd.fl0id = cpu_to_be16(fl0id);
+ cmd.fl1id = cpu_to_be16(fl1id);
+ return t4vf_wr_mbox(adapter, &cmd, sizeof(cmd), NULL);
+}
+
+/**
+ * t4vf_eth_eq_free - free an Ethernet egress queue
+ * @adapter: the adapter
+ * @eqid: egress queue ID
+ *
+ * Frees an Ethernet egress queue.
+ */
+int t4vf_eth_eq_free(struct adapter *adapter, unsigned int eqid)
+{
+ struct fw_eq_eth_cmd cmd;
+
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.op_to_vfn = cpu_to_be32(FW_CMD_OP(FW_EQ_ETH_CMD) |
+ FW_CMD_REQUEST |
+ FW_CMD_EXEC);
+ cmd.alloc_to_len16 = cpu_to_be32(FW_EQ_ETH_CMD_FREE |
+ FW_LEN16(cmd));
+ cmd.eqid_pkd = cpu_to_be32(FW_EQ_ETH_CMD_EQID(eqid));
+ return t4vf_wr_mbox(adapter, &cmd, sizeof(cmd), NULL);
+}
+
+/**
+ * t4vf_handle_fw_rpl - process a firmware reply message
+ * @adapter: the adapter
+ * @rpl: start of the firmware message
+ *
+ * Processes a firmware message, such as link state change messages.
+ */
+int t4vf_handle_fw_rpl(struct adapter *adapter, const __be64 *rpl)
+{
+ struct fw_cmd_hdr *cmd_hdr = (struct fw_cmd_hdr *)rpl;
+ u8 opcode = FW_CMD_OP_GET(be32_to_cpu(cmd_hdr->hi));
+
+ switch (opcode) {
+ case FW_PORT_CMD: {
+ /*
+ * Link/module state change message.
+ */
+ const struct fw_port_cmd *port_cmd = (void *)rpl;
+ u32 word;
+ int action, port_id, link_ok, speed, fc, pidx;
+
+ /*
+ * Extract various fields from port status change message.
+ */
+ action = FW_PORT_CMD_ACTION_GET(
+ be32_to_cpu(port_cmd->action_to_len16));
+ if (action != FW_PORT_ACTION_GET_PORT_INFO) {
+ dev_err(adapter->pdev_dev,
+ "Unknown firmware PORT reply action %x\n",
+ action);
+ break;
+ }
+
+ port_id = FW_PORT_CMD_PORTID_GET(
+ be32_to_cpu(port_cmd->op_to_portid));
+
+ word = be32_to_cpu(port_cmd->u.info.lstatus_to_modtype);
+ link_ok = (word & FW_PORT_CMD_LSTATUS) != 0;
+ speed = 0;
+ fc = 0;
+ if (word & FW_PORT_CMD_RXPAUSE)
+ fc |= PAUSE_RX;
+ if (word & FW_PORT_CMD_TXPAUSE)
+ fc |= PAUSE_TX;
+ if (word & FW_PORT_CMD_LSPEED(FW_PORT_CAP_SPEED_100M))
+ speed = SPEED_100;
+ else if (word & FW_PORT_CMD_LSPEED(FW_PORT_CAP_SPEED_1G))
+ speed = SPEED_1000;
+ else if (word & FW_PORT_CMD_LSPEED(FW_PORT_CAP_SPEED_10G))
+ speed = SPEED_10000;
+
+ /*
+ * Scan all of our "ports" (Virtual Interfaces) looking for
+ * those bound to the physical port which has changed. If
+ * our recorded state doesn't match the current state,
+ * signal that change to the OS code.
+ */
+ for_each_port(adapter, pidx) {
+ struct port_info *pi = adap2pinfo(adapter, pidx);
+ struct link_config *lc;
+
+ if (pi->port_id != port_id)
+ continue;
+
+ lc = &pi->link_cfg;
+ if (link_ok != lc->link_ok || speed != lc->speed ||
+ fc != lc->fc) {
+ /* something changed */
+ lc->link_ok = link_ok;
+ lc->speed = speed;
+ lc->fc = fc;
+ t4vf_os_link_changed(adapter, pidx, link_ok);
+ }
+ }
+ break;
+ }
+
+ default:
+ dev_err(adapter->pdev_dev, "Unknown firmware reply %X\n",
+ opcode);
+ }
+ return 0;
+}
diff --git a/drivers/net/davinci_emac.c b/drivers/net/davinci_emac.c
index 08e82b1a0b3..d0824e32206 100644
--- a/drivers/net/davinci_emac.c
+++ b/drivers/net/davinci_emac.c
@@ -298,6 +298,11 @@ static const char emac_version_string[] = "TI DaVinci EMAC Linux v6.1";
#define EMAC_CTRL_EWCTL (0x4)
#define EMAC_CTRL_EWINTTCNT (0x8)
+/* EMAC DM644x control module masks */
+#define EMAC_DM644X_EWINTCNT_MASK 0x1FFFF
+#define EMAC_DM644X_INTMIN_INTVL 0x1
+#define EMAC_DM644X_INTMAX_INTVL (EMAC_DM644X_EWINTCNT_MASK)
+
/* EMAC MDIO related */
/* Mask & Control defines */
#define MDIO_CONTROL_CLKDIV (0xFF)
@@ -318,8 +323,20 @@ static const char emac_version_string[] = "TI DaVinci EMAC Linux v6.1";
#define MDIO_CONTROL (0x04)
/* EMAC DM646X control module registers */
-#define EMAC_DM646X_CMRXINTEN (0x14)
-#define EMAC_DM646X_CMTXINTEN (0x18)
+#define EMAC_DM646X_CMINTCTRL 0x0C
+#define EMAC_DM646X_CMRXINTEN 0x14
+#define EMAC_DM646X_CMTXINTEN 0x18
+#define EMAC_DM646X_CMRXINTMAX 0x70
+#define EMAC_DM646X_CMTXINTMAX 0x74
+
+/* EMAC DM646X control module masks */
+#define EMAC_DM646X_INTPACEEN (0x3 << 16)
+#define EMAC_DM646X_INTPRESCALE_MASK (0x7FF << 0)
+#define EMAC_DM646X_CMINTMAX_CNT 63
+#define EMAC_DM646X_CMINTMIN_CNT 2
+#define EMAC_DM646X_CMINTMAX_INTVL (1000 / EMAC_DM646X_CMINTMIN_CNT)
+#define EMAC_DM646X_CMINTMIN_INTVL ((1000 / EMAC_DM646X_CMINTMAX_CNT) + 1)
+
/* EMAC EOI codes for C0 */
#define EMAC_DM646X_MAC_EOI_C0_RXEN (0x01)
@@ -468,9 +485,10 @@ struct emac_priv {
u32 duplex; /* Link duplex: 0=Half, 1=Full */
u32 rx_buf_size;
u32 isr_count;
+ u32 coal_intvl;
+ u32 bus_freq_mhz;
u8 rmii_en;
u8 version;
- struct net_device_stats net_dev_stats;
u32 mac_hash1;
u32 mac_hash2;
u32 multicast_hash_cnt[EMAC_NUM_MULTICAST_BITS];
@@ -546,9 +564,11 @@ static void emac_dump_regs(struct emac_priv *priv)
/* Print important registers in EMAC */
dev_info(emac_dev, "EMAC Basic registers\n");
- dev_info(emac_dev, "EMAC: EWCTL: %08X, EWINTTCNT: %08X\n",
- emac_ctrl_read(EMAC_CTRL_EWCTL),
- emac_ctrl_read(EMAC_CTRL_EWINTTCNT));
+ if (priv->version == EMAC_VERSION_1) {
+ dev_info(emac_dev, "EMAC: EWCTL: %08X, EWINTTCNT: %08X\n",
+ emac_ctrl_read(EMAC_CTRL_EWCTL),
+ emac_ctrl_read(EMAC_CTRL_EWINTTCNT));
+ }
dev_info(emac_dev, "EMAC: TXID: %08X %s, RXID: %08X %s\n",
emac_read(EMAC_TXIDVER),
((emac_read(EMAC_TXCONTROL)) ? "enabled" : "disabled"),
@@ -692,6 +712,103 @@ static int emac_set_settings(struct net_device *ndev, struct ethtool_cmd *ecmd)
}
/**
+ * emac_get_coalesce : Get interrupt coalesce settings for this device
+ * @ndev : The DaVinci EMAC network adapter
+ * @coal : ethtool coalesce settings structure
+ *
+ * Fetch the current interrupt coalesce settings
+ *
+ */
+static int emac_get_coalesce(struct net_device *ndev,
+ struct ethtool_coalesce *coal)
+{
+ struct emac_priv *priv = netdev_priv(ndev);
+
+ coal->rx_coalesce_usecs = priv->coal_intvl;
+ return 0;
+
+}
+
+/**
+ * emac_set_coalesce : Set interrupt coalesce settings for this device
+ * @ndev : The DaVinci EMAC network adapter
+ * @coal : ethtool coalesce settings structure
+ *
+ * Set interrupt coalesce parameters
+ *
+ */
+static int emac_set_coalesce(struct net_device *ndev,
+ struct ethtool_coalesce *coal)
+{
+ struct emac_priv *priv = netdev_priv(ndev);
+ u32 int_ctrl, num_interrupts = 0;
+ u32 prescale = 0, addnl_dvdr = 1, coal_intvl = 0;
+
+ if (!coal->rx_coalesce_usecs)
+ return -EINVAL;
+
+ coal_intvl = coal->rx_coalesce_usecs;
+
+ switch (priv->version) {
+ case EMAC_VERSION_2:
+ int_ctrl = emac_ctrl_read(EMAC_DM646X_CMINTCTRL);
+ prescale = priv->bus_freq_mhz * 4;
+
+ if (coal_intvl < EMAC_DM646X_CMINTMIN_INTVL)
+ coal_intvl = EMAC_DM646X_CMINTMIN_INTVL;
+
+ if (coal_intvl > EMAC_DM646X_CMINTMAX_INTVL) {
+ /*
+ * Interrupt pacer works with 4us Pulse, we can
+ * throttle further by dilating the 4us pulse.
+ */
+ addnl_dvdr = EMAC_DM646X_INTPRESCALE_MASK / prescale;
+
+ if (addnl_dvdr > 1) {
+ prescale *= addnl_dvdr;
+ if (coal_intvl > (EMAC_DM646X_CMINTMAX_INTVL
+ * addnl_dvdr))
+ coal_intvl = (EMAC_DM646X_CMINTMAX_INTVL
+ * addnl_dvdr);
+ } else {
+ addnl_dvdr = 1;
+ coal_intvl = EMAC_DM646X_CMINTMAX_INTVL;
+ }
+ }
+
+ num_interrupts = (1000 * addnl_dvdr) / coal_intvl;
+
+ int_ctrl |= EMAC_DM646X_INTPACEEN;
+ int_ctrl &= (~EMAC_DM646X_INTPRESCALE_MASK);
+ int_ctrl |= (prescale & EMAC_DM646X_INTPRESCALE_MASK);
+ emac_ctrl_write(EMAC_DM646X_CMINTCTRL, int_ctrl);
+
+ emac_ctrl_write(EMAC_DM646X_CMRXINTMAX, num_interrupts);
+ emac_ctrl_write(EMAC_DM646X_CMTXINTMAX, num_interrupts);
+
+ break;
+ default:
+ int_ctrl = emac_ctrl_read(EMAC_CTRL_EWINTTCNT);
+ int_ctrl &= (~EMAC_DM644X_EWINTCNT_MASK);
+ prescale = coal_intvl * priv->bus_freq_mhz;
+ if (prescale > EMAC_DM644X_EWINTCNT_MASK) {
+ prescale = EMAC_DM644X_EWINTCNT_MASK;
+ coal_intvl = prescale / priv->bus_freq_mhz;
+ }
+ emac_ctrl_write(EMAC_CTRL_EWINTTCNT, (int_ctrl | prescale));
+
+ break;
+ }
+
+ printk(KERN_INFO"Set coalesce to %d usecs.\n", coal_intvl);
+ priv->coal_intvl = coal_intvl;
+
+ return 0;
+
+}
+
+
+/**
* ethtool_ops: DaVinci EMAC Ethtool structure
*
* Ethtool support for EMAC adapter
@@ -702,6 +819,8 @@ static const struct ethtool_ops ethtool_ops = {
.get_settings = emac_get_settings,
.set_settings = emac_set_settings,
.get_link = ethtool_op_get_link,
+ .get_coalesce = emac_get_coalesce,
+ .set_coalesce = emac_set_coalesce,
};
/**
@@ -1180,16 +1299,17 @@ static int emac_net_tx_complete(struct emac_priv *priv,
void **net_data_tokens,
int num_tokens, u32 ch)
{
+ struct net_device *ndev = priv->ndev;
u32 cnt;
- if (unlikely(num_tokens && netif_queue_stopped(priv->ndev)))
- netif_start_queue(priv->ndev);
+ if (unlikely(num_tokens && netif_queue_stopped(ndev)))
+ netif_start_queue(ndev);
for (cnt = 0; cnt < num_tokens; cnt++) {
struct sk_buff *skb = (struct sk_buff *)net_data_tokens[cnt];
if (skb == NULL)
continue;
- priv->net_dev_stats.tx_packets++;
- priv->net_dev_stats.tx_bytes += skb->len;
+ ndev->stats.tx_packets++;
+ ndev->stats.tx_bytes += skb->len;
dev_kfree_skb_any(skb);
}
return 0;
@@ -1476,7 +1596,7 @@ static int emac_dev_xmit(struct sk_buff *skb, struct net_device *ndev)
" err. Out of TX BD's");
netif_stop_queue(priv->ndev);
}
- priv->net_dev_stats.tx_dropped++;
+ ndev->stats.tx_dropped++;
return NETDEV_TX_BUSY;
}
@@ -1501,7 +1621,7 @@ static void emac_dev_tx_timeout(struct net_device *ndev)
if (netif_msg_tx_err(priv))
dev_err(emac_dev, "DaVinci EMAC: xmit timeout, restarting TX");
- priv->net_dev_stats.tx_errors++;
+ ndev->stats.tx_errors++;
emac_int_disable(priv);
emac_stop_txch(priv, EMAC_DEF_TX_CH);
emac_cleanup_txch(priv, EMAC_DEF_TX_CH);
@@ -1926,14 +2046,14 @@ static void emac_addbd_to_rx_queue(struct emac_priv *priv, u32 ch,
static int emac_net_rx_cb(struct emac_priv *priv,
struct emac_netpktobj *net_pkt_list)
{
- struct sk_buff *p_skb;
- p_skb = (struct sk_buff *)net_pkt_list->pkt_token;
+ struct net_device *ndev = priv->ndev;
+ struct sk_buff *p_skb = net_pkt_list->pkt_token;
/* set length of packet */
skb_put(p_skb, net_pkt_list->pkt_length);
p_skb->protocol = eth_type_trans(p_skb, priv->ndev);
netif_receive_skb(p_skb);
- priv->net_dev_stats.rx_bytes += net_pkt_list->pkt_length;
- priv->net_dev_stats.rx_packets++;
+ ndev->stats.rx_bytes += net_pkt_list->pkt_length;
+ ndev->stats.rx_packets++;
return 0;
}
@@ -2148,7 +2268,7 @@ static int emac_poll(struct napi_struct *napi, int budget)
struct net_device *ndev = priv->ndev;
struct device *emac_dev = &ndev->dev;
u32 status = 0;
- u32 num_pkts = 0;
+ u32 num_tx_pkts = 0, num_rx_pkts = 0;
/* Check interrupt vectors and call packet processing */
status = emac_read(EMAC_MACINVECTOR);
@@ -2159,27 +2279,19 @@ static int emac_poll(struct napi_struct *napi, int budget)
mask = EMAC_DM646X_MAC_IN_VECTOR_TX_INT_VEC;
if (status & mask) {
- num_pkts = emac_tx_bdproc(priv, EMAC_DEF_TX_CH,
+ num_tx_pkts = emac_tx_bdproc(priv, EMAC_DEF_TX_CH,
EMAC_DEF_TX_MAX_SERVICE);
} /* TX processing */
- if (num_pkts)
- return budget;
-
mask = EMAC_DM644X_MAC_IN_VECTOR_RX_INT_VEC;
if (priv->version == EMAC_VERSION_2)
mask = EMAC_DM646X_MAC_IN_VECTOR_RX_INT_VEC;
if (status & mask) {
- num_pkts = emac_rx_bdproc(priv, EMAC_DEF_RX_CH, budget);
+ num_rx_pkts = emac_rx_bdproc(priv, EMAC_DEF_RX_CH, budget);
} /* RX processing */
- if (num_pkts < budget) {
- napi_complete(napi);
- emac_int_enable(priv);
- }
-
mask = EMAC_DM644X_MAC_IN_VECTOR_HOST_INT;
if (priv->version == EMAC_VERSION_2)
mask = EMAC_DM646X_MAC_IN_VECTOR_HOST_INT;
@@ -2210,9 +2322,12 @@ static int emac_poll(struct napi_struct *napi, int budget)
dev_err(emac_dev, "RX Host error %s on ch=%d\n",
&emac_rxhost_errcodes[cause][0], ch);
}
- } /* Host error processing */
+ } else if (num_rx_pkts < budget) {
+ napi_complete(napi);
+ emac_int_enable(priv);
+ }
- return num_pkts;
+ return num_rx_pkts;
}
#ifdef CONFIG_NET_POLL_CONTROLLER
@@ -2437,6 +2552,14 @@ static int emac_dev_open(struct net_device *ndev)
/* Start/Enable EMAC hardware */
emac_hw_enable(priv);
+ /* Enable Interrupt pacing if configured */
+ if (priv->coal_intvl != 0) {
+ struct ethtool_coalesce coal;
+
+ coal.rx_coalesce_usecs = (priv->coal_intvl << 4);
+ emac_set_coalesce(ndev, &coal);
+ }
+
/* find the first phy */
priv->phydev = NULL;
if (priv->phy_mask) {
@@ -2570,39 +2693,39 @@ static struct net_device_stats *emac_dev_getnetstats(struct net_device *ndev)
else
stats_clear_mask = 0;
- priv->net_dev_stats.multicast += emac_read(EMAC_RXMCASTFRAMES);
+ ndev->stats.multicast += emac_read(EMAC_RXMCASTFRAMES);
emac_write(EMAC_RXMCASTFRAMES, stats_clear_mask);
- priv->net_dev_stats.collisions += (emac_read(EMAC_TXCOLLISION) +
+ ndev->stats.collisions += (emac_read(EMAC_TXCOLLISION) +
emac_read(EMAC_TXSINGLECOLL) +
emac_read(EMAC_TXMULTICOLL));
emac_write(EMAC_TXCOLLISION, stats_clear_mask);
emac_write(EMAC_TXSINGLECOLL, stats_clear_mask);
emac_write(EMAC_TXMULTICOLL, stats_clear_mask);
- priv->net_dev_stats.rx_length_errors += (emac_read(EMAC_RXOVERSIZED) +
+ ndev->stats.rx_length_errors += (emac_read(EMAC_RXOVERSIZED) +
emac_read(EMAC_RXJABBER) +
emac_read(EMAC_RXUNDERSIZED));
emac_write(EMAC_RXOVERSIZED, stats_clear_mask);
emac_write(EMAC_RXJABBER, stats_clear_mask);
emac_write(EMAC_RXUNDERSIZED, stats_clear_mask);
- priv->net_dev_stats.rx_over_errors += (emac_read(EMAC_RXSOFOVERRUNS) +
+ ndev->stats.rx_over_errors += (emac_read(EMAC_RXSOFOVERRUNS) +
emac_read(EMAC_RXMOFOVERRUNS));
emac_write(EMAC_RXSOFOVERRUNS, stats_clear_mask);
emac_write(EMAC_RXMOFOVERRUNS, stats_clear_mask);
- priv->net_dev_stats.rx_fifo_errors += emac_read(EMAC_RXDMAOVERRUNS);
+ ndev->stats.rx_fifo_errors += emac_read(EMAC_RXDMAOVERRUNS);
emac_write(EMAC_RXDMAOVERRUNS, stats_clear_mask);
- priv->net_dev_stats.tx_carrier_errors +=
+ ndev->stats.tx_carrier_errors +=
emac_read(EMAC_TXCARRIERSENSE);
emac_write(EMAC_TXCARRIERSENSE, stats_clear_mask);
- priv->net_dev_stats.tx_fifo_errors = emac_read(EMAC_TXUNDERRUN);
+ ndev->stats.tx_fifo_errors = emac_read(EMAC_TXUNDERRUN);
emac_write(EMAC_TXUNDERRUN, stats_clear_mask);
- return &priv->net_dev_stats;
+ return &ndev->stats;
}
static const struct net_device_ops emac_netdev_ops = {
@@ -2677,6 +2800,9 @@ static int __devinit davinci_emac_probe(struct platform_device *pdev)
priv->int_enable = pdata->interrupt_enable;
priv->int_disable = pdata->interrupt_disable;
+ priv->coal_intvl = 0;
+ priv->bus_freq_mhz = (u32)(emac_bus_frequency / 1000000);
+
emac_dev = &ndev->dev;
/* Get EMAC platform data */
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
diff --git a/drivers/net/depca.c b/drivers/net/depca.c
index bf66e9b3b19..44c0694c1f4 100644
--- a/drivers/net/depca.c
+++ b/drivers/net/depca.c
@@ -2061,18 +2061,35 @@ static int depca_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
static int __init depca_module_init (void)
{
- int err = 0;
+ int err = 0;
#ifdef CONFIG_MCA
- err = mca_register_driver (&depca_mca_driver);
+ err = mca_register_driver(&depca_mca_driver);
+ if (err)
+ goto err;
#endif
#ifdef CONFIG_EISA
- err |= eisa_driver_register (&depca_eisa_driver);
+ err = eisa_driver_register(&depca_eisa_driver);
+ if (err)
+ goto err_mca;
#endif
- err |= platform_driver_register (&depca_isa_driver);
- depca_platform_probe ();
+ err = platform_driver_register(&depca_isa_driver);
+ if (err)
+ goto err_eisa;
- return err;
+ depca_platform_probe();
+ return 0;
+
+err_eisa:
+#ifdef CONFIG_EISA
+ eisa_driver_unregister(&depca_eisa_driver);
+err_mca:
+#endif
+#ifdef CONFIG_MCA
+ mca_unregister_driver(&depca_mca_driver);
+err:
+#endif
+ return err;
}
static void __exit depca_module_exit (void)
diff --git a/drivers/net/dm9000.c b/drivers/net/dm9000.c
index abcc838e18a..4fd6b2b4554 100644
--- a/drivers/net/dm9000.c
+++ b/drivers/net/dm9000.c
@@ -961,7 +961,7 @@ struct dm9000_rxhdr {
u8 RxPktReady;
u8 RxStatus;
__le16 RxLen;
-} __attribute__((__packed__));
+} __packed;
/*
* Received a packet and pass to upper layer
diff --git a/drivers/net/dnet.c b/drivers/net/dnet.c
index 8b0f50bbf3e..7c075756611 100644
--- a/drivers/net/dnet.c
+++ b/drivers/net/dnet.c
@@ -797,7 +797,7 @@ static int dnet_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
if (!phydev)
return -ENODEV;
- return phy_mii_ioctl(phydev, if_mii(rq), cmd);
+ return phy_mii_ioctl(phydev, rq, cmd);
}
static void dnet_get_drvinfo(struct net_device *dev,
@@ -854,7 +854,7 @@ static int __devinit dnet_probe(struct platform_device *pdev)
dev = alloc_etherdev(sizeof(*bp));
if (!dev) {
dev_err(&pdev->dev, "etherdev alloc failed, aborting.\n");
- goto err_out;
+ goto err_out_release_mem;
}
/* TODO: Actually, we have some interesting features... */
@@ -911,7 +911,8 @@ static int __devinit dnet_probe(struct platform_device *pdev)
if (err)
dev_warn(&pdev->dev, "Cannot register PHY board fixup.\n");
- if (dnet_mii_init(bp) != 0)
+ err = dnet_mii_init(bp);
+ if (err)
goto err_out_unregister_netdev;
dev_info(&pdev->dev, "Dave DNET at 0x%p (0x%08x) irq %d %pM\n",
@@ -936,6 +937,8 @@ err_out_iounmap:
iounmap(bp->regs);
err_out_free_dev:
free_netdev(dev);
+err_out_release_mem:
+ release_mem_region(mem_base, mem_size);
err_out:
return err;
}
diff --git a/drivers/net/e1000/e1000.h b/drivers/net/e1000/e1000.h
index 40b62b406b0..99288b95aea 100644
--- a/drivers/net/e1000/e1000.h
+++ b/drivers/net/e1000/e1000.h
@@ -86,12 +86,12 @@ struct e1000_adapter;
/* TX/RX descriptor defines */
#define E1000_DEFAULT_TXD 256
#define E1000_MAX_TXD 256
-#define E1000_MIN_TXD 80
+#define E1000_MIN_TXD 48
#define E1000_MAX_82544_TXD 4096
#define E1000_DEFAULT_RXD 256
#define E1000_MAX_RXD 256
-#define E1000_MIN_RXD 80
+#define E1000_MIN_RXD 48
#define E1000_MAX_82544_RXD 4096
#define E1000_MIN_ITR_USECS 10 /* 100000 irq/sec */
@@ -324,18 +324,20 @@ enum e1000_state_t {
extern struct net_device *e1000_get_hw_dev(struct e1000_hw *hw);
#define e_dbg(format, arg...) \
netdev_dbg(e1000_get_hw_dev(hw), format, ## arg)
-#define e_err(format, arg...) \
- netdev_err(adapter->netdev, format, ## arg)
-#define e_info(format, arg...) \
- netdev_info(adapter->netdev, format, ## arg)
-#define e_warn(format, arg...) \
- netdev_warn(adapter->netdev, format, ## arg)
-#define e_notice(format, arg...) \
- netdev_notice(adapter->netdev, format, ## arg)
+#define e_err(msglvl, format, arg...) \
+ netif_err(adapter, msglvl, adapter->netdev, format, ## arg)
+#define e_info(msglvl, format, arg...) \
+ netif_info(adapter, msglvl, adapter->netdev, format, ## arg)
+#define e_warn(msglvl, format, arg...) \
+ netif_warn(adapter, msglvl, adapter->netdev, format, ## arg)
+#define e_notice(msglvl, format, arg...) \
+ netif_notice(adapter, msglvl, adapter->netdev, format, ## arg)
#define e_dev_info(format, arg...) \
dev_info(&adapter->pdev->dev, format, ## arg)
#define e_dev_warn(format, arg...) \
dev_warn(&adapter->pdev->dev, format, ## arg)
+#define e_dev_err(format, arg...) \
+ dev_err(&adapter->pdev->dev, format, ## arg)
extern char e1000_driver_name[];
extern const char e1000_driver_version[];
diff --git a/drivers/net/e1000/e1000_ethtool.c b/drivers/net/e1000/e1000_ethtool.c
index d5ff029aa7b..f4d0922ec65 100644
--- a/drivers/net/e1000/e1000_ethtool.c
+++ b/drivers/net/e1000/e1000_ethtool.c
@@ -346,7 +346,7 @@ static int e1000_set_tso(struct net_device *netdev, u32 data)
netdev->features &= ~NETIF_F_TSO6;
- e_info("TSO is %s\n", data ? "Enabled" : "Disabled");
+ e_info(probe, "TSO is %s\n", data ? "Enabled" : "Disabled");
adapter->tso_force = true;
return 0;
}
@@ -714,9 +714,9 @@ static bool reg_pattern_test(struct e1000_adapter *adapter, u64 *data, int reg,
writel(write & test[i], address);
read = readl(address);
if (read != (write & test[i] & mask)) {
- e_info("pattern test reg %04X failed: "
- "got 0x%08X expected 0x%08X\n",
- reg, read, (write & test[i] & mask));
+ e_err(drv, "pattern test reg %04X failed: "
+ "got 0x%08X expected 0x%08X\n",
+ reg, read, (write & test[i] & mask));
*data = reg;
return true;
}
@@ -734,7 +734,7 @@ static bool reg_set_and_check(struct e1000_adapter *adapter, u64 *data, int reg,
writel(write & mask, address);
read = readl(address);
if ((read & mask) != (write & mask)) {
- e_err("set/check reg %04X test failed: "
+ e_err(drv, "set/check reg %04X test failed: "
"got 0x%08X expected 0x%08X\n",
reg, (read & mask), (write & mask));
*data = reg;
@@ -779,7 +779,7 @@ static int e1000_reg_test(struct e1000_adapter *adapter, u64 *data)
ew32(STATUS, toggle);
after = er32(STATUS) & toggle;
if (value != after) {
- e_err("failed STATUS register test got: "
+ e_err(drv, "failed STATUS register test got: "
"0x%08X expected: 0x%08X\n", after, value);
*data = 1;
return 1;
@@ -894,7 +894,8 @@ static int e1000_intr_test(struct e1000_adapter *adapter, u64 *data)
*data = 1;
return -1;
}
- e_info("testing %s interrupt\n", (shared_int ? "shared" : "unshared"));
+ e_info(hw, "testing %s interrupt\n", (shared_int ?
+ "shared" : "unshared"));
/* Disable all the interrupts */
ew32(IMC, 0xFFFFFFFF);
@@ -1561,7 +1562,7 @@ static void e1000_diag_test(struct net_device *netdev,
u8 forced_speed_duplex = hw->forced_speed_duplex;
u8 autoneg = hw->autoneg;
- e_info("offline testing starting\n");
+ e_info(hw, "offline testing starting\n");
/* Link test performed before hardware reset so autoneg doesn't
* interfere with test result */
@@ -1601,7 +1602,7 @@ static void e1000_diag_test(struct net_device *netdev,
if (if_running)
dev_open(netdev);
} else {
- e_info("online testing starting\n");
+ e_info(hw, "online testing starting\n");
/* Online tests */
if (e1000_link_test(adapter, &data[4]))
eth_test->flags |= ETH_TEST_FL_FAILED;
@@ -1694,8 +1695,8 @@ static void e1000_get_wol(struct net_device *netdev,
wol->supported &= ~WAKE_UCAST;
if (adapter->wol & E1000_WUFC_EX)
- e_err("Interface does not support "
- "directed (unicast) frame wake-up packets\n");
+ e_err(drv, "Interface does not support directed "
+ "(unicast) frame wake-up packets\n");
break;
default:
break;
@@ -1726,8 +1727,8 @@ static int e1000_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol)
switch (hw->device_id) {
case E1000_DEV_ID_82546GB_QUAD_COPPER_KSP3:
if (wol->wolopts & WAKE_UCAST) {
- e_err("Interface does not support "
- "directed (unicast) frame wake-up packets\n");
+ e_err(drv, "Interface does not support directed "
+ "(unicast) frame wake-up packets\n");
return -EOPNOTSUPP;
}
break;
diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c
index 68a80893dce..02833af8a0b 100644
--- a/drivers/net/e1000/e1000_main.c
+++ b/drivers/net/e1000/e1000_main.c
@@ -275,7 +275,7 @@ static int e1000_request_irq(struct e1000_adapter *adapter)
err = request_irq(adapter->pdev->irq, handler, irq_flags, netdev->name,
netdev);
if (err) {
- e_err("Unable to allocate interrupt Error: %d\n", err);
+ e_err(probe, "Unable to allocate interrupt Error: %d\n", err);
}
return err;
@@ -657,7 +657,7 @@ void e1000_reset(struct e1000_adapter *adapter)
ew32(WUC, 0);
if (e1000_init_hw(hw))
- e_err("Hardware Error\n");
+ e_dev_err("Hardware Error\n");
e1000_update_mng_vlan(adapter);
/* if (adapter->hwflags & HWFLAGS_PHY_PWR_BIT) { */
@@ -925,7 +925,7 @@ static int __devinit e1000_probe(struct pci_dev *pdev,
/* initialize eeprom parameters */
if (e1000_init_eeprom_params(hw)) {
- e_err("EEPROM initialization failed\n");
+ e_err(probe, "EEPROM initialization failed\n");
goto err_eeprom;
}
@@ -936,7 +936,7 @@ static int __devinit e1000_probe(struct pci_dev *pdev,
/* make sure the EEPROM is good */
if (e1000_validate_eeprom_checksum(hw) < 0) {
- e_err("The EEPROM Checksum Is Not Valid\n");
+ e_err(probe, "The EEPROM Checksum Is Not Valid\n");
e1000_dump_eeprom(adapter);
/*
* set MAC address to all zeroes to invalidate and temporary
@@ -950,14 +950,14 @@ static int __devinit e1000_probe(struct pci_dev *pdev,
} else {
/* copy the MAC address out of the EEPROM */
if (e1000_read_mac_addr(hw))
- e_err("EEPROM Read Error\n");
+ e_err(probe, "EEPROM Read Error\n");
}
/* don't block initalization here due to bad MAC address */
memcpy(netdev->dev_addr, hw->mac_addr, netdev->addr_len);
memcpy(netdev->perm_addr, hw->mac_addr, netdev->addr_len);
if (!is_valid_ether_addr(netdev->perm_addr))
- e_err("Invalid MAC Address\n");
+ e_err(probe, "Invalid MAC Address\n");
e1000_get_bus_info(hw);
@@ -1047,7 +1047,7 @@ static int __devinit e1000_probe(struct pci_dev *pdev,
goto err_register;
/* print bus type/speed/width info */
- e_info("(PCI%s:%dMHz:%d-bit) %pM\n",
+ e_info(probe, "(PCI%s:%dMHz:%d-bit) %pM\n",
((hw->bus_type == e1000_bus_type_pcix) ? "-X" : ""),
((hw->bus_speed == e1000_bus_speed_133) ? 133 :
(hw->bus_speed == e1000_bus_speed_120) ? 120 :
@@ -1059,7 +1059,7 @@ static int __devinit e1000_probe(struct pci_dev *pdev,
/* carrier off reporting is important to ethtool even BEFORE open */
netif_carrier_off(netdev);
- e_info("Intel(R) PRO/1000 Network Connection\n");
+ e_info(probe, "Intel(R) PRO/1000 Network Connection\n");
cards_found++;
return 0;
@@ -1159,7 +1159,7 @@ static int __devinit e1000_sw_init(struct e1000_adapter *adapter)
/* identify the MAC */
if (e1000_set_mac_type(hw)) {
- e_err("Unknown MAC Type\n");
+ e_err(probe, "Unknown MAC Type\n");
return -EIO;
}
@@ -1192,7 +1192,7 @@ static int __devinit e1000_sw_init(struct e1000_adapter *adapter)
adapter->num_rx_queues = 1;
if (e1000_alloc_queues(adapter)) {
- e_err("Unable to allocate memory for queues\n");
+ e_err(probe, "Unable to allocate memory for queues\n");
return -ENOMEM;
}
@@ -1386,7 +1386,8 @@ static int e1000_setup_tx_resources(struct e1000_adapter *adapter,
size = sizeof(struct e1000_buffer) * txdr->count;
txdr->buffer_info = vmalloc(size);
if (!txdr->buffer_info) {
- e_err("Unable to allocate memory for the Tx descriptor ring\n");
+ e_err(probe, "Unable to allocate memory for the Tx descriptor "
+ "ring\n");
return -ENOMEM;
}
memset(txdr->buffer_info, 0, size);
@@ -1401,7 +1402,8 @@ static int e1000_setup_tx_resources(struct e1000_adapter *adapter,
if (!txdr->desc) {
setup_tx_desc_die:
vfree(txdr->buffer_info);
- e_err("Unable to allocate memory for the Tx descriptor ring\n");
+ e_err(probe, "Unable to allocate memory for the Tx descriptor "
+ "ring\n");
return -ENOMEM;
}
@@ -1409,7 +1411,7 @@ setup_tx_desc_die:
if (!e1000_check_64k_bound(adapter, txdr->desc, txdr->size)) {
void *olddesc = txdr->desc;
dma_addr_t olddma = txdr->dma;
- e_err("txdr align check failed: %u bytes at %p\n",
+ e_err(tx_err, "txdr align check failed: %u bytes at %p\n",
txdr->size, txdr->desc);
/* Try again, without freeing the previous */
txdr->desc = dma_alloc_coherent(&pdev->dev, txdr->size,
@@ -1427,7 +1429,7 @@ setup_tx_desc_die:
txdr->dma);
dma_free_coherent(&pdev->dev, txdr->size, olddesc,
olddma);
- e_err("Unable to allocate aligned memory "
+ e_err(probe, "Unable to allocate aligned memory "
"for the transmit descriptor ring\n");
vfree(txdr->buffer_info);
return -ENOMEM;
@@ -1460,7 +1462,7 @@ int e1000_setup_all_tx_resources(struct e1000_adapter *adapter)
for (i = 0; i < adapter->num_tx_queues; i++) {
err = e1000_setup_tx_resources(adapter, &adapter->tx_ring[i]);
if (err) {
- e_err("Allocation for Tx Queue %u failed\n", i);
+ e_err(probe, "Allocation for Tx Queue %u failed\n", i);
for (i-- ; i >= 0; i--)
e1000_free_tx_resources(adapter,
&adapter->tx_ring[i]);
@@ -1580,7 +1582,8 @@ static int e1000_setup_rx_resources(struct e1000_adapter *adapter,
size = sizeof(struct e1000_buffer) * rxdr->count;
rxdr->buffer_info = vmalloc(size);
if (!rxdr->buffer_info) {
- e_err("Unable to allocate memory for the Rx descriptor ring\n");
+ e_err(probe, "Unable to allocate memory for the Rx descriptor "
+ "ring\n");
return -ENOMEM;
}
memset(rxdr->buffer_info, 0, size);
@@ -1596,7 +1599,8 @@ static int e1000_setup_rx_resources(struct e1000_adapter *adapter,
GFP_KERNEL);
if (!rxdr->desc) {
- e_err("Unable to allocate memory for the Rx descriptor ring\n");
+ e_err(probe, "Unable to allocate memory for the Rx descriptor "
+ "ring\n");
setup_rx_desc_die:
vfree(rxdr->buffer_info);
return -ENOMEM;
@@ -1606,7 +1610,7 @@ setup_rx_desc_die:
if (!e1000_check_64k_bound(adapter, rxdr->desc, rxdr->size)) {
void *olddesc = rxdr->desc;
dma_addr_t olddma = rxdr->dma;
- e_err("rxdr align check failed: %u bytes at %p\n",
+ e_err(rx_err, "rxdr align check failed: %u bytes at %p\n",
rxdr->size, rxdr->desc);
/* Try again, without freeing the previous */
rxdr->desc = dma_alloc_coherent(&pdev->dev, rxdr->size,
@@ -1615,8 +1619,8 @@ setup_rx_desc_die:
if (!rxdr->desc) {
dma_free_coherent(&pdev->dev, rxdr->size, olddesc,
olddma);
- e_err("Unable to allocate memory for the Rx descriptor "
- "ring\n");
+ e_err(probe, "Unable to allocate memory for the Rx "
+ "descriptor ring\n");
goto setup_rx_desc_die;
}
@@ -1626,8 +1630,8 @@ setup_rx_desc_die:
rxdr->dma);
dma_free_coherent(&pdev->dev, rxdr->size, olddesc,
olddma);
- e_err("Unable to allocate aligned memory for the Rx "
- "descriptor ring\n");
+ e_err(probe, "Unable to allocate aligned memory for "
+ "the Rx descriptor ring\n");
goto setup_rx_desc_die;
} else {
/* Free old allocation, new allocation was successful */
@@ -1659,7 +1663,7 @@ int e1000_setup_all_rx_resources(struct e1000_adapter *adapter)
for (i = 0; i < adapter->num_rx_queues; i++) {
err = e1000_setup_rx_resources(adapter, &adapter->rx_ring[i]);
if (err) {
- e_err("Allocation for Rx Queue %u failed\n", i);
+ e_err(probe, "Allocation for Rx Queue %u failed\n", i);
for (i-- ; i >= 0; i--)
e1000_free_rx_resources(adapter,
&adapter->rx_ring[i]);
@@ -2110,7 +2114,7 @@ static void e1000_set_rx_mode(struct net_device *netdev)
u32 *mcarray = kcalloc(mta_reg_count, sizeof(u32), GFP_ATOMIC);
if (!mcarray) {
- e_err("memory allocation failed\n");
+ e_err(probe, "memory allocation failed\n");
return;
}
@@ -2648,7 +2652,8 @@ static bool e1000_tx_csum(struct e1000_adapter *adapter,
break;
default:
if (unlikely(net_ratelimit()))
- e_warn("checksum_partial proto=%x!\n", skb->protocol);
+ e_warn(drv, "checksum_partial proto=%x!\n",
+ skb->protocol);
break;
}
@@ -2992,7 +2997,8 @@ static netdev_tx_t e1000_xmit_frame(struct sk_buff *skb,
/* fall through */
pull_size = min((unsigned int)4, skb->data_len);
if (!__pskb_pull_tail(skb, pull_size)) {
- e_err("__pskb_pull_tail failed.\n");
+ e_err(drv, "__pskb_pull_tail "
+ "failed.\n");
dev_kfree_skb_any(skb);
return NETDEV_TX_OK;
}
@@ -3140,7 +3146,7 @@ static int e1000_change_mtu(struct net_device *netdev, int new_mtu)
if ((max_frame < MINIMUM_ETHERNET_FRAME_SIZE) ||
(max_frame > MAX_JUMBO_FRAME_SIZE)) {
- e_err("Invalid MTU setting\n");
+ e_err(probe, "Invalid MTU setting\n");
return -EINVAL;
}
@@ -3148,7 +3154,7 @@ static int e1000_change_mtu(struct net_device *netdev, int new_mtu)
switch (hw->mac_type) {
case e1000_undefined ... e1000_82542_rev2_1:
if (max_frame > (ETH_FRAME_LEN + ETH_FCS_LEN)) {
- e_err("Jumbo Frames not supported.\n");
+ e_err(probe, "Jumbo Frames not supported.\n");
return -EINVAL;
}
break;
@@ -3500,7 +3506,7 @@ static bool e1000_clean_tx_irq(struct e1000_adapter *adapter,
!(er32(STATUS) & E1000_STATUS_TXOFF)) {
/* detected Tx unit hang */
- e_err("Detected Tx Unit Hang\n"
+ e_err(drv, "Detected Tx Unit Hang\n"
" Tx Queue <%lu>\n"
" TDH <%x>\n"
" TDT <%x>\n"
@@ -3749,7 +3755,7 @@ static bool e1000_clean_jumbo_rx_irq(struct e1000_adapter *adapter,
/* eth type trans needs skb->data to point to something */
if (!pskb_may_pull(skb, ETH_HLEN)) {
- e_err("pskb_may_pull failed.\n");
+ e_err(drv, "pskb_may_pull failed.\n");
dev_kfree_skb(skb);
goto next_desc;
}
@@ -3874,7 +3880,7 @@ static bool e1000_clean_rx_irq(struct e1000_adapter *adapter,
if (adapter->discarding) {
/* All receives must fit into a single buffer */
- e_info("Receive packet consumed multiple buffers\n");
+ e_dbg("Receive packet consumed multiple buffers\n");
/* recycle */
buffer_info->skb = skb;
if (status & E1000_RXD_STAT_EOP)
@@ -3986,8 +3992,8 @@ e1000_alloc_jumbo_rx_buffers(struct e1000_adapter *adapter,
/* Fix for errata 23, can't cross 64kB boundary */
if (!e1000_check_64k_bound(adapter, skb->data, bufsz)) {
struct sk_buff *oldskb = skb;
- e_err("skb align check failed: %u bytes at %p\n",
- bufsz, skb->data);
+ e_err(rx_err, "skb align check failed: %u bytes at "
+ "%p\n", bufsz, skb->data);
/* Try again, without freeing the previous */
skb = netdev_alloc_skb_ip_align(netdev, bufsz);
/* Failed allocation, critical failure */
@@ -4095,8 +4101,8 @@ static void e1000_alloc_rx_buffers(struct e1000_adapter *adapter,
/* Fix for errata 23, can't cross 64kB boundary */
if (!e1000_check_64k_bound(adapter, skb->data, bufsz)) {
struct sk_buff *oldskb = skb;
- e_err("skb align check failed: %u bytes at %p\n",
- bufsz, skb->data);
+ e_err(rx_err, "skb align check failed: %u bytes at "
+ "%p\n", bufsz, skb->data);
/* Try again, without freeing the previous */
skb = netdev_alloc_skb_ip_align(netdev, bufsz);
/* Failed allocation, critical failure */
@@ -4141,8 +4147,8 @@ map_skb:
if (!e1000_check_64k_bound(adapter,
(void *)(unsigned long)buffer_info->dma,
adapter->rx_buffer_len)) {
- e_err("dma align check failed: %u bytes at %p\n",
- adapter->rx_buffer_len,
+ e_err(rx_err, "dma align check failed: %u bytes at "
+ "%p\n", adapter->rx_buffer_len,
(void *)(unsigned long)buffer_info->dma);
dev_kfree_skb(skb);
buffer_info->skb = NULL;
@@ -4355,7 +4361,7 @@ void e1000_pci_set_mwi(struct e1000_hw *hw)
int ret_val = pci_set_mwi(adapter->pdev);
if (ret_val)
- e_err("Error in setting MWI\n");
+ e_err(probe, "Error in setting MWI\n");
}
void e1000_pci_clear_mwi(struct e1000_hw *hw)
@@ -4486,7 +4492,7 @@ int e1000_set_spd_dplx(struct e1000_adapter *adapter, u16 spddplx)
/* Fiber NICs only allow 1000 gbps Full duplex */
if ((hw->media_type == e1000_media_type_fiber) &&
spddplx != (SPEED_1000 + DUPLEX_FULL)) {
- e_err("Unsupported Speed/Duplex configuration\n");
+ e_err(probe, "Unsupported Speed/Duplex configuration\n");
return -EINVAL;
}
@@ -4509,7 +4515,7 @@ int e1000_set_spd_dplx(struct e1000_adapter *adapter, u16 spddplx)
break;
case SPEED_1000 + DUPLEX_HALF: /* not supported */
default:
- e_err("Unsupported Speed/Duplex configuration\n");
+ e_err(probe, "Unsupported Speed/Duplex configuration\n");
return -EINVAL;
}
return 0;
diff --git a/drivers/net/e1000e/82571.c b/drivers/net/e1000e/82571.c
index f654db9121d..a4a0d2b6eb1 100644
--- a/drivers/net/e1000e/82571.c
+++ b/drivers/net/e1000e/82571.c
@@ -1,7 +1,7 @@
/*******************************************************************************
Intel PRO/1000 Linux driver
- Copyright(c) 1999 - 2009 Intel Corporation.
+ Copyright(c) 1999 - 2010 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,
diff --git a/drivers/net/e1000e/defines.h b/drivers/net/e1000e/defines.h
index 4dc02c71ffd..307a72f483e 100644
--- a/drivers/net/e1000e/defines.h
+++ b/drivers/net/e1000e/defines.h
@@ -1,7 +1,7 @@
/*******************************************************************************
Intel PRO/1000 Linux driver
- Copyright(c) 1999 - 2009 Intel Corporation.
+ Copyright(c) 1999 - 2010 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,
@@ -359,6 +359,7 @@
#define E1000_EXTCNF_CTRL_LCD_WRITE_ENABLE 0x00000001
#define E1000_EXTCNF_CTRL_OEM_WRITE_ENABLE 0x00000008
#define E1000_EXTCNF_CTRL_SWFLAG 0x00000020
+#define E1000_EXTCNF_CTRL_GATE_PHY_CFG 0x00000080
#define E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH_MASK 0x00FF0000
#define E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH_SHIFT 16
#define E1000_EXTCNF_CTRL_EXT_CNF_POINTER_MASK 0x0FFF0000
@@ -714,6 +715,7 @@
#define BME1000_E_PHY_ID_R2 0x01410CB1
#define I82577_E_PHY_ID 0x01540050
#define I82578_E_PHY_ID 0x004DD040
+#define I82579_E_PHY_ID 0x01540090
/* M88E1000 Specific Registers */
#define M88E1000_PHY_SPEC_CTRL 0x10 /* PHY Specific Control Register */
diff --git a/drivers/net/e1000e/e1000.h b/drivers/net/e1000e/e1000.h
index c0b3db40bd7..f9a31c82f87 100644
--- a/drivers/net/e1000e/e1000.h
+++ b/drivers/net/e1000e/e1000.h
@@ -1,7 +1,7 @@
/*******************************************************************************
Intel PRO/1000 Linux driver
- Copyright(c) 1999 - 2009 Intel Corporation.
+ Copyright(c) 1999 - 2010 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,
@@ -164,6 +164,7 @@ enum e1000_boards {
board_ich9lan,
board_ich10lan,
board_pchlan,
+ board_pch2lan,
};
struct e1000_queue_stats {
@@ -347,6 +348,7 @@ struct e1000_adapter {
u32 test_icr;
u32 msg_enable;
+ unsigned int num_vectors;
struct msix_entry *msix_entries;
int int_mode;
u32 eiac_mask;
@@ -421,6 +423,8 @@ struct e1000_info {
#define FLAG2_HAS_PHY_WAKEUP (1 << 1)
#define FLAG2_IS_DISCARDING (1 << 2)
#define FLAG2_DISABLE_ASPM_L1 (1 << 3)
+#define FLAG2_HAS_PHY_STATS (1 << 4)
+#define FLAG2_HAS_EEE (1 << 5)
#define E1000_RX_DESC_PS(R, i) \
(&(((union e1000_rx_desc_packet_split *)((R).desc))[i]))
@@ -458,7 +462,6 @@ extern int e1000e_setup_tx_resources(struct e1000_adapter *adapter);
extern void e1000e_free_rx_resources(struct e1000_adapter *adapter);
extern void e1000e_free_tx_resources(struct e1000_adapter *adapter);
extern void e1000e_update_stats(struct e1000_adapter *adapter);
-extern bool e1000e_has_link(struct e1000_adapter *adapter);
extern void e1000e_set_interrupt_capability(struct e1000_adapter *adapter);
extern void e1000e_reset_interrupt_capability(struct e1000_adapter *adapter);
extern void e1000e_disable_aspm(struct pci_dev *pdev, u16 state);
@@ -476,6 +479,7 @@ extern struct e1000_info e1000_ich8_info;
extern struct e1000_info e1000_ich9_info;
extern struct e1000_info e1000_ich10_info;
extern struct e1000_info e1000_pch_info;
+extern struct e1000_info e1000_pch2_info;
extern struct e1000_info e1000_es2_info;
extern s32 e1000e_read_pba_num(struct e1000_hw *hw, u32 *pba_num);
@@ -494,6 +498,8 @@ extern void e1000e_igp3_phy_powerdown_workaround_ich8lan(struct e1000_hw *hw);
extern void e1000e_gig_downshift_workaround_ich8lan(struct e1000_hw *hw);
extern void e1000e_disable_gig_wol_ich8lan(struct e1000_hw *hw);
extern s32 e1000_configure_k1_ich8lan(struct e1000_hw *hw, bool k1_enable);
+extern s32 e1000_lv_jumbo_workaround_ich8lan(struct e1000_hw *hw, bool enable);
+extern void e1000_copy_rx_addrs_to_phy_ich8lan(struct e1000_hw *hw);
extern s32 e1000e_check_for_copper_link(struct e1000_hw *hw);
extern s32 e1000e_check_for_fiber_link(struct e1000_hw *hw);
diff --git a/drivers/net/e1000e/es2lan.c b/drivers/net/e1000e/es2lan.c
index 38d79a66905..45aebb4a6fe 100644
--- a/drivers/net/e1000e/es2lan.c
+++ b/drivers/net/e1000e/es2lan.c
@@ -1,7 +1,7 @@
/*******************************************************************************
Intel PRO/1000 Linux driver
- Copyright(c) 1999 - 2009 Intel Corporation.
+ Copyright(c) 1999 - 2010 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,
diff --git a/drivers/net/e1000e/ethtool.c b/drivers/net/e1000e/ethtool.c
index 2c521218102..6355a1b779d 100644
--- a/drivers/net/e1000e/ethtool.c
+++ b/drivers/net/e1000e/ethtool.c
@@ -1,7 +1,7 @@
/*******************************************************************************
Intel PRO/1000 Linux driver
- Copyright(c) 1999 - 2009 Intel Corporation.
+ Copyright(c) 1999 - 2010 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,
@@ -118,7 +118,6 @@ static int e1000_get_settings(struct net_device *netdev,
{
struct e1000_adapter *adapter = netdev_priv(netdev);
struct e1000_hw *hw = &adapter->hw;
- u32 status;
if (hw->phy.media_type == e1000_media_type_copper) {
@@ -156,22 +155,29 @@ static int e1000_get_settings(struct net_device *netdev,
ecmd->transceiver = XCVR_EXTERNAL;
}
- status = er32(STATUS);
- if (status & E1000_STATUS_LU) {
- if (status & E1000_STATUS_SPEED_1000)
- ecmd->speed = 1000;
- else if (status & E1000_STATUS_SPEED_100)
- ecmd->speed = 100;
- else
- ecmd->speed = 10;
+ ecmd->speed = -1;
+ ecmd->duplex = -1;
- if (status & E1000_STATUS_FD)
- ecmd->duplex = DUPLEX_FULL;
- else
- ecmd->duplex = DUPLEX_HALF;
+ if (netif_running(netdev)) {
+ if (netif_carrier_ok(netdev)) {
+ ecmd->speed = adapter->link_speed;
+ ecmd->duplex = adapter->link_duplex - 1;
+ }
} else {
- ecmd->speed = -1;
- ecmd->duplex = -1;
+ u32 status = er32(STATUS);
+ if (status & E1000_STATUS_LU) {
+ if (status & E1000_STATUS_SPEED_1000)
+ ecmd->speed = 1000;
+ else if (status & E1000_STATUS_SPEED_100)
+ ecmd->speed = 100;
+ else
+ ecmd->speed = 10;
+
+ if (status & E1000_STATUS_FD)
+ ecmd->duplex = DUPLEX_FULL;
+ else
+ ecmd->duplex = DUPLEX_HALF;
+ }
}
ecmd->autoneg = ((hw->phy.media_type == e1000_media_type_fiber) ||
@@ -179,7 +185,7 @@ static int e1000_get_settings(struct net_device *netdev,
/* MDI-X => 2; MDI =>1; Invalid =>0 */
if ((hw->phy.media_type == e1000_media_type_copper) &&
- !hw->mac.get_link_status)
+ netif_carrier_ok(netdev))
ecmd->eth_tp_mdix = hw->phy.is_mdix ? ETH_TP_MDI_X :
ETH_TP_MDI;
else
@@ -191,19 +197,15 @@ static int e1000_get_settings(struct net_device *netdev,
static u32 e1000_get_link(struct net_device *netdev)
{
struct e1000_adapter *adapter = netdev_priv(netdev);
- struct e1000_mac_info *mac = &adapter->hw.mac;
+ struct e1000_hw *hw = &adapter->hw;
/*
- * If the link is not reported up to netdev, interrupts are disabled,
- * and so the physical link state may have changed since we last
- * looked. Set get_link_status to make sure that the true link
- * state is interrogated, rather than pulling a cached and possibly
- * stale link state from the driver.
+ * Avoid touching hardware registers when possible, otherwise
+ * link negotiation can get messed up when user-level scripts
+ * are rapidly polling the driver to see if link is up.
*/
- if (!netif_carrier_ok(netdev))
- mac->get_link_status = 1;
-
- return e1000e_has_link(adapter);
+ return netif_running(netdev) ? netif_carrier_ok(netdev) :
+ !!(er32(STATUS) & E1000_STATUS_LU);
}
static int e1000_set_spd_dplx(struct e1000_adapter *adapter, u16 spddplx)
@@ -880,6 +882,7 @@ static int e1000_reg_test(struct e1000_adapter *adapter, u64 *data)
switch (mac->type) {
case e1000_ich10lan:
case e1000_pchlan:
+ case e1000_pch2lan:
mask |= (1 << 18);
break;
default:
@@ -1263,33 +1266,36 @@ static int e1000_integrated_phy_loopback(struct e1000_adapter *adapter)
hw->mac.autoneg = 0;
- /* Workaround: K1 must be disabled for stable 1Gbps operation */
- if (hw->mac.type == e1000_pchlan)
- e1000_configure_k1_ich8lan(hw, false);
-
- if (hw->phy.type == e1000_phy_m88) {
- /* Auto-MDI/MDIX Off */
- e1e_wphy(hw, M88E1000_PHY_SPEC_CTRL, 0x0808);
- /* reset to update Auto-MDI/MDIX */
- e1e_wphy(hw, PHY_CONTROL, 0x9140);
- /* autoneg off */
- e1e_wphy(hw, PHY_CONTROL, 0x8140);
- } else if (hw->phy.type == e1000_phy_gg82563)
- e1e_wphy(hw, GG82563_PHY_KMRN_MODE_CTRL, 0x1CC);
-
- ctrl_reg = er32(CTRL);
-
- switch (hw->phy.type) {
- case e1000_phy_ife:
+ if (hw->phy.type == e1000_phy_ife) {
/* force 100, set loopback */
e1e_wphy(hw, PHY_CONTROL, 0x6100);
/* Now set up the MAC to the same speed/duplex as the PHY. */
+ ctrl_reg = er32(CTRL);
ctrl_reg &= ~E1000_CTRL_SPD_SEL; /* Clear the speed sel bits */
ctrl_reg |= (E1000_CTRL_FRCSPD | /* Set the Force Speed Bit */
E1000_CTRL_FRCDPX | /* Set the Force Duplex Bit */
E1000_CTRL_SPD_100 |/* Force Speed to 100 */
E1000_CTRL_FD); /* Force Duplex to FULL */
+
+ ew32(CTRL, ctrl_reg);
+ udelay(500);
+
+ return 0;
+ }
+
+ /* Specific PHY configuration for loopback */
+ switch (hw->phy.type) {
+ case e1000_phy_m88:
+ /* Auto-MDI/MDIX Off */
+ e1e_wphy(hw, M88E1000_PHY_SPEC_CTRL, 0x0808);
+ /* reset to update Auto-MDI/MDIX */
+ e1e_wphy(hw, PHY_CONTROL, 0x9140);
+ /* autoneg off */
+ e1e_wphy(hw, PHY_CONTROL, 0x8140);
+ break;
+ case e1000_phy_gg82563:
+ e1e_wphy(hw, GG82563_PHY_KMRN_MODE_CTRL, 0x1CC);
break;
case e1000_phy_bm:
/* Set Default MAC Interface speed to 1GB */
@@ -1312,23 +1318,41 @@ static int e1000_integrated_phy_loopback(struct e1000_adapter *adapter)
/* Set Early Link Enable */
e1e_rphy(hw, PHY_REG(769, 20), &phy_reg);
e1e_wphy(hw, PHY_REG(769, 20), phy_reg | 0x0400);
- /* fall through */
+ break;
+ case e1000_phy_82577:
+ case e1000_phy_82578:
+ /* Workaround: K1 must be disabled for stable 1Gbps operation */
+ e1000_configure_k1_ich8lan(hw, false);
+ break;
+ case e1000_phy_82579:
+ /* Disable PHY energy detect power down */
+ e1e_rphy(hw, PHY_REG(0, 21), &phy_reg);
+ e1e_wphy(hw, PHY_REG(0, 21), phy_reg & ~(1 << 3));
+ /* Disable full chip energy detect */
+ e1e_rphy(hw, PHY_REG(776, 18), &phy_reg);
+ e1e_wphy(hw, PHY_REG(776, 18), phy_reg | 1);
+ /* Enable loopback on the PHY */
+#define I82577_PHY_LBK_CTRL 19
+ e1e_wphy(hw, I82577_PHY_LBK_CTRL, 0x8001);
+ break;
default:
- /* force 1000, set loopback */
- e1e_wphy(hw, PHY_CONTROL, 0x4140);
- mdelay(250);
+ break;
+ }
- /* Now set up the MAC to the same speed/duplex as the PHY. */
- ctrl_reg = er32(CTRL);
- ctrl_reg &= ~E1000_CTRL_SPD_SEL; /* Clear the speed sel bits */
- ctrl_reg |= (E1000_CTRL_FRCSPD | /* Set the Force Speed Bit */
- E1000_CTRL_FRCDPX | /* Set the Force Duplex Bit */
- E1000_CTRL_SPD_1000 |/* Force Speed to 1000 */
- E1000_CTRL_FD); /* Force Duplex to FULL */
+ /* force 1000, set loopback */
+ e1e_wphy(hw, PHY_CONTROL, 0x4140);
+ mdelay(250);
- if (adapter->flags & FLAG_IS_ICH)
- ctrl_reg |= E1000_CTRL_SLU; /* Set Link Up */
- }
+ /* Now set up the MAC to the same speed/duplex as the PHY. */
+ ctrl_reg = er32(CTRL);
+ ctrl_reg &= ~E1000_CTRL_SPD_SEL; /* Clear the speed sel bits */
+ ctrl_reg |= (E1000_CTRL_FRCSPD | /* Set the Force Speed Bit */
+ E1000_CTRL_FRCDPX | /* Set the Force Duplex Bit */
+ E1000_CTRL_SPD_1000 |/* Force Speed to 1000 */
+ E1000_CTRL_FD); /* Force Duplex to FULL */
+
+ if (adapter->flags & FLAG_IS_ICH)
+ ctrl_reg |= E1000_CTRL_SLU; /* Set Link Up */
if (hw->phy.media_type == e1000_media_type_copper &&
hw->phy.type == e1000_phy_m88) {
@@ -1868,6 +1892,7 @@ static int e1000_phys_id(struct net_device *netdev, u32 data)
if ((hw->phy.type == e1000_phy_ife) ||
(hw->mac.type == e1000_pchlan) ||
+ (hw->mac.type == e1000_pch2lan) ||
(hw->mac.type == e1000_82583) ||
(hw->mac.type == e1000_82574)) {
INIT_WORK(&adapter->led_blink_task, e1000e_led_blink_task);
@@ -2026,7 +2051,6 @@ static const struct ethtool_ops e1000_ethtool_ops = {
.get_coalesce = e1000_get_coalesce,
.set_coalesce = e1000_set_coalesce,
.get_flags = ethtool_op_get_flags,
- .set_flags = ethtool_op_set_flags,
};
void e1000e_set_ethtool_ops(struct net_device *netdev)
diff --git a/drivers/net/e1000e/hw.h b/drivers/net/e1000e/hw.h
index 5d1220d188d..66ed08f726f 100644
--- a/drivers/net/e1000e/hw.h
+++ b/drivers/net/e1000e/hw.h
@@ -1,7 +1,7 @@
/*******************************************************************************
Intel PRO/1000 Linux driver
- Copyright(c) 1999 - 2009 Intel Corporation.
+ Copyright(c) 1999 - 2010 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,
@@ -217,7 +217,10 @@ enum e1e_registers {
E1000_SWSM = 0x05B50, /* SW Semaphore */
E1000_FWSM = 0x05B54, /* FW Semaphore */
E1000_SWSM2 = 0x05B58, /* Driver-only SW semaphore */
- E1000_CRC_OFFSET = 0x05F50, /* CRC Offset register */
+ E1000_FFLT_DBG = 0x05F04, /* Debug Register */
+ E1000_PCH_RAICC_BASE = 0x05F50, /* Receive Address Initial CRC */
+#define E1000_PCH_RAICC(_n) (E1000_PCH_RAICC_BASE + ((_n) * 4))
+#define E1000_CRC_OFFSET E1000_PCH_RAICC_BASE
E1000_HICR = 0x08F00, /* Host Interface Control */
};
@@ -303,13 +306,14 @@ enum e1e_registers {
#define E1000_KMRNCTRLSTA_OFFSET 0x001F0000
#define E1000_KMRNCTRLSTA_OFFSET_SHIFT 16
#define E1000_KMRNCTRLSTA_REN 0x00200000
+#define E1000_KMRNCTRLSTA_CTRL_OFFSET 0x1 /* Kumeran Control */
#define E1000_KMRNCTRLSTA_DIAG_OFFSET 0x3 /* Kumeran Diagnostic */
#define E1000_KMRNCTRLSTA_TIMEOUTS 0x4 /* Kumeran Timeouts */
#define E1000_KMRNCTRLSTA_INBAND_PARAM 0x9 /* Kumeran InBand Parameters */
#define E1000_KMRNCTRLSTA_DIAG_NELPBK 0x1000 /* Nearend Loopback mode */
#define E1000_KMRNCTRLSTA_K1_CONFIG 0x7
-#define E1000_KMRNCTRLSTA_K1_ENABLE 0x140E
-#define E1000_KMRNCTRLSTA_K1_DISABLE 0x1400
+#define E1000_KMRNCTRLSTA_K1_ENABLE 0x0002
+#define E1000_KMRNCTRLSTA_HD_CTRL 0x10 /* Kumeran HD Control */
#define IFE_PHY_EXTENDED_STATUS_CONTROL 0x10
#define IFE_PHY_SPECIAL_CONTROL 0x11 /* 100BaseTx PHY Special Control */
@@ -387,6 +391,8 @@ enum e1e_registers {
#define E1000_DEV_ID_PCH_M_HV_LC 0x10EB
#define E1000_DEV_ID_PCH_D_HV_DM 0x10EF
#define E1000_DEV_ID_PCH_D_HV_DC 0x10F0
+#define E1000_DEV_ID_PCH2_LV_LM 0x1502
+#define E1000_DEV_ID_PCH2_LV_V 0x1503
#define E1000_REVISION_4 4
@@ -406,6 +412,7 @@ enum e1000_mac_type {
e1000_ich9lan,
e1000_ich10lan,
e1000_pchlan,
+ e1000_pch2lan,
};
enum e1000_media_type {
@@ -442,6 +449,7 @@ enum e1000_phy_type {
e1000_phy_bm,
e1000_phy_82578,
e1000_phy_82577,
+ e1000_phy_82579,
};
enum e1000_bus_width {
@@ -929,6 +937,7 @@ struct e1000_dev_spec_ich8lan {
bool kmrn_lock_loss_workaround_enabled;
struct e1000_shadow_ram shadow_ram[E1000_ICH8_SHADOW_RAM_WORDS];
bool nvm_k1_enabled;
+ bool eee_disable;
};
struct e1000_hw {
diff --git a/drivers/net/e1000e/ich8lan.c b/drivers/net/e1000e/ich8lan.c
index b2507d93de9..63930d12711 100644
--- a/drivers/net/e1000e/ich8lan.c
+++ b/drivers/net/e1000e/ich8lan.c
@@ -1,7 +1,7 @@
/*******************************************************************************
Intel PRO/1000 Linux driver
- Copyright(c) 1999 - 2009 Intel Corporation.
+ Copyright(c) 1999 - 2010 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,
@@ -52,6 +52,8 @@
* 82577LC Gigabit Network Connection
* 82578DM Gigabit Network Connection
* 82578DC Gigabit Network Connection
+ * 82579LM Gigabit Network Connection
+ * 82579V Gigabit Network Connection
*/
#include "e1000.h"
@@ -126,6 +128,13 @@
#define HV_SMB_ADDR_PEC_EN 0x0200
#define HV_SMB_ADDR_VALID 0x0080
+/* PHY Power Management Control */
+#define HV_PM_CTRL PHY_REG(770, 17)
+
+/* PHY Low Power Idle Control */
+#define I82579_LPI_CTRL PHY_REG(772, 20)
+#define I82579_LPI_CTRL_ENABLE_MASK 0x6000
+
/* Strapping Option Register - RO */
#define E1000_STRAP 0x0000C
#define E1000_STRAP_SMBUS_ADDRESS_MASK 0x00FE0000
@@ -226,6 +235,8 @@ static void e1000_power_down_phy_copper_ich8lan(struct e1000_hw *hw);
static void e1000_lan_init_done_ich8lan(struct e1000_hw *hw);
static s32 e1000_k1_gig_workaround_hv(struct e1000_hw *hw, bool link);
static s32 e1000_set_mdio_slow_mode_hv(struct e1000_hw *hw);
+static bool e1000_check_mng_mode_ich8lan(struct e1000_hw *hw);
+static bool e1000_check_mng_mode_pchlan(struct e1000_hw *hw);
static inline u16 __er16flash(struct e1000_hw *hw, unsigned long reg)
{
@@ -277,13 +288,13 @@ static s32 e1000_init_phy_params_pchlan(struct e1000_hw *hw)
phy->ops.power_down = e1000_power_down_phy_copper_ich8lan;
phy->autoneg_mask = AUTONEG_ADVERTISE_SPEED_DEFAULT;
+ /*
+ * The MAC-PHY interconnect may still be in SMBus mode
+ * after Sx->S0. If the manageability engine (ME) is
+ * disabled, then toggle the LANPHYPC Value bit to force
+ * the interconnect to PCIe mode.
+ */
if (!(er32(FWSM) & E1000_ICH_FWSM_FW_VALID)) {
- /*
- * The MAC-PHY interconnect may still be in SMBus mode
- * after Sx->S0. Toggle the LANPHYPC Value bit to force
- * the interconnect to PCIe mode, but only if there is no
- * firmware present otherwise firmware will have done it.
- */
ctrl = er32(CTRL);
ctrl |= E1000_CTRL_LANPHYPC_OVERRIDE;
ctrl &= ~E1000_CTRL_LANPHYPC_VALUE;
@@ -324,6 +335,7 @@ static s32 e1000_init_phy_params_pchlan(struct e1000_hw *hw)
switch (phy->type) {
case e1000_phy_82577:
+ case e1000_phy_82579:
phy->ops.check_polarity = e1000_check_polarity_82577;
phy->ops.force_speed_duplex =
e1000_phy_force_speed_duplex_82577;
@@ -515,6 +527,8 @@ static s32 e1000_init_mac_params_ich8lan(struct e1000_adapter *adapter)
case e1000_ich8lan:
case e1000_ich9lan:
case e1000_ich10lan:
+ /* check management mode */
+ mac->ops.check_mng_mode = e1000_check_mng_mode_ich8lan;
/* ID LED init */
mac->ops.id_led_init = e1000e_id_led_init;
/* setup LED */
@@ -526,6 +540,9 @@ static s32 e1000_init_mac_params_ich8lan(struct e1000_adapter *adapter)
mac->ops.led_off = e1000_led_off_ich8lan;
break;
case e1000_pchlan:
+ case e1000_pch2lan:
+ /* check management mode */
+ mac->ops.check_mng_mode = e1000_check_mng_mode_pchlan;
/* ID LED init */
mac->ops.id_led_init = e1000_id_led_init_pchlan;
/* setup LED */
@@ -544,10 +561,47 @@ static s32 e1000_init_mac_params_ich8lan(struct e1000_adapter *adapter)
if (mac->type == e1000_ich8lan)
e1000e_set_kmrn_lock_loss_workaround_ich8lan(hw, true);
+ /* Disable PHY configuration by hardware, config by software */
+ if (mac->type == e1000_pch2lan) {
+ u32 extcnf_ctrl = er32(EXTCNF_CTRL);
+
+ extcnf_ctrl |= E1000_EXTCNF_CTRL_GATE_PHY_CFG;
+ ew32(EXTCNF_CTRL, extcnf_ctrl);
+ }
+
return 0;
}
/**
+ * e1000_set_eee_pchlan - Enable/disable EEE support
+ * @hw: pointer to the HW structure
+ *
+ * Enable/disable EEE based on setting in dev_spec structure. The bits in
+ * the LPI Control register will remain set only if/when link is up.
+ **/
+static s32 e1000_set_eee_pchlan(struct e1000_hw *hw)
+{
+ s32 ret_val = 0;
+ u16 phy_reg;
+
+ if (hw->phy.type != e1000_phy_82579)
+ goto out;
+
+ ret_val = e1e_rphy(hw, I82579_LPI_CTRL, &phy_reg);
+ if (ret_val)
+ goto out;
+
+ if (hw->dev_spec.ich8lan.eee_disable)
+ phy_reg &= ~I82579_LPI_CTRL_ENABLE_MASK;
+ else
+ phy_reg |= I82579_LPI_CTRL_ENABLE_MASK;
+
+ ret_val = e1e_wphy(hw, I82579_LPI_CTRL, phy_reg);
+out:
+ return ret_val;
+}
+
+/**
* e1000_check_for_copper_link_ich8lan - Check for link (Copper)
* @hw: pointer to the HW structure
*
@@ -604,6 +658,11 @@ static s32 e1000_check_for_copper_link_ich8lan(struct e1000_hw *hw)
*/
e1000e_check_downshift(hw);
+ /* Enable/Disable EEE after link up */
+ ret_val = e1000_set_eee_pchlan(hw);
+ if (ret_val)
+ goto out;
+
/*
* If we are forcing speed/duplex, then we simply return since
* we have already determined whether we have link or not.
@@ -647,10 +706,19 @@ static s32 e1000_get_variants_ich8lan(struct e1000_adapter *adapter)
if (rc)
return rc;
- if (hw->mac.type == e1000_pchlan)
- rc = e1000_init_phy_params_pchlan(hw);
- else
+ switch (hw->mac.type) {
+ case e1000_ich8lan:
+ case e1000_ich9lan:
+ case e1000_ich10lan:
rc = e1000_init_phy_params_ich8lan(hw);
+ break;
+ case e1000_pchlan:
+ case e1000_pch2lan:
+ rc = e1000_init_phy_params_pchlan(hw);
+ break;
+ default:
+ break;
+ }
if (rc)
return rc;
@@ -663,6 +731,10 @@ static s32 e1000_get_variants_ich8lan(struct e1000_adapter *adapter)
(adapter->hw.phy.type == e1000_phy_igp_3))
adapter->flags |= FLAG_LSC_GIG_SPEED_DROP;
+ /* Disable EEE by default until IEEE802.3az spec is finalized */
+ if (adapter->flags2 & FLAG2_HAS_EEE)
+ adapter->hw.dev_spec.ich8lan.eee_disable = true;
+
return 0;
}
@@ -774,7 +846,7 @@ static void e1000_release_swflag_ich8lan(struct e1000_hw *hw)
* e1000_check_mng_mode_ich8lan - Checks management mode
* @hw: pointer to the HW structure
*
- * This checks if the adapter has manageability enabled.
+ * This checks if the adapter has any manageability enabled.
* This is a function pointer entry point only called by read/write
* routines for the PHY and NVM parts.
**/
@@ -783,9 +855,26 @@ static bool e1000_check_mng_mode_ich8lan(struct e1000_hw *hw)
u32 fwsm;
fwsm = er32(FWSM);
+ return (fwsm & E1000_ICH_FWSM_FW_VALID) &&
+ ((fwsm & E1000_FWSM_MODE_MASK) ==
+ (E1000_ICH_MNG_IAMT_MODE << E1000_FWSM_MODE_SHIFT));
+}
+
+/**
+ * e1000_check_mng_mode_pchlan - Checks management mode
+ * @hw: pointer to the HW structure
+ *
+ * This checks if the adapter has iAMT enabled.
+ * This is a function pointer entry point only called by read/write
+ * routines for the PHY and NVM parts.
+ **/
+static bool e1000_check_mng_mode_pchlan(struct e1000_hw *hw)
+{
+ u32 fwsm;
- return (fwsm & E1000_FWSM_MODE_MASK) ==
- (E1000_ICH_MNG_IAMT_MODE << E1000_FWSM_MODE_SHIFT);
+ fwsm = er32(FWSM);
+ return (fwsm & E1000_ICH_FWSM_FW_VALID) &&
+ (fwsm & (E1000_ICH_MNG_IAMT_MODE << E1000_FWSM_MODE_SHIFT));
}
/**
@@ -820,14 +909,6 @@ static s32 e1000_sw_lcd_config_ich8lan(struct e1000_hw *hw)
s32 ret_val = 0;
u16 word_addr, reg_data, reg_addr, phy_page = 0;
- if (!(hw->mac.type == e1000_ich8lan && phy->type == e1000_phy_igp_3) &&
- !(hw->mac.type == e1000_pchlan))
- return ret_val;
-
- ret_val = hw->phy.ops.acquire(hw);
- if (ret_val)
- return ret_val;
-
/*
* Initialize the PHY from the NVM on ICH platforms. This
* is needed due to an issue where the NVM configuration is
@@ -835,12 +916,27 @@ static s32 e1000_sw_lcd_config_ich8lan(struct e1000_hw *hw)
* Therefore, after each PHY reset, we will load the
* configuration data out of the NVM manually.
*/
- if ((adapter->pdev->device == E1000_DEV_ID_ICH8_IGP_M_AMT) ||
- (adapter->pdev->device == E1000_DEV_ID_ICH8_IGP_M) ||
- (hw->mac.type == e1000_pchlan))
+ switch (hw->mac.type) {
+ case e1000_ich8lan:
+ if (phy->type != e1000_phy_igp_3)
+ return ret_val;
+
+ if (adapter->pdev->device == E1000_DEV_ID_ICH8_IGP_AMT) {
+ sw_cfg_mask = E1000_FEXTNVM_SW_CONFIG;
+ break;
+ }
+ /* Fall-thru */
+ case e1000_pchlan:
+ case e1000_pch2lan:
sw_cfg_mask = E1000_FEXTNVM_SW_CONFIG_ICH8M;
- else
- sw_cfg_mask = E1000_FEXTNVM_SW_CONFIG;
+ break;
+ default:
+ return ret_val;
+ }
+
+ ret_val = hw->phy.ops.acquire(hw);
+ if (ret_val)
+ return ret_val;
data = er32(FEXTNVM);
if (!(data & sw_cfg_mask))
@@ -851,8 +947,10 @@ static s32 e1000_sw_lcd_config_ich8lan(struct e1000_hw *hw)
* extended configuration before SW configuration
*/
data = er32(EXTCNF_CTRL);
- if (data & E1000_EXTCNF_CTRL_LCD_WRITE_ENABLE)
- goto out;
+ if (!(hw->mac.type == e1000_pch2lan)) {
+ if (data & E1000_EXTCNF_CTRL_LCD_WRITE_ENABLE)
+ goto out;
+ }
cnf_size = er32(EXTCNF_SIZE);
cnf_size &= E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH_MASK;
@@ -864,7 +962,8 @@ static s32 e1000_sw_lcd_config_ich8lan(struct e1000_hw *hw)
cnf_base_addr >>= E1000_EXTCNF_CTRL_EXT_CNF_POINTER_SHIFT;
if (!(data & E1000_EXTCNF_CTRL_OEM_WRITE_ENABLE) &&
- (hw->mac.type == e1000_pchlan)) {
+ ((hw->mac.type == e1000_pchlan) ||
+ (hw->mac.type == e1000_pch2lan))) {
/*
* HW configures the SMBus address and LEDs when the
* OEM and LCD Write Enable bits are set in the NVM.
@@ -1071,16 +1170,18 @@ static s32 e1000_oem_bits_config_ich8lan(struct e1000_hw *hw, bool d0_state)
u32 mac_reg;
u16 oem_reg;
- if (hw->mac.type != e1000_pchlan)
+ if ((hw->mac.type != e1000_pch2lan) && (hw->mac.type != e1000_pchlan))
return ret_val;
ret_val = hw->phy.ops.acquire(hw);
if (ret_val)
return ret_val;
- mac_reg = er32(EXTCNF_CTRL);
- if (mac_reg & E1000_EXTCNF_CTRL_OEM_WRITE_ENABLE)
- goto out;
+ if (!(hw->mac.type == e1000_pch2lan)) {
+ mac_reg = er32(EXTCNF_CTRL);
+ if (mac_reg & E1000_EXTCNF_CTRL_OEM_WRITE_ENABLE)
+ goto out;
+ }
mac_reg = er32(FEXTNVM);
if (!(mac_reg & E1000_FEXTNVM_SW_CONFIG_ICH8M))
@@ -1221,6 +1322,243 @@ out:
}
/**
+ * e1000_copy_rx_addrs_to_phy_ich8lan - Copy Rx addresses from MAC to PHY
+ * @hw: pointer to the HW structure
+ **/
+void e1000_copy_rx_addrs_to_phy_ich8lan(struct e1000_hw *hw)
+{
+ u32 mac_reg;
+ u16 i;
+
+ /* Copy both RAL/H (rar_entry_count) and SHRAL/H (+4) to PHY */
+ for (i = 0; i < (hw->mac.rar_entry_count + 4); i++) {
+ mac_reg = er32(RAL(i));
+ e1e_wphy(hw, BM_RAR_L(i), (u16)(mac_reg & 0xFFFF));
+ e1e_wphy(hw, BM_RAR_M(i), (u16)((mac_reg >> 16) & 0xFFFF));
+ mac_reg = er32(RAH(i));
+ e1e_wphy(hw, BM_RAR_H(i), (u16)(mac_reg & 0xFFFF));
+ e1e_wphy(hw, BM_RAR_CTRL(i), (u16)((mac_reg >> 16) & 0x8000));
+ }
+}
+
+static u32 e1000_calc_rx_da_crc(u8 mac[])
+{
+ u32 poly = 0xEDB88320; /* Polynomial for 802.3 CRC calculation */
+ u32 i, j, mask, crc;
+
+ crc = 0xffffffff;
+ for (i = 0; i < 6; i++) {
+ crc = crc ^ mac[i];
+ for (j = 8; j > 0; j--) {
+ mask = (crc & 1) * (-1);
+ crc = (crc >> 1) ^ (poly & mask);
+ }
+ }
+ return ~crc;
+}
+
+/**
+ * e1000_lv_jumbo_workaround_ich8lan - required for jumbo frame operation
+ * with 82579 PHY
+ * @hw: pointer to the HW structure
+ * @enable: flag to enable/disable workaround when enabling/disabling jumbos
+ **/
+s32 e1000_lv_jumbo_workaround_ich8lan(struct e1000_hw *hw, bool enable)
+{
+ s32 ret_val = 0;
+ u16 phy_reg, data;
+ u32 mac_reg;
+ u16 i;
+
+ if (hw->mac.type != e1000_pch2lan)
+ goto out;
+
+ /* disable Rx path while enabling/disabling workaround */
+ e1e_rphy(hw, PHY_REG(769, 20), &phy_reg);
+ ret_val = e1e_wphy(hw, PHY_REG(769, 20), phy_reg | (1 << 14));
+ if (ret_val)
+ goto out;
+
+ if (enable) {
+ /*
+ * Write Rx addresses (rar_entry_count for RAL/H, +4 for
+ * SHRAL/H) and initial CRC values to the MAC
+ */
+ for (i = 0; i < (hw->mac.rar_entry_count + 4); i++) {
+ u8 mac_addr[ETH_ALEN] = {0};
+ u32 addr_high, addr_low;
+
+ addr_high = er32(RAH(i));
+ if (!(addr_high & E1000_RAH_AV))
+ continue;
+ addr_low = er32(RAL(i));
+ mac_addr[0] = (addr_low & 0xFF);
+ mac_addr[1] = ((addr_low >> 8) & 0xFF);
+ mac_addr[2] = ((addr_low >> 16) & 0xFF);
+ mac_addr[3] = ((addr_low >> 24) & 0xFF);
+ mac_addr[4] = (addr_high & 0xFF);
+ mac_addr[5] = ((addr_high >> 8) & 0xFF);
+
+ ew32(PCH_RAICC(i),
+ e1000_calc_rx_da_crc(mac_addr));
+ }
+
+ /* Write Rx addresses to the PHY */
+ e1000_copy_rx_addrs_to_phy_ich8lan(hw);
+
+ /* Enable jumbo frame workaround in the MAC */
+ mac_reg = er32(FFLT_DBG);
+ mac_reg &= ~(1 << 14);
+ mac_reg |= (7 << 15);
+ ew32(FFLT_DBG, mac_reg);
+
+ mac_reg = er32(RCTL);
+ mac_reg |= E1000_RCTL_SECRC;
+ ew32(RCTL, mac_reg);
+
+ ret_val = e1000e_read_kmrn_reg(hw,
+ E1000_KMRNCTRLSTA_CTRL_OFFSET,
+ &data);
+ if (ret_val)
+ goto out;
+ ret_val = e1000e_write_kmrn_reg(hw,
+ E1000_KMRNCTRLSTA_CTRL_OFFSET,
+ data | (1 << 0));
+ if (ret_val)
+ goto out;
+ ret_val = e1000e_read_kmrn_reg(hw,
+ E1000_KMRNCTRLSTA_HD_CTRL,
+ &data);
+ if (ret_val)
+ goto out;
+ data &= ~(0xF << 8);
+ data |= (0xB << 8);
+ ret_val = e1000e_write_kmrn_reg(hw,
+ E1000_KMRNCTRLSTA_HD_CTRL,
+ data);
+ if (ret_val)
+ goto out;
+
+ /* Enable jumbo frame workaround in the PHY */
+ e1e_rphy(hw, PHY_REG(769, 20), &data);
+ ret_val = e1e_wphy(hw, PHY_REG(769, 20), data & ~(1 << 14));
+ if (ret_val)
+ goto out;
+ e1e_rphy(hw, PHY_REG(769, 23), &data);
+ data &= ~(0x7F << 5);
+ data |= (0x37 << 5);
+ ret_val = e1e_wphy(hw, PHY_REG(769, 23), data);
+ if (ret_val)
+ goto out;
+ e1e_rphy(hw, PHY_REG(769, 16), &data);
+ data &= ~(1 << 13);
+ data |= (1 << 12);
+ ret_val = e1e_wphy(hw, PHY_REG(769, 16), data);
+ if (ret_val)
+ goto out;
+ e1e_rphy(hw, PHY_REG(776, 20), &data);
+ data &= ~(0x3FF << 2);
+ data |= (0x1A << 2);
+ ret_val = e1e_wphy(hw, PHY_REG(776, 20), data);
+ if (ret_val)
+ goto out;
+ ret_val = e1e_wphy(hw, PHY_REG(776, 23), 0xFE00);
+ if (ret_val)
+ goto out;
+ e1e_rphy(hw, HV_PM_CTRL, &data);
+ ret_val = e1e_wphy(hw, HV_PM_CTRL, data | (1 << 10));
+ if (ret_val)
+ goto out;
+ } else {
+ /* Write MAC register values back to h/w defaults */
+ mac_reg = er32(FFLT_DBG);
+ mac_reg &= ~(0xF << 14);
+ ew32(FFLT_DBG, mac_reg);
+
+ mac_reg = er32(RCTL);
+ mac_reg &= ~E1000_RCTL_SECRC;
+ ew32(FFLT_DBG, mac_reg);
+
+ ret_val = e1000e_read_kmrn_reg(hw,
+ E1000_KMRNCTRLSTA_CTRL_OFFSET,
+ &data);
+ if (ret_val)
+ goto out;
+ ret_val = e1000e_write_kmrn_reg(hw,
+ E1000_KMRNCTRLSTA_CTRL_OFFSET,
+ data & ~(1 << 0));
+ if (ret_val)
+ goto out;
+ ret_val = e1000e_read_kmrn_reg(hw,
+ E1000_KMRNCTRLSTA_HD_CTRL,
+ &data);
+ if (ret_val)
+ goto out;
+ data &= ~(0xF << 8);
+ data |= (0xB << 8);
+ ret_val = e1000e_write_kmrn_reg(hw,
+ E1000_KMRNCTRLSTA_HD_CTRL,
+ data);
+ if (ret_val)
+ goto out;
+
+ /* Write PHY register values back to h/w defaults */
+ e1e_rphy(hw, PHY_REG(769, 20), &data);
+ ret_val = e1e_wphy(hw, PHY_REG(769, 20), data & ~(1 << 14));
+ if (ret_val)
+ goto out;
+ e1e_rphy(hw, PHY_REG(769, 23), &data);
+ data &= ~(0x7F << 5);
+ ret_val = e1e_wphy(hw, PHY_REG(769, 23), data);
+ if (ret_val)
+ goto out;
+ e1e_rphy(hw, PHY_REG(769, 16), &data);
+ data &= ~(1 << 12);
+ data |= (1 << 13);
+ ret_val = e1e_wphy(hw, PHY_REG(769, 16), data);
+ if (ret_val)
+ goto out;
+ e1e_rphy(hw, PHY_REG(776, 20), &data);
+ data &= ~(0x3FF << 2);
+ data |= (0x8 << 2);
+ ret_val = e1e_wphy(hw, PHY_REG(776, 20), data);
+ if (ret_val)
+ goto out;
+ ret_val = e1e_wphy(hw, PHY_REG(776, 23), 0x7E00);
+ if (ret_val)
+ goto out;
+ e1e_rphy(hw, HV_PM_CTRL, &data);
+ ret_val = e1e_wphy(hw, HV_PM_CTRL, data & ~(1 << 10));
+ if (ret_val)
+ goto out;
+ }
+
+ /* re-enable Rx path after enabling/disabling workaround */
+ ret_val = e1e_wphy(hw, PHY_REG(769, 20), phy_reg & ~(1 << 14));
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_lv_phy_workarounds_ich8lan - A series of Phy workarounds to be
+ * done after every PHY reset.
+ **/
+static s32 e1000_lv_phy_workarounds_ich8lan(struct e1000_hw *hw)
+{
+ s32 ret_val = 0;
+
+ if (hw->mac.type != e1000_pch2lan)
+ goto out;
+
+ /* Set MDIO slow mode before any other MDIO access */
+ ret_val = e1000_set_mdio_slow_mode_hv(hw);
+
+out:
+ return ret_val;
+}
+
+/**
* e1000_lan_init_done_ich8lan - Check for PHY config completion
* @hw: pointer to the HW structure
*
@@ -1271,12 +1609,17 @@ static s32 e1000_post_phy_reset_ich8lan(struct e1000_hw *hw)
if (ret_val)
goto out;
break;
+ case e1000_pch2lan:
+ ret_val = e1000_lv_phy_workarounds_ich8lan(hw);
+ if (ret_val)
+ goto out;
+ break;
default:
break;
}
/* Dummy read to clear the phy wakeup bit after lcd reset */
- if (hw->mac.type == e1000_pchlan)
+ if (hw->mac.type >= e1000_pchlan)
e1e_rphy(hw, BM_WUC, &reg);
/* Configure the LCD with the extended configuration region in NVM */
@@ -2800,6 +3143,7 @@ static s32 e1000_setup_link_ich8lan(struct e1000_hw *hw)
ew32(FCTTV, hw->fc.pause_time);
if ((hw->phy.type == e1000_phy_82578) ||
+ (hw->phy.type == e1000_phy_82579) ||
(hw->phy.type == e1000_phy_82577)) {
ew32(FCRTV_PCH, hw->fc.refresh_time);
@@ -2863,6 +3207,7 @@ static s32 e1000_setup_copper_link_ich8lan(struct e1000_hw *hw)
return ret_val;
break;
case e1000_phy_82577:
+ case e1000_phy_82579:
ret_val = e1000_copper_link_setup_82577(hw);
if (ret_val)
return ret_val;
@@ -3116,21 +3461,12 @@ void e1000e_disable_gig_wol_ich8lan(struct e1000_hw *hw)
{
u32 phy_ctrl;
- switch (hw->mac.type) {
- case e1000_ich8lan:
- case e1000_ich9lan:
- case e1000_ich10lan:
- case e1000_pchlan:
- phy_ctrl = er32(PHY_CTRL);
- phy_ctrl |= E1000_PHY_CTRL_D0A_LPLU |
- E1000_PHY_CTRL_GBE_DISABLE;
- ew32(PHY_CTRL, phy_ctrl);
+ phy_ctrl = er32(PHY_CTRL);
+ phy_ctrl |= E1000_PHY_CTRL_D0A_LPLU | E1000_PHY_CTRL_GBE_DISABLE;
+ ew32(PHY_CTRL, phy_ctrl);
- if (hw->mac.type == e1000_pchlan)
- e1000_phy_hw_reset_ich8lan(hw);
- default:
- break;
- }
+ if (hw->mac.type >= e1000_pchlan)
+ e1000_phy_hw_reset_ich8lan(hw);
}
/**
@@ -3370,6 +3706,7 @@ static void e1000_clear_hw_cntrs_ich8lan(struct e1000_hw *hw)
/* Clear PHY statistics registers */
if ((hw->phy.type == e1000_phy_82578) ||
+ (hw->phy.type == e1000_phy_82579) ||
(hw->phy.type == e1000_phy_82577)) {
hw->phy.ops.read_reg(hw, HV_SCC_UPPER, &phy_data);
hw->phy.ops.read_reg(hw, HV_SCC_LOWER, &phy_data);
@@ -3390,7 +3727,7 @@ static void e1000_clear_hw_cntrs_ich8lan(struct e1000_hw *hw)
static struct e1000_mac_operations ich8_mac_ops = {
.id_led_init = e1000e_id_led_init,
- .check_mng_mode = e1000_check_mng_mode_ich8lan,
+ /* check_mng_mode dependent on mac type */
.check_for_link = e1000_check_for_copper_link_ich8lan,
/* cleanup_led dependent on mac type */
.clear_hw_cntrs = e1000_clear_hw_cntrs_ich8lan,
@@ -3497,6 +3834,7 @@ struct e1000_info e1000_pch_info = {
| FLAG_HAS_JUMBO_FRAMES
| FLAG_DISABLE_FC_PAUSE_TIME /* errata */
| FLAG_APME_IN_WUC,
+ .flags2 = FLAG2_HAS_PHY_STATS,
.pba = 26,
.max_hw_frame_size = 4096,
.get_variants = e1000_get_variants_ich8lan,
@@ -3504,3 +3842,23 @@ struct e1000_info e1000_pch_info = {
.phy_ops = &ich8_phy_ops,
.nvm_ops = &ich8_nvm_ops,
};
+
+struct e1000_info e1000_pch2_info = {
+ .mac = e1000_pch2lan,
+ .flags = FLAG_IS_ICH
+ | FLAG_HAS_WOL
+ | FLAG_RX_CSUM_ENABLED
+ | FLAG_HAS_CTRLEXT_ON_LOAD
+ | FLAG_HAS_AMT
+ | FLAG_HAS_FLASH
+ | FLAG_HAS_JUMBO_FRAMES
+ | FLAG_APME_IN_WUC,
+ .flags2 = FLAG2_HAS_PHY_STATS
+ | FLAG2_HAS_EEE,
+ .pba = 18,
+ .max_hw_frame_size = DEFAULT_JUMBO,
+ .get_variants = e1000_get_variants_ich8lan,
+ .mac_ops = &ich8_mac_ops,
+ .phy_ops = &ich8_phy_ops,
+ .nvm_ops = &ich8_nvm_ops,
+};
diff --git a/drivers/net/e1000e/lib.c b/drivers/net/e1000e/lib.c
index a968e3a416a..df4a2792293 100644
--- a/drivers/net/e1000e/lib.c
+++ b/drivers/net/e1000e/lib.c
@@ -1,7 +1,7 @@
/*******************************************************************************
Intel PRO/1000 Linux driver
- Copyright(c) 1999 - 2009 Intel Corporation.
+ Copyright(c) 1999 - 2010 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,
diff --git a/drivers/net/e1000e/netdev.c b/drivers/net/e1000e/netdev.c
index 57a7e41da69..521c6ee1f32 100644
--- a/drivers/net/e1000e/netdev.c
+++ b/drivers/net/e1000e/netdev.c
@@ -1,7 +1,7 @@
/*******************************************************************************
Intel PRO/1000 Linux driver
- Copyright(c) 1999 - 2009 Intel Corporation.
+ Copyright(c) 1999 - 2010 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,
@@ -52,7 +52,9 @@
#include "e1000.h"
-#define DRV_VERSION "1.0.2-k4"
+#define DRV_EXTRAVERSION "-k2"
+
+#define DRV_VERSION "1.2.7" DRV_EXTRAVERSION
char e1000e_driver_name[] = "e1000e";
const char e1000e_driver_version[] = DRV_VERSION;
@@ -67,6 +69,7 @@ static const struct e1000_info *e1000_info_tbl[] = {
[board_ich9lan] = &e1000_ich9_info,
[board_ich10lan] = &e1000_ich10_info,
[board_pchlan] = &e1000_pch_info,
+ [board_pch2lan] = &e1000_pch2_info,
};
struct e1000_reg_info {
@@ -221,10 +224,10 @@ static void e1000e_dump(struct e1000_adapter *adapter)
buffer_info = &tx_ring->buffer_info[tx_ring->next_to_clean];
printk(KERN_INFO " %5d %5X %5X %016llX %04X %3X %016llX\n",
0, tx_ring->next_to_use, tx_ring->next_to_clean,
- (u64)buffer_info->dma,
+ (unsigned long long)buffer_info->dma,
buffer_info->length,
buffer_info->next_to_watch,
- (u64)buffer_info->time_stamp);
+ (unsigned long long)buffer_info->time_stamp);
/* Print TX Rings */
if (!netif_msg_tx_done(adapter))
@@ -276,9 +279,11 @@ static void e1000e_dump(struct e1000_adapter *adapter)
"%04X %3X %016llX %p",
(!(le64_to_cpu(u0->b) & (1<<29)) ? 'l' :
((le64_to_cpu(u0->b) & (1<<20)) ? 'd' : 'c')), i,
- le64_to_cpu(u0->a), le64_to_cpu(u0->b),
- (u64)buffer_info->dma, buffer_info->length,
- buffer_info->next_to_watch, (u64)buffer_info->time_stamp,
+ (unsigned long long)le64_to_cpu(u0->a),
+ (unsigned long long)le64_to_cpu(u0->b),
+ (unsigned long long)buffer_info->dma,
+ buffer_info->length, buffer_info->next_to_watch,
+ (unsigned long long)buffer_info->time_stamp,
buffer_info->skb);
if (i == tx_ring->next_to_use && i == tx_ring->next_to_clean)
printk(KERN_CONT " NTC/U\n");
@@ -353,19 +358,19 @@ rx_ring_summary:
printk(KERN_INFO "RWB[0x%03X] %016llX "
"%016llX %016llX %016llX "
"---------------- %p", i,
- le64_to_cpu(u1->a),
- le64_to_cpu(u1->b),
- le64_to_cpu(u1->c),
- le64_to_cpu(u1->d),
+ (unsigned long long)le64_to_cpu(u1->a),
+ (unsigned long long)le64_to_cpu(u1->b),
+ (unsigned long long)le64_to_cpu(u1->c),
+ (unsigned long long)le64_to_cpu(u1->d),
buffer_info->skb);
} else {
printk(KERN_INFO "R [0x%03X] %016llX "
"%016llX %016llX %016llX %016llX %p", i,
- le64_to_cpu(u1->a),
- le64_to_cpu(u1->b),
- le64_to_cpu(u1->c),
- le64_to_cpu(u1->d),
- (u64)buffer_info->dma,
+ (unsigned long long)le64_to_cpu(u1->a),
+ (unsigned long long)le64_to_cpu(u1->b),
+ (unsigned long long)le64_to_cpu(u1->c),
+ (unsigned long long)le64_to_cpu(u1->d),
+ (unsigned long long)buffer_info->dma,
buffer_info->skb);
if (netif_msg_pktdata(adapter))
@@ -402,9 +407,11 @@ rx_ring_summary:
buffer_info = &rx_ring->buffer_info[i];
u0 = (struct my_u0 *)rx_desc;
printk(KERN_INFO "Rl[0x%03X] %016llX %016llX "
- "%016llX %p",
- i, le64_to_cpu(u0->a), le64_to_cpu(u0->b),
- (u64)buffer_info->dma, buffer_info->skb);
+ "%016llX %p", i,
+ (unsigned long long)le64_to_cpu(u0->a),
+ (unsigned long long)le64_to_cpu(u0->b),
+ (unsigned long long)buffer_info->dma,
+ buffer_info->skb);
if (i == rx_ring->next_to_use)
printk(KERN_CONT " NTU\n");
else if (i == rx_ring->next_to_clean)
@@ -1778,25 +1785,25 @@ void e1000e_reset_interrupt_capability(struct e1000_adapter *adapter)
void e1000e_set_interrupt_capability(struct e1000_adapter *adapter)
{
int err;
- int numvecs, i;
-
+ int i;
switch (adapter->int_mode) {
case E1000E_INT_MODE_MSIX:
if (adapter->flags & FLAG_HAS_MSIX) {
- numvecs = 3; /* RxQ0, TxQ0 and other */
- adapter->msix_entries = kcalloc(numvecs,
+ adapter->num_vectors = 3; /* RxQ0, TxQ0 and other */
+ adapter->msix_entries = kcalloc(adapter->num_vectors,
sizeof(struct msix_entry),
GFP_KERNEL);
if (adapter->msix_entries) {
- for (i = 0; i < numvecs; i++)
+ for (i = 0; i < adapter->num_vectors; i++)
adapter->msix_entries[i].entry = i;
err = pci_enable_msix(adapter->pdev,
adapter->msix_entries,
- numvecs);
- if (err == 0)
+ adapter->num_vectors);
+ if (err == 0) {
return;
+ }
}
/* MSI-X failed, so fall through and try MSI */
e_err("Failed to initialize MSI-X interrupts. "
@@ -1818,6 +1825,9 @@ void e1000e_set_interrupt_capability(struct e1000_adapter *adapter)
/* Don't do anything; this is the system default */
break;
}
+
+ /* store the number of vectors being used */
+ adapter->num_vectors = 1;
}
/**
@@ -1939,7 +1949,14 @@ static void e1000_irq_disable(struct e1000_adapter *adapter)
if (adapter->msix_entries)
ew32(EIAC_82574, 0);
e1e_flush();
- synchronize_irq(adapter->pdev->irq);
+
+ if (adapter->msix_entries) {
+ int i;
+ for (i = 0; i < adapter->num_vectors; i++)
+ synchronize_irq(adapter->msix_entries[i].vector);
+ } else {
+ synchronize_irq(adapter->pdev->irq);
+ }
}
/**
@@ -2723,6 +2740,16 @@ static void e1000_setup_rctl(struct e1000_adapter *adapter)
e1e_wphy(hw, 22, phy_data);
}
+ /* Workaround Si errata on 82579 - configure jumbo frame flow */
+ if (hw->mac.type == e1000_pch2lan) {
+ s32 ret_val;
+
+ if (rctl & E1000_RCTL_LPE)
+ ret_val = e1000_lv_jumbo_workaround_ich8lan(hw, true);
+ else
+ ret_val = e1000_lv_jumbo_workaround_ich8lan(hw, false);
+ }
+
/* Setup buffer sizes */
rctl &= ~E1000_RCTL_SZ_4096;
rctl |= E1000_RCTL_BSEX;
@@ -2759,7 +2786,7 @@ static void e1000_setup_rctl(struct e1000_adapter *adapter)
* per packet.
*/
pages = PAGE_USE_COUNT(adapter->netdev->mtu);
- if (!(adapter->flags & FLAG_IS_ICH) && (pages <= 3) &&
+ if (!(adapter->flags & FLAG_HAS_ERT) && (pages <= 3) &&
(PAGE_SIZE <= 16384) && (rctl & E1000_RCTL_LPE))
adapter->rx_ps_pages = pages;
else
@@ -2901,10 +2928,10 @@ static void e1000_configure_rx(struct e1000_adapter *adapter)
* dropped transactions.
*/
pm_qos_update_request(
- adapter->netdev->pm_qos_req, 55);
+ &adapter->netdev->pm_qos_req, 55);
} else {
pm_qos_update_request(
- adapter->netdev->pm_qos_req,
+ &adapter->netdev->pm_qos_req,
PM_QOS_DEFAULT_VALUE);
}
}
@@ -3118,7 +3145,27 @@ void e1000e_reset(struct e1000_adapter *adapter)
* with ERT support assuming ERT set to E1000_ERT_2048), or
* - the full Rx FIFO size minus one full frame
*/
- if (hw->mac.type == e1000_pchlan) {
+ if (adapter->flags & FLAG_DISABLE_FC_PAUSE_TIME)
+ fc->pause_time = 0xFFFF;
+ else
+ fc->pause_time = E1000_FC_PAUSE_TIME;
+ fc->send_xon = 1;
+ fc->current_mode = fc->requested_mode;
+
+ switch (hw->mac.type) {
+ default:
+ if ((adapter->flags & FLAG_HAS_ERT) &&
+ (adapter->netdev->mtu > ETH_DATA_LEN))
+ hwm = min(((pba << 10) * 9 / 10),
+ ((pba << 10) - (E1000_ERT_2048 << 3)));
+ else
+ hwm = min(((pba << 10) * 9 / 10),
+ ((pba << 10) - adapter->max_frame_size));
+
+ fc->high_water = hwm & E1000_FCRTH_RTH; /* 8-byte granularity */
+ fc->low_water = fc->high_water - 8;
+ break;
+ case e1000_pchlan:
/*
* Workaround PCH LOM adapter hangs with certain network
* loads. If hangs persist, try disabling Tx flow control.
@@ -3131,26 +3178,15 @@ void e1000e_reset(struct e1000_adapter *adapter)
fc->low_water = 0x3000;
}
fc->refresh_time = 0x1000;
- } else {
- if ((adapter->flags & FLAG_HAS_ERT) &&
- (adapter->netdev->mtu > ETH_DATA_LEN))
- hwm = min(((pba << 10) * 9 / 10),
- ((pba << 10) - (E1000_ERT_2048 << 3)));
- else
- hwm = min(((pba << 10) * 9 / 10),
- ((pba << 10) - adapter->max_frame_size));
-
- fc->high_water = hwm & E1000_FCRTH_RTH; /* 8-byte granularity */
- fc->low_water = fc->high_water - 8;
+ break;
+ case e1000_pch2lan:
+ fc->high_water = 0x05C20;
+ fc->low_water = 0x05048;
+ fc->pause_time = 0x0650;
+ fc->refresh_time = 0x0400;
+ break;
}
- if (adapter->flags & FLAG_DISABLE_FC_PAUSE_TIME)
- fc->pause_time = 0xFFFF;
- else
- fc->pause_time = E1000_FC_PAUSE_TIME;
- fc->send_xon = 1;
- fc->current_mode = fc->requested_mode;
-
/* Allow time for pending master requests to run */
mac->ops.reset_hw(hw);
@@ -3162,8 +3198,6 @@ void e1000e_reset(struct e1000_adapter *adapter)
e1000_get_hw_control(adapter);
ew32(WUC, 0);
- if (adapter->flags2 & FLAG2_HAS_PHY_WAKEUP)
- e1e_wphy(&adapter->hw, BM_WUC, 0);
if (mac->ops.init_hw(hw))
e_err("Hardware Error\n");
@@ -3194,12 +3228,6 @@ int e1000e_up(struct e1000_adapter *adapter)
{
struct e1000_hw *hw = &adapter->hw;
- /* DMA latency requirement to workaround early-receive/jumbo issue */
- if (adapter->flags & FLAG_HAS_ERT)
- adapter->netdev->pm_qos_req =
- pm_qos_add_request(PM_QOS_CPU_DMA_LATENCY,
- PM_QOS_DEFAULT_VALUE);
-
/* hardware has been reset, we need to reload some things */
e1000_configure(adapter);
@@ -3263,12 +3291,6 @@ void e1000e_down(struct e1000_adapter *adapter)
e1000_clean_tx_ring(adapter);
e1000_clean_rx_ring(adapter);
- if (adapter->flags & FLAG_HAS_ERT) {
- pm_qos_remove_request(
- adapter->netdev->pm_qos_req);
- adapter->netdev->pm_qos_req = NULL;
- }
-
/*
* TODO: for power management, we could drop the link and
* pci_disable_device here.
@@ -3419,13 +3441,18 @@ static int e1000_test_msi(struct e1000_adapter *adapter)
/* disable SERR in case the MSI write causes a master abort */
pci_read_config_word(adapter->pdev, PCI_COMMAND, &pci_cmd);
- pci_write_config_word(adapter->pdev, PCI_COMMAND,
- pci_cmd & ~PCI_COMMAND_SERR);
+ if (pci_cmd & PCI_COMMAND_SERR)
+ pci_write_config_word(adapter->pdev, PCI_COMMAND,
+ pci_cmd & ~PCI_COMMAND_SERR);
err = e1000_test_msi_interrupt(adapter);
- /* restore previous setting of command word */
- pci_write_config_word(adapter->pdev, PCI_COMMAND, pci_cmd);
+ /* re-enable SERR */
+ if (pci_cmd & PCI_COMMAND_SERR) {
+ pci_read_config_word(adapter->pdev, PCI_COMMAND, &pci_cmd);
+ pci_cmd |= PCI_COMMAND_SERR;
+ pci_write_config_word(adapter->pdev, PCI_COMMAND, pci_cmd);
+ }
/* success ! */
if (!err)
@@ -3498,6 +3525,12 @@ static int e1000_open(struct net_device *netdev)
E1000_MNG_DHCP_COOKIE_STATUS_VLAN))
e1000_update_mng_vlan(adapter);
+ /* DMA latency requirement to workaround early-receive/jumbo issue */
+ if (adapter->flags & FLAG_HAS_ERT)
+ pm_qos_add_request(&adapter->netdev->pm_qos_req,
+ PM_QOS_CPU_DMA_LATENCY,
+ PM_QOS_DEFAULT_VALUE);
+
/*
* before we allocate an interrupt, we must be ready to handle it.
* Setting DEBUG_SHIRQ in the kernel makes it fire an interrupt
@@ -3602,6 +3635,9 @@ static int e1000_close(struct net_device *netdev)
if (adapter->flags & FLAG_HAS_AMT)
e1000_release_hw_control(adapter);
+ if (adapter->flags & FLAG_HAS_ERT)
+ pm_qos_remove_request(&adapter->netdev->pm_qos_req);
+
pm_runtime_put_sync(&pdev->dev);
return 0;
@@ -3672,6 +3708,110 @@ static void e1000_update_phy_info(unsigned long data)
}
/**
+ * e1000e_update_phy_stats - Update the PHY statistics counters
+ * @adapter: board private structure
+ **/
+static void e1000e_update_phy_stats(struct e1000_adapter *adapter)
+{
+ struct e1000_hw *hw = &adapter->hw;
+ s32 ret_val;
+ u16 phy_data;
+
+ ret_val = hw->phy.ops.acquire(hw);
+ if (ret_val)
+ return;
+
+ hw->phy.addr = 1;
+
+#define HV_PHY_STATS_PAGE 778
+ /*
+ * A page set is expensive so check if already on desired page.
+ * If not, set to the page with the PHY status registers.
+ */
+ ret_val = e1000e_read_phy_reg_mdic(hw, IGP01E1000_PHY_PAGE_SELECT,
+ &phy_data);
+ if (ret_val)
+ goto release;
+ if (phy_data != (HV_PHY_STATS_PAGE << IGP_PAGE_SHIFT)) {
+ ret_val = e1000e_write_phy_reg_mdic(hw,
+ IGP01E1000_PHY_PAGE_SELECT,
+ (HV_PHY_STATS_PAGE <<
+ IGP_PAGE_SHIFT));
+ if (ret_val)
+ goto release;
+ }
+
+ /* Read/clear the upper 16-bit registers and read/accumulate lower */
+
+ /* Single Collision Count */
+ e1000e_read_phy_reg_mdic(hw, HV_SCC_UPPER & MAX_PHY_REG_ADDRESS,
+ &phy_data);
+ ret_val = e1000e_read_phy_reg_mdic(hw,
+ HV_SCC_LOWER & MAX_PHY_REG_ADDRESS,
+ &phy_data);
+ if (!ret_val)
+ adapter->stats.scc += phy_data;
+
+ /* Excessive Collision Count */
+ e1000e_read_phy_reg_mdic(hw, HV_ECOL_UPPER & MAX_PHY_REG_ADDRESS,
+ &phy_data);
+ ret_val = e1000e_read_phy_reg_mdic(hw,
+ HV_ECOL_LOWER & MAX_PHY_REG_ADDRESS,
+ &phy_data);
+ if (!ret_val)
+ adapter->stats.ecol += phy_data;
+
+ /* Multiple Collision Count */
+ e1000e_read_phy_reg_mdic(hw, HV_MCC_UPPER & MAX_PHY_REG_ADDRESS,
+ &phy_data);
+ ret_val = e1000e_read_phy_reg_mdic(hw,
+ HV_MCC_LOWER & MAX_PHY_REG_ADDRESS,
+ &phy_data);
+ if (!ret_val)
+ adapter->stats.mcc += phy_data;
+
+ /* Late Collision Count */
+ e1000e_read_phy_reg_mdic(hw, HV_LATECOL_UPPER & MAX_PHY_REG_ADDRESS,
+ &phy_data);
+ ret_val = e1000e_read_phy_reg_mdic(hw,
+ HV_LATECOL_LOWER &
+ MAX_PHY_REG_ADDRESS,
+ &phy_data);
+ if (!ret_val)
+ adapter->stats.latecol += phy_data;
+
+ /* Collision Count - also used for adaptive IFS */
+ e1000e_read_phy_reg_mdic(hw, HV_COLC_UPPER & MAX_PHY_REG_ADDRESS,
+ &phy_data);
+ ret_val = e1000e_read_phy_reg_mdic(hw,
+ HV_COLC_LOWER & MAX_PHY_REG_ADDRESS,
+ &phy_data);
+ if (!ret_val)
+ hw->mac.collision_delta = phy_data;
+
+ /* Defer Count */
+ e1000e_read_phy_reg_mdic(hw, HV_DC_UPPER & MAX_PHY_REG_ADDRESS,
+ &phy_data);
+ ret_val = e1000e_read_phy_reg_mdic(hw,
+ HV_DC_LOWER & MAX_PHY_REG_ADDRESS,
+ &phy_data);
+ if (!ret_val)
+ adapter->stats.dc += phy_data;
+
+ /* Transmit with no CRS */
+ e1000e_read_phy_reg_mdic(hw, HV_TNCRS_UPPER & MAX_PHY_REG_ADDRESS,
+ &phy_data);
+ ret_val = e1000e_read_phy_reg_mdic(hw,
+ HV_TNCRS_LOWER & MAX_PHY_REG_ADDRESS,
+ &phy_data);
+ if (!ret_val)
+ adapter->stats.tncrs += phy_data;
+
+release:
+ hw->phy.ops.release(hw);
+}
+
+/**
* e1000e_update_stats - Update the board statistics counters
* @adapter: board private structure
**/
@@ -3680,7 +3820,6 @@ void e1000e_update_stats(struct e1000_adapter *adapter)
struct net_device *netdev = adapter->netdev;
struct e1000_hw *hw = &adapter->hw;
struct pci_dev *pdev = adapter->pdev;
- u16 phy_data;
/*
* Prevent stats update while adapter is being reset, or if the pci
@@ -3700,34 +3839,27 @@ void e1000e_update_stats(struct e1000_adapter *adapter)
adapter->stats.roc += er32(ROC);
adapter->stats.mpc += er32(MPC);
- if ((hw->phy.type == e1000_phy_82578) ||
- (hw->phy.type == e1000_phy_82577)) {
- e1e_rphy(hw, HV_SCC_UPPER, &phy_data);
- if (!e1e_rphy(hw, HV_SCC_LOWER, &phy_data))
- adapter->stats.scc += phy_data;
-
- e1e_rphy(hw, HV_ECOL_UPPER, &phy_data);
- if (!e1e_rphy(hw, HV_ECOL_LOWER, &phy_data))
- adapter->stats.ecol += phy_data;
-
- e1e_rphy(hw, HV_MCC_UPPER, &phy_data);
- if (!e1e_rphy(hw, HV_MCC_LOWER, &phy_data))
- adapter->stats.mcc += phy_data;
-
- e1e_rphy(hw, HV_LATECOL_UPPER, &phy_data);
- if (!e1e_rphy(hw, HV_LATECOL_LOWER, &phy_data))
- adapter->stats.latecol += phy_data;
-
- e1e_rphy(hw, HV_DC_UPPER, &phy_data);
- if (!e1e_rphy(hw, HV_DC_LOWER, &phy_data))
- adapter->stats.dc += phy_data;
- } else {
- adapter->stats.scc += er32(SCC);
- adapter->stats.ecol += er32(ECOL);
- adapter->stats.mcc += er32(MCC);
- adapter->stats.latecol += er32(LATECOL);
- adapter->stats.dc += er32(DC);
+
+ /* Half-duplex statistics */
+ if (adapter->link_duplex == HALF_DUPLEX) {
+ if (adapter->flags2 & FLAG2_HAS_PHY_STATS) {
+ e1000e_update_phy_stats(adapter);
+ } else {
+ adapter->stats.scc += er32(SCC);
+ adapter->stats.ecol += er32(ECOL);
+ adapter->stats.mcc += er32(MCC);
+ adapter->stats.latecol += er32(LATECOL);
+ adapter->stats.dc += er32(DC);
+
+ hw->mac.collision_delta = er32(COLC);
+
+ if ((hw->mac.type != e1000_82574) &&
+ (hw->mac.type != e1000_82583))
+ adapter->stats.tncrs += er32(TNCRS);
+ }
+ adapter->stats.colc += hw->mac.collision_delta;
}
+
adapter->stats.xonrxc += er32(XONRXC);
adapter->stats.xontxc += er32(XONTXC);
adapter->stats.xoffrxc += er32(XOFFRXC);
@@ -3745,28 +3877,9 @@ void e1000e_update_stats(struct e1000_adapter *adapter)
hw->mac.tx_packet_delta = er32(TPT);
adapter->stats.tpt += hw->mac.tx_packet_delta;
- if ((hw->phy.type == e1000_phy_82578) ||
- (hw->phy.type == e1000_phy_82577)) {
- e1e_rphy(hw, HV_COLC_UPPER, &phy_data);
- if (!e1e_rphy(hw, HV_COLC_LOWER, &phy_data))
- hw->mac.collision_delta = phy_data;
- } else {
- hw->mac.collision_delta = er32(COLC);
- }
- adapter->stats.colc += hw->mac.collision_delta;
adapter->stats.algnerrc += er32(ALGNERRC);
adapter->stats.rxerrc += er32(RXERRC);
- if ((hw->phy.type == e1000_phy_82578) ||
- (hw->phy.type == e1000_phy_82577)) {
- e1e_rphy(hw, HV_TNCRS_UPPER, &phy_data);
- if (!e1e_rphy(hw, HV_TNCRS_LOWER, &phy_data))
- adapter->stats.tncrs += phy_data;
- } else {
- if ((hw->mac.type != e1000_82574) &&
- (hw->mac.type != e1000_82583))
- adapter->stats.tncrs += er32(TNCRS);
- }
adapter->stats.cexterr += er32(CEXTERR);
adapter->stats.tsctc += er32(TSCTC);
adapter->stats.tsctfc += er32(TSCTFC);
@@ -3865,7 +3978,7 @@ static void e1000_print_link_info(struct e1000_adapter *adapter)
((ctrl & E1000_CTRL_TFCE) ? "TX" : "None" )));
}
-bool e1000e_has_link(struct e1000_adapter *adapter)
+static bool e1000e_has_link(struct e1000_adapter *adapter)
{
struct e1000_hw *hw = &adapter->hw;
bool link_active = 0;
@@ -4841,14 +4954,7 @@ static int e1000_init_phy_wakeup(struct e1000_adapter *adapter, u32 wufc)
int retval = 0;
/* copy MAC RARs to PHY RARs */
- for (i = 0; i < adapter->hw.mac.rar_entry_count; i++) {
- mac_reg = er32(RAL(i));
- e1e_wphy(hw, BM_RAR_L(i), (u16)(mac_reg & 0xFFFF));
- e1e_wphy(hw, BM_RAR_M(i), (u16)((mac_reg >> 16) & 0xFFFF));
- mac_reg = er32(RAH(i));
- e1e_wphy(hw, BM_RAR_H(i), (u16)(mac_reg & 0xFFFF));
- e1e_wphy(hw, BM_RAR_CTRL(i), (u16)((mac_reg >> 16) & 0xFFFF));
- }
+ e1000_copy_rx_addrs_to_phy_ich8lan(hw);
/* copy MAC MTA to PHY MTA */
for (i = 0; i < adapter->hw.mac.mta_reg_count; i++) {
@@ -5551,8 +5657,6 @@ static int __devinit e1000_probe(struct pci_dev *pdev,
if (err)
goto err_sw_init;
- err = -EIO;
-
memcpy(&hw->mac.ops, ei->mac_ops, sizeof(hw->mac.ops));
memcpy(&hw->nvm.ops, ei->nvm_ops, sizeof(hw->nvm.ops));
memcpy(&hw->phy.ops, ei->phy_ops, sizeof(hw->phy.ops));
@@ -5721,11 +5825,8 @@ static int __devinit e1000_probe(struct pci_dev *pdev,
e1000_print_device_info(adapter);
- if (pci_dev_run_wake(pdev)) {
- pm_runtime_set_active(&pdev->dev);
- pm_runtime_enable(&pdev->dev);
- }
- pm_schedule_suspend(&pdev->dev, MSEC_PER_SEC);
+ if (pci_dev_run_wake(pdev))
+ pm_runtime_put_noidle(&pdev->dev);
return 0;
@@ -5771,8 +5872,6 @@ static void __devexit e1000_remove(struct pci_dev *pdev)
struct e1000_adapter *adapter = netdev_priv(netdev);
bool down = test_bit(__E1000_DOWN, &adapter->state);
- pm_runtime_get_sync(&pdev->dev);
-
/*
* flush_scheduled work may reschedule our watchdog task, so
* explicitly disable watchdog tasks from being rescheduled
@@ -5797,11 +5896,8 @@ static void __devexit e1000_remove(struct pci_dev *pdev)
clear_bit(__E1000_DOWN, &adapter->state);
unregister_netdev(netdev);
- if (pci_dev_run_wake(pdev)) {
- pm_runtime_disable(&pdev->dev);
- pm_runtime_set_suspended(&pdev->dev);
- }
- pm_runtime_put_noidle(&pdev->dev);
+ if (pci_dev_run_wake(pdev))
+ pm_runtime_get_noresume(&pdev->dev);
/*
* Release control of h/w to f/w. If f/w is AMT enabled, this
@@ -5899,6 +5995,9 @@ static DEFINE_PCI_DEVICE_TABLE(e1000_pci_tbl) = {
{ PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_D_HV_DM), board_pchlan },
{ PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_D_HV_DC), board_pchlan },
+ { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH2_LV_LM), board_pch2lan },
+ { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH2_LV_V), board_pch2lan },
+
{ } /* terminate list */
};
MODULE_DEVICE_TABLE(pci, e1000_pci_tbl);
@@ -5935,7 +6034,7 @@ static int __init e1000_init_module(void)
int ret;
pr_info("Intel(R) PRO/1000 Network Driver - %s\n",
e1000e_driver_version);
- pr_info("Copyright (c) 1999 - 2009 Intel Corporation.\n");
+ pr_info("Copyright (c) 1999 - 2010 Intel Corporation.\n");
ret = pci_register_driver(&e1000_driver);
return ret;
diff --git a/drivers/net/e1000e/param.c b/drivers/net/e1000e/param.c
index a150e48a117..34aeec13bb1 100644
--- a/drivers/net/e1000e/param.c
+++ b/drivers/net/e1000e/param.c
@@ -1,7 +1,7 @@
/*******************************************************************************
Intel PRO/1000 Linux driver
- Copyright(c) 1999 - 2009 Intel Corporation.
+ Copyright(c) 1999 - 2010 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,
diff --git a/drivers/net/e1000e/phy.c b/drivers/net/e1000e/phy.c
index b4ac82d51b2..3d3dc0c8235 100644
--- a/drivers/net/e1000e/phy.c
+++ b/drivers/net/e1000e/phy.c
@@ -1,7 +1,7 @@
/*******************************************************************************
Intel PRO/1000 Linux driver
- Copyright(c) 1999 - 2009 Intel Corporation.
+ Copyright(c) 1999 - 2010 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,
@@ -2319,6 +2319,9 @@ enum e1000_phy_type e1000e_get_phy_type_from_id(u32 phy_id)
case I82577_E_PHY_ID:
phy_type = e1000_phy_82577;
break;
+ case I82579_E_PHY_ID:
+ phy_type = e1000_phy_82579;
+ break;
default:
phy_type = e1000_phy_unknown;
break;
diff --git a/drivers/net/ehea/ehea_main.c b/drivers/net/ehea/ehea_main.c
index 8b92acb448c..3beba70b7de 100644
--- a/drivers/net/ehea/ehea_main.c
+++ b/drivers/net/ehea/ehea_main.c
@@ -335,7 +335,7 @@ static struct net_device_stats *ehea_get_stats(struct net_device *dev)
memset(stats, 0, sizeof(*stats));
- cb2 = (void *)get_zeroed_page(GFP_ATOMIC);
+ cb2 = (void *)get_zeroed_page(GFP_KERNEL);
if (!cb2) {
ehea_error("no mem for cb2");
goto out;
diff --git a/drivers/net/ehea/ehea_qmr.h b/drivers/net/ehea/ehea_qmr.h
index 882c50c9c34..f608a6c54af 100644
--- a/drivers/net/ehea/ehea_qmr.h
+++ b/drivers/net/ehea/ehea_qmr.h
@@ -126,7 +126,7 @@ struct ehea_swqe {
u8 immediate_data[SWQE2_MAX_IMM];
/* 0xd0 */
struct ehea_vsgentry sg_list[EHEA_MAX_WQE_SG_ENTRIES-1];
- } immdata_desc __attribute__ ((packed));
+ } immdata_desc __packed;
/* Send WQE Format 3 */
struct {
diff --git a/drivers/net/enic/cq_desc.h b/drivers/net/enic/cq_desc.h
index 1eb289f773b..d6dd1b4edf6 100644
--- a/drivers/net/enic/cq_desc.h
+++ b/drivers/net/enic/cq_desc.h
@@ -1,5 +1,5 @@
/*
- * Copyright 2008 Cisco Systems, Inc. All rights reserved.
+ * Copyright 2008-2010 Cisco Systems, Inc. All rights reserved.
* Copyright 2007 Nuova Systems, Inc. All rights reserved.
*
* This program is free software; you may redistribute it and/or modify
diff --git a/drivers/net/enic/cq_enet_desc.h b/drivers/net/enic/cq_enet_desc.h
index 337d1943af4..c2c0680a114 100644
--- a/drivers/net/enic/cq_enet_desc.h
+++ b/drivers/net/enic/cq_enet_desc.h
@@ -1,5 +1,5 @@
/*
- * Copyright 2008 Cisco Systems, Inc. All rights reserved.
+ * Copyright 2008-2010 Cisco Systems, Inc. All rights reserved.
* Copyright 2007 Nuova Systems, Inc. All rights reserved.
*
* This program is free software; you may redistribute it and/or modify
@@ -73,7 +73,16 @@ struct cq_enet_rq_desc {
#define CQ_ENET_RQ_DESC_FLAGS_TRUNCATED (0x1 << 14)
#define CQ_ENET_RQ_DESC_FLAGS_VLAN_STRIPPED (0x1 << 15)
-#define CQ_ENET_RQ_DESC_FCOE_SOF_BITS 4
+#define CQ_ENET_RQ_DESC_VLAN_TCI_VLAN_BITS 12
+#define CQ_ENET_RQ_DESC_VLAN_TCI_VLAN_MASK \
+ ((1 << CQ_ENET_RQ_DESC_VLAN_TCI_VLAN_BITS) - 1)
+#define CQ_ENET_RQ_DESC_VLAN_TCI_CFI_MASK (0x1 << 12)
+#define CQ_ENET_RQ_DESC_VLAN_TCI_USER_PRIO_BITS 3
+#define CQ_ENET_RQ_DESC_VLAN_TCI_USER_PRIO_MASK \
+ ((1 << CQ_ENET_RQ_DESC_VLAN_TCI_USER_PRIO_BITS) - 1)
+#define CQ_ENET_RQ_DESC_VLAN_TCI_USER_PRIO_SHIFT 13
+
+#define CQ_ENET_RQ_DESC_FCOE_SOF_BITS 8
#define CQ_ENET_RQ_DESC_FCOE_SOF_MASK \
((1 << CQ_ENET_RQ_DESC_FCOE_SOF_BITS) - 1)
#define CQ_ENET_RQ_DESC_FCOE_EOF_BITS 8
@@ -96,7 +105,7 @@ static inline void cq_enet_rq_desc_dec(struct cq_enet_rq_desc *desc,
u8 *type, u8 *color, u16 *q_number, u16 *completed_index,
u8 *ingress_port, u8 *fcoe, u8 *eop, u8 *sop, u8 *rss_type,
u8 *csum_not_calc, u32 *rss_hash, u16 *bytes_written, u8 *packet_error,
- u8 *vlan_stripped, u16 *vlan, u16 *checksum, u8 *fcoe_sof,
+ u8 *vlan_stripped, u16 *vlan_tci, u16 *checksum, u8 *fcoe_sof,
u8 *fcoe_fc_crc_ok, u8 *fcoe_enc_error, u8 *fcoe_eof,
u8 *tcp_udp_csum_ok, u8 *udp, u8 *tcp, u8 *ipv4_csum_ok,
u8 *ipv6, u8 *ipv4, u8 *ipv4_fragment, u8 *fcs_ok)
@@ -136,7 +145,10 @@ static inline void cq_enet_rq_desc_dec(struct cq_enet_rq_desc *desc,
*vlan_stripped = (bytes_written_flags &
CQ_ENET_RQ_DESC_FLAGS_VLAN_STRIPPED) ? 1 : 0;
- *vlan = le16_to_cpu(desc->vlan);
+ /*
+ * Tag Control Information(16) = user_priority(3) + cfi(1) + vlan(12)
+ */
+ *vlan_tci = le16_to_cpu(desc->vlan);
if (*fcoe) {
*fcoe_sof = (u8)(le16_to_cpu(desc->checksum_fcoe) &
diff --git a/drivers/net/enic/enic.h b/drivers/net/enic/enic.h
index 45e86d1e5b1..f239aa8c6f4 100644
--- a/drivers/net/enic/enic.h
+++ b/drivers/net/enic/enic.h
@@ -1,5 +1,5 @@
/*
- * Copyright 2008 Cisco Systems, Inc. All rights reserved.
+ * Copyright 2008-2010 Cisco Systems, Inc. All rights reserved.
* Copyright 2007 Nuova Systems, Inc. All rights reserved.
*
* This program is free software; you may redistribute it and/or modify
@@ -20,8 +20,6 @@
#ifndef _ENIC_H_
#define _ENIC_H_
-#include <linux/inet_lro.h>
-
#include "vnic_enet.h"
#include "vnic_dev.h"
#include "vnic_wq.h"
@@ -34,12 +32,8 @@
#define DRV_NAME "enic"
#define DRV_DESCRIPTION "Cisco VIC Ethernet NIC Driver"
-#define DRV_VERSION "1.3.1.1-pp"
-#define DRV_COPYRIGHT "Copyright 2008-2009 Cisco Systems, Inc"
-#define PFX DRV_NAME ": "
-
-#define ENIC_LRO_MAX_DESC 8
-#define ENIC_LRO_MAX_AGGR 64
+#define DRV_VERSION "1.4.1.1"
+#define DRV_COPYRIGHT "Copyright 2008-2010 Cisco Systems, Inc"
#define ENIC_BARS_MAX 6
@@ -116,6 +110,8 @@ struct enic {
spinlock_t wq_lock[ENIC_WQ_MAX];
unsigned int wq_count;
struct vlan_group *vlan_group;
+ u16 loop_enable;
+ u16 loop_tag;
/* receive queue cache line section */
____cacheline_aligned struct vnic_rq rq[ENIC_RQ_MAX];
@@ -124,8 +120,6 @@ struct enic {
u64 rq_truncated_pkts;
u64 rq_bad_fcs;
struct napi_struct napi;
- struct net_lro_mgr lro_mgr;
- struct net_lro_desc lro_desc[ENIC_LRO_MAX_DESC];
/* interrupt resource cache line section */
____cacheline_aligned struct vnic_intr intr[ENIC_INTR_MAX];
@@ -137,4 +131,9 @@ struct enic {
unsigned int cq_count;
};
+static inline struct device *enic_get_dev(struct enic *enic)
+{
+ return &(enic->pdev->dev);
+}
+
#endif /* _ENIC_H_ */
diff --git a/drivers/net/enic/enic_main.c b/drivers/net/enic/enic_main.c
index bc7d6b96de3..77a7f87d498 100644
--- a/drivers/net/enic/enic_main.c
+++ b/drivers/net/enic/enic_main.c
@@ -1,5 +1,5 @@
/*
- * Copyright 2008 Cisco Systems, Inc. All rights reserved.
+ * Copyright 2008-2010 Cisco Systems, Inc. All rights reserved.
* Copyright 2007 Nuova Systems, Inc. All rights reserved.
*
* This program is free software; you may redistribute it and/or modify
@@ -29,12 +29,12 @@
#include <linux/etherdevice.h>
#include <linux/if_ether.h>
#include <linux/if_vlan.h>
-#include <linux/if_link.h>
#include <linux/ethtool.h>
#include <linux/in.h>
#include <linux/ip.h>
#include <linux/ipv6.h>
#include <linux/tcp.h>
+#include <linux/rtnetlink.h>
#include <net/ip6_checksum.h>
#include "cq_enet_desc.h"
@@ -145,15 +145,25 @@ static int enic_get_settings(struct net_device *netdev,
return 0;
}
+static int enic_dev_fw_info(struct enic *enic,
+ struct vnic_devcmd_fw_info **fw_info)
+{
+ int err;
+
+ spin_lock(&enic->devcmd_lock);
+ err = vnic_dev_fw_info(enic->vdev, fw_info);
+ spin_unlock(&enic->devcmd_lock);
+
+ return err;
+}
+
static void enic_get_drvinfo(struct net_device *netdev,
struct ethtool_drvinfo *drvinfo)
{
struct enic *enic = netdev_priv(netdev);
struct vnic_devcmd_fw_info *fw_info;
- spin_lock(&enic->devcmd_lock);
- vnic_dev_fw_info(enic->vdev, &fw_info);
- spin_unlock(&enic->devcmd_lock);
+ enic_dev_fw_info(enic, &fw_info);
strncpy(drvinfo->driver, DRV_NAME, sizeof(drvinfo->driver));
strncpy(drvinfo->version, DRV_VERSION, sizeof(drvinfo->version));
@@ -191,6 +201,17 @@ static int enic_get_sset_count(struct net_device *netdev, int sset)
}
}
+static int enic_dev_stats_dump(struct enic *enic, struct vnic_stats **vstats)
+{
+ int err;
+
+ spin_lock(&enic->devcmd_lock);
+ err = vnic_dev_stats_dump(enic->vdev, vstats);
+ spin_unlock(&enic->devcmd_lock);
+
+ return err;
+}
+
static void enic_get_ethtool_stats(struct net_device *netdev,
struct ethtool_stats *stats, u64 *data)
{
@@ -198,9 +219,7 @@ static void enic_get_ethtool_stats(struct net_device *netdev,
struct vnic_stats *vstats;
unsigned int i;
- spin_lock(&enic->devcmd_lock);
- vnic_dev_stats_dump(enic->vdev, &vstats);
- spin_unlock(&enic->devcmd_lock);
+ enic_dev_stats_dump(enic, &vstats);
for (i = 0; i < enic_n_tx_stats; i++)
*(data++) = ((u64 *)&vstats->tx)[enic_tx_stats[i].offset];
@@ -346,7 +365,6 @@ static const struct ethtool_ops enic_ethtool_ops = {
.get_coalesce = enic_get_coalesce,
.set_coalesce = enic_set_coalesce,
.get_flags = ethtool_op_get_flags,
- .set_flags = ethtool_op_set_flags,
};
static void enic_free_wq_buf(struct vnic_wq *wq, struct vnic_wq_buf *buf)
@@ -399,54 +417,55 @@ static void enic_log_q_error(struct enic *enic)
for (i = 0; i < enic->wq_count; i++) {
error_status = vnic_wq_error_status(&enic->wq[i]);
if (error_status)
- printk(KERN_ERR PFX "%s: WQ[%d] error_status %d\n",
- enic->netdev->name, i, error_status);
+ netdev_err(enic->netdev, "WQ[%d] error_status %d\n",
+ i, error_status);
}
for (i = 0; i < enic->rq_count; i++) {
error_status = vnic_rq_error_status(&enic->rq[i]);
if (error_status)
- printk(KERN_ERR PFX "%s: RQ[%d] error_status %d\n",
- enic->netdev->name, i, error_status);
+ netdev_err(enic->netdev, "RQ[%d] error_status %d\n",
+ i, error_status);
}
}
-static void enic_link_check(struct enic *enic)
+static void enic_msglvl_check(struct enic *enic)
{
- int link_status = vnic_dev_link_status(enic->vdev);
- int carrier_ok = netif_carrier_ok(enic->netdev);
+ u32 msg_enable = vnic_dev_msg_lvl(enic->vdev);
- if (link_status && !carrier_ok) {
- printk(KERN_INFO PFX "%s: Link UP\n", enic->netdev->name);
- netif_carrier_on(enic->netdev);
- } else if (!link_status && carrier_ok) {
- printk(KERN_INFO PFX "%s: Link DOWN\n", enic->netdev->name);
- netif_carrier_off(enic->netdev);
+ if (msg_enable != enic->msg_enable) {
+ netdev_info(enic->netdev, "msg lvl changed from 0x%x to 0x%x\n",
+ enic->msg_enable, msg_enable);
+ enic->msg_enable = msg_enable;
}
}
static void enic_mtu_check(struct enic *enic)
{
u32 mtu = vnic_dev_mtu(enic->vdev);
+ struct net_device *netdev = enic->netdev;
if (mtu && mtu != enic->port_mtu) {
enic->port_mtu = mtu;
- if (mtu < enic->netdev->mtu)
- printk(KERN_WARNING PFX
- "%s: interface MTU (%d) set higher "
+ if (mtu < netdev->mtu)
+ netdev_warn(netdev,
+ "interface MTU (%d) set higher "
"than switch port MTU (%d)\n",
- enic->netdev->name, enic->netdev->mtu, mtu);
+ netdev->mtu, mtu);
}
}
-static void enic_msglvl_check(struct enic *enic)
+static void enic_link_check(struct enic *enic)
{
- u32 msg_enable = vnic_dev_msg_lvl(enic->vdev);
+ int link_status = vnic_dev_link_status(enic->vdev);
+ int carrier_ok = netif_carrier_ok(enic->netdev);
- if (msg_enable != enic->msg_enable) {
- printk(KERN_INFO PFX "%s: msg lvl changed from 0x%x to 0x%x\n",
- enic->netdev->name, enic->msg_enable, msg_enable);
- enic->msg_enable = msg_enable;
+ if (link_status && !carrier_ok) {
+ netdev_info(enic->netdev, "Link UP\n");
+ netif_carrier_on(enic->netdev);
+ } else if (!link_status && carrier_ok) {
+ netdev_info(enic->netdev, "Link DOWN\n");
+ netif_carrier_off(enic->netdev);
}
}
@@ -574,7 +593,7 @@ static irqreturn_t enic_isr_msix_notify(int irq, void *data)
static inline void enic_queue_wq_skb_cont(struct enic *enic,
struct vnic_wq *wq, struct sk_buff *skb,
- unsigned int len_left)
+ unsigned int len_left, int loopback)
{
skb_frag_t *frag;
@@ -586,13 +605,14 @@ static inline void enic_queue_wq_skb_cont(struct enic *enic,
frag->page_offset, frag->size,
PCI_DMA_TODEVICE),
frag->size,
- (len_left == 0)); /* EOP? */
+ (len_left == 0), /* EOP? */
+ loopback);
}
}
static inline void enic_queue_wq_skb_vlan(struct enic *enic,
struct vnic_wq *wq, struct sk_buff *skb,
- int vlan_tag_insert, unsigned int vlan_tag)
+ int vlan_tag_insert, unsigned int vlan_tag, int loopback)
{
unsigned int head_len = skb_headlen(skb);
unsigned int len_left = skb->len - head_len;
@@ -608,15 +628,15 @@ static inline void enic_queue_wq_skb_vlan(struct enic *enic,
head_len, PCI_DMA_TODEVICE),
head_len,
vlan_tag_insert, vlan_tag,
- eop);
+ eop, loopback);
if (!eop)
- enic_queue_wq_skb_cont(enic, wq, skb, len_left);
+ enic_queue_wq_skb_cont(enic, wq, skb, len_left, loopback);
}
static inline void enic_queue_wq_skb_csum_l4(struct enic *enic,
struct vnic_wq *wq, struct sk_buff *skb,
- int vlan_tag_insert, unsigned int vlan_tag)
+ int vlan_tag_insert, unsigned int vlan_tag, int loopback)
{
unsigned int head_len = skb_headlen(skb);
unsigned int len_left = skb->len - head_len;
@@ -636,15 +656,15 @@ static inline void enic_queue_wq_skb_csum_l4(struct enic *enic,
csum_offset,
hdr_len,
vlan_tag_insert, vlan_tag,
- eop);
+ eop, loopback);
if (!eop)
- enic_queue_wq_skb_cont(enic, wq, skb, len_left);
+ enic_queue_wq_skb_cont(enic, wq, skb, len_left, loopback);
}
static inline void enic_queue_wq_skb_tso(struct enic *enic,
struct vnic_wq *wq, struct sk_buff *skb, unsigned int mss,
- int vlan_tag_insert, unsigned int vlan_tag)
+ int vlan_tag_insert, unsigned int vlan_tag, int loopback)
{
unsigned int frag_len_left = skb_headlen(skb);
unsigned int len_left = skb->len - frag_len_left;
@@ -681,7 +701,7 @@ static inline void enic_queue_wq_skb_tso(struct enic *enic,
len,
mss, hdr_len,
vlan_tag_insert, vlan_tag,
- eop && (len == frag_len_left));
+ eop && (len == frag_len_left), loopback);
frag_len_left -= len;
offset += len;
}
@@ -707,7 +727,8 @@ static inline void enic_queue_wq_skb_tso(struct enic *enic,
dma_addr,
len,
(len_left == 0) &&
- (len == frag_len_left)); /* EOP? */
+ (len == frag_len_left), /* EOP? */
+ loopback);
frag_len_left -= len;
offset += len;
}
@@ -720,22 +741,26 @@ static inline void enic_queue_wq_skb(struct enic *enic,
unsigned int mss = skb_shinfo(skb)->gso_size;
unsigned int vlan_tag = 0;
int vlan_tag_insert = 0;
+ int loopback = 0;
if (enic->vlan_group && vlan_tx_tag_present(skb)) {
/* VLAN tag from trunking driver */
vlan_tag_insert = 1;
vlan_tag = vlan_tx_tag_get(skb);
+ } else if (enic->loop_enable) {
+ vlan_tag = enic->loop_tag;
+ loopback = 1;
}
if (mss)
enic_queue_wq_skb_tso(enic, wq, skb, mss,
- vlan_tag_insert, vlan_tag);
+ vlan_tag_insert, vlan_tag, loopback);
else if (skb->ip_summed == CHECKSUM_PARTIAL)
enic_queue_wq_skb_csum_l4(enic, wq, skb,
- vlan_tag_insert, vlan_tag);
+ vlan_tag_insert, vlan_tag, loopback);
else
enic_queue_wq_skb_vlan(enic, wq, skb,
- vlan_tag_insert, vlan_tag);
+ vlan_tag_insert, vlan_tag, loopback);
}
/* netif_tx_lock held, process context with BHs disabled, or BH */
@@ -769,8 +794,7 @@ static netdev_tx_t enic_hard_start_xmit(struct sk_buff *skb,
skb_shinfo(skb)->nr_frags + ENIC_DESC_MAX_SPLITS) {
netif_stop_queue(netdev);
/* This is a hard error, log it */
- printk(KERN_ERR PFX "%s: BUG! Tx ring full when "
- "queue awake!\n", netdev->name);
+ netdev_err(netdev, "BUG! Tx ring full when queue awake!\n");
spin_unlock_irqrestore(&enic->wq_lock[0], flags);
return NETDEV_TX_BUSY;
}
@@ -792,9 +816,7 @@ static struct net_device_stats *enic_get_stats(struct net_device *netdev)
struct net_device_stats *net_stats = &netdev->stats;
struct vnic_stats *stats;
- spin_lock(&enic->devcmd_lock);
- vnic_dev_stats_dump(enic->vdev, &stats);
- spin_unlock(&enic->devcmd_lock);
+ enic_dev_stats_dump(enic, &stats);
net_stats->tx_packets = stats->tx.tx_frames_ok;
net_stats->tx_bytes = stats->tx.tx_bytes_ok;
@@ -812,9 +834,10 @@ static struct net_device_stats *enic_get_stats(struct net_device *netdev)
return net_stats;
}
-static void enic_reset_mcaddrs(struct enic *enic)
+static void enic_reset_multicast_list(struct enic *enic)
{
enic->mc_count = 0;
+ enic->flags = 0;
}
static int enic_set_mac_addr(struct net_device *netdev, char *addr)
@@ -891,6 +914,41 @@ static int enic_set_mac_address(struct net_device *netdev, void *p)
return -EOPNOTSUPP;
}
+static int enic_dev_packet_filter(struct enic *enic, int directed,
+ int multicast, int broadcast, int promisc, int allmulti)
+{
+ int err;
+
+ spin_lock(&enic->devcmd_lock);
+ err = vnic_dev_packet_filter(enic->vdev, directed,
+ multicast, broadcast, promisc, allmulti);
+ spin_unlock(&enic->devcmd_lock);
+
+ return err;
+}
+
+static int enic_dev_add_multicast_addr(struct enic *enic, u8 *addr)
+{
+ int err;
+
+ spin_lock(&enic->devcmd_lock);
+ err = vnic_dev_add_addr(enic->vdev, addr);
+ spin_unlock(&enic->devcmd_lock);
+
+ return err;
+}
+
+static int enic_dev_del_multicast_addr(struct enic *enic, u8 *addr)
+{
+ int err;
+
+ spin_lock(&enic->devcmd_lock);
+ err = vnic_dev_del_addr(enic->vdev, addr);
+ spin_unlock(&enic->devcmd_lock);
+
+ return err;
+}
+
/* netif_tx_lock held, BHs disabled */
static void enic_set_multicast_list(struct net_device *netdev)
{
@@ -910,11 +968,9 @@ static void enic_set_multicast_list(struct net_device *netdev)
if (mc_count > ENIC_MULTICAST_PERFECT_FILTERS)
mc_count = ENIC_MULTICAST_PERFECT_FILTERS;
- spin_lock(&enic->devcmd_lock);
-
if (enic->flags != flags) {
enic->flags = flags;
- vnic_dev_packet_filter(enic->vdev, directed,
+ enic_dev_packet_filter(enic, directed,
multicast, broadcast, promisc, allmulti);
}
@@ -937,7 +993,7 @@ static void enic_set_multicast_list(struct net_device *netdev)
mc_addr[j]) == 0)
break;
if (j == mc_count)
- enic_del_multicast_addr(enic, enic->mc_addr[i]);
+ enic_dev_del_multicast_addr(enic, enic->mc_addr[i]);
}
for (i = 0; i < mc_count; i++) {
@@ -946,7 +1002,7 @@ static void enic_set_multicast_list(struct net_device *netdev)
enic->mc_addr[j]) == 0)
break;
if (j == enic->mc_count)
- enic_add_multicast_addr(enic, mc_addr[i]);
+ enic_dev_add_multicast_addr(enic, mc_addr[i]);
}
/* Save the list to compare against next time
@@ -956,8 +1012,6 @@ static void enic_set_multicast_list(struct net_device *netdev)
memcpy(enic->mc_addr[i], mc_addr[i], ETH_ALEN);
enic->mc_count = mc_count;
-
- spin_unlock(&enic->devcmd_lock);
}
/* rtnl lock is held */
@@ -1226,7 +1280,7 @@ static int enic_rq_alloc_buf(struct vnic_rq *rq)
struct enic *enic = vnic_dev_priv(rq->vdev);
struct net_device *netdev = enic->netdev;
struct sk_buff *skb;
- unsigned int len = netdev->mtu + ETH_HLEN;
+ unsigned int len = netdev->mtu + VLAN_ETH_HLEN;
unsigned int os_buf_index = 0;
dma_addr_t dma_addr;
@@ -1263,12 +1317,24 @@ static int enic_rq_alloc_buf_a1(struct vnic_rq *rq)
return 0;
}
+static int enic_dev_hw_version(struct enic *enic,
+ enum vnic_dev_hw_version *hw_ver)
+{
+ int err;
+
+ spin_lock(&enic->devcmd_lock);
+ err = vnic_dev_hw_version(enic->vdev, hw_ver);
+ spin_unlock(&enic->devcmd_lock);
+
+ return err;
+}
+
static int enic_set_rq_alloc_buf(struct enic *enic)
{
enum vnic_dev_hw_version hw_ver;
int err;
- err = vnic_dev_hw_version(enic->vdev, &hw_ver);
+ err = enic_dev_hw_version(enic, &hw_ver);
if (err)
return err;
@@ -1287,51 +1353,6 @@ static int enic_set_rq_alloc_buf(struct enic *enic)
return 0;
}
-static int enic_get_skb_header(struct sk_buff *skb, void **iphdr,
- void **tcph, u64 *hdr_flags, void *priv)
-{
- struct cq_enet_rq_desc *cq_desc = priv;
- unsigned int ip_len;
- struct iphdr *iph;
-
- u8 type, color, eop, sop, ingress_port, vlan_stripped;
- u8 fcoe, fcoe_sof, fcoe_fc_crc_ok, fcoe_enc_error, fcoe_eof;
- u8 tcp_udp_csum_ok, udp, tcp, ipv4_csum_ok;
- u8 ipv6, ipv4, ipv4_fragment, fcs_ok, rss_type, csum_not_calc;
- u8 packet_error;
- u16 q_number, completed_index, bytes_written, vlan, checksum;
- u32 rss_hash;
-
- cq_enet_rq_desc_dec(cq_desc,
- &type, &color, &q_number, &completed_index,
- &ingress_port, &fcoe, &eop, &sop, &rss_type,
- &csum_not_calc, &rss_hash, &bytes_written,
- &packet_error, &vlan_stripped, &vlan, &checksum,
- &fcoe_sof, &fcoe_fc_crc_ok, &fcoe_enc_error,
- &fcoe_eof, &tcp_udp_csum_ok, &udp, &tcp,
- &ipv4_csum_ok, &ipv6, &ipv4, &ipv4_fragment,
- &fcs_ok);
-
- if (!(ipv4 && tcp && !ipv4_fragment))
- return -1;
-
- skb_reset_network_header(skb);
- iph = ip_hdr(skb);
-
- ip_len = ip_hdrlen(skb);
- skb_set_transport_header(skb, ip_len);
-
- /* check if ip header and tcp header are complete */
- if (ntohs(iph->tot_len) < ip_len + tcp_hdrlen(skb))
- return -1;
-
- *hdr_flags = LRO_IPV4 | LRO_TCP;
- *tcph = tcp_hdr(skb);
- *iphdr = iph;
-
- return 0;
-}
-
static void enic_rq_indicate_buf(struct vnic_rq *rq,
struct cq_desc *cq_desc, struct vnic_rq_buf *buf,
int skipped, void *opaque)
@@ -1345,7 +1366,7 @@ static void enic_rq_indicate_buf(struct vnic_rq *rq,
u8 tcp_udp_csum_ok, udp, tcp, ipv4_csum_ok;
u8 ipv6, ipv4, ipv4_fragment, fcs_ok, rss_type, csum_not_calc;
u8 packet_error;
- u16 q_number, completed_index, bytes_written, vlan, checksum;
+ u16 q_number, completed_index, bytes_written, vlan_tci, checksum;
u32 rss_hash;
if (skipped)
@@ -1360,7 +1381,7 @@ static void enic_rq_indicate_buf(struct vnic_rq *rq,
&type, &color, &q_number, &completed_index,
&ingress_port, &fcoe, &eop, &sop, &rss_type,
&csum_not_calc, &rss_hash, &bytes_written,
- &packet_error, &vlan_stripped, &vlan, &checksum,
+ &packet_error, &vlan_stripped, &vlan_tci, &checksum,
&fcoe_sof, &fcoe_fc_crc_ok, &fcoe_enc_error,
&fcoe_eof, &tcp_udp_csum_ok, &udp, &tcp,
&ipv4_csum_ok, &ipv6, &ipv4, &ipv4_fragment,
@@ -1395,20 +1416,20 @@ static void enic_rq_indicate_buf(struct vnic_rq *rq,
skb->dev = netdev;
- if (enic->vlan_group && vlan_stripped) {
+ if (enic->vlan_group && vlan_stripped &&
+ (vlan_tci & CQ_ENET_RQ_DESC_VLAN_TCI_VLAN_MASK)) {
- if ((netdev->features & NETIF_F_LRO) && ipv4)
- lro_vlan_hwaccel_receive_skb(&enic->lro_mgr,
- skb, enic->vlan_group,
- vlan, cq_desc);
+ if (netdev->features & NETIF_F_GRO)
+ vlan_gro_receive(&enic->napi, enic->vlan_group,
+ vlan_tci, skb);
else
vlan_hwaccel_receive_skb(skb,
- enic->vlan_group, vlan);
+ enic->vlan_group, vlan_tci);
} else {
- if ((netdev->features & NETIF_F_LRO) && ipv4)
- lro_receive_skb(&enic->lro_mgr, skb, cq_desc);
+ if (netdev->features & NETIF_F_GRO)
+ napi_gro_receive(&enic->napi, skb);
else
netif_receive_skb(skb);
@@ -1438,7 +1459,6 @@ static int enic_rq_service(struct vnic_dev *vdev, struct cq_desc *cq_desc,
static int enic_poll(struct napi_struct *napi, int budget)
{
struct enic *enic = container_of(napi, struct enic, napi);
- struct net_device *netdev = enic->netdev;
unsigned int rq_work_to_do = budget;
unsigned int wq_work_to_do = -1; /* no limit */
unsigned int work_done, rq_work_done, wq_work_done;
@@ -1478,12 +1498,9 @@ static int enic_poll(struct napi_struct *napi, int budget)
if (rq_work_done < rq_work_to_do) {
/* Some work done, but not enough to stay in polling,
- * flush all LROs and exit polling
+ * exit polling
*/
- if (netdev->features & NETIF_F_LRO)
- lro_flush_all(&enic->lro_mgr);
-
napi_complete(napi);
vnic_intr_unmask(&enic->intr[ENIC_INTX_WQ_RQ]);
}
@@ -1494,7 +1511,6 @@ static int enic_poll(struct napi_struct *napi, int budget)
static int enic_poll_msix(struct napi_struct *napi, int budget)
{
struct enic *enic = container_of(napi, struct enic, napi);
- struct net_device *netdev = enic->netdev;
unsigned int work_to_do = budget;
unsigned int work_done;
int err;
@@ -1528,12 +1544,9 @@ static int enic_poll_msix(struct napi_struct *napi, int budget)
if (work_done < work_to_do) {
/* Some work done, but not enough to stay in polling,
- * flush all LROs and exit polling
+ * exit polling
*/
- if (netdev->features & NETIF_F_LRO)
- lro_flush_all(&enic->lro_mgr);
-
napi_complete(napi);
vnic_intr_unmask(&enic->intr[ENIC_MSIX_RQ]);
}
@@ -1655,7 +1668,7 @@ static void enic_synchronize_irqs(struct enic *enic)
}
}
-static int enic_notify_set(struct enic *enic)
+static int enic_dev_notify_set(struct enic *enic)
{
int err;
@@ -1676,6 +1689,39 @@ static int enic_notify_set(struct enic *enic)
return err;
}
+static int enic_dev_notify_unset(struct enic *enic)
+{
+ int err;
+
+ spin_lock(&enic->devcmd_lock);
+ err = vnic_dev_notify_unset(enic->vdev);
+ spin_unlock(&enic->devcmd_lock);
+
+ return err;
+}
+
+static int enic_dev_enable(struct enic *enic)
+{
+ int err;
+
+ spin_lock(&enic->devcmd_lock);
+ err = vnic_dev_enable(enic->vdev);
+ spin_unlock(&enic->devcmd_lock);
+
+ return err;
+}
+
+static int enic_dev_disable(struct enic *enic)
+{
+ int err;
+
+ spin_lock(&enic->devcmd_lock);
+ err = vnic_dev_disable(enic->vdev);
+ spin_unlock(&enic->devcmd_lock);
+
+ return err;
+}
+
static void enic_notify_timer_start(struct enic *enic)
{
switch (vnic_dev_get_intr_mode(enic->vdev)) {
@@ -1697,16 +1743,14 @@ static int enic_open(struct net_device *netdev)
err = enic_request_intr(enic);
if (err) {
- printk(KERN_ERR PFX "%s: Unable to request irq.\n",
- netdev->name);
+ netdev_err(netdev, "Unable to request irq.\n");
return err;
}
- err = enic_notify_set(enic);
+ err = enic_dev_notify_set(enic);
if (err) {
- printk(KERN_ERR PFX
- "%s: Failed to alloc notify buffer, aborting.\n",
- netdev->name);
+ netdev_err(netdev,
+ "Failed to alloc notify buffer, aborting.\n");
goto err_out_free_intr;
}
@@ -1714,9 +1758,7 @@ static int enic_open(struct net_device *netdev)
vnic_rq_fill(&enic->rq[i], enic->rq_alloc_buf);
/* Need at least one buffer on ring to get going */
if (vnic_rq_desc_used(&enic->rq[i]) == 0) {
- printk(KERN_ERR PFX
- "%s: Unable to alloc receive buffers.\n",
- netdev->name);
+ netdev_err(netdev, "Unable to alloc receive buffers\n");
err = -ENOMEM;
goto err_out_notify_unset;
}
@@ -1732,9 +1774,7 @@ static int enic_open(struct net_device *netdev)
netif_wake_queue(netdev);
napi_enable(&enic->napi);
- spin_lock(&enic->devcmd_lock);
- vnic_dev_enable(enic->vdev);
- spin_unlock(&enic->devcmd_lock);
+ enic_dev_enable(enic);
for (i = 0; i < enic->intr_count; i++)
vnic_intr_unmask(&enic->intr[i]);
@@ -1744,9 +1784,7 @@ static int enic_open(struct net_device *netdev)
return 0;
err_out_notify_unset:
- spin_lock(&enic->devcmd_lock);
- vnic_dev_notify_unset(enic->vdev);
- spin_unlock(&enic->devcmd_lock);
+ enic_dev_notify_unset(enic);
err_out_free_intr:
enic_free_intr(enic);
@@ -1760,20 +1798,19 @@ static int enic_stop(struct net_device *netdev)
unsigned int i;
int err;
- for (i = 0; i < enic->intr_count; i++)
+ for (i = 0; i < enic->intr_count; i++) {
vnic_intr_mask(&enic->intr[i]);
+ (void)vnic_intr_masked(&enic->intr[i]); /* flush write */
+ }
enic_synchronize_irqs(enic);
del_timer_sync(&enic->notify_timer);
- spin_lock(&enic->devcmd_lock);
- vnic_dev_disable(enic->vdev);
- spin_unlock(&enic->devcmd_lock);
+ enic_dev_disable(enic);
napi_disable(&enic->napi);
netif_carrier_off(netdev);
netif_tx_disable(netdev);
-
enic_dev_del_station_addr(enic);
for (i = 0; i < enic->wq_count; i++) {
@@ -1787,9 +1824,7 @@ static int enic_stop(struct net_device *netdev)
return err;
}
- spin_lock(&enic->devcmd_lock);
- vnic_dev_notify_unset(enic->vdev);
- spin_unlock(&enic->devcmd_lock);
+ enic_dev_notify_unset(enic);
enic_free_intr(enic);
for (i = 0; i < enic->wq_count; i++)
@@ -1818,10 +1853,9 @@ static int enic_change_mtu(struct net_device *netdev, int new_mtu)
netdev->mtu = new_mtu;
if (netdev->mtu > enic->port_mtu)
- printk(KERN_WARNING PFX
- "%s: interface MTU (%d) set higher "
- "than port MTU (%d)\n",
- netdev->name, netdev->mtu, enic->port_mtu);
+ netdev_warn(netdev,
+ "interface MTU (%d) set higher than port MTU (%d)\n",
+ netdev->mtu, enic->port_mtu);
if (running)
enic_open(netdev);
@@ -1894,21 +1928,21 @@ static int enic_dev_open(struct enic *enic)
err = enic_dev_wait(enic->vdev, vnic_dev_open,
vnic_dev_open_done, 0);
if (err)
- printk(KERN_ERR PFX
- "vNIC device open failed, err %d.\n", err);
+ dev_err(enic_get_dev(enic), "vNIC device open failed, err %d\n",
+ err);
return err;
}
-static int enic_dev_soft_reset(struct enic *enic)
+static int enic_dev_hang_reset(struct enic *enic)
{
int err;
- err = enic_dev_wait(enic->vdev, vnic_dev_soft_reset,
- vnic_dev_soft_reset_done, 0);
+ err = enic_dev_wait(enic->vdev, vnic_dev_hang_reset,
+ vnic_dev_hang_reset_done, 0);
if (err)
- printk(KERN_ERR PFX
- "vNIC soft reset failed, err %d.\n", err);
+ netdev_err(enic->netdev, "vNIC hang reset failed, err %d\n",
+ err);
return err;
}
@@ -1922,15 +1956,43 @@ static int enic_set_niccfg(struct enic *enic)
const u8 rss_enable = 0;
const u8 tso_ipid_split_en = 0;
const u8 ig_vlan_strip_en = 1;
+ int err;
/* Enable VLAN tag stripping. RSS not enabled (yet).
*/
- return enic_set_nic_cfg(enic,
+ spin_lock(&enic->devcmd_lock);
+ err = enic_set_nic_cfg(enic,
rss_default_cpu, rss_hash_type,
rss_hash_bits, rss_base_cpu,
rss_enable, tso_ipid_split_en,
ig_vlan_strip_en);
+ spin_unlock(&enic->devcmd_lock);
+
+ return err;
+}
+
+static int enic_dev_hang_notify(struct enic *enic)
+{
+ int err;
+
+ spin_lock(&enic->devcmd_lock);
+ err = vnic_dev_hang_notify(enic->vdev);
+ spin_unlock(&enic->devcmd_lock);
+
+ return err;
+}
+
+int enic_dev_set_ig_vlan_rewrite_mode(struct enic *enic)
+{
+ int err;
+
+ spin_lock(&enic->devcmd_lock);
+ err = vnic_dev_set_ig_vlan_rewrite_mode(enic->vdev,
+ IG_VLAN_REWRITE_MODE_PRIORITY_TAG_DEFAULT_VLAN);
+ spin_unlock(&enic->devcmd_lock);
+
+ return err;
}
static void enic_reset(struct work_struct *work)
@@ -1942,16 +2004,13 @@ static void enic_reset(struct work_struct *work)
rtnl_lock();
- spin_lock(&enic->devcmd_lock);
- vnic_dev_hang_notify(enic->vdev);
- spin_unlock(&enic->devcmd_lock);
-
+ enic_dev_hang_notify(enic);
enic_stop(enic->netdev);
- enic_dev_soft_reset(enic);
- vnic_dev_init(enic->vdev, 0);
- enic_reset_mcaddrs(enic);
+ enic_dev_hang_reset(enic);
+ enic_reset_multicast_list(enic);
enic_init_vnic_resources(enic);
enic_set_niccfg(enic);
+ enic_dev_set_ig_vlan_rewrite_mode(enic);
enic_open(enic->netdev);
rtnl_unlock();
@@ -2087,8 +2146,8 @@ static const struct net_device_ops enic_netdev_ops = {
.ndo_start_xmit = enic_hard_start_xmit,
.ndo_get_stats = enic_get_stats,
.ndo_validate_addr = eth_validate_addr,
- .ndo_set_multicast_list = enic_set_multicast_list,
.ndo_set_mac_address = enic_set_mac_address,
+ .ndo_set_multicast_list = enic_set_multicast_list,
.ndo_change_mtu = enic_change_mtu,
.ndo_vlan_rx_register = enic_vlan_rx_register,
.ndo_vlan_rx_add_vid = enic_vlan_rx_add_vid,
@@ -2106,8 +2165,20 @@ void enic_dev_deinit(struct enic *enic)
enic_clear_intr_mode(enic);
}
+static int enic_dev_stats_clear(struct enic *enic)
+{
+ int err;
+
+ spin_lock(&enic->devcmd_lock);
+ err = vnic_dev_stats_clear(enic->vdev);
+ spin_unlock(&enic->devcmd_lock);
+
+ return err;
+}
+
int enic_dev_init(struct enic *enic)
{
+ struct device *dev = enic_get_dev(enic);
struct net_device *netdev = enic->netdev;
int err;
@@ -2116,8 +2187,7 @@ int enic_dev_init(struct enic *enic)
err = enic_get_vnic_config(enic);
if (err) {
- printk(KERN_ERR PFX
- "Get vNIC configuration failed, aborting.\n");
+ dev_err(dev, "Get vNIC configuration failed, aborting\n");
return err;
}
@@ -2132,9 +2202,8 @@ int enic_dev_init(struct enic *enic)
err = enic_set_intr_mode(enic);
if (err) {
- printk(KERN_ERR PFX
- "Failed to set intr mode based on resource "
- "counts and system capabilities, aborting.\n");
+ dev_err(dev, "Failed to set intr mode based on resource "
+ "counts and system capabilities, aborting\n");
return err;
}
@@ -2143,24 +2212,32 @@ int enic_dev_init(struct enic *enic)
err = enic_alloc_vnic_resources(enic);
if (err) {
- printk(KERN_ERR PFX
- "Failed to alloc vNIC resources, aborting.\n");
+ dev_err(dev, "Failed to alloc vNIC resources, aborting\n");
goto err_out_free_vnic_resources;
}
enic_init_vnic_resources(enic);
+ /* Clear LIF stats
+ */
+ enic_dev_stats_clear(enic);
+
err = enic_set_rq_alloc_buf(enic);
if (err) {
- printk(KERN_ERR PFX
- "Failed to set RQ buffer allocator, aborting.\n");
+ dev_err(dev, "Failed to set RQ buffer allocator, aborting\n");
goto err_out_free_vnic_resources;
}
err = enic_set_niccfg(enic);
if (err) {
- printk(KERN_ERR PFX
- "Failed to config nic, aborting.\n");
+ dev_err(dev, "Failed to config nic, aborting\n");
+ goto err_out_free_vnic_resources;
+ }
+
+ err = enic_dev_set_ig_vlan_rewrite_mode(enic);
+ if (err) {
+ netdev_err(netdev,
+ "Failed to set ingress vlan rewrite mode, aborting.\n");
goto err_out_free_vnic_resources;
}
@@ -2194,6 +2271,7 @@ static void enic_iounmap(struct enic *enic)
static int __devinit enic_probe(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
+ struct device *dev = &pdev->dev;
struct net_device *netdev;
struct enic *enic;
int using_dac = 0;
@@ -2206,7 +2284,7 @@ static int __devinit enic_probe(struct pci_dev *pdev,
netdev = alloc_etherdev(sizeof(struct enic));
if (!netdev) {
- printk(KERN_ERR PFX "Etherdev alloc failed, aborting.\n");
+ pr_err("Etherdev alloc failed, aborting\n");
return -ENOMEM;
}
@@ -2221,17 +2299,15 @@ static int __devinit enic_probe(struct pci_dev *pdev,
/* Setup PCI resources
*/
- err = pci_enable_device(pdev);
+ err = pci_enable_device_mem(pdev);
if (err) {
- printk(KERN_ERR PFX
- "Cannot enable PCI device, aborting.\n");
+ dev_err(dev, "Cannot enable PCI device, aborting\n");
goto err_out_free_netdev;
}
err = pci_request_regions(pdev, DRV_NAME);
if (err) {
- printk(KERN_ERR PFX
- "Cannot request PCI regions, aborting.\n");
+ dev_err(dev, "Cannot request PCI regions, aborting\n");
goto err_out_disable_device;
}
@@ -2246,23 +2322,20 @@ static int __devinit enic_probe(struct pci_dev *pdev,
if (err) {
err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
if (err) {
- printk(KERN_ERR PFX
- "No usable DMA configuration, aborting.\n");
+ dev_err(dev, "No usable DMA configuration, aborting\n");
goto err_out_release_regions;
}
err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));
if (err) {
- printk(KERN_ERR PFX
- "Unable to obtain 32-bit DMA "
- "for consistent allocations, aborting.\n");
+ dev_err(dev, "Unable to obtain %u-bit DMA "
+ "for consistent allocations, aborting\n", 32);
goto err_out_release_regions;
}
} else {
err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(40));
if (err) {
- printk(KERN_ERR PFX
- "Unable to obtain 40-bit DMA "
- "for consistent allocations, aborting.\n");
+ dev_err(dev, "Unable to obtain %u-bit DMA "
+ "for consistent allocations, aborting\n", 40);
goto err_out_release_regions;
}
using_dac = 1;
@@ -2277,8 +2350,7 @@ static int __devinit enic_probe(struct pci_dev *pdev,
enic->bar[i].len = pci_resource_len(pdev, i);
enic->bar[i].vaddr = pci_iomap(pdev, i, enic->bar[i].len);
if (!enic->bar[i].vaddr) {
- printk(KERN_ERR PFX
- "Cannot memory-map BAR %d, aborting.\n", i);
+ dev_err(dev, "Cannot memory-map BAR %d, aborting\n", i);
err = -ENODEV;
goto err_out_iounmap;
}
@@ -2291,8 +2363,7 @@ static int __devinit enic_probe(struct pci_dev *pdev,
enic->vdev = vnic_dev_register(NULL, enic, pdev, enic->bar,
ARRAY_SIZE(enic->bar));
if (!enic->vdev) {
- printk(KERN_ERR PFX
- "vNIC registration failed, aborting.\n");
+ dev_err(dev, "vNIC registration failed, aborting\n");
err = -ENODEV;
goto err_out_iounmap;
}
@@ -2302,8 +2373,7 @@ static int __devinit enic_probe(struct pci_dev *pdev,
err = enic_dev_open(enic);
if (err) {
- printk(KERN_ERR PFX
- "vNIC dev open failed, aborting.\n");
+ dev_err(dev, "vNIC dev open failed, aborting\n");
goto err_out_vnic_unregister;
}
@@ -2317,23 +2387,31 @@ static int __devinit enic_probe(struct pci_dev *pdev,
netif_carrier_off(netdev);
+ /* Do not call dev_init for a dynamic vnic.
+ * For a dynamic vnic, init_prov_info will be
+ * called later by an upper layer.
+ */
+
if (!enic_is_dynamic(enic)) {
err = vnic_dev_init(enic->vdev, 0);
if (err) {
- printk(KERN_ERR PFX
- "vNIC dev init failed, aborting.\n");
+ dev_err(dev, "vNIC dev init failed, aborting\n");
goto err_out_dev_close;
}
}
+ /* Setup devcmd lock
+ */
+
+ spin_lock_init(&enic->devcmd_lock);
+
err = enic_dev_init(enic);
if (err) {
- printk(KERN_ERR PFX
- "Device initialization failed, aborting.\n");
+ dev_err(dev, "Device initialization failed, aborting\n");
goto err_out_dev_close;
}
- /* Setup notification timer, HW reset task, and locks
+ /* Setup notification timer, HW reset task, and wq locks
*/
init_timer(&enic->notify_timer);
@@ -2345,8 +2423,6 @@ static int __devinit enic_probe(struct pci_dev *pdev,
for (i = 0; i < enic->wq_count; i++)
spin_lock_init(&enic->wq_lock[i]);
- spin_lock_init(&enic->devcmd_lock);
-
/* Register net device
*/
@@ -2355,8 +2431,7 @@ static int __devinit enic_probe(struct pci_dev *pdev,
err = enic_set_mac_addr(netdev, enic->mac_addr);
if (err) {
- printk(KERN_ERR PFX
- "Invalid MAC address, aborting.\n");
+ dev_err(dev, "Invalid MAC address, aborting\n");
goto err_out_dev_deinit;
}
@@ -2372,31 +2447,27 @@ static int __devinit enic_probe(struct pci_dev *pdev,
netdev->ethtool_ops = &enic_ethtool_ops;
netdev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
+ if (ENIC_SETTING(enic, LOOP)) {
+ netdev->features &= ~NETIF_F_HW_VLAN_TX;
+ enic->loop_enable = 1;
+ enic->loop_tag = enic->config.loop_tag;
+ dev_info(dev, "loopback tag=0x%04x\n", enic->loop_tag);
+ }
if (ENIC_SETTING(enic, TXCSUM))
netdev->features |= NETIF_F_SG | NETIF_F_HW_CSUM;
if (ENIC_SETTING(enic, TSO))
netdev->features |= NETIF_F_TSO |
NETIF_F_TSO6 | NETIF_F_TSO_ECN;
if (ENIC_SETTING(enic, LRO))
- netdev->features |= NETIF_F_LRO;
+ netdev->features |= NETIF_F_GRO;
if (using_dac)
netdev->features |= NETIF_F_HIGHDMA;
enic->csum_rx_enabled = ENIC_SETTING(enic, RXCSUM);
- enic->lro_mgr.max_aggr = ENIC_LRO_MAX_AGGR;
- enic->lro_mgr.max_desc = ENIC_LRO_MAX_DESC;
- enic->lro_mgr.lro_arr = enic->lro_desc;
- enic->lro_mgr.get_skb_header = enic_get_skb_header;
- enic->lro_mgr.features = LRO_F_NAPI | LRO_F_EXTRACT_VLAN_ID;
- enic->lro_mgr.dev = netdev;
- enic->lro_mgr.ip_summed = CHECKSUM_COMPLETE;
- enic->lro_mgr.ip_summed_aggr = CHECKSUM_UNNECESSARY;
-
err = register_netdev(netdev);
if (err) {
- printk(KERN_ERR PFX
- "Cannot register net device, aborting.\n");
+ dev_err(dev, "Cannot register net device, aborting\n");
goto err_out_dev_deinit;
}
@@ -2450,7 +2521,7 @@ static struct pci_driver enic_driver = {
static int __init enic_init_module(void)
{
- printk(KERN_INFO PFX "%s, ver %s\n", DRV_DESCRIPTION, DRV_VERSION);
+ pr_info("%s, ver %s\n", DRV_DESCRIPTION, DRV_VERSION);
return pci_register_driver(&enic_driver);
}
diff --git a/drivers/net/enic/enic_res.c b/drivers/net/enic/enic_res.c
index 9b18840cba9..29ede8a17a2 100644
--- a/drivers/net/enic/enic_res.c
+++ b/drivers/net/enic/enic_res.c
@@ -1,5 +1,5 @@
/*
- * Copyright 2008 Cisco Systems, Inc. All rights reserved.
+ * Copyright 2008-2010 Cisco Systems, Inc. All rights reserved.
* Copyright 2007 Nuova Systems, Inc. All rights reserved.
*
* This program is free software; you may redistribute it and/or modify
@@ -46,7 +46,8 @@ int enic_get_vnic_config(struct enic *enic)
err = vnic_dev_mac_addr(enic->vdev, enic->mac_addr);
if (err) {
- printk(KERN_ERR PFX "Error getting MAC addr, %d\n", err);
+ dev_err(enic_get_dev(enic),
+ "Error getting MAC addr, %d\n", err);
return err;
}
@@ -56,7 +57,7 @@ int enic_get_vnic_config(struct enic *enic)
offsetof(struct vnic_enet_config, m), \
sizeof(c->m), &c->m); \
if (err) { \
- printk(KERN_ERR PFX \
+ dev_err(enic_get_dev(enic), \
"Error getting %s, %d\n", #m, err); \
return err; \
} \
@@ -69,6 +70,7 @@ int enic_get_vnic_config(struct enic *enic)
GET_CONFIG(intr_timer_type);
GET_CONFIG(intr_mode);
GET_CONFIG(intr_timer_usec);
+ GET_CONFIG(loop_tag);
c->wq_desc_count =
min_t(u32, ENIC_MAX_WQ_DESCS,
@@ -92,10 +94,10 @@ int enic_get_vnic_config(struct enic *enic)
INTR_COALESCE_HW_TO_USEC(VNIC_INTR_TIMER_MAX),
c->intr_timer_usec);
- printk(KERN_INFO PFX "vNIC MAC addr %pM wq/rq %d/%d\n",
+ dev_info(enic_get_dev(enic), "vNIC MAC addr %pM wq/rq %d/%d\n",
enic->mac_addr, c->wq_desc_count, c->rq_desc_count);
- printk(KERN_INFO PFX "vNIC mtu %d csum tx/rx %d/%d tso/lro %d/%d "
- "intr timer %d usec\n",
+ dev_info(enic_get_dev(enic), "vNIC mtu %d csum tx/rx %d/%d "
+ "tso/lro %d/%d intr timer %d usec\n",
c->mtu, ENIC_SETTING(enic, TXCSUM),
ENIC_SETTING(enic, RXCSUM), ENIC_SETTING(enic, TSO),
ENIC_SETTING(enic, LRO), c->intr_timer_usec);
@@ -103,17 +105,7 @@ int enic_get_vnic_config(struct enic *enic)
return 0;
}
-void enic_add_multicast_addr(struct enic *enic, u8 *addr)
-{
- vnic_dev_add_addr(enic->vdev, addr);
-}
-
-void enic_del_multicast_addr(struct enic *enic, u8 *addr)
-{
- vnic_dev_del_addr(enic->vdev, addr);
-}
-
-void enic_add_vlan(struct enic *enic, u16 vlanid)
+int enic_add_vlan(struct enic *enic, u16 vlanid)
{
u64 a0 = vlanid, a1 = 0;
int wait = 1000;
@@ -121,10 +113,12 @@ void enic_add_vlan(struct enic *enic, u16 vlanid)
err = vnic_dev_cmd(enic->vdev, CMD_VLAN_ADD, &a0, &a1, wait);
if (err)
- printk(KERN_ERR PFX "Can't add vlan id, %d\n", err);
+ dev_err(enic_get_dev(enic), "Can't add vlan id, %d\n", err);
+
+ return err;
}
-void enic_del_vlan(struct enic *enic, u16 vlanid)
+int enic_del_vlan(struct enic *enic, u16 vlanid)
{
u64 a0 = vlanid, a1 = 0;
int wait = 1000;
@@ -132,7 +126,9 @@ void enic_del_vlan(struct enic *enic, u16 vlanid)
err = vnic_dev_cmd(enic->vdev, CMD_VLAN_DEL, &a0, &a1, wait);
if (err)
- printk(KERN_ERR PFX "Can't delete vlan id, %d\n", err);
+ dev_err(enic_get_dev(enic), "Can't delete vlan id, %d\n", err);
+
+ return err;
}
int enic_set_nic_cfg(struct enic *enic, u8 rss_default_cpu, u8 rss_hash_type,
@@ -198,8 +194,8 @@ void enic_get_res_counts(struct enic *enic)
vnic_dev_get_res_count(enic->vdev, RES_TYPE_INTR_CTRL),
ENIC_INTR_MAX);
- printk(KERN_INFO PFX "vNIC resources avail: "
- "wq %d rq %d cq %d intr %d\n",
+ dev_info(enic_get_dev(enic),
+ "vNIC resources avail: wq %d rq %d cq %d intr %d\n",
enic->wq_count, enic->rq_count,
enic->cq_count, enic->intr_count);
}
@@ -304,11 +300,6 @@ void enic_init_vnic_resources(struct enic *enic)
enic->config.intr_timer_type,
mask_on_assertion);
}
-
- /* Clear LIF stats
- */
-
- vnic_dev_stats_clear(enic->vdev);
}
int enic_alloc_vnic_resources(struct enic *enic)
@@ -319,15 +310,14 @@ int enic_alloc_vnic_resources(struct enic *enic)
intr_mode = vnic_dev_get_intr_mode(enic->vdev);
- printk(KERN_INFO PFX "vNIC resources used: "
+ dev_info(enic_get_dev(enic), "vNIC resources used: "
"wq %d rq %d cq %d intr %d intr mode %s\n",
enic->wq_count, enic->rq_count,
enic->cq_count, enic->intr_count,
intr_mode == VNIC_DEV_INTR_MODE_INTX ? "legacy PCI INTx" :
intr_mode == VNIC_DEV_INTR_MODE_MSI ? "MSI" :
intr_mode == VNIC_DEV_INTR_MODE_MSIX ? "MSI-X" :
- "unknown"
- );
+ "unknown");
/* Allocate queue resources
*/
@@ -373,7 +363,8 @@ int enic_alloc_vnic_resources(struct enic *enic)
enic->legacy_pba = vnic_dev_get_res(enic->vdev,
RES_TYPE_INTR_PBA_LEGACY, 0);
if (!enic->legacy_pba && intr_mode == VNIC_DEV_INTR_MODE_INTX) {
- printk(KERN_ERR PFX "Failed to hook legacy pba resource\n");
+ dev_err(enic_get_dev(enic),
+ "Failed to hook legacy pba resource\n");
err = -ENODEV;
goto err_out_cleanup;
}
diff --git a/drivers/net/enic/enic_res.h b/drivers/net/enic/enic_res.h
index 494664f7fcc..83bd172c356 100644
--- a/drivers/net/enic/enic_res.h
+++ b/drivers/net/enic/enic_res.h
@@ -1,5 +1,5 @@
/*
- * Copyright 2008 Cisco Systems, Inc. All rights reserved.
+ * Copyright 2008-2010 Cisco Systems, Inc. All rights reserved.
* Copyright 2007 Nuova Systems, Inc. All rights reserved.
*
* This program is free software; you may redistribute it and/or modify
@@ -43,7 +43,7 @@ static inline void enic_queue_wq_desc_ex(struct vnic_wq *wq,
void *os_buf, dma_addr_t dma_addr, unsigned int len,
unsigned int mss_or_csum_offset, unsigned int hdr_len,
int vlan_tag_insert, unsigned int vlan_tag,
- int offload_mode, int cq_entry, int sop, int eop)
+ int offload_mode, int cq_entry, int sop, int eop, int loopback)
{
struct wq_enet_desc *desc = vnic_wq_next_desc(wq);
@@ -56,61 +56,62 @@ static inline void enic_queue_wq_desc_ex(struct vnic_wq *wq,
0, /* fcoe_encap */
(u8)vlan_tag_insert,
(u16)vlan_tag,
- 0 /* loopback */);
+ (u8)loopback);
vnic_wq_post(wq, os_buf, dma_addr, len, sop, eop);
}
static inline void enic_queue_wq_desc_cont(struct vnic_wq *wq,
- void *os_buf, dma_addr_t dma_addr, unsigned int len, int eop)
+ void *os_buf, dma_addr_t dma_addr, unsigned int len,
+ int eop, int loopback)
{
enic_queue_wq_desc_ex(wq, os_buf, dma_addr, len,
0, 0, 0, 0, 0,
- eop, 0 /* !SOP */, eop);
+ eop, 0 /* !SOP */, eop, loopback);
}
static inline void enic_queue_wq_desc(struct vnic_wq *wq, void *os_buf,
dma_addr_t dma_addr, unsigned int len, int vlan_tag_insert,
- unsigned int vlan_tag, int eop)
+ unsigned int vlan_tag, int eop, int loopback)
{
enic_queue_wq_desc_ex(wq, os_buf, dma_addr, len,
0, 0, vlan_tag_insert, vlan_tag,
WQ_ENET_OFFLOAD_MODE_CSUM,
- eop, 1 /* SOP */, eop);
+ eop, 1 /* SOP */, eop, loopback);
}
static inline void enic_queue_wq_desc_csum(struct vnic_wq *wq,
void *os_buf, dma_addr_t dma_addr, unsigned int len,
int ip_csum, int tcpudp_csum, int vlan_tag_insert,
- unsigned int vlan_tag, int eop)
+ unsigned int vlan_tag, int eop, int loopback)
{
enic_queue_wq_desc_ex(wq, os_buf, dma_addr, len,
(ip_csum ? 1 : 0) + (tcpudp_csum ? 2 : 0),
0, vlan_tag_insert, vlan_tag,
WQ_ENET_OFFLOAD_MODE_CSUM,
- eop, 1 /* SOP */, eop);
+ eop, 1 /* SOP */, eop, loopback);
}
static inline void enic_queue_wq_desc_csum_l4(struct vnic_wq *wq,
void *os_buf, dma_addr_t dma_addr, unsigned int len,
unsigned int csum_offset, unsigned int hdr_len,
- int vlan_tag_insert, unsigned int vlan_tag, int eop)
+ int vlan_tag_insert, unsigned int vlan_tag, int eop, int loopback)
{
enic_queue_wq_desc_ex(wq, os_buf, dma_addr, len,
csum_offset, hdr_len, vlan_tag_insert, vlan_tag,
WQ_ENET_OFFLOAD_MODE_CSUM_L4,
- eop, 1 /* SOP */, eop);
+ eop, 1 /* SOP */, eop, loopback);
}
static inline void enic_queue_wq_desc_tso(struct vnic_wq *wq,
void *os_buf, dma_addr_t dma_addr, unsigned int len,
unsigned int mss, unsigned int hdr_len, int vlan_tag_insert,
- unsigned int vlan_tag, int eop)
+ unsigned int vlan_tag, int eop, int loopback)
{
enic_queue_wq_desc_ex(wq, os_buf, dma_addr, len,
mss, hdr_len, vlan_tag_insert, vlan_tag,
WQ_ENET_OFFLOAD_MODE_TSO,
- eop, 1 /* SOP */, eop);
+ eop, 1 /* SOP */, eop, loopback);
}
static inline void enic_queue_rq_desc(struct vnic_rq *rq,
@@ -131,10 +132,8 @@ static inline void enic_queue_rq_desc(struct vnic_rq *rq,
struct enic;
int enic_get_vnic_config(struct enic *);
-void enic_add_multicast_addr(struct enic *enic, u8 *addr);
-void enic_del_multicast_addr(struct enic *enic, u8 *addr);
-void enic_add_vlan(struct enic *enic, u16 vlanid);
-void enic_del_vlan(struct enic *enic, u16 vlanid);
+int enic_add_vlan(struct enic *enic, u16 vlanid);
+int enic_del_vlan(struct enic *enic, u16 vlanid);
int enic_set_nic_cfg(struct enic *enic, u8 rss_default_cpu, u8 rss_hash_type,
u8 rss_hash_bits, u8 rss_base_cpu, u8 rss_enable, u8 tso_ipid_split_en,
u8 ig_vlan_strip_en);
diff --git a/drivers/net/enic/rq_enet_desc.h b/drivers/net/enic/rq_enet_desc.h
index a06e649010c..e6dd30988d6 100644
--- a/drivers/net/enic/rq_enet_desc.h
+++ b/drivers/net/enic/rq_enet_desc.h
@@ -1,5 +1,5 @@
/*
- * Copyright 2008 Cisco Systems, Inc. All rights reserved.
+ * Copyright 2008-2010 Cisco Systems, Inc. All rights reserved.
* Copyright 2007 Nuova Systems, Inc. All rights reserved.
*
* This program is free software; you may redistribute it and/or modify
diff --git a/drivers/net/enic/vnic_cq.c b/drivers/net/enic/vnic_cq.c
index 020ae6c3f3d..b86d6ef8dad 100644
--- a/drivers/net/enic/vnic_cq.c
+++ b/drivers/net/enic/vnic_cq.c
@@ -1,5 +1,5 @@
/*
- * Copyright 2008 Cisco Systems, Inc. All rights reserved.
+ * Copyright 2008-2010 Cisco Systems, Inc. All rights reserved.
* Copyright 2007 Nuova Systems, Inc. All rights reserved.
*
* This program is free software; you may redistribute it and/or modify
@@ -42,7 +42,7 @@ int vnic_cq_alloc(struct vnic_dev *vdev, struct vnic_cq *cq, unsigned int index,
cq->ctrl = vnic_dev_get_res(vdev, RES_TYPE_CQ, index);
if (!cq->ctrl) {
- printk(KERN_ERR "Failed to hook CQ[%d] resource\n", index);
+ pr_err("Failed to hook CQ[%d] resource\n", index);
return -EINVAL;
}
diff --git a/drivers/net/enic/vnic_cq.h b/drivers/net/enic/vnic_cq.h
index 114763cbc2f..552d3daf250 100644
--- a/drivers/net/enic/vnic_cq.h
+++ b/drivers/net/enic/vnic_cq.h
@@ -1,5 +1,5 @@
/*
- * Copyright 2008 Cisco Systems, Inc. All rights reserved.
+ * Copyright 2008-2010 Cisco Systems, Inc. All rights reserved.
* Copyright 2007 Nuova Systems, Inc. All rights reserved.
*
* This program is free software; you may redistribute it and/or modify
diff --git a/drivers/net/enic/vnic_dev.c b/drivers/net/enic/vnic_dev.c
index e0d33281ec9..6a5b578a69e 100644
--- a/drivers/net/enic/vnic_dev.c
+++ b/drivers/net/enic/vnic_dev.c
@@ -1,5 +1,5 @@
/*
- * Copyright 2008 Cisco Systems, Inc. All rights reserved.
+ * Copyright 2008-2010 Cisco Systems, Inc. All rights reserved.
* Copyright 2007 Nuova Systems, Inc. All rights reserved.
*
* This program is free software; you may redistribute it and/or modify
@@ -23,21 +23,23 @@
#include <linux/pci.h>
#include <linux/delay.h>
#include <linux/if_ether.h>
-#include <linux/slab.h>
#include "vnic_resource.h"
#include "vnic_devcmd.h"
#include "vnic_dev.h"
#include "vnic_stats.h"
+enum vnic_proxy_type {
+ PROXY_NONE,
+ PROXY_BY_BDF,
+};
+
struct vnic_res {
void __iomem *vaddr;
dma_addr_t bus_addr;
unsigned int count;
};
-#define VNIC_DEV_CAP_INIT 0x0001
-
struct vnic_dev {
void *priv;
struct pci_dev *pdev;
@@ -48,13 +50,14 @@ struct vnic_dev {
struct vnic_devcmd_notify notify_copy;
dma_addr_t notify_pa;
u32 notify_sz;
- u32 *linkstatus;
dma_addr_t linkstatus_pa;
struct vnic_stats *stats;
dma_addr_t stats_pa;
struct vnic_devcmd_fw_info *fw_info;
dma_addr_t fw_info_pa;
- u32 cap_flags;
+ enum vnic_proxy_type proxy;
+ u32 proxy_index;
+ u64 args[VNIC_DEVCMD_NARGS];
};
#define VNIC_MAX_RES_HDR_SIZE \
@@ -78,19 +81,19 @@ static int vnic_dev_discover_res(struct vnic_dev *vdev,
return -EINVAL;
if (bar->len < VNIC_MAX_RES_HDR_SIZE) {
- printk(KERN_ERR "vNIC BAR0 res hdr length error\n");
+ pr_err("vNIC BAR0 res hdr length error\n");
return -EINVAL;
}
rh = bar->vaddr;
if (!rh) {
- printk(KERN_ERR "vNIC BAR0 res hdr not mem-mapped\n");
+ pr_err("vNIC BAR0 res hdr not mem-mapped\n");
return -EINVAL;
}
if (ioread32(&rh->magic) != VNIC_RES_MAGIC ||
ioread32(&rh->version) != VNIC_RES_VERSION) {
- printk(KERN_ERR "vNIC BAR0 res magic/version error "
+ pr_err("vNIC BAR0 res magic/version error "
"exp (%lx/%lx) curr (%x/%x)\n",
VNIC_RES_MAGIC, VNIC_RES_VERSION,
ioread32(&rh->magic), ioread32(&rh->version));
@@ -122,7 +125,7 @@ static int vnic_dev_discover_res(struct vnic_dev *vdev,
/* each count is stride bytes long */
len = count * VNIC_RES_STRIDE;
if (len + bar_offset > bar[bar_num].len) {
- printk(KERN_ERR "vNIC BAR0 resource %d "
+ pr_err("vNIC BAR0 resource %d "
"out-of-bounds, offset 0x%x + "
"size 0x%x > bar len 0x%lx\n",
type, bar_offset,
@@ -229,8 +232,7 @@ int vnic_dev_alloc_desc_ring(struct vnic_dev *vdev, struct vnic_dev_ring *ring,
&ring->base_addr_unaligned);
if (!ring->descs_unaligned) {
- printk(KERN_ERR
- "Failed to allocate ring (size=%d), aborting\n",
+ pr_err("Failed to allocate ring (size=%d), aborting\n",
(int)ring->size);
return -ENOMEM;
}
@@ -258,23 +260,28 @@ void vnic_dev_free_desc_ring(struct vnic_dev *vdev, struct vnic_dev_ring *ring)
}
}
-int vnic_dev_cmd(struct vnic_dev *vdev, enum vnic_devcmd_cmd cmd,
- u64 *a0, u64 *a1, int wait)
+static int _vnic_dev_cmd(struct vnic_dev *vdev, enum vnic_devcmd_cmd cmd,
+ int wait)
{
struct vnic_devcmd __iomem *devcmd = vdev->devcmd;
+ unsigned int i;
int delay;
u32 status;
int err;
status = ioread32(&devcmd->status);
+ if (status == 0xFFFFFFFF) {
+ /* PCI-e target device is gone */
+ return -ENODEV;
+ }
if (status & STAT_BUSY) {
- printk(KERN_ERR "Busy devcmd %d\n", _CMD_N(cmd));
+ pr_err("Busy devcmd %d\n", _CMD_N(cmd));
return -EBUSY;
}
if (_CMD_DIR(cmd) & _CMD_DIR_WRITE) {
- writeq(*a0, &devcmd->args[0]);
- writeq(*a1, &devcmd->args[1]);
+ for (i = 0; i < VNIC_DEVCMD_NARGS; i++)
+ writeq(vdev->args[i], &devcmd->args[i]);
wmb();
}
@@ -288,31 +295,110 @@ int vnic_dev_cmd(struct vnic_dev *vdev, enum vnic_devcmd_cmd cmd,
udelay(100);
status = ioread32(&devcmd->status);
+ if (status == 0xFFFFFFFF) {
+ /* PCI-e target device is gone */
+ return -ENODEV;
+ }
+
if (!(status & STAT_BUSY)) {
if (status & STAT_ERROR) {
err = (int)readq(&devcmd->args[0]);
if (err != ERR_ECMDUNKNOWN ||
cmd != CMD_CAPABILITY)
- printk(KERN_ERR "Error %d devcmd %d\n",
+ pr_err("Error %d devcmd %d\n",
err, _CMD_N(cmd));
return err;
}
if (_CMD_DIR(cmd) & _CMD_DIR_READ) {
rmb();
- *a0 = readq(&devcmd->args[0]);
- *a1 = readq(&devcmd->args[1]);
+ for (i = 0; i < VNIC_DEVCMD_NARGS; i++)
+ vdev->args[i] = readq(&devcmd->args[i]);
}
return 0;
}
}
- printk(KERN_ERR "Timedout devcmd %d\n", _CMD_N(cmd));
+ pr_err("Timedout devcmd %d\n", _CMD_N(cmd));
return -ETIMEDOUT;
}
+static int vnic_dev_cmd_proxy_by_bdf(struct vnic_dev *vdev,
+ enum vnic_devcmd_cmd cmd, u64 *a0, u64 *a1, int wait)
+{
+ u32 status;
+ int err;
+
+ memset(vdev->args, 0, sizeof(vdev->args));
+
+ vdev->args[0] = vdev->proxy_index; /* bdf */
+ vdev->args[1] = cmd;
+ vdev->args[2] = *a0;
+ vdev->args[3] = *a1;
+
+ err = _vnic_dev_cmd(vdev, CMD_PROXY_BY_BDF, wait);
+ if (err)
+ return err;
+
+ status = (u32)vdev->args[0];
+ if (status & STAT_ERROR) {
+ err = (int)vdev->args[1];
+ if (err != ERR_ECMDUNKNOWN ||
+ cmd != CMD_CAPABILITY)
+ pr_err("Error %d proxy devcmd %d\n", err, _CMD_N(cmd));
+ return err;
+ }
+
+ *a0 = vdev->args[1];
+ *a1 = vdev->args[2];
+
+ return 0;
+}
+
+static int vnic_dev_cmd_no_proxy(struct vnic_dev *vdev,
+ enum vnic_devcmd_cmd cmd, u64 *a0, u64 *a1, int wait)
+{
+ int err;
+
+ vdev->args[0] = *a0;
+ vdev->args[1] = *a1;
+
+ err = _vnic_dev_cmd(vdev, cmd, wait);
+
+ *a0 = vdev->args[0];
+ *a1 = vdev->args[1];
+
+ return err;
+}
+
+void vnic_dev_cmd_proxy_by_bdf_start(struct vnic_dev *vdev, u16 bdf)
+{
+ vdev->proxy = PROXY_BY_BDF;
+ vdev->proxy_index = bdf;
+}
+
+void vnic_dev_cmd_proxy_end(struct vnic_dev *vdev)
+{
+ vdev->proxy = PROXY_NONE;
+ vdev->proxy_index = 0;
+}
+
+int vnic_dev_cmd(struct vnic_dev *vdev, enum vnic_devcmd_cmd cmd,
+ u64 *a0, u64 *a1, int wait)
+{
+ memset(vdev->args, 0, sizeof(vdev->args));
+
+ switch (vdev->proxy) {
+ case PROXY_BY_BDF:
+ return vnic_dev_cmd_proxy_by_bdf(vdev, cmd, a0, a1, wait);
+ case PROXY_NONE:
+ default:
+ return vnic_dev_cmd_no_proxy(vdev, cmd, a0, a1, wait);
+ }
+}
+
static int vnic_dev_capable(struct vnic_dev *vdev, enum vnic_devcmd_cmd cmd)
{
u64 a0 = (u32)cmd, a1 = 0;
@@ -431,6 +517,19 @@ int vnic_dev_enable(struct vnic_dev *vdev)
return vnic_dev_cmd(vdev, CMD_ENABLE, &a0, &a1, wait);
}
+int vnic_dev_enable_wait(struct vnic_dev *vdev)
+{
+ u64 a0 = 0, a1 = 0;
+ int wait = 1000;
+ int err;
+
+ err = vnic_dev_cmd(vdev, CMD_ENABLE_WAIT, &a0, &a1, wait);
+ if (err == ERR_ECMDUNKNOWN)
+ return vnic_dev_cmd(vdev, CMD_ENABLE, &a0, &a1, wait);
+
+ return err;
+}
+
int vnic_dev_disable(struct vnic_dev *vdev)
{
u64 a0 = 0, a1 = 0;
@@ -486,6 +585,44 @@ int vnic_dev_soft_reset_done(struct vnic_dev *vdev, int *done)
return 0;
}
+int vnic_dev_hang_reset(struct vnic_dev *vdev, int arg)
+{
+ u64 a0 = (u32)arg, a1 = 0;
+ int wait = 1000;
+ int err;
+
+ err = vnic_dev_cmd(vdev, CMD_HANG_RESET, &a0, &a1, wait);
+ if (err == ERR_ECMDUNKNOWN) {
+ err = vnic_dev_soft_reset(vdev, arg);
+ if (err)
+ return err;
+
+ return vnic_dev_init(vdev, 0);
+ }
+
+ return err;
+}
+
+int vnic_dev_hang_reset_done(struct vnic_dev *vdev, int *done)
+{
+ u64 a0 = 0, a1 = 0;
+ int wait = 1000;
+ int err;
+
+ *done = 0;
+
+ err = vnic_dev_cmd(vdev, CMD_HANG_RESET_STATUS, &a0, &a1, wait);
+ if (err) {
+ if (err == ERR_ECMDUNKNOWN)
+ return vnic_dev_soft_reset_done(vdev, done);
+ return err;
+ }
+
+ *done = (a0 == 0);
+
+ return 0;
+}
+
int vnic_dev_hang_notify(struct vnic_dev *vdev)
{
u64 a0, a1;
@@ -512,7 +649,7 @@ int vnic_dev_mac_addr(struct vnic_dev *vdev, u8 *mac_addr)
return 0;
}
-void vnic_dev_packet_filter(struct vnic_dev *vdev, int directed, int multicast,
+int vnic_dev_packet_filter(struct vnic_dev *vdev, int directed, int multicast,
int broadcast, int promisc, int allmulti)
{
u64 a0, a1 = 0;
@@ -527,7 +664,29 @@ void vnic_dev_packet_filter(struct vnic_dev *vdev, int directed, int multicast,
err = vnic_dev_cmd(vdev, CMD_PACKET_FILTER, &a0, &a1, wait);
if (err)
- printk(KERN_ERR "Can't set packet filter\n");
+ pr_err("Can't set packet filter\n");
+
+ return err;
+}
+
+int vnic_dev_packet_filter_all(struct vnic_dev *vdev, int directed,
+ int multicast, int broadcast, int promisc, int allmulti)
+{
+ u64 a0, a1 = 0;
+ int wait = 1000;
+ int err;
+
+ a0 = (directed ? CMD_PFILTER_DIRECTED : 0) |
+ (multicast ? CMD_PFILTER_MULTICAST : 0) |
+ (broadcast ? CMD_PFILTER_BROADCAST : 0) |
+ (promisc ? CMD_PFILTER_PROMISCUOUS : 0) |
+ (allmulti ? CMD_PFILTER_ALL_MULTICAST : 0);
+
+ err = vnic_dev_cmd(vdev, CMD_PACKET_FILTER_ALL, &a0, &a1, wait);
+ if (err)
+ pr_err("Can't set packet filter\n");
+
+ return err;
}
int vnic_dev_add_addr(struct vnic_dev *vdev, u8 *addr)
@@ -542,7 +701,7 @@ int vnic_dev_add_addr(struct vnic_dev *vdev, u8 *addr)
err = vnic_dev_cmd(vdev, CMD_ADDR_ADD, &a0, &a1, wait);
if (err)
- printk(KERN_ERR "Can't add addr [%pM], %d\n", addr, err);
+ pr_err("Can't add addr [%pM], %d\n", addr, err);
return err;
}
@@ -559,7 +718,21 @@ int vnic_dev_del_addr(struct vnic_dev *vdev, u8 *addr)
err = vnic_dev_cmd(vdev, CMD_ADDR_DEL, &a0, &a1, wait);
if (err)
- printk(KERN_ERR "Can't del addr [%pM], %d\n", addr, err);
+ pr_err("Can't del addr [%pM], %d\n", addr, err);
+
+ return err;
+}
+
+int vnic_dev_set_ig_vlan_rewrite_mode(struct vnic_dev *vdev,
+ u8 ig_vlan_rewrite_mode)
+{
+ u64 a0 = ig_vlan_rewrite_mode, a1 = 0;
+ int wait = 1000;
+ int err;
+
+ err = vnic_dev_cmd(vdev, CMD_IG_VLAN_REWRITE_MODE, &a0, &a1, wait);
+ if (err == ERR_ECMDUNKNOWN)
+ return 0;
return err;
}
@@ -572,8 +745,7 @@ int vnic_dev_raise_intr(struct vnic_dev *vdev, u16 intr)
err = vnic_dev_cmd(vdev, CMD_IAR, &a0, &a1, wait);
if (err)
- printk(KERN_ERR "Failed to raise INTR[%d], err %d\n",
- intr, err);
+ pr_err("Failed to raise INTR[%d], err %d\n", intr, err);
return err;
}
@@ -604,8 +776,7 @@ int vnic_dev_notify_set(struct vnic_dev *vdev, u16 intr)
dma_addr_t notify_pa;
if (vdev->notify || vdev->notify_pa) {
- printk(KERN_ERR "notify block %p still allocated",
- vdev->notify);
+ pr_err("notify block %p still allocated", vdev->notify);
return -EINVAL;
}
@@ -618,22 +789,25 @@ int vnic_dev_notify_set(struct vnic_dev *vdev, u16 intr)
return vnic_dev_notify_setcmd(vdev, notify_addr, notify_pa, intr);
}
-void vnic_dev_notify_unsetcmd(struct vnic_dev *vdev)
+int vnic_dev_notify_unsetcmd(struct vnic_dev *vdev)
{
u64 a0, a1;
int wait = 1000;
+ int err;
a0 = 0; /* paddr = 0 to unset notify buffer */
a1 = 0x0000ffff00000000ULL; /* intr num = -1 to unreg for intr */
a1 += sizeof(struct vnic_devcmd_notify);
- vnic_dev_cmd(vdev, CMD_NOTIFY, &a0, &a1, wait);
+ err = vnic_dev_cmd(vdev, CMD_NOTIFY, &a0, &a1, wait);
vdev->notify = NULL;
vdev->notify_pa = 0;
vdev->notify_sz = 0;
+
+ return err;
}
-void vnic_dev_notify_unset(struct vnic_dev *vdev)
+int vnic_dev_notify_unset(struct vnic_dev *vdev)
{
if (vdev->notify) {
pci_free_consistent(vdev->pdev,
@@ -642,7 +816,7 @@ void vnic_dev_notify_unset(struct vnic_dev *vdev)
vdev->notify_pa);
}
- vnic_dev_notify_unsetcmd(vdev);
+ return vnic_dev_notify_unsetcmd(vdev);
}
static int vnic_dev_notify_ready(struct vnic_dev *vdev)
@@ -672,13 +846,14 @@ int vnic_dev_init(struct vnic_dev *vdev, int arg)
int wait = 1000;
int r = 0;
- if (vdev->cap_flags & VNIC_DEV_CAP_INIT)
+ if (vnic_dev_capable(vdev, CMD_INIT))
r = vnic_dev_cmd(vdev, CMD_INIT, &a0, &a1, wait);
else {
vnic_dev_cmd(vdev, CMD_INIT_v1, &a0, &a1, wait);
if (a0 & CMD_INITF_DEFAULT_MAC) {
- // Emulate these for old CMD_INIT_v1 which
- // didn't pass a0 so no CMD_INITF_*.
+ /* Emulate these for old CMD_INIT_v1 which
+ * didn't pass a0 so no CMD_INITF_*.
+ */
vnic_dev_cmd(vdev, CMD_MAC_ADDR, &a0, &a1, wait);
vnic_dev_cmd(vdev, CMD_ADDR_ADD, &a0, &a1, wait);
}
@@ -700,7 +875,7 @@ int vnic_dev_init_done(struct vnic_dev *vdev, int *done, int *err)
*done = (a0 == 0);
- *err = (a0 == 0) ? a1 : 0;
+ *err = (a0 == 0) ? (int)a1:0;
return 0;
}
@@ -738,9 +913,6 @@ int vnic_dev_deinit(struct vnic_dev *vdev)
int vnic_dev_link_status(struct vnic_dev *vdev)
{
- if (vdev->linkstatus)
- return *vdev->linkstatus;
-
if (!vnic_dev_notify_ready(vdev))
return 0;
@@ -787,6 +959,14 @@ u32 vnic_dev_notify_status(struct vnic_dev *vdev)
return vdev->notify_copy.status;
}
+u32 vnic_dev_uif(struct vnic_dev *vdev)
+{
+ if (!vnic_dev_notify_ready(vdev))
+ return 0;
+
+ return vdev->notify_copy.uif;
+}
+
void vnic_dev_set_intr_mode(struct vnic_dev *vdev,
enum vnic_dev_intr_mode intr_mode)
{
@@ -807,14 +987,9 @@ void vnic_dev_unregister(struct vnic_dev *vdev)
sizeof(struct vnic_devcmd_notify),
vdev->notify,
vdev->notify_pa);
- if (vdev->linkstatus)
- pci_free_consistent(vdev->pdev,
- sizeof(u32),
- vdev->linkstatus,
- vdev->linkstatus_pa);
if (vdev->stats)
pci_free_consistent(vdev->pdev,
- sizeof(struct vnic_dev),
+ sizeof(struct vnic_stats),
vdev->stats, vdev->stats_pa);
if (vdev->fw_info)
pci_free_consistent(vdev->pdev,
@@ -844,11 +1019,6 @@ struct vnic_dev *vnic_dev_register(struct vnic_dev *vdev,
if (!vdev->devcmd)
goto err_out;
- vdev->cap_flags = 0;
-
- if (vnic_dev_capable(vdev, CMD_INIT))
- vdev->cap_flags |= VNIC_DEV_CAP_INIT;
-
return vdev;
err_out:
diff --git a/drivers/net/enic/vnic_dev.h b/drivers/net/enic/vnic_dev.h
index caccce36957..3a61873138b 100644
--- a/drivers/net/enic/vnic_dev.h
+++ b/drivers/net/enic/vnic_dev.h
@@ -1,5 +1,5 @@
/*
- * Copyright 2008 Cisco Systems, Inc. All rights reserved.
+ * Copyright 2008-2010 Cisco Systems, Inc. All rights reserved.
* Copyright 2007 Nuova Systems, Inc. All rights reserved.
*
* This program is free software; you may redistribute it and/or modify
@@ -41,6 +41,9 @@ static inline void writeq(u64 val, void __iomem *reg)
}
#endif
+#undef pr_fmt
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
enum vnic_dev_hw_version {
VNIC_DEV_HW_VER_UNKNOWN,
VNIC_DEV_HW_VER_A1,
@@ -92,6 +95,8 @@ void vnic_dev_free_desc_ring(struct vnic_dev *vdev,
struct vnic_dev_ring *ring);
int vnic_dev_cmd(struct vnic_dev *vdev, enum vnic_devcmd_cmd cmd,
u64 *a0, u64 *a1, int wait);
+void vnic_dev_cmd_proxy_by_bdf_start(struct vnic_dev *vdev, u16 bdf);
+void vnic_dev_cmd_proxy_end(struct vnic_dev *vdev);
int vnic_dev_fw_info(struct vnic_dev *vdev,
struct vnic_devcmd_fw_info **fw_info);
int vnic_dev_hw_version(struct vnic_dev *vdev,
@@ -101,8 +106,10 @@ int vnic_dev_spec(struct vnic_dev *vdev, unsigned int offset, unsigned int size,
int vnic_dev_stats_clear(struct vnic_dev *vdev);
int vnic_dev_stats_dump(struct vnic_dev *vdev, struct vnic_stats **stats);
int vnic_dev_hang_notify(struct vnic_dev *vdev);
-void vnic_dev_packet_filter(struct vnic_dev *vdev, int directed, int multicast,
+int vnic_dev_packet_filter(struct vnic_dev *vdev, int directed, int multicast,
int broadcast, int promisc, int allmulti);
+int vnic_dev_packet_filter_all(struct vnic_dev *vdev, int directed,
+ int multicast, int broadcast, int promisc, int allmulti);
int vnic_dev_add_addr(struct vnic_dev *vdev, u8 *addr);
int vnic_dev_del_addr(struct vnic_dev *vdev, u8 *addr);
int vnic_dev_mac_addr(struct vnic_dev *vdev, u8 *mac_addr);
@@ -110,16 +117,18 @@ int vnic_dev_raise_intr(struct vnic_dev *vdev, u16 intr);
int vnic_dev_notify_setcmd(struct vnic_dev *vdev,
void *notify_addr, dma_addr_t notify_pa, u16 intr);
int vnic_dev_notify_set(struct vnic_dev *vdev, u16 intr);
-void vnic_dev_notify_unsetcmd(struct vnic_dev *vdev);
-void vnic_dev_notify_unset(struct vnic_dev *vdev);
+int vnic_dev_notify_unsetcmd(struct vnic_dev *vdev);
+int vnic_dev_notify_unset(struct vnic_dev *vdev);
int vnic_dev_link_status(struct vnic_dev *vdev);
u32 vnic_dev_port_speed(struct vnic_dev *vdev);
u32 vnic_dev_msg_lvl(struct vnic_dev *vdev);
u32 vnic_dev_mtu(struct vnic_dev *vdev);
u32 vnic_dev_link_down_cnt(struct vnic_dev *vdev);
u32 vnic_dev_notify_status(struct vnic_dev *vdev);
+u32 vnic_dev_uif(struct vnic_dev *vdev);
int vnic_dev_close(struct vnic_dev *vdev);
int vnic_dev_enable(struct vnic_dev *vdev);
+int vnic_dev_enable_wait(struct vnic_dev *vdev);
int vnic_dev_disable(struct vnic_dev *vdev);
int vnic_dev_open(struct vnic_dev *vdev, int arg);
int vnic_dev_open_done(struct vnic_dev *vdev, int *done);
@@ -129,10 +138,14 @@ int vnic_dev_init_prov(struct vnic_dev *vdev, u8 *buf, u32 len);
int vnic_dev_deinit(struct vnic_dev *vdev);
int vnic_dev_soft_reset(struct vnic_dev *vdev, int arg);
int vnic_dev_soft_reset_done(struct vnic_dev *vdev, int *done);
+int vnic_dev_hang_reset(struct vnic_dev *vdev, int arg);
+int vnic_dev_hang_reset_done(struct vnic_dev *vdev, int *done);
void vnic_dev_set_intr_mode(struct vnic_dev *vdev,
enum vnic_dev_intr_mode intr_mode);
enum vnic_dev_intr_mode vnic_dev_get_intr_mode(struct vnic_dev *vdev);
void vnic_dev_unregister(struct vnic_dev *vdev);
+int vnic_dev_set_ig_vlan_rewrite_mode(struct vnic_dev *vdev,
+ u8 ig_vlan_rewrite_mode);
struct vnic_dev *vnic_dev_register(struct vnic_dev *vdev,
void *priv, struct pci_dev *pdev, struct vnic_dev_bar *bar,
unsigned int num_bars);
diff --git a/drivers/net/enic/vnic_devcmd.h b/drivers/net/enic/vnic_devcmd.h
index d78bbcc1fdf..20661755df6 100644
--- a/drivers/net/enic/vnic_devcmd.h
+++ b/drivers/net/enic/vnic_devcmd.h
@@ -1,5 +1,5 @@
/*
- * Copyright 2008 Cisco Systems, Inc. All rights reserved.
+ * Copyright 2008-2010 Cisco Systems, Inc. All rights reserved.
* Copyright 2007 Nuova Systems, Inc. All rights reserved.
*
* This program is free software; you may redistribute it and/or modify
@@ -98,6 +98,9 @@ enum vnic_devcmd_cmd {
/* set Rx packet filter: (u32)a0=filters (see CMD_PFILTER_*) */
CMD_PACKET_FILTER = _CMDCNW(_CMD_DIR_WRITE, _CMD_VTYPE_ENET, 7),
+ /* set Rx packet filter for all: (u32)a0=filters (see CMD_PFILTER_*) */
+ CMD_PACKET_FILTER_ALL = _CMDCNW(_CMD_DIR_WRITE, _CMD_VTYPE_ALL, 7),
+
/* hang detection notification */
CMD_HANG_NOTIFY = _CMDC(_CMD_DIR_NONE, _CMD_VTYPE_ALL, 8),
@@ -171,6 +174,9 @@ enum vnic_devcmd_cmd {
/* enable virtual link */
CMD_ENABLE = _CMDCNW(_CMD_DIR_WRITE, _CMD_VTYPE_ALL, 28),
+ /* enable virtual link, waiting variant. */
+ CMD_ENABLE_WAIT = _CMDC(_CMD_DIR_WRITE, _CMD_VTYPE_ALL, 28),
+
/* disable virtual link */
CMD_DISABLE = _CMDC(_CMD_DIR_NONE, _CMD_VTYPE_ALL, 29),
@@ -211,6 +217,27 @@ enum vnic_devcmd_cmd {
* in: (u16)a0=interrupt number to assert
*/
CMD_IAR = _CMDCNW(_CMD_DIR_WRITE, _CMD_VTYPE_ALL, 38),
+
+ /* initiate hangreset, like softreset after hang detected */
+ CMD_HANG_RESET = _CMDC(_CMD_DIR_NONE, _CMD_VTYPE_ALL, 39),
+
+ /* hangreset status:
+ * out: a0=0 reset complete, a0=1 reset in progress */
+ CMD_HANG_RESET_STATUS = _CMDC(_CMD_DIR_READ, _CMD_VTYPE_ALL, 40),
+
+ /*
+ * Set hw ingress packet vlan rewrite mode:
+ * in: (u32)a0=new vlan rewrite mode
+ * out: (u32)a0=old vlan rewrite mode */
+ CMD_IG_VLAN_REWRITE_MODE = _CMDC(_CMD_DIR_RW, _CMD_VTYPE_ENET, 41),
+
+ /*
+ * in: (u16)a0=bdf of target vnic
+ * (u32)a1=cmd to proxy
+ * a2-a15=args to cmd in a1
+ * out: (u32)a0=status of proxied cmd
+ * a1-a15=out args of proxied cmd */
+ CMD_PROXY_BY_BDF = _CMDC(_CMD_DIR_RW, _CMD_VTYPE_ALL, 42),
};
/* flags for CMD_OPEN */
@@ -226,6 +253,12 @@ enum vnic_devcmd_cmd {
#define CMD_PFILTER_PROMISCUOUS 0x08
#define CMD_PFILTER_ALL_MULTICAST 0x10
+/* rewrite modes for CMD_IG_VLAN_REWRITE_MODE */
+#define IG_VLAN_REWRITE_MODE_DEFAULT_TRUNK 0
+#define IG_VLAN_REWRITE_MODE_UNTAG_DEFAULT_VLAN 1
+#define IG_VLAN_REWRITE_MODE_PRIORITY_TAG_DEFAULT_VLAN 2
+#define IG_VLAN_REWRITE_MODE_PASS_THRU 3
+
enum vnic_devcmd_status {
STAT_NONE = 0,
STAT_BUSY = 1 << 0, /* cmd in progress */
diff --git a/drivers/net/enic/vnic_enet.h b/drivers/net/enic/vnic_enet.h
index 8eeb6758491..3b329124895 100644
--- a/drivers/net/enic/vnic_enet.h
+++ b/drivers/net/enic/vnic_enet.h
@@ -1,5 +1,5 @@
/*
- * Copyright 2008 Cisco Systems, Inc. All rights reserved.
+ * Copyright 2008-2010 Cisco Systems, Inc. All rights reserved.
* Copyright 2007 Nuova Systems, Inc. All rights reserved.
*
* This program is free software; you may redistribute it and/or modify
@@ -35,6 +35,7 @@ struct vnic_enet_config {
u8 intr_mode;
char devname[16];
u32 intr_timer_usec;
+ u16 loop_tag;
};
#define VENETF_TSO 0x1 /* TSO enabled */
@@ -48,5 +49,6 @@ struct vnic_enet_config {
#define VENETF_RSSHASH_TCPIPV6 0x100 /* Hash on TCP + IPv6 fields */
#define VENETF_RSSHASH_IPV6_EX 0x200 /* Hash on IPv6 extended fields */
#define VENETF_RSSHASH_TCPIPV6_EX 0x400 /* Hash on TCP + IPv6 ext. fields */
+#define VENETF_LOOP 0x800 /* Loopback enabled */
#endif /* _VNIC_ENIC_H_ */
diff --git a/drivers/net/enic/vnic_intr.c b/drivers/net/enic/vnic_intr.c
index 3934309a949..52ab61af275 100644
--- a/drivers/net/enic/vnic_intr.c
+++ b/drivers/net/enic/vnic_intr.c
@@ -1,5 +1,5 @@
/*
- * Copyright 2008 Cisco Systems, Inc. All rights reserved.
+ * Copyright 2008-2010 Cisco Systems, Inc. All rights reserved.
* Copyright 2007 Nuova Systems, Inc. All rights reserved.
*
* This program is free software; you may redistribute it and/or modify
@@ -39,8 +39,7 @@ int vnic_intr_alloc(struct vnic_dev *vdev, struct vnic_intr *intr,
intr->ctrl = vnic_dev_get_res(vdev, RES_TYPE_INTR_CTRL, index);
if (!intr->ctrl) {
- printk(KERN_ERR "Failed to hook INTR[%d].ctrl resource\n",
- index);
+ pr_err("Failed to hook INTR[%d].ctrl resource\n", index);
return -EINVAL;
}
diff --git a/drivers/net/enic/vnic_intr.h b/drivers/net/enic/vnic_intr.h
index 2fe6c6339e3..09dc0b73ff4 100644
--- a/drivers/net/enic/vnic_intr.h
+++ b/drivers/net/enic/vnic_intr.h
@@ -1,5 +1,5 @@
/*
- * Copyright 2008 Cisco Systems, Inc. All rights reserved.
+ * Copyright 2008-2010 Cisco Systems, Inc. All rights reserved.
* Copyright 2007 Nuova Systems, Inc. All rights reserved.
*
* This program is free software; you may redistribute it and/or modify
@@ -61,7 +61,11 @@ static inline void vnic_intr_unmask(struct vnic_intr *intr)
static inline void vnic_intr_mask(struct vnic_intr *intr)
{
iowrite32(1, &intr->ctrl->mask);
- (void)ioread32(&intr->ctrl->mask);
+}
+
+static inline int vnic_intr_masked(struct vnic_intr *intr)
+{
+ return ioread32(&intr->ctrl->mask);
}
static inline void vnic_intr_return_credits(struct vnic_intr *intr,
diff --git a/drivers/net/enic/vnic_nic.h b/drivers/net/enic/vnic_nic.h
index cf80ab46d58..995a50dd4c9 100644
--- a/drivers/net/enic/vnic_nic.h
+++ b/drivers/net/enic/vnic_nic.h
@@ -1,5 +1,5 @@
/*
- * Copyright 2008 Cisco Systems, Inc. All rights reserved.
+ * Copyright 2008-2010 Cisco Systems, Inc. All rights reserved.
* Copyright 2007 Nuova Systems, Inc. All rights reserved.
*
* This program is free software; you may redistribute it and/or modify
diff --git a/drivers/net/enic/vnic_resource.h b/drivers/net/enic/vnic_resource.h
index b61c22aec41..810287beff1 100644
--- a/drivers/net/enic/vnic_resource.h
+++ b/drivers/net/enic/vnic_resource.h
@@ -1,5 +1,5 @@
/*
- * Copyright 2008 Cisco Systems, Inc. All rights reserved.
+ * Copyright 2008-2010 Cisco Systems, Inc. All rights reserved.
* Copyright 2007 Nuova Systems, Inc. All rights reserved.
*
* This program is free software; you may redistribute it and/or modify
diff --git a/drivers/net/enic/vnic_rq.c b/drivers/net/enic/vnic_rq.c
index cc580cfec41..dbb2aca258b 100644
--- a/drivers/net/enic/vnic_rq.c
+++ b/drivers/net/enic/vnic_rq.c
@@ -1,5 +1,5 @@
/*
- * Copyright 2008 Cisco Systems, Inc. All rights reserved.
+ * Copyright 2008-2010 Cisco Systems, Inc. All rights reserved.
* Copyright 2007 Nuova Systems, Inc. All rights reserved.
*
* This program is free software; you may redistribute it and/or modify
@@ -37,23 +37,23 @@ static int vnic_rq_alloc_bufs(struct vnic_rq *rq)
vdev = rq->vdev;
for (i = 0; i < blks; i++) {
- rq->bufs[i] = kzalloc(VNIC_RQ_BUF_BLK_SZ, GFP_ATOMIC);
+ rq->bufs[i] = kzalloc(VNIC_RQ_BUF_BLK_SZ(count), GFP_ATOMIC);
if (!rq->bufs[i]) {
- printk(KERN_ERR "Failed to alloc rq_bufs\n");
+ pr_err("Failed to alloc rq_bufs\n");
return -ENOMEM;
}
}
for (i = 0; i < blks; i++) {
buf = rq->bufs[i];
- for (j = 0; j < VNIC_RQ_BUF_BLK_ENTRIES; j++) {
- buf->index = i * VNIC_RQ_BUF_BLK_ENTRIES + j;
+ for (j = 0; j < VNIC_RQ_BUF_BLK_ENTRIES(count); j++) {
+ buf->index = i * VNIC_RQ_BUF_BLK_ENTRIES(count) + j;
buf->desc = (u8 *)rq->ring.descs +
rq->ring.desc_size * buf->index;
if (buf->index + 1 == count) {
buf->next = rq->bufs[0];
break;
- } else if (j + 1 == VNIC_RQ_BUF_BLK_ENTRIES) {
+ } else if (j + 1 == VNIC_RQ_BUF_BLK_ENTRIES(count)) {
buf->next = rq->bufs[i + 1];
} else {
buf->next = buf + 1;
@@ -94,7 +94,7 @@ int vnic_rq_alloc(struct vnic_dev *vdev, struct vnic_rq *rq, unsigned int index,
rq->ctrl = vnic_dev_get_res(vdev, RES_TYPE_RQ, index);
if (!rq->ctrl) {
- printk(KERN_ERR "Failed to hook RQ[%d] resource\n", index);
+ pr_err("Failed to hook RQ[%d] resource\n", index);
return -EINVAL;
}
@@ -119,10 +119,11 @@ void vnic_rq_init_start(struct vnic_rq *rq, unsigned int cq_index,
unsigned int error_interrupt_offset)
{
u64 paddr;
+ unsigned int count = rq->ring.desc_count;
paddr = (u64)rq->ring.base_addr | VNIC_PADDR_TARGET;
writeq(paddr, &rq->ctrl->ring_base);
- iowrite32(rq->ring.desc_count, &rq->ctrl->ring_size);
+ iowrite32(count, &rq->ctrl->ring_size);
iowrite32(cq_index, &rq->ctrl->cq_index);
iowrite32(error_interrupt_enable, &rq->ctrl->error_interrupt_enable);
iowrite32(error_interrupt_offset, &rq->ctrl->error_interrupt_offset);
@@ -132,8 +133,8 @@ void vnic_rq_init_start(struct vnic_rq *rq, unsigned int cq_index,
iowrite32(posted_index, &rq->ctrl->posted_index);
rq->to_use = rq->to_clean =
- &rq->bufs[fetch_index / VNIC_RQ_BUF_BLK_ENTRIES]
- [fetch_index % VNIC_RQ_BUF_BLK_ENTRIES];
+ &rq->bufs[fetch_index / VNIC_RQ_BUF_BLK_ENTRIES(count)]
+ [fetch_index % VNIC_RQ_BUF_BLK_ENTRIES(count)];
}
void vnic_rq_init(struct vnic_rq *rq, unsigned int cq_index,
@@ -145,6 +146,11 @@ void vnic_rq_init(struct vnic_rq *rq, unsigned int cq_index,
/* Use current fetch_index as the ring starting point */
fetch_index = ioread32(&rq->ctrl->fetch_index);
+ if (fetch_index == 0xFFFFFFFF) { /* check for hardware gone */
+ /* Hardware surprise removal: reset fetch_index */
+ fetch_index = 0;
+ }
+
vnic_rq_init_start(rq, cq_index,
fetch_index, fetch_index,
error_interrupt_enable,
@@ -174,7 +180,7 @@ int vnic_rq_disable(struct vnic_rq *rq)
udelay(10);
}
- printk(KERN_ERR "Failed to disable RQ[%d]\n", rq->index);
+ pr_err("Failed to disable RQ[%d]\n", rq->index);
return -ETIMEDOUT;
}
@@ -184,8 +190,7 @@ void vnic_rq_clean(struct vnic_rq *rq,
{
struct vnic_rq_buf *buf;
u32 fetch_index;
-
- BUG_ON(ioread32(&rq->ctrl->enable));
+ unsigned int count = rq->ring.desc_count;
buf = rq->to_clean;
@@ -199,9 +204,14 @@ void vnic_rq_clean(struct vnic_rq *rq,
/* Use current fetch_index as the ring starting point */
fetch_index = ioread32(&rq->ctrl->fetch_index);
+
+ if (fetch_index == 0xFFFFFFFF) { /* check for hardware gone */
+ /* Hardware surprise removal: reset fetch_index */
+ fetch_index = 0;
+ }
rq->to_use = rq->to_clean =
- &rq->bufs[fetch_index / VNIC_RQ_BUF_BLK_ENTRIES]
- [fetch_index % VNIC_RQ_BUF_BLK_ENTRIES];
+ &rq->bufs[fetch_index / VNIC_RQ_BUF_BLK_ENTRIES(count)]
+ [fetch_index % VNIC_RQ_BUF_BLK_ENTRIES(count)];
iowrite32(fetch_index, &rq->ctrl->posted_index);
vnic_dev_clear_desc_ring(&rq->ring);
diff --git a/drivers/net/enic/vnic_rq.h b/drivers/net/enic/vnic_rq.h
index 35e736cc2d8..2dc48f91abf 100644
--- a/drivers/net/enic/vnic_rq.h
+++ b/drivers/net/enic/vnic_rq.h
@@ -1,5 +1,5 @@
/*
- * Copyright 2008, 2009 Cisco Systems, Inc. All rights reserved.
+ * Copyright 2008-2010 Cisco Systems, Inc. All rights reserved.
* Copyright 2007 Nuova Systems, Inc. All rights reserved.
*
* This program is free software; you may redistribute it and/or modify
@@ -52,12 +52,16 @@ struct vnic_rq_ctrl {
u32 pad10;
};
-/* Break the vnic_rq_buf allocations into blocks of 64 entries */
-#define VNIC_RQ_BUF_BLK_ENTRIES 64
-#define VNIC_RQ_BUF_BLK_SZ \
- (VNIC_RQ_BUF_BLK_ENTRIES * sizeof(struct vnic_rq_buf))
+/* Break the vnic_rq_buf allocations into blocks of 32/64 entries */
+#define VNIC_RQ_BUF_MIN_BLK_ENTRIES 32
+#define VNIC_RQ_BUF_DFLT_BLK_ENTRIES 64
+#define VNIC_RQ_BUF_BLK_ENTRIES(entries) \
+ ((unsigned int)((entries < VNIC_RQ_BUF_DFLT_BLK_ENTRIES) ? \
+ VNIC_RQ_BUF_MIN_BLK_ENTRIES : VNIC_RQ_BUF_DFLT_BLK_ENTRIES))
+#define VNIC_RQ_BUF_BLK_SZ(entries) \
+ (VNIC_RQ_BUF_BLK_ENTRIES(entries) * sizeof(struct vnic_rq_buf))
#define VNIC_RQ_BUF_BLKS_NEEDED(entries) \
- DIV_ROUND_UP(entries, VNIC_RQ_BUF_BLK_ENTRIES)
+ DIV_ROUND_UP(entries, VNIC_RQ_BUF_BLK_ENTRIES(entries))
#define VNIC_RQ_BUF_BLKS_MAX VNIC_RQ_BUF_BLKS_NEEDED(4096)
struct vnic_rq_buf {
diff --git a/drivers/net/enic/vnic_rss.h b/drivers/net/enic/vnic_rss.h
index 5fbb3c923bc..f62d1871962 100644
--- a/drivers/net/enic/vnic_rss.h
+++ b/drivers/net/enic/vnic_rss.h
@@ -1,5 +1,5 @@
/*
- * Copyright 2008 Cisco Systems, Inc. All rights reserved.
+ * Copyright 2008-2010 Cisco Systems, Inc. All rights reserved.
* Copyright 2007 Nuova Systems, Inc. All rights reserved.
*
* This program is free software; you may redistribute it and/or modify
diff --git a/drivers/net/enic/vnic_stats.h b/drivers/net/enic/vnic_stats.h
index 9ff9614d89b..77750ec9395 100644
--- a/drivers/net/enic/vnic_stats.h
+++ b/drivers/net/enic/vnic_stats.h
@@ -1,5 +1,5 @@
/*
- * Copyright 2008 Cisco Systems, Inc. All rights reserved.
+ * Copyright 2008-2010 Cisco Systems, Inc. All rights reserved.
* Copyright 2007 Nuova Systems, Inc. All rights reserved.
*
* This program is free software; you may redistribute it and/or modify
diff --git a/drivers/net/enic/vnic_vic.c b/drivers/net/enic/vnic_vic.c
index d769772998c..197c9d24af8 100644
--- a/drivers/net/enic/vnic_vic.c
+++ b/drivers/net/enic/vnic_vic.c
@@ -25,9 +25,13 @@
struct vic_provinfo *vic_provinfo_alloc(gfp_t flags, u8 *oui, u8 type)
{
- struct vic_provinfo *vp = kzalloc(VIC_PROVINFO_MAX_DATA, flags);
+ struct vic_provinfo *vp;
- if (!vp || !oui)
+ if (!oui)
+ return NULL;
+
+ vp = kzalloc(VIC_PROVINFO_MAX_DATA, flags);
+ if (!vp)
return NULL;
memcpy(vp->oui, oui, sizeof(vp->oui));
diff --git a/drivers/net/enic/vnic_vic.h b/drivers/net/enic/vnic_vic.h
index 085c2a274cb..7e46e5e8600 100644
--- a/drivers/net/enic/vnic_vic.h
+++ b/drivers/net/enic/vnic_vic.h
@@ -44,7 +44,7 @@ struct vic_provinfo {
u16 length;
u8 value[0];
} tlv[0];
-} __attribute__ ((packed));
+} __packed;
#define VIC_PROVINFO_MAX_DATA 1385
#define VIC_PROVINFO_MAX_TLV_DATA (VIC_PROVINFO_MAX_DATA - \
diff --git a/drivers/net/enic/vnic_wq.c b/drivers/net/enic/vnic_wq.c
index 1378afbdfe6..122e33bcc57 100644
--- a/drivers/net/enic/vnic_wq.c
+++ b/drivers/net/enic/vnic_wq.c
@@ -1,5 +1,5 @@
/*
- * Copyright 2008 Cisco Systems, Inc. All rights reserved.
+ * Copyright 2008-2010 Cisco Systems, Inc. All rights reserved.
* Copyright 2007 Nuova Systems, Inc. All rights reserved.
*
* This program is free software; you may redistribute it and/or modify
@@ -37,23 +37,23 @@ static int vnic_wq_alloc_bufs(struct vnic_wq *wq)
vdev = wq->vdev;
for (i = 0; i < blks; i++) {
- wq->bufs[i] = kzalloc(VNIC_WQ_BUF_BLK_SZ, GFP_ATOMIC);
+ wq->bufs[i] = kzalloc(VNIC_WQ_BUF_BLK_SZ(count), GFP_ATOMIC);
if (!wq->bufs[i]) {
- printk(KERN_ERR "Failed to alloc wq_bufs\n");
+ pr_err("Failed to alloc wq_bufs\n");
return -ENOMEM;
}
}
for (i = 0; i < blks; i++) {
buf = wq->bufs[i];
- for (j = 0; j < VNIC_WQ_BUF_BLK_ENTRIES; j++) {
- buf->index = i * VNIC_WQ_BUF_BLK_ENTRIES + j;
+ for (j = 0; j < VNIC_WQ_BUF_BLK_ENTRIES(count); j++) {
+ buf->index = i * VNIC_WQ_BUF_BLK_ENTRIES(count) + j;
buf->desc = (u8 *)wq->ring.descs +
wq->ring.desc_size * buf->index;
if (buf->index + 1 == count) {
buf->next = wq->bufs[0];
break;
- } else if (j + 1 == VNIC_WQ_BUF_BLK_ENTRIES) {
+ } else if (j + 1 == VNIC_WQ_BUF_BLK_ENTRIES(count)) {
buf->next = wq->bufs[i + 1];
} else {
buf->next = buf + 1;
@@ -94,7 +94,7 @@ int vnic_wq_alloc(struct vnic_dev *vdev, struct vnic_wq *wq, unsigned int index,
wq->ctrl = vnic_dev_get_res(vdev, RES_TYPE_WQ, index);
if (!wq->ctrl) {
- printk(KERN_ERR "Failed to hook WQ[%d] resource\n", index);
+ pr_err("Failed to hook WQ[%d] resource\n", index);
return -EINVAL;
}
@@ -119,10 +119,11 @@ void vnic_wq_init_start(struct vnic_wq *wq, unsigned int cq_index,
unsigned int error_interrupt_offset)
{
u64 paddr;
+ unsigned int count = wq->ring.desc_count;
paddr = (u64)wq->ring.base_addr | VNIC_PADDR_TARGET;
writeq(paddr, &wq->ctrl->ring_base);
- iowrite32(wq->ring.desc_count, &wq->ctrl->ring_size);
+ iowrite32(count, &wq->ctrl->ring_size);
iowrite32(fetch_index, &wq->ctrl->fetch_index);
iowrite32(posted_index, &wq->ctrl->posted_index);
iowrite32(cq_index, &wq->ctrl->cq_index);
@@ -131,8 +132,8 @@ void vnic_wq_init_start(struct vnic_wq *wq, unsigned int cq_index,
iowrite32(0, &wq->ctrl->error_status);
wq->to_use = wq->to_clean =
- &wq->bufs[fetch_index / VNIC_WQ_BUF_BLK_ENTRIES]
- [fetch_index % VNIC_WQ_BUF_BLK_ENTRIES];
+ &wq->bufs[fetch_index / VNIC_WQ_BUF_BLK_ENTRIES(count)]
+ [fetch_index % VNIC_WQ_BUF_BLK_ENTRIES(count)];
}
void vnic_wq_init(struct vnic_wq *wq, unsigned int cq_index,
@@ -167,7 +168,7 @@ int vnic_wq_disable(struct vnic_wq *wq)
udelay(10);
}
- printk(KERN_ERR "Failed to disable WQ[%d]\n", wq->index);
+ pr_err("Failed to disable WQ[%d]\n", wq->index);
return -ETIMEDOUT;
}
@@ -177,8 +178,6 @@ void vnic_wq_clean(struct vnic_wq *wq,
{
struct vnic_wq_buf *buf;
- BUG_ON(ioread32(&wq->ctrl->enable));
-
buf = wq->to_clean;
while (vnic_wq_desc_used(wq) > 0) {
diff --git a/drivers/net/enic/vnic_wq.h b/drivers/net/enic/vnic_wq.h
index 9c34d41a887..94ac4621acc 100644
--- a/drivers/net/enic/vnic_wq.h
+++ b/drivers/net/enic/vnic_wq.h
@@ -1,5 +1,5 @@
/*
- * Copyright 2008 Cisco Systems, Inc. All rights reserved.
+ * Copyright 2008-2010 Cisco Systems, Inc. All rights reserved.
* Copyright 2007 Nuova Systems, Inc. All rights reserved.
*
* This program is free software; you may redistribute it and/or modify
@@ -60,12 +60,16 @@ struct vnic_wq_buf {
void *desc;
};
-/* Break the vnic_wq_buf allocations into blocks of 64 entries */
-#define VNIC_WQ_BUF_BLK_ENTRIES 64
-#define VNIC_WQ_BUF_BLK_SZ \
- (VNIC_WQ_BUF_BLK_ENTRIES * sizeof(struct vnic_wq_buf))
+/* Break the vnic_wq_buf allocations into blocks of 32/64 entries */
+#define VNIC_WQ_BUF_MIN_BLK_ENTRIES 32
+#define VNIC_WQ_BUF_DFLT_BLK_ENTRIES 64
+#define VNIC_WQ_BUF_BLK_ENTRIES(entries) \
+ ((unsigned int)((entries < VNIC_WQ_BUF_DFLT_BLK_ENTRIES) ? \
+ VNIC_WQ_BUF_MIN_BLK_ENTRIES : VNIC_WQ_BUF_DFLT_BLK_ENTRIES))
+#define VNIC_WQ_BUF_BLK_SZ(entries) \
+ (VNIC_WQ_BUF_BLK_ENTRIES(entries) * sizeof(struct vnic_wq_buf))
#define VNIC_WQ_BUF_BLKS_NEEDED(entries) \
- DIV_ROUND_UP(entries, VNIC_WQ_BUF_BLK_ENTRIES)
+ DIV_ROUND_UP(entries, VNIC_WQ_BUF_BLK_ENTRIES(entries))
#define VNIC_WQ_BUF_BLKS_MAX VNIC_WQ_BUF_BLKS_NEEDED(4096)
struct vnic_wq {
diff --git a/drivers/net/enic/wq_enet_desc.h b/drivers/net/enic/wq_enet_desc.h
index 483596c2d8b..c7021e3a631 100644
--- a/drivers/net/enic/wq_enet_desc.h
+++ b/drivers/net/enic/wq_enet_desc.h
@@ -1,5 +1,5 @@
/*
- * Copyright 2008 Cisco Systems, Inc. All rights reserved.
+ * Copyright 2008-2010 Cisco Systems, Inc. All rights reserved.
* Copyright 2007 Nuova Systems, Inc. All rights reserved.
*
* This program is free software; you may redistribute it and/or modify
diff --git a/drivers/net/epic100.c b/drivers/net/epic100.c
index 4c274657283..57c8ac0ef3f 100644
--- a/drivers/net/epic100.c
+++ b/drivers/net/epic100.c
@@ -278,7 +278,6 @@ struct epic_private {
struct pci_dev *pci_dev; /* PCI bus location. */
int chip_id, chip_flags;
- struct net_device_stats stats;
struct timer_list timer; /* Media selection timer. */
int tx_threshold;
unsigned char mc_filter[8];
@@ -770,7 +769,6 @@ static int epic_open(struct net_device *dev)
static void epic_pause(struct net_device *dev)
{
long ioaddr = dev->base_addr;
- struct epic_private *ep = netdev_priv(dev);
netif_stop_queue (dev);
@@ -781,9 +779,9 @@ static void epic_pause(struct net_device *dev)
/* Update the error counts. */
if (inw(ioaddr + COMMAND) != 0xffff) {
- ep->stats.rx_missed_errors += inb(ioaddr + MPCNT);
- ep->stats.rx_frame_errors += inb(ioaddr + ALICNT);
- ep->stats.rx_crc_errors += inb(ioaddr + CRCCNT);
+ dev->stats.rx_missed_errors += inb(ioaddr + MPCNT);
+ dev->stats.rx_frame_errors += inb(ioaddr + ALICNT);
+ dev->stats.rx_crc_errors += inb(ioaddr + CRCCNT);
}
/* Remove the packets on the Rx queue. */
@@ -900,7 +898,7 @@ static void epic_tx_timeout(struct net_device *dev)
}
}
if (inw(ioaddr + TxSTAT) & 0x10) { /* Tx FIFO underflow. */
- ep->stats.tx_fifo_errors++;
+ dev->stats.tx_fifo_errors++;
outl(RestartTx, ioaddr + COMMAND);
} else {
epic_restart(dev);
@@ -908,7 +906,7 @@ static void epic_tx_timeout(struct net_device *dev)
}
dev->trans_start = jiffies; /* prevent tx timeout */
- ep->stats.tx_errors++;
+ dev->stats.tx_errors++;
if (!ep->tx_full)
netif_wake_queue(dev);
}
@@ -1016,7 +1014,7 @@ static netdev_tx_t epic_start_xmit(struct sk_buff *skb, struct net_device *dev)
static void epic_tx_error(struct net_device *dev, struct epic_private *ep,
int status)
{
- struct net_device_stats *stats = &ep->stats;
+ struct net_device_stats *stats = &dev->stats;
#ifndef final_version
/* There was an major error, log it. */
@@ -1053,9 +1051,9 @@ static void epic_tx(struct net_device *dev, struct epic_private *ep)
break; /* It still hasn't been Txed */
if (likely(txstatus & 0x0001)) {
- ep->stats.collisions += (txstatus >> 8) & 15;
- ep->stats.tx_packets++;
- ep->stats.tx_bytes += ep->tx_skbuff[entry]->len;
+ dev->stats.collisions += (txstatus >> 8) & 15;
+ dev->stats.tx_packets++;
+ dev->stats.tx_bytes += ep->tx_skbuff[entry]->len;
} else
epic_tx_error(dev, ep, txstatus);
@@ -1125,12 +1123,12 @@ static irqreturn_t epic_interrupt(int irq, void *dev_instance)
goto out;
/* Always update the error counts to avoid overhead later. */
- ep->stats.rx_missed_errors += inb(ioaddr + MPCNT);
- ep->stats.rx_frame_errors += inb(ioaddr + ALICNT);
- ep->stats.rx_crc_errors += inb(ioaddr + CRCCNT);
+ dev->stats.rx_missed_errors += inb(ioaddr + MPCNT);
+ dev->stats.rx_frame_errors += inb(ioaddr + ALICNT);
+ dev->stats.rx_crc_errors += inb(ioaddr + CRCCNT);
if (status & TxUnderrun) { /* Tx FIFO underflow. */
- ep->stats.tx_fifo_errors++;
+ dev->stats.tx_fifo_errors++;
outl(ep->tx_threshold += 128, ioaddr + TxThresh);
/* Restart the transmit process. */
outl(RestartTx, ioaddr + COMMAND);
@@ -1183,10 +1181,10 @@ static int epic_rx(struct net_device *dev, int budget)
if (status & 0x2000) {
printk(KERN_WARNING "%s: Oversized Ethernet frame spanned "
"multiple buffers, status %4.4x!\n", dev->name, status);
- ep->stats.rx_length_errors++;
+ dev->stats.rx_length_errors++;
} else if (status & 0x0006)
/* Rx Frame errors are counted in hardware. */
- ep->stats.rx_errors++;
+ dev->stats.rx_errors++;
} else {
/* Malloc up new buffer, compatible with net-2e. */
/* Omit the four octet CRC from the length. */
@@ -1223,8 +1221,8 @@ static int epic_rx(struct net_device *dev, int budget)
}
skb->protocol = eth_type_trans(skb, dev);
netif_receive_skb(skb);
- ep->stats.rx_packets++;
- ep->stats.rx_bytes += pkt_len;
+ dev->stats.rx_packets++;
+ dev->stats.rx_bytes += pkt_len;
}
work_done++;
entry = (++ep->cur_rx) % RX_RING_SIZE;
@@ -1259,7 +1257,7 @@ static void epic_rx_err(struct net_device *dev, struct epic_private *ep)
if (status == EpicRemoved)
return;
if (status & RxOverflow) /* Missed a Rx frame. */
- ep->stats.rx_errors++;
+ dev->stats.rx_errors++;
if (status & (RxOverflow | RxFull))
outw(RxQueued, ioaddr + COMMAND);
}
@@ -1357,17 +1355,16 @@ static int epic_close(struct net_device *dev)
static struct net_device_stats *epic_get_stats(struct net_device *dev)
{
- struct epic_private *ep = netdev_priv(dev);
long ioaddr = dev->base_addr;
if (netif_running(dev)) {
/* Update the error counts. */
- ep->stats.rx_missed_errors += inb(ioaddr + MPCNT);
- ep->stats.rx_frame_errors += inb(ioaddr + ALICNT);
- ep->stats.rx_crc_errors += inb(ioaddr + CRCCNT);
+ dev->stats.rx_missed_errors += inb(ioaddr + MPCNT);
+ dev->stats.rx_frame_errors += inb(ioaddr + ALICNT);
+ dev->stats.rx_crc_errors += inb(ioaddr + CRCCNT);
}
- return &ep->stats;
+ return &dev->stats;
}
/* Set or clear the multicast filter for this adaptor.
diff --git a/drivers/net/eth16i.c b/drivers/net/eth16i.c
index 874973f558e..10e39f2b31c 100644
--- a/drivers/net/eth16i.c
+++ b/drivers/net/eth16i.c
@@ -1442,8 +1442,10 @@ int __init init_module(void)
dev->if_port = eth16i_parse_mediatype(mediatype[this_dev]);
if(io[this_dev] == 0) {
- if(this_dev != 0) /* Only autoprobe 1st one */
+ if (this_dev != 0) { /* Only autoprobe 1st one */
+ free_netdev(dev);
break;
+ }
printk(KERN_NOTICE "eth16i.c: Presently autoprobing (not recommended) for a single card.\n");
}
diff --git a/drivers/net/ethoc.c b/drivers/net/ethoc.c
index 6ed2df14ec8..6d653c459c1 100644
--- a/drivers/net/ethoc.c
+++ b/drivers/net/ethoc.c
@@ -180,9 +180,9 @@ MODULE_PARM_DESC(buffer_size, "DMA buffer allocation size");
* @dty_tx: last buffer actually sent
* @num_rx: number of receive buffers
* @cur_rx: current receive buffer
+ * @vma: pointer to array of virtual memory addresses for buffers
* @netdev: pointer to network device structure
* @napi: NAPI structure
- * @stats: network device statistics
* @msg_enable: device state flags
* @rx_lock: receive lock
* @lock: device lock
@@ -203,9 +203,10 @@ struct ethoc {
unsigned int num_rx;
unsigned int cur_rx;
+ void** vma;
+
struct net_device *netdev;
struct napi_struct napi;
- struct net_device_stats stats;
u32 msg_enable;
spinlock_t rx_lock;
@@ -285,18 +286,22 @@ static inline void ethoc_disable_rx_and_tx(struct ethoc *dev)
ethoc_write(dev, MODER, mode);
}
-static int ethoc_init_ring(struct ethoc *dev)
+static int ethoc_init_ring(struct ethoc *dev, unsigned long mem_start)
{
struct ethoc_bd bd;
int i;
+ void* vma;
dev->cur_tx = 0;
dev->dty_tx = 0;
dev->cur_rx = 0;
+ ethoc_write(dev, TX_BD_NUM, dev->num_tx);
+
/* setup transmission buffers */
- bd.addr = virt_to_phys(dev->membase);
+ bd.addr = mem_start;
bd.stat = TX_BD_IRQ | TX_BD_CRC;
+ vma = dev->membase;
for (i = 0; i < dev->num_tx; i++) {
if (i == dev->num_tx - 1)
@@ -304,6 +309,9 @@ static int ethoc_init_ring(struct ethoc *dev)
ethoc_write_bd(dev, i, &bd);
bd.addr += ETHOC_BUFSIZ;
+
+ dev->vma[i] = vma;
+ vma += ETHOC_BUFSIZ;
}
bd.stat = RX_BD_EMPTY | RX_BD_IRQ;
@@ -314,6 +322,9 @@ static int ethoc_init_ring(struct ethoc *dev)
ethoc_write_bd(dev, dev->num_tx + i, &bd);
bd.addr += ETHOC_BUFSIZ;
+
+ dev->vma[dev->num_tx + i] = vma;
+ vma += ETHOC_BUFSIZ;
}
return 0;
@@ -354,39 +365,39 @@ static unsigned int ethoc_update_rx_stats(struct ethoc *dev,
if (bd->stat & RX_BD_TL) {
dev_err(&netdev->dev, "RX: frame too long\n");
- dev->stats.rx_length_errors++;
+ netdev->stats.rx_length_errors++;
ret++;
}
if (bd->stat & RX_BD_SF) {
dev_err(&netdev->dev, "RX: frame too short\n");
- dev->stats.rx_length_errors++;
+ netdev->stats.rx_length_errors++;
ret++;
}
if (bd->stat & RX_BD_DN) {
dev_err(&netdev->dev, "RX: dribble nibble\n");
- dev->stats.rx_frame_errors++;
+ netdev->stats.rx_frame_errors++;
}
if (bd->stat & RX_BD_CRC) {
dev_err(&netdev->dev, "RX: wrong CRC\n");
- dev->stats.rx_crc_errors++;
+ netdev->stats.rx_crc_errors++;
ret++;
}
if (bd->stat & RX_BD_OR) {
dev_err(&netdev->dev, "RX: overrun\n");
- dev->stats.rx_over_errors++;
+ netdev->stats.rx_over_errors++;
ret++;
}
if (bd->stat & RX_BD_MISS)
- dev->stats.rx_missed_errors++;
+ netdev->stats.rx_missed_errors++;
if (bd->stat & RX_BD_LC) {
dev_err(&netdev->dev, "RX: late collision\n");
- dev->stats.collisions++;
+ netdev->stats.collisions++;
ret++;
}
@@ -415,18 +426,18 @@ static int ethoc_rx(struct net_device *dev, int limit)
skb = netdev_alloc_skb_ip_align(dev, size);
if (likely(skb)) {
- void *src = phys_to_virt(bd.addr);
+ void *src = priv->vma[entry];
memcpy_fromio(skb_put(skb, size), src, size);
skb->protocol = eth_type_trans(skb, dev);
- priv->stats.rx_packets++;
- priv->stats.rx_bytes += size;
+ dev->stats.rx_packets++;
+ dev->stats.rx_bytes += size;
netif_receive_skb(skb);
} else {
if (net_ratelimit())
dev_warn(&dev->dev, "low on memory - "
"packet dropped\n");
- priv->stats.rx_dropped++;
+ dev->stats.rx_dropped++;
break;
}
}
@@ -447,30 +458,30 @@ static int ethoc_update_tx_stats(struct ethoc *dev, struct ethoc_bd *bd)
if (bd->stat & TX_BD_LC) {
dev_err(&netdev->dev, "TX: late collision\n");
- dev->stats.tx_window_errors++;
+ netdev->stats.tx_window_errors++;
}
if (bd->stat & TX_BD_RL) {
dev_err(&netdev->dev, "TX: retransmit limit\n");
- dev->stats.tx_aborted_errors++;
+ netdev->stats.tx_aborted_errors++;
}
if (bd->stat & TX_BD_UR) {
dev_err(&netdev->dev, "TX: underrun\n");
- dev->stats.tx_fifo_errors++;
+ netdev->stats.tx_fifo_errors++;
}
if (bd->stat & TX_BD_CS) {
dev_err(&netdev->dev, "TX: carrier sense lost\n");
- dev->stats.tx_carrier_errors++;
+ netdev->stats.tx_carrier_errors++;
}
if (bd->stat & TX_BD_STATS)
- dev->stats.tx_errors++;
+ netdev->stats.tx_errors++;
- dev->stats.collisions += (bd->stat >> 4) & 0xf;
- dev->stats.tx_bytes += bd->stat >> 16;
- dev->stats.tx_packets++;
+ netdev->stats.collisions += (bd->stat >> 4) & 0xf;
+ netdev->stats.tx_bytes += bd->stat >> 16;
+ netdev->stats.tx_packets++;
return 0;
}
@@ -501,7 +512,7 @@ static void ethoc_tx(struct net_device *dev)
static irqreturn_t ethoc_interrupt(int irq, void *dev_id)
{
- struct net_device *dev = (struct net_device *)dev_id;
+ struct net_device *dev = dev_id;
struct ethoc *priv = netdev_priv(dev);
u32 pending;
@@ -516,7 +527,7 @@ static irqreturn_t ethoc_interrupt(int irq, void *dev_id)
if (pending & INT_MASK_BUSY) {
dev_err(&dev->dev, "packet dropped\n");
- priv->stats.rx_dropped++;
+ dev->stats.rx_dropped++;
}
if (pending & INT_MASK_RX) {
@@ -600,8 +611,11 @@ static int ethoc_mdio_write(struct mii_bus *bus, int phy, int reg, u16 val)
while (time_before(jiffies, timeout)) {
u32 stat = ethoc_read(priv, MIISTATUS);
- if (!(stat & MIISTATUS_BUSY))
+ if (!(stat & MIISTATUS_BUSY)) {
+ /* reset MII command register */
+ ethoc_write(priv, MIICOMMAND, 0);
return 0;
+ }
schedule();
}
@@ -618,25 +632,16 @@ static void ethoc_mdio_poll(struct net_device *dev)
{
}
-static int ethoc_mdio_probe(struct net_device *dev)
+static int __devinit ethoc_mdio_probe(struct net_device *dev)
{
struct ethoc *priv = netdev_priv(dev);
struct phy_device *phy;
- int i;
+ int err;
- for (i = 0; i < PHY_MAX_ADDR; i++) {
- phy = priv->mdio->phy_map[i];
- if (phy) {
- if (priv->phy_id != -1) {
- /* attach to specified PHY */
- if (priv->phy_id == phy->addr)
- break;
- } else {
- /* autoselect PHY if none was specified */
- if (phy->addr != 0)
- break;
- }
- }
+ if (priv->phy_id != -1) {
+ phy = priv->mdio->phy_map[priv->phy_id];
+ } else {
+ phy = phy_find_first(priv->mdio);
}
if (!phy) {
@@ -644,11 +649,11 @@ static int ethoc_mdio_probe(struct net_device *dev)
return -ENXIO;
}
- phy = phy_connect(dev, dev_name(&phy->dev), ethoc_mdio_poll, 0,
+ err = phy_connect_direct(dev, phy, ethoc_mdio_poll, 0,
PHY_INTERFACE_MODE_GMII);
- if (IS_ERR(phy)) {
+ if (err) {
dev_err(&dev->dev, "could not attach to PHY\n");
- return PTR_ERR(phy);
+ return err;
}
priv->phy = phy;
@@ -658,8 +663,6 @@ static int ethoc_mdio_probe(struct net_device *dev)
static int ethoc_open(struct net_device *dev)
{
struct ethoc *priv = netdev_priv(dev);
- unsigned int min_tx = 2;
- unsigned int num_bd;
int ret;
ret = request_irq(dev->irq, ethoc_interrupt, IRQF_SHARED,
@@ -667,14 +670,7 @@ static int ethoc_open(struct net_device *dev)
if (ret)
return ret;
- /* calculate the number of TX/RX buffers, maximum 128 supported */
- num_bd = min_t(unsigned int,
- 128, (dev->mem_end - dev->mem_start + 1) / ETHOC_BUFSIZ);
- priv->num_tx = max(min_tx, num_bd / 4);
- priv->num_rx = num_bd - priv->num_tx;
- ethoc_write(priv, TX_BD_NUM, priv->num_tx);
-
- ethoc_init_ring(priv);
+ ethoc_init_ring(priv, dev->mem_start);
ethoc_reset(priv);
if (netif_queue_stopped(dev)) {
@@ -734,7 +730,7 @@ static int ethoc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
phy = priv->phy;
}
- return phy_mii_ioctl(phy, mdio, cmd);
+ return phy_mii_ioctl(phy, ifr, cmd);
}
static int ethoc_config(struct net_device *dev, struct ifmap *map)
@@ -812,8 +808,7 @@ static void ethoc_tx_timeout(struct net_device *dev)
static struct net_device_stats *ethoc_stats(struct net_device *dev)
{
- struct ethoc *priv = netdev_priv(dev);
- return &priv->stats;
+ return &dev->stats;
}
static netdev_tx_t ethoc_start_xmit(struct sk_buff *skb, struct net_device *dev)
@@ -824,7 +819,7 @@ static netdev_tx_t ethoc_start_xmit(struct sk_buff *skb, struct net_device *dev)
void *dest;
if (unlikely(skb->len > ETHOC_BUFSIZ)) {
- priv->stats.tx_errors++;
+ dev->stats.tx_errors++;
goto out;
}
@@ -838,7 +833,7 @@ static netdev_tx_t ethoc_start_xmit(struct sk_buff *skb, struct net_device *dev)
else
bd.stat &= ~TX_BD_PAD;
- dest = phys_to_virt(bd.addr);
+ dest = priv->vma[entry];
memcpy_toio(dest, skb->data, skb->len);
bd.stat &= ~(TX_BD_STATS | TX_BD_LEN_MASK);
@@ -876,7 +871,7 @@ static const struct net_device_ops ethoc_netdev_ops = {
* ethoc_probe() - initialize OpenCores ethernet MAC
* pdev: platform device
*/
-static int ethoc_probe(struct platform_device *pdev)
+static int __devinit ethoc_probe(struct platform_device *pdev)
{
struct net_device *netdev = NULL;
struct resource *res = NULL;
@@ -884,6 +879,7 @@ static int ethoc_probe(struct platform_device *pdev)
struct resource *mem = NULL;
struct ethoc *priv = NULL;
unsigned int phy;
+ int num_bd;
int ret = 0;
/* allocate networking device */
@@ -965,7 +961,7 @@ static int ethoc_probe(struct platform_device *pdev)
}
} else {
/* Allocate buffer memory */
- priv->membase = dma_alloc_coherent(NULL,
+ priv->membase = dmam_alloc_coherent(&pdev->dev,
buffer_size, (void *)&netdev->mem_start,
GFP_KERNEL);
if (!priv->membase) {
@@ -978,6 +974,18 @@ static int ethoc_probe(struct platform_device *pdev)
priv->dma_alloc = buffer_size;
}
+ /* calculate the number of TX/RX buffers, maximum 128 supported */
+ num_bd = min_t(unsigned int,
+ 128, (netdev->mem_end - netdev->mem_start + 1) / ETHOC_BUFSIZ);
+ priv->num_tx = max(2, num_bd / 4);
+ priv->num_rx = num_bd - priv->num_tx;
+
+ priv->vma = devm_kzalloc(&pdev->dev, num_bd*sizeof(void*), GFP_KERNEL);
+ if (!priv->vma) {
+ ret = -ENOMEM;
+ goto error;
+ }
+
/* Allow the platform setup code to pass in a MAC address. */
if (pdev->dev.platform_data) {
struct ethoc_platform_data *pdata =
@@ -1063,21 +1071,6 @@ free_mdio:
kfree(priv->mdio->irq);
mdiobus_free(priv->mdio);
free:
- if (priv) {
- if (priv->dma_alloc)
- dma_free_coherent(NULL, priv->dma_alloc, priv->membase,
- netdev->mem_start);
- else if (priv->membase)
- devm_iounmap(&pdev->dev, priv->membase);
- if (priv->iobase)
- devm_iounmap(&pdev->dev, priv->iobase);
- }
- if (mem)
- devm_release_mem_region(&pdev->dev, mem->start,
- mem->end - mem->start + 1);
- if (mmio)
- devm_release_mem_region(&pdev->dev, mmio->start,
- mmio->end - mmio->start + 1);
free_netdev(netdev);
out:
return ret;
@@ -1087,7 +1080,7 @@ out:
* ethoc_remove() - shutdown OpenCores ethernet MAC
* @pdev: platform device
*/
-static int ethoc_remove(struct platform_device *pdev)
+static int __devexit ethoc_remove(struct platform_device *pdev)
{
struct net_device *netdev = platform_get_drvdata(pdev);
struct ethoc *priv = netdev_priv(netdev);
@@ -1104,17 +1097,6 @@ static int ethoc_remove(struct platform_device *pdev)
kfree(priv->mdio->irq);
mdiobus_free(priv->mdio);
}
- if (priv->dma_alloc)
- dma_free_coherent(NULL, priv->dma_alloc, priv->membase,
- netdev->mem_start);
- else {
- devm_iounmap(&pdev->dev, priv->membase);
- devm_release_mem_region(&pdev->dev, netdev->mem_start,
- netdev->mem_end - netdev->mem_start + 1);
- }
- devm_iounmap(&pdev->dev, priv->iobase);
- devm_release_mem_region(&pdev->dev, netdev->base_addr,
- priv->io_region_size);
unregister_netdev(netdev);
free_netdev(netdev);
}
@@ -1139,7 +1121,7 @@ static int ethoc_resume(struct platform_device *pdev)
static struct platform_driver ethoc_driver = {
.probe = ethoc_probe,
- .remove = ethoc_remove,
+ .remove = __devexit_p(ethoc_remove),
.suspend = ethoc_suspend,
.resume = ethoc_resume,
.driver = {
diff --git a/drivers/net/fealnx.c b/drivers/net/fealnx.c
index 15f4f8d3d46..d7e8f6b8f4c 100644
--- a/drivers/net/fealnx.c
+++ b/drivers/net/fealnx.c
@@ -382,8 +382,6 @@ struct netdev_private {
spinlock_t lock;
- struct net_device_stats stats;
-
/* Media monitoring timer. */
struct timer_list timer;
@@ -1234,7 +1232,7 @@ static void fealnx_tx_timeout(struct net_device *dev)
spin_unlock_irqrestore(&np->lock, flags);
dev->trans_start = jiffies; /* prevent tx timeout */
- np->stats.tx_errors++;
+ dev->stats.tx_errors++;
netif_wake_queue(dev); /* or .._start_.. ?? */
}
@@ -1479,10 +1477,11 @@ static irqreturn_t intr_handler(int irq, void *dev_instance)
if (intr_status & CNTOVF) {
/* missed pkts */
- np->stats.rx_missed_errors += ioread32(ioaddr + TALLY) & 0x7fff;
+ dev->stats.rx_missed_errors +=
+ ioread32(ioaddr + TALLY) & 0x7fff;
/* crc error */
- np->stats.rx_crc_errors +=
+ dev->stats.rx_crc_errors +=
(ioread32(ioaddr + TALLY) & 0x7fff0000) >> 16;
}
@@ -1513,30 +1512,30 @@ static irqreturn_t intr_handler(int irq, void *dev_instance)
if (!(np->crvalue & CR_W_ENH)) {
if (tx_status & (CSL | LC | EC | UDF | HF)) {
- np->stats.tx_errors++;
+ dev->stats.tx_errors++;
if (tx_status & EC)
- np->stats.tx_aborted_errors++;
+ dev->stats.tx_aborted_errors++;
if (tx_status & CSL)
- np->stats.tx_carrier_errors++;
+ dev->stats.tx_carrier_errors++;
if (tx_status & LC)
- np->stats.tx_window_errors++;
+ dev->stats.tx_window_errors++;
if (tx_status & UDF)
- np->stats.tx_fifo_errors++;
+ dev->stats.tx_fifo_errors++;
if ((tx_status & HF) && np->mii.full_duplex == 0)
- np->stats.tx_heartbeat_errors++;
+ dev->stats.tx_heartbeat_errors++;
} else {
- np->stats.tx_bytes +=
+ dev->stats.tx_bytes +=
((tx_control & PKTSMask) >> PKTSShift);
- np->stats.collisions +=
+ dev->stats.collisions +=
((tx_status & NCRMask) >> NCRShift);
- np->stats.tx_packets++;
+ dev->stats.tx_packets++;
}
} else {
- np->stats.tx_bytes +=
+ dev->stats.tx_bytes +=
((tx_control & PKTSMask) >> PKTSShift);
- np->stats.tx_packets++;
+ dev->stats.tx_packets++;
}
/* Free the original skb. */
@@ -1564,10 +1563,12 @@ static irqreturn_t intr_handler(int irq, void *dev_instance)
long data;
data = ioread32(ioaddr + TSR);
- np->stats.tx_errors += (data & 0xff000000) >> 24;
- np->stats.tx_aborted_errors += (data & 0xff000000) >> 24;
- np->stats.tx_window_errors += (data & 0x00ff0000) >> 16;
- np->stats.collisions += (data & 0x0000ffff);
+ dev->stats.tx_errors += (data & 0xff000000) >> 24;
+ dev->stats.tx_aborted_errors +=
+ (data & 0xff000000) >> 24;
+ dev->stats.tx_window_errors +=
+ (data & 0x00ff0000) >> 16;
+ dev->stats.collisions += (data & 0x0000ffff);
}
if (--boguscnt < 0) {
@@ -1593,10 +1594,11 @@ static irqreturn_t intr_handler(int irq, void *dev_instance)
/* read the tally counters */
/* missed pkts */
- np->stats.rx_missed_errors += ioread32(ioaddr + TALLY) & 0x7fff;
+ dev->stats.rx_missed_errors += ioread32(ioaddr + TALLY) & 0x7fff;
/* crc error */
- np->stats.rx_crc_errors += (ioread32(ioaddr + TALLY) & 0x7fff0000) >> 16;
+ dev->stats.rx_crc_errors +=
+ (ioread32(ioaddr + TALLY) & 0x7fff0000) >> 16;
if (debug)
printk(KERN_DEBUG "%s: exiting interrupt, status=%#4.4x.\n",
@@ -1635,13 +1637,13 @@ static int netdev_rx(struct net_device *dev)
"%s: Receive error, Rx status %8.8x.\n",
dev->name, rx_status);
- np->stats.rx_errors++; /* end of a packet. */
+ dev->stats.rx_errors++; /* end of a packet. */
if (rx_status & (LONG | RUNT))
- np->stats.rx_length_errors++;
+ dev->stats.rx_length_errors++;
if (rx_status & RXER)
- np->stats.rx_frame_errors++;
+ dev->stats.rx_frame_errors++;
if (rx_status & CRC)
- np->stats.rx_crc_errors++;
+ dev->stats.rx_crc_errors++;
} else {
int need_to_reset = 0;
int desno = 0;
@@ -1667,7 +1669,7 @@ static int netdev_rx(struct net_device *dev)
if (need_to_reset == 0) {
int i;
- np->stats.rx_length_errors++;
+ dev->stats.rx_length_errors++;
/* free all rx descriptors related this long pkt */
for (i = 0; i < desno; ++i) {
@@ -1733,8 +1735,8 @@ static int netdev_rx(struct net_device *dev)
}
skb->protocol = eth_type_trans(skb, dev);
netif_rx(skb);
- np->stats.rx_packets++;
- np->stats.rx_bytes += pkt_len;
+ dev->stats.rx_packets++;
+ dev->stats.rx_bytes += pkt_len;
}
np->cur_rx = np->cur_rx->next_desc_logical;
@@ -1754,11 +1756,13 @@ static struct net_device_stats *get_stats(struct net_device *dev)
/* The chip only need report frame silently dropped. */
if (netif_running(dev)) {
- np->stats.rx_missed_errors += ioread32(ioaddr + TALLY) & 0x7fff;
- np->stats.rx_crc_errors += (ioread32(ioaddr + TALLY) & 0x7fff0000) >> 16;
+ dev->stats.rx_missed_errors +=
+ ioread32(ioaddr + TALLY) & 0x7fff;
+ dev->stats.rx_crc_errors +=
+ (ioread32(ioaddr + TALLY) & 0x7fff0000) >> 16;
}
- return &np->stats;
+ return &dev->stats;
}
diff --git a/drivers/net/fec.c b/drivers/net/fec.c
index edfff92a6d8..768b840aeb6 100644
--- a/drivers/net/fec.c
+++ b/drivers/net/fec.c
@@ -118,6 +118,8 @@ static unsigned char fec_mac_default[] = {
#define FEC_ENET_MII ((uint)0x00800000) /* MII interrupt */
#define FEC_ENET_EBERR ((uint)0x00400000) /* SDMA bus error */
+#define FEC_DEFAULT_IMASK (FEC_ENET_TXF | FEC_ENET_RXF | FEC_ENET_MII)
+
/* The FEC stores dest/src/type, data, and checksum for receive packets.
*/
#define PKT_MAXBUF_SIZE 1518
@@ -187,6 +189,7 @@ struct fec_enet_private {
int index;
int link;
int full_duplex;
+ struct completion mdio_done;
};
static irqreturn_t fec_enet_interrupt(int irq, void * dev_id);
@@ -205,12 +208,12 @@ static void fec_stop(struct net_device *dev);
#define FEC_MMFR_TA (2 << 16)
#define FEC_MMFR_DATA(v) (v & 0xffff)
-#define FEC_MII_TIMEOUT 10000
+#define FEC_MII_TIMEOUT 1000 /* us */
/* Transmitter timeout */
#define TX_TIMEOUT (2 * HZ)
-static int
+static netdev_tx_t
fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct fec_enet_private *fep = netdev_priv(dev);
@@ -334,6 +337,11 @@ fec_enet_interrupt(int irq, void * dev_id)
ret = IRQ_HANDLED;
fec_enet_tx(dev);
}
+
+ if (int_events & FEC_ENET_MII) {
+ ret = IRQ_HANDLED;
+ complete(&fep->mdio_done);
+ }
} while (int_events);
return ret;
@@ -608,18 +616,13 @@ spin_unlock:
phy_print_status(phy_dev);
}
-/*
- * NOTE: a MII transaction is during around 25 us, so polling it...
- */
static int fec_enet_mdio_read(struct mii_bus *bus, int mii_id, int regnum)
{
struct fec_enet_private *fep = bus->priv;
- int timeout = FEC_MII_TIMEOUT;
+ unsigned long time_left;
fep->mii_timeout = 0;
-
- /* clear MII end of transfer bit*/
- writel(FEC_ENET_MII, fep->hwp + FEC_IEVENT);
+ init_completion(&fep->mdio_done);
/* start a read op */
writel(FEC_MMFR_ST | FEC_MMFR_OP_READ |
@@ -627,13 +630,12 @@ static int fec_enet_mdio_read(struct mii_bus *bus, int mii_id, int regnum)
FEC_MMFR_TA, fep->hwp + FEC_MII_DATA);
/* wait for end of transfer */
- while (!(readl(fep->hwp + FEC_IEVENT) & FEC_ENET_MII)) {
- cpu_relax();
- if (timeout-- < 0) {
- fep->mii_timeout = 1;
- printk(KERN_ERR "FEC: MDIO read timeout\n");
- return -ETIMEDOUT;
- }
+ time_left = wait_for_completion_timeout(&fep->mdio_done,
+ usecs_to_jiffies(FEC_MII_TIMEOUT));
+ if (time_left == 0) {
+ fep->mii_timeout = 1;
+ printk(KERN_ERR "FEC: MDIO read timeout\n");
+ return -ETIMEDOUT;
}
/* return value */
@@ -644,12 +646,10 @@ static int fec_enet_mdio_write(struct mii_bus *bus, int mii_id, int regnum,
u16 value)
{
struct fec_enet_private *fep = bus->priv;
- int timeout = FEC_MII_TIMEOUT;
+ unsigned long time_left;
fep->mii_timeout = 0;
-
- /* clear MII end of transfer bit*/
- writel(FEC_ENET_MII, fep->hwp + FEC_IEVENT);
+ init_completion(&fep->mdio_done);
/* start a read op */
writel(FEC_MMFR_ST | FEC_MMFR_OP_READ |
@@ -658,13 +658,12 @@ static int fec_enet_mdio_write(struct mii_bus *bus, int mii_id, int regnum,
fep->hwp + FEC_MII_DATA);
/* wait for end of transfer */
- while (!(readl(fep->hwp + FEC_IEVENT) & FEC_ENET_MII)) {
- cpu_relax();
- if (timeout-- < 0) {
- fep->mii_timeout = 1;
- printk(KERN_ERR "FEC: MDIO write timeout\n");
- return -ETIMEDOUT;
- }
+ time_left = wait_for_completion_timeout(&fep->mdio_done,
+ usecs_to_jiffies(FEC_MII_TIMEOUT));
+ if (time_left == 0) {
+ fep->mii_timeout = 1;
+ printk(KERN_ERR "FEC: MDIO write timeout\n");
+ return -ETIMEDOUT;
}
return 0;
@@ -679,30 +678,24 @@ static int fec_enet_mii_probe(struct net_device *dev)
{
struct fec_enet_private *fep = netdev_priv(dev);
struct phy_device *phy_dev = NULL;
- int phy_addr;
+ int ret;
fep->phy_dev = NULL;
/* find the first phy */
- for (phy_addr = 0; phy_addr < PHY_MAX_ADDR; phy_addr++) {
- if (fep->mii_bus->phy_map[phy_addr]) {
- phy_dev = fep->mii_bus->phy_map[phy_addr];
- break;
- }
- }
-
+ phy_dev = phy_find_first(fep->mii_bus);
if (!phy_dev) {
printk(KERN_ERR "%s: no PHY found\n", dev->name);
return -ENODEV;
}
/* attach the mac to the phy */
- phy_dev = phy_connect(dev, dev_name(&phy_dev->dev),
+ ret = phy_connect_direct(dev, phy_dev,
&fec_enet_adjust_link, 0,
PHY_INTERFACE_MODE_MII);
- if (IS_ERR(phy_dev)) {
+ if (ret) {
printk(KERN_ERR "%s: Could not attach to PHY\n", dev->name);
- return PTR_ERR(phy_dev);
+ return ret;
}
/* mask with MAC supported features */
@@ -834,7 +827,7 @@ static int fec_enet_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
if (!phydev)
return -ENODEV;
- return phy_mii_ioctl(phydev, if_mii(rq), cmd);
+ return phy_mii_ioctl(phydev, rq, cmd);
}
static void fec_enet_free_buffers(struct net_device *dev)
@@ -1222,7 +1215,7 @@ fec_restart(struct net_device *dev, int duplex)
writel(0, fep->hwp + FEC_R_DES_ACTIVE);
/* Enable interrupts we wish to service */
- writel(FEC_ENET_TXF | FEC_ENET_RXF, fep->hwp + FEC_IMASK);
+ writel(FEC_DEFAULT_IMASK, fep->hwp + FEC_IMASK);
}
static void
@@ -1241,11 +1234,8 @@ fec_stop(struct net_device *dev)
/* Whack a reset. We should wait for this. */
writel(1, fep->hwp + FEC_ECNTRL);
udelay(10);
-
- /* Clear outstanding MII command interrupts. */
- writel(FEC_ENET_MII, fep->hwp + FEC_IEVENT);
-
writel(fep->phy_speed, fep->hwp + FEC_MII_SPEED);
+ writel(FEC_DEFAULT_IMASK, fep->hwp + FEC_IMASK);
}
static int __devinit
@@ -1365,10 +1355,11 @@ fec_drv_remove(struct platform_device *pdev)
return 0;
}
+#ifdef CONFIG_PM
static int
-fec_suspend(struct platform_device *dev, pm_message_t state)
+fec_suspend(struct device *dev)
{
- struct net_device *ndev = platform_get_drvdata(dev);
+ struct net_device *ndev = dev_get_drvdata(dev);
struct fec_enet_private *fep;
if (ndev) {
@@ -1381,9 +1372,9 @@ fec_suspend(struct platform_device *dev, pm_message_t state)
}
static int
-fec_resume(struct platform_device *dev)
+fec_resume(struct device *dev)
{
- struct net_device *ndev = platform_get_drvdata(dev);
+ struct net_device *ndev = dev_get_drvdata(dev);
struct fec_enet_private *fep;
if (ndev) {
@@ -1395,15 +1386,26 @@ fec_resume(struct platform_device *dev)
return 0;
}
+static const struct dev_pm_ops fec_pm_ops = {
+ .suspend = fec_suspend,
+ .resume = fec_resume,
+ .freeze = fec_suspend,
+ .thaw = fec_resume,
+ .poweroff = fec_suspend,
+ .restore = fec_resume,
+};
+#endif
+
static struct platform_driver fec_driver = {
.driver = {
- .name = "fec",
- .owner = THIS_MODULE,
+ .name = "fec",
+ .owner = THIS_MODULE,
+#ifdef CONFIG_PM
+ .pm = &fec_pm_ops,
+#endif
},
- .probe = fec_probe,
- .remove = __devexit_p(fec_drv_remove),
- .suspend = fec_suspend,
- .resume = fec_resume,
+ .probe = fec_probe,
+ .remove = __devexit_p(fec_drv_remove),
};
static int __init
diff --git a/drivers/net/fec_mpc52xx.c b/drivers/net/fec_mpc52xx.c
index 25e6cc6840b..d1a5b17b2a9 100644
--- a/drivers/net/fec_mpc52xx.c
+++ b/drivers/net/fec_mpc52xx.c
@@ -826,7 +826,7 @@ static int mpc52xx_fec_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
if (!priv->phydev)
return -ENOTSUPP;
- return phy_mii_ioctl(priv->phydev, if_mii(rq), cmd);
+ return phy_mii_ioctl(priv->phydev, rq, cmd);
}
static const struct net_device_ops mpc52xx_fec_netdev_ops = {
@@ -875,17 +875,21 @@ mpc52xx_fec_probe(struct of_device *op, const struct of_device_id *match)
if (rv) {
printk(KERN_ERR DRIVER_NAME ": "
"Error while parsing device node resource\n" );
- return rv;
+ goto err_netdev;
}
if ((mem.end - mem.start + 1) < sizeof(struct mpc52xx_fec)) {
printk(KERN_ERR DRIVER_NAME
" - invalid resource size (%lx < %x), check mpc52xx_devices.c\n",
(unsigned long)(mem.end - mem.start + 1), sizeof(struct mpc52xx_fec));
- return -EINVAL;
+ rv = -EINVAL;
+ goto err_netdev;
}
- if (!request_mem_region(mem.start, sizeof(struct mpc52xx_fec), DRIVER_NAME))
- return -EBUSY;
+ if (!request_mem_region(mem.start, sizeof(struct mpc52xx_fec),
+ DRIVER_NAME)) {
+ rv = -EBUSY;
+ goto err_netdev;
+ }
/* Init ether ndev with what we have */
ndev->netdev_ops = &mpc52xx_fec_netdev_ops;
@@ -901,7 +905,7 @@ mpc52xx_fec_probe(struct of_device *op, const struct of_device_id *match)
if (!priv->fec) {
rv = -ENOMEM;
- goto probe_error;
+ goto err_mem_region;
}
/* Bestcomm init */
@@ -914,7 +918,7 @@ mpc52xx_fec_probe(struct of_device *op, const struct of_device_id *match)
if (!priv->rx_dmatsk || !priv->tx_dmatsk) {
printk(KERN_ERR DRIVER_NAME ": Can not init SDMA tasks\n" );
rv = -ENOMEM;
- goto probe_error;
+ goto err_rx_tx_dmatsk;
}
/* Get the IRQ we need one by one */
@@ -966,33 +970,25 @@ mpc52xx_fec_probe(struct of_device *op, const struct of_device_id *match)
rv = register_netdev(ndev);
if (rv < 0)
- goto probe_error;
+ goto err_node;
/* We're done ! */
dev_set_drvdata(&op->dev, ndev);
return 0;
-
- /* Error handling - free everything that might be allocated */
-probe_error:
-
- if (priv->phy_node)
- of_node_put(priv->phy_node);
- priv->phy_node = NULL;
-
+err_node:
+ of_node_put(priv->phy_node);
irq_dispose_mapping(ndev->irq);
-
+err_rx_tx_dmatsk:
if (priv->rx_dmatsk)
bcom_fec_rx_release(priv->rx_dmatsk);
if (priv->tx_dmatsk)
bcom_fec_tx_release(priv->tx_dmatsk);
-
- if (priv->fec)
- iounmap(priv->fec);
-
+ iounmap(priv->fec);
+err_mem_region:
release_mem_region(mem.start, sizeof(struct mpc52xx_fec));
-
+err_netdev:
free_netdev(ndev);
return rv;
diff --git a/drivers/net/fec_mpc52xx_phy.c b/drivers/net/fec_mpc52xx_phy.c
index 006f64d9f96..dbaf72cbb23 100644
--- a/drivers/net/fec_mpc52xx_phy.c
+++ b/drivers/net/fec_mpc52xx_phy.c
@@ -29,15 +29,14 @@ static int mpc52xx_fec_mdio_transfer(struct mii_bus *bus, int phy_id,
int reg, u32 value)
{
struct mpc52xx_fec_mdio_priv *priv = bus->priv;
- struct mpc52xx_fec __iomem *fec;
+ struct mpc52xx_fec __iomem *fec = priv->regs;
int tries = 3;
value |= (phy_id << FEC_MII_DATA_PA_SHIFT) & FEC_MII_DATA_PA_MSK;
value |= (reg << FEC_MII_DATA_RA_SHIFT) & FEC_MII_DATA_RA_MSK;
- fec = priv->regs;
out_be32(&fec->ievent, FEC_IEVENT_MII);
- out_be32(&priv->regs->mii_data, value);
+ out_be32(&fec->mii_data, value);
/* wait for it to finish, this takes about 23 us on lite5200b */
while (!(in_be32(&fec->ievent) & FEC_IEVENT_MII) && --tries)
@@ -47,7 +46,7 @@ static int mpc52xx_fec_mdio_transfer(struct mii_bus *bus, int phy_id,
return -ETIMEDOUT;
return value & FEC_MII_DATA_OP_RD ?
- in_be32(&priv->regs->mii_data) & FEC_MII_DATA_DATAMSK : 0;
+ in_be32(&fec->mii_data) & FEC_MII_DATA_DATAMSK : 0;
}
static int mpc52xx_fec_mdio_read(struct mii_bus *bus, int phy_id, int reg)
@@ -69,9 +68,8 @@ static int mpc52xx_fec_mdio_probe(struct of_device *of,
struct device_node *np = of->dev.of_node;
struct mii_bus *bus;
struct mpc52xx_fec_mdio_priv *priv;
- struct resource res = {};
+ struct resource res;
int err;
- int i;
bus = mdiobus_alloc();
if (bus == NULL)
@@ -93,7 +91,7 @@ static int mpc52xx_fec_mdio_probe(struct of_device *of,
err = of_address_to_resource(np, 0, &res);
if (err)
goto out_free;
- priv->regs = ioremap(res.start, res.end - res.start + 1);
+ priv->regs = ioremap(res.start, resource_size(&res));
if (priv->regs == NULL) {
err = -ENOMEM;
goto out_free;
@@ -118,10 +116,6 @@ static int mpc52xx_fec_mdio_probe(struct of_device *of,
out_unmap:
iounmap(priv->regs);
out_free:
- for (i=0; i<PHY_MAX_ADDR; i++)
- if (bus->irq[i] != PHY_POLL)
- irq_dispose_mapping(bus->irq[i]);
- kfree(bus->irq);
kfree(priv);
mdiobus_free(bus);
@@ -133,23 +127,16 @@ static int mpc52xx_fec_mdio_remove(struct of_device *of)
struct device *dev = &of->dev;
struct mii_bus *bus = dev_get_drvdata(dev);
struct mpc52xx_fec_mdio_priv *priv = bus->priv;
- int i;
mdiobus_unregister(bus);
dev_set_drvdata(dev, NULL);
-
iounmap(priv->regs);
- for (i=0; i<PHY_MAX_ADDR; i++)
- if (bus->irq[i] != PHY_POLL)
- irq_dispose_mapping(bus->irq[i]);
kfree(priv);
- kfree(bus->irq);
mdiobus_free(bus);
return 0;
}
-
static struct of_device_id mpc52xx_fec_mdio_match[] = {
{ .compatible = "fsl,mpc5200b-mdio", },
{ .compatible = "fsl,mpc5200-mdio", },
@@ -171,5 +158,4 @@ struct of_platform_driver mpc52xx_fec_mdio_driver = {
/* let fec driver call it, since this has to be registered before it */
EXPORT_SYMBOL_GPL(mpc52xx_fec_mdio_driver);
-
MODULE_LICENSE("Dual BSD/GPL");
diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c
index 268ea4d566d..4da05b1b445 100644
--- a/drivers/net/forcedeth.c
+++ b/drivers/net/forcedeth.c
@@ -89,8 +89,10 @@
#define DEV_HAS_MSI_X 0x0000080 /* device supports MSI-X */
#define DEV_HAS_POWER_CNTRL 0x0000100 /* device supports power savings */
#define DEV_HAS_STATISTICS_V1 0x0000200 /* device supports hw statistics version 1 */
-#define DEV_HAS_STATISTICS_V2 0x0000600 /* device supports hw statistics version 2 */
-#define DEV_HAS_STATISTICS_V3 0x0000e00 /* device supports hw statistics version 3 */
+#define DEV_HAS_STATISTICS_V2 0x0000400 /* device supports hw statistics version 2 */
+#define DEV_HAS_STATISTICS_V3 0x0000800 /* device supports hw statistics version 3 */
+#define DEV_HAS_STATISTICS_V12 0x0000600 /* device supports hw statistics version 1 and 2 */
+#define DEV_HAS_STATISTICS_V123 0x0000e00 /* device supports hw statistics version 1, 2, and 3 */
#define DEV_HAS_TEST_EXTENDED 0x0001000 /* device supports extended diagnostic test */
#define DEV_HAS_MGMT_UNIT 0x0002000 /* device supports management unit */
#define DEV_HAS_CORRECT_MACADDR 0x0004000 /* device supports correct mac address order */
@@ -2468,7 +2470,7 @@ static int nv_tx_done_optimized(struct net_device *dev, int limit)
struct ring_desc_ex* orig_get_tx = np->get_tx.ex;
while ((np->get_tx.ex != np->put_tx.ex) &&
- !((flags = le32_to_cpu(np->get_tx.ex->flaglen)) & NV_TX_VALID) &&
+ !((flags = le32_to_cpu(np->get_tx.ex->flaglen)) & NV_TX2_VALID) &&
(tx_work < limit)) {
dprintk(KERN_DEBUG "%s: nv_tx_done_optimized: flags 0x%x.\n",
@@ -6067,111 +6069,111 @@ static DEFINE_PCI_DEVICE_TABLE(pci_tbl) = {
},
{ /* MCP55 Ethernet Controller */
PCI_DEVICE(0x10DE, 0x0372),
- .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_VLAN|DEV_HAS_MSI|DEV_HAS_MSI_X|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_NEED_TX_LIMIT|DEV_NEED_MSI_FIX,
+ .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_VLAN|DEV_HAS_MSI|DEV_HAS_MSI_X|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V12|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_NEED_TX_LIMIT|DEV_NEED_MSI_FIX,
},
{ /* MCP55 Ethernet Controller */
PCI_DEVICE(0x10DE, 0x0373),
- .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_VLAN|DEV_HAS_MSI|DEV_HAS_MSI_X|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_NEED_TX_LIMIT|DEV_NEED_MSI_FIX,
+ .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_VLAN|DEV_HAS_MSI|DEV_HAS_MSI_X|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V12|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_NEED_TX_LIMIT|DEV_NEED_MSI_FIX,
},
{ /* MCP61 Ethernet Controller */
PCI_DEVICE(0x10DE, 0x03E5),
- .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_NEED_MSI_FIX,
+ .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V12|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_NEED_MSI_FIX,
},
{ /* MCP61 Ethernet Controller */
PCI_DEVICE(0x10DE, 0x03E6),
- .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_NEED_MSI_FIX,
+ .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V12|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_NEED_MSI_FIX,
},
{ /* MCP61 Ethernet Controller */
PCI_DEVICE(0x10DE, 0x03EE),
- .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_NEED_MSI_FIX,
+ .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V12|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_NEED_MSI_FIX,
},
{ /* MCP61 Ethernet Controller */
PCI_DEVICE(0x10DE, 0x03EF),
- .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_NEED_MSI_FIX,
+ .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V12|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_NEED_MSI_FIX,
},
{ /* MCP65 Ethernet Controller */
PCI_DEVICE(0x10DE, 0x0450),
- .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE|DEV_NEED_MSI_FIX,
+ .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V12|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE|DEV_NEED_MSI_FIX,
},
{ /* MCP65 Ethernet Controller */
PCI_DEVICE(0x10DE, 0x0451),
- .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE|DEV_NEED_MSI_FIX,
+ .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V12|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE|DEV_NEED_MSI_FIX,
},
{ /* MCP65 Ethernet Controller */
PCI_DEVICE(0x10DE, 0x0452),
- .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE|DEV_NEED_MSI_FIX,
+ .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V12|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE|DEV_NEED_MSI_FIX,
},
{ /* MCP65 Ethernet Controller */
PCI_DEVICE(0x10DE, 0x0453),
- .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE|DEV_NEED_MSI_FIX,
+ .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V12|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE|DEV_NEED_MSI_FIX,
},
{ /* MCP67 Ethernet Controller */
PCI_DEVICE(0x10DE, 0x054C),
- .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_GEAR_MODE|DEV_NEED_MSI_FIX,
+ .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V12|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_GEAR_MODE|DEV_NEED_MSI_FIX,
},
{ /* MCP67 Ethernet Controller */
PCI_DEVICE(0x10DE, 0x054D),
- .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_GEAR_MODE|DEV_NEED_MSI_FIX,
+ .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V12|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_GEAR_MODE|DEV_NEED_MSI_FIX,
},
{ /* MCP67 Ethernet Controller */
PCI_DEVICE(0x10DE, 0x054E),
- .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_GEAR_MODE|DEV_NEED_MSI_FIX,
+ .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V12|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_GEAR_MODE|DEV_NEED_MSI_FIX,
},
{ /* MCP67 Ethernet Controller */
PCI_DEVICE(0x10DE, 0x054F),
- .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_GEAR_MODE|DEV_NEED_MSI_FIX,
+ .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V12|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_GEAR_MODE|DEV_NEED_MSI_FIX,
},
{ /* MCP73 Ethernet Controller */
PCI_DEVICE(0x10DE, 0x07DC),
- .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_HAS_GEAR_MODE|DEV_NEED_MSI_FIX,
+ .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V12|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_HAS_GEAR_MODE|DEV_NEED_MSI_FIX,
},
{ /* MCP73 Ethernet Controller */
PCI_DEVICE(0x10DE, 0x07DD),
- .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_HAS_GEAR_MODE|DEV_NEED_MSI_FIX,
+ .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V12|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_HAS_GEAR_MODE|DEV_NEED_MSI_FIX,
},
{ /* MCP73 Ethernet Controller */
PCI_DEVICE(0x10DE, 0x07DE),
- .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_HAS_GEAR_MODE|DEV_NEED_MSI_FIX,
+ .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V12|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_HAS_GEAR_MODE|DEV_NEED_MSI_FIX,
},
{ /* MCP73 Ethernet Controller */
PCI_DEVICE(0x10DE, 0x07DF),
- .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_HAS_GEAR_MODE|DEV_NEED_MSI_FIX,
+ .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V12|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_HAS_GEAR_MODE|DEV_NEED_MSI_FIX,
},
{ /* MCP77 Ethernet Controller */
PCI_DEVICE(0x10DE, 0x0760),
- .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V2|DEV_HAS_STATISTICS_V3|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT2|DEV_HAS_GEAR_MODE|DEV_NEED_PHY_INIT_FIX|DEV_NEED_MSI_FIX,
+ .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V2|DEV_HAS_STATISTICS_V123|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT2|DEV_HAS_GEAR_MODE|DEV_NEED_PHY_INIT_FIX|DEV_NEED_MSI_FIX,
},
{ /* MCP77 Ethernet Controller */
PCI_DEVICE(0x10DE, 0x0761),
- .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V2|DEV_HAS_STATISTICS_V3|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT2|DEV_HAS_GEAR_MODE|DEV_NEED_PHY_INIT_FIX|DEV_NEED_MSI_FIX,
+ .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V2|DEV_HAS_STATISTICS_V123|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT2|DEV_HAS_GEAR_MODE|DEV_NEED_PHY_INIT_FIX|DEV_NEED_MSI_FIX,
},
{ /* MCP77 Ethernet Controller */
PCI_DEVICE(0x10DE, 0x0762),
- .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V2|DEV_HAS_STATISTICS_V3|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT2|DEV_HAS_GEAR_MODE|DEV_NEED_PHY_INIT_FIX|DEV_NEED_MSI_FIX,
+ .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V2|DEV_HAS_STATISTICS_V123|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT2|DEV_HAS_GEAR_MODE|DEV_NEED_PHY_INIT_FIX|DEV_NEED_MSI_FIX,
},
{ /* MCP77 Ethernet Controller */
PCI_DEVICE(0x10DE, 0x0763),
- .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V2|DEV_HAS_STATISTICS_V3|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT2|DEV_HAS_GEAR_MODE|DEV_NEED_PHY_INIT_FIX|DEV_NEED_MSI_FIX,
+ .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V2|DEV_HAS_STATISTICS_V123|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT2|DEV_HAS_GEAR_MODE|DEV_NEED_PHY_INIT_FIX|DEV_NEED_MSI_FIX,
},
{ /* MCP79 Ethernet Controller */
PCI_DEVICE(0x10DE, 0x0AB0),
- .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V3|DEV_HAS_STATISTICS_V3|DEV_HAS_TEST_EXTENDED|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT2|DEV_HAS_GEAR_MODE|DEV_NEED_PHY_INIT_FIX|DEV_NEED_MSI_FIX,
+ .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V3|DEV_HAS_STATISTICS_V123|DEV_HAS_TEST_EXTENDED|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT2|DEV_HAS_GEAR_MODE|DEV_NEED_PHY_INIT_FIX|DEV_NEED_MSI_FIX,
},
{ /* MCP79 Ethernet Controller */
PCI_DEVICE(0x10DE, 0x0AB1),
- .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V3|DEV_HAS_STATISTICS_V3|DEV_HAS_TEST_EXTENDED|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT2|DEV_HAS_GEAR_MODE|DEV_NEED_PHY_INIT_FIX|DEV_NEED_MSI_FIX,
+ .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V3|DEV_HAS_STATISTICS_V123|DEV_HAS_TEST_EXTENDED|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT2|DEV_HAS_GEAR_MODE|DEV_NEED_PHY_INIT_FIX|DEV_NEED_MSI_FIX,
},
{ /* MCP79 Ethernet Controller */
PCI_DEVICE(0x10DE, 0x0AB2),
- .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V3|DEV_HAS_STATISTICS_V3|DEV_HAS_TEST_EXTENDED|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT2|DEV_HAS_GEAR_MODE|DEV_NEED_PHY_INIT_FIX|DEV_NEED_MSI_FIX,
+ .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V3|DEV_HAS_STATISTICS_V123|DEV_HAS_TEST_EXTENDED|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT2|DEV_HAS_GEAR_MODE|DEV_NEED_PHY_INIT_FIX|DEV_NEED_MSI_FIX,
},
{ /* MCP79 Ethernet Controller */
PCI_DEVICE(0x10DE, 0x0AB3),
- .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V3|DEV_HAS_STATISTICS_V3|DEV_HAS_TEST_EXTENDED|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT2|DEV_HAS_GEAR_MODE|DEV_NEED_PHY_INIT_FIX|DEV_NEED_MSI_FIX,
+ .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V3|DEV_HAS_STATISTICS_V123|DEV_HAS_TEST_EXTENDED|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT2|DEV_HAS_GEAR_MODE|DEV_NEED_PHY_INIT_FIX|DEV_NEED_MSI_FIX,
},
{ /* MCP89 Ethernet Controller */
PCI_DEVICE(0x10DE, 0x0D7D),
- .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V3|DEV_HAS_STATISTICS_V3|DEV_HAS_TEST_EXTENDED|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_HAS_GEAR_MODE|DEV_NEED_PHY_INIT_FIX,
+ .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V3|DEV_HAS_STATISTICS_V123|DEV_HAS_TEST_EXTENDED|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_HAS_GEAR_MODE|DEV_NEED_PHY_INIT_FIX,
},
{0,},
};
diff --git a/drivers/net/fs_enet/fs_enet-main.c b/drivers/net/fs_enet/fs_enet-main.c
index 309a0eaddd8..f08cff9020b 100644
--- a/drivers/net/fs_enet/fs_enet-main.c
+++ b/drivers/net/fs_enet/fs_enet-main.c
@@ -963,12 +963,11 @@ static const struct ethtool_ops fs_ethtool_ops = {
static int fs_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
{
struct fs_enet_private *fep = netdev_priv(dev);
- struct mii_ioctl_data *mii = (struct mii_ioctl_data *)&rq->ifr_data;
if (!netif_running(dev))
return -EINVAL;
- return phy_mii_ioctl(fep->phydev, mii, cmd);
+ return phy_mii_ioctl(fep->phydev, rq, cmd);
}
extern int fs_mii_connect(struct net_device *dev);
diff --git a/drivers/net/fsl_pq_mdio.c b/drivers/net/fsl_pq_mdio.c
index b4c41d72c42..f53f850b641 100644
--- a/drivers/net/fsl_pq_mdio.c
+++ b/drivers/net/fsl_pq_mdio.c
@@ -35,6 +35,7 @@
#include <linux/mii.h>
#include <linux/phy.h>
#include <linux/of.h>
+#include <linux/of_address.h>
#include <linux/of_mdio.h>
#include <linux/of_platform.h>
diff --git a/drivers/net/fsl_pq_mdio.h b/drivers/net/fsl_pq_mdio.h
index 1f7d865cedb..bd17a2a0139 100644
--- a/drivers/net/fsl_pq_mdio.h
+++ b/drivers/net/fsl_pq_mdio.h
@@ -39,7 +39,7 @@ struct fsl_pq_mdio {
u8 reserved[28]; /* Space holder */
u32 utbipar; /* TBI phy address reg (only on UCC) */
u8 res4[2728];
-} __attribute__ ((packed));
+} __packed;
int fsl_pq_mdio_read(struct mii_bus *bus, int mii_id, int regnum);
int fsl_pq_mdio_write(struct mii_bus *bus, int mii_id, int regnum, u16 value);
diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c
index 28b53d1cd4f..a1b6301bc67 100644
--- a/drivers/net/gianfar.c
+++ b/drivers/net/gianfar.c
@@ -85,6 +85,7 @@
#include <linux/net_tstamp.h>
#include <asm/io.h>
+#include <asm/reg.h>
#include <asm/irq.h>
#include <asm/uaccess.h>
#include <linux/module.h>
@@ -685,8 +686,8 @@ static int gfar_of_init(struct of_device *ofdev, struct net_device **pdev)
priv->rx_queue[i] = NULL;
for (i = 0; i < priv->num_tx_queues; i++) {
- priv->tx_queue[i] = (struct gfar_priv_tx_q *)kzalloc(
- sizeof (struct gfar_priv_tx_q), GFP_KERNEL);
+ priv->tx_queue[i] = kzalloc(sizeof(struct gfar_priv_tx_q),
+ GFP_KERNEL);
if (!priv->tx_queue[i]) {
err = -ENOMEM;
goto tx_alloc_failed;
@@ -698,8 +699,8 @@ static int gfar_of_init(struct of_device *ofdev, struct net_device **pdev)
}
for (i = 0; i < priv->num_rx_queues; i++) {
- priv->rx_queue[i] = (struct gfar_priv_rx_q *)kzalloc(
- sizeof (struct gfar_priv_rx_q), GFP_KERNEL);
+ priv->rx_queue[i] = kzalloc(sizeof(struct gfar_priv_rx_q),
+ GFP_KERNEL);
if (!priv->rx_queue[i]) {
err = -ENOMEM;
goto rx_alloc_failed;
@@ -846,7 +847,7 @@ static int gfar_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
if (!priv->phydev)
return -ENODEV;
- return phy_mii_ioctl(priv->phydev, if_mii(rq), cmd);
+ return phy_mii_ioctl(priv->phydev, rq, cmd);
}
static unsigned int reverse_bitmap(unsigned int bit_map, unsigned int max_qs)
@@ -916,7 +917,7 @@ static void gfar_init_filer_table(struct gfar_private *priv)
rqfar = cluster_entry_per_class(priv, rqfar, RQFPR_IPV4 | RQFPR_UDP);
rqfar = cluster_entry_per_class(priv, rqfar, RQFPR_IPV4 | RQFPR_TCP);
- /* cur_filer_idx indicated the fisrt non-masked rule */
+ /* cur_filer_idx indicated the first non-masked rule */
priv->cur_filer_idx = rqfar;
/* Rest are masked rules */
@@ -928,6 +929,34 @@ static void gfar_init_filer_table(struct gfar_private *priv)
}
}
+static void gfar_detect_errata(struct gfar_private *priv)
+{
+ struct device *dev = &priv->ofdev->dev;
+ unsigned int pvr = mfspr(SPRN_PVR);
+ unsigned int svr = mfspr(SPRN_SVR);
+ unsigned int mod = (svr >> 16) & 0xfff6; /* w/o E suffix */
+ unsigned int rev = svr & 0xffff;
+
+ /* MPC8313 Rev 2.0 and higher; All MPC837x */
+ if ((pvr == 0x80850010 && mod == 0x80b0 && rev >= 0x0020) ||
+ (pvr == 0x80861010 && (mod & 0xfff9) == 0x80c0))
+ priv->errata |= GFAR_ERRATA_74;
+
+ /* MPC8313 and MPC837x all rev */
+ if ((pvr == 0x80850010 && mod == 0x80b0) ||
+ (pvr == 0x80861010 && (mod & 0xfff9) == 0x80c0))
+ priv->errata |= GFAR_ERRATA_76;
+
+ /* MPC8313 and MPC837x all rev */
+ if ((pvr == 0x80850010 && mod == 0x80b0) ||
+ (pvr == 0x80861010 && (mod & 0xfff9) == 0x80c0))
+ priv->errata |= GFAR_ERRATA_A002;
+
+ if (priv->errata)
+ dev_info(dev, "enabled errata workarounds, flags: 0x%x\n",
+ priv->errata);
+}
+
/* Set up the ethernet device structure, private data,
* and anything else we need before we start */
static int gfar_probe(struct of_device *ofdev,
@@ -960,6 +989,8 @@ static int gfar_probe(struct of_device *ofdev,
dev_set_drvdata(&ofdev->dev, priv);
regs = priv->gfargrp[0].regs;
+ gfar_detect_errata(priv);
+
/* Stop the DMA engine now, in case it was running before */
/* (The firmware could have used it, and left it running). */
gfar_halt(dev);
@@ -974,7 +1005,10 @@ static int gfar_probe(struct of_device *ofdev,
gfar_write(&regs->maccfg1, tempval);
/* Initialize MACCFG2. */
- gfar_write(&regs->maccfg2, MACCFG2_INIT_SETTINGS);
+ tempval = MACCFG2_INIT_SETTINGS;
+ if (gfar_has_errata(priv, GFAR_ERRATA_74))
+ tempval |= MACCFG2_HUGEFRAME | MACCFG2_LENGTHCHECK;
+ gfar_write(&regs->maccfg2, tempval);
/* Initialize ECNTRL */
gfar_write(&regs->ecntrl, ECNTRL_INIT_SETTINGS);
@@ -1541,6 +1575,29 @@ static void init_registers(struct net_device *dev)
gfar_write(&regs->minflr, MINFLR_INIT_SETTINGS);
}
+static int __gfar_is_rx_idle(struct gfar_private *priv)
+{
+ u32 res;
+
+ /*
+ * Normaly TSEC should not hang on GRS commands, so we should
+ * actually wait for IEVENT_GRSC flag.
+ */
+ if (likely(!gfar_has_errata(priv, GFAR_ERRATA_A002)))
+ return 0;
+
+ /*
+ * Read the eTSEC register at offset 0xD1C. If bits 7-14 are
+ * the same as bits 23-30, the eTSEC Rx is assumed to be idle
+ * and the Rx can be safely reset.
+ */
+ res = gfar_read((void __iomem *)priv->gfargrp[0].regs + 0xd1c);
+ res &= 0x7f807f80;
+ if ((res & 0xffff) == (res >> 16))
+ return 1;
+
+ return 0;
+}
/* Halt the receive and transmit queues */
static void gfar_halt_nodisable(struct net_device *dev)
@@ -1564,12 +1621,18 @@ static void gfar_halt_nodisable(struct net_device *dev)
tempval = gfar_read(&regs->dmactrl);
if ((tempval & (DMACTRL_GRS | DMACTRL_GTS))
!= (DMACTRL_GRS | DMACTRL_GTS)) {
+ int ret;
+
tempval |= (DMACTRL_GRS | DMACTRL_GTS);
gfar_write(&regs->dmactrl, tempval);
- spin_event_timeout(((gfar_read(&regs->ievent) &
- (IEVENT_GRSC | IEVENT_GTSC)) ==
- (IEVENT_GRSC | IEVENT_GTSC)), -1, 0);
+ do {
+ ret = spin_event_timeout(((gfar_read(&regs->ievent) &
+ (IEVENT_GRSC | IEVENT_GTSC)) ==
+ (IEVENT_GRSC | IEVENT_GTSC)), 1000000, 0);
+ if (!ret && !(gfar_read(&regs->ievent) & IEVENT_GRSC))
+ ret = __gfar_is_rx_idle(priv);
+ } while (!ret);
}
}
@@ -1987,6 +2050,20 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev)
unsigned int nr_frags, nr_txbds, length;
union skb_shared_tx *shtx;
+ /*
+ * TOE=1 frames larger than 2500 bytes may see excess delays
+ * before start of transmission.
+ */
+ if (unlikely(gfar_has_errata(priv, GFAR_ERRATA_76) &&
+ skb->ip_summed == CHECKSUM_PARTIAL &&
+ skb->len > 2500)) {
+ int ret;
+
+ ret = skb_checksum_help(skb);
+ if (ret)
+ return ret;
+ }
+
rq = skb->queue_mapping;
tx_queue = priv->tx_queue[rq];
txq = netdev_get_tx_queue(dev, rq);
@@ -2300,7 +2377,8 @@ static int gfar_change_mtu(struct net_device *dev, int new_mtu)
* to allow huge frames, and to check the length */
tempval = gfar_read(&regs->maccfg2);
- if (priv->rx_buffer_size > DEFAULT_RX_BUFFER_SIZE)
+ if (priv->rx_buffer_size > DEFAULT_RX_BUFFER_SIZE ||
+ gfar_has_errata(priv, GFAR_ERRATA_74))
tempval |= (MACCFG2_HUGEFRAME | MACCFG2_LENGTHCHECK);
else
tempval &= ~(MACCFG2_HUGEFRAME | MACCFG2_LENGTHCHECK);
@@ -2342,6 +2420,15 @@ static void gfar_timeout(struct net_device *dev)
schedule_work(&priv->reset_task);
}
+static void gfar_align_skb(struct sk_buff *skb)
+{
+ /* We need the data buffer to be aligned properly. We will reserve
+ * as many bytes as needed to align the data properly
+ */
+ skb_reserve(skb, RXBUF_ALIGNMENT -
+ (((unsigned long) skb->data) & (RXBUF_ALIGNMENT - 1)));
+}
+
/* Interrupt Handler for Transmit complete */
static int gfar_clean_tx_ring(struct gfar_priv_tx_q *tx_queue)
{
@@ -2426,9 +2513,10 @@ static int gfar_clean_tx_ring(struct gfar_priv_tx_q *tx_queue)
*/
if (skb_queue_len(&priv->rx_recycle) < rx_queue->rx_ring_size &&
skb_recycle_check(skb, priv->rx_buffer_size +
- RXBUF_ALIGNMENT))
+ RXBUF_ALIGNMENT)) {
+ gfar_align_skb(skb);
__skb_queue_head(&priv->rx_recycle, skb);
- else
+ } else
dev_kfree_skb_any(skb);
tx_queue->tx_skbuff[skb_dirtytx] = NULL;
@@ -2491,29 +2579,28 @@ static void gfar_new_rxbdp(struct gfar_priv_rx_q *rx_queue, struct rxbd8 *bdp,
gfar_init_rxbdp(rx_queue, bdp, buf);
}
-
-struct sk_buff * gfar_new_skb(struct net_device *dev)
+static struct sk_buff * gfar_alloc_skb(struct net_device *dev)
{
- unsigned int alignamount;
struct gfar_private *priv = netdev_priv(dev);
struct sk_buff *skb = NULL;
- skb = __skb_dequeue(&priv->rx_recycle);
- if (!skb)
- skb = netdev_alloc_skb(dev,
- priv->rx_buffer_size + RXBUF_ALIGNMENT);
-
+ skb = netdev_alloc_skb(dev, priv->rx_buffer_size + RXBUF_ALIGNMENT);
if (!skb)
return NULL;
- alignamount = RXBUF_ALIGNMENT -
- (((unsigned long) skb->data) & (RXBUF_ALIGNMENT - 1));
+ gfar_align_skb(skb);
- /* We need the data buffer to be aligned properly. We will reserve
- * as many bytes as needed to align the data properly
- */
- skb_reserve(skb, alignamount);
- GFAR_CB(skb)->alignamount = alignamount;
+ return skb;
+}
+
+struct sk_buff * gfar_new_skb(struct net_device *dev)
+{
+ struct gfar_private *priv = netdev_priv(dev);
+ struct sk_buff *skb = NULL;
+
+ skb = __skb_dequeue(&priv->rx_recycle);
+ if (!skb)
+ skb = gfar_alloc_skb(dev);
return skb;
}
@@ -2666,17 +2753,8 @@ int gfar_clean_rx_ring(struct gfar_priv_rx_q *rx_queue, int rx_work_limit)
if (unlikely(!newskb))
newskb = skb;
- else if (skb) {
- /*
- * We need to un-reserve() the skb to what it
- * was before gfar_new_skb() re-aligned
- * it to an RXBUF_ALIGNMENT boundary
- * before we put the skb back on the
- * recycle list.
- */
- skb_reserve(skb, -GFAR_CB(skb)->alignamount);
+ else if (skb)
__skb_queue_head(&priv->rx_recycle, skb);
- }
} else {
/* Increment the number of packets */
rx_queue->stats.rx_packets++;
diff --git a/drivers/net/gianfar.h b/drivers/net/gianfar.h
index ac4a92e08c0..710810e2adb 100644
--- a/drivers/net/gianfar.h
+++ b/drivers/net/gianfar.h
@@ -1025,6 +1025,12 @@ struct gfar_priv_grp {
char int_name_er[GFAR_INT_NAME_MAX];
};
+enum gfar_errata {
+ GFAR_ERRATA_74 = 0x01,
+ GFAR_ERRATA_76 = 0x02,
+ GFAR_ERRATA_A002 = 0x04,
+};
+
/* Struct stolen almost completely (and shamelessly) from the FCC enet source
* (Ok, that's not so true anymore, but there is a family resemblence)
* The GFAR buffer descriptors track the ring buffers. The rx_bd_base
@@ -1049,6 +1055,7 @@ struct gfar_private {
struct device_node *node;
struct net_device *ndev;
struct of_device *ofdev;
+ enum gfar_errata errata;
struct gfar_priv_grp gfargrp[MAXGROUPS];
struct gfar_priv_tx_q *tx_queue[MAX_TX_QS];
@@ -1111,6 +1118,12 @@ struct gfar_private {
extern unsigned int ftp_rqfpr[MAX_FILER_IDX + 1];
extern unsigned int ftp_rqfcr[MAX_FILER_IDX + 1];
+static inline int gfar_has_errata(struct gfar_private *priv,
+ enum gfar_errata err)
+{
+ return priv->errata & err;
+}
+
static inline u32 gfar_read(volatile unsigned __iomem *addr)
{
u32 val;
diff --git a/drivers/net/greth.c b/drivers/net/greth.c
index 3a029d02c2b..4d09eab3548 100644
--- a/drivers/net/greth.c
+++ b/drivers/net/greth.c
@@ -1555,7 +1555,6 @@ static int __devinit greth_of_probe(struct of_device *ofdev, const struct of_dev
}
/* setup NAPI */
- memset(&greth->napi, 0, sizeof(greth->napi));
netif_napi_add(dev, &greth->napi, greth_poll, 64);
return 0;
diff --git a/drivers/net/hamachi.c b/drivers/net/hamachi.c
index 61f2b1cfcd4..49aac7027fb 100644
--- a/drivers/net/hamachi.c
+++ b/drivers/net/hamachi.c
@@ -492,7 +492,6 @@ struct hamachi_private {
struct sk_buff* tx_skbuff[TX_RING_SIZE];
dma_addr_t tx_ring_dma;
dma_addr_t rx_ring_dma;
- struct net_device_stats stats;
struct timer_list timer; /* Media selection timer. */
/* Frequently used and paired value: keep adjacent for cache effect. */
spinlock_t lock;
@@ -1036,7 +1035,7 @@ static inline int hamachi_tx(struct net_device *dev)
if (entry >= TX_RING_SIZE-1)
hmp->tx_ring[TX_RING_SIZE-1].status_n_length |=
cpu_to_le32(DescEndRing);
- hmp->stats.tx_packets++;
+ dev->stats.tx_packets++;
}
return 0;
@@ -1167,7 +1166,7 @@ static void hamachi_tx_timeout(struct net_device *dev)
/* Trigger an immediate transmit demand. */
dev->trans_start = jiffies; /* prevent tx timeout */
- hmp->stats.tx_errors++;
+ dev->stats.tx_errors++;
/* Restart the chip's Tx/Rx processes . */
writew(0x0002, ioaddr + TxCmd); /* STOP Tx */
@@ -1434,7 +1433,7 @@ static irqreturn_t hamachi_interrupt(int irq, void *dev_instance)
if (entry >= TX_RING_SIZE-1)
hmp->tx_ring[TX_RING_SIZE-1].status_n_length |=
cpu_to_le32(DescEndRing);
- hmp->stats.tx_packets++;
+ dev->stats.tx_packets++;
}
if (hmp->cur_tx - hmp->dirty_tx < TX_RING_SIZE - 4){
/* The ring is no longer full */
@@ -1525,18 +1524,22 @@ static int hamachi_rx(struct net_device *dev)
le32_to_cpu(hmp->rx_ring[(hmp->cur_rx+1) % RX_RING_SIZE].status_n_length) & 0xffff0000,
le32_to_cpu(hmp->rx_ring[(hmp->cur_rx+1) % RX_RING_SIZE].status_n_length) & 0x0000ffff,
le32_to_cpu(hmp->rx_ring[(hmp->cur_rx-1) % RX_RING_SIZE].status_n_length));
- hmp->stats.rx_length_errors++;
+ dev->stats.rx_length_errors++;
} /* else Omit for prototype errata??? */
if (frame_status & 0x00380000) {
/* There was an error. */
if (hamachi_debug > 2)
printk(KERN_DEBUG " hamachi_rx() Rx error was %8.8x.\n",
frame_status);
- hmp->stats.rx_errors++;
- if (frame_status & 0x00600000) hmp->stats.rx_length_errors++;
- if (frame_status & 0x00080000) hmp->stats.rx_frame_errors++;
- if (frame_status & 0x00100000) hmp->stats.rx_crc_errors++;
- if (frame_status < 0) hmp->stats.rx_dropped++;
+ dev->stats.rx_errors++;
+ if (frame_status & 0x00600000)
+ dev->stats.rx_length_errors++;
+ if (frame_status & 0x00080000)
+ dev->stats.rx_frame_errors++;
+ if (frame_status & 0x00100000)
+ dev->stats.rx_crc_errors++;
+ if (frame_status < 0)
+ dev->stats.rx_dropped++;
} else {
struct sk_buff *skb;
/* Omit CRC */
@@ -1654,7 +1657,7 @@ static int hamachi_rx(struct net_device *dev)
#endif /* RX_CHECKSUM */
netif_rx(skb);
- hmp->stats.rx_packets++;
+ dev->stats.rx_packets++;
}
entry = (++hmp->cur_rx) % RX_RING_SIZE;
}
@@ -1724,9 +1727,9 @@ static void hamachi_error(struct net_device *dev, int intr_status)
dev->name, intr_status);
/* Hmmmmm, it's not clear how to recover from PCI faults. */
if (intr_status & (IntrTxPCIErr | IntrTxPCIFault))
- hmp->stats.tx_fifo_errors++;
+ dev->stats.tx_fifo_errors++;
if (intr_status & (IntrRxPCIErr | IntrRxPCIFault))
- hmp->stats.rx_fifo_errors++;
+ dev->stats.rx_fifo_errors++;
}
static int hamachi_close(struct net_device *dev)
@@ -1828,19 +1831,27 @@ static struct net_device_stats *hamachi_get_stats(struct net_device *dev)
so I think I'll comment it out here and see if better things
happen.
*/
- /* hmp->stats.tx_packets = readl(ioaddr + 0x000); */
-
- hmp->stats.rx_bytes = readl(ioaddr + 0x330); /* Total Uni+Brd+Multi */
- hmp->stats.tx_bytes = readl(ioaddr + 0x3B0); /* Total Uni+Brd+Multi */
- hmp->stats.multicast = readl(ioaddr + 0x320); /* Multicast Rx */
-
- hmp->stats.rx_length_errors = readl(ioaddr + 0x368); /* Over+Undersized */
- hmp->stats.rx_over_errors = readl(ioaddr + 0x35C); /* Jabber */
- hmp->stats.rx_crc_errors = readl(ioaddr + 0x360); /* Jabber */
- hmp->stats.rx_frame_errors = readl(ioaddr + 0x364); /* Symbol Errs */
- hmp->stats.rx_missed_errors = readl(ioaddr + 0x36C); /* Dropped */
-
- return &hmp->stats;
+ /* dev->stats.tx_packets = readl(ioaddr + 0x000); */
+
+ /* Total Uni+Brd+Multi */
+ dev->stats.rx_bytes = readl(ioaddr + 0x330);
+ /* Total Uni+Brd+Multi */
+ dev->stats.tx_bytes = readl(ioaddr + 0x3B0);
+ /* Multicast Rx */
+ dev->stats.multicast = readl(ioaddr + 0x320);
+
+ /* Over+Undersized */
+ dev->stats.rx_length_errors = readl(ioaddr + 0x368);
+ /* Jabber */
+ dev->stats.rx_over_errors = readl(ioaddr + 0x35C);
+ /* Jabber */
+ dev->stats.rx_crc_errors = readl(ioaddr + 0x360);
+ /* Symbol Errs */
+ dev->stats.rx_frame_errors = readl(ioaddr + 0x364);
+ /* Dropped */
+ dev->stats.rx_missed_errors = readl(ioaddr + 0x36C);
+
+ return &dev->stats;
}
static void set_rx_mode(struct net_device *dev)
diff --git a/drivers/net/hp100.c b/drivers/net/hp100.c
index 68e5ac8832a..095b17ecf60 100644
--- a/drivers/net/hp100.c
+++ b/drivers/net/hp100.c
@@ -168,7 +168,6 @@ struct hp100_private {
u_char mac1_mode;
u_char mac2_mode;
u_char hash_bytes[8];
- struct net_device_stats stats;
/* Rings for busmaster mode: */
hp100_ring_t *rxrhead; /* Head (oldest) index into rxring */
@@ -721,9 +720,10 @@ static int __devinit hp100_probe1(struct net_device *dev, int ioaddr,
/* Conversion to new PCI API :
* Pages are always aligned and zeroed, no need to it ourself.
* Doc says should be OK for EISA bus as well - Jean II */
- if ((lp->page_vaddr_algn = pci_alloc_consistent(lp->pci_dev, MAX_RINGSIZE, &page_baddr)) == NULL) {
+ lp->page_vaddr_algn = pci_alloc_consistent(lp->pci_dev, MAX_RINGSIZE, &page_baddr);
+ if (!lp->page_vaddr_algn) {
err = -ENOMEM;
- goto out2;
+ goto out_mem_ptr;
}
lp->whatever_offset = ((u_long) page_baddr) - ((u_long) lp->page_vaddr_algn);
@@ -799,6 +799,7 @@ out3:
pci_free_consistent(lp->pci_dev, MAX_RINGSIZE + 0x0f,
lp->page_vaddr_algn,
virt_to_whatever(dev, lp->page_vaddr_algn));
+out_mem_ptr:
if (mem_ptr_virt)
iounmap(mem_ptr_virt);
out2:
@@ -1071,7 +1072,7 @@ static void hp100_mmuinit(struct net_device *dev)
if (lp->mode == 1)
hp100_init_pdls(dev);
- /* Go to performance page and initalize isr and imr registers */
+ /* Go to performance page and initialize isr and imr registers */
hp100_page(PERFORMANCE);
hp100_outw(0xfefe, IRQ_MASK); /* mask off all ints */
hp100_outw(0xffff, IRQ_STATUS); /* ack IRQ */
@@ -1582,8 +1583,8 @@ static netdev_tx_t hp100_start_xmit_bm(struct sk_buff *skb,
spin_unlock_irqrestore(&lp->lock, flags);
/* Update statistics */
- lp->stats.tx_packets++;
- lp->stats.tx_bytes += skb->len;
+ dev->stats.tx_packets++;
+ dev->stats.tx_bytes += skb->len;
return NETDEV_TX_OK;
@@ -1740,8 +1741,8 @@ static netdev_tx_t hp100_start_xmit(struct sk_buff *skb,
hp100_outb(HP100_TX_CMD | HP100_SET_LB, OPTION_MSW); /* send packet */
- lp->stats.tx_packets++;
- lp->stats.tx_bytes += skb->len;
+ dev->stats.tx_packets++;
+ dev->stats.tx_bytes += skb->len;
hp100_ints_on();
spin_unlock_irqrestore(&lp->lock, flags);
@@ -1822,7 +1823,7 @@ static void hp100_rx(struct net_device *dev)
printk("hp100: %s: rx: couldn't allocate a sk_buff of size %d\n",
dev->name, pkt_len);
#endif
- lp->stats.rx_dropped++;
+ dev->stats.rx_dropped++;
} else { /* skb successfully allocated */
u_char *ptr;
@@ -1848,8 +1849,8 @@ static void hp100_rx(struct net_device *dev)
ptr[9], ptr[10], ptr[11]);
#endif
netif_rx(skb);
- lp->stats.rx_packets++;
- lp->stats.rx_bytes += pkt_len;
+ dev->stats.rx_packets++;
+ dev->stats.rx_bytes += pkt_len;
}
/* Indicate the card that we have got the packet */
@@ -1858,7 +1859,7 @@ static void hp100_rx(struct net_device *dev)
switch (header & 0x00070000) {
case (HP100_MULTI_ADDR_HASH << 16):
case (HP100_MULTI_ADDR_NO_HASH << 16):
- lp->stats.multicast++;
+ dev->stats.multicast++;
break;
}
} /* end of while(there are packets) loop */
@@ -1930,7 +1931,7 @@ static void hp100_rx_bm(struct net_device *dev)
if (ptr->skb == NULL) {
printk("hp100: %s: rx_bm: skb null\n", dev->name);
/* can happen if we only allocated room for the pdh due to memory shortage. */
- lp->stats.rx_dropped++;
+ dev->stats.rx_dropped++;
} else {
skb_trim(ptr->skb, pkt_len); /* Shorten it */
ptr->skb->protocol =
@@ -1938,14 +1939,14 @@ static void hp100_rx_bm(struct net_device *dev)
netif_rx(ptr->skb); /* Up and away... */
- lp->stats.rx_packets++;
- lp->stats.rx_bytes += pkt_len;
+ dev->stats.rx_packets++;
+ dev->stats.rx_bytes += pkt_len;
}
switch (header & 0x00070000) {
case (HP100_MULTI_ADDR_HASH << 16):
case (HP100_MULTI_ADDR_NO_HASH << 16):
- lp->stats.multicast++;
+ dev->stats.multicast++;
break;
}
} else {
@@ -1954,7 +1955,7 @@ static void hp100_rx_bm(struct net_device *dev)
#endif
if (ptr->skb != NULL)
dev_kfree_skb_any(ptr->skb);
- lp->stats.rx_errors++;
+ dev->stats.rx_errors++;
}
lp->rxrhead = lp->rxrhead->next;
@@ -1992,14 +1993,13 @@ static struct net_device_stats *hp100_get_stats(struct net_device *dev)
hp100_update_stats(dev);
hp100_ints_on();
spin_unlock_irqrestore(&lp->lock, flags);
- return &(lp->stats);
+ return &(dev->stats);
}
static void hp100_update_stats(struct net_device *dev)
{
int ioaddr = dev->base_addr;
u_short val;
- struct hp100_private *lp = netdev_priv(dev);
#ifdef HP100_DEBUG_B
hp100_outw(0x4216, TRACE);
@@ -2009,14 +2009,14 @@ static void hp100_update_stats(struct net_device *dev)
/* Note: Statistics counters clear when read. */
hp100_page(MAC_CTRL);
val = hp100_inw(DROPPED) & 0x0fff;
- lp->stats.rx_errors += val;
- lp->stats.rx_over_errors += val;
+ dev->stats.rx_errors += val;
+ dev->stats.rx_over_errors += val;
val = hp100_inb(CRC);
- lp->stats.rx_errors += val;
- lp->stats.rx_crc_errors += val;
+ dev->stats.rx_errors += val;
+ dev->stats.rx_crc_errors += val;
val = hp100_inb(ABORT);
- lp->stats.tx_errors += val;
- lp->stats.tx_aborted_errors += val;
+ dev->stats.tx_errors += val;
+ dev->stats.tx_aborted_errors += val;
hp100_page(PERFORMANCE);
}
@@ -2025,7 +2025,6 @@ static void hp100_misc_interrupt(struct net_device *dev)
#ifdef HP100_DEBUG_B
int ioaddr = dev->base_addr;
#endif
- struct hp100_private *lp = netdev_priv(dev);
#ifdef HP100_DEBUG_B
int ioaddr = dev->base_addr;
@@ -2034,8 +2033,8 @@ static void hp100_misc_interrupt(struct net_device *dev)
#endif
/* Note: Statistics counters clear when read. */
- lp->stats.rx_errors++;
- lp->stats.tx_errors++;
+ dev->stats.rx_errors++;
+ dev->stats.tx_errors++;
}
static void hp100_clear_stats(struct hp100_private *lp, int ioaddr)
diff --git a/drivers/net/ibm_newemac/core.c b/drivers/net/ibm_newemac/core.c
index b150c102ca5..eeec7bc2ce7 100644
--- a/drivers/net/ibm_newemac/core.c
+++ b/drivers/net/ibm_newemac/core.c
@@ -1045,7 +1045,7 @@ static int emac_change_mtu(struct net_device *ndev, int new_mtu)
DBG(dev, "change_mtu(%d)" NL, new_mtu);
if (netif_running(ndev)) {
- /* Check if we really need to reinitalize RX ring */
+ /* Check if we really need to reinitialize RX ring */
if (emac_rx_skb_size(ndev->mtu) != emac_rx_skb_size(new_mtu))
ret = emac_resize_rx_ring(dev, new_mtu);
}
@@ -2339,11 +2339,11 @@ static int __devinit emac_wait_deps(struct emac_instance *dev)
deps[EMAC_DEP_MDIO_IDX].phandle = dev->mdio_ph;
if (dev->blist && dev->blist > emac_boot_list)
deps[EMAC_DEP_PREV_IDX].phandle = 0xffffffffu;
- bus_register_notifier(&of_platform_bus_type, &emac_of_bus_notifier);
+ bus_register_notifier(&platform_bus_type, &emac_of_bus_notifier);
wait_event_timeout(emac_probe_wait,
emac_check_deps(dev, deps),
EMAC_PROBE_DEP_TIMEOUT);
- bus_unregister_notifier(&of_platform_bus_type, &emac_of_bus_notifier);
+ bus_unregister_notifier(&platform_bus_type, &emac_of_bus_notifier);
err = emac_check_deps(dev, deps) ? 0 : -ENODEV;
for (i = 0; i < EMAC_DEP_COUNT; i++) {
if (deps[i].node)
diff --git a/drivers/net/igb/e1000_82575.c b/drivers/net/igb/e1000_82575.c
index 86438b59fa2..187622f1c81 100644
--- a/drivers/net/igb/e1000_82575.c
+++ b/drivers/net/igb/e1000_82575.c
@@ -63,6 +63,7 @@ static bool igb_sgmii_active_82575(struct e1000_hw *);
static s32 igb_reset_init_script_82575(struct e1000_hw *);
static s32 igb_read_mac_addr_82575(struct e1000_hw *);
static s32 igb_set_pcie_completion_timeout(struct e1000_hw *hw);
+static s32 igb_reset_mdicnfg_82580(struct e1000_hw *hw);
static const u16 e1000_82580_rxpbs_table[] =
{ 36, 72, 144, 1, 2, 4, 8, 16,
@@ -70,6 +71,35 @@ static const u16 e1000_82580_rxpbs_table[] =
#define E1000_82580_RXPBS_TABLE_SIZE \
(sizeof(e1000_82580_rxpbs_table)/sizeof(u16))
+/**
+ * igb_sgmii_uses_mdio_82575 - Determine if I2C pins are for external MDIO
+ * @hw: pointer to the HW structure
+ *
+ * Called to determine if the I2C pins are being used for I2C or as an
+ * external MDIO interface since the two options are mutually exclusive.
+ **/
+static bool igb_sgmii_uses_mdio_82575(struct e1000_hw *hw)
+{
+ u32 reg = 0;
+ bool ext_mdio = false;
+
+ switch (hw->mac.type) {
+ case e1000_82575:
+ case e1000_82576:
+ reg = rd32(E1000_MDIC);
+ ext_mdio = !!(reg & E1000_MDIC_DEST);
+ break;
+ case e1000_82580:
+ case e1000_i350:
+ reg = rd32(E1000_MDICNFG);
+ ext_mdio = !!(reg & E1000_MDICNFG_EXT_MDIO);
+ break;
+ default:
+ break;
+ }
+ return ext_mdio;
+}
+
static s32 igb_get_invariants_82575(struct e1000_hw *hw)
{
struct e1000_phy_info *phy = &hw->phy;
@@ -130,27 +160,15 @@ static s32 igb_get_invariants_82575(struct e1000_hw *hw)
switch (ctrl_ext & E1000_CTRL_EXT_LINK_MODE_MASK) {
case E1000_CTRL_EXT_LINK_MODE_SGMII:
dev_spec->sgmii_active = true;
- ctrl_ext |= E1000_CTRL_I2C_ENA;
break;
case E1000_CTRL_EXT_LINK_MODE_1000BASE_KX:
case E1000_CTRL_EXT_LINK_MODE_PCIE_SERDES:
hw->phy.media_type = e1000_media_type_internal_serdes;
- ctrl_ext |= E1000_CTRL_I2C_ENA;
break;
default:
- ctrl_ext &= ~E1000_CTRL_I2C_ENA;
break;
}
- wr32(E1000_CTRL_EXT, ctrl_ext);
-
- /*
- * if using i2c make certain the MDICNFG register is cleared to prevent
- * communications from being misrouted to the mdic registers
- */
- if ((ctrl_ext & E1000_CTRL_I2C_ENA) && (hw->mac.type == e1000_82580))
- wr32(E1000_MDICNFG, 0);
-
/* Set mta register count */
mac->mta_reg_count = 128;
/* Set rar entry count */
@@ -228,19 +246,29 @@ static s32 igb_get_invariants_82575(struct e1000_hw *hw)
phy->autoneg_mask = AUTONEG_ADVERTISE_SPEED_DEFAULT;
phy->reset_delay_us = 100;
+ ctrl_ext = rd32(E1000_CTRL_EXT);
+
/* PHY function pointers */
if (igb_sgmii_active_82575(hw)) {
- phy->ops.reset = igb_phy_hw_reset_sgmii_82575;
- phy->ops.read_reg = igb_read_phy_reg_sgmii_82575;
- phy->ops.write_reg = igb_write_phy_reg_sgmii_82575;
+ phy->ops.reset = igb_phy_hw_reset_sgmii_82575;
+ ctrl_ext |= E1000_CTRL_I2C_ENA;
+ } else {
+ phy->ops.reset = igb_phy_hw_reset;
+ ctrl_ext &= ~E1000_CTRL_I2C_ENA;
+ }
+
+ wr32(E1000_CTRL_EXT, ctrl_ext);
+ igb_reset_mdicnfg_82580(hw);
+
+ if (igb_sgmii_active_82575(hw) && !igb_sgmii_uses_mdio_82575(hw)) {
+ phy->ops.read_reg = igb_read_phy_reg_sgmii_82575;
+ phy->ops.write_reg = igb_write_phy_reg_sgmii_82575;
} else if (hw->mac.type >= e1000_82580) {
- phy->ops.reset = igb_phy_hw_reset;
- phy->ops.read_reg = igb_read_phy_reg_82580;
- phy->ops.write_reg = igb_write_phy_reg_82580;
+ phy->ops.read_reg = igb_read_phy_reg_82580;
+ phy->ops.write_reg = igb_write_phy_reg_82580;
} else {
- phy->ops.reset = igb_phy_hw_reset;
- phy->ops.read_reg = igb_read_phy_reg_igp;
- phy->ops.write_reg = igb_write_phy_reg_igp;
+ phy->ops.read_reg = igb_read_phy_reg_igp;
+ phy->ops.write_reg = igb_write_phy_reg_igp;
}
/* set lan id */
@@ -295,6 +323,10 @@ static s32 igb_acquire_phy_82575(struct e1000_hw *hw)
if (hw->bus.func == E1000_FUNC_1)
mask = E1000_SWFW_PHY1_SM;
+ else if (hw->bus.func == E1000_FUNC_2)
+ mask = E1000_SWFW_PHY2_SM;
+ else if (hw->bus.func == E1000_FUNC_3)
+ mask = E1000_SWFW_PHY3_SM;
return igb_acquire_swfw_sync_82575(hw, mask);
}
@@ -312,6 +344,10 @@ static void igb_release_phy_82575(struct e1000_hw *hw)
if (hw->bus.func == E1000_FUNC_1)
mask = E1000_SWFW_PHY1_SM;
+ else if (hw->bus.func == E1000_FUNC_2)
+ mask = E1000_SWFW_PHY2_SM;
+ else if (hw->bus.func == E1000_FUNC_3)
+ mask = E1000_SWFW_PHY3_SM;
igb_release_swfw_sync_82575(hw, mask);
}
@@ -392,6 +428,7 @@ static s32 igb_get_phy_id_82575(struct e1000_hw *hw)
s32 ret_val = 0;
u16 phy_id;
u32 ctrl_ext;
+ u32 mdic;
/*
* For SGMII PHYs, we try the list of possible addresses until
@@ -406,6 +443,29 @@ static s32 igb_get_phy_id_82575(struct e1000_hw *hw)
goto out;
}
+ if (igb_sgmii_uses_mdio_82575(hw)) {
+ switch (hw->mac.type) {
+ case e1000_82575:
+ case e1000_82576:
+ mdic = rd32(E1000_MDIC);
+ mdic &= E1000_MDIC_PHY_MASK;
+ phy->addr = mdic >> E1000_MDIC_PHY_SHIFT;
+ break;
+ case e1000_82580:
+ case e1000_i350:
+ mdic = rd32(E1000_MDICNFG);
+ mdic &= E1000_MDICNFG_PHY_MASK;
+ phy->addr = mdic >> E1000_MDICNFG_PHY_SHIFT;
+ break;
+ default:
+ ret_val = -E1000_ERR_PHY;
+ goto out;
+ break;
+ }
+ ret_val = igb_get_phy_id(hw);
+ goto out;
+ }
+
/* Power on sgmii phy if it is disabled */
ctrl_ext = rd32(E1000_CTRL_EXT);
wr32(E1000_CTRL_EXT, ctrl_ext & ~E1000_CTRL_EXT_SDP3_DATA);
@@ -1493,6 +1553,43 @@ out:
}
/**
+ * igb_reset_mdicnfg_82580 - Reset MDICNFG destination and com_mdio bits
+ * @hw: pointer to the HW structure
+ *
+ * This resets the the MDICNFG.Destination and MDICNFG.Com_MDIO bits based on
+ * the values found in the EEPROM. This addresses an issue in which these
+ * bits are not restored from EEPROM after reset.
+ **/
+static s32 igb_reset_mdicnfg_82580(struct e1000_hw *hw)
+{
+ s32 ret_val = 0;
+ u32 mdicnfg;
+ u16 nvm_data;
+
+ if (hw->mac.type != e1000_82580)
+ goto out;
+ if (!igb_sgmii_active_82575(hw))
+ goto out;
+
+ ret_val = hw->nvm.ops.read(hw, NVM_INIT_CONTROL3_PORT_A +
+ NVM_82580_LAN_FUNC_OFFSET(hw->bus.func), 1,
+ &nvm_data);
+ if (ret_val) {
+ hw_dbg("NVM Read Error\n");
+ goto out;
+ }
+
+ mdicnfg = rd32(E1000_MDICNFG);
+ if (nvm_data & NVM_WORD24_EXT_MDIO)
+ mdicnfg |= E1000_MDICNFG_EXT_MDIO;
+ if (nvm_data & NVM_WORD24_COM_MDIO)
+ mdicnfg |= E1000_MDICNFG_COM_MDIO;
+ wr32(E1000_MDICNFG, mdicnfg);
+out:
+ return ret_val;
+}
+
+/**
* igb_reset_hw_82580 - Reset hardware
* @hw: pointer to the HW structure
*
@@ -1567,6 +1664,10 @@ static s32 igb_reset_hw_82580(struct e1000_hw *hw)
wr32(E1000_IMC, 0xffffffff);
icr = rd32(E1000_ICR);
+ ret_val = igb_reset_mdicnfg_82580(hw);
+ if (ret_val)
+ hw_dbg("Could not reset MDICNFG based on EEPROM\n");
+
/* Install any alternate MAC address into RAR0 */
ret_val = igb_check_alt_mac_addr(hw);
diff --git a/drivers/net/igb/e1000_defines.h b/drivers/net/igb/e1000_defines.h
index 24d9be64342..bbd2ec308eb 100644
--- a/drivers/net/igb/e1000_defines.h
+++ b/drivers/net/igb/e1000_defines.h
@@ -164,6 +164,8 @@
#define E1000_SWFW_EEP_SM 0x1
#define E1000_SWFW_PHY0_SM 0x2
#define E1000_SWFW_PHY1_SM 0x4
+#define E1000_SWFW_PHY2_SM 0x20
+#define E1000_SWFW_PHY3_SM 0x40
/* FACTPS Definitions */
/* Device Control */
@@ -466,6 +468,11 @@
#define E1000_TIMINCA_16NS_SHIFT 24
+#define E1000_MDICNFG_EXT_MDIO 0x80000000 /* MDI ext/int destination */
+#define E1000_MDICNFG_COM_MDIO 0x40000000 /* MDI shared w/ lan 0 */
+#define E1000_MDICNFG_PHY_MASK 0x03E00000
+#define E1000_MDICNFG_PHY_SHIFT 21
+
/* PCI Express Control */
#define E1000_GCR_CMPL_TMOUT_MASK 0x0000F000
#define E1000_GCR_CMPL_TMOUT_10ms 0x00001000
@@ -563,6 +570,10 @@
#define NVM_82580_LAN_FUNC_OFFSET(a) (a ? (0x40 + (0x40 * a)) : 0)
+/* Mask bits for fields in Word 0x24 of the NVM */
+#define NVM_WORD24_COM_MDIO 0x0008 /* MDIO interface shared */
+#define NVM_WORD24_EXT_MDIO 0x0004 /* MDIO accesses routed external */
+
/* Mask bits for fields in Word 0x0f of the NVM */
#define NVM_WORD0F_PAUSE_MASK 0x3000
#define NVM_WORD0F_ASM_DIR 0x2000
@@ -696,12 +707,17 @@
#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_5X 0x0800
/* MDI Control */
+#define E1000_MDIC_DATA_MASK 0x0000FFFF
+#define E1000_MDIC_REG_MASK 0x001F0000
#define E1000_MDIC_REG_SHIFT 16
+#define E1000_MDIC_PHY_MASK 0x03E00000
#define E1000_MDIC_PHY_SHIFT 21
#define E1000_MDIC_OP_WRITE 0x04000000
#define E1000_MDIC_OP_READ 0x08000000
#define E1000_MDIC_READY 0x10000000
+#define E1000_MDIC_INT_EN 0x20000000
#define E1000_MDIC_ERROR 0x40000000
+#define E1000_MDIC_DEST 0x80000000
/* SerDes Control */
#define E1000_GEN_CTL_READY 0x80000000
diff --git a/drivers/net/igb/igb_ethtool.c b/drivers/net/igb/igb_ethtool.c
index f2ebf927e4b..26bf6a13d1c 100644
--- a/drivers/net/igb/igb_ethtool.c
+++ b/drivers/net/igb/igb_ethtool.c
@@ -1823,12 +1823,10 @@ static void igb_diag_test(struct net_device *netdev,
dev_info(&adapter->pdev->dev, "online testing starting\n");
/* PHY is powered down when interface is down */
- if (!netif_carrier_ok(netdev)) {
+ if (if_running && igb_link_test(adapter, &data[4]))
+ eth_test->flags |= ETH_TEST_FL_FAILED;
+ else
data[4] = 0;
- } else {
- if (igb_link_test(adapter, &data[4]))
- eth_test->flags |= ETH_TEST_FL_FAILED;
- }
/* Online tests aren't run; pass by default */
data[0] = 0;
diff --git a/drivers/net/igb/igb_main.c b/drivers/net/igb/igb_main.c
index cea37e0837f..df5dcd23e4f 100644
--- a/drivers/net/igb/igb_main.c
+++ b/drivers/net/igb/igb_main.c
@@ -630,9 +630,6 @@ static void igb_cache_ring_register(struct igb_adapter *adapter)
for (; i < adapter->rss_queues; i++)
adapter->rx_ring[i]->reg_idx = rbase_offset +
Q_IDX_82576(i);
- for (; j < adapter->rss_queues; j++)
- adapter->tx_ring[j]->reg_idx = rbase_offset +
- Q_IDX_82576(j);
}
case e1000_82575:
case e1000_82580:
@@ -996,7 +993,10 @@ static void igb_set_interrupt_capability(struct igb_adapter *adapter)
/* Number of supported queues. */
adapter->num_rx_queues = adapter->rss_queues;
- adapter->num_tx_queues = adapter->rss_queues;
+ if (adapter->vfs_allocated_count)
+ adapter->num_tx_queues = 1;
+ else
+ adapter->num_tx_queues = adapter->rss_queues;
/* start with one vector for every rx queue */
numvecs = adapter->num_rx_queues;
@@ -1290,7 +1290,13 @@ static void igb_irq_disable(struct igb_adapter *adapter)
wr32(E1000_IAM, 0);
wr32(E1000_IMC, ~0);
wrfl();
- synchronize_irq(adapter->pdev->irq);
+ if (adapter->msix_entries) {
+ int i;
+ for (i = 0; i < adapter->num_q_vectors; i++)
+ synchronize_irq(adapter->msix_entries[i].vector);
+ } else {
+ synchronize_irq(adapter->pdev->irq);
+ }
}
/**
@@ -2100,9 +2106,6 @@ static void __devinit igb_probe_vfs(struct igb_adapter * adapter)
#ifdef CONFIG_PCI_IOV
struct pci_dev *pdev = adapter->pdev;
- if (adapter->vfs_allocated_count > 7)
- adapter->vfs_allocated_count = 7;
-
if (adapter->vfs_allocated_count) {
adapter->vf_data = kcalloc(adapter->vfs_allocated_count,
sizeof(struct vf_data_storage),
@@ -2267,7 +2270,7 @@ static int __devinit igb_sw_init(struct igb_adapter *adapter)
#ifdef CONFIG_PCI_IOV
if (hw->mac.type == e1000_82576)
- adapter->vfs_allocated_count = max_vfs;
+ adapter->vfs_allocated_count = (max_vfs > 7) ? 7 : max_vfs;
#endif /* CONFIG_PCI_IOV */
adapter->rss_queues = min_t(u32, IGB_MAX_RX_QUEUES, num_online_cpus());
@@ -2729,14 +2732,16 @@ static void igb_setup_mrqc(struct igb_adapter *adapter)
}
igb_vmm_control(adapter);
- mrqc |= (E1000_MRQC_RSS_FIELD_IPV4 |
- E1000_MRQC_RSS_FIELD_IPV4_TCP);
- mrqc |= (E1000_MRQC_RSS_FIELD_IPV6 |
- E1000_MRQC_RSS_FIELD_IPV6_TCP);
- mrqc |= (E1000_MRQC_RSS_FIELD_IPV4_UDP |
- E1000_MRQC_RSS_FIELD_IPV6_UDP);
- mrqc |= (E1000_MRQC_RSS_FIELD_IPV6_UDP_EX |
- E1000_MRQC_RSS_FIELD_IPV6_TCP_EX);
+ /*
+ * Generate RSS hash based on TCP port numbers and/or
+ * IPv4/v6 src and dst addresses since UDP cannot be
+ * hashed reliably due to IP fragmentation
+ */
+ mrqc |= E1000_MRQC_RSS_FIELD_IPV4 |
+ E1000_MRQC_RSS_FIELD_IPV4_TCP |
+ E1000_MRQC_RSS_FIELD_IPV6 |
+ E1000_MRQC_RSS_FIELD_IPV6_TCP |
+ E1000_MRQC_RSS_FIELD_IPV6_TCP_EX;
wr32(E1000_MRQC, mrqc);
}
@@ -4986,6 +4991,10 @@ static void igb_vf_reset_msg(struct igb_adapter *adapter, u32 vf)
static int igb_set_vf_mac_addr(struct igb_adapter *adapter, u32 *msg, int vf)
{
+ /*
+ * The VF MAC Address is stored in a packed array of bytes
+ * starting at the second 32 bit word of the msg array
+ */
unsigned char *addr = (char *)&msg[1];
int err = -1;
diff --git a/drivers/net/igbvf/netdev.c b/drivers/net/igbvf/netdev.c
index 5e2b2a8c56c..ec808fa8dc2 100644
--- a/drivers/net/igbvf/netdev.c
+++ b/drivers/net/igbvf/netdev.c
@@ -48,7 +48,7 @@
#define DRV_VERSION "1.0.0-k0"
char igbvf_driver_name[] = "igbvf";
const char igbvf_driver_version[] = DRV_VERSION;
-struct pm_qos_request_list *igbvf_driver_pm_qos_req;
+static struct pm_qos_request_list igbvf_driver_pm_qos_req;
static const char igbvf_driver_string[] =
"Intel(R) Virtual Function Network Driver";
static const char igbvf_copyright[] = "Copyright (c) 2009 Intel Corporation.";
@@ -2751,7 +2751,7 @@ static int __devinit igbvf_probe(struct pci_dev *pdev,
dev_info(&pdev->dev,
"PF still in reset state, assigning new address."
" Is the PF interface up?\n");
- random_ether_addr(hw->mac.addr);
+ dev_hw_addr_random(adapter->netdev, hw->mac.addr);
} else {
err = hw->mac.ops.read_mac_addr(hw);
if (err) {
@@ -2902,8 +2902,8 @@ static int __init igbvf_init_module(void)
printk(KERN_INFO "%s\n", igbvf_copyright);
ret = pci_register_driver(&igbvf_driver);
- igbvf_driver_pm_qos_req = pm_qos_add_request(PM_QOS_CPU_DMA_LATENCY,
- PM_QOS_DEFAULT_VALUE);
+ pm_qos_add_request(&igbvf_driver_pm_qos_req, PM_QOS_CPU_DMA_LATENCY,
+ PM_QOS_DEFAULT_VALUE);
return ret;
}
@@ -2918,8 +2918,7 @@ module_init(igbvf_init_module);
static void __exit igbvf_exit_module(void)
{
pci_unregister_driver(&igbvf_driver);
- pm_qos_remove_request(igbvf_driver_pm_qos_req);
- igbvf_driver_pm_qos_req = NULL;
+ pm_qos_remove_request(&igbvf_driver_pm_qos_req);
}
module_exit(igbvf_exit_module);
diff --git a/drivers/net/ioc3-eth.c b/drivers/net/ioc3-eth.c
index e3b5e949060..0b3f6df5cff 100644
--- a/drivers/net/ioc3-eth.c
+++ b/drivers/net/ioc3-eth.c
@@ -82,7 +82,6 @@ struct ioc3_private {
struct ioc3_etxd *txr;
struct sk_buff *rx_skbs[512];
struct sk_buff *tx_skbs[128];
- struct net_device_stats stats;
int rx_ci; /* RX consumer index */
int rx_pi; /* RX producer index */
int tx_ci; /* TX consumer index */
@@ -504,8 +503,8 @@ static struct net_device_stats *ioc3_get_stats(struct net_device *dev)
struct ioc3_private *ip = netdev_priv(dev);
struct ioc3 *ioc3 = ip->regs;
- ip->stats.collisions += (ioc3_r_etcdc() & ETCDC_COLLCNT_MASK);
- return &ip->stats;
+ dev->stats.collisions += (ioc3_r_etcdc() & ETCDC_COLLCNT_MASK);
+ return &dev->stats;
}
static void ioc3_tcpudp_checksum(struct sk_buff *skb, uint32_t hwsum, int len)
@@ -576,8 +575,9 @@ static void ioc3_tcpudp_checksum(struct sk_buff *skb, uint32_t hwsum, int len)
skb->ip_summed = CHECKSUM_UNNECESSARY;
}
-static inline void ioc3_rx(struct ioc3_private *ip)
+static inline void ioc3_rx(struct net_device *dev)
{
+ struct ioc3_private *ip = netdev_priv(dev);
struct sk_buff *skb, *new_skb;
struct ioc3 *ioc3 = ip->regs;
int rx_entry, n_entry, len;
@@ -598,13 +598,13 @@ static inline void ioc3_rx(struct ioc3_private *ip)
if (err & ERXBUF_GOODPKT) {
len = ((w0 >> ERXBUF_BYTECNT_SHIFT) & 0x7ff) - 4;
skb_trim(skb, len);
- skb->protocol = eth_type_trans(skb, priv_netdev(ip));
+ skb->protocol = eth_type_trans(skb, dev);
new_skb = ioc3_alloc_skb(RX_BUF_ALLOC_SIZE, GFP_ATOMIC);
if (!new_skb) {
/* Ouch, drop packet and just recycle packet
to keep the ring filled. */
- ip->stats.rx_dropped++;
+ dev->stats.rx_dropped++;
new_skb = skb;
goto next;
}
@@ -622,19 +622,19 @@ static inline void ioc3_rx(struct ioc3_private *ip)
rxb = (struct ioc3_erxbuf *) new_skb->data;
skb_reserve(new_skb, RX_OFFSET);
- ip->stats.rx_packets++; /* Statistics */
- ip->stats.rx_bytes += len;
+ dev->stats.rx_packets++; /* Statistics */
+ dev->stats.rx_bytes += len;
} else {
- /* The frame is invalid and the skb never
- reached the network layer so we can just
- recycle it. */
- new_skb = skb;
- ip->stats.rx_errors++;
+ /* The frame is invalid and the skb never
+ reached the network layer so we can just
+ recycle it. */
+ new_skb = skb;
+ dev->stats.rx_errors++;
}
if (err & ERXBUF_CRCERR) /* Statistics */
- ip->stats.rx_crc_errors++;
+ dev->stats.rx_crc_errors++;
if (err & ERXBUF_FRAMERR)
- ip->stats.rx_frame_errors++;
+ dev->stats.rx_frame_errors++;
next:
ip->rx_skbs[n_entry] = new_skb;
rxr[n_entry] = cpu_to_be64(ioc3_map(rxb, 1));
@@ -652,8 +652,9 @@ next:
ip->rx_ci = rx_entry;
}
-static inline void ioc3_tx(struct ioc3_private *ip)
+static inline void ioc3_tx(struct net_device *dev)
{
+ struct ioc3_private *ip = netdev_priv(dev);
unsigned long packets, bytes;
struct ioc3 *ioc3 = ip->regs;
int tx_entry, o_entry;
@@ -681,12 +682,12 @@ static inline void ioc3_tx(struct ioc3_private *ip)
tx_entry = (etcir >> 7) & 127;
}
- ip->stats.tx_packets += packets;
- ip->stats.tx_bytes += bytes;
+ dev->stats.tx_packets += packets;
+ dev->stats.tx_bytes += bytes;
ip->txqlen -= packets;
if (ip->txqlen < 128)
- netif_wake_queue(priv_netdev(ip));
+ netif_wake_queue(dev);
ip->tx_ci = o_entry;
spin_unlock(&ip->ioc3_lock);
@@ -699,9 +700,9 @@ static inline void ioc3_tx(struct ioc3_private *ip)
* with such error interrupts if something really goes wrong, so we might
* also consider to take the interface down.
*/
-static void ioc3_error(struct ioc3_private *ip, u32 eisr)
+static void ioc3_error(struct net_device *dev, u32 eisr)
{
- struct net_device *dev = priv_netdev(ip);
+ struct ioc3_private *ip = netdev_priv(dev);
unsigned char *iface = dev->name;
spin_lock(&ip->ioc3_lock);
@@ -747,11 +748,11 @@ static irqreturn_t ioc3_interrupt(int irq, void *_dev)
if (eisr & (EISR_RXOFLO | EISR_RXBUFOFLO | EISR_RXMEMERR |
EISR_RXPARERR | EISR_TXBUFUFLO | EISR_TXMEMERR))
- ioc3_error(ip, eisr);
+ ioc3_error(dev, eisr);
if (eisr & EISR_RXTIMERINT)
- ioc3_rx(ip);
+ ioc3_rx(dev);
if (eisr & EISR_TXEXPLICIT)
- ioc3_tx(ip);
+ ioc3_tx(dev);
return IRQ_HANDLED;
}
diff --git a/drivers/net/irda/donauboe.h b/drivers/net/irda/donauboe.h
index 0dbd1932b72..36c3060411d 100644
--- a/drivers/net/irda/donauboe.h
+++ b/drivers/net/irda/donauboe.h
@@ -273,7 +273,7 @@ struct OboeSlot
__u8 control; /*Slot control/status see below */
__u32 address; /*Slot buffer address */
}
-__attribute__ ((packed));
+__packed;
#define OBOE_NTASKS OBOE_TXRING_OFFSET_IN_SLOTS
diff --git a/drivers/net/irda/irda-usb.h b/drivers/net/irda/irda-usb.h
index ac0443d52e5..58ddb521491 100644
--- a/drivers/net/irda/irda-usb.h
+++ b/drivers/net/irda/irda-usb.h
@@ -125,7 +125,7 @@ struct irda_class_desc {
__u8 bmAdditionalBOFs;
__u8 bIrdaRateSniff;
__u8 bMaxUnicastList;
-} __attribute__ ((packed));
+} __packed;
/* class specific interface request to get the IrDA-USB class descriptor
* (6.2.5, USB-IrDA class spec 1.0) */
diff --git a/drivers/net/irda/ks959-sir.c b/drivers/net/irda/ks959-sir.c
index b54d3b48045..1046014dd6c 100644
--- a/drivers/net/irda/ks959-sir.c
+++ b/drivers/net/irda/ks959-sir.c
@@ -154,7 +154,7 @@ struct ks959_speedparams {
__le32 baudrate; /* baud rate, little endian */
__u8 flags;
__u8 reserved[3];
-} __attribute__ ((packed));
+} __packed;
#define KS_DATA_5_BITS 0x00
#define KS_DATA_6_BITS 0x01
diff --git a/drivers/net/irda/ksdazzle-sir.c b/drivers/net/irda/ksdazzle-sir.c
index 8d713ebac15..9cc142fcc71 100644
--- a/drivers/net/irda/ksdazzle-sir.c
+++ b/drivers/net/irda/ksdazzle-sir.c
@@ -117,7 +117,7 @@ struct ksdazzle_speedparams {
__le32 baudrate; /* baud rate, little endian */
__u8 flags;
__u8 reserved[3];
-} __attribute__ ((packed));
+} __packed;
#define KS_DATA_5_BITS 0x00
#define KS_DATA_6_BITS 0x01
diff --git a/drivers/net/irda/sh_irda.c b/drivers/net/irda/sh_irda.c
index 9a828b06a57..edd5666f0ff 100644
--- a/drivers/net/irda/sh_irda.c
+++ b/drivers/net/irda/sh_irda.c
@@ -749,7 +749,7 @@ static int __devinit sh_irda_probe(struct platform_device *pdev)
struct sh_irda_self *self;
struct resource *res;
char clk_name[8];
- unsigned int irq;
+ int irq;
int err = -ENOMEM;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
diff --git a/drivers/net/irda/sh_sir.c b/drivers/net/irda/sh_sir.c
index 5c5f99d5034..00b38bccd6d 100644
--- a/drivers/net/irda/sh_sir.c
+++ b/drivers/net/irda/sh_sir.c
@@ -709,7 +709,7 @@ static int __devinit sh_sir_probe(struct platform_device *pdev)
struct sh_sir_self *self;
struct resource *res;
char clk_name[8];
- unsigned int irq;
+ int irq;
int err = -ENOMEM;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
diff --git a/drivers/net/irda/smsc-ircc2.c b/drivers/net/irda/smsc-ircc2.c
index d67e48418e5..850ca1c5ee1 100644
--- a/drivers/net/irda/smsc-ircc2.c
+++ b/drivers/net/irda/smsc-ircc2.c
@@ -2848,9 +2848,7 @@ static int __init smsc_ircc_preconfigure_subsystems(unsigned short ircc_cfg,
unsigned short ss_device = 0x0000;
int ret = 0;
- dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev);
-
- while (dev != NULL) {
+ for_each_pci_dev(dev) {
struct smsc_ircc_subsystem_configuration *conf;
/*
@@ -2899,7 +2897,6 @@ static int __init smsc_ircc_preconfigure_subsystems(unsigned short ircc_cfg,
ret = -ENODEV;
}
}
- dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev);
}
return ret;
diff --git a/drivers/net/irda/vlsi_ir.h b/drivers/net/irda/vlsi_ir.h
index 3050d1a0ccc..3f24a1f3302 100644
--- a/drivers/net/irda/vlsi_ir.h
+++ b/drivers/net/irda/vlsi_ir.h
@@ -544,9 +544,9 @@ struct ring_descr_hw {
struct {
u8 addr_res[3];
volatile u8 status; /* descriptor status */
- } __attribute__((packed)) rd_s;
- } __attribute((packed)) rd_u;
-} __attribute__ ((packed));
+ } __packed rd_s;
+ } __packed rd_u;
+} __packed;
#define rd_addr rd_u.addr
#define rd_status rd_u.rd_s.status
diff --git a/drivers/net/ixgbe/ixgbe.h b/drivers/net/ixgbe/ixgbe.h
index ffae480587a..9e15eb93860 100644
--- a/drivers/net/ixgbe/ixgbe.h
+++ b/drivers/net/ixgbe/ixgbe.h
@@ -44,11 +44,9 @@
#include <linux/dca.h>
#endif
-#define PFX "ixgbe: "
-#define DPRINTK(nlevel, klevel, fmt, args...) \
- ((void)((NETIF_MSG_##nlevel & adapter->msg_enable) && \
- printk(KERN_##klevel PFX "%s: %s: " fmt, adapter->netdev->name, \
- __func__ , ## args)))
+/* common prefix used by pr_<> macros */
+#undef pr_fmt
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
/* TX/RX descriptor defines */
#define IXGBE_DEFAULT_TXD 512
@@ -112,7 +110,6 @@ struct vf_data_storage {
u16 vlans_enabled;
bool clear_to_send;
bool pf_set_mac;
- int rar;
u16 pf_vlan; /* When set, guest VLAN config not allowed. */
u16 pf_qos;
};
diff --git a/drivers/net/ixgbe/ixgbe_82599.c b/drivers/net/ixgbe/ixgbe_82599.c
index a4e2901f2f0..3e06a61da92 100644
--- a/drivers/net/ixgbe/ixgbe_82599.c
+++ b/drivers/net/ixgbe/ixgbe_82599.c
@@ -206,6 +206,14 @@ static s32 ixgbe_get_link_capabilities_82599(struct ixgbe_hw *hw,
s32 status = 0;
u32 autoc = 0;
+ /* Determine 1G link capabilities off of SFP+ type */
+ if (hw->phy.sfp_type == ixgbe_sfp_type_1g_cu_core0 ||
+ hw->phy.sfp_type == ixgbe_sfp_type_1g_cu_core1) {
+ *speed = IXGBE_LINK_SPEED_1GB_FULL;
+ *negotiation = true;
+ goto out;
+ }
+
/*
* Determine link capabilities based on the stored value of AUTOC,
* which represents EEPROM defaults. If AUTOC value has not been
@@ -707,9 +715,8 @@ static s32 ixgbe_setup_mac_link_smartspeed(struct ixgbe_hw *hw,
out:
if (link_up && (link_speed == IXGBE_LINK_SPEED_1GB_FULL))
- netif_info(adapter, hw, adapter->netdev, "Smartspeed has"
- " downgraded the link speed from the maximum"
- " advertised\n");
+ e_info(hw, "Smartspeed has downgraded the link speed from "
+ "the maximum advertised\n");
return status;
}
@@ -2088,6 +2095,7 @@ static u32 ixgbe_get_supported_physical_layer_82599(struct ixgbe_hw *hw)
u32 pma_pmd_1g = autoc & IXGBE_AUTOC_1G_PMA_PMD_MASK;
u16 ext_ability = 0;
u8 comp_codes_10g = 0;
+ u8 comp_codes_1g = 0;
hw->phy.ops.identify(hw);
@@ -2168,11 +2176,15 @@ sfp_check:
case ixgbe_phy_sfp_intel:
case ixgbe_phy_sfp_unknown:
hw->phy.ops.read_i2c_eeprom(hw,
+ IXGBE_SFF_1GBE_COMP_CODES, &comp_codes_1g);
+ hw->phy.ops.read_i2c_eeprom(hw,
IXGBE_SFF_10GBE_COMP_CODES, &comp_codes_10g);
if (comp_codes_10g & IXGBE_SFF_10GBASESR_CAPABLE)
physical_layer = IXGBE_PHYSICAL_LAYER_10GBASE_SR;
else if (comp_codes_10g & IXGBE_SFF_10GBASELR_CAPABLE)
physical_layer = IXGBE_PHYSICAL_LAYER_10GBASE_LR;
+ else if (comp_codes_1g & IXGBE_SFF_1GBASET_CAPABLE)
+ physical_layer = IXGBE_PHYSICAL_LAYER_1000BASE_T;
break;
default:
break;
diff --git a/drivers/net/ixgbe/ixgbe_common.h b/drivers/net/ixgbe/ixgbe_common.h
index 3080afb12bd..5cf15aa11ca 100644
--- a/drivers/net/ixgbe/ixgbe_common.h
+++ b/drivers/net/ixgbe/ixgbe_common.h
@@ -105,12 +105,23 @@ s32 ixgbe_blink_led_stop_generic(struct ixgbe_hw *hw, u32 index);
#define IXGBE_WRITE_FLUSH(a) IXGBE_READ_REG(a, IXGBE_STATUS)
-#ifdef DEBUG
-extern char *ixgbe_get_hw_dev_name(struct ixgbe_hw *hw);
+extern struct net_device *ixgbe_get_hw_dev(struct ixgbe_hw *hw);
#define hw_dbg(hw, format, arg...) \
- printk(KERN_DEBUG "%s: " format, ixgbe_get_hw_dev_name(hw), ##arg)
-#else
-#define hw_dbg(hw, format, arg...) do {} while (0)
-#endif
-
+ netdev_dbg(ixgbe_get_hw_dev(hw), format, ##arg)
+#define e_dev_info(format, arg...) \
+ dev_info(&adapter->pdev->dev, format, ## arg)
+#define e_dev_warn(format, arg...) \
+ dev_warn(&adapter->pdev->dev, format, ## arg)
+#define e_dev_err(format, arg...) \
+ dev_err(&adapter->pdev->dev, format, ## arg)
+#define e_dev_notice(format, arg...) \
+ dev_notice(&adapter->pdev->dev, format, ## arg)
+#define e_info(msglvl, format, arg...) \
+ netif_info(adapter, msglvl, adapter->netdev, format, ## arg)
+#define e_err(msglvl, format, arg...) \
+ netif_err(adapter, msglvl, adapter->netdev, format, ## arg)
+#define e_warn(msglvl, format, arg...) \
+ netif_warn(adapter, msglvl, adapter->netdev, format, ## arg)
+#define e_crit(msglvl, format, arg...) \
+ netif_crit(adapter, msglvl, adapter->netdev, format, ## arg)
#endif /* IXGBE_COMMON */
diff --git a/drivers/net/ixgbe/ixgbe_dcb_82599.c b/drivers/net/ixgbe/ixgbe_dcb_82599.c
index 4f7a26ab411..25b02fb425a 100644
--- a/drivers/net/ixgbe/ixgbe_dcb_82599.c
+++ b/drivers/net/ixgbe/ixgbe_dcb_82599.c
@@ -346,7 +346,7 @@ s32 ixgbe_dcb_config_pfc_82599(struct ixgbe_hw *hw,
*/
reg = IXGBE_READ_REG(hw, IXGBE_MFLCN);
reg &= ~IXGBE_MFLCN_RFCE;
- reg |= IXGBE_MFLCN_RPFCE;
+ reg |= IXGBE_MFLCN_RPFCE | IXGBE_MFLCN_DPF;
IXGBE_WRITE_REG(hw, IXGBE_MFLCN, reg);
out:
return 0;
diff --git a/drivers/net/ixgbe/ixgbe_dcb_nl.c b/drivers/net/ixgbe/ixgbe_dcb_nl.c
index 71da325dfa8..b53b465e24a 100644
--- a/drivers/net/ixgbe/ixgbe_dcb_nl.c
+++ b/drivers/net/ixgbe/ixgbe_dcb_nl.c
@@ -121,7 +121,7 @@ static u8 ixgbe_dcbnl_set_state(struct net_device *netdev, u8 state)
goto out;
if (!(adapter->flags & IXGBE_FLAG_MSIX_ENABLED)) {
- DPRINTK(DRV, ERR, "Enable failed, needs MSI-X\n");
+ e_err(drv, "Enable failed, needs MSI-X\n");
err = 1;
goto out;
}
diff --git a/drivers/net/ixgbe/ixgbe_ethtool.c b/drivers/net/ixgbe/ixgbe_ethtool.c
index 3a93a81872b..dcebc82c6f4 100644
--- a/drivers/net/ixgbe/ixgbe_ethtool.c
+++ b/drivers/net/ixgbe/ixgbe_ethtool.c
@@ -54,14 +54,14 @@ struct ixgbe_stats {
sizeof(((struct ixgbe_adapter *)0)->m), \
offsetof(struct ixgbe_adapter, m)
#define IXGBE_NETDEV_STAT(m) NETDEV_STATS, \
- sizeof(((struct net_device *)0)->m), \
- offsetof(struct net_device, m)
+ sizeof(((struct rtnl_link_stats64 *)0)->m), \
+ offsetof(struct rtnl_link_stats64, m)
static struct ixgbe_stats ixgbe_gstrings_stats[] = {
- {"rx_packets", IXGBE_NETDEV_STAT(stats.rx_packets)},
- {"tx_packets", IXGBE_NETDEV_STAT(stats.tx_packets)},
- {"rx_bytes", IXGBE_NETDEV_STAT(stats.rx_bytes)},
- {"tx_bytes", IXGBE_NETDEV_STAT(stats.tx_bytes)},
+ {"rx_packets", IXGBE_NETDEV_STAT(rx_packets)},
+ {"tx_packets", IXGBE_NETDEV_STAT(tx_packets)},
+ {"rx_bytes", IXGBE_NETDEV_STAT(rx_bytes)},
+ {"tx_bytes", IXGBE_NETDEV_STAT(tx_bytes)},
{"rx_pkts_nic", IXGBE_STAT(stats.gprc)},
{"tx_pkts_nic", IXGBE_STAT(stats.gptc)},
{"rx_bytes_nic", IXGBE_STAT(stats.gorc)},
@@ -69,27 +69,27 @@ static struct ixgbe_stats ixgbe_gstrings_stats[] = {
{"lsc_int", IXGBE_STAT(lsc_int)},
{"tx_busy", IXGBE_STAT(tx_busy)},
{"non_eop_descs", IXGBE_STAT(non_eop_descs)},
- {"rx_errors", IXGBE_NETDEV_STAT(stats.rx_errors)},
- {"tx_errors", IXGBE_NETDEV_STAT(stats.tx_errors)},
- {"rx_dropped", IXGBE_NETDEV_STAT(stats.rx_dropped)},
- {"tx_dropped", IXGBE_NETDEV_STAT(stats.tx_dropped)},
- {"multicast", IXGBE_NETDEV_STAT(stats.multicast)},
+ {"rx_errors", IXGBE_NETDEV_STAT(rx_errors)},
+ {"tx_errors", IXGBE_NETDEV_STAT(tx_errors)},
+ {"rx_dropped", IXGBE_NETDEV_STAT(rx_dropped)},
+ {"tx_dropped", IXGBE_NETDEV_STAT(tx_dropped)},
+ {"multicast", IXGBE_NETDEV_STAT(multicast)},
{"broadcast", IXGBE_STAT(stats.bprc)},
{"rx_no_buffer_count", IXGBE_STAT(stats.rnbc[0]) },
- {"collisions", IXGBE_NETDEV_STAT(stats.collisions)},
- {"rx_over_errors", IXGBE_NETDEV_STAT(stats.rx_over_errors)},
- {"rx_crc_errors", IXGBE_NETDEV_STAT(stats.rx_crc_errors)},
- {"rx_frame_errors", IXGBE_NETDEV_STAT(stats.rx_frame_errors)},
+ {"collisions", IXGBE_NETDEV_STAT(collisions)},
+ {"rx_over_errors", IXGBE_NETDEV_STAT(rx_over_errors)},
+ {"rx_crc_errors", IXGBE_NETDEV_STAT(rx_crc_errors)},
+ {"rx_frame_errors", IXGBE_NETDEV_STAT(rx_frame_errors)},
{"hw_rsc_aggregated", IXGBE_STAT(rsc_total_count)},
{"hw_rsc_flushed", IXGBE_STAT(rsc_total_flush)},
{"fdir_match", IXGBE_STAT(stats.fdirmatch)},
{"fdir_miss", IXGBE_STAT(stats.fdirmiss)},
- {"rx_fifo_errors", IXGBE_NETDEV_STAT(stats.rx_fifo_errors)},
- {"rx_missed_errors", IXGBE_NETDEV_STAT(stats.rx_missed_errors)},
- {"tx_aborted_errors", IXGBE_NETDEV_STAT(stats.tx_aborted_errors)},
- {"tx_carrier_errors", IXGBE_NETDEV_STAT(stats.tx_carrier_errors)},
- {"tx_fifo_errors", IXGBE_NETDEV_STAT(stats.tx_fifo_errors)},
- {"tx_heartbeat_errors", IXGBE_NETDEV_STAT(stats.tx_heartbeat_errors)},
+ {"rx_fifo_errors", IXGBE_NETDEV_STAT(rx_fifo_errors)},
+ {"rx_missed_errors", IXGBE_NETDEV_STAT(rx_missed_errors)},
+ {"tx_aborted_errors", IXGBE_NETDEV_STAT(tx_aborted_errors)},
+ {"tx_carrier_errors", IXGBE_NETDEV_STAT(tx_carrier_errors)},
+ {"tx_fifo_errors", IXGBE_NETDEV_STAT(tx_fifo_errors)},
+ {"tx_heartbeat_errors", IXGBE_NETDEV_STAT(tx_heartbeat_errors)},
{"tx_timeout_count", IXGBE_STAT(tx_timeout_count)},
{"tx_restart_queue", IXGBE_STAT(restart_queue)},
{"rx_long_length_errors", IXGBE_STAT(stats.roc)},
@@ -234,6 +234,13 @@ static int ixgbe_get_settings(struct net_device *netdev,
case ixgbe_sfp_type_not_present:
ecmd->port = PORT_NONE;
break;
+ case ixgbe_sfp_type_1g_cu_core0:
+ case ixgbe_sfp_type_1g_cu_core1:
+ ecmd->port = PORT_TP;
+ ecmd->supported = SUPPORTED_TP;
+ ecmd->advertising = (ADVERTISED_1000baseT_Full |
+ ADVERTISED_TP);
+ break;
case ixgbe_sfp_type_unknown:
default:
ecmd->port = PORT_OTHER;
@@ -294,8 +301,7 @@ static int ixgbe_set_settings(struct net_device *netdev,
hw->mac.autotry_restart = true;
err = hw->mac.ops.setup_link(hw, advertised, true, true);
if (err) {
- DPRINTK(PROBE, INFO,
- "setup link failed with code %d\n", err);
+ e_info(probe, "setup link failed with code %d\n", err);
hw->mac.ops.setup_link(hw, old, true, true);
}
} else {
@@ -992,16 +998,18 @@ static void ixgbe_get_ethtool_stats(struct net_device *netdev,
struct ixgbe_adapter *adapter = netdev_priv(netdev);
u64 *queue_stat;
int stat_count = sizeof(struct ixgbe_queue_stats) / sizeof(u64);
+ struct rtnl_link_stats64 temp;
+ const struct rtnl_link_stats64 *net_stats;
int j, k;
int i;
char *p = NULL;
ixgbe_update_stats(adapter);
- dev_get_stats(netdev);
+ net_stats = dev_get_stats(netdev, &temp);
for (i = 0; i < IXGBE_GLOBAL_STATS_LEN; i++) {
switch (ixgbe_gstrings_stats[i].type) {
case NETDEV_STATS:
- p = (char *) netdev +
+ p = (char *) net_stats +
ixgbe_gstrings_stats[i].stat_offset;
break;
case IXGBE_STATS:
@@ -1188,9 +1196,9 @@ static struct ixgbe_reg_test reg_test_82598[] = {
writel((_test[pat] & W), (adapter->hw.hw_addr + R)); \
val = readl(adapter->hw.hw_addr + R); \
if (val != (_test[pat] & W & M)) { \
- DPRINTK(DRV, ERR, "pattern test reg %04X failed: got "\
- "0x%08X expected 0x%08X\n", \
- R, val, (_test[pat] & W & M)); \
+ e_err(drv, "pattern test reg %04X failed: got " \
+ "0x%08X expected 0x%08X\n", \
+ R, val, (_test[pat] & W & M)); \
*data = R; \
writel(before, adapter->hw.hw_addr + R); \
return 1; \
@@ -1206,8 +1214,8 @@ static struct ixgbe_reg_test reg_test_82598[] = {
writel((W & M), (adapter->hw.hw_addr + R)); \
val = readl(adapter->hw.hw_addr + R); \
if ((W & M) != (val & M)) { \
- DPRINTK(DRV, ERR, "set/check reg %04X test failed: got 0x%08X "\
- "expected 0x%08X\n", R, (val & M), (W & M)); \
+ e_err(drv, "set/check reg %04X test failed: got 0x%08X " \
+ "expected 0x%08X\n", R, (val & M), (W & M)); \
*data = R; \
writel(before, (adapter->hw.hw_addr + R)); \
return 1; \
@@ -1240,8 +1248,8 @@ static int ixgbe_reg_test(struct ixgbe_adapter *adapter, u64 *data)
IXGBE_WRITE_REG(&adapter->hw, IXGBE_STATUS, toggle);
after = IXGBE_READ_REG(&adapter->hw, IXGBE_STATUS) & toggle;
if (value != after) {
- DPRINTK(DRV, ERR, "failed STATUS register test got: "
- "0x%08X expected: 0x%08X\n", after, value);
+ e_err(drv, "failed STATUS register test got: 0x%08X "
+ "expected: 0x%08X\n", after, value);
*data = 1;
return 1;
}
@@ -1341,8 +1349,8 @@ static int ixgbe_intr_test(struct ixgbe_adapter *adapter, u64 *data)
*data = 1;
return -1;
}
- DPRINTK(HW, INFO, "testing %s interrupt\n",
- (shared_int ? "shared" : "unshared"));
+ e_info(hw, "testing %s interrupt\n", shared_int ?
+ "shared" : "unshared");
/* Disable all the interrupts */
IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC, 0xFFFFFFFF);
@@ -1847,7 +1855,7 @@ static void ixgbe_diag_test(struct net_device *netdev,
if (eth_test->flags == ETH_TEST_FL_OFFLINE) {
/* Offline tests */
- DPRINTK(HW, INFO, "offline testing starting\n");
+ e_info(hw, "offline testing starting\n");
/* Link test performed before hardware reset so autoneg doesn't
* interfere with test result */
@@ -1880,17 +1888,17 @@ static void ixgbe_diag_test(struct net_device *netdev,
else
ixgbe_reset(adapter);
- DPRINTK(HW, INFO, "register testing starting\n");
+ e_info(hw, "register testing starting\n");
if (ixgbe_reg_test(adapter, &data[0]))
eth_test->flags |= ETH_TEST_FL_FAILED;
ixgbe_reset(adapter);
- DPRINTK(HW, INFO, "eeprom testing starting\n");
+ e_info(hw, "eeprom testing starting\n");
if (ixgbe_eeprom_test(adapter, &data[1]))
eth_test->flags |= ETH_TEST_FL_FAILED;
ixgbe_reset(adapter);
- DPRINTK(HW, INFO, "interrupt testing starting\n");
+ e_info(hw, "interrupt testing starting\n");
if (ixgbe_intr_test(adapter, &data[2]))
eth_test->flags |= ETH_TEST_FL_FAILED;
@@ -1898,14 +1906,14 @@ static void ixgbe_diag_test(struct net_device *netdev,
* loopback diagnostic. */
if (adapter->flags & (IXGBE_FLAG_SRIOV_ENABLED |
IXGBE_FLAG_VMDQ_ENABLED)) {
- DPRINTK(HW, INFO, "Skip MAC loopback diagnostic in VT "
- "mode\n");
+ e_info(hw, "Skip MAC loopback diagnostic in VT "
+ "mode\n");
data[3] = 0;
goto skip_loopback;
}
ixgbe_reset(adapter);
- DPRINTK(HW, INFO, "loopback testing starting\n");
+ e_info(hw, "loopback testing starting\n");
if (ixgbe_loopback_test(adapter, &data[3]))
eth_test->flags |= ETH_TEST_FL_FAILED;
@@ -1916,7 +1924,7 @@ skip_loopback:
if (if_running)
dev_open(netdev);
} else {
- DPRINTK(HW, INFO, "online testing starting\n");
+ e_info(hw, "online testing starting\n");
/* Online tests */
if (ixgbe_link_test(adapter, &data[4]))
eth_test->flags |= ETH_TEST_FL_FAILED;
@@ -2134,8 +2142,8 @@ static int ixgbe_set_coalesce(struct net_device *netdev,
adapter->flags2 &= ~IXGBE_FLAG2_RSC_ENABLED;
if (netdev->features & NETIF_F_LRO) {
netdev->features &= ~NETIF_F_LRO;
- DPRINTK(PROBE, INFO, "rx-usecs set to 0, "
- "disabling LRO/RSC\n");
+ e_info(probe, "rx-usecs set to 0, "
+ "disabling RSC\n");
}
need_reset = true;
}
@@ -2208,8 +2216,11 @@ static int ixgbe_set_flags(struct net_device *netdev, u32 data)
{
struct ixgbe_adapter *adapter = netdev_priv(netdev);
bool need_reset = false;
+ int rc;
- ethtool_op_set_flags(netdev, data);
+ rc = ethtool_op_set_flags(netdev, data, ETH_FLAG_LRO | ETH_FLAG_NTUPLE);
+ if (rc)
+ return rc;
/* if state changes we need to update adapter->flags and reset */
if (adapter->flags2 & IXGBE_FLAG2_RSC_CAPABLE) {
@@ -2230,10 +2241,10 @@ static int ixgbe_set_flags(struct net_device *netdev, u32 data)
break;
}
} else if (!adapter->rx_itr_setting) {
- netdev->features &= ~ETH_FLAG_LRO;
+ netdev->features &= ~NETIF_F_LRO;
if (data & ETH_FLAG_LRO)
- DPRINTK(PROBE, INFO, "rx-usecs set to 0, "
- "LRO/RSC cannot be enabled.\n");
+ e_info(probe, "rx-usecs set to 0, "
+ "LRO/RSC cannot be enabled.\n");
}
}
diff --git a/drivers/net/ixgbe/ixgbe_fcoe.c b/drivers/net/ixgbe/ixgbe_fcoe.c
index 45182ab41d6..072327c5e41 100644
--- a/drivers/net/ixgbe/ixgbe_fcoe.c
+++ b/drivers/net/ixgbe/ixgbe_fcoe.c
@@ -25,7 +25,6 @@
*******************************************************************************/
-
#include "ixgbe.h"
#ifdef CONFIG_IXGBE_DCB
#include "ixgbe_dcb_82599.h"
@@ -165,20 +164,20 @@ int ixgbe_fcoe_ddp_get(struct net_device *netdev, u16 xid,
adapter = netdev_priv(netdev);
if (xid >= IXGBE_FCOE_DDP_MAX) {
- DPRINTK(DRV, WARNING, "xid=0x%x out-of-range\n", xid);
+ e_warn(drv, "xid=0x%x out-of-range\n", xid);
return 0;
}
fcoe = &adapter->fcoe;
if (!fcoe->pool) {
- DPRINTK(DRV, WARNING, "xid=0x%x no ddp pool for fcoe\n", xid);
+ e_warn(drv, "xid=0x%x no ddp pool for fcoe\n", xid);
return 0;
}
ddp = &fcoe->ddp[xid];
if (ddp->sgl) {
- DPRINTK(DRV, ERR, "xid 0x%x w/ non-null sgl=%p nents=%d\n",
- xid, ddp->sgl, ddp->sgc);
+ e_err(drv, "xid 0x%x w/ non-null sgl=%p nents=%d\n",
+ xid, ddp->sgl, ddp->sgc);
return 0;
}
ixgbe_fcoe_clear_ddp(ddp);
@@ -186,14 +185,14 @@ int ixgbe_fcoe_ddp_get(struct net_device *netdev, u16 xid,
/* setup dma from scsi command sgl */
dmacount = pci_map_sg(adapter->pdev, sgl, sgc, DMA_FROM_DEVICE);
if (dmacount == 0) {
- DPRINTK(DRV, ERR, "xid 0x%x DMA map error\n", xid);
+ e_err(drv, "xid 0x%x DMA map error\n", xid);
return 0;
}
/* alloc the udl from our ddp pool */
- ddp->udl = pci_pool_alloc(fcoe->pool, GFP_KERNEL, &ddp->udp);
+ ddp->udl = pci_pool_alloc(fcoe->pool, GFP_ATOMIC, &ddp->udp);
if (!ddp->udl) {
- DPRINTK(DRV, ERR, "failed allocated ddp context\n");
+ e_err(drv, "failed allocated ddp context\n");
goto out_noddp_unmap;
}
ddp->sgl = sgl;
@@ -206,10 +205,9 @@ int ixgbe_fcoe_ddp_get(struct net_device *netdev, u16 xid,
while (len) {
/* max number of buffers allowed in one DDP context */
if (j >= IXGBE_BUFFCNT_MAX) {
- netif_err(adapter, drv, adapter->netdev,
- "xid=%x:%d,%d,%d:addr=%llx "
- "not enough descriptors\n",
- xid, i, j, dmacount, (u64)addr);
+ e_err(drv, "xid=%x:%d,%d,%d:addr=%llx "
+ "not enough descriptors\n",
+ xid, i, j, dmacount, (u64)addr);
goto out_noddp_free;
}
@@ -387,8 +385,8 @@ int ixgbe_fso(struct ixgbe_adapter *adapter,
struct fc_frame_header *fh;
if (skb_is_gso(skb) && (skb_shinfo(skb)->gso_type != SKB_GSO_FCOE)) {
- DPRINTK(DRV, ERR, "Wrong gso type %d:expecting SKB_GSO_FCOE\n",
- skb_shinfo(skb)->gso_type);
+ e_err(drv, "Wrong gso type %d:expecting SKB_GSO_FCOE\n",
+ skb_shinfo(skb)->gso_type);
return -EINVAL;
}
@@ -414,7 +412,7 @@ int ixgbe_fso(struct ixgbe_adapter *adapter,
fcoe_sof_eof |= IXGBE_ADVTXD_FCOEF_SOF;
break;
default:
- DPRINTK(DRV, WARNING, "unknown sof = 0x%x\n", sof);
+ e_warn(drv, "unknown sof = 0x%x\n", sof);
return -EINVAL;
}
@@ -441,7 +439,7 @@ int ixgbe_fso(struct ixgbe_adapter *adapter,
fcoe_sof_eof |= IXGBE_ADVTXD_FCOEF_EOF_A;
break;
default:
- DPRINTK(DRV, WARNING, "unknown eof = 0x%x\n", eof);
+ e_warn(drv, "unknown eof = 0x%x\n", eof);
return -EINVAL;
}
@@ -517,8 +515,7 @@ void ixgbe_configure_fcoe(struct ixgbe_adapter *adapter)
adapter->pdev, IXGBE_FCPTR_MAX,
IXGBE_FCPTR_ALIGN, PAGE_SIZE);
if (!fcoe->pool)
- DPRINTK(DRV, ERR,
- "failed to allocated FCoE DDP pool\n");
+ e_err(drv, "failed to allocated FCoE DDP pool\n");
spin_lock_init(&fcoe->lock);
}
@@ -614,7 +611,7 @@ int ixgbe_fcoe_enable(struct net_device *netdev)
if (adapter->flags & IXGBE_FLAG_FCOE_ENABLED)
goto out_enable;
- DPRINTK(DRV, INFO, "Enabling FCoE offload features.\n");
+ e_info(drv, "Enabling FCoE offload features.\n");
if (netif_running(netdev))
netdev->netdev_ops->ndo_stop(netdev);
@@ -625,9 +622,6 @@ int ixgbe_fcoe_enable(struct net_device *netdev)
netdev->features |= NETIF_F_FCOE_CRC;
netdev->features |= NETIF_F_FSO;
netdev->features |= NETIF_F_FCOE_MTU;
- netdev->vlan_features |= NETIF_F_FCOE_CRC;
- netdev->vlan_features |= NETIF_F_FSO;
- netdev->vlan_features |= NETIF_F_FCOE_MTU;
netdev->fcoe_ddp_xid = IXGBE_FCOE_DDP_MAX - 1;
ixgbe_init_interrupt_scheme(adapter);
@@ -660,25 +654,21 @@ int ixgbe_fcoe_disable(struct net_device *netdev)
if (!(adapter->flags & IXGBE_FLAG_FCOE_ENABLED))
goto out_disable;
- DPRINTK(DRV, INFO, "Disabling FCoE offload features.\n");
+ e_info(drv, "Disabling FCoE offload features.\n");
+ netdev->features &= ~NETIF_F_FCOE_CRC;
+ netdev->features &= ~NETIF_F_FSO;
+ netdev->features &= ~NETIF_F_FCOE_MTU;
+ netdev->fcoe_ddp_xid = 0;
+ netdev_features_change(netdev);
+
if (netif_running(netdev))
netdev->netdev_ops->ndo_stop(netdev);
ixgbe_clear_interrupt_scheme(adapter);
-
adapter->flags &= ~IXGBE_FLAG_FCOE_ENABLED;
adapter->ring_feature[RING_F_FCOE].indices = 0;
- netdev->features &= ~NETIF_F_FCOE_CRC;
- netdev->features &= ~NETIF_F_FSO;
- netdev->features &= ~NETIF_F_FCOE_MTU;
- netdev->vlan_features &= ~NETIF_F_FCOE_CRC;
- netdev->vlan_features &= ~NETIF_F_FSO;
- netdev->vlan_features &= ~NETIF_F_FCOE_MTU;
- netdev->fcoe_ddp_xid = 0;
-
ixgbe_cleanup_fcoe(adapter);
ixgbe_init_interrupt_scheme(adapter);
- netdev_features_change(netdev);
if (netif_running(netdev))
netdev->netdev_ops->ndo_open(netdev);
diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c
index 74d9b6df302..7d6a415bcf8 100644
--- a/drivers/net/ixgbe/ixgbe_main.c
+++ b/drivers/net/ixgbe/ixgbe_main.c
@@ -52,7 +52,7 @@ char ixgbe_driver_name[] = "ixgbe";
static const char ixgbe_driver_string[] =
"Intel(R) 10 Gigabit PCI Express Network Driver";
-#define DRV_VERSION "2.0.62-k2"
+#define DRV_VERSION "2.0.84-k2"
const char ixgbe_driver_version[] = DRV_VERSION;
static char ixgbe_copyright[] = "Copyright (c) 1999-2010 Intel Corporation.";
@@ -696,19 +696,19 @@ static inline bool ixgbe_check_tx_hang(struct ixgbe_adapter *adapter,
/* detected Tx unit hang */
union ixgbe_adv_tx_desc *tx_desc;
tx_desc = IXGBE_TX_DESC_ADV(*tx_ring, eop);
- DPRINTK(DRV, ERR, "Detected Tx Unit Hang\n"
- " Tx Queue <%d>\n"
- " TDH, TDT <%x>, <%x>\n"
- " next_to_use <%x>\n"
- " next_to_clean <%x>\n"
- "tx_buffer_info[next_to_clean]\n"
- " time_stamp <%lx>\n"
- " jiffies <%lx>\n",
- tx_ring->queue_index,
- IXGBE_READ_REG(hw, tx_ring->head),
- IXGBE_READ_REG(hw, tx_ring->tail),
- tx_ring->next_to_use, eop,
- tx_ring->tx_buffer_info[eop].time_stamp, jiffies);
+ e_err(drv, "Detected Tx Unit Hang\n"
+ " Tx Queue <%d>\n"
+ " TDH, TDT <%x>, <%x>\n"
+ " next_to_use <%x>\n"
+ " next_to_clean <%x>\n"
+ "tx_buffer_info[next_to_clean]\n"
+ " time_stamp <%lx>\n"
+ " jiffies <%lx>\n",
+ tx_ring->queue_index,
+ IXGBE_READ_REG(hw, tx_ring->head),
+ IXGBE_READ_REG(hw, tx_ring->tail),
+ tx_ring->next_to_use, eop,
+ tx_ring->tx_buffer_info[eop].time_stamp, jiffies);
return true;
}
@@ -812,9 +812,8 @@ static bool ixgbe_clean_tx_irq(struct ixgbe_q_vector *q_vector,
if (adapter->detect_tx_hung) {
if (ixgbe_check_tx_hang(adapter, tx_ring, i)) {
/* schedule immediate reset if we believe we hung */
- DPRINTK(PROBE, INFO,
- "tx hang %d detected, resetting adapter\n",
- adapter->tx_timeout_count + 1);
+ e_info(probe, "tx hang %d detected, resetting "
+ "adapter\n", adapter->tx_timeout_count + 1);
ixgbe_tx_timeout(adapter->netdev);
}
}
@@ -1653,10 +1652,10 @@ static void ixgbe_check_overtemp_task(struct work_struct *work)
return;
break;
}
- DPRINTK(DRV, ERR, "Network adapter has been stopped because it "
- "has over heated. Restart the computer. If the problem "
- "persists, power off the system and replace the "
- "adapter\n");
+ e_crit(drv, "Network adapter has been stopped because it has "
+ "over heated. Restart the computer. If the problem "
+ "persists, power off the system and replace the "
+ "adapter\n");
/* write to clear the interrupt */
IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_GPI_SDP0);
}
@@ -1668,7 +1667,7 @@ static void ixgbe_check_fan_failure(struct ixgbe_adapter *adapter, u32 eicr)
if ((adapter->flags & IXGBE_FLAG_FAN_FAIL_CAPABLE) &&
(eicr & IXGBE_EICR_GPI_SDP1)) {
- DPRINTK(PROBE, CRIT, "Fan has stopped, replace the adapter\n");
+ e_crit(probe, "Fan has stopped, replace the adapter\n");
/* write to clear the interrupt */
IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_GPI_SDP1);
}
@@ -2154,9 +2153,8 @@ static int ixgbe_request_msix_irqs(struct ixgbe_adapter *adapter)
handler, 0, adapter->name[vector],
adapter->q_vector[vector]);
if (err) {
- DPRINTK(PROBE, ERR,
- "request_irq failed for MSIX interrupt "
- "Error: %d\n", err);
+ e_err(probe, "request_irq failed for MSIX interrupt "
+ "Error: %d\n", err);
goto free_queue_irqs;
}
}
@@ -2165,8 +2163,7 @@ static int ixgbe_request_msix_irqs(struct ixgbe_adapter *adapter)
err = request_irq(adapter->msix_entries[vector].vector,
ixgbe_msix_lsc, 0, adapter->name[vector], netdev);
if (err) {
- DPRINTK(PROBE, ERR,
- "request_irq for msix_lsc failed: %d\n", err);
+ e_err(probe, "request_irq for msix_lsc failed: %d\n", err);
goto free_queue_irqs;
}
@@ -2352,7 +2349,7 @@ static int ixgbe_request_irq(struct ixgbe_adapter *adapter)
}
if (err)
- DPRINTK(PROBE, ERR, "request_irq failed, Error %d\n", err);
+ e_err(probe, "request_irq failed, Error %d\n", err);
return err;
}
@@ -2423,7 +2420,7 @@ static void ixgbe_configure_msi_and_legacy(struct ixgbe_adapter *adapter)
map_vector_to_rxq(adapter, 0, 0);
map_vector_to_txq(adapter, 0, 0);
- DPRINTK(HW, INFO, "Legacy interrupt IVAR setup done\n");
+ e_info(hw, "Legacy interrupt IVAR setup done\n");
}
/**
@@ -2803,10 +2800,8 @@ static void ixgbe_configure_rx(struct ixgbe_adapter *adapter)
/* Perform hash on these packet types */
mrqc |= IXGBE_MRQC_RSS_FIELD_IPV4
| IXGBE_MRQC_RSS_FIELD_IPV4_TCP
- | IXGBE_MRQC_RSS_FIELD_IPV4_UDP
| IXGBE_MRQC_RSS_FIELD_IPV6
- | IXGBE_MRQC_RSS_FIELD_IPV6_TCP
- | IXGBE_MRQC_RSS_FIELD_IPV6_UDP;
+ | IXGBE_MRQC_RSS_FIELD_IPV6_TCP;
}
IXGBE_WRITE_REG(hw, IXGBE_MRQC, mrqc);
@@ -2995,6 +2990,48 @@ static void ixgbe_restore_vlan(struct ixgbe_adapter *adapter)
}
/**
+ * ixgbe_write_uc_addr_list - write unicast addresses to RAR table
+ * @netdev: network interface device structure
+ *
+ * Writes unicast address list to the RAR table.
+ * Returns: -ENOMEM on failure/insufficient address space
+ * 0 on no addresses written
+ * X on writing X addresses to the RAR table
+ **/
+static int ixgbe_write_uc_addr_list(struct net_device *netdev)
+{
+ struct ixgbe_adapter *adapter = netdev_priv(netdev);
+ struct ixgbe_hw *hw = &adapter->hw;
+ unsigned int vfn = adapter->num_vfs;
+ unsigned int rar_entries = hw->mac.num_rar_entries - (vfn + 1);
+ int count = 0;
+
+ /* return ENOMEM indicating insufficient memory for addresses */
+ if (netdev_uc_count(netdev) > rar_entries)
+ return -ENOMEM;
+
+ if (!netdev_uc_empty(netdev) && rar_entries) {
+ struct netdev_hw_addr *ha;
+ /* return error if we do not support writing to RAR table */
+ if (!hw->mac.ops.set_rar)
+ return -ENOMEM;
+
+ netdev_for_each_uc_addr(ha, netdev) {
+ if (!rar_entries)
+ break;
+ hw->mac.ops.set_rar(hw, rar_entries--, ha->addr,
+ vfn, IXGBE_RAH_AV);
+ count++;
+ }
+ }
+ /* write the addresses in reverse order to avoid write combining */
+ for (; rar_entries > 0 ; rar_entries--)
+ hw->mac.ops.clear_rar(hw, rar_entries);
+
+ return count;
+}
+
+/**
* ixgbe_set_rx_mode - Unicast, Multicast and Promiscuous mode set
* @netdev: network interface device structure
*
@@ -3007,38 +3044,58 @@ void ixgbe_set_rx_mode(struct net_device *netdev)
{
struct ixgbe_adapter *adapter = netdev_priv(netdev);
struct ixgbe_hw *hw = &adapter->hw;
- u32 fctrl;
+ u32 fctrl, vmolr = IXGBE_VMOLR_BAM | IXGBE_VMOLR_AUPE;
+ int count;
/* Check for Promiscuous and All Multicast modes */
fctrl = IXGBE_READ_REG(hw, IXGBE_FCTRL);
+ /* clear the bits we are changing the status of */
+ fctrl &= ~(IXGBE_FCTRL_UPE | IXGBE_FCTRL_MPE);
+
if (netdev->flags & IFF_PROMISC) {
hw->addr_ctrl.user_set_promisc = true;
fctrl |= (IXGBE_FCTRL_UPE | IXGBE_FCTRL_MPE);
+ vmolr |= (IXGBE_VMOLR_ROPE | IXGBE_VMOLR_MPE);
/* don't hardware filter vlans in promisc mode */
ixgbe_vlan_filter_disable(adapter);
} else {
if (netdev->flags & IFF_ALLMULTI) {
fctrl |= IXGBE_FCTRL_MPE;
- fctrl &= ~IXGBE_FCTRL_UPE;
- } else if (!hw->addr_ctrl.uc_set_promisc) {
- fctrl &= ~(IXGBE_FCTRL_UPE | IXGBE_FCTRL_MPE);
+ vmolr |= IXGBE_VMOLR_MPE;
+ } else {
+ /*
+ * Write addresses to the MTA, if the attempt fails
+ * then we should just turn on promiscous mode so
+ * that we can at least receive multicast traffic
+ */
+ hw->mac.ops.update_mc_addr_list(hw, netdev);
+ vmolr |= IXGBE_VMOLR_ROMPE;
}
ixgbe_vlan_filter_enable(adapter);
hw->addr_ctrl.user_set_promisc = false;
+ /*
+ * Write addresses to available RAR registers, if there is not
+ * sufficient space to store all the addresses then enable
+ * unicast promiscous mode
+ */
+ count = ixgbe_write_uc_addr_list(netdev);
+ if (count < 0) {
+ fctrl |= IXGBE_FCTRL_UPE;
+ vmolr |= IXGBE_VMOLR_ROPE;
+ }
}
- IXGBE_WRITE_REG(hw, IXGBE_FCTRL, fctrl);
-
- /* reprogram secondary unicast list */
- hw->mac.ops.update_uc_addr_list(hw, netdev);
-
- /* reprogram multicast list */
- hw->mac.ops.update_mc_addr_list(hw, netdev);
-
- if (adapter->num_vfs)
+ if (adapter->num_vfs) {
ixgbe_restore_vf_multicasts(adapter);
+ vmolr |= IXGBE_READ_REG(hw, IXGBE_VMOLR(adapter->num_vfs)) &
+ ~(IXGBE_VMOLR_MPE | IXGBE_VMOLR_ROMPE |
+ IXGBE_VMOLR_ROPE);
+ IXGBE_WRITE_REG(hw, IXGBE_VMOLR(adapter->num_vfs), vmolr);
+ }
+
+ IXGBE_WRITE_REG(hw, IXGBE_FCTRL, fctrl);
}
static void ixgbe_napi_enable_all(struct ixgbe_adapter *adapter)
@@ -3257,8 +3314,8 @@ static inline void ixgbe_rx_desc_queue_enable(struct ixgbe_adapter *adapter,
msleep(1);
}
if (k >= IXGBE_MAX_RX_DESC_POLL) {
- DPRINTK(DRV, ERR, "RXDCTL.ENABLE on Rx queue %d "
- "not set within the polling period\n", rxr);
+ e_err(drv, "RXDCTL.ENABLE on Rx queue %d not set within "
+ "the polling period\n", rxr);
}
ixgbe_release_rx_desc(&adapter->hw, adapter->rx_ring[rxr],
(adapter->rx_ring[rxr]->count - 1));
@@ -3387,8 +3444,7 @@ static int ixgbe_up_complete(struct ixgbe_adapter *adapter)
} while (--wait_loop &&
!(txdctl & IXGBE_TXDCTL_ENABLE));
if (!wait_loop)
- DPRINTK(DRV, ERR, "Could not enable "
- "Tx Queue %d\n", j);
+ e_err(drv, "Could not enable Tx Queue %d\n", j);
}
}
@@ -3436,8 +3492,7 @@ static int ixgbe_up_complete(struct ixgbe_adapter *adapter)
if (adapter->flags & IXGBE_FLAG_FAN_FAIL_CAPABLE) {
u32 esdp = IXGBE_READ_REG(hw, IXGBE_ESDP);
if (esdp & IXGBE_ESDP_SDP1)
- DPRINTK(DRV, CRIT,
- "Fan has stopped, replace the adapter\n");
+ e_crit(drv, "Fan has stopped, replace the adapter\n");
}
/*
@@ -3466,7 +3521,7 @@ static int ixgbe_up_complete(struct ixgbe_adapter *adapter)
} else {
err = ixgbe_non_sfp_link_config(hw);
if (err)
- DPRINTK(PROBE, ERR, "link_config FAILED %d\n", err);
+ e_err(probe, "link_config FAILED %d\n", err);
}
for (i = 0; i < adapter->num_tx_queues; i++)
@@ -3527,19 +3582,19 @@ void ixgbe_reset(struct ixgbe_adapter *adapter)
case IXGBE_ERR_SFP_NOT_PRESENT:
break;
case IXGBE_ERR_MASTER_REQUESTS_PENDING:
- dev_err(&adapter->pdev->dev, "master disable timed out\n");
+ e_dev_err("master disable timed out\n");
break;
case IXGBE_ERR_EEPROM_VERSION:
/* We are running on a pre-production device, log a warning */
- dev_warn(&adapter->pdev->dev, "This device is a pre-production "
- "adapter/LOM. Please be aware there may be issues "
- "associated with your hardware. If you are "
- "experiencing problems please contact your Intel or "
- "hardware representative who provided you with this "
- "hardware.\n");
+ e_dev_warn("This device is a pre-production adapter/LOM. "
+ "Please be aware there may be issuesassociated with "
+ "your hardware. If you are experiencing problems "
+ "please contact your Intel or hardware "
+ "representative who provided you with this "
+ "hardware.\n");
break;
default:
- dev_err(&adapter->pdev->dev, "Hardware Error: %d\n", err);
+ e_dev_err("Hardware Error: %d\n", err);
}
/* reprogram the RAR[0] in case user changed it. */
@@ -3920,12 +3975,12 @@ static inline bool ixgbe_set_fcoe_queues(struct ixgbe_adapter *adapter)
adapter->num_tx_queues = 1;
#ifdef CONFIG_IXGBE_DCB
if (adapter->flags & IXGBE_FLAG_DCB_ENABLED) {
- DPRINTK(PROBE, INFO, "FCoE enabled with DCB\n");
+ e_info(probe, "FCoE enabled with DCB\n");
ixgbe_set_dcb_queues(adapter);
}
#endif
if (adapter->flags & IXGBE_FLAG_RSS_ENABLED) {
- DPRINTK(PROBE, INFO, "FCoE enabled with RSS\n");
+ e_info(probe, "FCoE enabled with RSS\n");
if ((adapter->flags & IXGBE_FLAG_FDIR_HASH_CAPABLE) ||
(adapter->flags & IXGBE_FLAG_FDIR_PERFECT_CAPABLE))
ixgbe_set_fdir_queues(adapter);
@@ -4038,7 +4093,8 @@ static void ixgbe_acquire_msix_vectors(struct ixgbe_adapter *adapter,
* This just means we'll go with either a single MSI
* vector or fall back to legacy interrupts.
*/
- DPRINTK(HW, DEBUG, "Unable to allocate MSI-X interrupts\n");
+ netif_printk(adapter, hw, KERN_DEBUG, adapter->netdev,
+ "Unable to allocate MSI-X interrupts\n");
adapter->flags &= ~IXGBE_FLAG_MSIX_ENABLED;
kfree(adapter->msix_entries);
adapter->msix_entries = NULL;
@@ -4435,8 +4491,9 @@ static int ixgbe_set_interrupt_capability(struct ixgbe_adapter *adapter)
if (!err) {
adapter->flags |= IXGBE_FLAG_MSI_ENABLED;
} else {
- DPRINTK(HW, DEBUG, "Unable to allocate MSI interrupt, "
- "falling back to legacy. Error: %d\n", err);
+ netif_printk(adapter, hw, KERN_DEBUG, adapter->netdev,
+ "Unable to allocate MSI interrupt, "
+ "falling back to legacy. Error: %d\n", err);
/* reset err */
err = 0;
}
@@ -4557,27 +4614,25 @@ int ixgbe_init_interrupt_scheme(struct ixgbe_adapter *adapter)
err = ixgbe_set_interrupt_capability(adapter);
if (err) {
- DPRINTK(PROBE, ERR, "Unable to setup interrupt capabilities\n");
+ e_dev_err("Unable to setup interrupt capabilities\n");
goto err_set_interrupt;
}
err = ixgbe_alloc_q_vectors(adapter);
if (err) {
- DPRINTK(PROBE, ERR, "Unable to allocate memory for queue "
- "vectors\n");
+ e_dev_err("Unable to allocate memory for queue vectors\n");
goto err_alloc_q_vectors;
}
err = ixgbe_alloc_queues(adapter);
if (err) {
- DPRINTK(PROBE, ERR, "Unable to allocate memory for queues\n");
+ e_dev_err("Unable to allocate memory for queues\n");
goto err_alloc_queues;
}
- DPRINTK(DRV, INFO, "Multiqueue %s: Rx Queue count = %u, "
- "Tx Queue count = %u\n",
- (adapter->num_rx_queues > 1) ? "Enabled" :
- "Disabled", adapter->num_rx_queues, adapter->num_tx_queues);
+ e_dev_info("Multiqueue %s: Rx Queue count = %u, Tx Queue count = %u\n",
+ (adapter->num_rx_queues > 1) ? "Enabled" : "Disabled",
+ adapter->num_rx_queues, adapter->num_tx_queues);
set_bit(__IXGBE_DOWN, &adapter->state);
@@ -4648,15 +4703,13 @@ static void ixgbe_sfp_task(struct work_struct *work)
goto reschedule;
ret = hw->phy.ops.reset(hw);
if (ret == IXGBE_ERR_SFP_NOT_SUPPORTED) {
- dev_err(&adapter->pdev->dev, "failed to initialize "
- "because an unsupported SFP+ module type "
- "was detected.\n"
- "Reload the driver after installing a "
- "supported module.\n");
+ e_dev_err("failed to initialize because an unsupported "
+ "SFP+ module type was detected.\n");
+ e_dev_err("Reload the driver after installing a "
+ "supported module.\n");
unregister_netdev(adapter->netdev);
} else {
- DPRINTK(PROBE, INFO, "detected SFP+: %d\n",
- hw->phy.sfp_type);
+ e_info(probe, "detected SFP+: %d\n", hw->phy.sfp_type);
}
/* don't need this routine any more */
clear_bit(__IXGBE_SFP_MODULE_NOT_FOUND, &adapter->state);
@@ -4730,6 +4783,7 @@ static int __devinit ixgbe_sw_init(struct ixgbe_adapter *adapter)
#ifdef CONFIG_IXGBE_DCB
/* Default traffic class to use for FCoE */
adapter->fcoe.tc = IXGBE_FCOE_DEFTC;
+ adapter->fcoe.up = IXGBE_FCOE_DEFTC;
#endif
#endif /* IXGBE_FCOE */
}
@@ -4783,7 +4837,7 @@ static int __devinit ixgbe_sw_init(struct ixgbe_adapter *adapter)
/* initialize eeprom parameters */
if (ixgbe_init_eeprom_params_generic(hw)) {
- dev_err(&pdev->dev, "EEPROM initialization failed\n");
+ e_dev_err("EEPROM initialization failed\n");
return -EIO;
}
@@ -4836,8 +4890,7 @@ int ixgbe_setup_tx_resources(struct ixgbe_adapter *adapter,
err:
vfree(tx_ring->tx_buffer_info);
tx_ring->tx_buffer_info = NULL;
- DPRINTK(PROBE, ERR, "Unable to allocate memory for the transmit "
- "descriptor ring\n");
+ e_err(probe, "Unable to allocate memory for the Tx descriptor ring\n");
return -ENOMEM;
}
@@ -4859,7 +4912,7 @@ static int ixgbe_setup_all_tx_resources(struct ixgbe_adapter *adapter)
err = ixgbe_setup_tx_resources(adapter, adapter->tx_ring[i]);
if (!err)
continue;
- DPRINTK(PROBE, ERR, "Allocation for Tx Queue %u failed\n", i);
+ e_err(probe, "Allocation for Tx Queue %u failed\n", i);
break;
}
@@ -4884,8 +4937,8 @@ int ixgbe_setup_rx_resources(struct ixgbe_adapter *adapter,
if (!rx_ring->rx_buffer_info)
rx_ring->rx_buffer_info = vmalloc(size);
if (!rx_ring->rx_buffer_info) {
- DPRINTK(PROBE, ERR,
- "vmalloc allocation failed for the rx desc ring\n");
+ e_err(probe, "vmalloc allocation failed for the Rx "
+ "descriptor ring\n");
goto alloc_failed;
}
memset(rx_ring->rx_buffer_info, 0, size);
@@ -4898,8 +4951,8 @@ int ixgbe_setup_rx_resources(struct ixgbe_adapter *adapter,
&rx_ring->dma, GFP_KERNEL);
if (!rx_ring->desc) {
- DPRINTK(PROBE, ERR,
- "Memory allocation failed for the rx desc ring\n");
+ e_err(probe, "Memory allocation failed for the Rx "
+ "descriptor ring\n");
vfree(rx_ring->rx_buffer_info);
goto alloc_failed;
}
@@ -4932,7 +4985,7 @@ static int ixgbe_setup_all_rx_resources(struct ixgbe_adapter *adapter)
err = ixgbe_setup_rx_resources(adapter, adapter->rx_ring[i]);
if (!err)
continue;
- DPRINTK(PROBE, ERR, "Allocation for Rx Queue %u failed\n", i);
+ e_err(probe, "Allocation for Rx Queue %u failed\n", i);
break;
}
@@ -5031,8 +5084,7 @@ static int ixgbe_change_mtu(struct net_device *netdev, int new_mtu)
if ((new_mtu < 68) || (max_frame > IXGBE_MAX_JUMBO_FRAME_SIZE))
return -EINVAL;
- DPRINTK(PROBE, INFO, "changing MTU from %d to %d\n",
- netdev->mtu, new_mtu);
+ e_info(probe, "changing MTU from %d to %d\n", netdev->mtu, new_mtu);
/* must set new MTU before calling down or up */
netdev->mtu = new_mtu;
@@ -5145,8 +5197,7 @@ static int ixgbe_resume(struct pci_dev *pdev)
err = pci_enable_device_mem(pdev);
if (err) {
- printk(KERN_ERR "ixgbe: Cannot enable PCI device from "
- "suspend\n");
+ e_dev_err("Cannot enable PCI device from suspend\n");
return err;
}
pci_set_master(pdev);
@@ -5155,8 +5206,7 @@ static int ixgbe_resume(struct pci_dev *pdev)
err = ixgbe_init_interrupt_scheme(adapter);
if (err) {
- printk(KERN_ERR "ixgbe: Cannot initialize interrupts for "
- "device\n");
+ e_dev_err("Cannot initialize interrupts for device\n");
return err;
}
@@ -5517,10 +5567,10 @@ static void ixgbe_sfp_config_module_task(struct work_struct *work)
err = hw->phy.ops.identify_sfp(hw);
if (err == IXGBE_ERR_SFP_NOT_SUPPORTED) {
- dev_err(&adapter->pdev->dev, "failed to initialize because "
- "an unsupported SFP+ module type was detected.\n"
- "Reload the driver after installing a supported "
- "module.\n");
+ e_dev_err("failed to initialize because an unsupported SFP+ "
+ "module type was detected.\n");
+ e_dev_err("Reload the driver after installing a supported "
+ "module.\n");
unregister_netdev(adapter->netdev);
return;
}
@@ -5549,8 +5599,8 @@ static void ixgbe_fdir_reinit_task(struct work_struct *work)
set_bit(__IXGBE_FDIR_INIT_DONE,
&(adapter->tx_ring[i]->reinit_state));
} else {
- DPRINTK(PROBE, ERR, "failed to finish FDIR re-initialization, "
- "ignored adding FDIR ATR filters\n");
+ e_err(probe, "failed to finish FDIR re-initialization, "
+ "ignored adding FDIR ATR filters\n");
}
/* Done FDIR Re-initialization, enable transmits */
netif_tx_start_all_queues(adapter->netdev);
@@ -5621,16 +5671,14 @@ static void ixgbe_watchdog_task(struct work_struct *work)
flow_tx = !!(rmcs & IXGBE_RMCS_TFCE_802_3X);
}
- printk(KERN_INFO "ixgbe: %s NIC Link is Up %s, "
- "Flow Control: %s\n",
- netdev->name,
+ e_info(drv, "NIC Link is Up %s, Flow Control: %s\n",
(link_speed == IXGBE_LINK_SPEED_10GB_FULL ?
- "10 Gbps" :
- (link_speed == IXGBE_LINK_SPEED_1GB_FULL ?
- "1 Gbps" : "unknown speed")),
+ "10 Gbps" :
+ (link_speed == IXGBE_LINK_SPEED_1GB_FULL ?
+ "1 Gbps" : "unknown speed")),
((flow_rx && flow_tx) ? "RX/TX" :
- (flow_rx ? "RX" :
- (flow_tx ? "TX" : "None"))));
+ (flow_rx ? "RX" :
+ (flow_tx ? "TX" : "None"))));
netif_carrier_on(netdev);
} else {
@@ -5641,8 +5689,7 @@ static void ixgbe_watchdog_task(struct work_struct *work)
adapter->link_up = false;
adapter->link_speed = 0;
if (netif_carrier_ok(netdev)) {
- printk(KERN_INFO "ixgbe: %s NIC Link is Down\n",
- netdev->name);
+ e_info(drv, "NIC Link is Down\n");
netif_carrier_off(netdev);
}
}
@@ -5818,9 +5865,9 @@ static bool ixgbe_tx_csum(struct ixgbe_adapter *adapter,
break;
default:
if (unlikely(net_ratelimit())) {
- DPRINTK(PROBE, WARNING,
- "partial checksum but proto=%x!\n",
- skb->protocol);
+ e_warn(probe, "partial checksum "
+ "but proto=%x!\n",
+ skb->protocol);
}
break;
}
@@ -5931,7 +5978,7 @@ static int ixgbe_tx_map(struct ixgbe_adapter *adapter,
return count;
dma_error:
- dev_err(&pdev->dev, "TX DMA map failed\n");
+ e_dev_err("TX DMA map failed\n");
/* clear timestamp and dma mappings for failed tx_buffer_info map */
tx_buffer_info->dma = 0;
@@ -6101,21 +6148,26 @@ static u16 ixgbe_select_queue(struct net_device *dev, struct sk_buff *skb)
struct ixgbe_adapter *adapter = netdev_priv(dev);
int txq = smp_processor_id();
+#ifdef IXGBE_FCOE
+ if ((skb->protocol == htons(ETH_P_FCOE)) ||
+ (skb->protocol == htons(ETH_P_FIP))) {
+ if (adapter->flags & IXGBE_FLAG_FCOE_ENABLED) {
+ txq &= (adapter->ring_feature[RING_F_FCOE].indices - 1);
+ txq += adapter->ring_feature[RING_F_FCOE].mask;
+ return txq;
+ } else if (adapter->flags & IXGBE_FLAG_DCB_ENABLED) {
+ txq = adapter->fcoe.up;
+ return txq;
+ }
+ }
+#endif
+
if (adapter->flags & IXGBE_FLAG_FDIR_HASH_CAPABLE) {
while (unlikely(txq >= dev->real_num_tx_queues))
txq -= dev->real_num_tx_queues;
return txq;
}
-#ifdef IXGBE_FCOE
- if ((adapter->flags & IXGBE_FLAG_FCOE_ENABLED) &&
- ((skb->protocol == htons(ETH_P_FCOE)) ||
- (skb->protocol == htons(ETH_P_FIP)))) {
- txq &= (adapter->ring_feature[RING_F_FCOE].indices - 1);
- txq += adapter->ring_feature[RING_F_FCOE].mask;
- return txq;
- }
-#endif
if (adapter->flags & IXGBE_FLAG_DCB_ENABLED) {
if (skb->priority == TC_PRIO_CONTROL)
txq = adapter->ring_feature[RING_F_DCB].indices-1;
@@ -6159,18 +6211,15 @@ static netdev_tx_t ixgbe_xmit_frame(struct sk_buff *skb,
tx_ring = adapter->tx_ring[skb->queue_mapping];
#ifdef IXGBE_FCOE
- if (adapter->flags & IXGBE_FLAG_FCOE_ENABLED) {
-#ifdef CONFIG_IXGBE_DCB
- /* for FCoE with DCB, we force the priority to what
- * was specified by the switch */
- if ((skb->protocol == htons(ETH_P_FCOE)) ||
- (skb->protocol == htons(ETH_P_FIP))) {
- tx_flags &= ~(IXGBE_TX_FLAGS_VLAN_PRIO_MASK
- << IXGBE_TX_FLAGS_VLAN_SHIFT);
- tx_flags |= ((adapter->fcoe.up << 13)
- << IXGBE_TX_FLAGS_VLAN_SHIFT);
- }
-#endif
+ /* for FCoE with DCB, we force the priority to what
+ * was specified by the switch */
+ if (adapter->flags & IXGBE_FLAG_FCOE_ENABLED &&
+ (skb->protocol == htons(ETH_P_FCOE) ||
+ skb->protocol == htons(ETH_P_FIP))) {
+ tx_flags &= ~(IXGBE_TX_FLAGS_VLAN_PRIO_MASK
+ << IXGBE_TX_FLAGS_VLAN_SHIFT);
+ tx_flags |= ((adapter->fcoe.up << 13)
+ << IXGBE_TX_FLAGS_VLAN_SHIFT);
/* flag for FCoE offloads */
if (skb->protocol == htons(ETH_P_FCOE))
tx_flags |= IXGBE_TX_FLAGS_FCOE;
@@ -6430,8 +6479,7 @@ static void __devinit ixgbe_probe_vf(struct ixgbe_adapter *adapter,
adapter->flags |= IXGBE_FLAG_SRIOV_ENABLED;
err = pci_enable_sriov(adapter->pdev, adapter->num_vfs);
if (err) {
- DPRINTK(PROBE, ERR,
- "Failed to enable PCI sriov: %d\n", err);
+ e_err(probe, "Failed to enable PCI sriov: %d\n", err);
goto err_novfs;
}
/* If call to enable VFs succeeded then allocate memory
@@ -6455,9 +6503,8 @@ static void __devinit ixgbe_probe_vf(struct ixgbe_adapter *adapter,
}
/* Oh oh */
- DPRINTK(PROBE, ERR,
- "Unable to allocate memory for VF "
- "Data Storage - SRIOV disabled\n");
+ e_err(probe, "Unable to allocate memory for VF Data Storage - "
+ "SRIOV disabled\n");
pci_disable_sriov(adapter->pdev);
err_novfs:
@@ -6514,8 +6561,8 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev,
err = dma_set_coherent_mask(&pdev->dev,
DMA_BIT_MASK(32));
if (err) {
- dev_err(&pdev->dev, "No usable DMA "
- "configuration, aborting\n");
+ dev_err(&pdev->dev,
+ "No usable DMA configuration, aborting\n");
goto err_dma;
}
}
@@ -6526,7 +6573,7 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev,
IORESOURCE_MEM), ixgbe_driver_name);
if (err) {
dev_err(&pdev->dev,
- "pci_request_selected_regions failed 0x%x\n", err);
+ "pci_request_selected_regions failed 0x%x\n", err);
goto err_pci_reg;
}
@@ -6637,8 +6684,7 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev,
if (adapter->flags & IXGBE_FLAG_FAN_FAIL_CAPABLE) {
u32 esdp = IXGBE_READ_REG(hw, IXGBE_ESDP);
if (esdp & IXGBE_ESDP_SDP1)
- DPRINTK(PROBE, CRIT,
- "Fan has stopped, replace the adapter\n");
+ e_crit(probe, "Fan has stopped, replace the adapter\n");
}
/* reset_hw fills in the perm_addr as well */
@@ -6657,13 +6703,13 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev,
round_jiffies(jiffies + (2 * HZ)));
err = 0;
} else if (err == IXGBE_ERR_SFP_NOT_SUPPORTED) {
- dev_err(&adapter->pdev->dev, "failed to initialize because "
- "an unsupported SFP+ module type was detected.\n"
- "Reload the driver after installing a supported "
- "module.\n");
+ e_dev_err("failed to initialize because an unsupported SFP+ "
+ "module type was detected.\n");
+ e_dev_err("Reload the driver after installing a supported "
+ "module.\n");
goto err_sw_init;
} else if (err) {
- dev_err(&adapter->pdev->dev, "HW Init failed: %d\n", err);
+ e_dev_err("HW Init failed: %d\n", err);
goto err_sw_init;
}
@@ -6707,6 +6753,11 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev,
adapter->flags &= ~IXGBE_FLAG_FCOE_CAPABLE;
}
}
+ if (adapter->flags & IXGBE_FLAG_FCOE_CAPABLE) {
+ netdev->vlan_features |= NETIF_F_FCOE_CRC;
+ netdev->vlan_features |= NETIF_F_FSO;
+ netdev->vlan_features |= NETIF_F_FCOE_MTU;
+ }
#endif /* IXGBE_FCOE */
if (pci_using_dac)
netdev->features |= NETIF_F_HIGHDMA;
@@ -6716,7 +6767,7 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev,
/* make sure the EEPROM is good */
if (hw->eeprom.ops.validate_checksum(hw, NULL) < 0) {
- dev_err(&pdev->dev, "The EEPROM Checksum Is Not Valid\n");
+ e_dev_err("The EEPROM Checksum Is Not Valid\n");
err = -EIO;
goto err_eeprom;
}
@@ -6725,7 +6776,7 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev,
memcpy(netdev->perm_addr, hw->mac.perm_addr, netdev->addr_len);
if (ixgbe_validate_mac_addr(netdev->perm_addr)) {
- dev_err(&pdev->dev, "invalid MAC address\n");
+ e_dev_err("invalid MAC address\n");
err = -EIO;
goto err_eeprom;
}
@@ -6760,7 +6811,7 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev,
hw->mac.ops.get_bus_info(hw);
/* print bus type/speed/width info */
- dev_info(&pdev->dev, "(PCI Express:%s:%s) %pM\n",
+ e_dev_info("(PCI Express:%s:%s) %pM\n",
((hw->bus.speed == ixgbe_bus_speed_5000) ? "5.0Gb/s":
(hw->bus.speed == ixgbe_bus_speed_2500) ? "2.5Gb/s":"Unknown"),
((hw->bus.width == ixgbe_bus_width_pcie_x8) ? "Width x8" :
@@ -6770,20 +6821,20 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev,
netdev->dev_addr);
ixgbe_read_pba_num_generic(hw, &part_num);
if (ixgbe_is_sfp(hw) && hw->phy.sfp_type != ixgbe_sfp_type_not_present)
- dev_info(&pdev->dev, "MAC: %d, PHY: %d, SFP+: %d, PBA No: %06x-%03x\n",
- hw->mac.type, hw->phy.type, hw->phy.sfp_type,
- (part_num >> 8), (part_num & 0xff));
+ e_dev_info("MAC: %d, PHY: %d, SFP+: %d, "
+ "PBA No: %06x-%03x\n",
+ hw->mac.type, hw->phy.type, hw->phy.sfp_type,
+ (part_num >> 8), (part_num & 0xff));
else
- dev_info(&pdev->dev, "MAC: %d, PHY: %d, PBA No: %06x-%03x\n",
- hw->mac.type, hw->phy.type,
- (part_num >> 8), (part_num & 0xff));
+ e_dev_info("MAC: %d, PHY: %d, PBA No: %06x-%03x\n",
+ hw->mac.type, hw->phy.type,
+ (part_num >> 8), (part_num & 0xff));
if (hw->bus.width <= ixgbe_bus_width_pcie_x4) {
- dev_warn(&pdev->dev, "PCI-Express bandwidth available for "
- "this card is not sufficient for optimal "
- "performance.\n");
- dev_warn(&pdev->dev, "For optimal performance a x8 "
- "PCI-Express slot is required.\n");
+ e_dev_warn("PCI-Express bandwidth available for this card is "
+ "not sufficient for optimal performance.\n");
+ e_dev_warn("For optimal performance a x8 PCI-Express slot "
+ "is required.\n");
}
/* save off EEPROM version number */
@@ -6794,12 +6845,12 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev,
if (err == IXGBE_ERR_EEPROM_VERSION) {
/* We are running on a pre-production device, log a warning */
- dev_warn(&pdev->dev, "This device is a pre-production "
- "adapter/LOM. Please be aware there may be issues "
- "associated with your hardware. If you are "
- "experiencing problems please contact your Intel or "
- "hardware representative who provided you with this "
- "hardware.\n");
+ e_dev_warn("This device is a pre-production adapter/LOM. "
+ "Please be aware there may be issues associated "
+ "with your hardware. If you are experiencing "
+ "problems please contact your Intel or hardware "
+ "representative who provided you with this "
+ "hardware.\n");
}
strcpy(netdev->name, "eth%d");
err = register_netdev(netdev);
@@ -6822,8 +6873,7 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev,
}
#endif
if (adapter->flags & IXGBE_FLAG_SRIOV_ENABLED) {
- DPRINTK(PROBE, INFO, "IOV is enabled with %d VFs\n",
- adapter->num_vfs);
+ e_info(probe, "IOV is enabled with %d VFs\n", adapter->num_vfs);
for (i = 0; i < adapter->num_vfs; i++)
ixgbe_vf_configuration(pdev, (i | 0x10000000));
}
@@ -6831,7 +6881,7 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev,
/* add san mac addr to netdev */
ixgbe_add_sanmac_netdev(netdev);
- dev_info(&pdev->dev, "Intel(R) 10 Gigabit Network Connection\n");
+ e_dev_info("Intel(R) 10 Gigabit Network Connection\n");
cards_found++;
return 0;
@@ -6921,7 +6971,7 @@ static void __devexit ixgbe_remove(struct pci_dev *pdev)
pci_release_selected_regions(pdev, pci_select_bars(pdev,
IORESOURCE_MEM));
- DPRINTK(PROBE, INFO, "complete\n");
+ e_dev_info("complete\n");
free_netdev(netdev);
@@ -6971,8 +7021,7 @@ static pci_ers_result_t ixgbe_io_slot_reset(struct pci_dev *pdev)
int err;
if (pci_enable_device_mem(pdev)) {
- DPRINTK(PROBE, ERR,
- "Cannot re-enable PCI device after reset.\n");
+ e_err(probe, "Cannot re-enable PCI device after reset.\n");
result = PCI_ERS_RESULT_DISCONNECT;
} else {
pci_set_master(pdev);
@@ -6988,8 +7037,8 @@ static pci_ers_result_t ixgbe_io_slot_reset(struct pci_dev *pdev)
err = pci_cleanup_aer_uncorrect_error_status(pdev);
if (err) {
- dev_err(&pdev->dev,
- "pci_cleanup_aer_uncorrect_error_status failed 0x%0x\n", err);
+ e_dev_err("pci_cleanup_aer_uncorrect_error_status "
+ "failed 0x%0x\n", err);
/* non-fatal, continue */
}
@@ -7010,7 +7059,7 @@ static void ixgbe_io_resume(struct pci_dev *pdev)
if (netif_running(netdev)) {
if (ixgbe_up(adapter)) {
- DPRINTK(PROBE, INFO, "ixgbe_up failed after reset\n");
+ e_info(probe, "ixgbe_up failed after reset\n");
return;
}
}
@@ -7046,10 +7095,9 @@ static struct pci_driver ixgbe_driver = {
static int __init ixgbe_init_module(void)
{
int ret;
- printk(KERN_INFO "%s: %s - version %s\n", ixgbe_driver_name,
- ixgbe_driver_string, ixgbe_driver_version);
-
- printk(KERN_INFO "%s: %s\n", ixgbe_driver_name, ixgbe_copyright);
+ pr_info("%s - version %s\n", ixgbe_driver_string,
+ ixgbe_driver_version);
+ pr_info("%s\n", ixgbe_copyright);
#ifdef CONFIG_IXGBE_DCA
dca_register_notify(&dca_notifier);
@@ -7088,18 +7136,17 @@ static int ixgbe_notify_dca(struct notifier_block *nb, unsigned long event,
}
#endif /* CONFIG_IXGBE_DCA */
-#ifdef DEBUG
+
/**
- * ixgbe_get_hw_dev_name - return device name string
+ * ixgbe_get_hw_dev return device
* used by hardware layer to print debugging information
**/
-char *ixgbe_get_hw_dev_name(struct ixgbe_hw *hw)
+struct net_device *ixgbe_get_hw_dev(struct ixgbe_hw *hw)
{
struct ixgbe_adapter *adapter = hw->back;
- return adapter->netdev->name;
+ return adapter->netdev;
}
-#endif
module_exit(ixgbe_exit_module);
/* ixgbe_main.c */
diff --git a/drivers/net/ixgbe/ixgbe_phy.c b/drivers/net/ixgbe/ixgbe_phy.c
index 48325a5beff..6c0d42e33f2 100644
--- a/drivers/net/ixgbe/ixgbe_phy.c
+++ b/drivers/net/ixgbe/ixgbe_phy.c
@@ -577,6 +577,8 @@ s32 ixgbe_identify_sfp_module_generic(struct ixgbe_hw *hw)
* 6 SFP_SR/LR_CORE1 - 82599-specific
* 7 SFP_act_lmt_DA_CORE0 - 82599-specific
* 8 SFP_act_lmt_DA_CORE1 - 82599-specific
+ * 9 SFP_1g_cu_CORE0 - 82599-specific
+ * 10 SFP_1g_cu_CORE1 - 82599-specific
*/
if (hw->mac.type == ixgbe_mac_82598EB) {
if (cable_tech & IXGBE_SFF_DA_PASSIVE_CABLE)
@@ -625,6 +627,13 @@ s32 ixgbe_identify_sfp_module_generic(struct ixgbe_hw *hw)
else
hw->phy.sfp_type =
ixgbe_sfp_type_srlr_core1;
+ else if (comp_codes_1g & IXGBE_SFF_1GBASET_CAPABLE)
+ if (hw->bus.lan_id == 0)
+ hw->phy.sfp_type =
+ ixgbe_sfp_type_1g_cu_core0;
+ else
+ hw->phy.sfp_type =
+ ixgbe_sfp_type_1g_cu_core1;
else
hw->phy.sfp_type = ixgbe_sfp_type_unknown;
}
@@ -696,8 +705,10 @@ s32 ixgbe_identify_sfp_module_generic(struct ixgbe_hw *hw)
goto out;
}
- /* 1G SFP modules are not supported */
- if (comp_codes_10g == 0) {
+ /* Verify supported 1G SFP modules */
+ if (comp_codes_10g == 0 &&
+ !(hw->phy.sfp_type == ixgbe_sfp_type_1g_cu_core1 ||
+ hw->phy.sfp_type == ixgbe_sfp_type_1g_cu_core0)) {
hw->phy.type = ixgbe_phy_sfp_unsupported;
status = IXGBE_ERR_SFP_NOT_SUPPORTED;
goto out;
@@ -711,7 +722,9 @@ s32 ixgbe_identify_sfp_module_generic(struct ixgbe_hw *hw)
/* This is guaranteed to be 82599, no need to check for NULL */
hw->mac.ops.get_device_caps(hw, &enforce_sfp);
- if (!(enforce_sfp & IXGBE_DEVICE_CAPS_ALLOW_ANY_SFP)) {
+ if (!(enforce_sfp & IXGBE_DEVICE_CAPS_ALLOW_ANY_SFP) &&
+ !((hw->phy.sfp_type == ixgbe_sfp_type_1g_cu_core0) ||
+ (hw->phy.sfp_type == ixgbe_sfp_type_1g_cu_core1))) {
/* Make sure we're a supported PHY type */
if (hw->phy.type == ixgbe_phy_sfp_intel) {
status = 0;
@@ -742,6 +755,7 @@ s32 ixgbe_get_sfp_init_sequence_offsets(struct ixgbe_hw *hw,
u16 *data_offset)
{
u16 sfp_id;
+ u16 sfp_type = hw->phy.sfp_type;
if (hw->phy.sfp_type == ixgbe_sfp_type_unknown)
return IXGBE_ERR_SFP_NOT_SUPPORTED;
@@ -753,6 +767,17 @@ s32 ixgbe_get_sfp_init_sequence_offsets(struct ixgbe_hw *hw,
(hw->phy.sfp_type == ixgbe_sfp_type_da_cu))
return IXGBE_ERR_SFP_NOT_SUPPORTED;
+ /*
+ * Limiting active cables and 1G Phys must be initialized as
+ * SR modules
+ */
+ if (sfp_type == ixgbe_sfp_type_da_act_lmt_core0 ||
+ sfp_type == ixgbe_sfp_type_1g_cu_core0)
+ sfp_type = ixgbe_sfp_type_srlr_core0;
+ else if (sfp_type == ixgbe_sfp_type_da_act_lmt_core1 ||
+ sfp_type == ixgbe_sfp_type_1g_cu_core1)
+ sfp_type = ixgbe_sfp_type_srlr_core1;
+
/* Read offset to PHY init contents */
hw->eeprom.ops.read(hw, IXGBE_PHY_INIT_OFFSET_NL, list_offset);
@@ -769,7 +794,7 @@ s32 ixgbe_get_sfp_init_sequence_offsets(struct ixgbe_hw *hw,
hw->eeprom.ops.read(hw, *list_offset, &sfp_id);
while (sfp_id != IXGBE_PHY_INIT_END_NL) {
- if (sfp_id == hw->phy.sfp_type) {
+ if (sfp_id == sfp_type) {
(*list_offset)++;
hw->eeprom.ops.read(hw, *list_offset, data_offset);
if ((!*data_offset) || (*data_offset == 0xFFFF)) {
diff --git a/drivers/net/ixgbe/ixgbe_phy.h b/drivers/net/ixgbe/ixgbe_phy.h
index ef4ba834c59..fb3898f12fc 100644
--- a/drivers/net/ixgbe/ixgbe_phy.h
+++ b/drivers/net/ixgbe/ixgbe_phy.h
@@ -48,6 +48,7 @@
#define IXGBE_SFF_DA_SPEC_ACTIVE_LIMITING 0x4
#define IXGBE_SFF_1GBASESX_CAPABLE 0x1
#define IXGBE_SFF_1GBASELX_CAPABLE 0x2
+#define IXGBE_SFF_1GBASET_CAPABLE 0x8
#define IXGBE_SFF_10GBASESR_CAPABLE 0x10
#define IXGBE_SFF_10GBASELR_CAPABLE 0x20
#define IXGBE_I2C_EEPROM_READ_MASK 0x100
diff --git a/drivers/net/ixgbe/ixgbe_sriov.c b/drivers/net/ixgbe/ixgbe_sriov.c
index f6cee94ec8e..49661a138e2 100644
--- a/drivers/net/ixgbe/ixgbe_sriov.c
+++ b/drivers/net/ixgbe/ixgbe_sriov.c
@@ -25,7 +25,6 @@
*******************************************************************************/
-
#include <linux/types.h>
#include <linux/module.h>
#include <linux/pci.h>
@@ -138,6 +137,7 @@ static void ixgbe_set_vmvir(struct ixgbe_adapter *adapter, u32 vid, u32 vf)
inline void ixgbe_vf_reset_event(struct ixgbe_adapter *adapter, u32 vf)
{
struct ixgbe_hw *hw = &adapter->hw;
+ int rar_entry = hw->mac.num_rar_entries - (vf + 1);
/* reset offloads to defaults */
if (adapter->vfinfo[vf].pf_vlan) {
@@ -159,26 +159,17 @@ inline void ixgbe_vf_reset_event(struct ixgbe_adapter *adapter, u32 vf)
/* Flush and reset the mta with the new values */
ixgbe_set_rx_mode(adapter->netdev);
- if (adapter->vfinfo[vf].rar > 0) {
- adapter->hw.mac.ops.clear_rar(&adapter->hw,
- adapter->vfinfo[vf].rar);
- adapter->vfinfo[vf].rar = -1;
- }
+ hw->mac.ops.clear_rar(hw, rar_entry);
}
int ixgbe_set_vf_mac(struct ixgbe_adapter *adapter,
int vf, unsigned char *mac_addr)
{
struct ixgbe_hw *hw = &adapter->hw;
-
- adapter->vfinfo[vf].rar = hw->mac.ops.set_rar(hw, vf + 1, mac_addr,
- vf, IXGBE_RAH_AV);
- if (adapter->vfinfo[vf].rar < 0) {
- DPRINTK(DRV, ERR, "Could not set MAC Filter for VF %d\n", vf);
- return -1;
- }
+ int rar_entry = hw->mac.num_rar_entries - (vf + 1);
memcpy(adapter->vfinfo[vf].vf_mac_addresses, mac_addr, 6);
+ hw->mac.ops.set_rar(hw, rar_entry, mac_addr, vf, IXGBE_RAH_AV);
return 0;
}
@@ -194,11 +185,8 @@ int ixgbe_vf_configuration(struct pci_dev *pdev, unsigned int event_mask)
if (enable) {
random_ether_addr(vf_mac_addr);
- DPRINTK(PROBE, INFO, "IOV: VF %d is enabled "
- "mac %02X:%02X:%02X:%02X:%02X:%02X\n",
- vfn,
- vf_mac_addr[0], vf_mac_addr[1], vf_mac_addr[2],
- vf_mac_addr[3], vf_mac_addr[4], vf_mac_addr[5]);
+ e_info(probe, "IOV: VF %d is enabled MAC %pM\n",
+ vfn, vf_mac_addr);
/*
* Store away the VF "permananet" MAC address, it will ask
* for it later.
@@ -243,7 +231,7 @@ static int ixgbe_rcv_msg_from_vf(struct ixgbe_adapter *adapter, u32 vf)
retval = ixgbe_read_mbx(hw, msgbuf, mbx_size, vf);
if (retval)
- printk(KERN_ERR "Error receiving message from VF\n");
+ pr_err("Error receiving message from VF\n");
/* this is a message we already processed, do nothing */
if (msgbuf[0] & (IXGBE_VT_MSGTYPE_ACK | IXGBE_VT_MSGTYPE_NACK))
@@ -257,7 +245,7 @@ static int ixgbe_rcv_msg_from_vf(struct ixgbe_adapter *adapter, u32 vf)
if (msgbuf[0] == IXGBE_VF_RESET) {
unsigned char *vf_mac = adapter->vfinfo[vf].vf_mac_addresses;
u8 *addr = (u8 *)(&msgbuf[1]);
- DPRINTK(PROBE, INFO, "VF Reset msg received from vf %d\n", vf);
+ e_info(probe, "VF Reset msg received from vf %d\n", vf);
adapter->vfinfo[vf].clear_to_send = false;
ixgbe_vf_reset_msg(adapter, vf);
adapter->vfinfo[vf].clear_to_send = true;
@@ -310,7 +298,7 @@ static int ixgbe_rcv_msg_from_vf(struct ixgbe_adapter *adapter, u32 vf)
retval = ixgbe_set_vf_vlan(adapter, add, vid, vf);
break;
default:
- DPRINTK(DRV, ERR, "Unhandled Msg %8.8x\n", msgbuf[0]);
+ e_err(drv, "Unhandled Msg %8.8x\n", msgbuf[0]);
retval = IXGBE_ERR_MBX;
break;
}
diff --git a/drivers/net/ixgbe/ixgbe_type.h b/drivers/net/ixgbe/ixgbe_type.h
index cdd1998f18c..9587d975d66 100644
--- a/drivers/net/ixgbe/ixgbe_type.h
+++ b/drivers/net/ixgbe/ixgbe_type.h
@@ -2214,6 +2214,8 @@ enum ixgbe_sfp_type {
ixgbe_sfp_type_srlr_core1 = 6,
ixgbe_sfp_type_da_act_lmt_core0 = 7,
ixgbe_sfp_type_da_act_lmt_core1 = 8,
+ ixgbe_sfp_type_1g_cu_core0 = 9,
+ ixgbe_sfp_type_1g_cu_core1 = 10,
ixgbe_sfp_type_not_present = 0xFFFE,
ixgbe_sfp_type_unknown = 0xFFFF
};
diff --git a/drivers/net/ixgbevf/ixgbevf_main.c b/drivers/net/ixgbevf/ixgbevf_main.c
index a16cff7e54a..3e291ccc629 100644
--- a/drivers/net/ixgbevf/ixgbevf_main.c
+++ b/drivers/net/ixgbevf/ixgbevf_main.c
@@ -1463,18 +1463,10 @@ static void ixgbevf_vlan_rx_add_vid(struct net_device *netdev, u16 vid)
{
struct ixgbevf_adapter *adapter = netdev_priv(netdev);
struct ixgbe_hw *hw = &adapter->hw;
- struct net_device *v_netdev;
/* add VID to filter table */
if (hw->mac.ops.set_vfta)
hw->mac.ops.set_vfta(hw, vid, 0, true);
- /*
- * Copy feature flags from netdev to the vlan netdev for this vid.
- * This allows things like TSO to bubble down to our vlan device.
- */
- v_netdev = vlan_group_get_device(adapter->vlgrp, vid);
- v_netdev->features |= adapter->netdev->features;
- vlan_group_set_device(adapter->vlgrp, vid, v_netdev);
}
static void ixgbevf_vlan_rx_kill_vid(struct net_device *netdev, u16 vid)
@@ -2229,7 +2221,7 @@ static int __devinit ixgbevf_sw_init(struct ixgbevf_adapter *adapter)
if (err) {
dev_info(&pdev->dev,
"PF still in reset state, assigning new address\n");
- random_ether_addr(hw->mac.addr);
+ dev_hw_addr_random(adapter->netdev, hw->mac.addr);
} else {
err = hw->mac.ops.init_hw(hw);
if (err) {
@@ -2935,7 +2927,8 @@ static int ixgbevf_tx_map(struct ixgbevf_adapter *adapter,
struct ixgbevf_tx_buffer *tx_buffer_info;
unsigned int len;
unsigned int total = skb->len;
- unsigned int offset = 0, size, count = 0;
+ unsigned int offset = 0, size;
+ int count = 0;
unsigned int nr_frags = skb_shinfo(skb)->nr_frags;
unsigned int f;
int i;
@@ -3401,7 +3394,6 @@ static int __devinit ixgbevf_probe(struct pci_dev *pdev,
/* setup the private structure */
err = ixgbevf_sw_init(adapter);
-#ifdef MAX_SKB_FRAGS
netdev->features = NETIF_F_SG |
NETIF_F_IP_CSUM |
NETIF_F_HW_VLAN_TX |
@@ -3411,16 +3403,16 @@ static int __devinit ixgbevf_probe(struct pci_dev *pdev,
netdev->features |= NETIF_F_IPV6_CSUM;
netdev->features |= NETIF_F_TSO;
netdev->features |= NETIF_F_TSO6;
+ netdev->features |= NETIF_F_GRO;
netdev->vlan_features |= NETIF_F_TSO;
netdev->vlan_features |= NETIF_F_TSO6;
netdev->vlan_features |= NETIF_F_IP_CSUM;
+ netdev->vlan_features |= NETIF_F_IPV6_CSUM;
netdev->vlan_features |= NETIF_F_SG;
if (pci_using_dac)
netdev->features |= NETIF_F_HIGHDMA;
-#endif /* MAX_SKB_FRAGS */
-
/* The HW MAC address was set and/or determined in sw_init */
memcpy(netdev->dev_addr, adapter->hw.mac.addr, netdev->addr_len);
memcpy(netdev->perm_addr, adapter->hw.mac.addr, netdev->addr_len);
diff --git a/drivers/net/jazzsonic.c b/drivers/net/jazzsonic.c
index 3e6aaf9e5ce..949c1f93364 100644
--- a/drivers/net/jazzsonic.c
+++ b/drivers/net/jazzsonic.c
@@ -82,11 +82,20 @@ static unsigned short known_revisions[] =
static int jazzsonic_open(struct net_device* dev)
{
- if (request_irq(dev->irq, sonic_interrupt, IRQF_DISABLED, "sonic", dev)) {
- printk(KERN_ERR "%s: unable to get IRQ %d.\n", dev->name, dev->irq);
- return -EAGAIN;
+ int retval;
+
+ retval = request_irq(dev->irq, sonic_interrupt, IRQF_DISABLED,
+ "sonic", dev);
+ if (retval) {
+ printk(KERN_ERR "%s: unable to get IRQ %d.\n",
+ dev->name, dev->irq);
+ return retval;
}
- return sonic_open(dev);
+
+ retval = sonic_open(dev);
+ if (retval)
+ free_irq(dev->irq, dev);
+ return retval;
}
static int jazzsonic_close(struct net_device* dev)
diff --git a/drivers/net/ks8842.c b/drivers/net/ks8842.c
index f852ab3ae9c..928b2b83cef 100644
--- a/drivers/net/ks8842.c
+++ b/drivers/net/ks8842.c
@@ -18,6 +18,7 @@
/* Supports:
* The Micrel KS8842 behind the timberdale FPGA
+ * The genuine Micrel KS8841/42 device with ISA 16/32bit bus interface
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
@@ -29,11 +30,19 @@
#include <linux/etherdevice.h>
#include <linux/ethtool.h>
#include <linux/ks8842.h>
+#include <linux/dmaengine.h>
+#include <linux/dma-mapping.h>
+#include <linux/scatterlist.h>
#define DRV_NAME "ks8842"
/* Timberdale specific Registers */
-#define REG_TIMB_RST 0x1c
+#define REG_TIMB_RST 0x1c
+#define REG_TIMB_FIFO 0x20
+#define REG_TIMB_ISR 0x24
+#define REG_TIMB_IER 0x28
+#define REG_TIMB_IAR 0x2C
+#define REQ_TIMB_DMA_RESUME 0x30
/* KS8842 registers */
@@ -76,6 +85,15 @@
#define IRQ_RX_ERROR 0x0080
#define ENABLED_IRQS (IRQ_LINK_CHANGE | IRQ_TX | IRQ_RX | IRQ_RX_STOPPED | \
IRQ_TX_STOPPED | IRQ_RX_OVERRUN | IRQ_RX_ERROR)
+/* When running via timberdale in DMA mode, the RX interrupt should be
+ enabled in the KS8842, but not in the FPGA IP, since the IP handles
+ RX DMA internally.
+ TX interrupts are not needed it is handled by the FPGA the driver is
+ notified via DMA callbacks.
+*/
+#define ENABLED_IRQS_DMA_IP (IRQ_LINK_CHANGE | IRQ_RX_STOPPED | \
+ IRQ_TX_STOPPED | IRQ_RX_OVERRUN | IRQ_RX_ERROR)
+#define ENABLED_IRQS_DMA (ENABLED_IRQS_DMA_IP | IRQ_RX)
#define REG_ISR 0x02
#define REG_RXSR 0x04
#define RXSR_VALID 0x8000
@@ -114,14 +132,53 @@
#define REG_P1CR4 0x02
#define REG_P1SR 0x04
+/* flags passed by platform_device for configuration */
+#define MICREL_KS884X 0x01 /* 0=Timeberdale(FPGA), 1=Micrel */
+#define KS884X_16BIT 0x02 /* 1=16bit, 0=32bit */
+
+#define DMA_BUFFER_SIZE 2048
+
+struct ks8842_tx_dma_ctl {
+ struct dma_chan *chan;
+ struct dma_async_tx_descriptor *adesc;
+ void *buf;
+ struct scatterlist sg;
+ int channel;
+};
+
+struct ks8842_rx_dma_ctl {
+ struct dma_chan *chan;
+ struct dma_async_tx_descriptor *adesc;
+ struct sk_buff *skb;
+ struct scatterlist sg;
+ struct tasklet_struct tasklet;
+ int channel;
+};
+
+#define KS8842_USE_DMA(adapter) (((adapter)->dma_tx.channel != -1) && \
+ ((adapter)->dma_rx.channel != -1))
+
struct ks8842_adapter {
void __iomem *hw_addr;
int irq;
+ unsigned long conf_flags; /* copy of platform_device config */
struct tasklet_struct tasklet;
spinlock_t lock; /* spinlock to be interrupt safe */
- struct platform_device *pdev;
+ struct work_struct timeout_work;
+ struct net_device *netdev;
+ struct device *dev;
+ struct ks8842_tx_dma_ctl dma_tx;
+ struct ks8842_rx_dma_ctl dma_rx;
};
+static void ks8842_dma_rx_cb(void *data);
+static void ks8842_dma_tx_cb(void *data);
+
+static inline void ks8842_resume_dma(struct ks8842_adapter *adapter)
+{
+ iowrite32(1, adapter->hw_addr + REQ_TIMB_DMA_RESUME);
+}
+
static inline void ks8842_select_bank(struct ks8842_adapter *adapter, u16 bank)
{
iowrite16(bank, adapter->hw_addr + REG_SELECT_BANK);
@@ -191,16 +248,21 @@ static inline u32 ks8842_read32(struct ks8842_adapter *adapter, u16 bank,
static void ks8842_reset(struct ks8842_adapter *adapter)
{
- /* The KS8842 goes haywire when doing softare reset
- * a work around in the timberdale IP is implemented to
- * do a hardware reset instead
- ks8842_write16(adapter, 3, 1, REG_GRR);
- msleep(10);
- iowrite16(0, adapter->hw_addr + REG_GRR);
- */
- iowrite16(32, adapter->hw_addr + REG_SELECT_BANK);
- iowrite32(0x1, adapter->hw_addr + REG_TIMB_RST);
- msleep(20);
+ if (adapter->conf_flags & MICREL_KS884X) {
+ ks8842_write16(adapter, 3, 1, REG_GRR);
+ msleep(10);
+ iowrite16(0, adapter->hw_addr + REG_GRR);
+ } else {
+ /* The KS8842 goes haywire when doing softare reset
+ * a work around in the timberdale IP is implemented to
+ * do a hardware reset instead
+ ks8842_write16(adapter, 3, 1, REG_GRR);
+ msleep(10);
+ iowrite16(0, adapter->hw_addr + REG_GRR);
+ */
+ iowrite32(0x1, adapter->hw_addr + REG_TIMB_RST);
+ msleep(20);
+ }
}
static void ks8842_update_link_status(struct net_device *netdev,
@@ -269,8 +331,6 @@ static void ks8842_reset_hw(struct ks8842_adapter *adapter)
/* restart port auto-negotiation */
ks8842_enable_bits(adapter, 49, 1 << 13, REG_P1CR4);
- /* only advertise 10Mbps */
- ks8842_clear_bits(adapter, 49, 3 << 2, REG_P1CR4);
/* Enable the transmitter */
ks8842_enable_tx(adapter);
@@ -282,8 +342,19 @@ static void ks8842_reset_hw(struct ks8842_adapter *adapter)
ks8842_write16(adapter, 18, 0xffff, REG_ISR);
/* enable interrupts */
- ks8842_write16(adapter, 18, ENABLED_IRQS, REG_IER);
-
+ if (KS8842_USE_DMA(adapter)) {
+ /* When running in DMA Mode the RX interrupt is not enabled in
+ timberdale because RX data is received by DMA callbacks
+ it must still be enabled in the KS8842 because it indicates
+ to timberdale when there is RX data for it's DMA FIFOs */
+ iowrite16(ENABLED_IRQS_DMA_IP, adapter->hw_addr + REG_TIMB_IER);
+ ks8842_write16(adapter, 18, ENABLED_IRQS_DMA, REG_IER);
+ } else {
+ if (!(adapter->conf_flags & MICREL_KS884X))
+ iowrite16(ENABLED_IRQS,
+ adapter->hw_addr + REG_TIMB_IER);
+ ks8842_write16(adapter, 18, ENABLED_IRQS, REG_IER);
+ }
/* enable the switch */
ks8842_write16(adapter, 32, 0x1, REG_SW_ID_AND_ENABLE);
}
@@ -296,13 +367,28 @@ static void ks8842_read_mac_addr(struct ks8842_adapter *adapter, u8 *dest)
for (i = 0; i < ETH_ALEN; i++)
dest[ETH_ALEN - i - 1] = ks8842_read8(adapter, 2, REG_MARL + i);
- /* make sure the switch port uses the same MAC as the QMU */
- mac = ks8842_read16(adapter, 2, REG_MARL);
- ks8842_write16(adapter, 39, mac, REG_MACAR1);
- mac = ks8842_read16(adapter, 2, REG_MARM);
- ks8842_write16(adapter, 39, mac, REG_MACAR2);
- mac = ks8842_read16(adapter, 2, REG_MARH);
- ks8842_write16(adapter, 39, mac, REG_MACAR3);
+ if (adapter->conf_flags & MICREL_KS884X) {
+ /*
+ the sequence of saving mac addr between MAC and Switch is
+ different.
+ */
+
+ mac = ks8842_read16(adapter, 2, REG_MARL);
+ ks8842_write16(adapter, 39, mac, REG_MACAR3);
+ mac = ks8842_read16(adapter, 2, REG_MARM);
+ ks8842_write16(adapter, 39, mac, REG_MACAR2);
+ mac = ks8842_read16(adapter, 2, REG_MARH);
+ ks8842_write16(adapter, 39, mac, REG_MACAR1);
+ } else {
+
+ /* make sure the switch port uses the same MAC as the QMU */
+ mac = ks8842_read16(adapter, 2, REG_MARL);
+ ks8842_write16(adapter, 39, mac, REG_MACAR1);
+ mac = ks8842_read16(adapter, 2, REG_MARM);
+ ks8842_write16(adapter, 39, mac, REG_MACAR2);
+ mac = ks8842_read16(adapter, 2, REG_MARH);
+ ks8842_write16(adapter, 39, mac, REG_MACAR3);
+ }
}
static void ks8842_write_mac_addr(struct ks8842_adapter *adapter, u8 *mac)
@@ -313,8 +399,25 @@ static void ks8842_write_mac_addr(struct ks8842_adapter *adapter, u8 *mac)
spin_lock_irqsave(&adapter->lock, flags);
for (i = 0; i < ETH_ALEN; i++) {
ks8842_write8(adapter, 2, mac[ETH_ALEN - i - 1], REG_MARL + i);
- ks8842_write8(adapter, 39, mac[ETH_ALEN - i - 1],
- REG_MACAR1 + i);
+ if (!(adapter->conf_flags & MICREL_KS884X))
+ ks8842_write8(adapter, 39, mac[ETH_ALEN - i - 1],
+ REG_MACAR1 + i);
+ }
+
+ if (adapter->conf_flags & MICREL_KS884X) {
+ /*
+ the sequence of saving mac addr between MAC and Switch is
+ different.
+ */
+
+ u16 mac;
+
+ mac = ks8842_read16(adapter, 2, REG_MARL);
+ ks8842_write16(adapter, 39, mac, REG_MACAR3);
+ mac = ks8842_read16(adapter, 2, REG_MARM);
+ ks8842_write16(adapter, 39, mac, REG_MACAR2);
+ mac = ks8842_read16(adapter, 2, REG_MARH);
+ ks8842_write16(adapter, 39, mac, REG_MACAR1);
}
spin_unlock_irqrestore(&adapter->lock, flags);
}
@@ -324,15 +427,59 @@ static inline u16 ks8842_tx_fifo_space(struct ks8842_adapter *adapter)
return ks8842_read16(adapter, 16, REG_TXMIR) & 0x1fff;
}
+static int ks8842_tx_frame_dma(struct sk_buff *skb, struct net_device *netdev)
+{
+ struct ks8842_adapter *adapter = netdev_priv(netdev);
+ struct ks8842_tx_dma_ctl *ctl = &adapter->dma_tx;
+ u8 *buf = ctl->buf;
+
+ if (ctl->adesc) {
+ netdev_dbg(netdev, "%s: TX ongoing\n", __func__);
+ /* transfer ongoing */
+ return NETDEV_TX_BUSY;
+ }
+
+ sg_dma_len(&ctl->sg) = skb->len + sizeof(u32);
+
+ /* copy data to the TX buffer */
+ /* the control word, enable IRQ, port 1 and the length */
+ *buf++ = 0x00;
+ *buf++ = 0x01; /* Port 1 */
+ *buf++ = skb->len & 0xff;
+ *buf++ = (skb->len >> 8) & 0xff;
+ skb_copy_from_linear_data(skb, buf, skb->len);
+
+ dma_sync_single_range_for_device(adapter->dev,
+ sg_dma_address(&ctl->sg), 0, sg_dma_len(&ctl->sg),
+ DMA_TO_DEVICE);
+
+ /* make sure the length is a multiple of 4 */
+ if (sg_dma_len(&ctl->sg) % 4)
+ sg_dma_len(&ctl->sg) += 4 - sg_dma_len(&ctl->sg) % 4;
+
+ ctl->adesc = ctl->chan->device->device_prep_slave_sg(ctl->chan,
+ &ctl->sg, 1, DMA_TO_DEVICE,
+ DMA_PREP_INTERRUPT | DMA_COMPL_SKIP_SRC_UNMAP);
+ if (!ctl->adesc)
+ return NETDEV_TX_BUSY;
+
+ ctl->adesc->callback_param = netdev;
+ ctl->adesc->callback = ks8842_dma_tx_cb;
+ ctl->adesc->tx_submit(ctl->adesc);
+
+ netdev->stats.tx_bytes += skb->len;
+
+ dev_kfree_skb(skb);
+
+ return NETDEV_TX_OK;
+}
+
static int ks8842_tx_frame(struct sk_buff *skb, struct net_device *netdev)
{
struct ks8842_adapter *adapter = netdev_priv(netdev);
int len = skb->len;
- u32 *ptr = (u32 *)skb->data;
- u32 ctrl;
- dev_dbg(&adapter->pdev->dev,
- "%s: len %u head %p data %p tail %p end %p\n",
+ netdev_dbg(netdev, "%s: len %u head %p data %p tail %p end %p\n",
__func__, skb->len, skb->head, skb->data,
skb_tail_pointer(skb), skb_end_pointer(skb));
@@ -340,17 +487,34 @@ static int ks8842_tx_frame(struct sk_buff *skb, struct net_device *netdev)
if (ks8842_tx_fifo_space(adapter) < len + 8)
return NETDEV_TX_BUSY;
- /* the control word, enable IRQ, port 1 and the length */
- ctrl = 0x8000 | 0x100 | (len << 16);
- ks8842_write32(adapter, 17, ctrl, REG_QMU_DATA_LO);
+ if (adapter->conf_flags & KS884X_16BIT) {
+ u16 *ptr16 = (u16 *)skb->data;
+ ks8842_write16(adapter, 17, 0x8000 | 0x100, REG_QMU_DATA_LO);
+ ks8842_write16(adapter, 17, (u16)len, REG_QMU_DATA_HI);
+ netdev->stats.tx_bytes += len;
+
+ /* copy buffer */
+ while (len > 0) {
+ iowrite16(*ptr16++, adapter->hw_addr + REG_QMU_DATA_LO);
+ iowrite16(*ptr16++, adapter->hw_addr + REG_QMU_DATA_HI);
+ len -= sizeof(u32);
+ }
+ } else {
- netdev->stats.tx_bytes += len;
+ u32 *ptr = (u32 *)skb->data;
+ u32 ctrl;
+ /* the control word, enable IRQ, port 1 and the length */
+ ctrl = 0x8000 | 0x100 | (len << 16);
+ ks8842_write32(adapter, 17, ctrl, REG_QMU_DATA_LO);
- /* copy buffer */
- while (len > 0) {
- iowrite32(*ptr, adapter->hw_addr + REG_QMU_DATA_LO);
- len -= sizeof(u32);
- ptr++;
+ netdev->stats.tx_bytes += len;
+
+ /* copy buffer */
+ while (len > 0) {
+ iowrite32(*ptr, adapter->hw_addr + REG_QMU_DATA_LO);
+ len -= sizeof(u32);
+ ptr++;
+ }
}
/* enqueue packet */
@@ -361,54 +525,174 @@ static int ks8842_tx_frame(struct sk_buff *skb, struct net_device *netdev)
return NETDEV_TX_OK;
}
-static void ks8842_rx_frame(struct net_device *netdev,
- struct ks8842_adapter *adapter)
+static void ks8842_update_rx_err_counters(struct net_device *netdev, u32 status)
+{
+ netdev_dbg(netdev, "RX error, status: %x\n", status);
+
+ netdev->stats.rx_errors++;
+ if (status & RXSR_TOO_LONG)
+ netdev->stats.rx_length_errors++;
+ if (status & RXSR_CRC_ERROR)
+ netdev->stats.rx_crc_errors++;
+ if (status & RXSR_RUNT)
+ netdev->stats.rx_frame_errors++;
+}
+
+static void ks8842_update_rx_counters(struct net_device *netdev, u32 status,
+ int len)
+{
+ netdev_dbg(netdev, "RX packet, len: %d\n", len);
+
+ netdev->stats.rx_packets++;
+ netdev->stats.rx_bytes += len;
+ if (status & RXSR_MULTICAST)
+ netdev->stats.multicast++;
+}
+
+static int __ks8842_start_new_rx_dma(struct net_device *netdev)
{
- u32 status = ks8842_read32(adapter, 17, REG_QMU_DATA_LO);
- int len = (status >> 16) & 0x7ff;
+ struct ks8842_adapter *adapter = netdev_priv(netdev);
+ struct ks8842_rx_dma_ctl *ctl = &adapter->dma_rx;
+ struct scatterlist *sg = &ctl->sg;
+ int err;
- status &= 0xffff;
+ ctl->skb = netdev_alloc_skb(netdev, DMA_BUFFER_SIZE);
+ if (ctl->skb) {
+ sg_init_table(sg, 1);
+ sg_dma_address(sg) = dma_map_single(adapter->dev,
+ ctl->skb->data, DMA_BUFFER_SIZE, DMA_FROM_DEVICE);
+ err = dma_mapping_error(adapter->dev, sg_dma_address(sg));
+ if (unlikely(err)) {
+ sg_dma_address(sg) = 0;
+ goto out;
+ }
+
+ sg_dma_len(sg) = DMA_BUFFER_SIZE;
+
+ ctl->adesc = ctl->chan->device->device_prep_slave_sg(ctl->chan,
+ sg, 1, DMA_FROM_DEVICE,
+ DMA_PREP_INTERRUPT | DMA_COMPL_SKIP_SRC_UNMAP);
+
+ if (!ctl->adesc)
+ goto out;
+
+ ctl->adesc->callback_param = netdev;
+ ctl->adesc->callback = ks8842_dma_rx_cb;
+ ctl->adesc->tx_submit(ctl->adesc);
+ } else {
+ err = -ENOMEM;
+ sg_dma_address(sg) = 0;
+ goto out;
+ }
- dev_dbg(&adapter->pdev->dev, "%s - rx_data: status: %x\n",
- __func__, status);
+ return err;
+out:
+ if (sg_dma_address(sg))
+ dma_unmap_single(adapter->dev, sg_dma_address(sg),
+ DMA_BUFFER_SIZE, DMA_FROM_DEVICE);
+ sg_dma_address(sg) = 0;
+ if (ctl->skb)
+ dev_kfree_skb(ctl->skb);
+
+ ctl->skb = NULL;
+
+ printk(KERN_ERR DRV_NAME": Failed to start RX DMA: %d\n", err);
+ return err;
+}
+
+static void ks8842_rx_frame_dma_tasklet(unsigned long arg)
+{
+ struct net_device *netdev = (struct net_device *)arg;
+ struct ks8842_adapter *adapter = netdev_priv(netdev);
+ struct ks8842_rx_dma_ctl *ctl = &adapter->dma_rx;
+ struct sk_buff *skb = ctl->skb;
+ dma_addr_t addr = sg_dma_address(&ctl->sg);
+ u32 status;
+
+ ctl->adesc = NULL;
+
+ /* kick next transfer going */
+ __ks8842_start_new_rx_dma(netdev);
+
+ /* now handle the data we got */
+ dma_unmap_single(adapter->dev, addr, DMA_BUFFER_SIZE, DMA_FROM_DEVICE);
+
+ status = *((u32 *)skb->data);
+
+ netdev_dbg(netdev, "%s - rx_data: status: %x\n",
+ __func__, status & 0xffff);
/* check the status */
if ((status & RXSR_VALID) && !(status & RXSR_ERROR)) {
- struct sk_buff *skb = netdev_alloc_skb_ip_align(netdev, len);
+ int len = (status >> 16) & 0x7ff;
- dev_dbg(&adapter->pdev->dev, "%s, got package, len: %d\n",
- __func__, len);
- if (skb) {
- u32 *data;
+ ks8842_update_rx_counters(netdev, status, len);
- netdev->stats.rx_packets++;
- netdev->stats.rx_bytes += len;
- if (status & RXSR_MULTICAST)
- netdev->stats.multicast++;
+ /* reserve 4 bytes which is the status word */
+ skb_reserve(skb, 4);
+ skb_put(skb, len);
- data = (u32 *)skb_put(skb, len);
+ skb->protocol = eth_type_trans(skb, netdev);
+ netif_rx(skb);
+ } else {
+ ks8842_update_rx_err_counters(netdev, status);
+ dev_kfree_skb(skb);
+ }
+}
- ks8842_select_bank(adapter, 17);
- while (len > 0) {
- *data++ = ioread32(adapter->hw_addr +
- REG_QMU_DATA_LO);
- len -= sizeof(u32);
- }
+static void ks8842_rx_frame(struct net_device *netdev,
+ struct ks8842_adapter *adapter)
+{
+ u32 status;
+ int len;
+
+ if (adapter->conf_flags & KS884X_16BIT) {
+ status = ks8842_read16(adapter, 17, REG_QMU_DATA_LO);
+ len = ks8842_read16(adapter, 17, REG_QMU_DATA_HI);
+ netdev_dbg(netdev, "%s - rx_data: status: %x\n",
+ __func__, status);
+ } else {
+ status = ks8842_read32(adapter, 17, REG_QMU_DATA_LO);
+ len = (status >> 16) & 0x7ff;
+ status &= 0xffff;
+ netdev_dbg(netdev, "%s - rx_data: status: %x\n",
+ __func__, status);
+ }
+ /* check the status */
+ if ((status & RXSR_VALID) && !(status & RXSR_ERROR)) {
+ struct sk_buff *skb = netdev_alloc_skb_ip_align(netdev, len);
+
+ if (skb) {
+
+ ks8842_update_rx_counters(netdev, status, len);
+
+ if (adapter->conf_flags & KS884X_16BIT) {
+ u16 *data16 = (u16 *)skb_put(skb, len);
+ ks8842_select_bank(adapter, 17);
+ while (len > 0) {
+ *data16++ = ioread16(adapter->hw_addr +
+ REG_QMU_DATA_LO);
+ *data16++ = ioread16(adapter->hw_addr +
+ REG_QMU_DATA_HI);
+ len -= sizeof(u32);
+ }
+ } else {
+ u32 *data = (u32 *)skb_put(skb, len);
+
+ ks8842_select_bank(adapter, 17);
+ while (len > 0) {
+ *data++ = ioread32(adapter->hw_addr +
+ REG_QMU_DATA_LO);
+ len -= sizeof(u32);
+ }
+ }
skb->protocol = eth_type_trans(skb, netdev);
netif_rx(skb);
} else
netdev->stats.rx_dropped++;
- } else {
- dev_dbg(&adapter->pdev->dev, "RX error, status: %x\n", status);
- netdev->stats.rx_errors++;
- if (status & RXSR_TOO_LONG)
- netdev->stats.rx_length_errors++;
- if (status & RXSR_CRC_ERROR)
- netdev->stats.rx_crc_errors++;
- if (status & RXSR_RUNT)
- netdev->stats.rx_frame_errors++;
- }
+ } else
+ ks8842_update_rx_err_counters(netdev, status);
/* set high watermark to 3K */
ks8842_clear_bits(adapter, 0, 1 << 12, REG_QRFCR);
@@ -423,8 +707,7 @@ static void ks8842_rx_frame(struct net_device *netdev,
void ks8842_handle_rx(struct net_device *netdev, struct ks8842_adapter *adapter)
{
u16 rx_data = ks8842_read16(adapter, 16, REG_RXMIR) & 0x1fff;
- dev_dbg(&adapter->pdev->dev, "%s Entry - rx_data: %d\n",
- __func__, rx_data);
+ netdev_dbg(netdev, "%s Entry - rx_data: %d\n", __func__, rx_data);
while (rx_data) {
ks8842_rx_frame(netdev, adapter);
rx_data = ks8842_read16(adapter, 16, REG_RXMIR) & 0x1fff;
@@ -434,7 +717,7 @@ void ks8842_handle_rx(struct net_device *netdev, struct ks8842_adapter *adapter)
void ks8842_handle_tx(struct net_device *netdev, struct ks8842_adapter *adapter)
{
u16 sr = ks8842_read16(adapter, 16, REG_TXSR);
- dev_dbg(&adapter->pdev->dev, "%s - entry, sr: %x\n", __func__, sr);
+ netdev_dbg(netdev, "%s - entry, sr: %x\n", __func__, sr);
netdev->stats.tx_packets++;
if (netif_queue_stopped(netdev))
netif_wake_queue(netdev);
@@ -443,7 +726,7 @@ void ks8842_handle_tx(struct net_device *netdev, struct ks8842_adapter *adapter)
void ks8842_handle_rx_overrun(struct net_device *netdev,
struct ks8842_adapter *adapter)
{
- dev_dbg(&adapter->pdev->dev, "%s: entry\n", __func__);
+ netdev_dbg(netdev, "%s: entry\n", __func__);
netdev->stats.rx_errors++;
netdev->stats.rx_fifo_errors++;
}
@@ -462,20 +745,32 @@ void ks8842_tasklet(unsigned long arg)
spin_unlock_irqrestore(&adapter->lock, flags);
isr = ks8842_read16(adapter, 18, REG_ISR);
- dev_dbg(&adapter->pdev->dev, "%s - ISR: 0x%x\n", __func__, isr);
+ netdev_dbg(netdev, "%s - ISR: 0x%x\n", __func__, isr);
+
+ /* when running in DMA mode, do not ack RX interrupts, it is handled
+ internally by timberdale, otherwise it's DMA FIFO:s would stop
+ */
+ if (KS8842_USE_DMA(adapter))
+ isr &= ~IRQ_RX;
/* Ack */
ks8842_write16(adapter, 18, isr, REG_ISR);
+ if (!(adapter->conf_flags & MICREL_KS884X))
+ /* Ack in the timberdale IP as well */
+ iowrite32(0x1, adapter->hw_addr + REG_TIMB_IAR);
+
if (!netif_running(netdev))
return;
if (isr & IRQ_LINK_CHANGE)
ks8842_update_link_status(netdev, adapter);
- if (isr & (IRQ_RX | IRQ_RX_ERROR))
+ /* should not get IRQ_RX when running DMA mode */
+ if (isr & (IRQ_RX | IRQ_RX_ERROR) && !KS8842_USE_DMA(adapter))
ks8842_handle_rx(netdev, adapter);
+ /* should only happen when in PIO mode */
if (isr & IRQ_TX)
ks8842_handle_tx(netdev, adapter);
@@ -494,24 +789,38 @@ void ks8842_tasklet(unsigned long arg)
/* re-enable interrupts, put back the bank selection register */
spin_lock_irqsave(&adapter->lock, flags);
- ks8842_write16(adapter, 18, ENABLED_IRQS, REG_IER);
+ if (KS8842_USE_DMA(adapter))
+ ks8842_write16(adapter, 18, ENABLED_IRQS_DMA, REG_IER);
+ else
+ ks8842_write16(adapter, 18, ENABLED_IRQS, REG_IER);
iowrite16(entry_bank, adapter->hw_addr + REG_SELECT_BANK);
+
+ /* Make sure timberdale continues DMA operations, they are stopped while
+ we are handling the ks8842 because we might change bank */
+ if (KS8842_USE_DMA(adapter))
+ ks8842_resume_dma(adapter);
+
spin_unlock_irqrestore(&adapter->lock, flags);
}
static irqreturn_t ks8842_irq(int irq, void *devid)
{
- struct ks8842_adapter *adapter = devid;
+ struct net_device *netdev = devid;
+ struct ks8842_adapter *adapter = netdev_priv(netdev);
u16 isr;
u16 entry_bank = ioread16(adapter->hw_addr + REG_SELECT_BANK);
irqreturn_t ret = IRQ_NONE;
isr = ks8842_read16(adapter, 18, REG_ISR);
- dev_dbg(&adapter->pdev->dev, "%s - ISR: 0x%x\n", __func__, isr);
+ netdev_dbg(netdev, "%s - ISR: 0x%x\n", __func__, isr);
if (isr) {
- /* disable IRQ */
- ks8842_write16(adapter, 18, 0x00, REG_IER);
+ if (KS8842_USE_DMA(adapter))
+ /* disable all but RX IRQ, since the FPGA relies on it*/
+ ks8842_write16(adapter, 18, IRQ_RX, REG_IER);
+ else
+ /* disable IRQ */
+ ks8842_write16(adapter, 18, 0x00, REG_IER);
/* schedule tasklet */
tasklet_schedule(&adapter->tasklet);
@@ -521,9 +830,151 @@ static irqreturn_t ks8842_irq(int irq, void *devid)
iowrite16(entry_bank, adapter->hw_addr + REG_SELECT_BANK);
+ /* After an interrupt, tell timberdale to continue DMA operations.
+ DMA is disabled while we are handling the ks8842 because we might
+ change bank */
+ ks8842_resume_dma(adapter);
+
return ret;
}
+static void ks8842_dma_rx_cb(void *data)
+{
+ struct net_device *netdev = data;
+ struct ks8842_adapter *adapter = netdev_priv(netdev);
+
+ netdev_dbg(netdev, "RX DMA finished\n");
+ /* schedule tasklet */
+ if (adapter->dma_rx.adesc)
+ tasklet_schedule(&adapter->dma_rx.tasklet);
+}
+
+static void ks8842_dma_tx_cb(void *data)
+{
+ struct net_device *netdev = data;
+ struct ks8842_adapter *adapter = netdev_priv(netdev);
+ struct ks8842_tx_dma_ctl *ctl = &adapter->dma_tx;
+
+ netdev_dbg(netdev, "TX DMA finished\n");
+
+ if (!ctl->adesc)
+ return;
+
+ netdev->stats.tx_packets++;
+ ctl->adesc = NULL;
+
+ if (netif_queue_stopped(netdev))
+ netif_wake_queue(netdev);
+}
+
+static void ks8842_stop_dma(struct ks8842_adapter *adapter)
+{
+ struct ks8842_tx_dma_ctl *tx_ctl = &adapter->dma_tx;
+ struct ks8842_rx_dma_ctl *rx_ctl = &adapter->dma_rx;
+
+ tx_ctl->adesc = NULL;
+ if (tx_ctl->chan)
+ tx_ctl->chan->device->device_control(tx_ctl->chan,
+ DMA_TERMINATE_ALL, 0);
+
+ rx_ctl->adesc = NULL;
+ if (rx_ctl->chan)
+ rx_ctl->chan->device->device_control(rx_ctl->chan,
+ DMA_TERMINATE_ALL, 0);
+
+ if (sg_dma_address(&rx_ctl->sg))
+ dma_unmap_single(adapter->dev, sg_dma_address(&rx_ctl->sg),
+ DMA_BUFFER_SIZE, DMA_FROM_DEVICE);
+ sg_dma_address(&rx_ctl->sg) = 0;
+
+ dev_kfree_skb(rx_ctl->skb);
+ rx_ctl->skb = NULL;
+}
+
+static void ks8842_dealloc_dma_bufs(struct ks8842_adapter *adapter)
+{
+ struct ks8842_tx_dma_ctl *tx_ctl = &adapter->dma_tx;
+ struct ks8842_rx_dma_ctl *rx_ctl = &adapter->dma_rx;
+
+ ks8842_stop_dma(adapter);
+
+ if (tx_ctl->chan)
+ dma_release_channel(tx_ctl->chan);
+ tx_ctl->chan = NULL;
+
+ if (rx_ctl->chan)
+ dma_release_channel(rx_ctl->chan);
+ rx_ctl->chan = NULL;
+
+ tasklet_kill(&rx_ctl->tasklet);
+
+ if (sg_dma_address(&tx_ctl->sg))
+ dma_unmap_single(adapter->dev, sg_dma_address(&tx_ctl->sg),
+ DMA_BUFFER_SIZE, DMA_TO_DEVICE);
+ sg_dma_address(&tx_ctl->sg) = 0;
+
+ kfree(tx_ctl->buf);
+ tx_ctl->buf = NULL;
+}
+
+static bool ks8842_dma_filter_fn(struct dma_chan *chan, void *filter_param)
+{
+ return chan->chan_id == (long)filter_param;
+}
+
+static int ks8842_alloc_dma_bufs(struct net_device *netdev)
+{
+ struct ks8842_adapter *adapter = netdev_priv(netdev);
+ struct ks8842_tx_dma_ctl *tx_ctl = &adapter->dma_tx;
+ struct ks8842_rx_dma_ctl *rx_ctl = &adapter->dma_rx;
+ int err;
+
+ dma_cap_mask_t mask;
+
+ dma_cap_zero(mask);
+ dma_cap_set(DMA_SLAVE, mask);
+ dma_cap_set(DMA_PRIVATE, mask);
+
+ sg_init_table(&tx_ctl->sg, 1);
+
+ tx_ctl->chan = dma_request_channel(mask, ks8842_dma_filter_fn,
+ (void *)(long)tx_ctl->channel);
+ if (!tx_ctl->chan) {
+ err = -ENODEV;
+ goto err;
+ }
+
+ /* allocate DMA buffer */
+ tx_ctl->buf = kmalloc(DMA_BUFFER_SIZE, GFP_KERNEL);
+ if (!tx_ctl->buf) {
+ err = -ENOMEM;
+ goto err;
+ }
+
+ sg_dma_address(&tx_ctl->sg) = dma_map_single(adapter->dev,
+ tx_ctl->buf, DMA_BUFFER_SIZE, DMA_TO_DEVICE);
+ err = dma_mapping_error(adapter->dev,
+ sg_dma_address(&tx_ctl->sg));
+ if (err) {
+ sg_dma_address(&tx_ctl->sg) = 0;
+ goto err;
+ }
+
+ rx_ctl->chan = dma_request_channel(mask, ks8842_dma_filter_fn,
+ (void *)(long)rx_ctl->channel);
+ if (!rx_ctl->chan) {
+ err = -ENODEV;
+ goto err;
+ }
+
+ tasklet_init(&rx_ctl->tasklet, ks8842_rx_frame_dma_tasklet,
+ (unsigned long)netdev);
+
+ return 0;
+err:
+ ks8842_dealloc_dma_bufs(adapter);
+ return err;
+}
/* Netdevice operations */
@@ -532,7 +983,26 @@ static int ks8842_open(struct net_device *netdev)
struct ks8842_adapter *adapter = netdev_priv(netdev);
int err;
- dev_dbg(&adapter->pdev->dev, "%s - entry\n", __func__);
+ netdev_dbg(netdev, "%s - entry\n", __func__);
+
+ if (KS8842_USE_DMA(adapter)) {
+ err = ks8842_alloc_dma_bufs(netdev);
+
+ if (!err) {
+ /* start RX dma */
+ err = __ks8842_start_new_rx_dma(netdev);
+ if (err)
+ ks8842_dealloc_dma_bufs(adapter);
+ }
+
+ if (err) {
+ printk(KERN_WARNING DRV_NAME
+ ": Failed to initiate DMA, running PIO\n");
+ ks8842_dealloc_dma_bufs(adapter);
+ adapter->dma_rx.channel = -1;
+ adapter->dma_tx.channel = -1;
+ }
+ }
/* reset the HW */
ks8842_reset_hw(adapter);
@@ -542,7 +1012,7 @@ static int ks8842_open(struct net_device *netdev)
ks8842_update_link_status(netdev, adapter);
err = request_irq(adapter->irq, ks8842_irq, IRQF_SHARED, DRV_NAME,
- adapter);
+ netdev);
if (err) {
pr_err("Failed to request IRQ: %d: %d\n", adapter->irq, err);
return err;
@@ -555,10 +1025,15 @@ static int ks8842_close(struct net_device *netdev)
{
struct ks8842_adapter *adapter = netdev_priv(netdev);
- dev_dbg(&adapter->pdev->dev, "%s - entry\n", __func__);
+ netdev_dbg(netdev, "%s - entry\n", __func__);
+
+ cancel_work_sync(&adapter->timeout_work);
+
+ if (KS8842_USE_DMA(adapter))
+ ks8842_dealloc_dma_bufs(adapter);
/* free the irq */
- free_irq(adapter->irq, adapter);
+ free_irq(adapter->irq, netdev);
/* disable the switch */
ks8842_write16(adapter, 32, 0x0, REG_SW_ID_AND_ENABLE);
@@ -572,7 +1047,18 @@ static netdev_tx_t ks8842_xmit_frame(struct sk_buff *skb,
int ret;
struct ks8842_adapter *adapter = netdev_priv(netdev);
- dev_dbg(&adapter->pdev->dev, "%s: entry\n", __func__);
+ netdev_dbg(netdev, "%s: entry\n", __func__);
+
+ if (KS8842_USE_DMA(adapter)) {
+ unsigned long flags;
+ ret = ks8842_tx_frame_dma(skb, netdev);
+ /* for now only allow one transfer at the time */
+ spin_lock_irqsave(&adapter->lock, flags);
+ if (adapter->dma_tx.adesc)
+ netif_stop_queue(netdev);
+ spin_unlock_irqrestore(&adapter->lock, flags);
+ return ret;
+ }
ret = ks8842_tx_frame(skb, netdev);
@@ -588,7 +1074,7 @@ static int ks8842_set_mac(struct net_device *netdev, void *p)
struct sockaddr *addr = p;
char *mac = (u8 *)addr->sa_data;
- dev_dbg(&adapter->pdev->dev, "%s: entry\n", __func__);
+ netdev_dbg(netdev, "%s: entry\n", __func__);
if (!is_valid_ether_addr(addr->sa_data))
return -EADDRNOTAVAIL;
@@ -599,17 +1085,26 @@ static int ks8842_set_mac(struct net_device *netdev, void *p)
return 0;
}
-static void ks8842_tx_timeout(struct net_device *netdev)
+static void ks8842_tx_timeout_work(struct work_struct *work)
{
- struct ks8842_adapter *adapter = netdev_priv(netdev);
+ struct ks8842_adapter *adapter =
+ container_of(work, struct ks8842_adapter, timeout_work);
+ struct net_device *netdev = adapter->netdev;
unsigned long flags;
- dev_dbg(&adapter->pdev->dev, "%s: entry\n", __func__);
+ netdev_dbg(netdev, "%s: entry\n", __func__);
spin_lock_irqsave(&adapter->lock, flags);
+
+ if (KS8842_USE_DMA(adapter))
+ ks8842_stop_dma(adapter);
+
/* disable interrupts */
ks8842_write16(adapter, 18, 0, REG_IER);
ks8842_write16(adapter, 18, 0xFFFF, REG_ISR);
+
+ netif_stop_queue(netdev);
+
spin_unlock_irqrestore(&adapter->lock, flags);
ks8842_reset_hw(adapter);
@@ -617,6 +1112,18 @@ static void ks8842_tx_timeout(struct net_device *netdev)
ks8842_write_mac_addr(adapter, netdev->dev_addr);
ks8842_update_link_status(netdev, adapter);
+
+ if (KS8842_USE_DMA(adapter))
+ __ks8842_start_new_rx_dma(netdev);
+}
+
+static void ks8842_tx_timeout(struct net_device *netdev)
+{
+ struct ks8842_adapter *adapter = netdev_priv(netdev);
+
+ netdev_dbg(netdev, "%s: entry\n", __func__);
+
+ schedule_work(&adapter->timeout_work);
}
static const struct net_device_ops ks8842_netdev_ops = {
@@ -653,7 +1160,11 @@ static int __devinit ks8842_probe(struct platform_device *pdev)
SET_NETDEV_DEV(netdev, &pdev->dev);
adapter = netdev_priv(netdev);
+ adapter->netdev = netdev;
+ INIT_WORK(&adapter->timeout_work, ks8842_tx_timeout_work);
adapter->hw_addr = ioremap(iomem->start, resource_size(iomem));
+ adapter->conf_flags = iomem->flags;
+
if (!adapter->hw_addr)
goto err_ioremap;
@@ -663,7 +1174,18 @@ static int __devinit ks8842_probe(struct platform_device *pdev)
goto err_get_irq;
}
- adapter->pdev = pdev;
+ adapter->dev = (pdev->dev.parent) ? pdev->dev.parent : &pdev->dev;
+
+ /* DMA is only supported when accessed via timberdale */
+ if (!(adapter->conf_flags & MICREL_KS884X) && pdata &&
+ (pdata->tx_dma_channel != -1) &&
+ (pdata->rx_dma_channel != -1)) {
+ adapter->dma_rx.channel = pdata->rx_dma_channel;
+ adapter->dma_tx.channel = pdata->tx_dma_channel;
+ } else {
+ adapter->dma_rx.channel = -1;
+ adapter->dma_tx.channel = -1;
+ }
tasklet_init(&adapter->tasklet, ks8842_tasklet, (unsigned long)netdev);
spin_lock_init(&adapter->lock);
diff --git a/drivers/net/ksz884x.c b/drivers/net/ksz884x.c
index 7805bbf1d53..37504a39890 100644
--- a/drivers/net/ksz884x.c
+++ b/drivers/net/ksz884x.c
@@ -1457,7 +1457,6 @@ struct dev_info {
* @adapter: Adapter device information.
* @port: Port information.
* @monitor_time_info: Timer to monitor ports.
- * @stats: Network statistics.
* @proc_sem: Semaphore for proc accessing.
* @id: Device ID.
* @mii_if: MII interface information.
@@ -1471,7 +1470,6 @@ struct dev_priv {
struct dev_info *adapter;
struct ksz_port port;
struct ksz_timer_info monitor_timer_info;
- struct net_device_stats stats;
struct semaphore proc_sem;
int id;
@@ -4751,8 +4749,8 @@ static void send_packet(struct sk_buff *skb, struct net_device *dev)
hw_send_pkt(hw);
/* Update transmit statistics. */
- priv->stats.tx_packets++;
- priv->stats.tx_bytes += len;
+ dev->stats.tx_packets++;
+ dev->stats.tx_bytes += len;
}
/**
@@ -5030,7 +5028,7 @@ static inline int rx_proc(struct net_device *dev, struct ksz_hw* hw,
/* skb->data != skb->head */
skb = dev_alloc_skb(packet_len + 2);
if (!skb) {
- priv->stats.rx_dropped++;
+ dev->stats.rx_dropped++;
return -ENOMEM;
}
@@ -5050,8 +5048,8 @@ static inline int rx_proc(struct net_device *dev, struct ksz_hw* hw,
csum_verified(skb);
/* Update receive statistics. */
- priv->stats.rx_packets++;
- priv->stats.rx_bytes += packet_len;
+ dev->stats.rx_packets++;
+ dev->stats.rx_bytes += packet_len;
/* Notify upper layer for received packet. */
rx_status = netif_rx(skb);
@@ -5291,7 +5289,7 @@ static irqreturn_t netdev_intr(int irq, void *dev_id)
}
if (unlikely(int_enable & KS884X_INT_RX_OVERRUN)) {
- priv->stats.rx_fifo_errors++;
+ dev->stats.rx_fifo_errors++;
hw_resume_rx(hw);
}
@@ -5522,7 +5520,7 @@ static int netdev_open(struct net_device *dev)
priv->promiscuous = 0;
/* Reset device statistics. */
- memset(&priv->stats, 0, sizeof(struct net_device_stats));
+ memset(&dev->stats, 0, sizeof(struct net_device_stats));
memset((void *) port->counter, 0,
(sizeof(u64) * OID_COUNTER_LAST));
@@ -5622,42 +5620,42 @@ static struct net_device_stats *netdev_query_statistics(struct net_device *dev)
int i;
int p;
- priv->stats.rx_errors = port->counter[OID_COUNTER_RCV_ERROR];
- priv->stats.tx_errors = port->counter[OID_COUNTER_XMIT_ERROR];
+ dev->stats.rx_errors = port->counter[OID_COUNTER_RCV_ERROR];
+ dev->stats.tx_errors = port->counter[OID_COUNTER_XMIT_ERROR];
/* Reset to zero to add count later. */
- priv->stats.multicast = 0;
- priv->stats.collisions = 0;
- priv->stats.rx_length_errors = 0;
- priv->stats.rx_crc_errors = 0;
- priv->stats.rx_frame_errors = 0;
- priv->stats.tx_window_errors = 0;
+ dev->stats.multicast = 0;
+ dev->stats.collisions = 0;
+ dev->stats.rx_length_errors = 0;
+ dev->stats.rx_crc_errors = 0;
+ dev->stats.rx_frame_errors = 0;
+ dev->stats.tx_window_errors = 0;
for (i = 0, p = port->first_port; i < port->mib_port_cnt; i++, p++) {
mib = &hw->port_mib[p];
- priv->stats.multicast += (unsigned long)
+ dev->stats.multicast += (unsigned long)
mib->counter[MIB_COUNTER_RX_MULTICAST];
- priv->stats.collisions += (unsigned long)
+ dev->stats.collisions += (unsigned long)
mib->counter[MIB_COUNTER_TX_TOTAL_COLLISION];
- priv->stats.rx_length_errors += (unsigned long)(
+ dev->stats.rx_length_errors += (unsigned long)(
mib->counter[MIB_COUNTER_RX_UNDERSIZE] +
mib->counter[MIB_COUNTER_RX_FRAGMENT] +
mib->counter[MIB_COUNTER_RX_OVERSIZE] +
mib->counter[MIB_COUNTER_RX_JABBER]);
- priv->stats.rx_crc_errors += (unsigned long)
+ dev->stats.rx_crc_errors += (unsigned long)
mib->counter[MIB_COUNTER_RX_CRC_ERR];
- priv->stats.rx_frame_errors += (unsigned long)(
+ dev->stats.rx_frame_errors += (unsigned long)(
mib->counter[MIB_COUNTER_RX_ALIGNMENT_ERR] +
mib->counter[MIB_COUNTER_RX_SYMBOL_ERR]);
- priv->stats.tx_window_errors += (unsigned long)
+ dev->stats.tx_window_errors += (unsigned long)
mib->counter[MIB_COUNTER_TX_LATE_COLLISION];
}
- return &priv->stats;
+ return &dev->stats;
}
/**
@@ -5718,7 +5716,7 @@ static void dev_set_promiscuous(struct net_device *dev, struct dev_priv *priv,
* from the bridge.
*/
if ((hw->features & STP_SUPPORT) && !promiscuous &&
- dev->br_port) {
+ (dev->priv_flags & IFF_BRIDGE_PORT)) {
struct ksz_switch *sw = hw->ksz_switch;
int port = priv->port.first_port;
@@ -6812,7 +6810,7 @@ static int stp;
static int fast_aging;
/**
- * netdev_init - initalize network device.
+ * netdev_init - initialize network device.
* @dev: Network device.
*
* This function initializes the network device.
@@ -6896,13 +6894,12 @@ static void get_mac_addr(struct dev_info *hw_priv, u8 *macaddr, int port)
i = j = num = got_num = 0;
while (j < MAC_ADDR_LEN) {
if (macaddr[i]) {
+ int digit;
+
got_num = 1;
- if ('0' <= macaddr[i] && macaddr[i] <= '9')
- num = num * 16 + macaddr[i] - '0';
- else if ('A' <= macaddr[i] && macaddr[i] <= 'F')
- num = num * 16 + 10 + macaddr[i] - 'A';
- else if ('a' <= macaddr[i] && macaddr[i] <= 'f')
- num = num * 16 + 10 + macaddr[i] - 'a';
+ digit = hex_to_bin(macaddr[i]);
+ if (digit >= 0)
+ num = num * 16 + digit;
else if (':' == macaddr[i])
got_num = 2;
else
diff --git a/drivers/net/lance.c b/drivers/net/lance.c
index 21f8adaa87c..f06296bfe29 100644
--- a/drivers/net/lance.c
+++ b/drivers/net/lance.c
@@ -248,7 +248,6 @@ struct lance_private {
int cur_rx, cur_tx; /* The next free ring entry */
int dirty_rx, dirty_tx; /* The ring entries to be free()ed. */
int dma;
- struct net_device_stats stats;
unsigned char chip_version; /* See lance_chip_type. */
spinlock_t devlock;
};
@@ -925,7 +924,7 @@ static void lance_tx_timeout (struct net_device *dev)
printk ("%s: transmit timed out, status %4.4x, resetting.\n",
dev->name, inw (ioaddr + LANCE_DATA));
outw (0x0004, ioaddr + LANCE_DATA);
- lp->stats.tx_errors++;
+ dev->stats.tx_errors++;
#ifndef final_version
if (lance_debug > 3) {
int i;
@@ -989,7 +988,7 @@ static netdev_tx_t lance_start_xmit(struct sk_buff *skb,
lp->tx_ring[entry].misc = 0x0000;
- lp->stats.tx_bytes += skb->len;
+ dev->stats.tx_bytes += skb->len;
/* If any part of this buffer is >16M we must copy it to a low-memory
buffer. */
@@ -1062,13 +1061,16 @@ static irqreturn_t lance_interrupt(int irq, void *dev_id)
if (status & 0x40000000) {
/* There was an major error, log it. */
int err_status = lp->tx_ring[entry].misc;
- lp->stats.tx_errors++;
- if (err_status & 0x0400) lp->stats.tx_aborted_errors++;
- if (err_status & 0x0800) lp->stats.tx_carrier_errors++;
- if (err_status & 0x1000) lp->stats.tx_window_errors++;
+ dev->stats.tx_errors++;
+ if (err_status & 0x0400)
+ dev->stats.tx_aborted_errors++;
+ if (err_status & 0x0800)
+ dev->stats.tx_carrier_errors++;
+ if (err_status & 0x1000)
+ dev->stats.tx_window_errors++;
if (err_status & 0x4000) {
/* Ackk! On FIFO errors the Tx unit is turned off! */
- lp->stats.tx_fifo_errors++;
+ dev->stats.tx_fifo_errors++;
/* Remove this verbosity later! */
printk("%s: Tx FIFO error! Status %4.4x.\n",
dev->name, csr0);
@@ -1077,8 +1079,8 @@ static irqreturn_t lance_interrupt(int irq, void *dev_id)
}
} else {
if (status & 0x18000000)
- lp->stats.collisions++;
- lp->stats.tx_packets++;
+ dev->stats.collisions++;
+ dev->stats.tx_packets++;
}
/* We must free the original skb if it's not a data-only copy
@@ -1108,8 +1110,10 @@ static irqreturn_t lance_interrupt(int irq, void *dev_id)
}
/* Log misc errors. */
- if (csr0 & 0x4000) lp->stats.tx_errors++; /* Tx babble. */
- if (csr0 & 0x1000) lp->stats.rx_errors++; /* Missed a Rx frame. */
+ if (csr0 & 0x4000)
+ dev->stats.tx_errors++; /* Tx babble. */
+ if (csr0 & 0x1000)
+ dev->stats.rx_errors++; /* Missed a Rx frame. */
if (csr0 & 0x0800) {
printk("%s: Bus master arbitration failure, status %4.4x.\n",
dev->name, csr0);
@@ -1155,11 +1159,15 @@ lance_rx(struct net_device *dev)
buffers it's possible for a jabber packet to use two
buffers, with only the last correctly noting the error. */
if (status & 0x01) /* Only count a general error at the */
- lp->stats.rx_errors++; /* end of a packet.*/
- if (status & 0x20) lp->stats.rx_frame_errors++;
- if (status & 0x10) lp->stats.rx_over_errors++;
- if (status & 0x08) lp->stats.rx_crc_errors++;
- if (status & 0x04) lp->stats.rx_fifo_errors++;
+ dev->stats.rx_errors++; /* end of a packet.*/
+ if (status & 0x20)
+ dev->stats.rx_frame_errors++;
+ if (status & 0x10)
+ dev->stats.rx_over_errors++;
+ if (status & 0x08)
+ dev->stats.rx_crc_errors++;
+ if (status & 0x04)
+ dev->stats.rx_fifo_errors++;
lp->rx_ring[entry].base &= 0x03ffffff;
}
else
@@ -1171,7 +1179,7 @@ lance_rx(struct net_device *dev)
if(pkt_len<60)
{
printk("%s: Runt packet!\n",dev->name);
- lp->stats.rx_errors++;
+ dev->stats.rx_errors++;
}
else
{
@@ -1185,7 +1193,7 @@ lance_rx(struct net_device *dev)
if (i > RX_RING_SIZE -2)
{
- lp->stats.rx_dropped++;
+ dev->stats.rx_dropped++;
lp->rx_ring[entry].base |= 0x80000000;
lp->cur_rx++;
}
@@ -1198,8 +1206,8 @@ lance_rx(struct net_device *dev)
pkt_len);
skb->protocol=eth_type_trans(skb,dev);
netif_rx(skb);
- lp->stats.rx_packets++;
- lp->stats.rx_bytes+=pkt_len;
+ dev->stats.rx_packets++;
+ dev->stats.rx_bytes += pkt_len;
}
}
/* The docs say that the buffer length isn't touched, but Andrew Boyd
@@ -1225,7 +1233,7 @@ lance_close(struct net_device *dev)
if (chip_table[lp->chip_version].flags & LANCE_HAS_MISSED_FRAME) {
outw(112, ioaddr+LANCE_ADDR);
- lp->stats.rx_missed_errors = inw(ioaddr+LANCE_DATA);
+ dev->stats.rx_missed_errors = inw(ioaddr+LANCE_DATA);
}
outw(0, ioaddr+LANCE_ADDR);
@@ -1262,12 +1270,12 @@ static struct net_device_stats *lance_get_stats(struct net_device *dev)
spin_lock_irqsave(&lp->devlock, flags);
saved_addr = inw(ioaddr+LANCE_ADDR);
outw(112, ioaddr+LANCE_ADDR);
- lp->stats.rx_missed_errors = inw(ioaddr+LANCE_DATA);
+ dev->stats.rx_missed_errors = inw(ioaddr+LANCE_DATA);
outw(saved_addr, ioaddr+LANCE_ADDR);
spin_unlock_irqrestore(&lp->devlock, flags);
}
- return &lp->stats;
+ return &dev->stats;
}
/* Set or clear the multicast filter for this adaptor.
diff --git a/drivers/net/ll_temac_main.c b/drivers/net/ll_temac_main.c
index 6474c4973d3..4eea3f70c5c 100644
--- a/drivers/net/ll_temac_main.c
+++ b/drivers/net/ll_temac_main.c
@@ -193,6 +193,35 @@ static int temac_dcr_setup(struct temac_local *lp, struct of_device *op,
#endif
/**
+ * * temac_dma_bd_release - Release buffer descriptor rings
+ */
+static void temac_dma_bd_release(struct net_device *ndev)
+{
+ struct temac_local *lp = netdev_priv(ndev);
+ int i;
+
+ for (i = 0; i < RX_BD_NUM; i++) {
+ if (!lp->rx_skb[i])
+ break;
+ else {
+ dma_unmap_single(ndev->dev.parent, lp->rx_bd_v[i].phys,
+ XTE_MAX_JUMBO_FRAME_SIZE, DMA_FROM_DEVICE);
+ dev_kfree_skb(lp->rx_skb[i]);
+ }
+ }
+ if (lp->rx_bd_v)
+ dma_free_coherent(ndev->dev.parent,
+ sizeof(*lp->rx_bd_v) * RX_BD_NUM,
+ lp->rx_bd_v, lp->rx_bd_p);
+ if (lp->tx_bd_v)
+ dma_free_coherent(ndev->dev.parent,
+ sizeof(*lp->tx_bd_v) * TX_BD_NUM,
+ lp->tx_bd_v, lp->tx_bd_p);
+ if (lp->rx_skb)
+ kfree(lp->rx_skb);
+}
+
+/**
* temac_dma_bd_init - Setup buffer descriptor rings
*/
static int temac_dma_bd_init(struct net_device *ndev)
@@ -202,14 +231,29 @@ static int temac_dma_bd_init(struct net_device *ndev)
int i;
lp->rx_skb = kzalloc(sizeof(*lp->rx_skb) * RX_BD_NUM, GFP_KERNEL);
+ if (!lp->rx_skb) {
+ dev_err(&ndev->dev,
+ "can't allocate memory for DMA RX buffer\n");
+ goto out;
+ }
/* allocate the tx and rx ring buffer descriptors. */
/* returns a virtual addres and a physical address. */
lp->tx_bd_v = dma_alloc_coherent(ndev->dev.parent,
sizeof(*lp->tx_bd_v) * TX_BD_NUM,
&lp->tx_bd_p, GFP_KERNEL);
+ if (!lp->tx_bd_v) {
+ dev_err(&ndev->dev,
+ "unable to allocate DMA TX buffer descriptors");
+ goto out;
+ }
lp->rx_bd_v = dma_alloc_coherent(ndev->dev.parent,
sizeof(*lp->rx_bd_v) * RX_BD_NUM,
&lp->rx_bd_p, GFP_KERNEL);
+ if (!lp->rx_bd_v) {
+ dev_err(&ndev->dev,
+ "unable to allocate DMA RX buffer descriptors");
+ goto out;
+ }
memset(lp->tx_bd_v, 0, sizeof(*lp->tx_bd_v) * TX_BD_NUM);
for (i = 0; i < TX_BD_NUM; i++) {
@@ -227,7 +271,7 @@ static int temac_dma_bd_init(struct net_device *ndev)
if (skb == 0) {
dev_err(&ndev->dev, "alloc_skb error %d\n", i);
- return -1;
+ goto out;
}
lp->rx_skb[i] = skb;
/* returns physical address of skb->data */
@@ -258,6 +302,10 @@ static int temac_dma_bd_init(struct net_device *ndev)
lp->dma_out(lp, TX_CURDESC_PTR, lp->tx_bd_p);
return 0;
+
+out:
+ temac_dma_bd_release(ndev);
+ return -ENOMEM;
}
/* ---------------------------------------------------------------------
@@ -449,7 +497,7 @@ static u32 temac_setoptions(struct net_device *ndev, u32 options)
return (0);
}
-/* Initilize temac */
+/* Initialize temac */
static void temac_device_reset(struct net_device *ndev)
{
struct temac_local *lp = netdev_priv(ndev);
@@ -505,7 +553,10 @@ static void temac_device_reset(struct net_device *ndev)
}
lp->dma_out(lp, DMA_CONTROL_REG, DMA_TAIL_ENABLE);
- temac_dma_bd_init(ndev);
+ if (temac_dma_bd_init(ndev)) {
+ dev_err(&ndev->dev,
+ "temac_device_reset descriptor allocation failed\n");
+ }
temac_indirect_out32(lp, XTE_RXC0_OFFSET, 0);
temac_indirect_out32(lp, XTE_RXC1_OFFSET, 0);
@@ -837,6 +888,8 @@ static int temac_stop(struct net_device *ndev)
phy_disconnect(lp->phy_dev);
lp->phy_dev = NULL;
+ temac_dma_bd_release(ndev);
+
return 0;
}
@@ -862,6 +915,7 @@ static const struct net_device_ops temac_netdev_ops = {
.ndo_stop = temac_stop,
.ndo_start_xmit = temac_start_xmit,
.ndo_set_mac_address = netdev_set_mac_address,
+ .ndo_validate_addr = eth_validate_addr,
//.ndo_set_multicast_list = temac_set_multicast_list,
#ifdef CONFIG_NET_POLL_CONTROLLER
.ndo_poll_controller = temac_poll_controller,
@@ -978,19 +1032,22 @@ temac_of_probe(struct of_device *op, const struct of_device_id *match)
dev_dbg(&op->dev, "MEM base: %p\n", lp->sdma_regs);
} else {
dev_err(&op->dev, "unable to map DMA registers\n");
+ of_node_put(np);
goto err_iounmap;
}
}
lp->rx_irq = irq_of_parse_and_map(np, 0);
lp->tx_irq = irq_of_parse_and_map(np, 1);
+
+ of_node_put(np); /* Finished with the DMA node; drop the reference */
+
if ((lp->rx_irq == NO_IRQ) || (lp->tx_irq == NO_IRQ)) {
dev_err(&op->dev, "could not determine irqs\n");
rc = -ENOMEM;
goto err_iounmap_2;
}
- of_node_put(np); /* Finished with the DMA node; drop the reference */
/* Retrieve the MAC address */
addr = of_get_property(op->dev.of_node, "local-mac-address", &size);
diff --git a/drivers/net/loopback.c b/drivers/net/loopback.c
index 72b7949c91b..9a099679532 100644
--- a/drivers/net/loopback.c
+++ b/drivers/net/loopback.c
@@ -58,11 +58,13 @@
#include <linux/tcp.h>
#include <linux/percpu.h>
#include <net/net_namespace.h>
+#include <linux/u64_stats_sync.h>
struct pcpu_lstats {
- unsigned long packets;
- unsigned long bytes;
- unsigned long drops;
+ u64 packets;
+ u64 bytes;
+ struct u64_stats_sync syncp;
+ unsigned long drops;
};
/*
@@ -86,31 +88,40 @@ static netdev_tx_t loopback_xmit(struct sk_buff *skb,
len = skb->len;
if (likely(netif_rx(skb) == NET_RX_SUCCESS)) {
+ u64_stats_update_begin(&lb_stats->syncp);
lb_stats->bytes += len;
lb_stats->packets++;
+ u64_stats_update_end(&lb_stats->syncp);
} else
lb_stats->drops++;
return NETDEV_TX_OK;
}
-static struct net_device_stats *loopback_get_stats(struct net_device *dev)
+static struct rtnl_link_stats64 *loopback_get_stats64(struct net_device *dev,
+ struct rtnl_link_stats64 *stats)
{
const struct pcpu_lstats __percpu *pcpu_lstats;
- struct net_device_stats *stats = &dev->stats;
- unsigned long bytes = 0;
- unsigned long packets = 0;
- unsigned long drops = 0;
+ u64 bytes = 0;
+ u64 packets = 0;
+ u64 drops = 0;
int i;
pcpu_lstats = (void __percpu __force *)dev->ml_priv;
for_each_possible_cpu(i) {
const struct pcpu_lstats *lb_stats;
+ u64 tbytes, tpackets;
+ unsigned int start;
lb_stats = per_cpu_ptr(pcpu_lstats, i);
- bytes += lb_stats->bytes;
- packets += lb_stats->packets;
+ do {
+ start = u64_stats_fetch_begin(&lb_stats->syncp);
+ tbytes = lb_stats->bytes;
+ tpackets = lb_stats->packets;
+ } while (u64_stats_fetch_retry(&lb_stats->syncp, start));
drops += lb_stats->drops;
+ bytes += tbytes;
+ packets += tpackets;
}
stats->rx_packets = packets;
stats->tx_packets = packets;
@@ -158,7 +169,7 @@ static void loopback_dev_free(struct net_device *dev)
static const struct net_device_ops loopback_ops = {
.ndo_init = loopback_dev_init,
.ndo_start_xmit= loopback_xmit,
- .ndo_get_stats = loopback_get_stats,
+ .ndo_get_stats64 = loopback_get_stats64,
};
/*
diff --git a/drivers/net/mac8390.c b/drivers/net/mac8390.c
index 1136c9a22b6..3832fa4961d 100644
--- a/drivers/net/mac8390.c
+++ b/drivers/net/mac8390.c
@@ -157,6 +157,8 @@ static void dayna_block_output(struct net_device *dev, int count,
#define memcpy_fromio(a, b, c) memcpy((a), (void *)(b), (c))
#define memcpy_toio(a, b, c) memcpy((void *)(a), (b), (c))
+#define memcmp_withio(a, b, c) memcmp((a), (void *)(b), (c))
+
/* Slow Sane (16-bit chunk memory read/write) Cabletron uses this */
static void slow_sane_get_8390_hdr(struct net_device *dev,
struct e8390_pkt_hdr *hdr, int ring_page);
@@ -164,8 +166,8 @@ static void slow_sane_block_input(struct net_device *dev, int count,
struct sk_buff *skb, int ring_offset);
static void slow_sane_block_output(struct net_device *dev, int count,
const unsigned char *buf, int start_page);
-static void word_memcpy_tocard(void *tp, const void *fp, int count);
-static void word_memcpy_fromcard(void *tp, const void *fp, int count);
+static void word_memcpy_tocard(unsigned long tp, const void *fp, int count);
+static void word_memcpy_fromcard(void *tp, unsigned long fp, int count);
static enum mac8390_type __init mac8390_ident(struct nubus_dev *dev)
{
@@ -245,9 +247,9 @@ static enum mac8390_access __init mac8390_testio(volatile unsigned long membase)
unsigned long outdata = 0xA5A0B5B0;
unsigned long indata = 0x00000000;
/* Try writing 32 bits */
- memcpy(membase, &outdata, 4);
+ memcpy_toio(membase, &outdata, 4);
/* Now compare them */
- if (memcmp((char *)&outdata, (char *)membase, 4) == 0)
+ if (memcmp_withio(&outdata, membase, 4) == 0)
return ACCESS_32;
/* Write 16 bit output */
word_memcpy_tocard(membase, &outdata, 4);
@@ -554,7 +556,7 @@ static int __init mac8390_initdev(struct net_device *dev,
case MAC8390_APPLE:
switch (mac8390_testio(dev->mem_start)) {
case ACCESS_UNKNOWN:
- pr_info("Don't know how to access card memory!\n");
+ pr_err("Don't know how to access card memory!\n");
return -ENODEV;
break;
@@ -641,12 +643,13 @@ static int __init mac8390_initdev(struct net_device *dev,
static int mac8390_open(struct net_device *dev)
{
+ int err;
+
__ei_open(dev);
- if (request_irq(dev->irq, __ei_interrupt, 0, "8390 Ethernet", dev)) {
- pr_info("%s: unable to get IRQ %d.\n", dev->name, dev->irq);
- return -EAGAIN;
- }
- return 0;
+ err = request_irq(dev->irq, __ei_interrupt, 0, "8390 Ethernet", dev);
+ if (err)
+ pr_err("%s: unable to get IRQ %d\n", dev->name, dev->irq);
+ return err;
}
static int mac8390_close(struct net_device *dev)
@@ -731,7 +734,7 @@ static void sane_get_8390_hdr(struct net_device *dev,
struct e8390_pkt_hdr *hdr, int ring_page)
{
unsigned long hdr_start = (ring_page - WD_START_PG)<<8;
- memcpy_fromio((void *)hdr, (char *)dev->mem_start + hdr_start, 4);
+ memcpy_fromio(hdr, dev->mem_start + hdr_start, 4);
/* Fix endianness */
hdr->count = swab16(hdr->count);
}
@@ -745,14 +748,13 @@ static void sane_block_input(struct net_device *dev, int count,
if (xfer_start + count > ei_status.rmem_end) {
/* We must wrap the input move. */
int semi_count = ei_status.rmem_end - xfer_start;
- memcpy_fromio(skb->data, (char *)dev->mem_start + xfer_base,
+ memcpy_fromio(skb->data, dev->mem_start + xfer_base,
semi_count);
count -= semi_count;
- memcpy_toio(skb->data + semi_count,
- (char *)ei_status.rmem_start, count);
- } else {
- memcpy_fromio(skb->data, (char *)dev->mem_start + xfer_base,
+ memcpy_fromio(skb->data + semi_count, ei_status.rmem_start,
count);
+ } else {
+ memcpy_fromio(skb->data, dev->mem_start + xfer_base, count);
}
}
@@ -761,7 +763,7 @@ static void sane_block_output(struct net_device *dev, int count,
{
long shmem = (start_page - WD_START_PG)<<8;
- memcpy_toio((char *)dev->mem_start + shmem, buf, count);
+ memcpy_toio(dev->mem_start + shmem, buf, count);
}
/* dayna block input/output */
@@ -812,7 +814,7 @@ static void slow_sane_get_8390_hdr(struct net_device *dev,
int ring_page)
{
unsigned long hdr_start = (ring_page - WD_START_PG)<<8;
- word_memcpy_fromcard(hdr, (char *)dev->mem_start + hdr_start, 4);
+ word_memcpy_fromcard(hdr, dev->mem_start + hdr_start, 4);
/* Register endianism - fix here rather than 8390.c */
hdr->count = (hdr->count&0xFF)<<8|(hdr->count>>8);
}
@@ -826,15 +828,14 @@ static void slow_sane_block_input(struct net_device *dev, int count,
if (xfer_start + count > ei_status.rmem_end) {
/* We must wrap the input move. */
int semi_count = ei_status.rmem_end - xfer_start;
- word_memcpy_fromcard(skb->data,
- (char *)dev->mem_start + xfer_base,
+ word_memcpy_fromcard(skb->data, dev->mem_start + xfer_base,
semi_count);
count -= semi_count;
word_memcpy_fromcard(skb->data + semi_count,
- (char *)ei_status.rmem_start, count);
+ ei_status.rmem_start, count);
} else {
- word_memcpy_fromcard(skb->data,
- (char *)dev->mem_start + xfer_base, count);
+ word_memcpy_fromcard(skb->data, dev->mem_start + xfer_base,
+ count);
}
}
@@ -843,12 +844,12 @@ static void slow_sane_block_output(struct net_device *dev, int count,
{
long shmem = (start_page - WD_START_PG)<<8;
- word_memcpy_tocard((char *)dev->mem_start + shmem, buf, count);
+ word_memcpy_tocard(dev->mem_start + shmem, buf, count);
}
-static void word_memcpy_tocard(void *tp, const void *fp, int count)
+static void word_memcpy_tocard(unsigned long tp, const void *fp, int count)
{
- volatile unsigned short *to = tp;
+ volatile unsigned short *to = (void *)tp;
const unsigned short *from = fp;
count++;
@@ -858,10 +859,10 @@ static void word_memcpy_tocard(void *tp, const void *fp, int count)
*to++ = *from++;
}
-static void word_memcpy_fromcard(void *tp, const void *fp, int count)
+static void word_memcpy_fromcard(void *tp, unsigned long fp, int count)
{
unsigned short *to = tp;
- const volatile unsigned short *from = fp;
+ const volatile unsigned short *from = (const void *)fp;
count++;
count /= 2;
diff --git a/drivers/net/mac89x0.c b/drivers/net/mac89x0.c
index 69fa4ef64dd..669b317974a 100644
--- a/drivers/net/mac89x0.c
+++ b/drivers/net/mac89x0.c
@@ -110,7 +110,6 @@ static unsigned int net_debug = NET_DEBUG;
/* Information that need to be kept for each board. */
struct net_local {
- struct net_device_stats stats;
int chip_type; /* one of: CS8900, CS8920, CS8920M */
char chip_revision; /* revision letter of the chip ('A'...) */
int send_cmd; /* the propercommand used to send a packet. */
@@ -444,13 +443,18 @@ static irqreturn_t net_interrupt(int irq, void *dev_id)
net_rx(dev);
break;
case ISQ_TRANSMITTER_EVENT:
- lp->stats.tx_packets++;
+ dev->stats.tx_packets++;
netif_wake_queue(dev);
- if ((status & TX_OK) == 0) lp->stats.tx_errors++;
- if (status & TX_LOST_CRS) lp->stats.tx_carrier_errors++;
- if (status & TX_SQE_ERROR) lp->stats.tx_heartbeat_errors++;
- if (status & TX_LATE_COL) lp->stats.tx_window_errors++;
- if (status & TX_16_COL) lp->stats.tx_aborted_errors++;
+ if ((status & TX_OK) == 0)
+ dev->stats.tx_errors++;
+ if (status & TX_LOST_CRS)
+ dev->stats.tx_carrier_errors++;
+ if (status & TX_SQE_ERROR)
+ dev->stats.tx_heartbeat_errors++;
+ if (status & TX_LATE_COL)
+ dev->stats.tx_window_errors++;
+ if (status & TX_16_COL)
+ dev->stats.tx_aborted_errors++;
break;
case ISQ_BUFFER_EVENT:
if (status & READY_FOR_TX) {
@@ -469,10 +473,10 @@ static irqreturn_t net_interrupt(int irq, void *dev_id)
}
break;
case ISQ_RX_MISS_EVENT:
- lp->stats.rx_missed_errors += (status >>6);
+ dev->stats.rx_missed_errors += (status >> 6);
break;
case ISQ_TX_COL_EVENT:
- lp->stats.collisions += (status >>6);
+ dev->stats.collisions += (status >> 6);
break;
}
}
@@ -483,19 +487,22 @@ static irqreturn_t net_interrupt(int irq, void *dev_id)
static void
net_rx(struct net_device *dev)
{
- struct net_local *lp = netdev_priv(dev);
struct sk_buff *skb;
int status, length;
status = readreg(dev, PP_RxStatus);
if ((status & RX_OK) == 0) {
- lp->stats.rx_errors++;
- if (status & RX_RUNT) lp->stats.rx_length_errors++;
- if (status & RX_EXTRA_DATA) lp->stats.rx_length_errors++;
- if (status & RX_CRC_ERROR) if (!(status & (RX_EXTRA_DATA|RX_RUNT)))
+ dev->stats.rx_errors++;
+ if (status & RX_RUNT)
+ dev->stats.rx_length_errors++;
+ if (status & RX_EXTRA_DATA)
+ dev->stats.rx_length_errors++;
+ if ((status & RX_CRC_ERROR) &&
+ !(status & (RX_EXTRA_DATA|RX_RUNT)))
/* per str 172 */
- lp->stats.rx_crc_errors++;
- if (status & RX_DRIBBLE) lp->stats.rx_frame_errors++;
+ dev->stats.rx_crc_errors++;
+ if (status & RX_DRIBBLE)
+ dev->stats.rx_frame_errors++;
return;
}
@@ -504,7 +511,7 @@ net_rx(struct net_device *dev)
skb = alloc_skb(length, GFP_ATOMIC);
if (skb == NULL) {
printk("%s: Memory squeeze, dropping packet.\n", dev->name);
- lp->stats.rx_dropped++;
+ dev->stats.rx_dropped++;
return;
}
skb_put(skb, length);
@@ -519,8 +526,8 @@ net_rx(struct net_device *dev)
skb->protocol=eth_type_trans(skb,dev);
netif_rx(skb);
- lp->stats.rx_packets++;
- lp->stats.rx_bytes += length;
+ dev->stats.rx_packets++;
+ dev->stats.rx_bytes += length;
}
/* The inverse routine to net_open(). */
@@ -548,16 +555,15 @@ net_close(struct net_device *dev)
static struct net_device_stats *
net_get_stats(struct net_device *dev)
{
- struct net_local *lp = netdev_priv(dev);
unsigned long flags;
local_irq_save(flags);
/* Update the statistics from the device registers. */
- lp->stats.rx_missed_errors += (readreg(dev, PP_RxMiss) >> 6);
- lp->stats.collisions += (readreg(dev, PP_TxCol) >> 6);
+ dev->stats.rx_missed_errors += (readreg(dev, PP_RxMiss) >> 6);
+ dev->stats.collisions += (readreg(dev, PP_TxCol) >> 6);
local_irq_restore(flags);
- return &lp->stats;
+ return &dev->stats;
}
static void set_multicast_list(struct net_device *dev)
diff --git a/drivers/net/macb.c b/drivers/net/macb.c
index 40797fbdca9..ff2f158ab0b 100644
--- a/drivers/net/macb.c
+++ b/drivers/net/macb.c
@@ -1082,7 +1082,7 @@ static int macb_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
if (!phydev)
return -ENODEV;
- return phy_mii_ioctl(phydev, if_mii(rq), cmd);
+ return phy_mii_ioctl(phydev, rq, cmd);
}
static const struct net_device_ops macb_netdev_ops = {
diff --git a/drivers/net/macsonic.c b/drivers/net/macsonic.c
index adb54fe2d82..c93679ee699 100644
--- a/drivers/net/macsonic.c
+++ b/drivers/net/macsonic.c
@@ -140,21 +140,40 @@ static irqreturn_t macsonic_interrupt(int irq, void *dev_id)
static int macsonic_open(struct net_device* dev)
{
- if (request_irq(dev->irq, sonic_interrupt, IRQ_FLG_FAST, "sonic", dev)) {
- printk(KERN_ERR "%s: unable to get IRQ %d.\n", dev->name, dev->irq);
- return -EAGAIN;
+ int retval;
+
+ retval = request_irq(dev->irq, sonic_interrupt, IRQ_FLG_FAST,
+ "sonic", dev);
+ if (retval) {
+ printk(KERN_ERR "%s: unable to get IRQ %d.\n",
+ dev->name, dev->irq);
+ goto err;
}
/* Under the A/UX interrupt scheme, the onboard SONIC interrupt comes
* in at priority level 3. However, we sometimes get the level 2 inter-
* rupt as well, which must prevent re-entrance of the sonic handler.
*/
- if (dev->irq == IRQ_AUTO_3)
- if (request_irq(IRQ_NUBUS_9, macsonic_interrupt, IRQ_FLG_FAST, "sonic", dev)) {
- printk(KERN_ERR "%s: unable to get IRQ %d.\n", dev->name, IRQ_NUBUS_9);
- free_irq(dev->irq, dev);
- return -EAGAIN;
+ if (dev->irq == IRQ_AUTO_3) {
+ retval = request_irq(IRQ_NUBUS_9, macsonic_interrupt,
+ IRQ_FLG_FAST, "sonic", dev);
+ if (retval) {
+ printk(KERN_ERR "%s: unable to get IRQ %d.\n",
+ dev->name, IRQ_NUBUS_9);
+ goto err_irq;
}
- return sonic_open(dev);
+ }
+ retval = sonic_open(dev);
+ if (retval)
+ goto err_irq_nubus;
+ return 0;
+
+err_irq_nubus:
+ if (dev->irq == IRQ_AUTO_3)
+ free_irq(IRQ_NUBUS_9, dev);
+err_irq:
+ free_irq(dev->irq, dev);
+err:
+ return retval;
}
static int macsonic_close(struct net_device* dev)
diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c
index f15fe2cf72a..0ef0eb0db94 100644
--- a/drivers/net/macvlan.c
+++ b/drivers/net/macvlan.c
@@ -37,8 +37,14 @@ struct macvlan_port {
struct net_device *dev;
struct hlist_head vlan_hash[MACVLAN_HASH_SIZE];
struct list_head vlans;
+ struct rcu_head rcu;
};
+#define macvlan_port_get_rcu(dev) \
+ ((struct macvlan_port *) rcu_dereference(dev->rx_handler_data))
+#define macvlan_port_get(dev) ((struct macvlan_port *) dev->rx_handler_data)
+#define macvlan_port_exists(dev) (dev->priv_flags & IFF_MACVLAN_PORT)
+
static struct macvlan_dev *macvlan_hash_lookup(const struct macvlan_port *port,
const unsigned char *addr)
{
@@ -145,15 +151,17 @@ static void macvlan_broadcast(struct sk_buff *skb,
}
/* called under rcu_read_lock() from netif_receive_skb */
-static struct sk_buff *macvlan_handle_frame(struct macvlan_port *port,
- struct sk_buff *skb)
+static struct sk_buff *macvlan_handle_frame(struct sk_buff *skb)
{
+ struct macvlan_port *port;
const struct ethhdr *eth = eth_hdr(skb);
const struct macvlan_dev *vlan;
const struct macvlan_dev *src;
struct net_device *dev;
- unsigned int len;
+ unsigned int len = 0;
+ int ret = NET_RX_DROP;
+ port = macvlan_port_get_rcu(skb->dev);
if (is_multicast_ether_addr(eth->h_dest)) {
src = macvlan_hash_lookup(port, eth->h_source);
if (!src)
@@ -188,14 +196,16 @@ static struct sk_buff *macvlan_handle_frame(struct macvlan_port *port,
}
len = skb->len + ETH_HLEN;
skb = skb_share_check(skb, GFP_ATOMIC);
- macvlan_count_rx(vlan, len, skb != NULL, 0);
if (!skb)
- return NULL;
+ goto out;
skb->dev = dev;
skb->pkt_type = PACKET_HOST;
- vlan->receive(skb);
+ ret = vlan->receive(skb);
+
+out:
+ macvlan_count_rx(vlan, len, ret == NET_RX_SUCCESS, 0);
return NULL;
}
@@ -424,29 +434,38 @@ static void macvlan_uninit(struct net_device *dev)
free_percpu(vlan->rx_stats);
}
-static struct net_device_stats *macvlan_dev_get_stats(struct net_device *dev)
+static struct rtnl_link_stats64 *macvlan_dev_get_stats64(struct net_device *dev,
+ struct rtnl_link_stats64 *stats)
{
- struct net_device_stats *stats = &dev->stats;
struct macvlan_dev *vlan = netdev_priv(dev);
dev_txq_stats_fold(dev, stats);
if (vlan->rx_stats) {
- struct macvlan_rx_stats *p, rx = {0};
+ struct macvlan_rx_stats *p, accum = {0};
+ u64 rx_packets, rx_bytes, rx_multicast;
+ unsigned int start;
int i;
for_each_possible_cpu(i) {
p = per_cpu_ptr(vlan->rx_stats, i);
- rx.rx_packets += p->rx_packets;
- rx.rx_bytes += p->rx_bytes;
- rx.rx_errors += p->rx_errors;
- rx.multicast += p->multicast;
+ do {
+ start = u64_stats_fetch_begin_bh(&p->syncp);
+ rx_packets = p->rx_packets;
+ rx_bytes = p->rx_bytes;
+ rx_multicast = p->rx_multicast;
+ } while (u64_stats_fetch_retry_bh(&p->syncp, start));
+ accum.rx_packets += rx_packets;
+ accum.rx_bytes += rx_bytes;
+ accum.rx_multicast += rx_multicast;
+ /* rx_errors is an ulong, updated without syncp protection */
+ accum.rx_errors += p->rx_errors;
}
- stats->rx_packets = rx.rx_packets;
- stats->rx_bytes = rx.rx_bytes;
- stats->rx_errors = rx.rx_errors;
- stats->rx_dropped = rx.rx_errors;
- stats->multicast = rx.multicast;
+ stats->rx_packets = accum.rx_packets;
+ stats->rx_bytes = accum.rx_bytes;
+ stats->rx_errors = accum.rx_errors;
+ stats->rx_dropped = accum.rx_errors;
+ stats->multicast = accum.rx_multicast;
}
return stats;
}
@@ -495,7 +514,7 @@ static const struct net_device_ops macvlan_netdev_ops = {
.ndo_change_rx_flags = macvlan_change_rx_flags,
.ndo_set_mac_address = macvlan_set_mac_address,
.ndo_set_multicast_list = macvlan_set_multicast_list,
- .ndo_get_stats = macvlan_dev_get_stats,
+ .ndo_get_stats64 = macvlan_dev_get_stats64,
.ndo_validate_addr = eth_validate_addr,
};
@@ -521,6 +540,7 @@ static int macvlan_port_create(struct net_device *dev)
{
struct macvlan_port *port;
unsigned int i;
+ int err;
if (dev->type != ARPHRD_ETHER || dev->flags & IFF_LOOPBACK)
return -EINVAL;
@@ -533,19 +553,32 @@ static int macvlan_port_create(struct net_device *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;
+
+ err = netdev_rx_handler_register(dev, macvlan_handle_frame, port);
+ if (err)
+ kfree(port);
+
+ dev->priv_flags |= IFF_MACVLAN_PORT;
+ return err;
}
-static void macvlan_port_destroy(struct net_device *dev)
+static void macvlan_port_rcu_free(struct rcu_head *head)
{
- struct macvlan_port *port = dev->macvlan_port;
+ struct macvlan_port *port;
- rcu_assign_pointer(dev->macvlan_port, NULL);
- synchronize_rcu();
+ port = container_of(head, struct macvlan_port, rcu);
kfree(port);
}
+static void macvlan_port_destroy(struct net_device *dev)
+{
+ struct macvlan_port *port = macvlan_port_get(dev);
+
+ dev->priv_flags &= ~IFF_MACVLAN_PORT;
+ netdev_rx_handler_unregister(dev);
+ call_rcu(&port->rcu, macvlan_port_rcu_free);
+}
+
static int macvlan_validate(struct nlattr *tb[], struct nlattr *data[])
{
if (tb[IFLA_ADDRESS]) {
@@ -621,12 +654,12 @@ int macvlan_common_newlink(struct net *src_net, struct net_device *dev,
if (!tb[IFLA_ADDRESS])
random_ether_addr(dev->dev_addr);
- if (lowerdev->macvlan_port == NULL) {
+ if (!macvlan_port_exists(lowerdev)) {
err = macvlan_port_create(lowerdev);
if (err < 0)
return err;
}
- port = lowerdev->macvlan_port;
+ port = macvlan_port_get(lowerdev);
vlan->lowerdev = lowerdev;
vlan->dev = dev;
@@ -736,10 +769,11 @@ static int macvlan_device_event(struct notifier_block *unused,
struct macvlan_dev *vlan, *next;
struct macvlan_port *port;
- port = dev->macvlan_port;
- if (port == NULL)
+ if (!macvlan_port_exists(dev))
return NOTIFY_DONE;
+ port = macvlan_port_get(dev);
+
switch (event) {
case NETDEV_CHANGE:
list_for_each_entry(vlan, &port->vlans, list)
@@ -773,14 +807,12 @@ static int __init macvlan_init_module(void)
int err;
register_netdevice_notifier(&macvlan_notifier_block);
- macvlan_handle_frame_hook = macvlan_handle_frame;
err = macvlan_link_register(&macvlan_link_ops);
if (err < 0)
goto err1;
return 0;
err1:
- macvlan_handle_frame_hook = NULL;
unregister_netdevice_notifier(&macvlan_notifier_block);
return err;
}
@@ -788,7 +820,6 @@ err1:
static void __exit macvlan_cleanup_module(void)
{
rtnl_link_unregister(&macvlan_link_ops);
- macvlan_handle_frame_hook = NULL;
unregister_netdevice_notifier(&macvlan_notifier_block);
}
diff --git a/drivers/net/macvtap.c b/drivers/net/macvtap.c
index ff02b836c3c..3b1c54a9c6e 100644
--- a/drivers/net/macvtap.c
+++ b/drivers/net/macvtap.c
@@ -58,7 +58,7 @@ static struct proto macvtap_proto = {
* only has one tap, the interface numbers assure that the
* device nodes are unique.
*/
-static unsigned int macvtap_major;
+static dev_t macvtap_major;
#define MACVTAP_NUM_DEVS 65536
static struct class *macvtap_class;
static struct cdev macvtap_cdev;
diff --git a/drivers/net/mlx4/catas.c b/drivers/net/mlx4/catas.c
index f599294fa8a..68aaa42d0ce 100644
--- a/drivers/net/mlx4/catas.c
+++ b/drivers/net/mlx4/catas.c
@@ -101,8 +101,8 @@ static void catas_reset(struct work_struct *work)
ret = mlx4_restart_one(priv->dev.pdev);
/* 'priv' now is not valid */
if (ret)
- printk(KERN_ERR "mlx4 %s: Reset failed (%d)\n",
- pci_name(pdev), ret);
+ pr_err("mlx4 %s: Reset failed (%d)\n",
+ pci_name(pdev), ret);
else {
dev = pci_get_drvdata(pdev);
mlx4_dbg(dev, "Reset succeeded\n");
diff --git a/drivers/net/mlx4/en_ethtool.c b/drivers/net/mlx4/en_ethtool.c
index d5afd037cd7..b275238fe70 100644
--- a/drivers/net/mlx4/en_ethtool.c
+++ b/drivers/net/mlx4/en_ethtool.c
@@ -387,6 +387,42 @@ static void mlx4_en_get_ringparam(struct net_device *dev,
param->tx_pending = mdev->profile.prof[priv->port].tx_ring_size;
}
+static int mlx4_ethtool_op_set_flags(struct net_device *dev, u32 data)
+{
+ struct mlx4_en_priv *priv = netdev_priv(dev);
+ struct mlx4_en_dev *mdev = priv->mdev;
+ int rc = 0;
+ int changed = 0;
+
+ if (data & ~ETH_FLAG_LRO)
+ return -EOPNOTSUPP;
+
+ if (data & ETH_FLAG_LRO) {
+ if (mdev->profile.num_lro == 0)
+ return -EOPNOTSUPP;
+ if (!(dev->features & NETIF_F_LRO))
+ changed = 1;
+ } else if (dev->features & NETIF_F_LRO) {
+ changed = 1;
+ }
+
+ if (changed) {
+ if (netif_running(dev)) {
+ mutex_lock(&mdev->state_lock);
+ mlx4_en_stop_port(dev);
+ }
+ dev->features ^= NETIF_F_LRO;
+ if (netif_running(dev)) {
+ rc = mlx4_en_start_port(dev);
+ if (rc)
+ en_err(priv, "Failed to restart port\n");
+ mutex_unlock(&mdev->state_lock);
+ }
+ }
+
+ return rc;
+}
+
const struct ethtool_ops mlx4_en_ethtool_ops = {
.get_drvinfo = mlx4_en_get_drvinfo,
.get_settings = mlx4_en_get_settings,
@@ -415,7 +451,7 @@ const struct ethtool_ops mlx4_en_ethtool_ops = {
.get_ringparam = mlx4_en_get_ringparam,
.set_ringparam = mlx4_en_set_ringparam,
.get_flags = ethtool_op_get_flags,
- .set_flags = ethtool_op_set_flags,
+ .set_flags = mlx4_ethtool_op_set_flags,
};
diff --git a/drivers/net/mlx4/en_main.c b/drivers/net/mlx4/en_main.c
index cbabf14f95d..97934f1ec53 100644
--- a/drivers/net/mlx4/en_main.c
+++ b/drivers/net/mlx4/en_main.c
@@ -79,6 +79,29 @@ MLX4_EN_PARM_INT(pfctx, 0, "Priority based Flow Control policy on TX[7:0]."
MLX4_EN_PARM_INT(pfcrx, 0, "Priority based Flow Control policy on RX[7:0]."
" Per priority bit mask");
+int en_print(const char *level, const struct mlx4_en_priv *priv,
+ const char *format, ...)
+{
+ va_list args;
+ struct va_format vaf;
+ int i;
+
+ va_start(args, format);
+
+ vaf.fmt = format;
+ vaf.va = &args;
+ if (priv->registered)
+ i = printk("%s%s: %s: %pV",
+ level, DRV_NAME, priv->dev->name, &vaf);
+ else
+ i = printk("%s%s: %s: Port %d: %pV",
+ level, DRV_NAME, dev_name(&priv->mdev->pdev->dev),
+ priv->port, &vaf);
+ va_end(args);
+
+ return i;
+}
+
static int mlx4_en_get_profile(struct mlx4_en_dev *mdev)
{
struct mlx4_en_profile *params = &mdev->profile;
@@ -152,15 +175,11 @@ static void mlx4_en_remove(struct mlx4_dev *dev, void *endev_ptr)
static void *mlx4_en_add(struct mlx4_dev *dev)
{
- static int mlx4_en_version_printed;
struct mlx4_en_dev *mdev;
int i;
int err;
- if (!mlx4_en_version_printed) {
- printk(KERN_INFO "%s", mlx4_en_version);
- mlx4_en_version_printed++;
- }
+ printk_once(KERN_INFO "%s", mlx4_en_version);
mdev = kzalloc(sizeof *mdev, GFP_KERNEL);
if (!mdev) {
diff --git a/drivers/net/mlx4/en_netdev.c b/drivers/net/mlx4/en_netdev.c
index 96180c0ec20..a0d8a26f5a0 100644
--- a/drivers/net/mlx4/en_netdev.c
+++ b/drivers/net/mlx4/en_netdev.c
@@ -961,6 +961,7 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port,
}
SET_NETDEV_DEV(dev, &mdev->dev->pdev->dev);
+ dev->dev_id = port - 1;
/*
* Initialize driver private data
diff --git a/drivers/net/mlx4/eq.c b/drivers/net/mlx4/eq.c
index 423053482ed..6d7b2bf210c 100644
--- a/drivers/net/mlx4/eq.c
+++ b/drivers/net/mlx4/eq.c
@@ -110,7 +110,7 @@ struct mlx4_eqe {
u32 raw[6];
struct {
__be32 cqn;
- } __attribute__((packed)) comp;
+ } __packed comp;
struct {
u16 reserved1;
__be16 token;
@@ -118,27 +118,27 @@ struct mlx4_eqe {
u8 reserved3[3];
u8 status;
__be64 out_param;
- } __attribute__((packed)) cmd;
+ } __packed cmd;
struct {
__be32 qpn;
- } __attribute__((packed)) qp;
+ } __packed qp;
struct {
__be32 srqn;
- } __attribute__((packed)) srq;
+ } __packed srq;
struct {
__be32 cqn;
u32 reserved1;
u8 reserved2[3];
u8 syndrome;
- } __attribute__((packed)) cq_err;
+ } __packed cq_err;
struct {
u32 reserved1[2];
__be32 port;
- } __attribute__((packed)) port_change;
+ } __packed port_change;
} event;
u8 reserved3[3];
u8 owner;
-} __attribute__((packed));
+} __packed;
static void eq_set_ci(struct mlx4_eq *eq, int req_not)
{
@@ -475,10 +475,10 @@ static void mlx4_free_eq(struct mlx4_dev *dev,
mlx4_dbg(dev, "Dumping EQ context %02x:\n", eq->eqn);
for (i = 0; i < sizeof (struct mlx4_eq_context) / 4; ++i) {
if (i % 4 == 0)
- printk("[%02x] ", i * 4);
- printk(" %08x", be32_to_cpup(mailbox->buf + i * 4));
+ pr_cont("[%02x] ", i * 4);
+ pr_cont(" %08x", be32_to_cpup(mailbox->buf + i * 4));
if ((i + 1) % 4 == 0)
- printk("\n");
+ pr_cont("\n");
}
}
diff --git a/drivers/net/mlx4/main.c b/drivers/net/mlx4/main.c
index e3e0d54a7c8..5102ab1ac56 100644
--- a/drivers/net/mlx4/main.c
+++ b/drivers/net/mlx4/main.c
@@ -1050,8 +1050,7 @@ static int __mlx4_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
int err;
int port;
- printk(KERN_INFO PFX "Initializing %s\n",
- pci_name(pdev));
+ pr_info(DRV_NAME ": Initializing %s\n", pci_name(pdev));
err = pci_enable_device(pdev);
if (err) {
@@ -1216,12 +1215,7 @@ err_disable_pdev:
static int __devinit mlx4_init_one(struct pci_dev *pdev,
const struct pci_device_id *id)
{
- static int mlx4_version_printed;
-
- if (!mlx4_version_printed) {
- printk(KERN_INFO "%s", mlx4_version);
- ++mlx4_version_printed;
- }
+ printk_once(KERN_INFO "%s", mlx4_version);
return __mlx4_init_one(pdev, id);
}
@@ -1301,17 +1295,17 @@ static struct pci_driver mlx4_driver = {
static int __init mlx4_verify_params(void)
{
if ((log_num_mac < 0) || (log_num_mac > 7)) {
- printk(KERN_WARNING "mlx4_core: bad num_mac: %d\n", log_num_mac);
+ pr_warning("mlx4_core: bad num_mac: %d\n", log_num_mac);
return -1;
}
if ((log_num_vlan < 0) || (log_num_vlan > 7)) {
- printk(KERN_WARNING "mlx4_core: bad num_vlan: %d\n", log_num_vlan);
+ pr_warning("mlx4_core: bad num_vlan: %d\n", log_num_vlan);
return -1;
}
if ((log_mtts_per_seg < 1) || (log_mtts_per_seg > 5)) {
- printk(KERN_WARNING "mlx4_core: bad log_mtts_per_seg: %d\n", log_mtts_per_seg);
+ pr_warning("mlx4_core: bad log_mtts_per_seg: %d\n", log_mtts_per_seg);
return -1;
}
diff --git a/drivers/net/mlx4/mlx4.h b/drivers/net/mlx4/mlx4.h
index 13343e88499..0da5bb7285b 100644
--- a/drivers/net/mlx4/mlx4.h
+++ b/drivers/net/mlx4/mlx4.h
@@ -48,7 +48,6 @@
#include <linux/mlx4/doorbell.h>
#define DRV_NAME "mlx4_core"
-#define PFX DRV_NAME ": "
#define DRV_VERSION "0.01"
#define DRV_RELDATE "May 1, 2007"
@@ -88,17 +87,17 @@ extern int mlx4_debug_level;
#endif /* CONFIG_MLX4_DEBUG */
#define mlx4_dbg(mdev, format, arg...) \
- do { \
- if (mlx4_debug_level) \
- dev_printk(KERN_DEBUG, &mdev->pdev->dev, format, ## arg); \
- } while (0)
+do { \
+ if (mlx4_debug_level) \
+ dev_printk(KERN_DEBUG, &mdev->pdev->dev, format, ##arg); \
+} while (0)
#define mlx4_err(mdev, format, arg...) \
- dev_err(&mdev->pdev->dev, format, ## arg)
+ dev_err(&mdev->pdev->dev, format, ##arg)
#define mlx4_info(mdev, format, arg...) \
- dev_info(&mdev->pdev->dev, format, ## arg)
+ dev_info(&mdev->pdev->dev, format, ##arg)
#define mlx4_warn(mdev, format, arg...) \
- dev_warn(&mdev->pdev->dev, format, ## arg)
+ dev_warn(&mdev->pdev->dev, format, ##arg)
struct mlx4_bitmap {
u32 last;
diff --git a/drivers/net/mlx4/mlx4_en.h b/drivers/net/mlx4/mlx4_en.h
index b55e46c8b68..449210994ee 100644
--- a/drivers/net/mlx4/mlx4_en.h
+++ b/drivers/net/mlx4/mlx4_en.h
@@ -52,40 +52,8 @@
#define DRV_VERSION "1.4.1.1"
#define DRV_RELDATE "June 2009"
-
#define MLX4_EN_MSG_LEVEL (NETIF_MSG_LINK | NETIF_MSG_IFDOWN)
-#define en_print(level, priv, format, arg...) \
- { \
- if ((priv)->registered) \
- printk(level "%s: %s: " format, DRV_NAME, \
- (priv->dev)->name, ## arg); \
- else \
- printk(level "%s: %s: Port %d: " format, \
- DRV_NAME, dev_name(&priv->mdev->pdev->dev), \
- (priv)->port, ## arg); \
- }
-
-#define en_dbg(mlevel, priv, format, arg...) \
- { \
- if (NETIF_MSG_##mlevel & priv->msg_enable) \
- en_print(KERN_DEBUG, priv, format, ## arg) \
- }
-#define en_warn(priv, format, arg...) \
- en_print(KERN_WARNING, priv, format, ## arg)
-#define en_err(priv, format, arg...) \
- en_print(KERN_ERR, priv, format, ## arg)
-
-#define mlx4_err(mdev, format, arg...) \
- printk(KERN_ERR "%s %s: " format , DRV_NAME ,\
- dev_name(&mdev->pdev->dev) , ## arg)
-#define mlx4_info(mdev, format, arg...) \
- printk(KERN_INFO "%s %s: " format , DRV_NAME ,\
- dev_name(&mdev->pdev->dev) , ## arg)
-#define mlx4_warn(mdev, format, arg...) \
- printk(KERN_WARNING "%s %s: " format , DRV_NAME ,\
- dev_name(&mdev->pdev->dev) , ## arg)
-
/*
* Device constants
*/
@@ -568,4 +536,34 @@ int mlx4_en_DUMP_ETH_STATS(struct mlx4_en_dev *mdev, u8 port, u8 reset);
* Globals
*/
extern const struct ethtool_ops mlx4_en_ethtool_ops;
+
+
+
+/*
+ * printk / logging functions
+ */
+
+int en_print(const char *level, const struct mlx4_en_priv *priv,
+ const char *format, ...) __attribute__ ((format (printf, 3, 4)));
+
+#define en_dbg(mlevel, priv, format, arg...) \
+do { \
+ if (NETIF_MSG_##mlevel & priv->msg_enable) \
+ en_print(KERN_DEBUG, priv, format, ##arg); \
+} while (0)
+#define en_warn(priv, format, arg...) \
+ en_print(KERN_WARNING, priv, format, ##arg)
+#define en_err(priv, format, arg...) \
+ en_print(KERN_ERR, priv, format, ##arg)
+
+#define mlx4_err(mdev, format, arg...) \
+ pr_err("%s %s: " format, DRV_NAME, \
+ dev_name(&mdev->pdev->dev), ##arg)
+#define mlx4_info(mdev, format, arg...) \
+ pr_info("%s %s: " format, DRV_NAME, \
+ dev_name(&mdev->pdev->dev), ##arg)
+#define mlx4_warn(mdev, format, arg...) \
+ pr_warning("%s %s: " format, DRV_NAME, \
+ dev_name(&mdev->pdev->dev), ##arg)
+
#endif
diff --git a/drivers/net/mlx4/mr.c b/drivers/net/mlx4/mr.c
index 3dc69be4949..9c188bdd7f4 100644
--- a/drivers/net/mlx4/mr.c
+++ b/drivers/net/mlx4/mr.c
@@ -58,7 +58,7 @@ struct mlx4_mpt_entry {
__be32 mtt_sz;
__be32 entity_size;
__be32 first_byte_offset;
-} __attribute__((packed));
+} __packed;
#define MLX4_MPT_FLAG_SW_OWNS (0xfUL << 28)
#define MLX4_MPT_FLAG_FREE (0x3UL << 28)
diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c
index 73bb8ea6f54..2d488abcf62 100644
--- a/drivers/net/mv643xx_eth.c
+++ b/drivers/net/mv643xx_eth.c
@@ -1640,6 +1640,11 @@ static void mv643xx_eth_get_ethtool_stats(struct net_device *dev,
}
}
+static int mv643xx_eth_set_flags(struct net_device *dev, u32 data)
+{
+ return ethtool_op_set_flags(dev, data, ETH_FLAG_LRO);
+}
+
static int mv643xx_eth_get_sset_count(struct net_device *dev, int sset)
{
if (sset == ETH_SS_STATS)
@@ -1665,7 +1670,7 @@ static const struct ethtool_ops mv643xx_eth_ethtool_ops = {
.get_strings = mv643xx_eth_get_strings,
.get_ethtool_stats = mv643xx_eth_get_ethtool_stats,
.get_flags = ethtool_op_get_flags,
- .set_flags = ethtool_op_set_flags,
+ .set_flags = mv643xx_eth_set_flags,
.get_sset_count = mv643xx_eth_get_sset_count,
};
@@ -2456,7 +2461,7 @@ static int mv643xx_eth_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
struct mv643xx_eth_private *mp = netdev_priv(dev);
if (mp->phy != NULL)
- return phy_mii_ioctl(mp->phy, if_mii(ifr), cmd);
+ return phy_mii_ioctl(mp->phy, ifr, cmd);
return -EOPNOTSUPP;
}
@@ -2670,7 +2675,8 @@ static int mv643xx_eth_shared_probe(struct platform_device *pdev)
* Detect hardware parameters.
*/
msp->t_clk = (pd != NULL && pd->t_clk != 0) ? pd->t_clk : 133000000;
- msp->tx_csum_limit = pd->tx_csum_limit ? pd->tx_csum_limit : 9 * 1024;
+ msp->tx_csum_limit = (pd != NULL && pd->tx_csum_limit) ?
+ pd->tx_csum_limit : 9 * 1024;
infer_hw_params(msp);
platform_set_drvdata(pdev, msp);
diff --git a/drivers/net/myri10ge/myri10ge.c b/drivers/net/myri10ge/myri10ge.c
index e0b47cc8a86..d771d1650d6 100644
--- a/drivers/net/myri10ge/myri10ge.c
+++ b/drivers/net/myri10ge/myri10ge.c
@@ -1730,8 +1730,7 @@ static int myri10ge_set_rx_csum(struct net_device *netdev, u32 csum_enabled)
if (csum_enabled)
mgp->csum_flag = MXGEFW_FLAGS_CKSUM;
else {
- u32 flags = ethtool_op_get_flags(netdev);
- err = ethtool_op_set_flags(netdev, (flags & ~ETH_FLAG_LRO));
+ netdev->features &= ~NETIF_F_LRO;
mgp->csum_flag = 0;
}
@@ -1900,6 +1899,11 @@ static u32 myri10ge_get_msglevel(struct net_device *netdev)
return mgp->msg_enable;
}
+static int myri10ge_set_flags(struct net_device *netdev, u32 value)
+{
+ return ethtool_op_set_flags(netdev, value, ETH_FLAG_LRO);
+}
+
static const struct ethtool_ops myri10ge_ethtool_ops = {
.get_settings = myri10ge_get_settings,
.get_drvinfo = myri10ge_get_drvinfo,
@@ -1920,7 +1924,7 @@ static const struct ethtool_ops myri10ge_ethtool_ops = {
.set_msglevel = myri10ge_set_msglevel,
.get_msglevel = myri10ge_get_msglevel,
.get_flags = ethtool_op_get_flags,
- .set_flags = ethtool_op_set_flags
+ .set_flags = myri10ge_set_flags
};
static int myri10ge_allocate_rings(struct myri10ge_slice_state *ss)
diff --git a/drivers/net/myri_sbus.c b/drivers/net/myri_sbus.c
index 1a57c3da1f4..04e552aa14e 100644
--- a/drivers/net/myri_sbus.c
+++ b/drivers/net/myri_sbus.c
@@ -1079,7 +1079,7 @@ static int __devinit myri_sbus_probe(struct of_device *op, const struct of_devic
mp->dev = dev;
dev->watchdog_timeo = 5*HZ;
- dev->irq = op->irqs[0];
+ dev->irq = op->archdata.irqs[0];
dev->netdev_ops = &myri_ops;
/* Register interrupt handler now. */
@@ -1172,12 +1172,12 @@ static struct of_platform_driver myri_sbus_driver = {
static int __init myri_sbus_init(void)
{
- return of_register_driver(&myri_sbus_driver, &of_bus_type);
+ return of_register_platform_driver(&myri_sbus_driver);
}
static void __exit myri_sbus_exit(void)
{
- of_unregister_driver(&myri_sbus_driver);
+ of_unregister_platform_driver(&myri_sbus_driver);
}
module_init(myri_sbus_init);
diff --git a/drivers/net/natsemi.c b/drivers/net/natsemi.c
index 2a17b503fea..a6033d48b5c 100644
--- a/drivers/net/natsemi.c
+++ b/drivers/net/natsemi.c
@@ -548,7 +548,6 @@ struct netdev_private {
dma_addr_t tx_dma[TX_RING_SIZE];
struct net_device *dev;
struct napi_struct napi;
- struct net_device_stats stats;
/* Media monitoring timer */
struct timer_list timer;
/* Frequently used values: keep some adjacent for cache effect */
@@ -1906,7 +1905,7 @@ static void ns_tx_timeout(struct net_device *dev)
enable_irq(dev->irq);
dev->trans_start = jiffies; /* prevent tx timeout */
- np->stats.tx_errors++;
+ dev->stats.tx_errors++;
netif_wake_queue(dev);
}
@@ -2009,7 +2008,7 @@ static void drain_tx(struct net_device *dev)
np->tx_dma[i], np->tx_skbuff[i]->len,
PCI_DMA_TODEVICE);
dev_kfree_skb(np->tx_skbuff[i]);
- np->stats.tx_dropped++;
+ dev->stats.tx_dropped++;
}
np->tx_skbuff[i] = NULL;
}
@@ -2115,7 +2114,7 @@ static netdev_tx_t start_tx(struct sk_buff *skb, struct net_device *dev)
writel(TxOn, ioaddr + ChipCmd);
} else {
dev_kfree_skb_irq(skb);
- np->stats.tx_dropped++;
+ dev->stats.tx_dropped++;
}
spin_unlock_irqrestore(&np->lock, flags);
@@ -2140,20 +2139,20 @@ static void netdev_tx_done(struct net_device *dev)
dev->name, np->dirty_tx,
le32_to_cpu(np->tx_ring[entry].cmd_status));
if (np->tx_ring[entry].cmd_status & cpu_to_le32(DescPktOK)) {
- np->stats.tx_packets++;
- np->stats.tx_bytes += np->tx_skbuff[entry]->len;
+ dev->stats.tx_packets++;
+ dev->stats.tx_bytes += np->tx_skbuff[entry]->len;
} else { /* Various Tx errors */
int tx_status =
le32_to_cpu(np->tx_ring[entry].cmd_status);
if (tx_status & (DescTxAbort|DescTxExcColl))
- np->stats.tx_aborted_errors++;
+ dev->stats.tx_aborted_errors++;
if (tx_status & DescTxFIFO)
- np->stats.tx_fifo_errors++;
+ dev->stats.tx_fifo_errors++;
if (tx_status & DescTxCarrier)
- np->stats.tx_carrier_errors++;
+ dev->stats.tx_carrier_errors++;
if (tx_status & DescTxOOWCol)
- np->stats.tx_window_errors++;
- np->stats.tx_errors++;
+ dev->stats.tx_window_errors++;
+ dev->stats.tx_errors++;
}
pci_unmap_single(np->pci_dev,np->tx_dma[entry],
np->tx_skbuff[entry]->len,
@@ -2301,7 +2300,7 @@ static void netdev_rx(struct net_device *dev, int *work_done, int work_to_do)
"buffers, entry %#08x "
"status %#08x.\n", dev->name,
np->cur_rx, desc_status);
- np->stats.rx_length_errors++;
+ dev->stats.rx_length_errors++;
/* The RX state machine has probably
* locked up beneath us. Follow the
@@ -2321,15 +2320,15 @@ static void netdev_rx(struct net_device *dev, int *work_done, int work_to_do)
} else {
/* There was an error. */
- np->stats.rx_errors++;
+ dev->stats.rx_errors++;
if (desc_status & (DescRxAbort|DescRxOver))
- np->stats.rx_over_errors++;
+ dev->stats.rx_over_errors++;
if (desc_status & (DescRxLong|DescRxRunt))
- np->stats.rx_length_errors++;
+ dev->stats.rx_length_errors++;
if (desc_status & (DescRxInvalid|DescRxAlign))
- np->stats.rx_frame_errors++;
+ dev->stats.rx_frame_errors++;
if (desc_status & DescRxCRC)
- np->stats.rx_crc_errors++;
+ dev->stats.rx_crc_errors++;
}
} else if (pkt_len > np->rx_buf_sz) {
/* if this is the tail of a double buffer
@@ -2364,8 +2363,8 @@ static void netdev_rx(struct net_device *dev, int *work_done, int work_to_do)
}
skb->protocol = eth_type_trans(skb, dev);
netif_receive_skb(skb);
- np->stats.rx_packets++;
- np->stats.rx_bytes += pkt_len;
+ dev->stats.rx_packets++;
+ dev->stats.rx_bytes += pkt_len;
}
entry = (++np->cur_rx) % RX_RING_SIZE;
np->rx_head_desc = &np->rx_ring[entry];
@@ -2428,17 +2427,17 @@ static void netdev_error(struct net_device *dev, int intr_status)
printk(KERN_NOTICE "%s: Rx status FIFO overrun\n",
dev->name);
}
- np->stats.rx_fifo_errors++;
- np->stats.rx_errors++;
+ dev->stats.rx_fifo_errors++;
+ dev->stats.rx_errors++;
}
/* Hmmmmm, it's not clear how to recover from PCI faults. */
if (intr_status & IntrPCIErr) {
printk(KERN_NOTICE "%s: PCI error %#08x\n", dev->name,
intr_status & IntrPCIErr);
- np->stats.tx_fifo_errors++;
- np->stats.tx_errors++;
- np->stats.rx_fifo_errors++;
- np->stats.rx_errors++;
+ dev->stats.tx_fifo_errors++;
+ dev->stats.tx_errors++;
+ dev->stats.rx_fifo_errors++;
+ dev->stats.rx_errors++;
}
spin_unlock(&np->lock);
}
@@ -2446,11 +2445,10 @@ static void netdev_error(struct net_device *dev, int intr_status)
static void __get_stats(struct net_device *dev)
{
void __iomem * ioaddr = ns_ioaddr(dev);
- struct netdev_private *np = netdev_priv(dev);
/* The chip only need report frame silently dropped. */
- np->stats.rx_crc_errors += readl(ioaddr + RxCRCErrs);
- np->stats.rx_missed_errors += readl(ioaddr + RxMissed);
+ dev->stats.rx_crc_errors += readl(ioaddr + RxCRCErrs);
+ dev->stats.rx_missed_errors += readl(ioaddr + RxMissed);
}
static struct net_device_stats *get_stats(struct net_device *dev)
@@ -2463,7 +2461,7 @@ static struct net_device_stats *get_stats(struct net_device *dev)
__get_stats(dev);
spin_unlock_irq(&np->lock);
- return &np->stats;
+ return &dev->stats;
}
#ifdef CONFIG_NET_POLL_CONTROLLER
diff --git a/drivers/net/netxen/netxen_nic_ctx.c b/drivers/net/netxen/netxen_nic_ctx.c
index 3a41b6a84a6..12612127a08 100644
--- a/drivers/net/netxen/netxen_nic_ctx.c
+++ b/drivers/net/netxen/netxen_nic_ctx.c
@@ -255,6 +255,19 @@ out_free_rq:
}
static void
+nx_fw_cmd_reset_ctx(struct netxen_adapter *adapter)
+{
+
+ netxen_issue_cmd(adapter, adapter->ahw.pci_func, NXHAL_VERSION,
+ adapter->ahw.pci_func, NX_DESTROY_CTX_RESET, 0,
+ NX_CDRP_CMD_DESTROY_RX_CTX);
+
+ netxen_issue_cmd(adapter, adapter->ahw.pci_func, NXHAL_VERSION,
+ adapter->ahw.pci_func, NX_DESTROY_CTX_RESET, 0,
+ NX_CDRP_CMD_DESTROY_TX_CTX);
+}
+
+static void
nx_fw_cmd_destroy_rx_ctx(struct netxen_adapter *adapter)
{
struct netxen_recv_context *recv_ctx = &adapter->recv_ctx;
@@ -685,7 +698,8 @@ int netxen_alloc_hw_resources(struct netxen_adapter *adapter)
if (!NX_IS_REVISION_P2(adapter->ahw.revision_id)) {
if (test_and_set_bit(__NX_FW_ATTACHED, &adapter->state))
goto done;
-
+ if (reset_devices)
+ nx_fw_cmd_reset_ctx(adapter);
err = nx_fw_cmd_create_rx_ctx(adapter);
if (err)
goto err_out_free;
diff --git a/drivers/net/netxen/netxen_nic_ethtool.c b/drivers/net/netxen/netxen_nic_ethtool.c
index 20f7c58bd09..b30de24f4a5 100644
--- a/drivers/net/netxen/netxen_nic_ethtool.c
+++ b/drivers/net/netxen/netxen_nic_ethtool.c
@@ -887,12 +887,19 @@ static int netxen_nic_set_flags(struct net_device *netdev, u32 data)
struct netxen_adapter *adapter = netdev_priv(netdev);
int hw_lro;
- if (!(adapter->capabilities & NX_FW_CAPABILITY_HW_LRO))
+ if (data & ~ETH_FLAG_LRO)
return -EINVAL;
- ethtool_op_set_flags(netdev, data);
+ if (!(adapter->capabilities & NX_FW_CAPABILITY_HW_LRO))
+ return -EINVAL;
- hw_lro = (data & ETH_FLAG_LRO) ? NETXEN_NIC_LRO_ENABLED : 0;
+ if (data & ETH_FLAG_LRO) {
+ hw_lro = NETXEN_NIC_LRO_ENABLED;
+ netdev->features |= NETIF_F_LRO;
+ } else {
+ hw_lro = 0;
+ netdev->features &= ~NETIF_F_LRO;
+ }
if (netxen_config_hw_lro(adapter, hw_lro))
return -EIO;
diff --git a/drivers/net/ni52.c b/drivers/net/ni52.c
index 9bddb5fa7a9..33618edc61f 100644
--- a/drivers/net/ni52.c
+++ b/drivers/net/ni52.c
@@ -185,7 +185,6 @@ static void ni52_xmt_int(struct net_device *dev);
static void ni52_rnr_int(struct net_device *dev);
struct priv {
- struct net_device_stats stats;
char __iomem *base;
char __iomem *mapped;
char __iomem *memtop;
@@ -972,10 +971,10 @@ static void ni52_rcv_int(struct net_device *dev)
memcpy_fromio(skb->data, p->base + readl(&rbd->buffer), totlen);
skb->protocol = eth_type_trans(skb, dev);
netif_rx(skb);
- p->stats.rx_packets++;
- p->stats.rx_bytes += totlen;
+ dev->stats.rx_packets++;
+ dev->stats.rx_bytes += totlen;
} else
- p->stats.rx_dropped++;
+ dev->stats.rx_dropped++;
} else {
int rstat;
/* free all RBD's until RBD_LAST is set */
@@ -993,12 +992,12 @@ static void ni52_rcv_int(struct net_device *dev)
writew(0, &rbd->status);
printk(KERN_ERR "%s: received oversized frame! length: %d\n",
dev->name, totlen);
- p->stats.rx_dropped++;
+ dev->stats.rx_dropped++;
}
} else {/* frame !(ok), only with 'save-bad-frames' */
printk(KERN_ERR "%s: oops! rfd-error-status: %04x\n",
dev->name, status);
- p->stats.rx_errors++;
+ dev->stats.rx_errors++;
}
writeb(0, &p->rfd_top->stat_high);
writeb(RFD_SUSP, &p->rfd_top->last); /* maybe exchange by RFD_LAST */
@@ -1043,7 +1042,7 @@ static void ni52_rnr_int(struct net_device *dev)
{
struct priv *p = netdev_priv(dev);
- p->stats.rx_errors++;
+ dev->stats.rx_errors++;
wait_for_scb_cmd(dev); /* wait for the last cmd, WAIT_4_FULLSTAT?? */
writeb(RUC_ABORT, &p->scb->cmd_ruc); /* usually the RU is in the 'no resource'-state .. abort it now. */
@@ -1076,29 +1075,29 @@ static void ni52_xmt_int(struct net_device *dev)
printk(KERN_ERR "%s: strange .. xmit-int without a 'COMPLETE'\n", dev->name);
if (status & STAT_OK) {
- p->stats.tx_packets++;
- p->stats.collisions += (status & TCMD_MAXCOLLMASK);
+ dev->stats.tx_packets++;
+ dev->stats.collisions += (status & TCMD_MAXCOLLMASK);
} else {
- p->stats.tx_errors++;
+ dev->stats.tx_errors++;
if (status & TCMD_LATECOLL) {
printk(KERN_ERR "%s: late collision detected.\n",
dev->name);
- p->stats.collisions++;
+ dev->stats.collisions++;
} else if (status & TCMD_NOCARRIER) {
- p->stats.tx_carrier_errors++;
+ dev->stats.tx_carrier_errors++;
printk(KERN_ERR "%s: no carrier detected.\n",
dev->name);
} else if (status & TCMD_LOSTCTS)
printk(KERN_ERR "%s: loss of CTS detected.\n",
dev->name);
else if (status & TCMD_UNDERRUN) {
- p->stats.tx_fifo_errors++;
+ dev->stats.tx_fifo_errors++;
printk(KERN_ERR "%s: DMA underrun detected.\n",
dev->name);
} else if (status & TCMD_MAXCOLL) {
printk(KERN_ERR "%s: Max. collisions exceeded.\n",
dev->name);
- p->stats.collisions += 16;
+ dev->stats.collisions += 16;
}
}
#if (NUM_XMIT_BUFFS > 1)
@@ -1286,12 +1285,12 @@ static struct net_device_stats *ni52_get_stats(struct net_device *dev)
ovrn = readw(&p->scb->ovrn_errs);
writew(0, &p->scb->ovrn_errs);
- p->stats.rx_crc_errors += crc;
- p->stats.rx_fifo_errors += ovrn;
- p->stats.rx_frame_errors += aln;
- p->stats.rx_dropped += rsc;
+ dev->stats.rx_crc_errors += crc;
+ dev->stats.rx_fifo_errors += ovrn;
+ dev->stats.rx_frame_errors += aln;
+ dev->stats.rx_dropped += rsc;
- return &p->stats;
+ return &dev->stats;
}
/********************************************************
diff --git a/drivers/net/niu.c b/drivers/net/niu.c
index 63e8e3893bd..404f2d55288 100644
--- a/drivers/net/niu.c
+++ b/drivers/net/niu.c
@@ -28,10 +28,7 @@
#include <linux/slab.h>
#include <linux/io.h>
-
-#ifdef CONFIG_SPARC64
#include <linux/of_device.h>
-#endif
#include "niu.h"
@@ -3330,10 +3327,12 @@ static struct page *niu_find_rxpage(struct rx_ring_info *rp, u64 addr,
for (; (p = *pp) != NULL; pp = (struct page **) &p->mapping) {
if (p->index == addr) {
*link = pp;
- break;
+ goto found;
}
}
+ BUG();
+found:
return p;
}
@@ -7920,14 +7919,7 @@ static int niu_phys_id(struct net_device *dev, u32 data)
static int niu_set_flags(struct net_device *dev, u32 data)
{
- if (data & (ETH_FLAG_LRO | ETH_FLAG_NTUPLE))
- return -EOPNOTSUPP;
-
- if (data & ETH_FLAG_RXHASH)
- dev->features |= NETIF_F_RXHASH;
- else
- dev->features &= ~NETIF_F_RXHASH;
- return 0;
+ return ethtool_op_set_flags(dev, data, ETH_FLAG_RXHASH);
}
static const struct ethtool_ops niu_ethtool_ops = {
@@ -9119,12 +9111,12 @@ static int __devinit niu_n2_irq_init(struct niu *np, u8 *ldg_num_map)
if (!int_prop)
return -ENODEV;
- for (i = 0; i < op->num_irqs; i++) {
+ for (i = 0; i < op->archdata.num_irqs; i++) {
ldg_num_map[i] = int_prop[i];
- np->ldg[i].irq = op->irqs[i];
+ np->ldg[i].irq = op->archdata.irqs[i];
}
- np->num_ldg = op->num_irqs;
+ np->num_ldg = op->archdata.num_irqs;
return 0;
#else
@@ -10254,14 +10246,14 @@ static int __init niu_init(void)
niu_debug = netif_msg_init(debug, NIU_MSG_DEFAULT);
#ifdef CONFIG_SPARC64
- err = of_register_driver(&niu_of_driver, &of_bus_type);
+ err = of_register_platform_driver(&niu_of_driver);
#endif
if (!err) {
err = pci_register_driver(&niu_pci_driver);
#ifdef CONFIG_SPARC64
if (err)
- of_unregister_driver(&niu_of_driver);
+ of_unregister_platform_driver(&niu_of_driver);
#endif
}
@@ -10272,7 +10264,7 @@ static void __exit niu_exit(void)
{
pci_unregister_driver(&niu_pci_driver);
#ifdef CONFIG_SPARC64
- of_unregister_driver(&niu_of_driver);
+ of_unregister_platform_driver(&niu_of_driver);
#endif
}
diff --git a/drivers/net/niu.h b/drivers/net/niu.h
index d6715465f35..a41fa8ebe05 100644
--- a/drivers/net/niu.h
+++ b/drivers/net/niu.h
@@ -3236,7 +3236,7 @@ struct niu_phy_ops {
int (*link_status)(struct niu *np, int *);
};
-struct of_device;
+struct platform_device;
struct niu {
void __iomem *regs;
struct net_device *dev;
@@ -3297,7 +3297,7 @@ struct niu {
struct niu_vpd vpd;
u32 eeprom_len;
- struct of_device *op;
+ struct platform_device *op;
void __iomem *vir_regs_1;
void __iomem *vir_regs_2;
};
diff --git a/drivers/net/ns83820.c b/drivers/net/ns83820.c
index e88e97cd1b1..5a3488f76b3 100644
--- a/drivers/net/ns83820.c
+++ b/drivers/net/ns83820.c
@@ -424,7 +424,6 @@ struct rx_info {
struct ns83820 {
- struct net_device_stats stats;
u8 __iomem *base;
struct pci_dev *pci_dev;
@@ -918,9 +917,9 @@ static void rx_irq(struct net_device *ndev)
if (unlikely(!skb))
goto netdev_mangle_me_harder_failed;
if (cmdsts & CMDSTS_DEST_MULTI)
- dev->stats.multicast ++;
- dev->stats.rx_packets ++;
- dev->stats.rx_bytes += len;
+ ndev->stats.multicast++;
+ ndev->stats.rx_packets++;
+ ndev->stats.rx_bytes += len;
if ((extsts & 0x002a0000) && !(extsts & 0x00540000)) {
skb->ip_summed = CHECKSUM_UNNECESSARY;
} else {
@@ -940,7 +939,7 @@ static void rx_irq(struct net_device *ndev)
#endif
if (NET_RX_DROP == rx_rc) {
netdev_mangle_me_harder_failed:
- dev->stats.rx_dropped ++;
+ ndev->stats.rx_dropped++;
}
} else {
kfree_skb(skb);
@@ -1008,11 +1007,11 @@ static void do_tx_done(struct net_device *ndev)
dma_addr_t addr;
if (cmdsts & CMDSTS_ERR)
- dev->stats.tx_errors ++;
+ ndev->stats.tx_errors++;
if (cmdsts & CMDSTS_OK)
- dev->stats.tx_packets ++;
+ ndev->stats.tx_packets++;
if (cmdsts & CMDSTS_OK)
- dev->stats.tx_bytes += cmdsts & 0xffff;
+ ndev->stats.tx_bytes += cmdsts & 0xffff;
dprintk("tx_done_idx=%d free_idx=%d cmdsts=%08x\n",
tx_done_idx, dev->tx_free_idx, cmdsts);
@@ -1212,20 +1211,21 @@ again:
static void ns83820_update_stats(struct ns83820 *dev)
{
+ struct net_device *ndev = dev->ndev;
u8 __iomem *base = dev->base;
/* the DP83820 will freeze counters, so we need to read all of them */
- dev->stats.rx_errors += readl(base + 0x60) & 0xffff;
- dev->stats.rx_crc_errors += readl(base + 0x64) & 0xffff;
- dev->stats.rx_missed_errors += readl(base + 0x68) & 0xffff;
- dev->stats.rx_frame_errors += readl(base + 0x6c) & 0xffff;
- /*dev->stats.rx_symbol_errors +=*/ readl(base + 0x70);
- dev->stats.rx_length_errors += readl(base + 0x74) & 0xffff;
- dev->stats.rx_length_errors += readl(base + 0x78) & 0xffff;
- /*dev->stats.rx_badopcode_errors += */ readl(base + 0x7c);
- /*dev->stats.rx_pause_count += */ readl(base + 0x80);
- /*dev->stats.tx_pause_count += */ readl(base + 0x84);
- dev->stats.tx_carrier_errors += readl(base + 0x88) & 0xff;
+ ndev->stats.rx_errors += readl(base + 0x60) & 0xffff;
+ ndev->stats.rx_crc_errors += readl(base + 0x64) & 0xffff;
+ ndev->stats.rx_missed_errors += readl(base + 0x68) & 0xffff;
+ ndev->stats.rx_frame_errors += readl(base + 0x6c) & 0xffff;
+ /*ndev->stats.rx_symbol_errors +=*/ readl(base + 0x70);
+ ndev->stats.rx_length_errors += readl(base + 0x74) & 0xffff;
+ ndev->stats.rx_length_errors += readl(base + 0x78) & 0xffff;
+ /*ndev->stats.rx_badopcode_errors += */ readl(base + 0x7c);
+ /*ndev->stats.rx_pause_count += */ readl(base + 0x80);
+ /*ndev->stats.tx_pause_count += */ readl(base + 0x84);
+ ndev->stats.tx_carrier_errors += readl(base + 0x88) & 0xff;
}
static struct net_device_stats *ns83820_get_stats(struct net_device *ndev)
@@ -1237,7 +1237,7 @@ static struct net_device_stats *ns83820_get_stats(struct net_device *ndev)
ns83820_update_stats(dev);
spin_unlock_irq(&dev->misc_lock);
- return &dev->stats;
+ return &ndev->stats;
}
/* Let ethtool retrieve info */
@@ -1464,12 +1464,12 @@ static void ns83820_do_isr(struct net_device *ndev, u32 isr)
if (unlikely(ISR_RXSOVR & isr)) {
//printk("overrun: rxsovr\n");
- dev->stats.rx_fifo_errors ++;
+ ndev->stats.rx_fifo_errors++;
}
if (unlikely(ISR_RXORN & isr)) {
//printk("overrun: rxorn\n");
- dev->stats.rx_fifo_errors ++;
+ ndev->stats.rx_fifo_errors++;
}
if ((ISR_RXRCMP & isr) && dev->rx_info.up)
diff --git a/drivers/net/octeon/octeon_mgmt.c b/drivers/net/octeon/octeon_mgmt.c
index 000e792d57c..b264f0f4560 100644
--- a/drivers/net/octeon/octeon_mgmt.c
+++ b/drivers/net/octeon/octeon_mgmt.c
@@ -620,7 +620,7 @@ static int octeon_mgmt_ioctl(struct net_device *netdev,
if (!p->phydev)
return -EINVAL;
- return phy_mii_ioctl(p->phydev, if_mii(rq), cmd);
+ return phy_mii_ioctl(p->phydev, rq, cmd);
}
static void octeon_mgmt_adjust_link(struct net_device *netdev)
@@ -1067,7 +1067,7 @@ static const struct net_device_ops octeon_mgmt_ops = {
#endif
};
-static int __init octeon_mgmt_probe(struct platform_device *pdev)
+static int __devinit octeon_mgmt_probe(struct platform_device *pdev)
{
struct resource *res_irq;
struct net_device *netdev;
@@ -1124,7 +1124,7 @@ err:
return -ENOENT;
}
-static int __exit octeon_mgmt_remove(struct platform_device *pdev)
+static int __devexit octeon_mgmt_remove(struct platform_device *pdev)
{
struct net_device *netdev = dev_get_drvdata(&pdev->dev);
@@ -1139,7 +1139,7 @@ static struct platform_driver octeon_mgmt_driver = {
.owner = THIS_MODULE,
},
.probe = octeon_mgmt_probe,
- .remove = __exit_p(octeon_mgmt_remove),
+ .remove = __devexit_p(octeon_mgmt_remove),
};
extern void octeon_mdiobus_force_mod_depencency(void);
diff --git a/drivers/net/pcmcia/3c574_cs.c b/drivers/net/pcmcia/3c574_cs.c
index 10ee106a161..c683f77c6f4 100644
--- a/drivers/net/pcmcia/3c574_cs.c
+++ b/drivers/net/pcmcia/3c574_cs.c
@@ -87,7 +87,6 @@ earlier 3Com products.
#include <linux/bitops.h>
#include <linux/mii.h>
-#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/cistpl.h>
#include <pcmcia/cisreg.h>
@@ -279,8 +278,8 @@ static int tc574_probe(struct pcmcia_device *link)
lp->p_dev = link;
spin_lock_init(&lp->window_lock);
- link->io.NumPorts1 = 32;
- link->io.Attributes1 = IO_DATA_PATH_WIDTH_16;
+ link->resource[0]->end = 32;
+ link->resource[0]->flags |= IO_DATA_PATH_WIDTH_16;
link->conf.Attributes = CONF_ENABLE_IRQ;
link->conf.IntType = INT_MEMORY_AND_IO;
link->conf.ConfigIndex = 1;
@@ -338,10 +337,11 @@ static int tc574_config(struct pcmcia_device *link)
dev_dbg(&link->dev, "3c574_config()\n");
- link->io.IOAddrLines = 16;
+ link->io_lines = 16;
+
for (i = j = 0; j < 0x400; j += 0x20) {
- link->io.BasePort1 = j ^ 0x300;
- i = pcmcia_request_io(link, &link->io);
+ link->resource[0]->start = j ^ 0x300;
+ i = pcmcia_request_io(link);
if (i == 0)
break;
}
@@ -357,7 +357,7 @@ static int tc574_config(struct pcmcia_device *link)
goto failed;
dev->irq = link->irq;
- dev->base_addr = link->io.BasePort1;
+ dev->base_addr = link->resource[0]->start;
ioaddr = dev->base_addr;
diff --git a/drivers/net/pcmcia/3c589_cs.c b/drivers/net/pcmcia/3c589_cs.c
index ce63c3773b4..61f9cf2100f 100644
--- a/drivers/net/pcmcia/3c589_cs.c
+++ b/drivers/net/pcmcia/3c589_cs.c
@@ -41,7 +41,6 @@
#include <linux/bitops.h>
#include <linux/jiffies.h>
-#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/cistpl.h>
#include <pcmcia/cisreg.h>
@@ -214,8 +213,8 @@ static int tc589_probe(struct pcmcia_device *link)
lp->p_dev = link;
spin_lock_init(&lp->lock);
- link->io.NumPorts1 = 16;
- link->io.Attributes1 = IO_DATA_PATH_WIDTH_16;
+ link->resource[0]->end = 16;
+ link->resource[0]->flags |= IO_DATA_PATH_WIDTH_16;
link->conf.Attributes = CONF_ENABLE_IRQ;
link->conf.IntType = INT_MEMORY_AND_IO;
@@ -278,12 +277,13 @@ static int tc589_config(struct pcmcia_device *link)
"3Com card??\n");
multi = (link->card_id == PRODID_3COM_3C562);
+ link->io_lines = 16;
+
/* For the 3c562, the base address must be xx00-xx7f */
- link->io.IOAddrLines = 16;
for (i = j = 0; j < 0x400; j += 0x10) {
if (multi && (j & 0x80)) continue;
- link->io.BasePort1 = j ^ 0x300;
- i = pcmcia_request_io(link, &link->io);
+ link->resource[0]->start = j ^ 0x300;
+ i = pcmcia_request_io(link);
if (i == 0)
break;
}
@@ -299,7 +299,7 @@ static int tc589_config(struct pcmcia_device *link)
goto failed;
dev->irq = link->irq;
- dev->base_addr = link->io.BasePort1;
+ dev->base_addr = link->resource[0]->start;
ioaddr = dev->base_addr;
EL3WINDOW(0);
diff --git a/drivers/net/pcmcia/axnet_cs.c b/drivers/net/pcmcia/axnet_cs.c
index 33525bf2a3d..5f05ffb240c 100644
--- a/drivers/net/pcmcia/axnet_cs.c
+++ b/drivers/net/pcmcia/axnet_cs.c
@@ -39,7 +39,6 @@
#include <linux/mii.h>
#include "../8390.h"
-#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/cistpl.h>
#include <pcmcia/ciscode.h>
@@ -260,28 +259,30 @@ static int get_prom(struct pcmcia_device *link)
static int try_io_port(struct pcmcia_device *link)
{
int j, ret;
- if (link->io.NumPorts1 == 32) {
- link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
+ link->resource[0]->flags &= ~IO_DATA_PATH_WIDTH;
+ link->resource[1]->flags &= ~IO_DATA_PATH_WIDTH;
+ if (link->resource[0]->end == 32) {
+ link->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO;
/* for master/slave multifunction cards */
- if (link->io.NumPorts2 > 0)
- link->io.Attributes2 = IO_DATA_PATH_WIDTH_8;
+ if (link->resource[1]->end > 0)
+ link->resource[1]->flags |= IO_DATA_PATH_WIDTH_8;
} else {
/* This should be two 16-port windows */
- link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
- link->io.Attributes2 = IO_DATA_PATH_WIDTH_16;
+ link->resource[0]->flags |= IO_DATA_PATH_WIDTH_8;
+ link->resource[1]->flags |= IO_DATA_PATH_WIDTH_16;
}
- if (link->io.BasePort1 == 0) {
- link->io.IOAddrLines = 16;
+ if (link->resource[0]->start == 0) {
for (j = 0; j < 0x400; j += 0x20) {
- link->io.BasePort1 = j ^ 0x300;
- link->io.BasePort2 = (j ^ 0x300) + 0x10;
- ret = pcmcia_request_io(link, &link->io);
+ link->resource[0]->start = j ^ 0x300;
+ link->resource[1]->start = (j ^ 0x300) + 0x10;
+ link->io_lines = 16;
+ ret = pcmcia_request_io(link);
if (ret == 0)
return ret;
}
return ret;
} else {
- return pcmcia_request_io(link, &link->io);
+ return pcmcia_request_io(link);
}
}
@@ -302,15 +303,15 @@ static int axnet_configcheck(struct pcmcia_device *p_dev,
network function with window 0, and serial with window 1 */
if (io->nwin > 1) {
i = (io->win[1].len > io->win[0].len);
- p_dev->io.BasePort2 = io->win[1-i].base;
- p_dev->io.NumPorts2 = io->win[1-i].len;
+ p_dev->resource[1]->start = io->win[1-i].base;
+ p_dev->resource[1]->end = io->win[1-i].len;
} else {
- i = p_dev->io.NumPorts2 = 0;
+ i = p_dev->resource[1]->end = 0;
}
- p_dev->io.BasePort1 = io->win[i].base;
- p_dev->io.NumPorts1 = io->win[i].len;
- p_dev->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK;
- if (p_dev->io.NumPorts1 + p_dev->io.NumPorts2 >= 32)
+ p_dev->resource[0]->start = io->win[i].base;
+ p_dev->resource[0]->end = io->win[i].len;
+ p_dev->io_lines = io->flags & CISTPL_IO_LINES_MASK;
+ if (p_dev->resource[0]->end + p_dev->resource[1]->end >= 32)
return try_io_port(p_dev);
return -ENODEV;
@@ -333,7 +334,7 @@ static int axnet_config(struct pcmcia_device *link)
if (!link->irq)
goto failed;
- if (link->io.NumPorts2 == 8) {
+ if (resource_size(link->resource[1]) == 8) {
link->conf.Attributes |= CONF_ENABLE_SPKR;
link->conf.Status = CCSR_AUDIO_ENA;
}
@@ -343,7 +344,7 @@ static int axnet_config(struct pcmcia_device *link)
goto failed;
dev->irq = link->irq;
- dev->base_addr = link->io.BasePort1;
+ dev->base_addr = link->resource[0]->start;
if (!get_prom(link)) {
printk(KERN_NOTICE "axnet_cs: this is not an AX88190 card!\n");
@@ -379,8 +380,7 @@ static int axnet_config(struct pcmcia_device *link)
/* Maybe PHY is in power down mode. (PPD_SET = 1)
Bit 2 of CCSR is active low. */
if (i == 32) {
- conf_reg_t reg = { 0, CS_WRITE, CISREG_CCSR, 0x04 };
- pcmcia_access_configuration_register(link, &reg);
+ pcmcia_write_config_byte(link, CISREG_CCSR, 0x04);
for (i = 0; i < 32; i++) {
j = mdio_read(dev->base_addr + AXNET_MII_EEP, i, 1);
j2 = mdio_read(dev->base_addr + AXNET_MII_EEP, i, 2);
diff --git a/drivers/net/pcmcia/com20020_cs.c b/drivers/net/pcmcia/com20020_cs.c
index 5643f94541b..3c400cfa82a 100644
--- a/drivers/net/pcmcia/com20020_cs.c
+++ b/drivers/net/pcmcia/com20020_cs.c
@@ -43,7 +43,6 @@
#include <linux/arcdevice.h>
#include <linux/com20020.h>
-#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/cistpl.h>
#include <pcmcia/ds.h>
@@ -159,9 +158,8 @@ static int com20020_probe(struct pcmcia_device *p_dev)
/* fill in our module parameters as defaults */
dev->dev_addr[0] = node;
- p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
- p_dev->io.NumPorts1 = 16;
- p_dev->io.IOAddrLines = 16;
+ p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_8;
+ p_dev->resource[0]->end = 16;
p_dev->conf.Attributes = CONF_ENABLE_IRQ;
p_dev->conf.IntType = INT_MEMORY_AND_IO;
@@ -246,20 +244,24 @@ static int com20020_config(struct pcmcia_device *link)
dev_dbg(&link->dev, "com20020_config\n");
- dev_dbg(&link->dev, "baseport1 is %Xh\n", link->io.BasePort1);
+ dev_dbg(&link->dev, "baseport1 is %Xh\n",
+ (unsigned int) link->resource[0]->start);
+
i = -ENODEV;
- if (!link->io.BasePort1)
+ link->io_lines = 16;
+
+ if (!link->resource[0]->start)
{
for (ioaddr = 0x100; ioaddr < 0x400; ioaddr += 0x10)
{
- link->io.BasePort1 = ioaddr;
- i = pcmcia_request_io(link, &link->io);
+ link->resource[0]->start = ioaddr;
+ i = pcmcia_request_io(link);
if (i == 0)
break;
}
}
else
- i = pcmcia_request_io(link, &link->io);
+ i = pcmcia_request_io(link);
if (i != 0)
{
@@ -267,7 +269,7 @@ static int com20020_config(struct pcmcia_device *link)
goto failed;
}
- ioaddr = dev->base_addr = link->io.BasePort1;
+ ioaddr = dev->base_addr = link->resource[0]->start;
dev_dbg(&link->dev, "got ioaddr %Xh\n", ioaddr);
dev_dbg(&link->dev, "request IRQ %d\n",
diff --git a/drivers/net/pcmcia/fmvj18x_cs.c b/drivers/net/pcmcia/fmvj18x_cs.c
index 7c27c50211a..98fffb03ecd 100644
--- a/drivers/net/pcmcia/fmvj18x_cs.c
+++ b/drivers/net/pcmcia/fmvj18x_cs.c
@@ -49,7 +49,6 @@
#include <linux/ioport.h>
#include <linux/crc32.h>
-#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/cistpl.h>
#include <pcmcia/ciscode.h>
@@ -249,9 +248,8 @@ static int fmvj18x_probe(struct pcmcia_device *link)
lp->base = NULL;
/* The io structure describes IO port mapping */
- link->io.NumPorts1 = 32;
- link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
- link->io.IOAddrLines = 5;
+ link->resource[0]->end = 32;
+ link->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO;
/* General socket configuration */
link->conf.Attributes = CONF_ENABLE_IRQ;
@@ -289,13 +287,13 @@ static int mfc_try_io_port(struct pcmcia_device *link)
{ 0x3f8, 0x2f8, 0x3e8, 0x2e8, 0x0 };
for (i = 0; i < 5; i++) {
- link->io.BasePort2 = serial_base[i];
- link->io.Attributes2 = IO_DATA_PATH_WIDTH_8;
- if (link->io.BasePort2 == 0) {
- link->io.NumPorts2 = 0;
+ link->resource[1]->start = serial_base[i];
+ link->resource[1]->flags |= IO_DATA_PATH_WIDTH_8;
+ if (link->resource[1]->start == 0) {
+ link->resource[1]->end = 0;
printk(KERN_NOTICE "fmvj18x_cs: out of resource for serial\n");
}
- ret = pcmcia_request_io(link, &link->io);
+ ret = pcmcia_request_io(link);
if (ret == 0)
return ret;
}
@@ -311,12 +309,12 @@ static int ungermann_try_io_port(struct pcmcia_device *link)
0x380,0x3c0 only for ioport.
*/
for (ioaddr = 0x300; ioaddr < 0x3e0; ioaddr += 0x20) {
- link->io.BasePort1 = ioaddr;
- ret = pcmcia_request_io(link, &link->io);
+ link->resource[0]->start = ioaddr;
+ ret = pcmcia_request_io(link);
if (ret == 0) {
/* calculate ConfigIndex value */
link->conf.ConfigIndex =
- ((link->io.BasePort1 & 0x0f0) >> 3) | 0x22;
+ ((link->resource[0]->start & 0x0f0) >> 3) | 0x22;
return ret;
}
}
@@ -346,6 +344,8 @@ static int fmvj18x_config(struct pcmcia_device *link)
dev_dbg(&link->dev, "fmvj18x_config\n");
+ link->io_lines = 5;
+
len = pcmcia_get_tuple(link, CISTPL_FUNCE, &buf);
kfree(buf);
@@ -364,20 +364,20 @@ static int fmvj18x_config(struct pcmcia_device *link)
/* MultiFunction Card */
link->conf.ConfigBase = 0x800;
link->conf.ConfigIndex = 0x47;
- link->io.NumPorts2 = 8;
+ link->resource[1]->end = 8;
}
break;
case MANFID_NEC:
cardtype = NEC; /* MultiFunction Card */
link->conf.ConfigBase = 0x800;
link->conf.ConfigIndex = 0x47;
- link->io.NumPorts2 = 8;
+ link->resource[1]->end = 8;
break;
case MANFID_KME:
cardtype = KME; /* MultiFunction Card */
link->conf.ConfigBase = 0x800;
link->conf.ConfigIndex = 0x47;
- link->io.NumPorts2 = 8;
+ link->resource[1]->end = 8;
break;
case MANFID_CONTEC:
cardtype = CONTEC;
@@ -418,14 +418,14 @@ static int fmvj18x_config(struct pcmcia_device *link)
}
}
- if (link->io.NumPorts2 != 0) {
+ if (link->resource[1]->end != 0) {
ret = mfc_try_io_port(link);
if (ret != 0) goto failed;
} else if (cardtype == UNGERMANN) {
ret = ungermann_try_io_port(link);
if (ret != 0) goto failed;
} else {
- ret = pcmcia_request_io(link, &link->io);
+ ret = pcmcia_request_io(link);
if (ret)
goto failed;
}
@@ -437,9 +437,9 @@ static int fmvj18x_config(struct pcmcia_device *link)
goto failed;
dev->irq = link->irq;
- dev->base_addr = link->io.BasePort1;
+ dev->base_addr = link->resource[0]->start;
- if (link->io.BasePort2 != 0) {
+ if (resource_size(link->resource[1]) != 0) {
ret = fmvj18x_setup_mfc(link);
if (ret != 0) goto failed;
}
@@ -545,7 +545,6 @@ failed:
static int fmvj18x_get_hwinfo(struct pcmcia_device *link, u_char *node_id)
{
win_req_t req;
- memreq_t mem;
u_char __iomem *base;
int i, j;
@@ -558,9 +557,7 @@ static int fmvj18x_get_hwinfo(struct pcmcia_device *link, u_char *node_id)
return -1;
base = ioremap(req.Base, req.Size);
- mem.Page = 0;
- mem.CardOffset = 0;
- pcmcia_map_mem_page(link, link->win, &mem);
+ pcmcia_map_mem_page(link, link->win, 0);
/*
* MBH10304 CISTPL_FUNCE_LAN_NODE_ID format
@@ -594,7 +591,6 @@ static int fmvj18x_get_hwinfo(struct pcmcia_device *link, u_char *node_id)
static int fmvj18x_setup_mfc(struct pcmcia_device *link)
{
win_req_t req;
- memreq_t mem;
int i;
struct net_device *dev = link->priv;
unsigned int ioaddr;
@@ -614,9 +610,7 @@ static int fmvj18x_setup_mfc(struct pcmcia_device *link)
return -1;
}
- mem.Page = 0;
- mem.CardOffset = 0;
- i = pcmcia_map_mem_page(link, link->win, &mem);
+ i = pcmcia_map_mem_page(link, link->win, 0);
if (i != 0) {
iounmap(lp->base);
lp->base = NULL;
diff --git a/drivers/net/pcmcia/ibmtr_cs.c b/drivers/net/pcmcia/ibmtr_cs.c
index 67ee9851a8e..b0d06a3d962 100644
--- a/drivers/net/pcmcia/ibmtr_cs.c
+++ b/drivers/net/pcmcia/ibmtr_cs.c
@@ -57,7 +57,6 @@
#include <linux/trdevice.h>
#include <linux/ibmtr.h>
-#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/cistpl.h>
#include <pcmcia/ds.h>
@@ -152,9 +151,8 @@ static int __devinit ibmtr_attach(struct pcmcia_device *link)
link->priv = info;
info->ti = netdev_priv(dev);
- link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
- link->io.NumPorts1 = 4;
- link->io.IOAddrLines = 16;
+ link->resource[0]->flags |= IO_DATA_PATH_WIDTH_8;
+ link->resource[0]->end = 4;
link->conf.Attributes = CONF_ENABLE_IRQ;
link->conf.IntType = INT_MEMORY_AND_IO;
link->conf.Present = PRESENT_OPTION;
@@ -213,26 +211,26 @@ static int __devinit ibmtr_config(struct pcmcia_device *link)
struct net_device *dev = info->dev;
struct tok_info *ti = netdev_priv(dev);
win_req_t req;
- memreq_t mem;
int i, ret;
dev_dbg(&link->dev, "ibmtr_config\n");
link->conf.ConfigIndex = 0x61;
+ link->io_lines = 16;
/* Determine if this is PRIMARY or ALTERNATE. */
/* Try PRIMARY card at 0xA20-0xA23 */
- link->io.BasePort1 = 0xA20;
- i = pcmcia_request_io(link, &link->io);
+ link->resource[0]->start = 0xA20;
+ i = pcmcia_request_io(link);
if (i != 0) {
/* Couldn't get 0xA20-0xA23. Try ALTERNATE at 0xA24-0xA27. */
- link->io.BasePort1 = 0xA24;
- ret = pcmcia_request_io(link, &link->io);
+ link->resource[0]->start = 0xA24;
+ ret = pcmcia_request_io(link);
if (ret)
goto failed;
}
- dev->base_addr = link->io.BasePort1;
+ dev->base_addr = link->resource[0]->start;
ret = pcmcia_request_exclusive_irq(link, ibmtr_interrupt);
if (ret)
@@ -251,9 +249,7 @@ static int __devinit ibmtr_config(struct pcmcia_device *link)
if (ret)
goto failed;
- mem.CardOffset = mmiobase;
- mem.Page = 0;
- ret = pcmcia_map_mem_page(link, link->win, &mem);
+ ret = pcmcia_map_mem_page(link, link->win, mmiobase);
if (ret)
goto failed;
ti->mmio = ioremap(req.Base, req.Size);
@@ -268,13 +264,11 @@ static int __devinit ibmtr_config(struct pcmcia_device *link)
if (ret)
goto failed;
- mem.CardOffset = srambase;
- mem.Page = 0;
- ret = pcmcia_map_mem_page(link, info->sram_win_handle, &mem);
+ ret = pcmcia_map_mem_page(link, info->sram_win_handle, srambase);
if (ret)
goto failed;
- ti->sram_base = mem.CardOffset >> 12;
+ ti->sram_base = srambase >> 12;
ti->sram_virt = ioremap(req.Base, req.Size);
ti->sram_phys = req.Base;
@@ -325,7 +319,6 @@ static void ibmtr_release(struct pcmcia_device *link)
if (link->win) {
struct tok_info *ti = netdev_priv(dev);
iounmap(ti->mmio);
- pcmcia_release_window(link, info->sram_win_handle);
}
pcmcia_disable_device(link);
}
diff --git a/drivers/net/pcmcia/nmclan_cs.c b/drivers/net/pcmcia/nmclan_cs.c
index 9b63dec549c..68f2deeb3ad 100644
--- a/drivers/net/pcmcia/nmclan_cs.c
+++ b/drivers/net/pcmcia/nmclan_cs.c
@@ -146,7 +146,6 @@ Include Files
#include <linux/ioport.h>
#include <linux/bitops.h>
-#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/cisreg.h>
#include <pcmcia/cistpl.h>
@@ -459,9 +458,8 @@ static int nmclan_probe(struct pcmcia_device *link)
link->priv = dev;
spin_lock_init(&lp->bank_lock);
- link->io.NumPorts1 = 32;
- link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
- link->io.IOAddrLines = 5;
+ link->resource[0]->end = 32;
+ link->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO;
link->conf.Attributes = CONF_ENABLE_IRQ;
link->conf.IntType = INT_MEMORY_AND_IO;
link->conf.ConfigIndex = 1;
@@ -645,7 +643,8 @@ static int nmclan_config(struct pcmcia_device *link)
dev_dbg(&link->dev, "nmclan_config\n");
- ret = pcmcia_request_io(link, &link->io);
+ link->io_lines = 5;
+ ret = pcmcia_request_io(link);
if (ret)
goto failed;
ret = pcmcia_request_exclusive_irq(link, mace_interrupt);
@@ -656,7 +655,7 @@ static int nmclan_config(struct pcmcia_device *link)
goto failed;
dev->irq = link->irq;
- dev->base_addr = link->io.BasePort1;
+ dev->base_addr = link->resource[0]->start;
ioaddr = dev->base_addr;
@@ -758,29 +757,20 @@ static void nmclan_reset(struct net_device *dev)
#if RESET_XILINX
struct pcmcia_device *link = &lp->link;
- conf_reg_t reg;
- u_long OrigCorValue;
+ u8 OrigCorValue;
/* Save original COR value */
- reg.Function = 0;
- reg.Action = CS_READ;
- reg.Offset = CISREG_COR;
- reg.Value = 0;
- pcmcia_access_configuration_register(link, &reg);
- OrigCorValue = reg.Value;
+ pcmcia_read_config_byte(link, CISREG_COR, &OrigCorValue);
/* Reset Xilinx */
- reg.Action = CS_WRITE;
- reg.Offset = CISREG_COR;
- dev_dbg(&link->dev, "nmclan_reset: OrigCorValue=0x%lX, resetting...\n",
+ dev_dbg(&link->dev, "nmclan_reset: OrigCorValue=0x%x, resetting...\n",
OrigCorValue);
- reg.Value = COR_SOFT_RESET;
- pcmcia_access_configuration_register(link, &reg);
+ pcmcia_write_config_byte(link, CISREG_COR, COR_SOFT_RESET);
/* Need to wait for 20 ms for PCMCIA to finish reset. */
/* Restore original COR configuration index */
- reg.Value = COR_LEVEL_REQ | (OrigCorValue & COR_CONFIG_MASK);
- pcmcia_access_configuration_register(link, &reg);
+ pcmcia_write_config_byte(link, CISREG_COR,
+ (COR_LEVEL_REQ | (OrigCorValue & COR_CONFIG_MASK)));
/* Xilinx is now completely reset along with the MACE chip. */
lp->tx_free_frames=AM2150_MAX_TX_FRAMES;
diff --git a/drivers/net/pcmcia/pcnet_cs.c b/drivers/net/pcmcia/pcnet_cs.c
index bfdef72c5d5..c3edfe4c265 100644
--- a/drivers/net/pcmcia/pcnet_cs.c
+++ b/drivers/net/pcmcia/pcnet_cs.c
@@ -42,7 +42,6 @@
#include <linux/mii.h>
#include "../8390.h"
-#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/cistpl.h>
#include <pcmcia/ciscode.h>
@@ -113,8 +112,6 @@ static int setup_dma_config(struct pcmcia_device *link, int start_pg,
static void pcnet_detach(struct pcmcia_device *p_dev);
-static dev_info_t dev_info = "pcnet_cs";
-
/*====================================================================*/
typedef struct hw_info_t {
@@ -304,7 +301,6 @@ static hw_info_t *get_hwinfo(struct pcmcia_device *link)
{
struct net_device *dev = link->priv;
win_req_t req;
- memreq_t mem;
u_char __iomem *base, *virt;
int i, j;
@@ -317,10 +313,8 @@ static hw_info_t *get_hwinfo(struct pcmcia_device *link)
return NULL;
virt = ioremap(req.Base, req.Size);
- mem.Page = 0;
for (i = 0; i < NR_INFO; i++) {
- mem.CardOffset = hw_info[i].offset & ~(req.Size-1);
- pcmcia_map_mem_page(link, link->win, &mem);
+ pcmcia_map_mem_page(link, link->win, hw_info[i].offset & ~(req.Size-1));
base = &virt[hw_info[i].offset & (req.Size-1)];
if ((readb(base+0) == hw_info[i].a0) &&
(readb(base+2) == hw_info[i].a1) &&
@@ -480,29 +474,31 @@ static hw_info_t *get_hwired(struct pcmcia_device *link)
static int try_io_port(struct pcmcia_device *link)
{
int j, ret;
- if (link->io.NumPorts1 == 32) {
- link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
- if (link->io.NumPorts2 > 0) {
+ link->resource[0]->flags &= ~IO_DATA_PATH_WIDTH;
+ link->resource[1]->flags &= ~IO_DATA_PATH_WIDTH;
+ if (link->resource[0]->end == 32) {
+ link->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO;
+ if (link->resource[1]->end > 0) {
/* for master/slave multifunction cards */
- link->io.Attributes2 = IO_DATA_PATH_WIDTH_8;
+ link->resource[1]->flags |= IO_DATA_PATH_WIDTH_8;
}
} else {
/* This should be two 16-port windows */
- link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
- link->io.Attributes2 = IO_DATA_PATH_WIDTH_16;
+ link->resource[0]->flags |= IO_DATA_PATH_WIDTH_8;
+ link->resource[1]->flags |= IO_DATA_PATH_WIDTH_16;
}
- if (link->io.BasePort1 == 0) {
- link->io.IOAddrLines = 16;
+ if (link->resource[0]->start == 0) {
for (j = 0; j < 0x400; j += 0x20) {
- link->io.BasePort1 = j ^ 0x300;
- link->io.BasePort2 = (j ^ 0x300) + 0x10;
- ret = pcmcia_request_io(link, &link->io);
+ link->resource[0]->start = j ^ 0x300;
+ link->resource[1]->start = (j ^ 0x300) + 0x10;
+ link->io_lines = 16;
+ ret = pcmcia_request_io(link);
if (ret == 0)
return ret;
}
return ret;
} else {
- return pcmcia_request_io(link, &link->io);
+ return pcmcia_request_io(link);
}
}
@@ -523,18 +519,18 @@ static int pcnet_confcheck(struct pcmcia_device *p_dev,
network function with window 0, and serial with window 1 */
if (io->nwin > 1) {
i = (io->win[1].len > io->win[0].len);
- p_dev->io.BasePort2 = io->win[1-i].base;
- p_dev->io.NumPorts2 = io->win[1-i].len;
+ p_dev->resource[1]->start = io->win[1-i].base;
+ p_dev->resource[1]->end = io->win[1-i].len;
} else {
- i = p_dev->io.NumPorts2 = 0;
+ i = p_dev->resource[1]->end = 0;
}
*has_shmem = ((cfg->mem.nwin == 1) &&
(cfg->mem.win[0].len >= 0x4000));
- p_dev->io.BasePort1 = io->win[i].base;
- p_dev->io.NumPorts1 = io->win[i].len;
- p_dev->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK;
- if (p_dev->io.NumPorts1 + p_dev->io.NumPorts2 >= 32)
+ p_dev->resource[0]->start = io->win[i].base;
+ p_dev->resource[0]->end = io->win[i].len;
+ p_dev->io_lines = io->flags & CISTPL_IO_LINES_MASK;
+ if (p_dev->resource[0]->end + p_dev->resource[1]->end >= 32)
return try_io_port(p_dev);
return 0;
@@ -557,7 +553,7 @@ static int pcnet_config(struct pcmcia_device *link)
if (!link->irq)
goto failed;
- if (link->io.NumPorts2 == 8) {
+ if (resource_size(link->resource[1]) == 8) {
link->conf.Attributes |= CONF_ENABLE_SPKR;
link->conf.Status = CCSR_AUDIO_ENA;
}
@@ -569,7 +565,7 @@ static int pcnet_config(struct pcmcia_device *link)
if (ret)
goto failed;
dev->irq = link->irq;
- dev->base_addr = link->io.BasePort1;
+ dev->base_addr = link->resource[0]->start;
if (info->flags & HAS_MISC_REG) {
if ((if_port == 1) || (if_port == 2))
dev->if_port = if_port;
@@ -956,7 +952,7 @@ static int pcnet_open(struct net_device *dev)
set_misc_reg(dev);
outb_p(0xFF, nic_base + EN0_ISR); /* Clear bogus intr. */
- ret = request_irq(dev->irq, ei_irq_wrapper, IRQF_SHARED, dev_info, dev);
+ ret = request_irq(dev->irq, ei_irq_wrapper, IRQF_SHARED, dev->name, dev);
if (ret)
return ret;
@@ -1464,7 +1460,6 @@ static int setup_shmem_window(struct pcmcia_device *link, int start_pg,
struct net_device *dev = link->priv;
pcnet_dev_t *info = PRIV(dev);
win_req_t req;
- memreq_t mem;
int i, window_size, offset, ret;
window_size = (stop_pg - start_pg) << 8;
@@ -1483,11 +1478,9 @@ static int setup_shmem_window(struct pcmcia_device *link, int start_pg,
if (ret)
goto failed;
- mem.CardOffset = (start_pg << 8) + cm_offset;
- offset = mem.CardOffset % window_size;
- mem.CardOffset -= offset;
- mem.Page = 0;
- ret = pcmcia_map_mem_page(link, link->win, &mem);
+ offset = (start_pg << 8) + cm_offset;
+ offset -= offset % window_size;
+ ret = pcmcia_map_mem_page(link, link->win, offset);
if (ret)
goto failed;
diff --git a/drivers/net/pcmcia/smc91c92_cs.c b/drivers/net/pcmcia/smc91c92_cs.c
index 307cd1721e9..377367d03b4 100644
--- a/drivers/net/pcmcia/smc91c92_cs.c
+++ b/drivers/net/pcmcia/smc91c92_cs.c
@@ -44,7 +44,6 @@
#include <linux/jiffies.h>
#include <linux/firmware.h>
-#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/cistpl.h>
#include <pcmcia/cisreg.h>
@@ -325,9 +324,8 @@ static int smc91c92_probe(struct pcmcia_device *link)
link->priv = dev;
spin_lock_init(&smc->lock);
- link->io.NumPorts1 = 16;
- link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
- link->io.IOAddrLines = 4;
+ link->resource[0]->end = 16;
+ link->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO;
link->conf.Attributes = CONF_ENABLE_IRQ;
link->conf.IntType = INT_MEMORY_AND_IO;
@@ -428,12 +426,13 @@ static int mhz_mfc_config_check(struct pcmcia_device *p_dev,
void *priv_data)
{
int k;
- p_dev->io.BasePort2 = cf->io.win[0].base;
+ p_dev->resource[1]->start = cf->io.win[0].base;
for (k = 0; k < 0x400; k += 0x10) {
if (k & 0x80)
continue;
- p_dev->io.BasePort1 = k ^ 0x300;
- if (!pcmcia_request_io(p_dev, &p_dev->io))
+ p_dev->resource[0]->start = k ^ 0x300;
+ p_dev->io_lines = 16;
+ if (!pcmcia_request_io(p_dev))
return 0;
}
return -ENODEV;
@@ -444,21 +443,20 @@ static int mhz_mfc_config(struct pcmcia_device *link)
struct net_device *dev = link->priv;
struct smc_private *smc = netdev_priv(dev);
win_req_t req;
- memreq_t mem;
+ unsigned int offset;
int i;
link->conf.Attributes |= CONF_ENABLE_SPKR;
link->conf.Status = CCSR_AUDIO_ENA;
- link->io.IOAddrLines = 16;
- link->io.Attributes2 = IO_DATA_PATH_WIDTH_8;
- link->io.NumPorts2 = 8;
+ link->resource[1]->flags |= IO_DATA_PATH_WIDTH_8;
+ link->resource[1]->end = 8;
/* The Megahertz combo cards have modem-like CIS entries, so
we have to explicitly try a bunch of port combinations. */
if (pcmcia_loop_config(link, mhz_mfc_config_check, NULL))
return -ENODEV;
- dev->base_addr = link->io.BasePort1;
+ dev->base_addr = link->resource[0]->start;
/* Allocate a memory window, for accessing the ISR */
req.Attributes = WIN_DATA_WIDTH_8|WIN_MEMORY_TYPE_AM|WIN_ENABLE;
@@ -469,11 +467,8 @@ static int mhz_mfc_config(struct pcmcia_device *link)
return -ENODEV;
smc->base = ioremap(req.Base, req.Size);
- mem.CardOffset = mem.Page = 0;
- if (smc->manfid == MANFID_MOTOROLA)
- mem.CardOffset = link->conf.ConfigBase;
- i = pcmcia_map_mem_page(link, link->win, &mem);
-
+ offset = (smc->manfid == MANFID_MOTOROLA) ? link->conf.ConfigBase : 0;
+ i = pcmcia_map_mem_page(link, link->win, offset);
if ((i == 0) &&
(smc->manfid == MANFID_MEGAHERTZ) &&
(smc->cardid == PRODID_MEGAHERTZ_EM3288))
@@ -546,7 +541,7 @@ static void mot_config(struct pcmcia_device *link)
struct net_device *dev = link->priv;
struct smc_private *smc = netdev_priv(dev);
unsigned int ioaddr = dev->base_addr;
- unsigned int iouart = link->io.BasePort2;
+ unsigned int iouart = link->resource[1]->start;
/* Set UART base address and force map with COR bit 1 */
writeb(iouart & 0xff, smc->base + MOT_UART + CISREG_IOBASE_0);
@@ -602,9 +597,9 @@ static int smc_configcheck(struct pcmcia_device *p_dev,
unsigned int vcc,
void *priv_data)
{
- p_dev->io.BasePort1 = cf->io.win[0].base;
- p_dev->io.IOAddrLines = cf->io.flags & CISTPL_IO_LINES_MASK;
- return pcmcia_request_io(p_dev, &p_dev->io);
+ p_dev->resource[0]->start = cf->io.win[0].base;
+ p_dev->io_lines = cf->io.flags & CISTPL_IO_LINES_MASK;
+ return pcmcia_request_io(p_dev);
}
static int smc_config(struct pcmcia_device *link)
@@ -612,10 +607,10 @@ static int smc_config(struct pcmcia_device *link)
struct net_device *dev = link->priv;
int i;
- link->io.NumPorts1 = 16;
+ link->resource[0]->end = 16;
i = pcmcia_loop_config(link, smc_configcheck, NULL);
if (!i)
- dev->base_addr = link->io.BasePort1;
+ dev->base_addr = link->resource[0]->start;
return i;
}
@@ -647,27 +642,27 @@ static int osi_config(struct pcmcia_device *link)
link->conf.Attributes |= CONF_ENABLE_SPKR;
link->conf.Status = CCSR_AUDIO_ENA;
- link->io.NumPorts1 = 64;
- link->io.Attributes2 = IO_DATA_PATH_WIDTH_8;
- link->io.NumPorts2 = 8;
- link->io.IOAddrLines = 16;
+ link->resource[0]->end = 64;
+ link->resource[1]->flags |= IO_DATA_PATH_WIDTH_8;
+ link->resource[1]->end = 8;
/* Enable Hard Decode, LAN, Modem */
link->conf.ConfigIndex = 0x23;
+ link->io_lines = 16;
for (i = j = 0; j < 4; j++) {
- link->io.BasePort2 = com[j];
- i = pcmcia_request_io(link, &link->io);
+ link->resource[1]->start = com[j];
+ i = pcmcia_request_io(link);
if (i == 0)
break;
}
if (i != 0) {
/* Fallback: turn off hard decode */
link->conf.ConfigIndex = 0x03;
- link->io.NumPorts2 = 0;
- i = pcmcia_request_io(link, &link->io);
+ link->resource[1]->end = 0;
+ i = pcmcia_request_io(link);
}
- dev->base_addr = link->io.BasePort1 + 0x10;
+ dev->base_addr = link->resource[0]->start + 0x10;
return i;
}
@@ -684,7 +679,7 @@ static int osi_load_firmware(struct pcmcia_device *link)
/* Download the Seven of Diamonds firmware */
for (i = 0; i < fw->size; i++) {
- outb(fw->data[i], link->io.BasePort1 + 2);
+ outb(fw->data[i], link->resource[0]->start + 2);
udelay(50);
}
release_firmware(fw);
@@ -726,12 +721,12 @@ static int osi_setup(struct pcmcia_device *link, u_short manfid, u_short cardid)
return rc;
} else if (manfid == MANFID_OSITECH) {
/* Make sure both functions are powered up */
- set_bits(0x300, link->io.BasePort1 + OSITECH_AUI_PWR);
+ set_bits(0x300, link->resource[0]->start + OSITECH_AUI_PWR);
/* Now, turn on the interrupt for both card functions */
- set_bits(0x300, link->io.BasePort1 + OSITECH_RESET_ISR);
+ set_bits(0x300, link->resource[0]->start + OSITECH_RESET_ISR);
dev_dbg(&link->dev, "AUI/PWR: %4.4x RESET/ISR: %4.4x\n",
- inw(link->io.BasePort1 + OSITECH_AUI_PWR),
- inw(link->io.BasePort1 + OSITECH_RESET_ISR));
+ inw(link->resource[0]->start + OSITECH_AUI_PWR),
+ inw(link->resource[0]->start + OSITECH_RESET_ISR));
}
return 0;
}
@@ -804,7 +799,7 @@ static int check_sig(struct pcmcia_device *link)
}
/* Try setting bus width */
- width = (link->io.Attributes1 == IO_DATA_PATH_WIDTH_AUTO);
+ width = (link->resource[0]->flags == IO_DATA_PATH_WIDTH_AUTO);
s = inb(ioaddr + CONFIG);
if (width)
s |= CFG_16BIT;
diff --git a/drivers/net/pcmcia/xirc2ps_cs.c b/drivers/net/pcmcia/xirc2ps_cs.c
index b6c3644888c..4eb6f986703 100644
--- a/drivers/net/pcmcia/xirc2ps_cs.c
+++ b/drivers/net/pcmcia/xirc2ps_cs.c
@@ -82,7 +82,6 @@
#include <linux/bitops.h>
#include <linux/mii.h>
-#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/cistpl.h>
#include <pcmcia/cisreg.h>
@@ -678,9 +677,9 @@ xirc2ps_config_modem(struct pcmcia_device *p_dev,
if (cf->io.nwin > 0 && (cf->io.win[0].base & 0xf) == 8) {
for (ioaddr = 0x300; ioaddr < 0x400; ioaddr += 0x10) {
- p_dev->io.BasePort2 = cf->io.win[0].base;
- p_dev->io.BasePort1 = ioaddr;
- if (!pcmcia_request_io(p_dev, &p_dev->io))
+ p_dev->resource[1]->start = cf->io.win[0].base;
+ p_dev->resource[0]->start = ioaddr;
+ if (!pcmcia_request_io(p_dev))
return 0;
}
}
@@ -697,11 +696,11 @@ xirc2ps_config_check(struct pcmcia_device *p_dev,
int *pass = priv_data;
if (cf->io.nwin > 0 && (cf->io.win[0].base & 0xf) == 8) {
- p_dev->io.BasePort2 = cf->io.win[0].base;
- p_dev->io.BasePort1 = p_dev->io.BasePort2
+ p_dev->resource[1]->start = cf->io.win[0].base;
+ p_dev->resource[0]->start = p_dev->resource[1]->start
+ (*pass ? (cf->index & 0x20 ? -24:8)
: (cf->index & 0x20 ? 8:-24));
- if (!pcmcia_request_io(p_dev, &p_dev->io))
+ if (!pcmcia_request_io(p_dev))
return 0;
}
return -ENODEV;
@@ -808,8 +807,7 @@ xirc2ps_config(struct pcmcia_device * link)
goto failure;
}
- link->io.IOAddrLines =10;
- link->io.Attributes1 = IO_DATA_PATH_WIDTH_16;
+ link->resource[0]->flags |= IO_DATA_PATH_WIDTH_16;
if (local->modem) {
int pass;
@@ -817,16 +815,16 @@ xirc2ps_config(struct pcmcia_device * link)
link->conf.Attributes |= CONF_ENABLE_SPKR;
link->conf.Status |= CCSR_AUDIO_ENA;
}
- link->io.NumPorts2 = 8;
- link->io.Attributes2 = IO_DATA_PATH_WIDTH_8;
+ link->resource[1]->end = 8;
+ link->resource[1]->flags |= IO_DATA_PATH_WIDTH_8;
if (local->dingo) {
/* Take the Modem IO port from the CIS and scan for a free
* Ethernet port */
- link->io.NumPorts1 = 16; /* no Mako stuff anymore */
+ link->resource[0]->end = 16; /* no Mako stuff anymore */
if (!pcmcia_loop_config(link, xirc2ps_config_modem, NULL))
goto port_found;
} else {
- link->io.NumPorts1 = 18;
+ link->resource[0]->end = 18;
/* We do 2 passes here: The first one uses the regular mapping and
* the second tries again, thereby considering that the 32 ports are
* mirrored every 32 bytes. Actually we use a mirrored port for
@@ -841,14 +839,15 @@ xirc2ps_config(struct pcmcia_device * link)
}
printk(KNOT_XIRC "no ports available\n");
} else {
- link->io.NumPorts1 = 16;
+ link->io_lines = 10;
+ link->resource[0]->end = 16;
for (ioaddr = 0x300; ioaddr < 0x400; ioaddr += 0x10) {
- link->io.BasePort1 = ioaddr;
- if (!(err=pcmcia_request_io(link, &link->io)))
+ link->resource[0]->start = ioaddr;
+ if (!(err = pcmcia_request_io(link)))
goto port_found;
}
- link->io.BasePort1 = 0; /* let CS decide */
- if ((err=pcmcia_request_io(link, &link->io)))
+ link->resource[0]->start = 0; /* let CS decide */
+ if ((err = pcmcia_request_io(link)))
goto config_error;
}
port_found:
@@ -870,24 +869,21 @@ xirc2ps_config(struct pcmcia_device * link)
goto config_error;
if (local->dingo) {
- conf_reg_t reg;
win_req_t req;
- memreq_t mem;
/* Reset the modem's BAR to the correct value
* This is necessary because in the RequestConfiguration call,
* the base address of the ethernet port (BasePort1) is written
* to the BAR registers of the modem.
*/
- reg.Action = CS_WRITE;
- reg.Offset = CISREG_IOBASE_0;
- reg.Value = link->io.BasePort2 & 0xff;
- if ((err = pcmcia_access_configuration_register(link, &reg)))
+ err = pcmcia_write_config_byte(link, CISREG_IOBASE_0, (u8)
+ link->resource[1]->start & 0xff);
+ if (err)
goto config_error;
- reg.Action = CS_WRITE;
- reg.Offset = CISREG_IOBASE_1;
- reg.Value = (link->io.BasePort2 >> 8) & 0xff;
- if ((err = pcmcia_access_configuration_register(link, &reg)))
+
+ err = pcmcia_write_config_byte(link, CISREG_IOBASE_1,
+ (link->resource[1]->start >> 8) & 0xff);
+ if (err)
goto config_error;
/* There is no config entry for the Ethernet part which
@@ -901,16 +897,14 @@ xirc2ps_config(struct pcmcia_device * link)
goto config_error;
local->dingo_ccr = ioremap(req.Base,0x1000) + 0x0800;
- mem.CardOffset = 0x0;
- mem.Page = 0;
- if ((err = pcmcia_map_mem_page(link, link->win, &mem)))
+ if ((err = pcmcia_map_mem_page(link, link->win, 0)))
goto config_error;
/* Setup the CCRs; there are no infos in the CIS about the Ethernet
* part.
*/
writeb(0x47, local->dingo_ccr + CISREG_COR);
- ioaddr = link->io.BasePort1;
+ ioaddr = link->resource[0]->start;
writeb(ioaddr & 0xff , local->dingo_ccr + CISREG_IOBASE_0);
writeb((ioaddr >> 8)&0xff , local->dingo_ccr + CISREG_IOBASE_1);
@@ -957,7 +951,7 @@ xirc2ps_config(struct pcmcia_device * link)
/* we can now register the device with the net subsystem */
dev->irq = link->irq;
- dev->base_addr = link->io.BasePort1;
+ dev->base_addr = link->resource[0]->start;
if (local->dingo)
do_reset(dev, 1); /* a kludge to make the cem56 work */
diff --git a/drivers/net/phy/broadcom.c b/drivers/net/phy/broadcom.c
index cecdbbd549e..4accd83d3df 100644
--- a/drivers/net/phy/broadcom.c
+++ b/drivers/net/phy/broadcom.c
@@ -685,7 +685,7 @@ static int brcm_fet_config_intr(struct phy_device *phydev)
}
static struct phy_driver bcm5411_driver = {
- .phy_id = 0x00206070,
+ .phy_id = PHY_ID_BCM5411,
.phy_id_mask = 0xfffffff0,
.name = "Broadcom BCM5411",
.features = PHY_GBIT_FEATURES |
@@ -700,7 +700,7 @@ static struct phy_driver bcm5411_driver = {
};
static struct phy_driver bcm5421_driver = {
- .phy_id = 0x002060e0,
+ .phy_id = PHY_ID_BCM5421,
.phy_id_mask = 0xfffffff0,
.name = "Broadcom BCM5421",
.features = PHY_GBIT_FEATURES |
@@ -715,7 +715,7 @@ static struct phy_driver bcm5421_driver = {
};
static struct phy_driver bcm5461_driver = {
- .phy_id = 0x002060c0,
+ .phy_id = PHY_ID_BCM5461,
.phy_id_mask = 0xfffffff0,
.name = "Broadcom BCM5461",
.features = PHY_GBIT_FEATURES |
@@ -730,7 +730,7 @@ static struct phy_driver bcm5461_driver = {
};
static struct phy_driver bcm5464_driver = {
- .phy_id = 0x002060b0,
+ .phy_id = PHY_ID_BCM5464,
.phy_id_mask = 0xfffffff0,
.name = "Broadcom BCM5464",
.features = PHY_GBIT_FEATURES |
@@ -745,7 +745,7 @@ static struct phy_driver bcm5464_driver = {
};
static struct phy_driver bcm5481_driver = {
- .phy_id = 0x0143bca0,
+ .phy_id = PHY_ID_BCM5481,
.phy_id_mask = 0xfffffff0,
.name = "Broadcom BCM5481",
.features = PHY_GBIT_FEATURES |
@@ -760,7 +760,7 @@ static struct phy_driver bcm5481_driver = {
};
static struct phy_driver bcm5482_driver = {
- .phy_id = 0x0143bcb0,
+ .phy_id = PHY_ID_BCM5482,
.phy_id_mask = 0xfffffff0,
.name = "Broadcom BCM5482",
.features = PHY_GBIT_FEATURES |
@@ -834,6 +834,21 @@ static struct phy_driver bcmac131_driver = {
.driver = { .owner = THIS_MODULE },
};
+static struct phy_driver bcm5241_driver = {
+ .phy_id = PHY_ID_BCM5241,
+ .phy_id_mask = 0xfffffff0,
+ .name = "Broadcom BCM5241",
+ .features = PHY_BASIC_FEATURES |
+ SUPPORTED_Pause | SUPPORTED_Asym_Pause,
+ .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
+ .config_init = brcm_fet_config_init,
+ .config_aneg = genphy_config_aneg,
+ .read_status = genphy_read_status,
+ .ack_interrupt = brcm_fet_ack_interrupt,
+ .config_intr = brcm_fet_config_intr,
+ .driver = { .owner = THIS_MODULE },
+};
+
static int __init broadcom_init(void)
{
int ret;
@@ -868,8 +883,13 @@ static int __init broadcom_init(void)
ret = phy_driver_register(&bcmac131_driver);
if (ret)
goto out_ac131;
+ ret = phy_driver_register(&bcm5241_driver);
+ if (ret)
+ goto out_5241;
return ret;
+out_5241:
+ phy_driver_unregister(&bcmac131_driver);
out_ac131:
phy_driver_unregister(&bcm57780_driver);
out_57780:
@@ -894,6 +914,7 @@ out_5411:
static void __exit broadcom_exit(void)
{
+ phy_driver_unregister(&bcm5241_driver);
phy_driver_unregister(&bcmac131_driver);
phy_driver_unregister(&bcm57780_driver);
phy_driver_unregister(&bcm50610m_driver);
@@ -910,16 +931,17 @@ module_init(broadcom_init);
module_exit(broadcom_exit);
static struct mdio_device_id broadcom_tbl[] = {
- { 0x00206070, 0xfffffff0 },
- { 0x002060e0, 0xfffffff0 },
- { 0x002060c0, 0xfffffff0 },
- { 0x002060b0, 0xfffffff0 },
- { 0x0143bca0, 0xfffffff0 },
- { 0x0143bcb0, 0xfffffff0 },
+ { PHY_ID_BCM5411, 0xfffffff0 },
+ { PHY_ID_BCM5421, 0xfffffff0 },
+ { PHY_ID_BCM5461, 0xfffffff0 },
+ { PHY_ID_BCM5464, 0xfffffff0 },
+ { PHY_ID_BCM5482, 0xfffffff0 },
+ { PHY_ID_BCM5482, 0xfffffff0 },
{ PHY_ID_BCM50610, 0xfffffff0 },
{ PHY_ID_BCM50610M, 0xfffffff0 },
{ PHY_ID_BCM57780, 0xfffffff0 },
{ PHY_ID_BCMAC131, 0xfffffff0 },
+ { PHY_ID_BCM5241, 0xfffffff0 },
{ }
};
diff --git a/drivers/net/phy/icplus.c b/drivers/net/phy/icplus.c
index 439adafeacb..3f2583f18a3 100644
--- a/drivers/net/phy/icplus.c
+++ b/drivers/net/phy/icplus.c
@@ -116,6 +116,8 @@ static struct phy_driver ip175c_driver = {
.config_init = &ip175c_config_init,
.config_aneg = &ip175c_config_aneg,
.read_status = &ip175c_read_status,
+ .suspend = genphy_suspend,
+ .resume = genphy_resume,
.driver = { .owner = THIS_MODULE,},
};
diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c
index 5a1bd5db2a9..0101f2bdf40 100644
--- a/drivers/net/phy/marvell.c
+++ b/drivers/net/phy/marvell.c
@@ -68,6 +68,15 @@
#define MII_M1111_COPPER 0
#define MII_M1111_FIBER 1
+#define MII_88E1121_PHY_MSCR_PAGE 2
+#define MII_88E1121_PHY_MSCR_REG 21
+#define MII_88E1121_PHY_MSCR_RX_DELAY BIT(5)
+#define MII_88E1121_PHY_MSCR_TX_DELAY BIT(4)
+#define MII_88E1121_PHY_MSCR_DELAY_MASK (~(0x3 << 4))
+
+#define MII_88EC048_PHY_MSCR1_REG 16
+#define MII_88EC048_PHY_MSCR1_PAD_ODD BIT(6)
+
#define MII_88E1121_PHY_LED_CTRL 16
#define MII_88E1121_PHY_LED_PAGE 3
#define MII_88E1121_PHY_LED_DEF 0x0030
@@ -179,7 +188,30 @@ static int marvell_config_aneg(struct phy_device *phydev)
static int m88e1121_config_aneg(struct phy_device *phydev)
{
- int err, temp;
+ int err, oldpage, mscr;
+
+ oldpage = phy_read(phydev, MII_88E1121_PHY_PAGE);
+
+ err = phy_write(phydev, MII_88E1121_PHY_PAGE,
+ MII_88E1121_PHY_MSCR_PAGE);
+ if (err < 0)
+ return err;
+ mscr = phy_read(phydev, MII_88E1121_PHY_MSCR_REG) &
+ MII_88E1121_PHY_MSCR_DELAY_MASK;
+
+ if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID)
+ mscr |= (MII_88E1121_PHY_MSCR_RX_DELAY |
+ MII_88E1121_PHY_MSCR_TX_DELAY);
+ else if (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID)
+ mscr |= MII_88E1121_PHY_MSCR_RX_DELAY;
+ else if (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID)
+ mscr |= MII_88E1121_PHY_MSCR_TX_DELAY;
+
+ err = phy_write(phydev, MII_88E1121_PHY_MSCR_REG, mscr);
+ if (err < 0)
+ return err;
+
+ phy_write(phydev, MII_88E1121_PHY_PAGE, oldpage);
err = phy_write(phydev, MII_BMCR, BMCR_RESET);
if (err < 0)
@@ -190,17 +222,42 @@ static int m88e1121_config_aneg(struct phy_device *phydev)
if (err < 0)
return err;
- temp = phy_read(phydev, MII_88E1121_PHY_PAGE);
+ oldpage = phy_read(phydev, MII_88E1121_PHY_PAGE);
phy_write(phydev, MII_88E1121_PHY_PAGE, MII_88E1121_PHY_LED_PAGE);
phy_write(phydev, MII_88E1121_PHY_LED_CTRL, MII_88E1121_PHY_LED_DEF);
- phy_write(phydev, MII_88E1121_PHY_PAGE, temp);
+ phy_write(phydev, MII_88E1121_PHY_PAGE, oldpage);
err = genphy_config_aneg(phydev);
return err;
}
+static int m88ec048_config_aneg(struct phy_device *phydev)
+{
+ int err, oldpage, mscr;
+
+ oldpage = phy_read(phydev, MII_88E1121_PHY_PAGE);
+
+ err = phy_write(phydev, MII_88E1121_PHY_PAGE,
+ MII_88E1121_PHY_MSCR_PAGE);
+ if (err < 0)
+ return err;
+
+ mscr = phy_read(phydev, MII_88EC048_PHY_MSCR1_REG);
+ mscr |= MII_88EC048_PHY_MSCR1_PAD_ODD;
+
+ err = phy_write(phydev, MII_88E1121_PHY_MSCR_REG, mscr);
+ if (err < 0)
+ return err;
+
+ err = phy_write(phydev, MII_88E1121_PHY_PAGE, oldpage);
+ if (err < 0)
+ return err;
+
+ return m88e1121_config_aneg(phydev);
+}
+
static int m88e1111_config_init(struct phy_device *phydev)
{
int err;
@@ -595,6 +652,19 @@ static struct phy_driver marvell_drivers[] = {
.driver = { .owner = THIS_MODULE },
},
{
+ .phy_id = MARVELL_PHY_ID_88EC048,
+ .phy_id_mask = MARVELL_PHY_ID_MASK,
+ .name = "Marvell 88EC048",
+ .features = PHY_GBIT_FEATURES,
+ .flags = PHY_HAS_INTERRUPT,
+ .config_aneg = &m88ec048_config_aneg,
+ .read_status = &marvell_read_status,
+ .ack_interrupt = &marvell_ack_interrupt,
+ .config_intr = &marvell_config_intr,
+ .did_interrupt = &m88e1121_did_interrupt,
+ .driver = { .owner = THIS_MODULE },
+ },
+ {
.phy_id = MARVELL_PHY_ID_88E1145,
.phy_id_mask = MARVELL_PHY_ID_MASK,
.name = "Marvell 88E1145",
@@ -659,6 +729,7 @@ static struct mdio_device_id marvell_tbl[] = {
{ 0x01410cb0, 0xfffffff0 },
{ 0x01410cd0, 0xfffffff0 },
{ 0x01410e30, 0xfffffff0 },
+ { 0x01410e90, 0xfffffff0 },
{ }
};
diff --git a/drivers/net/phy/mdio-octeon.c b/drivers/net/phy/mdio-octeon.c
index f443d43edd8..bd12ba941be 100644
--- a/drivers/net/phy/mdio-octeon.c
+++ b/drivers/net/phy/mdio-octeon.c
@@ -85,7 +85,7 @@ static int octeon_mdiobus_write(struct mii_bus *bus, int phy_id,
return 0;
}
-static int __init octeon_mdiobus_probe(struct platform_device *pdev)
+static int __devinit octeon_mdiobus_probe(struct platform_device *pdev)
{
struct octeon_mdiobus *bus;
union cvmx_smix_en smi_en;
@@ -143,7 +143,7 @@ err:
return err;
}
-static int __exit octeon_mdiobus_remove(struct platform_device *pdev)
+static int __devexit octeon_mdiobus_remove(struct platform_device *pdev)
{
struct octeon_mdiobus *bus;
union cvmx_smix_en smi_en;
@@ -163,7 +163,7 @@ static struct platform_driver octeon_mdiobus_driver = {
.owner = THIS_MODULE,
},
.probe = octeon_mdiobus_probe,
- .remove = __exit_p(octeon_mdiobus_remove),
+ .remove = __devexit_p(octeon_mdiobus_remove),
};
void octeon_mdiobus_force_mod_depencency(void)
diff --git a/drivers/net/phy/micrel.c b/drivers/net/phy/micrel.c
index 0692f750c40..8bb7db676a5 100644
--- a/drivers/net/phy/micrel.c
+++ b/drivers/net/phy/micrel.c
@@ -12,7 +12,8 @@
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
- * Support : ksz9021 , vsc8201, ks8001
+ * Support : ksz9021 1000/100/10 phy from Micrel
+ * ks8001, ks8737, ks8721, ks8041, ks8051 100/10 phy
*/
#include <linux/kernel.h>
@@ -20,37 +21,146 @@
#include <linux/phy.h>
#define PHY_ID_KSZ9021 0x00221611
-#define PHY_ID_VSC8201 0x000FC413
+#define PHY_ID_KS8737 0x00221720
+#define PHY_ID_KS8041 0x00221510
+#define PHY_ID_KS8051 0x00221550
+/* both for ks8001 Rev. A/B, and for ks8721 Rev 3. */
#define PHY_ID_KS8001 0x0022161A
+/* general Interrupt control/status reg in vendor specific block. */
+#define MII_KSZPHY_INTCS 0x1B
+#define KSZPHY_INTCS_JABBER (1 << 15)
+#define KSZPHY_INTCS_RECEIVE_ERR (1 << 14)
+#define KSZPHY_INTCS_PAGE_RECEIVE (1 << 13)
+#define KSZPHY_INTCS_PARELLEL (1 << 12)
+#define KSZPHY_INTCS_LINK_PARTNER_ACK (1 << 11)
+#define KSZPHY_INTCS_LINK_DOWN (1 << 10)
+#define KSZPHY_INTCS_REMOTE_FAULT (1 << 9)
+#define KSZPHY_INTCS_LINK_UP (1 << 8)
+#define KSZPHY_INTCS_ALL (KSZPHY_INTCS_LINK_UP |\
+ KSZPHY_INTCS_LINK_DOWN)
+
+/* general PHY control reg in vendor specific block. */
+#define MII_KSZPHY_CTRL 0x1F
+/* bitmap of PHY register to set interrupt mode */
+#define KSZPHY_CTRL_INT_ACTIVE_HIGH (1 << 9)
+#define KSZ9021_CTRL_INT_ACTIVE_HIGH (1 << 14)
+#define KS8737_CTRL_INT_ACTIVE_HIGH (1 << 14)
+
+static int kszphy_ack_interrupt(struct phy_device *phydev)
+{
+ /* bit[7..0] int status, which is a read and clear register. */
+ int rc;
+
+ rc = phy_read(phydev, MII_KSZPHY_INTCS);
+
+ return (rc < 0) ? rc : 0;
+}
+
+static int kszphy_set_interrupt(struct phy_device *phydev)
+{
+ int temp;
+ temp = (PHY_INTERRUPT_ENABLED == phydev->interrupts) ?
+ KSZPHY_INTCS_ALL : 0;
+ return phy_write(phydev, MII_KSZPHY_INTCS, temp);
+}
+
+static int kszphy_config_intr(struct phy_device *phydev)
+{
+ int temp, rc;
+
+ /* set the interrupt pin active low */
+ temp = phy_read(phydev, MII_KSZPHY_CTRL);
+ temp &= ~KSZPHY_CTRL_INT_ACTIVE_HIGH;
+ phy_write(phydev, MII_KSZPHY_CTRL, temp);
+ rc = kszphy_set_interrupt(phydev);
+ return rc < 0 ? rc : 0;
+}
+
+static int ksz9021_config_intr(struct phy_device *phydev)
+{
+ int temp, rc;
+
+ /* set the interrupt pin active low */
+ temp = phy_read(phydev, MII_KSZPHY_CTRL);
+ temp &= ~KSZ9021_CTRL_INT_ACTIVE_HIGH;
+ phy_write(phydev, MII_KSZPHY_CTRL, temp);
+ rc = kszphy_set_interrupt(phydev);
+ return rc < 0 ? rc : 0;
+}
+
+static int ks8737_config_intr(struct phy_device *phydev)
+{
+ int temp, rc;
+
+ /* set the interrupt pin active low */
+ temp = phy_read(phydev, MII_KSZPHY_CTRL);
+ temp &= ~KS8737_CTRL_INT_ACTIVE_HIGH;
+ phy_write(phydev, MII_KSZPHY_CTRL, temp);
+ rc = kszphy_set_interrupt(phydev);
+ return rc < 0 ? rc : 0;
+}
static int kszphy_config_init(struct phy_device *phydev)
{
return 0;
}
+static struct phy_driver ks8737_driver = {
+ .phy_id = PHY_ID_KS8737,
+ .phy_id_mask = 0x00fffff0,
+ .name = "Micrel KS8737",
+ .features = (PHY_BASIC_FEATURES | SUPPORTED_Pause),
+ .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
+ .config_init = kszphy_config_init,
+ .config_aneg = genphy_config_aneg,
+ .read_status = genphy_read_status,
+ .ack_interrupt = kszphy_ack_interrupt,
+ .config_intr = ks8737_config_intr,
+ .driver = { .owner = THIS_MODULE,},
+};
+
+static struct phy_driver ks8041_driver = {
+ .phy_id = PHY_ID_KS8041,
+ .phy_id_mask = 0x00fffff0,
+ .name = "Micrel KS8041",
+ .features = (PHY_BASIC_FEATURES | SUPPORTED_Pause
+ | SUPPORTED_Asym_Pause),
+ .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
+ .config_init = kszphy_config_init,
+ .config_aneg = genphy_config_aneg,
+ .read_status = genphy_read_status,
+ .ack_interrupt = kszphy_ack_interrupt,
+ .config_intr = kszphy_config_intr,
+ .driver = { .owner = THIS_MODULE,},
+};
-static struct phy_driver ks8001_driver = {
- .phy_id = PHY_ID_KS8001,
- .name = "Micrel KS8001",
+static struct phy_driver ks8051_driver = {
+ .phy_id = PHY_ID_KS8051,
.phy_id_mask = 0x00fffff0,
- .features = PHY_BASIC_FEATURES,
- .flags = PHY_POLL,
+ .name = "Micrel KS8051",
+ .features = (PHY_BASIC_FEATURES | SUPPORTED_Pause
+ | SUPPORTED_Asym_Pause),
+ .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
.config_init = kszphy_config_init,
.config_aneg = genphy_config_aneg,
.read_status = genphy_read_status,
+ .ack_interrupt = kszphy_ack_interrupt,
+ .config_intr = kszphy_config_intr,
.driver = { .owner = THIS_MODULE,},
};
-static struct phy_driver vsc8201_driver = {
- .phy_id = PHY_ID_VSC8201,
- .name = "Micrel VSC8201",
+static struct phy_driver ks8001_driver = {
+ .phy_id = PHY_ID_KS8001,
+ .name = "Micrel KS8001 or KS8721",
.phy_id_mask = 0x00fffff0,
- .features = PHY_BASIC_FEATURES,
- .flags = PHY_POLL,
+ .features = (PHY_BASIC_FEATURES | SUPPORTED_Pause),
+ .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
.config_init = kszphy_config_init,
.config_aneg = genphy_config_aneg,
.read_status = genphy_read_status,
+ .ack_interrupt = kszphy_ack_interrupt,
+ .config_intr = kszphy_config_intr,
.driver = { .owner = THIS_MODULE,},
};
@@ -58,11 +168,14 @@ static struct phy_driver ksz9021_driver = {
.phy_id = PHY_ID_KSZ9021,
.phy_id_mask = 0x000fff10,
.name = "Micrel KSZ9021 Gigabit PHY",
- .features = PHY_GBIT_FEATURES | SUPPORTED_Pause,
- .flags = PHY_POLL,
+ .features = (PHY_GBIT_FEATURES | SUPPORTED_Pause
+ | SUPPORTED_Asym_Pause),
+ .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
.config_init = kszphy_config_init,
.config_aneg = genphy_config_aneg,
.read_status = genphy_read_status,
+ .ack_interrupt = kszphy_ack_interrupt,
+ .config_intr = ksz9021_config_intr,
.driver = { .owner = THIS_MODULE, },
};
@@ -73,17 +186,29 @@ static int __init ksphy_init(void)
ret = phy_driver_register(&ks8001_driver);
if (ret)
goto err1;
- ret = phy_driver_register(&vsc8201_driver);
+
+ ret = phy_driver_register(&ksz9021_driver);
if (ret)
goto err2;
- ret = phy_driver_register(&ksz9021_driver);
+ ret = phy_driver_register(&ks8737_driver);
if (ret)
goto err3;
+ ret = phy_driver_register(&ks8041_driver);
+ if (ret)
+ goto err4;
+ ret = phy_driver_register(&ks8051_driver);
+ if (ret)
+ goto err5;
+
return 0;
+err5:
+ phy_driver_unregister(&ks8041_driver);
+err4:
+ phy_driver_unregister(&ks8737_driver);
err3:
- phy_driver_unregister(&vsc8201_driver);
+ phy_driver_unregister(&ksz9021_driver);
err2:
phy_driver_unregister(&ks8001_driver);
err1:
@@ -93,8 +218,10 @@ err1:
static void __exit ksphy_exit(void)
{
phy_driver_unregister(&ks8001_driver);
- phy_driver_unregister(&vsc8201_driver);
+ phy_driver_unregister(&ks8737_driver);
phy_driver_unregister(&ksz9021_driver);
+ phy_driver_unregister(&ks8041_driver);
+ phy_driver_unregister(&ks8051_driver);
}
module_init(ksphy_init);
@@ -106,8 +233,10 @@ MODULE_LICENSE("GPL");
static struct mdio_device_id micrel_tbl[] = {
{ PHY_ID_KSZ9021, 0x000fff10 },
- { PHY_ID_VSC8201, 0x00fffff0 },
{ PHY_ID_KS8001, 0x00fffff0 },
+ { PHY_ID_KS8737, 0x00fffff0 },
+ { PHY_ID_KS8041, 0x00fffff0 },
+ { PHY_ID_KS8051, 0x00fffff0 },
{ }
};
diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c
index 64be4664cca..5130db8f5c4 100644
--- a/drivers/net/phy/phy.c
+++ b/drivers/net/phy/phy.c
@@ -309,8 +309,9 @@ EXPORT_SYMBOL(phy_ethtool_gset);
* current state. Use at own risk.
*/
int phy_mii_ioctl(struct phy_device *phydev,
- struct mii_ioctl_data *mii_data, int cmd)
+ struct ifreq *ifr, int cmd)
{
+ struct mii_ioctl_data *mii_data = if_mii(ifr);
u16 val = mii_data->val_in;
switch (cmd) {
@@ -360,6 +361,11 @@ int phy_mii_ioctl(struct phy_device *phydev,
}
break;
+ case SIOCSHWTSTAMP:
+ if (phydev->drv->hwtstamp)
+ return phydev->drv->hwtstamp(phydev, ifr);
+ /* fall through */
+
default:
return -EOPNOTSUPP;
}
diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c
index 1a99bb24410..c0761197c07 100644
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
@@ -460,6 +460,7 @@ int phy_attach_direct(struct net_device *dev, struct phy_device *phydev,
}
phydev->attached_dev = dev;
+ dev->phydev = phydev;
phydev->dev_flags = flags;
@@ -513,6 +514,7 @@ EXPORT_SYMBOL(phy_attach);
*/
void phy_detach(struct phy_device *phydev)
{
+ phydev->attached_dev->phydev = NULL;
phydev->attached_dev = NULL;
/* If the device had no specific driver before (i.e. - it
diff --git a/drivers/net/ppp_generic.c b/drivers/net/ppp_generic.c
index 1b2c2915020..6695a51e09e 100644
--- a/drivers/net/ppp_generic.c
+++ b/drivers/net/ppp_generic.c
@@ -40,7 +40,6 @@
#include <linux/if_arp.h>
#include <linux/ip.h>
#include <linux/tcp.h>
-#include <linux/smp_lock.h>
#include <linux/spinlock.h>
#include <linux/rwsem.h>
#include <linux/stddef.h>
@@ -69,7 +68,6 @@
#define MPHDRLEN 6 /* multilink protocol header length */
#define MPHDRLEN_SSN 4 /* ditto with short sequence numbers */
-#define MIN_FRAG_SIZE 64
/*
* An instance of /dev/ppp can be associated with either a ppp
@@ -181,6 +179,7 @@ struct channel {
* channel.downl.
*/
+static DEFINE_MUTEX(ppp_mutex);
static atomic_t ppp_unit_count = ATOMIC_INIT(0);
static atomic_t channel_count = ATOMIC_INIT(0);
@@ -363,7 +362,6 @@ static const int npindex_to_ethertype[NUM_NP] = {
*/
static int ppp_open(struct inode *inode, struct file *file)
{
- cycle_kernel_lock();
/*
* This could (should?) be enforced by the permissions on /dev/ppp.
*/
@@ -539,14 +537,9 @@ static int get_filter(void __user *arg, struct sock_filter **p)
}
len = uprog.len * sizeof(struct sock_filter);
- code = kmalloc(len, GFP_KERNEL);
- if (code == NULL)
- return -ENOMEM;
-
- if (copy_from_user(code, uprog.filter, len)) {
- kfree(code);
- return -EFAULT;
- }
+ code = memdup_user(uprog.filter, len);
+ if (IS_ERR(code))
+ return PTR_ERR(code);
err = sk_chk_filter(code, uprog.len);
if (err) {
@@ -588,7 +581,7 @@ static long ppp_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
* this fd and reopening /dev/ppp.
*/
err = -EINVAL;
- lock_kernel();
+ mutex_lock(&ppp_mutex);
if (pf->kind == INTERFACE) {
ppp = PF_TO_PPP(pf);
if (file == ppp->owner)
@@ -600,7 +593,7 @@ static long ppp_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
} else
printk(KERN_DEBUG "PPPIOCDETACH file->f_count=%ld\n",
atomic_long_read(&file->f_count));
- unlock_kernel();
+ mutex_unlock(&ppp_mutex);
return err;
}
@@ -608,7 +601,7 @@ static long ppp_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
struct channel *pch;
struct ppp_channel *chan;
- lock_kernel();
+ mutex_lock(&ppp_mutex);
pch = PF_TO_CHANNEL(pf);
switch (cmd) {
@@ -630,7 +623,7 @@ static long ppp_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
err = chan->ops->ioctl(chan, cmd, arg);
up_read(&pch->chan_sem);
}
- unlock_kernel();
+ mutex_unlock(&ppp_mutex);
return err;
}
@@ -640,7 +633,7 @@ static long ppp_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
return -EINVAL;
}
- lock_kernel();
+ mutex_lock(&ppp_mutex);
ppp = PF_TO_PPP(pf);
switch (cmd) {
case PPPIOCSMRU:
@@ -788,7 +781,7 @@ static long ppp_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
default:
err = -ENOTTY;
}
- unlock_kernel();
+ mutex_unlock(&ppp_mutex);
return err;
}
@@ -801,7 +794,7 @@ static int ppp_unattached_ioctl(struct net *net, struct ppp_file *pf,
struct ppp_net *pn;
int __user *p = (int __user *)arg;
- lock_kernel();
+ mutex_lock(&ppp_mutex);
switch (cmd) {
case PPPIOCNEWUNIT:
/* Create a new ppp unit */
@@ -852,7 +845,7 @@ static int ppp_unattached_ioctl(struct net *net, struct ppp_file *pf,
default:
err = -ENOTTY;
}
- unlock_kernel();
+ mutex_unlock(&ppp_mutex);
return err;
}
@@ -1933,9 +1926,9 @@ ppp_receive_mp_frame(struct ppp *ppp, struct sk_buff *skb, struct channel *pch)
/* If the queue is getting long, don't wait any longer for packets
before the start of the queue. */
if (skb_queue_len(&ppp->mrq) >= PPP_MP_MAX_QLEN) {
- struct sk_buff *skb = skb_peek(&ppp->mrq);
- if (seq_before(ppp->minseq, skb->sequence))
- ppp->minseq = skb->sequence;
+ struct sk_buff *mskb = skb_peek(&ppp->mrq);
+ if (seq_before(ppp->minseq, mskb->sequence))
+ ppp->minseq = mskb->sequence;
}
/* Pull completed packets off the queue and receive them. */
diff --git a/drivers/net/pppoe.c b/drivers/net/pppoe.c
index 805b64d1e89..344ef330e12 100644
--- a/drivers/net/pppoe.c
+++ b/drivers/net/pppoe.c
@@ -89,7 +89,6 @@
#define PPPOE_HASH_SIZE (1 << PPPOE_HASH_BITS)
#define PPPOE_HASH_MASK (PPPOE_HASH_SIZE - 1)
-static int pppoe_xmit(struct ppp_channel *chan, struct sk_buff *skb);
static int __pppoe_xmit(struct sock *sk, struct sk_buff *skb);
static const struct proto_ops pppoe_ops;
@@ -949,7 +948,7 @@ static int __pppoe_xmit(struct sock *sk, struct sk_buff *skb)
abort:
kfree_skb(skb);
- return 1;
+ return 0;
}
/************************************************************************
diff --git a/drivers/net/ps3_gelic_wireless.h b/drivers/net/ps3_gelic_wireless.h
index 0a88b535197..f7e51b7d704 100644
--- a/drivers/net/ps3_gelic_wireless.h
+++ b/drivers/net/ps3_gelic_wireless.h
@@ -74,7 +74,7 @@ struct gelic_eurus_common_cfg {
u16 bss_type; /* infra or adhoc */
u16 auth_method; /* shared key or open */
u16 op_mode; /* B/G */
-} __attribute__((packed));
+} __packed;
/* for GELIC_EURUS_CMD_WEP_CFG */
@@ -88,7 +88,7 @@ struct gelic_eurus_wep_cfg {
/* all fields are big endian */
u16 security;
u8 key[4][16];
-} __attribute__((packed));
+} __packed;
/* for GELIC_EURUS_CMD_WPA_CFG */
enum gelic_eurus_wpa_security {
@@ -120,7 +120,7 @@ struct gelic_eurus_wpa_cfg {
u16 security;
u16 psk_type; /* psk key encoding type */
u8 psk[GELIC_WL_EURUS_PSK_MAX_LEN]; /* psk key; hex or passphrase */
-} __attribute__((packed));
+} __packed;
/* for GELIC_EURUS_CMD_{START,GET}_SCAN */
enum gelic_eurus_scan_capability {
@@ -171,7 +171,7 @@ struct gelic_eurus_scan_info {
__be32 reserved3;
__be32 reserved4;
u8 elements[0]; /* ie */
-} __attribute__ ((packed));
+} __packed;
/* the hypervisor returns bbs up to 16 */
#define GELIC_EURUS_MAX_SCAN (16)
@@ -193,7 +193,7 @@ struct gelic_wl_scan_info {
struct gelic_eurus_rssi_info {
/* big endian */
__be16 rssi;
-} __attribute__ ((packed));
+} __packed;
/* for 'stat' member of gelic_wl_info */
diff --git a/drivers/net/qla3xxx.c b/drivers/net/qla3xxx.c
index 54ebb65ada1..6168a130f33 100644
--- a/drivers/net/qla3xxx.c
+++ b/drivers/net/qla3xxx.c
@@ -5,6 +5,8 @@
* See LICENSE.qla3xxx for copyright and licensing details.
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/types.h>
@@ -36,14 +38,16 @@
#include "qla3xxx.h"
-#define DRV_NAME "qla3xxx"
-#define DRV_STRING "QLogic ISP3XXX Network Driver"
+#define DRV_NAME "qla3xxx"
+#define DRV_STRING "QLogic ISP3XXX Network Driver"
#define DRV_VERSION "v2.03.00-k5"
-#define PFX DRV_NAME " "
static const char ql3xxx_driver_name[] = DRV_NAME;
static const char ql3xxx_driver_version[] = DRV_VERSION;
+#define TIMED_OUT_MSG \
+"Timed out waiting for management port to get free before issuing command\n"
+
MODULE_AUTHOR("QLogic Corporation");
MODULE_DESCRIPTION("QLogic ISP3XXX Network Driver " DRV_VERSION " ");
MODULE_LICENSE("GPL");
@@ -73,24 +77,24 @@ MODULE_DEVICE_TABLE(pci, ql3xxx_pci_tbl);
/*
* These are the known PHY's which are used
*/
-typedef enum {
+enum PHY_DEVICE_TYPE {
PHY_TYPE_UNKNOWN = 0,
PHY_VITESSE_VSC8211,
PHY_AGERE_ET1011C,
MAX_PHY_DEV_TYPES
-} PHY_DEVICE_et;
-
-typedef struct {
- PHY_DEVICE_et phyDevice;
- u32 phyIdOUI;
- u16 phyIdModel;
- char *name;
-} PHY_DEVICE_INFO_t;
-
-static const PHY_DEVICE_INFO_t PHY_DEVICES[] =
- {{PHY_TYPE_UNKNOWN, 0x000000, 0x0, "PHY_TYPE_UNKNOWN"},
- {PHY_VITESSE_VSC8211, 0x0003f1, 0xb, "PHY_VITESSE_VSC8211"},
- {PHY_AGERE_ET1011C, 0x00a0bc, 0x1, "PHY_AGERE_ET1011C"},
+};
+
+struct PHY_DEVICE_INFO {
+ const enum PHY_DEVICE_TYPE phyDevice;
+ const u32 phyIdOUI;
+ const u16 phyIdModel;
+ const char *name;
+};
+
+static const struct PHY_DEVICE_INFO PHY_DEVICES[] = {
+ {PHY_TYPE_UNKNOWN, 0x000000, 0x0, "PHY_TYPE_UNKNOWN"},
+ {PHY_VITESSE_VSC8211, 0x0003f1, 0xb, "PHY_VITESSE_VSC8211"},
+ {PHY_AGERE_ET1011C, 0x00a0bc, 0x1, "PHY_AGERE_ET1011C"},
};
@@ -100,7 +104,8 @@ static const PHY_DEVICE_INFO_t PHY_DEVICES[] =
static int ql_sem_spinlock(struct ql3_adapter *qdev,
u32 sem_mask, u32 sem_bits)
{
- struct ql3xxx_port_registers __iomem *port_regs = qdev->mem_map_registers;
+ struct ql3xxx_port_registers __iomem *port_regs =
+ qdev->mem_map_registers;
u32 value;
unsigned int seconds = 3;
@@ -111,20 +116,22 @@ static int ql_sem_spinlock(struct ql3_adapter *qdev,
if ((value & (sem_mask >> 16)) == sem_bits)
return 0;
ssleep(1);
- } while(--seconds);
+ } while (--seconds);
return -1;
}
static void ql_sem_unlock(struct ql3_adapter *qdev, u32 sem_mask)
{
- struct ql3xxx_port_registers __iomem *port_regs = qdev->mem_map_registers;
+ struct ql3xxx_port_registers __iomem *port_regs =
+ qdev->mem_map_registers;
writel(sem_mask, &port_regs->CommonRegs.semaphoreReg);
readl(&port_regs->CommonRegs.semaphoreReg);
}
static int ql_sem_lock(struct ql3_adapter *qdev, u32 sem_mask, u32 sem_bits)
{
- struct ql3xxx_port_registers __iomem *port_regs = qdev->mem_map_registers;
+ struct ql3xxx_port_registers __iomem *port_regs =
+ qdev->mem_map_registers;
u32 value;
writel((sem_mask | sem_bits), &port_regs->CommonRegs.semaphoreReg);
@@ -139,32 +146,28 @@ static int ql_wait_for_drvr_lock(struct ql3_adapter *qdev)
{
int i = 0;
- while (1) {
- if (!ql_sem_lock(qdev,
- QL_DRVR_SEM_MASK,
- (QL_RESOURCE_BITS_BASE_CODE | (qdev->mac_index)
- * 2) << 1)) {
- if (i < 10) {
- ssleep(1);
- i++;
- } else {
- printk(KERN_ERR PFX "%s: Timed out waiting for "
- "driver lock...\n",
- qdev->ndev->name);
- return 0;
- }
- } else {
- printk(KERN_DEBUG PFX
- "%s: driver lock acquired.\n",
- qdev->ndev->name);
+ while (i < 10) {
+ if (i)
+ ssleep(1);
+
+ if (ql_sem_lock(qdev,
+ QL_DRVR_SEM_MASK,
+ (QL_RESOURCE_BITS_BASE_CODE | (qdev->mac_index)
+ * 2) << 1)) {
+ netdev_printk(KERN_DEBUG, qdev->ndev,
+ "driver lock acquired\n");
return 1;
}
}
+
+ netdev_err(qdev->ndev, "Timed out waiting for driver lock...\n");
+ return 0;
}
static void ql_set_register_page(struct ql3_adapter *qdev, u32 page)
{
- struct ql3xxx_port_registers __iomem *port_regs = qdev->mem_map_registers;
+ struct ql3xxx_port_registers __iomem *port_regs =
+ qdev->mem_map_registers;
writel(((ISP_CONTROL_NP_MASK << 16) | page),
&port_regs->CommonRegs.ispControlStatus);
@@ -172,8 +175,7 @@ static void ql_set_register_page(struct ql3_adapter *qdev, u32 page)
qdev->current_page = page;
}
-static u32 ql_read_common_reg_l(struct ql3_adapter *qdev,
- u32 __iomem * reg)
+static u32 ql_read_common_reg_l(struct ql3_adapter *qdev, u32 __iomem *reg)
{
u32 value;
unsigned long hw_flags;
@@ -185,8 +187,7 @@ static u32 ql_read_common_reg_l(struct ql3_adapter *qdev,
return value;
}
-static u32 ql_read_common_reg(struct ql3_adapter *qdev,
- u32 __iomem * reg)
+static u32 ql_read_common_reg(struct ql3_adapter *qdev, u32 __iomem *reg)
{
return readl(reg);
}
@@ -199,7 +200,7 @@ static u32 ql_read_page0_reg_l(struct ql3_adapter *qdev, u32 __iomem *reg)
spin_lock_irqsave(&qdev->hw_lock, hw_flags);
if (qdev->current_page != 0)
- ql_set_register_page(qdev,0);
+ ql_set_register_page(qdev, 0);
value = readl(reg);
spin_unlock_irqrestore(&qdev->hw_lock, hw_flags);
@@ -209,7 +210,7 @@ static u32 ql_read_page0_reg_l(struct ql3_adapter *qdev, u32 __iomem *reg)
static u32 ql_read_page0_reg(struct ql3_adapter *qdev, u32 __iomem *reg)
{
if (qdev->current_page != 0)
- ql_set_register_page(qdev,0);
+ ql_set_register_page(qdev, 0);
return readl(reg);
}
@@ -243,7 +244,7 @@ static void ql_write_page0_reg(struct ql3_adapter *qdev,
u32 __iomem *reg, u32 value)
{
if (qdev->current_page != 0)
- ql_set_register_page(qdev,0);
+ ql_set_register_page(qdev, 0);
writel(value, reg);
readl(reg);
}
@@ -255,7 +256,7 @@ static void ql_write_page1_reg(struct ql3_adapter *qdev,
u32 __iomem *reg, u32 value)
{
if (qdev->current_page != 1)
- ql_set_register_page(qdev,1);
+ ql_set_register_page(qdev, 1);
writel(value, reg);
readl(reg);
}
@@ -267,14 +268,15 @@ static void ql_write_page2_reg(struct ql3_adapter *qdev,
u32 __iomem *reg, u32 value)
{
if (qdev->current_page != 2)
- ql_set_register_page(qdev,2);
+ ql_set_register_page(qdev, 2);
writel(value, reg);
readl(reg);
}
static void ql_disable_interrupts(struct ql3_adapter *qdev)
{
- struct ql3xxx_port_registers __iomem *port_regs = qdev->mem_map_registers;
+ struct ql3xxx_port_registers __iomem *port_regs =
+ qdev->mem_map_registers;
ql_write_common_reg_l(qdev, &port_regs->CommonRegs.ispInterruptMaskReg,
(ISP_IMR_ENABLE_INT << 16));
@@ -283,7 +285,8 @@ static void ql_disable_interrupts(struct ql3_adapter *qdev)
static void ql_enable_interrupts(struct ql3_adapter *qdev)
{
- struct ql3xxx_port_registers __iomem *port_regs = qdev->mem_map_registers;
+ struct ql3xxx_port_registers __iomem *port_regs =
+ qdev->mem_map_registers;
ql_write_common_reg_l(qdev, &port_regs->CommonRegs.ispInterruptMaskReg,
((0xff << 16) | ISP_IMR_ENABLE_INT));
@@ -308,8 +311,7 @@ static void ql_release_to_lrg_buf_free_list(struct ql3_adapter *qdev,
lrg_buf_cb->skb = netdev_alloc_skb(qdev->ndev,
qdev->lrg_buffer_len);
if (unlikely(!lrg_buf_cb->skb)) {
- printk(KERN_ERR PFX "%s: failed netdev_alloc_skb().\n",
- qdev->ndev->name);
+ netdev_err(qdev->ndev, "failed netdev_alloc_skb()\n");
qdev->lrg_buf_skb_check++;
} else {
/*
@@ -323,9 +325,10 @@ static void ql_release_to_lrg_buf_free_list(struct ql3_adapter *qdev,
QL_HEADER_SPACE,
PCI_DMA_FROMDEVICE);
err = pci_dma_mapping_error(qdev->pdev, map);
- if(err) {
- printk(KERN_ERR "%s: PCI mapping failed with error: %d\n",
- qdev->ndev->name, err);
+ if (err) {
+ netdev_err(qdev->ndev,
+ "PCI mapping failed with error: %d\n",
+ err);
dev_kfree_skb(lrg_buf_cb->skb);
lrg_buf_cb->skb = NULL;
@@ -350,10 +353,11 @@ static void ql_release_to_lrg_buf_free_list(struct ql3_adapter *qdev,
static struct ql_rcv_buf_cb *ql_get_from_lrg_buf_free_list(struct ql3_adapter
*qdev)
{
- struct ql_rcv_buf_cb *lrg_buf_cb;
+ struct ql_rcv_buf_cb *lrg_buf_cb = qdev->lrg_buf_free_head;
- if ((lrg_buf_cb = qdev->lrg_buf_free_head) != NULL) {
- if ((qdev->lrg_buf_free_head = lrg_buf_cb->next) == NULL)
+ if (lrg_buf_cb != NULL) {
+ qdev->lrg_buf_free_head = lrg_buf_cb->next;
+ if (qdev->lrg_buf_free_head == NULL)
qdev->lrg_buf_free_tail = NULL;
qdev->lrg_buf_free_count--;
}
@@ -374,13 +378,13 @@ static void eeprom_readword(struct ql3_adapter *qdev, u32 eepromAddr,
static void fm93c56a_select(struct ql3_adapter *qdev)
{
struct ql3xxx_port_registers __iomem *port_regs =
- qdev->mem_map_registers;
+ qdev->mem_map_registers;
+ u32 *spir = &port_regs->CommonRegs.serialPortInterfaceReg;
qdev->eeprom_cmd_data = AUBURN_EEPROM_CS_1;
- ql_write_nvram_reg(qdev, &port_regs->CommonRegs.serialPortInterfaceReg,
- ISP_NVRAM_MASK | qdev->eeprom_cmd_data);
- ql_write_nvram_reg(qdev, &port_regs->CommonRegs.serialPortInterfaceReg,
- ((ISP_NVRAM_MASK << 16) | qdev->eeprom_cmd_data));
+ ql_write_nvram_reg(qdev, spir, ISP_NVRAM_MASK | qdev->eeprom_cmd_data);
+ ql_write_nvram_reg(qdev, spir,
+ ((ISP_NVRAM_MASK << 16) | qdev->eeprom_cmd_data));
}
/*
@@ -393,51 +397,40 @@ static void fm93c56a_cmd(struct ql3_adapter *qdev, u32 cmd, u32 eepromAddr)
u32 dataBit;
u32 previousBit;
struct ql3xxx_port_registers __iomem *port_regs =
- qdev->mem_map_registers;
+ qdev->mem_map_registers;
+ u32 *spir = &port_regs->CommonRegs.serialPortInterfaceReg;
/* Clock in a zero, then do the start bit */
- ql_write_nvram_reg(qdev, &port_regs->CommonRegs.serialPortInterfaceReg,
- ISP_NVRAM_MASK | qdev->eeprom_cmd_data |
- AUBURN_EEPROM_DO_1);
- ql_write_nvram_reg(qdev, &port_regs->CommonRegs.serialPortInterfaceReg,
- ISP_NVRAM_MASK | qdev->
- eeprom_cmd_data | AUBURN_EEPROM_DO_1 |
- AUBURN_EEPROM_CLK_RISE);
- ql_write_nvram_reg(qdev, &port_regs->CommonRegs.serialPortInterfaceReg,
- ISP_NVRAM_MASK | qdev->
- eeprom_cmd_data | AUBURN_EEPROM_DO_1 |
- AUBURN_EEPROM_CLK_FALL);
+ ql_write_nvram_reg(qdev, spir,
+ (ISP_NVRAM_MASK | qdev->eeprom_cmd_data |
+ AUBURN_EEPROM_DO_1));
+ ql_write_nvram_reg(qdev, spir,
+ (ISP_NVRAM_MASK | qdev->eeprom_cmd_data |
+ AUBURN_EEPROM_DO_1 | AUBURN_EEPROM_CLK_RISE));
+ ql_write_nvram_reg(qdev, spir,
+ (ISP_NVRAM_MASK | qdev->eeprom_cmd_data |
+ AUBURN_EEPROM_DO_1 | AUBURN_EEPROM_CLK_FALL));
mask = 1 << (FM93C56A_CMD_BITS - 1);
/* Force the previous data bit to be different */
previousBit = 0xffff;
for (i = 0; i < FM93C56A_CMD_BITS; i++) {
- dataBit =
- (cmd & mask) ? AUBURN_EEPROM_DO_1 : AUBURN_EEPROM_DO_0;
+ dataBit = (cmd & mask)
+ ? AUBURN_EEPROM_DO_1
+ : AUBURN_EEPROM_DO_0;
if (previousBit != dataBit) {
- /*
- * If the bit changed, then change the DO state to
- * match
- */
- ql_write_nvram_reg(qdev,
- &port_regs->CommonRegs.
- serialPortInterfaceReg,
- ISP_NVRAM_MASK | qdev->
- eeprom_cmd_data | dataBit);
+ /* If the bit changed, change the DO state to match */
+ ql_write_nvram_reg(qdev, spir,
+ (ISP_NVRAM_MASK |
+ qdev->eeprom_cmd_data | dataBit));
previousBit = dataBit;
}
- ql_write_nvram_reg(qdev,
- &port_regs->CommonRegs.
- serialPortInterfaceReg,
- ISP_NVRAM_MASK | qdev->
- eeprom_cmd_data | dataBit |
- AUBURN_EEPROM_CLK_RISE);
- ql_write_nvram_reg(qdev,
- &port_regs->CommonRegs.
- serialPortInterfaceReg,
- ISP_NVRAM_MASK | qdev->
- eeprom_cmd_data | dataBit |
- AUBURN_EEPROM_CLK_FALL);
+ ql_write_nvram_reg(qdev, spir,
+ (ISP_NVRAM_MASK | qdev->eeprom_cmd_data |
+ dataBit | AUBURN_EEPROM_CLK_RISE));
+ ql_write_nvram_reg(qdev, spir,
+ (ISP_NVRAM_MASK | qdev->eeprom_cmd_data |
+ dataBit | AUBURN_EEPROM_CLK_FALL));
cmd = cmd << 1;
}
@@ -445,33 +438,24 @@ static void fm93c56a_cmd(struct ql3_adapter *qdev, u32 cmd, u32 eepromAddr)
/* Force the previous data bit to be different */
previousBit = 0xffff;
for (i = 0; i < addrBits; i++) {
- dataBit =
- (eepromAddr & mask) ? AUBURN_EEPROM_DO_1 :
- AUBURN_EEPROM_DO_0;
+ dataBit = (eepromAddr & mask) ? AUBURN_EEPROM_DO_1
+ : AUBURN_EEPROM_DO_0;
if (previousBit != dataBit) {
/*
* If the bit changed, then change the DO state to
* match
*/
- ql_write_nvram_reg(qdev,
- &port_regs->CommonRegs.
- serialPortInterfaceReg,
- ISP_NVRAM_MASK | qdev->
- eeprom_cmd_data | dataBit);
+ ql_write_nvram_reg(qdev, spir,
+ (ISP_NVRAM_MASK |
+ qdev->eeprom_cmd_data | dataBit));
previousBit = dataBit;
}
- ql_write_nvram_reg(qdev,
- &port_regs->CommonRegs.
- serialPortInterfaceReg,
- ISP_NVRAM_MASK | qdev->
- eeprom_cmd_data | dataBit |
- AUBURN_EEPROM_CLK_RISE);
- ql_write_nvram_reg(qdev,
- &port_regs->CommonRegs.
- serialPortInterfaceReg,
- ISP_NVRAM_MASK | qdev->
- eeprom_cmd_data | dataBit |
- AUBURN_EEPROM_CLK_FALL);
+ ql_write_nvram_reg(qdev, spir,
+ (ISP_NVRAM_MASK | qdev->eeprom_cmd_data |
+ dataBit | AUBURN_EEPROM_CLK_RISE));
+ ql_write_nvram_reg(qdev, spir,
+ (ISP_NVRAM_MASK | qdev->eeprom_cmd_data |
+ dataBit | AUBURN_EEPROM_CLK_FALL));
eepromAddr = eepromAddr << 1;
}
}
@@ -482,10 +466,11 @@ static void fm93c56a_cmd(struct ql3_adapter *qdev, u32 cmd, u32 eepromAddr)
static void fm93c56a_deselect(struct ql3_adapter *qdev)
{
struct ql3xxx_port_registers __iomem *port_regs =
- qdev->mem_map_registers;
+ qdev->mem_map_registers;
+ u32 *spir = &port_regs->CommonRegs.serialPortInterfaceReg;
+
qdev->eeprom_cmd_data = AUBURN_EEPROM_CS_0;
- ql_write_nvram_reg(qdev, &port_regs->CommonRegs.serialPortInterfaceReg,
- ISP_NVRAM_MASK | qdev->eeprom_cmd_data);
+ ql_write_nvram_reg(qdev, spir, ISP_NVRAM_MASK | qdev->eeprom_cmd_data);
}
/*
@@ -497,29 +482,23 @@ static void fm93c56a_datain(struct ql3_adapter *qdev, unsigned short *value)
u32 data = 0;
u32 dataBit;
struct ql3xxx_port_registers __iomem *port_regs =
- qdev->mem_map_registers;
+ qdev->mem_map_registers;
+ u32 *spir = &port_regs->CommonRegs.serialPortInterfaceReg;
/* Read the data bits */
/* The first bit is a dummy. Clock right over it. */
for (i = 0; i < dataBits; i++) {
- ql_write_nvram_reg(qdev,
- &port_regs->CommonRegs.
- serialPortInterfaceReg,
- ISP_NVRAM_MASK | qdev->eeprom_cmd_data |
- AUBURN_EEPROM_CLK_RISE);
- ql_write_nvram_reg(qdev,
- &port_regs->CommonRegs.
- serialPortInterfaceReg,
- ISP_NVRAM_MASK | qdev->eeprom_cmd_data |
- AUBURN_EEPROM_CLK_FALL);
- dataBit =
- (ql_read_common_reg
- (qdev,
- &port_regs->CommonRegs.
- serialPortInterfaceReg) & AUBURN_EEPROM_DI_1) ? 1 : 0;
+ ql_write_nvram_reg(qdev, spir,
+ ISP_NVRAM_MASK | qdev->eeprom_cmd_data |
+ AUBURN_EEPROM_CLK_RISE);
+ ql_write_nvram_reg(qdev, spir,
+ ISP_NVRAM_MASK | qdev->eeprom_cmd_data |
+ AUBURN_EEPROM_CLK_FALL);
+ dataBit = (ql_read_common_reg(qdev, spir) &
+ AUBURN_EEPROM_DI_1) ? 1 : 0;
data = (data << 1) | dataBit;
}
- *value = (u16) data;
+ *value = (u16)data;
}
/*
@@ -551,13 +530,12 @@ static int ql_get_nvram_params(struct ql3_adapter *qdev)
spin_lock_irqsave(&qdev->hw_lock, hw_flags);
- pEEPROMData = (u16 *) & qdev->nvram_data;
+ pEEPROMData = (u16 *)&qdev->nvram_data;
qdev->eeprom_cmd_data = 0;
- if(ql_sem_spinlock(qdev, QL_NVRAM_SEM_MASK,
+ if (ql_sem_spinlock(qdev, QL_NVRAM_SEM_MASK,
(QL_RESOURCE_BITS_BASE_CODE | (qdev->mac_index) *
2) << 10)) {
- printk(KERN_ERR PFX"%s: Failed ql_sem_spinlock().\n",
- __func__);
+ pr_err("%s: Failed ql_sem_spinlock()\n", __func__);
spin_unlock_irqrestore(&qdev->hw_lock, hw_flags);
return -1;
}
@@ -570,8 +548,8 @@ static int ql_get_nvram_params(struct ql3_adapter *qdev)
ql_sem_unlock(qdev, QL_NVRAM_SEM_MASK);
if (checksum != 0) {
- printk(KERN_ERR PFX "%s: checksum should be zero, is %x!!\n",
- qdev->ndev->name, checksum);
+ netdev_err(qdev->ndev, "checksum should be zero, is %x!!\n",
+ checksum);
spin_unlock_irqrestore(&qdev->hw_lock, hw_flags);
return -1;
}
@@ -587,7 +565,7 @@ static const u32 PHYAddr[2] = {
static int ql_wait_for_mii_ready(struct ql3_adapter *qdev)
{
struct ql3xxx_port_registers __iomem *port_regs =
- qdev->mem_map_registers;
+ qdev->mem_map_registers;
u32 temp;
int count = 1000;
@@ -604,7 +582,7 @@ static int ql_wait_for_mii_ready(struct ql3_adapter *qdev)
static void ql_mii_enable_scan_mode(struct ql3_adapter *qdev)
{
struct ql3xxx_port_registers __iomem *port_regs =
- qdev->mem_map_registers;
+ qdev->mem_map_registers;
u32 scanControl;
if (qdev->numPorts > 1) {
@@ -632,7 +610,7 @@ static u8 ql_mii_disable_scan_mode(struct ql3_adapter *qdev)
{
u8 ret;
struct ql3xxx_port_registers __iomem *port_regs =
- qdev->mem_map_registers;
+ qdev->mem_map_registers;
/* See if scan mode is enabled before we turn it off */
if (ql_read_page0_reg(qdev, &port_regs->macMIIMgmtControlReg) &
@@ -662,17 +640,13 @@ static int ql_mii_write_reg_ex(struct ql3_adapter *qdev,
u16 regAddr, u16 value, u32 phyAddr)
{
struct ql3xxx_port_registers __iomem *port_regs =
- qdev->mem_map_registers;
+ qdev->mem_map_registers;
u8 scanWasEnabled;
scanWasEnabled = ql_mii_disable_scan_mode(qdev);
if (ql_wait_for_mii_ready(qdev)) {
- if (netif_msg_link(qdev))
- printk(KERN_WARNING PFX
- "%s Timed out waiting for management port to "
- "get free before issuing command.\n",
- qdev->ndev->name);
+ netif_warn(qdev, link, qdev->ndev, TIMED_OUT_MSG);
return -1;
}
@@ -683,11 +657,7 @@ static int ql_mii_write_reg_ex(struct ql3_adapter *qdev,
/* Wait for write to complete 9/10/04 SJP */
if (ql_wait_for_mii_ready(qdev)) {
- if (netif_msg_link(qdev))
- printk(KERN_WARNING PFX
- "%s: Timed out waiting for management port to "
- "get free before issuing command.\n",
- qdev->ndev->name);
+ netif_warn(qdev, link, qdev->ndev, TIMED_OUT_MSG);
return -1;
}
@@ -698,21 +668,17 @@ static int ql_mii_write_reg_ex(struct ql3_adapter *qdev,
}
static int ql_mii_read_reg_ex(struct ql3_adapter *qdev, u16 regAddr,
- u16 * value, u32 phyAddr)
+ u16 *value, u32 phyAddr)
{
struct ql3xxx_port_registers __iomem *port_regs =
- qdev->mem_map_registers;
+ qdev->mem_map_registers;
u8 scanWasEnabled;
u32 temp;
scanWasEnabled = ql_mii_disable_scan_mode(qdev);
if (ql_wait_for_mii_ready(qdev)) {
- if (netif_msg_link(qdev))
- printk(KERN_WARNING PFX
- "%s: Timed out waiting for management port to "
- "get free before issuing command.\n",
- qdev->ndev->name);
+ netif_warn(qdev, link, qdev->ndev, TIMED_OUT_MSG);
return -1;
}
@@ -727,11 +693,7 @@ static int ql_mii_read_reg_ex(struct ql3_adapter *qdev, u16 regAddr,
/* Wait for the read to complete */
if (ql_wait_for_mii_ready(qdev)) {
- if (netif_msg_link(qdev))
- printk(KERN_WARNING PFX
- "%s: Timed out waiting for management port to "
- "get free after issuing command.\n",
- qdev->ndev->name);
+ netif_warn(qdev, link, qdev->ndev, TIMED_OUT_MSG);
return -1;
}
@@ -747,16 +709,12 @@ static int ql_mii_read_reg_ex(struct ql3_adapter *qdev, u16 regAddr,
static int ql_mii_write_reg(struct ql3_adapter *qdev, u16 regAddr, u16 value)
{
struct ql3xxx_port_registers __iomem *port_regs =
- qdev->mem_map_registers;
+ qdev->mem_map_registers;
ql_mii_disable_scan_mode(qdev);
if (ql_wait_for_mii_ready(qdev)) {
- if (netif_msg_link(qdev))
- printk(KERN_WARNING PFX
- "%s: Timed out waiting for management port to "
- "get free before issuing command.\n",
- qdev->ndev->name);
+ netif_warn(qdev, link, qdev->ndev, TIMED_OUT_MSG);
return -1;
}
@@ -767,11 +725,7 @@ static int ql_mii_write_reg(struct ql3_adapter *qdev, u16 regAddr, u16 value)
/* Wait for write to complete. */
if (ql_wait_for_mii_ready(qdev)) {
- if (netif_msg_link(qdev))
- printk(KERN_WARNING PFX
- "%s: Timed out waiting for management port to "
- "get free before issuing command.\n",
- qdev->ndev->name);
+ netif_warn(qdev, link, qdev->ndev, TIMED_OUT_MSG);
return -1;
}
@@ -784,16 +738,12 @@ static int ql_mii_read_reg(struct ql3_adapter *qdev, u16 regAddr, u16 *value)
{
u32 temp;
struct ql3xxx_port_registers __iomem *port_regs =
- qdev->mem_map_registers;
+ qdev->mem_map_registers;
ql_mii_disable_scan_mode(qdev);
if (ql_wait_for_mii_ready(qdev)) {
- if (netif_msg_link(qdev))
- printk(KERN_WARNING PFX
- "%s: Timed out waiting for management port to "
- "get free before issuing command.\n",
- qdev->ndev->name);
+ netif_warn(qdev, link, qdev->ndev, TIMED_OUT_MSG);
return -1;
}
@@ -808,11 +758,7 @@ static int ql_mii_read_reg(struct ql3_adapter *qdev, u16 regAddr, u16 *value)
/* Wait for the read to complete */
if (ql_wait_for_mii_ready(qdev)) {
- if (netif_msg_link(qdev))
- printk(KERN_WARNING PFX
- "%s: Timed out waiting for management port to "
- "get free before issuing command.\n",
- qdev->ndev->name);
+ netif_warn(qdev, link, qdev->ndev, TIMED_OUT_MSG);
return -1;
}
@@ -898,7 +844,7 @@ static int ql_is_petbi_neg_pause(struct ql3_adapter *qdev)
static void phyAgereSpecificInit(struct ql3_adapter *qdev, u32 miiAddr)
{
- printk(KERN_INFO "%s: enabling Agere specific PHY\n", qdev->ndev->name);
+ netdev_info(qdev->ndev, "enabling Agere specific PHY\n");
/* power down device bit 11 = 1 */
ql_mii_write_reg_ex(qdev, 0x00, 0x1940, miiAddr);
/* enable diagnostic mode bit 2 = 1 */
@@ -918,7 +864,8 @@ static void phyAgereSpecificInit(struct ql3_adapter *qdev, u32 miiAddr)
/* point to hidden reg 0x2806 */
ql_mii_write_reg_ex(qdev, 0x10, 0x2806, miiAddr);
/* Write new PHYAD w/bit 5 set */
- ql_mii_write_reg_ex(qdev, 0x11, 0x0020 | (PHYAddr[qdev->mac_index] >> 8), miiAddr);
+ ql_mii_write_reg_ex(qdev, 0x11,
+ 0x0020 | (PHYAddr[qdev->mac_index] >> 8), miiAddr);
/*
* Disable diagnostic mode bit 2 = 0
* Power up device bit 11 = 0
@@ -929,21 +876,19 @@ static void phyAgereSpecificInit(struct ql3_adapter *qdev, u32 miiAddr)
ql_mii_write_reg(qdev, 0x1c, 0xfaf0);
}
-static PHY_DEVICE_et getPhyType (struct ql3_adapter *qdev,
- u16 phyIdReg0, u16 phyIdReg1)
+static enum PHY_DEVICE_TYPE getPhyType(struct ql3_adapter *qdev,
+ u16 phyIdReg0, u16 phyIdReg1)
{
- PHY_DEVICE_et result = PHY_TYPE_UNKNOWN;
+ enum PHY_DEVICE_TYPE result = PHY_TYPE_UNKNOWN;
u32 oui;
u16 model;
int i;
- if (phyIdReg0 == 0xffff) {
+ if (phyIdReg0 == 0xffff)
return result;
- }
- if (phyIdReg1 == 0xffff) {
+ if (phyIdReg1 == 0xffff)
return result;
- }
/* oui is split between two registers */
oui = (phyIdReg0 << 6) | ((phyIdReg1 & PHY_OUI_1_MASK) >> 10);
@@ -951,15 +896,13 @@ static PHY_DEVICE_et getPhyType (struct ql3_adapter *qdev,
model = (phyIdReg1 & PHY_MODEL_MASK) >> 4;
/* Scan table for this PHY */
- for(i = 0; i < MAX_PHY_DEV_TYPES; i++) {
- if ((oui == PHY_DEVICES[i].phyIdOUI) && (model == PHY_DEVICES[i].phyIdModel))
- {
+ for (i = 0; i < MAX_PHY_DEV_TYPES; i++) {
+ if ((oui == PHY_DEVICES[i].phyIdOUI) &&
+ (model == PHY_DEVICES[i].phyIdModel)) {
+ netdev_info(qdev->ndev, "Phy: %s\n",
+ PHY_DEVICES[i].name);
result = PHY_DEVICES[i].phyDevice;
-
- printk(KERN_INFO "%s: Phy: %s\n",
- qdev->ndev->name, PHY_DEVICES[i].name);
-
- break;
+ break;
}
}
@@ -970,9 +913,8 @@ static int ql_phy_get_speed(struct ql3_adapter *qdev)
{
u16 reg;
- switch(qdev->phyType) {
- case PHY_AGERE_ET1011C:
- {
+ switch (qdev->phyType) {
+ case PHY_AGERE_ET1011C: {
if (ql_mii_read_reg(qdev, 0x1A, &reg) < 0)
return 0;
@@ -980,20 +922,20 @@ static int ql_phy_get_speed(struct ql3_adapter *qdev)
break;
}
default:
- if (ql_mii_read_reg(qdev, AUX_CONTROL_STATUS, &reg) < 0)
- return 0;
+ if (ql_mii_read_reg(qdev, AUX_CONTROL_STATUS, &reg) < 0)
+ return 0;
- reg = (((reg & 0x18) >> 3) & 3);
+ reg = (((reg & 0x18) >> 3) & 3);
}
- switch(reg) {
- case 2:
+ switch (reg) {
+ case 2:
return SPEED_1000;
- case 1:
+ case 1:
return SPEED_100;
- case 0:
+ case 0:
return SPEED_10;
- default:
+ default:
return -1;
}
}
@@ -1002,17 +944,15 @@ static int ql_is_full_dup(struct ql3_adapter *qdev)
{
u16 reg;
- switch(qdev->phyType) {
- case PHY_AGERE_ET1011C:
- {
+ switch (qdev->phyType) {
+ case PHY_AGERE_ET1011C: {
if (ql_mii_read_reg(qdev, 0x1A, &reg))
return 0;
return ((reg & 0x0080) && (reg & 0x1000)) != 0;
}
case PHY_VITESSE_VSC8211:
- default:
- {
+ default: {
if (ql_mii_read_reg(qdev, AUX_CONTROL_STATUS, &reg) < 0)
return 0;
return (reg & PHY_AUX_DUPLEX_STAT) != 0;
@@ -1040,17 +980,15 @@ static int PHY_Setup(struct ql3_adapter *qdev)
/* Determine the PHY we are using by reading the ID's */
err = ql_mii_read_reg(qdev, PHY_ID_0_REG, &reg1);
- if(err != 0) {
- printk(KERN_ERR "%s: Could not read from reg PHY_ID_0_REG\n",
- qdev->ndev->name);
- return err;
+ if (err != 0) {
+ netdev_err(qdev->ndev, "Could not read from reg PHY_ID_0_REG\n");
+ return err;
}
err = ql_mii_read_reg(qdev, PHY_ID_1_REG, &reg2);
- if(err != 0) {
- printk(KERN_ERR "%s: Could not read from reg PHY_ID_0_REG\n",
- qdev->ndev->name);
- return err;
+ if (err != 0) {
+ netdev_err(qdev->ndev, "Could not read from reg PHY_ID_1_REG\n");
+ return err;
}
/* Check if we have a Agere PHY */
@@ -1058,24 +996,22 @@ static int PHY_Setup(struct ql3_adapter *qdev)
/* Determine which MII address we should be using
determined by the index of the card */
- if (qdev->mac_index == 0) {
+ if (qdev->mac_index == 0)
miiAddr = MII_AGERE_ADDR_1;
- } else {
+ else
miiAddr = MII_AGERE_ADDR_2;
- }
- err =ql_mii_read_reg_ex(qdev, PHY_ID_0_REG, &reg1, miiAddr);
- if(err != 0) {
- printk(KERN_ERR "%s: Could not read from reg PHY_ID_0_REG after Agere detected\n",
- qdev->ndev->name);
+ err = ql_mii_read_reg_ex(qdev, PHY_ID_0_REG, &reg1, miiAddr);
+ if (err != 0) {
+ netdev_err(qdev->ndev,
+ "Could not read from reg PHY_ID_0_REG after Agere detected\n");
return err;
}
err = ql_mii_read_reg_ex(qdev, PHY_ID_1_REG, &reg2, miiAddr);
- if(err != 0) {
- printk(KERN_ERR "%s: Could not read from reg PHY_ID_0_REG after Agere detected\n",
- qdev->ndev->name);
- return err;
+ if (err != 0) {
+ netdev_err(qdev->ndev, "Could not read from reg PHY_ID_1_REG after Agere detected\n");
+ return err;
}
/* We need to remember to initialize the Agere PHY */
@@ -1090,7 +1026,7 @@ static int PHY_Setup(struct ql3_adapter *qdev)
/* need this here so address gets changed */
phyAgereSpecificInit(qdev, miiAddr);
} else if (qdev->phyType == PHY_TYPE_UNKNOWN) {
- printk(KERN_ERR "%s: PHY is unknown\n", qdev->ndev->name);
+ netdev_err(qdev->ndev, "PHY is unknown\n");
return -EIO;
}
@@ -1103,7 +1039,7 @@ static int PHY_Setup(struct ql3_adapter *qdev)
static void ql_mac_enable(struct ql3_adapter *qdev, u32 enable)
{
struct ql3xxx_port_registers __iomem *port_regs =
- qdev->mem_map_registers;
+ qdev->mem_map_registers;
u32 value;
if (enable)
@@ -1123,7 +1059,7 @@ static void ql_mac_enable(struct ql3_adapter *qdev, u32 enable)
static void ql_mac_cfg_soft_reset(struct ql3_adapter *qdev, u32 enable)
{
struct ql3xxx_port_registers __iomem *port_regs =
- qdev->mem_map_registers;
+ qdev->mem_map_registers;
u32 value;
if (enable)
@@ -1143,7 +1079,7 @@ static void ql_mac_cfg_soft_reset(struct ql3_adapter *qdev, u32 enable)
static void ql_mac_cfg_gig(struct ql3_adapter *qdev, u32 enable)
{
struct ql3xxx_port_registers __iomem *port_regs =
- qdev->mem_map_registers;
+ qdev->mem_map_registers;
u32 value;
if (enable)
@@ -1163,7 +1099,7 @@ static void ql_mac_cfg_gig(struct ql3_adapter *qdev, u32 enable)
static void ql_mac_cfg_full_dup(struct ql3_adapter *qdev, u32 enable)
{
struct ql3xxx_port_registers __iomem *port_regs =
- qdev->mem_map_registers;
+ qdev->mem_map_registers;
u32 value;
if (enable)
@@ -1183,7 +1119,7 @@ static void ql_mac_cfg_full_dup(struct ql3_adapter *qdev, u32 enable)
static void ql_mac_cfg_pause(struct ql3_adapter *qdev, u32 enable)
{
struct ql3xxx_port_registers __iomem *port_regs =
- qdev->mem_map_registers;
+ qdev->mem_map_registers;
u32 value;
if (enable)
@@ -1205,7 +1141,7 @@ static void ql_mac_cfg_pause(struct ql3_adapter *qdev, u32 enable)
static int ql_is_fiber(struct ql3_adapter *qdev)
{
struct ql3xxx_port_registers __iomem *port_regs =
- qdev->mem_map_registers;
+ qdev->mem_map_registers;
u32 bitToCheck = 0;
u32 temp;
@@ -1235,7 +1171,7 @@ static int ql_is_auto_cfg(struct ql3_adapter *qdev)
static int ql_is_auto_neg_complete(struct ql3_adapter *qdev)
{
struct ql3xxx_port_registers __iomem *port_regs =
- qdev->mem_map_registers;
+ qdev->mem_map_registers;
u32 bitToCheck = 0;
u32 temp;
@@ -1250,18 +1186,11 @@ static int ql_is_auto_neg_complete(struct ql3_adapter *qdev)
temp = ql_read_page0_reg(qdev, &port_regs->portStatus);
if (temp & bitToCheck) {
- if (netif_msg_link(qdev))
- printk(KERN_INFO PFX
- "%s: Auto-Negotiate complete.\n",
- qdev->ndev->name);
+ netif_info(qdev, link, qdev->ndev, "Auto-Negotiate complete\n");
return 1;
- } else {
- if (netif_msg_link(qdev))
- printk(KERN_WARNING PFX
- "%s: Auto-Negotiate incomplete.\n",
- qdev->ndev->name);
- return 0;
}
+ netif_info(qdev, link, qdev->ndev, "Auto-Negotiate incomplete\n");
+ return 0;
}
/*
@@ -1278,7 +1207,7 @@ static int ql_is_neg_pause(struct ql3_adapter *qdev)
static int ql_auto_neg_error(struct ql3_adapter *qdev)
{
struct ql3xxx_port_registers __iomem *port_regs =
- qdev->mem_map_registers;
+ qdev->mem_map_registers;
u32 bitToCheck = 0;
u32 temp;
@@ -1316,7 +1245,7 @@ static int ql_is_link_full_dup(struct ql3_adapter *qdev)
static int ql_link_down_detect(struct ql3_adapter *qdev)
{
struct ql3xxx_port_registers __iomem *port_regs =
- qdev->mem_map_registers;
+ qdev->mem_map_registers;
u32 bitToCheck = 0;
u32 temp;
@@ -1340,7 +1269,7 @@ static int ql_link_down_detect(struct ql3_adapter *qdev)
static int ql_link_down_detect_clear(struct ql3_adapter *qdev)
{
struct ql3xxx_port_registers __iomem *port_regs =
- qdev->mem_map_registers;
+ qdev->mem_map_registers;
switch (qdev->mac_index) {
case 0:
@@ -1370,7 +1299,7 @@ static int ql_link_down_detect_clear(struct ql3_adapter *qdev)
static int ql_this_adapter_controls_port(struct ql3_adapter *qdev)
{
struct ql3xxx_port_registers __iomem *port_regs =
- qdev->mem_map_registers;
+ qdev->mem_map_registers;
u32 bitToCheck = 0;
u32 temp;
@@ -1387,16 +1316,13 @@ static int ql_this_adapter_controls_port(struct ql3_adapter *qdev)
temp = ql_read_page0_reg(qdev, &port_regs->portStatus);
if (temp & bitToCheck) {
- if (netif_msg_link(qdev))
- printk(KERN_DEBUG PFX
- "%s: is not link master.\n", qdev->ndev->name);
+ netif_printk(qdev, link, KERN_DEBUG, qdev->ndev,
+ "not link master\n");
return 0;
- } else {
- if (netif_msg_link(qdev))
- printk(KERN_DEBUG PFX
- "%s: is link master.\n", qdev->ndev->name);
- return 1;
}
+
+ netif_printk(qdev, link, KERN_DEBUG, qdev->ndev, "link master\n");
+ return 1;
}
static void ql_phy_reset_ex(struct ql3_adapter *qdev)
@@ -1410,19 +1336,20 @@ static void ql_phy_start_neg_ex(struct ql3_adapter *qdev)
u16 reg;
u16 portConfiguration;
- if(qdev->phyType == PHY_AGERE_ET1011C) {
- /* turn off external loopback */
+ if (qdev->phyType == PHY_AGERE_ET1011C)
ql_mii_write_reg(qdev, 0x13, 0x0000);
- }
+ /* turn off external loopback */
- if(qdev->mac_index == 0)
- portConfiguration = qdev->nvram_data.macCfg_port0.portConfiguration;
+ if (qdev->mac_index == 0)
+ portConfiguration =
+ qdev->nvram_data.macCfg_port0.portConfiguration;
else
- portConfiguration = qdev->nvram_data.macCfg_port1.portConfiguration;
+ portConfiguration =
+ qdev->nvram_data.macCfg_port1.portConfiguration;
/* Some HBA's in the field are set to 0 and they need to
be reinterpreted with a default value */
- if(portConfiguration == 0)
+ if (portConfiguration == 0)
portConfiguration = PORT_CONFIG_DEFAULT;
/* Set the 1000 advertisements */
@@ -1430,8 +1357,8 @@ static void ql_phy_start_neg_ex(struct ql3_adapter *qdev)
PHYAddr[qdev->mac_index]);
reg &= ~PHY_GIG_ALL_PARAMS;
- if(portConfiguration & PORT_CONFIG_1000MB_SPEED) {
- if(portConfiguration & PORT_CONFIG_FULL_DUPLEX_ENABLED)
+ if (portConfiguration & PORT_CONFIG_1000MB_SPEED) {
+ if (portConfiguration & PORT_CONFIG_FULL_DUPLEX_ENABLED)
reg |= PHY_GIG_ADV_1000F;
else
reg |= PHY_GIG_ADV_1000H;
@@ -1445,29 +1372,27 @@ static void ql_phy_start_neg_ex(struct ql3_adapter *qdev)
PHYAddr[qdev->mac_index]);
reg &= ~PHY_NEG_ALL_PARAMS;
- if(portConfiguration & PORT_CONFIG_SYM_PAUSE_ENABLED)
+ if (portConfiguration & PORT_CONFIG_SYM_PAUSE_ENABLED)
reg |= PHY_NEG_ASY_PAUSE | PHY_NEG_SYM_PAUSE;
- if(portConfiguration & PORT_CONFIG_FULL_DUPLEX_ENABLED) {
- if(portConfiguration & PORT_CONFIG_100MB_SPEED)
+ if (portConfiguration & PORT_CONFIG_FULL_DUPLEX_ENABLED) {
+ if (portConfiguration & PORT_CONFIG_100MB_SPEED)
reg |= PHY_NEG_ADV_100F;
- if(portConfiguration & PORT_CONFIG_10MB_SPEED)
+ if (portConfiguration & PORT_CONFIG_10MB_SPEED)
reg |= PHY_NEG_ADV_10F;
}
- if(portConfiguration & PORT_CONFIG_HALF_DUPLEX_ENABLED) {
- if(portConfiguration & PORT_CONFIG_100MB_SPEED)
+ if (portConfiguration & PORT_CONFIG_HALF_DUPLEX_ENABLED) {
+ if (portConfiguration & PORT_CONFIG_100MB_SPEED)
reg |= PHY_NEG_ADV_100H;
- if(portConfiguration & PORT_CONFIG_10MB_SPEED)
+ if (portConfiguration & PORT_CONFIG_10MB_SPEED)
reg |= PHY_NEG_ADV_10H;
}
- if(portConfiguration &
- PORT_CONFIG_1000MB_SPEED) {
+ if (portConfiguration & PORT_CONFIG_1000MB_SPEED)
reg |= 1;
- }
ql_mii_write_reg_ex(qdev, PHY_NEG_ADVER, reg,
PHYAddr[qdev->mac_index]);
@@ -1492,7 +1417,7 @@ static void ql_phy_init_ex(struct ql3_adapter *qdev)
static u32 ql_get_link_state(struct ql3_adapter *qdev)
{
struct ql3xxx_port_registers __iomem *port_regs =
- qdev->mem_map_registers;
+ qdev->mem_map_registers;
u32 bitToCheck = 0;
u32 temp, linkState;
@@ -1504,22 +1429,22 @@ static u32 ql_get_link_state(struct ql3_adapter *qdev)
bitToCheck = PORT_STATUS_UP1;
break;
}
+
temp = ql_read_page0_reg(qdev, &port_regs->portStatus);
- if (temp & bitToCheck) {
+ if (temp & bitToCheck)
linkState = LS_UP;
- } else {
+ else
linkState = LS_DOWN;
- }
+
return linkState;
}
static int ql_port_start(struct ql3_adapter *qdev)
{
- if(ql_sem_spinlock(qdev, QL_PHY_GIO_SEM_MASK,
+ if (ql_sem_spinlock(qdev, QL_PHY_GIO_SEM_MASK,
(QL_RESOURCE_BITS_BASE_CODE | (qdev->mac_index) *
2) << 7)) {
- printk(KERN_ERR "%s: Could not get hw lock for GIO\n",
- qdev->ndev->name);
+ netdev_err(qdev->ndev, "Could not get hw lock for GIO\n");
return -1;
}
@@ -1537,19 +1462,16 @@ static int ql_port_start(struct ql3_adapter *qdev)
static int ql_finish_auto_neg(struct ql3_adapter *qdev)
{
- if(ql_sem_spinlock(qdev, QL_PHY_GIO_SEM_MASK,
+ if (ql_sem_spinlock(qdev, QL_PHY_GIO_SEM_MASK,
(QL_RESOURCE_BITS_BASE_CODE | (qdev->mac_index) *
2) << 7))
return -1;
if (!ql_auto_neg_error(qdev)) {
- if (test_bit(QL_LINK_MASTER,&qdev->flags)) {
+ if (test_bit(QL_LINK_MASTER, &qdev->flags)) {
/* configure the MAC */
- if (netif_msg_link(qdev))
- printk(KERN_DEBUG PFX
- "%s: Configuring link.\n",
- qdev->ndev->
- name);
+ netif_printk(qdev, link, KERN_DEBUG, qdev->ndev,
+ "Configuring link\n");
ql_mac_cfg_soft_reset(qdev, 1);
ql_mac_cfg_gig(qdev,
(ql_get_link_speed
@@ -1564,43 +1486,32 @@ static int ql_finish_auto_neg(struct ql3_adapter *qdev)
ql_mac_cfg_soft_reset(qdev, 0);
/* enable the MAC */
- if (netif_msg_link(qdev))
- printk(KERN_DEBUG PFX
- "%s: Enabling mac.\n",
- qdev->ndev->
- name);
+ netif_printk(qdev, link, KERN_DEBUG, qdev->ndev,
+ "Enabling mac\n");
ql_mac_enable(qdev, 1);
}
qdev->port_link_state = LS_UP;
netif_start_queue(qdev->ndev);
netif_carrier_on(qdev->ndev);
- if (netif_msg_link(qdev))
- printk(KERN_INFO PFX
- "%s: Link is up at %d Mbps, %s duplex.\n",
- qdev->ndev->name,
- ql_get_link_speed(qdev),
- ql_is_link_full_dup(qdev)
- ? "full" : "half");
+ netif_info(qdev, link, qdev->ndev,
+ "Link is up at %d Mbps, %s duplex\n",
+ ql_get_link_speed(qdev),
+ ql_is_link_full_dup(qdev) ? "full" : "half");
} else { /* Remote error detected */
- if (test_bit(QL_LINK_MASTER,&qdev->flags)) {
- if (netif_msg_link(qdev))
- printk(KERN_DEBUG PFX
- "%s: Remote error detected. "
- "Calling ql_port_start().\n",
- qdev->ndev->
- name);
+ if (test_bit(QL_LINK_MASTER, &qdev->flags)) {
+ netif_printk(qdev, link, KERN_DEBUG, qdev->ndev,
+ "Remote error detected. Calling ql_port_start()\n");
/*
* ql_port_start() is shared code and needs
* to lock the PHY on it's own.
*/
ql_sem_unlock(qdev, QL_PHY_GIO_SEM_MASK);
- if(ql_port_start(qdev)) {/* Restart port */
+ if (ql_port_start(qdev)) /* Restart port */
return -1;
- } else
- return 0;
+ return 0;
}
}
ql_sem_unlock(qdev, QL_PHY_GIO_SEM_MASK);
@@ -1619,33 +1530,28 @@ static void ql_link_state_machine_work(struct work_struct *work)
curr_link_state = ql_get_link_state(qdev);
- if (test_bit(QL_RESET_ACTIVE,&qdev->flags)) {
- if (netif_msg_link(qdev))
- printk(KERN_INFO PFX
- "%s: Reset in progress, skip processing link "
- "state.\n", qdev->ndev->name);
+ if (test_bit(QL_RESET_ACTIVE, &qdev->flags)) {
+ netif_info(qdev, link, qdev->ndev,
+ "Reset in progress, skip processing link state\n");
spin_unlock_irqrestore(&qdev->hw_lock, hw_flags);
/* Restart timer on 2 second interval. */
- mod_timer(&qdev->adapter_timer, jiffies + HZ * 1);\
+ mod_timer(&qdev->adapter_timer, jiffies + HZ * 1);
return;
}
switch (qdev->port_link_state) {
default:
- if (test_bit(QL_LINK_MASTER,&qdev->flags)) {
+ if (test_bit(QL_LINK_MASTER, &qdev->flags))
ql_port_start(qdev);
- }
qdev->port_link_state = LS_DOWN;
/* Fall Through */
case LS_DOWN:
if (curr_link_state == LS_UP) {
- if (netif_msg_link(qdev))
- printk(KERN_INFO PFX "%s: Link is up.\n",
- qdev->ndev->name);
+ netif_info(qdev, link, qdev->ndev, "Link is up\n");
if (ql_is_auto_neg_complete(qdev))
ql_finish_auto_neg(qdev);
@@ -1662,9 +1568,7 @@ static void ql_link_state_machine_work(struct work_struct *work)
* back up
*/
if (curr_link_state == LS_DOWN) {
- if (netif_msg_link(qdev))
- printk(KERN_INFO PFX "%s: Link is down.\n",
- qdev->ndev->name);
+ netif_info(qdev, link, qdev->ndev, "Link is down\n");
qdev->port_link_state = LS_DOWN;
}
if (ql_link_down_detect(qdev))
@@ -1683,9 +1587,9 @@ static void ql_link_state_machine_work(struct work_struct *work)
static void ql_get_phy_owner(struct ql3_adapter *qdev)
{
if (ql_this_adapter_controls_port(qdev))
- set_bit(QL_LINK_MASTER,&qdev->flags);
+ set_bit(QL_LINK_MASTER, &qdev->flags);
else
- clear_bit(QL_LINK_MASTER,&qdev->flags);
+ clear_bit(QL_LINK_MASTER, &qdev->flags);
}
/*
@@ -1695,7 +1599,7 @@ static void ql_init_scan_mode(struct ql3_adapter *qdev)
{
ql_mii_enable_scan_mode(qdev);
- if (test_bit(QL_LINK_OPTICAL,&qdev->flags)) {
+ if (test_bit(QL_LINK_OPTICAL, &qdev->flags)) {
if (ql_this_adapter_controls_port(qdev))
ql_petbi_init_ex(qdev);
} else {
@@ -1705,18 +1609,18 @@ static void ql_init_scan_mode(struct ql3_adapter *qdev)
}
/*
- * MII_Setup needs to be called before taking the PHY out of reset so that the
- * management interface clock speed can be set properly. It would be better if
- * we had a way to disable MDC until after the PHY is out of reset, but we
- * don't have that capability.
+ * MII_Setup needs to be called before taking the PHY out of reset
+ * so that the management interface clock speed can be set properly.
+ * It would be better if we had a way to disable MDC until after the
+ * PHY is out of reset, but we don't have that capability.
*/
static int ql_mii_setup(struct ql3_adapter *qdev)
{
u32 reg;
struct ql3xxx_port_registers __iomem *port_regs =
- qdev->mem_map_registers;
+ qdev->mem_map_registers;
- if(ql_sem_spinlock(qdev, QL_PHY_GIO_SEM_MASK,
+ if (ql_sem_spinlock(qdev, QL_PHY_GIO_SEM_MASK,
(QL_RESOURCE_BITS_BASE_CODE | (qdev->mac_index) *
2) << 7))
return -1;
@@ -1735,24 +1639,24 @@ static int ql_mii_setup(struct ql3_adapter *qdev)
return 0;
}
+#define SUPPORTED_OPTICAL_MODES (SUPPORTED_1000baseT_Full | \
+ SUPPORTED_FIBRE | \
+ SUPPORTED_Autoneg)
+#define SUPPORTED_TP_MODES (SUPPORTED_10baseT_Half | \
+ SUPPORTED_10baseT_Full | \
+ SUPPORTED_100baseT_Half | \
+ SUPPORTED_100baseT_Full | \
+ SUPPORTED_1000baseT_Half | \
+ SUPPORTED_1000baseT_Full | \
+ SUPPORTED_Autoneg | \
+ SUPPORTED_TP); \
+
static u32 ql_supported_modes(struct ql3_adapter *qdev)
{
- u32 supported;
+ if (test_bit(QL_LINK_OPTICAL, &qdev->flags))
+ return SUPPORTED_OPTICAL_MODES;
- if (test_bit(QL_LINK_OPTICAL,&qdev->flags)) {
- supported = SUPPORTED_1000baseT_Full | SUPPORTED_FIBRE
- | SUPPORTED_Autoneg;
- } else {
- supported = SUPPORTED_10baseT_Half
- | SUPPORTED_10baseT_Full
- | SUPPORTED_100baseT_Half
- | SUPPORTED_100baseT_Full
- | SUPPORTED_1000baseT_Half
- | SUPPORTED_1000baseT_Full
- | SUPPORTED_Autoneg | SUPPORTED_TP;
- }
-
- return supported;
+ return SUPPORTED_TP_MODES;
}
static int ql_get_auto_cfg_status(struct ql3_adapter *qdev)
@@ -1760,9 +1664,9 @@ static int ql_get_auto_cfg_status(struct ql3_adapter *qdev)
int status;
unsigned long hw_flags;
spin_lock_irqsave(&qdev->hw_lock, hw_flags);
- if(ql_sem_spinlock(qdev, QL_PHY_GIO_SEM_MASK,
- (QL_RESOURCE_BITS_BASE_CODE | (qdev->mac_index) *
- 2) << 7)) {
+ if (ql_sem_spinlock(qdev, QL_PHY_GIO_SEM_MASK,
+ (QL_RESOURCE_BITS_BASE_CODE |
+ (qdev->mac_index) * 2) << 7)) {
spin_unlock_irqrestore(&qdev->hw_lock, hw_flags);
return 0;
}
@@ -1777,9 +1681,9 @@ static u32 ql_get_speed(struct ql3_adapter *qdev)
u32 status;
unsigned long hw_flags;
spin_lock_irqsave(&qdev->hw_lock, hw_flags);
- if(ql_sem_spinlock(qdev, QL_PHY_GIO_SEM_MASK,
- (QL_RESOURCE_BITS_BASE_CODE | (qdev->mac_index) *
- 2) << 7)) {
+ if (ql_sem_spinlock(qdev, QL_PHY_GIO_SEM_MASK,
+ (QL_RESOURCE_BITS_BASE_CODE |
+ (qdev->mac_index) * 2) << 7)) {
spin_unlock_irqrestore(&qdev->hw_lock, hw_flags);
return 0;
}
@@ -1794,9 +1698,9 @@ static int ql_get_full_dup(struct ql3_adapter *qdev)
int status;
unsigned long hw_flags;
spin_lock_irqsave(&qdev->hw_lock, hw_flags);
- if(ql_sem_spinlock(qdev, QL_PHY_GIO_SEM_MASK,
- (QL_RESOURCE_BITS_BASE_CODE | (qdev->mac_index) *
- 2) << 7)) {
+ if (ql_sem_spinlock(qdev, QL_PHY_GIO_SEM_MASK,
+ (QL_RESOURCE_BITS_BASE_CODE |
+ (qdev->mac_index) * 2) << 7)) {
spin_unlock_irqrestore(&qdev->hw_lock, hw_flags);
return 0;
}
@@ -1806,7 +1710,6 @@ static int ql_get_full_dup(struct ql3_adapter *qdev)
return status;
}
-
static int ql_get_settings(struct net_device *ndev, struct ethtool_cmd *ecmd)
{
struct ql3_adapter *qdev = netdev_priv(ndev);
@@ -1814,7 +1717,7 @@ static int ql_get_settings(struct net_device *ndev, struct ethtool_cmd *ecmd)
ecmd->transceiver = XCVR_INTERNAL;
ecmd->supported = ql_supported_modes(qdev);
- if (test_bit(QL_LINK_OPTICAL,&qdev->flags)) {
+ if (test_bit(QL_LINK_OPTICAL, &qdev->flags)) {
ecmd->port = PORT_FIBRE;
} else {
ecmd->port = PORT_TP;
@@ -1855,10 +1758,11 @@ static void ql_get_pauseparam(struct net_device *ndev,
struct ethtool_pauseparam *pause)
{
struct ql3_adapter *qdev = netdev_priv(ndev);
- struct ql3xxx_port_registers __iomem *port_regs = qdev->mem_map_registers;
+ struct ql3xxx_port_registers __iomem *port_regs =
+ qdev->mem_map_registers;
u32 reg;
- if(qdev->mac_index == 0)
+ if (qdev->mac_index == 0)
reg = ql_read_page0_reg(qdev, &port_regs->mac0ConfigReg);
else
reg = ql_read_page0_reg(qdev, &port_regs->mac1ConfigReg);
@@ -1885,12 +1789,12 @@ static int ql_populate_free_queue(struct ql3_adapter *qdev)
while (lrg_buf_cb) {
if (!lrg_buf_cb->skb) {
- lrg_buf_cb->skb = netdev_alloc_skb(qdev->ndev,
- qdev->lrg_buffer_len);
+ lrg_buf_cb->skb =
+ netdev_alloc_skb(qdev->ndev,
+ qdev->lrg_buffer_len);
if (unlikely(!lrg_buf_cb->skb)) {
- printk(KERN_DEBUG PFX
- "%s: Failed netdev_alloc_skb().\n",
- qdev->ndev->name);
+ netdev_printk(KERN_DEBUG, qdev->ndev,
+ "Failed netdev_alloc_skb()\n");
break;
} else {
/*
@@ -1905,9 +1809,10 @@ static int ql_populate_free_queue(struct ql3_adapter *qdev)
PCI_DMA_FROMDEVICE);
err = pci_dma_mapping_error(qdev->pdev, map);
- if(err) {
- printk(KERN_ERR "%s: PCI mapping failed with error: %d\n",
- qdev->ndev->name, err);
+ if (err) {
+ netdev_err(qdev->ndev,
+ "PCI mapping failed with error: %d\n",
+ err);
dev_kfree_skb(lrg_buf_cb->skb);
lrg_buf_cb->skb = NULL;
break;
@@ -1915,9 +1820,9 @@ static int ql_populate_free_queue(struct ql3_adapter *qdev)
lrg_buf_cb->buf_phy_addr_low =
- cpu_to_le32(LS_64BITS(map));
+ cpu_to_le32(LS_64BITS(map));
lrg_buf_cb->buf_phy_addr_high =
- cpu_to_le32(MS_64BITS(map));
+ cpu_to_le32(MS_64BITS(map));
dma_unmap_addr_set(lrg_buf_cb, mapaddr, map);
dma_unmap_len_set(lrg_buf_cb, maplen,
qdev->lrg_buffer_len -
@@ -1937,7 +1842,9 @@ static int ql_populate_free_queue(struct ql3_adapter *qdev)
*/
static void ql_update_small_bufq_prod_index(struct ql3_adapter *qdev)
{
- struct ql3xxx_port_registers __iomem *port_regs = qdev->mem_map_registers;
+ struct ql3xxx_port_registers __iomem *port_regs =
+ qdev->mem_map_registers;
+
if (qdev->small_buf_release_cnt >= 16) {
while (qdev->small_buf_release_cnt >= 16) {
qdev->small_buf_q_producer_index++;
@@ -1961,7 +1868,8 @@ static void ql_update_lrg_bufq_prod_index(struct ql3_adapter *qdev)
struct bufq_addr_element *lrg_buf_q_ele;
int i;
struct ql_rcv_buf_cb *lrg_buf_cb;
- struct ql3xxx_port_registers __iomem *port_regs = qdev->mem_map_registers;
+ struct ql3xxx_port_registers __iomem *port_regs =
+ qdev->mem_map_registers;
if ((qdev->lrg_buf_free_count >= 8) &&
(qdev->lrg_buf_release_cnt >= 16)) {
@@ -1989,7 +1897,8 @@ static void ql_update_lrg_bufq_prod_index(struct ql3_adapter *qdev)
qdev->lrg_buf_q_producer_index++;
- if (qdev->lrg_buf_q_producer_index == qdev->num_lbufq_entries)
+ if (qdev->lrg_buf_q_producer_index ==
+ qdev->num_lbufq_entries)
qdev->lrg_buf_q_producer_index = 0;
if (qdev->lrg_buf_q_producer_index ==
@@ -2011,23 +1920,26 @@ static void ql_process_mac_tx_intr(struct ql3_adapter *qdev,
int i;
int retval = 0;
- if(mac_rsp->flags & OB_MAC_IOCB_RSP_S) {
- printk(KERN_WARNING "Frame short but, frame was padded and sent.\n");
+ if (mac_rsp->flags & OB_MAC_IOCB_RSP_S) {
+ netdev_warn(qdev->ndev,
+ "Frame too short but it was padded and sent\n");
}
tx_cb = &qdev->tx_buf[mac_rsp->transaction_id];
/* Check the transmit response flags for any errors */
- if(mac_rsp->flags & OB_MAC_IOCB_RSP_S) {
- printk(KERN_ERR "Frame too short to be legal, frame not sent.\n");
+ if (mac_rsp->flags & OB_MAC_IOCB_RSP_S) {
+ netdev_err(qdev->ndev,
+ "Frame too short to be legal, frame not sent\n");
qdev->ndev->stats.tx_errors++;
retval = -EIO;
goto frame_not_sent;
}
- if(tx_cb->seg_count == 0) {
- printk(KERN_ERR "tx_cb->seg_count == 0: %d\n", mac_rsp->transaction_id);
+ if (tx_cb->seg_count == 0) {
+ netdev_err(qdev->ndev, "tx_cb->seg_count == 0: %d\n",
+ mac_rsp->transaction_id);
qdev->ndev->stats.tx_errors++;
retval = -EIO;
@@ -2073,7 +1985,7 @@ static struct ql_rcv_buf_cb *ql_get_lbuf(struct ql3_adapter *qdev)
qdev->lrg_buf_release_cnt++;
if (++qdev->lrg_buf_index == qdev->num_large_buffers)
qdev->lrg_buf_index = 0;
- return(lrg_buf_cb);
+ return lrg_buf_cb;
}
/*
@@ -2177,12 +2089,11 @@ static void ql_process_macip_rx_intr(struct ql3_adapter *qdev,
if (checksum &
(IB_IP_IOCB_RSP_3032_ICE |
IB_IP_IOCB_RSP_3032_CE)) {
- printk(KERN_ERR
- "%s: Bad checksum for this %s packet, checksum = %x.\n",
- __func__,
- ((checksum &
- IB_IP_IOCB_RSP_3032_TCP) ? "TCP" :
- "UDP"),checksum);
+ netdev_err(ndev,
+ "%s: Bad checksum for this %s packet, checksum = %x\n",
+ __func__,
+ ((checksum & IB_IP_IOCB_RSP_3032_TCP) ?
+ "TCP" : "UDP"), checksum);
} else if ((checksum & IB_IP_IOCB_RSP_3032_TCP) ||
(checksum & IB_IP_IOCB_RSP_3032_UDP &&
!(checksum & IB_IP_IOCB_RSP_3032_NUC))) {
@@ -2215,8 +2126,8 @@ static int ql_tx_rx_clean(struct ql3_adapter *qdev,
net_rsp = qdev->rsp_current;
rmb();
/*
- * Fix 4032 chipe undocumented "feature" where bit-8 is set if the
- * inbound completion is for a VLAN.
+ * Fix 4032 chip's undocumented "feature" where bit-8 is set
+ * if the inbound completion is for a VLAN.
*/
if (qdev->device_id == QL3032_DEVICE_ID)
net_rsp->opcode &= 0x7f;
@@ -2242,22 +2153,18 @@ static int ql_tx_rx_clean(struct ql3_adapter *qdev,
net_rsp);
(*rx_cleaned)++;
break;
- default:
- {
- u32 *tmp = (u32 *) net_rsp;
- printk(KERN_ERR PFX
- "%s: Hit default case, not "
- "handled!\n"
- " dropping the packet, opcode = "
- "%x.\n",
- ndev->name, net_rsp->opcode);
- printk(KERN_ERR PFX
- "0x%08lx 0x%08lx 0x%08lx 0x%08lx\n",
- (unsigned long int)tmp[0],
- (unsigned long int)tmp[1],
- (unsigned long int)tmp[2],
- (unsigned long int)tmp[3]);
- }
+ default: {
+ u32 *tmp = (u32 *)net_rsp;
+ netdev_err(ndev,
+ "Hit default case, not handled!\n"
+ " dropping the packet, opcode = %x\n"
+ "0x%08lx 0x%08lx 0x%08lx 0x%08lx\n",
+ net_rsp->opcode,
+ (unsigned long int)tmp[0],
+ (unsigned long int)tmp[1],
+ (unsigned long int)tmp[2],
+ (unsigned long int)tmp[3]);
+ }
}
qdev->rsp_consumer_index++;
@@ -2280,7 +2187,8 @@ static int ql_poll(struct napi_struct *napi, int budget)
struct ql3_adapter *qdev = container_of(napi, struct ql3_adapter, napi);
int rx_cleaned = 0, tx_cleaned = 0;
unsigned long hw_flags;
- struct ql3xxx_port_registers __iomem *port_regs = qdev->mem_map_registers;
+ struct ql3xxx_port_registers __iomem *port_regs =
+ qdev->mem_map_registers;
ql_tx_rx_clean(qdev, &tx_cleaned, &rx_cleaned, budget);
@@ -2303,15 +2211,14 @@ static irqreturn_t ql3xxx_isr(int irq, void *dev_id)
struct net_device *ndev = dev_id;
struct ql3_adapter *qdev = netdev_priv(ndev);
- struct ql3xxx_port_registers __iomem *port_regs = qdev->mem_map_registers;
+ struct ql3xxx_port_registers __iomem *port_regs =
+ qdev->mem_map_registers;
u32 value;
int handled = 1;
u32 var;
- port_regs = qdev->mem_map_registers;
-
- value =
- ql_read_common_reg_l(qdev, &port_regs->CommonRegs.ispControlStatus);
+ value = ql_read_common_reg_l(qdev,
+ &port_regs->CommonRegs.ispControlStatus);
if (value & (ISP_CONTROL_FE | ISP_CONTROL_RI)) {
spin_lock(&qdev->adapter_lock);
@@ -2319,7 +2226,7 @@ static irqreturn_t ql3xxx_isr(int irq, void *dev_id)
netif_carrier_off(qdev->ndev);
ql_disable_interrupts(qdev);
qdev->port_link_state = LS_DOWN;
- set_bit(QL_RESET_ACTIVE,&qdev->flags) ;
+ set_bit(QL_RESET_ACTIVE, &qdev->flags) ;
if (value & ISP_CONTROL_FE) {
/*
@@ -2328,69 +2235,53 @@ static irqreturn_t ql3xxx_isr(int irq, void *dev_id)
var =
ql_read_page0_reg_l(qdev,
&port_regs->PortFatalErrStatus);
- printk(KERN_WARNING PFX
- "%s: Resetting chip. PortFatalErrStatus "
- "register = 0x%x\n", ndev->name, var);
- set_bit(QL_RESET_START,&qdev->flags) ;
+ netdev_warn(ndev,
+ "Resetting chip. PortFatalErrStatus register = 0x%x\n",
+ var);
+ set_bit(QL_RESET_START, &qdev->flags) ;
} else {
/*
* Soft Reset Requested.
*/
- set_bit(QL_RESET_PER_SCSI,&qdev->flags) ;
- printk(KERN_ERR PFX
- "%s: Another function issued a reset to the "
- "chip. ISR value = %x.\n", ndev->name, value);
+ set_bit(QL_RESET_PER_SCSI, &qdev->flags) ;
+ netdev_err(ndev,
+ "Another function issued a reset to the chip. ISR value = %x\n",
+ value);
}
queue_delayed_work(qdev->workqueue, &qdev->reset_work, 0);
spin_unlock(&qdev->adapter_lock);
} else if (value & ISP_IMR_DISABLE_CMPL_INT) {
ql_disable_interrupts(qdev);
- if (likely(napi_schedule_prep(&qdev->napi))) {
+ if (likely(napi_schedule_prep(&qdev->napi)))
__napi_schedule(&qdev->napi);
- }
- } else {
+ } else
return IRQ_NONE;
- }
return IRQ_RETVAL(handled);
}
/*
- * Get the total number of segments needed for the
- * given number of fragments. This is necessary because
- * outbound address lists (OAL) will be used when more than
- * two frags are given. Each address list has 5 addr/len
- * pairs. The 5th pair in each AOL is used to point to
- * the next AOL if more frags are coming.
- * That is why the frags:segment count ratio is not linear.
+ * Get the total number of segments needed for the given number of fragments.
+ * This is necessary because outbound address lists (OAL) will be used when
+ * more than two frags are given. Each address list has 5 addr/len pairs.
+ * The 5th pair in each OAL is used to point to the next OAL if more frags
+ * are coming. That is why the frags:segment count ratio is not linear.
*/
-static int ql_get_seg_count(struct ql3_adapter *qdev,
- unsigned short frags)
+static int ql_get_seg_count(struct ql3_adapter *qdev, unsigned short frags)
{
if (qdev->device_id == QL3022_DEVICE_ID)
return 1;
- switch(frags) {
- case 0: return 1; /* just the skb->data seg */
- case 1: return 2; /* skb->data + 1 frag */
- case 2: return 3; /* skb->data + 2 frags */
- case 3: return 5; /* skb->data + 1 frag + 1 AOL containting 2 frags */
- case 4: return 6;
- case 5: return 7;
- case 6: return 8;
- case 7: return 10;
- case 8: return 11;
- case 9: return 12;
- case 10: return 13;
- case 11: return 15;
- case 12: return 16;
- case 13: return 17;
- case 14: return 18;
- case 15: return 20;
- case 16: return 21;
- case 17: return 22;
- case 18: return 23;
- }
+ if (frags <= 2)
+ return frags + 1;
+ else if (frags <= 6)
+ return frags + 2;
+ else if (frags <= 10)
+ return frags + 3;
+ else if (frags <= 14)
+ return frags + 4;
+ else if (frags <= 18)
+ return frags + 5;
return -1;
}
@@ -2413,8 +2304,8 @@ static void ql_hw_csum_setup(const struct sk_buff *skb,
}
/*
- * Map the buffers for this transmit. This will return
- * NETDEV_TX_BUSY or NETDEV_TX_OK based on success.
+ * Map the buffers for this transmit.
+ * This will return NETDEV_TX_BUSY or NETDEV_TX_OK based on success.
*/
static int ql_send_map(struct ql3_adapter *qdev,
struct ob_mac_iocb_req *mac_iocb_ptr,
@@ -2437,9 +2328,9 @@ static int ql_send_map(struct ql3_adapter *qdev,
map = pci_map_single(qdev->pdev, skb->data, len, PCI_DMA_TODEVICE);
err = pci_dma_mapping_error(qdev->pdev, map);
- if(err) {
- printk(KERN_ERR "%s: PCI mapping failed with error: %d\n",
- qdev->ndev->name, err);
+ if (err) {
+ netdev_err(qdev->ndev, "PCI mapping failed with error: %d\n",
+ err);
return NETDEV_TX_BUSY;
}
@@ -2455,65 +2346,67 @@ static int ql_send_map(struct ql3_adapter *qdev,
if (seg_cnt == 1) {
/* Terminate the last segment. */
oal_entry->len |= cpu_to_le32(OAL_LAST_ENTRY);
- } else {
- oal = tx_cb->oal;
- for (completed_segs=0; completed_segs<frag_cnt; completed_segs++,seg++) {
- skb_frag_t *frag = &skb_shinfo(skb)->frags[completed_segs];
- oal_entry++;
- if ((seg == 2 && seg_cnt > 3) || /* Check for continuation */
- (seg == 7 && seg_cnt > 8) || /* requirements. It's strange */
- (seg == 12 && seg_cnt > 13) || /* but necessary. */
- (seg == 17 && seg_cnt > 18)) {
- /* Continuation entry points to outbound address list. */
- map = pci_map_single(qdev->pdev, oal,
- sizeof(struct oal),
- PCI_DMA_TODEVICE);
-
- err = pci_dma_mapping_error(qdev->pdev, map);
- if(err) {
-
- printk(KERN_ERR "%s: PCI mapping outbound address list with error: %d\n",
- qdev->ndev->name, err);
- goto map_error;
- }
-
- oal_entry->dma_lo = cpu_to_le32(LS_64BITS(map));
- oal_entry->dma_hi = cpu_to_le32(MS_64BITS(map));
- oal_entry->len =
- cpu_to_le32(sizeof(struct oal) |
- OAL_CONT_ENTRY);
- dma_unmap_addr_set(&tx_cb->map[seg], mapaddr,
- map);
- dma_unmap_len_set(&tx_cb->map[seg], maplen,
- sizeof(struct oal));
- oal_entry = (struct oal_entry *)oal;
- oal++;
- seg++;
- }
-
- map =
- pci_map_page(qdev->pdev, frag->page,
- frag->page_offset, frag->size,
- PCI_DMA_TODEVICE);
+ return NETDEV_TX_OK;
+ }
+ oal = tx_cb->oal;
+ for (completed_segs = 0;
+ completed_segs < frag_cnt;
+ completed_segs++, seg++) {
+ skb_frag_t *frag = &skb_shinfo(skb)->frags[completed_segs];
+ oal_entry++;
+ /*
+ * Check for continuation requirements.
+ * It's strange but necessary.
+ * Continuation entry points to outbound address list.
+ */
+ if ((seg == 2 && seg_cnt > 3) ||
+ (seg == 7 && seg_cnt > 8) ||
+ (seg == 12 && seg_cnt > 13) ||
+ (seg == 17 && seg_cnt > 18)) {
+ map = pci_map_single(qdev->pdev, oal,
+ sizeof(struct oal),
+ PCI_DMA_TODEVICE);
err = pci_dma_mapping_error(qdev->pdev, map);
- if(err) {
- printk(KERN_ERR "%s: PCI mapping frags failed with error: %d\n",
- qdev->ndev->name, err);
+ if (err) {
+ netdev_err(qdev->ndev,
+ "PCI mapping outbound address list with error: %d\n",
+ err);
goto map_error;
}
oal_entry->dma_lo = cpu_to_le32(LS_64BITS(map));
oal_entry->dma_hi = cpu_to_le32(MS_64BITS(map));
- oal_entry->len = cpu_to_le32(frag->size);
+ oal_entry->len = cpu_to_le32(sizeof(struct oal) |
+ OAL_CONT_ENTRY);
dma_unmap_addr_set(&tx_cb->map[seg], mapaddr, map);
dma_unmap_len_set(&tx_cb->map[seg], maplen,
- frag->size);
+ sizeof(struct oal));
+ oal_entry = (struct oal_entry *)oal;
+ oal++;
+ seg++;
+ }
+
+ map = pci_map_page(qdev->pdev, frag->page,
+ frag->page_offset, frag->size,
+ PCI_DMA_TODEVICE);
+
+ err = pci_dma_mapping_error(qdev->pdev, map);
+ if (err) {
+ netdev_err(qdev->ndev,
+ "PCI mapping frags failed with error: %d\n",
+ err);
+ goto map_error;
}
- /* Terminate the last segment. */
- oal_entry->len |= cpu_to_le32(OAL_LAST_ENTRY);
- }
+ oal_entry->dma_lo = cpu_to_le32(LS_64BITS(map));
+ oal_entry->dma_hi = cpu_to_le32(MS_64BITS(map));
+ oal_entry->len = cpu_to_le32(frag->size);
+ dma_unmap_addr_set(&tx_cb->map[seg], mapaddr, map);
+ dma_unmap_len_set(&tx_cb->map[seg], maplen, frag->size);
+ }
+ /* Terminate the last segment. */
+ oal_entry->len |= cpu_to_le32(OAL_LAST_ENTRY);
return NETDEV_TX_OK;
map_error:
@@ -2525,13 +2418,18 @@ map_error:
seg = 1;
oal_entry = (struct oal_entry *)&mac_iocb_ptr->buf_addr0_low;
oal = tx_cb->oal;
- for (i=0; i<completed_segs; i++,seg++) {
+ for (i = 0; i < completed_segs; i++, seg++) {
oal_entry++;
- if((seg == 2 && seg_cnt > 3) || /* Check for continuation */
- (seg == 7 && seg_cnt > 8) || /* requirements. It's strange */
- (seg == 12 && seg_cnt > 13) || /* but necessary. */
- (seg == 17 && seg_cnt > 18)) {
+ /*
+ * Check for continuation requirements.
+ * It's strange but necessary.
+ */
+
+ if ((seg == 2 && seg_cnt > 3) ||
+ (seg == 7 && seg_cnt > 8) ||
+ (seg == 12 && seg_cnt > 13) ||
+ (seg == 17 && seg_cnt > 18)) {
pci_unmap_single(qdev->pdev,
dma_unmap_addr(&tx_cb->map[seg], mapaddr),
dma_unmap_len(&tx_cb->map[seg], maplen),
@@ -2570,19 +2468,20 @@ static netdev_tx_t ql3xxx_send(struct sk_buff *skb,
struct net_device *ndev)
{
struct ql3_adapter *qdev = (struct ql3_adapter *)netdev_priv(ndev);
- struct ql3xxx_port_registers __iomem *port_regs = qdev->mem_map_registers;
+ struct ql3xxx_port_registers __iomem *port_regs =
+ qdev->mem_map_registers;
struct ql_tx_buf_cb *tx_cb;
u32 tot_len = skb->len;
struct ob_mac_iocb_req *mac_iocb_ptr;
- if (unlikely(atomic_read(&qdev->tx_count) < 2)) {
+ if (unlikely(atomic_read(&qdev->tx_count) < 2))
return NETDEV_TX_BUSY;
- }
- tx_cb = &qdev->tx_buf[qdev->req_producer_index] ;
- if((tx_cb->seg_count = ql_get_seg_count(qdev,
- (skb_shinfo(skb)->nr_frags))) == -1) {
- printk(KERN_ERR PFX"%s: invalid segment count!\n",__func__);
+ tx_cb = &qdev->tx_buf[qdev->req_producer_index];
+ tx_cb->seg_count = ql_get_seg_count(qdev,
+ skb_shinfo(skb)->nr_frags);
+ if (tx_cb->seg_count == -1) {
+ netdev_err(ndev, "%s: invalid segment count!\n", __func__);
return NETDEV_TX_OK;
}
@@ -2598,8 +2497,8 @@ static netdev_tx_t ql3xxx_send(struct sk_buff *skb,
skb->ip_summed == CHECKSUM_PARTIAL)
ql_hw_csum_setup(skb, mac_iocb_ptr);
- if(ql_send_map(qdev,mac_iocb_ptr,tx_cb,skb) != NETDEV_TX_OK) {
- printk(KERN_ERR PFX"%s: Could not map the segments!\n",__func__);
+ if (ql_send_map(qdev, mac_iocb_ptr, tx_cb, skb) != NETDEV_TX_OK) {
+ netdev_err(ndev, "%s: Could not map the segments!\n", __func__);
return NETDEV_TX_BUSY;
}
@@ -2612,9 +2511,9 @@ static netdev_tx_t ql3xxx_send(struct sk_buff *skb,
&port_regs->CommonRegs.reqQProducerIndex,
qdev->req_producer_index);
- if (netif_msg_tx_queued(qdev))
- printk(KERN_DEBUG PFX "%s: tx queued, slot %d, len %d\n",
- ndev->name, qdev->req_producer_index, skb->len);
+ netif_printk(qdev, tx_queued, KERN_DEBUG, ndev,
+ "tx queued, slot %d, len %d\n",
+ qdev->req_producer_index, skb->len);
atomic_dec(&qdev->tx_count);
return NETDEV_TX_OK;
@@ -2632,8 +2531,7 @@ static int ql_alloc_net_req_rsp_queues(struct ql3_adapter *qdev)
if ((qdev->req_q_virt_addr == NULL) ||
LS_64BITS(qdev->req_q_phy_addr) & (qdev->req_q_size - 1)) {
- printk(KERN_ERR PFX "%s: reqQ failed.\n",
- qdev->ndev->name);
+ netdev_err(qdev->ndev, "reqQ failed\n");
return -ENOMEM;
}
@@ -2646,25 +2544,22 @@ static int ql_alloc_net_req_rsp_queues(struct ql3_adapter *qdev)
if ((qdev->rsp_q_virt_addr == NULL) ||
LS_64BITS(qdev->rsp_q_phy_addr) & (qdev->rsp_q_size - 1)) {
- printk(KERN_ERR PFX
- "%s: rspQ allocation failed\n",
- qdev->ndev->name);
+ netdev_err(qdev->ndev, "rspQ allocation failed\n");
pci_free_consistent(qdev->pdev, (size_t) qdev->req_q_size,
qdev->req_q_virt_addr,
qdev->req_q_phy_addr);
return -ENOMEM;
}
- set_bit(QL_ALLOC_REQ_RSP_Q_DONE,&qdev->flags);
+ set_bit(QL_ALLOC_REQ_RSP_Q_DONE, &qdev->flags);
return 0;
}
static void ql_free_net_req_rsp_queues(struct ql3_adapter *qdev)
{
- if (!test_bit(QL_ALLOC_REQ_RSP_Q_DONE,&qdev->flags)) {
- printk(KERN_INFO PFX
- "%s: Already done.\n", qdev->ndev->name);
+ if (!test_bit(QL_ALLOC_REQ_RSP_Q_DONE, &qdev->flags)) {
+ netdev_info(qdev->ndev, "Already done\n");
return;
}
@@ -2680,34 +2575,34 @@ static void ql_free_net_req_rsp_queues(struct ql3_adapter *qdev)
qdev->rsp_q_virt_addr = NULL;
- clear_bit(QL_ALLOC_REQ_RSP_Q_DONE,&qdev->flags);
+ clear_bit(QL_ALLOC_REQ_RSP_Q_DONE, &qdev->flags);
}
static int ql_alloc_buffer_queues(struct ql3_adapter *qdev)
{
/* Create Large Buffer Queue */
qdev->lrg_buf_q_size =
- qdev->num_lbufq_entries * sizeof(struct lrg_buf_q_entry);
+ qdev->num_lbufq_entries * sizeof(struct lrg_buf_q_entry);
if (qdev->lrg_buf_q_size < PAGE_SIZE)
qdev->lrg_buf_q_alloc_size = PAGE_SIZE;
else
qdev->lrg_buf_q_alloc_size = qdev->lrg_buf_q_size * 2;
- qdev->lrg_buf = kmalloc(qdev->num_large_buffers * sizeof(struct ql_rcv_buf_cb),GFP_KERNEL);
+ qdev->lrg_buf =
+ kmalloc(qdev->num_large_buffers * sizeof(struct ql_rcv_buf_cb),
+ GFP_KERNEL);
if (qdev->lrg_buf == NULL) {
- printk(KERN_ERR PFX
- "%s: qdev->lrg_buf alloc failed.\n", qdev->ndev->name);
+ netdev_err(qdev->ndev, "qdev->lrg_buf alloc failed\n");
return -ENOMEM;
}
qdev->lrg_buf_q_alloc_virt_addr =
- pci_alloc_consistent(qdev->pdev,
- qdev->lrg_buf_q_alloc_size,
- &qdev->lrg_buf_q_alloc_phy_addr);
+ pci_alloc_consistent(qdev->pdev,
+ qdev->lrg_buf_q_alloc_size,
+ &qdev->lrg_buf_q_alloc_phy_addr);
if (qdev->lrg_buf_q_alloc_virt_addr == NULL) {
- printk(KERN_ERR PFX
- "%s: lBufQ failed\n", qdev->ndev->name);
+ netdev_err(qdev->ndev, "lBufQ failed\n");
return -ENOMEM;
}
qdev->lrg_buf_q_virt_addr = qdev->lrg_buf_q_alloc_virt_addr;
@@ -2715,21 +2610,19 @@ static int ql_alloc_buffer_queues(struct ql3_adapter *qdev)
/* Create Small Buffer Queue */
qdev->small_buf_q_size =
- NUM_SBUFQ_ENTRIES * sizeof(struct lrg_buf_q_entry);
+ NUM_SBUFQ_ENTRIES * sizeof(struct lrg_buf_q_entry);
if (qdev->small_buf_q_size < PAGE_SIZE)
qdev->small_buf_q_alloc_size = PAGE_SIZE;
else
qdev->small_buf_q_alloc_size = qdev->small_buf_q_size * 2;
qdev->small_buf_q_alloc_virt_addr =
- pci_alloc_consistent(qdev->pdev,
- qdev->small_buf_q_alloc_size,
- &qdev->small_buf_q_alloc_phy_addr);
+ pci_alloc_consistent(qdev->pdev,
+ qdev->small_buf_q_alloc_size,
+ &qdev->small_buf_q_alloc_phy_addr);
if (qdev->small_buf_q_alloc_virt_addr == NULL) {
- printk(KERN_ERR PFX
- "%s: Small Buffer Queue allocation failed.\n",
- qdev->ndev->name);
+ netdev_err(qdev->ndev, "Small Buffer Queue allocation failed\n");
pci_free_consistent(qdev->pdev, qdev->lrg_buf_q_alloc_size,
qdev->lrg_buf_q_alloc_virt_addr,
qdev->lrg_buf_q_alloc_phy_addr);
@@ -2738,18 +2631,17 @@ static int ql_alloc_buffer_queues(struct ql3_adapter *qdev)
qdev->small_buf_q_virt_addr = qdev->small_buf_q_alloc_virt_addr;
qdev->small_buf_q_phy_addr = qdev->small_buf_q_alloc_phy_addr;
- set_bit(QL_ALLOC_BUFQS_DONE,&qdev->flags);
+ set_bit(QL_ALLOC_BUFQS_DONE, &qdev->flags);
return 0;
}
static void ql_free_buffer_queues(struct ql3_adapter *qdev)
{
- if (!test_bit(QL_ALLOC_BUFQS_DONE,&qdev->flags)) {
- printk(KERN_INFO PFX
- "%s: Already done.\n", qdev->ndev->name);
+ if (!test_bit(QL_ALLOC_BUFQS_DONE, &qdev->flags)) {
+ netdev_info(qdev->ndev, "Already done\n");
return;
}
- if(qdev->lrg_buf) kfree(qdev->lrg_buf);
+ kfree(qdev->lrg_buf);
pci_free_consistent(qdev->pdev,
qdev->lrg_buf_q_alloc_size,
qdev->lrg_buf_q_alloc_virt_addr,
@@ -2764,7 +2656,7 @@ static void ql_free_buffer_queues(struct ql3_adapter *qdev)
qdev->small_buf_q_virt_addr = NULL;
- clear_bit(QL_ALLOC_BUFQS_DONE,&qdev->flags);
+ clear_bit(QL_ALLOC_BUFQS_DONE, &qdev->flags);
}
static int ql_alloc_small_buffers(struct ql3_adapter *qdev)
@@ -2774,18 +2666,16 @@ static int ql_alloc_small_buffers(struct ql3_adapter *qdev)
/* Currently we allocate on one of memory and use it for smallbuffers */
qdev->small_buf_total_size =
- (QL_ADDR_ELE_PER_BUFQ_ENTRY * NUM_SBUFQ_ENTRIES *
- QL_SMALL_BUFFER_SIZE);
+ (QL_ADDR_ELE_PER_BUFQ_ENTRY * NUM_SBUFQ_ENTRIES *
+ QL_SMALL_BUFFER_SIZE);
qdev->small_buf_virt_addr =
- pci_alloc_consistent(qdev->pdev,
- qdev->small_buf_total_size,
- &qdev->small_buf_phy_addr);
+ pci_alloc_consistent(qdev->pdev,
+ qdev->small_buf_total_size,
+ &qdev->small_buf_phy_addr);
if (qdev->small_buf_virt_addr == NULL) {
- printk(KERN_ERR PFX
- "%s: Failed to get small buffer memory.\n",
- qdev->ndev->name);
+ netdev_err(qdev->ndev, "Failed to get small buffer memory\n");
return -ENOMEM;
}
@@ -2804,15 +2694,14 @@ static int ql_alloc_small_buffers(struct ql3_adapter *qdev)
small_buf_q_entry++;
}
qdev->small_buf_index = 0;
- set_bit(QL_ALLOC_SMALL_BUF_DONE,&qdev->flags);
+ set_bit(QL_ALLOC_SMALL_BUF_DONE, &qdev->flags);
return 0;
}
static void ql_free_small_buffers(struct ql3_adapter *qdev)
{
- if (!test_bit(QL_ALLOC_SMALL_BUF_DONE,&qdev->flags)) {
- printk(KERN_INFO PFX
- "%s: Already done.\n", qdev->ndev->name);
+ if (!test_bit(QL_ALLOC_SMALL_BUF_DONE, &qdev->flags)) {
+ netdev_info(qdev->ndev, "Already done\n");
return;
}
if (qdev->small_buf_virt_addr != NULL) {
@@ -2874,11 +2763,9 @@ static int ql_alloc_large_buffers(struct ql3_adapter *qdev)
qdev->lrg_buffer_len);
if (unlikely(!skb)) {
/* Better luck next round */
- printk(KERN_ERR PFX
- "%s: large buff alloc failed, "
- "for %d bytes at index %d.\n",
- qdev->ndev->name,
- qdev->lrg_buffer_len * 2, i);
+ netdev_err(qdev->ndev,
+ "large buff alloc failed for %d bytes at index %d\n",
+ qdev->lrg_buffer_len * 2, i);
ql_free_large_buffers(qdev);
return -ENOMEM;
} else {
@@ -2899,9 +2786,10 @@ static int ql_alloc_large_buffers(struct ql3_adapter *qdev)
PCI_DMA_FROMDEVICE);
err = pci_dma_mapping_error(qdev->pdev, map);
- if(err) {
- printk(KERN_ERR "%s: PCI mapping failed with error: %d\n",
- qdev->ndev->name, err);
+ if (err) {
+ netdev_err(qdev->ndev,
+ "PCI mapping failed with error: %d\n",
+ err);
ql_free_large_buffers(qdev);
return -ENOMEM;
}
@@ -2926,10 +2814,8 @@ static void ql_free_send_free_list(struct ql3_adapter *qdev)
tx_cb = &qdev->tx_buf[0];
for (i = 0; i < NUM_REQ_Q_ENTRIES; i++) {
- if (tx_cb->oal) {
- kfree(tx_cb->oal);
- tx_cb->oal = NULL;
- }
+ kfree(tx_cb->oal);
+ tx_cb->oal = NULL;
tx_cb++;
}
}
@@ -2938,8 +2824,7 @@ static int ql_create_send_free_list(struct ql3_adapter *qdev)
{
struct ql_tx_buf_cb *tx_cb;
int i;
- struct ob_mac_iocb_req *req_q_curr =
- qdev->req_q_virt_addr;
+ struct ob_mac_iocb_req *req_q_curr = qdev->req_q_virt_addr;
/* Create free list of transmit buffers */
for (i = 0; i < NUM_REQ_Q_ENTRIES; i++) {
@@ -2960,23 +2845,22 @@ static int ql_alloc_mem_resources(struct ql3_adapter *qdev)
if (qdev->ndev->mtu == NORMAL_MTU_SIZE) {
qdev->num_lbufq_entries = NUM_LBUFQ_ENTRIES;
qdev->lrg_buffer_len = NORMAL_MTU_SIZE;
- }
- else if (qdev->ndev->mtu == JUMBO_MTU_SIZE) {
+ } else if (qdev->ndev->mtu == JUMBO_MTU_SIZE) {
/*
* Bigger buffers, so less of them.
*/
qdev->num_lbufq_entries = JUMBO_NUM_LBUFQ_ENTRIES;
qdev->lrg_buffer_len = JUMBO_MTU_SIZE;
} else {
- printk(KERN_ERR PFX
- "%s: Invalid mtu size. Only 1500 and 9000 are accepted.\n",
- qdev->ndev->name);
+ netdev_err(qdev->ndev, "Invalid mtu size: %d. Only %d and %d are accepted.\n",
+ qdev->ndev->mtu, NORMAL_MTU_SIZE, JUMBO_MTU_SIZE);
return -ENOMEM;
}
- qdev->num_large_buffers = qdev->num_lbufq_entries * QL_ADDR_ELE_PER_BUFQ_ENTRY;
+ qdev->num_large_buffers =
+ qdev->num_lbufq_entries * QL_ADDR_ELE_PER_BUFQ_ENTRY;
qdev->lrg_buffer_len += VLAN_ETH_HLEN + VLAN_ID_LEN + QL_HEADER_SPACE;
qdev->max_frame_size =
- (qdev->lrg_buffer_len - QL_HEADER_SPACE) + ETHERNET_CRC_SIZE;
+ (qdev->lrg_buffer_len - QL_HEADER_SPACE) + ETHERNET_CRC_SIZE;
/*
* First allocate a page of shared memory and use it for shadow
@@ -2984,51 +2868,44 @@ static int ql_alloc_mem_resources(struct ql3_adapter *qdev)
* Network Completion Queue Producer Index Register
*/
qdev->shadow_reg_virt_addr =
- pci_alloc_consistent(qdev->pdev,
- PAGE_SIZE, &qdev->shadow_reg_phy_addr);
+ pci_alloc_consistent(qdev->pdev,
+ PAGE_SIZE, &qdev->shadow_reg_phy_addr);
if (qdev->shadow_reg_virt_addr != NULL) {
qdev->preq_consumer_index = (u16 *) qdev->shadow_reg_virt_addr;
qdev->req_consumer_index_phy_addr_high =
- MS_64BITS(qdev->shadow_reg_phy_addr);
+ MS_64BITS(qdev->shadow_reg_phy_addr);
qdev->req_consumer_index_phy_addr_low =
- LS_64BITS(qdev->shadow_reg_phy_addr);
+ LS_64BITS(qdev->shadow_reg_phy_addr);
qdev->prsp_producer_index =
- (__le32 *) (((u8 *) qdev->preq_consumer_index) + 8);
+ (__le32 *) (((u8 *) qdev->preq_consumer_index) + 8);
qdev->rsp_producer_index_phy_addr_high =
- qdev->req_consumer_index_phy_addr_high;
+ qdev->req_consumer_index_phy_addr_high;
qdev->rsp_producer_index_phy_addr_low =
- qdev->req_consumer_index_phy_addr_low + 8;
+ qdev->req_consumer_index_phy_addr_low + 8;
} else {
- printk(KERN_ERR PFX
- "%s: shadowReg Alloc failed.\n", qdev->ndev->name);
+ netdev_err(qdev->ndev, "shadowReg Alloc failed\n");
return -ENOMEM;
}
if (ql_alloc_net_req_rsp_queues(qdev) != 0) {
- printk(KERN_ERR PFX
- "%s: ql_alloc_net_req_rsp_queues failed.\n",
- qdev->ndev->name);
+ netdev_err(qdev->ndev, "ql_alloc_net_req_rsp_queues failed\n");
goto err_req_rsp;
}
if (ql_alloc_buffer_queues(qdev) != 0) {
- printk(KERN_ERR PFX
- "%s: ql_alloc_buffer_queues failed.\n",
- qdev->ndev->name);
+ netdev_err(qdev->ndev, "ql_alloc_buffer_queues failed\n");
goto err_buffer_queues;
}
if (ql_alloc_small_buffers(qdev) != 0) {
- printk(KERN_ERR PFX
- "%s: ql_alloc_small_buffers failed\n", qdev->ndev->name);
+ netdev_err(qdev->ndev, "ql_alloc_small_buffers failed\n");
goto err_small_buffers;
}
if (ql_alloc_large_buffers(qdev) != 0) {
- printk(KERN_ERR PFX
- "%s: ql_alloc_large_buffers failed\n", qdev->ndev->name);
+ netdev_err(qdev->ndev, "ql_alloc_large_buffers failed\n");
goto err_small_buffers;
}
@@ -3076,7 +2953,7 @@ static int ql_init_misc_registers(struct ql3_adapter *qdev)
struct ql3xxx_local_ram_registers __iomem *local_ram =
(void __iomem *)qdev->mem_map_registers;
- if(ql_sem_spinlock(qdev, QL_DDR_RAM_SEM_MASK,
+ if (ql_sem_spinlock(qdev, QL_DDR_RAM_SEM_MASK,
(QL_RESOURCE_BITS_BASE_CODE | (qdev->mac_index) *
2) << 4))
return -1;
@@ -3132,18 +3009,20 @@ static int ql_init_misc_registers(struct ql3_adapter *qdev)
static int ql_adapter_initialize(struct ql3_adapter *qdev)
{
u32 value;
- struct ql3xxx_port_registers __iomem *port_regs = qdev->mem_map_registers;
+ struct ql3xxx_port_registers __iomem *port_regs =
+ qdev->mem_map_registers;
+ u32 *spir = &port_regs->CommonRegs.serialPortInterfaceReg;
struct ql3xxx_host_memory_registers __iomem *hmem_regs =
- (void __iomem *)port_regs;
+ (void __iomem *)port_regs;
u32 delay = 10;
int status = 0;
unsigned long hw_flags = 0;
- if(ql_mii_setup(qdev))
+ if (ql_mii_setup(qdev))
return -1;
/* Bring out PHY out of reset */
- ql_write_common_reg(qdev, &port_regs->CommonRegs.serialPortInterfaceReg,
+ ql_write_common_reg(qdev, spir,
(ISP_SERIAL_PORT_IF_WE |
(ISP_SERIAL_PORT_IF_WE << 16)));
/* Give the PHY time to come out of reset. */
@@ -3152,13 +3031,13 @@ static int ql_adapter_initialize(struct ql3_adapter *qdev)
netif_carrier_off(qdev->ndev);
/* V2 chip fix for ARS-39168. */
- ql_write_common_reg(qdev, &port_regs->CommonRegs.serialPortInterfaceReg,
+ ql_write_common_reg(qdev, spir,
(ISP_SERIAL_PORT_IF_SDE |
(ISP_SERIAL_PORT_IF_SDE << 16)));
/* Request Queue Registers */
- *((u32 *) (qdev->preq_consumer_index)) = 0;
- atomic_set(&qdev->tx_count,NUM_REQ_Q_ENTRIES);
+ *((u32 *)(qdev->preq_consumer_index)) = 0;
+ atomic_set(&qdev->tx_count, NUM_REQ_Q_ENTRIES);
qdev->req_producer_index = 0;
ql_write_page1_reg(qdev,
@@ -3208,7 +3087,9 @@ static int ql_adapter_initialize(struct ql3_adapter *qdev)
&hmem_regs->rxLargeQBaseAddrLow,
LS_64BITS(qdev->lrg_buf_q_phy_addr));
- ql_write_page1_reg(qdev, &hmem_regs->rxLargeQLength, qdev->num_lbufq_entries);
+ ql_write_page1_reg(qdev,
+ &hmem_regs->rxLargeQLength,
+ qdev->num_lbufq_entries);
ql_write_page1_reg(qdev,
&hmem_regs->rxLargeBufferLength,
@@ -3258,7 +3139,7 @@ static int ql_adapter_initialize(struct ql3_adapter *qdev)
if ((value & PORT_STATUS_IC) == 0) {
/* Chip has not been configured yet, so let it rip. */
- if(ql_init_misc_registers(qdev)) {
+ if (ql_init_misc_registers(qdev)) {
status = -1;
goto out;
}
@@ -3268,7 +3149,7 @@ static int ql_adapter_initialize(struct ql3_adapter *qdev)
value = (0xFFFF << 16) | qdev->nvram_data.extHwConfig;
- if(ql_sem_spinlock(qdev, QL_FLASH_SEM_MASK,
+ if (ql_sem_spinlock(qdev, QL_FLASH_SEM_MASK,
(QL_RESOURCE_BITS_BASE_CODE | (qdev->mac_index)
* 2) << 13)) {
status = -1;
@@ -3291,7 +3172,7 @@ static int ql_adapter_initialize(struct ql3_adapter *qdev)
&port_regs->mac0MaxFrameLengthReg,
qdev->max_frame_size);
- if(ql_sem_spinlock(qdev, QL_PHY_GIO_SEM_MASK,
+ if (ql_sem_spinlock(qdev, QL_PHY_GIO_SEM_MASK,
(QL_RESOURCE_BITS_BASE_CODE | (qdev->mac_index) *
2) << 7)) {
status = -1;
@@ -3353,8 +3234,7 @@ static int ql_adapter_initialize(struct ql3_adapter *qdev)
} while (--delay);
if (delay == 0) {
- printk(KERN_ERR PFX
- "%s: Hw Initialization timeout.\n", qdev->ndev->name);
+ netdev_err(qdev->ndev, "Hw Initialization timeout\n");
status = -1;
goto out;
}
@@ -3385,7 +3265,8 @@ out:
*/
static int ql_adapter_reset(struct ql3_adapter *qdev)
{
- struct ql3xxx_port_registers __iomem *port_regs = qdev->mem_map_registers;
+ struct ql3xxx_port_registers __iomem *port_regs =
+ qdev->mem_map_registers;
int status = 0;
u16 value;
int max_wait_time;
@@ -3396,17 +3277,14 @@ static int ql_adapter_reset(struct ql3_adapter *qdev)
/*
* Issue soft reset to chip.
*/
- printk(KERN_DEBUG PFX
- "%s: Issue soft reset to chip.\n",
- qdev->ndev->name);
+ netdev_printk(KERN_DEBUG, qdev->ndev, "Issue soft reset to chip\n");
ql_write_common_reg(qdev,
&port_regs->CommonRegs.ispControlStatus,
((ISP_CONTROL_SR << 16) | ISP_CONTROL_SR));
/* Wait 3 seconds for reset to complete. */
- printk(KERN_DEBUG PFX
- "%s: Wait 10 milliseconds for reset to complete.\n",
- qdev->ndev->name);
+ netdev_printk(KERN_DEBUG, qdev->ndev,
+ "Wait 10 milliseconds for reset to complete\n");
/* Wait until the firmware tells us the Soft Reset is done */
max_wait_time = 5;
@@ -3427,8 +3305,8 @@ static int ql_adapter_reset(struct ql3_adapter *qdev)
value =
ql_read_common_reg(qdev, &port_regs->CommonRegs.ispControlStatus);
if (value & ISP_CONTROL_RI) {
- printk(KERN_DEBUG PFX
- "ql_adapter_reset: clearing RI after reset.\n");
+ netdev_printk(KERN_DEBUG, qdev->ndev,
+ "clearing RI after reset\n");
ql_write_common_reg(qdev,
&port_regs->CommonRegs.
ispControlStatus,
@@ -3448,13 +3326,11 @@ static int ql_adapter_reset(struct ql3_adapter *qdev)
*/
max_wait_time = 5;
do {
- value =
- ql_read_common_reg(qdev,
- &port_regs->CommonRegs.
- ispControlStatus);
- if ((value & ISP_CONTROL_FSR) == 0) {
+ value = ql_read_common_reg(qdev,
+ &port_regs->CommonRegs.
+ ispControlStatus);
+ if ((value & ISP_CONTROL_FSR) == 0)
break;
- }
ssleep(1);
} while ((--max_wait_time));
}
@@ -3468,7 +3344,8 @@ static int ql_adapter_reset(struct ql3_adapter *qdev)
static void ql_set_mac_info(struct ql3_adapter *qdev)
{
- struct ql3xxx_port_registers __iomem *port_regs = qdev->mem_map_registers;
+ struct ql3xxx_port_registers __iomem *port_regs =
+ qdev->mem_map_registers;
u32 value, port_status;
u8 func_number;
@@ -3484,9 +3361,9 @@ static void ql_set_mac_info(struct ql3_adapter *qdev)
qdev->mb_bit_mask = FN0_MA_BITS_MASK;
qdev->PHYAddr = PORT0_PHY_ADDRESS;
if (port_status & PORT_STATUS_SM0)
- set_bit(QL_LINK_OPTICAL,&qdev->flags);
+ set_bit(QL_LINK_OPTICAL, &qdev->flags);
else
- clear_bit(QL_LINK_OPTICAL,&qdev->flags);
+ clear_bit(QL_LINK_OPTICAL, &qdev->flags);
break;
case ISP_CONTROL_FN1_NET:
@@ -3495,17 +3372,17 @@ static void ql_set_mac_info(struct ql3_adapter *qdev)
qdev->mb_bit_mask = FN1_MA_BITS_MASK;
qdev->PHYAddr = PORT1_PHY_ADDRESS;
if (port_status & PORT_STATUS_SM1)
- set_bit(QL_LINK_OPTICAL,&qdev->flags);
+ set_bit(QL_LINK_OPTICAL, &qdev->flags);
else
- clear_bit(QL_LINK_OPTICAL,&qdev->flags);
+ clear_bit(QL_LINK_OPTICAL, &qdev->flags);
break;
case ISP_CONTROL_FN0_SCSI:
case ISP_CONTROL_FN1_SCSI:
default:
- printk(KERN_DEBUG PFX
- "%s: Invalid function number, ispControlStatus = 0x%x\n",
- qdev->ndev->name,value);
+ netdev_printk(KERN_DEBUG, qdev->ndev,
+ "Invalid function number, ispControlStatus = 0x%x\n",
+ value);
break;
}
qdev->numPorts = qdev->nvram_data.version_and_numPorts >> 8;
@@ -3516,32 +3393,26 @@ static void ql_display_dev_info(struct net_device *ndev)
struct ql3_adapter *qdev = (struct ql3_adapter *)netdev_priv(ndev);
struct pci_dev *pdev = qdev->pdev;
- printk(KERN_INFO PFX
- "\n%s Adapter %d RevisionID %d found %s on PCI slot %d.\n",
- DRV_NAME, qdev->index, qdev->chip_rev_id,
- (qdev->device_id == QL3032_DEVICE_ID) ? "QLA3032" : "QLA3022",
- qdev->pci_slot);
- printk(KERN_INFO PFX
- "%s Interface.\n",
- test_bit(QL_LINK_OPTICAL,&qdev->flags) ? "OPTICAL" : "COPPER");
+ netdev_info(ndev,
+ "%s Adapter %d RevisionID %d found %s on PCI slot %d\n",
+ DRV_NAME, qdev->index, qdev->chip_rev_id,
+ qdev->device_id == QL3032_DEVICE_ID ? "QLA3032" : "QLA3022",
+ qdev->pci_slot);
+ netdev_info(ndev, "%s Interface\n",
+ test_bit(QL_LINK_OPTICAL, &qdev->flags) ? "OPTICAL" : "COPPER");
/*
* Print PCI bus width/type.
*/
- printk(KERN_INFO PFX
- "Bus interface is %s %s.\n",
- ((qdev->pci_width == 64) ? "64-bit" : "32-bit"),
- ((qdev->pci_x) ? "PCI-X" : "PCI"));
+ netdev_info(ndev, "Bus interface is %s %s\n",
+ ((qdev->pci_width == 64) ? "64-bit" : "32-bit"),
+ ((qdev->pci_x) ? "PCI-X" : "PCI"));
- printk(KERN_INFO PFX
- "mem IO base address adjusted = 0x%p\n",
- qdev->mem_map_registers);
- printk(KERN_INFO PFX "Interrupt number = %d\n", pdev->irq);
+ netdev_info(ndev, "mem IO base address adjusted = 0x%p\n",
+ qdev->mem_map_registers);
+ netdev_info(ndev, "Interrupt number = %d\n", pdev->irq);
- if (netif_msg_probe(qdev))
- printk(KERN_INFO PFX
- "%s: MAC address %pM\n",
- ndev->name, ndev->dev_addr);
+ netif_info(qdev, probe, ndev, "MAC address %pM\n", ndev->dev_addr);
}
static int ql_adapter_down(struct ql3_adapter *qdev, int do_reset)
@@ -3552,17 +3423,16 @@ static int ql_adapter_down(struct ql3_adapter *qdev, int do_reset)
netif_stop_queue(ndev);
netif_carrier_off(ndev);
- clear_bit(QL_ADAPTER_UP,&qdev->flags);
- clear_bit(QL_LINK_MASTER,&qdev->flags);
+ clear_bit(QL_ADAPTER_UP, &qdev->flags);
+ clear_bit(QL_LINK_MASTER, &qdev->flags);
ql_disable_interrupts(qdev);
free_irq(qdev->pdev->irq, ndev);
- if (qdev->msi && test_bit(QL_MSI_ENABLED,&qdev->flags)) {
- printk(KERN_INFO PFX
- "%s: calling pci_disable_msi().\n", qdev->ndev->name);
- clear_bit(QL_MSI_ENABLED,&qdev->flags);
+ if (qdev->msi && test_bit(QL_MSI_ENABLED, &qdev->flags)) {
+ netdev_info(qdev->ndev, "calling pci_disable_msi()\n");
+ clear_bit(QL_MSI_ENABLED, &qdev->flags);
pci_disable_msi(qdev->pdev);
}
@@ -3576,17 +3446,16 @@ static int ql_adapter_down(struct ql3_adapter *qdev, int do_reset)
spin_lock_irqsave(&qdev->hw_lock, hw_flags);
if (ql_wait_for_drvr_lock(qdev)) {
- if ((soft_reset = ql_adapter_reset(qdev))) {
- printk(KERN_ERR PFX
- "%s: ql_adapter_reset(%d) FAILED!\n",
- ndev->name, qdev->index);
+ soft_reset = ql_adapter_reset(qdev);
+ if (soft_reset) {
+ netdev_err(ndev, "ql_adapter_reset(%d) FAILED!\n",
+ qdev->index);
}
- printk(KERN_ERR PFX
- "%s: Releaseing driver lock via chip reset.\n",ndev->name);
+ netdev_err(ndev,
+ "Releasing driver lock via chip reset\n");
} else {
- printk(KERN_ERR PFX
- "%s: Could not acquire driver lock to do "
- "reset!\n", ndev->name);
+ netdev_err(ndev,
+ "Could not acquire driver lock to do reset!\n");
retval = -1;
}
spin_unlock_irqrestore(&qdev->hw_lock, hw_flags);
@@ -3603,56 +3472,50 @@ static int ql_adapter_up(struct ql3_adapter *qdev)
unsigned long hw_flags;
if (ql_alloc_mem_resources(qdev)) {
- printk(KERN_ERR PFX
- "%s Unable to allocate buffers.\n", ndev->name);
+ netdev_err(ndev, "Unable to allocate buffers\n");
return -ENOMEM;
}
if (qdev->msi) {
if (pci_enable_msi(qdev->pdev)) {
- printk(KERN_ERR PFX
- "%s: User requested MSI, but MSI failed to "
- "initialize. Continuing without MSI.\n",
- qdev->ndev->name);
+ netdev_err(ndev,
+ "User requested MSI, but MSI failed to initialize. Continuing without MSI.\n");
qdev->msi = 0;
} else {
- printk(KERN_INFO PFX "%s: MSI Enabled...\n", qdev->ndev->name);
- set_bit(QL_MSI_ENABLED,&qdev->flags);
+ netdev_info(ndev, "MSI Enabled...\n");
+ set_bit(QL_MSI_ENABLED, &qdev->flags);
irq_flags &= ~IRQF_SHARED;
}
}
- if ((err = request_irq(qdev->pdev->irq,
- ql3xxx_isr,
- irq_flags, ndev->name, ndev))) {
- printk(KERN_ERR PFX
- "%s: Failed to reserve interrupt %d already in use.\n",
- ndev->name, qdev->pdev->irq);
+ err = request_irq(qdev->pdev->irq, ql3xxx_isr,
+ irq_flags, ndev->name, ndev);
+ if (err) {
+ netdev_err(ndev,
+ "Failed to reserve interrupt %d - already in use\n",
+ qdev->pdev->irq);
goto err_irq;
}
spin_lock_irqsave(&qdev->hw_lock, hw_flags);
- if ((err = ql_wait_for_drvr_lock(qdev))) {
- if ((err = ql_adapter_initialize(qdev))) {
- printk(KERN_ERR PFX
- "%s: Unable to initialize adapter.\n",
- ndev->name);
+ err = ql_wait_for_drvr_lock(qdev);
+ if (err) {
+ err = ql_adapter_initialize(qdev);
+ if (err) {
+ netdev_err(ndev, "Unable to initialize adapter\n");
goto err_init;
}
- printk(KERN_ERR PFX
- "%s: Releaseing driver lock.\n",ndev->name);
+ netdev_err(ndev, "Releasing driver lock\n");
ql_sem_unlock(qdev, QL_DRVR_SEM_MASK);
} else {
- printk(KERN_ERR PFX
- "%s: Could not acquire driver lock.\n",
- ndev->name);
+ netdev_err(ndev, "Could not acquire driver lock\n");
goto err_lock;
}
spin_unlock_irqrestore(&qdev->hw_lock, hw_flags);
- set_bit(QL_ADAPTER_UP,&qdev->flags);
+ set_bit(QL_ADAPTER_UP, &qdev->flags);
mod_timer(&qdev->adapter_timer, jiffies + HZ * 1);
@@ -3666,11 +3529,9 @@ err_lock:
spin_unlock_irqrestore(&qdev->hw_lock, hw_flags);
free_irq(qdev->pdev->irq, ndev);
err_irq:
- if (qdev->msi && test_bit(QL_MSI_ENABLED,&qdev->flags)) {
- printk(KERN_INFO PFX
- "%s: calling pci_disable_msi().\n",
- qdev->ndev->name);
- clear_bit(QL_MSI_ENABLED,&qdev->flags);
+ if (qdev->msi && test_bit(QL_MSI_ENABLED, &qdev->flags)) {
+ netdev_info(ndev, "calling pci_disable_msi()\n");
+ clear_bit(QL_MSI_ENABLED, &qdev->flags);
pci_disable_msi(qdev->pdev);
}
return err;
@@ -3678,10 +3539,9 @@ err_irq:
static int ql_cycle_adapter(struct ql3_adapter *qdev, int reset)
{
- if( ql_adapter_down(qdev,reset) || ql_adapter_up(qdev)) {
- printk(KERN_ERR PFX
- "%s: Driver up/down cycle failed, "
- "closing device\n",qdev->ndev->name);
+ if (ql_adapter_down(qdev, reset) || ql_adapter_up(qdev)) {
+ netdev_err(qdev->ndev,
+ "Driver up/down cycle failed, closing device\n");
rtnl_lock();
dev_close(qdev->ndev);
rtnl_unlock();
@@ -3698,24 +3558,24 @@ static int ql3xxx_close(struct net_device *ndev)
* Wait for device to recover from a reset.
* (Rarely happens, but possible.)
*/
- while (!test_bit(QL_ADAPTER_UP,&qdev->flags))
+ while (!test_bit(QL_ADAPTER_UP, &qdev->flags))
msleep(50);
- ql_adapter_down(qdev,QL_DO_RESET);
+ ql_adapter_down(qdev, QL_DO_RESET);
return 0;
}
static int ql3xxx_open(struct net_device *ndev)
{
struct ql3_adapter *qdev = netdev_priv(ndev);
- return (ql_adapter_up(qdev));
+ return ql_adapter_up(qdev);
}
static int ql3xxx_set_mac_address(struct net_device *ndev, void *p)
{
struct ql3_adapter *qdev = (struct ql3_adapter *)netdev_priv(ndev);
struct ql3xxx_port_registers __iomem *port_regs =
- qdev->mem_map_registers;
+ qdev->mem_map_registers;
struct sockaddr *addr = p;
unsigned long hw_flags;
@@ -3750,7 +3610,7 @@ static void ql3xxx_tx_timeout(struct net_device *ndev)
{
struct ql3_adapter *qdev = (struct ql3_adapter *)netdev_priv(ndev);
- printk(KERN_ERR PFX "%s: Resetting...\n", ndev->name);
+ netdev_err(ndev, "Resetting...\n");
/*
* Stop the queues, we've got a problem.
*/
@@ -3770,11 +3630,12 @@ static void ql_reset_work(struct work_struct *work)
u32 value;
struct ql_tx_buf_cb *tx_cb;
int max_wait_time, i;
- struct ql3xxx_port_registers __iomem *port_regs = qdev->mem_map_registers;
+ struct ql3xxx_port_registers __iomem *port_regs =
+ qdev->mem_map_registers;
unsigned long hw_flags;
- if (test_bit((QL_RESET_PER_SCSI | QL_RESET_START),&qdev->flags)) {
- clear_bit(QL_LINK_MASTER,&qdev->flags);
+ if (test_bit((QL_RESET_PER_SCSI | QL_RESET_START), &qdev->flags)) {
+ clear_bit(QL_LINK_MASTER, &qdev->flags);
/*
* Loop through the active list and return the skb.
@@ -3783,17 +3644,19 @@ static void ql_reset_work(struct work_struct *work)
int j;
tx_cb = &qdev->tx_buf[i];
if (tx_cb->skb) {
- printk(KERN_DEBUG PFX
- "%s: Freeing lost SKB.\n",
- qdev->ndev->name);
+ netdev_printk(KERN_DEBUG, ndev,
+ "Freeing lost SKB\n");
pci_unmap_single(qdev->pdev,
- dma_unmap_addr(&tx_cb->map[0], mapaddr),
+ dma_unmap_addr(&tx_cb->map[0],
+ mapaddr),
dma_unmap_len(&tx_cb->map[0], maplen),
PCI_DMA_TODEVICE);
- for(j=1;j<tx_cb->seg_count;j++) {
+ for (j = 1; j < tx_cb->seg_count; j++) {
pci_unmap_page(qdev->pdev,
- dma_unmap_addr(&tx_cb->map[j],mapaddr),
- dma_unmap_len(&tx_cb->map[j],maplen),
+ dma_unmap_addr(&tx_cb->map[j],
+ mapaddr),
+ dma_unmap_len(&tx_cb->map[j],
+ maplen),
PCI_DMA_TODEVICE);
}
dev_kfree_skb(tx_cb->skb);
@@ -3801,8 +3664,7 @@ static void ql_reset_work(struct work_struct *work)
}
}
- printk(KERN_ERR PFX
- "%s: Clearing NRI after reset.\n", qdev->ndev->name);
+ netdev_err(ndev, "Clearing NRI after reset\n");
spin_lock_irqsave(&qdev->hw_lock, hw_flags);
ql_write_common_reg(qdev,
&port_regs->CommonRegs.
@@ -3818,16 +3680,14 @@ static void ql_reset_work(struct work_struct *work)
ispControlStatus);
if ((value & ISP_CONTROL_SR) == 0) {
- printk(KERN_DEBUG PFX
- "%s: reset completed.\n",
- qdev->ndev->name);
+ netdev_printk(KERN_DEBUG, ndev,
+ "reset completed\n");
break;
}
if (value & ISP_CONTROL_RI) {
- printk(KERN_DEBUG PFX
- "%s: clearing NRI after reset.\n",
- qdev->ndev->name);
+ netdev_printk(KERN_DEBUG, ndev,
+ "clearing NRI after reset\n");
ql_write_common_reg(qdev,
&port_regs->
CommonRegs.
@@ -3848,21 +3708,19 @@ static void ql_reset_work(struct work_struct *work)
* Set the reset flags and clear the board again.
* Nothing else to do...
*/
- printk(KERN_ERR PFX
- "%s: Timed out waiting for reset to "
- "complete.\n", ndev->name);
- printk(KERN_ERR PFX
- "%s: Do a reset.\n", ndev->name);
- clear_bit(QL_RESET_PER_SCSI,&qdev->flags);
- clear_bit(QL_RESET_START,&qdev->flags);
- ql_cycle_adapter(qdev,QL_DO_RESET);
+ netdev_err(ndev,
+ "Timed out waiting for reset to complete\n");
+ netdev_err(ndev, "Do a reset\n");
+ clear_bit(QL_RESET_PER_SCSI, &qdev->flags);
+ clear_bit(QL_RESET_START, &qdev->flags);
+ ql_cycle_adapter(qdev, QL_DO_RESET);
return;
}
- clear_bit(QL_RESET_ACTIVE,&qdev->flags);
- clear_bit(QL_RESET_PER_SCSI,&qdev->flags);
- clear_bit(QL_RESET_START,&qdev->flags);
- ql_cycle_adapter(qdev,QL_NO_RESET);
+ clear_bit(QL_RESET_ACTIVE, &qdev->flags);
+ clear_bit(QL_RESET_PER_SCSI, &qdev->flags);
+ clear_bit(QL_RESET_START, &qdev->flags);
+ ql_cycle_adapter(qdev, QL_NO_RESET);
}
}
@@ -3876,7 +3734,8 @@ static void ql_tx_timeout_work(struct work_struct *work)
static void ql_get_board_info(struct ql3_adapter *qdev)
{
- struct ql3xxx_port_registers __iomem *port_regs = qdev->mem_map_registers;
+ struct ql3xxx_port_registers __iomem *port_regs =
+ qdev->mem_map_registers;
u32 value;
value = ql_read_page0_reg_l(qdev, &port_regs->portStatus);
@@ -3915,20 +3774,18 @@ static int __devinit ql3xxx_probe(struct pci_dev *pdev,
{
struct net_device *ndev = NULL;
struct ql3_adapter *qdev = NULL;
- static int cards_found = 0;
+ static int cards_found;
int uninitialized_var(pci_using_dac), err;
err = pci_enable_device(pdev);
if (err) {
- printk(KERN_ERR PFX "%s cannot enable PCI device\n",
- pci_name(pdev));
+ pr_err("%s cannot enable PCI device\n", pci_name(pdev));
goto err_out;
}
err = pci_request_regions(pdev, DRV_NAME);
if (err) {
- printk(KERN_ERR PFX "%s cannot obtain PCI resources\n",
- pci_name(pdev));
+ pr_err("%s cannot obtain PCI resources\n", pci_name(pdev));
goto err_out_disable_pdev;
}
@@ -3943,15 +3800,13 @@ static int __devinit ql3xxx_probe(struct pci_dev *pdev,
}
if (err) {
- printk(KERN_ERR PFX "%s no usable DMA configuration\n",
- pci_name(pdev));
+ pr_err("%s no usable DMA configuration\n", pci_name(pdev));
goto err_out_free_regions;
}
ndev = alloc_etherdev(sizeof(struct ql3_adapter));
if (!ndev) {
- printk(KERN_ERR PFX "%s could not alloc etherdev\n",
- pci_name(pdev));
+ pr_err("%s could not alloc etherdev\n", pci_name(pdev));
err = -ENOMEM;
goto err_out_free_regions;
}
@@ -3978,8 +3833,7 @@ static int __devinit ql3xxx_probe(struct pci_dev *pdev,
qdev->mem_map_registers = pci_ioremap_bar(pdev, 1);
if (!qdev->mem_map_registers) {
- printk(KERN_ERR PFX "%s: cannot map device registers\n",
- pci_name(pdev));
+ pr_err("%s: cannot map device registers\n", pci_name(pdev));
err = -EIO;
goto err_out_free_ndev;
}
@@ -3998,9 +3852,8 @@ static int __devinit ql3xxx_probe(struct pci_dev *pdev,
/* make sure the EEPROM is good */
if (ql_get_nvram_params(qdev)) {
- printk(KERN_ALERT PFX
- "ql3xxx_probe: Adapter #%d, Invalid NVRAM parameters.\n",
- qdev->index);
+ pr_alert("%s: Adapter #%d, Invalid NVRAM parameters\n",
+ __func__, qdev->index);
err = -EIO;
goto err_out_iounmap;
}
@@ -4026,14 +3879,12 @@ static int __devinit ql3xxx_probe(struct pci_dev *pdev,
* Set the Maximum Memory Read Byte Count value. We do this to handle
* jumbo frames.
*/
- if (qdev->pci_x) {
+ if (qdev->pci_x)
pci_write_config_word(pdev, (int)0x4e, (u16) 0x0036);
- }
err = register_netdev(ndev);
if (err) {
- printk(KERN_ERR PFX "%s: cannot register net device\n",
- pci_name(pdev));
+ pr_err("%s: cannot register net device\n", pci_name(pdev));
goto err_out_iounmap;
}
@@ -4052,10 +3903,10 @@ static int __devinit ql3xxx_probe(struct pci_dev *pdev,
qdev->adapter_timer.expires = jiffies + HZ * 2; /* two second delay */
qdev->adapter_timer.data = (unsigned long)qdev;
- if(!cards_found) {
- printk(KERN_ALERT PFX "%s\n", DRV_STRING);
- printk(KERN_ALERT PFX "Driver name: %s, Version: %s.\n",
- DRV_NAME, DRV_VERSION);
+ if (!cards_found) {
+ pr_alert("%s\n", DRV_STRING);
+ pr_alert("Driver name: %s, Version: %s\n",
+ DRV_NAME, DRV_VERSION);
}
ql_display_dev_info(ndev);
diff --git a/drivers/net/qlcnic/qlcnic.h b/drivers/net/qlcnic/qlcnic.h
index 896d40df9a1..970389331bb 100644
--- a/drivers/net/qlcnic/qlcnic.h
+++ b/drivers/net/qlcnic/qlcnic.h
@@ -51,8 +51,8 @@
#define _QLCNIC_LINUX_MAJOR 5
#define _QLCNIC_LINUX_MINOR 0
-#define _QLCNIC_LINUX_SUBVERSION 2
-#define QLCNIC_LINUX_VERSIONID "5.0.2"
+#define _QLCNIC_LINUX_SUBVERSION 7
+#define QLCNIC_LINUX_VERSIONID "5.0.7"
#define QLCNIC_DRV_IDC_VER 0x01
#define QLCNIC_VERSION_CODE(a, b, c) (((a) << 24) + ((b) << 16) + (c))
@@ -68,6 +68,7 @@
#define QLCNIC_DECODE_VERSION(v) \
QLCNIC_VERSION_CODE(((v) & 0xff), (((v) >> 8) & 0xff), ((v) >> 16))
+#define QLCNIC_MIN_FW_VERSION QLCNIC_VERSION_CODE(4, 4, 2)
#define QLCNIC_NUM_FLASH_SECTORS (64)
#define QLCNIC_FLASH_SECTOR_SIZE (64 * 1024)
#define QLCNIC_FLASH_TOTAL_SIZE (QLCNIC_NUM_FLASH_SECTORS \
@@ -112,8 +113,10 @@
#define TX_UDPV6_PKT 0x0c
/* Tx defines */
-#define MAX_BUFFERS_PER_CMD 32
-#define TX_STOP_THRESH ((MAX_SKB_FRAGS >> 2) + 4)
+#define MAX_TSO_HEADER_DESC 2
+#define MGMT_CMD_DESC_RESV 4
+#define TX_STOP_THRESH ((MAX_SKB_FRAGS >> 2) + MAX_TSO_HEADER_DESC \
+ + MGMT_CMD_DESC_RESV)
#define QLCNIC_MAX_TX_TIMEOUTS 2
/*
@@ -197,8 +200,7 @@ struct cmd_desc_type0 {
__le64 addr_buffer4;
- __le32 reserved2;
- __le16 reserved;
+ u8 eth_addr[ETH_ALEN];
__le16 vlan_TCI;
} __attribute__ ((aligned(64)));
@@ -315,6 +317,8 @@ struct uni_data_desc{
#define QLCNIC_BRDTYPE_P3_10G_XFP 0x0032
#define QLCNIC_BRDTYPE_P3_10G_TP 0x0080
+#define QLCNIC_MSIX_TABLE_OFFSET 0x44
+
/* Flash memory map */
#define QLCNIC_BRDCFG_START 0x4000 /* board config */
#define QLCNIC_BOOTLD_START 0x10000 /* bootld */
@@ -367,7 +371,7 @@ struct qlcnic_recv_crb {
*/
struct qlcnic_cmd_buffer {
struct sk_buff *skb;
- struct qlcnic_skb_frag frag_array[MAX_BUFFERS_PER_CMD + 1];
+ struct qlcnic_skb_frag frag_array[MAX_SKB_FRAGS + 1];
u32 frag_count;
};
@@ -377,7 +381,6 @@ struct qlcnic_rx_buffer {
struct sk_buff *skb;
u64 dma;
u16 ref_handle;
- u16 state;
};
/* Board types */
@@ -419,7 +422,6 @@ struct qlcnic_adapter_stats {
u64 xmit_on;
u64 xmit_off;
u64 skb_alloc_failure;
- u64 null_skb;
u64 null_rxbuf;
u64 rx_dma_map_error;
u64 tx_dma_map_error;
@@ -542,7 +544,17 @@ struct qlcnic_recv_context {
#define QLCNIC_CDRP_CMD_READ_PEXQ_PARAMETERS 0x0000001c
#define QLCNIC_CDRP_CMD_GET_LIC_CAPABILITIES 0x0000001d
#define QLCNIC_CDRP_CMD_READ_MAX_LRO_PER_BOARD 0x0000001e
-#define QLCNIC_CDRP_CMD_MAX 0x0000001f
+#define QLCNIC_CDRP_CMD_MAC_ADDRESS 0x0000001f
+
+#define QLCNIC_CDRP_CMD_GET_PCI_INFO 0x00000020
+#define QLCNIC_CDRP_CMD_GET_NIC_INFO 0x00000021
+#define QLCNIC_CDRP_CMD_SET_NIC_INFO 0x00000022
+#define QLCNIC_CDRP_CMD_RESET_NPAR 0x00000023
+#define QLCNIC_CDRP_CMD_GET_ESWITCH_CAPABILITY 0x00000024
+#define QLCNIC_CDRP_CMD_TOGGLE_ESWITCH 0x00000025
+#define QLCNIC_CDRP_CMD_GET_ESWITCH_STATUS 0x00000026
+#define QLCNIC_CDRP_CMD_SET_PORTMIRRORING 0x00000027
+#define QLCNIC_CDRP_CMD_CONFIGURE_ESWITCH 0x00000028
#define QLCNIC_RCODE_SUCCESS 0
#define QLCNIC_RCODE_TIMEOUT 17
@@ -556,12 +568,12 @@ struct qlcnic_recv_context {
#define QLCNIC_CAP0_LSO (1 << 6)
#define QLCNIC_CAP0_JUMBO_CONTIGUOUS (1 << 7)
#define QLCNIC_CAP0_LRO_CONTIGUOUS (1 << 8)
+#define QLCNIC_CAP0_VALIDOFF (1 << 11)
/*
* Context state
*/
-#define QLCHAL_VERSION 1
-
+#define QLCNIC_HOST_CTX_STATE_FREED 0
#define QLCNIC_HOST_CTX_STATE_ACTIVE 2
/*
@@ -592,9 +604,10 @@ struct qlcnic_hostrq_rx_ctx {
__le32 sds_ring_offset; /* Offset to SDS config */
__le16 num_rds_rings; /* Count of RDS rings */
__le16 num_sds_rings; /* Count of SDS rings */
- __le16 rsvd1; /* Padding */
- __le16 rsvd2; /* Padding */
- u8 reserved[128]; /* reserve space for future expansion*/
+ __le16 valid_field_offset;
+ u8 txrx_sds_binding;
+ u8 msix_handler;
+ u8 reserved[128]; /* reserve space for future expansion*/
/* MUST BE 64-bit aligned.
The following is packed:
- N hostrq_rds_rings
@@ -808,9 +821,10 @@ struct qlcnic_nic_intr_coalesce {
#define QLCNIC_LRO_REQUEST_CLEANUP 4
/* Capabilites received */
-#define QLCNIC_FW_CAPABILITY_BDG (1 << 8)
-#define QLCNIC_FW_CAPABILITY_FVLANTX (1 << 9)
-#define QLCNIC_FW_CAPABILITY_HW_LRO (1 << 10)
+#define QLCNIC_FW_CAPABILITY_TSO BIT_1
+#define QLCNIC_FW_CAPABILITY_BDG BIT_8
+#define QLCNIC_FW_CAPABILITY_FVLANTX BIT_9
+#define QLCNIC_FW_CAPABILITY_HW_LRO BIT_10
/* module types */
#define LINKEVENT_MODULE_NOT_PRESENT 1
@@ -881,12 +895,14 @@ struct qlcnic_mac_req {
#define QLCNIC_LRO_ENABLED 0x08
#define QLCNIC_BRIDGE_ENABLED 0X10
#define QLCNIC_DIAG_ENABLED 0x20
+#define QLCNIC_ESWITCH_ENABLED 0x40
#define QLCNIC_IS_MSI_FAMILY(adapter) \
((adapter)->flags & (QLCNIC_MSI_ENABLED | QLCNIC_MSIX_ENABLED))
#define MSIX_ENTRIES_PER_ADAPTER NUM_STS_DESC_RINGS
#define QLCNIC_MSIX_TBL_SPACE 8192
#define QLCNIC_PCI_REG_MSIX_TBL 0x44
+#define QLCNIC_MSIX_TBL_PGSIZE 4096
#define QLCNIC_NETDEV_WEIGHT 128
#define QLCNIC_ADAPTER_UP_MAGIC 777
@@ -895,6 +911,7 @@ struct qlcnic_mac_req {
#define __QLCNIC_DEV_UP 1
#define __QLCNIC_RESETTING 2
#define __QLCNIC_START_FW 4
+#define __QLCNIC_AER 5
#define QLCNIC_INTERRUPT_TEST 1
#define QLCNIC_LOOPBACK_TEST 2
@@ -919,11 +936,11 @@ struct qlcnic_adapter {
u8 rx_csum;
u8 portnum;
u8 physical_port;
+ u8 reset_context;
u8 mc_enabled;
u8 max_mc_count;
u8 rss_supported;
- u8 rsrvd1;
u8 fw_wait_cnt;
u8 fw_fail_cnt;
u8 tx_timeo_cnt;
@@ -932,7 +949,6 @@ struct qlcnic_adapter {
u8 has_link_events;
u8 fw_type;
u16 tx_context_id;
- u16 mtu;
u16 is_up;
u16 link_speed;
@@ -940,6 +956,13 @@ struct qlcnic_adapter {
u16 link_autoneg;
u16 module_type;
+ u16 op_mode;
+ u16 switch_mode;
+ u16 max_tx_ques;
+ u16 max_rx_ques;
+ u16 max_mtu;
+
+ u32 fw_hal_version;
u32 capabilities;
u32 flags;
u32 irq;
@@ -948,18 +971,22 @@ struct qlcnic_adapter {
u32 int_vec_bit;
u32 heartbit;
+ u8 max_mac_filters;
u8 dev_state;
u8 diag_test;
u8 diag_cnt;
u8 reset_ack_timeo;
u8 dev_init_timeo;
- u8 rsrd1;
u16 msg_enable;
u8 mac_addr[ETH_ALEN];
u64 dev_rst_time;
+ struct qlcnic_npar_info *npars;
+ struct qlcnic_eswitch *eswitch;
+ struct qlcnic_nic_template *nic_ops;
+
struct qlcnic_adapter_stats stats;
struct qlcnic_recv_context recv_ctx;
@@ -974,8 +1001,6 @@ struct qlcnic_adapter {
struct delayed_work fw_work;
- struct work_struct tx_timeout_task;
-
struct qlcnic_nic_intr_coalesce coal;
unsigned long state;
@@ -984,6 +1009,123 @@ struct qlcnic_adapter {
const struct firmware *fw;
};
+struct qlcnic_info {
+ __le16 pci_func;
+ __le16 op_mode; /* 1 = Priv, 2 = NP, 3 = NP passthru */
+ __le16 phys_port;
+ __le16 switch_mode; /* 0 = disabled, 1 = int, 2 = ext */
+
+ __le32 capabilities;
+ u8 max_mac_filters;
+ u8 reserved1;
+ __le16 max_mtu;
+
+ __le16 max_tx_ques;
+ __le16 max_rx_ques;
+ __le16 min_tx_bw;
+ __le16 max_tx_bw;
+ u8 reserved2[104];
+};
+
+struct qlcnic_pci_info {
+ __le16 id; /* pci function id */
+ __le16 active; /* 1 = Enabled */
+ __le16 type; /* 1 = NIC, 2 = FCoE, 3 = iSCSI */
+ __le16 default_port; /* default port number */
+
+ __le16 tx_min_bw; /* Multiple of 100mbpc */
+ __le16 tx_max_bw;
+ __le16 reserved1[2];
+
+ u8 mac[ETH_ALEN];
+ u8 reserved2[106];
+};
+
+struct qlcnic_npar_info {
+ u16 vlan_id;
+ u16 min_bw;
+ u16 max_bw;
+ u8 phy_port;
+ u8 type;
+ u8 active;
+ u8 enable_pm;
+ u8 dest_npar;
+ u8 host_vlan_tag;
+ u8 promisc_mode;
+ u8 discard_tagged;
+ u8 mac_learning;
+};
+struct qlcnic_eswitch {
+ u8 port;
+ u8 active_vports;
+ u8 active_vlans;
+ u8 active_ucast_filters;
+ u8 max_ucast_filters;
+ u8 max_active_vlans;
+
+ u32 flags;
+#define QLCNIC_SWITCH_ENABLE BIT_1
+#define QLCNIC_SWITCH_VLAN_FILTERING BIT_2
+#define QLCNIC_SWITCH_PROMISC_MODE BIT_3
+#define QLCNIC_SWITCH_PORT_MIRRORING BIT_4
+};
+
+
+/* Return codes for Error handling */
+#define QL_STATUS_INVALID_PARAM -1
+
+#define MAX_BW 100
+#define MIN_BW 1
+#define MAX_VLAN_ID 4095
+#define MIN_VLAN_ID 2
+#define MAX_TX_QUEUES 1
+#define MAX_RX_QUEUES 4
+#define DEFAULT_MAC_LEARN 1
+
+#define IS_VALID_VLAN(vlan) (vlan >= MIN_VLAN_ID && vlan <= MAX_VLAN_ID)
+#define IS_VALID_BW(bw) (bw >= MIN_BW && bw <= MAX_BW)
+#define IS_VALID_TX_QUEUES(que) (que > 0 && que <= MAX_TX_QUEUES)
+#define IS_VALID_RX_QUEUES(que) (que > 0 && que <= MAX_RX_QUEUES)
+#define IS_VALID_MODE(mode) (mode == 0 || mode == 1)
+
+struct qlcnic_pci_func_cfg {
+ u16 func_type;
+ u16 min_bw;
+ u16 max_bw;
+ u16 port_num;
+ u8 pci_func;
+ u8 func_state;
+ u8 def_mac_addr[6];
+};
+
+struct qlcnic_npar_func_cfg {
+ u32 fw_capab;
+ u16 port_num;
+ u16 min_bw;
+ u16 max_bw;
+ u16 max_tx_queues;
+ u16 max_rx_queues;
+ u8 pci_func;
+ u8 op_mode;
+};
+
+struct qlcnic_pm_func_cfg {
+ u8 pci_func;
+ u8 action;
+ u8 dest_npar;
+ u8 reserved[5];
+};
+
+struct qlcnic_esw_func_cfg {
+ u16 vlan_id;
+ u8 pci_func;
+ u8 host_vlan_tag;
+ u8 promisc_mode;
+ u8 discard_tagged;
+ u8 mac_learning;
+ u8 reserved;
+};
+
int qlcnic_fw_cmd_query_phy(struct qlcnic_adapter *adapter, u32 reg, u32 *val);
int qlcnic_fw_cmd_set_phy(struct qlcnic_adapter *adapter, u32 reg, u32 val);
@@ -1031,13 +1173,13 @@ int qlcnic_wol_supported(struct qlcnic_adapter *adapter);
int qlcnic_config_led(struct qlcnic_adapter *adapter, u32 state, u32 rate);
/* Functions from qlcnic_init.c */
-int qlcnic_phantom_init(struct qlcnic_adapter *adapter);
int qlcnic_load_firmware(struct qlcnic_adapter *adapter);
int qlcnic_need_fw_reset(struct qlcnic_adapter *adapter);
void qlcnic_request_firmware(struct qlcnic_adapter *adapter);
void qlcnic_release_firmware(struct qlcnic_adapter *adapter);
int qlcnic_pinit_from_rom(struct qlcnic_adapter *adapter);
int qlcnic_setup_idc_param(struct qlcnic_adapter *adapter);
+int qlcnic_check_flash_fw_ver(struct qlcnic_adapter *adapter);
int qlcnic_rom_fast_read(struct qlcnic_adapter *adapter, int addr, int *valp);
int qlcnic_rom_fast_read_words(struct qlcnic_adapter *adapter, int addr,
@@ -1050,6 +1192,10 @@ void __iomem *qlcnic_get_ioaddr(struct qlcnic_adapter *, u32);
int qlcnic_alloc_hw_resources(struct qlcnic_adapter *adapter);
void qlcnic_free_hw_resources(struct qlcnic_adapter *adapter);
+int qlcnic_fw_create_ctx(struct qlcnic_adapter *adapter);
+void qlcnic_fw_destroy_ctx(struct qlcnic_adapter *adapter);
+
+void qlcnic_reset_rx_buffers_list(struct qlcnic_adapter *adapter);
void qlcnic_release_rx_buffers(struct qlcnic_adapter *adapter);
void qlcnic_release_tx_buffers(struct qlcnic_adapter *adapter);
@@ -1070,13 +1216,14 @@ void qlcnic_advert_link_change(struct qlcnic_adapter *adapter, int linkup);
int qlcnic_fw_cmd_set_mtu(struct qlcnic_adapter *adapter, int mtu);
int qlcnic_change_mtu(struct net_device *netdev, int new_mtu);
int qlcnic_config_hw_lro(struct qlcnic_adapter *adapter, int enable);
-int qlcnic_config_bridged_mode(struct qlcnic_adapter *adapter, int enable);
+int qlcnic_config_bridged_mode(struct qlcnic_adapter *adapter, u32 enable);
int qlcnic_send_lro_cleanup(struct qlcnic_adapter *adapter);
void qlcnic_update_cmd_producer(struct qlcnic_adapter *adapter,
struct qlcnic_host_tx_ring *tx_ring);
-int qlcnic_get_mac_addr(struct qlcnic_adapter *adapter, u64 *mac);
+int qlcnic_get_mac_addr(struct qlcnic_adapter *adapter, u8 *mac);
void qlcnic_clear_ilb_mode(struct qlcnic_adapter *adapter);
int qlcnic_set_ilb_mode(struct qlcnic_adapter *adapter);
+void qlcnic_fetch_mac(struct qlcnic_adapter *, u32, u32, u8, u8 *);
/* Functions from qlcnic_main.c */
int qlcnic_reset_context(struct qlcnic_adapter *);
@@ -1088,6 +1235,25 @@ int qlcnic_check_loopback_buff(unsigned char *data);
netdev_tx_t qlcnic_xmit_frame(struct sk_buff *skb, struct net_device *netdev);
void qlcnic_process_rcv_ring_diag(struct qlcnic_host_sds_ring *sds_ring);
+/* Management functions */
+int qlcnic_set_mac_address(struct qlcnic_adapter *, u8*);
+int qlcnic_get_mac_address(struct qlcnic_adapter *, u8*);
+int qlcnic_get_nic_info(struct qlcnic_adapter *, struct qlcnic_info *, u8);
+int qlcnic_set_nic_info(struct qlcnic_adapter *, struct qlcnic_info *);
+int qlcnic_get_pci_info(struct qlcnic_adapter *, struct qlcnic_pci_info*);
+int qlcnic_reset_partition(struct qlcnic_adapter *, u8);
+
+/* eSwitch management functions */
+int qlcnic_get_eswitch_capabilities(struct qlcnic_adapter *, u8,
+ struct qlcnic_eswitch *);
+int qlcnic_get_eswitch_status(struct qlcnic_adapter *, u8,
+ struct qlcnic_eswitch *);
+int qlcnic_toggle_eswitch(struct qlcnic_adapter *, u8, u8);
+int qlcnic_config_switch_port(struct qlcnic_adapter *, u8, int, u8, u8,
+ u8, u8, u16);
+int qlcnic_config_port_mirroring(struct qlcnic_adapter *, u8, u8, u8);
+extern int qlcnic_config_tso;
+
/*
* QLOGIC Board information
*/
@@ -1131,6 +1297,13 @@ static inline u32 qlcnic_tx_avail(struct qlcnic_host_tx_ring *tx_ring)
extern const struct ethtool_ops qlcnic_ethtool_ops;
+struct qlcnic_nic_template {
+ int (*get_mac_addr) (struct qlcnic_adapter *, u8*);
+ int (*config_bridged_mode) (struct qlcnic_adapter *, u32);
+ int (*config_led) (struct qlcnic_adapter *, u32, u32);
+ int (*start_firmware) (struct qlcnic_adapter *);
+};
+
#define QLCDB(adapter, lvl, _fmt, _args...) do { \
if (NETIF_MSG_##lvl & adapter->msg_enable) \
printk(KERN_INFO "%s: %s: " _fmt, \
diff --git a/drivers/net/qlcnic/qlcnic_ctx.c b/drivers/net/qlcnic/qlcnic_ctx.c
index c2c1f5cc16c..cc5d861d9a1 100644
--- a/drivers/net/qlcnic/qlcnic_ctx.c
+++ b/drivers/net/qlcnic/qlcnic_ctx.c
@@ -88,12 +88,12 @@ qlcnic_fw_cmd_set_mtu(struct qlcnic_adapter *adapter, int mtu)
if (recv_ctx->state == QLCNIC_HOST_CTX_STATE_ACTIVE) {
if (qlcnic_issue_cmd(adapter,
- adapter->ahw.pci_func,
- QLCHAL_VERSION,
- recv_ctx->context_id,
- mtu,
- 0,
- QLCNIC_CDRP_CMD_SET_MTU)) {
+ adapter->ahw.pci_func,
+ adapter->fw_hal_version,
+ recv_ctx->context_id,
+ mtu,
+ 0,
+ QLCNIC_CDRP_CMD_SET_MTU)) {
dev_err(&adapter->pdev->dev, "Failed to set mtu\n");
return -EIO;
@@ -121,7 +121,7 @@ qlcnic_fw_cmd_create_rx_ctx(struct qlcnic_adapter *adapter)
int i, nrds_rings, nsds_rings;
size_t rq_size, rsp_size;
- u32 cap, reg, val;
+ u32 cap, reg, val, reg2;
int err;
struct qlcnic_recv_context *recv_ctx = &adapter->recv_ctx;
@@ -152,9 +152,14 @@ qlcnic_fw_cmd_create_rx_ctx(struct qlcnic_adapter *adapter)
prq->host_rsp_dma_addr = cpu_to_le64(cardrsp_phys_addr);
- cap = (QLCNIC_CAP0_LEGACY_CONTEXT | QLCNIC_CAP0_LEGACY_MN);
+ cap = (QLCNIC_CAP0_LEGACY_CONTEXT | QLCNIC_CAP0_LEGACY_MN
+ | QLCNIC_CAP0_VALIDOFF);
cap |= (QLCNIC_CAP0_JUMBO_CONTIGUOUS | QLCNIC_CAP0_LRO_CONTIGUOUS);
+ prq->valid_field_offset = offsetof(struct qlcnic_hostrq_rx_ctx,
+ msix_handler);
+ prq->txrx_sds_binding = nsds_rings - 1;
+
prq->capabilities[0] = cpu_to_le32(cap);
prq->host_int_crb_mode =
cpu_to_le32(QLCNIC_HOST_INT_CRB_MODE_SHARED);
@@ -175,6 +180,7 @@ qlcnic_fw_cmd_create_rx_ctx(struct qlcnic_adapter *adapter)
for (i = 0; i < nrds_rings; i++) {
rds_ring = &recv_ctx->rds_rings[i];
+ rds_ring->producer = 0;
prq_rds[i].host_phys_addr = cpu_to_le64(rds_ring->phys_addr);
prq_rds[i].ring_size = cpu_to_le32(rds_ring->num_desc);
@@ -188,6 +194,8 @@ qlcnic_fw_cmd_create_rx_ctx(struct qlcnic_adapter *adapter)
for (i = 0; i < nsds_rings; i++) {
sds_ring = &recv_ctx->sds_rings[i];
+ sds_ring->consumer = 0;
+ memset(sds_ring->desc_head, 0, STATUS_DESC_RINGSIZE(sds_ring));
prq_sds[i].host_phys_addr = cpu_to_le64(sds_ring->phys_addr);
prq_sds[i].ring_size = cpu_to_le32(sds_ring->num_desc);
@@ -197,7 +205,7 @@ qlcnic_fw_cmd_create_rx_ctx(struct qlcnic_adapter *adapter)
phys_addr = hostrq_phys_addr;
err = qlcnic_issue_cmd(adapter,
adapter->ahw.pci_func,
- QLCHAL_VERSION,
+ adapter->fw_hal_version,
(u32)(phys_addr >> 32),
(u32)(phys_addr & 0xffffffff),
rq_size,
@@ -216,8 +224,7 @@ qlcnic_fw_cmd_create_rx_ctx(struct qlcnic_adapter *adapter)
rds_ring = &recv_ctx->rds_rings[i];
reg = le32_to_cpu(prsp_rds[i].host_producer_crb);
- rds_ring->crb_rcv_producer = qlcnic_get_ioaddr(adapter,
- QLCNIC_REG(reg - 0x200));
+ rds_ring->crb_rcv_producer = adapter->ahw.pci_base0 + reg;
}
prsp_sds = ((struct qlcnic_cardrsp_sds_ring *)
@@ -227,12 +234,10 @@ qlcnic_fw_cmd_create_rx_ctx(struct qlcnic_adapter *adapter)
sds_ring = &recv_ctx->sds_rings[i];
reg = le32_to_cpu(prsp_sds[i].host_consumer_crb);
- sds_ring->crb_sts_consumer = qlcnic_get_ioaddr(adapter,
- QLCNIC_REG(reg - 0x200));
+ reg2 = le32_to_cpu(prsp_sds[i].interrupt_crb);
- reg = le32_to_cpu(prsp_sds[i].interrupt_crb);
- sds_ring->crb_intr_mask = qlcnic_get_ioaddr(adapter,
- QLCNIC_REG(reg - 0x200));
+ sds_ring->crb_sts_consumer = adapter->ahw.pci_base0 + reg;
+ sds_ring->crb_intr_mask = adapter->ahw.pci_base0 + reg2;
}
recv_ctx->state = le32_to_cpu(prsp->host_ctx_state);
@@ -253,7 +258,7 @@ qlcnic_fw_cmd_destroy_rx_ctx(struct qlcnic_adapter *adapter)
if (qlcnic_issue_cmd(adapter,
adapter->ahw.pci_func,
- QLCHAL_VERSION,
+ adapter->fw_hal_version,
recv_ctx->context_id,
QLCNIC_DESTROY_CTX_RESET,
0,
@@ -262,6 +267,8 @@ qlcnic_fw_cmd_destroy_rx_ctx(struct qlcnic_adapter *adapter)
dev_err(&adapter->pdev->dev,
"Failed to destroy rx ctx in firmware\n");
}
+
+ recv_ctx->state = QLCNIC_HOST_CTX_STATE_FREED;
}
static int
@@ -278,6 +285,11 @@ qlcnic_fw_cmd_create_tx_ctx(struct qlcnic_adapter *adapter)
dma_addr_t rq_phys_addr, rsp_phys_addr;
struct qlcnic_host_tx_ring *tx_ring = adapter->tx_ring;
+ /* reset host resources */
+ tx_ring->producer = 0;
+ tx_ring->sw_consumer = 0;
+ *(tx_ring->hw_consumer) = 0;
+
rq_size = SIZEOF_HOSTRQ_TX(struct qlcnic_hostrq_tx_ctx);
rq_addr = pci_alloc_consistent(adapter->pdev,
rq_size, &rq_phys_addr);
@@ -319,7 +331,7 @@ qlcnic_fw_cmd_create_tx_ctx(struct qlcnic_adapter *adapter)
phys_addr = rq_phys_addr;
err = qlcnic_issue_cmd(adapter,
adapter->ahw.pci_func,
- QLCHAL_VERSION,
+ adapter->fw_hal_version,
(u32)(phys_addr >> 32),
((u32)phys_addr & 0xffffffff),
rq_size,
@@ -327,8 +339,7 @@ qlcnic_fw_cmd_create_tx_ctx(struct qlcnic_adapter *adapter)
if (err == QLCNIC_RCODE_SUCCESS) {
temp = le32_to_cpu(prsp->cds_ring.host_producer_crb);
- tx_ring->crb_cmd_producer = qlcnic_get_ioaddr(adapter,
- QLCNIC_REG(temp - 0x200));
+ tx_ring->crb_cmd_producer = adapter->ahw.pci_base0 + temp;
adapter->tx_context_id =
le16_to_cpu(prsp->context_id);
@@ -351,7 +362,7 @@ qlcnic_fw_cmd_destroy_tx_ctx(struct qlcnic_adapter *adapter)
{
if (qlcnic_issue_cmd(adapter,
adapter->ahw.pci_func,
- QLCHAL_VERSION,
+ adapter->fw_hal_version,
adapter->tx_context_id,
QLCNIC_DESTROY_CTX_RESET,
0,
@@ -368,7 +379,7 @@ qlcnic_fw_cmd_query_phy(struct qlcnic_adapter *adapter, u32 reg, u32 *val)
if (qlcnic_issue_cmd(adapter,
adapter->ahw.pci_func,
- QLCHAL_VERSION,
+ adapter->fw_hal_version,
reg,
0,
0,
@@ -385,7 +396,7 @@ qlcnic_fw_cmd_set_phy(struct qlcnic_adapter *adapter, u32 reg, u32 val)
{
return qlcnic_issue_cmd(adapter,
adapter->ahw.pci_func,
- QLCHAL_VERSION,
+ adapter->fw_hal_version,
reg,
val,
0,
@@ -457,15 +468,6 @@ int qlcnic_alloc_hw_resources(struct qlcnic_adapter *adapter)
sds_ring->desc_head = (struct status_desc *)addr;
}
-
- err = qlcnic_fw_cmd_create_rx_ctx(adapter);
- if (err)
- goto err_out_free;
- err = qlcnic_fw_cmd_create_tx_ctx(adapter);
- if (err)
- goto err_out_free;
-
- set_bit(__QLCNIC_FW_ATTACHED, &adapter->state);
return 0;
err_out_free:
@@ -473,15 +475,27 @@ err_out_free:
return err;
}
-void qlcnic_free_hw_resources(struct qlcnic_adapter *adapter)
+
+int qlcnic_fw_create_ctx(struct qlcnic_adapter *adapter)
{
- struct qlcnic_recv_context *recv_ctx;
- struct qlcnic_host_rds_ring *rds_ring;
- struct qlcnic_host_sds_ring *sds_ring;
- struct qlcnic_host_tx_ring *tx_ring;
- int ring;
+ int err;
+ err = qlcnic_fw_cmd_create_rx_ctx(adapter);
+ if (err)
+ return err;
+ err = qlcnic_fw_cmd_create_tx_ctx(adapter);
+ if (err) {
+ qlcnic_fw_cmd_destroy_rx_ctx(adapter);
+ return err;
+ }
+
+ set_bit(__QLCNIC_FW_ATTACHED, &adapter->state);
+ return 0;
+}
+
+void qlcnic_fw_destroy_ctx(struct qlcnic_adapter *adapter)
+{
if (test_and_clear_bit(__QLCNIC_FW_ATTACHED, &adapter->state)) {
qlcnic_fw_cmd_destroy_rx_ctx(adapter);
qlcnic_fw_cmd_destroy_tx_ctx(adapter);
@@ -489,6 +503,15 @@ void qlcnic_free_hw_resources(struct qlcnic_adapter *adapter)
/* Allow dma queues to drain after context reset */
msleep(20);
}
+}
+
+void qlcnic_free_hw_resources(struct qlcnic_adapter *adapter)
+{
+ struct qlcnic_recv_context *recv_ctx;
+ struct qlcnic_host_rds_ring *rds_ring;
+ struct qlcnic_host_sds_ring *sds_ring;
+ struct qlcnic_host_tx_ring *tx_ring;
+ int ring;
recv_ctx = &adapter->recv_ctx;
@@ -533,3 +556,430 @@ void qlcnic_free_hw_resources(struct qlcnic_adapter *adapter)
}
}
+/* Set MAC address of a NIC partition */
+int qlcnic_set_mac_address(struct qlcnic_adapter *adapter, u8* mac)
+{
+ int err = 0;
+ u32 arg1, arg2, arg3;
+
+ arg1 = adapter->ahw.pci_func | BIT_9;
+ arg2 = mac[0] | (mac[1] << 8) | (mac[2] << 16) | (mac[3] << 24);
+ arg3 = mac[4] | (mac[5] << 16);
+
+ err = qlcnic_issue_cmd(adapter,
+ adapter->ahw.pci_func,
+ adapter->fw_hal_version,
+ arg1,
+ arg2,
+ arg3,
+ QLCNIC_CDRP_CMD_MAC_ADDRESS);
+
+ if (err != QLCNIC_RCODE_SUCCESS) {
+ dev_err(&adapter->pdev->dev,
+ "Failed to set mac address%d\n", err);
+ err = -EIO;
+ }
+
+ return err;
+}
+
+/* Get MAC address of a NIC partition */
+int qlcnic_get_mac_address(struct qlcnic_adapter *adapter, u8 *mac)
+{
+ int err;
+ u32 arg1;
+
+ arg1 = adapter->ahw.pci_func | BIT_8;
+ err = qlcnic_issue_cmd(adapter,
+ adapter->ahw.pci_func,
+ adapter->fw_hal_version,
+ arg1,
+ 0,
+ 0,
+ QLCNIC_CDRP_CMD_MAC_ADDRESS);
+
+ if (err == QLCNIC_RCODE_SUCCESS)
+ qlcnic_fetch_mac(adapter, QLCNIC_ARG1_CRB_OFFSET,
+ QLCNIC_ARG2_CRB_OFFSET, 0, mac);
+ else {
+ dev_err(&adapter->pdev->dev,
+ "Failed to get mac address%d\n", err);
+ err = -EIO;
+ }
+
+ return err;
+}
+
+/* Get info of a NIC partition */
+int qlcnic_get_nic_info(struct qlcnic_adapter *adapter,
+ struct qlcnic_info *npar_info, u8 func_id)
+{
+ int err;
+ dma_addr_t nic_dma_t;
+ struct qlcnic_info *nic_info;
+ void *nic_info_addr;
+ size_t nic_size = sizeof(struct qlcnic_info);
+
+ nic_info_addr = pci_alloc_consistent(adapter->pdev,
+ nic_size, &nic_dma_t);
+ if (!nic_info_addr)
+ return -ENOMEM;
+ memset(nic_info_addr, 0, nic_size);
+
+ nic_info = (struct qlcnic_info *) nic_info_addr;
+ err = qlcnic_issue_cmd(adapter,
+ adapter->ahw.pci_func,
+ adapter->fw_hal_version,
+ MSD(nic_dma_t),
+ LSD(nic_dma_t),
+ (func_id << 16 | nic_size),
+ QLCNIC_CDRP_CMD_GET_NIC_INFO);
+
+ if (err == QLCNIC_RCODE_SUCCESS) {
+ npar_info->pci_func = le16_to_cpu(nic_info->pci_func);
+ npar_info->op_mode = le16_to_cpu(nic_info->op_mode);
+ npar_info->phys_port = le16_to_cpu(nic_info->phys_port);
+ npar_info->switch_mode = le16_to_cpu(nic_info->switch_mode);
+ npar_info->max_tx_ques = le16_to_cpu(nic_info->max_tx_ques);
+ npar_info->max_rx_ques = le16_to_cpu(nic_info->max_rx_ques);
+ npar_info->min_tx_bw = le16_to_cpu(nic_info->min_tx_bw);
+ npar_info->max_tx_bw = le16_to_cpu(nic_info->max_tx_bw);
+ npar_info->capabilities = le32_to_cpu(nic_info->capabilities);
+ npar_info->max_mtu = le16_to_cpu(nic_info->max_mtu);
+
+ dev_info(&adapter->pdev->dev,
+ "phy port: %d switch_mode: %d,\n"
+ "\tmax_tx_q: %d max_rx_q: %d min_tx_bw: 0x%x,\n"
+ "\tmax_tx_bw: 0x%x max_mtu:0x%x, capabilities: 0x%x\n",
+ npar_info->phys_port, npar_info->switch_mode,
+ npar_info->max_tx_ques, npar_info->max_rx_ques,
+ npar_info->min_tx_bw, npar_info->max_tx_bw,
+ npar_info->max_mtu, npar_info->capabilities);
+ } else {
+ dev_err(&adapter->pdev->dev,
+ "Failed to get nic info%d\n", err);
+ err = -EIO;
+ }
+
+ pci_free_consistent(adapter->pdev, nic_size, nic_info_addr, nic_dma_t);
+ return err;
+}
+
+/* Configure a NIC partition */
+int qlcnic_set_nic_info(struct qlcnic_adapter *adapter, struct qlcnic_info *nic)
+{
+ int err = -EIO;
+ dma_addr_t nic_dma_t;
+ void *nic_info_addr;
+ struct qlcnic_info *nic_info;
+ size_t nic_size = sizeof(struct qlcnic_info);
+
+ if (adapter->op_mode != QLCNIC_MGMT_FUNC)
+ return err;
+
+ nic_info_addr = pci_alloc_consistent(adapter->pdev, nic_size,
+ &nic_dma_t);
+ if (!nic_info_addr)
+ return -ENOMEM;
+
+ memset(nic_info_addr, 0, nic_size);
+ nic_info = (struct qlcnic_info *)nic_info_addr;
+
+ nic_info->pci_func = cpu_to_le16(nic->pci_func);
+ nic_info->op_mode = cpu_to_le16(nic->op_mode);
+ nic_info->phys_port = cpu_to_le16(nic->phys_port);
+ nic_info->switch_mode = cpu_to_le16(nic->switch_mode);
+ nic_info->capabilities = cpu_to_le32(nic->capabilities);
+ nic_info->max_mac_filters = nic->max_mac_filters;
+ nic_info->max_tx_ques = cpu_to_le16(nic->max_tx_ques);
+ nic_info->max_rx_ques = cpu_to_le16(nic->max_rx_ques);
+ nic_info->min_tx_bw = cpu_to_le16(nic->min_tx_bw);
+ nic_info->max_tx_bw = cpu_to_le16(nic->max_tx_bw);
+
+ err = qlcnic_issue_cmd(adapter,
+ adapter->ahw.pci_func,
+ adapter->fw_hal_version,
+ MSD(nic_dma_t),
+ LSD(nic_dma_t),
+ ((nic->pci_func << 16) | nic_size),
+ QLCNIC_CDRP_CMD_SET_NIC_INFO);
+
+ if (err != QLCNIC_RCODE_SUCCESS) {
+ dev_err(&adapter->pdev->dev,
+ "Failed to set nic info%d\n", err);
+ err = -EIO;
+ }
+
+ pci_free_consistent(adapter->pdev, nic_size, nic_info_addr, nic_dma_t);
+ return err;
+}
+
+/* Get PCI Info of a partition */
+int qlcnic_get_pci_info(struct qlcnic_adapter *adapter,
+ struct qlcnic_pci_info *pci_info)
+{
+ int err = 0, i;
+ dma_addr_t pci_info_dma_t;
+ struct qlcnic_pci_info *npar;
+ void *pci_info_addr;
+ size_t npar_size = sizeof(struct qlcnic_pci_info);
+ size_t pci_size = npar_size * QLCNIC_MAX_PCI_FUNC;
+
+ pci_info_addr = pci_alloc_consistent(adapter->pdev, pci_size,
+ &pci_info_dma_t);
+ if (!pci_info_addr)
+ return -ENOMEM;
+ memset(pci_info_addr, 0, pci_size);
+
+ npar = (struct qlcnic_pci_info *) pci_info_addr;
+ err = qlcnic_issue_cmd(adapter,
+ adapter->ahw.pci_func,
+ adapter->fw_hal_version,
+ MSD(pci_info_dma_t),
+ LSD(pci_info_dma_t),
+ pci_size,
+ QLCNIC_CDRP_CMD_GET_PCI_INFO);
+
+ if (err == QLCNIC_RCODE_SUCCESS) {
+ for (i = 0; i < QLCNIC_MAX_PCI_FUNC; i++, npar++, pci_info++) {
+ pci_info->id = le32_to_cpu(npar->id);
+ pci_info->active = le32_to_cpu(npar->active);
+ pci_info->type = le32_to_cpu(npar->type);
+ pci_info->default_port =
+ le32_to_cpu(npar->default_port);
+ pci_info->tx_min_bw =
+ le32_to_cpu(npar->tx_min_bw);
+ pci_info->tx_max_bw =
+ le32_to_cpu(npar->tx_max_bw);
+ memcpy(pci_info->mac, npar->mac, ETH_ALEN);
+ }
+ } else {
+ dev_err(&adapter->pdev->dev,
+ "Failed to get PCI Info%d\n", err);
+ err = -EIO;
+ }
+
+ pci_free_consistent(adapter->pdev, pci_size, pci_info_addr,
+ pci_info_dma_t);
+ return err;
+}
+
+/* Reset a NIC partition */
+
+int qlcnic_reset_partition(struct qlcnic_adapter *adapter, u8 func_no)
+{
+ int err = -EIO;
+
+ if (adapter->op_mode != QLCNIC_MGMT_FUNC)
+ return err;
+
+ err = qlcnic_issue_cmd(adapter,
+ adapter->ahw.pci_func,
+ adapter->fw_hal_version,
+ func_no,
+ 0,
+ 0,
+ QLCNIC_CDRP_CMD_RESET_NPAR);
+
+ if (err != QLCNIC_RCODE_SUCCESS) {
+ dev_err(&adapter->pdev->dev,
+ "Failed to issue reset partition%d\n", err);
+ err = -EIO;
+ }
+
+ return err;
+}
+
+/* Get eSwitch Capabilities */
+int qlcnic_get_eswitch_capabilities(struct qlcnic_adapter *adapter, u8 port,
+ struct qlcnic_eswitch *eswitch)
+{
+ int err = -EIO;
+ u32 arg1, arg2;
+
+ if (adapter->op_mode == QLCNIC_NON_PRIV_FUNC)
+ return err;
+
+ err = qlcnic_issue_cmd(adapter,
+ adapter->ahw.pci_func,
+ adapter->fw_hal_version,
+ port,
+ 0,
+ 0,
+ QLCNIC_CDRP_CMD_GET_ESWITCH_CAPABILITY);
+
+ if (err == QLCNIC_RCODE_SUCCESS) {
+ arg1 = QLCRD32(adapter, QLCNIC_ARG1_CRB_OFFSET);
+ arg2 = QLCRD32(adapter, QLCNIC_ARG2_CRB_OFFSET);
+
+ eswitch->port = arg1 & 0xf;
+ eswitch->active_vports = LSB(arg2);
+ eswitch->max_ucast_filters = MSB(arg2);
+ eswitch->max_active_vlans = LSB(MSW(arg2));
+ if (arg1 & BIT_6)
+ eswitch->flags |= QLCNIC_SWITCH_VLAN_FILTERING;
+ if (arg1 & BIT_7)
+ eswitch->flags |= QLCNIC_SWITCH_PROMISC_MODE;
+ if (arg1 & BIT_8)
+ eswitch->flags |= QLCNIC_SWITCH_PORT_MIRRORING;
+ } else {
+ dev_err(&adapter->pdev->dev,
+ "Failed to get eswitch capabilities%d\n", err);
+ }
+
+ return err;
+}
+
+/* Get current status of eswitch */
+int qlcnic_get_eswitch_status(struct qlcnic_adapter *adapter, u8 port,
+ struct qlcnic_eswitch *eswitch)
+{
+ int err = -EIO;
+ u32 arg1, arg2;
+
+ if (adapter->op_mode != QLCNIC_MGMT_FUNC)
+ return err;
+
+ err = qlcnic_issue_cmd(adapter,
+ adapter->ahw.pci_func,
+ adapter->fw_hal_version,
+ port,
+ 0,
+ 0,
+ QLCNIC_CDRP_CMD_GET_ESWITCH_STATUS);
+
+ if (err == QLCNIC_RCODE_SUCCESS) {
+ arg1 = QLCRD32(adapter, QLCNIC_ARG1_CRB_OFFSET);
+ arg2 = QLCRD32(adapter, QLCNIC_ARG2_CRB_OFFSET);
+
+ eswitch->port = arg1 & 0xf;
+ eswitch->active_vports = LSB(arg2);
+ eswitch->active_ucast_filters = MSB(arg2);
+ eswitch->active_vlans = LSB(MSW(arg2));
+ if (arg1 & BIT_6)
+ eswitch->flags |= QLCNIC_SWITCH_VLAN_FILTERING;
+ if (arg1 & BIT_8)
+ eswitch->flags |= QLCNIC_SWITCH_PORT_MIRRORING;
+
+ } else {
+ dev_err(&adapter->pdev->dev,
+ "Failed to get eswitch status%d\n", err);
+ }
+
+ return err;
+}
+
+/* Enable/Disable eSwitch */
+int qlcnic_toggle_eswitch(struct qlcnic_adapter *adapter, u8 id, u8 enable)
+{
+ int err = -EIO;
+ u32 arg1, arg2;
+ struct qlcnic_eswitch *eswitch;
+
+ if (adapter->op_mode != QLCNIC_MGMT_FUNC)
+ return err;
+
+ eswitch = &adapter->eswitch[id];
+ if (!eswitch)
+ return err;
+
+ arg1 = eswitch->port | (enable ? BIT_4 : 0);
+ arg2 = eswitch->active_vports | (eswitch->max_ucast_filters << 8) |
+ (eswitch->max_active_vlans << 16);
+ err = qlcnic_issue_cmd(adapter,
+ adapter->ahw.pci_func,
+ adapter->fw_hal_version,
+ arg1,
+ arg2,
+ 0,
+ QLCNIC_CDRP_CMD_TOGGLE_ESWITCH);
+
+ if (err != QLCNIC_RCODE_SUCCESS) {
+ dev_err(&adapter->pdev->dev,
+ "Failed to enable eswitch%d\n", eswitch->port);
+ eswitch->flags &= ~QLCNIC_SWITCH_ENABLE;
+ err = -EIO;
+ } else {
+ eswitch->flags |= QLCNIC_SWITCH_ENABLE;
+ dev_info(&adapter->pdev->dev,
+ "Enabled eSwitch for port %d\n", eswitch->port);
+ }
+
+ return err;
+}
+
+/* Configure eSwitch for port mirroring */
+int qlcnic_config_port_mirroring(struct qlcnic_adapter *adapter, u8 id,
+ u8 enable_mirroring, u8 pci_func)
+{
+ int err = -EIO;
+ u32 arg1;
+
+ if (adapter->op_mode != QLCNIC_MGMT_FUNC ||
+ !(adapter->eswitch[id].flags & QLCNIC_SWITCH_ENABLE))
+ return err;
+
+ arg1 = id | (enable_mirroring ? BIT_4 : 0);
+ arg1 |= pci_func << 8;
+
+ err = qlcnic_issue_cmd(adapter,
+ adapter->ahw.pci_func,
+ adapter->fw_hal_version,
+ arg1,
+ 0,
+ 0,
+ QLCNIC_CDRP_CMD_SET_PORTMIRRORING);
+
+ if (err != QLCNIC_RCODE_SUCCESS) {
+ dev_err(&adapter->pdev->dev,
+ "Failed to configure port mirroring%d on eswitch:%d\n",
+ pci_func, id);
+ } else {
+ dev_info(&adapter->pdev->dev,
+ "Configured eSwitch %d for port mirroring:%d\n",
+ id, pci_func);
+ }
+
+ return err;
+}
+
+/* Configure eSwitch port */
+int qlcnic_config_switch_port(struct qlcnic_adapter *adapter, u8 id,
+ int vlan_tagging, u8 discard_tagged, u8 promsc_mode,
+ u8 mac_learn, u8 pci_func, u16 vlan_id)
+{
+ int err = -EIO;
+ u32 arg1;
+ struct qlcnic_eswitch *eswitch;
+
+ if (adapter->op_mode != QLCNIC_MGMT_FUNC)
+ return err;
+
+ eswitch = &adapter->eswitch[id];
+ if (!(eswitch->flags & QLCNIC_SWITCH_ENABLE))
+ return err;
+
+ arg1 = eswitch->port | (discard_tagged ? BIT_4 : 0);
+ arg1 |= (promsc_mode ? BIT_6 : 0) | (mac_learn ? BIT_7 : 0);
+ arg1 |= pci_func << 8;
+ if (vlan_tagging)
+ arg1 |= BIT_5 | (vlan_id << 16);
+
+ err = qlcnic_issue_cmd(adapter,
+ adapter->ahw.pci_func,
+ adapter->fw_hal_version,
+ arg1,
+ 0,
+ 0,
+ QLCNIC_CDRP_CMD_CONFIGURE_ESWITCH);
+
+ if (err != QLCNIC_RCODE_SUCCESS) {
+ dev_err(&adapter->pdev->dev,
+ "Failed to configure eswitch port%d\n", eswitch->port);
+ } else {
+ dev_info(&adapter->pdev->dev,
+ "Configured eSwitch for port %d\n", eswitch->port);
+ }
+
+ return err;
+}
diff --git a/drivers/net/qlcnic/qlcnic_ethtool.c b/drivers/net/qlcnic/qlcnic_ethtool.c
index 3bd514ec7e8..9328d59e21e 100644
--- a/drivers/net/qlcnic/qlcnic_ethtool.c
+++ b/drivers/net/qlcnic/qlcnic_ethtool.c
@@ -69,8 +69,6 @@ static const struct qlcnic_stats qlcnic_gstrings_stats[] = {
QLC_SIZEOF(stats.xmit_off), QLC_OFF(stats.xmit_off)},
{"skb_alloc_failure", QLC_SIZEOF(stats.skb_alloc_failure),
QLC_OFF(stats.skb_alloc_failure)},
- {"null skb",
- QLC_SIZEOF(stats.null_skb), QLC_OFF(stats.null_skb)},
{"null rxbuf",
QLC_SIZEOF(stats.null_rxbuf), QLC_OFF(stats.null_rxbuf)},
{"rx dma map error", QLC_SIZEOF(stats.rx_dma_map_error),
@@ -350,7 +348,7 @@ qlcnic_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *p)
for (i = 0; diag_registers[i] != -1; i++)
regs_buff[i] = QLCRD32(adapter, diag_registers[i]);
- if (adapter->is_up != QLCNIC_ADAPTER_UP_MAGIC)
+ if (!test_bit(__QLCNIC_DEV_UP, &adapter->state))
return;
regs_buff[i++] = 0xFFEFCDAB; /* Marker btw regs and ring count*/
@@ -580,8 +578,12 @@ qlcnic_set_pauseparam(struct net_device *netdev,
}
QLCWR32(adapter, QLCNIC_NIU_GB_PAUSE_CTL, val);
} else if (adapter->ahw.port_type == QLCNIC_XGBE) {
+ if (!pause->rx_pause || pause->autoneg)
+ return -EOPNOTSUPP;
+
if ((port < 0) || (port > QLCNIC_NIU_MAX_XG_PORTS))
return -EIO;
+
val = QLCRD32(adapter, QLCNIC_NIU_XG_PAUSE_CTL);
if (port == 0) {
if (pause->tx_pause)
@@ -676,6 +678,12 @@ static int qlcnic_loopback_test(struct net_device *netdev)
int max_sds_rings = adapter->max_sds_rings;
int ret;
+ if (adapter->op_mode == QLCNIC_NON_PRIV_FUNC) {
+ dev_warn(&adapter->pdev->dev, "Loopback test not supported"
+ "for non privilege function\n");
+ return 0;
+ }
+
if (test_and_set_bit(__QLCNIC_RESETTING, &adapter->state))
return -EIO;
@@ -715,7 +723,8 @@ static int qlcnic_irq_test(struct net_device *netdev)
adapter->diag_cnt = 0;
ret = qlcnic_issue_cmd(adapter, adapter->ahw.pci_func,
- QLCHAL_VERSION, adapter->portnum, 0, 0, 0x00000011);
+ adapter->fw_hal_version, adapter->portnum,
+ 0, 0, 0x00000011);
if (ret)
goto done;
@@ -821,6 +830,9 @@ static u32 qlcnic_get_tso(struct net_device *dev)
static int qlcnic_set_tso(struct net_device *dev, u32 data)
{
+ struct qlcnic_adapter *adapter = netdev_priv(dev);
+ if (!(adapter->capabilities & QLCNIC_FW_CAPABILITY_TSO))
+ return -EOPNOTSUPP;
if (data)
dev->features |= (NETIF_F_TSO | NETIF_F_TSO6);
else
@@ -834,7 +846,10 @@ static int qlcnic_blink_led(struct net_device *dev, u32 val)
struct qlcnic_adapter *adapter = netdev_priv(dev);
int ret;
- ret = qlcnic_config_led(adapter, 1, 0xf);
+ if (!test_bit(__QLCNIC_DEV_UP, &adapter->state))
+ return -EIO;
+
+ ret = adapter->nic_ops->config_led(adapter, 1, 0xf);
if (ret) {
dev_err(&adapter->pdev->dev,
"Failed to set LED blink state.\n");
@@ -843,7 +858,7 @@ static int qlcnic_blink_led(struct net_device *dev, u32 val)
msleep_interruptible(val * 1000);
- ret = qlcnic_config_led(adapter, 0, 0xf);
+ ret = adapter->nic_ops->config_led(adapter, 0, 0xf);
if (ret) {
dev_err(&adapter->pdev->dev,
"Failed to reset LED blink state.\n");
@@ -905,7 +920,7 @@ static int qlcnic_set_intr_coalesce(struct net_device *netdev,
{
struct qlcnic_adapter *adapter = netdev_priv(netdev);
- if (adapter->is_up != QLCNIC_ADAPTER_UP_MAGIC)
+ if (!test_bit(__QLCNIC_DEV_UP, &adapter->state))
return -EINVAL;
/*
@@ -981,12 +996,19 @@ static int qlcnic_set_flags(struct net_device *netdev, u32 data)
struct qlcnic_adapter *adapter = netdev_priv(netdev);
int hw_lro;
- if (!(adapter->capabilities & QLCNIC_FW_CAPABILITY_HW_LRO))
+ if (data & ~ETH_FLAG_LRO)
return -EINVAL;
- ethtool_op_set_flags(netdev, data);
+ if (!(adapter->capabilities & QLCNIC_FW_CAPABILITY_HW_LRO))
+ return -EINVAL;
- hw_lro = (data & ETH_FLAG_LRO) ? QLCNIC_LRO_ENABLED : 0;
+ if (data & ETH_FLAG_LRO) {
+ hw_lro = QLCNIC_LRO_ENABLED;
+ netdev->features |= NETIF_F_LRO;
+ } else {
+ hw_lro = 0;
+ netdev->features &= ~NETIF_F_LRO;
+ }
if (qlcnic_config_hw_lro(adapter, hw_lro))
return -EIO;
diff --git a/drivers/net/qlcnic/qlcnic_hdr.h b/drivers/net/qlcnic/qlcnic_hdr.h
index ad9d167723c..15fc32070be 100644
--- a/drivers/net/qlcnic/qlcnic_hdr.h
+++ b/drivers/net/qlcnic/qlcnic_hdr.h
@@ -208,6 +208,39 @@ enum {
QLCNIC_HW_PX_MAP_CRB_PGR0
};
+#define BIT_0 0x1
+#define BIT_1 0x2
+#define BIT_2 0x4
+#define BIT_3 0x8
+#define BIT_4 0x10
+#define BIT_5 0x20
+#define BIT_6 0x40
+#define BIT_7 0x80
+#define BIT_8 0x100
+#define BIT_9 0x200
+#define BIT_10 0x400
+#define BIT_11 0x800
+#define BIT_12 0x1000
+#define BIT_13 0x2000
+#define BIT_14 0x4000
+#define BIT_15 0x8000
+#define BIT_16 0x10000
+#define BIT_17 0x20000
+#define BIT_18 0x40000
+#define BIT_19 0x80000
+#define BIT_20 0x100000
+#define BIT_21 0x200000
+#define BIT_22 0x400000
+#define BIT_23 0x800000
+#define BIT_24 0x1000000
+#define BIT_25 0x2000000
+#define BIT_26 0x4000000
+#define BIT_27 0x8000000
+#define BIT_28 0x10000000
+#define BIT_29 0x20000000
+#define BIT_30 0x40000000
+#define BIT_31 0x80000000
+
/* This field defines CRB adr [31:20] of the agents */
#define QLCNIC_HW_CRB_HUB_AGT_ADR_MN \
@@ -668,10 +701,11 @@ enum {
#define QLCNIC_CRB_DEV_REF_COUNT (QLCNIC_CAM_RAM(0x138))
#define QLCNIC_CRB_DEV_STATE (QLCNIC_CAM_RAM(0x140))
-#define QLCNIC_CRB_DRV_STATE (QLCNIC_CAM_RAM(0x144))
-#define QLCNIC_CRB_DRV_SCRATCH (QLCNIC_CAM_RAM(0x148))
-#define QLCNIC_CRB_DEV_PARTITION_INFO (QLCNIC_CAM_RAM(0x14c))
+#define QLCNIC_CRB_DRV_STATE (QLCNIC_CAM_RAM(0x144))
+#define QLCNIC_CRB_DRV_SCRATCH (QLCNIC_CAM_RAM(0x148))
+#define QLCNIC_CRB_DEV_PARTITION_INFO (QLCNIC_CAM_RAM(0x14c))
#define QLCNIC_CRB_DRV_IDC_VER (QLCNIC_CAM_RAM(0x174))
+#define QLCNIC_CRB_DEV_NPAR_STATE (QLCNIC_CAM_RAM(0x19c))
#define QLCNIC_ROM_DEV_INIT_TIMEOUT (0x3e885c)
#define QLCNIC_ROM_DRV_RESET_TIMEOUT (0x3e8860)
@@ -684,15 +718,26 @@ enum {
#define QLCNIC_DEV_FAILED 0x6
#define QLCNIC_DEV_QUISCENT 0x7
+#define QLCNIC_DEV_NPAR_NOT_RDY 0
+#define QLCNIC_DEV_NPAR_RDY 1
+
+#define QLC_DEV_CHECK_ACTIVE(VAL, FN) ((VAL) &= (1 << (FN * 4)))
#define QLC_DEV_SET_REF_CNT(VAL, FN) ((VAL) |= (1 << (FN * 4)))
#define QLC_DEV_CLR_REF_CNT(VAL, FN) ((VAL) &= ~(1 << (FN * 4)))
#define QLC_DEV_SET_RST_RDY(VAL, FN) ((VAL) |= (1 << (FN * 4)))
#define QLC_DEV_SET_QSCNT_RDY(VAL, FN) ((VAL) |= (2 << (FN * 4)))
#define QLC_DEV_CLR_RST_QSCNT(VAL, FN) ((VAL) &= ~(3 << (FN * 4)))
+#define QLC_DEV_GET_DRV(VAL, FN) (0xf & ((VAL) >> (FN * 4)))
+#define QLC_DEV_SET_DRV(VAL, FN) ((VAL) << (FN * 4))
+
+#define QLCNIC_TYPE_NIC 1
+#define QLCNIC_TYPE_FCOE 2
+#define QLCNIC_TYPE_ISCSI 3
+
#define QLCNIC_RCODE_DRIVER_INFO 0x20000000
-#define QLCNIC_RCODE_DRIVER_CAN_RELOAD 0x40000000
-#define QLCNIC_RCODE_FATAL_ERROR 0x80000000
+#define QLCNIC_RCODE_DRIVER_CAN_RELOAD BIT_30
+#define QLCNIC_RCODE_FATAL_ERROR BIT_31
#define QLCNIC_FWERROR_PEGNUM(code) ((code) & 0xff)
#define QLCNIC_FWERROR_CODE(code) ((code >> 8) & 0xfffff)
@@ -721,6 +766,29 @@ struct qlcnic_legacy_intr_set {
u32 pci_int_reg;
};
+#define QLCNIC_FW_API 0x1b216c
+#define QLCNIC_DRV_OP_MODE 0x1b2170
+#define QLCNIC_MSIX_BASE 0x132110
+#define QLCNIC_MAX_PCI_FUNC 8
+
+/* PCI function operational mode */
+enum {
+ QLCNIC_MGMT_FUNC = 0,
+ QLCNIC_PRIV_FUNC = 1,
+ QLCNIC_NON_PRIV_FUNC = 2
+};
+
+#define QLC_DEV_DRV_DEFAULT 0x11111111
+
+#define LSB(x) ((uint8_t)(x))
+#define MSB(x) ((uint8_t)((uint16_t)(x) >> 8))
+
+#define LSW(x) ((uint16_t)((uint32_t)(x)))
+#define MSW(x) ((uint16_t)((uint32_t)(x) >> 16))
+
+#define LSD(x) ((uint32_t)((uint64_t)(x)))
+#define MSD(x) ((uint32_t)((((uint64_t)(x)) >> 16) >> 16))
+
#define QLCNIC_LEGACY_INTR_CONFIG \
{ \
{ \
diff --git a/drivers/net/qlcnic/qlcnic_hw.c b/drivers/net/qlcnic/qlcnic_hw.c
index 0c2e1f08f45..e08c8b0556a 100644
--- a/drivers/net/qlcnic/qlcnic_hw.c
+++ b/drivers/net/qlcnic/qlcnic_hw.c
@@ -327,7 +327,7 @@ qlcnic_send_cmd_descs(struct qlcnic_adapter *adapter,
i = 0;
- if (adapter->is_up != QLCNIC_ADAPTER_UP_MAGIC)
+ if (!test_bit(__QLCNIC_FW_ATTACHED, &adapter->state))
return -EIO;
tx_ring = adapter->tx_ring;
@@ -338,9 +338,15 @@ qlcnic_send_cmd_descs(struct qlcnic_adapter *adapter,
if (nr_desc >= qlcnic_tx_avail(tx_ring)) {
netif_tx_stop_queue(tx_ring->txq);
- __netif_tx_unlock_bh(tx_ring->txq);
- adapter->stats.xmit_off++;
- return -EBUSY;
+ smp_mb();
+ if (qlcnic_tx_avail(tx_ring) > nr_desc) {
+ if (qlcnic_tx_avail(tx_ring) > TX_STOP_THRESH)
+ netif_tx_wake_queue(tx_ring->txq);
+ } else {
+ adapter->stats.xmit_off++;
+ __netif_tx_unlock_bh(tx_ring->txq);
+ return -EBUSY;
+ }
}
do {
@@ -407,10 +413,15 @@ static int qlcnic_nic_add_mac(struct qlcnic_adapter *adapter, u8 *addr)
return -ENOMEM;
}
memcpy(cur->mac_addr, addr, ETH_ALEN);
- list_add_tail(&cur->list, &adapter->mac_list);
- return qlcnic_sre_macaddr_change(adapter,
- cur->mac_addr, QLCNIC_MAC_ADD);
+ if (qlcnic_sre_macaddr_change(adapter,
+ cur->mac_addr, QLCNIC_MAC_ADD)) {
+ kfree(cur);
+ return -EIO;
+ }
+
+ list_add_tail(&cur->list, &adapter->mac_list);
+ return 0;
}
void qlcnic_set_multi(struct net_device *netdev)
@@ -420,7 +431,7 @@ void qlcnic_set_multi(struct net_device *netdev)
u8 bcast_addr[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
u32 mode = VPORT_MISS_MODE_DROP;
- if (adapter->is_up != QLCNIC_ADAPTER_UP_MAGIC)
+ if (!test_bit(__QLCNIC_FW_ATTACHED, &adapter->state))
return;
qlcnic_nic_add_mac(adapter, adapter->mac_addr);
@@ -538,7 +549,7 @@ int qlcnic_config_hw_lro(struct qlcnic_adapter *adapter, int enable)
return rv;
}
-int qlcnic_config_bridged_mode(struct qlcnic_adapter *adapter, int enable)
+int qlcnic_config_bridged_mode(struct qlcnic_adapter *adapter, u32 enable)
{
struct qlcnic_nic_req req;
u64 word;
@@ -704,21 +715,15 @@ int qlcnic_change_mtu(struct net_device *netdev, int mtu)
return rc;
}
-int qlcnic_get_mac_addr(struct qlcnic_adapter *adapter, u64 *mac)
+int qlcnic_get_mac_addr(struct qlcnic_adapter *adapter, u8 *mac)
{
- u32 crbaddr, mac_hi, mac_lo;
+ u32 crbaddr;
int pci_func = adapter->ahw.pci_func;
crbaddr = CRB_MAC_BLOCK_START +
(4 * ((pci_func/2) * 3)) + (4 * (pci_func & 1));
- mac_lo = QLCRD32(adapter, crbaddr);
- mac_hi = QLCRD32(adapter, crbaddr+4);
-
- if (pci_func & 1)
- *mac = le64_to_cpu((mac_lo >> 16) | ((u64)mac_hi << 16));
- else
- *mac = le64_to_cpu((u64)mac_lo | ((u64)mac_hi << 32));
+ qlcnic_fetch_mac(adapter, crbaddr, crbaddr+4, pci_func & 1, mac);
return 0;
}
@@ -766,7 +771,7 @@ qlcnic_pci_get_crb_addr_2M(struct qlcnic_adapter *adapter,
* Out: 'off' is 2M pci map addr
* side effect: lock crb window
*/
-static void
+static int
qlcnic_pci_set_crbwindow_2M(struct qlcnic_adapter *adapter, ulong off)
{
u32 window;
@@ -775,6 +780,10 @@ qlcnic_pci_set_crbwindow_2M(struct qlcnic_adapter *adapter, ulong off)
off -= QLCNIC_PCI_CRBSPACE;
window = CRB_HI(off);
+ if (window == 0) {
+ dev_err(&adapter->pdev->dev, "Invalid offset 0x%lx\n", off);
+ return -EIO;
+ }
writel(window, addr);
if (readl(addr) != window) {
@@ -782,7 +791,9 @@ qlcnic_pci_set_crbwindow_2M(struct qlcnic_adapter *adapter, ulong off)
dev_warn(&adapter->pdev->dev,
"failed to set CRB window to %d off 0x%lx\n",
window, off);
+ return -EIO;
}
+ return 0;
}
int
@@ -803,11 +814,12 @@ qlcnic_hw_write_wx_2M(struct qlcnic_adapter *adapter, ulong off, u32 data)
/* indirect access */
write_lock_irqsave(&adapter->ahw.crb_lock, flags);
crb_win_lock(adapter);
- qlcnic_pci_set_crbwindow_2M(adapter, off);
- writel(data, addr);
+ rv = qlcnic_pci_set_crbwindow_2M(adapter, off);
+ if (!rv)
+ writel(data, addr);
crb_win_unlock(adapter);
write_unlock_irqrestore(&adapter->ahw.crb_lock, flags);
- return 0;
+ return rv;
}
dev_err(&adapter->pdev->dev,
@@ -821,7 +833,7 @@ qlcnic_hw_read_wx_2M(struct qlcnic_adapter *adapter, ulong off)
{
unsigned long flags;
int rv;
- u32 data;
+ u32 data = -1;
void __iomem *addr = NULL;
rv = qlcnic_pci_get_crb_addr_2M(adapter, off, &addr);
@@ -833,8 +845,8 @@ qlcnic_hw_read_wx_2M(struct qlcnic_adapter *adapter, ulong off)
/* indirect access */
write_lock_irqsave(&adapter->ahw.crb_lock, flags);
crb_win_lock(adapter);
- qlcnic_pci_set_crbwindow_2M(adapter, off);
- data = readl(addr);
+ if (!qlcnic_pci_set_crbwindow_2M(adapter, off))
+ data = readl(addr);
crb_win_unlock(adapter);
write_unlock_irqrestore(&adapter->ahw.crb_lock, flags);
return data;
diff --git a/drivers/net/qlcnic/qlcnic_init.c b/drivers/net/qlcnic/qlcnic_init.c
index 71a4e664ad7..75ba744b173 100644
--- a/drivers/net/qlcnic/qlcnic_init.c
+++ b/drivers/net/qlcnic/qlcnic_init.c
@@ -112,18 +112,45 @@ void qlcnic_release_rx_buffers(struct qlcnic_adapter *adapter)
rds_ring = &recv_ctx->rds_rings[ring];
for (i = 0; i < rds_ring->num_desc; ++i) {
rx_buf = &(rds_ring->rx_buf_arr[i]);
- if (rx_buf->state == QLCNIC_BUFFER_FREE)
+ if (rx_buf->skb == NULL)
continue;
+
pci_unmap_single(adapter->pdev,
rx_buf->dma,
rds_ring->dma_size,
PCI_DMA_FROMDEVICE);
- if (rx_buf->skb != NULL)
- dev_kfree_skb_any(rx_buf->skb);
+
+ dev_kfree_skb_any(rx_buf->skb);
}
}
}
+void qlcnic_reset_rx_buffers_list(struct qlcnic_adapter *adapter)
+{
+ struct qlcnic_recv_context *recv_ctx;
+ struct qlcnic_host_rds_ring *rds_ring;
+ struct qlcnic_rx_buffer *rx_buf;
+ int i, ring;
+
+ recv_ctx = &adapter->recv_ctx;
+ for (ring = 0; ring < adapter->max_rds_rings; ring++) {
+ rds_ring = &recv_ctx->rds_rings[ring];
+
+ spin_lock(&rds_ring->lock);
+
+ INIT_LIST_HEAD(&rds_ring->free_list);
+
+ rx_buf = rds_ring->rx_buf_arr;
+ for (i = 0; i < rds_ring->num_desc; i++) {
+ list_add_tail(&rx_buf->list,
+ &rds_ring->free_list);
+ rx_buf++;
+ }
+
+ spin_unlock(&rds_ring->lock);
+ }
+}
+
void qlcnic_release_tx_buffers(struct qlcnic_adapter *adapter)
{
struct qlcnic_cmd_buffer *cmd_buf;
@@ -181,7 +208,9 @@ skip_rds:
tx_ring = adapter->tx_ring;
vfree(tx_ring->cmd_buf_arr);
+ tx_ring->cmd_buf_arr = NULL;
kfree(adapter->tx_ring);
+ adapter->tx_ring = NULL;
}
int qlcnic_alloc_sw_resources(struct qlcnic_adapter *adapter)
@@ -264,7 +293,6 @@ int qlcnic_alloc_sw_resources(struct qlcnic_adapter *adapter)
list_add_tail(&rx_buf->list,
&rds_ring->free_list);
rx_buf->ref_handle = i;
- rx_buf->state = QLCNIC_BUFFER_FREE;
rx_buf++;
}
spin_lock_init(&rds_ring->lock);
@@ -413,7 +441,7 @@ int qlcnic_pinit_from_rom(struct qlcnic_adapter *adapter)
/* resetall */
qlcnic_rom_lock(adapter);
- QLCWR32(adapter, QLCNIC_ROMUSB_GLB_SW_RESET, 0xffffffff);
+ QLCWR32(adapter, QLCNIC_ROMUSB_GLB_SW_RESET, 0xfeffffff);
qlcnic_rom_unlock(adapter);
if (qlcnic_rom_fast_read(adapter, 0, &n) != 0 || (n != 0xcafecafe) ||
@@ -521,16 +549,13 @@ qlcnic_setup_idc_param(struct qlcnic_adapter *adapter) {
u32 val;
val = QLCRD32(adapter, QLCNIC_CRB_DEV_PARTITION_INFO);
- val = (val >> (adapter->portnum * 4)) & 0xf;
-
- if ((val & 0x3) != 1) {
- dev_err(&adapter->pdev->dev, "Not an Ethernet NIC func=%u\n",
- val);
+ val = QLC_DEV_GET_DRV(val, adapter->portnum);
+ if ((val & 0x3) != QLCNIC_TYPE_NIC) {
+ dev_err(&adapter->pdev->dev,
+ "Not an Ethernet NIC func=%u\n", val);
return -EIO;
}
-
adapter->physical_port = (val >> 2);
-
if (qlcnic_rom_fast_read(adapter, QLCNIC_ROM_DEV_INIT_TIMEOUT, &timeo))
timeo = 30;
@@ -544,16 +569,34 @@ qlcnic_setup_idc_param(struct qlcnic_adapter *adapter) {
return 0;
}
+int
+qlcnic_check_flash_fw_ver(struct qlcnic_adapter *adapter)
+{
+ u32 ver = -1, min_ver;
+
+ qlcnic_rom_fast_read(adapter, QLCNIC_FW_VERSION_OFFSET, (int *)&ver);
+
+ ver = QLCNIC_DECODE_VERSION(ver);
+ min_ver = QLCNIC_MIN_FW_VERSION;
+
+ if (ver < min_ver) {
+ dev_err(&adapter->pdev->dev,
+ "firmware version %d.%d.%d unsupported."
+ "Min supported version %d.%d.%d\n",
+ _major(ver), _minor(ver), _build(ver),
+ _major(min_ver), _minor(min_ver), _build(min_ver));
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
static int
qlcnic_has_mn(struct qlcnic_adapter *adapter)
{
- u32 capability, flashed_ver;
+ u32 capability;
capability = 0;
- qlcnic_rom_fast_read(adapter,
- QLCNIC_FW_VERSION_OFFSET, (int *)&flashed_ver);
- flashed_ver = QLCNIC_DECODE_VERSION(flashed_ver);
-
capability = QLCRD32(adapter, QLCNIC_PEG_TUNE_CAPABILITY);
if (capability & QLCNIC_PEG_TUNE_MN_PRESENT)
return 1;
@@ -1007,7 +1050,7 @@ static int
qlcnic_validate_firmware(struct qlcnic_adapter *adapter)
{
__le32 val;
- u32 ver, min_ver, bios, min_size;
+ u32 ver, bios, min_size;
struct pci_dev *pdev = adapter->pdev;
const struct firmware *fw = adapter->fw;
u8 fw_type = adapter->fw_type;
@@ -1029,12 +1072,9 @@ qlcnic_validate_firmware(struct qlcnic_adapter *adapter)
return -EINVAL;
val = qlcnic_get_fw_version(adapter);
-
- min_ver = QLCNIC_VERSION_CODE(4, 0, 216);
-
ver = QLCNIC_DECODE_VERSION(val);
- if ((_major(ver) > _QLCNIC_LINUX_MAJOR) || (ver < min_ver)) {
+ if (ver < QLCNIC_MIN_FW_VERSION) {
dev_err(&pdev->dev,
"%s: firmware version %d.%d.%d unsupported\n",
fw_name[fw_type], _major(ver), _minor(ver), _build(ver));
@@ -1122,7 +1162,7 @@ qlcnic_release_firmware(struct qlcnic_adapter *adapter)
adapter->fw = NULL;
}
-int qlcnic_phantom_init(struct qlcnic_adapter *adapter)
+static int qlcnic_cmd_peg_ready(struct qlcnic_adapter *adapter)
{
u32 val;
int retries = 60;
@@ -1147,7 +1187,8 @@ int qlcnic_phantom_init(struct qlcnic_adapter *adapter)
QLCWR32(adapter, CRB_CMDPEG_STATE, PHAN_INITIALIZE_FAILED);
out_err:
- dev_err(&adapter->pdev->dev, "firmware init failed\n");
+ dev_err(&adapter->pdev->dev, "Command Peg initialization not "
+ "complete, state: 0x%x.\n", val);
return -EIO;
}
@@ -1180,6 +1221,10 @@ int qlcnic_init_firmware(struct qlcnic_adapter *adapter)
{
int err;
+ err = qlcnic_cmd_peg_ready(adapter);
+ if (err)
+ return err;
+
err = qlcnic_receive_peg_ready(adapter);
if (err)
return err;
@@ -1265,14 +1310,12 @@ qlcnic_alloc_rx_skb(struct qlcnic_adapter *adapter,
dma_addr_t dma;
struct pci_dev *pdev = adapter->pdev;
- buffer->skb = dev_alloc_skb(rds_ring->skb_size);
- if (!buffer->skb) {
+ skb = dev_alloc_skb(rds_ring->skb_size);
+ if (!skb) {
adapter->stats.skb_alloc_failure++;
return -ENOMEM;
}
- skb = buffer->skb;
-
skb_reserve(skb, 2);
dma = pci_map_single(pdev, skb->data,
@@ -1281,13 +1324,11 @@ qlcnic_alloc_rx_skb(struct qlcnic_adapter *adapter,
if (pci_dma_mapping_error(pdev, dma)) {
adapter->stats.rx_dma_map_error++;
dev_kfree_skb_any(skb);
- buffer->skb = NULL;
return -ENOMEM;
}
buffer->skb = skb;
buffer->dma = dma;
- buffer->state = QLCNIC_BUFFER_BUSY;
return 0;
}
@@ -1300,14 +1341,15 @@ static struct sk_buff *qlcnic_process_rxbuf(struct qlcnic_adapter *adapter,
buffer = &rds_ring->rx_buf_arr[index];
+ if (unlikely(buffer->skb == NULL)) {
+ WARN_ON(1);
+ return NULL;
+ }
+
pci_unmap_single(adapter->pdev, buffer->dma, rds_ring->dma_size,
PCI_DMA_FROMDEVICE);
skb = buffer->skb;
- if (!skb) {
- adapter->stats.null_skb++;
- goto no_skb;
- }
if (likely(adapter->rx_csum && cksum == STATUS_CKSUM_OK)) {
adapter->stats.csummed++;
@@ -1319,8 +1361,7 @@ static struct sk_buff *qlcnic_process_rxbuf(struct qlcnic_adapter *adapter,
skb->dev = adapter->netdev;
buffer->skb = NULL;
-no_skb:
- buffer->state = QLCNIC_BUFFER_FREE;
+
return skb;
}
@@ -1495,7 +1536,7 @@ qlcnic_process_rcv_ring(struct qlcnic_host_sds_ring *sds_ring, int max)
WARN_ON(desc_cnt > 1);
- if (rxbuf)
+ if (likely(rxbuf))
list_add_tail(&rxbuf->list, &sds_ring->free_list[ring]);
else
adapter->stats.null_rxbuf++;
@@ -1701,3 +1742,24 @@ qlcnic_process_rcv_ring_diag(struct qlcnic_host_sds_ring *sds_ring)
sds_ring->consumer = consumer;
writel(consumer, sds_ring->crb_sts_consumer);
}
+
+void
+qlcnic_fetch_mac(struct qlcnic_adapter *adapter, u32 off1, u32 off2,
+ u8 alt_mac, u8 *mac)
+{
+ u32 mac_low, mac_high;
+ int i;
+
+ mac_low = QLCRD32(adapter, off1);
+ mac_high = QLCRD32(adapter, off2);
+
+ if (alt_mac) {
+ mac_low |= (mac_low >> 16) | (mac_high << 16);
+ mac_high >>= 16;
+ }
+
+ for (i = 0; i < 2; i++)
+ mac[i] = (u8)(mac_high >> ((1 - i) * 8));
+ for (i = 2; i < 6; i++)
+ mac[i] = (u8)(mac_low >> ((5 - i) * 8));
+}
diff --git a/drivers/net/qlcnic/qlcnic_main.c b/drivers/net/qlcnic/qlcnic_main.c
index 23ea9caa526..b9615bd745e 100644
--- a/drivers/net/qlcnic/qlcnic_main.c
+++ b/drivers/net/qlcnic/qlcnic_main.c
@@ -34,15 +34,16 @@
#include <linux/ipv6.h>
#include <linux/inetdevice.h>
#include <linux/sysfs.h>
+#include <linux/aer.h>
-MODULE_DESCRIPTION("QLogic 10 GbE Converged Ethernet Driver");
+MODULE_DESCRIPTION("QLogic 1/10 GbE Converged/Intelligent Ethernet Driver");
MODULE_LICENSE("GPL");
MODULE_VERSION(QLCNIC_LINUX_VERSIONID);
MODULE_FIRMWARE(QLCNIC_UNIFIED_ROMIMAGE_NAME);
char qlcnic_driver_name[] = "qlcnic";
-static const char qlcnic_driver_string[] = "QLogic Converged Ethernet Driver v"
- QLCNIC_LINUX_VERSIONID;
+static const char qlcnic_driver_string[] = "QLogic 1/10 GbE "
+ "Converged/Intelligent Ethernet Driver v" QLCNIC_LINUX_VERSIONID;
static int port_mode = QLCNIC_PORT_MODE_AUTO_NEG;
@@ -65,13 +66,16 @@ static int load_fw_file;
module_param(load_fw_file, int, 0644);
MODULE_PARM_DESC(load_fw_file, "Load firmware from (0=flash, 1=file");
+static int qlcnic_config_npars;
+module_param(qlcnic_config_npars, int, 0644);
+MODULE_PARM_DESC(qlcnic_config_npars, "Configure NPARs (0=disabled, 1=enabled");
+
static int __devinit qlcnic_probe(struct pci_dev *pdev,
const struct pci_device_id *ent);
static void __devexit qlcnic_remove(struct pci_dev *pdev);
static int qlcnic_open(struct net_device *netdev);
static int qlcnic_close(struct net_device *netdev);
static void qlcnic_tx_timeout(struct net_device *netdev);
-static void qlcnic_tx_timeout_task(struct work_struct *work);
static void qlcnic_attach_work(struct work_struct *work);
static void qlcnic_fwinit_work(struct work_struct *work);
static void qlcnic_fw_poll_work(struct work_struct *work);
@@ -79,6 +83,7 @@ static void qlcnic_schedule_work(struct qlcnic_adapter *adapter,
work_func_t func, int delay);
static void qlcnic_cancel_fw_work(struct qlcnic_adapter *adapter);
static int qlcnic_poll(struct napi_struct *napi, int budget);
+static int qlcnic_rx_poll(struct napi_struct *napi, int budget);
#ifdef CONFIG_NET_POLL_CONTROLLER
static void qlcnic_poll_controller(struct net_device *netdev);
#endif
@@ -99,7 +104,12 @@ static irqreturn_t qlcnic_msix_intr(int irq, void *data);
static struct net_device_stats *qlcnic_get_stats(struct net_device *netdev);
static void qlcnic_config_indev_addr(struct net_device *dev, unsigned long);
+static int qlcnic_start_firmware(struct qlcnic_adapter *);
+static void qlcnic_dev_set_npar_ready(struct qlcnic_adapter *);
+static int qlcnicvf_config_led(struct qlcnic_adapter *, u32, u32);
+static int qlcnicvf_config_bridged_mode(struct qlcnic_adapter *, u32);
+static int qlcnicvf_start_firmware(struct qlcnic_adapter *);
/* PCI Device ID Table */
#define ENTRY(device) \
{PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, (device)), \
@@ -120,12 +130,6 @@ qlcnic_update_cmd_producer(struct qlcnic_adapter *adapter,
struct qlcnic_host_tx_ring *tx_ring)
{
writel(tx_ring->producer, tx_ring->crb_cmd_producer);
-
- if (qlcnic_tx_avail(tx_ring) <= TX_STOP_THRESH) {
- netif_stop_queue(adapter->netdev);
- smp_mb();
- adapter->stats.xmit_off++;
- }
}
static const u32 msi_tgt_status[8] = {
@@ -184,8 +188,13 @@ qlcnic_napi_add(struct qlcnic_adapter *adapter, struct net_device *netdev)
for (ring = 0; ring < adapter->max_sds_rings; ring++) {
sds_ring = &recv_ctx->sds_rings[ring];
- netif_napi_add(netdev, &sds_ring->napi,
- qlcnic_poll, QLCNIC_NETDEV_WEIGHT);
+
+ if (ring == adapter->max_sds_rings - 1)
+ netif_napi_add(netdev, &sds_ring->napi, qlcnic_poll,
+ QLCNIC_NETDEV_WEIGHT/adapter->max_sds_rings);
+ else
+ netif_napi_add(netdev, &sds_ring->napi,
+ qlcnic_rx_poll, QLCNIC_NETDEV_WEIGHT*2);
}
return 0;
@@ -307,19 +316,14 @@ static void qlcnic_init_msix_entries(struct qlcnic_adapter *adapter, int count)
static int
qlcnic_read_mac_addr(struct qlcnic_adapter *adapter)
{
- int i;
- unsigned char *p;
- u64 mac_addr;
+ u8 mac_addr[ETH_ALEN];
struct net_device *netdev = adapter->netdev;
struct pci_dev *pdev = adapter->pdev;
- if (qlcnic_get_mac_addr(adapter, &mac_addr) != 0)
+ if (adapter->nic_ops->get_mac_addr(adapter, mac_addr) != 0)
return -EIO;
- p = (unsigned char *)&mac_addr;
- for (i = 0; i < 6; i++)
- netdev->dev_addr[i] = *(p + 5 - i);
-
+ memcpy(netdev->dev_addr, mac_addr, ETH_ALEN);
memcpy(netdev->perm_addr, netdev->dev_addr, netdev->addr_len);
memcpy(adapter->mac_addr, netdev->dev_addr, netdev->addr_len);
@@ -340,7 +344,7 @@ static int qlcnic_set_mac(struct net_device *netdev, void *p)
if (!is_valid_ether_addr(addr->sa_data))
return -EINVAL;
- if (netif_running(netdev)) {
+ if (test_bit(__QLCNIC_DEV_UP, &adapter->state)) {
netif_device_detach(netdev);
qlcnic_napi_disable(adapter);
}
@@ -349,7 +353,7 @@ static int qlcnic_set_mac(struct net_device *netdev, void *p)
memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len);
qlcnic_set_multi(adapter->netdev);
- if (netif_running(netdev)) {
+ if (test_bit(__QLCNIC_DEV_UP, &adapter->state)) {
netif_device_attach(netdev);
qlcnic_napi_enable(adapter);
}
@@ -371,6 +375,20 @@ static const struct net_device_ops qlcnic_netdev_ops = {
#endif
};
+static struct qlcnic_nic_template qlcnic_ops = {
+ .get_mac_addr = qlcnic_get_mac_address,
+ .config_bridged_mode = qlcnic_config_bridged_mode,
+ .config_led = qlcnic_config_led,
+ .start_firmware = qlcnic_start_firmware
+};
+
+static struct qlcnic_nic_template qlcnic_vf_ops = {
+ .get_mac_addr = qlcnic_get_mac_address,
+ .config_bridged_mode = qlcnicvf_config_bridged_mode,
+ .config_led = qlcnicvf_config_led,
+ .start_firmware = qlcnicvf_start_firmware
+};
+
static void
qlcnic_setup_intr(struct qlcnic_adapter *adapter)
{
@@ -453,6 +471,169 @@ qlcnic_cleanup_pci_map(struct qlcnic_adapter *adapter)
}
static int
+qlcnic_init_pci_info(struct qlcnic_adapter *adapter)
+{
+ struct qlcnic_pci_info pci_info[QLCNIC_MAX_PCI_FUNC];
+ int i, ret = 0, err;
+ u8 pfn;
+
+ if (!adapter->npars)
+ adapter->npars = kzalloc(sizeof(struct qlcnic_npar_info) *
+ QLCNIC_MAX_PCI_FUNC, GFP_KERNEL);
+ if (!adapter->npars)
+ return -ENOMEM;
+
+ if (!adapter->eswitch)
+ adapter->eswitch = kzalloc(sizeof(struct qlcnic_eswitch) *
+ QLCNIC_NIU_MAX_XG_PORTS, GFP_KERNEL);
+ if (!adapter->eswitch) {
+ err = -ENOMEM;
+ goto err_eswitch;
+ }
+
+ ret = qlcnic_get_pci_info(adapter, pci_info);
+ if (!ret) {
+ for (i = 0; i < QLCNIC_MAX_PCI_FUNC; i++) {
+ pfn = pci_info[i].id;
+ if (pfn > QLCNIC_MAX_PCI_FUNC)
+ return QL_STATUS_INVALID_PARAM;
+ adapter->npars[pfn].active = pci_info[i].active;
+ adapter->npars[pfn].type = pci_info[i].type;
+ adapter->npars[pfn].phy_port = pci_info[i].default_port;
+ adapter->npars[pfn].mac_learning = DEFAULT_MAC_LEARN;
+ adapter->npars[pfn].min_bw = pci_info[i].tx_min_bw;
+ adapter->npars[pfn].max_bw = pci_info[i].tx_max_bw;
+ }
+
+ for (i = 0; i < QLCNIC_NIU_MAX_XG_PORTS; i++)
+ adapter->eswitch[i].flags |= QLCNIC_SWITCH_ENABLE;
+
+ return ret;
+ }
+
+ kfree(adapter->eswitch);
+ adapter->eswitch = NULL;
+err_eswitch:
+ kfree(adapter->npars);
+
+ return ret;
+}
+
+static int
+qlcnic_set_function_modes(struct qlcnic_adapter *adapter)
+{
+ u8 id;
+ u32 ref_count;
+ int i, ret = 1;
+ u32 data = QLCNIC_MGMT_FUNC;
+ void __iomem *priv_op = adapter->ahw.pci_base0 + QLCNIC_DRV_OP_MODE;
+
+ /* If other drivers are not in use set their privilege level */
+ ref_count = QLCRD32(adapter, QLCNIC_CRB_DEV_REF_COUNT);
+ ret = qlcnic_api_lock(adapter);
+ if (ret)
+ goto err_lock;
+ if (QLC_DEV_CLR_REF_CNT(ref_count, adapter->ahw.pci_func))
+ goto err_npar;
+
+ if (qlcnic_config_npars) {
+ for (i = 0; i < QLCNIC_MAX_PCI_FUNC; i++) {
+ id = i;
+ if (adapter->npars[i].type != QLCNIC_TYPE_NIC ||
+ id == adapter->ahw.pci_func)
+ continue;
+ data |= (qlcnic_config_npars &
+ QLC_DEV_SET_DRV(0xf, id));
+ }
+ } else {
+ data = readl(priv_op);
+ data = (data & ~QLC_DEV_SET_DRV(0xf, adapter->ahw.pci_func)) |
+ (QLC_DEV_SET_DRV(QLCNIC_MGMT_FUNC,
+ adapter->ahw.pci_func));
+ }
+ writel(data, priv_op);
+err_npar:
+ qlcnic_api_unlock(adapter);
+err_lock:
+ return ret;
+}
+
+static u32
+qlcnic_get_driver_mode(struct qlcnic_adapter *adapter)
+{
+ void __iomem *msix_base_addr;
+ void __iomem *priv_op;
+ struct qlcnic_info nic_info;
+ u32 func;
+ u32 msix_base;
+ u32 op_mode, priv_level;
+
+ /* Determine FW API version */
+ adapter->fw_hal_version = readl(adapter->ahw.pci_base0 + QLCNIC_FW_API);
+
+ /* Find PCI function number */
+ pci_read_config_dword(adapter->pdev, QLCNIC_MSIX_TABLE_OFFSET, &func);
+ msix_base_addr = adapter->ahw.pci_base0 + QLCNIC_MSIX_BASE;
+ msix_base = readl(msix_base_addr);
+ func = (func - msix_base)/QLCNIC_MSIX_TBL_PGSIZE;
+ adapter->ahw.pci_func = func;
+
+ if (!qlcnic_get_nic_info(adapter, &nic_info, adapter->ahw.pci_func)) {
+ adapter->capabilities = nic_info.capabilities;
+
+ if (adapter->capabilities & BIT_6)
+ adapter->flags |= QLCNIC_ESWITCH_ENABLED;
+ else
+ adapter->flags &= ~QLCNIC_ESWITCH_ENABLED;
+ }
+
+ if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED)) {
+ adapter->nic_ops = &qlcnic_ops;
+ return adapter->fw_hal_version;
+ }
+
+ /* Determine function privilege level */
+ priv_op = adapter->ahw.pci_base0 + QLCNIC_DRV_OP_MODE;
+ op_mode = readl(priv_op);
+ if (op_mode == QLC_DEV_DRV_DEFAULT)
+ priv_level = QLCNIC_MGMT_FUNC;
+ else
+ priv_level = QLC_DEV_GET_DRV(op_mode, adapter->ahw.pci_func);
+
+ switch (priv_level) {
+ case QLCNIC_MGMT_FUNC:
+ adapter->op_mode = QLCNIC_MGMT_FUNC;
+ adapter->nic_ops = &qlcnic_ops;
+ qlcnic_init_pci_info(adapter);
+ /* Set privilege level for other functions */
+ qlcnic_set_function_modes(adapter);
+ dev_info(&adapter->pdev->dev,
+ "HAL Version: %d, Management function\n",
+ adapter->fw_hal_version);
+ break;
+ case QLCNIC_PRIV_FUNC:
+ adapter->op_mode = QLCNIC_PRIV_FUNC;
+ dev_info(&adapter->pdev->dev,
+ "HAL Version: %d, Privileged function\n",
+ adapter->fw_hal_version);
+ adapter->nic_ops = &qlcnic_ops;
+ break;
+ case QLCNIC_NON_PRIV_FUNC:
+ adapter->op_mode = QLCNIC_NON_PRIV_FUNC;
+ dev_info(&adapter->pdev->dev,
+ "HAL Version: %d Non Privileged function\n",
+ adapter->fw_hal_version);
+ adapter->nic_ops = &qlcnic_vf_ops;
+ break;
+ default:
+ dev_info(&adapter->pdev->dev, "Unknown function mode: %d\n",
+ priv_level);
+ return 0;
+ }
+ return adapter->fw_hal_version;
+}
+
+static int
qlcnic_setup_pci_map(struct qlcnic_adapter *adapter)
{
void __iomem *mem_ptr0 = NULL;
@@ -460,7 +641,6 @@ qlcnic_setup_pci_map(struct qlcnic_adapter *adapter)
unsigned long mem_len, pci_len0 = 0;
struct pci_dev *pdev = adapter->pdev;
- int pci_func = adapter->ahw.pci_func;
/* remap phys address */
mem_base = pci_resource_start(pdev, 0); /* 0 is for BAR 0 */
@@ -483,8 +663,13 @@ qlcnic_setup_pci_map(struct qlcnic_adapter *adapter)
adapter->ahw.pci_base0 = mem_ptr0;
adapter->ahw.pci_len0 = pci_len0;
+ if (!qlcnic_get_driver_mode(adapter)) {
+ iounmap(adapter->ahw.pci_base0);
+ return -EIO;
+ }
+
adapter->ahw.ocm_win_crb = qlcnic_get_ioaddr(adapter,
- QLCNIC_PCIX_PS_REG(PCIX_OCM_WINDOW_REG(pci_func)));
+ QLCNIC_PCIX_PS_REG(PCIX_OCM_WINDOW_REG(adapter->ahw.pci_func)));
return 0;
}
@@ -509,7 +694,7 @@ static void get_brd_name(struct qlcnic_adapter *adapter, char *name)
}
if (!found)
- name = "Unknown";
+ sprintf(name, "%pM Gigabit Ethernet", adapter->mac_addr);
}
static void
@@ -521,7 +706,7 @@ qlcnic_check_options(struct qlcnic_adapter *adapter)
int i, offset, val;
int *ptr32;
struct pci_dev *pdev = adapter->pdev;
-
+ struct qlcnic_info nic_info;
adapter->driver_mismatch = 0;
ptr32 = (int *)&serial_num;
@@ -553,8 +738,6 @@ qlcnic_check_options(struct qlcnic_adapter *adapter)
dev_info(&pdev->dev, "firmware v%d.%d.%d\n",
fw_major, fw_minor, fw_build);
- adapter->capabilities = QLCRD32(adapter, CRB_FW_CAPABILITIES_1);
-
adapter->flags &= ~QLCNIC_LRO_ENABLED;
if (adapter->ahw.port_type == QLCNIC_XGBE) {
@@ -565,6 +748,16 @@ qlcnic_check_options(struct qlcnic_adapter *adapter)
adapter->num_jumbo_rxd = MAX_JUMBO_RCV_DESCRIPTORS_1G;
}
+ if (!qlcnic_get_nic_info(adapter, &nic_info, adapter->ahw.pci_func)) {
+ adapter->physical_port = nic_info.phys_port;
+ adapter->switch_mode = nic_info.switch_mode;
+ adapter->max_tx_ques = nic_info.max_tx_ques;
+ adapter->max_rx_ques = nic_info.max_rx_ques;
+ adapter->capabilities = nic_info.capabilities;
+ adapter->max_mac_filters = nic_info.max_mac_filters;
+ adapter->max_mtu = nic_info.max_mtu;
+ }
+
adapter->msix_supported = !!use_msi_x;
adapter->rss_supported = !!use_msi_x;
@@ -574,6 +767,50 @@ qlcnic_check_options(struct qlcnic_adapter *adapter)
}
static int
+qlcnic_reset_npar_config(struct qlcnic_adapter *adapter)
+{
+ int i, err = 0;
+ struct qlcnic_npar_info *npar;
+ struct qlcnic_info nic_info;
+
+ if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED) ||
+ !adapter->need_fw_reset)
+ return 0;
+
+ if (adapter->op_mode == QLCNIC_MGMT_FUNC) {
+ /* Set the NPAR config data after FW reset */
+ for (i = 0; i < QLCNIC_MAX_PCI_FUNC; i++) {
+ npar = &adapter->npars[i];
+ if (npar->type != QLCNIC_TYPE_NIC)
+ continue;
+ err = qlcnic_get_nic_info(adapter, &nic_info, i);
+ if (err)
+ goto err_out;
+ nic_info.min_tx_bw = npar->min_bw;
+ nic_info.max_tx_bw = npar->max_bw;
+ err = qlcnic_set_nic_info(adapter, &nic_info);
+ if (err)
+ goto err_out;
+
+ if (npar->enable_pm) {
+ err = qlcnic_config_port_mirroring(adapter,
+ npar->dest_npar, 1, i);
+ if (err)
+ goto err_out;
+
+ }
+ npar->mac_learning = DEFAULT_MAC_LEARN;
+ npar->host_vlan_tag = 0;
+ npar->promisc_mode = 0;
+ npar->discard_tagged = 0;
+ npar->vlan_id = 0;
+ }
+ }
+err_out:
+ return err;
+}
+
+static int
qlcnic_start_firmware(struct qlcnic_adapter *adapter)
{
int val, err, first_boot;
@@ -591,8 +828,12 @@ qlcnic_start_firmware(struct qlcnic_adapter *adapter)
if (load_fw_file)
qlcnic_request_firmware(adapter);
- else
+ else {
+ if (qlcnic_check_flash_fw_ver(adapter))
+ goto err_out;
+
adapter->fw_type = QLCNIC_FLASH_ROMIMAGE;
+ }
err = qlcnic_need_fw_reset(adapter);
if (err < 0)
@@ -602,6 +843,7 @@ qlcnic_start_firmware(struct qlcnic_adapter *adapter)
if (first_boot != 0x55555555) {
QLCWR32(adapter, CRB_CMDPEG_STATE, 0);
+ QLCWR32(adapter, CRB_RCVPEG_STATE, 0);
qlcnic_pinit_from_rom(adapter);
msleep(1);
}
@@ -624,7 +866,7 @@ qlcnic_start_firmware(struct qlcnic_adapter *adapter)
wait_init:
/* Handshake with the card before we register the devices. */
- err = qlcnic_phantom_init(adapter);
+ err = qlcnic_init_firmware(adapter);
if (err)
goto err_out;
@@ -632,6 +874,9 @@ wait_init:
qlcnic_idc_debug_info(adapter, 1);
qlcnic_check_options(adapter);
+ if (qlcnic_reset_npar_config(adapter))
+ goto err_out;
+ qlcnic_dev_set_npar_ready(adapter);
adapter->need_fw_reset = 0;
@@ -716,9 +961,23 @@ qlcnic_init_coalesce_defaults(struct qlcnic_adapter *adapter)
static int
__qlcnic_up(struct qlcnic_adapter *adapter, struct net_device *netdev)
{
+ int ring;
+ struct qlcnic_host_rds_ring *rds_ring;
+
if (adapter->is_up != QLCNIC_ADAPTER_UP_MAGIC)
return -EIO;
+ if (test_bit(__QLCNIC_DEV_UP, &adapter->state))
+ return 0;
+
+ if (qlcnic_fw_create_ctx(adapter))
+ return -EIO;
+
+ for (ring = 0; ring < adapter->max_rds_rings; ring++) {
+ rds_ring = &adapter->recv_ctx.rds_rings[ring];
+ qlcnic_post_rx_buffers(adapter, ring, rds_ring);
+ }
+
qlcnic_set_multi(netdev);
qlcnic_fw_cmd_set_mtu(adapter, netdev->mtu);
@@ -736,6 +995,7 @@ __qlcnic_up(struct qlcnic_adapter *adapter, struct net_device *netdev)
qlcnic_linkevent_request(adapter, 1);
+ adapter->reset_context = 0;
set_bit(__QLCNIC_DEV_UP, &adapter->state);
return 0;
}
@@ -775,6 +1035,9 @@ __qlcnic_down(struct qlcnic_adapter *adapter, struct net_device *netdev)
qlcnic_napi_disable(adapter);
+ qlcnic_fw_destroy_ctx(adapter);
+
+ qlcnic_reset_rx_buffers_list(adapter);
qlcnic_release_tx_buffers(adapter);
spin_unlock(&adapter->tx_clean_lock);
}
@@ -796,16 +1059,11 @@ qlcnic_attach(struct qlcnic_adapter *adapter)
{
struct net_device *netdev = adapter->netdev;
struct pci_dev *pdev = adapter->pdev;
- int err, ring;
- struct qlcnic_host_rds_ring *rds_ring;
+ int err;
if (adapter->is_up == QLCNIC_ADAPTER_UP_MAGIC)
return 0;
- err = qlcnic_init_firmware(adapter);
- if (err)
- return err;
-
err = qlcnic_napi_add(adapter, netdev);
if (err)
return err;
@@ -813,7 +1071,7 @@ qlcnic_attach(struct qlcnic_adapter *adapter)
err = qlcnic_alloc_sw_resources(adapter);
if (err) {
dev_err(&pdev->dev, "Error in setting sw resources\n");
- return err;
+ goto err_out_napi_del;
}
err = qlcnic_alloc_hw_resources(adapter);
@@ -822,16 +1080,10 @@ qlcnic_attach(struct qlcnic_adapter *adapter)
goto err_out_free_sw;
}
-
- for (ring = 0; ring < adapter->max_rds_rings; ring++) {
- rds_ring = &adapter->recv_ctx.rds_rings[ring];
- qlcnic_post_rx_buffers(adapter, ring, rds_ring);
- }
-
err = qlcnic_request_irq(adapter);
if (err) {
dev_err(&pdev->dev, "failed to setup interrupt\n");
- goto err_out_free_rxbuf;
+ goto err_out_free_hw;
}
qlcnic_init_coalesce_defaults(adapter);
@@ -841,11 +1093,12 @@ qlcnic_attach(struct qlcnic_adapter *adapter)
adapter->is_up = QLCNIC_ADAPTER_UP_MAGIC;
return 0;
-err_out_free_rxbuf:
- qlcnic_release_rx_buffers(adapter);
+err_out_free_hw:
qlcnic_free_hw_resources(adapter);
err_out_free_sw:
qlcnic_free_sw_resources(adapter);
+err_out_napi_del:
+ qlcnic_napi_del(adapter);
return err;
}
@@ -880,6 +1133,8 @@ void qlcnic_diag_free_res(struct net_device *netdev, int max_sds_rings)
}
}
+ qlcnic_fw_destroy_ctx(adapter);
+
qlcnic_detach(adapter);
adapter->diag_test = 0;
@@ -898,6 +1153,7 @@ int qlcnic_diag_alloc_res(struct net_device *netdev, int test)
{
struct qlcnic_adapter *adapter = netdev_priv(netdev);
struct qlcnic_host_sds_ring *sds_ring;
+ struct qlcnic_host_rds_ring *rds_ring;
int ring;
int ret;
@@ -917,6 +1173,18 @@ int qlcnic_diag_alloc_res(struct net_device *netdev, int test)
return ret;
}
+ ret = qlcnic_fw_create_ctx(adapter);
+ if (ret) {
+ qlcnic_detach(adapter);
+ netif_device_attach(netdev);
+ return ret;
+ }
+
+ for (ring = 0; ring < adapter->max_rds_rings; ring++) {
+ rds_ring = &adapter->recv_ctx.rds_rings[ring];
+ qlcnic_post_rx_buffers(adapter, ring, rds_ring);
+ }
+
if (adapter->diag_test == QLCNIC_INTERRUPT_TEST) {
for (ring = 0; ring < adapter->max_sds_rings; ring++) {
sds_ring = &adapter->recv_ctx.sds_rings[ring];
@@ -928,6 +1196,27 @@ int qlcnic_diag_alloc_res(struct net_device *netdev, int test)
return 0;
}
+/* Reset context in hardware only */
+static int
+qlcnic_reset_hw_context(struct qlcnic_adapter *adapter)
+{
+ struct net_device *netdev = adapter->netdev;
+
+ if (test_and_set_bit(__QLCNIC_RESETTING, &adapter->state))
+ return -EBUSY;
+
+ netif_device_detach(netdev);
+
+ qlcnic_down(adapter, netdev);
+
+ qlcnic_up(adapter, netdev);
+
+ netif_device_attach(netdev);
+
+ clear_bit(__QLCNIC_RESETTING, &adapter->state);
+ return 0;
+}
+
int
qlcnic_reset_context(struct qlcnic_adapter *adapter)
{
@@ -971,18 +1260,21 @@ qlcnic_setup_netdev(struct qlcnic_adapter *adapter,
adapter->max_mc_count = 38;
netdev->netdev_ops = &qlcnic_netdev_ops;
- netdev->watchdog_timeo = 2*HZ;
+ netdev->watchdog_timeo = 5*HZ;
qlcnic_change_mtu(netdev, netdev->mtu);
SET_ETHTOOL_OPS(netdev, &qlcnic_ethtool_ops);
- netdev->features |= (NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO);
- netdev->features |= (NETIF_F_GRO);
- netdev->vlan_features |= (NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO);
+ netdev->features |= (NETIF_F_SG | NETIF_F_IP_CSUM |
+ NETIF_F_IPV6_CSUM | NETIF_F_GRO);
+ netdev->vlan_features |= (NETIF_F_SG | NETIF_F_IP_CSUM |
+ NETIF_F_IPV6_CSUM);
- netdev->features |= (NETIF_F_IPV6_CSUM | NETIF_F_TSO6);
- netdev->vlan_features |= (NETIF_F_IPV6_CSUM | NETIF_F_TSO6);
+ if (adapter->capabilities & QLCNIC_FW_CAPABILITY_TSO) {
+ netdev->features |= (NETIF_F_TSO | NETIF_F_TSO6);
+ netdev->vlan_features |= (NETIF_F_TSO | NETIF_F_TSO6);
+ }
if (pci_using_dac) {
netdev->features |= NETIF_F_HIGHDMA;
@@ -997,8 +1289,6 @@ qlcnic_setup_netdev(struct qlcnic_adapter *adapter,
netdev->irq = adapter->msix_entries[0].vector;
- INIT_WORK(&adapter->tx_timeout_task, qlcnic_tx_timeout_task);
-
if (qlcnic_read_mac_addr(adapter))
dev_warn(&pdev->dev, "failed to read mac addr\n");
@@ -1036,7 +1326,6 @@ qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
struct net_device *netdev = NULL;
struct qlcnic_adapter *adapter = NULL;
int err;
- int pci_func_id = PCI_FUNC(pdev->devfn);
uint8_t revision_id;
uint8_t pci_using_dac;
@@ -1058,6 +1347,7 @@ qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
goto err_out_disable_pdev;
pci_set_master(pdev);
+ pci_enable_pcie_error_reporting(pdev);
netdev = alloc_etherdev(sizeof(struct qlcnic_adapter));
if (!netdev) {
@@ -1072,7 +1362,6 @@ qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
adapter->netdev = netdev;
adapter->pdev = pdev;
adapter->dev_rst_time = jiffies;
- adapter->ahw.pci_func = pci_func_id;
revision_id = pdev->revision;
adapter->ahw.revision_id = revision_id;
@@ -1088,7 +1377,7 @@ qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
goto err_out_free_netdev;
/* This will be reset for mezz cards */
- adapter->portnum = pci_func_id;
+ adapter->portnum = adapter->ahw.pci_func;
err = qlcnic_get_board_info(adapter);
if (err) {
@@ -1102,7 +1391,7 @@ qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
if (qlcnic_setup_idc_param(adapter))
goto err_out_iounmap;
- err = qlcnic_start_firmware(adapter);
+ err = adapter->nic_ops->start_firmware(adapter);
if (err) {
dev_err(&pdev->dev, "Loading fw failed.Please Reboot\n");
goto err_out_decr_ref;
@@ -1171,10 +1460,13 @@ static void __devexit qlcnic_remove(struct pci_dev *pdev)
unregister_netdev(netdev);
- cancel_work_sync(&adapter->tx_timeout_task);
-
qlcnic_detach(adapter);
+ if (adapter->npars != NULL)
+ kfree(adapter->npars);
+ if (adapter->eswitch != NULL)
+ kfree(adapter->eswitch);
+
qlcnic_clr_all_drv_state(adapter);
clear_bit(__QLCNIC_RESETTING, &adapter->state);
@@ -1187,6 +1479,7 @@ static void __devexit qlcnic_remove(struct pci_dev *pdev)
qlcnic_release_firmware(adapter);
+ pci_disable_pcie_error_reporting(pdev);
pci_release_regions(pdev);
pci_disable_device(pdev);
pci_set_drvdata(pdev, NULL);
@@ -1206,10 +1499,6 @@ static int __qlcnic_shutdown(struct pci_dev *pdev)
if (netif_running(netdev))
qlcnic_down(adapter, netdev);
- cancel_work_sync(&adapter->tx_timeout_task);
-
- qlcnic_detach(adapter);
-
qlcnic_clr_all_drv_state(adapter);
clear_bit(__QLCNIC_RESETTING, &adapter->state);
@@ -1263,35 +1552,23 @@ qlcnic_resume(struct pci_dev *pdev)
pci_set_master(pdev);
pci_restore_state(pdev);
- err = qlcnic_start_firmware(adapter);
+ err = adapter->nic_ops->start_firmware(adapter);
if (err) {
dev_err(&pdev->dev, "failed to start firmware\n");
return err;
}
if (netif_running(netdev)) {
- err = qlcnic_attach(adapter);
- if (err)
- goto err_out;
-
err = qlcnic_up(adapter, netdev);
if (err)
- goto err_out_detach;
-
+ goto done;
qlcnic_config_indev_addr(netdev, NETDEV_UP);
}
-
+done:
netif_device_attach(netdev);
qlcnic_schedule_work(adapter, qlcnic_fw_poll_work, FW_POLL_DELAY);
return 0;
-
-err_out_detach:
- qlcnic_detach(adapter);
-err_out:
- qlcnic_clr_all_drv_state(adapter);
- netif_device_attach(netdev);
- return err;
}
#endif
@@ -1340,11 +1617,11 @@ qlcnic_tso_check(struct net_device *netdev,
u8 opcode = TX_ETHER_PKT;
__be16 protocol = skb->protocol;
u16 flags = 0, vid = 0;
- u32 producer;
int copied, offset, copy_len, hdr_len = 0, tso = 0, vlan_oob = 0;
struct cmd_desc_type0 *hwdesc;
struct vlan_ethhdr *vh;
struct qlcnic_adapter *adapter = netdev_priv(netdev);
+ u32 producer = tx_ring->producer;
if (protocol == cpu_to_be16(ETH_P_8021Q)) {
@@ -1360,6 +1637,11 @@ qlcnic_tso_check(struct net_device *netdev,
vlan_oob = 1;
}
+ if (*(skb->data) & BIT_0) {
+ flags |= BIT_0;
+ memcpy(&first_desc->eth_addr, skb->data, ETH_ALEN);
+ }
+
if ((netdev->features & (NETIF_F_TSO | NETIF_F_TSO6)) &&
skb_shinfo(skb)->gso_size > 0) {
@@ -1409,7 +1691,6 @@ qlcnic_tso_check(struct net_device *netdev,
/* For LSO, we need to copy the MAC/IP/TCP headers into
* the descriptor ring
*/
- producer = tx_ring->producer;
copied = 0;
offset = 2;
@@ -1537,10 +1818,15 @@ qlcnic_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
/* 4 fragments per cmd des */
no_of_desc = (frag_count + 3) >> 2;
- if (unlikely(no_of_desc + 2 > qlcnic_tx_avail(tx_ring))) {
+ if (unlikely(qlcnic_tx_avail(tx_ring) <= TX_STOP_THRESH)) {
netif_stop_queue(netdev);
- adapter->stats.xmit_off++;
- return NETDEV_TX_BUSY;
+ smp_mb();
+ if (qlcnic_tx_avail(tx_ring) > TX_STOP_THRESH)
+ netif_start_queue(netdev);
+ else {
+ adapter->stats.xmit_off++;
+ return NETDEV_TX_BUSY;
+ }
}
producer = tx_ring->producer;
@@ -1675,35 +1961,11 @@ static void qlcnic_tx_timeout(struct net_device *netdev)
return;
dev_err(&netdev->dev, "transmit timeout, resetting.\n");
- schedule_work(&adapter->tx_timeout_task);
-}
-
-static void qlcnic_tx_timeout_task(struct work_struct *work)
-{
- struct qlcnic_adapter *adapter =
- container_of(work, struct qlcnic_adapter, tx_timeout_task);
-
- if (!netif_running(adapter->netdev))
- return;
-
- if (test_and_set_bit(__QLCNIC_RESETTING, &adapter->state))
- return;
if (++adapter->tx_timeo_cnt >= QLCNIC_MAX_TX_TIMEOUTS)
- goto request_reset;
-
- clear_bit(__QLCNIC_RESETTING, &adapter->state);
- if (!qlcnic_reset_context(adapter)) {
- adapter->netdev->trans_start = jiffies;
- return;
-
- /* context reset failed, fall through for fw reset */
- }
-
-request_reset:
- adapter->need_fw_reset = 1;
- clear_bit(__QLCNIC_RESETTING, &adapter->state);
- QLCDB(adapter, DRV, "Resetting adapter\n");
+ adapter->need_fw_reset = 1;
+ else
+ adapter->reset_context = 1;
}
static struct net_device_stats *qlcnic_get_stats(struct net_device *netdev)
@@ -1846,14 +2108,12 @@ static int qlcnic_process_cmd_ring(struct qlcnic_adapter *adapter)
smp_mb();
if (netif_queue_stopped(netdev) && netif_carrier_ok(netdev)) {
- __netif_tx_lock(tx_ring->txq, smp_processor_id());
if (qlcnic_tx_avail(tx_ring) > TX_STOP_THRESH) {
netif_wake_queue(netdev);
- adapter->tx_timeo_cnt = 0;
adapter->stats.xmit_on++;
}
- __netif_tx_unlock(tx_ring->txq);
}
+ adapter->tx_timeo_cnt = 0;
}
/*
* If everything is freed up to consumer then check if the ring is full
@@ -1898,6 +2158,25 @@ static int qlcnic_poll(struct napi_struct *napi, int budget)
return work_done;
}
+static int qlcnic_rx_poll(struct napi_struct *napi, int budget)
+{
+ struct qlcnic_host_sds_ring *sds_ring =
+ container_of(napi, struct qlcnic_host_sds_ring, napi);
+
+ struct qlcnic_adapter *adapter = sds_ring->adapter;
+ int work_done;
+
+ work_done = qlcnic_process_rcv_ring(sds_ring, budget);
+
+ if (work_done < budget) {
+ napi_complete(&sds_ring->napi);
+ if (test_bit(__QLCNIC_DEV_UP, &adapter->state))
+ qlcnic_enable_int(sds_ring);
+ }
+
+ return work_done;
+}
+
#ifdef CONFIG_NET_POLL_CONTROLLER
static void qlcnic_poll_controller(struct net_device *netdev)
{
@@ -2109,7 +2388,7 @@ qlcnic_fwinit_work(struct work_struct *work)
{
struct qlcnic_adapter *adapter = container_of(work,
struct qlcnic_adapter, fw_work.work);
- u32 dev_state = 0xf;
+ u32 dev_state = 0xf, npar_state;
if (qlcnic_api_lock(adapter))
goto err_ret;
@@ -2122,6 +2401,19 @@ qlcnic_fwinit_work(struct work_struct *work)
return;
}
+ if (adapter->op_mode == QLCNIC_NON_PRIV_FUNC) {
+ npar_state = QLCRD32(adapter, QLCNIC_CRB_DEV_NPAR_STATE);
+ if (npar_state == QLCNIC_DEV_NPAR_RDY) {
+ qlcnic_api_unlock(adapter);
+ goto wait_npar;
+ } else {
+ qlcnic_schedule_work(adapter, qlcnic_fwinit_work,
+ FW_POLL_DELAY);
+ qlcnic_api_unlock(adapter);
+ return;
+ }
+ }
+
if (adapter->fw_wait_cnt++ > adapter->reset_ack_timeo) {
dev_err(&adapter->pdev->dev, "Reset:Failed to get ack %d sec\n",
adapter->reset_ack_timeo);
@@ -2154,7 +2446,7 @@ skip_ack_check:
qlcnic_api_unlock(adapter);
- if (!qlcnic_start_firmware(adapter)) {
+ if (!adapter->nic_ops->start_firmware(adapter)) {
qlcnic_schedule_work(adapter, qlcnic_attach_work, 0);
return;
}
@@ -2163,6 +2455,7 @@ skip_ack_check:
qlcnic_api_unlock(adapter);
+wait_npar:
dev_state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE);
QLCDB(adapter, HW, "Func waiting: Device state=%u\n", dev_state);
@@ -2177,7 +2470,7 @@ skip_ack_check:
break;
default:
- if (!qlcnic_start_firmware(adapter)) {
+ if (!adapter->nic_ops->start_firmware(adapter)) {
qlcnic_schedule_work(adapter, qlcnic_attach_work, 0);
return;
}
@@ -2202,10 +2495,6 @@ qlcnic_detach_work(struct work_struct *work)
qlcnic_down(adapter, netdev);
- rtnl_lock();
- qlcnic_detach(adapter);
- rtnl_unlock();
-
status = QLCRD32(adapter, QLCNIC_PEG_HALT_STATUS1);
if (status & QLCNIC_RCODE_FATAL_ERROR)
@@ -2237,6 +2526,7 @@ qlcnic_dev_request_reset(struct qlcnic_adapter *adapter)
{
u32 state;
+ adapter->need_fw_reset = 1;
if (qlcnic_api_lock(adapter))
return;
@@ -2251,10 +2541,36 @@ qlcnic_dev_request_reset(struct qlcnic_adapter *adapter)
qlcnic_api_unlock(adapter);
}
+/* Transit to NPAR READY state from NPAR NOT READY state */
+static void
+qlcnic_dev_set_npar_ready(struct qlcnic_adapter *adapter)
+{
+ u32 state;
+
+ if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED) ||
+ adapter->op_mode == QLCNIC_NON_PRIV_FUNC)
+ return;
+ if (qlcnic_api_lock(adapter))
+ return;
+
+ state = QLCRD32(adapter, QLCNIC_CRB_DEV_NPAR_STATE);
+
+ if (state != QLCNIC_DEV_NPAR_RDY) {
+ QLCWR32(adapter, QLCNIC_CRB_DEV_NPAR_STATE,
+ QLCNIC_DEV_NPAR_RDY);
+ QLCDB(adapter, DRV, "NPAR READY state set\n");
+ }
+
+ qlcnic_api_unlock(adapter);
+}
+
static void
qlcnic_schedule_work(struct qlcnic_adapter *adapter,
work_func_t func, int delay)
{
+ if (test_bit(__QLCNIC_AER, &adapter->state))
+ return;
+
INIT_DELAYED_WORK(&adapter->fw_work, func);
schedule_delayed_work(&adapter->fw_work, round_jiffies_relative(delay));
}
@@ -2274,18 +2590,10 @@ qlcnic_attach_work(struct work_struct *work)
struct qlcnic_adapter *adapter = container_of(work,
struct qlcnic_adapter, fw_work.work);
struct net_device *netdev = adapter->netdev;
- int err;
if (netif_running(netdev)) {
- err = qlcnic_attach(adapter);
- if (err)
- goto done;
-
- err = qlcnic_up(adapter, netdev);
- if (err) {
- qlcnic_detach(adapter);
+ if (qlcnic_up(adapter, netdev))
goto done;
- }
qlcnic_config_indev_addr(netdev, NETDEV_UP);
}
@@ -2322,6 +2630,13 @@ qlcnic_check_health(struct qlcnic_adapter *adapter)
adapter->fw_fail_cnt = 0;
if (adapter->need_fw_reset)
goto detach;
+
+ if (adapter->reset_context &&
+ auto_fw_reset == AUTO_FW_RESET_ENABLED) {
+ qlcnic_reset_hw_context(adapter);
+ adapter->netdev->trans_start = jiffies;
+ }
+
return 0;
}
@@ -2330,7 +2645,8 @@ qlcnic_check_health(struct qlcnic_adapter *adapter)
qlcnic_dev_request_reset(adapter);
- clear_bit(__QLCNIC_FW_ATTACHED, &adapter->state);
+ if ((auto_fw_reset == AUTO_FW_RESET_ENABLED))
+ clear_bit(__QLCNIC_FW_ATTACHED, &adapter->state);
dev_info(&netdev->dev, "firmware hang detected\n");
@@ -2365,6 +2681,161 @@ reschedule:
qlcnic_schedule_work(adapter, qlcnic_fw_poll_work, FW_POLL_DELAY);
}
+static int qlcnic_is_first_func(struct pci_dev *pdev)
+{
+ struct pci_dev *oth_pdev;
+ int val = pdev->devfn;
+
+ while (val-- > 0) {
+ oth_pdev = pci_get_domain_bus_and_slot(pci_domain_nr
+ (pdev->bus), pdev->bus->number,
+ PCI_DEVFN(PCI_SLOT(pdev->devfn), val));
+ if (!oth_pdev)
+ continue;
+
+ if (oth_pdev->current_state != PCI_D3cold) {
+ pci_dev_put(oth_pdev);
+ return 0;
+ }
+ pci_dev_put(oth_pdev);
+ }
+ return 1;
+}
+
+static int qlcnic_attach_func(struct pci_dev *pdev)
+{
+ int err, first_func;
+ struct qlcnic_adapter *adapter = pci_get_drvdata(pdev);
+ struct net_device *netdev = adapter->netdev;
+
+ pdev->error_state = pci_channel_io_normal;
+
+ err = pci_enable_device(pdev);
+ if (err)
+ return err;
+
+ pci_set_power_state(pdev, PCI_D0);
+ pci_set_master(pdev);
+ pci_restore_state(pdev);
+
+ first_func = qlcnic_is_first_func(pdev);
+
+ if (qlcnic_api_lock(adapter))
+ return -EINVAL;
+
+ if (first_func) {
+ adapter->need_fw_reset = 1;
+ set_bit(__QLCNIC_START_FW, &adapter->state);
+ QLCWR32(adapter, QLCNIC_CRB_DEV_STATE, QLCNIC_DEV_INITIALIZING);
+ QLCDB(adapter, DRV, "Restarting fw\n");
+ }
+ qlcnic_api_unlock(adapter);
+
+ err = adapter->nic_ops->start_firmware(adapter);
+ if (err)
+ return err;
+
+ qlcnic_clr_drv_state(adapter);
+ qlcnic_setup_intr(adapter);
+
+ if (netif_running(netdev)) {
+ err = qlcnic_attach(adapter);
+ if (err) {
+ qlcnic_clr_all_drv_state(adapter);
+ clear_bit(__QLCNIC_AER, &adapter->state);
+ netif_device_attach(netdev);
+ return err;
+ }
+
+ err = qlcnic_up(adapter, netdev);
+ if (err)
+ goto done;
+
+ qlcnic_config_indev_addr(netdev, NETDEV_UP);
+ }
+ done:
+ netif_device_attach(netdev);
+ return err;
+}
+
+static pci_ers_result_t qlcnic_io_error_detected(struct pci_dev *pdev,
+ pci_channel_state_t state)
+{
+ struct qlcnic_adapter *adapter = pci_get_drvdata(pdev);
+ struct net_device *netdev = adapter->netdev;
+
+ if (state == pci_channel_io_perm_failure)
+ return PCI_ERS_RESULT_DISCONNECT;
+
+ if (state == pci_channel_io_normal)
+ return PCI_ERS_RESULT_RECOVERED;
+
+ set_bit(__QLCNIC_AER, &adapter->state);
+ netif_device_detach(netdev);
+
+ cancel_delayed_work_sync(&adapter->fw_work);
+
+ if (netif_running(netdev))
+ qlcnic_down(adapter, netdev);
+
+ qlcnic_detach(adapter);
+ qlcnic_teardown_intr(adapter);
+
+ clear_bit(__QLCNIC_RESETTING, &adapter->state);
+
+ pci_save_state(pdev);
+ pci_disable_device(pdev);
+
+ return PCI_ERS_RESULT_NEED_RESET;
+}
+
+static pci_ers_result_t qlcnic_io_slot_reset(struct pci_dev *pdev)
+{
+ return qlcnic_attach_func(pdev) ? PCI_ERS_RESULT_DISCONNECT :
+ PCI_ERS_RESULT_RECOVERED;
+}
+
+static void qlcnic_io_resume(struct pci_dev *pdev)
+{
+ struct qlcnic_adapter *adapter = pci_get_drvdata(pdev);
+
+ pci_cleanup_aer_uncorrect_error_status(pdev);
+
+ if (QLCRD32(adapter, QLCNIC_CRB_DEV_STATE) == QLCNIC_DEV_READY &&
+ test_and_clear_bit(__QLCNIC_AER, &adapter->state))
+ qlcnic_schedule_work(adapter, qlcnic_fw_poll_work,
+ FW_POLL_DELAY);
+}
+
+
+static int
+qlcnicvf_start_firmware(struct qlcnic_adapter *adapter)
+{
+ int err;
+
+ err = qlcnic_can_start_firmware(adapter);
+ if (err)
+ return err;
+
+ qlcnic_check_options(adapter);
+
+ adapter->need_fw_reset = 0;
+
+ return err;
+}
+
+static int
+qlcnicvf_config_bridged_mode(struct qlcnic_adapter *adapter, u32 enable)
+{
+ return -EOPNOTSUPP;
+}
+
+static int
+qlcnicvf_config_led(struct qlcnic_adapter *adapter, u32 state, u32 rate)
+{
+ return -EOPNOTSUPP;
+}
+
static ssize_t
qlcnic_store_bridged_mode(struct device *dev,
struct device_attribute *attr, const char *buf, size_t len)
@@ -2376,13 +2847,13 @@ qlcnic_store_bridged_mode(struct device *dev,
if (!(adapter->capabilities & QLCNIC_FW_CAPABILITY_BDG))
goto err_out;
- if (adapter->is_up != QLCNIC_ADAPTER_UP_MAGIC)
+ if (!test_bit(__QLCNIC_DEV_UP, &adapter->state))
goto err_out;
if (strict_strtoul(buf, 2, &new))
goto err_out;
- if (!qlcnic_config_bridged_mode(adapter, !!new))
+ if (!adapter->nic_ops->config_bridged_mode(adapter, !!new))
ret = len;
err_out:
@@ -2585,6 +3056,361 @@ static struct bin_attribute bin_attr_mem = {
.write = qlcnic_sysfs_write_mem,
};
+static int
+validate_pm_config(struct qlcnic_adapter *adapter,
+ struct qlcnic_pm_func_cfg *pm_cfg, int count)
+{
+
+ u8 src_pci_func, s_esw_id, d_esw_id;
+ u8 dest_pci_func;
+ int i;
+
+ for (i = 0; i < count; i++) {
+ src_pci_func = pm_cfg[i].pci_func;
+ dest_pci_func = pm_cfg[i].dest_npar;
+ if (src_pci_func >= QLCNIC_MAX_PCI_FUNC
+ || dest_pci_func >= QLCNIC_MAX_PCI_FUNC)
+ return QL_STATUS_INVALID_PARAM;
+
+ if (adapter->npars[src_pci_func].type != QLCNIC_TYPE_NIC)
+ return QL_STATUS_INVALID_PARAM;
+
+ if (adapter->npars[dest_pci_func].type != QLCNIC_TYPE_NIC)
+ return QL_STATUS_INVALID_PARAM;
+
+ if (!IS_VALID_MODE(pm_cfg[i].action))
+ return QL_STATUS_INVALID_PARAM;
+
+ s_esw_id = adapter->npars[src_pci_func].phy_port;
+ d_esw_id = adapter->npars[dest_pci_func].phy_port;
+
+ if (s_esw_id != d_esw_id)
+ return QL_STATUS_INVALID_PARAM;
+
+ }
+ return 0;
+
+}
+
+static ssize_t
+qlcnic_sysfs_write_pm_config(struct file *filp, struct kobject *kobj,
+ struct bin_attribute *attr, char *buf, loff_t offset, size_t size)
+{
+ struct device *dev = container_of(kobj, struct device, kobj);
+ struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
+ struct qlcnic_pm_func_cfg *pm_cfg;
+ u32 id, action, pci_func;
+ int count, rem, i, ret;
+
+ count = size / sizeof(struct qlcnic_pm_func_cfg);
+ rem = size % sizeof(struct qlcnic_pm_func_cfg);
+ if (rem)
+ return QL_STATUS_INVALID_PARAM;
+
+ pm_cfg = (struct qlcnic_pm_func_cfg *) buf;
+
+ ret = validate_pm_config(adapter, pm_cfg, count);
+ if (ret)
+ return ret;
+ for (i = 0; i < count; i++) {
+ pci_func = pm_cfg[i].pci_func;
+ action = pm_cfg[i].action;
+ id = adapter->npars[pci_func].phy_port;
+ ret = qlcnic_config_port_mirroring(adapter, id,
+ action, pci_func);
+ if (ret)
+ return ret;
+ }
+
+ for (i = 0; i < count; i++) {
+ pci_func = pm_cfg[i].pci_func;
+ id = adapter->npars[pci_func].phy_port;
+ adapter->npars[pci_func].enable_pm = pm_cfg[i].action;
+ adapter->npars[pci_func].dest_npar = id;
+ }
+ return size;
+}
+
+static ssize_t
+qlcnic_sysfs_read_pm_config(struct file *filp, struct kobject *kobj,
+ struct bin_attribute *attr, char *buf, loff_t offset, size_t size)
+{
+ struct device *dev = container_of(kobj, struct device, kobj);
+ struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
+ struct qlcnic_pm_func_cfg pm_cfg[QLCNIC_MAX_PCI_FUNC];
+ int i;
+
+ if (size != sizeof(pm_cfg))
+ return QL_STATUS_INVALID_PARAM;
+
+ for (i = 0; i < QLCNIC_MAX_PCI_FUNC; i++) {
+ if (adapter->npars[i].type != QLCNIC_TYPE_NIC)
+ continue;
+ pm_cfg[i].action = adapter->npars[i].enable_pm;
+ pm_cfg[i].dest_npar = 0;
+ pm_cfg[i].pci_func = i;
+ }
+ memcpy(buf, &pm_cfg, size);
+
+ return size;
+}
+
+static int
+validate_esw_config(struct qlcnic_adapter *adapter,
+ struct qlcnic_esw_func_cfg *esw_cfg, int count)
+{
+ u8 pci_func;
+ int i;
+
+ for (i = 0; i < count; i++) {
+ pci_func = esw_cfg[i].pci_func;
+ if (pci_func >= QLCNIC_MAX_PCI_FUNC)
+ return QL_STATUS_INVALID_PARAM;
+
+ if (adapter->npars[i].type != QLCNIC_TYPE_NIC)
+ return QL_STATUS_INVALID_PARAM;
+
+ if (esw_cfg->host_vlan_tag == 1)
+ if (!IS_VALID_VLAN(esw_cfg[i].vlan_id))
+ return QL_STATUS_INVALID_PARAM;
+
+ if (!IS_VALID_MODE(esw_cfg[i].promisc_mode)
+ || !IS_VALID_MODE(esw_cfg[i].host_vlan_tag)
+ || !IS_VALID_MODE(esw_cfg[i].mac_learning)
+ || !IS_VALID_MODE(esw_cfg[i].discard_tagged))
+ return QL_STATUS_INVALID_PARAM;
+ }
+
+ return 0;
+}
+
+static ssize_t
+qlcnic_sysfs_write_esw_config(struct file *file, struct kobject *kobj,
+ struct bin_attribute *attr, char *buf, loff_t offset, size_t size)
+{
+ struct device *dev = container_of(kobj, struct device, kobj);
+ struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
+ struct qlcnic_esw_func_cfg *esw_cfg;
+ int count, rem, i, ret;
+ u8 id, pci_func;
+
+ count = size / sizeof(struct qlcnic_esw_func_cfg);
+ rem = size % sizeof(struct qlcnic_esw_func_cfg);
+ if (rem)
+ return QL_STATUS_INVALID_PARAM;
+
+ esw_cfg = (struct qlcnic_esw_func_cfg *) buf;
+ ret = validate_esw_config(adapter, esw_cfg, count);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < count; i++) {
+ pci_func = esw_cfg[i].pci_func;
+ id = adapter->npars[pci_func].phy_port;
+ ret = qlcnic_config_switch_port(adapter, id,
+ esw_cfg[i].host_vlan_tag,
+ esw_cfg[i].discard_tagged,
+ esw_cfg[i].promisc_mode,
+ esw_cfg[i].mac_learning,
+ esw_cfg[i].pci_func,
+ esw_cfg[i].vlan_id);
+ if (ret)
+ return ret;
+ }
+
+ for (i = 0; i < count; i++) {
+ pci_func = esw_cfg[i].pci_func;
+ adapter->npars[pci_func].promisc_mode = esw_cfg[i].promisc_mode;
+ adapter->npars[pci_func].mac_learning = esw_cfg[i].mac_learning;
+ adapter->npars[pci_func].vlan_id = esw_cfg[i].vlan_id;
+ adapter->npars[pci_func].discard_tagged =
+ esw_cfg[i].discard_tagged;
+ adapter->npars[pci_func].host_vlan_tag =
+ esw_cfg[i].host_vlan_tag;
+ }
+
+ return size;
+}
+
+static ssize_t
+qlcnic_sysfs_read_esw_config(struct file *file, struct kobject *kobj,
+ struct bin_attribute *attr, char *buf, loff_t offset, size_t size)
+{
+ struct device *dev = container_of(kobj, struct device, kobj);
+ struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
+ struct qlcnic_esw_func_cfg esw_cfg[QLCNIC_MAX_PCI_FUNC];
+ int i;
+
+ if (size != sizeof(esw_cfg))
+ return QL_STATUS_INVALID_PARAM;
+
+ for (i = 0; i < QLCNIC_MAX_PCI_FUNC; i++) {
+ if (adapter->npars[i].type != QLCNIC_TYPE_NIC)
+ continue;
+
+ esw_cfg[i].host_vlan_tag = adapter->npars[i].host_vlan_tag;
+ esw_cfg[i].promisc_mode = adapter->npars[i].promisc_mode;
+ esw_cfg[i].discard_tagged = adapter->npars[i].discard_tagged;
+ esw_cfg[i].vlan_id = adapter->npars[i].vlan_id;
+ esw_cfg[i].mac_learning = adapter->npars[i].mac_learning;
+ }
+ memcpy(buf, &esw_cfg, size);
+
+ return size;
+}
+
+static int
+validate_npar_config(struct qlcnic_adapter *adapter,
+ struct qlcnic_npar_func_cfg *np_cfg, int count)
+{
+ u8 pci_func, i;
+
+ for (i = 0; i < count; i++) {
+ pci_func = np_cfg[i].pci_func;
+ if (pci_func >= QLCNIC_MAX_PCI_FUNC)
+ return QL_STATUS_INVALID_PARAM;
+
+ if (adapter->npars[pci_func].type != QLCNIC_TYPE_NIC)
+ return QL_STATUS_INVALID_PARAM;
+
+ if (!IS_VALID_BW(np_cfg[i].min_bw)
+ || !IS_VALID_BW(np_cfg[i].max_bw)
+ || !IS_VALID_RX_QUEUES(np_cfg[i].max_rx_queues)
+ || !IS_VALID_TX_QUEUES(np_cfg[i].max_tx_queues))
+ return QL_STATUS_INVALID_PARAM;
+ }
+ return 0;
+}
+
+static ssize_t
+qlcnic_sysfs_write_npar_config(struct file *file, struct kobject *kobj,
+ struct bin_attribute *attr, char *buf, loff_t offset, size_t size)
+{
+ struct device *dev = container_of(kobj, struct device, kobj);
+ struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
+ struct qlcnic_info nic_info;
+ struct qlcnic_npar_func_cfg *np_cfg;
+ int i, count, rem, ret;
+ u8 pci_func;
+
+ count = size / sizeof(struct qlcnic_npar_func_cfg);
+ rem = size % sizeof(struct qlcnic_npar_func_cfg);
+ if (rem)
+ return QL_STATUS_INVALID_PARAM;
+
+ np_cfg = (struct qlcnic_npar_func_cfg *) buf;
+ ret = validate_npar_config(adapter, np_cfg, count);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < count ; i++) {
+ pci_func = np_cfg[i].pci_func;
+ ret = qlcnic_get_nic_info(adapter, &nic_info, pci_func);
+ if (ret)
+ return ret;
+ nic_info.pci_func = pci_func;
+ nic_info.min_tx_bw = np_cfg[i].min_bw;
+ nic_info.max_tx_bw = np_cfg[i].max_bw;
+ ret = qlcnic_set_nic_info(adapter, &nic_info);
+ if (ret)
+ return ret;
+ adapter->npars[i].min_bw = nic_info.min_tx_bw;
+ adapter->npars[i].max_bw = nic_info.max_tx_bw;
+ }
+
+ return size;
+
+}
+static ssize_t
+qlcnic_sysfs_read_npar_config(struct file *file, struct kobject *kobj,
+ struct bin_attribute *attr, char *buf, loff_t offset, size_t size)
+{
+ struct device *dev = container_of(kobj, struct device, kobj);
+ struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
+ struct qlcnic_info nic_info;
+ struct qlcnic_npar_func_cfg np_cfg[QLCNIC_MAX_PCI_FUNC];
+ int i, ret;
+
+ if (size != sizeof(np_cfg))
+ return QL_STATUS_INVALID_PARAM;
+
+ for (i = 0; i < QLCNIC_MAX_PCI_FUNC ; i++) {
+ if (adapter->npars[i].type != QLCNIC_TYPE_NIC)
+ continue;
+ ret = qlcnic_get_nic_info(adapter, &nic_info, i);
+ if (ret)
+ return ret;
+
+ np_cfg[i].pci_func = i;
+ np_cfg[i].op_mode = nic_info.op_mode;
+ np_cfg[i].port_num = nic_info.phys_port;
+ np_cfg[i].fw_capab = nic_info.capabilities;
+ np_cfg[i].min_bw = nic_info.min_tx_bw ;
+ np_cfg[i].max_bw = nic_info.max_tx_bw;
+ np_cfg[i].max_tx_queues = nic_info.max_tx_ques;
+ np_cfg[i].max_rx_queues = nic_info.max_rx_ques;
+ }
+ memcpy(buf, &np_cfg, size);
+ return size;
+}
+
+static ssize_t
+qlcnic_sysfs_read_pci_config(struct file *file, struct kobject *kobj,
+ struct bin_attribute *attr, char *buf, loff_t offset, size_t size)
+{
+ struct device *dev = container_of(kobj, struct device, kobj);
+ struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
+ struct qlcnic_pci_func_cfg pci_cfg[QLCNIC_MAX_PCI_FUNC];
+ struct qlcnic_pci_info pci_info[QLCNIC_MAX_PCI_FUNC];
+ int i, ret;
+
+ if (size != sizeof(pci_cfg))
+ return QL_STATUS_INVALID_PARAM;
+
+ ret = qlcnic_get_pci_info(adapter, pci_info);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < QLCNIC_MAX_PCI_FUNC ; i++) {
+ pci_cfg[i].pci_func = pci_info[i].id;
+ pci_cfg[i].func_type = pci_info[i].type;
+ pci_cfg[i].port_num = pci_info[i].default_port;
+ pci_cfg[i].min_bw = pci_info[i].tx_min_bw;
+ pci_cfg[i].max_bw = pci_info[i].tx_max_bw;
+ memcpy(&pci_cfg[i].def_mac_addr, &pci_info[i].mac, ETH_ALEN);
+ }
+ memcpy(buf, &pci_cfg, size);
+ return size;
+
+}
+static struct bin_attribute bin_attr_npar_config = {
+ .attr = {.name = "npar_config", .mode = (S_IRUGO | S_IWUSR)},
+ .size = 0,
+ .read = qlcnic_sysfs_read_npar_config,
+ .write = qlcnic_sysfs_write_npar_config,
+};
+
+static struct bin_attribute bin_attr_pci_config = {
+ .attr = {.name = "pci_config", .mode = (S_IRUGO | S_IWUSR)},
+ .size = 0,
+ .read = qlcnic_sysfs_read_pci_config,
+ .write = NULL,
+};
+
+static struct bin_attribute bin_attr_esw_config = {
+ .attr = {.name = "esw_config", .mode = (S_IRUGO | S_IWUSR)},
+ .size = 0,
+ .read = qlcnic_sysfs_read_esw_config,
+ .write = qlcnic_sysfs_write_esw_config,
+};
+
+static struct bin_attribute bin_attr_pm_config = {
+ .attr = {.name = "pm_config", .mode = (S_IRUGO | S_IWUSR)},
+ .size = 0,
+ .read = qlcnic_sysfs_read_pm_config,
+ .write = qlcnic_sysfs_write_pm_config,
+};
+
static void
qlcnic_create_sysfs_entries(struct qlcnic_adapter *adapter)
{
@@ -2610,23 +3436,45 @@ qlcnic_create_diag_entries(struct qlcnic_adapter *adapter)
{
struct device *dev = &adapter->pdev->dev;
+ if (adapter->op_mode == QLCNIC_NON_PRIV_FUNC)
+ return;
if (device_create_file(dev, &dev_attr_diag_mode))
dev_info(dev, "failed to create diag_mode sysfs entry\n");
if (device_create_bin_file(dev, &bin_attr_crb))
dev_info(dev, "failed to create crb sysfs entry\n");
if (device_create_bin_file(dev, &bin_attr_mem))
dev_info(dev, "failed to create mem sysfs entry\n");
-}
+ if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED) ||
+ adapter->op_mode != QLCNIC_MGMT_FUNC)
+ return;
+ if (device_create_bin_file(dev, &bin_attr_pci_config))
+ dev_info(dev, "failed to create pci config sysfs entry");
+ if (device_create_bin_file(dev, &bin_attr_npar_config))
+ dev_info(dev, "failed to create npar config sysfs entry");
+ if (device_create_bin_file(dev, &bin_attr_esw_config))
+ dev_info(dev, "failed to create esw config sysfs entry");
+ if (device_create_bin_file(dev, &bin_attr_pm_config))
+ dev_info(dev, "failed to create pm config sysfs entry");
+}
static void
qlcnic_remove_diag_entries(struct qlcnic_adapter *adapter)
{
struct device *dev = &adapter->pdev->dev;
+ if (adapter->op_mode == QLCNIC_NON_PRIV_FUNC)
+ return;
device_remove_file(dev, &dev_attr_diag_mode);
device_remove_bin_file(dev, &bin_attr_crb);
device_remove_bin_file(dev, &bin_attr_mem);
+ if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED) ||
+ adapter->op_mode != QLCNIC_MGMT_FUNC)
+ return;
+ device_remove_bin_file(dev, &bin_attr_pci_config);
+ device_remove_bin_file(dev, &bin_attr_npar_config);
+ device_remove_bin_file(dev, &bin_attr_esw_config);
+ device_remove_bin_file(dev, &bin_attr_pm_config);
}
#ifdef CONFIG_INET
@@ -2684,7 +3532,7 @@ recheck:
if (!adapter)
goto done;
- if (adapter->is_up != QLCNIC_ADAPTER_UP_MAGIC)
+ if (!test_bit(__QLCNIC_DEV_UP, &adapter->state))
goto done;
qlcnic_config_indev_addr(dev, event);
@@ -2720,7 +3568,7 @@ recheck:
if (!adapter)
goto done;
- if (adapter->is_up != QLCNIC_ADAPTER_UP_MAGIC)
+ if (!test_bit(__QLCNIC_DEV_UP, &adapter->state))
goto done;
switch (event) {
@@ -2750,6 +3598,11 @@ static void
qlcnic_config_indev_addr(struct net_device *dev, unsigned long event)
{ }
#endif
+static struct pci_error_handlers qlcnic_err_handler = {
+ .error_detected = qlcnic_io_error_detected,
+ .slot_reset = qlcnic_io_slot_reset,
+ .resume = qlcnic_io_resume,
+};
static struct pci_driver qlcnic_driver = {
.name = qlcnic_driver_name,
@@ -2760,11 +3613,14 @@ static struct pci_driver qlcnic_driver = {
.suspend = qlcnic_suspend,
.resume = qlcnic_resume,
#endif
- .shutdown = qlcnic_shutdown
+ .shutdown = qlcnic_shutdown,
+ .err_handler = &qlcnic_err_handler
+
};
static int __init qlcnic_init_module(void)
{
+ int ret;
printk(KERN_INFO "%s\n", qlcnic_driver_string);
@@ -2773,8 +3629,15 @@ static int __init qlcnic_init_module(void)
register_inetaddr_notifier(&qlcnic_inetaddr_cb);
#endif
+ ret = pci_register_driver(&qlcnic_driver);
+ if (ret) {
+#ifdef CONFIG_INET
+ unregister_inetaddr_notifier(&qlcnic_inetaddr_cb);
+ unregister_netdevice_notifier(&qlcnic_netdev_cb);
+#endif
+ }
- return pci_register_driver(&qlcnic_driver);
+ return ret;
}
module_init(qlcnic_init_module);
diff --git a/drivers/net/qlge/qlge.h b/drivers/net/qlge/qlge.h
index 20624ba44a3..a478786840a 100644
--- a/drivers/net/qlge/qlge.h
+++ b/drivers/net/qlge/qlge.h
@@ -16,9 +16,7 @@
*/
#define DRV_NAME "qlge"
#define DRV_STRING "QLogic 10 Gigabit PCI-E Ethernet Driver "
-#define DRV_VERSION "v1.00.00.23.00.00-01"
-
-#define PFX "qlge: "
+#define DRV_VERSION "v1.00.00.25.00.00-01"
#define WQ_ADDR_ALIGN 0x3 /* 4 byte alignment */
@@ -1062,7 +1060,7 @@ struct tx_buf_desc {
#define TX_DESC_LEN_MASK 0x000fffff
#define TX_DESC_C 0x40000000
#define TX_DESC_E 0x80000000
-} __attribute((packed));
+} __packed;
/*
* IOCB Definitions...
@@ -1095,7 +1093,7 @@ struct ob_mac_iocb_req {
__le16 vlan_tci;
__le16 reserved4;
struct tx_buf_desc tbd[TX_DESC_PER_IOCB];
-} __attribute((packed));
+} __packed;
struct ob_mac_iocb_rsp {
u8 opcode; /* */
@@ -1112,7 +1110,7 @@ struct ob_mac_iocb_rsp {
u32 tid;
u32 txq_idx;
__le32 reserved[13];
-} __attribute((packed));
+} __packed;
struct ob_mac_tso_iocb_req {
u8 opcode;
@@ -1140,7 +1138,7 @@ struct ob_mac_tso_iocb_req {
__le16 vlan_tci;
__le16 mss;
struct tx_buf_desc tbd[TX_DESC_PER_IOCB];
-} __attribute((packed));
+} __packed;
struct ob_mac_tso_iocb_rsp {
u8 opcode;
@@ -1157,7 +1155,7 @@ struct ob_mac_tso_iocb_rsp {
u32 tid;
u32 txq_idx;
__le32 reserved2[13];
-} __attribute((packed));
+} __packed;
struct ib_mac_iocb_rsp {
u8 opcode; /* 0x20 */
@@ -1216,7 +1214,7 @@ struct ib_mac_iocb_rsp {
#define IB_MAC_IOCB_RSP_HL 0x80
__le32 hdr_len; /* */
__le64 hdr_addr; /* */
-} __attribute((packed));
+} __packed;
struct ib_ae_iocb_rsp {
u8 opcode;
@@ -1237,7 +1235,7 @@ struct ib_ae_iocb_rsp {
#define PCI_ERR_ANON_BUF_RD 0x40
u8 q_id;
__le32 reserved[15];
-} __attribute((packed));
+} __packed;
/*
* These three structures are for generic
@@ -1249,7 +1247,7 @@ struct ql_net_rsp_iocb {
__le16 length;
__le32 tid;
__le32 reserved[14];
-} __attribute((packed));
+} __packed;
struct net_req_iocb {
u8 opcode;
@@ -1257,7 +1255,7 @@ struct net_req_iocb {
__le16 flags1;
__le32 tid;
__le32 reserved1[30];
-} __attribute((packed));
+} __packed;
/*
* tx ring initialization control block for chip.
@@ -1283,7 +1281,7 @@ struct wqicb {
__le16 rid;
__le64 addr;
__le64 cnsmr_idx_addr;
-} __attribute((packed));
+} __packed;
/*
* rx ring initialization control block for chip.
@@ -1317,7 +1315,7 @@ struct cqicb {
__le64 sbq_addr;
__le16 sbq_buf_size;
__le16 sbq_len; /* entry count */
-} __attribute((packed));
+} __packed;
struct ricb {
u8 base_cq;
@@ -1335,7 +1333,7 @@ struct ricb {
u8 hash_cq_id[1024];
__le32 ipv6_hash_key[10];
__le32 ipv4_hash_key[4];
-} __attribute((packed));
+} __packed;
/* SOFTWARE/DRIVER DATA STRUCTURES. */
@@ -2227,7 +2225,6 @@ int ql_dump_risc_ram_area(struct ql_adapter *qdev, void *buf,
u32 ram_addr, int word_count);
int ql_core_dump(struct ql_adapter *qdev,
struct ql_mpi_coredump *mpi_coredump);
-int ql_mb_sys_err(struct ql_adapter *qdev);
int ql_mb_about_fw(struct ql_adapter *qdev);
int ql_wol(struct ql_adapter *qdev);
int ql_mb_wol_set_magic(struct ql_adapter *qdev, u32 enable_wol);
@@ -2246,6 +2243,7 @@ netdev_tx_t ql_lb_send(struct sk_buff *skb, struct net_device *ndev);
void ql_check_lb_frame(struct ql_adapter *, struct sk_buff *);
int ql_own_firmware(struct ql_adapter *qdev);
int ql_clean_lb_rx_ring(struct rx_ring *rx_ring, int budget);
+void qlge_set_multicast_list(struct net_device *ndev);
#if 1
#define QL_ALL_DUMP
diff --git a/drivers/net/qlge/qlge_dbg.c b/drivers/net/qlge/qlge_dbg.c
index 68a1c9b91e7..4747492935e 100644
--- a/drivers/net/qlge/qlge_dbg.c
+++ b/drivers/net/qlge/qlge_dbg.c
@@ -1,3 +1,5 @@
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/slab.h>
#include "qlge.h"
@@ -446,7 +448,7 @@ static int ql_get_cam_entries(struct ql_adapter *qdev, u32 * buf)
MAC_ADDR_TYPE_CAM_MAC, i, value);
if (status) {
netif_err(qdev, drv, qdev->ndev,
- "Failed read of mac index register.\n");
+ "Failed read of mac index register\n");
goto err;
}
*buf++ = value[0]; /* lower MAC address */
@@ -458,7 +460,7 @@ static int ql_get_cam_entries(struct ql_adapter *qdev, u32 * buf)
MAC_ADDR_TYPE_MULTI_MAC, i, value);
if (status) {
netif_err(qdev, drv, qdev->ndev,
- "Failed read of mac index register.\n");
+ "Failed read of mac index register\n");
goto err;
}
*buf++ = value[0]; /* lower Mcast address */
@@ -482,7 +484,7 @@ static int ql_get_routing_entries(struct ql_adapter *qdev, u32 * buf)
status = ql_get_routing_reg(qdev, i, &value);
if (status) {
netif_err(qdev, drv, qdev->ndev,
- "Failed read of routing index register.\n");
+ "Failed read of routing index register\n");
goto err;
} else {
*buf++ = value;
@@ -668,7 +670,7 @@ static void ql_get_mac_protocol_registers(struct ql_adapter *qdev, u32 *buf)
max_offset = MAC_ADDR_MAX_MGMT_TU_DP_WCOUNT;
break;
default:
- printk(KERN_ERR"Bad type!!! 0x%08x\n", type);
+ pr_err("Bad type!!! 0x%08x\n", type);
max_index = 0;
max_offset = 0;
break;
@@ -738,7 +740,7 @@ int ql_core_dump(struct ql_adapter *qdev, struct ql_mpi_coredump *mpi_coredump)
int i;
if (!mpi_coredump) {
- netif_err(qdev, drv, qdev->ndev, "No memory available.\n");
+ netif_err(qdev, drv, qdev->ndev, "No memory available\n");
return -ENOMEM;
}
@@ -1234,15 +1236,10 @@ static void ql_get_core_dump(struct ql_adapter *qdev)
if (!netif_running(qdev->ndev)) {
netif_err(qdev, ifup, qdev->ndev,
- "Force Coredump can only be done from interface that is up.\n");
- return;
- }
-
- if (ql_mb_sys_err(qdev)) {
- netif_err(qdev, ifup, qdev->ndev,
- "Fail force coredump with ql_mb_sys_err().\n");
+ "Force Coredump can only be done from interface that is up\n");
return;
}
+ ql_queue_fw_error(qdev);
}
void ql_gen_reg_dump(struct ql_adapter *qdev,
@@ -1339,7 +1336,7 @@ void ql_mpi_core_to_log(struct work_struct *work)
"Core is dumping to log file!\n");
for (i = 0; i < count; i += 8) {
- printk(KERN_ERR "%.08x: %.08x %.08x %.08x %.08x %.08x "
+ pr_err("%.08x: %.08x %.08x %.08x %.08x %.08x "
"%.08x %.08x %.08x\n", i,
tmp[i + 0],
tmp[i + 1],
@@ -1361,71 +1358,43 @@ static void ql_dump_intr_states(struct ql_adapter *qdev)
for (i = 0; i < qdev->intr_count; i++) {
ql_write32(qdev, INTR_EN, qdev->intr_context[i].intr_read_mask);
value = ql_read32(qdev, INTR_EN);
- printk(KERN_ERR PFX
- "%s: Interrupt %d is %s.\n",
+ pr_err("%s: Interrupt %d is %s\n",
qdev->ndev->name, i,
(value & INTR_EN_EN ? "enabled" : "disabled"));
}
}
+#define DUMP_XGMAC(qdev, reg) \
+do { \
+ u32 data; \
+ ql_read_xgmac_reg(qdev, reg, &data); \
+ pr_err("%s: %s = 0x%.08x\n", qdev->ndev->name, #reg, data); \
+} while (0)
+
void ql_dump_xgmac_control_regs(struct ql_adapter *qdev)
{
- u32 data;
if (ql_sem_spinlock(qdev, qdev->xg_sem_mask)) {
- printk(KERN_ERR "%s: Couldn't get xgmac sem.\n", __func__);
+ pr_err("%s: Couldn't get xgmac sem\n", __func__);
return;
}
- ql_read_xgmac_reg(qdev, PAUSE_SRC_LO, &data);
- printk(KERN_ERR PFX "%s: PAUSE_SRC_LO = 0x%.08x.\n", qdev->ndev->name,
- data);
- ql_read_xgmac_reg(qdev, PAUSE_SRC_HI, &data);
- printk(KERN_ERR PFX "%s: PAUSE_SRC_HI = 0x%.08x.\n", qdev->ndev->name,
- data);
- ql_read_xgmac_reg(qdev, GLOBAL_CFG, &data);
- printk(KERN_ERR PFX "%s: GLOBAL_CFG = 0x%.08x.\n", qdev->ndev->name,
- data);
- ql_read_xgmac_reg(qdev, TX_CFG, &data);
- printk(KERN_ERR PFX "%s: TX_CFG = 0x%.08x.\n", qdev->ndev->name, data);
- ql_read_xgmac_reg(qdev, RX_CFG, &data);
- printk(KERN_ERR PFX "%s: RX_CFG = 0x%.08x.\n", qdev->ndev->name, data);
- ql_read_xgmac_reg(qdev, FLOW_CTL, &data);
- printk(KERN_ERR PFX "%s: FLOW_CTL = 0x%.08x.\n", qdev->ndev->name,
- data);
- ql_read_xgmac_reg(qdev, PAUSE_OPCODE, &data);
- printk(KERN_ERR PFX "%s: PAUSE_OPCODE = 0x%.08x.\n", qdev->ndev->name,
- data);
- ql_read_xgmac_reg(qdev, PAUSE_TIMER, &data);
- printk(KERN_ERR PFX "%s: PAUSE_TIMER = 0x%.08x.\n", qdev->ndev->name,
- data);
- ql_read_xgmac_reg(qdev, PAUSE_FRM_DEST_LO, &data);
- printk(KERN_ERR PFX "%s: PAUSE_FRM_DEST_LO = 0x%.08x.\n",
- qdev->ndev->name, data);
- ql_read_xgmac_reg(qdev, PAUSE_FRM_DEST_HI, &data);
- printk(KERN_ERR PFX "%s: PAUSE_FRM_DEST_HI = 0x%.08x.\n",
- qdev->ndev->name, data);
- ql_read_xgmac_reg(qdev, MAC_TX_PARAMS, &data);
- printk(KERN_ERR PFX "%s: MAC_TX_PARAMS = 0x%.08x.\n", qdev->ndev->name,
- data);
- ql_read_xgmac_reg(qdev, MAC_RX_PARAMS, &data);
- printk(KERN_ERR PFX "%s: MAC_RX_PARAMS = 0x%.08x.\n", qdev->ndev->name,
- data);
- ql_read_xgmac_reg(qdev, MAC_SYS_INT, &data);
- printk(KERN_ERR PFX "%s: MAC_SYS_INT = 0x%.08x.\n", qdev->ndev->name,
- data);
- ql_read_xgmac_reg(qdev, MAC_SYS_INT_MASK, &data);
- printk(KERN_ERR PFX "%s: MAC_SYS_INT_MASK = 0x%.08x.\n",
- qdev->ndev->name, data);
- ql_read_xgmac_reg(qdev, MAC_MGMT_INT, &data);
- printk(KERN_ERR PFX "%s: MAC_MGMT_INT = 0x%.08x.\n", qdev->ndev->name,
- data);
- ql_read_xgmac_reg(qdev, MAC_MGMT_IN_MASK, &data);
- printk(KERN_ERR PFX "%s: MAC_MGMT_IN_MASK = 0x%.08x.\n",
- qdev->ndev->name, data);
- ql_read_xgmac_reg(qdev, EXT_ARB_MODE, &data);
- printk(KERN_ERR PFX "%s: EXT_ARB_MODE = 0x%.08x.\n", qdev->ndev->name,
- data);
+ DUMP_XGMAC(qdev, PAUSE_SRC_LO);
+ DUMP_XGMAC(qdev, PAUSE_SRC_HI);
+ DUMP_XGMAC(qdev, GLOBAL_CFG);
+ DUMP_XGMAC(qdev, TX_CFG);
+ DUMP_XGMAC(qdev, RX_CFG);
+ DUMP_XGMAC(qdev, FLOW_CTL);
+ DUMP_XGMAC(qdev, PAUSE_OPCODE);
+ DUMP_XGMAC(qdev, PAUSE_TIMER);
+ DUMP_XGMAC(qdev, PAUSE_FRM_DEST_LO);
+ DUMP_XGMAC(qdev, PAUSE_FRM_DEST_HI);
+ DUMP_XGMAC(qdev, MAC_TX_PARAMS);
+ DUMP_XGMAC(qdev, MAC_RX_PARAMS);
+ DUMP_XGMAC(qdev, MAC_SYS_INT);
+ DUMP_XGMAC(qdev, MAC_SYS_INT_MASK);
+ DUMP_XGMAC(qdev, MAC_MGMT_INT);
+ DUMP_XGMAC(qdev, MAC_MGMT_IN_MASK);
+ DUMP_XGMAC(qdev, EXT_ARB_MODE);
ql_sem_unlock(qdev, qdev->xg_sem_mask);
-
}
static void ql_dump_ets_regs(struct ql_adapter *qdev)
@@ -1442,14 +1411,12 @@ static void ql_dump_cam_entries(struct ql_adapter *qdev)
return;
for (i = 0; i < 4; i++) {
if (ql_get_mac_addr_reg(qdev, MAC_ADDR_TYPE_CAM_MAC, i, value)) {
- printk(KERN_ERR PFX
- "%s: Failed read of mac index register.\n",
+ pr_err("%s: Failed read of mac index register\n",
__func__);
return;
} else {
if (value[0])
- printk(KERN_ERR PFX
- "%s: CAM index %d CAM Lookup Lower = 0x%.08x:%.08x, Output = 0x%.08x.\n",
+ pr_err("%s: CAM index %d CAM Lookup Lower = 0x%.08x:%.08x, Output = 0x%.08x\n",
qdev->ndev->name, i, value[1], value[0],
value[2]);
}
@@ -1457,14 +1424,12 @@ static void ql_dump_cam_entries(struct ql_adapter *qdev)
for (i = 0; i < 32; i++) {
if (ql_get_mac_addr_reg
(qdev, MAC_ADDR_TYPE_MULTI_MAC, i, value)) {
- printk(KERN_ERR PFX
- "%s: Failed read of mac index register.\n",
+ pr_err("%s: Failed read of mac index register\n",
__func__);
return;
} else {
if (value[0])
- printk(KERN_ERR PFX
- "%s: MCAST index %d CAM Lookup Lower = 0x%.08x:%.08x.\n",
+ pr_err("%s: MCAST index %d CAM Lookup Lower = 0x%.08x:%.08x\n",
qdev->ndev->name, i, value[1], value[0]);
}
}
@@ -1481,129 +1446,77 @@ void ql_dump_routing_entries(struct ql_adapter *qdev)
for (i = 0; i < 16; i++) {
value = 0;
if (ql_get_routing_reg(qdev, i, &value)) {
- printk(KERN_ERR PFX
- "%s: Failed read of routing index register.\n",
+ pr_err("%s: Failed read of routing index register\n",
__func__);
return;
} else {
if (value)
- printk(KERN_ERR PFX
- "%s: Routing Mask %d = 0x%.08x.\n",
+ pr_err("%s: Routing Mask %d = 0x%.08x\n",
qdev->ndev->name, i, value);
}
}
ql_sem_unlock(qdev, SEM_RT_IDX_MASK);
}
+#define DUMP_REG(qdev, reg) \
+ pr_err("%-32s= 0x%x\n", #reg, ql_read32(qdev, reg))
+
void ql_dump_regs(struct ql_adapter *qdev)
{
- printk(KERN_ERR PFX "reg dump for function #%d.\n", qdev->func);
- printk(KERN_ERR PFX "SYS = 0x%x.\n",
- ql_read32(qdev, SYS));
- printk(KERN_ERR PFX "RST_FO = 0x%x.\n",
- ql_read32(qdev, RST_FO));
- printk(KERN_ERR PFX "FSC = 0x%x.\n",
- ql_read32(qdev, FSC));
- printk(KERN_ERR PFX "CSR = 0x%x.\n",
- ql_read32(qdev, CSR));
- printk(KERN_ERR PFX "ICB_RID = 0x%x.\n",
- ql_read32(qdev, ICB_RID));
- printk(KERN_ERR PFX "ICB_L = 0x%x.\n",
- ql_read32(qdev, ICB_L));
- printk(KERN_ERR PFX "ICB_H = 0x%x.\n",
- ql_read32(qdev, ICB_H));
- printk(KERN_ERR PFX "CFG = 0x%x.\n",
- ql_read32(qdev, CFG));
- printk(KERN_ERR PFX "BIOS_ADDR = 0x%x.\n",
- ql_read32(qdev, BIOS_ADDR));
- printk(KERN_ERR PFX "STS = 0x%x.\n",
- ql_read32(qdev, STS));
- printk(KERN_ERR PFX "INTR_EN = 0x%x.\n",
- ql_read32(qdev, INTR_EN));
- printk(KERN_ERR PFX "INTR_MASK = 0x%x.\n",
- ql_read32(qdev, INTR_MASK));
- printk(KERN_ERR PFX "ISR1 = 0x%x.\n",
- ql_read32(qdev, ISR1));
- printk(KERN_ERR PFX "ISR2 = 0x%x.\n",
- ql_read32(qdev, ISR2));
- printk(KERN_ERR PFX "ISR3 = 0x%x.\n",
- ql_read32(qdev, ISR3));
- printk(KERN_ERR PFX "ISR4 = 0x%x.\n",
- ql_read32(qdev, ISR4));
- printk(KERN_ERR PFX "REV_ID = 0x%x.\n",
- ql_read32(qdev, REV_ID));
- printk(KERN_ERR PFX "FRC_ECC_ERR = 0x%x.\n",
- ql_read32(qdev, FRC_ECC_ERR));
- printk(KERN_ERR PFX "ERR_STS = 0x%x.\n",
- ql_read32(qdev, ERR_STS));
- printk(KERN_ERR PFX "RAM_DBG_ADDR = 0x%x.\n",
- ql_read32(qdev, RAM_DBG_ADDR));
- printk(KERN_ERR PFX "RAM_DBG_DATA = 0x%x.\n",
- ql_read32(qdev, RAM_DBG_DATA));
- printk(KERN_ERR PFX "ECC_ERR_CNT = 0x%x.\n",
- ql_read32(qdev, ECC_ERR_CNT));
- printk(KERN_ERR PFX "SEM = 0x%x.\n",
- ql_read32(qdev, SEM));
- printk(KERN_ERR PFX "GPIO_1 = 0x%x.\n",
- ql_read32(qdev, GPIO_1));
- printk(KERN_ERR PFX "GPIO_2 = 0x%x.\n",
- ql_read32(qdev, GPIO_2));
- printk(KERN_ERR PFX "GPIO_3 = 0x%x.\n",
- ql_read32(qdev, GPIO_3));
- printk(KERN_ERR PFX "XGMAC_ADDR = 0x%x.\n",
- ql_read32(qdev, XGMAC_ADDR));
- printk(KERN_ERR PFX "XGMAC_DATA = 0x%x.\n",
- ql_read32(qdev, XGMAC_DATA));
- printk(KERN_ERR PFX "NIC_ETS = 0x%x.\n",
- ql_read32(qdev, NIC_ETS));
- printk(KERN_ERR PFX "CNA_ETS = 0x%x.\n",
- ql_read32(qdev, CNA_ETS));
- printk(KERN_ERR PFX "FLASH_ADDR = 0x%x.\n",
- ql_read32(qdev, FLASH_ADDR));
- printk(KERN_ERR PFX "FLASH_DATA = 0x%x.\n",
- ql_read32(qdev, FLASH_DATA));
- printk(KERN_ERR PFX "CQ_STOP = 0x%x.\n",
- ql_read32(qdev, CQ_STOP));
- printk(KERN_ERR PFX "PAGE_TBL_RID = 0x%x.\n",
- ql_read32(qdev, PAGE_TBL_RID));
- printk(KERN_ERR PFX "WQ_PAGE_TBL_LO = 0x%x.\n",
- ql_read32(qdev, WQ_PAGE_TBL_LO));
- printk(KERN_ERR PFX "WQ_PAGE_TBL_HI = 0x%x.\n",
- ql_read32(qdev, WQ_PAGE_TBL_HI));
- printk(KERN_ERR PFX "CQ_PAGE_TBL_LO = 0x%x.\n",
- ql_read32(qdev, CQ_PAGE_TBL_LO));
- printk(KERN_ERR PFX "CQ_PAGE_TBL_HI = 0x%x.\n",
- ql_read32(qdev, CQ_PAGE_TBL_HI));
- printk(KERN_ERR PFX "COS_DFLT_CQ1 = 0x%x.\n",
- ql_read32(qdev, COS_DFLT_CQ1));
- printk(KERN_ERR PFX "COS_DFLT_CQ2 = 0x%x.\n",
- ql_read32(qdev, COS_DFLT_CQ2));
- printk(KERN_ERR PFX "SPLT_HDR = 0x%x.\n",
- ql_read32(qdev, SPLT_HDR));
- printk(KERN_ERR PFX "FC_PAUSE_THRES = 0x%x.\n",
- ql_read32(qdev, FC_PAUSE_THRES));
- printk(KERN_ERR PFX "NIC_PAUSE_THRES = 0x%x.\n",
- ql_read32(qdev, NIC_PAUSE_THRES));
- printk(KERN_ERR PFX "FC_ETHERTYPE = 0x%x.\n",
- ql_read32(qdev, FC_ETHERTYPE));
- printk(KERN_ERR PFX "FC_RCV_CFG = 0x%x.\n",
- ql_read32(qdev, FC_RCV_CFG));
- printk(KERN_ERR PFX "NIC_RCV_CFG = 0x%x.\n",
- ql_read32(qdev, NIC_RCV_CFG));
- printk(KERN_ERR PFX "FC_COS_TAGS = 0x%x.\n",
- ql_read32(qdev, FC_COS_TAGS));
- printk(KERN_ERR PFX "NIC_COS_TAGS = 0x%x.\n",
- ql_read32(qdev, NIC_COS_TAGS));
- printk(KERN_ERR PFX "MGMT_RCV_CFG = 0x%x.\n",
- ql_read32(qdev, MGMT_RCV_CFG));
- printk(KERN_ERR PFX "XG_SERDES_ADDR = 0x%x.\n",
- ql_read32(qdev, XG_SERDES_ADDR));
- printk(KERN_ERR PFX "XG_SERDES_DATA = 0x%x.\n",
- ql_read32(qdev, XG_SERDES_DATA));
- printk(KERN_ERR PFX "PRB_MX_ADDR = 0x%x.\n",
- ql_read32(qdev, PRB_MX_ADDR));
- printk(KERN_ERR PFX "PRB_MX_DATA = 0x%x.\n",
- ql_read32(qdev, PRB_MX_DATA));
+ pr_err("reg dump for function #%d\n", qdev->func);
+ DUMP_REG(qdev, SYS);
+ DUMP_REG(qdev, RST_FO);
+ DUMP_REG(qdev, FSC);
+ DUMP_REG(qdev, CSR);
+ DUMP_REG(qdev, ICB_RID);
+ DUMP_REG(qdev, ICB_L);
+ DUMP_REG(qdev, ICB_H);
+ DUMP_REG(qdev, CFG);
+ DUMP_REG(qdev, BIOS_ADDR);
+ DUMP_REG(qdev, STS);
+ DUMP_REG(qdev, INTR_EN);
+ DUMP_REG(qdev, INTR_MASK);
+ DUMP_REG(qdev, ISR1);
+ DUMP_REG(qdev, ISR2);
+ DUMP_REG(qdev, ISR3);
+ DUMP_REG(qdev, ISR4);
+ DUMP_REG(qdev, REV_ID);
+ DUMP_REG(qdev, FRC_ECC_ERR);
+ DUMP_REG(qdev, ERR_STS);
+ DUMP_REG(qdev, RAM_DBG_ADDR);
+ DUMP_REG(qdev, RAM_DBG_DATA);
+ DUMP_REG(qdev, ECC_ERR_CNT);
+ DUMP_REG(qdev, SEM);
+ DUMP_REG(qdev, GPIO_1);
+ DUMP_REG(qdev, GPIO_2);
+ DUMP_REG(qdev, GPIO_3);
+ DUMP_REG(qdev, XGMAC_ADDR);
+ DUMP_REG(qdev, XGMAC_DATA);
+ DUMP_REG(qdev, NIC_ETS);
+ DUMP_REG(qdev, CNA_ETS);
+ DUMP_REG(qdev, FLASH_ADDR);
+ DUMP_REG(qdev, FLASH_DATA);
+ DUMP_REG(qdev, CQ_STOP);
+ DUMP_REG(qdev, PAGE_TBL_RID);
+ DUMP_REG(qdev, WQ_PAGE_TBL_LO);
+ DUMP_REG(qdev, WQ_PAGE_TBL_HI);
+ DUMP_REG(qdev, CQ_PAGE_TBL_LO);
+ DUMP_REG(qdev, CQ_PAGE_TBL_HI);
+ DUMP_REG(qdev, COS_DFLT_CQ1);
+ DUMP_REG(qdev, COS_DFLT_CQ2);
+ DUMP_REG(qdev, SPLT_HDR);
+ DUMP_REG(qdev, FC_PAUSE_THRES);
+ DUMP_REG(qdev, NIC_PAUSE_THRES);
+ DUMP_REG(qdev, FC_ETHERTYPE);
+ DUMP_REG(qdev, FC_RCV_CFG);
+ DUMP_REG(qdev, NIC_RCV_CFG);
+ DUMP_REG(qdev, FC_COS_TAGS);
+ DUMP_REG(qdev, NIC_COS_TAGS);
+ DUMP_REG(qdev, MGMT_RCV_CFG);
+ DUMP_REG(qdev, XG_SERDES_ADDR);
+ DUMP_REG(qdev, XG_SERDES_DATA);
+ DUMP_REG(qdev, PRB_MX_ADDR);
+ DUMP_REG(qdev, PRB_MX_DATA);
ql_dump_intr_states(qdev);
ql_dump_xgmac_control_regs(qdev);
ql_dump_ets_regs(qdev);
@@ -1613,191 +1526,124 @@ void ql_dump_regs(struct ql_adapter *qdev)
#endif
#ifdef QL_STAT_DUMP
+
+#define DUMP_STAT(qdev, stat) \
+ pr_err("%s = %ld\n", #stat, (unsigned long)qdev->nic_stats.stat)
+
void ql_dump_stat(struct ql_adapter *qdev)
{
- printk(KERN_ERR "%s: Enter.\n", __func__);
- printk(KERN_ERR "tx_pkts = %ld\n",
- (unsigned long)qdev->nic_stats.tx_pkts);
- printk(KERN_ERR "tx_bytes = %ld\n",
- (unsigned long)qdev->nic_stats.tx_bytes);
- printk(KERN_ERR "tx_mcast_pkts = %ld.\n",
- (unsigned long)qdev->nic_stats.tx_mcast_pkts);
- printk(KERN_ERR "tx_bcast_pkts = %ld.\n",
- (unsigned long)qdev->nic_stats.tx_bcast_pkts);
- printk(KERN_ERR "tx_ucast_pkts = %ld.\n",
- (unsigned long)qdev->nic_stats.tx_ucast_pkts);
- printk(KERN_ERR "tx_ctl_pkts = %ld.\n",
- (unsigned long)qdev->nic_stats.tx_ctl_pkts);
- printk(KERN_ERR "tx_pause_pkts = %ld.\n",
- (unsigned long)qdev->nic_stats.tx_pause_pkts);
- printk(KERN_ERR "tx_64_pkt = %ld.\n",
- (unsigned long)qdev->nic_stats.tx_64_pkt);
- printk(KERN_ERR "tx_65_to_127_pkt = %ld.\n",
- (unsigned long)qdev->nic_stats.tx_65_to_127_pkt);
- printk(KERN_ERR "tx_128_to_255_pkt = %ld.\n",
- (unsigned long)qdev->nic_stats.tx_128_to_255_pkt);
- printk(KERN_ERR "tx_256_511_pkt = %ld.\n",
- (unsigned long)qdev->nic_stats.tx_256_511_pkt);
- printk(KERN_ERR "tx_512_to_1023_pkt = %ld.\n",
- (unsigned long)qdev->nic_stats.tx_512_to_1023_pkt);
- printk(KERN_ERR "tx_1024_to_1518_pkt = %ld.\n",
- (unsigned long)qdev->nic_stats.tx_1024_to_1518_pkt);
- printk(KERN_ERR "tx_1519_to_max_pkt = %ld.\n",
- (unsigned long)qdev->nic_stats.tx_1519_to_max_pkt);
- printk(KERN_ERR "tx_undersize_pkt = %ld.\n",
- (unsigned long)qdev->nic_stats.tx_undersize_pkt);
- printk(KERN_ERR "tx_oversize_pkt = %ld.\n",
- (unsigned long)qdev->nic_stats.tx_oversize_pkt);
- printk(KERN_ERR "rx_bytes = %ld.\n",
- (unsigned long)qdev->nic_stats.rx_bytes);
- printk(KERN_ERR "rx_bytes_ok = %ld.\n",
- (unsigned long)qdev->nic_stats.rx_bytes_ok);
- printk(KERN_ERR "rx_pkts = %ld.\n",
- (unsigned long)qdev->nic_stats.rx_pkts);
- printk(KERN_ERR "rx_pkts_ok = %ld.\n",
- (unsigned long)qdev->nic_stats.rx_pkts_ok);
- printk(KERN_ERR "rx_bcast_pkts = %ld.\n",
- (unsigned long)qdev->nic_stats.rx_bcast_pkts);
- printk(KERN_ERR "rx_mcast_pkts = %ld.\n",
- (unsigned long)qdev->nic_stats.rx_mcast_pkts);
- printk(KERN_ERR "rx_ucast_pkts = %ld.\n",
- (unsigned long)qdev->nic_stats.rx_ucast_pkts);
- printk(KERN_ERR "rx_undersize_pkts = %ld.\n",
- (unsigned long)qdev->nic_stats.rx_undersize_pkts);
- printk(KERN_ERR "rx_oversize_pkts = %ld.\n",
- (unsigned long)qdev->nic_stats.rx_oversize_pkts);
- printk(KERN_ERR "rx_jabber_pkts = %ld.\n",
- (unsigned long)qdev->nic_stats.rx_jabber_pkts);
- printk(KERN_ERR "rx_undersize_fcerr_pkts = %ld.\n",
- (unsigned long)qdev->nic_stats.rx_undersize_fcerr_pkts);
- printk(KERN_ERR "rx_drop_events = %ld.\n",
- (unsigned long)qdev->nic_stats.rx_drop_events);
- printk(KERN_ERR "rx_fcerr_pkts = %ld.\n",
- (unsigned long)qdev->nic_stats.rx_fcerr_pkts);
- printk(KERN_ERR "rx_align_err = %ld.\n",
- (unsigned long)qdev->nic_stats.rx_align_err);
- printk(KERN_ERR "rx_symbol_err = %ld.\n",
- (unsigned long)qdev->nic_stats.rx_symbol_err);
- printk(KERN_ERR "rx_mac_err = %ld.\n",
- (unsigned long)qdev->nic_stats.rx_mac_err);
- printk(KERN_ERR "rx_ctl_pkts = %ld.\n",
- (unsigned long)qdev->nic_stats.rx_ctl_pkts);
- printk(KERN_ERR "rx_pause_pkts = %ld.\n",
- (unsigned long)qdev->nic_stats.rx_pause_pkts);
- printk(KERN_ERR "rx_64_pkts = %ld.\n",
- (unsigned long)qdev->nic_stats.rx_64_pkts);
- printk(KERN_ERR "rx_65_to_127_pkts = %ld.\n",
- (unsigned long)qdev->nic_stats.rx_65_to_127_pkts);
- printk(KERN_ERR "rx_128_255_pkts = %ld.\n",
- (unsigned long)qdev->nic_stats.rx_128_255_pkts);
- printk(KERN_ERR "rx_256_511_pkts = %ld.\n",
- (unsigned long)qdev->nic_stats.rx_256_511_pkts);
- printk(KERN_ERR "rx_512_to_1023_pkts = %ld.\n",
- (unsigned long)qdev->nic_stats.rx_512_to_1023_pkts);
- printk(KERN_ERR "rx_1024_to_1518_pkts = %ld.\n",
- (unsigned long)qdev->nic_stats.rx_1024_to_1518_pkts);
- printk(KERN_ERR "rx_1519_to_max_pkts = %ld.\n",
- (unsigned long)qdev->nic_stats.rx_1519_to_max_pkts);
- printk(KERN_ERR "rx_len_err_pkts = %ld.\n",
- (unsigned long)qdev->nic_stats.rx_len_err_pkts);
+ pr_err("%s: Enter\n", __func__);
+ DUMP_STAT(qdev, tx_pkts);
+ DUMP_STAT(qdev, tx_bytes);
+ DUMP_STAT(qdev, tx_mcast_pkts);
+ DUMP_STAT(qdev, tx_bcast_pkts);
+ DUMP_STAT(qdev, tx_ucast_pkts);
+ DUMP_STAT(qdev, tx_ctl_pkts);
+ DUMP_STAT(qdev, tx_pause_pkts);
+ DUMP_STAT(qdev, tx_64_pkt);
+ DUMP_STAT(qdev, tx_65_to_127_pkt);
+ DUMP_STAT(qdev, tx_128_to_255_pkt);
+ DUMP_STAT(qdev, tx_256_511_pkt);
+ DUMP_STAT(qdev, tx_512_to_1023_pkt);
+ DUMP_STAT(qdev, tx_1024_to_1518_pkt);
+ DUMP_STAT(qdev, tx_1519_to_max_pkt);
+ DUMP_STAT(qdev, tx_undersize_pkt);
+ DUMP_STAT(qdev, tx_oversize_pkt);
+ DUMP_STAT(qdev, rx_bytes);
+ DUMP_STAT(qdev, rx_bytes_ok);
+ DUMP_STAT(qdev, rx_pkts);
+ DUMP_STAT(qdev, rx_pkts_ok);
+ DUMP_STAT(qdev, rx_bcast_pkts);
+ DUMP_STAT(qdev, rx_mcast_pkts);
+ DUMP_STAT(qdev, rx_ucast_pkts);
+ DUMP_STAT(qdev, rx_undersize_pkts);
+ DUMP_STAT(qdev, rx_oversize_pkts);
+ DUMP_STAT(qdev, rx_jabber_pkts);
+ DUMP_STAT(qdev, rx_undersize_fcerr_pkts);
+ DUMP_STAT(qdev, rx_drop_events);
+ DUMP_STAT(qdev, rx_fcerr_pkts);
+ DUMP_STAT(qdev, rx_align_err);
+ DUMP_STAT(qdev, rx_symbol_err);
+ DUMP_STAT(qdev, rx_mac_err);
+ DUMP_STAT(qdev, rx_ctl_pkts);
+ DUMP_STAT(qdev, rx_pause_pkts);
+ DUMP_STAT(qdev, rx_64_pkts);
+ DUMP_STAT(qdev, rx_65_to_127_pkts);
+ DUMP_STAT(qdev, rx_128_255_pkts);
+ DUMP_STAT(qdev, rx_256_511_pkts);
+ DUMP_STAT(qdev, rx_512_to_1023_pkts);
+ DUMP_STAT(qdev, rx_1024_to_1518_pkts);
+ DUMP_STAT(qdev, rx_1519_to_max_pkts);
+ DUMP_STAT(qdev, rx_len_err_pkts);
};
#endif
#ifdef QL_DEV_DUMP
+
+#define DUMP_QDEV_FIELD(qdev, type, field) \
+ pr_err("qdev->%-24s = " type "\n", #field, qdev->field)
+#define DUMP_QDEV_DMA_FIELD(qdev, field) \
+ pr_err("qdev->%-24s = %llx\n", #field, (unsigned long long)qdev->field)
+#define DUMP_QDEV_ARRAY(qdev, type, array, index, field) \
+ pr_err("%s[%d].%s = " type "\n", \
+ #array, index, #field, qdev->array[index].field);
void ql_dump_qdev(struct ql_adapter *qdev)
{
int i;
- printk(KERN_ERR PFX "qdev->flags = %lx.\n",
- qdev->flags);
- printk(KERN_ERR PFX "qdev->vlgrp = %p.\n",
- qdev->vlgrp);
- printk(KERN_ERR PFX "qdev->pdev = %p.\n",
- qdev->pdev);
- printk(KERN_ERR PFX "qdev->ndev = %p.\n",
- qdev->ndev);
- printk(KERN_ERR PFX "qdev->chip_rev_id = %d.\n",
- qdev->chip_rev_id);
- printk(KERN_ERR PFX "qdev->reg_base = %p.\n",
- qdev->reg_base);
- printk(KERN_ERR PFX "qdev->doorbell_area = %p.\n",
- qdev->doorbell_area);
- printk(KERN_ERR PFX "qdev->doorbell_area_size = %d.\n",
- qdev->doorbell_area_size);
- printk(KERN_ERR PFX "msg_enable = %x.\n",
- qdev->msg_enable);
- printk(KERN_ERR PFX "qdev->rx_ring_shadow_reg_area = %p.\n",
- qdev->rx_ring_shadow_reg_area);
- printk(KERN_ERR PFX "qdev->rx_ring_shadow_reg_dma = %llx.\n",
- (unsigned long long) qdev->rx_ring_shadow_reg_dma);
- printk(KERN_ERR PFX "qdev->tx_ring_shadow_reg_area = %p.\n",
- qdev->tx_ring_shadow_reg_area);
- printk(KERN_ERR PFX "qdev->tx_ring_shadow_reg_dma = %llx.\n",
- (unsigned long long) qdev->tx_ring_shadow_reg_dma);
- printk(KERN_ERR PFX "qdev->intr_count = %d.\n",
- qdev->intr_count);
+ DUMP_QDEV_FIELD(qdev, "%lx", flags);
+ DUMP_QDEV_FIELD(qdev, "%p", vlgrp);
+ DUMP_QDEV_FIELD(qdev, "%p", pdev);
+ DUMP_QDEV_FIELD(qdev, "%p", ndev);
+ DUMP_QDEV_FIELD(qdev, "%d", chip_rev_id);
+ DUMP_QDEV_FIELD(qdev, "%p", reg_base);
+ DUMP_QDEV_FIELD(qdev, "%p", doorbell_area);
+ DUMP_QDEV_FIELD(qdev, "%d", doorbell_area_size);
+ DUMP_QDEV_FIELD(qdev, "%x", msg_enable);
+ DUMP_QDEV_FIELD(qdev, "%p", rx_ring_shadow_reg_area);
+ DUMP_QDEV_DMA_FIELD(qdev, rx_ring_shadow_reg_dma);
+ DUMP_QDEV_FIELD(qdev, "%p", tx_ring_shadow_reg_area);
+ DUMP_QDEV_DMA_FIELD(qdev, tx_ring_shadow_reg_dma);
+ DUMP_QDEV_FIELD(qdev, "%d", intr_count);
if (qdev->msi_x_entry)
for (i = 0; i < qdev->intr_count; i++) {
- printk(KERN_ERR PFX
- "msi_x_entry.[%d]vector = %d.\n", i,
- qdev->msi_x_entry[i].vector);
- printk(KERN_ERR PFX
- "msi_x_entry.[%d]entry = %d.\n", i,
- qdev->msi_x_entry[i].entry);
+ DUMP_QDEV_ARRAY(qdev, "%d", msi_x_entry, i, vector);
+ DUMP_QDEV_ARRAY(qdev, "%d", msi_x_entry, i, entry);
}
for (i = 0; i < qdev->intr_count; i++) {
- printk(KERN_ERR PFX
- "intr_context[%d].qdev = %p.\n", i,
- qdev->intr_context[i].qdev);
- printk(KERN_ERR PFX
- "intr_context[%d].intr = %d.\n", i,
- qdev->intr_context[i].intr);
- printk(KERN_ERR PFX
- "intr_context[%d].hooked = %d.\n", i,
- qdev->intr_context[i].hooked);
- printk(KERN_ERR PFX
- "intr_context[%d].intr_en_mask = 0x%08x.\n", i,
- qdev->intr_context[i].intr_en_mask);
- printk(KERN_ERR PFX
- "intr_context[%d].intr_dis_mask = 0x%08x.\n", i,
- qdev->intr_context[i].intr_dis_mask);
- printk(KERN_ERR PFX
- "intr_context[%d].intr_read_mask = 0x%08x.\n", i,
- qdev->intr_context[i].intr_read_mask);
+ DUMP_QDEV_ARRAY(qdev, "%p", intr_context, i, qdev);
+ DUMP_QDEV_ARRAY(qdev, "%d", intr_context, i, intr);
+ DUMP_QDEV_ARRAY(qdev, "%d", intr_context, i, hooked);
+ DUMP_QDEV_ARRAY(qdev, "0x%08x", intr_context, i, intr_en_mask);
+ DUMP_QDEV_ARRAY(qdev, "0x%08x", intr_context, i, intr_dis_mask);
+ DUMP_QDEV_ARRAY(qdev, "0x%08x", intr_context, i, intr_read_mask);
}
- printk(KERN_ERR PFX "qdev->tx_ring_count = %d.\n", qdev->tx_ring_count);
- printk(KERN_ERR PFX "qdev->rx_ring_count = %d.\n", qdev->rx_ring_count);
- printk(KERN_ERR PFX "qdev->ring_mem_size = %d.\n", qdev->ring_mem_size);
- printk(KERN_ERR PFX "qdev->ring_mem = %p.\n", qdev->ring_mem);
- printk(KERN_ERR PFX "qdev->intr_count = %d.\n", qdev->intr_count);
- printk(KERN_ERR PFX "qdev->tx_ring = %p.\n",
- qdev->tx_ring);
- printk(KERN_ERR PFX "qdev->rss_ring_count = %d.\n",
- qdev->rss_ring_count);
- printk(KERN_ERR PFX "qdev->rx_ring = %p.\n", qdev->rx_ring);
- printk(KERN_ERR PFX "qdev->default_rx_queue = %d.\n",
- qdev->default_rx_queue);
- printk(KERN_ERR PFX "qdev->xg_sem_mask = 0x%08x.\n",
- qdev->xg_sem_mask);
- printk(KERN_ERR PFX "qdev->port_link_up = 0x%08x.\n",
- qdev->port_link_up);
- printk(KERN_ERR PFX "qdev->port_init = 0x%08x.\n",
- qdev->port_init);
-
+ DUMP_QDEV_FIELD(qdev, "%d", tx_ring_count);
+ DUMP_QDEV_FIELD(qdev, "%d", rx_ring_count);
+ DUMP_QDEV_FIELD(qdev, "%d", ring_mem_size);
+ DUMP_QDEV_FIELD(qdev, "%p", ring_mem);
+ DUMP_QDEV_FIELD(qdev, "%d", intr_count);
+ DUMP_QDEV_FIELD(qdev, "%p", tx_ring);
+ DUMP_QDEV_FIELD(qdev, "%d", rss_ring_count);
+ DUMP_QDEV_FIELD(qdev, "%p", rx_ring);
+ DUMP_QDEV_FIELD(qdev, "%d", default_rx_queue);
+ DUMP_QDEV_FIELD(qdev, "0x%08x", xg_sem_mask);
+ DUMP_QDEV_FIELD(qdev, "0x%08x", port_link_up);
+ DUMP_QDEV_FIELD(qdev, "0x%08x", port_init);
}
#endif
#ifdef QL_CB_DUMP
void ql_dump_wqicb(struct wqicb *wqicb)
{
- printk(KERN_ERR PFX "Dumping wqicb stuff...\n");
- printk(KERN_ERR PFX "wqicb->len = 0x%x.\n", le16_to_cpu(wqicb->len));
- printk(KERN_ERR PFX "wqicb->flags = %x.\n", le16_to_cpu(wqicb->flags));
- printk(KERN_ERR PFX "wqicb->cq_id_rss = %d.\n",
+ pr_err("Dumping wqicb stuff...\n");
+ pr_err("wqicb->len = 0x%x\n", le16_to_cpu(wqicb->len));
+ pr_err("wqicb->flags = %x\n", le16_to_cpu(wqicb->flags));
+ pr_err("wqicb->cq_id_rss = %d\n",
le16_to_cpu(wqicb->cq_id_rss));
- printk(KERN_ERR PFX "wqicb->rid = 0x%x.\n", le16_to_cpu(wqicb->rid));
- printk(KERN_ERR PFX "wqicb->wq_addr = 0x%llx.\n",
+ pr_err("wqicb->rid = 0x%x\n", le16_to_cpu(wqicb->rid));
+ pr_err("wqicb->wq_addr = 0x%llx\n",
(unsigned long long) le64_to_cpu(wqicb->addr));
- printk(KERN_ERR PFX "wqicb->wq_cnsmr_idx_addr = 0x%llx.\n",
+ pr_err("wqicb->wq_cnsmr_idx_addr = 0x%llx\n",
(unsigned long long) le64_to_cpu(wqicb->cnsmr_idx_addr));
}
@@ -1805,40 +1651,34 @@ void ql_dump_tx_ring(struct tx_ring *tx_ring)
{
if (tx_ring == NULL)
return;
- printk(KERN_ERR PFX
- "===================== Dumping tx_ring %d ===============.\n",
+ pr_err("===================== Dumping tx_ring %d ===============\n",
tx_ring->wq_id);
- printk(KERN_ERR PFX "tx_ring->base = %p.\n", tx_ring->wq_base);
- printk(KERN_ERR PFX "tx_ring->base_dma = 0x%llx.\n",
+ pr_err("tx_ring->base = %p\n", tx_ring->wq_base);
+ pr_err("tx_ring->base_dma = 0x%llx\n",
(unsigned long long) tx_ring->wq_base_dma);
- printk(KERN_ERR PFX
- "tx_ring->cnsmr_idx_sh_reg, addr = 0x%p, value = %d.\n",
+ pr_err("tx_ring->cnsmr_idx_sh_reg, addr = 0x%p, value = %d\n",
tx_ring->cnsmr_idx_sh_reg,
tx_ring->cnsmr_idx_sh_reg
? ql_read_sh_reg(tx_ring->cnsmr_idx_sh_reg) : 0);
- printk(KERN_ERR PFX "tx_ring->size = %d.\n", tx_ring->wq_size);
- printk(KERN_ERR PFX "tx_ring->len = %d.\n", tx_ring->wq_len);
- printk(KERN_ERR PFX "tx_ring->prod_idx_db_reg = %p.\n",
- tx_ring->prod_idx_db_reg);
- printk(KERN_ERR PFX "tx_ring->valid_db_reg = %p.\n",
- tx_ring->valid_db_reg);
- printk(KERN_ERR PFX "tx_ring->prod_idx = %d.\n", tx_ring->prod_idx);
- printk(KERN_ERR PFX "tx_ring->cq_id = %d.\n", tx_ring->cq_id);
- printk(KERN_ERR PFX "tx_ring->wq_id = %d.\n", tx_ring->wq_id);
- printk(KERN_ERR PFX "tx_ring->q = %p.\n", tx_ring->q);
- printk(KERN_ERR PFX "tx_ring->tx_count = %d.\n",
- atomic_read(&tx_ring->tx_count));
+ pr_err("tx_ring->size = %d\n", tx_ring->wq_size);
+ pr_err("tx_ring->len = %d\n", tx_ring->wq_len);
+ pr_err("tx_ring->prod_idx_db_reg = %p\n", tx_ring->prod_idx_db_reg);
+ pr_err("tx_ring->valid_db_reg = %p\n", tx_ring->valid_db_reg);
+ pr_err("tx_ring->prod_idx = %d\n", tx_ring->prod_idx);
+ pr_err("tx_ring->cq_id = %d\n", tx_ring->cq_id);
+ pr_err("tx_ring->wq_id = %d\n", tx_ring->wq_id);
+ pr_err("tx_ring->q = %p\n", tx_ring->q);
+ pr_err("tx_ring->tx_count = %d\n", atomic_read(&tx_ring->tx_count));
}
void ql_dump_ricb(struct ricb *ricb)
{
int i;
- printk(KERN_ERR PFX
- "===================== Dumping ricb ===============.\n");
- printk(KERN_ERR PFX "Dumping ricb stuff...\n");
+ pr_err("===================== Dumping ricb ===============\n");
+ pr_err("Dumping ricb stuff...\n");
- printk(KERN_ERR PFX "ricb->base_cq = %d.\n", ricb->base_cq & 0x1f);
- printk(KERN_ERR PFX "ricb->flags = %s%s%s%s%s%s%s%s%s.\n",
+ pr_err("ricb->base_cq = %d\n", ricb->base_cq & 0x1f);
+ pr_err("ricb->flags = %s%s%s%s%s%s%s%s%s\n",
ricb->base_cq & RSS_L4K ? "RSS_L4K " : "",
ricb->flags & RSS_L6K ? "RSS_L6K " : "",
ricb->flags & RSS_LI ? "RSS_LI " : "",
@@ -1848,44 +1688,44 @@ void ql_dump_ricb(struct ricb *ricb)
ricb->flags & RSS_RT4 ? "RSS_RT4 " : "",
ricb->flags & RSS_RI6 ? "RSS_RI6 " : "",
ricb->flags & RSS_RT6 ? "RSS_RT6 " : "");
- printk(KERN_ERR PFX "ricb->mask = 0x%.04x.\n", le16_to_cpu(ricb->mask));
+ pr_err("ricb->mask = 0x%.04x\n", le16_to_cpu(ricb->mask));
for (i = 0; i < 16; i++)
- printk(KERN_ERR PFX "ricb->hash_cq_id[%d] = 0x%.08x.\n", i,
+ pr_err("ricb->hash_cq_id[%d] = 0x%.08x\n", i,
le32_to_cpu(ricb->hash_cq_id[i]));
for (i = 0; i < 10; i++)
- printk(KERN_ERR PFX "ricb->ipv6_hash_key[%d] = 0x%.08x.\n", i,
+ pr_err("ricb->ipv6_hash_key[%d] = 0x%.08x\n", i,
le32_to_cpu(ricb->ipv6_hash_key[i]));
for (i = 0; i < 4; i++)
- printk(KERN_ERR PFX "ricb->ipv4_hash_key[%d] = 0x%.08x.\n", i,
+ pr_err("ricb->ipv4_hash_key[%d] = 0x%.08x\n", i,
le32_to_cpu(ricb->ipv4_hash_key[i]));
}
void ql_dump_cqicb(struct cqicb *cqicb)
{
- printk(KERN_ERR PFX "Dumping cqicb stuff...\n");
+ pr_err("Dumping cqicb stuff...\n");
- printk(KERN_ERR PFX "cqicb->msix_vect = %d.\n", cqicb->msix_vect);
- printk(KERN_ERR PFX "cqicb->flags = %x.\n", cqicb->flags);
- printk(KERN_ERR PFX "cqicb->len = %d.\n", le16_to_cpu(cqicb->len));
- printk(KERN_ERR PFX "cqicb->addr = 0x%llx.\n",
+ pr_err("cqicb->msix_vect = %d\n", cqicb->msix_vect);
+ pr_err("cqicb->flags = %x\n", cqicb->flags);
+ pr_err("cqicb->len = %d\n", le16_to_cpu(cqicb->len));
+ pr_err("cqicb->addr = 0x%llx\n",
(unsigned long long) le64_to_cpu(cqicb->addr));
- printk(KERN_ERR PFX "cqicb->prod_idx_addr = 0x%llx.\n",
+ pr_err("cqicb->prod_idx_addr = 0x%llx\n",
(unsigned long long) le64_to_cpu(cqicb->prod_idx_addr));
- printk(KERN_ERR PFX "cqicb->pkt_delay = 0x%.04x.\n",
+ pr_err("cqicb->pkt_delay = 0x%.04x\n",
le16_to_cpu(cqicb->pkt_delay));
- printk(KERN_ERR PFX "cqicb->irq_delay = 0x%.04x.\n",
+ pr_err("cqicb->irq_delay = 0x%.04x\n",
le16_to_cpu(cqicb->irq_delay));
- printk(KERN_ERR PFX "cqicb->lbq_addr = 0x%llx.\n",
+ pr_err("cqicb->lbq_addr = 0x%llx\n",
(unsigned long long) le64_to_cpu(cqicb->lbq_addr));
- printk(KERN_ERR PFX "cqicb->lbq_buf_size = 0x%.04x.\n",
+ pr_err("cqicb->lbq_buf_size = 0x%.04x\n",
le16_to_cpu(cqicb->lbq_buf_size));
- printk(KERN_ERR PFX "cqicb->lbq_len = 0x%.04x.\n",
+ pr_err("cqicb->lbq_len = 0x%.04x\n",
le16_to_cpu(cqicb->lbq_len));
- printk(KERN_ERR PFX "cqicb->sbq_addr = 0x%llx.\n",
+ pr_err("cqicb->sbq_addr = 0x%llx\n",
(unsigned long long) le64_to_cpu(cqicb->sbq_addr));
- printk(KERN_ERR PFX "cqicb->sbq_buf_size = 0x%.04x.\n",
+ pr_err("cqicb->sbq_buf_size = 0x%.04x\n",
le16_to_cpu(cqicb->sbq_buf_size));
- printk(KERN_ERR PFX "cqicb->sbq_len = 0x%.04x.\n",
+ pr_err("cqicb->sbq_len = 0x%.04x\n",
le16_to_cpu(cqicb->sbq_len));
}
@@ -1893,100 +1733,85 @@ void ql_dump_rx_ring(struct rx_ring *rx_ring)
{
if (rx_ring == NULL)
return;
- printk(KERN_ERR PFX
- "===================== Dumping rx_ring %d ===============.\n",
+ pr_err("===================== Dumping rx_ring %d ===============\n",
rx_ring->cq_id);
- printk(KERN_ERR PFX "Dumping rx_ring %d, type = %s%s%s.\n",
+ pr_err("Dumping rx_ring %d, type = %s%s%s\n",
rx_ring->cq_id, rx_ring->type == DEFAULT_Q ? "DEFAULT" : "",
rx_ring->type == TX_Q ? "OUTBOUND COMPLETIONS" : "",
rx_ring->type == RX_Q ? "INBOUND_COMPLETIONS" : "");
- printk(KERN_ERR PFX "rx_ring->cqicb = %p.\n", &rx_ring->cqicb);
- printk(KERN_ERR PFX "rx_ring->cq_base = %p.\n", rx_ring->cq_base);
- printk(KERN_ERR PFX "rx_ring->cq_base_dma = %llx.\n",
+ pr_err("rx_ring->cqicb = %p\n", &rx_ring->cqicb);
+ pr_err("rx_ring->cq_base = %p\n", rx_ring->cq_base);
+ pr_err("rx_ring->cq_base_dma = %llx\n",
(unsigned long long) rx_ring->cq_base_dma);
- printk(KERN_ERR PFX "rx_ring->cq_size = %d.\n", rx_ring->cq_size);
- printk(KERN_ERR PFX "rx_ring->cq_len = %d.\n", rx_ring->cq_len);
- printk(KERN_ERR PFX
- "rx_ring->prod_idx_sh_reg, addr = 0x%p, value = %d.\n",
+ pr_err("rx_ring->cq_size = %d\n", rx_ring->cq_size);
+ pr_err("rx_ring->cq_len = %d\n", rx_ring->cq_len);
+ pr_err("rx_ring->prod_idx_sh_reg, addr = 0x%p, value = %d\n",
rx_ring->prod_idx_sh_reg,
rx_ring->prod_idx_sh_reg
? ql_read_sh_reg(rx_ring->prod_idx_sh_reg) : 0);
- printk(KERN_ERR PFX "rx_ring->prod_idx_sh_reg_dma = %llx.\n",
+ pr_err("rx_ring->prod_idx_sh_reg_dma = %llx\n",
(unsigned long long) rx_ring->prod_idx_sh_reg_dma);
- printk(KERN_ERR PFX "rx_ring->cnsmr_idx_db_reg = %p.\n",
+ pr_err("rx_ring->cnsmr_idx_db_reg = %p\n",
rx_ring->cnsmr_idx_db_reg);
- printk(KERN_ERR PFX "rx_ring->cnsmr_idx = %d.\n", rx_ring->cnsmr_idx);
- printk(KERN_ERR PFX "rx_ring->curr_entry = %p.\n", rx_ring->curr_entry);
- printk(KERN_ERR PFX "rx_ring->valid_db_reg = %p.\n",
- rx_ring->valid_db_reg);
+ pr_err("rx_ring->cnsmr_idx = %d\n", rx_ring->cnsmr_idx);
+ pr_err("rx_ring->curr_entry = %p\n", rx_ring->curr_entry);
+ pr_err("rx_ring->valid_db_reg = %p\n", rx_ring->valid_db_reg);
- printk(KERN_ERR PFX "rx_ring->lbq_base = %p.\n", rx_ring->lbq_base);
- printk(KERN_ERR PFX "rx_ring->lbq_base_dma = %llx.\n",
+ pr_err("rx_ring->lbq_base = %p\n", rx_ring->lbq_base);
+ pr_err("rx_ring->lbq_base_dma = %llx\n",
(unsigned long long) rx_ring->lbq_base_dma);
- printk(KERN_ERR PFX "rx_ring->lbq_base_indirect = %p.\n",
+ pr_err("rx_ring->lbq_base_indirect = %p\n",
rx_ring->lbq_base_indirect);
- printk(KERN_ERR PFX "rx_ring->lbq_base_indirect_dma = %llx.\n",
+ pr_err("rx_ring->lbq_base_indirect_dma = %llx\n",
(unsigned long long) rx_ring->lbq_base_indirect_dma);
- printk(KERN_ERR PFX "rx_ring->lbq = %p.\n", rx_ring->lbq);
- printk(KERN_ERR PFX "rx_ring->lbq_len = %d.\n", rx_ring->lbq_len);
- printk(KERN_ERR PFX "rx_ring->lbq_size = %d.\n", rx_ring->lbq_size);
- printk(KERN_ERR PFX "rx_ring->lbq_prod_idx_db_reg = %p.\n",
+ pr_err("rx_ring->lbq = %p\n", rx_ring->lbq);
+ pr_err("rx_ring->lbq_len = %d\n", rx_ring->lbq_len);
+ pr_err("rx_ring->lbq_size = %d\n", rx_ring->lbq_size);
+ pr_err("rx_ring->lbq_prod_idx_db_reg = %p\n",
rx_ring->lbq_prod_idx_db_reg);
- printk(KERN_ERR PFX "rx_ring->lbq_prod_idx = %d.\n",
- rx_ring->lbq_prod_idx);
- printk(KERN_ERR PFX "rx_ring->lbq_curr_idx = %d.\n",
- rx_ring->lbq_curr_idx);
- printk(KERN_ERR PFX "rx_ring->lbq_clean_idx = %d.\n",
- rx_ring->lbq_clean_idx);
- printk(KERN_ERR PFX "rx_ring->lbq_free_cnt = %d.\n",
- rx_ring->lbq_free_cnt);
- printk(KERN_ERR PFX "rx_ring->lbq_buf_size = %d.\n",
- rx_ring->lbq_buf_size);
-
- printk(KERN_ERR PFX "rx_ring->sbq_base = %p.\n", rx_ring->sbq_base);
- printk(KERN_ERR PFX "rx_ring->sbq_base_dma = %llx.\n",
+ pr_err("rx_ring->lbq_prod_idx = %d\n", rx_ring->lbq_prod_idx);
+ pr_err("rx_ring->lbq_curr_idx = %d\n", rx_ring->lbq_curr_idx);
+ pr_err("rx_ring->lbq_clean_idx = %d\n", rx_ring->lbq_clean_idx);
+ pr_err("rx_ring->lbq_free_cnt = %d\n", rx_ring->lbq_free_cnt);
+ pr_err("rx_ring->lbq_buf_size = %d\n", rx_ring->lbq_buf_size);
+
+ pr_err("rx_ring->sbq_base = %p\n", rx_ring->sbq_base);
+ pr_err("rx_ring->sbq_base_dma = %llx\n",
(unsigned long long) rx_ring->sbq_base_dma);
- printk(KERN_ERR PFX "rx_ring->sbq_base_indirect = %p.\n",
+ pr_err("rx_ring->sbq_base_indirect = %p\n",
rx_ring->sbq_base_indirect);
- printk(KERN_ERR PFX "rx_ring->sbq_base_indirect_dma = %llx.\n",
+ pr_err("rx_ring->sbq_base_indirect_dma = %llx\n",
(unsigned long long) rx_ring->sbq_base_indirect_dma);
- printk(KERN_ERR PFX "rx_ring->sbq = %p.\n", rx_ring->sbq);
- printk(KERN_ERR PFX "rx_ring->sbq_len = %d.\n", rx_ring->sbq_len);
- printk(KERN_ERR PFX "rx_ring->sbq_size = %d.\n", rx_ring->sbq_size);
- printk(KERN_ERR PFX "rx_ring->sbq_prod_idx_db_reg addr = %p.\n",
+ pr_err("rx_ring->sbq = %p\n", rx_ring->sbq);
+ pr_err("rx_ring->sbq_len = %d\n", rx_ring->sbq_len);
+ pr_err("rx_ring->sbq_size = %d\n", rx_ring->sbq_size);
+ pr_err("rx_ring->sbq_prod_idx_db_reg addr = %p\n",
rx_ring->sbq_prod_idx_db_reg);
- printk(KERN_ERR PFX "rx_ring->sbq_prod_idx = %d.\n",
- rx_ring->sbq_prod_idx);
- printk(KERN_ERR PFX "rx_ring->sbq_curr_idx = %d.\n",
- rx_ring->sbq_curr_idx);
- printk(KERN_ERR PFX "rx_ring->sbq_clean_idx = %d.\n",
- rx_ring->sbq_clean_idx);
- printk(KERN_ERR PFX "rx_ring->sbq_free_cnt = %d.\n",
- rx_ring->sbq_free_cnt);
- printk(KERN_ERR PFX "rx_ring->sbq_buf_size = %d.\n",
- rx_ring->sbq_buf_size);
- printk(KERN_ERR PFX "rx_ring->cq_id = %d.\n", rx_ring->cq_id);
- printk(KERN_ERR PFX "rx_ring->irq = %d.\n", rx_ring->irq);
- printk(KERN_ERR PFX "rx_ring->cpu = %d.\n", rx_ring->cpu);
- printk(KERN_ERR PFX "rx_ring->qdev = %p.\n", rx_ring->qdev);
+ pr_err("rx_ring->sbq_prod_idx = %d\n", rx_ring->sbq_prod_idx);
+ pr_err("rx_ring->sbq_curr_idx = %d\n", rx_ring->sbq_curr_idx);
+ pr_err("rx_ring->sbq_clean_idx = %d\n", rx_ring->sbq_clean_idx);
+ pr_err("rx_ring->sbq_free_cnt = %d\n", rx_ring->sbq_free_cnt);
+ pr_err("rx_ring->sbq_buf_size = %d\n", rx_ring->sbq_buf_size);
+ pr_err("rx_ring->cq_id = %d\n", rx_ring->cq_id);
+ pr_err("rx_ring->irq = %d\n", rx_ring->irq);
+ pr_err("rx_ring->cpu = %d\n", rx_ring->cpu);
+ pr_err("rx_ring->qdev = %p\n", rx_ring->qdev);
}
void ql_dump_hw_cb(struct ql_adapter *qdev, int size, u32 bit, u16 q_id)
{
void *ptr;
- printk(KERN_ERR PFX "%s: Enter.\n", __func__);
+ pr_err("%s: Enter\n", __func__);
ptr = kmalloc(size, GFP_ATOMIC);
if (ptr == NULL) {
- printk(KERN_ERR PFX "%s: Couldn't allocate a buffer.\n",
- __func__);
+ pr_err("%s: Couldn't allocate a buffer\n", __func__);
return;
}
if (ql_write_cfg(qdev, ptr, size, bit, q_id)) {
- printk(KERN_ERR "%s: Failed to upload control block!\n",
- __func__);
+ pr_err("%s: Failed to upload control block!\n", __func__);
goto fail_it;
}
switch (bit) {
@@ -2000,8 +1825,7 @@ void ql_dump_hw_cb(struct ql_adapter *qdev, int size, u32 bit, u16 q_id)
ql_dump_ricb((struct ricb *)ptr);
break;
default:
- printk(KERN_ERR PFX "%s: Invalid bit value = %x.\n",
- __func__, bit);
+ pr_err("%s: Invalid bit value = %x\n", __func__, bit);
break;
}
fail_it:
@@ -2012,27 +1836,27 @@ fail_it:
#ifdef QL_OB_DUMP
void ql_dump_tx_desc(struct tx_buf_desc *tbd)
{
- printk(KERN_ERR PFX "tbd->addr = 0x%llx\n",
+ pr_err("tbd->addr = 0x%llx\n",
le64_to_cpu((u64) tbd->addr));
- printk(KERN_ERR PFX "tbd->len = %d\n",
+ pr_err("tbd->len = %d\n",
le32_to_cpu(tbd->len & TX_DESC_LEN_MASK));
- printk(KERN_ERR PFX "tbd->flags = %s %s\n",
+ pr_err("tbd->flags = %s %s\n",
tbd->len & TX_DESC_C ? "C" : ".",
tbd->len & TX_DESC_E ? "E" : ".");
tbd++;
- printk(KERN_ERR PFX "tbd->addr = 0x%llx\n",
+ pr_err("tbd->addr = 0x%llx\n",
le64_to_cpu((u64) tbd->addr));
- printk(KERN_ERR PFX "tbd->len = %d\n",
+ pr_err("tbd->len = %d\n",
le32_to_cpu(tbd->len & TX_DESC_LEN_MASK));
- printk(KERN_ERR PFX "tbd->flags = %s %s\n",
+ pr_err("tbd->flags = %s %s\n",
tbd->len & TX_DESC_C ? "C" : ".",
tbd->len & TX_DESC_E ? "E" : ".");
tbd++;
- printk(KERN_ERR PFX "tbd->addr = 0x%llx\n",
+ pr_err("tbd->addr = 0x%llx\n",
le64_to_cpu((u64) tbd->addr));
- printk(KERN_ERR PFX "tbd->len = %d\n",
+ pr_err("tbd->len = %d\n",
le32_to_cpu(tbd->len & TX_DESC_LEN_MASK));
- printk(KERN_ERR PFX "tbd->flags = %s %s\n",
+ pr_err("tbd->flags = %s %s\n",
tbd->len & TX_DESC_C ? "C" : ".",
tbd->len & TX_DESC_E ? "E" : ".");
@@ -2045,38 +1869,38 @@ void ql_dump_ob_mac_iocb(struct ob_mac_iocb_req *ob_mac_iocb)
struct tx_buf_desc *tbd;
u16 frame_len;
- printk(KERN_ERR PFX "%s\n", __func__);
- printk(KERN_ERR PFX "opcode = %s\n",
+ pr_err("%s\n", __func__);
+ pr_err("opcode = %s\n",
(ob_mac_iocb->opcode == OPCODE_OB_MAC_IOCB) ? "MAC" : "TSO");
- printk(KERN_ERR PFX "flags1 = %s %s %s %s %s\n",
+ pr_err("flags1 = %s %s %s %s %s\n",
ob_mac_tso_iocb->flags1 & OB_MAC_TSO_IOCB_OI ? "OI" : "",
ob_mac_tso_iocb->flags1 & OB_MAC_TSO_IOCB_I ? "I" : "",
ob_mac_tso_iocb->flags1 & OB_MAC_TSO_IOCB_D ? "D" : "",
ob_mac_tso_iocb->flags1 & OB_MAC_TSO_IOCB_IP4 ? "IP4" : "",
ob_mac_tso_iocb->flags1 & OB_MAC_TSO_IOCB_IP6 ? "IP6" : "");
- printk(KERN_ERR PFX "flags2 = %s %s %s\n",
+ pr_err("flags2 = %s %s %s\n",
ob_mac_tso_iocb->flags2 & OB_MAC_TSO_IOCB_LSO ? "LSO" : "",
ob_mac_tso_iocb->flags2 & OB_MAC_TSO_IOCB_UC ? "UC" : "",
ob_mac_tso_iocb->flags2 & OB_MAC_TSO_IOCB_TC ? "TC" : "");
- printk(KERN_ERR PFX "flags3 = %s %s %s\n",
+ pr_err("flags3 = %s %s %s\n",
ob_mac_tso_iocb->flags3 & OB_MAC_TSO_IOCB_IC ? "IC" : "",
ob_mac_tso_iocb->flags3 & OB_MAC_TSO_IOCB_DFP ? "DFP" : "",
ob_mac_tso_iocb->flags3 & OB_MAC_TSO_IOCB_V ? "V" : "");
- printk(KERN_ERR PFX "tid = %x\n", ob_mac_iocb->tid);
- printk(KERN_ERR PFX "txq_idx = %d\n", ob_mac_iocb->txq_idx);
- printk(KERN_ERR PFX "vlan_tci = %x\n", ob_mac_tso_iocb->vlan_tci);
+ pr_err("tid = %x\n", ob_mac_iocb->tid);
+ pr_err("txq_idx = %d\n", ob_mac_iocb->txq_idx);
+ pr_err("vlan_tci = %x\n", ob_mac_tso_iocb->vlan_tci);
if (ob_mac_iocb->opcode == OPCODE_OB_MAC_TSO_IOCB) {
- printk(KERN_ERR PFX "frame_len = %d\n",
+ pr_err("frame_len = %d\n",
le32_to_cpu(ob_mac_tso_iocb->frame_len));
- printk(KERN_ERR PFX "mss = %d\n",
+ pr_err("mss = %d\n",
le16_to_cpu(ob_mac_tso_iocb->mss));
- printk(KERN_ERR PFX "prot_hdr_len = %d\n",
+ pr_err("prot_hdr_len = %d\n",
le16_to_cpu(ob_mac_tso_iocb->total_hdrs_len));
- printk(KERN_ERR PFX "hdr_offset = 0x%.04x\n",
+ pr_err("hdr_offset = 0x%.04x\n",
le16_to_cpu(ob_mac_tso_iocb->net_trans_offset));
frame_len = le32_to_cpu(ob_mac_tso_iocb->frame_len);
} else {
- printk(KERN_ERR PFX "frame_len = %d\n",
+ pr_err("frame_len = %d\n",
le16_to_cpu(ob_mac_iocb->frame_len));
frame_len = le16_to_cpu(ob_mac_iocb->frame_len);
}
@@ -2086,9 +1910,9 @@ void ql_dump_ob_mac_iocb(struct ob_mac_iocb_req *ob_mac_iocb)
void ql_dump_ob_mac_rsp(struct ob_mac_iocb_rsp *ob_mac_rsp)
{
- printk(KERN_ERR PFX "%s\n", __func__);
- printk(KERN_ERR PFX "opcode = %d\n", ob_mac_rsp->opcode);
- printk(KERN_ERR PFX "flags = %s %s %s %s %s %s %s\n",
+ pr_err("%s\n", __func__);
+ pr_err("opcode = %d\n", ob_mac_rsp->opcode);
+ pr_err("flags = %s %s %s %s %s %s %s\n",
ob_mac_rsp->flags1 & OB_MAC_IOCB_RSP_OI ? "OI" : ".",
ob_mac_rsp->flags1 & OB_MAC_IOCB_RSP_I ? "I" : ".",
ob_mac_rsp->flags1 & OB_MAC_IOCB_RSP_E ? "E" : ".",
@@ -2096,16 +1920,16 @@ void ql_dump_ob_mac_rsp(struct ob_mac_iocb_rsp *ob_mac_rsp)
ob_mac_rsp->flags1 & OB_MAC_IOCB_RSP_L ? "L" : ".",
ob_mac_rsp->flags1 & OB_MAC_IOCB_RSP_P ? "P" : ".",
ob_mac_rsp->flags2 & OB_MAC_IOCB_RSP_B ? "B" : ".");
- printk(KERN_ERR PFX "tid = %x\n", ob_mac_rsp->tid);
+ pr_err("tid = %x\n", ob_mac_rsp->tid);
}
#endif
#ifdef QL_IB_DUMP
void ql_dump_ib_mac_rsp(struct ib_mac_iocb_rsp *ib_mac_rsp)
{
- printk(KERN_ERR PFX "%s\n", __func__);
- printk(KERN_ERR PFX "opcode = 0x%x\n", ib_mac_rsp->opcode);
- printk(KERN_ERR PFX "flags1 = %s%s%s%s%s%s\n",
+ pr_err("%s\n", __func__);
+ pr_err("opcode = 0x%x\n", ib_mac_rsp->opcode);
+ pr_err("flags1 = %s%s%s%s%s%s\n",
ib_mac_rsp->flags1 & IB_MAC_IOCB_RSP_OI ? "OI " : "",
ib_mac_rsp->flags1 & IB_MAC_IOCB_RSP_I ? "I " : "",
ib_mac_rsp->flags1 & IB_MAC_IOCB_RSP_TE ? "TE " : "",
@@ -2114,7 +1938,7 @@ void ql_dump_ib_mac_rsp(struct ib_mac_iocb_rsp *ib_mac_rsp)
ib_mac_rsp->flags1 & IB_MAC_IOCB_RSP_B ? "B " : "");
if (ib_mac_rsp->flags1 & IB_MAC_IOCB_RSP_M_MASK)
- printk(KERN_ERR PFX "%s%s%s Multicast.\n",
+ pr_err("%s%s%s Multicast\n",
(ib_mac_rsp->flags1 & IB_MAC_IOCB_RSP_M_MASK) ==
IB_MAC_IOCB_RSP_M_HASH ? "Hash" : "",
(ib_mac_rsp->flags1 & IB_MAC_IOCB_RSP_M_MASK) ==
@@ -2122,7 +1946,7 @@ void ql_dump_ib_mac_rsp(struct ib_mac_iocb_rsp *ib_mac_rsp)
(ib_mac_rsp->flags1 & IB_MAC_IOCB_RSP_M_MASK) ==
IB_MAC_IOCB_RSP_M_PROM ? "Promiscuous" : "");
- printk(KERN_ERR PFX "flags2 = %s%s%s%s%s\n",
+ pr_err("flags2 = %s%s%s%s%s\n",
(ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_P) ? "P " : "",
(ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_V) ? "V " : "",
(ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_U) ? "U " : "",
@@ -2130,7 +1954,7 @@ void ql_dump_ib_mac_rsp(struct ib_mac_iocb_rsp *ib_mac_rsp)
(ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_FO) ? "FO " : "");
if (ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_ERR_MASK)
- printk(KERN_ERR PFX "%s%s%s%s%s error.\n",
+ pr_err("%s%s%s%s%s error\n",
(ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_ERR_MASK) ==
IB_MAC_IOCB_RSP_ERR_OVERSIZE ? "oversize" : "",
(ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_ERR_MASK) ==
@@ -2142,12 +1966,12 @@ void ql_dump_ib_mac_rsp(struct ib_mac_iocb_rsp *ib_mac_rsp)
(ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_ERR_MASK) ==
IB_MAC_IOCB_RSP_ERR_CRC ? "CRC" : "");
- printk(KERN_ERR PFX "flags3 = %s%s.\n",
+ pr_err("flags3 = %s%s\n",
ib_mac_rsp->flags3 & IB_MAC_IOCB_RSP_DS ? "DS " : "",
ib_mac_rsp->flags3 & IB_MAC_IOCB_RSP_DL ? "DL " : "");
if (ib_mac_rsp->flags3 & IB_MAC_IOCB_RSP_RSS_MASK)
- printk(KERN_ERR PFX "RSS flags = %s%s%s%s.\n",
+ pr_err("RSS flags = %s%s%s%s\n",
((ib_mac_rsp->flags3 & IB_MAC_IOCB_RSP_RSS_MASK) ==
IB_MAC_IOCB_RSP_M_IPV4) ? "IPv4 RSS" : "",
((ib_mac_rsp->flags3 & IB_MAC_IOCB_RSP_RSS_MASK) ==
@@ -2157,26 +1981,26 @@ void ql_dump_ib_mac_rsp(struct ib_mac_iocb_rsp *ib_mac_rsp)
((ib_mac_rsp->flags3 & IB_MAC_IOCB_RSP_RSS_MASK) ==
IB_MAC_IOCB_RSP_M_TCP_V6) ? "TCP/IPv6 RSS" : "");
- printk(KERN_ERR PFX "data_len = %d\n",
+ pr_err("data_len = %d\n",
le32_to_cpu(ib_mac_rsp->data_len));
- printk(KERN_ERR PFX "data_addr = 0x%llx\n",
+ pr_err("data_addr = 0x%llx\n",
(unsigned long long) le64_to_cpu(ib_mac_rsp->data_addr));
if (ib_mac_rsp->flags3 & IB_MAC_IOCB_RSP_RSS_MASK)
- printk(KERN_ERR PFX "rss = %x\n",
+ pr_err("rss = %x\n",
le32_to_cpu(ib_mac_rsp->rss));
if (ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_V)
- printk(KERN_ERR PFX "vlan_id = %x\n",
+ pr_err("vlan_id = %x\n",
le16_to_cpu(ib_mac_rsp->vlan_id));
- printk(KERN_ERR PFX "flags4 = %s%s%s.\n",
+ pr_err("flags4 = %s%s%s\n",
ib_mac_rsp->flags4 & IB_MAC_IOCB_RSP_HV ? "HV " : "",
ib_mac_rsp->flags4 & IB_MAC_IOCB_RSP_HS ? "HS " : "",
ib_mac_rsp->flags4 & IB_MAC_IOCB_RSP_HL ? "HL " : "");
if (ib_mac_rsp->flags4 & IB_MAC_IOCB_RSP_HV) {
- printk(KERN_ERR PFX "hdr length = %d.\n",
+ pr_err("hdr length = %d\n",
le32_to_cpu(ib_mac_rsp->hdr_len));
- printk(KERN_ERR PFX "hdr addr = 0x%llx.\n",
+ pr_err("hdr addr = 0x%llx\n",
(unsigned long long) le64_to_cpu(ib_mac_rsp->hdr_addr));
}
}
diff --git a/drivers/net/qlge/qlge_main.c b/drivers/net/qlge/qlge_main.c
index d10bcefc0e4..8d63f69b27d 100644
--- a/drivers/net/qlge/qlge_main.c
+++ b/drivers/net/qlge/qlge_main.c
@@ -574,6 +574,22 @@ static int ql_set_routing_reg(struct ql_adapter *qdev, u32 index, u32 mask,
(RT_IDX_ALL_ERR_SLOT << RT_IDX_IDX_SHIFT);/* index */
break;
}
+ case RT_IDX_IP_CSUM_ERR: /* Pass up IP CSUM error frames. */
+ {
+ value = RT_IDX_DST_DFLT_Q | /* dest */
+ RT_IDX_TYPE_NICQ | /* type */
+ (RT_IDX_IP_CSUM_ERR_SLOT <<
+ RT_IDX_IDX_SHIFT); /* index */
+ break;
+ }
+ case RT_IDX_TU_CSUM_ERR: /* Pass up TCP/UDP CSUM error frames. */
+ {
+ value = RT_IDX_DST_DFLT_Q | /* dest */
+ RT_IDX_TYPE_NICQ | /* type */
+ (RT_IDX_TCP_UDP_CSUM_ERR_SLOT <<
+ RT_IDX_IDX_SHIFT); /* index */
+ break;
+ }
case RT_IDX_BCAST: /* Pass up Broadcast frames to default Q. */
{
value = RT_IDX_DST_DFLT_Q | /* dest */
@@ -1521,7 +1537,7 @@ static void ql_process_mac_rx_page(struct ql_adapter *qdev,
/* Frame error, so drop the packet. */
if (ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_ERR_MASK) {
- netif_err(qdev, drv, qdev->ndev,
+ netif_info(qdev, drv, qdev->ndev,
"Receive error, flags2 = 0x%x\n", ib_mac_rsp->flags2);
rx_ring->rx_errors++;
goto err_out;
@@ -1618,7 +1634,7 @@ static void ql_process_mac_rx_skb(struct ql_adapter *qdev,
/* Frame error, so drop the packet. */
if (ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_ERR_MASK) {
- netif_err(qdev, drv, qdev->ndev,
+ netif_info(qdev, drv, qdev->ndev,
"Receive error, flags2 = 0x%x\n", ib_mac_rsp->flags2);
dev_kfree_skb_any(skb);
rx_ring->rx_errors++;
@@ -1677,7 +1693,7 @@ static void ql_process_mac_rx_skb(struct ql_adapter *qdev,
/* Unfragmented ipv4 UDP frame. */
struct iphdr *iph = (struct iphdr *) skb->data;
if (!(iph->frag_off &
- cpu_to_be16(IP_MF|IP_OFFSET))) {
+ ntohs(IP_MF|IP_OFFSET))) {
skb->ip_summed = CHECKSUM_UNNECESSARY;
netif_printk(qdev, rx_status, KERN_DEBUG,
qdev->ndev,
@@ -1939,7 +1955,7 @@ static void ql_process_mac_split_rx_intr(struct ql_adapter *qdev,
/* Frame error, so drop the packet. */
if (ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_ERR_MASK) {
- netif_err(qdev, drv, qdev->ndev,
+ netif_info(qdev, drv, qdev->ndev,
"Receive error, flags2 = 0x%x\n", ib_mac_rsp->flags2);
dev_kfree_skb_any(skb);
rx_ring->rx_errors++;
@@ -1997,7 +2013,7 @@ static void ql_process_mac_split_rx_intr(struct ql_adapter *qdev,
/* Unfragmented ipv4 UDP frame. */
struct iphdr *iph = (struct iphdr *) skb->data;
if (!(iph->frag_off &
- cpu_to_be16(IP_MF|IP_OFFSET))) {
+ ntohs(IP_MF|IP_OFFSET))) {
skb->ip_summed = CHECKSUM_UNNECESSARY;
netif_printk(qdev, rx_status, KERN_DEBUG, qdev->ndev,
"TCP checksum done!\n");
@@ -3587,10 +3603,20 @@ static int ql_route_initialize(struct ql_adapter *qdev)
if (status)
return status;
- status = ql_set_routing_reg(qdev, RT_IDX_ALL_ERR_SLOT, RT_IDX_ERR, 1);
+ status = ql_set_routing_reg(qdev, RT_IDX_IP_CSUM_ERR_SLOT,
+ RT_IDX_IP_CSUM_ERR, 1);
+ if (status) {
+ netif_err(qdev, ifup, qdev->ndev,
+ "Failed to init routing register "
+ "for IP CSUM error packets.\n");
+ goto exit;
+ }
+ status = ql_set_routing_reg(qdev, RT_IDX_TCP_UDP_CSUM_ERR_SLOT,
+ RT_IDX_TU_CSUM_ERR, 1);
if (status) {
netif_err(qdev, ifup, qdev->ndev,
- "Failed to init routing register for error packets.\n");
+ "Failed to init routing register "
+ "for TCP/UDP CSUM error packets.\n");
goto exit;
}
status = ql_set_routing_reg(qdev, RT_IDX_BCAST_SLOT, RT_IDX_BCAST, 1);
@@ -3919,6 +3945,11 @@ static int ql_adapter_up(struct ql_adapter *qdev)
if ((ql_read32(qdev, STS) & qdev->port_init) &&
(ql_read32(qdev, STS) & qdev->port_link_up))
ql_link_on(qdev);
+ /* Restore rx mode. */
+ clear_bit(QL_ALLMULTI, &qdev->flags);
+ clear_bit(QL_PROMISCUOUS, &qdev->flags);
+ qlge_set_multicast_list(qdev->ndev);
+
ql_enable_interrupts(qdev);
ql_enable_all_completion_interrupts(qdev);
netif_tx_start_all_queues(qdev->ndev);
@@ -4204,7 +4235,7 @@ static struct net_device_stats *qlge_get_stats(struct net_device
return &ndev->stats;
}
-static void qlge_set_multicast_list(struct net_device *ndev)
+void qlge_set_multicast_list(struct net_device *ndev)
{
struct ql_adapter *qdev = (struct ql_adapter *)netdev_priv(ndev);
struct netdev_hw_addr *ha;
diff --git a/drivers/net/qlge/qlge_mpi.c b/drivers/net/qlge/qlge_mpi.c
index 3c00462a5d2..f84e8570c7c 100644
--- a/drivers/net/qlge/qlge_mpi.c
+++ b/drivers/net/qlge/qlge_mpi.c
@@ -606,23 +606,6 @@ end:
return status;
}
-int ql_mb_sys_err(struct ql_adapter *qdev)
-{
- struct mbox_params mbc;
- struct mbox_params *mbcp = &mbc;
- int status;
-
- memset(mbcp, 0, sizeof(struct mbox_params));
-
- mbcp->in_count = 1;
- mbcp->out_count = 0;
-
- mbcp->mbox_in[0] = MB_CMD_MAKE_SYS_ERR;
-
- status = ql_mailbox_command(qdev, mbcp);
- return status;
-}
-
/* Get MPI firmware version. This will be used for
* driver banner and for ethtool info.
* Returns zero on success.
diff --git a/drivers/net/r6040.c b/drivers/net/r6040.c
index 9a251acf5ab..142c381e1d7 100644
--- a/drivers/net/r6040.c
+++ b/drivers/net/r6040.c
@@ -44,12 +44,13 @@
#include <linux/io.h>
#include <linux/irq.h>
#include <linux/uaccess.h>
+#include <linux/phy.h>
#include <asm/processor.h>
#define DRV_NAME "r6040"
-#define DRV_VERSION "0.25"
-#define DRV_RELDATE "20Aug2009"
+#define DRV_VERSION "0.26"
+#define DRV_RELDATE "30May2010"
/* PHY CHIP Address */
#define PHY1_ADDR 1 /* For MAC1 */
@@ -179,7 +180,6 @@ struct r6040_descriptor {
struct r6040_private {
spinlock_t lock; /* driver lock */
- struct timer_list timer;
struct pci_dev *pdev;
struct r6040_descriptor *rx_insert_ptr;
struct r6040_descriptor *rx_remove_ptr;
@@ -189,13 +189,15 @@ struct r6040_private {
struct r6040_descriptor *tx_ring;
dma_addr_t rx_ring_dma;
dma_addr_t tx_ring_dma;
- u16 tx_free_desc, phy_addr, phy_mode;
+ u16 tx_free_desc, phy_addr;
u16 mcr0, mcr1;
- u16 switch_sig;
struct net_device *dev;
- struct mii_if_info mii_if;
+ struct mii_bus *mii_bus;
struct napi_struct napi;
void __iomem *base;
+ struct phy_device *phydev;
+ int old_link;
+ int old_duplex;
};
static char version[] __devinitdata = KERN_INFO DRV_NAME
@@ -238,20 +240,30 @@ static void r6040_phy_write(void __iomem *ioaddr, int phy_addr, int reg, u16 val
}
}
-static int r6040_mdio_read(struct net_device *dev, int mii_id, int reg)
+static int r6040_mdiobus_read(struct mii_bus *bus, int phy_addr, int reg)
{
+ struct net_device *dev = bus->priv;
struct r6040_private *lp = netdev_priv(dev);
void __iomem *ioaddr = lp->base;
- return (r6040_phy_read(ioaddr, lp->phy_addr, reg));
+ return r6040_phy_read(ioaddr, phy_addr, reg);
}
-static void r6040_mdio_write(struct net_device *dev, int mii_id, int reg, int val)
+static int r6040_mdiobus_write(struct mii_bus *bus, int phy_addr,
+ int reg, u16 value)
{
+ struct net_device *dev = bus->priv;
struct r6040_private *lp = netdev_priv(dev);
void __iomem *ioaddr = lp->base;
- r6040_phy_write(ioaddr, lp->phy_addr, reg, val);
+ r6040_phy_write(ioaddr, phy_addr, reg, value);
+
+ return 0;
+}
+
+static int r6040_mdiobus_reset(struct mii_bus *bus)
+{
+ return 0;
}
static void r6040_free_txbufs(struct net_device *dev)
@@ -408,10 +420,9 @@ static void r6040_tx_timeout(struct net_device *dev)
void __iomem *ioaddr = priv->base;
netdev_warn(dev, "transmit timed out, int enable %4.4x "
- "status %4.4x, PHY status %4.4x\n",
+ "status %4.4x\n",
ioread16(ioaddr + MIER),
- ioread16(ioaddr + MISR),
- r6040_mdio_read(dev, priv->mii_if.phy_id, MII_BMSR));
+ ioread16(ioaddr + MISR));
dev->stats.tx_errors++;
@@ -463,9 +474,6 @@ static int r6040_close(struct net_device *dev)
struct r6040_private *lp = netdev_priv(dev);
struct pci_dev *pdev = lp->pdev;
- /* deleted timer */
- del_timer_sync(&lp->timer);
-
spin_lock_irq(&lp->lock);
napi_disable(&lp->napi);
netif_stop_queue(dev);
@@ -495,64 +503,14 @@ static int r6040_close(struct net_device *dev)
return 0;
}
-/* Status of PHY CHIP */
-static int r6040_phy_mode_chk(struct net_device *dev)
-{
- struct r6040_private *lp = netdev_priv(dev);
- void __iomem *ioaddr = lp->base;
- int phy_dat;
-
- /* PHY Link Status Check */
- phy_dat = r6040_phy_read(ioaddr, lp->phy_addr, 1);
- if (!(phy_dat & 0x4))
- phy_dat = 0x8000; /* Link Failed, full duplex */
-
- /* PHY Chip Auto-Negotiation Status */
- phy_dat = r6040_phy_read(ioaddr, lp->phy_addr, 1);
- if (phy_dat & 0x0020) {
- /* Auto Negotiation Mode */
- phy_dat = r6040_phy_read(ioaddr, lp->phy_addr, 5);
- phy_dat &= r6040_phy_read(ioaddr, lp->phy_addr, 4);
- if (phy_dat & 0x140)
- /* Force full duplex */
- phy_dat = 0x8000;
- else
- phy_dat = 0;
- } else {
- /* Force Mode */
- phy_dat = r6040_phy_read(ioaddr, lp->phy_addr, 0);
- if (phy_dat & 0x100)
- phy_dat = 0x8000;
- else
- phy_dat = 0x0000;
- }
-
- return phy_dat;
-};
-
-static void r6040_set_carrier(struct mii_if_info *mii)
-{
- if (r6040_phy_mode_chk(mii->dev)) {
- /* autoneg is off: Link is always assumed to be up */
- if (!netif_carrier_ok(mii->dev))
- netif_carrier_on(mii->dev);
- } else
- r6040_phy_mode_chk(mii->dev);
-}
-
static int r6040_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
{
struct r6040_private *lp = netdev_priv(dev);
- struct mii_ioctl_data *data = if_mii(rq);
- int rc;
- if (!netif_running(dev))
+ if (!lp->phydev)
return -EINVAL;
- spin_lock_irq(&lp->lock);
- rc = generic_mii_ioctl(&lp->mii_if, data, cmd, NULL);
- spin_unlock_irq(&lp->lock);
- r6040_set_carrier(&lp->mii_if);
- return rc;
+
+ return phy_mii_ioctl(lp->phydev, rq, cmd);
}
static int r6040_rx(struct net_device *dev, int limit)
@@ -751,26 +709,6 @@ static int r6040_up(struct net_device *dev)
if (ret)
return ret;
- /* Read the PHY ID */
- lp->switch_sig = r6040_phy_read(ioaddr, 0, 2);
-
- if (lp->switch_sig == ICPLUS_PHY_ID) {
- r6040_phy_write(ioaddr, 29, 31, 0x175C); /* Enable registers */
- lp->phy_mode = 0x8000;
- } else {
- /* PHY Mode Check */
- r6040_phy_write(ioaddr, lp->phy_addr, 4, PHY_CAP);
- r6040_phy_write(ioaddr, lp->phy_addr, 0, PHY_MODE);
-
- if (PHY_MODE == 0x3100)
- lp->phy_mode = r6040_phy_mode_chk(dev);
- else
- lp->phy_mode = (PHY_MODE & 0x0100) ? 0x8000:0x0;
- }
-
- /* Set duplex mode */
- lp->mcr0 |= lp->phy_mode;
-
/* improve performance (by RDC guys) */
r6040_phy_write(ioaddr, 30, 17, (r6040_phy_read(ioaddr, 30, 17) | 0x4000));
r6040_phy_write(ioaddr, 30, 17, ~((~r6040_phy_read(ioaddr, 30, 17)) | 0x2000));
@@ -783,35 +721,6 @@ static int r6040_up(struct net_device *dev)
return 0;
}
-/*
- A periodic timer routine
- Polling PHY Chip Link Status
-*/
-static void r6040_timer(unsigned long data)
-{
- struct net_device *dev = (struct net_device *)data;
- struct r6040_private *lp = netdev_priv(dev);
- void __iomem *ioaddr = lp->base;
- u16 phy_mode;
-
- /* Polling PHY Chip Status */
- if (PHY_MODE == 0x3100)
- phy_mode = r6040_phy_mode_chk(dev);
- else
- phy_mode = (PHY_MODE & 0x0100) ? 0x8000:0x0;
-
- if (phy_mode != lp->phy_mode) {
- lp->phy_mode = phy_mode;
- lp->mcr0 = (lp->mcr0 & 0x7fff) | phy_mode;
- iowrite16(lp->mcr0, ioaddr);
- }
-
- /* Timer active again */
- mod_timer(&lp->timer, round_jiffies(jiffies + HZ));
-
- /* Check media */
- mii_check_media(&lp->mii_if, 1, 1);
-}
/* Read/set MAC address routines */
static void r6040_mac_address(struct net_device *dev)
@@ -873,10 +782,6 @@ static int r6040_open(struct net_device *dev)
napi_enable(&lp->napi);
netif_start_queue(dev);
- /* set and active a timer process */
- setup_timer(&lp->timer, r6040_timer, (unsigned long) dev);
- if (lp->switch_sig != ICPLUS_PHY_ID)
- mod_timer(&lp->timer, jiffies + HZ);
return 0;
}
@@ -1015,40 +920,22 @@ static void netdev_get_drvinfo(struct net_device *dev,
static int netdev_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
{
struct r6040_private *rp = netdev_priv(dev);
- int rc;
-
- spin_lock_irq(&rp->lock);
- rc = mii_ethtool_gset(&rp->mii_if, cmd);
- spin_unlock_irq(&rp->lock);
- return rc;
+ return phy_ethtool_gset(rp->phydev, cmd);
}
static int netdev_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
{
struct r6040_private *rp = netdev_priv(dev);
- int rc;
-
- spin_lock_irq(&rp->lock);
- rc = mii_ethtool_sset(&rp->mii_if, cmd);
- spin_unlock_irq(&rp->lock);
- r6040_set_carrier(&rp->mii_if);
-
- return rc;
-}
-
-static u32 netdev_get_link(struct net_device *dev)
-{
- struct r6040_private *rp = netdev_priv(dev);
- return mii_link_ok(&rp->mii_if);
+ return phy_ethtool_sset(rp->phydev, cmd);
}
static const struct ethtool_ops netdev_ethtool_ops = {
.get_drvinfo = netdev_get_drvinfo,
.get_settings = netdev_get_settings,
.set_settings = netdev_set_settings,
- .get_link = netdev_get_link,
+ .get_link = ethtool_op_get_link,
};
static const struct net_device_ops r6040_netdev_ops = {
@@ -1067,6 +954,79 @@ static const struct net_device_ops r6040_netdev_ops = {
#endif
};
+static void r6040_adjust_link(struct net_device *dev)
+{
+ struct r6040_private *lp = netdev_priv(dev);
+ struct phy_device *phydev = lp->phydev;
+ int status_changed = 0;
+ void __iomem *ioaddr = lp->base;
+
+ BUG_ON(!phydev);
+
+ if (lp->old_link != phydev->link) {
+ status_changed = 1;
+ lp->old_link = phydev->link;
+ }
+
+ /* reflect duplex change */
+ if (phydev->link && (lp->old_duplex != phydev->duplex)) {
+ lp->mcr0 |= (phydev->duplex == DUPLEX_FULL ? 0x8000 : 0);
+ iowrite16(lp->mcr0, ioaddr);
+
+ status_changed = 1;
+ lp->old_duplex = phydev->duplex;
+ }
+
+ if (status_changed) {
+ pr_info("%s: link %s", dev->name, phydev->link ?
+ "UP" : "DOWN");
+ if (phydev->link)
+ pr_cont(" - %d/%s", phydev->speed,
+ DUPLEX_FULL == phydev->duplex ? "full" : "half");
+ pr_cont("\n");
+ }
+}
+
+static int r6040_mii_probe(struct net_device *dev)
+{
+ struct r6040_private *lp = netdev_priv(dev);
+ struct phy_device *phydev = NULL;
+
+ phydev = phy_find_first(lp->mii_bus);
+ if (!phydev) {
+ dev_err(&lp->pdev->dev, "no PHY found\n");
+ return -ENODEV;
+ }
+
+ phydev = phy_connect(dev, dev_name(&phydev->dev), &r6040_adjust_link,
+ 0, PHY_INTERFACE_MODE_MII);
+
+ if (IS_ERR(phydev)) {
+ dev_err(&lp->pdev->dev, "could not attach to PHY\n");
+ return PTR_ERR(phydev);
+ }
+
+ /* mask with MAC supported features */
+ phydev->supported &= (SUPPORTED_10baseT_Half
+ | SUPPORTED_10baseT_Full
+ | SUPPORTED_100baseT_Half
+ | SUPPORTED_100baseT_Full
+ | SUPPORTED_Autoneg
+ | SUPPORTED_MII
+ | SUPPORTED_TP);
+
+ phydev->advertising = phydev->supported;
+ lp->phydev = phydev;
+ lp->old_link = 0;
+ lp->old_duplex = -1;
+
+ dev_info(&lp->pdev->dev, "attached PHY driver [%s] "
+ "(mii_bus:phy_addr=%s)\n",
+ phydev->drv->name, dev_name(&phydev->dev));
+
+ return 0;
+}
+
static int __devinit r6040_init_one(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
@@ -1077,6 +1037,7 @@ static int __devinit r6040_init_one(struct pci_dev *pdev,
static int card_idx = -1;
int bar = 0;
u16 *adrp;
+ int i;
printk("%s\n", version);
@@ -1163,7 +1124,6 @@ static int __devinit r6040_init_one(struct pci_dev *pdev,
/* Init RDC private data */
lp->mcr0 = 0x1002;
lp->phy_addr = phy_table[card_idx];
- lp->switch_sig = 0;
/* The RDC-specific entries in the device structure. */
dev->netdev_ops = &r6040_netdev_ops;
@@ -1171,28 +1131,54 @@ static int __devinit r6040_init_one(struct pci_dev *pdev,
dev->watchdog_timeo = TX_TIMEOUT;
netif_napi_add(dev, &lp->napi, r6040_poll, 64);
- lp->mii_if.dev = dev;
- lp->mii_if.mdio_read = r6040_mdio_read;
- lp->mii_if.mdio_write = r6040_mdio_write;
- lp->mii_if.phy_id = lp->phy_addr;
- lp->mii_if.phy_id_mask = 0x1f;
- lp->mii_if.reg_num_mask = 0x1f;
-
- /* Check the vendor ID on the PHY, if 0xffff assume none attached */
- if (r6040_phy_read(ioaddr, lp->phy_addr, 2) == 0xffff) {
- dev_err(&pdev->dev, "Failed to detect an attached PHY\n");
- err = -ENODEV;
+
+ lp->mii_bus = mdiobus_alloc();
+ if (!lp->mii_bus) {
+ dev_err(&pdev->dev, "mdiobus_alloc() failed\n");
goto err_out_unmap;
}
+ lp->mii_bus->priv = dev;
+ lp->mii_bus->read = r6040_mdiobus_read;
+ lp->mii_bus->write = r6040_mdiobus_write;
+ lp->mii_bus->reset = r6040_mdiobus_reset;
+ lp->mii_bus->name = "r6040_eth_mii";
+ snprintf(lp->mii_bus->id, MII_BUS_ID_SIZE, "%x", card_idx);
+ lp->mii_bus->irq = kmalloc(sizeof(int)*PHY_MAX_ADDR, GFP_KERNEL);
+ if (!lp->mii_bus->irq) {
+ dev_err(&pdev->dev, "mii_bus irq allocation failed\n");
+ goto err_out_mdio;
+ }
+
+ for (i = 0; i < PHY_MAX_ADDR; i++)
+ lp->mii_bus->irq[i] = PHY_POLL;
+
+ err = mdiobus_register(lp->mii_bus);
+ if (err) {
+ dev_err(&pdev->dev, "failed to register MII bus\n");
+ goto err_out_mdio_irq;
+ }
+
+ err = r6040_mii_probe(dev);
+ if (err) {
+ dev_err(&pdev->dev, "failed to probe MII bus\n");
+ goto err_out_mdio_unregister;
+ }
+
/* Register net device. After this dev->name assign */
err = register_netdev(dev);
if (err) {
dev_err(&pdev->dev, "Failed to register net device\n");
- goto err_out_unmap;
+ goto err_out_mdio_unregister;
}
return 0;
+err_out_mdio_unregister:
+ mdiobus_unregister(lp->mii_bus);
+err_out_mdio_irq:
+ kfree(lp->mii_bus->irq);
+err_out_mdio:
+ mdiobus_free(lp->mii_bus);
err_out_unmap:
pci_iounmap(pdev, ioaddr);
err_out_free_res:
@@ -1206,8 +1192,12 @@ err_out:
static void __devexit r6040_remove_one(struct pci_dev *pdev)
{
struct net_device *dev = pci_get_drvdata(pdev);
+ struct r6040_private *lp = netdev_priv(dev);
unregister_netdev(dev);
+ mdiobus_unregister(lp->mii_bus);
+ kfree(lp->mii_bus->irq);
+ mdiobus_free(lp->mii_bus);
pci_release_regions(pdev);
free_netdev(dev);
pci_disable_device(pdev);
diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c
index cdc6a5c2e70..078bbf4e6f1 100644
--- a/drivers/net/r8169.c
+++ b/drivers/net/r8169.c
@@ -88,7 +88,7 @@ static const int multicast_filter_limit = 32;
#define RTL_W32(reg, val32) writel ((val32), ioaddr + (reg))
#define RTL_R8(reg) readb (ioaddr + (reg))
#define RTL_R16(reg) readw (ioaddr + (reg))
-#define RTL_R32(reg) ((unsigned long) readl (ioaddr + (reg)))
+#define RTL_R32(reg) readl (ioaddr + (reg))
enum mac_version {
RTL_GIGA_MAC_NONE = 0x00,
@@ -3219,11 +3219,8 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
device_set_wakeup_enable(&pdev->dev, tp->features & RTL_FEATURE_WOL);
- if (pci_dev_run_wake(pdev)) {
- pm_runtime_set_active(&pdev->dev);
- pm_runtime_enable(&pdev->dev);
- }
- pm_runtime_idle(&pdev->dev);
+ if (pci_dev_run_wake(pdev))
+ pm_runtime_put_noidle(&pdev->dev);
out:
return rc;
@@ -3246,17 +3243,12 @@ static void __devexit rtl8169_remove_one(struct pci_dev *pdev)
struct net_device *dev = pci_get_drvdata(pdev);
struct rtl8169_private *tp = netdev_priv(dev);
- pm_runtime_get_sync(&pdev->dev);
-
flush_scheduled_work();
unregister_netdev(dev);
- if (pci_dev_run_wake(pdev)) {
- pm_runtime_disable(&pdev->dev);
- pm_runtime_set_suspended(&pdev->dev);
- }
- pm_runtime_put_noidle(&pdev->dev);
+ if (pci_dev_run_wake(pdev))
+ pm_runtime_get_noresume(&pdev->dev);
/* restore original MAC address */
rtl_rar_set(tp, dev->perm_addr);
diff --git a/drivers/net/s2io-regs.h b/drivers/net/s2io-regs.h
index 416669fd68c..3688325c11f 100644
--- a/drivers/net/s2io-regs.h
+++ b/drivers/net/s2io-regs.h
@@ -1,6 +1,6 @@
/************************************************************************
* regs.h: A Linux PCI-X Ethernet driver for Neterion 10GbE Server NIC
- * Copyright(c) 2002-2007 Neterion Inc.
+ * Copyright(c) 2002-2010 Exar Corp.
* This software may be used and distributed according to the terms of
* the GNU General Public License (GPL), incorporated herein by reference.
diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c
index 1d37f0c310c..18bc5b718bb 100644
--- a/drivers/net/s2io.c
+++ b/drivers/net/s2io.c
@@ -1,6 +1,6 @@
/************************************************************************
* s2io.c: A Linux PCI-X Ethernet driver for Neterion 10GbE Server NIC
- * Copyright(c) 2002-2007 Neterion Inc.
+ * Copyright(c) 2002-2010 Exar Corp.
*
* This software may be used and distributed according to the terms of
* the GNU General Public License (GPL), incorporated herein by reference.
@@ -38,7 +38,7 @@
* Tx descriptors that can be associated with each corresponding FIFO.
* intr_type: This defines the type of interrupt. The values can be 0(INTA),
* 2(MSI_X). Default value is '2(MSI_X)'
- * lro_enable: Specifies whether to enable Large Receive Offload (LRO) or not.
+ * lro: Specifies whether to enable Large Receive Offload (LRO) or not.
* Possible values '1' for enable '0' for disable. Default is '0'
* lro_max_pkts: This parameter defines maximum number of packets can be
* aggregated as a single large packet
@@ -90,7 +90,7 @@
#include "s2io.h"
#include "s2io-regs.h"
-#define DRV_VERSION "2.0.26.25"
+#define DRV_VERSION "2.0.26.26"
/* S2io Driver name & version. */
static char s2io_driver_name[] = "Neterion";
@@ -496,7 +496,7 @@ S2IO_PARM_INT(rxsync_frequency, 3);
/* Interrupt type. Values can be 0(INTA), 2(MSI_X) */
S2IO_PARM_INT(intr_type, 2);
/* Large receive offload feature */
-static unsigned int lro_enable;
+static unsigned int lro_enable = 1;
module_param_named(lro, lro_enable, uint, 0);
/* Max pkts to be aggregated by LRO at one time. If not specified,
@@ -795,7 +795,6 @@ static int init_shared_mem(struct s2io_nic *nic)
ring->rx_curr_put_info.ring_len = rx_cfg->num_rxd - 1;
ring->nic = nic;
ring->ring_no = i;
- ring->lro = lro_enable;
blk_cnt = rx_cfg->num_rxd / (rxd_count[nic->rxd_mode] + 1);
/* Allocating all the Rx blocks */
@@ -5797,7 +5796,7 @@ static void s2io_vpd_read(struct s2io_nic *nic)
{
u8 *vpd_data;
u8 data;
- int i = 0, cnt, fail = 0;
+ int i = 0, cnt, len, fail = 0;
int vpd_addr = 0x80;
struct swStat *swstats = &nic->mac_control.stats_info->sw_stat;
@@ -5838,20 +5837,28 @@ static void s2io_vpd_read(struct s2io_nic *nic)
if (!fail) {
/* read serial number of adapter */
- for (cnt = 0; cnt < 256; cnt++) {
+ for (cnt = 0; cnt < 252; cnt++) {
if ((vpd_data[cnt] == 'S') &&
- (vpd_data[cnt+1] == 'N') &&
- (vpd_data[cnt+2] < VPD_STRING_LEN)) {
- memset(nic->serial_num, 0, VPD_STRING_LEN);
- memcpy(nic->serial_num, &vpd_data[cnt + 3],
- vpd_data[cnt+2]);
- break;
+ (vpd_data[cnt+1] == 'N')) {
+ len = vpd_data[cnt+2];
+ if (len < min(VPD_STRING_LEN, 256-cnt-2)) {
+ memcpy(nic->serial_num,
+ &vpd_data[cnt + 3],
+ len);
+ memset(nic->serial_num+len,
+ 0,
+ VPD_STRING_LEN-len);
+ break;
+ }
}
}
}
- if ((!fail) && (vpd_data[1] < VPD_STRING_LEN))
- memcpy(nic->product_name, &vpd_data[3], vpd_data[1]);
+ if ((!fail) && (vpd_data[1] < VPD_STRING_LEN)) {
+ len = vpd_data[1];
+ memcpy(nic->product_name, &vpd_data[3], len);
+ nic->product_name[len] = 0;
+ }
kfree(vpd_data);
swstats->mem_freed += 256;
}
@@ -6707,6 +6714,7 @@ static u32 s2io_ethtool_op_get_tso(struct net_device *dev)
{
return (dev->features & NETIF_F_TSO) != 0;
}
+
static int s2io_ethtool_op_set_tso(struct net_device *dev, u32 data)
{
if (data)
@@ -6717,6 +6725,42 @@ static int s2io_ethtool_op_set_tso(struct net_device *dev, u32 data)
return 0;
}
+static int s2io_ethtool_set_flags(struct net_device *dev, u32 data)
+{
+ struct s2io_nic *sp = netdev_priv(dev);
+ int rc = 0;
+ int changed = 0;
+
+ if (data & ~ETH_FLAG_LRO)
+ return -EINVAL;
+
+ if (data & ETH_FLAG_LRO) {
+ if (lro_enable) {
+ if (!(dev->features & NETIF_F_LRO)) {
+ dev->features |= NETIF_F_LRO;
+ changed = 1;
+ }
+ } else
+ rc = -EINVAL;
+ } else if (dev->features & NETIF_F_LRO) {
+ dev->features &= ~NETIF_F_LRO;
+ changed = 1;
+ }
+
+ if (changed && netif_running(dev)) {
+ s2io_stop_all_tx_queue(sp);
+ s2io_card_down(sp);
+ sp->lro = !!(dev->features & NETIF_F_LRO);
+ rc = s2io_card_up(sp);
+ if (rc)
+ s2io_reset(sp);
+ else
+ s2io_start_all_tx_queue(sp);
+ }
+
+ return rc;
+}
+
static const struct ethtool_ops netdev_ethtool_ops = {
.get_settings = s2io_ethtool_gset,
.set_settings = s2io_ethtool_sset,
@@ -6733,6 +6777,8 @@ static const struct ethtool_ops netdev_ethtool_ops = {
.get_rx_csum = s2io_ethtool_get_rx_csum,
.set_rx_csum = s2io_ethtool_set_rx_csum,
.set_tx_csum = s2io_ethtool_op_set_tx_csum,
+ .set_flags = s2io_ethtool_set_flags,
+ .get_flags = ethtool_op_get_flags,
.set_sg = ethtool_op_set_sg,
.get_tso = s2io_ethtool_op_get_tso,
.set_tso = s2io_ethtool_op_set_tso,
@@ -7261,6 +7307,7 @@ static int s2io_card_up(struct s2io_nic *sp)
struct ring_info *ring = &mac_control->rings[i];
ring->mtu = dev->mtu;
+ ring->lro = sp->lro;
ret = fill_rx_buffers(sp, ring, 1);
if (ret) {
DBG_PRINT(ERR_DBG, "%s: Out of memory in Open\n",
@@ -7847,7 +7894,6 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
/* Private member variable initialized to s2io NIC structure */
sp = netdev_priv(dev);
- memset(sp, 0, sizeof(struct s2io_nic));
sp->dev = dev;
sp->pdev = pdev;
sp->high_dma_flag = dma_flag;
@@ -8001,7 +8047,8 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
dev->netdev_ops = &s2io_netdev_ops;
SET_ETHTOOL_OPS(dev, &netdev_ethtool_ops);
dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
-
+ if (lro_enable)
+ dev->features |= NETIF_F_LRO;
dev->features |= NETIF_F_SG | NETIF_F_IP_CSUM;
if (sp->high_dma_flag == true)
dev->features |= NETIF_F_HIGHDMA;
@@ -8159,7 +8206,7 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
goto register_failed;
}
s2io_vpd_read(sp);
- DBG_PRINT(ERR_DBG, "Copyright(c) 2002-2007 Neterion Inc.\n");
+ DBG_PRINT(ERR_DBG, "Copyright(c) 2002-2010 Exar Corp.\n");
DBG_PRINT(ERR_DBG, "%s: Neterion %s (rev %d)\n", dev->name,
sp->product_name, pdev->revision);
DBG_PRINT(ERR_DBG, "%s: Driver version %s\n", dev->name,
diff --git a/drivers/net/s2io.h b/drivers/net/s2io.h
index 7f3a53dcc6e..0af03353390 100644
--- a/drivers/net/s2io.h
+++ b/drivers/net/s2io.h
@@ -1,6 +1,6 @@
/************************************************************************
* s2io.h: A Linux PCI-X Ethernet driver for Neterion 10GbE Server NIC
- * Copyright(c) 2002-2007 Neterion Inc.
+ * Copyright(c) 2002-2010 Exar Corp.
* This software may be used and distributed according to the terms of
* the GNU General Public License (GPL), incorporated herein by reference.
diff --git a/drivers/net/sb1250-mac.c b/drivers/net/sb1250-mac.c
index 79eee306208..8e6bd45b9f3 100644
--- a/drivers/net/sb1250-mac.c
+++ b/drivers/net/sb1250-mac.c
@@ -2532,7 +2532,7 @@ static int sbmac_mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
if (!netif_running(dev) || !sc->phy_dev)
return -EINVAL;
- return phy_mii_ioctl(sc->phy_dev, if_mii(rq), cmd);
+ return phy_mii_ioctl(sc->phy_dev, rq, cmd);
}
static int sbmac_close(struct net_device *dev)
diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c
index 15646052723..ba674c5ca29 100644
--- a/drivers/net/sfc/efx.c
+++ b/drivers/net/sfc/efx.c
@@ -27,6 +27,7 @@
#include "nic.h"
#include "mcdi.h"
+#include "workarounds.h"
/**************************************************************************
*
@@ -92,13 +93,6 @@ const char *efx_reset_type_names[] = {
#define EFX_MAX_MTU (9 * 1024)
-/* RX slow fill workqueue. If memory allocation fails in the fast path,
- * a work item is pushed onto this work queue to retry the allocation later,
- * to avoid the NIC being starved of RX buffers. Since this is a per cpu
- * workqueue, there is nothing to be gained in making it per NIC
- */
-static struct workqueue_struct *refill_workqueue;
-
/* Reset workqueue. If any NIC has a hardware failure then a reset will be
* queued onto this work queue. This is not a per-nic work queue, because
* efx_reset_work() acquires the rtnl lock, so resets are naturally serialised.
@@ -195,6 +189,13 @@ module_param(irq_adapt_high_thresh, uint, 0644);
MODULE_PARM_DESC(irq_adapt_high_thresh,
"Threshold score for increasing IRQ moderation");
+static unsigned debug = (NETIF_MSG_DRV | NETIF_MSG_PROBE |
+ NETIF_MSG_LINK | NETIF_MSG_IFDOWN |
+ NETIF_MSG_IFUP | NETIF_MSG_RX_ERR |
+ NETIF_MSG_TX_ERR | NETIF_MSG_HW);
+module_param(debug, uint, 0);
+MODULE_PARM_DESC(debug, "Bitmapped debugging message enable value");
+
/**************************************************************************
*
* Utility functions and prototypes
@@ -278,16 +279,16 @@ static int efx_poll(struct napi_struct *napi, int budget)
{
struct efx_channel *channel =
container_of(napi, struct efx_channel, napi_str);
+ struct efx_nic *efx = channel->efx;
int spent;
- EFX_TRACE(channel->efx, "channel %d NAPI poll executing on CPU %d\n",
- channel->channel, raw_smp_processor_id());
+ netif_vdbg(efx, intr, efx->net_dev,
+ "channel %d NAPI poll executing on CPU %d\n",
+ channel->channel, raw_smp_processor_id());
spent = efx_process_channel(channel, budget);
if (spent < budget) {
- struct efx_nic *efx = channel->efx;
-
if (channel->channel < efx->n_rx_channels &&
efx->irq_rx_adaptive &&
unlikely(++channel->irq_count == 1000)) {
@@ -363,7 +364,8 @@ void efx_process_channel_now(struct efx_channel *channel)
*/
static int efx_probe_eventq(struct efx_channel *channel)
{
- EFX_LOG(channel->efx, "chan %d create event queue\n", channel->channel);
+ netif_dbg(channel->efx, probe, channel->efx->net_dev,
+ "chan %d create event queue\n", channel->channel);
return efx_nic_probe_eventq(channel);
}
@@ -371,7 +373,8 @@ static int efx_probe_eventq(struct efx_channel *channel)
/* Prepare channel's event queue */
static void efx_init_eventq(struct efx_channel *channel)
{
- EFX_LOG(channel->efx, "chan %d init event queue\n", channel->channel);
+ netif_dbg(channel->efx, drv, channel->efx->net_dev,
+ "chan %d init event queue\n", channel->channel);
channel->eventq_read_ptr = 0;
@@ -380,14 +383,16 @@ static void efx_init_eventq(struct efx_channel *channel)
static void efx_fini_eventq(struct efx_channel *channel)
{
- EFX_LOG(channel->efx, "chan %d fini event queue\n", channel->channel);
+ netif_dbg(channel->efx, drv, channel->efx->net_dev,
+ "chan %d fini event queue\n", channel->channel);
efx_nic_fini_eventq(channel);
}
static void efx_remove_eventq(struct efx_channel *channel)
{
- EFX_LOG(channel->efx, "chan %d remove event queue\n", channel->channel);
+ netif_dbg(channel->efx, drv, channel->efx->net_dev,
+ "chan %d remove event queue\n", channel->channel);
efx_nic_remove_eventq(channel);
}
@@ -404,7 +409,8 @@ static int efx_probe_channel(struct efx_channel *channel)
struct efx_rx_queue *rx_queue;
int rc;
- EFX_LOG(channel->efx, "creating channel %d\n", channel->channel);
+ netif_dbg(channel->efx, probe, channel->efx->net_dev,
+ "creating channel %d\n", channel->channel);
rc = efx_probe_eventq(channel);
if (rc)
@@ -474,12 +480,15 @@ static void efx_init_channels(struct efx_nic *efx)
*/
efx->rx_buffer_len = (max(EFX_PAGE_IP_ALIGN, NET_IP_ALIGN) +
EFX_MAX_FRAME_LEN(efx->net_dev->mtu) +
+ efx->type->rx_buffer_hash_size +
efx->type->rx_buffer_padding);
- efx->rx_buffer_order = get_order(efx->rx_buffer_len);
+ efx->rx_buffer_order = get_order(efx->rx_buffer_len +
+ sizeof(struct efx_rx_page_state));
/* Initialise the channels */
efx_for_each_channel(channel, efx) {
- EFX_LOG(channel->efx, "init chan %d\n", channel->channel);
+ netif_dbg(channel->efx, drv, channel->efx->net_dev,
+ "init chan %d\n", channel->channel);
efx_init_eventq(channel);
@@ -506,7 +515,8 @@ static void efx_start_channel(struct efx_channel *channel)
{
struct efx_rx_queue *rx_queue;
- EFX_LOG(channel->efx, "starting chan %d\n", channel->channel);
+ netif_dbg(channel->efx, ifup, channel->efx->net_dev,
+ "starting chan %d\n", channel->channel);
/* The interrupt handler for this channel may set work_pending
* as soon as we enable it. Make sure it's cleared before
@@ -515,11 +525,11 @@ static void efx_start_channel(struct efx_channel *channel)
channel->enabled = true;
smp_wmb();
- napi_enable(&channel->napi_str);
-
- /* Load up RX descriptors */
+ /* Fill the queues before enabling NAPI */
efx_for_each_channel_rx_queue(rx_queue, channel)
efx_fast_push_rx_descriptors(rx_queue);
+
+ napi_enable(&channel->napi_str);
}
/* This disables event queue processing and packet transmission.
@@ -528,21 +538,14 @@ static void efx_start_channel(struct efx_channel *channel)
*/
static void efx_stop_channel(struct efx_channel *channel)
{
- struct efx_rx_queue *rx_queue;
-
if (!channel->enabled)
return;
- EFX_LOG(channel->efx, "stop chan %d\n", channel->channel);
+ netif_dbg(channel->efx, ifdown, channel->efx->net_dev,
+ "stop chan %d\n", channel->channel);
channel->enabled = false;
napi_disable(&channel->napi_str);
-
- /* Ensure that any worker threads have exited or will be no-ops */
- efx_for_each_channel_rx_queue(rx_queue, channel) {
- spin_lock_bh(&rx_queue->add_lock);
- spin_unlock_bh(&rx_queue->add_lock);
- }
}
static void efx_fini_channels(struct efx_nic *efx)
@@ -556,13 +559,24 @@ static void efx_fini_channels(struct efx_nic *efx)
BUG_ON(efx->port_enabled);
rc = efx_nic_flush_queues(efx);
- if (rc)
- EFX_ERR(efx, "failed to flush queues\n");
- else
- EFX_LOG(efx, "successfully flushed all queues\n");
+ if (rc && EFX_WORKAROUND_7803(efx)) {
+ /* Schedule a reset to recover from the flush failure. The
+ * descriptor caches reference memory we're about to free,
+ * but falcon_reconfigure_mac_wrapper() won't reconnect
+ * the MACs because of the pending reset. */
+ netif_err(efx, drv, efx->net_dev,
+ "Resetting to recover from flush failure\n");
+ efx_schedule_reset(efx, RESET_TYPE_ALL);
+ } else if (rc) {
+ netif_err(efx, drv, efx->net_dev, "failed to flush queues\n");
+ } else {
+ netif_dbg(efx, drv, efx->net_dev,
+ "successfully flushed all queues\n");
+ }
efx_for_each_channel(channel, efx) {
- EFX_LOG(channel->efx, "shut down chan %d\n", channel->channel);
+ netif_dbg(channel->efx, drv, channel->efx->net_dev,
+ "shut down chan %d\n", channel->channel);
efx_for_each_channel_rx_queue(rx_queue, channel)
efx_fini_rx_queue(rx_queue);
@@ -577,7 +591,8 @@ static void efx_remove_channel(struct efx_channel *channel)
struct efx_tx_queue *tx_queue;
struct efx_rx_queue *rx_queue;
- EFX_LOG(channel->efx, "destroy chan %d\n", channel->channel);
+ netif_dbg(channel->efx, drv, channel->efx->net_dev,
+ "destroy chan %d\n", channel->channel);
efx_for_each_channel_rx_queue(rx_queue, channel)
efx_remove_rx_queue(rx_queue);
@@ -586,9 +601,9 @@ static void efx_remove_channel(struct efx_channel *channel)
efx_remove_eventq(channel);
}
-void efx_schedule_slow_fill(struct efx_rx_queue *rx_queue, int delay)
+void efx_schedule_slow_fill(struct efx_rx_queue *rx_queue)
{
- queue_delayed_work(refill_workqueue, &rx_queue->work, delay);
+ mod_timer(&rx_queue->slow_fill, jiffies + msecs_to_jiffies(100));
}
/**************************************************************************
@@ -628,12 +643,13 @@ void efx_link_status_changed(struct efx_nic *efx)
/* Status message for kernel log */
if (link_state->up) {
- EFX_INFO(efx, "link up at %uMbps %s-duplex (MTU %d)%s\n",
- link_state->speed, link_state->fd ? "full" : "half",
- efx->net_dev->mtu,
- (efx->promiscuous ? " [PROMISC]" : ""));
+ netif_info(efx, link, efx->net_dev,
+ "link up at %uMbps %s-duplex (MTU %d)%s\n",
+ link_state->speed, link_state->fd ? "full" : "half",
+ efx->net_dev->mtu,
+ (efx->promiscuous ? " [PROMISC]" : ""));
} else {
- EFX_INFO(efx, "link down\n");
+ netif_info(efx, link, efx->net_dev, "link down\n");
}
}
@@ -737,7 +753,7 @@ static int efx_probe_port(struct efx_nic *efx)
{
int rc;
- EFX_LOG(efx, "create port\n");
+ netif_dbg(efx, probe, efx->net_dev, "create port\n");
if (phy_flash_cfg)
efx->phy_mode = PHY_MODE_SPECIAL;
@@ -751,15 +767,16 @@ static int efx_probe_port(struct efx_nic *efx)
if (is_valid_ether_addr(efx->mac_address)) {
memcpy(efx->net_dev->dev_addr, efx->mac_address, ETH_ALEN);
} else {
- EFX_ERR(efx, "invalid MAC address %pM\n",
- efx->mac_address);
+ netif_err(efx, probe, efx->net_dev, "invalid MAC address %pM\n",
+ efx->mac_address);
if (!allow_bad_hwaddr) {
rc = -EINVAL;
goto err;
}
random_ether_addr(efx->net_dev->dev_addr);
- EFX_INFO(efx, "using locally-generated MAC %pM\n",
- efx->net_dev->dev_addr);
+ netif_info(efx, probe, efx->net_dev,
+ "using locally-generated MAC %pM\n",
+ efx->net_dev->dev_addr);
}
return 0;
@@ -773,7 +790,7 @@ static int efx_init_port(struct efx_nic *efx)
{
int rc;
- EFX_LOG(efx, "init port\n");
+ netif_dbg(efx, drv, efx->net_dev, "init port\n");
mutex_lock(&efx->mac_lock);
@@ -804,7 +821,7 @@ fail1:
static void efx_start_port(struct efx_nic *efx)
{
- EFX_LOG(efx, "start port\n");
+ netif_dbg(efx, ifup, efx->net_dev, "start port\n");
BUG_ON(efx->port_enabled);
mutex_lock(&efx->mac_lock);
@@ -821,7 +838,7 @@ static void efx_start_port(struct efx_nic *efx)
/* Prevent efx_mac_work() and efx_monitor() from working */
static void efx_stop_port(struct efx_nic *efx)
{
- EFX_LOG(efx, "stop port\n");
+ netif_dbg(efx, ifdown, efx->net_dev, "stop port\n");
mutex_lock(&efx->mac_lock);
efx->port_enabled = false;
@@ -836,7 +853,7 @@ static void efx_stop_port(struct efx_nic *efx)
static void efx_fini_port(struct efx_nic *efx)
{
- EFX_LOG(efx, "shut down port\n");
+ netif_dbg(efx, drv, efx->net_dev, "shut down port\n");
if (!efx->port_initialized)
return;
@@ -850,7 +867,7 @@ static void efx_fini_port(struct efx_nic *efx)
static void efx_remove_port(struct efx_nic *efx)
{
- EFX_LOG(efx, "destroying port\n");
+ netif_dbg(efx, drv, efx->net_dev, "destroying port\n");
efx->type->remove_port(efx);
}
@@ -868,11 +885,12 @@ static int efx_init_io(struct efx_nic *efx)
dma_addr_t dma_mask = efx->type->max_dma_mask;
int rc;
- EFX_LOG(efx, "initialising I/O\n");
+ netif_dbg(efx, probe, efx->net_dev, "initialising I/O\n");
rc = pci_enable_device(pci_dev);
if (rc) {
- EFX_ERR(efx, "failed to enable PCI device\n");
+ netif_err(efx, probe, efx->net_dev,
+ "failed to enable PCI device\n");
goto fail1;
}
@@ -890,39 +908,45 @@ static int efx_init_io(struct efx_nic *efx)
dma_mask >>= 1;
}
if (rc) {
- EFX_ERR(efx, "could not find a suitable DMA mask\n");
+ netif_err(efx, probe, efx->net_dev,
+ "could not find a suitable DMA mask\n");
goto fail2;
}
- EFX_LOG(efx, "using DMA mask %llx\n", (unsigned long long) dma_mask);
+ netif_dbg(efx, probe, efx->net_dev,
+ "using DMA mask %llx\n", (unsigned long long) dma_mask);
rc = pci_set_consistent_dma_mask(pci_dev, dma_mask);
if (rc) {
/* pci_set_consistent_dma_mask() is not *allowed* to
* fail with a mask that pci_set_dma_mask() accepted,
* but just in case...
*/
- EFX_ERR(efx, "failed to set consistent DMA mask\n");
+ netif_err(efx, probe, efx->net_dev,
+ "failed to set consistent DMA mask\n");
goto fail2;
}
efx->membase_phys = pci_resource_start(efx->pci_dev, EFX_MEM_BAR);
rc = pci_request_region(pci_dev, EFX_MEM_BAR, "sfc");
if (rc) {
- EFX_ERR(efx, "request for memory BAR failed\n");
+ netif_err(efx, probe, efx->net_dev,
+ "request for memory BAR failed\n");
rc = -EIO;
goto fail3;
}
efx->membase = ioremap_nocache(efx->membase_phys,
efx->type->mem_map_size);
if (!efx->membase) {
- EFX_ERR(efx, "could not map memory BAR at %llx+%x\n",
- (unsigned long long)efx->membase_phys,
- efx->type->mem_map_size);
+ netif_err(efx, probe, efx->net_dev,
+ "could not map memory BAR at %llx+%x\n",
+ (unsigned long long)efx->membase_phys,
+ efx->type->mem_map_size);
rc = -ENOMEM;
goto fail4;
}
- EFX_LOG(efx, "memory BAR at %llx+%x (virtual %p)\n",
- (unsigned long long)efx->membase_phys,
- efx->type->mem_map_size, efx->membase);
+ netif_dbg(efx, probe, efx->net_dev,
+ "memory BAR at %llx+%x (virtual %p)\n",
+ (unsigned long long)efx->membase_phys,
+ efx->type->mem_map_size, efx->membase);
return 0;
@@ -938,7 +962,7 @@ static int efx_init_io(struct efx_nic *efx)
static void efx_fini_io(struct efx_nic *efx)
{
- EFX_LOG(efx, "shutting down I/O\n");
+ netif_dbg(efx, drv, efx->net_dev, "shutting down I/O\n");
if (efx->membase) {
iounmap(efx->membase);
@@ -1002,9 +1026,11 @@ static void efx_probe_interrupts(struct efx_nic *efx)
xentries[i].entry = i;
rc = pci_enable_msix(efx->pci_dev, xentries, n_channels);
if (rc > 0) {
- EFX_ERR(efx, "WARNING: Insufficient MSI-X vectors"
- " available (%d < %d).\n", rc, n_channels);
- EFX_ERR(efx, "WARNING: Performance may be reduced.\n");
+ netif_err(efx, drv, efx->net_dev,
+ "WARNING: Insufficient MSI-X vectors"
+ " available (%d < %d).\n", rc, n_channels);
+ netif_err(efx, drv, efx->net_dev,
+ "WARNING: Performance may be reduced.\n");
EFX_BUG_ON_PARANOID(rc >= n_channels);
n_channels = rc;
rc = pci_enable_msix(efx->pci_dev, xentries,
@@ -1028,7 +1054,8 @@ static void efx_probe_interrupts(struct efx_nic *efx)
} else {
/* Fall back to single channel MSI */
efx->interrupt_mode = EFX_INT_MODE_MSI;
- EFX_ERR(efx, "could not enable MSI-X\n");
+ netif_err(efx, drv, efx->net_dev,
+ "could not enable MSI-X\n");
}
}
@@ -1041,7 +1068,8 @@ static void efx_probe_interrupts(struct efx_nic *efx)
if (rc == 0) {
efx->channel[0].irq = efx->pci_dev->irq;
} else {
- EFX_ERR(efx, "could not enable MSI\n");
+ netif_err(efx, drv, efx->net_dev,
+ "could not enable MSI\n");
efx->interrupt_mode = EFX_INT_MODE_LEGACY;
}
}
@@ -1093,9 +1121,10 @@ static void efx_set_channels(struct efx_nic *efx)
static int efx_probe_nic(struct efx_nic *efx)
{
+ size_t i;
int rc;
- EFX_LOG(efx, "creating NIC\n");
+ netif_dbg(efx, probe, efx->net_dev, "creating NIC\n");
/* Carry out hardware-type specific initialisation */
rc = efx->type->probe(efx);
@@ -1106,6 +1135,11 @@ static int efx_probe_nic(struct efx_nic *efx)
* in MSI-X interrupts. */
efx_probe_interrupts(efx);
+ if (efx->n_channels > 1)
+ get_random_bytes(&efx->rx_hash_key, sizeof(efx->rx_hash_key));
+ for (i = 0; i < ARRAY_SIZE(efx->rx_indir_table); i++)
+ efx->rx_indir_table[i] = i % efx->n_rx_channels;
+
efx_set_channels(efx);
efx->net_dev->real_num_tx_queues = efx->n_tx_channels;
@@ -1117,7 +1151,7 @@ static int efx_probe_nic(struct efx_nic *efx)
static void efx_remove_nic(struct efx_nic *efx)
{
- EFX_LOG(efx, "destroying NIC\n");
+ netif_dbg(efx, drv, efx->net_dev, "destroying NIC\n");
efx_remove_interrupts(efx);
efx->type->remove(efx);
@@ -1137,14 +1171,14 @@ static int efx_probe_all(struct efx_nic *efx)
/* Create NIC */
rc = efx_probe_nic(efx);
if (rc) {
- EFX_ERR(efx, "failed to create NIC\n");
+ netif_err(efx, probe, efx->net_dev, "failed to create NIC\n");
goto fail1;
}
/* Create port */
rc = efx_probe_port(efx);
if (rc) {
- EFX_ERR(efx, "failed to create port\n");
+ netif_err(efx, probe, efx->net_dev, "failed to create port\n");
goto fail2;
}
@@ -1152,8 +1186,9 @@ static int efx_probe_all(struct efx_nic *efx)
efx_for_each_channel(channel, efx) {
rc = efx_probe_channel(channel);
if (rc) {
- EFX_ERR(efx, "failed to create channel %d\n",
- channel->channel);
+ netif_err(efx, probe, efx->net_dev,
+ "failed to create channel %d\n",
+ channel->channel);
goto fail3;
}
}
@@ -1233,15 +1268,8 @@ static void efx_start_all(struct efx_nic *efx)
* since we're holding the rtnl_lock at this point. */
static void efx_flush_all(struct efx_nic *efx)
{
- struct efx_rx_queue *rx_queue;
-
/* Make sure the hardware monitor is stopped */
cancel_delayed_work_sync(&efx->monitor_work);
-
- /* Ensure that all RX slow refills are complete. */
- efx_for_each_rx_queue(rx_queue, efx)
- cancel_delayed_work_sync(&rx_queue->work);
-
/* Stop scheduled port reconfigurations */
cancel_work_sync(&efx->mac_work);
}
@@ -1356,8 +1384,9 @@ static void efx_monitor(struct work_struct *data)
struct efx_nic *efx = container_of(data, struct efx_nic,
monitor_work.work);
- EFX_TRACE(efx, "hardware monitor executing on CPU %d\n",
- raw_smp_processor_id());
+ netif_vdbg(efx, timer, efx->net_dev,
+ "hardware monitor executing on CPU %d\n",
+ raw_smp_processor_id());
BUG_ON(efx->type->monitor == NULL);
/* If the mac_lock is already held then it is likely a port
@@ -1464,8 +1493,8 @@ static int efx_net_open(struct net_device *net_dev)
struct efx_nic *efx = netdev_priv(net_dev);
EFX_ASSERT_RESET_SERIALISED(efx);
- EFX_LOG(efx, "opening device %s on CPU %d\n", net_dev->name,
- raw_smp_processor_id());
+ netif_dbg(efx, ifup, efx->net_dev, "opening device on CPU %d\n",
+ raw_smp_processor_id());
if (efx->state == STATE_DISABLED)
return -EIO;
@@ -1490,8 +1519,8 @@ static int efx_net_stop(struct net_device *net_dev)
{
struct efx_nic *efx = netdev_priv(net_dev);
- EFX_LOG(efx, "closing %s on CPU %d\n", net_dev->name,
- raw_smp_processor_id());
+ netif_dbg(efx, ifdown, efx->net_dev, "closing on CPU %d\n",
+ raw_smp_processor_id());
if (efx->state != STATE_DISABLED) {
/* Stop the device and flush all the channels */
@@ -1504,11 +1533,10 @@ static int efx_net_stop(struct net_device *net_dev)
}
/* Context: process, dev_base_lock or RTNL held, non-blocking. */
-static struct net_device_stats *efx_net_stats(struct net_device *net_dev)
+static struct rtnl_link_stats64 *efx_net_stats(struct net_device *net_dev, struct rtnl_link_stats64 *stats)
{
struct efx_nic *efx = netdev_priv(net_dev);
struct efx_mac_stats *mac_stats = &efx->mac_stats;
- struct net_device_stats *stats = &net_dev->stats;
spin_lock_bh(&efx->stats_lock);
efx->type->update_stats(efx);
@@ -1530,11 +1558,8 @@ static struct net_device_stats *efx_net_stats(struct net_device *net_dev)
stats->tx_window_errors = mac_stats->tx_late_collision;
stats->rx_errors = (stats->rx_length_errors +
- stats->rx_over_errors +
stats->rx_crc_errors +
stats->rx_frame_errors +
- stats->rx_fifo_errors +
- stats->rx_missed_errors +
mac_stats->rx_symbol_error);
stats->tx_errors = (stats->tx_window_errors +
mac_stats->tx_bad);
@@ -1547,8 +1572,9 @@ static void efx_watchdog(struct net_device *net_dev)
{
struct efx_nic *efx = netdev_priv(net_dev);
- EFX_ERR(efx, "TX stuck with port_enabled=%d: resetting channels\n",
- efx->port_enabled);
+ netif_err(efx, tx_err, efx->net_dev,
+ "TX stuck with port_enabled=%d: resetting channels\n",
+ efx->port_enabled);
efx_schedule_reset(efx, RESET_TYPE_TX_WATCHDOG);
}
@@ -1567,7 +1593,7 @@ static int efx_change_mtu(struct net_device *net_dev, int new_mtu)
efx_stop_all(efx);
- EFX_LOG(efx, "changing MTU to %d\n", new_mtu);
+ netif_dbg(efx, drv, efx->net_dev, "changing MTU to %d\n", new_mtu);
efx_fini_channels(efx);
@@ -1593,8 +1619,9 @@ static int efx_set_mac_address(struct net_device *net_dev, void *data)
EFX_ASSERT_RESET_SERIALISED(efx);
if (!is_valid_ether_addr(new_addr)) {
- EFX_ERR(efx, "invalid ethernet MAC address requested: %pM\n",
- new_addr);
+ netif_err(efx, drv, efx->net_dev,
+ "invalid ethernet MAC address requested: %pM\n",
+ new_addr);
return -EINVAL;
}
@@ -1645,7 +1672,7 @@ static void efx_set_multicast_list(struct net_device *net_dev)
static const struct net_device_ops efx_netdev_ops = {
.ndo_open = efx_net_open,
.ndo_stop = efx_net_stop,
- .ndo_get_stats = efx_net_stats,
+ .ndo_get_stats64 = efx_net_stats,
.ndo_tx_timeout = efx_watchdog,
.ndo_start_xmit = efx_hard_start_xmit,
.ndo_validate_addr = eth_validate_addr,
@@ -1697,7 +1724,6 @@ static int efx_register_netdev(struct efx_nic *efx)
net_dev->watchdog_timeo = 5 * HZ;
net_dev->irq = efx->pci_dev->irq;
net_dev->netdev_ops = &efx_netdev_ops;
- SET_NETDEV_DEV(net_dev, &efx->pci_dev->dev);
SET_ETHTOOL_OPS(net_dev, &efx_ethtool_ops);
/* Clear MAC statistics */
@@ -1722,7 +1748,8 @@ static int efx_register_netdev(struct efx_nic *efx)
rc = device_create_file(&efx->pci_dev->dev, &dev_attr_phy_type);
if (rc) {
- EFX_ERR(efx, "failed to init net dev attributes\n");
+ netif_err(efx, drv, efx->net_dev,
+ "failed to init net dev attributes\n");
goto fail_registered;
}
@@ -1730,7 +1757,7 @@ static int efx_register_netdev(struct efx_nic *efx)
fail_locked:
rtnl_unlock();
- EFX_ERR(efx, "could not register net dev\n");
+ netif_err(efx, drv, efx->net_dev, "could not register net dev\n");
return rc;
fail_registered:
@@ -1795,7 +1822,7 @@ int efx_reset_up(struct efx_nic *efx, enum reset_type method, bool ok)
rc = efx->type->init(efx);
if (rc) {
- EFX_ERR(efx, "failed to initialise NIC\n");
+ netif_err(efx, drv, efx->net_dev, "failed to initialise NIC\n");
goto fail;
}
@@ -1807,7 +1834,8 @@ int efx_reset_up(struct efx_nic *efx, enum reset_type method, bool ok)
if (rc)
goto fail;
if (efx->phy_op->reconfigure(efx))
- EFX_ERR(efx, "could not restore PHY settings\n");
+ netif_err(efx, drv, efx->net_dev,
+ "could not restore PHY settings\n");
}
efx->mac_op->reconfigure(efx);
@@ -1840,13 +1868,14 @@ int efx_reset(struct efx_nic *efx, enum reset_type method)
int rc, rc2;
bool disabled;
- EFX_INFO(efx, "resetting (%s)\n", RESET_TYPE(method));
+ netif_info(efx, drv, efx->net_dev, "resetting (%s)\n",
+ RESET_TYPE(method));
efx_reset_down(efx, method);
rc = efx->type->reset(efx, method);
if (rc) {
- EFX_ERR(efx, "failed to reset hardware\n");
+ netif_err(efx, drv, efx->net_dev, "failed to reset hardware\n");
goto out;
}
@@ -1871,10 +1900,10 @@ out:
if (disabled) {
dev_close(efx->net_dev);
- EFX_ERR(efx, "has been disabled\n");
+ netif_err(efx, drv, efx->net_dev, "has been disabled\n");
efx->state = STATE_DISABLED;
} else {
- EFX_LOG(efx, "reset complete\n");
+ netif_dbg(efx, drv, efx->net_dev, "reset complete\n");
}
return rc;
}
@@ -1886,10 +1915,14 @@ static void efx_reset_work(struct work_struct *data)
{
struct efx_nic *efx = container_of(data, struct efx_nic, reset_work);
+ if (efx->reset_pending == RESET_TYPE_NONE)
+ return;
+
/* If we're not RUNNING then don't reset. Leave the reset_pending
* flag set so that efx_pci_probe_main will be retried */
if (efx->state != STATE_RUNNING) {
- EFX_INFO(efx, "scheduled reset quenched. NIC not RUNNING\n");
+ netif_info(efx, drv, efx->net_dev,
+ "scheduled reset quenched. NIC not RUNNING\n");
return;
}
@@ -1903,7 +1936,8 @@ void efx_schedule_reset(struct efx_nic *efx, enum reset_type type)
enum reset_type method;
if (efx->reset_pending != RESET_TYPE_NONE) {
- EFX_INFO(efx, "quenching already scheduled reset\n");
+ netif_info(efx, drv, efx->net_dev,
+ "quenching already scheduled reset\n");
return;
}
@@ -1927,10 +1961,12 @@ void efx_schedule_reset(struct efx_nic *efx, enum reset_type type)
}
if (method != type)
- EFX_LOG(efx, "scheduling %s reset for %s\n",
- RESET_TYPE(method), RESET_TYPE(type));
+ netif_dbg(efx, drv, efx->net_dev,
+ "scheduling %s reset for %s\n",
+ RESET_TYPE(method), RESET_TYPE(type));
else
- EFX_LOG(efx, "scheduling %s reset\n", RESET_TYPE(method));
+ netif_dbg(efx, drv, efx->net_dev, "scheduling %s reset\n",
+ RESET_TYPE(method));
efx->reset_pending = method;
@@ -2017,6 +2053,7 @@ static int efx_init_struct(struct efx_nic *efx, struct efx_nic_type *type,
INIT_WORK(&efx->reset_work, efx_reset_work);
INIT_DELAYED_WORK(&efx->monitor_work, efx_monitor);
efx->pci_dev = pci_dev;
+ efx->msg_enable = debug;
efx->state = STATE_INIT;
efx->reset_pending = RESET_TYPE_NONE;
strlcpy(efx->name, pci_name(pci_dev), sizeof(efx->name));
@@ -2052,8 +2089,8 @@ static int efx_init_struct(struct efx_nic *efx, struct efx_nic_type *type,
rx_queue->queue = i;
rx_queue->channel = &efx->channel[0]; /* for safety */
rx_queue->buffer = NULL;
- spin_lock_init(&rx_queue->add_lock);
- INIT_DELAYED_WORK(&rx_queue->work, efx_rx_work);
+ setup_timer(&rx_queue->slow_fill, efx_rx_slow_fill,
+ (unsigned long)rx_queue);
}
efx->type = type;
@@ -2136,7 +2173,7 @@ static void efx_pci_remove(struct pci_dev *pci_dev)
efx_pci_remove_main(efx);
efx_fini_io(efx);
- EFX_LOG(efx, "shutdown successful\n");
+ netif_dbg(efx, drv, efx->net_dev, "shutdown successful\n");
pci_set_drvdata(pci_dev, NULL);
efx_fini_struct(efx);
@@ -2161,13 +2198,15 @@ static int efx_pci_probe_main(struct efx_nic *efx)
rc = efx->type->init(efx);
if (rc) {
- EFX_ERR(efx, "failed to initialise NIC\n");
+ netif_err(efx, probe, efx->net_dev,
+ "failed to initialise NIC\n");
goto fail3;
}
rc = efx_init_port(efx);
if (rc) {
- EFX_ERR(efx, "failed to initialise port\n");
+ netif_err(efx, probe, efx->net_dev,
+ "failed to initialise port\n");
goto fail4;
}
@@ -2223,11 +2262,13 @@ static int __devinit efx_pci_probe(struct pci_dev *pci_dev,
NETIF_F_HIGHDMA | NETIF_F_TSO);
efx = netdev_priv(net_dev);
pci_set_drvdata(pci_dev, efx);
+ SET_NETDEV_DEV(net_dev, &pci_dev->dev);
rc = efx_init_struct(efx, type, pci_dev, net_dev);
if (rc)
goto fail1;
- EFX_INFO(efx, "Solarflare Communications NIC detected\n");
+ netif_info(efx, probe, efx->net_dev,
+ "Solarflare Communications NIC detected\n");
/* Set up basic I/O (BAR mappings etc) */
rc = efx_init_io(efx);
@@ -2265,7 +2306,7 @@ static int __devinit efx_pci_probe(struct pci_dev *pci_dev,
}
if (rc) {
- EFX_ERR(efx, "Could not reset NIC\n");
+ netif_err(efx, probe, efx->net_dev, "Could not reset NIC\n");
goto fail4;
}
@@ -2277,7 +2318,7 @@ static int __devinit efx_pci_probe(struct pci_dev *pci_dev,
if (rc)
goto fail5;
- EFX_LOG(efx, "initialisation successful\n");
+ netif_dbg(efx, probe, efx->net_dev, "initialisation successful\n");
rtnl_lock();
efx_mtd_probe(efx); /* allowed to fail */
@@ -2293,7 +2334,7 @@ static int __devinit efx_pci_probe(struct pci_dev *pci_dev,
efx_fini_struct(efx);
fail1:
WARN_ON(rc > 0);
- EFX_LOG(efx, "initialisation failed. rc=%d\n", rc);
+ netif_dbg(efx, drv, efx->net_dev, "initialisation failed. rc=%d\n", rc);
free_netdev(net_dev);
return rc;
}
@@ -2332,6 +2373,9 @@ static int efx_pm_thaw(struct device *dev)
efx->type->resume_wol(efx);
+ /* Reschedule any quenched resets scheduled during efx_pm_freeze() */
+ queue_work(reset_workqueue, &efx->reset_work);
+
return 0;
}
@@ -2394,7 +2438,7 @@ static struct dev_pm_ops efx_pm_ops = {
};
static struct pci_driver efx_pci_driver = {
- .name = EFX_DRIVER_NAME,
+ .name = KBUILD_MODNAME,
.id_table = efx_pci_table,
.probe = efx_pci_probe,
.remove = efx_pci_remove,
@@ -2421,11 +2465,6 @@ static int __init efx_init_module(void)
if (rc)
goto err_notifier;
- refill_workqueue = create_workqueue("sfc_refill");
- if (!refill_workqueue) {
- rc = -ENOMEM;
- goto err_refill;
- }
reset_workqueue = create_singlethread_workqueue("sfc_reset");
if (!reset_workqueue) {
rc = -ENOMEM;
@@ -2441,8 +2480,6 @@ static int __init efx_init_module(void)
err_pci:
destroy_workqueue(reset_workqueue);
err_reset:
- destroy_workqueue(refill_workqueue);
- err_refill:
unregister_netdevice_notifier(&efx_netdev_notifier);
err_notifier:
return rc;
@@ -2454,7 +2491,6 @@ static void __exit efx_exit_module(void)
pci_unregister_driver(&efx_pci_driver);
destroy_workqueue(reset_workqueue);
- destroy_workqueue(refill_workqueue);
unregister_netdevice_notifier(&efx_netdev_notifier);
}
diff --git a/drivers/net/sfc/efx.h b/drivers/net/sfc/efx.h
index ffd708c5304..060dc952a0f 100644
--- a/drivers/net/sfc/efx.h
+++ b/drivers/net/sfc/efx.h
@@ -47,12 +47,12 @@ extern void efx_init_rx_queue(struct efx_rx_queue *rx_queue);
extern void efx_fini_rx_queue(struct efx_rx_queue *rx_queue);
extern void efx_rx_strategy(struct efx_channel *channel);
extern void efx_fast_push_rx_descriptors(struct efx_rx_queue *rx_queue);
-extern void efx_rx_work(struct work_struct *data);
+extern void efx_rx_slow_fill(unsigned long context);
extern void __efx_rx_packet(struct efx_channel *channel,
struct efx_rx_buffer *rx_buf, bool checksummed);
extern void efx_rx_packet(struct efx_rx_queue *rx_queue, unsigned int index,
unsigned int len, bool checksummed, bool discard);
-extern void efx_schedule_slow_fill(struct efx_rx_queue *rx_queue, int delay);
+extern void efx_schedule_slow_fill(struct efx_rx_queue *rx_queue);
#define EFX_RXQ_SIZE 1024
#define EFX_RXQ_MASK (EFX_RXQ_SIZE - 1)
@@ -106,8 +106,9 @@ extern unsigned int efx_monitor_interval;
static inline void efx_schedule_channel(struct efx_channel *channel)
{
- EFX_TRACE(channel->efx, "channel %d scheduling NAPI poll on CPU%d\n",
- channel->channel, raw_smp_processor_id());
+ netif_vdbg(channel->efx, intr, channel->efx->net_dev,
+ "channel %d scheduling NAPI poll on CPU%d\n",
+ channel->channel, raw_smp_processor_id());
channel->work_pending = true;
napi_schedule(&channel->napi_str);
diff --git a/drivers/net/sfc/ethtool.c b/drivers/net/sfc/ethtool.c
index 22026bfbc4c..fd19d6ab97a 100644
--- a/drivers/net/sfc/ethtool.c
+++ b/drivers/net/sfc/ethtool.c
@@ -218,8 +218,8 @@ int efx_ethtool_set_settings(struct net_device *net_dev,
/* GMAC does not support 1000Mbps HD */
if (ecmd->speed == SPEED_1000 && ecmd->duplex != DUPLEX_FULL) {
- EFX_LOG(efx, "rejecting unsupported 1000Mbps HD"
- " setting\n");
+ netif_dbg(efx, drv, efx->net_dev,
+ "rejecting unsupported 1000Mbps HD setting\n");
return -EINVAL;
}
@@ -234,7 +234,7 @@ static void efx_ethtool_get_drvinfo(struct net_device *net_dev,
{
struct efx_nic *efx = netdev_priv(net_dev);
- strlcpy(info->driver, EFX_DRIVER_NAME, sizeof(info->driver));
+ strlcpy(info->driver, KBUILD_MODNAME, sizeof(info->driver));
strlcpy(info->version, EFX_DRIVER_VERSION, sizeof(info->version));
if (efx_nic_rev(efx) >= EFX_REV_SIENA_A0)
siena_print_fwver(efx, info->fw_version,
@@ -242,6 +242,32 @@ static void efx_ethtool_get_drvinfo(struct net_device *net_dev,
strlcpy(info->bus_info, pci_name(efx->pci_dev), sizeof(info->bus_info));
}
+static int efx_ethtool_get_regs_len(struct net_device *net_dev)
+{
+ return efx_nic_get_regs_len(netdev_priv(net_dev));
+}
+
+static void efx_ethtool_get_regs(struct net_device *net_dev,
+ struct ethtool_regs *regs, void *buf)
+{
+ struct efx_nic *efx = netdev_priv(net_dev);
+
+ regs->version = efx->type->revision;
+ efx_nic_get_regs(efx, buf);
+}
+
+static u32 efx_ethtool_get_msglevel(struct net_device *net_dev)
+{
+ struct efx_nic *efx = netdev_priv(net_dev);
+ return efx->msg_enable;
+}
+
+static void efx_ethtool_set_msglevel(struct net_device *net_dev, u32 msg_enable)
+{
+ struct efx_nic *efx = netdev_priv(net_dev);
+ efx->msg_enable = msg_enable;
+}
+
/**
* efx_fill_test - fill in an individual self-test entry
* @test_index: Index of the test
@@ -443,12 +469,13 @@ static void efx_ethtool_get_stats(struct net_device *net_dev,
struct efx_mac_stats *mac_stats = &efx->mac_stats;
struct efx_ethtool_stat *stat;
struct efx_channel *channel;
+ struct rtnl_link_stats64 temp;
int i;
EFX_BUG_ON_PARANOID(stats->n_stats != EFX_ETHTOOL_NUM_STATS);
/* Update MAC and NIC statistics */
- dev_get_stats(net_dev);
+ dev_get_stats(net_dev, &temp);
/* Fill detailed statistics buffer */
for (i = 0; i < EFX_ETHTOOL_NUM_STATS; i++) {
@@ -520,6 +547,14 @@ static u32 efx_ethtool_get_rx_csum(struct net_device *net_dev)
return efx->rx_checksum_enabled;
}
+static int efx_ethtool_set_flags(struct net_device *net_dev, u32 data)
+{
+ struct efx_nic *efx = netdev_priv(net_dev);
+ u32 supported = efx->type->offload_features & ETH_FLAG_RXHASH;
+
+ return ethtool_op_set_flags(net_dev, data, supported);
+}
+
static void efx_ethtool_self_test(struct net_device *net_dev,
struct ethtool_test *test, u64 *data)
{
@@ -539,7 +574,8 @@ static void efx_ethtool_self_test(struct net_device *net_dev,
if (!already_up) {
rc = dev_open(efx->net_dev);
if (rc) {
- EFX_ERR(efx, "failed opening device.\n");
+ netif_err(efx, drv, efx->net_dev,
+ "failed opening device.\n");
goto fail2;
}
}
@@ -551,9 +587,9 @@ static void efx_ethtool_self_test(struct net_device *net_dev,
if (!already_up)
dev_close(efx->net_dev);
- EFX_LOG(efx, "%s %sline self-tests\n",
- rc == 0 ? "passed" : "failed",
- (test->flags & ETH_TEST_FL_OFFLINE) ? "off" : "on");
+ netif_dbg(efx, drv, efx->net_dev, "%s %sline self-tests\n",
+ rc == 0 ? "passed" : "failed",
+ (test->flags & ETH_TEST_FL_OFFLINE) ? "off" : "on");
fail2:
fail1:
@@ -679,8 +715,8 @@ static int efx_ethtool_set_coalesce(struct net_device *net_dev,
return -EOPNOTSUPP;
if (coalesce->rx_coalesce_usecs || coalesce->tx_coalesce_usecs) {
- EFX_ERR(efx, "invalid coalescing setting. "
- "Only rx/tx_coalesce_usecs_irq are supported\n");
+ netif_err(efx, drv, efx->net_dev, "invalid coalescing setting. "
+ "Only rx/tx_coalesce_usecs_irq are supported\n");
return -EOPNOTSUPP;
}
@@ -692,8 +728,8 @@ static int efx_ethtool_set_coalesce(struct net_device *net_dev,
efx_for_each_tx_queue(tx_queue, efx) {
if ((tx_queue->channel->channel < efx->n_rx_channels) &&
tx_usecs) {
- EFX_ERR(efx, "Channel is shared. "
- "Only RX coalescing may be set\n");
+ netif_err(efx, drv, efx->net_dev, "Channel is shared. "
+ "Only RX coalescing may be set\n");
return -EOPNOTSUPP;
}
}
@@ -721,13 +757,15 @@ static int efx_ethtool_set_pauseparam(struct net_device *net_dev,
(pause->autoneg ? EFX_FC_AUTO : 0));
if ((wanted_fc & EFX_FC_TX) && !(wanted_fc & EFX_FC_RX)) {
- EFX_LOG(efx, "Flow control unsupported: tx ON rx OFF\n");
+ netif_dbg(efx, drv, efx->net_dev,
+ "Flow control unsupported: tx ON rx OFF\n");
rc = -EINVAL;
goto out;
}
if ((wanted_fc & EFX_FC_AUTO) && !efx->link_advertising) {
- EFX_LOG(efx, "Autonegotiation is disabled\n");
+ netif_dbg(efx, drv, efx->net_dev,
+ "Autonegotiation is disabled\n");
rc = -EINVAL;
goto out;
}
@@ -758,8 +796,9 @@ static int efx_ethtool_set_pauseparam(struct net_device *net_dev,
(efx->wanted_fc ^ old_fc) & EFX_FC_AUTO) {
rc = efx->phy_op->reconfigure(efx);
if (rc) {
- EFX_ERR(efx, "Unable to advertise requested flow "
- "control setting\n");
+ netif_err(efx, drv, efx->net_dev,
+ "Unable to advertise requested flow "
+ "control setting\n");
goto out;
}
}
@@ -830,10 +869,101 @@ extern int efx_ethtool_reset(struct net_device *net_dev, u32 *flags)
return efx_reset(efx, method);
}
+static int
+efx_ethtool_get_rxnfc(struct net_device *net_dev,
+ struct ethtool_rxnfc *info, void *rules __always_unused)
+{
+ struct efx_nic *efx = netdev_priv(net_dev);
+
+ switch (info->cmd) {
+ case ETHTOOL_GRXRINGS:
+ info->data = efx->n_rx_channels;
+ return 0;
+
+ case ETHTOOL_GRXFH: {
+ unsigned min_revision = 0;
+
+ info->data = 0;
+ switch (info->flow_type) {
+ case TCP_V4_FLOW:
+ info->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
+ /* fall through */
+ case UDP_V4_FLOW:
+ case SCTP_V4_FLOW:
+ case AH_ESP_V4_FLOW:
+ case IPV4_FLOW:
+ info->data |= RXH_IP_SRC | RXH_IP_DST;
+ min_revision = EFX_REV_FALCON_B0;
+ break;
+ case TCP_V6_FLOW:
+ info->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
+ /* fall through */
+ case UDP_V6_FLOW:
+ case SCTP_V6_FLOW:
+ case AH_ESP_V6_FLOW:
+ case IPV6_FLOW:
+ info->data |= RXH_IP_SRC | RXH_IP_DST;
+ min_revision = EFX_REV_SIENA_A0;
+ break;
+ default:
+ break;
+ }
+ if (efx_nic_rev(efx) < min_revision)
+ info->data = 0;
+ return 0;
+ }
+
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
+static int efx_ethtool_get_rxfh_indir(struct net_device *net_dev,
+ struct ethtool_rxfh_indir *indir)
+{
+ struct efx_nic *efx = netdev_priv(net_dev);
+ size_t copy_size =
+ min_t(size_t, indir->size, ARRAY_SIZE(efx->rx_indir_table));
+
+ if (efx_nic_rev(efx) < EFX_REV_FALCON_B0)
+ return -EOPNOTSUPP;
+
+ indir->size = ARRAY_SIZE(efx->rx_indir_table);
+ memcpy(indir->ring_index, efx->rx_indir_table,
+ copy_size * sizeof(indir->ring_index[0]));
+ return 0;
+}
+
+static int efx_ethtool_set_rxfh_indir(struct net_device *net_dev,
+ const struct ethtool_rxfh_indir *indir)
+{
+ struct efx_nic *efx = netdev_priv(net_dev);
+ size_t i;
+
+ if (efx_nic_rev(efx) < EFX_REV_FALCON_B0)
+ return -EOPNOTSUPP;
+
+ /* Validate size and indices */
+ if (indir->size != ARRAY_SIZE(efx->rx_indir_table))
+ return -EINVAL;
+ for (i = 0; i < ARRAY_SIZE(efx->rx_indir_table); i++)
+ if (indir->ring_index[i] >= efx->n_rx_channels)
+ return -EINVAL;
+
+ memcpy(efx->rx_indir_table, indir->ring_index,
+ sizeof(efx->rx_indir_table));
+ efx_nic_push_rx_indir_table(efx);
+ return 0;
+}
+
const struct ethtool_ops efx_ethtool_ops = {
.get_settings = efx_ethtool_get_settings,
.set_settings = efx_ethtool_set_settings,
.get_drvinfo = efx_ethtool_get_drvinfo,
+ .get_regs_len = efx_ethtool_get_regs_len,
+ .get_regs = efx_ethtool_get_regs,
+ .get_msglevel = efx_ethtool_get_msglevel,
+ .set_msglevel = efx_ethtool_set_msglevel,
.nway_reset = efx_ethtool_nway_reset,
.get_link = efx_ethtool_get_link,
.get_eeprom_len = efx_ethtool_get_eeprom_len,
@@ -854,7 +984,7 @@ const struct ethtool_ops efx_ethtool_ops = {
/* Need to enable/disable TSO-IPv6 too */
.set_tso = efx_ethtool_set_tso,
.get_flags = ethtool_op_get_flags,
- .set_flags = ethtool_op_set_flags,
+ .set_flags = efx_ethtool_set_flags,
.get_sset_count = efx_ethtool_get_sset_count,
.self_test = efx_ethtool_self_test,
.get_strings = efx_ethtool_get_strings,
@@ -863,4 +993,7 @@ const struct ethtool_ops efx_ethtool_ops = {
.get_wol = efx_ethtool_get_wol,
.set_wol = efx_ethtool_set_wol,
.reset = efx_ethtool_reset,
+ .get_rxnfc = efx_ethtool_get_rxnfc,
+ .get_rxfh_indir = efx_ethtool_get_rxfh_indir,
+ .set_rxfh_indir = efx_ethtool_set_rxfh_indir,
};
diff --git a/drivers/net/sfc/falcon.c b/drivers/net/sfc/falcon.c
index 655b697b45b..4f9d33f3cca 100644
--- a/drivers/net/sfc/falcon.c
+++ b/drivers/net/sfc/falcon.c
@@ -167,13 +167,15 @@ irqreturn_t falcon_legacy_interrupt_a1(int irq, void *dev_id)
* exit without having touched the hardware.
*/
if (unlikely(EFX_OWORD_IS_ZERO(*int_ker))) {
- EFX_TRACE(efx, "IRQ %d on CPU %d not for me\n", irq,
- raw_smp_processor_id());
+ netif_vdbg(efx, intr, efx->net_dev,
+ "IRQ %d on CPU %d not for me\n", irq,
+ raw_smp_processor_id());
return IRQ_NONE;
}
efx->last_irq_cpu = raw_smp_processor_id();
- EFX_TRACE(efx, "IRQ %d on CPU %d status " EFX_OWORD_FMT "\n",
- irq, raw_smp_processor_id(), EFX_OWORD_VAL(*int_ker));
+ netif_vdbg(efx, intr, efx->net_dev,
+ "IRQ %d on CPU %d status " EFX_OWORD_FMT "\n",
+ irq, raw_smp_processor_id(), EFX_OWORD_VAL(*int_ker));
/* Determine interrupting queues, clear interrupt status
* register and acknowledge the device interrupt.
@@ -239,7 +241,8 @@ static int falcon_spi_wait(struct efx_nic *efx)
if (!falcon_spi_poll(efx))
return 0;
if (time_after_eq(jiffies, timeout)) {
- EFX_ERR(efx, "timed out waiting for SPI\n");
+ netif_err(efx, hw, efx->net_dev,
+ "timed out waiting for SPI\n");
return -ETIMEDOUT;
}
schedule_timeout_uninterruptible(1);
@@ -333,9 +336,10 @@ falcon_spi_wait_write(struct efx_nic *efx, const struct efx_spi_device *spi)
if (!(status & SPI_STATUS_NRDY))
return 0;
if (time_after_eq(jiffies, timeout)) {
- EFX_ERR(efx, "SPI write timeout on device %d"
- " last status=0x%02x\n",
- spi->device_id, status);
+ netif_err(efx, hw, efx->net_dev,
+ "SPI write timeout on device %d"
+ " last status=0x%02x\n",
+ spi->device_id, status);
return -ETIMEDOUT;
}
schedule_timeout_uninterruptible(1);
@@ -469,7 +473,8 @@ static void falcon_reset_macs(struct efx_nic *efx)
udelay(10);
}
- EFX_ERR(efx, "timed out waiting for XMAC core reset\n");
+ netif_err(efx, hw, efx->net_dev,
+ "timed out waiting for XMAC core reset\n");
}
}
@@ -492,12 +497,13 @@ static void falcon_reset_macs(struct efx_nic *efx)
if (!EFX_OWORD_FIELD(reg, FRF_AB_RST_XGTX) &&
!EFX_OWORD_FIELD(reg, FRF_AB_RST_XGRX) &&
!EFX_OWORD_FIELD(reg, FRF_AB_RST_EM)) {
- EFX_LOG(efx, "Completed MAC reset after %d loops\n",
- count);
+ netif_dbg(efx, hw, efx->net_dev,
+ "Completed MAC reset after %d loops\n",
+ count);
break;
}
if (count > 20) {
- EFX_ERR(efx, "MAC reset failed\n");
+ netif_err(efx, hw, efx->net_dev, "MAC reset failed\n");
break;
}
count++;
@@ -548,7 +554,9 @@ void falcon_reconfigure_mac_wrapper(struct efx_nic *efx)
{
struct efx_link_state *link_state = &efx->link_state;
efx_oword_t reg;
- int link_speed;
+ int link_speed, isolate;
+
+ isolate = (efx->reset_pending != RESET_TYPE_NONE);
switch (link_state->speed) {
case 10000: link_speed = 3; break;
@@ -570,7 +578,7 @@ void falcon_reconfigure_mac_wrapper(struct efx_nic *efx)
* discarded. */
if (efx_nic_rev(efx) >= EFX_REV_FALCON_B0) {
EFX_SET_OWORD_FIELD(reg, FRF_BB_TXFIFO_DRAIN_EN,
- !link_state->up);
+ !link_state->up || isolate);
}
efx_writeo(efx, &reg, FR_AB_MAC_CTRL);
@@ -584,7 +592,7 @@ void falcon_reconfigure_mac_wrapper(struct efx_nic *efx)
EFX_SET_OWORD_FIELD(reg, FRF_AZ_RX_XOFF_MAC_EN, 1);
/* Unisolate the MAC -> RX */
if (efx_nic_rev(efx) >= EFX_REV_FALCON_B0)
- EFX_SET_OWORD_FIELD(reg, FRF_BZ_RX_INGR_EN, 1);
+ EFX_SET_OWORD_FIELD(reg, FRF_BZ_RX_INGR_EN, !isolate);
efx_writeo(efx, &reg, FR_AZ_RX_CFG);
}
@@ -625,7 +633,8 @@ static void falcon_stats_complete(struct efx_nic *efx)
rmb(); /* read the done flag before the stats */
efx->mac_op->update_stats(efx);
} else {
- EFX_ERR(efx, "timed out waiting for statistics\n");
+ netif_err(efx, hw, efx->net_dev,
+ "timed out waiting for statistics\n");
}
}
@@ -715,16 +724,17 @@ static int falcon_gmii_wait(struct efx_nic *efx)
if (EFX_OWORD_FIELD(md_stat, FRF_AB_MD_BSY) == 0) {
if (EFX_OWORD_FIELD(md_stat, FRF_AB_MD_LNFL) != 0 ||
EFX_OWORD_FIELD(md_stat, FRF_AB_MD_BSERR) != 0) {
- EFX_ERR(efx, "error from GMII access "
- EFX_OWORD_FMT"\n",
- EFX_OWORD_VAL(md_stat));
+ netif_err(efx, hw, efx->net_dev,
+ "error from GMII access "
+ EFX_OWORD_FMT"\n",
+ EFX_OWORD_VAL(md_stat));
return -EIO;
}
return 0;
}
udelay(10);
}
- EFX_ERR(efx, "timed out waiting for GMII\n");
+ netif_err(efx, hw, efx->net_dev, "timed out waiting for GMII\n");
return -ETIMEDOUT;
}
@@ -736,7 +746,8 @@ static int falcon_mdio_write(struct net_device *net_dev,
efx_oword_t reg;
int rc;
- EFX_REGDUMP(efx, "writing MDIO %d register %d.%d with 0x%04x\n",
+ netif_vdbg(efx, hw, efx->net_dev,
+ "writing MDIO %d register %d.%d with 0x%04x\n",
prtad, devad, addr, value);
mutex_lock(&efx->mdio_lock);
@@ -810,8 +821,9 @@ static int falcon_mdio_read(struct net_device *net_dev,
if (rc == 0) {
efx_reado(efx, &reg, FR_AB_MD_RXD);
rc = EFX_OWORD_FIELD(reg, FRF_AB_MD_RXD);
- EFX_REGDUMP(efx, "read from MDIO %d register %d.%d, got %04x\n",
- prtad, devad, addr, rc);
+ netif_vdbg(efx, hw, efx->net_dev,
+ "read from MDIO %d register %d.%d, got %04x\n",
+ prtad, devad, addr, rc);
} else {
/* Abort the read operation */
EFX_POPULATE_OWORD_2(reg,
@@ -819,8 +831,9 @@ static int falcon_mdio_read(struct net_device *net_dev,
FRF_AB_MD_GC, 1);
efx_writeo(efx, &reg, FR_AB_MD_CS);
- EFX_LOG(efx, "read from MDIO %d register %d.%d, got error %d\n",
- prtad, devad, addr, rc);
+ netif_dbg(efx, hw, efx->net_dev,
+ "read from MDIO %d register %d.%d, got error %d\n",
+ prtad, devad, addr, rc);
}
out:
@@ -871,7 +884,8 @@ static void falcon_switch_mac(struct efx_nic *efx)
falcon_clock_mac(efx);
- EFX_LOG(efx, "selected %cMAC\n", EFX_IS10G(efx) ? 'X' : 'G');
+ netif_dbg(efx, hw, efx->net_dev, "selected %cMAC\n",
+ EFX_IS10G(efx) ? 'X' : 'G');
/* Not all macs support a mac-level link state */
efx->xmac_poll_required = false;
falcon_reset_macs(efx);
@@ -895,8 +909,8 @@ static int falcon_probe_port(struct efx_nic *efx)
efx->phy_op = &falcon_qt202x_phy_ops;
break;
default:
- EFX_ERR(efx, "Unknown PHY type %d\n",
- efx->phy_type);
+ netif_err(efx, probe, efx->net_dev, "Unknown PHY type %d\n",
+ efx->phy_type);
return -ENODEV;
}
@@ -924,10 +938,11 @@ static int falcon_probe_port(struct efx_nic *efx)
FALCON_MAC_STATS_SIZE);
if (rc)
return rc;
- EFX_LOG(efx, "stats buffer at %llx (virt %p phys %llx)\n",
- (u64)efx->stats_buffer.dma_addr,
- efx->stats_buffer.addr,
- (u64)virt_to_phys(efx->stats_buffer.addr));
+ netif_dbg(efx, probe, efx->net_dev,
+ "stats buffer at %llx (virt %p phys %llx)\n",
+ (u64)efx->stats_buffer.dma_addr,
+ efx->stats_buffer.addr,
+ (u64)virt_to_phys(efx->stats_buffer.addr));
return 0;
}
@@ -967,8 +982,8 @@ falcon_read_nvram(struct efx_nic *efx, struct falcon_nvconfig *nvconfig_out)
rc = falcon_spi_read(efx, spi, 0, FALCON_NVCONFIG_END, NULL, region);
mutex_unlock(&efx->spi_lock);
if (rc) {
- EFX_ERR(efx, "Failed to read %s\n",
- efx->spi_flash ? "flash" : "EEPROM");
+ netif_err(efx, hw, efx->net_dev, "Failed to read %s\n",
+ efx->spi_flash ? "flash" : "EEPROM");
rc = -EIO;
goto out;
}
@@ -978,11 +993,13 @@ falcon_read_nvram(struct efx_nic *efx, struct falcon_nvconfig *nvconfig_out)
rc = -EINVAL;
if (magic_num != FALCON_NVCONFIG_BOARD_MAGIC_NUM) {
- EFX_ERR(efx, "NVRAM bad magic 0x%x\n", magic_num);
+ netif_err(efx, hw, efx->net_dev,
+ "NVRAM bad magic 0x%x\n", magic_num);
goto out;
}
if (struct_ver < 2) {
- EFX_ERR(efx, "NVRAM has ancient version 0x%x\n", struct_ver);
+ netif_err(efx, hw, efx->net_dev,
+ "NVRAM has ancient version 0x%x\n", struct_ver);
goto out;
} else if (struct_ver < 4) {
word = &nvconfig->board_magic_num;
@@ -995,7 +1012,8 @@ falcon_read_nvram(struct efx_nic *efx, struct falcon_nvconfig *nvconfig_out)
csum += le16_to_cpu(*word);
if (~csum & 0xffff) {
- EFX_ERR(efx, "NVRAM has incorrect checksum\n");
+ netif_err(efx, hw, efx->net_dev,
+ "NVRAM has incorrect checksum\n");
goto out;
}
@@ -1073,22 +1091,25 @@ static int falcon_reset_hw(struct efx_nic *efx, enum reset_type method)
efx_oword_t glb_ctl_reg_ker;
int rc;
- EFX_LOG(efx, "performing %s hardware reset\n", RESET_TYPE(method));
+ netif_dbg(efx, hw, efx->net_dev, "performing %s hardware reset\n",
+ RESET_TYPE(method));
/* Initiate device reset */
if (method == RESET_TYPE_WORLD) {
rc = pci_save_state(efx->pci_dev);
if (rc) {
- EFX_ERR(efx, "failed to backup PCI state of primary "
- "function prior to hardware reset\n");
+ netif_err(efx, drv, efx->net_dev,
+ "failed to backup PCI state of primary "
+ "function prior to hardware reset\n");
goto fail1;
}
if (efx_nic_is_dual_func(efx)) {
rc = pci_save_state(nic_data->pci_dev2);
if (rc) {
- EFX_ERR(efx, "failed to backup PCI state of "
- "secondary function prior to "
- "hardware reset\n");
+ netif_err(efx, drv, efx->net_dev,
+ "failed to backup PCI state of "
+ "secondary function prior to "
+ "hardware reset\n");
goto fail2;
}
}
@@ -1113,7 +1134,7 @@ static int falcon_reset_hw(struct efx_nic *efx, enum reset_type method)
}
efx_writeo(efx, &glb_ctl_reg_ker, FR_AB_GLB_CTL);
- EFX_LOG(efx, "waiting for hardware reset\n");
+ netif_dbg(efx, hw, efx->net_dev, "waiting for hardware reset\n");
schedule_timeout_uninterruptible(HZ / 20);
/* Restore PCI configuration if needed */
@@ -1121,28 +1142,32 @@ static int falcon_reset_hw(struct efx_nic *efx, enum reset_type method)
if (efx_nic_is_dual_func(efx)) {
rc = pci_restore_state(nic_data->pci_dev2);
if (rc) {
- EFX_ERR(efx, "failed to restore PCI config for "
- "the secondary function\n");
+ netif_err(efx, drv, efx->net_dev,
+ "failed to restore PCI config for "
+ "the secondary function\n");
goto fail3;
}
}
rc = pci_restore_state(efx->pci_dev);
if (rc) {
- EFX_ERR(efx, "failed to restore PCI config for the "
- "primary function\n");
+ netif_err(efx, drv, efx->net_dev,
+ "failed to restore PCI config for the "
+ "primary function\n");
goto fail4;
}
- EFX_LOG(efx, "successfully restored PCI config\n");
+ netif_dbg(efx, drv, efx->net_dev,
+ "successfully restored PCI config\n");
}
/* Assert that reset complete */
efx_reado(efx, &glb_ctl_reg_ker, FR_AB_GLB_CTL);
if (EFX_OWORD_FIELD(glb_ctl_reg_ker, FRF_AB_SWRST) != 0) {
rc = -ETIMEDOUT;
- EFX_ERR(efx, "timed out waiting for hardware reset\n");
+ netif_err(efx, hw, efx->net_dev,
+ "timed out waiting for hardware reset\n");
goto fail5;
}
- EFX_LOG(efx, "hardware reset complete\n");
+ netif_dbg(efx, hw, efx->net_dev, "hardware reset complete\n");
return 0;
@@ -1165,8 +1190,9 @@ static void falcon_monitor(struct efx_nic *efx)
rc = falcon_board(efx)->type->monitor(efx);
if (rc) {
- EFX_ERR(efx, "Board sensor %s; shutting down PHY\n",
- (rc == -ERANGE) ? "reported fault" : "failed");
+ netif_err(efx, hw, efx->net_dev,
+ "Board sensor %s; shutting down PHY\n",
+ (rc == -ERANGE) ? "reported fault" : "failed");
efx->phy_mode |= PHY_MODE_LOW_POWER;
rc = __efx_reconfigure_port(efx);
WARN_ON(rc);
@@ -1217,7 +1243,8 @@ static int falcon_reset_sram(struct efx_nic *efx)
/* Wait for SRAM reset to complete */
count = 0;
do {
- EFX_LOG(efx, "waiting for SRAM reset (attempt %d)...\n", count);
+ netif_dbg(efx, hw, efx->net_dev,
+ "waiting for SRAM reset (attempt %d)...\n", count);
/* SRAM reset is slow; expect around 16ms */
schedule_timeout_uninterruptible(HZ / 50);
@@ -1225,13 +1252,14 @@ static int falcon_reset_sram(struct efx_nic *efx)
/* Check for reset complete */
efx_reado(efx, &srm_cfg_reg_ker, FR_AZ_SRM_CFG);
if (!EFX_OWORD_FIELD(srm_cfg_reg_ker, FRF_AZ_SRM_INIT_EN)) {
- EFX_LOG(efx, "SRAM reset complete\n");
+ netif_dbg(efx, hw, efx->net_dev,
+ "SRAM reset complete\n");
return 0;
}
} while (++count < 20); /* wait upto 0.4 sec */
- EFX_ERR(efx, "timed out waiting for SRAM reset\n");
+ netif_err(efx, hw, efx->net_dev, "timed out waiting for SRAM reset\n");
return -ETIMEDOUT;
}
@@ -1290,7 +1318,8 @@ static int falcon_probe_nvconfig(struct efx_nic *efx)
rc = falcon_read_nvram(efx, nvconfig);
if (rc == -EINVAL) {
- EFX_ERR(efx, "NVRAM is invalid therefore using defaults\n");
+ netif_err(efx, probe, efx->net_dev,
+ "NVRAM is invalid therefore using defaults\n");
efx->phy_type = PHY_TYPE_NONE;
efx->mdio.prtad = MDIO_PRTAD_NONE;
board_rev = 0;
@@ -1324,7 +1353,8 @@ static int falcon_probe_nvconfig(struct efx_nic *efx)
/* Read the MAC addresses */
memcpy(efx->mac_address, nvconfig->mac_address[0], ETH_ALEN);
- EFX_LOG(efx, "PHY is %d phy_id %d\n", efx->phy_type, efx->mdio.prtad);
+ netif_dbg(efx, probe, efx->net_dev, "PHY is %d phy_id %d\n",
+ efx->phy_type, efx->mdio.prtad);
rc = falcon_probe_board(efx, board_rev);
if (rc)
@@ -1353,14 +1383,16 @@ static void falcon_probe_spi_devices(struct efx_nic *efx)
if (EFX_OWORD_FIELD(gpio_ctl, FRF_AB_GPIO3_PWRUP_VALUE)) {
boot_dev = (EFX_OWORD_FIELD(nic_stat, FRF_AB_SF_PRST) ?
FFE_AB_SPI_DEVICE_FLASH : FFE_AB_SPI_DEVICE_EEPROM);
- EFX_LOG(efx, "Booted from %s\n",
- boot_dev == FFE_AB_SPI_DEVICE_FLASH ? "flash" : "EEPROM");
+ netif_dbg(efx, probe, efx->net_dev, "Booted from %s\n",
+ boot_dev == FFE_AB_SPI_DEVICE_FLASH ?
+ "flash" : "EEPROM");
} else {
/* Disable VPD and set clock dividers to safe
* values for initial programming. */
boot_dev = -1;
- EFX_LOG(efx, "Booted from internal ASIC settings;"
- " setting SPI config\n");
+ netif_dbg(efx, probe, efx->net_dev,
+ "Booted from internal ASIC settings;"
+ " setting SPI config\n");
EFX_POPULATE_OWORD_3(ee_vpd_cfg, FRF_AB_EE_VPD_EN, 0,
/* 125 MHz / 7 ~= 20 MHz */
FRF_AB_EE_SF_CLOCK_DIV, 7,
@@ -1394,7 +1426,8 @@ static int falcon_probe_nic(struct efx_nic *efx)
rc = -ENODEV;
if (efx_nic_fpga_ver(efx) != 0) {
- EFX_ERR(efx, "Falcon FPGA not supported\n");
+ netif_err(efx, probe, efx->net_dev,
+ "Falcon FPGA not supported\n");
goto fail1;
}
@@ -1404,16 +1437,19 @@ static int falcon_probe_nic(struct efx_nic *efx)
u8 pci_rev = efx->pci_dev->revision;
if ((pci_rev == 0xff) || (pci_rev == 0)) {
- EFX_ERR(efx, "Falcon rev A0 not supported\n");
+ netif_err(efx, probe, efx->net_dev,
+ "Falcon rev A0 not supported\n");
goto fail1;
}
efx_reado(efx, &nic_stat, FR_AB_NIC_STAT);
if (EFX_OWORD_FIELD(nic_stat, FRF_AB_STRAP_10G) == 0) {
- EFX_ERR(efx, "Falcon rev A1 1G not supported\n");
+ netif_err(efx, probe, efx->net_dev,
+ "Falcon rev A1 1G not supported\n");
goto fail1;
}
if (EFX_OWORD_FIELD(nic_stat, FRF_AA_STRAP_PCIE) == 0) {
- EFX_ERR(efx, "Falcon rev A1 PCI-X not supported\n");
+ netif_err(efx, probe, efx->net_dev,
+ "Falcon rev A1 PCI-X not supported\n");
goto fail1;
}
@@ -1427,7 +1463,8 @@ static int falcon_probe_nic(struct efx_nic *efx)
}
}
if (!nic_data->pci_dev2) {
- EFX_ERR(efx, "failed to find secondary function\n");
+ netif_err(efx, probe, efx->net_dev,
+ "failed to find secondary function\n");
rc = -ENODEV;
goto fail2;
}
@@ -1436,7 +1473,7 @@ static int falcon_probe_nic(struct efx_nic *efx)
/* Now we can reset the NIC */
rc = falcon_reset_hw(efx, RESET_TYPE_ALL);
if (rc) {
- EFX_ERR(efx, "failed to reset NIC\n");
+ netif_err(efx, probe, efx->net_dev, "failed to reset NIC\n");
goto fail3;
}
@@ -1446,9 +1483,11 @@ static int falcon_probe_nic(struct efx_nic *efx)
goto fail4;
BUG_ON(efx->irq_status.dma_addr & 0x0f);
- EFX_LOG(efx, "INT_KER at %llx (virt %p phys %llx)\n",
- (u64)efx->irq_status.dma_addr,
- efx->irq_status.addr, (u64)virt_to_phys(efx->irq_status.addr));
+ netif_dbg(efx, probe, efx->net_dev,
+ "INT_KER at %llx (virt %p phys %llx)\n",
+ (u64)efx->irq_status.dma_addr,
+ efx->irq_status.addr,
+ (u64)virt_to_phys(efx->irq_status.addr));
falcon_probe_spi_devices(efx);
@@ -1472,7 +1511,8 @@ static int falcon_probe_nic(struct efx_nic *efx)
rc = falcon_board(efx)->type->init(efx);
if (rc) {
- EFX_ERR(efx, "failed to initialise board\n");
+ netif_err(efx, probe, efx->net_dev,
+ "failed to initialise board\n");
goto fail6;
}
@@ -1542,6 +1582,13 @@ static void falcon_init_rx_cfg(struct efx_nic *efx)
EFX_SET_OWORD_FIELD(reg, FRF_BZ_RX_XON_TX_TH, ctrl_xon_thr);
EFX_SET_OWORD_FIELD(reg, FRF_BZ_RX_XOFF_TX_TH, ctrl_xoff_thr);
EFX_SET_OWORD_FIELD(reg, FRF_BZ_RX_INGR_EN, 1);
+
+ /* Enable hash insertion. This is broken for the
+ * 'Falcon' hash so also select Toeplitz TCP/IPv4 and
+ * IPv4 hashes. */
+ EFX_SET_OWORD_FIELD(reg, FRF_BZ_RX_HASH_INSRT_HDR, 1);
+ EFX_SET_OWORD_FIELD(reg, FRF_BZ_RX_HASH_ALG, 1);
+ EFX_SET_OWORD_FIELD(reg, FRF_BZ_RX_IP_HASH, 1);
}
/* Always enable XOFF signal from RX FIFO. We enable
* or disable transmission of pause frames at the MAC. */
@@ -1615,8 +1662,12 @@ static int falcon_init_nic(struct efx_nic *efx)
falcon_init_rx_cfg(efx);
- /* Set destination of both TX and RX Flush events */
if (efx_nic_rev(efx) >= EFX_REV_FALCON_B0) {
+ /* Set hash key for IPv4 */
+ memcpy(&temp, efx->rx_hash_key, sizeof(temp));
+ efx_writeo(efx, &temp, FR_BZ_RX_RSS_TKEY);
+
+ /* Set destination of both TX and RX Flush events */
EFX_POPULATE_OWORD_1(temp, FRF_BZ_FLS_EVQ_ID, 0);
efx_writeo(efx, &temp, FR_BZ_DP_CTRL);
}
@@ -1821,6 +1872,7 @@ struct efx_nic_type falcon_b0_nic_type = {
.evq_ptr_tbl_base = FR_BZ_EVQ_PTR_TBL,
.evq_rptr_tbl_base = FR_BZ_EVQ_RPTR,
.max_dma_mask = DMA_BIT_MASK(FSF_AZ_TX_KER_BUF_ADDR_WIDTH),
+ .rx_buffer_hash_size = 0x10,
.rx_buffer_padding = 0,
.max_interrupt_mode = EFX_INT_MODE_MSIX,
.phys_addr_channels = 32, /* Hardware limit is 64, but the legacy
@@ -1828,7 +1880,7 @@ struct efx_nic_type falcon_b0_nic_type = {
* channels */
.tx_dc_base = 0x130000,
.rx_dc_base = 0x100000,
- .offload_features = NETIF_F_IP_CSUM,
+ .offload_features = NETIF_F_IP_CSUM | NETIF_F_RXHASH,
.reset_world_flags = ETH_RESET_IRQ,
};
diff --git a/drivers/net/sfc/falcon_boards.c b/drivers/net/sfc/falcon_boards.c
index c7a933a3292..3d950c2cf20 100644
--- a/drivers/net/sfc/falcon_boards.c
+++ b/drivers/net/sfc/falcon_boards.c
@@ -106,12 +106,17 @@ static int efx_check_lm87(struct efx_nic *efx, unsigned mask)
alarms1 &= mask;
alarms2 &= mask >> 8;
if (alarms1 || alarms2) {
- EFX_ERR(efx,
- "LM87 detected a hardware failure (status %02x:%02x)"
- "%s%s\n",
- alarms1, alarms2,
- (alarms1 & LM87_ALARM_TEMP_INT) ? " INTERNAL" : "",
- (alarms1 & LM87_ALARM_TEMP_EXT1) ? " EXTERNAL" : "");
+ netif_err(efx, hw, efx->net_dev,
+ "LM87 detected a hardware failure (status %02x:%02x)"
+ "%s%s%s\n",
+ alarms1, alarms2,
+ (alarms1 & LM87_ALARM_TEMP_INT) ?
+ "; board is overheating" : "",
+ (alarms1 & LM87_ALARM_TEMP_EXT1) ?
+ "; controller is overheating" : "",
+ (alarms1 & ~(LM87_ALARM_TEMP_INT | LM87_ALARM_TEMP_EXT1)
+ || alarms2) ?
+ "; electrical fault" : "");
return -ERANGE;
}
@@ -243,7 +248,7 @@ static int sfe4001_poweron(struct efx_nic *efx)
(0 << P0_EN_3V3X_LBN) | (0 << P0_EN_5V_LBN) |
(0 << P0_EN_1V0X_LBN));
if (rc != out) {
- EFX_INFO(efx, "power-cycling PHY\n");
+ netif_info(efx, hw, efx->net_dev, "power-cycling PHY\n");
rc = i2c_smbus_write_byte_data(ioexp_client, P0_OUT, out);
if (rc)
goto fail_on;
@@ -269,7 +274,8 @@ static int sfe4001_poweron(struct efx_nic *efx)
if (rc)
goto fail_on;
- EFX_INFO(efx, "waiting for DSP boot (attempt %d)...\n", i);
+ netif_info(efx, hw, efx->net_dev,
+ "waiting for DSP boot (attempt %d)...\n", i);
/* In flash config mode, DSP does not turn on AFE, so
* just wait 1 second.
@@ -291,7 +297,7 @@ static int sfe4001_poweron(struct efx_nic *efx)
}
}
- EFX_INFO(efx, "timed out waiting for DSP boot\n");
+ netif_info(efx, hw, efx->net_dev, "timed out waiting for DSP boot\n");
rc = -ETIMEDOUT;
fail_on:
sfe4001_poweroff(efx);
@@ -377,7 +383,7 @@ static void sfe4001_fini(struct efx_nic *efx)
{
struct falcon_board *board = falcon_board(efx);
- EFX_INFO(efx, "%s\n", __func__);
+ netif_info(efx, drv, efx->net_dev, "%s\n", __func__);
device_remove_file(&efx->pci_dev->dev, &dev_attr_phy_flash_cfg);
sfe4001_poweroff(efx);
@@ -461,7 +467,7 @@ static int sfe4001_init(struct efx_nic *efx)
if (rc)
goto fail_on;
- EFX_INFO(efx, "PHY is powered on\n");
+ netif_info(efx, hw, efx->net_dev, "PHY is powered on\n");
return 0;
fail_on:
@@ -493,7 +499,7 @@ static int sfn4111t_check_hw(struct efx_nic *efx)
static void sfn4111t_fini(struct efx_nic *efx)
{
- EFX_INFO(efx, "%s\n", __func__);
+ netif_info(efx, drv, efx->net_dev, "%s\n", __func__);
device_remove_file(&efx->pci_dev->dev, &dev_attr_phy_flash_cfg);
i2c_unregister_device(falcon_board(efx)->hwmon_client);
@@ -742,13 +748,14 @@ int falcon_probe_board(struct efx_nic *efx, u16 revision_info)
board->type = &board_types[i];
if (board->type) {
- EFX_INFO(efx, "board is %s rev %c%d\n",
+ netif_info(efx, probe, efx->net_dev, "board is %s rev %c%d\n",
(efx->pci_dev->subsystem_vendor == EFX_VENDID_SFC)
? board->type->ref_model : board->type->gen_type,
'A' + board->major, board->minor);
return 0;
} else {
- EFX_ERR(efx, "unknown board type %d\n", type_id);
+ netif_err(efx, probe, efx->net_dev, "unknown board type %d\n",
+ type_id);
return -ENODEV;
}
}
diff --git a/drivers/net/sfc/falcon_xmac.c b/drivers/net/sfc/falcon_xmac.c
index c84a2ce2ccb..bae656dd2c4 100644
--- a/drivers/net/sfc/falcon_xmac.c
+++ b/drivers/net/sfc/falcon_xmac.c
@@ -81,7 +81,8 @@ int falcon_reset_xaui(struct efx_nic *efx)
}
udelay(10);
}
- EFX_ERR(efx, "timed out waiting for XAUI/XGXS reset\n");
+ netif_err(efx, hw, efx->net_dev,
+ "timed out waiting for XAUI/XGXS reset\n");
return -ETIMEDOUT;
}
@@ -256,7 +257,7 @@ static bool falcon_xmac_link_ok_retry(struct efx_nic *efx, int tries)
falcon_stop_nic_stats(efx);
while (!mac_up && tries) {
- EFX_LOG(efx, "bashing xaui\n");
+ netif_dbg(efx, hw, efx->net_dev, "bashing xaui\n");
falcon_reset_xaui(efx);
udelay(200);
diff --git a/drivers/net/sfc/io.h b/drivers/net/sfc/io.h
index b89177c27f4..85a99fe8743 100644
--- a/drivers/net/sfc/io.h
+++ b/drivers/net/sfc/io.h
@@ -78,8 +78,9 @@ static inline void efx_writeo(struct efx_nic *efx, efx_oword_t *value,
{
unsigned long flags __attribute__ ((unused));
- EFX_REGDUMP(efx, "writing register %x with " EFX_OWORD_FMT "\n", reg,
- EFX_OWORD_VAL(*value));
+ netif_vdbg(efx, hw, efx->net_dev,
+ "writing register %x with " EFX_OWORD_FMT "\n", reg,
+ EFX_OWORD_VAL(*value));
spin_lock_irqsave(&efx->biu_lock, flags);
#ifdef EFX_USE_QWORD_IO
@@ -105,8 +106,9 @@ static inline void efx_sram_writeq(struct efx_nic *efx, void __iomem *membase,
unsigned int addr = index * sizeof(*value);
unsigned long flags __attribute__ ((unused));
- EFX_REGDUMP(efx, "writing SRAM address %x with " EFX_QWORD_FMT "\n",
- addr, EFX_QWORD_VAL(*value));
+ netif_vdbg(efx, hw, efx->net_dev,
+ "writing SRAM address %x with " EFX_QWORD_FMT "\n",
+ addr, EFX_QWORD_VAL(*value));
spin_lock_irqsave(&efx->biu_lock, flags);
#ifdef EFX_USE_QWORD_IO
@@ -129,8 +131,9 @@ static inline void efx_sram_writeq(struct efx_nic *efx, void __iomem *membase,
static inline void efx_writed(struct efx_nic *efx, efx_dword_t *value,
unsigned int reg)
{
- EFX_REGDUMP(efx, "writing partial register %x with "EFX_DWORD_FMT"\n",
- reg, EFX_DWORD_VAL(*value));
+ netif_vdbg(efx, hw, efx->net_dev,
+ "writing partial register %x with "EFX_DWORD_FMT"\n",
+ reg, EFX_DWORD_VAL(*value));
/* No lock required */
_efx_writed(efx, value->u32[0], reg);
@@ -155,8 +158,9 @@ static inline void efx_reado(struct efx_nic *efx, efx_oword_t *value,
value->u32[3] = _efx_readd(efx, reg + 12);
spin_unlock_irqrestore(&efx->biu_lock, flags);
- EFX_REGDUMP(efx, "read from register %x, got " EFX_OWORD_FMT "\n", reg,
- EFX_OWORD_VAL(*value));
+ netif_vdbg(efx, hw, efx->net_dev,
+ "read from register %x, got " EFX_OWORD_FMT "\n", reg,
+ EFX_OWORD_VAL(*value));
}
/* Read an 8-byte SRAM entry through supplied mapping,
@@ -177,8 +181,9 @@ static inline void efx_sram_readq(struct efx_nic *efx, void __iomem *membase,
#endif
spin_unlock_irqrestore(&efx->biu_lock, flags);
- EFX_REGDUMP(efx, "read from SRAM address %x, got "EFX_QWORD_FMT"\n",
- addr, EFX_QWORD_VAL(*value));
+ netif_vdbg(efx, hw, efx->net_dev,
+ "read from SRAM address %x, got "EFX_QWORD_FMT"\n",
+ addr, EFX_QWORD_VAL(*value));
}
/* Read dword from register that allows partial writes (sic) */
@@ -186,8 +191,9 @@ static inline void efx_readd(struct efx_nic *efx, efx_dword_t *value,
unsigned int reg)
{
value->u32[0] = _efx_readd(efx, reg);
- EFX_REGDUMP(efx, "read from register %x, got "EFX_DWORD_FMT"\n",
- reg, EFX_DWORD_VAL(*value));
+ netif_vdbg(efx, hw, efx->net_dev,
+ "read from register %x, got "EFX_DWORD_FMT"\n",
+ reg, EFX_DWORD_VAL(*value));
}
/* Write to a register forming part of a table */
@@ -211,6 +217,13 @@ static inline void efx_writed_table(struct efx_nic *efx, efx_dword_t *value,
efx_writed(efx, value, reg + index * sizeof(efx_oword_t));
}
+/* Read from a dword register forming part of a table */
+static inline void efx_readd_table(struct efx_nic *efx, efx_dword_t *value,
+ unsigned int reg, unsigned int index)
+{
+ efx_readd(efx, value, reg + index * sizeof(efx_dword_t));
+}
+
/* Page-mapped register block size */
#define EFX_PAGE_BLOCK_SIZE 0x2000
diff --git a/drivers/net/sfc/mcdi.c b/drivers/net/sfc/mcdi.c
index 93cc3c1b945..3912b8fed91 100644
--- a/drivers/net/sfc/mcdi.c
+++ b/drivers/net/sfc/mcdi.c
@@ -168,11 +168,12 @@ static int efx_mcdi_poll(struct efx_nic *efx)
error = EFX_DWORD_FIELD(reg, MCDI_HEADER_ERROR);
if (error && mcdi->resplen == 0) {
- EFX_ERR(efx, "MC rebooted\n");
+ netif_err(efx, hw, efx->net_dev, "MC rebooted\n");
rc = EIO;
} else if ((respseq ^ mcdi->seqno) & SEQ_MASK) {
- EFX_ERR(efx, "MC response mismatch tx seq 0x%x rx seq 0x%x\n",
- respseq, mcdi->seqno);
+ netif_err(efx, hw, efx->net_dev,
+ "MC response mismatch tx seq 0x%x rx seq 0x%x\n",
+ respseq, mcdi->seqno);
rc = EIO;
} else if (error) {
efx_readd(efx, &reg, pdu + 4);
@@ -303,8 +304,9 @@ static void efx_mcdi_ev_cpl(struct efx_nic *efx, unsigned int seqno,
/* The request has been cancelled */
--mcdi->credits;
else
- EFX_ERR(efx, "MC response mismatch tx seq 0x%x rx "
- "seq 0x%x\n", seqno, mcdi->seqno);
+ netif_err(efx, hw, efx->net_dev,
+ "MC response mismatch tx seq 0x%x rx "
+ "seq 0x%x\n", seqno, mcdi->seqno);
} else {
mcdi->resprc = errno;
mcdi->resplen = datalen;
@@ -352,8 +354,9 @@ int efx_mcdi_rpc(struct efx_nic *efx, unsigned cmd,
++mcdi->credits;
spin_unlock_bh(&mcdi->iface_lock);
- EFX_ERR(efx, "MC command 0x%x inlen %d mode %d timed out\n",
- cmd, (int)inlen, mcdi->mode);
+ netif_err(efx, hw, efx->net_dev,
+ "MC command 0x%x inlen %d mode %d timed out\n",
+ cmd, (int)inlen, mcdi->mode);
} else {
size_t resplen;
@@ -374,11 +377,13 @@ int efx_mcdi_rpc(struct efx_nic *efx, unsigned cmd,
} else if (cmd == MC_CMD_REBOOT && rc == -EIO)
; /* Don't reset if MC_CMD_REBOOT returns EIO */
else if (rc == -EIO || rc == -EINTR) {
- EFX_ERR(efx, "MC fatal error %d\n", -rc);
+ netif_err(efx, hw, efx->net_dev, "MC fatal error %d\n",
+ -rc);
efx_schedule_reset(efx, RESET_TYPE_MC_FAILURE);
} else
- EFX_ERR(efx, "MC command 0x%x inlen %d failed rc=%d\n",
- cmd, (int)inlen, -rc);
+ netif_err(efx, hw, efx->net_dev,
+ "MC command 0x%x inlen %d failed rc=%d\n",
+ cmd, (int)inlen, -rc);
}
efx_mcdi_release(mcdi);
@@ -534,8 +539,9 @@ static void efx_mcdi_sensor_event(struct efx_nic *efx, efx_qword_t *ev)
EFX_BUG_ON_PARANOID(state >= ARRAY_SIZE(sensor_status_names));
state_txt = sensor_status_names[state];
- EFX_ERR(efx, "Sensor %d (%s) reports condition '%s' for raw value %d\n",
- monitor, name, state_txt, value);
+ netif_err(efx, hw, efx->net_dev,
+ "Sensor %d (%s) reports condition '%s' for raw value %d\n",
+ monitor, name, state_txt, value);
}
/* Called from falcon_process_eventq for MCDI events */
@@ -548,12 +554,13 @@ void efx_mcdi_process_event(struct efx_channel *channel,
switch (code) {
case MCDI_EVENT_CODE_BADSSERT:
- EFX_ERR(efx, "MC watchdog or assertion failure at 0x%x\n", data);
+ netif_err(efx, hw, efx->net_dev,
+ "MC watchdog or assertion failure at 0x%x\n", data);
efx_mcdi_ev_death(efx, EINTR);
break;
case MCDI_EVENT_CODE_PMNOTICE:
- EFX_INFO(efx, "MCDI PM event.\n");
+ netif_info(efx, wol, efx->net_dev, "MCDI PM event.\n");
break;
case MCDI_EVENT_CODE_CMDDONE:
@@ -570,10 +577,11 @@ void efx_mcdi_process_event(struct efx_channel *channel,
efx_mcdi_sensor_event(efx, event);
break;
case MCDI_EVENT_CODE_SCHEDERR:
- EFX_INFO(efx, "MC Scheduler error address=0x%x\n", data);
+ netif_info(efx, hw, efx->net_dev,
+ "MC Scheduler error address=0x%x\n", data);
break;
case MCDI_EVENT_CODE_REBOOT:
- EFX_INFO(efx, "MC Reboot\n");
+ netif_info(efx, hw, efx->net_dev, "MC Reboot\n");
efx_mcdi_ev_death(efx, EIO);
break;
case MCDI_EVENT_CODE_MAC_STATS_DMA:
@@ -581,7 +589,8 @@ void efx_mcdi_process_event(struct efx_channel *channel,
break;
default:
- EFX_ERR(efx, "Unknown MCDI event 0x%x\n", code);
+ netif_err(efx, hw, efx->net_dev, "Unknown MCDI event 0x%x\n",
+ code);
}
}
@@ -627,7 +636,7 @@ int efx_mcdi_fwver(struct efx_nic *efx, u64 *version, u32 *build)
return 0;
fail:
- EFX_ERR(efx, "%s: failed rc=%d\n", __func__, rc);
+ netif_err(efx, probe, efx->net_dev, "%s: failed rc=%d\n", __func__, rc);
return rc;
}
@@ -657,7 +666,7 @@ int efx_mcdi_drv_attach(struct efx_nic *efx, bool driver_operating,
return 0;
fail:
- EFX_ERR(efx, "%s: failed rc=%d\n", __func__, rc);
+ netif_err(efx, probe, efx->net_dev, "%s: failed rc=%d\n", __func__, rc);
return rc;
}
@@ -695,7 +704,8 @@ int efx_mcdi_get_board_cfg(struct efx_nic *efx, u8 *mac_address,
return 0;
fail:
- EFX_ERR(efx, "%s: failed rc=%d len=%d\n", __func__, rc, (int)outlen);
+ netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d len=%d\n",
+ __func__, rc, (int)outlen);
return rc;
}
@@ -724,7 +734,7 @@ int efx_mcdi_log_ctrl(struct efx_nic *efx, bool evq, bool uart, u32 dest_evq)
return 0;
fail:
- EFX_ERR(efx, "%s: failed rc=%d\n", __func__, rc);
+ netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc);
return rc;
}
@@ -749,8 +759,8 @@ int efx_mcdi_nvram_types(struct efx_nic *efx, u32 *nvram_types_out)
return 0;
fail:
- EFX_ERR(efx, "%s: failed rc=%d\n",
- __func__, rc);
+ netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n",
+ __func__, rc);
return rc;
}
@@ -781,7 +791,7 @@ int efx_mcdi_nvram_info(struct efx_nic *efx, unsigned int type,
return 0;
fail:
- EFX_ERR(efx, "%s: failed rc=%d\n", __func__, rc);
+ netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc);
return rc;
}
@@ -802,7 +812,7 @@ int efx_mcdi_nvram_update_start(struct efx_nic *efx, unsigned int type)
return 0;
fail:
- EFX_ERR(efx, "%s: failed rc=%d\n", __func__, rc);
+ netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc);
return rc;
}
@@ -827,7 +837,7 @@ int efx_mcdi_nvram_read(struct efx_nic *efx, unsigned int type,
return 0;
fail:
- EFX_ERR(efx, "%s: failed rc=%d\n", __func__, rc);
+ netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc);
return rc;
}
@@ -853,7 +863,7 @@ int efx_mcdi_nvram_write(struct efx_nic *efx, unsigned int type,
return 0;
fail:
- EFX_ERR(efx, "%s: failed rc=%d\n", __func__, rc);
+ netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc);
return rc;
}
@@ -877,7 +887,7 @@ int efx_mcdi_nvram_erase(struct efx_nic *efx, unsigned int type,
return 0;
fail:
- EFX_ERR(efx, "%s: failed rc=%d\n", __func__, rc);
+ netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc);
return rc;
}
@@ -898,7 +908,7 @@ int efx_mcdi_nvram_update_finish(struct efx_nic *efx, unsigned int type)
return 0;
fail:
- EFX_ERR(efx, "%s: failed rc=%d\n", __func__, rc);
+ netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc);
return rc;
}
@@ -948,9 +958,10 @@ int efx_mcdi_nvram_test_all(struct efx_nic *efx)
return 0;
fail2:
- EFX_ERR(efx, "%s: failed type=%u\n", __func__, type);
+ netif_err(efx, hw, efx->net_dev, "%s: failed type=%u\n",
+ __func__, type);
fail1:
- EFX_ERR(efx, "%s: failed rc=%d\n", __func__, rc);
+ netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc);
return rc;
}
@@ -994,14 +1005,15 @@ static int efx_mcdi_read_assertion(struct efx_nic *efx)
: (flags == MC_CMD_GET_ASSERTS_FLAGS_WDOG_FIRED)
? "watchdog reset"
: "unknown assertion";
- EFX_ERR(efx, "MCPU %s at PC = 0x%.8x in thread 0x%.8x\n", reason,
- MCDI_DWORD(outbuf, GET_ASSERTS_OUT_SAVED_PC_OFFS),
- MCDI_DWORD(outbuf, GET_ASSERTS_OUT_THREAD_OFFS));
+ netif_err(efx, hw, efx->net_dev,
+ "MCPU %s at PC = 0x%.8x in thread 0x%.8x\n", reason,
+ MCDI_DWORD(outbuf, GET_ASSERTS_OUT_SAVED_PC_OFFS),
+ MCDI_DWORD(outbuf, GET_ASSERTS_OUT_THREAD_OFFS));
/* Print out the registers */
ofst = MC_CMD_GET_ASSERTS_OUT_GP_REGS_OFFS_OFST;
for (index = 1; index < 32; index++) {
- EFX_ERR(efx, "R%.2d (?): 0x%.8x\n", index,
+ netif_err(efx, hw, efx->net_dev, "R%.2d (?): 0x%.8x\n", index,
MCDI_DWORD2(outbuf, ofst));
ofst += sizeof(efx_dword_t);
}
@@ -1050,14 +1062,16 @@ void efx_mcdi_set_id_led(struct efx_nic *efx, enum efx_led_mode mode)
rc = efx_mcdi_rpc(efx, MC_CMD_SET_ID_LED, inbuf, sizeof(inbuf),
NULL, 0, NULL);
if (rc)
- EFX_ERR(efx, "%s: failed rc=%d\n", __func__, rc);
+ netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n",
+ __func__, rc);
}
int efx_mcdi_reset_port(struct efx_nic *efx)
{
int rc = efx_mcdi_rpc(efx, MC_CMD_PORT_RESET, NULL, 0, NULL, 0, NULL);
if (rc)
- EFX_ERR(efx, "%s: failed rc=%d\n", __func__, rc);
+ netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n",
+ __func__, rc);
return rc;
}
@@ -1075,7 +1089,7 @@ int efx_mcdi_reset_mc(struct efx_nic *efx)
return 0;
if (rc == 0)
rc = -EIO;
- EFX_ERR(efx, "%s: failed rc=%d\n", __func__, rc);
+ netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc);
return rc;
}
@@ -1108,7 +1122,7 @@ int efx_mcdi_wol_filter_set(struct efx_nic *efx, u32 type,
fail:
*id_out = -1;
- EFX_ERR(efx, "%s: failed rc=%d\n", __func__, rc);
+ netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc);
return rc;
}
@@ -1143,7 +1157,7 @@ int efx_mcdi_wol_filter_get_magic(struct efx_nic *efx, int *id_out)
fail:
*id_out = -1;
- EFX_ERR(efx, "%s: failed rc=%d\n", __func__, rc);
+ netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc);
return rc;
}
@@ -1163,7 +1177,7 @@ int efx_mcdi_wol_filter_remove(struct efx_nic *efx, int id)
return 0;
fail:
- EFX_ERR(efx, "%s: failed rc=%d\n", __func__, rc);
+ netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc);
return rc;
}
@@ -1179,7 +1193,7 @@ int efx_mcdi_wol_filter_reset(struct efx_nic *efx)
return 0;
fail:
- EFX_ERR(efx, "%s: failed rc=%d\n", __func__, rc);
+ netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc);
return rc;
}
diff --git a/drivers/net/sfc/mcdi_mac.c b/drivers/net/sfc/mcdi_mac.c
index 39182631ac9..f88f4bf986f 100644
--- a/drivers/net/sfc/mcdi_mac.c
+++ b/drivers/net/sfc/mcdi_mac.c
@@ -69,8 +69,8 @@ static int efx_mcdi_get_mac_faults(struct efx_nic *efx, u32 *faults)
return 0;
fail:
- EFX_ERR(efx, "%s: failed rc=%d\n",
- __func__, rc);
+ netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n",
+ __func__, rc);
return rc;
}
@@ -110,8 +110,8 @@ int efx_mcdi_mac_stats(struct efx_nic *efx, dma_addr_t dma_addr,
return 0;
fail:
- EFX_ERR(efx, "%s: %s failed rc=%d\n",
- __func__, enable ? "enable" : "disable", rc);
+ netif_err(efx, hw, efx->net_dev, "%s: %s failed rc=%d\n",
+ __func__, enable ? "enable" : "disable", rc);
return rc;
}
diff --git a/drivers/net/sfc/mcdi_phy.c b/drivers/net/sfc/mcdi_phy.c
index 6032c0e1f1f..0121e71702b 100644
--- a/drivers/net/sfc/mcdi_phy.c
+++ b/drivers/net/sfc/mcdi_phy.c
@@ -20,7 +20,7 @@
#include "nic.h"
#include "selftest.h"
-struct efx_mcdi_phy_cfg {
+struct efx_mcdi_phy_data {
u32 flags;
u32 type;
u32 supported_cap;
@@ -35,7 +35,7 @@ struct efx_mcdi_phy_cfg {
};
static int
-efx_mcdi_get_phy_cfg(struct efx_nic *efx, struct efx_mcdi_phy_cfg *cfg)
+efx_mcdi_get_phy_cfg(struct efx_nic *efx, struct efx_mcdi_phy_data *cfg)
{
u8 outbuf[MC_CMD_GET_PHY_CFG_OUT_LEN];
size_t outlen;
@@ -71,7 +71,7 @@ efx_mcdi_get_phy_cfg(struct efx_nic *efx, struct efx_mcdi_phy_cfg *cfg)
return 0;
fail:
- EFX_ERR(efx, "%s: failed rc=%d\n", __func__, rc);
+ netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc);
return rc;
}
@@ -97,7 +97,7 @@ static int efx_mcdi_set_link(struct efx_nic *efx, u32 capabilities,
return 0;
fail:
- EFX_ERR(efx, "%s: failed rc=%d\n", __func__, rc);
+ netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc);
return rc;
}
@@ -122,7 +122,7 @@ static int efx_mcdi_loopback_modes(struct efx_nic *efx, u64 *loopback_modes)
return 0;
fail:
- EFX_ERR(efx, "%s: failed rc=%d\n", __func__, rc);
+ netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc);
return rc;
}
@@ -150,7 +150,7 @@ int efx_mcdi_mdio_read(struct efx_nic *efx, unsigned int bus,
return 0;
fail:
- EFX_ERR(efx, "%s: failed rc=%d\n", __func__, rc);
+ netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc);
return rc;
}
@@ -178,7 +178,7 @@ int efx_mcdi_mdio_write(struct efx_nic *efx, unsigned int bus,
return 0;
fail:
- EFX_ERR(efx, "%s: failed rc=%d\n", __func__, rc);
+ netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc);
return rc;
}
@@ -259,7 +259,7 @@ static u32 ethtool_to_mcdi_cap(u32 cap)
static u32 efx_get_mcdi_phy_flags(struct efx_nic *efx)
{
- struct efx_mcdi_phy_cfg *phy_cfg = efx->phy_data;
+ struct efx_mcdi_phy_data *phy_cfg = efx->phy_data;
enum efx_phy_mode mode, supported;
u32 flags;
@@ -307,7 +307,7 @@ static u32 mcdi_to_ethtool_media(u32 media)
static int efx_mcdi_phy_probe(struct efx_nic *efx)
{
- struct efx_mcdi_phy_cfg *phy_data;
+ struct efx_mcdi_phy_data *phy_data;
u8 outbuf[MC_CMD_GET_LINK_OUT_LEN];
u32 caps;
int rc;
@@ -395,6 +395,7 @@ static int efx_mcdi_phy_probe(struct efx_nic *efx)
efx->wanted_fc = EFX_FC_RX | EFX_FC_TX;
if (phy_data->supported_cap & (1 << MC_CMD_PHY_CAP_AN_LBN))
efx->wanted_fc |= EFX_FC_AUTO;
+ efx_link_set_wanted_fc(efx, efx->wanted_fc);
return 0;
@@ -405,7 +406,7 @@ fail:
int efx_mcdi_phy_reconfigure(struct efx_nic *efx)
{
- struct efx_mcdi_phy_cfg *phy_cfg = efx->phy_data;
+ struct efx_mcdi_phy_data *phy_cfg = efx->phy_data;
u32 caps = (efx->link_advertising ?
ethtool_to_mcdi_cap(efx->link_advertising) :
phy_cfg->forced_cap);
@@ -446,7 +447,7 @@ void efx_mcdi_phy_decode_link(struct efx_nic *efx,
*/
void efx_mcdi_phy_check_fcntl(struct efx_nic *efx, u32 lpa)
{
- struct efx_mcdi_phy_cfg *phy_cfg = efx->phy_data;
+ struct efx_mcdi_phy_data *phy_cfg = efx->phy_data;
u32 rmtadv;
/* The link partner capabilities are only relevent if the
@@ -465,8 +466,8 @@ void efx_mcdi_phy_check_fcntl(struct efx_nic *efx, u32 lpa)
rmtadv |= ADVERTISED_Asym_Pause;
if ((efx->wanted_fc & EFX_FC_TX) && rmtadv == ADVERTISED_Asym_Pause)
- EFX_ERR(efx, "warning: link partner doesn't support "
- "pause frames");
+ netif_err(efx, link, efx->net_dev,
+ "warning: link partner doesn't support pause frames");
}
static bool efx_mcdi_phy_poll(struct efx_nic *efx)
@@ -482,7 +483,8 @@ static bool efx_mcdi_phy_poll(struct efx_nic *efx)
rc = efx_mcdi_rpc(efx, MC_CMD_GET_LINK, NULL, 0,
outbuf, sizeof(outbuf), NULL);
if (rc) {
- EFX_ERR(efx, "%s: failed rc=%d\n", __func__, rc);
+ netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n",
+ __func__, rc);
efx->link_state.up = false;
} else {
efx_mcdi_phy_decode_link(
@@ -505,7 +507,7 @@ static void efx_mcdi_phy_remove(struct efx_nic *efx)
static void efx_mcdi_phy_get_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd)
{
- struct efx_mcdi_phy_cfg *phy_cfg = efx->phy_data;
+ struct efx_mcdi_phy_data *phy_cfg = efx->phy_data;
u8 outbuf[MC_CMD_GET_LINK_OUT_LEN];
int rc;
@@ -525,7 +527,8 @@ static void efx_mcdi_phy_get_settings(struct efx_nic *efx, struct ethtool_cmd *e
rc = efx_mcdi_rpc(efx, MC_CMD_GET_LINK, NULL, 0,
outbuf, sizeof(outbuf), NULL);
if (rc) {
- EFX_ERR(efx, "%s: failed rc=%d\n", __func__, rc);
+ netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n",
+ __func__, rc);
return;
}
ecmd->lp_advertising =
@@ -535,7 +538,7 @@ static void efx_mcdi_phy_get_settings(struct efx_nic *efx, struct ethtool_cmd *e
static int efx_mcdi_phy_set_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd)
{
- struct efx_mcdi_phy_cfg *phy_cfg = efx->phy_data;
+ struct efx_mcdi_phy_data *phy_cfg = efx->phy_data;
u32 caps;
int rc;
@@ -674,7 +677,7 @@ out:
static int efx_mcdi_phy_run_tests(struct efx_nic *efx, int *results,
unsigned flags)
{
- struct efx_mcdi_phy_cfg *phy_cfg = efx->phy_data;
+ struct efx_mcdi_phy_data *phy_cfg = efx->phy_data;
u32 mode;
int rc;
@@ -712,7 +715,7 @@ static int efx_mcdi_phy_run_tests(struct efx_nic *efx, int *results,
const char *efx_mcdi_phy_test_name(struct efx_nic *efx, unsigned int index)
{
- struct efx_mcdi_phy_cfg *phy_cfg = efx->phy_data;
+ struct efx_mcdi_phy_data *phy_cfg = efx->phy_data;
if (phy_cfg->flags & (1 << MC_CMD_GET_PHY_CFG_BIST_LBN)) {
if (index == 0)
diff --git a/drivers/net/sfc/mdio_10g.c b/drivers/net/sfc/mdio_10g.c
index 0548fcbbdcd..eeaf0bd64bd 100644
--- a/drivers/net/sfc/mdio_10g.c
+++ b/drivers/net/sfc/mdio_10g.c
@@ -63,7 +63,8 @@ static int efx_mdio_check_mmd(struct efx_nic *efx, int mmd, int fault_fatal)
/* Read MMD STATUS2 to check it is responding. */
status = efx_mdio_read(efx, mmd, MDIO_STAT2);
if ((status & MDIO_STAT2_DEVPRST) != MDIO_STAT2_DEVPRST_VAL) {
- EFX_ERR(efx, "PHY MMD %d not responding.\n", mmd);
+ netif_err(efx, hw, efx->net_dev,
+ "PHY MMD %d not responding.\n", mmd);
return -EIO;
}
}
@@ -72,12 +73,14 @@ static int efx_mdio_check_mmd(struct efx_nic *efx, int mmd, int fault_fatal)
status = efx_mdio_read(efx, mmd, MDIO_STAT1);
if (status & MDIO_STAT1_FAULT) {
if (fault_fatal) {
- EFX_ERR(efx, "PHY MMD %d reporting fatal"
- " fault: status %x\n", mmd, status);
+ netif_err(efx, hw, efx->net_dev,
+ "PHY MMD %d reporting fatal"
+ " fault: status %x\n", mmd, status);
return -EIO;
} else {
- EFX_LOG(efx, "PHY MMD %d reporting status"
- " %x (expected)\n", mmd, status);
+ netif_dbg(efx, hw, efx->net_dev,
+ "PHY MMD %d reporting status"
+ " %x (expected)\n", mmd, status);
}
}
return 0;
@@ -103,8 +106,9 @@ int efx_mdio_wait_reset_mmds(struct efx_nic *efx, unsigned int mmd_mask)
if (mask & 1) {
stat = efx_mdio_read(efx, mmd, MDIO_CTRL1);
if (stat < 0) {
- EFX_ERR(efx, "failed to read status of"
- " MMD %d\n", mmd);
+ netif_err(efx, hw, efx->net_dev,
+ "failed to read status of"
+ " MMD %d\n", mmd);
return -EIO;
}
if (stat & MDIO_CTRL1_RESET)
@@ -119,8 +123,9 @@ int efx_mdio_wait_reset_mmds(struct efx_nic *efx, unsigned int mmd_mask)
msleep(spintime);
}
if (in_reset != 0) {
- EFX_ERR(efx, "not all MMDs came out of reset in time."
- " MMDs still in reset: %x\n", in_reset);
+ netif_err(efx, hw, efx->net_dev,
+ "not all MMDs came out of reset in time."
+ " MMDs still in reset: %x\n", in_reset);
rc = -ETIMEDOUT;
}
return rc;
@@ -142,16 +147,18 @@ int efx_mdio_check_mmds(struct efx_nic *efx,
devs1 = efx_mdio_read(efx, probe_mmd, MDIO_DEVS1);
devs2 = efx_mdio_read(efx, probe_mmd, MDIO_DEVS2);
if (devs1 < 0 || devs2 < 0) {
- EFX_ERR(efx, "failed to read devices present\n");
+ netif_err(efx, hw, efx->net_dev,
+ "failed to read devices present\n");
return -EIO;
}
devices = devs1 | (devs2 << 16);
if ((devices & mmd_mask) != mmd_mask) {
- EFX_ERR(efx, "required MMDs not present: got %x, "
- "wanted %x\n", devices, mmd_mask);
+ netif_err(efx, hw, efx->net_dev,
+ "required MMDs not present: got %x, wanted %x\n",
+ devices, mmd_mask);
return -ENODEV;
}
- EFX_TRACE(efx, "Devices present: %x\n", devices);
+ netif_vdbg(efx, hw, efx->net_dev, "Devices present: %x\n", devices);
/* Check all required MMDs are responding and happy. */
while (mmd_mask) {
@@ -219,7 +226,7 @@ static void efx_mdio_set_mmd_lpower(struct efx_nic *efx,
{
int stat = efx_mdio_read(efx, mmd, MDIO_STAT1);
- EFX_TRACE(efx, "Setting low power mode for MMD %d to %d\n",
+ netif_vdbg(efx, drv, efx->net_dev, "Setting low power mode for MMD %d to %d\n",
mmd, lpower);
if (stat & MDIO_STAT1_LPOWERABLE) {
@@ -349,8 +356,8 @@ int efx_mdio_test_alive(struct efx_nic *efx)
if ((physid1 == 0x0000) || (physid1 == 0xffff) ||
(physid2 == 0x0000) || (physid2 == 0xffff)) {
- EFX_ERR(efx, "no MDIO PHY present with ID %d\n",
- efx->mdio.prtad);
+ netif_err(efx, hw, efx->net_dev,
+ "no MDIO PHY present with ID %d\n", efx->mdio.prtad);
rc = -EINVAL;
} else {
rc = efx_mdio_check_mmds(efx, efx->mdio.mmds, 0);
diff --git a/drivers/net/sfc/mdio_10g.h b/drivers/net/sfc/mdio_10g.h
index f89e7192960..75791d3d496 100644
--- a/drivers/net/sfc/mdio_10g.h
+++ b/drivers/net/sfc/mdio_10g.h
@@ -51,7 +51,8 @@ static inline bool efx_mdio_phyxgxs_lane_sync(struct efx_nic *efx)
sync = !!(lane_status & MDIO_PHYXS_LNSTAT_ALIGN);
if (!sync)
- EFX_LOG(efx, "XGXS lane status: %x\n", lane_status);
+ netif_dbg(efx, hw, efx->net_dev, "XGXS lane status: %x\n",
+ lane_status);
return sync;
}
diff --git a/drivers/net/sfc/mtd.c b/drivers/net/sfc/mtd.c
index f3ac7f30b5e..02e54b4f701 100644
--- a/drivers/net/sfc/mtd.c
+++ b/drivers/net/sfc/mtd.c
@@ -15,7 +15,6 @@
#include <linux/slab.h>
#include <linux/rtnetlink.h>
-#define EFX_DRIVER_NAME "sfc_mtd"
#include "net_driver.h"
#include "spi.h"
#include "efx.h"
@@ -71,8 +70,10 @@ static int siena_mtd_probe(struct efx_nic *efx);
/* SPI utilities */
-static int efx_spi_slow_wait(struct efx_mtd *efx_mtd, bool uninterruptible)
+static int
+efx_spi_slow_wait(struct efx_mtd_partition *part, bool uninterruptible)
{
+ struct efx_mtd *efx_mtd = part->mtd.priv;
const struct efx_spi_device *spi = efx_mtd->spi;
struct efx_nic *efx = efx_mtd->efx;
u8 status;
@@ -92,7 +93,7 @@ static int efx_spi_slow_wait(struct efx_mtd *efx_mtd, bool uninterruptible)
if (signal_pending(current))
return -EINTR;
}
- EFX_ERR(efx, "timed out waiting for %s\n", efx_mtd->name);
+ pr_err("%s: timed out waiting for %s\n", part->name, efx_mtd->name);
return -ETIMEDOUT;
}
@@ -131,8 +132,10 @@ efx_spi_unlock(struct efx_nic *efx, const struct efx_spi_device *spi)
return 0;
}
-static int efx_spi_erase(struct efx_mtd *efx_mtd, loff_t start, size_t len)
+static int
+efx_spi_erase(struct efx_mtd_partition *part, loff_t start, size_t len)
{
+ struct efx_mtd *efx_mtd = part->mtd.priv;
const struct efx_spi_device *spi = efx_mtd->spi;
struct efx_nic *efx = efx_mtd->efx;
unsigned pos, block_len;
@@ -156,7 +159,7 @@ static int efx_spi_erase(struct efx_mtd *efx_mtd, loff_t start, size_t len)
NULL, 0);
if (rc)
return rc;
- rc = efx_spi_slow_wait(efx_mtd, false);
+ rc = efx_spi_slow_wait(part, false);
/* Verify the entire region has been wiped */
memset(empty, 0xff, sizeof(empty));
@@ -198,13 +201,14 @@ static int efx_mtd_erase(struct mtd_info *mtd, struct erase_info *erase)
static void efx_mtd_sync(struct mtd_info *mtd)
{
+ struct efx_mtd_partition *part = to_efx_mtd_partition(mtd);
struct efx_mtd *efx_mtd = mtd->priv;
- struct efx_nic *efx = efx_mtd->efx;
int rc;
rc = efx_mtd->ops->sync(mtd);
if (rc)
- EFX_ERR(efx, "%s sync failed (%d)\n", efx_mtd->name, rc);
+ pr_err("%s: %s sync failed (%d)\n",
+ part->name, efx_mtd->name, rc);
}
static void efx_mtd_remove_partition(struct efx_mtd_partition *part)
@@ -338,7 +342,7 @@ static int falcon_mtd_erase(struct mtd_info *mtd, loff_t start, size_t len)
rc = mutex_lock_interruptible(&efx->spi_lock);
if (rc)
return rc;
- rc = efx_spi_erase(efx_mtd, part->offset + start, len);
+ rc = efx_spi_erase(part, part->offset + start, len);
mutex_unlock(&efx->spi_lock);
return rc;
}
@@ -363,12 +367,13 @@ static int falcon_mtd_write(struct mtd_info *mtd, loff_t start,
static int falcon_mtd_sync(struct mtd_info *mtd)
{
+ struct efx_mtd_partition *part = to_efx_mtd_partition(mtd);
struct efx_mtd *efx_mtd = mtd->priv;
struct efx_nic *efx = efx_mtd->efx;
int rc;
mutex_lock(&efx->spi_lock);
- rc = efx_spi_slow_wait(efx_mtd, true);
+ rc = efx_spi_slow_wait(part, true);
mutex_unlock(&efx->spi_lock);
return rc;
}
diff --git a/drivers/net/sfc/net_driver.h b/drivers/net/sfc/net_driver.h
index 4762c91cb58..64e7caa4bbb 100644
--- a/drivers/net/sfc/net_driver.h
+++ b/drivers/net/sfc/net_driver.h
@@ -13,11 +13,16 @@
#ifndef EFX_NET_DRIVER_H
#define EFX_NET_DRIVER_H
+#if defined(EFX_ENABLE_DEBUG) && !defined(DEBUG)
+#define DEBUG
+#endif
+
#include <linux/version.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/ethtool.h>
#include <linux/if_vlan.h>
+#include <linux/timer.h>
#include <linux/mdio.h>
#include <linux/list.h>
#include <linux/pci.h>
@@ -34,9 +39,7 @@
* Build definitions
*
**************************************************************************/
-#ifndef EFX_DRIVER_NAME
-#define EFX_DRIVER_NAME "sfc"
-#endif
+
#define EFX_DRIVER_VERSION "3.0"
#ifdef EFX_ENABLE_DEBUG
@@ -47,35 +50,6 @@
#define EFX_WARN_ON_PARANOID(x) do {} while (0)
#endif
-/* Un-rate-limited logging */
-#define EFX_ERR(efx, fmt, args...) \
-dev_err(&((efx)->pci_dev->dev), "ERR: %s " fmt, efx_dev_name(efx), ##args)
-
-#define EFX_INFO(efx, fmt, args...) \
-dev_info(&((efx)->pci_dev->dev), "INFO: %s " fmt, efx_dev_name(efx), ##args)
-
-#ifdef EFX_ENABLE_DEBUG
-#define EFX_LOG(efx, fmt, args...) \
-dev_info(&((efx)->pci_dev->dev), "DBG: %s " fmt, efx_dev_name(efx), ##args)
-#else
-#define EFX_LOG(efx, fmt, args...) \
-dev_dbg(&((efx)->pci_dev->dev), "DBG: %s " fmt, efx_dev_name(efx), ##args)
-#endif
-
-#define EFX_TRACE(efx, fmt, args...) do {} while (0)
-
-#define EFX_REGDUMP(efx, fmt, args...) do {} while (0)
-
-/* Rate-limited logging */
-#define EFX_ERR_RL(efx, fmt, args...) \
-do {if (net_ratelimit()) EFX_ERR(efx, fmt, ##args); } while (0)
-
-#define EFX_INFO_RL(efx, fmt, args...) \
-do {if (net_ratelimit()) EFX_INFO(efx, fmt, ##args); } while (0)
-
-#define EFX_LOG_RL(efx, fmt, args...) \
-do {if (net_ratelimit()) EFX_LOG(efx, fmt, ##args); } while (0)
-
/**************************************************************************
*
* Efx data structures
@@ -221,7 +195,6 @@ struct efx_tx_queue {
* If both this and skb are %NULL, the buffer slot is currently free.
* @data: Pointer to ethernet header
* @len: Buffer length, in bytes.
- * @unmap_addr: DMA address to unmap
*/
struct efx_rx_buffer {
dma_addr_t dma_addr;
@@ -229,7 +202,24 @@ struct efx_rx_buffer {
struct page *page;
char *data;
unsigned int len;
- dma_addr_t unmap_addr;
+};
+
+/**
+ * struct efx_rx_page_state - Page-based rx buffer state
+ *
+ * Inserted at the start of every page allocated for receive buffers.
+ * Used to facilitate sharing dma mappings between recycled rx buffers
+ * and those passed up to the kernel.
+ *
+ * @refcnt: Number of struct efx_rx_buffer's referencing this page.
+ * When refcnt falls to zero, the page is unmapped for dma
+ * @dma_addr: The dma address of this page.
+ */
+struct efx_rx_page_state {
+ unsigned refcnt;
+ dma_addr_t dma_addr;
+
+ unsigned int __pad[0] ____cacheline_aligned;
};
/**
@@ -242,10 +232,6 @@ struct efx_rx_buffer {
* @added_count: Number of buffers added to the receive queue.
* @notified_count: Number of buffers given to NIC (<= @added_count).
* @removed_count: Number of buffers removed from the receive queue.
- * @add_lock: Receive queue descriptor add spin lock.
- * This lock must be held in order to add buffers to the RX
- * descriptor ring (rxd and buffer) and to update added_count (but
- * not removed_count).
* @max_fill: RX descriptor maximum fill level (<= ring size)
* @fast_fill_trigger: RX descriptor fill level that will trigger a fast fill
* (<= @max_fill)
@@ -259,12 +245,7 @@ struct efx_rx_buffer {
* overflow was observed. It should never be set.
* @alloc_page_count: RX allocation strategy counter.
* @alloc_skb_count: RX allocation strategy counter.
- * @work: Descriptor push work thread
- * @buf_page: Page for next RX buffer.
- * We can use a single page for multiple RX buffers. This tracks
- * the remaining space in the allocation.
- * @buf_dma_addr: Page's DMA address.
- * @buf_data: Page's host address.
+ * @slow_fill: Timer used to defer efx_nic_generate_fill_event().
* @flushed: Use when handling queue flushing
*/
struct efx_rx_queue {
@@ -277,7 +258,6 @@ struct efx_rx_queue {
int added_count;
int notified_count;
int removed_count;
- spinlock_t add_lock;
unsigned int max_fill;
unsigned int fast_fill_trigger;
unsigned int fast_fill_limit;
@@ -285,12 +265,9 @@ struct efx_rx_queue {
unsigned int min_overfill;
unsigned int alloc_page_count;
unsigned int alloc_skb_count;
- struct delayed_work work;
+ struct timer_list slow_fill;
unsigned int slow_fill_count;
- struct page *buf_page;
- dma_addr_t buf_dma_addr;
- char *buf_data;
enum efx_flush_state flushed;
};
@@ -336,7 +313,7 @@ enum efx_rx_alloc_method {
* @eventq: Event queue buffer
* @eventq_read_ptr: Event queue read pointer
* @last_eventq_read_ptr: Last event queue read pointer value.
- * @eventq_magic: Event queue magic value for driver-generated test events
+ * @magic_count: Event queue test event count
* @irq_count: Number of IRQs since last adaptive moderation decision
* @irq_mod_score: IRQ moderation score
* @rx_alloc_level: Watermark based heuristic counter for pushing descriptors
@@ -367,7 +344,7 @@ struct efx_channel {
struct efx_special_buffer eventq;
unsigned int eventq_read_ptr;
unsigned int last_eventq_read_ptr;
- unsigned int eventq_magic;
+ unsigned int magic_count;
unsigned int irq_count;
unsigned int irq_mod_score;
@@ -658,6 +635,7 @@ union efx_multicast_hash {
* @interrupt_mode: Interrupt mode
* @irq_rx_adaptive: Adaptive IRQ moderation enabled for RX event queues
* @irq_rx_moderation: IRQ moderation time for RX event queues
+ * @msg_enable: Log message enable flags
* @state: Device state flag. Serialised by the rtnl_lock.
* @reset_pending: Pending reset method (normally RESET_TYPE_NONE)
* @tx_queue: TX DMA queues
@@ -669,6 +647,7 @@ union efx_multicast_hash {
* @n_tx_channels: Number of channels used for TX
* @rx_buffer_len: RX buffer length
* @rx_buffer_order: Order (log2) of number of pages for each RX buffer
+ * @rx_indir_table: Indirection table for RSS
* @int_error_count: Number of internal errors seen recently
* @int_error_expire: Time at which error count will be expired
* @irq_status: Interrupt status buffer
@@ -740,6 +719,7 @@ struct efx_nic {
enum efx_int_mode interrupt_mode;
bool irq_rx_adaptive;
unsigned int irq_rx_moderation;
+ u32 msg_enable;
enum nic_state state;
enum reset_type reset_pending;
@@ -754,6 +734,8 @@ struct efx_nic {
unsigned n_tx_channels;
unsigned int rx_buffer_len;
unsigned int rx_buffer_order;
+ u8 rx_hash_key[40];
+ u32 rx_indir_table[128];
unsigned int_error_count;
unsigned long int_error_expire;
@@ -866,7 +848,8 @@ static inline unsigned int efx_port_num(struct efx_nic *efx)
* @evq_ptr_tbl_base: Event queue pointer table base address
* @evq_rptr_tbl_base: Event queue read-pointer table base address
* @max_dma_mask: Maximum possible DMA mask
- * @rx_buffer_padding: Padding added to each RX buffer
+ * @rx_buffer_hash_size: Size of hash at start of RX buffer
+ * @rx_buffer_padding: Size of padding at end of RX buffer
* @max_interrupt_mode: Highest capability interrupt mode supported
* from &enum efx_init_mode.
* @phys_addr_channels: Number of channels with physically addressed
@@ -910,6 +893,7 @@ struct efx_nic_type {
unsigned int evq_ptr_tbl_base;
unsigned int evq_rptr_tbl_base;
u64 max_dma_mask;
+ unsigned int rx_buffer_hash_size;
unsigned int rx_buffer_padding;
unsigned int max_interrupt_mode;
unsigned int phys_addr_channels;
diff --git a/drivers/net/sfc/nic.c b/drivers/net/sfc/nic.c
index 5d3aaec5855..f595d920c7c 100644
--- a/drivers/net/sfc/nic.c
+++ b/drivers/net/sfc/nic.c
@@ -79,6 +79,14 @@ MODULE_PARM_DESC(rx_xon_thresh_bytes, "RX fifo XON threshold");
/* Depth of RX flush request fifo */
#define EFX_RX_FLUSH_COUNT 4
+/* Generated event code for efx_generate_test_event() */
+#define EFX_CHANNEL_MAGIC_TEST(_channel) \
+ (0x00010100 + (_channel)->channel)
+
+/* Generated event code for efx_generate_fill_event() */
+#define EFX_CHANNEL_MAGIC_FILL(_channel) \
+ (0x00010200 + (_channel)->channel)
+
/**************************************************************************
*
* Solarstorm hardware access
@@ -171,9 +179,10 @@ int efx_nic_test_registers(struct efx_nic *efx,
return 0;
fail:
- EFX_ERR(efx, "wrote "EFX_OWORD_FMT" read "EFX_OWORD_FMT
- " at address 0x%x mask "EFX_OWORD_FMT"\n", EFX_OWORD_VAL(reg),
- EFX_OWORD_VAL(buf), address, EFX_OWORD_VAL(mask));
+ netif_err(efx, hw, efx->net_dev,
+ "wrote "EFX_OWORD_FMT" read "EFX_OWORD_FMT
+ " at address 0x%x mask "EFX_OWORD_FMT"\n", EFX_OWORD_VAL(reg),
+ EFX_OWORD_VAL(buf), address, EFX_OWORD_VAL(mask));
return -EIO;
}
@@ -206,8 +215,9 @@ efx_init_special_buffer(struct efx_nic *efx, struct efx_special_buffer *buffer)
for (i = 0; i < buffer->entries; i++) {
index = buffer->index + i;
dma_addr = buffer->dma_addr + (i * 4096);
- EFX_LOG(efx, "mapping special buffer %d at %llx\n",
- index, (unsigned long long)dma_addr);
+ netif_dbg(efx, probe, efx->net_dev,
+ "mapping special buffer %d at %llx\n",
+ index, (unsigned long long)dma_addr);
EFX_POPULATE_QWORD_3(buf_desc,
FRF_AZ_BUF_ADR_REGION, 0,
FRF_AZ_BUF_ADR_FBUF, dma_addr >> 12,
@@ -227,8 +237,8 @@ efx_fini_special_buffer(struct efx_nic *efx, struct efx_special_buffer *buffer)
if (!buffer->entries)
return;
- EFX_LOG(efx, "unmapping special buffers %d-%d\n",
- buffer->index, buffer->index + buffer->entries - 1);
+ netif_dbg(efx, hw, efx->net_dev, "unmapping special buffers %d-%d\n",
+ buffer->index, buffer->index + buffer->entries - 1);
EFX_POPULATE_OWORD_4(buf_tbl_upd,
FRF_AZ_BUF_UPD_CMD, 0,
@@ -268,11 +278,12 @@ static int efx_alloc_special_buffer(struct efx_nic *efx,
buffer->index = efx->next_buffer_table;
efx->next_buffer_table += buffer->entries;
- EFX_LOG(efx, "allocating special buffers %d-%d at %llx+%x "
- "(virt %p phys %llx)\n", buffer->index,
- buffer->index + buffer->entries - 1,
- (u64)buffer->dma_addr, len,
- buffer->addr, (u64)virt_to_phys(buffer->addr));
+ netif_dbg(efx, probe, efx->net_dev,
+ "allocating special buffers %d-%d at %llx+%x "
+ "(virt %p phys %llx)\n", buffer->index,
+ buffer->index + buffer->entries - 1,
+ (u64)buffer->dma_addr, len,
+ buffer->addr, (u64)virt_to_phys(buffer->addr));
return 0;
}
@@ -283,11 +294,12 @@ efx_free_special_buffer(struct efx_nic *efx, struct efx_special_buffer *buffer)
if (!buffer->addr)
return;
- EFX_LOG(efx, "deallocating special buffers %d-%d at %llx+%x "
- "(virt %p phys %llx)\n", buffer->index,
- buffer->index + buffer->entries - 1,
- (u64)buffer->dma_addr, buffer->len,
- buffer->addr, (u64)virt_to_phys(buffer->addr));
+ netif_dbg(efx, hw, efx->net_dev,
+ "deallocating special buffers %d-%d at %llx+%x "
+ "(virt %p phys %llx)\n", buffer->index,
+ buffer->index + buffer->entries - 1,
+ (u64)buffer->dma_addr, buffer->len,
+ buffer->addr, (u64)virt_to_phys(buffer->addr));
pci_free_consistent(efx->pci_dev, buffer->len, buffer->addr,
buffer->dma_addr);
@@ -547,9 +559,10 @@ void efx_nic_init_rx(struct efx_rx_queue *rx_queue)
bool is_b0 = efx_nic_rev(efx) >= EFX_REV_FALCON_B0;
bool iscsi_digest_en = is_b0;
- EFX_LOG(efx, "RX queue %d ring in special buffers %d-%d\n",
- rx_queue->queue, rx_queue->rxd.index,
- rx_queue->rxd.index + rx_queue->rxd.entries - 1);
+ netif_dbg(efx, hw, efx->net_dev,
+ "RX queue %d ring in special buffers %d-%d\n",
+ rx_queue->queue, rx_queue->rxd.index,
+ rx_queue->rxd.index + rx_queue->rxd.entries - 1);
rx_queue->flushed = FLUSH_NONE;
@@ -686,9 +699,10 @@ efx_handle_tx_event(struct efx_channel *channel, efx_qword_t *event)
EFX_WORKAROUND_10727(efx)) {
efx_schedule_reset(efx, RESET_TYPE_TX_DESC_FETCH);
} else {
- EFX_ERR(efx, "channel %d unexpected TX event "
- EFX_QWORD_FMT"\n", channel->channel,
- EFX_QWORD_VAL(*event));
+ netif_err(efx, tx_err, efx->net_dev,
+ "channel %d unexpected TX event "
+ EFX_QWORD_FMT"\n", channel->channel,
+ EFX_QWORD_VAL(*event));
}
return tx_packets;
@@ -751,20 +765,21 @@ static void efx_handle_rx_not_ok(struct efx_rx_queue *rx_queue,
* to a FIFO overflow.
*/
#ifdef EFX_ENABLE_DEBUG
- if (rx_ev_other_err) {
- EFX_INFO_RL(efx, " RX queue %d unexpected RX event "
- EFX_QWORD_FMT "%s%s%s%s%s%s%s%s\n",
- rx_queue->queue, EFX_QWORD_VAL(*event),
- rx_ev_buf_owner_id_err ? " [OWNER_ID_ERR]" : "",
- rx_ev_ip_hdr_chksum_err ?
- " [IP_HDR_CHKSUM_ERR]" : "",
- rx_ev_tcp_udp_chksum_err ?
- " [TCP_UDP_CHKSUM_ERR]" : "",
- rx_ev_eth_crc_err ? " [ETH_CRC_ERR]" : "",
- rx_ev_frm_trunc ? " [FRM_TRUNC]" : "",
- rx_ev_drib_nib ? " [DRIB_NIB]" : "",
- rx_ev_tobe_disc ? " [TOBE_DISC]" : "",
- rx_ev_pause_frm ? " [PAUSE]" : "");
+ if (rx_ev_other_err && net_ratelimit()) {
+ netif_dbg(efx, rx_err, efx->net_dev,
+ " RX queue %d unexpected RX event "
+ EFX_QWORD_FMT "%s%s%s%s%s%s%s%s\n",
+ rx_queue->queue, EFX_QWORD_VAL(*event),
+ rx_ev_buf_owner_id_err ? " [OWNER_ID_ERR]" : "",
+ rx_ev_ip_hdr_chksum_err ?
+ " [IP_HDR_CHKSUM_ERR]" : "",
+ rx_ev_tcp_udp_chksum_err ?
+ " [TCP_UDP_CHKSUM_ERR]" : "",
+ rx_ev_eth_crc_err ? " [ETH_CRC_ERR]" : "",
+ rx_ev_frm_trunc ? " [FRM_TRUNC]" : "",
+ rx_ev_drib_nib ? " [DRIB_NIB]" : "",
+ rx_ev_tobe_disc ? " [TOBE_DISC]" : "",
+ rx_ev_pause_frm ? " [PAUSE]" : "");
}
#endif
}
@@ -778,8 +793,9 @@ efx_handle_rx_bad_index(struct efx_rx_queue *rx_queue, unsigned index)
expected = rx_queue->removed_count & EFX_RXQ_MASK;
dropped = (index - expected) & EFX_RXQ_MASK;
- EFX_INFO(efx, "dropped %d events (index=%d expected=%d)\n",
- dropped, index, expected);
+ netif_info(efx, rx_err, efx->net_dev,
+ "dropped %d events (index=%d expected=%d)\n",
+ dropped, index, expected);
efx_schedule_reset(efx, EFX_WORKAROUND_5676(efx) ?
RESET_TYPE_RX_RECOVERY : RESET_TYPE_DISABLE);
@@ -850,6 +866,26 @@ efx_handle_rx_event(struct efx_channel *channel, const efx_qword_t *event)
checksummed, discard);
}
+static void
+efx_handle_generated_event(struct efx_channel *channel, efx_qword_t *event)
+{
+ struct efx_nic *efx = channel->efx;
+ unsigned code;
+
+ code = EFX_QWORD_FIELD(*event, FSF_AZ_DRV_GEN_EV_MAGIC);
+ if (code == EFX_CHANNEL_MAGIC_TEST(channel))
+ ++channel->magic_count;
+ else if (code == EFX_CHANNEL_MAGIC_FILL(channel))
+ /* The queue must be empty, so we won't receive any rx
+ * events, so efx_process_channel() won't refill the
+ * queue. Refill it here */
+ efx_fast_push_rx_descriptors(&efx->rx_queue[channel->channel]);
+ else
+ netif_dbg(efx, hw, efx->net_dev, "channel %d received "
+ "generated event "EFX_QWORD_FMT"\n",
+ channel->channel, EFX_QWORD_VAL(*event));
+}
+
/* Global events are basically PHY events */
static void
efx_handle_global_event(struct efx_channel *channel, efx_qword_t *event)
@@ -873,8 +909,9 @@ efx_handle_global_event(struct efx_channel *channel, efx_qword_t *event)
if (efx_nic_rev(efx) <= EFX_REV_FALCON_A1 ?
EFX_QWORD_FIELD(*event, FSF_AA_GLB_EV_RX_RECOVERY) :
EFX_QWORD_FIELD(*event, FSF_BB_GLB_EV_RX_RECOVERY)) {
- EFX_ERR(efx, "channel %d seen global RX_RESET "
- "event. Resetting.\n", channel->channel);
+ netif_err(efx, rx_err, efx->net_dev,
+ "channel %d seen global RX_RESET event. Resetting.\n",
+ channel->channel);
atomic_inc(&efx->rx_reset);
efx_schedule_reset(efx, EFX_WORKAROUND_6555(efx) ?
@@ -883,9 +920,10 @@ efx_handle_global_event(struct efx_channel *channel, efx_qword_t *event)
}
if (!handled)
- EFX_ERR(efx, "channel %d unknown global event "
- EFX_QWORD_FMT "\n", channel->channel,
- EFX_QWORD_VAL(*event));
+ netif_err(efx, hw, efx->net_dev,
+ "channel %d unknown global event "
+ EFX_QWORD_FMT "\n", channel->channel,
+ EFX_QWORD_VAL(*event));
}
static void
@@ -900,31 +938,35 @@ efx_handle_driver_event(struct efx_channel *channel, efx_qword_t *event)
switch (ev_sub_code) {
case FSE_AZ_TX_DESCQ_FLS_DONE_EV:
- EFX_TRACE(efx, "channel %d TXQ %d flushed\n",
- channel->channel, ev_sub_data);
+ netif_vdbg(efx, hw, efx->net_dev, "channel %d TXQ %d flushed\n",
+ channel->channel, ev_sub_data);
break;
case FSE_AZ_RX_DESCQ_FLS_DONE_EV:
- EFX_TRACE(efx, "channel %d RXQ %d flushed\n",
- channel->channel, ev_sub_data);
+ netif_vdbg(efx, hw, efx->net_dev, "channel %d RXQ %d flushed\n",
+ channel->channel, ev_sub_data);
break;
case FSE_AZ_EVQ_INIT_DONE_EV:
- EFX_LOG(efx, "channel %d EVQ %d initialised\n",
- channel->channel, ev_sub_data);
+ netif_dbg(efx, hw, efx->net_dev,
+ "channel %d EVQ %d initialised\n",
+ channel->channel, ev_sub_data);
break;
case FSE_AZ_SRM_UPD_DONE_EV:
- EFX_TRACE(efx, "channel %d SRAM update done\n",
- channel->channel);
+ netif_vdbg(efx, hw, efx->net_dev,
+ "channel %d SRAM update done\n", channel->channel);
break;
case FSE_AZ_WAKE_UP_EV:
- EFX_TRACE(efx, "channel %d RXQ %d wakeup event\n",
- channel->channel, ev_sub_data);
+ netif_vdbg(efx, hw, efx->net_dev,
+ "channel %d RXQ %d wakeup event\n",
+ channel->channel, ev_sub_data);
break;
case FSE_AZ_TIMER_EV:
- EFX_TRACE(efx, "channel %d RX queue %d timer expired\n",
- channel->channel, ev_sub_data);
+ netif_vdbg(efx, hw, efx->net_dev,
+ "channel %d RX queue %d timer expired\n",
+ channel->channel, ev_sub_data);
break;
case FSE_AA_RX_RECOVER_EV:
- EFX_ERR(efx, "channel %d seen DRIVER RX_RESET event. "
+ netif_err(efx, rx_err, efx->net_dev,
+ "channel %d seen DRIVER RX_RESET event. "
"Resetting.\n", channel->channel);
atomic_inc(&efx->rx_reset);
efx_schedule_reset(efx,
@@ -933,19 +975,22 @@ efx_handle_driver_event(struct efx_channel *channel, efx_qword_t *event)
RESET_TYPE_DISABLE);
break;
case FSE_BZ_RX_DSC_ERROR_EV:
- EFX_ERR(efx, "RX DMA Q %d reports descriptor fetch error."
- " RX Q %d is disabled.\n", ev_sub_data, ev_sub_data);
+ netif_err(efx, rx_err, efx->net_dev,
+ "RX DMA Q %d reports descriptor fetch error."
+ " RX Q %d is disabled.\n", ev_sub_data, ev_sub_data);
efx_schedule_reset(efx, RESET_TYPE_RX_DESC_FETCH);
break;
case FSE_BZ_TX_DSC_ERROR_EV:
- EFX_ERR(efx, "TX DMA Q %d reports descriptor fetch error."
- " TX Q %d is disabled.\n", ev_sub_data, ev_sub_data);
+ netif_err(efx, tx_err, efx->net_dev,
+ "TX DMA Q %d reports descriptor fetch error."
+ " TX Q %d is disabled.\n", ev_sub_data, ev_sub_data);
efx_schedule_reset(efx, RESET_TYPE_TX_DESC_FETCH);
break;
default:
- EFX_TRACE(efx, "channel %d unknown driver event code %d "
- "data %04x\n", channel->channel, ev_sub_code,
- ev_sub_data);
+ netif_vdbg(efx, hw, efx->net_dev,
+ "channel %d unknown driver event code %d "
+ "data %04x\n", channel->channel, ev_sub_code,
+ ev_sub_data);
break;
}
}
@@ -968,8 +1013,9 @@ int efx_nic_process_eventq(struct efx_channel *channel, int budget)
/* End of events */
break;
- EFX_TRACE(channel->efx, "channel %d event is "EFX_QWORD_FMT"\n",
- channel->channel, EFX_QWORD_VAL(event));
+ netif_vdbg(channel->efx, intr, channel->efx->net_dev,
+ "channel %d event is "EFX_QWORD_FMT"\n",
+ channel->channel, EFX_QWORD_VAL(event));
/* Clear this event by marking it all ones */
EFX_SET_QWORD(*p_event);
@@ -993,11 +1039,7 @@ int efx_nic_process_eventq(struct efx_channel *channel, int budget)
}
break;
case FSE_AZ_EV_CODE_DRV_GEN_EV:
- channel->eventq_magic = EFX_QWORD_FIELD(
- event, FSF_AZ_DRV_GEN_EV_MAGIC);
- EFX_LOG(channel->efx, "channel %d received generated "
- "event "EFX_QWORD_FMT"\n", channel->channel,
- EFX_QWORD_VAL(event));
+ efx_handle_generated_event(channel, &event);
break;
case FSE_AZ_EV_CODE_GLOBAL_EV:
efx_handle_global_event(channel, &event);
@@ -1009,9 +1051,10 @@ int efx_nic_process_eventq(struct efx_channel *channel, int budget)
efx_mcdi_process_event(channel, &event);
break;
default:
- EFX_ERR(channel->efx, "channel %d unknown event type %d"
- " (data " EFX_QWORD_FMT ")\n", channel->channel,
- ev_code, EFX_QWORD_VAL(event));
+ netif_err(channel->efx, hw, channel->efx->net_dev,
+ "channel %d unknown event type %d (data "
+ EFX_QWORD_FMT ")\n", channel->channel,
+ ev_code, EFX_QWORD_VAL(event));
}
}
@@ -1036,9 +1079,10 @@ void efx_nic_init_eventq(struct efx_channel *channel)
efx_oword_t reg;
struct efx_nic *efx = channel->efx;
- EFX_LOG(efx, "channel %d event queue in special buffers %d-%d\n",
- channel->channel, channel->eventq.index,
- channel->eventq.index + channel->eventq.entries - 1);
+ netif_dbg(efx, hw, efx->net_dev,
+ "channel %d event queue in special buffers %d-%d\n",
+ channel->channel, channel->eventq.index,
+ channel->eventq.index + channel->eventq.entries - 1);
if (efx_nic_rev(efx) >= EFX_REV_SIENA_A0) {
EFX_POPULATE_OWORD_3(reg,
@@ -1088,12 +1132,20 @@ void efx_nic_remove_eventq(struct efx_channel *channel)
}
-/* Generates a test event on the event queue. A subsequent call to
- * process_eventq() should pick up the event and place the value of
- * "magic" into channel->eventq_magic;
- */
-void efx_nic_generate_test_event(struct efx_channel *channel, unsigned int magic)
+void efx_nic_generate_test_event(struct efx_channel *channel)
{
+ unsigned int magic = EFX_CHANNEL_MAGIC_TEST(channel);
+ efx_qword_t test_event;
+
+ EFX_POPULATE_QWORD_2(test_event, FSF_AZ_EV_CODE,
+ FSE_AZ_EV_CODE_DRV_GEN_EV,
+ FSF_AZ_DRV_GEN_EV_MAGIC, magic);
+ efx_generate_event(channel, &test_event);
+}
+
+void efx_nic_generate_fill_event(struct efx_channel *channel)
+{
+ unsigned int magic = EFX_CHANNEL_MAGIC_FILL(channel);
efx_qword_t test_event;
EFX_POPULATE_QWORD_2(test_event, FSF_AZ_EV_CODE,
@@ -1208,20 +1260,19 @@ int efx_nic_flush_queues(struct efx_nic *efx)
* leading to a reset, or fake up success anyway */
efx_for_each_tx_queue(tx_queue, efx) {
if (tx_queue->flushed != FLUSH_DONE)
- EFX_ERR(efx, "tx queue %d flush command timed out\n",
- tx_queue->queue);
+ netif_err(efx, hw, efx->net_dev,
+ "tx queue %d flush command timed out\n",
+ tx_queue->queue);
tx_queue->flushed = FLUSH_DONE;
}
efx_for_each_rx_queue(rx_queue, efx) {
if (rx_queue->flushed != FLUSH_DONE)
- EFX_ERR(efx, "rx queue %d flush command timed out\n",
- rx_queue->queue);
+ netif_err(efx, hw, efx->net_dev,
+ "rx queue %d flush command timed out\n",
+ rx_queue->queue);
rx_queue->flushed = FLUSH_DONE;
}
- if (EFX_WORKAROUND_7803(efx))
- return 0;
-
return -ETIMEDOUT;
}
@@ -1290,10 +1341,10 @@ irqreturn_t efx_nic_fatal_interrupt(struct efx_nic *efx)
efx_reado(efx, &fatal_intr, FR_AZ_FATAL_INTR_KER);
error = EFX_OWORD_FIELD(fatal_intr, FRF_AZ_FATAL_INTR);
- EFX_ERR(efx, "SYSTEM ERROR " EFX_OWORD_FMT " status "
- EFX_OWORD_FMT ": %s\n", EFX_OWORD_VAL(*int_ker),
- EFX_OWORD_VAL(fatal_intr),
- error ? "disabling bus mastering" : "no recognised error");
+ netif_err(efx, hw, efx->net_dev, "SYSTEM ERROR "EFX_OWORD_FMT" status "
+ EFX_OWORD_FMT ": %s\n", EFX_OWORD_VAL(*int_ker),
+ EFX_OWORD_VAL(fatal_intr),
+ error ? "disabling bus mastering" : "no recognised error");
/* If this is a memory parity error dump which blocks are offending */
mem_perr = (EFX_OWORD_FIELD(fatal_intr, FRF_AZ_MEM_PERR_INT_KER) ||
@@ -1301,8 +1352,9 @@ irqreturn_t efx_nic_fatal_interrupt(struct efx_nic *efx)
if (mem_perr) {
efx_oword_t reg;
efx_reado(efx, &reg, FR_AZ_MEM_STAT);
- EFX_ERR(efx, "SYSTEM ERROR: memory parity error "
- EFX_OWORD_FMT "\n", EFX_OWORD_VAL(reg));
+ netif_err(efx, hw, efx->net_dev,
+ "SYSTEM ERROR: memory parity error "EFX_OWORD_FMT"\n",
+ EFX_OWORD_VAL(reg));
}
/* Disable both devices */
@@ -1319,11 +1371,13 @@ irqreturn_t efx_nic_fatal_interrupt(struct efx_nic *efx)
jiffies + EFX_INT_ERROR_EXPIRE * HZ;
}
if (++efx->int_error_count < EFX_MAX_INT_ERRORS) {
- EFX_ERR(efx, "SYSTEM ERROR - reset scheduled\n");
+ netif_err(efx, hw, efx->net_dev,
+ "SYSTEM ERROR - reset scheduled\n");
efx_schedule_reset(efx, RESET_TYPE_INT_ERROR);
} else {
- EFX_ERR(efx, "SYSTEM ERROR - max number of errors seen."
- "NIC will be disabled\n");
+ netif_err(efx, hw, efx->net_dev,
+ "SYSTEM ERROR - max number of errors seen."
+ "NIC will be disabled\n");
efx_schedule_reset(efx, RESET_TYPE_DISABLE);
}
@@ -1386,8 +1440,9 @@ static irqreturn_t efx_legacy_interrupt(int irq, void *dev_id)
if (result == IRQ_HANDLED) {
efx->last_irq_cpu = raw_smp_processor_id();
- EFX_TRACE(efx, "IRQ %d on CPU %d status " EFX_DWORD_FMT "\n",
- irq, raw_smp_processor_id(), EFX_DWORD_VAL(reg));
+ netif_vdbg(efx, intr, efx->net_dev,
+ "IRQ %d on CPU %d status " EFX_DWORD_FMT "\n",
+ irq, raw_smp_processor_id(), EFX_DWORD_VAL(reg));
}
return result;
@@ -1408,8 +1463,9 @@ static irqreturn_t efx_msi_interrupt(int irq, void *dev_id)
int syserr;
efx->last_irq_cpu = raw_smp_processor_id();
- EFX_TRACE(efx, "IRQ %d on CPU %d status " EFX_OWORD_FMT "\n",
- irq, raw_smp_processor_id(), EFX_OWORD_VAL(*int_ker));
+ netif_vdbg(efx, intr, efx->net_dev,
+ "IRQ %d on CPU %d status " EFX_OWORD_FMT "\n",
+ irq, raw_smp_processor_id(), EFX_OWORD_VAL(*int_ker));
/* Check to see if we have a serious error condition */
if (channel->channel == efx->fatal_irq_level) {
@@ -1428,22 +1484,21 @@ static irqreturn_t efx_msi_interrupt(int irq, void *dev_id)
/* Setup RSS indirection table.
* This maps from the hash value of the packet to RXQ
*/
-static void efx_setup_rss_indir_table(struct efx_nic *efx)
+void efx_nic_push_rx_indir_table(struct efx_nic *efx)
{
- int i = 0;
- unsigned long offset;
+ size_t i = 0;
efx_dword_t dword;
if (efx_nic_rev(efx) < EFX_REV_FALCON_B0)
return;
- for (offset = FR_BZ_RX_INDIRECTION_TBL;
- offset < FR_BZ_RX_INDIRECTION_TBL + 0x800;
- offset += 0x10) {
+ BUILD_BUG_ON(ARRAY_SIZE(efx->rx_indir_table) !=
+ FR_BZ_RX_INDIRECTION_TBL_ROWS);
+
+ for (i = 0; i < FR_BZ_RX_INDIRECTION_TBL_ROWS; i++) {
EFX_POPULATE_DWORD_1(dword, FRF_BZ_IT_QUEUE,
- i % efx->n_rx_channels);
- efx_writed(efx, &dword, offset);
- i++;
+ efx->rx_indir_table[i]);
+ efx_writed_table(efx, &dword, FR_BZ_RX_INDIRECTION_TBL, i);
}
}
@@ -1465,8 +1520,9 @@ int efx_nic_init_interrupt(struct efx_nic *efx)
rc = request_irq(efx->legacy_irq, handler, IRQF_SHARED,
efx->name, efx);
if (rc) {
- EFX_ERR(efx, "failed to hook legacy IRQ %d\n",
- efx->pci_dev->irq);
+ netif_err(efx, drv, efx->net_dev,
+ "failed to hook legacy IRQ %d\n",
+ efx->pci_dev->irq);
goto fail1;
}
return 0;
@@ -1478,7 +1534,8 @@ int efx_nic_init_interrupt(struct efx_nic *efx)
IRQF_PROBE_SHARED, /* Not shared */
channel->name, channel);
if (rc) {
- EFX_ERR(efx, "failed to hook IRQ %d\n", channel->irq);
+ netif_err(efx, drv, efx->net_dev,
+ "failed to hook IRQ %d\n", channel->irq);
goto fail2;
}
}
@@ -1576,7 +1633,7 @@ void efx_nic_init_common(struct efx_nic *efx)
EFX_INVERT_OWORD(temp);
efx_writeo(efx, &temp, FR_AZ_FATAL_INTR_KER);
- efx_setup_rss_indir_table(efx);
+ efx_nic_push_rx_indir_table(efx);
/* Disable the ugly timer-based TX DMA backoff and allow TX DMA to be
* controlled by the RX FIFO fill level. Set arbitration to one pkt/Q.
@@ -1598,3 +1655,269 @@ void efx_nic_init_common(struct efx_nic *efx)
EFX_SET_OWORD_FIELD(temp, FRF_BZ_TX_FLUSH_MIN_LEN_EN, 1);
efx_writeo(efx, &temp, FR_AZ_TX_RESERVED);
}
+
+/* Register dump */
+
+#define REGISTER_REVISION_A 1
+#define REGISTER_REVISION_B 2
+#define REGISTER_REVISION_C 3
+#define REGISTER_REVISION_Z 3 /* latest revision */
+
+struct efx_nic_reg {
+ u32 offset:24;
+ u32 min_revision:2, max_revision:2;
+};
+
+#define REGISTER(name, min_rev, max_rev) { \
+ FR_ ## min_rev ## max_rev ## _ ## name, \
+ REGISTER_REVISION_ ## min_rev, REGISTER_REVISION_ ## max_rev \
+}
+#define REGISTER_AA(name) REGISTER(name, A, A)
+#define REGISTER_AB(name) REGISTER(name, A, B)
+#define REGISTER_AZ(name) REGISTER(name, A, Z)
+#define REGISTER_BB(name) REGISTER(name, B, B)
+#define REGISTER_BZ(name) REGISTER(name, B, Z)
+#define REGISTER_CZ(name) REGISTER(name, C, Z)
+
+static const struct efx_nic_reg efx_nic_regs[] = {
+ REGISTER_AZ(ADR_REGION),
+ REGISTER_AZ(INT_EN_KER),
+ REGISTER_BZ(INT_EN_CHAR),
+ REGISTER_AZ(INT_ADR_KER),
+ REGISTER_BZ(INT_ADR_CHAR),
+ /* INT_ACK_KER is WO */
+ /* INT_ISR0 is RC */
+ REGISTER_AZ(HW_INIT),
+ REGISTER_CZ(USR_EV_CFG),
+ REGISTER_AB(EE_SPI_HCMD),
+ REGISTER_AB(EE_SPI_HADR),
+ REGISTER_AB(EE_SPI_HDATA),
+ REGISTER_AB(EE_BASE_PAGE),
+ REGISTER_AB(EE_VPD_CFG0),
+ /* EE_VPD_SW_CNTL and EE_VPD_SW_DATA are not used */
+ /* PMBX_DBG_IADDR and PBMX_DBG_IDATA are indirect */
+ /* PCIE_CORE_INDIRECT is indirect */
+ REGISTER_AB(NIC_STAT),
+ REGISTER_AB(GPIO_CTL),
+ REGISTER_AB(GLB_CTL),
+ /* FATAL_INTR_KER and FATAL_INTR_CHAR are partly RC */
+ REGISTER_BZ(DP_CTRL),
+ REGISTER_AZ(MEM_STAT),
+ REGISTER_AZ(CS_DEBUG),
+ REGISTER_AZ(ALTERA_BUILD),
+ REGISTER_AZ(CSR_SPARE),
+ REGISTER_AB(PCIE_SD_CTL0123),
+ REGISTER_AB(PCIE_SD_CTL45),
+ REGISTER_AB(PCIE_PCS_CTL_STAT),
+ /* DEBUG_DATA_OUT is not used */
+ /* DRV_EV is WO */
+ REGISTER_AZ(EVQ_CTL),
+ REGISTER_AZ(EVQ_CNT1),
+ REGISTER_AZ(EVQ_CNT2),
+ REGISTER_AZ(BUF_TBL_CFG),
+ REGISTER_AZ(SRM_RX_DC_CFG),
+ REGISTER_AZ(SRM_TX_DC_CFG),
+ REGISTER_AZ(SRM_CFG),
+ /* BUF_TBL_UPD is WO */
+ REGISTER_AZ(SRM_UPD_EVQ),
+ REGISTER_AZ(SRAM_PARITY),
+ REGISTER_AZ(RX_CFG),
+ REGISTER_BZ(RX_FILTER_CTL),
+ /* RX_FLUSH_DESCQ is WO */
+ REGISTER_AZ(RX_DC_CFG),
+ REGISTER_AZ(RX_DC_PF_WM),
+ REGISTER_BZ(RX_RSS_TKEY),
+ /* RX_NODESC_DROP is RC */
+ REGISTER_AA(RX_SELF_RST),
+ /* RX_DEBUG, RX_PUSH_DROP are not used */
+ REGISTER_CZ(RX_RSS_IPV6_REG1),
+ REGISTER_CZ(RX_RSS_IPV6_REG2),
+ REGISTER_CZ(RX_RSS_IPV6_REG3),
+ /* TX_FLUSH_DESCQ is WO */
+ REGISTER_AZ(TX_DC_CFG),
+ REGISTER_AA(TX_CHKSM_CFG),
+ REGISTER_AZ(TX_CFG),
+ /* TX_PUSH_DROP is not used */
+ REGISTER_AZ(TX_RESERVED),
+ REGISTER_BZ(TX_PACE),
+ /* TX_PACE_DROP_QID is RC */
+ REGISTER_BB(TX_VLAN),
+ REGISTER_BZ(TX_IPFIL_PORTEN),
+ REGISTER_AB(MD_TXD),
+ REGISTER_AB(MD_RXD),
+ REGISTER_AB(MD_CS),
+ REGISTER_AB(MD_PHY_ADR),
+ REGISTER_AB(MD_ID),
+ /* MD_STAT is RC */
+ REGISTER_AB(MAC_STAT_DMA),
+ REGISTER_AB(MAC_CTRL),
+ REGISTER_BB(GEN_MODE),
+ REGISTER_AB(MAC_MC_HASH_REG0),
+ REGISTER_AB(MAC_MC_HASH_REG1),
+ REGISTER_AB(GM_CFG1),
+ REGISTER_AB(GM_CFG2),
+ /* GM_IPG and GM_HD are not used */
+ REGISTER_AB(GM_MAX_FLEN),
+ /* GM_TEST is not used */
+ REGISTER_AB(GM_ADR1),
+ REGISTER_AB(GM_ADR2),
+ REGISTER_AB(GMF_CFG0),
+ REGISTER_AB(GMF_CFG1),
+ REGISTER_AB(GMF_CFG2),
+ REGISTER_AB(GMF_CFG3),
+ REGISTER_AB(GMF_CFG4),
+ REGISTER_AB(GMF_CFG5),
+ REGISTER_BB(TX_SRC_MAC_CTL),
+ REGISTER_AB(XM_ADR_LO),
+ REGISTER_AB(XM_ADR_HI),
+ REGISTER_AB(XM_GLB_CFG),
+ REGISTER_AB(XM_TX_CFG),
+ REGISTER_AB(XM_RX_CFG),
+ REGISTER_AB(XM_MGT_INT_MASK),
+ REGISTER_AB(XM_FC),
+ REGISTER_AB(XM_PAUSE_TIME),
+ REGISTER_AB(XM_TX_PARAM),
+ REGISTER_AB(XM_RX_PARAM),
+ /* XM_MGT_INT_MSK (note no 'A') is RC */
+ REGISTER_AB(XX_PWR_RST),
+ REGISTER_AB(XX_SD_CTL),
+ REGISTER_AB(XX_TXDRV_CTL),
+ /* XX_PRBS_CTL, XX_PRBS_CHK and XX_PRBS_ERR are not used */
+ /* XX_CORE_STAT is partly RC */
+};
+
+struct efx_nic_reg_table {
+ u32 offset:24;
+ u32 min_revision:2, max_revision:2;
+ u32 step:6, rows:21;
+};
+
+#define REGISTER_TABLE_DIMENSIONS(_, offset, min_rev, max_rev, step, rows) { \
+ offset, \
+ REGISTER_REVISION_ ## min_rev, REGISTER_REVISION_ ## max_rev, \
+ step, rows \
+}
+#define REGISTER_TABLE(name, min_rev, max_rev) \
+ REGISTER_TABLE_DIMENSIONS( \
+ name, FR_ ## min_rev ## max_rev ## _ ## name, \
+ min_rev, max_rev, \
+ FR_ ## min_rev ## max_rev ## _ ## name ## _STEP, \
+ FR_ ## min_rev ## max_rev ## _ ## name ## _ROWS)
+#define REGISTER_TABLE_AA(name) REGISTER_TABLE(name, A, A)
+#define REGISTER_TABLE_AZ(name) REGISTER_TABLE(name, A, Z)
+#define REGISTER_TABLE_BB(name) REGISTER_TABLE(name, B, B)
+#define REGISTER_TABLE_BZ(name) REGISTER_TABLE(name, B, Z)
+#define REGISTER_TABLE_BB_CZ(name) \
+ REGISTER_TABLE_DIMENSIONS(name, FR_BZ_ ## name, B, B, \
+ FR_BZ_ ## name ## _STEP, \
+ FR_BB_ ## name ## _ROWS), \
+ REGISTER_TABLE_DIMENSIONS(name, FR_BZ_ ## name, C, Z, \
+ FR_BZ_ ## name ## _STEP, \
+ FR_CZ_ ## name ## _ROWS)
+#define REGISTER_TABLE_CZ(name) REGISTER_TABLE(name, C, Z)
+
+static const struct efx_nic_reg_table efx_nic_reg_tables[] = {
+ /* DRIVER is not used */
+ /* EVQ_RPTR, TIMER_COMMAND, USR_EV and {RX,TX}_DESC_UPD are WO */
+ REGISTER_TABLE_BB(TX_IPFIL_TBL),
+ REGISTER_TABLE_BB(TX_SRC_MAC_TBL),
+ REGISTER_TABLE_AA(RX_DESC_PTR_TBL_KER),
+ REGISTER_TABLE_BB_CZ(RX_DESC_PTR_TBL),
+ REGISTER_TABLE_AA(TX_DESC_PTR_TBL_KER),
+ REGISTER_TABLE_BB_CZ(TX_DESC_PTR_TBL),
+ REGISTER_TABLE_AA(EVQ_PTR_TBL_KER),
+ REGISTER_TABLE_BB_CZ(EVQ_PTR_TBL),
+ /* The register buffer is allocated with slab, so we can't
+ * reasonably read all of the buffer table (up to 8MB!).
+ * However this driver will only use a few entries. Reading
+ * 1K entries allows for some expansion of queue count and
+ * size before we need to change the version. */
+ REGISTER_TABLE_DIMENSIONS(BUF_FULL_TBL_KER, FR_AA_BUF_FULL_TBL_KER,
+ A, A, 8, 1024),
+ REGISTER_TABLE_DIMENSIONS(BUF_FULL_TBL, FR_BZ_BUF_FULL_TBL,
+ B, Z, 8, 1024),
+ /* RX_FILTER_TBL{0,1} is huge and not used by this driver */
+ REGISTER_TABLE_CZ(RX_MAC_FILTER_TBL0),
+ REGISTER_TABLE_BB_CZ(TIMER_TBL),
+ REGISTER_TABLE_BB_CZ(TX_PACE_TBL),
+ REGISTER_TABLE_BZ(RX_INDIRECTION_TBL),
+ /* TX_FILTER_TBL0 is huge and not used by this driver */
+ REGISTER_TABLE_CZ(TX_MAC_FILTER_TBL0),
+ REGISTER_TABLE_CZ(MC_TREG_SMEM),
+ /* MSIX_PBA_TABLE is not mapped */
+ /* SRM_DBG is not mapped (and is redundant with BUF_FLL_TBL) */
+};
+
+size_t efx_nic_get_regs_len(struct efx_nic *efx)
+{
+ const struct efx_nic_reg *reg;
+ const struct efx_nic_reg_table *table;
+ size_t len = 0;
+
+ for (reg = efx_nic_regs;
+ reg < efx_nic_regs + ARRAY_SIZE(efx_nic_regs);
+ reg++)
+ if (efx->type->revision >= reg->min_revision &&
+ efx->type->revision <= reg->max_revision)
+ len += sizeof(efx_oword_t);
+
+ for (table = efx_nic_reg_tables;
+ table < efx_nic_reg_tables + ARRAY_SIZE(efx_nic_reg_tables);
+ table++)
+ if (efx->type->revision >= table->min_revision &&
+ efx->type->revision <= table->max_revision)
+ len += table->rows * min_t(size_t, table->step, 16);
+
+ return len;
+}
+
+void efx_nic_get_regs(struct efx_nic *efx, void *buf)
+{
+ const struct efx_nic_reg *reg;
+ const struct efx_nic_reg_table *table;
+
+ for (reg = efx_nic_regs;
+ reg < efx_nic_regs + ARRAY_SIZE(efx_nic_regs);
+ reg++) {
+ if (efx->type->revision >= reg->min_revision &&
+ efx->type->revision <= reg->max_revision) {
+ efx_reado(efx, (efx_oword_t *)buf, reg->offset);
+ buf += sizeof(efx_oword_t);
+ }
+ }
+
+ for (table = efx_nic_reg_tables;
+ table < efx_nic_reg_tables + ARRAY_SIZE(efx_nic_reg_tables);
+ table++) {
+ size_t size, i;
+
+ if (!(efx->type->revision >= table->min_revision &&
+ efx->type->revision <= table->max_revision))
+ continue;
+
+ size = min_t(size_t, table->step, 16);
+
+ for (i = 0; i < table->rows; i++) {
+ switch (table->step) {
+ case 4: /* 32-bit register or SRAM */
+ efx_readd_table(efx, buf, table->offset, i);
+ break;
+ case 8: /* 64-bit SRAM */
+ efx_sram_readq(efx,
+ efx->membase + table->offset,
+ buf, i);
+ break;
+ case 16: /* 128-bit register */
+ efx_reado_table(efx, buf, table->offset, i);
+ break;
+ case 32: /* 128-bit register, interleaved */
+ efx_reado_table(efx, buf, table->offset, 2 * i);
+ break;
+ default:
+ WARN_ON(1);
+ return;
+ }
+ buf += size;
+ }
+ }
+}
diff --git a/drivers/net/sfc/nic.h b/drivers/net/sfc/nic.h
index bbc2c0c2f84..0438dc98722 100644
--- a/drivers/net/sfc/nic.h
+++ b/drivers/net/sfc/nic.h
@@ -142,7 +142,6 @@ struct siena_nic_data {
u32 fw_build;
struct efx_mcdi_iface mcdi;
int wol_filter_id;
- u8 ipv6_rss_key[40];
};
extern void siena_print_fwver(struct efx_nic *efx, char *buf, size_t len);
@@ -190,8 +189,8 @@ extern int efx_nic_rx_xoff_thresh, efx_nic_rx_xon_thresh;
/* Interrupts and test events */
extern int efx_nic_init_interrupt(struct efx_nic *efx);
extern void efx_nic_enable_interrupts(struct efx_nic *efx);
-extern void efx_nic_generate_test_event(struct efx_channel *channel,
- unsigned int magic);
+extern void efx_nic_generate_test_event(struct efx_channel *channel);
+extern void efx_nic_generate_fill_event(struct efx_channel *channel);
extern void efx_nic_generate_interrupt(struct efx_nic *efx);
extern void efx_nic_disable_interrupts(struct efx_nic *efx);
extern void efx_nic_fini_interrupt(struct efx_nic *efx);
@@ -208,6 +207,7 @@ extern void falcon_stop_nic_stats(struct efx_nic *efx);
extern void falcon_setup_xaui(struct efx_nic *efx);
extern int falcon_reset_xaui(struct efx_nic *efx);
extern void efx_nic_init_common(struct efx_nic *efx);
+extern void efx_nic_push_rx_indir_table(struct efx_nic *efx);
int efx_nic_alloc_buffer(struct efx_nic *efx, struct efx_buffer *buffer,
unsigned int len);
@@ -222,6 +222,9 @@ extern int efx_nic_test_registers(struct efx_nic *efx,
const struct efx_nic_register_test *regs,
size_t n_regs);
+extern size_t efx_nic_get_regs_len(struct efx_nic *efx);
+extern void efx_nic_get_regs(struct efx_nic *efx, void *buf);
+
/**************************************************************************
*
* Falcon MAC stats
diff --git a/drivers/net/sfc/qt202x_phy.c b/drivers/net/sfc/qt202x_phy.c
index e077bef08a5..68813d1d85f 100644
--- a/drivers/net/sfc/qt202x_phy.c
+++ b/drivers/net/sfc/qt202x_phy.c
@@ -91,9 +91,10 @@ static int qt2025c_wait_heartbeat(struct efx_nic *efx)
if (time_after(jiffies, timeout)) {
/* Some cables have EEPROMs that conflict with the
* PHY's on-board EEPROM so it cannot load firmware */
- EFX_ERR(efx, "If an SFP+ direct attach cable is"
- " connected, please check that it complies"
- " with the SFP+ specification\n");
+ netif_err(efx, hw, efx->net_dev,
+ "If an SFP+ direct attach cable is"
+ " connected, please check that it complies"
+ " with the SFP+ specification\n");
return -ETIMEDOUT;
}
msleep(QT2025C_HEARTB_WAIT);
@@ -145,7 +146,8 @@ static int qt2025c_wait_reset(struct efx_nic *efx)
/* Bug 17689: occasionally heartbeat starts but firmware status
* code never progresses beyond 0x00. Try again, once, after
* restarting execution of the firmware image. */
- EFX_LOG(efx, "bashing QT2025C microcontroller\n");
+ netif_dbg(efx, hw, efx->net_dev,
+ "bashing QT2025C microcontroller\n");
qt2025c_restart_firmware(efx);
rc = qt2025c_wait_heartbeat(efx);
if (rc != 0)
@@ -165,11 +167,12 @@ static void qt2025c_firmware_id(struct efx_nic *efx)
for (i = 0; i < sizeof(firmware_id); i++)
firmware_id[i] = efx_mdio_read(efx, MDIO_MMD_PCS,
PCS_FW_PRODUCT_CODE_1 + i);
- EFX_INFO(efx, "QT2025C firmware %xr%d v%d.%d.%d.%d [20%02d-%02d-%02d]\n",
- (firmware_id[0] << 8) | firmware_id[1], firmware_id[2],
- firmware_id[3] >> 4, firmware_id[3] & 0xf,
- firmware_id[4], firmware_id[5],
- firmware_id[6], firmware_id[7], firmware_id[8]);
+ netif_info(efx, probe, efx->net_dev,
+ "QT2025C firmware %xr%d v%d.%d.%d.%d [20%02d-%02d-%02d]\n",
+ (firmware_id[0] << 8) | firmware_id[1], firmware_id[2],
+ firmware_id[3] >> 4, firmware_id[3] & 0xf,
+ firmware_id[4], firmware_id[5],
+ firmware_id[6], firmware_id[7], firmware_id[8]);
phy_data->firmware_ver = ((firmware_id[3] & 0xf0) << 20) |
((firmware_id[3] & 0x0f) << 16) |
(firmware_id[4] << 8) | firmware_id[5];
@@ -198,7 +201,7 @@ static void qt2025c_bug17190_workaround(struct efx_nic *efx)
}
if (time_after_eq(jiffies, phy_data->bug17190_timer)) {
- EFX_LOG(efx, "bashing QT2025C PMA/PMD\n");
+ netif_dbg(efx, hw, efx->net_dev, "bashing QT2025C PMA/PMD\n");
efx_mdio_set_flag(efx, MDIO_MMD_PMAPMD, MDIO_CTRL1,
MDIO_PMA_CTRL1_LOOPBACK, true);
msleep(100);
@@ -231,7 +234,8 @@ static int qt2025c_select_phy_mode(struct efx_nic *efx)
reg = efx_mdio_read(efx, 1, 0xc319);
if ((reg & 0x0038) == phy_op_mode)
return 0;
- EFX_LOG(efx, "Switching PHY to mode 0x%04x\n", phy_op_mode);
+ netif_dbg(efx, hw, efx->net_dev, "Switching PHY to mode 0x%04x\n",
+ phy_op_mode);
/* This sequence replicates the register writes configured in the boot
* EEPROM (including the differences between board revisions), except
@@ -287,8 +291,9 @@ static int qt2025c_select_phy_mode(struct efx_nic *efx)
/* Wait for the microcontroller to be ready again */
rc = qt2025c_wait_reset(efx);
if (rc < 0) {
- EFX_ERR(efx, "PHY microcontroller reset during mode switch "
- "timed out\n");
+ netif_err(efx, hw, efx->net_dev,
+ "PHY microcontroller reset during mode switch "
+ "timed out\n");
return rc;
}
@@ -324,7 +329,7 @@ static int qt202x_reset_phy(struct efx_nic *efx)
return 0;
fail:
- EFX_ERR(efx, "PHY reset timed out\n");
+ netif_err(efx, hw, efx->net_dev, "PHY reset timed out\n");
return rc;
}
@@ -353,14 +358,15 @@ static int qt202x_phy_init(struct efx_nic *efx)
rc = qt202x_reset_phy(efx);
if (rc) {
- EFX_ERR(efx, "PHY init failed\n");
+ netif_err(efx, probe, efx->net_dev, "PHY init failed\n");
return rc;
}
devid = efx_mdio_read_id(efx, MDIO_MMD_PHYXS);
- EFX_INFO(efx, "PHY ID reg %x (OUI %06x model %02x revision %x)\n",
- devid, efx_mdio_id_oui(devid), efx_mdio_id_model(devid),
- efx_mdio_id_rev(devid));
+ netif_info(efx, probe, efx->net_dev,
+ "PHY ID reg %x (OUI %06x model %02x revision %x)\n",
+ devid, efx_mdio_id_oui(devid), efx_mdio_id_model(devid),
+ efx_mdio_id_rev(devid));
if (efx->phy_type == PHY_TYPE_QT2025C)
qt2025c_firmware_id(efx);
diff --git a/drivers/net/sfc/rx.c b/drivers/net/sfc/rx.c
index e308818b9f5..799c461ce7b 100644
--- a/drivers/net/sfc/rx.c
+++ b/drivers/net/sfc/rx.c
@@ -25,6 +25,9 @@
/* Number of RX descriptors pushed at once. */
#define EFX_RX_BATCH 8
+/* Maximum size of a buffer sharing a page */
+#define EFX_RX_HALF_PAGE ((PAGE_SIZE >> 1) - sizeof(struct efx_rx_page_state))
+
/* Size of buffer allocated for skb header area. */
#define EFX_SKB_HEADERS 64u
@@ -98,155 +101,151 @@ static inline unsigned int efx_rx_buf_size(struct efx_nic *efx)
return PAGE_SIZE << efx->rx_buffer_order;
}
+static inline u32 efx_rx_buf_hash(struct efx_rx_buffer *buf)
+{
+#if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) || NET_IP_ALIGN % 4 == 0
+ return __le32_to_cpup((const __le32 *)(buf->data - 4));
+#else
+ const u8 *data = (const u8 *)(buf->data - 4);
+ return ((u32)data[0] |
+ (u32)data[1] << 8 |
+ (u32)data[2] << 16 |
+ (u32)data[3] << 24);
+#endif
+}
/**
- * efx_init_rx_buffer_skb - create new RX buffer using skb-based allocation
+ * efx_init_rx_buffers_skb - create EFX_RX_BATCH skb-based RX buffers
*
* @rx_queue: Efx RX queue
- * @rx_buf: RX buffer structure to populate
*
- * This allocates memory for a new receive buffer, maps it for DMA,
- * and populates a struct efx_rx_buffer with the relevant
- * information. Return a negative error code or 0 on success.
+ * This allocates EFX_RX_BATCH skbs, maps them for DMA, and populates a
+ * struct efx_rx_buffer for each one. Return a negative error code or 0
+ * on success. May fail having only inserted fewer than EFX_RX_BATCH
+ * buffers.
*/
-static int efx_init_rx_buffer_skb(struct efx_rx_queue *rx_queue,
- struct efx_rx_buffer *rx_buf)
+static int efx_init_rx_buffers_skb(struct efx_rx_queue *rx_queue)
{
struct efx_nic *efx = rx_queue->efx;
struct net_device *net_dev = efx->net_dev;
+ struct efx_rx_buffer *rx_buf;
int skb_len = efx->rx_buffer_len;
+ unsigned index, count;
- rx_buf->skb = netdev_alloc_skb(net_dev, skb_len);
- if (unlikely(!rx_buf->skb))
- return -ENOMEM;
+ for (count = 0; count < EFX_RX_BATCH; ++count) {
+ index = rx_queue->added_count & EFX_RXQ_MASK;
+ rx_buf = efx_rx_buffer(rx_queue, index);
- /* Adjust the SKB for padding and checksum */
- skb_reserve(rx_buf->skb, NET_IP_ALIGN);
- rx_buf->len = skb_len - NET_IP_ALIGN;
- rx_buf->data = (char *)rx_buf->skb->data;
- rx_buf->skb->ip_summed = CHECKSUM_UNNECESSARY;
+ rx_buf->skb = netdev_alloc_skb(net_dev, skb_len);
+ if (unlikely(!rx_buf->skb))
+ return -ENOMEM;
+ rx_buf->page = NULL;
- rx_buf->dma_addr = pci_map_single(efx->pci_dev,
- rx_buf->data, rx_buf->len,
- PCI_DMA_FROMDEVICE);
+ /* Adjust the SKB for padding and checksum */
+ skb_reserve(rx_buf->skb, NET_IP_ALIGN);
+ rx_buf->len = skb_len - NET_IP_ALIGN;
+ rx_buf->data = (char *)rx_buf->skb->data;
+ rx_buf->skb->ip_summed = CHECKSUM_UNNECESSARY;
+
+ rx_buf->dma_addr = pci_map_single(efx->pci_dev,
+ rx_buf->data, rx_buf->len,
+ PCI_DMA_FROMDEVICE);
+ if (unlikely(pci_dma_mapping_error(efx->pci_dev,
+ rx_buf->dma_addr))) {
+ dev_kfree_skb_any(rx_buf->skb);
+ rx_buf->skb = NULL;
+ return -EIO;
+ }
- if (unlikely(pci_dma_mapping_error(efx->pci_dev, rx_buf->dma_addr))) {
- dev_kfree_skb_any(rx_buf->skb);
- rx_buf->skb = NULL;
- return -EIO;
+ ++rx_queue->added_count;
+ ++rx_queue->alloc_skb_count;
}
return 0;
}
/**
- * efx_init_rx_buffer_page - create new RX buffer using page-based allocation
+ * efx_init_rx_buffers_page - create EFX_RX_BATCH page-based RX buffers
*
* @rx_queue: Efx RX queue
- * @rx_buf: RX buffer structure to populate
*
- * This allocates memory for a new receive buffer, maps it for DMA,
- * and populates a struct efx_rx_buffer with the relevant
- * information. Return a negative error code or 0 on success.
+ * This allocates memory for EFX_RX_BATCH receive buffers, maps them for DMA,
+ * and populates struct efx_rx_buffers for each one. Return a negative error
+ * code or 0 on success. If a single page can be split between two buffers,
+ * then the page will either be inserted fully, or not at at all.
*/
-static int efx_init_rx_buffer_page(struct efx_rx_queue *rx_queue,
- struct efx_rx_buffer *rx_buf)
+static int efx_init_rx_buffers_page(struct efx_rx_queue *rx_queue)
{
struct efx_nic *efx = rx_queue->efx;
- int bytes, space, offset;
-
- bytes = efx->rx_buffer_len - EFX_PAGE_IP_ALIGN;
-
- /* If there is space left in the previously allocated page,
- * then use it. Otherwise allocate a new one */
- rx_buf->page = rx_queue->buf_page;
- if (rx_buf->page == NULL) {
- dma_addr_t dma_addr;
-
- rx_buf->page = alloc_pages(__GFP_COLD | __GFP_COMP | GFP_ATOMIC,
- efx->rx_buffer_order);
- if (unlikely(rx_buf->page == NULL))
+ struct efx_rx_buffer *rx_buf;
+ struct page *page;
+ void *page_addr;
+ struct efx_rx_page_state *state;
+ dma_addr_t dma_addr;
+ unsigned index, count;
+
+ /* We can split a page between two buffers */
+ BUILD_BUG_ON(EFX_RX_BATCH & 1);
+
+ for (count = 0; count < EFX_RX_BATCH; ++count) {
+ page = alloc_pages(__GFP_COLD | __GFP_COMP | GFP_ATOMIC,
+ efx->rx_buffer_order);
+ if (unlikely(page == NULL))
return -ENOMEM;
-
- dma_addr = pci_map_page(efx->pci_dev, rx_buf->page,
- 0, efx_rx_buf_size(efx),
+ dma_addr = pci_map_page(efx->pci_dev, page, 0,
+ efx_rx_buf_size(efx),
PCI_DMA_FROMDEVICE);
-
if (unlikely(pci_dma_mapping_error(efx->pci_dev, dma_addr))) {
- __free_pages(rx_buf->page, efx->rx_buffer_order);
- rx_buf->page = NULL;
+ __free_pages(page, efx->rx_buffer_order);
return -EIO;
}
-
- rx_queue->buf_page = rx_buf->page;
- rx_queue->buf_dma_addr = dma_addr;
- rx_queue->buf_data = (page_address(rx_buf->page) +
- EFX_PAGE_IP_ALIGN);
- }
-
- rx_buf->len = bytes;
- rx_buf->data = rx_queue->buf_data;
- offset = efx_rx_buf_offset(rx_buf);
- rx_buf->dma_addr = rx_queue->buf_dma_addr + offset;
-
- /* Try to pack multiple buffers per page */
- if (efx->rx_buffer_order == 0) {
- /* The next buffer starts on the next 512 byte boundary */
- rx_queue->buf_data += ((bytes + 0x1ff) & ~0x1ff);
- offset += ((bytes + 0x1ff) & ~0x1ff);
-
- space = efx_rx_buf_size(efx) - offset;
- if (space >= bytes) {
- /* Refs dropped on kernel releasing each skb */
- get_page(rx_queue->buf_page);
- goto out;
+ page_addr = page_address(page);
+ state = page_addr;
+ state->refcnt = 0;
+ state->dma_addr = dma_addr;
+
+ page_addr += sizeof(struct efx_rx_page_state);
+ dma_addr += sizeof(struct efx_rx_page_state);
+
+ split:
+ index = rx_queue->added_count & EFX_RXQ_MASK;
+ rx_buf = efx_rx_buffer(rx_queue, index);
+ rx_buf->dma_addr = dma_addr + EFX_PAGE_IP_ALIGN;
+ rx_buf->skb = NULL;
+ rx_buf->page = page;
+ rx_buf->data = page_addr + EFX_PAGE_IP_ALIGN;
+ rx_buf->len = efx->rx_buffer_len - EFX_PAGE_IP_ALIGN;
+ ++rx_queue->added_count;
+ ++rx_queue->alloc_page_count;
+ ++state->refcnt;
+
+ if ((~count & 1) && (efx->rx_buffer_len <= EFX_RX_HALF_PAGE)) {
+ /* Use the second half of the page */
+ get_page(page);
+ dma_addr += (PAGE_SIZE >> 1);
+ page_addr += (PAGE_SIZE >> 1);
+ ++count;
+ goto split;
}
}
- /* This is the final RX buffer for this page, so mark it for
- * unmapping */
- rx_queue->buf_page = NULL;
- rx_buf->unmap_addr = rx_queue->buf_dma_addr;
-
- out:
return 0;
}
-/* This allocates memory for a new receive buffer, maps it for DMA,
- * and populates a struct efx_rx_buffer with the relevant
- * information.
- */
-static int efx_init_rx_buffer(struct efx_rx_queue *rx_queue,
- struct efx_rx_buffer *new_rx_buf)
-{
- int rc = 0;
-
- if (rx_queue->channel->rx_alloc_push_pages) {
- new_rx_buf->skb = NULL;
- rc = efx_init_rx_buffer_page(rx_queue, new_rx_buf);
- rx_queue->alloc_page_count++;
- } else {
- new_rx_buf->page = NULL;
- rc = efx_init_rx_buffer_skb(rx_queue, new_rx_buf);
- rx_queue->alloc_skb_count++;
- }
-
- if (unlikely(rc < 0))
- EFX_LOG_RL(rx_queue->efx, "%s RXQ[%d] =%d\n", __func__,
- rx_queue->queue, rc);
- return rc;
-}
-
static void efx_unmap_rx_buffer(struct efx_nic *efx,
struct efx_rx_buffer *rx_buf)
{
if (rx_buf->page) {
+ struct efx_rx_page_state *state;
+
EFX_BUG_ON_PARANOID(rx_buf->skb);
- if (rx_buf->unmap_addr) {
- pci_unmap_page(efx->pci_dev, rx_buf->unmap_addr,
+
+ state = page_address(rx_buf->page);
+ if (--state->refcnt == 0) {
+ pci_unmap_page(efx->pci_dev,
+ state->dma_addr,
efx_rx_buf_size(efx),
PCI_DMA_FROMDEVICE);
- rx_buf->unmap_addr = 0;
}
} else if (likely(rx_buf->skb)) {
pci_unmap_single(efx->pci_dev, rx_buf->dma_addr,
@@ -273,31 +272,84 @@ static void efx_fini_rx_buffer(struct efx_rx_queue *rx_queue,
efx_free_rx_buffer(rx_queue->efx, rx_buf);
}
+/* Attempt to resurrect the other receive buffer that used to share this page,
+ * which had previously been passed up to the kernel and freed. */
+static void efx_resurrect_rx_buffer(struct efx_rx_queue *rx_queue,
+ struct efx_rx_buffer *rx_buf)
+{
+ struct efx_rx_page_state *state = page_address(rx_buf->page);
+ struct efx_rx_buffer *new_buf;
+ unsigned fill_level, index;
+
+ /* +1 because efx_rx_packet() incremented removed_count. +1 because
+ * we'd like to insert an additional descriptor whilst leaving
+ * EFX_RXD_HEAD_ROOM for the non-recycle path */
+ fill_level = (rx_queue->added_count - rx_queue->removed_count + 2);
+ if (unlikely(fill_level >= EFX_RXQ_SIZE - EFX_RXD_HEAD_ROOM)) {
+ /* We could place "state" on a list, and drain the list in
+ * efx_fast_push_rx_descriptors(). For now, this will do. */
+ return;
+ }
+
+ ++state->refcnt;
+ get_page(rx_buf->page);
+
+ index = rx_queue->added_count & EFX_RXQ_MASK;
+ new_buf = efx_rx_buffer(rx_queue, index);
+ new_buf->dma_addr = rx_buf->dma_addr ^ (PAGE_SIZE >> 1);
+ new_buf->skb = NULL;
+ new_buf->page = rx_buf->page;
+ new_buf->data = (void *)
+ ((__force unsigned long)rx_buf->data ^ (PAGE_SIZE >> 1));
+ new_buf->len = rx_buf->len;
+ ++rx_queue->added_count;
+}
+
+/* Recycle the given rx buffer directly back into the rx_queue. There is
+ * always room to add this buffer, because we've just popped a buffer. */
+static void efx_recycle_rx_buffer(struct efx_channel *channel,
+ struct efx_rx_buffer *rx_buf)
+{
+ struct efx_nic *efx = channel->efx;
+ struct efx_rx_queue *rx_queue = &efx->rx_queue[channel->channel];
+ struct efx_rx_buffer *new_buf;
+ unsigned index;
+
+ if (rx_buf->page != NULL && efx->rx_buffer_len <= EFX_RX_HALF_PAGE &&
+ page_count(rx_buf->page) == 1)
+ efx_resurrect_rx_buffer(rx_queue, rx_buf);
+
+ index = rx_queue->added_count & EFX_RXQ_MASK;
+ new_buf = efx_rx_buffer(rx_queue, index);
+
+ memcpy(new_buf, rx_buf, sizeof(*new_buf));
+ rx_buf->page = NULL;
+ rx_buf->skb = NULL;
+ ++rx_queue->added_count;
+}
+
/**
* efx_fast_push_rx_descriptors - push new RX descriptors quickly
* @rx_queue: RX descriptor queue
- * @retry: Recheck the fill level
* This will aim to fill the RX descriptor queue up to
* @rx_queue->@fast_fill_limit. If there is insufficient atomic
- * memory to do so, the caller should retry.
+ * memory to do so, a slow fill will be scheduled.
+ *
+ * The caller must provide serialisation (none is used here). In practise,
+ * this means this function must run from the NAPI handler, or be called
+ * when NAPI is disabled.
*/
-static int __efx_fast_push_rx_descriptors(struct efx_rx_queue *rx_queue,
- int retry)
+void efx_fast_push_rx_descriptors(struct efx_rx_queue *rx_queue)
{
- struct efx_rx_buffer *rx_buf;
- unsigned fill_level, index;
- int i, space, rc = 0;
+ struct efx_channel *channel = rx_queue->channel;
+ unsigned fill_level;
+ int space, rc = 0;
- /* Calculate current fill level. Do this outside the lock,
- * because most of the time we'll end up not wanting to do the
- * fill anyway.
- */
+ /* Calculate current fill level, and exit if we don't need to fill */
fill_level = (rx_queue->added_count - rx_queue->removed_count);
EFX_BUG_ON_PARANOID(fill_level > EFX_RXQ_SIZE);
-
- /* Don't fill if we don't need to */
if (fill_level >= rx_queue->fast_fill_trigger)
- return 0;
+ goto out;
/* Record minimum fill level */
if (unlikely(fill_level < rx_queue->min_fill)) {
@@ -305,99 +357,47 @@ static int __efx_fast_push_rx_descriptors(struct efx_rx_queue *rx_queue,
rx_queue->min_fill = fill_level;
}
- /* Acquire RX add lock. If this lock is contended, then a fast
- * fill must already be in progress (e.g. in the refill
- * tasklet), so we don't need to do anything
- */
- if (!spin_trylock_bh(&rx_queue->add_lock))
- return -1;
-
- retry:
- /* Recalculate current fill level now that we have the lock */
- fill_level = (rx_queue->added_count - rx_queue->removed_count);
- EFX_BUG_ON_PARANOID(fill_level > EFX_RXQ_SIZE);
space = rx_queue->fast_fill_limit - fill_level;
if (space < EFX_RX_BATCH)
- goto out_unlock;
+ goto out;
- EFX_TRACE(rx_queue->efx, "RX queue %d fast-filling descriptor ring from"
- " level %d to level %d using %s allocation\n",
- rx_queue->queue, fill_level, rx_queue->fast_fill_limit,
- rx_queue->channel->rx_alloc_push_pages ? "page" : "skb");
+ netif_vdbg(rx_queue->efx, rx_status, rx_queue->efx->net_dev,
+ "RX queue %d fast-filling descriptor ring from"
+ " level %d to level %d using %s allocation\n",
+ rx_queue->queue, fill_level, rx_queue->fast_fill_limit,
+ channel->rx_alloc_push_pages ? "page" : "skb");
do {
- for (i = 0; i < EFX_RX_BATCH; ++i) {
- index = rx_queue->added_count & EFX_RXQ_MASK;
- rx_buf = efx_rx_buffer(rx_queue, index);
- rc = efx_init_rx_buffer(rx_queue, rx_buf);
- if (unlikely(rc))
- goto out;
- ++rx_queue->added_count;
+ if (channel->rx_alloc_push_pages)
+ rc = efx_init_rx_buffers_page(rx_queue);
+ else
+ rc = efx_init_rx_buffers_skb(rx_queue);
+ if (unlikely(rc)) {
+ /* Ensure that we don't leave the rx queue empty */
+ if (rx_queue->added_count == rx_queue->removed_count)
+ efx_schedule_slow_fill(rx_queue);
+ goto out;
}
} while ((space -= EFX_RX_BATCH) >= EFX_RX_BATCH);
- EFX_TRACE(rx_queue->efx, "RX queue %d fast-filled descriptor ring "
- "to level %d\n", rx_queue->queue,
- rx_queue->added_count - rx_queue->removed_count);
+ netif_vdbg(rx_queue->efx, rx_status, rx_queue->efx->net_dev,
+ "RX queue %d fast-filled descriptor ring "
+ "to level %d\n", rx_queue->queue,
+ rx_queue->added_count - rx_queue->removed_count);
out:
- /* Send write pointer to card. */
- efx_nic_notify_rx_desc(rx_queue);
-
- /* If the fast fill is running inside from the refill tasklet, then
- * for SMP systems it may be running on a different CPU to
- * RX event processing, which means that the fill level may now be
- * out of date. */
- if (unlikely(retry && (rc == 0)))
- goto retry;
-
- out_unlock:
- spin_unlock_bh(&rx_queue->add_lock);
-
- return rc;
-}
-
-/**
- * efx_fast_push_rx_descriptors - push new RX descriptors quickly
- * @rx_queue: RX descriptor queue
- *
- * This will aim to fill the RX descriptor queue up to
- * @rx_queue->@fast_fill_limit. If there is insufficient memory to do so,
- * it will schedule a work item to immediately continue the fast fill
- */
-void efx_fast_push_rx_descriptors(struct efx_rx_queue *rx_queue)
-{
- int rc;
-
- rc = __efx_fast_push_rx_descriptors(rx_queue, 0);
- if (unlikely(rc)) {
- /* Schedule the work item to run immediately. The hope is
- * that work is immediately pending to free some memory
- * (e.g. an RX event or TX completion)
- */
- efx_schedule_slow_fill(rx_queue, 0);
- }
+ if (rx_queue->notified_count != rx_queue->added_count)
+ efx_nic_notify_rx_desc(rx_queue);
}
-void efx_rx_work(struct work_struct *data)
+void efx_rx_slow_fill(unsigned long context)
{
- struct efx_rx_queue *rx_queue;
- int rc;
-
- rx_queue = container_of(data, struct efx_rx_queue, work.work);
-
- if (unlikely(!rx_queue->channel->enabled))
- return;
-
- EFX_TRACE(rx_queue->efx, "RX queue %d worker thread executing on CPU "
- "%d\n", rx_queue->queue, raw_smp_processor_id());
+ struct efx_rx_queue *rx_queue = (struct efx_rx_queue *)context;
+ struct efx_channel *channel = rx_queue->channel;
+ /* Post an event to cause NAPI to run and refill the queue */
+ efx_nic_generate_fill_event(channel);
++rx_queue->slow_fill_count;
- /* Push new RX descriptors, allowing at least 1 jiffy for
- * the kernel to free some more memory. */
- rc = __efx_fast_push_rx_descriptors(rx_queue, 1);
- if (rc)
- efx_schedule_slow_fill(rx_queue, 1);
}
static void efx_rx_packet__check_len(struct efx_rx_queue *rx_queue,
@@ -417,10 +417,12 @@ static void efx_rx_packet__check_len(struct efx_rx_queue *rx_queue,
*discard = true;
if ((len > rx_buf->len) && EFX_WORKAROUND_8071(efx)) {
- EFX_ERR_RL(efx, " RX queue %d seriously overlength "
- "RX event (0x%x > 0x%x+0x%x). Leaking\n",
- rx_queue->queue, len, max_len,
- efx->type->rx_buffer_padding);
+ if (net_ratelimit())
+ netif_err(efx, rx_err, efx->net_dev,
+ " RX queue %d seriously overlength "
+ "RX event (0x%x > 0x%x+0x%x). Leaking\n",
+ rx_queue->queue, len, max_len,
+ efx->type->rx_buffer_padding);
/* If this buffer was skb-allocated, then the meta
* data at the end of the skb will be trashed. So
* we have no choice but to leak the fragment.
@@ -428,8 +430,11 @@ static void efx_rx_packet__check_len(struct efx_rx_queue *rx_queue,
*leak_packet = (rx_buf->skb != NULL);
efx_schedule_reset(efx, RESET_TYPE_RX_RECOVERY);
} else {
- EFX_ERR_RL(efx, " RX queue %d overlength RX event "
- "(0x%x > 0x%x)\n", rx_queue->queue, len, max_len);
+ if (net_ratelimit())
+ netif_err(efx, rx_err, efx->net_dev,
+ " RX queue %d overlength RX event "
+ "(0x%x > 0x%x)\n",
+ rx_queue->queue, len, max_len);
}
rx_queue->channel->n_rx_overlength++;
@@ -449,6 +454,7 @@ static void efx_rx_packet_lro(struct efx_channel *channel,
/* Pass the skb/page into the LRO engine */
if (rx_buf->page) {
+ struct efx_nic *efx = channel->efx;
struct page *page = rx_buf->page;
struct sk_buff *skb;
@@ -461,6 +467,9 @@ static void efx_rx_packet_lro(struct efx_channel *channel,
return;
}
+ if (efx->net_dev->features & NETIF_F_RXHASH)
+ skb->rxhash = efx_rx_buf_hash(rx_buf);
+
skb_shinfo(skb)->frags[0].page = page;
skb_shinfo(skb)->frags[0].page_offset =
efx_rx_buf_offset(rx_buf);
@@ -498,6 +507,7 @@ void efx_rx_packet(struct efx_rx_queue *rx_queue, unsigned int index,
unsigned int len, bool checksummed, bool discard)
{
struct efx_nic *efx = rx_queue->efx;
+ struct efx_channel *channel = rx_queue->channel;
struct efx_rx_buffer *rx_buf;
bool leak_packet = false;
@@ -516,21 +526,23 @@ void efx_rx_packet(struct efx_rx_queue *rx_queue, unsigned int index,
efx_rx_packet__check_len(rx_queue, rx_buf, len,
&discard, &leak_packet);
- EFX_TRACE(efx, "RX queue %d received id %x at %llx+%x %s%s\n",
- rx_queue->queue, index,
- (unsigned long long)rx_buf->dma_addr, len,
- (checksummed ? " [SUMMED]" : ""),
- (discard ? " [DISCARD]" : ""));
+ netif_vdbg(efx, rx_status, efx->net_dev,
+ "RX queue %d received id %x at %llx+%x %s%s\n",
+ rx_queue->queue, index,
+ (unsigned long long)rx_buf->dma_addr, len,
+ (checksummed ? " [SUMMED]" : ""),
+ (discard ? " [DISCARD]" : ""));
/* Discard packet, if instructed to do so */
if (unlikely(discard)) {
if (unlikely(leak_packet))
- rx_queue->channel->n_skbuff_leaks++;
+ channel->n_skbuff_leaks++;
else
- /* We haven't called efx_unmap_rx_buffer yet,
- * so fini the entire rx_buffer here */
- efx_fini_rx_buffer(rx_queue, rx_buf);
- return;
+ efx_recycle_rx_buffer(channel, rx_buf);
+
+ /* Don't hold off the previous receive */
+ rx_buf = NULL;
+ goto out;
}
/* Release card resources - assumes all RX buffers consumed in-order
@@ -547,6 +559,7 @@ void efx_rx_packet(struct efx_rx_queue *rx_queue, unsigned int index,
* prefetched into cache.
*/
rx_buf->len = len;
+out:
if (rx_queue->channel->rx_pkt)
__efx_rx_packet(rx_queue->channel,
rx_queue->channel->rx_pkt,
@@ -562,6 +575,9 @@ void __efx_rx_packet(struct efx_channel *channel,
struct efx_nic *efx = channel->efx;
struct sk_buff *skb;
+ rx_buf->data += efx->type->rx_buffer_hash_size;
+ rx_buf->len -= efx->type->rx_buffer_hash_size;
+
/* If we're in loopback test, then pass the packet directly to the
* loopback layer, and free the rx_buf here
*/
@@ -574,8 +590,12 @@ void __efx_rx_packet(struct efx_channel *channel,
if (rx_buf->skb) {
prefetch(skb_shinfo(rx_buf->skb));
+ skb_reserve(rx_buf->skb, efx->type->rx_buffer_hash_size);
skb_put(rx_buf->skb, rx_buf->len);
+ if (efx->net_dev->features & NETIF_F_RXHASH)
+ rx_buf->skb->rxhash = efx_rx_buf_hash(rx_buf);
+
/* Move past the ethernet header. rx_buf->data still points
* at the ethernet header */
rx_buf->skb->protocol = eth_type_trans(rx_buf->skb,
@@ -633,7 +653,8 @@ int efx_probe_rx_queue(struct efx_rx_queue *rx_queue)
unsigned int rxq_size;
int rc;
- EFX_LOG(efx, "creating RX queue %d\n", rx_queue->queue);
+ netif_dbg(efx, probe, efx->net_dev,
+ "creating RX queue %d\n", rx_queue->queue);
/* Allocate RX buffers */
rxq_size = EFX_RXQ_SIZE * sizeof(*rx_queue->buffer);
@@ -653,7 +674,8 @@ void efx_init_rx_queue(struct efx_rx_queue *rx_queue)
{
unsigned int max_fill, trigger, limit;
- EFX_LOG(rx_queue->efx, "initialising RX queue %d\n", rx_queue->queue);
+ netif_dbg(rx_queue->efx, drv, rx_queue->efx->net_dev,
+ "initialising RX queue %d\n", rx_queue->queue);
/* Initialise ptr fields */
rx_queue->added_count = 0;
@@ -680,8 +702,10 @@ void efx_fini_rx_queue(struct efx_rx_queue *rx_queue)
int i;
struct efx_rx_buffer *rx_buf;
- EFX_LOG(rx_queue->efx, "shutting down RX queue %d\n", rx_queue->queue);
+ netif_dbg(rx_queue->efx, drv, rx_queue->efx->net_dev,
+ "shutting down RX queue %d\n", rx_queue->queue);
+ del_timer_sync(&rx_queue->slow_fill);
efx_nic_fini_rx(rx_queue);
/* Release RX buffers NB start at index 0 not current HW ptr */
@@ -691,21 +715,12 @@ void efx_fini_rx_queue(struct efx_rx_queue *rx_queue)
efx_fini_rx_buffer(rx_queue, rx_buf);
}
}
-
- /* For a page that is part-way through splitting into RX buffers */
- if (rx_queue->buf_page != NULL) {
- pci_unmap_page(rx_queue->efx->pci_dev, rx_queue->buf_dma_addr,
- efx_rx_buf_size(rx_queue->efx),
- PCI_DMA_FROMDEVICE);
- __free_pages(rx_queue->buf_page,
- rx_queue->efx->rx_buffer_order);
- rx_queue->buf_page = NULL;
- }
}
void efx_remove_rx_queue(struct efx_rx_queue *rx_queue)
{
- EFX_LOG(rx_queue->efx, "destroying RX queue %d\n", rx_queue->queue);
+ netif_dbg(rx_queue->efx, drv, rx_queue->efx->net_dev,
+ "destroying RX queue %d\n", rx_queue->queue);
efx_nic_remove_rx(rx_queue);
diff --git a/drivers/net/sfc/selftest.c b/drivers/net/sfc/selftest.c
index 371e86cc090..85f015f005d 100644
--- a/drivers/net/sfc/selftest.c
+++ b/drivers/net/sfc/selftest.c
@@ -38,7 +38,7 @@ struct efx_loopback_payload {
struct udphdr udp;
__be16 iteration;
const char msg[64];
-} __attribute__ ((packed));
+} __packed;
/* Loopback test source MAC address */
static const unsigned char payload_source[ETH_ALEN] = {
@@ -123,7 +123,7 @@ static int efx_test_interrupts(struct efx_nic *efx,
{
struct efx_channel *channel;
- EFX_LOG(efx, "testing interrupts\n");
+ netif_dbg(efx, drv, efx->net_dev, "testing interrupts\n");
tests->interrupt = -1;
/* Reset interrupt flag */
@@ -142,16 +142,17 @@ static int efx_test_interrupts(struct efx_nic *efx,
efx_nic_generate_interrupt(efx);
/* Wait for arrival of test interrupt. */
- EFX_LOG(efx, "waiting for test interrupt\n");
+ netif_dbg(efx, drv, efx->net_dev, "waiting for test interrupt\n");
schedule_timeout_uninterruptible(HZ / 10);
if (efx->last_irq_cpu >= 0)
goto success;
- EFX_ERR(efx, "timed out waiting for interrupt\n");
+ netif_err(efx, drv, efx->net_dev, "timed out waiting for interrupt\n");
return -ETIMEDOUT;
success:
- EFX_LOG(efx, "%s test interrupt seen on CPU%d\n", INT_MODE(efx),
+ netif_dbg(efx, drv, efx->net_dev, "%s test interrupt seen on CPU%d\n",
+ INT_MODE(efx),
efx->last_irq_cpu);
tests->interrupt = 1;
return 0;
@@ -161,23 +162,18 @@ static int efx_test_interrupts(struct efx_nic *efx,
static int efx_test_eventq_irq(struct efx_channel *channel,
struct efx_self_tests *tests)
{
- unsigned int magic, count;
-
- /* Channel specific code, limited to 20 bits */
- magic = (0x00010150 + channel->channel);
- EFX_LOG(channel->efx, "channel %d testing event queue with code %x\n",
- channel->channel, magic);
+ struct efx_nic *efx = channel->efx;
+ unsigned int magic_count, count;
tests->eventq_dma[channel->channel] = -1;
tests->eventq_int[channel->channel] = -1;
tests->eventq_poll[channel->channel] = -1;
- /* Reset flag and zero magic word */
+ magic_count = channel->magic_count;
channel->efx->last_irq_cpu = -1;
- channel->eventq_magic = 0;
smp_wmb();
- efx_nic_generate_test_event(channel, magic);
+ efx_nic_generate_test_event(channel);
/* Wait for arrival of interrupt */
count = 0;
@@ -187,33 +183,36 @@ static int efx_test_eventq_irq(struct efx_channel *channel,
if (channel->work_pending)
efx_process_channel_now(channel);
- if (channel->eventq_magic == magic)
+ if (channel->magic_count != magic_count)
goto eventq_ok;
} while (++count < 2);
- EFX_ERR(channel->efx, "channel %d timed out waiting for event queue\n",
- channel->channel);
+ netif_err(efx, drv, efx->net_dev,
+ "channel %d timed out waiting for event queue\n",
+ channel->channel);
/* See if interrupt arrived */
if (channel->efx->last_irq_cpu >= 0) {
- EFX_ERR(channel->efx, "channel %d saw interrupt on CPU%d "
- "during event queue test\n", channel->channel,
- raw_smp_processor_id());
+ netif_err(efx, drv, efx->net_dev,
+ "channel %d saw interrupt on CPU%d "
+ "during event queue test\n", channel->channel,
+ raw_smp_processor_id());
tests->eventq_int[channel->channel] = 1;
}
/* Check to see if event was received even if interrupt wasn't */
efx_process_channel_now(channel);
- if (channel->eventq_magic == magic) {
- EFX_ERR(channel->efx, "channel %d event was generated, but "
- "failed to trigger an interrupt\n", channel->channel);
+ if (channel->magic_count != magic_count) {
+ netif_err(efx, drv, efx->net_dev,
+ "channel %d event was generated, but "
+ "failed to trigger an interrupt\n", channel->channel);
tests->eventq_dma[channel->channel] = 1;
}
return -ETIMEDOUT;
eventq_ok:
- EFX_LOG(channel->efx, "channel %d event queue passed\n",
- channel->channel);
+ netif_dbg(efx, drv, efx->net_dev, "channel %d event queue passed\n",
+ channel->channel);
tests->eventq_dma[channel->channel] = 1;
tests->eventq_int[channel->channel] = 1;
tests->eventq_poll[channel->channel] = 1;
@@ -266,51 +265,57 @@ void efx_loopback_rx_packet(struct efx_nic *efx,
/* Check that header exists */
if (pkt_len < sizeof(received->header)) {
- EFX_ERR(efx, "saw runt RX packet (length %d) in %s loopback "
- "test\n", pkt_len, LOOPBACK_MODE(efx));
+ netif_err(efx, drv, efx->net_dev,
+ "saw runt RX packet (length %d) in %s loopback "
+ "test\n", pkt_len, LOOPBACK_MODE(efx));
goto err;
}
/* Check that the ethernet header exists */
if (memcmp(&received->header, &payload->header, ETH_HLEN) != 0) {
- EFX_ERR(efx, "saw non-loopback RX packet in %s loopback test\n",
- LOOPBACK_MODE(efx));
+ netif_err(efx, drv, efx->net_dev,
+ "saw non-loopback RX packet in %s loopback test\n",
+ LOOPBACK_MODE(efx));
goto err;
}
/* Check packet length */
if (pkt_len != sizeof(*payload)) {
- EFX_ERR(efx, "saw incorrect RX packet length %d (wanted %d) in "
- "%s loopback test\n", pkt_len, (int)sizeof(*payload),
- LOOPBACK_MODE(efx));
+ netif_err(efx, drv, efx->net_dev,
+ "saw incorrect RX packet length %d (wanted %d) in "
+ "%s loopback test\n", pkt_len, (int)sizeof(*payload),
+ LOOPBACK_MODE(efx));
goto err;
}
/* Check that IP header matches */
if (memcmp(&received->ip, &payload->ip, sizeof(payload->ip)) != 0) {
- EFX_ERR(efx, "saw corrupted IP header in %s loopback test\n",
- LOOPBACK_MODE(efx));
+ netif_err(efx, drv, efx->net_dev,
+ "saw corrupted IP header in %s loopback test\n",
+ LOOPBACK_MODE(efx));
goto err;
}
/* Check that msg and padding matches */
if (memcmp(&received->msg, &payload->msg, sizeof(received->msg)) != 0) {
- EFX_ERR(efx, "saw corrupted RX packet in %s loopback test\n",
- LOOPBACK_MODE(efx));
+ netif_err(efx, drv, efx->net_dev,
+ "saw corrupted RX packet in %s loopback test\n",
+ LOOPBACK_MODE(efx));
goto err;
}
/* Check that iteration matches */
if (received->iteration != payload->iteration) {
- EFX_ERR(efx, "saw RX packet from iteration %d (wanted %d) in "
- "%s loopback test\n", ntohs(received->iteration),
- ntohs(payload->iteration), LOOPBACK_MODE(efx));
+ netif_err(efx, drv, efx->net_dev,
+ "saw RX packet from iteration %d (wanted %d) in "
+ "%s loopback test\n", ntohs(received->iteration),
+ ntohs(payload->iteration), LOOPBACK_MODE(efx));
goto err;
}
/* Increase correct RX count */
- EFX_TRACE(efx, "got loopback RX in %s loopback test\n",
- LOOPBACK_MODE(efx));
+ netif_vdbg(efx, drv, efx->net_dev,
+ "got loopback RX in %s loopback test\n", LOOPBACK_MODE(efx));
atomic_inc(&state->rx_good);
return;
@@ -318,10 +323,10 @@ void efx_loopback_rx_packet(struct efx_nic *efx,
err:
#ifdef EFX_ENABLE_DEBUG
if (atomic_read(&state->rx_bad) == 0) {
- EFX_ERR(efx, "received packet:\n");
+ netif_err(efx, drv, efx->net_dev, "received packet:\n");
print_hex_dump(KERN_ERR, "", DUMP_PREFIX_OFFSET, 0x10, 1,
buf_ptr, pkt_len, 0);
- EFX_ERR(efx, "expected packet:\n");
+ netif_err(efx, drv, efx->net_dev, "expected packet:\n");
print_hex_dump(KERN_ERR, "", DUMP_PREFIX_OFFSET, 0x10, 1,
&state->payload, sizeof(state->payload), 0);
}
@@ -402,9 +407,11 @@ static int efx_begin_loopback(struct efx_tx_queue *tx_queue)
netif_tx_unlock_bh(efx->net_dev);
if (rc != NETDEV_TX_OK) {
- EFX_ERR(efx, "TX queue %d could not transmit packet %d "
- "of %d in %s loopback test\n", tx_queue->queue,
- i + 1, state->packet_count, LOOPBACK_MODE(efx));
+ netif_err(efx, drv, efx->net_dev,
+ "TX queue %d could not transmit packet %d of "
+ "%d in %s loopback test\n", tx_queue->queue,
+ i + 1, state->packet_count,
+ LOOPBACK_MODE(efx));
/* Defer cleaning up the other skbs for the caller */
kfree_skb(skb);
@@ -460,20 +467,22 @@ static int efx_end_loopback(struct efx_tx_queue *tx_queue,
/* Don't free the skbs; they will be picked up on TX
* overflow or channel teardown.
*/
- EFX_ERR(efx, "TX queue %d saw only %d out of an expected %d "
- "TX completion events in %s loopback test\n",
- tx_queue->queue, tx_done, state->packet_count,
- LOOPBACK_MODE(efx));
+ netif_err(efx, drv, efx->net_dev,
+ "TX queue %d saw only %d out of an expected %d "
+ "TX completion events in %s loopback test\n",
+ tx_queue->queue, tx_done, state->packet_count,
+ LOOPBACK_MODE(efx));
rc = -ETIMEDOUT;
/* Allow to fall through so we see the RX errors as well */
}
/* We may always be up to a flush away from our desired packet total */
if (rx_good != state->packet_count) {
- EFX_LOG(efx, "TX queue %d saw only %d out of an expected %d "
- "received packets in %s loopback test\n",
- tx_queue->queue, rx_good, state->packet_count,
- LOOPBACK_MODE(efx));
+ netif_dbg(efx, drv, efx->net_dev,
+ "TX queue %d saw only %d out of an expected %d "
+ "received packets in %s loopback test\n",
+ tx_queue->queue, rx_good, state->packet_count,
+ LOOPBACK_MODE(efx));
rc = -ETIMEDOUT;
/* Fall through */
}
@@ -505,9 +514,10 @@ efx_test_loopback(struct efx_tx_queue *tx_queue,
return -ENOMEM;
state->flush = false;
- EFX_LOG(efx, "TX queue %d testing %s loopback with %d "
- "packets\n", tx_queue->queue, LOOPBACK_MODE(efx),
- state->packet_count);
+ netif_dbg(efx, drv, efx->net_dev,
+ "TX queue %d testing %s loopback with %d packets\n",
+ tx_queue->queue, LOOPBACK_MODE(efx),
+ state->packet_count);
efx_iterate_state(efx);
begin_rc = efx_begin_loopback(tx_queue);
@@ -531,9 +541,10 @@ efx_test_loopback(struct efx_tx_queue *tx_queue,
}
}
- EFX_LOG(efx, "TX queue %d passed %s loopback test with a burst length "
- "of %d packets\n", tx_queue->queue, LOOPBACK_MODE(efx),
- state->packet_count);
+ netif_dbg(efx, drv, efx->net_dev,
+ "TX queue %d passed %s loopback test with a burst length "
+ "of %d packets\n", tx_queue->queue, LOOPBACK_MODE(efx),
+ state->packet_count);
return 0;
}
@@ -545,7 +556,7 @@ efx_test_loopback(struct efx_tx_queue *tx_queue,
static int efx_wait_for_link(struct efx_nic *efx)
{
struct efx_link_state *link_state = &efx->link_state;
- int count;
+ int count, link_up_count = 0;
bool link_up;
for (count = 0; count < 40; count++) {
@@ -567,8 +578,12 @@ static int efx_wait_for_link(struct efx_nic *efx)
link_up = !efx->mac_op->check_fault(efx);
mutex_unlock(&efx->mac_lock);
- if (link_up)
- return 0;
+ if (link_up) {
+ if (++link_up_count == 2)
+ return 0;
+ } else {
+ link_up_count = 0;
+ }
}
return -ETIMEDOUT;
@@ -604,15 +619,17 @@ static int efx_test_loopbacks(struct efx_nic *efx, struct efx_self_tests *tests,
rc = __efx_reconfigure_port(efx);
mutex_unlock(&efx->mac_lock);
if (rc) {
- EFX_ERR(efx, "unable to move into %s loopback\n",
- LOOPBACK_MODE(efx));
+ netif_err(efx, drv, efx->net_dev,
+ "unable to move into %s loopback\n",
+ LOOPBACK_MODE(efx));
goto out;
}
rc = efx_wait_for_link(efx);
if (rc) {
- EFX_ERR(efx, "loopback %s never came up\n",
- LOOPBACK_MODE(efx));
+ netif_err(efx, drv, efx->net_dev,
+ "loopback %s never came up\n",
+ LOOPBACK_MODE(efx));
goto out;
}
@@ -720,7 +737,8 @@ int efx_selftest(struct efx_nic *efx, struct efx_self_tests *tests,
rc_reset = rc;
if (rc_reset) {
- EFX_ERR(efx, "Unable to recover from chip test\n");
+ netif_err(efx, drv, efx->net_dev,
+ "Unable to recover from chip test\n");
efx_schedule_reset(efx, RESET_TYPE_DISABLE);
return rc_reset;
}
diff --git a/drivers/net/sfc/siena.c b/drivers/net/sfc/siena.c
index f2b1e618075..3fab030f8ab 100644
--- a/drivers/net/sfc/siena.c
+++ b/drivers/net/sfc/siena.c
@@ -118,10 +118,11 @@ static int siena_probe_port(struct efx_nic *efx)
MC_CMD_MAC_NSTATS * sizeof(u64));
if (rc)
return rc;
- EFX_LOG(efx, "stats buffer at %llx (virt %p phys %llx)\n",
- (u64)efx->stats_buffer.dma_addr,
- efx->stats_buffer.addr,
- (u64)virt_to_phys(efx->stats_buffer.addr));
+ netif_dbg(efx, probe, efx->net_dev,
+ "stats buffer at %llx (virt %p phys %llx)\n",
+ (u64)efx->stats_buffer.dma_addr,
+ efx->stats_buffer.addr,
+ (u64)virt_to_phys(efx->stats_buffer.addr));
efx_mcdi_mac_stats(efx, efx->stats_buffer.dma_addr, 0, 0, 1);
@@ -216,7 +217,8 @@ static int siena_probe_nic(struct efx_nic *efx)
efx->nic_data = nic_data;
if (efx_nic_fpga_ver(efx) != 0) {
- EFX_ERR(efx, "Siena FPGA not supported\n");
+ netif_err(efx, probe, efx->net_dev,
+ "Siena FPGA not supported\n");
rc = -ENODEV;
goto fail1;
}
@@ -233,8 +235,8 @@ static int siena_probe_nic(struct efx_nic *efx)
rc = efx_mcdi_fwver(efx, &nic_data->fw_version, &nic_data->fw_build);
if (rc) {
- EFX_ERR(efx, "Failed to read MCPU firmware version - "
- "rc %d\n", rc);
+ netif_err(efx, probe, efx->net_dev,
+ "Failed to read MCPU firmware version - rc %d\n", rc);
goto fail1; /* MCPU absent? */
}
@@ -242,17 +244,19 @@ static int siena_probe_nic(struct efx_nic *efx)
* filter settings. We must do this before we reset the NIC */
rc = efx_mcdi_drv_attach(efx, true, &already_attached);
if (rc) {
- EFX_ERR(efx, "Unable to register driver with MCPU\n");
+ netif_err(efx, probe, efx->net_dev,
+ "Unable to register driver with MCPU\n");
goto fail2;
}
if (already_attached)
/* Not a fatal error */
- EFX_ERR(efx, "Host already registered with MCPU\n");
+ netif_err(efx, probe, efx->net_dev,
+ "Host already registered with MCPU\n");
/* Now we can reset the NIC */
rc = siena_reset_hw(efx, RESET_TYPE_ALL);
if (rc) {
- EFX_ERR(efx, "failed to reset NIC\n");
+ netif_err(efx, probe, efx->net_dev, "failed to reset NIC\n");
goto fail3;
}
@@ -264,24 +268,23 @@ static int siena_probe_nic(struct efx_nic *efx)
goto fail4;
BUG_ON(efx->irq_status.dma_addr & 0x0f);
- EFX_LOG(efx, "INT_KER at %llx (virt %p phys %llx)\n",
- (unsigned long long)efx->irq_status.dma_addr,
- efx->irq_status.addr,
- (unsigned long long)virt_to_phys(efx->irq_status.addr));
+ netif_dbg(efx, probe, efx->net_dev,
+ "INT_KER at %llx (virt %p phys %llx)\n",
+ (unsigned long long)efx->irq_status.dma_addr,
+ efx->irq_status.addr,
+ (unsigned long long)virt_to_phys(efx->irq_status.addr));
/* Read in the non-volatile configuration */
rc = siena_probe_nvconfig(efx);
if (rc == -EINVAL) {
- EFX_ERR(efx, "NVRAM is invalid therefore using defaults\n");
+ netif_err(efx, probe, efx->net_dev,
+ "NVRAM is invalid therefore using defaults\n");
efx->phy_type = PHY_TYPE_NONE;
efx->mdio.prtad = MDIO_PRTAD_NONE;
} else if (rc) {
goto fail5;
}
- get_random_bytes(&nic_data->ipv6_rss_key,
- sizeof(nic_data->ipv6_rss_key));
-
return 0;
fail5:
@@ -301,7 +304,6 @@ fail1:
*/
static int siena_init_nic(struct efx_nic *efx)
{
- struct siena_nic_data *nic_data = efx->nic_data;
efx_oword_t temp;
int rc;
@@ -326,25 +328,36 @@ static int siena_init_nic(struct efx_nic *efx)
efx_reado(efx, &temp, FR_AZ_RX_CFG);
EFX_SET_OWORD_FIELD(temp, FRF_BZ_RX_DESC_PUSH_EN, 0);
EFX_SET_OWORD_FIELD(temp, FRF_BZ_RX_INGR_EN, 1);
+ /* Enable hash insertion. This is broken for the 'Falcon' hash
+ * if IPv6 hashing is also enabled, so also select Toeplitz
+ * TCP/IPv4 and IPv4 hashes. */
+ EFX_SET_OWORD_FIELD(temp, FRF_BZ_RX_HASH_INSRT_HDR, 1);
+ EFX_SET_OWORD_FIELD(temp, FRF_BZ_RX_HASH_ALG, 1);
+ EFX_SET_OWORD_FIELD(temp, FRF_BZ_RX_IP_HASH, 1);
efx_writeo(efx, &temp, FR_AZ_RX_CFG);
+ /* Set hash key for IPv4 */
+ memcpy(&temp, efx->rx_hash_key, sizeof(temp));
+ efx_writeo(efx, &temp, FR_BZ_RX_RSS_TKEY);
+
/* Enable IPv6 RSS */
- BUILD_BUG_ON(sizeof(nic_data->ipv6_rss_key) !=
+ BUILD_BUG_ON(sizeof(efx->rx_hash_key) <
2 * sizeof(temp) + FRF_CZ_RX_RSS_IPV6_TKEY_HI_WIDTH / 8 ||
FRF_CZ_RX_RSS_IPV6_TKEY_HI_LBN != 0);
- memcpy(&temp, nic_data->ipv6_rss_key, sizeof(temp));
+ memcpy(&temp, efx->rx_hash_key, sizeof(temp));
efx_writeo(efx, &temp, FR_CZ_RX_RSS_IPV6_REG1);
- memcpy(&temp, nic_data->ipv6_rss_key + sizeof(temp), sizeof(temp));
+ memcpy(&temp, efx->rx_hash_key + sizeof(temp), sizeof(temp));
efx_writeo(efx, &temp, FR_CZ_RX_RSS_IPV6_REG2);
EFX_POPULATE_OWORD_2(temp, FRF_CZ_RX_RSS_IPV6_THASH_ENABLE, 1,
FRF_CZ_RX_RSS_IPV6_IP_THASH_ENABLE, 1);
- memcpy(&temp, nic_data->ipv6_rss_key + 2 * sizeof(temp),
+ memcpy(&temp, efx->rx_hash_key + 2 * sizeof(temp),
FRF_CZ_RX_RSS_IPV6_TKEY_HI_WIDTH / 8);
efx_writeo(efx, &temp, FR_CZ_RX_RSS_IPV6_REG3);
if (efx_nic_rx_xoff_thresh >= 0 || efx_nic_rx_xon_thresh >= 0)
/* No MCDI operation has been defined to set thresholds */
- EFX_ERR(efx, "ignoring RX flow control thresholds\n");
+ netif_err(efx, hw, efx->net_dev,
+ "ignoring RX flow control thresholds\n");
/* Enable event logging */
rc = efx_mcdi_log_ctrl(efx, true, false, 0);
@@ -565,7 +578,8 @@ static int siena_set_wol(struct efx_nic *efx, u32 type)
return 0;
fail:
- EFX_ERR(efx, "%s failed: type=%d rc=%d\n", __func__, type, rc);
+ netif_err(efx, hw, efx->net_dev, "%s failed: type=%d rc=%d\n",
+ __func__, type, rc);
return rc;
}
@@ -628,6 +642,7 @@ struct efx_nic_type siena_a0_nic_type = {
.evq_ptr_tbl_base = FR_BZ_EVQ_PTR_TBL,
.evq_rptr_tbl_base = FR_BZ_EVQ_RPTR,
.max_dma_mask = DMA_BIT_MASK(FSF_AZ_TX_KER_BUF_ADDR_WIDTH),
+ .rx_buffer_hash_size = 0x10,
.rx_buffer_padding = 0,
.max_interrupt_mode = EFX_INT_MODE_MSIX,
.phys_addr_channels = 32, /* Hardware limit is 64, but the legacy
@@ -635,6 +650,7 @@ struct efx_nic_type siena_a0_nic_type = {
* channels */
.tx_dc_base = 0x88000,
.rx_dc_base = 0x68000,
- .offload_features = NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM,
+ .offload_features = (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
+ NETIF_F_RXHASH),
.reset_world_flags = ETH_RESET_MGMT << ETH_RESET_SHARED_SHIFT,
};
diff --git a/drivers/net/sfc/tenxpress.c b/drivers/net/sfc/tenxpress.c
index f21efe7bd31..6791be90c2f 100644
--- a/drivers/net/sfc/tenxpress.c
+++ b/drivers/net/sfc/tenxpress.c
@@ -228,7 +228,8 @@ int sft9001_wait_boot(struct efx_nic *efx)
boot_stat = efx_mdio_read(efx, MDIO_MMD_PCS,
PCS_BOOT_STATUS_REG);
if (boot_stat >= 0) {
- EFX_LOG(efx, "PHY boot status = %#x\n", boot_stat);
+ netif_dbg(efx, hw, efx->net_dev,
+ "PHY boot status = %#x\n", boot_stat);
switch (boot_stat &
((1 << PCS_BOOT_FATAL_ERROR_LBN) |
(3 << PCS_BOOT_PROGRESS_LBN) |
@@ -463,10 +464,11 @@ static void sfx7101_check_bad_lp(struct efx_nic *efx, bool link_ok)
reg |= PMA_PMD_LED_OFF << PMA_PMD_LED_RX_LBN;
} else {
reg |= PMA_PMD_LED_FLASH << PMA_PMD_LED_RX_LBN;
- EFX_ERR(efx, "appears to be plugged into a port"
- " that is not 10GBASE-T capable. The PHY"
- " supports 10GBASE-T ONLY, so no link can"
- " be established\n");
+ netif_err(efx, link, efx->net_dev,
+ "appears to be plugged into a port"
+ " that is not 10GBASE-T capable. The PHY"
+ " supports 10GBASE-T ONLY, so no link can"
+ " be established\n");
}
efx_mdio_write(efx, MDIO_MMD_PMAPMD,
PMA_PMD_LED_OVERR_REG, reg);
diff --git a/drivers/net/sfc/tx.c b/drivers/net/sfc/tx.c
index 6bb12a87ef2..c6942da2c99 100644
--- a/drivers/net/sfc/tx.c
+++ b/drivers/net/sfc/tx.c
@@ -42,7 +42,7 @@ void efx_stop_queue(struct efx_channel *channel)
return;
spin_lock_bh(&channel->tx_stop_lock);
- EFX_TRACE(efx, "stop TX queue\n");
+ netif_vdbg(efx, tx_queued, efx->net_dev, "stop TX queue\n");
atomic_inc(&channel->tx_stop_count);
netif_tx_stop_queue(
@@ -64,7 +64,7 @@ void efx_wake_queue(struct efx_channel *channel)
local_bh_disable();
if (atomic_dec_and_lock(&channel->tx_stop_count,
&channel->tx_stop_lock)) {
- EFX_TRACE(efx, "waking TX queue\n");
+ netif_vdbg(efx, tx_queued, efx->net_dev, "waking TX queue\n");
netif_tx_wake_queue(
netdev_get_tx_queue(
efx->net_dev,
@@ -94,8 +94,9 @@ static void efx_dequeue_buffer(struct efx_tx_queue *tx_queue,
if (buffer->skb) {
dev_kfree_skb_any((struct sk_buff *) buffer->skb);
buffer->skb = NULL;
- EFX_TRACE(tx_queue->efx, "TX queue %d transmission id %x "
- "complete\n", tx_queue->queue, read_ptr);
+ netif_vdbg(tx_queue->efx, tx_done, tx_queue->efx->net_dev,
+ "TX queue %d transmission id %x complete\n",
+ tx_queue->queue, tx_queue->read_count);
}
}
@@ -300,9 +301,10 @@ netdev_tx_t efx_enqueue_skb(struct efx_tx_queue *tx_queue, struct sk_buff *skb)
return NETDEV_TX_OK;
pci_err:
- EFX_ERR_RL(efx, " TX queue %d could not map skb with %d bytes %d "
- "fragments for DMA\n", tx_queue->queue, skb->len,
- skb_shinfo(skb)->nr_frags + 1);
+ netif_err(efx, tx_err, efx->net_dev,
+ " TX queue %d could not map skb with %d bytes %d "
+ "fragments for DMA\n", tx_queue->queue, skb->len,
+ skb_shinfo(skb)->nr_frags + 1);
/* Mark the packet as transmitted, and free the SKB ourselves */
dev_kfree_skb_any(skb);
@@ -354,9 +356,9 @@ static void efx_dequeue_buffers(struct efx_tx_queue *tx_queue,
while (read_ptr != stop_index) {
struct efx_tx_buffer *buffer = &tx_queue->buffer[read_ptr];
if (unlikely(buffer->len == 0)) {
- EFX_ERR(tx_queue->efx, "TX queue %d spurious TX "
- "completion id %x\n", tx_queue->queue,
- read_ptr);
+ netif_err(efx, tx_err, efx->net_dev,
+ "TX queue %d spurious TX completion id %x\n",
+ tx_queue->queue, read_ptr);
efx_schedule_reset(efx, RESET_TYPE_TX_SKIP);
return;
}
@@ -431,7 +433,8 @@ int efx_probe_tx_queue(struct efx_tx_queue *tx_queue)
unsigned int txq_size;
int i, rc;
- EFX_LOG(efx, "creating TX queue %d\n", tx_queue->queue);
+ netif_dbg(efx, probe, efx->net_dev, "creating TX queue %d\n",
+ tx_queue->queue);
/* Allocate software ring */
txq_size = EFX_TXQ_SIZE * sizeof(*tx_queue->buffer);
@@ -456,7 +459,8 @@ int efx_probe_tx_queue(struct efx_tx_queue *tx_queue)
void efx_init_tx_queue(struct efx_tx_queue *tx_queue)
{
- EFX_LOG(tx_queue->efx, "initialising TX queue %d\n", tx_queue->queue);
+ netif_dbg(tx_queue->efx, drv, tx_queue->efx->net_dev,
+ "initialising TX queue %d\n", tx_queue->queue);
tx_queue->insert_count = 0;
tx_queue->write_count = 0;
@@ -488,7 +492,8 @@ void efx_release_tx_buffers(struct efx_tx_queue *tx_queue)
void efx_fini_tx_queue(struct efx_tx_queue *tx_queue)
{
- EFX_LOG(tx_queue->efx, "shutting down TX queue %d\n", tx_queue->queue);
+ netif_dbg(tx_queue->efx, drv, tx_queue->efx->net_dev,
+ "shutting down TX queue %d\n", tx_queue->queue);
/* Flush TX queue, remove descriptor ring */
efx_nic_fini_tx(tx_queue);
@@ -507,7 +512,8 @@ void efx_fini_tx_queue(struct efx_tx_queue *tx_queue)
void efx_remove_tx_queue(struct efx_tx_queue *tx_queue)
{
- EFX_LOG(tx_queue->efx, "destroying TX queue %d\n", tx_queue->queue);
+ netif_dbg(tx_queue->efx, drv, tx_queue->efx->net_dev,
+ "destroying TX queue %d\n", tx_queue->queue);
efx_nic_remove_tx(tx_queue);
kfree(tx_queue->buffer);
@@ -639,8 +645,8 @@ static int efx_tsoh_block_alloc(struct efx_tx_queue *tx_queue)
base_kva = pci_alloc_consistent(pci_dev, PAGE_SIZE, &dma_addr);
if (base_kva == NULL) {
- EFX_ERR(tx_queue->efx, "Unable to allocate page for TSO"
- " headers\n");
+ netif_err(tx_queue->efx, tx_err, tx_queue->efx->net_dev,
+ "Unable to allocate page for TSO headers\n");
return -ENOMEM;
}
@@ -1124,7 +1130,8 @@ static int efx_enqueue_skb_tso(struct efx_tx_queue *tx_queue,
return NETDEV_TX_OK;
mem_err:
- EFX_ERR(efx, "Out of memory for TSO headers, or PCI mapping error\n");
+ netif_err(efx, tx_err, efx->net_dev,
+ "Out of memory for TSO headers, or PCI mapping error\n");
dev_kfree_skb_any(skb);
goto unwind;
diff --git a/drivers/net/sfc/workarounds.h b/drivers/net/sfc/workarounds.h
index 518f7fc9147..782e45a613d 100644
--- a/drivers/net/sfc/workarounds.h
+++ b/drivers/net/sfc/workarounds.h
@@ -54,7 +54,7 @@
/* Increase filter depth to avoid RX_RESET */
#define EFX_WORKAROUND_7244 EFX_WORKAROUND_FALCON_A
/* Flushes may never complete */
-#define EFX_WORKAROUND_7803 EFX_WORKAROUND_FALCON_A
+#define EFX_WORKAROUND_7803 EFX_WORKAROUND_FALCON_AB
/* Leak overlength packets rather than free */
#define EFX_WORKAROUND_8071 EFX_WORKAROUND_FALCON_A
diff --git a/drivers/net/sh_eth.c b/drivers/net/sh_eth.c
index 501a55ffce5..f5a9eb1df59 100644
--- a/drivers/net/sh_eth.c
+++ b/drivers/net/sh_eth.c
@@ -88,6 +88,55 @@ static struct sh_eth_cpu_data sh_eth_my_cpu_data = {
.rpadir = 1,
.rpadir_value = 0x00020000, /* NET_IP_ALIGN assumed to be 2 */
};
+#elif defined(CONFIG_CPU_SUBTYPE_SH7757)
+#define SH_ETH_RESET_DEFAULT 1
+static void sh_eth_set_duplex(struct net_device *ndev)
+{
+ struct sh_eth_private *mdp = netdev_priv(ndev);
+ u32 ioaddr = ndev->base_addr;
+
+ if (mdp->duplex) /* Full */
+ ctrl_outl(ctrl_inl(ioaddr + ECMR) | ECMR_DM, ioaddr + ECMR);
+ else /* Half */
+ ctrl_outl(ctrl_inl(ioaddr + ECMR) & ~ECMR_DM, ioaddr + ECMR);
+}
+
+static void sh_eth_set_rate(struct net_device *ndev)
+{
+ struct sh_eth_private *mdp = netdev_priv(ndev);
+ u32 ioaddr = ndev->base_addr;
+
+ switch (mdp->speed) {
+ case 10: /* 10BASE */
+ ctrl_outl(0, ioaddr + RTRATE);
+ break;
+ case 100:/* 100BASE */
+ ctrl_outl(1, ioaddr + RTRATE);
+ break;
+ default:
+ break;
+ }
+}
+
+/* SH7757 */
+static struct sh_eth_cpu_data sh_eth_my_cpu_data = {
+ .set_duplex = sh_eth_set_duplex,
+ .set_rate = sh_eth_set_rate,
+
+ .eesipr_value = DMAC_M_RFRMER | DMAC_M_ECI | 0x003fffff,
+ .rmcr_value = 0x00000001,
+
+ .tx_check = EESR_FTC | EESR_CND | EESR_DLC | EESR_CD | EESR_RTO,
+ .eesr_err_check = EESR_TWB | EESR_TABT | EESR_RABT | EESR_RDE |
+ EESR_RFRMER | EESR_TFE | EESR_TDE | EESR_ECI,
+ .tx_error_check = EESR_TWB | EESR_TABT | EESR_TDE | EESR_TFE,
+
+ .apr = 1,
+ .mpr = 1,
+ .tpauser = 1,
+ .hw_swap = 1,
+ .no_ade = 1,
+};
#elif defined(CONFIG_CPU_SUBTYPE_SH7763)
#define SH_ETH_HAS_TSU 1
@@ -1023,7 +1072,9 @@ static int sh_eth_open(struct net_device *ndev)
pm_runtime_get_sync(&mdp->pdev->dev);
ret = request_irq(ndev->irq, sh_eth_interrupt,
-#if defined(CONFIG_CPU_SUBTYPE_SH7763) || defined(CONFIG_CPU_SUBTYPE_SH7764)
+#if defined(CONFIG_CPU_SUBTYPE_SH7763) || \
+ defined(CONFIG_CPU_SUBTYPE_SH7764) || \
+ defined(CONFIG_CPU_SUBTYPE_SH7757)
IRQF_SHARED,
#else
0,
@@ -1233,7 +1284,7 @@ static int sh_eth_do_ioctl(struct net_device *ndev, struct ifreq *rq,
if (!phydev)
return -ENODEV;
- return phy_mii_ioctl(phydev, if_mii(rq), cmd);
+ return phy_mii_ioctl(phydev, rq, cmd);
}
#if defined(SH_ETH_HAS_TSU)
@@ -1325,7 +1376,7 @@ static int sh_mdio_init(struct net_device *ndev, int id)
bitbang->mdc_msk = 0x01;
bitbang->ctrl.ops = &bb_ops;
- /* MII contorller setting */
+ /* MII controller setting */
mdp->mii_bus = alloc_mdio_bitbang(&bitbang->ctrl);
if (!mdp->mii_bus) {
ret = -ENOMEM;
diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c
index 7985165e84f..194e5cf8c76 100644
--- a/drivers/net/sky2.c
+++ b/drivers/net/sky2.c
@@ -79,7 +79,7 @@
#define SKY2_EEPROM_MAGIC 0x9955aabb
-#define RING_NEXT(x,s) (((x)+1) & ((s)-1))
+#define RING_NEXT(x, s) (((x)+1) & ((s)-1))
static const u32 default_msg =
NETIF_MSG_DRV | NETIF_MSG_PROBE | NETIF_MSG_LINK
@@ -172,7 +172,7 @@ static int gm_phy_write(struct sky2_hw *hw, unsigned port, u16 reg, u16 val)
udelay(10);
}
- dev_warn(&hw->pdev->dev,"%s: phy write timeout\n", hw->dev[port]->name);
+ dev_warn(&hw->pdev->dev, "%s: phy write timeout\n", hw->dev[port]->name);
return -ETIMEDOUT;
io_error:
@@ -1067,7 +1067,7 @@ static inline struct sky2_rx_le *sky2_next_rx(struct sky2_port *sky2)
return le;
}
-static unsigned sky2_get_rx_threshold(struct sky2_port* sky2)
+static unsigned sky2_get_rx_threshold(struct sky2_port *sky2)
{
unsigned size;
@@ -1078,7 +1078,7 @@ static unsigned sky2_get_rx_threshold(struct sky2_port* sky2)
return (size - 8) / sizeof(u32);
}
-static unsigned sky2_get_rx_data_size(struct sky2_port* sky2)
+static unsigned sky2_get_rx_data_size(struct sky2_port *sky2)
{
struct rx_ring_info *re;
unsigned size;
@@ -1102,7 +1102,7 @@ static unsigned sky2_get_rx_data_size(struct sky2_port* sky2)
}
/* Build description to hardware for one receive segment */
-static void sky2_rx_add(struct sky2_port *sky2, u8 op,
+static void sky2_rx_add(struct sky2_port *sky2, u8 op,
dma_addr_t map, unsigned len)
{
struct sky2_rx_le *le;
@@ -3014,7 +3014,7 @@ static int __devinit sky2_init(struct sky2_hw *hw)
hw->chip_id = sky2_read8(hw, B2_CHIP_ID);
hw->chip_rev = (sky2_read8(hw, B2_MAC_CFG) & CFG_CHIP_R_MSK) >> 4;
- switch(hw->chip_id) {
+ switch (hw->chip_id) {
case CHIP_ID_YUKON_XL:
hw->flags = SKY2_HW_GIGABIT | SKY2_HW_NEWER_PHY;
if (hw->chip_rev < CHIP_REV_YU_XL_A2)
@@ -3685,7 +3685,7 @@ static int sky2_set_mac_address(struct net_device *dev, void *p)
return 0;
}
-static void inline sky2_add_filter(u8 filter[8], const u8 *addr)
+static inline void sky2_add_filter(u8 filter[8], const u8 *addr)
{
u32 bit;
@@ -3911,7 +3911,7 @@ static int sky2_set_coalesce(struct net_device *dev,
return -EINVAL;
if (ecmd->rx_max_coalesced_frames > RX_MAX_PENDING)
return -EINVAL;
- if (ecmd->rx_max_coalesced_frames_irq >RX_MAX_PENDING)
+ if (ecmd->rx_max_coalesced_frames_irq > RX_MAX_PENDING)
return -EINVAL;
if (ecmd->tx_coalesce_usecs == 0)
@@ -4188,17 +4188,13 @@ static int sky2_set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom
static int sky2_set_flags(struct net_device *dev, u32 data)
{
struct sky2_port *sky2 = netdev_priv(dev);
+ u32 supported =
+ (sky2->hw->flags & SKY2_HW_RSS_BROKEN) ? 0 : ETH_FLAG_RXHASH;
+ int rc;
- if (data & ~ETH_FLAG_RXHASH)
- return -EOPNOTSUPP;
-
- if (data & ETH_FLAG_RXHASH) {
- if (sky2->hw->flags & SKY2_HW_RSS_BROKEN)
- return -EINVAL;
-
- dev->features |= NETIF_F_RXHASH;
- } else
- dev->features &= ~NETIF_F_RXHASH;
+ rc = ethtool_op_set_flags(dev, data, supported);
+ if (rc)
+ return rc;
rx_set_rss(dev);
@@ -4376,7 +4372,7 @@ static int sky2_debug_show(struct seq_file *seq, void *v)
seq_printf(seq, "%u:", idx);
sop = 0;
- switch(le->opcode & ~HW_OWNER) {
+ switch (le->opcode & ~HW_OWNER) {
case OP_ADDR64:
seq_printf(seq, " %#x:", a);
break;
@@ -4445,7 +4441,7 @@ static int sky2_device_event(struct notifier_block *unused,
if (dev->netdev_ops->ndo_open != sky2_up || !sky2_debug)
return NOTIFY_DONE;
- switch(event) {
+ switch (event) {
case NETDEV_CHANGENAME:
if (sky2->debugfs) {
sky2->debugfs = debugfs_rename(sky2_debug, sky2->debugfs,
@@ -4640,7 +4636,7 @@ static int __devinit sky2_test_msi(struct sky2_hw *hw)
struct pci_dev *pdev = hw->pdev;
int err;
- init_waitqueue_head (&hw->msi_wait);
+ init_waitqueue_head(&hw->msi_wait);
sky2_write32(hw, B0_IMSK, Y2_IS_IRQ_SW);
@@ -4757,7 +4753,7 @@ static int __devinit sky2_probe(struct pci_dev *pdev,
* this driver uses software swapping.
*/
reg &= ~PCI_REV_DESC;
- err = pci_write_config_dword(pdev,PCI_DEV_REG2, reg);
+ err = pci_write_config_dword(pdev, PCI_DEV_REG2, reg);
if (err) {
dev_err(&pdev->dev, "PCI write config failed\n");
goto err_out_free_regions;
diff --git a/drivers/net/sky2.h b/drivers/net/sky2.h
index 084eff21b67..61891a6cacc 100644
--- a/drivers/net/sky2.h
+++ b/drivers/net/sky2.h
@@ -2161,21 +2161,21 @@ struct sky2_tx_le {
__le16 length; /* also vlan tag or checksum start */
u8 ctrl;
u8 opcode;
-} __attribute((packed));
+} __packed;
struct sky2_rx_le {
__le32 addr;
__le16 length;
u8 ctrl;
u8 opcode;
-} __attribute((packed));
+} __packed;
struct sky2_status_le {
__le32 status; /* also checksum */
__le16 length; /* also vlan tag */
u8 css;
u8 opcode;
-} __attribute((packed));
+} __packed;
struct tx_ring_info {
struct sk_buff *skb;
diff --git a/drivers/net/smc91x.h b/drivers/net/smc91x.h
index 8d2772cc42f..ee747919a76 100644
--- a/drivers/net/smc91x.h
+++ b/drivers/net/smc91x.h
@@ -83,43 +83,6 @@ static inline void SMC_outw(u16 val, void __iomem *ioaddr, int reg)
}
}
-#elif defined(CONFIG_REDWOOD_5) || defined(CONFIG_REDWOOD_6)
-
-/* We can only do 16-bit reads and writes in the static memory space. */
-#define SMC_CAN_USE_8BIT 0
-#define SMC_CAN_USE_16BIT 1
-#define SMC_CAN_USE_32BIT 0
-#define SMC_NOWAIT 1
-
-#define SMC_IO_SHIFT 0
-
-#define SMC_inw(a, r) in_be16((volatile u16 *)((a) + (r)))
-#define SMC_outw(v, a, r) out_be16((volatile u16 *)((a) + (r)), v)
-#define SMC_insw(a, r, p, l) \
- do { \
- unsigned long __port = (a) + (r); \
- u16 *__p = (u16 *)(p); \
- int __l = (l); \
- insw(__port, __p, __l); \
- while (__l > 0) { \
- *__p = swab16(*__p); \
- __p++; \
- __l--; \
- } \
- } while (0)
-#define SMC_outsw(a, r, p, l) \
- do { \
- unsigned long __port = (a) + (r); \
- u16 *__p = (u16 *)(p); \
- int __l = (l); \
- while (__l > 0) { \
- /* Believe it or not, the swab isn't needed. */ \
- outw( /* swab16 */ (*__p++), __port); \
- __l--; \
- } \
- } while (0)
-#define SMC_IRQ_FLAGS (0)
-
#elif defined(CONFIG_SA1100_PLEB)
/* We can only do 16-bit reads and writes in the static memory space. */
#define SMC_CAN_USE_8BIT 1
diff --git a/drivers/net/smsc911x.c b/drivers/net/smsc911x.c
index cc559741b0f..0909ae934ad 100644
--- a/drivers/net/smsc911x.c
+++ b/drivers/net/smsc911x.c
@@ -84,8 +84,7 @@ struct smsc911x_data {
*/
spinlock_t mac_lock;
- /* spinlock to ensure 16-bit accesses are serialised.
- * unused with a 32-bit bus */
+ /* spinlock to ensure register accesses are serialised */
spinlock_t dev_lock;
struct phy_device *phy_dev;
@@ -118,37 +117,33 @@ struct smsc911x_data {
unsigned int hashlo;
};
-/* The 16-bit access functions are significantly slower, due to the locking
- * necessary. If your bus hardware can be configured to do this for you
- * (in response to a single 32-bit operation from software), you should use
- * the 32-bit access functions instead. */
-
-static inline u32 smsc911x_reg_read(struct smsc911x_data *pdata, u32 reg)
+static inline u32 __smsc911x_reg_read(struct smsc911x_data *pdata, u32 reg)
{
if (pdata->config.flags & SMSC911X_USE_32BIT)
return readl(pdata->ioaddr + reg);
- if (pdata->config.flags & SMSC911X_USE_16BIT) {
- u32 data;
- unsigned long flags;
-
- /* these two 16-bit reads must be performed consecutively, so
- * must not be interrupted by our own ISR (which would start
- * another read operation) */
- spin_lock_irqsave(&pdata->dev_lock, flags);
- data = ((readw(pdata->ioaddr + reg) & 0xFFFF) |
+ if (pdata->config.flags & SMSC911X_USE_16BIT)
+ return ((readw(pdata->ioaddr + reg) & 0xFFFF) |
((readw(pdata->ioaddr + reg + 2) & 0xFFFF) << 16));
- spin_unlock_irqrestore(&pdata->dev_lock, flags);
-
- return data;
- }
BUG();
return 0;
}
-static inline void smsc911x_reg_write(struct smsc911x_data *pdata, u32 reg,
- u32 val)
+static inline u32 smsc911x_reg_read(struct smsc911x_data *pdata, u32 reg)
+{
+ u32 data;
+ unsigned long flags;
+
+ spin_lock_irqsave(&pdata->dev_lock, flags);
+ data = __smsc911x_reg_read(pdata, reg);
+ spin_unlock_irqrestore(&pdata->dev_lock, flags);
+
+ return data;
+}
+
+static inline void __smsc911x_reg_write(struct smsc911x_data *pdata, u32 reg,
+ u32 val)
{
if (pdata->config.flags & SMSC911X_USE_32BIT) {
writel(val, pdata->ioaddr + reg);
@@ -156,44 +151,54 @@ static inline void smsc911x_reg_write(struct smsc911x_data *pdata, u32 reg,
}
if (pdata->config.flags & SMSC911X_USE_16BIT) {
- unsigned long flags;
-
- /* these two 16-bit writes must be performed consecutively, so
- * must not be interrupted by our own ISR (which would start
- * another read operation) */
- spin_lock_irqsave(&pdata->dev_lock, flags);
writew(val & 0xFFFF, pdata->ioaddr + reg);
writew((val >> 16) & 0xFFFF, pdata->ioaddr + reg + 2);
- spin_unlock_irqrestore(&pdata->dev_lock, flags);
return;
}
BUG();
}
+static inline void smsc911x_reg_write(struct smsc911x_data *pdata, u32 reg,
+ u32 val)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&pdata->dev_lock, flags);
+ __smsc911x_reg_write(pdata, reg, val);
+ spin_unlock_irqrestore(&pdata->dev_lock, flags);
+}
+
/* Writes a packet to the TX_DATA_FIFO */
static inline void
smsc911x_tx_writefifo(struct smsc911x_data *pdata, unsigned int *buf,
unsigned int wordcount)
{
+ unsigned long flags;
+
+ spin_lock_irqsave(&pdata->dev_lock, flags);
+
if (pdata->config.flags & SMSC911X_SWAP_FIFO) {
while (wordcount--)
- smsc911x_reg_write(pdata, TX_DATA_FIFO, swab32(*buf++));
- return;
+ __smsc911x_reg_write(pdata, TX_DATA_FIFO,
+ swab32(*buf++));
+ goto out;
}
if (pdata->config.flags & SMSC911X_USE_32BIT) {
writesl(pdata->ioaddr + TX_DATA_FIFO, buf, wordcount);
- return;
+ goto out;
}
if (pdata->config.flags & SMSC911X_USE_16BIT) {
while (wordcount--)
- smsc911x_reg_write(pdata, TX_DATA_FIFO, *buf++);
- return;
+ __smsc911x_reg_write(pdata, TX_DATA_FIFO, *buf++);
+ goto out;
}
BUG();
+out:
+ spin_unlock_irqrestore(&pdata->dev_lock, flags);
}
/* Reads a packet out of the RX_DATA_FIFO */
@@ -201,24 +206,31 @@ static inline void
smsc911x_rx_readfifo(struct smsc911x_data *pdata, unsigned int *buf,
unsigned int wordcount)
{
+ unsigned long flags;
+
+ spin_lock_irqsave(&pdata->dev_lock, flags);
+
if (pdata->config.flags & SMSC911X_SWAP_FIFO) {
while (wordcount--)
- *buf++ = swab32(smsc911x_reg_read(pdata, RX_DATA_FIFO));
- return;
+ *buf++ = swab32(__smsc911x_reg_read(pdata,
+ RX_DATA_FIFO));
+ goto out;
}
if (pdata->config.flags & SMSC911X_USE_32BIT) {
readsl(pdata->ioaddr + RX_DATA_FIFO, buf, wordcount);
- return;
+ goto out;
}
if (pdata->config.flags & SMSC911X_USE_16BIT) {
while (wordcount--)
- *buf++ = smsc911x_reg_read(pdata, RX_DATA_FIFO);
- return;
+ *buf++ = __smsc911x_reg_read(pdata, RX_DATA_FIFO);
+ goto out;
}
BUG();
+out:
+ spin_unlock_irqrestore(&pdata->dev_lock, flags);
}
/* waits for MAC not busy, with timeout. Only called by smsc911x_mac_read
@@ -1538,7 +1550,7 @@ static int smsc911x_do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
if (!netif_running(dev) || !pdata->phy_dev)
return -EINVAL;
- return phy_mii_ioctl(pdata->phy_dev, if_mii(ifr), cmd);
+ return phy_mii_ioctl(pdata->phy_dev, ifr, cmd);
}
static int
diff --git a/drivers/net/smsc9420.c b/drivers/net/smsc9420.c
index 6cdee6a15f9..b09ee1c319e 100644
--- a/drivers/net/smsc9420.c
+++ b/drivers/net/smsc9420.c
@@ -245,7 +245,7 @@ static int smsc9420_do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
if (!netif_running(dev) || !pd->phy_dev)
return -EINVAL;
- return phy_mii_ioctl(pd->phy_dev, if_mii(ifr), cmd);
+ return phy_mii_ioctl(pd->phy_dev, ifr, cmd);
}
static int smsc9420_ethtool_get_settings(struct net_device *dev,
diff --git a/drivers/net/starfire.c b/drivers/net/starfire.c
index 74b7ae76906..a42b6873370 100644
--- a/drivers/net/starfire.c
+++ b/drivers/net/starfire.c
@@ -562,7 +562,6 @@ struct netdev_private {
unsigned int tx_done;
struct napi_struct napi;
struct net_device *dev;
- struct net_device_stats stats;
struct pci_dev *pci_dev;
#ifdef VLAN_SUPPORT
struct vlan_group *vlgrp;
@@ -1174,7 +1173,7 @@ static void tx_timeout(struct net_device *dev)
/* Trigger an immediate transmit demand. */
dev->trans_start = jiffies; /* prevent tx timeout */
- np->stats.tx_errors++;
+ dev->stats.tx_errors++;
netif_wake_queue(dev);
}
@@ -1265,7 +1264,7 @@ static netdev_tx_t start_tx(struct sk_buff *skb, struct net_device *dev)
}
if (skb->ip_summed == CHECKSUM_PARTIAL) {
status |= TxCalTCP;
- np->stats.tx_compressed++;
+ dev->stats.tx_compressed++;
}
status |= skb_first_frag_len(skb) | (skb_num_frags(skb) << 16);
@@ -1374,7 +1373,7 @@ static irqreturn_t intr_handler(int irq, void *dev_instance)
printk(KERN_DEBUG "%s: Tx completion #%d entry %d is %#8.8x.\n",
dev->name, np->dirty_tx, np->tx_done, tx_status);
if ((tx_status & 0xe0000000) == 0xa0000000) {
- np->stats.tx_packets++;
+ dev->stats.tx_packets++;
} else if ((tx_status & 0xe0000000) == 0x80000000) {
u16 entry = (tx_status & 0x7fff) / sizeof(starfire_tx_desc);
struct sk_buff *skb = np->tx_info[entry].skb;
@@ -1462,9 +1461,9 @@ static int __netdev_rx(struct net_device *dev, int *quota)
/* There was an error. */
if (debug > 2)
printk(KERN_DEBUG " netdev_rx() Rx error was %#8.8x.\n", desc_status);
- np->stats.rx_errors++;
+ dev->stats.rx_errors++;
if (desc_status & RxFIFOErr)
- np->stats.rx_fifo_errors++;
+ dev->stats.rx_fifo_errors++;
goto next_rx;
}
@@ -1515,7 +1514,7 @@ static int __netdev_rx(struct net_device *dev, int *quota)
#endif
if (le16_to_cpu(desc->status2) & 0x0100) {
skb->ip_summed = CHECKSUM_UNNECESSARY;
- np->stats.rx_compressed++;
+ dev->stats.rx_compressed++;
}
/*
* This feature doesn't seem to be working, at least
@@ -1547,7 +1546,7 @@ static int __netdev_rx(struct net_device *dev, int *quota)
} else
#endif /* VLAN_SUPPORT */
netif_receive_skb(skb);
- np->stats.rx_packets++;
+ dev->stats.rx_packets++;
next_rx:
np->cur_rx++;
@@ -1717,12 +1716,12 @@ static void netdev_error(struct net_device *dev, int intr_status)
printk(KERN_WARNING "%s: PCI Tx underflow -- adapter is probably malfunctioning\n", dev->name);
}
if (intr_status & IntrRxGFPDead) {
- np->stats.rx_fifo_errors++;
- np->stats.rx_errors++;
+ dev->stats.rx_fifo_errors++;
+ dev->stats.rx_errors++;
}
if (intr_status & (IntrNoTxCsum | IntrDMAErr)) {
- np->stats.tx_fifo_errors++;
- np->stats.tx_errors++;
+ dev->stats.tx_fifo_errors++;
+ dev->stats.tx_errors++;
}
if ((intr_status & ~(IntrNormalMask | IntrAbnormalSummary | IntrLinkChange | IntrStatsMax | IntrTxDataLow | IntrRxGFPDead | IntrNoTxCsum | IntrPCIPad)) && debug)
printk(KERN_ERR "%s: Something Wicked happened! %#8.8x.\n",
@@ -1736,24 +1735,24 @@ static struct net_device_stats *get_stats(struct net_device *dev)
void __iomem *ioaddr = np->base;
/* This adapter architecture needs no SMP locks. */
- np->stats.tx_bytes = readl(ioaddr + 0x57010);
- np->stats.rx_bytes = readl(ioaddr + 0x57044);
- np->stats.tx_packets = readl(ioaddr + 0x57000);
- np->stats.tx_aborted_errors =
+ dev->stats.tx_bytes = readl(ioaddr + 0x57010);
+ dev->stats.rx_bytes = readl(ioaddr + 0x57044);
+ dev->stats.tx_packets = readl(ioaddr + 0x57000);
+ dev->stats.tx_aborted_errors =
readl(ioaddr + 0x57024) + readl(ioaddr + 0x57028);
- np->stats.tx_window_errors = readl(ioaddr + 0x57018);
- np->stats.collisions =
+ dev->stats.tx_window_errors = readl(ioaddr + 0x57018);
+ dev->stats.collisions =
readl(ioaddr + 0x57004) + readl(ioaddr + 0x57008);
/* The chip only need report frame silently dropped. */
- np->stats.rx_dropped += readw(ioaddr + RxDMAStatus);
+ dev->stats.rx_dropped += readw(ioaddr + RxDMAStatus);
writew(0, ioaddr + RxDMAStatus);
- np->stats.rx_crc_errors = readl(ioaddr + 0x5703C);
- np->stats.rx_frame_errors = readl(ioaddr + 0x57040);
- np->stats.rx_length_errors = readl(ioaddr + 0x57058);
- np->stats.rx_missed_errors = readl(ioaddr + 0x5707C);
+ dev->stats.rx_crc_errors = readl(ioaddr + 0x5703C);
+ dev->stats.rx_frame_errors = readl(ioaddr + 0x57040);
+ dev->stats.rx_length_errors = readl(ioaddr + 0x57058);
+ dev->stats.rx_missed_errors = readl(ioaddr + 0x5707C);
- return &np->stats;
+ return &dev->stats;
}
diff --git a/drivers/net/stmmac/common.h b/drivers/net/stmmac/common.h
index 144f76fd3e3..66b9da0260f 100644
--- a/drivers/net/stmmac/common.h
+++ b/drivers/net/stmmac/common.h
@@ -108,6 +108,7 @@ enum rx_frame_status { /* IPC status */
good_frame = 0,
discard_frame = 1,
csum_none = 2,
+ llc_snap = 4,
};
enum tx_dma_irq_status {
diff --git a/drivers/net/stmmac/dwmac1000.h b/drivers/net/stmmac/dwmac1000.h
index d8d0f355377..8b20b19971c 100644
--- a/drivers/net/stmmac/dwmac1000.h
+++ b/drivers/net/stmmac/dwmac1000.h
@@ -93,7 +93,7 @@ enum inter_frame_gap {
#define GMAC_CONTROL_IPC 0x00000400 /* Checksum Offload */
#define GMAC_CONTROL_DR 0x00000200 /* Disable Retry */
#define GMAC_CONTROL_LUD 0x00000100 /* Link up/down */
-#define GMAC_CONTROL_ACS 0x00000080 /* Automatic Pad Stripping */
+#define GMAC_CONTROL_ACS 0x00000080 /* Automatic Pad/FCS Stripping */
#define GMAC_CONTROL_DC 0x00000010 /* Deferral Check */
#define GMAC_CONTROL_TE 0x00000008 /* Transmitter Enable */
#define GMAC_CONTROL_RE 0x00000004 /* Receiver Enable */
diff --git a/drivers/net/stmmac/dwmac1000_core.c b/drivers/net/stmmac/dwmac1000_core.c
index 917b4e16923..2b2f5c8caf1 100644
--- a/drivers/net/stmmac/dwmac1000_core.c
+++ b/drivers/net/stmmac/dwmac1000_core.c
@@ -220,6 +220,8 @@ struct mac_device_info *dwmac1000_setup(unsigned long ioaddr)
((uid & 0x0000ff00) >> 8), (uid & 0x000000ff));
mac = kzalloc(sizeof(const struct mac_device_info), GFP_KERNEL);
+ if (!mac)
+ return NULL;
mac->mac = &dwmac1000_ops;
mac->dma = &dwmac1000_dma_ops;
diff --git a/drivers/net/stmmac/dwmac100_core.c b/drivers/net/stmmac/dwmac100_core.c
index 6f270a0e151..2fb165fa2ba 100644
--- a/drivers/net/stmmac/dwmac100_core.c
+++ b/drivers/net/stmmac/dwmac100_core.c
@@ -179,6 +179,8 @@ struct mac_device_info *dwmac100_setup(unsigned long ioaddr)
struct mac_device_info *mac;
mac = kzalloc(sizeof(const struct mac_device_info), GFP_KERNEL);
+ if (!mac)
+ return NULL;
pr_info("\tDWMAC100\n");
diff --git a/drivers/net/stmmac/enh_desc.c b/drivers/net/stmmac/enh_desc.c
index 3c18ebece04..f612f986a7e 100644
--- a/drivers/net/stmmac/enh_desc.c
+++ b/drivers/net/stmmac/enh_desc.c
@@ -123,7 +123,7 @@ static int enh_desc_coe_rdes0(int ipc_err, int type, int payload_err)
*/
if (status == 0x0) {
CHIP_DBG(KERN_INFO "RX Des0 status: IEEE 802.3 Type frame.\n");
- ret = good_frame;
+ ret = llc_snap;
} else if (status == 0x4) {
CHIP_DBG(KERN_INFO "RX Des0 status: IPv4/6 No CSUM errorS.\n");
ret = good_frame;
diff --git a/drivers/net/stmmac/stmmac_main.c b/drivers/net/stmmac/stmmac_main.c
index a31d580f306..bbb7951b9c4 100644
--- a/drivers/net/stmmac/stmmac_main.c
+++ b/drivers/net/stmmac/stmmac_main.c
@@ -829,7 +829,6 @@ static int stmmac_open(struct net_device *dev)
* In case of failure continue without timer. */
if (unlikely((stmmac_open_ext_timer(dev, priv->tm)) < 0)) {
pr_warning("stmmaceth: cannot attach the external timer.\n");
- tmrate = 0;
priv->tm->freq = 0;
priv->tm->timer_start = stmmac_no_timer_started;
priv->tm->timer_stop = stmmac_no_timer_stopped;
@@ -1217,9 +1216,13 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit)
priv->dev->stats.rx_errors++;
else {
struct sk_buff *skb;
- /* Length should omit the CRC */
- int frame_len = priv->hw->desc->get_rx_frame_len(p) - 4;
+ int frame_len;
+ frame_len = priv->hw->desc->get_rx_frame_len(p);
+ /* ACS is set; GMAC core strips PAD/FCS for IEEE 802.3
+ * Type frames (LLC/LLC-SNAP) */
+ if (unlikely(status != llc_snap))
+ frame_len -= ETH_FCS_LEN;
#ifdef STMMAC_RX_DEBUG
if (frame_len > ETH_FRAME_LEN)
pr_debug("\tRX frame size %d, COE status: %d\n",
@@ -1437,24 +1440,18 @@ static void stmmac_poll_controller(struct net_device *dev)
static int stmmac_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
{
struct stmmac_priv *priv = netdev_priv(dev);
- int ret = -EOPNOTSUPP;
+ int ret;
if (!netif_running(dev))
return -EINVAL;
- switch (cmd) {
- case SIOCGMIIPHY:
- case SIOCGMIIREG:
- case SIOCSMIIREG:
- if (!priv->phydev)
- return -EINVAL;
-
- spin_lock(&priv->lock);
- ret = phy_mii_ioctl(priv->phydev, if_mii(rq), cmd);
- spin_unlock(&priv->lock);
- default:
- break;
- }
+ if (!priv->phydev)
+ return -EINVAL;
+
+ spin_lock(&priv->lock);
+ ret = phy_mii_ioctl(priv->phydev, rq, cmd);
+ spin_unlock(&priv->lock);
+
return ret;
}
@@ -1564,15 +1561,15 @@ static int stmmac_mac_device_setup(struct net_device *dev)
else
device = dwmac100_setup(ioaddr);
+ if (!device)
+ return -ENOMEM;
+
if (priv->enh_desc) {
device->desc = &enh_desc_ops;
pr_info("\tEnhanced descriptor structure\n");
} else
device->desc = &ndesc_ops;
- if (!device)
- return -ENOMEM;
-
priv->hw = device;
priv->wolenabled = priv->hw->pmt; /* PMT supported */
diff --git a/drivers/net/sun3_82586.c b/drivers/net/sun3_82586.c
index 15131234224..b6ae53bada7 100644
--- a/drivers/net/sun3_82586.c
+++ b/drivers/net/sun3_82586.c
@@ -142,7 +142,6 @@ static void sun3_82586_rnr_int(struct net_device *dev);
struct priv
{
- struct net_device_stats stats;
unsigned long base;
char *memtop;
long int lock;
@@ -788,10 +787,10 @@ static void sun3_82586_rcv_int(struct net_device *dev)
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++;
+ dev->stats.rx_packets++;
}
else
- p->stats.rx_dropped++;
+ dev->stats.rx_dropped++;
}
else
{
@@ -812,13 +811,13 @@ static void sun3_82586_rcv_int(struct net_device *dev)
totlen += rstat & RBD_MASK;
rbd->status = 0;
printk("%s: received oversized frame! length: %d\n",dev->name,totlen);
- p->stats.rx_dropped++;
+ dev->stats.rx_dropped++;
}
}
else /* frame !(ok), only with 'save-bad-frames' */
{
printk("%s: oops! rfd-error-status: %04x\n",dev->name,status);
- p->stats.rx_errors++;
+ dev->stats.rx_errors++;
}
p->rfd_top->stat_high = 0;
p->rfd_top->last = RFD_SUSP; /* maybe exchange by RFD_LAST */
@@ -885,7 +884,7 @@ static void sun3_82586_rnr_int(struct net_device *dev)
{
struct priv *p = netdev_priv(dev);
- p->stats.rx_errors++;
+ dev->stats.rx_errors++;
WAIT_4_SCB_CMD(); /* wait for the last cmd, WAIT_4_FULLSTAT?? */
p->scb->cmd_ruc = RUC_ABORT; /* usually the RU is in the 'no resource'-state .. abort it now. */
@@ -918,29 +917,29 @@ static void sun3_82586_xmt_int(struct net_device *dev)
if(status & STAT_OK)
{
- p->stats.tx_packets++;
- p->stats.collisions += (status & TCMD_MAXCOLLMASK);
+ dev->stats.tx_packets++;
+ dev->stats.collisions += (status & TCMD_MAXCOLLMASK);
}
else
{
- p->stats.tx_errors++;
+ dev->stats.tx_errors++;
if(status & TCMD_LATECOLL) {
printk("%s: late collision detected.\n",dev->name);
- p->stats.collisions++;
+ dev->stats.collisions++;
}
else if(status & TCMD_NOCARRIER) {
- p->stats.tx_carrier_errors++;
+ dev->stats.tx_carrier_errors++;
printk("%s: no carrier detected.\n",dev->name);
}
else if(status & TCMD_LOSTCTS)
printk("%s: loss of CTS detected.\n",dev->name);
else if(status & TCMD_UNDERRUN) {
- p->stats.tx_fifo_errors++;
+ dev->stats.tx_fifo_errors++;
printk("%s: DMA underrun detected.\n",dev->name);
}
else if(status & TCMD_MAXCOLL) {
printk("%s: Max. collisions exceeded.\n",dev->name);
- p->stats.collisions += 16;
+ dev->stats.collisions += 16;
}
}
@@ -1129,12 +1128,12 @@ static struct net_device_stats *sun3_82586_get_stats(struct net_device *dev)
ovrn = swab16(p->scb->ovrn_errs);
p->scb->ovrn_errs = 0;
- p->stats.rx_crc_errors += crc;
- p->stats.rx_fifo_errors += ovrn;
- p->stats.rx_frame_errors += aln;
- p->stats.rx_dropped += rsc;
+ dev->stats.rx_crc_errors += crc;
+ dev->stats.rx_fifo_errors += ovrn;
+ dev->stats.rx_frame_errors += aln;
+ dev->stats.rx_dropped += rsc;
- return &p->stats;
+ return &dev->stats;
}
/********************************************************
diff --git a/drivers/net/sunbmac.c b/drivers/net/sunbmac.c
index 367e96f317d..09c071bd6ad 100644
--- a/drivers/net/sunbmac.c
+++ b/drivers/net/sunbmac.c
@@ -1201,7 +1201,7 @@ static int __devinit bigmac_ether_init(struct of_device *op,
dev->watchdog_timeo = 5*HZ;
/* Finish net device registration. */
- dev->irq = bp->bigmac_op->irqs[0];
+ dev->irq = bp->bigmac_op->archdata.irqs[0];
dev->dma = 0;
if (register_netdev(dev)) {
@@ -1301,12 +1301,12 @@ static struct of_platform_driver bigmac_sbus_driver = {
static int __init bigmac_init(void)
{
- return of_register_driver(&bigmac_sbus_driver, &of_bus_type);
+ return of_register_platform_driver(&bigmac_sbus_driver);
}
static void __exit bigmac_exit(void)
{
- of_unregister_driver(&bigmac_sbus_driver);
+ of_unregister_platform_driver(&bigmac_sbus_driver);
}
module_init(bigmac_init);
diff --git a/drivers/net/sunhme.c b/drivers/net/sunhme.c
index 3d9650b8d38..eec443f6407 100644
--- a/drivers/net/sunhme.c
+++ b/drivers/net/sunhme.c
@@ -2561,7 +2561,7 @@ static int __init quattro_sbus_register_irqs(void)
if (skip)
continue;
- err = request_irq(op->irqs[0],
+ err = request_irq(op->archdata.irqs[0],
quattro_sbus_interrupt,
IRQF_SHARED, "Quattro",
qp);
@@ -2590,7 +2590,7 @@ static void quattro_sbus_free_irqs(void)
if (skip)
continue;
- free_irq(op->irqs[0], qp);
+ free_irq(op->archdata.irqs[0], qp);
}
}
#endif /* CONFIG_SBUS */
@@ -2790,7 +2790,7 @@ static int __devinit happy_meal_sbus_probe_one(struct of_device *op, int is_qfe)
/* Happy Meal can do it all... */
dev->features |= NETIF_F_SG | NETIF_F_HW_CSUM;
- dev->irq = op->irqs[0];
+ dev->irq = op->archdata.irqs[0];
#if defined(CONFIG_SBUS) && defined(CONFIG_PCI)
/* Hook up SBUS register/descriptor accessors. */
@@ -3304,7 +3304,7 @@ static int __init happy_meal_sbus_init(void)
{
int err;
- err = of_register_driver(&hme_sbus_driver, &of_bus_type);
+ err = of_register_platform_driver(&hme_sbus_driver);
if (!err)
err = quattro_sbus_register_irqs();
@@ -3313,7 +3313,7 @@ static int __init happy_meal_sbus_init(void)
static void happy_meal_sbus_exit(void)
{
- of_unregister_driver(&hme_sbus_driver);
+ of_unregister_platform_driver(&hme_sbus_driver);
quattro_sbus_free_irqs();
while (qfe_sbus_list) {
diff --git a/drivers/net/sunlance.c b/drivers/net/sunlance.c
index 7d9c33dd9d1..ee364fa7563 100644
--- a/drivers/net/sunlance.c
+++ b/drivers/net/sunlance.c
@@ -1474,7 +1474,7 @@ no_link_test:
dev->ethtool_ops = &sparc_lance_ethtool_ops;
dev->netdev_ops = &sparc_lance_ops;
- dev->irq = op->irqs[0];
+ dev->irq = op->archdata.irqs[0];
/* We cannot sleep if the chip is busy during a
* multicast list update event, because such events
@@ -1558,12 +1558,12 @@ static struct of_platform_driver sunlance_sbus_driver = {
/* Find all the lance cards on the system and initialize them */
static int __init sparc_lance_init(void)
{
- return of_register_driver(&sunlance_sbus_driver, &of_bus_type);
+ return of_register_platform_driver(&sunlance_sbus_driver);
}
static void __exit sparc_lance_exit(void)
{
- of_unregister_driver(&sunlance_sbus_driver);
+ of_unregister_platform_driver(&sunlance_sbus_driver);
}
module_init(sparc_lance_init);
diff --git a/drivers/net/sunqe.c b/drivers/net/sunqe.c
index 72b579c8d81..5f84a5daded 100644
--- a/drivers/net/sunqe.c
+++ b/drivers/net/sunqe.c
@@ -803,7 +803,7 @@ static struct sunqec * __devinit get_qec(struct of_device *child)
qec_init_once(qecp, op);
- if (request_irq(op->irqs[0], qec_interrupt,
+ if (request_irq(op->archdata.irqs[0], qec_interrupt,
IRQF_SHARED, "qec", (void *) qecp)) {
printk(KERN_ERR "qec: Can't register irq.\n");
goto fail;
@@ -901,7 +901,7 @@ static int __devinit qec_ether_init(struct of_device *op)
SET_NETDEV_DEV(dev, &op->dev);
dev->watchdog_timeo = 5*HZ;
- dev->irq = op->irqs[0];
+ dev->irq = op->archdata.irqs[0];
dev->dma = 0;
dev->ethtool_ops = &qe_ethtool_ops;
dev->netdev_ops = &qec_ops;
@@ -988,18 +988,18 @@ static struct of_platform_driver qec_sbus_driver = {
static int __init qec_init(void)
{
- return of_register_driver(&qec_sbus_driver, &of_bus_type);
+ return of_register_platform_driver(&qec_sbus_driver);
}
static void __exit qec_exit(void)
{
- of_unregister_driver(&qec_sbus_driver);
+ of_unregister_platform_driver(&qec_sbus_driver);
while (root_qec_dev) {
struct sunqec *next = root_qec_dev->next_module;
struct of_device *op = root_qec_dev->op;
- free_irq(op->irqs[0], (void *) root_qec_dev);
+ free_irq(op->archdata.irqs[0], (void *) root_qec_dev);
of_iounmap(&op->resource[0], root_qec_dev->gregs,
GLOB_REG_SIZE);
kfree(root_qec_dev);
diff --git a/drivers/net/tc35815.c b/drivers/net/tc35815.c
index be08b75dbc1..99e423a5b9f 100644
--- a/drivers/net/tc35815.c
+++ b/drivers/net/tc35815.c
@@ -2066,7 +2066,7 @@ static int tc35815_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
return -EINVAL;
if (!lp->phy_dev)
return -ENODEV;
- return phy_mii_ioctl(lp->phy_dev, if_mii(rq), cmd);
+ return phy_mii_ioctl(lp->phy_dev, rq, cmd);
}
static void tc35815_chip_reset(struct net_device *dev)
diff --git a/drivers/net/tehuti.h b/drivers/net/tehuti.h
index cff98d07cba..67e3b71bf70 100644
--- a/drivers/net/tehuti.h
+++ b/drivers/net/tehuti.h
@@ -334,7 +334,7 @@ struct txd_desc {
u32 va_lo;
u32 va_hi;
struct pbl pbl[0]; /* Fragments */
-} __attribute__ ((packed));
+} __packed;
/* Register region size */
#define BDX_REGS_SIZE 0x1000
diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c
index 573054ae7b5..bc3af78a869 100644
--- a/drivers/net/tg3.c
+++ b/drivers/net/tg3.c
@@ -18,6 +18,7 @@
#include <linux/module.h>
#include <linux/moduleparam.h>
+#include <linux/stringify.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/compiler.h>
@@ -67,8 +68,11 @@
#include "tg3.h"
#define DRV_MODULE_NAME "tg3"
-#define DRV_MODULE_VERSION "3.110"
-#define DRV_MODULE_RELDATE "April 9, 2010"
+#define TG3_MAJ_NUM 3
+#define TG3_MIN_NUM 113
+#define DRV_MODULE_VERSION \
+ __stringify(TG3_MAJ_NUM) "." __stringify(TG3_MIN_NUM)
+#define DRV_MODULE_RELDATE "August 2, 2010"
#define TG3_DEF_MAC_MODE 0
#define TG3_DEF_RX_MODE 0
@@ -145,8 +149,6 @@
#define TG3_RX_JMB_BUFF_RING_SIZE \
(sizeof(struct ring_info) * TG3_RX_JUMBO_RING_SIZE)
-#define TG3_RSS_MIN_NUM_MSIX_VECS 2
-
/* Due to a hardware bug, the 5701 can only DMA to memory addresses
* that are at least dword aligned when used in PCIX mode. The driver
* works around this bug by double copying the packet. This workaround
@@ -219,12 +221,9 @@ static DEFINE_PCI_DEVICE_TABLE(tg3_pci_tbl) = {
{PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5901_2)},
{PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5704S_2)},
{PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5705F)},
- {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5720)},
{PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5721)},
{PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5722)},
- {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5750)},
{PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5751)},
- {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5750M)},
{PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5751M)},
{PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5751F)},
{PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5752)},
@@ -272,6 +271,7 @@ static DEFINE_PCI_DEVICE_TABLE(tg3_pci_tbl) = {
{PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_57765)},
{PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_57791)},
{PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_57795)},
+ {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_5719)},
{PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, PCI_DEVICE_ID_SYSKONNECT_9DXX)},
{PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, PCI_DEVICE_ID_SYSKONNECT_9MXX)},
{PCI_DEVICE(PCI_VENDOR_ID_ALTIMA, PCI_DEVICE_ID_ALTIMA_AC1000)},
@@ -585,18 +585,23 @@ static void tg3_read_mem(struct tg3 *tp, u32 off, u32 *val)
static void tg3_ape_lock_init(struct tg3 *tp)
{
int i;
+ u32 regbase;
+
+ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761)
+ regbase = TG3_APE_LOCK_GRANT;
+ else
+ regbase = TG3_APE_PER_LOCK_GRANT;
/* Make sure the driver hasn't any stale locks. */
for (i = 0; i < 8; i++)
- tg3_ape_write32(tp, TG3_APE_LOCK_GRANT + 4 * i,
- APE_LOCK_GRANT_DRIVER);
+ tg3_ape_write32(tp, regbase + 4 * i, APE_LOCK_GRANT_DRIVER);
}
static int tg3_ape_lock(struct tg3 *tp, int locknum)
{
int i, off;
int ret = 0;
- u32 status;
+ u32 status, req, gnt;
if (!(tp->tg3_flags3 & TG3_FLG3_ENABLE_APE))
return 0;
@@ -609,13 +614,21 @@ static int tg3_ape_lock(struct tg3 *tp, int locknum)
return -EINVAL;
}
+ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761) {
+ req = TG3_APE_LOCK_REQ;
+ gnt = TG3_APE_LOCK_GRANT;
+ } else {
+ req = TG3_APE_PER_LOCK_REQ;
+ gnt = TG3_APE_PER_LOCK_GRANT;
+ }
+
off = 4 * locknum;
- tg3_ape_write32(tp, TG3_APE_LOCK_REQ + off, APE_LOCK_REQ_DRIVER);
+ tg3_ape_write32(tp, req + off, APE_LOCK_REQ_DRIVER);
/* Wait for up to 1 millisecond to acquire lock. */
for (i = 0; i < 100; i++) {
- status = tg3_ape_read32(tp, TG3_APE_LOCK_GRANT + off);
+ status = tg3_ape_read32(tp, gnt + off);
if (status == APE_LOCK_GRANT_DRIVER)
break;
udelay(10);
@@ -623,7 +636,7 @@ static int tg3_ape_lock(struct tg3 *tp, int locknum)
if (status != APE_LOCK_GRANT_DRIVER) {
/* Revoke the lock request. */
- tg3_ape_write32(tp, TG3_APE_LOCK_GRANT + off,
+ tg3_ape_write32(tp, gnt + off,
APE_LOCK_GRANT_DRIVER);
ret = -EBUSY;
@@ -634,7 +647,7 @@ static int tg3_ape_lock(struct tg3 *tp, int locknum)
static void tg3_ape_unlock(struct tg3 *tp, int locknum)
{
- int off;
+ u32 gnt;
if (!(tp->tg3_flags3 & TG3_FLG3_ENABLE_APE))
return;
@@ -647,8 +660,12 @@ static void tg3_ape_unlock(struct tg3 *tp, int locknum)
return;
}
- off = 4 * locknum;
- tg3_ape_write32(tp, TG3_APE_LOCK_GRANT + off, APE_LOCK_GRANT_DRIVER);
+ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761)
+ gnt = TG3_APE_LOCK_GRANT;
+ else
+ gnt = TG3_APE_PER_LOCK_GRANT;
+
+ tg3_ape_write32(tp, gnt + 4 * locknum, APE_LOCK_GRANT_DRIVER);
}
static void tg3_disable_ints(struct tg3 *tp)
@@ -862,7 +879,7 @@ static int tg3_writephy(struct tg3 *tp, int reg, u32 val)
unsigned int loops;
int ret;
- if ((tp->tg3_flags3 & TG3_FLG3_PHY_IS_FET) &&
+ if ((tp->phy_flags & TG3_PHYFLG_IS_FET) &&
(reg == MII_TG3_CTRL || reg == MII_TG3_AUX_CTRL))
return 0;
@@ -1069,14 +1086,11 @@ static int tg3_mdio_init(struct tg3 *tp)
u32 reg;
struct phy_device *phydev;
- if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717) {
- u32 funcnum, is_serdes;
+ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 ||
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719) {
+ u32 is_serdes;
- funcnum = tr32(TG3_CPMU_STATUS) & TG3_CPMU_STATUS_PCIE_FUNC;
- if (funcnum)
- tp->phy_addr = 2;
- else
- tp->phy_addr = 1;
+ tp->phy_addr = PCI_FUNC(tp->pdev->devfn) + 1;
if (tp->pci_chip_rev_id != CHIPREV_ID_5717_A0)
is_serdes = tr32(SG_DIG_STATUS) & SG_DIG_IS_SERDES;
@@ -1161,7 +1175,7 @@ static int tg3_mdio_init(struct tg3 *tp)
case PHY_ID_BCMAC131:
phydev->interface = PHY_INTERFACE_MODE_MII;
phydev->dev_flags |= PHY_BRCM_AUTO_PWRDWN_ENABLE;
- tp->tg3_flags3 |= TG3_FLG3_PHY_IS_FET;
+ tp->phy_flags |= TG3_PHYFLG_IS_FET;
break;
}
@@ -1254,7 +1268,7 @@ static void tg3_ump_link_report(struct tg3 *tp)
tg3_write_mem(tp, NIC_SRAM_FW_CMD_DATA_MBOX + 4, val);
val = 0;
- if (!(tp->tg3_flags2 & TG3_FLG2_MII_SERDES)) {
+ if (!(tp->phy_flags & TG3_PHYFLG_MII_SERDES)) {
if (!tg3_readphy(tp, MII_CTRL1000, &reg))
val = reg << 16;
if (!tg3_readphy(tp, MII_STAT1000, &reg))
@@ -1362,7 +1376,7 @@ static void tg3_setup_flow_control(struct tg3 *tp, u32 lcladv, u32 rmtadv)
if (autoneg == AUTONEG_ENABLE &&
(tp->tg3_flags & TG3_FLAG_PAUSE_AUTONEG)) {
- if (tp->tg3_flags2 & TG3_FLG2_ANY_SERDES)
+ if (tp->phy_flags & TG3_PHYFLG_ANY_SERDES)
flowctrl = tg3_resolve_flowctrl_1000X(lcladv, rmtadv);
else
flowctrl = mii_resolve_flowctrl_fdx(lcladv, rmtadv);
@@ -1476,7 +1490,7 @@ static int tg3_phy_init(struct tg3 *tp)
{
struct phy_device *phydev;
- if (tp->tg3_flags3 & TG3_FLG3_PHY_CONNECTED)
+ if (tp->phy_flags & TG3_PHYFLG_IS_CONNECTED)
return 0;
/* Bring the PHY back to a known state. */
@@ -1496,7 +1510,7 @@ static int tg3_phy_init(struct tg3 *tp)
switch (phydev->interface) {
case PHY_INTERFACE_MODE_GMII:
case PHY_INTERFACE_MODE_RGMII:
- if (!(tp->tg3_flags & TG3_FLAG_10_100_ONLY)) {
+ if (!(tp->phy_flags & TG3_PHYFLG_10_100_ONLY)) {
phydev->supported &= (PHY_GBIT_FEATURES |
SUPPORTED_Pause |
SUPPORTED_Asym_Pause);
@@ -1513,7 +1527,7 @@ static int tg3_phy_init(struct tg3 *tp)
return -EINVAL;
}
- tp->tg3_flags3 |= TG3_FLG3_PHY_CONNECTED;
+ tp->phy_flags |= TG3_PHYFLG_IS_CONNECTED;
phydev->advertising = phydev->supported;
@@ -1524,13 +1538,13 @@ static void tg3_phy_start(struct tg3 *tp)
{
struct phy_device *phydev;
- if (!(tp->tg3_flags3 & TG3_FLG3_PHY_CONNECTED))
+ if (!(tp->phy_flags & TG3_PHYFLG_IS_CONNECTED))
return;
phydev = tp->mdio_bus->phy_map[TG3_PHY_MII_ADDR];
- if (tp->link_config.phy_is_low_power) {
- tp->link_config.phy_is_low_power = 0;
+ if (tp->phy_flags & TG3_PHYFLG_IS_LOW_POWER) {
+ tp->phy_flags &= ~TG3_PHYFLG_IS_LOW_POWER;
phydev->speed = tp->link_config.orig_speed;
phydev->duplex = tp->link_config.orig_duplex;
phydev->autoneg = tp->link_config.orig_autoneg;
@@ -1544,7 +1558,7 @@ static void tg3_phy_start(struct tg3 *tp)
static void tg3_phy_stop(struct tg3 *tp)
{
- if (!(tp->tg3_flags3 & TG3_FLG3_PHY_CONNECTED))
+ if (!(tp->phy_flags & TG3_PHYFLG_IS_CONNECTED))
return;
phy_stop(tp->mdio_bus->phy_map[TG3_PHY_MII_ADDR]);
@@ -1552,16 +1566,21 @@ static void tg3_phy_stop(struct tg3 *tp)
static void tg3_phy_fini(struct tg3 *tp)
{
- if (tp->tg3_flags3 & TG3_FLG3_PHY_CONNECTED) {
+ if (tp->phy_flags & TG3_PHYFLG_IS_CONNECTED) {
phy_disconnect(tp->mdio_bus->phy_map[TG3_PHY_MII_ADDR]);
- tp->tg3_flags3 &= ~TG3_FLG3_PHY_CONNECTED;
+ tp->phy_flags &= ~TG3_PHYFLG_IS_CONNECTED;
}
}
-static void tg3_phydsp_write(struct tg3 *tp, u32 reg, u32 val)
+static int tg3_phydsp_write(struct tg3 *tp, u32 reg, u32 val)
{
- tg3_writephy(tp, MII_TG3_DSP_ADDRESS, reg);
- tg3_writephy(tp, MII_TG3_DSP_RW_PORT, val);
+ int err;
+
+ err = tg3_writephy(tp, MII_TG3_DSP_ADDRESS, reg);
+ if (!err)
+ err = tg3_writephy(tp, MII_TG3_DSP_RW_PORT, val);
+
+ return err;
}
static void tg3_phy_fet_toggle_apd(struct tg3 *tp, bool enable)
@@ -1589,11 +1608,12 @@ static void tg3_phy_toggle_apd(struct tg3 *tp, bool enable)
u32 reg;
if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS) ||
- (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 &&
- (tp->tg3_flags2 & TG3_FLG2_MII_SERDES)))
+ ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 ||
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719) &&
+ (tp->phy_flags & TG3_PHYFLG_MII_SERDES)))
return;
- if (tp->tg3_flags3 & TG3_FLG3_PHY_IS_FET) {
+ if (tp->phy_flags & TG3_PHYFLG_IS_FET) {
tg3_phy_fet_toggle_apd(tp, enable);
return;
}
@@ -1624,10 +1644,10 @@ 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))
+ (tp->phy_flags & TG3_PHYFLG_ANY_SERDES))
return;
- if (tp->tg3_flags3 & TG3_FLG3_PHY_IS_FET) {
+ if (tp->phy_flags & TG3_PHYFLG_IS_FET) {
u32 ephy;
if (!tg3_readphy(tp, MII_TG3_FET_TEST, &ephy)) {
@@ -1663,7 +1683,7 @@ static void tg3_phy_set_wirespeed(struct tg3 *tp)
{
u32 val;
- if (tp->tg3_flags2 & TG3_FLG2_NO_ETH_WIRE_SPEED)
+ if (tp->phy_flags & TG3_PHYFLG_NO_ETH_WIRE_SPEED)
return;
if (!tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x7007) &&
@@ -1722,7 +1742,7 @@ static int tg3_wait_macro_done(struct tg3 *tp)
while (limit--) {
u32 tmp32;
- if (!tg3_readphy(tp, 0x16, &tmp32)) {
+ if (!tg3_readphy(tp, MII_TG3_DSP_CONTROL, &tmp32)) {
if ((tmp32 & 0x1000) == 0)
break;
}
@@ -1748,13 +1768,13 @@ static int tg3_phy_write_and_check_testpat(struct tg3 *tp, int *resetp)
tg3_writephy(tp, MII_TG3_DSP_ADDRESS,
(chan * 0x2000) | 0x0200);
- tg3_writephy(tp, 0x16, 0x0002);
+ tg3_writephy(tp, MII_TG3_DSP_CONTROL, 0x0002);
for (i = 0; i < 6; i++)
tg3_writephy(tp, MII_TG3_DSP_RW_PORT,
test_pat[chan][i]);
- tg3_writephy(tp, 0x16, 0x0202);
+ tg3_writephy(tp, MII_TG3_DSP_CONTROL, 0x0202);
if (tg3_wait_macro_done(tp)) {
*resetp = 1;
return -EBUSY;
@@ -1762,13 +1782,13 @@ static int tg3_phy_write_and_check_testpat(struct tg3 *tp, int *resetp)
tg3_writephy(tp, MII_TG3_DSP_ADDRESS,
(chan * 0x2000) | 0x0200);
- tg3_writephy(tp, 0x16, 0x0082);
+ tg3_writephy(tp, MII_TG3_DSP_CONTROL, 0x0082);
if (tg3_wait_macro_done(tp)) {
*resetp = 1;
return -EBUSY;
}
- tg3_writephy(tp, 0x16, 0x0802);
+ tg3_writephy(tp, MII_TG3_DSP_CONTROL, 0x0802);
if (tg3_wait_macro_done(tp)) {
*resetp = 1;
return -EBUSY;
@@ -1808,10 +1828,10 @@ static int tg3_phy_reset_chanpat(struct tg3 *tp)
tg3_writephy(tp, MII_TG3_DSP_ADDRESS,
(chan * 0x2000) | 0x0200);
- tg3_writephy(tp, 0x16, 0x0002);
+ tg3_writephy(tp, MII_TG3_DSP_CONTROL, 0x0002);
for (i = 0; i < 6; i++)
tg3_writephy(tp, MII_TG3_DSP_RW_PORT, 0x000);
- tg3_writephy(tp, 0x16, 0x0202);
+ tg3_writephy(tp, MII_TG3_DSP_CONTROL, 0x0202);
if (tg3_wait_macro_done(tp))
return -EBUSY;
}
@@ -1857,8 +1877,7 @@ static int tg3_phy_reset_5703_4_5(struct tg3 *tp)
tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x0c00);
/* Block the PHY control access. */
- tg3_writephy(tp, MII_TG3_DSP_ADDRESS, 0x8005);
- tg3_writephy(tp, MII_TG3_DSP_RW_PORT, 0x0800);
+ tg3_phydsp_write(tp, 0x8005, 0x0800);
err = tg3_phy_write_and_check_testpat(tp, &do_phy_reset);
if (!err)
@@ -1869,11 +1888,10 @@ static int tg3_phy_reset_5703_4_5(struct tg3 *tp)
if (err)
return err;
- tg3_writephy(tp, MII_TG3_DSP_ADDRESS, 0x8005);
- tg3_writephy(tp, MII_TG3_DSP_RW_PORT, 0x0000);
+ tg3_phydsp_write(tp, 0x8005, 0x0000);
tg3_writephy(tp, MII_TG3_DSP_ADDRESS, 0x8200);
- tg3_writephy(tp, 0x16, 0x0000);
+ tg3_writephy(tp, MII_TG3_DSP_CONTROL, 0x0000);
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5703 ||
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704) {
@@ -1964,43 +1982,39 @@ static int tg3_phy_reset(struct tg3 *tp)
}
}
- if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 &&
- (tp->tg3_flags2 & TG3_FLG2_MII_SERDES))
+ if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 ||
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719) &&
+ (tp->phy_flags & TG3_PHYFLG_MII_SERDES))
return 0;
tg3_phy_apply_otp(tp);
- if (tp->tg3_flags3 & TG3_FLG3_PHY_ENABLE_APD)
+ if (tp->phy_flags & TG3_PHYFLG_ENABLE_APD)
tg3_phy_toggle_apd(tp, true);
else
tg3_phy_toggle_apd(tp, false);
out:
- if (tp->tg3_flags2 & TG3_FLG2_PHY_ADC_BUG) {
+ if (tp->phy_flags & TG3_PHYFLG_ADC_BUG) {
tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x0c00);
- tg3_writephy(tp, MII_TG3_DSP_ADDRESS, 0x201f);
- tg3_writephy(tp, MII_TG3_DSP_RW_PORT, 0x2aaa);
- tg3_writephy(tp, MII_TG3_DSP_ADDRESS, 0x000a);
- tg3_writephy(tp, MII_TG3_DSP_RW_PORT, 0x0323);
+ tg3_phydsp_write(tp, 0x201f, 0x2aaa);
+ tg3_phydsp_write(tp, 0x000a, 0x0323);
tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x0400);
}
- if (tp->tg3_flags2 & TG3_FLG2_PHY_5704_A0_BUG) {
- tg3_writephy(tp, 0x1c, 0x8d68);
- tg3_writephy(tp, 0x1c, 0x8d68);
+ if (tp->phy_flags & TG3_PHYFLG_5704_A0_BUG) {
+ tg3_writephy(tp, MII_TG3_MISC_SHDW, 0x8d68);
+ tg3_writephy(tp, MII_TG3_MISC_SHDW, 0x8d68);
}
- if (tp->tg3_flags2 & TG3_FLG2_PHY_BER_BUG) {
+ if (tp->phy_flags & TG3_PHYFLG_BER_BUG) {
tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x0c00);
- tg3_writephy(tp, MII_TG3_DSP_ADDRESS, 0x000a);
- tg3_writephy(tp, MII_TG3_DSP_RW_PORT, 0x310b);
- tg3_writephy(tp, MII_TG3_DSP_ADDRESS, 0x201f);
- tg3_writephy(tp, MII_TG3_DSP_RW_PORT, 0x9506);
- tg3_writephy(tp, MII_TG3_DSP_ADDRESS, 0x401f);
- tg3_writephy(tp, MII_TG3_DSP_RW_PORT, 0x14e2);
+ tg3_phydsp_write(tp, 0x000a, 0x310b);
+ tg3_phydsp_write(tp, 0x201f, 0x9506);
+ tg3_phydsp_write(tp, 0x401f, 0x14e2);
tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x0400);
- } else if (tp->tg3_flags2 & TG3_FLG2_PHY_JITTER_BUG) {
+ } else if (tp->phy_flags & TG3_PHYFLG_JITTER_BUG) {
tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x0c00);
tg3_writephy(tp, MII_TG3_DSP_ADDRESS, 0x000a);
- if (tp->tg3_flags2 & TG3_FLG2_PHY_ADJUST_TRIM) {
+ if (tp->phy_flags & TG3_PHYFLG_ADJUST_TRIM) {
tg3_writephy(tp, MII_TG3_DSP_RW_PORT, 0x110b);
tg3_writephy(tp, MII_TG3_TEST1,
MII_TG3_TEST1_TRIM_EN | 0x4);
@@ -2049,6 +2063,7 @@ static void tg3_frob_aux_power(struct tg3 *tp)
/* The GPIOs do something completely different on 57765. */
if ((tp->tg3_flags2 & TG3_FLG2_IS_NIC) == 0 ||
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719 ||
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765)
return;
@@ -2184,7 +2199,7 @@ static void tg3_power_down_phy(struct tg3 *tp, bool do_low_power)
{
u32 val;
- if (tp->tg3_flags2 & TG3_FLG2_PHY_SERDES) {
+ if (tp->phy_flags & TG3_PHYFLG_PHY_SERDES) {
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704) {
u32 sg_dig_ctrl = tr32(SG_DIG_CTRL);
u32 serdes_cfg = tr32(MAC_SERDES_CFG);
@@ -2203,7 +2218,7 @@ static void tg3_power_down_phy(struct tg3 *tp, bool do_low_power)
tw32_f(GRC_MISC_CFG, val | GRC_MISC_CFG_EPHY_IDDQ);
udelay(40);
return;
- } else if (tp->tg3_flags3 & TG3_FLG3_PHY_IS_FET) {
+ } else if (tp->phy_flags & TG3_PHYFLG_IS_FET) {
u32 phytest;
if (!tg3_readphy(tp, MII_TG3_FET_TEST, &phytest)) {
u32 phy;
@@ -2240,7 +2255,7 @@ static void tg3_power_down_phy(struct tg3 *tp, bool do_low_power)
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700 ||
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704 ||
(GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5780 &&
- (tp->tg3_flags2 & TG3_FLG2_MII_SERDES)))
+ (tp->phy_flags & TG3_PHYFLG_MII_SERDES)))
return;
if (GET_CHIP_REV(tp->pci_chip_rev_id) == CHIPREV_5784_AX ||
@@ -2543,14 +2558,14 @@ static int tg3_set_power_state(struct tg3 *tp, pci_power_t state)
if (tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB) {
do_low_power = false;
- if ((tp->tg3_flags3 & TG3_FLG3_PHY_CONNECTED) &&
- !tp->link_config.phy_is_low_power) {
+ if ((tp->phy_flags & TG3_PHYFLG_IS_CONNECTED) &&
+ !(tp->phy_flags & TG3_PHYFLG_IS_LOW_POWER)) {
struct phy_device *phydev;
u32 phyid, advertising;
phydev = tp->mdio_bus->phy_map[TG3_PHY_MII_ADDR];
- tp->link_config.phy_is_low_power = 1;
+ tp->phy_flags |= TG3_PHYFLG_IS_LOW_POWER;
tp->link_config.orig_speed = phydev->speed;
tp->link_config.orig_duplex = phydev->duplex;
@@ -2589,14 +2604,14 @@ static int tg3_set_power_state(struct tg3 *tp, pci_power_t state)
} else {
do_low_power = true;
- if (tp->link_config.phy_is_low_power == 0) {
- tp->link_config.phy_is_low_power = 1;
+ if (!(tp->phy_flags & TG3_PHYFLG_IS_LOW_POWER)) {
+ tp->phy_flags |= TG3_PHYFLG_IS_LOW_POWER;
tp->link_config.orig_speed = tp->link_config.speed;
tp->link_config.orig_duplex = tp->link_config.duplex;
tp->link_config.orig_autoneg = tp->link_config.autoneg;
}
- if (!(tp->tg3_flags2 & TG3_FLG2_ANY_SERDES)) {
+ if (!(tp->phy_flags & TG3_PHYFLG_ANY_SERDES)) {
tp->link_config.speed = SPEED_10;
tp->link_config.duplex = DUPLEX_HALF;
tp->link_config.autoneg = AUTONEG_ENABLE;
@@ -2629,13 +2644,13 @@ static int tg3_set_power_state(struct tg3 *tp, pci_power_t state)
if (device_should_wake) {
u32 mac_mode;
- if (!(tp->tg3_flags2 & TG3_FLG2_PHY_SERDES)) {
+ if (!(tp->phy_flags & TG3_PHYFLG_PHY_SERDES)) {
if (do_low_power) {
tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x5a);
udelay(40);
}
- if (tp->tg3_flags2 & TG3_FLG2_MII_SERDES)
+ if (tp->phy_flags & TG3_PHYFLG_MII_SERDES)
mac_mode = MAC_MODE_PORT_MODE_GMII;
else
mac_mode = MAC_MODE_PORT_MODE_MII;
@@ -2803,7 +2818,7 @@ static void tg3_aux_stat_to_speed_duplex(struct tg3 *tp, u32 val, u16 *speed, u8
break;
default:
- if (tp->tg3_flags3 & TG3_FLG3_PHY_IS_FET) {
+ if (tp->phy_flags & TG3_PHYFLG_IS_FET) {
*speed = (val & MII_TG3_AUX_STAT_100) ? SPEED_100 :
SPEED_10;
*duplex = (val & MII_TG3_AUX_STAT_FULL) ? DUPLEX_FULL :
@@ -2821,7 +2836,7 @@ static void tg3_phy_copper_begin(struct tg3 *tp)
u32 new_adv;
int i;
- if (tp->link_config.phy_is_low_power) {
+ if (tp->phy_flags & TG3_PHYFLG_IS_LOW_POWER) {
/* Entering low power mode. Disable gigabit and
* 100baseT advertisements.
*/
@@ -2834,7 +2849,7 @@ static void tg3_phy_copper_begin(struct tg3 *tp)
tg3_writephy(tp, MII_ADVERTISE, new_adv);
} else if (tp->link_config.speed == SPEED_INVALID) {
- if (tp->tg3_flags & TG3_FLAG_10_100_ONLY)
+ if (tp->phy_flags & TG3_PHYFLG_10_100_ONLY)
tp->link_config.advertising &=
~(ADVERTISED_1000baseT_Half |
ADVERTISED_1000baseT_Full);
@@ -2860,7 +2875,7 @@ static void tg3_phy_copper_begin(struct tg3 *tp)
new_adv |= MII_TG3_CTRL_ADV_1000_HALF;
if (tp->link_config.advertising & ADVERTISED_1000baseT_Full)
new_adv |= MII_TG3_CTRL_ADV_1000_FULL;
- if (!(tp->tg3_flags & TG3_FLAG_10_100_ONLY) &&
+ if (!(tp->phy_flags & TG3_PHYFLG_10_100_ONLY) &&
(tp->pci_chip_rev_id == CHIPREV_ID_5701_A0 ||
tp->pci_chip_rev_id == CHIPREV_ID_5701_B0))
new_adv |= (MII_TG3_CTRL_AS_MASTER |
@@ -2962,20 +2977,11 @@ static int tg3_init_5401phy_dsp(struct tg3 *tp)
/* Set Extended packet length bit */
err = tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x4c20);
- err |= tg3_writephy(tp, MII_TG3_DSP_ADDRESS, 0x0012);
- err |= tg3_writephy(tp, MII_TG3_DSP_RW_PORT, 0x1804);
-
- err |= tg3_writephy(tp, MII_TG3_DSP_ADDRESS, 0x0013);
- err |= tg3_writephy(tp, MII_TG3_DSP_RW_PORT, 0x1204);
-
- err |= tg3_writephy(tp, MII_TG3_DSP_ADDRESS, 0x8006);
- err |= tg3_writephy(tp, MII_TG3_DSP_RW_PORT, 0x0132);
-
- err |= tg3_writephy(tp, MII_TG3_DSP_ADDRESS, 0x8006);
- err |= tg3_writephy(tp, MII_TG3_DSP_RW_PORT, 0x0232);
-
- err |= tg3_writephy(tp, MII_TG3_DSP_ADDRESS, 0x201f);
- err |= tg3_writephy(tp, MII_TG3_DSP_RW_PORT, 0x0a20);
+ err |= tg3_phydsp_write(tp, 0x0012, 0x1804);
+ err |= tg3_phydsp_write(tp, 0x0013, 0x1204);
+ err |= tg3_phydsp_write(tp, 0x8006, 0x0132);
+ err |= tg3_phydsp_write(tp, 0x8006, 0x0232);
+ err |= tg3_phydsp_write(tp, 0x201f, 0x0a20);
udelay(40);
@@ -3000,7 +3006,7 @@ static int tg3_copper_is_advertising_all(struct tg3 *tp, u32 mask)
if ((adv_reg & all_mask) != all_mask)
return 0;
- if (!(tp->tg3_flags & TG3_FLAG_10_100_ONLY)) {
+ if (!(tp->phy_flags & TG3_PHYFLG_10_100_ONLY)) {
u32 tg3_ctrl;
all_mask = 0;
@@ -3128,18 +3134,18 @@ static int tg3_setup_copper_phy(struct tg3 *tp, int force_reset)
tp->pci_chip_rev_id == CHIPREV_ID_5701_B0) {
/* 5701 {A0,B0} CRC bug workaround */
tg3_writephy(tp, 0x15, 0x0a75);
- tg3_writephy(tp, 0x1c, 0x8c68);
- tg3_writephy(tp, 0x1c, 0x8d68);
- tg3_writephy(tp, 0x1c, 0x8c68);
+ tg3_writephy(tp, MII_TG3_MISC_SHDW, 0x8c68);
+ tg3_writephy(tp, MII_TG3_MISC_SHDW, 0x8d68);
+ tg3_writephy(tp, MII_TG3_MISC_SHDW, 0x8c68);
}
/* Clear pending interrupts... */
tg3_readphy(tp, MII_TG3_ISTAT, &dummy);
tg3_readphy(tp, MII_TG3_ISTAT, &dummy);
- if (tp->tg3_flags & TG3_FLAG_USE_MI_INTERRUPT)
+ if (tp->phy_flags & TG3_PHYFLG_USE_MI_INTERRUPT)
tg3_writephy(tp, MII_TG3_IMASK, ~MII_TG3_INT_LINKCHG);
- else if (!(tp->tg3_flags3 & TG3_FLG3_PHY_IS_FET))
+ else if (!(tp->phy_flags & TG3_PHYFLG_IS_FET))
tg3_writephy(tp, MII_TG3_IMASK, ~0);
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700 ||
@@ -3155,7 +3161,7 @@ static int tg3_setup_copper_phy(struct tg3 *tp, int force_reset)
current_speed = SPEED_INVALID;
current_duplex = DUPLEX_INVALID;
- if (tp->tg3_flags2 & TG3_FLG2_CAPACITIVE_COUPLING) {
+ if (tp->phy_flags & TG3_PHYFLG_CAPACITIVE_COUPLING) {
u32 val;
tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x4007);
@@ -3231,7 +3237,7 @@ static int tg3_setup_copper_phy(struct tg3 *tp, int force_reset)
}
relink:
- if (current_link_up == 0 || tp->link_config.phy_is_low_power) {
+ if (current_link_up == 0 || (tp->phy_flags & TG3_PHYFLG_IS_LOW_POWER)) {
u32 tmp;
tg3_phy_copper_begin(tp);
@@ -3249,7 +3255,7 @@ relink:
tp->mac_mode |= MAC_MODE_PORT_MODE_MII;
else
tp->mac_mode |= MAC_MODE_PORT_MODE_GMII;
- } else if (tp->tg3_flags3 & TG3_FLG3_PHY_IS_FET)
+ } else if (tp->phy_flags & TG3_PHYFLG_IS_FET)
tp->mac_mode |= MAC_MODE_PORT_MODE_MII;
else
tp->mac_mode |= MAC_MODE_PORT_MODE_GMII;
@@ -3800,7 +3806,7 @@ static int tg3_setup_fiber_hw_autoneg(struct tg3 *tp, u32 mac_status)
expected_sg_dig_ctrl |= SG_DIG_ASYM_PAUSE;
if (sg_dig_ctrl != expected_sg_dig_ctrl) {
- if ((tp->tg3_flags2 & TG3_FLG2_PARALLEL_DETECT) &&
+ if ((tp->phy_flags & TG3_PHYFLG_PARALLEL_DETECT) &&
tp->serdes_counter &&
((mac_status & (MAC_STATUS_PCS_SYNCED |
MAC_STATUS_RCVD_CFG)) ==
@@ -3817,7 +3823,7 @@ restart_autoneg:
tw32_f(SG_DIG_CTRL, expected_sg_dig_ctrl);
tp->serdes_counter = SERDES_AN_TIMEOUT_5704S;
- tp->tg3_flags2 &= ~TG3_FLG2_PARALLEL_DETECT;
+ tp->phy_flags &= ~TG3_PHYFLG_PARALLEL_DETECT;
} else if (mac_status & (MAC_STATUS_PCS_SYNCED |
MAC_STATUS_SIGNAL_DET)) {
sg_dig_status = tr32(SG_DIG_STATUS);
@@ -3840,7 +3846,7 @@ restart_autoneg:
tg3_setup_flow_control(tp, local_adv, remote_adv);
current_link_up = 1;
tp->serdes_counter = 0;
- tp->tg3_flags2 &= ~TG3_FLG2_PARALLEL_DETECT;
+ tp->phy_flags &= ~TG3_PHYFLG_PARALLEL_DETECT;
} else if (!(sg_dig_status & SG_DIG_AUTONEG_COMPLETE)) {
if (tp->serdes_counter)
tp->serdes_counter--;
@@ -3867,8 +3873,8 @@ restart_autoneg:
!(mac_status & MAC_STATUS_RCVD_CFG)) {
tg3_setup_flow_control(tp, 0, 0);
current_link_up = 1;
- tp->tg3_flags2 |=
- TG3_FLG2_PARALLEL_DETECT;
+ tp->phy_flags |=
+ TG3_PHYFLG_PARALLEL_DETECT;
tp->serdes_counter =
SERDES_PARALLEL_DET_TIMEOUT;
} else
@@ -3877,7 +3883,7 @@ restart_autoneg:
}
} else {
tp->serdes_counter = SERDES_AN_TIMEOUT_5704S;
- tp->tg3_flags2 &= ~TG3_FLG2_PARALLEL_DETECT;
+ tp->phy_flags &= ~TG3_PHYFLG_PARALLEL_DETECT;
}
out:
@@ -4094,7 +4100,7 @@ static int tg3_setup_fiber_mii_phy(struct tg3 *tp, int force_reset)
err |= tg3_readphy(tp, MII_BMCR, &bmcr);
if ((tp->link_config.autoneg == AUTONEG_ENABLE) && !force_reset &&
- (tp->tg3_flags2 & TG3_FLG2_PARALLEL_DETECT)) {
+ (tp->phy_flags & TG3_PHYFLG_PARALLEL_DETECT)) {
/* do nothing, just check for link up at the end */
} else if (tp->link_config.autoneg == AUTONEG_ENABLE) {
u32 adv, new_adv;
@@ -4119,7 +4125,7 @@ static int tg3_setup_fiber_mii_phy(struct tg3 *tp, int force_reset)
tw32_f(MAC_EVENT, MAC_EVENT_LNKSTATE_CHANGED);
tp->serdes_counter = SERDES_AN_TIMEOUT_5714S;
- tp->tg3_flags2 &= ~TG3_FLG2_PARALLEL_DETECT;
+ tp->phy_flags &= ~TG3_PHYFLG_PARALLEL_DETECT;
return err;
}
@@ -4164,7 +4170,7 @@ static int tg3_setup_fiber_mii_phy(struct tg3 *tp, int force_reset)
else
bmsr &= ~BMSR_LSTATUS;
}
- tp->tg3_flags2 &= ~TG3_FLG2_PARALLEL_DETECT;
+ tp->phy_flags &= ~TG3_PHYFLG_PARALLEL_DETECT;
}
}
@@ -4191,6 +4197,8 @@ static int tg3_setup_fiber_mii_phy(struct tg3 *tp, int force_reset)
current_duplex = DUPLEX_FULL;
else
current_duplex = DUPLEX_HALF;
+ } else if (!(tp->tg3_flags2 & TG3_FLG2_5780_CLASS)) {
+ /* Link is up via parallel detect */
} else {
current_link_up = 0;
}
@@ -4217,7 +4225,7 @@ static int tg3_setup_fiber_mii_phy(struct tg3 *tp, int force_reset)
netif_carrier_on(tp->dev);
else {
netif_carrier_off(tp->dev);
- tp->tg3_flags2 &= ~TG3_FLG2_PARALLEL_DETECT;
+ tp->phy_flags &= ~TG3_PHYFLG_PARALLEL_DETECT;
}
tg3_link_report(tp);
}
@@ -4241,13 +4249,14 @@ static void tg3_serdes_parallel_detect(struct tg3 *tp)
u32 phy1, phy2;
/* Select shadow register 0x1f */
- tg3_writephy(tp, 0x1c, 0x7c00);
- tg3_readphy(tp, 0x1c, &phy1);
+ tg3_writephy(tp, MII_TG3_MISC_SHDW, 0x7c00);
+ tg3_readphy(tp, MII_TG3_MISC_SHDW, &phy1);
/* Select expansion interrupt status register */
- tg3_writephy(tp, 0x17, 0x0f01);
- tg3_readphy(tp, 0x15, &phy2);
- tg3_readphy(tp, 0x15, &phy2);
+ tg3_writephy(tp, MII_TG3_DSP_ADDRESS,
+ MII_TG3_DSP_EXP1_INT_STAT);
+ tg3_readphy(tp, MII_TG3_DSP_RW_PORT, &phy2);
+ tg3_readphy(tp, MII_TG3_DSP_RW_PORT, &phy2);
if ((phy1 & 0x10) && !(phy2 & 0x20)) {
/* We have signal detect and not receiving
@@ -4258,17 +4267,18 @@ static void tg3_serdes_parallel_detect(struct tg3 *tp)
bmcr &= ~BMCR_ANENABLE;
bmcr |= BMCR_SPEED1000 | BMCR_FULLDPLX;
tg3_writephy(tp, MII_BMCR, bmcr);
- tp->tg3_flags2 |= TG3_FLG2_PARALLEL_DETECT;
+ tp->phy_flags |= TG3_PHYFLG_PARALLEL_DETECT;
}
}
} else if (netif_carrier_ok(tp->dev) &&
(tp->link_config.autoneg == AUTONEG_ENABLE) &&
- (tp->tg3_flags2 & TG3_FLG2_PARALLEL_DETECT)) {
+ (tp->phy_flags & TG3_PHYFLG_PARALLEL_DETECT)) {
u32 phy2;
/* Select expansion interrupt status register */
- tg3_writephy(tp, 0x17, 0x0f01);
- tg3_readphy(tp, 0x15, &phy2);
+ tg3_writephy(tp, MII_TG3_DSP_ADDRESS,
+ MII_TG3_DSP_EXP1_INT_STAT);
+ tg3_readphy(tp, MII_TG3_DSP_RW_PORT, &phy2);
if (phy2 & 0x20) {
u32 bmcr;
@@ -4276,7 +4286,7 @@ static void tg3_serdes_parallel_detect(struct tg3 *tp)
tg3_readphy(tp, MII_BMCR, &bmcr);
tg3_writephy(tp, MII_BMCR, bmcr | BMCR_ANENABLE);
- tp->tg3_flags2 &= ~TG3_FLG2_PARALLEL_DETECT;
+ tp->phy_flags &= ~TG3_PHYFLG_PARALLEL_DETECT;
}
}
@@ -4286,9 +4296,9 @@ static int tg3_setup_phy(struct tg3 *tp, int force_reset)
{
int err;
- if (tp->tg3_flags2 & TG3_FLG2_PHY_SERDES)
+ if (tp->phy_flags & TG3_PHYFLG_PHY_SERDES)
err = tg3_setup_fiber_phy(tp, force_reset);
- else if (tp->tg3_flags2 & TG3_FLG2_MII_SERDES)
+ else if (tp->phy_flags & TG3_PHYFLG_MII_SERDES)
err = tg3_setup_fiber_mii_phy(tp, force_reset);
else
err = tg3_setup_copper_phy(tp, force_reset);
@@ -4367,7 +4377,8 @@ static void tg3_tx_recover(struct tg3 *tp)
static inline u32 tg3_tx_avail(struct tg3_napi *tnapi)
{
- smp_mb();
+ /* Tell compiler to fetch tx indices from memory. */
+ barrier();
return tnapi->tx_pending -
((tnapi->tx_prod - tnapi->tx_cons) & (TG3_TX_RING_SIZE - 1));
}
@@ -5552,8 +5563,8 @@ static netdev_tx_t tg3_start_xmit(struct sk_buff *skb,
entry = tnapi->tx_prod;
base_flags = 0;
- mss = 0;
- if ((mss = skb_shinfo(skb)->gso_size) != 0) {
+ mss = skb_shinfo(skb)->gso_size;
+ if (mss) {
int tcp_opt_len, ip_tcp_len;
u32 hdrlen;
@@ -5651,6 +5662,13 @@ static netdev_tx_t tg3_start_xmit(struct sk_buff *skb,
tnapi->tx_prod = entry;
if (unlikely(tg3_tx_avail(tnapi) <= (MAX_SKB_FRAGS + 1))) {
netif_tx_stop_queue(txq);
+
+ /* netif_tx_stop_queue() must be done before checking
+ * checking tx index in tg3_tx_avail() below, because in
+ * tg3_tx(), we update tx index before checking for
+ * netif_tx_queue_stopped().
+ */
+ smp_mb();
if (tg3_tx_avail(tnapi) > TG3_TX_WAKEUP_THRESH(tnapi))
netif_tx_wake_queue(txq);
}
@@ -5696,6 +5714,13 @@ static int tg3_tso_bug(struct tg3 *tp, struct sk_buff *skb)
/* Estimate the number of fragments in the worst case */
if (unlikely(tg3_tx_avail(&tp->napi[0]) <= frag_cnt_est)) {
netif_stop_queue(tp->dev);
+
+ /* netif_tx_stop_queue() must be done before checking
+ * checking tx index in tg3_tx_avail() below, because in
+ * tg3_tx(), we update tx index before checking for
+ * netif_tx_queue_stopped().
+ */
+ smp_mb();
if (tg3_tx_avail(&tp->napi[0]) <= frag_cnt_est)
return NETDEV_TX_BUSY;
@@ -5759,9 +5784,10 @@ static netdev_tx_t tg3_start_xmit_dma_bug(struct sk_buff *skb,
if (skb->ip_summed == CHECKSUM_PARTIAL)
base_flags |= TXD_FLAG_TCPUDP_CSUM;
- if ((mss = skb_shinfo(skb)->gso_size) != 0) {
+ mss = skb_shinfo(skb)->gso_size;
+ if (mss) {
struct iphdr *iph;
- u32 tcp_opt_len, ip_tcp_len, hdr_len;
+ u32 tcp_opt_len, hdr_len;
if (skb_header_cloned(skb) &&
pskb_expand_head(skb, 0, 0, GFP_ATOMIC)) {
@@ -5769,10 +5795,21 @@ static netdev_tx_t tg3_start_xmit_dma_bug(struct sk_buff *skb,
goto out_unlock;
}
+ iph = ip_hdr(skb);
tcp_opt_len = tcp_optlen(skb);
- ip_tcp_len = ip_hdrlen(skb) + sizeof(struct tcphdr);
- hdr_len = ip_tcp_len + tcp_opt_len;
+ if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV6) {
+ hdr_len = skb_headlen(skb) - ETH_HLEN;
+ } else {
+ u32 ip_tcp_len;
+
+ ip_tcp_len = ip_hdrlen(skb) + sizeof(struct tcphdr);
+ hdr_len = ip_tcp_len + tcp_opt_len;
+
+ iph->check = 0;
+ iph->tot_len = htons(mss + hdr_len);
+ }
+
if (unlikely((ETH_HLEN + hdr_len) > 80) &&
(tp->tg3_flags2 & TG3_FLG2_TSO_BUG))
return tg3_tso_bug(tp, skb);
@@ -5780,9 +5817,6 @@ static netdev_tx_t tg3_start_xmit_dma_bug(struct sk_buff *skb,
base_flags |= (TXD_FLAG_CPU_PRE_DMA |
TXD_FLAG_CPU_POST_DMA);
- iph = ip_hdr(skb);
- iph->check = 0;
- iph->tot_len = htons(mss + hdr_len);
if (tp->tg3_flags2 & TG3_FLG2_HW_TSO) {
tcp_hdr(skb)->check = 0;
base_flags &= ~TXD_FLAG_TCPUDP_CSUM;
@@ -5922,6 +5956,13 @@ static netdev_tx_t tg3_start_xmit_dma_bug(struct sk_buff *skb,
tnapi->tx_prod = entry;
if (unlikely(tg3_tx_avail(tnapi) <= (MAX_SKB_FRAGS + 1))) {
netif_tx_stop_queue(txq);
+
+ /* netif_tx_stop_queue() must be done before checking
+ * checking tx index in tg3_tx_avail() below, because in
+ * tg3_tx(), we update tx index before checking for
+ * netif_tx_queue_stopped().
+ */
+ smp_mb();
if (tg3_tx_avail(tnapi) > TG3_TX_WAKEUP_THRESH(tnapi))
netif_tx_wake_queue(txq);
}
@@ -6212,6 +6253,8 @@ static void tg3_free_rings(struct tg3 *tp)
for (j = 0; j < tp->irq_cnt; j++) {
struct tg3_napi *tnapi = &tp->napi[j];
+ tg3_rx_prodring_free(tp, &tp->prodring[j]);
+
if (!tnapi->tx_buffers)
continue;
@@ -6247,8 +6290,6 @@ static void tg3_free_rings(struct tg3 *tp)
dev_kfree_skb_any(skb);
}
-
- tg3_rx_prodring_free(tp, &tp->prodring[j]);
}
}
@@ -6603,7 +6644,7 @@ static void tg3_ape_driver_state_change(struct tg3 *tp, int kind)
apedata = tg3_ape_read32(tp, TG3_APE_HOST_INIT_COUNT);
tg3_ape_write32(tp, TG3_APE_HOST_INIT_COUNT, ++apedata);
tg3_ape_write32(tp, TG3_APE_HOST_DRIVER_ID,
- APE_HOST_DRIVER_ID_MAGIC);
+ APE_HOST_DRIVER_ID_MAGIC(TG3_MAJ_NUM, TG3_MIN_NUM));
tg3_ape_write32(tp, TG3_APE_HOST_BEHAVIOR,
APE_HOST_BEHAV_NO_PHYLOCK);
@@ -6782,7 +6823,8 @@ static void tg3_restore_pci_state(struct tg3 *tp)
/* Allow reads and writes to the APE register and memory space. */
if (tp->tg3_flags3 & TG3_FLG3_ENABLE_APE)
val |= PCISTATE_ALLOW_APE_CTLSPC_WR |
- PCISTATE_ALLOW_APE_SHMEM_WR;
+ PCISTATE_ALLOW_APE_SHMEM_WR |
+ PCISTATE_ALLOW_APE_PSPACE_WR;
pci_write_config_dword(tp->pdev, TG3PCI_PCISTATE, val);
pci_write_config_word(tp->pdev, PCI_COMMAND, tp->pci_cmd);
@@ -6897,9 +6939,13 @@ static int tg3_chip_reset(struct tg3 *tp)
val = GRC_MISC_CFG_CORECLK_RESET;
if (tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS) {
- if (tr32(0x7e2c) == 0x60) {
- tw32(0x7e2c, 0x20);
- }
+ /* Force PCIe 1.0a mode */
+ if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5785 &&
+ !(tp->tg3_flags3 & TG3_FLG3_5717_PLUS) &&
+ tr32(TG3_PCIE_PHY_TSTCTL) ==
+ (TG3_PCIE_PHY_TSTCTL_PCIE10 | TG3_PCIE_PHY_TSTCTL_PSCRAM))
+ tw32(TG3_PCIE_PHY_TSTCTL, TG3_PCIE_PHY_TSTCTL_PSCRAM);
+
if (tp->pci_chip_rev_id != CHIPREV_ID_5750_A0) {
tw32(GRC_MISC_CFG, (1 << 29));
val |= (1 << 29);
@@ -6912,8 +6958,11 @@ static int tg3_chip_reset(struct tg3 *tp)
tr32(GRC_VCPU_EXT_CTRL) & ~GRC_VCPU_EXT_CTRL_HALT_CPU);
}
- if (tp->tg3_flags2 & TG3_FLG2_5705_PLUS)
+ /* Manage gphy power for all CPMU absent PCIe devices. */
+ if ((tp->tg3_flags2 & TG3_FLG2_5705_PLUS) &&
+ !(tp->tg3_flags & TG3_FLAG_CPMU_PRESENT))
val |= GRC_MISC_CFG_KEEP_GPHY_POWER;
+
tw32(GRC_MISC_CFG, val);
/* restore 5701 hardware bug workaround write method */
@@ -6970,8 +7019,7 @@ static int tg3_chip_reset(struct tg3 *tp)
* Older PCIe devices only support the 128 byte
* MPS setting. Enforce the restriction.
*/
- if (!(tp->tg3_flags & TG3_FLAG_CPMU_PRESENT) ||
- (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784))
+ if (!(tp->tg3_flags & TG3_FLAG_CPMU_PRESENT))
val16 &= ~PCI_EXP_DEVCTL_PAYLOAD;
pci_write_config_word(tp->pdev,
tp->pcie_cap + PCI_EXP_DEVCTL,
@@ -7018,10 +7066,10 @@ static int tg3_chip_reset(struct tg3 *tp)
tw32(TG3PCI_CLOCK_CTRL, tp->pci_clock_ctrl);
}
- if (tp->tg3_flags2 & TG3_FLG2_PHY_SERDES) {
+ if (tp->phy_flags & TG3_PHYFLG_PHY_SERDES) {
tp->mac_mode = MAC_MODE_PORT_MODE_TBI;
tw32_f(MAC_MODE, tp->mac_mode);
- } else if (tp->tg3_flags2 & TG3_FLG2_MII_SERDES) {
+ } else if (tp->phy_flags & TG3_PHYFLG_MII_SERDES) {
tp->mac_mode = MAC_MODE_PORT_MODE_GMII;
tw32_f(MAC_MODE, tp->mac_mode);
} else if (tp->tg3_flags3 & TG3_FLG3_ENABLE_APE) {
@@ -7041,35 +7089,10 @@ static int tg3_chip_reset(struct tg3 *tp)
tg3_mdio_start(tp);
- if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780) {
- u8 phy_addr;
-
- phy_addr = tp->phy_addr;
- tp->phy_addr = TG3_PHY_PCIE_ADDR;
-
- tg3_writephy(tp, TG3_PCIEPHY_BLOCK_ADDR,
- TG3_PCIEPHY_TXB_BLK << TG3_PCIEPHY_BLOCK_SHIFT);
- val = TG3_PCIEPHY_TX0CTRL1_TXOCM | TG3_PCIEPHY_TX0CTRL1_RDCTL |
- TG3_PCIEPHY_TX0CTRL1_TXCMV | TG3_PCIEPHY_TX0CTRL1_TKSEL |
- TG3_PCIEPHY_TX0CTRL1_NB_EN;
- tg3_writephy(tp, TG3_PCIEPHY_TX0CTRL1, val);
- udelay(10);
-
- tg3_writephy(tp, TG3_PCIEPHY_BLOCK_ADDR,
- TG3_PCIEPHY_XGXS_BLK1 << TG3_PCIEPHY_BLOCK_SHIFT);
- val = TG3_PCIEPHY_PWRMGMT4_LOWPWR_EN |
- TG3_PCIEPHY_PWRMGMT4_L1PLLPD_EN;
- tg3_writephy(tp, TG3_PCIEPHY_PWRMGMT4, val);
- udelay(10);
-
- tp->phy_addr = phy_addr;
- }
-
if ((tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS) &&
tp->pci_chip_rev_id != CHIPREV_ID_5750_A0 &&
GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5785 &&
- GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5717 &&
- GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_57765) {
+ !(tp->tg3_flags3 & TG3_FLG3_5717_PLUS)) {
val = tr32(0x7c00);
tw32(0x7c00, val | (1 << 25));
@@ -7427,7 +7450,7 @@ static void __tg3_set_coalesce(struct tg3 *tp, struct ethtool_coalesce *ec)
tw32(HOSTCC_TXCOAL_MAXF_INT, 0);
}
- if (!(tp->tg3_flags2 & TG3_FLG2_USING_MSIX)) {
+ if (!(tp->tg3_flags3 & TG3_FLG3_ENABLE_RSS)) {
tw32(HOSTCC_RXCOL_TICKS, ec->rx_coalesce_usecs);
tw32(HOSTCC_RXMAX_FRAMES, ec->rx_max_coalesced_frames);
tw32(HOSTCC_RXCOAL_MAXF_INT, ec->rx_max_coalesced_frames_irq);
@@ -7504,7 +7527,8 @@ static void tg3_rings_reset(struct tg3 *tp)
/* Disable all receive return rings but the first. */
- if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717)
+ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 ||
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719)
limit = NIC_SRAM_RCV_RET_RCB + TG3_BDINFO_SIZE * 17;
else if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS))
limit = NIC_SRAM_RCV_RET_RCB + TG3_BDINFO_SIZE * 16;
@@ -7720,7 +7744,8 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
*/
val = tr32(TG3PCI_PCISTATE);
val |= PCISTATE_ALLOW_APE_CTLSPC_WR |
- PCISTATE_ALLOW_APE_SHMEM_WR;
+ PCISTATE_ALLOW_APE_SHMEM_WR |
+ PCISTATE_ALLOW_APE_PSPACE_WR;
tw32(TG3PCI_PCISTATE, val);
}
@@ -7740,8 +7765,7 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
if (err)
return err;
- if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 ||
- GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765) {
+ if (tp->tg3_flags3 & TG3_FLG3_5717_PLUS) {
val = tr32(TG3PCI_DMA_RW_CTRL) &
~DMA_RWCTRL_DIS_CACHE_ALIGNMENT;
if (tp->pci_chip_rev_id == CHIPREV_ID_57765_A0)
@@ -7869,7 +7893,8 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
((u64) tpr->rx_std_mapping >> 32));
tw32(RCVDBDI_STD_BD + TG3_BDINFO_HOST_ADDR + TG3_64BIT_REG_LOW,
((u64) tpr->rx_std_mapping & 0xffffffff));
- if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5717)
+ if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5717 &&
+ GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5719)
tw32(RCVDBDI_STD_BD + TG3_BDINFO_NIC_ADDR,
NIC_SRAM_RX_BUFFER_DESC);
@@ -7894,7 +7919,8 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
tw32(RCVDBDI_JUMBO_BD + TG3_BDINFO_MAXLEN_FLAGS,
(RX_JUMBO_MAX_SIZE << BDINFO_FLAGS_MAXLEN_SHIFT) |
BDINFO_FLAGS_USE_EXT_RECV);
- if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5717)
+ if (!(tp->tg3_flags3 & TG3_FLG3_USE_JUMBO_BDFLAG) ||
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765)
tw32(RCVDBDI_JUMBO_BD + TG3_BDINFO_NIC_ADDR,
NIC_SRAM_RX_JUMBO_BUFFER_DESC);
} else {
@@ -7902,8 +7928,7 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
BDINFO_FLAGS_DISABLED);
}
- if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 ||
- GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765)
+ if (tp->tg3_flags3 & TG3_FLG3_5717_PLUS)
val = (RX_STD_MAX_SIZE_5705 << BDINFO_FLAGS_MAXLEN_SHIFT) |
(TG3_RX_STD_DMA_SZ << 2);
else
@@ -7920,8 +7945,7 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
tp->rx_jumbo_pending : 0;
tw32_rx_mbox(TG3_RX_JMB_PROD_IDX_REG, tpr->rx_jmb_prod_idx);
- if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 ||
- GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765) {
+ if (tp->tg3_flags3 & TG3_FLG3_5717_PLUS) {
tw32(STD_REPLENISH_LWM, 32);
tw32(JMB_REPLENISH_LWM, 16);
}
@@ -7956,7 +7980,8 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
RDMAC_MODE_FIFOURUN_ENAB | RDMAC_MODE_FIFOOREAD_ENAB |
RDMAC_MODE_LNGREAD_ENAB);
- if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717)
+ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 ||
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719)
rdmac_mode |= RDMAC_MODE_MULT_DMA_RD_DIS;
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 ||
@@ -8048,8 +8073,8 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS))
tw32(RCVLSC_MODE, RCVLSC_MODE_ENABLE | RCVLSC_MODE_ATTN_ENABLE);
- if (tp->tg3_flags2 & TG3_FLG2_MII_SERDES) {
- tp->tg3_flags2 &= ~TG3_FLG2_PARALLEL_DETECT;
+ if (tp->phy_flags & TG3_PHYFLG_MII_SERDES) {
+ tp->phy_flags &= ~TG3_PHYFLG_PARALLEL_DETECT;
/* reset to prevent losing 1st rx packet intermittently */
tw32_f(MAC_RX_MODE, RX_MODE_RESET);
udelay(10);
@@ -8062,7 +8087,7 @@ 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) &&
+ !(tp->phy_flags & TG3_PHYFLG_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);
@@ -8195,6 +8220,9 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
}
tp->tx_mode = TX_MODE_ENABLE;
+ if ((tp->tg3_flags3 & TG3_FLG3_5755_PLUS) ||
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906)
+ tp->tx_mode |= TX_MODE_MBUF_LOCKUP_FIX;
tw32_f(MAC_TX_MODE, tp->tx_mode);
udelay(100);
@@ -8244,16 +8272,16 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
tw32(MAC_LED_CTRL, tp->led_ctrl);
tw32(MAC_MI_STAT, MAC_MI_STAT_LNKSTAT_ATTN_ENAB);
- if (tp->tg3_flags2 & TG3_FLG2_PHY_SERDES) {
+ if (tp->phy_flags & TG3_PHYFLG_PHY_SERDES) {
tw32_f(MAC_RX_MODE, RX_MODE_RESET);
udelay(10);
}
tw32_f(MAC_RX_MODE, tp->rx_mode);
udelay(10);
- if (tp->tg3_flags2 & TG3_FLG2_PHY_SERDES) {
+ if (tp->phy_flags & TG3_PHYFLG_PHY_SERDES) {
if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704) &&
- !(tp->tg3_flags2 & TG3_FLG2_SERDES_PREEMPHASIS)) {
+ !(tp->phy_flags & TG3_PHYFLG_SERDES_PREEMPHASIS)) {
/* Set drive transmission level to 1.2V */
/* only if the signal pre-emphasis bit is not set */
val = tr32(MAC_SERDES_CFG);
@@ -8275,12 +8303,12 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
tw32_f(MAC_LOW_WMARK_MAX_RX_FRAME, val);
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704 &&
- (tp->tg3_flags2 & TG3_FLG2_PHY_SERDES)) {
+ (tp->phy_flags & TG3_PHYFLG_PHY_SERDES)) {
/* Use hardware link auto-negotiation */
tp->tg3_flags2 |= TG3_FLG2_HW_AUTONEG;
}
- if ((tp->tg3_flags2 & TG3_FLG2_MII_SERDES) &&
+ if ((tp->phy_flags & TG3_PHYFLG_MII_SERDES) &&
(GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5714)) {
u32 tmp;
@@ -8292,8 +8320,8 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
}
if (!(tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB)) {
- if (tp->link_config.phy_is_low_power) {
- tp->link_config.phy_is_low_power = 0;
+ if (tp->phy_flags & TG3_PHYFLG_IS_LOW_POWER) {
+ tp->phy_flags &= ~TG3_PHYFLG_IS_LOW_POWER;
tp->link_config.speed = tp->link_config.orig_speed;
tp->link_config.duplex = tp->link_config.orig_duplex;
tp->link_config.autoneg = tp->link_config.orig_autoneg;
@@ -8303,15 +8331,15 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
if (err)
return err;
- if (!(tp->tg3_flags2 & TG3_FLG2_PHY_SERDES) &&
- !(tp->tg3_flags3 & TG3_FLG3_PHY_IS_FET)) {
+ if (!(tp->phy_flags & TG3_PHYFLG_PHY_SERDES) &&
+ !(tp->phy_flags & TG3_PHYFLG_IS_FET)) {
u32 tmp;
/* Clear CRC stats. */
if (!tg3_readphy(tp, MII_TG3_TEST1, &tmp)) {
tg3_writephy(tp, MII_TG3_TEST1,
tmp | MII_TG3_TEST1_CRC_EN);
- tg3_readphy(tp, 0x14, &tmp);
+ tg3_readphy(tp, MII_TG3_RXR_COUNTERS, &tmp);
}
}
}
@@ -8479,7 +8507,7 @@ static void tg3_timer(unsigned long __opaque)
mac_stat = tr32(MAC_STATUS);
phy_event = 0;
- if (tp->tg3_flags & TG3_FLAG_USE_MI_INTERRUPT) {
+ if (tp->phy_flags & TG3_PHYFLG_USE_MI_INTERRUPT) {
if (mac_stat & MAC_STATUS_MI_INTERRUPT)
phy_event = 1;
} else if (mac_stat & MAC_STATUS_LNKSTATE_CHANGED)
@@ -8495,7 +8523,7 @@ static void tg3_timer(unsigned long __opaque)
(mac_stat & MAC_STATUS_LNKSTATE_CHANGED)) {
need_setup = 1;
}
- if (! netif_carrier_ok(tp->dev) &&
+ if (!netif_carrier_ok(tp->dev) &&
(mac_stat & (MAC_STATUS_PCS_SYNCED |
MAC_STATUS_SIGNAL_DET))) {
need_setup = 1;
@@ -8511,8 +8539,10 @@ static void tg3_timer(unsigned long __opaque)
}
tg3_setup_phy(tp, 0);
}
- } else if (tp->tg3_flags2 & TG3_FLG2_MII_SERDES)
+ } else if ((tp->phy_flags & TG3_PHYFLG_MII_SERDES) &&
+ (tp->tg3_flags2 & TG3_FLG2_5780_CLASS)) {
tg3_serdes_parallel_detect(tp);
+ }
tp->timer_counter = tp->timer_multiplier;
}
@@ -8605,8 +8635,7 @@ static int tg3_test_interrupt(struct tg3 *tp)
* Turn off MSI one shot mode. Otherwise this test has no
* observable way to know whether the interrupt was delivered.
*/
- if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 ||
- GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765) &&
+ if ((tp->tg3_flags3 & TG3_FLG3_5717_PLUS) &&
(tp->tg3_flags2 & TG3_FLG2_USING_MSI)) {
val = tr32(MSGINT_MODE) | MSGINT_MODE_ONE_SHOT_DISABLE;
tw32(MSGINT_MODE, val);
@@ -8649,8 +8678,7 @@ static int tg3_test_interrupt(struct tg3 *tp)
if (intr_ok) {
/* Reenable MSI one shot mode. */
- if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 ||
- GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765) &&
+ if ((tp->tg3_flags3 & TG3_FLG3_5717_PLUS) &&
(tp->tg3_flags2 & TG3_FLG2_USING_MSI)) {
val = tr32(MSGINT_MODE) & ~MSGINT_MODE_ONE_SHOT_DISABLE;
tw32(MSGINT_MODE, val);
@@ -8775,9 +8803,9 @@ static bool tg3_enable_msix(struct tg3 *tp)
}
rc = pci_enable_msix(tp->pdev, msix_ent, tp->irq_cnt);
- if (rc != 0) {
- if (rc < TG3_RSS_MIN_NUM_MSIX_VECS)
- return false;
+ if (rc < 0) {
+ return false;
+ } else if (rc != 0) {
if (pci_enable_msix(tp->pdev, msix_ent, rc))
return false;
netdev_notice(tp->dev, "Requested %d MSI-X vectors, received %d\n",
@@ -8785,16 +8813,19 @@ static bool tg3_enable_msix(struct tg3 *tp)
tp->irq_cnt = rc;
}
- tp->tg3_flags3 |= TG3_FLG3_ENABLE_RSS;
-
for (i = 0; i < tp->irq_max; i++)
tp->napi[i].irq_vec = msix_ent[i].vector;
- if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717) {
- tp->tg3_flags3 |= TG3_FLG3_ENABLE_TSS;
- tp->dev->real_num_tx_queues = tp->irq_cnt - 1;
- } else
- tp->dev->real_num_tx_queues = 1;
+ tp->dev->real_num_tx_queues = 1;
+ if (tp->irq_cnt > 1) {
+ tp->tg3_flags3 |= TG3_FLG3_ENABLE_RSS;
+
+ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 ||
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719) {
+ tp->tg3_flags3 |= TG3_FLG3_ENABLE_TSS;
+ tp->dev->real_num_tx_queues = tp->irq_cnt - 1;
+ }
+ }
return true;
}
@@ -8838,7 +8869,7 @@ static void tg3_ints_fini(struct tg3 *tp)
else if (tp->tg3_flags2 & TG3_FLG2_USING_MSI)
pci_disable_msi(tp->pdev);
tp->tg3_flags2 &= ~TG3_FLG2_USING_MSI_OR_MSIX;
- tp->tg3_flags3 &= ~TG3_FLG3_ENABLE_RSS;
+ tp->tg3_flags3 &= ~(TG3_FLG3_ENABLE_RSS | TG3_FLG3_ENABLE_TSS);
}
static int tg3_open(struct net_device *dev)
@@ -8942,10 +8973,8 @@ static int tg3_open(struct net_device *dev)
goto err_out2;
}
- if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5717 &&
- GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_57765 &&
- (tp->tg3_flags2 & TG3_FLG2_USING_MSI) &&
- (tp->tg3_flags2 & TG3_FLG2_1SHOT_MSI)) {
+ if (!(tp->tg3_flags3 & TG3_FLG3_5717_PLUS) &&
+ (tp->tg3_flags2 & TG3_FLG2_USING_MSI)) {
u32 val = tr32(PCIE_TRANSACTION_CFG);
tw32(PCIE_TRANSACTION_CFG,
@@ -8982,7 +9011,8 @@ err_out1:
return err;
}
-static struct net_device_stats *tg3_get_stats(struct net_device *);
+static struct rtnl_link_stats64 *tg3_get_stats64(struct net_device *,
+ struct rtnl_link_stats64 *);
static struct tg3_ethtool_stats *tg3_get_estats(struct tg3 *);
static int tg3_close(struct net_device *dev)
@@ -9016,8 +9046,8 @@ static int tg3_close(struct net_device *dev)
tg3_ints_fini(tp);
- memcpy(&tp->net_stats_prev, tg3_get_stats(tp->dev),
- sizeof(tp->net_stats_prev));
+ tg3_get_stats64(tp->dev, &tp->net_stats_prev);
+
memcpy(&tp->estats_prev, tg3_get_estats(tp),
sizeof(tp->estats_prev));
@@ -9030,28 +9060,16 @@ static int tg3_close(struct net_device *dev)
return 0;
}
-static inline unsigned long get_stat64(tg3_stat64_t *val)
-{
- unsigned long ret;
-
-#if (BITS_PER_LONG == 32)
- ret = val->low;
-#else
- ret = ((u64)val->high << 32) | ((u64)val->low);
-#endif
- return ret;
-}
-
-static inline u64 get_estat64(tg3_stat64_t *val)
+static inline u64 get_stat64(tg3_stat64_t *val)
{
return ((u64)val->high << 32) | ((u64)val->low);
}
-static unsigned long calc_crc_errors(struct tg3 *tp)
+static u64 calc_crc_errors(struct tg3 *tp)
{
struct tg3_hw_stats *hw_stats = tp->hw_stats;
- if (!(tp->tg3_flags2 & TG3_FLG2_PHY_SERDES) &&
+ if (!(tp->phy_flags & TG3_PHYFLG_PHY_SERDES) &&
(GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700 ||
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701)) {
u32 val;
@@ -9060,7 +9078,7 @@ static unsigned long calc_crc_errors(struct tg3 *tp)
if (!tg3_readphy(tp, MII_TG3_TEST1, &val)) {
tg3_writephy(tp, MII_TG3_TEST1,
val | MII_TG3_TEST1_CRC_EN);
- tg3_readphy(tp, 0x14, &val);
+ tg3_readphy(tp, MII_TG3_RXR_COUNTERS, &val);
} else
val = 0;
spin_unlock_bh(&tp->lock);
@@ -9075,7 +9093,7 @@ static unsigned long calc_crc_errors(struct tg3 *tp)
#define ESTAT_ADD(member) \
estats->member = old_estats->member + \
- get_estat64(&hw_stats->member)
+ get_stat64(&hw_stats->member)
static struct tg3_ethtool_stats *tg3_get_estats(struct tg3 *tp)
{
@@ -9165,11 +9183,11 @@ static struct tg3_ethtool_stats *tg3_get_estats(struct tg3 *tp)
return estats;
}
-static struct net_device_stats *tg3_get_stats(struct net_device *dev)
+static struct rtnl_link_stats64 *tg3_get_stats64(struct net_device *dev,
+ struct rtnl_link_stats64 *stats)
{
struct tg3 *tp = netdev_priv(dev);
- struct net_device_stats *stats = &tp->net_stats;
- struct net_device_stats *old_stats = &tp->net_stats_prev;
+ struct rtnl_link_stats64 *old_stats = &tp->net_stats_prev;
struct tg3_hw_stats *hw_stats = tp->hw_stats;
if (!hw_stats)
@@ -9350,13 +9368,13 @@ static void tg3_get_regs(struct net_device *dev,
memset(p, 0, TG3_REGDUMP_LEN);
- if (tp->link_config.phy_is_low_power)
+ if (tp->phy_flags & TG3_PHYFLG_IS_LOW_POWER)
return;
tg3_full_lock(tp, 0);
#define __GET_REG32(reg) (*(p)++ = tr32(reg))
-#define GET_REG32_LOOP(base,len) \
+#define GET_REG32_LOOP(base, len) \
do { p = (u32 *)(orig_p + (base)); \
for (i = 0; i < len; i += 4) \
__GET_REG32((base) + i); \
@@ -9429,7 +9447,7 @@ static int tg3_get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
if (tp->tg3_flags3 & TG3_FLG3_NO_NVRAM)
return -EINVAL;
- if (tp->link_config.phy_is_low_power)
+ if (tp->phy_flags & TG3_PHYFLG_IS_LOW_POWER)
return -EAGAIN;
offset = eeprom->offset;
@@ -9449,7 +9467,7 @@ static int tg3_get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
ret = tg3_nvram_read_be32(tp, offset-b_offset, &val);
if (ret)
return ret;
- memcpy(data, ((char*)&val) + b_offset, b_count);
+ memcpy(data, ((char *)&val) + b_offset, b_count);
len -= b_count;
offset += b_count;
eeprom->len += b_count;
@@ -9491,7 +9509,7 @@ static int tg3_set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
u8 *buf;
__be32 start, end;
- if (tp->link_config.phy_is_low_power)
+ if (tp->phy_flags & TG3_PHYFLG_IS_LOW_POWER)
return -EAGAIN;
if ((tp->tg3_flags3 & TG3_FLG3_NO_NVRAM) ||
@@ -9548,7 +9566,7 @@ static int tg3_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
if (tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB) {
struct phy_device *phydev;
- if (!(tp->tg3_flags3 & TG3_FLG3_PHY_CONNECTED))
+ if (!(tp->phy_flags & TG3_PHYFLG_IS_CONNECTED))
return -EAGAIN;
phydev = tp->mdio_bus->phy_map[TG3_PHY_MII_ADDR];
return phy_ethtool_gset(phydev, cmd);
@@ -9556,11 +9574,11 @@ static int tg3_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
cmd->supported = (SUPPORTED_Autoneg);
- if (!(tp->tg3_flags & TG3_FLAG_10_100_ONLY))
+ if (!(tp->phy_flags & TG3_PHYFLG_10_100_ONLY))
cmd->supported |= (SUPPORTED_1000baseT_Half |
SUPPORTED_1000baseT_Full);
- if (!(tp->tg3_flags2 & TG3_FLG2_ANY_SERDES)) {
+ if (!(tp->phy_flags & TG3_PHYFLG_ANY_SERDES)) {
cmd->supported |= (SUPPORTED_100baseT_Half |
SUPPORTED_100baseT_Full |
SUPPORTED_10baseT_Half |
@@ -9591,7 +9609,7 @@ static int tg3_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
if (tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB) {
struct phy_device *phydev;
- if (!(tp->tg3_flags3 & TG3_FLG3_PHY_CONNECTED))
+ if (!(tp->phy_flags & TG3_PHYFLG_IS_CONNECTED))
return -EAGAIN;
phydev = tp->mdio_bus->phy_map[TG3_PHY_MII_ADDR];
return phy_ethtool_sset(phydev, cmd);
@@ -9611,11 +9629,11 @@ static int tg3_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
ADVERTISED_Pause |
ADVERTISED_Asym_Pause;
- if (!(tp->tg3_flags & TG3_FLAG_10_100_ONLY))
+ if (!(tp->phy_flags & TG3_PHYFLG_10_100_ONLY))
mask |= ADVERTISED_1000baseT_Half |
ADVERTISED_1000baseT_Full;
- if (!(tp->tg3_flags2 & TG3_FLG2_ANY_SERDES))
+ if (!(tp->phy_flags & TG3_PHYFLG_ANY_SERDES))
mask |= ADVERTISED_100baseT_Half |
ADVERTISED_100baseT_Full |
ADVERTISED_10baseT_Half |
@@ -9636,7 +9654,7 @@ static int tg3_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
cmd->advertising &= mask;
} else {
- if (tp->tg3_flags2 & TG3_FLG2_ANY_SERDES) {
+ if (tp->phy_flags & TG3_PHYFLG_ANY_SERDES) {
if (cmd->speed != SPEED_1000)
return -EINVAL;
@@ -9772,11 +9790,11 @@ static int tg3_nway_reset(struct net_device *dev)
if (!netif_running(dev))
return -EAGAIN;
- if (tp->tg3_flags2 & TG3_FLG2_PHY_SERDES)
+ if (tp->phy_flags & TG3_PHYFLG_PHY_SERDES)
return -EINVAL;
if (tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB) {
- if (!(tp->tg3_flags3 & TG3_FLG3_PHY_CONNECTED))
+ if (!(tp->phy_flags & TG3_PHYFLG_IS_CONNECTED))
return -EAGAIN;
r = phy_start_aneg(tp->mdio_bus->phy_map[TG3_PHY_MII_ADDR]);
} else {
@@ -9787,7 +9805,7 @@ static int tg3_nway_reset(struct net_device *dev)
tg3_readphy(tp, MII_BMCR, &bmcr);
if (!tg3_readphy(tp, MII_BMCR, &bmcr) &&
((bmcr & BMCR_ANENABLE) ||
- (tp->tg3_flags2 & TG3_FLG2_PARALLEL_DETECT))) {
+ (tp->phy_flags & TG3_PHYFLG_PARALLEL_DETECT))) {
tg3_writephy(tp, MII_BMCR, bmcr | BMCR_ANRESTART |
BMCR_ANENABLE);
r = 0;
@@ -9922,7 +9940,7 @@ static int tg3_set_pauseparam(struct net_device *dev, struct ethtool_pauseparam
else
tp->tg3_flags &= ~TG3_FLAG_PAUSE_AUTONEG;
- if (tp->tg3_flags3 & TG3_FLG3_PHY_CONNECTED) {
+ if (tp->phy_flags & TG3_PHYFLG_IS_CONNECTED) {
u32 oldadv = phydev->advertising &
(ADVERTISED_Pause | ADVERTISED_Asym_Pause);
if (oldadv != newadv) {
@@ -10251,7 +10269,7 @@ static int tg3_test_link(struct tg3 *tp)
if (!netif_running(tp->dev))
return -ENODEV;
- if (tp->tg3_flags2 & TG3_FLG2_ANY_SERDES)
+ if (tp->phy_flags & TG3_PHYFLG_ANY_SERDES)
max = TG3_SERDES_TIMEOUT_SEC;
else
max = TG3_COPPER_TIMEOUT_SEC;
@@ -10554,7 +10572,8 @@ static int tg3_test_memory(struct tg3 *tp)
int err = 0;
int i;
- if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717)
+ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 ||
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719)
mem_tbl = mem_tbl_5717;
else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765)
mem_tbl = mem_tbl_57765;
@@ -10568,8 +10587,8 @@ static int tg3_test_memory(struct tg3 *tp)
mem_tbl = mem_tbl_570x;
for (i = 0; mem_tbl[i].offset != 0xffffffff; i++) {
- if ((err = tg3_do_mem_test(tp, mem_tbl[i].offset,
- mem_tbl[i].len)) != 0)
+ err = tg3_do_mem_test(tp, mem_tbl[i].offset, mem_tbl[i].len);
+ if (err)
break;
}
@@ -10612,7 +10631,7 @@ static int tg3_run_loopback(struct tg3 *tp, int loopback_mode)
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)
+ if (tp->phy_flags & TG3_PHYFLG_10_100_ONLY)
mac_mode |= MAC_MODE_PORT_MODE_MII;
else
mac_mode |= MAC_MODE_PORT_MODE_GMII;
@@ -10620,7 +10639,7 @@ static int tg3_run_loopback(struct tg3 *tp, int loopback_mode)
} else if (loopback_mode == TG3_PHY_LOOPBACK) {
u32 val;
- if (tp->tg3_flags3 & TG3_FLG3_PHY_IS_FET) {
+ if (tp->phy_flags & TG3_PHYFLG_IS_FET) {
tg3_phy_fet_toggle_apd(tp, false);
val = BMCR_LOOPBACK | BMCR_FULLDPLX | BMCR_SPEED100;
} else
@@ -10632,7 +10651,7 @@ static int tg3_run_loopback(struct tg3 *tp, int loopback_mode)
udelay(40);
mac_mode = tp->mac_mode & ~MAC_MODE_PORT_MODE_MASK;
- if (tp->tg3_flags3 & TG3_FLG3_PHY_IS_FET) {
+ if (tp->phy_flags & TG3_PHYFLG_IS_FET) {
tg3_writephy(tp, MII_TG3_FET_PTEST,
MII_TG3_FET_PTEST_FRC_TX_LINK |
MII_TG3_FET_PTEST_FRC_TX_LOCK);
@@ -10644,7 +10663,7 @@ static int tg3_run_loopback(struct tg3 *tp, int loopback_mode)
mac_mode |= MAC_MODE_PORT_MODE_GMII;
/* reset to prevent losing 1st rx packet intermittently */
- if (tp->tg3_flags2 & TG3_FLG2_MII_SERDES) {
+ if (tp->phy_flags & TG3_PHYFLG_MII_SERDES) {
tw32_f(MAC_RX_MODE, RX_MODE_RESET);
udelay(10);
tw32_f(MAC_RX_MODE, tp->rx_mode);
@@ -10775,7 +10794,7 @@ static int tg3_test_loopback(struct tg3 *tp)
return TG3_LOOPBACK_FAILED;
/* Turn off gphy autopowerdown. */
- if (tp->tg3_flags3 & TG3_FLG3_PHY_ENABLE_APD)
+ if (tp->phy_flags & TG3_PHYFLG_ENABLE_APD)
tg3_phy_toggle_apd(tp, false);
if (tp->tg3_flags & TG3_FLAG_CPMU_PRESENT) {
@@ -10812,14 +10831,14 @@ static int tg3_test_loopback(struct tg3 *tp)
tw32(TG3_CPMU_MUTEX_GNT, CPMU_MUTEX_GNT_DRIVER);
}
- if (!(tp->tg3_flags2 & TG3_FLG2_PHY_SERDES) &&
+ if (!(tp->phy_flags & TG3_PHYFLG_PHY_SERDES) &&
!(tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB)) {
if (tg3_run_loopback(tp, TG3_PHY_LOOPBACK))
err |= TG3_PHY_LOOPBACK_FAILED;
}
/* Re-enable gphy autopowerdown. */
- if (tp->tg3_flags3 & TG3_FLG3_PHY_ENABLE_APD)
+ if (tp->phy_flags & TG3_PHYFLG_ENABLE_APD)
tg3_phy_toggle_apd(tp, true);
return err;
@@ -10830,7 +10849,7 @@ static void tg3_self_test(struct net_device *dev, struct ethtool_test *etest,
{
struct tg3 *tp = netdev_priv(dev);
- if (tp->link_config.phy_is_low_power)
+ if (tp->phy_flags & TG3_PHYFLG_IS_LOW_POWER)
tg3_set_power_state(tp, PCI_D0);
memset(data, 0, sizeof(u64) * TG3_NUM_TEST);
@@ -10862,7 +10881,7 @@ static void tg3_self_test(struct net_device *dev, struct ethtool_test *etest,
if (!err)
tg3_nvram_unlock(tp);
- if (tp->tg3_flags2 & TG3_FLG2_MII_SERDES)
+ if (tp->phy_flags & TG3_PHYFLG_MII_SERDES)
tg3_phy_reset(tp);
if (tg3_test_registers(tp) != 0) {
@@ -10898,7 +10917,7 @@ static void tg3_self_test(struct net_device *dev, struct ethtool_test *etest,
if (irq_sync && !err2)
tg3_phy_start(tp);
}
- if (tp->link_config.phy_is_low_power)
+ if (tp->phy_flags & TG3_PHYFLG_IS_LOW_POWER)
tg3_set_power_state(tp, PCI_D3hot);
}
@@ -10911,10 +10930,10 @@ static int tg3_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
if (tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB) {
struct phy_device *phydev;
- if (!(tp->tg3_flags3 & TG3_FLG3_PHY_CONNECTED))
+ if (!(tp->phy_flags & TG3_PHYFLG_IS_CONNECTED))
return -EAGAIN;
phydev = tp->mdio_bus->phy_map[TG3_PHY_MII_ADDR];
- return phy_mii_ioctl(phydev, data, cmd);
+ return phy_mii_ioctl(phydev, ifr, cmd);
}
switch (cmd) {
@@ -10925,10 +10944,10 @@ static int tg3_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
case SIOCGMIIREG: {
u32 mii_regval;
- if (tp->tg3_flags2 & TG3_FLG2_PHY_SERDES)
+ if (tp->phy_flags & TG3_PHYFLG_PHY_SERDES)
break; /* We have no PHY */
- if (tp->link_config.phy_is_low_power)
+ if (tp->phy_flags & TG3_PHYFLG_IS_LOW_POWER)
return -EAGAIN;
spin_lock_bh(&tp->lock);
@@ -10941,10 +10960,10 @@ static int tg3_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
}
case SIOCSMIIREG:
- if (tp->tg3_flags2 & TG3_FLG2_PHY_SERDES)
+ if (tp->phy_flags & TG3_PHYFLG_PHY_SERDES)
break; /* We have no PHY */
- if (tp->link_config.phy_is_low_power)
+ if (tp->phy_flags & TG3_PHYFLG_IS_LOW_POWER)
return -EAGAIN;
spin_lock_bh(&tp->lock);
@@ -11634,7 +11653,8 @@ static void __devinit tg3_nvram_init(struct tg3 *tp)
else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780 ||
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765)
tg3_get_57780_nvram_info(tp);
- else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717)
+ else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 ||
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719)
tg3_get_5717_nvram_info(tp);
else
tg3_get_nvram_info(tp);
@@ -12070,11 +12090,10 @@ static void __devinit tg3_get_eeprom_hw_cfg(struct tg3 *tp)
tp->phy_id = eeprom_phy_id;
if (eeprom_phy_serdes) {
- if ((tp->tg3_flags2 & TG3_FLG2_5780_CLASS) ||
- GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717)
- tp->tg3_flags2 |= TG3_FLG2_MII_SERDES;
+ if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS))
+ tp->phy_flags |= TG3_PHYFLG_PHY_SERDES;
else
- tp->tg3_flags2 |= TG3_FLG2_PHY_SERDES;
+ tp->phy_flags |= TG3_PHYFLG_MII_SERDES;
}
if (tp->tg3_flags2 & TG3_FLG2_5750_PLUS)
@@ -12158,7 +12177,7 @@ static void __devinit tg3_get_eeprom_hw_cfg(struct tg3 *tp)
(tp->tg3_flags2 & TG3_FLG2_5750_PLUS))
tp->tg3_flags3 |= TG3_FLG3_ENABLE_APE;
- if (tp->tg3_flags2 & TG3_FLG2_ANY_SERDES &&
+ if (tp->phy_flags & TG3_PHYFLG_ANY_SERDES &&
!(nic_cfg & NIC_SRAM_DATA_CFG_FIBER_WOL))
tp->tg3_flags &= ~TG3_FLAG_WOL_CAP;
@@ -12167,19 +12186,21 @@ static void __devinit tg3_get_eeprom_hw_cfg(struct tg3 *tp)
tp->tg3_flags |= TG3_FLAG_WOL_ENABLE;
if (cfg2 & (1 << 17))
- tp->tg3_flags2 |= TG3_FLG2_CAPACITIVE_COUPLING;
+ tp->phy_flags |= TG3_PHYFLG_CAPACITIVE_COUPLING;
/* serdes signal pre-emphasis in register 0x590 set by */
/* bootcode if bit 18 is set */
if (cfg2 & (1 << 18))
- tp->tg3_flags2 |= TG3_FLG2_SERDES_PREEMPHASIS;
+ tp->phy_flags |= TG3_PHYFLG_SERDES_PREEMPHASIS;
if (((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 &&
GET_CHIP_REV(tp->pci_chip_rev_id) != CHIPREV_5784_AX)) &&
(cfg2 & NIC_SRAM_DATA_CFG_2_APD_EN))
- tp->tg3_flags3 |= TG3_FLG3_PHY_ENABLE_APD;
+ tp->phy_flags |= TG3_PHYFLG_ENABLE_APD;
- if (tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS) {
+ if ((tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS) &&
+ GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5785 &&
+ !(tp->tg3_flags3 & TG3_FLG3_5717_PLUS)) {
u32 cfg3;
tg3_read_mem(tp, NIC_SRAM_DATA_CFG_3, &cfg3);
@@ -12284,9 +12305,9 @@ static int __devinit tg3_phy_probe(struct tg3 *tp)
if (!err && TG3_KNOWN_PHY_ID(hw_phy_id_masked)) {
tp->phy_id = hw_phy_id;
if (hw_phy_id_masked == TG3_PHY_ID_BCM8002)
- tp->tg3_flags2 |= TG3_FLG2_PHY_SERDES;
+ tp->phy_flags |= TG3_PHYFLG_PHY_SERDES;
else
- tp->tg3_flags2 &= ~TG3_FLG2_PHY_SERDES;
+ tp->phy_flags &= ~TG3_PHYFLG_PHY_SERDES;
} else {
if (tp->phy_id != TG3_PHY_ID_INVALID) {
/* Do nothing, phy ID already set up in
@@ -12305,11 +12326,11 @@ static int __devinit tg3_phy_probe(struct tg3 *tp)
tp->phy_id = p->phy_id;
if (!tp->phy_id ||
tp->phy_id == TG3_PHY_ID_BCM8002)
- tp->tg3_flags2 |= TG3_FLG2_PHY_SERDES;
+ tp->phy_flags |= TG3_PHYFLG_PHY_SERDES;
}
}
- if (!(tp->tg3_flags2 & TG3_FLG2_ANY_SERDES) &&
+ if (!(tp->phy_flags & TG3_PHYFLG_ANY_SERDES) &&
!(tp->tg3_flags3 & TG3_FLG3_ENABLE_APE) &&
!(tp->tg3_flags & TG3_FLAG_ENABLE_ASF)) {
u32 bmsr, adv_reg, tg3_ctrl, mask;
@@ -12327,7 +12348,7 @@ static int __devinit tg3_phy_probe(struct tg3 *tp)
ADVERTISE_100HALF | ADVERTISE_100FULL |
ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP);
tg3_ctrl = 0;
- if (!(tp->tg3_flags & TG3_FLAG_10_100_ONLY)) {
+ if (!(tp->phy_flags & TG3_PHYFLG_10_100_ONLY)) {
tg3_ctrl = (MII_TG3_CTRL_ADV_1000_HALF |
MII_TG3_CTRL_ADV_1000_FULL);
if (tp->pci_chip_rev_id == CHIPREV_ID_5701_A0 ||
@@ -12342,7 +12363,7 @@ static int __devinit tg3_phy_probe(struct tg3 *tp)
if (!tg3_copper_is_advertising_all(tp, mask)) {
tg3_writephy(tp, MII_ADVERTISE, adv_reg);
- if (!(tp->tg3_flags & TG3_FLAG_10_100_ONLY))
+ if (!(tp->phy_flags & TG3_PHYFLG_10_100_ONLY))
tg3_writephy(tp, MII_TG3_CTRL, tg3_ctrl);
tg3_writephy(tp, MII_BMCR,
@@ -12351,7 +12372,7 @@ static int __devinit tg3_phy_probe(struct tg3 *tp)
tg3_phy_set_wirespeed(tp);
tg3_writephy(tp, MII_ADVERTISE, adv_reg);
- if (!(tp->tg3_flags & TG3_FLAG_10_100_ONLY))
+ if (!(tp->phy_flags & TG3_PHYFLG_10_100_ONLY))
tg3_writephy(tp, MII_TG3_CTRL, tg3_ctrl);
}
@@ -12364,13 +12385,13 @@ skip_phy_reset:
err = tg3_init_5401phy_dsp(tp);
}
- if (tp->tg3_flags2 & TG3_FLG2_ANY_SERDES)
+ if (tp->phy_flags & TG3_PHYFLG_ANY_SERDES)
tp->link_config.advertising =
(ADVERTISED_1000baseT_Half |
ADVERTISED_1000baseT_Full |
ADVERTISED_Autoneg |
ADVERTISED_FIBRE);
- if (tp->tg3_flags & TG3_FLAG_10_100_ONLY)
+ if (tp->phy_flags & TG3_PHYFLG_10_100_ONLY)
tp->link_config.advertising &=
~(ADVERTISED_1000baseT_Half |
ADVERTISED_1000baseT_Full);
@@ -12699,6 +12720,7 @@ static void __devinit tg3_read_dash_ver(struct tg3 *tp)
{
int vlen;
u32 apedata;
+ char *fwtype;
if (!(tp->tg3_flags3 & TG3_FLG3_ENABLE_APE) ||
!(tp->tg3_flags & TG3_FLAG_ENABLE_ASF))
@@ -12714,9 +12736,15 @@ static void __devinit tg3_read_dash_ver(struct tg3 *tp)
apedata = tg3_ape_read32(tp, TG3_APE_FW_VERSION);
+ if (tg3_ape_read32(tp, TG3_APE_FW_FEATURES) & TG3_APE_FW_FEATURE_NCSI)
+ fwtype = "NCSI";
+ else
+ fwtype = "DASH";
+
vlen = strlen(tp->fw_ver);
- snprintf(&tp->fw_ver[vlen], TG3_VER_SIZE - vlen, " DASH v%d.%d.%d.%d",
+ snprintf(&tp->fw_ver[vlen], TG3_VER_SIZE - vlen, " %s v%d.%d.%d.%d",
+ fwtype,
(apedata & APE_FW_VERSION_MAJMSK) >> APE_FW_VERSION_MAJSFT,
(apedata & APE_FW_VERSION_MINMSK) >> APE_FW_VERSION_MINSFT,
(apedata & APE_FW_VERSION_REVMSK) >> APE_FW_VERSION_REVSFT,
@@ -12760,6 +12788,13 @@ done:
static struct pci_dev * __devinit tg3_find_peer(struct tg3 *);
+static void inline vlan_features_add(struct net_device *dev, unsigned long flags)
+{
+#if TG3_VLAN_TAG_USED
+ dev->vlan_features |= flags;
+#endif
+}
+
static int __devinit tg3_get_invariants(struct tg3 *tp)
{
static struct pci_device_id write_reorder_chipsets[] = {
@@ -12804,7 +12839,8 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
if (tp->pdev->device == TG3PCI_DEVICE_TIGON3_5717 ||
tp->pdev->device == TG3PCI_DEVICE_TIGON3_5718 ||
- tp->pdev->device == TG3PCI_DEVICE_TIGON3_5724)
+ tp->pdev->device == TG3PCI_DEVICE_TIGON3_5724 ||
+ tp->pdev->device == TG3PCI_DEVICE_TIGON3_5719)
pci_read_config_dword(tp->pdev,
TG3PCI_GEN2_PRODID_ASICREV,
&prod_id_asic_rev);
@@ -12962,6 +12998,11 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717)
tp->pdev_peer = tg3_find_peer(tp);
+ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 ||
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719 ||
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765)
+ tp->tg3_flags3 |= TG3_FLG3_5717_PLUS;
+
/* Intentionally exclude ASIC_REV_5906 */
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 ||
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787 ||
@@ -12969,8 +13010,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 ||
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785 ||
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780 ||
- GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 ||
- GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765)
+ (tp->tg3_flags3 & TG3_FLG3_5717_PLUS))
tp->tg3_flags3 |= TG3_FLG3_5755_PLUS;
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750 ||
@@ -12990,16 +13030,17 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
if (tp->pci_chip_rev_id == CHIPREV_ID_5700_B0)
tp->tg3_flags |= TG3_FLAG_BROKEN_CHECKSUMS;
else {
+ unsigned long features = NETIF_F_IP_CSUM | NETIF_F_SG | NETIF_F_GRO;
+
tp->tg3_flags |= TG3_FLAG_RX_CHECKSUMS;
- tp->dev->features |= NETIF_F_IP_CSUM | NETIF_F_SG;
if (tp->tg3_flags3 & TG3_FLG3_5755_PLUS)
- tp->dev->features |= NETIF_F_IPV6_CSUM;
- tp->dev->features |= NETIF_F_GRO;
+ features |= NETIF_F_IPV6_CSUM;
+ tp->dev->features |= features;
+ vlan_features_add(tp->dev, features);
}
/* Determine TSO capabilities */
- if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 ||
- GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765)
+ if (tp->tg3_flags3 & TG3_FLG3_5717_PLUS)
tp->tg3_flags2 |= TG3_FLG2_HW_TSO_3;
else if ((tp->tg3_flags3 & TG3_FLG3_5755_PLUS) ||
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906)
@@ -13035,14 +13076,14 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
tp->tg3_flags2 |= TG3_FLG2_1SHOT_MSI;
}
- if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 ||
- GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765) {
+ if (tp->tg3_flags3 & TG3_FLG3_5717_PLUS) {
tp->tg3_flags |= TG3_FLAG_SUPPORT_MSIX;
tp->irq_max = TG3_IRQ_MAX_VECS;
}
}
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 ||
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719 ||
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906)
tp->tg3_flags3 |= TG3_FLG3_SHORT_DMA_BUG;
else if (!(tp->tg3_flags3 & TG3_FLG3_5755_PLUS)) {
@@ -13050,8 +13091,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
tp->tg3_flags3 |= TG3_FLG3_40BIT_DMA_LIMIT_BUG;
}
- if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 ||
- GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765)
+ if (tp->tg3_flags3 & TG3_FLG3_5717_PLUS)
tp->tg3_flags3 |= TG3_FLG3_USE_JUMBO_BDFLAG;
if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS) ||
@@ -13242,7 +13282,8 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
* APE register and memory space.
*/
pci_state_reg |= PCISTATE_ALLOW_APE_CTLSPC_WR |
- PCISTATE_ALLOW_APE_SHMEM_WR;
+ PCISTATE_ALLOW_APE_SHMEM_WR |
+ PCISTATE_ALLOW_APE_PSPACE_WR;
pci_write_config_dword(tp->pdev, TG3PCI_PCISTATE,
pci_state_reg);
}
@@ -13251,8 +13292,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 ||
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785 ||
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780 ||
- GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 ||
- GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765)
+ (tp->tg3_flags3 & TG3_FLG3_5717_PLUS))
tp->tg3_flags |= TG3_FLAG_CPMU_PRESENT;
/* Set up tp->grc_local_ctrl before calling tg3_set_power_state().
@@ -13310,40 +13350,39 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
}
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906)
- tp->tg3_flags3 |= TG3_FLG3_PHY_IS_FET;
+ tp->phy_flags |= TG3_PHYFLG_IS_FET;
/* A few boards don't want Ethernet@WireSpeed phy feature */
if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700) ||
((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705) &&
(tp->pci_chip_rev_id != CHIPREV_ID_5705_A0) &&
(tp->pci_chip_rev_id != CHIPREV_ID_5705_A1)) ||
- (tp->tg3_flags3 & TG3_FLG3_PHY_IS_FET) ||
- (tp->tg3_flags2 & TG3_FLG2_ANY_SERDES))
- tp->tg3_flags2 |= TG3_FLG2_NO_ETH_WIRE_SPEED;
+ (tp->phy_flags & TG3_PHYFLG_IS_FET) ||
+ (tp->phy_flags & TG3_PHYFLG_ANY_SERDES))
+ tp->phy_flags |= TG3_PHYFLG_NO_ETH_WIRE_SPEED;
if (GET_CHIP_REV(tp->pci_chip_rev_id) == CHIPREV_5703_AX ||
GET_CHIP_REV(tp->pci_chip_rev_id) == CHIPREV_5704_AX)
- tp->tg3_flags2 |= TG3_FLG2_PHY_ADC_BUG;
+ tp->phy_flags |= TG3_PHYFLG_ADC_BUG;
if (tp->pci_chip_rev_id == CHIPREV_ID_5704_A0)
- tp->tg3_flags2 |= TG3_FLG2_PHY_5704_A0_BUG;
+ tp->phy_flags |= TG3_PHYFLG_5704_A0_BUG;
if ((tp->tg3_flags2 & TG3_FLG2_5705_PLUS) &&
- !(tp->tg3_flags3 & TG3_FLG3_PHY_IS_FET) &&
+ !(tp->phy_flags & TG3_PHYFLG_IS_FET) &&
GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5785 &&
GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_57780 &&
- GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5717 &&
- GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_57765) {
+ !(tp->tg3_flags3 & TG3_FLG3_5717_PLUS)) {
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 ||
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787 ||
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 ||
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761) {
if (tp->pdev->device != PCI_DEVICE_ID_TIGON3_5756 &&
tp->pdev->device != PCI_DEVICE_ID_TIGON3_5722)
- tp->tg3_flags2 |= TG3_FLG2_PHY_JITTER_BUG;
+ tp->phy_flags |= TG3_PHYFLG_JITTER_BUG;
if (tp->pdev->device == PCI_DEVICE_ID_TIGON3_5755M)
- tp->tg3_flags2 |= TG3_FLG2_PHY_ADJUST_TRIM;
+ tp->phy_flags |= TG3_PHYFLG_ADJUST_TRIM;
} else
- tp->tg3_flags2 |= TG3_FLG2_PHY_BER_BUG;
+ tp->phy_flags |= TG3_PHYFLG_BER_BUG;
}
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 &&
@@ -13372,8 +13411,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
return err;
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 &&
- (tp->pci_chip_rev_id != CHIPREV_ID_5717_A0 ||
- (tp->tg3_flags2 & TG3_FLG2_MII_SERDES)))
+ tp->pci_chip_rev_id != CHIPREV_ID_5717_A0)
return -ENOTSUPP;
/* Initialize data/descriptor byte/word swapping. */
@@ -13457,8 +13495,8 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
tp->pdev->device == TG3PCI_DEVICE_TIGON3_57790 ||
tp->pdev->device == TG3PCI_DEVICE_TIGON3_57791 ||
tp->pdev->device == TG3PCI_DEVICE_TIGON3_57795 ||
- (tp->tg3_flags3 & TG3_FLG3_PHY_IS_FET))
- tp->tg3_flags |= TG3_FLAG_10_100_ONLY;
+ (tp->phy_flags & TG3_PHYFLG_IS_FET))
+ tp->phy_flags |= TG3_PHYFLG_10_100_ONLY;
err = tg3_phy_probe(tp);
if (err) {
@@ -13470,13 +13508,13 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
tg3_read_vpd(tp);
tg3_read_fw_ver(tp);
- if (tp->tg3_flags2 & TG3_FLG2_PHY_SERDES) {
- tp->tg3_flags &= ~TG3_FLAG_USE_MI_INTERRUPT;
+ if (tp->phy_flags & TG3_PHYFLG_PHY_SERDES) {
+ tp->phy_flags &= ~TG3_PHYFLG_USE_MI_INTERRUPT;
} else {
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700)
- tp->tg3_flags |= TG3_FLAG_USE_MI_INTERRUPT;
+ tp->phy_flags |= TG3_PHYFLG_USE_MI_INTERRUPT;
else
- tp->tg3_flags &= ~TG3_FLAG_USE_MI_INTERRUPT;
+ tp->phy_flags &= ~TG3_PHYFLG_USE_MI_INTERRUPT;
}
/* 5700 {AX,BX} chips have a broken status block link
@@ -13494,13 +13532,13 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
*/
if (tp->pdev->subsystem_vendor == PCI_VENDOR_ID_DELL &&
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701 &&
- !(tp->tg3_flags2 & TG3_FLG2_PHY_SERDES)) {
- tp->tg3_flags |= (TG3_FLAG_USE_MI_INTERRUPT |
- TG3_FLAG_USE_LINKCHG_REG);
+ !(tp->phy_flags & TG3_PHYFLG_PHY_SERDES)) {
+ tp->phy_flags |= TG3_PHYFLG_USE_MI_INTERRUPT;
+ tp->tg3_flags |= TG3_FLAG_USE_LINKCHG_REG;
}
/* For all SERDES we poll the MAC status register. */
- if (tp->tg3_flags2 & TG3_FLG2_PHY_SERDES)
+ if (tp->phy_flags & TG3_PHYFLG_PHY_SERDES)
tp->tg3_flags |= TG3_FLAG_POLL_SERDES;
else
tp->tg3_flags &= ~TG3_FLAG_POLL_SERDES;
@@ -13580,9 +13618,12 @@ static int __devinit tg3_get_device_address(struct tg3 *tp)
tw32_f(NVRAM_CMD, NVRAM_CMD_RESET);
else
tg3_nvram_unlock(tp);
- } else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717) {
- if (tr32(TG3_CPMU_STATUS) & TG3_CPMU_STATUS_PCIE_FUNC)
+ } else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 ||
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719) {
+ if (PCI_FUNC(tp->pdev->devfn) & 1)
mac_offset = 0xcc;
+ if (PCI_FUNC(tp->pdev->devfn) > 1)
+ mac_offset += 0x18c;
} else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906)
mac_offset = 0x10;
@@ -13667,8 +13708,7 @@ static u32 __devinit tg3_calc_dma_bndry(struct tg3 *tp, u32 val)
#endif
#endif
- if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 ||
- GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765) {
+ if (tp->tg3_flags3 & TG3_FLG3_5717_PLUS) {
val = goal ? 0 : DMA_RWCTRL_DIS_CACHE_ALIGNMENT;
goto out;
}
@@ -13879,8 +13919,7 @@ static int __devinit tg3_test_dma(struct tg3 *tp)
tp->dma_rwctrl = tg3_calc_dma_bndry(tp, tp->dma_rwctrl);
- if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 ||
- GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765)
+ if (tp->tg3_flags3 & TG3_FLG3_5717_PLUS)
goto out;
if (tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS) {
@@ -14070,7 +14109,6 @@ static void __devinit tg3_init_link_config(struct tg3 *tp)
tp->link_config.autoneg = AUTONEG_ENABLE;
tp->link_config.active_speed = SPEED_INVALID;
tp->link_config.active_duplex = DUPLEX_INVALID;
- tp->link_config.phy_is_low_power = 0;
tp->link_config.orig_speed = SPEED_INVALID;
tp->link_config.orig_duplex = DUPLEX_INVALID;
tp->link_config.orig_autoneg = AUTONEG_INVALID;
@@ -14078,8 +14116,7 @@ static void __devinit tg3_init_link_config(struct tg3 *tp)
static void __devinit tg3_init_bufmgr_config(struct tg3 *tp)
{
- if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 ||
- GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765) {
+ if (tp->tg3_flags3 & TG3_FLG3_5717_PLUS) {
tp->bufmgr_config.mbuf_read_dma_low_water =
DEFAULT_MB_RDMA_LOW_WATER_5705;
tp->bufmgr_config.mbuf_mac_rx_low_water =
@@ -14156,6 +14193,7 @@ static char * __devinit tg3_phy_string(struct tg3 *tp)
case TG3_PHY_ID_BCM5718C: return "5718C";
case TG3_PHY_ID_BCM5718S: return "5718S";
case TG3_PHY_ID_BCM57765: return "57765";
+ case TG3_PHY_ID_BCM5719C: return "5719C";
case TG3_PHY_ID_BCM8002: return "8002/serdes";
case 0: return "serdes";
default: return "unknown";
@@ -14261,7 +14299,7 @@ static const struct net_device_ops tg3_netdev_ops = {
.ndo_open = tg3_open,
.ndo_stop = tg3_close,
.ndo_start_xmit = tg3_start_xmit,
- .ndo_get_stats = tg3_get_stats,
+ .ndo_get_stats64 = tg3_get_stats64,
.ndo_validate_addr = eth_validate_addr,
.ndo_set_multicast_list = tg3_set_rx_mode,
.ndo_set_mac_address = tg3_set_mac_addr,
@@ -14280,7 +14318,7 @@ static const struct net_device_ops tg3_netdev_ops_dma_bug = {
.ndo_open = tg3_open,
.ndo_stop = tg3_close,
.ndo_start_xmit = tg3_start_xmit_dma_bug,
- .ndo_get_stats = tg3_get_stats,
+ .ndo_get_stats64 = tg3_get_stats64,
.ndo_validate_addr = eth_validate_addr,
.ndo_set_multicast_list = tg3_set_rx_mode,
.ndo_set_mac_address = tg3_set_mac_addr,
@@ -14404,7 +14442,8 @@ static int __devinit tg3_init_one(struct pci_dev *pdev,
}
if ((tp->tg3_flags3 & TG3_FLG3_5755_PLUS) &&
- tp->pci_chip_rev_id != CHIPREV_ID_5717_A0)
+ tp->pci_chip_rev_id != CHIPREV_ID_5717_A0 &&
+ GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5719)
dev->netdev_ops = &tg3_netdev_ops;
else
dev->netdev_ops = &tg3_netdev_ops_dma_bug;
@@ -14468,20 +14507,25 @@ static int __devinit tg3_init_one(struct pci_dev *pdev,
* is off by default, but can be enabled using ethtool.
*/
if ((tp->tg3_flags2 & TG3_FLG2_HW_TSO) &&
- (dev->features & NETIF_F_IP_CSUM))
+ (dev->features & NETIF_F_IP_CSUM)) {
dev->features |= NETIF_F_TSO;
-
+ vlan_features_add(dev, NETIF_F_TSO);
+ }
if ((tp->tg3_flags2 & TG3_FLG2_HW_TSO_2) ||
(tp->tg3_flags2 & TG3_FLG2_HW_TSO_3)) {
- if (dev->features & NETIF_F_IPV6_CSUM)
+ if (dev->features & NETIF_F_IPV6_CSUM) {
dev->features |= NETIF_F_TSO6;
+ vlan_features_add(dev, NETIF_F_TSO6);
+ }
if ((tp->tg3_flags2 & TG3_FLG2_HW_TSO_3) ||
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 ||
(GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 &&
GET_CHIP_REV(tp->pci_chip_rev_id) != CHIPREV_5784_AX) ||
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785 ||
- GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780)
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780) {
dev->features |= NETIF_F_TSO_ECN;
+ vlan_features_add(dev, NETIF_F_TSO_ECN);
+ }
}
if (tp->pci_chip_rev_id == CHIPREV_ID_5705_A1 &&
@@ -14597,24 +14641,31 @@ static int __devinit tg3_init_one(struct pci_dev *pdev,
tg3_bus_string(tp, str),
dev->dev_addr);
- if (tp->tg3_flags3 & TG3_FLG3_PHY_CONNECTED) {
+ if (tp->phy_flags & TG3_PHYFLG_IS_CONNECTED) {
struct phy_device *phydev;
phydev = tp->mdio_bus->phy_map[TG3_PHY_MII_ADDR];
netdev_info(dev,
"attached PHY driver [%s] (mii_bus:phy_addr=%s)\n",
phydev->drv->name, dev_name(&phydev->dev));
- } else
+ } else {
+ char *ethtype;
+
+ if (tp->phy_flags & TG3_PHYFLG_10_100_ONLY)
+ ethtype = "10/100Base-TX";
+ else if (tp->phy_flags & TG3_PHYFLG_ANY_SERDES)
+ ethtype = "1000Base-SX";
+ else
+ ethtype = "10/100/1000Base-T";
+
netdev_info(dev, "attached PHY is %s (%s Ethernet) "
- "(WireSpeed[%d])\n", tg3_phy_string(tp),
- ((tp->tg3_flags & TG3_FLAG_10_100_ONLY) ? "10/100Base-TX" :
- ((tp->tg3_flags2 & TG3_FLG2_ANY_SERDES) ? "1000Base-SX" :
- "10/100/1000Base-T")),
- (tp->tg3_flags2 & TG3_FLG2_NO_ETH_WIRE_SPEED) == 0);
+ "(WireSpeed[%d])\n", tg3_phy_string(tp), ethtype,
+ (tp->phy_flags & TG3_PHYFLG_NO_ETH_WIRE_SPEED) == 0);
+ }
netdev_info(dev, "RXcsums[%d] LinkChgREG[%d] MIirq[%d] ASF[%d] TSOcap[%d]\n",
(tp->tg3_flags & TG3_FLAG_RX_CHECKSUMS) != 0,
(tp->tg3_flags & TG3_FLAG_USE_LINKCHG_REG) != 0,
- (tp->tg3_flags & TG3_FLAG_USE_MI_INTERRUPT) != 0,
+ (tp->phy_flags & TG3_PHYFLG_USE_MI_INTERRUPT) != 0,
(tp->tg3_flags & TG3_FLAG_ENABLE_ASF) != 0,
(tp->tg3_flags2 & TG3_FLG2_TSO_CAPABLE) != 0);
netdev_info(dev, "dma_rwctrl[%08x] dma_mask[%d-bit]\n",
diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h
index ce9c4918c31..4937bd19096 100644
--- a/drivers/net/tg3.h
+++ b/drivers/net/tg3.h
@@ -53,6 +53,7 @@
#define TG3PCI_DEVICE_TIGON3_57765 0x16b4
#define TG3PCI_DEVICE_TIGON3_57791 0x16b2
#define TG3PCI_DEVICE_TIGON3_57795 0x16b6
+#define TG3PCI_DEVICE_TIGON3_5719 0x1657
/* 0x04 --> 0x2c unused */
#define TG3PCI_SUBVENDOR_ID_BROADCOM PCI_VENDOR_ID_BROADCOM
#define TG3PCI_SUBDEVICE_ID_BROADCOM_95700A6 0x1644
@@ -160,6 +161,7 @@
#define ASIC_REV_57780 0x57780
#define ASIC_REV_5717 0x5717
#define ASIC_REV_57765 0x57785
+#define ASIC_REV_5719 0x5719
#define GET_CHIP_REV(CHIP_REV_ID) ((CHIP_REV_ID) >> 8)
#define CHIPREV_5700_AX 0x70
#define CHIPREV_5700_BX 0x71
@@ -231,6 +233,7 @@
#define PCISTATE_RETRY_SAME_DMA 0x00002000
#define PCISTATE_ALLOW_APE_CTLSPC_WR 0x00010000
#define PCISTATE_ALLOW_APE_SHMEM_WR 0x00020000
+#define PCISTATE_ALLOW_APE_PSPACE_WR 0x00040000
#define TG3PCI_CLOCK_CTRL 0x00000074
#define CLOCK_CTRL_CORECLK_DISABLE 0x00000200
#define CLOCK_CTRL_RXCLK_DISABLE 0x00000400
@@ -468,6 +471,7 @@
#define TX_MODE_FLOW_CTRL_ENABLE 0x00000010
#define TX_MODE_BIG_BCKOFF_ENABLE 0x00000020
#define TX_MODE_LONG_PAUSE_ENABLE 0x00000040
+#define TX_MODE_MBUF_LOCKUP_FIX 0x00000100
#define MAC_TX_STATUS 0x00000460
#define TX_STATUS_XOFFED 0x00000001
#define TX_STATUS_SENT_XOFF 0x00000002
@@ -1071,10 +1075,8 @@
#define TG3_CPMU_HST_ACC 0x0000361c
#define CPMU_HST_ACC_MACCLK_MASK 0x001f0000
#define CPMU_HST_ACC_MACCLK_6_25 0x00130000
-/* 0x3620 --> 0x362c unused */
+/* 0x3620 --> 0x3630 unused */
-#define TG3_CPMU_STATUS 0x0000362c
-#define TG3_CPMU_STATUS_PCIE_FUNC 0x20000000
#define TG3_CPMU_CLCK_STAT 0x00003630
#define CPMU_CLCK_STAT_MAC_CLCK_MASK 0x001f0000
#define CPMU_CLCK_STAT_MAC_CLCK_62_5 0x00000000
@@ -1842,6 +1844,10 @@
#define TG3_PCIE_LNKCTL_L1_PLL_PD_DIS 0x00000080
/* 0x7d58 --> 0x7e70 unused */
+#define TG3_PCIE_PHY_TSTCTL 0x00007e2c
+#define TG3_PCIE_PHY_TSTCTL_PCIE10 0x00000040
+#define TG3_PCIE_PHY_TSTCTL_PSCRAM 0x00000020
+
#define TG3_PCIE_EIDLE_DELAY 0x00007e70
#define TG3_PCIE_EIDLE_DELAY_MASK 0x0000001f
#define TG3_PCIE_EIDLE_DELAY_13_CLKS 0x0000000c
@@ -2030,31 +2036,9 @@
/* Currently this is fixed. */
-#define TG3_PHY_PCIE_ADDR 0x00
#define TG3_PHY_MII_ADDR 0x01
-/*** Tigon3 specific PHY PCIE registers. ***/
-
-#define TG3_PCIEPHY_BLOCK_ADDR 0x1f
-#define TG3_PCIEPHY_XGXS_BLK1 0x0801
-#define TG3_PCIEPHY_TXB_BLK 0x0861
-#define TG3_PCIEPHY_BLOCK_SHIFT 4
-
-/* TG3_PCIEPHY_TXB_BLK */
-#define TG3_PCIEPHY_TX0CTRL1 0x15
-#define TG3_PCIEPHY_TX0CTRL1_TXOCM 0x0003
-#define TG3_PCIEPHY_TX0CTRL1_RDCTL 0x0008
-#define TG3_PCIEPHY_TX0CTRL1_TXCMV 0x0030
-#define TG3_PCIEPHY_TX0CTRL1_TKSEL 0x0040
-#define TG3_PCIEPHY_TX0CTRL1_NB_EN 0x0400
-
-/* TG3_PCIEPHY_XGXS_BLK1 */
-#define TG3_PCIEPHY_PWRMGMT4 0x1a
-#define TG3_PCIEPHY_PWRMGMT4_L1PLLPD_EN 0x0038
-#define TG3_PCIEPHY_PWRMGMT4_LOWPWR_EN 0x4000
-
-
/*** Tigon3 specific PHY MII registers. ***/
#define TG3_BMCR_SPEED1000 0x0040
@@ -2073,8 +2057,9 @@
#define MII_TG3_EXT_STAT 0x11 /* Extended status register */
#define MII_TG3_EXT_STAT_LPASS 0x0100
+#define MII_TG3_RXR_COUNTERS 0x14 /* Local/Remote Receiver Counts */
#define MII_TG3_DSP_RW_PORT 0x15 /* DSP coefficient read/write port */
-
+#define MII_TG3_DSP_CONTROL 0x16 /* DSP control register */
#define MII_TG3_DSP_ADDRESS 0x17 /* DSP address register */
#define MII_TG3_DSP_TAP1 0x0001
@@ -2082,6 +2067,7 @@
#define MII_TG3_DSP_AADJ1CH0 0x001f
#define MII_TG3_DSP_AADJ1CH3 0x601f
#define MII_TG3_DSP_AADJ1CH3_ADCCKADJ 0x0002
+#define MII_TG3_DSP_EXP1_INT_STAT 0x0f01
#define MII_TG3_DSP_EXP8 0x0f08
#define MII_TG3_DSP_EXP8_REJ2MHz 0x0001
#define MII_TG3_DSP_EXP8_AEDW 0x0200
@@ -2177,6 +2163,8 @@
/* APE shared memory. Accessible through BAR1 */
#define TG3_APE_FW_STATUS 0x400c
#define APE_FW_STATUS_READY 0x00000100
+#define TG3_APE_FW_FEATURES 0x4010
+#define TG3_APE_FW_FEATURE_NCSI 0x00000002
#define TG3_APE_FW_VERSION 0x4018
#define APE_FW_VERSION_MAJMSK 0xff000000
#define APE_FW_VERSION_MAJSFT 24
@@ -2191,7 +2179,9 @@
#define APE_HOST_SEG_LEN_MAGIC 0x0000001c
#define TG3_APE_HOST_INIT_COUNT 0x4208
#define TG3_APE_HOST_DRIVER_ID 0x420c
-#define APE_HOST_DRIVER_ID_MAGIC 0xf0035100
+#define APE_HOST_DRIVER_ID_LINUX 0xf0000000
+#define APE_HOST_DRIVER_ID_MAGIC(maj, min) \
+ (APE_HOST_DRIVER_ID_LINUX | (maj & 0xff) << 16 | (min & 0xff) << 8)
#define TG3_APE_HOST_BEHAVIOR 0x4210
#define APE_HOST_BEHAV_NO_PHYLOCK 0x00000001
#define TG3_APE_HOST_HEARTBEAT_INT_MS 0x4214
@@ -2209,6 +2199,11 @@
#define APE_EVENT_STATUS_STATE_SUSPEND 0x00040000
#define APE_EVENT_STATUS_EVENT_PENDING 0x80000000
+#define TG3_APE_PER_LOCK_REQ 0x8400
+#define APE_LOCK_PER_REQ_DRIVER 0x00001000
+#define TG3_APE_PER_LOCK_GRANT 0x8420
+#define APE_PER_LOCK_GRANT_DRIVER 0x00001000
+
/* APE convenience enumerations. */
#define TG3_APE_LOCK_GRC 1
#define TG3_APE_LOCK_MEM 4
@@ -2539,7 +2534,6 @@ struct tg3_link_config {
/* When we go in and out of low power mode we need
* to swap with this state.
*/
- int phy_is_low_power;
u16 orig_speed;
u8 orig_duplex;
u8 orig_autoneg;
@@ -2765,8 +2759,8 @@ struct tg3 {
/* begin "everything else" cacheline(s) section */
- struct net_device_stats net_stats;
- struct net_device_stats net_stats_prev;
+ struct rtnl_link_stats64 net_stats;
+ struct rtnl_link_stats64 net_stats_prev;
struct tg3_ethtool_stats estats;
struct tg3_ethtool_stats estats_prev;
@@ -2780,7 +2774,6 @@ struct tg3 {
#define TG3_FLAG_TXD_MBOX_HWBUG 0x00000002
#define TG3_FLAG_RX_CHECKSUMS 0x00000004
#define TG3_FLAG_USE_LINKCHG_REG 0x00000008
-#define TG3_FLAG_USE_MI_INTERRUPT 0x00000010
#define TG3_FLAG_ENABLE_ASF 0x00000020
#define TG3_FLAG_ASPM_WORKAROUND 0x00000040
#define TG3_FLAG_POLL_SERDES 0x00000080
@@ -2802,7 +2795,6 @@ struct tg3 {
#define TG3_FLAG_TX_RECOVERY_PENDING 0x00200000
#define TG3_FLAG_WOL_CAP 0x00400000
#define TG3_FLAG_JUMBO_RING_ENABLE 0x00800000
-#define TG3_FLAG_10_100_ONLY 0x01000000
#define TG3_FLAG_PAUSE_AUTONEG 0x02000000
#define TG3_FLAG_CPMU_PRESENT 0x04000000
#define TG3_FLAG_40BIT_DMA_BUG 0x08000000
@@ -2813,22 +2805,15 @@ struct tg3 {
u32 tg3_flags2;
#define TG3_FLG2_RESTART_TIMER 0x00000001
#define TG3_FLG2_TSO_BUG 0x00000002
-#define TG3_FLG2_NO_ETH_WIRE_SPEED 0x00000004
#define TG3_FLG2_IS_5788 0x00000008
#define TG3_FLG2_MAX_RXPEND_64 0x00000010
#define TG3_FLG2_TSO_CAPABLE 0x00000020
-#define TG3_FLG2_PHY_ADC_BUG 0x00000040
-#define TG3_FLG2_PHY_5704_A0_BUG 0x00000080
-#define TG3_FLG2_PHY_BER_BUG 0x00000100
#define TG3_FLG2_PCI_EXPRESS 0x00000200
#define TG3_FLG2_ASF_NEW_HANDSHAKE 0x00000400
#define TG3_FLG2_HW_AUTONEG 0x00000800
#define TG3_FLG2_IS_NIC 0x00001000
-#define TG3_FLG2_PHY_SERDES 0x00002000
-#define TG3_FLG2_CAPACITIVE_COUPLING 0x00004000
#define TG3_FLG2_FLASH 0x00008000
#define TG3_FLG2_HW_TSO_1 0x00010000
-#define TG3_FLG2_SERDES_PREEMPHASIS 0x00020000
#define TG3_FLG2_5705_PLUS 0x00040000
#define TG3_FLG2_5750_PLUS 0x00080000
#define TG3_FLG2_HW_TSO_3 0x00100000
@@ -2836,10 +2821,6 @@ struct tg3 {
#define TG3_FLG2_USING_MSIX 0x00400000
#define TG3_FLG2_USING_MSI_OR_MSIX (TG3_FLG2_USING_MSI | \
TG3_FLG2_USING_MSIX)
-#define TG3_FLG2_MII_SERDES 0x00800000
-#define TG3_FLG2_ANY_SERDES (TG3_FLG2_PHY_SERDES | \
- TG3_FLG2_MII_SERDES)
-#define TG3_FLG2_PARALLEL_DETECT 0x01000000
#define TG3_FLG2_ICH_WORKAROUND 0x02000000
#define TG3_FLG2_5780_CLASS 0x04000000
#define TG3_FLG2_HW_TSO_2 0x08000000
@@ -2847,9 +2828,7 @@ struct tg3 {
TG3_FLG2_HW_TSO_2 | \
TG3_FLG2_HW_TSO_3)
#define TG3_FLG2_1SHOT_MSI 0x10000000
-#define TG3_FLG2_PHY_JITTER_BUG 0x20000000
#define TG3_FLG2_NO_FWARE_REPORTED 0x40000000
-#define TG3_FLG2_PHY_ADJUST_TRIM 0x80000000
u32 tg3_flags3;
#define TG3_FLG3_NO_NVRAM_ADDR_TRANS 0x00000001
#define TG3_FLG3_ENABLE_APE 0x00000002
@@ -2857,15 +2836,12 @@ struct tg3 {
#define TG3_FLG3_5701_DMA_BUG 0x00000008
#define TG3_FLG3_USE_PHYLIB 0x00000010
#define TG3_FLG3_MDIOBUS_INITED 0x00000020
-#define TG3_FLG3_PHY_CONNECTED 0x00000080
#define TG3_FLG3_RGMII_INBAND_DISABLE 0x00000100
#define TG3_FLG3_RGMII_EXT_IBND_RX_EN 0x00000200
#define TG3_FLG3_RGMII_EXT_IBND_TX_EN 0x00000400
#define TG3_FLG3_CLKREQ_BUG 0x00000800
-#define TG3_FLG3_PHY_ENABLE_APD 0x00001000
#define TG3_FLG3_5755_PLUS 0x00002000
#define TG3_FLG3_NO_NVRAM 0x00004000
-#define TG3_FLG3_PHY_IS_FET 0x00010000
#define TG3_FLG3_ENABLE_RSS 0x00020000
#define TG3_FLG3_ENABLE_TSS 0x00040000
#define TG3_FLG3_4G_DMA_BNDRY_BUG 0x00080000
@@ -2873,6 +2849,7 @@ struct tg3 {
#define TG3_FLG3_SHORT_DMA_BUG 0x00200000
#define TG3_FLG3_USE_JUMBO_BDFLAG 0x00400000
#define TG3_FLG3_L1PLLPD_EN 0x00800000
+#define TG3_FLG3_5717_PLUS 0x01000000
struct timer_list timer;
u16 timer_counter;
@@ -2942,6 +2919,7 @@ struct tg3 {
#define TG3_PHY_ID_BCM5718C 0x5c0d8a00
#define TG3_PHY_ID_BCM5718S 0xbc050ff0
#define TG3_PHY_ID_BCM57765 0x5c0d8a40
+#define TG3_PHY_ID_BCM5719C 0x5c0d8a20
#define TG3_PHY_ID_BCM5906 0xdc00ac40
#define TG3_PHY_ID_BCM8002 0x60010140
#define TG3_PHY_ID_INVALID 0xffffffff
@@ -2965,7 +2943,29 @@ struct tg3 {
(X) == TG3_PHY_ID_BCM5755 || (X) == TG3_PHY_ID_BCM5756 || \
(X) == TG3_PHY_ID_BCM5906 || (X) == TG3_PHY_ID_BCM5761 || \
(X) == TG3_PHY_ID_BCM5718C || (X) == TG3_PHY_ID_BCM5718S || \
- (X) == TG3_PHY_ID_BCM57765 || (X) == TG3_PHY_ID_BCM8002)
+ (X) == TG3_PHY_ID_BCM57765 || (X) == TG3_PHY_ID_BCM5719C || \
+ (X) == TG3_PHY_ID_BCM8002)
+
+ u32 phy_flags;
+#define TG3_PHYFLG_IS_LOW_POWER 0x00000001
+#define TG3_PHYFLG_IS_CONNECTED 0x00000002
+#define TG3_PHYFLG_USE_MI_INTERRUPT 0x00000004
+#define TG3_PHYFLG_PHY_SERDES 0x00000010
+#define TG3_PHYFLG_MII_SERDES 0x00000020
+#define TG3_PHYFLG_ANY_SERDES (TG3_PHYFLG_PHY_SERDES | \
+ TG3_PHYFLG_MII_SERDES)
+#define TG3_PHYFLG_IS_FET 0x00000040
+#define TG3_PHYFLG_10_100_ONLY 0x00000080
+#define TG3_PHYFLG_ENABLE_APD 0x00000100
+#define TG3_PHYFLG_CAPACITIVE_COUPLING 0x00000200
+#define TG3_PHYFLG_NO_ETH_WIRE_SPEED 0x00000400
+#define TG3_PHYFLG_JITTER_BUG 0x00000800
+#define TG3_PHYFLG_ADJUST_TRIM 0x00001000
+#define TG3_PHYFLG_ADC_BUG 0x00002000
+#define TG3_PHYFLG_5704_A0_BUG 0x00004000
+#define TG3_PHYFLG_BER_BUG 0x00008000
+#define TG3_PHYFLG_SERDES_PREEMPHASIS 0x00010000
+#define TG3_PHYFLG_PARALLEL_DETECT 0x00020000
u32 led_ctrl;
u32 phy_otp;
diff --git a/drivers/net/tulip/de2104x.c b/drivers/net/tulip/de2104x.c
index 06b552fca63..5efa57757a2 100644
--- a/drivers/net/tulip/de2104x.c
+++ b/drivers/net/tulip/de2104x.c
@@ -262,13 +262,13 @@ struct de_srom_media_block {
u16 csr13;
u16 csr14;
u16 csr15;
-} __attribute__((packed));
+} __packed;
struct de_srom_info_leaf {
u16 default_media;
u8 n_blocks;
u8 unused;
-} __attribute__((packed));
+} __packed;
struct de_desc {
__le32 opts1;
diff --git a/drivers/net/tulip/dmfe.c b/drivers/net/tulip/dmfe.c
index 29e6c63d39f..0bc4f3030a8 100644
--- a/drivers/net/tulip/dmfe.c
+++ b/drivers/net/tulip/dmfe.c
@@ -589,7 +589,7 @@ static int dmfe_open(struct DEVICE *dev)
db->dm910x_chk_mode = 1; /* Enter the check mode */
}
- /* Initilize DM910X board */
+ /* Initialize DM910X board */
dmfe_init_dm910x(dev);
/* Active System Interface */
@@ -606,9 +606,9 @@ static int dmfe_open(struct DEVICE *dev)
}
-/* Initilize DM910X board
+/* Initialize DM910X board
* Reset DM910X board
- * Initilize TX/Rx descriptor chain structure
+ * Initialize TX/Rx descriptor chain structure
* Send the set-up frame
* Enable Tx/Rx machine
*/
@@ -649,7 +649,7 @@ static void dmfe_init_dm910x(struct DEVICE *dev)
if ( !(db->media_mode & DMFE_AUTO) )
db->op_mode = db->media_mode; /* Force Mode */
- /* Initiliaze Transmit/Receive decriptor and CR3/4 */
+ /* Initialize Transmit/Receive decriptor and CR3/4 */
dmfe_descriptor_init(db, ioaddr);
/* Init CR6 to program DM910x operation */
@@ -1288,7 +1288,7 @@ static void dmfe_timer(unsigned long data)
* Stop DM910X board
* Free Tx/Rx allocated memory
* Reset DM910X board
- * Re-initilize DM910X board
+ * Re-initialize DM910X board
*/
static void dmfe_dynamic_reset(struct DEVICE *dev)
@@ -1316,7 +1316,7 @@ static void dmfe_dynamic_reset(struct DEVICE *dev)
netif_carrier_off(dev);
db->wait_reset = 0;
- /* Re-initilize DM910X board */
+ /* Re-initialize DM910X board */
dmfe_init_dm910x(dev);
/* Restart upper layer interface */
@@ -1447,7 +1447,7 @@ static void update_cr6(u32 cr6_data, unsigned long ioaddr)
/*
* Send a setup frame for DM9132
- * This setup frame initilize DM910X address filter mode
+ * This setup frame initialize DM910X address filter mode
*/
static void dm9132_id_table(struct DEVICE *dev)
@@ -1489,7 +1489,7 @@ static void dm9132_id_table(struct DEVICE *dev)
/*
* Send a setup frame for DM9102/DM9102A
- * This setup frame initilize DM910X address filter mode
+ * This setup frame initialize DM910X address filter mode
*/
static void send_filter_frame(struct DEVICE *dev)
@@ -2142,7 +2142,7 @@ static int dmfe_resume(struct pci_dev *pci_dev)
pci_set_power_state(pci_dev, PCI_D0);
pci_restore_state(pci_dev);
- /* Re-initilize DM910X board */
+ /* Re-initialize DM910X board */
dmfe_init_dm910x(dev);
/* Disable WOL */
@@ -2196,7 +2196,7 @@ MODULE_PARM_DESC(SF_mode, "Davicom DM9xxx special function "
/* Description:
* when user used insmod to add module, system invoked init_module()
- * to initilize and register.
+ * to initialize and register.
*/
static int __init dmfe_init_module(void)
diff --git a/drivers/net/tulip/eeprom.c b/drivers/net/tulip/eeprom.c
index 6002e651b9e..3031ed9c4a1 100644
--- a/drivers/net/tulip/eeprom.c
+++ b/drivers/net/tulip/eeprom.c
@@ -120,8 +120,8 @@ static void __devinit tulip_build_fake_mediatable(struct tulip_private *tp)
0x00, 0x06 /* ttm bit map */
};
- tp->mtable = (struct mediatable *)
- kmalloc(sizeof(struct mediatable) + sizeof(struct medialeaf), GFP_KERNEL);
+ tp->mtable = kmalloc(sizeof(struct mediatable) +
+ sizeof(struct medialeaf), GFP_KERNEL);
if (tp->mtable == NULL)
return; /* Horrible, impossible failure. */
@@ -227,9 +227,9 @@ subsequent_board:
return;
}
- mtable = (struct mediatable *)
- kmalloc(sizeof(struct mediatable) + count*sizeof(struct medialeaf),
- GFP_KERNEL);
+ mtable = kmalloc(sizeof(struct mediatable) +
+ count * sizeof(struct medialeaf),
+ GFP_KERNEL);
if (mtable == NULL)
return; /* Horrible, impossible failure. */
last_mediatable = tp->mtable = mtable;
diff --git a/drivers/net/tulip/tulip.h b/drivers/net/tulip/tulip.h
index 0afa2d4f947..e525875ed67 100644
--- a/drivers/net/tulip/tulip.h
+++ b/drivers/net/tulip/tulip.h
@@ -20,6 +20,7 @@
#include <linux/types.h>
#include <linux/spinlock.h>
#include <linux/netdevice.h>
+#include <linux/ethtool.h>
#include <linux/timer.h>
#include <linux/delay.h>
#include <linux/pci.h>
@@ -51,22 +52,23 @@ struct tulip_chip_table {
enum tbl_flag {
- HAS_MII = 0x0001,
- HAS_MEDIA_TABLE = 0x0002,
- CSR12_IN_SROM = 0x0004,
- ALWAYS_CHECK_MII = 0x0008,
- HAS_ACPI = 0x0010,
- MC_HASH_ONLY = 0x0020, /* Hash-only multicast filter. */
- HAS_PNICNWAY = 0x0080,
- HAS_NWAY = 0x0040, /* Uses internal NWay xcvr. */
- HAS_INTR_MITIGATION = 0x0100,
- IS_ASIX = 0x0200,
- HAS_8023X = 0x0400,
- COMET_MAC_ADDR = 0x0800,
- HAS_PCI_MWI = 0x1000,
- HAS_PHY_IRQ = 0x2000,
- HAS_SWAPPED_SEEPROM = 0x4000,
- NEEDS_FAKE_MEDIA_TABLE = 0x8000,
+ HAS_MII = 0x00001,
+ HAS_MEDIA_TABLE = 0x00002,
+ CSR12_IN_SROM = 0x00004,
+ ALWAYS_CHECK_MII = 0x00008,
+ HAS_ACPI = 0x00010,
+ MC_HASH_ONLY = 0x00020, /* Hash-only multicast filter. */
+ HAS_PNICNWAY = 0x00080,
+ HAS_NWAY = 0x00040, /* Uses internal NWay xcvr. */
+ HAS_INTR_MITIGATION = 0x00100,
+ IS_ASIX = 0x00200,
+ HAS_8023X = 0x00400,
+ COMET_MAC_ADDR = 0x00800,
+ HAS_PCI_MWI = 0x01000,
+ HAS_PHY_IRQ = 0x02000,
+ HAS_SWAPPED_SEEPROM = 0x04000,
+ NEEDS_FAKE_MEDIA_TABLE = 0x08000,
+ COMET_PM = 0x10000,
};
@@ -120,6 +122,11 @@ enum tulip_offsets {
CSR13 = 0x68,
CSR14 = 0x70,
CSR15 = 0x78,
+ CSR18 = 0x88,
+ CSR19 = 0x8c,
+ CSR20 = 0x90,
+ CSR27 = 0xAC,
+ CSR28 = 0xB0,
};
/* register offset and bits for CFDD PCI config reg */
@@ -289,6 +296,30 @@ enum t21143_csr6_bits {
csr6_mask_100bt = (csr6_scr | csr6_pcs | csr6_hbd),
};
+enum tulip_comet_csr13_bits {
+/* The LINKOFFE and LINKONE work in conjunction with LSCE, i.e. they
+ * determine which link status transition wakes up if LSCE is
+ * enabled */
+ comet_csr13_linkoffe = (1 << 17),
+ comet_csr13_linkone = (1 << 16),
+ comet_csr13_wfre = (1 << 10),
+ comet_csr13_mpre = (1 << 9),
+ comet_csr13_lsce = (1 << 8),
+ comet_csr13_wfr = (1 << 2),
+ comet_csr13_mpr = (1 << 1),
+ comet_csr13_lsc = (1 << 0),
+};
+
+enum tulip_comet_csr18_bits {
+ comet_csr18_pmes_sticky = (1 << 24),
+ comet_csr18_pm_mode = (1 << 19),
+ comet_csr18_apm_mode = (1 << 18),
+ comet_csr18_d3a = (1 << 7)
+};
+
+enum tulip_comet_csr20_bits {
+ comet_csr20_pmes = (1 << 15),
+};
/* Keep the ring sizes a power of two for efficiency.
Making the Tx ring too large decreases the effectiveness of channel
@@ -411,6 +442,7 @@ struct tulip_private {
unsigned int csr6; /* Current CSR6 control settings. */
unsigned char eeprom[EEPROM_SIZE]; /* Serial EEPROM contents. */
void (*link_change) (struct net_device * dev, int csr5);
+ struct ethtool_wolinfo wolinfo; /* WOL settings */
u16 sym_advertise, mii_advertise; /* NWay capabilities advertised. */
u16 lpar; /* 21143 Link partner ability. */
u16 advertising[4];
diff --git a/drivers/net/tulip/tulip_core.c b/drivers/net/tulip/tulip_core.c
index 254643ed945..3a8d7efa2ac 100644
--- a/drivers/net/tulip/tulip_core.c
+++ b/drivers/net/tulip/tulip_core.c
@@ -30,7 +30,6 @@
#include <linux/etherdevice.h>
#include <linux/delay.h>
#include <linux/mii.h>
-#include <linux/ethtool.h>
#include <linux/crc32.h>
#include <asm/unaligned.h>
#include <asm/uaccess.h>
@@ -272,6 +271,7 @@ static void tulip_down(struct net_device *dev);
static struct net_device_stats *tulip_get_stats(struct net_device *dev);
static int private_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
static void set_rx_mode(struct net_device *dev);
+static void tulip_set_wolopts(struct pci_dev *pdev, u32 wolopts);
#ifdef CONFIG_NET_POLL_CONTROLLER
static void poll_tulip(struct net_device *dev);
#endif
@@ -309,6 +309,11 @@ static void tulip_up(struct net_device *dev)
/* Wake the chip from sleep/snooze mode. */
tulip_set_power_state (tp, 0, 0);
+ /* Disable all WOL events */
+ pci_enable_wake(tp->pdev, PCI_D3hot, 0);
+ pci_enable_wake(tp->pdev, PCI_D3cold, 0);
+ tulip_set_wolopts(tp->pdev, 0);
+
/* On some chip revs we must set the MII/SYM port before the reset!? */
if (tp->mii_cnt || (tp->mtable && tp->mtable->has_mii))
iowrite32(0x00040000, ioaddr + CSR6);
@@ -345,8 +350,8 @@ static void tulip_up(struct net_device *dev)
} else if (tp->flags & COMET_MAC_ADDR) {
iowrite32(addr_low, ioaddr + 0xA4);
iowrite32(addr_high, ioaddr + 0xA8);
- iowrite32(0, ioaddr + 0xAC);
- iowrite32(0, ioaddr + 0xB0);
+ iowrite32(0, ioaddr + CSR27);
+ iowrite32(0, ioaddr + CSR28);
}
} else {
/* This is set_rx_mode(), but without starting the transmitter. */
@@ -591,10 +596,10 @@ static void tulip_tx_timeout(struct net_device *dev)
pr_cont(" %02x", buf[j]);
pr_cont(" j=%d\n", j);
}
- printk(KERN_DEBUG " Rx ring %08x: ", (int)tp->rx_ring);
+ printk(KERN_DEBUG " Rx ring %p: ", tp->rx_ring);
for (i = 0; i < RX_RING_SIZE; i++)
pr_cont(" %08x", (unsigned int)tp->rx_ring[i].status);
- printk(KERN_DEBUG " Tx ring %08x: ", (int)tp->tx_ring);
+ printk(KERN_DEBUG " Tx ring %p: ", tp->tx_ring);
for (i = 0; i < TX_RING_SIZE; i++)
pr_cont(" %08x", (unsigned int)tp->tx_ring[i].status);
pr_cont("\n");
@@ -876,8 +881,35 @@ static void tulip_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *in
strcpy(info->bus_info, pci_name(np->pdev));
}
+
+static int tulip_ethtool_set_wol(struct net_device *dev,
+ struct ethtool_wolinfo *wolinfo)
+{
+ struct tulip_private *tp = netdev_priv(dev);
+
+ if (wolinfo->wolopts & (~tp->wolinfo.supported))
+ return -EOPNOTSUPP;
+
+ tp->wolinfo.wolopts = wolinfo->wolopts;
+ device_set_wakeup_enable(&tp->pdev->dev, tp->wolinfo.wolopts);
+ return 0;
+}
+
+static void tulip_ethtool_get_wol(struct net_device *dev,
+ struct ethtool_wolinfo *wolinfo)
+{
+ struct tulip_private *tp = netdev_priv(dev);
+
+ wolinfo->supported = tp->wolinfo.supported;
+ wolinfo->wolopts = tp->wolinfo.wolopts;
+ return;
+}
+
+
static const struct ethtool_ops ops = {
- .get_drvinfo = tulip_get_drvinfo
+ .get_drvinfo = tulip_get_drvinfo,
+ .set_wol = tulip_ethtool_set_wol,
+ .get_wol = tulip_ethtool_get_wol,
};
/* Provide ioctl() calls to examine the MII xcvr state. */
@@ -1093,8 +1125,8 @@ static void set_rx_mode(struct net_device *dev)
iowrite32(3, ioaddr + CSR13);
iowrite32(mc_filter[1], ioaddr + CSR14);
} else if (tp->flags & COMET_MAC_ADDR) {
- iowrite32(mc_filter[0], ioaddr + 0xAC);
- iowrite32(mc_filter[1], ioaddr + 0xB0);
+ iowrite32(mc_filter[0], ioaddr + CSR27);
+ iowrite32(mc_filter[1], ioaddr + CSR28);
}
tp->mc_filter[0] = mc_filter[0];
tp->mc_filter[1] = mc_filter[1];
@@ -1309,6 +1341,12 @@ static int __devinit tulip_init_one (struct pci_dev *pdev,
if (pdev->subsystem_vendor == PCI_VENDOR_ID_LMC) {
pr_err(PFX "skipping LMC card\n");
return -ENODEV;
+ } else if (pdev->subsystem_vendor == PCI_VENDOR_ID_SBE &&
+ (pdev->subsystem_device == PCI_SUBDEVICE_ID_SBE_T3E3 ||
+ pdev->subsystem_device == PCI_SUBDEVICE_ID_SBE_2T3E3_P0 ||
+ pdev->subsystem_device == PCI_SUBDEVICE_ID_SBE_2T3E3_P1)) {
+ pr_err(PFX "skipping SBE T3E3 port\n");
+ return -ENODEV;
}
/*
@@ -1381,6 +1419,13 @@ static int __devinit tulip_init_one (struct pci_dev *pdev,
return i;
}
+ /* The chip will fail to enter a low-power state later unless
+ * first explicitly commanded into D0 */
+ if (pci_set_power_state(pdev, PCI_D0)) {
+ printk (KERN_NOTICE PFX
+ "Failed to set power state to D0\n");
+ }
+
irq = pdev->irq;
/* alloc_etherdev ensures aligned and zeroed private structures */
@@ -1427,6 +1472,19 @@ static int __devinit tulip_init_one (struct pci_dev *pdev,
tp->chip_id = chip_idx;
tp->flags = tulip_tbl[chip_idx].flags;
+
+ tp->wolinfo.supported = 0;
+ tp->wolinfo.wolopts = 0;
+ /* COMET: Enable power management only for AN983B */
+ if (chip_idx == COMET ) {
+ u32 sig;
+ pci_read_config_dword (pdev, 0x80, &sig);
+ if (sig == 0x09811317) {
+ tp->flags |= COMET_PM;
+ tp->wolinfo.supported = WAKE_PHY | WAKE_MAGIC;
+ printk(KERN_INFO "tulip_init_one: Enabled WOL support for AN983B\n");
+ }
+ }
tp->pdev = pdev;
tp->base_addr = ioaddr;
tp->revision = pdev->revision;
@@ -1759,11 +1817,43 @@ err_out_free_netdev:
}
+/* set the registers according to the given wolopts */
+static void tulip_set_wolopts (struct pci_dev *pdev, u32 wolopts)
+{
+ struct net_device *dev = pci_get_drvdata(pdev);
+ struct tulip_private *tp = netdev_priv(dev);
+ void __iomem *ioaddr = tp->base_addr;
+
+ if (tp->flags & COMET_PM) {
+
+ unsigned int tmp;
+
+ tmp = ioread32(ioaddr + CSR18);
+ tmp &= ~(comet_csr18_pmes_sticky | comet_csr18_apm_mode | comet_csr18_d3a);
+ tmp |= comet_csr18_pm_mode;
+ iowrite32(tmp, ioaddr + CSR18);
+
+ /* Set the Wake-up Control/Status Register to the given WOL options*/
+ tmp = ioread32(ioaddr + CSR13);
+ tmp &= ~(comet_csr13_linkoffe | comet_csr13_linkone | comet_csr13_wfre | comet_csr13_lsce | comet_csr13_mpre);
+ if (wolopts & WAKE_MAGIC)
+ tmp |= comet_csr13_mpre;
+ if (wolopts & WAKE_PHY)
+ tmp |= comet_csr13_linkoffe | comet_csr13_linkone | comet_csr13_lsce;
+ /* Clear the event flags */
+ tmp |= comet_csr13_wfr | comet_csr13_mpr | comet_csr13_lsc;
+ iowrite32(tmp, ioaddr + CSR13);
+ }
+}
+
#ifdef CONFIG_PM
+
static int tulip_suspend (struct pci_dev *pdev, pm_message_t state)
{
+ pci_power_t pstate;
struct net_device *dev = pci_get_drvdata(pdev);
+ struct tulip_private *tp = netdev_priv(dev);
if (!dev)
return -EINVAL;
@@ -1779,7 +1869,16 @@ static int tulip_suspend (struct pci_dev *pdev, pm_message_t state)
save_state:
pci_save_state(pdev);
pci_disable_device(pdev);
- pci_set_power_state(pdev, pci_choose_state(pdev, state));
+ pstate = pci_choose_state(pdev, state);
+ if (state.event == PM_EVENT_SUSPEND && pstate != PCI_D0) {
+ int rc;
+
+ tulip_set_wolopts(pdev, tp->wolinfo.wolopts);
+ rc = pci_enable_wake(pdev, pstate, tp->wolinfo.wolopts);
+ if (rc)
+ printk("tulip: pci_enable_wake failed (%d)\n", rc);
+ }
+ pci_set_power_state(pdev, pstate);
return 0;
}
@@ -1788,7 +1887,10 @@ save_state:
static int tulip_resume(struct pci_dev *pdev)
{
struct net_device *dev = pci_get_drvdata(pdev);
+ struct tulip_private *tp = netdev_priv(dev);
+ void __iomem *ioaddr = tp->base_addr;
int retval;
+ unsigned int tmp;
if (!dev)
return -EINVAL;
@@ -1809,6 +1911,18 @@ static int tulip_resume(struct pci_dev *pdev)
return retval;
}
+ if (tp->flags & COMET_PM) {
+ pci_enable_wake(pdev, PCI_D3hot, 0);
+ pci_enable_wake(pdev, PCI_D3cold, 0);
+
+ /* Clear the PMES flag */
+ tmp = ioread32(ioaddr + CSR20);
+ tmp |= comet_csr20_pmes;
+ iowrite32(tmp, ioaddr + CSR20);
+
+ /* Disable all wake-up events */
+ tulip_set_wolopts(pdev, 0);
+ }
netif_device_attach(dev);
if (netif_running(dev))
diff --git a/drivers/net/tulip/winbond-840.c b/drivers/net/tulip/winbond-840.c
index 608b279b921..66d41cf8da2 100644
--- a/drivers/net/tulip/winbond-840.c
+++ b/drivers/net/tulip/winbond-840.c
@@ -1514,12 +1514,12 @@ static int netdev_close(struct net_device *dev)
if (debug > 2) {
int i;
- printk(KERN_DEBUG" Tx ring at %08x:\n", (int)np->tx_ring);
+ printk(KERN_DEBUG" Tx ring at %p:\n", np->tx_ring);
for (i = 0; i < TX_RING_SIZE; i++)
printk(KERN_DEBUG " #%d desc. %04x %04x %08x\n",
i, np->tx_ring[i].length,
np->tx_ring[i].status, np->tx_ring[i].buffer1);
- printk(KERN_DEBUG " Rx ring %08x:\n", (int)np->rx_ring);
+ printk(KERN_DEBUG " Rx ring %p:\n", np->rx_ring);
for (i = 0; i < RX_RING_SIZE; i++) {
printk(KERN_DEBUG " #%d desc. %04x %04x %08x\n",
i, np->rx_ring[i].length,
diff --git a/drivers/net/tun.c b/drivers/net/tun.c
index 63042596f0c..55f3a3e667a 100644
--- a/drivers/net/tun.c
+++ b/drivers/net/tun.c
@@ -149,6 +149,7 @@ static int tun_attach(struct tun_struct *tun, struct file *file)
tfile->tun = tun;
tun->tfile = tfile;
tun->socket.file = file;
+ netif_carrier_on(tun->dev);
dev_hold(tun->dev);
sock_hold(tun->socket.sk);
atomic_inc(&tfile->count);
@@ -162,6 +163,7 @@ static void __tun_detach(struct tun_struct *tun)
{
/* Detach from net device */
netif_tx_lock_bh(tun->dev);
+ netif_carrier_off(tun->dev);
tun->tfile = NULL;
tun->socket.file = NULL;
netif_tx_unlock_bh(tun->dev);
@@ -1574,12 +1576,6 @@ static void tun_set_msglevel(struct net_device *dev, u32 value)
#endif
}
-static u32 tun_get_link(struct net_device *dev)
-{
- struct tun_struct *tun = netdev_priv(dev);
- return !!tun->tfile;
-}
-
static u32 tun_get_rx_csum(struct net_device *dev)
{
struct tun_struct *tun = netdev_priv(dev);
@@ -1601,7 +1597,7 @@ static const struct ethtool_ops tun_ethtool_ops = {
.get_drvinfo = tun_get_drvinfo,
.get_msglevel = tun_get_msglevel,
.set_msglevel = tun_set_msglevel,
- .get_link = tun_get_link,
+ .get_link = ethtool_op_get_link,
.get_rx_csum = tun_get_rx_csum,
.set_rx_csum = tun_set_rx_csum
};
diff --git a/drivers/net/typhoon.c b/drivers/net/typhoon.c
index 22bde49262c..2e50077ff45 100644
--- a/drivers/net/typhoon.c
+++ b/drivers/net/typhoon.c
@@ -255,7 +255,7 @@ struct typhoon_shared {
struct rx_free rxBuff[RXFREE_ENTRIES] __3xp_aligned;
u32 zeroWord;
struct tx_desc txHi[TXHI_ENTRIES];
-} __attribute__ ((packed));
+} __packed;
struct rxbuff_ent {
struct sk_buff *skb;
diff --git a/drivers/net/typhoon.h b/drivers/net/typhoon.h
index 673fd512591..88187fc84aa 100644
--- a/drivers/net/typhoon.h
+++ b/drivers/net/typhoon.h
@@ -77,7 +77,7 @@ struct typhoon_indexes {
volatile __le32 cmdCleared;
volatile __le32 respReady;
volatile __le32 rxHiReady;
-} __attribute__ ((packed));
+} __packed;
/* The host<->Typhoon interface
* Our means of communicating where things are
@@ -125,7 +125,7 @@ struct typhoon_interface {
__le32 rxHiAddr;
__le32 rxHiAddrHi;
__le32 rxHiSize;
-} __attribute__ ((packed));
+} __packed;
/* The Typhoon transmit/fragment descriptor
*
@@ -187,7 +187,7 @@ struct tx_desc {
#define TYPHOON_TX_PF_VLAN_MASK cpu_to_le32(0x0ffff000)
#define TYPHOON_TX_PF_INTERNAL cpu_to_le32(0xf0000000)
#define TYPHOON_TX_PF_VLAN_TAG_SHIFT 12
-} __attribute__ ((packed));
+} __packed;
/* The TCP Segmentation offload option descriptor
*
@@ -208,7 +208,7 @@ struct tcpopt_desc {
__le32 respAddrLo;
__le32 bytesTx;
__le32 status;
-} __attribute__ ((packed));
+} __packed;
/* The IPSEC Offload descriptor
*
@@ -227,7 +227,7 @@ struct ipsec_desc {
__le32 sa1;
__le32 sa2;
__le32 reserved;
-} __attribute__ ((packed));
+} __packed;
/* The Typhoon receive descriptor (Updated by NIC)
*
@@ -284,7 +284,7 @@ struct rx_desc {
#define TYPHOON_RX_UNKNOWN_SA cpu_to_le16(0x0100)
#define TYPHOON_RX_ESP_FORMAT_ERR cpu_to_le16(0x0200)
__be32 vlanTag;
-} __attribute__ ((packed));
+} __packed;
/* The Typhoon free buffer descriptor, used to give a buffer to the NIC
*
@@ -301,7 +301,7 @@ struct rx_free {
__le32 physAddrHi;
u32 virtAddr;
u32 virtAddrHi;
-} __attribute__ ((packed));
+} __packed;
/* The Typhoon command descriptor, used for commands and responses
*
@@ -347,7 +347,7 @@ struct cmd_desc {
__le16 parm1;
__le32 parm2;
__le32 parm3;
-} __attribute__ ((packed));
+} __packed;
/* The Typhoon response descriptor, see command descriptor for details
*/
@@ -359,7 +359,7 @@ struct resp_desc {
__le16 parm1;
__le32 parm2;
__le32 parm3;
-} __attribute__ ((packed));
+} __packed;
#define INIT_COMMAND_NO_RESPONSE(x, command) \
do { struct cmd_desc *_ptr = (x); \
@@ -427,7 +427,7 @@ struct stats_resp {
#define TYPHOON_LINK_HALF_DUPLEX cpu_to_le32(0x00000000)
__le32 unused2;
__le32 unused3;
-} __attribute__ ((packed));
+} __packed;
/* TYPHOON_CMD_XCVR_SELECT xcvr values (resp.parm1)
*/
@@ -488,7 +488,7 @@ struct sa_descriptor {
u32 index;
u32 unused;
u32 unused2;
-} __attribute__ ((packed));
+} __packed;
/* TYPHOON_CMD_SET_OFFLOAD_TASKS bits (cmd.parm2 (Tx) & cmd.parm3 (Rx))
* This is all for IPv4.
@@ -518,14 +518,14 @@ struct typhoon_file_header {
__le32 numSections;
__le32 startAddr;
__le32 hmacDigest[5];
-} __attribute__ ((packed));
+} __packed;
struct typhoon_section_header {
__le32 len;
u16 checksum;
u16 reserved;
__le32 startAddr;
-} __attribute__ ((packed));
+} __packed;
/* The Typhoon Register offsets
*/
diff --git a/drivers/net/ucc_geth.c b/drivers/net/ucc_geth.c
index 807470e156a..8d532f9b50d 100644
--- a/drivers/net/ucc_geth.c
+++ b/drivers/net/ucc_geth.c
@@ -594,7 +594,7 @@ static void dump_regs(struct ucc_geth_private *ugeth)
{
int i;
- ugeth_info("UCC%d Geth registers:", ugeth->ug_info->uf_info.ucc_num);
+ ugeth_info("UCC%d Geth registers:", ugeth->ug_info->uf_info.ucc_num + 1);
ugeth_info("Base address: 0x%08x", (u32) ugeth->ug_regs);
ugeth_info("maccfg1 : addr - 0x%08x, val - 0x%08x",
@@ -3704,6 +3704,19 @@ static phy_interface_t to_phy_interface(const char *phy_connection_type)
return PHY_INTERFACE_MODE_MII;
}
+static int ucc_geth_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+{
+ struct ucc_geth_private *ugeth = netdev_priv(dev);
+
+ if (!netif_running(dev))
+ return -EINVAL;
+
+ if (!ugeth->phydev)
+ return -ENODEV;
+
+ return phy_mii_ioctl(ugeth->phydev, rq, cmd);
+}
+
static const struct net_device_ops ucc_geth_netdev_ops = {
.ndo_open = ucc_geth_open,
.ndo_stop = ucc_geth_close,
@@ -3713,6 +3726,7 @@ static const struct net_device_ops ucc_geth_netdev_ops = {
.ndo_change_mtu = eth_change_mtu,
.ndo_set_multicast_list = ucc_geth_set_multi,
.ndo_tx_timeout = ucc_geth_timeout,
+ .ndo_do_ioctl = ucc_geth_ioctl,
#ifdef CONFIG_NET_POLL_CONTROLLER
.ndo_poll_controller = ucc_netpoll,
#endif
diff --git a/drivers/net/ucc_geth.h b/drivers/net/ucc_geth.h
index ef1fbeb11c6..05a95586f3c 100644
--- a/drivers/net/ucc_geth.h
+++ b/drivers/net/ucc_geth.h
@@ -106,7 +106,7 @@ struct ucc_geth {
u32 scar; /* Statistics carry register */
u32 scam; /* Statistics caryy mask register */
u8 res5[0x200 - 0x1c4];
-} __attribute__ ((packed));
+} __packed;
/* UCC GETH TEMODR Register */
#define TEMODER_TX_RMON_STATISTICS_ENABLE 0x0100 /* enable Tx statistics
@@ -420,11 +420,11 @@ struct ucc_geth {
struct ucc_geth_thread_data_tx {
u8 res0[104];
-} __attribute__ ((packed));
+} __packed;
struct ucc_geth_thread_data_rx {
u8 res0[40];
-} __attribute__ ((packed));
+} __packed;
/* Send Queue Queue-Descriptor */
struct ucc_geth_send_queue_qd {
@@ -432,19 +432,19 @@ struct ucc_geth_send_queue_qd {
u8 res0[0x8];
u32 last_bd_completed_address;/* initialize to last entry in BD ring */
u8 res1[0x30];
-} __attribute__ ((packed));
+} __packed;
struct ucc_geth_send_queue_mem_region {
struct ucc_geth_send_queue_qd sqqd[NUM_TX_QUEUES];
-} __attribute__ ((packed));
+} __packed;
struct ucc_geth_thread_tx_pram {
u8 res0[64];
-} __attribute__ ((packed));
+} __packed;
struct ucc_geth_thread_rx_pram {
u8 res0[128];
-} __attribute__ ((packed));
+} __packed;
#define THREAD_RX_PRAM_ADDITIONAL_FOR_EXTENDED_FILTERING 64
#define THREAD_RX_PRAM_ADDITIONAL_FOR_EXTENDED_FILTERING_8 64
@@ -484,7 +484,7 @@ struct ucc_geth_scheduler {
/**< weight factor for queues */
u32 minw; /* temporary variable handled by QE */
u8 res1[0x70 - 0x64];
-} __attribute__ ((packed));
+} __packed;
struct ucc_geth_tx_firmware_statistics_pram {
u32 sicoltx; /* single collision */
@@ -506,7 +506,7 @@ struct ucc_geth_tx_firmware_statistics_pram {
and 1518 octets */
u32 txpktsjumbo; /* total packets (including bad) between 1024
and MAXLength octets */
-} __attribute__ ((packed));
+} __packed;
struct ucc_geth_rx_firmware_statistics_pram {
u32 frrxfcser; /* frames with crc error */
@@ -540,7 +540,7 @@ struct ucc_geth_rx_firmware_statistics_pram {
replaced */
u32 insertvlan; /* total frames that had their VLAN tag
inserted */
-} __attribute__ ((packed));
+} __packed;
struct ucc_geth_rx_interrupt_coalescing_entry {
u32 interruptcoalescingmaxvalue; /* interrupt coalescing max
@@ -548,23 +548,23 @@ struct ucc_geth_rx_interrupt_coalescing_entry {
u32 interruptcoalescingcounter; /* interrupt coalescing counter,
initialize to
interruptcoalescingmaxvalue */
-} __attribute__ ((packed));
+} __packed;
struct ucc_geth_rx_interrupt_coalescing_table {
struct ucc_geth_rx_interrupt_coalescing_entry coalescingentry[NUM_RX_QUEUES];
/**< interrupt coalescing entry */
-} __attribute__ ((packed));
+} __packed;
struct ucc_geth_rx_prefetched_bds {
struct qe_bd bd[NUM_BDS_IN_PREFETCHED_BDS]; /* prefetched bd */
-} __attribute__ ((packed));
+} __packed;
struct ucc_geth_rx_bd_queues_entry {
u32 bdbaseptr; /* BD base pointer */
u32 bdptr; /* BD pointer */
u32 externalbdbaseptr; /* external BD base pointer */
u32 externalbdptr; /* external BD pointer */
-} __attribute__ ((packed));
+} __packed;
struct ucc_geth_tx_global_pram {
u16 temoder;
@@ -580,13 +580,13 @@ struct ucc_geth_tx_global_pram {
u32 tqptr; /* a base pointer to the Tx Queues Memory
Region */
u8 res2[0x80 - 0x74];
-} __attribute__ ((packed));
+} __packed;
/* structure representing Extended Filtering Global Parameters in PRAM */
struct ucc_geth_exf_global_pram {
u32 l2pcdptr; /* individual address filter, high */
u8 res0[0x10 - 0x04];
-} __attribute__ ((packed));
+} __packed;
struct ucc_geth_rx_global_pram {
u32 remoder; /* ethernet mode reg. */
@@ -620,7 +620,7 @@ struct ucc_geth_rx_global_pram {
u32 exfGlobalParam; /* base address for extended filtering global
parameters */
u8 res6[0x100 - 0xC4]; /* Initialize to zero */
-} __attribute__ ((packed));
+} __packed;
#define GRACEFUL_STOP_ACKNOWLEDGE_RX 0x01
@@ -639,7 +639,7 @@ struct ucc_geth_init_pram {
u32 txglobal; /* tx global */
u32 txthread[ENET_INIT_PARAM_MAX_ENTRIES_TX]; /* tx threads */
u8 res3[0x1];
-} __attribute__ ((packed));
+} __packed;
#define ENET_INIT_PARAM_RGF_SHIFT (32 - 4)
#define ENET_INIT_PARAM_TGF_SHIFT (32 - 8)
@@ -661,7 +661,7 @@ struct ucc_geth_82xx_enet_address {
u16 h; /* address (MSB) */
u16 m; /* address */
u16 l; /* address (LSB) */
-} __attribute__ ((packed));
+} __packed;
/* structure representing 82xx Address Filtering PRAM */
struct ucc_geth_82xx_address_filtering_pram {
@@ -672,7 +672,7 @@ struct ucc_geth_82xx_address_filtering_pram {
struct ucc_geth_82xx_enet_address __iomem taddr;
struct ucc_geth_82xx_enet_address __iomem paddr[NUM_OF_PADDRS];
u8 res0[0x40 - 0x38];
-} __attribute__ ((packed));
+} __packed;
/* GETH Tx firmware statistics structure, used when calling
UCC_GETH_GetStatistics. */
@@ -696,7 +696,7 @@ struct ucc_geth_tx_firmware_statistics {
and 1518 octets */
u32 txpktsjumbo; /* total packets (including bad) between 1024
and MAXLength octets */
-} __attribute__ ((packed));
+} __packed;
/* GETH Rx firmware statistics structure, used when calling
UCC_GETH_GetStatistics. */
@@ -732,7 +732,7 @@ struct ucc_geth_rx_firmware_statistics {
replaced */
u32 insertvlan; /* total frames that had their VLAN tag
inserted */
-} __attribute__ ((packed));
+} __packed;
/* GETH hardware statistics structure, used when calling
UCC_GETH_GetStatistics. */
@@ -781,7 +781,7 @@ struct ucc_geth_hardware_statistics {
u32 rbca; /* Total number of frames received successfully
that had destination address equal to the
broadcast address */
-} __attribute__ ((packed));
+} __packed;
/* UCC GETH Tx errors returned via TxConf callback */
#define TX_ERRORS_DEF 0x0200
diff --git a/drivers/net/usb/asix.c b/drivers/net/usb/asix.c
index 9516f382a6b..aea4645be7f 100644
--- a/drivers/net/usb/asix.c
+++ b/drivers/net/usb/asix.c
@@ -179,7 +179,7 @@ struct ax88172_int_data {
__le16 res2;
u8 status;
__le16 res3;
-} __attribute__ ((packed));
+} __packed;
static int asix_read_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index,
u16 size, void *data)
diff --git a/drivers/net/usb/cdc-phonet.c b/drivers/net/usb/cdc-phonet.c
index dc9444525b4..109751bad3b 100644
--- a/drivers/net/usb/cdc-phonet.c
+++ b/drivers/net/usb/cdc-phonet.c
@@ -97,8 +97,9 @@ static void tx_complete(struct urb *req)
struct sk_buff *skb = req->context;
struct net_device *dev = skb->dev;
struct usbpn_dev *pnd = netdev_priv(dev);
+ int status = req->status;
- switch (req->status) {
+ switch (status) {
case 0:
dev->stats.tx_bytes += skb->len;
break;
@@ -109,7 +110,7 @@ static void tx_complete(struct urb *req)
dev->stats.tx_aborted_errors++;
default:
dev->stats.tx_errors++;
- dev_dbg(&dev->dev, "TX error (%d)\n", req->status);
+ dev_dbg(&dev->dev, "TX error (%d)\n", status);
}
dev->stats.tx_packets++;
@@ -150,8 +151,9 @@ static void rx_complete(struct urb *req)
struct page *page = virt_to_page(req->transfer_buffer);
struct sk_buff *skb;
unsigned long flags;
+ int status = req->status;
- switch (req->status) {
+ switch (status) {
case 0:
spin_lock_irqsave(&pnd->rx_lock, flags);
skb = pnd->rx_skb;
diff --git a/drivers/net/usb/hso.c b/drivers/net/usb/hso.c
index 4dd23513c5a..6efca66b876 100644
--- a/drivers/net/usb/hso.c
+++ b/drivers/net/usb/hso.c
@@ -73,7 +73,6 @@
#include <linux/serial.h>
-#define DRIVER_VERSION "1.2"
#define MOD_AUTHOR "Option Wireless"
#define MOD_DESCRIPTION "USB High Speed Option driver"
#define MOD_LICENSE "GPL"
@@ -211,7 +210,7 @@ struct hso_serial_state_notification {
u16 wIndex;
u16 wLength;
u16 UART_state_bitmap;
-} __attribute__((packed));
+} __packed;
struct hso_tiocmget {
struct mutex mutex;
@@ -401,7 +400,7 @@ static int disable_net;
/* driver info */
static const char driver_name[] = "hso";
static const char tty_filename[] = "ttyHS";
-static const char *version = __FILE__ ": " DRIVER_VERSION " " MOD_AUTHOR;
+static const char *version = __FILE__ ": " MOD_AUTHOR;
/* the usb driver itself (registered in hso_init) */
static struct usb_driver hso_driver;
/* serial structures */
@@ -478,6 +477,7 @@ static const struct usb_device_id hso_ids[] = {
{USB_DEVICE(0x0af0, 0x8600)},
{USB_DEVICE(0x0af0, 0x8800)},
{USB_DEVICE(0x0af0, 0x8900)},
+ {USB_DEVICE(0x0af0, 0x9000)},
{USB_DEVICE(0x0af0, 0xd035)},
{USB_DEVICE(0x0af0, 0xd055)},
{USB_DEVICE(0x0af0, 0xd155)},
@@ -848,7 +848,6 @@ static void hso_get_drvinfo(struct net_device *net, struct ethtool_drvinfo *info
struct hso_net *odev = netdev_priv(net);
strncpy(info->driver, driver_name, ETHTOOL_BUSINFO_LEN);
- strncpy(info->version, DRIVER_VERSION, ETHTOOL_BUSINFO_LEN);
usb_make_path(odev->parent->usb, info->bus_info, sizeof info->bus_info);
}
@@ -3388,7 +3387,6 @@ module_exit(hso_exit);
MODULE_AUTHOR(MOD_AUTHOR);
MODULE_DESCRIPTION(MOD_DESCRIPTION);
MODULE_LICENSE(MOD_LICENSE);
-MODULE_INFO(Version, DRIVER_VERSION);
/* change the debug level (eg: insmod hso.ko debug=0x04) */
MODULE_PARM_DESC(debug, "Level of debug [0x01 | 0x02 | 0x04 | 0x08 | 0x10]");
diff --git a/drivers/net/usb/ipheth.c b/drivers/net/usb/ipheth.c
index 197c352c47f..08e7b6abacd 100644
--- a/drivers/net/usb/ipheth.c
+++ b/drivers/net/usb/ipheth.c
@@ -193,7 +193,7 @@ static void ipheth_rcvbulk_callback(struct urb *urb)
case 0:
break;
default:
- err("%s: urb status: %d", __func__, urb->status);
+ err("%s: urb status: %d", __func__, status);
return;
}
@@ -222,16 +222,17 @@ static void ipheth_rcvbulk_callback(struct urb *urb)
static void ipheth_sndbulk_callback(struct urb *urb)
{
struct ipheth_device *dev;
+ int status = urb->status;
dev = urb->context;
if (dev == NULL)
return;
- if (urb->status != 0 &&
- urb->status != -ENOENT &&
- urb->status != -ECONNRESET &&
- urb->status != -ESHUTDOWN)
- err("%s: urb status: %d", __func__, urb->status);
+ if (status != 0 &&
+ status != -ENOENT &&
+ status != -ECONNRESET &&
+ status != -ESHUTDOWN)
+ err("%s: urb status: %d", __func__, status);
dev_kfree_skb_irq(dev->tx_skb);
netif_wake_queue(dev->net);
diff --git a/drivers/net/usb/kaweth.c b/drivers/net/usb/kaweth.c
index d6078b8c427..2b7b39cad1c 100644
--- a/drivers/net/usb/kaweth.c
+++ b/drivers/net/usb/kaweth.c
@@ -207,7 +207,7 @@ struct kaweth_ethernet_configuration
__le16 segment_size;
__u16 max_multicast_filters;
__u8 reserved3;
-} __attribute__ ((packed));
+} __packed;
/****************************************************************
* kaweth_device
diff --git a/drivers/net/usb/net1080.c b/drivers/net/usb/net1080.c
index 961a8ed38d8..ba72a7281cb 100644
--- a/drivers/net/usb/net1080.c
+++ b/drivers/net/usb/net1080.c
@@ -64,13 +64,13 @@ struct nc_header { // packed:
// all else is optional, and must start with:
// __le16 vendorId; // from usb-if
// __le16 productId;
-} __attribute__((__packed__));
+} __packed;
#define PAD_BYTE ((unsigned char)0xAC)
struct nc_trailer {
__le16 packet_id;
-} __attribute__((__packed__));
+} __packed;
// packets may use FLAG_FRAMING_NC and optional pad
#define FRAMED_SIZE(mtu) (sizeof (struct nc_header) \
diff --git a/drivers/net/usb/pegasus.c b/drivers/net/usb/pegasus.c
index 974d17f0263..6710f09346d 100644
--- a/drivers/net/usb/pegasus.c
+++ b/drivers/net/usb/pegasus.c
@@ -21,11 +21,11 @@
* behaves. Pegasus II support added since this version.
* TODO: suppressing HCD warnings spewage on disconnect.
* v0.4.13 Ethernet address is now set at probe(), not at open()
- * time as this seems to break dhcpd.
+ * time as this seems to break dhcpd.
* v0.5.0 branch to 2.5.x kernels
* v0.5.1 ethtool support added
* v0.5.5 rx socket buffers are in a pool and the their allocation
- * is out of the interrupt routine.
+ * is out of the interrupt routine.
*/
#include <linux/sched.h>
@@ -55,9 +55,9 @@ static const char driver_name[] = "pegasus";
#define BMSR_MEDIA (BMSR_10HALF | BMSR_10FULL | BMSR_100HALF | \
BMSR_100FULL | BMSR_ANEGCAPABLE)
-static int loopback = 0;
-static int mii_mode = 0;
-static char *devid=NULL;
+static int loopback;
+static int mii_mode;
+static char *devid;
static struct usb_eth_dev usb_dev_id[] = {
#define PEGASUS_DEV(pn, vid, pid, flags) \
@@ -102,8 +102,8 @@ MODULE_PARM_DESC(devid, "The format is: 'DEV_name:VendorID:DeviceID:Flags'");
/* use ethtool to change the level for any given device */
static int msg_level = -1;
-module_param (msg_level, int, 0);
-MODULE_PARM_DESC (msg_level, "Override default message level");
+module_param(msg_level, int, 0);
+MODULE_PARM_DESC(msg_level, "Override default message level");
MODULE_DEVICE_TABLE(usb, pegasus_ids);
static const struct net_device_ops pegasus_netdev_ops;
@@ -141,7 +141,7 @@ static void ctrl_callback(struct urb *urb)
wake_up(&pegasus->ctrl_wait);
}
-static int get_registers(pegasus_t * pegasus, __u16 indx, __u16 size,
+static int get_registers(pegasus_t *pegasus, __u16 indx, __u16 size,
void *data)
{
int ret;
@@ -196,7 +196,7 @@ out:
return ret;
}
-static int set_registers(pegasus_t * pegasus, __u16 indx, __u16 size,
+static int set_registers(pegasus_t *pegasus, __u16 indx, __u16 size,
void *data)
{
int ret;
@@ -248,7 +248,7 @@ out:
return ret;
}
-static int set_register(pegasus_t * pegasus, __u16 indx, __u8 data)
+static int set_register(pegasus_t *pegasus, __u16 indx, __u8 data)
{
int ret;
char *tmp;
@@ -299,7 +299,7 @@ out:
return ret;
}
-static int update_eth_regs_async(pegasus_t * pegasus)
+static int update_eth_regs_async(pegasus_t *pegasus)
{
int ret;
@@ -326,7 +326,7 @@ static int update_eth_regs_async(pegasus_t * pegasus)
}
/* Returns 0 on success, error on failure */
-static int read_mii_word(pegasus_t * pegasus, __u8 phy, __u8 indx, __u16 * regd)
+static int read_mii_word(pegasus_t *pegasus, __u8 phy, __u8 indx, __u16 *regd)
{
int i;
__u8 data[4] = { phy, 0, 0, indx };
@@ -334,7 +334,7 @@ static int read_mii_word(pegasus_t * pegasus, __u8 phy, __u8 indx, __u16 * regd)
int ret;
set_register(pegasus, PhyCtrl, 0);
- set_registers(pegasus, PhyAddr, sizeof (data), data);
+ set_registers(pegasus, PhyAddr, sizeof(data), data);
set_register(pegasus, PhyCtrl, (indx | PHY_READ));
for (i = 0; i < REG_TIMEOUT; i++) {
ret = get_registers(pegasus, PhyCtrl, 1, data);
@@ -366,7 +366,7 @@ static int mdio_read(struct net_device *dev, int phy_id, int loc)
return (int)res;
}
-static int write_mii_word(pegasus_t * pegasus, __u8 phy, __u8 indx, __u16 regd)
+static int write_mii_word(pegasus_t *pegasus, __u8 phy, __u8 indx, __u16 regd)
{
int i;
__u8 data[4] = { phy, 0, 0, indx };
@@ -402,7 +402,7 @@ static void mdio_write(struct net_device *dev, int phy_id, int loc, int val)
write_mii_word(pegasus, phy_id, loc, val);
}
-static int read_eprom_word(pegasus_t * pegasus, __u8 index, __u16 * retdata)
+static int read_eprom_word(pegasus_t *pegasus, __u8 index, __u16 *retdata)
{
int i;
__u8 tmp;
@@ -433,7 +433,7 @@ fail:
}
#ifdef PEGASUS_WRITE_EEPROM
-static inline void enable_eprom_write(pegasus_t * pegasus)
+static inline void enable_eprom_write(pegasus_t *pegasus)
{
__u8 tmp;
int ret;
@@ -442,7 +442,7 @@ static inline void enable_eprom_write(pegasus_t * pegasus)
set_register(pegasus, EthCtrl2, tmp | EPROM_WR_ENABLE);
}
-static inline void disable_eprom_write(pegasus_t * pegasus)
+static inline void disable_eprom_write(pegasus_t *pegasus)
{
__u8 tmp;
int ret;
@@ -452,7 +452,7 @@ static inline void disable_eprom_write(pegasus_t * pegasus)
set_register(pegasus, EthCtrl2, tmp & ~EPROM_WR_ENABLE);
}
-static int write_eprom_word(pegasus_t * pegasus, __u8 index, __u16 data)
+static int write_eprom_word(pegasus_t *pegasus, __u8 index, __u16 data)
{
int i;
__u8 tmp, d[4] = { 0x3f, 0, 0, EPROM_WRITE };
@@ -484,7 +484,7 @@ fail:
}
#endif /* PEGASUS_WRITE_EEPROM */
-static inline void get_node_id(pegasus_t * pegasus, __u8 * id)
+static inline void get_node_id(pegasus_t *pegasus, __u8 *id)
{
int i;
__u16 w16;
@@ -495,7 +495,7 @@ static inline void get_node_id(pegasus_t * pegasus, __u8 * id)
}
}
-static void set_ethernet_addr(pegasus_t * pegasus)
+static void set_ethernet_addr(pegasus_t *pegasus)
{
__u8 node_id[6];
@@ -503,12 +503,12 @@ static void set_ethernet_addr(pegasus_t * pegasus)
get_registers(pegasus, 0x10, sizeof(node_id), node_id);
} else {
get_node_id(pegasus, node_id);
- set_registers(pegasus, EthID, sizeof (node_id), node_id);
+ set_registers(pegasus, EthID, sizeof(node_id), node_id);
}
- memcpy(pegasus->net->dev_addr, node_id, sizeof (node_id));
+ memcpy(pegasus->net->dev_addr, node_id, sizeof(node_id));
}
-static inline int reset_mac(pegasus_t * pegasus)
+static inline int reset_mac(pegasus_t *pegasus)
{
__u8 data = 0x8;
int i;
@@ -563,7 +563,7 @@ static int enable_net_traffic(struct net_device *dev, struct usb_device *usb)
data[1] = 0;
data[2] = (loopback & 1) ? 0x09 : 0x01;
- memcpy(pegasus->eth_regs, data, sizeof (data));
+ memcpy(pegasus->eth_regs, data, sizeof(data));
ret = set_registers(pegasus, EthCtrl0, 3, data);
if (usb_dev_id[pegasus->dev_index].vendor == VENDOR_LINKSYS ||
@@ -577,7 +577,7 @@ static int enable_net_traffic(struct net_device *dev, struct usb_device *usb)
return ret;
}
-static void fill_skb_pool(pegasus_t * pegasus)
+static void fill_skb_pool(pegasus_t *pegasus)
{
int i;
@@ -595,7 +595,7 @@ static void fill_skb_pool(pegasus_t * pegasus)
}
}
-static void free_skb_pool(pegasus_t * pegasus)
+static void free_skb_pool(pegasus_t *pegasus)
{
int i;
@@ -667,11 +667,11 @@ static void read_bulk_callback(struct urb *urb)
netif_dbg(pegasus, rx_err, net,
"RX packet error %x\n", rx_status);
pegasus->stats.rx_errors++;
- if (rx_status & 0x06) // long or runt
+ if (rx_status & 0x06) /* long or runt */
pegasus->stats.rx_length_errors++;
if (rx_status & 0x08)
pegasus->stats.rx_crc_errors++;
- if (rx_status & 0x10) // extra bits
+ if (rx_status & 0x10) /* extra bits */
pegasus->stats.rx_frame_errors++;
goto goon;
}
@@ -748,9 +748,8 @@ static void rx_fixup(unsigned long data)
if (pegasus->flags & PEGASUS_RX_URB_FAIL)
if (pegasus->rx_skb)
goto try_again;
- if (pegasus->rx_skb == NULL) {
+ if (pegasus->rx_skb == NULL)
pegasus->rx_skb = pull_skb(pegasus);
- }
if (pegasus->rx_skb == NULL) {
netif_warn(pegasus, rx_err, pegasus->net, "low on memory\n");
tasklet_schedule(&pegasus->rx_tl);
@@ -835,7 +834,7 @@ static void intr_callback(struct urb *urb)
}
if (urb->actual_length >= 6) {
- u8 * d = urb->transfer_buffer;
+ u8 *d = urb->transfer_buffer;
/* byte 0 == tx_status1, reg 2B */
if (d[0] & (TX_UNDERRUN|EXCESSIVE_COL
@@ -918,14 +917,14 @@ static struct net_device_stats *pegasus_netdev_stats(struct net_device *dev)
return &((pegasus_t *) netdev_priv(dev))->stats;
}
-static inline void disable_net_traffic(pegasus_t * pegasus)
+static inline void disable_net_traffic(pegasus_t *pegasus)
{
__le16 tmp = cpu_to_le16(0);
set_registers(pegasus, EthCtrl0, sizeof(tmp), &tmp);
}
-static inline void get_interrupt_interval(pegasus_t * pegasus)
+static inline void get_interrupt_interval(pegasus_t *pegasus)
{
u16 data;
u8 interval;
@@ -961,7 +960,7 @@ static void set_carrier(struct net_device *net)
netif_carrier_off(net);
}
-static void free_all_urbs(pegasus_t * pegasus)
+static void free_all_urbs(pegasus_t *pegasus)
{
usb_free_urb(pegasus->intr_urb);
usb_free_urb(pegasus->tx_urb);
@@ -969,7 +968,7 @@ static void free_all_urbs(pegasus_t * pegasus)
usb_free_urb(pegasus->ctrl_urb);
}
-static void unlink_all_urbs(pegasus_t * pegasus)
+static void unlink_all_urbs(pegasus_t *pegasus)
{
usb_kill_urb(pegasus->intr_urb);
usb_kill_urb(pegasus->tx_urb);
@@ -977,12 +976,11 @@ static void unlink_all_urbs(pegasus_t * pegasus)
usb_kill_urb(pegasus->ctrl_urb);
}
-static int alloc_urbs(pegasus_t * pegasus)
+static int alloc_urbs(pegasus_t *pegasus)
{
pegasus->ctrl_urb = usb_alloc_urb(0, GFP_KERNEL);
- if (!pegasus->ctrl_urb) {
+ if (!pegasus->ctrl_urb)
return 0;
- }
pegasus->rx_urb = usb_alloc_urb(0, GFP_KERNEL);
if (!pegasus->rx_urb) {
usb_free_urb(pegasus->ctrl_urb);
@@ -1019,7 +1017,7 @@ static int pegasus_open(struct net_device *net)
return -ENOMEM;
res = set_registers(pegasus, EthID, 6, net->dev_addr);
-
+
usb_fill_bulk_urb(pegasus->rx_urb, pegasus->usb,
usb_rcvbulkpipe(pegasus->usb, 1),
pegasus->rx_skb->data, PEGASUS_MTU + 8,
@@ -1033,7 +1031,7 @@ static int pegasus_open(struct net_device *net)
usb_fill_int_urb(pegasus->intr_urb, pegasus->usb,
usb_rcvintpipe(pegasus->usb, 3),
- pegasus->intr_buff, sizeof (pegasus->intr_buff),
+ pegasus->intr_buff, sizeof(pegasus->intr_buff),
intr_callback, pegasus, pegasus->intr_interval);
if ((res = usb_submit_urb(pegasus->intr_urb, GFP_KERNEL))) {
if (res == -ENODEV)
@@ -1076,9 +1074,9 @@ static void pegasus_get_drvinfo(struct net_device *dev,
struct ethtool_drvinfo *info)
{
pegasus_t *pegasus = netdev_priv(dev);
- strncpy(info->driver, driver_name, sizeof (info->driver) - 1);
- strncpy(info->version, DRIVER_VERSION, sizeof (info->version) - 1);
- usb_make_path(pegasus->usb, info->bus_info, sizeof (info->bus_info));
+ strncpy(info->driver, driver_name, sizeof(info->driver) - 1);
+ strncpy(info->version, DRIVER_VERSION, sizeof(info->version) - 1);
+ usb_make_path(pegasus->usb, info->bus_info, sizeof(info->bus_info));
}
/* also handles three patterns of some kind in hardware */
@@ -1098,7 +1096,7 @@ pegasus_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
{
pegasus_t *pegasus = netdev_priv(dev);
u8 reg78 = 0x04;
-
+
if (wol->wolopts & ~WOL_SUPPORTED)
return -EINVAL;
@@ -1118,7 +1116,7 @@ pegasus_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
static inline void pegasus_reset_wol(struct net_device *dev)
{
struct ethtool_wolinfo wol;
-
+
memset(&wol, 0, sizeof wol);
(void) pegasus_set_wol(dev, &wol);
}
@@ -1178,7 +1176,7 @@ static const struct ethtool_ops ops = {
static int pegasus_ioctl(struct net_device *net, struct ifreq *rq, int cmd)
{
- __u16 *data = (__u16 *) & rq->ifr_ifru;
+ __u16 *data = (__u16 *) &rq->ifr_ifru;
pegasus_t *pegasus = netdev_priv(net);
int res;
@@ -1223,7 +1221,7 @@ static void pegasus_set_multicast(struct net_device *net)
ctrl_callback(pegasus->ctrl_urb);
}
-static __u8 mii_phy_probe(pegasus_t * pegasus)
+static __u8 mii_phy_probe(pegasus_t *pegasus)
{
int i;
__u16 tmp;
@@ -1239,10 +1237,10 @@ static __u8 mii_phy_probe(pegasus_t * pegasus)
return 0xff;
}
-static inline void setup_pegasus_II(pegasus_t * pegasus)
+static inline void setup_pegasus_II(pegasus_t *pegasus)
{
__u8 data = 0xa5;
-
+
set_register(pegasus, Reg1d, 0);
set_register(pegasus, Reg7b, 1);
mdelay(100);
@@ -1254,16 +1252,15 @@ static inline void setup_pegasus_II(pegasus_t * pegasus)
set_register(pegasus, 0x83, data);
get_registers(pegasus, 0x83, 1, &data);
- if (data == 0xa5) {
+ if (data == 0xa5)
pegasus->chip = 0x8513;
- } else {
+ else
pegasus->chip = 0;
- }
set_register(pegasus, 0x80, 0xc0);
set_register(pegasus, 0x83, 0xff);
set_register(pegasus, 0x84, 0x01);
-
+
if (pegasus->features & HAS_HOME_PNA && mii_mode)
set_register(pegasus, Reg81, 6);
else
@@ -1272,7 +1269,7 @@ static inline void setup_pegasus_II(pegasus_t * pegasus)
static int pegasus_count;
-static struct workqueue_struct *pegasus_workqueue = NULL;
+static struct workqueue_struct *pegasus_workqueue;
#define CARRIER_CHECK_DELAY (2 * HZ)
static void check_carrier(struct work_struct *work)
@@ -1367,7 +1364,7 @@ static int pegasus_probe(struct usb_interface *intf,
pegasus->mii.phy_id_mask = 0x1f;
pegasus->mii.reg_num_mask = 0x1f;
spin_lock_init(&pegasus->rx_pool_lock);
- pegasus->msg_enable = netif_msg_init (msg_level, NETIF_MSG_DRV
+ pegasus->msg_enable = netif_msg_init(msg_level, NETIF_MSG_DRV
| NETIF_MSG_PROBE | NETIF_MSG_LINK);
pegasus->features = usb_dev_id[dev_index].private;
@@ -1442,11 +1439,11 @@ static void pegasus_disconnect(struct usb_interface *intf)
pegasus_dec_workqueue();
}
-static int pegasus_suspend (struct usb_interface *intf, pm_message_t message)
+static int pegasus_suspend(struct usb_interface *intf, pm_message_t message)
{
struct pegasus *pegasus = usb_get_intfdata(intf);
-
- netif_device_detach (pegasus->net);
+
+ netif_device_detach(pegasus->net);
cancel_delayed_work(&pegasus->carrier_check);
if (netif_running(pegasus->net)) {
usb_kill_urb(pegasus->rx_urb);
@@ -1455,11 +1452,11 @@ static int pegasus_suspend (struct usb_interface *intf, pm_message_t message)
return 0;
}
-static int pegasus_resume (struct usb_interface *intf)
+static int pegasus_resume(struct usb_interface *intf)
{
struct pegasus *pegasus = usb_get_intfdata(intf);
- netif_device_attach (pegasus->net);
+ netif_device_attach(pegasus->net);
if (netif_running(pegasus->net)) {
pegasus->rx_urb->status = 0;
pegasus->rx_urb->actual_length = 0;
@@ -1498,8 +1495,8 @@ static struct usb_driver pegasus_driver = {
static void __init parse_id(char *id)
{
- unsigned int vendor_id=0, device_id=0, flags=0, i=0;
- char *token, *name=NULL;
+ unsigned int vendor_id = 0, device_id = 0, flags = 0, i = 0;
+ char *token, *name = NULL;
if ((token = strsep(&id, ":")) != NULL)
name = token;
@@ -1510,14 +1507,14 @@ static void __init parse_id(char *id)
device_id = simple_strtoul(token, NULL, 16);
flags = simple_strtoul(id, NULL, 16);
pr_info("%s: new device %s, vendor ID 0x%04x, device ID 0x%04x, flags: 0x%x\n",
- driver_name, name, vendor_id, device_id, flags);
+ driver_name, name, vendor_id, device_id, flags);
if (vendor_id > 0x10000 || vendor_id == 0)
return;
if (device_id > 0x10000 || device_id == 0)
return;
- for (i=0; usb_dev_id[i].name; i++);
+ for (i = 0; usb_dev_id[i].name; i++);
usb_dev_id[i].name = name;
usb_dev_id[i].vendor = vendor_id;
usb_dev_id[i].device = device_id;
diff --git a/drivers/net/usb/pegasus.h b/drivers/net/usb/pegasus.h
index 29f5211e645..65b78b35b73 100644
--- a/drivers/net/usb/pegasus.h
+++ b/drivers/net/usb/pegasus.h
@@ -68,7 +68,7 @@ enum pegasus_registers {
EpromData = 0x21, /* 0x21 low, 0x22 high byte */
EpromCtrl = 0x23,
PhyAddr = 0x25,
- PhyData = 0x26, /* 0x26 low, 0x27 high byte */
+ PhyData = 0x26, /* 0x26 low, 0x27 high byte */
PhyCtrl = 0x28,
UsbStst = 0x2a,
EthTxStat0 = 0x2b,
@@ -154,162 +154,162 @@ struct usb_eth_dev {
#else /* PEGASUS_DEV */
-PEGASUS_DEV( "3Com USB Ethernet 3C460B", VENDOR_3COM, 0x4601,
- DEFAULT_GPIO_RESET | PEGASUS_II )
-PEGASUS_DEV( "ATEN USB Ethernet UC-110T", VENDOR_ATEN, 0x2007,
- DEFAULT_GPIO_RESET | PEGASUS_II )
-PEGASUS_DEV( "USB HPNA/Ethernet", VENDOR_ABOCOM, 0x110c,
- DEFAULT_GPIO_RESET | PEGASUS_II | HAS_HOME_PNA )
-PEGASUS_DEV( "USB HPNA/Ethernet", VENDOR_ABOCOM, 0x4104,
- DEFAULT_GPIO_RESET | HAS_HOME_PNA )
-PEGASUS_DEV( "USB HPNA/Ethernet", VENDOR_ABOCOM, 0x4004,
- DEFAULT_GPIO_RESET | HAS_HOME_PNA )
-PEGASUS_DEV( "USB HPNA/Ethernet", VENDOR_ABOCOM, 0x4007,
- DEFAULT_GPIO_RESET | HAS_HOME_PNA )
-PEGASUS_DEV( "USB 10/100 Fast Ethernet", VENDOR_ABOCOM, 0x4102,
- DEFAULT_GPIO_RESET | PEGASUS_II )
-PEGASUS_DEV( "USB 10/100 Fast Ethernet", VENDOR_ABOCOM, 0x4002,
- DEFAULT_GPIO_RESET )
-PEGASUS_DEV( "USB 10/100 Fast Ethernet", VENDOR_ABOCOM, 0x400b,
- DEFAULT_GPIO_RESET | PEGASUS_II )
-PEGASUS_DEV( "USB 10/100 Fast Ethernet", VENDOR_ABOCOM, 0x400c,
- DEFAULT_GPIO_RESET | PEGASUS_II )
-PEGASUS_DEV( "USB 10/100 Fast Ethernet", VENDOR_ABOCOM, 0xabc1,
- DEFAULT_GPIO_RESET )
-PEGASUS_DEV( "USB 10/100 Fast Ethernet", VENDOR_ABOCOM, 0x200c,
- DEFAULT_GPIO_RESET | PEGASUS_II )
-PEGASUS_DEV( "Accton USB 10/100 Ethernet Adapter", VENDOR_ACCTON, 0x1046,
- DEFAULT_GPIO_RESET )
-PEGASUS_DEV( "SpeedStream USB 10/100 Ethernet", VENDOR_ACCTON, 0x5046,
- DEFAULT_GPIO_RESET | PEGASUS_II )
-PEGASUS_DEV( "Philips USB 10/100 Ethernet", VENDOR_ACCTON, 0xb004,
- DEFAULT_GPIO_RESET | PEGASUS_II )
-PEGASUS_DEV( "ADMtek ADM8511 \"Pegasus II\" USB Ethernet",
+PEGASUS_DEV("3Com USB Ethernet 3C460B", VENDOR_3COM, 0x4601,
+ DEFAULT_GPIO_RESET | PEGASUS_II)
+PEGASUS_DEV("ATEN USB Ethernet UC-110T", VENDOR_ATEN, 0x2007,
+ DEFAULT_GPIO_RESET | PEGASUS_II)
+PEGASUS_DEV("USB HPNA/Ethernet", VENDOR_ABOCOM, 0x110c,
+ DEFAULT_GPIO_RESET | PEGASUS_II | HAS_HOME_PNA)
+PEGASUS_DEV("USB HPNA/Ethernet", VENDOR_ABOCOM, 0x4104,
+ DEFAULT_GPIO_RESET | HAS_HOME_PNA)
+PEGASUS_DEV("USB HPNA/Ethernet", VENDOR_ABOCOM, 0x4004,
+ DEFAULT_GPIO_RESET | HAS_HOME_PNA)
+PEGASUS_DEV("USB HPNA/Ethernet", VENDOR_ABOCOM, 0x4007,
+ DEFAULT_GPIO_RESET | HAS_HOME_PNA)
+PEGASUS_DEV("USB 10/100 Fast Ethernet", VENDOR_ABOCOM, 0x4102,
+ DEFAULT_GPIO_RESET | PEGASUS_II)
+PEGASUS_DEV("USB 10/100 Fast Ethernet", VENDOR_ABOCOM, 0x4002,
+ DEFAULT_GPIO_RESET)
+PEGASUS_DEV("USB 10/100 Fast Ethernet", VENDOR_ABOCOM, 0x400b,
+ DEFAULT_GPIO_RESET | PEGASUS_II)
+PEGASUS_DEV("USB 10/100 Fast Ethernet", VENDOR_ABOCOM, 0x400c,
+ DEFAULT_GPIO_RESET | PEGASUS_II)
+PEGASUS_DEV("USB 10/100 Fast Ethernet", VENDOR_ABOCOM, 0xabc1,
+ DEFAULT_GPIO_RESET)
+PEGASUS_DEV("USB 10/100 Fast Ethernet", VENDOR_ABOCOM, 0x200c,
+ DEFAULT_GPIO_RESET | PEGASUS_II)
+PEGASUS_DEV("Accton USB 10/100 Ethernet Adapter", VENDOR_ACCTON, 0x1046,
+ DEFAULT_GPIO_RESET)
+PEGASUS_DEV("SpeedStream USB 10/100 Ethernet", VENDOR_ACCTON, 0x5046,
+ DEFAULT_GPIO_RESET | PEGASUS_II)
+PEGASUS_DEV("Philips USB 10/100 Ethernet", VENDOR_ACCTON, 0xb004,
+ DEFAULT_GPIO_RESET | PEGASUS_II)
+PEGASUS_DEV("ADMtek ADM8511 \"Pegasus II\" USB Ethernet",
VENDOR_ADMTEK, 0x8511,
- DEFAULT_GPIO_RESET | PEGASUS_II | HAS_HOME_PNA )
-PEGASUS_DEV( "ADMtek ADM8513 \"Pegasus II\" USB Ethernet",
+ DEFAULT_GPIO_RESET | PEGASUS_II | HAS_HOME_PNA)
+PEGASUS_DEV("ADMtek ADM8513 \"Pegasus II\" USB Ethernet",
VENDOR_ADMTEK, 0x8513,
- DEFAULT_GPIO_RESET | PEGASUS_II )
-PEGASUS_DEV( "ADMtek ADM8515 \"Pegasus II\" USB-2.0 Ethernet",
+ DEFAULT_GPIO_RESET | PEGASUS_II)
+PEGASUS_DEV("ADMtek ADM8515 \"Pegasus II\" USB-2.0 Ethernet",
VENDOR_ADMTEK, 0x8515,
- DEFAULT_GPIO_RESET | PEGASUS_II )
-PEGASUS_DEV( "ADMtek AN986 \"Pegasus\" USB Ethernet (evaluation board)",
+ DEFAULT_GPIO_RESET | PEGASUS_II)
+PEGASUS_DEV("ADMtek AN986 \"Pegasus\" USB Ethernet (evaluation board)",
VENDOR_ADMTEK, 0x0986,
- DEFAULT_GPIO_RESET | HAS_HOME_PNA )
-PEGASUS_DEV( "AN986A USB MAC", VENDOR_ADMTEK, 1986,
- DEFAULT_GPIO_RESET | PEGASUS_II )
-PEGASUS_DEV( "AEI USB Fast Ethernet Adapter", VENDOR_AEILAB, 0x1701,
- DEFAULT_GPIO_RESET | PEGASUS_II )
-PEGASUS_DEV( "Allied Telesyn Int. AT-USB100", VENDOR_ALLIEDTEL, 0xb100,
- DEFAULT_GPIO_RESET | PEGASUS_II )
+ DEFAULT_GPIO_RESET | HAS_HOME_PNA)
+PEGASUS_DEV("AN986A USB MAC", VENDOR_ADMTEK, 1986,
+ DEFAULT_GPIO_RESET | PEGASUS_II)
+PEGASUS_DEV("AEI USB Fast Ethernet Adapter", VENDOR_AEILAB, 0x1701,
+ DEFAULT_GPIO_RESET | PEGASUS_II)
+PEGASUS_DEV("Allied Telesyn Int. AT-USB100", VENDOR_ALLIEDTEL, 0xb100,
+ DEFAULT_GPIO_RESET | PEGASUS_II)
/*
* Distinguish between this Belkin adaptor and the Belkin bluetooth adaptors
* with the same product IDs by checking the device class too.
*/
-PEGASUS_DEV_CLASS( "Belkin F5D5050 USB Ethernet", VENDOR_BELKIN, 0x0121, 0x00,
- DEFAULT_GPIO_RESET | PEGASUS_II )
-PEGASUS_DEV( "Belkin F5U122 10/100 USB Ethernet", VENDOR_BELKIN, 0x0122,
- DEFAULT_GPIO_RESET | PEGASUS_II )
-PEGASUS_DEV( "Billionton USB-100", VENDOR_BILLIONTON, 0x0986,
- DEFAULT_GPIO_RESET )
-PEGASUS_DEV( "Billionton USBLP-100", VENDOR_BILLIONTON, 0x0987,
- DEFAULT_GPIO_RESET | HAS_HOME_PNA )
-PEGASUS_DEV( "iPAQ Networking 10/100 USB", VENDOR_COMPAQ, 0x8511,
- DEFAULT_GPIO_RESET | PEGASUS_II )
-PEGASUS_DEV( "Billionton USBEL-100", VENDOR_BILLIONTON, 0x0988,
- DEFAULT_GPIO_RESET )
-PEGASUS_DEV( "Billionton USBE-100", VENDOR_BILLIONTON, 0x8511,
- DEFAULT_GPIO_RESET | PEGASUS_II )
-PEGASUS_DEV( "Corega FEther USB-TX", VENDOR_COREGA, 0x0004,
- DEFAULT_GPIO_RESET )
-PEGASUS_DEV( "Corega FEther USB-TXS", VENDOR_COREGA, 0x000d,
- DEFAULT_GPIO_RESET | PEGASUS_II )
-PEGASUS_DEV( "D-Link DSB-650TX", VENDOR_DLINK, 0x4001,
- DEFAULT_GPIO_RESET )
-PEGASUS_DEV( "D-Link DSB-650TX", VENDOR_DLINK, 0x4002,
- DEFAULT_GPIO_RESET )
-PEGASUS_DEV( "D-Link DSB-650TX", VENDOR_DLINK, 0x4102,
- DEFAULT_GPIO_RESET | PEGASUS_II )
-PEGASUS_DEV( "D-Link DSB-650TX", VENDOR_DLINK, 0x400b,
- DEFAULT_GPIO_RESET | PEGASUS_II )
-PEGASUS_DEV( "D-Link DSB-650TX", VENDOR_DLINK, 0x200c,
- DEFAULT_GPIO_RESET | PEGASUS_II )
-PEGASUS_DEV( "D-Link DSB-650TX(PNA)", VENDOR_DLINK, 0x4003,
- DEFAULT_GPIO_RESET | HAS_HOME_PNA )
-PEGASUS_DEV( "D-Link DSB-650", VENDOR_DLINK, 0xabc1,
- DEFAULT_GPIO_RESET )
-PEGASUS_DEV( "GOLDPFEIL USB Adapter", VENDOR_ELCON, 0x0002,
- DEFAULT_GPIO_RESET | PEGASUS_II | HAS_HOME_PNA )
-PEGASUS_DEV( "ELECOM USB Ethernet LD-USB20", VENDOR_ELECOM, 0x4010,
- DEFAULT_GPIO_RESET | PEGASUS_II )
-PEGASUS_DEV( "EasiDock Ethernet", VENDOR_MOBILITY, 0x0304,
- DEFAULT_GPIO_RESET )
-PEGASUS_DEV( "Elsa Micolink USB2Ethernet", VENDOR_ELSA, 0x3000,
- DEFAULT_GPIO_RESET )
-PEGASUS_DEV( "GIGABYTE GN-BR402W Wireless Router", VENDOR_GIGABYTE, 0x8002,
- DEFAULT_GPIO_RESET )
-PEGASUS_DEV( "Hawking UF100 10/100 Ethernet", VENDOR_HAWKING, 0x400c,
- DEFAULT_GPIO_RESET | PEGASUS_II )
-PEGASUS_DEV( "HP hn210c Ethernet USB", VENDOR_HP, 0x811c,
- DEFAULT_GPIO_RESET | PEGASUS_II )
-PEGASUS_DEV( "IO DATA USB ET/TX", VENDOR_IODATA, 0x0904,
- DEFAULT_GPIO_RESET )
-PEGASUS_DEV( "IO DATA USB ET/TX-S", VENDOR_IODATA, 0x0913,
- DEFAULT_GPIO_RESET | PEGASUS_II )
-PEGASUS_DEV( "IO DATA USB ETX-US2", VENDOR_IODATA, 0x093a,
- DEFAULT_GPIO_RESET | PEGASUS_II )
-PEGASUS_DEV( "Kingston KNU101TX Ethernet", VENDOR_KINGSTON, 0x000a,
+PEGASUS_DEV_CLASS("Belkin F5D5050 USB Ethernet", VENDOR_BELKIN, 0x0121, 0x00,
+ DEFAULT_GPIO_RESET | PEGASUS_II)
+PEGASUS_DEV("Belkin F5U122 10/100 USB Ethernet", VENDOR_BELKIN, 0x0122,
+ DEFAULT_GPIO_RESET | PEGASUS_II)
+PEGASUS_DEV("Billionton USB-100", VENDOR_BILLIONTON, 0x0986,
+ DEFAULT_GPIO_RESET)
+PEGASUS_DEV("Billionton USBLP-100", VENDOR_BILLIONTON, 0x0987,
+ DEFAULT_GPIO_RESET | HAS_HOME_PNA)
+PEGASUS_DEV("iPAQ Networking 10/100 USB", VENDOR_COMPAQ, 0x8511,
+ DEFAULT_GPIO_RESET | PEGASUS_II)
+PEGASUS_DEV("Billionton USBEL-100", VENDOR_BILLIONTON, 0x0988,
+ DEFAULT_GPIO_RESET)
+PEGASUS_DEV("Billionton USBE-100", VENDOR_BILLIONTON, 0x8511,
+ DEFAULT_GPIO_RESET | PEGASUS_II)
+PEGASUS_DEV("Corega FEther USB-TX", VENDOR_COREGA, 0x0004,
+ DEFAULT_GPIO_RESET)
+PEGASUS_DEV("Corega FEther USB-TXS", VENDOR_COREGA, 0x000d,
+ DEFAULT_GPIO_RESET | PEGASUS_II)
+PEGASUS_DEV("D-Link DSB-650TX", VENDOR_DLINK, 0x4001,
+ DEFAULT_GPIO_RESET)
+PEGASUS_DEV("D-Link DSB-650TX", VENDOR_DLINK, 0x4002,
+ DEFAULT_GPIO_RESET)
+PEGASUS_DEV("D-Link DSB-650TX", VENDOR_DLINK, 0x4102,
+ DEFAULT_GPIO_RESET | PEGASUS_II)
+PEGASUS_DEV("D-Link DSB-650TX", VENDOR_DLINK, 0x400b,
+ DEFAULT_GPIO_RESET | PEGASUS_II)
+PEGASUS_DEV("D-Link DSB-650TX", VENDOR_DLINK, 0x200c,
+ DEFAULT_GPIO_RESET | PEGASUS_II)
+PEGASUS_DEV("D-Link DSB-650TX(PNA)", VENDOR_DLINK, 0x4003,
+ DEFAULT_GPIO_RESET | HAS_HOME_PNA)
+PEGASUS_DEV("D-Link DSB-650", VENDOR_DLINK, 0xabc1,
+ DEFAULT_GPIO_RESET)
+PEGASUS_DEV("GOLDPFEIL USB Adapter", VENDOR_ELCON, 0x0002,
+ DEFAULT_GPIO_RESET | PEGASUS_II | HAS_HOME_PNA)
+PEGASUS_DEV("ELECOM USB Ethernet LD-USB20", VENDOR_ELECOM, 0x4010,
+ DEFAULT_GPIO_RESET | PEGASUS_II)
+PEGASUS_DEV("EasiDock Ethernet", VENDOR_MOBILITY, 0x0304,
+ DEFAULT_GPIO_RESET)
+PEGASUS_DEV("Elsa Micolink USB2Ethernet", VENDOR_ELSA, 0x3000,
DEFAULT_GPIO_RESET)
-PEGASUS_DEV( "LANEED USB Ethernet LD-USB/TX", VENDOR_LANEED, 0x4002,
- DEFAULT_GPIO_RESET )
-PEGASUS_DEV( "LANEED USB Ethernet LD-USBL/TX", VENDOR_LANEED, 0x4005,
- DEFAULT_GPIO_RESET | PEGASUS_II)
-PEGASUS_DEV( "LANEED USB Ethernet LD-USB/TX", VENDOR_LANEED, 0x400b,
- DEFAULT_GPIO_RESET | PEGASUS_II )
-PEGASUS_DEV( "LANEED USB Ethernet LD-USB/T", VENDOR_LANEED, 0xabc1,
- DEFAULT_GPIO_RESET )
-PEGASUS_DEV( "LANEED USB Ethernet LD-USB/TX", VENDOR_LANEED, 0x200c,
- DEFAULT_GPIO_RESET | PEGASUS_II )
-PEGASUS_DEV( "Linksys USB10TX", VENDOR_LINKSYS, 0x2202,
- DEFAULT_GPIO_RESET )
-PEGASUS_DEV( "Linksys USB100TX", VENDOR_LINKSYS, 0x2203,
- DEFAULT_GPIO_RESET )
-PEGASUS_DEV( "Linksys USB100TX", VENDOR_LINKSYS, 0x2204,
- DEFAULT_GPIO_RESET | HAS_HOME_PNA )
-PEGASUS_DEV( "Linksys USB10T Ethernet Adapter", VENDOR_LINKSYS, 0x2206,
- DEFAULT_GPIO_RESET | PEGASUS_II)
-PEGASUS_DEV( "Linksys USBVPN1", VENDOR_LINKSYS2, 0x08b4,
- DEFAULT_GPIO_RESET )
-PEGASUS_DEV( "Linksys USB USB100TX", VENDOR_LINKSYS, 0x400b,
- DEFAULT_GPIO_RESET | PEGASUS_II )
-PEGASUS_DEV( "Linksys USB10TX", VENDOR_LINKSYS, 0x200c,
- DEFAULT_GPIO_RESET | PEGASUS_II )
-PEGASUS_DEV( "MELCO/BUFFALO LUA-TX", VENDOR_MELCO, 0x0001,
- DEFAULT_GPIO_RESET )
-PEGASUS_DEV( "MELCO/BUFFALO LUA-TX", VENDOR_MELCO, 0x0005,
- DEFAULT_GPIO_RESET )
-PEGASUS_DEV( "MELCO/BUFFALO LUA2-TX", VENDOR_MELCO, 0x0009,
- DEFAULT_GPIO_RESET | PEGASUS_II )
-PEGASUS_DEV( "Microsoft MN-110", VENDOR_MICROSOFT, 0x007a,
- DEFAULT_GPIO_RESET | PEGASUS_II )
-PEGASUS_DEV( "NETGEAR FA101", VENDOR_NETGEAR, 0x1020,
- DEFAULT_GPIO_RESET | PEGASUS_II )
-PEGASUS_DEV( "OCT Inc.", VENDOR_OCT, 0x0109,
- DEFAULT_GPIO_RESET | PEGASUS_II )
-PEGASUS_DEV( "OCT USB TO Ethernet", VENDOR_OCT, 0x0901,
- DEFAULT_GPIO_RESET | PEGASUS_II )
-PEGASUS_DEV( "smartNIC 2 PnP Adapter", VENDOR_SMARTBRIDGES, 0x0003,
- DEFAULT_GPIO_RESET | PEGASUS_II )
-PEGASUS_DEV( "SMC 202 USB Ethernet", VENDOR_SMC, 0x0200,
- DEFAULT_GPIO_RESET )
-PEGASUS_DEV( "SMC 2206 USB Ethernet", VENDOR_SMC, 0x0201,
- DEFAULT_GPIO_RESET | PEGASUS_II)
-PEGASUS_DEV( "SOHOware NUB100 Ethernet", VENDOR_SOHOWARE, 0x9100,
- DEFAULT_GPIO_RESET )
-PEGASUS_DEV( "SOHOware NUB110 Ethernet", VENDOR_SOHOWARE, 0x9110,
- DEFAULT_GPIO_RESET | PEGASUS_II )
-PEGASUS_DEV( "SpeedStream USB 10/100 Ethernet", VENDOR_SIEMENS, 0x1001,
- DEFAULT_GPIO_RESET | PEGASUS_II )
+PEGASUS_DEV("GIGABYTE GN-BR402W Wireless Router", VENDOR_GIGABYTE, 0x8002,
+ DEFAULT_GPIO_RESET)
+PEGASUS_DEV("Hawking UF100 10/100 Ethernet", VENDOR_HAWKING, 0x400c,
+ DEFAULT_GPIO_RESET | PEGASUS_II)
+PEGASUS_DEV("HP hn210c Ethernet USB", VENDOR_HP, 0x811c,
+ DEFAULT_GPIO_RESET | PEGASUS_II)
+PEGASUS_DEV("IO DATA USB ET/TX", VENDOR_IODATA, 0x0904,
+ DEFAULT_GPIO_RESET)
+PEGASUS_DEV("IO DATA USB ET/TX-S", VENDOR_IODATA, 0x0913,
+ DEFAULT_GPIO_RESET | PEGASUS_II)
+PEGASUS_DEV("IO DATA USB ETX-US2", VENDOR_IODATA, 0x093a,
+ DEFAULT_GPIO_RESET | PEGASUS_II)
+PEGASUS_DEV("Kingston KNU101TX Ethernet", VENDOR_KINGSTON, 0x000a,
+ DEFAULT_GPIO_RESET)
+PEGASUS_DEV("LANEED USB Ethernet LD-USB/TX", VENDOR_LANEED, 0x4002,
+ DEFAULT_GPIO_RESET)
+PEGASUS_DEV("LANEED USB Ethernet LD-USBL/TX", VENDOR_LANEED, 0x4005,
+ DEFAULT_GPIO_RESET | PEGASUS_II)
+PEGASUS_DEV("LANEED USB Ethernet LD-USB/TX", VENDOR_LANEED, 0x400b,
+ DEFAULT_GPIO_RESET | PEGASUS_II)
+PEGASUS_DEV("LANEED USB Ethernet LD-USB/T", VENDOR_LANEED, 0xabc1,
+ DEFAULT_GPIO_RESET)
+PEGASUS_DEV("LANEED USB Ethernet LD-USB/TX", VENDOR_LANEED, 0x200c,
+ DEFAULT_GPIO_RESET | PEGASUS_II)
+PEGASUS_DEV("Linksys USB10TX", VENDOR_LINKSYS, 0x2202,
+ DEFAULT_GPIO_RESET)
+PEGASUS_DEV("Linksys USB100TX", VENDOR_LINKSYS, 0x2203,
+ DEFAULT_GPIO_RESET)
+PEGASUS_DEV("Linksys USB100TX", VENDOR_LINKSYS, 0x2204,
+ DEFAULT_GPIO_RESET | HAS_HOME_PNA)
+PEGASUS_DEV("Linksys USB10T Ethernet Adapter", VENDOR_LINKSYS, 0x2206,
+ DEFAULT_GPIO_RESET | PEGASUS_II)
+PEGASUS_DEV("Linksys USBVPN1", VENDOR_LINKSYS2, 0x08b4,
+ DEFAULT_GPIO_RESET)
+PEGASUS_DEV("Linksys USB USB100TX", VENDOR_LINKSYS, 0x400b,
+ DEFAULT_GPIO_RESET | PEGASUS_II)
+PEGASUS_DEV("Linksys USB10TX", VENDOR_LINKSYS, 0x200c,
+ DEFAULT_GPIO_RESET | PEGASUS_II)
+PEGASUS_DEV("MELCO/BUFFALO LUA-TX", VENDOR_MELCO, 0x0001,
+ DEFAULT_GPIO_RESET)
+PEGASUS_DEV("MELCO/BUFFALO LUA-TX", VENDOR_MELCO, 0x0005,
+ DEFAULT_GPIO_RESET)
+PEGASUS_DEV("MELCO/BUFFALO LUA2-TX", VENDOR_MELCO, 0x0009,
+ DEFAULT_GPIO_RESET | PEGASUS_II)
+PEGASUS_DEV("Microsoft MN-110", VENDOR_MICROSOFT, 0x007a,
+ DEFAULT_GPIO_RESET | PEGASUS_II)
+PEGASUS_DEV("NETGEAR FA101", VENDOR_NETGEAR, 0x1020,
+ DEFAULT_GPIO_RESET | PEGASUS_II)
+PEGASUS_DEV("OCT Inc.", VENDOR_OCT, 0x0109,
+ DEFAULT_GPIO_RESET | PEGASUS_II)
+PEGASUS_DEV("OCT USB TO Ethernet", VENDOR_OCT, 0x0901,
+ DEFAULT_GPIO_RESET | PEGASUS_II)
+PEGASUS_DEV("smartNIC 2 PnP Adapter", VENDOR_SMARTBRIDGES, 0x0003,
+ DEFAULT_GPIO_RESET | PEGASUS_II)
+PEGASUS_DEV("SMC 202 USB Ethernet", VENDOR_SMC, 0x0200,
+ DEFAULT_GPIO_RESET)
+PEGASUS_DEV("SMC 2206 USB Ethernet", VENDOR_SMC, 0x0201,
+ DEFAULT_GPIO_RESET | PEGASUS_II)
+PEGASUS_DEV("SOHOware NUB100 Ethernet", VENDOR_SOHOWARE, 0x9100,
+ DEFAULT_GPIO_RESET)
+PEGASUS_DEV("SOHOware NUB110 Ethernet", VENDOR_SOHOWARE, 0x9110,
+ DEFAULT_GPIO_RESET | PEGASUS_II)
+PEGASUS_DEV("SpeedStream USB 10/100 Ethernet", VENDOR_SIEMENS, 0x1001,
+ DEFAULT_GPIO_RESET | PEGASUS_II)
#endif /* PEGASUS_DEV */
diff --git a/drivers/net/usb/sierra_net.c b/drivers/net/usb/sierra_net.c
index f1942d69a0d..ee85c8b9a85 100644
--- a/drivers/net/usb/sierra_net.c
+++ b/drivers/net/usb/sierra_net.c
@@ -165,7 +165,7 @@ struct lsi_umts {
u8 gw_addr_len; /* NW-supplied GW address len */
u8 gw_addr[16]; /* NW-supplied GW address (bigendian) */
u8 reserved[8];
-} __attribute__ ((packed));
+} __packed;
#define SIERRA_NET_LSI_COMMON_LEN 4
#define SIERRA_NET_LSI_UMTS_LEN (sizeof(struct lsi_umts))
diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c
index 81c76ada8e5..3b03794ac3f 100644
--- a/drivers/net/usb/usbnet.c
+++ b/drivers/net/usb/usbnet.c
@@ -44,6 +44,7 @@
#include <linux/usb.h>
#include <linux/usb/usbnet.h>
#include <linux/slab.h>
+#include <linux/kernel.h>
#define DRIVER_VERSION "22-Aug-2005"
@@ -158,16 +159,6 @@ int usbnet_get_endpoints(struct usbnet *dev, struct usb_interface *intf)
}
EXPORT_SYMBOL_GPL(usbnet_get_endpoints);
-static u8 nibble(unsigned char c)
-{
- if (likely(isdigit(c)))
- return c - '0';
- c = toupper(c);
- if (likely(isxdigit(c)))
- return 10 + c - 'A';
- return 0;
-}
-
int usbnet_get_ethernet_addr(struct usbnet *dev, int iMACAddress)
{
int tmp, i;
@@ -183,7 +174,7 @@ int usbnet_get_ethernet_addr(struct usbnet *dev, int iMACAddress)
}
for (i = tmp = 0; i < 6; i++, tmp += 2)
dev->net->dev_addr [i] =
- (nibble(buf [tmp]) << 4) + nibble(buf [tmp + 1]);
+ (hex_to_bin(buf[tmp]) << 4) + hex_to_bin(buf[tmp + 1]);
return 0;
}
EXPORT_SYMBOL_GPL(usbnet_get_ethernet_addr);
@@ -624,7 +615,7 @@ static void usbnet_terminate_urbs(struct usbnet *dev)
while (!skb_queue_empty(&dev->rxq)
&& !skb_queue_empty(&dev->txq)
&& !skb_queue_empty(&dev->done)) {
- schedule_timeout(UNLINK_TIMEOUT_MS);
+ schedule_timeout(msecs_to_jiffies(UNLINK_TIMEOUT_MS));
set_current_state(TASK_UNINTERRUPTIBLE);
netif_dbg(dev, ifdown, dev->net,
"waited for %d urb completions\n", temp);
@@ -643,7 +634,7 @@ int usbnet_stop (struct net_device *net)
netif_stop_queue (net);
netif_info(dev, ifdown, dev->net,
- "stop stats: rx/tx %ld/%ld, errs %ld/%ld\n",
+ "stop stats: rx/tx %lu/%lu, errs %lu/%lu\n",
net->stats.rx_packets, net->stats.tx_packets,
net->stats.rx_errors, net->stats.tx_errors);
diff --git a/drivers/net/via-velocity.h b/drivers/net/via-velocity.h
index c38191179fa..f7b33ae7a70 100644
--- a/drivers/net/via-velocity.h
+++ b/drivers/net/via-velocity.h
@@ -193,7 +193,7 @@ struct rx_desc {
__le32 pa_low; /* Low 32 bit PCI address */
__le16 pa_high; /* Next 16 bit PCI address (48 total) */
__le16 size; /* bits 0--14 - frame size, bit 15 - enable int. */
-} __attribute__ ((__packed__));
+} __packed;
/*
* Transmit descriptor
@@ -208,7 +208,7 @@ struct tdesc1 {
__le16 vlan;
u8 TCR;
u8 cmd; /* bits 0--1 - TCPLS, bits 4--7 - CMDZ */
-} __attribute__ ((__packed__));
+} __packed;
enum {
TD_QUEUE = cpu_to_le16(0x8000)
@@ -218,7 +218,7 @@ struct td_buf {
__le32 pa_low;
__le16 pa_high;
__le16 size; /* bits 0--13 - size, bit 15 - queue */
-} __attribute__ ((__packed__));
+} __packed;
struct tx_desc {
struct tdesc0 tdesc0;
@@ -1096,7 +1096,7 @@ struct mac_regs {
volatile __le16 PatternCRC[8]; /* 0xB0 */
volatile __le32 ByteMask[4][4]; /* 0xC0 */
-} __attribute__ ((__packed__));
+} __packed;
enum hw_mib {
@@ -1216,7 +1216,7 @@ struct arp_packet {
u8 ar_sip[4];
u8 ar_tha[ETH_ALEN];
u8 ar_tip[4];
-} __attribute__ ((__packed__));
+} __packed;
struct _magic_packet {
u8 dest_mac[6];
@@ -1224,7 +1224,7 @@ struct _magic_packet {
__be16 type;
u8 MAC[16][6];
u8 password[6];
-} __attribute__ ((__packed__));
+} __packed;
/*
* Store for chip context when saving and restoring status. Not
diff --git a/drivers/net/vmxnet3/vmxnet3_defs.h b/drivers/net/vmxnet3/vmxnet3_defs.h
index b4889e6c4a5..ca7727b940a 100644
--- a/drivers/net/vmxnet3/vmxnet3_defs.h
+++ b/drivers/net/vmxnet3/vmxnet3_defs.h
@@ -464,6 +464,9 @@ enum vmxnet3_intr_type {
/* addition 1 for events */
#define VMXNET3_MAX_INTRS 25
+/* value of intrCtrl */
+#define VMXNET3_IC_DISABLE_ALL 0x1 /* bit 0 */
+
struct Vmxnet3_IntrConf {
bool autoMask;
@@ -471,7 +474,8 @@ struct Vmxnet3_IntrConf {
u8 eventIntrIdx;
u8 modLevels[VMXNET3_MAX_INTRS]; /* moderation level for
* each intr */
- __le32 reserved[3];
+ __le32 intrCtrl;
+ __le32 reserved[2];
};
/* one bit per VLAN ID, the size is in the units of u32 */
diff --git a/drivers/net/vmxnet3/vmxnet3_drv.c b/drivers/net/vmxnet3/vmxnet3_drv.c
index 989b742551a..abe0ff53daf 100644
--- a/drivers/net/vmxnet3/vmxnet3_drv.c
+++ b/drivers/net/vmxnet3/vmxnet3_drv.c
@@ -72,6 +72,8 @@ vmxnet3_enable_all_intrs(struct vmxnet3_adapter *adapter)
for (i = 0; i < adapter->intr.num_intrs; i++)
vmxnet3_enable_intr(adapter, i);
+ adapter->shared->devRead.intrConf.intrCtrl &=
+ cpu_to_le32(~VMXNET3_IC_DISABLE_ALL);
}
@@ -80,6 +82,8 @@ vmxnet3_disable_all_intrs(struct vmxnet3_adapter *adapter)
{
int i;
+ adapter->shared->devRead.intrConf.intrCtrl |=
+ cpu_to_le32(VMXNET3_IC_DISABLE_ALL);
for (i = 0; i < adapter->intr.num_intrs; i++)
vmxnet3_disable_intr(adapter, i);
}
@@ -128,7 +132,7 @@ vmxnet3_tq_stop(struct vmxnet3_tx_queue *tq, struct vmxnet3_adapter *adapter)
* Check the link state. This may start or stop the tx queue.
*/
static void
-vmxnet3_check_link(struct vmxnet3_adapter *adapter)
+vmxnet3_check_link(struct vmxnet3_adapter *adapter, bool affectTxQueue)
{
u32 ret;
@@ -141,14 +145,16 @@ vmxnet3_check_link(struct vmxnet3_adapter *adapter)
if (!netif_carrier_ok(adapter->netdev))
netif_carrier_on(adapter->netdev);
- vmxnet3_tq_start(&adapter->tx_queue, adapter);
+ if (affectTxQueue)
+ vmxnet3_tq_start(&adapter->tx_queue, adapter);
} else {
printk(KERN_INFO "%s: NIC Link is Down\n",
adapter->netdev->name);
if (netif_carrier_ok(adapter->netdev))
netif_carrier_off(adapter->netdev);
- vmxnet3_tq_stop(&adapter->tx_queue, adapter);
+ if (affectTxQueue)
+ vmxnet3_tq_stop(&adapter->tx_queue, adapter);
}
}
@@ -163,7 +169,7 @@ vmxnet3_process_events(struct vmxnet3_adapter *adapter)
/* Check if link state has changed */
if (events & VMXNET3_ECR_LINK)
- vmxnet3_check_link(adapter);
+ vmxnet3_check_link(adapter, true);
/* Check if there is an error on xmit/recv queues */
if (events & (VMXNET3_ECR_TQERR | VMXNET3_ECR_RQERR)) {
@@ -658,8 +664,13 @@ vmxnet3_map_pkt(struct sk_buff *skb, struct vmxnet3_tx_ctx *ctx,
while (len) {
u32 buf_size;
- buf_size = len > VMXNET3_MAX_TX_BUF_SIZE ?
- VMXNET3_MAX_TX_BUF_SIZE : len;
+ if (len < VMXNET3_MAX_TX_BUF_SIZE) {
+ buf_size = len;
+ dw2 |= len;
+ } else {
+ buf_size = VMXNET3_MAX_TX_BUF_SIZE;
+ /* spec says that for TxDesc.len, 0 == 2^14 */
+ }
tbi = tq->buf_info + tq->tx_ring.next2fill;
tbi->map_type = VMXNET3_MAP_SINGLE;
@@ -667,13 +678,13 @@ vmxnet3_map_pkt(struct sk_buff *skb, struct vmxnet3_tx_ctx *ctx,
skb->data + buf_offset, buf_size,
PCI_DMA_TODEVICE);
- tbi->len = buf_size; /* this automatically convert 2^14 to 0 */
+ tbi->len = buf_size;
gdesc = tq->tx_ring.base + tq->tx_ring.next2fill;
BUG_ON(gdesc->txd.gen == tq->tx_ring.gen);
gdesc->txd.addr = cpu_to_le64(tbi->dma_addr);
- gdesc->dword[2] = cpu_to_le32(dw2 | buf_size);
+ gdesc->dword[2] = cpu_to_le32(dw2);
gdesc->dword[3] = 0;
dev_dbg(&adapter->netdev->dev,
@@ -1825,6 +1836,7 @@ vmxnet3_setup_driver_shared(struct vmxnet3_adapter *adapter)
devRead->intrConf.modLevels[i] = adapter->intr.mod_levels[i];
devRead->intrConf.eventIntrIdx = adapter->intr.event_intr_idx;
+ devRead->intrConf.intrCtrl |= cpu_to_le32(VMXNET3_IC_DISABLE_ALL);
/* rx filter settings */
devRead->rxFilterConf.rxMode = 0;
@@ -1889,7 +1901,7 @@ vmxnet3_activate_dev(struct vmxnet3_adapter *adapter)
* Check link state when first activating device. It will start the
* tx queue if the link is up.
*/
- vmxnet3_check_link(adapter);
+ vmxnet3_check_link(adapter, true);
napi_enable(&adapter->napi);
vmxnet3_enable_all_intrs(adapter);
@@ -2295,9 +2307,13 @@ vmxnet3_alloc_intr_resources(struct vmxnet3_adapter *adapter)
adapter->intr.mask_mode = (cfg >> 2) & 0x3;
if (adapter->intr.type == VMXNET3_IT_AUTO) {
- int err;
+ adapter->intr.type = VMXNET3_IT_MSIX;
+ }
#ifdef CONFIG_PCI_MSI
+ if (adapter->intr.type == VMXNET3_IT_MSIX) {
+ int err;
+
adapter->intr.msix_entries[0].entry = 0;
err = pci_enable_msix(adapter->pdev, adapter->intr.msix_entries,
VMXNET3_LINUX_MAX_MSIX_VECT);
@@ -2306,15 +2322,18 @@ vmxnet3_alloc_intr_resources(struct vmxnet3_adapter *adapter)
adapter->intr.type = VMXNET3_IT_MSIX;
return;
}
-#endif
+ adapter->intr.type = VMXNET3_IT_MSI;
+ }
+ if (adapter->intr.type == VMXNET3_IT_MSI) {
+ int err;
err = pci_enable_msi(adapter->pdev);
if (!err) {
adapter->intr.num_intrs = 1;
- adapter->intr.type = VMXNET3_IT_MSI;
return;
}
}
+#endif /* CONFIG_PCI_MSI */
adapter->intr.type = VMXNET3_IT_INTX;
@@ -2358,6 +2377,7 @@ vmxnet3_reset_work(struct work_struct *data)
return;
/* if the device is closed, we must leave it alone */
+ rtnl_lock();
if (netif_running(adapter->netdev)) {
printk(KERN_INFO "%s: resetting\n", adapter->netdev->name);
vmxnet3_quiesce_dev(adapter);
@@ -2366,6 +2386,7 @@ vmxnet3_reset_work(struct work_struct *data)
} else {
printk(KERN_INFO "%s: already closed\n", adapter->netdev->name);
}
+ rtnl_unlock();
clear_bit(VMXNET3_STATE_BIT_RESETTING, &adapter->state);
}
@@ -2491,6 +2512,7 @@ vmxnet3_probe_device(struct pci_dev *pdev,
}
set_bit(VMXNET3_STATE_BIT_QUIESCED, &adapter->state);
+ vmxnet3_check_link(adapter, false);
atomic_inc(&devices_found);
return 0;
diff --git a/drivers/net/vmxnet3/vmxnet3_ethtool.c b/drivers/net/vmxnet3/vmxnet3_ethtool.c
index 3935c4493fb..7e4b5a89165 100644
--- a/drivers/net/vmxnet3/vmxnet3_ethtool.c
+++ b/drivers/net/vmxnet3/vmxnet3_ethtool.c
@@ -275,27 +275,27 @@ vmxnet3_get_strings(struct net_device *netdev, u32 stringset, u8 *buf)
}
}
-static u32
-vmxnet3_get_flags(struct net_device *netdev) {
- return netdev->features;
-}
-
static int
-vmxnet3_set_flags(struct net_device *netdev, u32 data) {
+vmxnet3_set_flags(struct net_device *netdev, u32 data)
+{
struct vmxnet3_adapter *adapter = netdev_priv(netdev);
u8 lro_requested = (data & ETH_FLAG_LRO) == 0 ? 0 : 1;
u8 lro_present = (netdev->features & NETIF_F_LRO) == 0 ? 0 : 1;
+ if (data & ~ETH_FLAG_LRO)
+ return -EOPNOTSUPP;
+
if (lro_requested ^ lro_present) {
/* toggle the LRO feature*/
netdev->features ^= NETIF_F_LRO;
/* update harware LRO capability accordingly */
if (lro_requested)
- adapter->shared->devRead.misc.uptFeatures &= UPT1_F_LRO;
+ adapter->shared->devRead.misc.uptFeatures |=
+ cpu_to_le64(UPT1_F_LRO);
else
adapter->shared->devRead.misc.uptFeatures &=
- ~UPT1_F_LRO;
+ cpu_to_le64(~UPT1_F_LRO);
VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD,
VMXNET3_CMD_UPDATE_FEATURE);
}
@@ -554,7 +554,7 @@ static struct ethtool_ops vmxnet3_ethtool_ops = {
.get_tso = ethtool_op_get_tso,
.set_tso = ethtool_op_set_tso,
.get_strings = vmxnet3_get_strings,
- .get_flags = vmxnet3_get_flags,
+ .get_flags = ethtool_op_get_flags,
.set_flags = vmxnet3_set_flags,
.get_sset_count = vmxnet3_get_sset_count,
.get_ethtool_stats = vmxnet3_get_ethtool_stats,
diff --git a/drivers/net/vmxnet3/vmxnet3_int.h b/drivers/net/vmxnet3/vmxnet3_int.h
index 34f392f46fb..2121c735cab 100644
--- a/drivers/net/vmxnet3/vmxnet3_int.h
+++ b/drivers/net/vmxnet3/vmxnet3_int.h
@@ -68,10 +68,10 @@
/*
* Version numbers
*/
-#define VMXNET3_DRIVER_VERSION_STRING "1.0.5.0-k"
+#define VMXNET3_DRIVER_VERSION_STRING "1.0.14.0-k"
/* a 32-bit int, each byte encode a verion number in VMXNET3_DRIVER_VERSION */
-#define VMXNET3_DRIVER_VERSION_NUM 0x01000500
+#define VMXNET3_DRIVER_VERSION_NUM 0x01000E00
/*
diff --git a/drivers/net/vxge/Makefile b/drivers/net/vxge/Makefile
index 8992ca26b27..b625e2c503f 100644
--- a/drivers/net/vxge/Makefile
+++ b/drivers/net/vxge/Makefile
@@ -1,5 +1,5 @@
#
-# Makefile for Neterion Inc's X3100 Series 10 GbE PCIe # I/O
+# Makefile for Exar Corp's X3100 Series 10 GbE PCIe I/O
# Virtualized Server Adapter linux driver
obj-$(CONFIG_VXGE) += vxge.o
diff --git a/drivers/net/vxge/vxge-config.c b/drivers/net/vxge/vxge-config.c
index 297f0d20207..0e6db593560 100644
--- a/drivers/net/vxge/vxge-config.c
+++ b/drivers/net/vxge/vxge-config.c
@@ -7,9 +7,9 @@
* system is licensed under the GPL.
* See the file COPYING in this distribution for more information.
*
- * vxge-config.c: Driver for Neterion Inc's X3100 Series 10GbE PCIe I/O
+ * vxge-config.c: Driver for Exar Corp's X3100 Series 10GbE PCIe I/O
* Virtualized Server Adapter.
- * Copyright(c) 2002-2009 Neterion Inc.
+ * Copyright(c) 2002-2010 Exar Corp.
******************************************************************************/
#include <linux/vmalloc.h>
#include <linux/etherdevice.h>
diff --git a/drivers/net/vxge/vxge-config.h b/drivers/net/vxge/vxge-config.h
index 4ae2625d4d8..1a94343023c 100644
--- a/drivers/net/vxge/vxge-config.h
+++ b/drivers/net/vxge/vxge-config.h
@@ -7,9 +7,9 @@
* system is licensed under the GPL.
* See the file COPYING in this distribution for more information.
*
- * vxge-config.h: Driver for Neterion Inc's X3100 Series 10GbE PCIe I/O
+ * vxge-config.h: Driver for Exar Corp's X3100 Series 10GbE PCIe I/O
* Virtualized Server Adapter.
- * Copyright(c) 2002-2009 Neterion Inc.
+ * Copyright(c) 2002-2010 Exar Corp.
******************************************************************************/
#ifndef VXGE_CONFIG_H
#define VXGE_CONFIG_H
diff --git a/drivers/net/vxge/vxge-ethtool.c b/drivers/net/vxge/vxge-ethtool.c
index cadef8549c0..05679e306fd 100644
--- a/drivers/net/vxge/vxge-ethtool.c
+++ b/drivers/net/vxge/vxge-ethtool.c
@@ -7,9 +7,9 @@
* system is licensed under the GPL.
* See the file COPYING in this distribution for more information.
*
- * vxge-ethtool.c: Driver for Neterion Inc's X3100 Series 10GbE PCIe I/O
+ * vxge-ethtool.c: Driver for Exar Corp's X3100 Series 10GbE PCIe I/O
* Virtualized Server Adapter.
- * Copyright(c) 2002-2009 Neterion Inc.
+ * Copyright(c) 2002-2010 Exar Corp.
******************************************************************************/
#include<linux/ethtool.h>
#include <linux/slab.h>
diff --git a/drivers/net/vxge/vxge-ethtool.h b/drivers/net/vxge/vxge-ethtool.h
index 1c3df0a34ac..6cf3044d7f4 100644
--- a/drivers/net/vxge/vxge-ethtool.h
+++ b/drivers/net/vxge/vxge-ethtool.h
@@ -7,9 +7,9 @@
* system is licensed under the GPL.
* See the file COPYING in this distribution for more information.
*
- * vxge-ethtool.h: Driver for Neterion Inc's X3100 Series 10GbE PCIe I/O
+ * vxge-ethtool.h: Driver for Exar Corp's X3100 Series 10GbE PCIe I/O
* Virtualized Server Adapter.
- * Copyright(c) 2002-2009 Neterion Inc.
+ * Copyright(c) 2002-2010 Exar Corp.
******************************************************************************/
#ifndef _VXGE_ETHTOOL_H
#define _VXGE_ETHTOOL_H
diff --git a/drivers/net/vxge/vxge-main.c b/drivers/net/vxge/vxge-main.c
index fc8b2d7a091..c7c5605b372 100644
--- a/drivers/net/vxge/vxge-main.c
+++ b/drivers/net/vxge/vxge-main.c
@@ -7,9 +7,9 @@
* system is licensed under the GPL.
* See the file COPYING in this distribution for more information.
*
-* vxge-main.c: Driver for Neterion Inc's X3100 Series 10GbE PCIe I/O
+* vxge-main.c: Driver for Exar Corp's X3100 Series 10GbE PCIe I/O
* Virtualized Server Adapter.
-* Copyright(c) 2002-2009 Neterion Inc.
+* Copyright(c) 2002-2010 Exar Corp.
*
* The module loadable parameters that are supported by the driver and a brief
* explanation of all the variables:
@@ -41,6 +41,8 @@
*
******************************************************************************/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/if_vlan.h>
#include <linux/pci.h>
#include <linux/slab.h>
@@ -87,7 +89,6 @@ static inline int is_vxge_card_up(struct vxgedev *vdev)
static inline void VXGE_COMPLETE_VPATH_TX(struct vxge_fifo *fifo)
{
- unsigned long flags = 0;
struct sk_buff **skb_ptr = NULL;
struct sk_buff **temp;
#define NR_SKB_COMPLETED 128
@@ -98,15 +99,16 @@ static inline void VXGE_COMPLETE_VPATH_TX(struct vxge_fifo *fifo)
more = 0;
skb_ptr = completed;
- if (spin_trylock_irqsave(&fifo->tx_lock, flags)) {
+ if (__netif_tx_trylock(fifo->txq)) {
vxge_hw_vpath_poll_tx(fifo->handle, &skb_ptr,
NR_SKB_COMPLETED, &more);
- spin_unlock_irqrestore(&fifo->tx_lock, flags);
+ __netif_tx_unlock(fifo->txq);
}
+
/* free SKBs */
for (temp = completed; temp != skb_ptr; temp++)
dev_kfree_skb_irq(*temp);
- } while (more) ;
+ } while (more);
}
static inline void VXGE_COMPLETE_ALL_TX(struct vxgedev *vdev)
@@ -131,80 +133,6 @@ static inline void VXGE_COMPLETE_ALL_RX(struct vxgedev *vdev)
}
/*
- * MultiQ manipulation helper functions
- */
-void vxge_stop_all_tx_queue(struct vxgedev *vdev)
-{
- int i;
- struct net_device *dev = vdev->ndev;
-
- if (vdev->config.tx_steering_type != TX_MULTIQ_STEERING) {
- for (i = 0; i < vdev->no_of_vpath; i++)
- vdev->vpaths[i].fifo.queue_state = VPATH_QUEUE_STOP;
- }
- netif_tx_stop_all_queues(dev);
-}
-
-void vxge_stop_tx_queue(struct vxge_fifo *fifo)
-{
- struct net_device *dev = fifo->ndev;
-
- struct netdev_queue *txq = NULL;
- if (fifo->tx_steering_type == TX_MULTIQ_STEERING)
- txq = netdev_get_tx_queue(dev, fifo->driver_id);
- else {
- txq = netdev_get_tx_queue(dev, 0);
- fifo->queue_state = VPATH_QUEUE_STOP;
- }
-
- netif_tx_stop_queue(txq);
-}
-
-void vxge_start_all_tx_queue(struct vxgedev *vdev)
-{
- int i;
- struct net_device *dev = vdev->ndev;
-
- if (vdev->config.tx_steering_type != TX_MULTIQ_STEERING) {
- for (i = 0; i < vdev->no_of_vpath; i++)
- vdev->vpaths[i].fifo.queue_state = VPATH_QUEUE_START;
- }
- netif_tx_start_all_queues(dev);
-}
-
-static void vxge_wake_all_tx_queue(struct vxgedev *vdev)
-{
- int i;
- struct net_device *dev = vdev->ndev;
-
- if (vdev->config.tx_steering_type != TX_MULTIQ_STEERING) {
- for (i = 0; i < vdev->no_of_vpath; i++)
- vdev->vpaths[i].fifo.queue_state = VPATH_QUEUE_START;
- }
- netif_tx_wake_all_queues(dev);
-}
-
-void vxge_wake_tx_queue(struct vxge_fifo *fifo, struct sk_buff *skb)
-{
- struct net_device *dev = fifo->ndev;
-
- int vpath_no = fifo->driver_id;
- struct netdev_queue *txq = NULL;
- if (fifo->tx_steering_type == TX_MULTIQ_STEERING) {
- txq = netdev_get_tx_queue(dev, vpath_no);
- if (netif_tx_queue_stopped(txq))
- netif_tx_wake_queue(txq);
- } else {
- txq = netdev_get_tx_queue(dev, 0);
- if (fifo->queue_state == VPATH_QUEUE_STOP)
- if (netif_tx_queue_stopped(txq)) {
- fifo->queue_state = VPATH_QUEUE_START;
- netif_tx_wake_queue(txq);
- }
- }
-}
-
-/*
* vxge_callback_link_up
*
* This function is called during interrupt context to notify link up state
@@ -218,11 +146,11 @@ vxge_callback_link_up(struct __vxge_hw_device *hldev)
vxge_debug_entryexit(VXGE_TRACE, "%s: %s:%d",
vdev->ndev->name, __func__, __LINE__);
- printk(KERN_NOTICE "%s: Link Up\n", vdev->ndev->name);
+ netdev_notice(vdev->ndev, "Link Up\n");
vdev->stats.link_up++;
netif_carrier_on(vdev->ndev);
- vxge_wake_all_tx_queue(vdev);
+ netif_tx_wake_all_queues(vdev->ndev);
vxge_debug_entryexit(VXGE_TRACE,
"%s: %s:%d Exiting...", vdev->ndev->name, __func__, __LINE__);
@@ -242,11 +170,11 @@ vxge_callback_link_down(struct __vxge_hw_device *hldev)
vxge_debug_entryexit(VXGE_TRACE,
"%s: %s:%d", vdev->ndev->name, __func__, __LINE__);
- printk(KERN_NOTICE "%s: Link Down\n", vdev->ndev->name);
+ netdev_notice(vdev->ndev, "Link Down\n");
vdev->stats.link_down++;
netif_carrier_off(vdev->ndev);
- vxge_stop_all_tx_queue(vdev);
+ netif_tx_stop_all_queues(vdev->ndev);
vxge_debug_entryexit(VXGE_TRACE,
"%s: %s:%d Exiting...", vdev->ndev->name, __func__, __LINE__);
@@ -677,7 +605,8 @@ vxge_xmit_compl(struct __vxge_hw_fifo *fifo_hw, void *dtr,
&dtr, &t_code) == VXGE_HW_OK);
*skb_ptr = done_skb;
- vxge_wake_tx_queue(fifo, skb);
+ if (netif_tx_queue_stopped(fifo->txq))
+ netif_tx_wake_queue(fifo->txq);
vxge_debug_entryexit(VXGE_TRACE,
"%s: %s:%d Exiting...",
@@ -686,8 +615,7 @@ vxge_xmit_compl(struct __vxge_hw_fifo *fifo_hw, void *dtr,
}
/* select a vpath to transmit the packet */
-static u32 vxge_get_vpath_no(struct vxgedev *vdev, struct sk_buff *skb,
- int *do_lock)
+static u32 vxge_get_vpath_no(struct vxgedev *vdev, struct sk_buff *skb)
{
u16 queue_len, counter = 0;
if (skb->protocol == htons(ETH_P_IP)) {
@@ -706,12 +634,6 @@ static u32 vxge_get_vpath_no(struct vxgedev *vdev, struct sk_buff *skb,
vdev->vpath_selector[queue_len - 1];
if (counter >= queue_len)
counter = queue_len - 1;
-
- if (ip->protocol == IPPROTO_UDP) {
-#ifdef NETIF_F_LLTX
- *do_lock = 0;
-#endif
- }
}
}
return counter;
@@ -808,8 +730,6 @@ static int vxge_learn_mac(struct vxgedev *vdev, u8 *mac_header)
*
* This function is the Tx entry point of the driver. Neterion NIC supports
* certain protocol assist features on Tx side, namely CSO, S/G, LSO.
- * NOTE: when device cant queue the pkt, just the trans_start variable will
- * not be upadted.
*/
static netdev_tx_t
vxge_xmit(struct sk_buff *skb, struct net_device *dev)
@@ -826,9 +746,7 @@ vxge_xmit(struct sk_buff *skb, struct net_device *dev)
struct vxge_tx_priv *txdl_priv = NULL;
struct __vxge_hw_fifo *fifo_hw;
int offload_type;
- unsigned long flags = 0;
int vpath_no = 0;
- int do_spin_tx_lock = 1;
vxge_debug_entryexit(VXGE_TRACE, "%s: %s:%d",
dev->name, __func__, __LINE__);
@@ -864,7 +782,7 @@ vxge_xmit(struct sk_buff *skb, struct net_device *dev)
if (vdev->config.tx_steering_type == TX_MULTIQ_STEERING)
vpath_no = skb_get_queue_mapping(skb);
else if (vdev->config.tx_steering_type == TX_PORT_STEERING)
- vpath_no = vxge_get_vpath_no(vdev, skb, &do_spin_tx_lock);
+ vpath_no = vxge_get_vpath_no(vdev, skb);
vxge_debug_tx(VXGE_TRACE, "%s: vpath_no= %d", dev->name, vpath_no);
@@ -874,46 +792,29 @@ vxge_xmit(struct sk_buff *skb, struct net_device *dev)
fifo = &vdev->vpaths[vpath_no].fifo;
fifo_hw = fifo->handle;
- if (do_spin_tx_lock)
- spin_lock_irqsave(&fifo->tx_lock, flags);
- else {
- if (unlikely(!spin_trylock_irqsave(&fifo->tx_lock, flags)))
- return NETDEV_TX_LOCKED;
- }
+ if (netif_tx_queue_stopped(fifo->txq))
+ return NETDEV_TX_BUSY;
- if (vdev->config.tx_steering_type == TX_MULTIQ_STEERING) {
- if (netif_subqueue_stopped(dev, skb)) {
- spin_unlock_irqrestore(&fifo->tx_lock, flags);
- return NETDEV_TX_BUSY;
- }
- } else if (unlikely(fifo->queue_state == VPATH_QUEUE_STOP)) {
- if (netif_queue_stopped(dev)) {
- spin_unlock_irqrestore(&fifo->tx_lock, flags);
- return NETDEV_TX_BUSY;
- }
- }
avail = vxge_hw_fifo_free_txdl_count_get(fifo_hw);
if (avail == 0) {
vxge_debug_tx(VXGE_ERR,
"%s: No free TXDs available", dev->name);
fifo->stats.txd_not_free++;
- vxge_stop_tx_queue(fifo);
- goto _exit2;
+ goto _exit0;
}
/* Last TXD? Stop tx queue to avoid dropping packets. TX
* completion will resume the queue.
*/
if (avail == 1)
- vxge_stop_tx_queue(fifo);
+ netif_tx_stop_queue(fifo->txq);
status = vxge_hw_fifo_txdl_reserve(fifo_hw, &dtr, &dtr_priv);
if (unlikely(status != VXGE_HW_OK)) {
vxge_debug_tx(VXGE_ERR,
"%s: Out of descriptors .", dev->name);
fifo->stats.txd_out_of_desc++;
- vxge_stop_tx_queue(fifo);
- goto _exit2;
+ goto _exit0;
}
vxge_debug_tx(VXGE_TRACE,
@@ -933,9 +834,8 @@ vxge_xmit(struct sk_buff *skb, struct net_device *dev)
if (unlikely(pci_dma_mapping_error(fifo->pdev, dma_pointer))) {
vxge_hw_fifo_txdl_free(fifo_hw, dtr);
- vxge_stop_tx_queue(fifo);
fifo->stats.pci_map_fail++;
- goto _exit2;
+ goto _exit0;
}
txdl_priv = vxge_hw_fifo_txdl_private_get(dtr);
@@ -958,13 +858,12 @@ vxge_xmit(struct sk_buff *skb, struct net_device *dev)
if (!frag->size)
continue;
- dma_pointer =
- (u64)pci_map_page(fifo->pdev, frag->page,
+ dma_pointer = (u64) pci_map_page(fifo->pdev, frag->page,
frag->page_offset, frag->size,
PCI_DMA_TODEVICE);
if (unlikely(pci_dma_mapping_error(fifo->pdev, dma_pointer)))
- goto _exit0;
+ goto _exit2;
vxge_debug_tx(VXGE_TRACE,
"%s: %s:%d frag = %d dma_pointer = 0x%llx",
dev->name, __func__, __LINE__, i,
@@ -979,11 +878,9 @@ vxge_xmit(struct sk_buff *skb, struct net_device *dev)
offload_type = vxge_offload_type(skb);
if (offload_type & (SKB_GSO_TCPV4 | SKB_GSO_TCPV6)) {
-
int mss = vxge_tcp_mss(skb);
if (mss) {
- vxge_debug_tx(VXGE_TRACE,
- "%s: %s:%d mss = %d",
+ vxge_debug_tx(VXGE_TRACE, "%s: %s:%d mss = %d",
dev->name, __func__, __LINE__, mss);
vxge_hw_fifo_txdl_mss_set(dtr, mss);
} else {
@@ -1001,19 +898,13 @@ vxge_xmit(struct sk_buff *skb, struct net_device *dev)
VXGE_HW_FIFO_TXD_TX_CKO_UDP_EN);
vxge_hw_fifo_txdl_post(fifo_hw, dtr);
-#ifdef NETIF_F_LLTX
- dev->trans_start = jiffies; /* NETIF_F_LLTX driver :( */
-#endif
- spin_unlock_irqrestore(&fifo->tx_lock, flags);
- VXGE_COMPLETE_VPATH_TX(fifo);
vxge_debug_entryexit(VXGE_TRACE, "%s: %s:%d Exiting...",
dev->name, __func__, __LINE__);
return NETDEV_TX_OK;
-_exit0:
+_exit2:
vxge_debug_tx(VXGE_TRACE, "%s: pci_map_page failed", dev->name);
-
_exit1:
j = 0;
frag = &skb_shinfo(skb)->frags[0];
@@ -1028,10 +919,9 @@ _exit1:
}
vxge_hw_fifo_txdl_free(fifo_hw, dtr);
-_exit2:
+_exit0:
+ netif_tx_stop_queue(fifo->txq);
dev_kfree_skb(skb);
- spin_unlock_irqrestore(&fifo->tx_lock, flags);
- VXGE_COMPLETE_VPATH_TX(fifo);
return NETDEV_TX_OK;
}
@@ -1121,7 +1011,8 @@ static void vxge_set_multicast(struct net_device *dev)
struct netdev_hw_addr *ha;
struct vxgedev *vdev;
int i, mcast_cnt = 0;
- struct __vxge_hw_device *hldev;
+ struct __vxge_hw_device *hldev;
+ struct vxge_vpath *vpath;
enum vxge_hw_status status = VXGE_HW_OK;
struct macInfo mac_info;
int vpath_idx = 0;
@@ -1141,46 +1032,48 @@ static void vxge_set_multicast(struct net_device *dev)
if ((dev->flags & IFF_ALLMULTI) && (!vdev->all_multi_flg)) {
for (i = 0; i < vdev->no_of_vpath; i++) {
- vxge_assert(vdev->vpaths[i].is_open);
- status = vxge_hw_vpath_mcast_enable(
- vdev->vpaths[i].handle);
+ vpath = &vdev->vpaths[i];
+ vxge_assert(vpath->is_open);
+ status = vxge_hw_vpath_mcast_enable(vpath->handle);
+ if (status != VXGE_HW_OK)
+ vxge_debug_init(VXGE_ERR, "failed to enable "
+ "multicast, status %d", status);
vdev->all_multi_flg = 1;
}
- } else if ((dev->flags & IFF_ALLMULTI) && (vdev->all_multi_flg)) {
+ } else if (!(dev->flags & IFF_ALLMULTI) && (vdev->all_multi_flg)) {
for (i = 0; i < vdev->no_of_vpath; i++) {
- vxge_assert(vdev->vpaths[i].is_open);
- status = vxge_hw_vpath_mcast_disable(
- vdev->vpaths[i].handle);
- vdev->all_multi_flg = 1;
+ vpath = &vdev->vpaths[i];
+ vxge_assert(vpath->is_open);
+ status = vxge_hw_vpath_mcast_disable(vpath->handle);
+ if (status != VXGE_HW_OK)
+ vxge_debug_init(VXGE_ERR, "failed to disable "
+ "multicast, status %d", status);
+ vdev->all_multi_flg = 0;
}
}
- if (status != VXGE_HW_OK)
- vxge_debug_init(VXGE_ERR,
- "failed to %s multicast, status %d",
- dev->flags & IFF_ALLMULTI ?
- "enable" : "disable", status);
if (!vdev->config.addr_learn_en) {
- if (dev->flags & IFF_PROMISC) {
- for (i = 0; i < vdev->no_of_vpath; i++) {
- vxge_assert(vdev->vpaths[i].is_open);
+ for (i = 0; i < vdev->no_of_vpath; i++) {
+ vpath = &vdev->vpaths[i];
+ vxge_assert(vpath->is_open);
+
+ if (dev->flags & IFF_PROMISC)
status = vxge_hw_vpath_promisc_enable(
- vdev->vpaths[i].handle);
- }
- } else {
- for (i = 0; i < vdev->no_of_vpath; i++) {
- vxge_assert(vdev->vpaths[i].is_open);
+ vpath->handle);
+ else
status = vxge_hw_vpath_promisc_disable(
- vdev->vpaths[i].handle);
- }
+ vpath->handle);
+ if (status != VXGE_HW_OK)
+ vxge_debug_init(VXGE_ERR, "failed to %s promisc"
+ ", status %d", dev->flags&IFF_PROMISC ?
+ "enable" : "disable", status);
}
}
memset(&mac_info, 0, sizeof(struct macInfo));
/* Update individual M_CAST address list */
if ((!vdev->all_multi_flg) && netdev_mc_count(dev)) {
-
mcast_cnt = vdev->vpaths[0].mcast_addr_cnt;
list_head = &vdev->vpaths[0].mac_addr_list;
if ((netdev_mc_count(dev) +
@@ -1190,14 +1083,7 @@ static void vxge_set_multicast(struct net_device *dev)
/* Delete previous MC's */
for (i = 0; i < mcast_cnt; i++) {
- if (!list_empty(list_head))
- mac_entry = (struct vxge_mac_addrs *)
- list_first_entry(list_head,
- struct vxge_mac_addrs,
- item);
-
list_for_each_safe(entry, next, list_head) {
-
mac_entry = (struct vxge_mac_addrs *) entry;
/* Copy the mac address to delete */
mac_address = (u8 *)&mac_entry->macaddr;
@@ -1240,9 +1126,7 @@ _set_all_mcast:
mcast_cnt = vdev->vpaths[0].mcast_addr_cnt;
/* Delete previous MC's */
for (i = 0; i < mcast_cnt; i++) {
-
list_for_each_safe(entry, next, list_head) {
-
mac_entry = (struct vxge_mac_addrs *) entry;
/* Copy the mac address to delete */
mac_address = (u8 *)&mac_entry->macaddr;
@@ -1262,9 +1146,10 @@ _set_all_mcast:
/* Enable all multicast */
for (i = 0; i < vdev->no_of_vpath; i++) {
- vxge_assert(vdev->vpaths[i].is_open);
- status = vxge_hw_vpath_mcast_enable(
- vdev->vpaths[i].handle);
+ vpath = &vdev->vpaths[i];
+ vxge_assert(vpath->is_open);
+
+ status = vxge_hw_vpath_mcast_enable(vpath->handle);
if (status != VXGE_HW_OK) {
vxge_debug_init(VXGE_ERR,
"%s:%d Enabling all multicasts failed",
@@ -1425,6 +1310,7 @@ void vxge_vpath_intr_disable(struct vxgedev *vdev, int vp_id)
static int vxge_reset_vpath(struct vxgedev *vdev, int vp_id)
{
enum vxge_hw_status status = VXGE_HW_OK;
+ struct vxge_vpath *vpath = &vdev->vpaths[vp_id];
int ret = 0;
/* check if device is down already */
@@ -1435,12 +1321,10 @@ static int vxge_reset_vpath(struct vxgedev *vdev, int vp_id)
if (test_bit(__VXGE_STATE_RESET_CARD, &vdev->state))
return 0;
- if (vdev->vpaths[vp_id].handle) {
- if (vxge_hw_vpath_reset(vdev->vpaths[vp_id].handle)
- == VXGE_HW_OK) {
+ if (vpath->handle) {
+ if (vxge_hw_vpath_reset(vpath->handle) == VXGE_HW_OK) {
if (is_vxge_card_up(vdev) &&
- vxge_hw_vpath_recover_from_reset(
- vdev->vpaths[vp_id].handle)
+ vxge_hw_vpath_recover_from_reset(vpath->handle)
!= VXGE_HW_OK) {
vxge_debug_init(VXGE_ERR,
"vxge_hw_vpath_recover_from_reset"
@@ -1456,11 +1340,20 @@ static int vxge_reset_vpath(struct vxgedev *vdev, int vp_id)
} else
return VXGE_HW_FAIL;
- vxge_restore_vpath_mac_addr(&vdev->vpaths[vp_id]);
- vxge_restore_vpath_vid_table(&vdev->vpaths[vp_id]);
+ vxge_restore_vpath_mac_addr(vpath);
+ vxge_restore_vpath_vid_table(vpath);
/* Enable all broadcast */
- vxge_hw_vpath_bcast_enable(vdev->vpaths[vp_id].handle);
+ vxge_hw_vpath_bcast_enable(vpath->handle);
+
+ /* Enable all multicast */
+ if (vdev->all_multi_flg) {
+ status = vxge_hw_vpath_mcast_enable(vpath->handle);
+ if (status != VXGE_HW_OK)
+ vxge_debug_init(VXGE_ERR,
+ "%s:%d Enabling multicast failed",
+ __func__, __LINE__);
+ }
/* Enable the interrupts */
vxge_vpath_intr_enable(vdev, vp_id);
@@ -1468,17 +1361,18 @@ static int vxge_reset_vpath(struct vxgedev *vdev, int vp_id)
smp_wmb();
/* Enable the flow of traffic through the vpath */
- vxge_hw_vpath_enable(vdev->vpaths[vp_id].handle);
+ vxge_hw_vpath_enable(vpath->handle);
smp_wmb();
- vxge_hw_vpath_rx_doorbell_init(vdev->vpaths[vp_id].handle);
- vdev->vpaths[vp_id].ring.last_status = VXGE_HW_OK;
+ vxge_hw_vpath_rx_doorbell_init(vpath->handle);
+ vpath->ring.last_status = VXGE_HW_OK;
/* Vpath reset done */
clear_bit(vp_id, &vdev->vp_reset);
/* Start the vpath queue */
- vxge_wake_tx_queue(&vdev->vpaths[vp_id].fifo, NULL);
+ if (netif_tx_queue_stopped(vpath->fifo.txq))
+ netif_tx_wake_queue(vpath->fifo.txq);
return ret;
}
@@ -1512,9 +1406,9 @@ static int do_vxge_reset(struct vxgedev *vdev, int event)
vxge_debug_init(VXGE_ERR,
"%s: execution mode is debug, returning..",
vdev->ndev->name);
- clear_bit(__VXGE_STATE_CARD_UP, &vdev->state);
- vxge_stop_all_tx_queue(vdev);
- return 0;
+ clear_bit(__VXGE_STATE_CARD_UP, &vdev->state);
+ netif_tx_stop_all_queues(vdev->ndev);
+ return 0;
}
}
@@ -1523,7 +1417,7 @@ static int do_vxge_reset(struct vxgedev *vdev, int event)
switch (vdev->cric_err_event) {
case VXGE_HW_EVENT_UNKNOWN:
- vxge_stop_all_tx_queue(vdev);
+ netif_tx_stop_all_queues(vdev->ndev);
vxge_debug_init(VXGE_ERR,
"fatal: %s: Disabling device due to"
"unknown error",
@@ -1544,7 +1438,7 @@ static int do_vxge_reset(struct vxgedev *vdev, int event)
case VXGE_HW_EVENT_VPATH_ERR:
break;
case VXGE_HW_EVENT_CRITICAL_ERR:
- vxge_stop_all_tx_queue(vdev);
+ netif_tx_stop_all_queues(vdev->ndev);
vxge_debug_init(VXGE_ERR,
"fatal: %s: Disabling device due to"
"serious error",
@@ -1554,7 +1448,7 @@ static int do_vxge_reset(struct vxgedev *vdev, int event)
ret = -EPERM;
goto out;
case VXGE_HW_EVENT_SERR:
- vxge_stop_all_tx_queue(vdev);
+ netif_tx_stop_all_queues(vdev->ndev);
vxge_debug_init(VXGE_ERR,
"fatal: %s: Disabling device due to"
"serious error",
@@ -1566,7 +1460,7 @@ static int do_vxge_reset(struct vxgedev *vdev, int event)
ret = -EPERM;
goto out;
case VXGE_HW_EVENT_SLOT_FREEZE:
- vxge_stop_all_tx_queue(vdev);
+ netif_tx_stop_all_queues(vdev->ndev);
vxge_debug_init(VXGE_ERR,
"fatal: %s: Disabling device due to"
"slot freeze",
@@ -1580,7 +1474,7 @@ static int do_vxge_reset(struct vxgedev *vdev, int event)
}
if ((event == VXGE_LL_FULL_RESET) || (event == VXGE_LL_START_RESET))
- vxge_stop_all_tx_queue(vdev);
+ netif_tx_stop_all_queues(vdev->ndev);
if (event == VXGE_LL_FULL_RESET) {
status = vxge_reset_all_vpaths(vdev);
@@ -1640,7 +1534,7 @@ static int do_vxge_reset(struct vxgedev *vdev, int event)
vxge_hw_vpath_rx_doorbell_init(vdev->vpaths[i].handle);
}
- vxge_wake_all_tx_queue(vdev);
+ netif_tx_wake_all_queues(vdev->ndev);
}
out:
@@ -1661,8 +1555,7 @@ out:
*/
int vxge_reset(struct vxgedev *vdev)
{
- do_vxge_reset(vdev, VXGE_LL_FULL_RESET);
- return 0;
+ return do_vxge_reset(vdev, VXGE_LL_FULL_RESET);
}
/**
@@ -2025,17 +1918,17 @@ enum vxge_hw_status vxge_restore_vpath_mac_addr(struct vxge_vpath *vpath)
/* reset vpaths */
enum vxge_hw_status vxge_reset_all_vpaths(struct vxgedev *vdev)
{
- int i;
enum vxge_hw_status status = VXGE_HW_OK;
+ struct vxge_vpath *vpath;
+ int i;
- for (i = 0; i < vdev->no_of_vpath; i++)
- if (vdev->vpaths[i].handle) {
- if (vxge_hw_vpath_reset(vdev->vpaths[i].handle)
- == VXGE_HW_OK) {
+ for (i = 0; i < vdev->no_of_vpath; i++) {
+ vpath = &vdev->vpaths[i];
+ if (vpath->handle) {
+ if (vxge_hw_vpath_reset(vpath->handle) == VXGE_HW_OK) {
if (is_vxge_card_up(vdev) &&
vxge_hw_vpath_recover_from_reset(
- vdev->vpaths[i].handle)
- != VXGE_HW_OK) {
+ vpath->handle) != VXGE_HW_OK) {
vxge_debug_init(VXGE_ERR,
"vxge_hw_vpath_recover_"
"from_reset failed for vpath: "
@@ -2049,83 +1942,93 @@ enum vxge_hw_status vxge_reset_all_vpaths(struct vxgedev *vdev)
return status;
}
}
+ }
+
return status;
}
/* close vpaths */
void vxge_close_vpaths(struct vxgedev *vdev, int index)
{
+ struct vxge_vpath *vpath;
int i;
+
for (i = index; i < vdev->no_of_vpath; i++) {
- if (vdev->vpaths[i].handle && vdev->vpaths[i].is_open) {
- vxge_hw_vpath_close(vdev->vpaths[i].handle);
+ vpath = &vdev->vpaths[i];
+
+ if (vpath->handle && vpath->is_open) {
+ vxge_hw_vpath_close(vpath->handle);
vdev->stats.vpaths_open--;
}
- vdev->vpaths[i].is_open = 0;
- vdev->vpaths[i].handle = NULL;
+ vpath->is_open = 0;
+ vpath->handle = NULL;
}
}
/* open vpaths */
int vxge_open_vpaths(struct vxgedev *vdev)
{
+ struct vxge_hw_vpath_attr attr;
enum vxge_hw_status status;
- int i;
+ struct vxge_vpath *vpath;
u32 vp_id = 0;
- struct vxge_hw_vpath_attr attr;
+ int i;
for (i = 0; i < vdev->no_of_vpath; i++) {
- vxge_assert(vdev->vpaths[i].is_configured);
- attr.vp_id = vdev->vpaths[i].device_id;
+ vpath = &vdev->vpaths[i];
+
+ vxge_assert(vpath->is_configured);
+ attr.vp_id = vpath->device_id;
attr.fifo_attr.callback = vxge_xmit_compl;
attr.fifo_attr.txdl_term = vxge_tx_term;
attr.fifo_attr.per_txdl_space = sizeof(struct vxge_tx_priv);
- attr.fifo_attr.userdata = (void *)&vdev->vpaths[i].fifo;
+ attr.fifo_attr.userdata = &vpath->fifo;
attr.ring_attr.callback = vxge_rx_1b_compl;
attr.ring_attr.rxd_init = vxge_rx_initial_replenish;
attr.ring_attr.rxd_term = vxge_rx_term;
attr.ring_attr.per_rxd_space = sizeof(struct vxge_rx_priv);
- attr.ring_attr.userdata = (void *)&vdev->vpaths[i].ring;
+ attr.ring_attr.userdata = &vpath->ring;
- vdev->vpaths[i].ring.ndev = vdev->ndev;
- vdev->vpaths[i].ring.pdev = vdev->pdev;
- status = vxge_hw_vpath_open(vdev->devh, &attr,
- &(vdev->vpaths[i].handle));
+ vpath->ring.ndev = vdev->ndev;
+ vpath->ring.pdev = vdev->pdev;
+ status = vxge_hw_vpath_open(vdev->devh, &attr, &vpath->handle);
if (status == VXGE_HW_OK) {
- vdev->vpaths[i].fifo.handle =
+ vpath->fifo.handle =
(struct __vxge_hw_fifo *)attr.fifo_attr.userdata;
- vdev->vpaths[i].ring.handle =
+ vpath->ring.handle =
(struct __vxge_hw_ring *)attr.ring_attr.userdata;
- vdev->vpaths[i].fifo.tx_steering_type =
+ vpath->fifo.tx_steering_type =
vdev->config.tx_steering_type;
- vdev->vpaths[i].fifo.ndev = vdev->ndev;
- vdev->vpaths[i].fifo.pdev = vdev->pdev;
- vdev->vpaths[i].fifo.indicate_max_pkts =
+ vpath->fifo.ndev = vdev->ndev;
+ vpath->fifo.pdev = vdev->pdev;
+ if (vdev->config.tx_steering_type)
+ vpath->fifo.txq =
+ netdev_get_tx_queue(vdev->ndev, i);
+ else
+ vpath->fifo.txq =
+ netdev_get_tx_queue(vdev->ndev, 0);
+ vpath->fifo.indicate_max_pkts =
vdev->config.fifo_indicate_max_pkts;
- vdev->vpaths[i].ring.rx_vector_no = 0;
- vdev->vpaths[i].ring.rx_csum = vdev->rx_csum;
- vdev->vpaths[i].is_open = 1;
- vdev->vp_handles[i] = vdev->vpaths[i].handle;
- vdev->vpaths[i].ring.gro_enable =
- vdev->config.gro_enable;
- vdev->vpaths[i].ring.vlan_tag_strip =
- vdev->vlan_tag_strip;
+ vpath->ring.rx_vector_no = 0;
+ vpath->ring.rx_csum = vdev->rx_csum;
+ vpath->is_open = 1;
+ vdev->vp_handles[i] = vpath->handle;
+ vpath->ring.gro_enable = vdev->config.gro_enable;
+ vpath->ring.vlan_tag_strip = vdev->vlan_tag_strip;
vdev->stats.vpaths_open++;
} else {
vdev->stats.vpath_open_fail++;
vxge_debug_init(VXGE_ERR,
"%s: vpath: %d failed to open "
"with status: %d",
- vdev->ndev->name, vdev->vpaths[i].device_id,
+ vdev->ndev->name, vpath->device_id,
status);
vxge_close_vpaths(vdev, 0);
return -EPERM;
}
- vp_id =
- ((struct __vxge_hw_vpath_handle *)vdev->vpaths[i].handle)->
- vpath->vp_id;
+ vp_id = vpath->handle->vpath->vp_id;
vdev->vpaths_deployed |= vxge_mBIT(vp_id);
}
return VXGE_HW_OK;
@@ -2299,7 +2202,6 @@ start:
vdev->vxge_entries[j].in_use = 0;
ret = pci_enable_msix(vdev->pdev, vdev->entries, vdev->intr_cnt);
-
if (ret > 0) {
vxge_debug_init(VXGE_ERR,
"%s: MSI-X enable failed for %d vectors, ret: %d",
@@ -2345,17 +2247,16 @@ static int vxge_enable_msix(struct vxgedev *vdev)
ret = vxge_alloc_msix(vdev);
if (!ret) {
for (i = 0; i < vdev->no_of_vpath; i++) {
+ struct vxge_vpath *vpath = &vdev->vpaths[i];
- /* If fifo or ring are not enabled
- the MSIX vector for that should be set to 0
- Hence initializeing this array to all 0s.
- */
- vdev->vpaths[i].ring.rx_vector_no =
- (vdev->vpaths[i].device_id *
- VXGE_HW_VPATH_MSIX_ACTIVE) + 1;
+ /* If fifo or ring are not enabled, the MSIX vector for
+ * it should be set to 0.
+ */
+ vpath->ring.rx_vector_no = (vpath->device_id *
+ VXGE_HW_VPATH_MSIX_ACTIVE) + 1;
- vxge_hw_vpath_msix_set(vdev->vpaths[i].handle,
- tim_msix_id, VXGE_ALARM_MSIX_ID);
+ vxge_hw_vpath_msix_set(vpath->handle, tim_msix_id,
+ VXGE_ALARM_MSIX_ID);
}
}
@@ -2570,9 +2471,10 @@ static void vxge_poll_vp_reset(unsigned long data)
static void vxge_poll_vp_lockup(unsigned long data)
{
struct vxgedev *vdev = (struct vxgedev *)data;
- int i;
- struct vxge_ring *ring;
enum vxge_hw_status status = VXGE_HW_OK;
+ struct vxge_vpath *vpath;
+ struct vxge_ring *ring;
+ int i;
for (i = 0; i < vdev->no_of_vpath; i++) {
ring = &vdev->vpaths[i].ring;
@@ -2586,13 +2488,13 @@ static void vxge_poll_vp_lockup(unsigned long data)
/* schedule vpath reset */
if (!test_and_set_bit(i, &vdev->vp_reset)) {
+ vpath = &vdev->vpaths[i];
/* disable interrupts for this vpath */
vxge_vpath_intr_disable(vdev, i);
/* stop the queue for this vpath */
- vxge_stop_tx_queue(&vdev->vpaths[i].
- fifo);
+ netif_tx_stop_queue(vpath->fifo.txq);
continue;
}
}
@@ -2621,6 +2523,7 @@ vxge_open(struct net_device *dev)
enum vxge_hw_status status;
struct vxgedev *vdev;
struct __vxge_hw_device *hldev;
+ struct vxge_vpath *vpath;
int ret = 0;
int i;
u64 val64, function_mode;
@@ -2654,20 +2557,21 @@ vxge_open(struct net_device *dev)
goto out1;
}
-
if (vdev->config.intr_type != MSI_X) {
netif_napi_add(dev, &vdev->napi, vxge_poll_inta,
vdev->config.napi_weight);
napi_enable(&vdev->napi);
- for (i = 0; i < vdev->no_of_vpath; i++)
- vdev->vpaths[i].ring.napi_p = &vdev->napi;
+ for (i = 0; i < vdev->no_of_vpath; i++) {
+ vpath = &vdev->vpaths[i];
+ vpath->ring.napi_p = &vdev->napi;
+ }
} else {
for (i = 0; i < vdev->no_of_vpath; i++) {
- netif_napi_add(dev, &vdev->vpaths[i].ring.napi,
+ vpath = &vdev->vpaths[i];
+ netif_napi_add(dev, &vpath->ring.napi,
vxge_poll_msix, vdev->config.napi_weight);
- napi_enable(&vdev->vpaths[i].ring.napi);
- vdev->vpaths[i].ring.napi_p =
- &vdev->vpaths[i].ring.napi;
+ napi_enable(&vpath->ring.napi);
+ vpath->ring.napi_p = &vpath->ring.napi;
}
}
@@ -2684,9 +2588,10 @@ vxge_open(struct net_device *dev)
}
for (i = 0; i < vdev->no_of_vpath; i++) {
+ vpath = &vdev->vpaths[i];
+
/* set initial mtu before enabling the device */
- status = vxge_hw_vpath_mtu_set(vdev->vpaths[i].handle,
- vdev->mtu);
+ status = vxge_hw_vpath_mtu_set(vpath->handle, vdev->mtu);
if (status != VXGE_HW_OK) {
vxge_debug_init(VXGE_ERR,
"%s: fatal: can not set new MTU", dev->name);
@@ -2700,10 +2605,21 @@ vxge_open(struct net_device *dev)
"%s: MTU is %d", vdev->ndev->name, vdev->mtu);
VXGE_DEVICE_DEBUG_LEVEL_SET(VXGE_ERR, VXGE_COMPONENT_LL, vdev);
- /* Reprogram the DA table with populated mac addresses */
- for (i = 0; i < vdev->no_of_vpath; i++) {
- vxge_restore_vpath_mac_addr(&vdev->vpaths[i]);
- vxge_restore_vpath_vid_table(&vdev->vpaths[i]);
+ /* Restore the DA, VID table and also multicast and promiscuous mode
+ * states
+ */
+ if (vdev->all_multi_flg) {
+ for (i = 0; i < vdev->no_of_vpath; i++) {
+ vpath = &vdev->vpaths[i];
+ vxge_restore_vpath_mac_addr(vpath);
+ vxge_restore_vpath_vid_table(vpath);
+
+ status = vxge_hw_vpath_mcast_enable(vpath->handle);
+ if (status != VXGE_HW_OK)
+ vxge_debug_init(VXGE_ERR,
+ "%s:%d Enabling multicast failed",
+ __func__, __LINE__);
+ }
}
/* Enable vpath to sniff all unicast/multicast traffic that not
@@ -2732,14 +2648,14 @@ vxge_open(struct net_device *dev)
/* Enabling Bcast and mcast for all vpath */
for (i = 0; i < vdev->no_of_vpath; i++) {
- status = vxge_hw_vpath_bcast_enable(vdev->vpaths[i].handle);
+ vpath = &vdev->vpaths[i];
+ status = vxge_hw_vpath_bcast_enable(vpath->handle);
if (status != VXGE_HW_OK)
vxge_debug_init(VXGE_ERR,
"%s : Can not enable bcast for vpath "
"id %d", dev->name, i);
if (vdev->config.addr_learn_en) {
- status =
- vxge_hw_vpath_mcast_enable(vdev->vpaths[i].handle);
+ status = vxge_hw_vpath_mcast_enable(vpath->handle);
if (status != VXGE_HW_OK)
vxge_debug_init(VXGE_ERR,
"%s : Can not enable mcast for vpath "
@@ -2765,7 +2681,7 @@ vxge_open(struct net_device *dev)
if (vxge_hw_device_link_state_get(vdev->devh) == VXGE_HW_LINK_UP) {
netif_carrier_on(vdev->ndev);
- printk(KERN_NOTICE "%s: Link Up\n", vdev->ndev->name);
+ netdev_notice(vdev->ndev, "Link Up\n");
vdev->stats.link_up++;
}
@@ -2774,12 +2690,14 @@ vxge_open(struct net_device *dev)
smp_wmb();
for (i = 0; i < vdev->no_of_vpath; i++) {
- vxge_hw_vpath_enable(vdev->vpaths[i].handle);
+ vpath = &vdev->vpaths[i];
+
+ vxge_hw_vpath_enable(vpath->handle);
smp_wmb();
- vxge_hw_vpath_rx_doorbell_init(vdev->vpaths[i].handle);
+ vxge_hw_vpath_rx_doorbell_init(vpath->handle);
}
- vxge_start_all_tx_queue(vdev);
+ netif_tx_start_all_queues(vdev->ndev);
goto out0;
out2:
@@ -2901,8 +2819,8 @@ int do_vxge_close(struct net_device *dev, int do_io)
}
netif_carrier_off(vdev->ndev);
- printk(KERN_NOTICE "%s: Link Down\n", vdev->ndev->name);
- vxge_stop_all_tx_queue(vdev);
+ netdev_notice(vdev->ndev, "Link Down\n");
+ netif_tx_stop_all_queues(vdev->ndev);
/* Note that at this point xmit() is stopped by upper layer */
if (do_io)
@@ -3211,11 +3129,11 @@ int __devinit vxge_device_register(struct __vxge_hw_device *hldev,
struct net_device *ndev;
enum vxge_hw_status status = VXGE_HW_OK;
struct vxgedev *vdev;
- int i, ret = 0, no_of_queue = 1;
+ int ret = 0, no_of_queue = 1;
u64 stat;
*vdev_out = NULL;
- if (config->tx_steering_type == TX_MULTIQ_STEERING)
+ if (config->tx_steering_type)
no_of_queue = no_of_vpath;
ndev = alloc_etherdev_mq(sizeof(struct vxgedev),
@@ -3284,16 +3202,6 @@ int __devinit vxge_device_register(struct __vxge_hw_device *hldev,
if (vdev->config.gro_enable)
ndev->features |= NETIF_F_GRO;
- if (vdev->config.tx_steering_type == TX_MULTIQ_STEERING)
- ndev->real_num_tx_queues = no_of_vpath;
-
-#ifdef NETIF_F_LLTX
- ndev->features |= NETIF_F_LLTX;
-#endif
-
- for (i = 0; i < no_of_vpath; i++)
- spin_lock_init(&vdev->vpaths[i].fifo.tx_lock);
-
if (register_netdev(ndev)) {
vxge_debug_init(vxge_hw_device_trace_level_get(hldev),
"%s: %s : device registration failed!",
@@ -3393,6 +3301,7 @@ vxge_callback_crit_err(struct __vxge_hw_device *hldev,
{
struct net_device *dev = hldev->ndev;
struct vxgedev *vdev = (struct vxgedev *)netdev_priv(dev);
+ struct vxge_vpath *vpath = NULL;
int vpath_idx;
vxge_debug_entryexit(vdev->level_trace,
@@ -3403,9 +3312,11 @@ vxge_callback_crit_err(struct __vxge_hw_device *hldev,
*/
vdev->cric_err_event = type;
- for (vpath_idx = 0; vpath_idx < vdev->no_of_vpath; vpath_idx++)
- if (vdev->vpaths[vpath_idx].device_id == vp_id)
+ for (vpath_idx = 0; vpath_idx < vdev->no_of_vpath; vpath_idx++) {
+ vpath = &vdev->vpaths[vpath_idx];
+ if (vpath->device_id == vp_id)
break;
+ }
if (!test_bit(__VXGE_STATE_RESET_CARD, &vdev->state)) {
if (type == VXGE_HW_EVENT_SLOT_FREEZE) {
@@ -3442,8 +3353,7 @@ vxge_callback_crit_err(struct __vxge_hw_device *hldev,
vxge_vpath_intr_disable(vdev, vpath_idx);
/* stop the queue for this vpath */
- vxge_stop_tx_queue(&vdev->vpaths[vpath_idx].
- fifo);
+ netif_tx_stop_queue(vpath->fifo.txq);
}
}
}
@@ -3936,9 +3846,7 @@ static pci_ers_result_t vxge_io_slot_reset(struct pci_dev *pdev)
struct vxgedev *vdev = netdev_priv(netdev);
if (pci_enable_device(pdev)) {
- printk(KERN_ERR "%s: "
- "Cannot re-enable device after reset\n",
- VXGE_DRIVER_NAME);
+ netdev_err(netdev, "Cannot re-enable device after reset\n");
return PCI_ERS_RESULT_DISCONNECT;
}
@@ -3963,9 +3871,8 @@ static void vxge_io_resume(struct pci_dev *pdev)
if (netif_running(netdev)) {
if (vxge_open(netdev)) {
- printk(KERN_ERR "%s: "
- "Can't bring device back up after reset\n",
- VXGE_DRIVER_NAME);
+ netdev_err(netdev,
+ "Can't bring device back up after reset\n");
return;
}
}
@@ -4023,7 +3930,7 @@ vxge_probe(struct pci_dev *pdev, const struct pci_device_id *pre)
int high_dma = 0;
u64 vpath_mask = 0;
struct vxgedev *vdev;
- struct vxge_config ll_config;
+ struct vxge_config *ll_config = NULL;
struct vxge_hw_device_config *device_config = NULL;
struct vxge_hw_device_attr attr;
int i, j, no_of_vpath = 0, max_vpath_supported = 0;
@@ -4082,17 +3989,24 @@ vxge_probe(struct pci_dev *pdev, const struct pci_device_id *pre)
goto _exit0;
}
- memset(&ll_config, 0, sizeof(struct vxge_config));
- ll_config.tx_steering_type = TX_MULTIQ_STEERING;
- ll_config.intr_type = MSI_X;
- ll_config.napi_weight = NEW_NAPI_WEIGHT;
- ll_config.rth_steering = RTH_STEERING;
+ ll_config = kzalloc(sizeof(*ll_config), GFP_KERNEL);
+ if (!ll_config) {
+ ret = -ENOMEM;
+ vxge_debug_init(VXGE_ERR,
+ "ll_config : malloc failed %s %d",
+ __FILE__, __LINE__);
+ goto _exit0;
+ }
+ ll_config->tx_steering_type = TX_MULTIQ_STEERING;
+ ll_config->intr_type = MSI_X;
+ ll_config->napi_weight = NEW_NAPI_WEIGHT;
+ ll_config->rth_steering = RTH_STEERING;
/* get the default configuration parameters */
vxge_hw_device_config_default_get(device_config);
/* initialize configuration parameters */
- vxge_device_config_init(device_config, &ll_config.intr_type);
+ vxge_device_config_init(device_config, &ll_config->intr_type);
ret = pci_enable_device(pdev);
if (ret) {
@@ -4145,7 +4059,7 @@ vxge_probe(struct pci_dev *pdev, const struct pci_device_id *pre)
(unsigned long long)pci_resource_start(pdev, 0));
status = vxge_hw_device_hw_info_get(attr.bar0,
- &ll_config.device_hw_info);
+ &ll_config->device_hw_info);
if (status != VXGE_HW_OK) {
vxge_debug_init(VXGE_ERR,
"%s: Reading of hardware info failed."
@@ -4154,7 +4068,7 @@ vxge_probe(struct pci_dev *pdev, const struct pci_device_id *pre)
goto _exit3;
}
- if (ll_config.device_hw_info.fw_version.major !=
+ if (ll_config->device_hw_info.fw_version.major !=
VXGE_DRIVER_FW_VERSION_MAJOR) {
vxge_debug_init(VXGE_ERR,
"%s: Incorrect firmware version."
@@ -4164,7 +4078,7 @@ vxge_probe(struct pci_dev *pdev, const struct pci_device_id *pre)
goto _exit3;
}
- vpath_mask = ll_config.device_hw_info.vpath_mask;
+ vpath_mask = ll_config->device_hw_info.vpath_mask;
if (vpath_mask == 0) {
vxge_debug_ll_config(VXGE_TRACE,
"%s: No vpaths available in device", VXGE_DRIVER_NAME);
@@ -4176,10 +4090,10 @@ vxge_probe(struct pci_dev *pdev, const struct pci_device_id *pre)
"%s:%d Vpath mask = %llx", __func__, __LINE__,
(unsigned long long)vpath_mask);
- function_mode = ll_config.device_hw_info.function_mode;
- host_type = ll_config.device_hw_info.host_type;
+ function_mode = ll_config->device_hw_info.function_mode;
+ host_type = ll_config->device_hw_info.host_type;
is_privileged = __vxge_hw_device_is_privilaged(host_type,
- ll_config.device_hw_info.func_id);
+ ll_config->device_hw_info.func_id);
/* Check how many vpaths are available */
for (i = 0; i < VXGE_HW_MAX_VIRTUAL_PATHS; i++) {
@@ -4193,7 +4107,7 @@ vxge_probe(struct pci_dev *pdev, const struct pci_device_id *pre)
/* Enable SRIOV mode, if firmware has SRIOV support and if it is a PF */
if (is_sriov(function_mode) && (max_config_dev > 1) &&
- (ll_config.intr_type != INTA) &&
+ (ll_config->intr_type != INTA) &&
(is_privileged == VXGE_HW_OK)) {
ret = pci_enable_sriov(pdev, ((max_config_dev - 1) < num_vfs)
? (max_config_dev - 1) : num_vfs);
@@ -4206,7 +4120,7 @@ vxge_probe(struct pci_dev *pdev, const struct pci_device_id *pre)
* Configure vpaths and get driver configured number of vpaths
* which is less than or equal to the maximum vpaths per function.
*/
- no_of_vpath = vxge_config_vpaths(device_config, vpath_mask, &ll_config);
+ no_of_vpath = vxge_config_vpaths(device_config, vpath_mask, ll_config);
if (!no_of_vpath) {
vxge_debug_ll_config(VXGE_ERR,
"%s: No more vpaths to configure", VXGE_DRIVER_NAME);
@@ -4241,21 +4155,21 @@ vxge_probe(struct pci_dev *pdev, const struct pci_device_id *pre)
/* set private device info */
pci_set_drvdata(pdev, hldev);
- ll_config.gro_enable = VXGE_GRO_ALWAYS_AGGREGATE;
- ll_config.fifo_indicate_max_pkts = VXGE_FIFO_INDICATE_MAX_PKTS;
- ll_config.addr_learn_en = addr_learn_en;
- ll_config.rth_algorithm = RTH_ALG_JENKINS;
- ll_config.rth_hash_type_tcpipv4 = VXGE_HW_RING_HASH_TYPE_TCP_IPV4;
- ll_config.rth_hash_type_ipv4 = VXGE_HW_RING_HASH_TYPE_NONE;
- ll_config.rth_hash_type_tcpipv6 = VXGE_HW_RING_HASH_TYPE_NONE;
- ll_config.rth_hash_type_ipv6 = VXGE_HW_RING_HASH_TYPE_NONE;
- ll_config.rth_hash_type_tcpipv6ex = VXGE_HW_RING_HASH_TYPE_NONE;
- ll_config.rth_hash_type_ipv6ex = VXGE_HW_RING_HASH_TYPE_NONE;
- ll_config.rth_bkt_sz = RTH_BUCKET_SIZE;
- ll_config.tx_pause_enable = VXGE_PAUSE_CTRL_ENABLE;
- ll_config.rx_pause_enable = VXGE_PAUSE_CTRL_ENABLE;
-
- if (vxge_device_register(hldev, &ll_config, high_dma, no_of_vpath,
+ ll_config->gro_enable = VXGE_GRO_ALWAYS_AGGREGATE;
+ ll_config->fifo_indicate_max_pkts = VXGE_FIFO_INDICATE_MAX_PKTS;
+ ll_config->addr_learn_en = addr_learn_en;
+ ll_config->rth_algorithm = RTH_ALG_JENKINS;
+ ll_config->rth_hash_type_tcpipv4 = VXGE_HW_RING_HASH_TYPE_TCP_IPV4;
+ ll_config->rth_hash_type_ipv4 = VXGE_HW_RING_HASH_TYPE_NONE;
+ ll_config->rth_hash_type_tcpipv6 = VXGE_HW_RING_HASH_TYPE_NONE;
+ ll_config->rth_hash_type_ipv6 = VXGE_HW_RING_HASH_TYPE_NONE;
+ ll_config->rth_hash_type_tcpipv6ex = VXGE_HW_RING_HASH_TYPE_NONE;
+ ll_config->rth_hash_type_ipv6ex = VXGE_HW_RING_HASH_TYPE_NONE;
+ ll_config->rth_bkt_sz = RTH_BUCKET_SIZE;
+ ll_config->tx_pause_enable = VXGE_PAUSE_CTRL_ENABLE;
+ ll_config->rx_pause_enable = VXGE_PAUSE_CTRL_ENABLE;
+
+ if (vxge_device_register(hldev, ll_config, high_dma, no_of_vpath,
&vdev)) {
ret = -EINVAL;
goto _exit4;
@@ -4281,12 +4195,11 @@ vxge_probe(struct pci_dev *pdev, const struct pci_device_id *pre)
vdev->vpaths[j].is_configured = 1;
vdev->vpaths[j].device_id = i;
- vdev->vpaths[j].fifo.driver_id = j;
vdev->vpaths[j].ring.driver_id = j;
vdev->vpaths[j].vdev = vdev;
vdev->vpaths[j].max_mac_addr_cnt = max_mac_vpath;
memcpy((u8 *)vdev->vpaths[j].macaddr,
- (u8 *)ll_config.device_hw_info.mac_addrs[i],
+ ll_config->device_hw_info.mac_addrs[i],
ETH_ALEN);
/* Initialize the mac address list header */
@@ -4307,18 +4220,18 @@ vxge_probe(struct pci_dev *pdev, const struct pci_device_id *pre)
macaddr = (u8 *)vdev->vpaths[0].macaddr;
- ll_config.device_hw_info.serial_number[VXGE_HW_INFO_LEN - 1] = '\0';
- ll_config.device_hw_info.product_desc[VXGE_HW_INFO_LEN - 1] = '\0';
- ll_config.device_hw_info.part_number[VXGE_HW_INFO_LEN - 1] = '\0';
+ ll_config->device_hw_info.serial_number[VXGE_HW_INFO_LEN - 1] = '\0';
+ ll_config->device_hw_info.product_desc[VXGE_HW_INFO_LEN - 1] = '\0';
+ ll_config->device_hw_info.part_number[VXGE_HW_INFO_LEN - 1] = '\0';
vxge_debug_init(VXGE_TRACE, "%s: SERIAL NUMBER: %s",
- vdev->ndev->name, ll_config.device_hw_info.serial_number);
+ vdev->ndev->name, ll_config->device_hw_info.serial_number);
vxge_debug_init(VXGE_TRACE, "%s: PART NUMBER: %s",
- vdev->ndev->name, ll_config.device_hw_info.part_number);
+ vdev->ndev->name, ll_config->device_hw_info.part_number);
vxge_debug_init(VXGE_TRACE, "%s: Neterion %s Server Adapter",
- vdev->ndev->name, ll_config.device_hw_info.product_desc);
+ vdev->ndev->name, ll_config->device_hw_info.product_desc);
vxge_debug_init(VXGE_TRACE, "%s: MAC ADDR: %pM",
vdev->ndev->name, macaddr);
@@ -4328,11 +4241,11 @@ vxge_probe(struct pci_dev *pdev, const struct pci_device_id *pre)
vxge_debug_init(VXGE_TRACE,
"%s: Firmware version : %s Date : %s", vdev->ndev->name,
- ll_config.device_hw_info.fw_version.version,
- ll_config.device_hw_info.fw_date.date);
+ ll_config->device_hw_info.fw_version.version,
+ ll_config->device_hw_info.fw_date.date);
if (new_device) {
- switch (ll_config.device_hw_info.function_mode) {
+ switch (ll_config->device_hw_info.function_mode) {
case VXGE_HW_FUNCTION_MODE_SINGLE_FUNCTION:
vxge_debug_init(VXGE_TRACE,
"%s: Single Function Mode Enabled", vdev->ndev->name);
@@ -4355,7 +4268,7 @@ vxge_probe(struct pci_dev *pdev, const struct pci_device_id *pre)
vxge_print_parm(vdev, vpath_mask);
/* Store the fw version for ethttool option */
- strcpy(vdev->fw_version, ll_config.device_hw_info.fw_version.version);
+ strcpy(vdev->fw_version, ll_config->device_hw_info.fw_version.version);
memcpy(vdev->ndev->dev_addr, (u8 *)vdev->vpaths[0].macaddr, ETH_ALEN);
memcpy(vdev->ndev->perm_addr, vdev->ndev->dev_addr, ETH_ALEN);
@@ -4394,7 +4307,7 @@ vxge_probe(struct pci_dev *pdev, const struct pci_device_id *pre)
* present to prevent such a failure.
*/
- if (ll_config.device_hw_info.function_mode ==
+ if (ll_config->device_hw_info.function_mode ==
VXGE_HW_FUNCTION_MODE_MULTI_FUNCTION)
if (vdev->config.intr_type == INTA)
vxge_hw_device_unmask_all(hldev);
@@ -4406,6 +4319,7 @@ vxge_probe(struct pci_dev *pdev, const struct pci_device_id *pre)
VXGE_COPY_DEBUG_INFO_TO_LL(vdev, vxge_hw_device_error_level_get(hldev),
vxge_hw_device_trace_level_get(hldev));
+ kfree(ll_config);
return 0;
_exit5:
@@ -4423,6 +4337,7 @@ _exit2:
_exit1:
pci_disable_device(pdev);
_exit0:
+ kfree(ll_config);
kfree(device_config);
driver_config->config_dev_cnt--;
pci_set_drvdata(pdev, NULL);
@@ -4514,13 +4429,9 @@ static int __init
vxge_starter(void)
{
int ret = 0;
- char version[32];
- snprintf(version, 32, "%s", DRV_VERSION);
- printk(KERN_INFO "%s: Copyright(c) 2002-2009 Neterion Inc\n",
- VXGE_DRIVER_NAME);
- printk(KERN_INFO "%s: Driver version: %s\n",
- VXGE_DRIVER_NAME, version);
+ pr_info("Copyright(c) 2002-2010 Exar Corp.\n");
+ pr_info("Driver version: %s\n", DRV_VERSION);
verify_bandwidth();
diff --git a/drivers/net/vxge/vxge-main.h b/drivers/net/vxge/vxge-main.h
index 60276b20fa5..2e3b064b8e4 100644
--- a/drivers/net/vxge/vxge-main.h
+++ b/drivers/net/vxge/vxge-main.h
@@ -7,9 +7,9 @@
* system is licensed under the GPL.
* See the file COPYING in this distribution for more information.
*
- * vxge-main.h: Driver for Neterion Inc's X3100 Series 10GbE PCIe I/O
+ * vxge-main.h: Driver for Exar Corp's X3100 Series 10GbE PCIe I/O
* Virtualized Server Adapter.
- * Copyright(c) 2002-2009 Neterion Inc.
+ * Copyright(c) 2002-2010 Exar Corp.
******************************************************************************/
#ifndef VXGE_MAIN_H
#define VXGE_MAIN_H
@@ -217,21 +217,13 @@ struct vxge_fifo_stats {
};
struct vxge_fifo {
- struct net_device *ndev;
- struct pci_dev *pdev;
+ struct net_device *ndev;
+ struct pci_dev *pdev;
struct __vxge_hw_fifo *handle;
+ struct netdev_queue *txq;
- /* The vpath id maintained in the driver -
- * 0 to 'maximum_vpaths_in_function - 1'
- */
- int driver_id;
int tx_steering_type;
int indicate_max_pkts;
- spinlock_t tx_lock;
- /* flag used to maintain queue state when MULTIQ is not enabled */
-#define VPATH_QUEUE_START 0
-#define VPATH_QUEUE_STOP 1
- int queue_state;
/* Tx stats */
struct vxge_fifo_stats stats;
@@ -279,7 +271,6 @@ struct vxge_ring {
} ____cacheline_aligned;
struct vxge_vpath {
-
struct vxge_fifo fifo;
struct vxge_ring ring;
@@ -447,14 +438,6 @@ int vxge_open_vpaths(struct vxgedev *vdev);
enum vxge_hw_status vxge_reset_all_vpaths(struct vxgedev *vdev);
-void vxge_stop_all_tx_queue(struct vxgedev *vdev);
-
-void vxge_stop_tx_queue(struct vxge_fifo *fifo);
-
-void vxge_start_all_tx_queue(struct vxgedev *vdev);
-
-void vxge_wake_tx_queue(struct vxge_fifo *fifo, struct sk_buff *skb);
-
enum vxge_hw_status vxge_add_mac_addr(struct vxgedev *vdev,
struct macInfo *mac);
diff --git a/drivers/net/vxge/vxge-reg.h b/drivers/net/vxge/vxge-reg.h
index 9a0cf8eaa32..3dd5c9615ef 100644
--- a/drivers/net/vxge/vxge-reg.h
+++ b/drivers/net/vxge/vxge-reg.h
@@ -7,9 +7,9 @@
* system is licensed under the GPL.
* See the file COPYING in this distribution for more information.
*
- * vxge-reg.h: Driver for Neterion Inc's X3100 Series 10GbE PCIe I/O Virtualized
+ * vxge-reg.h: Driver for Exar Corp's X3100 Series 10GbE PCIe I/O Virtualized
* Server Adapter.
- * Copyright(c) 2002-2009 Neterion Inc.
+ * Copyright(c) 2002-2010 Exar Corp.
******************************************************************************/
#ifndef VXGE_REG_H
#define VXGE_REG_H
diff --git a/drivers/net/vxge/vxge-traffic.c b/drivers/net/vxge/vxge-traffic.c
index 6cc1dd79b40..cedf08f99cb 100644
--- a/drivers/net/vxge/vxge-traffic.c
+++ b/drivers/net/vxge/vxge-traffic.c
@@ -7,9 +7,9 @@
* system is licensed under the GPL.
* See the file COPYING in this distribution for more information.
*
- * vxge-traffic.c: Driver for Neterion Inc's X3100 Series 10GbE PCIe I/O
+ * vxge-traffic.c: Driver for Exar Corp's X3100 Series 10GbE PCIe I/O
* Virtualized Server Adapter.
- * Copyright(c) 2002-2009 Neterion Inc.
+ * Copyright(c) 2002-2010 Exar Corp.
******************************************************************************/
#include <linux/etherdevice.h>
@@ -2466,14 +2466,12 @@ enum vxge_hw_status vxge_hw_vpath_poll_rx(struct __vxge_hw_ring *ring)
* the same.
* @fifo: Handle to the fifo object used for non offload send
*
- * The function polls the Tx for the completed descriptors and calls
+ * The function polls the Tx for the completed descriptors and calls
* the driver via supplied completion callback.
*
* Returns: VXGE_HW_OK, if the polling is completed successful.
* VXGE_HW_COMPLETIONS_REMAIN: There are still more completed
* descriptors available which are yet to be processed.
- *
- * See also: vxge_hw_vpath_poll_tx().
*/
enum vxge_hw_status vxge_hw_vpath_poll_tx(struct __vxge_hw_fifo *fifo,
struct sk_buff ***skb_ptr, int nr_skb,
diff --git a/drivers/net/vxge/vxge-traffic.h b/drivers/net/vxge/vxge-traffic.h
index c252f3d3f65..6fa07d13798 100644
--- a/drivers/net/vxge/vxge-traffic.h
+++ b/drivers/net/vxge/vxge-traffic.h
@@ -7,9 +7,9 @@
* system is licensed under the GPL.
* See the file COPYING in this distribution for more information.
*
- * vxge-traffic.h: Driver for Neterion Inc's X3100 Series 10GbE PCIe I/O
+ * vxge-traffic.h: Driver for Exar Corp's X3100 Series 10GbE PCIe I/O
* Virtualized Server Adapter.
- * Copyright(c) 2002-2009 Neterion Inc.
+ * Copyright(c) 2002-2010 Exar Corp.
******************************************************************************/
#ifndef VXGE_TRAFFIC_H
#define VXGE_TRAFFIC_H
diff --git a/drivers/net/vxge/vxge-version.h b/drivers/net/vxge/vxge-version.h
index 5da7ab1fd30..53fefe13736 100644
--- a/drivers/net/vxge/vxge-version.h
+++ b/drivers/net/vxge/vxge-version.h
@@ -7,17 +7,16 @@
* system is licensed under the GPL.
* See the file COPYING in this distribution for more information.
*
- * vxge-version.h: Driver for Neterion Inc's X3100 Series 10GbE PCIe I/O
+ * vxge-version.h: Driver for Exar Corp's X3100 Series 10GbE PCIe I/O
* Virtualized Server Adapter.
- * Copyright(c) 2002-2009 Neterion Inc.
+ * Copyright(c) 2002-2010 Exar Corp.
******************************************************************************/
#ifndef VXGE_VERSION_H
-
#define VXGE_VERSION_H
#define VXGE_VERSION_MAJOR "2"
#define VXGE_VERSION_MINOR "0"
-#define VXGE_VERSION_FIX "8"
-#define VXGE_VERSION_BUILD "20182"
+#define VXGE_VERSION_FIX "9"
+#define VXGE_VERSION_BUILD "20840"
#define VXGE_VERSION_FOR "k"
#endif
diff --git a/drivers/net/wan/cosa.c b/drivers/net/wan/cosa.c
index f0bd70fb650..04c6cd4333f 100644
--- a/drivers/net/wan/cosa.c
+++ b/drivers/net/wan/cosa.c
@@ -89,7 +89,6 @@
#include <linux/spinlock.h>
#include <linux/mutex.h>
#include <linux/device.h>
-#include <linux/smp_lock.h>
#include <asm/io.h>
#include <asm/dma.h>
#include <asm/byteorder.h>
@@ -174,6 +173,7 @@ struct cosa_data {
* Character device major number. 117 was allocated for us.
* The value of 0 means to allocate a first free one.
*/
+static DEFINE_MUTEX(cosa_chardev_mutex);
static int cosa_major = 117;
/*
@@ -944,7 +944,7 @@ static int cosa_open(struct inode *inode, struct file *file)
int n;
int ret = 0;
- lock_kernel();
+ mutex_lock(&cosa_chardev_mutex);
if ((n=iminor(file->f_path.dentry->d_inode)>>CARD_MINOR_BITS)
>= nr_cards) {
ret = -ENODEV;
@@ -976,7 +976,7 @@ static int cosa_open(struct inode *inode, struct file *file)
chan->rx_done = chrdev_rx_done;
spin_unlock_irqrestore(&cosa->lock, flags);
out:
- unlock_kernel();
+ mutex_unlock(&cosa_chardev_mutex);
return ret;
}
@@ -1212,10 +1212,10 @@ static long cosa_chardev_ioctl(struct file *file, unsigned int cmd,
struct cosa_data *cosa;
long ret;
- lock_kernel();
+ mutex_lock(&cosa_chardev_mutex);
cosa = channel->cosa;
ret = cosa_ioctl_common(cosa, channel, cmd, arg);
- unlock_kernel();
+ mutex_unlock(&cosa_chardev_mutex);
return ret;
}
diff --git a/drivers/net/wan/farsync.c b/drivers/net/wan/farsync.c
index e087b9a6daa..ad7719fe6d0 100644
--- a/drivers/net/wan/farsync.c
+++ b/drivers/net/wan/farsync.c
@@ -15,6 +15,8 @@
* Maintainer: Kevin Curtis <kevin.curtis@farsite.co.uk>
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/version.h>
@@ -511,21 +513,19 @@ static int fst_debug_mask = { FST_DEBUG };
* support variable numbers of macro parameters. The inverted if prevents us
* eating someone else's else clause.
*/
-#define dbg(F,fmt,A...) if ( ! ( fst_debug_mask & (F))) \
- ; \
- else \
- printk ( KERN_DEBUG FST_NAME ": " fmt, ## A )
-
+#define dbg(F, fmt, args...) \
+do { \
+ if (fst_debug_mask & (F)) \
+ printk(KERN_DEBUG pr_fmt(fmt), ##args); \
+} while (0)
#else
-#define dbg(X...) /* NOP */
+#define dbg(F, fmt, args...) \
+do { \
+ if (0) \
+ printk(KERN_DEBUG pr_fmt(fmt), ##args); \
+} while (0)
#endif
-/* Printing short cuts
- */
-#define printk_err(fmt,A...) printk ( KERN_ERR FST_NAME ": " fmt, ## A )
-#define printk_warn(fmt,A...) printk ( KERN_WARNING FST_NAME ": " fmt, ## A )
-#define printk_info(fmt,A...) printk ( KERN_INFO FST_NAME ": " fmt, ## A )
-
/*
* PCI ID lookup table
*/
@@ -961,7 +961,7 @@ fst_issue_cmd(struct fst_port_info *port, unsigned short cmd)
spin_lock_irqsave(&card->card_lock, flags);
if (++safety > 2000) {
- printk_err("Mailbox safety timeout\n");
+ pr_err("Mailbox safety timeout\n");
break;
}
@@ -1241,8 +1241,8 @@ fst_intr_rx(struct fst_card_info *card, struct fst_port_info *port)
* This seems to happen on the TE1 interface sometimes
* so throw the frame away and log the event.
*/
- printk_err("Frame received with 0 length. Card %d Port %d\n",
- card->card_no, port->index);
+ pr_err("Frame received with 0 length. Card %d Port %d\n",
+ card->card_no, port->index);
/* Return descriptor to card */
FST_WRB(card, rxDescrRing[pi][rxp].bits, DMA_OWN);
@@ -1486,9 +1486,8 @@ fst_intr(int dummy, void *dev_id)
*/
dbg(DBG_INTR, "intr: %d %p\n", card->irq, card);
if (card->state != FST_RUNNING) {
- printk_err
- ("Interrupt received for card %d in a non running state (%d)\n",
- card->card_no, card->state);
+ pr_err("Interrupt received for card %d in a non running state (%d)\n",
+ card->card_no, card->state);
/*
* It is possible to really be running, i.e. we have re-loaded
@@ -1614,8 +1613,7 @@ fst_intr(int dummy, void *dev_id)
break;
default:
- printk_err("intr: unknown card event %d. ignored\n",
- event);
+ pr_err("intr: unknown card event %d. ignored\n", event);
break;
}
@@ -1637,13 +1635,13 @@ check_started_ok(struct fst_card_info *card)
/* Check structure version and end marker */
if (FST_RDW(card, smcVersion) != SMC_VERSION) {
- printk_err("Bad shared memory version %d expected %d\n",
- FST_RDW(card, smcVersion), SMC_VERSION);
+ pr_err("Bad shared memory version %d expected %d\n",
+ FST_RDW(card, smcVersion), SMC_VERSION);
card->state = FST_BADVERSION;
return;
}
if (FST_RDL(card, endOfSmcSignature) != END_SIG) {
- printk_err("Missing shared memory signature\n");
+ pr_err("Missing shared memory signature\n");
card->state = FST_BADVERSION;
return;
}
@@ -1651,11 +1649,11 @@ check_started_ok(struct fst_card_info *card)
if ((i = FST_RDB(card, taskStatus)) == 0x01) {
card->state = FST_RUNNING;
} else if (i == 0xFF) {
- printk_err("Firmware initialisation failed. Card halted\n");
+ pr_err("Firmware initialisation failed. Card halted\n");
card->state = FST_HALTED;
return;
} else if (i != 0x00) {
- printk_err("Unknown firmware status 0x%x\n", i);
+ pr_err("Unknown firmware status 0x%x\n", i);
card->state = FST_HALTED;
return;
}
@@ -1665,9 +1663,10 @@ check_started_ok(struct fst_card_info *card)
* existing firmware etc so we just report it for the moment.
*/
if (FST_RDL(card, numberOfPorts) != card->nports) {
- printk_warn("Port count mismatch on card %d."
- " Firmware thinks %d we say %d\n", card->card_no,
- FST_RDL(card, numberOfPorts), card->nports);
+ pr_warning("Port count mismatch on card %d. "
+ "Firmware thinks %d we say %d\n",
+ card->card_no,
+ FST_RDL(card, numberOfPorts), card->nports);
}
}
@@ -2038,16 +2037,10 @@ fst_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
/* Now copy the data to the card. */
- buf = kmalloc(wrthdr.size, GFP_KERNEL);
- if (!buf)
- return -ENOMEM;
-
- if (copy_from_user(buf,
- ifr->ifr_data + sizeof (struct fstioc_write),
- wrthdr.size)) {
- kfree(buf);
- return -EFAULT;
- }
+ buf = memdup_user(ifr->ifr_data + sizeof(struct fstioc_write),
+ wrthdr.size);
+ if (IS_ERR(buf))
+ return PTR_ERR(buf);
memcpy_toio(card->mem + wrthdr.offset, buf, wrthdr.size);
kfree(buf);
@@ -2096,9 +2089,8 @@ fst_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
*/
if (card->state != FST_RUNNING) {
- printk_err
- ("Attempt to configure card %d in non-running state (%d)\n",
- card->card_no, card->state);
+ pr_err("Attempt to configure card %d in non-running state (%d)\n",
+ card->card_no, card->state);
return -EIO;
}
if (copy_from_user(&info, ifr->ifr_data, sizeof (info))) {
@@ -2390,8 +2382,8 @@ fst_init_card(struct fst_card_info *card)
err = register_hdlc_device(card->ports[i].dev);
if (err < 0) {
int j;
- printk_err ("Cannot register HDLC device for port %d"
- " (errno %d)\n", i, -err );
+ pr_err("Cannot register HDLC device for port %d (errno %d)\n",
+ i, -err);
for (j = i; j < card->nports; j++) {
free_netdev(card->ports[j].dev);
card->ports[j].dev = NULL;
@@ -2401,10 +2393,10 @@ fst_init_card(struct fst_card_info *card)
}
}
- printk_info("%s-%s: %s IRQ%d, %d ports\n",
- port_to_dev(&card->ports[0])->name,
- port_to_dev(&card->ports[card->nports - 1])->name,
- type_strings[card->type], card->irq, card->nports);
+ pr_info("%s-%s: %s IRQ%d, %d ports\n",
+ port_to_dev(&card->ports[0])->name,
+ port_to_dev(&card->ports[card->nports - 1])->name,
+ type_strings[card->type], card->irq, card->nports);
}
static const struct net_device_ops fst_ops = {
@@ -2423,19 +2415,17 @@ static const struct net_device_ops fst_ops = {
static int __devinit
fst_add_one(struct pci_dev *pdev, const struct pci_device_id *ent)
{
- static int firsttime_done = 0;
static int no_of_cards_added = 0;
struct fst_card_info *card;
int err = 0;
int i;
- if (!firsttime_done) {
- printk_info("FarSync WAN driver " FST_USER_VERSION
- " (c) 2001-2004 FarSite Communications Ltd.\n");
- firsttime_done = 1;
- dbg(DBG_ASS, "The value of debug mask is %x\n", fst_debug_mask);
- }
-
+ printk_once(KERN_INFO
+ pr_fmt("FarSync WAN driver " FST_USER_VERSION
+ " (c) 2001-2004 FarSite Communications Ltd.\n"));
+#if FST_DEBUG
+ dbg(DBG_ASS, "The value of debug mask is %x\n", fst_debug_mask);
+#endif
/*
* We are going to be clever and allow certain cards not to be
* configured. An exclude list can be provided in /etc/modules.conf
@@ -2447,8 +2437,8 @@ fst_add_one(struct pci_dev *pdev, const struct pci_device_id *ent)
*/
for (i = 0; i < fst_excluded_cards; i++) {
if ((pdev->devfn) >> 3 == fst_excluded_list[i]) {
- printk_info("FarSync PCI device %d not assigned\n",
- (pdev->devfn) >> 3);
+ pr_info("FarSync PCI device %d not assigned\n",
+ (pdev->devfn) >> 3);
return -EBUSY;
}
}
@@ -2457,20 +2447,19 @@ fst_add_one(struct pci_dev *pdev, const struct pci_device_id *ent)
/* Allocate driver private data */
card = kzalloc(sizeof (struct fst_card_info), GFP_KERNEL);
if (card == NULL) {
- printk_err("FarSync card found but insufficient memory for"
- " driver storage\n");
+ pr_err("FarSync card found but insufficient memory for driver storage\n");
return -ENOMEM;
}
/* Try to enable the device */
if ((err = pci_enable_device(pdev)) != 0) {
- printk_err("Failed to enable card. Err %d\n", -err);
+ pr_err("Failed to enable card. Err %d\n", -err);
kfree(card);
return err;
}
if ((err = pci_request_regions(pdev, "FarSync")) !=0) {
- printk_err("Failed to allocate regions. Err %d\n", -err);
+ pr_err("Failed to allocate regions. Err %d\n", -err);
pci_disable_device(pdev);
kfree(card);
return err;
@@ -2481,14 +2470,14 @@ fst_add_one(struct pci_dev *pdev, const struct pci_device_id *ent)
card->phys_mem = pci_resource_start(pdev, 2);
card->phys_ctlmem = pci_resource_start(pdev, 3);
if ((card->mem = ioremap(card->phys_mem, FST_MEMSIZE)) == NULL) {
- printk_err("Physical memory remap failed\n");
+ pr_err("Physical memory remap failed\n");
pci_release_regions(pdev);
pci_disable_device(pdev);
kfree(card);
return -ENODEV;
}
if ((card->ctlmem = ioremap(card->phys_ctlmem, 0x10)) == NULL) {
- printk_err("Control memory remap failed\n");
+ pr_err("Control memory remap failed\n");
pci_release_regions(pdev);
pci_disable_device(pdev);
kfree(card);
@@ -2498,7 +2487,7 @@ fst_add_one(struct pci_dev *pdev, const struct pci_device_id *ent)
/* Register the interrupt handler */
if (request_irq(pdev->irq, fst_intr, IRQF_SHARED, FST_DEV_NAME, card)) {
- printk_err("Unable to register interrupt %d\n", card->irq);
+ pr_err("Unable to register interrupt %d\n", card->irq);
pci_release_regions(pdev);
pci_disable_device(pdev);
iounmap(card->ctlmem);
@@ -2529,7 +2518,7 @@ fst_add_one(struct pci_dev *pdev, const struct pci_device_id *ent)
if (!dev) {
while (i--)
free_netdev(card->ports[i].dev);
- printk_err ("FarSync: out of memory\n");
+ pr_err("FarSync: out of memory\n");
free_irq(card->irq, card);
pci_release_regions(pdev);
pci_disable_device(pdev);
@@ -2593,7 +2582,7 @@ fst_add_one(struct pci_dev *pdev, const struct pci_device_id *ent)
pci_alloc_consistent(card->device, FST_MAX_MTU,
&card->rx_dma_handle_card);
if (card->rx_dma_handle_host == NULL) {
- printk_err("Could not allocate rx dma buffer\n");
+ pr_err("Could not allocate rx dma buffer\n");
fst_disable_intr(card);
pci_release_regions(pdev);
pci_disable_device(pdev);
@@ -2606,7 +2595,7 @@ fst_add_one(struct pci_dev *pdev, const struct pci_device_id *ent)
pci_alloc_consistent(card->device, FST_MAX_MTU,
&card->tx_dma_handle_card);
if (card->tx_dma_handle_host == NULL) {
- printk_err("Could not allocate tx dma buffer\n");
+ pr_err("Could not allocate tx dma buffer\n");
fst_disable_intr(card);
pci_release_regions(pdev);
pci_disable_device(pdev);
@@ -2678,7 +2667,7 @@ fst_init(void)
static void __exit
fst_cleanup_module(void)
{
- printk_info("FarSync WAN driver unloading\n");
+ pr_info("FarSync WAN driver unloading\n");
pci_unregister_driver(&fst_driver);
}
diff --git a/drivers/net/wan/hd64570.h b/drivers/net/wan/hd64570.h
index 3839662ff20..e4f539ad071 100644
--- a/drivers/net/wan/hd64570.h
+++ b/drivers/net/wan/hd64570.h
@@ -153,7 +153,7 @@ typedef struct {
u16 len; /* Data Length */
u8 stat; /* Status */
u8 unused; /* pads to 2-byte boundary */
-}__attribute__ ((packed)) pkt_desc;
+}__packed pkt_desc;
/* Packet Descriptor Status bits */
diff --git a/drivers/net/wan/hdlc_cisco.c b/drivers/net/wan/hdlc_cisco.c
index ee7083fbea5..b38ffa149ab 100644
--- a/drivers/net/wan/hdlc_cisco.c
+++ b/drivers/net/wan/hdlc_cisco.c
@@ -36,7 +36,7 @@ struct hdlc_header {
u8 address;
u8 control;
__be16 protocol;
-}__attribute__ ((packed));
+}__packed;
struct cisco_packet {
@@ -45,7 +45,7 @@ struct cisco_packet {
__be32 par2;
__be16 rel; /* reliability */
__be32 time;
-}__attribute__ ((packed));
+}__packed;
#define CISCO_PACKET_LEN 18
#define CISCO_BIG_PACKET_LEN 20
diff --git a/drivers/net/wan/hdlc_fr.c b/drivers/net/wan/hdlc_fr.c
index 0e52993e207..0edb535bb2b 100644
--- a/drivers/net/wan/hdlc_fr.c
+++ b/drivers/net/wan/hdlc_fr.c
@@ -112,7 +112,7 @@ typedef struct {
unsigned de: 1;
unsigned ea2: 1;
#endif
-}__attribute__ ((packed)) fr_hdr;
+}__packed fr_hdr;
typedef struct pvc_device_struct {
diff --git a/drivers/net/wan/sdla.c b/drivers/net/wan/sdla.c
index 43ae6f440bf..f4125da2762 100644
--- a/drivers/net/wan/sdla.c
+++ b/drivers/net/wan/sdla.c
@@ -330,7 +330,7 @@ struct _dlci_stat
{
short dlci;
char flags;
-} __attribute__((packed));
+} __packed;
struct _frad_stat
{
@@ -1211,14 +1211,9 @@ static int sdla_xfer(struct net_device *dev, struct sdla_mem __user *info, int r
}
else
{
- temp = kmalloc(mem.len, GFP_KERNEL);
- if (!temp)
- return(-ENOMEM);
- if(copy_from_user(temp, mem.data, mem.len))
- {
- kfree(temp);
- return -EFAULT;
- }
+ temp = memdup_user(mem.data, mem.len);
+ if (IS_ERR(temp))
+ return PTR_ERR(temp);
sdla_write(dev, mem.addr, temp, mem.len);
kfree(temp);
}
diff --git a/drivers/net/wd.c b/drivers/net/wd.c
index 746a5ee32f3..eb72c67699a 100644
--- a/drivers/net/wd.c
+++ b/drivers/net/wd.c
@@ -358,8 +358,10 @@ static int __init wd_probe1(struct net_device *dev, int ioaddr)
#endif
err = register_netdev(dev);
- if (err)
+ if (err) {
free_irq(dev->irq, dev);
+ iounmap(ei_status.mem);
+ }
return err;
}
diff --git a/drivers/net/wimax/i2400m/control.c b/drivers/net/wimax/i2400m/control.c
index d86e8f31e7f..9fb03082153 100644
--- a/drivers/net/wimax/i2400m/control.c
+++ b/drivers/net/wimax/i2400m/control.c
@@ -50,7 +50,7 @@
*
* ROADMAP
*
- * i2400m_dev_initalize() Called by i2400m_dev_start()
+ * i2400m_dev_initialize() Called by i2400m_dev_start()
* i2400m_set_init_config()
* i2400m_cmd_get_state()
* i2400m_dev_shutdown() Called by i2400m_dev_stop()
@@ -848,7 +848,7 @@ struct i2400m_cmd_enter_power_save {
struct i2400m_l3l4_hdr hdr;
struct i2400m_tlv_hdr tlv;
__le32 val;
-} __attribute__((packed));
+} __packed;
/*
diff --git a/drivers/net/wimax/i2400m/fw.c b/drivers/net/wimax/i2400m/fw.c
index 11491354e5b..8b55a5b1415 100644
--- a/drivers/net/wimax/i2400m/fw.c
+++ b/drivers/net/wimax/i2400m/fw.c
@@ -651,7 +651,7 @@ static int i2400m_download_chunk(struct i2400m *i2400m, const void *chunk,
struct {
struct i2400m_bootrom_header cmd;
u8 cmd_payload[chunk_len];
- } __attribute__((packed)) *buf;
+ } __packed *buf;
struct i2400m_bootrom_header ack;
d_fnstart(5, dev, "(i2400m %p chunk %p __chunk_len %zu addr 0x%08lx "
@@ -794,7 +794,7 @@ int i2400m_dnload_finalize(struct i2400m *i2400m,
struct {
struct i2400m_bootrom_header cmd;
u8 cmd_pl[0];
- } __attribute__((packed)) *cmd_buf;
+ } __packed *cmd_buf;
size_t signature_block_offset, signature_block_size;
d_fnstart(3, dev, "offset %zu\n", offset);
@@ -1029,7 +1029,7 @@ int i2400m_read_mac_addr(struct i2400m *i2400m)
struct {
struct i2400m_bootrom_header ack;
u8 ack_pl[16];
- } __attribute__((packed)) ack_buf;
+ } __packed ack_buf;
d_fnstart(5, dev, "(i2400m %p)\n", i2400m);
cmd = i2400m->bm_cmd_buf;
@@ -1115,7 +1115,7 @@ int i2400m_dnload_init_signed(struct i2400m *i2400m,
struct {
struct i2400m_bootrom_header cmd;
struct i2400m_bcf_hdr cmd_pl;
- } __attribute__((packed)) *cmd_buf;
+ } __packed *cmd_buf;
struct i2400m_bootrom_header ack;
d_fnstart(5, dev, "(i2400m %p bcf_hdr %p)\n", i2400m, bcf_hdr);
diff --git a/drivers/net/wimax/i2400m/op-rfkill.c b/drivers/net/wimax/i2400m/op-rfkill.c
index 035e4cf3e6e..9e02b90b008 100644
--- a/drivers/net/wimax/i2400m/op-rfkill.c
+++ b/drivers/net/wimax/i2400m/op-rfkill.c
@@ -91,7 +91,7 @@ int i2400m_op_rfkill_sw_toggle(struct wimax_dev *wimax_dev,
struct {
struct i2400m_l3l4_hdr hdr;
struct i2400m_tlv_rf_operation sw_rf;
- } __attribute__((packed)) *cmd;
+ } __packed *cmd;
char strerr[32];
d_fnstart(4, dev, "(wimax_dev %p state %d)\n", wimax_dev, state);
diff --git a/drivers/net/wireless/adm8211.c b/drivers/net/wireless/adm8211.c
index 880ad9d170c..a105087af96 100644
--- a/drivers/net/wireless/adm8211.c
+++ b/drivers/net/wireless/adm8211.c
@@ -373,8 +373,8 @@ static void adm8211_interrupt_rci(struct ieee80211_hw *dev)
pktlen = status & RDES0_STATUS_FL;
if (pktlen > RX_PKT_SIZE) {
if (net_ratelimit())
- printk(KERN_DEBUG "%s: frame too long (%d)\n",
- wiphy_name(dev->wiphy), pktlen);
+ wiphy_debug(dev->wiphy, "frame too long (%d)\n",
+ pktlen);
pktlen = RX_PKT_SIZE;
}
@@ -454,10 +454,10 @@ static void adm8211_interrupt_rci(struct ieee80211_hw *dev)
static irqreturn_t adm8211_interrupt(int irq, void *dev_id)
{
-#define ADM8211_INT(x) \
-do { \
- if (unlikely(stsr & ADM8211_STSR_ ## x)) \
- printk(KERN_DEBUG "%s: " #x "\n", wiphy_name(dev->wiphy)); \
+#define ADM8211_INT(x) \
+do { \
+ if (unlikely(stsr & ADM8211_STSR_ ## x)) \
+ wiphy_debug(dev->wiphy, "%s\n", #x); \
} while (0)
struct ieee80211_hw *dev = dev_id;
@@ -570,9 +570,9 @@ static int adm8211_write_bbp(struct ieee80211_hw *dev, u8 addr, u8 data)
}
if (timeout == 0) {
- printk(KERN_DEBUG "%s: adm8211_write_bbp(%d,%d) failed"
- " prewrite (reg=0x%08x)\n",
- wiphy_name(dev->wiphy), addr, data, reg);
+ wiphy_debug(dev->wiphy,
+ "adm8211_write_bbp(%d,%d) failed prewrite (reg=0x%08x)\n",
+ addr, data, reg);
return -ETIMEDOUT;
}
@@ -605,9 +605,9 @@ static int adm8211_write_bbp(struct ieee80211_hw *dev, u8 addr, u8 data)
if (timeout == 0) {
ADM8211_CSR_WRITE(BBPCTL, ADM8211_CSR_READ(BBPCTL) &
~ADM8211_BBPCTL_WR);
- printk(KERN_DEBUG "%s: adm8211_write_bbp(%d,%d) failed"
- " postwrite (reg=0x%08x)\n",
- wiphy_name(dev->wiphy), addr, data, reg);
+ wiphy_debug(dev->wiphy,
+ "adm8211_write_bbp(%d,%d) failed postwrite (reg=0x%08x)\n",
+ addr, data, reg);
return -ETIMEDOUT;
}
@@ -675,8 +675,8 @@ static int adm8211_rf_set_channel(struct ieee80211_hw *dev, unsigned int chan)
break;
default:
- printk(KERN_DEBUG "%s: unsupported transceiver type %d\n",
- wiphy_name(dev->wiphy), priv->transceiver_type);
+ wiphy_debug(dev->wiphy, "unsupported transceiver type %d\n",
+ priv->transceiver_type);
break;
}
@@ -732,8 +732,8 @@ static int adm8211_rf_set_channel(struct ieee80211_hw *dev, unsigned int chan)
/* Nothing to do for ADMtek BBP */
} else if (priv->bbp_type != ADM8211_TYPE_ADMTEK)
- printk(KERN_DEBUG "%s: unsupported BBP type %d\n",
- wiphy_name(dev->wiphy), priv->bbp_type);
+ wiphy_debug(dev->wiphy, "unsupported bbp type %d\n",
+ priv->bbp_type);
ADM8211_RESTORE();
@@ -1027,13 +1027,12 @@ static int adm8211_hw_init_bbp(struct ieee80211_hw *dev)
break;
default:
- printk(KERN_DEBUG "%s: unsupported transceiver %d\n",
- wiphy_name(dev->wiphy), priv->transceiver_type);
+ wiphy_debug(dev->wiphy, "unsupported transceiver %d\n",
+ priv->transceiver_type);
break;
}
} else
- printk(KERN_DEBUG "%s: unsupported BBP %d\n",
- wiphy_name(dev->wiphy), priv->bbp_type);
+ wiphy_debug(dev->wiphy, "unsupported bbp %d\n", priv->bbp_type);
ADM8211_CSR_WRITE(SYNRF, 0);
@@ -1509,15 +1508,13 @@ static int adm8211_start(struct ieee80211_hw *dev)
/* Power up MAC and RF chips */
retval = adm8211_hw_reset(dev);
if (retval) {
- printk(KERN_ERR "%s: hardware reset failed\n",
- wiphy_name(dev->wiphy));
+ wiphy_err(dev->wiphy, "hardware reset failed\n");
goto fail;
}
retval = adm8211_init_rings(dev);
if (retval) {
- printk(KERN_ERR "%s: failed to initialize rings\n",
- wiphy_name(dev->wiphy));
+ wiphy_err(dev->wiphy, "failed to initialize rings\n");
goto fail;
}
@@ -1528,8 +1525,7 @@ static int adm8211_start(struct ieee80211_hw *dev)
retval = request_irq(priv->pdev->irq, adm8211_interrupt,
IRQF_SHARED, "adm8211", dev);
if (retval) {
- printk(KERN_ERR "%s: failed to register IRQ handler\n",
- wiphy_name(dev->wiphy));
+ wiphy_err(dev->wiphy, "failed to register irq handler\n");
goto fail;
}
@@ -1903,15 +1899,17 @@ static int __devinit adm8211_probe(struct pci_dev *pdev,
if (err) {
printk(KERN_ERR "%s (adm8211): Cannot register device\n",
pci_name(pdev));
- goto err_free_desc;
+ goto err_free_eeprom;
}
- printk(KERN_INFO "%s: hwaddr %pM, Rev 0x%02x\n",
- wiphy_name(dev->wiphy), dev->wiphy->perm_addr,
- pdev->revision);
+ wiphy_info(dev->wiphy, "hwaddr %pm, rev 0x%02x\n",
+ dev->wiphy->perm_addr, pdev->revision);
return 0;
+ err_free_eeprom:
+ kfree(priv->eeprom);
+
err_free_desc:
pci_free_consistent(pdev,
sizeof(struct adm8211_desc) * priv->rx_ring_size +
diff --git a/drivers/net/wireless/adm8211.h b/drivers/net/wireless/adm8211.h
index b07e4d3a6b4..bbc10b1cde8 100644
--- a/drivers/net/wireless/adm8211.h
+++ b/drivers/net/wireless/adm8211.h
@@ -80,7 +80,7 @@ struct adm8211_csr {
__le32 FEMR; /* 0x104 */
__le32 FPSR; /* 0x108 */
__le32 FFER; /* 0x10C */
-} __attribute__ ((packed));
+} __packed;
/* CSR0 - PAR (PCI Address Register) */
#define ADM8211_PAR_MWIE (1 << 24)
@@ -484,7 +484,7 @@ struct adm8211_tx_hdr {
u8 entry_control; // huh??
u16 reserved_1;
u32 reserved_2;
-} __attribute__ ((packed));
+} __packed;
#define RX_COPY_BREAK 128
@@ -531,7 +531,7 @@ struct adm8211_eeprom {
u8 lnags_threshold[14]; /* 0x70 */
__le16 checksum; /* 0x7E */
u8 cis_data[0]; /* 0x80, 384 bytes */
-} __attribute__ ((packed));
+} __packed;
struct adm8211_priv {
struct pci_dev *pdev;
diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c
index 3b7ab20a5c5..1d05445d4ba 100644
--- a/drivers/net/wireless/airo.c
+++ b/drivers/net/wireless/airo.c
@@ -506,20 +506,20 @@ struct WepKeyRid {
u8 mac[ETH_ALEN];
__le16 klen;
u8 key[16];
-} __attribute__ ((packed));
+} __packed;
/* These structures are from the Aironet's PC4500 Developers Manual */
typedef struct Ssid Ssid;
struct Ssid {
__le16 len;
u8 ssid[32];
-} __attribute__ ((packed));
+} __packed;
typedef struct SsidRid SsidRid;
struct SsidRid {
__le16 len;
Ssid ssids[3];
-} __attribute__ ((packed));
+} __packed;
typedef struct ModulationRid ModulationRid;
struct ModulationRid {
@@ -528,7 +528,7 @@ struct ModulationRid {
#define MOD_DEFAULT cpu_to_le16(0)
#define MOD_CCK cpu_to_le16(1)
#define MOD_MOK cpu_to_le16(2)
-} __attribute__ ((packed));
+} __packed;
typedef struct ConfigRid ConfigRid;
struct ConfigRid {
@@ -652,7 +652,7 @@ struct ConfigRid {
#define MAGIC_STAY_IN_CAM (1<<10)
u8 magicControl;
__le16 autoWake;
-} __attribute__ ((packed));
+} __packed;
typedef struct StatusRid StatusRid;
struct StatusRid {
@@ -711,20 +711,20 @@ struct StatusRid {
#define STAT_LEAPFAILED 91
#define STAT_LEAPTIMEDOUT 92
#define STAT_LEAPCOMPLETE 93
-} __attribute__ ((packed));
+} __packed;
typedef struct StatsRid StatsRid;
struct StatsRid {
__le16 len;
__le16 spacer;
__le32 vals[100];
-} __attribute__ ((packed));
+} __packed;
typedef struct APListRid APListRid;
struct APListRid {
__le16 len;
u8 ap[4][ETH_ALEN];
-} __attribute__ ((packed));
+} __packed;
typedef struct CapabilityRid CapabilityRid;
struct CapabilityRid {
@@ -754,7 +754,7 @@ struct CapabilityRid {
__le16 bootBlockVer;
__le16 requiredHard;
__le16 extSoftCap;
-} __attribute__ ((packed));
+} __packed;
/* Only present on firmware >= 5.30.17 */
typedef struct BSSListRidExtra BSSListRidExtra;
@@ -762,7 +762,7 @@ struct BSSListRidExtra {
__le16 unknown[4];
u8 fixed[12]; /* WLAN management frame */
u8 iep[624];
-} __attribute__ ((packed));
+} __packed;
typedef struct BSSListRid BSSListRid;
struct BSSListRid {
@@ -796,7 +796,7 @@ struct BSSListRid {
/* Only present on firmware >= 5.30.17 */
BSSListRidExtra extra;
-} __attribute__ ((packed));
+} __packed;
typedef struct {
BSSListRid bss;
@@ -807,13 +807,13 @@ typedef struct tdsRssiEntry tdsRssiEntry;
struct tdsRssiEntry {
u8 rssipct;
u8 rssidBm;
-} __attribute__ ((packed));
+} __packed;
typedef struct tdsRssiRid tdsRssiRid;
struct tdsRssiRid {
u16 len;
tdsRssiEntry x[256];
-} __attribute__ ((packed));
+} __packed;
typedef struct MICRid MICRid;
struct MICRid {
@@ -823,7 +823,7 @@ struct MICRid {
u8 multicast[16];
__le16 unicastValid;
u8 unicast[16];
-} __attribute__ ((packed));
+} __packed;
typedef struct MICBuffer MICBuffer;
struct MICBuffer {
@@ -841,7 +841,7 @@ struct MICBuffer {
} u;
__be32 mic;
__be32 seq;
-} __attribute__ ((packed));
+} __packed;
typedef struct {
u8 da[ETH_ALEN];
@@ -996,7 +996,7 @@ struct rx_hdr {
u8 rate;
u8 freq;
__le16 tmp[4];
-} __attribute__ ((packed));
+} __packed;
typedef struct {
unsigned int ctl: 15;
@@ -2931,8 +2931,8 @@ err_out_res:
release_region( dev->base_addr, 64 );
err_out_nets:
airo_networks_free(ai);
- del_airo_dev(ai);
err_out_free:
+ del_airo_dev(ai);
free_netdev(dev);
return NULL;
}
@@ -4657,7 +4657,7 @@ static ssize_t proc_write( struct file *file,
loff_t *offset )
{
loff_t pos = *offset;
- struct proc_data *priv = (struct proc_data*)file->private_data;
+ struct proc_data *priv = file->private_data;
if (!priv->wbuffer)
return -EINVAL;
@@ -4689,7 +4689,7 @@ static int proc_status_open(struct inode *inode, struct file *file)
if ((file->private_data = kzalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL)
return -ENOMEM;
- data = (struct proc_data *)file->private_data;
+ data = file->private_data;
if ((data->rbuffer = kmalloc( 2048, GFP_KERNEL )) == NULL) {
kfree (file->private_data);
return -ENOMEM;
@@ -4772,7 +4772,7 @@ static int proc_stats_rid_open( struct inode *inode,
if ((file->private_data = kzalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL)
return -ENOMEM;
- data = (struct proc_data *)file->private_data;
+ data = file->private_data;
if ((data->rbuffer = kmalloc( 4096, GFP_KERNEL )) == NULL) {
kfree (file->private_data);
return -ENOMEM;
@@ -5045,7 +5045,7 @@ static int proc_config_open(struct inode *inode, struct file *file)
if ((file->private_data = kzalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL)
return -ENOMEM;
- data = (struct proc_data *)file->private_data;
+ data = file->private_data;
if ((data->rbuffer = kmalloc( 2048, GFP_KERNEL )) == NULL) {
kfree (file->private_data);
return -ENOMEM;
@@ -5127,7 +5127,7 @@ static int proc_config_open(struct inode *inode, struct file *file)
static void proc_SSID_on_close(struct inode *inode, struct file *file)
{
- struct proc_data *data = (struct proc_data *)file->private_data;
+ struct proc_data *data = file->private_data;
struct proc_dir_entry *dp = PDE(inode);
struct net_device *dev = dp->data;
struct airo_info *ai = dev->ml_priv;
@@ -5163,7 +5163,7 @@ static void proc_SSID_on_close(struct inode *inode, struct file *file)
}
static void proc_APList_on_close( struct inode *inode, struct file *file ) {
- struct proc_data *data = (struct proc_data *)file->private_data;
+ struct proc_data *data = file->private_data;
struct proc_dir_entry *dp = PDE(inode);
struct net_device *dev = dp->data;
struct airo_info *ai = dev->ml_priv;
@@ -5309,7 +5309,7 @@ static void proc_wepkey_on_close( struct inode *inode, struct file *file ) {
memset(key, 0, sizeof(key));
- data = (struct proc_data *)file->private_data;
+ data = file->private_data;
if ( !data->writelen ) return;
if (data->wbuffer[0] >= '0' && data->wbuffer[0] <= '3' &&
@@ -5363,7 +5363,7 @@ static int proc_wepkey_open( struct inode *inode, struct file *file )
if ((file->private_data = kzalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL)
return -ENOMEM;
memset(&wkr, 0, sizeof(wkr));
- data = (struct proc_data *)file->private_data;
+ data = file->private_data;
if ((data->rbuffer = kzalloc( 180, GFP_KERNEL )) == NULL) {
kfree (file->private_data);
return -ENOMEM;
@@ -5409,7 +5409,7 @@ static int proc_SSID_open(struct inode *inode, struct file *file)
if ((file->private_data = kzalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL)
return -ENOMEM;
- data = (struct proc_data *)file->private_data;
+ data = file->private_data;
if ((data->rbuffer = kmalloc( 104, GFP_KERNEL )) == NULL) {
kfree (file->private_data);
return -ENOMEM;
@@ -5453,7 +5453,7 @@ static int proc_APList_open( struct inode *inode, struct file *file ) {
if ((file->private_data = kzalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL)
return -ENOMEM;
- data = (struct proc_data *)file->private_data;
+ data = file->private_data;
if ((data->rbuffer = kmalloc( 104, GFP_KERNEL )) == NULL) {
kfree (file->private_data);
return -ENOMEM;
@@ -5495,7 +5495,7 @@ static int proc_BSSList_open( struct inode *inode, struct file *file ) {
if ((file->private_data = kzalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL)
return -ENOMEM;
- data = (struct proc_data *)file->private_data;
+ data = file->private_data;
if ((data->rbuffer = kmalloc( 1024, GFP_KERNEL )) == NULL) {
kfree (file->private_data);
return -ENOMEM;
diff --git a/drivers/net/wireless/airo_cs.c b/drivers/net/wireless/airo_cs.c
index 33bdc6a84e8..9a121a5b787 100644
--- a/drivers/net/wireless/airo_cs.c
+++ b/drivers/net/wireless/airo_cs.c
@@ -32,7 +32,6 @@
#include <linux/timer.h>
#include <linux/netdevice.h>
-#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/cistpl.h>
#include <pcmcia/cisreg.h>
@@ -155,8 +154,6 @@ static int airo_cs_config_check(struct pcmcia_device *p_dev,
unsigned int vcc,
void *priv_data)
{
- win_req_t *req = priv_data;
-
if (cfg->index == 0)
return -ENODEV;
@@ -176,52 +173,25 @@ static int airo_cs_config_check(struct pcmcia_device *p_dev,
p_dev->conf.Attributes |= CONF_ENABLE_IRQ;
/* IO window settings */
- p_dev->io.NumPorts1 = p_dev->io.NumPorts2 = 0;
+ p_dev->resource[0]->end = p_dev->resource[1]->end = 0;
if ((cfg->io.nwin > 0) || (dflt->io.nwin > 0)) {
cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt->io;
- p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
- if (!(io->flags & CISTPL_IO_8BIT))
- p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_16;
- if (!(io->flags & CISTPL_IO_16BIT))
- p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
- p_dev->io.BasePort1 = io->win[0].base;
- p_dev->io.NumPorts1 = io->win[0].len;
+ p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH;
+ p_dev->resource[0]->flags |=
+ pcmcia_io_cfg_data_width(io->flags);
+ p_dev->resource[0]->start = io->win[0].base;
+ p_dev->resource[0]->end = io->win[0].len;
if (io->nwin > 1) {
- p_dev->io.Attributes2 = p_dev->io.Attributes1;
- p_dev->io.BasePort2 = io->win[1].base;
- p_dev->io.NumPorts2 = io->win[1].len;
+ p_dev->resource[1]->flags = p_dev->resource[0]->flags;
+ p_dev->resource[1]->start = io->win[1].base;
+ p_dev->resource[1]->end = io->win[1].len;
}
}
/* This reserves IO space but doesn't actually enable it */
- if (pcmcia_request_io(p_dev, &p_dev->io) != 0)
+ if (pcmcia_request_io(p_dev) != 0)
return -ENODEV;
- /*
- Now set up a common memory window, if needed. There is room
- in the struct pcmcia_device structure for one memory window handle,
- but if the base addresses need to be saved, or if multiple
- windows are needed, the info should go in the private data
- structure for this device.
-
- Note that the memory window base is a physical address, and
- needs to be mapped to virtual space with ioremap() before it
- is used.
- */
- if ((cfg->mem.nwin > 0) || (dflt->mem.nwin > 0)) {
- cistpl_mem_t *mem = (cfg->mem.nwin) ? &cfg->mem : &dflt->mem;
- memreq_t map;
- req->Attributes = WIN_DATA_WIDTH_16|WIN_MEMORY_TYPE_CM;
- req->Base = mem->win[0].host_addr;
- req->Size = mem->win[0].len;
- req->AccessSpeed = 0;
- if (pcmcia_request_window(p_dev, req, &p_dev->win) != 0)
- return -ENODEV;
- map.Page = 0;
- map.CardOffset = mem->win[0].card_addr;
- if (pcmcia_map_mem_page(p_dev, p_dev->win, &map) != 0)
- return -ENODEV;
- }
/* If we got this far, we're cool! */
return 0;
}
@@ -230,17 +200,12 @@ static int airo_cs_config_check(struct pcmcia_device *p_dev,
static int airo_config(struct pcmcia_device *link)
{
local_info_t *dev;
- win_req_t *req;
int ret;
dev = link->priv;
dev_dbg(&link->dev, "airo_config\n");
- req = kzalloc(sizeof(win_req_t), GFP_KERNEL);
- if (!req)
- return -ENOMEM;
-
/*
* In this loop, we scan the CIS for configuration table
* entries, each of which describes a valid card
@@ -255,7 +220,7 @@ static int airo_config(struct pcmcia_device *link)
* and most client drivers will only use the CIS to fill in
* implementation-defined details.
*/
- ret = pcmcia_loop_config(link, airo_cs_config_check, req);
+ ret = pcmcia_loop_config(link, airo_cs_config_check, NULL);
if (ret)
goto failed;
@@ -272,7 +237,7 @@ static int airo_config(struct pcmcia_device *link)
goto failed;
((local_info_t *)link->priv)->eth_dev =
init_airo_card(link->irq,
- link->io.BasePort1, 1, &link->dev);
+ link->resource[0]->start, 1, &link->dev);
if (!((local_info_t *)link->priv)->eth_dev)
goto failed;
@@ -282,22 +247,15 @@ static int airo_config(struct pcmcia_device *link)
if (link->conf.Vpp)
printk(", Vpp %d.%d", link->conf.Vpp/10, link->conf.Vpp%10);
printk(", irq %d", link->irq);
- if (link->io.NumPorts1)
- printk(", io 0x%04x-0x%04x", link->io.BasePort1,
- link->io.BasePort1+link->io.NumPorts1-1);
- if (link->io.NumPorts2)
- printk(" & 0x%04x-0x%04x", link->io.BasePort2,
- link->io.BasePort2+link->io.NumPorts2-1);
- if (link->win)
- printk(", mem 0x%06lx-0x%06lx", req->Base,
- req->Base+req->Size-1);
+ if (link->resource[0])
+ printk(" & %pR", link->resource[0]);
+ if (link->resource[1])
+ printk(" & %pR", link->resource[1]);
printk("\n");
- kfree(req);
return 0;
failed:
airo_release(link);
- kfree(req);
return -ENODEV;
} /* airo_config */
diff --git a/drivers/net/wireless/at76c50x-usb.c b/drivers/net/wireless/at76c50x-usb.c
index 8a2d4afc74f..d5140a87f07 100644
--- a/drivers/net/wireless/at76c50x-usb.c
+++ b/drivers/net/wireless/at76c50x-usb.c
@@ -7,6 +7,7 @@
* Copyright (c) 2004 Balint Seeber <n0_5p4m_p13453@hotmail.com>
* Copyright (c) 2007 Guido Guenther <agx@sigxcpu.org>
* Copyright (c) 2007 Kalle Valo <kalle.valo@iki.fi>
+ * Copyright (c) 2010 Sebastian Smolorz <sesmo@gmx.net>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
@@ -88,22 +89,19 @@
#define DBG_DEFAULTS 0
/* Use our own dbg macro */
-#define at76_dbg(bits, format, arg...) \
- do { \
- if (at76_debug & (bits)) \
- printk(KERN_DEBUG DRIVER_NAME ": " format "\n" , \
- ## arg); \
- } while (0)
-
-#define at76_dbg_dump(bits, buf, len, format, arg...) \
- do { \
- if (at76_debug & (bits)) { \
- printk(KERN_DEBUG DRIVER_NAME ": " format "\n" , \
- ## arg); \
- print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, \
- buf, len); \
- } \
- } while (0)
+#define at76_dbg(bits, format, arg...) \
+do { \
+ if (at76_debug & (bits)) \
+ printk(KERN_DEBUG DRIVER_NAME ": " format "\n", ##arg); \
+} while (0)
+
+#define at76_dbg_dump(bits, buf, len, format, arg...) \
+do { \
+ if (at76_debug & (bits)) { \
+ printk(KERN_DEBUG DRIVER_NAME ": " format "\n", ##arg); \
+ print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, buf, len); \
+ } \
+} while (0)
static uint at76_debug = DBG_DEFAULTS;
@@ -305,7 +303,7 @@ struct dfu_status {
unsigned char poll_timeout[3];
unsigned char state;
unsigned char string;
-} __attribute__((packed));
+} __packed;
static inline int at76_is_intersil(enum board_type board)
{
@@ -657,8 +655,8 @@ static int at76_get_hw_config(struct at76_priv *priv)
exit:
kfree(hwcfg);
if (ret < 0)
- printk(KERN_ERR "%s: cannot get HW Config (error %d)\n",
- wiphy_name(priv->hw->wiphy), ret);
+ wiphy_err(priv->hw->wiphy, "cannot get hw config (error %d)\n",
+ ret);
return ret;
}
@@ -793,8 +791,9 @@ static int at76_wait_completion(struct at76_priv *priv, int cmd)
do {
status = at76_get_cmd_status(priv->udev, cmd);
if (status < 0) {
- printk(KERN_ERR "%s: at76_get_cmd_status failed: %d\n",
- wiphy_name(priv->hw->wiphy), status);
+ wiphy_err(priv->hw->wiphy,
+ "at76_get_cmd_status failed: %d\n",
+ status);
break;
}
@@ -809,9 +808,8 @@ static int at76_wait_completion(struct at76_priv *priv, int cmd)
schedule_timeout_interruptible(HZ / 10); /* 100 ms */
if (time_after(jiffies, timeout)) {
- printk(KERN_ERR
- "%s: completion timeout for command %d\n",
- wiphy_name(priv->hw->wiphy), cmd);
+ wiphy_err(priv->hw->wiphy,
+ "completion timeout for command %d\n", cmd);
status = -ETIMEDOUT;
break;
}
@@ -832,9 +830,9 @@ static int at76_set_mib(struct at76_priv *priv, struct set_mib_buffer *buf)
ret = at76_wait_completion(priv, CMD_SET_MIB);
if (ret != CMD_STATUS_COMPLETE) {
- printk(KERN_INFO
- "%s: set_mib: at76_wait_completion failed "
- "with %d\n", wiphy_name(priv->hw->wiphy), ret);
+ wiphy_info(priv->hw->wiphy,
+ "set_mib: at76_wait_completion failed with %d\n",
+ ret);
ret = -EIO;
}
@@ -854,8 +852,8 @@ static int at76_set_radio(struct at76_priv *priv, int enable)
ret = at76_set_card_command(priv->udev, cmd, NULL, 0);
if (ret < 0)
- printk(KERN_ERR "%s: at76_set_card_command(%d) failed: %d\n",
- wiphy_name(priv->hw->wiphy), cmd, ret);
+ wiphy_err(priv->hw->wiphy,
+ "at76_set_card_command(%d) failed: %d\n", cmd, ret);
else
ret = 1;
@@ -875,8 +873,8 @@ static int at76_set_pm_mode(struct at76_priv *priv)
ret = at76_set_mib(priv, &priv->mib_buf);
if (ret < 0)
- printk(KERN_ERR "%s: set_mib (pm_mode) failed: %d\n",
- wiphy_name(priv->hw->wiphy), ret);
+ wiphy_err(priv->hw->wiphy, "set_mib (pm_mode) failed: %d\n",
+ ret);
return ret;
}
@@ -892,8 +890,8 @@ static int at76_set_preamble(struct at76_priv *priv, u8 type)
ret = at76_set_mib(priv, &priv->mib_buf);
if (ret < 0)
- printk(KERN_ERR "%s: set_mib (preamble) failed: %d\n",
- wiphy_name(priv->hw->wiphy), ret);
+ wiphy_err(priv->hw->wiphy, "set_mib (preamble) failed: %d\n",
+ ret);
return ret;
}
@@ -909,8 +907,8 @@ static int at76_set_frag(struct at76_priv *priv, u16 size)
ret = at76_set_mib(priv, &priv->mib_buf);
if (ret < 0)
- printk(KERN_ERR "%s: set_mib (frag threshold) failed: %d\n",
- wiphy_name(priv->hw->wiphy), ret);
+ wiphy_err(priv->hw->wiphy,
+ "set_mib (frag threshold) failed: %d\n", ret);
return ret;
}
@@ -926,8 +924,7 @@ static int at76_set_rts(struct at76_priv *priv, u16 size)
ret = at76_set_mib(priv, &priv->mib_buf);
if (ret < 0)
- printk(KERN_ERR "%s: set_mib (rts) failed: %d\n",
- wiphy_name(priv->hw->wiphy), ret);
+ wiphy_err(priv->hw->wiphy, "set_mib (rts) failed: %d\n", ret);
return ret;
}
@@ -943,8 +940,8 @@ static int at76_set_autorate_fallback(struct at76_priv *priv, int onoff)
ret = at76_set_mib(priv, &priv->mib_buf);
if (ret < 0)
- printk(KERN_ERR "%s: set_mib (autorate fallback) failed: %d\n",
- wiphy_name(priv->hw->wiphy), ret);
+ wiphy_err(priv->hw->wiphy,
+ "set_mib (autorate fallback) failed: %d\n", ret);
return ret;
}
@@ -962,8 +959,8 @@ static void at76_dump_mib_mac_addr(struct at76_priv *priv)
ret = at76_get_mib(priv->udev, MIB_MAC_ADDR, m,
sizeof(struct mib_mac_addr));
if (ret < 0) {
- printk(KERN_ERR "%s: at76_get_mib (MAC_ADDR) failed: %d\n",
- wiphy_name(priv->hw->wiphy), ret);
+ wiphy_err(priv->hw->wiphy,
+ "at76_get_mib (mac_addr) failed: %d\n", ret);
goto exit;
}
@@ -991,8 +988,8 @@ static void at76_dump_mib_mac_wep(struct at76_priv *priv)
ret = at76_get_mib(priv->udev, MIB_MAC_WEP, m,
sizeof(struct mib_mac_wep));
if (ret < 0) {
- printk(KERN_ERR "%s: at76_get_mib (MAC_WEP) failed: %d\n",
- wiphy_name(priv->hw->wiphy), ret);
+ wiphy_err(priv->hw->wiphy,
+ "at76_get_mib (mac_wep) failed: %d\n", ret);
goto exit;
}
@@ -1028,8 +1025,8 @@ static void at76_dump_mib_mac_mgmt(struct at76_priv *priv)
ret = at76_get_mib(priv->udev, MIB_MAC_MGMT, m,
sizeof(struct mib_mac_mgmt));
if (ret < 0) {
- printk(KERN_ERR "%s: at76_get_mib (MAC_MGMT) failed: %d\n",
- wiphy_name(priv->hw->wiphy), ret);
+ wiphy_err(priv->hw->wiphy,
+ "at76_get_mib (mac_mgmt) failed: %d\n", ret);
goto exit;
}
@@ -1064,8 +1061,8 @@ static void at76_dump_mib_mac(struct at76_priv *priv)
ret = at76_get_mib(priv->udev, MIB_MAC, m, sizeof(struct mib_mac));
if (ret < 0) {
- printk(KERN_ERR "%s: at76_get_mib (MAC) failed: %d\n",
- wiphy_name(priv->hw->wiphy), ret);
+ wiphy_err(priv->hw->wiphy,
+ "at76_get_mib (mac) failed: %d\n", ret);
goto exit;
}
@@ -1101,8 +1098,8 @@ static void at76_dump_mib_phy(struct at76_priv *priv)
ret = at76_get_mib(priv->udev, MIB_PHY, m, sizeof(struct mib_phy));
if (ret < 0) {
- printk(KERN_ERR "%s: at76_get_mib (PHY) failed: %d\n",
- wiphy_name(priv->hw->wiphy), ret);
+ wiphy_err(priv->hw->wiphy,
+ "at76_get_mib (phy) failed: %d\n", ret);
goto exit;
}
@@ -1134,8 +1131,8 @@ static void at76_dump_mib_local(struct at76_priv *priv)
ret = at76_get_mib(priv->udev, MIB_LOCAL, m, sizeof(struct mib_local));
if (ret < 0) {
- printk(KERN_ERR "%s: at76_get_mib (LOCAL) failed: %d\n",
- wiphy_name(priv->hw->wiphy), ret);
+ wiphy_err(priv->hw->wiphy,
+ "at76_get_mib (local) failed: %d\n", ret);
goto exit;
}
@@ -1160,8 +1157,8 @@ static void at76_dump_mib_mdomain(struct at76_priv *priv)
ret = at76_get_mib(priv->udev, MIB_MDOMAIN, m,
sizeof(struct mib_mdomain));
if (ret < 0) {
- printk(KERN_ERR "%s: at76_get_mib (MDOMAIN) failed: %d\n",
- wiphy_name(priv->hw->wiphy), ret);
+ wiphy_err(priv->hw->wiphy,
+ "at76_get_mib (mdomain) failed: %d\n", ret);
goto exit;
}
@@ -1232,16 +1229,16 @@ static int at76_submit_rx_urb(struct at76_priv *priv)
struct sk_buff *skb = priv->rx_skb;
if (!priv->rx_urb) {
- printk(KERN_ERR "%s: %s: priv->rx_urb is NULL\n",
- wiphy_name(priv->hw->wiphy), __func__);
+ wiphy_err(priv->hw->wiphy, "%s: priv->rx_urb is null\n",
+ __func__);
return -EFAULT;
}
if (!skb) {
skb = dev_alloc_skb(sizeof(struct at76_rx_buffer));
if (!skb) {
- printk(KERN_ERR "%s: cannot allocate rx skbuff\n",
- wiphy_name(priv->hw->wiphy));
+ wiphy_err(priv->hw->wiphy,
+ "cannot allocate rx skbuff\n");
ret = -ENOMEM;
goto exit;
}
@@ -1260,15 +1257,14 @@ static int at76_submit_rx_urb(struct at76_priv *priv)
at76_dbg(DBG_DEVSTART,
"usb_submit_urb returned -ENODEV");
else
- printk(KERN_ERR "%s: rx, usb_submit_urb failed: %d\n",
- wiphy_name(priv->hw->wiphy), ret);
+ wiphy_err(priv->hw->wiphy,
+ "rx, usb_submit_urb failed: %d\n", ret);
}
exit:
if (ret < 0 && ret != -ENODEV)
- printk(KERN_ERR "%s: cannot submit rx urb - please unload the "
- "driver and/or power cycle the device\n",
- wiphy_name(priv->hw->wiphy));
+ wiphy_err(priv->hw->wiphy,
+ "cannot submit rx urb - please unload the driver and/or power cycle the device\n");
return ret;
}
@@ -1437,8 +1433,8 @@ static int at76_startup_device(struct at76_priv *priv)
ret = at76_set_card_command(priv->udev, CMD_STARTUP, &priv->card_config,
sizeof(struct at76_card_config));
if (ret < 0) {
- printk(KERN_ERR "%s: at76_set_card_command failed: %d\n",
- wiphy_name(priv->hw->wiphy), ret);
+ wiphy_err(priv->hw->wiphy, "at76_set_card_command failed: %d\n",
+ ret);
return ret;
}
@@ -1503,8 +1499,8 @@ static void at76_work_set_promisc(struct work_struct *work)
ret = at76_set_mib(priv, &priv->mib_buf);
if (ret < 0)
- printk(KERN_ERR "%s: set_mib (promiscuous_mode) failed: %d\n",
- wiphy_name(priv->hw->wiphy), ret);
+ wiphy_err(priv->hw->wiphy,
+ "set_mib (promiscuous_mode) failed: %d\n", ret);
mutex_unlock(&priv->mtx);
}
@@ -1649,6 +1645,58 @@ exit:
return NULL;
}
+static int at76_join(struct at76_priv *priv)
+{
+ struct at76_req_join join;
+ int ret;
+
+ memset(&join, 0, sizeof(struct at76_req_join));
+ memcpy(join.essid, priv->essid, priv->essid_size);
+ join.essid_size = priv->essid_size;
+ memcpy(join.bssid, priv->bssid, ETH_ALEN);
+ join.bss_type = INFRASTRUCTURE_MODE;
+ join.channel = priv->channel;
+ join.timeout = cpu_to_le16(2000);
+
+ at76_dbg(DBG_MAC80211, "%s: sending CMD_JOIN", __func__);
+ ret = at76_set_card_command(priv->udev, CMD_JOIN, &join,
+ sizeof(struct at76_req_join));
+
+ if (ret < 0) {
+ wiphy_err(priv->hw->wiphy, "at76_set_card_command failed: %d\n",
+ ret);
+ return 0;
+ }
+
+ ret = at76_wait_completion(priv, CMD_JOIN);
+ at76_dbg(DBG_MAC80211, "%s: CMD_JOIN returned: 0x%02x", __func__, ret);
+ if (ret != CMD_STATUS_COMPLETE) {
+ wiphy_err(priv->hw->wiphy, "at76_wait_completion failed: %d\n",
+ ret);
+ return 0;
+ }
+
+ at76_set_pm_mode(priv);
+
+ return 0;
+}
+
+static void at76_work_join_bssid(struct work_struct *work)
+{
+ struct at76_priv *priv = container_of(work, struct at76_priv,
+ work_join_bssid);
+
+ if (priv->device_unplugged)
+ return;
+
+ mutex_lock(&priv->mtx);
+
+ if (is_valid_ether_addr(priv->bssid))
+ at76_join(priv);
+
+ mutex_unlock(&priv->mtx);
+}
+
static void at76_mac80211_tx_callback(struct urb *urb)
{
struct at76_priv *priv = urb->context;
@@ -1686,16 +1734,32 @@ static int at76_mac80211_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
struct at76_priv *priv = hw->priv;
struct at76_tx_buffer *tx_buffer = priv->bulk_out_buffer;
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+ struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data;
int padding, submit_len, ret;
at76_dbg(DBG_MAC80211, "%s()", __func__);
if (priv->tx_urb->status == -EINPROGRESS) {
- printk(KERN_ERR "%s: %s called while tx urb is pending\n",
- wiphy_name(priv->hw->wiphy), __func__);
+ wiphy_err(priv->hw->wiphy,
+ "%s called while tx urb is pending\n", __func__);
return NETDEV_TX_BUSY;
}
+ /* The following code lines are important when the device is going to
+ * authenticate with a new bssid. The driver must send CMD_JOIN before
+ * an authentication frame is transmitted. For this to succeed, the
+ * correct bssid of the AP must be known. As mac80211 does not inform
+ * drivers about the bssid prior to the authentication process the
+ * following workaround is necessary. If the TX frame is an
+ * authentication frame extract the bssid and send the CMD_JOIN. */
+ if (mgmt->frame_control & cpu_to_le16(IEEE80211_STYPE_AUTH)) {
+ if (compare_ether_addr(priv->bssid, mgmt->bssid)) {
+ memcpy(priv->bssid, mgmt->bssid, ETH_ALEN);
+ ieee80211_queue_work(hw, &priv->work_join_bssid);
+ return NETDEV_TX_BUSY;
+ }
+ }
+
ieee80211_stop_queues(hw);
at76_ledtrig_tx_activity(); /* tell ledtrigger we send a packet */
@@ -1725,13 +1789,12 @@ static int at76_mac80211_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
submit_len, at76_mac80211_tx_callback, priv);
ret = usb_submit_urb(priv->tx_urb, GFP_ATOMIC);
if (ret) {
- printk(KERN_ERR "%s: error in tx submit urb: %d\n",
- wiphy_name(priv->hw->wiphy), ret);
+ wiphy_err(priv->hw->wiphy, "error in tx submit urb: %d\n", ret);
if (ret == -EINVAL)
- printk(KERN_ERR
- "%s: -EINVAL: tx urb %p hcpriv %p complete %p\n",
- wiphy_name(priv->hw->wiphy), priv->tx_urb,
- priv->tx_urb->hcpriv, priv->tx_urb->complete);
+ wiphy_err(priv->hw->wiphy,
+ "-einval: tx urb %p hcpriv %p complete %p\n",
+ priv->tx_urb,
+ priv->tx_urb->hcpriv, priv->tx_urb->complete);
}
return 0;
@@ -1748,8 +1811,8 @@ static int at76_mac80211_start(struct ieee80211_hw *hw)
ret = at76_submit_rx_urb(priv);
if (ret < 0) {
- printk(KERN_ERR "%s: open: submit_rx_urb failed: %d\n",
- wiphy_name(priv->hw->wiphy), ret);
+ wiphy_err(priv->hw->wiphy, "open: submit_rx_urb failed: %d\n",
+ ret);
goto error;
}
@@ -1770,6 +1833,7 @@ static void at76_mac80211_stop(struct ieee80211_hw *hw)
at76_dbg(DBG_MAC80211, "%s()", __func__);
cancel_delayed_work(&priv->dwork_hw_scan);
+ cancel_work_sync(&priv->work_join_bssid);
cancel_work_sync(&priv->work_set_promisc);
mutex_lock(&priv->mtx);
@@ -1818,42 +1882,6 @@ static void at76_remove_interface(struct ieee80211_hw *hw,
at76_dbg(DBG_MAC80211, "%s()", __func__);
}
-static int at76_join(struct at76_priv *priv)
-{
- struct at76_req_join join;
- int ret;
-
- memset(&join, 0, sizeof(struct at76_req_join));
- memcpy(join.essid, priv->essid, priv->essid_size);
- join.essid_size = priv->essid_size;
- memcpy(join.bssid, priv->bssid, ETH_ALEN);
- join.bss_type = INFRASTRUCTURE_MODE;
- join.channel = priv->channel;
- join.timeout = cpu_to_le16(2000);
-
- at76_dbg(DBG_MAC80211, "%s: sending CMD_JOIN", __func__);
- ret = at76_set_card_command(priv->udev, CMD_JOIN, &join,
- sizeof(struct at76_req_join));
-
- if (ret < 0) {
- printk(KERN_ERR "%s: at76_set_card_command failed: %d\n",
- wiphy_name(priv->hw->wiphy), ret);
- return 0;
- }
-
- ret = at76_wait_completion(priv, CMD_JOIN);
- at76_dbg(DBG_MAC80211, "%s: CMD_JOIN returned: 0x%02x", __func__, ret);
- if (ret != CMD_STATUS_COMPLETE) {
- printk(KERN_ERR "%s: at76_wait_completion failed: %d\n",
- wiphy_name(priv->hw->wiphy), ret);
- return 0;
- }
-
- at76_set_pm_mode(priv);
-
- return 0;
-}
-
static void at76_dwork_hw_scan(struct work_struct *work)
{
struct at76_priv *priv = container_of(work, struct at76_priv,
@@ -2107,6 +2135,7 @@ static struct at76_priv *at76_alloc_new_device(struct usb_device *udev)
mutex_init(&priv->mtx);
INIT_WORK(&priv->work_set_promisc, at76_work_set_promisc);
INIT_WORK(&priv->work_submit_rx, at76_work_submit_rx);
+ INIT_WORK(&priv->work_join_bssid, at76_work_join_bssid);
INIT_DELAYED_WORK(&priv->dwork_hw_scan, at76_dwork_hw_scan);
tasklet_init(&priv->rx_tasklet, at76_rx_tasklet, 0);
@@ -2281,14 +2310,12 @@ static int at76_init_new_device(struct at76_priv *priv,
priv->mac80211_registered = 1;
- printk(KERN_INFO "%s: USB %s, MAC %pM, firmware %d.%d.%d-%d\n",
- wiphy_name(priv->hw->wiphy),
- dev_name(&interface->dev), priv->mac_addr,
- priv->fw_version.major, priv->fw_version.minor,
- priv->fw_version.patch, priv->fw_version.build);
- printk(KERN_INFO "%s: regulatory domain 0x%02x: %s\n",
- wiphy_name(priv->hw->wiphy),
- priv->regulatory_domain, priv->domain->name);
+ wiphy_info(priv->hw->wiphy, "usb %s, mac %pm, firmware %d.%d.%d-%d\n",
+ dev_name(&interface->dev), priv->mac_addr,
+ priv->fw_version.major, priv->fw_version.minor,
+ priv->fw_version.patch, priv->fw_version.build);
+ wiphy_info(priv->hw->wiphy, "regulatory domain 0x%02x: %s\n",
+ priv->regulatory_domain, priv->domain->name);
exit:
return ret;
@@ -2450,7 +2477,7 @@ static void at76_disconnect(struct usb_interface *interface)
if (!priv)
return;
- printk(KERN_INFO "%s: disconnecting\n", wiphy_name(priv->hw->wiphy));
+ wiphy_info(priv->hw->wiphy, "disconnecting\n");
at76_delete_device(priv);
dev_printk(KERN_INFO, &interface->dev, "disconnected\n");
}
@@ -2508,5 +2535,6 @@ MODULE_AUTHOR("Balint Seeber <n0_5p4m_p13453@hotmail.com>");
MODULE_AUTHOR("Pavel Roskin <proski@gnu.org>");
MODULE_AUTHOR("Guido Guenther <agx@sigxcpu.org>");
MODULE_AUTHOR("Kalle Valo <kalle.valo@iki.fi>");
+MODULE_AUTHOR("Sebastian Smolorz <sesmo@gmx.net>");
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL");
diff --git a/drivers/net/wireless/at76c50x-usb.h b/drivers/net/wireless/at76c50x-usb.h
index 1ec5ccffdbc..4a37447dfc0 100644
--- a/drivers/net/wireless/at76c50x-usb.h
+++ b/drivers/net/wireless/at76c50x-usb.h
@@ -99,7 +99,7 @@ struct hwcfg_r505 {
u8 reserved2[14];
u8 cr15_values[14];
u8 reserved3[3];
-} __attribute__((packed));
+} __packed;
struct hwcfg_rfmd {
u8 cr20_values[14];
@@ -111,7 +111,7 @@ struct hwcfg_rfmd {
u8 low_power_values[14];
u8 normal_power_values[14];
u8 reserved1[3];
-} __attribute__((packed));
+} __packed;
struct hwcfg_intersil {
u8 mac_addr[ETH_ALEN];
@@ -120,7 +120,7 @@ struct hwcfg_intersil {
u8 pidvid[4];
u8 regulatory_domain;
u8 reserved[1];
-} __attribute__((packed));
+} __packed;
union at76_hwcfg {
struct hwcfg_intersil i;
@@ -149,14 +149,14 @@ struct at76_card_config {
u8 ssid_len;
u8 short_preamble;
__le16 beacon_period;
-} __attribute__((packed));
+} __packed;
struct at76_command {
u8 cmd;
u8 reserved;
__le16 size;
u8 data[0];
-} __attribute__((packed));
+} __packed;
/* Length of Atmel-specific Rx header before 802.11 frame */
#define AT76_RX_HDRLEN offsetof(struct at76_rx_buffer, packet)
@@ -171,7 +171,7 @@ struct at76_rx_buffer {
u8 noise_level;
__le32 rx_time;
u8 packet[IEEE80211_MAX_FRAG_THRESHOLD];
-} __attribute__((packed));
+} __packed;
/* Length of Atmel-specific Tx header before 802.11 frame */
#define AT76_TX_HDRLEN offsetof(struct at76_tx_buffer, packet)
@@ -182,7 +182,7 @@ struct at76_tx_buffer {
u8 padding;
u8 reserved[4];
u8 packet[IEEE80211_MAX_FRAG_THRESHOLD];
-} __attribute__((packed));
+} __packed;
/* defines for scan_type below */
#define SCAN_TYPE_ACTIVE 0
@@ -198,7 +198,7 @@ struct at76_req_scan {
__le16 max_channel_time;
u8 essid_size;
u8 international_scan;
-} __attribute__((packed));
+} __packed;
struct at76_req_ibss {
u8 bssid[ETH_ALEN];
@@ -207,7 +207,7 @@ struct at76_req_ibss {
u8 channel;
u8 essid_size;
u8 reserved[3];
-} __attribute__((packed));
+} __packed;
struct at76_req_join {
u8 bssid[ETH_ALEN];
@@ -217,7 +217,7 @@ struct at76_req_join {
__le16 timeout;
u8 essid_size;
u8 reserved;
-} __attribute__((packed));
+} __packed;
struct set_mib_buffer {
u8 type;
@@ -229,7 +229,7 @@ struct set_mib_buffer {
__le16 word;
u8 addr[ETH_ALEN];
} data;
-} __attribute__((packed));
+} __packed;
struct mib_local {
u16 reserved0;
@@ -241,14 +241,14 @@ struct mib_local {
u16 reserved2;
u8 preamble_type;
u16 reserved3;
-} __attribute__((packed));
+} __packed;
struct mib_mac_addr {
u8 mac_addr[ETH_ALEN];
u8 res[2]; /* ??? */
u8 group_addr[4][ETH_ALEN];
u8 group_addr_status[4];
-} __attribute__((packed));
+} __packed;
struct mib_mac {
__le32 max_tx_msdu_lifetime;
@@ -269,7 +269,7 @@ struct mib_mac {
u8 desired_bssid[ETH_ALEN];
u8 desired_bsstype; /* ad-hoc or infrastructure */
u8 reserved2;
-} __attribute__((packed));
+} __packed;
struct mib_mac_mgmt {
__le16 beacon_period;
@@ -292,7 +292,7 @@ struct mib_mac_mgmt {
u8 multi_domain_capability_enabled;
u8 country_string[3];
u8 reserved[3];
-} __attribute__((packed));
+} __packed;
struct mib_mac_wep {
u8 privacy_invoked; /* 0 disable encr., 1 enable encr */
@@ -303,7 +303,7 @@ struct mib_mac_wep {
__le32 wep_excluded_count;
u8 wep_default_keyvalue[WEP_KEYS][WEP_LARGE_KEY_LEN];
u8 encryption_level; /* 1 for 40bit, 2 for 104bit encryption */
-} __attribute__((packed));
+} __packed;
struct mib_phy {
__le32 ed_threshold;
@@ -320,19 +320,19 @@ struct mib_phy {
u8 current_cca_mode;
u8 phy_type;
u8 current_reg_domain;
-} __attribute__((packed));
+} __packed;
struct mib_fw_version {
u8 major;
u8 minor;
u8 patch;
u8 build;
-} __attribute__((packed));
+} __packed;
struct mib_mdomain {
u8 tx_powerlevel[14];
u8 channel_list[14]; /* 0 for invalid channels */
-} __attribute__((packed));
+} __packed;
struct at76_fw_header {
__le32 crc; /* CRC32 of the whole image */
@@ -346,7 +346,7 @@ struct at76_fw_header {
__le32 int_fw_len; /* internal firmware image length */
__le32 ext_fw_offset; /* external firmware image offset */
__le32 ext_fw_len; /* external firmware image length */
-} __attribute__((packed));
+} __packed;
/* a description of a regulatory domain and the allowed channels */
struct reg_domain {
@@ -387,6 +387,7 @@ struct at76_priv {
/* work queues */
struct work_struct work_set_promisc;
struct work_struct work_submit_rx;
+ struct work_struct work_join_bssid;
struct delayed_work dwork_hw_scan;
struct tasklet_struct rx_tasklet;
diff --git a/drivers/net/wireless/ath/ar9170/cmd.c b/drivers/net/wireless/ath/ar9170/cmd.c
index cf6f5c4174a..4604de09a8b 100644
--- a/drivers/net/wireless/ath/ar9170/cmd.c
+++ b/drivers/net/wireless/ath/ar9170/cmd.c
@@ -48,8 +48,7 @@ int ar9170_write_mem(struct ar9170 *ar, const __le32 *data, size_t len)
err = ar->exec_cmd(ar, AR9170_CMD_WMEM, len, (u8 *) data, 0, NULL);
if (err)
- printk(KERN_DEBUG "%s: writing memory failed\n",
- wiphy_name(ar->hw->wiphy));
+ wiphy_debug(ar->hw->wiphy, "writing memory failed\n");
return err;
}
@@ -67,8 +66,8 @@ int ar9170_write_reg(struct ar9170 *ar, const u32 reg, const u32 val)
err = ar->exec_cmd(ar, AR9170_CMD_WREG, sizeof(buf),
(u8 *) buf, 0, NULL);
if (err)
- printk(KERN_DEBUG "%s: writing reg %#x (val %#x) failed\n",
- wiphy_name(ar->hw->wiphy), reg, val);
+ wiphy_debug(ar->hw->wiphy, "writing reg %#x (val %#x) failed\n",
+ reg, val);
return err;
}
diff --git a/drivers/net/wireless/ath/ar9170/led.c b/drivers/net/wireless/ath/ar9170/led.c
index 86c4e79f6bc..832d90087f8 100644
--- a/drivers/net/wireless/ath/ar9170/led.c
+++ b/drivers/net/wireless/ath/ar9170/led.c
@@ -133,8 +133,8 @@ static int ar9170_register_led(struct ar9170 *ar, int i, char *name,
err = led_classdev_register(wiphy_dev(ar->hw->wiphy),
&ar->leds[i].l);
if (err)
- printk(KERN_ERR "%s: failed to register %s LED (%d).\n",
- wiphy_name(ar->hw->wiphy), ar->leds[i].name, err);
+ wiphy_err(ar->hw->wiphy, "failed to register %s LED (%d).\n",
+ ar->leds[i].name, err);
else
ar->leds[i].registered = true;
diff --git a/drivers/net/wireless/ath/ar9170/main.c b/drivers/net/wireless/ath/ar9170/main.c
index 2abc8757899..c67b05f3bcb 100644
--- a/drivers/net/wireless/ath/ar9170/main.c
+++ b/drivers/net/wireless/ath/ar9170/main.c
@@ -198,12 +198,13 @@ static void ar9170_print_txheader(struct ar9170 *ar, struct sk_buff *skb)
struct ar9170_tx_info *arinfo = (void *) txinfo->rate_driver_data;
struct ieee80211_hdr *hdr = (void *) txc->frame_data;
- printk(KERN_DEBUG "%s: => FRAME [skb:%p, q:%d, DA:[%pM] s:%d "
- "mac_ctrl:%04x, phy_ctrl:%08x, timeout:[%d ms]]\n",
- wiphy_name(ar->hw->wiphy), skb, skb_get_queue_mapping(skb),
- ieee80211_get_DA(hdr), ar9170_get_seq_h(hdr),
- le16_to_cpu(txc->mac_control), le32_to_cpu(txc->phy_control),
- jiffies_to_msecs(arinfo->timeout - jiffies));
+ wiphy_debug(ar->hw->wiphy,
+ "=> FRAME [skb:%p, q:%d, DA:[%pM] s:%d "
+ "mac_ctrl:%04x, phy_ctrl:%08x, timeout:[%d ms]]\n",
+ skb, skb_get_queue_mapping(skb),
+ ieee80211_get_DA(hdr), ar9170_get_seq_h(hdr),
+ le16_to_cpu(txc->mac_control), le32_to_cpu(txc->phy_control),
+ jiffies_to_msecs(arinfo->timeout - jiffies));
}
static void __ar9170_dump_txqueue(struct ar9170 *ar,
@@ -213,8 +214,8 @@ static void __ar9170_dump_txqueue(struct ar9170 *ar,
int i = 0;
printk(KERN_DEBUG "---[ cut here ]---\n");
- printk(KERN_DEBUG "%s: %d entries in queue.\n",
- wiphy_name(ar->hw->wiphy), skb_queue_len(queue));
+ wiphy_debug(ar->hw->wiphy, "%d entries in queue.\n",
+ skb_queue_len(queue));
skb_queue_walk(queue, skb) {
printk(KERN_DEBUG "index:%d =>\n", i++);
@@ -244,15 +245,14 @@ static void __ar9170_dump_txstats(struct ar9170 *ar)
{
int i;
- printk(KERN_DEBUG "%s: QoS queue stats\n",
- wiphy_name(ar->hw->wiphy));
+ wiphy_debug(ar->hw->wiphy, "qos queue stats\n");
for (i = 0; i < __AR9170_NUM_TXQ; i++)
- printk(KERN_DEBUG "%s: queue:%d limit:%d len:%d waitack:%d "
- " stopped:%d\n", wiphy_name(ar->hw->wiphy), i,
- ar->tx_stats[i].limit, ar->tx_stats[i].len,
- skb_queue_len(&ar->tx_status[i]),
- ieee80211_queue_stopped(ar->hw, i));
+ wiphy_debug(ar->hw->wiphy,
+ "queue:%d limit:%d len:%d waitack:%d stopped:%d\n",
+ i, ar->tx_stats[i].limit, ar->tx_stats[i].len,
+ skb_queue_len(&ar->tx_status[i]),
+ ieee80211_queue_stopped(ar->hw, i));
}
#endif /* AR9170_QUEUE_STOP_DEBUG */
@@ -274,9 +274,9 @@ static void ar9170_recycle_expired(struct ar9170 *ar,
if (time_is_before_jiffies(arinfo->timeout)) {
#ifdef AR9170_QUEUE_DEBUG
- printk(KERN_DEBUG "%s: [%ld > %ld] frame expired => "
- "recycle\n", wiphy_name(ar->hw->wiphy),
- jiffies, arinfo->timeout);
+ wiphy_debug(ar->hw->wiphy,
+ "[%ld > %ld] frame expired => recycle\n",
+ jiffies, arinfo->timeout);
ar9170_print_txheader(ar, skb);
#endif /* AR9170_QUEUE_DEBUG */
__skb_unlink(skb, queue);
@@ -317,8 +317,8 @@ static void ar9170_tx_status(struct ar9170 *ar, struct sk_buff *skb,
break;
default:
- printk(KERN_ERR "%s: invalid tx_status response (%x).\n",
- wiphy_name(ar->hw->wiphy), tx_status);
+ wiphy_err(ar->hw->wiphy,
+ "invalid tx_status response (%x)\n", tx_status);
break;
}
@@ -339,8 +339,7 @@ void ar9170_tx_callback(struct ar9170 *ar, struct sk_buff *skb)
if (ar->tx_stats[queue].len < AR9170_NUM_TX_LIMIT_SOFT) {
#ifdef AR9170_QUEUE_STOP_DEBUG
- printk(KERN_DEBUG "%s: wake queue %d\n",
- wiphy_name(ar->hw->wiphy), queue);
+ wiphy_debug(ar->hw->wiphy, "wake queue %d\n", queue);
__ar9170_dump_txstats(ar);
#endif /* AR9170_QUEUE_STOP_DEBUG */
ieee80211_wake_queue(ar->hw, queue);
@@ -387,9 +386,9 @@ static struct sk_buff *ar9170_get_queued_skb(struct ar9170 *ar,
if (mac && compare_ether_addr(ieee80211_get_DA(hdr), mac)) {
#ifdef AR9170_QUEUE_DEBUG
- printk(KERN_DEBUG "%s: skip frame => DA %pM != %pM\n",
- wiphy_name(ar->hw->wiphy), mac,
- ieee80211_get_DA(hdr));
+ wiphy_debug(ar->hw->wiphy,
+ "skip frame => da %pm != %pm\n",
+ mac, ieee80211_get_DA(hdr));
ar9170_print_txheader(ar, skb);
#endif /* AR9170_QUEUE_DEBUG */
continue;
@@ -400,8 +399,8 @@ static struct sk_buff *ar9170_get_queued_skb(struct ar9170 *ar,
if ((rate != AR9170_TX_INVALID_RATE) && (r != rate)) {
#ifdef AR9170_QUEUE_DEBUG
- printk(KERN_DEBUG "%s: skip frame => rate %d != %d\n",
- wiphy_name(ar->hw->wiphy), rate, r);
+ wiphy_debug(ar->hw->wiphy,
+ "skip frame => rate %d != %d\n", rate, r);
ar9170_print_txheader(ar, skb);
#endif /* AR9170_QUEUE_DEBUG */
continue;
@@ -413,9 +412,9 @@ static struct sk_buff *ar9170_get_queued_skb(struct ar9170 *ar,
}
#ifdef AR9170_QUEUE_DEBUG
- printk(KERN_ERR "%s: ESS:[%pM] does not have any "
- "outstanding frames in queue.\n",
- wiphy_name(ar->hw->wiphy), mac);
+ wiphy_err(ar->hw->wiphy,
+ "ESS:[%pM] does not have any outstanding frames in queue.\n",
+ mac);
__ar9170_dump_txqueue(ar, queue);
#endif /* AR9170_QUEUE_DEBUG */
spin_unlock_irqrestore(&queue->lock, flags);
@@ -444,8 +443,8 @@ static void ar9170_tx_janitor(struct work_struct *work)
for (i = 0; i < __AR9170_NUM_TXQ; i++) {
#ifdef AR9170_QUEUE_DEBUG
- printk(KERN_DEBUG "%s: garbage collector scans queue:%d\n",
- wiphy_name(ar->hw->wiphy), i);
+ wiphy_debug(ar->hw->wiphy, "garbage collector scans queue:%d\n",
+ i);
ar9170_dump_txqueue(ar, &ar->tx_pending[i]);
ar9170_dump_txqueue(ar, &ar->tx_status[i]);
#endif /* AR9170_QUEUE_DEBUG */
@@ -495,8 +494,9 @@ void ar9170_handle_command_response(struct ar9170 *ar, void *buf, u32 len)
u32 q = (phy & AR9170_TX_PHY_QOS_MASK) >>
AR9170_TX_PHY_QOS_SHIFT;
#ifdef AR9170_QUEUE_DEBUG
- printk(KERN_DEBUG "%s: recv tx_status for %pM, p:%08x, q:%d\n",
- wiphy_name(ar->hw->wiphy), cmd->tx_status.dst, phy, q);
+ wiphy_debug(ar->hw->wiphy,
+ "recv tx_status for %pm, p:%08x, q:%d\n",
+ cmd->tx_status.dst, phy, q);
#endif /* AR9170_QUEUE_DEBUG */
skb = ar9170_get_queued_skb(ar, cmd->tx_status.dst,
@@ -582,7 +582,7 @@ void ar9170_handle_command_response(struct ar9170 *ar, void *buf, u32 len)
break;
default:
- printk(KERN_INFO "received unhandled event %x\n", cmd->type);
+ pr_info("received unhandled event %x\n", cmd->type);
print_hex_dump_bytes("dump:", DUMP_PREFIX_NONE, buf, len);
break;
}
@@ -675,9 +675,9 @@ static int ar9170_rx_mac_status(struct ar9170 *ar,
/* TODO: update netdevice's RX dropped/errors statistics */
if (ar9170_nag_limiter(ar))
- printk(KERN_DEBUG "%s: received frame with "
- "suspicious error code (%#x).\n",
- wiphy_name(ar->hw->wiphy), error);
+ wiphy_debug(ar->hw->wiphy,
+ "received frame with suspicious error code (%#x).\n",
+ error);
return -EINVAL;
}
@@ -704,9 +704,9 @@ static int ar9170_rx_mac_status(struct ar9170 *ar,
break;
default:
if (ar9170_nag_limiter(ar))
- printk(KERN_ERR "%s: invalid plcp cck rate "
- "(%x).\n", wiphy_name(ar->hw->wiphy),
- head->plcp[0]);
+ wiphy_err(ar->hw->wiphy,
+ "invalid plcp cck rate (%x).\n",
+ head->plcp[0]);
return -EINVAL;
}
break;
@@ -740,9 +740,9 @@ static int ar9170_rx_mac_status(struct ar9170 *ar,
break;
default:
if (ar9170_nag_limiter(ar))
- printk(KERN_ERR "%s: invalid plcp ofdm rate "
- "(%x).\n", wiphy_name(ar->hw->wiphy),
- head->plcp[0]);
+ wiphy_err(ar->hw->wiphy,
+ "invalid plcp ofdm rate (%x).\n",
+ head->plcp[0]);
return -EINVAL;
}
if (status->band == IEEE80211_BAND_2GHZ)
@@ -761,8 +761,7 @@ static int ar9170_rx_mac_status(struct ar9170 *ar,
default:
if (ar9170_nag_limiter(ar))
- printk(KERN_ERR "%s: invalid modulation\n",
- wiphy_name(ar->hw->wiphy));
+ wiphy_err(ar->hw->wiphy, "invalid modulation\n");
return -EINVAL;
}
@@ -863,8 +862,8 @@ static void ar9170_handle_mpdu(struct ar9170 *ar, u8 *buf, int len)
ar->rx_mpdu.has_plcp = true;
} else {
if (ar9170_nag_limiter(ar))
- printk(KERN_ERR "%s: plcp info is clipped.\n",
- wiphy_name(ar->hw->wiphy));
+ wiphy_err(ar->hw->wiphy,
+ "plcp info is clipped.\n");
return ;
}
break;
@@ -877,8 +876,8 @@ static void ar9170_handle_mpdu(struct ar9170 *ar, u8 *buf, int len)
phy = (void *)(buf + mpdu_len);
} else {
if (ar9170_nag_limiter(ar))
- printk(KERN_ERR "%s: frame tail is clipped.\n",
- wiphy_name(ar->hw->wiphy));
+ wiphy_err(ar->hw->wiphy,
+ "frame tail is clipped.\n");
return ;
}
@@ -888,9 +887,8 @@ static void ar9170_handle_mpdu(struct ar9170 *ar, u8 *buf, int len)
if (!ar9170_nag_limiter(ar))
return ;
- printk(KERN_ERR "%s: rx stream did not start "
- "with a first_mpdu frame tag.\n",
- wiphy_name(ar->hw->wiphy));
+ wiphy_err(ar->hw->wiphy,
+ "rx stream did not start with a first_mpdu frame tag.\n");
return ;
}
@@ -954,8 +952,8 @@ void ar9170_rx(struct ar9170 *ar, struct sk_buff *skb)
if (!ar->rx_failover_missing) {
/* this is no "short read". */
if (ar9170_nag_limiter(ar)) {
- printk(KERN_ERR "%s: missing tag!\n",
- wiphy_name(ar->hw->wiphy));
+ wiphy_err(ar->hw->wiphy,
+ "missing tag!\n");
goto err_telluser;
} else
goto err_silent;
@@ -963,9 +961,8 @@ void ar9170_rx(struct ar9170 *ar, struct sk_buff *skb)
if (ar->rx_failover_missing > tlen) {
if (ar9170_nag_limiter(ar)) {
- printk(KERN_ERR "%s: possible multi "
- "stream corruption!\n",
- wiphy_name(ar->hw->wiphy));
+ wiphy_err(ar->hw->wiphy,
+ "possible multi stream corruption!\n");
goto err_telluser;
} else
goto err_silent;
@@ -997,9 +994,8 @@ void ar9170_rx(struct ar9170 *ar, struct sk_buff *skb)
if (ar->rx_failover_missing) {
/* TODO: handle double stream corruption. */
if (ar9170_nag_limiter(ar)) {
- printk(KERN_ERR "%s: double rx stream "
- "corruption!\n",
- wiphy_name(ar->hw->wiphy));
+ wiphy_err(ar->hw->wiphy,
+ "double rx stream corruption!\n");
goto err_telluser;
} else
goto err_silent;
@@ -1042,9 +1038,9 @@ void ar9170_rx(struct ar9170 *ar, struct sk_buff *skb)
if (tlen) {
if (net_ratelimit())
- printk(KERN_ERR "%s: %d bytes of unprocessed "
- "data left in rx stream!\n",
- wiphy_name(ar->hw->wiphy), tlen);
+ wiphy_err(ar->hw->wiphy,
+ "%d bytes of unprocessed data left in rx stream!\n",
+ tlen);
goto err_telluser;
}
@@ -1052,10 +1048,9 @@ void ar9170_rx(struct ar9170 *ar, struct sk_buff *skb)
return ;
err_telluser:
- printk(KERN_ERR "%s: damaged RX stream data [want:%d, "
- "data:%d, rx:%d, pending:%d ]\n",
- wiphy_name(ar->hw->wiphy), clen, wlen, tlen,
- ar->rx_failover_missing);
+ wiphy_err(ar->hw->wiphy,
+ "damaged RX stream data [want:%d, data:%d, rx:%d, pending:%d ]\n",
+ clen, wlen, tlen, ar->rx_failover_missing);
if (ar->rx_failover_missing)
print_hex_dump_bytes("rxbuf:", DUMP_PREFIX_OFFSET,
@@ -1065,9 +1060,8 @@ err_telluser:
print_hex_dump_bytes("stream:", DUMP_PREFIX_OFFSET,
skb->data, skb->len);
- printk(KERN_ERR "%s: please check your hardware and cables, if "
- "you see this message frequently.\n",
- wiphy_name(ar->hw->wiphy));
+ wiphy_err(ar->hw->wiphy,
+ "If you see this message frequently, please check your hardware and cables.\n");
err_silent:
if (ar->rx_failover_missing) {
@@ -1384,10 +1378,10 @@ static void ar9170_tx(struct ar9170 *ar)
if (remaining_space < frames) {
#ifdef AR9170_QUEUE_DEBUG
- printk(KERN_DEBUG "%s: tx quota reached queue:%d, "
- "remaining slots:%d, needed:%d\n",
- wiphy_name(ar->hw->wiphy), i, remaining_space,
- frames);
+ wiphy_debug(ar->hw->wiphy,
+ "tx quota reached queue:%d, "
+ "remaining slots:%d, needed:%d\n",
+ i, remaining_space, frames);
#endif /* AR9170_QUEUE_DEBUG */
frames = remaining_space;
}
@@ -1396,18 +1390,14 @@ static void ar9170_tx(struct ar9170 *ar)
ar->tx_stats[i].count += frames;
if (ar->tx_stats[i].len >= ar->tx_stats[i].limit) {
#ifdef AR9170_QUEUE_DEBUG
- printk(KERN_DEBUG "%s: queue %d full\n",
- wiphy_name(ar->hw->wiphy), i);
-
- printk(KERN_DEBUG "%s: stuck frames: ===>\n",
- wiphy_name(ar->hw->wiphy));
+ wiphy_debug(ar->hw->wiphy, "queue %d full\n", i);
+ wiphy_debug(ar->hw->wiphy, "stuck frames: ===>\n");
ar9170_dump_txqueue(ar, &ar->tx_pending[i]);
ar9170_dump_txqueue(ar, &ar->tx_status[i]);
#endif /* AR9170_QUEUE_DEBUG */
#ifdef AR9170_QUEUE_STOP_DEBUG
- printk(KERN_DEBUG "%s: stop queue %d\n",
- wiphy_name(ar->hw->wiphy), i);
+ wiphy_debug(ar->hw->wiphy, "stop queue %d\n", i);
__ar9170_dump_txstats(ar);
#endif /* AR9170_QUEUE_STOP_DEBUG */
ieee80211_stop_queue(ar->hw, i);
@@ -1435,8 +1425,7 @@ static void ar9170_tx(struct ar9170 *ar)
msecs_to_jiffies(AR9170_TX_TIMEOUT);
#ifdef AR9170_QUEUE_DEBUG
- printk(KERN_DEBUG "%s: send frame q:%d =>\n",
- wiphy_name(ar->hw->wiphy), i);
+ wiphy_debug(ar->hw->wiphy, "send frame q:%d =>\n", i);
ar9170_print_txheader(ar, skb);
#endif /* AR9170_QUEUE_DEBUG */
@@ -1453,26 +1442,25 @@ static void ar9170_tx(struct ar9170 *ar)
}
#ifdef AR9170_QUEUE_DEBUG
- printk(KERN_DEBUG "%s: ar9170_tx report for queue %d\n",
- wiphy_name(ar->hw->wiphy), i);
+ wiphy_debug(ar->hw->wiphy,
+ "ar9170_tx report for queue %d\n", i);
- printk(KERN_DEBUG "%s: unprocessed pending frames left:\n",
- wiphy_name(ar->hw->wiphy));
+ wiphy_debug(ar->hw->wiphy,
+ "unprocessed pending frames left:\n");
ar9170_dump_txqueue(ar, &ar->tx_pending[i]);
#endif /* AR9170_QUEUE_DEBUG */
if (unlikely(frames_failed)) {
#ifdef AR9170_QUEUE_DEBUG
- printk(KERN_DEBUG "%s: frames failed %d =>\n",
- wiphy_name(ar->hw->wiphy), frames_failed);
+ wiphy_debug(ar->hw->wiphy,
+ "frames failed %d =>\n", frames_failed);
#endif /* AR9170_QUEUE_DEBUG */
spin_lock_irqsave(&ar->tx_stats_lock, flags);
ar->tx_stats[i].len -= frames_failed;
ar->tx_stats[i].count -= frames_failed;
#ifdef AR9170_QUEUE_STOP_DEBUG
- printk(KERN_DEBUG "%s: wake queue %d\n",
- wiphy_name(ar->hw->wiphy), i);
+ wiphy_debug(ar->hw->wiphy, "wake queue %d\n", i);
__ar9170_dump_txstats(ar);
#endif /* AR9170_QUEUE_STOP_DEBUG */
ieee80211_wake_queue(ar->hw, i);
@@ -1917,6 +1905,24 @@ static int ar9170_get_stats(struct ieee80211_hw *hw,
return 0;
}
+static int ar9170_get_survey(struct ieee80211_hw *hw, int idx,
+ struct survey_info *survey)
+{
+ struct ar9170 *ar = hw->priv;
+ struct ieee80211_conf *conf = &hw->conf;
+
+ if (idx != 0)
+ return -ENOENT;
+
+ /* TODO: update noise value, e.g. call ar9170_set_channel */
+
+ survey->channel = conf->channel;
+ survey->filled = SURVEY_INFO_NOISE_DBM;
+ survey->noise = ar->noise[0];
+
+ return 0;
+}
+
static int ar9170_conf_tx(struct ieee80211_hw *hw, u16 queue,
const struct ieee80211_tx_queue_params *param)
{
@@ -1969,6 +1975,7 @@ static const struct ieee80211_ops ar9170_ops = {
.get_tsf = ar9170_op_get_tsf,
.set_key = ar9170_set_key,
.get_stats = ar9170_get_stats,
+ .get_survey = ar9170_get_survey,
.ampdu_action = ar9170_ampdu_action,
};
diff --git a/drivers/net/wireless/ath/ar9170/phy.c b/drivers/net/wireless/ath/ar9170/phy.c
index 45a415ea809..0dbfcf79ac9 100644
--- a/drivers/net/wireless/ath/ar9170/phy.c
+++ b/drivers/net/wireless/ath/ar9170/phy.c
@@ -670,8 +670,7 @@ static int ar9170_init_rf_banks_0_7(struct ar9170 *ar, bool band5ghz)
ar9170_regwrite_finish();
err = ar9170_regwrite_result();
if (err)
- printk(KERN_ERR "%s: rf init failed\n",
- wiphy_name(ar->hw->wiphy));
+ wiphy_err(ar->hw->wiphy, "rf init failed\n");
return err;
}
@@ -1702,9 +1701,8 @@ int ar9170_set_channel(struct ar9170 *ar, struct ieee80211_channel *channel,
0x200 | ar->phy_heavy_clip);
if (err) {
if (ar9170_nag_limiter(ar))
- printk(KERN_ERR "%s: failed to set "
- "heavy clip\n",
- wiphy_name(ar->hw->wiphy));
+ wiphy_err(ar->hw->wiphy,
+ "failed to set heavy clip\n");
}
}
diff --git a/drivers/net/wireless/ath/ath5k/Makefile b/drivers/net/wireless/ath/ath5k/Makefile
index cc09595b781..2242a140e4f 100644
--- a/drivers/net/wireless/ath/ath5k/Makefile
+++ b/drivers/net/wireless/ath/ath5k/Makefile
@@ -13,5 +13,6 @@ ath5k-y += base.o
ath5k-y += led.o
ath5k-y += rfkill.o
ath5k-y += ani.o
+ath5k-y += sysfs.o
ath5k-$(CONFIG_ATH5K_DEBUG) += debug.o
obj-$(CONFIG_ATH5K) += ath5k.o
diff --git a/drivers/net/wireless/ath/ath5k/ani.c b/drivers/net/wireless/ath/ath5k/ani.c
index f2311ab3550..26dbe65fedb 100644
--- a/drivers/net/wireless/ath/ath5k/ani.c
+++ b/drivers/net/wireless/ath/ath5k/ani.c
@@ -74,8 +74,8 @@ ath5k_ani_set_noise_immunity_level(struct ath5k_hw *ah, int level)
const s8 fr[] = { -78, -80 };
#endif
if (level < 0 || level >= ARRAY_SIZE(sz)) {
- ATH5K_DBG_UNLIMIT(ah->ah_sc, ATH5K_DEBUG_ANI,
- "level out of range %d", level);
+ ATH5K_ERR(ah->ah_sc, "noise immuniy level %d out of range",
+ level);
return;
}
@@ -106,8 +106,8 @@ ath5k_ani_set_spur_immunity_level(struct ath5k_hw *ah, int level)
if (level < 0 || level >= ARRAY_SIZE(val) ||
level > ah->ah_sc->ani_state.max_spur_level) {
- ATH5K_DBG_UNLIMIT(ah->ah_sc, ATH5K_DEBUG_ANI,
- "level out of range %d", level);
+ ATH5K_ERR(ah->ah_sc, "spur immunity level %d out of range",
+ level);
return;
}
@@ -130,8 +130,7 @@ ath5k_ani_set_firstep_level(struct ath5k_hw *ah, int level)
const int val[] = { 0, 4, 8 };
if (level < 0 || level >= ARRAY_SIZE(val)) {
- ATH5K_DBG_UNLIMIT(ah->ah_sc, ATH5K_DEBUG_ANI,
- "level out of range %d", level);
+ ATH5K_ERR(ah->ah_sc, "firstep level %d out of range", level);
return;
}
@@ -481,14 +480,15 @@ ath5k_ani_calibration(struct ath5k_hw *ah)
struct ath5k_ani_state *as = &ah->ah_sc->ani_state;
int listen, ofdm_high, ofdm_low, cck_high, cck_low;
- if (as->ani_mode != ATH5K_ANI_MODE_AUTO)
- return;
-
/* get listen time since last call and add it to the counter because we
- * might not have restarted the "ani period" last time */
+ * might not have restarted the "ani period" last time.
+ * always do this to calculate the busy time also in manual mode */
listen = ath5k_hw_ani_get_listen_time(ah, as);
as->listen_time += listen;
+ if (as->ani_mode != ATH5K_ANI_MODE_AUTO)
+ return;
+
ath5k_ani_save_and_clear_phy_errors(ah, as);
ofdm_high = as->listen_time * ATH5K_ANI_OFDM_TRIG_HIGH / 1000;
diff --git a/drivers/net/wireless/ath/ath5k/ath5k.h b/drivers/net/wireless/ath/ath5k/ath5k.h
index 2785946f659..ea6362a8988 100644
--- a/drivers/net/wireless/ath/ath5k/ath5k.h
+++ b/drivers/net/wireless/ath/ath5k/ath5k.h
@@ -204,6 +204,7 @@
#define AR5K_TUNE_TPC_TXPOWER false
#define ATH5K_TUNE_CALIBRATION_INTERVAL_FULL 10000 /* 10 sec */
#define ATH5K_TUNE_CALIBRATION_INTERVAL_ANI 1000 /* 1 sec */
+#define ATH5K_TUNE_CALIBRATION_INTERVAL_NF 60000 /* 60 sec */
#define AR5K_INIT_CARR_SENSE_EN 1
@@ -565,7 +566,7 @@ enum ath5k_pkt_type {
)
/*
- * DMA size definitions (2^n+2)
+ * DMA size definitions (2^(n+2))
*/
enum ath5k_dmasize {
AR5K_DMASIZE_4B = 0,
@@ -1118,6 +1119,7 @@ struct ath5k_hw {
/* Calibration timestamp */
unsigned long ah_cal_next_full;
unsigned long ah_cal_next_ani;
+ unsigned long ah_cal_next_nf;
/* Calibration mask */
u8 ah_cal_mask;
@@ -1125,15 +1127,10 @@ struct ath5k_hw {
/*
* Function pointers
*/
- int (*ah_setup_rx_desc)(struct ath5k_hw *ah, struct ath5k_desc *desc,
- u32 size, unsigned int flags);
int (*ah_setup_tx_desc)(struct ath5k_hw *, struct ath5k_desc *,
unsigned int, unsigned int, int, enum ath5k_pkt_type,
unsigned int, unsigned int, unsigned int, unsigned int,
unsigned int, unsigned int, unsigned int, unsigned int);
- int (*ah_setup_mrr_tx_desc)(struct ath5k_hw *, struct ath5k_desc *,
- unsigned int, unsigned int, unsigned int, unsigned int,
- unsigned int, unsigned int);
int (*ah_proc_tx_desc)(struct ath5k_hw *, struct ath5k_desc *,
struct ath5k_tx_status *);
int (*ah_proc_rx_desc)(struct ath5k_hw *, struct ath5k_desc *,
@@ -1148,6 +1145,9 @@ struct ath5k_hw {
int ath5k_hw_attach(struct ath5k_softc *sc);
void ath5k_hw_detach(struct ath5k_hw *ah);
+int ath5k_sysfs_register(struct ath5k_softc *sc);
+void ath5k_sysfs_unregister(struct ath5k_softc *sc);
+
/* LED functions */
int ath5k_init_leds(struct ath5k_softc *sc);
void ath5k_led_enable(struct ath5k_softc *sc);
@@ -1231,6 +1231,11 @@ int ath5k_hw_set_slot_time(struct ath5k_hw *ah, unsigned int slot_time);
/* Hardware Descriptor Functions */
int ath5k_hw_init_desc_functions(struct ath5k_hw *ah);
+int ath5k_hw_setup_rx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc,
+ u32 size, unsigned int flags);
+int ath5k_hw_setup_mrr_tx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc,
+ unsigned int tx_rate1, u_int tx_tries1, u_int tx_rate2,
+ u_int tx_tries2, unsigned int tx_rate3, u_int tx_tries3);
/* GPIO Functions */
void ath5k_hw_set_ledstate(struct ath5k_hw *ah, unsigned int state);
@@ -1270,6 +1275,7 @@ int ath5k_hw_channel(struct ath5k_hw *ah, struct ieee80211_channel *channel);
void ath5k_hw_init_nfcal_hist(struct ath5k_hw *ah);
int ath5k_hw_phy_calibrate(struct ath5k_hw *ah,
struct ieee80211_channel *channel);
+void ath5k_hw_update_noise_floor(struct ath5k_hw *ah);
/* Spur mitigation */
bool ath5k_hw_chan_has_spur_noise(struct ath5k_hw *ah,
struct ieee80211_channel *channel);
@@ -1280,6 +1286,7 @@ u16 ath5k_hw_radio_revision(struct ath5k_hw *ah, unsigned int chan);
int ath5k_hw_phy_disable(struct ath5k_hw *ah);
/* Antenna control */
void ath5k_hw_set_antenna_mode(struct ath5k_hw *ah, u8 ant_mode);
+void ath5k_hw_set_antenna_switch(struct ath5k_hw *ah, u8 ee_mode);
/* TX power setup */
int ath5k_hw_txpower(struct ath5k_hw *ah, struct ieee80211_channel *channel,
u8 ee_mode, u8 txpower);
diff --git a/drivers/net/wireless/ath/ath5k/attach.c b/drivers/net/wireless/ath/ath5k/attach.c
index 31c008042bf..b32e28caeee 100644
--- a/drivers/net/wireless/ath/ath5k/attach.c
+++ b/drivers/net/wireless/ath/ath5k/attach.c
@@ -352,8 +352,6 @@ err_free:
*/
void ath5k_hw_detach(struct ath5k_hw *ah)
{
- ATH5K_TRACE(ah->ah_sc);
-
__set_bit(ATH_STAT_INVALID, ah->ah_sc->status);
if (ah->ah_rf_banks != NULL)
diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c
index 648972df369..0d5de2574dd 100644
--- a/drivers/net/wireless/ath/ath5k/base.c
+++ b/drivers/net/wireless/ath/ath5k/base.c
@@ -311,7 +311,8 @@ static int ath5k_rxbuf_setup(struct ath5k_softc *sc,
static int ath5k_txbuf_setup(struct ath5k_softc *sc,
struct ath5k_buf *bf,
struct ath5k_txq *txq, int padsize);
-static inline void ath5k_txbuf_free(struct ath5k_softc *sc,
+
+static inline void ath5k_txbuf_free_skb(struct ath5k_softc *sc,
struct ath5k_buf *bf)
{
BUG_ON(!bf);
@@ -321,9 +322,11 @@ static inline void ath5k_txbuf_free(struct ath5k_softc *sc,
PCI_DMA_TODEVICE);
dev_kfree_skb_any(bf->skb);
bf->skb = NULL;
+ bf->skbaddr = 0;
+ bf->desc->ds_data = 0;
}
-static inline void ath5k_rxbuf_free(struct ath5k_softc *sc,
+static inline void ath5k_rxbuf_free_skb(struct ath5k_softc *sc,
struct ath5k_buf *bf)
{
struct ath5k_hw *ah = sc->ah;
@@ -336,6 +339,8 @@ static inline void ath5k_rxbuf_free(struct ath5k_softc *sc,
PCI_DMA_FROMDEVICE);
dev_kfree_skb_any(bf->skb);
bf->skb = NULL;
+ bf->skbaddr = 0;
+ bf->desc->ds_data = 0;
}
@@ -352,7 +357,6 @@ static void ath5k_txq_release(struct ath5k_softc *sc);
static int ath5k_rx_start(struct ath5k_softc *sc);
static void ath5k_rx_stop(struct ath5k_softc *sc);
static unsigned int ath5k_rx_decrypted(struct ath5k_softc *sc,
- struct ath5k_desc *ds,
struct sk_buff *skb,
struct ath5k_rx_status *rs);
static void ath5k_tasklet_rx(unsigned long data);
@@ -384,7 +388,7 @@ static int ath5k_init(struct ath5k_softc *sc);
static int ath5k_stop_locked(struct ath5k_softc *sc);
static int ath5k_stop_hw(struct ath5k_softc *sc);
static irqreturn_t ath5k_intr(int irq, void *dev_id);
-static void ath5k_tasklet_reset(unsigned long data);
+static void ath5k_reset_work(struct work_struct *work);
static void ath5k_tasklet_calibrate(unsigned long data);
@@ -578,7 +582,7 @@ ath5k_pci_probe(struct pci_dev *pdev,
spin_lock_init(&sc->block);
/* Set private data */
- pci_set_drvdata(pdev, hw);
+ pci_set_drvdata(pdev, sc);
/* Setup interrupt handler */
ret = request_irq(pdev->irq, ath5k_intr, IRQF_SHARED, "ath", sc);
@@ -694,25 +698,23 @@ err:
static void __devexit
ath5k_pci_remove(struct pci_dev *pdev)
{
- struct ieee80211_hw *hw = pci_get_drvdata(pdev);
- struct ath5k_softc *sc = hw->priv;
+ struct ath5k_softc *sc = pci_get_drvdata(pdev);
ath5k_debug_finish_device(sc);
- ath5k_detach(pdev, hw);
+ ath5k_detach(pdev, sc->hw);
ath5k_hw_detach(sc->ah);
kfree(sc->ah);
free_irq(pdev->irq, sc);
pci_iounmap(pdev, sc->iobase);
pci_release_region(pdev, 0);
pci_disable_device(pdev);
- ieee80211_free_hw(hw);
+ ieee80211_free_hw(sc->hw);
}
#ifdef CONFIG_PM_SLEEP
static int ath5k_pci_suspend(struct device *dev)
{
- struct ieee80211_hw *hw = pci_get_drvdata(to_pci_dev(dev));
- struct ath5k_softc *sc = hw->priv;
+ struct ath5k_softc *sc = pci_get_drvdata(to_pci_dev(dev));
ath5k_led_off(sc);
return 0;
@@ -721,8 +723,7 @@ static int ath5k_pci_suspend(struct device *dev)
static int ath5k_pci_resume(struct device *dev)
{
struct pci_dev *pdev = to_pci_dev(dev);
- struct ieee80211_hw *hw = pci_get_drvdata(pdev);
- struct ath5k_softc *sc = hw->priv;
+ struct ath5k_softc *sc = pci_get_drvdata(pdev);
/*
* Suspend/Resume resets the PCI configuration space, so we have to
@@ -768,7 +769,8 @@ ath5k_attach(struct pci_dev *pdev, struct ieee80211_hw *hw)
* return false w/o doing anything. MAC's that do
* support it will return true w/o doing anything.
*/
- ret = ah->ah_setup_mrr_tx_desc(ah, NULL, 0, 0, 0, 0, 0, 0);
+ ret = ath5k_hw_setup_mrr_tx_desc(ah, NULL, 0, 0, 0, 0, 0, 0);
+
if (ret < 0)
goto err;
if (ret > 0)
@@ -829,11 +831,12 @@ ath5k_attach(struct pci_dev *pdev, struct ieee80211_hw *hw)
tasklet_init(&sc->rxtq, ath5k_tasklet_rx, (unsigned long)sc);
tasklet_init(&sc->txtq, ath5k_tasklet_tx, (unsigned long)sc);
- tasklet_init(&sc->restq, ath5k_tasklet_reset, (unsigned long)sc);
tasklet_init(&sc->calib, ath5k_tasklet_calibrate, (unsigned long)sc);
tasklet_init(&sc->beacontq, ath5k_tasklet_beacon, (unsigned long)sc);
tasklet_init(&sc->ani_tasklet, ath5k_tasklet_ani, (unsigned long)sc);
+ INIT_WORK(&sc->reset_work, ath5k_reset_work);
+
ret = ath5k_eeprom_read_mac(ah, mac);
if (ret) {
ATH5K_ERR(sc, "unable to read address from EEPROM: 0x%04x\n",
@@ -864,6 +867,8 @@ ath5k_attach(struct pci_dev *pdev, struct ieee80211_hw *hw)
ath5k_init_leds(sc);
+ ath5k_sysfs_register(sc);
+
return 0;
err_queues:
ath5k_txq_release(sc);
@@ -899,6 +904,7 @@ ath5k_detach(struct pci_dev *pdev, struct ieee80211_hw *hw)
ath5k_hw_release_tx_queue(sc->ah, sc->bhalq);
ath5k_unregister_leds(sc);
+ ath5k_sysfs_unregister(sc);
/*
* NB: can't reclaim these until after ieee80211_ifdetach
* returns because we'll get called back to reclaim node
@@ -1111,8 +1117,9 @@ ath5k_setup_bands(struct ieee80211_hw *hw)
static int
ath5k_chan_set(struct ath5k_softc *sc, struct ieee80211_channel *chan)
{
- ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "(%u MHz) -> (%u MHz)\n",
- sc->curchan->center_freq, chan->center_freq);
+ ATH5K_DBG(sc, ATH5K_DEBUG_RESET,
+ "channel set, resetting (%u -> %u MHz)\n",
+ sc->curchan->center_freq, chan->center_freq);
/*
* To switch channels clear any pending DMA operations;
@@ -1228,21 +1235,23 @@ ath5k_rxbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf)
* not get overrun under high load (as can happen with a
* 5212 when ANI processing enables PHY error frames).
*
- * To insure the last descriptor is self-linked we create
+ * To ensure the last descriptor is self-linked we create
* each descriptor as self-linked and add it to the end. As
* each additional descriptor is added the previous self-linked
- * entry is ``fixed'' naturally. This should be safe even
+ * entry is "fixed" naturally. This should be safe even
* if DMA is happening. When processing RX interrupts we
* never remove/process the last, self-linked, entry on the
- * descriptor list. This insures the hardware always has
+ * descriptor list. This ensures the hardware always has
* someplace to write a new frame.
*/
ds = bf->desc;
ds->ds_link = bf->daddr; /* link to self */
ds->ds_data = bf->skbaddr;
- ret = ah->ah_setup_rx_desc(ah, ds, ah->common.rx_bufsize, 0);
- if (ret)
+ ret = ath5k_hw_setup_rx_desc(ah, ds, ah->common.rx_bufsize, 0);
+ if (ret) {
+ ATH5K_ERR(sc, "%s: could not setup RX desc\n", __func__);
return ret;
+ }
if (sc->rxlink != NULL)
*sc->rxlink = bf->daddr;
@@ -1347,7 +1356,7 @@ ath5k_txbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf,
mrr_tries[i] = info->control.rates[i + 1].count;
}
- ah->ah_setup_mrr_tx_desc(ah, ds,
+ ath5k_hw_setup_mrr_tx_desc(ah, ds,
mrr_rate[0], mrr_tries[0],
mrr_rate[1], mrr_tries[1],
mrr_rate[2], mrr_tries[2]);
@@ -1443,17 +1452,20 @@ ath5k_desc_free(struct ath5k_softc *sc, struct pci_dev *pdev)
{
struct ath5k_buf *bf;
- ath5k_txbuf_free(sc, sc->bbuf);
+ ath5k_txbuf_free_skb(sc, sc->bbuf);
list_for_each_entry(bf, &sc->txbuf, list)
- ath5k_txbuf_free(sc, bf);
+ ath5k_txbuf_free_skb(sc, bf);
list_for_each_entry(bf, &sc->rxbuf, list)
- ath5k_rxbuf_free(sc, bf);
+ ath5k_rxbuf_free_skb(sc, bf);
/* Free memory associated with all descriptors */
pci_free_consistent(pdev, sc->desc_len, sc->desc, sc->desc_daddr);
+ sc->desc = NULL;
+ sc->desc_daddr = 0;
kfree(sc->bufptr);
sc->bufptr = NULL;
+ sc->bbuf = NULL;
}
@@ -1602,7 +1614,7 @@ ath5k_txq_drainq(struct ath5k_softc *sc, struct ath5k_txq *txq)
list_for_each_entry_safe(bf, bf0, &txq->q, list) {
ath5k_debug_printtxbuf(sc, bf);
- ath5k_txbuf_free(sc, bf);
+ ath5k_txbuf_free_skb(sc, bf);
spin_lock_bh(&sc->txbuflock);
list_move_tail(&bf->list, &sc->txbuf);
@@ -1716,13 +1728,11 @@ ath5k_rx_stop(struct ath5k_softc *sc)
ath5k_hw_stop_rx_dma(ah); /* disable DMA engine */
ath5k_debug_printrxbuffs(sc, ah);
-
- sc->rxlink = NULL; /* just in case */
}
static unsigned int
-ath5k_rx_decrypted(struct ath5k_softc *sc, struct ath5k_desc *ds,
- struct sk_buff *skb, struct ath5k_rx_status *rs)
+ath5k_rx_decrypted(struct ath5k_softc *sc, struct sk_buff *skb,
+ struct ath5k_rx_status *rs)
{
struct ath5k_hw *ah = sc->ah;
struct ath_common *common = ath5k_hw_common(ah);
@@ -1889,9 +1899,138 @@ static int ath5k_remove_padding(struct sk_buff *skb)
}
static void
-ath5k_tasklet_rx(unsigned long data)
+ath5k_receive_frame(struct ath5k_softc *sc, struct sk_buff *skb,
+ struct ath5k_rx_status *rs)
{
struct ieee80211_rx_status *rxs;
+
+ /* The MAC header is padded to have 32-bit boundary if the
+ * packet payload is non-zero. The general calculation for
+ * padsize would take into account odd header lengths:
+ * padsize = (4 - hdrlen % 4) % 4; However, since only
+ * even-length headers are used, padding can only be 0 or 2
+ * bytes and we can optimize this a bit. In addition, we must
+ * not try to remove padding from short control frames that do
+ * not have payload. */
+ ath5k_remove_padding(skb);
+
+ rxs = IEEE80211_SKB_RXCB(skb);
+
+ rxs->flag = 0;
+ if (unlikely(rs->rs_status & AR5K_RXERR_MIC))
+ rxs->flag |= RX_FLAG_MMIC_ERROR;
+
+ /*
+ * always extend the mac timestamp, since this information is
+ * also needed for proper IBSS merging.
+ *
+ * XXX: it might be too late to do it here, since rs_tstamp is
+ * 15bit only. that means TSF extension has to be done within
+ * 32768usec (about 32ms). it might be necessary to move this to
+ * the interrupt handler, like it is done in madwifi.
+ *
+ * Unfortunately we don't know when the hardware takes the rx
+ * timestamp (beginning of phy frame, data frame, end of rx?).
+ * The only thing we know is that it is hardware specific...
+ * On AR5213 it seems the rx timestamp is at the end of the
+ * frame, but i'm not sure.
+ *
+ * NOTE: mac80211 defines mactime at the beginning of the first
+ * data symbol. Since we don't have any time references it's
+ * impossible to comply to that. This affects IBSS merge only
+ * right now, so it's not too bad...
+ */
+ rxs->mactime = ath5k_extend_tsf(sc->ah, rs->rs_tstamp);
+ rxs->flag |= RX_FLAG_TSFT;
+
+ rxs->freq = sc->curchan->center_freq;
+ rxs->band = sc->curband->band;
+
+ rxs->signal = sc->ah->ah_noise_floor + rs->rs_rssi;
+
+ rxs->antenna = rs->rs_antenna;
+
+ if (rs->rs_antenna > 0 && rs->rs_antenna < 5)
+ sc->stats.antenna_rx[rs->rs_antenna]++;
+ else
+ sc->stats.antenna_rx[0]++; /* invalid */
+
+ rxs->rate_idx = ath5k_hw_to_driver_rix(sc, rs->rs_rate);
+ rxs->flag |= ath5k_rx_decrypted(sc, skb, rs);
+
+ if (rxs->rate_idx >= 0 && rs->rs_rate ==
+ sc->curband->bitrates[rxs->rate_idx].hw_value_short)
+ rxs->flag |= RX_FLAG_SHORTPRE;
+
+ ath5k_debug_dump_skb(sc, skb, "RX ", 0);
+
+ ath5k_update_beacon_rssi(sc, skb, rs->rs_rssi);
+
+ /* check beacons in IBSS mode */
+ if (sc->opmode == NL80211_IFTYPE_ADHOC)
+ ath5k_check_ibss_tsf(sc, skb, rxs);
+
+ ieee80211_rx(sc->hw, skb);
+}
+
+/** ath5k_frame_receive_ok() - Do we want to receive this frame or not?
+ *
+ * Check if we want to further process this frame or not. Also update
+ * statistics. Return true if we want this frame, false if not.
+ */
+static bool
+ath5k_receive_frame_ok(struct ath5k_softc *sc, struct ath5k_rx_status *rs)
+{
+ sc->stats.rx_all_count++;
+
+ if (unlikely(rs->rs_status)) {
+ if (rs->rs_status & AR5K_RXERR_CRC)
+ sc->stats.rxerr_crc++;
+ if (rs->rs_status & AR5K_RXERR_FIFO)
+ sc->stats.rxerr_fifo++;
+ if (rs->rs_status & AR5K_RXERR_PHY) {
+ sc->stats.rxerr_phy++;
+ if (rs->rs_phyerr > 0 && rs->rs_phyerr < 32)
+ sc->stats.rxerr_phy_code[rs->rs_phyerr]++;
+ return false;
+ }
+ if (rs->rs_status & AR5K_RXERR_DECRYPT) {
+ /*
+ * Decrypt error. If the error occurred
+ * because there was no hardware key, then
+ * let the frame through so the upper layers
+ * can process it. This is necessary for 5210
+ * parts which have no way to setup a ``clear''
+ * key cache entry.
+ *
+ * XXX do key cache faulting
+ */
+ sc->stats.rxerr_decrypt++;
+ if (rs->rs_keyix == AR5K_RXKEYIX_INVALID &&
+ !(rs->rs_status & AR5K_RXERR_CRC))
+ return true;
+ }
+ if (rs->rs_status & AR5K_RXERR_MIC) {
+ sc->stats.rxerr_mic++;
+ return true;
+ }
+
+ /* let crypto-error packets fall through in MNTR */
+ if ((rs->rs_status & ~(AR5K_RXERR_DECRYPT|AR5K_RXERR_MIC)) ||
+ sc->opmode != NL80211_IFTYPE_MONITOR)
+ return false;
+ }
+
+ if (unlikely(rs->rs_more)) {
+ sc->stats.rxerr_jumbo++;
+ return false;
+ }
+ return true;
+}
+
+static void
+ath5k_tasklet_rx(unsigned long data)
+{
struct ath5k_rx_status rs = {};
struct sk_buff *skb, *next_skb;
dma_addr_t next_skb_addr;
@@ -1901,7 +2040,6 @@ ath5k_tasklet_rx(unsigned long data)
struct ath5k_buf *bf;
struct ath5k_desc *ds;
int ret;
- int rx_flag;
spin_lock(&sc->rxbuflock);
if (list_empty(&sc->rxbuf)) {
@@ -1909,8 +2047,6 @@ ath5k_tasklet_rx(unsigned long data)
goto unlock;
}
do {
- rx_flag = 0;
-
bf = list_first_entry(&sc->rxbuf, struct ath5k_buf, list);
BUG_ON(bf->skb == NULL);
skb = bf->skb;
@@ -1926,137 +2062,30 @@ ath5k_tasklet_rx(unsigned long data)
else if (unlikely(ret)) {
ATH5K_ERR(sc, "error in processing rx descriptor\n");
sc->stats.rxerr_proc++;
- spin_unlock(&sc->rxbuflock);
- return;
+ break;
}
- sc->stats.rx_all_count++;
-
- if (unlikely(rs.rs_status)) {
- if (rs.rs_status & AR5K_RXERR_CRC)
- sc->stats.rxerr_crc++;
- if (rs.rs_status & AR5K_RXERR_FIFO)
- sc->stats.rxerr_fifo++;
- if (rs.rs_status & AR5K_RXERR_PHY) {
- sc->stats.rxerr_phy++;
- if (rs.rs_phyerr > 0 && rs.rs_phyerr < 32)
- sc->stats.rxerr_phy_code[rs.rs_phyerr]++;
- goto next;
- }
- if (rs.rs_status & AR5K_RXERR_DECRYPT) {
- /*
- * Decrypt error. If the error occurred
- * because there was no hardware key, then
- * let the frame through so the upper layers
- * can process it. This is necessary for 5210
- * parts which have no way to setup a ``clear''
- * key cache entry.
- *
- * XXX do key cache faulting
- */
- sc->stats.rxerr_decrypt++;
- if (rs.rs_keyix == AR5K_RXKEYIX_INVALID &&
- !(rs.rs_status & AR5K_RXERR_CRC))
- goto accept;
- }
- if (rs.rs_status & AR5K_RXERR_MIC) {
- rx_flag |= RX_FLAG_MMIC_ERROR;
- sc->stats.rxerr_mic++;
- goto accept;
- }
+ if (ath5k_receive_frame_ok(sc, &rs)) {
+ next_skb = ath5k_rx_skb_alloc(sc, &next_skb_addr);
- /* let crypto-error packets fall through in MNTR */
- if ((rs.rs_status &
- ~(AR5K_RXERR_DECRYPT|AR5K_RXERR_MIC)) ||
- sc->opmode != NL80211_IFTYPE_MONITOR)
+ /*
+ * If we can't replace bf->skb with a new skb under
+ * memory pressure, just skip this packet
+ */
+ if (!next_skb)
goto next;
- }
- if (unlikely(rs.rs_more)) {
- sc->stats.rxerr_jumbo++;
- goto next;
+ pci_unmap_single(sc->pdev, bf->skbaddr,
+ common->rx_bufsize,
+ PCI_DMA_FROMDEVICE);
- }
-accept:
- next_skb = ath5k_rx_skb_alloc(sc, &next_skb_addr);
+ skb_put(skb, rs.rs_datalen);
- /*
- * If we can't replace bf->skb with a new skb under memory
- * pressure, just skip this packet
- */
- if (!next_skb)
- goto next;
-
- pci_unmap_single(sc->pdev, bf->skbaddr, common->rx_bufsize,
- PCI_DMA_FROMDEVICE);
- skb_put(skb, rs.rs_datalen);
-
- /* The MAC header is padded to have 32-bit boundary if the
- * packet payload is non-zero. The general calculation for
- * padsize would take into account odd header lengths:
- * padsize = (4 - hdrlen % 4) % 4; However, since only
- * even-length headers are used, padding can only be 0 or 2
- * bytes and we can optimize this a bit. In addition, we must
- * not try to remove padding from short control frames that do
- * not have payload. */
- ath5k_remove_padding(skb);
-
- rxs = IEEE80211_SKB_RXCB(skb);
-
- /*
- * always extend the mac timestamp, since this information is
- * also needed for proper IBSS merging.
- *
- * XXX: it might be too late to do it here, since rs_tstamp is
- * 15bit only. that means TSF extension has to be done within
- * 32768usec (about 32ms). it might be necessary to move this to
- * the interrupt handler, like it is done in madwifi.
- *
- * Unfortunately we don't know when the hardware takes the rx
- * timestamp (beginning of phy frame, data frame, end of rx?).
- * The only thing we know is that it is hardware specific...
- * On AR5213 it seems the rx timestamp is at the end of the
- * frame, but i'm not sure.
- *
- * NOTE: mac80211 defines mactime at the beginning of the first
- * data symbol. Since we don't have any time references it's
- * impossible to comply to that. This affects IBSS merge only
- * right now, so it's not too bad...
- */
- rxs->mactime = ath5k_extend_tsf(sc->ah, rs.rs_tstamp);
- rxs->flag = rx_flag | RX_FLAG_TSFT;
-
- rxs->freq = sc->curchan->center_freq;
- rxs->band = sc->curband->band;
-
- rxs->signal = sc->ah->ah_noise_floor + rs.rs_rssi;
-
- rxs->antenna = rs.rs_antenna;
-
- if (rs.rs_antenna > 0 && rs.rs_antenna < 5)
- sc->stats.antenna_rx[rs.rs_antenna]++;
- else
- sc->stats.antenna_rx[0]++; /* invalid */
-
- rxs->rate_idx = ath5k_hw_to_driver_rix(sc, rs.rs_rate);
- rxs->flag |= ath5k_rx_decrypted(sc, ds, skb, &rs);
+ ath5k_receive_frame(sc, skb, &rs);
- if (rxs->rate_idx >= 0 && rs.rs_rate ==
- sc->curband->bitrates[rxs->rate_idx].hw_value_short)
- rxs->flag |= RX_FLAG_SHORTPRE;
-
- ath5k_debug_dump_skb(sc, skb, "RX ", 0);
-
- ath5k_update_beacon_rssi(sc, skb, rs.rs_rssi);
-
- /* check beacons in IBSS mode */
- if (sc->opmode == NL80211_IFTYPE_ADHOC)
- ath5k_check_ibss_tsf(sc, skb, rxs);
-
- ieee80211_rx(sc->hw, skb);
-
- bf->skb = next_skb;
- bf->skbaddr = next_skb_addr;
+ bf->skb = next_skb;
+ bf->skbaddr = next_skb_addr;
+ }
next:
list_move_tail(&bf->list, &sc->rxbuf);
} while (ath5k_rxbuf_setup(sc, bf) == 0);
@@ -2065,8 +2094,6 @@ unlock:
}
-
-
/*************\
* TX Handling *
\*************/
@@ -2266,8 +2293,8 @@ err_unmap:
* frame contents are done as needed and the slot time is
* also adjusted based on current state.
*
- * This is called from software irq context (beacontq or restq
- * tasklets) or user context from ath5k_beacon_config.
+ * This is called from software irq context (beacontq tasklets)
+ * or user context from ath5k_beacon_config.
*/
static void
ath5k_beacon_send(struct ath5k_softc *sc)
@@ -2298,7 +2325,9 @@ ath5k_beacon_send(struct ath5k_softc *sc)
ATH5K_DBG(sc, ATH5K_DEBUG_BEACON,
"stuck beacon time (%u missed)\n",
sc->bmisscount);
- tasklet_schedule(&sc->restq);
+ ATH5K_DBG(sc, ATH5K_DEBUG_RESET,
+ "stuck beacon, resetting\n");
+ ieee80211_queue_work(sc->hw, &sc->reset_work);
}
return;
}
@@ -2602,12 +2631,20 @@ ath5k_stop_locked(struct ath5k_softc *sc)
if (!test_bit(ATH_STAT_INVALID, sc->status)) {
ath5k_rx_stop(sc);
ath5k_hw_phy_disable(ah);
- } else
- sc->rxlink = NULL;
+ }
return 0;
}
+static void stop_tasklets(struct ath5k_softc *sc)
+{
+ tasklet_kill(&sc->rxtq);
+ tasklet_kill(&sc->txtq);
+ tasklet_kill(&sc->calib);
+ tasklet_kill(&sc->beacontq);
+ tasklet_kill(&sc->ani_tasklet);
+}
+
/*
* Stop the device, grabbing the top-level lock to protect
* against concurrent entry through ath5k_init (which can happen
@@ -2647,17 +2684,12 @@ ath5k_stop_hw(struct ath5k_softc *sc)
ATH5K_DBG(sc, ATH5K_DEBUG_RESET,
"putting device to sleep\n");
}
- ath5k_txbuf_free(sc, sc->bbuf);
+ ath5k_txbuf_free_skb(sc, sc->bbuf);
mmiowb();
mutex_unlock(&sc->lock);
- tasklet_kill(&sc->rxtq);
- tasklet_kill(&sc->txtq);
- tasklet_kill(&sc->restq);
- tasklet_kill(&sc->calib);
- tasklet_kill(&sc->beacontq);
- tasklet_kill(&sc->ani_tasklet);
+ stop_tasklets(sc);
ath5k_rfkill_hw_stop(sc->ah);
@@ -2705,7 +2737,9 @@ ath5k_intr(int irq, void *dev_id)
* Fatal errors are unrecoverable.
* Typically these are caused by DMA errors.
*/
- tasklet_schedule(&sc->restq);
+ ATH5K_DBG(sc, ATH5K_DEBUG_RESET,
+ "fatal int, resetting\n");
+ ieee80211_queue_work(sc->hw, &sc->reset_work);
} else if (unlikely(status & AR5K_INT_RXORN)) {
/*
* Receive buffers are full. Either the bus is busy or
@@ -2717,8 +2751,11 @@ ath5k_intr(int irq, void *dev_id)
* this guess is copied from the HAL.
*/
sc->stats.rxorn_intr++;
- if (ah->ah_mac_srev < AR5K_SREV_AR5212)
- tasklet_schedule(&sc->restq);
+ if (ah->ah_mac_srev < AR5K_SREV_AR5212) {
+ ATH5K_DBG(sc, ATH5K_DEBUG_RESET,
+ "rx overrun, resetting\n");
+ ieee80211_queue_work(sc->hw, &sc->reset_work);
+ }
else
tasklet_schedule(&sc->rxtq);
} else {
@@ -2731,7 +2768,7 @@ ath5k_intr(int irq, void *dev_id)
* RXE bit is written, but it doesn't work at
* least on older hardware revs.
*/
- sc->rxlink = NULL;
+ sc->stats.rxeol_intr++;
}
if (status & AR5K_INT_TXURN) {
/* bump tx trigger level */
@@ -2764,14 +2801,6 @@ ath5k_intr(int irq, void *dev_id)
return IRQ_HANDLED;
}
-static void
-ath5k_tasklet_reset(unsigned long data)
-{
- struct ath5k_softc *sc = (void *)data;
-
- ath5k_reset(sc, sc->curchan);
-}
-
/*
* Periodically recalibrate the PHY to account
* for temperature/environment changes.
@@ -2785,10 +2814,6 @@ ath5k_tasklet_calibrate(unsigned long data)
/* Only full calibration for now */
ah->ah_cal_mask |= AR5K_CALIBRATION_FULL;
- /* Stop queues so that calibration
- * doesn't interfere with tx */
- ieee80211_stop_queues(sc->hw);
-
ATH5K_DBG(sc, ATH5K_DEBUG_CALIBRATE, "channel %u/%x\n",
ieee80211_frequency_to_channel(sc->curchan->center_freq),
sc->curchan->hw_value);
@@ -2799,15 +2824,23 @@ ath5k_tasklet_calibrate(unsigned long data)
* to load new gain values.
*/
ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "calibration, resetting\n");
- ath5k_reset(sc, sc->curchan);
+ ieee80211_queue_work(sc->hw, &sc->reset_work);
}
if (ath5k_hw_phy_calibrate(ah, sc->curchan))
ATH5K_ERR(sc, "calibration of channel %u failed\n",
ieee80211_frequency_to_channel(
sc->curchan->center_freq));
- /* Wake queues */
- ieee80211_wake_queues(sc->hw);
+ /* Noise floor calibration interrupts rx/tx path while I/Q calibration
+ * doesn't. We stop the queues so that calibration doesn't interfere
+ * with TX and don't run it as often */
+ if (time_is_before_eq_jiffies(ah->ah_cal_next_nf)) {
+ ah->ah_cal_next_nf = jiffies +
+ msecs_to_jiffies(ATH5K_TUNE_CALIBRATION_INTERVAL_NF);
+ ieee80211_stop_queues(sc->hw);
+ ath5k_hw_update_noise_floor(ah);
+ ieee80211_wake_queues(sc->hw);
+ }
ah->ah_cal_mask &= ~AR5K_CALIBRATION_FULL;
}
@@ -2895,6 +2928,8 @@ drop_packet:
/*
* Reset the hardware. If chan is not NULL, then also pause rx/tx
* and change to the given channel.
+ *
+ * This should be called with sc->lock.
*/
static int
ath5k_reset(struct ath5k_softc *sc, struct ieee80211_channel *chan)
@@ -2904,8 +2939,11 @@ ath5k_reset(struct ath5k_softc *sc, struct ieee80211_channel *chan)
ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "resetting\n");
+ ath5k_hw_set_imr(ah, 0);
+ synchronize_irq(sc->pdev->irq);
+ stop_tasklets(sc);
+
if (chan) {
- ath5k_hw_set_imr(ah, 0);
ath5k_txq_cleanup(sc);
ath5k_rx_stop(sc);
@@ -2926,6 +2964,10 @@ ath5k_reset(struct ath5k_softc *sc, struct ieee80211_channel *chan)
ath5k_ani_init(ah, ah->ah_sc->ani_state.ani_mode);
+ ah->ah_cal_next_full = jiffies;
+ ah->ah_cal_next_ani = jiffies;
+ ah->ah_cal_next_nf = jiffies;
+
/*
* Change channels and update the h/w rate map if we're switching;
* e.g. 11a to 11b/g.
@@ -2947,6 +2989,16 @@ err:
return ret;
}
+static void ath5k_reset_work(struct work_struct *work)
+{
+ struct ath5k_softc *sc = container_of(work, struct ath5k_softc,
+ reset_work);
+
+ mutex_lock(&sc->lock);
+ ath5k_reset(sc, sc->curchan);
+ mutex_unlock(&sc->lock);
+}
+
static int ath5k_start(struct ieee80211_hw *hw)
{
return ath5k_init(hw->priv);
@@ -3360,7 +3412,7 @@ ath5k_beacon_update(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
ath5k_debug_dump_skb(sc, skb, "BC ", 1);
- ath5k_txbuf_free(sc, sc->bbuf);
+ ath5k_txbuf_free_skb(sc, sc->bbuf);
sc->bbuf->skb = skb;
ret = ath5k_beacon_setup(sc, sc->bbuf);
if (ret)
diff --git a/drivers/net/wireless/ath/ath5k/base.h b/drivers/net/wireless/ath/ath5k/base.h
index 56221bc7c8c..dc1241f9c4e 100644
--- a/drivers/net/wireless/ath/ath5k/base.h
+++ b/drivers/net/wireless/ath/ath5k/base.h
@@ -47,6 +47,7 @@
#include <linux/if_ether.h>
#include <linux/leds.h>
#include <linux/rfkill.h>
+#include <linux/workqueue.h>
#include "ath5k.h"
#include "debug.h"
@@ -136,6 +137,7 @@ struct ath5k_statistics {
unsigned int mib_intr;
unsigned int rxorn_intr;
+ unsigned int rxeol_intr;
};
#if CHAN_DEBUG
@@ -189,7 +191,7 @@ struct ath5k_softc {
unsigned int led_pin, /* GPIO pin for driving LED */
led_on; /* pin setting for LED on */
- struct tasklet_struct restq; /* reset tasklet */
+ struct work_struct reset_work; /* deferred chip reset */
unsigned int rxbufsize; /* rx size based on mtu */
struct list_head rxbuf; /* receive buffer */
diff --git a/drivers/net/wireless/ath/ath5k/caps.c b/drivers/net/wireless/ath/ath5k/caps.c
index 74f007126f4..beae519aa73 100644
--- a/drivers/net/wireless/ath/ath5k/caps.c
+++ b/drivers/net/wireless/ath/ath5k/caps.c
@@ -34,7 +34,6 @@ int ath5k_hw_set_capabilities(struct ath5k_hw *ah)
{
u16 ee_header;
- ATH5K_TRACE(ah->ah_sc);
/* Capabilities stored in the EEPROM */
ee_header = ah->ah_capabilities.cap_eeprom.ee_header;
@@ -123,8 +122,6 @@ int ath5k_hw_get_capability(struct ath5k_hw *ah,
enum ath5k_capability_type cap_type,
u32 capability, u32 *result)
{
- ATH5K_TRACE(ah->ah_sc);
-
switch (cap_type) {
case AR5K_CAP_NUM_TXQUEUES:
if (result) {
@@ -173,8 +170,6 @@ yes:
int ath5k_hw_enable_pspoll(struct ath5k_hw *ah, u8 *bssid,
u16 assoc_id)
{
- ATH5K_TRACE(ah->ah_sc);
-
if (ah->ah_version == AR5K_AR5210) {
AR5K_REG_DISABLE_BITS(ah, AR5K_STA_ID1,
AR5K_STA_ID1_NO_PSPOLL | AR5K_STA_ID1_DEFAULT_ANTENNA);
@@ -186,8 +181,6 @@ int ath5k_hw_enable_pspoll(struct ath5k_hw *ah, u8 *bssid,
int ath5k_hw_disable_pspoll(struct ath5k_hw *ah)
{
- ATH5K_TRACE(ah->ah_sc);
-
if (ah->ah_version == AR5K_AR5210) {
AR5K_REG_ENABLE_BITS(ah, AR5K_STA_ID1,
AR5K_STA_ID1_NO_PSPOLL | AR5K_STA_ID1_DEFAULT_ANTENNA);
diff --git a/drivers/net/wireless/ath/ath5k/debug.c b/drivers/net/wireless/ath/ath5k/debug.c
index 6fb5c5ffa5b..4cccc29964f 100644
--- a/drivers/net/wireless/ath/ath5k/debug.c
+++ b/drivers/net/wireless/ath/ath5k/debug.c
@@ -239,6 +239,9 @@ static ssize_t read_file_beacon(struct file *file, char __user *user_buf,
"TSF\t\t0x%016llx\tTU: %08x\n",
(unsigned long long)tsf, TSF_TO_TU(tsf));
+ if (len > sizeof(buf))
+ len = sizeof(buf);
+
return simple_read_from_buffer(user_buf, count, ppos, buf, len);
}
@@ -278,7 +281,8 @@ static ssize_t write_file_reset(struct file *file,
size_t count, loff_t *ppos)
{
struct ath5k_softc *sc = file->private_data;
- tasklet_schedule(&sc->restq);
+ ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "debug file triggered reset\n");
+ ieee80211_queue_work(sc->hw, &sc->reset_work);
return count;
}
@@ -307,7 +311,6 @@ static const struct {
{ ATH5K_DEBUG_DUMP_RX, "dumprx", "print received skb content" },
{ ATH5K_DEBUG_DUMP_TX, "dumptx", "print transmit skb content" },
{ ATH5K_DEBUG_DUMPBANDS, "dumpbands", "dump bands" },
- { ATH5K_DEBUG_TRACE, "trace", "trace function calls" },
{ ATH5K_DEBUG_ANI, "ani", "adaptive noise immunity" },
{ ATH5K_DEBUG_ANY, "all", "show all debug levels" },
};
@@ -334,6 +337,9 @@ static ssize_t read_file_debug(struct file *file, char __user *user_buf,
sc->debug.level == dbg_info[i].level ? '+' : ' ',
dbg_info[i].level, dbg_info[i].desc);
+ if (len > sizeof(buf))
+ len = sizeof(buf);
+
return simple_read_from_buffer(user_buf, count, ppos, buf, len);
}
@@ -426,6 +432,16 @@ static ssize_t read_file_antenna(struct file *file, char __user *user_buf,
"AR5K_PHY_FAST_ANT_DIV_EN\t%d\n",
(v & AR5K_PHY_FAST_ANT_DIV_EN) != 0);
+ v = ath5k_hw_reg_read(sc->ah, AR5K_PHY_ANT_SWITCH_TABLE_0);
+ len += snprintf(buf+len, sizeof(buf)-len,
+ "\nAR5K_PHY_ANT_SWITCH_TABLE_0\t0x%08x\n", v);
+ v = ath5k_hw_reg_read(sc->ah, AR5K_PHY_ANT_SWITCH_TABLE_1);
+ len += snprintf(buf+len, sizeof(buf)-len,
+ "AR5K_PHY_ANT_SWITCH_TABLE_1\t0x%08x\n", v);
+
+ if (len > sizeof(buf))
+ len = sizeof(buf);
+
return simple_read_from_buffer(user_buf, count, ppos, buf, len);
}
@@ -535,6 +551,9 @@ static ssize_t read_file_frameerrors(struct file *file, char __user *user_buf,
len += snprintf(buf+len, sizeof(buf)-len, "[TX all\t%d]\n",
st->tx_all_count);
+ if (len > sizeof(buf))
+ len = sizeof(buf);
+
return simple_read_from_buffer(user_buf, count, ppos, buf, len);
}
@@ -674,6 +693,9 @@ static ssize_t read_file_ani(struct file *file, char __user *user_buf,
ATH5K_ANI_CCK_TRIG_HIGH - (ATH5K_PHYERR_CNT_MAX -
ath5k_hw_reg_read(sc->ah, AR5K_PHYERR_CNT2)));
+ if (len > sizeof(buf))
+ len = sizeof(buf);
+
return simple_read_from_buffer(user_buf, count, ppos, buf, len);
}
@@ -729,6 +751,69 @@ static const struct file_operations fops_ani = {
};
+/* debugfs: queues etc */
+
+static ssize_t read_file_queue(struct file *file, char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct ath5k_softc *sc = file->private_data;
+ char buf[700];
+ unsigned int len = 0;
+
+ struct ath5k_txq *txq;
+ struct ath5k_buf *bf, *bf0;
+ int i, n = 0;
+
+ len += snprintf(buf+len, sizeof(buf)-len,
+ "available txbuffers: %d\n", sc->txbuf_len);
+
+ for (i = 0; i < ARRAY_SIZE(sc->txqs); i++) {
+ txq = &sc->txqs[i];
+
+ len += snprintf(buf+len, sizeof(buf)-len,
+ "%02d: %ssetup\n", i, txq->setup ? "" : "not ");
+
+ if (!txq->setup)
+ continue;
+
+ list_for_each_entry_safe(bf, bf0, &txq->q, list)
+ n++;
+ len += snprintf(buf+len, sizeof(buf)-len, " len: %d\n", n);
+ }
+
+ if (len > sizeof(buf))
+ len = sizeof(buf);
+
+ return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+}
+
+static ssize_t write_file_queue(struct file *file,
+ const char __user *userbuf,
+ size_t count, loff_t *ppos)
+{
+ struct ath5k_softc *sc = file->private_data;
+ char buf[20];
+
+ if (copy_from_user(buf, userbuf, min(count, sizeof(buf))))
+ return -EFAULT;
+
+ if (strncmp(buf, "start", 5) == 0)
+ ieee80211_wake_queues(sc->hw);
+ else if (strncmp(buf, "stop", 4) == 0)
+ ieee80211_stop_queues(sc->hw);
+
+ return count;
+}
+
+
+static const struct file_operations fops_queue = {
+ .read = read_file_queue,
+ .write = write_file_queue,
+ .open = ath5k_debugfs_open,
+ .owner = THIS_MODULE,
+};
+
+
/* init */
void
@@ -772,6 +857,11 @@ ath5k_debug_init_device(struct ath5k_softc *sc)
S_IWUSR | S_IRUSR,
sc->debug.debugfs_phydir, sc,
&fops_ani);
+
+ sc->debug.debugfs_queue = debugfs_create_file("queue",
+ S_IWUSR | S_IRUSR,
+ sc->debug.debugfs_phydir, sc,
+ &fops_queue);
}
void
@@ -790,6 +880,7 @@ ath5k_debug_finish_device(struct ath5k_softc *sc)
debugfs_remove(sc->debug.debugfs_antenna);
debugfs_remove(sc->debug.debugfs_frameerrors);
debugfs_remove(sc->debug.debugfs_ani);
+ debugfs_remove(sc->debug.debugfs_queue);
debugfs_remove(sc->debug.debugfs_phydir);
}
@@ -852,7 +943,7 @@ ath5k_debug_printrxbuf(struct ath5k_buf *bf, int done,
ds, (unsigned long long)bf->daddr,
ds->ds_link, ds->ds_data,
rd->rx_ctl.rx_control_0, rd->rx_ctl.rx_control_1,
- rd->u.rx_stat.rx_status_0, rd->u.rx_stat.rx_status_0,
+ rd->rx_stat.rx_status_0, rd->rx_stat.rx_status_1,
!done ? ' ' : (rs->rs_status == 0) ? '*' : '!');
}
@@ -867,7 +958,7 @@ ath5k_debug_printrxbuffs(struct ath5k_softc *sc, struct ath5k_hw *ah)
if (likely(!(sc->debug.level & ATH5K_DEBUG_RESET)))
return;
- printk(KERN_DEBUG "rx queue %x, link %p\n",
+ printk(KERN_DEBUG "rxdp %x, rxlink %p\n",
ath5k_hw_get_rxdp(ah), sc->rxlink);
spin_lock_bh(&sc->rxbuflock);
diff --git a/drivers/net/wireless/ath/ath5k/debug.h b/drivers/net/wireless/ath/ath5k/debug.h
index ddd5b3a99e8..606ae94a915 100644
--- a/drivers/net/wireless/ath/ath5k/debug.h
+++ b/drivers/net/wireless/ath/ath5k/debug.h
@@ -77,6 +77,7 @@ struct ath5k_dbg_info {
struct dentry *debugfs_antenna;
struct dentry *debugfs_frameerrors;
struct dentry *debugfs_ani;
+ struct dentry *debugfs_queue;
};
/**
@@ -115,18 +116,12 @@ enum ath5k_debug_level {
ATH5K_DEBUG_DUMP_RX = 0x00000100,
ATH5K_DEBUG_DUMP_TX = 0x00000200,
ATH5K_DEBUG_DUMPBANDS = 0x00000400,
- ATH5K_DEBUG_TRACE = 0x00001000,
ATH5K_DEBUG_ANI = 0x00002000,
ATH5K_DEBUG_ANY = 0xffffffff
};
#ifdef CONFIG_ATH5K_DEBUG
-#define ATH5K_TRACE(_sc) do { \
- if (unlikely((_sc)->debug.level & ATH5K_DEBUG_TRACE)) \
- printk(KERN_DEBUG "ath5k trace %s:%d\n", __func__, __LINE__); \
- } while (0)
-
#define ATH5K_DBG(_sc, _m, _fmt, ...) do { \
if (unlikely((_sc)->debug.level & (_m) && net_ratelimit())) \
ATH5K_PRINTK(_sc, KERN_DEBUG, "(%s:%d): " _fmt, \
@@ -168,8 +163,6 @@ ath5k_debug_printtxbuf(struct ath5k_softc *sc, struct ath5k_buf *bf);
#include <linux/compiler.h>
-#define ATH5K_TRACE(_sc) typecheck(struct ath5k_softc *, (_sc))
-
static inline void __attribute__ ((format (printf, 3, 4)))
ATH5K_DBG(struct ath5k_softc *sc, unsigned int m, const char *fmt, ...) {}
diff --git a/drivers/net/wireless/ath/ath5k/desc.c b/drivers/net/wireless/ath/ath5k/desc.c
index 7d7b646ab65..43244382f21 100644
--- a/drivers/net/wireless/ath/ath5k/desc.c
+++ b/drivers/net/wireless/ath/ath5k/desc.c
@@ -91,14 +91,13 @@ ath5k_hw_setup_2word_tx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc,
tx_ctl->tx_control_1 = pkt_len & AR5K_2W_TX_DESC_CTL1_BUF_LEN;
/*
- * Verify and set header length
- * XXX: I only found that on 5210 code, does it work on 5211 ?
+ * Verify and set header length (only 5210)
*/
if (ah->ah_version == AR5K_AR5210) {
- if (hdr_len & ~AR5K_2W_TX_DESC_CTL0_HEADER_LEN)
+ if (hdr_len & ~AR5K_2W_TX_DESC_CTL0_HEADER_LEN_5210)
return -EINVAL;
tx_ctl->tx_control_0 |=
- AR5K_REG_SM(hdr_len, AR5K_2W_TX_DESC_CTL0_HEADER_LEN);
+ AR5K_REG_SM(hdr_len, AR5K_2W_TX_DESC_CTL0_HEADER_LEN_5210);
}
/*Differences between 5210-5211*/
@@ -110,11 +109,11 @@ ath5k_hw_setup_2word_tx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc,
case AR5K_PKT_TYPE_PIFS:
frame_type = AR5K_AR5210_TX_DESC_FRAME_TYPE_PIFS;
default:
- frame_type = type /*<< 2 ?*/;
+ frame_type = type;
}
tx_ctl->tx_control_0 |=
- AR5K_REG_SM(frame_type, AR5K_2W_TX_DESC_CTL0_FRAME_TYPE) |
+ AR5K_REG_SM(frame_type, AR5K_2W_TX_DESC_CTL0_FRAME_TYPE_5210) |
AR5K_REG_SM(tx_rate0, AR5K_2W_TX_DESC_CTL0_XMIT_RATE);
} else {
@@ -123,21 +122,30 @@ ath5k_hw_setup_2word_tx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc,
AR5K_REG_SM(antenna_mode,
AR5K_2W_TX_DESC_CTL0_ANT_MODE_XMIT);
tx_ctl->tx_control_1 |=
- AR5K_REG_SM(type, AR5K_2W_TX_DESC_CTL1_FRAME_TYPE);
+ AR5K_REG_SM(type, AR5K_2W_TX_DESC_CTL1_FRAME_TYPE_5211);
}
+
#define _TX_FLAGS(_c, _flag) \
if (flags & AR5K_TXDESC_##_flag) { \
tx_ctl->tx_control_##_c |= \
AR5K_2W_TX_DESC_CTL##_c##_##_flag; \
}
-
+#define _TX_FLAGS_5211(_c, _flag) \
+ if (flags & AR5K_TXDESC_##_flag) { \
+ tx_ctl->tx_control_##_c |= \
+ AR5K_2W_TX_DESC_CTL##_c##_##_flag##_5211; \
+ }
_TX_FLAGS(0, CLRDMASK);
- _TX_FLAGS(0, VEOL);
_TX_FLAGS(0, INTREQ);
_TX_FLAGS(0, RTSENA);
- _TX_FLAGS(1, NOACK);
+
+ if (ah->ah_version == AR5K_AR5211) {
+ _TX_FLAGS_5211(0, VEOL);
+ _TX_FLAGS_5211(1, NOACK);
+ }
#undef _TX_FLAGS
+#undef _TX_FLAGS_5211
/*
* WEP crap
@@ -147,7 +155,7 @@ ath5k_hw_setup_2word_tx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc,
AR5K_2W_TX_DESC_CTL0_ENCRYPT_KEY_VALID;
tx_ctl->tx_control_1 |=
AR5K_REG_SM(key_index,
- AR5K_2W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX);
+ AR5K_2W_TX_DESC_CTL1_ENC_KEY_IDX);
}
/*
@@ -156,7 +164,7 @@ ath5k_hw_setup_2word_tx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc,
if ((ah->ah_version == AR5K_AR5210) &&
(flags & (AR5K_TXDESC_RTSENA | AR5K_TXDESC_CTSENA)))
tx_ctl->tx_control_1 |= rtscts_duration &
- AR5K_2W_TX_DESC_CTL1_RTS_DURATION;
+ AR5K_2W_TX_DESC_CTL1_RTS_DURATION_5210;
return 0;
}
@@ -176,7 +184,6 @@ static int ath5k_hw_setup_4word_tx_desc(struct ath5k_hw *ah,
struct ath5k_hw_4w_tx_ctl *tx_ctl;
unsigned int frame_len;
- ATH5K_TRACE(ah->ah_sc);
tx_ctl = &desc->ud.ds_tx5212.tx_ctl;
/*
@@ -256,7 +263,7 @@ static int ath5k_hw_setup_4word_tx_desc(struct ath5k_hw *ah,
if (key_index != AR5K_TXKEYIX_INVALID) {
tx_ctl->tx_control_0 |= AR5K_4W_TX_DESC_CTL0_ENCRYPT_KEY_VALID;
tx_ctl->tx_control_1 |= AR5K_REG_SM(key_index,
- AR5K_4W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX);
+ AR5K_4W_TX_DESC_CTL1_ENCRYPT_KEY_IDX);
}
/*
@@ -278,13 +285,17 @@ static int ath5k_hw_setup_4word_tx_desc(struct ath5k_hw *ah,
/*
* Initialize a 4-word multi rate retry tx control descriptor on 5212
*/
-static int
+int
ath5k_hw_setup_mrr_tx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc,
unsigned int tx_rate1, u_int tx_tries1, u_int tx_rate2,
u_int tx_tries2, unsigned int tx_rate3, u_int tx_tries3)
{
struct ath5k_hw_4w_tx_ctl *tx_ctl;
+ /* no mrr support for cards older than 5212 */
+ if (ah->ah_version < AR5K_AR5212)
+ return 0;
+
/*
* Rates can be 0 as long as the retry count is 0 too.
* A zero rate and nonzero retry count will put the HW into a mode where
@@ -324,15 +335,6 @@ ath5k_hw_setup_mrr_tx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc,
return 0;
}
-/* no mrr support for cards older than 5212 */
-static int
-ath5k_hw_setup_no_mrr(struct ath5k_hw *ah, struct ath5k_desc *desc,
- unsigned int tx_rate1, u_int tx_tries1, u_int tx_rate2,
- u_int tx_tries2, unsigned int tx_rate3, u_int tx_tries3)
-{
- return 0;
-}
-
/*
* Proccess the tx status descriptor on 5210/5211
*/
@@ -342,8 +344,6 @@ static int ath5k_hw_proc_2word_tx_status(struct ath5k_hw *ah,
struct ath5k_hw_2w_tx_ctl *tx_ctl;
struct ath5k_hw_tx_status *tx_status;
- ATH5K_TRACE(ah->ah_sc);
-
tx_ctl = &desc->ud.ds_tx5210.tx_ctl;
tx_status = &desc->ud.ds_tx5210.tx_stat;
@@ -396,8 +396,6 @@ static int ath5k_hw_proc_4word_tx_status(struct ath5k_hw *ah,
struct ath5k_hw_4w_tx_ctl *tx_ctl;
struct ath5k_hw_tx_status *tx_status;
- ATH5K_TRACE(ah->ah_sc);
-
tx_ctl = &desc->ud.ds_tx5212.tx_ctl;
tx_status = &desc->ud.ds_tx5212.tx_stat;
@@ -419,11 +417,11 @@ static int ath5k_hw_proc_4word_tx_status(struct ath5k_hw *ah,
ts->ts_rssi = AR5K_REG_MS(tx_status->tx_status_1,
AR5K_DESC_TX_STATUS1_ACK_SIG_STRENGTH);
ts->ts_antenna = (tx_status->tx_status_1 &
- AR5K_DESC_TX_STATUS1_XMIT_ANTENNA) ? 2 : 1;
+ AR5K_DESC_TX_STATUS1_XMIT_ANTENNA_5212) ? 2 : 1;
ts->ts_status = 0;
ts->ts_final_idx = AR5K_REG_MS(tx_status->tx_status_1,
- AR5K_DESC_TX_STATUS1_FINAL_TS_INDEX);
+ AR5K_DESC_TX_STATUS1_FINAL_TS_IX_5212);
/* The longretry counter has the number of un-acked retries
* for the final rate. To get the total number of retries
@@ -485,12 +483,11 @@ static int ath5k_hw_proc_4word_tx_status(struct ath5k_hw *ah,
/*
* Initialize an rx control descriptor
*/
-static int ath5k_hw_setup_rx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc,
- u32 size, unsigned int flags)
+int ath5k_hw_setup_rx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc,
+ u32 size, unsigned int flags)
{
struct ath5k_hw_rx_ctl *rx_ctl;
- ATH5K_TRACE(ah->ah_sc);
rx_ctl = &desc->ud.ds_rx.rx_ctl;
/*
@@ -502,10 +499,11 @@ static int ath5k_hw_setup_rx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc,
*/
memset(&desc->ud.ds_rx, 0, sizeof(struct ath5k_hw_all_rx_desc));
+ if (unlikely(size & ~AR5K_DESC_RX_CTL1_BUF_LEN))
+ return -EINVAL;
+
/* Setup descriptor */
rx_ctl->rx_control_1 = size & AR5K_DESC_RX_CTL1_BUF_LEN;
- if (unlikely(rx_ctl->rx_control_1 != size))
- return -EINVAL;
if (flags & AR5K_RXDESC_INTREQ)
rx_ctl->rx_control_1 |= AR5K_DESC_RX_CTL1_INTREQ;
@@ -521,13 +519,15 @@ static int ath5k_hw_proc_5210_rx_status(struct ath5k_hw *ah,
{
struct ath5k_hw_rx_status *rx_status;
- rx_status = &desc->ud.ds_rx.u.rx_stat;
+ rx_status = &desc->ud.ds_rx.rx_stat;
/* No frame received / not ready */
if (unlikely(!(rx_status->rx_status_1 &
- AR5K_5210_RX_DESC_STATUS1_DONE)))
+ AR5K_5210_RX_DESC_STATUS1_DONE)))
return -EINPROGRESS;
+ memset(rs, 0, sizeof(struct ath5k_rx_status));
+
/*
* Frame receive status
*/
@@ -537,15 +537,23 @@ static int ath5k_hw_proc_5210_rx_status(struct ath5k_hw *ah,
AR5K_5210_RX_DESC_STATUS0_RECEIVE_SIGNAL);
rs->rs_rate = AR5K_REG_MS(rx_status->rx_status_0,
AR5K_5210_RX_DESC_STATUS0_RECEIVE_RATE);
- rs->rs_antenna = AR5K_REG_MS(rx_status->rx_status_0,
- AR5K_5210_RX_DESC_STATUS0_RECEIVE_ANTENNA);
rs->rs_more = !!(rx_status->rx_status_0 &
AR5K_5210_RX_DESC_STATUS0_MORE);
- /* TODO: this timestamp is 13 bit, later on we assume 15 bit */
+ /* TODO: this timestamp is 13 bit, later on we assume 15 bit!
+ * also the HAL code for 5210 says the timestamp is bits [10..22] of the
+ * TSF, and extends the timestamp here to 15 bit.
+ * we need to check on 5210...
+ */
rs->rs_tstamp = AR5K_REG_MS(rx_status->rx_status_1,
AR5K_5210_RX_DESC_STATUS1_RECEIVE_TIMESTAMP);
- rs->rs_status = 0;
- rs->rs_phyerr = 0;
+
+ if (ah->ah_version == AR5K_AR5211)
+ rs->rs_antenna = AR5K_REG_MS(rx_status->rx_status_0,
+ AR5K_5210_RX_DESC_STATUS0_RECEIVE_ANT_5211);
+ else
+ rs->rs_antenna = (rx_status->rx_status_0 &
+ AR5K_5210_RX_DESC_STATUS0_RECEIVE_ANT_5210)
+ ? 2 : 1;
/*
* Key table status
@@ -560,19 +568,21 @@ static int ath5k_hw_proc_5210_rx_status(struct ath5k_hw *ah,
* Receive/descriptor errors
*/
if (!(rx_status->rx_status_1 &
- AR5K_5210_RX_DESC_STATUS1_FRAME_RECEIVE_OK)) {
+ AR5K_5210_RX_DESC_STATUS1_FRAME_RECEIVE_OK)) {
if (rx_status->rx_status_1 &
AR5K_5210_RX_DESC_STATUS1_CRC_ERROR)
rs->rs_status |= AR5K_RXERR_CRC;
- if (rx_status->rx_status_1 &
- AR5K_5210_RX_DESC_STATUS1_FIFO_OVERRUN)
+ /* only on 5210 */
+ if ((ah->ah_version == AR5K_AR5210) &&
+ (rx_status->rx_status_1 &
+ AR5K_5210_RX_DESC_STATUS1_FIFO_OVERRUN_5210))
rs->rs_status |= AR5K_RXERR_FIFO;
if (rx_status->rx_status_1 &
AR5K_5210_RX_DESC_STATUS1_PHY_ERROR) {
rs->rs_status |= AR5K_RXERR_PHY;
- rs->rs_phyerr |= AR5K_REG_MS(rx_status->rx_status_1,
+ rs->rs_phyerr = AR5K_REG_MS(rx_status->rx_status_1,
AR5K_5210_RX_DESC_STATUS1_PHY_ERROR);
}
@@ -588,22 +598,20 @@ static int ath5k_hw_proc_5210_rx_status(struct ath5k_hw *ah,
* Proccess the rx status descriptor on 5212
*/
static int ath5k_hw_proc_5212_rx_status(struct ath5k_hw *ah,
- struct ath5k_desc *desc, struct ath5k_rx_status *rs)
+ struct ath5k_desc *desc,
+ struct ath5k_rx_status *rs)
{
struct ath5k_hw_rx_status *rx_status;
- struct ath5k_hw_rx_error *rx_err;
- ATH5K_TRACE(ah->ah_sc);
- rx_status = &desc->ud.ds_rx.u.rx_stat;
-
- /* Overlay on error */
- rx_err = &desc->ud.ds_rx.u.rx_err;
+ rx_status = &desc->ud.ds_rx.rx_stat;
/* No frame received / not ready */
if (unlikely(!(rx_status->rx_status_1 &
- AR5K_5212_RX_DESC_STATUS1_DONE)))
+ AR5K_5212_RX_DESC_STATUS1_DONE)))
return -EINPROGRESS;
+ memset(rs, 0, sizeof(struct ath5k_rx_status));
+
/*
* Frame receive status
*/
@@ -619,15 +627,13 @@ static int ath5k_hw_proc_5212_rx_status(struct ath5k_hw *ah,
AR5K_5212_RX_DESC_STATUS0_MORE);
rs->rs_tstamp = AR5K_REG_MS(rx_status->rx_status_1,
AR5K_5212_RX_DESC_STATUS1_RECEIVE_TIMESTAMP);
- rs->rs_status = 0;
- rs->rs_phyerr = 0;
/*
* Key table status
*/
if (rx_status->rx_status_1 & AR5K_5212_RX_DESC_STATUS1_KEY_INDEX_VALID)
rs->rs_keyix = AR5K_REG_MS(rx_status->rx_status_1,
- AR5K_5212_RX_DESC_STATUS1_KEY_INDEX);
+ AR5K_5212_RX_DESC_STATUS1_KEY_INDEX);
else
rs->rs_keyix = AR5K_RXKEYIX_INVALID;
@@ -635,7 +641,7 @@ static int ath5k_hw_proc_5212_rx_status(struct ath5k_hw *ah,
* Receive/descriptor errors
*/
if (!(rx_status->rx_status_1 &
- AR5K_5212_RX_DESC_STATUS1_FRAME_RECEIVE_OK)) {
+ AR5K_5212_RX_DESC_STATUS1_FRAME_RECEIVE_OK)) {
if (rx_status->rx_status_1 &
AR5K_5212_RX_DESC_STATUS1_CRC_ERROR)
rs->rs_status |= AR5K_RXERR_CRC;
@@ -643,9 +649,10 @@ static int ath5k_hw_proc_5212_rx_status(struct ath5k_hw *ah,
if (rx_status->rx_status_1 &
AR5K_5212_RX_DESC_STATUS1_PHY_ERROR) {
rs->rs_status |= AR5K_RXERR_PHY;
- rs->rs_phyerr |= AR5K_REG_MS(rx_err->rx_error_1,
- AR5K_RX_DESC_ERROR1_PHY_ERROR_CODE);
- ath5k_ani_phy_error_report(ah, rs->rs_phyerr);
+ rs->rs_phyerr = AR5K_REG_MS(rx_status->rx_status_1,
+ AR5K_5212_RX_DESC_STATUS1_PHY_ERROR_CODE);
+ if (!ah->ah_capabilities.cap_has_phyerr_counters)
+ ath5k_ani_phy_error_report(ah, rs->rs_phyerr);
}
if (rx_status->rx_status_1 &
@@ -656,7 +663,6 @@ static int ath5k_hw_proc_5212_rx_status(struct ath5k_hw *ah,
AR5K_5212_RX_DESC_STATUS1_MIC_ERROR)
rs->rs_status |= AR5K_RXERR_MIC;
}
-
return 0;
}
@@ -665,29 +671,15 @@ static int ath5k_hw_proc_5212_rx_status(struct ath5k_hw *ah,
*/
int ath5k_hw_init_desc_functions(struct ath5k_hw *ah)
{
-
- if (ah->ah_version != AR5K_AR5210 &&
- ah->ah_version != AR5K_AR5211 &&
- ah->ah_version != AR5K_AR5212)
- return -ENOTSUPP;
-
if (ah->ah_version == AR5K_AR5212) {
- ah->ah_setup_rx_desc = ath5k_hw_setup_rx_desc;
ah->ah_setup_tx_desc = ath5k_hw_setup_4word_tx_desc;
- ah->ah_setup_mrr_tx_desc = ath5k_hw_setup_mrr_tx_desc;
ah->ah_proc_tx_desc = ath5k_hw_proc_4word_tx_status;
- } else {
- ah->ah_setup_rx_desc = ath5k_hw_setup_rx_desc;
+ ah->ah_proc_rx_desc = ath5k_hw_proc_5212_rx_status;
+ } else if (ah->ah_version <= AR5K_AR5211) {
ah->ah_setup_tx_desc = ath5k_hw_setup_2word_tx_desc;
- ah->ah_setup_mrr_tx_desc = ath5k_hw_setup_no_mrr;
ah->ah_proc_tx_desc = ath5k_hw_proc_2word_tx_status;
- }
-
- if (ah->ah_version == AR5K_AR5212)
- ah->ah_proc_rx_desc = ath5k_hw_proc_5212_rx_status;
- else if (ah->ah_version <= AR5K_AR5211)
ah->ah_proc_rx_desc = ath5k_hw_proc_5210_rx_status;
-
+ } else
+ return -ENOTSUPP;
return 0;
}
-
diff --git a/drivers/net/wireless/ath/ath5k/desc.h b/drivers/net/wireless/ath/ath5k/desc.h
index 64538fbe416..b2adb2a281c 100644
--- a/drivers/net/wireless/ath/ath5k/desc.h
+++ b/drivers/net/wireless/ath/ath5k/desc.h
@@ -17,28 +17,24 @@
*/
/*
- * Internal RX/TX descriptor structures
- * (rX: reserved fields possibily used by future versions of the ar5k chipset)
+ * RX/TX descriptor structures
*/
/*
- * common hardware RX control descriptor
+ * Common hardware RX control descriptor
*/
struct ath5k_hw_rx_ctl {
u32 rx_control_0; /* RX control word 0 */
u32 rx_control_1; /* RX control word 1 */
} __packed;
-/* RX control word 0 field/sflags */
-#define AR5K_DESC_RX_CTL0 0x00000000
-
/* RX control word 1 fields/flags */
-#define AR5K_DESC_RX_CTL1_BUF_LEN 0x00000fff
-#define AR5K_DESC_RX_CTL1_INTREQ 0x00002000
+#define AR5K_DESC_RX_CTL1_BUF_LEN 0x00000fff /* data buffer length */
+#define AR5K_DESC_RX_CTL1_INTREQ 0x00002000 /* RX interrupt request */
/*
- * common hardware RX status descriptor
- * 5210/11 and 5212 differ only in the flags defined below
+ * Common hardware RX status descriptor
+ * 5210, 5211 and 5212 differ only in the fields and flags defined below
*/
struct ath5k_hw_rx_status {
u32 rx_status_0; /* RX status word 0 */
@@ -47,81 +43,69 @@ struct ath5k_hw_rx_status {
/* 5210/5211 */
/* RX status word 0 fields/flags */
-#define AR5K_5210_RX_DESC_STATUS0_DATA_LEN 0x00000fff
-#define AR5K_5210_RX_DESC_STATUS0_MORE 0x00001000
-#define AR5K_5210_RX_DESC_STATUS0_RECEIVE_RATE 0x00078000
+#define AR5K_5210_RX_DESC_STATUS0_DATA_LEN 0x00000fff /* RX data length */
+#define AR5K_5210_RX_DESC_STATUS0_MORE 0x00001000 /* more desc for this frame */
+#define AR5K_5210_RX_DESC_STATUS0_RECEIVE_ANT_5210 0x00004000 /* [5210] receive on ant 1 */
+#define AR5K_5210_RX_DESC_STATUS0_RECEIVE_RATE 0x00078000 /* reception rate */
#define AR5K_5210_RX_DESC_STATUS0_RECEIVE_RATE_S 15
-#define AR5K_5210_RX_DESC_STATUS0_RECEIVE_SIGNAL 0x07f80000
+#define AR5K_5210_RX_DESC_STATUS0_RECEIVE_SIGNAL 0x07f80000 /* rssi */
#define AR5K_5210_RX_DESC_STATUS0_RECEIVE_SIGNAL_S 19
-#define AR5K_5210_RX_DESC_STATUS0_RECEIVE_ANTENNA 0x38000000
-#define AR5K_5210_RX_DESC_STATUS0_RECEIVE_ANTENNA_S 27
+#define AR5K_5210_RX_DESC_STATUS0_RECEIVE_ANT_5211 0x38000000 /* [5211] receive antenna */
+#define AR5K_5210_RX_DESC_STATUS0_RECEIVE_ANT_5211_S 27
/* RX status word 1 fields/flags */
-#define AR5K_5210_RX_DESC_STATUS1_DONE 0x00000001
-#define AR5K_5210_RX_DESC_STATUS1_FRAME_RECEIVE_OK 0x00000002
-#define AR5K_5210_RX_DESC_STATUS1_CRC_ERROR 0x00000004
-#define AR5K_5210_RX_DESC_STATUS1_FIFO_OVERRUN 0x00000008
-#define AR5K_5210_RX_DESC_STATUS1_DECRYPT_CRC_ERROR 0x00000010
-#define AR5K_5210_RX_DESC_STATUS1_PHY_ERROR 0x000000e0
+#define AR5K_5210_RX_DESC_STATUS1_DONE 0x00000001 /* descriptor complete */
+#define AR5K_5210_RX_DESC_STATUS1_FRAME_RECEIVE_OK 0x00000002 /* reception success */
+#define AR5K_5210_RX_DESC_STATUS1_CRC_ERROR 0x00000004 /* CRC error */
+#define AR5K_5210_RX_DESC_STATUS1_FIFO_OVERRUN_5210 0x00000008 /* [5210] FIFO overrun */
+#define AR5K_5210_RX_DESC_STATUS1_DECRYPT_CRC_ERROR 0x00000010 /* decyption CRC failure */
+#define AR5K_5210_RX_DESC_STATUS1_PHY_ERROR 0x000000e0 /* PHY error */
#define AR5K_5210_RX_DESC_STATUS1_PHY_ERROR_S 5
-#define AR5K_5210_RX_DESC_STATUS1_KEY_INDEX_VALID 0x00000100
-#define AR5K_5210_RX_DESC_STATUS1_KEY_INDEX 0x00007e00
+#define AR5K_5210_RX_DESC_STATUS1_KEY_INDEX_VALID 0x00000100 /* key index valid */
+#define AR5K_5210_RX_DESC_STATUS1_KEY_INDEX 0x00007e00 /* decyption key index */
#define AR5K_5210_RX_DESC_STATUS1_KEY_INDEX_S 9
-#define AR5K_5210_RX_DESC_STATUS1_RECEIVE_TIMESTAMP 0x0fff8000
+#define AR5K_5210_RX_DESC_STATUS1_RECEIVE_TIMESTAMP 0x0fff8000 /* 13 bit of TSF */
#define AR5K_5210_RX_DESC_STATUS1_RECEIVE_TIMESTAMP_S 15
-#define AR5K_5210_RX_DESC_STATUS1_KEY_CACHE_MISS 0x10000000
+#define AR5K_5210_RX_DESC_STATUS1_KEY_CACHE_MISS 0x10000000 /* key cache miss */
/* 5212 */
/* RX status word 0 fields/flags */
-#define AR5K_5212_RX_DESC_STATUS0_DATA_LEN 0x00000fff
-#define AR5K_5212_RX_DESC_STATUS0_MORE 0x00001000
-#define AR5K_5212_RX_DESC_STATUS0_DECOMP_CRC_ERROR 0x00002000
-#define AR5K_5212_RX_DESC_STATUS0_RECEIVE_RATE 0x000f8000
+#define AR5K_5212_RX_DESC_STATUS0_DATA_LEN 0x00000fff /* RX data length */
+#define AR5K_5212_RX_DESC_STATUS0_MORE 0x00001000 /* more desc for this frame */
+#define AR5K_5212_RX_DESC_STATUS0_DECOMP_CRC_ERROR 0x00002000 /* decompression CRC error */
+#define AR5K_5212_RX_DESC_STATUS0_RECEIVE_RATE 0x000f8000 /* reception rate */
#define AR5K_5212_RX_DESC_STATUS0_RECEIVE_RATE_S 15
-#define AR5K_5212_RX_DESC_STATUS0_RECEIVE_SIGNAL 0x0ff00000
+#define AR5K_5212_RX_DESC_STATUS0_RECEIVE_SIGNAL 0x0ff00000 /* rssi */
#define AR5K_5212_RX_DESC_STATUS0_RECEIVE_SIGNAL_S 20
-#define AR5K_5212_RX_DESC_STATUS0_RECEIVE_ANTENNA 0xf0000000
+#define AR5K_5212_RX_DESC_STATUS0_RECEIVE_ANTENNA 0xf0000000 /* receive antenna */
#define AR5K_5212_RX_DESC_STATUS0_RECEIVE_ANTENNA_S 28
/* RX status word 1 fields/flags */
-#define AR5K_5212_RX_DESC_STATUS1_DONE 0x00000001
-#define AR5K_5212_RX_DESC_STATUS1_FRAME_RECEIVE_OK 0x00000002
-#define AR5K_5212_RX_DESC_STATUS1_CRC_ERROR 0x00000004
-#define AR5K_5212_RX_DESC_STATUS1_DECRYPT_CRC_ERROR 0x00000008
-#define AR5K_5212_RX_DESC_STATUS1_PHY_ERROR 0x00000010
-#define AR5K_5212_RX_DESC_STATUS1_MIC_ERROR 0x00000020
-#define AR5K_5212_RX_DESC_STATUS1_KEY_INDEX_VALID 0x00000100
-#define AR5K_5212_RX_DESC_STATUS1_KEY_INDEX 0x0000fe00
+#define AR5K_5212_RX_DESC_STATUS1_DONE 0x00000001 /* descriptor complete */
+#define AR5K_5212_RX_DESC_STATUS1_FRAME_RECEIVE_OK 0x00000002 /* frame reception success */
+#define AR5K_5212_RX_DESC_STATUS1_CRC_ERROR 0x00000004 /* CRC error */
+#define AR5K_5212_RX_DESC_STATUS1_DECRYPT_CRC_ERROR 0x00000008 /* decryption CRC failure */
+#define AR5K_5212_RX_DESC_STATUS1_PHY_ERROR 0x00000010 /* PHY error */
+#define AR5K_5212_RX_DESC_STATUS1_MIC_ERROR 0x00000020 /* MIC decrypt error */
+#define AR5K_5212_RX_DESC_STATUS1_KEY_INDEX_VALID 0x00000100 /* key index valid */
+#define AR5K_5212_RX_DESC_STATUS1_KEY_INDEX 0x0000fe00 /* decryption key index */
#define AR5K_5212_RX_DESC_STATUS1_KEY_INDEX_S 9
-#define AR5K_5212_RX_DESC_STATUS1_RECEIVE_TIMESTAMP 0x7fff0000
+#define AR5K_5212_RX_DESC_STATUS1_RECEIVE_TIMESTAMP 0x7fff0000 /* first 15bit of the TSF */
#define AR5K_5212_RX_DESC_STATUS1_RECEIVE_TIMESTAMP_S 16
-#define AR5K_5212_RX_DESC_STATUS1_KEY_CACHE_MISS 0x80000000
-
-/*
- * common hardware RX error descriptor
- */
-struct ath5k_hw_rx_error {
- u32 rx_error_0; /* RX status word 0 */
- u32 rx_error_1; /* RX status word 1 */
-} __packed;
-
-/* RX error word 0 fields/flags */
-#define AR5K_RX_DESC_ERROR0 0x00000000
-
-/* RX error word 1 fields/flags */
-#define AR5K_RX_DESC_ERROR1_PHY_ERROR_CODE 0x0000ff00
-#define AR5K_RX_DESC_ERROR1_PHY_ERROR_CODE_S 8
+#define AR5K_5212_RX_DESC_STATUS1_KEY_CACHE_MISS 0x80000000 /* key cache miss */
+#define AR5K_5212_RX_DESC_STATUS1_PHY_ERROR_CODE 0x0000ff00 /* phy error code overlays key index and valid fields */
+#define AR5K_5212_RX_DESC_STATUS1_PHY_ERROR_CODE_S 8
/**
* enum ath5k_phy_error_code - PHY Error codes
*/
enum ath5k_phy_error_code {
- AR5K_RX_PHY_ERROR_UNDERRUN = 0, /* Transmit underrun */
+ AR5K_RX_PHY_ERROR_UNDERRUN = 0, /* Transmit underrun, [5210] No error */
AR5K_RX_PHY_ERROR_TIMING = 1, /* Timing error */
AR5K_RX_PHY_ERROR_PARITY = 2, /* Illegal parity */
AR5K_RX_PHY_ERROR_RATE = 3, /* Illegal rate */
AR5K_RX_PHY_ERROR_LENGTH = 4, /* Illegal length */
- AR5K_RX_PHY_ERROR_RADAR = 5, /* Radar detect */
+ AR5K_RX_PHY_ERROR_RADAR = 5, /* Radar detect, [5210] 64 QAM rate */
AR5K_RX_PHY_ERROR_SERVICE = 6, /* Illegal service */
AR5K_RX_PHY_ERROR_TOR = 7, /* Transmit override receive */
/* these are specific to the 5212 */
@@ -148,112 +132,111 @@ struct ath5k_hw_2w_tx_ctl {
} __packed;
/* TX control word 0 fields/flags */
-#define AR5K_2W_TX_DESC_CTL0_FRAME_LEN 0x00000fff
-#define AR5K_2W_TX_DESC_CTL0_HEADER_LEN 0x0003f000 /*[5210 ?]*/
-#define AR5K_2W_TX_DESC_CTL0_HEADER_LEN_S 12
-#define AR5K_2W_TX_DESC_CTL0_XMIT_RATE 0x003c0000
+#define AR5K_2W_TX_DESC_CTL0_FRAME_LEN 0x00000fff /* frame length */
+#define AR5K_2W_TX_DESC_CTL0_HEADER_LEN_5210 0x0003f000 /* [5210] header length */
+#define AR5K_2W_TX_DESC_CTL0_HEADER_LEN_5210_S 12
+#define AR5K_2W_TX_DESC_CTL0_XMIT_RATE 0x003c0000 /* tx rate */
#define AR5K_2W_TX_DESC_CTL0_XMIT_RATE_S 18
-#define AR5K_2W_TX_DESC_CTL0_RTSENA 0x00400000
-#define AR5K_2W_TX_DESC_CTL0_CLRDMASK 0x01000000
-#define AR5K_2W_TX_DESC_CTL0_LONG_PACKET 0x00800000 /*[5210]*/
-#define AR5K_2W_TX_DESC_CTL0_VEOL 0x00800000 /*[5211]*/
-#define AR5K_2W_TX_DESC_CTL0_FRAME_TYPE 0x1c000000 /*[5210]*/
-#define AR5K_2W_TX_DESC_CTL0_FRAME_TYPE_S 26
-#define AR5K_2W_TX_DESC_CTL0_ANT_MODE_XMIT_5210 0x02000000
-#define AR5K_2W_TX_DESC_CTL0_ANT_MODE_XMIT_5211 0x1e000000
-
+#define AR5K_2W_TX_DESC_CTL0_RTSENA 0x00400000 /* RTS/CTS enable */
+#define AR5K_2W_TX_DESC_CTL0_LONG_PACKET_5210 0x00800000 /* [5210] long packet */
+#define AR5K_2W_TX_DESC_CTL0_VEOL_5211 0x00800000 /* [5211] virtual end-of-list */
+#define AR5K_2W_TX_DESC_CTL0_CLRDMASK 0x01000000 /* clear destination mask */
+#define AR5K_2W_TX_DESC_CTL0_ANT_MODE_XMIT_5210 0x02000000 /* [5210] antenna selection */
+#define AR5K_2W_TX_DESC_CTL0_ANT_MODE_XMIT_5211 0x1e000000 /* [5211] antenna selection */
#define AR5K_2W_TX_DESC_CTL0_ANT_MODE_XMIT \
(ah->ah_version == AR5K_AR5210 ? \
AR5K_2W_TX_DESC_CTL0_ANT_MODE_XMIT_5210 : \
AR5K_2W_TX_DESC_CTL0_ANT_MODE_XMIT_5211)
-
#define AR5K_2W_TX_DESC_CTL0_ANT_MODE_XMIT_S 25
-#define AR5K_2W_TX_DESC_CTL0_INTREQ 0x20000000
-#define AR5K_2W_TX_DESC_CTL0_ENCRYPT_KEY_VALID 0x40000000
+#define AR5K_2W_TX_DESC_CTL0_FRAME_TYPE_5210 0x1c000000 /* [5210] frame type */
+#define AR5K_2W_TX_DESC_CTL0_FRAME_TYPE_5210_S 26
+#define AR5K_2W_TX_DESC_CTL0_INTREQ 0x20000000 /* TX interrupt request */
+#define AR5K_2W_TX_DESC_CTL0_ENCRYPT_KEY_VALID 0x40000000 /* key is valid */
/* TX control word 1 fields/flags */
-#define AR5K_2W_TX_DESC_CTL1_BUF_LEN 0x00000fff
-#define AR5K_2W_TX_DESC_CTL1_MORE 0x00001000
-#define AR5K_2W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX_5210 0x0007e000
-#define AR5K_2W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX_5211 0x000fe000
-
-#define AR5K_2W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX \
+#define AR5K_2W_TX_DESC_CTL1_BUF_LEN 0x00000fff /* data buffer length */
+#define AR5K_2W_TX_DESC_CTL1_MORE 0x00001000 /* more desc for this frame */
+#define AR5K_2W_TX_DESC_CTL1_ENC_KEY_IDX_5210 0x0007e000 /* [5210] key table index */
+#define AR5K_2W_TX_DESC_CTL1_ENC_KEY_IDX_5211 0x000fe000 /* [5211] key table index */
+#define AR5K_2W_TX_DESC_CTL1_ENC_KEY_IDX \
(ah->ah_version == AR5K_AR5210 ? \
- AR5K_2W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX_5210 : \
- AR5K_2W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX_5211)
-
-#define AR5K_2W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX_S 13
-#define AR5K_2W_TX_DESC_CTL1_FRAME_TYPE 0x00700000 /*[5211]*/
-#define AR5K_2W_TX_DESC_CTL1_FRAME_TYPE_S 20
-#define AR5K_2W_TX_DESC_CTL1_NOACK 0x00800000 /*[5211]*/
-#define AR5K_2W_TX_DESC_CTL1_RTS_DURATION 0xfff80000 /*[5210 ?]*/
+ AR5K_2W_TX_DESC_CTL1_ENC_KEY_IDX_5210 : \
+ AR5K_2W_TX_DESC_CTL1_ENC_KEY_IDX_5211)
+#define AR5K_2W_TX_DESC_CTL1_ENC_KEY_IDX_S 13
+#define AR5K_2W_TX_DESC_CTL1_FRAME_TYPE_5211 0x00700000 /* [5211] frame type */
+#define AR5K_2W_TX_DESC_CTL1_FRAME_TYPE_5211_S 20
+#define AR5K_2W_TX_DESC_CTL1_NOACK_5211 0x00800000 /* [5211] no ACK */
+#define AR5K_2W_TX_DESC_CTL1_RTS_DURATION_5210 0xfff80000 /* [5210] lower 13 bit of duration */
/* Frame types */
-#define AR5K_AR5210_TX_DESC_FRAME_TYPE_NORMAL 0x00
-#define AR5K_AR5210_TX_DESC_FRAME_TYPE_ATIM 0x04
-#define AR5K_AR5210_TX_DESC_FRAME_TYPE_PSPOLL 0x08
-#define AR5K_AR5210_TX_DESC_FRAME_TYPE_NO_DELAY 0x0c
-#define AR5K_AR5210_TX_DESC_FRAME_TYPE_PIFS 0x10
+#define AR5K_AR5210_TX_DESC_FRAME_TYPE_NORMAL 0
+#define AR5K_AR5210_TX_DESC_FRAME_TYPE_ATIM 1
+#define AR5K_AR5210_TX_DESC_FRAME_TYPE_PSPOLL 2
+#define AR5K_AR5210_TX_DESC_FRAME_TYPE_NO_DELAY 3
+#define AR5K_AR5211_TX_DESC_FRAME_TYPE_BEACON 3
+#define AR5K_AR5210_TX_DESC_FRAME_TYPE_PIFS 4
+#define AR5K_AR5211_TX_DESC_FRAME_TYPE_PRESP 4
/*
* 5212 hardware 4-word TX control descriptor
*/
struct ath5k_hw_4w_tx_ctl {
u32 tx_control_0; /* TX control word 0 */
+ u32 tx_control_1; /* TX control word 1 */
+ u32 tx_control_2; /* TX control word 2 */
+ u32 tx_control_3; /* TX control word 3 */
+} __packed;
-#define AR5K_4W_TX_DESC_CTL0_FRAME_LEN 0x00000fff
-#define AR5K_4W_TX_DESC_CTL0_XMIT_POWER 0x003f0000
+/* TX control word 0 fields/flags */
+#define AR5K_4W_TX_DESC_CTL0_FRAME_LEN 0x00000fff /* frame length */
+#define AR5K_4W_TX_DESC_CTL0_XMIT_POWER 0x003f0000 /* transmit power */
#define AR5K_4W_TX_DESC_CTL0_XMIT_POWER_S 16
-#define AR5K_4W_TX_DESC_CTL0_RTSENA 0x00400000
-#define AR5K_4W_TX_DESC_CTL0_VEOL 0x00800000
-#define AR5K_4W_TX_DESC_CTL0_CLRDMASK 0x01000000
-#define AR5K_4W_TX_DESC_CTL0_ANT_MODE_XMIT 0x1e000000
+#define AR5K_4W_TX_DESC_CTL0_RTSENA 0x00400000 /* RTS/CTS enable */
+#define AR5K_4W_TX_DESC_CTL0_VEOL 0x00800000 /* virtual end-of-list */
+#define AR5K_4W_TX_DESC_CTL0_CLRDMASK 0x01000000 /* clear destination mask */
+#define AR5K_4W_TX_DESC_CTL0_ANT_MODE_XMIT 0x1e000000 /* TX antenna selection */
#define AR5K_4W_TX_DESC_CTL0_ANT_MODE_XMIT_S 25
-#define AR5K_4W_TX_DESC_CTL0_INTREQ 0x20000000
-#define AR5K_4W_TX_DESC_CTL0_ENCRYPT_KEY_VALID 0x40000000
-#define AR5K_4W_TX_DESC_CTL0_CTSENA 0x80000000
-
- u32 tx_control_1; /* TX control word 1 */
+#define AR5K_4W_TX_DESC_CTL0_INTREQ 0x20000000 /* TX interrupt request */
+#define AR5K_4W_TX_DESC_CTL0_ENCRYPT_KEY_VALID 0x40000000 /* destination index valid */
+#define AR5K_4W_TX_DESC_CTL0_CTSENA 0x80000000 /* precede frame with CTS */
-#define AR5K_4W_TX_DESC_CTL1_BUF_LEN 0x00000fff
-#define AR5K_4W_TX_DESC_CTL1_MORE 0x00001000
-#define AR5K_4W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX 0x000fe000
-#define AR5K_4W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX_S 13
-#define AR5K_4W_TX_DESC_CTL1_FRAME_TYPE 0x00f00000
+/* TX control word 1 fields/flags */
+#define AR5K_4W_TX_DESC_CTL1_BUF_LEN 0x00000fff /* data buffer length */
+#define AR5K_4W_TX_DESC_CTL1_MORE 0x00001000 /* more desc for this frame */
+#define AR5K_4W_TX_DESC_CTL1_ENCRYPT_KEY_IDX 0x000fe000 /* destination table index */
+#define AR5K_4W_TX_DESC_CTL1_ENCRYPT_KEY_IDX_S 13
+#define AR5K_4W_TX_DESC_CTL1_FRAME_TYPE 0x00f00000 /* frame type */
#define AR5K_4W_TX_DESC_CTL1_FRAME_TYPE_S 20
-#define AR5K_4W_TX_DESC_CTL1_NOACK 0x01000000
-#define AR5K_4W_TX_DESC_CTL1_COMP_PROC 0x06000000
+#define AR5K_4W_TX_DESC_CTL1_NOACK 0x01000000 /* no ACK */
+#define AR5K_4W_TX_DESC_CTL1_COMP_PROC 0x06000000 /* compression processing */
#define AR5K_4W_TX_DESC_CTL1_COMP_PROC_S 25
-#define AR5K_4W_TX_DESC_CTL1_COMP_IV_LEN 0x18000000
+#define AR5K_4W_TX_DESC_CTL1_COMP_IV_LEN 0x18000000 /* length of frame IV */
#define AR5K_4W_TX_DESC_CTL1_COMP_IV_LEN_S 27
-#define AR5K_4W_TX_DESC_CTL1_COMP_ICV_LEN 0x60000000
+#define AR5K_4W_TX_DESC_CTL1_COMP_ICV_LEN 0x60000000 /* length of frame ICV */
#define AR5K_4W_TX_DESC_CTL1_COMP_ICV_LEN_S 29
- u32 tx_control_2; /* TX control word 2 */
-
-#define AR5K_4W_TX_DESC_CTL2_RTS_DURATION 0x00007fff
-#define AR5K_4W_TX_DESC_CTL2_DURATION_UPDATE_ENABLE 0x00008000
-#define AR5K_4W_TX_DESC_CTL2_XMIT_TRIES0 0x000f0000
-#define AR5K_4W_TX_DESC_CTL2_XMIT_TRIES0_S 16
-#define AR5K_4W_TX_DESC_CTL2_XMIT_TRIES1 0x00f00000
-#define AR5K_4W_TX_DESC_CTL2_XMIT_TRIES1_S 20
-#define AR5K_4W_TX_DESC_CTL2_XMIT_TRIES2 0x0f000000
-#define AR5K_4W_TX_DESC_CTL2_XMIT_TRIES2_S 24
-#define AR5K_4W_TX_DESC_CTL2_XMIT_TRIES3 0xf0000000
-#define AR5K_4W_TX_DESC_CTL2_XMIT_TRIES3_S 28
-
- u32 tx_control_3; /* TX control word 3 */
-
-#define AR5K_4W_TX_DESC_CTL3_XMIT_RATE0 0x0000001f
-#define AR5K_4W_TX_DESC_CTL3_XMIT_RATE1 0x000003e0
+/* TX control word 2 fields/flags */
+#define AR5K_4W_TX_DESC_CTL2_RTS_DURATION 0x00007fff /* RTS/CTS duration */
+#define AR5K_4W_TX_DESC_CTL2_DURATION_UPD_EN 0x00008000 /* frame duration update */
+#define AR5K_4W_TX_DESC_CTL2_XMIT_TRIES0 0x000f0000 /* series 0 max attempts */
+#define AR5K_4W_TX_DESC_CTL2_XMIT_TRIES0_S 16
+#define AR5K_4W_TX_DESC_CTL2_XMIT_TRIES1 0x00f00000 /* series 1 max attempts */
+#define AR5K_4W_TX_DESC_CTL2_XMIT_TRIES1_S 20
+#define AR5K_4W_TX_DESC_CTL2_XMIT_TRIES2 0x0f000000 /* series 2 max attempts */
+#define AR5K_4W_TX_DESC_CTL2_XMIT_TRIES2_S 24
+#define AR5K_4W_TX_DESC_CTL2_XMIT_TRIES3 0xf0000000 /* series 3 max attempts */
+#define AR5K_4W_TX_DESC_CTL2_XMIT_TRIES3_S 28
+
+/* TX control word 3 fields/flags */
+#define AR5K_4W_TX_DESC_CTL3_XMIT_RATE0 0x0000001f /* series 0 tx rate */
+#define AR5K_4W_TX_DESC_CTL3_XMIT_RATE1 0x000003e0 /* series 1 tx rate */
#define AR5K_4W_TX_DESC_CTL3_XMIT_RATE1_S 5
-#define AR5K_4W_TX_DESC_CTL3_XMIT_RATE2 0x00007c00
+#define AR5K_4W_TX_DESC_CTL3_XMIT_RATE2 0x00007c00 /* series 2 tx rate */
#define AR5K_4W_TX_DESC_CTL3_XMIT_RATE2_S 10
-#define AR5K_4W_TX_DESC_CTL3_XMIT_RATE3 0x000f8000
+#define AR5K_4W_TX_DESC_CTL3_XMIT_RATE3 0x000f8000 /* series 3 tx rate */
#define AR5K_4W_TX_DESC_CTL3_XMIT_RATE3_S 15
-#define AR5K_4W_TX_DESC_CTL3_RTS_CTS_RATE 0x01f00000
+#define AR5K_4W_TX_DESC_CTL3_RTS_CTS_RATE 0x01f00000 /* RTS or CTS rate */
#define AR5K_4W_TX_DESC_CTL3_RTS_CTS_RATE_S 20
-} __packed;
/*
* Common TX status descriptor
@@ -264,37 +247,34 @@ struct ath5k_hw_tx_status {
} __packed;
/* TX status word 0 fields/flags */
-#define AR5K_DESC_TX_STATUS0_FRAME_XMIT_OK 0x00000001
-#define AR5K_DESC_TX_STATUS0_EXCESSIVE_RETRIES 0x00000002
-#define AR5K_DESC_TX_STATUS0_FIFO_UNDERRUN 0x00000004
-#define AR5K_DESC_TX_STATUS0_FILTERED 0x00000008
-/*???
-#define AR5K_DESC_TX_STATUS0_RTS_FAIL_COUNT 0x000000f0
-#define AR5K_DESC_TX_STATUS0_RTS_FAIL_COUNT_S 4
-*/
-#define AR5K_DESC_TX_STATUS0_SHORT_RETRY_COUNT 0x000000f0
+#define AR5K_DESC_TX_STATUS0_FRAME_XMIT_OK 0x00000001 /* TX success */
+#define AR5K_DESC_TX_STATUS0_EXCESSIVE_RETRIES 0x00000002 /* excessive retries */
+#define AR5K_DESC_TX_STATUS0_FIFO_UNDERRUN 0x00000004 /* FIFO underrun */
+#define AR5K_DESC_TX_STATUS0_FILTERED 0x00000008 /* TX filter indication */
+/* according to the HAL sources the spec has short/long retry counts reversed.
+ * we have it reversed to the HAL sources as well, for 5210 and 5211.
+ * For 5212 these fields are defined as RTS_FAIL_COUNT and DATA_FAIL_COUNT,
+ * but used respectively as SHORT and LONG retry count in the code later. This
+ * is consistent with the definitions here... TODO: check */
+#define AR5K_DESC_TX_STATUS0_SHORT_RETRY_COUNT 0x000000f0 /* short retry count */
#define AR5K_DESC_TX_STATUS0_SHORT_RETRY_COUNT_S 4
-/*???
-#define AR5K_DESC_TX_STATUS0_DATA_FAIL_COUNT 0x00000f00
-#define AR5K_DESC_TX_STATUS0_DATA_FAIL_COUNT_S 8
-*/
-#define AR5K_DESC_TX_STATUS0_LONG_RETRY_COUNT 0x00000f00
+#define AR5K_DESC_TX_STATUS0_LONG_RETRY_COUNT 0x00000f00 /* long retry count */
#define AR5K_DESC_TX_STATUS0_LONG_RETRY_COUNT_S 8
-#define AR5K_DESC_TX_STATUS0_VIRT_COLL_COUNT 0x0000f000
-#define AR5K_DESC_TX_STATUS0_VIRT_COLL_COUNT_S 12
-#define AR5K_DESC_TX_STATUS0_SEND_TIMESTAMP 0xffff0000
+#define AR5K_DESC_TX_STATUS0_VIRTCOLL_CT_5211 0x0000f000 /* [5211+] virtual collision count */
+#define AR5K_DESC_TX_STATUS0_VIRTCOLL_CT_5212_S 12
+#define AR5K_DESC_TX_STATUS0_SEND_TIMESTAMP 0xffff0000 /* TX timestamp */
#define AR5K_DESC_TX_STATUS0_SEND_TIMESTAMP_S 16
/* TX status word 1 fields/flags */
-#define AR5K_DESC_TX_STATUS1_DONE 0x00000001
-#define AR5K_DESC_TX_STATUS1_SEQ_NUM 0x00001ffe
+#define AR5K_DESC_TX_STATUS1_DONE 0x00000001 /* descriptor complete */
+#define AR5K_DESC_TX_STATUS1_SEQ_NUM 0x00001ffe /* TX sequence number */
#define AR5K_DESC_TX_STATUS1_SEQ_NUM_S 1
-#define AR5K_DESC_TX_STATUS1_ACK_SIG_STRENGTH 0x001fe000
+#define AR5K_DESC_TX_STATUS1_ACK_SIG_STRENGTH 0x001fe000 /* signal strength of ACK */
#define AR5K_DESC_TX_STATUS1_ACK_SIG_STRENGTH_S 13
-#define AR5K_DESC_TX_STATUS1_FINAL_TS_INDEX 0x00600000
-#define AR5K_DESC_TX_STATUS1_FINAL_TS_INDEX_S 21
-#define AR5K_DESC_TX_STATUS1_COMP_SUCCESS 0x00800000
-#define AR5K_DESC_TX_STATUS1_XMIT_ANTENNA 0x01000000
+#define AR5K_DESC_TX_STATUS1_FINAL_TS_IX_5212 0x00600000 /* [5212] final TX attempt series ix */
+#define AR5K_DESC_TX_STATUS1_FINAL_TS_IX_5212_S 21
+#define AR5K_DESC_TX_STATUS1_COMP_SUCCESS_5212 0x00800000 /* [5212] compression status */
+#define AR5K_DESC_TX_STATUS1_XMIT_ANTENNA_5212 0x01000000 /* [5212] transmit antenna */
/*
* 5210/5211 hardware TX descriptor
@@ -313,18 +293,15 @@ struct ath5k_hw_5212_tx_desc {
} __packed;
/*
- * common hardware RX descriptor
+ * Common hardware RX descriptor
*/
struct ath5k_hw_all_rx_desc {
- struct ath5k_hw_rx_ctl rx_ctl;
- union {
- struct ath5k_hw_rx_status rx_stat;
- struct ath5k_hw_rx_error rx_err;
- } u;
+ struct ath5k_hw_rx_ctl rx_ctl;
+ struct ath5k_hw_rx_status rx_stat;
} __packed;
/*
- * Atheros hardware descriptor
+ * Atheros hardware DMA descriptor
* This is read and written to by the hardware
*/
struct ath5k_desc {
@@ -346,4 +323,3 @@ struct ath5k_desc {
#define AR5K_TXDESC_CTSENA 0x0008
#define AR5K_TXDESC_INTREQ 0x0010
#define AR5K_TXDESC_VEOL 0x0020 /*[5211+]*/
-
diff --git a/drivers/net/wireless/ath/ath5k/dma.c b/drivers/net/wireless/ath/ath5k/dma.c
index 941b51130a6..484f31870ba 100644
--- a/drivers/net/wireless/ath/ath5k/dma.c
+++ b/drivers/net/wireless/ath/ath5k/dma.c
@@ -48,7 +48,6 @@
*/
void ath5k_hw_start_rx_dma(struct ath5k_hw *ah)
{
- ATH5K_TRACE(ah->ah_sc);
ath5k_hw_reg_write(ah, AR5K_CR_RXE, AR5K_CR);
ath5k_hw_reg_read(ah, AR5K_CR);
}
@@ -62,7 +61,6 @@ int ath5k_hw_stop_rx_dma(struct ath5k_hw *ah)
{
unsigned int i;
- ATH5K_TRACE(ah->ah_sc);
ath5k_hw_reg_write(ah, AR5K_CR_RXD, AR5K_CR);
/*
@@ -96,8 +94,6 @@ u32 ath5k_hw_get_rxdp(struct ath5k_hw *ah)
*/
void ath5k_hw_set_rxdp(struct ath5k_hw *ah, u32 phys_addr)
{
- ATH5K_TRACE(ah->ah_sc);
-
ath5k_hw_reg_write(ah, phys_addr, AR5K_RXDP);
}
@@ -125,7 +121,6 @@ int ath5k_hw_start_tx_dma(struct ath5k_hw *ah, unsigned int queue)
{
u32 tx_queue;
- ATH5K_TRACE(ah->ah_sc);
AR5K_ASSERT_ENTRY(queue, ah->ah_capabilities.cap_queues.q_tx_num);
/* Return if queue is declared inactive */
@@ -186,7 +181,6 @@ int ath5k_hw_stop_tx_dma(struct ath5k_hw *ah, unsigned int queue)
unsigned int i = 40;
u32 tx_queue, pending;
- ATH5K_TRACE(ah->ah_sc);
AR5K_ASSERT_ENTRY(queue, ah->ah_capabilities.cap_queues.q_tx_num);
/* Return if queue is declared inactive */
@@ -297,7 +291,6 @@ u32 ath5k_hw_get_txdp(struct ath5k_hw *ah, unsigned int queue)
{
u16 tx_reg;
- ATH5K_TRACE(ah->ah_sc);
AR5K_ASSERT_ENTRY(queue, ah->ah_capabilities.cap_queues.q_tx_num);
/*
@@ -340,7 +333,6 @@ int ath5k_hw_set_txdp(struct ath5k_hw *ah, unsigned int queue, u32 phys_addr)
{
u16 tx_reg;
- ATH5K_TRACE(ah->ah_sc);
AR5K_ASSERT_ENTRY(queue, ah->ah_capabilities.cap_queues.q_tx_num);
/*
@@ -400,8 +392,6 @@ int ath5k_hw_update_tx_triglevel(struct ath5k_hw *ah, bool increase)
u32 trigger_level, imr;
int ret = -EIO;
- ATH5K_TRACE(ah->ah_sc);
-
/*
* Disable interrupts by setting the mask
*/
@@ -451,7 +441,6 @@ done:
*/
bool ath5k_hw_is_intr_pending(struct ath5k_hw *ah)
{
- ATH5K_TRACE(ah->ah_sc);
return ath5k_hw_reg_read(ah, AR5K_INTPEND) == 1 ? 1 : 0;
}
@@ -475,8 +464,6 @@ int ath5k_hw_get_isr(struct ath5k_hw *ah, enum ath5k_int *interrupt_mask)
{
u32 data;
- ATH5K_TRACE(ah->ah_sc);
-
/*
* Read interrupt status from the Interrupt Status register
* on 5210
diff --git a/drivers/net/wireless/ath/ath5k/eeprom.c b/drivers/net/wireless/ath/ath5k/eeprom.c
index ed0263672d6..ae316fec4a6 100644
--- a/drivers/net/wireless/ath/ath5k/eeprom.c
+++ b/drivers/net/wireless/ath/ath5k/eeprom.c
@@ -35,7 +35,6 @@ static int ath5k_hw_eeprom_read(struct ath5k_hw *ah, u32 offset, u16 *data)
{
u32 status, timeout;
- ATH5K_TRACE(ah->ah_sc);
/*
* Initialize EEPROM access
*/
@@ -715,7 +714,7 @@ ath5k_eeprom_convert_pcal_info_5111(struct ath5k_hw *ah, int mode,
/* Only one curve for RF5111
* find out which one and place
- * in in pd_curves.
+ * in pd_curves.
* Note: ee_x_gain is reversed here */
for (idx = 0; idx < AR5K_EEPROM_N_PD_CURVES; idx++) {
diff --git a/drivers/net/wireless/ath/ath5k/gpio.c b/drivers/net/wireless/ath/ath5k/gpio.c
index 64a27e73d02..bc90503f4b7 100644
--- a/drivers/net/wireless/ath/ath5k/gpio.c
+++ b/drivers/net/wireless/ath/ath5k/gpio.c
@@ -34,8 +34,6 @@ void ath5k_hw_set_ledstate(struct ath5k_hw *ah, unsigned int state)
/*5210 has different led mode handling*/
u32 led_5210;
- ATH5K_TRACE(ah->ah_sc);
-
/*Reset led status*/
if (ah->ah_version != AR5K_AR5210)
AR5K_REG_DISABLE_BITS(ah, AR5K_PCICFG,
@@ -82,7 +80,6 @@ void ath5k_hw_set_ledstate(struct ath5k_hw *ah, unsigned int state)
*/
int ath5k_hw_set_gpio_input(struct ath5k_hw *ah, u32 gpio)
{
- ATH5K_TRACE(ah->ah_sc);
if (gpio >= AR5K_NUM_GPIO)
return -EINVAL;
@@ -98,7 +95,6 @@ int ath5k_hw_set_gpio_input(struct ath5k_hw *ah, u32 gpio)
*/
int ath5k_hw_set_gpio_output(struct ath5k_hw *ah, u32 gpio)
{
- ATH5K_TRACE(ah->ah_sc);
if (gpio >= AR5K_NUM_GPIO)
return -EINVAL;
@@ -114,7 +110,6 @@ int ath5k_hw_set_gpio_output(struct ath5k_hw *ah, u32 gpio)
*/
u32 ath5k_hw_get_gpio(struct ath5k_hw *ah, u32 gpio)
{
- ATH5K_TRACE(ah->ah_sc);
if (gpio >= AR5K_NUM_GPIO)
return 0xffffffff;
@@ -129,7 +124,6 @@ u32 ath5k_hw_get_gpio(struct ath5k_hw *ah, u32 gpio)
int ath5k_hw_set_gpio(struct ath5k_hw *ah, u32 gpio, u32 val)
{
u32 data;
- ATH5K_TRACE(ah->ah_sc);
if (gpio >= AR5K_NUM_GPIO)
return -EINVAL;
@@ -153,7 +147,6 @@ void ath5k_hw_set_gpio_intr(struct ath5k_hw *ah, unsigned int gpio,
{
u32 data;
- ATH5K_TRACE(ah->ah_sc);
if (gpio >= AR5K_NUM_GPIO)
return;
diff --git a/drivers/net/wireless/ath/ath5k/pcu.c b/drivers/net/wireless/ath/ath5k/pcu.c
index 5212e275f1c..86fdb6ddfaa 100644
--- a/drivers/net/wireless/ath/ath5k/pcu.c
+++ b/drivers/net/wireless/ath/ath5k/pcu.c
@@ -59,8 +59,6 @@ int ath5k_hw_set_opmode(struct ath5k_hw *ah, enum nl80211_iftype op_mode)
beacon_reg = 0;
- ATH5K_TRACE(ah->ah_sc);
-
switch (op_mode) {
case NL80211_IFTYPE_ADHOC:
pcu_reg |= AR5K_STA_ID1_ADHOC | AR5K_STA_ID1_KEYSRCH_MODE;
@@ -173,7 +171,6 @@ void ath5k_hw_set_ack_bitrate_high(struct ath5k_hw *ah, bool high)
*/
static int ath5k_hw_set_ack_timeout(struct ath5k_hw *ah, unsigned int timeout)
{
- ATH5K_TRACE(ah->ah_sc);
if (ath5k_hw_clocktoh(ah, AR5K_REG_MS(0xffffffff, AR5K_TIME_OUT_ACK))
<= timeout)
return -EINVAL;
@@ -192,7 +189,6 @@ static int ath5k_hw_set_ack_timeout(struct ath5k_hw *ah, unsigned int timeout)
*/
static int ath5k_hw_set_cts_timeout(struct ath5k_hw *ah, unsigned int timeout)
{
- ATH5K_TRACE(ah->ah_sc);
if (ath5k_hw_clocktoh(ah, AR5K_REG_MS(0xffffffff, AR5K_TIME_OUT_CTS))
<= timeout)
return -EINVAL;
@@ -297,7 +293,6 @@ int ath5k_hw_set_lladdr(struct ath5k_hw *ah, const u8 *mac)
u32 low_id, high_id;
u32 pcu_reg;
- ATH5K_TRACE(ah->ah_sc);
/* Set new station ID */
memcpy(common->macaddr, mac, ETH_ALEN);
@@ -357,7 +352,6 @@ void ath5k_hw_set_associd(struct ath5k_hw *ah)
void ath5k_hw_set_bssid_mask(struct ath5k_hw *ah, const u8 *mask)
{
struct ath_common *common = ath5k_hw_common(ah);
- ATH5K_TRACE(ah->ah_sc);
/* Cache bssid mask so that we can restore it
* on reset */
@@ -382,7 +376,6 @@ void ath5k_hw_set_bssid_mask(struct ath5k_hw *ah, const u8 *mask)
*/
void ath5k_hw_start_rx_pcu(struct ath5k_hw *ah)
{
- ATH5K_TRACE(ah->ah_sc);
AR5K_REG_DISABLE_BITS(ah, AR5K_DIAG_SW, AR5K_DIAG_SW_DIS_RX);
}
@@ -397,7 +390,6 @@ void ath5k_hw_start_rx_pcu(struct ath5k_hw *ah)
*/
void ath5k_hw_stop_rx_pcu(struct ath5k_hw *ah)
{
- ATH5K_TRACE(ah->ah_sc);
AR5K_REG_ENABLE_BITS(ah, AR5K_DIAG_SW, AR5K_DIAG_SW_DIS_RX);
}
@@ -406,8 +398,6 @@ void ath5k_hw_stop_rx_pcu(struct ath5k_hw *ah)
*/
void ath5k_hw_set_mcast_filter(struct ath5k_hw *ah, u32 filter0, u32 filter1)
{
- ATH5K_TRACE(ah->ah_sc);
- /* Set the multicat filter */
ath5k_hw_reg_write(ah, filter0, AR5K_MCAST_FILTER0);
ath5k_hw_reg_write(ah, filter1, AR5K_MCAST_FILTER1);
}
@@ -427,7 +417,6 @@ u32 ath5k_hw_get_rx_filter(struct ath5k_hw *ah)
{
u32 data, filter = 0;
- ATH5K_TRACE(ah->ah_sc);
filter = ath5k_hw_reg_read(ah, AR5K_RX_FILTER);
/*Radar detection for 5212*/
@@ -457,8 +446,6 @@ void ath5k_hw_set_rx_filter(struct ath5k_hw *ah, u32 filter)
{
u32 data = 0;
- ATH5K_TRACE(ah->ah_sc);
-
/* Set PHY error filter register on 5212*/
if (ah->ah_version == AR5K_AR5212) {
if (filter & AR5K_RX_FILTER_RADARERR)
@@ -533,8 +520,6 @@ u64 ath5k_hw_get_tsf64(struct ath5k_hw *ah)
WARN_ON( i == ATH5K_MAX_TSF_READ );
- ATH5K_TRACE(ah->ah_sc);
-
return (((u64)tsf_upper1 << 32) | tsf_lower);
}
@@ -548,8 +533,6 @@ u64 ath5k_hw_get_tsf64(struct ath5k_hw *ah)
*/
void ath5k_hw_set_tsf64(struct ath5k_hw *ah, u64 tsf64)
{
- ATH5K_TRACE(ah->ah_sc);
-
ath5k_hw_reg_write(ah, tsf64 & 0xffffffff, AR5K_TSF_L32);
ath5k_hw_reg_write(ah, (tsf64 >> 32) & 0xffffffff, AR5K_TSF_U32);
}
@@ -565,8 +548,6 @@ void ath5k_hw_reset_tsf(struct ath5k_hw *ah)
{
u32 val;
- ATH5K_TRACE(ah->ah_sc);
-
val = ath5k_hw_reg_read(ah, AR5K_BEACON) | AR5K_BEACON_RESET_TSF;
/*
@@ -586,7 +567,6 @@ void ath5k_hw_init_beacon(struct ath5k_hw *ah, u32 next_beacon, u32 interval)
{
u32 timer1, timer2, timer3;
- ATH5K_TRACE(ah->ah_sc);
/*
* Set the additional timers by mode
*/
@@ -674,7 +654,6 @@ int ath5k_hw_reset_key(struct ath5k_hw *ah, u16 entry)
unsigned int i, type;
u16 micentry = entry + AR5K_KEYTABLE_MIC_OFFSET;
- ATH5K_TRACE(ah->ah_sc);
AR5K_ASSERT_ENTRY(entry, AR5K_KEYTABLE_SIZE);
type = ath5k_hw_reg_read(ah, AR5K_KEYTABLE_TYPE(entry));
@@ -749,8 +728,6 @@ int ath5k_hw_set_key(struct ath5k_hw *ah, u16 entry,
bool is_tkip;
const u8 *key_ptr;
- ATH5K_TRACE(ah->ah_sc);
-
is_tkip = (key->alg == ALG_TKIP);
/*
@@ -836,7 +813,6 @@ int ath5k_hw_set_key_lladdr(struct ath5k_hw *ah, u16 entry, const u8 *mac)
{
u32 low_id, high_id;
- ATH5K_TRACE(ah->ah_sc);
/* Invalid entry (key table overflow) */
AR5K_ASSERT_ENTRY(entry, AR5K_KEYTABLE_SIZE);
diff --git a/drivers/net/wireless/ath/ath5k/phy.c b/drivers/net/wireless/ath/ath5k/phy.c
index 492cbb15720..6284c389ba1 100644
--- a/drivers/net/wireless/ath/ath5k/phy.c
+++ b/drivers/net/wireless/ath/ath5k/phy.c
@@ -378,8 +378,6 @@ enum ath5k_rfgain ath5k_hw_gainf_calibrate(struct ath5k_hw *ah)
u32 data, type;
struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
- ATH5K_TRACE(ah->ah_sc);
-
if (ah->ah_rf_banks == NULL ||
ah->ah_gain.g_state == AR5K_RFGAIN_INACTIVE)
return AR5K_RFGAIN_INACTIVE;
@@ -1167,7 +1165,7 @@ static s16 ath5k_hw_get_median_noise_floor(struct ath5k_hw *ah)
* The median of the values in the history is then loaded into the
* hardware for its own use for RSSI and CCA measurements.
*/
-static void ath5k_hw_update_noise_floor(struct ath5k_hw *ah)
+void ath5k_hw_update_noise_floor(struct ath5k_hw *ah)
{
struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
u32 val;
@@ -1248,7 +1246,6 @@ static void ath5k_hw_update_noise_floor(struct ath5k_hw *ah)
/*
* Perform a PHY calibration on RF5110
* -Fix BPSK/QAM Constellation (I/Q correction)
- * -Calculate Noise Floor
*/
static int ath5k_hw_rf5110_calibrate(struct ath5k_hw *ah,
struct ieee80211_channel *channel)
@@ -1335,8 +1332,6 @@ static int ath5k_hw_rf5110_calibrate(struct ath5k_hw *ah,
return ret;
}
- ath5k_hw_update_noise_floor(ah);
-
/*
* Re-enable RX/TX and beacons
*/
@@ -1348,22 +1343,20 @@ static int ath5k_hw_rf5110_calibrate(struct ath5k_hw *ah,
}
/*
- * Perform a PHY calibration on RF5111/5112 and newer chips
+ * Perform I/Q calibration on RF5111/5112 and newer chips
*/
-static int ath5k_hw_rf511x_calibrate(struct ath5k_hw *ah,
- struct ieee80211_channel *channel)
+static int
+ath5k_hw_rf511x_iq_calibrate(struct ath5k_hw *ah)
{
u32 i_pwr, q_pwr;
s32 iq_corr, i_coff, i_coffd, q_coff, q_coffd;
int i;
- ATH5K_TRACE(ah->ah_sc);
if (!ah->ah_calibration ||
ath5k_hw_reg_read(ah, AR5K_PHY_IQ) & AR5K_PHY_IQ_RUN)
- goto done;
+ return 0;
/* Calibration has finished, get the results and re-run */
-
/* work around empty results which can apparently happen on 5212 */
for (i = 0; i <= 10; i++) {
iq_corr = ath5k_hw_reg_read(ah, AR5K_PHY_IQRES_CAL_CORR);
@@ -1384,7 +1377,7 @@ static int ath5k_hw_rf511x_calibrate(struct ath5k_hw *ah,
/* protect against divide by 0 and loss of sign bits */
if (i_coffd == 0 || q_coffd < 2)
- goto done;
+ return -1;
i_coff = (-iq_corr) / i_coffd;
i_coff = clamp(i_coff, -32, 31); /* signed 6 bit */
@@ -1410,17 +1403,6 @@ static int ath5k_hw_rf511x_calibrate(struct ath5k_hw *ah,
AR5K_PHY_IQ_CAL_NUM_LOG_MAX, 15);
AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_IQ, AR5K_PHY_IQ_RUN);
-done:
-
- /* TODO: Separate noise floor calibration from I/Q calibration
- * since noise floor calibration interrupts rx path while I/Q
- * calibration doesn't. We don't need to run noise floor calibration
- * as often as I/Q calibration.*/
- ath5k_hw_update_noise_floor(ah);
-
- /* Initiate a gain_F calibration */
- ath5k_hw_request_rfgain_probe(ah);
-
return 0;
}
@@ -1434,8 +1416,10 @@ int ath5k_hw_phy_calibrate(struct ath5k_hw *ah,
if (ah->ah_radio == AR5K_RF5110)
ret = ath5k_hw_rf5110_calibrate(ah, channel);
- else
- ret = ath5k_hw_rf511x_calibrate(ah, channel);
+ else {
+ ret = ath5k_hw_rf511x_iq_calibrate(ah);
+ ath5k_hw_request_rfgain_probe(ah);
+ }
return ret;
}
@@ -1693,7 +1677,6 @@ ath5k_hw_set_spur_mitigation_filter(struct ath5k_hw *ah,
int ath5k_hw_phy_disable(struct ath5k_hw *ah)
{
- ATH5K_TRACE(ah->ah_sc);
/*Just a try M.F.*/
ath5k_hw_reg_write(ah, AR5K_PHY_ACT_DISABLE, AR5K_PHY_ACT);
@@ -1709,8 +1692,6 @@ u16 ath5k_hw_radio_revision(struct ath5k_hw *ah, unsigned int chan)
u32 srev;
u16 ret;
- ATH5K_TRACE(ah->ah_sc);
-
/*
* Set the radio chip access register
*/
@@ -1755,8 +1736,6 @@ u16 ath5k_hw_radio_revision(struct ath5k_hw *ah, unsigned int chan)
static void /*TODO:Boundary check*/
ath5k_hw_set_def_antenna(struct ath5k_hw *ah, u8 ant)
{
- ATH5K_TRACE(ah->ah_sc);
-
if (ah->ah_version != AR5K_AR5210)
ath5k_hw_reg_write(ah, ant & 0x7, AR5K_DEFAULT_ANTENNA);
}
@@ -1789,19 +1768,50 @@ ath5k_hw_set_fast_div(struct ath5k_hw *ah, u8 ee_mode, bool enable)
if (enable) {
AR5K_REG_WRITE_BITS(ah, AR5K_PHY_RESTART,
- AR5K_PHY_RESTART_DIV_GC, 0xc);
+ AR5K_PHY_RESTART_DIV_GC, 4);
AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_FAST_ANT_DIV,
AR5K_PHY_FAST_ANT_DIV_EN);
} else {
AR5K_REG_WRITE_BITS(ah, AR5K_PHY_RESTART,
- AR5K_PHY_RESTART_DIV_GC, 0x8);
+ AR5K_PHY_RESTART_DIV_GC, 0);
AR5K_REG_DISABLE_BITS(ah, AR5K_PHY_FAST_ANT_DIV,
AR5K_PHY_FAST_ANT_DIV_EN);
}
}
+void
+ath5k_hw_set_antenna_switch(struct ath5k_hw *ah, u8 ee_mode)
+{
+ u8 ant0, ant1;
+
+ /*
+ * In case a fixed antenna was set as default
+ * use the same switch table twice.
+ */
+ if (ah->ah_ant_mode == AR5K_ANTMODE_FIXED_A)
+ ant0 = ant1 = AR5K_ANT_SWTABLE_A;
+ else if (ah->ah_ant_mode == AR5K_ANTMODE_FIXED_B)
+ ant0 = ant1 = AR5K_ANT_SWTABLE_B;
+ else {
+ ant0 = AR5K_ANT_SWTABLE_A;
+ ant1 = AR5K_ANT_SWTABLE_B;
+ }
+
+ /* Set antenna idle switch table */
+ AR5K_REG_WRITE_BITS(ah, AR5K_PHY_ANT_CTL,
+ AR5K_PHY_ANT_CTL_SWTABLE_IDLE,
+ (ah->ah_ant_ctl[ee_mode][AR5K_ANT_CTL] |
+ AR5K_PHY_ANT_CTL_TXRX_EN));
+
+ /* Set antenna switch tables */
+ ath5k_hw_reg_write(ah, ah->ah_ant_ctl[ee_mode][ant0],
+ AR5K_PHY_ANT_SWITCH_TABLE_0);
+ ath5k_hw_reg_write(ah, ah->ah_ant_ctl[ee_mode][ant1],
+ AR5K_PHY_ANT_SWITCH_TABLE_1);
+}
+
/*
* Set antenna operating mode
*/
@@ -1823,8 +1833,6 @@ ath5k_hw_set_antenna_mode(struct ath5k_hw *ah, u8 ant_mode)
def_ant = ah->ah_def_ant;
- ATH5K_TRACE(ah->ah_sc);
-
switch (channel->hw_value & CHANNEL_MODES) {
case CHANNEL_A:
case CHANNEL_T:
@@ -1923,6 +1931,7 @@ ath5k_hw_set_antenna_mode(struct ath5k_hw *ah, u8 ant_mode)
if (sta_id1)
AR5K_REG_ENABLE_BITS(ah, AR5K_STA_ID1, sta_id1);
+ ath5k_hw_set_antenna_switch(ah, ee_mode);
/* Note: set diversity before default antenna
* because it won't work correctly */
ath5k_hw_set_fast_div(ah, ee_mode, fast_div);
@@ -2988,7 +2997,6 @@ ath5k_hw_txpower(struct ath5k_hw *ah, struct ieee80211_channel *channel,
u8 type;
int ret;
- ATH5K_TRACE(ah->ah_sc);
if (txpower > AR5K_TUNE_MAX_TXPOWER) {
ATH5K_ERR(ah->ah_sc, "invalid tx power: %u\n", txpower);
return -EINVAL;
@@ -3084,8 +3092,6 @@ int ath5k_hw_set_txpower_limit(struct ath5k_hw *ah, u8 txpower)
struct ieee80211_channel *channel = ah->ah_current_channel;
u8 ee_mode;
- ATH5K_TRACE(ah->ah_sc);
-
switch (channel->hw_value & CHANNEL_MODES) {
case CHANNEL_A:
case CHANNEL_T:
diff --git a/drivers/net/wireless/ath/ath5k/qcu.c b/drivers/net/wireless/ath/ath5k/qcu.c
index f5831da33f7..4186ff4c6e9 100644
--- a/drivers/net/wireless/ath/ath5k/qcu.c
+++ b/drivers/net/wireless/ath/ath5k/qcu.c
@@ -31,7 +31,6 @@ Queue Control Unit, DFS Control Unit Functions
int ath5k_hw_get_tx_queueprops(struct ath5k_hw *ah, int queue,
struct ath5k_txq_info *queue_info)
{
- ATH5K_TRACE(ah->ah_sc);
memcpy(queue_info, &ah->ah_txq[queue], sizeof(struct ath5k_txq_info));
return 0;
}
@@ -42,7 +41,6 @@ int ath5k_hw_get_tx_queueprops(struct ath5k_hw *ah, int queue,
int ath5k_hw_set_tx_queueprops(struct ath5k_hw *ah, int queue,
const struct ath5k_txq_info *queue_info)
{
- ATH5K_TRACE(ah->ah_sc);
AR5K_ASSERT_ENTRY(queue, ah->ah_capabilities.cap_queues.q_tx_num);
if (ah->ah_txq[queue].tqi_type == AR5K_TX_QUEUE_INACTIVE)
@@ -69,8 +67,6 @@ int ath5k_hw_setup_tx_queue(struct ath5k_hw *ah, enum ath5k_tx_queue queue_type,
unsigned int queue;
int ret;
- ATH5K_TRACE(ah->ah_sc);
-
/*
* Get queue by type
*/
@@ -149,7 +145,6 @@ int ath5k_hw_setup_tx_queue(struct ath5k_hw *ah, enum ath5k_tx_queue queue_type,
u32 ath5k_hw_num_tx_pending(struct ath5k_hw *ah, unsigned int queue)
{
u32 pending;
- ATH5K_TRACE(ah->ah_sc);
AR5K_ASSERT_ENTRY(queue, ah->ah_capabilities.cap_queues.q_tx_num);
/* Return if queue is declared inactive */
@@ -177,7 +172,6 @@ u32 ath5k_hw_num_tx_pending(struct ath5k_hw *ah, unsigned int queue)
*/
void ath5k_hw_release_tx_queue(struct ath5k_hw *ah, unsigned int queue)
{
- ATH5K_TRACE(ah->ah_sc);
if (WARN_ON(queue >= ah->ah_capabilities.cap_queues.q_tx_num))
return;
@@ -195,7 +189,6 @@ int ath5k_hw_reset_tx_queue(struct ath5k_hw *ah, unsigned int queue)
u32 cw_min, cw_max, retry_lg, retry_sh;
struct ath5k_txq_info *tq = &ah->ah_txq[queue];
- ATH5K_TRACE(ah->ah_sc);
AR5K_ASSERT_ENTRY(queue, ah->ah_capabilities.cap_queues.q_tx_num);
tq = &ah->ah_txq[queue];
@@ -523,8 +516,6 @@ int ath5k_hw_set_slot_time(struct ath5k_hw *ah, unsigned int slot_time)
{
u32 slot_time_clock = ath5k_hw_htoclock(ah, slot_time);
- ATH5K_TRACE(ah->ah_sc);
-
if (slot_time < 6 || slot_time_clock > AR5K_SLOT_TIME_MAX)
return -EINVAL;
diff --git a/drivers/net/wireless/ath/ath5k/reset.c b/drivers/net/wireless/ath/ath5k/reset.c
index 307f80e83f9..498aa28ea9e 100644
--- a/drivers/net/wireless/ath/ath5k/reset.c
+++ b/drivers/net/wireless/ath/ath5k/reset.c
@@ -201,8 +201,6 @@ static int ath5k_hw_nic_reset(struct ath5k_hw *ah, u32 val)
int ret;
u32 mask = val ? val : ~0U;
- ATH5K_TRACE(ah->ah_sc);
-
/* Read-and-clear RX Descriptor Pointer*/
ath5k_hw_reg_read(ah, AR5K_RXDP);
@@ -246,7 +244,6 @@ static int ath5k_hw_set_power(struct ath5k_hw *ah, enum ath5k_power_mode mode,
unsigned int i;
u32 staid, data;
- ATH5K_TRACE(ah->ah_sc);
staid = ath5k_hw_reg_read(ah, AR5K_STA_ID1);
switch (mode) {
@@ -393,8 +390,6 @@ int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, int flags, bool initial)
mode = 0;
clock = 0;
- ATH5K_TRACE(ah->ah_sc);
-
/* Wakeup the device */
ret = ath5k_hw_set_power(ah, AR5K_PM_AWAKE, true, 0);
if (ret) {
@@ -734,7 +729,7 @@ static void ath5k_hw_tweak_initval_settings(struct ath5k_hw *ah,
}
static void ath5k_hw_commit_eeprom_settings(struct ath5k_hw *ah,
- struct ieee80211_channel *channel, u8 *ant, u8 ee_mode)
+ struct ieee80211_channel *channel, u8 ee_mode)
{
struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
s16 cck_ofdm_pwr_delta;
@@ -768,17 +763,9 @@ static void ath5k_hw_commit_eeprom_settings(struct ath5k_hw *ah,
ee->ee_cck_ofdm_gain_delta;
}
- /* Set antenna idle switch table */
- AR5K_REG_WRITE_BITS(ah, AR5K_PHY_ANT_CTL,
- AR5K_PHY_ANT_CTL_SWTABLE_IDLE,
- (ah->ah_ant_ctl[ee_mode][0] |
- AR5K_PHY_ANT_CTL_TXRX_EN));
-
- /* Set antenna switch tables */
- ath5k_hw_reg_write(ah, ah->ah_ant_ctl[ee_mode][ant[0]],
- AR5K_PHY_ANT_SWITCH_TABLE_0);
- ath5k_hw_reg_write(ah, ah->ah_ant_ctl[ee_mode][ant[1]],
- AR5K_PHY_ANT_SWITCH_TABLE_1);
+ /* XXX: necessary here? is called from ath5k_hw_set_antenna_mode()
+ * too */
+ ath5k_hw_set_antenna_switch(ah, ee_mode);
/* Noise floor threshold */
ath5k_hw_reg_write(ah,
@@ -855,7 +842,6 @@ static void ath5k_hw_commit_eeprom_settings(struct ath5k_hw *ah,
AR5K_PHY_NF_THRESH62,
ee->ee_thr_62[ee_mode]);
-
/* False detect backoff for channels
* that have spur noise. Write the new
* cyclic power RSSI threshold. */
@@ -891,14 +877,11 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode,
struct ieee80211_channel *channel, bool change_channel)
{
struct ath_common *common = ath5k_hw_common(ah);
- u32 s_seq[10], s_ant, s_led[3], staid1_flags, tsf_up, tsf_lo;
+ u32 s_seq[10], s_led[3], staid1_flags, tsf_up, tsf_lo;
u32 phy_tst1;
- u8 mode, freq, ee_mode, ant[2];
+ u8 mode, freq, ee_mode;
int i, ret;
- ATH5K_TRACE(ah->ah_sc);
-
- s_ant = 0;
ee_mode = 0;
staid1_flags = 0;
tsf_up = 0;
@@ -995,9 +978,6 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode,
}
}
- /* Save default antenna */
- s_ant = ath5k_hw_reg_read(ah, AR5K_DEFAULT_ANTENNA);
-
if (ah->ah_version == AR5K_AR5212) {
/* Restore normal 32/40MHz clock operation
* to avoid register access delay on certain
@@ -1094,22 +1074,17 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode,
/* Write OFDM timings on 5212*/
if (ah->ah_version == AR5K_AR5212 &&
channel->hw_value & CHANNEL_OFDM) {
- struct ath5k_eeprom_info *ee =
- &ah->ah_capabilities.cap_eeprom;
ret = ath5k_hw_write_ofdm_timings(ah, channel);
if (ret)
return ret;
- /* Note: According to docs we can have a newer
- * EEPROM on old hardware, so we need to verify
- * that our hardware is new enough to have spur
- * mitigation registers (delta phase etc) */
- if (ah->ah_mac_srev >= AR5K_SREV_AR5424 ||
- (ah->ah_mac_srev >= AR5K_SREV_AR5424 &&
- ee->ee_version >= AR5K_EEPROM_VERSION_5_3))
+ /* Spur info is available only from EEPROM versions
+ * bigger than 5.3 but but the EEPOM routines will use
+ * static values for older versions */
+ if (ah->ah_mac_srev >= AR5K_SREV_AR5424)
ath5k_hw_set_spur_mitigation_filter(ah,
- channel);
+ channel);
}
/*Enable/disable 802.11b mode on 5111
@@ -1123,21 +1098,8 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode,
AR5K_TXCFG_B_MODE);
}
- /*
- * In case a fixed antenna was set as default
- * use the same switch table twice.
- */
- if (ah->ah_ant_mode == AR5K_ANTMODE_FIXED_A)
- ant[0] = ant[1] = AR5K_ANT_SWTABLE_A;
- else if (ah->ah_ant_mode == AR5K_ANTMODE_FIXED_B)
- ant[0] = ant[1] = AR5K_ANT_SWTABLE_B;
- else {
- ant[0] = AR5K_ANT_SWTABLE_A;
- ant[1] = AR5K_ANT_SWTABLE_B;
- }
-
/* Commit values from EEPROM */
- ath5k_hw_commit_eeprom_settings(ah, channel, ant, ee_mode);
+ ath5k_hw_commit_eeprom_settings(ah, channel, ee_mode);
} else {
/*
@@ -1175,8 +1137,6 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode,
ath5k_hw_reg_write(ah, tsf_lo, AR5K_TSF_L32);
}
}
-
- ath5k_hw_reg_write(ah, s_ant, AR5K_DEFAULT_ANTENNA);
}
/* Ledstate */
diff --git a/drivers/net/wireless/ath/ath5k/sysfs.c b/drivers/net/wireless/ath/ath5k/sysfs.c
new file mode 100644
index 00000000000..90757de7bf5
--- /dev/null
+++ b/drivers/net/wireless/ath/ath5k/sysfs.c
@@ -0,0 +1,116 @@
+#include <linux/device.h>
+#include <linux/pci.h>
+
+#include "base.h"
+#include "ath5k.h"
+#include "reg.h"
+
+#define SIMPLE_SHOW_STORE(name, get, set) \
+static ssize_t ath5k_attr_show_##name(struct device *dev, \
+ struct device_attribute *attr, \
+ char *buf) \
+{ \
+ struct ath5k_softc *sc = dev_get_drvdata(dev); \
+ return snprintf(buf, PAGE_SIZE, "%d\n", get); \
+} \
+ \
+static ssize_t ath5k_attr_store_##name(struct device *dev, \
+ struct device_attribute *attr, \
+ const char *buf, size_t count) \
+{ \
+ struct ath5k_softc *sc = dev_get_drvdata(dev); \
+ int val; \
+ \
+ val = (int)simple_strtoul(buf, NULL, 10); \
+ set(sc->ah, val); \
+ return count; \
+} \
+static DEVICE_ATTR(name, S_IRUGO | S_IWUSR, \
+ ath5k_attr_show_##name, ath5k_attr_store_##name)
+
+#define SIMPLE_SHOW(name, get) \
+static ssize_t ath5k_attr_show_##name(struct device *dev, \
+ struct device_attribute *attr, \
+ char *buf) \
+{ \
+ struct ath5k_softc *sc = dev_get_drvdata(dev); \
+ return snprintf(buf, PAGE_SIZE, "%d\n", get); \
+} \
+static DEVICE_ATTR(name, S_IRUGO, ath5k_attr_show_##name, NULL)
+
+/*** ANI ***/
+
+SIMPLE_SHOW_STORE(ani_mode, sc->ani_state.ani_mode, ath5k_ani_init);
+SIMPLE_SHOW_STORE(noise_immunity_level, sc->ani_state.noise_imm_level,
+ ath5k_ani_set_noise_immunity_level);
+SIMPLE_SHOW_STORE(spur_level, sc->ani_state.spur_level,
+ ath5k_ani_set_spur_immunity_level);
+SIMPLE_SHOW_STORE(firstep_level, sc->ani_state.firstep_level,
+ ath5k_ani_set_firstep_level);
+SIMPLE_SHOW_STORE(ofdm_weak_signal_detection, sc->ani_state.ofdm_weak_sig,
+ ath5k_ani_set_ofdm_weak_signal_detection);
+SIMPLE_SHOW_STORE(cck_weak_signal_detection, sc->ani_state.cck_weak_sig,
+ ath5k_ani_set_cck_weak_signal_detection);
+SIMPLE_SHOW(spur_level_max, sc->ani_state.max_spur_level);
+
+static ssize_t ath5k_attr_show_noise_immunity_level_max(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "%d\n", ATH5K_ANI_MAX_NOISE_IMM_LVL);
+}
+static DEVICE_ATTR(noise_immunity_level_max, S_IRUGO,
+ ath5k_attr_show_noise_immunity_level_max, NULL);
+
+static ssize_t ath5k_attr_show_firstep_level_max(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "%d\n", ATH5K_ANI_MAX_FIRSTEP_LVL);
+}
+static DEVICE_ATTR(firstep_level_max, S_IRUGO,
+ ath5k_attr_show_firstep_level_max, NULL);
+
+static struct attribute *ath5k_sysfs_entries_ani[] = {
+ &dev_attr_ani_mode.attr,
+ &dev_attr_noise_immunity_level.attr,
+ &dev_attr_spur_level.attr,
+ &dev_attr_firstep_level.attr,
+ &dev_attr_ofdm_weak_signal_detection.attr,
+ &dev_attr_cck_weak_signal_detection.attr,
+ &dev_attr_noise_immunity_level_max.attr,
+ &dev_attr_spur_level_max.attr,
+ &dev_attr_firstep_level_max.attr,
+ NULL
+};
+
+static struct attribute_group ath5k_attribute_group_ani = {
+ .name = "ani",
+ .attrs = ath5k_sysfs_entries_ani,
+};
+
+
+/*** register / unregister ***/
+
+int
+ath5k_sysfs_register(struct ath5k_softc *sc)
+{
+ struct device *dev = &sc->pdev->dev;
+ int err;
+
+ err = sysfs_create_group(&dev->kobj, &ath5k_attribute_group_ani);
+ if (err) {
+ ATH5K_ERR(sc, "failed to create sysfs group\n");
+ return err;
+ }
+
+ return 0;
+}
+
+void
+ath5k_sysfs_unregister(struct ath5k_softc *sc)
+{
+ struct device *dev = &sc->pdev->dev;
+
+ sysfs_remove_group(&dev->kobj, &ath5k_attribute_group_ani);
+}
diff --git a/drivers/net/wireless/ath/ath9k/Makefile b/drivers/net/wireless/ath/ath9k/Makefile
index dd112be218a..973ae4f49f3 100644
--- a/drivers/net/wireless/ath/ath9k/Makefile
+++ b/drivers/net/wireless/ath/ath9k/Makefile
@@ -32,7 +32,8 @@ ath9k_hw-y:= \
mac.o \
ar9002_mac.o \
ar9003_mac.o \
- ar9003_eeprom.o
+ ar9003_eeprom.o \
+ ar9003_paprd.o
obj-$(CONFIG_ATH9K_HW) += ath9k_hw.o
diff --git a/drivers/net/wireless/ath/ath9k/ahb.c b/drivers/net/wireless/ath/ath9k/ahb.c
index 85fdd26039c..1a984b02e9e 100644
--- a/drivers/net/wireless/ath/ath9k/ahb.c
+++ b/drivers/net/wireless/ath/ath9k/ahb.c
@@ -131,11 +131,8 @@ static int ath_ahb_probe(struct platform_device *pdev)
ah = sc->sc_ah;
ath9k_hw_name(ah, hw_name, sizeof(hw_name));
- printk(KERN_INFO
- "%s: %s mem=0x%lx, irq=%d\n",
- wiphy_name(hw->wiphy),
- hw_name,
- (unsigned long)mem, irq);
+ wiphy_info(hw->wiphy, "%s mem=0x%lx, irq=%d\n",
+ hw_name, (unsigned long)mem, irq);
return 0;
diff --git a/drivers/net/wireless/ath/ath9k/ani.c b/drivers/net/wireless/ath/ath9k/ani.c
index ba8b20f0159..cc648b6ae31 100644
--- a/drivers/net/wireless/ath/ath9k/ani.c
+++ b/drivers/net/wireless/ath/ath9k/ani.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2008-2009 Atheros Communications Inc.
+ * Copyright (c) 2008-2010 Atheros Communications Inc.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -17,8 +17,99 @@
#include "hw.h"
#include "hw-ops.h"
-static int ath9k_hw_get_ani_channel_idx(struct ath_hw *ah,
- struct ath9k_channel *chan)
+struct ani_ofdm_level_entry {
+ int spur_immunity_level;
+ int fir_step_level;
+ int ofdm_weak_signal_on;
+};
+
+/* values here are relative to the INI */
+
+/*
+ * Legend:
+ *
+ * SI: Spur immunity
+ * FS: FIR Step
+ * WS: OFDM / CCK Weak Signal detection
+ * MRC-CCK: Maximal Ratio Combining for CCK
+ */
+
+static const struct ani_ofdm_level_entry ofdm_level_table[] = {
+ /* SI FS WS */
+ { 0, 0, 1 }, /* lvl 0 */
+ { 1, 1, 1 }, /* lvl 1 */
+ { 2, 2, 1 }, /* lvl 2 */
+ { 3, 2, 1 }, /* lvl 3 (default) */
+ { 4, 3, 1 }, /* lvl 4 */
+ { 5, 4, 1 }, /* lvl 5 */
+ { 6, 5, 1 }, /* lvl 6 */
+ { 7, 6, 1 }, /* lvl 7 */
+ { 7, 7, 1 }, /* lvl 8 */
+ { 7, 8, 0 } /* lvl 9 */
+};
+#define ATH9K_ANI_OFDM_NUM_LEVEL \
+ (sizeof(ofdm_level_table)/sizeof(ofdm_level_table[0]))
+#define ATH9K_ANI_OFDM_MAX_LEVEL \
+ (ATH9K_ANI_OFDM_NUM_LEVEL-1)
+#define ATH9K_ANI_OFDM_DEF_LEVEL \
+ 3 /* default level - matches the INI settings */
+
+/*
+ * MRC (Maximal Ratio Combining) has always been used with multi-antenna ofdm.
+ * With OFDM for single stream you just add up all antenna inputs, you're
+ * only interested in what you get after FFT. Signal aligment is also not
+ * required for OFDM because any phase difference adds up in the frequency
+ * domain.
+ *
+ * MRC requires extra work for use with CCK. You need to align the antenna
+ * signals from the different antenna before you can add the signals together.
+ * You need aligment of signals as CCK is in time domain, so addition can cancel
+ * your signal completely if phase is 180 degrees (think of adding sine waves).
+ * You also need to remove noise before the addition and this is where ANI
+ * MRC CCK comes into play. One of the antenna inputs may be stronger but
+ * lower SNR, so just adding after alignment can be dangerous.
+ *
+ * Regardless of alignment in time, the antenna signals add constructively after
+ * FFT and improve your reception. For more information:
+ *
+ * http://en.wikipedia.org/wiki/Maximal-ratio_combining
+ */
+
+struct ani_cck_level_entry {
+ int fir_step_level;
+ int mrc_cck_on;
+};
+
+static const struct ani_cck_level_entry cck_level_table[] = {
+ /* FS MRC-CCK */
+ { 0, 1 }, /* lvl 0 */
+ { 1, 1 }, /* lvl 1 */
+ { 2, 1 }, /* lvl 2 (default) */
+ { 3, 1 }, /* lvl 3 */
+ { 4, 0 }, /* lvl 4 */
+ { 5, 0 }, /* lvl 5 */
+ { 6, 0 }, /* lvl 6 */
+ { 7, 0 }, /* lvl 7 (only for high rssi) */
+ { 8, 0 } /* lvl 8 (only for high rssi) */
+};
+
+#define ATH9K_ANI_CCK_NUM_LEVEL \
+ (sizeof(cck_level_table)/sizeof(cck_level_table[0]))
+#define ATH9K_ANI_CCK_MAX_LEVEL \
+ (ATH9K_ANI_CCK_NUM_LEVEL-1)
+#define ATH9K_ANI_CCK_MAX_LEVEL_LOW_RSSI \
+ (ATH9K_ANI_CCK_NUM_LEVEL-3)
+#define ATH9K_ANI_CCK_DEF_LEVEL \
+ 2 /* default level - matches the INI settings */
+
+/* Private to ani.c */
+static void ath9k_hw_ani_lower_immunity(struct ath_hw *ah)
+{
+ ath9k_hw_private_ops(ah)->ani_lower_immunity(ah);
+}
+
+int ath9k_hw_get_ani_channel_idx(struct ath_hw *ah,
+ struct ath9k_channel *chan)
{
int i;
@@ -48,7 +139,7 @@ static void ath9k_hw_update_mibstats(struct ath_hw *ah,
stats->beacons += REG_READ(ah, AR_BEACON_CNT);
}
-static void ath9k_ani_restart(struct ath_hw *ah)
+static void ath9k_ani_restart_old(struct ath_hw *ah)
{
struct ar5416AniState *aniState;
struct ath_common *common = ath9k_hw_common(ah);
@@ -96,7 +187,42 @@ static void ath9k_ani_restart(struct ath_hw *ah)
aniState->cckPhyErrCount = 0;
}
-static void ath9k_hw_ani_ofdm_err_trigger(struct ath_hw *ah)
+static void ath9k_ani_restart_new(struct ath_hw *ah)
+{
+ struct ar5416AniState *aniState;
+ struct ath_common *common = ath9k_hw_common(ah);
+
+ if (!DO_ANI(ah))
+ return;
+
+ aniState = ah->curani;
+ aniState->listenTime = 0;
+
+ aniState->ofdmPhyErrBase = 0;
+ aniState->cckPhyErrBase = 0;
+
+ ath_print(common, ATH_DBG_ANI,
+ "Writing ofdmbase=%08x cckbase=%08x\n",
+ aniState->ofdmPhyErrBase,
+ aniState->cckPhyErrBase);
+
+ ENABLE_REGWRITE_BUFFER(ah);
+
+ REG_WRITE(ah, AR_PHY_ERR_1, aniState->ofdmPhyErrBase);
+ REG_WRITE(ah, AR_PHY_ERR_2, aniState->cckPhyErrBase);
+ REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING);
+ REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING);
+
+ REGWRITE_BUFFER_FLUSH(ah);
+ DISABLE_REGWRITE_BUFFER(ah);
+
+ ath9k_hw_update_mibstats(ah, &ah->ah_mibStats);
+
+ aniState->ofdmPhyErrCount = 0;
+ aniState->cckPhyErrCount = 0;
+}
+
+static void ath9k_hw_ani_ofdm_err_trigger_old(struct ath_hw *ah)
{
struct ieee80211_conf *conf = &ath9k_hw_common(ah)->hw->conf;
struct ar5416AniState *aniState;
@@ -168,7 +294,7 @@ static void ath9k_hw_ani_ofdm_err_trigger(struct ath_hw *ah)
}
}
-static void ath9k_hw_ani_cck_err_trigger(struct ath_hw *ah)
+static void ath9k_hw_ani_cck_err_trigger_old(struct ath_hw *ah)
{
struct ieee80211_conf *conf = &ath9k_hw_common(ah)->hw->conf;
struct ar5416AniState *aniState;
@@ -206,7 +332,125 @@ static void ath9k_hw_ani_cck_err_trigger(struct ath_hw *ah)
}
}
-static void ath9k_hw_ani_lower_immunity(struct ath_hw *ah)
+/* Adjust the OFDM Noise Immunity Level */
+static void ath9k_hw_set_ofdm_nil(struct ath_hw *ah, u8 immunityLevel)
+{
+ struct ar5416AniState *aniState = ah->curani;
+ struct ath_common *common = ath9k_hw_common(ah);
+ const struct ani_ofdm_level_entry *entry_ofdm;
+ const struct ani_cck_level_entry *entry_cck;
+
+ aniState->noiseFloor = BEACON_RSSI(ah);
+
+ ath_print(common, ATH_DBG_ANI,
+ "**** ofdmlevel %d=>%d, rssi=%d[lo=%d hi=%d]\n",
+ aniState->ofdmNoiseImmunityLevel,
+ immunityLevel, aniState->noiseFloor,
+ aniState->rssiThrLow, aniState->rssiThrHigh);
+
+ aniState->ofdmNoiseImmunityLevel = immunityLevel;
+
+ entry_ofdm = &ofdm_level_table[aniState->ofdmNoiseImmunityLevel];
+ entry_cck = &cck_level_table[aniState->cckNoiseImmunityLevel];
+
+ if (aniState->spurImmunityLevel != entry_ofdm->spur_immunity_level)
+ ath9k_hw_ani_control(ah,
+ ATH9K_ANI_SPUR_IMMUNITY_LEVEL,
+ entry_ofdm->spur_immunity_level);
+
+ if (aniState->firstepLevel != entry_ofdm->fir_step_level &&
+ entry_ofdm->fir_step_level >= entry_cck->fir_step_level)
+ ath9k_hw_ani_control(ah,
+ ATH9K_ANI_FIRSTEP_LEVEL,
+ entry_ofdm->fir_step_level);
+
+ if ((ah->opmode != NL80211_IFTYPE_STATION &&
+ ah->opmode != NL80211_IFTYPE_ADHOC) ||
+ aniState->noiseFloor <= aniState->rssiThrHigh) {
+ if (aniState->ofdmWeakSigDetectOff)
+ /* force on ofdm weak sig detect */
+ ath9k_hw_ani_control(ah,
+ ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION,
+ true);
+ else if (aniState->ofdmWeakSigDetectOff ==
+ entry_ofdm->ofdm_weak_signal_on)
+ ath9k_hw_ani_control(ah,
+ ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION,
+ entry_ofdm->ofdm_weak_signal_on);
+ }
+}
+
+static void ath9k_hw_ani_ofdm_err_trigger_new(struct ath_hw *ah)
+{
+ struct ar5416AniState *aniState;
+
+ if (!DO_ANI(ah))
+ return;
+
+ aniState = ah->curani;
+
+ if (aniState->ofdmNoiseImmunityLevel < ATH9K_ANI_OFDM_MAX_LEVEL)
+ ath9k_hw_set_ofdm_nil(ah, aniState->ofdmNoiseImmunityLevel + 1);
+}
+
+/*
+ * Set the ANI settings to match an CCK level.
+ */
+static void ath9k_hw_set_cck_nil(struct ath_hw *ah, u_int8_t immunityLevel)
+{
+ struct ar5416AniState *aniState = ah->curani;
+ struct ath_common *common = ath9k_hw_common(ah);
+ const struct ani_ofdm_level_entry *entry_ofdm;
+ const struct ani_cck_level_entry *entry_cck;
+
+ aniState->noiseFloor = BEACON_RSSI(ah);
+ ath_print(common, ATH_DBG_ANI,
+ "**** ccklevel %d=>%d, rssi=%d[lo=%d hi=%d]\n",
+ aniState->cckNoiseImmunityLevel, immunityLevel,
+ aniState->noiseFloor, aniState->rssiThrLow,
+ aniState->rssiThrHigh);
+
+ if ((ah->opmode == NL80211_IFTYPE_STATION ||
+ ah->opmode == NL80211_IFTYPE_ADHOC) &&
+ aniState->noiseFloor <= aniState->rssiThrLow &&
+ immunityLevel > ATH9K_ANI_CCK_MAX_LEVEL_LOW_RSSI)
+ immunityLevel = ATH9K_ANI_CCK_MAX_LEVEL_LOW_RSSI;
+
+ aniState->cckNoiseImmunityLevel = immunityLevel;
+
+ entry_ofdm = &ofdm_level_table[aniState->ofdmNoiseImmunityLevel];
+ entry_cck = &cck_level_table[aniState->cckNoiseImmunityLevel];
+
+ if (aniState->firstepLevel != entry_cck->fir_step_level &&
+ entry_cck->fir_step_level >= entry_ofdm->fir_step_level)
+ ath9k_hw_ani_control(ah,
+ ATH9K_ANI_FIRSTEP_LEVEL,
+ entry_cck->fir_step_level);
+
+ /* Skip MRC CCK for pre AR9003 families */
+ if (!AR_SREV_9300_20_OR_LATER(ah))
+ return;
+
+ if (aniState->mrcCCKOff == entry_cck->mrc_cck_on)
+ ath9k_hw_ani_control(ah,
+ ATH9K_ANI_MRC_CCK,
+ entry_cck->mrc_cck_on);
+}
+
+static void ath9k_hw_ani_cck_err_trigger_new(struct ath_hw *ah)
+{
+ struct ar5416AniState *aniState;
+
+ if (!DO_ANI(ah))
+ return;
+
+ aniState = ah->curani;
+
+ if (aniState->cckNoiseImmunityLevel < ATH9K_ANI_CCK_MAX_LEVEL)
+ ath9k_hw_set_cck_nil(ah, aniState->cckNoiseImmunityLevel + 1);
+}
+
+static void ath9k_hw_ani_lower_immunity_old(struct ath_hw *ah)
{
struct ar5416AniState *aniState;
int32_t rssi;
@@ -259,9 +503,53 @@ static void ath9k_hw_ani_lower_immunity(struct ath_hw *ah)
}
}
+/*
+ * only lower either OFDM or CCK errors per turn
+ * we lower the other one next time
+ */
+static void ath9k_hw_ani_lower_immunity_new(struct ath_hw *ah)
+{
+ struct ar5416AniState *aniState;
+
+ aniState = ah->curani;
+
+ /* lower OFDM noise immunity */
+ if (aniState->ofdmNoiseImmunityLevel > 0 &&
+ (aniState->ofdmsTurn || aniState->cckNoiseImmunityLevel == 0)) {
+ ath9k_hw_set_ofdm_nil(ah, aniState->ofdmNoiseImmunityLevel - 1);
+ return;
+ }
+
+ /* lower CCK noise immunity */
+ if (aniState->cckNoiseImmunityLevel > 0)
+ ath9k_hw_set_cck_nil(ah, aniState->cckNoiseImmunityLevel - 1);
+}
+
+static u8 ath9k_hw_chan_2_clockrate_mhz(struct ath_hw *ah)
+{
+ struct ath9k_channel *chan = ah->curchan;
+ struct ieee80211_conf *conf = &ath9k_hw_common(ah)->hw->conf;
+ u8 clockrate; /* in MHz */
+
+ if (!ah->curchan) /* should really check for CCK instead */
+ clockrate = ATH9K_CLOCK_RATE_CCK;
+ else if (conf->channel->band == IEEE80211_BAND_2GHZ)
+ clockrate = ATH9K_CLOCK_RATE_2GHZ_OFDM;
+ else if (IS_CHAN_A_FAST_CLOCK(ah, chan))
+ clockrate = ATH9K_CLOCK_FAST_RATE_5GHZ_OFDM;
+ else
+ clockrate = ATH9K_CLOCK_RATE_5GHZ_OFDM;
+
+ if (conf_is_ht40(conf))
+ return clockrate * 2;
+
+ return clockrate * 2;
+}
+
static int32_t ath9k_hw_ani_get_listen_time(struct ath_hw *ah)
{
struct ar5416AniState *aniState;
+ struct ath_common *common = ath9k_hw_common(ah);
u32 txFrameCount, rxFrameCount, cycleCount;
int32_t listenTime;
@@ -271,15 +559,31 @@ static int32_t ath9k_hw_ani_get_listen_time(struct ath_hw *ah)
aniState = ah->curani;
if (aniState->cycleCount == 0 || aniState->cycleCount > cycleCount) {
-
listenTime = 0;
ah->stats.ast_ani_lzero++;
+ ath_print(common, ATH_DBG_ANI,
+ "1st call: aniState->cycleCount=%d\n",
+ aniState->cycleCount);
} else {
int32_t ccdelta = cycleCount - aniState->cycleCount;
int32_t rfdelta = rxFrameCount - aniState->rxFrameCount;
int32_t tfdelta = txFrameCount - aniState->txFrameCount;
- listenTime = (ccdelta - rfdelta - tfdelta) / 44000;
+ int32_t clock_rate;
+
+ /*
+ * convert HW counter values to ms using mode
+ * specifix clock rate
+ */
+ clock_rate = ath9k_hw_chan_2_clockrate_mhz(ah) * 1000;;
+
+ listenTime = (ccdelta - rfdelta - tfdelta) / clock_rate;
+
+ ath_print(common, ATH_DBG_ANI,
+ "cyclecount=%d, rfcount=%d, "
+ "tfcount=%d, listenTime=%d CLOCK_RATE=%d\n",
+ ccdelta, rfdelta, tfdelta, listenTime, clock_rate);
}
+
aniState->cycleCount = cycleCount;
aniState->txFrameCount = txFrameCount;
aniState->rxFrameCount = rxFrameCount;
@@ -287,7 +591,7 @@ static int32_t ath9k_hw_ani_get_listen_time(struct ath_hw *ah)
return listenTime;
}
-void ath9k_ani_reset(struct ath_hw *ah)
+static void ath9k_ani_reset_old(struct ath_hw *ah, bool is_scanning)
{
struct ar5416AniState *aniState;
struct ath9k_channel *chan = ah->curchan;
@@ -340,7 +644,7 @@ void ath9k_ani_reset(struct ath_hw *ah)
ah->curani->cckTrigLow =
ah->config.cck_trig_low;
}
- ath9k_ani_restart(ah);
+ ath9k_ani_restart_old(ah);
return;
}
@@ -362,7 +666,7 @@ void ath9k_ani_reset(struct ath_hw *ah)
ath9k_hw_setrxfilter(ah, ath9k_hw_getrxfilter(ah) &
~ATH9K_RX_FILTER_PHYERR);
- ath9k_ani_restart(ah);
+ ath9k_ani_restart_old(ah);
ENABLE_REGWRITE_BUFFER(ah);
@@ -373,8 +677,102 @@ void ath9k_ani_reset(struct ath_hw *ah)
DISABLE_REGWRITE_BUFFER(ah);
}
-void ath9k_hw_ani_monitor(struct ath_hw *ah,
- struct ath9k_channel *chan)
+/*
+ * Restore the ANI parameters in the HAL and reset the statistics.
+ * This routine should be called for every hardware reset and for
+ * every channel change.
+ */
+static void ath9k_ani_reset_new(struct ath_hw *ah, bool is_scanning)
+{
+ struct ar5416AniState *aniState = ah->curani;
+ struct ath9k_channel *chan = ah->curchan;
+ struct ath_common *common = ath9k_hw_common(ah);
+
+ if (!DO_ANI(ah))
+ return;
+
+ BUG_ON(aniState == NULL);
+ ah->stats.ast_ani_reset++;
+
+ /* only allow a subset of functions in AP mode */
+ if (ah->opmode == NL80211_IFTYPE_AP) {
+ if (IS_CHAN_2GHZ(chan)) {
+ ah->ani_function = (ATH9K_ANI_SPUR_IMMUNITY_LEVEL |
+ ATH9K_ANI_FIRSTEP_LEVEL);
+ if (AR_SREV_9300_20_OR_LATER(ah))
+ ah->ani_function |= ATH9K_ANI_MRC_CCK;
+ } else
+ ah->ani_function = 0;
+ }
+
+ /* always allow mode (on/off) to be controlled */
+ ah->ani_function |= ATH9K_ANI_MODE;
+
+ if (is_scanning ||
+ (ah->opmode != NL80211_IFTYPE_STATION &&
+ ah->opmode != NL80211_IFTYPE_ADHOC)) {
+ /*
+ * If we're scanning or in AP mode, the defaults (ini)
+ * should be in place. For an AP we assume the historical
+ * levels for this channel are probably outdated so start
+ * from defaults instead.
+ */
+ if (aniState->ofdmNoiseImmunityLevel !=
+ ATH9K_ANI_OFDM_DEF_LEVEL ||
+ aniState->cckNoiseImmunityLevel !=
+ ATH9K_ANI_CCK_DEF_LEVEL) {
+ ath_print(common, ATH_DBG_ANI,
+ "Restore defaults: opmode %u "
+ "chan %d Mhz/0x%x is_scanning=%d "
+ "ofdm:%d cck:%d\n",
+ ah->opmode,
+ chan->channel,
+ chan->channelFlags,
+ is_scanning,
+ aniState->ofdmNoiseImmunityLevel,
+ aniState->cckNoiseImmunityLevel);
+
+ ath9k_hw_set_ofdm_nil(ah, ATH9K_ANI_OFDM_DEF_LEVEL);
+ ath9k_hw_set_cck_nil(ah, ATH9K_ANI_CCK_DEF_LEVEL);
+ }
+ } else {
+ /*
+ * restore historical levels for this channel
+ */
+ ath_print(common, ATH_DBG_ANI,
+ "Restore history: opmode %u "
+ "chan %d Mhz/0x%x is_scanning=%d "
+ "ofdm:%d cck:%d\n",
+ ah->opmode,
+ chan->channel,
+ chan->channelFlags,
+ is_scanning,
+ aniState->ofdmNoiseImmunityLevel,
+ aniState->cckNoiseImmunityLevel);
+
+ ath9k_hw_set_ofdm_nil(ah,
+ aniState->ofdmNoiseImmunityLevel);
+ ath9k_hw_set_cck_nil(ah,
+ aniState->cckNoiseImmunityLevel);
+ }
+
+ /*
+ * enable phy counters if hw supports or if not, enable phy
+ * interrupts (so we can count each one)
+ */
+ ath9k_ani_restart_new(ah);
+
+ ENABLE_REGWRITE_BUFFER(ah);
+
+ REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING);
+ REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING);
+
+ REGWRITE_BUFFER_FLUSH(ah);
+ DISABLE_REGWRITE_BUFFER(ah);
+}
+
+static void ath9k_hw_ani_monitor_old(struct ath_hw *ah,
+ struct ath9k_channel *chan)
{
struct ar5416AniState *aniState;
struct ath_common *common = ath9k_hw_common(ah);
@@ -390,7 +788,7 @@ void ath9k_hw_ani_monitor(struct ath_hw *ah,
listenTime = ath9k_hw_ani_get_listen_time(ah);
if (listenTime < 0) {
ah->stats.ast_ani_lneg++;
- ath9k_ani_restart(ah);
+ ath9k_ani_restart_old(ah);
return;
}
@@ -444,21 +842,166 @@ void ath9k_hw_ani_monitor(struct ath_hw *ah,
aniState->cckPhyErrCount <= aniState->listenTime *
aniState->cckTrigLow / 1000)
ath9k_hw_ani_lower_immunity(ah);
- ath9k_ani_restart(ah);
+ ath9k_ani_restart_old(ah);
} else if (aniState->listenTime > ah->aniperiod) {
if (aniState->ofdmPhyErrCount > aniState->listenTime *
aniState->ofdmTrigHigh / 1000) {
- ath9k_hw_ani_ofdm_err_trigger(ah);
- ath9k_ani_restart(ah);
+ ath9k_hw_ani_ofdm_err_trigger_old(ah);
+ ath9k_ani_restart_old(ah);
} else if (aniState->cckPhyErrCount >
aniState->listenTime * aniState->cckTrigHigh /
1000) {
- ath9k_hw_ani_cck_err_trigger(ah);
- ath9k_ani_restart(ah);
+ ath9k_hw_ani_cck_err_trigger_old(ah);
+ ath9k_ani_restart_old(ah);
+ }
+ }
+}
+
+static void ath9k_hw_ani_monitor_new(struct ath_hw *ah,
+ struct ath9k_channel *chan)
+{
+ struct ar5416AniState *aniState;
+ struct ath_common *common = ath9k_hw_common(ah);
+ int32_t listenTime;
+ u32 phyCnt1, phyCnt2;
+ u32 ofdmPhyErrCnt, cckPhyErrCnt;
+ u32 ofdmPhyErrRate, cckPhyErrRate;
+
+ if (!DO_ANI(ah))
+ return;
+
+ aniState = ah->curani;
+ if (WARN_ON(!aniState))
+ return;
+
+ listenTime = ath9k_hw_ani_get_listen_time(ah);
+ if (listenTime <= 0) {
+ ah->stats.ast_ani_lneg++;
+ /* restart ANI period if listenTime is invalid */
+ ath_print(common, ATH_DBG_ANI,
+ "listenTime=%d - on new ani monitor\n",
+ listenTime);
+ ath9k_ani_restart_new(ah);
+ return;
+ }
+
+ aniState->listenTime += listenTime;
+
+ ath9k_hw_update_mibstats(ah, &ah->ah_mibStats);
+
+ phyCnt1 = REG_READ(ah, AR_PHY_ERR_1);
+ phyCnt2 = REG_READ(ah, AR_PHY_ERR_2);
+
+ if (phyCnt1 < aniState->ofdmPhyErrBase ||
+ phyCnt2 < aniState->cckPhyErrBase) {
+ if (phyCnt1 < aniState->ofdmPhyErrBase) {
+ ath_print(common, ATH_DBG_ANI,
+ "phyCnt1 0x%x, resetting "
+ "counter value to 0x%x\n",
+ phyCnt1,
+ aniState->ofdmPhyErrBase);
+ REG_WRITE(ah, AR_PHY_ERR_1,
+ aniState->ofdmPhyErrBase);
+ REG_WRITE(ah, AR_PHY_ERR_MASK_1,
+ AR_PHY_ERR_OFDM_TIMING);
+ }
+ if (phyCnt2 < aniState->cckPhyErrBase) {
+ ath_print(common, ATH_DBG_ANI,
+ "phyCnt2 0x%x, resetting "
+ "counter value to 0x%x\n",
+ phyCnt2,
+ aniState->cckPhyErrBase);
+ REG_WRITE(ah, AR_PHY_ERR_2,
+ aniState->cckPhyErrBase);
+ REG_WRITE(ah, AR_PHY_ERR_MASK_2,
+ AR_PHY_ERR_CCK_TIMING);
+ }
+ return;
+ }
+
+ ofdmPhyErrCnt = phyCnt1 - aniState->ofdmPhyErrBase;
+ ah->stats.ast_ani_ofdmerrs +=
+ ofdmPhyErrCnt - aniState->ofdmPhyErrCount;
+ aniState->ofdmPhyErrCount = ofdmPhyErrCnt;
+
+ cckPhyErrCnt = phyCnt2 - aniState->cckPhyErrBase;
+ ah->stats.ast_ani_cckerrs +=
+ cckPhyErrCnt - aniState->cckPhyErrCount;
+ aniState->cckPhyErrCount = cckPhyErrCnt;
+
+ ath_print(common, ATH_DBG_ANI,
+ "Errors: OFDM=0x%08x-0x%08x=%d "
+ "CCK=0x%08x-0x%08x=%d\n",
+ phyCnt1,
+ aniState->ofdmPhyErrBase,
+ ofdmPhyErrCnt,
+ phyCnt2,
+ aniState->cckPhyErrBase,
+ cckPhyErrCnt);
+
+ ofdmPhyErrRate = aniState->ofdmPhyErrCount * 1000 /
+ aniState->listenTime;
+ cckPhyErrRate = aniState->cckPhyErrCount * 1000 /
+ aniState->listenTime;
+
+ ath_print(common, ATH_DBG_ANI,
+ "listenTime=%d OFDM:%d errs=%d/s CCK:%d "
+ "errs=%d/s ofdm_turn=%d\n",
+ listenTime, aniState->ofdmNoiseImmunityLevel,
+ ofdmPhyErrRate, aniState->cckNoiseImmunityLevel,
+ cckPhyErrRate, aniState->ofdmsTurn);
+
+ if (aniState->listenTime > 5 * ah->aniperiod) {
+ if (ofdmPhyErrRate <= aniState->ofdmTrigLow &&
+ cckPhyErrRate <= aniState->cckTrigLow) {
+ ath_print(common, ATH_DBG_ANI,
+ "1. listenTime=%d OFDM:%d errs=%d/s(<%d) "
+ "CCK:%d errs=%d/s(<%d) -> "
+ "ath9k_hw_ani_lower_immunity()\n",
+ aniState->listenTime,
+ aniState->ofdmNoiseImmunityLevel,
+ ofdmPhyErrRate,
+ aniState->ofdmTrigLow,
+ aniState->cckNoiseImmunityLevel,
+ cckPhyErrRate,
+ aniState->cckTrigLow);
+ ath9k_hw_ani_lower_immunity(ah);
+ aniState->ofdmsTurn = !aniState->ofdmsTurn;
+ }
+ ath_print(common, ATH_DBG_ANI,
+ "1 listenTime=%d ofdm=%d/s cck=%d/s - "
+ "calling ath9k_ani_restart_new()\n",
+ aniState->listenTime, ofdmPhyErrRate, cckPhyErrRate);
+ ath9k_ani_restart_new(ah);
+ } else if (aniState->listenTime > ah->aniperiod) {
+ /* check to see if need to raise immunity */
+ if (ofdmPhyErrRate > aniState->ofdmTrigHigh &&
+ (cckPhyErrRate <= aniState->cckTrigHigh ||
+ aniState->ofdmsTurn)) {
+ ath_print(common, ATH_DBG_ANI,
+ "2 listenTime=%d OFDM:%d errs=%d/s(>%d) -> "
+ "ath9k_hw_ani_ofdm_err_trigger_new()\n",
+ aniState->listenTime,
+ aniState->ofdmNoiseImmunityLevel,
+ ofdmPhyErrRate,
+ aniState->ofdmTrigHigh);
+ ath9k_hw_ani_ofdm_err_trigger_new(ah);
+ ath9k_ani_restart_new(ah);
+ aniState->ofdmsTurn = false;
+ } else if (cckPhyErrRate > aniState->cckTrigHigh) {
+ ath_print(common, ATH_DBG_ANI,
+ "3 listenTime=%d CCK:%d errs=%d/s(>%d) -> "
+ "ath9k_hw_ani_cck_err_trigger_new()\n",
+ aniState->listenTime,
+ aniState->cckNoiseImmunityLevel,
+ cckPhyErrRate,
+ aniState->cckTrigHigh);
+ ath9k_hw_ani_cck_err_trigger_new(ah);
+ ath9k_ani_restart_new(ah);
+ aniState->ofdmsTurn = true;
}
}
}
-EXPORT_SYMBOL(ath9k_hw_ani_monitor);
void ath9k_enable_mib_counters(struct ath_hw *ah)
{
@@ -495,6 +1038,7 @@ void ath9k_hw_disable_mib_counters(struct ath_hw *ah)
REG_WRITE(ah, AR_FILT_OFDM, 0);
REG_WRITE(ah, AR_FILT_CCK, 0);
}
+EXPORT_SYMBOL(ath9k_hw_disable_mib_counters);
u32 ath9k_hw_GetMibCycleCountsPct(struct ath_hw *ah,
u32 *rxc_pcnt,
@@ -542,7 +1086,7 @@ u32 ath9k_hw_GetMibCycleCountsPct(struct ath_hw *ah,
* any of the MIB counters overflow/trigger so don't assume we're
* here because a PHY error counter triggered.
*/
-void ath9k_hw_procmibevent(struct ath_hw *ah)
+static void ath9k_hw_proc_mib_event_old(struct ath_hw *ah)
{
u32 phyCnt1, phyCnt2;
@@ -555,8 +1099,15 @@ void ath9k_hw_procmibevent(struct ath_hw *ah)
/* Clear the mib counters and save them in the stats */
ath9k_hw_update_mibstats(ah, &ah->ah_mibStats);
- if (!DO_ANI(ah))
+ if (!DO_ANI(ah)) {
+ /*
+ * We must always clear the interrupt cause by
+ * resetting the phy error regs.
+ */
+ REG_WRITE(ah, AR_PHY_ERR_1, 0);
+ REG_WRITE(ah, AR_PHY_ERR_2, 0);
return;
+ }
/* NB: these are not reset-on-read */
phyCnt1 = REG_READ(ah, AR_PHY_ERR_1);
@@ -584,14 +1135,51 @@ void ath9k_hw_procmibevent(struct ath_hw *ah)
* check will never be true.
*/
if (aniState->ofdmPhyErrCount > aniState->ofdmTrigHigh)
- ath9k_hw_ani_ofdm_err_trigger(ah);
+ ath9k_hw_ani_ofdm_err_trigger_new(ah);
if (aniState->cckPhyErrCount > aniState->cckTrigHigh)
- ath9k_hw_ani_cck_err_trigger(ah);
+ ath9k_hw_ani_cck_err_trigger_old(ah);
/* NB: always restart to insure the h/w counters are reset */
- ath9k_ani_restart(ah);
+ ath9k_ani_restart_old(ah);
}
}
-EXPORT_SYMBOL(ath9k_hw_procmibevent);
+
+/*
+ * Process a MIB interrupt. We may potentially be invoked because
+ * any of the MIB counters overflow/trigger so don't assume we're
+ * here because a PHY error counter triggered.
+ */
+static void ath9k_hw_proc_mib_event_new(struct ath_hw *ah)
+{
+ u32 phyCnt1, phyCnt2;
+
+ /* Reset these counters regardless */
+ REG_WRITE(ah, AR_FILT_OFDM, 0);
+ REG_WRITE(ah, AR_FILT_CCK, 0);
+ if (!(REG_READ(ah, AR_SLP_MIB_CTRL) & AR_SLP_MIB_PENDING))
+ REG_WRITE(ah, AR_SLP_MIB_CTRL, AR_SLP_MIB_CLEAR);
+
+ /* Clear the mib counters and save them in the stats */
+ ath9k_hw_update_mibstats(ah, &ah->ah_mibStats);
+
+ if (!DO_ANI(ah)) {
+ /*
+ * We must always clear the interrupt cause by
+ * resetting the phy error regs.
+ */
+ REG_WRITE(ah, AR_PHY_ERR_1, 0);
+ REG_WRITE(ah, AR_PHY_ERR_2, 0);
+ return;
+ }
+
+ /* NB: these are not reset-on-read */
+ phyCnt1 = REG_READ(ah, AR_PHY_ERR_1);
+ phyCnt2 = REG_READ(ah, AR_PHY_ERR_2);
+
+ /* NB: always restart to insure the h/w counters are reset */
+ if (((phyCnt1 & AR_MIBCNT_INTRMASK) == AR_MIBCNT_INTRMASK) ||
+ ((phyCnt2 & AR_MIBCNT_INTRMASK) == AR_MIBCNT_INTRMASK))
+ ath9k_ani_restart_new(ah);
+}
void ath9k_hw_ani_setup(struct ath_hw *ah)
{
@@ -619,22 +1207,70 @@ void ath9k_hw_ani_init(struct ath_hw *ah)
memset(ah->ani, 0, sizeof(ah->ani));
for (i = 0; i < ARRAY_SIZE(ah->ani); i++) {
- ah->ani[i].ofdmTrigHigh = ATH9K_ANI_OFDM_TRIG_HIGH;
- ah->ani[i].ofdmTrigLow = ATH9K_ANI_OFDM_TRIG_LOW;
- ah->ani[i].cckTrigHigh = ATH9K_ANI_CCK_TRIG_HIGH;
- ah->ani[i].cckTrigLow = ATH9K_ANI_CCK_TRIG_LOW;
+ if (AR_SREV_9300_20_OR_LATER(ah) || modparam_force_new_ani) {
+ ah->ani[i].ofdmTrigHigh = ATH9K_ANI_OFDM_TRIG_HIGH_NEW;
+ ah->ani[i].ofdmTrigLow = ATH9K_ANI_OFDM_TRIG_LOW_NEW;
+
+ ah->ani[i].cckTrigHigh = ATH9K_ANI_CCK_TRIG_HIGH_NEW;
+ ah->ani[i].cckTrigLow = ATH9K_ANI_CCK_TRIG_LOW_NEW;
+
+ ah->ani[i].spurImmunityLevel =
+ ATH9K_ANI_SPUR_IMMUNE_LVL_NEW;
+
+ ah->ani[i].firstepLevel = ATH9K_ANI_FIRSTEP_LVL_NEW;
+
+ ah->ani[i].ofdmPhyErrBase = 0;
+ ah->ani[i].cckPhyErrBase = 0;
+
+ if (AR_SREV_9300_20_OR_LATER(ah))
+ ah->ani[i].mrcCCKOff =
+ !ATH9K_ANI_ENABLE_MRC_CCK;
+ else
+ ah->ani[i].mrcCCKOff = true;
+
+ ah->ani[i].ofdmsTurn = true;
+ } else {
+ ah->ani[i].ofdmTrigHigh = ATH9K_ANI_OFDM_TRIG_HIGH_OLD;
+ ah->ani[i].ofdmTrigLow = ATH9K_ANI_OFDM_TRIG_LOW_OLD;
+
+ ah->ani[i].cckTrigHigh = ATH9K_ANI_CCK_TRIG_HIGH_OLD;
+ ah->ani[i].cckTrigLow = ATH9K_ANI_CCK_TRIG_LOW_OLD;
+
+ ah->ani[i].spurImmunityLevel =
+ ATH9K_ANI_SPUR_IMMUNE_LVL_OLD;
+ ah->ani[i].firstepLevel = ATH9K_ANI_FIRSTEP_LVL_OLD;
+
+ ah->ani[i].ofdmPhyErrBase =
+ AR_PHY_COUNTMAX - ATH9K_ANI_OFDM_TRIG_HIGH_OLD;
+ ah->ani[i].cckPhyErrBase =
+ AR_PHY_COUNTMAX - ATH9K_ANI_CCK_TRIG_HIGH_OLD;
+ ah->ani[i].cckWeakSigThreshold =
+ ATH9K_ANI_CCK_WEAK_SIG_THR;
+ }
+
ah->ani[i].rssiThrHigh = ATH9K_ANI_RSSI_THR_HIGH;
ah->ani[i].rssiThrLow = ATH9K_ANI_RSSI_THR_LOW;
ah->ani[i].ofdmWeakSigDetectOff =
!ATH9K_ANI_USE_OFDM_WEAK_SIG;
- ah->ani[i].cckWeakSigThreshold =
- ATH9K_ANI_CCK_WEAK_SIG_THR;
- ah->ani[i].spurImmunityLevel = ATH9K_ANI_SPUR_IMMUNE_LVL;
- ah->ani[i].firstepLevel = ATH9K_ANI_FIRSTEP_LVL;
- ah->ani[i].ofdmPhyErrBase =
- AR_PHY_COUNTMAX - ATH9K_ANI_OFDM_TRIG_HIGH;
- ah->ani[i].cckPhyErrBase =
- AR_PHY_COUNTMAX - ATH9K_ANI_CCK_TRIG_HIGH;
+ ah->ani[i].cckNoiseImmunityLevel = ATH9K_ANI_CCK_DEF_LEVEL;
+ }
+
+ /*
+ * since we expect some ongoing maintenance on the tables, let's sanity
+ * check here default level should not modify INI setting.
+ */
+ if (AR_SREV_9300_20_OR_LATER(ah) || modparam_force_new_ani) {
+ const struct ani_ofdm_level_entry *entry_ofdm;
+ const struct ani_cck_level_entry *entry_cck;
+
+ entry_ofdm = &ofdm_level_table[ATH9K_ANI_OFDM_DEF_LEVEL];
+ entry_cck = &cck_level_table[ATH9K_ANI_CCK_DEF_LEVEL];
+
+ ah->aniperiod = ATH9K_ANI_PERIOD_NEW;
+ ah->config.ani_poll_interval = ATH9K_ANI_POLLINTERVAL_NEW;
+ } else {
+ ah->aniperiod = ATH9K_ANI_PERIOD_OLD;
+ ah->config.ani_poll_interval = ATH9K_ANI_POLLINTERVAL_OLD;
}
ath_print(common, ATH_DBG_ANI,
@@ -653,7 +1289,34 @@ void ath9k_hw_ani_init(struct ath_hw *ah)
ath9k_enable_mib_counters(ah);
- ah->aniperiod = ATH9K_ANI_PERIOD;
if (ah->config.enable_ani)
ah->proc_phyerr |= HAL_PROCESS_ANI;
}
+
+void ath9k_hw_attach_ani_ops_old(struct ath_hw *ah)
+{
+ struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah);
+ struct ath_hw_ops *ops = ath9k_hw_ops(ah);
+
+ priv_ops->ani_reset = ath9k_ani_reset_old;
+ priv_ops->ani_lower_immunity = ath9k_hw_ani_lower_immunity_old;
+
+ ops->ani_proc_mib_event = ath9k_hw_proc_mib_event_old;
+ ops->ani_monitor = ath9k_hw_ani_monitor_old;
+
+ ath_print(ath9k_hw_common(ah), ATH_DBG_ANY, "Using ANI v1\n");
+}
+
+void ath9k_hw_attach_ani_ops_new(struct ath_hw *ah)
+{
+ struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah);
+ struct ath_hw_ops *ops = ath9k_hw_ops(ah);
+
+ priv_ops->ani_reset = ath9k_ani_reset_new;
+ priv_ops->ani_lower_immunity = ath9k_hw_ani_lower_immunity_new;
+
+ ops->ani_proc_mib_event = ath9k_hw_proc_mib_event_new;
+ ops->ani_monitor = ath9k_hw_ani_monitor_new;
+
+ ath_print(ath9k_hw_common(ah), ATH_DBG_ANY, "Using ANI v2\n");
+}
diff --git a/drivers/net/wireless/ath/ath9k/ani.h b/drivers/net/wireless/ath/ath9k/ani.h
index 3356762ea38..f4d0a4d48b3 100644
--- a/drivers/net/wireless/ath/ath9k/ani.h
+++ b/drivers/net/wireless/ath/ath9k/ani.h
@@ -23,23 +23,55 @@
#define BEACON_RSSI(ahp) (ahp->stats.avgbrssi)
-#define ATH9K_ANI_OFDM_TRIG_HIGH 500
-#define ATH9K_ANI_OFDM_TRIG_LOW 200
-#define ATH9K_ANI_CCK_TRIG_HIGH 200
-#define ATH9K_ANI_CCK_TRIG_LOW 100
+/* units are errors per second */
+#define ATH9K_ANI_OFDM_TRIG_HIGH_OLD 500
+#define ATH9K_ANI_OFDM_TRIG_HIGH_NEW 1000
+
+/* units are errors per second */
+#define ATH9K_ANI_OFDM_TRIG_LOW_OLD 200
+#define ATH9K_ANI_OFDM_TRIG_LOW_NEW 400
+
+/* units are errors per second */
+#define ATH9K_ANI_CCK_TRIG_HIGH_OLD 200
+#define ATH9K_ANI_CCK_TRIG_HIGH_NEW 600
+
+/* units are errors per second */
+#define ATH9K_ANI_CCK_TRIG_LOW_OLD 100
+#define ATH9K_ANI_CCK_TRIG_LOW_NEW 300
+
#define ATH9K_ANI_NOISE_IMMUNE_LVL 4
#define ATH9K_ANI_USE_OFDM_WEAK_SIG true
#define ATH9K_ANI_CCK_WEAK_SIG_THR false
-#define ATH9K_ANI_SPUR_IMMUNE_LVL 7
-#define ATH9K_ANI_FIRSTEP_LVL 0
+
+#define ATH9K_ANI_SPUR_IMMUNE_LVL_OLD 7
+#define ATH9K_ANI_SPUR_IMMUNE_LVL_NEW 3
+
+#define ATH9K_ANI_FIRSTEP_LVL_OLD 0
+#define ATH9K_ANI_FIRSTEP_LVL_NEW 2
+
#define ATH9K_ANI_RSSI_THR_HIGH 40
#define ATH9K_ANI_RSSI_THR_LOW 7
-#define ATH9K_ANI_PERIOD 100
+
+#define ATH9K_ANI_PERIOD_OLD 100
+#define ATH9K_ANI_PERIOD_NEW 1000
+
+/* in ms */
+#define ATH9K_ANI_POLLINTERVAL_OLD 100
+#define ATH9K_ANI_POLLINTERVAL_NEW 1000
#define HAL_NOISE_IMMUNE_MAX 4
#define HAL_SPUR_IMMUNE_MAX 7
#define HAL_FIRST_STEP_MAX 2
+#define ATH9K_SIG_FIRSTEP_SETTING_MIN 0
+#define ATH9K_SIG_FIRSTEP_SETTING_MAX 20
+#define ATH9K_SIG_SPUR_IMM_SETTING_MIN 0
+#define ATH9K_SIG_SPUR_IMM_SETTING_MAX 22
+
+#define ATH9K_ANI_ENABLE_MRC_CCK true
+
+/* values here are relative to the INI */
+
enum ath9k_ani_cmd {
ATH9K_ANI_PRESENT = 0x1,
ATH9K_ANI_NOISE_IMMUNITY_LEVEL = 0x2,
@@ -49,7 +81,8 @@ enum ath9k_ani_cmd {
ATH9K_ANI_SPUR_IMMUNITY_LEVEL = 0x20,
ATH9K_ANI_MODE = 0x40,
ATH9K_ANI_PHYERR_RESET = 0x80,
- ATH9K_ANI_ALL = 0xff
+ ATH9K_ANI_MRC_CCK = 0x100,
+ ATH9K_ANI_ALL = 0xfff
};
struct ath9k_mib_stats {
@@ -60,9 +93,31 @@ struct ath9k_mib_stats {
u32 beacons;
};
+/* INI default values for ANI registers */
+struct ath9k_ani_default {
+ u16 m1ThreshLow;
+ u16 m2ThreshLow;
+ u16 m1Thresh;
+ u16 m2Thresh;
+ u16 m2CountThr;
+ u16 m2CountThrLow;
+ u16 m1ThreshLowExt;
+ u16 m2ThreshLowExt;
+ u16 m1ThreshExt;
+ u16 m2ThreshExt;
+ u16 firstep;
+ u16 firstepLow;
+ u16 cycpwrThr1;
+ u16 cycpwrThr1Ext;
+};
+
struct ar5416AniState {
struct ath9k_channel *c;
u8 noiseImmunityLevel;
+ u8 ofdmNoiseImmunityLevel;
+ u8 cckNoiseImmunityLevel;
+ bool ofdmsTurn;
+ u8 mrcCCKOff;
u8 spurImmunityLevel;
u8 firstepLevel;
u8 ofdmWeakSigDetectOff;
@@ -85,6 +140,7 @@ struct ar5416AniState {
int16_t pktRssi[2];
int16_t ofdmErrRssi[2];
int16_t cckErrRssi[2];
+ struct ath9k_ani_default iniDef;
};
struct ar5416Stats {
@@ -108,15 +164,13 @@ struct ar5416Stats {
};
#define ah_mibStats stats.ast_mibstats
-void ath9k_ani_reset(struct ath_hw *ah);
-void ath9k_hw_ani_monitor(struct ath_hw *ah,
- struct ath9k_channel *chan);
void ath9k_enable_mib_counters(struct ath_hw *ah);
void ath9k_hw_disable_mib_counters(struct ath_hw *ah);
u32 ath9k_hw_GetMibCycleCountsPct(struct ath_hw *ah, u32 *rxc_pcnt,
u32 *rxf_pcnt, u32 *txf_pcnt);
-void ath9k_hw_procmibevent(struct ath_hw *ah);
void ath9k_hw_ani_setup(struct ath_hw *ah);
void ath9k_hw_ani_init(struct ath_hw *ah);
+int ath9k_hw_get_ani_channel_idx(struct ath_hw *ah,
+ struct ath9k_channel *chan);
#endif /* ANI_H */
diff --git a/drivers/net/wireless/ath/ath9k/ar5008_initvals.h b/drivers/net/wireless/ath/ath9k/ar5008_initvals.h
index 025c31ac614..36f7d0639db 100644
--- a/drivers/net/wireless/ath/ath9k/ar5008_initvals.h
+++ b/drivers/net/wireless/ath/ath9k/ar5008_initvals.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2008-2009 Atheros Communications Inc.
+ * Copyright (c) 2010 Atheros Communications Inc.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -14,729 +14,660 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-#ifndef INITVALS_AR5008_H
-#define INITVALS_AR5008_H
-
static const u32 ar5416Modes[][6] = {
- { 0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160, 0x000001e0 },
- { 0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c, 0x000001e0 },
- { 0x000010b0, 0x00000e60, 0x00001cc0, 0x00007c70, 0x00003e38, 0x00001180 },
- { 0x000010f0, 0x0000a000, 0x00014000, 0x00016000, 0x0000b000, 0x00014008 },
- { 0x00008014, 0x03e803e8, 0x07d007d0, 0x10801600, 0x08400b00, 0x06e006e0 },
- { 0x0000801c, 0x128d93a7, 0x128d93cf, 0x12e013d7, 0x12e013ab, 0x098813cf },
- { 0x00008120, 0x08f04800, 0x08f04800, 0x08f04810, 0x08f04810, 0x08f04810 },
- { 0x000081d0, 0x00003210, 0x00003210, 0x0000320a, 0x0000320a, 0x0000320a },
- { 0x00009804, 0x00000300, 0x000003c4, 0x000003c4, 0x00000300, 0x00000303 },
- { 0x00009820, 0x02020200, 0x02020200, 0x02020200, 0x02020200, 0x02020200 },
- { 0x00009824, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e },
- { 0x00009828, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001 },
- { 0x00009834, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e },
- { 0x00009838, 0x00000007, 0x00000007, 0x00000007, 0x00000007, 0x00000007 },
- { 0x00009844, 0x1372161e, 0x1372161e, 0x137216a0, 0x137216a0, 0x137216a0 },
- { 0x00009848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68 },
- { 0x0000a848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68 },
- { 0x0000b848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68 },
- { 0x00009850, 0x6c48b4e0, 0x6d48b4e0, 0x6d48b0de, 0x6c48b0de, 0x6c48b0de },
- { 0x00009858, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e },
- { 0x0000985c, 0x31395d5e, 0x3139605e, 0x3139605e, 0x31395d5e, 0x31395d5e },
- { 0x00009860, 0x00049d18, 0x00049d18, 0x00049d18, 0x00049d18, 0x00049d18 },
- { 0x00009864, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00 },
- { 0x00009868, 0x409a4190, 0x409a4190, 0x409a4190, 0x409a4190, 0x409a4190 },
- { 0x0000986c, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081 },
- { 0x00009914, 0x000007d0, 0x00000fa0, 0x00001130, 0x00000898, 0x000007d0 },
- { 0x00009918, 0x000001b8, 0x00000370, 0x00000268, 0x00000134, 0x00000134 },
- { 0x00009924, 0xd0058a0b, 0xd0058a0b, 0xd0058a0b, 0xd0058a0b, 0xd0058a0b },
- { 0x00009944, 0xffb81020, 0xffb81020, 0xffb81020, 0xffb81020, 0xffb81020 },
- { 0x00009960, 0x00000900, 0x00000900, 0x00012d80, 0x00012d80, 0x00012d80 },
- { 0x0000a960, 0x00000900, 0x00000900, 0x00012d80, 0x00012d80, 0x00012d80 },
- { 0x0000b960, 0x00000900, 0x00000900, 0x00012d80, 0x00012d80, 0x00012d80 },
- { 0x00009964, 0x00000000, 0x00000000, 0x00001120, 0x00001120, 0x00001120 },
- { 0x000099bc, 0x001a0a00, 0x001a0a00, 0x001a0a00, 0x001a0a00, 0x001a0a00 },
- { 0x000099c0, 0x038919be, 0x038919be, 0x038919be, 0x038919be, 0x038919be },
- { 0x000099c4, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77 },
- { 0x000099c8, 0x6af6532c, 0x6af6532c, 0x6af6532c, 0x6af6532c, 0x6af6532c },
- { 0x000099cc, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8 },
- { 0x000099d0, 0x00046384, 0x00046384, 0x00046384, 0x00046384, 0x00046384 },
- { 0x000099d4, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
- { 0x000099d8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
- { 0x0000a204, 0x00000880, 0x00000880, 0x00000880, 0x00000880, 0x00000880 },
- { 0x0000a208, 0xd6be4788, 0xd6be4788, 0xd03e4788, 0xd03e4788, 0xd03e4788 },
- { 0x0000a20c, 0x002ec1e0, 0x002ec1e0, 0x002ac120, 0x002ac120, 0x002ac120 },
- { 0x0000b20c, 0x002ec1e0, 0x002ec1e0, 0x002ac120, 0x002ac120, 0x002ac120 },
- { 0x0000c20c, 0x002ec1e0, 0x002ec1e0, 0x002ac120, 0x002ac120, 0x002ac120 },
- { 0x0000a21c, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a },
- { 0x0000a230, 0x00000000, 0x00000000, 0x00000210, 0x00000108, 0x00000000 },
- { 0x0000a274, 0x0a1a9caa, 0x0a1a9caa, 0x0a1a7caa, 0x0a1a7caa, 0x0a1a7caa },
- { 0x0000a300, 0x18010000, 0x18010000, 0x18010000, 0x18010000, 0x18010000 },
- { 0x0000a304, 0x30032602, 0x30032602, 0x2e032402, 0x2e032402, 0x2e032402 },
- { 0x0000a308, 0x48073e06, 0x48073e06, 0x4a0a3c06, 0x4a0a3c06, 0x4a0a3c06 },
- { 0x0000a30c, 0x560b4c0a, 0x560b4c0a, 0x621a540b, 0x621a540b, 0x621a540b },
- { 0x0000a310, 0x641a600f, 0x641a600f, 0x764f6c1b, 0x764f6c1b, 0x764f6c1b },
- { 0x0000a314, 0x7a4f6e1b, 0x7a4f6e1b, 0x845b7a5a, 0x845b7a5a, 0x845b7a5a },
- { 0x0000a318, 0x8c5b7e5a, 0x8c5b7e5a, 0x950f8ccf, 0x950f8ccf, 0x950f8ccf },
- { 0x0000a31c, 0x9d0f96cf, 0x9d0f96cf, 0xa5cf9b4f, 0xa5cf9b4f, 0xa5cf9b4f },
- { 0x0000a320, 0xb51fa69f, 0xb51fa69f, 0xbddfaf1f, 0xbddfaf1f, 0xbddfaf1f },
- { 0x0000a324, 0xcb3fbd07, 0xcb3fbcbf, 0xd1ffc93f, 0xd1ffc93f, 0xd1ffc93f },
- { 0x0000a328, 0x0000d7bf, 0x0000d7bf, 0x00000000, 0x00000000, 0x00000000 },
- { 0x0000a32c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
- { 0x0000a330, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
- { 0x0000a334, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
+ {0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160, 0x000001e0},
+ {0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c, 0x000001e0},
+ {0x000010b0, 0x00000e60, 0x00001cc0, 0x00007c70, 0x00003e38, 0x00001180},
+ {0x000010f0, 0x0000a000, 0x00014000, 0x00016000, 0x0000b000, 0x00014008},
+ {0x00008014, 0x03e803e8, 0x07d007d0, 0x10801600, 0x08400b00, 0x06e006e0},
+ {0x0000801c, 0x128d93a7, 0x128d93cf, 0x12e013d7, 0x12e013ab, 0x098813cf},
+ {0x00008120, 0x08f04800, 0x08f04800, 0x08f04810, 0x08f04810, 0x08f04810},
+ {0x000081d0, 0x00003210, 0x00003210, 0x0000320a, 0x0000320a, 0x0000320a},
+ {0x00009804, 0x00000300, 0x000003c4, 0x000003c4, 0x00000300, 0x00000303},
+ {0x00009820, 0x02020200, 0x02020200, 0x02020200, 0x02020200, 0x02020200},
+ {0x00009824, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e},
+ {0x00009828, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001},
+ {0x00009834, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e},
+ {0x00009838, 0x00000007, 0x00000007, 0x00000007, 0x00000007, 0x00000007},
+ {0x00009844, 0x1372161e, 0x1372161e, 0x137216a0, 0x137216a0, 0x137216a0},
+ {0x00009848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68},
+ {0x0000a848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68},
+ {0x0000b848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68},
+ {0x00009850, 0x6c48b4e0, 0x6d48b4e0, 0x6d48b0de, 0x6c48b0de, 0x6c48b0de},
+ {0x00009858, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e},
+ {0x0000985c, 0x31395d5e, 0x3139605e, 0x3139605e, 0x31395d5e, 0x31395d5e},
+ {0x00009860, 0x00049d18, 0x00049d18, 0x00049d18, 0x00049d18, 0x00049d18},
+ {0x00009864, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00},
+ {0x00009868, 0x409a4190, 0x409a4190, 0x409a4190, 0x409a4190, 0x409a4190},
+ {0x0000986c, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081},
+ {0x00009914, 0x000007d0, 0x00000fa0, 0x00001130, 0x00000898, 0x000007d0},
+ {0x00009918, 0x000001b8, 0x00000370, 0x00000268, 0x00000134, 0x00000134},
+ {0x00009924, 0xd0058a0b, 0xd0058a0b, 0xd0058a0b, 0xd0058a0b, 0xd0058a0b},
+ {0x00009944, 0xffb81020, 0xffb81020, 0xffb81020, 0xffb81020, 0xffb81020},
+ {0x00009960, 0x00000900, 0x00000900, 0x00012d80, 0x00012d80, 0x00012d80},
+ {0x0000a960, 0x00000900, 0x00000900, 0x00012d80, 0x00012d80, 0x00012d80},
+ {0x0000b960, 0x00000900, 0x00000900, 0x00012d80, 0x00012d80, 0x00012d80},
+ {0x00009964, 0x00000000, 0x00000000, 0x00001120, 0x00001120, 0x00001120},
+ {0x000099bc, 0x001a0a00, 0x001a0a00, 0x001a0a00, 0x001a0a00, 0x001a0a00},
+ {0x000099c0, 0x038919be, 0x038919be, 0x038919be, 0x038919be, 0x038919be},
+ {0x000099c4, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77},
+ {0x000099c8, 0x6af6532c, 0x6af6532c, 0x6af6532c, 0x6af6532c, 0x6af6532c},
+ {0x000099cc, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8},
+ {0x000099d0, 0x00046384, 0x00046384, 0x00046384, 0x00046384, 0x00046384},
+ {0x000099d4, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+ {0x000099d8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+ {0x0000a204, 0x00000880, 0x00000880, 0x00000880, 0x00000880, 0x00000880},
+ {0x0000a208, 0xd6be4788, 0xd6be4788, 0xd03e4788, 0xd03e4788, 0xd03e4788},
+ {0x0000a20c, 0x002ec1e0, 0x002ec1e0, 0x002ac120, 0x002ac120, 0x002ac120},
+ {0x0000b20c, 0x002ec1e0, 0x002ec1e0, 0x002ac120, 0x002ac120, 0x002ac120},
+ {0x0000c20c, 0x002ec1e0, 0x002ec1e0, 0x002ac120, 0x002ac120, 0x002ac120},
+ {0x0000a21c, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a},
+ {0x0000a230, 0x00000000, 0x00000000, 0x00000210, 0x00000108, 0x00000000},
+ {0x0000a274, 0x0a1a9caa, 0x0a1a9caa, 0x0a1a7caa, 0x0a1a7caa, 0x0a1a7caa},
+ {0x0000a300, 0x18010000, 0x18010000, 0x18010000, 0x18010000, 0x18010000},
+ {0x0000a304, 0x30032602, 0x30032602, 0x2e032402, 0x2e032402, 0x2e032402},
+ {0x0000a308, 0x48073e06, 0x48073e06, 0x4a0a3c06, 0x4a0a3c06, 0x4a0a3c06},
+ {0x0000a30c, 0x560b4c0a, 0x560b4c0a, 0x621a540b, 0x621a540b, 0x621a540b},
+ {0x0000a310, 0x641a600f, 0x641a600f, 0x764f6c1b, 0x764f6c1b, 0x764f6c1b},
+ {0x0000a314, 0x7a4f6e1b, 0x7a4f6e1b, 0x845b7a5a, 0x845b7a5a, 0x845b7a5a},
+ {0x0000a318, 0x8c5b7e5a, 0x8c5b7e5a, 0x950f8ccf, 0x950f8ccf, 0x950f8ccf},
+ {0x0000a31c, 0x9d0f96cf, 0x9d0f96cf, 0xa5cf9b4f, 0xa5cf9b4f, 0xa5cf9b4f},
+ {0x0000a320, 0xb51fa69f, 0xb51fa69f, 0xbddfaf1f, 0xbddfaf1f, 0xbddfaf1f},
+ {0x0000a324, 0xcb3fbd07, 0xcb3fbcbf, 0xd1ffc93f, 0xd1ffc93f, 0xd1ffc93f},
+ {0x0000a328, 0x0000d7bf, 0x0000d7bf, 0x00000000, 0x00000000, 0x00000000},
+ {0x0000a32c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+ {0x0000a330, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+ {0x0000a334, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
};
static const u32 ar5416Common[][2] = {
- { 0x0000000c, 0x00000000 },
- { 0x00000030, 0x00020015 },
- { 0x00000034, 0x00000005 },
- { 0x00000040, 0x00000000 },
- { 0x00000044, 0x00000008 },
- { 0x00000048, 0x00000008 },
- { 0x0000004c, 0x00000010 },
- { 0x00000050, 0x00000000 },
- { 0x00000054, 0x0000001f },
- { 0x00000800, 0x00000000 },
- { 0x00000804, 0x00000000 },
- { 0x00000808, 0x00000000 },
- { 0x0000080c, 0x00000000 },
- { 0x00000810, 0x00000000 },
- { 0x00000814, 0x00000000 },
- { 0x00000818, 0x00000000 },
- { 0x0000081c, 0x00000000 },
- { 0x00000820, 0x00000000 },
- { 0x00000824, 0x00000000 },
- { 0x00001040, 0x002ffc0f },
- { 0x00001044, 0x002ffc0f },
- { 0x00001048, 0x002ffc0f },
- { 0x0000104c, 0x002ffc0f },
- { 0x00001050, 0x002ffc0f },
- { 0x00001054, 0x002ffc0f },
- { 0x00001058, 0x002ffc0f },
- { 0x0000105c, 0x002ffc0f },
- { 0x00001060, 0x002ffc0f },
- { 0x00001064, 0x002ffc0f },
- { 0x00001230, 0x00000000 },
- { 0x00001270, 0x00000000 },
- { 0x00001038, 0x00000000 },
- { 0x00001078, 0x00000000 },
- { 0x000010b8, 0x00000000 },
- { 0x000010f8, 0x00000000 },
- { 0x00001138, 0x00000000 },
- { 0x00001178, 0x00000000 },
- { 0x000011b8, 0x00000000 },
- { 0x000011f8, 0x00000000 },
- { 0x00001238, 0x00000000 },
- { 0x00001278, 0x00000000 },
- { 0x000012b8, 0x00000000 },
- { 0x000012f8, 0x00000000 },
- { 0x00001338, 0x00000000 },
- { 0x00001378, 0x00000000 },
- { 0x000013b8, 0x00000000 },
- { 0x000013f8, 0x00000000 },
- { 0x00001438, 0x00000000 },
- { 0x00001478, 0x00000000 },
- { 0x000014b8, 0x00000000 },
- { 0x000014f8, 0x00000000 },
- { 0x00001538, 0x00000000 },
- { 0x00001578, 0x00000000 },
- { 0x000015b8, 0x00000000 },
- { 0x000015f8, 0x00000000 },
- { 0x00001638, 0x00000000 },
- { 0x00001678, 0x00000000 },
- { 0x000016b8, 0x00000000 },
- { 0x000016f8, 0x00000000 },
- { 0x00001738, 0x00000000 },
- { 0x00001778, 0x00000000 },
- { 0x000017b8, 0x00000000 },
- { 0x000017f8, 0x00000000 },
- { 0x0000103c, 0x00000000 },
- { 0x0000107c, 0x00000000 },
- { 0x000010bc, 0x00000000 },
- { 0x000010fc, 0x00000000 },
- { 0x0000113c, 0x00000000 },
- { 0x0000117c, 0x00000000 },
- { 0x000011bc, 0x00000000 },
- { 0x000011fc, 0x00000000 },
- { 0x0000123c, 0x00000000 },
- { 0x0000127c, 0x00000000 },
- { 0x000012bc, 0x00000000 },
- { 0x000012fc, 0x00000000 },
- { 0x0000133c, 0x00000000 },
- { 0x0000137c, 0x00000000 },
- { 0x000013bc, 0x00000000 },
- { 0x000013fc, 0x00000000 },
- { 0x0000143c, 0x00000000 },
- { 0x0000147c, 0x00000000 },
- { 0x00004030, 0x00000002 },
- { 0x0000403c, 0x00000002 },
- { 0x00007010, 0x00000000 },
- { 0x00007038, 0x000004c2 },
- { 0x00008004, 0x00000000 },
- { 0x00008008, 0x00000000 },
- { 0x0000800c, 0x00000000 },
- { 0x00008018, 0x00000700 },
- { 0x00008020, 0x00000000 },
- { 0x00008038, 0x00000000 },
- { 0x0000803c, 0x00000000 },
- { 0x00008048, 0x40000000 },
- { 0x00008054, 0x00000000 },
- { 0x00008058, 0x00000000 },
- { 0x0000805c, 0x000fc78f },
- { 0x00008060, 0x0000000f },
- { 0x00008064, 0x00000000 },
- { 0x000080c0, 0x2a82301a },
- { 0x000080c4, 0x05dc01e0 },
- { 0x000080c8, 0x1f402710 },
- { 0x000080cc, 0x01f40000 },
- { 0x000080d0, 0x00001e00 },
- { 0x000080d4, 0x00000000 },
- { 0x000080d8, 0x00400000 },
- { 0x000080e0, 0xffffffff },
- { 0x000080e4, 0x0000ffff },
- { 0x000080e8, 0x003f3f3f },
- { 0x000080ec, 0x00000000 },
- { 0x000080f0, 0x00000000 },
- { 0x000080f4, 0x00000000 },
- { 0x000080f8, 0x00000000 },
- { 0x000080fc, 0x00020000 },
- { 0x00008100, 0x00020000 },
- { 0x00008104, 0x00000001 },
- { 0x00008108, 0x00000052 },
- { 0x0000810c, 0x00000000 },
- { 0x00008110, 0x00000168 },
- { 0x00008118, 0x000100aa },
- { 0x0000811c, 0x00003210 },
- { 0x00008124, 0x00000000 },
- { 0x00008128, 0x00000000 },
- { 0x0000812c, 0x00000000 },
- { 0x00008130, 0x00000000 },
- { 0x00008134, 0x00000000 },
- { 0x00008138, 0x00000000 },
- { 0x0000813c, 0x00000000 },
- { 0x00008144, 0xffffffff },
- { 0x00008168, 0x00000000 },
- { 0x0000816c, 0x00000000 },
- { 0x00008170, 0x32143320 },
- { 0x00008174, 0xfaa4fa50 },
- { 0x00008178, 0x00000100 },
- { 0x0000817c, 0x00000000 },
- { 0x000081c4, 0x00000000 },
- { 0x000081ec, 0x00000000 },
- { 0x000081f0, 0x00000000 },
- { 0x000081f4, 0x00000000 },
- { 0x000081f8, 0x00000000 },
- { 0x000081fc, 0x00000000 },
- { 0x00008200, 0x00000000 },
- { 0x00008204, 0x00000000 },
- { 0x00008208, 0x00000000 },
- { 0x0000820c, 0x00000000 },
- { 0x00008210, 0x00000000 },
- { 0x00008214, 0x00000000 },
- { 0x00008218, 0x00000000 },
- { 0x0000821c, 0x00000000 },
- { 0x00008220, 0x00000000 },
- { 0x00008224, 0x00000000 },
- { 0x00008228, 0x00000000 },
- { 0x0000822c, 0x00000000 },
- { 0x00008230, 0x00000000 },
- { 0x00008234, 0x00000000 },
- { 0x00008238, 0x00000000 },
- { 0x0000823c, 0x00000000 },
- { 0x00008240, 0x00100000 },
- { 0x00008244, 0x0010f400 },
- { 0x00008248, 0x00000100 },
- { 0x0000824c, 0x0001e800 },
- { 0x00008250, 0x00000000 },
- { 0x00008254, 0x00000000 },
- { 0x00008258, 0x00000000 },
- { 0x0000825c, 0x400000ff },
- { 0x00008260, 0x00080922 },
- { 0x00008264, 0x88000010 },
- { 0x00008270, 0x00000000 },
- { 0x00008274, 0x40000000 },
- { 0x00008278, 0x003e4180 },
- { 0x0000827c, 0x00000000 },
- { 0x00008284, 0x0000002c },
- { 0x00008288, 0x0000002c },
- { 0x0000828c, 0x00000000 },
- { 0x00008294, 0x00000000 },
- { 0x00008298, 0x00000000 },
- { 0x00008300, 0x00000000 },
- { 0x00008304, 0x00000000 },
- { 0x00008308, 0x00000000 },
- { 0x0000830c, 0x00000000 },
- { 0x00008310, 0x00000000 },
- { 0x00008314, 0x00000000 },
- { 0x00008318, 0x00000000 },
- { 0x00008328, 0x00000000 },
- { 0x0000832c, 0x00000007 },
- { 0x00008330, 0x00000302 },
- { 0x00008334, 0x00000e00 },
- { 0x00008338, 0x00070000 },
- { 0x0000833c, 0x00000000 },
- { 0x00008340, 0x000107ff },
- { 0x00009808, 0x00000000 },
- { 0x0000980c, 0xad848e19 },
- { 0x00009810, 0x7d14e000 },
- { 0x00009814, 0x9c0a9f6b },
- { 0x0000981c, 0x00000000 },
- { 0x0000982c, 0x0000a000 },
- { 0x00009830, 0x00000000 },
- { 0x0000983c, 0x00200400 },
- { 0x00009840, 0x206a002e },
- { 0x0000984c, 0x1284233c },
- { 0x00009854, 0x00000859 },
- { 0x00009900, 0x00000000 },
- { 0x00009904, 0x00000000 },
- { 0x00009908, 0x00000000 },
- { 0x0000990c, 0x00000000 },
- { 0x0000991c, 0x10000fff },
- { 0x00009920, 0x05100000 },
- { 0x0000a920, 0x05100000 },
- { 0x0000b920, 0x05100000 },
- { 0x00009928, 0x00000001 },
- { 0x0000992c, 0x00000004 },
- { 0x00009934, 0x1e1f2022 },
- { 0x00009938, 0x0a0b0c0d },
- { 0x0000993c, 0x00000000 },
- { 0x00009948, 0x9280b212 },
- { 0x0000994c, 0x00020028 },
- { 0x00009954, 0x5d50e188 },
- { 0x00009958, 0x00081fff },
- { 0x0000c95c, 0x004b6a8e },
- { 0x0000c968, 0x000003ce },
- { 0x00009970, 0x190fb515 },
- { 0x00009974, 0x00000000 },
- { 0x00009978, 0x00000001 },
- { 0x0000997c, 0x00000000 },
- { 0x00009980, 0x00000000 },
- { 0x00009984, 0x00000000 },
- { 0x00009988, 0x00000000 },
- { 0x0000998c, 0x00000000 },
- { 0x00009990, 0x00000000 },
- { 0x00009994, 0x00000000 },
- { 0x00009998, 0x00000000 },
- { 0x0000999c, 0x00000000 },
- { 0x000099a0, 0x00000000 },
- { 0x000099a4, 0x00000001 },
- { 0x000099a8, 0x001fff00 },
- { 0x000099ac, 0x00000000 },
- { 0x000099b0, 0x03051000 },
- { 0x000099dc, 0x00000000 },
- { 0x000099e0, 0x00000200 },
- { 0x000099e4, 0xaaaaaaaa },
- { 0x000099e8, 0x3c466478 },
- { 0x000099ec, 0x000000aa },
- { 0x000099fc, 0x00001042 },
- { 0x00009b00, 0x00000000 },
- { 0x00009b04, 0x00000001 },
- { 0x00009b08, 0x00000002 },
- { 0x00009b0c, 0x00000003 },
- { 0x00009b10, 0x00000004 },
- { 0x00009b14, 0x00000005 },
- { 0x00009b18, 0x00000008 },
- { 0x00009b1c, 0x00000009 },
- { 0x00009b20, 0x0000000a },
- { 0x00009b24, 0x0000000b },
- { 0x00009b28, 0x0000000c },
- { 0x00009b2c, 0x0000000d },
- { 0x00009b30, 0x00000010 },
- { 0x00009b34, 0x00000011 },
- { 0x00009b38, 0x00000012 },
- { 0x00009b3c, 0x00000013 },
- { 0x00009b40, 0x00000014 },
- { 0x00009b44, 0x00000015 },
- { 0x00009b48, 0x00000018 },
- { 0x00009b4c, 0x00000019 },
- { 0x00009b50, 0x0000001a },
- { 0x00009b54, 0x0000001b },
- { 0x00009b58, 0x0000001c },
- { 0x00009b5c, 0x0000001d },
- { 0x00009b60, 0x00000020 },
- { 0x00009b64, 0x00000021 },
- { 0x00009b68, 0x00000022 },
- { 0x00009b6c, 0x00000023 },
- { 0x00009b70, 0x00000024 },
- { 0x00009b74, 0x00000025 },
- { 0x00009b78, 0x00000028 },
- { 0x00009b7c, 0x00000029 },
- { 0x00009b80, 0x0000002a },
- { 0x00009b84, 0x0000002b },
- { 0x00009b88, 0x0000002c },
- { 0x00009b8c, 0x0000002d },
- { 0x00009b90, 0x00000030 },
- { 0x00009b94, 0x00000031 },
- { 0x00009b98, 0x00000032 },
- { 0x00009b9c, 0x00000033 },
- { 0x00009ba0, 0x00000034 },
- { 0x00009ba4, 0x00000035 },
- { 0x00009ba8, 0x00000035 },
- { 0x00009bac, 0x00000035 },
- { 0x00009bb0, 0x00000035 },
- { 0x00009bb4, 0x00000035 },
- { 0x00009bb8, 0x00000035 },
- { 0x00009bbc, 0x00000035 },
- { 0x00009bc0, 0x00000035 },
- { 0x00009bc4, 0x00000035 },
- { 0x00009bc8, 0x00000035 },
- { 0x00009bcc, 0x00000035 },
- { 0x00009bd0, 0x00000035 },
- { 0x00009bd4, 0x00000035 },
- { 0x00009bd8, 0x00000035 },
- { 0x00009bdc, 0x00000035 },
- { 0x00009be0, 0x00000035 },
- { 0x00009be4, 0x00000035 },
- { 0x00009be8, 0x00000035 },
- { 0x00009bec, 0x00000035 },
- { 0x00009bf0, 0x00000035 },
- { 0x00009bf4, 0x00000035 },
- { 0x00009bf8, 0x00000010 },
- { 0x00009bfc, 0x0000001a },
- { 0x0000a210, 0x40806333 },
- { 0x0000a214, 0x00106c10 },
- { 0x0000a218, 0x009c4060 },
- { 0x0000a220, 0x018830c6 },
- { 0x0000a224, 0x00000400 },
- { 0x0000a228, 0x00000bb5 },
- { 0x0000a22c, 0x00000011 },
- { 0x0000a234, 0x20202020 },
- { 0x0000a238, 0x20202020 },
- { 0x0000a23c, 0x13c889af },
- { 0x0000a240, 0x38490a20 },
- { 0x0000a244, 0x00007bb6 },
- { 0x0000a248, 0x0fff3ffc },
- { 0x0000a24c, 0x00000001 },
- { 0x0000a250, 0x0000a000 },
- { 0x0000a254, 0x00000000 },
- { 0x0000a258, 0x0cc75380 },
- { 0x0000a25c, 0x0f0f0f01 },
- { 0x0000a260, 0xdfa91f01 },
- { 0x0000a268, 0x00000000 },
- { 0x0000a26c, 0x0e79e5c6 },
- { 0x0000b26c, 0x0e79e5c6 },
- { 0x0000c26c, 0x0e79e5c6 },
- { 0x0000d270, 0x00820820 },
- { 0x0000a278, 0x1ce739ce },
- { 0x0000a27c, 0x051701ce },
- { 0x0000a338, 0x00000000 },
- { 0x0000a33c, 0x00000000 },
- { 0x0000a340, 0x00000000 },
- { 0x0000a344, 0x00000000 },
- { 0x0000a348, 0x3fffffff },
- { 0x0000a34c, 0x3fffffff },
- { 0x0000a350, 0x3fffffff },
- { 0x0000a354, 0x0003ffff },
- { 0x0000a358, 0x79a8aa1f },
- { 0x0000d35c, 0x07ffffef },
- { 0x0000d360, 0x0fffffe7 },
- { 0x0000d364, 0x17ffffe5 },
- { 0x0000d368, 0x1fffffe4 },
- { 0x0000d36c, 0x37ffffe3 },
- { 0x0000d370, 0x3fffffe3 },
- { 0x0000d374, 0x57ffffe3 },
- { 0x0000d378, 0x5fffffe2 },
- { 0x0000d37c, 0x7fffffe2 },
- { 0x0000d380, 0x7f3c7bba },
- { 0x0000d384, 0xf3307ff0 },
- { 0x0000a388, 0x08000000 },
- { 0x0000a38c, 0x20202020 },
- { 0x0000a390, 0x20202020 },
- { 0x0000a394, 0x1ce739ce },
- { 0x0000a398, 0x000001ce },
- { 0x0000a39c, 0x00000001 },
- { 0x0000a3a0, 0x00000000 },
- { 0x0000a3a4, 0x00000000 },
- { 0x0000a3a8, 0x00000000 },
- { 0x0000a3ac, 0x00000000 },
- { 0x0000a3b0, 0x00000000 },
- { 0x0000a3b4, 0x00000000 },
- { 0x0000a3b8, 0x00000000 },
- { 0x0000a3bc, 0x00000000 },
- { 0x0000a3c0, 0x00000000 },
- { 0x0000a3c4, 0x00000000 },
- { 0x0000a3c8, 0x00000246 },
- { 0x0000a3cc, 0x20202020 },
- { 0x0000a3d0, 0x20202020 },
- { 0x0000a3d4, 0x20202020 },
- { 0x0000a3dc, 0x1ce739ce },
- { 0x0000a3e0, 0x000001ce },
+ /* Addr allmodes */
+ {0x0000000c, 0x00000000},
+ {0x00000030, 0x00020015},
+ {0x00000034, 0x00000005},
+ {0x00000040, 0x00000000},
+ {0x00000044, 0x00000008},
+ {0x00000048, 0x00000008},
+ {0x0000004c, 0x00000010},
+ {0x00000050, 0x00000000},
+ {0x00000054, 0x0000001f},
+ {0x00000800, 0x00000000},
+ {0x00000804, 0x00000000},
+ {0x00000808, 0x00000000},
+ {0x0000080c, 0x00000000},
+ {0x00000810, 0x00000000},
+ {0x00000814, 0x00000000},
+ {0x00000818, 0x00000000},
+ {0x0000081c, 0x00000000},
+ {0x00000820, 0x00000000},
+ {0x00000824, 0x00000000},
+ {0x00001040, 0x002ffc0f},
+ {0x00001044, 0x002ffc0f},
+ {0x00001048, 0x002ffc0f},
+ {0x0000104c, 0x002ffc0f},
+ {0x00001050, 0x002ffc0f},
+ {0x00001054, 0x002ffc0f},
+ {0x00001058, 0x002ffc0f},
+ {0x0000105c, 0x002ffc0f},
+ {0x00001060, 0x002ffc0f},
+ {0x00001064, 0x002ffc0f},
+ {0x00001230, 0x00000000},
+ {0x00001270, 0x00000000},
+ {0x00001038, 0x00000000},
+ {0x00001078, 0x00000000},
+ {0x000010b8, 0x00000000},
+ {0x000010f8, 0x00000000},
+ {0x00001138, 0x00000000},
+ {0x00001178, 0x00000000},
+ {0x000011b8, 0x00000000},
+ {0x000011f8, 0x00000000},
+ {0x00001238, 0x00000000},
+ {0x00001278, 0x00000000},
+ {0x000012b8, 0x00000000},
+ {0x000012f8, 0x00000000},
+ {0x00001338, 0x00000000},
+ {0x00001378, 0x00000000},
+ {0x000013b8, 0x00000000},
+ {0x000013f8, 0x00000000},
+ {0x00001438, 0x00000000},
+ {0x00001478, 0x00000000},
+ {0x000014b8, 0x00000000},
+ {0x000014f8, 0x00000000},
+ {0x00001538, 0x00000000},
+ {0x00001578, 0x00000000},
+ {0x000015b8, 0x00000000},
+ {0x000015f8, 0x00000000},
+ {0x00001638, 0x00000000},
+ {0x00001678, 0x00000000},
+ {0x000016b8, 0x00000000},
+ {0x000016f8, 0x00000000},
+ {0x00001738, 0x00000000},
+ {0x00001778, 0x00000000},
+ {0x000017b8, 0x00000000},
+ {0x000017f8, 0x00000000},
+ {0x0000103c, 0x00000000},
+ {0x0000107c, 0x00000000},
+ {0x000010bc, 0x00000000},
+ {0x000010fc, 0x00000000},
+ {0x0000113c, 0x00000000},
+ {0x0000117c, 0x00000000},
+ {0x000011bc, 0x00000000},
+ {0x000011fc, 0x00000000},
+ {0x0000123c, 0x00000000},
+ {0x0000127c, 0x00000000},
+ {0x000012bc, 0x00000000},
+ {0x000012fc, 0x00000000},
+ {0x0000133c, 0x00000000},
+ {0x0000137c, 0x00000000},
+ {0x000013bc, 0x00000000},
+ {0x000013fc, 0x00000000},
+ {0x0000143c, 0x00000000},
+ {0x0000147c, 0x00000000},
+ {0x00004030, 0x00000002},
+ {0x0000403c, 0x00000002},
+ {0x00007010, 0x00000000},
+ {0x00007038, 0x000004c2},
+ {0x00008004, 0x00000000},
+ {0x00008008, 0x00000000},
+ {0x0000800c, 0x00000000},
+ {0x00008018, 0x00000700},
+ {0x00008020, 0x00000000},
+ {0x00008038, 0x00000000},
+ {0x0000803c, 0x00000000},
+ {0x00008048, 0x40000000},
+ {0x00008054, 0x00000000},
+ {0x00008058, 0x00000000},
+ {0x0000805c, 0x000fc78f},
+ {0x00008060, 0x0000000f},
+ {0x00008064, 0x00000000},
+ {0x000080c0, 0x2a82301a},
+ {0x000080c4, 0x05dc01e0},
+ {0x000080c8, 0x1f402710},
+ {0x000080cc, 0x01f40000},
+ {0x000080d0, 0x00001e00},
+ {0x000080d4, 0x00000000},
+ {0x000080d8, 0x00400000},
+ {0x000080e0, 0xffffffff},
+ {0x000080e4, 0x0000ffff},
+ {0x000080e8, 0x003f3f3f},
+ {0x000080ec, 0x00000000},
+ {0x000080f0, 0x00000000},
+ {0x000080f4, 0x00000000},
+ {0x000080f8, 0x00000000},
+ {0x000080fc, 0x00020000},
+ {0x00008100, 0x00020000},
+ {0x00008104, 0x00000001},
+ {0x00008108, 0x00000052},
+ {0x0000810c, 0x00000000},
+ {0x00008110, 0x00000168},
+ {0x00008118, 0x000100aa},
+ {0x0000811c, 0x00003210},
+ {0x00008124, 0x00000000},
+ {0x00008128, 0x00000000},
+ {0x0000812c, 0x00000000},
+ {0x00008130, 0x00000000},
+ {0x00008134, 0x00000000},
+ {0x00008138, 0x00000000},
+ {0x0000813c, 0x00000000},
+ {0x00008144, 0xffffffff},
+ {0x00008168, 0x00000000},
+ {0x0000816c, 0x00000000},
+ {0x00008170, 0x32143320},
+ {0x00008174, 0xfaa4fa50},
+ {0x00008178, 0x00000100},
+ {0x0000817c, 0x00000000},
+ {0x000081c4, 0x00000000},
+ {0x000081ec, 0x00000000},
+ {0x000081f0, 0x00000000},
+ {0x000081f4, 0x00000000},
+ {0x000081f8, 0x00000000},
+ {0x000081fc, 0x00000000},
+ {0x00008200, 0x00000000},
+ {0x00008204, 0x00000000},
+ {0x00008208, 0x00000000},
+ {0x0000820c, 0x00000000},
+ {0x00008210, 0x00000000},
+ {0x00008214, 0x00000000},
+ {0x00008218, 0x00000000},
+ {0x0000821c, 0x00000000},
+ {0x00008220, 0x00000000},
+ {0x00008224, 0x00000000},
+ {0x00008228, 0x00000000},
+ {0x0000822c, 0x00000000},
+ {0x00008230, 0x00000000},
+ {0x00008234, 0x00000000},
+ {0x00008238, 0x00000000},
+ {0x0000823c, 0x00000000},
+ {0x00008240, 0x00100000},
+ {0x00008244, 0x0010f400},
+ {0x00008248, 0x00000100},
+ {0x0000824c, 0x0001e800},
+ {0x00008250, 0x00000000},
+ {0x00008254, 0x00000000},
+ {0x00008258, 0x00000000},
+ {0x0000825c, 0x400000ff},
+ {0x00008260, 0x00080922},
+ {0x00008264, 0x88000010},
+ {0x00008270, 0x00000000},
+ {0x00008274, 0x40000000},
+ {0x00008278, 0x003e4180},
+ {0x0000827c, 0x00000000},
+ {0x00008284, 0x0000002c},
+ {0x00008288, 0x0000002c},
+ {0x0000828c, 0x00000000},
+ {0x00008294, 0x00000000},
+ {0x00008298, 0x00000000},
+ {0x00008300, 0x00000000},
+ {0x00008304, 0x00000000},
+ {0x00008308, 0x00000000},
+ {0x0000830c, 0x00000000},
+ {0x00008310, 0x00000000},
+ {0x00008314, 0x00000000},
+ {0x00008318, 0x00000000},
+ {0x00008328, 0x00000000},
+ {0x0000832c, 0x00000007},
+ {0x00008330, 0x00000302},
+ {0x00008334, 0x00000e00},
+ {0x00008338, 0x00070000},
+ {0x0000833c, 0x00000000},
+ {0x00008340, 0x000107ff},
+ {0x00009808, 0x00000000},
+ {0x0000980c, 0xad848e19},
+ {0x00009810, 0x7d14e000},
+ {0x00009814, 0x9c0a9f6b},
+ {0x0000981c, 0x00000000},
+ {0x0000982c, 0x0000a000},
+ {0x00009830, 0x00000000},
+ {0x0000983c, 0x00200400},
+ {0x00009840, 0x206a002e},
+ {0x0000984c, 0x1284233c},
+ {0x00009854, 0x00000859},
+ {0x00009900, 0x00000000},
+ {0x00009904, 0x00000000},
+ {0x00009908, 0x00000000},
+ {0x0000990c, 0x00000000},
+ {0x0000991c, 0x10000fff},
+ {0x00009920, 0x05100000},
+ {0x0000a920, 0x05100000},
+ {0x0000b920, 0x05100000},
+ {0x00009928, 0x00000001},
+ {0x0000992c, 0x00000004},
+ {0x00009934, 0x1e1f2022},
+ {0x00009938, 0x0a0b0c0d},
+ {0x0000993c, 0x00000000},
+ {0x00009948, 0x9280b212},
+ {0x0000994c, 0x00020028},
+ {0x00009954, 0x5d50e188},
+ {0x00009958, 0x00081fff},
+ {0x0000c95c, 0x004b6a8e},
+ {0x0000c968, 0x000003ce},
+ {0x00009970, 0x190fb515},
+ {0x00009974, 0x00000000},
+ {0x00009978, 0x00000001},
+ {0x0000997c, 0x00000000},
+ {0x00009980, 0x00000000},
+ {0x00009984, 0x00000000},
+ {0x00009988, 0x00000000},
+ {0x0000998c, 0x00000000},
+ {0x00009990, 0x00000000},
+ {0x00009994, 0x00000000},
+ {0x00009998, 0x00000000},
+ {0x0000999c, 0x00000000},
+ {0x000099a0, 0x00000000},
+ {0x000099a4, 0x00000001},
+ {0x000099a8, 0x001fff00},
+ {0x000099ac, 0x00000000},
+ {0x000099b0, 0x03051000},
+ {0x000099dc, 0x00000000},
+ {0x000099e0, 0x00000200},
+ {0x000099e4, 0xaaaaaaaa},
+ {0x000099e8, 0x3c466478},
+ {0x000099ec, 0x000000aa},
+ {0x000099fc, 0x00001042},
+ {0x00009b00, 0x00000000},
+ {0x00009b04, 0x00000001},
+ {0x00009b08, 0x00000002},
+ {0x00009b0c, 0x00000003},
+ {0x00009b10, 0x00000004},
+ {0x00009b14, 0x00000005},
+ {0x00009b18, 0x00000008},
+ {0x00009b1c, 0x00000009},
+ {0x00009b20, 0x0000000a},
+ {0x00009b24, 0x0000000b},
+ {0x00009b28, 0x0000000c},
+ {0x00009b2c, 0x0000000d},
+ {0x00009b30, 0x00000010},
+ {0x00009b34, 0x00000011},
+ {0x00009b38, 0x00000012},
+ {0x00009b3c, 0x00000013},
+ {0x00009b40, 0x00000014},
+ {0x00009b44, 0x00000015},
+ {0x00009b48, 0x00000018},
+ {0x00009b4c, 0x00000019},
+ {0x00009b50, 0x0000001a},
+ {0x00009b54, 0x0000001b},
+ {0x00009b58, 0x0000001c},
+ {0x00009b5c, 0x0000001d},
+ {0x00009b60, 0x00000020},
+ {0x00009b64, 0x00000021},
+ {0x00009b68, 0x00000022},
+ {0x00009b6c, 0x00000023},
+ {0x00009b70, 0x00000024},
+ {0x00009b74, 0x00000025},
+ {0x00009b78, 0x00000028},
+ {0x00009b7c, 0x00000029},
+ {0x00009b80, 0x0000002a},
+ {0x00009b84, 0x0000002b},
+ {0x00009b88, 0x0000002c},
+ {0x00009b8c, 0x0000002d},
+ {0x00009b90, 0x00000030},
+ {0x00009b94, 0x00000031},
+ {0x00009b98, 0x00000032},
+ {0x00009b9c, 0x00000033},
+ {0x00009ba0, 0x00000034},
+ {0x00009ba4, 0x00000035},
+ {0x00009ba8, 0x00000035},
+ {0x00009bac, 0x00000035},
+ {0x00009bb0, 0x00000035},
+ {0x00009bb4, 0x00000035},
+ {0x00009bb8, 0x00000035},
+ {0x00009bbc, 0x00000035},
+ {0x00009bc0, 0x00000035},
+ {0x00009bc4, 0x00000035},
+ {0x00009bc8, 0x00000035},
+ {0x00009bcc, 0x00000035},
+ {0x00009bd0, 0x00000035},
+ {0x00009bd4, 0x00000035},
+ {0x00009bd8, 0x00000035},
+ {0x00009bdc, 0x00000035},
+ {0x00009be0, 0x00000035},
+ {0x00009be4, 0x00000035},
+ {0x00009be8, 0x00000035},
+ {0x00009bec, 0x00000035},
+ {0x00009bf0, 0x00000035},
+ {0x00009bf4, 0x00000035},
+ {0x00009bf8, 0x00000010},
+ {0x00009bfc, 0x0000001a},
+ {0x0000a210, 0x40806333},
+ {0x0000a214, 0x00106c10},
+ {0x0000a218, 0x009c4060},
+ {0x0000a220, 0x018830c6},
+ {0x0000a224, 0x00000400},
+ {0x0000a228, 0x00000bb5},
+ {0x0000a22c, 0x00000011},
+ {0x0000a234, 0x20202020},
+ {0x0000a238, 0x20202020},
+ {0x0000a23c, 0x13c889af},
+ {0x0000a240, 0x38490a20},
+ {0x0000a244, 0x00007bb6},
+ {0x0000a248, 0x0fff3ffc},
+ {0x0000a24c, 0x00000001},
+ {0x0000a250, 0x0000a000},
+ {0x0000a254, 0x00000000},
+ {0x0000a258, 0x0cc75380},
+ {0x0000a25c, 0x0f0f0f01},
+ {0x0000a260, 0xdfa91f01},
+ {0x0000a268, 0x00000000},
+ {0x0000a26c, 0x0e79e5c6},
+ {0x0000b26c, 0x0e79e5c6},
+ {0x0000c26c, 0x0e79e5c6},
+ {0x0000d270, 0x00820820},
+ {0x0000a278, 0x1ce739ce},
+ {0x0000a27c, 0x051701ce},
+ {0x0000a338, 0x00000000},
+ {0x0000a33c, 0x00000000},
+ {0x0000a340, 0x00000000},
+ {0x0000a344, 0x00000000},
+ {0x0000a348, 0x3fffffff},
+ {0x0000a34c, 0x3fffffff},
+ {0x0000a350, 0x3fffffff},
+ {0x0000a354, 0x0003ffff},
+ {0x0000a358, 0x79a8aa1f},
+ {0x0000d35c, 0x07ffffef},
+ {0x0000d360, 0x0fffffe7},
+ {0x0000d364, 0x17ffffe5},
+ {0x0000d368, 0x1fffffe4},
+ {0x0000d36c, 0x37ffffe3},
+ {0x0000d370, 0x3fffffe3},
+ {0x0000d374, 0x57ffffe3},
+ {0x0000d378, 0x5fffffe2},
+ {0x0000d37c, 0x7fffffe2},
+ {0x0000d380, 0x7f3c7bba},
+ {0x0000d384, 0xf3307ff0},
+ {0x0000a388, 0x08000000},
+ {0x0000a38c, 0x20202020},
+ {0x0000a390, 0x20202020},
+ {0x0000a394, 0x1ce739ce},
+ {0x0000a398, 0x000001ce},
+ {0x0000a39c, 0x00000001},
+ {0x0000a3a0, 0x00000000},
+ {0x0000a3a4, 0x00000000},
+ {0x0000a3a8, 0x00000000},
+ {0x0000a3ac, 0x00000000},
+ {0x0000a3b0, 0x00000000},
+ {0x0000a3b4, 0x00000000},
+ {0x0000a3b8, 0x00000000},
+ {0x0000a3bc, 0x00000000},
+ {0x0000a3c0, 0x00000000},
+ {0x0000a3c4, 0x00000000},
+ {0x0000a3c8, 0x00000246},
+ {0x0000a3cc, 0x20202020},
+ {0x0000a3d0, 0x20202020},
+ {0x0000a3d4, 0x20202020},
+ {0x0000a3dc, 0x1ce739ce},
+ {0x0000a3e0, 0x000001ce},
};
static const u32 ar5416Bank0[][2] = {
- { 0x000098b0, 0x1e5795e5 },
- { 0x000098e0, 0x02008020 },
+ /* Addr allmodes */
+ {0x000098b0, 0x1e5795e5},
+ {0x000098e0, 0x02008020},
};
static const u32 ar5416BB_RfGain[][3] = {
- { 0x00009a00, 0x00000000, 0x00000000 },
- { 0x00009a04, 0x00000040, 0x00000040 },
- { 0x00009a08, 0x00000080, 0x00000080 },
- { 0x00009a0c, 0x000001a1, 0x00000141 },
- { 0x00009a10, 0x000001e1, 0x00000181 },
- { 0x00009a14, 0x00000021, 0x000001c1 },
- { 0x00009a18, 0x00000061, 0x00000001 },
- { 0x00009a1c, 0x00000168, 0x00000041 },
- { 0x00009a20, 0x000001a8, 0x000001a8 },
- { 0x00009a24, 0x000001e8, 0x000001e8 },
- { 0x00009a28, 0x00000028, 0x00000028 },
- { 0x00009a2c, 0x00000068, 0x00000068 },
- { 0x00009a30, 0x00000189, 0x000000a8 },
- { 0x00009a34, 0x000001c9, 0x00000169 },
- { 0x00009a38, 0x00000009, 0x000001a9 },
- { 0x00009a3c, 0x00000049, 0x000001e9 },
- { 0x00009a40, 0x00000089, 0x00000029 },
- { 0x00009a44, 0x00000170, 0x00000069 },
- { 0x00009a48, 0x000001b0, 0x00000190 },
- { 0x00009a4c, 0x000001f0, 0x000001d0 },
- { 0x00009a50, 0x00000030, 0x00000010 },
- { 0x00009a54, 0x00000070, 0x00000050 },
- { 0x00009a58, 0x00000191, 0x00000090 },
- { 0x00009a5c, 0x000001d1, 0x00000151 },
- { 0x00009a60, 0x00000011, 0x00000191 },
- { 0x00009a64, 0x00000051, 0x000001d1 },
- { 0x00009a68, 0x00000091, 0x00000011 },
- { 0x00009a6c, 0x000001b8, 0x00000051 },
- { 0x00009a70, 0x000001f8, 0x00000198 },
- { 0x00009a74, 0x00000038, 0x000001d8 },
- { 0x00009a78, 0x00000078, 0x00000018 },
- { 0x00009a7c, 0x00000199, 0x00000058 },
- { 0x00009a80, 0x000001d9, 0x00000098 },
- { 0x00009a84, 0x00000019, 0x00000159 },
- { 0x00009a88, 0x00000059, 0x00000199 },
- { 0x00009a8c, 0x00000099, 0x000001d9 },
- { 0x00009a90, 0x000000d9, 0x00000019 },
- { 0x00009a94, 0x000000f9, 0x00000059 },
- { 0x00009a98, 0x000000f9, 0x00000099 },
- { 0x00009a9c, 0x000000f9, 0x000000d9 },
- { 0x00009aa0, 0x000000f9, 0x000000f9 },
- { 0x00009aa4, 0x000000f9, 0x000000f9 },
- { 0x00009aa8, 0x000000f9, 0x000000f9 },
- { 0x00009aac, 0x000000f9, 0x000000f9 },
- { 0x00009ab0, 0x000000f9, 0x000000f9 },
- { 0x00009ab4, 0x000000f9, 0x000000f9 },
- { 0x00009ab8, 0x000000f9, 0x000000f9 },
- { 0x00009abc, 0x000000f9, 0x000000f9 },
- { 0x00009ac0, 0x000000f9, 0x000000f9 },
- { 0x00009ac4, 0x000000f9, 0x000000f9 },
- { 0x00009ac8, 0x000000f9, 0x000000f9 },
- { 0x00009acc, 0x000000f9, 0x000000f9 },
- { 0x00009ad0, 0x000000f9, 0x000000f9 },
- { 0x00009ad4, 0x000000f9, 0x000000f9 },
- { 0x00009ad8, 0x000000f9, 0x000000f9 },
- { 0x00009adc, 0x000000f9, 0x000000f9 },
- { 0x00009ae0, 0x000000f9, 0x000000f9 },
- { 0x00009ae4, 0x000000f9, 0x000000f9 },
- { 0x00009ae8, 0x000000f9, 0x000000f9 },
- { 0x00009aec, 0x000000f9, 0x000000f9 },
- { 0x00009af0, 0x000000f9, 0x000000f9 },
- { 0x00009af4, 0x000000f9, 0x000000f9 },
- { 0x00009af8, 0x000000f9, 0x000000f9 },
- { 0x00009afc, 0x000000f9, 0x000000f9 },
+ /* Addr 5G_HT20 5G_HT40 */
+ {0x00009a00, 0x00000000, 0x00000000},
+ {0x00009a04, 0x00000040, 0x00000040},
+ {0x00009a08, 0x00000080, 0x00000080},
+ {0x00009a0c, 0x000001a1, 0x00000141},
+ {0x00009a10, 0x000001e1, 0x00000181},
+ {0x00009a14, 0x00000021, 0x000001c1},
+ {0x00009a18, 0x00000061, 0x00000001},
+ {0x00009a1c, 0x00000168, 0x00000041},
+ {0x00009a20, 0x000001a8, 0x000001a8},
+ {0x00009a24, 0x000001e8, 0x000001e8},
+ {0x00009a28, 0x00000028, 0x00000028},
+ {0x00009a2c, 0x00000068, 0x00000068},
+ {0x00009a30, 0x00000189, 0x000000a8},
+ {0x00009a34, 0x000001c9, 0x00000169},
+ {0x00009a38, 0x00000009, 0x000001a9},
+ {0x00009a3c, 0x00000049, 0x000001e9},
+ {0x00009a40, 0x00000089, 0x00000029},
+ {0x00009a44, 0x00000170, 0x00000069},
+ {0x00009a48, 0x000001b0, 0x00000190},
+ {0x00009a4c, 0x000001f0, 0x000001d0},
+ {0x00009a50, 0x00000030, 0x00000010},
+ {0x00009a54, 0x00000070, 0x00000050},
+ {0x00009a58, 0x00000191, 0x00000090},
+ {0x00009a5c, 0x000001d1, 0x00000151},
+ {0x00009a60, 0x00000011, 0x00000191},
+ {0x00009a64, 0x00000051, 0x000001d1},
+ {0x00009a68, 0x00000091, 0x00000011},
+ {0x00009a6c, 0x000001b8, 0x00000051},
+ {0x00009a70, 0x000001f8, 0x00000198},
+ {0x00009a74, 0x00000038, 0x000001d8},
+ {0x00009a78, 0x00000078, 0x00000018},
+ {0x00009a7c, 0x00000199, 0x00000058},
+ {0x00009a80, 0x000001d9, 0x00000098},
+ {0x00009a84, 0x00000019, 0x00000159},
+ {0x00009a88, 0x00000059, 0x00000199},
+ {0x00009a8c, 0x00000099, 0x000001d9},
+ {0x00009a90, 0x000000d9, 0x00000019},
+ {0x00009a94, 0x000000f9, 0x00000059},
+ {0x00009a98, 0x000000f9, 0x00000099},
+ {0x00009a9c, 0x000000f9, 0x000000d9},
+ {0x00009aa0, 0x000000f9, 0x000000f9},
+ {0x00009aa4, 0x000000f9, 0x000000f9},
+ {0x00009aa8, 0x000000f9, 0x000000f9},
+ {0x00009aac, 0x000000f9, 0x000000f9},
+ {0x00009ab0, 0x000000f9, 0x000000f9},
+ {0x00009ab4, 0x000000f9, 0x000000f9},
+ {0x00009ab8, 0x000000f9, 0x000000f9},
+ {0x00009abc, 0x000000f9, 0x000000f9},
+ {0x00009ac0, 0x000000f9, 0x000000f9},
+ {0x00009ac4, 0x000000f9, 0x000000f9},
+ {0x00009ac8, 0x000000f9, 0x000000f9},
+ {0x00009acc, 0x000000f9, 0x000000f9},
+ {0x00009ad0, 0x000000f9, 0x000000f9},
+ {0x00009ad4, 0x000000f9, 0x000000f9},
+ {0x00009ad8, 0x000000f9, 0x000000f9},
+ {0x00009adc, 0x000000f9, 0x000000f9},
+ {0x00009ae0, 0x000000f9, 0x000000f9},
+ {0x00009ae4, 0x000000f9, 0x000000f9},
+ {0x00009ae8, 0x000000f9, 0x000000f9},
+ {0x00009aec, 0x000000f9, 0x000000f9},
+ {0x00009af0, 0x000000f9, 0x000000f9},
+ {0x00009af4, 0x000000f9, 0x000000f9},
+ {0x00009af8, 0x000000f9, 0x000000f9},
+ {0x00009afc, 0x000000f9, 0x000000f9},
};
static const u32 ar5416Bank1[][2] = {
- { 0x000098b0, 0x02108421 },
- { 0x000098ec, 0x00000008 },
+ /* Addr allmodes */
+ {0x000098b0, 0x02108421},
+ {0x000098ec, 0x00000008},
};
static const u32 ar5416Bank2[][2] = {
- { 0x000098b0, 0x0e73ff17 },
- { 0x000098e0, 0x00000420 },
+ /* Addr allmodes */
+ {0x000098b0, 0x0e73ff17},
+ {0x000098e0, 0x00000420},
};
static const u32 ar5416Bank3[][3] = {
- { 0x000098f0, 0x01400018, 0x01c00018 },
+ /* Addr 5G_HT20 5G_HT40 */
+ {0x000098f0, 0x01400018, 0x01c00018},
};
static const u32 ar5416Bank6[][3] = {
-
- { 0x0000989c, 0x00000000, 0x00000000 },
- { 0x0000989c, 0x00000000, 0x00000000 },
- { 0x0000989c, 0x00000000, 0x00000000 },
- { 0x0000989c, 0x00e00000, 0x00e00000 },
- { 0x0000989c, 0x005e0000, 0x005e0000 },
- { 0x0000989c, 0x00120000, 0x00120000 },
- { 0x0000989c, 0x00620000, 0x00620000 },
- { 0x0000989c, 0x00020000, 0x00020000 },
- { 0x0000989c, 0x00ff0000, 0x00ff0000 },
- { 0x0000989c, 0x00ff0000, 0x00ff0000 },
- { 0x0000989c, 0x00ff0000, 0x00ff0000 },
- { 0x0000989c, 0x40ff0000, 0x40ff0000 },
- { 0x0000989c, 0x005f0000, 0x005f0000 },
- { 0x0000989c, 0x00870000, 0x00870000 },
- { 0x0000989c, 0x00f90000, 0x00f90000 },
- { 0x0000989c, 0x007b0000, 0x007b0000 },
- { 0x0000989c, 0x00ff0000, 0x00ff0000 },
- { 0x0000989c, 0x00f50000, 0x00f50000 },
- { 0x0000989c, 0x00dc0000, 0x00dc0000 },
- { 0x0000989c, 0x00110000, 0x00110000 },
- { 0x0000989c, 0x006100a8, 0x006100a8 },
- { 0x0000989c, 0x004210a2, 0x004210a2 },
- { 0x0000989c, 0x0014008f, 0x0014008f },
- { 0x0000989c, 0x00c40003, 0x00c40003 },
- { 0x0000989c, 0x003000f2, 0x003000f2 },
- { 0x0000989c, 0x00440016, 0x00440016 },
- { 0x0000989c, 0x00410040, 0x00410040 },
- { 0x0000989c, 0x0001805e, 0x0001805e },
- { 0x0000989c, 0x0000c0ab, 0x0000c0ab },
- { 0x0000989c, 0x000000f1, 0x000000f1 },
- { 0x0000989c, 0x00002081, 0x00002081 },
- { 0x0000989c, 0x000000d4, 0x000000d4 },
- { 0x000098d0, 0x0000000f, 0x0010000f },
+ /* Addr 5G_HT20 5G_HT40 */
+ {0x0000989c, 0x00000000, 0x00000000},
+ {0x0000989c, 0x00000000, 0x00000000},
+ {0x0000989c, 0x00000000, 0x00000000},
+ {0x0000989c, 0x00e00000, 0x00e00000},
+ {0x0000989c, 0x005e0000, 0x005e0000},
+ {0x0000989c, 0x00120000, 0x00120000},
+ {0x0000989c, 0x00620000, 0x00620000},
+ {0x0000989c, 0x00020000, 0x00020000},
+ {0x0000989c, 0x00ff0000, 0x00ff0000},
+ {0x0000989c, 0x00ff0000, 0x00ff0000},
+ {0x0000989c, 0x00ff0000, 0x00ff0000},
+ {0x0000989c, 0x40ff0000, 0x40ff0000},
+ {0x0000989c, 0x005f0000, 0x005f0000},
+ {0x0000989c, 0x00870000, 0x00870000},
+ {0x0000989c, 0x00f90000, 0x00f90000},
+ {0x0000989c, 0x007b0000, 0x007b0000},
+ {0x0000989c, 0x00ff0000, 0x00ff0000},
+ {0x0000989c, 0x00f50000, 0x00f50000},
+ {0x0000989c, 0x00dc0000, 0x00dc0000},
+ {0x0000989c, 0x00110000, 0x00110000},
+ {0x0000989c, 0x006100a8, 0x006100a8},
+ {0x0000989c, 0x004210a2, 0x004210a2},
+ {0x0000989c, 0x0014008f, 0x0014008f},
+ {0x0000989c, 0x00c40003, 0x00c40003},
+ {0x0000989c, 0x003000f2, 0x003000f2},
+ {0x0000989c, 0x00440016, 0x00440016},
+ {0x0000989c, 0x00410040, 0x00410040},
+ {0x0000989c, 0x0001805e, 0x0001805e},
+ {0x0000989c, 0x0000c0ab, 0x0000c0ab},
+ {0x0000989c, 0x000000f1, 0x000000f1},
+ {0x0000989c, 0x00002081, 0x00002081},
+ {0x0000989c, 0x000000d4, 0x000000d4},
+ {0x000098d0, 0x0000000f, 0x0010000f},
};
static const u32 ar5416Bank6TPC[][3] = {
- { 0x0000989c, 0x00000000, 0x00000000 },
- { 0x0000989c, 0x00000000, 0x00000000 },
- { 0x0000989c, 0x00000000, 0x00000000 },
- { 0x0000989c, 0x00e00000, 0x00e00000 },
- { 0x0000989c, 0x005e0000, 0x005e0000 },
- { 0x0000989c, 0x00120000, 0x00120000 },
- { 0x0000989c, 0x00620000, 0x00620000 },
- { 0x0000989c, 0x00020000, 0x00020000 },
- { 0x0000989c, 0x00ff0000, 0x00ff0000 },
- { 0x0000989c, 0x00ff0000, 0x00ff0000 },
- { 0x0000989c, 0x00ff0000, 0x00ff0000 },
- { 0x0000989c, 0x40ff0000, 0x40ff0000 },
- { 0x0000989c, 0x005f0000, 0x005f0000 },
- { 0x0000989c, 0x00870000, 0x00870000 },
- { 0x0000989c, 0x00f90000, 0x00f90000 },
- { 0x0000989c, 0x007b0000, 0x007b0000 },
- { 0x0000989c, 0x00ff0000, 0x00ff0000 },
- { 0x0000989c, 0x00f50000, 0x00f50000 },
- { 0x0000989c, 0x00dc0000, 0x00dc0000 },
- { 0x0000989c, 0x00110000, 0x00110000 },
- { 0x0000989c, 0x006100a8, 0x006100a8 },
- { 0x0000989c, 0x00423022, 0x00423022 },
- { 0x0000989c, 0x201400df, 0x201400df },
- { 0x0000989c, 0x00c40002, 0x00c40002 },
- { 0x0000989c, 0x003000f2, 0x003000f2 },
- { 0x0000989c, 0x00440016, 0x00440016 },
- { 0x0000989c, 0x00410040, 0x00410040 },
- { 0x0000989c, 0x0001805e, 0x0001805e },
- { 0x0000989c, 0x0000c0ab, 0x0000c0ab },
- { 0x0000989c, 0x000000e1, 0x000000e1 },
- { 0x0000989c, 0x00007081, 0x00007081 },
- { 0x0000989c, 0x000000d4, 0x000000d4 },
- { 0x000098d0, 0x0000000f, 0x0010000f },
+ /* Addr 5G_HT20 5G_HT40 */
+ {0x0000989c, 0x00000000, 0x00000000},
+ {0x0000989c, 0x00000000, 0x00000000},
+ {0x0000989c, 0x00000000, 0x00000000},
+ {0x0000989c, 0x00e00000, 0x00e00000},
+ {0x0000989c, 0x005e0000, 0x005e0000},
+ {0x0000989c, 0x00120000, 0x00120000},
+ {0x0000989c, 0x00620000, 0x00620000},
+ {0x0000989c, 0x00020000, 0x00020000},
+ {0x0000989c, 0x00ff0000, 0x00ff0000},
+ {0x0000989c, 0x00ff0000, 0x00ff0000},
+ {0x0000989c, 0x00ff0000, 0x00ff0000},
+ {0x0000989c, 0x40ff0000, 0x40ff0000},
+ {0x0000989c, 0x005f0000, 0x005f0000},
+ {0x0000989c, 0x00870000, 0x00870000},
+ {0x0000989c, 0x00f90000, 0x00f90000},
+ {0x0000989c, 0x007b0000, 0x007b0000},
+ {0x0000989c, 0x00ff0000, 0x00ff0000},
+ {0x0000989c, 0x00f50000, 0x00f50000},
+ {0x0000989c, 0x00dc0000, 0x00dc0000},
+ {0x0000989c, 0x00110000, 0x00110000},
+ {0x0000989c, 0x006100a8, 0x006100a8},
+ {0x0000989c, 0x00423022, 0x00423022},
+ {0x0000989c, 0x201400df, 0x201400df},
+ {0x0000989c, 0x00c40002, 0x00c40002},
+ {0x0000989c, 0x003000f2, 0x003000f2},
+ {0x0000989c, 0x00440016, 0x00440016},
+ {0x0000989c, 0x00410040, 0x00410040},
+ {0x0000989c, 0x0001805e, 0x0001805e},
+ {0x0000989c, 0x0000c0ab, 0x0000c0ab},
+ {0x0000989c, 0x000000e1, 0x000000e1},
+ {0x0000989c, 0x00007081, 0x00007081},
+ {0x0000989c, 0x000000d4, 0x000000d4},
+ {0x000098d0, 0x0000000f, 0x0010000f},
};
static const u32 ar5416Bank7[][2] = {
- { 0x0000989c, 0x00000500 },
- { 0x0000989c, 0x00000800 },
- { 0x000098cc, 0x0000000e },
+ /* Addr allmodes */
+ {0x0000989c, 0x00000500},
+ {0x0000989c, 0x00000800},
+ {0x000098cc, 0x0000000e},
};
static const u32 ar5416Addac[][2] = {
- {0x0000989c, 0x00000000 },
- {0x0000989c, 0x00000003 },
- {0x0000989c, 0x00000000 },
- {0x0000989c, 0x0000000c },
- {0x0000989c, 0x00000000 },
- {0x0000989c, 0x00000030 },
- {0x0000989c, 0x00000000 },
- {0x0000989c, 0x00000000 },
- {0x0000989c, 0x00000000 },
- {0x0000989c, 0x00000000 },
- {0x0000989c, 0x00000000 },
- {0x0000989c, 0x00000000 },
- {0x0000989c, 0x00000000 },
- {0x0000989c, 0x00000000 },
- {0x0000989c, 0x00000000 },
- {0x0000989c, 0x00000000 },
- {0x0000989c, 0x00000000 },
- {0x0000989c, 0x00000000 },
- {0x0000989c, 0x00000060 },
- {0x0000989c, 0x00000000 },
- {0x0000989c, 0x00000000 },
- {0x0000989c, 0x00000000 },
- {0x0000989c, 0x00000000 },
- {0x0000989c, 0x00000000 },
- {0x0000989c, 0x00000000 },
- {0x0000989c, 0x00000000 },
- {0x0000989c, 0x00000000 },
- {0x0000989c, 0x00000000 },
- {0x0000989c, 0x00000000 },
- {0x0000989c, 0x00000000 },
- {0x0000989c, 0x00000000 },
- {0x0000989c, 0x00000058 },
- {0x0000989c, 0x00000000 },
- {0x0000989c, 0x00000000 },
- {0x0000989c, 0x00000000 },
- {0x0000989c, 0x00000000 },
- {0x000098cc, 0x00000000 },
-};
-
-static const u32 ar5416Modes_9100[][6] = {
- { 0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160, 0x000001e0 },
- { 0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c, 0x000001e0 },
- { 0x000010b0, 0x00000e60, 0x00001cc0, 0x00007c70, 0x00003e38, 0x00001180 },
- { 0x000010f0, 0x0000a000, 0x00014000, 0x00016000, 0x0000b000, 0x00014008 },
- { 0x00008014, 0x03e803e8, 0x07d007d0, 0x10801600, 0x08400b00, 0x06e006e0 },
- { 0x0000801c, 0x128d93a7, 0x128d93cf, 0x12e013d7, 0x12e013ab, 0x098813cf },
- { 0x00009804, 0x00000300, 0x000003c4, 0x000003c4, 0x00000300, 0x00000303 },
- { 0x00009820, 0x02020200, 0x02020200, 0x02020200, 0x02020200, 0x02020200 },
- { 0x00009824, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e },
- { 0x00009828, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001 },
- { 0x00009834, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e },
- { 0x00009838, 0x00000007, 0x00000007, 0x00000007, 0x00000007, 0x00000007 },
- { 0x00009844, 0x0372161e, 0x0372161e, 0x037216a0, 0x037216a0, 0x037216a0 },
- { 0x00009848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68 },
- { 0x0000a848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68 },
- { 0x0000b848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68 },
- { 0x00009850, 0x6d48b4e2, 0x6d48b4e2, 0x6d48b0e2, 0x6d48b0e2, 0x6d48b0e2 },
- { 0x00009858, 0x7ec82d2e, 0x7ec82d2e, 0x7ec86d2e, 0x7ec84d2e, 0x7ec82d2e },
- { 0x0000985c, 0x3139605e, 0x3139605e, 0x3139605e, 0x3139605e, 0x3139605e },
- { 0x00009860, 0x00048d18, 0x00048d18, 0x00048d20, 0x00048d20, 0x00048d18 },
- { 0x0000c864, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00 },
- { 0x00009868, 0x409a40d0, 0x409a40d0, 0x409a40d0, 0x409a40d0, 0x409a40d0 },
- { 0x0000986c, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081 },
- { 0x00009914, 0x000007d0, 0x000007d0, 0x00000898, 0x00000898, 0x000007d0 },
- { 0x00009918, 0x0000000a, 0x00000014, 0x00000016, 0x0000000b, 0x00000016 },
- { 0x00009924, 0xd00a8a07, 0xd00a8a07, 0xd00a8a11, 0xd00a8a0d, 0xd00a8a0d },
- { 0x00009940, 0x00754604, 0x00754604, 0xfff81204, 0xfff81204, 0xfff81204 },
- { 0x00009944, 0xdfb81020, 0xdfb81020, 0xdfb81020, 0xdfb81020, 0xdfb81020 },
- { 0x00009954, 0x5f3ca3de, 0x5f3ca3de, 0xe250a51e, 0xe250a51e, 0xe250a51e },
- { 0x00009958, 0x2108ecff, 0x2108ecff, 0x3388ffff, 0x3388ffff, 0x3388ffff },
-#ifdef TB243
- { 0x00009960, 0x00000900, 0x00000900, 0x00009b40, 0x00009b40, 0x00012d80 },
- { 0x0000a960, 0x00000900, 0x00000900, 0x00009b40, 0x00009b40, 0x00012d80 },
- { 0x0000b960, 0x00000900, 0x00000900, 0x00009b40, 0x00009b40, 0x00012d80 },
- { 0x00009964, 0x00000000, 0x00000000, 0x00002210, 0x00002210, 0x00001120 },
-#else
- { 0x00009960, 0x0001bfc0, 0x0001bfc0, 0x0001bfc0, 0x0001bfc0, 0x0001bfc0 },
- { 0x0000a960, 0x0001bfc0, 0x0001bfc0, 0x0001bfc0, 0x0001bfc0, 0x0001bfc0 },
- { 0x0000b960, 0x0001bfc0, 0x0001bfc0, 0x0001bfc0, 0x0001bfc0, 0x0001bfc0 },
- { 0x00009964, 0x00001120, 0x00001120, 0x00001120, 0x00001120, 0x00001120 },
-#endif
- { 0x0000c9bc, 0x001a0600, 0x001a0600, 0x001a1000, 0x001a0c00, 0x001a0c00 },
- { 0x000099c0, 0x038919be, 0x038919be, 0x038919be, 0x038919be, 0x038919be },
- { 0x000099c4, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77 },
- { 0x000099c8, 0x60f65329, 0x60f65329, 0x60f65329, 0x60f65329, 0x60f65329 },
- { 0x000099cc, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8 },
- { 0x000099d0, 0x00046384, 0x00046384, 0x00046384, 0x00046384, 0x00046384 },
- { 0x000099d4, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
- { 0x000099d8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
- { 0x0000a204, 0x00000880, 0x00000880, 0x00000880, 0x00000880, 0x00000880 },
- { 0x0000a208, 0xd6be4788, 0xd6be4788, 0xd03e4788, 0xd03e4788, 0xd03e4788 },
- { 0x0000a20c, 0x002fc160, 0x002fc160, 0x002ac120, 0x002ac120, 0x002ac120 },
- { 0x0000b20c, 0x002fc160, 0x002fc160, 0x002ac120, 0x002ac120, 0x002ac120 },
- { 0x0000c20c, 0x002fc160, 0x002fc160, 0x002ac120, 0x002ac120, 0x002ac120 },
- { 0x0000a21c, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a },
- { 0x0000a230, 0x00000000, 0x00000000, 0x00000210, 0x00000108, 0x00000000 },
- { 0x0000a274, 0x0a1a9caa, 0x0a1a9caa, 0x0a1a7caa, 0x0a1a7caa, 0x0a1a7caa },
- { 0x0000a300, 0x18010000, 0x18010000, 0x18010000, 0x18010000, 0x18010000 },
- { 0x0000a304, 0x30032602, 0x30032602, 0x2e032402, 0x2e032402, 0x2e032402 },
- { 0x0000a308, 0x48073e06, 0x48073e06, 0x4a0a3c06, 0x4a0a3c06, 0x4a0a3c06 },
- { 0x0000a30c, 0x560b4c0a, 0x560b4c0a, 0x621a540b, 0x621a540b, 0x621a540b },
- { 0x0000a310, 0x641a600f, 0x641a600f, 0x764f6c1b, 0x764f6c1b, 0x764f6c1b },
- { 0x0000a314, 0x7a4f6e1b, 0x7a4f6e1b, 0x845b7a5a, 0x845b7a5a, 0x845b7a5a },
- { 0x0000a318, 0x8c5b7e5a, 0x8c5b7e5a, 0x950f8ccf, 0x950f8ccf, 0x950f8ccf },
- { 0x0000a31c, 0x9d0f96cf, 0x9d0f96cf, 0xa5cf9b4f, 0xa5cf9b4f, 0xa5cf9b4f },
- { 0x0000a320, 0xb51fa69f, 0xb51fa69f, 0xbddfaf1f, 0xbddfaf1f, 0xbddfaf1f },
- { 0x0000a324, 0xcb3fbd07, 0xcb3fbcbf, 0xd1ffc93f, 0xd1ffc93f, 0xd1ffc93f },
- { 0x0000a328, 0x0000d7bf, 0x0000d7bf, 0x00000000, 0x00000000, 0x00000000 },
- { 0x0000a32c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
- { 0x0000a330, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
- { 0x0000a334, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
+ /* Addr allmodes */
+ {0x0000989c, 0x00000000},
+ {0x0000989c, 0x00000003},
+ {0x0000989c, 0x00000000},
+ {0x0000989c, 0x0000000c},
+ {0x0000989c, 0x00000000},
+ {0x0000989c, 0x00000030},
+ {0x0000989c, 0x00000000},
+ {0x0000989c, 0x00000000},
+ {0x0000989c, 0x00000000},
+ {0x0000989c, 0x00000000},
+ {0x0000989c, 0x00000000},
+ {0x0000989c, 0x00000000},
+ {0x0000989c, 0x00000000},
+ {0x0000989c, 0x00000000},
+ {0x0000989c, 0x00000000},
+ {0x0000989c, 0x00000000},
+ {0x0000989c, 0x00000000},
+ {0x0000989c, 0x00000000},
+ {0x0000989c, 0x00000060},
+ {0x0000989c, 0x00000000},
+ {0x0000989c, 0x00000000},
+ {0x0000989c, 0x00000000},
+ {0x0000989c, 0x00000000},
+ {0x0000989c, 0x00000000},
+ {0x0000989c, 0x00000000},
+ {0x0000989c, 0x00000000},
+ {0x0000989c, 0x00000000},
+ {0x0000989c, 0x00000000},
+ {0x0000989c, 0x00000000},
+ {0x0000989c, 0x00000000},
+ {0x0000989c, 0x00000000},
+ {0x0000989c, 0x00000058},
+ {0x0000989c, 0x00000000},
+ {0x0000989c, 0x00000000},
+ {0x0000989c, 0x00000000},
+ {0x0000989c, 0x00000000},
+ {0x000098cc, 0x00000000},
};
-#endif /* INITVALS_AR5008_H */
diff --git a/drivers/net/wireless/ath/ath9k/ar5008_phy.c b/drivers/net/wireless/ath/ath9k/ar5008_phy.c
index b2c17c98bb3..3d2c8679bc8 100644
--- a/drivers/net/wireless/ath/ath9k/ar5008_phy.c
+++ b/drivers/net/wireless/ath/ath9k/ar5008_phy.c
@@ -19,7 +19,30 @@
#include "../regd.h"
#include "ar9002_phy.h"
-/* All code below is for non single-chip solutions */
+/* All code below is for AR5008, AR9001, AR9002 */
+
+static const int firstep_table[] =
+/* level: 0 1 2 3 4 5 6 7 8 */
+ { -4, -2, 0, 2, 4, 6, 8, 10, 12 }; /* lvl 0-8, default 2 */
+
+static const int cycpwrThr1_table[] =
+/* level: 0 1 2 3 4 5 6 7 8 */
+ { -6, -4, -2, 0, 2, 4, 6, 8 }; /* lvl 0-7, default 3 */
+
+/*
+ * register values to turn OFDM weak signal detection OFF
+ */
+static const int m1ThreshLow_off = 127;
+static const int m2ThreshLow_off = 127;
+static const int m1Thresh_off = 127;
+static const int m2Thresh_off = 127;
+static const int m2CountThr_off = 31;
+static const int m2CountThrLow_off = 63;
+static const int m1ThreshLowExt_off = 127;
+static const int m2ThreshLowExt_off = 127;
+static const int m1ThreshExt_off = 127;
+static const int m2ThreshExt_off = 127;
+
/**
* ar5008_hw_phy_modify_rx_buffer() - perform analog swizzling of parameters
@@ -742,17 +765,6 @@ static int ar5008_hw_process_ini(struct ath_hw *ah,
return -EINVAL;
}
- if (AR_SREV_9287_12_OR_LATER(ah)) {
- /* Enable ASYNC FIFO */
- REG_SET_BIT(ah, AR_MAC_PCU_ASYNC_FIFO_REG3,
- AR_MAC_PCU_ASYNC_FIFO_REG3_DATAPATH_SEL);
- REG_SET_BIT(ah, AR_PHY_MODE, AR_PHY_MODE_ASYNCFIFO);
- REG_CLR_BIT(ah, AR_MAC_PCU_ASYNC_FIFO_REG3,
- AR_MAC_PCU_ASYNC_FIFO_REG3_SOFT_RESET);
- REG_SET_BIT(ah, AR_MAC_PCU_ASYNC_FIFO_REG3,
- AR_MAC_PCU_ASYNC_FIFO_REG3_SOFT_RESET);
- }
-
/*
* Set correct baseband to analog shift setting to
* access analog chips.
@@ -1037,8 +1049,9 @@ static u32 ar5008_hw_compute_pll_control(struct ath_hw *ah,
return pll;
}
-static bool ar5008_hw_ani_control(struct ath_hw *ah,
- enum ath9k_ani_cmd cmd, int param)
+static bool ar5008_hw_ani_control_old(struct ath_hw *ah,
+ enum ath9k_ani_cmd cmd,
+ int param)
{
struct ar5416AniState *aniState = ah->curani;
struct ath_common *common = ath9k_hw_common(ah);
@@ -1220,129 +1233,377 @@ static bool ar5008_hw_ani_control(struct ath_hw *ah,
return true;
}
+static bool ar5008_hw_ani_control_new(struct ath_hw *ah,
+ enum ath9k_ani_cmd cmd,
+ int param)
+{
+ struct ar5416AniState *aniState = ah->curani;
+ struct ath_common *common = ath9k_hw_common(ah);
+ struct ath9k_channel *chan = ah->curchan;
+ s32 value, value2;
+
+ switch (cmd & ah->ani_function) {
+ case ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION:{
+ /*
+ * on == 1 means ofdm weak signal detection is ON
+ * on == 1 is the default, for less noise immunity
+ *
+ * on == 0 means ofdm weak signal detection is OFF
+ * on == 0 means more noise imm
+ */
+ u32 on = param ? 1 : 0;
+ /*
+ * make register setting for default
+ * (weak sig detect ON) come from INI file
+ */
+ int m1ThreshLow = on ?
+ aniState->iniDef.m1ThreshLow : m1ThreshLow_off;
+ int m2ThreshLow = on ?
+ aniState->iniDef.m2ThreshLow : m2ThreshLow_off;
+ int m1Thresh = on ?
+ aniState->iniDef.m1Thresh : m1Thresh_off;
+ int m2Thresh = on ?
+ aniState->iniDef.m2Thresh : m2Thresh_off;
+ int m2CountThr = on ?
+ aniState->iniDef.m2CountThr : m2CountThr_off;
+ int m2CountThrLow = on ?
+ aniState->iniDef.m2CountThrLow : m2CountThrLow_off;
+ int m1ThreshLowExt = on ?
+ aniState->iniDef.m1ThreshLowExt : m1ThreshLowExt_off;
+ int m2ThreshLowExt = on ?
+ aniState->iniDef.m2ThreshLowExt : m2ThreshLowExt_off;
+ int m1ThreshExt = on ?
+ aniState->iniDef.m1ThreshExt : m1ThreshExt_off;
+ int m2ThreshExt = on ?
+ aniState->iniDef.m2ThreshExt : m2ThreshExt_off;
+
+ REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW,
+ AR_PHY_SFCORR_LOW_M1_THRESH_LOW,
+ m1ThreshLow);
+ REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW,
+ AR_PHY_SFCORR_LOW_M2_THRESH_LOW,
+ m2ThreshLow);
+ REG_RMW_FIELD(ah, AR_PHY_SFCORR,
+ AR_PHY_SFCORR_M1_THRESH, m1Thresh);
+ REG_RMW_FIELD(ah, AR_PHY_SFCORR,
+ AR_PHY_SFCORR_M2_THRESH, m2Thresh);
+ REG_RMW_FIELD(ah, AR_PHY_SFCORR,
+ AR_PHY_SFCORR_M2COUNT_THR, m2CountThr);
+ REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW,
+ AR_PHY_SFCORR_LOW_M2COUNT_THR_LOW,
+ m2CountThrLow);
+
+ REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT,
+ AR_PHY_SFCORR_EXT_M1_THRESH_LOW, m1ThreshLowExt);
+ REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT,
+ AR_PHY_SFCORR_EXT_M2_THRESH_LOW, m2ThreshLowExt);
+ REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT,
+ AR_PHY_SFCORR_EXT_M1_THRESH, m1ThreshExt);
+ REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT,
+ AR_PHY_SFCORR_EXT_M2_THRESH, m2ThreshExt);
+
+ if (on)
+ REG_SET_BIT(ah, AR_PHY_SFCORR_LOW,
+ AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW);
+ else
+ REG_CLR_BIT(ah, AR_PHY_SFCORR_LOW,
+ AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW);
+
+ if (!on != aniState->ofdmWeakSigDetectOff) {
+ ath_print(common, ATH_DBG_ANI,
+ "** ch %d: ofdm weak signal: %s=>%s\n",
+ chan->channel,
+ !aniState->ofdmWeakSigDetectOff ?
+ "on" : "off",
+ on ? "on" : "off");
+ if (on)
+ ah->stats.ast_ani_ofdmon++;
+ else
+ ah->stats.ast_ani_ofdmoff++;
+ aniState->ofdmWeakSigDetectOff = !on;
+ }
+ break;
+ }
+ case ATH9K_ANI_FIRSTEP_LEVEL:{
+ u32 level = param;
+
+ if (level >= ARRAY_SIZE(firstep_table)) {
+ ath_print(common, ATH_DBG_ANI,
+ "ATH9K_ANI_FIRSTEP_LEVEL: level "
+ "out of range (%u > %u)\n",
+ level,
+ (unsigned) ARRAY_SIZE(firstep_table));
+ return false;
+ }
+
+ /*
+ * make register setting relative to default
+ * from INI file & cap value
+ */
+ value = firstep_table[level] -
+ firstep_table[ATH9K_ANI_FIRSTEP_LVL_NEW] +
+ aniState->iniDef.firstep;
+ if (value < ATH9K_SIG_FIRSTEP_SETTING_MIN)
+ value = ATH9K_SIG_FIRSTEP_SETTING_MIN;
+ if (value > ATH9K_SIG_FIRSTEP_SETTING_MAX)
+ value = ATH9K_SIG_FIRSTEP_SETTING_MAX;
+ REG_RMW_FIELD(ah, AR_PHY_FIND_SIG,
+ AR_PHY_FIND_SIG_FIRSTEP,
+ value);
+ /*
+ * we need to set first step low register too
+ * make register setting relative to default
+ * from INI file & cap value
+ */
+ value2 = firstep_table[level] -
+ firstep_table[ATH9K_ANI_FIRSTEP_LVL_NEW] +
+ aniState->iniDef.firstepLow;
+ if (value2 < ATH9K_SIG_FIRSTEP_SETTING_MIN)
+ value2 = ATH9K_SIG_FIRSTEP_SETTING_MIN;
+ if (value2 > ATH9K_SIG_FIRSTEP_SETTING_MAX)
+ value2 = ATH9K_SIG_FIRSTEP_SETTING_MAX;
+
+ REG_RMW_FIELD(ah, AR_PHY_FIND_SIG_LOW,
+ AR_PHY_FIND_SIG_FIRSTEP_LOW, value2);
+
+ if (level != aniState->firstepLevel) {
+ ath_print(common, ATH_DBG_ANI,
+ "** ch %d: level %d=>%d[def:%d] "
+ "firstep[level]=%d ini=%d\n",
+ chan->channel,
+ aniState->firstepLevel,
+ level,
+ ATH9K_ANI_FIRSTEP_LVL_NEW,
+ value,
+ aniState->iniDef.firstep);
+ ath_print(common, ATH_DBG_ANI,
+ "** ch %d: level %d=>%d[def:%d] "
+ "firstep_low[level]=%d ini=%d\n",
+ chan->channel,
+ aniState->firstepLevel,
+ level,
+ ATH9K_ANI_FIRSTEP_LVL_NEW,
+ value2,
+ aniState->iniDef.firstepLow);
+ if (level > aniState->firstepLevel)
+ ah->stats.ast_ani_stepup++;
+ else if (level < aniState->firstepLevel)
+ ah->stats.ast_ani_stepdown++;
+ aniState->firstepLevel = level;
+ }
+ break;
+ }
+ case ATH9K_ANI_SPUR_IMMUNITY_LEVEL:{
+ u32 level = param;
+
+ if (level >= ARRAY_SIZE(cycpwrThr1_table)) {
+ ath_print(common, ATH_DBG_ANI,
+ "ATH9K_ANI_SPUR_IMMUNITY_LEVEL: level "
+ "out of range (%u > %u)\n",
+ level,
+ (unsigned) ARRAY_SIZE(cycpwrThr1_table));
+ return false;
+ }
+ /*
+ * make register setting relative to default
+ * from INI file & cap value
+ */
+ value = cycpwrThr1_table[level] -
+ cycpwrThr1_table[ATH9K_ANI_SPUR_IMMUNE_LVL_NEW] +
+ aniState->iniDef.cycpwrThr1;
+ if (value < ATH9K_SIG_SPUR_IMM_SETTING_MIN)
+ value = ATH9K_SIG_SPUR_IMM_SETTING_MIN;
+ if (value > ATH9K_SIG_SPUR_IMM_SETTING_MAX)
+ value = ATH9K_SIG_SPUR_IMM_SETTING_MAX;
+ REG_RMW_FIELD(ah, AR_PHY_TIMING5,
+ AR_PHY_TIMING5_CYCPWR_THR1,
+ value);
+
+ /*
+ * set AR_PHY_EXT_CCA for extension channel
+ * make register setting relative to default
+ * from INI file & cap value
+ */
+ value2 = cycpwrThr1_table[level] -
+ cycpwrThr1_table[ATH9K_ANI_SPUR_IMMUNE_LVL_NEW] +
+ aniState->iniDef.cycpwrThr1Ext;
+ if (value2 < ATH9K_SIG_SPUR_IMM_SETTING_MIN)
+ value2 = ATH9K_SIG_SPUR_IMM_SETTING_MIN;
+ if (value2 > ATH9K_SIG_SPUR_IMM_SETTING_MAX)
+ value2 = ATH9K_SIG_SPUR_IMM_SETTING_MAX;
+ REG_RMW_FIELD(ah, AR_PHY_EXT_CCA,
+ AR_PHY_EXT_TIMING5_CYCPWR_THR1, value2);
+
+ if (level != aniState->spurImmunityLevel) {
+ ath_print(common, ATH_DBG_ANI,
+ "** ch %d: level %d=>%d[def:%d] "
+ "cycpwrThr1[level]=%d ini=%d\n",
+ chan->channel,
+ aniState->spurImmunityLevel,
+ level,
+ ATH9K_ANI_SPUR_IMMUNE_LVL_NEW,
+ value,
+ aniState->iniDef.cycpwrThr1);
+ ath_print(common, ATH_DBG_ANI,
+ "** ch %d: level %d=>%d[def:%d] "
+ "cycpwrThr1Ext[level]=%d ini=%d\n",
+ chan->channel,
+ aniState->spurImmunityLevel,
+ level,
+ ATH9K_ANI_SPUR_IMMUNE_LVL_NEW,
+ value2,
+ aniState->iniDef.cycpwrThr1Ext);
+ if (level > aniState->spurImmunityLevel)
+ ah->stats.ast_ani_spurup++;
+ else if (level < aniState->spurImmunityLevel)
+ ah->stats.ast_ani_spurdown++;
+ aniState->spurImmunityLevel = level;
+ }
+ break;
+ }
+ case ATH9K_ANI_MRC_CCK:
+ /*
+ * You should not see this as AR5008, AR9001, AR9002
+ * does not have hardware support for MRC CCK.
+ */
+ WARN_ON(1);
+ break;
+ case ATH9K_ANI_PRESENT:
+ break;
+ default:
+ ath_print(common, ATH_DBG_ANI,
+ "invalid cmd %u\n", cmd);
+ return false;
+ }
+
+ ath_print(common, ATH_DBG_ANI,
+ "ANI parameters: SI=%d, ofdmWS=%s FS=%d "
+ "MRCcck=%s listenTime=%d CC=%d listen=%d "
+ "ofdmErrs=%d cckErrs=%d\n",
+ aniState->spurImmunityLevel,
+ !aniState->ofdmWeakSigDetectOff ? "on" : "off",
+ aniState->firstepLevel,
+ !aniState->mrcCCKOff ? "on" : "off",
+ aniState->listenTime,
+ aniState->cycleCount,
+ aniState->listenTime,
+ aniState->ofdmPhyErrCount,
+ aniState->cckPhyErrCount);
+ return true;
+}
+
static void ar5008_hw_do_getnf(struct ath_hw *ah,
int16_t nfarray[NUM_NF_READINGS])
{
- struct ath_common *common = ath9k_hw_common(ah);
int16_t nf;
nf = MS(REG_READ(ah, AR_PHY_CCA), AR_PHY_MINCCA_PWR);
- if (nf & 0x100)
- nf = 0 - ((nf ^ 0x1ff) + 1);
- ath_print(common, ATH_DBG_CALIBRATE,
- "NF calibrated [ctl] [chain 0] is %d\n", nf);
- nfarray[0] = nf;
+ nfarray[0] = sign_extend(nf, 9);
nf = MS(REG_READ(ah, AR_PHY_CH1_CCA), AR_PHY_CH1_MINCCA_PWR);
- if (nf & 0x100)
- nf = 0 - ((nf ^ 0x1ff) + 1);
- ath_print(common, ATH_DBG_CALIBRATE,
- "NF calibrated [ctl] [chain 1] is %d\n", nf);
- nfarray[1] = nf;
+ nfarray[1] = sign_extend(nf, 9);
nf = MS(REG_READ(ah, AR_PHY_CH2_CCA), AR_PHY_CH2_MINCCA_PWR);
- if (nf & 0x100)
- nf = 0 - ((nf ^ 0x1ff) + 1);
- ath_print(common, ATH_DBG_CALIBRATE,
- "NF calibrated [ctl] [chain 2] is %d\n", nf);
- nfarray[2] = nf;
+ nfarray[2] = sign_extend(nf, 9);
+
+ if (!IS_CHAN_HT40(ah->curchan))
+ return;
nf = MS(REG_READ(ah, AR_PHY_EXT_CCA), AR_PHY_EXT_MINCCA_PWR);
- if (nf & 0x100)
- nf = 0 - ((nf ^ 0x1ff) + 1);
- ath_print(common, ATH_DBG_CALIBRATE,
- "NF calibrated [ext] [chain 0] is %d\n", nf);
- nfarray[3] = nf;
+ nfarray[3] = sign_extend(nf, 9);
nf = MS(REG_READ(ah, AR_PHY_CH1_EXT_CCA), AR_PHY_CH1_EXT_MINCCA_PWR);
- if (nf & 0x100)
- nf = 0 - ((nf ^ 0x1ff) + 1);
- ath_print(common, ATH_DBG_CALIBRATE,
- "NF calibrated [ext] [chain 1] is %d\n", nf);
- nfarray[4] = nf;
+ nfarray[4] = sign_extend(nf, 9);
nf = MS(REG_READ(ah, AR_PHY_CH2_EXT_CCA), AR_PHY_CH2_EXT_MINCCA_PWR);
- if (nf & 0x100)
- nf = 0 - ((nf ^ 0x1ff) + 1);
- ath_print(common, ATH_DBG_CALIBRATE,
- "NF calibrated [ext] [chain 2] is %d\n", nf);
- nfarray[5] = nf;
+ nfarray[5] = sign_extend(nf, 9);
}
-static void ar5008_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan)
+/*
+ * Initialize the ANI register values with default (ini) values.
+ * This routine is called during a (full) hardware reset after
+ * all the registers are initialised from the INI.
+ */
+static void ar5008_hw_ani_cache_ini_regs(struct ath_hw *ah)
{
- struct ath9k_nfcal_hist *h;
- int i, j;
- int32_t val;
- const u32 ar5416_cca_regs[6] = {
- AR_PHY_CCA,
- AR_PHY_CH1_CCA,
- AR_PHY_CH2_CCA,
- AR_PHY_EXT_CCA,
- AR_PHY_CH1_EXT_CCA,
- AR_PHY_CH2_EXT_CCA
- };
- u8 chainmask, rx_chain_status;
-
- rx_chain_status = REG_READ(ah, AR_PHY_RX_CHAINMASK);
- if (AR_SREV_9285(ah) || AR_SREV_9271(ah))
- chainmask = 0x9;
- else if (AR_SREV_9280(ah) || AR_SREV_9287(ah)) {
- if ((rx_chain_status & 0x2) || (rx_chain_status & 0x4))
- chainmask = 0x1B;
- else
- chainmask = 0x09;
- } else {
- if (rx_chain_status & 0x4)
- chainmask = 0x3F;
- else if (rx_chain_status & 0x2)
- chainmask = 0x1B;
- else
- chainmask = 0x09;
- }
-
- h = ah->nfCalHist;
-
- for (i = 0; i < NUM_NF_READINGS; i++) {
- if (chainmask & (1 << i)) {
- val = REG_READ(ah, ar5416_cca_regs[i]);
- val &= 0xFFFFFE00;
- val |= (((u32) (h[i].privNF) << 1) & 0x1ff);
- REG_WRITE(ah, ar5416_cca_regs[i], val);
- }
- }
-
- REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL,
- AR_PHY_AGC_CONTROL_ENABLE_NF);
- REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL,
- AR_PHY_AGC_CONTROL_NO_UPDATE_NF);
- REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NF);
-
- for (j = 0; j < 5; j++) {
- if ((REG_READ(ah, AR_PHY_AGC_CONTROL) &
- AR_PHY_AGC_CONTROL_NF) == 0)
- break;
- udelay(50);
- }
+ struct ar5416AniState *aniState;
+ struct ath_common *common = ath9k_hw_common(ah);
+ struct ath9k_channel *chan = ah->curchan;
+ struct ath9k_ani_default *iniDef;
+ int index;
+ u32 val;
- ENABLE_REGWRITE_BUFFER(ah);
+ index = ath9k_hw_get_ani_channel_idx(ah, chan);
+ aniState = &ah->ani[index];
+ ah->curani = aniState;
+ iniDef = &aniState->iniDef;
- for (i = 0; i < NUM_NF_READINGS; i++) {
- if (chainmask & (1 << i)) {
- val = REG_READ(ah, ar5416_cca_regs[i]);
- val &= 0xFFFFFE00;
- val |= (((u32) (-50) << 1) & 0x1ff);
- REG_WRITE(ah, ar5416_cca_regs[i], val);
- }
- }
+ ath_print(common, ATH_DBG_ANI,
+ "ver %d.%d opmode %u chan %d Mhz/0x%x\n",
+ ah->hw_version.macVersion,
+ ah->hw_version.macRev,
+ ah->opmode,
+ chan->channel,
+ chan->channelFlags);
+
+ val = REG_READ(ah, AR_PHY_SFCORR);
+ iniDef->m1Thresh = MS(val, AR_PHY_SFCORR_M1_THRESH);
+ iniDef->m2Thresh = MS(val, AR_PHY_SFCORR_M2_THRESH);
+ iniDef->m2CountThr = MS(val, AR_PHY_SFCORR_M2COUNT_THR);
+
+ val = REG_READ(ah, AR_PHY_SFCORR_LOW);
+ iniDef->m1ThreshLow = MS(val, AR_PHY_SFCORR_LOW_M1_THRESH_LOW);
+ iniDef->m2ThreshLow = MS(val, AR_PHY_SFCORR_LOW_M2_THRESH_LOW);
+ iniDef->m2CountThrLow = MS(val, AR_PHY_SFCORR_LOW_M2COUNT_THR_LOW);
+
+ val = REG_READ(ah, AR_PHY_SFCORR_EXT);
+ iniDef->m1ThreshExt = MS(val, AR_PHY_SFCORR_EXT_M1_THRESH);
+ iniDef->m2ThreshExt = MS(val, AR_PHY_SFCORR_EXT_M2_THRESH);
+ iniDef->m1ThreshLowExt = MS(val, AR_PHY_SFCORR_EXT_M1_THRESH_LOW);
+ iniDef->m2ThreshLowExt = MS(val, AR_PHY_SFCORR_EXT_M2_THRESH_LOW);
+ iniDef->firstep = REG_READ_FIELD(ah,
+ AR_PHY_FIND_SIG,
+ AR_PHY_FIND_SIG_FIRSTEP);
+ iniDef->firstepLow = REG_READ_FIELD(ah,
+ AR_PHY_FIND_SIG_LOW,
+ AR_PHY_FIND_SIG_FIRSTEP_LOW);
+ iniDef->cycpwrThr1 = REG_READ_FIELD(ah,
+ AR_PHY_TIMING5,
+ AR_PHY_TIMING5_CYCPWR_THR1);
+ iniDef->cycpwrThr1Ext = REG_READ_FIELD(ah,
+ AR_PHY_EXT_CCA,
+ AR_PHY_EXT_TIMING5_CYCPWR_THR1);
+
+ /* these levels just got reset to defaults by the INI */
+ aniState->spurImmunityLevel = ATH9K_ANI_SPUR_IMMUNE_LVL_NEW;
+ aniState->firstepLevel = ATH9K_ANI_FIRSTEP_LVL_NEW;
+ aniState->ofdmWeakSigDetectOff = !ATH9K_ANI_USE_OFDM_WEAK_SIG;
+ aniState->mrcCCKOff = true; /* not available on pre AR9003 */
+
+ aniState->cycleCount = 0;
+}
- REGWRITE_BUFFER_FLUSH(ah);
- DISABLE_REGWRITE_BUFFER(ah);
+static void ar5008_hw_set_nf_limits(struct ath_hw *ah)
+{
+ ah->nf_2g.max = AR_PHY_CCA_MAX_GOOD_VAL_5416_2GHZ;
+ ah->nf_2g.min = AR_PHY_CCA_MIN_GOOD_VAL_5416_2GHZ;
+ ah->nf_2g.nominal = AR_PHY_CCA_NOM_VAL_5416_2GHZ;
+ ah->nf_5g.max = AR_PHY_CCA_MAX_GOOD_VAL_5416_5GHZ;
+ ah->nf_5g.min = AR_PHY_CCA_MIN_GOOD_VAL_5416_5GHZ;
+ ah->nf_5g.nominal = AR_PHY_CCA_NOM_VAL_5416_5GHZ;
}
void ar5008_hw_attach_phy_ops(struct ath_hw *ah)
{
struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah);
+ const u32 ar5416_cca_regs[6] = {
+ AR_PHY_CCA,
+ AR_PHY_CH1_CCA,
+ AR_PHY_CH2_CCA,
+ AR_PHY_EXT_CCA,
+ AR_PHY_CH1_EXT_CCA,
+ AR_PHY_CH2_EXT_CCA
+ };
priv_ops->rf_set_freq = ar5008_hw_set_channel;
priv_ops->spur_mitigate_freq = ar5008_hw_spur_mitigate;
@@ -1361,9 +1622,13 @@ void ar5008_hw_attach_phy_ops(struct ath_hw *ah)
priv_ops->enable_rfkill = ar5008_hw_enable_rfkill;
priv_ops->restore_chainmask = ar5008_restore_chainmask;
priv_ops->set_diversity = ar5008_set_diversity;
- priv_ops->ani_control = ar5008_hw_ani_control;
priv_ops->do_getnf = ar5008_hw_do_getnf;
- priv_ops->loadnf = ar5008_hw_loadnf;
+
+ if (modparam_force_new_ani) {
+ priv_ops->ani_control = ar5008_hw_ani_control_new;
+ priv_ops->ani_cache_ini_regs = ar5008_hw_ani_cache_ini_regs;
+ } else
+ priv_ops->ani_control = ar5008_hw_ani_control_old;
if (AR_SREV_9100(ah))
priv_ops->compute_pll_control = ar9100_hw_compute_pll_control;
@@ -1371,4 +1636,7 @@ void ar5008_hw_attach_phy_ops(struct ath_hw *ah)
priv_ops->compute_pll_control = ar9160_hw_compute_pll_control;
else
priv_ops->compute_pll_control = ar5008_hw_compute_pll_control;
+
+ ar5008_hw_set_nf_limits(ah);
+ memcpy(ah->nf_regs, ar5416_cca_regs, sizeof(ah->nf_regs));
}
diff --git a/drivers/net/wireless/ath/ath9k/ar9001_initvals.h b/drivers/net/wireless/ath/ath9k/ar9001_initvals.h
index 0b94bd385b0..69a94c7e45c 100644
--- a/drivers/net/wireless/ath/ath9k/ar9001_initvals.h
+++ b/drivers/net/wireless/ath/ath9k/ar9001_initvals.h
@@ -1,1254 +1,1357 @@
+/*
+ * Copyright (c) 2010 Atheros Communications Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+static const u32 ar5416Modes_9100[][6] = {
+ {0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160, 0x000001e0},
+ {0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c, 0x000001e0},
+ {0x000010b0, 0x00000e60, 0x00001cc0, 0x00007c70, 0x00003e38, 0x00001180},
+ {0x000010f0, 0x0000a000, 0x00014000, 0x00016000, 0x0000b000, 0x00014008},
+ {0x00008014, 0x03e803e8, 0x07d007d0, 0x10801600, 0x08400b00, 0x06e006e0},
+ {0x0000801c, 0x128d93a7, 0x128d93cf, 0x12e013d7, 0x12e013ab, 0x098813cf},
+ {0x00008120, 0x08f04800, 0x08f04800, 0x08f04810, 0x08f04810, 0x08f04810},
+ {0x000081d0, 0x00003210, 0x00003210, 0x0000320a, 0x0000320a, 0x0000320a},
+ {0x00009804, 0x00000300, 0x000003c4, 0x000003c4, 0x00000300, 0x00000303},
+ {0x00009820, 0x02020200, 0x02020200, 0x02020200, 0x02020200, 0x02020200},
+ {0x00009824, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e},
+ {0x00009828, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001},
+ {0x00009834, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e},
+ {0x00009838, 0x00000007, 0x00000007, 0x00000007, 0x00000007, 0x00000007},
+ {0x00009844, 0x0372161e, 0x0372161e, 0x037216a0, 0x037216a0, 0x037216a0},
+ {0x00009848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68},
+ {0x0000a848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68},
+ {0x0000b848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68},
+ {0x00009850, 0x6c48b4e2, 0x6d48b4e2, 0x6d48b0e2, 0x6c48b0e2, 0x6c48b0e2},
+ {0x00009858, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e},
+ {0x0000985c, 0x31395d5e, 0x3139605e, 0x3139605e, 0x31395d5e, 0x31395d5e},
+ {0x00009860, 0x00048d18, 0x00048d18, 0x00048d20, 0x00048d20, 0x00048d18},
+ {0x0000c864, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00},
+ {0x00009868, 0x409a40d0, 0x409a40d0, 0x409a40d0, 0x409a40d0, 0x409a40d0},
+ {0x0000986c, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081},
+ {0x00009914, 0x000007d0, 0x00000fa0, 0x00001130, 0x00000898, 0x000007d0},
+ {0x00009918, 0x0000000a, 0x00000014, 0x00000016, 0x0000000b, 0x00000016},
+ {0x00009924, 0xd00a8a07, 0xd00a8a07, 0xd00a8a0d, 0xd00a8a0d, 0xd00a8a0d},
+ {0x00009940, 0x00750604, 0x00754604, 0xfff81204, 0xfff81204, 0xfff81204},
+ {0x00009944, 0xdfb81020, 0xdfb81020, 0xdfb81020, 0xdfb81020, 0xdfb81020},
+ {0x00009954, 0x5f3ca3de, 0x5f3ca3de, 0xe250a51e, 0xe250a51e, 0xe250a51e},
+ {0x00009958, 0x2108ecff, 0x2108ecff, 0x3388ffff, 0x3388ffff, 0x3388ffff},
+ {0x00009960, 0x0001bfc0, 0x0001bfc0, 0x0001bfc0, 0x0001bfc0, 0x0001bfc0},
+ {0x0000a960, 0x0001bfc0, 0x0001bfc0, 0x0001bfc0, 0x0001bfc0, 0x0001bfc0},
+ {0x0000b960, 0x0001bfc0, 0x0001bfc0, 0x0001bfc0, 0x0001bfc0, 0x0001bfc0},
+ {0x00009964, 0x00001120, 0x00001120, 0x00001120, 0x00001120, 0x00001120},
+ {0x0000c9bc, 0x001a0600, 0x001a0600, 0x001a1000, 0x001a0c00, 0x001a0c00},
+ {0x000099c0, 0x038919be, 0x038919be, 0x038919be, 0x038919be, 0x038919be},
+ {0x000099c4, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77},
+ {0x000099c8, 0x6af65329, 0x6af65329, 0x6af65329, 0x6af65329, 0x6af65329},
+ {0x000099cc, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8},
+ {0x000099d0, 0x00046384, 0x00046384, 0x00046384, 0x00046384, 0x00046384},
+ {0x000099d4, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+ {0x000099d8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+ {0x0000a204, 0x00000880, 0x00000880, 0x00000880, 0x00000880, 0x00000880},
+ {0x0000a208, 0xd6be4788, 0xd6be4788, 0xd03e4788, 0xd03e4788, 0xd03e4788},
+ {0x0000a20c, 0x002fc160, 0x002fc160, 0x002ac120, 0x002ac120, 0x002ac120},
+ {0x0000b20c, 0x002fc160, 0x002fc160, 0x002ac120, 0x002ac120, 0x002ac120},
+ {0x0000c20c, 0x002fc160, 0x002fc160, 0x002ac120, 0x002ac120, 0x002ac120},
+ {0x0000a21c, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a},
+ {0x0000a230, 0x00000000, 0x00000000, 0x00000210, 0x00000108, 0x00000000},
+ {0x0000a274, 0x0a1a9caa, 0x0a1a9caa, 0x0a1a7caa, 0x0a1a7caa, 0x0a1a7caa},
+ {0x0000a300, 0x18010000, 0x18010000, 0x18010000, 0x18010000, 0x18010000},
+ {0x0000a304, 0x30032602, 0x30032602, 0x2e032402, 0x2e032402, 0x2e032402},
+ {0x0000a308, 0x48073e06, 0x48073e06, 0x4a0a3c06, 0x4a0a3c06, 0x4a0a3c06},
+ {0x0000a30c, 0x560b4c0a, 0x560b4c0a, 0x621a540b, 0x621a540b, 0x621a540b},
+ {0x0000a310, 0x641a600f, 0x641a600f, 0x764f6c1b, 0x764f6c1b, 0x764f6c1b},
+ {0x0000a314, 0x7a4f6e1b, 0x7a4f6e1b, 0x845b7a5a, 0x845b7a5a, 0x845b7a5a},
+ {0x0000a318, 0x8c5b7e5a, 0x8c5b7e5a, 0x950f8ccf, 0x950f8ccf, 0x950f8ccf},
+ {0x0000a31c, 0x9d0f96cf, 0x9d0f96cf, 0xa5cf9b4f, 0xa5cf9b4f, 0xa5cf9b4f},
+ {0x0000a320, 0xb51fa69f, 0xb51fa69f, 0xbddfaf1f, 0xbddfaf1f, 0xbddfaf1f},
+ {0x0000a324, 0xcb3fbd07, 0xcb3fbcbf, 0xd1ffc93f, 0xd1ffc93f, 0xd1ffc93f},
+ {0x0000a328, 0x0000d7bf, 0x0000d7bf, 0x00000000, 0x00000000, 0x00000000},
+ {0x0000a32c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+ {0x0000a330, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+ {0x0000a334, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+};
static const u32 ar5416Common_9100[][2] = {
- { 0x0000000c, 0x00000000 },
- { 0x00000030, 0x00020015 },
- { 0x00000034, 0x00000005 },
- { 0x00000040, 0x00000000 },
- { 0x00000044, 0x00000008 },
- { 0x00000048, 0x00000008 },
- { 0x0000004c, 0x00000010 },
- { 0x00000050, 0x00000000 },
- { 0x00000054, 0x0000001f },
- { 0x00000800, 0x00000000 },
- { 0x00000804, 0x00000000 },
- { 0x00000808, 0x00000000 },
- { 0x0000080c, 0x00000000 },
- { 0x00000810, 0x00000000 },
- { 0x00000814, 0x00000000 },
- { 0x00000818, 0x00000000 },
- { 0x0000081c, 0x00000000 },
- { 0x00000820, 0x00000000 },
- { 0x00000824, 0x00000000 },
- { 0x00001040, 0x002ffc0f },
- { 0x00001044, 0x002ffc0f },
- { 0x00001048, 0x002ffc0f },
- { 0x0000104c, 0x002ffc0f },
- { 0x00001050, 0x002ffc0f },
- { 0x00001054, 0x002ffc0f },
- { 0x00001058, 0x002ffc0f },
- { 0x0000105c, 0x002ffc0f },
- { 0x00001060, 0x002ffc0f },
- { 0x00001064, 0x002ffc0f },
- { 0x00001230, 0x00000000 },
- { 0x00001270, 0x00000000 },
- { 0x00001038, 0x00000000 },
- { 0x00001078, 0x00000000 },
- { 0x000010b8, 0x00000000 },
- { 0x000010f8, 0x00000000 },
- { 0x00001138, 0x00000000 },
- { 0x00001178, 0x00000000 },
- { 0x000011b8, 0x00000000 },
- { 0x000011f8, 0x00000000 },
- { 0x00001238, 0x00000000 },
- { 0x00001278, 0x00000000 },
- { 0x000012b8, 0x00000000 },
- { 0x000012f8, 0x00000000 },
- { 0x00001338, 0x00000000 },
- { 0x00001378, 0x00000000 },
- { 0x000013b8, 0x00000000 },
- { 0x000013f8, 0x00000000 },
- { 0x00001438, 0x00000000 },
- { 0x00001478, 0x00000000 },
- { 0x000014b8, 0x00000000 },
- { 0x000014f8, 0x00000000 },
- { 0x00001538, 0x00000000 },
- { 0x00001578, 0x00000000 },
- { 0x000015b8, 0x00000000 },
- { 0x000015f8, 0x00000000 },
- { 0x00001638, 0x00000000 },
- { 0x00001678, 0x00000000 },
- { 0x000016b8, 0x00000000 },
- { 0x000016f8, 0x00000000 },
- { 0x00001738, 0x00000000 },
- { 0x00001778, 0x00000000 },
- { 0x000017b8, 0x00000000 },
- { 0x000017f8, 0x00000000 },
- { 0x0000103c, 0x00000000 },
- { 0x0000107c, 0x00000000 },
- { 0x000010bc, 0x00000000 },
- { 0x000010fc, 0x00000000 },
- { 0x0000113c, 0x00000000 },
- { 0x0000117c, 0x00000000 },
- { 0x000011bc, 0x00000000 },
- { 0x000011fc, 0x00000000 },
- { 0x0000123c, 0x00000000 },
- { 0x0000127c, 0x00000000 },
- { 0x000012bc, 0x00000000 },
- { 0x000012fc, 0x00000000 },
- { 0x0000133c, 0x00000000 },
- { 0x0000137c, 0x00000000 },
- { 0x000013bc, 0x00000000 },
- { 0x000013fc, 0x00000000 },
- { 0x0000143c, 0x00000000 },
- { 0x0000147c, 0x00000000 },
- { 0x00020010, 0x00000003 },
- { 0x00020038, 0x000004c2 },
- { 0x00008004, 0x00000000 },
- { 0x00008008, 0x00000000 },
- { 0x0000800c, 0x00000000 },
- { 0x00008018, 0x00000700 },
- { 0x00008020, 0x00000000 },
- { 0x00008038, 0x00000000 },
- { 0x0000803c, 0x00000000 },
- { 0x00008048, 0x40000000 },
- { 0x00008054, 0x00004000 },
- { 0x00008058, 0x00000000 },
- { 0x0000805c, 0x000fc78f },
- { 0x00008060, 0x0000000f },
- { 0x00008064, 0x00000000 },
- { 0x000080c0, 0x2a82301a },
- { 0x000080c4, 0x05dc01e0 },
- { 0x000080c8, 0x1f402710 },
- { 0x000080cc, 0x01f40000 },
- { 0x000080d0, 0x00001e00 },
- { 0x000080d4, 0x00000000 },
- { 0x000080d8, 0x00400000 },
- { 0x000080e0, 0xffffffff },
- { 0x000080e4, 0x0000ffff },
- { 0x000080e8, 0x003f3f3f },
- { 0x000080ec, 0x00000000 },
- { 0x000080f0, 0x00000000 },
- { 0x000080f4, 0x00000000 },
- { 0x000080f8, 0x00000000 },
- { 0x000080fc, 0x00020000 },
- { 0x00008100, 0x00020000 },
- { 0x00008104, 0x00000001 },
- { 0x00008108, 0x00000052 },
- { 0x0000810c, 0x00000000 },
- { 0x00008110, 0x00000168 },
- { 0x00008118, 0x000100aa },
- { 0x0000811c, 0x00003210 },
- { 0x00008120, 0x08f04800 },
- { 0x00008124, 0x00000000 },
- { 0x00008128, 0x00000000 },
- { 0x0000812c, 0x00000000 },
- { 0x00008130, 0x00000000 },
- { 0x00008134, 0x00000000 },
- { 0x00008138, 0x00000000 },
- { 0x0000813c, 0x00000000 },
- { 0x00008144, 0x00000000 },
- { 0x00008168, 0x00000000 },
- { 0x0000816c, 0x00000000 },
- { 0x00008170, 0x32143320 },
- { 0x00008174, 0xfaa4fa50 },
- { 0x00008178, 0x00000100 },
- { 0x0000817c, 0x00000000 },
- { 0x000081c4, 0x00000000 },
- { 0x000081d0, 0x00003210 },
- { 0x000081ec, 0x00000000 },
- { 0x000081f0, 0x00000000 },
- { 0x000081f4, 0x00000000 },
- { 0x000081f8, 0x00000000 },
- { 0x000081fc, 0x00000000 },
- { 0x00008200, 0x00000000 },
- { 0x00008204, 0x00000000 },
- { 0x00008208, 0x00000000 },
- { 0x0000820c, 0x00000000 },
- { 0x00008210, 0x00000000 },
- { 0x00008214, 0x00000000 },
- { 0x00008218, 0x00000000 },
- { 0x0000821c, 0x00000000 },
- { 0x00008220, 0x00000000 },
- { 0x00008224, 0x00000000 },
- { 0x00008228, 0x00000000 },
- { 0x0000822c, 0x00000000 },
- { 0x00008230, 0x00000000 },
- { 0x00008234, 0x00000000 },
- { 0x00008238, 0x00000000 },
- { 0x0000823c, 0x00000000 },
- { 0x00008240, 0x00100000 },
- { 0x00008244, 0x0010f400 },
- { 0x00008248, 0x00000100 },
- { 0x0000824c, 0x0001e800 },
- { 0x00008250, 0x00000000 },
- { 0x00008254, 0x00000000 },
- { 0x00008258, 0x00000000 },
- { 0x0000825c, 0x400000ff },
- { 0x00008260, 0x00080922 },
- { 0x00008270, 0x00000000 },
- { 0x00008274, 0x40000000 },
- { 0x00008278, 0x003e4180 },
- { 0x0000827c, 0x00000000 },
- { 0x00008284, 0x0000002c },
- { 0x00008288, 0x0000002c },
- { 0x0000828c, 0x00000000 },
- { 0x00008294, 0x00000000 },
- { 0x00008298, 0x00000000 },
- { 0x00008300, 0x00000000 },
- { 0x00008304, 0x00000000 },
- { 0x00008308, 0x00000000 },
- { 0x0000830c, 0x00000000 },
- { 0x00008310, 0x00000000 },
- { 0x00008314, 0x00000000 },
- { 0x00008318, 0x00000000 },
- { 0x00008328, 0x00000000 },
- { 0x0000832c, 0x00000007 },
- { 0x00008330, 0x00000302 },
- { 0x00008334, 0x00000e00 },
- { 0x00008338, 0x00000000 },
- { 0x0000833c, 0x00000000 },
- { 0x00008340, 0x000107ff },
- { 0x00009808, 0x00000000 },
- { 0x0000980c, 0xad848e19 },
- { 0x00009810, 0x7d14e000 },
- { 0x00009814, 0x9c0a9f6b },
- { 0x0000981c, 0x00000000 },
- { 0x0000982c, 0x0000a000 },
- { 0x00009830, 0x00000000 },
- { 0x0000983c, 0x00200400 },
- { 0x00009840, 0x206a01ae },
- { 0x0000984c, 0x1284233c },
- { 0x00009854, 0x00000859 },
- { 0x00009900, 0x00000000 },
- { 0x00009904, 0x00000000 },
- { 0x00009908, 0x00000000 },
- { 0x0000990c, 0x00000000 },
- { 0x0000991c, 0x10000fff },
- { 0x00009920, 0x05100000 },
- { 0x0000a920, 0x05100000 },
- { 0x0000b920, 0x05100000 },
- { 0x00009928, 0x00000001 },
- { 0x0000992c, 0x00000004 },
- { 0x00009934, 0x1e1f2022 },
- { 0x00009938, 0x0a0b0c0d },
- { 0x0000993c, 0x00000000 },
- { 0x00009948, 0x9280b212 },
- { 0x0000994c, 0x00020028 },
- { 0x0000c95c, 0x004b6a8e },
- { 0x0000c968, 0x000003ce },
- { 0x00009970, 0x190fb515 },
- { 0x00009974, 0x00000000 },
- { 0x00009978, 0x00000001 },
- { 0x0000997c, 0x00000000 },
- { 0x00009980, 0x00000000 },
- { 0x00009984, 0x00000000 },
- { 0x00009988, 0x00000000 },
- { 0x0000998c, 0x00000000 },
- { 0x00009990, 0x00000000 },
- { 0x00009994, 0x00000000 },
- { 0x00009998, 0x00000000 },
- { 0x0000999c, 0x00000000 },
- { 0x000099a0, 0x00000000 },
- { 0x000099a4, 0x00000001 },
- { 0x000099a8, 0x201fff00 },
- { 0x000099ac, 0x006f0000 },
- { 0x000099b0, 0x03051000 },
- { 0x000099dc, 0x00000000 },
- { 0x000099e0, 0x00000200 },
- { 0x000099e4, 0xaaaaaaaa },
- { 0x000099e8, 0x3c466478 },
- { 0x000099ec, 0x0cc80caa },
- { 0x000099fc, 0x00001042 },
- { 0x00009b00, 0x00000000 },
- { 0x00009b04, 0x00000001 },
- { 0x00009b08, 0x00000002 },
- { 0x00009b0c, 0x00000003 },
- { 0x00009b10, 0x00000004 },
- { 0x00009b14, 0x00000005 },
- { 0x00009b18, 0x00000008 },
- { 0x00009b1c, 0x00000009 },
- { 0x00009b20, 0x0000000a },
- { 0x00009b24, 0x0000000b },
- { 0x00009b28, 0x0000000c },
- { 0x00009b2c, 0x0000000d },
- { 0x00009b30, 0x00000010 },
- { 0x00009b34, 0x00000011 },
- { 0x00009b38, 0x00000012 },
- { 0x00009b3c, 0x00000013 },
- { 0x00009b40, 0x00000014 },
- { 0x00009b44, 0x00000015 },
- { 0x00009b48, 0x00000018 },
- { 0x00009b4c, 0x00000019 },
- { 0x00009b50, 0x0000001a },
- { 0x00009b54, 0x0000001b },
- { 0x00009b58, 0x0000001c },
- { 0x00009b5c, 0x0000001d },
- { 0x00009b60, 0x00000020 },
- { 0x00009b64, 0x00000021 },
- { 0x00009b68, 0x00000022 },
- { 0x00009b6c, 0x00000023 },
- { 0x00009b70, 0x00000024 },
- { 0x00009b74, 0x00000025 },
- { 0x00009b78, 0x00000028 },
- { 0x00009b7c, 0x00000029 },
- { 0x00009b80, 0x0000002a },
- { 0x00009b84, 0x0000002b },
- { 0x00009b88, 0x0000002c },
- { 0x00009b8c, 0x0000002d },
- { 0x00009b90, 0x00000030 },
- { 0x00009b94, 0x00000031 },
- { 0x00009b98, 0x00000032 },
- { 0x00009b9c, 0x00000033 },
- { 0x00009ba0, 0x00000034 },
- { 0x00009ba4, 0x00000035 },
- { 0x00009ba8, 0x00000035 },
- { 0x00009bac, 0x00000035 },
- { 0x00009bb0, 0x00000035 },
- { 0x00009bb4, 0x00000035 },
- { 0x00009bb8, 0x00000035 },
- { 0x00009bbc, 0x00000035 },
- { 0x00009bc0, 0x00000035 },
- { 0x00009bc4, 0x00000035 },
- { 0x00009bc8, 0x00000035 },
- { 0x00009bcc, 0x00000035 },
- { 0x00009bd0, 0x00000035 },
- { 0x00009bd4, 0x00000035 },
- { 0x00009bd8, 0x00000035 },
- { 0x00009bdc, 0x00000035 },
- { 0x00009be0, 0x00000035 },
- { 0x00009be4, 0x00000035 },
- { 0x00009be8, 0x00000035 },
- { 0x00009bec, 0x00000035 },
- { 0x00009bf0, 0x00000035 },
- { 0x00009bf4, 0x00000035 },
- { 0x00009bf8, 0x00000010 },
- { 0x00009bfc, 0x0000001a },
- { 0x0000a210, 0x40806333 },
- { 0x0000a214, 0x00106c10 },
- { 0x0000a218, 0x009c4060 },
- { 0x0000a220, 0x018830c6 },
- { 0x0000a224, 0x00000400 },
- { 0x0000a228, 0x001a0bb5 },
- { 0x0000a22c, 0x00000000 },
- { 0x0000a234, 0x20202020 },
- { 0x0000a238, 0x20202020 },
- { 0x0000a23c, 0x13c889ae },
- { 0x0000a240, 0x38490a20 },
- { 0x0000a244, 0x00007bb6 },
- { 0x0000a248, 0x0fff3ffc },
- { 0x0000a24c, 0x00000001 },
- { 0x0000a250, 0x0000a000 },
- { 0x0000a254, 0x00000000 },
- { 0x0000a258, 0x0cc75380 },
- { 0x0000a25c, 0x0f0f0f01 },
- { 0x0000a260, 0xdfa91f01 },
- { 0x0000a268, 0x00000001 },
- { 0x0000a26c, 0x0ebae9c6 },
- { 0x0000b26c, 0x0ebae9c6 },
- { 0x0000c26c, 0x0ebae9c6 },
- { 0x0000d270, 0x00820820 },
- { 0x0000a278, 0x1ce739ce },
- { 0x0000a27c, 0x050701ce },
- { 0x0000a338, 0x00000000 },
- { 0x0000a33c, 0x00000000 },
- { 0x0000a340, 0x00000000 },
- { 0x0000a344, 0x00000000 },
- { 0x0000a348, 0x3fffffff },
- { 0x0000a34c, 0x3fffffff },
- { 0x0000a350, 0x3fffffff },
- { 0x0000a354, 0x0003ffff },
- { 0x0000a358, 0x79a8aa33 },
- { 0x0000d35c, 0x07ffffef },
- { 0x0000d360, 0x0fffffe7 },
- { 0x0000d364, 0x17ffffe5 },
- { 0x0000d368, 0x1fffffe4 },
- { 0x0000d36c, 0x37ffffe3 },
- { 0x0000d370, 0x3fffffe3 },
- { 0x0000d374, 0x57ffffe3 },
- { 0x0000d378, 0x5fffffe2 },
- { 0x0000d37c, 0x7fffffe2 },
- { 0x0000d380, 0x7f3c7bba },
- { 0x0000d384, 0xf3307ff0 },
- { 0x0000a388, 0x0c000000 },
- { 0x0000a38c, 0x20202020 },
- { 0x0000a390, 0x20202020 },
- { 0x0000a394, 0x1ce739ce },
- { 0x0000a398, 0x000001ce },
- { 0x0000a39c, 0x00000001 },
- { 0x0000a3a0, 0x00000000 },
- { 0x0000a3a4, 0x00000000 },
- { 0x0000a3a8, 0x00000000 },
- { 0x0000a3ac, 0x00000000 },
- { 0x0000a3b0, 0x00000000 },
- { 0x0000a3b4, 0x00000000 },
- { 0x0000a3b8, 0x00000000 },
- { 0x0000a3bc, 0x00000000 },
- { 0x0000a3c0, 0x00000000 },
- { 0x0000a3c4, 0x00000000 },
- { 0x0000a3c8, 0x00000246 },
- { 0x0000a3cc, 0x20202020 },
- { 0x0000a3d0, 0x20202020 },
- { 0x0000a3d4, 0x20202020 },
- { 0x0000a3dc, 0x1ce739ce },
- { 0x0000a3e0, 0x000001ce },
+ /* Addr allmodes */
+ {0x0000000c, 0x00000000},
+ {0x00000030, 0x00020015},
+ {0x00000034, 0x00000005},
+ {0x00000040, 0x00000000},
+ {0x00000044, 0x00000008},
+ {0x00000048, 0x00000008},
+ {0x0000004c, 0x00000010},
+ {0x00000050, 0x00000000},
+ {0x00000054, 0x0000001f},
+ {0x00000800, 0x00000000},
+ {0x00000804, 0x00000000},
+ {0x00000808, 0x00000000},
+ {0x0000080c, 0x00000000},
+ {0x00000810, 0x00000000},
+ {0x00000814, 0x00000000},
+ {0x00000818, 0x00000000},
+ {0x0000081c, 0x00000000},
+ {0x00000820, 0x00000000},
+ {0x00000824, 0x00000000},
+ {0x00001040, 0x002ffc0f},
+ {0x00001044, 0x002ffc0f},
+ {0x00001048, 0x002ffc0f},
+ {0x0000104c, 0x002ffc0f},
+ {0x00001050, 0x002ffc0f},
+ {0x00001054, 0x002ffc0f},
+ {0x00001058, 0x002ffc0f},
+ {0x0000105c, 0x002ffc0f},
+ {0x00001060, 0x002ffc0f},
+ {0x00001064, 0x002ffc0f},
+ {0x00001230, 0x00000000},
+ {0x00001270, 0x00000000},
+ {0x00001038, 0x00000000},
+ {0x00001078, 0x00000000},
+ {0x000010b8, 0x00000000},
+ {0x000010f8, 0x00000000},
+ {0x00001138, 0x00000000},
+ {0x00001178, 0x00000000},
+ {0x000011b8, 0x00000000},
+ {0x000011f8, 0x00000000},
+ {0x00001238, 0x00000000},
+ {0x00001278, 0x00000000},
+ {0x000012b8, 0x00000000},
+ {0x000012f8, 0x00000000},
+ {0x00001338, 0x00000000},
+ {0x00001378, 0x00000000},
+ {0x000013b8, 0x00000000},
+ {0x000013f8, 0x00000000},
+ {0x00001438, 0x00000000},
+ {0x00001478, 0x00000000},
+ {0x000014b8, 0x00000000},
+ {0x000014f8, 0x00000000},
+ {0x00001538, 0x00000000},
+ {0x00001578, 0x00000000},
+ {0x000015b8, 0x00000000},
+ {0x000015f8, 0x00000000},
+ {0x00001638, 0x00000000},
+ {0x00001678, 0x00000000},
+ {0x000016b8, 0x00000000},
+ {0x000016f8, 0x00000000},
+ {0x00001738, 0x00000000},
+ {0x00001778, 0x00000000},
+ {0x000017b8, 0x00000000},
+ {0x000017f8, 0x00000000},
+ {0x0000103c, 0x00000000},
+ {0x0000107c, 0x00000000},
+ {0x000010bc, 0x00000000},
+ {0x000010fc, 0x00000000},
+ {0x0000113c, 0x00000000},
+ {0x0000117c, 0x00000000},
+ {0x000011bc, 0x00000000},
+ {0x000011fc, 0x00000000},
+ {0x0000123c, 0x00000000},
+ {0x0000127c, 0x00000000},
+ {0x000012bc, 0x00000000},
+ {0x000012fc, 0x00000000},
+ {0x0000133c, 0x00000000},
+ {0x0000137c, 0x00000000},
+ {0x000013bc, 0x00000000},
+ {0x000013fc, 0x00000000},
+ {0x0000143c, 0x00000000},
+ {0x0000147c, 0x00000000},
+ {0x00020010, 0x00000003},
+ {0x00020038, 0x000004c2},
+ {0x00008004, 0x00000000},
+ {0x00008008, 0x00000000},
+ {0x0000800c, 0x00000000},
+ {0x00008018, 0x00000700},
+ {0x00008020, 0x00000000},
+ {0x00008038, 0x00000000},
+ {0x0000803c, 0x00000000},
+ {0x00008048, 0x40000000},
+ {0x00008054, 0x00004000},
+ {0x00008058, 0x00000000},
+ {0x0000805c, 0x000fc78f},
+ {0x00008060, 0x0000000f},
+ {0x00008064, 0x00000000},
+ {0x000080c0, 0x2a82301a},
+ {0x000080c4, 0x05dc01e0},
+ {0x000080c8, 0x1f402710},
+ {0x000080cc, 0x01f40000},
+ {0x000080d0, 0x00001e00},
+ {0x000080d4, 0x00000000},
+ {0x000080d8, 0x00400000},
+ {0x000080e0, 0xffffffff},
+ {0x000080e4, 0x0000ffff},
+ {0x000080e8, 0x003f3f3f},
+ {0x000080ec, 0x00000000},
+ {0x000080f0, 0x00000000},
+ {0x000080f4, 0x00000000},
+ {0x000080f8, 0x00000000},
+ {0x000080fc, 0x00020000},
+ {0x00008100, 0x00020000},
+ {0x00008104, 0x00000001},
+ {0x00008108, 0x00000052},
+ {0x0000810c, 0x00000000},
+ {0x00008110, 0x00000168},
+ {0x00008118, 0x000100aa},
+ {0x0000811c, 0x00003210},
+ {0x00008120, 0x08f04800},
+ {0x00008124, 0x00000000},
+ {0x00008128, 0x00000000},
+ {0x0000812c, 0x00000000},
+ {0x00008130, 0x00000000},
+ {0x00008134, 0x00000000},
+ {0x00008138, 0x00000000},
+ {0x0000813c, 0x00000000},
+ {0x00008144, 0x00000000},
+ {0x00008168, 0x00000000},
+ {0x0000816c, 0x00000000},
+ {0x00008170, 0x32143320},
+ {0x00008174, 0xfaa4fa50},
+ {0x00008178, 0x00000100},
+ {0x0000817c, 0x00000000},
+ {0x000081c4, 0x00000000},
+ {0x000081d0, 0x00003210},
+ {0x000081ec, 0x00000000},
+ {0x000081f0, 0x00000000},
+ {0x000081f4, 0x00000000},
+ {0x000081f8, 0x00000000},
+ {0x000081fc, 0x00000000},
+ {0x00008200, 0x00000000},
+ {0x00008204, 0x00000000},
+ {0x00008208, 0x00000000},
+ {0x0000820c, 0x00000000},
+ {0x00008210, 0x00000000},
+ {0x00008214, 0x00000000},
+ {0x00008218, 0x00000000},
+ {0x0000821c, 0x00000000},
+ {0x00008220, 0x00000000},
+ {0x00008224, 0x00000000},
+ {0x00008228, 0x00000000},
+ {0x0000822c, 0x00000000},
+ {0x00008230, 0x00000000},
+ {0x00008234, 0x00000000},
+ {0x00008238, 0x00000000},
+ {0x0000823c, 0x00000000},
+ {0x00008240, 0x00100000},
+ {0x00008244, 0x0010f400},
+ {0x00008248, 0x00000100},
+ {0x0000824c, 0x0001e800},
+ {0x00008250, 0x00000000},
+ {0x00008254, 0x00000000},
+ {0x00008258, 0x00000000},
+ {0x0000825c, 0x400000ff},
+ {0x00008260, 0x00080922},
+ {0x00008270, 0x00000000},
+ {0x00008274, 0x40000000},
+ {0x00008278, 0x003e4180},
+ {0x0000827c, 0x00000000},
+ {0x00008284, 0x0000002c},
+ {0x00008288, 0x0000002c},
+ {0x0000828c, 0x00000000},
+ {0x00008294, 0x00000000},
+ {0x00008298, 0x00000000},
+ {0x00008300, 0x00000000},
+ {0x00008304, 0x00000000},
+ {0x00008308, 0x00000000},
+ {0x0000830c, 0x00000000},
+ {0x00008310, 0x00000000},
+ {0x00008314, 0x00000000},
+ {0x00008318, 0x00000000},
+ {0x00008328, 0x00000000},
+ {0x0000832c, 0x00000007},
+ {0x00008330, 0x00000302},
+ {0x00008334, 0x00000e00},
+ {0x00008338, 0x00000000},
+ {0x0000833c, 0x00000000},
+ {0x00008340, 0x000107ff},
+ {0x00009808, 0x00000000},
+ {0x0000980c, 0xad848e19},
+ {0x00009810, 0x7d14e000},
+ {0x00009814, 0x9c0a9f6b},
+ {0x0000981c, 0x00000000},
+ {0x0000982c, 0x0000a000},
+ {0x00009830, 0x00000000},
+ {0x0000983c, 0x00200400},
+ {0x00009840, 0x206a01ae},
+ {0x0000984c, 0x1284233c},
+ {0x00009854, 0x00000859},
+ {0x00009900, 0x00000000},
+ {0x00009904, 0x00000000},
+ {0x00009908, 0x00000000},
+ {0x0000990c, 0x00000000},
+ {0x0000991c, 0x10000fff},
+ {0x00009920, 0x05100000},
+ {0x0000a920, 0x05100000},
+ {0x0000b920, 0x05100000},
+ {0x00009928, 0x00000001},
+ {0x0000992c, 0x00000004},
+ {0x00009934, 0x1e1f2022},
+ {0x00009938, 0x0a0b0c0d},
+ {0x0000993c, 0x00000000},
+ {0x00009948, 0x9280b212},
+ {0x0000994c, 0x00020028},
+ {0x0000c95c, 0x004b6a8e},
+ {0x0000c968, 0x000003ce},
+ {0x00009970, 0x190fb515},
+ {0x00009974, 0x00000000},
+ {0x00009978, 0x00000001},
+ {0x0000997c, 0x00000000},
+ {0x00009980, 0x00000000},
+ {0x00009984, 0x00000000},
+ {0x00009988, 0x00000000},
+ {0x0000998c, 0x00000000},
+ {0x00009990, 0x00000000},
+ {0x00009994, 0x00000000},
+ {0x00009998, 0x00000000},
+ {0x0000999c, 0x00000000},
+ {0x000099a0, 0x00000000},
+ {0x000099a4, 0x00000001},
+ {0x000099a8, 0x201fff00},
+ {0x000099ac, 0x006f0000},
+ {0x000099b0, 0x03051000},
+ {0x000099dc, 0x00000000},
+ {0x000099e0, 0x00000200},
+ {0x000099e4, 0xaaaaaaaa},
+ {0x000099e8, 0x3c466478},
+ {0x000099ec, 0x0cc80caa},
+ {0x000099fc, 0x00001042},
+ {0x00009b00, 0x00000000},
+ {0x00009b04, 0x00000001},
+ {0x00009b08, 0x00000002},
+ {0x00009b0c, 0x00000003},
+ {0x00009b10, 0x00000004},
+ {0x00009b14, 0x00000005},
+ {0x00009b18, 0x00000008},
+ {0x00009b1c, 0x00000009},
+ {0x00009b20, 0x0000000a},
+ {0x00009b24, 0x0000000b},
+ {0x00009b28, 0x0000000c},
+ {0x00009b2c, 0x0000000d},
+ {0x00009b30, 0x00000010},
+ {0x00009b34, 0x00000011},
+ {0x00009b38, 0x00000012},
+ {0x00009b3c, 0x00000013},
+ {0x00009b40, 0x00000014},
+ {0x00009b44, 0x00000015},
+ {0x00009b48, 0x00000018},
+ {0x00009b4c, 0x00000019},
+ {0x00009b50, 0x0000001a},
+ {0x00009b54, 0x0000001b},
+ {0x00009b58, 0x0000001c},
+ {0x00009b5c, 0x0000001d},
+ {0x00009b60, 0x00000020},
+ {0x00009b64, 0x00000021},
+ {0x00009b68, 0x00000022},
+ {0x00009b6c, 0x00000023},
+ {0x00009b70, 0x00000024},
+ {0x00009b74, 0x00000025},
+ {0x00009b78, 0x00000028},
+ {0x00009b7c, 0x00000029},
+ {0x00009b80, 0x0000002a},
+ {0x00009b84, 0x0000002b},
+ {0x00009b88, 0x0000002c},
+ {0x00009b8c, 0x0000002d},
+ {0x00009b90, 0x00000030},
+ {0x00009b94, 0x00000031},
+ {0x00009b98, 0x00000032},
+ {0x00009b9c, 0x00000033},
+ {0x00009ba0, 0x00000034},
+ {0x00009ba4, 0x00000035},
+ {0x00009ba8, 0x00000035},
+ {0x00009bac, 0x00000035},
+ {0x00009bb0, 0x00000035},
+ {0x00009bb4, 0x00000035},
+ {0x00009bb8, 0x00000035},
+ {0x00009bbc, 0x00000035},
+ {0x00009bc0, 0x00000035},
+ {0x00009bc4, 0x00000035},
+ {0x00009bc8, 0x00000035},
+ {0x00009bcc, 0x00000035},
+ {0x00009bd0, 0x00000035},
+ {0x00009bd4, 0x00000035},
+ {0x00009bd8, 0x00000035},
+ {0x00009bdc, 0x00000035},
+ {0x00009be0, 0x00000035},
+ {0x00009be4, 0x00000035},
+ {0x00009be8, 0x00000035},
+ {0x00009bec, 0x00000035},
+ {0x00009bf0, 0x00000035},
+ {0x00009bf4, 0x00000035},
+ {0x00009bf8, 0x00000010},
+ {0x00009bfc, 0x0000001a},
+ {0x0000a210, 0x40806333},
+ {0x0000a214, 0x00106c10},
+ {0x0000a218, 0x009c4060},
+ {0x0000a220, 0x018830c6},
+ {0x0000a224, 0x00000400},
+ {0x0000a228, 0x001a0bb5},
+ {0x0000a22c, 0x00000000},
+ {0x0000a234, 0x20202020},
+ {0x0000a238, 0x20202020},
+ {0x0000a23c, 0x13c889af},
+ {0x0000a240, 0x38490a20},
+ {0x0000a244, 0x00007bb6},
+ {0x0000a248, 0x0fff3ffc},
+ {0x0000a24c, 0x00000001},
+ {0x0000a250, 0x0000e000},
+ {0x0000a254, 0x00000000},
+ {0x0000a258, 0x0cc75380},
+ {0x0000a25c, 0x0f0f0f01},
+ {0x0000a260, 0xdfa91f01},
+ {0x0000a268, 0x00000001},
+ {0x0000a26c, 0x0ebae9c6},
+ {0x0000b26c, 0x0ebae9c6},
+ {0x0000c26c, 0x0ebae9c6},
+ {0x0000d270, 0x00820820},
+ {0x0000a278, 0x1ce739ce},
+ {0x0000a27c, 0x050701ce},
+ {0x0000a338, 0x00000000},
+ {0x0000a33c, 0x00000000},
+ {0x0000a340, 0x00000000},
+ {0x0000a344, 0x00000000},
+ {0x0000a348, 0x3fffffff},
+ {0x0000a34c, 0x3fffffff},
+ {0x0000a350, 0x3fffffff},
+ {0x0000a354, 0x0003ffff},
+ {0x0000a358, 0x79a8aa33},
+ {0x0000d35c, 0x07ffffef},
+ {0x0000d360, 0x0fffffe7},
+ {0x0000d364, 0x17ffffe5},
+ {0x0000d368, 0x1fffffe4},
+ {0x0000d36c, 0x37ffffe3},
+ {0x0000d370, 0x3fffffe3},
+ {0x0000d374, 0x57ffffe3},
+ {0x0000d378, 0x5fffffe2},
+ {0x0000d37c, 0x7fffffe2},
+ {0x0000d380, 0x7f3c7bba},
+ {0x0000d384, 0xf3307ff0},
+ {0x0000a388, 0x0c000000},
+ {0x0000a38c, 0x20202020},
+ {0x0000a390, 0x20202020},
+ {0x0000a394, 0x1ce739ce},
+ {0x0000a398, 0x000001ce},
+ {0x0000a39c, 0x00000001},
+ {0x0000a3a0, 0x00000000},
+ {0x0000a3a4, 0x00000000},
+ {0x0000a3a8, 0x00000000},
+ {0x0000a3ac, 0x00000000},
+ {0x0000a3b0, 0x00000000},
+ {0x0000a3b4, 0x00000000},
+ {0x0000a3b8, 0x00000000},
+ {0x0000a3bc, 0x00000000},
+ {0x0000a3c0, 0x00000000},
+ {0x0000a3c4, 0x00000000},
+ {0x0000a3c8, 0x00000246},
+ {0x0000a3cc, 0x20202020},
+ {0x0000a3d0, 0x20202020},
+ {0x0000a3d4, 0x20202020},
+ {0x0000a3dc, 0x1ce739ce},
+ {0x0000a3e0, 0x000001ce},
};
static const u32 ar5416Bank0_9100[][2] = {
- { 0x000098b0, 0x1e5795e5 },
- { 0x000098e0, 0x02008020 },
+ /* Addr allmodes */
+ {0x000098b0, 0x1e5795e5},
+ {0x000098e0, 0x02008020},
};
static const u32 ar5416BB_RfGain_9100[][3] = {
- { 0x00009a00, 0x00000000, 0x00000000 },
- { 0x00009a04, 0x00000040, 0x00000040 },
- { 0x00009a08, 0x00000080, 0x00000080 },
- { 0x00009a0c, 0x000001a1, 0x00000141 },
- { 0x00009a10, 0x000001e1, 0x00000181 },
- { 0x00009a14, 0x00000021, 0x000001c1 },
- { 0x00009a18, 0x00000061, 0x00000001 },
- { 0x00009a1c, 0x00000168, 0x00000041 },
- { 0x00009a20, 0x000001a8, 0x000001a8 },
- { 0x00009a24, 0x000001e8, 0x000001e8 },
- { 0x00009a28, 0x00000028, 0x00000028 },
- { 0x00009a2c, 0x00000068, 0x00000068 },
- { 0x00009a30, 0x00000189, 0x000000a8 },
- { 0x00009a34, 0x000001c9, 0x00000169 },
- { 0x00009a38, 0x00000009, 0x000001a9 },
- { 0x00009a3c, 0x00000049, 0x000001e9 },
- { 0x00009a40, 0x00000089, 0x00000029 },
- { 0x00009a44, 0x00000170, 0x00000069 },
- { 0x00009a48, 0x000001b0, 0x00000190 },
- { 0x00009a4c, 0x000001f0, 0x000001d0 },
- { 0x00009a50, 0x00000030, 0x00000010 },
- { 0x00009a54, 0x00000070, 0x00000050 },
- { 0x00009a58, 0x00000191, 0x00000090 },
- { 0x00009a5c, 0x000001d1, 0x00000151 },
- { 0x00009a60, 0x00000011, 0x00000191 },
- { 0x00009a64, 0x00000051, 0x000001d1 },
- { 0x00009a68, 0x00000091, 0x00000011 },
- { 0x00009a6c, 0x000001b8, 0x00000051 },
- { 0x00009a70, 0x000001f8, 0x00000198 },
- { 0x00009a74, 0x00000038, 0x000001d8 },
- { 0x00009a78, 0x00000078, 0x00000018 },
- { 0x00009a7c, 0x00000199, 0x00000058 },
- { 0x00009a80, 0x000001d9, 0x00000098 },
- { 0x00009a84, 0x00000019, 0x00000159 },
- { 0x00009a88, 0x00000059, 0x00000199 },
- { 0x00009a8c, 0x00000099, 0x000001d9 },
- { 0x00009a90, 0x000000d9, 0x00000019 },
- { 0x00009a94, 0x000000f9, 0x00000059 },
- { 0x00009a98, 0x000000f9, 0x00000099 },
- { 0x00009a9c, 0x000000f9, 0x000000d9 },
- { 0x00009aa0, 0x000000f9, 0x000000f9 },
- { 0x00009aa4, 0x000000f9, 0x000000f9 },
- { 0x00009aa8, 0x000000f9, 0x000000f9 },
- { 0x00009aac, 0x000000f9, 0x000000f9 },
- { 0x00009ab0, 0x000000f9, 0x000000f9 },
- { 0x00009ab4, 0x000000f9, 0x000000f9 },
- { 0x00009ab8, 0x000000f9, 0x000000f9 },
- { 0x00009abc, 0x000000f9, 0x000000f9 },
- { 0x00009ac0, 0x000000f9, 0x000000f9 },
- { 0x00009ac4, 0x000000f9, 0x000000f9 },
- { 0x00009ac8, 0x000000f9, 0x000000f9 },
- { 0x00009acc, 0x000000f9, 0x000000f9 },
- { 0x00009ad0, 0x000000f9, 0x000000f9 },
- { 0x00009ad4, 0x000000f9, 0x000000f9 },
- { 0x00009ad8, 0x000000f9, 0x000000f9 },
- { 0x00009adc, 0x000000f9, 0x000000f9 },
- { 0x00009ae0, 0x000000f9, 0x000000f9 },
- { 0x00009ae4, 0x000000f9, 0x000000f9 },
- { 0x00009ae8, 0x000000f9, 0x000000f9 },
- { 0x00009aec, 0x000000f9, 0x000000f9 },
- { 0x00009af0, 0x000000f9, 0x000000f9 },
- { 0x00009af4, 0x000000f9, 0x000000f9 },
- { 0x00009af8, 0x000000f9, 0x000000f9 },
- { 0x00009afc, 0x000000f9, 0x000000f9 },
+ /* Addr 5G_HT20 5G_HT40 */
+ {0x00009a00, 0x00000000, 0x00000000},
+ {0x00009a04, 0x00000040, 0x00000040},
+ {0x00009a08, 0x00000080, 0x00000080},
+ {0x00009a0c, 0x000001a1, 0x00000141},
+ {0x00009a10, 0x000001e1, 0x00000181},
+ {0x00009a14, 0x00000021, 0x000001c1},
+ {0x00009a18, 0x00000061, 0x00000001},
+ {0x00009a1c, 0x00000168, 0x00000041},
+ {0x00009a20, 0x000001a8, 0x000001a8},
+ {0x00009a24, 0x000001e8, 0x000001e8},
+ {0x00009a28, 0x00000028, 0x00000028},
+ {0x00009a2c, 0x00000068, 0x00000068},
+ {0x00009a30, 0x00000189, 0x000000a8},
+ {0x00009a34, 0x000001c9, 0x00000169},
+ {0x00009a38, 0x00000009, 0x000001a9},
+ {0x00009a3c, 0x00000049, 0x000001e9},
+ {0x00009a40, 0x00000089, 0x00000029},
+ {0x00009a44, 0x00000170, 0x00000069},
+ {0x00009a48, 0x000001b0, 0x00000190},
+ {0x00009a4c, 0x000001f0, 0x000001d0},
+ {0x00009a50, 0x00000030, 0x00000010},
+ {0x00009a54, 0x00000070, 0x00000050},
+ {0x00009a58, 0x00000191, 0x00000090},
+ {0x00009a5c, 0x000001d1, 0x00000151},
+ {0x00009a60, 0x00000011, 0x00000191},
+ {0x00009a64, 0x00000051, 0x000001d1},
+ {0x00009a68, 0x00000091, 0x00000011},
+ {0x00009a6c, 0x000001b8, 0x00000051},
+ {0x00009a70, 0x000001f8, 0x00000198},
+ {0x00009a74, 0x00000038, 0x000001d8},
+ {0x00009a78, 0x00000078, 0x00000018},
+ {0x00009a7c, 0x00000199, 0x00000058},
+ {0x00009a80, 0x000001d9, 0x00000098},
+ {0x00009a84, 0x00000019, 0x00000159},
+ {0x00009a88, 0x00000059, 0x00000199},
+ {0x00009a8c, 0x00000099, 0x000001d9},
+ {0x00009a90, 0x000000d9, 0x00000019},
+ {0x00009a94, 0x000000f9, 0x00000059},
+ {0x00009a98, 0x000000f9, 0x00000099},
+ {0x00009a9c, 0x000000f9, 0x000000d9},
+ {0x00009aa0, 0x000000f9, 0x000000f9},
+ {0x00009aa4, 0x000000f9, 0x000000f9},
+ {0x00009aa8, 0x000000f9, 0x000000f9},
+ {0x00009aac, 0x000000f9, 0x000000f9},
+ {0x00009ab0, 0x000000f9, 0x000000f9},
+ {0x00009ab4, 0x000000f9, 0x000000f9},
+ {0x00009ab8, 0x000000f9, 0x000000f9},
+ {0x00009abc, 0x000000f9, 0x000000f9},
+ {0x00009ac0, 0x000000f9, 0x000000f9},
+ {0x00009ac4, 0x000000f9, 0x000000f9},
+ {0x00009ac8, 0x000000f9, 0x000000f9},
+ {0x00009acc, 0x000000f9, 0x000000f9},
+ {0x00009ad0, 0x000000f9, 0x000000f9},
+ {0x00009ad4, 0x000000f9, 0x000000f9},
+ {0x00009ad8, 0x000000f9, 0x000000f9},
+ {0x00009adc, 0x000000f9, 0x000000f9},
+ {0x00009ae0, 0x000000f9, 0x000000f9},
+ {0x00009ae4, 0x000000f9, 0x000000f9},
+ {0x00009ae8, 0x000000f9, 0x000000f9},
+ {0x00009aec, 0x000000f9, 0x000000f9},
+ {0x00009af0, 0x000000f9, 0x000000f9},
+ {0x00009af4, 0x000000f9, 0x000000f9},
+ {0x00009af8, 0x000000f9, 0x000000f9},
+ {0x00009afc, 0x000000f9, 0x000000f9},
};
static const u32 ar5416Bank1_9100[][2] = {
- { 0x000098b0, 0x02108421},
- { 0x000098ec, 0x00000008},
+ /* Addr allmodes */
+ {0x000098b0, 0x02108421},
+ {0x000098ec, 0x00000008},
};
static const u32 ar5416Bank2_9100[][2] = {
- { 0x000098b0, 0x0e73ff17},
- { 0x000098e0, 0x00000420},
+ /* Addr allmodes */
+ {0x000098b0, 0x0e73ff17},
+ {0x000098e0, 0x00000420},
};
static const u32 ar5416Bank3_9100[][3] = {
- { 0x000098f0, 0x01400018, 0x01c00018 },
+ /* Addr 5G_HT20 5G_HT40 */
+ {0x000098f0, 0x01400018, 0x01c00018},
};
static const u32 ar5416Bank6_9100[][3] = {
-
- { 0x0000989c, 0x00000000, 0x00000000 },
- { 0x0000989c, 0x00000000, 0x00000000 },
- { 0x0000989c, 0x00000000, 0x00000000 },
- { 0x0000989c, 0x00e00000, 0x00e00000 },
- { 0x0000989c, 0x005e0000, 0x005e0000 },
- { 0x0000989c, 0x00120000, 0x00120000 },
- { 0x0000989c, 0x00620000, 0x00620000 },
- { 0x0000989c, 0x00020000, 0x00020000 },
- { 0x0000989c, 0x00ff0000, 0x00ff0000 },
- { 0x0000989c, 0x00ff0000, 0x00ff0000 },
- { 0x0000989c, 0x00ff0000, 0x00ff0000 },
- { 0x0000989c, 0x00ff0000, 0x00ff0000 },
- { 0x0000989c, 0x005f0000, 0x005f0000 },
- { 0x0000989c, 0x00870000, 0x00870000 },
- { 0x0000989c, 0x00f90000, 0x00f90000 },
- { 0x0000989c, 0x007b0000, 0x007b0000 },
- { 0x0000989c, 0x00ff0000, 0x00ff0000 },
- { 0x0000989c, 0x00f50000, 0x00f50000 },
- { 0x0000989c, 0x00dc0000, 0x00dc0000 },
- { 0x0000989c, 0x00110000, 0x00110000 },
- { 0x0000989c, 0x006100a8, 0x006100a8 },
- { 0x0000989c, 0x004210a2, 0x004210a2 },
- { 0x0000989c, 0x0014000f, 0x0014000f },
- { 0x0000989c, 0x00c40002, 0x00c40002 },
- { 0x0000989c, 0x003000f2, 0x003000f2 },
- { 0x0000989c, 0x00440016, 0x00440016 },
- { 0x0000989c, 0x00410040, 0x00410040 },
- { 0x0000989c, 0x000180d6, 0x000180d6 },
- { 0x0000989c, 0x0000c0aa, 0x0000c0aa },
- { 0x0000989c, 0x000000b1, 0x000000b1 },
- { 0x0000989c, 0x00002000, 0x00002000 },
- { 0x0000989c, 0x000000d4, 0x000000d4 },
- { 0x000098d0, 0x0000000f, 0x0010000f },
+ /* Addr 5G_HT20 5G_HT40 */
+ {0x0000989c, 0x00000000, 0x00000000},
+ {0x0000989c, 0x00000000, 0x00000000},
+ {0x0000989c, 0x00000000, 0x00000000},
+ {0x0000989c, 0x00e00000, 0x00e00000},
+ {0x0000989c, 0x005e0000, 0x005e0000},
+ {0x0000989c, 0x00120000, 0x00120000},
+ {0x0000989c, 0x00620000, 0x00620000},
+ {0x0000989c, 0x00020000, 0x00020000},
+ {0x0000989c, 0x00ff0000, 0x00ff0000},
+ {0x0000989c, 0x00ff0000, 0x00ff0000},
+ {0x0000989c, 0x00ff0000, 0x00ff0000},
+ {0x0000989c, 0x00ff0000, 0x00ff0000},
+ {0x0000989c, 0x005f0000, 0x005f0000},
+ {0x0000989c, 0x00870000, 0x00870000},
+ {0x0000989c, 0x00f90000, 0x00f90000},
+ {0x0000989c, 0x007b0000, 0x007b0000},
+ {0x0000989c, 0x00ff0000, 0x00ff0000},
+ {0x0000989c, 0x00f50000, 0x00f50000},
+ {0x0000989c, 0x00dc0000, 0x00dc0000},
+ {0x0000989c, 0x00110000, 0x00110000},
+ {0x0000989c, 0x006100a8, 0x006100a8},
+ {0x0000989c, 0x004210a2, 0x004210a2},
+ {0x0000989c, 0x0014000f, 0x0014000f},
+ {0x0000989c, 0x00c40002, 0x00c40002},
+ {0x0000989c, 0x003000f2, 0x003000f2},
+ {0x0000989c, 0x00440016, 0x00440016},
+ {0x0000989c, 0x00410040, 0x00410040},
+ {0x0000989c, 0x000180d6, 0x000180d6},
+ {0x0000989c, 0x0000c0aa, 0x0000c0aa},
+ {0x0000989c, 0x000000b1, 0x000000b1},
+ {0x0000989c, 0x00002000, 0x00002000},
+ {0x0000989c, 0x000000d4, 0x000000d4},
+ {0x000098d0, 0x0000000f, 0x0010000f},
};
-
static const u32 ar5416Bank6TPC_9100[][3] = {
-
- { 0x0000989c, 0x00000000, 0x00000000 },
- { 0x0000989c, 0x00000000, 0x00000000 },
- { 0x0000989c, 0x00000000, 0x00000000 },
- { 0x0000989c, 0x00e00000, 0x00e00000 },
- { 0x0000989c, 0x005e0000, 0x005e0000 },
- { 0x0000989c, 0x00120000, 0x00120000 },
- { 0x0000989c, 0x00620000, 0x00620000 },
- { 0x0000989c, 0x00020000, 0x00020000 },
- { 0x0000989c, 0x00ff0000, 0x00ff0000 },
- { 0x0000989c, 0x00ff0000, 0x00ff0000 },
- { 0x0000989c, 0x00ff0000, 0x00ff0000 },
- { 0x0000989c, 0x40ff0000, 0x40ff0000 },
- { 0x0000989c, 0x005f0000, 0x005f0000 },
- { 0x0000989c, 0x00870000, 0x00870000 },
- { 0x0000989c, 0x00f90000, 0x00f90000 },
- { 0x0000989c, 0x007b0000, 0x007b0000 },
- { 0x0000989c, 0x00ff0000, 0x00ff0000 },
- { 0x0000989c, 0x00f50000, 0x00f50000 },
- { 0x0000989c, 0x00dc0000, 0x00dc0000 },
- { 0x0000989c, 0x00110000, 0x00110000 },
- { 0x0000989c, 0x006100a8, 0x006100a8 },
- { 0x0000989c, 0x00423022, 0x00423022 },
- { 0x0000989c, 0x2014008f, 0x2014008f },
- { 0x0000989c, 0x00c40002, 0x00c40002 },
- { 0x0000989c, 0x003000f2, 0x003000f2 },
- { 0x0000989c, 0x00440016, 0x00440016 },
- { 0x0000989c, 0x00410040, 0x00410040 },
- { 0x0000989c, 0x0001805e, 0x0001805e },
- { 0x0000989c, 0x0000c0ab, 0x0000c0ab },
- { 0x0000989c, 0x000000e1, 0x000000e1 },
- { 0x0000989c, 0x00007080, 0x00007080 },
- { 0x0000989c, 0x000000d4, 0x000000d4 },
- { 0x000098d0, 0x0000000f, 0x0010000f },
+ /* Addr 5G_HT20 5G_HT40 */
+ {0x0000989c, 0x00000000, 0x00000000},
+ {0x0000989c, 0x00000000, 0x00000000},
+ {0x0000989c, 0x00000000, 0x00000000},
+ {0x0000989c, 0x00e00000, 0x00e00000},
+ {0x0000989c, 0x005e0000, 0x005e0000},
+ {0x0000989c, 0x00120000, 0x00120000},
+ {0x0000989c, 0x00620000, 0x00620000},
+ {0x0000989c, 0x00020000, 0x00020000},
+ {0x0000989c, 0x00ff0000, 0x00ff0000},
+ {0x0000989c, 0x00ff0000, 0x00ff0000},
+ {0x0000989c, 0x00ff0000, 0x00ff0000},
+ {0x0000989c, 0x40ff0000, 0x40ff0000},
+ {0x0000989c, 0x005f0000, 0x005f0000},
+ {0x0000989c, 0x00870000, 0x00870000},
+ {0x0000989c, 0x00f90000, 0x00f90000},
+ {0x0000989c, 0x007b0000, 0x007b0000},
+ {0x0000989c, 0x00ff0000, 0x00ff0000},
+ {0x0000989c, 0x00f50000, 0x00f50000},
+ {0x0000989c, 0x00dc0000, 0x00dc0000},
+ {0x0000989c, 0x00110000, 0x00110000},
+ {0x0000989c, 0x006100a8, 0x006100a8},
+ {0x0000989c, 0x00423022, 0x00423022},
+ {0x0000989c, 0x2014008f, 0x2014008f},
+ {0x0000989c, 0x00c40002, 0x00c40002},
+ {0x0000989c, 0x003000f2, 0x003000f2},
+ {0x0000989c, 0x00440016, 0x00440016},
+ {0x0000989c, 0x00410040, 0x00410040},
+ {0x0000989c, 0x0001805e, 0x0001805e},
+ {0x0000989c, 0x0000c0ab, 0x0000c0ab},
+ {0x0000989c, 0x000000e1, 0x000000e1},
+ {0x0000989c, 0x00007080, 0x00007080},
+ {0x0000989c, 0x000000d4, 0x000000d4},
+ {0x000098d0, 0x0000000f, 0x0010000f},
};
static const u32 ar5416Bank7_9100[][2] = {
- { 0x0000989c, 0x00000500 },
- { 0x0000989c, 0x00000800 },
- { 0x000098cc, 0x0000000e },
+ /* Addr allmodes */
+ {0x0000989c, 0x00000500},
+ {0x0000989c, 0x00000800},
+ {0x000098cc, 0x0000000e},
};
static const u32 ar5416Addac_9100[][2] = {
- {0x0000989c, 0x00000000 },
- {0x0000989c, 0x00000000 },
- {0x0000989c, 0x00000000 },
- {0x0000989c, 0x00000000 },
- {0x0000989c, 0x00000000 },
- {0x0000989c, 0x00000000 },
- {0x0000989c, 0x00000000 },
- {0x0000989c, 0x00000010 },
- {0x0000989c, 0x00000000 },
- {0x0000989c, 0x00000000 },
- {0x0000989c, 0x00000000 },
- {0x0000989c, 0x00000000 },
- {0x0000989c, 0x00000000 },
- {0x0000989c, 0x00000000 },
- {0x0000989c, 0x00000000 },
- {0x0000989c, 0x00000000 },
- {0x0000989c, 0x00000000 },
- {0x0000989c, 0x00000000 },
- {0x0000989c, 0x00000000 },
- {0x0000989c, 0x00000000 },
- {0x0000989c, 0x00000000 },
- {0x0000989c, 0x000000c0 },
- {0x0000989c, 0x00000015 },
- {0x0000989c, 0x00000000 },
- {0x0000989c, 0x00000000 },
- {0x0000989c, 0x00000000 },
- {0x0000989c, 0x00000000 },
- {0x0000989c, 0x00000000 },
- {0x0000989c, 0x00000000 },
- {0x0000989c, 0x00000000 },
- {0x0000989c, 0x00000000 },
- {0x000098cc, 0x00000000 },
+ /* Addr allmodes */
+ {0x0000989c, 0x00000000},
+ {0x0000989c, 0x00000000},
+ {0x0000989c, 0x00000000},
+ {0x0000989c, 0x00000000},
+ {0x0000989c, 0x00000000},
+ {0x0000989c, 0x00000000},
+ {0x0000989c, 0x00000000},
+ {0x0000989c, 0x00000010},
+ {0x0000989c, 0x00000000},
+ {0x0000989c, 0x00000000},
+ {0x0000989c, 0x00000000},
+ {0x0000989c, 0x00000000},
+ {0x0000989c, 0x00000000},
+ {0x0000989c, 0x00000000},
+ {0x0000989c, 0x00000000},
+ {0x0000989c, 0x00000000},
+ {0x0000989c, 0x00000000},
+ {0x0000989c, 0x00000000},
+ {0x0000989c, 0x00000000},
+ {0x0000989c, 0x00000000},
+ {0x0000989c, 0x00000000},
+ {0x0000989c, 0x000000c0},
+ {0x0000989c, 0x00000015},
+ {0x0000989c, 0x00000000},
+ {0x0000989c, 0x00000000},
+ {0x0000989c, 0x00000000},
+ {0x0000989c, 0x00000000},
+ {0x0000989c, 0x00000000},
+ {0x0000989c, 0x00000000},
+ {0x0000989c, 0x00000000},
+ {0x0000989c, 0x00000000},
+ {0x000098cc, 0x00000000},
};
static const u32 ar5416Modes_9160[][6] = {
- { 0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160, 0x000001e0 },
- { 0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c, 0x000001e0 },
- { 0x000010b0, 0x00000e60, 0x00001cc0, 0x00007c70, 0x00003e38, 0x00001180 },
- { 0x000010f0, 0x0000a000, 0x00014000, 0x00016000, 0x0000b000, 0x00014008 },
- { 0x00008014, 0x03e803e8, 0x07d007d0, 0x10801600, 0x08400b00, 0x06e006e0 },
- { 0x0000801c, 0x128d93a7, 0x128d93cf, 0x12e013d7, 0x12e013ab, 0x098813cf },
- { 0x00009804, 0x00000300, 0x000003c4, 0x000003c4, 0x00000300, 0x00000303 },
- { 0x00009820, 0x02020200, 0x02020200, 0x02020200, 0x02020200, 0x02020200 },
- { 0x00009824, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e },
- { 0x00009828, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001 },
- { 0x00009834, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e },
- { 0x00009838, 0x00000007, 0x00000007, 0x00000007, 0x00000007, 0x00000007 },
- { 0x00009844, 0x0372161e, 0x0372161e, 0x037216a0, 0x037216a0, 0x037216a0 },
- { 0x00009848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68 },
- { 0x0000a848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68 },
- { 0x0000b848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68 },
- { 0x00009850, 0x6c48b4e2, 0x6c48b4e2, 0x6c48b0e2, 0x6c48b0e2, 0x6c48b0e2 },
- { 0x00009858, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e },
- { 0x0000985c, 0x31395d5e, 0x31395d5e, 0x31395d5e, 0x31395d5e, 0x31395d5e },
- { 0x00009860, 0x00048d18, 0x00048d18, 0x00048d20, 0x00048d20, 0x00048d18 },
- { 0x0000c864, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00 },
- { 0x00009868, 0x409a40d0, 0x409a40d0, 0x409a40d0, 0x409a40d0, 0x409a40d0 },
- { 0x0000986c, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081 },
- { 0x00009914, 0x000007d0, 0x00000fa0, 0x00001130, 0x00000898, 0x000007d0 },
- { 0x00009918, 0x0000000a, 0x00000014, 0x00000016, 0x0000000b, 0x00000016 },
- { 0x00009924, 0xd00a8a07, 0xd00a8a07, 0xd00a8a0d, 0xd00a8a0d, 0xd00a8a0d },
- { 0x00009944, 0xffb81020, 0xffb81020, 0xffb81020, 0xffb81020, 0xffb81020 },
- { 0x00009960, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40 },
- { 0x0000a960, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40 },
- { 0x0000b960, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40 },
- { 0x00009964, 0x00001120, 0x00001120, 0x00001120, 0x00001120, 0x00001120 },
- { 0x0000c968, 0x000003b5, 0x000003b5, 0x000003ce, 0x000003ce, 0x000003ce },
- { 0x0000c9bc, 0x001a0600, 0x001a0600, 0x001a0c00, 0x001a0c00, 0x001a0c00 },
- { 0x000099c0, 0x038919be, 0x038919be, 0x038919be, 0x038919be, 0x038919be },
- { 0x000099c4, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77 },
- { 0x000099c8, 0x60f65329, 0x60f65329, 0x60f65329, 0x60f65329, 0x60f65329 },
- { 0x000099cc, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8 },
- { 0x000099d0, 0x00046384, 0x00046384, 0x00046384, 0x00046384, 0x00046384 },
- { 0x000099d4, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
- { 0x000099d8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
- { 0x0000a204, 0x00000880, 0x00000880, 0x00000880, 0x00000880, 0x00000880 },
- { 0x0000a208, 0xd6be4788, 0xd6be4788, 0xd03e4788, 0xd03e4788, 0xd03e4788 },
- { 0x0000a20c, 0x002fc160, 0x002fc160, 0x002ac120, 0x002ac120, 0x002ac120 },
- { 0x0000b20c, 0x002fc160, 0x002fc160, 0x002ac120, 0x002ac120, 0x002ac120 },
- { 0x0000c20c, 0x002fc160, 0x002fc160, 0x002ac120, 0x002ac120, 0x002ac120 },
- { 0x0000a21c, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a },
- { 0x0000a230, 0x00000000, 0x00000000, 0x00000210, 0x00000108, 0x00000000 },
- { 0x0000a274, 0x0a1a9caa, 0x0a1a9caa, 0x0a1a7caa, 0x0a1a7caa, 0x0a1a7caa },
- { 0x0000a300, 0x18010000, 0x18010000, 0x18010000, 0x18010000, 0x18010000 },
- { 0x0000a304, 0x30032602, 0x30032602, 0x2e032402, 0x2e032402, 0x2e032402 },
- { 0x0000a308, 0x48073e06, 0x48073e06, 0x4a0a3c06, 0x4a0a3c06, 0x4a0a3c06 },
- { 0x0000a30c, 0x560b4c0a, 0x560b4c0a, 0x621a540b, 0x621a540b, 0x621a540b },
- { 0x0000a310, 0x641a600f, 0x641a600f, 0x764f6c1b, 0x764f6c1b, 0x764f6c1b },
- { 0x0000a314, 0x7a4f6e1b, 0x7a4f6e1b, 0x845b7a5a, 0x845b7a5a, 0x845b7a5a },
- { 0x0000a318, 0x8c5b7e5a, 0x8c5b7e5a, 0x950f8ccf, 0x950f8ccf, 0x950f8ccf },
- { 0x0000a31c, 0x9d0f96cf, 0x9d0f96cf, 0xa5cf9b4f, 0xa5cf9b4f, 0xa5cf9b4f },
- { 0x0000a320, 0xb51fa69f, 0xb51fa69f, 0xbddfaf1f, 0xbddfaf1f, 0xbddfaf1f },
- { 0x0000a324, 0xcb3fbd07, 0xcb3fbcbf, 0xd1ffc93f, 0xd1ffc93f, 0xd1ffc93f },
- { 0x0000a328, 0x0000d7bf, 0x0000d7bf, 0x00000000, 0x00000000, 0x00000000 },
- { 0x0000a32c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
- { 0x0000a330, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
- { 0x0000a334, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
+ {0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160, 0x000001e0},
+ {0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c, 0x000001e0},
+ {0x000010b0, 0x00000e60, 0x00001cc0, 0x00007c70, 0x00003e38, 0x00001180},
+ {0x000010f0, 0x0000a000, 0x00014000, 0x00016000, 0x0000b000, 0x00014008},
+ {0x00008014, 0x03e803e8, 0x07d007d0, 0x10801600, 0x08400b00, 0x06e006e0},
+ {0x0000801c, 0x128d93a7, 0x128d93cf, 0x12e013d7, 0x12e013ab, 0x098813cf},
+ {0x00008120, 0x08f04800, 0x08f04800, 0x08f04810, 0x08f04810, 0x08f04810},
+ {0x000081d0, 0x00003210, 0x00003210, 0x0000320a, 0x0000320a, 0x0000320a},
+ {0x00009804, 0x00000300, 0x000003c4, 0x000003c4, 0x00000300, 0x00000303},
+ {0x00009820, 0x02020200, 0x02020200, 0x02020200, 0x02020200, 0x02020200},
+ {0x00009824, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e},
+ {0x00009828, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001},
+ {0x00009834, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e},
+ {0x00009838, 0x00000007, 0x00000007, 0x00000007, 0x00000007, 0x00000007},
+ {0x00009844, 0x0372161e, 0x0372161e, 0x037216a0, 0x037216a0, 0x037216a0},
+ {0x00009848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68},
+ {0x0000a848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68},
+ {0x0000b848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68},
+ {0x00009850, 0x6c48b4e2, 0x6d48b4e2, 0x6d48b0e2, 0x6c48b0e2, 0x6c48b0e2},
+ {0x00009858, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e},
+ {0x0000985c, 0x31395d5e, 0x3139605e, 0x3139605e, 0x31395d5e, 0x31395d5e},
+ {0x00009860, 0x00048d18, 0x00048d18, 0x00048d20, 0x00048d20, 0x00048d18},
+ {0x00009864, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00},
+ {0x00009868, 0x409a40d0, 0x409a40d0, 0x409a40d0, 0x409a40d0, 0x409a40d0},
+ {0x0000986c, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081},
+ {0x00009914, 0x000007d0, 0x00000fa0, 0x00001130, 0x00000898, 0x000007d0},
+ {0x00009918, 0x0000000a, 0x00000014, 0x00000016, 0x0000000b, 0x00000016},
+ {0x00009924, 0xd00a8a07, 0xd00a8a07, 0xd00a8a0d, 0xd00a8a0d, 0xd00a8a0d},
+ {0x00009944, 0xffb81020, 0xffb81020, 0xffb81020, 0xffb81020, 0xffb81020},
+ {0x00009960, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40},
+ {0x0000a960, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40},
+ {0x0000b960, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40},
+ {0x00009964, 0x00001120, 0x00001120, 0x00001120, 0x00001120, 0x00001120},
+ {0x0000c968, 0x000003b5, 0x000003b5, 0x000003ce, 0x000003ce, 0x000003ce},
+ {0x000099bc, 0x001a0600, 0x001a0600, 0x001a0c00, 0x001a0c00, 0x001a0c00},
+ {0x000099c0, 0x038919be, 0x038919be, 0x038919be, 0x038919be, 0x038919be},
+ {0x000099c4, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77},
+ {0x000099c8, 0x6af65329, 0x6af65329, 0x6af65329, 0x6af65329, 0x6af65329},
+ {0x000099cc, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8},
+ {0x000099d0, 0x00046384, 0x00046384, 0x00046384, 0x00046384, 0x00046384},
+ {0x000099d4, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+ {0x000099d8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+ {0x0000a204, 0x00000880, 0x00000880, 0x00000880, 0x00000880, 0x00000880},
+ {0x0000a208, 0xd6be4788, 0xd6be4788, 0xd03e4788, 0xd03e4788, 0xd03e4788},
+ {0x0000a20c, 0x002fc160, 0x002fc160, 0x002ac120, 0x002ac120, 0x002ac120},
+ {0x0000b20c, 0x002fc160, 0x002fc160, 0x002ac120, 0x002ac120, 0x002ac120},
+ {0x0000c20c, 0x002fc160, 0x002fc160, 0x002ac120, 0x002ac120, 0x002ac120},
+ {0x0000a21c, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a},
+ {0x0000a230, 0x00000000, 0x00000000, 0x00000210, 0x00000108, 0x00000000},
+ {0x0000a274, 0x0a1a9caa, 0x0a1a9caa, 0x0a1a7caa, 0x0a1a7caa, 0x0a1a7caa},
+ {0x0000a300, 0x18010000, 0x18010000, 0x18010000, 0x18010000, 0x18010000},
+ {0x0000a304, 0x30032602, 0x30032602, 0x2e032402, 0x2e032402, 0x2e032402},
+ {0x0000a308, 0x48073e06, 0x48073e06, 0x4a0a3c06, 0x4a0a3c06, 0x4a0a3c06},
+ {0x0000a30c, 0x560b4c0a, 0x560b4c0a, 0x621a540b, 0x621a540b, 0x621a540b},
+ {0x0000a310, 0x641a600f, 0x641a600f, 0x764f6c1b, 0x764f6c1b, 0x764f6c1b},
+ {0x0000a314, 0x7a4f6e1b, 0x7a4f6e1b, 0x845b7a5a, 0x845b7a5a, 0x845b7a5a},
+ {0x0000a318, 0x8c5b7e5a, 0x8c5b7e5a, 0x950f8ccf, 0x950f8ccf, 0x950f8ccf},
+ {0x0000a31c, 0x9d0f96cf, 0x9d0f96cf, 0xa5cf9b4f, 0xa5cf9b4f, 0xa5cf9b4f},
+ {0x0000a320, 0xb51fa69f, 0xb51fa69f, 0xbddfaf1f, 0xbddfaf1f, 0xbddfaf1f},
+ {0x0000a324, 0xcb3fbd07, 0xcb3fbcbf, 0xd1ffc93f, 0xd1ffc93f, 0xd1ffc93f},
+ {0x0000a328, 0x0000d7bf, 0x0000d7bf, 0x00000000, 0x00000000, 0x00000000},
+ {0x0000a32c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+ {0x0000a330, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+ {0x0000a334, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
};
static const u32 ar5416Common_9160[][2] = {
- { 0x0000000c, 0x00000000 },
- { 0x00000030, 0x00020015 },
- { 0x00000034, 0x00000005 },
- { 0x00000040, 0x00000000 },
- { 0x00000044, 0x00000008 },
- { 0x00000048, 0x00000008 },
- { 0x0000004c, 0x00000010 },
- { 0x00000050, 0x00000000 },
- { 0x00000054, 0x0000001f },
- { 0x00000800, 0x00000000 },
- { 0x00000804, 0x00000000 },
- { 0x00000808, 0x00000000 },
- { 0x0000080c, 0x00000000 },
- { 0x00000810, 0x00000000 },
- { 0x00000814, 0x00000000 },
- { 0x00000818, 0x00000000 },
- { 0x0000081c, 0x00000000 },
- { 0x00000820, 0x00000000 },
- { 0x00000824, 0x00000000 },
- { 0x00001040, 0x002ffc0f },
- { 0x00001044, 0x002ffc0f },
- { 0x00001048, 0x002ffc0f },
- { 0x0000104c, 0x002ffc0f },
- { 0x00001050, 0x002ffc0f },
- { 0x00001054, 0x002ffc0f },
- { 0x00001058, 0x002ffc0f },
- { 0x0000105c, 0x002ffc0f },
- { 0x00001060, 0x002ffc0f },
- { 0x00001064, 0x002ffc0f },
- { 0x00001230, 0x00000000 },
- { 0x00001270, 0x00000000 },
- { 0x00001038, 0x00000000 },
- { 0x00001078, 0x00000000 },
- { 0x000010b8, 0x00000000 },
- { 0x000010f8, 0x00000000 },
- { 0x00001138, 0x00000000 },
- { 0x00001178, 0x00000000 },
- { 0x000011b8, 0x00000000 },
- { 0x000011f8, 0x00000000 },
- { 0x00001238, 0x00000000 },
- { 0x00001278, 0x00000000 },
- { 0x000012b8, 0x00000000 },
- { 0x000012f8, 0x00000000 },
- { 0x00001338, 0x00000000 },
- { 0x00001378, 0x00000000 },
- { 0x000013b8, 0x00000000 },
- { 0x000013f8, 0x00000000 },
- { 0x00001438, 0x00000000 },
- { 0x00001478, 0x00000000 },
- { 0x000014b8, 0x00000000 },
- { 0x000014f8, 0x00000000 },
- { 0x00001538, 0x00000000 },
- { 0x00001578, 0x00000000 },
- { 0x000015b8, 0x00000000 },
- { 0x000015f8, 0x00000000 },
- { 0x00001638, 0x00000000 },
- { 0x00001678, 0x00000000 },
- { 0x000016b8, 0x00000000 },
- { 0x000016f8, 0x00000000 },
- { 0x00001738, 0x00000000 },
- { 0x00001778, 0x00000000 },
- { 0x000017b8, 0x00000000 },
- { 0x000017f8, 0x00000000 },
- { 0x0000103c, 0x00000000 },
- { 0x0000107c, 0x00000000 },
- { 0x000010bc, 0x00000000 },
- { 0x000010fc, 0x00000000 },
- { 0x0000113c, 0x00000000 },
- { 0x0000117c, 0x00000000 },
- { 0x000011bc, 0x00000000 },
- { 0x000011fc, 0x00000000 },
- { 0x0000123c, 0x00000000 },
- { 0x0000127c, 0x00000000 },
- { 0x000012bc, 0x00000000 },
- { 0x000012fc, 0x00000000 },
- { 0x0000133c, 0x00000000 },
- { 0x0000137c, 0x00000000 },
- { 0x000013bc, 0x00000000 },
- { 0x000013fc, 0x00000000 },
- { 0x0000143c, 0x00000000 },
- { 0x0000147c, 0x00000000 },
- { 0x00004030, 0x00000002 },
- { 0x0000403c, 0x00000002 },
- { 0x00007010, 0x00000020 },
- { 0x00007038, 0x000004c2 },
- { 0x00008004, 0x00000000 },
- { 0x00008008, 0x00000000 },
- { 0x0000800c, 0x00000000 },
- { 0x00008018, 0x00000700 },
- { 0x00008020, 0x00000000 },
- { 0x00008038, 0x00000000 },
- { 0x0000803c, 0x00000000 },
- { 0x00008048, 0x40000000 },
- { 0x00008054, 0x00000000 },
- { 0x00008058, 0x00000000 },
- { 0x0000805c, 0x000fc78f },
- { 0x00008060, 0x0000000f },
- { 0x00008064, 0x00000000 },
- { 0x000080c0, 0x2a82301a },
- { 0x000080c4, 0x05dc01e0 },
- { 0x000080c8, 0x1f402710 },
- { 0x000080cc, 0x01f40000 },
- { 0x000080d0, 0x00001e00 },
- { 0x000080d4, 0x00000000 },
- { 0x000080d8, 0x00400000 },
- { 0x000080e0, 0xffffffff },
- { 0x000080e4, 0x0000ffff },
- { 0x000080e8, 0x003f3f3f },
- { 0x000080ec, 0x00000000 },
- { 0x000080f0, 0x00000000 },
- { 0x000080f4, 0x00000000 },
- { 0x000080f8, 0x00000000 },
- { 0x000080fc, 0x00020000 },
- { 0x00008100, 0x00020000 },
- { 0x00008104, 0x00000001 },
- { 0x00008108, 0x00000052 },
- { 0x0000810c, 0x00000000 },
- { 0x00008110, 0x00000168 },
- { 0x00008118, 0x000100aa },
- { 0x0000811c, 0x00003210 },
- { 0x00008120, 0x08f04800 },
- { 0x00008124, 0x00000000 },
- { 0x00008128, 0x00000000 },
- { 0x0000812c, 0x00000000 },
- { 0x00008130, 0x00000000 },
- { 0x00008134, 0x00000000 },
- { 0x00008138, 0x00000000 },
- { 0x0000813c, 0x00000000 },
- { 0x00008144, 0xffffffff },
- { 0x00008168, 0x00000000 },
- { 0x0000816c, 0x00000000 },
- { 0x00008170, 0x32143320 },
- { 0x00008174, 0xfaa4fa50 },
- { 0x00008178, 0x00000100 },
- { 0x0000817c, 0x00000000 },
- { 0x000081c4, 0x00000000 },
- { 0x000081d0, 0x00003210 },
- { 0x000081ec, 0x00000000 },
- { 0x000081f0, 0x00000000 },
- { 0x000081f4, 0x00000000 },
- { 0x000081f8, 0x00000000 },
- { 0x000081fc, 0x00000000 },
- { 0x00008200, 0x00000000 },
- { 0x00008204, 0x00000000 },
- { 0x00008208, 0x00000000 },
- { 0x0000820c, 0x00000000 },
- { 0x00008210, 0x00000000 },
- { 0x00008214, 0x00000000 },
- { 0x00008218, 0x00000000 },
- { 0x0000821c, 0x00000000 },
- { 0x00008220, 0x00000000 },
- { 0x00008224, 0x00000000 },
- { 0x00008228, 0x00000000 },
- { 0x0000822c, 0x00000000 },
- { 0x00008230, 0x00000000 },
- { 0x00008234, 0x00000000 },
- { 0x00008238, 0x00000000 },
- { 0x0000823c, 0x00000000 },
- { 0x00008240, 0x00100000 },
- { 0x00008244, 0x0010f400 },
- { 0x00008248, 0x00000100 },
- { 0x0000824c, 0x0001e800 },
- { 0x00008250, 0x00000000 },
- { 0x00008254, 0x00000000 },
- { 0x00008258, 0x00000000 },
- { 0x0000825c, 0x400000ff },
- { 0x00008260, 0x00080922 },
- { 0x00008270, 0x00000000 },
- { 0x00008274, 0x40000000 },
- { 0x00008278, 0x003e4180 },
- { 0x0000827c, 0x00000000 },
- { 0x00008284, 0x0000002c },
- { 0x00008288, 0x0000002c },
- { 0x0000828c, 0x00000000 },
- { 0x00008294, 0x00000000 },
- { 0x00008298, 0x00000000 },
- { 0x00008300, 0x00000000 },
- { 0x00008304, 0x00000000 },
- { 0x00008308, 0x00000000 },
- { 0x0000830c, 0x00000000 },
- { 0x00008310, 0x00000000 },
- { 0x00008314, 0x00000000 },
- { 0x00008318, 0x00000000 },
- { 0x00008328, 0x00000000 },
- { 0x0000832c, 0x00000007 },
- { 0x00008330, 0x00000302 },
- { 0x00008334, 0x00000e00 },
- { 0x00008338, 0x00ff0000 },
- { 0x0000833c, 0x00000000 },
- { 0x00008340, 0x000107ff },
- { 0x00009808, 0x00000000 },
- { 0x0000980c, 0xad848e19 },
- { 0x00009810, 0x7d14e000 },
- { 0x00009814, 0x9c0a9f6b },
- { 0x0000981c, 0x00000000 },
- { 0x0000982c, 0x0000a000 },
- { 0x00009830, 0x00000000 },
- { 0x0000983c, 0x00200400 },
- { 0x00009840, 0x206a01ae },
- { 0x0000984c, 0x1284233c },
- { 0x00009854, 0x00000859 },
- { 0x00009900, 0x00000000 },
- { 0x00009904, 0x00000000 },
- { 0x00009908, 0x00000000 },
- { 0x0000990c, 0x00000000 },
- { 0x0000991c, 0x10000fff },
- { 0x00009920, 0x05100000 },
- { 0x0000a920, 0x05100000 },
- { 0x0000b920, 0x05100000 },
- { 0x00009928, 0x00000001 },
- { 0x0000992c, 0x00000004 },
- { 0x00009934, 0x1e1f2022 },
- { 0x00009938, 0x0a0b0c0d },
- { 0x0000993c, 0x00000000 },
- { 0x00009948, 0x9280b212 },
- { 0x0000994c, 0x00020028 },
- { 0x00009954, 0x5f3ca3de },
- { 0x00009958, 0x2108ecff },
- { 0x00009940, 0x00750604 },
- { 0x0000c95c, 0x004b6a8e },
- { 0x00009970, 0x190fb515 },
- { 0x00009974, 0x00000000 },
- { 0x00009978, 0x00000001 },
- { 0x0000997c, 0x00000000 },
- { 0x00009980, 0x00000000 },
- { 0x00009984, 0x00000000 },
- { 0x00009988, 0x00000000 },
- { 0x0000998c, 0x00000000 },
- { 0x00009990, 0x00000000 },
- { 0x00009994, 0x00000000 },
- { 0x00009998, 0x00000000 },
- { 0x0000999c, 0x00000000 },
- { 0x000099a0, 0x00000000 },
- { 0x000099a4, 0x00000001 },
- { 0x000099a8, 0x201fff00 },
- { 0x000099ac, 0x006f0000 },
- { 0x000099b0, 0x03051000 },
- { 0x000099dc, 0x00000000 },
- { 0x000099e0, 0x00000200 },
- { 0x000099e4, 0xaaaaaaaa },
- { 0x000099e8, 0x3c466478 },
- { 0x000099ec, 0x0cc80caa },
- { 0x000099fc, 0x00001042 },
- { 0x00009b00, 0x00000000 },
- { 0x00009b04, 0x00000001 },
- { 0x00009b08, 0x00000002 },
- { 0x00009b0c, 0x00000003 },
- { 0x00009b10, 0x00000004 },
- { 0x00009b14, 0x00000005 },
- { 0x00009b18, 0x00000008 },
- { 0x00009b1c, 0x00000009 },
- { 0x00009b20, 0x0000000a },
- { 0x00009b24, 0x0000000b },
- { 0x00009b28, 0x0000000c },
- { 0x00009b2c, 0x0000000d },
- { 0x00009b30, 0x00000010 },
- { 0x00009b34, 0x00000011 },
- { 0x00009b38, 0x00000012 },
- { 0x00009b3c, 0x00000013 },
- { 0x00009b40, 0x00000014 },
- { 0x00009b44, 0x00000015 },
- { 0x00009b48, 0x00000018 },
- { 0x00009b4c, 0x00000019 },
- { 0x00009b50, 0x0000001a },
- { 0x00009b54, 0x0000001b },
- { 0x00009b58, 0x0000001c },
- { 0x00009b5c, 0x0000001d },
- { 0x00009b60, 0x00000020 },
- { 0x00009b64, 0x00000021 },
- { 0x00009b68, 0x00000022 },
- { 0x00009b6c, 0x00000023 },
- { 0x00009b70, 0x00000024 },
- { 0x00009b74, 0x00000025 },
- { 0x00009b78, 0x00000028 },
- { 0x00009b7c, 0x00000029 },
- { 0x00009b80, 0x0000002a },
- { 0x00009b84, 0x0000002b },
- { 0x00009b88, 0x0000002c },
- { 0x00009b8c, 0x0000002d },
- { 0x00009b90, 0x00000030 },
- { 0x00009b94, 0x00000031 },
- { 0x00009b98, 0x00000032 },
- { 0x00009b9c, 0x00000033 },
- { 0x00009ba0, 0x00000034 },
- { 0x00009ba4, 0x00000035 },
- { 0x00009ba8, 0x00000035 },
- { 0x00009bac, 0x00000035 },
- { 0x00009bb0, 0x00000035 },
- { 0x00009bb4, 0x00000035 },
- { 0x00009bb8, 0x00000035 },
- { 0x00009bbc, 0x00000035 },
- { 0x00009bc0, 0x00000035 },
- { 0x00009bc4, 0x00000035 },
- { 0x00009bc8, 0x00000035 },
- { 0x00009bcc, 0x00000035 },
- { 0x00009bd0, 0x00000035 },
- { 0x00009bd4, 0x00000035 },
- { 0x00009bd8, 0x00000035 },
- { 0x00009bdc, 0x00000035 },
- { 0x00009be0, 0x00000035 },
- { 0x00009be4, 0x00000035 },
- { 0x00009be8, 0x00000035 },
- { 0x00009bec, 0x00000035 },
- { 0x00009bf0, 0x00000035 },
- { 0x00009bf4, 0x00000035 },
- { 0x00009bf8, 0x00000010 },
- { 0x00009bfc, 0x0000001a },
- { 0x0000a210, 0x40806333 },
- { 0x0000a214, 0x00106c10 },
- { 0x0000a218, 0x009c4060 },
- { 0x0000a220, 0x018830c6 },
- { 0x0000a224, 0x00000400 },
- { 0x0000a228, 0x001a0bb5 },
- { 0x0000a22c, 0x00000000 },
- { 0x0000a234, 0x20202020 },
- { 0x0000a238, 0x20202020 },
- { 0x0000a23c, 0x13c889af },
- { 0x0000a240, 0x38490a20 },
- { 0x0000a244, 0x00007bb6 },
- { 0x0000a248, 0x0fff3ffc },
- { 0x0000a24c, 0x00000001 },
- { 0x0000a250, 0x0000e000 },
- { 0x0000a254, 0x00000000 },
- { 0x0000a258, 0x0cc75380 },
- { 0x0000a25c, 0x0f0f0f01 },
- { 0x0000a260, 0xdfa91f01 },
- { 0x0000a268, 0x00000001 },
- { 0x0000a26c, 0x0ebae9c6 },
- { 0x0000b26c, 0x0ebae9c6 },
- { 0x0000c26c, 0x0ebae9c6 },
- { 0x0000d270, 0x00820820 },
- { 0x0000a278, 0x1ce739ce },
- { 0x0000a27c, 0x050701ce },
- { 0x0000a338, 0x00000000 },
- { 0x0000a33c, 0x00000000 },
- { 0x0000a340, 0x00000000 },
- { 0x0000a344, 0x00000000 },
- { 0x0000a348, 0x3fffffff },
- { 0x0000a34c, 0x3fffffff },
- { 0x0000a350, 0x3fffffff },
- { 0x0000a354, 0x0003ffff },
- { 0x0000a358, 0x79bfaa03 },
- { 0x0000d35c, 0x07ffffef },
- { 0x0000d360, 0x0fffffe7 },
- { 0x0000d364, 0x17ffffe5 },
- { 0x0000d368, 0x1fffffe4 },
- { 0x0000d36c, 0x37ffffe3 },
- { 0x0000d370, 0x3fffffe3 },
- { 0x0000d374, 0x57ffffe3 },
- { 0x0000d378, 0x5fffffe2 },
- { 0x0000d37c, 0x7fffffe2 },
- { 0x0000d380, 0x7f3c7bba },
- { 0x0000d384, 0xf3307ff0 },
- { 0x0000a388, 0x0c000000 },
- { 0x0000a38c, 0x20202020 },
- { 0x0000a390, 0x20202020 },
- { 0x0000a394, 0x1ce739ce },
- { 0x0000a398, 0x000001ce },
- { 0x0000a39c, 0x00000001 },
- { 0x0000a3a0, 0x00000000 },
- { 0x0000a3a4, 0x00000000 },
- { 0x0000a3a8, 0x00000000 },
- { 0x0000a3ac, 0x00000000 },
- { 0x0000a3b0, 0x00000000 },
- { 0x0000a3b4, 0x00000000 },
- { 0x0000a3b8, 0x00000000 },
- { 0x0000a3bc, 0x00000000 },
- { 0x0000a3c0, 0x00000000 },
- { 0x0000a3c4, 0x00000000 },
- { 0x0000a3c8, 0x00000246 },
- { 0x0000a3cc, 0x20202020 },
- { 0x0000a3d0, 0x20202020 },
- { 0x0000a3d4, 0x20202020 },
- { 0x0000a3dc, 0x1ce739ce },
- { 0x0000a3e0, 0x000001ce },
+ /* Addr allmodes */
+ {0x0000000c, 0x00000000},
+ {0x00000030, 0x00020015},
+ {0x00000034, 0x00000005},
+ {0x00000040, 0x00000000},
+ {0x00000044, 0x00000008},
+ {0x00000048, 0x00000008},
+ {0x0000004c, 0x00000010},
+ {0x00000050, 0x00000000},
+ {0x00000054, 0x0000001f},
+ {0x00000800, 0x00000000},
+ {0x00000804, 0x00000000},
+ {0x00000808, 0x00000000},
+ {0x0000080c, 0x00000000},
+ {0x00000810, 0x00000000},
+ {0x00000814, 0x00000000},
+ {0x00000818, 0x00000000},
+ {0x0000081c, 0x00000000},
+ {0x00000820, 0x00000000},
+ {0x00000824, 0x00000000},
+ {0x00001040, 0x002ffc0f},
+ {0x00001044, 0x002ffc0f},
+ {0x00001048, 0x002ffc0f},
+ {0x0000104c, 0x002ffc0f},
+ {0x00001050, 0x002ffc0f},
+ {0x00001054, 0x002ffc0f},
+ {0x00001058, 0x002ffc0f},
+ {0x0000105c, 0x002ffc0f},
+ {0x00001060, 0x002ffc0f},
+ {0x00001064, 0x002ffc0f},
+ {0x00001230, 0x00000000},
+ {0x00001270, 0x00000000},
+ {0x00001038, 0x00000000},
+ {0x00001078, 0x00000000},
+ {0x000010b8, 0x00000000},
+ {0x000010f8, 0x00000000},
+ {0x00001138, 0x00000000},
+ {0x00001178, 0x00000000},
+ {0x000011b8, 0x00000000},
+ {0x000011f8, 0x00000000},
+ {0x00001238, 0x00000000},
+ {0x00001278, 0x00000000},
+ {0x000012b8, 0x00000000},
+ {0x000012f8, 0x00000000},
+ {0x00001338, 0x00000000},
+ {0x00001378, 0x00000000},
+ {0x000013b8, 0x00000000},
+ {0x000013f8, 0x00000000},
+ {0x00001438, 0x00000000},
+ {0x00001478, 0x00000000},
+ {0x000014b8, 0x00000000},
+ {0x000014f8, 0x00000000},
+ {0x00001538, 0x00000000},
+ {0x00001578, 0x00000000},
+ {0x000015b8, 0x00000000},
+ {0x000015f8, 0x00000000},
+ {0x00001638, 0x00000000},
+ {0x00001678, 0x00000000},
+ {0x000016b8, 0x00000000},
+ {0x000016f8, 0x00000000},
+ {0x00001738, 0x00000000},
+ {0x00001778, 0x00000000},
+ {0x000017b8, 0x00000000},
+ {0x000017f8, 0x00000000},
+ {0x0000103c, 0x00000000},
+ {0x0000107c, 0x00000000},
+ {0x000010bc, 0x00000000},
+ {0x000010fc, 0x00000000},
+ {0x0000113c, 0x00000000},
+ {0x0000117c, 0x00000000},
+ {0x000011bc, 0x00000000},
+ {0x000011fc, 0x00000000},
+ {0x0000123c, 0x00000000},
+ {0x0000127c, 0x00000000},
+ {0x000012bc, 0x00000000},
+ {0x000012fc, 0x00000000},
+ {0x0000133c, 0x00000000},
+ {0x0000137c, 0x00000000},
+ {0x000013bc, 0x00000000},
+ {0x000013fc, 0x00000000},
+ {0x0000143c, 0x00000000},
+ {0x0000147c, 0x00000000},
+ {0x00004030, 0x00000002},
+ {0x0000403c, 0x00000002},
+ {0x00007010, 0x00000020},
+ {0x00007038, 0x000004c2},
+ {0x00008004, 0x00000000},
+ {0x00008008, 0x00000000},
+ {0x0000800c, 0x00000000},
+ {0x00008018, 0x00000700},
+ {0x00008020, 0x00000000},
+ {0x00008038, 0x00000000},
+ {0x0000803c, 0x00000000},
+ {0x00008048, 0x40000000},
+ {0x00008054, 0x00000000},
+ {0x00008058, 0x00000000},
+ {0x0000805c, 0x000fc78f},
+ {0x00008060, 0x0000000f},
+ {0x00008064, 0x00000000},
+ {0x000080c0, 0x2a82301a},
+ {0x000080c4, 0x05dc01e0},
+ {0x000080c8, 0x1f402710},
+ {0x000080cc, 0x01f40000},
+ {0x000080d0, 0x00001e00},
+ {0x000080d4, 0x00000000},
+ {0x000080d8, 0x00400000},
+ {0x000080e0, 0xffffffff},
+ {0x000080e4, 0x0000ffff},
+ {0x000080e8, 0x003f3f3f},
+ {0x000080ec, 0x00000000},
+ {0x000080f0, 0x00000000},
+ {0x000080f4, 0x00000000},
+ {0x000080f8, 0x00000000},
+ {0x000080fc, 0x00020000},
+ {0x00008100, 0x00020000},
+ {0x00008104, 0x00000001},
+ {0x00008108, 0x00000052},
+ {0x0000810c, 0x00000000},
+ {0x00008110, 0x00000168},
+ {0x00008118, 0x000100aa},
+ {0x0000811c, 0x00003210},
+ {0x00008124, 0x00000000},
+ {0x00008128, 0x00000000},
+ {0x0000812c, 0x00000000},
+ {0x00008130, 0x00000000},
+ {0x00008134, 0x00000000},
+ {0x00008138, 0x00000000},
+ {0x0000813c, 0x00000000},
+ {0x00008144, 0xffffffff},
+ {0x00008168, 0x00000000},
+ {0x0000816c, 0x00000000},
+ {0x00008170, 0x32143320},
+ {0x00008174, 0xfaa4fa50},
+ {0x00008178, 0x00000100},
+ {0x0000817c, 0x00000000},
+ {0x000081c4, 0x00000000},
+ {0x000081ec, 0x00000000},
+ {0x000081f0, 0x00000000},
+ {0x000081f4, 0x00000000},
+ {0x000081f8, 0x00000000},
+ {0x000081fc, 0x00000000},
+ {0x00008200, 0x00000000},
+ {0x00008204, 0x00000000},
+ {0x00008208, 0x00000000},
+ {0x0000820c, 0x00000000},
+ {0x00008210, 0x00000000},
+ {0x00008214, 0x00000000},
+ {0x00008218, 0x00000000},
+ {0x0000821c, 0x00000000},
+ {0x00008220, 0x00000000},
+ {0x00008224, 0x00000000},
+ {0x00008228, 0x00000000},
+ {0x0000822c, 0x00000000},
+ {0x00008230, 0x00000000},
+ {0x00008234, 0x00000000},
+ {0x00008238, 0x00000000},
+ {0x0000823c, 0x00000000},
+ {0x00008240, 0x00100000},
+ {0x00008244, 0x0010f400},
+ {0x00008248, 0x00000100},
+ {0x0000824c, 0x0001e800},
+ {0x00008250, 0x00000000},
+ {0x00008254, 0x00000000},
+ {0x00008258, 0x00000000},
+ {0x0000825c, 0x400000ff},
+ {0x00008260, 0x00080922},
+ {0x00008264, 0x88a00010},
+ {0x00008270, 0x00000000},
+ {0x00008274, 0x40000000},
+ {0x00008278, 0x003e4180},
+ {0x0000827c, 0x00000000},
+ {0x00008284, 0x0000002c},
+ {0x00008288, 0x0000002c},
+ {0x0000828c, 0x00000000},
+ {0x00008294, 0x00000000},
+ {0x00008298, 0x00000000},
+ {0x00008300, 0x00000000},
+ {0x00008304, 0x00000000},
+ {0x00008308, 0x00000000},
+ {0x0000830c, 0x00000000},
+ {0x00008310, 0x00000000},
+ {0x00008314, 0x00000000},
+ {0x00008318, 0x00000000},
+ {0x00008328, 0x00000000},
+ {0x0000832c, 0x00000007},
+ {0x00008330, 0x00000302},
+ {0x00008334, 0x00000e00},
+ {0x00008338, 0x00ff0000},
+ {0x0000833c, 0x00000000},
+ {0x00008340, 0x000107ff},
+ {0x00009808, 0x00000000},
+ {0x0000980c, 0xad848e19},
+ {0x00009810, 0x7d14e000},
+ {0x00009814, 0x9c0a9f6b},
+ {0x0000981c, 0x00000000},
+ {0x0000982c, 0x0000a000},
+ {0x00009830, 0x00000000},
+ {0x0000983c, 0x00200400},
+ {0x00009840, 0x206a01ae},
+ {0x0000984c, 0x1284233c},
+ {0x00009854, 0x00000859},
+ {0x00009900, 0x00000000},
+ {0x00009904, 0x00000000},
+ {0x00009908, 0x00000000},
+ {0x0000990c, 0x00000000},
+ {0x0000991c, 0x10000fff},
+ {0x00009920, 0x05100000},
+ {0x0000a920, 0x05100000},
+ {0x0000b920, 0x05100000},
+ {0x00009928, 0x00000001},
+ {0x0000992c, 0x00000004},
+ {0x00009934, 0x1e1f2022},
+ {0x00009938, 0x0a0b0c0d},
+ {0x0000993c, 0x00000000},
+ {0x00009948, 0x9280b212},
+ {0x0000994c, 0x00020028},
+ {0x00009954, 0x5f3ca3de},
+ {0x00009958, 0x2108ecff},
+ {0x00009940, 0x00750604},
+ {0x0000c95c, 0x004b6a8e},
+ {0x00009970, 0x190fb515},
+ {0x00009974, 0x00000000},
+ {0x00009978, 0x00000001},
+ {0x0000997c, 0x00000000},
+ {0x00009980, 0x00000000},
+ {0x00009984, 0x00000000},
+ {0x00009988, 0x00000000},
+ {0x0000998c, 0x00000000},
+ {0x00009990, 0x00000000},
+ {0x00009994, 0x00000000},
+ {0x00009998, 0x00000000},
+ {0x0000999c, 0x00000000},
+ {0x000099a0, 0x00000000},
+ {0x000099a4, 0x00000001},
+ {0x000099a8, 0x201fff00},
+ {0x000099ac, 0x006f0000},
+ {0x000099b0, 0x03051000},
+ {0x000099dc, 0x00000000},
+ {0x000099e0, 0x00000200},
+ {0x000099e4, 0xaaaaaaaa},
+ {0x000099e8, 0x3c466478},
+ {0x000099ec, 0x0cc80caa},
+ {0x000099fc, 0x00001042},
+ {0x00009b00, 0x00000000},
+ {0x00009b04, 0x00000001},
+ {0x00009b08, 0x00000002},
+ {0x00009b0c, 0x00000003},
+ {0x00009b10, 0x00000004},
+ {0x00009b14, 0x00000005},
+ {0x00009b18, 0x00000008},
+ {0x00009b1c, 0x00000009},
+ {0x00009b20, 0x0000000a},
+ {0x00009b24, 0x0000000b},
+ {0x00009b28, 0x0000000c},
+ {0x00009b2c, 0x0000000d},
+ {0x00009b30, 0x00000010},
+ {0x00009b34, 0x00000011},
+ {0x00009b38, 0x00000012},
+ {0x00009b3c, 0x00000013},
+ {0x00009b40, 0x00000014},
+ {0x00009b44, 0x00000015},
+ {0x00009b48, 0x00000018},
+ {0x00009b4c, 0x00000019},
+ {0x00009b50, 0x0000001a},
+ {0x00009b54, 0x0000001b},
+ {0x00009b58, 0x0000001c},
+ {0x00009b5c, 0x0000001d},
+ {0x00009b60, 0x00000020},
+ {0x00009b64, 0x00000021},
+ {0x00009b68, 0x00000022},
+ {0x00009b6c, 0x00000023},
+ {0x00009b70, 0x00000024},
+ {0x00009b74, 0x00000025},
+ {0x00009b78, 0x00000028},
+ {0x00009b7c, 0x00000029},
+ {0x00009b80, 0x0000002a},
+ {0x00009b84, 0x0000002b},
+ {0x00009b88, 0x0000002c},
+ {0x00009b8c, 0x0000002d},
+ {0x00009b90, 0x00000030},
+ {0x00009b94, 0x00000031},
+ {0x00009b98, 0x00000032},
+ {0x00009b9c, 0x00000033},
+ {0x00009ba0, 0x00000034},
+ {0x00009ba4, 0x00000035},
+ {0x00009ba8, 0x00000035},
+ {0x00009bac, 0x00000035},
+ {0x00009bb0, 0x00000035},
+ {0x00009bb4, 0x00000035},
+ {0x00009bb8, 0x00000035},
+ {0x00009bbc, 0x00000035},
+ {0x00009bc0, 0x00000035},
+ {0x00009bc4, 0x00000035},
+ {0x00009bc8, 0x00000035},
+ {0x00009bcc, 0x00000035},
+ {0x00009bd0, 0x00000035},
+ {0x00009bd4, 0x00000035},
+ {0x00009bd8, 0x00000035},
+ {0x00009bdc, 0x00000035},
+ {0x00009be0, 0x00000035},
+ {0x00009be4, 0x00000035},
+ {0x00009be8, 0x00000035},
+ {0x00009bec, 0x00000035},
+ {0x00009bf0, 0x00000035},
+ {0x00009bf4, 0x00000035},
+ {0x00009bf8, 0x00000010},
+ {0x00009bfc, 0x0000001a},
+ {0x0000a210, 0x40806333},
+ {0x0000a214, 0x00106c10},
+ {0x0000a218, 0x009c4060},
+ {0x0000a220, 0x018830c6},
+ {0x0000a224, 0x00000400},
+ {0x0000a228, 0x001a0bb5},
+ {0x0000a22c, 0x00000000},
+ {0x0000a234, 0x20202020},
+ {0x0000a238, 0x20202020},
+ {0x0000a23c, 0x13c889af},
+ {0x0000a240, 0x38490a20},
+ {0x0000a244, 0x00007bb6},
+ {0x0000a248, 0x0fff3ffc},
+ {0x0000a24c, 0x00000001},
+ {0x0000a250, 0x0000e000},
+ {0x0000a254, 0x00000000},
+ {0x0000a258, 0x0cc75380},
+ {0x0000a25c, 0x0f0f0f01},
+ {0x0000a260, 0xdfa91f01},
+ {0x0000a268, 0x00000001},
+ {0x0000a26c, 0x0e79e5c6},
+ {0x0000b26c, 0x0e79e5c6},
+ {0x0000c26c, 0x0e79e5c6},
+ {0x0000d270, 0x00820820},
+ {0x0000a278, 0x1ce739ce},
+ {0x0000a27c, 0x050701ce},
+ {0x0000a338, 0x00000000},
+ {0x0000a33c, 0x00000000},
+ {0x0000a340, 0x00000000},
+ {0x0000a344, 0x00000000},
+ {0x0000a348, 0x3fffffff},
+ {0x0000a34c, 0x3fffffff},
+ {0x0000a350, 0x3fffffff},
+ {0x0000a354, 0x0003ffff},
+ {0x0000a358, 0x79bfaa03},
+ {0x0000d35c, 0x07ffffef},
+ {0x0000d360, 0x0fffffe7},
+ {0x0000d364, 0x17ffffe5},
+ {0x0000d368, 0x1fffffe4},
+ {0x0000d36c, 0x37ffffe3},
+ {0x0000d370, 0x3fffffe3},
+ {0x0000d374, 0x57ffffe3},
+ {0x0000d378, 0x5fffffe2},
+ {0x0000d37c, 0x7fffffe2},
+ {0x0000d380, 0x7f3c7bba},
+ {0x0000d384, 0xf3307ff0},
+ {0x0000a388, 0x0c000000},
+ {0x0000a38c, 0x20202020},
+ {0x0000a390, 0x20202020},
+ {0x0000a394, 0x1ce739ce},
+ {0x0000a398, 0x000001ce},
+ {0x0000a39c, 0x00000001},
+ {0x0000a3a0, 0x00000000},
+ {0x0000a3a4, 0x00000000},
+ {0x0000a3a8, 0x00000000},
+ {0x0000a3ac, 0x00000000},
+ {0x0000a3b0, 0x00000000},
+ {0x0000a3b4, 0x00000000},
+ {0x0000a3b8, 0x00000000},
+ {0x0000a3bc, 0x00000000},
+ {0x0000a3c0, 0x00000000},
+ {0x0000a3c4, 0x00000000},
+ {0x0000a3c8, 0x00000246},
+ {0x0000a3cc, 0x20202020},
+ {0x0000a3d0, 0x20202020},
+ {0x0000a3d4, 0x20202020},
+ {0x0000a3dc, 0x1ce739ce},
+ {0x0000a3e0, 0x000001ce},
};
static const u32 ar5416Bank0_9160[][2] = {
- { 0x000098b0, 0x1e5795e5 },
- { 0x000098e0, 0x02008020 },
+ /* Addr allmodes */
+ {0x000098b0, 0x1e5795e5},
+ {0x000098e0, 0x02008020},
};
static const u32 ar5416BB_RfGain_9160[][3] = {
- { 0x00009a00, 0x00000000, 0x00000000 },
- { 0x00009a04, 0x00000040, 0x00000040 },
- { 0x00009a08, 0x00000080, 0x00000080 },
- { 0x00009a0c, 0x000001a1, 0x00000141 },
- { 0x00009a10, 0x000001e1, 0x00000181 },
- { 0x00009a14, 0x00000021, 0x000001c1 },
- { 0x00009a18, 0x00000061, 0x00000001 },
- { 0x00009a1c, 0x00000168, 0x00000041 },
- { 0x00009a20, 0x000001a8, 0x000001a8 },
- { 0x00009a24, 0x000001e8, 0x000001e8 },
- { 0x00009a28, 0x00000028, 0x00000028 },
- { 0x00009a2c, 0x00000068, 0x00000068 },
- { 0x00009a30, 0x00000189, 0x000000a8 },
- { 0x00009a34, 0x000001c9, 0x00000169 },
- { 0x00009a38, 0x00000009, 0x000001a9 },
- { 0x00009a3c, 0x00000049, 0x000001e9 },
- { 0x00009a40, 0x00000089, 0x00000029 },
- { 0x00009a44, 0x00000170, 0x00000069 },
- { 0x00009a48, 0x000001b0, 0x00000190 },
- { 0x00009a4c, 0x000001f0, 0x000001d0 },
- { 0x00009a50, 0x00000030, 0x00000010 },
- { 0x00009a54, 0x00000070, 0x00000050 },
- { 0x00009a58, 0x00000191, 0x00000090 },
- { 0x00009a5c, 0x000001d1, 0x00000151 },
- { 0x00009a60, 0x00000011, 0x00000191 },
- { 0x00009a64, 0x00000051, 0x000001d1 },
- { 0x00009a68, 0x00000091, 0x00000011 },
- { 0x00009a6c, 0x000001b8, 0x00000051 },
- { 0x00009a70, 0x000001f8, 0x00000198 },
- { 0x00009a74, 0x00000038, 0x000001d8 },
- { 0x00009a78, 0x00000078, 0x00000018 },
- { 0x00009a7c, 0x00000199, 0x00000058 },
- { 0x00009a80, 0x000001d9, 0x00000098 },
- { 0x00009a84, 0x00000019, 0x00000159 },
- { 0x00009a88, 0x00000059, 0x00000199 },
- { 0x00009a8c, 0x00000099, 0x000001d9 },
- { 0x00009a90, 0x000000d9, 0x00000019 },
- { 0x00009a94, 0x000000f9, 0x00000059 },
- { 0x00009a98, 0x000000f9, 0x00000099 },
- { 0x00009a9c, 0x000000f9, 0x000000d9 },
- { 0x00009aa0, 0x000000f9, 0x000000f9 },
- { 0x00009aa4, 0x000000f9, 0x000000f9 },
- { 0x00009aa8, 0x000000f9, 0x000000f9 },
- { 0x00009aac, 0x000000f9, 0x000000f9 },
- { 0x00009ab0, 0x000000f9, 0x000000f9 },
- { 0x00009ab4, 0x000000f9, 0x000000f9 },
- { 0x00009ab8, 0x000000f9, 0x000000f9 },
- { 0x00009abc, 0x000000f9, 0x000000f9 },
- { 0x00009ac0, 0x000000f9, 0x000000f9 },
- { 0x00009ac4, 0x000000f9, 0x000000f9 },
- { 0x00009ac8, 0x000000f9, 0x000000f9 },
- { 0x00009acc, 0x000000f9, 0x000000f9 },
- { 0x00009ad0, 0x000000f9, 0x000000f9 },
- { 0x00009ad4, 0x000000f9, 0x000000f9 },
- { 0x00009ad8, 0x000000f9, 0x000000f9 },
- { 0x00009adc, 0x000000f9, 0x000000f9 },
- { 0x00009ae0, 0x000000f9, 0x000000f9 },
- { 0x00009ae4, 0x000000f9, 0x000000f9 },
- { 0x00009ae8, 0x000000f9, 0x000000f9 },
- { 0x00009aec, 0x000000f9, 0x000000f9 },
- { 0x00009af0, 0x000000f9, 0x000000f9 },
- { 0x00009af4, 0x000000f9, 0x000000f9 },
- { 0x00009af8, 0x000000f9, 0x000000f9 },
- { 0x00009afc, 0x000000f9, 0x000000f9 },
+ /* Addr 5G_HT20 5G_HT40 */
+ {0x00009a00, 0x00000000, 0x00000000},
+ {0x00009a04, 0x00000040, 0x00000040},
+ {0x00009a08, 0x00000080, 0x00000080},
+ {0x00009a0c, 0x000001a1, 0x00000141},
+ {0x00009a10, 0x000001e1, 0x00000181},
+ {0x00009a14, 0x00000021, 0x000001c1},
+ {0x00009a18, 0x00000061, 0x00000001},
+ {0x00009a1c, 0x00000168, 0x00000041},
+ {0x00009a20, 0x000001a8, 0x000001a8},
+ {0x00009a24, 0x000001e8, 0x000001e8},
+ {0x00009a28, 0x00000028, 0x00000028},
+ {0x00009a2c, 0x00000068, 0x00000068},
+ {0x00009a30, 0x00000189, 0x000000a8},
+ {0x00009a34, 0x000001c9, 0x00000169},
+ {0x00009a38, 0x00000009, 0x000001a9},
+ {0x00009a3c, 0x00000049, 0x000001e9},
+ {0x00009a40, 0x00000089, 0x00000029},
+ {0x00009a44, 0x00000170, 0x00000069},
+ {0x00009a48, 0x000001b0, 0x00000190},
+ {0x00009a4c, 0x000001f0, 0x000001d0},
+ {0x00009a50, 0x00000030, 0x00000010},
+ {0x00009a54, 0x00000070, 0x00000050},
+ {0x00009a58, 0x00000191, 0x00000090},
+ {0x00009a5c, 0x000001d1, 0x00000151},
+ {0x00009a60, 0x00000011, 0x00000191},
+ {0x00009a64, 0x00000051, 0x000001d1},
+ {0x00009a68, 0x00000091, 0x00000011},
+ {0x00009a6c, 0x000001b8, 0x00000051},
+ {0x00009a70, 0x000001f8, 0x00000198},
+ {0x00009a74, 0x00000038, 0x000001d8},
+ {0x00009a78, 0x00000078, 0x00000018},
+ {0x00009a7c, 0x00000199, 0x00000058},
+ {0x00009a80, 0x000001d9, 0x00000098},
+ {0x00009a84, 0x00000019, 0x00000159},
+ {0x00009a88, 0x00000059, 0x00000199},
+ {0x00009a8c, 0x00000099, 0x000001d9},
+ {0x00009a90, 0x000000d9, 0x00000019},
+ {0x00009a94, 0x000000f9, 0x00000059},
+ {0x00009a98, 0x000000f9, 0x00000099},
+ {0x00009a9c, 0x000000f9, 0x000000d9},
+ {0x00009aa0, 0x000000f9, 0x000000f9},
+ {0x00009aa4, 0x000000f9, 0x000000f9},
+ {0x00009aa8, 0x000000f9, 0x000000f9},
+ {0x00009aac, 0x000000f9, 0x000000f9},
+ {0x00009ab0, 0x000000f9, 0x000000f9},
+ {0x00009ab4, 0x000000f9, 0x000000f9},
+ {0x00009ab8, 0x000000f9, 0x000000f9},
+ {0x00009abc, 0x000000f9, 0x000000f9},
+ {0x00009ac0, 0x000000f9, 0x000000f9},
+ {0x00009ac4, 0x000000f9, 0x000000f9},
+ {0x00009ac8, 0x000000f9, 0x000000f9},
+ {0x00009acc, 0x000000f9, 0x000000f9},
+ {0x00009ad0, 0x000000f9, 0x000000f9},
+ {0x00009ad4, 0x000000f9, 0x000000f9},
+ {0x00009ad8, 0x000000f9, 0x000000f9},
+ {0x00009adc, 0x000000f9, 0x000000f9},
+ {0x00009ae0, 0x000000f9, 0x000000f9},
+ {0x00009ae4, 0x000000f9, 0x000000f9},
+ {0x00009ae8, 0x000000f9, 0x000000f9},
+ {0x00009aec, 0x000000f9, 0x000000f9},
+ {0x00009af0, 0x000000f9, 0x000000f9},
+ {0x00009af4, 0x000000f9, 0x000000f9},
+ {0x00009af8, 0x000000f9, 0x000000f9},
+ {0x00009afc, 0x000000f9, 0x000000f9},
};
static const u32 ar5416Bank1_9160[][2] = {
- { 0x000098b0, 0x02108421 },
- { 0x000098ec, 0x00000008 },
+ /* Addr allmodes */
+ {0x000098b0, 0x02108421},
+ {0x000098ec, 0x00000008},
};
static const u32 ar5416Bank2_9160[][2] = {
- { 0x000098b0, 0x0e73ff17 },
- { 0x000098e0, 0x00000420 },
+ /* Addr allmodes */
+ {0x000098b0, 0x0e73ff17},
+ {0x000098e0, 0x00000420},
};
static const u32 ar5416Bank3_9160[][3] = {
- { 0x000098f0, 0x01400018, 0x01c00018 },
+ /* Addr 5G_HT20 5G_HT40 */
+ {0x000098f0, 0x01400018, 0x01c00018},
};
static const u32 ar5416Bank6_9160[][3] = {
- { 0x0000989c, 0x00000000, 0x00000000 },
- { 0x0000989c, 0x00000000, 0x00000000 },
- { 0x0000989c, 0x00000000, 0x00000000 },
- { 0x0000989c, 0x00e00000, 0x00e00000 },
- { 0x0000989c, 0x005e0000, 0x005e0000 },
- { 0x0000989c, 0x00120000, 0x00120000 },
- { 0x0000989c, 0x00620000, 0x00620000 },
- { 0x0000989c, 0x00020000, 0x00020000 },
- { 0x0000989c, 0x00ff0000, 0x00ff0000 },
- { 0x0000989c, 0x00ff0000, 0x00ff0000 },
- { 0x0000989c, 0x00ff0000, 0x00ff0000 },
- { 0x0000989c, 0x40ff0000, 0x40ff0000 },
- { 0x0000989c, 0x005f0000, 0x005f0000 },
- { 0x0000989c, 0x00870000, 0x00870000 },
- { 0x0000989c, 0x00f90000, 0x00f90000 },
- { 0x0000989c, 0x007b0000, 0x007b0000 },
- { 0x0000989c, 0x00ff0000, 0x00ff0000 },
- { 0x0000989c, 0x00f50000, 0x00f50000 },
- { 0x0000989c, 0x00dc0000, 0x00dc0000 },
- { 0x0000989c, 0x00110000, 0x00110000 },
- { 0x0000989c, 0x006100a8, 0x006100a8 },
- { 0x0000989c, 0x004210a2, 0x004210a2 },
- { 0x0000989c, 0x0014008f, 0x0014008f },
- { 0x0000989c, 0x00c40003, 0x00c40003 },
- { 0x0000989c, 0x003000f2, 0x003000f2 },
- { 0x0000989c, 0x00440016, 0x00440016 },
- { 0x0000989c, 0x00410040, 0x00410040 },
- { 0x0000989c, 0x0001805e, 0x0001805e },
- { 0x0000989c, 0x0000c0ab, 0x0000c0ab },
- { 0x0000989c, 0x000000f1, 0x000000f1 },
- { 0x0000989c, 0x00002081, 0x00002081 },
- { 0x0000989c, 0x000000d4, 0x000000d4 },
- { 0x000098d0, 0x0000000f, 0x0010000f },
+ /* Addr 5G_HT20 5G_HT40 */
+ {0x0000989c, 0x00000000, 0x00000000},
+ {0x0000989c, 0x00000000, 0x00000000},
+ {0x0000989c, 0x00000000, 0x00000000},
+ {0x0000989c, 0x00e00000, 0x00e00000},
+ {0x0000989c, 0x005e0000, 0x005e0000},
+ {0x0000989c, 0x00120000, 0x00120000},
+ {0x0000989c, 0x00620000, 0x00620000},
+ {0x0000989c, 0x00020000, 0x00020000},
+ {0x0000989c, 0x00ff0000, 0x00ff0000},
+ {0x0000989c, 0x00ff0000, 0x00ff0000},
+ {0x0000989c, 0x00ff0000, 0x00ff0000},
+ {0x0000989c, 0x40ff0000, 0x40ff0000},
+ {0x0000989c, 0x005f0000, 0x005f0000},
+ {0x0000989c, 0x00870000, 0x00870000},
+ {0x0000989c, 0x00f90000, 0x00f90000},
+ {0x0000989c, 0x007b0000, 0x007b0000},
+ {0x0000989c, 0x00ff0000, 0x00ff0000},
+ {0x0000989c, 0x00f50000, 0x00f50000},
+ {0x0000989c, 0x00dc0000, 0x00dc0000},
+ {0x0000989c, 0x00110000, 0x00110000},
+ {0x0000989c, 0x006100a8, 0x006100a8},
+ {0x0000989c, 0x004210a2, 0x004210a2},
+ {0x0000989c, 0x0014008f, 0x0014008f},
+ {0x0000989c, 0x00c40003, 0x00c40003},
+ {0x0000989c, 0x003000f2, 0x003000f2},
+ {0x0000989c, 0x00440016, 0x00440016},
+ {0x0000989c, 0x00410040, 0x00410040},
+ {0x0000989c, 0x0001805e, 0x0001805e},
+ {0x0000989c, 0x0000c0ab, 0x0000c0ab},
+ {0x0000989c, 0x000000f1, 0x000000f1},
+ {0x0000989c, 0x00002081, 0x00002081},
+ {0x0000989c, 0x000000d4, 0x000000d4},
+ {0x000098d0, 0x0000000f, 0x0010000f},
};
static const u32 ar5416Bank6TPC_9160[][3] = {
- { 0x0000989c, 0x00000000, 0x00000000 },
- { 0x0000989c, 0x00000000, 0x00000000 },
- { 0x0000989c, 0x00000000, 0x00000000 },
- { 0x0000989c, 0x00e00000, 0x00e00000 },
- { 0x0000989c, 0x005e0000, 0x005e0000 },
- { 0x0000989c, 0x00120000, 0x00120000 },
- { 0x0000989c, 0x00620000, 0x00620000 },
- { 0x0000989c, 0x00020000, 0x00020000 },
- { 0x0000989c, 0x00ff0000, 0x00ff0000 },
- { 0x0000989c, 0x00ff0000, 0x00ff0000 },
- { 0x0000989c, 0x00ff0000, 0x00ff0000 },
- { 0x0000989c, 0x40ff0000, 0x40ff0000 },
- { 0x0000989c, 0x005f0000, 0x005f0000 },
- { 0x0000989c, 0x00870000, 0x00870000 },
- { 0x0000989c, 0x00f90000, 0x00f90000 },
- { 0x0000989c, 0x007b0000, 0x007b0000 },
- { 0x0000989c, 0x00ff0000, 0x00ff0000 },
- { 0x0000989c, 0x00f50000, 0x00f50000 },
- { 0x0000989c, 0x00dc0000, 0x00dc0000 },
- { 0x0000989c, 0x00110000, 0x00110000 },
- { 0x0000989c, 0x006100a8, 0x006100a8 },
- { 0x0000989c, 0x00423022, 0x00423022 },
- { 0x0000989c, 0x2014008f, 0x2014008f },
- { 0x0000989c, 0x00c40002, 0x00c40002 },
- { 0x0000989c, 0x003000f2, 0x003000f2 },
- { 0x0000989c, 0x00440016, 0x00440016 },
- { 0x0000989c, 0x00410040, 0x00410040 },
- { 0x0000989c, 0x0001805e, 0x0001805e },
- { 0x0000989c, 0x0000c0ab, 0x0000c0ab },
- { 0x0000989c, 0x000000e1, 0x000000e1 },
- { 0x0000989c, 0x00007080, 0x00007080 },
- { 0x0000989c, 0x000000d4, 0x000000d4 },
- { 0x000098d0, 0x0000000f, 0x0010000f },
+ /* Addr 5G_HT20 5G_HT40 */
+ {0x0000989c, 0x00000000, 0x00000000},
+ {0x0000989c, 0x00000000, 0x00000000},
+ {0x0000989c, 0x00000000, 0x00000000},
+ {0x0000989c, 0x00e00000, 0x00e00000},
+ {0x0000989c, 0x005e0000, 0x005e0000},
+ {0x0000989c, 0x00120000, 0x00120000},
+ {0x0000989c, 0x00620000, 0x00620000},
+ {0x0000989c, 0x00020000, 0x00020000},
+ {0x0000989c, 0x00ff0000, 0x00ff0000},
+ {0x0000989c, 0x00ff0000, 0x00ff0000},
+ {0x0000989c, 0x00ff0000, 0x00ff0000},
+ {0x0000989c, 0x40ff0000, 0x40ff0000},
+ {0x0000989c, 0x005f0000, 0x005f0000},
+ {0x0000989c, 0x00870000, 0x00870000},
+ {0x0000989c, 0x00f90000, 0x00f90000},
+ {0x0000989c, 0x007b0000, 0x007b0000},
+ {0x0000989c, 0x00ff0000, 0x00ff0000},
+ {0x0000989c, 0x00f50000, 0x00f50000},
+ {0x0000989c, 0x00dc0000, 0x00dc0000},
+ {0x0000989c, 0x00110000, 0x00110000},
+ {0x0000989c, 0x006100a8, 0x006100a8},
+ {0x0000989c, 0x00423022, 0x00423022},
+ {0x0000989c, 0x2014008f, 0x2014008f},
+ {0x0000989c, 0x00c40002, 0x00c40002},
+ {0x0000989c, 0x003000f2, 0x003000f2},
+ {0x0000989c, 0x00440016, 0x00440016},
+ {0x0000989c, 0x00410040, 0x00410040},
+ {0x0000989c, 0x0001805e, 0x0001805e},
+ {0x0000989c, 0x0000c0ab, 0x0000c0ab},
+ {0x0000989c, 0x000000e1, 0x000000e1},
+ {0x0000989c, 0x00007080, 0x00007080},
+ {0x0000989c, 0x000000d4, 0x000000d4},
+ {0x000098d0, 0x0000000f, 0x0010000f},
};
static const u32 ar5416Bank7_9160[][2] = {
- { 0x0000989c, 0x00000500 },
- { 0x0000989c, 0x00000800 },
- { 0x000098cc, 0x0000000e },
+ /* Addr allmodes */
+ {0x0000989c, 0x00000500},
+ {0x0000989c, 0x00000800},
+ {0x000098cc, 0x0000000e},
};
static const u32 ar5416Addac_9160[][2] = {
- {0x0000989c, 0x00000000 },
- {0x0000989c, 0x00000000 },
- {0x0000989c, 0x00000000 },
- {0x0000989c, 0x00000000 },
- {0x0000989c, 0x00000000 },
- {0x0000989c, 0x00000000 },
- {0x0000989c, 0x000000c0 },
- {0x0000989c, 0x00000018 },
- {0x0000989c, 0x00000004 },
- {0x0000989c, 0x00000000 },
- {0x0000989c, 0x00000000 },
- {0x0000989c, 0x00000000 },
- {0x0000989c, 0x00000000 },
- {0x0000989c, 0x00000000 },
- {0x0000989c, 0x00000000 },
- {0x0000989c, 0x00000000 },
- {0x0000989c, 0x00000000 },
- {0x0000989c, 0x00000000 },
- {0x0000989c, 0x00000000 },
- {0x0000989c, 0x00000000 },
- {0x0000989c, 0x00000000 },
- {0x0000989c, 0x000000c0 },
- {0x0000989c, 0x00000019 },
- {0x0000989c, 0x00000004 },
- {0x0000989c, 0x00000000 },
- {0x0000989c, 0x00000000 },
- {0x0000989c, 0x00000000 },
- {0x0000989c, 0x00000004 },
- {0x0000989c, 0x00000003 },
- {0x0000989c, 0x00000008 },
- {0x0000989c, 0x00000000 },
- {0x000098cc, 0x00000000 },
+ /* Addr allmodes */
+ {0x0000989c, 0x00000000},
+ {0x0000989c, 0x00000000},
+ {0x0000989c, 0x00000000},
+ {0x0000989c, 0x00000000},
+ {0x0000989c, 0x00000000},
+ {0x0000989c, 0x00000000},
+ {0x0000989c, 0x000000c0},
+ {0x0000989c, 0x00000018},
+ {0x0000989c, 0x00000004},
+ {0x0000989c, 0x00000000},
+ {0x0000989c, 0x00000000},
+ {0x0000989c, 0x00000000},
+ {0x0000989c, 0x00000000},
+ {0x0000989c, 0x00000000},
+ {0x0000989c, 0x00000000},
+ {0x0000989c, 0x00000000},
+ {0x0000989c, 0x00000000},
+ {0x0000989c, 0x00000000},
+ {0x0000989c, 0x00000000},
+ {0x0000989c, 0x00000000},
+ {0x0000989c, 0x00000000},
+ {0x0000989c, 0x000000c0},
+ {0x0000989c, 0x00000019},
+ {0x0000989c, 0x00000004},
+ {0x0000989c, 0x00000000},
+ {0x0000989c, 0x00000000},
+ {0x0000989c, 0x00000000},
+ {0x0000989c, 0x00000004},
+ {0x0000989c, 0x00000003},
+ {0x0000989c, 0x00000008},
+ {0x0000989c, 0x00000000},
+ {0x000098cc, 0x00000000},
};
-static const u32 ar5416Addac_91601_1[][2] = {
- {0x0000989c, 0x00000000 },
- {0x0000989c, 0x00000000 },
- {0x0000989c, 0x00000000 },
- {0x0000989c, 0x00000000 },
- {0x0000989c, 0x00000000 },
- {0x0000989c, 0x00000000 },
- {0x0000989c, 0x000000c0 },
- {0x0000989c, 0x00000018 },
- {0x0000989c, 0x00000004 },
- {0x0000989c, 0x00000000 },
- {0x0000989c, 0x00000000 },
- {0x0000989c, 0x00000000 },
- {0x0000989c, 0x00000000 },
- {0x0000989c, 0x00000000 },
- {0x0000989c, 0x00000000 },
- {0x0000989c, 0x00000000 },
- {0x0000989c, 0x00000000 },
- {0x0000989c, 0x00000000 },
- {0x0000989c, 0x00000000 },
- {0x0000989c, 0x00000000 },
- {0x0000989c, 0x00000000 },
- {0x0000989c, 0x000000c0 },
- {0x0000989c, 0x00000019 },
- {0x0000989c, 0x00000004 },
- {0x0000989c, 0x00000000 },
- {0x0000989c, 0x00000000 },
- {0x0000989c, 0x00000000 },
- {0x0000989c, 0x00000000 },
- {0x0000989c, 0x00000000 },
- {0x0000989c, 0x00000000 },
- {0x0000989c, 0x00000000 },
- {0x000098cc, 0x00000000 },
+static const u32 ar5416Addac_9160_1_1[][2] = {
+ /* Addr allmodes */
+ {0x0000989c, 0x00000000},
+ {0x0000989c, 0x00000000},
+ {0x0000989c, 0x00000000},
+ {0x0000989c, 0x00000000},
+ {0x0000989c, 0x00000000},
+ {0x0000989c, 0x00000000},
+ {0x0000989c, 0x000000c0},
+ {0x0000989c, 0x00000018},
+ {0x0000989c, 0x00000004},
+ {0x0000989c, 0x00000000},
+ {0x0000989c, 0x00000000},
+ {0x0000989c, 0x00000000},
+ {0x0000989c, 0x00000000},
+ {0x0000989c, 0x00000000},
+ {0x0000989c, 0x00000000},
+ {0x0000989c, 0x00000000},
+ {0x0000989c, 0x00000000},
+ {0x0000989c, 0x00000000},
+ {0x0000989c, 0x00000000},
+ {0x0000989c, 0x00000000},
+ {0x0000989c, 0x00000000},
+ {0x0000989c, 0x000000c0},
+ {0x0000989c, 0x00000019},
+ {0x0000989c, 0x00000004},
+ {0x0000989c, 0x00000000},
+ {0x0000989c, 0x00000000},
+ {0x0000989c, 0x00000000},
+ {0x0000989c, 0x00000000},
+ {0x0000989c, 0x00000000},
+ {0x0000989c, 0x00000000},
+ {0x0000989c, 0x00000000},
+ {0x000098cc, 0x00000000},
};
diff --git a/drivers/net/wireless/ath/ath9k/ar9002_calib.c b/drivers/net/wireless/ath/ath9k/ar9002_calib.c
index 5fdbb53b47e..dabafb874c3 100644
--- a/drivers/net/wireless/ath/ath9k/ar9002_calib.c
+++ b/drivers/net/wireless/ath/ath9k/ar9002_calib.c
@@ -239,7 +239,7 @@ static void ar9002_hw_iqcalibrate(struct ath_hw *ah, u8 numChains)
if (qCoff > 15)
qCoff = 15;
else if (qCoff <= -16)
- qCoff = 16;
+ qCoff = -16;
ath_print(common, ATH_DBG_CALIBRATE,
"Chn %d : iCoff = 0x%x qCoff = 0x%x\n",
diff --git a/drivers/net/wireless/ath/ath9k/ar9002_hw.c b/drivers/net/wireless/ath/ath9k/ar9002_hw.c
index a8a8cdc04af..303c63da5ea 100644
--- a/drivers/net/wireless/ath/ath9k/ar9002_hw.c
+++ b/drivers/net/wireless/ath/ath9k/ar9002_hw.c
@@ -18,6 +18,11 @@
#include "ar5008_initvals.h"
#include "ar9001_initvals.h"
#include "ar9002_initvals.h"
+#include "ar9002_phy.h"
+
+int modparam_force_new_ani;
+module_param_named(force_new_ani, modparam_force_new_ani, int, 0444);
+MODULE_PARM_DESC(nohwcrypt, "Force new ANI for AR5008, AR9001, AR9002");
/* General hardware code for the A5008/AR9001/AR9002 hadware families */
@@ -80,21 +85,6 @@ static void ar9002_hw_init_mode_regs(struct ath_hw *ah)
ar9287PciePhy_clkreq_always_on_L1_9287_1_1,
ARRAY_SIZE(ar9287PciePhy_clkreq_always_on_L1_9287_1_1),
2);
- } else if (AR_SREV_9287_10_OR_LATER(ah)) {
- INIT_INI_ARRAY(&ah->iniModes, ar9287Modes_9287_1_0,
- ARRAY_SIZE(ar9287Modes_9287_1_0), 6);
- INIT_INI_ARRAY(&ah->iniCommon, ar9287Common_9287_1_0,
- ARRAY_SIZE(ar9287Common_9287_1_0), 2);
-
- if (ah->config.pcie_clock_req)
- INIT_INI_ARRAY(&ah->iniPcieSerdes,
- ar9287PciePhy_clkreq_off_L1_9287_1_0,
- ARRAY_SIZE(ar9287PciePhy_clkreq_off_L1_9287_1_0), 2);
- else
- INIT_INI_ARRAY(&ah->iniPcieSerdes,
- ar9287PciePhy_clkreq_always_on_L1_9287_1_0,
- ARRAY_SIZE(ar9287PciePhy_clkreq_always_on_L1_9287_1_0),
- 2);
} else if (AR_SREV_9285_12_OR_LATER(ah)) {
@@ -113,21 +103,6 @@ static void ar9002_hw_init_mode_regs(struct ath_hw *ah)
ARRAY_SIZE(ar9285PciePhy_clkreq_always_on_L1_9285_1_2),
2);
}
- } else if (AR_SREV_9285_10_OR_LATER(ah)) {
- INIT_INI_ARRAY(&ah->iniModes, ar9285Modes_9285,
- ARRAY_SIZE(ar9285Modes_9285), 6);
- INIT_INI_ARRAY(&ah->iniCommon, ar9285Common_9285,
- ARRAY_SIZE(ar9285Common_9285), 2);
-
- if (ah->config.pcie_clock_req) {
- INIT_INI_ARRAY(&ah->iniPcieSerdes,
- ar9285PciePhy_clkreq_off_L1_9285,
- ARRAY_SIZE(ar9285PciePhy_clkreq_off_L1_9285), 2);
- } else {
- INIT_INI_ARRAY(&ah->iniPcieSerdes,
- ar9285PciePhy_clkreq_always_on_L1_9285,
- ARRAY_SIZE(ar9285PciePhy_clkreq_always_on_L1_9285), 2);
- }
} else if (AR_SREV_9280_20_OR_LATER(ah)) {
INIT_INI_ARRAY(&ah->iniModes, ar9280Modes_9280_2,
ARRAY_SIZE(ar9280Modes_9280_2), 6);
@@ -146,11 +121,6 @@ static void ar9002_hw_init_mode_regs(struct ath_hw *ah)
INIT_INI_ARRAY(&ah->iniModesAdditional,
ar9280Modes_fast_clock_9280_2,
ARRAY_SIZE(ar9280Modes_fast_clock_9280_2), 3);
- } else if (AR_SREV_9280_10_OR_LATER(ah)) {
- INIT_INI_ARRAY(&ah->iniModes, ar9280Modes_9280,
- ARRAY_SIZE(ar9280Modes_9280), 6);
- INIT_INI_ARRAY(&ah->iniCommon, ar9280Common_9280,
- ARRAY_SIZE(ar9280Common_9280), 2);
} else if (AR_SREV_9160_10_OR_LATER(ah)) {
INIT_INI_ARRAY(&ah->iniModes, ar5416Modes_9160,
ARRAY_SIZE(ar5416Modes_9160), 6);
@@ -174,8 +144,8 @@ static void ar9002_hw_init_mode_regs(struct ath_hw *ah)
ARRAY_SIZE(ar5416Bank7_9160), 2);
if (AR_SREV_9160_11(ah)) {
INIT_INI_ARRAY(&ah->iniAddac,
- ar5416Addac_91601_1,
- ARRAY_SIZE(ar5416Addac_91601_1), 2);
+ ar5416Addac_9160_1_1,
+ ARRAY_SIZE(ar5416Addac_9160_1_1), 2);
} else {
INIT_INI_ARRAY(&ah->iniAddac, ar5416Addac_9160,
ARRAY_SIZE(ar5416Addac_9160), 2);
@@ -234,12 +204,12 @@ void ar9002_hw_cck_chan14_spread(struct ath_hw *ah)
{
if (AR_SREV_9287_11_OR_LATER(ah)) {
INIT_INI_ARRAY(&ah->iniCckfirNormal,
- ar9287Common_normal_cck_fir_coeff_92871_1,
- ARRAY_SIZE(ar9287Common_normal_cck_fir_coeff_92871_1),
+ ar9287Common_normal_cck_fir_coeff_9287_1_1,
+ ARRAY_SIZE(ar9287Common_normal_cck_fir_coeff_9287_1_1),
2);
INIT_INI_ARRAY(&ah->iniCckfirJapan2484,
- ar9287Common_japan_2484_cck_fir_coeff_92871_1,
- ARRAY_SIZE(ar9287Common_japan_2484_cck_fir_coeff_92871_1),
+ ar9287Common_japan_2484_cck_fir_coeff_9287_1_1,
+ ARRAY_SIZE(ar9287Common_japan_2484_cck_fir_coeff_9287_1_1),
2);
}
}
@@ -300,10 +270,6 @@ static void ar9002_hw_init_mode_gain_regs(struct ath_hw *ah)
INIT_INI_ARRAY(&ah->iniModesRxGain,
ar9287Modes_rx_gain_9287_1_1,
ARRAY_SIZE(ar9287Modes_rx_gain_9287_1_1), 6);
- else if (AR_SREV_9287_10(ah))
- INIT_INI_ARRAY(&ah->iniModesRxGain,
- ar9287Modes_rx_gain_9287_1_0,
- ARRAY_SIZE(ar9287Modes_rx_gain_9287_1_0), 6);
else if (AR_SREV_9280_20(ah))
ar9280_20_hw_init_rxgain_ini(ah);
@@ -311,10 +277,6 @@ static void ar9002_hw_init_mode_gain_regs(struct ath_hw *ah)
INIT_INI_ARRAY(&ah->iniModesTxGain,
ar9287Modes_tx_gain_9287_1_1,
ARRAY_SIZE(ar9287Modes_tx_gain_9287_1_1), 6);
- } else if (AR_SREV_9287_10(ah)) {
- INIT_INI_ARRAY(&ah->iniModesTxGain,
- ar9287Modes_tx_gain_9287_1_0,
- ARRAY_SIZE(ar9287Modes_tx_gain_9287_1_0), 6);
} else if (AR_SREV_9280_20(ah)) {
ar9280_20_hw_init_txgain_ini(ah);
} else if (AR_SREV_9285_12_OR_LATER(ah)) {
@@ -384,29 +346,6 @@ static void ar9002_hw_configpcipowersave(struct ath_hw *ah,
REG_WRITE(ah, INI_RA(&ah->iniPcieSerdes, i, 0),
INI_RA(&ah->iniPcieSerdes, i, 1));
}
- } else if (AR_SREV_9280(ah) &&
- (ah->hw_version.macRev == AR_SREV_REVISION_9280_10)) {
- REG_WRITE(ah, AR_PCIE_SERDES, 0x9248fd00);
- REG_WRITE(ah, AR_PCIE_SERDES, 0x24924924);
-
- /* RX shut off when elecidle is asserted */
- REG_WRITE(ah, AR_PCIE_SERDES, 0xa8000019);
- REG_WRITE(ah, AR_PCIE_SERDES, 0x13160820);
- REG_WRITE(ah, AR_PCIE_SERDES, 0xe5980560);
-
- /* Shut off CLKREQ active in L1 */
- if (ah->config.pcie_clock_req)
- REG_WRITE(ah, AR_PCIE_SERDES, 0x401deffc);
- else
- REG_WRITE(ah, AR_PCIE_SERDES, 0x401deffd);
-
- REG_WRITE(ah, AR_PCIE_SERDES, 0x1aaabe40);
- REG_WRITE(ah, AR_PCIE_SERDES, 0xbe105554);
- REG_WRITE(ah, AR_PCIE_SERDES, 0x00043007);
-
- /* Load the new settings */
- REG_WRITE(ah, AR_PCIE_SERDES2, 0x00000000);
-
} else {
ENABLE_REGWRITE_BUFFER(ah);
@@ -436,55 +375,84 @@ static void ar9002_hw_configpcipowersave(struct ath_hw *ah,
}
udelay(1000);
+ }
- /* set bit 19 to allow forcing of pcie core into L1 state */
- REG_SET_BIT(ah, AR_PCIE_PM_CTRL, AR_PCIE_PM_CTRL_ENA);
+ if (power_off) {
+ /* clear bit 19 to disable L1 */
+ REG_CLR_BIT(ah, AR_PCIE_PM_CTRL, AR_PCIE_PM_CTRL_ENA);
+
+ val = REG_READ(ah, AR_WA);
- /* Several PCIe massages to ensure proper behaviour */
+ /*
+ * Set PCIe workaround bits
+ * In AR9280 and AR9285, bit 14 in WA register (disable L1)
+ * should only be set when device enters D3 and be
+ * cleared when device comes back to D0.
+ */
+ if (ah->config.pcie_waen) {
+ if (ah->config.pcie_waen & AR_WA_D3_L1_DISABLE)
+ val |= AR_WA_D3_L1_DISABLE;
+ } else {
+ if (((AR_SREV_9285(ah) ||
+ AR_SREV_9271(ah) ||
+ AR_SREV_9287(ah)) &&
+ (AR9285_WA_DEFAULT & AR_WA_D3_L1_DISABLE)) ||
+ (AR_SREV_9280(ah) &&
+ (AR9280_WA_DEFAULT & AR_WA_D3_L1_DISABLE))) {
+ val |= AR_WA_D3_L1_DISABLE;
+ }
+ }
+
+ if (AR_SREV_9280(ah) || AR_SREV_9285(ah) || AR_SREV_9287(ah)) {
+ /*
+ * Disable bit 6 and 7 before entering D3 to
+ * prevent system hang.
+ */
+ val &= ~(AR_WA_BIT6 | AR_WA_BIT7);
+ }
+
+ if (AR_SREV_9285E_20(ah))
+ val |= AR_WA_BIT23;
+
+ REG_WRITE(ah, AR_WA, val);
+ } else {
if (ah->config.pcie_waen) {
val = ah->config.pcie_waen;
if (!power_off)
val &= (~AR_WA_D3_L1_DISABLE);
} else {
- if (AR_SREV_9285(ah) || AR_SREV_9271(ah) ||
+ if (AR_SREV_9285(ah) ||
+ AR_SREV_9271(ah) ||
AR_SREV_9287(ah)) {
val = AR9285_WA_DEFAULT;
if (!power_off)
val &= (~AR_WA_D3_L1_DISABLE);
- } else if (AR_SREV_9280(ah)) {
+ }
+ else if (AR_SREV_9280(ah)) {
/*
- * On AR9280 chips bit 22 of 0x4004 needs to be
- * set otherwise card may disappear.
+ * For AR9280 chips, bit 22 of 0x4004
+ * needs to be set.
*/
val = AR9280_WA_DEFAULT;
if (!power_off)
val &= (~AR_WA_D3_L1_DISABLE);
- } else
+ } else {
val = AR_WA_DEFAULT;
+ }
+ }
+
+ /* WAR for ASPM system hang */
+ if (AR_SREV_9280(ah) || AR_SREV_9285(ah) || AR_SREV_9287(ah)) {
+ val |= (AR_WA_BIT6 | AR_WA_BIT7);
}
+ if (AR_SREV_9285E_20(ah))
+ val |= AR_WA_BIT23;
+
REG_WRITE(ah, AR_WA, val);
- }
- if (power_off) {
- /*
- * Set PCIe workaround bits
- * bit 14 in WA register (disable L1) should only
- * be set when device enters D3 and be cleared
- * when device comes back to D0.
- */
- if (ah->config.pcie_waen) {
- if (ah->config.pcie_waen & AR_WA_D3_L1_DISABLE)
- REG_SET_BIT(ah, AR_WA, AR_WA_D3_L1_DISABLE);
- } else {
- if (((AR_SREV_9285(ah) || AR_SREV_9271(ah) ||
- AR_SREV_9287(ah)) &&
- (AR9285_WA_DEFAULT & AR_WA_D3_L1_DISABLE)) ||
- (AR_SREV_9280(ah) &&
- (AR9280_WA_DEFAULT & AR_WA_D3_L1_DISABLE))) {
- REG_SET_BIT(ah, AR_WA, AR_WA_D3_L1_DISABLE);
- }
- }
+ /* set bit 19 to allow forcing of pcie core into L1 state */
+ REG_SET_BIT(ah, AR_PCIE_PM_CTRL, AR_PCIE_PM_CTRL_ENA);
}
}
@@ -536,18 +504,29 @@ int ar9002_hw_rf_claim(struct ath_hw *ah)
return 0;
}
+void ar9002_hw_enable_async_fifo(struct ath_hw *ah)
+{
+ if (AR_SREV_9287_13_OR_LATER(ah)) {
+ REG_SET_BIT(ah, AR_MAC_PCU_ASYNC_FIFO_REG3,
+ AR_MAC_PCU_ASYNC_FIFO_REG3_DATAPATH_SEL);
+ REG_SET_BIT(ah, AR_PHY_MODE, AR_PHY_MODE_ASYNCFIFO);
+ REG_CLR_BIT(ah, AR_MAC_PCU_ASYNC_FIFO_REG3,
+ AR_MAC_PCU_ASYNC_FIFO_REG3_SOFT_RESET);
+ REG_SET_BIT(ah, AR_MAC_PCU_ASYNC_FIFO_REG3,
+ AR_MAC_PCU_ASYNC_FIFO_REG3_SOFT_RESET);
+ }
+}
+
/*
- * Enable ASYNC FIFO
- *
* If Async FIFO is enabled, the following counters change as MAC now runs
* at 117 Mhz instead of 88/44MHz when async FIFO is disabled.
*
* The values below tested for ht40 2 chain.
* Overwrite the delay/timeouts initialized in process ini.
*/
-void ar9002_hw_enable_async_fifo(struct ath_hw *ah)
+void ar9002_hw_update_async_fifo(struct ath_hw *ah)
{
- if (AR_SREV_9287_12_OR_LATER(ah)) {
+ if (AR_SREV_9287_13_OR_LATER(ah)) {
REG_WRITE(ah, AR_D_GBL_IFS_SIFS,
AR_D_GBL_IFS_SIFS_ASYNC_FIFO_DUR);
REG_WRITE(ah, AR_D_GBL_IFS_SLOT,
@@ -571,9 +550,9 @@ void ar9002_hw_enable_async_fifo(struct ath_hw *ah)
*/
void ar9002_hw_enable_wep_aggregation(struct ath_hw *ah)
{
- if (AR_SREV_9287_12_OR_LATER(ah)) {
+ if (AR_SREV_9287_13_OR_LATER(ah)) {
REG_SET_BIT(ah, AR_PCU_MISC_MODE2,
- AR_PCU_MISC_MODE2_ENABLE_AGGWEP);
+ AR_PCU_MISC_MODE2_ENABLE_AGGWEP);
}
}
@@ -595,4 +574,9 @@ void ar9002_hw_attach_ops(struct ath_hw *ah)
ar9002_hw_attach_calib_ops(ah);
ar9002_hw_attach_mac_ops(ah);
+
+ if (modparam_force_new_ani)
+ ath9k_hw_attach_ani_ops_new(ah);
+ else
+ ath9k_hw_attach_ani_ops_old(ah);
}
diff --git a/drivers/net/wireless/ath/ath9k/ar9002_initvals.h b/drivers/net/wireless/ath/ath9k/ar9002_initvals.h
index dae7f3304eb..6203eed860d 100644
--- a/drivers/net/wireless/ath/ath9k/ar9002_initvals.h
+++ b/drivers/net/wireless/ath/ath9k/ar9002_initvals.h
@@ -14,5217 +14,3252 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-#ifndef INITVALS_9002_10_H
-#define INITVALS_9002_10_H
-
-static const u32 ar9280Modes_9280[][6] = {
- { 0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160, 0x000001e0 },
- { 0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c, 0x000001e0 },
- { 0x000010b0, 0x00000e60, 0x00001cc0, 0x00007c70, 0x00003e38, 0x00001180 },
- { 0x000010f0, 0x0000a000, 0x00014000, 0x00016000, 0x0000b000, 0x00014008 },
- { 0x00008014, 0x03e803e8, 0x07d007d0, 0x10801080, 0x08400840, 0x06e006e0 },
- { 0x0000801c, 0x128d8027, 0x128d804f, 0x12e00057, 0x12e0002b, 0x0988004f },
- { 0x00009804, 0x00000300, 0x000003c4, 0x000003c4, 0x00000300, 0x00000303 },
- { 0x00009820, 0x02020200, 0x02020200, 0x02020200, 0x02020200, 0x02020200 },
- { 0x00009824, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e },
- { 0x00009828, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001 },
- { 0x00009834, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e },
- { 0x00009838, 0x00000007, 0x00000007, 0x00000007, 0x00000007, 0x00000007 },
- { 0x00009844, 0x1372161e, 0x1372161e, 0x137216a0, 0x137216a0, 0x137216a0 },
- { 0x00009848, 0x00028566, 0x00028566, 0x00028563, 0x00028563, 0x00028563 },
- { 0x0000a848, 0x00028566, 0x00028566, 0x00028563, 0x00028563, 0x00028563 },
- { 0x00009850, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2 },
- { 0x00009858, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e },
- { 0x0000985c, 0x3139605e, 0x3139605e, 0x3139605e, 0x3139605e, 0x3139605e },
- { 0x00009860, 0x00049d18, 0x00049d18, 0x00049d20, 0x00049d20, 0x00049d18 },
- { 0x0000c864, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00 },
- { 0x00009868, 0x5ac64190, 0x5ac64190, 0x5ac64190, 0x5ac64190, 0x5ac64190 },
- { 0x0000986c, 0x06903081, 0x06903081, 0x06903881, 0x06903881, 0x06903881 },
- { 0x00009914, 0x000007d0, 0x000007d0, 0x00000898, 0x00000898, 0x000007d0 },
- { 0x00009918, 0x0000000a, 0x00000014, 0x00000016, 0x0000000b, 0x00000016 },
- { 0x00009924, 0xd00a8a07, 0xd00a8a07, 0xd00a8a0d, 0xd00a8a0d, 0xd00a8a0d },
- { 0x00009944, 0xdfbc1010, 0xdfbc1010, 0xdfbc1010, 0xdfbc1010, 0xdfbc1010 },
- { 0x00009960, 0x00000010, 0x00000010, 0x00000010, 0x00000010, 0x00000010 },
- { 0x0000a960, 0x00000010, 0x00000010, 0x00000010, 0x00000010, 0x00000010 },
- { 0x00009964, 0x00000210, 0x00000210, 0x00000210, 0x00000210, 0x00000210 },
- { 0x0000c9b8, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a },
- { 0x0000c9bc, 0x00000600, 0x00000600, 0x00000c00, 0x00000c00, 0x00000c00 },
- { 0x000099c0, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4 },
- { 0x000099c4, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77 },
- { 0x000099c8, 0x60f6532c, 0x60f6532c, 0x60f6532c, 0x60f6532c, 0x60f6532c },
- { 0x000099cc, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8 },
- { 0x000099d0, 0x00046384, 0x00046384, 0x00046384, 0x00046384, 0x00046384 },
- { 0x000099d4, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
- { 0x000099d8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
- { 0x00009a00, 0x00008184, 0x00008184, 0x00000214, 0x00000214, 0x00000214 },
- { 0x00009a04, 0x00008188, 0x00008188, 0x00000218, 0x00000218, 0x00000218 },
- { 0x00009a08, 0x0000818c, 0x0000818c, 0x00000224, 0x00000224, 0x00000224 },
- { 0x00009a0c, 0x00008190, 0x00008190, 0x00000228, 0x00000228, 0x00000228 },
- { 0x00009a10, 0x00008194, 0x00008194, 0x0000022c, 0x0000022c, 0x0000022c },
- { 0x00009a14, 0x00008200, 0x00008200, 0x00000230, 0x00000230, 0x00000230 },
- { 0x00009a18, 0x00008204, 0x00008204, 0x000002a4, 0x000002a4, 0x000002a4 },
- { 0x00009a1c, 0x00008208, 0x00008208, 0x000002a8, 0x000002a8, 0x000002a8 },
- { 0x00009a20, 0x0000820c, 0x0000820c, 0x000002ac, 0x000002ac, 0x000002ac },
- { 0x00009a24, 0x00008210, 0x00008210, 0x000002b0, 0x000002b0, 0x000002b0 },
- { 0x00009a28, 0x00008214, 0x00008214, 0x000002b4, 0x000002b4, 0x000002b4 },
- { 0x00009a2c, 0x00008280, 0x00008280, 0x000002b8, 0x000002b8, 0x000002b8 },
- { 0x00009a30, 0x00008284, 0x00008284, 0x00000390, 0x00000390, 0x00000390 },
- { 0x00009a34, 0x00008288, 0x00008288, 0x00000394, 0x00000394, 0x00000394 },
- { 0x00009a38, 0x0000828c, 0x0000828c, 0x00000398, 0x00000398, 0x00000398 },
- { 0x00009a3c, 0x00008290, 0x00008290, 0x00000334, 0x00000334, 0x00000334 },
- { 0x00009a40, 0x00008300, 0x00008300, 0x00000338, 0x00000338, 0x00000338 },
- { 0x00009a44, 0x00008304, 0x00008304, 0x000003ac, 0x000003ac, 0x000003ac },
- { 0x00009a48, 0x00008308, 0x00008308, 0x000003b0, 0x000003b0, 0x000003b0 },
- { 0x00009a4c, 0x0000830c, 0x0000830c, 0x000003b4, 0x000003b4, 0x000003b4 },
- { 0x00009a50, 0x00008310, 0x00008310, 0x000003b8, 0x000003b8, 0x000003b8 },
- { 0x00009a54, 0x00008314, 0x00008314, 0x000003a5, 0x000003a5, 0x000003a5 },
- { 0x00009a58, 0x00008380, 0x00008380, 0x000003a9, 0x000003a9, 0x000003a9 },
- { 0x00009a5c, 0x00008384, 0x00008384, 0x000003ad, 0x000003ad, 0x000003ad },
- { 0x00009a60, 0x00008388, 0x00008388, 0x00008194, 0x00008194, 0x00008194 },
- { 0x00009a64, 0x0000838c, 0x0000838c, 0x000081a0, 0x000081a0, 0x000081a0 },
- { 0x00009a68, 0x00008390, 0x00008390, 0x0000820c, 0x0000820c, 0x0000820c },
- { 0x00009a6c, 0x00008394, 0x00008394, 0x000081a8, 0x000081a8, 0x000081a8 },
- { 0x00009a70, 0x0000a380, 0x0000a380, 0x00008284, 0x00008284, 0x00008284 },
- { 0x00009a74, 0x0000a384, 0x0000a384, 0x00008288, 0x00008288, 0x00008288 },
- { 0x00009a78, 0x0000a388, 0x0000a388, 0x00008224, 0x00008224, 0x00008224 },
- { 0x00009a7c, 0x0000a38c, 0x0000a38c, 0x00008290, 0x00008290, 0x00008290 },
- { 0x00009a80, 0x0000a390, 0x0000a390, 0x00008300, 0x00008300, 0x00008300 },
- { 0x00009a84, 0x0000a394, 0x0000a394, 0x00008304, 0x00008304, 0x00008304 },
- { 0x00009a88, 0x0000a780, 0x0000a780, 0x00008308, 0x00008308, 0x00008308 },
- { 0x00009a8c, 0x0000a784, 0x0000a784, 0x0000830c, 0x0000830c, 0x0000830c },
- { 0x00009a90, 0x0000a788, 0x0000a788, 0x00008380, 0x00008380, 0x00008380 },
- { 0x00009a94, 0x0000a78c, 0x0000a78c, 0x00008384, 0x00008384, 0x00008384 },
- { 0x00009a98, 0x0000a790, 0x0000a790, 0x00008700, 0x00008700, 0x00008700 },
- { 0x00009a9c, 0x0000a794, 0x0000a794, 0x00008704, 0x00008704, 0x00008704 },
- { 0x00009aa0, 0x0000ab84, 0x0000ab84, 0x00008708, 0x00008708, 0x00008708 },
- { 0x00009aa4, 0x0000ab88, 0x0000ab88, 0x0000870c, 0x0000870c, 0x0000870c },
- { 0x00009aa8, 0x0000ab8c, 0x0000ab8c, 0x00008780, 0x00008780, 0x00008780 },
- { 0x00009aac, 0x0000ab90, 0x0000ab90, 0x00008784, 0x00008784, 0x00008784 },
- { 0x00009ab0, 0x0000ab94, 0x0000ab94, 0x00008b00, 0x00008b00, 0x00008b00 },
- { 0x00009ab4, 0x0000af80, 0x0000af80, 0x00008b04, 0x00008b04, 0x00008b04 },
- { 0x00009ab8, 0x0000af84, 0x0000af84, 0x00008b08, 0x00008b08, 0x00008b08 },
- { 0x00009abc, 0x0000af88, 0x0000af88, 0x00008b0c, 0x00008b0c, 0x00008b0c },
- { 0x00009ac0, 0x0000af8c, 0x0000af8c, 0x00008b80, 0x00008b80, 0x00008b80 },
- { 0x00009ac4, 0x0000af90, 0x0000af90, 0x00008b84, 0x00008b84, 0x00008b84 },
- { 0x00009ac8, 0x0000af94, 0x0000af94, 0x00008b88, 0x00008b88, 0x00008b88 },
- { 0x00009acc, 0x0000b380, 0x0000b380, 0x00008b8c, 0x00008b8c, 0x00008b8c },
- { 0x00009ad0, 0x0000b384, 0x0000b384, 0x00008b90, 0x00008b90, 0x00008b90 },
- { 0x00009ad4, 0x0000b388, 0x0000b388, 0x00008f80, 0x00008f80, 0x00008f80 },
- { 0x00009ad8, 0x0000b38c, 0x0000b38c, 0x00008f84, 0x00008f84, 0x00008f84 },
- { 0x00009adc, 0x0000b390, 0x0000b390, 0x00008f88, 0x00008f88, 0x00008f88 },
- { 0x00009ae0, 0x0000b394, 0x0000b394, 0x00008f8c, 0x00008f8c, 0x00008f8c },
- { 0x00009ae4, 0x0000b398, 0x0000b398, 0x00008f90, 0x00008f90, 0x00008f90 },
- { 0x00009ae8, 0x0000b780, 0x0000b780, 0x0000930c, 0x0000930c, 0x0000930c },
- { 0x00009aec, 0x0000b784, 0x0000b784, 0x00009310, 0x00009310, 0x00009310 },
- { 0x00009af0, 0x0000b788, 0x0000b788, 0x00009384, 0x00009384, 0x00009384 },
- { 0x00009af4, 0x0000b78c, 0x0000b78c, 0x00009388, 0x00009388, 0x00009388 },
- { 0x00009af8, 0x0000b790, 0x0000b790, 0x00009324, 0x00009324, 0x00009324 },
- { 0x00009afc, 0x0000b794, 0x0000b794, 0x00009704, 0x00009704, 0x00009704 },
- { 0x00009b00, 0x0000b798, 0x0000b798, 0x000096a4, 0x000096a4, 0x000096a4 },
- { 0x00009b04, 0x0000d784, 0x0000d784, 0x000096a8, 0x000096a8, 0x000096a8 },
- { 0x00009b08, 0x0000d788, 0x0000d788, 0x00009710, 0x00009710, 0x00009710 },
- { 0x00009b0c, 0x0000d78c, 0x0000d78c, 0x00009714, 0x00009714, 0x00009714 },
- { 0x00009b10, 0x0000d790, 0x0000d790, 0x00009720, 0x00009720, 0x00009720 },
- { 0x00009b14, 0x0000f780, 0x0000f780, 0x00009724, 0x00009724, 0x00009724 },
- { 0x00009b18, 0x0000f784, 0x0000f784, 0x00009728, 0x00009728, 0x00009728 },
- { 0x00009b1c, 0x0000f788, 0x0000f788, 0x0000972c, 0x0000972c, 0x0000972c },
- { 0x00009b20, 0x0000f78c, 0x0000f78c, 0x000097a0, 0x000097a0, 0x000097a0 },
- { 0x00009b24, 0x0000f790, 0x0000f790, 0x000097a4, 0x000097a4, 0x000097a4 },
- { 0x00009b28, 0x0000f794, 0x0000f794, 0x000097a8, 0x000097a8, 0x000097a8 },
- { 0x00009b2c, 0x0000f7a4, 0x0000f7a4, 0x000097b0, 0x000097b0, 0x000097b0 },
- { 0x00009b30, 0x0000f7a8, 0x0000f7a8, 0x000097b4, 0x000097b4, 0x000097b4 },
- { 0x00009b34, 0x0000f7ac, 0x0000f7ac, 0x000097b8, 0x000097b8, 0x000097b8 },
- { 0x00009b38, 0x0000f7b0, 0x0000f7b0, 0x000097a5, 0x000097a5, 0x000097a5 },
- { 0x00009b3c, 0x0000f7b4, 0x0000f7b4, 0x000097a9, 0x000097a9, 0x000097a9 },
- { 0x00009b40, 0x0000f7a1, 0x0000f7a1, 0x000097ad, 0x000097ad, 0x000097ad },
- { 0x00009b44, 0x0000f7a5, 0x0000f7a5, 0x000097b1, 0x000097b1, 0x000097b1 },
- { 0x00009b48, 0x0000f7a9, 0x0000f7a9, 0x000097b5, 0x000097b5, 0x000097b5 },
- { 0x00009b4c, 0x0000f7ad, 0x0000f7ad, 0x000097b9, 0x000097b9, 0x000097b9 },
- { 0x00009b50, 0x0000f7b1, 0x0000f7b1, 0x000097c5, 0x000097c5, 0x000097c5 },
- { 0x00009b54, 0x0000f7b5, 0x0000f7b5, 0x000097c9, 0x000097c9, 0x000097c9 },
- { 0x00009b58, 0x0000f7c5, 0x0000f7c5, 0x000097d1, 0x000097d1, 0x000097d1 },
- { 0x00009b5c, 0x0000f7c9, 0x0000f7c9, 0x000097d5, 0x000097d5, 0x000097d5 },
- { 0x00009b60, 0x0000f7cd, 0x0000f7cd, 0x000097d9, 0x000097d9, 0x000097d9 },
- { 0x00009b64, 0x0000f7d1, 0x0000f7d1, 0x000097c6, 0x000097c6, 0x000097c6 },
- { 0x00009b68, 0x0000f7d5, 0x0000f7d5, 0x000097ca, 0x000097ca, 0x000097ca },
- { 0x00009b6c, 0x0000f7c2, 0x0000f7c2, 0x000097ce, 0x000097ce, 0x000097ce },
- { 0x00009b70, 0x0000f7c6, 0x0000f7c6, 0x000097d2, 0x000097d2, 0x000097d2 },
- { 0x00009b74, 0x0000f7ca, 0x0000f7ca, 0x000097d6, 0x000097d6, 0x000097d6 },
- { 0x00009b78, 0x0000f7ce, 0x0000f7ce, 0x000097c3, 0x000097c3, 0x000097c3 },
- { 0x00009b7c, 0x0000f7d2, 0x0000f7d2, 0x000097c7, 0x000097c7, 0x000097c7 },
- { 0x00009b80, 0x0000f7d6, 0x0000f7d6, 0x000097cb, 0x000097cb, 0x000097cb },
- { 0x00009b84, 0x0000f7c3, 0x0000f7c3, 0x000097cf, 0x000097cf, 0x000097cf },
- { 0x00009b88, 0x0000f7c7, 0x0000f7c7, 0x000097d7, 0x000097d7, 0x000097d7 },
- { 0x00009b8c, 0x0000f7cb, 0x0000f7cb, 0x000097db, 0x000097db, 0x000097db },
- { 0x00009b90, 0x0000f7d3, 0x0000f7d3, 0x000097db, 0x000097db, 0x000097db },
- { 0x00009b94, 0x0000f7d7, 0x0000f7d7, 0x000097db, 0x000097db, 0x000097db },
- { 0x00009b98, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
- { 0x00009b9c, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
- { 0x00009ba0, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
- { 0x00009ba4, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
- { 0x00009ba8, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
- { 0x00009bac, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
- { 0x00009bb0, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
- { 0x00009bb4, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
- { 0x00009bb8, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
- { 0x00009bbc, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
- { 0x00009bc0, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
- { 0x00009bc4, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
- { 0x00009bc8, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
- { 0x00009bcc, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
- { 0x00009bd0, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
- { 0x00009bd4, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
- { 0x00009bd8, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
- { 0x00009bdc, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
- { 0x00009be0, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
- { 0x00009be4, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
- { 0x00009be8, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
- { 0x00009bec, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
- { 0x00009bf0, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
- { 0x00009bf4, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
- { 0x00009bf8, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
- { 0x00009bfc, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
- { 0x0000a204, 0x00000444, 0x00000444, 0x00000444, 0x00000444, 0x00000444 },
- { 0x0000a208, 0x803e4788, 0x803e4788, 0x803e4788, 0x803e4788, 0x803e4788 },
- { 0x0000a20c, 0x000c6019, 0x000c6019, 0x000c6019, 0x000c6019, 0x000c6019 },
- { 0x0000b20c, 0x000c6019, 0x000c6019, 0x000c6019, 0x000c6019, 0x000c6019 },
- { 0x0000a21c, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a },
- { 0x0000a230, 0x00000000, 0x00000000, 0x00000210, 0x00000108, 0x00000000 },
- { 0x0000a274, 0x0a19c652, 0x0a19c652, 0x0a1aa652, 0x0a1aa652, 0x0a1aa652 },
- { 0x0000a300, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
- { 0x0000a304, 0x00003002, 0x00003002, 0x00003002, 0x00003002, 0x00003002 },
- { 0x0000a308, 0x00006004, 0x00006004, 0x00008009, 0x00008009, 0x00008009 },
- { 0x0000a30c, 0x0000a006, 0x0000a006, 0x0000b00b, 0x0000b00b, 0x0000b00b },
- { 0x0000a310, 0x0000e012, 0x0000e012, 0x0000e012, 0x0000e012, 0x0000e012 },
- { 0x0000a314, 0x00011014, 0x00011014, 0x00012048, 0x00012048, 0x00012048 },
- { 0x0000a318, 0x0001504a, 0x0001504a, 0x0001604a, 0x0001604a, 0x0001604a },
- { 0x0000a31c, 0x0001904c, 0x0001904c, 0x0001a211, 0x0001a211, 0x0001a211 },
- { 0x0000a320, 0x0001c04e, 0x0001c04e, 0x0001e213, 0x0001e213, 0x0001e213 },
- { 0x0000a324, 0x00020092, 0x00020092, 0x0002121b, 0x0002121b, 0x0002121b },
- { 0x0000a328, 0x0002410a, 0x0002410a, 0x00024412, 0x00024412, 0x00024412 },
- { 0x0000a32c, 0x0002710c, 0x0002710c, 0x00028414, 0x00028414, 0x00028414 },
- { 0x0000a330, 0x0002b18b, 0x0002b18b, 0x0002b44a, 0x0002b44a, 0x0002b44a },
- { 0x0000a334, 0x0002e1cc, 0x0002e1cc, 0x00030649, 0x00030649, 0x00030649 },
- { 0x0000a338, 0x000321ec, 0x000321ec, 0x0003364b, 0x0003364b, 0x0003364b },
- { 0x0000a33c, 0x000321ec, 0x000321ec, 0x00038a49, 0x00038a49, 0x00038a49 },
- { 0x0000a340, 0x000321ec, 0x000321ec, 0x0003be48, 0x0003be48, 0x0003be48 },
- { 0x0000a344, 0x000321ec, 0x000321ec, 0x0003ee4a, 0x0003ee4a, 0x0003ee4a },
- { 0x0000a348, 0x000321ec, 0x000321ec, 0x00042e88, 0x00042e88, 0x00042e88 },
- { 0x0000a34c, 0x000321ec, 0x000321ec, 0x00046e8a, 0x00046e8a, 0x00046e8a },
- { 0x0000a350, 0x000321ec, 0x000321ec, 0x00049ec9, 0x00049ec9, 0x00049ec9 },
- { 0x0000a354, 0x000321ec, 0x000321ec, 0x0004bf42, 0x0004bf42, 0x0004bf42 },
- { 0x0000784c, 0x0e4f048c, 0x0e4f048c, 0x0e4d048c, 0x0e4d048c, 0x0e4d048c },
- { 0x00007854, 0x12031828, 0x12031828, 0x12035828, 0x12035828, 0x12035828 },
- { 0x00007870, 0x807ec400, 0x807ec400, 0x807ec000, 0x807ec000, 0x807ec000 },
- { 0x0000788c, 0x00010000, 0x00010000, 0x00110000, 0x00110000, 0x00110000 },
-};
-
-static const u32 ar9280Common_9280[][2] = {
- { 0x0000000c, 0x00000000 },
- { 0x00000030, 0x00020015 },
- { 0x00000034, 0x00000005 },
- { 0x00000040, 0x00000000 },
- { 0x00000044, 0x00000008 },
- { 0x00000048, 0x00000008 },
- { 0x0000004c, 0x00000010 },
- { 0x00000050, 0x00000000 },
- { 0x00000054, 0x0000001f },
- { 0x00000800, 0x00000000 },
- { 0x00000804, 0x00000000 },
- { 0x00000808, 0x00000000 },
- { 0x0000080c, 0x00000000 },
- { 0x00000810, 0x00000000 },
- { 0x00000814, 0x00000000 },
- { 0x00000818, 0x00000000 },
- { 0x0000081c, 0x00000000 },
- { 0x00000820, 0x00000000 },
- { 0x00000824, 0x00000000 },
- { 0x00001040, 0x002ffc0f },
- { 0x00001044, 0x002ffc0f },
- { 0x00001048, 0x002ffc0f },
- { 0x0000104c, 0x002ffc0f },
- { 0x00001050, 0x002ffc0f },
- { 0x00001054, 0x002ffc0f },
- { 0x00001058, 0x002ffc0f },
- { 0x0000105c, 0x002ffc0f },
- { 0x00001060, 0x002ffc0f },
- { 0x00001064, 0x002ffc0f },
- { 0x00001230, 0x00000000 },
- { 0x00001270, 0x00000000 },
- { 0x00001038, 0x00000000 },
- { 0x00001078, 0x00000000 },
- { 0x000010b8, 0x00000000 },
- { 0x000010f8, 0x00000000 },
- { 0x00001138, 0x00000000 },
- { 0x00001178, 0x00000000 },
- { 0x000011b8, 0x00000000 },
- { 0x000011f8, 0x00000000 },
- { 0x00001238, 0x00000000 },
- { 0x00001278, 0x00000000 },
- { 0x000012b8, 0x00000000 },
- { 0x000012f8, 0x00000000 },
- { 0x00001338, 0x00000000 },
- { 0x00001378, 0x00000000 },
- { 0x000013b8, 0x00000000 },
- { 0x000013f8, 0x00000000 },
- { 0x00001438, 0x00000000 },
- { 0x00001478, 0x00000000 },
- { 0x000014b8, 0x00000000 },
- { 0x000014f8, 0x00000000 },
- { 0x00001538, 0x00000000 },
- { 0x00001578, 0x00000000 },
- { 0x000015b8, 0x00000000 },
- { 0x000015f8, 0x00000000 },
- { 0x00001638, 0x00000000 },
- { 0x00001678, 0x00000000 },
- { 0x000016b8, 0x00000000 },
- { 0x000016f8, 0x00000000 },
- { 0x00001738, 0x00000000 },
- { 0x00001778, 0x00000000 },
- { 0x000017b8, 0x00000000 },
- { 0x000017f8, 0x00000000 },
- { 0x0000103c, 0x00000000 },
- { 0x0000107c, 0x00000000 },
- { 0x000010bc, 0x00000000 },
- { 0x000010fc, 0x00000000 },
- { 0x0000113c, 0x00000000 },
- { 0x0000117c, 0x00000000 },
- { 0x000011bc, 0x00000000 },
- { 0x000011fc, 0x00000000 },
- { 0x0000123c, 0x00000000 },
- { 0x0000127c, 0x00000000 },
- { 0x000012bc, 0x00000000 },
- { 0x000012fc, 0x00000000 },
- { 0x0000133c, 0x00000000 },
- { 0x0000137c, 0x00000000 },
- { 0x000013bc, 0x00000000 },
- { 0x000013fc, 0x00000000 },
- { 0x0000143c, 0x00000000 },
- { 0x0000147c, 0x00000000 },
- { 0x00004030, 0x00000002 },
- { 0x0000403c, 0x00000002 },
- { 0x00004024, 0x0000001f },
- { 0x00007010, 0x00000033 },
- { 0x00007038, 0x000004c2 },
- { 0x00008004, 0x00000000 },
- { 0x00008008, 0x00000000 },
- { 0x0000800c, 0x00000000 },
- { 0x00008018, 0x00000700 },
- { 0x00008020, 0x00000000 },
- { 0x00008038, 0x00000000 },
- { 0x0000803c, 0x00000000 },
- { 0x00008048, 0x40000000 },
- { 0x00008054, 0x00000000 },
- { 0x00008058, 0x00000000 },
- { 0x0000805c, 0x000fc78f },
- { 0x00008060, 0x0000000f },
- { 0x00008064, 0x00000000 },
- { 0x00008070, 0x00000000 },
- { 0x000080c0, 0x2a82301a },
- { 0x000080c4, 0x05dc01e0 },
- { 0x000080c8, 0x1f402710 },
- { 0x000080cc, 0x01f40000 },
- { 0x000080d0, 0x00001e00 },
- { 0x000080d4, 0x00000000 },
- { 0x000080d8, 0x00400000 },
- { 0x000080e0, 0xffffffff },
- { 0x000080e4, 0x0000ffff },
- { 0x000080e8, 0x003f3f3f },
- { 0x000080ec, 0x00000000 },
- { 0x000080f0, 0x00000000 },
- { 0x000080f4, 0x00000000 },
- { 0x000080f8, 0x00000000 },
- { 0x000080fc, 0x00020000 },
- { 0x00008100, 0x00020000 },
- { 0x00008104, 0x00000001 },
- { 0x00008108, 0x00000052 },
- { 0x0000810c, 0x00000000 },
- { 0x00008110, 0x00000168 },
- { 0x00008118, 0x000100aa },
- { 0x0000811c, 0x00003210 },
- { 0x00008120, 0x08f04800 },
- { 0x00008124, 0x00000000 },
- { 0x00008128, 0x00000000 },
- { 0x0000812c, 0x00000000 },
- { 0x00008130, 0x00000000 },
- { 0x00008134, 0x00000000 },
- { 0x00008138, 0x00000000 },
- { 0x0000813c, 0x00000000 },
- { 0x00008144, 0x00000000 },
- { 0x00008168, 0x00000000 },
- { 0x0000816c, 0x00000000 },
- { 0x00008170, 0x32143320 },
- { 0x00008174, 0xfaa4fa50 },
- { 0x00008178, 0x00000100 },
- { 0x0000817c, 0x00000000 },
- { 0x000081c4, 0x00000000 },
- { 0x000081d0, 0x00003210 },
- { 0x000081ec, 0x00000000 },
- { 0x000081f0, 0x00000000 },
- { 0x000081f4, 0x00000000 },
- { 0x000081f8, 0x00000000 },
- { 0x000081fc, 0x00000000 },
- { 0x00008200, 0x00000000 },
- { 0x00008204, 0x00000000 },
- { 0x00008208, 0x00000000 },
- { 0x0000820c, 0x00000000 },
- { 0x00008210, 0x00000000 },
- { 0x00008214, 0x00000000 },
- { 0x00008218, 0x00000000 },
- { 0x0000821c, 0x00000000 },
- { 0x00008220, 0x00000000 },
- { 0x00008224, 0x00000000 },
- { 0x00008228, 0x00000000 },
- { 0x0000822c, 0x00000000 },
- { 0x00008230, 0x00000000 },
- { 0x00008234, 0x00000000 },
- { 0x00008238, 0x00000000 },
- { 0x0000823c, 0x00000000 },
- { 0x00008240, 0x00100000 },
- { 0x00008244, 0x0010f400 },
- { 0x00008248, 0x00000100 },
- { 0x0000824c, 0x0001e800 },
- { 0x00008250, 0x00000000 },
- { 0x00008254, 0x00000000 },
- { 0x00008258, 0x00000000 },
- { 0x0000825c, 0x400000ff },
- { 0x00008260, 0x00080922 },
- { 0x00008270, 0x00000000 },
- { 0x00008274, 0x40000000 },
- { 0x00008278, 0x003e4180 },
- { 0x0000827c, 0x00000000 },
- { 0x00008284, 0x0000002c },
- { 0x00008288, 0x0000002c },
- { 0x0000828c, 0x00000000 },
- { 0x00008294, 0x00000000 },
- { 0x00008298, 0x00000000 },
- { 0x00008300, 0x00000000 },
- { 0x00008304, 0x00000000 },
- { 0x00008308, 0x00000000 },
- { 0x0000830c, 0x00000000 },
- { 0x00008310, 0x00000000 },
- { 0x00008314, 0x00000000 },
- { 0x00008318, 0x00000000 },
- { 0x00008328, 0x00000000 },
- { 0x0000832c, 0x00000007 },
- { 0x00008330, 0x00000302 },
- { 0x00008334, 0x00000e00 },
- { 0x00008338, 0x00000000 },
- { 0x0000833c, 0x00000000 },
- { 0x00008340, 0x000107ff },
- { 0x00008344, 0x00000000 },
- { 0x00009808, 0x00000000 },
- { 0x0000980c, 0xaf268e30 },
- { 0x00009810, 0xfd14e000 },
- { 0x00009814, 0x9c0a9f6b },
- { 0x0000981c, 0x00000000 },
- { 0x0000982c, 0x0000a000 },
- { 0x00009830, 0x00000000 },
- { 0x0000983c, 0x00200400 },
- { 0x00009840, 0x206a01ae },
- { 0x0000984c, 0x0040233c },
- { 0x0000a84c, 0x0040233c },
- { 0x00009854, 0x00000044 },
- { 0x00009900, 0x00000000 },
- { 0x00009904, 0x00000000 },
- { 0x00009908, 0x00000000 },
- { 0x0000990c, 0x00000000 },
- { 0x0000991c, 0x10000fff },
- { 0x00009920, 0x04900000 },
- { 0x0000a920, 0x04900000 },
- { 0x00009928, 0x00000001 },
- { 0x0000992c, 0x00000004 },
- { 0x00009934, 0x1e1f2022 },
- { 0x00009938, 0x0a0b0c0d },
- { 0x0000993c, 0x00000000 },
- { 0x00009948, 0x9280c00a },
- { 0x0000994c, 0x00020028 },
- { 0x00009954, 0xe250a51e },
- { 0x00009958, 0x3388ffff },
- { 0x00009940, 0x00781204 },
- { 0x0000c95c, 0x004b6a8e },
- { 0x0000c968, 0x000003ce },
- { 0x00009970, 0x190fb514 },
- { 0x00009974, 0x00000000 },
- { 0x00009978, 0x00000001 },
- { 0x0000997c, 0x00000000 },
- { 0x00009980, 0x00000000 },
- { 0x00009984, 0x00000000 },
- { 0x00009988, 0x00000000 },
- { 0x0000998c, 0x00000000 },
- { 0x00009990, 0x00000000 },
- { 0x00009994, 0x00000000 },
- { 0x00009998, 0x00000000 },
- { 0x0000999c, 0x00000000 },
- { 0x000099a0, 0x00000000 },
- { 0x000099a4, 0x00000001 },
- { 0x000099a8, 0x201fff00 },
- { 0x000099ac, 0x006f00c4 },
- { 0x000099b0, 0x03051000 },
- { 0x000099b4, 0x00000820 },
- { 0x000099dc, 0x00000000 },
- { 0x000099e0, 0x00000000 },
- { 0x000099e4, 0xaaaaaaaa },
- { 0x000099e8, 0x3c466478 },
- { 0x000099ec, 0x0cc80caa },
- { 0x000099fc, 0x00001042 },
- { 0x0000a210, 0x4080a333 },
- { 0x0000a214, 0x40206c10 },
- { 0x0000a218, 0x009c4060 },
- { 0x0000a220, 0x01834061 },
- { 0x0000a224, 0x00000400 },
- { 0x0000a228, 0x000003b5 },
- { 0x0000a22c, 0x23277200 },
- { 0x0000a234, 0x20202020 },
- { 0x0000a238, 0x20202020 },
- { 0x0000a23c, 0x13c889af },
- { 0x0000a240, 0x38490a20 },
- { 0x0000a244, 0x00007bb6 },
- { 0x0000a248, 0x0fff3ffc },
- { 0x0000a24c, 0x00000001 },
- { 0x0000a250, 0x001da000 },
- { 0x0000a254, 0x00000000 },
- { 0x0000a258, 0x0cdbd380 },
- { 0x0000a25c, 0x0f0f0f01 },
- { 0x0000a260, 0xdfa91f01 },
- { 0x0000a268, 0x00000000 },
- { 0x0000a26c, 0x0ebae9c6 },
- { 0x0000b26c, 0x0ebae9c6 },
- { 0x0000d270, 0x00820820 },
- { 0x0000a278, 0x1ce739ce },
- { 0x0000a27c, 0x050701ce },
- { 0x0000a358, 0x7999aa0f },
- { 0x0000d35c, 0x07ffffef },
- { 0x0000d360, 0x0fffffe7 },
- { 0x0000d364, 0x17ffffe5 },
- { 0x0000d368, 0x1fffffe4 },
- { 0x0000d36c, 0x37ffffe3 },
- { 0x0000d370, 0x3fffffe3 },
- { 0x0000d374, 0x57ffffe3 },
- { 0x0000d378, 0x5fffffe2 },
- { 0x0000d37c, 0x7fffffe2 },
- { 0x0000d380, 0x7f3c7bba },
- { 0x0000d384, 0xf3307ff0 },
- { 0x0000a388, 0x0c000000 },
- { 0x0000a38c, 0x20202020 },
- { 0x0000a390, 0x20202020 },
- { 0x0000a394, 0x1ce739ce },
- { 0x0000a398, 0x000001ce },
- { 0x0000a39c, 0x00000001 },
- { 0x0000a3a0, 0x00000000 },
- { 0x0000a3a4, 0x00000000 },
- { 0x0000a3a8, 0x00000000 },
- { 0x0000a3ac, 0x00000000 },
- { 0x0000a3b0, 0x00000000 },
- { 0x0000a3b4, 0x00000000 },
- { 0x0000a3b8, 0x00000000 },
- { 0x0000a3bc, 0x00000000 },
- { 0x0000a3c0, 0x00000000 },
- { 0x0000a3c4, 0x00000000 },
- { 0x0000a3c8, 0x00000246 },
- { 0x0000a3cc, 0x20202020 },
- { 0x0000a3d0, 0x20202020 },
- { 0x0000a3d4, 0x20202020 },
- { 0x0000a3dc, 0x1ce739ce },
- { 0x0000a3e0, 0x000001ce },
- { 0x0000a3e4, 0x00000000 },
- { 0x0000a3e8, 0x18c43433 },
- { 0x0000a3ec, 0x00f38081 },
- { 0x00007800, 0x00040000 },
- { 0x00007804, 0xdb005012 },
- { 0x00007808, 0x04924914 },
- { 0x0000780c, 0x21084210 },
- { 0x00007810, 0x6d801300 },
- { 0x00007814, 0x0019beff },
- { 0x00007818, 0x07e40000 },
- { 0x0000781c, 0x00492000 },
- { 0x00007820, 0x92492480 },
- { 0x00007824, 0x00040000 },
- { 0x00007828, 0xdb005012 },
- { 0x0000782c, 0x04924914 },
- { 0x00007830, 0x21084210 },
- { 0x00007834, 0x6d801300 },
- { 0x00007838, 0x0019beff },
- { 0x0000783c, 0x07e40000 },
- { 0x00007840, 0x00492000 },
- { 0x00007844, 0x92492480 },
- { 0x00007848, 0x00120000 },
- { 0x00007850, 0x54214514 },
- { 0x00007858, 0x92592692 },
- { 0x00007860, 0x52802000 },
- { 0x00007864, 0x0a8e370e },
- { 0x00007868, 0xc0102850 },
- { 0x0000786c, 0x812d4000 },
- { 0x00007874, 0x001b6db0 },
- { 0x00007878, 0x00376b63 },
- { 0x0000787c, 0x06db6db6 },
- { 0x00007880, 0x006d8000 },
- { 0x00007884, 0xffeffffe },
- { 0x00007888, 0xffeffffe },
- { 0x00007890, 0x00060aeb },
- { 0x00007894, 0x5a108000 },
- { 0x00007898, 0x2a850160 },
-};
-
-/* XXX 9280 2 */
static const u32 ar9280Modes_9280_2[][6] = {
- { 0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160, 0x000001e0 },
- { 0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c, 0x000001e0 },
- { 0x000010b0, 0x00000e60, 0x00001cc0, 0x00007c70, 0x00003e38, 0x00001180 },
- { 0x000010f0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000008 },
- { 0x00008014, 0x03e803e8, 0x07d007d0, 0x10801600, 0x08400b00, 0x06e006e0 },
- { 0x0000801c, 0x128d8027, 0x128d804f, 0x12e00057, 0x12e0002b, 0x0988004f },
- { 0x00008120, 0x08f04800, 0x08f04800, 0x08f04810, 0x08f04810, 0x08f04810 },
- { 0x000081d0, 0x00003210, 0x00003210, 0x0000320a, 0x0000320a, 0x0000320a },
- { 0x00008318, 0x00003e80, 0x00007d00, 0x00006880, 0x00003440, 0x00006880 },
- { 0x00009804, 0x00000300, 0x000003c4, 0x000003c4, 0x00000300, 0x00000303 },
- { 0x00009820, 0x02020200, 0x02020200, 0x02020200, 0x02020200, 0x02020200 },
- { 0x00009824, 0x01000e0e, 0x01000e0e, 0x01000e0e, 0x01000e0e, 0x01000e0e },
- { 0x00009828, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001 },
- { 0x00009834, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e },
- { 0x00009838, 0x00000007, 0x00000007, 0x00000007, 0x00000007, 0x00000007 },
- { 0x00009840, 0x206a022e, 0x206a022e, 0x206a012e, 0x206a012e, 0x206a012e },
- { 0x00009844, 0x0372161e, 0x0372161e, 0x037216a0, 0x037216a0, 0x037216a0 },
- { 0x00009850, 0x6c4000e2, 0x6d4000e2, 0x6d4000e2, 0x6c4000e2, 0x6c4000e2 },
- { 0x00009858, 0x7ec88d2e, 0x7ec88d2e, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e },
- { 0x0000985c, 0x31395d5e, 0x3139605e, 0x3139605e, 0x31395d5e, 0x31395d5e },
- { 0x00009860, 0x00048d18, 0x00048d18, 0x00048d20, 0x00048d20, 0x00048d18 },
- { 0x00009864, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00 },
- { 0x00009868, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0 },
- { 0x0000986c, 0x06903081, 0x06903081, 0x06903881, 0x06903881, 0x06903881 },
- { 0x00009914, 0x000007d0, 0x00000fa0, 0x00001130, 0x00000898, 0x000007d0 },
- { 0x00009918, 0x0000000a, 0x00000014, 0x00000268, 0x0000000b, 0x00000016 },
- { 0x00009924, 0xd00a8a0b, 0xd00a8a0b, 0xd00a8a0d, 0xd00a8a0d, 0xd00a8a0d },
- { 0x00009944, 0xffbc1010, 0xffbc1010, 0xffbc1010, 0xffbc1010, 0xffbc1010 },
- { 0x00009960, 0x00000010, 0x00000010, 0x00000010, 0x00000010, 0x00000010 },
- { 0x0000a960, 0x00000010, 0x00000010, 0x00000010, 0x00000010, 0x00000010 },
- { 0x00009964, 0x00000210, 0x00000210, 0x00000210, 0x00000210, 0x00000210 },
- { 0x0000c968, 0x000003b5, 0x000003b5, 0x000003ce, 0x000003ce, 0x000003ce },
- { 0x000099b8, 0x0000001c, 0x0000001c, 0x0000001c, 0x0000001c, 0x0000001c },
- { 0x000099bc, 0x00000a00, 0x00000a00, 0x00000c00, 0x00000c00, 0x00000c00 },
- { 0x000099c0, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4 },
- { 0x000099c4, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77 },
- { 0x000099c8, 0x60f65329, 0x60f65329, 0x60f65329, 0x60f65329, 0x60f65329 },
- { 0x000099cc, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8 },
- { 0x000099d0, 0x00046384, 0x00046384, 0x00046384, 0x00046384, 0x00046384 },
- { 0x000099d4, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
- { 0x000099d8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
- { 0x0000a204, 0x00000444, 0x00000444, 0x00000444, 0x00000444, 0x00000444 },
- { 0x0000a20c, 0x00000014, 0x00000014, 0x0001f019, 0x0001f019, 0x0001f019 },
- { 0x0000b20c, 0x00000014, 0x00000014, 0x0001f019, 0x0001f019, 0x0001f019 },
- { 0x0000a21c, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a },
- { 0x0000a230, 0x00000000, 0x00000000, 0x00000210, 0x00000108, 0x00000000 },
- { 0x0000a23c, 0x13c88000, 0x13c88000, 0x13c88001, 0x13c88000, 0x13c88000 },
- { 0x0000a250, 0x001ff000, 0x001ff000, 0x0004a000, 0x0004a000, 0x0004a000 },
- { 0x0000a358, 0x7999aa02, 0x7999aa02, 0x7999aa0e, 0x7999aa0e, 0x7999aa0e },
- { 0x0000a388, 0x0c000000, 0x0c000000, 0x08000000, 0x0c000000, 0x0c000000 },
- { 0x0000a3d8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
- { 0x00007894, 0x5a508000, 0x5a508000, 0x5a508000, 0x5a508000, 0x5a508000 },
+ {0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160, 0x000001e0},
+ {0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c, 0x000001e0},
+ {0x000010b0, 0x00000e60, 0x00001cc0, 0x00007c70, 0x00003e38, 0x00001180},
+ {0x000010f0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000008},
+ {0x00008014, 0x03e803e8, 0x07d007d0, 0x10801600, 0x08400b00, 0x06e006e0},
+ {0x0000801c, 0x128d8027, 0x128d804f, 0x12e00057, 0x12e0002b, 0x0988004f},
+ {0x00008120, 0x08f04800, 0x08f04800, 0x08f04810, 0x08f04810, 0x08f04810},
+ {0x000081d0, 0x00003210, 0x00003210, 0x0000320a, 0x0000320a, 0x0000320a},
+ {0x00008318, 0x00003e80, 0x00007d00, 0x00006880, 0x00003440, 0x00006880},
+ {0x00009804, 0x00000300, 0x000003c4, 0x000003c4, 0x00000300, 0x00000303},
+ {0x00009820, 0x02020200, 0x02020200, 0x02020200, 0x02020200, 0x02020200},
+ {0x00009824, 0x01000e0e, 0x01000e0e, 0x01000e0e, 0x01000e0e, 0x01000e0e},
+ {0x00009828, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001},
+ {0x00009834, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e},
+ {0x00009838, 0x00000007, 0x00000007, 0x00000007, 0x00000007, 0x00000007},
+ {0x00009840, 0x206a022e, 0x206a022e, 0x206a012e, 0x206a012e, 0x206a012e},
+ {0x00009844, 0x0372161e, 0x0372161e, 0x037216a0, 0x037216a0, 0x037216a0},
+ {0x00009850, 0x6c4000e2, 0x6d4000e2, 0x6d4000e2, 0x6c4000e2, 0x6c4000e2},
+ {0x00009858, 0x7ec88d2e, 0x7ec88d2e, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e},
+ {0x0000985c, 0x31395d5e, 0x3139605e, 0x3139605e, 0x31395d5e, 0x31395d5e},
+ {0x00009860, 0x00048d18, 0x00048d18, 0x00048d20, 0x00048d20, 0x00048d18},
+ {0x00009864, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00},
+ {0x00009868, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0},
+ {0x0000986c, 0x06903081, 0x06903081, 0x06903881, 0x06903881, 0x06903881},
+ {0x00009914, 0x000007d0, 0x00000fa0, 0x00001130, 0x00000898, 0x000007d0},
+ {0x00009918, 0x0000000a, 0x00000014, 0x00000268, 0x0000000b, 0x00000016},
+ {0x00009924, 0xd00a8a0b, 0xd00a8a0b, 0xd00a8a0d, 0xd00a8a0d, 0xd00a8a0d},
+ {0x00009944, 0xffbc1010, 0xffbc1010, 0xffbc1010, 0xffbc1010, 0xffbc1010},
+ {0x00009960, 0x00000010, 0x00000010, 0x00000010, 0x00000010, 0x00000010},
+ {0x0000a960, 0x00000010, 0x00000010, 0x00000010, 0x00000010, 0x00000010},
+ {0x00009964, 0x00000210, 0x00000210, 0x00000210, 0x00000210, 0x00000210},
+ {0x0000c968, 0x000003b5, 0x000003b5, 0x000003ce, 0x000003ce, 0x000003ce},
+ {0x000099b8, 0x0000001c, 0x0000001c, 0x0000001c, 0x0000001c, 0x0000001c},
+ {0x000099bc, 0x00000a00, 0x00000a00, 0x00000c00, 0x00000c00, 0x00000c00},
+ {0x000099c0, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4},
+ {0x0000a204, 0x00000444, 0x00000444, 0x00000444, 0x00000444, 0x00000444},
+ {0x0000a20c, 0x00000014, 0x00000014, 0x0001f019, 0x0001f019, 0x0001f019},
+ {0x0000b20c, 0x00000014, 0x00000014, 0x0001f019, 0x0001f019, 0x0001f019},
+ {0x0000a21c, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a},
+ {0x0000a230, 0x00000000, 0x00000000, 0x00000210, 0x00000108, 0x00000000},
+ {0x0000a23c, 0x13c88000, 0x13c88000, 0x13c88001, 0x13c88000, 0x13c88000},
+ {0x0000a250, 0x001ff000, 0x001ff000, 0x0004a000, 0x0004a000, 0x0004a000},
+ {0x0000a358, 0x7999aa02, 0x7999aa02, 0x7999aa0e, 0x7999aa0e, 0x7999aa0e},
+ {0x0000a388, 0x0c000000, 0x0c000000, 0x08000000, 0x0c000000, 0x0c000000},
+ {0x0000a3d8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+ {0x00007894, 0x5a508000, 0x5a508000, 0x5a508000, 0x5a508000, 0x5a508000},
};
static const u32 ar9280Common_9280_2[][2] = {
- { 0x0000000c, 0x00000000 },
- { 0x00000030, 0x00020015 },
- { 0x00000034, 0x00000005 },
- { 0x00000040, 0x00000000 },
- { 0x00000044, 0x00000008 },
- { 0x00000048, 0x00000008 },
- { 0x0000004c, 0x00000010 },
- { 0x00000050, 0x00000000 },
- { 0x00000054, 0x0000001f },
- { 0x00000800, 0x00000000 },
- { 0x00000804, 0x00000000 },
- { 0x00000808, 0x00000000 },
- { 0x0000080c, 0x00000000 },
- { 0x00000810, 0x00000000 },
- { 0x00000814, 0x00000000 },
- { 0x00000818, 0x00000000 },
- { 0x0000081c, 0x00000000 },
- { 0x00000820, 0x00000000 },
- { 0x00000824, 0x00000000 },
- { 0x00001040, 0x002ffc0f },
- { 0x00001044, 0x002ffc0f },
- { 0x00001048, 0x002ffc0f },
- { 0x0000104c, 0x002ffc0f },
- { 0x00001050, 0x002ffc0f },
- { 0x00001054, 0x002ffc0f },
- { 0x00001058, 0x002ffc0f },
- { 0x0000105c, 0x002ffc0f },
- { 0x00001060, 0x002ffc0f },
- { 0x00001064, 0x002ffc0f },
- { 0x00001230, 0x00000000 },
- { 0x00001270, 0x00000000 },
- { 0x00001038, 0x00000000 },
- { 0x00001078, 0x00000000 },
- { 0x000010b8, 0x00000000 },
- { 0x000010f8, 0x00000000 },
- { 0x00001138, 0x00000000 },
- { 0x00001178, 0x00000000 },
- { 0x000011b8, 0x00000000 },
- { 0x000011f8, 0x00000000 },
- { 0x00001238, 0x00000000 },
- { 0x00001278, 0x00000000 },
- { 0x000012b8, 0x00000000 },
- { 0x000012f8, 0x00000000 },
- { 0x00001338, 0x00000000 },
- { 0x00001378, 0x00000000 },
- { 0x000013b8, 0x00000000 },
- { 0x000013f8, 0x00000000 },
- { 0x00001438, 0x00000000 },
- { 0x00001478, 0x00000000 },
- { 0x000014b8, 0x00000000 },
- { 0x000014f8, 0x00000000 },
- { 0x00001538, 0x00000000 },
- { 0x00001578, 0x00000000 },
- { 0x000015b8, 0x00000000 },
- { 0x000015f8, 0x00000000 },
- { 0x00001638, 0x00000000 },
- { 0x00001678, 0x00000000 },
- { 0x000016b8, 0x00000000 },
- { 0x000016f8, 0x00000000 },
- { 0x00001738, 0x00000000 },
- { 0x00001778, 0x00000000 },
- { 0x000017b8, 0x00000000 },
- { 0x000017f8, 0x00000000 },
- { 0x0000103c, 0x00000000 },
- { 0x0000107c, 0x00000000 },
- { 0x000010bc, 0x00000000 },
- { 0x000010fc, 0x00000000 },
- { 0x0000113c, 0x00000000 },
- { 0x0000117c, 0x00000000 },
- { 0x000011bc, 0x00000000 },
- { 0x000011fc, 0x00000000 },
- { 0x0000123c, 0x00000000 },
- { 0x0000127c, 0x00000000 },
- { 0x000012bc, 0x00000000 },
- { 0x000012fc, 0x00000000 },
- { 0x0000133c, 0x00000000 },
- { 0x0000137c, 0x00000000 },
- { 0x000013bc, 0x00000000 },
- { 0x000013fc, 0x00000000 },
- { 0x0000143c, 0x00000000 },
- { 0x0000147c, 0x00000000 },
- { 0x00004030, 0x00000002 },
- { 0x0000403c, 0x00000002 },
- { 0x00004024, 0x0000001f },
- { 0x00004060, 0x00000000 },
- { 0x00004064, 0x00000000 },
- { 0x00007010, 0x00000033 },
- { 0x00007034, 0x00000002 },
- { 0x00007038, 0x000004c2 },
- { 0x00008004, 0x00000000 },
- { 0x00008008, 0x00000000 },
- { 0x0000800c, 0x00000000 },
- { 0x00008018, 0x00000700 },
- { 0x00008020, 0x00000000 },
- { 0x00008038, 0x00000000 },
- { 0x0000803c, 0x00000000 },
- { 0x00008048, 0x40000000 },
- { 0x00008054, 0x00000000 },
- { 0x00008058, 0x00000000 },
- { 0x0000805c, 0x000fc78f },
- { 0x00008060, 0x0000000f },
- { 0x00008064, 0x00000000 },
- { 0x00008070, 0x00000000 },
- { 0x000080c0, 0x2a80001a },
- { 0x000080c4, 0x05dc01e0 },
- { 0x000080c8, 0x1f402710 },
- { 0x000080cc, 0x01f40000 },
- { 0x000080d0, 0x00001e00 },
- { 0x000080d4, 0x00000000 },
- { 0x000080d8, 0x00400000 },
- { 0x000080e0, 0xffffffff },
- { 0x000080e4, 0x0000ffff },
- { 0x000080e8, 0x003f3f3f },
- { 0x000080ec, 0x00000000 },
- { 0x000080f0, 0x00000000 },
- { 0x000080f4, 0x00000000 },
- { 0x000080f8, 0x00000000 },
- { 0x000080fc, 0x00020000 },
- { 0x00008100, 0x00020000 },
- { 0x00008104, 0x00000001 },
- { 0x00008108, 0x00000052 },
- { 0x0000810c, 0x00000000 },
- { 0x00008110, 0x00000168 },
- { 0x00008118, 0x000100aa },
- { 0x0000811c, 0x00003210 },
- { 0x00008124, 0x00000000 },
- { 0x00008128, 0x00000000 },
- { 0x0000812c, 0x00000000 },
- { 0x00008130, 0x00000000 },
- { 0x00008134, 0x00000000 },
- { 0x00008138, 0x00000000 },
- { 0x0000813c, 0x00000000 },
- { 0x00008144, 0xffffffff },
- { 0x00008168, 0x00000000 },
- { 0x0000816c, 0x00000000 },
- { 0x00008170, 0x32143320 },
- { 0x00008174, 0xfaa4fa50 },
- { 0x00008178, 0x00000100 },
- { 0x0000817c, 0x00000000 },
- { 0x000081c0, 0x00000000 },
- { 0x000081ec, 0x00000000 },
- { 0x000081f0, 0x00000000 },
- { 0x000081f4, 0x00000000 },
- { 0x000081f8, 0x00000000 },
- { 0x000081fc, 0x00000000 },
- { 0x00008200, 0x00000000 },
- { 0x00008204, 0x00000000 },
- { 0x00008208, 0x00000000 },
- { 0x0000820c, 0x00000000 },
- { 0x00008210, 0x00000000 },
- { 0x00008214, 0x00000000 },
- { 0x00008218, 0x00000000 },
- { 0x0000821c, 0x00000000 },
- { 0x00008220, 0x00000000 },
- { 0x00008224, 0x00000000 },
- { 0x00008228, 0x00000000 },
- { 0x0000822c, 0x00000000 },
- { 0x00008230, 0x00000000 },
- { 0x00008234, 0x00000000 },
- { 0x00008238, 0x00000000 },
- { 0x0000823c, 0x00000000 },
- { 0x00008240, 0x00100000 },
- { 0x00008244, 0x0010f400 },
- { 0x00008248, 0x00000100 },
- { 0x0000824c, 0x0001e800 },
- { 0x00008250, 0x00000000 },
- { 0x00008254, 0x00000000 },
- { 0x00008258, 0x00000000 },
- { 0x0000825c, 0x400000ff },
- { 0x00008260, 0x00080922 },
- { 0x00008264, 0x88a00010 },
- { 0x00008270, 0x00000000 },
- { 0x00008274, 0x40000000 },
- { 0x00008278, 0x003e4180 },
- { 0x0000827c, 0x00000000 },
- { 0x00008284, 0x0000002c },
- { 0x00008288, 0x0000002c },
- { 0x0000828c, 0x00000000 },
- { 0x00008294, 0x00000000 },
- { 0x00008298, 0x00000000 },
- { 0x0000829c, 0x00000000 },
- { 0x00008300, 0x00000040 },
- { 0x00008314, 0x00000000 },
- { 0x00008328, 0x00000000 },
- { 0x0000832c, 0x00000007 },
- { 0x00008330, 0x00000302 },
- { 0x00008334, 0x00000e00 },
- { 0x00008338, 0x00ff0000 },
- { 0x0000833c, 0x00000000 },
- { 0x00008340, 0x000107ff },
- { 0x00008344, 0x00481043 },
- { 0x00009808, 0x00000000 },
- { 0x0000980c, 0xafa68e30 },
- { 0x00009810, 0xfd14e000 },
- { 0x00009814, 0x9c0a9f6b },
- { 0x0000981c, 0x00000000 },
- { 0x0000982c, 0x0000a000 },
- { 0x00009830, 0x00000000 },
- { 0x0000983c, 0x00200400 },
- { 0x0000984c, 0x0040233c },
- { 0x0000a84c, 0x0040233c },
- { 0x00009854, 0x00000044 },
- { 0x00009900, 0x00000000 },
- { 0x00009904, 0x00000000 },
- { 0x00009908, 0x00000000 },
- { 0x0000990c, 0x00000000 },
- { 0x00009910, 0x01002310 },
- { 0x0000991c, 0x10000fff },
- { 0x00009920, 0x04900000 },
- { 0x0000a920, 0x04900000 },
- { 0x00009928, 0x00000001 },
- { 0x0000992c, 0x00000004 },
- { 0x00009934, 0x1e1f2022 },
- { 0x00009938, 0x0a0b0c0d },
- { 0x0000993c, 0x00000000 },
- { 0x00009948, 0x9280c00a },
- { 0x0000994c, 0x00020028 },
- { 0x00009954, 0x5f3ca3de },
- { 0x00009958, 0x2108ecff },
- { 0x00009940, 0x14750604 },
- { 0x0000c95c, 0x004b6a8e },
- { 0x00009970, 0x190fb515 },
- { 0x00009974, 0x00000000 },
- { 0x00009978, 0x00000001 },
- { 0x0000997c, 0x00000000 },
- { 0x00009980, 0x00000000 },
- { 0x00009984, 0x00000000 },
- { 0x00009988, 0x00000000 },
- { 0x0000998c, 0x00000000 },
- { 0x00009990, 0x00000000 },
- { 0x00009994, 0x00000000 },
- { 0x00009998, 0x00000000 },
- { 0x0000999c, 0x00000000 },
- { 0x000099a0, 0x00000000 },
- { 0x000099a4, 0x00000001 },
- { 0x000099a8, 0x201fff00 },
- { 0x000099ac, 0x006f0000 },
- { 0x000099b0, 0x03051000 },
- { 0x000099b4, 0x00000820 },
- { 0x000099dc, 0x00000000 },
- { 0x000099e0, 0x00000000 },
- { 0x000099e4, 0xaaaaaaaa },
- { 0x000099e8, 0x3c466478 },
- { 0x000099ec, 0x0cc80caa },
- { 0x000099f0, 0x00000000 },
- { 0x000099fc, 0x00001042 },
- { 0x0000a208, 0x803e4788 },
- { 0x0000a210, 0x4080a333 },
- { 0x0000a214, 0x40206c10 },
- { 0x0000a218, 0x009c4060 },
- { 0x0000a220, 0x01834061 },
- { 0x0000a224, 0x00000400 },
- { 0x0000a228, 0x000003b5 },
- { 0x0000a22c, 0x233f7180 },
- { 0x0000a234, 0x20202020 },
- { 0x0000a238, 0x20202020 },
- { 0x0000a240, 0x38490a20 },
- { 0x0000a244, 0x00007bb6 },
- { 0x0000a248, 0x0fff3ffc },
- { 0x0000a24c, 0x00000000 },
- { 0x0000a254, 0x00000000 },
- { 0x0000a258, 0x0cdbd380 },
- { 0x0000a25c, 0x0f0f0f01 },
- { 0x0000a260, 0xdfa91f01 },
- { 0x0000a268, 0x00000000 },
- { 0x0000a26c, 0x0e79e5c6 },
- { 0x0000b26c, 0x0e79e5c6 },
- { 0x0000d270, 0x00820820 },
- { 0x0000a278, 0x1ce739ce },
- { 0x0000d35c, 0x07ffffef },
- { 0x0000d360, 0x0fffffe7 },
- { 0x0000d364, 0x17ffffe5 },
- { 0x0000d368, 0x1fffffe4 },
- { 0x0000d36c, 0x37ffffe3 },
- { 0x0000d370, 0x3fffffe3 },
- { 0x0000d374, 0x57ffffe3 },
- { 0x0000d378, 0x5fffffe2 },
- { 0x0000d37c, 0x7fffffe2 },
- { 0x0000d380, 0x7f3c7bba },
- { 0x0000d384, 0xf3307ff0 },
- { 0x0000a38c, 0x20202020 },
- { 0x0000a390, 0x20202020 },
- { 0x0000a394, 0x1ce739ce },
- { 0x0000a398, 0x000001ce },
- { 0x0000a39c, 0x00000001 },
- { 0x0000a3a0, 0x00000000 },
- { 0x0000a3a4, 0x00000000 },
- { 0x0000a3a8, 0x00000000 },
- { 0x0000a3ac, 0x00000000 },
- { 0x0000a3b0, 0x00000000 },
- { 0x0000a3b4, 0x00000000 },
- { 0x0000a3b8, 0x00000000 },
- { 0x0000a3bc, 0x00000000 },
- { 0x0000a3c0, 0x00000000 },
- { 0x0000a3c4, 0x00000000 },
- { 0x0000a3c8, 0x00000246 },
- { 0x0000a3cc, 0x20202020 },
- { 0x0000a3d0, 0x20202020 },
- { 0x0000a3d4, 0x20202020 },
- { 0x0000a3dc, 0x1ce739ce },
- { 0x0000a3e0, 0x000001ce },
- { 0x0000a3e4, 0x00000000 },
- { 0x0000a3e8, 0x18c43433 },
- { 0x0000a3ec, 0x00f70081 },
- { 0x00007800, 0x00040000 },
- { 0x00007804, 0xdb005012 },
- { 0x00007808, 0x04924914 },
- { 0x0000780c, 0x21084210 },
- { 0x00007810, 0x6d801300 },
- { 0x00007818, 0x07e41000 },
- { 0x00007824, 0x00040000 },
- { 0x00007828, 0xdb005012 },
- { 0x0000782c, 0x04924914 },
- { 0x00007830, 0x21084210 },
- { 0x00007834, 0x6d801300 },
- { 0x0000783c, 0x07e40000 },
- { 0x00007848, 0x00100000 },
- { 0x0000784c, 0x773f0567 },
- { 0x00007850, 0x54214514 },
- { 0x00007854, 0x12035828 },
- { 0x00007858, 0x9259269a },
- { 0x00007860, 0x52802000 },
- { 0x00007864, 0x0a8e370e },
- { 0x00007868, 0xc0102850 },
- { 0x0000786c, 0x812d4000 },
- { 0x00007870, 0x807ec400 },
- { 0x00007874, 0x001b6db0 },
- { 0x00007878, 0x00376b63 },
- { 0x0000787c, 0x06db6db6 },
- { 0x00007880, 0x006d8000 },
- { 0x00007884, 0xffeffffe },
- { 0x00007888, 0xffeffffe },
- { 0x0000788c, 0x00010000 },
- { 0x00007890, 0x02060aeb },
- { 0x00007898, 0x2a850160 },
+ /* Addr allmodes */
+ {0x0000000c, 0x00000000},
+ {0x00000030, 0x00020015},
+ {0x00000034, 0x00000005},
+ {0x00000040, 0x00000000},
+ {0x00000044, 0x00000008},
+ {0x00000048, 0x00000008},
+ {0x0000004c, 0x00000010},
+ {0x00000050, 0x00000000},
+ {0x00000054, 0x0000001f},
+ {0x00000800, 0x00000000},
+ {0x00000804, 0x00000000},
+ {0x00000808, 0x00000000},
+ {0x0000080c, 0x00000000},
+ {0x00000810, 0x00000000},
+ {0x00000814, 0x00000000},
+ {0x00000818, 0x00000000},
+ {0x0000081c, 0x00000000},
+ {0x00000820, 0x00000000},
+ {0x00000824, 0x00000000},
+ {0x00001040, 0x002ffc0f},
+ {0x00001044, 0x002ffc0f},
+ {0x00001048, 0x002ffc0f},
+ {0x0000104c, 0x002ffc0f},
+ {0x00001050, 0x002ffc0f},
+ {0x00001054, 0x002ffc0f},
+ {0x00001058, 0x002ffc0f},
+ {0x0000105c, 0x002ffc0f},
+ {0x00001060, 0x002ffc0f},
+ {0x00001064, 0x002ffc0f},
+ {0x00001230, 0x00000000},
+ {0x00001270, 0x00000000},
+ {0x00001038, 0x00000000},
+ {0x00001078, 0x00000000},
+ {0x000010b8, 0x00000000},
+ {0x000010f8, 0x00000000},
+ {0x00001138, 0x00000000},
+ {0x00001178, 0x00000000},
+ {0x000011b8, 0x00000000},
+ {0x000011f8, 0x00000000},
+ {0x00001238, 0x00000000},
+ {0x00001278, 0x00000000},
+ {0x000012b8, 0x00000000},
+ {0x000012f8, 0x00000000},
+ {0x00001338, 0x00000000},
+ {0x00001378, 0x00000000},
+ {0x000013b8, 0x00000000},
+ {0x000013f8, 0x00000000},
+ {0x00001438, 0x00000000},
+ {0x00001478, 0x00000000},
+ {0x000014b8, 0x00000000},
+ {0x000014f8, 0x00000000},
+ {0x00001538, 0x00000000},
+ {0x00001578, 0x00000000},
+ {0x000015b8, 0x00000000},
+ {0x000015f8, 0x00000000},
+ {0x00001638, 0x00000000},
+ {0x00001678, 0x00000000},
+ {0x000016b8, 0x00000000},
+ {0x000016f8, 0x00000000},
+ {0x00001738, 0x00000000},
+ {0x00001778, 0x00000000},
+ {0x000017b8, 0x00000000},
+ {0x000017f8, 0x00000000},
+ {0x0000103c, 0x00000000},
+ {0x0000107c, 0x00000000},
+ {0x000010bc, 0x00000000},
+ {0x000010fc, 0x00000000},
+ {0x0000113c, 0x00000000},
+ {0x0000117c, 0x00000000},
+ {0x000011bc, 0x00000000},
+ {0x000011fc, 0x00000000},
+ {0x0000123c, 0x00000000},
+ {0x0000127c, 0x00000000},
+ {0x000012bc, 0x00000000},
+ {0x000012fc, 0x00000000},
+ {0x0000133c, 0x00000000},
+ {0x0000137c, 0x00000000},
+ {0x000013bc, 0x00000000},
+ {0x000013fc, 0x00000000},
+ {0x0000143c, 0x00000000},
+ {0x0000147c, 0x00000000},
+ {0x00004030, 0x00000002},
+ {0x0000403c, 0x00000002},
+ {0x00004024, 0x0000001f},
+ {0x00004060, 0x00000000},
+ {0x00004064, 0x00000000},
+ {0x00007010, 0x00000033},
+ {0x00007034, 0x00000002},
+ {0x00007038, 0x000004c2},
+ {0x00008004, 0x00000000},
+ {0x00008008, 0x00000000},
+ {0x0000800c, 0x00000000},
+ {0x00008018, 0x00000700},
+ {0x00008020, 0x00000000},
+ {0x00008038, 0x00000000},
+ {0x0000803c, 0x00000000},
+ {0x00008048, 0x40000000},
+ {0x00008054, 0x00000000},
+ {0x00008058, 0x00000000},
+ {0x0000805c, 0x000fc78f},
+ {0x00008060, 0x0000000f},
+ {0x00008064, 0x00000000},
+ {0x00008070, 0x00000000},
+ {0x000080c0, 0x2a80001a},
+ {0x000080c4, 0x05dc01e0},
+ {0x000080c8, 0x1f402710},
+ {0x000080cc, 0x01f40000},
+ {0x000080d0, 0x00001e00},
+ {0x000080d4, 0x00000000},
+ {0x000080d8, 0x00400000},
+ {0x000080e0, 0xffffffff},
+ {0x000080e4, 0x0000ffff},
+ {0x000080e8, 0x003f3f3f},
+ {0x000080ec, 0x00000000},
+ {0x000080f0, 0x00000000},
+ {0x000080f4, 0x00000000},
+ {0x000080f8, 0x00000000},
+ {0x000080fc, 0x00020000},
+ {0x00008100, 0x00020000},
+ {0x00008104, 0x00000001},
+ {0x00008108, 0x00000052},
+ {0x0000810c, 0x00000000},
+ {0x00008110, 0x00000168},
+ {0x00008118, 0x000100aa},
+ {0x0000811c, 0x00003210},
+ {0x00008124, 0x00000000},
+ {0x00008128, 0x00000000},
+ {0x0000812c, 0x00000000},
+ {0x00008130, 0x00000000},
+ {0x00008134, 0x00000000},
+ {0x00008138, 0x00000000},
+ {0x0000813c, 0x00000000},
+ {0x00008144, 0xffffffff},
+ {0x00008168, 0x00000000},
+ {0x0000816c, 0x00000000},
+ {0x00008170, 0x32143320},
+ {0x00008174, 0xfaa4fa50},
+ {0x00008178, 0x00000100},
+ {0x0000817c, 0x00000000},
+ {0x000081c0, 0x00000000},
+ {0x000081ec, 0x00000000},
+ {0x000081f0, 0x00000000},
+ {0x000081f4, 0x00000000},
+ {0x000081f8, 0x00000000},
+ {0x000081fc, 0x00000000},
+ {0x00008200, 0x00000000},
+ {0x00008204, 0x00000000},
+ {0x00008208, 0x00000000},
+ {0x0000820c, 0x00000000},
+ {0x00008210, 0x00000000},
+ {0x00008214, 0x00000000},
+ {0x00008218, 0x00000000},
+ {0x0000821c, 0x00000000},
+ {0x00008220, 0x00000000},
+ {0x00008224, 0x00000000},
+ {0x00008228, 0x00000000},
+ {0x0000822c, 0x00000000},
+ {0x00008230, 0x00000000},
+ {0x00008234, 0x00000000},
+ {0x00008238, 0x00000000},
+ {0x0000823c, 0x00000000},
+ {0x00008240, 0x00100000},
+ {0x00008244, 0x0010f400},
+ {0x00008248, 0x00000100},
+ {0x0000824c, 0x0001e800},
+ {0x00008250, 0x00000000},
+ {0x00008254, 0x00000000},
+ {0x00008258, 0x00000000},
+ {0x0000825c, 0x400000ff},
+ {0x00008260, 0x00080922},
+ {0x00008264, 0x88a00010},
+ {0x00008270, 0x00000000},
+ {0x00008274, 0x40000000},
+ {0x00008278, 0x003e4180},
+ {0x0000827c, 0x00000000},
+ {0x00008284, 0x0000002c},
+ {0x00008288, 0x0000002c},
+ {0x0000828c, 0x00000000},
+ {0x00008294, 0x00000000},
+ {0x00008298, 0x00000000},
+ {0x0000829c, 0x00000000},
+ {0x00008300, 0x00000040},
+ {0x00008314, 0x00000000},
+ {0x00008328, 0x00000000},
+ {0x0000832c, 0x00000007},
+ {0x00008330, 0x00000302},
+ {0x00008334, 0x00000e00},
+ {0x00008338, 0x00ff0000},
+ {0x0000833c, 0x00000000},
+ {0x00008340, 0x000107ff},
+ {0x00008344, 0x00481043},
+ {0x00009808, 0x00000000},
+ {0x0000980c, 0xafa68e30},
+ {0x00009810, 0xfd14e000},
+ {0x00009814, 0x9c0a9f6b},
+ {0x0000981c, 0x00000000},
+ {0x0000982c, 0x0000a000},
+ {0x00009830, 0x00000000},
+ {0x0000983c, 0x00200400},
+ {0x0000984c, 0x0040233c},
+ {0x0000a84c, 0x0040233c},
+ {0x00009854, 0x00000044},
+ {0x00009900, 0x00000000},
+ {0x00009904, 0x00000000},
+ {0x00009908, 0x00000000},
+ {0x0000990c, 0x00000000},
+ {0x00009910, 0x01002310},
+ {0x0000991c, 0x10000fff},
+ {0x00009920, 0x04900000},
+ {0x0000a920, 0x04900000},
+ {0x00009928, 0x00000001},
+ {0x0000992c, 0x00000004},
+ {0x00009934, 0x1e1f2022},
+ {0x00009938, 0x0a0b0c0d},
+ {0x0000993c, 0x00000000},
+ {0x00009948, 0x9280c00a},
+ {0x0000994c, 0x00020028},
+ {0x00009954, 0x5f3ca3de},
+ {0x00009958, 0x2108ecff},
+ {0x00009940, 0x14750604},
+ {0x0000c95c, 0x004b6a8e},
+ {0x00009970, 0x190fb514},
+ {0x00009974, 0x00000000},
+ {0x00009978, 0x00000001},
+ {0x0000997c, 0x00000000},
+ {0x00009980, 0x00000000},
+ {0x00009984, 0x00000000},
+ {0x00009988, 0x00000000},
+ {0x0000998c, 0x00000000},
+ {0x00009990, 0x00000000},
+ {0x00009994, 0x00000000},
+ {0x00009998, 0x00000000},
+ {0x0000999c, 0x00000000},
+ {0x000099a0, 0x00000000},
+ {0x000099a4, 0x00000001},
+ {0x000099a8, 0x201fff00},
+ {0x000099ac, 0x006f0000},
+ {0x000099b0, 0x03051000},
+ {0x000099b4, 0x00000820},
+ {0x000099c4, 0x06336f77},
+ {0x000099c8, 0x6af6532f},
+ {0x000099cc, 0x08f186c8},
+ {0x000099d0, 0x00046384},
+ {0x000099d4, 0x00000000},
+ {0x000099d8, 0x00000000},
+ {0x000099dc, 0x00000000},
+ {0x000099e0, 0x00000000},
+ {0x000099e4, 0xaaaaaaaa},
+ {0x000099e8, 0x3c466478},
+ {0x000099ec, 0x0cc80caa},
+ {0x000099f0, 0x00000000},
+ {0x000099fc, 0x00001042},
+ {0x0000a208, 0x803e4788},
+ {0x0000a210, 0x4080a333},
+ {0x0000a214, 0x40206c10},
+ {0x0000a218, 0x009c4060},
+ {0x0000a220, 0x01834061},
+ {0x0000a224, 0x00000400},
+ {0x0000a228, 0x000003b5},
+ {0x0000a22c, 0x233f7180},
+ {0x0000a234, 0x20202020},
+ {0x0000a238, 0x20202020},
+ {0x0000a240, 0x38490a20},
+ {0x0000a244, 0x00007bb6},
+ {0x0000a248, 0x0fff3ffc},
+ {0x0000a24c, 0x00000000},
+ {0x0000a254, 0x00000000},
+ {0x0000a258, 0x0cdbd380},
+ {0x0000a25c, 0x0f0f0f01},
+ {0x0000a260, 0xdfa91f01},
+ {0x0000a268, 0x00000000},
+ {0x0000a26c, 0x0e79e5c6},
+ {0x0000b26c, 0x0e79e5c6},
+ {0x0000d270, 0x00820820},
+ {0x0000a278, 0x1ce739ce},
+ {0x0000d35c, 0x07ffffef},
+ {0x0000d360, 0x0fffffe7},
+ {0x0000d364, 0x17ffffe5},
+ {0x0000d368, 0x1fffffe4},
+ {0x0000d36c, 0x37ffffe3},
+ {0x0000d370, 0x3fffffe3},
+ {0x0000d374, 0x57ffffe3},
+ {0x0000d378, 0x5fffffe2},
+ {0x0000d37c, 0x7fffffe2},
+ {0x0000d380, 0x7f3c7bba},
+ {0x0000d384, 0xf3307ff0},
+ {0x0000a38c, 0x20202020},
+ {0x0000a390, 0x20202020},
+ {0x0000a394, 0x1ce739ce},
+ {0x0000a398, 0x000001ce},
+ {0x0000a39c, 0x00000001},
+ {0x0000a3a0, 0x00000000},
+ {0x0000a3a4, 0x00000000},
+ {0x0000a3a8, 0x00000000},
+ {0x0000a3ac, 0x00000000},
+ {0x0000a3b0, 0x00000000},
+ {0x0000a3b4, 0x00000000},
+ {0x0000a3b8, 0x00000000},
+ {0x0000a3bc, 0x00000000},
+ {0x0000a3c0, 0x00000000},
+ {0x0000a3c4, 0x00000000},
+ {0x0000a3c8, 0x00000246},
+ {0x0000a3cc, 0x20202020},
+ {0x0000a3d0, 0x20202020},
+ {0x0000a3d4, 0x20202020},
+ {0x0000a3dc, 0x1ce739ce},
+ {0x0000a3e0, 0x000001ce},
+ {0x0000a3e4, 0x00000000},
+ {0x0000a3e8, 0x18c43433},
+ {0x00007800, 0x00040000},
+ {0x00007804, 0xdb005012},
+ {0x00007808, 0x04924914},
+ {0x0000780c, 0x21084210},
+ {0x00007810, 0x6d801300},
+ {0x00007818, 0x07e41000},
+ {0x00007824, 0x00040000},
+ {0x00007828, 0xdb005012},
+ {0x0000782c, 0x04924914},
+ {0x00007830, 0x21084210},
+ {0x00007834, 0x6d801300},
+ {0x0000783c, 0x07e40000},
+ {0x00007848, 0x00100000},
+ {0x0000784c, 0x773f0567},
+ {0x00007850, 0x54214514},
+ {0x00007854, 0x12035828},
+ {0x00007858, 0x9259269a},
+ {0x00007860, 0x52802000},
+ {0x00007864, 0x0a8e370e},
+ {0x00007868, 0xc0102850},
+ {0x0000786c, 0x812d4000},
+ {0x00007870, 0x807ec400},
+ {0x00007874, 0x001b6db0},
+ {0x00007878, 0x00376b63},
+ {0x0000787c, 0x06db6db6},
+ {0x00007880, 0x006d8000},
+ {0x00007884, 0xffeffffe},
+ {0x00007888, 0xffeffffe},
+ {0x0000788c, 0x00010000},
+ {0x00007890, 0x02060aeb},
+ {0x00007898, 0x2a850160},
};
static const u32 ar9280Modes_fast_clock_9280_2[][3] = {
- { 0x00001030, 0x00000268, 0x000004d0 },
- { 0x00001070, 0x0000018c, 0x00000318 },
- { 0x000010b0, 0x00000fd0, 0x00001fa0 },
- { 0x00008014, 0x044c044c, 0x08980898 },
- { 0x0000801c, 0x148ec02b, 0x148ec057 },
- { 0x00008318, 0x000044c0, 0x00008980 },
- { 0x00009820, 0x02020200, 0x02020200 },
- { 0x00009824, 0x01000f0f, 0x01000f0f },
- { 0x00009828, 0x0b020001, 0x0b020001 },
- { 0x00009834, 0x00000f0f, 0x00000f0f },
- { 0x00009844, 0x03721821, 0x03721821 },
- { 0x00009914, 0x00000898, 0x00001130 },
- { 0x00009918, 0x0000000b, 0x00000016 },
+ /* Addr 5G_HT20 5G_HT40 */
+ {0x00001030, 0x00000268, 0x000004d0},
+ {0x00001070, 0x0000018c, 0x00000318},
+ {0x000010b0, 0x00000fd0, 0x00001fa0},
+ {0x00008014, 0x044c044c, 0x08980898},
+ {0x0000801c, 0x148ec02b, 0x148ec057},
+ {0x00008318, 0x000044c0, 0x00008980},
+ {0x00009820, 0x02020200, 0x02020200},
+ {0x00009824, 0x01000f0f, 0x01000f0f},
+ {0x00009828, 0x0b020001, 0x0b020001},
+ {0x00009834, 0x00000f0f, 0x00000f0f},
+ {0x00009844, 0x03721821, 0x03721821},
+ {0x00009914, 0x00000898, 0x00001130},
+ {0x00009918, 0x0000000b, 0x00000016},
};
static const u32 ar9280Modes_backoff_23db_rxgain_9280_2[][6] = {
- { 0x00009a00, 0x00008184, 0x00008184, 0x00000290, 0x00000290, 0x00000290 },
- { 0x00009a04, 0x00008188, 0x00008188, 0x00000300, 0x00000300, 0x00000300 },
- { 0x00009a08, 0x0000818c, 0x0000818c, 0x00000304, 0x00000304, 0x00000304 },
- { 0x00009a0c, 0x00008190, 0x00008190, 0x00000308, 0x00000308, 0x00000308 },
- { 0x00009a10, 0x00008194, 0x00008194, 0x0000030c, 0x0000030c, 0x0000030c },
- { 0x00009a14, 0x00008200, 0x00008200, 0x00008000, 0x00008000, 0x00008000 },
- { 0x00009a18, 0x00008204, 0x00008204, 0x00008004, 0x00008004, 0x00008004 },
- { 0x00009a1c, 0x00008208, 0x00008208, 0x00008008, 0x00008008, 0x00008008 },
- { 0x00009a20, 0x0000820c, 0x0000820c, 0x0000800c, 0x0000800c, 0x0000800c },
- { 0x00009a24, 0x00008210, 0x00008210, 0x00008080, 0x00008080, 0x00008080 },
- { 0x00009a28, 0x00008214, 0x00008214, 0x00008084, 0x00008084, 0x00008084 },
- { 0x00009a2c, 0x00008280, 0x00008280, 0x00008088, 0x00008088, 0x00008088 },
- { 0x00009a30, 0x00008284, 0x00008284, 0x0000808c, 0x0000808c, 0x0000808c },
- { 0x00009a34, 0x00008288, 0x00008288, 0x00008100, 0x00008100, 0x00008100 },
- { 0x00009a38, 0x0000828c, 0x0000828c, 0x00008104, 0x00008104, 0x00008104 },
- { 0x00009a3c, 0x00008290, 0x00008290, 0x00008108, 0x00008108, 0x00008108 },
- { 0x00009a40, 0x00008300, 0x00008300, 0x0000810c, 0x0000810c, 0x0000810c },
- { 0x00009a44, 0x00008304, 0x00008304, 0x00008110, 0x00008110, 0x00008110 },
- { 0x00009a48, 0x00008308, 0x00008308, 0x00008114, 0x00008114, 0x00008114 },
- { 0x00009a4c, 0x0000830c, 0x0000830c, 0x00008180, 0x00008180, 0x00008180 },
- { 0x00009a50, 0x00008310, 0x00008310, 0x00008184, 0x00008184, 0x00008184 },
- { 0x00009a54, 0x00008314, 0x00008314, 0x00008188, 0x00008188, 0x00008188 },
- { 0x00009a58, 0x00008380, 0x00008380, 0x0000818c, 0x0000818c, 0x0000818c },
- { 0x00009a5c, 0x00008384, 0x00008384, 0x00008190, 0x00008190, 0x00008190 },
- { 0x00009a60, 0x00008388, 0x00008388, 0x00008194, 0x00008194, 0x00008194 },
- { 0x00009a64, 0x0000838c, 0x0000838c, 0x000081a0, 0x000081a0, 0x000081a0 },
- { 0x00009a68, 0x00008390, 0x00008390, 0x0000820c, 0x0000820c, 0x0000820c },
- { 0x00009a6c, 0x00008394, 0x00008394, 0x000081a8, 0x000081a8, 0x000081a8 },
- { 0x00009a70, 0x0000a380, 0x0000a380, 0x00008284, 0x00008284, 0x00008284 },
- { 0x00009a74, 0x0000a384, 0x0000a384, 0x00008288, 0x00008288, 0x00008288 },
- { 0x00009a78, 0x0000a388, 0x0000a388, 0x00008224, 0x00008224, 0x00008224 },
- { 0x00009a7c, 0x0000a38c, 0x0000a38c, 0x00008290, 0x00008290, 0x00008290 },
- { 0x00009a80, 0x0000a390, 0x0000a390, 0x00008300, 0x00008300, 0x00008300 },
- { 0x00009a84, 0x0000a394, 0x0000a394, 0x00008304, 0x00008304, 0x00008304 },
- { 0x00009a88, 0x0000a780, 0x0000a780, 0x00008308, 0x00008308, 0x00008308 },
- { 0x00009a8c, 0x0000a784, 0x0000a784, 0x0000830c, 0x0000830c, 0x0000830c },
- { 0x00009a90, 0x0000a788, 0x0000a788, 0x00008380, 0x00008380, 0x00008380 },
- { 0x00009a94, 0x0000a78c, 0x0000a78c, 0x00008384, 0x00008384, 0x00008384 },
- { 0x00009a98, 0x0000a790, 0x0000a790, 0x00008700, 0x00008700, 0x00008700 },
- { 0x00009a9c, 0x0000a794, 0x0000a794, 0x00008704, 0x00008704, 0x00008704 },
- { 0x00009aa0, 0x0000ab84, 0x0000ab84, 0x00008708, 0x00008708, 0x00008708 },
- { 0x00009aa4, 0x0000ab88, 0x0000ab88, 0x0000870c, 0x0000870c, 0x0000870c },
- { 0x00009aa8, 0x0000ab8c, 0x0000ab8c, 0x00008780, 0x00008780, 0x00008780 },
- { 0x00009aac, 0x0000ab90, 0x0000ab90, 0x00008784, 0x00008784, 0x00008784 },
- { 0x00009ab0, 0x0000ab94, 0x0000ab94, 0x00008b00, 0x00008b00, 0x00008b00 },
- { 0x00009ab4, 0x0000af80, 0x0000af80, 0x00008b04, 0x00008b04, 0x00008b04 },
- { 0x00009ab8, 0x0000af84, 0x0000af84, 0x00008b08, 0x00008b08, 0x00008b08 },
- { 0x00009abc, 0x0000af88, 0x0000af88, 0x00008b0c, 0x00008b0c, 0x00008b0c },
- { 0x00009ac0, 0x0000af8c, 0x0000af8c, 0x00008b10, 0x00008b10, 0x00008b10 },
- { 0x00009ac4, 0x0000af90, 0x0000af90, 0x00008b14, 0x00008b14, 0x00008b14 },
- { 0x00009ac8, 0x0000af94, 0x0000af94, 0x00008b01, 0x00008b01, 0x00008b01 },
- { 0x00009acc, 0x0000b380, 0x0000b380, 0x00008b05, 0x00008b05, 0x00008b05 },
- { 0x00009ad0, 0x0000b384, 0x0000b384, 0x00008b09, 0x00008b09, 0x00008b09 },
- { 0x00009ad4, 0x0000b388, 0x0000b388, 0x00008b0d, 0x00008b0d, 0x00008b0d },
- { 0x00009ad8, 0x0000b38c, 0x0000b38c, 0x00008b11, 0x00008b11, 0x00008b11 },
- { 0x00009adc, 0x0000b390, 0x0000b390, 0x00008b15, 0x00008b15, 0x00008b15 },
- { 0x00009ae0, 0x0000b394, 0x0000b394, 0x00008b02, 0x00008b02, 0x00008b02 },
- { 0x00009ae4, 0x0000b398, 0x0000b398, 0x00008b06, 0x00008b06, 0x00008b06 },
- { 0x00009ae8, 0x0000b780, 0x0000b780, 0x00008b0a, 0x00008b0a, 0x00008b0a },
- { 0x00009aec, 0x0000b784, 0x0000b784, 0x00008b0e, 0x00008b0e, 0x00008b0e },
- { 0x00009af0, 0x0000b788, 0x0000b788, 0x00008b12, 0x00008b12, 0x00008b12 },
- { 0x00009af4, 0x0000b78c, 0x0000b78c, 0x00008b16, 0x00008b16, 0x00008b16 },
- { 0x00009af8, 0x0000b790, 0x0000b790, 0x00008b03, 0x00008b03, 0x00008b03 },
- { 0x00009afc, 0x0000b794, 0x0000b794, 0x00008b07, 0x00008b07, 0x00008b07 },
- { 0x00009b00, 0x0000b798, 0x0000b798, 0x00008b0b, 0x00008b0b, 0x00008b0b },
- { 0x00009b04, 0x0000d784, 0x0000d784, 0x00008b0f, 0x00008b0f, 0x00008b0f },
- { 0x00009b08, 0x0000d788, 0x0000d788, 0x00008b13, 0x00008b13, 0x00008b13 },
- { 0x00009b0c, 0x0000d78c, 0x0000d78c, 0x00008b17, 0x00008b17, 0x00008b17 },
- { 0x00009b10, 0x0000d790, 0x0000d790, 0x00008b23, 0x00008b23, 0x00008b23 },
- { 0x00009b14, 0x0000f780, 0x0000f780, 0x00008b27, 0x00008b27, 0x00008b27 },
- { 0x00009b18, 0x0000f784, 0x0000f784, 0x00008b2b, 0x00008b2b, 0x00008b2b },
- { 0x00009b1c, 0x0000f788, 0x0000f788, 0x00008b2f, 0x00008b2f, 0x00008b2f },
- { 0x00009b20, 0x0000f78c, 0x0000f78c, 0x00008b33, 0x00008b33, 0x00008b33 },
- { 0x00009b24, 0x0000f790, 0x0000f790, 0x00008b37, 0x00008b37, 0x00008b37 },
- { 0x00009b28, 0x0000f794, 0x0000f794, 0x00008b43, 0x00008b43, 0x00008b43 },
- { 0x00009b2c, 0x0000f7a4, 0x0000f7a4, 0x00008b47, 0x00008b47, 0x00008b47 },
- { 0x00009b30, 0x0000f7a8, 0x0000f7a8, 0x00008b4b, 0x00008b4b, 0x00008b4b },
- { 0x00009b34, 0x0000f7ac, 0x0000f7ac, 0x00008b4f, 0x00008b4f, 0x00008b4f },
- { 0x00009b38, 0x0000f7b0, 0x0000f7b0, 0x00008b53, 0x00008b53, 0x00008b53 },
- { 0x00009b3c, 0x0000f7b4, 0x0000f7b4, 0x00008b57, 0x00008b57, 0x00008b57 },
- { 0x00009b40, 0x0000f7a1, 0x0000f7a1, 0x00008b5b, 0x00008b5b, 0x00008b5b },
- { 0x00009b44, 0x0000f7a5, 0x0000f7a5, 0x00008b5b, 0x00008b5b, 0x00008b5b },
- { 0x00009b48, 0x0000f7a9, 0x0000f7a9, 0x00008b5b, 0x00008b5b, 0x00008b5b },
- { 0x00009b4c, 0x0000f7ad, 0x0000f7ad, 0x00008b5b, 0x00008b5b, 0x00008b5b },
- { 0x00009b50, 0x0000f7b1, 0x0000f7b1, 0x00008b5b, 0x00008b5b, 0x00008b5b },
- { 0x00009b54, 0x0000f7b5, 0x0000f7b5, 0x00008b5b, 0x00008b5b, 0x00008b5b },
- { 0x00009b58, 0x0000f7c5, 0x0000f7c5, 0x00008b5b, 0x00008b5b, 0x00008b5b },
- { 0x00009b5c, 0x0000f7c9, 0x0000f7c9, 0x00008b5b, 0x00008b5b, 0x00008b5b },
- { 0x00009b60, 0x0000f7cd, 0x0000f7cd, 0x00008b5b, 0x00008b5b, 0x00008b5b },
- { 0x00009b64, 0x0000f7d1, 0x0000f7d1, 0x00008b5b, 0x00008b5b, 0x00008b5b },
- { 0x00009b68, 0x0000f7d5, 0x0000f7d5, 0x00008b5b, 0x00008b5b, 0x00008b5b },
- { 0x00009b6c, 0x0000f7c2, 0x0000f7c2, 0x00008b5b, 0x00008b5b, 0x00008b5b },
- { 0x00009b70, 0x0000f7c6, 0x0000f7c6, 0x00008b5b, 0x00008b5b, 0x00008b5b },
- { 0x00009b74, 0x0000f7ca, 0x0000f7ca, 0x00008b5b, 0x00008b5b, 0x00008b5b },
- { 0x00009b78, 0x0000f7ce, 0x0000f7ce, 0x00008b5b, 0x00008b5b, 0x00008b5b },
- { 0x00009b7c, 0x0000f7d2, 0x0000f7d2, 0x00008b5b, 0x00008b5b, 0x00008b5b },
- { 0x00009b80, 0x0000f7d6, 0x0000f7d6, 0x00008b5b, 0x00008b5b, 0x00008b5b },
- { 0x00009b84, 0x0000f7c3, 0x0000f7c3, 0x00008b5b, 0x00008b5b, 0x00008b5b },
- { 0x00009b88, 0x0000f7c7, 0x0000f7c7, 0x00008b5b, 0x00008b5b, 0x00008b5b },
- { 0x00009b8c, 0x0000f7cb, 0x0000f7cb, 0x00008b5b, 0x00008b5b, 0x00008b5b },
- { 0x00009b90, 0x0000f7d3, 0x0000f7d3, 0x00008b5b, 0x00008b5b, 0x00008b5b },
- { 0x00009b94, 0x0000f7d7, 0x0000f7d7, 0x00008b5b, 0x00008b5b, 0x00008b5b },
- { 0x00009b98, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b },
- { 0x00009b9c, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b },
- { 0x00009ba0, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b },
- { 0x00009ba4, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b },
- { 0x00009ba8, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b },
- { 0x00009bac, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b },
- { 0x00009bb0, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b },
- { 0x00009bb4, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b },
- { 0x00009bb8, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b },
- { 0x00009bbc, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b },
- { 0x00009bc0, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b },
- { 0x00009bc4, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b },
- { 0x00009bc8, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b },
- { 0x00009bcc, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b },
- { 0x00009bd0, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b },
- { 0x00009bd4, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b },
- { 0x00009bd8, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b },
- { 0x00009bdc, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b },
- { 0x00009be0, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b },
- { 0x00009be4, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b },
- { 0x00009be8, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b },
- { 0x00009bec, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b },
- { 0x00009bf0, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b },
- { 0x00009bf4, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b },
- { 0x00009bf8, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b },
- { 0x00009bfc, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b },
- { 0x00009848, 0x00001066, 0x00001066, 0x00001050, 0x00001050, 0x00001050 },
- { 0x0000a848, 0x00001066, 0x00001066, 0x00001050, 0x00001050, 0x00001050 },
+ {0x00009a00, 0x00008184, 0x00008184, 0x00000290, 0x00000290, 0x00000290},
+ {0x00009a04, 0x00008188, 0x00008188, 0x00000300, 0x00000300, 0x00000300},
+ {0x00009a08, 0x0000818c, 0x0000818c, 0x00000304, 0x00000304, 0x00000304},
+ {0x00009a0c, 0x00008190, 0x00008190, 0x00000308, 0x00000308, 0x00000308},
+ {0x00009a10, 0x00008194, 0x00008194, 0x0000030c, 0x0000030c, 0x0000030c},
+ {0x00009a14, 0x00008200, 0x00008200, 0x00008000, 0x00008000, 0x00008000},
+ {0x00009a18, 0x00008204, 0x00008204, 0x00008004, 0x00008004, 0x00008004},
+ {0x00009a1c, 0x00008208, 0x00008208, 0x00008008, 0x00008008, 0x00008008},
+ {0x00009a20, 0x0000820c, 0x0000820c, 0x0000800c, 0x0000800c, 0x0000800c},
+ {0x00009a24, 0x00008210, 0x00008210, 0x00008080, 0x00008080, 0x00008080},
+ {0x00009a28, 0x00008214, 0x00008214, 0x00008084, 0x00008084, 0x00008084},
+ {0x00009a2c, 0x00008280, 0x00008280, 0x00008088, 0x00008088, 0x00008088},
+ {0x00009a30, 0x00008284, 0x00008284, 0x0000808c, 0x0000808c, 0x0000808c},
+ {0x00009a34, 0x00008288, 0x00008288, 0x00008100, 0x00008100, 0x00008100},
+ {0x00009a38, 0x0000828c, 0x0000828c, 0x00008104, 0x00008104, 0x00008104},
+ {0x00009a3c, 0x00008290, 0x00008290, 0x00008108, 0x00008108, 0x00008108},
+ {0x00009a40, 0x00008300, 0x00008300, 0x0000810c, 0x0000810c, 0x0000810c},
+ {0x00009a44, 0x00008304, 0x00008304, 0x00008110, 0x00008110, 0x00008110},
+ {0x00009a48, 0x00008308, 0x00008308, 0x00008114, 0x00008114, 0x00008114},
+ {0x00009a4c, 0x0000830c, 0x0000830c, 0x00008180, 0x00008180, 0x00008180},
+ {0x00009a50, 0x00008310, 0x00008310, 0x00008184, 0x00008184, 0x00008184},
+ {0x00009a54, 0x00008314, 0x00008314, 0x00008188, 0x00008188, 0x00008188},
+ {0x00009a58, 0x00008380, 0x00008380, 0x0000818c, 0x0000818c, 0x0000818c},
+ {0x00009a5c, 0x00008384, 0x00008384, 0x00008190, 0x00008190, 0x00008190},
+ {0x00009a60, 0x00008388, 0x00008388, 0x00008194, 0x00008194, 0x00008194},
+ {0x00009a64, 0x0000838c, 0x0000838c, 0x000081a0, 0x000081a0, 0x000081a0},
+ {0x00009a68, 0x00008390, 0x00008390, 0x0000820c, 0x0000820c, 0x0000820c},
+ {0x00009a6c, 0x00008394, 0x00008394, 0x000081a8, 0x000081a8, 0x000081a8},
+ {0x00009a70, 0x0000a380, 0x0000a380, 0x00008284, 0x00008284, 0x00008284},
+ {0x00009a74, 0x0000a384, 0x0000a384, 0x00008288, 0x00008288, 0x00008288},
+ {0x00009a78, 0x0000a388, 0x0000a388, 0x00008224, 0x00008224, 0x00008224},
+ {0x00009a7c, 0x0000a38c, 0x0000a38c, 0x00008290, 0x00008290, 0x00008290},
+ {0x00009a80, 0x0000a390, 0x0000a390, 0x00008300, 0x00008300, 0x00008300},
+ {0x00009a84, 0x0000a394, 0x0000a394, 0x00008304, 0x00008304, 0x00008304},
+ {0x00009a88, 0x0000a780, 0x0000a780, 0x00008308, 0x00008308, 0x00008308},
+ {0x00009a8c, 0x0000a784, 0x0000a784, 0x0000830c, 0x0000830c, 0x0000830c},
+ {0x00009a90, 0x0000a788, 0x0000a788, 0x00008380, 0x00008380, 0x00008380},
+ {0x00009a94, 0x0000a78c, 0x0000a78c, 0x00008384, 0x00008384, 0x00008384},
+ {0x00009a98, 0x0000a790, 0x0000a790, 0x00008700, 0x00008700, 0x00008700},
+ {0x00009a9c, 0x0000a794, 0x0000a794, 0x00008704, 0x00008704, 0x00008704},
+ {0x00009aa0, 0x0000ab84, 0x0000ab84, 0x00008708, 0x00008708, 0x00008708},
+ {0x00009aa4, 0x0000ab88, 0x0000ab88, 0x0000870c, 0x0000870c, 0x0000870c},
+ {0x00009aa8, 0x0000ab8c, 0x0000ab8c, 0x00008780, 0x00008780, 0x00008780},
+ {0x00009aac, 0x0000ab90, 0x0000ab90, 0x00008784, 0x00008784, 0x00008784},
+ {0x00009ab0, 0x0000ab94, 0x0000ab94, 0x00008b00, 0x00008b00, 0x00008b00},
+ {0x00009ab4, 0x0000af80, 0x0000af80, 0x00008b04, 0x00008b04, 0x00008b04},
+ {0x00009ab8, 0x0000af84, 0x0000af84, 0x00008b08, 0x00008b08, 0x00008b08},
+ {0x00009abc, 0x0000af88, 0x0000af88, 0x00008b0c, 0x00008b0c, 0x00008b0c},
+ {0x00009ac0, 0x0000af8c, 0x0000af8c, 0x00008b10, 0x00008b10, 0x00008b10},
+ {0x00009ac4, 0x0000af90, 0x0000af90, 0x00008b80, 0x00008b80, 0x00008b80},
+ {0x00009ac8, 0x0000af94, 0x0000af94, 0x00008b84, 0x00008b84, 0x00008b84},
+ {0x00009acc, 0x0000b380, 0x0000b380, 0x00008b88, 0x00008b88, 0x00008b88},
+ {0x00009ad0, 0x0000b384, 0x0000b384, 0x00008b8c, 0x00008b8c, 0x00008b8c},
+ {0x00009ad4, 0x0000b388, 0x0000b388, 0x00008b90, 0x00008b90, 0x00008b90},
+ {0x00009ad8, 0x0000b38c, 0x0000b38c, 0x00008b94, 0x00008b94, 0x00008b94},
+ {0x00009adc, 0x0000b390, 0x0000b390, 0x00008b98, 0x00008b98, 0x00008b98},
+ {0x00009ae0, 0x0000b394, 0x0000b394, 0x00008ba4, 0x00008ba4, 0x00008ba4},
+ {0x00009ae4, 0x0000b398, 0x0000b398, 0x00008ba8, 0x00008ba8, 0x00008ba8},
+ {0x00009ae8, 0x0000b780, 0x0000b780, 0x00008bac, 0x00008bac, 0x00008bac},
+ {0x00009aec, 0x0000b784, 0x0000b784, 0x00008bb0, 0x00008bb0, 0x00008bb0},
+ {0x00009af0, 0x0000b788, 0x0000b788, 0x00008bb4, 0x00008bb4, 0x00008bb4},
+ {0x00009af4, 0x0000b78c, 0x0000b78c, 0x00008ba1, 0x00008ba1, 0x00008ba1},
+ {0x00009af8, 0x0000b790, 0x0000b790, 0x00008ba5, 0x00008ba5, 0x00008ba5},
+ {0x00009afc, 0x0000b794, 0x0000b794, 0x00008ba9, 0x00008ba9, 0x00008ba9},
+ {0x00009b00, 0x0000b798, 0x0000b798, 0x00008bad, 0x00008bad, 0x00008bad},
+ {0x00009b04, 0x0000d784, 0x0000d784, 0x00008bb1, 0x00008bb1, 0x00008bb1},
+ {0x00009b08, 0x0000d788, 0x0000d788, 0x00008bb5, 0x00008bb5, 0x00008bb5},
+ {0x00009b0c, 0x0000d78c, 0x0000d78c, 0x00008ba2, 0x00008ba2, 0x00008ba2},
+ {0x00009b10, 0x0000d790, 0x0000d790, 0x00008ba6, 0x00008ba6, 0x00008ba6},
+ {0x00009b14, 0x0000f780, 0x0000f780, 0x00008baa, 0x00008baa, 0x00008baa},
+ {0x00009b18, 0x0000f784, 0x0000f784, 0x00008bae, 0x00008bae, 0x00008bae},
+ {0x00009b1c, 0x0000f788, 0x0000f788, 0x00008bb2, 0x00008bb2, 0x00008bb2},
+ {0x00009b20, 0x0000f78c, 0x0000f78c, 0x00008bb6, 0x00008bb6, 0x00008bb6},
+ {0x00009b24, 0x0000f790, 0x0000f790, 0x00008ba3, 0x00008ba3, 0x00008ba3},
+ {0x00009b28, 0x0000f794, 0x0000f794, 0x00008ba7, 0x00008ba7, 0x00008ba7},
+ {0x00009b2c, 0x0000f7a4, 0x0000f7a4, 0x00008bab, 0x00008bab, 0x00008bab},
+ {0x00009b30, 0x0000f7a8, 0x0000f7a8, 0x00008baf, 0x00008baf, 0x00008baf},
+ {0x00009b34, 0x0000f7ac, 0x0000f7ac, 0x00008bb3, 0x00008bb3, 0x00008bb3},
+ {0x00009b38, 0x0000f7b0, 0x0000f7b0, 0x00008bb7, 0x00008bb7, 0x00008bb7},
+ {0x00009b3c, 0x0000f7b4, 0x0000f7b4, 0x00008bc3, 0x00008bc3, 0x00008bc3},
+ {0x00009b40, 0x0000f7a1, 0x0000f7a1, 0x00008bc7, 0x00008bc7, 0x00008bc7},
+ {0x00009b44, 0x0000f7a5, 0x0000f7a5, 0x00008bcb, 0x00008bcb, 0x00008bcb},
+ {0x00009b48, 0x0000f7a9, 0x0000f7a9, 0x00008bcf, 0x00008bcf, 0x00008bcf},
+ {0x00009b4c, 0x0000f7ad, 0x0000f7ad, 0x00008bd3, 0x00008bd3, 0x00008bd3},
+ {0x00009b50, 0x0000f7b1, 0x0000f7b1, 0x00008bd7, 0x00008bd7, 0x00008bd7},
+ {0x00009b54, 0x0000f7b5, 0x0000f7b5, 0x00008bdb, 0x00008bdb, 0x00008bdb},
+ {0x00009b58, 0x0000f7c5, 0x0000f7c5, 0x00008bdb, 0x00008bdb, 0x00008bdb},
+ {0x00009b5c, 0x0000f7c9, 0x0000f7c9, 0x00008bdb, 0x00008bdb, 0x00008bdb},
+ {0x00009b60, 0x0000f7cd, 0x0000f7cd, 0x00008bdb, 0x00008bdb, 0x00008bdb},
+ {0x00009b64, 0x0000f7d1, 0x0000f7d1, 0x00008bdb, 0x00008bdb, 0x00008bdb},
+ {0x00009b68, 0x0000f7d5, 0x0000f7d5, 0x00008bdb, 0x00008bdb, 0x00008bdb},
+ {0x00009b6c, 0x0000f7c2, 0x0000f7c2, 0x00008bdb, 0x00008bdb, 0x00008bdb},
+ {0x00009b70, 0x0000f7c6, 0x0000f7c6, 0x00008bdb, 0x00008bdb, 0x00008bdb},
+ {0x00009b74, 0x0000f7ca, 0x0000f7ca, 0x00008bdb, 0x00008bdb, 0x00008bdb},
+ {0x00009b78, 0x0000f7ce, 0x0000f7ce, 0x00008bdb, 0x00008bdb, 0x00008bdb},
+ {0x00009b7c, 0x0000f7d2, 0x0000f7d2, 0x00008bdb, 0x00008bdb, 0x00008bdb},
+ {0x00009b80, 0x0000f7d6, 0x0000f7d6, 0x00008bdb, 0x00008bdb, 0x00008bdb},
+ {0x00009b84, 0x0000f7c3, 0x0000f7c3, 0x00008bdb, 0x00008bdb, 0x00008bdb},
+ {0x00009b88, 0x0000f7c7, 0x0000f7c7, 0x00008bdb, 0x00008bdb, 0x00008bdb},
+ {0x00009b8c, 0x0000f7cb, 0x0000f7cb, 0x00008bdb, 0x00008bdb, 0x00008bdb},
+ {0x00009b90, 0x0000f7d3, 0x0000f7d3, 0x00008bdb, 0x00008bdb, 0x00008bdb},
+ {0x00009b94, 0x0000f7d7, 0x0000f7d7, 0x00008bdb, 0x00008bdb, 0x00008bdb},
+ {0x00009b98, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb, 0x00008bdb},
+ {0x00009b9c, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb, 0x00008bdb},
+ {0x00009ba0, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb, 0x00008bdb},
+ {0x00009ba4, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb, 0x00008bdb},
+ {0x00009ba8, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb, 0x00008bdb},
+ {0x00009bac, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb, 0x00008bdb},
+ {0x00009bb0, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb, 0x00008bdb},
+ {0x00009bb4, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb, 0x00008bdb},
+ {0x00009bb8, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb, 0x00008bdb},
+ {0x00009bbc, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb, 0x00008bdb},
+ {0x00009bc0, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb, 0x00008bdb},
+ {0x00009bc4, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb, 0x00008bdb},
+ {0x00009bc8, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb, 0x00008bdb},
+ {0x00009bcc, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb, 0x00008bdb},
+ {0x00009bd0, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb, 0x00008bdb},
+ {0x00009bd4, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb, 0x00008bdb},
+ {0x00009bd8, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb, 0x00008bdb},
+ {0x00009bdc, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb, 0x00008bdb},
+ {0x00009be0, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb, 0x00008bdb},
+ {0x00009be4, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb, 0x00008bdb},
+ {0x00009be8, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb, 0x00008bdb},
+ {0x00009bec, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb, 0x00008bdb},
+ {0x00009bf0, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb, 0x00008bdb},
+ {0x00009bf4, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb, 0x00008bdb},
+ {0x00009bf8, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb, 0x00008bdb},
+ {0x00009bfc, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb, 0x00008bdb},
+ {0x00009848, 0x00001066, 0x00001066, 0x00001055, 0x00001055, 0x00001055},
+ {0x0000a848, 0x00001066, 0x00001066, 0x00001055, 0x00001055, 0x00001055},
};
static const u32 ar9280Modes_original_rxgain_9280_2[][6] = {
- { 0x00009a00, 0x00008184, 0x00008184, 0x00000290, 0x00000290, 0x00000290 },
- { 0x00009a04, 0x00008188, 0x00008188, 0x00000300, 0x00000300, 0x00000300 },
- { 0x00009a08, 0x0000818c, 0x0000818c, 0x00000304, 0x00000304, 0x00000304 },
- { 0x00009a0c, 0x00008190, 0x00008190, 0x00000308, 0x00000308, 0x00000308 },
- { 0x00009a10, 0x00008194, 0x00008194, 0x0000030c, 0x0000030c, 0x0000030c },
- { 0x00009a14, 0x00008200, 0x00008200, 0x00008000, 0x00008000, 0x00008000 },
- { 0x00009a18, 0x00008204, 0x00008204, 0x00008004, 0x00008004, 0x00008004 },
- { 0x00009a1c, 0x00008208, 0x00008208, 0x00008008, 0x00008008, 0x00008008 },
- { 0x00009a20, 0x0000820c, 0x0000820c, 0x0000800c, 0x0000800c, 0x0000800c },
- { 0x00009a24, 0x00008210, 0x00008210, 0x00008080, 0x00008080, 0x00008080 },
- { 0x00009a28, 0x00008214, 0x00008214, 0x00008084, 0x00008084, 0x00008084 },
- { 0x00009a2c, 0x00008280, 0x00008280, 0x00008088, 0x00008088, 0x00008088 },
- { 0x00009a30, 0x00008284, 0x00008284, 0x0000808c, 0x0000808c, 0x0000808c },
- { 0x00009a34, 0x00008288, 0x00008288, 0x00008100, 0x00008100, 0x00008100 },
- { 0x00009a38, 0x0000828c, 0x0000828c, 0x00008104, 0x00008104, 0x00008104 },
- { 0x00009a3c, 0x00008290, 0x00008290, 0x00008108, 0x00008108, 0x00008108 },
- { 0x00009a40, 0x00008300, 0x00008300, 0x0000810c, 0x0000810c, 0x0000810c },
- { 0x00009a44, 0x00008304, 0x00008304, 0x00008110, 0x00008110, 0x00008110 },
- { 0x00009a48, 0x00008308, 0x00008308, 0x00008114, 0x00008114, 0x00008114 },
- { 0x00009a4c, 0x0000830c, 0x0000830c, 0x00008180, 0x00008180, 0x00008180 },
- { 0x00009a50, 0x00008310, 0x00008310, 0x00008184, 0x00008184, 0x00008184 },
- { 0x00009a54, 0x00008314, 0x00008314, 0x00008188, 0x00008188, 0x00008188 },
- { 0x00009a58, 0x00008380, 0x00008380, 0x0000818c, 0x0000818c, 0x0000818c },
- { 0x00009a5c, 0x00008384, 0x00008384, 0x00008190, 0x00008190, 0x00008190 },
- { 0x00009a60, 0x00008388, 0x00008388, 0x00008194, 0x00008194, 0x00008194 },
- { 0x00009a64, 0x0000838c, 0x0000838c, 0x000081a0, 0x000081a0, 0x000081a0 },
- { 0x00009a68, 0x00008390, 0x00008390, 0x0000820c, 0x0000820c, 0x0000820c },
- { 0x00009a6c, 0x00008394, 0x00008394, 0x000081a8, 0x000081a8, 0x000081a8 },
- { 0x00009a70, 0x0000a380, 0x0000a380, 0x00008284, 0x00008284, 0x00008284 },
- { 0x00009a74, 0x0000a384, 0x0000a384, 0x00008288, 0x00008288, 0x00008288 },
- { 0x00009a78, 0x0000a388, 0x0000a388, 0x00008224, 0x00008224, 0x00008224 },
- { 0x00009a7c, 0x0000a38c, 0x0000a38c, 0x00008290, 0x00008290, 0x00008290 },
- { 0x00009a80, 0x0000a390, 0x0000a390, 0x00008300, 0x00008300, 0x00008300 },
- { 0x00009a84, 0x0000a394, 0x0000a394, 0x00008304, 0x00008304, 0x00008304 },
- { 0x00009a88, 0x0000a780, 0x0000a780, 0x00008308, 0x00008308, 0x00008308 },
- { 0x00009a8c, 0x0000a784, 0x0000a784, 0x0000830c, 0x0000830c, 0x0000830c },
- { 0x00009a90, 0x0000a788, 0x0000a788, 0x00008380, 0x00008380, 0x00008380 },
- { 0x00009a94, 0x0000a78c, 0x0000a78c, 0x00008384, 0x00008384, 0x00008384 },
- { 0x00009a98, 0x0000a790, 0x0000a790, 0x00008700, 0x00008700, 0x00008700 },
- { 0x00009a9c, 0x0000a794, 0x0000a794, 0x00008704, 0x00008704, 0x00008704 },
- { 0x00009aa0, 0x0000ab84, 0x0000ab84, 0x00008708, 0x00008708, 0x00008708 },
- { 0x00009aa4, 0x0000ab88, 0x0000ab88, 0x0000870c, 0x0000870c, 0x0000870c },
- { 0x00009aa8, 0x0000ab8c, 0x0000ab8c, 0x00008780, 0x00008780, 0x00008780 },
- { 0x00009aac, 0x0000ab90, 0x0000ab90, 0x00008784, 0x00008784, 0x00008784 },
- { 0x00009ab0, 0x0000ab94, 0x0000ab94, 0x00008b00, 0x00008b00, 0x00008b00 },
- { 0x00009ab4, 0x0000af80, 0x0000af80, 0x00008b04, 0x00008b04, 0x00008b04 },
- { 0x00009ab8, 0x0000af84, 0x0000af84, 0x00008b08, 0x00008b08, 0x00008b08 },
- { 0x00009abc, 0x0000af88, 0x0000af88, 0x00008b0c, 0x00008b0c, 0x00008b0c },
- { 0x00009ac0, 0x0000af8c, 0x0000af8c, 0x00008b80, 0x00008b80, 0x00008b80 },
- { 0x00009ac4, 0x0000af90, 0x0000af90, 0x00008b84, 0x00008b84, 0x00008b84 },
- { 0x00009ac8, 0x0000af94, 0x0000af94, 0x00008b88, 0x00008b88, 0x00008b88 },
- { 0x00009acc, 0x0000b380, 0x0000b380, 0x00008b8c, 0x00008b8c, 0x00008b8c },
- { 0x00009ad0, 0x0000b384, 0x0000b384, 0x00008b90, 0x00008b90, 0x00008b90 },
- { 0x00009ad4, 0x0000b388, 0x0000b388, 0x00008f80, 0x00008f80, 0x00008f80 },
- { 0x00009ad8, 0x0000b38c, 0x0000b38c, 0x00008f84, 0x00008f84, 0x00008f84 },
- { 0x00009adc, 0x0000b390, 0x0000b390, 0x00008f88, 0x00008f88, 0x00008f88 },
- { 0x00009ae0, 0x0000b394, 0x0000b394, 0x00008f8c, 0x00008f8c, 0x00008f8c },
- { 0x00009ae4, 0x0000b398, 0x0000b398, 0x00008f90, 0x00008f90, 0x00008f90 },
- { 0x00009ae8, 0x0000b780, 0x0000b780, 0x0000930c, 0x0000930c, 0x0000930c },
- { 0x00009aec, 0x0000b784, 0x0000b784, 0x00009310, 0x00009310, 0x00009310 },
- { 0x00009af0, 0x0000b788, 0x0000b788, 0x00009384, 0x00009384, 0x00009384 },
- { 0x00009af4, 0x0000b78c, 0x0000b78c, 0x00009388, 0x00009388, 0x00009388 },
- { 0x00009af8, 0x0000b790, 0x0000b790, 0x00009324, 0x00009324, 0x00009324 },
- { 0x00009afc, 0x0000b794, 0x0000b794, 0x00009704, 0x00009704, 0x00009704 },
- { 0x00009b00, 0x0000b798, 0x0000b798, 0x000096a4, 0x000096a4, 0x000096a4 },
- { 0x00009b04, 0x0000d784, 0x0000d784, 0x000096a8, 0x000096a8, 0x000096a8 },
- { 0x00009b08, 0x0000d788, 0x0000d788, 0x00009710, 0x00009710, 0x00009710 },
- { 0x00009b0c, 0x0000d78c, 0x0000d78c, 0x00009714, 0x00009714, 0x00009714 },
- { 0x00009b10, 0x0000d790, 0x0000d790, 0x00009720, 0x00009720, 0x00009720 },
- { 0x00009b14, 0x0000f780, 0x0000f780, 0x00009724, 0x00009724, 0x00009724 },
- { 0x00009b18, 0x0000f784, 0x0000f784, 0x00009728, 0x00009728, 0x00009728 },
- { 0x00009b1c, 0x0000f788, 0x0000f788, 0x0000972c, 0x0000972c, 0x0000972c },
- { 0x00009b20, 0x0000f78c, 0x0000f78c, 0x000097a0, 0x000097a0, 0x000097a0 },
- { 0x00009b24, 0x0000f790, 0x0000f790, 0x000097a4, 0x000097a4, 0x000097a4 },
- { 0x00009b28, 0x0000f794, 0x0000f794, 0x000097a8, 0x000097a8, 0x000097a8 },
- { 0x00009b2c, 0x0000f7a4, 0x0000f7a4, 0x000097b0, 0x000097b0, 0x000097b0 },
- { 0x00009b30, 0x0000f7a8, 0x0000f7a8, 0x000097b4, 0x000097b4, 0x000097b4 },
- { 0x00009b34, 0x0000f7ac, 0x0000f7ac, 0x000097b8, 0x000097b8, 0x000097b8 },
- { 0x00009b38, 0x0000f7b0, 0x0000f7b0, 0x000097a5, 0x000097a5, 0x000097a5 },
- { 0x00009b3c, 0x0000f7b4, 0x0000f7b4, 0x000097a9, 0x000097a9, 0x000097a9 },
- { 0x00009b40, 0x0000f7a1, 0x0000f7a1, 0x000097ad, 0x000097ad, 0x000097ad },
- { 0x00009b44, 0x0000f7a5, 0x0000f7a5, 0x000097b1, 0x000097b1, 0x000097b1 },
- { 0x00009b48, 0x0000f7a9, 0x0000f7a9, 0x000097b5, 0x000097b5, 0x000097b5 },
- { 0x00009b4c, 0x0000f7ad, 0x0000f7ad, 0x000097b9, 0x000097b9, 0x000097b9 },
- { 0x00009b50, 0x0000f7b1, 0x0000f7b1, 0x000097c5, 0x000097c5, 0x000097c5 },
- { 0x00009b54, 0x0000f7b5, 0x0000f7b5, 0x000097c9, 0x000097c9, 0x000097c9 },
- { 0x00009b58, 0x0000f7c5, 0x0000f7c5, 0x000097d1, 0x000097d1, 0x000097d1 },
- { 0x00009b5c, 0x0000f7c9, 0x0000f7c9, 0x000097d5, 0x000097d5, 0x000097d5 },
- { 0x00009b60, 0x0000f7cd, 0x0000f7cd, 0x000097d9, 0x000097d9, 0x000097d9 },
- { 0x00009b64, 0x0000f7d1, 0x0000f7d1, 0x000097c6, 0x000097c6, 0x000097c6 },
- { 0x00009b68, 0x0000f7d5, 0x0000f7d5, 0x000097ca, 0x000097ca, 0x000097ca },
- { 0x00009b6c, 0x0000f7c2, 0x0000f7c2, 0x000097ce, 0x000097ce, 0x000097ce },
- { 0x00009b70, 0x0000f7c6, 0x0000f7c6, 0x000097d2, 0x000097d2, 0x000097d2 },
- { 0x00009b74, 0x0000f7ca, 0x0000f7ca, 0x000097d6, 0x000097d6, 0x000097d6 },
- { 0x00009b78, 0x0000f7ce, 0x0000f7ce, 0x000097c3, 0x000097c3, 0x000097c3 },
- { 0x00009b7c, 0x0000f7d2, 0x0000f7d2, 0x000097c7, 0x000097c7, 0x000097c7 },
- { 0x00009b80, 0x0000f7d6, 0x0000f7d6, 0x000097cb, 0x000097cb, 0x000097cb },
- { 0x00009b84, 0x0000f7c3, 0x0000f7c3, 0x000097cf, 0x000097cf, 0x000097cf },
- { 0x00009b88, 0x0000f7c7, 0x0000f7c7, 0x000097d7, 0x000097d7, 0x000097d7 },
- { 0x00009b8c, 0x0000f7cb, 0x0000f7cb, 0x000097db, 0x000097db, 0x000097db },
- { 0x00009b90, 0x0000f7d3, 0x0000f7d3, 0x000097db, 0x000097db, 0x000097db },
- { 0x00009b94, 0x0000f7d7, 0x0000f7d7, 0x000097db, 0x000097db, 0x000097db },
- { 0x00009b98, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
- { 0x00009b9c, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
- { 0x00009ba0, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
- { 0x00009ba4, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
- { 0x00009ba8, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
- { 0x00009bac, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
- { 0x00009bb0, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
- { 0x00009bb4, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
- { 0x00009bb8, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
- { 0x00009bbc, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
- { 0x00009bc0, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
- { 0x00009bc4, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
- { 0x00009bc8, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
- { 0x00009bcc, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
- { 0x00009bd0, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
- { 0x00009bd4, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
- { 0x00009bd8, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
- { 0x00009bdc, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
- { 0x00009be0, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
- { 0x00009be4, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
- { 0x00009be8, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
- { 0x00009bec, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
- { 0x00009bf0, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
- { 0x00009bf4, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
- { 0x00009bf8, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
- { 0x00009bfc, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
- { 0x00009848, 0x00001066, 0x00001066, 0x00001063, 0x00001063, 0x00001063 },
- { 0x0000a848, 0x00001066, 0x00001066, 0x00001063, 0x00001063, 0x00001063 },
+ {0x00009a00, 0x00008184, 0x00008184, 0x00008000, 0x00008000, 0x00008000},
+ {0x00009a04, 0x00008188, 0x00008188, 0x00008000, 0x00008000, 0x00008000},
+ {0x00009a08, 0x0000818c, 0x0000818c, 0x00008000, 0x00008000, 0x00008000},
+ {0x00009a0c, 0x00008190, 0x00008190, 0x00008000, 0x00008000, 0x00008000},
+ {0x00009a10, 0x00008194, 0x00008194, 0x00008000, 0x00008000, 0x00008000},
+ {0x00009a14, 0x00008200, 0x00008200, 0x00008000, 0x00008000, 0x00008000},
+ {0x00009a18, 0x00008204, 0x00008204, 0x00008004, 0x00008004, 0x00008004},
+ {0x00009a1c, 0x00008208, 0x00008208, 0x00008008, 0x00008008, 0x00008008},
+ {0x00009a20, 0x0000820c, 0x0000820c, 0x0000800c, 0x0000800c, 0x0000800c},
+ {0x00009a24, 0x00008210, 0x00008210, 0x00008080, 0x00008080, 0x00008080},
+ {0x00009a28, 0x00008214, 0x00008214, 0x00008084, 0x00008084, 0x00008084},
+ {0x00009a2c, 0x00008280, 0x00008280, 0x00008088, 0x00008088, 0x00008088},
+ {0x00009a30, 0x00008284, 0x00008284, 0x0000808c, 0x0000808c, 0x0000808c},
+ {0x00009a34, 0x00008288, 0x00008288, 0x00008100, 0x00008100, 0x00008100},
+ {0x00009a38, 0x0000828c, 0x0000828c, 0x00008104, 0x00008104, 0x00008104},
+ {0x00009a3c, 0x00008290, 0x00008290, 0x00008108, 0x00008108, 0x00008108},
+ {0x00009a40, 0x00008300, 0x00008300, 0x0000810c, 0x0000810c, 0x0000810c},
+ {0x00009a44, 0x00008304, 0x00008304, 0x00008110, 0x00008110, 0x00008110},
+ {0x00009a48, 0x00008308, 0x00008308, 0x00008114, 0x00008114, 0x00008114},
+ {0x00009a4c, 0x0000830c, 0x0000830c, 0x00008180, 0x00008180, 0x00008180},
+ {0x00009a50, 0x00008310, 0x00008310, 0x00008184, 0x00008184, 0x00008184},
+ {0x00009a54, 0x00008314, 0x00008314, 0x00008188, 0x00008188, 0x00008188},
+ {0x00009a58, 0x00008380, 0x00008380, 0x0000818c, 0x0000818c, 0x0000818c},
+ {0x00009a5c, 0x00008384, 0x00008384, 0x00008190, 0x00008190, 0x00008190},
+ {0x00009a60, 0x00008388, 0x00008388, 0x00008194, 0x00008194, 0x00008194},
+ {0x00009a64, 0x0000838c, 0x0000838c, 0x000081a0, 0x000081a0, 0x000081a0},
+ {0x00009a68, 0x00008390, 0x00008390, 0x0000820c, 0x0000820c, 0x0000820c},
+ {0x00009a6c, 0x00008394, 0x00008394, 0x000081a8, 0x000081a8, 0x000081a8},
+ {0x00009a70, 0x0000a380, 0x0000a380, 0x00008284, 0x00008284, 0x00008284},
+ {0x00009a74, 0x0000a384, 0x0000a384, 0x00008288, 0x00008288, 0x00008288},
+ {0x00009a78, 0x0000a388, 0x0000a388, 0x00008224, 0x00008224, 0x00008224},
+ {0x00009a7c, 0x0000a38c, 0x0000a38c, 0x00008290, 0x00008290, 0x00008290},
+ {0x00009a80, 0x0000a390, 0x0000a390, 0x00008300, 0x00008300, 0x00008300},
+ {0x00009a84, 0x0000a394, 0x0000a394, 0x00008304, 0x00008304, 0x00008304},
+ {0x00009a88, 0x0000a780, 0x0000a780, 0x00008308, 0x00008308, 0x00008308},
+ {0x00009a8c, 0x0000a784, 0x0000a784, 0x0000830c, 0x0000830c, 0x0000830c},
+ {0x00009a90, 0x0000a788, 0x0000a788, 0x00008380, 0x00008380, 0x00008380},
+ {0x00009a94, 0x0000a78c, 0x0000a78c, 0x00008384, 0x00008384, 0x00008384},
+ {0x00009a98, 0x0000a790, 0x0000a790, 0x00008700, 0x00008700, 0x00008700},
+ {0x00009a9c, 0x0000a794, 0x0000a794, 0x00008704, 0x00008704, 0x00008704},
+ {0x00009aa0, 0x0000ab84, 0x0000ab84, 0x00008708, 0x00008708, 0x00008708},
+ {0x00009aa4, 0x0000ab88, 0x0000ab88, 0x0000870c, 0x0000870c, 0x0000870c},
+ {0x00009aa8, 0x0000ab8c, 0x0000ab8c, 0x00008780, 0x00008780, 0x00008780},
+ {0x00009aac, 0x0000ab90, 0x0000ab90, 0x00008784, 0x00008784, 0x00008784},
+ {0x00009ab0, 0x0000ab94, 0x0000ab94, 0x00008b00, 0x00008b00, 0x00008b00},
+ {0x00009ab4, 0x0000af80, 0x0000af80, 0x00008b04, 0x00008b04, 0x00008b04},
+ {0x00009ab8, 0x0000af84, 0x0000af84, 0x00008b08, 0x00008b08, 0x00008b08},
+ {0x00009abc, 0x0000af88, 0x0000af88, 0x00008b0c, 0x00008b0c, 0x00008b0c},
+ {0x00009ac0, 0x0000af8c, 0x0000af8c, 0x00008b80, 0x00008b80, 0x00008b80},
+ {0x00009ac4, 0x0000af90, 0x0000af90, 0x00008b84, 0x00008b84, 0x00008b84},
+ {0x00009ac8, 0x0000af94, 0x0000af94, 0x00008b88, 0x00008b88, 0x00008b88},
+ {0x00009acc, 0x0000b380, 0x0000b380, 0x00008b8c, 0x00008b8c, 0x00008b8c},
+ {0x00009ad0, 0x0000b384, 0x0000b384, 0x00008b90, 0x00008b90, 0x00008b90},
+ {0x00009ad4, 0x0000b388, 0x0000b388, 0x00008f80, 0x00008f80, 0x00008f80},
+ {0x00009ad8, 0x0000b38c, 0x0000b38c, 0x00008f84, 0x00008f84, 0x00008f84},
+ {0x00009adc, 0x0000b390, 0x0000b390, 0x00008f88, 0x00008f88, 0x00008f88},
+ {0x00009ae0, 0x0000b394, 0x0000b394, 0x00008f8c, 0x00008f8c, 0x00008f8c},
+ {0x00009ae4, 0x0000b398, 0x0000b398, 0x00008f90, 0x00008f90, 0x00008f90},
+ {0x00009ae8, 0x0000b780, 0x0000b780, 0x0000930c, 0x0000930c, 0x0000930c},
+ {0x00009aec, 0x0000b784, 0x0000b784, 0x00009310, 0x00009310, 0x00009310},
+ {0x00009af0, 0x0000b788, 0x0000b788, 0x00009384, 0x00009384, 0x00009384},
+ {0x00009af4, 0x0000b78c, 0x0000b78c, 0x00009388, 0x00009388, 0x00009388},
+ {0x00009af8, 0x0000b790, 0x0000b790, 0x00009324, 0x00009324, 0x00009324},
+ {0x00009afc, 0x0000b794, 0x0000b794, 0x00009704, 0x00009704, 0x00009704},
+ {0x00009b00, 0x0000b798, 0x0000b798, 0x000096a4, 0x000096a4, 0x000096a4},
+ {0x00009b04, 0x0000d784, 0x0000d784, 0x000096a8, 0x000096a8, 0x000096a8},
+ {0x00009b08, 0x0000d788, 0x0000d788, 0x00009710, 0x00009710, 0x00009710},
+ {0x00009b0c, 0x0000d78c, 0x0000d78c, 0x00009714, 0x00009714, 0x00009714},
+ {0x00009b10, 0x0000d790, 0x0000d790, 0x00009720, 0x00009720, 0x00009720},
+ {0x00009b14, 0x0000f780, 0x0000f780, 0x00009724, 0x00009724, 0x00009724},
+ {0x00009b18, 0x0000f784, 0x0000f784, 0x00009728, 0x00009728, 0x00009728},
+ {0x00009b1c, 0x0000f788, 0x0000f788, 0x0000972c, 0x0000972c, 0x0000972c},
+ {0x00009b20, 0x0000f78c, 0x0000f78c, 0x000097a0, 0x000097a0, 0x000097a0},
+ {0x00009b24, 0x0000f790, 0x0000f790, 0x000097a4, 0x000097a4, 0x000097a4},
+ {0x00009b28, 0x0000f794, 0x0000f794, 0x000097a8, 0x000097a8, 0x000097a8},
+ {0x00009b2c, 0x0000f7a4, 0x0000f7a4, 0x000097b0, 0x000097b0, 0x000097b0},
+ {0x00009b30, 0x0000f7a8, 0x0000f7a8, 0x000097b4, 0x000097b4, 0x000097b4},
+ {0x00009b34, 0x0000f7ac, 0x0000f7ac, 0x000097b8, 0x000097b8, 0x000097b8},
+ {0x00009b38, 0x0000f7b0, 0x0000f7b0, 0x000097a5, 0x000097a5, 0x000097a5},
+ {0x00009b3c, 0x0000f7b4, 0x0000f7b4, 0x000097a9, 0x000097a9, 0x000097a9},
+ {0x00009b40, 0x0000f7a1, 0x0000f7a1, 0x000097ad, 0x000097ad, 0x000097ad},
+ {0x00009b44, 0x0000f7a5, 0x0000f7a5, 0x000097b1, 0x000097b1, 0x000097b1},
+ {0x00009b48, 0x0000f7a9, 0x0000f7a9, 0x000097b5, 0x000097b5, 0x000097b5},
+ {0x00009b4c, 0x0000f7ad, 0x0000f7ad, 0x000097b9, 0x000097b9, 0x000097b9},
+ {0x00009b50, 0x0000f7b1, 0x0000f7b1, 0x000097c5, 0x000097c5, 0x000097c5},
+ {0x00009b54, 0x0000f7b5, 0x0000f7b5, 0x000097c9, 0x000097c9, 0x000097c9},
+ {0x00009b58, 0x0000f7c5, 0x0000f7c5, 0x000097d1, 0x000097d1, 0x000097d1},
+ {0x00009b5c, 0x0000f7c9, 0x0000f7c9, 0x000097d5, 0x000097d5, 0x000097d5},
+ {0x00009b60, 0x0000f7cd, 0x0000f7cd, 0x000097d9, 0x000097d9, 0x000097d9},
+ {0x00009b64, 0x0000f7d1, 0x0000f7d1, 0x000097c6, 0x000097c6, 0x000097c6},
+ {0x00009b68, 0x0000f7d5, 0x0000f7d5, 0x000097ca, 0x000097ca, 0x000097ca},
+ {0x00009b6c, 0x0000f7c2, 0x0000f7c2, 0x000097ce, 0x000097ce, 0x000097ce},
+ {0x00009b70, 0x0000f7c6, 0x0000f7c6, 0x000097d2, 0x000097d2, 0x000097d2},
+ {0x00009b74, 0x0000f7ca, 0x0000f7ca, 0x000097d6, 0x000097d6, 0x000097d6},
+ {0x00009b78, 0x0000f7ce, 0x0000f7ce, 0x000097c3, 0x000097c3, 0x000097c3},
+ {0x00009b7c, 0x0000f7d2, 0x0000f7d2, 0x000097c7, 0x000097c7, 0x000097c7},
+ {0x00009b80, 0x0000f7d6, 0x0000f7d6, 0x000097cb, 0x000097cb, 0x000097cb},
+ {0x00009b84, 0x0000f7c3, 0x0000f7c3, 0x000097cf, 0x000097cf, 0x000097cf},
+ {0x00009b88, 0x0000f7c7, 0x0000f7c7, 0x000097d7, 0x000097d7, 0x000097d7},
+ {0x00009b8c, 0x0000f7cb, 0x0000f7cb, 0x000097db, 0x000097db, 0x000097db},
+ {0x00009b90, 0x0000f7d3, 0x0000f7d3, 0x000097db, 0x000097db, 0x000097db},
+ {0x00009b94, 0x0000f7d7, 0x0000f7d7, 0x000097db, 0x000097db, 0x000097db},
+ {0x00009b98, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db},
+ {0x00009b9c, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db},
+ {0x00009ba0, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db},
+ {0x00009ba4, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db},
+ {0x00009ba8, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db},
+ {0x00009bac, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db},
+ {0x00009bb0, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db},
+ {0x00009bb4, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db},
+ {0x00009bb8, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db},
+ {0x00009bbc, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db},
+ {0x00009bc0, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db},
+ {0x00009bc4, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db},
+ {0x00009bc8, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db},
+ {0x00009bcc, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db},
+ {0x00009bd0, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db},
+ {0x00009bd4, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db},
+ {0x00009bd8, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db},
+ {0x00009bdc, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db},
+ {0x00009be0, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db},
+ {0x00009be4, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db},
+ {0x00009be8, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db},
+ {0x00009bec, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db},
+ {0x00009bf0, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db},
+ {0x00009bf4, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db},
+ {0x00009bf8, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db},
+ {0x00009bfc, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db},
+ {0x00009848, 0x00001066, 0x00001066, 0x00001063, 0x00001063, 0x00001063},
+ {0x0000a848, 0x00001066, 0x00001066, 0x00001063, 0x00001063, 0x00001063},
};
static const u32 ar9280Modes_backoff_13db_rxgain_9280_2[][6] = {
- { 0x00009a00, 0x00008184, 0x00008184, 0x00000290, 0x00000290, 0x00000290 },
- { 0x00009a04, 0x00008188, 0x00008188, 0x00000300, 0x00000300, 0x00000300 },
- { 0x00009a08, 0x0000818c, 0x0000818c, 0x00000304, 0x00000304, 0x00000304 },
- { 0x00009a0c, 0x00008190, 0x00008190, 0x00000308, 0x00000308, 0x00000308 },
- { 0x00009a10, 0x00008194, 0x00008194, 0x0000030c, 0x0000030c, 0x0000030c },
- { 0x00009a14, 0x00008200, 0x00008200, 0x00008000, 0x00008000, 0x00008000 },
- { 0x00009a18, 0x00008204, 0x00008204, 0x00008004, 0x00008004, 0x00008004 },
- { 0x00009a1c, 0x00008208, 0x00008208, 0x00008008, 0x00008008, 0x00008008 },
- { 0x00009a20, 0x0000820c, 0x0000820c, 0x0000800c, 0x0000800c, 0x0000800c },
- { 0x00009a24, 0x00008210, 0x00008210, 0x00008080, 0x00008080, 0x00008080 },
- { 0x00009a28, 0x00008214, 0x00008214, 0x00008084, 0x00008084, 0x00008084 },
- { 0x00009a2c, 0x00008280, 0x00008280, 0x00008088, 0x00008088, 0x00008088 },
- { 0x00009a30, 0x00008284, 0x00008284, 0x0000808c, 0x0000808c, 0x0000808c },
- { 0x00009a34, 0x00008288, 0x00008288, 0x00008100, 0x00008100, 0x00008100 },
- { 0x00009a38, 0x0000828c, 0x0000828c, 0x00008104, 0x00008104, 0x00008104 },
- { 0x00009a3c, 0x00008290, 0x00008290, 0x00008108, 0x00008108, 0x00008108 },
- { 0x00009a40, 0x00008300, 0x00008300, 0x0000810c, 0x0000810c, 0x0000810c },
- { 0x00009a44, 0x00008304, 0x00008304, 0x00008110, 0x00008110, 0x00008110 },
- { 0x00009a48, 0x00008308, 0x00008308, 0x00008114, 0x00008114, 0x00008114 },
- { 0x00009a4c, 0x0000830c, 0x0000830c, 0x00008180, 0x00008180, 0x00008180 },
- { 0x00009a50, 0x00008310, 0x00008310, 0x00008184, 0x00008184, 0x00008184 },
- { 0x00009a54, 0x00008314, 0x00008314, 0x00008188, 0x00008188, 0x00008188 },
- { 0x00009a58, 0x00008380, 0x00008380, 0x0000818c, 0x0000818c, 0x0000818c },
- { 0x00009a5c, 0x00008384, 0x00008384, 0x00008190, 0x00008190, 0x00008190 },
- { 0x00009a60, 0x00008388, 0x00008388, 0x00008194, 0x00008194, 0x00008194 },
- { 0x00009a64, 0x0000838c, 0x0000838c, 0x000081a0, 0x000081a0, 0x000081a0 },
- { 0x00009a68, 0x00008390, 0x00008390, 0x0000820c, 0x0000820c, 0x0000820c },
- { 0x00009a6c, 0x00008394, 0x00008394, 0x000081a8, 0x000081a8, 0x000081a8 },
- { 0x00009a70, 0x0000a380, 0x0000a380, 0x00008284, 0x00008284, 0x00008284 },
- { 0x00009a74, 0x0000a384, 0x0000a384, 0x00008288, 0x00008288, 0x00008288 },
- { 0x00009a78, 0x0000a388, 0x0000a388, 0x00008224, 0x00008224, 0x00008224 },
- { 0x00009a7c, 0x0000a38c, 0x0000a38c, 0x00008290, 0x00008290, 0x00008290 },
- { 0x00009a80, 0x0000a390, 0x0000a390, 0x00008300, 0x00008300, 0x00008300 },
- { 0x00009a84, 0x0000a394, 0x0000a394, 0x00008304, 0x00008304, 0x00008304 },
- { 0x00009a88, 0x0000a780, 0x0000a780, 0x00008308, 0x00008308, 0x00008308 },
- { 0x00009a8c, 0x0000a784, 0x0000a784, 0x0000830c, 0x0000830c, 0x0000830c },
- { 0x00009a90, 0x0000a788, 0x0000a788, 0x00008380, 0x00008380, 0x00008380 },
- { 0x00009a94, 0x0000a78c, 0x0000a78c, 0x00008384, 0x00008384, 0x00008384 },
- { 0x00009a98, 0x0000a790, 0x0000a790, 0x00008700, 0x00008700, 0x00008700 },
- { 0x00009a9c, 0x0000a794, 0x0000a794, 0x00008704, 0x00008704, 0x00008704 },
- { 0x00009aa0, 0x0000ab84, 0x0000ab84, 0x00008708, 0x00008708, 0x00008708 },
- { 0x00009aa4, 0x0000ab88, 0x0000ab88, 0x0000870c, 0x0000870c, 0x0000870c },
- { 0x00009aa8, 0x0000ab8c, 0x0000ab8c, 0x00008780, 0x00008780, 0x00008780 },
- { 0x00009aac, 0x0000ab90, 0x0000ab90, 0x00008784, 0x00008784, 0x00008784 },
- { 0x00009ab0, 0x0000ab94, 0x0000ab94, 0x00008b00, 0x00008b00, 0x00008b00 },
- { 0x00009ab4, 0x0000af80, 0x0000af80, 0x00008b04, 0x00008b04, 0x00008b04 },
- { 0x00009ab8, 0x0000af84, 0x0000af84, 0x00008b08, 0x00008b08, 0x00008b08 },
- { 0x00009abc, 0x0000af88, 0x0000af88, 0x00008b0c, 0x00008b0c, 0x00008b0c },
- { 0x00009ac0, 0x0000af8c, 0x0000af8c, 0x00008b80, 0x00008b80, 0x00008b80 },
- { 0x00009ac4, 0x0000af90, 0x0000af90, 0x00008b84, 0x00008b84, 0x00008b84 },
- { 0x00009ac8, 0x0000af94, 0x0000af94, 0x00008b88, 0x00008b88, 0x00008b88 },
- { 0x00009acc, 0x0000b380, 0x0000b380, 0x00008b8c, 0x00008b8c, 0x00008b8c },
- { 0x00009ad0, 0x0000b384, 0x0000b384, 0x00008b90, 0x00008b90, 0x00008b90 },
- { 0x00009ad4, 0x0000b388, 0x0000b388, 0x00008f80, 0x00008f80, 0x00008f80 },
- { 0x00009ad8, 0x0000b38c, 0x0000b38c, 0x00008f84, 0x00008f84, 0x00008f84 },
- { 0x00009adc, 0x0000b390, 0x0000b390, 0x00008f88, 0x00008f88, 0x00008f88 },
- { 0x00009ae0, 0x0000b394, 0x0000b394, 0x00008f8c, 0x00008f8c, 0x00008f8c },
- { 0x00009ae4, 0x0000b398, 0x0000b398, 0x00008f90, 0x00008f90, 0x00008f90 },
- { 0x00009ae8, 0x0000b780, 0x0000b780, 0x00009310, 0x00009310, 0x00009310 },
- { 0x00009aec, 0x0000b784, 0x0000b784, 0x00009314, 0x00009314, 0x00009314 },
- { 0x00009af0, 0x0000b788, 0x0000b788, 0x00009320, 0x00009320, 0x00009320 },
- { 0x00009af4, 0x0000b78c, 0x0000b78c, 0x00009324, 0x00009324, 0x00009324 },
- { 0x00009af8, 0x0000b790, 0x0000b790, 0x00009328, 0x00009328, 0x00009328 },
- { 0x00009afc, 0x0000b794, 0x0000b794, 0x0000932c, 0x0000932c, 0x0000932c },
- { 0x00009b00, 0x0000b798, 0x0000b798, 0x00009330, 0x00009330, 0x00009330 },
- { 0x00009b04, 0x0000d784, 0x0000d784, 0x00009334, 0x00009334, 0x00009334 },
- { 0x00009b08, 0x0000d788, 0x0000d788, 0x00009321, 0x00009321, 0x00009321 },
- { 0x00009b0c, 0x0000d78c, 0x0000d78c, 0x00009325, 0x00009325, 0x00009325 },
- { 0x00009b10, 0x0000d790, 0x0000d790, 0x00009329, 0x00009329, 0x00009329 },
- { 0x00009b14, 0x0000f780, 0x0000f780, 0x0000932d, 0x0000932d, 0x0000932d },
- { 0x00009b18, 0x0000f784, 0x0000f784, 0x00009331, 0x00009331, 0x00009331 },
- { 0x00009b1c, 0x0000f788, 0x0000f788, 0x00009335, 0x00009335, 0x00009335 },
- { 0x00009b20, 0x0000f78c, 0x0000f78c, 0x00009322, 0x00009322, 0x00009322 },
- { 0x00009b24, 0x0000f790, 0x0000f790, 0x00009326, 0x00009326, 0x00009326 },
- { 0x00009b28, 0x0000f794, 0x0000f794, 0x0000932a, 0x0000932a, 0x0000932a },
- { 0x00009b2c, 0x0000f7a4, 0x0000f7a4, 0x0000932e, 0x0000932e, 0x0000932e },
- { 0x00009b30, 0x0000f7a8, 0x0000f7a8, 0x00009332, 0x00009332, 0x00009332 },
- { 0x00009b34, 0x0000f7ac, 0x0000f7ac, 0x00009336, 0x00009336, 0x00009336 },
- { 0x00009b38, 0x0000f7b0, 0x0000f7b0, 0x00009323, 0x00009323, 0x00009323 },
- { 0x00009b3c, 0x0000f7b4, 0x0000f7b4, 0x00009327, 0x00009327, 0x00009327 },
- { 0x00009b40, 0x0000f7a1, 0x0000f7a1, 0x0000932b, 0x0000932b, 0x0000932b },
- { 0x00009b44, 0x0000f7a5, 0x0000f7a5, 0x0000932f, 0x0000932f, 0x0000932f },
- { 0x00009b48, 0x0000f7a9, 0x0000f7a9, 0x00009333, 0x00009333, 0x00009333 },
- { 0x00009b4c, 0x0000f7ad, 0x0000f7ad, 0x00009337, 0x00009337, 0x00009337 },
- { 0x00009b50, 0x0000f7b1, 0x0000f7b1, 0x00009343, 0x00009343, 0x00009343 },
- { 0x00009b54, 0x0000f7b5, 0x0000f7b5, 0x00009347, 0x00009347, 0x00009347 },
- { 0x00009b58, 0x0000f7c5, 0x0000f7c5, 0x0000934b, 0x0000934b, 0x0000934b },
- { 0x00009b5c, 0x0000f7c9, 0x0000f7c9, 0x0000934f, 0x0000934f, 0x0000934f },
- { 0x00009b60, 0x0000f7cd, 0x0000f7cd, 0x00009353, 0x00009353, 0x00009353 },
- { 0x00009b64, 0x0000f7d1, 0x0000f7d1, 0x00009357, 0x00009357, 0x00009357 },
- { 0x00009b68, 0x0000f7d5, 0x0000f7d5, 0x0000935b, 0x0000935b, 0x0000935b },
- { 0x00009b6c, 0x0000f7c2, 0x0000f7c2, 0x0000935b, 0x0000935b, 0x0000935b },
- { 0x00009b70, 0x0000f7c6, 0x0000f7c6, 0x0000935b, 0x0000935b, 0x0000935b },
- { 0x00009b74, 0x0000f7ca, 0x0000f7ca, 0x0000935b, 0x0000935b, 0x0000935b },
- { 0x00009b78, 0x0000f7ce, 0x0000f7ce, 0x0000935b, 0x0000935b, 0x0000935b },
- { 0x00009b7c, 0x0000f7d2, 0x0000f7d2, 0x0000935b, 0x0000935b, 0x0000935b },
- { 0x00009b80, 0x0000f7d6, 0x0000f7d6, 0x0000935b, 0x0000935b, 0x0000935b },
- { 0x00009b84, 0x0000f7c3, 0x0000f7c3, 0x0000935b, 0x0000935b, 0x0000935b },
- { 0x00009b88, 0x0000f7c7, 0x0000f7c7, 0x0000935b, 0x0000935b, 0x0000935b },
- { 0x00009b8c, 0x0000f7cb, 0x0000f7cb, 0x0000935b, 0x0000935b, 0x0000935b },
- { 0x00009b90, 0x0000f7d3, 0x0000f7d3, 0x0000935b, 0x0000935b, 0x0000935b },
- { 0x00009b94, 0x0000f7d7, 0x0000f7d7, 0x0000935b, 0x0000935b, 0x0000935b },
- { 0x00009b98, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b },
- { 0x00009b9c, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b },
- { 0x00009ba0, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b },
- { 0x00009ba4, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b },
- { 0x00009ba8, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b },
- { 0x00009bac, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b },
- { 0x00009bb0, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b },
- { 0x00009bb4, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b },
- { 0x00009bb8, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b },
- { 0x00009bbc, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b },
- { 0x00009bc0, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b },
- { 0x00009bc4, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b },
- { 0x00009bc8, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b },
- { 0x00009bcc, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b },
- { 0x00009bd0, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b },
- { 0x00009bd4, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b },
- { 0x00009bd8, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b },
- { 0x00009bdc, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b },
- { 0x00009be0, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b },
- { 0x00009be4, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b },
- { 0x00009be8, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b },
- { 0x00009bec, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b },
- { 0x00009bf0, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b },
- { 0x00009bf4, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b },
- { 0x00009bf8, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b },
- { 0x00009bfc, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b },
- { 0x00009848, 0x00001066, 0x00001066, 0x0000105a, 0x0000105a, 0x0000105a },
- { 0x0000a848, 0x00001066, 0x00001066, 0x0000105a, 0x0000105a, 0x0000105a },
+ {0x00009a00, 0x00008184, 0x00008184, 0x00000290, 0x00000290, 0x00000290},
+ {0x00009a04, 0x00008188, 0x00008188, 0x00000300, 0x00000300, 0x00000300},
+ {0x00009a08, 0x0000818c, 0x0000818c, 0x00000304, 0x00000304, 0x00000304},
+ {0x00009a0c, 0x00008190, 0x00008190, 0x00000308, 0x00000308, 0x00000308},
+ {0x00009a10, 0x00008194, 0x00008194, 0x0000030c, 0x0000030c, 0x0000030c},
+ {0x00009a14, 0x00008200, 0x00008200, 0x00008000, 0x00008000, 0x00008000},
+ {0x00009a18, 0x00008204, 0x00008204, 0x00008004, 0x00008004, 0x00008004},
+ {0x00009a1c, 0x00008208, 0x00008208, 0x00008008, 0x00008008, 0x00008008},
+ {0x00009a20, 0x0000820c, 0x0000820c, 0x0000800c, 0x0000800c, 0x0000800c},
+ {0x00009a24, 0x00008210, 0x00008210, 0x00008080, 0x00008080, 0x00008080},
+ {0x00009a28, 0x00008214, 0x00008214, 0x00008084, 0x00008084, 0x00008084},
+ {0x00009a2c, 0x00008280, 0x00008280, 0x00008088, 0x00008088, 0x00008088},
+ {0x00009a30, 0x00008284, 0x00008284, 0x0000808c, 0x0000808c, 0x0000808c},
+ {0x00009a34, 0x00008288, 0x00008288, 0x00008100, 0x00008100, 0x00008100},
+ {0x00009a38, 0x0000828c, 0x0000828c, 0x00008104, 0x00008104, 0x00008104},
+ {0x00009a3c, 0x00008290, 0x00008290, 0x00008108, 0x00008108, 0x00008108},
+ {0x00009a40, 0x00008300, 0x00008300, 0x0000810c, 0x0000810c, 0x0000810c},
+ {0x00009a44, 0x00008304, 0x00008304, 0x00008110, 0x00008110, 0x00008110},
+ {0x00009a48, 0x00008308, 0x00008308, 0x00008114, 0x00008114, 0x00008114},
+ {0x00009a4c, 0x0000830c, 0x0000830c, 0x00008180, 0x00008180, 0x00008180},
+ {0x00009a50, 0x00008310, 0x00008310, 0x00008184, 0x00008184, 0x00008184},
+ {0x00009a54, 0x00008314, 0x00008314, 0x00008188, 0x00008188, 0x00008188},
+ {0x00009a58, 0x00008380, 0x00008380, 0x0000818c, 0x0000818c, 0x0000818c},
+ {0x00009a5c, 0x00008384, 0x00008384, 0x00008190, 0x00008190, 0x00008190},
+ {0x00009a60, 0x00008388, 0x00008388, 0x00008194, 0x00008194, 0x00008194},
+ {0x00009a64, 0x0000838c, 0x0000838c, 0x000081a0, 0x000081a0, 0x000081a0},
+ {0x00009a68, 0x00008390, 0x00008390, 0x0000820c, 0x0000820c, 0x0000820c},
+ {0x00009a6c, 0x00008394, 0x00008394, 0x000081a8, 0x000081a8, 0x000081a8},
+ {0x00009a70, 0x0000a380, 0x0000a380, 0x00008284, 0x00008284, 0x00008284},
+ {0x00009a74, 0x0000a384, 0x0000a384, 0x00008288, 0x00008288, 0x00008288},
+ {0x00009a78, 0x0000a388, 0x0000a388, 0x00008224, 0x00008224, 0x00008224},
+ {0x00009a7c, 0x0000a38c, 0x0000a38c, 0x00008290, 0x00008290, 0x00008290},
+ {0x00009a80, 0x0000a390, 0x0000a390, 0x00008300, 0x00008300, 0x00008300},
+ {0x00009a84, 0x0000a394, 0x0000a394, 0x00008304, 0x00008304, 0x00008304},
+ {0x00009a88, 0x0000a780, 0x0000a780, 0x00008308, 0x00008308, 0x00008308},
+ {0x00009a8c, 0x0000a784, 0x0000a784, 0x0000830c, 0x0000830c, 0x0000830c},
+ {0x00009a90, 0x0000a788, 0x0000a788, 0x00008380, 0x00008380, 0x00008380},
+ {0x00009a94, 0x0000a78c, 0x0000a78c, 0x00008384, 0x00008384, 0x00008384},
+ {0x00009a98, 0x0000a790, 0x0000a790, 0x00008700, 0x00008700, 0x00008700},
+ {0x00009a9c, 0x0000a794, 0x0000a794, 0x00008704, 0x00008704, 0x00008704},
+ {0x00009aa0, 0x0000ab84, 0x0000ab84, 0x00008708, 0x00008708, 0x00008708},
+ {0x00009aa4, 0x0000ab88, 0x0000ab88, 0x0000870c, 0x0000870c, 0x0000870c},
+ {0x00009aa8, 0x0000ab8c, 0x0000ab8c, 0x00008780, 0x00008780, 0x00008780},
+ {0x00009aac, 0x0000ab90, 0x0000ab90, 0x00008784, 0x00008784, 0x00008784},
+ {0x00009ab0, 0x0000ab94, 0x0000ab94, 0x00008b00, 0x00008b00, 0x00008b00},
+ {0x00009ab4, 0x0000af80, 0x0000af80, 0x00008b04, 0x00008b04, 0x00008b04},
+ {0x00009ab8, 0x0000af84, 0x0000af84, 0x00008b08, 0x00008b08, 0x00008b08},
+ {0x00009abc, 0x0000af88, 0x0000af88, 0x00008b0c, 0x00008b0c, 0x00008b0c},
+ {0x00009ac0, 0x0000af8c, 0x0000af8c, 0x00008b80, 0x00008b80, 0x00008b80},
+ {0x00009ac4, 0x0000af90, 0x0000af90, 0x00008b84, 0x00008b84, 0x00008b84},
+ {0x00009ac8, 0x0000af94, 0x0000af94, 0x00008b88, 0x00008b88, 0x00008b88},
+ {0x00009acc, 0x0000b380, 0x0000b380, 0x00008b8c, 0x00008b8c, 0x00008b8c},
+ {0x00009ad0, 0x0000b384, 0x0000b384, 0x00008b90, 0x00008b90, 0x00008b90},
+ {0x00009ad4, 0x0000b388, 0x0000b388, 0x00008f80, 0x00008f80, 0x00008f80},
+ {0x00009ad8, 0x0000b38c, 0x0000b38c, 0x00008f84, 0x00008f84, 0x00008f84},
+ {0x00009adc, 0x0000b390, 0x0000b390, 0x00008f88, 0x00008f88, 0x00008f88},
+ {0x00009ae0, 0x0000b394, 0x0000b394, 0x00008f8c, 0x00008f8c, 0x00008f8c},
+ {0x00009ae4, 0x0000b398, 0x0000b398, 0x00008f90, 0x00008f90, 0x00008f90},
+ {0x00009ae8, 0x0000b780, 0x0000b780, 0x00009310, 0x00009310, 0x00009310},
+ {0x00009aec, 0x0000b784, 0x0000b784, 0x00009314, 0x00009314, 0x00009314},
+ {0x00009af0, 0x0000b788, 0x0000b788, 0x00009320, 0x00009320, 0x00009320},
+ {0x00009af4, 0x0000b78c, 0x0000b78c, 0x00009324, 0x00009324, 0x00009324},
+ {0x00009af8, 0x0000b790, 0x0000b790, 0x00009328, 0x00009328, 0x00009328},
+ {0x00009afc, 0x0000b794, 0x0000b794, 0x0000932c, 0x0000932c, 0x0000932c},
+ {0x00009b00, 0x0000b798, 0x0000b798, 0x00009330, 0x00009330, 0x00009330},
+ {0x00009b04, 0x0000d784, 0x0000d784, 0x00009334, 0x00009334, 0x00009334},
+ {0x00009b08, 0x0000d788, 0x0000d788, 0x00009321, 0x00009321, 0x00009321},
+ {0x00009b0c, 0x0000d78c, 0x0000d78c, 0x00009325, 0x00009325, 0x00009325},
+ {0x00009b10, 0x0000d790, 0x0000d790, 0x00009329, 0x00009329, 0x00009329},
+ {0x00009b14, 0x0000f780, 0x0000f780, 0x0000932d, 0x0000932d, 0x0000932d},
+ {0x00009b18, 0x0000f784, 0x0000f784, 0x00009331, 0x00009331, 0x00009331},
+ {0x00009b1c, 0x0000f788, 0x0000f788, 0x00009335, 0x00009335, 0x00009335},
+ {0x00009b20, 0x0000f78c, 0x0000f78c, 0x00009322, 0x00009322, 0x00009322},
+ {0x00009b24, 0x0000f790, 0x0000f790, 0x00009326, 0x00009326, 0x00009326},
+ {0x00009b28, 0x0000f794, 0x0000f794, 0x0000932a, 0x0000932a, 0x0000932a},
+ {0x00009b2c, 0x0000f7a4, 0x0000f7a4, 0x0000932e, 0x0000932e, 0x0000932e},
+ {0x00009b30, 0x0000f7a8, 0x0000f7a8, 0x00009332, 0x00009332, 0x00009332},
+ {0x00009b34, 0x0000f7ac, 0x0000f7ac, 0x00009336, 0x00009336, 0x00009336},
+ {0x00009b38, 0x0000f7b0, 0x0000f7b0, 0x00009323, 0x00009323, 0x00009323},
+ {0x00009b3c, 0x0000f7b4, 0x0000f7b4, 0x00009327, 0x00009327, 0x00009327},
+ {0x00009b40, 0x0000f7a1, 0x0000f7a1, 0x0000932b, 0x0000932b, 0x0000932b},
+ {0x00009b44, 0x0000f7a5, 0x0000f7a5, 0x0000932f, 0x0000932f, 0x0000932f},
+ {0x00009b48, 0x0000f7a9, 0x0000f7a9, 0x00009333, 0x00009333, 0x00009333},
+ {0x00009b4c, 0x0000f7ad, 0x0000f7ad, 0x00009337, 0x00009337, 0x00009337},
+ {0x00009b50, 0x0000f7b1, 0x0000f7b1, 0x00009343, 0x00009343, 0x00009343},
+ {0x00009b54, 0x0000f7b5, 0x0000f7b5, 0x00009347, 0x00009347, 0x00009347},
+ {0x00009b58, 0x0000f7c5, 0x0000f7c5, 0x0000934b, 0x0000934b, 0x0000934b},
+ {0x00009b5c, 0x0000f7c9, 0x0000f7c9, 0x0000934f, 0x0000934f, 0x0000934f},
+ {0x00009b60, 0x0000f7cd, 0x0000f7cd, 0x00009353, 0x00009353, 0x00009353},
+ {0x00009b64, 0x0000f7d1, 0x0000f7d1, 0x00009357, 0x00009357, 0x00009357},
+ {0x00009b68, 0x0000f7d5, 0x0000f7d5, 0x0000935b, 0x0000935b, 0x0000935b},
+ {0x00009b6c, 0x0000f7c2, 0x0000f7c2, 0x0000935b, 0x0000935b, 0x0000935b},
+ {0x00009b70, 0x0000f7c6, 0x0000f7c6, 0x0000935b, 0x0000935b, 0x0000935b},
+ {0x00009b74, 0x0000f7ca, 0x0000f7ca, 0x0000935b, 0x0000935b, 0x0000935b},
+ {0x00009b78, 0x0000f7ce, 0x0000f7ce, 0x0000935b, 0x0000935b, 0x0000935b},
+ {0x00009b7c, 0x0000f7d2, 0x0000f7d2, 0x0000935b, 0x0000935b, 0x0000935b},
+ {0x00009b80, 0x0000f7d6, 0x0000f7d6, 0x0000935b, 0x0000935b, 0x0000935b},
+ {0x00009b84, 0x0000f7c3, 0x0000f7c3, 0x0000935b, 0x0000935b, 0x0000935b},
+ {0x00009b88, 0x0000f7c7, 0x0000f7c7, 0x0000935b, 0x0000935b, 0x0000935b},
+ {0x00009b8c, 0x0000f7cb, 0x0000f7cb, 0x0000935b, 0x0000935b, 0x0000935b},
+ {0x00009b90, 0x0000f7d3, 0x0000f7d3, 0x0000935b, 0x0000935b, 0x0000935b},
+ {0x00009b94, 0x0000f7d7, 0x0000f7d7, 0x0000935b, 0x0000935b, 0x0000935b},
+ {0x00009b98, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b},
+ {0x00009b9c, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b},
+ {0x00009ba0, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b},
+ {0x00009ba4, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b},
+ {0x00009ba8, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b},
+ {0x00009bac, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b},
+ {0x00009bb0, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b},
+ {0x00009bb4, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b},
+ {0x00009bb8, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b},
+ {0x00009bbc, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b},
+ {0x00009bc0, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b},
+ {0x00009bc4, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b},
+ {0x00009bc8, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b},
+ {0x00009bcc, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b},
+ {0x00009bd0, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b},
+ {0x00009bd4, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b},
+ {0x00009bd8, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b},
+ {0x00009bdc, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b},
+ {0x00009be0, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b},
+ {0x00009be4, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b},
+ {0x00009be8, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b},
+ {0x00009bec, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b},
+ {0x00009bf0, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b},
+ {0x00009bf4, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b},
+ {0x00009bf8, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b},
+ {0x00009bfc, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b},
+ {0x00009848, 0x00001066, 0x00001066, 0x0000105a, 0x0000105a, 0x0000105a},
+ {0x0000a848, 0x00001066, 0x00001066, 0x0000105a, 0x0000105a, 0x0000105a},
};
static const u32 ar9280Modes_high_power_tx_gain_9280_2[][6] = {
- { 0x0000a274, 0x0a19e652, 0x0a19e652, 0x0a1aa652, 0x0a1aa652, 0x0a1aa652 },
- { 0x0000a27c, 0x050739ce, 0x050739ce, 0x050739ce, 0x050739ce, 0x050739ce },
- { 0x0000a300, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
- { 0x0000a304, 0x00003002, 0x00003002, 0x00004002, 0x00004002, 0x00004002 },
- { 0x0000a308, 0x00006004, 0x00006004, 0x00007008, 0x00007008, 0x00007008 },
- { 0x0000a30c, 0x0000a006, 0x0000a006, 0x0000c010, 0x0000c010, 0x0000c010 },
- { 0x0000a310, 0x0000e012, 0x0000e012, 0x00010012, 0x00010012, 0x00010012 },
- { 0x0000a314, 0x00011014, 0x00011014, 0x00013014, 0x00013014, 0x00013014 },
- { 0x0000a318, 0x0001504a, 0x0001504a, 0x0001820a, 0x0001820a, 0x0001820a },
- { 0x0000a31c, 0x0001904c, 0x0001904c, 0x0001b211, 0x0001b211, 0x0001b211 },
- { 0x0000a320, 0x0001c04e, 0x0001c04e, 0x0001e213, 0x0001e213, 0x0001e213 },
- { 0x0000a324, 0x00021092, 0x00021092, 0x00022411, 0x00022411, 0x00022411 },
- { 0x0000a328, 0x0002510a, 0x0002510a, 0x00025413, 0x00025413, 0x00025413 },
- { 0x0000a32c, 0x0002910c, 0x0002910c, 0x00029811, 0x00029811, 0x00029811 },
- { 0x0000a330, 0x0002c18b, 0x0002c18b, 0x0002c813, 0x0002c813, 0x0002c813 },
- { 0x0000a334, 0x0002f1cc, 0x0002f1cc, 0x00030a14, 0x00030a14, 0x00030a14 },
- { 0x0000a338, 0x000321eb, 0x000321eb, 0x00035a50, 0x00035a50, 0x00035a50 },
- { 0x0000a33c, 0x000341ec, 0x000341ec, 0x00039c4c, 0x00039c4c, 0x00039c4c },
- { 0x0000a340, 0x000341ec, 0x000341ec, 0x0003de8a, 0x0003de8a, 0x0003de8a },
- { 0x0000a344, 0x000341ec, 0x000341ec, 0x00042e92, 0x00042e92, 0x00042e92 },
- { 0x0000a348, 0x000341ec, 0x000341ec, 0x00046ed2, 0x00046ed2, 0x00046ed2 },
- { 0x0000a34c, 0x000341ec, 0x000341ec, 0x0004bed5, 0x0004bed5, 0x0004bed5 },
- { 0x0000a350, 0x000341ec, 0x000341ec, 0x0004ff54, 0x0004ff54, 0x0004ff54 },
- { 0x0000a354, 0x000341ec, 0x000341ec, 0x00055fd5, 0x00055fd5, 0x00055fd5 },
- { 0x00007814, 0x00198eff, 0x00198eff, 0x00198eff, 0x00198eff, 0x00198eff },
- { 0x00007838, 0x00198eff, 0x00198eff, 0x00198eff, 0x00198eff, 0x00198eff },
- { 0x0000781c, 0x00172000, 0x00172000, 0x00172000, 0x00172000, 0x00172000 },
- { 0x00007840, 0x00172000, 0x00172000, 0x00172000, 0x00172000, 0x00172000 },
- { 0x00007820, 0xf258a480, 0xf258a480, 0xf258a480, 0xf258a480, 0xf258a480 },
- { 0x00007844, 0xf258a480, 0xf258a480, 0xf258a480, 0xf258a480, 0xf258a480 },
+ {0x0000a274, 0x0a19e652, 0x0a19e652, 0x0a1aa652, 0x0a1aa652, 0x0a1aa652},
+ {0x0000a27c, 0x050739ce, 0x050739ce, 0x050739ce, 0x050739ce, 0x050739ce},
+ {0x0000a300, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+ {0x0000a304, 0x00003002, 0x00003002, 0x00004002, 0x00004002, 0x00004002},
+ {0x0000a308, 0x00006004, 0x00006004, 0x00007008, 0x00007008, 0x00007008},
+ {0x0000a30c, 0x0000a006, 0x0000a006, 0x0000c010, 0x0000c010, 0x0000c010},
+ {0x0000a310, 0x0000e012, 0x0000e012, 0x00010012, 0x00010012, 0x00010012},
+ {0x0000a314, 0x00011014, 0x00011014, 0x00013014, 0x00013014, 0x00013014},
+ {0x0000a318, 0x0001504a, 0x0001504a, 0x0001820a, 0x0001820a, 0x0001820a},
+ {0x0000a31c, 0x0001904c, 0x0001904c, 0x0001b211, 0x0001b211, 0x0001b211},
+ {0x0000a320, 0x0001c04e, 0x0001c04e, 0x0001e213, 0x0001e213, 0x0001e213},
+ {0x0000a324, 0x00021092, 0x00021092, 0x00022411, 0x00022411, 0x00022411},
+ {0x0000a328, 0x0002510a, 0x0002510a, 0x00025413, 0x00025413, 0x00025413},
+ {0x0000a32c, 0x0002910c, 0x0002910c, 0x00029811, 0x00029811, 0x00029811},
+ {0x0000a330, 0x0002c18b, 0x0002c18b, 0x0002c813, 0x0002c813, 0x0002c813},
+ {0x0000a334, 0x0002f1cc, 0x0002f1cc, 0x00030a14, 0x00030a14, 0x00030a14},
+ {0x0000a338, 0x000321eb, 0x000321eb, 0x00035a50, 0x00035a50, 0x00035a50},
+ {0x0000a33c, 0x000341ec, 0x000341ec, 0x00039c4c, 0x00039c4c, 0x00039c4c},
+ {0x0000a340, 0x000341ec, 0x000341ec, 0x0003de8a, 0x0003de8a, 0x0003de8a},
+ {0x0000a344, 0x000341ec, 0x000341ec, 0x00042e92, 0x00042e92, 0x00042e92},
+ {0x0000a348, 0x000341ec, 0x000341ec, 0x00046ed2, 0x00046ed2, 0x00046ed2},
+ {0x0000a34c, 0x000341ec, 0x000341ec, 0x0004bed5, 0x0004bed5, 0x0004bed5},
+ {0x0000a350, 0x000341ec, 0x000341ec, 0x0004ff54, 0x0004ff54, 0x0004ff54},
+ {0x0000a354, 0x000341ec, 0x000341ec, 0x00055fd5, 0x00055fd5, 0x00055fd5},
+ {0x0000a3ec, 0x00f70081, 0x00f70081, 0x00f70081, 0x00f70081, 0x00f70081},
+ {0x00007814, 0x00198eff, 0x00198eff, 0x00198eff, 0x00198eff, 0x00198eff},
+ {0x00007838, 0x00198eff, 0x00198eff, 0x00198eff, 0x00198eff, 0x00198eff},
+ {0x0000781c, 0x00172000, 0x00172000, 0x00172000, 0x00172000, 0x00172000},
+ {0x00007840, 0x00172000, 0x00172000, 0x00172000, 0x00172000, 0x00172000},
+ {0x00007820, 0xf258a480, 0xf258a480, 0xf258a480, 0xf258a480, 0xf258a480},
+ {0x00007844, 0xf258a480, 0xf258a480, 0xf258a480, 0xf258a480, 0xf258a480},
};
static const u32 ar9280Modes_original_tx_gain_9280_2[][6] = {
- { 0x0000a274, 0x0a19c652, 0x0a19c652, 0x0a1aa652, 0x0a1aa652, 0x0a1aa652 },
- { 0x0000a27c, 0x050701ce, 0x050701ce, 0x050701ce, 0x050701ce, 0x050701ce },
- { 0x0000a300, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
- { 0x0000a304, 0x00003002, 0x00003002, 0x00003002, 0x00003002, 0x00003002 },
- { 0x0000a308, 0x00006004, 0x00006004, 0x00008009, 0x00008009, 0x00008009 },
- { 0x0000a30c, 0x0000a006, 0x0000a006, 0x0000b00b, 0x0000b00b, 0x0000b00b },
- { 0x0000a310, 0x0000e012, 0x0000e012, 0x0000e012, 0x0000e012, 0x0000e012 },
- { 0x0000a314, 0x00011014, 0x00011014, 0x00012048, 0x00012048, 0x00012048 },
- { 0x0000a318, 0x0001504a, 0x0001504a, 0x0001604a, 0x0001604a, 0x0001604a },
- { 0x0000a31c, 0x0001904c, 0x0001904c, 0x0001a211, 0x0001a211, 0x0001a211 },
- { 0x0000a320, 0x0001c04e, 0x0001c04e, 0x0001e213, 0x0001e213, 0x0001e213 },
- { 0x0000a324, 0x00020092, 0x00020092, 0x0002121b, 0x0002121b, 0x0002121b },
- { 0x0000a328, 0x0002410a, 0x0002410a, 0x00024412, 0x00024412, 0x00024412 },
- { 0x0000a32c, 0x0002710c, 0x0002710c, 0x00028414, 0x00028414, 0x00028414 },
- { 0x0000a330, 0x0002b18b, 0x0002b18b, 0x0002b44a, 0x0002b44a, 0x0002b44a },
- { 0x0000a334, 0x0002e1cc, 0x0002e1cc, 0x00030649, 0x00030649, 0x00030649 },
- { 0x0000a338, 0x000321ec, 0x000321ec, 0x0003364b, 0x0003364b, 0x0003364b },
- { 0x0000a33c, 0x000321ec, 0x000321ec, 0x00038a49, 0x00038a49, 0x00038a49 },
- { 0x0000a340, 0x000321ec, 0x000321ec, 0x0003be48, 0x0003be48, 0x0003be48 },
- { 0x0000a344, 0x000321ec, 0x000321ec, 0x0003ee4a, 0x0003ee4a, 0x0003ee4a },
- { 0x0000a348, 0x000321ec, 0x000321ec, 0x00042e88, 0x00042e88, 0x00042e88 },
- { 0x0000a34c, 0x000321ec, 0x000321ec, 0x00046e8a, 0x00046e8a, 0x00046e8a },
- { 0x0000a350, 0x000321ec, 0x000321ec, 0x00049ec9, 0x00049ec9, 0x00049ec9 },
- { 0x0000a354, 0x000321ec, 0x000321ec, 0x0004bf42, 0x0004bf42, 0x0004bf42 },
- { 0x00007814, 0x0019beff, 0x0019beff, 0x0019beff, 0x0019beff, 0x0019beff },
- { 0x00007838, 0x0019beff, 0x0019beff, 0x0019beff, 0x0019beff, 0x0019beff },
- { 0x0000781c, 0x00392000, 0x00392000, 0x00392000, 0x00392000, 0x00392000 },
- { 0x00007840, 0x00392000, 0x00392000, 0x00392000, 0x00392000, 0x00392000 },
- { 0x00007820, 0x92592480, 0x92592480, 0x92592480, 0x92592480, 0x92592480 },
- { 0x00007844, 0x92592480, 0x92592480, 0x92592480, 0x92592480, 0x92592480 },
+ {0x0000a274, 0x0a19c652, 0x0a19c652, 0x0a1aa652, 0x0a1aa652, 0x0a1aa652},
+ {0x0000a27c, 0x050701ce, 0x050701ce, 0x050701ce, 0x050701ce, 0x050701ce},
+ {0x0000a300, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+ {0x0000a304, 0x00003002, 0x00003002, 0x00003002, 0x00003002, 0x00003002},
+ {0x0000a308, 0x00006004, 0x00006004, 0x00008009, 0x00008009, 0x00008009},
+ {0x0000a30c, 0x0000a006, 0x0000a006, 0x0000b00b, 0x0000b00b, 0x0000b00b},
+ {0x0000a310, 0x0000e012, 0x0000e012, 0x0000e012, 0x0000e012, 0x0000e012},
+ {0x0000a314, 0x00011014, 0x00011014, 0x00012048, 0x00012048, 0x00012048},
+ {0x0000a318, 0x0001504a, 0x0001504a, 0x0001604a, 0x0001604a, 0x0001604a},
+ {0x0000a31c, 0x0001904c, 0x0001904c, 0x0001a211, 0x0001a211, 0x0001a211},
+ {0x0000a320, 0x0001c04e, 0x0001c04e, 0x0001e213, 0x0001e213, 0x0001e213},
+ {0x0000a324, 0x00020092, 0x00020092, 0x0002121b, 0x0002121b, 0x0002121b},
+ {0x0000a328, 0x0002410a, 0x0002410a, 0x00024412, 0x00024412, 0x00024412},
+ {0x0000a32c, 0x0002710c, 0x0002710c, 0x00028414, 0x00028414, 0x00028414},
+ {0x0000a330, 0x0002b18b, 0x0002b18b, 0x0002b44a, 0x0002b44a, 0x0002b44a},
+ {0x0000a334, 0x0002e1cc, 0x0002e1cc, 0x00030649, 0x00030649, 0x00030649},
+ {0x0000a338, 0x000321ec, 0x000321ec, 0x0003364b, 0x0003364b, 0x0003364b},
+ {0x0000a33c, 0x000321ec, 0x000321ec, 0x00038a49, 0x00038a49, 0x00038a49},
+ {0x0000a340, 0x000321ec, 0x000321ec, 0x0003be48, 0x0003be48, 0x0003be48},
+ {0x0000a344, 0x000321ec, 0x000321ec, 0x0003ee4a, 0x0003ee4a, 0x0003ee4a},
+ {0x0000a348, 0x000321ec, 0x000321ec, 0x00042e88, 0x00042e88, 0x00042e88},
+ {0x0000a34c, 0x000321ec, 0x000321ec, 0x00046e8a, 0x00046e8a, 0x00046e8a},
+ {0x0000a350, 0x000321ec, 0x000321ec, 0x00049ec9, 0x00049ec9, 0x00049ec9},
+ {0x0000a354, 0x000321ec, 0x000321ec, 0x0004bf42, 0x0004bf42, 0x0004bf42},
+ {0x0000a3ec, 0x00f70081, 0x00f70081, 0x00f70081, 0x00f70081, 0x00f70081},
+ {0x00007814, 0x0019beff, 0x0019beff, 0x0019beff, 0x0019beff, 0x0019beff},
+ {0x00007838, 0x0019beff, 0x0019beff, 0x0019beff, 0x0019beff, 0x0019beff},
+ {0x0000781c, 0x00392000, 0x00392000, 0x00392000, 0x00392000, 0x00392000},
+ {0x00007840, 0x00392000, 0x00392000, 0x00392000, 0x00392000, 0x00392000},
+ {0x00007820, 0x92592480, 0x92592480, 0x92592480, 0x92592480, 0x92592480},
+ {0x00007844, 0x92592480, 0x92592480, 0x92592480, 0x92592480, 0x92592480},
};
static const u32 ar9280PciePhy_clkreq_off_L1_9280[][2] = {
- {0x00004040, 0x9248fd00 },
- {0x00004040, 0x24924924 },
- {0x00004040, 0xa8000019 },
- {0x00004040, 0x13160820 },
- {0x00004040, 0xe5980560 },
- {0x00004040, 0xc01dcffc },
- {0x00004040, 0x1aaabe41 },
- {0x00004040, 0xbe105554 },
- {0x00004040, 0x00043007 },
- {0x00004044, 0x00000000 },
+ /* Addr allmodes */
+ {0x00004040, 0x9248fd00},
+ {0x00004040, 0x24924924},
+ {0x00004040, 0xa8000019},
+ {0x00004040, 0x13160820},
+ {0x00004040, 0xe5980560},
+ {0x00004040, 0xc01dcffc},
+ {0x00004040, 0x1aaabe41},
+ {0x00004040, 0xbe105554},
+ {0x00004040, 0x00043007},
+ {0x00004044, 0x00000000},
};
static const u32 ar9280PciePhy_clkreq_always_on_L1_9280[][2] = {
- {0x00004040, 0x9248fd00 },
- {0x00004040, 0x24924924 },
- {0x00004040, 0xa8000019 },
- {0x00004040, 0x13160820 },
- {0x00004040, 0xe5980560 },
- {0x00004040, 0xc01dcffd },
- {0x00004040, 0x1aaabe41 },
- {0x00004040, 0xbe105554 },
- {0x00004040, 0x00043007 },
- {0x00004044, 0x00000000 },
-};
-
-/* AR9285 Revsion 10*/
-static const u32 ar9285Modes_9285[][6] = {
- { 0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160, 0x000001e0 },
- { 0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c, 0x000001e0 },
- { 0x000010b0, 0x00000e60, 0x00001cc0, 0x00007c70, 0x00003e38, 0x00001180 },
- { 0x000010f0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000008 },
- { 0x00008014, 0x03e803e8, 0x07d007d0, 0x10801600, 0x08400b00, 0x06e006e0 },
- { 0x0000801c, 0x128d8027, 0x128d804f, 0x12e00057, 0x12e0002b, 0x0988004f },
- { 0x00008318, 0x00003e80, 0x00007d00, 0x00006880, 0x00003440, 0x00006880 },
- { 0x00009804, 0x00000300, 0x000003c4, 0x000003c4, 0x00000300, 0x00000303 },
- { 0x00009820, 0x02020200, 0x02020200, 0x02020200, 0x02020200, 0x02020200 },
- { 0x00009824, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e },
- { 0x00009828, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001 },
- { 0x00009834, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e },
- { 0x00009838, 0x00000007, 0x00000007, 0x00000007, 0x00000007, 0x00000007 },
- { 0x00009840, 0x206a012e, 0x206a012e, 0x206a012e, 0x206a012e, 0x206a012e },
- { 0x00009844, 0x0372161e, 0x0372161e, 0x03720020, 0x03720020, 0x037216a0 },
- { 0x00009848, 0x00001066, 0x00001066, 0x0000004e, 0x0000004e, 0x00001059 },
- { 0x00009850, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2 },
- { 0x00009858, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e },
- { 0x0000985c, 0x3139605e, 0x3139605e, 0x3136605e, 0x3136605e, 0x3139605e },
- { 0x00009860, 0x00058d18, 0x00058d18, 0x00058d20, 0x00058d20, 0x00058d18 },
- { 0x00009864, 0x0000fe00, 0x0000fe00, 0x0001ce00, 0x0001ce00, 0x0001ce00 },
- { 0x00009868, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0 },
- { 0x0000986c, 0x06903081, 0x06903081, 0x06903881, 0x06903881, 0x06903881 },
- { 0x00009914, 0x000007d0, 0x00000fa0, 0x00001130, 0x00000898, 0x000007d0 },
- { 0x00009918, 0x0000000a, 0x00000014, 0x00000016, 0x0000000b, 0x00000016 },
- { 0x00009924, 0xd00a8007, 0xd00a8007, 0xd00a800d, 0xd00a800d, 0xd00a800d },
- { 0x00009944, 0xdfbc1010, 0xdfbc1010, 0xdfbc1020, 0xdfbc1020, 0xdfbc1010 },
- { 0x00009960, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
- { 0x00009964, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
- { 0x000099b8, 0x00cf4d1c, 0x00cf4d1c, 0x00cf4d1c, 0x00cf4d1c, 0x00cf4d1c },
- { 0x000099bc, 0x00000600, 0x00000600, 0x00000c00, 0x00000c00, 0x00000c00 },
- { 0x000099c0, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4 },
- { 0x000099c4, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77 },
- { 0x000099c8, 0x60f65329, 0x60f65329, 0x60f65329, 0x60f65329, 0x60f65329 },
- { 0x000099cc, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8 },
- { 0x000099d0, 0x00046384, 0x00046384, 0x00046384, 0x00046384, 0x00046384 },
- { 0x000099d4, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
- { 0x000099d8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
- { 0x00009a00, 0x00000000, 0x00000000, 0x00068084, 0x00068084, 0x00000000 },
- { 0x00009a04, 0x00000000, 0x00000000, 0x00068088, 0x00068088, 0x00000000 },
- { 0x00009a08, 0x00000000, 0x00000000, 0x0006808c, 0x0006808c, 0x00000000 },
- { 0x00009a0c, 0x00000000, 0x00000000, 0x00068100, 0x00068100, 0x00000000 },
- { 0x00009a10, 0x00000000, 0x00000000, 0x00068104, 0x00068104, 0x00000000 },
- { 0x00009a14, 0x00000000, 0x00000000, 0x00068108, 0x00068108, 0x00000000 },
- { 0x00009a18, 0x00000000, 0x00000000, 0x0006810c, 0x0006810c, 0x00000000 },
- { 0x00009a1c, 0x00000000, 0x00000000, 0x00068110, 0x00068110, 0x00000000 },
- { 0x00009a20, 0x00000000, 0x00000000, 0x00068114, 0x00068114, 0x00000000 },
- { 0x00009a24, 0x00000000, 0x00000000, 0x00068180, 0x00068180, 0x00000000 },
- { 0x00009a28, 0x00000000, 0x00000000, 0x00068184, 0x00068184, 0x00000000 },
- { 0x00009a2c, 0x00000000, 0x00000000, 0x00068188, 0x00068188, 0x00000000 },
- { 0x00009a30, 0x00000000, 0x00000000, 0x0006818c, 0x0006818c, 0x00000000 },
- { 0x00009a34, 0x00000000, 0x00000000, 0x00068190, 0x00068190, 0x00000000 },
- { 0x00009a38, 0x00000000, 0x00000000, 0x00068194, 0x00068194, 0x00000000 },
- { 0x00009a3c, 0x00000000, 0x00000000, 0x000681a0, 0x000681a0, 0x00000000 },
- { 0x00009a40, 0x00000000, 0x00000000, 0x0006820c, 0x0006820c, 0x00000000 },
- { 0x00009a44, 0x00000000, 0x00000000, 0x000681a8, 0x000681a8, 0x00000000 },
- { 0x00009a48, 0x00000000, 0x00000000, 0x00068284, 0x00068284, 0x00000000 },
- { 0x00009a4c, 0x00000000, 0x00000000, 0x00068288, 0x00068288, 0x00000000 },
- { 0x00009a50, 0x00000000, 0x00000000, 0x00068220, 0x00068220, 0x00000000 },
- { 0x00009a54, 0x00000000, 0x00000000, 0x00068290, 0x00068290, 0x00000000 },
- { 0x00009a58, 0x00000000, 0x00000000, 0x00068300, 0x00068300, 0x00000000 },
- { 0x00009a5c, 0x00000000, 0x00000000, 0x00068304, 0x00068304, 0x00000000 },
- { 0x00009a60, 0x00000000, 0x00000000, 0x00068308, 0x00068308, 0x00000000 },
- { 0x00009a64, 0x00000000, 0x00000000, 0x0006830c, 0x0006830c, 0x00000000 },
- { 0x00009a68, 0x00000000, 0x00000000, 0x00068380, 0x00068380, 0x00000000 },
- { 0x00009a6c, 0x00000000, 0x00000000, 0x00068384, 0x00068384, 0x00000000 },
- { 0x00009a70, 0x00000000, 0x00000000, 0x00068700, 0x00068700, 0x00000000 },
- { 0x00009a74, 0x00000000, 0x00000000, 0x00068704, 0x00068704, 0x00000000 },
- { 0x00009a78, 0x00000000, 0x00000000, 0x00068708, 0x00068708, 0x00000000 },
- { 0x00009a7c, 0x00000000, 0x00000000, 0x0006870c, 0x0006870c, 0x00000000 },
- { 0x00009a80, 0x00000000, 0x00000000, 0x00068780, 0x00068780, 0x00000000 },
- { 0x00009a84, 0x00000000, 0x00000000, 0x00068784, 0x00068784, 0x00000000 },
- { 0x00009a88, 0x00000000, 0x00000000, 0x00068b04, 0x00068b04, 0x00000000 },
- { 0x00009a8c, 0x00000000, 0x00000000, 0x00068b08, 0x00068b08, 0x00000000 },
- { 0x00009a90, 0x00000000, 0x00000000, 0x00068b08, 0x00068b08, 0x00000000 },
- { 0x00009a94, 0x00000000, 0x00000000, 0x00068b0c, 0x00068b0c, 0x00000000 },
- { 0x00009a98, 0x00000000, 0x00000000, 0x00068b80, 0x00068b80, 0x00000000 },
- { 0x00009a9c, 0x00000000, 0x00000000, 0x00068b84, 0x00068b84, 0x00000000 },
- { 0x00009aa0, 0x00000000, 0x00000000, 0x00068b88, 0x00068b88, 0x00000000 },
- { 0x00009aa4, 0x00000000, 0x00000000, 0x00068b8c, 0x00068b8c, 0x00000000 },
- { 0x00009aa8, 0x00000000, 0x00000000, 0x000b8b90, 0x000b8b90, 0x00000000 },
- { 0x00009aac, 0x00000000, 0x00000000, 0x000b8f80, 0x000b8f80, 0x00000000 },
- { 0x00009ab0, 0x00000000, 0x00000000, 0x000b8f84, 0x000b8f84, 0x00000000 },
- { 0x00009ab4, 0x00000000, 0x00000000, 0x000b8f88, 0x000b8f88, 0x00000000 },
- { 0x00009ab8, 0x00000000, 0x00000000, 0x000b8f8c, 0x000b8f8c, 0x00000000 },
- { 0x00009abc, 0x00000000, 0x00000000, 0x000b8f90, 0x000b8f90, 0x00000000 },
- { 0x00009ac0, 0x00000000, 0x00000000, 0x000bb30c, 0x000bb30c, 0x00000000 },
- { 0x00009ac4, 0x00000000, 0x00000000, 0x000bb310, 0x000bb310, 0x00000000 },
- { 0x00009ac8, 0x00000000, 0x00000000, 0x000bb384, 0x000bb384, 0x00000000 },
- { 0x00009acc, 0x00000000, 0x00000000, 0x000bb388, 0x000bb388, 0x00000000 },
- { 0x00009ad0, 0x00000000, 0x00000000, 0x000bb324, 0x000bb324, 0x00000000 },
- { 0x00009ad4, 0x00000000, 0x00000000, 0x000bb704, 0x000bb704, 0x00000000 },
- { 0x00009ad8, 0x00000000, 0x00000000, 0x000f96a4, 0x000f96a4, 0x00000000 },
- { 0x00009adc, 0x00000000, 0x00000000, 0x000f96a8, 0x000f96a8, 0x00000000 },
- { 0x00009ae0, 0x00000000, 0x00000000, 0x000f9710, 0x000f9710, 0x00000000 },
- { 0x00009ae4, 0x00000000, 0x00000000, 0x000f9714, 0x000f9714, 0x00000000 },
- { 0x00009ae8, 0x00000000, 0x00000000, 0x000f9720, 0x000f9720, 0x00000000 },
- { 0x00009aec, 0x00000000, 0x00000000, 0x000f9724, 0x000f9724, 0x00000000 },
- { 0x00009af0, 0x00000000, 0x00000000, 0x000f9728, 0x000f9728, 0x00000000 },
- { 0x00009af4, 0x00000000, 0x00000000, 0x000f972c, 0x000f972c, 0x00000000 },
- { 0x00009af8, 0x00000000, 0x00000000, 0x000f97a0, 0x000f97a0, 0x00000000 },
- { 0x00009afc, 0x00000000, 0x00000000, 0x000f97a4, 0x000f97a4, 0x00000000 },
- { 0x00009b00, 0x00000000, 0x00000000, 0x000fb7a8, 0x000fb7a8, 0x00000000 },
- { 0x00009b04, 0x00000000, 0x00000000, 0x000fb7b0, 0x000fb7b0, 0x00000000 },
- { 0x00009b08, 0x00000000, 0x00000000, 0x000fb7b4, 0x000fb7b4, 0x00000000 },
- { 0x00009b0c, 0x00000000, 0x00000000, 0x000fb7b8, 0x000fb7b8, 0x00000000 },
- { 0x00009b10, 0x00000000, 0x00000000, 0x000fb7a5, 0x000fb7a5, 0x00000000 },
- { 0x00009b14, 0x00000000, 0x00000000, 0x000fb7a9, 0x000fb7a9, 0x00000000 },
- { 0x00009b18, 0x00000000, 0x00000000, 0x000fb7ad, 0x000fb7ad, 0x00000000 },
- { 0x00009b1c, 0x00000000, 0x00000000, 0x000fb7b1, 0x000fb7b1, 0x00000000 },
- { 0x00009b20, 0x00000000, 0x00000000, 0x000fb7b5, 0x000fb7b5, 0x00000000 },
- { 0x00009b24, 0x00000000, 0x00000000, 0x000fb7b9, 0x000fb7b9, 0x00000000 },
- { 0x00009b28, 0x00000000, 0x00000000, 0x000fb7c5, 0x000fb7c5, 0x00000000 },
- { 0x00009b2c, 0x00000000, 0x00000000, 0x000fb7c9, 0x000fb7c9, 0x00000000 },
- { 0x00009b30, 0x00000000, 0x00000000, 0x000fb7d1, 0x000fb7d1, 0x00000000 },
- { 0x00009b34, 0x00000000, 0x00000000, 0x000fb7d5, 0x000fb7d5, 0x00000000 },
- { 0x00009b38, 0x00000000, 0x00000000, 0x000fb7d9, 0x000fb7d9, 0x00000000 },
- { 0x00009b3c, 0x00000000, 0x00000000, 0x000fb7c6, 0x000fb7c6, 0x00000000 },
- { 0x00009b40, 0x00000000, 0x00000000, 0x000fb7ca, 0x000fb7ca, 0x00000000 },
- { 0x00009b44, 0x00000000, 0x00000000, 0x000fb7ce, 0x000fb7ce, 0x00000000 },
- { 0x00009b48, 0x00000000, 0x00000000, 0x000fb7d2, 0x000fb7d2, 0x00000000 },
- { 0x00009b4c, 0x00000000, 0x00000000, 0x000fb7d6, 0x000fb7d6, 0x00000000 },
- { 0x00009b50, 0x00000000, 0x00000000, 0x000fb7c3, 0x000fb7c3, 0x00000000 },
- { 0x00009b54, 0x00000000, 0x00000000, 0x000fb7c7, 0x000fb7c7, 0x00000000 },
- { 0x00009b58, 0x00000000, 0x00000000, 0x000fb7cb, 0x000fb7cb, 0x00000000 },
- { 0x00009b5c, 0x00000000, 0x00000000, 0x000fb7cf, 0x000fb7cf, 0x00000000 },
- { 0x00009b60, 0x00000000, 0x00000000, 0x000fb7d7, 0x000fb7d7, 0x00000000 },
- { 0x00009b64, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
- { 0x00009b68, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
- { 0x00009b6c, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
- { 0x00009b70, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
- { 0x00009b74, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
- { 0x00009b78, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
- { 0x00009b7c, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
- { 0x00009b80, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
- { 0x00009b84, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
- { 0x00009b88, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
- { 0x00009b8c, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
- { 0x00009b90, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
- { 0x00009b94, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
- { 0x00009b98, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
- { 0x00009b9c, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
- { 0x00009ba0, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
- { 0x00009ba4, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
- { 0x00009ba8, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
- { 0x00009bac, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
- { 0x00009bb0, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
- { 0x00009bb4, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
- { 0x00009bb8, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
- { 0x00009bbc, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
- { 0x00009bc0, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
- { 0x00009bc4, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
- { 0x00009bc8, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
- { 0x00009bcc, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
- { 0x00009bd0, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
- { 0x00009bd4, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
- { 0x00009bd8, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
- { 0x00009bdc, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
- { 0x00009be0, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
- { 0x00009be4, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
- { 0x00009be8, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
- { 0x00009bec, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
- { 0x00009bf0, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
- { 0x00009bf4, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
- { 0x00009bf8, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
- { 0x00009bfc, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
- { 0x0000aa00, 0x00000000, 0x00000000, 0x0006801c, 0x0006801c, 0x00000000 },
- { 0x0000aa04, 0x00000000, 0x00000000, 0x00068080, 0x00068080, 0x00000000 },
- { 0x0000aa08, 0x00000000, 0x00000000, 0x00068084, 0x00068084, 0x00000000 },
- { 0x0000aa0c, 0x00000000, 0x00000000, 0x00068088, 0x00068088, 0x00000000 },
- { 0x0000aa10, 0x00000000, 0x00000000, 0x0006808c, 0x0006808c, 0x00000000 },
- { 0x0000aa14, 0x00000000, 0x00000000, 0x00068100, 0x00068100, 0x00000000 },
- { 0x0000aa18, 0x00000000, 0x00000000, 0x00068104, 0x00068104, 0x00000000 },
- { 0x0000aa1c, 0x00000000, 0x00000000, 0x00068108, 0x00068108, 0x00000000 },
- { 0x0000aa20, 0x00000000, 0x00000000, 0x0006810c, 0x0006810c, 0x00000000 },
- { 0x0000aa24, 0x00000000, 0x00000000, 0x00068110, 0x00068110, 0x00000000 },
- { 0x0000aa28, 0x00000000, 0x00000000, 0x00068110, 0x00068110, 0x00000000 },
- { 0x0000aa2c, 0x00000000, 0x00000000, 0x00068180, 0x00068180, 0x00000000 },
- { 0x0000aa30, 0x00000000, 0x00000000, 0x00068184, 0x00068184, 0x00000000 },
- { 0x0000aa34, 0x00000000, 0x00000000, 0x00068188, 0x00068188, 0x00000000 },
- { 0x0000aa38, 0x00000000, 0x00000000, 0x0006818c, 0x0006818c, 0x00000000 },
- { 0x0000aa3c, 0x00000000, 0x00000000, 0x00068190, 0x00068190, 0x00000000 },
- { 0x0000aa40, 0x00000000, 0x00000000, 0x00068194, 0x00068194, 0x00000000 },
- { 0x0000aa44, 0x00000000, 0x00000000, 0x000681a0, 0x000681a0, 0x00000000 },
- { 0x0000aa48, 0x00000000, 0x00000000, 0x0006820c, 0x0006820c, 0x00000000 },
- { 0x0000aa4c, 0x00000000, 0x00000000, 0x000681a8, 0x000681a8, 0x00000000 },
- { 0x0000aa50, 0x00000000, 0x00000000, 0x000681ac, 0x000681ac, 0x00000000 },
- { 0x0000aa54, 0x00000000, 0x00000000, 0x0006821c, 0x0006821c, 0x00000000 },
- { 0x0000aa58, 0x00000000, 0x00000000, 0x00068224, 0x00068224, 0x00000000 },
- { 0x0000aa5c, 0x00000000, 0x00000000, 0x00068290, 0x00068290, 0x00000000 },
- { 0x0000aa60, 0x00000000, 0x00000000, 0x00068300, 0x00068300, 0x00000000 },
- { 0x0000aa64, 0x00000000, 0x00000000, 0x00068308, 0x00068308, 0x00000000 },
- { 0x0000aa68, 0x00000000, 0x00000000, 0x0006830c, 0x0006830c, 0x00000000 },
- { 0x0000aa6c, 0x00000000, 0x00000000, 0x00068310, 0x00068310, 0x00000000 },
- { 0x0000aa70, 0x00000000, 0x00000000, 0x00068788, 0x00068788, 0x00000000 },
- { 0x0000aa74, 0x00000000, 0x00000000, 0x0006878c, 0x0006878c, 0x00000000 },
- { 0x0000aa78, 0x00000000, 0x00000000, 0x00068790, 0x00068790, 0x00000000 },
- { 0x0000aa7c, 0x00000000, 0x00000000, 0x00068794, 0x00068794, 0x00000000 },
- { 0x0000aa80, 0x00000000, 0x00000000, 0x00068798, 0x00068798, 0x00000000 },
- { 0x0000aa84, 0x00000000, 0x00000000, 0x0006879c, 0x0006879c, 0x00000000 },
- { 0x0000aa88, 0x00000000, 0x00000000, 0x00068b89, 0x00068b89, 0x00000000 },
- { 0x0000aa8c, 0x00000000, 0x00000000, 0x00068b8d, 0x00068b8d, 0x00000000 },
- { 0x0000aa90, 0x00000000, 0x00000000, 0x00068b91, 0x00068b91, 0x00000000 },
- { 0x0000aa94, 0x00000000, 0x00000000, 0x00068b95, 0x00068b95, 0x00000000 },
- { 0x0000aa98, 0x00000000, 0x00000000, 0x00068b99, 0x00068b99, 0x00000000 },
- { 0x0000aa9c, 0x00000000, 0x00000000, 0x00068ba5, 0x00068ba5, 0x00000000 },
- { 0x0000aaa0, 0x00000000, 0x00000000, 0x00068ba9, 0x00068ba9, 0x00000000 },
- { 0x0000aaa4, 0x00000000, 0x00000000, 0x00068bad, 0x00068bad, 0x00000000 },
- { 0x0000aaa8, 0x00000000, 0x00000000, 0x000b8b0c, 0x000b8b0c, 0x00000000 },
- { 0x0000aaac, 0x00000000, 0x00000000, 0x000b8f10, 0x000b8f10, 0x00000000 },
- { 0x0000aab0, 0x00000000, 0x00000000, 0x000b8f14, 0x000b8f14, 0x00000000 },
- { 0x0000aab4, 0x00000000, 0x00000000, 0x000b8f84, 0x000b8f84, 0x00000000 },
- { 0x0000aab8, 0x00000000, 0x00000000, 0x000b8f84, 0x000b8f84, 0x00000000 },
- { 0x0000aabc, 0x00000000, 0x00000000, 0x000b8f88, 0x000b8f88, 0x00000000 },
- { 0x0000aac0, 0x00000000, 0x00000000, 0x000bb380, 0x000bb380, 0x00000000 },
- { 0x0000aac4, 0x00000000, 0x00000000, 0x000bb384, 0x000bb384, 0x00000000 },
- { 0x0000aac8, 0x00000000, 0x00000000, 0x000bb388, 0x000bb388, 0x00000000 },
- { 0x0000aacc, 0x00000000, 0x00000000, 0x000bb38c, 0x000bb38c, 0x00000000 },
- { 0x0000aad0, 0x00000000, 0x00000000, 0x000bb394, 0x000bb394, 0x00000000 },
- { 0x0000aad4, 0x00000000, 0x00000000, 0x000bb798, 0x000bb798, 0x00000000 },
- { 0x0000aad8, 0x00000000, 0x00000000, 0x000f970c, 0x000f970c, 0x00000000 },
- { 0x0000aadc, 0x00000000, 0x00000000, 0x000f9710, 0x000f9710, 0x00000000 },
- { 0x0000aae0, 0x00000000, 0x00000000, 0x000f9714, 0x000f9714, 0x00000000 },
- { 0x0000aae4, 0x00000000, 0x00000000, 0x000f9718, 0x000f9718, 0x00000000 },
- { 0x0000aae8, 0x00000000, 0x00000000, 0x000f9705, 0x000f9705, 0x00000000 },
- { 0x0000aaec, 0x00000000, 0x00000000, 0x000f9709, 0x000f9709, 0x00000000 },
- { 0x0000aaf0, 0x00000000, 0x00000000, 0x000f970d, 0x000f970d, 0x00000000 },
- { 0x0000aaf4, 0x00000000, 0x00000000, 0x000f9711, 0x000f9711, 0x00000000 },
- { 0x0000aaf8, 0x00000000, 0x00000000, 0x000f9715, 0x000f9715, 0x00000000 },
- { 0x0000aafc, 0x00000000, 0x00000000, 0x000f9719, 0x000f9719, 0x00000000 },
- { 0x0000ab00, 0x00000000, 0x00000000, 0x000fb7a4, 0x000fb7a4, 0x00000000 },
- { 0x0000ab04, 0x00000000, 0x00000000, 0x000fb7a8, 0x000fb7a8, 0x00000000 },
- { 0x0000ab08, 0x00000000, 0x00000000, 0x000fb7ac, 0x000fb7ac, 0x00000000 },
- { 0x0000ab0c, 0x00000000, 0x00000000, 0x000fb7ac, 0x000fb7ac, 0x00000000 },
- { 0x0000ab10, 0x00000000, 0x00000000, 0x000fb7b0, 0x000fb7b0, 0x00000000 },
- { 0x0000ab14, 0x00000000, 0x00000000, 0x000fb7b8, 0x000fb7b8, 0x00000000 },
- { 0x0000ab18, 0x00000000, 0x00000000, 0x000fb7bc, 0x000fb7bc, 0x00000000 },
- { 0x0000ab1c, 0x00000000, 0x00000000, 0x000fb7a1, 0x000fb7a1, 0x00000000 },
- { 0x0000ab20, 0x00000000, 0x00000000, 0x000fb7a5, 0x000fb7a5, 0x00000000 },
- { 0x0000ab24, 0x00000000, 0x00000000, 0x000fb7a9, 0x000fb7a9, 0x00000000 },
- { 0x0000ab28, 0x00000000, 0x00000000, 0x000fb7b1, 0x000fb7b1, 0x00000000 },
- { 0x0000ab2c, 0x00000000, 0x00000000, 0x000fb7b5, 0x000fb7b5, 0x00000000 },
- { 0x0000ab30, 0x00000000, 0x00000000, 0x000fb7bd, 0x000fb7bd, 0x00000000 },
- { 0x0000ab34, 0x00000000, 0x00000000, 0x000fb7c9, 0x000fb7c9, 0x00000000 },
- { 0x0000ab38, 0x00000000, 0x00000000, 0x000fb7cd, 0x000fb7cd, 0x00000000 },
- { 0x0000ab3c, 0x00000000, 0x00000000, 0x000fb7d1, 0x000fb7d1, 0x00000000 },
- { 0x0000ab40, 0x00000000, 0x00000000, 0x000fb7d9, 0x000fb7d9, 0x00000000 },
- { 0x0000ab44, 0x00000000, 0x00000000, 0x000fb7c2, 0x000fb7c2, 0x00000000 },
- { 0x0000ab48, 0x00000000, 0x00000000, 0x000fb7c6, 0x000fb7c6, 0x00000000 },
- { 0x0000ab4c, 0x00000000, 0x00000000, 0x000fb7ca, 0x000fb7ca, 0x00000000 },
- { 0x0000ab50, 0x00000000, 0x00000000, 0x000fb7ce, 0x000fb7ce, 0x00000000 },
- { 0x0000ab54, 0x00000000, 0x00000000, 0x000fb7d2, 0x000fb7d2, 0x00000000 },
- { 0x0000ab58, 0x00000000, 0x00000000, 0x000fb7d6, 0x000fb7d6, 0x00000000 },
- { 0x0000ab5c, 0x00000000, 0x00000000, 0x000fb7c3, 0x000fb7c3, 0x00000000 },
- { 0x0000ab60, 0x00000000, 0x00000000, 0x000fb7cb, 0x000fb7cb, 0x00000000 },
- { 0x0000ab64, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
- { 0x0000ab68, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
- { 0x0000ab6c, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
- { 0x0000ab70, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
- { 0x0000ab74, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
- { 0x0000ab78, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
- { 0x0000ab7c, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
- { 0x0000ab80, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
- { 0x0000ab84, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
- { 0x0000ab88, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
- { 0x0000ab8c, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
- { 0x0000ab90, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
- { 0x0000ab94, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
- { 0x0000ab98, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
- { 0x0000ab9c, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
- { 0x0000aba0, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
- { 0x0000aba4, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
- { 0x0000aba8, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
- { 0x0000abac, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
- { 0x0000abb0, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
- { 0x0000abb4, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
- { 0x0000abb8, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
- { 0x0000abbc, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
- { 0x0000abc0, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
- { 0x0000abc4, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
- { 0x0000abc8, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
- { 0x0000abcc, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
- { 0x0000abd0, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
- { 0x0000abd4, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
- { 0x0000abd8, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
- { 0x0000abdc, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
- { 0x0000abe0, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
- { 0x0000abe4, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
- { 0x0000abe8, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
- { 0x0000abec, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
- { 0x0000abf0, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
- { 0x0000abf4, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
- { 0x0000abf8, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
- { 0x0000abfc, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
- { 0x0000a204, 0x00000004, 0x00000004, 0x00000004, 0x00000004, 0x00000004 },
- { 0x0000a20c, 0x00000014, 0x00000014, 0x00000000, 0x00000000, 0x0001f000 },
- { 0x0000a21c, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a },
- { 0x0000a230, 0x00000000, 0x00000000, 0x00000210, 0x00000108, 0x00000000 },
- { 0x0000a250, 0x001ff000, 0x001ff000, 0x001ca000, 0x001ca000, 0x001da000 },
- { 0x0000a274, 0x0a81c652, 0x0a81c652, 0x0a820652, 0x0a820652, 0x0a82a652 },
- { 0x0000a300, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
- { 0x0000a304, 0x00000000, 0x00000000, 0x00007201, 0x00007201, 0x00000000 },
- { 0x0000a308, 0x00000000, 0x00000000, 0x00010408, 0x00010408, 0x00000000 },
- { 0x0000a30c, 0x00000000, 0x00000000, 0x0001860a, 0x0001860a, 0x00000000 },
- { 0x0000a310, 0x00000000, 0x00000000, 0x00020818, 0x00020818, 0x00000000 },
- { 0x0000a314, 0x00000000, 0x00000000, 0x00024858, 0x00024858, 0x00000000 },
- { 0x0000a318, 0x00000000, 0x00000000, 0x00026859, 0x00026859, 0x00000000 },
- { 0x0000a31c, 0x00000000, 0x00000000, 0x0002985b, 0x0002985b, 0x00000000 },
- { 0x0000a320, 0x00000000, 0x00000000, 0x0002c89a, 0x0002c89a, 0x00000000 },
- { 0x0000a324, 0x00000000, 0x00000000, 0x0002e89b, 0x0002e89b, 0x00000000 },
- { 0x0000a328, 0x00000000, 0x00000000, 0x0003089c, 0x0003089c, 0x00000000 },
- { 0x0000a32c, 0x00000000, 0x00000000, 0x0003289d, 0x0003289d, 0x00000000 },
- { 0x0000a330, 0x00000000, 0x00000000, 0x0003489e, 0x0003489e, 0x00000000 },
- { 0x0000a334, 0x00000000, 0x00000000, 0x000388de, 0x000388de, 0x00000000 },
- { 0x0000a338, 0x00000000, 0x00000000, 0x0003b91e, 0x0003b91e, 0x00000000 },
- { 0x0000a33c, 0x00000000, 0x00000000, 0x0003d95e, 0x0003d95e, 0x00000000 },
- { 0x0000a340, 0x00000000, 0x00000000, 0x000419df, 0x000419df, 0x00000000 },
- { 0x0000a344, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 },
- { 0x0000a358, 0x7999aa02, 0x7999aa02, 0x7999aa0e, 0x7999aa0e, 0x7999aa0e },
-};
-
-static const u32 ar9285Common_9285[][2] = {
- { 0x0000000c, 0x00000000 },
- { 0x00000030, 0x00020045 },
- { 0x00000034, 0x00000005 },
- { 0x00000040, 0x00000000 },
- { 0x00000044, 0x00000008 },
- { 0x00000048, 0x00000008 },
- { 0x0000004c, 0x00000010 },
- { 0x00000050, 0x00000000 },
- { 0x00000054, 0x0000001f },
- { 0x00000800, 0x00000000 },
- { 0x00000804, 0x00000000 },
- { 0x00000808, 0x00000000 },
- { 0x0000080c, 0x00000000 },
- { 0x00000810, 0x00000000 },
- { 0x00000814, 0x00000000 },
- { 0x00000818, 0x00000000 },
- { 0x0000081c, 0x00000000 },
- { 0x00000820, 0x00000000 },
- { 0x00000824, 0x00000000 },
- { 0x00001040, 0x002ffc0f },
- { 0x00001044, 0x002ffc0f },
- { 0x00001048, 0x002ffc0f },
- { 0x0000104c, 0x002ffc0f },
- { 0x00001050, 0x002ffc0f },
- { 0x00001054, 0x002ffc0f },
- { 0x00001058, 0x002ffc0f },
- { 0x0000105c, 0x002ffc0f },
- { 0x00001060, 0x002ffc0f },
- { 0x00001064, 0x002ffc0f },
- { 0x00001230, 0x00000000 },
- { 0x00001270, 0x00000000 },
- { 0x00001038, 0x00000000 },
- { 0x00001078, 0x00000000 },
- { 0x000010b8, 0x00000000 },
- { 0x000010f8, 0x00000000 },
- { 0x00001138, 0x00000000 },
- { 0x00001178, 0x00000000 },
- { 0x000011b8, 0x00000000 },
- { 0x000011f8, 0x00000000 },
- { 0x00001238, 0x00000000 },
- { 0x00001278, 0x00000000 },
- { 0x000012b8, 0x00000000 },
- { 0x000012f8, 0x00000000 },
- { 0x00001338, 0x00000000 },
- { 0x00001378, 0x00000000 },
- { 0x000013b8, 0x00000000 },
- { 0x000013f8, 0x00000000 },
- { 0x00001438, 0x00000000 },
- { 0x00001478, 0x00000000 },
- { 0x000014b8, 0x00000000 },
- { 0x000014f8, 0x00000000 },
- { 0x00001538, 0x00000000 },
- { 0x00001578, 0x00000000 },
- { 0x000015b8, 0x00000000 },
- { 0x000015f8, 0x00000000 },
- { 0x00001638, 0x00000000 },
- { 0x00001678, 0x00000000 },
- { 0x000016b8, 0x00000000 },
- { 0x000016f8, 0x00000000 },
- { 0x00001738, 0x00000000 },
- { 0x00001778, 0x00000000 },
- { 0x000017b8, 0x00000000 },
- { 0x000017f8, 0x00000000 },
- { 0x0000103c, 0x00000000 },
- { 0x0000107c, 0x00000000 },
- { 0x000010bc, 0x00000000 },
- { 0x000010fc, 0x00000000 },
- { 0x0000113c, 0x00000000 },
- { 0x0000117c, 0x00000000 },
- { 0x000011bc, 0x00000000 },
- { 0x000011fc, 0x00000000 },
- { 0x0000123c, 0x00000000 },
- { 0x0000127c, 0x00000000 },
- { 0x000012bc, 0x00000000 },
- { 0x000012fc, 0x00000000 },
- { 0x0000133c, 0x00000000 },
- { 0x0000137c, 0x00000000 },
- { 0x000013bc, 0x00000000 },
- { 0x000013fc, 0x00000000 },
- { 0x0000143c, 0x00000000 },
- { 0x0000147c, 0x00000000 },
- { 0x00004030, 0x00000002 },
- { 0x0000403c, 0x00000002 },
- { 0x00004024, 0x0000001f },
- { 0x00004060, 0x00000000 },
- { 0x00004064, 0x00000000 },
- { 0x00007010, 0x00000031 },
- { 0x00007034, 0x00000002 },
- { 0x00007038, 0x000004c2 },
- { 0x00008004, 0x00000000 },
- { 0x00008008, 0x00000000 },
- { 0x0000800c, 0x00000000 },
- { 0x00008018, 0x00000700 },
- { 0x00008020, 0x00000000 },
- { 0x00008038, 0x00000000 },
- { 0x0000803c, 0x00000000 },
- { 0x00008048, 0x00000000 },
- { 0x00008054, 0x00000000 },
- { 0x00008058, 0x00000000 },
- { 0x0000805c, 0x000fc78f },
- { 0x00008060, 0x0000000f },
- { 0x00008064, 0x00000000 },
- { 0x00008070, 0x00000000 },
- { 0x000080c0, 0x2a80001a },
- { 0x000080c4, 0x05dc01e0 },
- { 0x000080c8, 0x1f402710 },
- { 0x000080cc, 0x01f40000 },
- { 0x000080d0, 0x00001e00 },
- { 0x000080d4, 0x00000000 },
- { 0x000080d8, 0x00400000 },
- { 0x000080e0, 0xffffffff },
- { 0x000080e4, 0x0000ffff },
- { 0x000080e8, 0x003f3f3f },
- { 0x000080ec, 0x00000000 },
- { 0x000080f0, 0x00000000 },
- { 0x000080f4, 0x00000000 },
- { 0x000080f8, 0x00000000 },
- { 0x000080fc, 0x00020000 },
- { 0x00008100, 0x00020000 },
- { 0x00008104, 0x00000001 },
- { 0x00008108, 0x00000052 },
- { 0x0000810c, 0x00000000 },
- { 0x00008110, 0x00000168 },
- { 0x00008118, 0x000100aa },
- { 0x0000811c, 0x00003210 },
- { 0x00008120, 0x08f04800 },
- { 0x00008124, 0x00000000 },
- { 0x00008128, 0x00000000 },
- { 0x0000812c, 0x00000000 },
- { 0x00008130, 0x00000000 },
- { 0x00008134, 0x00000000 },
- { 0x00008138, 0x00000000 },
- { 0x0000813c, 0x00000000 },
- { 0x00008144, 0x00000000 },
- { 0x00008168, 0x00000000 },
- { 0x0000816c, 0x00000000 },
- { 0x00008170, 0x32143320 },
- { 0x00008174, 0xfaa4fa50 },
- { 0x00008178, 0x00000100 },
- { 0x0000817c, 0x00000000 },
- { 0x000081c0, 0x00000000 },
- { 0x000081d0, 0x00003210 },
- { 0x000081ec, 0x00000000 },
- { 0x000081f0, 0x00000000 },
- { 0x000081f4, 0x00000000 },
- { 0x000081f8, 0x00000000 },
- { 0x000081fc, 0x00000000 },
- { 0x00008200, 0x00000000 },
- { 0x00008204, 0x00000000 },
- { 0x00008208, 0x00000000 },
- { 0x0000820c, 0x00000000 },
- { 0x00008210, 0x00000000 },
- { 0x00008214, 0x00000000 },
- { 0x00008218, 0x00000000 },
- { 0x0000821c, 0x00000000 },
- { 0x00008220, 0x00000000 },
- { 0x00008224, 0x00000000 },
- { 0x00008228, 0x00000000 },
- { 0x0000822c, 0x00000000 },
- { 0x00008230, 0x00000000 },
- { 0x00008234, 0x00000000 },
- { 0x00008238, 0x00000000 },
- { 0x0000823c, 0x00000000 },
- { 0x00008240, 0x00100000 },
- { 0x00008244, 0x0010f400 },
- { 0x00008248, 0x00000100 },
- { 0x0000824c, 0x0001e800 },
- { 0x00008250, 0x00000000 },
- { 0x00008254, 0x00000000 },
- { 0x00008258, 0x00000000 },
- { 0x0000825c, 0x400000ff },
- { 0x00008260, 0x00080922 },
- { 0x00008264, 0x88a00010 },
- { 0x00008270, 0x00000000 },
- { 0x00008274, 0x40000000 },
- { 0x00008278, 0x003e4180 },
- { 0x0000827c, 0x00000000 },
- { 0x00008284, 0x0000002c },
- { 0x00008288, 0x0000002c },
- { 0x0000828c, 0x00000000 },
- { 0x00008294, 0x00000000 },
- { 0x00008298, 0x00000000 },
- { 0x0000829c, 0x00000000 },
- { 0x00008300, 0x00000040 },
- { 0x00008314, 0x00000000 },
- { 0x00008328, 0x00000000 },
- { 0x0000832c, 0x00000001 },
- { 0x00008330, 0x00000302 },
- { 0x00008334, 0x00000e00 },
- { 0x00008338, 0x00000000 },
- { 0x0000833c, 0x00000000 },
- { 0x00008340, 0x00010380 },
- { 0x00008344, 0x00481043 },
- { 0x00009808, 0x00000000 },
- { 0x0000980c, 0xafe68e30 },
- { 0x00009810, 0xfd14e000 },
- { 0x00009814, 0x9c0a9f6b },
- { 0x0000981c, 0x00000000 },
- { 0x0000982c, 0x0000a000 },
- { 0x00009830, 0x00000000 },
- { 0x0000983c, 0x00200400 },
- { 0x0000984c, 0x0040233c },
- { 0x00009854, 0x00000044 },
- { 0x00009900, 0x00000000 },
- { 0x00009904, 0x00000000 },
- { 0x00009908, 0x00000000 },
- { 0x0000990c, 0x00000000 },
- { 0x00009910, 0x01002310 },
- { 0x0000991c, 0x10000fff },
- { 0x00009920, 0x04900000 },
- { 0x00009928, 0x00000001 },
- { 0x0000992c, 0x00000004 },
- { 0x00009934, 0x1e1f2022 },
- { 0x00009938, 0x0a0b0c0d },
- { 0x0000993c, 0x00000000 },
- { 0x00009940, 0x14750604 },
- { 0x00009948, 0x9280c00a },
- { 0x0000994c, 0x00020028 },
- { 0x00009954, 0x5f3ca3de },
- { 0x00009958, 0x2108ecff },
- { 0x00009968, 0x000003ce },
- { 0x00009970, 0x1927b515 },
- { 0x00009974, 0x00000000 },
- { 0x00009978, 0x00000001 },
- { 0x0000997c, 0x00000000 },
- { 0x00009980, 0x00000000 },
- { 0x00009984, 0x00000000 },
- { 0x00009988, 0x00000000 },
- { 0x0000998c, 0x00000000 },
- { 0x00009990, 0x00000000 },
- { 0x00009994, 0x00000000 },
- { 0x00009998, 0x00000000 },
- { 0x0000999c, 0x00000000 },
- { 0x000099a0, 0x00000000 },
- { 0x000099a4, 0x00000001 },
- { 0x000099a8, 0x201fff00 },
- { 0x000099ac, 0x2def0a00 },
- { 0x000099b0, 0x03051000 },
- { 0x000099b4, 0x00000820 },
- { 0x000099dc, 0x00000000 },
- { 0x000099e0, 0x00000000 },
- { 0x000099e4, 0xaaaaaaaa },
- { 0x000099e8, 0x3c466478 },
- { 0x000099ec, 0x0cc80caa },
- { 0x000099f0, 0x00000000 },
- { 0x0000a208, 0x803e6788 },
- { 0x0000a210, 0x4080a333 },
- { 0x0000a214, 0x00206c10 },
- { 0x0000a218, 0x009c4060 },
- { 0x0000a220, 0x01834061 },
- { 0x0000a224, 0x00000400 },
- { 0x0000a228, 0x000003b5 },
- { 0x0000a22c, 0x00000000 },
- { 0x0000a234, 0x20202020 },
- { 0x0000a238, 0x20202020 },
- { 0x0000a244, 0x00000000 },
- { 0x0000a248, 0xfffffffc },
- { 0x0000a24c, 0x00000000 },
- { 0x0000a254, 0x00000000 },
- { 0x0000a258, 0x0ccb5380 },
- { 0x0000a25c, 0x15151501 },
- { 0x0000a260, 0xdfa90f01 },
- { 0x0000a268, 0x00000000 },
- { 0x0000a26c, 0x0ebae9e6 },
- { 0x0000d270, 0x0d820820 },
- { 0x0000a278, 0x39ce739c },
- { 0x0000a27c, 0x050e039c },
- { 0x0000d35c, 0x07ffffef },
- { 0x0000d360, 0x0fffffe7 },
- { 0x0000d364, 0x17ffffe5 },
- { 0x0000d368, 0x1fffffe4 },
- { 0x0000d36c, 0x37ffffe3 },
- { 0x0000d370, 0x3fffffe3 },
- { 0x0000d374, 0x57ffffe3 },
- { 0x0000d378, 0x5fffffe2 },
- { 0x0000d37c, 0x7fffffe2 },
- { 0x0000d380, 0x7f3c7bba },
- { 0x0000d384, 0xf3307ff0 },
- { 0x0000a388, 0x0c000000 },
- { 0x0000a38c, 0x20202020 },
- { 0x0000a390, 0x20202020 },
- { 0x0000a394, 0x39ce739c },
- { 0x0000a398, 0x0000039c },
- { 0x0000a39c, 0x00000001 },
- { 0x0000a3a0, 0x00000000 },
- { 0x0000a3a4, 0x00000000 },
- { 0x0000a3a8, 0x00000000 },
- { 0x0000a3ac, 0x00000000 },
- { 0x0000a3b0, 0x00000000 },
- { 0x0000a3b4, 0x00000000 },
- { 0x0000a3b8, 0x00000000 },
- { 0x0000a3bc, 0x00000000 },
- { 0x0000a3c0, 0x00000000 },
- { 0x0000a3c4, 0x00000000 },
- { 0x0000a3cc, 0x20202020 },
- { 0x0000a3d0, 0x20202020 },
- { 0x0000a3d4, 0x20202020 },
- { 0x0000a3dc, 0x39ce739c },
- { 0x0000a3e0, 0x0000039c },
- { 0x0000a3e4, 0x00000000 },
- { 0x0000a3e8, 0x18c43433 },
- { 0x0000a3ec, 0x00f70081 },
- { 0x00007800, 0x00140000 },
- { 0x00007804, 0x0e4548d8 },
- { 0x00007808, 0x54214514 },
- { 0x0000780c, 0x02025820 },
- { 0x00007810, 0x71c0d388 },
- { 0x00007814, 0x924934a8 },
- { 0x0000781c, 0x00000000 },
- { 0x00007820, 0x00000c04 },
- { 0x00007824, 0x00d86fff },
- { 0x00007828, 0x26d2491b },
- { 0x0000782c, 0x6e36d97b },
- { 0x00007830, 0xedb6d96c },
- { 0x00007834, 0x71400086 },
- { 0x00007838, 0xfac68800 },
- { 0x0000783c, 0x0001fffe },
- { 0x00007840, 0xffeb1a20 },
- { 0x00007844, 0x000c0db6 },
- { 0x00007848, 0x6db61b6f },
- { 0x0000784c, 0x6d9b66db },
- { 0x00007850, 0x6d8c6dba },
- { 0x00007854, 0x00040000 },
- { 0x00007858, 0xdb003012 },
- { 0x0000785c, 0x04924914 },
- { 0x00007860, 0x21084210 },
- { 0x00007864, 0xf7d7ffde },
- { 0x00007868, 0xc2034080 },
- { 0x0000786c, 0x48609eb4 },
- { 0x00007870, 0x10142c00 },
+ /* Addr allmodes */
+ {0x00004040, 0x9248fd00},
+ {0x00004040, 0x24924924},
+ {0x00004040, 0xa8000019},
+ {0x00004040, 0x13160820},
+ {0x00004040, 0xe5980560},
+ {0x00004040, 0xc01dcffd},
+ {0x00004040, 0x1aaabe41},
+ {0x00004040, 0xbe105554},
+ {0x00004040, 0x00043007},
+ {0x00004044, 0x00000000},
};
static const u32 ar9285PciePhy_clkreq_always_on_L1_9285[][2] = {
- {0x00004040, 0x9248fd00 },
- {0x00004040, 0x24924924 },
- {0x00004040, 0xa8000019 },
- {0x00004040, 0x13160820 },
- {0x00004040, 0xe5980560 },
- {0x00004040, 0xc01dcffd },
- {0x00004040, 0x1aaabe41 },
- {0x00004040, 0xbe105554 },
- {0x00004040, 0x00043007 },
- {0x00004044, 0x00000000 },
+ /* Addr allmodes */
+ {0x00004040, 0x9248fd00},
+ {0x00004040, 0x24924924},
+ {0x00004040, 0xa8000019},
+ {0x00004040, 0x13160820},
+ {0x00004040, 0xe5980560},
+ {0x00004040, 0xc01dcffd},
+ {0x00004040, 0x1aaabe41},
+ {0x00004040, 0xbe105554},
+ {0x00004040, 0x00043007},
+ {0x00004044, 0x00000000},
};
static const u32 ar9285PciePhy_clkreq_off_L1_9285[][2] = {
- {0x00004040, 0x9248fd00 },
- {0x00004040, 0x24924924 },
- {0x00004040, 0xa8000019 },
- {0x00004040, 0x13160820 },
- {0x00004040, 0xe5980560 },
- {0x00004040, 0xc01dcffc },
- {0x00004040, 0x1aaabe41 },
- {0x00004040, 0xbe105554 },
- {0x00004040, 0x00043007 },
- {0x00004044, 0x00000000 },
+ /* Addr allmodes */
+ {0x00004040, 0x9248fd00},
+ {0x00004040, 0x24924924},
+ {0x00004040, 0xa8000019},
+ {0x00004040, 0x13160820},
+ {0x00004040, 0xe5980560},
+ {0x00004040, 0xc01dcffc},
+ {0x00004040, 0x1aaabe41},
+ {0x00004040, 0xbe105554},
+ {0x00004040, 0x00043007},
+ {0x00004044, 0x00000000},
};
-/* AR9285 v1_2 PCI Register Writes. Created: 04/13/09 */
static const u32 ar9285Modes_9285_1_2[][6] = {
- /* Address 5G-HT20 5G-HT40 2G-HT40 2G-HT20 Turbo */
- { 0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160, 0x000001e0 },
- { 0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c, 0x000001e0 },
- { 0x000010b0, 0x00000e60, 0x00001cc0, 0x00007c70, 0x00003e38, 0x00001180 },
- { 0x000010f0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000008 },
- { 0x00008014, 0x03e803e8, 0x07d007d0, 0x10801600, 0x08400b00, 0x06e006e0 },
- { 0x0000801c, 0x128d8027, 0x128d804f, 0x12e00057, 0x12e0002b, 0x0988004f },
- { 0x00008318, 0x00003e80, 0x00007d00, 0x00006880, 0x00003440, 0x00006880 },
- { 0x00009804, 0x00000300, 0x000003c4, 0x000003c4, 0x00000300, 0x00000303 },
- { 0x00009820, 0x02020200, 0x02020200, 0x02020200, 0x02020200, 0x02020200 },
- { 0x00009824, 0x01000e0e, 0x01000e0e, 0x01000e0e, 0x01000e0e, 0x01000e0e },
- { 0x00009828, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001 },
- { 0x00009834, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e },
- { 0x00009838, 0x00000007, 0x00000007, 0x00000007, 0x00000007, 0x00000007 },
- { 0x00009840, 0x206a012e, 0x206a012e, 0x206a012e, 0x206a012e, 0x206a012e },
- { 0x00009844, 0x0372161e, 0x0372161e, 0x03721620, 0x03721620, 0x037216a0 },
- { 0x00009848, 0x00001066, 0x00001066, 0x00001053, 0x00001053, 0x00001059 },
- { 0x0000a848, 0x00001066, 0x00001066, 0x00001053, 0x00001053, 0x00001059 },
- { 0x00009850, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2 },
- { 0x00009858, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e },
- { 0x0000985c, 0x3139605e, 0x3139605e, 0x3137605e, 0x3137605e, 0x3139605e },
- { 0x00009860, 0x00058d18, 0x00058d18, 0x00058d20, 0x00058d20, 0x00058d18 },
- { 0x00009864, 0x0000fe00, 0x0000fe00, 0x0001ce00, 0x0001ce00, 0x0001ce00 },
- { 0x00009868, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0 },
- { 0x0000986c, 0x06903081, 0x06903081, 0x06903881, 0x06903881, 0x06903881 },
- { 0x00009914, 0x000007d0, 0x00000fa0, 0x00001130, 0x00000898, 0x000007d0 },
- { 0x00009918, 0x0000000a, 0x00000014, 0x00000016, 0x0000000b, 0x00000016 },
- { 0x00009924, 0xd00a8007, 0xd00a8007, 0xd00a800d, 0xd00a800d, 0xd00a800d },
- { 0x00009944, 0xffbc1010, 0xffbc1010, 0xffbc1020, 0xffbc1020, 0xffbc1010 },
- { 0x00009960, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
- { 0x00009964, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
- { 0x000099b8, 0x0000421c, 0x0000421c, 0x0000421c, 0x0000421c, 0x0000421c },
- { 0x000099bc, 0x00000600, 0x00000600, 0x00000c00, 0x00000c00, 0x00000c00 },
- { 0x000099c0, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4 },
- { 0x000099c4, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77 },
- { 0x000099c8, 0x6af6532f, 0x6af6532f, 0x6af6532f, 0x6af6532f, 0x6af6532f },
- { 0x000099cc, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8 },
- { 0x000099d0, 0x00046384, 0x00046384, 0x00046384, 0x00046384, 0x00046384 },
- { 0x000099d4, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
- { 0x000099d8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
- { 0x00009a00, 0x00000000, 0x00000000, 0x00058084, 0x00058084, 0x00000000 },
- { 0x00009a04, 0x00000000, 0x00000000, 0x00058088, 0x00058088, 0x00000000 },
- { 0x00009a08, 0x00000000, 0x00000000, 0x0005808c, 0x0005808c, 0x00000000 },
- { 0x00009a0c, 0x00000000, 0x00000000, 0x00058100, 0x00058100, 0x00000000 },
- { 0x00009a10, 0x00000000, 0x00000000, 0x00058104, 0x00058104, 0x00000000 },
- { 0x00009a14, 0x00000000, 0x00000000, 0x00058108, 0x00058108, 0x00000000 },
- { 0x00009a18, 0x00000000, 0x00000000, 0x0005810c, 0x0005810c, 0x00000000 },
- { 0x00009a1c, 0x00000000, 0x00000000, 0x00058110, 0x00058110, 0x00000000 },
- { 0x00009a20, 0x00000000, 0x00000000, 0x00058114, 0x00058114, 0x00000000 },
- { 0x00009a24, 0x00000000, 0x00000000, 0x00058180, 0x00058180, 0x00000000 },
- { 0x00009a28, 0x00000000, 0x00000000, 0x00058184, 0x00058184, 0x00000000 },
- { 0x00009a2c, 0x00000000, 0x00000000, 0x00058188, 0x00058188, 0x00000000 },
- { 0x00009a30, 0x00000000, 0x00000000, 0x0005818c, 0x0005818c, 0x00000000 },
- { 0x00009a34, 0x00000000, 0x00000000, 0x00058190, 0x00058190, 0x00000000 },
- { 0x00009a38, 0x00000000, 0x00000000, 0x00058194, 0x00058194, 0x00000000 },
- { 0x00009a3c, 0x00000000, 0x00000000, 0x000581a0, 0x000581a0, 0x00000000 },
- { 0x00009a40, 0x00000000, 0x00000000, 0x0005820c, 0x0005820c, 0x00000000 },
- { 0x00009a44, 0x00000000, 0x00000000, 0x000581a8, 0x000581a8, 0x00000000 },
- { 0x00009a48, 0x00000000, 0x00000000, 0x00058284, 0x00058284, 0x00000000 },
- { 0x00009a4c, 0x00000000, 0x00000000, 0x00058288, 0x00058288, 0x00000000 },
- { 0x00009a50, 0x00000000, 0x00000000, 0x00058224, 0x00058224, 0x00000000 },
- { 0x00009a54, 0x00000000, 0x00000000, 0x00058290, 0x00058290, 0x00000000 },
- { 0x00009a58, 0x00000000, 0x00000000, 0x00058300, 0x00058300, 0x00000000 },
- { 0x00009a5c, 0x00000000, 0x00000000, 0x00058304, 0x00058304, 0x00000000 },
- { 0x00009a60, 0x00000000, 0x00000000, 0x00058308, 0x00058308, 0x00000000 },
- { 0x00009a64, 0x00000000, 0x00000000, 0x0005830c, 0x0005830c, 0x00000000 },
- { 0x00009a68, 0x00000000, 0x00000000, 0x00058380, 0x00058380, 0x00000000 },
- { 0x00009a6c, 0x00000000, 0x00000000, 0x00058384, 0x00058384, 0x00000000 },
- { 0x00009a70, 0x00000000, 0x00000000, 0x00068700, 0x00068700, 0x00000000 },
- { 0x00009a74, 0x00000000, 0x00000000, 0x00068704, 0x00068704, 0x00000000 },
- { 0x00009a78, 0x00000000, 0x00000000, 0x00068708, 0x00068708, 0x00000000 },
- { 0x00009a7c, 0x00000000, 0x00000000, 0x0006870c, 0x0006870c, 0x00000000 },
- { 0x00009a80, 0x00000000, 0x00000000, 0x00068780, 0x00068780, 0x00000000 },
- { 0x00009a84, 0x00000000, 0x00000000, 0x00068784, 0x00068784, 0x00000000 },
- { 0x00009a88, 0x00000000, 0x00000000, 0x00078b00, 0x00078b00, 0x00000000 },
- { 0x00009a8c, 0x00000000, 0x00000000, 0x00078b04, 0x00078b04, 0x00000000 },
- { 0x00009a90, 0x00000000, 0x00000000, 0x00078b08, 0x00078b08, 0x00000000 },
- { 0x00009a94, 0x00000000, 0x00000000, 0x00078b0c, 0x00078b0c, 0x00000000 },
- { 0x00009a98, 0x00000000, 0x00000000, 0x00078b80, 0x00078b80, 0x00000000 },
- { 0x00009a9c, 0x00000000, 0x00000000, 0x00078b84, 0x00078b84, 0x00000000 },
- { 0x00009aa0, 0x00000000, 0x00000000, 0x00078b88, 0x00078b88, 0x00000000 },
- { 0x00009aa4, 0x00000000, 0x00000000, 0x00078b8c, 0x00078b8c, 0x00000000 },
- { 0x00009aa8, 0x00000000, 0x00000000, 0x00078b90, 0x00078b90, 0x00000000 },
- { 0x00009aac, 0x00000000, 0x00000000, 0x000caf80, 0x000caf80, 0x00000000 },
- { 0x00009ab0, 0x00000000, 0x00000000, 0x000caf84, 0x000caf84, 0x00000000 },
- { 0x00009ab4, 0x00000000, 0x00000000, 0x000caf88, 0x000caf88, 0x00000000 },
- { 0x00009ab8, 0x00000000, 0x00000000, 0x000caf8c, 0x000caf8c, 0x00000000 },
- { 0x00009abc, 0x00000000, 0x00000000, 0x000caf90, 0x000caf90, 0x00000000 },
- { 0x00009ac0, 0x00000000, 0x00000000, 0x000db30c, 0x000db30c, 0x00000000 },
- { 0x00009ac4, 0x00000000, 0x00000000, 0x000db310, 0x000db310, 0x00000000 },
- { 0x00009ac8, 0x00000000, 0x00000000, 0x000db384, 0x000db384, 0x00000000 },
- { 0x00009acc, 0x00000000, 0x00000000, 0x000db388, 0x000db388, 0x00000000 },
- { 0x00009ad0, 0x00000000, 0x00000000, 0x000db324, 0x000db324, 0x00000000 },
- { 0x00009ad4, 0x00000000, 0x00000000, 0x000eb704, 0x000eb704, 0x00000000 },
- { 0x00009ad8, 0x00000000, 0x00000000, 0x000eb6a4, 0x000eb6a4, 0x00000000 },
- { 0x00009adc, 0x00000000, 0x00000000, 0x000eb6a8, 0x000eb6a8, 0x00000000 },
- { 0x00009ae0, 0x00000000, 0x00000000, 0x000eb710, 0x000eb710, 0x00000000 },
- { 0x00009ae4, 0x00000000, 0x00000000, 0x000eb714, 0x000eb714, 0x00000000 },
- { 0x00009ae8, 0x00000000, 0x00000000, 0x000eb720, 0x000eb720, 0x00000000 },
- { 0x00009aec, 0x00000000, 0x00000000, 0x000eb724, 0x000eb724, 0x00000000 },
- { 0x00009af0, 0x00000000, 0x00000000, 0x000eb728, 0x000eb728, 0x00000000 },
- { 0x00009af4, 0x00000000, 0x00000000, 0x000eb72c, 0x000eb72c, 0x00000000 },
- { 0x00009af8, 0x00000000, 0x00000000, 0x000eb7a0, 0x000eb7a0, 0x00000000 },
- { 0x00009afc, 0x00000000, 0x00000000, 0x000eb7a4, 0x000eb7a4, 0x00000000 },
- { 0x00009b00, 0x00000000, 0x00000000, 0x000eb7a8, 0x000eb7a8, 0x00000000 },
- { 0x00009b04, 0x00000000, 0x00000000, 0x000eb7b0, 0x000eb7b0, 0x00000000 },
- { 0x00009b08, 0x00000000, 0x00000000, 0x000eb7b4, 0x000eb7b4, 0x00000000 },
- { 0x00009b0c, 0x00000000, 0x00000000, 0x000eb7b8, 0x000eb7b8, 0x00000000 },
- { 0x00009b10, 0x00000000, 0x00000000, 0x000eb7a5, 0x000eb7a5, 0x00000000 },
- { 0x00009b14, 0x00000000, 0x00000000, 0x000eb7a9, 0x000eb7a9, 0x00000000 },
- { 0x00009b18, 0x00000000, 0x00000000, 0x000eb7ad, 0x000eb7ad, 0x00000000 },
- { 0x00009b1c, 0x00000000, 0x00000000, 0x000eb7b1, 0x000eb7b1, 0x00000000 },
- { 0x00009b20, 0x00000000, 0x00000000, 0x000eb7b5, 0x000eb7b5, 0x00000000 },
- { 0x00009b24, 0x00000000, 0x00000000, 0x000eb7b9, 0x000eb7b9, 0x00000000 },
- { 0x00009b28, 0x00000000, 0x00000000, 0x000eb7c5, 0x000eb7c5, 0x00000000 },
- { 0x00009b2c, 0x00000000, 0x00000000, 0x000eb7c9, 0x000eb7c9, 0x00000000 },
- { 0x00009b30, 0x00000000, 0x00000000, 0x000eb7d1, 0x000eb7d1, 0x00000000 },
- { 0x00009b34, 0x00000000, 0x00000000, 0x000eb7d5, 0x000eb7d5, 0x00000000 },
- { 0x00009b38, 0x00000000, 0x00000000, 0x000eb7d9, 0x000eb7d9, 0x00000000 },
- { 0x00009b3c, 0x00000000, 0x00000000, 0x000eb7c6, 0x000eb7c6, 0x00000000 },
- { 0x00009b40, 0x00000000, 0x00000000, 0x000eb7ca, 0x000eb7ca, 0x00000000 },
- { 0x00009b44, 0x00000000, 0x00000000, 0x000eb7ce, 0x000eb7ce, 0x00000000 },
- { 0x00009b48, 0x00000000, 0x00000000, 0x000eb7d2, 0x000eb7d2, 0x00000000 },
- { 0x00009b4c, 0x00000000, 0x00000000, 0x000eb7d6, 0x000eb7d6, 0x00000000 },
- { 0x00009b50, 0x00000000, 0x00000000, 0x000eb7c3, 0x000eb7c3, 0x00000000 },
- { 0x00009b54, 0x00000000, 0x00000000, 0x000eb7c7, 0x000eb7c7, 0x00000000 },
- { 0x00009b58, 0x00000000, 0x00000000, 0x000eb7cb, 0x000eb7cb, 0x00000000 },
- { 0x00009b5c, 0x00000000, 0x00000000, 0x000eb7cf, 0x000eb7cf, 0x00000000 },
- { 0x00009b60, 0x00000000, 0x00000000, 0x000eb7d7, 0x000eb7d7, 0x00000000 },
- { 0x00009b64, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
- { 0x00009b68, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
- { 0x00009b6c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
- { 0x00009b70, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
- { 0x00009b74, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
- { 0x00009b78, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
- { 0x00009b7c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
- { 0x00009b80, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
- { 0x00009b84, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
- { 0x00009b88, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
- { 0x00009b8c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
- { 0x00009b90, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
- { 0x00009b94, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
- { 0x00009b98, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
- { 0x00009b9c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
- { 0x00009ba0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
- { 0x00009ba4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
- { 0x00009ba8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
- { 0x00009bac, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
- { 0x00009bb0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
- { 0x00009bb4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
- { 0x00009bb8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
- { 0x00009bbc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
- { 0x00009bc0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
- { 0x00009bc4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
- { 0x00009bc8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
- { 0x00009bcc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
- { 0x00009bd0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
- { 0x00009bd4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
- { 0x00009bd8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
- { 0x00009bdc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
- { 0x00009be0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
- { 0x00009be4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
- { 0x00009be8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
- { 0x00009bec, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
- { 0x00009bf0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
- { 0x00009bf4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
- { 0x00009bf8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
- { 0x00009bfc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
- { 0x0000aa00, 0x00000000, 0x00000000, 0x00058084, 0x00058084, 0x00000000 },
- { 0x0000aa04, 0x00000000, 0x00000000, 0x00058088, 0x00058088, 0x00000000 },
- { 0x0000aa08, 0x00000000, 0x00000000, 0x0005808c, 0x0005808c, 0x00000000 },
- { 0x0000aa0c, 0x00000000, 0x00000000, 0x00058100, 0x00058100, 0x00000000 },
- { 0x0000aa10, 0x00000000, 0x00000000, 0x00058104, 0x00058104, 0x00000000 },
- { 0x0000aa14, 0x00000000, 0x00000000, 0x00058108, 0x00058108, 0x00000000 },
- { 0x0000aa18, 0x00000000, 0x00000000, 0x0005810c, 0x0005810c, 0x00000000 },
- { 0x0000aa1c, 0x00000000, 0x00000000, 0x00058110, 0x00058110, 0x00000000 },
- { 0x0000aa20, 0x00000000, 0x00000000, 0x00058114, 0x00058114, 0x00000000 },
- { 0x0000aa24, 0x00000000, 0x00000000, 0x00058180, 0x00058180, 0x00000000 },
- { 0x0000aa28, 0x00000000, 0x00000000, 0x00058184, 0x00058184, 0x00000000 },
- { 0x0000aa2c, 0x00000000, 0x00000000, 0x00058188, 0x00058188, 0x00000000 },
- { 0x0000aa30, 0x00000000, 0x00000000, 0x0005818c, 0x0005818c, 0x00000000 },
- { 0x0000aa34, 0x00000000, 0x00000000, 0x00058190, 0x00058190, 0x00000000 },
- { 0x0000aa38, 0x00000000, 0x00000000, 0x00058194, 0x00058194, 0x00000000 },
- { 0x0000aa3c, 0x00000000, 0x00000000, 0x000581a0, 0x000581a0, 0x00000000 },
- { 0x0000aa40, 0x00000000, 0x00000000, 0x0005820c, 0x0005820c, 0x00000000 },
- { 0x0000aa44, 0x00000000, 0x00000000, 0x000581a8, 0x000581a8, 0x00000000 },
- { 0x0000aa48, 0x00000000, 0x00000000, 0x00058284, 0x00058284, 0x00000000 },
- { 0x0000aa4c, 0x00000000, 0x00000000, 0x00058288, 0x00058288, 0x00000000 },
- { 0x0000aa50, 0x00000000, 0x00000000, 0x00058224, 0x00058224, 0x00000000 },
- { 0x0000aa54, 0x00000000, 0x00000000, 0x00058290, 0x00058290, 0x00000000 },
- { 0x0000aa58, 0x00000000, 0x00000000, 0x00058300, 0x00058300, 0x00000000 },
- { 0x0000aa5c, 0x00000000, 0x00000000, 0x00058304, 0x00058304, 0x00000000 },
- { 0x0000aa60, 0x00000000, 0x00000000, 0x00058308, 0x00058308, 0x00000000 },
- { 0x0000aa64, 0x00000000, 0x00000000, 0x0005830c, 0x0005830c, 0x00000000 },
- { 0x0000aa68, 0x00000000, 0x00000000, 0x00058380, 0x00058380, 0x00000000 },
- { 0x0000aa6c, 0x00000000, 0x00000000, 0x00058384, 0x00058384, 0x00000000 },
- { 0x0000aa70, 0x00000000, 0x00000000, 0x00068700, 0x00068700, 0x00000000 },
- { 0x0000aa74, 0x00000000, 0x00000000, 0x00068704, 0x00068704, 0x00000000 },
- { 0x0000aa78, 0x00000000, 0x00000000, 0x00068708, 0x00068708, 0x00000000 },
- { 0x0000aa7c, 0x00000000, 0x00000000, 0x0006870c, 0x0006870c, 0x00000000 },
- { 0x0000aa80, 0x00000000, 0x00000000, 0x00068780, 0x00068780, 0x00000000 },
- { 0x0000aa84, 0x00000000, 0x00000000, 0x00068784, 0x00068784, 0x00000000 },
- { 0x0000aa88, 0x00000000, 0x00000000, 0x00078b00, 0x00078b00, 0x00000000 },
- { 0x0000aa8c, 0x00000000, 0x00000000, 0x00078b04, 0x00078b04, 0x00000000 },
- { 0x0000aa90, 0x00000000, 0x00000000, 0x00078b08, 0x00078b08, 0x00000000 },
- { 0x0000aa94, 0x00000000, 0x00000000, 0x00078b0c, 0x00078b0c, 0x00000000 },
- { 0x0000aa98, 0x00000000, 0x00000000, 0x00078b80, 0x00078b80, 0x00000000 },
- { 0x0000aa9c, 0x00000000, 0x00000000, 0x00078b84, 0x00078b84, 0x00000000 },
- { 0x0000aaa0, 0x00000000, 0x00000000, 0x00078b88, 0x00078b88, 0x00000000 },
- { 0x0000aaa4, 0x00000000, 0x00000000, 0x00078b8c, 0x00078b8c, 0x00000000 },
- { 0x0000aaa8, 0x00000000, 0x00000000, 0x00078b90, 0x00078b90, 0x00000000 },
- { 0x0000aaac, 0x00000000, 0x00000000, 0x000caf80, 0x000caf80, 0x00000000 },
- { 0x0000aab0, 0x00000000, 0x00000000, 0x000caf84, 0x000caf84, 0x00000000 },
- { 0x0000aab4, 0x00000000, 0x00000000, 0x000caf88, 0x000caf88, 0x00000000 },
- { 0x0000aab8, 0x00000000, 0x00000000, 0x000caf8c, 0x000caf8c, 0x00000000 },
- { 0x0000aabc, 0x00000000, 0x00000000, 0x000caf90, 0x000caf90, 0x00000000 },
- { 0x0000aac0, 0x00000000, 0x00000000, 0x000db30c, 0x000db30c, 0x00000000 },
- { 0x0000aac4, 0x00000000, 0x00000000, 0x000db310, 0x000db310, 0x00000000 },
- { 0x0000aac8, 0x00000000, 0x00000000, 0x000db384, 0x000db384, 0x00000000 },
- { 0x0000aacc, 0x00000000, 0x00000000, 0x000db388, 0x000db388, 0x00000000 },
- { 0x0000aad0, 0x00000000, 0x00000000, 0x000db324, 0x000db324, 0x00000000 },
- { 0x0000aad4, 0x00000000, 0x00000000, 0x000eb704, 0x000eb704, 0x00000000 },
- { 0x0000aad8, 0x00000000, 0x00000000, 0x000eb6a4, 0x000eb6a4, 0x00000000 },
- { 0x0000aadc, 0x00000000, 0x00000000, 0x000eb6a8, 0x000eb6a8, 0x00000000 },
- { 0x0000aae0, 0x00000000, 0x00000000, 0x000eb710, 0x000eb710, 0x00000000 },
- { 0x0000aae4, 0x00000000, 0x00000000, 0x000eb714, 0x000eb714, 0x00000000 },
- { 0x0000aae8, 0x00000000, 0x00000000, 0x000eb720, 0x000eb720, 0x00000000 },
- { 0x0000aaec, 0x00000000, 0x00000000, 0x000eb724, 0x000eb724, 0x00000000 },
- { 0x0000aaf0, 0x00000000, 0x00000000, 0x000eb728, 0x000eb728, 0x00000000 },
- { 0x0000aaf4, 0x00000000, 0x00000000, 0x000eb72c, 0x000eb72c, 0x00000000 },
- { 0x0000aaf8, 0x00000000, 0x00000000, 0x000eb7a0, 0x000eb7a0, 0x00000000 },
- { 0x0000aafc, 0x00000000, 0x00000000, 0x000eb7a4, 0x000eb7a4, 0x00000000 },
- { 0x0000ab00, 0x00000000, 0x00000000, 0x000eb7a8, 0x000eb7a8, 0x00000000 },
- { 0x0000ab04, 0x00000000, 0x00000000, 0x000eb7b0, 0x000eb7b0, 0x00000000 },
- { 0x0000ab08, 0x00000000, 0x00000000, 0x000eb7b4, 0x000eb7b4, 0x00000000 },
- { 0x0000ab0c, 0x00000000, 0x00000000, 0x000eb7b8, 0x000eb7b8, 0x00000000 },
- { 0x0000ab10, 0x00000000, 0x00000000, 0x000eb7a5, 0x000eb7a5, 0x00000000 },
- { 0x0000ab14, 0x00000000, 0x00000000, 0x000eb7a9, 0x000eb7a9, 0x00000000 },
- { 0x0000ab18, 0x00000000, 0x00000000, 0x000eb7ad, 0x000eb7ad, 0x00000000 },
- { 0x0000ab1c, 0x00000000, 0x00000000, 0x000eb7b1, 0x000eb7b1, 0x00000000 },
- { 0x0000ab20, 0x00000000, 0x00000000, 0x000eb7b5, 0x000eb7b5, 0x00000000 },
- { 0x0000ab24, 0x00000000, 0x00000000, 0x000eb7b9, 0x000eb7b9, 0x00000000 },
- { 0x0000ab28, 0x00000000, 0x00000000, 0x000eb7c5, 0x000eb7c5, 0x00000000 },
- { 0x0000ab2c, 0x00000000, 0x00000000, 0x000eb7c9, 0x000eb7c9, 0x00000000 },
- { 0x0000ab30, 0x00000000, 0x00000000, 0x000eb7d1, 0x000eb7d1, 0x00000000 },
- { 0x0000ab34, 0x00000000, 0x00000000, 0x000eb7d5, 0x000eb7d5, 0x00000000 },
- { 0x0000ab38, 0x00000000, 0x00000000, 0x000eb7d9, 0x000eb7d9, 0x00000000 },
- { 0x0000ab3c, 0x00000000, 0x00000000, 0x000eb7c6, 0x000eb7c6, 0x00000000 },
- { 0x0000ab40, 0x00000000, 0x00000000, 0x000eb7ca, 0x000eb7ca, 0x00000000 },
- { 0x0000ab44, 0x00000000, 0x00000000, 0x000eb7ce, 0x000eb7ce, 0x00000000 },
- { 0x0000ab48, 0x00000000, 0x00000000, 0x000eb7d2, 0x000eb7d2, 0x00000000 },
- { 0x0000ab4c, 0x00000000, 0x00000000, 0x000eb7d6, 0x000eb7d6, 0x00000000 },
- { 0x0000ab50, 0x00000000, 0x00000000, 0x000eb7c3, 0x000eb7c3, 0x00000000 },
- { 0x0000ab54, 0x00000000, 0x00000000, 0x000eb7c7, 0x000eb7c7, 0x00000000 },
- { 0x0000ab58, 0x00000000, 0x00000000, 0x000eb7cb, 0x000eb7cb, 0x00000000 },
- { 0x0000ab5c, 0x00000000, 0x00000000, 0x000eb7cf, 0x000eb7cf, 0x00000000 },
- { 0x0000ab60, 0x00000000, 0x00000000, 0x000eb7d7, 0x000eb7d7, 0x00000000 },
- { 0x0000ab64, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
- { 0x0000ab68, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
- { 0x0000ab6c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
- { 0x0000ab70, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
- { 0x0000ab74, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
- { 0x0000ab78, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
- { 0x0000ab7c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
- { 0x0000ab80, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
- { 0x0000ab84, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
- { 0x0000ab88, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
- { 0x0000ab8c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
- { 0x0000ab90, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
- { 0x0000ab94, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
- { 0x0000ab98, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
- { 0x0000ab9c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
- { 0x0000aba0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
- { 0x0000aba4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
- { 0x0000aba8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
- { 0x0000abac, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
- { 0x0000abb0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
- { 0x0000abb4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
- { 0x0000abb8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
- { 0x0000abbc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
- { 0x0000abc0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
- { 0x0000abc4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
- { 0x0000abc8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
- { 0x0000abcc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
- { 0x0000abd0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
- { 0x0000abd4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
- { 0x0000abd8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
- { 0x0000abdc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
- { 0x0000abe0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
- { 0x0000abe4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
- { 0x0000abe8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
- { 0x0000abec, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
- { 0x0000abf0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
- { 0x0000abf4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
- { 0x0000abf8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
- { 0x0000abfc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
- { 0x0000a204, 0x00000004, 0x00000004, 0x00000004, 0x00000004, 0x00000004 },
- { 0x0000a20c, 0x00000014, 0x00000014, 0x0001f000, 0x0001f000, 0x0001f000 },
- { 0x0000b20c, 0x00000014, 0x00000014, 0x0001f000, 0x0001f000, 0x0001f000 },
- { 0x0000a21c, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a },
- { 0x0000a230, 0x00000000, 0x00000000, 0x00000210, 0x00000108, 0x00000000 },
- { 0x0000a250, 0x0004f000, 0x0004f000, 0x0004a000, 0x0004a000, 0x0004a000 },
- { 0x0000a358, 0x7999aa02, 0x7999aa02, 0x7999aa0e, 0x7999aa0e, 0x7999aa0e },
+ {0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160, 0x000001e0},
+ {0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c, 0x000001e0},
+ {0x000010b0, 0x00000e60, 0x00001cc0, 0x00007c70, 0x00003e38, 0x00001180},
+ {0x000010f0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000008},
+ {0x00008014, 0x03e803e8, 0x07d007d0, 0x10801600, 0x08400b00, 0x06e006e0},
+ {0x0000801c, 0x128d8027, 0x128d804f, 0x12e00057, 0x12e0002b, 0x0988004f},
+ {0x00008318, 0x00003e80, 0x00007d00, 0x00006880, 0x00003440, 0x00006880},
+ {0x00009804, 0x00000300, 0x000003c4, 0x000003c4, 0x00000300, 0x00000303},
+ {0x00009820, 0x02020200, 0x02020200, 0x02020200, 0x02020200, 0x02020200},
+ {0x00009824, 0x01000e0e, 0x01000e0e, 0x01000e0e, 0x01000e0e, 0x01000e0e},
+ {0x00009828, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001},
+ {0x00009834, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e},
+ {0x00009838, 0x00000007, 0x00000007, 0x00000007, 0x00000007, 0x00000007},
+ {0x00009840, 0x206a012e, 0x206a012e, 0x206a012e, 0x206a012e, 0x206a012e},
+ {0x00009844, 0x0372161e, 0x0372161e, 0x03721620, 0x03721620, 0x037216a0},
+ {0x00009848, 0x00001066, 0x00001066, 0x00001053, 0x00001053, 0x00001059},
+ {0x0000a848, 0x00001066, 0x00001066, 0x00001053, 0x00001053, 0x00001059},
+ {0x00009850, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2},
+ {0x00009858, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e},
+ {0x0000985c, 0x3139605e, 0x3139605e, 0x3137605e, 0x3137605e, 0x3139605e},
+ {0x00009860, 0x00058d18, 0x00058d18, 0x00058d20, 0x00058d20, 0x00058d18},
+ {0x00009864, 0x0000fe00, 0x0000fe00, 0x0001ce00, 0x0001ce00, 0x0001ce00},
+ {0x00009868, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0},
+ {0x0000986c, 0x06903081, 0x06903081, 0x06903881, 0x06903881, 0x06903881},
+ {0x00009914, 0x000007d0, 0x00000fa0, 0x00001130, 0x00000898, 0x000007d0},
+ {0x00009918, 0x0000000a, 0x00000014, 0x00000016, 0x0000000b, 0x00000016},
+ {0x00009924, 0xd00a8007, 0xd00a8007, 0xd00a800d, 0xd00a800d, 0xd00a800d},
+ {0x00009944, 0xffbc1010, 0xffbc1010, 0xffbc1020, 0xffbc1020, 0xffbc1010},
+ {0x00009960, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+ {0x00009964, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+ {0x000099b8, 0x0000421c, 0x0000421c, 0x0000421c, 0x0000421c, 0x0000421c},
+ {0x000099bc, 0x00000600, 0x00000600, 0x00000c00, 0x00000c00, 0x00000c00},
+ {0x000099c0, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4},
+ {0x000099c4, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77},
+ {0x000099c8, 0x6af6532f, 0x6af6532f, 0x6af6532f, 0x6af6532f, 0x6af6532f},
+ {0x000099cc, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8},
+ {0x000099d0, 0x00046384, 0x00046384, 0x00046384, 0x00046384, 0x00046384},
+ {0x000099d4, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+ {0x000099d8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+ {0x00009a00, 0x00000000, 0x00000000, 0x00058084, 0x00058084, 0x00000000},
+ {0x00009a04, 0x00000000, 0x00000000, 0x00058088, 0x00058088, 0x00000000},
+ {0x00009a08, 0x00000000, 0x00000000, 0x0005808c, 0x0005808c, 0x00000000},
+ {0x00009a0c, 0x00000000, 0x00000000, 0x00058100, 0x00058100, 0x00000000},
+ {0x00009a10, 0x00000000, 0x00000000, 0x00058104, 0x00058104, 0x00000000},
+ {0x00009a14, 0x00000000, 0x00000000, 0x00058108, 0x00058108, 0x00000000},
+ {0x00009a18, 0x00000000, 0x00000000, 0x0005810c, 0x0005810c, 0x00000000},
+ {0x00009a1c, 0x00000000, 0x00000000, 0x00058110, 0x00058110, 0x00000000},
+ {0x00009a20, 0x00000000, 0x00000000, 0x00058114, 0x00058114, 0x00000000},
+ {0x00009a24, 0x00000000, 0x00000000, 0x00058180, 0x00058180, 0x00000000},
+ {0x00009a28, 0x00000000, 0x00000000, 0x00058184, 0x00058184, 0x00000000},
+ {0x00009a2c, 0x00000000, 0x00000000, 0x00058188, 0x00058188, 0x00000000},
+ {0x00009a30, 0x00000000, 0x00000000, 0x0005818c, 0x0005818c, 0x00000000},
+ {0x00009a34, 0x00000000, 0x00000000, 0x00058190, 0x00058190, 0x00000000},
+ {0x00009a38, 0x00000000, 0x00000000, 0x00058194, 0x00058194, 0x00000000},
+ {0x00009a3c, 0x00000000, 0x00000000, 0x000581a0, 0x000581a0, 0x00000000},
+ {0x00009a40, 0x00000000, 0x00000000, 0x0005820c, 0x0005820c, 0x00000000},
+ {0x00009a44, 0x00000000, 0x00000000, 0x000581a8, 0x000581a8, 0x00000000},
+ {0x00009a48, 0x00000000, 0x00000000, 0x00058284, 0x00058284, 0x00000000},
+ {0x00009a4c, 0x00000000, 0x00000000, 0x00058288, 0x00058288, 0x00000000},
+ {0x00009a50, 0x00000000, 0x00000000, 0x00058224, 0x00058224, 0x00000000},
+ {0x00009a54, 0x00000000, 0x00000000, 0x00058290, 0x00058290, 0x00000000},
+ {0x00009a58, 0x00000000, 0x00000000, 0x00058300, 0x00058300, 0x00000000},
+ {0x00009a5c, 0x00000000, 0x00000000, 0x00058304, 0x00058304, 0x00000000},
+ {0x00009a60, 0x00000000, 0x00000000, 0x00058308, 0x00058308, 0x00000000},
+ {0x00009a64, 0x00000000, 0x00000000, 0x0005830c, 0x0005830c, 0x00000000},
+ {0x00009a68, 0x00000000, 0x00000000, 0x00058380, 0x00058380, 0x00000000},
+ {0x00009a6c, 0x00000000, 0x00000000, 0x00058384, 0x00058384, 0x00000000},
+ {0x00009a70, 0x00000000, 0x00000000, 0x00068700, 0x00068700, 0x00000000},
+ {0x00009a74, 0x00000000, 0x00000000, 0x00068704, 0x00068704, 0x00000000},
+ {0x00009a78, 0x00000000, 0x00000000, 0x00068708, 0x00068708, 0x00000000},
+ {0x00009a7c, 0x00000000, 0x00000000, 0x0006870c, 0x0006870c, 0x00000000},
+ {0x00009a80, 0x00000000, 0x00000000, 0x00068780, 0x00068780, 0x00000000},
+ {0x00009a84, 0x00000000, 0x00000000, 0x00068784, 0x00068784, 0x00000000},
+ {0x00009a88, 0x00000000, 0x00000000, 0x00078b00, 0x00078b00, 0x00000000},
+ {0x00009a8c, 0x00000000, 0x00000000, 0x00078b04, 0x00078b04, 0x00000000},
+ {0x00009a90, 0x00000000, 0x00000000, 0x00078b08, 0x00078b08, 0x00000000},
+ {0x00009a94, 0x00000000, 0x00000000, 0x00078b0c, 0x00078b0c, 0x00000000},
+ {0x00009a98, 0x00000000, 0x00000000, 0x00078b80, 0x00078b80, 0x00000000},
+ {0x00009a9c, 0x00000000, 0x00000000, 0x00078b84, 0x00078b84, 0x00000000},
+ {0x00009aa0, 0x00000000, 0x00000000, 0x00078b88, 0x00078b88, 0x00000000},
+ {0x00009aa4, 0x00000000, 0x00000000, 0x00078b8c, 0x00078b8c, 0x00000000},
+ {0x00009aa8, 0x00000000, 0x00000000, 0x00078b90, 0x00078b90, 0x00000000},
+ {0x00009aac, 0x00000000, 0x00000000, 0x000caf80, 0x000caf80, 0x00000000},
+ {0x00009ab0, 0x00000000, 0x00000000, 0x000caf84, 0x000caf84, 0x00000000},
+ {0x00009ab4, 0x00000000, 0x00000000, 0x000caf88, 0x000caf88, 0x00000000},
+ {0x00009ab8, 0x00000000, 0x00000000, 0x000caf8c, 0x000caf8c, 0x00000000},
+ {0x00009abc, 0x00000000, 0x00000000, 0x000caf90, 0x000caf90, 0x00000000},
+ {0x00009ac0, 0x00000000, 0x00000000, 0x000db30c, 0x000db30c, 0x00000000},
+ {0x00009ac4, 0x00000000, 0x00000000, 0x000db310, 0x000db310, 0x00000000},
+ {0x00009ac8, 0x00000000, 0x00000000, 0x000db384, 0x000db384, 0x00000000},
+ {0x00009acc, 0x00000000, 0x00000000, 0x000db388, 0x000db388, 0x00000000},
+ {0x00009ad0, 0x00000000, 0x00000000, 0x000db324, 0x000db324, 0x00000000},
+ {0x00009ad4, 0x00000000, 0x00000000, 0x000eb704, 0x000eb704, 0x00000000},
+ {0x00009ad8, 0x00000000, 0x00000000, 0x000eb6a4, 0x000eb6a4, 0x00000000},
+ {0x00009adc, 0x00000000, 0x00000000, 0x000eb6a8, 0x000eb6a8, 0x00000000},
+ {0x00009ae0, 0x00000000, 0x00000000, 0x000eb710, 0x000eb710, 0x00000000},
+ {0x00009ae4, 0x00000000, 0x00000000, 0x000eb714, 0x000eb714, 0x00000000},
+ {0x00009ae8, 0x00000000, 0x00000000, 0x000eb720, 0x000eb720, 0x00000000},
+ {0x00009aec, 0x00000000, 0x00000000, 0x000eb724, 0x000eb724, 0x00000000},
+ {0x00009af0, 0x00000000, 0x00000000, 0x000eb728, 0x000eb728, 0x00000000},
+ {0x00009af4, 0x00000000, 0x00000000, 0x000eb72c, 0x000eb72c, 0x00000000},
+ {0x00009af8, 0x00000000, 0x00000000, 0x000eb7a0, 0x000eb7a0, 0x00000000},
+ {0x00009afc, 0x00000000, 0x00000000, 0x000eb7a4, 0x000eb7a4, 0x00000000},
+ {0x00009b00, 0x00000000, 0x00000000, 0x000eb7a8, 0x000eb7a8, 0x00000000},
+ {0x00009b04, 0x00000000, 0x00000000, 0x000eb7b0, 0x000eb7b0, 0x00000000},
+ {0x00009b08, 0x00000000, 0x00000000, 0x000eb7b4, 0x000eb7b4, 0x00000000},
+ {0x00009b0c, 0x00000000, 0x00000000, 0x000eb7b8, 0x000eb7b8, 0x00000000},
+ {0x00009b10, 0x00000000, 0x00000000, 0x000eb7a5, 0x000eb7a5, 0x00000000},
+ {0x00009b14, 0x00000000, 0x00000000, 0x000eb7a9, 0x000eb7a9, 0x00000000},
+ {0x00009b18, 0x00000000, 0x00000000, 0x000eb7ad, 0x000eb7ad, 0x00000000},
+ {0x00009b1c, 0x00000000, 0x00000000, 0x000eb7b1, 0x000eb7b1, 0x00000000},
+ {0x00009b20, 0x00000000, 0x00000000, 0x000eb7b5, 0x000eb7b5, 0x00000000},
+ {0x00009b24, 0x00000000, 0x00000000, 0x000eb7b9, 0x000eb7b9, 0x00000000},
+ {0x00009b28, 0x00000000, 0x00000000, 0x000eb7c5, 0x000eb7c5, 0x00000000},
+ {0x00009b2c, 0x00000000, 0x00000000, 0x000eb7c9, 0x000eb7c9, 0x00000000},
+ {0x00009b30, 0x00000000, 0x00000000, 0x000eb7d1, 0x000eb7d1, 0x00000000},
+ {0x00009b34, 0x00000000, 0x00000000, 0x000eb7d5, 0x000eb7d5, 0x00000000},
+ {0x00009b38, 0x00000000, 0x00000000, 0x000eb7d9, 0x000eb7d9, 0x00000000},
+ {0x00009b3c, 0x00000000, 0x00000000, 0x000eb7c6, 0x000eb7c6, 0x00000000},
+ {0x00009b40, 0x00000000, 0x00000000, 0x000eb7ca, 0x000eb7ca, 0x00000000},
+ {0x00009b44, 0x00000000, 0x00000000, 0x000eb7ce, 0x000eb7ce, 0x00000000},
+ {0x00009b48, 0x00000000, 0x00000000, 0x000eb7d2, 0x000eb7d2, 0x00000000},
+ {0x00009b4c, 0x00000000, 0x00000000, 0x000eb7d6, 0x000eb7d6, 0x00000000},
+ {0x00009b50, 0x00000000, 0x00000000, 0x000eb7c3, 0x000eb7c3, 0x00000000},
+ {0x00009b54, 0x00000000, 0x00000000, 0x000eb7c7, 0x000eb7c7, 0x00000000},
+ {0x00009b58, 0x00000000, 0x00000000, 0x000eb7cb, 0x000eb7cb, 0x00000000},
+ {0x00009b5c, 0x00000000, 0x00000000, 0x000eb7cf, 0x000eb7cf, 0x00000000},
+ {0x00009b60, 0x00000000, 0x00000000, 0x000eb7d7, 0x000eb7d7, 0x00000000},
+ {0x00009b64, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+ {0x00009b68, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+ {0x00009b6c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+ {0x00009b70, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+ {0x00009b74, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+ {0x00009b78, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+ {0x00009b7c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+ {0x00009b80, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+ {0x00009b84, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+ {0x00009b88, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+ {0x00009b8c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+ {0x00009b90, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+ {0x00009b94, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+ {0x00009b98, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+ {0x00009b9c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+ {0x00009ba0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+ {0x00009ba4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+ {0x00009ba8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+ {0x00009bac, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+ {0x00009bb0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+ {0x00009bb4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+ {0x00009bb8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+ {0x00009bbc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+ {0x00009bc0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+ {0x00009bc4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+ {0x00009bc8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+ {0x00009bcc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+ {0x00009bd0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+ {0x00009bd4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+ {0x00009bd8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+ {0x00009bdc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+ {0x00009be0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+ {0x00009be4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+ {0x00009be8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+ {0x00009bec, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+ {0x00009bf0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+ {0x00009bf4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+ {0x00009bf8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+ {0x00009bfc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+ {0x0000aa00, 0x00000000, 0x00000000, 0x00058084, 0x00058084, 0x00000000},
+ {0x0000aa04, 0x00000000, 0x00000000, 0x00058088, 0x00058088, 0x00000000},
+ {0x0000aa08, 0x00000000, 0x00000000, 0x0005808c, 0x0005808c, 0x00000000},
+ {0x0000aa0c, 0x00000000, 0x00000000, 0x00058100, 0x00058100, 0x00000000},
+ {0x0000aa10, 0x00000000, 0x00000000, 0x00058104, 0x00058104, 0x00000000},
+ {0x0000aa14, 0x00000000, 0x00000000, 0x00058108, 0x00058108, 0x00000000},
+ {0x0000aa18, 0x00000000, 0x00000000, 0x0005810c, 0x0005810c, 0x00000000},
+ {0x0000aa1c, 0x00000000, 0x00000000, 0x00058110, 0x00058110, 0x00000000},
+ {0x0000aa20, 0x00000000, 0x00000000, 0x00058114, 0x00058114, 0x00000000},
+ {0x0000aa24, 0x00000000, 0x00000000, 0x00058180, 0x00058180, 0x00000000},
+ {0x0000aa28, 0x00000000, 0x00000000, 0x00058184, 0x00058184, 0x00000000},
+ {0x0000aa2c, 0x00000000, 0x00000000, 0x00058188, 0x00058188, 0x00000000},
+ {0x0000aa30, 0x00000000, 0x00000000, 0x0005818c, 0x0005818c, 0x00000000},
+ {0x0000aa34, 0x00000000, 0x00000000, 0x00058190, 0x00058190, 0x00000000},
+ {0x0000aa38, 0x00000000, 0x00000000, 0x00058194, 0x00058194, 0x00000000},
+ {0x0000aa3c, 0x00000000, 0x00000000, 0x000581a0, 0x000581a0, 0x00000000},
+ {0x0000aa40, 0x00000000, 0x00000000, 0x0005820c, 0x0005820c, 0x00000000},
+ {0x0000aa44, 0x00000000, 0x00000000, 0x000581a8, 0x000581a8, 0x00000000},
+ {0x0000aa48, 0x00000000, 0x00000000, 0x00058284, 0x00058284, 0x00000000},
+ {0x0000aa4c, 0x00000000, 0x00000000, 0x00058288, 0x00058288, 0x00000000},
+ {0x0000aa50, 0x00000000, 0x00000000, 0x00058224, 0x00058224, 0x00000000},
+ {0x0000aa54, 0x00000000, 0x00000000, 0x00058290, 0x00058290, 0x00000000},
+ {0x0000aa58, 0x00000000, 0x00000000, 0x00058300, 0x00058300, 0x00000000},
+ {0x0000aa5c, 0x00000000, 0x00000000, 0x00058304, 0x00058304, 0x00000000},
+ {0x0000aa60, 0x00000000, 0x00000000, 0x00058308, 0x00058308, 0x00000000},
+ {0x0000aa64, 0x00000000, 0x00000000, 0x0005830c, 0x0005830c, 0x00000000},
+ {0x0000aa68, 0x00000000, 0x00000000, 0x00058380, 0x00058380, 0x00000000},
+ {0x0000aa6c, 0x00000000, 0x00000000, 0x00058384, 0x00058384, 0x00000000},
+ {0x0000aa70, 0x00000000, 0x00000000, 0x00068700, 0x00068700, 0x00000000},
+ {0x0000aa74, 0x00000000, 0x00000000, 0x00068704, 0x00068704, 0x00000000},
+ {0x0000aa78, 0x00000000, 0x00000000, 0x00068708, 0x00068708, 0x00000000},
+ {0x0000aa7c, 0x00000000, 0x00000000, 0x0006870c, 0x0006870c, 0x00000000},
+ {0x0000aa80, 0x00000000, 0x00000000, 0x00068780, 0x00068780, 0x00000000},
+ {0x0000aa84, 0x00000000, 0x00000000, 0x00068784, 0x00068784, 0x00000000},
+ {0x0000aa88, 0x00000000, 0x00000000, 0x00078b00, 0x00078b00, 0x00000000},
+ {0x0000aa8c, 0x00000000, 0x00000000, 0x00078b04, 0x00078b04, 0x00000000},
+ {0x0000aa90, 0x00000000, 0x00000000, 0x00078b08, 0x00078b08, 0x00000000},
+ {0x0000aa94, 0x00000000, 0x00000000, 0x00078b0c, 0x00078b0c, 0x00000000},
+ {0x0000aa98, 0x00000000, 0x00000000, 0x00078b80, 0x00078b80, 0x00000000},
+ {0x0000aa9c, 0x00000000, 0x00000000, 0x00078b84, 0x00078b84, 0x00000000},
+ {0x0000aaa0, 0x00000000, 0x00000000, 0x00078b88, 0x00078b88, 0x00000000},
+ {0x0000aaa4, 0x00000000, 0x00000000, 0x00078b8c, 0x00078b8c, 0x00000000},
+ {0x0000aaa8, 0x00000000, 0x00000000, 0x00078b90, 0x00078b90, 0x00000000},
+ {0x0000aaac, 0x00000000, 0x00000000, 0x000caf80, 0x000caf80, 0x00000000},
+ {0x0000aab0, 0x00000000, 0x00000000, 0x000caf84, 0x000caf84, 0x00000000},
+ {0x0000aab4, 0x00000000, 0x00000000, 0x000caf88, 0x000caf88, 0x00000000},
+ {0x0000aab8, 0x00000000, 0x00000000, 0x000caf8c, 0x000caf8c, 0x00000000},
+ {0x0000aabc, 0x00000000, 0x00000000, 0x000caf90, 0x000caf90, 0x00000000},
+ {0x0000aac0, 0x00000000, 0x00000000, 0x000db30c, 0x000db30c, 0x00000000},
+ {0x0000aac4, 0x00000000, 0x00000000, 0x000db310, 0x000db310, 0x00000000},
+ {0x0000aac8, 0x00000000, 0x00000000, 0x000db384, 0x000db384, 0x00000000},
+ {0x0000aacc, 0x00000000, 0x00000000, 0x000db388, 0x000db388, 0x00000000},
+ {0x0000aad0, 0x00000000, 0x00000000, 0x000db324, 0x000db324, 0x00000000},
+ {0x0000aad4, 0x00000000, 0x00000000, 0x000eb704, 0x000eb704, 0x00000000},
+ {0x0000aad8, 0x00000000, 0x00000000, 0x000eb6a4, 0x000eb6a4, 0x00000000},
+ {0x0000aadc, 0x00000000, 0x00000000, 0x000eb6a8, 0x000eb6a8, 0x00000000},
+ {0x0000aae0, 0x00000000, 0x00000000, 0x000eb710, 0x000eb710, 0x00000000},
+ {0x0000aae4, 0x00000000, 0x00000000, 0x000eb714, 0x000eb714, 0x00000000},
+ {0x0000aae8, 0x00000000, 0x00000000, 0x000eb720, 0x000eb720, 0x00000000},
+ {0x0000aaec, 0x00000000, 0x00000000, 0x000eb724, 0x000eb724, 0x00000000},
+ {0x0000aaf0, 0x00000000, 0x00000000, 0x000eb728, 0x000eb728, 0x00000000},
+ {0x0000aaf4, 0x00000000, 0x00000000, 0x000eb72c, 0x000eb72c, 0x00000000},
+ {0x0000aaf8, 0x00000000, 0x00000000, 0x000eb7a0, 0x000eb7a0, 0x00000000},
+ {0x0000aafc, 0x00000000, 0x00000000, 0x000eb7a4, 0x000eb7a4, 0x00000000},
+ {0x0000ab00, 0x00000000, 0x00000000, 0x000eb7a8, 0x000eb7a8, 0x00000000},
+ {0x0000ab04, 0x00000000, 0x00000000, 0x000eb7b0, 0x000eb7b0, 0x00000000},
+ {0x0000ab08, 0x00000000, 0x00000000, 0x000eb7b4, 0x000eb7b4, 0x00000000},
+ {0x0000ab0c, 0x00000000, 0x00000000, 0x000eb7b8, 0x000eb7b8, 0x00000000},
+ {0x0000ab10, 0x00000000, 0x00000000, 0x000eb7a5, 0x000eb7a5, 0x00000000},
+ {0x0000ab14, 0x00000000, 0x00000000, 0x000eb7a9, 0x000eb7a9, 0x00000000},
+ {0x0000ab18, 0x00000000, 0x00000000, 0x000eb7ad, 0x000eb7ad, 0x00000000},
+ {0x0000ab1c, 0x00000000, 0x00000000, 0x000eb7b1, 0x000eb7b1, 0x00000000},
+ {0x0000ab20, 0x00000000, 0x00000000, 0x000eb7b5, 0x000eb7b5, 0x00000000},
+ {0x0000ab24, 0x00000000, 0x00000000, 0x000eb7b9, 0x000eb7b9, 0x00000000},
+ {0x0000ab28, 0x00000000, 0x00000000, 0x000eb7c5, 0x000eb7c5, 0x00000000},
+ {0x0000ab2c, 0x00000000, 0x00000000, 0x000eb7c9, 0x000eb7c9, 0x00000000},
+ {0x0000ab30, 0x00000000, 0x00000000, 0x000eb7d1, 0x000eb7d1, 0x00000000},
+ {0x0000ab34, 0x00000000, 0x00000000, 0x000eb7d5, 0x000eb7d5, 0x00000000},
+ {0x0000ab38, 0x00000000, 0x00000000, 0x000eb7d9, 0x000eb7d9, 0x00000000},
+ {0x0000ab3c, 0x00000000, 0x00000000, 0x000eb7c6, 0x000eb7c6, 0x00000000},
+ {0x0000ab40, 0x00000000, 0x00000000, 0x000eb7ca, 0x000eb7ca, 0x00000000},
+ {0x0000ab44, 0x00000000, 0x00000000, 0x000eb7ce, 0x000eb7ce, 0x00000000},
+ {0x0000ab48, 0x00000000, 0x00000000, 0x000eb7d2, 0x000eb7d2, 0x00000000},
+ {0x0000ab4c, 0x00000000, 0x00000000, 0x000eb7d6, 0x000eb7d6, 0x00000000},
+ {0x0000ab50, 0x00000000, 0x00000000, 0x000eb7c3, 0x000eb7c3, 0x00000000},
+ {0x0000ab54, 0x00000000, 0x00000000, 0x000eb7c7, 0x000eb7c7, 0x00000000},
+ {0x0000ab58, 0x00000000, 0x00000000, 0x000eb7cb, 0x000eb7cb, 0x00000000},
+ {0x0000ab5c, 0x00000000, 0x00000000, 0x000eb7cf, 0x000eb7cf, 0x00000000},
+ {0x0000ab60, 0x00000000, 0x00000000, 0x000eb7d7, 0x000eb7d7, 0x00000000},
+ {0x0000ab64, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+ {0x0000ab68, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+ {0x0000ab6c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+ {0x0000ab70, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+ {0x0000ab74, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+ {0x0000ab78, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+ {0x0000ab7c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+ {0x0000ab80, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+ {0x0000ab84, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+ {0x0000ab88, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+ {0x0000ab8c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+ {0x0000ab90, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+ {0x0000ab94, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+ {0x0000ab98, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+ {0x0000ab9c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+ {0x0000aba0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+ {0x0000aba4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+ {0x0000aba8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+ {0x0000abac, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+ {0x0000abb0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+ {0x0000abb4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+ {0x0000abb8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+ {0x0000abbc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+ {0x0000abc0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+ {0x0000abc4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+ {0x0000abc8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+ {0x0000abcc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+ {0x0000abd0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+ {0x0000abd4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+ {0x0000abd8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+ {0x0000abdc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+ {0x0000abe0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+ {0x0000abe4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+ {0x0000abe8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+ {0x0000abec, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+ {0x0000abf0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+ {0x0000abf4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+ {0x0000abf8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+ {0x0000abfc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+ {0x0000a204, 0x00000004, 0x00000004, 0x00000004, 0x00000004, 0x00000004},
+ {0x0000a20c, 0x00000014, 0x00000014, 0x0001f000, 0x0001f000, 0x0001f000},
+ {0x0000b20c, 0x00000014, 0x00000014, 0x0001f000, 0x0001f000, 0x0001f000},
+ {0x0000a21c, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a},
+ {0x0000a230, 0x00000000, 0x00000000, 0x00000210, 0x00000108, 0x00000000},
+ {0x0000a250, 0x0004f000, 0x0004f000, 0x0004a000, 0x0004a000, 0x0004a000},
+ {0x0000a358, 0x7999aa02, 0x7999aa02, 0x7999aa0e, 0x7999aa0e, 0x7999aa0e},
};
static const u32 ar9285Common_9285_1_2[][2] = {
- { 0x0000000c, 0x00000000 },
- { 0x00000030, 0x00020045 },
- { 0x00000034, 0x00000005 },
- { 0x00000040, 0x00000000 },
- { 0x00000044, 0x00000008 },
- { 0x00000048, 0x00000008 },
- { 0x0000004c, 0x00000010 },
- { 0x00000050, 0x00000000 },
- { 0x00000054, 0x0000001f },
- { 0x00000800, 0x00000000 },
- { 0x00000804, 0x00000000 },
- { 0x00000808, 0x00000000 },
- { 0x0000080c, 0x00000000 },
- { 0x00000810, 0x00000000 },
- { 0x00000814, 0x00000000 },
- { 0x00000818, 0x00000000 },
- { 0x0000081c, 0x00000000 },
- { 0x00000820, 0x00000000 },
- { 0x00000824, 0x00000000 },
- { 0x00001040, 0x002ffc0f },
- { 0x00001044, 0x002ffc0f },
- { 0x00001048, 0x002ffc0f },
- { 0x0000104c, 0x002ffc0f },
- { 0x00001050, 0x002ffc0f },
- { 0x00001054, 0x002ffc0f },
- { 0x00001058, 0x002ffc0f },
- { 0x0000105c, 0x002ffc0f },
- { 0x00001060, 0x002ffc0f },
- { 0x00001064, 0x002ffc0f },
- { 0x00001230, 0x00000000 },
- { 0x00001270, 0x00000000 },
- { 0x00001038, 0x00000000 },
- { 0x00001078, 0x00000000 },
- { 0x000010b8, 0x00000000 },
- { 0x000010f8, 0x00000000 },
- { 0x00001138, 0x00000000 },
- { 0x00001178, 0x00000000 },
- { 0x000011b8, 0x00000000 },
- { 0x000011f8, 0x00000000 },
- { 0x00001238, 0x00000000 },
- { 0x00001278, 0x00000000 },
- { 0x000012b8, 0x00000000 },
- { 0x000012f8, 0x00000000 },
- { 0x00001338, 0x00000000 },
- { 0x00001378, 0x00000000 },
- { 0x000013b8, 0x00000000 },
- { 0x000013f8, 0x00000000 },
- { 0x00001438, 0x00000000 },
- { 0x00001478, 0x00000000 },
- { 0x000014b8, 0x00000000 },
- { 0x000014f8, 0x00000000 },
- { 0x00001538, 0x00000000 },
- { 0x00001578, 0x00000000 },
- { 0x000015b8, 0x00000000 },
- { 0x000015f8, 0x00000000 },
- { 0x00001638, 0x00000000 },
- { 0x00001678, 0x00000000 },
- { 0x000016b8, 0x00000000 },
- { 0x000016f8, 0x00000000 },
- { 0x00001738, 0x00000000 },
- { 0x00001778, 0x00000000 },
- { 0x000017b8, 0x00000000 },
- { 0x000017f8, 0x00000000 },
- { 0x0000103c, 0x00000000 },
- { 0x0000107c, 0x00000000 },
- { 0x000010bc, 0x00000000 },
- { 0x000010fc, 0x00000000 },
- { 0x0000113c, 0x00000000 },
- { 0x0000117c, 0x00000000 },
- { 0x000011bc, 0x00000000 },
- { 0x000011fc, 0x00000000 },
- { 0x0000123c, 0x00000000 },
- { 0x0000127c, 0x00000000 },
- { 0x000012bc, 0x00000000 },
- { 0x000012fc, 0x00000000 },
- { 0x0000133c, 0x00000000 },
- { 0x0000137c, 0x00000000 },
- { 0x000013bc, 0x00000000 },
- { 0x000013fc, 0x00000000 },
- { 0x0000143c, 0x00000000 },
- { 0x0000147c, 0x00000000 },
- { 0x00004030, 0x00000002 },
- { 0x0000403c, 0x00000002 },
- { 0x00004024, 0x0000001f },
- { 0x00004060, 0x00000000 },
- { 0x00004064, 0x00000000 },
- { 0x00007010, 0x00000031 },
- { 0x00007034, 0x00000002 },
- { 0x00007038, 0x000004c2 },
- { 0x00008004, 0x00000000 },
- { 0x00008008, 0x00000000 },
- { 0x0000800c, 0x00000000 },
- { 0x00008018, 0x00000700 },
- { 0x00008020, 0x00000000 },
- { 0x00008038, 0x00000000 },
- { 0x0000803c, 0x00000000 },
- { 0x00008048, 0x00000000 },
- { 0x00008054, 0x00000000 },
- { 0x00008058, 0x00000000 },
- { 0x0000805c, 0x000fc78f },
- { 0x00008060, 0x0000000f },
- { 0x00008064, 0x00000000 },
- { 0x00008070, 0x00000000 },
- { 0x000080c0, 0x2a80001a },
- { 0x000080c4, 0x05dc01e0 },
- { 0x000080c8, 0x1f402710 },
- { 0x000080cc, 0x01f40000 },
- { 0x000080d0, 0x00001e00 },
- { 0x000080d4, 0x00000000 },
- { 0x000080d8, 0x00400000 },
- { 0x000080e0, 0xffffffff },
- { 0x000080e4, 0x0000ffff },
- { 0x000080e8, 0x003f3f3f },
- { 0x000080ec, 0x00000000 },
- { 0x000080f0, 0x00000000 },
- { 0x000080f4, 0x00000000 },
- { 0x000080f8, 0x00000000 },
- { 0x000080fc, 0x00020000 },
- { 0x00008100, 0x00020000 },
- { 0x00008104, 0x00000001 },
- { 0x00008108, 0x00000052 },
- { 0x0000810c, 0x00000000 },
- { 0x00008110, 0x00000168 },
- { 0x00008118, 0x000100aa },
- { 0x0000811c, 0x00003210 },
- { 0x00008120, 0x08f04810 },
- { 0x00008124, 0x00000000 },
- { 0x00008128, 0x00000000 },
- { 0x0000812c, 0x00000000 },
- { 0x00008130, 0x00000000 },
- { 0x00008134, 0x00000000 },
- { 0x00008138, 0x00000000 },
- { 0x0000813c, 0x00000000 },
- { 0x00008144, 0xffffffff },
- { 0x00008168, 0x00000000 },
- { 0x0000816c, 0x00000000 },
- { 0x00008170, 0x32143320 },
- { 0x00008174, 0xfaa4fa50 },
- { 0x00008178, 0x00000100 },
- { 0x0000817c, 0x00000000 },
- { 0x000081c0, 0x00000000 },
- { 0x000081d0, 0x0000320a },
- { 0x000081ec, 0x00000000 },
- { 0x000081f0, 0x00000000 },
- { 0x000081f4, 0x00000000 },
- { 0x000081f8, 0x00000000 },
- { 0x000081fc, 0x00000000 },
- { 0x00008200, 0x00000000 },
- { 0x00008204, 0x00000000 },
- { 0x00008208, 0x00000000 },
- { 0x0000820c, 0x00000000 },
- { 0x00008210, 0x00000000 },
- { 0x00008214, 0x00000000 },
- { 0x00008218, 0x00000000 },
- { 0x0000821c, 0x00000000 },
- { 0x00008220, 0x00000000 },
- { 0x00008224, 0x00000000 },
- { 0x00008228, 0x00000000 },
- { 0x0000822c, 0x00000000 },
- { 0x00008230, 0x00000000 },
- { 0x00008234, 0x00000000 },
- { 0x00008238, 0x00000000 },
- { 0x0000823c, 0x00000000 },
- { 0x00008240, 0x00100000 },
- { 0x00008244, 0x0010f400 },
- { 0x00008248, 0x00000100 },
- { 0x0000824c, 0x0001e800 },
- { 0x00008250, 0x00000000 },
- { 0x00008254, 0x00000000 },
- { 0x00008258, 0x00000000 },
- { 0x0000825c, 0x400000ff },
- { 0x00008260, 0x00080922 },
- { 0x00008264, 0x88a00010 },
- { 0x00008270, 0x00000000 },
- { 0x00008274, 0x40000000 },
- { 0x00008278, 0x003e4180 },
- { 0x0000827c, 0x00000000 },
- { 0x00008284, 0x0000002c },
- { 0x00008288, 0x0000002c },
- { 0x0000828c, 0x00000000 },
- { 0x00008294, 0x00000000 },
- { 0x00008298, 0x00000000 },
- { 0x0000829c, 0x00000000 },
- { 0x00008300, 0x00000040 },
- { 0x00008314, 0x00000000 },
- { 0x00008328, 0x00000000 },
- { 0x0000832c, 0x00000001 },
- { 0x00008330, 0x00000302 },
- { 0x00008334, 0x00000e00 },
- { 0x00008338, 0x00ff0000 },
- { 0x0000833c, 0x00000000 },
- { 0x00008340, 0x00010380 },
- { 0x00008344, 0x00481043 },
- { 0x00009808, 0x00000000 },
- { 0x0000980c, 0xafe68e30 },
- { 0x00009810, 0xfd14e000 },
- { 0x00009814, 0x9c0a9f6b },
- { 0x0000981c, 0x00000000 },
- { 0x0000982c, 0x0000a000 },
- { 0x00009830, 0x00000000 },
- { 0x0000983c, 0x00200400 },
- { 0x0000984c, 0x0040233c },
- { 0x00009854, 0x00000044 },
- { 0x00009900, 0x00000000 },
- { 0x00009904, 0x00000000 },
- { 0x00009908, 0x00000000 },
- { 0x0000990c, 0x00000000 },
- { 0x00009910, 0x01002310 },
- { 0x0000991c, 0x10000fff },
- { 0x00009920, 0x04900000 },
- { 0x00009928, 0x00000001 },
- { 0x0000992c, 0x00000004 },
- { 0x00009934, 0x1e1f2022 },
- { 0x00009938, 0x0a0b0c0d },
- { 0x0000993c, 0x00000000 },
- { 0x00009940, 0x14750604 },
- { 0x00009948, 0x9280c00a },
- { 0x0000994c, 0x00020028 },
- { 0x00009954, 0x5f3ca3de },
- { 0x00009958, 0x2108ecff },
- { 0x00009968, 0x000003ce },
- { 0x00009970, 0x192bb514 },
- { 0x00009974, 0x00000000 },
- { 0x00009978, 0x00000001 },
- { 0x0000997c, 0x00000000 },
- { 0x00009980, 0x00000000 },
- { 0x00009984, 0x00000000 },
- { 0x00009988, 0x00000000 },
- { 0x0000998c, 0x00000000 },
- { 0x00009990, 0x00000000 },
- { 0x00009994, 0x00000000 },
- { 0x00009998, 0x00000000 },
- { 0x0000999c, 0x00000000 },
- { 0x000099a0, 0x00000000 },
- { 0x000099a4, 0x00000001 },
- { 0x000099a8, 0x201fff00 },
- { 0x000099ac, 0x2def0400 },
- { 0x000099b0, 0x03051000 },
- { 0x000099b4, 0x00000820 },
- { 0x000099dc, 0x00000000 },
- { 0x000099e0, 0x00000000 },
- { 0x000099e4, 0xaaaaaaaa },
- { 0x000099e8, 0x3c466478 },
- { 0x000099ec, 0x0cc80caa },
- { 0x000099f0, 0x00000000 },
- { 0x0000a208, 0x803e68c8 },
- { 0x0000a210, 0x4080a333 },
- { 0x0000a214, 0x00206c10 },
- { 0x0000a218, 0x009c4060 },
- { 0x0000a220, 0x01834061 },
- { 0x0000a224, 0x00000400 },
- { 0x0000a228, 0x000003b5 },
- { 0x0000a22c, 0x00000000 },
- { 0x0000a234, 0x20202020 },
- { 0x0000a238, 0x20202020 },
- { 0x0000a244, 0x00000000 },
- { 0x0000a248, 0xfffffffc },
- { 0x0000a24c, 0x00000000 },
- { 0x0000a254, 0x00000000 },
- { 0x0000a258, 0x0ccb5380 },
- { 0x0000a25c, 0x15151501 },
- { 0x0000a260, 0xdfa90f01 },
- { 0x0000a268, 0x00000000 },
- { 0x0000a26c, 0x0ebae9e6 },
- { 0x0000d270, 0x0d820820 },
- { 0x0000d35c, 0x07ffffef },
- { 0x0000d360, 0x0fffffe7 },
- { 0x0000d364, 0x17ffffe5 },
- { 0x0000d368, 0x1fffffe4 },
- { 0x0000d36c, 0x37ffffe3 },
- { 0x0000d370, 0x3fffffe3 },
- { 0x0000d374, 0x57ffffe3 },
- { 0x0000d378, 0x5fffffe2 },
- { 0x0000d37c, 0x7fffffe2 },
- { 0x0000d380, 0x7f3c7bba },
- { 0x0000d384, 0xf3307ff0 },
- { 0x0000a388, 0x0c000000 },
- { 0x0000a38c, 0x20202020 },
- { 0x0000a390, 0x20202020 },
- { 0x0000a39c, 0x00000001 },
- { 0x0000a3a0, 0x00000000 },
- { 0x0000a3a4, 0x00000000 },
- { 0x0000a3a8, 0x00000000 },
- { 0x0000a3ac, 0x00000000 },
- { 0x0000a3b0, 0x00000000 },
- { 0x0000a3b4, 0x00000000 },
- { 0x0000a3b8, 0x00000000 },
- { 0x0000a3bc, 0x00000000 },
- { 0x0000a3c0, 0x00000000 },
- { 0x0000a3c4, 0x00000000 },
- { 0x0000a3cc, 0x20202020 },
- { 0x0000a3d0, 0x20202020 },
- { 0x0000a3d4, 0x20202020 },
- { 0x0000a3e4, 0x00000000 },
- { 0x0000a3e8, 0x18c43433 },
- { 0x0000a3ec, 0x00f70081 },
- { 0x00007800, 0x00140000 },
- { 0x00007804, 0x0e4548d8 },
- { 0x00007808, 0x54214514 },
- { 0x0000780c, 0x02025830 },
- { 0x00007810, 0x71c0d388 },
- { 0x0000781c, 0x00000000 },
- { 0x00007824, 0x00d86fff },
- { 0x0000782c, 0x6e36d97b },
- { 0x00007834, 0x71400087 },
- { 0x00007844, 0x000c0db6 },
- { 0x00007848, 0x6db6246f },
- { 0x0000784c, 0x6d9b66db },
- { 0x00007850, 0x6d8c6dba },
- { 0x00007854, 0x00040000 },
- { 0x00007858, 0xdb003012 },
- { 0x0000785c, 0x04924914 },
- { 0x00007860, 0x21084210 },
- { 0x00007864, 0xf7d7ffde },
- { 0x00007868, 0xc2034080 },
- { 0x00007870, 0x10142c00 },
+ /* Addr allmodes */
+ {0x0000000c, 0x00000000},
+ {0x00000030, 0x00020045},
+ {0x00000034, 0x00000005},
+ {0x00000040, 0x00000000},
+ {0x00000044, 0x00000008},
+ {0x00000048, 0x00000008},
+ {0x0000004c, 0x00000010},
+ {0x00000050, 0x00000000},
+ {0x00000054, 0x0000001f},
+ {0x00000800, 0x00000000},
+ {0x00000804, 0x00000000},
+ {0x00000808, 0x00000000},
+ {0x0000080c, 0x00000000},
+ {0x00000810, 0x00000000},
+ {0x00000814, 0x00000000},
+ {0x00000818, 0x00000000},
+ {0x0000081c, 0x00000000},
+ {0x00000820, 0x00000000},
+ {0x00000824, 0x00000000},
+ {0x00001040, 0x002ffc0f},
+ {0x00001044, 0x002ffc0f},
+ {0x00001048, 0x002ffc0f},
+ {0x0000104c, 0x002ffc0f},
+ {0x00001050, 0x002ffc0f},
+ {0x00001054, 0x002ffc0f},
+ {0x00001058, 0x002ffc0f},
+ {0x0000105c, 0x002ffc0f},
+ {0x00001060, 0x002ffc0f},
+ {0x00001064, 0x002ffc0f},
+ {0x00001230, 0x00000000},
+ {0x00001270, 0x00000000},
+ {0x00001038, 0x00000000},
+ {0x00001078, 0x00000000},
+ {0x000010b8, 0x00000000},
+ {0x000010f8, 0x00000000},
+ {0x00001138, 0x00000000},
+ {0x00001178, 0x00000000},
+ {0x000011b8, 0x00000000},
+ {0x000011f8, 0x00000000},
+ {0x00001238, 0x00000000},
+ {0x00001278, 0x00000000},
+ {0x000012b8, 0x00000000},
+ {0x000012f8, 0x00000000},
+ {0x00001338, 0x00000000},
+ {0x00001378, 0x00000000},
+ {0x000013b8, 0x00000000},
+ {0x000013f8, 0x00000000},
+ {0x00001438, 0x00000000},
+ {0x00001478, 0x00000000},
+ {0x000014b8, 0x00000000},
+ {0x000014f8, 0x00000000},
+ {0x00001538, 0x00000000},
+ {0x00001578, 0x00000000},
+ {0x000015b8, 0x00000000},
+ {0x000015f8, 0x00000000},
+ {0x00001638, 0x00000000},
+ {0x00001678, 0x00000000},
+ {0x000016b8, 0x00000000},
+ {0x000016f8, 0x00000000},
+ {0x00001738, 0x00000000},
+ {0x00001778, 0x00000000},
+ {0x000017b8, 0x00000000},
+ {0x000017f8, 0x00000000},
+ {0x0000103c, 0x00000000},
+ {0x0000107c, 0x00000000},
+ {0x000010bc, 0x00000000},
+ {0x000010fc, 0x00000000},
+ {0x0000113c, 0x00000000},
+ {0x0000117c, 0x00000000},
+ {0x000011bc, 0x00000000},
+ {0x000011fc, 0x00000000},
+ {0x0000123c, 0x00000000},
+ {0x0000127c, 0x00000000},
+ {0x000012bc, 0x00000000},
+ {0x000012fc, 0x00000000},
+ {0x0000133c, 0x00000000},
+ {0x0000137c, 0x00000000},
+ {0x000013bc, 0x00000000},
+ {0x000013fc, 0x00000000},
+ {0x0000143c, 0x00000000},
+ {0x0000147c, 0x00000000},
+ {0x00004030, 0x00000002},
+ {0x0000403c, 0x00000002},
+ {0x00004024, 0x0000001f},
+ {0x00004060, 0x00000000},
+ {0x00004064, 0x00000000},
+ {0x00007010, 0x00000031},
+ {0x00007034, 0x00000002},
+ {0x00007038, 0x000004c2},
+ {0x00008004, 0x00000000},
+ {0x00008008, 0x00000000},
+ {0x0000800c, 0x00000000},
+ {0x00008018, 0x00000700},
+ {0x00008020, 0x00000000},
+ {0x00008038, 0x00000000},
+ {0x0000803c, 0x00000000},
+ {0x00008048, 0x00000000},
+ {0x00008054, 0x00000000},
+ {0x00008058, 0x00000000},
+ {0x0000805c, 0x000fc78f},
+ {0x00008060, 0x0000000f},
+ {0x00008064, 0x00000000},
+ {0x00008070, 0x00000000},
+ {0x000080c0, 0x2a80001a},
+ {0x000080c4, 0x05dc01e0},
+ {0x000080c8, 0x1f402710},
+ {0x000080cc, 0x01f40000},
+ {0x000080d0, 0x00001e00},
+ {0x000080d4, 0x00000000},
+ {0x000080d8, 0x00400000},
+ {0x000080e0, 0xffffffff},
+ {0x000080e4, 0x0000ffff},
+ {0x000080e8, 0x003f3f3f},
+ {0x000080ec, 0x00000000},
+ {0x000080f0, 0x00000000},
+ {0x000080f4, 0x00000000},
+ {0x000080f8, 0x00000000},
+ {0x000080fc, 0x00020000},
+ {0x00008100, 0x00020000},
+ {0x00008104, 0x00000001},
+ {0x00008108, 0x00000052},
+ {0x0000810c, 0x00000000},
+ {0x00008110, 0x00000168},
+ {0x00008118, 0x000100aa},
+ {0x0000811c, 0x00003210},
+ {0x00008120, 0x08f04810},
+ {0x00008124, 0x00000000},
+ {0x00008128, 0x00000000},
+ {0x0000812c, 0x00000000},
+ {0x00008130, 0x00000000},
+ {0x00008134, 0x00000000},
+ {0x00008138, 0x00000000},
+ {0x0000813c, 0x00000000},
+ {0x00008144, 0xffffffff},
+ {0x00008168, 0x00000000},
+ {0x0000816c, 0x00000000},
+ {0x00008170, 0x32143320},
+ {0x00008174, 0xfaa4fa50},
+ {0x00008178, 0x00000100},
+ {0x0000817c, 0x00000000},
+ {0x000081c0, 0x00000000},
+ {0x000081d0, 0x0000320a},
+ {0x000081ec, 0x00000000},
+ {0x000081f0, 0x00000000},
+ {0x000081f4, 0x00000000},
+ {0x000081f8, 0x00000000},
+ {0x000081fc, 0x00000000},
+ {0x00008200, 0x00000000},
+ {0x00008204, 0x00000000},
+ {0x00008208, 0x00000000},
+ {0x0000820c, 0x00000000},
+ {0x00008210, 0x00000000},
+ {0x00008214, 0x00000000},
+ {0x00008218, 0x00000000},
+ {0x0000821c, 0x00000000},
+ {0x00008220, 0x00000000},
+ {0x00008224, 0x00000000},
+ {0x00008228, 0x00000000},
+ {0x0000822c, 0x00000000},
+ {0x00008230, 0x00000000},
+ {0x00008234, 0x00000000},
+ {0x00008238, 0x00000000},
+ {0x0000823c, 0x00000000},
+ {0x00008240, 0x00100000},
+ {0x00008244, 0x0010f400},
+ {0x00008248, 0x00000100},
+ {0x0000824c, 0x0001e800},
+ {0x00008250, 0x00000000},
+ {0x00008254, 0x00000000},
+ {0x00008258, 0x00000000},
+ {0x0000825c, 0x400000ff},
+ {0x00008260, 0x00080922},
+ {0x00008264, 0x88a00010},
+ {0x00008270, 0x00000000},
+ {0x00008274, 0x40000000},
+ {0x00008278, 0x003e4180},
+ {0x0000827c, 0x00000000},
+ {0x00008284, 0x0000002c},
+ {0x00008288, 0x0000002c},
+ {0x0000828c, 0x00000000},
+ {0x00008294, 0x00000000},
+ {0x00008298, 0x00000000},
+ {0x0000829c, 0x00000000},
+ {0x00008300, 0x00000040},
+ {0x00008314, 0x00000000},
+ {0x00008328, 0x00000000},
+ {0x0000832c, 0x00000001},
+ {0x00008330, 0x00000302},
+ {0x00008334, 0x00000e00},
+ {0x00008338, 0x00ff0000},
+ {0x0000833c, 0x00000000},
+ {0x00008340, 0x00010380},
+ {0x00008344, 0x00481043},
+ {0x00009808, 0x00000000},
+ {0x0000980c, 0xafe68e30},
+ {0x00009810, 0xfd14e000},
+ {0x00009814, 0x9c0a9f6b},
+ {0x0000981c, 0x00000000},
+ {0x0000982c, 0x0000a000},
+ {0x00009830, 0x00000000},
+ {0x0000983c, 0x00200400},
+ {0x0000984c, 0x0040233c},
+ {0x00009854, 0x00000044},
+ {0x00009900, 0x00000000},
+ {0x00009904, 0x00000000},
+ {0x00009908, 0x00000000},
+ {0x0000990c, 0x00000000},
+ {0x00009910, 0x01002310},
+ {0x0000991c, 0x10000fff},
+ {0x00009920, 0x04900000},
+ {0x00009928, 0x00000001},
+ {0x0000992c, 0x00000004},
+ {0x00009934, 0x1e1f2022},
+ {0x00009938, 0x0a0b0c0d},
+ {0x0000993c, 0x00000000},
+ {0x00009940, 0x14750604},
+ {0x00009948, 0x9280c00a},
+ {0x0000994c, 0x00020028},
+ {0x00009954, 0x5f3ca3de},
+ {0x00009958, 0x2108ecff},
+ {0x00009968, 0x000003ce},
+ {0x00009970, 0x192bb514},
+ {0x00009974, 0x00000000},
+ {0x00009978, 0x00000001},
+ {0x0000997c, 0x00000000},
+ {0x00009980, 0x00000000},
+ {0x00009984, 0x00000000},
+ {0x00009988, 0x00000000},
+ {0x0000998c, 0x00000000},
+ {0x00009990, 0x00000000},
+ {0x00009994, 0x00000000},
+ {0x00009998, 0x00000000},
+ {0x0000999c, 0x00000000},
+ {0x000099a0, 0x00000000},
+ {0x000099a4, 0x00000001},
+ {0x000099a8, 0x201fff00},
+ {0x000099ac, 0x2def0400},
+ {0x000099b0, 0x03051000},
+ {0x000099b4, 0x00000820},
+ {0x000099dc, 0x00000000},
+ {0x000099e0, 0x00000000},
+ {0x000099e4, 0xaaaaaaaa},
+ {0x000099e8, 0x3c466478},
+ {0x000099ec, 0x0cc80caa},
+ {0x000099f0, 0x00000000},
+ {0x0000a208, 0x803e68c8},
+ {0x0000a210, 0x4080a333},
+ {0x0000a214, 0x00206c10},
+ {0x0000a218, 0x009c4060},
+ {0x0000a220, 0x01834061},
+ {0x0000a224, 0x00000400},
+ {0x0000a228, 0x000003b5},
+ {0x0000a22c, 0x00000000},
+ {0x0000a234, 0x20202020},
+ {0x0000a238, 0x20202020},
+ {0x0000a244, 0x00000000},
+ {0x0000a248, 0xfffffffc},
+ {0x0000a24c, 0x00000000},
+ {0x0000a254, 0x00000000},
+ {0x0000a258, 0x0ccb5380},
+ {0x0000a25c, 0x15151501},
+ {0x0000a260, 0xdfa90f01},
+ {0x0000a268, 0x00000000},
+ {0x0000a26c, 0x0ebae9e6},
+ {0x0000d270, 0x0d820820},
+ {0x0000d35c, 0x07ffffef},
+ {0x0000d360, 0x0fffffe7},
+ {0x0000d364, 0x17ffffe5},
+ {0x0000d368, 0x1fffffe4},
+ {0x0000d36c, 0x37ffffe3},
+ {0x0000d370, 0x3fffffe3},
+ {0x0000d374, 0x57ffffe3},
+ {0x0000d378, 0x5fffffe2},
+ {0x0000d37c, 0x7fffffe2},
+ {0x0000d380, 0x7f3c7bba},
+ {0x0000d384, 0xf3307ff0},
+ {0x0000a388, 0x0c000000},
+ {0x0000a38c, 0x20202020},
+ {0x0000a390, 0x20202020},
+ {0x0000a39c, 0x00000001},
+ {0x0000a3a0, 0x00000000},
+ {0x0000a3a4, 0x00000000},
+ {0x0000a3a8, 0x00000000},
+ {0x0000a3ac, 0x00000000},
+ {0x0000a3b0, 0x00000000},
+ {0x0000a3b4, 0x00000000},
+ {0x0000a3b8, 0x00000000},
+ {0x0000a3bc, 0x00000000},
+ {0x0000a3c0, 0x00000000},
+ {0x0000a3c4, 0x00000000},
+ {0x0000a3cc, 0x20202020},
+ {0x0000a3d0, 0x20202020},
+ {0x0000a3d4, 0x20202020},
+ {0x0000a3e4, 0x00000000},
+ {0x0000a3e8, 0x18c43433},
+ {0x0000a3ec, 0x00f70081},
+ {0x00007800, 0x00140000},
+ {0x00007804, 0x0e4548d8},
+ {0x00007808, 0x54214514},
+ {0x0000780c, 0x02025830},
+ {0x00007810, 0x71c0d388},
+ {0x0000781c, 0x00000000},
+ {0x00007824, 0x00d86fff},
+ {0x0000782c, 0x6e36d97b},
+ {0x00007834, 0x71400087},
+ {0x00007844, 0x000c0db6},
+ {0x00007848, 0x6db6246f},
+ {0x0000784c, 0x6d9b66db},
+ {0x00007850, 0x6d8c6dba},
+ {0x00007854, 0x00040000},
+ {0x00007858, 0xdb003012},
+ {0x0000785c, 0x04924914},
+ {0x00007860, 0x21084210},
+ {0x00007864, 0xf7d7ffde},
+ {0x00007868, 0xc2034080},
+ {0x00007870, 0x10142c00},
};
static const u32 ar9285Modes_high_power_tx_gain_9285_1_2[][6] = {
- /* Address 5G-HT20 5G-HT40 2G-HT40 2G-HT20 Turbo */
- { 0x0000a300, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
- { 0x0000a304, 0x00000000, 0x00000000, 0x00006200, 0x00006200, 0x00000000 },
- { 0x0000a308, 0x00000000, 0x00000000, 0x00008201, 0x00008201, 0x00000000 },
- { 0x0000a30c, 0x00000000, 0x00000000, 0x0000b240, 0x0000b240, 0x00000000 },
- { 0x0000a310, 0x00000000, 0x00000000, 0x0000d241, 0x0000d241, 0x00000000 },
- { 0x0000a314, 0x00000000, 0x00000000, 0x0000f600, 0x0000f600, 0x00000000 },
- { 0x0000a318, 0x00000000, 0x00000000, 0x00012800, 0x00012800, 0x00000000 },
- { 0x0000a31c, 0x00000000, 0x00000000, 0x00016802, 0x00016802, 0x00000000 },
- { 0x0000a320, 0x00000000, 0x00000000, 0x0001b805, 0x0001b805, 0x00000000 },
- { 0x0000a324, 0x00000000, 0x00000000, 0x00021a80, 0x00021a80, 0x00000000 },
- { 0x0000a328, 0x00000000, 0x00000000, 0x00028b00, 0x00028b00, 0x00000000 },
- { 0x0000a32c, 0x00000000, 0x00000000, 0x0002ab40, 0x0002ab40, 0x00000000 },
- { 0x0000a330, 0x00000000, 0x00000000, 0x0002cd80, 0x0002cd80, 0x00000000 },
- { 0x0000a334, 0x00000000, 0x00000000, 0x00033d82, 0x00033d82, 0x00000000 },
- { 0x0000a338, 0x0003891e, 0x0003891e, 0x0003891e, 0x0003891e, 0x00000000 },
- { 0x0000a33c, 0x0003a95e, 0x0003a95e, 0x0003a95e, 0x0003a95e, 0x00000000 },
- { 0x0000a340, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 },
- { 0x0000a344, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 },
- { 0x0000a348, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 },
- { 0x0000a34c, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 },
- { 0x0000a350, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 },
- { 0x0000a354, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 },
- { 0x00007814, 0x924934a8, 0x924934a8, 0x924934a8, 0x924934a8, 0x924934a8 },
- { 0x00007828, 0x26d2491b, 0x26d2491b, 0x26d2491b, 0x26d2491b, 0x26d2491b },
- { 0x00007830, 0xedb6d96e, 0xedb6d96e, 0xedb6d96e, 0xedb6d96e, 0xedb6d96e },
- { 0x00007838, 0xfac68803, 0xfac68803, 0xfac68803, 0xfac68803, 0xfac68803 },
- { 0x0000783c, 0x0001fffe, 0x0001fffe, 0x0001fffe, 0x0001fffe, 0x0001fffe },
- { 0x00007840, 0xffeb1a20, 0xffeb1a20, 0xffeb1a20, 0xffeb1a20, 0xffeb1a20 },
- { 0x0000786c, 0x08609ebe, 0x08609ebe, 0x08609ebe, 0x08609ebe, 0x08609ebe },
- { 0x00007820, 0x00000c00, 0x00000c00, 0x00000c00, 0x00000c00, 0x00000c00 },
- { 0x0000a274, 0x0a22a652, 0x0a22a652, 0x0a216652, 0x0a216652, 0x0a22a652 },
- { 0x0000a278, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7 },
- { 0x0000a27c, 0x050380e7, 0x050380e7, 0x050380e7, 0x050380e7, 0x050380e7 },
- { 0x0000a394, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7 },
- { 0x0000a398, 0x000000e7, 0x000000e7, 0x000000e7, 0x000000e7, 0x000000e7 },
- { 0x0000a3dc, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7 },
- { 0x0000a3e0, 0x000000e7, 0x000000e7, 0x000000e7, 0x000000e7, 0x000000e7 },
+ {0x0000a300, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+ {0x0000a304, 0x00000000, 0x00000000, 0x00006200, 0x00006200, 0x00000000},
+ {0x0000a308, 0x00000000, 0x00000000, 0x00008201, 0x00008201, 0x00000000},
+ {0x0000a30c, 0x00000000, 0x00000000, 0x0000b240, 0x0000b240, 0x00000000},
+ {0x0000a310, 0x00000000, 0x00000000, 0x0000d241, 0x0000d241, 0x00000000},
+ {0x0000a314, 0x00000000, 0x00000000, 0x0000f600, 0x0000f600, 0x00000000},
+ {0x0000a318, 0x00000000, 0x00000000, 0x00012800, 0x00012800, 0x00000000},
+ {0x0000a31c, 0x00000000, 0x00000000, 0x00016802, 0x00016802, 0x00000000},
+ {0x0000a320, 0x00000000, 0x00000000, 0x0001b805, 0x0001b805, 0x00000000},
+ {0x0000a324, 0x00000000, 0x00000000, 0x00021a80, 0x00021a80, 0x00000000},
+ {0x0000a328, 0x00000000, 0x00000000, 0x00028b00, 0x00028b00, 0x00000000},
+ {0x0000a32c, 0x00000000, 0x00000000, 0x0002ab40, 0x0002ab40, 0x00000000},
+ {0x0000a330, 0x00000000, 0x00000000, 0x0002cd80, 0x0002cd80, 0x00000000},
+ {0x0000a334, 0x00000000, 0x00000000, 0x00033d82, 0x00033d82, 0x00000000},
+ {0x0000a338, 0x0003891e, 0x0003891e, 0x0003891e, 0x0003891e, 0x00000000},
+ {0x0000a33c, 0x0003a95e, 0x0003a95e, 0x0003a95e, 0x0003a95e, 0x00000000},
+ {0x0000a340, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000},
+ {0x0000a344, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000},
+ {0x0000a348, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000},
+ {0x0000a34c, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000},
+ {0x0000a350, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000},
+ {0x0000a354, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000},
+ {0x00007814, 0x924934a8, 0x924934a8, 0x924934a8, 0x924934a8, 0x924934a8},
+ {0x00007828, 0x26d2491b, 0x26d2491b, 0x26d2491b, 0x26d2491b, 0x26d2491b},
+ {0x00007830, 0xedb6d96e, 0xedb6d96e, 0xedb6d96e, 0xedb6d96e, 0xedb6d96e},
+ {0x00007838, 0xfac68803, 0xfac68803, 0xfac68803, 0xfac68803, 0xfac68803},
+ {0x0000783c, 0x0001fffe, 0x0001fffe, 0x0001fffe, 0x0001fffe, 0x0001fffe},
+ {0x00007840, 0xffeb1a20, 0xffeb1a20, 0xffeb1a20, 0xffeb1a20, 0xffeb1a20},
+ {0x0000786c, 0x08609ebe, 0x08609ebe, 0x08609ebe, 0x08609ebe, 0x08609ebe},
+ {0x00007820, 0x00000c00, 0x00000c00, 0x00000c00, 0x00000c00, 0x00000c00},
+ {0x0000a274, 0x0a22a652, 0x0a22a652, 0x0a216652, 0x0a216652, 0x0a22a652},
+ {0x0000a278, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7},
+ {0x0000a27c, 0x050380e7, 0x050380e7, 0x050380e7, 0x050380e7, 0x050380e7},
+ {0x0000a394, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7},
+ {0x0000a398, 0x000000e7, 0x000000e7, 0x000000e7, 0x000000e7, 0x000000e7},
+ {0x0000a3dc, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7},
+ {0x0000a3e0, 0x000000e7, 0x000000e7, 0x000000e7, 0x000000e7, 0x000000e7},
};
static const u32 ar9285Modes_original_tx_gain_9285_1_2[][6] = {
- /* Address 5G-HT20 5G-HT40 2G-HT40 2G-HT20 Turbo */
- { 0x0000a300, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
- { 0x0000a304, 0x00000000, 0x00000000, 0x00009200, 0x00009200, 0x00000000 },
- { 0x0000a308, 0x00000000, 0x00000000, 0x00010208, 0x00010208, 0x00000000 },
- { 0x0000a30c, 0x00000000, 0x00000000, 0x00019608, 0x00019608, 0x00000000 },
- { 0x0000a310, 0x00000000, 0x00000000, 0x00022618, 0x00022618, 0x00000000 },
- { 0x0000a314, 0x00000000, 0x00000000, 0x0002a6c9, 0x0002a6c9, 0x00000000 },
- { 0x0000a318, 0x00000000, 0x00000000, 0x00031710, 0x00031710, 0x00000000 },
- { 0x0000a31c, 0x00000000, 0x00000000, 0x00035718, 0x00035718, 0x00000000 },
- { 0x0000a320, 0x00000000, 0x00000000, 0x00038758, 0x00038758, 0x00000000 },
- { 0x0000a324, 0x00000000, 0x00000000, 0x0003c75a, 0x0003c75a, 0x00000000 },
- { 0x0000a328, 0x00000000, 0x00000000, 0x0004075c, 0x0004075c, 0x00000000 },
- { 0x0000a32c, 0x00000000, 0x00000000, 0x0004475e, 0x0004475e, 0x00000000 },
- { 0x0000a330, 0x00000000, 0x00000000, 0x0004679f, 0x0004679f, 0x00000000 },
- { 0x0000a334, 0x00000000, 0x00000000, 0x000487df, 0x000487df, 0x00000000 },
- { 0x0000a338, 0x0003891e, 0x0003891e, 0x0003891e, 0x0003891e, 0x00000000 },
- { 0x0000a33c, 0x0003a95e, 0x0003a95e, 0x0003a95e, 0x0003a95e, 0x00000000 },
- { 0x0000a340, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 },
- { 0x0000a344, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 },
- { 0x0000a348, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 },
- { 0x0000a34c, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 },
- { 0x0000a350, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 },
- { 0x0000a354, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 },
- { 0x00007814, 0x924934a8, 0x924934a8, 0x924934a8, 0x924934a8, 0x924934a8 },
- { 0x00007828, 0x26d2491b, 0x26d2491b, 0x26d2491b, 0x26d2491b, 0x26d2491b },
- { 0x00007830, 0xedb6d96e, 0xedb6d96e, 0xedb6d96e, 0xedb6d96e, 0xedb6d96e },
- { 0x00007838, 0xfac68801, 0xfac68801, 0xfac68801, 0xfac68801, 0xfac68801 },
- { 0x0000783c, 0x0001fffe, 0x0001fffe, 0x0001fffe, 0x0001fffe, 0x0001fffe },
- { 0x00007840, 0xffeb1a20, 0xffeb1a20, 0xffeb1a20, 0xffeb1a20, 0xffeb1a20 },
- { 0x0000786c, 0x48609eb4, 0x48609eb4, 0x48609eb4, 0x48609eb4, 0x48609eb4 },
- { 0x00007820, 0x00000c04, 0x00000c04, 0x00000c04, 0x00000c04, 0x00000c04 },
- { 0x0000a274, 0x0a21c652, 0x0a21c652, 0x0a21a652, 0x0a21a652, 0x0a22a652 },
- { 0x0000a278, 0x39ce739c, 0x39ce739c, 0x39ce739c, 0x39ce739c, 0x39ce739c },
- { 0x0000a27c, 0x050e039c, 0x050e039c, 0x050e039c, 0x050e039c, 0x050e039c },
- { 0x0000a394, 0x39ce739c, 0x39ce739c, 0x39ce739c, 0x39ce739c, 0x39ce739c },
- { 0x0000a398, 0x0000039c, 0x0000039c, 0x0000039c, 0x0000039c, 0x0000039c },
- { 0x0000a3dc, 0x39ce739c, 0x39ce739c, 0x39ce739c, 0x39ce739c, 0x39ce739c },
- { 0x0000a3e0, 0x0000039c, 0x0000039c, 0x0000039c, 0x0000039c, 0x0000039c },
+ {0x0000a300, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+ {0x0000a304, 0x00000000, 0x00000000, 0x00009200, 0x00009200, 0x00000000},
+ {0x0000a308, 0x00000000, 0x00000000, 0x00010208, 0x00010208, 0x00000000},
+ {0x0000a30c, 0x00000000, 0x00000000, 0x00019608, 0x00019608, 0x00000000},
+ {0x0000a310, 0x00000000, 0x00000000, 0x00022618, 0x00022618, 0x00000000},
+ {0x0000a314, 0x00000000, 0x00000000, 0x0002a6c9, 0x0002a6c9, 0x00000000},
+ {0x0000a318, 0x00000000, 0x00000000, 0x00031710, 0x00031710, 0x00000000},
+ {0x0000a31c, 0x00000000, 0x00000000, 0x00035718, 0x00035718, 0x00000000},
+ {0x0000a320, 0x00000000, 0x00000000, 0x00038758, 0x00038758, 0x00000000},
+ {0x0000a324, 0x00000000, 0x00000000, 0x0003c75a, 0x0003c75a, 0x00000000},
+ {0x0000a328, 0x00000000, 0x00000000, 0x0004075c, 0x0004075c, 0x00000000},
+ {0x0000a32c, 0x00000000, 0x00000000, 0x0004475e, 0x0004475e, 0x00000000},
+ {0x0000a330, 0x00000000, 0x00000000, 0x0004679f, 0x0004679f, 0x00000000},
+ {0x0000a334, 0x00000000, 0x00000000, 0x000487df, 0x000487df, 0x00000000},
+ {0x0000a338, 0x0003891e, 0x0003891e, 0x0003891e, 0x0003891e, 0x00000000},
+ {0x0000a33c, 0x0003a95e, 0x0003a95e, 0x0003a95e, 0x0003a95e, 0x00000000},
+ {0x0000a340, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000},
+ {0x0000a344, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000},
+ {0x0000a348, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000},
+ {0x0000a34c, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000},
+ {0x0000a350, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000},
+ {0x0000a354, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000},
+ {0x00007814, 0x924934a8, 0x924934a8, 0x924934a8, 0x924934a8, 0x924934a8},
+ {0x00007828, 0x26d2491b, 0x26d2491b, 0x26d2491b, 0x26d2491b, 0x26d2491b},
+ {0x00007830, 0xedb6d96e, 0xedb6d96e, 0xedb6d96e, 0xedb6d96e, 0xedb6d96e},
+ {0x00007838, 0xfac68801, 0xfac68801, 0xfac68801, 0xfac68801, 0xfac68801},
+ {0x0000783c, 0x0001fffe, 0x0001fffe, 0x0001fffe, 0x0001fffe, 0x0001fffe},
+ {0x00007840, 0xffeb1a20, 0xffeb1a20, 0xffeb1a20, 0xffeb1a20, 0xffeb1a20},
+ {0x0000786c, 0x48609eb4, 0x48609eb4, 0x48609eb4, 0x48609eb4, 0x48609eb4},
+ {0x00007820, 0x00000c04, 0x00000c04, 0x00000c04, 0x00000c04, 0x00000c04},
+ {0x0000a274, 0x0a21c652, 0x0a21c652, 0x0a21a652, 0x0a21a652, 0x0a22a652},
+ {0x0000a278, 0x39ce739c, 0x39ce739c, 0x39ce739c, 0x39ce739c, 0x39ce739c},
+ {0x0000a27c, 0x050e039c, 0x050e039c, 0x050e039c, 0x050e039c, 0x050e039c},
+ {0x0000a394, 0x39ce739c, 0x39ce739c, 0x39ce739c, 0x39ce739c, 0x39ce739c},
+ {0x0000a398, 0x0000039c, 0x0000039c, 0x0000039c, 0x0000039c, 0x0000039c},
+ {0x0000a3dc, 0x39ce739c, 0x39ce739c, 0x39ce739c, 0x39ce739c, 0x39ce739c},
+ {0x0000a3e0, 0x0000039c, 0x0000039c, 0x0000039c, 0x0000039c, 0x0000039c},
};
static const u32 ar9285Modes_XE2_0_normal_power[][6] = {
- { 0x0000a300, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
- { 0x0000a304, 0x00000000, 0x00000000, 0x00009200, 0x00009200, 0x00000000 },
- { 0x0000a308, 0x00000000, 0x00000000, 0x00010208, 0x00010208, 0x00000000 },
- { 0x0000a30c, 0x00000000, 0x00000000, 0x00019608, 0x00019608, 0x00000000 },
- { 0x0000a310, 0x00000000, 0x00000000, 0x00022618, 0x00022618, 0x00000000 },
- { 0x0000a314, 0x00000000, 0x00000000, 0x0002a6c9, 0x0002a6c9, 0x00000000 },
- { 0x0000a318, 0x00000000, 0x00000000, 0x00031710, 0x00031710, 0x00000000 },
- { 0x0000a31c, 0x00000000, 0x00000000, 0x00035718, 0x00035718, 0x00000000 },
- { 0x0000a320, 0x00000000, 0x00000000, 0x00038758, 0x00038758, 0x00000000 },
- { 0x0000a324, 0x00000000, 0x00000000, 0x0003c75a, 0x0003c75a, 0x00000000 },
- { 0x0000a328, 0x00000000, 0x00000000, 0x0004075c, 0x0004075c, 0x00000000 },
- { 0x0000a32c, 0x00000000, 0x00000000, 0x0004475e, 0x0004475e, 0x00000000 },
- { 0x0000a330, 0x00000000, 0x00000000, 0x0004679f, 0x0004679f, 0x00000000 },
- { 0x0000a334, 0x00000000, 0x00000000, 0x000487df, 0x000487df, 0x00000000 },
- { 0x0000a338, 0x0003891e, 0x0003891e, 0x0003891e, 0x0003891e, 0x00000000 },
- { 0x0000a33c, 0x0003a95e, 0x0003a95e, 0x0003a95e, 0x0003a95e, 0x00000000 },
- { 0x0000a340, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 },
- { 0x0000a344, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 },
- { 0x0000a348, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 },
- { 0x0000a34c, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 },
- { 0x0000a350, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 },
- { 0x0000a354, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 },
- { 0x00007814, 0x92497ca8, 0x92497ca8, 0x92497ca8, 0x92497ca8, 0x92497ca8 },
- { 0x00007828, 0x4ad2491b, 0x4ad2491b, 0x2ad2491b, 0x4ad2491b, 0x4ad2491b },
- { 0x00007830, 0xedb6da6e, 0xedb6da6e, 0xedb6da6e, 0xedb6da6e, 0xedb6dbae },
- { 0x00007838, 0xdac71441, 0xdac71441, 0xdac71441, 0xdac71441, 0xdac71441 },
- { 0x0000783c, 0x2481f6fe, 0x2481f6fe, 0x2481f6fe, 0x2481f6fe, 0x2481f6fe },
- { 0x00007840, 0xba5f638c, 0xba5f638c, 0xba5f638c, 0xba5f638c, 0xba5f638c },
- { 0x0000786c, 0x48609eb4, 0x48609eb4, 0x48609eb4, 0x48609eb4, 0x48609eb4 },
- { 0x00007820, 0x00000c04, 0x00000c04, 0x00000c04, 0x00000c04, 0x00000c04 },
- { 0x0000a274, 0x0a21c652, 0x0a21c652, 0x0a21a652, 0x0a21a652, 0x0a22a652 },
- { 0x0000a278, 0x39ce739c, 0x39ce739c, 0x39ce739c, 0x39ce739c, 0x39ce739c },
- { 0x0000a27c, 0x050e039c, 0x050e039c, 0x050e039c, 0x050e039c, 0x050e039c },
- { 0x0000a394, 0x39ce739c, 0x39ce739c, 0x39ce739c, 0x39ce739c, 0x39ce739c },
- { 0x0000a398, 0x0000039c, 0x0000039c, 0x0000039c, 0x0000039c, 0x0000039c },
- { 0x0000a3dc, 0x39ce739c, 0x39ce739c, 0x39ce739c, 0x39ce739c, 0x39ce739c },
- { 0x0000a3e0, 0x0000039c, 0x0000039c, 0x0000039c, 0x0000039c, 0x0000039c },
+ {0x0000a300, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+ {0x0000a304, 0x00000000, 0x00000000, 0x00009200, 0x00009200, 0x00000000},
+ {0x0000a308, 0x00000000, 0x00000000, 0x00010208, 0x00010208, 0x00000000},
+ {0x0000a30c, 0x00000000, 0x00000000, 0x00019608, 0x00019608, 0x00000000},
+ {0x0000a310, 0x00000000, 0x00000000, 0x00022618, 0x00022618, 0x00000000},
+ {0x0000a314, 0x00000000, 0x00000000, 0x0002a6c9, 0x0002a6c9, 0x00000000},
+ {0x0000a318, 0x00000000, 0x00000000, 0x00031710, 0x00031710, 0x00000000},
+ {0x0000a31c, 0x00000000, 0x00000000, 0x00035718, 0x00035718, 0x00000000},
+ {0x0000a320, 0x00000000, 0x00000000, 0x00038758, 0x00038758, 0x00000000},
+ {0x0000a324, 0x00000000, 0x00000000, 0x0003c75a, 0x0003c75a, 0x00000000},
+ {0x0000a328, 0x00000000, 0x00000000, 0x0004075c, 0x0004075c, 0x00000000},
+ {0x0000a32c, 0x00000000, 0x00000000, 0x0004475e, 0x0004475e, 0x00000000},
+ {0x0000a330, 0x00000000, 0x00000000, 0x0004679f, 0x0004679f, 0x00000000},
+ {0x0000a334, 0x00000000, 0x00000000, 0x000487df, 0x000487df, 0x00000000},
+ {0x0000a338, 0x0003891e, 0x0003891e, 0x0003891e, 0x0003891e, 0x00000000},
+ {0x0000a33c, 0x0003a95e, 0x0003a95e, 0x0003a95e, 0x0003a95e, 0x00000000},
+ {0x0000a340, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000},
+ {0x0000a344, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000},
+ {0x0000a348, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000},
+ {0x0000a34c, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000},
+ {0x0000a350, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000},
+ {0x0000a354, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000},
+ {0x00007814, 0x92497ca8, 0x92497ca8, 0x92497ca8, 0x92497ca8, 0x92497ca8},
+ {0x00007828, 0x4ad2491b, 0x4ad2491b, 0x2ad2491b, 0x4ad2491b, 0x4ad2491b},
+ {0x00007830, 0xedb6da6e, 0xedb6da6e, 0xedb6da6e, 0xedb6da6e, 0xedb6dbae},
+ {0x00007838, 0xdac71441, 0xdac71441, 0xdac71441, 0xdac71441, 0xdac71441},
+ {0x0000783c, 0x2481f6fe, 0x2481f6fe, 0x2481f6fe, 0x2481f6fe, 0x2481f6fe},
+ {0x00007840, 0xba5f638c, 0xba5f638c, 0xba5f638c, 0xba5f638c, 0xba5f638c},
+ {0x0000786c, 0x48609eb4, 0x48609eb4, 0x48609eb4, 0x48609eb4, 0x48609eb4},
+ {0x00007820, 0x00000c04, 0x00000c04, 0x00000c04, 0x00000c04, 0x00000c04},
+ {0x0000a274, 0x0a21c652, 0x0a21c652, 0x0a21a652, 0x0a21a652, 0x0a22a652},
+ {0x0000a278, 0x39ce739c, 0x39ce739c, 0x39ce739c, 0x39ce739c, 0x39ce739c},
+ {0x0000a27c, 0x050e039c, 0x050e039c, 0x050e039c, 0x050e039c, 0x050e039c},
+ {0x0000a394, 0x39ce739c, 0x39ce739c, 0x39ce739c, 0x39ce739c, 0x39ce739c},
+ {0x0000a398, 0x0000039c, 0x0000039c, 0x0000039c, 0x0000039c, 0x0000039c},
+ {0x0000a3dc, 0x39ce739c, 0x39ce739c, 0x39ce739c, 0x39ce739c, 0x39ce739c},
+ {0x0000a3e0, 0x0000039c, 0x0000039c, 0x0000039c, 0x0000039c, 0x0000039c},
};
static const u32 ar9285Modes_XE2_0_high_power[][6] = {
- { 0x0000a300, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
- { 0x0000a304, 0x00000000, 0x00000000, 0x00006200, 0x00006200, 0x00000000 },
- { 0x0000a308, 0x00000000, 0x00000000, 0x00008201, 0x00008201, 0x00000000 },
- { 0x0000a30c, 0x00000000, 0x00000000, 0x0000b240, 0x0000b240, 0x00000000 },
- { 0x0000a310, 0x00000000, 0x00000000, 0x0000d241, 0x0000d241, 0x00000000 },
- { 0x0000a314, 0x00000000, 0x00000000, 0x0000f600, 0x0000f600, 0x00000000 },
- { 0x0000a318, 0x00000000, 0x00000000, 0x00012800, 0x00012800, 0x00000000 },
- { 0x0000a31c, 0x00000000, 0x00000000, 0x00016802, 0x00016802, 0x00000000 },
- { 0x0000a320, 0x00000000, 0x00000000, 0x0001b805, 0x0001b805, 0x00000000 },
- { 0x0000a324, 0x00000000, 0x00000000, 0x00021a80, 0x00021a80, 0x00000000 },
- { 0x0000a328, 0x00000000, 0x00000000, 0x00028b00, 0x00028b00, 0x00000000 },
- { 0x0000a32c, 0x00000000, 0x00000000, 0x0002ab40, 0x0002ab40, 0x00000000 },
- { 0x0000a330, 0x00000000, 0x00000000, 0x0002cd80, 0x0002cd80, 0x00000000 },
- { 0x0000a334, 0x00000000, 0x00000000, 0x00033d82, 0x00033d82, 0x00000000 },
- { 0x0000a338, 0x0003891e, 0x0003891e, 0x0003891e, 0x0003891e, 0x00000000 },
- { 0x0000a33c, 0x0003a95e, 0x0003a95e, 0x0003a95e, 0x0003a95e, 0x00000000 },
- { 0x0000a340, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 },
- { 0x0000a344, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 },
- { 0x0000a348, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 },
- { 0x0000a34c, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 },
- { 0x0000a350, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 },
- { 0x0000a354, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 },
- { 0x00007814, 0x92497ca8, 0x92497ca8, 0x92497ca8, 0x92497ca8, 0x92497ca8 },
- { 0x00007828, 0x4ad2491b, 0x4ad2491b, 0x2ad2491b, 0x4ad2491b, 0x4ad2491b },
- { 0x00007830, 0xedb6da6e, 0xedb6da6e, 0xedb6da6e, 0xedb6da6e, 0xedb6da6e },
- { 0x00007838, 0xdac71443, 0xdac71443, 0xdac71443, 0xdac71443, 0xdac71443 },
- { 0x0000783c, 0x2481f6fe, 0x2481f6fe, 0x2481f6fe, 0x2481f6fe, 0x2481f6fe },
- { 0x00007840, 0xba5f638c, 0xba5f638c, 0xba5f638c, 0xba5f638c, 0xba5f638c },
- { 0x0000786c, 0x08609ebe, 0x08609ebe, 0x08609ebe, 0x08609ebe, 0x08609ebe },
- { 0x00007820, 0x00000c00, 0x00000c00, 0x00000c00, 0x00000c00, 0x00000c00 },
- { 0x0000a274, 0x0a22a652, 0x0a22a652, 0x0a216652, 0x0a216652, 0x0a22a652 },
- { 0x0000a278, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7 },
- { 0x0000a27c, 0x050380e7, 0x050380e7, 0x050380e7, 0x050380e7, 0x050380e7 },
- { 0x0000a394, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7 },
- { 0x0000a398, 0x000000e7, 0x000000e7, 0x000000e7, 0x000000e7, 0x000000e7 },
- { 0x0000a3dc, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7 },
- { 0x0000a3e0, 0x000000e7, 0x000000e7, 0x000000e7, 0x000000e7, 0x000000e7 },
+ {0x0000a300, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+ {0x0000a304, 0x00000000, 0x00000000, 0x00006200, 0x00006200, 0x00000000},
+ {0x0000a308, 0x00000000, 0x00000000, 0x00008201, 0x00008201, 0x00000000},
+ {0x0000a30c, 0x00000000, 0x00000000, 0x0000b240, 0x0000b240, 0x00000000},
+ {0x0000a310, 0x00000000, 0x00000000, 0x0000d241, 0x0000d241, 0x00000000},
+ {0x0000a314, 0x00000000, 0x00000000, 0x0000f600, 0x0000f600, 0x00000000},
+ {0x0000a318, 0x00000000, 0x00000000, 0x00012800, 0x00012800, 0x00000000},
+ {0x0000a31c, 0x00000000, 0x00000000, 0x00016802, 0x00016802, 0x00000000},
+ {0x0000a320, 0x00000000, 0x00000000, 0x0001b805, 0x0001b805, 0x00000000},
+ {0x0000a324, 0x00000000, 0x00000000, 0x00021a80, 0x00021a80, 0x00000000},
+ {0x0000a328, 0x00000000, 0x00000000, 0x00028b00, 0x00028b00, 0x00000000},
+ {0x0000a32c, 0x00000000, 0x00000000, 0x0002ab40, 0x0002ab40, 0x00000000},
+ {0x0000a330, 0x00000000, 0x00000000, 0x0002cd80, 0x0002cd80, 0x00000000},
+ {0x0000a334, 0x00000000, 0x00000000, 0x00033d82, 0x00033d82, 0x00000000},
+ {0x0000a338, 0x0003891e, 0x0003891e, 0x0003891e, 0x0003891e, 0x00000000},
+ {0x0000a33c, 0x0003a95e, 0x0003a95e, 0x0003a95e, 0x0003a95e, 0x00000000},
+ {0x0000a340, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000},
+ {0x0000a344, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000},
+ {0x0000a348, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000},
+ {0x0000a34c, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000},
+ {0x0000a350, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000},
+ {0x0000a354, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000},
+ {0x00007814, 0x92497ca8, 0x92497ca8, 0x92497ca8, 0x92497ca8, 0x92497ca8},
+ {0x00007828, 0x4ad2491b, 0x4ad2491b, 0x2ad2491b, 0x4ad2491b, 0x4ad2491b},
+ {0x00007830, 0xedb6da6e, 0xedb6da6e, 0xedb6da6e, 0xedb6da6e, 0xedb6da6e},
+ {0x00007838, 0xdac71443, 0xdac71443, 0xdac71443, 0xdac71443, 0xdac71443},
+ {0x0000783c, 0x2481f6fe, 0x2481f6fe, 0x2481f6fe, 0x2481f6fe, 0x2481f6fe},
+ {0x00007840, 0xba5f638c, 0xba5f638c, 0xba5f638c, 0xba5f638c, 0xba5f638c},
+ {0x0000786c, 0x08609ebe, 0x08609ebe, 0x08609ebe, 0x08609ebe, 0x08609ebe},
+ {0x00007820, 0x00000c00, 0x00000c00, 0x00000c00, 0x00000c00, 0x00000c00},
+ {0x0000a274, 0x0a22a652, 0x0a22a652, 0x0a216652, 0x0a216652, 0x0a22a652},
+ {0x0000a278, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7},
+ {0x0000a27c, 0x050380e7, 0x050380e7, 0x050380e7, 0x050380e7, 0x050380e7},
+ {0x0000a394, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7},
+ {0x0000a398, 0x000000e7, 0x000000e7, 0x000000e7, 0x000000e7, 0x000000e7},
+ {0x0000a3dc, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7},
+ {0x0000a3e0, 0x000000e7, 0x000000e7, 0x000000e7, 0x000000e7, 0x000000e7},
};
static const u32 ar9285PciePhy_clkreq_always_on_L1_9285_1_2[][2] = {
- {0x00004040, 0x9248fd00 },
- {0x00004040, 0x24924924 },
- {0x00004040, 0xa8000019 },
- {0x00004040, 0x13160820 },
- {0x00004040, 0xe5980560 },
- {0x00004040, 0xc01dcffd },
- {0x00004040, 0x1aaabe41 },
- {0x00004040, 0xbe105554 },
- {0x00004040, 0x00043007 },
- {0x00004044, 0x00000000 },
+ /* Addr allmodes */
+ {0x00004040, 0x9248fd00},
+ {0x00004040, 0x24924924},
+ {0x00004040, 0xa8000019},
+ {0x00004040, 0x13160820},
+ {0x00004040, 0xe5980560},
+ {0x00004040, 0xc01dcffd},
+ {0x00004040, 0x1aaabe41},
+ {0x00004040, 0xbe105554},
+ {0x00004040, 0x00043007},
+ {0x00004044, 0x00000000},
};
static const u32 ar9285PciePhy_clkreq_off_L1_9285_1_2[][2] = {
- {0x00004040, 0x9248fd00 },
- {0x00004040, 0x24924924 },
- {0x00004040, 0xa8000019 },
- {0x00004040, 0x13160820 },
- {0x00004040, 0xe5980560 },
- {0x00004040, 0xc01dcffc },
- {0x00004040, 0x1aaabe41 },
- {0x00004040, 0xbe105554 },
- {0x00004040, 0x00043007 },
- {0x00004044, 0x00000000 },
-};
-
-/* AR9287 Revision 10 */
-static const u32 ar9287Modes_9287_1_0[][6] = {
- /* Address 5G-HT20 5G-HT40 2G-HT40 2G-HT20 Turbo */
- { 0x00001030, 0x00000000, 0x00000000, 0x000002c0, 0x00000160, 0x000001e0 },
- { 0x00001070, 0x00000000, 0x00000000, 0x00000318, 0x0000018c, 0x000001e0 },
- { 0x000010b0, 0x00000000, 0x00000000, 0x00007c70, 0x00003e38, 0x00001180 },
- { 0x000010f0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000008 },
- { 0x00008014, 0x00000000, 0x00000000, 0x10801600, 0x08400b00, 0x06e006e0 },
- { 0x0000801c, 0x00000000, 0x00000000, 0x12e00057, 0x12e0002b, 0x0988004f },
- { 0x00008120, 0x08f04800, 0x08f04800, 0x08f04810, 0x08f04810, 0x08f04810 },
- { 0x000081d0, 0x00003200, 0x00003200, 0x0000320a, 0x0000320a, 0x0000320a },
- { 0x00008318, 0x00000000, 0x00000000, 0x00006880, 0x00003440, 0x00006880 },
- { 0x00009804, 0x00000000, 0x00000000, 0x000003c4, 0x00000300, 0x00000303 },
- { 0x00009820, 0x00000000, 0x00000000, 0x02020200, 0x02020200, 0x02020200 },
- { 0x00009824, 0x00000000, 0x00000000, 0x01000e0e, 0x01000e0e, 0x01000e0e },
- { 0x00009828, 0x00000000, 0x00000000, 0x0a020001, 0x0a020001, 0x0a020001 },
- { 0x00009834, 0x00000000, 0x00000000, 0x00000e0e, 0x00000e0e, 0x00000e0e },
- { 0x00009838, 0x00000003, 0x00000003, 0x00000007, 0x00000007, 0x00000007 },
- { 0x00009840, 0x206a002e, 0x206a002e, 0x206a012e, 0x206a012e, 0x206a012e },
- { 0x00009844, 0x03720000, 0x03720000, 0x037216a0, 0x037216a0, 0x037216a0 },
- { 0x00009850, 0x60000000, 0x60000000, 0x6d4000e2, 0x6c4000e2, 0x6c4000e2 },
- { 0x00009858, 0x7c000d00, 0x7c000d00, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e },
- { 0x0000985c, 0x3100005e, 0x3100005e, 0x3139605e, 0x31395d5e, 0x31395d5e },
- { 0x00009860, 0x00058d00, 0x00058d00, 0x00058d20, 0x00058d20, 0x00058d18 },
- { 0x00009864, 0x00000e00, 0x00000e00, 0x0001ce00, 0x0001ce00, 0x0001ce00 },
- { 0x00009868, 0x000040c0, 0x000040c0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0 },
- { 0x0000986c, 0x00000080, 0x00000080, 0x06903881, 0x06903881, 0x06903881 },
- { 0x00009914, 0x00000000, 0x00000000, 0x00001130, 0x00000898, 0x000007d0 },
- { 0x00009918, 0x00000000, 0x00000000, 0x00000016, 0x0000000b, 0x00000016 },
- { 0x00009924, 0xd00a8a01, 0xd00a8a01, 0xd00a8a0d, 0xd00a8a0d, 0xd00a8a0d },
- { 0x00009944, 0xefbc0000, 0xefbc0000, 0xefbc1010, 0xefbc1010, 0xefbc1010 },
- { 0x00009960, 0x00000000, 0x00000000, 0x00000010, 0x00000010, 0x00000010 },
- { 0x0000a960, 0x00000000, 0x00000000, 0x00000010, 0x00000010, 0x00000010 },
- { 0x00009964, 0x00000000, 0x00000000, 0x00000210, 0x00000210, 0x00000210 },
- { 0x0000c968, 0x00000200, 0x00000200, 0x000003ce, 0x000003ce, 0x000003ce },
- { 0x000099b8, 0x00000000, 0x00000000, 0x0000001c, 0x0000001c, 0x0000001c },
- { 0x000099bc, 0x00000000, 0x00000000, 0x00000c00, 0x00000c00, 0x00000c00 },
- { 0x000099c0, 0x00000000, 0x00000000, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4 },
- { 0x0000a204, 0x00000440, 0x00000440, 0x00000444, 0x00000444, 0x00000444 },
- { 0x0000a20c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
- { 0x0000b20c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
- { 0x0000a21c, 0x1803800a, 0x1803800a, 0x1883800a, 0x1883800a, 0x1883800a },
- { 0x0000a230, 0x00000000, 0x00000000, 0x00000210, 0x00000108, 0x00000000 },
- { 0x0000a250, 0x00000000, 0x00000000, 0x0004a000, 0x0004a000, 0x0004a000 },
- { 0x0000a358, 0x7999aa02, 0x7999aa02, 0x7999aa0e, 0x7999aa0e, 0x7999aa0e },
- { 0x0000a3d8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
-};
-
-static const u32 ar9287Common_9287_1_0[][2] = {
- { 0x0000000c, 0x00000000 },
- { 0x00000030, 0x00020015 },
- { 0x00000034, 0x00000005 },
- { 0x00000040, 0x00000000 },
- { 0x00000044, 0x00000008 },
- { 0x00000048, 0x00000008 },
- { 0x0000004c, 0x00000010 },
- { 0x00000050, 0x00000000 },
- { 0x00000054, 0x0000001f },
- { 0x00000800, 0x00000000 },
- { 0x00000804, 0x00000000 },
- { 0x00000808, 0x00000000 },
- { 0x0000080c, 0x00000000 },
- { 0x00000810, 0x00000000 },
- { 0x00000814, 0x00000000 },
- { 0x00000818, 0x00000000 },
- { 0x0000081c, 0x00000000 },
- { 0x00000820, 0x00000000 },
- { 0x00000824, 0x00000000 },
- { 0x00001040, 0x002ffc0f },
- { 0x00001044, 0x002ffc0f },
- { 0x00001048, 0x002ffc0f },
- { 0x0000104c, 0x002ffc0f },
- { 0x00001050, 0x002ffc0f },
- { 0x00001054, 0x002ffc0f },
- { 0x00001058, 0x002ffc0f },
- { 0x0000105c, 0x002ffc0f },
- { 0x00001060, 0x002ffc0f },
- { 0x00001064, 0x002ffc0f },
- { 0x00001230, 0x00000000 },
- { 0x00001270, 0x00000000 },
- { 0x00001038, 0x00000000 },
- { 0x00001078, 0x00000000 },
- { 0x000010b8, 0x00000000 },
- { 0x000010f8, 0x00000000 },
- { 0x00001138, 0x00000000 },
- { 0x00001178, 0x00000000 },
- { 0x000011b8, 0x00000000 },
- { 0x000011f8, 0x00000000 },
- { 0x00001238, 0x00000000 },
- { 0x00001278, 0x00000000 },
- { 0x000012b8, 0x00000000 },
- { 0x000012f8, 0x00000000 },
- { 0x00001338, 0x00000000 },
- { 0x00001378, 0x00000000 },
- { 0x000013b8, 0x00000000 },
- { 0x000013f8, 0x00000000 },
- { 0x00001438, 0x00000000 },
- { 0x00001478, 0x00000000 },
- { 0x000014b8, 0x00000000 },
- { 0x000014f8, 0x00000000 },
- { 0x00001538, 0x00000000 },
- { 0x00001578, 0x00000000 },
- { 0x000015b8, 0x00000000 },
- { 0x000015f8, 0x00000000 },
- { 0x00001638, 0x00000000 },
- { 0x00001678, 0x00000000 },
- { 0x000016b8, 0x00000000 },
- { 0x000016f8, 0x00000000 },
- { 0x00001738, 0x00000000 },
- { 0x00001778, 0x00000000 },
- { 0x000017b8, 0x00000000 },
- { 0x000017f8, 0x00000000 },
- { 0x0000103c, 0x00000000 },
- { 0x0000107c, 0x00000000 },
- { 0x000010bc, 0x00000000 },
- { 0x000010fc, 0x00000000 },
- { 0x0000113c, 0x00000000 },
- { 0x0000117c, 0x00000000 },
- { 0x000011bc, 0x00000000 },
- { 0x000011fc, 0x00000000 },
- { 0x0000123c, 0x00000000 },
- { 0x0000127c, 0x00000000 },
- { 0x000012bc, 0x00000000 },
- { 0x000012fc, 0x00000000 },
- { 0x0000133c, 0x00000000 },
- { 0x0000137c, 0x00000000 },
- { 0x000013bc, 0x00000000 },
- { 0x000013fc, 0x00000000 },
- { 0x0000143c, 0x00000000 },
- { 0x0000147c, 0x00000000 },
- { 0x00004030, 0x00000002 },
- { 0x0000403c, 0x00000002 },
- { 0x00004024, 0x0000001f },
- { 0x00004060, 0x00000000 },
- { 0x00004064, 0x00000000 },
- { 0x00007010, 0x00000033 },
- { 0x00007020, 0x00000000 },
- { 0x00007034, 0x00000002 },
- { 0x00007038, 0x000004c2 },
- { 0x00008004, 0x00000000 },
- { 0x00008008, 0x00000000 },
- { 0x0000800c, 0x00000000 },
- { 0x00008018, 0x00000700 },
- { 0x00008020, 0x00000000 },
- { 0x00008038, 0x00000000 },
- { 0x0000803c, 0x00000000 },
- { 0x00008048, 0x40000000 },
- { 0x00008054, 0x00000000 },
- { 0x00008058, 0x00000000 },
- { 0x0000805c, 0x000fc78f },
- { 0x00008060, 0x0000000f },
- { 0x00008064, 0x00000000 },
- { 0x00008070, 0x00000000 },
- { 0x000080c0, 0x2a80001a },
- { 0x000080c4, 0x05dc01e0 },
- { 0x000080c8, 0x1f402710 },
- { 0x000080cc, 0x01f40000 },
- { 0x000080d0, 0x00001e00 },
- { 0x000080d4, 0x00000000 },
- { 0x000080d8, 0x00400000 },
- { 0x000080e0, 0xffffffff },
- { 0x000080e4, 0x0000ffff },
- { 0x000080e8, 0x003f3f3f },
- { 0x000080ec, 0x00000000 },
- { 0x000080f0, 0x00000000 },
- { 0x000080f4, 0x00000000 },
- { 0x000080f8, 0x00000000 },
- { 0x000080fc, 0x00020000 },
- { 0x00008100, 0x00020000 },
- { 0x00008104, 0x00000001 },
- { 0x00008108, 0x00000052 },
- { 0x0000810c, 0x00000000 },
- { 0x00008110, 0x00000168 },
- { 0x00008118, 0x000100aa },
- { 0x0000811c, 0x00003210 },
- { 0x00008124, 0x00000000 },
- { 0x00008128, 0x00000000 },
- { 0x0000812c, 0x00000000 },
- { 0x00008130, 0x00000000 },
- { 0x00008134, 0x00000000 },
- { 0x00008138, 0x00000000 },
- { 0x0000813c, 0x00000000 },
- { 0x00008144, 0xffffffff },
- { 0x00008168, 0x00000000 },
- { 0x0000816c, 0x00000000 },
- { 0x00008170, 0x18487320 },
- { 0x00008174, 0xfaa4fa50 },
- { 0x00008178, 0x00000100 },
- { 0x0000817c, 0x00000000 },
- { 0x000081c0, 0x00000000 },
- { 0x000081c4, 0x00000000 },
- { 0x000081d4, 0x00000000 },
- { 0x000081ec, 0x00000000 },
- { 0x000081f0, 0x00000000 },
- { 0x000081f4, 0x00000000 },
- { 0x000081f8, 0x00000000 },
- { 0x000081fc, 0x00000000 },
- { 0x00008200, 0x00000000 },
- { 0x00008204, 0x00000000 },
- { 0x00008208, 0x00000000 },
- { 0x0000820c, 0x00000000 },
- { 0x00008210, 0x00000000 },
- { 0x00008214, 0x00000000 },
- { 0x00008218, 0x00000000 },
- { 0x0000821c, 0x00000000 },
- { 0x00008220, 0x00000000 },
- { 0x00008224, 0x00000000 },
- { 0x00008228, 0x00000000 },
- { 0x0000822c, 0x00000000 },
- { 0x00008230, 0x00000000 },
- { 0x00008234, 0x00000000 },
- { 0x00008238, 0x00000000 },
- { 0x0000823c, 0x00000000 },
- { 0x00008240, 0x00100000 },
- { 0x00008244, 0x0010f400 },
- { 0x00008248, 0x00000100 },
- { 0x0000824c, 0x0001e800 },
- { 0x00008250, 0x00000000 },
- { 0x00008254, 0x00000000 },
- { 0x00008258, 0x00000000 },
- { 0x0000825c, 0x400000ff },
- { 0x00008260, 0x00080922 },
- { 0x00008264, 0x88a00010 },
- { 0x00008270, 0x00000000 },
- { 0x00008274, 0x40000000 },
- { 0x00008278, 0x003e4180 },
- { 0x0000827c, 0x00000000 },
- { 0x00008284, 0x0000002c },
- { 0x00008288, 0x0000002c },
- { 0x0000828c, 0x000000ff },
- { 0x00008294, 0x00000000 },
- { 0x00008298, 0x00000000 },
- { 0x0000829c, 0x00000000 },
- { 0x00008300, 0x00000040 },
- { 0x00008314, 0x00000000 },
- { 0x00008328, 0x00000000 },
- { 0x0000832c, 0x00000007 },
- { 0x00008330, 0x00000302 },
- { 0x00008334, 0x00000e00 },
- { 0x00008338, 0x00ff0000 },
- { 0x0000833c, 0x00000000 },
- { 0x00008340, 0x000107ff },
- { 0x00008344, 0x01c81043 },
- { 0x00008360, 0xffffffff },
- { 0x00008364, 0xffffffff },
- { 0x00008368, 0x00000000 },
- { 0x00008370, 0x00000000 },
- { 0x00008374, 0x000000ff },
- { 0x00008378, 0x00000000 },
- { 0x0000837c, 0x00000000 },
- { 0x00008380, 0xffffffff },
- { 0x00008384, 0xffffffff },
- { 0x00008390, 0x0fffffff },
- { 0x00008394, 0x0fffffff },
- { 0x00008398, 0x00000000 },
- { 0x0000839c, 0x00000000 },
- { 0x000083a0, 0x00000000 },
- { 0x00009808, 0x00000000 },
- { 0x0000980c, 0xafe68e30 },
- { 0x00009810, 0xfd14e000 },
- { 0x00009814, 0x9c0a9f6b },
- { 0x0000981c, 0x00000000 },
- { 0x0000982c, 0x0000a000 },
- { 0x00009830, 0x00000000 },
- { 0x0000983c, 0x00200400 },
- { 0x0000984c, 0x0040233c },
- { 0x0000a84c, 0x0040233c },
- { 0x00009854, 0x00000044 },
- { 0x00009900, 0x00000000 },
- { 0x00009904, 0x00000000 },
- { 0x00009908, 0x00000000 },
- { 0x0000990c, 0x00000000 },
- { 0x00009910, 0x10002310 },
- { 0x0000991c, 0x10000fff },
- { 0x00009920, 0x04900000 },
- { 0x0000a920, 0x04900000 },
- { 0x00009928, 0x00000001 },
- { 0x0000992c, 0x00000004 },
- { 0x00009930, 0x00000000 },
- { 0x0000a930, 0x00000000 },
- { 0x00009934, 0x1e1f2022 },
- { 0x00009938, 0x0a0b0c0d },
- { 0x0000993c, 0x00000000 },
- { 0x00009948, 0x9280c00a },
- { 0x0000994c, 0x00020028 },
- { 0x00009954, 0x5f3ca3de },
- { 0x00009958, 0x0108ecff },
- { 0x00009940, 0x14750604 },
- { 0x0000c95c, 0x004b6a8e },
- { 0x00009970, 0x990bb515 },
- { 0x00009974, 0x00000000 },
- { 0x00009978, 0x00000001 },
- { 0x0000997c, 0x00000000 },
- { 0x000099a0, 0x00000000 },
- { 0x000099a4, 0x00000001 },
- { 0x000099a8, 0x201fff00 },
- { 0x000099ac, 0x0c6f0000 },
- { 0x000099b0, 0x03051000 },
- { 0x000099b4, 0x00000820 },
- { 0x000099c4, 0x06336f77 },
- { 0x000099c8, 0x6af65329 },
- { 0x000099cc, 0x08f186c8 },
- { 0x000099d0, 0x00046384 },
- { 0x000099dc, 0x00000000 },
- { 0x000099e0, 0x00000000 },
- { 0x000099e4, 0xaaaaaaaa },
- { 0x000099e8, 0x3c466478 },
- { 0x000099ec, 0x0cc80caa },
- { 0x000099f0, 0x00000000 },
- { 0x000099fc, 0x00001042 },
- { 0x0000a1f4, 0x00fffeff },
- { 0x0000a1f8, 0x00f5f9ff },
- { 0x0000a1fc, 0xb79f6427 },
- { 0x0000a208, 0x803e4788 },
- { 0x0000a210, 0x4080a333 },
- { 0x0000a214, 0x40206c10 },
- { 0x0000a218, 0x009c4060 },
- { 0x0000a220, 0x01834061 },
- { 0x0000a224, 0x00000400 },
- { 0x0000a228, 0x000003b5 },
- { 0x0000a22c, 0x233f7180 },
- { 0x0000a234, 0x20202020 },
- { 0x0000a238, 0x20202020 },
- { 0x0000a23c, 0x13c889af },
- { 0x0000a240, 0x38490a20 },
- { 0x0000a244, 0x00000000 },
- { 0x0000a248, 0xfffffffc },
- { 0x0000a24c, 0x00000000 },
- { 0x0000a254, 0x00000000 },
- { 0x0000a258, 0x0cdbd380 },
- { 0x0000a25c, 0x0f0f0f01 },
- { 0x0000a260, 0xdfa91f01 },
- { 0x0000a264, 0x00418a11 },
- { 0x0000b264, 0x00418a11 },
- { 0x0000a268, 0x00000000 },
- { 0x0000a26c, 0x0e79e5c6 },
- { 0x0000b26c, 0x0e79e5c6 },
- { 0x0000d270, 0x00820820 },
- { 0x0000a278, 0x1ce739ce },
- { 0x0000a27c, 0x050701ce },
- { 0x0000d35c, 0x07ffffef },
- { 0x0000d360, 0x0fffffe7 },
- { 0x0000d364, 0x17ffffe5 },
- { 0x0000d368, 0x1fffffe4 },
- { 0x0000d36c, 0x37ffffe3 },
- { 0x0000d370, 0x3fffffe3 },
- { 0x0000d374, 0x57ffffe3 },
- { 0x0000d378, 0x5fffffe2 },
- { 0x0000d37c, 0x7fffffe2 },
- { 0x0000d380, 0x7f3c7bba },
- { 0x0000d384, 0xf3307ff0 },
- { 0x0000a388, 0x0c000000 },
- { 0x0000a38c, 0x20202020 },
- { 0x0000a390, 0x20202020 },
- { 0x0000a394, 0x1ce739ce },
- { 0x0000a398, 0x000001ce },
- { 0x0000b398, 0x000001ce },
- { 0x0000a39c, 0x00000001 },
- { 0x0000a3c8, 0x00000246 },
- { 0x0000a3cc, 0x20202020 },
- { 0x0000a3d0, 0x20202020 },
- { 0x0000a3d4, 0x20202020 },
- { 0x0000a3dc, 0x1ce739ce },
- { 0x0000a3e0, 0x000001ce },
- { 0x0000a3e4, 0x00000000 },
- { 0x0000a3e8, 0x18c43433 },
- { 0x0000a3ec, 0x00f70081 },
- { 0x0000a3f0, 0x01036a1e },
- { 0x0000a3f4, 0x00000000 },
- { 0x0000b3f4, 0x00000000 },
- { 0x0000a7d8, 0x00000001 },
- { 0x00007800, 0x00000800 },
- { 0x00007804, 0x6c35ffb0 },
- { 0x00007808, 0x6db6c000 },
- { 0x0000780c, 0x6db6cb30 },
- { 0x00007810, 0x6db6cb6c },
- { 0x00007814, 0x0501e200 },
- { 0x00007818, 0x0094128d },
- { 0x0000781c, 0x976ee392 },
- { 0x00007820, 0xf75ff6fc },
- { 0x00007824, 0x00040000 },
- { 0x00007828, 0xdb003012 },
- { 0x0000782c, 0x04924914 },
- { 0x00007830, 0x21084210 },
- { 0x00007834, 0x00140000 },
- { 0x00007838, 0x0e4548d8 },
- { 0x0000783c, 0x54214514 },
- { 0x00007840, 0x02025820 },
- { 0x00007844, 0x71c0d388 },
- { 0x00007848, 0x934934a8 },
- { 0x00007850, 0x00000000 },
- { 0x00007854, 0x00000800 },
- { 0x00007858, 0x6c35ffb0 },
- { 0x0000785c, 0x6db6c000 },
- { 0x00007860, 0x6db6cb2c },
- { 0x00007864, 0x6db6cb6c },
- { 0x00007868, 0x0501e200 },
- { 0x0000786c, 0x0094128d },
- { 0x00007870, 0x976ee392 },
- { 0x00007874, 0xf75ff6fc },
- { 0x00007878, 0x00040000 },
- { 0x0000787c, 0xdb003012 },
- { 0x00007880, 0x04924914 },
- { 0x00007884, 0x21084210 },
- { 0x00007888, 0x001b6db0 },
- { 0x0000788c, 0x00376b63 },
- { 0x00007890, 0x06db6db6 },
- { 0x00007894, 0x006d8000 },
- { 0x00007898, 0x48100000 },
- { 0x0000789c, 0x00000000 },
- { 0x000078a0, 0x08000000 },
- { 0x000078a4, 0x0007ffd8 },
- { 0x000078a8, 0x0007ffd8 },
- { 0x000078ac, 0x001c0020 },
- { 0x000078b0, 0x000611eb },
- { 0x000078b4, 0x40008080 },
- { 0x000078b8, 0x2a850160 },
+ /* Addr allmodes */
+ {0x00004040, 0x9248fd00},
+ {0x00004040, 0x24924924},
+ {0x00004040, 0xa8000019},
+ {0x00004040, 0x13160820},
+ {0x00004040, 0xe5980560},
+ {0x00004040, 0xc01dcffc},
+ {0x00004040, 0x1aaabe41},
+ {0x00004040, 0xbe105554},
+ {0x00004040, 0x00043007},
+ {0x00004044, 0x00000000},
};
-static const u32 ar9287Modes_tx_gain_9287_1_0[][6] = {
- /* Address 5G-HT20 5G-HT40 2G-HT40 2G-HT20 Turbo */
- { 0x0000a300, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
- { 0x0000a304, 0x00000000, 0x00000000, 0x00004002, 0x00004002, 0x00004002 },
- { 0x0000a308, 0x00000000, 0x00000000, 0x00008004, 0x00008004, 0x00008004 },
- { 0x0000a30c, 0x00000000, 0x00000000, 0x0000c00a, 0x0000c00a, 0x0000c00a },
- { 0x0000a310, 0x00000000, 0x00000000, 0x0001000c, 0x0001000c, 0x0001000c },
- { 0x0000a314, 0x00000000, 0x00000000, 0x0001420b, 0x0001420b, 0x0001420b },
- { 0x0000a318, 0x00000000, 0x00000000, 0x0001824a, 0x0001824a, 0x0001824a },
- { 0x0000a31c, 0x00000000, 0x00000000, 0x0001c44a, 0x0001c44a, 0x0001c44a },
- { 0x0000a320, 0x00000000, 0x00000000, 0x0002064a, 0x0002064a, 0x0002064a },
- { 0x0000a324, 0x00000000, 0x00000000, 0x0002484a, 0x0002484a, 0x0002484a },
- { 0x0000a328, 0x00000000, 0x00000000, 0x00028a4a, 0x00028a4a, 0x00028a4a },
- { 0x0000a32c, 0x00000000, 0x00000000, 0x0002cc4a, 0x0002cc4a, 0x0002cc4a },
- { 0x0000a330, 0x00000000, 0x00000000, 0x00030e4a, 0x00030e4a, 0x00030e4a },
- { 0x0000a334, 0x00000000, 0x00000000, 0x00034e8a, 0x00034e8a, 0x00034e8a },
- { 0x0000a338, 0x00000000, 0x00000000, 0x00038e8c, 0x00038e8c, 0x00038e8c },
- { 0x0000a33c, 0x00000000, 0x00000000, 0x0003cecc, 0x0003cecc, 0x0003cecc },
- { 0x0000a340, 0x00000000, 0x00000000, 0x00040ed4, 0x00040ed4, 0x00040ed4 },
- { 0x0000a344, 0x00000000, 0x00000000, 0x00044edc, 0x00044edc, 0x00044edc },
- { 0x0000a348, 0x00000000, 0x00000000, 0x00048ede, 0x00048ede, 0x00048ede },
- { 0x0000a34c, 0x00000000, 0x00000000, 0x0004cf1e, 0x0004cf1e, 0x0004cf1e },
- { 0x0000a350, 0x00000000, 0x00000000, 0x00050f5e, 0x00050f5e, 0x00050f5e },
- { 0x0000a354, 0x00000000, 0x00000000, 0x00054f9e, 0x00054f9e, 0x00054f9e },
- { 0x0000a780, 0x00000000, 0x00000000, 0x00000060, 0x00000060, 0x00000060 },
- { 0x0000a784, 0x00000000, 0x00000000, 0x00004062, 0x00004062, 0x00004062 },
- { 0x0000a788, 0x00000000, 0x00000000, 0x00008064, 0x00008064, 0x00008064 },
- { 0x0000a78c, 0x00000000, 0x00000000, 0x0000c0a4, 0x0000c0a4, 0x0000c0a4 },
- { 0x0000a790, 0x00000000, 0x00000000, 0x000100b0, 0x000100b0, 0x000100b0 },
- { 0x0000a794, 0x00000000, 0x00000000, 0x000140b2, 0x000140b2, 0x000140b2 },
- { 0x0000a798, 0x00000000, 0x00000000, 0x000180b4, 0x000180b4, 0x000180b4 },
- { 0x0000a79c, 0x00000000, 0x00000000, 0x0001c0f4, 0x0001c0f4, 0x0001c0f4 },
- { 0x0000a7a0, 0x00000000, 0x00000000, 0x00020134, 0x00020134, 0x00020134 },
- { 0x0000a7a4, 0x00000000, 0x00000000, 0x000240fe, 0x000240fe, 0x000240fe },
- { 0x0000a7a8, 0x00000000, 0x00000000, 0x0002813e, 0x0002813e, 0x0002813e },
- { 0x0000a7ac, 0x00000000, 0x00000000, 0x0002c17e, 0x0002c17e, 0x0002c17e },
- { 0x0000a7b0, 0x00000000, 0x00000000, 0x000301be, 0x000301be, 0x000301be },
- { 0x0000a7b4, 0x00000000, 0x00000000, 0x000341fe, 0x000341fe, 0x000341fe },
- { 0x0000a7b8, 0x00000000, 0x00000000, 0x000341fe, 0x000341fe, 0x000341fe },
- { 0x0000a7bc, 0x00000000, 0x00000000, 0x000341fe, 0x000341fe, 0x000341fe },
- { 0x0000a7c0, 0x00000000, 0x00000000, 0x000341fe, 0x000341fe, 0x000341fe },
- { 0x0000a7c4, 0x00000000, 0x00000000, 0x000341fe, 0x000341fe, 0x000341fe },
- { 0x0000a7c8, 0x00000000, 0x00000000, 0x000341fe, 0x000341fe, 0x000341fe },
- { 0x0000a7cc, 0x00000000, 0x00000000, 0x000341fe, 0x000341fe, 0x000341fe },
- { 0x0000a7d0, 0x00000000, 0x00000000, 0x000341fe, 0x000341fe, 0x000341fe },
- { 0x0000a7d4, 0x00000000, 0x00000000, 0x000341fe, 0x000341fe, 0x000341fe },
- { 0x0000a274, 0x0a180000, 0x0a180000, 0x0a1aa000, 0x0a1aa000, 0x0a1aa000 },
-};
-
-
-static const u32 ar9287Modes_rx_gain_9287_1_0[][6] = {
- /* Address 5G-HT20 5G-HT40 2G-HT40 2G-HT20 Turbo */
- { 0x00009a00, 0x00000000, 0x00000000, 0x0000a120, 0x0000a120, 0x0000a120 },
- { 0x00009a04, 0x00000000, 0x00000000, 0x0000a124, 0x0000a124, 0x0000a124 },
- { 0x00009a08, 0x00000000, 0x00000000, 0x0000a128, 0x0000a128, 0x0000a128 },
- { 0x00009a0c, 0x00000000, 0x00000000, 0x0000a12c, 0x0000a12c, 0x0000a12c },
- { 0x00009a10, 0x00000000, 0x00000000, 0x0000a130, 0x0000a130, 0x0000a130 },
- { 0x00009a14, 0x00000000, 0x00000000, 0x0000a194, 0x0000a194, 0x0000a194 },
- { 0x00009a18, 0x00000000, 0x00000000, 0x0000a198, 0x0000a198, 0x0000a198 },
- { 0x00009a1c, 0x00000000, 0x00000000, 0x0000a20c, 0x0000a20c, 0x0000a20c },
- { 0x00009a20, 0x00000000, 0x00000000, 0x0000a210, 0x0000a210, 0x0000a210 },
- { 0x00009a24, 0x00000000, 0x00000000, 0x0000a284, 0x0000a284, 0x0000a284 },
- { 0x00009a28, 0x00000000, 0x00000000, 0x0000a288, 0x0000a288, 0x0000a288 },
- { 0x00009a2c, 0x00000000, 0x00000000, 0x0000a28c, 0x0000a28c, 0x0000a28c },
- { 0x00009a30, 0x00000000, 0x00000000, 0x0000a290, 0x0000a290, 0x0000a290 },
- { 0x00009a34, 0x00000000, 0x00000000, 0x0000a294, 0x0000a294, 0x0000a294 },
- { 0x00009a38, 0x00000000, 0x00000000, 0x0000a2a0, 0x0000a2a0, 0x0000a2a0 },
- { 0x00009a3c, 0x00000000, 0x00000000, 0x0000a2a4, 0x0000a2a4, 0x0000a2a4 },
- { 0x00009a40, 0x00000000, 0x00000000, 0x0000a2a8, 0x0000a2a8, 0x0000a2a8 },
- { 0x00009a44, 0x00000000, 0x00000000, 0x0000a2ac, 0x0000a2ac, 0x0000a2ac },
- { 0x00009a48, 0x00000000, 0x00000000, 0x0000a2b0, 0x0000a2b0, 0x0000a2b0 },
- { 0x00009a4c, 0x00000000, 0x00000000, 0x0000a2b4, 0x0000a2b4, 0x0000a2b4 },
- { 0x00009a50, 0x00000000, 0x00000000, 0x0000a2b8, 0x0000a2b8, 0x0000a2b8 },
- { 0x00009a54, 0x00000000, 0x00000000, 0x0000a2c4, 0x0000a2c4, 0x0000a2c4 },
- { 0x00009a58, 0x00000000, 0x00000000, 0x0000a708, 0x0000a708, 0x0000a708 },
- { 0x00009a5c, 0x00000000, 0x00000000, 0x0000a70c, 0x0000a70c, 0x0000a70c },
- { 0x00009a60, 0x00000000, 0x00000000, 0x0000a710, 0x0000a710, 0x0000a710 },
- { 0x00009a64, 0x00000000, 0x00000000, 0x0000ab04, 0x0000ab04, 0x0000ab04 },
- { 0x00009a68, 0x00000000, 0x00000000, 0x0000ab08, 0x0000ab08, 0x0000ab08 },
- { 0x00009a6c, 0x00000000, 0x00000000, 0x0000ab0c, 0x0000ab0c, 0x0000ab0c },
- { 0x00009a70, 0x00000000, 0x00000000, 0x0000ab10, 0x0000ab10, 0x0000ab10 },
- { 0x00009a74, 0x00000000, 0x00000000, 0x0000ab14, 0x0000ab14, 0x0000ab14 },
- { 0x00009a78, 0x00000000, 0x00000000, 0x0000ab18, 0x0000ab18, 0x0000ab18 },
- { 0x00009a7c, 0x00000000, 0x00000000, 0x0000ab8c, 0x0000ab8c, 0x0000ab8c },
- { 0x00009a80, 0x00000000, 0x00000000, 0x0000ab90, 0x0000ab90, 0x0000ab90 },
- { 0x00009a84, 0x00000000, 0x00000000, 0x0000ab94, 0x0000ab94, 0x0000ab94 },
- { 0x00009a88, 0x00000000, 0x00000000, 0x0000ab98, 0x0000ab98, 0x0000ab98 },
- { 0x00009a8c, 0x00000000, 0x00000000, 0x0000aba4, 0x0000aba4, 0x0000aba4 },
- { 0x00009a90, 0x00000000, 0x00000000, 0x0000aba8, 0x0000aba8, 0x0000aba8 },
- { 0x00009a94, 0x00000000, 0x00000000, 0x0000cb04, 0x0000cb04, 0x0000cb04 },
- { 0x00009a98, 0x00000000, 0x00000000, 0x0000cb08, 0x0000cb08, 0x0000cb08 },
- { 0x00009a9c, 0x00000000, 0x00000000, 0x0000cb0c, 0x0000cb0c, 0x0000cb0c },
- { 0x00009aa0, 0x00000000, 0x00000000, 0x0000cb10, 0x0000cb10, 0x0000cb10 },
- { 0x00009aa4, 0x00000000, 0x00000000, 0x0000cb14, 0x0000cb14, 0x0000cb14 },
- { 0x00009aa8, 0x00000000, 0x00000000, 0x0000cb18, 0x0000cb18, 0x0000cb18 },
- { 0x00009aac, 0x00000000, 0x00000000, 0x0000cb8c, 0x0000cb8c, 0x0000cb8c },
- { 0x00009ab0, 0x00000000, 0x00000000, 0x0000cb90, 0x0000cb90, 0x0000cb90 },
- { 0x00009ab4, 0x00000000, 0x00000000, 0x0000cf18, 0x0000cf18, 0x0000cf18 },
- { 0x00009ab8, 0x00000000, 0x00000000, 0x0000cf24, 0x0000cf24, 0x0000cf24 },
- { 0x00009abc, 0x00000000, 0x00000000, 0x0000cf28, 0x0000cf28, 0x0000cf28 },
- { 0x00009ac0, 0x00000000, 0x00000000, 0x0000d314, 0x0000d314, 0x0000d314 },
- { 0x00009ac4, 0x00000000, 0x00000000, 0x0000d318, 0x0000d318, 0x0000d318 },
- { 0x00009ac8, 0x00000000, 0x00000000, 0x0000d38c, 0x0000d38c, 0x0000d38c },
- { 0x00009acc, 0x00000000, 0x00000000, 0x0000d390, 0x0000d390, 0x0000d390 },
- { 0x00009ad0, 0x00000000, 0x00000000, 0x0000d394, 0x0000d394, 0x0000d394 },
- { 0x00009ad4, 0x00000000, 0x00000000, 0x0000d398, 0x0000d398, 0x0000d398 },
- { 0x00009ad8, 0x00000000, 0x00000000, 0x0000d3a4, 0x0000d3a4, 0x0000d3a4 },
- { 0x00009adc, 0x00000000, 0x00000000, 0x0000d3a8, 0x0000d3a8, 0x0000d3a8 },
- { 0x00009ae0, 0x00000000, 0x00000000, 0x0000d3ac, 0x0000d3ac, 0x0000d3ac },
- { 0x00009ae4, 0x00000000, 0x00000000, 0x0000d3b0, 0x0000d3b0, 0x0000d3b0 },
- { 0x00009ae8, 0x00000000, 0x00000000, 0x0000f380, 0x0000f380, 0x0000f380 },
- { 0x00009aec, 0x00000000, 0x00000000, 0x0000f384, 0x0000f384, 0x0000f384 },
- { 0x00009af0, 0x00000000, 0x00000000, 0x0000f388, 0x0000f388, 0x0000f388 },
- { 0x00009af4, 0x00000000, 0x00000000, 0x0000f710, 0x0000f710, 0x0000f710 },
- { 0x00009af8, 0x00000000, 0x00000000, 0x0000f714, 0x0000f714, 0x0000f714 },
- { 0x00009afc, 0x00000000, 0x00000000, 0x0000f718, 0x0000f718, 0x0000f718 },
- { 0x00009b00, 0x00000000, 0x00000000, 0x0000fb10, 0x0000fb10, 0x0000fb10 },
- { 0x00009b04, 0x00000000, 0x00000000, 0x0000fb14, 0x0000fb14, 0x0000fb14 },
- { 0x00009b08, 0x00000000, 0x00000000, 0x0000fb18, 0x0000fb18, 0x0000fb18 },
- { 0x00009b0c, 0x00000000, 0x00000000, 0x0000fb8c, 0x0000fb8c, 0x0000fb8c },
- { 0x00009b10, 0x00000000, 0x00000000, 0x0000fb90, 0x0000fb90, 0x0000fb90 },
- { 0x00009b14, 0x00000000, 0x00000000, 0x0000fb94, 0x0000fb94, 0x0000fb94 },
- { 0x00009b18, 0x00000000, 0x00000000, 0x0000ff8c, 0x0000ff8c, 0x0000ff8c },
- { 0x00009b1c, 0x00000000, 0x00000000, 0x0000ff90, 0x0000ff90, 0x0000ff90 },
- { 0x00009b20, 0x00000000, 0x00000000, 0x0000ff94, 0x0000ff94, 0x0000ff94 },
- { 0x00009b24, 0x00000000, 0x00000000, 0x0000ffa0, 0x0000ffa0, 0x0000ffa0 },
- { 0x00009b28, 0x00000000, 0x00000000, 0x0000ffa4, 0x0000ffa4, 0x0000ffa4 },
- { 0x00009b2c, 0x00000000, 0x00000000, 0x0000ffa8, 0x0000ffa8, 0x0000ffa8 },
- { 0x00009b30, 0x00000000, 0x00000000, 0x0000ffac, 0x0000ffac, 0x0000ffac },
- { 0x00009b34, 0x00000000, 0x00000000, 0x0000ffb0, 0x0000ffb0, 0x0000ffb0 },
- { 0x00009b38, 0x00000000, 0x00000000, 0x0000ffb4, 0x0000ffb4, 0x0000ffb4 },
- { 0x00009b3c, 0x00000000, 0x00000000, 0x0000ffa1, 0x0000ffa1, 0x0000ffa1 },
- { 0x00009b40, 0x00000000, 0x00000000, 0x0000ffa5, 0x0000ffa5, 0x0000ffa5 },
- { 0x00009b44, 0x00000000, 0x00000000, 0x0000ffa9, 0x0000ffa9, 0x0000ffa9 },
- { 0x00009b48, 0x00000000, 0x00000000, 0x0000ffad, 0x0000ffad, 0x0000ffad },
- { 0x00009b4c, 0x00000000, 0x00000000, 0x0000ffb1, 0x0000ffb1, 0x0000ffb1 },
- { 0x00009b50, 0x00000000, 0x00000000, 0x0000ffb5, 0x0000ffb5, 0x0000ffb5 },
- { 0x00009b54, 0x00000000, 0x00000000, 0x0000ffb9, 0x0000ffb9, 0x0000ffb9 },
- { 0x00009b58, 0x00000000, 0x00000000, 0x0000ffc5, 0x0000ffc5, 0x0000ffc5 },
- { 0x00009b5c, 0x00000000, 0x00000000, 0x0000ffc9, 0x0000ffc9, 0x0000ffc9 },
- { 0x00009b60, 0x00000000, 0x00000000, 0x0000ffcd, 0x0000ffcd, 0x0000ffcd },
- { 0x00009b64, 0x00000000, 0x00000000, 0x0000ffd1, 0x0000ffd1, 0x0000ffd1 },
- { 0x00009b68, 0x00000000, 0x00000000, 0x0000ffd5, 0x0000ffd5, 0x0000ffd5 },
- { 0x00009b6c, 0x00000000, 0x00000000, 0x0000ffc2, 0x0000ffc2, 0x0000ffc2 },
- { 0x00009b70, 0x00000000, 0x00000000, 0x0000ffc6, 0x0000ffc6, 0x0000ffc6 },
- { 0x00009b74, 0x00000000, 0x00000000, 0x0000ffca, 0x0000ffca, 0x0000ffca },
- { 0x00009b78, 0x00000000, 0x00000000, 0x0000ffce, 0x0000ffce, 0x0000ffce },
- { 0x00009b7c, 0x00000000, 0x00000000, 0x0000ffd2, 0x0000ffd2, 0x0000ffd2 },
- { 0x00009b80, 0x00000000, 0x00000000, 0x0000ffd6, 0x0000ffd6, 0x0000ffd6 },
- { 0x00009b84, 0x00000000, 0x00000000, 0x0000ffda, 0x0000ffda, 0x0000ffda },
- { 0x00009b88, 0x00000000, 0x00000000, 0x0000ffc7, 0x0000ffc7, 0x0000ffc7 },
- { 0x00009b8c, 0x00000000, 0x00000000, 0x0000ffcb, 0x0000ffcb, 0x0000ffcb },
- { 0x00009b90, 0x00000000, 0x00000000, 0x0000ffcf, 0x0000ffcf, 0x0000ffcf },
- { 0x00009b94, 0x00000000, 0x00000000, 0x0000ffd3, 0x0000ffd3, 0x0000ffd3 },
- { 0x00009b98, 0x00000000, 0x00000000, 0x0000ffd7, 0x0000ffd7, 0x0000ffd7 },
- { 0x00009b9c, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
- { 0x00009ba0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
- { 0x00009ba4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
- { 0x00009ba8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
- { 0x00009bac, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
- { 0x00009bb0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
- { 0x00009bb4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
- { 0x00009bb8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
- { 0x00009bbc, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
- { 0x00009bc0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
- { 0x00009bc4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
- { 0x00009bc8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
- { 0x00009bcc, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
- { 0x00009bd0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
- { 0x00009bd4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
- { 0x00009bd8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
- { 0x00009bdc, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
- { 0x00009be0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
- { 0x00009be4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
- { 0x00009be8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
- { 0x00009bec, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
- { 0x00009bf0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
- { 0x00009bf4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
- { 0x00009bf8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
- { 0x00009bfc, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
- { 0x0000aa00, 0x00000000, 0x00000000, 0x0000a120, 0x0000a120, 0x0000a120 },
- { 0x0000aa04, 0x00000000, 0x00000000, 0x0000a124, 0x0000a124, 0x0000a124 },
- { 0x0000aa08, 0x00000000, 0x00000000, 0x0000a128, 0x0000a128, 0x0000a128 },
- { 0x0000aa0c, 0x00000000, 0x00000000, 0x0000a12c, 0x0000a12c, 0x0000a12c },
- { 0x0000aa10, 0x00000000, 0x00000000, 0x0000a130, 0x0000a130, 0x0000a130 },
- { 0x0000aa14, 0x00000000, 0x00000000, 0x0000a194, 0x0000a194, 0x0000a194 },
- { 0x0000aa18, 0x00000000, 0x00000000, 0x0000a198, 0x0000a198, 0x0000a198 },
- { 0x0000aa1c, 0x00000000, 0x00000000, 0x0000a20c, 0x0000a20c, 0x0000a20c },
- { 0x0000aa20, 0x00000000, 0x00000000, 0x0000a210, 0x0000a210, 0x0000a210 },
- { 0x0000aa24, 0x00000000, 0x00000000, 0x0000a284, 0x0000a284, 0x0000a284 },
- { 0x0000aa28, 0x00000000, 0x00000000, 0x0000a288, 0x0000a288, 0x0000a288 },
- { 0x0000aa2c, 0x00000000, 0x00000000, 0x0000a28c, 0x0000a28c, 0x0000a28c },
- { 0x0000aa30, 0x00000000, 0x00000000, 0x0000a290, 0x0000a290, 0x0000a290 },
- { 0x0000aa34, 0x00000000, 0x00000000, 0x0000a294, 0x0000a294, 0x0000a294 },
- { 0x0000aa38, 0x00000000, 0x00000000, 0x0000a2a0, 0x0000a2a0, 0x0000a2a0 },
- { 0x0000aa3c, 0x00000000, 0x00000000, 0x0000a2a4, 0x0000a2a4, 0x0000a2a4 },
- { 0x0000aa40, 0x00000000, 0x00000000, 0x0000a2a8, 0x0000a2a8, 0x0000a2a8 },
- { 0x0000aa44, 0x00000000, 0x00000000, 0x0000a2ac, 0x0000a2ac, 0x0000a2ac },
- { 0x0000aa48, 0x00000000, 0x00000000, 0x0000a2b0, 0x0000a2b0, 0x0000a2b0 },
- { 0x0000aa4c, 0x00000000, 0x00000000, 0x0000a2b4, 0x0000a2b4, 0x0000a2b4 },
- { 0x0000aa50, 0x00000000, 0x00000000, 0x0000a2b8, 0x0000a2b8, 0x0000a2b8 },
- { 0x0000aa54, 0x00000000, 0x00000000, 0x0000a2c4, 0x0000a2c4, 0x0000a2c4 },
- { 0x0000aa58, 0x00000000, 0x00000000, 0x0000a708, 0x0000a708, 0x0000a708 },
- { 0x0000aa5c, 0x00000000, 0x00000000, 0x0000a70c, 0x0000a70c, 0x0000a70c },
- { 0x0000aa60, 0x00000000, 0x00000000, 0x0000a710, 0x0000a710, 0x0000a710 },
- { 0x0000aa64, 0x00000000, 0x00000000, 0x0000ab04, 0x0000ab04, 0x0000ab04 },
- { 0x0000aa68, 0x00000000, 0x00000000, 0x0000ab08, 0x0000ab08, 0x0000ab08 },
- { 0x0000aa6c, 0x00000000, 0x00000000, 0x0000ab0c, 0x0000ab0c, 0x0000ab0c },
- { 0x0000aa70, 0x00000000, 0x00000000, 0x0000ab10, 0x0000ab10, 0x0000ab10 },
- { 0x0000aa74, 0x00000000, 0x00000000, 0x0000ab14, 0x0000ab14, 0x0000ab14 },
- { 0x0000aa78, 0x00000000, 0x00000000, 0x0000ab18, 0x0000ab18, 0x0000ab18 },
- { 0x0000aa7c, 0x00000000, 0x00000000, 0x0000ab8c, 0x0000ab8c, 0x0000ab8c },
- { 0x0000aa80, 0x00000000, 0x00000000, 0x0000ab90, 0x0000ab90, 0x0000ab90 },
- { 0x0000aa84, 0x00000000, 0x00000000, 0x0000ab94, 0x0000ab94, 0x0000ab94 },
- { 0x0000aa88, 0x00000000, 0x00000000, 0x0000ab98, 0x0000ab98, 0x0000ab98 },
- { 0x0000aa8c, 0x00000000, 0x00000000, 0x0000aba4, 0x0000aba4, 0x0000aba4 },
- { 0x0000aa90, 0x00000000, 0x00000000, 0x0000aba8, 0x0000aba8, 0x0000aba8 },
- { 0x0000aa94, 0x00000000, 0x00000000, 0x0000cb04, 0x0000cb04, 0x0000cb04 },
- { 0x0000aa98, 0x00000000, 0x00000000, 0x0000cb08, 0x0000cb08, 0x0000cb08 },
- { 0x0000aa9c, 0x00000000, 0x00000000, 0x0000cb0c, 0x0000cb0c, 0x0000cb0c },
- { 0x0000aaa0, 0x00000000, 0x00000000, 0x0000cb10, 0x0000cb10, 0x0000cb10 },
- { 0x0000aaa4, 0x00000000, 0x00000000, 0x0000cb14, 0x0000cb14, 0x0000cb14 },
- { 0x0000aaa8, 0x00000000, 0x00000000, 0x0000cb18, 0x0000cb18, 0x0000cb18 },
- { 0x0000aaac, 0x00000000, 0x00000000, 0x0000cb8c, 0x0000cb8c, 0x0000cb8c },
- { 0x0000aab0, 0x00000000, 0x00000000, 0x0000cb90, 0x0000cb90, 0x0000cb90 },
- { 0x0000aab4, 0x00000000, 0x00000000, 0x0000cf18, 0x0000cf18, 0x0000cf18 },
- { 0x0000aab8, 0x00000000, 0x00000000, 0x0000cf24, 0x0000cf24, 0x0000cf24 },
- { 0x0000aabc, 0x00000000, 0x00000000, 0x0000cf28, 0x0000cf28, 0x0000cf28 },
- { 0x0000aac0, 0x00000000, 0x00000000, 0x0000d314, 0x0000d314, 0x0000d314 },
- { 0x0000aac4, 0x00000000, 0x00000000, 0x0000d318, 0x0000d318, 0x0000d318 },
- { 0x0000aac8, 0x00000000, 0x00000000, 0x0000d38c, 0x0000d38c, 0x0000d38c },
- { 0x0000aacc, 0x00000000, 0x00000000, 0x0000d390, 0x0000d390, 0x0000d390 },
- { 0x0000aad0, 0x00000000, 0x00000000, 0x0000d394, 0x0000d394, 0x0000d394 },
- { 0x0000aad4, 0x00000000, 0x00000000, 0x0000d398, 0x0000d398, 0x0000d398 },
- { 0x0000aad8, 0x00000000, 0x00000000, 0x0000d3a4, 0x0000d3a4, 0x0000d3a4 },
- { 0x0000aadc, 0x00000000, 0x00000000, 0x0000d3a8, 0x0000d3a8, 0x0000d3a8 },
- { 0x0000aae0, 0x00000000, 0x00000000, 0x0000d3ac, 0x0000d3ac, 0x0000d3ac },
- { 0x0000aae4, 0x00000000, 0x00000000, 0x0000d3b0, 0x0000d3b0, 0x0000d3b0 },
- { 0x0000aae8, 0x00000000, 0x00000000, 0x0000f380, 0x0000f380, 0x0000f380 },
- { 0x0000aaec, 0x00000000, 0x00000000, 0x0000f384, 0x0000f384, 0x0000f384 },
- { 0x0000aaf0, 0x00000000, 0x00000000, 0x0000f388, 0x0000f388, 0x0000f388 },
- { 0x0000aaf4, 0x00000000, 0x00000000, 0x0000f710, 0x0000f710, 0x0000f710 },
- { 0x0000aaf8, 0x00000000, 0x00000000, 0x0000f714, 0x0000f714, 0x0000f714 },
- { 0x0000aafc, 0x00000000, 0x00000000, 0x0000f718, 0x0000f718, 0x0000f718 },
- { 0x0000ab00, 0x00000000, 0x00000000, 0x0000fb10, 0x0000fb10, 0x0000fb10 },
- { 0x0000ab04, 0x00000000, 0x00000000, 0x0000fb14, 0x0000fb14, 0x0000fb14 },
- { 0x0000ab08, 0x00000000, 0x00000000, 0x0000fb18, 0x0000fb18, 0x0000fb18 },
- { 0x0000ab0c, 0x00000000, 0x00000000, 0x0000fb8c, 0x0000fb8c, 0x0000fb8c },
- { 0x0000ab10, 0x00000000, 0x00000000, 0x0000fb90, 0x0000fb90, 0x0000fb90 },
- { 0x0000ab14, 0x00000000, 0x00000000, 0x0000fb94, 0x0000fb94, 0x0000fb94 },
- { 0x0000ab18, 0x00000000, 0x00000000, 0x0000ff8c, 0x0000ff8c, 0x0000ff8c },
- { 0x0000ab1c, 0x00000000, 0x00000000, 0x0000ff90, 0x0000ff90, 0x0000ff90 },
- { 0x0000ab20, 0x00000000, 0x00000000, 0x0000ff94, 0x0000ff94, 0x0000ff94 },
- { 0x0000ab24, 0x00000000, 0x00000000, 0x0000ffa0, 0x0000ffa0, 0x0000ffa0 },
- { 0x0000ab28, 0x00000000, 0x00000000, 0x0000ffa4, 0x0000ffa4, 0x0000ffa4 },
- { 0x0000ab2c, 0x00000000, 0x00000000, 0x0000ffa8, 0x0000ffa8, 0x0000ffa8 },
- { 0x0000ab30, 0x00000000, 0x00000000, 0x0000ffac, 0x0000ffac, 0x0000ffac },
- { 0x0000ab34, 0x00000000, 0x00000000, 0x0000ffb0, 0x0000ffb0, 0x0000ffb0 },
- { 0x0000ab38, 0x00000000, 0x00000000, 0x0000ffb4, 0x0000ffb4, 0x0000ffb4 },
- { 0x0000ab3c, 0x00000000, 0x00000000, 0x0000ffa1, 0x0000ffa1, 0x0000ffa1 },
- { 0x0000ab40, 0x00000000, 0x00000000, 0x0000ffa5, 0x0000ffa5, 0x0000ffa5 },
- { 0x0000ab44, 0x00000000, 0x00000000, 0x0000ffa9, 0x0000ffa9, 0x0000ffa9 },
- { 0x0000ab48, 0x00000000, 0x00000000, 0x0000ffad, 0x0000ffad, 0x0000ffad },
- { 0x0000ab4c, 0x00000000, 0x00000000, 0x0000ffb1, 0x0000ffb1, 0x0000ffb1 },
- { 0x0000ab50, 0x00000000, 0x00000000, 0x0000ffb5, 0x0000ffb5, 0x0000ffb5 },
- { 0x0000ab54, 0x00000000, 0x00000000, 0x0000ffb9, 0x0000ffb9, 0x0000ffb9 },
- { 0x0000ab58, 0x00000000, 0x00000000, 0x0000ffc5, 0x0000ffc5, 0x0000ffc5 },
- { 0x0000ab5c, 0x00000000, 0x00000000, 0x0000ffc9, 0x0000ffc9, 0x0000ffc9 },
- { 0x0000ab60, 0x00000000, 0x00000000, 0x0000ffcd, 0x0000ffcd, 0x0000ffcd },
- { 0x0000ab64, 0x00000000, 0x00000000, 0x0000ffd1, 0x0000ffd1, 0x0000ffd1 },
- { 0x0000ab68, 0x00000000, 0x00000000, 0x0000ffd5, 0x0000ffd5, 0x0000ffd5 },
- { 0x0000ab6c, 0x00000000, 0x00000000, 0x0000ffc2, 0x0000ffc2, 0x0000ffc2 },
- { 0x0000ab70, 0x00000000, 0x00000000, 0x0000ffc6, 0x0000ffc6, 0x0000ffc6 },
- { 0x0000ab74, 0x00000000, 0x00000000, 0x0000ffca, 0x0000ffca, 0x0000ffca },
- { 0x0000ab78, 0x00000000, 0x00000000, 0x0000ffce, 0x0000ffce, 0x0000ffce },
- { 0x0000ab7c, 0x00000000, 0x00000000, 0x0000ffd2, 0x0000ffd2, 0x0000ffd2 },
- { 0x0000ab80, 0x00000000, 0x00000000, 0x0000ffd6, 0x0000ffd6, 0x0000ffd6 },
- { 0x0000ab84, 0x00000000, 0x00000000, 0x0000ffda, 0x0000ffda, 0x0000ffda },
- { 0x0000ab88, 0x00000000, 0x00000000, 0x0000ffc7, 0x0000ffc7, 0x0000ffc7 },
- { 0x0000ab8c, 0x00000000, 0x00000000, 0x0000ffcb, 0x0000ffcb, 0x0000ffcb },
- { 0x0000ab90, 0x00000000, 0x00000000, 0x0000ffcf, 0x0000ffcf, 0x0000ffcf },
- { 0x0000ab94, 0x00000000, 0x00000000, 0x0000ffd3, 0x0000ffd3, 0x0000ffd3 },
- { 0x0000ab98, 0x00000000, 0x00000000, 0x0000ffd7, 0x0000ffd7, 0x0000ffd7 },
- { 0x0000ab9c, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
- { 0x0000aba0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
- { 0x0000aba4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
- { 0x0000aba8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
- { 0x0000abac, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
- { 0x0000abb0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
- { 0x0000abb4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
- { 0x0000abb8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
- { 0x0000abbc, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
- { 0x0000abc0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
- { 0x0000abc4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
- { 0x0000abc8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
- { 0x0000abcc, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
- { 0x0000abd0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
- { 0x0000abd4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
- { 0x0000abd8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
- { 0x0000abdc, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
- { 0x0000abe0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
- { 0x0000abe4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
- { 0x0000abe8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
- { 0x0000abec, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
- { 0x0000abf0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
- { 0x0000abf4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
- { 0x0000abf8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
- { 0x0000abfc, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
- { 0x00009848, 0x00000000, 0x00000000, 0x00001067, 0x00001067, 0x00001067 },
- { 0x0000a848, 0x00000000, 0x00000000, 0x00001067, 0x00001067, 0x00001067 },
-};
-
-static const u32 ar9287PciePhy_clkreq_always_on_L1_9287_1_0[][2] = {
- {0x00004040, 0x9248fd00 },
- {0x00004040, 0x24924924 },
- {0x00004040, 0xa8000019 },
- {0x00004040, 0x13160820 },
- {0x00004040, 0xe5980560 },
- {0x00004040, 0xc01dcffd },
- {0x00004040, 0x1aaabe41 },
- {0x00004040, 0xbe105554 },
- {0x00004040, 0x00043007 },
- {0x00004044, 0x00000000 },
-};
-
-static const u32 ar9287PciePhy_clkreq_off_L1_9287_1_0[][2] = {
- {0x00004040, 0x9248fd00 },
- {0x00004040, 0x24924924 },
- {0x00004040, 0xa8000019 },
- {0x00004040, 0x13160820 },
- {0x00004040, 0xe5980560 },
- {0x00004040, 0xc01dcffc },
- {0x00004040, 0x1aaabe41 },
- {0x00004040, 0xbe105554 },
- {0x00004040, 0x00043007 },
- {0x00004044, 0x00000000 },
-};
-
-/* AR9287 Revision 11 */
-
static const u32 ar9287Modes_9287_1_1[][6] = {
- /* Address 5G-HT20 5G-HT40 2G-HT40 2G-HT20 Turbo */
- { 0x00001030, 0x00000000, 0x00000000, 0x000002c0, 0x00000160, 0x000001e0 },
- { 0x00001070, 0x00000000, 0x00000000, 0x00000318, 0x0000018c, 0x000001e0 },
- { 0x000010b0, 0x00000000, 0x00000000, 0x00007c70, 0x00003e38, 0x00001180 },
- { 0x000010f0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000008 },
- { 0x00008014, 0x00000000, 0x00000000, 0x10801600, 0x08400b00, 0x06e006e0 },
- { 0x0000801c, 0x00000000, 0x00000000, 0x12e00057, 0x12e0002b, 0x0988004f },
- { 0x00008120, 0x08f04800, 0x08f04800, 0x08f04810, 0x08f04810, 0x08f04810 },
- { 0x000081d0, 0x00003200, 0x00003200, 0x0000320a, 0x0000320a, 0x0000320a },
- { 0x00008318, 0x00000000, 0x00000000, 0x00006880, 0x00003440, 0x00006880 },
- { 0x00009804, 0x00000000, 0x00000000, 0x000003c4, 0x00000300, 0x00000303 },
- { 0x00009820, 0x00000000, 0x00000000, 0x02020200, 0x02020200, 0x02020200 },
- { 0x00009824, 0x00000000, 0x00000000, 0x01000e0e, 0x01000e0e, 0x01000e0e },
- { 0x00009828, 0x00000000, 0x00000000, 0x3a020001, 0x3a020001, 0x3a020001 },
- { 0x00009834, 0x00000000, 0x00000000, 0x00000e0e, 0x00000e0e, 0x00000e0e },
- { 0x00009838, 0x00000003, 0x00000003, 0x00000007, 0x00000007, 0x00000007 },
- { 0x00009840, 0x206a002e, 0x206a002e, 0x206a012e, 0x206a012e, 0x206a012e },
- { 0x00009844, 0x03720000, 0x03720000, 0x037216a0, 0x037216a0, 0x037216a0 },
- { 0x00009850, 0x60000000, 0x60000000, 0x6d4000e2, 0x6c4000e2, 0x6c4000e2 },
- { 0x00009858, 0x7c000d00, 0x7c000d00, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e },
- { 0x0000985c, 0x3100005e, 0x3100005e, 0x3139605e, 0x31395d5e, 0x31395d5e },
- { 0x00009860, 0x00058d00, 0x00058d00, 0x00058d20, 0x00058d20, 0x00058d18 },
- { 0x00009864, 0x00000e00, 0x00000e00, 0x0001ce00, 0x0001ce00, 0x0001ce00 },
- { 0x00009868, 0x000040c0, 0x000040c0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0 },
- { 0x0000986c, 0x00000080, 0x00000080, 0x06903881, 0x06903881, 0x06903881 },
- { 0x00009914, 0x00000000, 0x00000000, 0x00001130, 0x00000898, 0x000007d0 },
- { 0x00009918, 0x00000000, 0x00000000, 0x00000016, 0x0000000b, 0x00000016 },
- { 0x00009924, 0xd00a8a01, 0xd00a8a01, 0xd00a8a0d, 0xd00a8a0d, 0xd00a8a0d },
- { 0x00009944, 0xefbc0000, 0xefbc0000, 0xefbc1010, 0xefbc1010, 0xefbc1010 },
- { 0x00009960, 0x00000000, 0x00000000, 0x00000010, 0x00000010, 0x00000010 },
- { 0x0000a960, 0x00000000, 0x00000000, 0x00000010, 0x00000010, 0x00000010 },
- { 0x00009964, 0x00000000, 0x00000000, 0x00000210, 0x00000210, 0x00000210 },
- { 0x0000c968, 0x00000200, 0x00000200, 0x000003ce, 0x000003ce, 0x000003ce },
- { 0x000099b8, 0x00000000, 0x00000000, 0x0000001c, 0x0000001c, 0x0000001c },
- { 0x000099bc, 0x00000000, 0x00000000, 0x00000c00, 0x00000c00, 0x00000c00 },
- { 0x000099c0, 0x00000000, 0x00000000, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4 },
- { 0x0000a204, 0x00000440, 0x00000440, 0x00000444, 0x00000444, 0x00000444 },
- { 0x0000a20c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
- { 0x0000b20c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
- { 0x0000a21c, 0x1803800a, 0x1803800a, 0x1883800a, 0x1883800a, 0x1883800a },
- { 0x0000a230, 0x00000000, 0x00000000, 0x00000210, 0x00000108, 0x00000000 },
- { 0x0000a250, 0x00000000, 0x00000000, 0x0004a000, 0x0004a000, 0x0004a000 },
- { 0x0000a358, 0x7999aa02, 0x7999aa02, 0x7999aa0e, 0x7999aa0e, 0x7999aa0e },
- { 0x0000a3d8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
+ {0x00001030, 0x00000000, 0x00000000, 0x000002c0, 0x00000160, 0x000001e0},
+ {0x00001070, 0x00000000, 0x00000000, 0x00000318, 0x0000018c, 0x000001e0},
+ {0x000010b0, 0x00000000, 0x00000000, 0x00007c70, 0x00003e38, 0x00001180},
+ {0x000010f0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000008},
+ {0x00008014, 0x00000000, 0x00000000, 0x10801600, 0x08400b00, 0x06e006e0},
+ {0x0000801c, 0x00000000, 0x00000000, 0x12e00057, 0x12e0002b, 0x0988004f},
+ {0x00008120, 0x08f04800, 0x08f04800, 0x08f04810, 0x08f04810, 0x08f04810},
+ {0x000081d0, 0x00003200, 0x00003200, 0x0000320a, 0x0000320a, 0x0000320a},
+ {0x00008318, 0x00000000, 0x00000000, 0x00006880, 0x00003440, 0x00006880},
+ {0x00009804, 0x00000000, 0x00000000, 0x000003c4, 0x00000300, 0x00000303},
+ {0x00009820, 0x00000000, 0x00000000, 0x02020200, 0x02020200, 0x02020200},
+ {0x00009824, 0x00000000, 0x00000000, 0x01000e0e, 0x01000e0e, 0x01000e0e},
+ {0x00009828, 0x00000000, 0x00000000, 0x3a020001, 0x3a020001, 0x3a020001},
+ {0x00009834, 0x00000000, 0x00000000, 0x00000e0e, 0x00000e0e, 0x00000e0e},
+ {0x00009838, 0x00000003, 0x00000003, 0x00000007, 0x00000007, 0x00000007},
+ {0x00009840, 0x206a002e, 0x206a002e, 0x206a012e, 0x206a012e, 0x206a012e},
+ {0x00009844, 0x03720000, 0x03720000, 0x037216a0, 0x037216a0, 0x037216a0},
+ {0x00009850, 0x60000000, 0x60000000, 0x6d4000e2, 0x6c4000e2, 0x6c4000e2},
+ {0x00009858, 0x7c000d00, 0x7c000d00, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e},
+ {0x0000985c, 0x3100005e, 0x3100005e, 0x3139605e, 0x31395d5e, 0x31395d5e},
+ {0x00009860, 0x00058d00, 0x00058d00, 0x00058d20, 0x00058d20, 0x00058d18},
+ {0x00009864, 0x00000e00, 0x00000e00, 0x0001ce00, 0x0001ce00, 0x0001ce00},
+ {0x00009868, 0x000040c0, 0x000040c0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0},
+ {0x0000986c, 0x00000080, 0x00000080, 0x06903881, 0x06903881, 0x06903881},
+ {0x00009914, 0x00000000, 0x00000000, 0x00001130, 0x00000898, 0x000007d0},
+ {0x00009918, 0x00000000, 0x00000000, 0x00000016, 0x0000000b, 0x00000016},
+ {0x00009924, 0xd00a8a01, 0xd00a8a01, 0xd00a8a0d, 0xd00a8a0d, 0xd00a8a0d},
+ {0x00009944, 0xefbc0000, 0xefbc0000, 0xefbc1010, 0xefbc1010, 0xefbc1010},
+ {0x00009960, 0x00000000, 0x00000000, 0x00000010, 0x00000010, 0x00000010},
+ {0x0000a960, 0x00000000, 0x00000000, 0x00000010, 0x00000010, 0x00000010},
+ {0x00009964, 0x00000000, 0x00000000, 0x00000210, 0x00000210, 0x00000210},
+ {0x0000c968, 0x00000200, 0x00000200, 0x000003ce, 0x000003ce, 0x000003ce},
+ {0x000099b8, 0x00000000, 0x00000000, 0x0000001c, 0x0000001c, 0x0000001c},
+ {0x000099bc, 0x00000000, 0x00000000, 0x00000c00, 0x00000c00, 0x00000c00},
+ {0x000099c0, 0x00000000, 0x00000000, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4},
+ {0x0000a204, 0x00000440, 0x00000440, 0x00000444, 0x00000444, 0x00000444},
+ {0x0000a20c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+ {0x0000b20c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+ {0x0000a21c, 0x1803800a, 0x1803800a, 0x1883800a, 0x1883800a, 0x1883800a},
+ {0x0000a230, 0x00000000, 0x00000000, 0x00000210, 0x00000108, 0x00000000},
+ {0x0000a250, 0x00000000, 0x00000000, 0x0004a000, 0x0004a000, 0x0004a000},
+ {0x0000a358, 0x7999aa02, 0x7999aa02, 0x7999aa0e, 0x7999aa0e, 0x7999aa0e},
+ {0x0000a3d8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
};
static const u32 ar9287Common_9287_1_1[][2] = {
- { 0x0000000c, 0x00000000 },
- { 0x00000030, 0x00020015 },
- { 0x00000034, 0x00000005 },
- { 0x00000040, 0x00000000 },
- { 0x00000044, 0x00000008 },
- { 0x00000048, 0x00000008 },
- { 0x0000004c, 0x00000010 },
- { 0x00000050, 0x00000000 },
- { 0x00000054, 0x0000001f },
- { 0x00000800, 0x00000000 },
- { 0x00000804, 0x00000000 },
- { 0x00000808, 0x00000000 },
- { 0x0000080c, 0x00000000 },
- { 0x00000810, 0x00000000 },
- { 0x00000814, 0x00000000 },
- { 0x00000818, 0x00000000 },
- { 0x0000081c, 0x00000000 },
- { 0x00000820, 0x00000000 },
- { 0x00000824, 0x00000000 },
- { 0x00001040, 0x002ffc0f },
- { 0x00001044, 0x002ffc0f },
- { 0x00001048, 0x002ffc0f },
- { 0x0000104c, 0x002ffc0f },
- { 0x00001050, 0x002ffc0f },
- { 0x00001054, 0x002ffc0f },
- { 0x00001058, 0x002ffc0f },
- { 0x0000105c, 0x002ffc0f },
- { 0x00001060, 0x002ffc0f },
- { 0x00001064, 0x002ffc0f },
- { 0x00001230, 0x00000000 },
- { 0x00001270, 0x00000000 },
- { 0x00001038, 0x00000000 },
- { 0x00001078, 0x00000000 },
- { 0x000010b8, 0x00000000 },
- { 0x000010f8, 0x00000000 },
- { 0x00001138, 0x00000000 },
- { 0x00001178, 0x00000000 },
- { 0x000011b8, 0x00000000 },
- { 0x000011f8, 0x00000000 },
- { 0x00001238, 0x00000000 },
- { 0x00001278, 0x00000000 },
- { 0x000012b8, 0x00000000 },
- { 0x000012f8, 0x00000000 },
- { 0x00001338, 0x00000000 },
- { 0x00001378, 0x00000000 },
- { 0x000013b8, 0x00000000 },
- { 0x000013f8, 0x00000000 },
- { 0x00001438, 0x00000000 },
- { 0x00001478, 0x00000000 },
- { 0x000014b8, 0x00000000 },
- { 0x000014f8, 0x00000000 },
- { 0x00001538, 0x00000000 },
- { 0x00001578, 0x00000000 },
- { 0x000015b8, 0x00000000 },
- { 0x000015f8, 0x00000000 },
- { 0x00001638, 0x00000000 },
- { 0x00001678, 0x00000000 },
- { 0x000016b8, 0x00000000 },
- { 0x000016f8, 0x00000000 },
- { 0x00001738, 0x00000000 },
- { 0x00001778, 0x00000000 },
- { 0x000017b8, 0x00000000 },
- { 0x000017f8, 0x00000000 },
- { 0x0000103c, 0x00000000 },
- { 0x0000107c, 0x00000000 },
- { 0x000010bc, 0x00000000 },
- { 0x000010fc, 0x00000000 },
- { 0x0000113c, 0x00000000 },
- { 0x0000117c, 0x00000000 },
- { 0x000011bc, 0x00000000 },
- { 0x000011fc, 0x00000000 },
- { 0x0000123c, 0x00000000 },
- { 0x0000127c, 0x00000000 },
- { 0x000012bc, 0x00000000 },
- { 0x000012fc, 0x00000000 },
- { 0x0000133c, 0x00000000 },
- { 0x0000137c, 0x00000000 },
- { 0x000013bc, 0x00000000 },
- { 0x000013fc, 0x00000000 },
- { 0x0000143c, 0x00000000 },
- { 0x0000147c, 0x00000000 },
- { 0x00004030, 0x00000002 },
- { 0x0000403c, 0x00000002 },
- { 0x00004024, 0x0000001f },
- { 0x00004060, 0x00000000 },
- { 0x00004064, 0x00000000 },
- { 0x00007010, 0x00000033 },
- { 0x00007020, 0x00000000 },
- { 0x00007034, 0x00000002 },
- { 0x00007038, 0x000004c2 },
- { 0x00008004, 0x00000000 },
- { 0x00008008, 0x00000000 },
- { 0x0000800c, 0x00000000 },
- { 0x00008018, 0x00000700 },
- { 0x00008020, 0x00000000 },
- { 0x00008038, 0x00000000 },
- { 0x0000803c, 0x00000000 },
- { 0x00008048, 0x40000000 },
- { 0x00008054, 0x00000000 },
- { 0x00008058, 0x00000000 },
- { 0x0000805c, 0x000fc78f },
- { 0x00008060, 0x0000000f },
- { 0x00008064, 0x00000000 },
- { 0x00008070, 0x00000000 },
- { 0x000080c0, 0x2a80001a },
- { 0x000080c4, 0x05dc01e0 },
- { 0x000080c8, 0x1f402710 },
- { 0x000080cc, 0x01f40000 },
- { 0x000080d0, 0x00001e00 },
- { 0x000080d4, 0x00000000 },
- { 0x000080d8, 0x00400000 },
- { 0x000080e0, 0xffffffff },
- { 0x000080e4, 0x0000ffff },
- { 0x000080e8, 0x003f3f3f },
- { 0x000080ec, 0x00000000 },
- { 0x000080f0, 0x00000000 },
- { 0x000080f4, 0x00000000 },
- { 0x000080f8, 0x00000000 },
- { 0x000080fc, 0x00020000 },
- { 0x00008100, 0x00020000 },
- { 0x00008104, 0x00000001 },
- { 0x00008108, 0x00000052 },
- { 0x0000810c, 0x00000000 },
- { 0x00008110, 0x00000168 },
- { 0x00008118, 0x000100aa },
- { 0x0000811c, 0x00003210 },
- { 0x00008124, 0x00000000 },
- { 0x00008128, 0x00000000 },
- { 0x0000812c, 0x00000000 },
- { 0x00008130, 0x00000000 },
- { 0x00008134, 0x00000000 },
- { 0x00008138, 0x00000000 },
- { 0x0000813c, 0x00000000 },
- { 0x00008144, 0xffffffff },
- { 0x00008168, 0x00000000 },
- { 0x0000816c, 0x00000000 },
- { 0x00008170, 0x18487320 },
- { 0x00008174, 0xfaa4fa50 },
- { 0x00008178, 0x00000100 },
- { 0x0000817c, 0x00000000 },
- { 0x000081c0, 0x00000000 },
- { 0x000081c4, 0x00000000 },
- { 0x000081d4, 0x00000000 },
- { 0x000081ec, 0x00000000 },
- { 0x000081f0, 0x00000000 },
- { 0x000081f4, 0x00000000 },
- { 0x000081f8, 0x00000000 },
- { 0x000081fc, 0x00000000 },
- { 0x00008200, 0x00000000 },
- { 0x00008204, 0x00000000 },
- { 0x00008208, 0x00000000 },
- { 0x0000820c, 0x00000000 },
- { 0x00008210, 0x00000000 },
- { 0x00008214, 0x00000000 },
- { 0x00008218, 0x00000000 },
- { 0x0000821c, 0x00000000 },
- { 0x00008220, 0x00000000 },
- { 0x00008224, 0x00000000 },
- { 0x00008228, 0x00000000 },
- { 0x0000822c, 0x00000000 },
- { 0x00008230, 0x00000000 },
- { 0x00008234, 0x00000000 },
- { 0x00008238, 0x00000000 },
- { 0x0000823c, 0x00000000 },
- { 0x00008240, 0x00100000 },
- { 0x00008244, 0x0010f400 },
- { 0x00008248, 0x00000100 },
- { 0x0000824c, 0x0001e800 },
- { 0x00008250, 0x00000000 },
- { 0x00008254, 0x00000000 },
- { 0x00008258, 0x00000000 },
- { 0x0000825c, 0x400000ff },
- { 0x00008260, 0x00080922 },
- { 0x00008264, 0x88a00010 },
- { 0x00008270, 0x00000000 },
- { 0x00008274, 0x40000000 },
- { 0x00008278, 0x003e4180 },
- { 0x0000827c, 0x00000000 },
- { 0x00008284, 0x0000002c },
- { 0x00008288, 0x0000002c },
- { 0x0000828c, 0x000000ff },
- { 0x00008294, 0x00000000 },
- { 0x00008298, 0x00000000 },
- { 0x0000829c, 0x00000000 },
- { 0x00008300, 0x00000040 },
- { 0x00008314, 0x00000000 },
- { 0x00008328, 0x00000000 },
- { 0x0000832c, 0x00000007 },
- { 0x00008330, 0x00000302 },
- { 0x00008334, 0x00000e00 },
- { 0x00008338, 0x00ff0000 },
- { 0x0000833c, 0x00000000 },
- { 0x00008340, 0x000107ff },
- { 0x00008344, 0x01c81043 },
- { 0x00008360, 0xffffffff },
- { 0x00008364, 0xffffffff },
- { 0x00008368, 0x00000000 },
- { 0x00008370, 0x00000000 },
- { 0x00008374, 0x000000ff },
- { 0x00008378, 0x00000000 },
- { 0x0000837c, 0x00000000 },
- { 0x00008380, 0xffffffff },
- { 0x00008384, 0xffffffff },
- { 0x00008390, 0x0fffffff },
- { 0x00008394, 0x0fffffff },
- { 0x00008398, 0x00000000 },
- { 0x0000839c, 0x00000000 },
- { 0x000083a0, 0x00000000 },
- { 0x00009808, 0x00000000 },
- { 0x0000980c, 0xafe68e30 },
- { 0x00009810, 0xfd14e000 },
- { 0x00009814, 0x9c0a9f6b },
- { 0x0000981c, 0x00000000 },
- { 0x0000982c, 0x0000a000 },
- { 0x00009830, 0x00000000 },
- { 0x0000983c, 0x00200400 },
- { 0x0000984c, 0x0040233c },
- { 0x0000a84c, 0x0040233c },
- { 0x00009854, 0x00000044 },
- { 0x00009900, 0x00000000 },
- { 0x00009904, 0x00000000 },
- { 0x00009908, 0x00000000 },
- { 0x0000990c, 0x00000000 },
- { 0x00009910, 0x10002310 },
- { 0x0000991c, 0x10000fff },
- { 0x00009920, 0x04900000 },
- { 0x0000a920, 0x04900000 },
- { 0x00009928, 0x00000001 },
- { 0x0000992c, 0x00000004 },
- { 0x00009930, 0x00000000 },
- { 0x0000a930, 0x00000000 },
- { 0x00009934, 0x1e1f2022 },
- { 0x00009938, 0x0a0b0c0d },
- { 0x0000993c, 0x00000000 },
- { 0x00009948, 0x9280c00a },
- { 0x0000994c, 0x00020028 },
- { 0x00009954, 0x5f3ca3de },
- { 0x00009958, 0x0108ecff },
- { 0x00009940, 0x14750604 },
- { 0x0000c95c, 0x004b6a8e },
- { 0x00009970, 0x990bb514 },
- { 0x00009974, 0x00000000 },
- { 0x00009978, 0x00000001 },
- { 0x0000997c, 0x00000000 },
- { 0x000099a0, 0x00000000 },
- { 0x000099a4, 0x00000001 },
- { 0x000099a8, 0x201fff00 },
- { 0x000099ac, 0x0c6f0000 },
- { 0x000099b0, 0x03051000 },
- { 0x000099b4, 0x00000820 },
- { 0x000099c4, 0x06336f77 },
- { 0x000099c8, 0x6af6532f },
- { 0x000099cc, 0x08f186c8 },
- { 0x000099d0, 0x00046384 },
- { 0x000099dc, 0x00000000 },
- { 0x000099e0, 0x00000000 },
- { 0x000099e4, 0xaaaaaaaa },
- { 0x000099e8, 0x3c466478 },
- { 0x000099ec, 0x0cc80caa },
- { 0x000099f0, 0x00000000 },
- { 0x000099fc, 0x00001042 },
- { 0x0000a208, 0x803e4788 },
- { 0x0000a210, 0x4080a333 },
- { 0x0000a214, 0x40206c10 },
- { 0x0000a218, 0x009c4060 },
- { 0x0000a220, 0x01834061 },
- { 0x0000a224, 0x00000400 },
- { 0x0000a228, 0x000003b5 },
- { 0x0000a22c, 0x233f7180 },
- { 0x0000a234, 0x20202020 },
- { 0x0000a238, 0x20202020 },
- { 0x0000a23c, 0x13c889af },
- { 0x0000a240, 0x38490a20 },
- { 0x0000a244, 0x00000000 },
- { 0x0000a248, 0xfffffffc },
- { 0x0000a24c, 0x00000000 },
- { 0x0000a254, 0x00000000 },
- { 0x0000a258, 0x0cdbd380 },
- { 0x0000a25c, 0x0f0f0f01 },
- { 0x0000a260, 0xdfa91f01 },
- { 0x0000a264, 0x00418a11 },
- { 0x0000b264, 0x00418a11 },
- { 0x0000a268, 0x00000000 },
- { 0x0000a26c, 0x0e79e5c6 },
- { 0x0000b26c, 0x0e79e5c6 },
- { 0x0000d270, 0x00820820 },
- { 0x0000a278, 0x1ce739ce },
- { 0x0000a27c, 0x050701ce },
- { 0x0000d35c, 0x07ffffef },
- { 0x0000d360, 0x0fffffe7 },
- { 0x0000d364, 0x17ffffe5 },
- { 0x0000d368, 0x1fffffe4 },
- { 0x0000d36c, 0x37ffffe3 },
- { 0x0000d370, 0x3fffffe3 },
- { 0x0000d374, 0x57ffffe3 },
- { 0x0000d378, 0x5fffffe2 },
- { 0x0000d37c, 0x7fffffe2 },
- { 0x0000d380, 0x7f3c7bba },
- { 0x0000d384, 0xf3307ff0 },
- { 0x0000a388, 0x0c000000 },
- { 0x0000a38c, 0x20202020 },
- { 0x0000a390, 0x20202020 },
- { 0x0000a394, 0x1ce739ce },
- { 0x0000a398, 0x000001ce },
- { 0x0000b398, 0x000001ce },
- { 0x0000a39c, 0x00000001 },
- { 0x0000a3c8, 0x00000246 },
- { 0x0000a3cc, 0x20202020 },
- { 0x0000a3d0, 0x20202020 },
- { 0x0000a3d4, 0x20202020 },
- { 0x0000a3dc, 0x1ce739ce },
- { 0x0000a3e0, 0x000001ce },
- { 0x0000a3e4, 0x00000000 },
- { 0x0000a3e8, 0x18c43433 },
- { 0x0000a3ec, 0x00f70081 },
- { 0x0000a3f0, 0x01036a1e },
- { 0x0000a3f4, 0x00000000 },
- { 0x0000b3f4, 0x00000000 },
- { 0x0000a7d8, 0x000003f1 },
- { 0x00007800, 0x00000800 },
- { 0x00007804, 0x6c35ffd2 },
- { 0x00007808, 0x6db6c000 },
- { 0x0000780c, 0x6db6cb30 },
- { 0x00007810, 0x6db6cb6c },
- { 0x00007814, 0x0501e200 },
- { 0x00007818, 0x0094128d },
- { 0x0000781c, 0x976ee392 },
- { 0x00007820, 0xf75ff6fc },
- { 0x00007824, 0x00040000 },
- { 0x00007828, 0xdb003012 },
- { 0x0000782c, 0x04924914 },
- { 0x00007830, 0x21084210 },
- { 0x00007834, 0x00140000 },
- { 0x00007838, 0x0e4548d8 },
- { 0x0000783c, 0x54214514 },
- { 0x00007840, 0x02025830 },
- { 0x00007844, 0x71c0d388 },
- { 0x00007848, 0x934934a8 },
- { 0x00007850, 0x00000000 },
- { 0x00007854, 0x00000800 },
- { 0x00007858, 0x6c35ffd2 },
- { 0x0000785c, 0x6db6c000 },
- { 0x00007860, 0x6db6cb30 },
- { 0x00007864, 0x6db6cb6c },
- { 0x00007868, 0x0501e200 },
- { 0x0000786c, 0x0094128d },
- { 0x00007870, 0x976ee392 },
- { 0x00007874, 0xf75ff6fc },
- { 0x00007878, 0x00040000 },
- { 0x0000787c, 0xdb003012 },
- { 0x00007880, 0x04924914 },
- { 0x00007884, 0x21084210 },
- { 0x00007888, 0x001b6db0 },
- { 0x0000788c, 0x00376b63 },
- { 0x00007890, 0x06db6db6 },
- { 0x00007894, 0x006d8000 },
- { 0x00007898, 0x48100000 },
- { 0x0000789c, 0x00000000 },
- { 0x000078a0, 0x08000000 },
- { 0x000078a4, 0x0007ffd8 },
- { 0x000078a8, 0x0007ffd8 },
- { 0x000078ac, 0x001c0020 },
- { 0x000078b0, 0x00060aeb },
- { 0x000078b4, 0x40008080 },
- { 0x000078b8, 0x2a850160 },
+ /* Addr allmodes */
+ {0x0000000c, 0x00000000},
+ {0x00000030, 0x00020015},
+ {0x00000034, 0x00000005},
+ {0x00000040, 0x00000000},
+ {0x00000044, 0x00000008},
+ {0x00000048, 0x00000008},
+ {0x0000004c, 0x00000010},
+ {0x00000050, 0x00000000},
+ {0x00000054, 0x0000001f},
+ {0x00000800, 0x00000000},
+ {0x00000804, 0x00000000},
+ {0x00000808, 0x00000000},
+ {0x0000080c, 0x00000000},
+ {0x00000810, 0x00000000},
+ {0x00000814, 0x00000000},
+ {0x00000818, 0x00000000},
+ {0x0000081c, 0x00000000},
+ {0x00000820, 0x00000000},
+ {0x00000824, 0x00000000},
+ {0x00001040, 0x002ffc0f},
+ {0x00001044, 0x002ffc0f},
+ {0x00001048, 0x002ffc0f},
+ {0x0000104c, 0x002ffc0f},
+ {0x00001050, 0x002ffc0f},
+ {0x00001054, 0x002ffc0f},
+ {0x00001058, 0x002ffc0f},
+ {0x0000105c, 0x002ffc0f},
+ {0x00001060, 0x002ffc0f},
+ {0x00001064, 0x002ffc0f},
+ {0x00001230, 0x00000000},
+ {0x00001270, 0x00000000},
+ {0x00001038, 0x00000000},
+ {0x00001078, 0x00000000},
+ {0x000010b8, 0x00000000},
+ {0x000010f8, 0x00000000},
+ {0x00001138, 0x00000000},
+ {0x00001178, 0x00000000},
+ {0x000011b8, 0x00000000},
+ {0x000011f8, 0x00000000},
+ {0x00001238, 0x00000000},
+ {0x00001278, 0x00000000},
+ {0x000012b8, 0x00000000},
+ {0x000012f8, 0x00000000},
+ {0x00001338, 0x00000000},
+ {0x00001378, 0x00000000},
+ {0x000013b8, 0x00000000},
+ {0x000013f8, 0x00000000},
+ {0x00001438, 0x00000000},
+ {0x00001478, 0x00000000},
+ {0x000014b8, 0x00000000},
+ {0x000014f8, 0x00000000},
+ {0x00001538, 0x00000000},
+ {0x00001578, 0x00000000},
+ {0x000015b8, 0x00000000},
+ {0x000015f8, 0x00000000},
+ {0x00001638, 0x00000000},
+ {0x00001678, 0x00000000},
+ {0x000016b8, 0x00000000},
+ {0x000016f8, 0x00000000},
+ {0x00001738, 0x00000000},
+ {0x00001778, 0x00000000},
+ {0x000017b8, 0x00000000},
+ {0x000017f8, 0x00000000},
+ {0x0000103c, 0x00000000},
+ {0x0000107c, 0x00000000},
+ {0x000010bc, 0x00000000},
+ {0x000010fc, 0x00000000},
+ {0x0000113c, 0x00000000},
+ {0x0000117c, 0x00000000},
+ {0x000011bc, 0x00000000},
+ {0x000011fc, 0x00000000},
+ {0x0000123c, 0x00000000},
+ {0x0000127c, 0x00000000},
+ {0x000012bc, 0x00000000},
+ {0x000012fc, 0x00000000},
+ {0x0000133c, 0x00000000},
+ {0x0000137c, 0x00000000},
+ {0x000013bc, 0x00000000},
+ {0x000013fc, 0x00000000},
+ {0x0000143c, 0x00000000},
+ {0x0000147c, 0x00000000},
+ {0x00004030, 0x00000002},
+ {0x0000403c, 0x00000002},
+ {0x00004024, 0x0000001f},
+ {0x00004060, 0x00000000},
+ {0x00004064, 0x00000000},
+ {0x00007010, 0x00000033},
+ {0x00007020, 0x00000000},
+ {0x00007034, 0x00000002},
+ {0x00007038, 0x000004c2},
+ {0x00008004, 0x00000000},
+ {0x00008008, 0x00000000},
+ {0x0000800c, 0x00000000},
+ {0x00008018, 0x00000700},
+ {0x00008020, 0x00000000},
+ {0x00008038, 0x00000000},
+ {0x0000803c, 0x00000000},
+ {0x00008048, 0x40000000},
+ {0x00008054, 0x00000000},
+ {0x00008058, 0x00000000},
+ {0x0000805c, 0x000fc78f},
+ {0x00008060, 0x0000000f},
+ {0x00008064, 0x00000000},
+ {0x00008070, 0x00000000},
+ {0x000080c0, 0x2a80001a},
+ {0x000080c4, 0x05dc01e0},
+ {0x000080c8, 0x1f402710},
+ {0x000080cc, 0x01f40000},
+ {0x000080d0, 0x00001e00},
+ {0x000080d4, 0x00000000},
+ {0x000080d8, 0x00400000},
+ {0x000080e0, 0xffffffff},
+ {0x000080e4, 0x0000ffff},
+ {0x000080e8, 0x003f3f3f},
+ {0x000080ec, 0x00000000},
+ {0x000080f0, 0x00000000},
+ {0x000080f4, 0x00000000},
+ {0x000080f8, 0x00000000},
+ {0x000080fc, 0x00020000},
+ {0x00008100, 0x00020000},
+ {0x00008104, 0x00000001},
+ {0x00008108, 0x00000052},
+ {0x0000810c, 0x00000000},
+ {0x00008110, 0x00000168},
+ {0x00008118, 0x000100aa},
+ {0x0000811c, 0x00003210},
+ {0x00008124, 0x00000000},
+ {0x00008128, 0x00000000},
+ {0x0000812c, 0x00000000},
+ {0x00008130, 0x00000000},
+ {0x00008134, 0x00000000},
+ {0x00008138, 0x00000000},
+ {0x0000813c, 0x00000000},
+ {0x00008144, 0xffffffff},
+ {0x00008168, 0x00000000},
+ {0x0000816c, 0x00000000},
+ {0x00008170, 0x18487320},
+ {0x00008174, 0xfaa4fa50},
+ {0x00008178, 0x00000100},
+ {0x0000817c, 0x00000000},
+ {0x000081c0, 0x00000000},
+ {0x000081c4, 0x00000000},
+ {0x000081d4, 0x00000000},
+ {0x000081ec, 0x00000000},
+ {0x000081f0, 0x00000000},
+ {0x000081f4, 0x00000000},
+ {0x000081f8, 0x00000000},
+ {0x000081fc, 0x00000000},
+ {0x00008200, 0x00000000},
+ {0x00008204, 0x00000000},
+ {0x00008208, 0x00000000},
+ {0x0000820c, 0x00000000},
+ {0x00008210, 0x00000000},
+ {0x00008214, 0x00000000},
+ {0x00008218, 0x00000000},
+ {0x0000821c, 0x00000000},
+ {0x00008220, 0x00000000},
+ {0x00008224, 0x00000000},
+ {0x00008228, 0x00000000},
+ {0x0000822c, 0x00000000},
+ {0x00008230, 0x00000000},
+ {0x00008234, 0x00000000},
+ {0x00008238, 0x00000000},
+ {0x0000823c, 0x00000000},
+ {0x00008240, 0x00100000},
+ {0x00008244, 0x0010f400},
+ {0x00008248, 0x00000100},
+ {0x0000824c, 0x0001e800},
+ {0x00008250, 0x00000000},
+ {0x00008254, 0x00000000},
+ {0x00008258, 0x00000000},
+ {0x0000825c, 0x400000ff},
+ {0x00008260, 0x00080922},
+ {0x00008264, 0x88a00010},
+ {0x00008270, 0x00000000},
+ {0x00008274, 0x40000000},
+ {0x00008278, 0x003e4180},
+ {0x0000827c, 0x00000000},
+ {0x00008284, 0x0000002c},
+ {0x00008288, 0x0000002c},
+ {0x0000828c, 0x000000ff},
+ {0x00008294, 0x00000000},
+ {0x00008298, 0x00000000},
+ {0x0000829c, 0x00000000},
+ {0x00008300, 0x00000040},
+ {0x00008314, 0x00000000},
+ {0x00008328, 0x00000000},
+ {0x0000832c, 0x00000007},
+ {0x00008330, 0x00000302},
+ {0x00008334, 0x00000e00},
+ {0x00008338, 0x00ff0000},
+ {0x0000833c, 0x00000000},
+ {0x00008340, 0x000107ff},
+ {0x00008344, 0x01c81043},
+ {0x00008360, 0xffffffff},
+ {0x00008364, 0xffffffff},
+ {0x00008368, 0x00000000},
+ {0x00008370, 0x00000000},
+ {0x00008374, 0x000000ff},
+ {0x00008378, 0x00000000},
+ {0x0000837c, 0x00000000},
+ {0x00008380, 0xffffffff},
+ {0x00008384, 0xffffffff},
+ {0x00008390, 0x0fffffff},
+ {0x00008394, 0x0fffffff},
+ {0x00008398, 0x00000000},
+ {0x0000839c, 0x00000000},
+ {0x000083a0, 0x00000000},
+ {0x00009808, 0x00000000},
+ {0x0000980c, 0xafe68e30},
+ {0x00009810, 0xfd14e000},
+ {0x00009814, 0x9c0a9f6b},
+ {0x0000981c, 0x00000000},
+ {0x0000982c, 0x0000a000},
+ {0x00009830, 0x00000000},
+ {0x0000983c, 0x00200400},
+ {0x0000984c, 0x0040233c},
+ {0x0000a84c, 0x0040233c},
+ {0x00009854, 0x00000044},
+ {0x00009900, 0x00000000},
+ {0x00009904, 0x00000000},
+ {0x00009908, 0x00000000},
+ {0x0000990c, 0x00000000},
+ {0x00009910, 0x10002310},
+ {0x0000991c, 0x10000fff},
+ {0x00009920, 0x04900000},
+ {0x0000a920, 0x04900000},
+ {0x00009928, 0x00000001},
+ {0x0000992c, 0x00000004},
+ {0x00009930, 0x00000000},
+ {0x0000a930, 0x00000000},
+ {0x00009934, 0x1e1f2022},
+ {0x00009938, 0x0a0b0c0d},
+ {0x0000993c, 0x00000000},
+ {0x00009948, 0x9280c00a},
+ {0x0000994c, 0x00020028},
+ {0x00009954, 0x5f3ca3de},
+ {0x00009958, 0x0108ecff},
+ {0x00009940, 0x14750604},
+ {0x0000c95c, 0x004b6a8e},
+ {0x00009970, 0x990bb514},
+ {0x00009974, 0x00000000},
+ {0x00009978, 0x00000001},
+ {0x0000997c, 0x00000000},
+ {0x000099a0, 0x00000000},
+ {0x000099a4, 0x00000001},
+ {0x000099a8, 0x201fff00},
+ {0x000099ac, 0x0c6f0000},
+ {0x000099b0, 0x03051000},
+ {0x000099b4, 0x00000820},
+ {0x000099c4, 0x06336f77},
+ {0x000099c8, 0x6af6532f},
+ {0x000099cc, 0x08f186c8},
+ {0x000099d0, 0x00046384},
+ {0x000099dc, 0x00000000},
+ {0x000099e0, 0x00000000},
+ {0x000099e4, 0xaaaaaaaa},
+ {0x000099e8, 0x3c466478},
+ {0x000099ec, 0x0cc80caa},
+ {0x000099f0, 0x00000000},
+ {0x000099fc, 0x00001042},
+ {0x0000a208, 0x803e4788},
+ {0x0000a210, 0x4080a333},
+ {0x0000a214, 0x40206c10},
+ {0x0000a218, 0x009c4060},
+ {0x0000a220, 0x01834061},
+ {0x0000a224, 0x00000400},
+ {0x0000a228, 0x000003b5},
+ {0x0000a22c, 0x233f7180},
+ {0x0000a234, 0x20202020},
+ {0x0000a238, 0x20202020},
+ {0x0000a23c, 0x13c889af},
+ {0x0000a240, 0x38490a20},
+ {0x0000a244, 0x00000000},
+ {0x0000a248, 0xfffffffc},
+ {0x0000a24c, 0x00000000},
+ {0x0000a254, 0x00000000},
+ {0x0000a258, 0x0cdbd380},
+ {0x0000a25c, 0x0f0f0f01},
+ {0x0000a260, 0xdfa91f01},
+ {0x0000a264, 0x00418a11},
+ {0x0000b264, 0x00418a11},
+ {0x0000a268, 0x00000000},
+ {0x0000a26c, 0x0e79e5c6},
+ {0x0000b26c, 0x0e79e5c6},
+ {0x0000d270, 0x00820820},
+ {0x0000a278, 0x1ce739ce},
+ {0x0000a27c, 0x050701ce},
+ {0x0000d35c, 0x07ffffef},
+ {0x0000d360, 0x0fffffe7},
+ {0x0000d364, 0x17ffffe5},
+ {0x0000d368, 0x1fffffe4},
+ {0x0000d36c, 0x37ffffe3},
+ {0x0000d370, 0x3fffffe3},
+ {0x0000d374, 0x57ffffe3},
+ {0x0000d378, 0x5fffffe2},
+ {0x0000d37c, 0x7fffffe2},
+ {0x0000d380, 0x7f3c7bba},
+ {0x0000d384, 0xf3307ff0},
+ {0x0000a388, 0x0c000000},
+ {0x0000a38c, 0x20202020},
+ {0x0000a390, 0x20202020},
+ {0x0000a394, 0x1ce739ce},
+ {0x0000a398, 0x000001ce},
+ {0x0000b398, 0x000001ce},
+ {0x0000a39c, 0x00000001},
+ {0x0000a3c8, 0x00000246},
+ {0x0000a3cc, 0x20202020},
+ {0x0000a3d0, 0x20202020},
+ {0x0000a3d4, 0x20202020},
+ {0x0000a3dc, 0x1ce739ce},
+ {0x0000a3e0, 0x000001ce},
+ {0x0000a3e4, 0x00000000},
+ {0x0000a3e8, 0x18c43433},
+ {0x0000a3ec, 0x00f70081},
+ {0x0000a3f0, 0x01036a1e},
+ {0x0000a3f4, 0x00000000},
+ {0x0000b3f4, 0x00000000},
+ {0x0000a7d8, 0x000003f1},
+ {0x00007800, 0x00000800},
+ {0x00007804, 0x6c35ffd2},
+ {0x00007808, 0x6db6c000},
+ {0x0000780c, 0x6db6cb30},
+ {0x00007810, 0x6db6cb6c},
+ {0x00007814, 0x0501e200},
+ {0x00007818, 0x0094128d},
+ {0x0000781c, 0x976ee392},
+ {0x00007820, 0xf75ff6fc},
+ {0x00007824, 0x00040000},
+ {0x00007828, 0xdb003012},
+ {0x0000782c, 0x04924914},
+ {0x00007830, 0x21084210},
+ {0x00007834, 0x00140000},
+ {0x00007838, 0x0e4548d8},
+ {0x0000783c, 0x54214514},
+ {0x00007840, 0x02025830},
+ {0x00007844, 0x71c0d388},
+ {0x00007848, 0x934934a8},
+ {0x00007850, 0x00000000},
+ {0x00007854, 0x00000800},
+ {0x00007858, 0x6c35ffd2},
+ {0x0000785c, 0x6db6c000},
+ {0x00007860, 0x6db6cb30},
+ {0x00007864, 0x6db6cb6c},
+ {0x00007868, 0x0501e200},
+ {0x0000786c, 0x0094128d},
+ {0x00007870, 0x976ee392},
+ {0x00007874, 0xf75ff6fc},
+ {0x00007878, 0x00040000},
+ {0x0000787c, 0xdb003012},
+ {0x00007880, 0x04924914},
+ {0x00007884, 0x21084210},
+ {0x00007888, 0x001b6db0},
+ {0x0000788c, 0x00376b63},
+ {0x00007890, 0x06db6db6},
+ {0x00007894, 0x006d8000},
+ {0x00007898, 0x48100000},
+ {0x0000789c, 0x00000000},
+ {0x000078a0, 0x08000000},
+ {0x000078a4, 0x0007ffd8},
+ {0x000078a8, 0x0007ffd8},
+ {0x000078ac, 0x001c0020},
+ {0x000078b0, 0x00060aeb},
+ {0x000078b4, 0x40008080},
+ {0x000078b8, 0x2a850160},
};
-/*
- * For Japanese regulatory requirements, 2484 MHz requires the following three
- * registers be programmed differently from the channel between 2412 and
- * 2472 MHz.
- */
-static const u32 ar9287Common_normal_cck_fir_coeff_92871_1[][2] = {
- { 0x0000a1f4, 0x00fffeff },
- { 0x0000a1f8, 0x00f5f9ff },
- { 0x0000a1fc, 0xb79f6427 },
+static const u32 ar9287Common_normal_cck_fir_coeff_9287_1_1[][2] = {
+ /* Addr allmodes */
+ {0x0000a1f4, 0x00fffeff},
+ {0x0000a1f8, 0x00f5f9ff},
+ {0x0000a1fc, 0xb79f6427},
};
-static const u32 ar9287Common_japan_2484_cck_fir_coeff_92871_1[][2] = {
- { 0x0000a1f4, 0x00000000 },
- { 0x0000a1f8, 0xefff0301 },
- { 0x0000a1fc, 0xca9228ee },
+static const u32 ar9287Common_japan_2484_cck_fir_coeff_9287_1_1[][2] = {
+ /* Addr allmodes */
+ {0x0000a1f4, 0x00000000},
+ {0x0000a1f8, 0xefff0301},
+ {0x0000a1fc, 0xca9228ee},
};
static const u32 ar9287Modes_tx_gain_9287_1_1[][6] = {
- /* Address 5G-HT20 5G-HT40 2G-HT40 2G-HT20 Turbo */
- { 0x0000a300, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
- { 0x0000a304, 0x00000000, 0x00000000, 0x00004002, 0x00004002, 0x00004002 },
- { 0x0000a308, 0x00000000, 0x00000000, 0x00008004, 0x00008004, 0x00008004 },
- { 0x0000a30c, 0x00000000, 0x00000000, 0x0000c00a, 0x0000c00a, 0x0000c00a },
- { 0x0000a310, 0x00000000, 0x00000000, 0x0001000c, 0x0001000c, 0x0001000c },
- { 0x0000a314, 0x00000000, 0x00000000, 0x0001420b, 0x0001420b, 0x0001420b },
- { 0x0000a318, 0x00000000, 0x00000000, 0x0001824a, 0x0001824a, 0x0001824a },
- { 0x0000a31c, 0x00000000, 0x00000000, 0x0001c44a, 0x0001c44a, 0x0001c44a },
- { 0x0000a320, 0x00000000, 0x00000000, 0x0002064a, 0x0002064a, 0x0002064a },
- { 0x0000a324, 0x00000000, 0x00000000, 0x0002484a, 0x0002484a, 0x0002484a },
- { 0x0000a328, 0x00000000, 0x00000000, 0x00028a4a, 0x00028a4a, 0x00028a4a },
- { 0x0000a32c, 0x00000000, 0x00000000, 0x0002cc4a, 0x0002cc4a, 0x0002cc4a },
- { 0x0000a330, 0x00000000, 0x00000000, 0x00030e4a, 0x00030e4a, 0x00030e4a },
- { 0x0000a334, 0x00000000, 0x00000000, 0x00034e8a, 0x00034e8a, 0x00034e8a },
- { 0x0000a338, 0x00000000, 0x00000000, 0x00038e8c, 0x00038e8c, 0x00038e8c },
- { 0x0000a33c, 0x00000000, 0x00000000, 0x0003cecc, 0x0003cecc, 0x0003cecc },
- { 0x0000a340, 0x00000000, 0x00000000, 0x00040ed4, 0x00040ed4, 0x00040ed4 },
- { 0x0000a344, 0x00000000, 0x00000000, 0x00044edc, 0x00044edc, 0x00044edc },
- { 0x0000a348, 0x00000000, 0x00000000, 0x00048ede, 0x00048ede, 0x00048ede },
- { 0x0000a34c, 0x00000000, 0x00000000, 0x0004cf1e, 0x0004cf1e, 0x0004cf1e },
- { 0x0000a350, 0x00000000, 0x00000000, 0x00050f5e, 0x00050f5e, 0x00050f5e },
- { 0x0000a354, 0x00000000, 0x00000000, 0x00054f9e, 0x00054f9e, 0x00054f9e },
- { 0x0000a780, 0x00000000, 0x00000000, 0x00000062, 0x00000062, 0x00000062 },
- { 0x0000a784, 0x00000000, 0x00000000, 0x00004064, 0x00004064, 0x00004064 },
- { 0x0000a788, 0x00000000, 0x00000000, 0x000080a4, 0x000080a4, 0x000080a4 },
- { 0x0000a78c, 0x00000000, 0x00000000, 0x0000c0aa, 0x0000c0aa, 0x0000c0aa },
- { 0x0000a790, 0x00000000, 0x00000000, 0x000100ac, 0x000100ac, 0x000100ac },
- { 0x0000a794, 0x00000000, 0x00000000, 0x000140b4, 0x000140b4, 0x000140b4 },
- { 0x0000a798, 0x00000000, 0x00000000, 0x000180f4, 0x000180f4, 0x000180f4 },
- { 0x0000a79c, 0x00000000, 0x00000000, 0x0001c134, 0x0001c134, 0x0001c134 },
- { 0x0000a7a0, 0x00000000, 0x00000000, 0x00020174, 0x00020174, 0x00020174 },
- { 0x0000a7a4, 0x00000000, 0x00000000, 0x0002417c, 0x0002417c, 0x0002417c },
- { 0x0000a7a8, 0x00000000, 0x00000000, 0x0002817e, 0x0002817e, 0x0002817e },
- { 0x0000a7ac, 0x00000000, 0x00000000, 0x0002c1be, 0x0002c1be, 0x0002c1be },
- { 0x0000a7b0, 0x00000000, 0x00000000, 0x000301fe, 0x000301fe, 0x000301fe },
- { 0x0000a7b4, 0x00000000, 0x00000000, 0x000301fe, 0x000301fe, 0x000301fe },
- { 0x0000a7b8, 0x00000000, 0x00000000, 0x000301fe, 0x000301fe, 0x000301fe },
- { 0x0000a7bc, 0x00000000, 0x00000000, 0x000301fe, 0x000301fe, 0x000301fe },
- { 0x0000a7c0, 0x00000000, 0x00000000, 0x000301fe, 0x000301fe, 0x000301fe },
- { 0x0000a7c4, 0x00000000, 0x00000000, 0x000301fe, 0x000301fe, 0x000301fe },
- { 0x0000a7c8, 0x00000000, 0x00000000, 0x000301fe, 0x000301fe, 0x000301fe },
- { 0x0000a7cc, 0x00000000, 0x00000000, 0x000301fe, 0x000301fe, 0x000301fe },
- { 0x0000a7d0, 0x00000000, 0x00000000, 0x000301fe, 0x000301fe, 0x000301fe },
- { 0x0000a7d4, 0x00000000, 0x00000000, 0x000301fe, 0x000301fe, 0x000301fe },
- { 0x0000a274, 0x0a180000, 0x0a180000, 0x0a1aa000, 0x0a1aa000, 0x0a1aa000 },
+ {0x0000a300, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+ {0x0000a304, 0x00000000, 0x00000000, 0x00004002, 0x00004002, 0x00004002},
+ {0x0000a308, 0x00000000, 0x00000000, 0x00008004, 0x00008004, 0x00008004},
+ {0x0000a30c, 0x00000000, 0x00000000, 0x0000c00a, 0x0000c00a, 0x0000c00a},
+ {0x0000a310, 0x00000000, 0x00000000, 0x0001000c, 0x0001000c, 0x0001000c},
+ {0x0000a314, 0x00000000, 0x00000000, 0x0001420b, 0x0001420b, 0x0001420b},
+ {0x0000a318, 0x00000000, 0x00000000, 0x0001824a, 0x0001824a, 0x0001824a},
+ {0x0000a31c, 0x00000000, 0x00000000, 0x0001c44a, 0x0001c44a, 0x0001c44a},
+ {0x0000a320, 0x00000000, 0x00000000, 0x0002064a, 0x0002064a, 0x0002064a},
+ {0x0000a324, 0x00000000, 0x00000000, 0x0002484a, 0x0002484a, 0x0002484a},
+ {0x0000a328, 0x00000000, 0x00000000, 0x00028a4a, 0x00028a4a, 0x00028a4a},
+ {0x0000a32c, 0x00000000, 0x00000000, 0x0002cc4a, 0x0002cc4a, 0x0002cc4a},
+ {0x0000a330, 0x00000000, 0x00000000, 0x00030e4a, 0x00030e4a, 0x00030e4a},
+ {0x0000a334, 0x00000000, 0x00000000, 0x00034e8a, 0x00034e8a, 0x00034e8a},
+ {0x0000a338, 0x00000000, 0x00000000, 0x00038e8c, 0x00038e8c, 0x00038e8c},
+ {0x0000a33c, 0x00000000, 0x00000000, 0x0003cecc, 0x0003cecc, 0x0003cecc},
+ {0x0000a340, 0x00000000, 0x00000000, 0x00040ed4, 0x00040ed4, 0x00040ed4},
+ {0x0000a344, 0x00000000, 0x00000000, 0x00044edc, 0x00044edc, 0x00044edc},
+ {0x0000a348, 0x00000000, 0x00000000, 0x00048ede, 0x00048ede, 0x00048ede},
+ {0x0000a34c, 0x00000000, 0x00000000, 0x0004cf1e, 0x0004cf1e, 0x0004cf1e},
+ {0x0000a350, 0x00000000, 0x00000000, 0x00050f5e, 0x00050f5e, 0x00050f5e},
+ {0x0000a354, 0x00000000, 0x00000000, 0x00054f9e, 0x00054f9e, 0x00054f9e},
+ {0x0000a780, 0x00000000, 0x00000000, 0x00000062, 0x00000062, 0x00000062},
+ {0x0000a784, 0x00000000, 0x00000000, 0x00004064, 0x00004064, 0x00004064},
+ {0x0000a788, 0x00000000, 0x00000000, 0x000080a4, 0x000080a4, 0x000080a4},
+ {0x0000a78c, 0x00000000, 0x00000000, 0x0000c0aa, 0x0000c0aa, 0x0000c0aa},
+ {0x0000a790, 0x00000000, 0x00000000, 0x000100ac, 0x000100ac, 0x000100ac},
+ {0x0000a794, 0x00000000, 0x00000000, 0x000140b4, 0x000140b4, 0x000140b4},
+ {0x0000a798, 0x00000000, 0x00000000, 0x000180f4, 0x000180f4, 0x000180f4},
+ {0x0000a79c, 0x00000000, 0x00000000, 0x0001c134, 0x0001c134, 0x0001c134},
+ {0x0000a7a0, 0x00000000, 0x00000000, 0x00020174, 0x00020174, 0x00020174},
+ {0x0000a7a4, 0x00000000, 0x00000000, 0x0002417c, 0x0002417c, 0x0002417c},
+ {0x0000a7a8, 0x00000000, 0x00000000, 0x0002817e, 0x0002817e, 0x0002817e},
+ {0x0000a7ac, 0x00000000, 0x00000000, 0x0002c1be, 0x0002c1be, 0x0002c1be},
+ {0x0000a7b0, 0x00000000, 0x00000000, 0x000301fe, 0x000301fe, 0x000301fe},
+ {0x0000a7b4, 0x00000000, 0x00000000, 0x000301fe, 0x000301fe, 0x000301fe},
+ {0x0000a7b8, 0x00000000, 0x00000000, 0x000301fe, 0x000301fe, 0x000301fe},
+ {0x0000a7bc, 0x00000000, 0x00000000, 0x000301fe, 0x000301fe, 0x000301fe},
+ {0x0000a7c0, 0x00000000, 0x00000000, 0x000301fe, 0x000301fe, 0x000301fe},
+ {0x0000a7c4, 0x00000000, 0x00000000, 0x000301fe, 0x000301fe, 0x000301fe},
+ {0x0000a7c8, 0x00000000, 0x00000000, 0x000301fe, 0x000301fe, 0x000301fe},
+ {0x0000a7cc, 0x00000000, 0x00000000, 0x000301fe, 0x000301fe, 0x000301fe},
+ {0x0000a7d0, 0x00000000, 0x00000000, 0x000301fe, 0x000301fe, 0x000301fe},
+ {0x0000a7d4, 0x00000000, 0x00000000, 0x000301fe, 0x000301fe, 0x000301fe},
+ {0x0000a274, 0x0a180000, 0x0a180000, 0x0a1aa000, 0x0a1aa000, 0x0a1aa000},
};
static const u32 ar9287Modes_rx_gain_9287_1_1[][6] = {
- /* Address 5G-HT20 5G-HT40 2G-HT40 2G-HT20 Turbo */
- { 0x00009a00, 0x00000000, 0x00000000, 0x0000a120, 0x0000a120, 0x0000a120 },
- { 0x00009a04, 0x00000000, 0x00000000, 0x0000a124, 0x0000a124, 0x0000a124 },
- { 0x00009a08, 0x00000000, 0x00000000, 0x0000a128, 0x0000a128, 0x0000a128 },
- { 0x00009a0c, 0x00000000, 0x00000000, 0x0000a12c, 0x0000a12c, 0x0000a12c },
- { 0x00009a10, 0x00000000, 0x00000000, 0x0000a130, 0x0000a130, 0x0000a130 },
- { 0x00009a14, 0x00000000, 0x00000000, 0x0000a194, 0x0000a194, 0x0000a194 },
- { 0x00009a18, 0x00000000, 0x00000000, 0x0000a198, 0x0000a198, 0x0000a198 },
- { 0x00009a1c, 0x00000000, 0x00000000, 0x0000a20c, 0x0000a20c, 0x0000a20c },
- { 0x00009a20, 0x00000000, 0x00000000, 0x0000a210, 0x0000a210, 0x0000a210 },
- { 0x00009a24, 0x00000000, 0x00000000, 0x0000a284, 0x0000a284, 0x0000a284 },
- { 0x00009a28, 0x00000000, 0x00000000, 0x0000a288, 0x0000a288, 0x0000a288 },
- { 0x00009a2c, 0x00000000, 0x00000000, 0x0000a28c, 0x0000a28c, 0x0000a28c },
- { 0x00009a30, 0x00000000, 0x00000000, 0x0000a290, 0x0000a290, 0x0000a290 },
- { 0x00009a34, 0x00000000, 0x00000000, 0x0000a294, 0x0000a294, 0x0000a294 },
- { 0x00009a38, 0x00000000, 0x00000000, 0x0000a2a0, 0x0000a2a0, 0x0000a2a0 },
- { 0x00009a3c, 0x00000000, 0x00000000, 0x0000a2a4, 0x0000a2a4, 0x0000a2a4 },
- { 0x00009a40, 0x00000000, 0x00000000, 0x0000a2a8, 0x0000a2a8, 0x0000a2a8 },
- { 0x00009a44, 0x00000000, 0x00000000, 0x0000a2ac, 0x0000a2ac, 0x0000a2ac },
- { 0x00009a48, 0x00000000, 0x00000000, 0x0000a2b0, 0x0000a2b0, 0x0000a2b0 },
- { 0x00009a4c, 0x00000000, 0x00000000, 0x0000a2b4, 0x0000a2b4, 0x0000a2b4 },
- { 0x00009a50, 0x00000000, 0x00000000, 0x0000a2b8, 0x0000a2b8, 0x0000a2b8 },
- { 0x00009a54, 0x00000000, 0x00000000, 0x0000a2c4, 0x0000a2c4, 0x0000a2c4 },
- { 0x00009a58, 0x00000000, 0x00000000, 0x0000a708, 0x0000a708, 0x0000a708 },
- { 0x00009a5c, 0x00000000, 0x00000000, 0x0000a70c, 0x0000a70c, 0x0000a70c },
- { 0x00009a60, 0x00000000, 0x00000000, 0x0000a710, 0x0000a710, 0x0000a710 },
- { 0x00009a64, 0x00000000, 0x00000000, 0x0000ab04, 0x0000ab04, 0x0000ab04 },
- { 0x00009a68, 0x00000000, 0x00000000, 0x0000ab08, 0x0000ab08, 0x0000ab08 },
- { 0x00009a6c, 0x00000000, 0x00000000, 0x0000ab0c, 0x0000ab0c, 0x0000ab0c },
- { 0x00009a70, 0x00000000, 0x00000000, 0x0000ab10, 0x0000ab10, 0x0000ab10 },
- { 0x00009a74, 0x00000000, 0x00000000, 0x0000ab14, 0x0000ab14, 0x0000ab14 },
- { 0x00009a78, 0x00000000, 0x00000000, 0x0000ab18, 0x0000ab18, 0x0000ab18 },
- { 0x00009a7c, 0x00000000, 0x00000000, 0x0000ab8c, 0x0000ab8c, 0x0000ab8c },
- { 0x00009a80, 0x00000000, 0x00000000, 0x0000ab90, 0x0000ab90, 0x0000ab90 },
- { 0x00009a84, 0x00000000, 0x00000000, 0x0000ab94, 0x0000ab94, 0x0000ab94 },
- { 0x00009a88, 0x00000000, 0x00000000, 0x0000ab98, 0x0000ab98, 0x0000ab98 },
- { 0x00009a8c, 0x00000000, 0x00000000, 0x0000aba4, 0x0000aba4, 0x0000aba4 },
- { 0x00009a90, 0x00000000, 0x00000000, 0x0000aba8, 0x0000aba8, 0x0000aba8 },
- { 0x00009a94, 0x00000000, 0x00000000, 0x0000cb04, 0x0000cb04, 0x0000cb04 },
- { 0x00009a98, 0x00000000, 0x00000000, 0x0000cb08, 0x0000cb08, 0x0000cb08 },
- { 0x00009a9c, 0x00000000, 0x00000000, 0x0000cb0c, 0x0000cb0c, 0x0000cb0c },
- { 0x00009aa0, 0x00000000, 0x00000000, 0x0000cb10, 0x0000cb10, 0x0000cb10 },
- { 0x00009aa4, 0x00000000, 0x00000000, 0x0000cb14, 0x0000cb14, 0x0000cb14 },
- { 0x00009aa8, 0x00000000, 0x00000000, 0x0000cb18, 0x0000cb18, 0x0000cb18 },
- { 0x00009aac, 0x00000000, 0x00000000, 0x0000cb8c, 0x0000cb8c, 0x0000cb8c },
- { 0x00009ab0, 0x00000000, 0x00000000, 0x0000cb90, 0x0000cb90, 0x0000cb90 },
- { 0x00009ab4, 0x00000000, 0x00000000, 0x0000cf18, 0x0000cf18, 0x0000cf18 },
- { 0x00009ab8, 0x00000000, 0x00000000, 0x0000cf24, 0x0000cf24, 0x0000cf24 },
- { 0x00009abc, 0x00000000, 0x00000000, 0x0000cf28, 0x0000cf28, 0x0000cf28 },
- { 0x00009ac0, 0x00000000, 0x00000000, 0x0000d314, 0x0000d314, 0x0000d314 },
- { 0x00009ac4, 0x00000000, 0x00000000, 0x0000d318, 0x0000d318, 0x0000d318 },
- { 0x00009ac8, 0x00000000, 0x00000000, 0x0000d38c, 0x0000d38c, 0x0000d38c },
- { 0x00009acc, 0x00000000, 0x00000000, 0x0000d390, 0x0000d390, 0x0000d390 },
- { 0x00009ad0, 0x00000000, 0x00000000, 0x0000d394, 0x0000d394, 0x0000d394 },
- { 0x00009ad4, 0x00000000, 0x00000000, 0x0000d398, 0x0000d398, 0x0000d398 },
- { 0x00009ad8, 0x00000000, 0x00000000, 0x0000d3a4, 0x0000d3a4, 0x0000d3a4 },
- { 0x00009adc, 0x00000000, 0x00000000, 0x0000d3a8, 0x0000d3a8, 0x0000d3a8 },
- { 0x00009ae0, 0x00000000, 0x00000000, 0x0000d3ac, 0x0000d3ac, 0x0000d3ac },
- { 0x00009ae4, 0x00000000, 0x00000000, 0x0000d3b0, 0x0000d3b0, 0x0000d3b0 },
- { 0x00009ae8, 0x00000000, 0x00000000, 0x0000f380, 0x0000f380, 0x0000f380 },
- { 0x00009aec, 0x00000000, 0x00000000, 0x0000f384, 0x0000f384, 0x0000f384 },
- { 0x00009af0, 0x00000000, 0x00000000, 0x0000f388, 0x0000f388, 0x0000f388 },
- { 0x00009af4, 0x00000000, 0x00000000, 0x0000f710, 0x0000f710, 0x0000f710 },
- { 0x00009af8, 0x00000000, 0x00000000, 0x0000f714, 0x0000f714, 0x0000f714 },
- { 0x00009afc, 0x00000000, 0x00000000, 0x0000f718, 0x0000f718, 0x0000f718 },
- { 0x00009b00, 0x00000000, 0x00000000, 0x0000fb10, 0x0000fb10, 0x0000fb10 },
- { 0x00009b04, 0x00000000, 0x00000000, 0x0000fb14, 0x0000fb14, 0x0000fb14 },
- { 0x00009b08, 0x00000000, 0x00000000, 0x0000fb18, 0x0000fb18, 0x0000fb18 },
- { 0x00009b0c, 0x00000000, 0x00000000, 0x0000fb8c, 0x0000fb8c, 0x0000fb8c },
- { 0x00009b10, 0x00000000, 0x00000000, 0x0000fb90, 0x0000fb90, 0x0000fb90 },
- { 0x00009b14, 0x00000000, 0x00000000, 0x0000fb94, 0x0000fb94, 0x0000fb94 },
- { 0x00009b18, 0x00000000, 0x00000000, 0x0000ff8c, 0x0000ff8c, 0x0000ff8c },
- { 0x00009b1c, 0x00000000, 0x00000000, 0x0000ff90, 0x0000ff90, 0x0000ff90 },
- { 0x00009b20, 0x00000000, 0x00000000, 0x0000ff94, 0x0000ff94, 0x0000ff94 },
- { 0x00009b24, 0x00000000, 0x00000000, 0x0000ffa0, 0x0000ffa0, 0x0000ffa0 },
- { 0x00009b28, 0x00000000, 0x00000000, 0x0000ffa4, 0x0000ffa4, 0x0000ffa4 },
- { 0x00009b2c, 0x00000000, 0x00000000, 0x0000ffa8, 0x0000ffa8, 0x0000ffa8 },
- { 0x00009b30, 0x00000000, 0x00000000, 0x0000ffac, 0x0000ffac, 0x0000ffac },
- { 0x00009b34, 0x00000000, 0x00000000, 0x0000ffb0, 0x0000ffb0, 0x0000ffb0 },
- { 0x00009b38, 0x00000000, 0x00000000, 0x0000ffb4, 0x0000ffb4, 0x0000ffb4 },
- { 0x00009b3c, 0x00000000, 0x00000000, 0x0000ffa1, 0x0000ffa1, 0x0000ffa1 },
- { 0x00009b40, 0x00000000, 0x00000000, 0x0000ffa5, 0x0000ffa5, 0x0000ffa5 },
- { 0x00009b44, 0x00000000, 0x00000000, 0x0000ffa9, 0x0000ffa9, 0x0000ffa9 },
- { 0x00009b48, 0x00000000, 0x00000000, 0x0000ffad, 0x0000ffad, 0x0000ffad },
- { 0x00009b4c, 0x00000000, 0x00000000, 0x0000ffb1, 0x0000ffb1, 0x0000ffb1 },
- { 0x00009b50, 0x00000000, 0x00000000, 0x0000ffb5, 0x0000ffb5, 0x0000ffb5 },
- { 0x00009b54, 0x00000000, 0x00000000, 0x0000ffb9, 0x0000ffb9, 0x0000ffb9 },
- { 0x00009b58, 0x00000000, 0x00000000, 0x0000ffc5, 0x0000ffc5, 0x0000ffc5 },
- { 0x00009b5c, 0x00000000, 0x00000000, 0x0000ffc9, 0x0000ffc9, 0x0000ffc9 },
- { 0x00009b60, 0x00000000, 0x00000000, 0x0000ffcd, 0x0000ffcd, 0x0000ffcd },
- { 0x00009b64, 0x00000000, 0x00000000, 0x0000ffd1, 0x0000ffd1, 0x0000ffd1 },
- { 0x00009b68, 0x00000000, 0x00000000, 0x0000ffd5, 0x0000ffd5, 0x0000ffd5 },
- { 0x00009b6c, 0x00000000, 0x00000000, 0x0000ffc2, 0x0000ffc2, 0x0000ffc2 },
- { 0x00009b70, 0x00000000, 0x00000000, 0x0000ffc6, 0x0000ffc6, 0x0000ffc6 },
- { 0x00009b74, 0x00000000, 0x00000000, 0x0000ffca, 0x0000ffca, 0x0000ffca },
- { 0x00009b78, 0x00000000, 0x00000000, 0x0000ffce, 0x0000ffce, 0x0000ffce },
- { 0x00009b7c, 0x00000000, 0x00000000, 0x0000ffd2, 0x0000ffd2, 0x0000ffd2 },
- { 0x00009b80, 0x00000000, 0x00000000, 0x0000ffd6, 0x0000ffd6, 0x0000ffd6 },
- { 0x00009b84, 0x00000000, 0x00000000, 0x0000ffda, 0x0000ffda, 0x0000ffda },
- { 0x00009b88, 0x00000000, 0x00000000, 0x0000ffc7, 0x0000ffc7, 0x0000ffc7 },
- { 0x00009b8c, 0x00000000, 0x00000000, 0x0000ffcb, 0x0000ffcb, 0x0000ffcb },
- { 0x00009b90, 0x00000000, 0x00000000, 0x0000ffcf, 0x0000ffcf, 0x0000ffcf },
- { 0x00009b94, 0x00000000, 0x00000000, 0x0000ffd3, 0x0000ffd3, 0x0000ffd3 },
- { 0x00009b98, 0x00000000, 0x00000000, 0x0000ffd7, 0x0000ffd7, 0x0000ffd7 },
- { 0x00009b9c, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
- { 0x00009ba0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
- { 0x00009ba4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
- { 0x00009ba8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
- { 0x00009bac, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
- { 0x00009bb0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
- { 0x00009bb4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
- { 0x00009bb8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
- { 0x00009bbc, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
- { 0x00009bc0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
- { 0x00009bc4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
- { 0x00009bc8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
- { 0x00009bcc, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
- { 0x00009bd0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
- { 0x00009bd4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
- { 0x00009bd8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
- { 0x00009bdc, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
- { 0x00009be0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
- { 0x00009be4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
- { 0x00009be8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
- { 0x00009bec, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
- { 0x00009bf0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
- { 0x00009bf4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
- { 0x00009bf8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
- { 0x00009bfc, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
- { 0x0000aa00, 0x00000000, 0x00000000, 0x0000a120, 0x0000a120, 0x0000a120 },
- { 0x0000aa04, 0x00000000, 0x00000000, 0x0000a124, 0x0000a124, 0x0000a124 },
- { 0x0000aa08, 0x00000000, 0x00000000, 0x0000a128, 0x0000a128, 0x0000a128 },
- { 0x0000aa0c, 0x00000000, 0x00000000, 0x0000a12c, 0x0000a12c, 0x0000a12c },
- { 0x0000aa10, 0x00000000, 0x00000000, 0x0000a130, 0x0000a130, 0x0000a130 },
- { 0x0000aa14, 0x00000000, 0x00000000, 0x0000a194, 0x0000a194, 0x0000a194 },
- { 0x0000aa18, 0x00000000, 0x00000000, 0x0000a198, 0x0000a198, 0x0000a198 },
- { 0x0000aa1c, 0x00000000, 0x00000000, 0x0000a20c, 0x0000a20c, 0x0000a20c },
- { 0x0000aa20, 0x00000000, 0x00000000, 0x0000a210, 0x0000a210, 0x0000a210 },
- { 0x0000aa24, 0x00000000, 0x00000000, 0x0000a284, 0x0000a284, 0x0000a284 },
- { 0x0000aa28, 0x00000000, 0x00000000, 0x0000a288, 0x0000a288, 0x0000a288 },
- { 0x0000aa2c, 0x00000000, 0x00000000, 0x0000a28c, 0x0000a28c, 0x0000a28c },
- { 0x0000aa30, 0x00000000, 0x00000000, 0x0000a290, 0x0000a290, 0x0000a290 },
- { 0x0000aa34, 0x00000000, 0x00000000, 0x0000a294, 0x0000a294, 0x0000a294 },
- { 0x0000aa38, 0x00000000, 0x00000000, 0x0000a2a0, 0x0000a2a0, 0x0000a2a0 },
- { 0x0000aa3c, 0x00000000, 0x00000000, 0x0000a2a4, 0x0000a2a4, 0x0000a2a4 },
- { 0x0000aa40, 0x00000000, 0x00000000, 0x0000a2a8, 0x0000a2a8, 0x0000a2a8 },
- { 0x0000aa44, 0x00000000, 0x00000000, 0x0000a2ac, 0x0000a2ac, 0x0000a2ac },
- { 0x0000aa48, 0x00000000, 0x00000000, 0x0000a2b0, 0x0000a2b0, 0x0000a2b0 },
- { 0x0000aa4c, 0x00000000, 0x00000000, 0x0000a2b4, 0x0000a2b4, 0x0000a2b4 },
- { 0x0000aa50, 0x00000000, 0x00000000, 0x0000a2b8, 0x0000a2b8, 0x0000a2b8 },
- { 0x0000aa54, 0x00000000, 0x00000000, 0x0000a2c4, 0x0000a2c4, 0x0000a2c4 },
- { 0x0000aa58, 0x00000000, 0x00000000, 0x0000a708, 0x0000a708, 0x0000a708 },
- { 0x0000aa5c, 0x00000000, 0x00000000, 0x0000a70c, 0x0000a70c, 0x0000a70c },
- { 0x0000aa60, 0x00000000, 0x00000000, 0x0000a710, 0x0000a710, 0x0000a710 },
- { 0x0000aa64, 0x00000000, 0x00000000, 0x0000ab04, 0x0000ab04, 0x0000ab04 },
- { 0x0000aa68, 0x00000000, 0x00000000, 0x0000ab08, 0x0000ab08, 0x0000ab08 },
- { 0x0000aa6c, 0x00000000, 0x00000000, 0x0000ab0c, 0x0000ab0c, 0x0000ab0c },
- { 0x0000aa70, 0x00000000, 0x00000000, 0x0000ab10, 0x0000ab10, 0x0000ab10 },
- { 0x0000aa74, 0x00000000, 0x00000000, 0x0000ab14, 0x0000ab14, 0x0000ab14 },
- { 0x0000aa78, 0x00000000, 0x00000000, 0x0000ab18, 0x0000ab18, 0x0000ab18 },
- { 0x0000aa7c, 0x00000000, 0x00000000, 0x0000ab8c, 0x0000ab8c, 0x0000ab8c },
- { 0x0000aa80, 0x00000000, 0x00000000, 0x0000ab90, 0x0000ab90, 0x0000ab90 },
- { 0x0000aa84, 0x00000000, 0x00000000, 0x0000ab94, 0x0000ab94, 0x0000ab94 },
- { 0x0000aa88, 0x00000000, 0x00000000, 0x0000ab98, 0x0000ab98, 0x0000ab98 },
- { 0x0000aa8c, 0x00000000, 0x00000000, 0x0000aba4, 0x0000aba4, 0x0000aba4 },
- { 0x0000aa90, 0x00000000, 0x00000000, 0x0000aba8, 0x0000aba8, 0x0000aba8 },
- { 0x0000aa94, 0x00000000, 0x00000000, 0x0000cb04, 0x0000cb04, 0x0000cb04 },
- { 0x0000aa98, 0x00000000, 0x00000000, 0x0000cb08, 0x0000cb08, 0x0000cb08 },
- { 0x0000aa9c, 0x00000000, 0x00000000, 0x0000cb0c, 0x0000cb0c, 0x0000cb0c },
- { 0x0000aaa0, 0x00000000, 0x00000000, 0x0000cb10, 0x0000cb10, 0x0000cb10 },
- { 0x0000aaa4, 0x00000000, 0x00000000, 0x0000cb14, 0x0000cb14, 0x0000cb14 },
- { 0x0000aaa8, 0x00000000, 0x00000000, 0x0000cb18, 0x0000cb18, 0x0000cb18 },
- { 0x0000aaac, 0x00000000, 0x00000000, 0x0000cb8c, 0x0000cb8c, 0x0000cb8c },
- { 0x0000aab0, 0x00000000, 0x00000000, 0x0000cb90, 0x0000cb90, 0x0000cb90 },
- { 0x0000aab4, 0x00000000, 0x00000000, 0x0000cf18, 0x0000cf18, 0x0000cf18 },
- { 0x0000aab8, 0x00000000, 0x00000000, 0x0000cf24, 0x0000cf24, 0x0000cf24 },
- { 0x0000aabc, 0x00000000, 0x00000000, 0x0000cf28, 0x0000cf28, 0x0000cf28 },
- { 0x0000aac0, 0x00000000, 0x00000000, 0x0000d314, 0x0000d314, 0x0000d314 },
- { 0x0000aac4, 0x00000000, 0x00000000, 0x0000d318, 0x0000d318, 0x0000d318 },
- { 0x0000aac8, 0x00000000, 0x00000000, 0x0000d38c, 0x0000d38c, 0x0000d38c },
- { 0x0000aacc, 0x00000000, 0x00000000, 0x0000d390, 0x0000d390, 0x0000d390 },
- { 0x0000aad0, 0x00000000, 0x00000000, 0x0000d394, 0x0000d394, 0x0000d394 },
- { 0x0000aad4, 0x00000000, 0x00000000, 0x0000d398, 0x0000d398, 0x0000d398 },
- { 0x0000aad8, 0x00000000, 0x00000000, 0x0000d3a4, 0x0000d3a4, 0x0000d3a4 },
- { 0x0000aadc, 0x00000000, 0x00000000, 0x0000d3a8, 0x0000d3a8, 0x0000d3a8 },
- { 0x0000aae0, 0x00000000, 0x00000000, 0x0000d3ac, 0x0000d3ac, 0x0000d3ac },
- { 0x0000aae4, 0x00000000, 0x00000000, 0x0000d3b0, 0x0000d3b0, 0x0000d3b0 },
- { 0x0000aae8, 0x00000000, 0x00000000, 0x0000f380, 0x0000f380, 0x0000f380 },
- { 0x0000aaec, 0x00000000, 0x00000000, 0x0000f384, 0x0000f384, 0x0000f384 },
- { 0x0000aaf0, 0x00000000, 0x00000000, 0x0000f388, 0x0000f388, 0x0000f388 },
- { 0x0000aaf4, 0x00000000, 0x00000000, 0x0000f710, 0x0000f710, 0x0000f710 },
- { 0x0000aaf8, 0x00000000, 0x00000000, 0x0000f714, 0x0000f714, 0x0000f714 },
- { 0x0000aafc, 0x00000000, 0x00000000, 0x0000f718, 0x0000f718, 0x0000f718 },
- { 0x0000ab00, 0x00000000, 0x00000000, 0x0000fb10, 0x0000fb10, 0x0000fb10 },
- { 0x0000ab04, 0x00000000, 0x00000000, 0x0000fb14, 0x0000fb14, 0x0000fb14 },
- { 0x0000ab08, 0x00000000, 0x00000000, 0x0000fb18, 0x0000fb18, 0x0000fb18 },
- { 0x0000ab0c, 0x00000000, 0x00000000, 0x0000fb8c, 0x0000fb8c, 0x0000fb8c },
- { 0x0000ab10, 0x00000000, 0x00000000, 0x0000fb90, 0x0000fb90, 0x0000fb90 },
- { 0x0000ab14, 0x00000000, 0x00000000, 0x0000fb94, 0x0000fb94, 0x0000fb94 },
- { 0x0000ab18, 0x00000000, 0x00000000, 0x0000ff8c, 0x0000ff8c, 0x0000ff8c },
- { 0x0000ab1c, 0x00000000, 0x00000000, 0x0000ff90, 0x0000ff90, 0x0000ff90 },
- { 0x0000ab20, 0x00000000, 0x00000000, 0x0000ff94, 0x0000ff94, 0x0000ff94 },
- { 0x0000ab24, 0x00000000, 0x00000000, 0x0000ffa0, 0x0000ffa0, 0x0000ffa0 },
- { 0x0000ab28, 0x00000000, 0x00000000, 0x0000ffa4, 0x0000ffa4, 0x0000ffa4 },
- { 0x0000ab2c, 0x00000000, 0x00000000, 0x0000ffa8, 0x0000ffa8, 0x0000ffa8 },
- { 0x0000ab30, 0x00000000, 0x00000000, 0x0000ffac, 0x0000ffac, 0x0000ffac },
- { 0x0000ab34, 0x00000000, 0x00000000, 0x0000ffb0, 0x0000ffb0, 0x0000ffb0 },
- { 0x0000ab38, 0x00000000, 0x00000000, 0x0000ffb4, 0x0000ffb4, 0x0000ffb4 },
- { 0x0000ab3c, 0x00000000, 0x00000000, 0x0000ffa1, 0x0000ffa1, 0x0000ffa1 },
- { 0x0000ab40, 0x00000000, 0x00000000, 0x0000ffa5, 0x0000ffa5, 0x0000ffa5 },
- { 0x0000ab44, 0x00000000, 0x00000000, 0x0000ffa9, 0x0000ffa9, 0x0000ffa9 },
- { 0x0000ab48, 0x00000000, 0x00000000, 0x0000ffad, 0x0000ffad, 0x0000ffad },
- { 0x0000ab4c, 0x00000000, 0x00000000, 0x0000ffb1, 0x0000ffb1, 0x0000ffb1 },
- { 0x0000ab50, 0x00000000, 0x00000000, 0x0000ffb5, 0x0000ffb5, 0x0000ffb5 },
- { 0x0000ab54, 0x00000000, 0x00000000, 0x0000ffb9, 0x0000ffb9, 0x0000ffb9 },
- { 0x0000ab58, 0x00000000, 0x00000000, 0x0000ffc5, 0x0000ffc5, 0x0000ffc5 },
- { 0x0000ab5c, 0x00000000, 0x00000000, 0x0000ffc9, 0x0000ffc9, 0x0000ffc9 },
- { 0x0000ab60, 0x00000000, 0x00000000, 0x0000ffcd, 0x0000ffcd, 0x0000ffcd },
- { 0x0000ab64, 0x00000000, 0x00000000, 0x0000ffd1, 0x0000ffd1, 0x0000ffd1 },
- { 0x0000ab68, 0x00000000, 0x00000000, 0x0000ffd5, 0x0000ffd5, 0x0000ffd5 },
- { 0x0000ab6c, 0x00000000, 0x00000000, 0x0000ffc2, 0x0000ffc2, 0x0000ffc2 },
- { 0x0000ab70, 0x00000000, 0x00000000, 0x0000ffc6, 0x0000ffc6, 0x0000ffc6 },
- { 0x0000ab74, 0x00000000, 0x00000000, 0x0000ffca, 0x0000ffca, 0x0000ffca },
- { 0x0000ab78, 0x00000000, 0x00000000, 0x0000ffce, 0x0000ffce, 0x0000ffce },
- { 0x0000ab7c, 0x00000000, 0x00000000, 0x0000ffd2, 0x0000ffd2, 0x0000ffd2 },
- { 0x0000ab80, 0x00000000, 0x00000000, 0x0000ffd6, 0x0000ffd6, 0x0000ffd6 },
- { 0x0000ab84, 0x00000000, 0x00000000, 0x0000ffda, 0x0000ffda, 0x0000ffda },
- { 0x0000ab88, 0x00000000, 0x00000000, 0x0000ffc7, 0x0000ffc7, 0x0000ffc7 },
- { 0x0000ab8c, 0x00000000, 0x00000000, 0x0000ffcb, 0x0000ffcb, 0x0000ffcb },
- { 0x0000ab90, 0x00000000, 0x00000000, 0x0000ffcf, 0x0000ffcf, 0x0000ffcf },
- { 0x0000ab94, 0x00000000, 0x00000000, 0x0000ffd3, 0x0000ffd3, 0x0000ffd3 },
- { 0x0000ab98, 0x00000000, 0x00000000, 0x0000ffd7, 0x0000ffd7, 0x0000ffd7 },
- { 0x0000ab9c, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
- { 0x0000aba0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
- { 0x0000aba4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
- { 0x0000aba8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
- { 0x0000abac, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
- { 0x0000abb0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
- { 0x0000abb4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
- { 0x0000abb8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
- { 0x0000abbc, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
- { 0x0000abc0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
- { 0x0000abc4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
- { 0x0000abc8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
- { 0x0000abcc, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
- { 0x0000abd0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
- { 0x0000abd4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
- { 0x0000abd8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
- { 0x0000abdc, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
- { 0x0000abe0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
- { 0x0000abe4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
- { 0x0000abe8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
- { 0x0000abec, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
- { 0x0000abf0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
- { 0x0000abf4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
- { 0x0000abf8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
- { 0x0000abfc, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb },
- { 0x00009848, 0x00000000, 0x00000000, 0x00001067, 0x00001067, 0x00001067 },
- { 0x0000a848, 0x00000000, 0x00000000, 0x00001067, 0x00001067, 0x00001067 },
+ {0x00009a00, 0x00000000, 0x00000000, 0x0000a120, 0x0000a120, 0x0000a120},
+ {0x00009a04, 0x00000000, 0x00000000, 0x0000a124, 0x0000a124, 0x0000a124},
+ {0x00009a08, 0x00000000, 0x00000000, 0x0000a128, 0x0000a128, 0x0000a128},
+ {0x00009a0c, 0x00000000, 0x00000000, 0x0000a12c, 0x0000a12c, 0x0000a12c},
+ {0x00009a10, 0x00000000, 0x00000000, 0x0000a130, 0x0000a130, 0x0000a130},
+ {0x00009a14, 0x00000000, 0x00000000, 0x0000a194, 0x0000a194, 0x0000a194},
+ {0x00009a18, 0x00000000, 0x00000000, 0x0000a198, 0x0000a198, 0x0000a198},
+ {0x00009a1c, 0x00000000, 0x00000000, 0x0000a20c, 0x0000a20c, 0x0000a20c},
+ {0x00009a20, 0x00000000, 0x00000000, 0x0000a210, 0x0000a210, 0x0000a210},
+ {0x00009a24, 0x00000000, 0x00000000, 0x0000a284, 0x0000a284, 0x0000a284},
+ {0x00009a28, 0x00000000, 0x00000000, 0x0000a288, 0x0000a288, 0x0000a288},
+ {0x00009a2c, 0x00000000, 0x00000000, 0x0000a28c, 0x0000a28c, 0x0000a28c},
+ {0x00009a30, 0x00000000, 0x00000000, 0x0000a290, 0x0000a290, 0x0000a290},
+ {0x00009a34, 0x00000000, 0x00000000, 0x0000a294, 0x0000a294, 0x0000a294},
+ {0x00009a38, 0x00000000, 0x00000000, 0x0000a2a0, 0x0000a2a0, 0x0000a2a0},
+ {0x00009a3c, 0x00000000, 0x00000000, 0x0000a2a4, 0x0000a2a4, 0x0000a2a4},
+ {0x00009a40, 0x00000000, 0x00000000, 0x0000a2a8, 0x0000a2a8, 0x0000a2a8},
+ {0x00009a44, 0x00000000, 0x00000000, 0x0000a2ac, 0x0000a2ac, 0x0000a2ac},
+ {0x00009a48, 0x00000000, 0x00000000, 0x0000a2b0, 0x0000a2b0, 0x0000a2b0},
+ {0x00009a4c, 0x00000000, 0x00000000, 0x0000a2b4, 0x0000a2b4, 0x0000a2b4},
+ {0x00009a50, 0x00000000, 0x00000000, 0x0000a2b8, 0x0000a2b8, 0x0000a2b8},
+ {0x00009a54, 0x00000000, 0x00000000, 0x0000a2c4, 0x0000a2c4, 0x0000a2c4},
+ {0x00009a58, 0x00000000, 0x00000000, 0x0000a708, 0x0000a708, 0x0000a708},
+ {0x00009a5c, 0x00000000, 0x00000000, 0x0000a70c, 0x0000a70c, 0x0000a70c},
+ {0x00009a60, 0x00000000, 0x00000000, 0x0000a710, 0x0000a710, 0x0000a710},
+ {0x00009a64, 0x00000000, 0x00000000, 0x0000ab04, 0x0000ab04, 0x0000ab04},
+ {0x00009a68, 0x00000000, 0x00000000, 0x0000ab08, 0x0000ab08, 0x0000ab08},
+ {0x00009a6c, 0x00000000, 0x00000000, 0x0000ab0c, 0x0000ab0c, 0x0000ab0c},
+ {0x00009a70, 0x00000000, 0x00000000, 0x0000ab10, 0x0000ab10, 0x0000ab10},
+ {0x00009a74, 0x00000000, 0x00000000, 0x0000ab14, 0x0000ab14, 0x0000ab14},
+ {0x00009a78, 0x00000000, 0x00000000, 0x0000ab18, 0x0000ab18, 0x0000ab18},
+ {0x00009a7c, 0x00000000, 0x00000000, 0x0000ab8c, 0x0000ab8c, 0x0000ab8c},
+ {0x00009a80, 0x00000000, 0x00000000, 0x0000ab90, 0x0000ab90, 0x0000ab90},
+ {0x00009a84, 0x00000000, 0x00000000, 0x0000ab94, 0x0000ab94, 0x0000ab94},
+ {0x00009a88, 0x00000000, 0x00000000, 0x0000ab98, 0x0000ab98, 0x0000ab98},
+ {0x00009a8c, 0x00000000, 0x00000000, 0x0000aba4, 0x0000aba4, 0x0000aba4},
+ {0x00009a90, 0x00000000, 0x00000000, 0x0000aba8, 0x0000aba8, 0x0000aba8},
+ {0x00009a94, 0x00000000, 0x00000000, 0x0000cb04, 0x0000cb04, 0x0000cb04},
+ {0x00009a98, 0x00000000, 0x00000000, 0x0000cb08, 0x0000cb08, 0x0000cb08},
+ {0x00009a9c, 0x00000000, 0x00000000, 0x0000cb0c, 0x0000cb0c, 0x0000cb0c},
+ {0x00009aa0, 0x00000000, 0x00000000, 0x0000cb10, 0x0000cb10, 0x0000cb10},
+ {0x00009aa4, 0x00000000, 0x00000000, 0x0000cb14, 0x0000cb14, 0x0000cb14},
+ {0x00009aa8, 0x00000000, 0x00000000, 0x0000cb18, 0x0000cb18, 0x0000cb18},
+ {0x00009aac, 0x00000000, 0x00000000, 0x0000cb8c, 0x0000cb8c, 0x0000cb8c},
+ {0x00009ab0, 0x00000000, 0x00000000, 0x0000cb90, 0x0000cb90, 0x0000cb90},
+ {0x00009ab4, 0x00000000, 0x00000000, 0x0000cf18, 0x0000cf18, 0x0000cf18},
+ {0x00009ab8, 0x00000000, 0x00000000, 0x0000cf24, 0x0000cf24, 0x0000cf24},
+ {0x00009abc, 0x00000000, 0x00000000, 0x0000cf28, 0x0000cf28, 0x0000cf28},
+ {0x00009ac0, 0x00000000, 0x00000000, 0x0000d314, 0x0000d314, 0x0000d314},
+ {0x00009ac4, 0x00000000, 0x00000000, 0x0000d318, 0x0000d318, 0x0000d318},
+ {0x00009ac8, 0x00000000, 0x00000000, 0x0000d38c, 0x0000d38c, 0x0000d38c},
+ {0x00009acc, 0x00000000, 0x00000000, 0x0000d390, 0x0000d390, 0x0000d390},
+ {0x00009ad0, 0x00000000, 0x00000000, 0x0000d394, 0x0000d394, 0x0000d394},
+ {0x00009ad4, 0x00000000, 0x00000000, 0x0000d398, 0x0000d398, 0x0000d398},
+ {0x00009ad8, 0x00000000, 0x00000000, 0x0000d3a4, 0x0000d3a4, 0x0000d3a4},
+ {0x00009adc, 0x00000000, 0x00000000, 0x0000d3a8, 0x0000d3a8, 0x0000d3a8},
+ {0x00009ae0, 0x00000000, 0x00000000, 0x0000d3ac, 0x0000d3ac, 0x0000d3ac},
+ {0x00009ae4, 0x00000000, 0x00000000, 0x0000d3b0, 0x0000d3b0, 0x0000d3b0},
+ {0x00009ae8, 0x00000000, 0x00000000, 0x0000f380, 0x0000f380, 0x0000f380},
+ {0x00009aec, 0x00000000, 0x00000000, 0x0000f384, 0x0000f384, 0x0000f384},
+ {0x00009af0, 0x00000000, 0x00000000, 0x0000f388, 0x0000f388, 0x0000f388},
+ {0x00009af4, 0x00000000, 0x00000000, 0x0000f710, 0x0000f710, 0x0000f710},
+ {0x00009af8, 0x00000000, 0x00000000, 0x0000f714, 0x0000f714, 0x0000f714},
+ {0x00009afc, 0x00000000, 0x00000000, 0x0000f718, 0x0000f718, 0x0000f718},
+ {0x00009b00, 0x00000000, 0x00000000, 0x0000fb10, 0x0000fb10, 0x0000fb10},
+ {0x00009b04, 0x00000000, 0x00000000, 0x0000fb14, 0x0000fb14, 0x0000fb14},
+ {0x00009b08, 0x00000000, 0x00000000, 0x0000fb18, 0x0000fb18, 0x0000fb18},
+ {0x00009b0c, 0x00000000, 0x00000000, 0x0000fb8c, 0x0000fb8c, 0x0000fb8c},
+ {0x00009b10, 0x00000000, 0x00000000, 0x0000fb90, 0x0000fb90, 0x0000fb90},
+ {0x00009b14, 0x00000000, 0x00000000, 0x0000fb94, 0x0000fb94, 0x0000fb94},
+ {0x00009b18, 0x00000000, 0x00000000, 0x0000ff8c, 0x0000ff8c, 0x0000ff8c},
+ {0x00009b1c, 0x00000000, 0x00000000, 0x0000ff90, 0x0000ff90, 0x0000ff90},
+ {0x00009b20, 0x00000000, 0x00000000, 0x0000ff94, 0x0000ff94, 0x0000ff94},
+ {0x00009b24, 0x00000000, 0x00000000, 0x0000ffa0, 0x0000ffa0, 0x0000ffa0},
+ {0x00009b28, 0x00000000, 0x00000000, 0x0000ffa4, 0x0000ffa4, 0x0000ffa4},
+ {0x00009b2c, 0x00000000, 0x00000000, 0x0000ffa8, 0x0000ffa8, 0x0000ffa8},
+ {0x00009b30, 0x00000000, 0x00000000, 0x0000ffac, 0x0000ffac, 0x0000ffac},
+ {0x00009b34, 0x00000000, 0x00000000, 0x0000ffb0, 0x0000ffb0, 0x0000ffb0},
+ {0x00009b38, 0x00000000, 0x00000000, 0x0000ffb4, 0x0000ffb4, 0x0000ffb4},
+ {0x00009b3c, 0x00000000, 0x00000000, 0x0000ffa1, 0x0000ffa1, 0x0000ffa1},
+ {0x00009b40, 0x00000000, 0x00000000, 0x0000ffa5, 0x0000ffa5, 0x0000ffa5},
+ {0x00009b44, 0x00000000, 0x00000000, 0x0000ffa9, 0x0000ffa9, 0x0000ffa9},
+ {0x00009b48, 0x00000000, 0x00000000, 0x0000ffad, 0x0000ffad, 0x0000ffad},
+ {0x00009b4c, 0x00000000, 0x00000000, 0x0000ffb1, 0x0000ffb1, 0x0000ffb1},
+ {0x00009b50, 0x00000000, 0x00000000, 0x0000ffb5, 0x0000ffb5, 0x0000ffb5},
+ {0x00009b54, 0x00000000, 0x00000000, 0x0000ffb9, 0x0000ffb9, 0x0000ffb9},
+ {0x00009b58, 0x00000000, 0x00000000, 0x0000ffc5, 0x0000ffc5, 0x0000ffc5},
+ {0x00009b5c, 0x00000000, 0x00000000, 0x0000ffc9, 0x0000ffc9, 0x0000ffc9},
+ {0x00009b60, 0x00000000, 0x00000000, 0x0000ffcd, 0x0000ffcd, 0x0000ffcd},
+ {0x00009b64, 0x00000000, 0x00000000, 0x0000ffd1, 0x0000ffd1, 0x0000ffd1},
+ {0x00009b68, 0x00000000, 0x00000000, 0x0000ffd5, 0x0000ffd5, 0x0000ffd5},
+ {0x00009b6c, 0x00000000, 0x00000000, 0x0000ffc2, 0x0000ffc2, 0x0000ffc2},
+ {0x00009b70, 0x00000000, 0x00000000, 0x0000ffc6, 0x0000ffc6, 0x0000ffc6},
+ {0x00009b74, 0x00000000, 0x00000000, 0x0000ffca, 0x0000ffca, 0x0000ffca},
+ {0x00009b78, 0x00000000, 0x00000000, 0x0000ffce, 0x0000ffce, 0x0000ffce},
+ {0x00009b7c, 0x00000000, 0x00000000, 0x0000ffd2, 0x0000ffd2, 0x0000ffd2},
+ {0x00009b80, 0x00000000, 0x00000000, 0x0000ffd6, 0x0000ffd6, 0x0000ffd6},
+ {0x00009b84, 0x00000000, 0x00000000, 0x0000ffda, 0x0000ffda, 0x0000ffda},
+ {0x00009b88, 0x00000000, 0x00000000, 0x0000ffc7, 0x0000ffc7, 0x0000ffc7},
+ {0x00009b8c, 0x00000000, 0x00000000, 0x0000ffcb, 0x0000ffcb, 0x0000ffcb},
+ {0x00009b90, 0x00000000, 0x00000000, 0x0000ffcf, 0x0000ffcf, 0x0000ffcf},
+ {0x00009b94, 0x00000000, 0x00000000, 0x0000ffd3, 0x0000ffd3, 0x0000ffd3},
+ {0x00009b98, 0x00000000, 0x00000000, 0x0000ffd7, 0x0000ffd7, 0x0000ffd7},
+ {0x00009b9c, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
+ {0x00009ba0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
+ {0x00009ba4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
+ {0x00009ba8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
+ {0x00009bac, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
+ {0x00009bb0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
+ {0x00009bb4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
+ {0x00009bb8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
+ {0x00009bbc, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
+ {0x00009bc0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
+ {0x00009bc4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
+ {0x00009bc8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
+ {0x00009bcc, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
+ {0x00009bd0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
+ {0x00009bd4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
+ {0x00009bd8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
+ {0x00009bdc, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
+ {0x00009be0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
+ {0x00009be4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
+ {0x00009be8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
+ {0x00009bec, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
+ {0x00009bf0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
+ {0x00009bf4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
+ {0x00009bf8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
+ {0x00009bfc, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
+ {0x0000aa00, 0x00000000, 0x00000000, 0x0000a120, 0x0000a120, 0x0000a120},
+ {0x0000aa04, 0x00000000, 0x00000000, 0x0000a124, 0x0000a124, 0x0000a124},
+ {0x0000aa08, 0x00000000, 0x00000000, 0x0000a128, 0x0000a128, 0x0000a128},
+ {0x0000aa0c, 0x00000000, 0x00000000, 0x0000a12c, 0x0000a12c, 0x0000a12c},
+ {0x0000aa10, 0x00000000, 0x00000000, 0x0000a130, 0x0000a130, 0x0000a130},
+ {0x0000aa14, 0x00000000, 0x00000000, 0x0000a194, 0x0000a194, 0x0000a194},
+ {0x0000aa18, 0x00000000, 0x00000000, 0x0000a198, 0x0000a198, 0x0000a198},
+ {0x0000aa1c, 0x00000000, 0x00000000, 0x0000a20c, 0x0000a20c, 0x0000a20c},
+ {0x0000aa20, 0x00000000, 0x00000000, 0x0000a210, 0x0000a210, 0x0000a210},
+ {0x0000aa24, 0x00000000, 0x00000000, 0x0000a284, 0x0000a284, 0x0000a284},
+ {0x0000aa28, 0x00000000, 0x00000000, 0x0000a288, 0x0000a288, 0x0000a288},
+ {0x0000aa2c, 0x00000000, 0x00000000, 0x0000a28c, 0x0000a28c, 0x0000a28c},
+ {0x0000aa30, 0x00000000, 0x00000000, 0x0000a290, 0x0000a290, 0x0000a290},
+ {0x0000aa34, 0x00000000, 0x00000000, 0x0000a294, 0x0000a294, 0x0000a294},
+ {0x0000aa38, 0x00000000, 0x00000000, 0x0000a2a0, 0x0000a2a0, 0x0000a2a0},
+ {0x0000aa3c, 0x00000000, 0x00000000, 0x0000a2a4, 0x0000a2a4, 0x0000a2a4},
+ {0x0000aa40, 0x00000000, 0x00000000, 0x0000a2a8, 0x0000a2a8, 0x0000a2a8},
+ {0x0000aa44, 0x00000000, 0x00000000, 0x0000a2ac, 0x0000a2ac, 0x0000a2ac},
+ {0x0000aa48, 0x00000000, 0x00000000, 0x0000a2b0, 0x0000a2b0, 0x0000a2b0},
+ {0x0000aa4c, 0x00000000, 0x00000000, 0x0000a2b4, 0x0000a2b4, 0x0000a2b4},
+ {0x0000aa50, 0x00000000, 0x00000000, 0x0000a2b8, 0x0000a2b8, 0x0000a2b8},
+ {0x0000aa54, 0x00000000, 0x00000000, 0x0000a2c4, 0x0000a2c4, 0x0000a2c4},
+ {0x0000aa58, 0x00000000, 0x00000000, 0x0000a708, 0x0000a708, 0x0000a708},
+ {0x0000aa5c, 0x00000000, 0x00000000, 0x0000a70c, 0x0000a70c, 0x0000a70c},
+ {0x0000aa60, 0x00000000, 0x00000000, 0x0000a710, 0x0000a710, 0x0000a710},
+ {0x0000aa64, 0x00000000, 0x00000000, 0x0000ab04, 0x0000ab04, 0x0000ab04},
+ {0x0000aa68, 0x00000000, 0x00000000, 0x0000ab08, 0x0000ab08, 0x0000ab08},
+ {0x0000aa6c, 0x00000000, 0x00000000, 0x0000ab0c, 0x0000ab0c, 0x0000ab0c},
+ {0x0000aa70, 0x00000000, 0x00000000, 0x0000ab10, 0x0000ab10, 0x0000ab10},
+ {0x0000aa74, 0x00000000, 0x00000000, 0x0000ab14, 0x0000ab14, 0x0000ab14},
+ {0x0000aa78, 0x00000000, 0x00000000, 0x0000ab18, 0x0000ab18, 0x0000ab18},
+ {0x0000aa7c, 0x00000000, 0x00000000, 0x0000ab8c, 0x0000ab8c, 0x0000ab8c},
+ {0x0000aa80, 0x00000000, 0x00000000, 0x0000ab90, 0x0000ab90, 0x0000ab90},
+ {0x0000aa84, 0x00000000, 0x00000000, 0x0000ab94, 0x0000ab94, 0x0000ab94},
+ {0x0000aa88, 0x00000000, 0x00000000, 0x0000ab98, 0x0000ab98, 0x0000ab98},
+ {0x0000aa8c, 0x00000000, 0x00000000, 0x0000aba4, 0x0000aba4, 0x0000aba4},
+ {0x0000aa90, 0x00000000, 0x00000000, 0x0000aba8, 0x0000aba8, 0x0000aba8},
+ {0x0000aa94, 0x00000000, 0x00000000, 0x0000cb04, 0x0000cb04, 0x0000cb04},
+ {0x0000aa98, 0x00000000, 0x00000000, 0x0000cb08, 0x0000cb08, 0x0000cb08},
+ {0x0000aa9c, 0x00000000, 0x00000000, 0x0000cb0c, 0x0000cb0c, 0x0000cb0c},
+ {0x0000aaa0, 0x00000000, 0x00000000, 0x0000cb10, 0x0000cb10, 0x0000cb10},
+ {0x0000aaa4, 0x00000000, 0x00000000, 0x0000cb14, 0x0000cb14, 0x0000cb14},
+ {0x0000aaa8, 0x00000000, 0x00000000, 0x0000cb18, 0x0000cb18, 0x0000cb18},
+ {0x0000aaac, 0x00000000, 0x00000000, 0x0000cb8c, 0x0000cb8c, 0x0000cb8c},
+ {0x0000aab0, 0x00000000, 0x00000000, 0x0000cb90, 0x0000cb90, 0x0000cb90},
+ {0x0000aab4, 0x00000000, 0x00000000, 0x0000cf18, 0x0000cf18, 0x0000cf18},
+ {0x0000aab8, 0x00000000, 0x00000000, 0x0000cf24, 0x0000cf24, 0x0000cf24},
+ {0x0000aabc, 0x00000000, 0x00000000, 0x0000cf28, 0x0000cf28, 0x0000cf28},
+ {0x0000aac0, 0x00000000, 0x00000000, 0x0000d314, 0x0000d314, 0x0000d314},
+ {0x0000aac4, 0x00000000, 0x00000000, 0x0000d318, 0x0000d318, 0x0000d318},
+ {0x0000aac8, 0x00000000, 0x00000000, 0x0000d38c, 0x0000d38c, 0x0000d38c},
+ {0x0000aacc, 0x00000000, 0x00000000, 0x0000d390, 0x0000d390, 0x0000d390},
+ {0x0000aad0, 0x00000000, 0x00000000, 0x0000d394, 0x0000d394, 0x0000d394},
+ {0x0000aad4, 0x00000000, 0x00000000, 0x0000d398, 0x0000d398, 0x0000d398},
+ {0x0000aad8, 0x00000000, 0x00000000, 0x0000d3a4, 0x0000d3a4, 0x0000d3a4},
+ {0x0000aadc, 0x00000000, 0x00000000, 0x0000d3a8, 0x0000d3a8, 0x0000d3a8},
+ {0x0000aae0, 0x00000000, 0x00000000, 0x0000d3ac, 0x0000d3ac, 0x0000d3ac},
+ {0x0000aae4, 0x00000000, 0x00000000, 0x0000d3b0, 0x0000d3b0, 0x0000d3b0},
+ {0x0000aae8, 0x00000000, 0x00000000, 0x0000f380, 0x0000f380, 0x0000f380},
+ {0x0000aaec, 0x00000000, 0x00000000, 0x0000f384, 0x0000f384, 0x0000f384},
+ {0x0000aaf0, 0x00000000, 0x00000000, 0x0000f388, 0x0000f388, 0x0000f388},
+ {0x0000aaf4, 0x00000000, 0x00000000, 0x0000f710, 0x0000f710, 0x0000f710},
+ {0x0000aaf8, 0x00000000, 0x00000000, 0x0000f714, 0x0000f714, 0x0000f714},
+ {0x0000aafc, 0x00000000, 0x00000000, 0x0000f718, 0x0000f718, 0x0000f718},
+ {0x0000ab00, 0x00000000, 0x00000000, 0x0000fb10, 0x0000fb10, 0x0000fb10},
+ {0x0000ab04, 0x00000000, 0x00000000, 0x0000fb14, 0x0000fb14, 0x0000fb14},
+ {0x0000ab08, 0x00000000, 0x00000000, 0x0000fb18, 0x0000fb18, 0x0000fb18},
+ {0x0000ab0c, 0x00000000, 0x00000000, 0x0000fb8c, 0x0000fb8c, 0x0000fb8c},
+ {0x0000ab10, 0x00000000, 0x00000000, 0x0000fb90, 0x0000fb90, 0x0000fb90},
+ {0x0000ab14, 0x00000000, 0x00000000, 0x0000fb94, 0x0000fb94, 0x0000fb94},
+ {0x0000ab18, 0x00000000, 0x00000000, 0x0000ff8c, 0x0000ff8c, 0x0000ff8c},
+ {0x0000ab1c, 0x00000000, 0x00000000, 0x0000ff90, 0x0000ff90, 0x0000ff90},
+ {0x0000ab20, 0x00000000, 0x00000000, 0x0000ff94, 0x0000ff94, 0x0000ff94},
+ {0x0000ab24, 0x00000000, 0x00000000, 0x0000ffa0, 0x0000ffa0, 0x0000ffa0},
+ {0x0000ab28, 0x00000000, 0x00000000, 0x0000ffa4, 0x0000ffa4, 0x0000ffa4},
+ {0x0000ab2c, 0x00000000, 0x00000000, 0x0000ffa8, 0x0000ffa8, 0x0000ffa8},
+ {0x0000ab30, 0x00000000, 0x00000000, 0x0000ffac, 0x0000ffac, 0x0000ffac},
+ {0x0000ab34, 0x00000000, 0x00000000, 0x0000ffb0, 0x0000ffb0, 0x0000ffb0},
+ {0x0000ab38, 0x00000000, 0x00000000, 0x0000ffb4, 0x0000ffb4, 0x0000ffb4},
+ {0x0000ab3c, 0x00000000, 0x00000000, 0x0000ffa1, 0x0000ffa1, 0x0000ffa1},
+ {0x0000ab40, 0x00000000, 0x00000000, 0x0000ffa5, 0x0000ffa5, 0x0000ffa5},
+ {0x0000ab44, 0x00000000, 0x00000000, 0x0000ffa9, 0x0000ffa9, 0x0000ffa9},
+ {0x0000ab48, 0x00000000, 0x00000000, 0x0000ffad, 0x0000ffad, 0x0000ffad},
+ {0x0000ab4c, 0x00000000, 0x00000000, 0x0000ffb1, 0x0000ffb1, 0x0000ffb1},
+ {0x0000ab50, 0x00000000, 0x00000000, 0x0000ffb5, 0x0000ffb5, 0x0000ffb5},
+ {0x0000ab54, 0x00000000, 0x00000000, 0x0000ffb9, 0x0000ffb9, 0x0000ffb9},
+ {0x0000ab58, 0x00000000, 0x00000000, 0x0000ffc5, 0x0000ffc5, 0x0000ffc5},
+ {0x0000ab5c, 0x00000000, 0x00000000, 0x0000ffc9, 0x0000ffc9, 0x0000ffc9},
+ {0x0000ab60, 0x00000000, 0x00000000, 0x0000ffcd, 0x0000ffcd, 0x0000ffcd},
+ {0x0000ab64, 0x00000000, 0x00000000, 0x0000ffd1, 0x0000ffd1, 0x0000ffd1},
+ {0x0000ab68, 0x00000000, 0x00000000, 0x0000ffd5, 0x0000ffd5, 0x0000ffd5},
+ {0x0000ab6c, 0x00000000, 0x00000000, 0x0000ffc2, 0x0000ffc2, 0x0000ffc2},
+ {0x0000ab70, 0x00000000, 0x00000000, 0x0000ffc6, 0x0000ffc6, 0x0000ffc6},
+ {0x0000ab74, 0x00000000, 0x00000000, 0x0000ffca, 0x0000ffca, 0x0000ffca},
+ {0x0000ab78, 0x00000000, 0x00000000, 0x0000ffce, 0x0000ffce, 0x0000ffce},
+ {0x0000ab7c, 0x00000000, 0x00000000, 0x0000ffd2, 0x0000ffd2, 0x0000ffd2},
+ {0x0000ab80, 0x00000000, 0x00000000, 0x0000ffd6, 0x0000ffd6, 0x0000ffd6},
+ {0x0000ab84, 0x00000000, 0x00000000, 0x0000ffda, 0x0000ffda, 0x0000ffda},
+ {0x0000ab88, 0x00000000, 0x00000000, 0x0000ffc7, 0x0000ffc7, 0x0000ffc7},
+ {0x0000ab8c, 0x00000000, 0x00000000, 0x0000ffcb, 0x0000ffcb, 0x0000ffcb},
+ {0x0000ab90, 0x00000000, 0x00000000, 0x0000ffcf, 0x0000ffcf, 0x0000ffcf},
+ {0x0000ab94, 0x00000000, 0x00000000, 0x0000ffd3, 0x0000ffd3, 0x0000ffd3},
+ {0x0000ab98, 0x00000000, 0x00000000, 0x0000ffd7, 0x0000ffd7, 0x0000ffd7},
+ {0x0000ab9c, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
+ {0x0000aba0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
+ {0x0000aba4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
+ {0x0000aba8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
+ {0x0000abac, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
+ {0x0000abb0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
+ {0x0000abb4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
+ {0x0000abb8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
+ {0x0000abbc, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
+ {0x0000abc0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
+ {0x0000abc4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
+ {0x0000abc8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
+ {0x0000abcc, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
+ {0x0000abd0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
+ {0x0000abd4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
+ {0x0000abd8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
+ {0x0000abdc, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
+ {0x0000abe0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
+ {0x0000abe4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
+ {0x0000abe8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
+ {0x0000abec, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
+ {0x0000abf0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
+ {0x0000abf4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
+ {0x0000abf8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
+ {0x0000abfc, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
+ {0x00009848, 0x00000000, 0x00000000, 0x00001067, 0x00001067, 0x00001067},
+ {0x0000a848, 0x00000000, 0x00000000, 0x00001067, 0x00001067, 0x00001067},
};
static const u32 ar9287PciePhy_clkreq_always_on_L1_9287_1_1[][2] = {
- {0x00004040, 0x9248fd00 },
- {0x00004040, 0x24924924 },
- {0x00004040, 0xa8000019 },
- {0x00004040, 0x13160820 },
- {0x00004040, 0xe5980560 },
- {0x00004040, 0xc01dcffd },
- {0x00004040, 0x1aaabe41 },
- {0x00004040, 0xbe105554 },
- {0x00004040, 0x00043007 },
- {0x00004044, 0x00000000 },
+ /* Addr allmodes */
+ {0x00004040, 0x9248fd00},
+ {0x00004040, 0x24924924},
+ {0x00004040, 0xa8000019},
+ {0x00004040, 0x13160820},
+ {0x00004040, 0xe5980560},
+ {0x00004040, 0xc01dcffd},
+ {0x00004040, 0x1aaabe41},
+ {0x00004040, 0xbe105554},
+ {0x00004040, 0x00043007},
+ {0x00004044, 0x00000000},
};
static const u32 ar9287PciePhy_clkreq_off_L1_9287_1_1[][2] = {
- {0x00004040, 0x9248fd00 },
- {0x00004040, 0x24924924 },
- {0x00004040, 0xa8000019 },
- {0x00004040, 0x13160820 },
- {0x00004040, 0xe5980560 },
- {0x00004040, 0xc01dcffc },
- {0x00004040, 0x1aaabe41 },
- {0x00004040, 0xbe105554 },
- {0x00004040, 0x00043007 },
- {0x00004044, 0x00000000 },
+ /* Addr allmodes */
+ {0x00004040, 0x9248fd00},
+ {0x00004040, 0x24924924},
+ {0x00004040, 0xa8000019},
+ {0x00004040, 0x13160820},
+ {0x00004040, 0xe5980560},
+ {0x00004040, 0xc01dcffc},
+ {0x00004040, 0x1aaabe41},
+ {0x00004040, 0xbe105554},
+ {0x00004040, 0x00043007},
+ {0x00004044, 0x00000000},
};
-
-/* AR9271 initialization values automaticaly created: 06/04/09 */
static const u32 ar9271Modes_9271[][6] = {
- { 0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160, 0x000001e0 },
- { 0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c, 0x000001e0 },
- { 0x000010b0, 0x00000e60, 0x00001cc0, 0x00007c70, 0x00003e38, 0x00001180 },
- { 0x000010f0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000008 },
- { 0x00008014, 0x03e803e8, 0x07d007d0, 0x10801600, 0x08400b00, 0x06e006e0 },
- { 0x0000801c, 0x128d8027, 0x128d804f, 0x12e00057, 0x12e0002b, 0x0988004f },
- { 0x00008318, 0x00003e80, 0x00007d00, 0x00006880, 0x00003440, 0x00006880 },
- { 0x00009804, 0x00000300, 0x000003c4, 0x000003c4, 0x00000300, 0x00000303 },
- { 0x00009820, 0x02020200, 0x02020200, 0x02020200, 0x02020200, 0x02020200 },
- { 0x00009824, 0x01000e0e, 0x01000e0e, 0x01000e0e, 0x01000e0e, 0x01000e0e },
- { 0x00009828, 0x3a020001, 0x3a020001, 0x3a020001, 0x3a020001, 0x3a020001 },
- { 0x00009834, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e },
- { 0x00009838, 0x00000007, 0x00000007, 0x00000007, 0x00000007, 0x00000007 },
- { 0x00009840, 0x206a012e, 0x206a012e, 0x206a012e, 0x206a012e, 0x206a012e },
- { 0x00009844, 0x0372161e, 0x0372161e, 0x03721620, 0x03721620, 0x037216a0 },
- { 0x00009848, 0x00001066, 0x00001066, 0x00001053, 0x00001053, 0x00001059 },
- { 0x0000a848, 0x00001066, 0x00001066, 0x00001053, 0x00001053, 0x00001059 },
- { 0x00009850, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2 },
- { 0x00009858, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e },
- { 0x0000985c, 0x3139605e, 0x3139605e, 0x3137605e, 0x3137605e, 0x3139605e },
- { 0x00009860, 0x00058d18, 0x00058d18, 0x00058d18, 0x00058d18, 0x00058d18 },
- { 0x00009864, 0x0000fe00, 0x0000fe00, 0x0001ce00, 0x0001ce00, 0x0001ce00 },
- { 0x00009868, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0 },
- { 0x0000986c, 0x06903081, 0x06903081, 0x06903881, 0x06903881, 0x06903881 },
- { 0x00009910, 0x30002310, 0x30002310, 0x30002310, 0x30002310, 0x30002310 },
- { 0x00009914, 0x000007d0, 0x00000fa0, 0x00001130, 0x00000898, 0x000007d0 },
- { 0x00009918, 0x0000000a, 0x00000014, 0x00000016, 0x0000000b, 0x00000016 },
- { 0x00009924, 0xd00a8007, 0xd00a8007, 0xd00a800d, 0xd00a800d, 0xd00a800d },
- { 0x00009944, 0xffbc1010, 0xffbc1010, 0xffbc1020, 0xffbc1020, 0xffbc1010 },
- { 0x00009960, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
- { 0x00009964, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
- { 0x000099b8, 0x0000421c, 0x0000421c, 0x0000421c, 0x0000421c, 0x0000421c },
- { 0x000099bc, 0x00000600, 0x00000600, 0x00000c00, 0x00000c00, 0x00000c00 },
- { 0x000099c0, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4 },
- { 0x000099c4, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77 },
- { 0x000099c8, 0x6af6532f, 0x6af6532f, 0x6af6532f, 0x6af6532f, 0x6af6532f },
- { 0x000099cc, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8 },
- { 0x000099d0, 0x00046384, 0x00046384, 0x00046384, 0x00046384, 0x00046384 },
- { 0x000099d4, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
- { 0x000099d8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
- { 0x00009a00, 0x00000000, 0x00000000, 0x00058084, 0x00058084, 0x00000000 },
- { 0x00009a04, 0x00000000, 0x00000000, 0x00058088, 0x00058088, 0x00000000 },
- { 0x00009a08, 0x00000000, 0x00000000, 0x0005808c, 0x0005808c, 0x00000000 },
- { 0x00009a0c, 0x00000000, 0x00000000, 0x00058100, 0x00058100, 0x00000000 },
- { 0x00009a10, 0x00000000, 0x00000000, 0x00058104, 0x00058104, 0x00000000 },
- { 0x00009a14, 0x00000000, 0x00000000, 0x00058108, 0x00058108, 0x00000000 },
- { 0x00009a18, 0x00000000, 0x00000000, 0x0005810c, 0x0005810c, 0x00000000 },
- { 0x00009a1c, 0x00000000, 0x00000000, 0x00058110, 0x00058110, 0x00000000 },
- { 0x00009a20, 0x00000000, 0x00000000, 0x00058114, 0x00058114, 0x00000000 },
- { 0x00009a24, 0x00000000, 0x00000000, 0x00058180, 0x00058180, 0x00000000 },
- { 0x00009a28, 0x00000000, 0x00000000, 0x00058184, 0x00058184, 0x00000000 },
- { 0x00009a2c, 0x00000000, 0x00000000, 0x00058188, 0x00058188, 0x00000000 },
- { 0x00009a30, 0x00000000, 0x00000000, 0x0005818c, 0x0005818c, 0x00000000 },
- { 0x00009a34, 0x00000000, 0x00000000, 0x00058190, 0x00058190, 0x00000000 },
- { 0x00009a38, 0x00000000, 0x00000000, 0x00058194, 0x00058194, 0x00000000 },
- { 0x00009a3c, 0x00000000, 0x00000000, 0x000581a0, 0x000581a0, 0x00000000 },
- { 0x00009a40, 0x00000000, 0x00000000, 0x0005820c, 0x0005820c, 0x00000000 },
- { 0x00009a44, 0x00000000, 0x00000000, 0x000581a8, 0x000581a8, 0x00000000 },
- { 0x00009a48, 0x00000000, 0x00000000, 0x00058284, 0x00058284, 0x00000000 },
- { 0x00009a4c, 0x00000000, 0x00000000, 0x00058288, 0x00058288, 0x00000000 },
- { 0x00009a50, 0x00000000, 0x00000000, 0x00058224, 0x00058224, 0x00000000 },
- { 0x00009a54, 0x00000000, 0x00000000, 0x00058290, 0x00058290, 0x00000000 },
- { 0x00009a58, 0x00000000, 0x00000000, 0x00058300, 0x00058300, 0x00000000 },
- { 0x00009a5c, 0x00000000, 0x00000000, 0x00058304, 0x00058304, 0x00000000 },
- { 0x00009a60, 0x00000000, 0x00000000, 0x00058308, 0x00058308, 0x00000000 },
- { 0x00009a64, 0x00000000, 0x00000000, 0x0005830c, 0x0005830c, 0x00000000 },
- { 0x00009a68, 0x00000000, 0x00000000, 0x00058380, 0x00058380, 0x00000000 },
- { 0x00009a6c, 0x00000000, 0x00000000, 0x00058384, 0x00058384, 0x00000000 },
- { 0x00009a70, 0x00000000, 0x00000000, 0x00068700, 0x00068700, 0x00000000 },
- { 0x00009a74, 0x00000000, 0x00000000, 0x00068704, 0x00068704, 0x00000000 },
- { 0x00009a78, 0x00000000, 0x00000000, 0x00068708, 0x00068708, 0x00000000 },
- { 0x00009a7c, 0x00000000, 0x00000000, 0x0006870c, 0x0006870c, 0x00000000 },
- { 0x00009a80, 0x00000000, 0x00000000, 0x00068780, 0x00068780, 0x00000000 },
- { 0x00009a84, 0x00000000, 0x00000000, 0x00068784, 0x00068784, 0x00000000 },
- { 0x00009a88, 0x00000000, 0x00000000, 0x00078b00, 0x00078b00, 0x00000000 },
- { 0x00009a8c, 0x00000000, 0x00000000, 0x00078b04, 0x00078b04, 0x00000000 },
- { 0x00009a90, 0x00000000, 0x00000000, 0x00078b08, 0x00078b08, 0x00000000 },
- { 0x00009a94, 0x00000000, 0x00000000, 0x00078b0c, 0x00078b0c, 0x00000000 },
- { 0x00009a98, 0x00000000, 0x00000000, 0x00078b80, 0x00078b80, 0x00000000 },
- { 0x00009a9c, 0x00000000, 0x00000000, 0x00078b84, 0x00078b84, 0x00000000 },
- { 0x00009aa0, 0x00000000, 0x00000000, 0x00078b88, 0x00078b88, 0x00000000 },
- { 0x00009aa4, 0x00000000, 0x00000000, 0x00078b8c, 0x00078b8c, 0x00000000 },
- { 0x00009aa8, 0x00000000, 0x00000000, 0x00078b90, 0x00078b90, 0x00000000 },
- { 0x00009aac, 0x00000000, 0x00000000, 0x000caf80, 0x000caf80, 0x00000000 },
- { 0x00009ab0, 0x00000000, 0x00000000, 0x000caf84, 0x000caf84, 0x00000000 },
- { 0x00009ab4, 0x00000000, 0x00000000, 0x000caf88, 0x000caf88, 0x00000000 },
- { 0x00009ab8, 0x00000000, 0x00000000, 0x000caf8c, 0x000caf8c, 0x00000000 },
- { 0x00009abc, 0x00000000, 0x00000000, 0x000caf90, 0x000caf90, 0x00000000 },
- { 0x00009ac0, 0x00000000, 0x00000000, 0x000db30c, 0x000db30c, 0x00000000 },
- { 0x00009ac4, 0x00000000, 0x00000000, 0x000db310, 0x000db310, 0x00000000 },
- { 0x00009ac8, 0x00000000, 0x00000000, 0x000db384, 0x000db384, 0x00000000 },
- { 0x00009acc, 0x00000000, 0x00000000, 0x000db388, 0x000db388, 0x00000000 },
- { 0x00009ad0, 0x00000000, 0x00000000, 0x000db324, 0x000db324, 0x00000000 },
- { 0x00009ad4, 0x00000000, 0x00000000, 0x000eb704, 0x000eb704, 0x00000000 },
- { 0x00009ad8, 0x00000000, 0x00000000, 0x000eb6a4, 0x000eb6a4, 0x00000000 },
- { 0x00009adc, 0x00000000, 0x00000000, 0x000eb6a8, 0x000eb6a8, 0x00000000 },
- { 0x00009ae0, 0x00000000, 0x00000000, 0x000eb710, 0x000eb710, 0x00000000 },
- { 0x00009ae4, 0x00000000, 0x00000000, 0x000eb714, 0x000eb714, 0x00000000 },
- { 0x00009ae8, 0x00000000, 0x00000000, 0x000eb720, 0x000eb720, 0x00000000 },
- { 0x00009aec, 0x00000000, 0x00000000, 0x000eb724, 0x000eb724, 0x00000000 },
- { 0x00009af0, 0x00000000, 0x00000000, 0x000eb728, 0x000eb728, 0x00000000 },
- { 0x00009af4, 0x00000000, 0x00000000, 0x000eb72c, 0x000eb72c, 0x00000000 },
- { 0x00009af8, 0x00000000, 0x00000000, 0x000eb7a0, 0x000eb7a0, 0x00000000 },
- { 0x00009afc, 0x00000000, 0x00000000, 0x000eb7a4, 0x000eb7a4, 0x00000000 },
- { 0x00009b00, 0x00000000, 0x00000000, 0x000eb7a8, 0x000eb7a8, 0x00000000 },
- { 0x00009b04, 0x00000000, 0x00000000, 0x000eb7b0, 0x000eb7b0, 0x00000000 },
- { 0x00009b08, 0x00000000, 0x00000000, 0x000eb7b4, 0x000eb7b4, 0x00000000 },
- { 0x00009b0c, 0x00000000, 0x00000000, 0x000eb7b8, 0x000eb7b8, 0x00000000 },
- { 0x00009b10, 0x00000000, 0x00000000, 0x000eb7a5, 0x000eb7a5, 0x00000000 },
- { 0x00009b14, 0x00000000, 0x00000000, 0x000eb7a9, 0x000eb7a9, 0x00000000 },
- { 0x00009b18, 0x00000000, 0x00000000, 0x000eb7ad, 0x000eb7ad, 0x00000000 },
- { 0x00009b1c, 0x00000000, 0x00000000, 0x000eb7b1, 0x000eb7b1, 0x00000000 },
- { 0x00009b20, 0x00000000, 0x00000000, 0x000eb7b5, 0x000eb7b5, 0x00000000 },
- { 0x00009b24, 0x00000000, 0x00000000, 0x000eb7b9, 0x000eb7b9, 0x00000000 },
- { 0x00009b28, 0x00000000, 0x00000000, 0x000eb7c5, 0x000eb7c5, 0x00000000 },
- { 0x00009b2c, 0x00000000, 0x00000000, 0x000eb7c9, 0x000eb7c9, 0x00000000 },
- { 0x00009b30, 0x00000000, 0x00000000, 0x000eb7d1, 0x000eb7d1, 0x00000000 },
- { 0x00009b34, 0x00000000, 0x00000000, 0x000eb7d5, 0x000eb7d5, 0x00000000 },
- { 0x00009b38, 0x00000000, 0x00000000, 0x000eb7d9, 0x000eb7d9, 0x00000000 },
- { 0x00009b3c, 0x00000000, 0x00000000, 0x000eb7c6, 0x000eb7c6, 0x00000000 },
- { 0x00009b40, 0x00000000, 0x00000000, 0x000eb7ca, 0x000eb7ca, 0x00000000 },
- { 0x00009b44, 0x00000000, 0x00000000, 0x000eb7ce, 0x000eb7ce, 0x00000000 },
- { 0x00009b48, 0x00000000, 0x00000000, 0x000eb7d2, 0x000eb7d2, 0x00000000 },
- { 0x00009b4c, 0x00000000, 0x00000000, 0x000eb7d6, 0x000eb7d6, 0x00000000 },
- { 0x00009b50, 0x00000000, 0x00000000, 0x000eb7c3, 0x000eb7c3, 0x00000000 },
- { 0x00009b54, 0x00000000, 0x00000000, 0x000eb7c7, 0x000eb7c7, 0x00000000 },
- { 0x00009b58, 0x00000000, 0x00000000, 0x000eb7cb, 0x000eb7cb, 0x00000000 },
- { 0x00009b5c, 0x00000000, 0x00000000, 0x000eb7cf, 0x000eb7cf, 0x00000000 },
- { 0x00009b60, 0x00000000, 0x00000000, 0x000eb7d7, 0x000eb7d7, 0x00000000 },
- { 0x00009b64, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
- { 0x00009b68, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
- { 0x00009b6c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
- { 0x00009b70, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
- { 0x00009b74, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
- { 0x00009b78, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
- { 0x00009b7c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
- { 0x00009b80, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
- { 0x00009b84, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
- { 0x00009b88, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
- { 0x00009b8c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
- { 0x00009b90, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
- { 0x00009b94, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
- { 0x00009b98, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
- { 0x00009b9c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
- { 0x00009ba0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
- { 0x00009ba4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
- { 0x00009ba8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
- { 0x00009bac, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
- { 0x00009bb0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
- { 0x00009bb4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
- { 0x00009bb8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
- { 0x00009bbc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
- { 0x00009bc0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
- { 0x00009bc4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
- { 0x00009bc8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
- { 0x00009bcc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
- { 0x00009bd0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
- { 0x00009bd4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
- { 0x00009bd8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
- { 0x00009bdc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
- { 0x00009be0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
- { 0x00009be4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
- { 0x00009be8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
- { 0x00009bec, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
- { 0x00009bf0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
- { 0x00009bf4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
- { 0x00009bf8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
- { 0x00009bfc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
- { 0x0000aa00, 0x00000000, 0x00000000, 0x00058084, 0x00058084, 0x00000000 },
- { 0x0000aa04, 0x00000000, 0x00000000, 0x00058088, 0x00058088, 0x00000000 },
- { 0x0000aa08, 0x00000000, 0x00000000, 0x0005808c, 0x0005808c, 0x00000000 },
- { 0x0000aa0c, 0x00000000, 0x00000000, 0x00058100, 0x00058100, 0x00000000 },
- { 0x0000aa10, 0x00000000, 0x00000000, 0x00058104, 0x00058104, 0x00000000 },
- { 0x0000aa14, 0x00000000, 0x00000000, 0x00058108, 0x00058108, 0x00000000 },
- { 0x0000aa18, 0x00000000, 0x00000000, 0x0005810c, 0x0005810c, 0x00000000 },
- { 0x0000aa1c, 0x00000000, 0x00000000, 0x00058110, 0x00058110, 0x00000000 },
- { 0x0000aa20, 0x00000000, 0x00000000, 0x00058114, 0x00058114, 0x00000000 },
- { 0x0000aa24, 0x00000000, 0x00000000, 0x00058180, 0x00058180, 0x00000000 },
- { 0x0000aa28, 0x00000000, 0x00000000, 0x00058184, 0x00058184, 0x00000000 },
- { 0x0000aa2c, 0x00000000, 0x00000000, 0x00058188, 0x00058188, 0x00000000 },
- { 0x0000aa30, 0x00000000, 0x00000000, 0x0005818c, 0x0005818c, 0x00000000 },
- { 0x0000aa34, 0x00000000, 0x00000000, 0x00058190, 0x00058190, 0x00000000 },
- { 0x0000aa38, 0x00000000, 0x00000000, 0x00058194, 0x00058194, 0x00000000 },
- { 0x0000aa3c, 0x00000000, 0x00000000, 0x000581a0, 0x000581a0, 0x00000000 },
- { 0x0000aa40, 0x00000000, 0x00000000, 0x0005820c, 0x0005820c, 0x00000000 },
- { 0x0000aa44, 0x00000000, 0x00000000, 0x000581a8, 0x000581a8, 0x00000000 },
- { 0x0000aa48, 0x00000000, 0x00000000, 0x00058284, 0x00058284, 0x00000000 },
- { 0x0000aa4c, 0x00000000, 0x00000000, 0x00058288, 0x00058288, 0x00000000 },
- { 0x0000aa50, 0x00000000, 0x00000000, 0x00058224, 0x00058224, 0x00000000 },
- { 0x0000aa54, 0x00000000, 0x00000000, 0x00058290, 0x00058290, 0x00000000 },
- { 0x0000aa58, 0x00000000, 0x00000000, 0x00058300, 0x00058300, 0x00000000 },
- { 0x0000aa5c, 0x00000000, 0x00000000, 0x00058304, 0x00058304, 0x00000000 },
- { 0x0000aa60, 0x00000000, 0x00000000, 0x00058308, 0x00058308, 0x00000000 },
- { 0x0000aa64, 0x00000000, 0x00000000, 0x0005830c, 0x0005830c, 0x00000000 },
- { 0x0000aa68, 0x00000000, 0x00000000, 0x00058380, 0x00058380, 0x00000000 },
- { 0x0000aa6c, 0x00000000, 0x00000000, 0x00058384, 0x00058384, 0x00000000 },
- { 0x0000aa70, 0x00000000, 0x00000000, 0x00068700, 0x00068700, 0x00000000 },
- { 0x0000aa74, 0x00000000, 0x00000000, 0x00068704, 0x00068704, 0x00000000 },
- { 0x0000aa78, 0x00000000, 0x00000000, 0x00068708, 0x00068708, 0x00000000 },
- { 0x0000aa7c, 0x00000000, 0x00000000, 0x0006870c, 0x0006870c, 0x00000000 },
- { 0x0000aa80, 0x00000000, 0x00000000, 0x00068780, 0x00068780, 0x00000000 },
- { 0x0000aa84, 0x00000000, 0x00000000, 0x00068784, 0x00068784, 0x00000000 },
- { 0x0000aa88, 0x00000000, 0x00000000, 0x00078b00, 0x00078b00, 0x00000000 },
- { 0x0000aa8c, 0x00000000, 0x00000000, 0x00078b04, 0x00078b04, 0x00000000 },
- { 0x0000aa90, 0x00000000, 0x00000000, 0x00078b08, 0x00078b08, 0x00000000 },
- { 0x0000aa94, 0x00000000, 0x00000000, 0x00078b0c, 0x00078b0c, 0x00000000 },
- { 0x0000aa98, 0x00000000, 0x00000000, 0x00078b80, 0x00078b80, 0x00000000 },
- { 0x0000aa9c, 0x00000000, 0x00000000, 0x00078b84, 0x00078b84, 0x00000000 },
- { 0x0000aaa0, 0x00000000, 0x00000000, 0x00078b88, 0x00078b88, 0x00000000 },
- { 0x0000aaa4, 0x00000000, 0x00000000, 0x00078b8c, 0x00078b8c, 0x00000000 },
- { 0x0000aaa8, 0x00000000, 0x00000000, 0x00078b90, 0x00078b90, 0x00000000 },
- { 0x0000aaac, 0x00000000, 0x00000000, 0x000caf80, 0x000caf80, 0x00000000 },
- { 0x0000aab0, 0x00000000, 0x00000000, 0x000caf84, 0x000caf84, 0x00000000 },
- { 0x0000aab4, 0x00000000, 0x00000000, 0x000caf88, 0x000caf88, 0x00000000 },
- { 0x0000aab8, 0x00000000, 0x00000000, 0x000caf8c, 0x000caf8c, 0x00000000 },
- { 0x0000aabc, 0x00000000, 0x00000000, 0x000caf90, 0x000caf90, 0x00000000 },
- { 0x0000aac0, 0x00000000, 0x00000000, 0x000db30c, 0x000db30c, 0x00000000 },
- { 0x0000aac4, 0x00000000, 0x00000000, 0x000db310, 0x000db310, 0x00000000 },
- { 0x0000aac8, 0x00000000, 0x00000000, 0x000db384, 0x000db384, 0x00000000 },
- { 0x0000aacc, 0x00000000, 0x00000000, 0x000db388, 0x000db388, 0x00000000 },
- { 0x0000aad0, 0x00000000, 0x00000000, 0x000db324, 0x000db324, 0x00000000 },
- { 0x0000aad4, 0x00000000, 0x00000000, 0x000eb704, 0x000eb704, 0x00000000 },
- { 0x0000aad8, 0x00000000, 0x00000000, 0x000eb6a4, 0x000eb6a4, 0x00000000 },
- { 0x0000aadc, 0x00000000, 0x00000000, 0x000eb6a8, 0x000eb6a8, 0x00000000 },
- { 0x0000aae0, 0x00000000, 0x00000000, 0x000eb710, 0x000eb710, 0x00000000 },
- { 0x0000aae4, 0x00000000, 0x00000000, 0x000eb714, 0x000eb714, 0x00000000 },
- { 0x0000aae8, 0x00000000, 0x00000000, 0x000eb720, 0x000eb720, 0x00000000 },
- { 0x0000aaec, 0x00000000, 0x00000000, 0x000eb724, 0x000eb724, 0x00000000 },
- { 0x0000aaf0, 0x00000000, 0x00000000, 0x000eb728, 0x000eb728, 0x00000000 },
- { 0x0000aaf4, 0x00000000, 0x00000000, 0x000eb72c, 0x000eb72c, 0x00000000 },
- { 0x0000aaf8, 0x00000000, 0x00000000, 0x000eb7a0, 0x000eb7a0, 0x00000000 },
- { 0x0000aafc, 0x00000000, 0x00000000, 0x000eb7a4, 0x000eb7a4, 0x00000000 },
- { 0x0000ab00, 0x00000000, 0x00000000, 0x000eb7a8, 0x000eb7a8, 0x00000000 },
- { 0x0000ab04, 0x00000000, 0x00000000, 0x000eb7b0, 0x000eb7b0, 0x00000000 },
- { 0x0000ab08, 0x00000000, 0x00000000, 0x000eb7b4, 0x000eb7b4, 0x00000000 },
- { 0x0000ab0c, 0x00000000, 0x00000000, 0x000eb7b8, 0x000eb7b8, 0x00000000 },
- { 0x0000ab10, 0x00000000, 0x00000000, 0x000eb7a5, 0x000eb7a5, 0x00000000 },
- { 0x0000ab14, 0x00000000, 0x00000000, 0x000eb7a9, 0x000eb7a9, 0x00000000 },
- { 0x0000ab18, 0x00000000, 0x00000000, 0x000eb7ad, 0x000eb7ad, 0x00000000 },
- { 0x0000ab1c, 0x00000000, 0x00000000, 0x000eb7b1, 0x000eb7b1, 0x00000000 },
- { 0x0000ab20, 0x00000000, 0x00000000, 0x000eb7b5, 0x000eb7b5, 0x00000000 },
- { 0x0000ab24, 0x00000000, 0x00000000, 0x000eb7b9, 0x000eb7b9, 0x00000000 },
- { 0x0000ab28, 0x00000000, 0x00000000, 0x000eb7c5, 0x000eb7c5, 0x00000000 },
- { 0x0000ab2c, 0x00000000, 0x00000000, 0x000eb7c9, 0x000eb7c9, 0x00000000 },
- { 0x0000ab30, 0x00000000, 0x00000000, 0x000eb7d1, 0x000eb7d1, 0x00000000 },
- { 0x0000ab34, 0x00000000, 0x00000000, 0x000eb7d5, 0x000eb7d5, 0x00000000 },
- { 0x0000ab38, 0x00000000, 0x00000000, 0x000eb7d9, 0x000eb7d9, 0x00000000 },
- { 0x0000ab3c, 0x00000000, 0x00000000, 0x000eb7c6, 0x000eb7c6, 0x00000000 },
- { 0x0000ab40, 0x00000000, 0x00000000, 0x000eb7ca, 0x000eb7ca, 0x00000000 },
- { 0x0000ab44, 0x00000000, 0x00000000, 0x000eb7ce, 0x000eb7ce, 0x00000000 },
- { 0x0000ab48, 0x00000000, 0x00000000, 0x000eb7d2, 0x000eb7d2, 0x00000000 },
- { 0x0000ab4c, 0x00000000, 0x00000000, 0x000eb7d6, 0x000eb7d6, 0x00000000 },
- { 0x0000ab50, 0x00000000, 0x00000000, 0x000eb7c3, 0x000eb7c3, 0x00000000 },
- { 0x0000ab54, 0x00000000, 0x00000000, 0x000eb7c7, 0x000eb7c7, 0x00000000 },
- { 0x0000ab58, 0x00000000, 0x00000000, 0x000eb7cb, 0x000eb7cb, 0x00000000 },
- { 0x0000ab5c, 0x00000000, 0x00000000, 0x000eb7cf, 0x000eb7cf, 0x00000000 },
- { 0x0000ab60, 0x00000000, 0x00000000, 0x000eb7d7, 0x000eb7d7, 0x00000000 },
- { 0x0000ab64, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
- { 0x0000ab68, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
- { 0x0000ab6c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
- { 0x0000ab70, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
- { 0x0000ab74, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
- { 0x0000ab78, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
- { 0x0000ab7c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
- { 0x0000ab80, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
- { 0x0000ab84, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
- { 0x0000ab88, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
- { 0x0000ab8c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
- { 0x0000ab90, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
- { 0x0000ab94, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
- { 0x0000ab98, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
- { 0x0000ab9c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
- { 0x0000aba0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
- { 0x0000aba4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
- { 0x0000aba8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
- { 0x0000abac, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
- { 0x0000abb0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
- { 0x0000abb4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
- { 0x0000abb8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
- { 0x0000abbc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
- { 0x0000abc0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
- { 0x0000abc4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
- { 0x0000abc8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
- { 0x0000abcc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
- { 0x0000abd0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
- { 0x0000abd4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
- { 0x0000abd8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
- { 0x0000abdc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
- { 0x0000abe0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
- { 0x0000abe4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
- { 0x0000abe8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
- { 0x0000abec, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
- { 0x0000abf0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
- { 0x0000abf4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
- { 0x0000abf8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
- { 0x0000abfc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
- { 0x0000a204, 0x00000004, 0x00000004, 0x00000004, 0x00000004, 0x00000004 },
- { 0x0000a20c, 0x00000014, 0x00000014, 0x0001f000, 0x0001f000, 0x0001f000 },
- { 0x0000b20c, 0x00000014, 0x00000014, 0x0001f000, 0x0001f000, 0x0001f000 },
- { 0x0000a21c, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a },
- { 0x0000a230, 0x00000000, 0x00000000, 0x00000210, 0x00000108, 0x00000000 },
- { 0x0000a250, 0x0004f000, 0x0004f000, 0x0004a000, 0x0004a000, 0x0004a000 },
- { 0x0000a358, 0x7999aa02, 0x7999aa02, 0x7999aa0e, 0x7999aa0e, 0x7999aa0e },
+ {0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160, 0x000001e0},
+ {0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c, 0x000001e0},
+ {0x000010b0, 0x00000e60, 0x00001cc0, 0x00007c70, 0x00003e38, 0x00001180},
+ {0x000010f0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000008},
+ {0x00008014, 0x03e803e8, 0x07d007d0, 0x10801600, 0x08400b00, 0x06e006e0},
+ {0x0000801c, 0x128d8027, 0x128d804f, 0x12e00057, 0x12e0002b, 0x0988004f},
+ {0x00008318, 0x00003e80, 0x00007d00, 0x00006880, 0x00003440, 0x00006880},
+ {0x00009804, 0x00000300, 0x000003c4, 0x000003c4, 0x00000300, 0x00000303},
+ {0x00009820, 0x02020200, 0x02020200, 0x02020200, 0x02020200, 0x02020200},
+ {0x00009824, 0x01000e0e, 0x01000e0e, 0x01000e0e, 0x01000e0e, 0x01000e0e},
+ {0x00009828, 0x3a020001, 0x3a020001, 0x3a020001, 0x3a020001, 0x3a020001},
+ {0x00009834, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e},
+ {0x00009838, 0x00000007, 0x00000007, 0x00000007, 0x00000007, 0x00000007},
+ {0x00009840, 0x206a012e, 0x206a012e, 0x206a012e, 0x206a012e, 0x206a012e},
+ {0x00009844, 0x0372161e, 0x0372161e, 0x03721620, 0x03721620, 0x037216a0},
+ {0x00009848, 0x00001066, 0x00001066, 0x00001053, 0x00001053, 0x00001059},
+ {0x0000a848, 0x00001066, 0x00001066, 0x00001053, 0x00001053, 0x00001059},
+ {0x00009850, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2},
+ {0x00009858, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e},
+ {0x0000985c, 0x3139605e, 0x3139605e, 0x3137605e, 0x3137605e, 0x3139605e},
+ {0x00009860, 0x00058d18, 0x00058d18, 0x00058d18, 0x00058d18, 0x00058d18},
+ {0x00009864, 0x0000fe00, 0x0000fe00, 0x0001ce00, 0x0001ce00, 0x0001ce00},
+ {0x00009868, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0},
+ {0x0000986c, 0x06903081, 0x06903081, 0x06903881, 0x06903881, 0x06903881},
+ {0x00009910, 0x30002310, 0x30002310, 0x30002310, 0x30002310, 0x30002310},
+ {0x00009914, 0x000007d0, 0x00000fa0, 0x00001130, 0x00000898, 0x000007d0},
+ {0x00009918, 0x0000000a, 0x00000014, 0x00000016, 0x0000000b, 0x00000016},
+ {0x00009924, 0xd00a8007, 0xd00a8007, 0xd00a800d, 0xd00a800d, 0xd00a800d},
+ {0x00009944, 0xffbc1010, 0xffbc1010, 0xffbc1020, 0xffbc1020, 0xffbc1010},
+ {0x00009960, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+ {0x00009964, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+ {0x000099b8, 0x0000421c, 0x0000421c, 0x0000421c, 0x0000421c, 0x0000421c},
+ {0x000099bc, 0x00000600, 0x00000600, 0x00000c00, 0x00000c00, 0x00000c00},
+ {0x000099c0, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4},
+ {0x000099c4, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77},
+ {0x000099c8, 0x6af6532f, 0x6af6532f, 0x6af6532f, 0x6af6532f, 0x6af6532f},
+ {0x000099cc, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8},
+ {0x000099d0, 0x00046384, 0x00046384, 0x00046384, 0x00046384, 0x00046384},
+ {0x000099d4, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+ {0x000099d8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+ {0x00009a00, 0x00000000, 0x00000000, 0x00058084, 0x00058084, 0x00000000},
+ {0x00009a04, 0x00000000, 0x00000000, 0x00058088, 0x00058088, 0x00000000},
+ {0x00009a08, 0x00000000, 0x00000000, 0x0005808c, 0x0005808c, 0x00000000},
+ {0x00009a0c, 0x00000000, 0x00000000, 0x00058100, 0x00058100, 0x00000000},
+ {0x00009a10, 0x00000000, 0x00000000, 0x00058104, 0x00058104, 0x00000000},
+ {0x00009a14, 0x00000000, 0x00000000, 0x00058108, 0x00058108, 0x00000000},
+ {0x00009a18, 0x00000000, 0x00000000, 0x0005810c, 0x0005810c, 0x00000000},
+ {0x00009a1c, 0x00000000, 0x00000000, 0x00058110, 0x00058110, 0x00000000},
+ {0x00009a20, 0x00000000, 0x00000000, 0x00058114, 0x00058114, 0x00000000},
+ {0x00009a24, 0x00000000, 0x00000000, 0x00058180, 0x00058180, 0x00000000},
+ {0x00009a28, 0x00000000, 0x00000000, 0x00058184, 0x00058184, 0x00000000},
+ {0x00009a2c, 0x00000000, 0x00000000, 0x00058188, 0x00058188, 0x00000000},
+ {0x00009a30, 0x00000000, 0x00000000, 0x0005818c, 0x0005818c, 0x00000000},
+ {0x00009a34, 0x00000000, 0x00000000, 0x00058190, 0x00058190, 0x00000000},
+ {0x00009a38, 0x00000000, 0x00000000, 0x00058194, 0x00058194, 0x00000000},
+ {0x00009a3c, 0x00000000, 0x00000000, 0x000581a0, 0x000581a0, 0x00000000},
+ {0x00009a40, 0x00000000, 0x00000000, 0x0005820c, 0x0005820c, 0x00000000},
+ {0x00009a44, 0x00000000, 0x00000000, 0x000581a8, 0x000581a8, 0x00000000},
+ {0x00009a48, 0x00000000, 0x00000000, 0x00058284, 0x00058284, 0x00000000},
+ {0x00009a4c, 0x00000000, 0x00000000, 0x00058288, 0x00058288, 0x00000000},
+ {0x00009a50, 0x00000000, 0x00000000, 0x00058224, 0x00058224, 0x00000000},
+ {0x00009a54, 0x00000000, 0x00000000, 0x00058290, 0x00058290, 0x00000000},
+ {0x00009a58, 0x00000000, 0x00000000, 0x00058300, 0x00058300, 0x00000000},
+ {0x00009a5c, 0x00000000, 0x00000000, 0x00058304, 0x00058304, 0x00000000},
+ {0x00009a60, 0x00000000, 0x00000000, 0x00058308, 0x00058308, 0x00000000},
+ {0x00009a64, 0x00000000, 0x00000000, 0x0005830c, 0x0005830c, 0x00000000},
+ {0x00009a68, 0x00000000, 0x00000000, 0x00058380, 0x00058380, 0x00000000},
+ {0x00009a6c, 0x00000000, 0x00000000, 0x00058384, 0x00058384, 0x00000000},
+ {0x00009a70, 0x00000000, 0x00000000, 0x00068700, 0x00068700, 0x00000000},
+ {0x00009a74, 0x00000000, 0x00000000, 0x00068704, 0x00068704, 0x00000000},
+ {0x00009a78, 0x00000000, 0x00000000, 0x00068708, 0x00068708, 0x00000000},
+ {0x00009a7c, 0x00000000, 0x00000000, 0x0006870c, 0x0006870c, 0x00000000},
+ {0x00009a80, 0x00000000, 0x00000000, 0x00068780, 0x00068780, 0x00000000},
+ {0x00009a84, 0x00000000, 0x00000000, 0x00068784, 0x00068784, 0x00000000},
+ {0x00009a88, 0x00000000, 0x00000000, 0x00078b00, 0x00078b00, 0x00000000},
+ {0x00009a8c, 0x00000000, 0x00000000, 0x00078b04, 0x00078b04, 0x00000000},
+ {0x00009a90, 0x00000000, 0x00000000, 0x00078b08, 0x00078b08, 0x00000000},
+ {0x00009a94, 0x00000000, 0x00000000, 0x00078b0c, 0x00078b0c, 0x00000000},
+ {0x00009a98, 0x00000000, 0x00000000, 0x00078b80, 0x00078b80, 0x00000000},
+ {0x00009a9c, 0x00000000, 0x00000000, 0x00078b84, 0x00078b84, 0x00000000},
+ {0x00009aa0, 0x00000000, 0x00000000, 0x00078b88, 0x00078b88, 0x00000000},
+ {0x00009aa4, 0x00000000, 0x00000000, 0x00078b8c, 0x00078b8c, 0x00000000},
+ {0x00009aa8, 0x00000000, 0x00000000, 0x00078b90, 0x00078b90, 0x00000000},
+ {0x00009aac, 0x00000000, 0x00000000, 0x000caf80, 0x000caf80, 0x00000000},
+ {0x00009ab0, 0x00000000, 0x00000000, 0x000caf84, 0x000caf84, 0x00000000},
+ {0x00009ab4, 0x00000000, 0x00000000, 0x000caf88, 0x000caf88, 0x00000000},
+ {0x00009ab8, 0x00000000, 0x00000000, 0x000caf8c, 0x000caf8c, 0x00000000},
+ {0x00009abc, 0x00000000, 0x00000000, 0x000caf90, 0x000caf90, 0x00000000},
+ {0x00009ac0, 0x00000000, 0x00000000, 0x000db30c, 0x000db30c, 0x00000000},
+ {0x00009ac4, 0x00000000, 0x00000000, 0x000db310, 0x000db310, 0x00000000},
+ {0x00009ac8, 0x00000000, 0x00000000, 0x000db384, 0x000db384, 0x00000000},
+ {0x00009acc, 0x00000000, 0x00000000, 0x000db388, 0x000db388, 0x00000000},
+ {0x00009ad0, 0x00000000, 0x00000000, 0x000db324, 0x000db324, 0x00000000},
+ {0x00009ad4, 0x00000000, 0x00000000, 0x000eb704, 0x000eb704, 0x00000000},
+ {0x00009ad8, 0x00000000, 0x00000000, 0x000eb6a4, 0x000eb6a4, 0x00000000},
+ {0x00009adc, 0x00000000, 0x00000000, 0x000eb6a8, 0x000eb6a8, 0x00000000},
+ {0x00009ae0, 0x00000000, 0x00000000, 0x000eb710, 0x000eb710, 0x00000000},
+ {0x00009ae4, 0x00000000, 0x00000000, 0x000eb714, 0x000eb714, 0x00000000},
+ {0x00009ae8, 0x00000000, 0x00000000, 0x000eb720, 0x000eb720, 0x00000000},
+ {0x00009aec, 0x00000000, 0x00000000, 0x000eb724, 0x000eb724, 0x00000000},
+ {0x00009af0, 0x00000000, 0x00000000, 0x000eb728, 0x000eb728, 0x00000000},
+ {0x00009af4, 0x00000000, 0x00000000, 0x000eb72c, 0x000eb72c, 0x00000000},
+ {0x00009af8, 0x00000000, 0x00000000, 0x000eb7a0, 0x000eb7a0, 0x00000000},
+ {0x00009afc, 0x00000000, 0x00000000, 0x000eb7a4, 0x000eb7a4, 0x00000000},
+ {0x00009b00, 0x00000000, 0x00000000, 0x000eb7a8, 0x000eb7a8, 0x00000000},
+ {0x00009b04, 0x00000000, 0x00000000, 0x000eb7b0, 0x000eb7b0, 0x00000000},
+ {0x00009b08, 0x00000000, 0x00000000, 0x000eb7b4, 0x000eb7b4, 0x00000000},
+ {0x00009b0c, 0x00000000, 0x00000000, 0x000eb7b8, 0x000eb7b8, 0x00000000},
+ {0x00009b10, 0x00000000, 0x00000000, 0x000eb7a5, 0x000eb7a5, 0x00000000},
+ {0x00009b14, 0x00000000, 0x00000000, 0x000eb7a9, 0x000eb7a9, 0x00000000},
+ {0x00009b18, 0x00000000, 0x00000000, 0x000eb7ad, 0x000eb7ad, 0x00000000},
+ {0x00009b1c, 0x00000000, 0x00000000, 0x000eb7b1, 0x000eb7b1, 0x00000000},
+ {0x00009b20, 0x00000000, 0x00000000, 0x000eb7b5, 0x000eb7b5, 0x00000000},
+ {0x00009b24, 0x00000000, 0x00000000, 0x000eb7b9, 0x000eb7b9, 0x00000000},
+ {0x00009b28, 0x00000000, 0x00000000, 0x000eb7c5, 0x000eb7c5, 0x00000000},
+ {0x00009b2c, 0x00000000, 0x00000000, 0x000eb7c9, 0x000eb7c9, 0x00000000},
+ {0x00009b30, 0x00000000, 0x00000000, 0x000eb7d1, 0x000eb7d1, 0x00000000},
+ {0x00009b34, 0x00000000, 0x00000000, 0x000eb7d5, 0x000eb7d5, 0x00000000},
+ {0x00009b38, 0x00000000, 0x00000000, 0x000eb7d9, 0x000eb7d9, 0x00000000},
+ {0x00009b3c, 0x00000000, 0x00000000, 0x000eb7c6, 0x000eb7c6, 0x00000000},
+ {0x00009b40, 0x00000000, 0x00000000, 0x000eb7ca, 0x000eb7ca, 0x00000000},
+ {0x00009b44, 0x00000000, 0x00000000, 0x000eb7ce, 0x000eb7ce, 0x00000000},
+ {0x00009b48, 0x00000000, 0x00000000, 0x000eb7d2, 0x000eb7d2, 0x00000000},
+ {0x00009b4c, 0x00000000, 0x00000000, 0x000eb7d6, 0x000eb7d6, 0x00000000},
+ {0x00009b50, 0x00000000, 0x00000000, 0x000eb7c3, 0x000eb7c3, 0x00000000},
+ {0x00009b54, 0x00000000, 0x00000000, 0x000eb7c7, 0x000eb7c7, 0x00000000},
+ {0x00009b58, 0x00000000, 0x00000000, 0x000eb7cb, 0x000eb7cb, 0x00000000},
+ {0x00009b5c, 0x00000000, 0x00000000, 0x000eb7cf, 0x000eb7cf, 0x00000000},
+ {0x00009b60, 0x00000000, 0x00000000, 0x000eb7d7, 0x000eb7d7, 0x00000000},
+ {0x00009b64, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+ {0x00009b68, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+ {0x00009b6c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+ {0x00009b70, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+ {0x00009b74, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+ {0x00009b78, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+ {0x00009b7c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+ {0x00009b80, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+ {0x00009b84, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+ {0x00009b88, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+ {0x00009b8c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+ {0x00009b90, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+ {0x00009b94, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+ {0x00009b98, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+ {0x00009b9c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+ {0x00009ba0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+ {0x00009ba4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+ {0x00009ba8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+ {0x00009bac, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+ {0x00009bb0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+ {0x00009bb4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+ {0x00009bb8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+ {0x00009bbc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+ {0x00009bc0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+ {0x00009bc4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+ {0x00009bc8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+ {0x00009bcc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+ {0x00009bd0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+ {0x00009bd4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+ {0x00009bd8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+ {0x00009bdc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+ {0x00009be0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+ {0x00009be4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+ {0x00009be8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+ {0x00009bec, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+ {0x00009bf0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+ {0x00009bf4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+ {0x00009bf8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+ {0x00009bfc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+ {0x0000aa00, 0x00000000, 0x00000000, 0x00058084, 0x00058084, 0x00000000},
+ {0x0000aa04, 0x00000000, 0x00000000, 0x00058088, 0x00058088, 0x00000000},
+ {0x0000aa08, 0x00000000, 0x00000000, 0x0005808c, 0x0005808c, 0x00000000},
+ {0x0000aa0c, 0x00000000, 0x00000000, 0x00058100, 0x00058100, 0x00000000},
+ {0x0000aa10, 0x00000000, 0x00000000, 0x00058104, 0x00058104, 0x00000000},
+ {0x0000aa14, 0x00000000, 0x00000000, 0x00058108, 0x00058108, 0x00000000},
+ {0x0000aa18, 0x00000000, 0x00000000, 0x0005810c, 0x0005810c, 0x00000000},
+ {0x0000aa1c, 0x00000000, 0x00000000, 0x00058110, 0x00058110, 0x00000000},
+ {0x0000aa20, 0x00000000, 0x00000000, 0x00058114, 0x00058114, 0x00000000},
+ {0x0000aa24, 0x00000000, 0x00000000, 0x00058180, 0x00058180, 0x00000000},
+ {0x0000aa28, 0x00000000, 0x00000000, 0x00058184, 0x00058184, 0x00000000},
+ {0x0000aa2c, 0x00000000, 0x00000000, 0x00058188, 0x00058188, 0x00000000},
+ {0x0000aa30, 0x00000000, 0x00000000, 0x0005818c, 0x0005818c, 0x00000000},
+ {0x0000aa34, 0x00000000, 0x00000000, 0x00058190, 0x00058190, 0x00000000},
+ {0x0000aa38, 0x00000000, 0x00000000, 0x00058194, 0x00058194, 0x00000000},
+ {0x0000aa3c, 0x00000000, 0x00000000, 0x000581a0, 0x000581a0, 0x00000000},
+ {0x0000aa40, 0x00000000, 0x00000000, 0x0005820c, 0x0005820c, 0x00000000},
+ {0x0000aa44, 0x00000000, 0x00000000, 0x000581a8, 0x000581a8, 0x00000000},
+ {0x0000aa48, 0x00000000, 0x00000000, 0x00058284, 0x00058284, 0x00000000},
+ {0x0000aa4c, 0x00000000, 0x00000000, 0x00058288, 0x00058288, 0x00000000},
+ {0x0000aa50, 0x00000000, 0x00000000, 0x00058224, 0x00058224, 0x00000000},
+ {0x0000aa54, 0x00000000, 0x00000000, 0x00058290, 0x00058290, 0x00000000},
+ {0x0000aa58, 0x00000000, 0x00000000, 0x00058300, 0x00058300, 0x00000000},
+ {0x0000aa5c, 0x00000000, 0x00000000, 0x00058304, 0x00058304, 0x00000000},
+ {0x0000aa60, 0x00000000, 0x00000000, 0x00058308, 0x00058308, 0x00000000},
+ {0x0000aa64, 0x00000000, 0x00000000, 0x0005830c, 0x0005830c, 0x00000000},
+ {0x0000aa68, 0x00000000, 0x00000000, 0x00058380, 0x00058380, 0x00000000},
+ {0x0000aa6c, 0x00000000, 0x00000000, 0x00058384, 0x00058384, 0x00000000},
+ {0x0000aa70, 0x00000000, 0x00000000, 0x00068700, 0x00068700, 0x00000000},
+ {0x0000aa74, 0x00000000, 0x00000000, 0x00068704, 0x00068704, 0x00000000},
+ {0x0000aa78, 0x00000000, 0x00000000, 0x00068708, 0x00068708, 0x00000000},
+ {0x0000aa7c, 0x00000000, 0x00000000, 0x0006870c, 0x0006870c, 0x00000000},
+ {0x0000aa80, 0x00000000, 0x00000000, 0x00068780, 0x00068780, 0x00000000},
+ {0x0000aa84, 0x00000000, 0x00000000, 0x00068784, 0x00068784, 0x00000000},
+ {0x0000aa88, 0x00000000, 0x00000000, 0x00078b00, 0x00078b00, 0x00000000},
+ {0x0000aa8c, 0x00000000, 0x00000000, 0x00078b04, 0x00078b04, 0x00000000},
+ {0x0000aa90, 0x00000000, 0x00000000, 0x00078b08, 0x00078b08, 0x00000000},
+ {0x0000aa94, 0x00000000, 0x00000000, 0x00078b0c, 0x00078b0c, 0x00000000},
+ {0x0000aa98, 0x00000000, 0x00000000, 0x00078b80, 0x00078b80, 0x00000000},
+ {0x0000aa9c, 0x00000000, 0x00000000, 0x00078b84, 0x00078b84, 0x00000000},
+ {0x0000aaa0, 0x00000000, 0x00000000, 0x00078b88, 0x00078b88, 0x00000000},
+ {0x0000aaa4, 0x00000000, 0x00000000, 0x00078b8c, 0x00078b8c, 0x00000000},
+ {0x0000aaa8, 0x00000000, 0x00000000, 0x00078b90, 0x00078b90, 0x00000000},
+ {0x0000aaac, 0x00000000, 0x00000000, 0x000caf80, 0x000caf80, 0x00000000},
+ {0x0000aab0, 0x00000000, 0x00000000, 0x000caf84, 0x000caf84, 0x00000000},
+ {0x0000aab4, 0x00000000, 0x00000000, 0x000caf88, 0x000caf88, 0x00000000},
+ {0x0000aab8, 0x00000000, 0x00000000, 0x000caf8c, 0x000caf8c, 0x00000000},
+ {0x0000aabc, 0x00000000, 0x00000000, 0x000caf90, 0x000caf90, 0x00000000},
+ {0x0000aac0, 0x00000000, 0x00000000, 0x000db30c, 0x000db30c, 0x00000000},
+ {0x0000aac4, 0x00000000, 0x00000000, 0x000db310, 0x000db310, 0x00000000},
+ {0x0000aac8, 0x00000000, 0x00000000, 0x000db384, 0x000db384, 0x00000000},
+ {0x0000aacc, 0x00000000, 0x00000000, 0x000db388, 0x000db388, 0x00000000},
+ {0x0000aad0, 0x00000000, 0x00000000, 0x000db324, 0x000db324, 0x00000000},
+ {0x0000aad4, 0x00000000, 0x00000000, 0x000eb704, 0x000eb704, 0x00000000},
+ {0x0000aad8, 0x00000000, 0x00000000, 0x000eb6a4, 0x000eb6a4, 0x00000000},
+ {0x0000aadc, 0x00000000, 0x00000000, 0x000eb6a8, 0x000eb6a8, 0x00000000},
+ {0x0000aae0, 0x00000000, 0x00000000, 0x000eb710, 0x000eb710, 0x00000000},
+ {0x0000aae4, 0x00000000, 0x00000000, 0x000eb714, 0x000eb714, 0x00000000},
+ {0x0000aae8, 0x00000000, 0x00000000, 0x000eb720, 0x000eb720, 0x00000000},
+ {0x0000aaec, 0x00000000, 0x00000000, 0x000eb724, 0x000eb724, 0x00000000},
+ {0x0000aaf0, 0x00000000, 0x00000000, 0x000eb728, 0x000eb728, 0x00000000},
+ {0x0000aaf4, 0x00000000, 0x00000000, 0x000eb72c, 0x000eb72c, 0x00000000},
+ {0x0000aaf8, 0x00000000, 0x00000000, 0x000eb7a0, 0x000eb7a0, 0x00000000},
+ {0x0000aafc, 0x00000000, 0x00000000, 0x000eb7a4, 0x000eb7a4, 0x00000000},
+ {0x0000ab00, 0x00000000, 0x00000000, 0x000eb7a8, 0x000eb7a8, 0x00000000},
+ {0x0000ab04, 0x00000000, 0x00000000, 0x000eb7b0, 0x000eb7b0, 0x00000000},
+ {0x0000ab08, 0x00000000, 0x00000000, 0x000eb7b4, 0x000eb7b4, 0x00000000},
+ {0x0000ab0c, 0x00000000, 0x00000000, 0x000eb7b8, 0x000eb7b8, 0x00000000},
+ {0x0000ab10, 0x00000000, 0x00000000, 0x000eb7a5, 0x000eb7a5, 0x00000000},
+ {0x0000ab14, 0x00000000, 0x00000000, 0x000eb7a9, 0x000eb7a9, 0x00000000},
+ {0x0000ab18, 0x00000000, 0x00000000, 0x000eb7ad, 0x000eb7ad, 0x00000000},
+ {0x0000ab1c, 0x00000000, 0x00000000, 0x000eb7b1, 0x000eb7b1, 0x00000000},
+ {0x0000ab20, 0x00000000, 0x00000000, 0x000eb7b5, 0x000eb7b5, 0x00000000},
+ {0x0000ab24, 0x00000000, 0x00000000, 0x000eb7b9, 0x000eb7b9, 0x00000000},
+ {0x0000ab28, 0x00000000, 0x00000000, 0x000eb7c5, 0x000eb7c5, 0x00000000},
+ {0x0000ab2c, 0x00000000, 0x00000000, 0x000eb7c9, 0x000eb7c9, 0x00000000},
+ {0x0000ab30, 0x00000000, 0x00000000, 0x000eb7d1, 0x000eb7d1, 0x00000000},
+ {0x0000ab34, 0x00000000, 0x00000000, 0x000eb7d5, 0x000eb7d5, 0x00000000},
+ {0x0000ab38, 0x00000000, 0x00000000, 0x000eb7d9, 0x000eb7d9, 0x00000000},
+ {0x0000ab3c, 0x00000000, 0x00000000, 0x000eb7c6, 0x000eb7c6, 0x00000000},
+ {0x0000ab40, 0x00000000, 0x00000000, 0x000eb7ca, 0x000eb7ca, 0x00000000},
+ {0x0000ab44, 0x00000000, 0x00000000, 0x000eb7ce, 0x000eb7ce, 0x00000000},
+ {0x0000ab48, 0x00000000, 0x00000000, 0x000eb7d2, 0x000eb7d2, 0x00000000},
+ {0x0000ab4c, 0x00000000, 0x00000000, 0x000eb7d6, 0x000eb7d6, 0x00000000},
+ {0x0000ab50, 0x00000000, 0x00000000, 0x000eb7c3, 0x000eb7c3, 0x00000000},
+ {0x0000ab54, 0x00000000, 0x00000000, 0x000eb7c7, 0x000eb7c7, 0x00000000},
+ {0x0000ab58, 0x00000000, 0x00000000, 0x000eb7cb, 0x000eb7cb, 0x00000000},
+ {0x0000ab5c, 0x00000000, 0x00000000, 0x000eb7cf, 0x000eb7cf, 0x00000000},
+ {0x0000ab60, 0x00000000, 0x00000000, 0x000eb7d7, 0x000eb7d7, 0x00000000},
+ {0x0000ab64, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+ {0x0000ab68, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+ {0x0000ab6c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+ {0x0000ab70, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+ {0x0000ab74, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+ {0x0000ab78, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+ {0x0000ab7c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+ {0x0000ab80, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+ {0x0000ab84, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+ {0x0000ab88, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+ {0x0000ab8c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+ {0x0000ab90, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+ {0x0000ab94, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+ {0x0000ab98, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+ {0x0000ab9c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+ {0x0000aba0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+ {0x0000aba4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+ {0x0000aba8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+ {0x0000abac, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+ {0x0000abb0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+ {0x0000abb4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+ {0x0000abb8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+ {0x0000abbc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+ {0x0000abc0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+ {0x0000abc4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+ {0x0000abc8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+ {0x0000abcc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+ {0x0000abd0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+ {0x0000abd4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+ {0x0000abd8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+ {0x0000abdc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+ {0x0000abe0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+ {0x0000abe4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+ {0x0000abe8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+ {0x0000abec, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+ {0x0000abf0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+ {0x0000abf4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+ {0x0000abf8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+ {0x0000abfc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+ {0x0000a204, 0x00000004, 0x00000004, 0x00000004, 0x00000004, 0x00000004},
+ {0x0000a20c, 0x00000014, 0x00000014, 0x0001f000, 0x0001f000, 0x0001f000},
+ {0x0000b20c, 0x00000014, 0x00000014, 0x0001f000, 0x0001f000, 0x0001f000},
+ {0x0000a21c, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a},
+ {0x0000a230, 0x00000000, 0x00000000, 0x00000210, 0x00000108, 0x00000000},
+ {0x0000a250, 0x0004f000, 0x0004f000, 0x0004a000, 0x0004a000, 0x0004a000},
+ {0x0000a358, 0x7999aa02, 0x7999aa02, 0x7999aa0e, 0x7999aa0e, 0x7999aa0e},
};
static const u32 ar9271Common_9271[][2] = {
- { 0x0000000c, 0x00000000 },
- { 0x00000030, 0x00020045 },
- { 0x00000034, 0x00000005 },
- { 0x00000040, 0x00000000 },
- { 0x00000044, 0x00000008 },
- { 0x00000048, 0x00000008 },
- { 0x0000004c, 0x00000010 },
- { 0x00000050, 0x00000000 },
- { 0x00000054, 0x0000001f },
- { 0x00000800, 0x00000000 },
- { 0x00000804, 0x00000000 },
- { 0x00000808, 0x00000000 },
- { 0x0000080c, 0x00000000 },
- { 0x00000810, 0x00000000 },
- { 0x00000814, 0x00000000 },
- { 0x00000818, 0x00000000 },
- { 0x0000081c, 0x00000000 },
- { 0x00000820, 0x00000000 },
- { 0x00000824, 0x00000000 },
- { 0x00001040, 0x002ffc0f },
- { 0x00001044, 0x002ffc0f },
- { 0x00001048, 0x002ffc0f },
- { 0x0000104c, 0x002ffc0f },
- { 0x00001050, 0x002ffc0f },
- { 0x00001054, 0x002ffc0f },
- { 0x00001058, 0x002ffc0f },
- { 0x0000105c, 0x002ffc0f },
- { 0x00001060, 0x002ffc0f },
- { 0x00001064, 0x002ffc0f },
- { 0x00001230, 0x00000000 },
- { 0x00001270, 0x00000000 },
- { 0x00001038, 0x00000000 },
- { 0x00001078, 0x00000000 },
- { 0x000010b8, 0x00000000 },
- { 0x000010f8, 0x00000000 },
- { 0x00001138, 0x00000000 },
- { 0x00001178, 0x00000000 },
- { 0x000011b8, 0x00000000 },
- { 0x000011f8, 0x00000000 },
- { 0x00001238, 0x00000000 },
- { 0x00001278, 0x00000000 },
- { 0x000012b8, 0x00000000 },
- { 0x000012f8, 0x00000000 },
- { 0x00001338, 0x00000000 },
- { 0x00001378, 0x00000000 },
- { 0x000013b8, 0x00000000 },
- { 0x000013f8, 0x00000000 },
- { 0x00001438, 0x00000000 },
- { 0x00001478, 0x00000000 },
- { 0x000014b8, 0x00000000 },
- { 0x000014f8, 0x00000000 },
- { 0x00001538, 0x00000000 },
- { 0x00001578, 0x00000000 },
- { 0x000015b8, 0x00000000 },
- { 0x000015f8, 0x00000000 },
- { 0x00001638, 0x00000000 },
- { 0x00001678, 0x00000000 },
- { 0x000016b8, 0x00000000 },
- { 0x000016f8, 0x00000000 },
- { 0x00001738, 0x00000000 },
- { 0x00001778, 0x00000000 },
- { 0x000017b8, 0x00000000 },
- { 0x000017f8, 0x00000000 },
- { 0x0000103c, 0x00000000 },
- { 0x0000107c, 0x00000000 },
- { 0x000010bc, 0x00000000 },
- { 0x000010fc, 0x00000000 },
- { 0x0000113c, 0x00000000 },
- { 0x0000117c, 0x00000000 },
- { 0x000011bc, 0x00000000 },
- { 0x000011fc, 0x00000000 },
- { 0x0000123c, 0x00000000 },
- { 0x0000127c, 0x00000000 },
- { 0x000012bc, 0x00000000 },
- { 0x000012fc, 0x00000000 },
- { 0x0000133c, 0x00000000 },
- { 0x0000137c, 0x00000000 },
- { 0x000013bc, 0x00000000 },
- { 0x000013fc, 0x00000000 },
- { 0x0000143c, 0x00000000 },
- { 0x0000147c, 0x00000000 },
- { 0x00004030, 0x00000002 },
- { 0x0000403c, 0x00000002 },
- { 0x00004024, 0x0000001f },
- { 0x00004060, 0x00000000 },
- { 0x00004064, 0x00000000 },
- { 0x00008004, 0x00000000 },
- { 0x00008008, 0x00000000 },
- { 0x0000800c, 0x00000000 },
- { 0x00008018, 0x00000700 },
- { 0x00008020, 0x00000000 },
- { 0x00008038, 0x00000000 },
- { 0x0000803c, 0x00000000 },
- { 0x00008048, 0x00000000 },
- { 0x00008054, 0x00000000 },
- { 0x00008058, 0x00000000 },
- { 0x0000805c, 0x000fc78f },
- { 0x00008060, 0x0000000f },
- { 0x00008064, 0x00000000 },
- { 0x00008070, 0x00000000 },
- { 0x000080b0, 0x00000000 },
- { 0x000080b4, 0x00000000 },
- { 0x000080b8, 0x00000000 },
- { 0x000080bc, 0x00000000 },
- { 0x000080c0, 0x2a80001a },
- { 0x000080c4, 0x05dc01e0 },
- { 0x000080c8, 0x1f402710 },
- { 0x000080cc, 0x01f40000 },
- { 0x000080d0, 0x00001e00 },
- { 0x000080d4, 0x00000000 },
- { 0x000080d8, 0x00400000 },
- { 0x000080e0, 0xffffffff },
- { 0x000080e4, 0x0000ffff },
- { 0x000080e8, 0x003f3f3f },
- { 0x000080ec, 0x00000000 },
- { 0x000080f0, 0x00000000 },
- { 0x000080f4, 0x00000000 },
- { 0x000080f8, 0x00000000 },
- { 0x000080fc, 0x00020000 },
- { 0x00008100, 0x00020000 },
- { 0x00008104, 0x00000001 },
- { 0x00008108, 0x00000052 },
- { 0x0000810c, 0x00000000 },
- { 0x00008110, 0x00000168 },
- { 0x00008118, 0x000100aa },
- { 0x0000811c, 0x00003210 },
- { 0x00008120, 0x08f04810 },
- { 0x00008124, 0x00000000 },
- { 0x00008128, 0x00000000 },
- { 0x0000812c, 0x00000000 },
- { 0x00008130, 0x00000000 },
- { 0x00008134, 0x00000000 },
- { 0x00008138, 0x00000000 },
- { 0x0000813c, 0x00000000 },
- { 0x00008144, 0xffffffff },
- { 0x00008168, 0x00000000 },
- { 0x0000816c, 0x00000000 },
- { 0x00008170, 0x32143320 },
- { 0x00008174, 0xfaa4fa50 },
- { 0x00008178, 0x00000100 },
- { 0x0000817c, 0x00000000 },
- { 0x000081c0, 0x00000000 },
- { 0x000081d0, 0x0000320a },
- { 0x000081ec, 0x00000000 },
- { 0x000081f0, 0x00000000 },
- { 0x000081f4, 0x00000000 },
- { 0x000081f8, 0x00000000 },
- { 0x000081fc, 0x00000000 },
- { 0x00008200, 0x00000000 },
- { 0x00008204, 0x00000000 },
- { 0x00008208, 0x00000000 },
- { 0x0000820c, 0x00000000 },
- { 0x00008210, 0x00000000 },
- { 0x00008214, 0x00000000 },
- { 0x00008218, 0x00000000 },
- { 0x0000821c, 0x00000000 },
- { 0x00008220, 0x00000000 },
- { 0x00008224, 0x00000000 },
- { 0x00008228, 0x00000000 },
- { 0x0000822c, 0x00000000 },
- { 0x00008230, 0x00000000 },
- { 0x00008234, 0x00000000 },
- { 0x00008238, 0x00000000 },
- { 0x0000823c, 0x00000000 },
- { 0x00008240, 0x00100000 },
- { 0x00008244, 0x0010f400 },
- { 0x00008248, 0x00000100 },
- { 0x0000824c, 0x0001e800 },
- { 0x00008250, 0x00000000 },
- { 0x00008254, 0x00000000 },
- { 0x00008258, 0x00000000 },
- { 0x0000825c, 0x400000ff },
- { 0x00008260, 0x00080922 },
- { 0x00008264, 0x88a00010 },
- { 0x00008270, 0x00000000 },
- { 0x00008274, 0x40000000 },
- { 0x00008278, 0x003e4180 },
- { 0x0000827c, 0x00000000 },
- { 0x00008284, 0x0000002c },
- { 0x00008288, 0x0000002c },
- { 0x0000828c, 0x00000000 },
- { 0x00008294, 0x00000000 },
- { 0x00008298, 0x00000000 },
- { 0x0000829c, 0x00000000 },
- { 0x00008300, 0x00000040 },
- { 0x00008314, 0x00000000 },
- { 0x00008328, 0x00000000 },
- { 0x0000832c, 0x00000001 },
- { 0x00008330, 0x00000302 },
- { 0x00008334, 0x00000e00 },
- { 0x00008338, 0x00ff0000 },
- { 0x0000833c, 0x00000000 },
- { 0x00008340, 0x00010380 },
- { 0x00008344, 0x00581043 },
- { 0x00007010, 0x00000030 },
- { 0x00007034, 0x00000002 },
- { 0x00007038, 0x000004c2 },
- { 0x00007800, 0x00140000 },
- { 0x00007804, 0x0e4548d8 },
- { 0x00007808, 0x54214514 },
- { 0x0000780c, 0x02025820 },
- { 0x00007810, 0x71c0d388 },
- { 0x00007814, 0x924934a8 },
- { 0x0000781c, 0x00000000 },
- { 0x00007828, 0x66964300 },
- { 0x0000782c, 0x8db6d961 },
- { 0x00007830, 0x8db6d96c },
- { 0x00007834, 0x6140008b },
- { 0x0000783c, 0x72ee0a72 },
- { 0x00007840, 0xbbfffffc },
- { 0x00007844, 0x000c0db6 },
- { 0x00007848, 0x6db61b6f },
- { 0x0000784c, 0x6d9b66db },
- { 0x00007850, 0x6d8c6dba },
- { 0x00007854, 0x00040000 },
- { 0x00007858, 0xdb003012 },
- { 0x0000785c, 0x04924914 },
- { 0x00007860, 0x21084210 },
- { 0x00007864, 0xf7d7ffde },
- { 0x00007868, 0xc2034080 },
- { 0x00007870, 0x10142c00 },
- { 0x00009808, 0x00000000 },
- { 0x0000980c, 0xafe68e30 },
- { 0x00009810, 0xfd14e000 },
- { 0x00009814, 0x9c0a9f6b },
- { 0x0000981c, 0x00000000 },
- { 0x0000982c, 0x0000a000 },
- { 0x00009830, 0x00000000 },
- { 0x0000983c, 0x00200400 },
- { 0x0000984c, 0x0040233c },
- { 0x00009854, 0x00000044 },
- { 0x00009900, 0x00000000 },
- { 0x00009904, 0x00000000 },
- { 0x00009908, 0x00000000 },
- { 0x0000990c, 0x00000000 },
- { 0x0000991c, 0x10000fff },
- { 0x00009920, 0x04900000 },
- { 0x00009928, 0x00000001 },
- { 0x0000992c, 0x00000004 },
- { 0x00009934, 0x1e1f2022 },
- { 0x00009938, 0x0a0b0c0d },
- { 0x0000993c, 0x00000000 },
- { 0x00009940, 0x14750604 },
- { 0x00009948, 0x9280c00a },
- { 0x0000994c, 0x00020028 },
- { 0x00009954, 0x5f3ca3de },
- { 0x00009958, 0x0108ecff },
- { 0x00009968, 0x000003ce },
- { 0x00009970, 0x192bb514 },
- { 0x00009974, 0x00000000 },
- { 0x00009978, 0x00000001 },
- { 0x0000997c, 0x00000000 },
- { 0x00009980, 0x00000000 },
- { 0x00009984, 0x00000000 },
- { 0x00009988, 0x00000000 },
- { 0x0000998c, 0x00000000 },
- { 0x00009990, 0x00000000 },
- { 0x00009994, 0x00000000 },
- { 0x00009998, 0x00000000 },
- { 0x0000999c, 0x00000000 },
- { 0x000099a0, 0x00000000 },
- { 0x000099a4, 0x00000001 },
- { 0x000099a8, 0x201fff00 },
- { 0x000099ac, 0x2def0400 },
- { 0x000099b0, 0x03051000 },
- { 0x000099b4, 0x00000820 },
- { 0x000099dc, 0x00000000 },
- { 0x000099e0, 0x00000000 },
- { 0x000099e4, 0xaaaaaaaa },
- { 0x000099e8, 0x3c466478 },
- { 0x000099ec, 0x0cc80caa },
- { 0x000099f0, 0x00000000 },
- { 0x0000a208, 0x803e68c8 },
- { 0x0000a210, 0x4080a333 },
- { 0x0000a214, 0x00206c10 },
- { 0x0000a218, 0x009c4060 },
- { 0x0000a220, 0x01834061 },
- { 0x0000a224, 0x00000400 },
- { 0x0000a228, 0x000003b5 },
- { 0x0000a22c, 0x00000000 },
- { 0x0000a234, 0x20202020 },
- { 0x0000a238, 0x20202020 },
- { 0x0000a244, 0x00000000 },
- { 0x0000a248, 0xfffffffc },
- { 0x0000a24c, 0x00000000 },
- { 0x0000a254, 0x00000000 },
- { 0x0000a258, 0x0ccb5380 },
- { 0x0000a25c, 0x15151501 },
- { 0x0000a260, 0xdfa90f01 },
- { 0x0000a268, 0x00000000 },
- { 0x0000a26c, 0x0ebae9e6 },
- { 0x0000a388, 0x0c000000 },
- { 0x0000a38c, 0x20202020 },
- { 0x0000a390, 0x20202020 },
- { 0x0000a39c, 0x00000001 },
- { 0x0000a3a0, 0x00000000 },
- { 0x0000a3a4, 0x00000000 },
- { 0x0000a3a8, 0x00000000 },
- { 0x0000a3ac, 0x00000000 },
- { 0x0000a3b0, 0x00000000 },
- { 0x0000a3b4, 0x00000000 },
- { 0x0000a3b8, 0x00000000 },
- { 0x0000a3bc, 0x00000000 },
- { 0x0000a3c0, 0x00000000 },
- { 0x0000a3c4, 0x00000000 },
- { 0x0000a3cc, 0x20202020 },
- { 0x0000a3d0, 0x20202020 },
- { 0x0000a3d4, 0x20202020 },
- { 0x0000a3e4, 0x00000000 },
- { 0x0000a3e8, 0x18c43433 },
- { 0x0000a3ec, 0x00f70081 },
- { 0x0000a3f0, 0x01036a2f },
- { 0x0000a3f4, 0x00000000 },
- { 0x0000d270, 0x0d820820 },
- { 0x0000d35c, 0x07ffffef },
- { 0x0000d360, 0x0fffffe7 },
- { 0x0000d364, 0x17ffffe5 },
- { 0x0000d368, 0x1fffffe4 },
- { 0x0000d36c, 0x37ffffe3 },
- { 0x0000d370, 0x3fffffe3 },
- { 0x0000d374, 0x57ffffe3 },
- { 0x0000d378, 0x5fffffe2 },
- { 0x0000d37c, 0x7fffffe2 },
- { 0x0000d380, 0x7f3c7bba },
- { 0x0000d384, 0xf3307ff0 },
+ /* Addr allmodes */
+ {0x0000000c, 0x00000000},
+ {0x00000030, 0x00020045},
+ {0x00000034, 0x00000005},
+ {0x00000040, 0x00000000},
+ {0x00000044, 0x00000008},
+ {0x00000048, 0x00000008},
+ {0x0000004c, 0x00000010},
+ {0x00000050, 0x00000000},
+ {0x00000054, 0x0000001f},
+ {0x00000800, 0x00000000},
+ {0x00000804, 0x00000000},
+ {0x00000808, 0x00000000},
+ {0x0000080c, 0x00000000},
+ {0x00000810, 0x00000000},
+ {0x00000814, 0x00000000},
+ {0x00000818, 0x00000000},
+ {0x0000081c, 0x00000000},
+ {0x00000820, 0x00000000},
+ {0x00000824, 0x00000000},
+ {0x00001040, 0x002ffc0f},
+ {0x00001044, 0x002ffc0f},
+ {0x00001048, 0x002ffc0f},
+ {0x0000104c, 0x002ffc0f},
+ {0x00001050, 0x002ffc0f},
+ {0x00001054, 0x002ffc0f},
+ {0x00001058, 0x002ffc0f},
+ {0x0000105c, 0x002ffc0f},
+ {0x00001060, 0x002ffc0f},
+ {0x00001064, 0x002ffc0f},
+ {0x00001230, 0x00000000},
+ {0x00001270, 0x00000000},
+ {0x00001038, 0x00000000},
+ {0x00001078, 0x00000000},
+ {0x000010b8, 0x00000000},
+ {0x000010f8, 0x00000000},
+ {0x00001138, 0x00000000},
+ {0x00001178, 0x00000000},
+ {0x000011b8, 0x00000000},
+ {0x000011f8, 0x00000000},
+ {0x00001238, 0x00000000},
+ {0x00001278, 0x00000000},
+ {0x000012b8, 0x00000000},
+ {0x000012f8, 0x00000000},
+ {0x00001338, 0x00000000},
+ {0x00001378, 0x00000000},
+ {0x000013b8, 0x00000000},
+ {0x000013f8, 0x00000000},
+ {0x00001438, 0x00000000},
+ {0x00001478, 0x00000000},
+ {0x000014b8, 0x00000000},
+ {0x000014f8, 0x00000000},
+ {0x00001538, 0x00000000},
+ {0x00001578, 0x00000000},
+ {0x000015b8, 0x00000000},
+ {0x000015f8, 0x00000000},
+ {0x00001638, 0x00000000},
+ {0x00001678, 0x00000000},
+ {0x000016b8, 0x00000000},
+ {0x000016f8, 0x00000000},
+ {0x00001738, 0x00000000},
+ {0x00001778, 0x00000000},
+ {0x000017b8, 0x00000000},
+ {0x000017f8, 0x00000000},
+ {0x0000103c, 0x00000000},
+ {0x0000107c, 0x00000000},
+ {0x000010bc, 0x00000000},
+ {0x000010fc, 0x00000000},
+ {0x0000113c, 0x00000000},
+ {0x0000117c, 0x00000000},
+ {0x000011bc, 0x00000000},
+ {0x000011fc, 0x00000000},
+ {0x0000123c, 0x00000000},
+ {0x0000127c, 0x00000000},
+ {0x000012bc, 0x00000000},
+ {0x000012fc, 0x00000000},
+ {0x0000133c, 0x00000000},
+ {0x0000137c, 0x00000000},
+ {0x000013bc, 0x00000000},
+ {0x000013fc, 0x00000000},
+ {0x0000143c, 0x00000000},
+ {0x0000147c, 0x00000000},
+ {0x00004030, 0x00000002},
+ {0x0000403c, 0x00000002},
+ {0x00004024, 0x0000001f},
+ {0x00004060, 0x00000000},
+ {0x00004064, 0x00000000},
+ {0x00008004, 0x00000000},
+ {0x00008008, 0x00000000},
+ {0x0000800c, 0x00000000},
+ {0x00008018, 0x00000700},
+ {0x00008020, 0x00000000},
+ {0x00008038, 0x00000000},
+ {0x0000803c, 0x00000000},
+ {0x00008048, 0x00000000},
+ {0x00008054, 0x00000000},
+ {0x00008058, 0x00000000},
+ {0x0000805c, 0x000fc78f},
+ {0x00008060, 0x0000000f},
+ {0x00008064, 0x00000000},
+ {0x00008070, 0x00000000},
+ {0x000080b0, 0x00000000},
+ {0x000080b4, 0x00000000},
+ {0x000080b8, 0x00000000},
+ {0x000080bc, 0x00000000},
+ {0x000080c0, 0x2a80001a},
+ {0x000080c4, 0x05dc01e0},
+ {0x000080c8, 0x1f402710},
+ {0x000080cc, 0x01f40000},
+ {0x000080d0, 0x00001e00},
+ {0x000080d4, 0x00000000},
+ {0x000080d8, 0x00400000},
+ {0x000080e0, 0xffffffff},
+ {0x000080e4, 0x0000ffff},
+ {0x000080e8, 0x003f3f3f},
+ {0x000080ec, 0x00000000},
+ {0x000080f0, 0x00000000},
+ {0x000080f4, 0x00000000},
+ {0x000080f8, 0x00000000},
+ {0x000080fc, 0x00020000},
+ {0x00008100, 0x00020000},
+ {0x00008104, 0x00000001},
+ {0x00008108, 0x00000052},
+ {0x0000810c, 0x00000000},
+ {0x00008110, 0x00000168},
+ {0x00008118, 0x000100aa},
+ {0x0000811c, 0x00003210},
+ {0x00008120, 0x08f04810},
+ {0x00008124, 0x00000000},
+ {0x00008128, 0x00000000},
+ {0x0000812c, 0x00000000},
+ {0x00008130, 0x00000000},
+ {0x00008134, 0x00000000},
+ {0x00008138, 0x00000000},
+ {0x0000813c, 0x00000000},
+ {0x00008144, 0xffffffff},
+ {0x00008168, 0x00000000},
+ {0x0000816c, 0x00000000},
+ {0x00008170, 0x32143320},
+ {0x00008174, 0xfaa4fa50},
+ {0x00008178, 0x00000100},
+ {0x0000817c, 0x00000000},
+ {0x000081c0, 0x00000000},
+ {0x000081d0, 0x0000320a},
+ {0x000081ec, 0x00000000},
+ {0x000081f0, 0x00000000},
+ {0x000081f4, 0x00000000},
+ {0x000081f8, 0x00000000},
+ {0x000081fc, 0x00000000},
+ {0x00008200, 0x00000000},
+ {0x00008204, 0x00000000},
+ {0x00008208, 0x00000000},
+ {0x0000820c, 0x00000000},
+ {0x00008210, 0x00000000},
+ {0x00008214, 0x00000000},
+ {0x00008218, 0x00000000},
+ {0x0000821c, 0x00000000},
+ {0x00008220, 0x00000000},
+ {0x00008224, 0x00000000},
+ {0x00008228, 0x00000000},
+ {0x0000822c, 0x00000000},
+ {0x00008230, 0x00000000},
+ {0x00008234, 0x00000000},
+ {0x00008238, 0x00000000},
+ {0x0000823c, 0x00000000},
+ {0x00008240, 0x00100000},
+ {0x00008244, 0x0010f400},
+ {0x00008248, 0x00000100},
+ {0x0000824c, 0x0001e800},
+ {0x00008250, 0x00000000},
+ {0x00008254, 0x00000000},
+ {0x00008258, 0x00000000},
+ {0x0000825c, 0x400000ff},
+ {0x00008260, 0x00080922},
+ {0x00008264, 0x88a00010},
+ {0x00008270, 0x00000000},
+ {0x00008274, 0x40000000},
+ {0x00008278, 0x003e4180},
+ {0x0000827c, 0x00000000},
+ {0x00008284, 0x0000002c},
+ {0x00008288, 0x0000002c},
+ {0x0000828c, 0x00000000},
+ {0x00008294, 0x00000000},
+ {0x00008298, 0x00000000},
+ {0x0000829c, 0x00000000},
+ {0x00008300, 0x00000040},
+ {0x00008314, 0x00000000},
+ {0x00008328, 0x00000000},
+ {0x0000832c, 0x00000001},
+ {0x00008330, 0x00000302},
+ {0x00008334, 0x00000e00},
+ {0x00008338, 0x00ff0000},
+ {0x0000833c, 0x00000000},
+ {0x00008340, 0x00010380},
+ {0x00008344, 0x00581043},
+ {0x00007010, 0x00000030},
+ {0x00007034, 0x00000002},
+ {0x00007038, 0x000004c2},
+ {0x00007800, 0x00140000},
+ {0x00007804, 0x0e4548d8},
+ {0x00007808, 0x54214514},
+ {0x0000780c, 0x02025820},
+ {0x00007810, 0x71c0d388},
+ {0x00007814, 0x924934a8},
+ {0x0000781c, 0x00000000},
+ {0x00007828, 0x66964300},
+ {0x0000782c, 0x8db6d961},
+ {0x00007830, 0x8db6d96c},
+ {0x00007834, 0x6140008b},
+ {0x0000783c, 0x72ee0a72},
+ {0x00007840, 0xbbfffffc},
+ {0x00007844, 0x000c0db6},
+ {0x00007848, 0x6db6246f},
+ {0x0000784c, 0x6d9b66db},
+ {0x00007850, 0x6d8c6dba},
+ {0x00007854, 0x00040000},
+ {0x00007858, 0xdb003012},
+ {0x0000785c, 0x04924914},
+ {0x00007860, 0x21084210},
+ {0x00007864, 0xf7d7ffde},
+ {0x00007868, 0xc2034080},
+ {0x00007870, 0x10142c00},
+ {0x00009808, 0x00000000},
+ {0x0000980c, 0xafe68e30},
+ {0x00009810, 0xfd14e000},
+ {0x00009814, 0x9c0a9f6b},
+ {0x0000981c, 0x00000000},
+ {0x0000982c, 0x0000a000},
+ {0x00009830, 0x00000000},
+ {0x0000983c, 0x00200400},
+ {0x0000984c, 0x0040233c},
+ {0x00009854, 0x00000044},
+ {0x00009900, 0x00000000},
+ {0x00009904, 0x00000000},
+ {0x00009908, 0x00000000},
+ {0x0000990c, 0x00000000},
+ {0x0000991c, 0x10000fff},
+ {0x00009920, 0x04900000},
+ {0x00009928, 0x00000001},
+ {0x0000992c, 0x00000004},
+ {0x00009934, 0x1e1f2022},
+ {0x00009938, 0x0a0b0c0d},
+ {0x0000993c, 0x00000000},
+ {0x00009940, 0x14750604},
+ {0x00009948, 0x9280c00a},
+ {0x0000994c, 0x00020028},
+ {0x00009954, 0x5f3ca3de},
+ {0x00009958, 0x0108ecff},
+ {0x00009968, 0x000003ce},
+ {0x00009970, 0x192bb514},
+ {0x00009974, 0x00000000},
+ {0x00009978, 0x00000001},
+ {0x0000997c, 0x00000000},
+ {0x00009980, 0x00000000},
+ {0x00009984, 0x00000000},
+ {0x00009988, 0x00000000},
+ {0x0000998c, 0x00000000},
+ {0x00009990, 0x00000000},
+ {0x00009994, 0x00000000},
+ {0x00009998, 0x00000000},
+ {0x0000999c, 0x00000000},
+ {0x000099a0, 0x00000000},
+ {0x000099a4, 0x00000001},
+ {0x000099a8, 0x201fff00},
+ {0x000099ac, 0x2def0400},
+ {0x000099b0, 0x03051000},
+ {0x000099b4, 0x00000820},
+ {0x000099dc, 0x00000000},
+ {0x000099e0, 0x00000000},
+ {0x000099e4, 0xaaaaaaaa},
+ {0x000099e8, 0x3c466478},
+ {0x000099ec, 0x0cc80caa},
+ {0x000099f0, 0x00000000},
+ {0x0000a208, 0x803e68c8},
+ {0x0000a210, 0x4080a333},
+ {0x0000a214, 0x00206c10},
+ {0x0000a218, 0x009c4060},
+ {0x0000a220, 0x01834061},
+ {0x0000a224, 0x00000400},
+ {0x0000a228, 0x000003b5},
+ {0x0000a22c, 0x00000000},
+ {0x0000a234, 0x20202020},
+ {0x0000a238, 0x20202020},
+ {0x0000a244, 0x00000000},
+ {0x0000a248, 0xfffffffc},
+ {0x0000a24c, 0x00000000},
+ {0x0000a254, 0x00000000},
+ {0x0000a258, 0x0ccb5380},
+ {0x0000a25c, 0x15151501},
+ {0x0000a260, 0xdfa90f01},
+ {0x0000a268, 0x00000000},
+ {0x0000a26c, 0x0ebae9e6},
+ {0x0000a388, 0x0c000000},
+ {0x0000a38c, 0x20202020},
+ {0x0000a390, 0x20202020},
+ {0x0000a39c, 0x00000001},
+ {0x0000a3a0, 0x00000000},
+ {0x0000a3a4, 0x00000000},
+ {0x0000a3a8, 0x00000000},
+ {0x0000a3ac, 0x00000000},
+ {0x0000a3b0, 0x00000000},
+ {0x0000a3b4, 0x00000000},
+ {0x0000a3b8, 0x00000000},
+ {0x0000a3bc, 0x00000000},
+ {0x0000a3c0, 0x00000000},
+ {0x0000a3c4, 0x00000000},
+ {0x0000a3cc, 0x20202020},
+ {0x0000a3d0, 0x20202020},
+ {0x0000a3d4, 0x20202020},
+ {0x0000a3e4, 0x00000000},
+ {0x0000a3e8, 0x18c43433},
+ {0x0000a3ec, 0x00f70081},
+ {0x0000a3f0, 0x01036a2f},
+ {0x0000a3f4, 0x00000000},
+ {0x0000d270, 0x0d820820},
+ {0x0000d35c, 0x07ffffef},
+ {0x0000d360, 0x0fffffe7},
+ {0x0000d364, 0x17ffffe5},
+ {0x0000d368, 0x1fffffe4},
+ {0x0000d36c, 0x37ffffe3},
+ {0x0000d370, 0x3fffffe3},
+ {0x0000d374, 0x57ffffe3},
+ {0x0000d378, 0x5fffffe2},
+ {0x0000d37c, 0x7fffffe2},
+ {0x0000d380, 0x7f3c7bba},
+ {0x0000d384, 0xf3307ff0},
};
static const u32 ar9271Common_normal_cck_fir_coeff_9271[][2] = {
- { 0x0000a1f4, 0x00fffeff },
- { 0x0000a1f8, 0x00f5f9ff },
- { 0x0000a1fc, 0xb79f6427 },
+ /* Addr allmodes */
+ {0x0000a1f4, 0x00fffeff},
+ {0x0000a1f8, 0x00f5f9ff},
+ {0x0000a1fc, 0xb79f6427},
};
static const u32 ar9271Common_japan_2484_cck_fir_coeff_9271[][2] = {
- { 0x0000a1f4, 0x00000000 },
- { 0x0000a1f8, 0xefff0301 },
- { 0x0000a1fc, 0xca9228ee },
+ /* Addr allmodes */
+ {0x0000a1f4, 0x00000000},
+ {0x0000a1f8, 0xefff0301},
+ {0x0000a1fc, 0xca9228ee},
};
static const u32 ar9271Modes_9271_1_0_only[][6] = {
- { 0x00009910, 0x30002311, 0x30002311, 0x30002311, 0x30002311, 0x30002311 },
- { 0x00009828, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001 },
+ {0x00009910, 0x30002311, 0x30002311, 0x30002311, 0x30002311, 0x30002311},
+ {0x00009828, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001},
};
static const u32 ar9271Modes_9271_ANI_reg[][6] = {
- { 0x00009850, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2 },
- { 0x0000985c, 0x3139605e, 0x3139605e, 0x3137605e, 0x3137605e, 0x3139605e },
- { 0x00009858, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e },
- { 0x0000986c, 0x06903881, 0x06903881, 0x06903881, 0x06903881, 0x06903881 },
- { 0x00009868, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0 },
- { 0x0000a208, 0x803e68c8, 0x803e68c8, 0x803e68c8, 0x803e68c8, 0x803e68c8 },
- { 0x00009924, 0xd00a8007, 0xd00a8007, 0xd00a800d, 0xd00a800d, 0xd00a800d },
- { 0x000099c0, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4 },
+ {0x00009850, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2},
+ {0x0000985c, 0x3139605e, 0x3139605e, 0x3137605e, 0x3137605e, 0x3139605e},
+ {0x00009858, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e},
+ {0x0000986c, 0x06903881, 0x06903881, 0x06903881, 0x06903881, 0x06903881},
+ {0x00009868, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0},
+ {0x0000a208, 0x803e68c8, 0x803e68c8, 0x803e68c8, 0x803e68c8, 0x803e68c8},
+ {0x00009924, 0xd00a8007, 0xd00a8007, 0xd00a800d, 0xd00a800d, 0xd00a800d},
+ {0x000099c0, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4},
};
static const u32 ar9271Modes_normal_power_tx_gain_9271[][6] = {
- { 0x0000a300, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
- { 0x0000a304, 0x00000000, 0x00000000, 0x00009200, 0x00009200, 0x00000000 },
- { 0x0000a308, 0x00000000, 0x00000000, 0x00010208, 0x00010208, 0x00000000 },
- { 0x0000a30c, 0x00000000, 0x00000000, 0x00019608, 0x00019608, 0x00000000 },
- { 0x0000a310, 0x00000000, 0x00000000, 0x0001e610, 0x0001e610, 0x00000000 },
- { 0x0000a314, 0x00000000, 0x00000000, 0x0002d6d0, 0x0002d6d0, 0x00000000 },
- { 0x0000a318, 0x00000000, 0x00000000, 0x00039758, 0x00039758, 0x00000000 },
- { 0x0000a31c, 0x00000000, 0x00000000, 0x0003b759, 0x0003b759, 0x00000000 },
- { 0x0000a320, 0x00000000, 0x00000000, 0x0003d75a, 0x0003d75a, 0x00000000 },
- { 0x0000a324, 0x00000000, 0x00000000, 0x0004175c, 0x0004175c, 0x00000000 },
- { 0x0000a328, 0x00000000, 0x00000000, 0x0004575e, 0x0004575e, 0x00000000 },
- { 0x0000a32c, 0x00000000, 0x00000000, 0x0004979f, 0x0004979f, 0x00000000 },
- { 0x0000a330, 0x00000000, 0x00000000, 0x0004d7df, 0x0004d7df, 0x00000000 },
- { 0x0000a334, 0x000368de, 0x000368de, 0x000368de, 0x000368de, 0x00000000 },
- { 0x0000a338, 0x0003891e, 0x0003891e, 0x0003891e, 0x0003891e, 0x00000000 },
- { 0x0000a33c, 0x0003a95e, 0x0003a95e, 0x0003a95e, 0x0003a95e, 0x00000000 },
- { 0x0000a340, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 },
- { 0x0000a344, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 },
- { 0x0000a348, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 },
- { 0x0000a34c, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 },
- { 0x0000a350, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 },
- { 0x0000a354, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 },
- { 0x00007838, 0x00000029, 0x00000029, 0x00000029, 0x00000029, 0x00000029 },
- { 0x00007824, 0x00d8abff, 0x00d8abff, 0x00d8abff, 0x00d8abff, 0x00d8abff },
- { 0x0000786c, 0x48609eb4, 0x48609eb4, 0x48609eb4, 0x48609eb4, 0x48609eb4 },
- { 0x00007820, 0x00000c04, 0x00000c04, 0x00000c04, 0x00000c04, 0x00000c04 },
- { 0x0000a274, 0x0a21c652, 0x0a21c652, 0x0a218652, 0x0a218652, 0x0a22a652 },
- { 0x0000a278, 0x3bdef7bd, 0x3bdef7bd, 0x3bdef7bd, 0x3bdef7bd, 0x3bdef7bd },
- { 0x0000a27c, 0x050e83bd, 0x050e83bd, 0x050e83bd, 0x050e83bd, 0x050e83bd },
- { 0x0000a394, 0x3bdef7bd, 0x3bdef7bd, 0x3bdef7bd, 0x3bdef7bd, 0x3bdef7bd },
- { 0x0000a398, 0x000003bd, 0x000003bd, 0x000003bd, 0x000003bd, 0x000003bd },
- { 0x0000a3dc, 0x3bdef7bd, 0x3bdef7bd, 0x3bdef7bd, 0x3bdef7bd, 0x3bdef7bd },
- { 0x0000a3e0, 0x000003bd, 0x000003bd, 0x000003bd, 0x000003bd, 0x000003bd },
+ {0x0000a300, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+ {0x0000a304, 0x00000000, 0x00000000, 0x00009200, 0x00009200, 0x00000000},
+ {0x0000a308, 0x00000000, 0x00000000, 0x00010208, 0x00010208, 0x00000000},
+ {0x0000a30c, 0x00000000, 0x00000000, 0x00019608, 0x00019608, 0x00000000},
+ {0x0000a310, 0x00000000, 0x00000000, 0x0001e610, 0x0001e610, 0x00000000},
+ {0x0000a314, 0x00000000, 0x00000000, 0x0002d6d0, 0x0002d6d0, 0x00000000},
+ {0x0000a318, 0x00000000, 0x00000000, 0x00039758, 0x00039758, 0x00000000},
+ {0x0000a31c, 0x00000000, 0x00000000, 0x0003b759, 0x0003b759, 0x00000000},
+ {0x0000a320, 0x00000000, 0x00000000, 0x0003d75a, 0x0003d75a, 0x00000000},
+ {0x0000a324, 0x00000000, 0x00000000, 0x0004175c, 0x0004175c, 0x00000000},
+ {0x0000a328, 0x00000000, 0x00000000, 0x0004575e, 0x0004575e, 0x00000000},
+ {0x0000a32c, 0x00000000, 0x00000000, 0x0004979f, 0x0004979f, 0x00000000},
+ {0x0000a330, 0x00000000, 0x00000000, 0x0004d7df, 0x0004d7df, 0x00000000},
+ {0x0000a334, 0x000368de, 0x000368de, 0x000368de, 0x000368de, 0x00000000},
+ {0x0000a338, 0x0003891e, 0x0003891e, 0x0003891e, 0x0003891e, 0x00000000},
+ {0x0000a33c, 0x0003a95e, 0x0003a95e, 0x0003a95e, 0x0003a95e, 0x00000000},
+ {0x0000a340, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000},
+ {0x0000a344, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000},
+ {0x0000a348, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000},
+ {0x0000a34c, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000},
+ {0x0000a350, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000},
+ {0x0000a354, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000},
+ {0x00007838, 0x00000029, 0x00000029, 0x00000029, 0x00000029, 0x00000029},
+ {0x00007824, 0x00d8abff, 0x00d8abff, 0x00d8abff, 0x00d8abff, 0x00d8abff},
+ {0x0000786c, 0x48609eb4, 0x48609eb4, 0x48609eb4, 0x48609eb4, 0x48609eb4},
+ {0x00007820, 0x00000c04, 0x00000c04, 0x00000c04, 0x00000c04, 0x00000c04},
+ {0x0000a274, 0x0a21c652, 0x0a21c652, 0x0a218652, 0x0a218652, 0x0a22a652},
+ {0x0000a278, 0x3bdef7bd, 0x3bdef7bd, 0x3bdef7bd, 0x3bdef7bd, 0x3bdef7bd},
+ {0x0000a27c, 0x050e83bd, 0x050e83bd, 0x050e83bd, 0x050e83bd, 0x050e83bd},
+ {0x0000a394, 0x3bdef7bd, 0x3bdef7bd, 0x3bdef7bd, 0x3bdef7bd, 0x3bdef7bd},
+ {0x0000a398, 0x000003bd, 0x000003bd, 0x000003bd, 0x000003bd, 0x000003bd},
+ {0x0000a3dc, 0x3bdef7bd, 0x3bdef7bd, 0x3bdef7bd, 0x3bdef7bd, 0x3bdef7bd},
+ {0x0000a3e0, 0x000003bd, 0x000003bd, 0x000003bd, 0x000003bd, 0x000003bd},
};
static const u32 ar9271Modes_high_power_tx_gain_9271[][6] = {
- { 0x0000a300, 0x00000000, 0x00000000, 0x00010000, 0x00010000, 0x00000000 },
- { 0x0000a304, 0x00000000, 0x00000000, 0x00016200, 0x00016200, 0x00000000 },
- { 0x0000a308, 0x00000000, 0x00000000, 0x00018201, 0x00018201, 0x00000000 },
- { 0x0000a30c, 0x00000000, 0x00000000, 0x0001b240, 0x0001b240, 0x00000000 },
- { 0x0000a310, 0x00000000, 0x00000000, 0x0001d241, 0x0001d241, 0x00000000 },
- { 0x0000a314, 0x00000000, 0x00000000, 0x0001f600, 0x0001f600, 0x00000000 },
- { 0x0000a318, 0x00000000, 0x00000000, 0x00022800, 0x00022800, 0x00000000 },
- { 0x0000a31c, 0x00000000, 0x00000000, 0x00026802, 0x00026802, 0x00000000 },
- { 0x0000a320, 0x00000000, 0x00000000, 0x0002b805, 0x0002b805, 0x00000000 },
- { 0x0000a324, 0x00000000, 0x00000000, 0x0002ea41, 0x0002ea41, 0x00000000 },
- { 0x0000a328, 0x00000000, 0x00000000, 0x00038b00, 0x00038b00, 0x00000000 },
- { 0x0000a32c, 0x00000000, 0x00000000, 0x0003ab40, 0x0003ab40, 0x00000000 },
- { 0x0000a330, 0x00000000, 0x00000000, 0x0003cd80, 0x0003cd80, 0x00000000 },
- { 0x0000a334, 0x000368de, 0x000368de, 0x000368de, 0x000368de, 0x00000000 },
- { 0x0000a338, 0x0003891e, 0x0003891e, 0x0003891e, 0x0003891e, 0x00000000 },
- { 0x0000a33c, 0x0003a95e, 0x0003a95e, 0x0003a95e, 0x0003a95e, 0x00000000 },
- { 0x0000a340, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 },
- { 0x0000a344, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 },
- { 0x0000a348, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 },
- { 0x0000a34c, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 },
- { 0x0000a350, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 },
- { 0x0000a354, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 },
- { 0x00007838, 0x0000002b, 0x0000002b, 0x0000002b, 0x0000002b, 0x0000002b },
- { 0x00007824, 0x00d8a7ff, 0x00d8a7ff, 0x00d8a7ff, 0x00d8a7ff, 0x00d8a7ff },
- { 0x0000786c, 0x08609eb6, 0x08609eb6, 0x08609eba, 0x08609eba, 0x08609eb6 },
- { 0x00007820, 0x00000c00, 0x00000c00, 0x00000c00, 0x00000c00, 0x00000c00 },
- { 0x0000a274, 0x0a22a652, 0x0a22a652, 0x0a212652, 0x0a212652, 0x0a22a652 },
- { 0x0000a278, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7 },
- { 0x0000a27c, 0x05018063, 0x05038063, 0x05018063, 0x05018063, 0x05018063 },
- { 0x0000a394, 0x06318c63, 0x06318c63, 0x06318c63, 0x06318c63, 0x06318c63 },
- { 0x0000a398, 0x00000063, 0x00000063, 0x00000063, 0x00000063, 0x00000063 },
- { 0x0000a3dc, 0x06318c63, 0x06318c63, 0x06318c63, 0x06318c63, 0x06318c63 },
- { 0x0000a3e0, 0x00000063, 0x00000063, 0x00000063, 0x00000063, 0x00000063 },
+ {0x0000a300, 0x00000000, 0x00000000, 0x00010000, 0x00010000, 0x00000000},
+ {0x0000a304, 0x00000000, 0x00000000, 0x00016200, 0x00016200, 0x00000000},
+ {0x0000a308, 0x00000000, 0x00000000, 0x00018201, 0x00018201, 0x00000000},
+ {0x0000a30c, 0x00000000, 0x00000000, 0x0001b240, 0x0001b240, 0x00000000},
+ {0x0000a310, 0x00000000, 0x00000000, 0x0001d241, 0x0001d241, 0x00000000},
+ {0x0000a314, 0x00000000, 0x00000000, 0x0001f600, 0x0001f600, 0x00000000},
+ {0x0000a318, 0x00000000, 0x00000000, 0x00022800, 0x00022800, 0x00000000},
+ {0x0000a31c, 0x00000000, 0x00000000, 0x00026802, 0x00026802, 0x00000000},
+ {0x0000a320, 0x00000000, 0x00000000, 0x0002b805, 0x0002b805, 0x00000000},
+ {0x0000a324, 0x00000000, 0x00000000, 0x0002ea41, 0x0002ea41, 0x00000000},
+ {0x0000a328, 0x00000000, 0x00000000, 0x00038b00, 0x00038b00, 0x00000000},
+ {0x0000a32c, 0x00000000, 0x00000000, 0x0003ab40, 0x0003ab40, 0x00000000},
+ {0x0000a330, 0x00000000, 0x00000000, 0x0003cd80, 0x0003cd80, 0x00000000},
+ {0x0000a334, 0x000368de, 0x000368de, 0x000368de, 0x000368de, 0x00000000},
+ {0x0000a338, 0x0003891e, 0x0003891e, 0x0003891e, 0x0003891e, 0x00000000},
+ {0x0000a33c, 0x0003a95e, 0x0003a95e, 0x0003a95e, 0x0003a95e, 0x00000000},
+ {0x0000a340, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000},
+ {0x0000a344, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000},
+ {0x0000a348, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000},
+ {0x0000a34c, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000},
+ {0x0000a350, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000},
+ {0x0000a354, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000},
+ {0x00007838, 0x0000002b, 0x0000002b, 0x0000002b, 0x0000002b, 0x0000002b},
+ {0x00007824, 0x00d8a7ff, 0x00d8a7ff, 0x00d8a7ff, 0x00d8a7ff, 0x00d8a7ff},
+ {0x0000786c, 0x08609eb6, 0x08609eb6, 0x08609eba, 0x08609eba, 0x08609eb6},
+ {0x00007820, 0x00000c00, 0x00000c00, 0x00000c00, 0x00000c00, 0x00000c00},
+ {0x0000a274, 0x0a22a652, 0x0a22a652, 0x0a214652, 0x0a214652, 0x0a22a652},
+ {0x0000a278, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7},
+ {0x0000a27c, 0x05018063, 0x05038063, 0x05018063, 0x05018063, 0x05018063},
+ {0x0000a394, 0x06318c63, 0x06318c63, 0x06318c63, 0x06318c63, 0x06318c63},
+ {0x0000a398, 0x00000063, 0x00000063, 0x00000063, 0x00000063, 0x00000063},
+ {0x0000a3dc, 0x06318c63, 0x06318c63, 0x06318c63, 0x06318c63, 0x06318c63},
+ {0x0000a3e0, 0x00000063, 0x00000063, 0x00000063, 0x00000063, 0x00000063},
};
-#endif /* INITVALS_9002_10_H */
diff --git a/drivers/net/wireless/ath/ath9k/ar9002_mac.c b/drivers/net/wireless/ath/ath9k/ar9002_mac.c
index 2be20d2070c..50dda394f8b 100644
--- a/drivers/net/wireless/ath/ath9k/ar9002_mac.c
+++ b/drivers/net/wireless/ath/ath9k/ar9002_mac.c
@@ -287,6 +287,7 @@ static int ar9002_hw_proc_txdesc(struct ath_hw *ah, void *ds,
ts->ts_shortretry = MS(ads->ds_txstatus1, AR_RTSFailCnt);
ts->ts_longretry = MS(ads->ds_txstatus1, AR_DataFailCnt);
ts->ts_virtcol = MS(ads->ds_txstatus1, AR_VirtRetryCnt);
+ ts->tid = MS(ads->ds_txstatus9, AR_TxTid);
ts->ts_antenna = 0;
return 0;
diff --git a/drivers/net/wireless/ath/ath9k/ar9002_phy.c b/drivers/net/wireless/ath/ath9k/ar9002_phy.c
index ed314e89bfe..adbf031fbc5 100644
--- a/drivers/net/wireless/ath/ath9k/ar9002_phy.c
+++ b/drivers/net/wireless/ath/ath9k/ar9002_phy.c
@@ -471,52 +471,47 @@ static u32 ar9002_hw_compute_pll_control(struct ath_hw *ah,
static void ar9002_hw_do_getnf(struct ath_hw *ah,
int16_t nfarray[NUM_NF_READINGS])
{
- struct ath_common *common = ath9k_hw_common(ah);
int16_t nf;
nf = MS(REG_READ(ah, AR_PHY_CCA), AR9280_PHY_MINCCA_PWR);
-
- if (nf & 0x100)
- nf = 0 - ((nf ^ 0x1ff) + 1);
- ath_print(common, ATH_DBG_CALIBRATE,
- "NF calibrated [ctl] [chain 0] is %d\n", nf);
-
- if (AR_SREV_9271(ah) && (nf >= -114))
- nf = -116;
-
- nfarray[0] = nf;
-
- if (!AR_SREV_9285(ah) && !AR_SREV_9271(ah)) {
- nf = MS(REG_READ(ah, AR_PHY_CH1_CCA),
- AR9280_PHY_CH1_MINCCA_PWR);
-
- if (nf & 0x100)
- nf = 0 - ((nf ^ 0x1ff) + 1);
- ath_print(common, ATH_DBG_CALIBRATE,
- "NF calibrated [ctl] [chain 1] is %d\n", nf);
- nfarray[1] = nf;
- }
+ nfarray[0] = sign_extend(nf, 9);
nf = MS(REG_READ(ah, AR_PHY_EXT_CCA), AR9280_PHY_EXT_MINCCA_PWR);
- if (nf & 0x100)
- nf = 0 - ((nf ^ 0x1ff) + 1);
- ath_print(common, ATH_DBG_CALIBRATE,
- "NF calibrated [ext] [chain 0] is %d\n", nf);
+ if (IS_CHAN_HT40(ah->curchan))
+ nfarray[3] = sign_extend(nf, 9);
- if (AR_SREV_9271(ah) && (nf >= -114))
- nf = -116;
+ if (AR_SREV_9285(ah) || AR_SREV_9271(ah))
+ return;
- nfarray[3] = nf;
+ nf = MS(REG_READ(ah, AR_PHY_CH1_CCA), AR9280_PHY_CH1_MINCCA_PWR);
+ nfarray[1] = sign_extend(nf, 9);
- if (!AR_SREV_9285(ah) && !AR_SREV_9271(ah)) {
- nf = MS(REG_READ(ah, AR_PHY_CH1_EXT_CCA),
- AR9280_PHY_CH1_EXT_MINCCA_PWR);
+ nf = MS(REG_READ(ah, AR_PHY_CH1_EXT_CCA), AR9280_PHY_CH1_EXT_MINCCA_PWR);
+ if (IS_CHAN_HT40(ah->curchan))
+ nfarray[4] = sign_extend(nf, 9);
+}
- if (nf & 0x100)
- nf = 0 - ((nf ^ 0x1ff) + 1);
- ath_print(common, ATH_DBG_CALIBRATE,
- "NF calibrated [ext] [chain 1] is %d\n", nf);
- nfarray[4] = nf;
+static void ar9002_hw_set_nf_limits(struct ath_hw *ah)
+{
+ if (AR_SREV_9285(ah)) {
+ ah->nf_2g.max = AR_PHY_CCA_MAX_GOOD_VAL_9285_2GHZ;
+ ah->nf_2g.min = AR_PHY_CCA_MIN_GOOD_VAL_9285_2GHZ;
+ ah->nf_2g.nominal = AR_PHY_CCA_NOM_VAL_9285_2GHZ;
+ } else if (AR_SREV_9287(ah)) {
+ ah->nf_2g.max = AR_PHY_CCA_MAX_GOOD_VAL_9287_2GHZ;
+ ah->nf_2g.min = AR_PHY_CCA_MIN_GOOD_VAL_9287_2GHZ;
+ ah->nf_2g.nominal = AR_PHY_CCA_NOM_VAL_9287_2GHZ;
+ } else if (AR_SREV_9271(ah)) {
+ ah->nf_2g.max = AR_PHY_CCA_MAX_GOOD_VAL_9271_2GHZ;
+ ah->nf_2g.min = AR_PHY_CCA_MIN_GOOD_VAL_9271_2GHZ;
+ ah->nf_2g.nominal = AR_PHY_CCA_NOM_VAL_9271_2GHZ;
+ } else {
+ ah->nf_2g.max = AR_PHY_CCA_MAX_GOOD_VAL_9280_2GHZ;
+ ah->nf_2g.min = AR_PHY_CCA_MIN_GOOD_VAL_9280_2GHZ;
+ ah->nf_2g.nominal = AR_PHY_CCA_NOM_VAL_9280_2GHZ;
+ ah->nf_5g.max = AR_PHY_CCA_MAX_GOOD_VAL_9280_5GHZ;
+ ah->nf_5g.min = AR_PHY_CCA_MIN_GOOD_VAL_9280_5GHZ;
+ ah->nf_5g.nominal = AR_PHY_CCA_NOM_VAL_9280_5GHZ;
}
}
@@ -532,4 +527,6 @@ void ar9002_hw_attach_phy_ops(struct ath_hw *ah)
priv_ops->olc_init = ar9002_olc_init;
priv_ops->compute_pll_control = ar9002_hw_compute_pll_control;
priv_ops->do_getnf = ar9002_hw_do_getnf;
+
+ ar9002_hw_set_nf_limits(ah);
}
diff --git a/drivers/net/wireless/ath/ath9k/ar9002_phy.h b/drivers/net/wireless/ath/ath9k/ar9002_phy.h
index 81bf6e5840e..c5151a4dd10 100644
--- a/drivers/net/wireless/ath/ath9k/ar9002_phy.h
+++ b/drivers/net/wireless/ath/ath9k/ar9002_phy.h
@@ -114,6 +114,10 @@
#define AR_PHY_FIND_SIG_FIRPWR 0x03FC0000
#define AR_PHY_FIND_SIG_FIRPWR_S 18
+#define AR_PHY_FIND_SIG_LOW 0x9840
+#define AR_PHY_FIND_SIG_FIRSTEP_LOW 0x00000FC0L
+#define AR_PHY_FIND_SIG_FIRSTEP_LOW_S 6
+
#define AR_PHY_AGC_CTL1 0x985C
#define AR_PHY_AGC_CTL1_COARSE_LOW 0x00007F80
#define AR_PHY_AGC_CTL1_COARSE_LOW_S 7
@@ -325,6 +329,9 @@
#define AR_PHY_EXT_CCA_CYCPWR_THR1_S 9
#define AR_PHY_EXT_CCA_THRESH62 0x007F0000
#define AR_PHY_EXT_CCA_THRESH62_S 16
+#define AR_PHY_EXT_TIMING5_CYCPWR_THR1 0x0000FE00L
+#define AR_PHY_EXT_TIMING5_CYCPWR_THR1_S 9
+
#define AR_PHY_EXT_MINCCA_PWR 0xFF800000
#define AR_PHY_EXT_MINCCA_PWR_S 23
#define AR9280_PHY_EXT_MINCCA_PWR 0x01FF0000
@@ -569,4 +576,30 @@
#define AR_PHY_CH2_EXT_MINCCA_PWR 0xFF800000
#define AR_PHY_CH2_EXT_MINCCA_PWR_S 23
+#define AR_PHY_CCA_NOM_VAL_5416_2GHZ -90
+#define AR_PHY_CCA_NOM_VAL_5416_5GHZ -100
+#define AR_PHY_CCA_MIN_GOOD_VAL_5416_2GHZ -100
+#define AR_PHY_CCA_MIN_GOOD_VAL_5416_5GHZ -110
+#define AR_PHY_CCA_MAX_GOOD_VAL_5416_2GHZ -80
+#define AR_PHY_CCA_MAX_GOOD_VAL_5416_5GHZ -90
+
+#define AR_PHY_CCA_NOM_VAL_9280_2GHZ -112
+#define AR_PHY_CCA_NOM_VAL_9280_5GHZ -112
+#define AR_PHY_CCA_MIN_GOOD_VAL_9280_2GHZ -127
+#define AR_PHY_CCA_MIN_GOOD_VAL_9280_5GHZ -122
+#define AR_PHY_CCA_MAX_GOOD_VAL_9280_2GHZ -97
+#define AR_PHY_CCA_MAX_GOOD_VAL_9280_5GHZ -102
+
+#define AR_PHY_CCA_NOM_VAL_9285_2GHZ -118
+#define AR_PHY_CCA_MIN_GOOD_VAL_9285_2GHZ -127
+#define AR_PHY_CCA_MAX_GOOD_VAL_9285_2GHZ -108
+
+#define AR_PHY_CCA_NOM_VAL_9271_2GHZ -118
+#define AR_PHY_CCA_MIN_GOOD_VAL_9271_2GHZ -127
+#define AR_PHY_CCA_MAX_GOOD_VAL_9271_2GHZ -116
+
+#define AR_PHY_CCA_NOM_VAL_9287_2GHZ -120
+#define AR_PHY_CCA_MIN_GOOD_VAL_9287_2GHZ -127
+#define AR_PHY_CCA_MAX_GOOD_VAL_9287_2GHZ -110
+
#endif
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_initvals.h b/drivers/net/wireless/ath/ath9k/ar9003_2p0_initvals.h
index db019dd220b..d3375fc4ce8 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_initvals.h
+++ b/drivers/net/wireless/ath/ath9k/ar9003_2p0_initvals.h
@@ -14,8 +14,8 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-#ifndef INITVALS_9003_H
-#define INITVALS_9003_H
+#ifndef INITVALS_9003_2P0_H
+#define INITVALS_9003_2P0_H
/* AR9003 2.0 */
@@ -835,71 +835,71 @@ static const u32 ar9300_2p0_baseband_core[][2] = {
static const u32 ar9300Modes_high_power_tx_gain_table_2p0[][5] = {
/* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */
- {0x0000a410, 0x000050d9, 0x000050d9, 0x000050d9, 0x000050d9},
+ {0x0000a410, 0x000050d8, 0x000050d8, 0x000050d9, 0x000050d9},
{0x0000a500, 0x00002220, 0x00002220, 0x00000000, 0x00000000},
- {0x0000a504, 0x06002223, 0x06002223, 0x04000002, 0x04000002},
- {0x0000a508, 0x0a022220, 0x0a022220, 0x08000004, 0x08000004},
- {0x0000a50c, 0x0f022223, 0x0f022223, 0x0b000200, 0x0b000200},
- {0x0000a510, 0x14022620, 0x14022620, 0x0f000202, 0x0f000202},
- {0x0000a514, 0x18022622, 0x18022622, 0x11000400, 0x11000400},
- {0x0000a518, 0x1b022822, 0x1b022822, 0x15000402, 0x15000402},
- {0x0000a51c, 0x20022842, 0x20022842, 0x19000404, 0x19000404},
- {0x0000a520, 0x22022c41, 0x22022c41, 0x1b000603, 0x1b000603},
- {0x0000a524, 0x28023042, 0x28023042, 0x1f000a02, 0x1f000a02},
- {0x0000a528, 0x2c023044, 0x2c023044, 0x23000a04, 0x23000a04},
- {0x0000a52c, 0x2f023644, 0x2f023644, 0x26000a20, 0x26000a20},
- {0x0000a530, 0x34025643, 0x34025643, 0x2a000e20, 0x2a000e20},
- {0x0000a534, 0x38025a44, 0x38025a44, 0x2e000e22, 0x2e000e22},
- {0x0000a538, 0x3b025e45, 0x3b025e45, 0x31000e24, 0x31000e24},
- {0x0000a53c, 0x41025e4a, 0x41025e4a, 0x34001640, 0x34001640},
- {0x0000a540, 0x48025e6c, 0x48025e6c, 0x38001660, 0x38001660},
- {0x0000a544, 0x4e025e8e, 0x4e025e8e, 0x3b001861, 0x3b001861},
- {0x0000a548, 0x53025eb2, 0x53025eb2, 0x3e001a81, 0x3e001a81},
+ {0x0000a504, 0x04002222, 0x04002222, 0x04000002, 0x04000002},
+ {0x0000a508, 0x09002421, 0x09002421, 0x08000004, 0x08000004},
+ {0x0000a50c, 0x0d002621, 0x0d002621, 0x0b000200, 0x0b000200},
+ {0x0000a510, 0x13004620, 0x13004620, 0x0f000202, 0x0f000202},
+ {0x0000a514, 0x19004a20, 0x19004a20, 0x11000400, 0x11000400},
+ {0x0000a518, 0x1d004e20, 0x1d004e20, 0x15000402, 0x15000402},
+ {0x0000a51c, 0x21005420, 0x21005420, 0x19000404, 0x19000404},
+ {0x0000a520, 0x26005e20, 0x26005e20, 0x1b000603, 0x1b000603},
+ {0x0000a524, 0x2b005e40, 0x2b005e40, 0x1f000a02, 0x1f000a02},
+ {0x0000a528, 0x2f005e42, 0x2f005e42, 0x23000a04, 0x23000a04},
+ {0x0000a52c, 0x33005e44, 0x33005e44, 0x26000a20, 0x26000a20},
+ {0x0000a530, 0x38005e65, 0x38005e65, 0x2a000e20, 0x2a000e20},
+ {0x0000a534, 0x3c005e69, 0x3c005e69, 0x2e000e22, 0x2e000e22},
+ {0x0000a538, 0x40005e6b, 0x40005e6b, 0x31000e24, 0x31000e24},
+ {0x0000a53c, 0x44005e6d, 0x44005e6d, 0x34001640, 0x34001640},
+ {0x0000a540, 0x49005e72, 0x49005e72, 0x38001660, 0x38001660},
+ {0x0000a544, 0x4e005eb2, 0x4e005eb2, 0x3b001861, 0x3b001861},
+ {0x0000a548, 0x53005f12, 0x53005f12, 0x3e001a81, 0x3e001a81},
{0x0000a54c, 0x59025eb5, 0x59025eb5, 0x42001a83, 0x42001a83},
- {0x0000a550, 0x5f025ef6, 0x5f025ef6, 0x44001c84, 0x44001c84},
- {0x0000a554, 0x62025f56, 0x62025f56, 0x48001ce3, 0x48001ce3},
- {0x0000a558, 0x66027f56, 0x66027f56, 0x4c001ce5, 0x4c001ce5},
- {0x0000a55c, 0x6a029f56, 0x6a029f56, 0x50001ce9, 0x50001ce9},
- {0x0000a560, 0x70049f56, 0x70049f56, 0x54001ceb, 0x54001ceb},
- {0x0000a564, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec},
- {0x0000a568, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec},
- {0x0000a56c, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec},
- {0x0000a570, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec},
- {0x0000a574, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec},
- {0x0000a578, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec},
- {0x0000a57c, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec},
+ {0x0000a550, 0x5e025f12, 0x5e025f12, 0x44001c84, 0x44001c84},
+ {0x0000a554, 0x61027f12, 0x61027f12, 0x48001ce3, 0x48001ce3},
+ {0x0000a558, 0x6702bf12, 0x6702bf12, 0x4c001ce5, 0x4c001ce5},
+ {0x0000a55c, 0x6b02bf14, 0x6b02bf14, 0x50001ce9, 0x50001ce9},
+ {0x0000a560, 0x6f02bf16, 0x6f02bf16, 0x54001ceb, 0x54001ceb},
+ {0x0000a564, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec},
+ {0x0000a568, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec},
+ {0x0000a56c, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec},
+ {0x0000a570, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec},
+ {0x0000a574, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec},
+ {0x0000a578, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec},
+ {0x0000a57c, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec},
{0x0000a580, 0x00802220, 0x00802220, 0x00800000, 0x00800000},
- {0x0000a584, 0x06802223, 0x06802223, 0x04800002, 0x04800002},
- {0x0000a588, 0x0a822220, 0x0a822220, 0x08800004, 0x08800004},
- {0x0000a58c, 0x0f822223, 0x0f822223, 0x0b800200, 0x0b800200},
- {0x0000a590, 0x14822620, 0x14822620, 0x0f800202, 0x0f800202},
- {0x0000a594, 0x18822622, 0x18822622, 0x11800400, 0x11800400},
- {0x0000a598, 0x1b822822, 0x1b822822, 0x15800402, 0x15800402},
- {0x0000a59c, 0x20822842, 0x20822842, 0x19800404, 0x19800404},
- {0x0000a5a0, 0x22822c41, 0x22822c41, 0x1b800603, 0x1b800603},
- {0x0000a5a4, 0x28823042, 0x28823042, 0x1f800a02, 0x1f800a02},
- {0x0000a5a8, 0x2c823044, 0x2c823044, 0x23800a04, 0x23800a04},
- {0x0000a5ac, 0x2f823644, 0x2f823644, 0x26800a20, 0x26800a20},
- {0x0000a5b0, 0x34825643, 0x34825643, 0x2a800e20, 0x2a800e20},
- {0x0000a5b4, 0x38825a44, 0x38825a44, 0x2e800e22, 0x2e800e22},
- {0x0000a5b8, 0x3b825e45, 0x3b825e45, 0x31800e24, 0x31800e24},
- {0x0000a5bc, 0x41825e4a, 0x41825e4a, 0x34801640, 0x34801640},
- {0x0000a5c0, 0x48825e6c, 0x48825e6c, 0x38801660, 0x38801660},
- {0x0000a5c4, 0x4e825e8e, 0x4e825e8e, 0x3b801861, 0x3b801861},
- {0x0000a5c8, 0x53825eb2, 0x53825eb2, 0x3e801a81, 0x3e801a81},
- {0x0000a5cc, 0x59825eb5, 0x59825eb5, 0x42801a83, 0x42801a83},
- {0x0000a5d0, 0x5f825ef6, 0x5f825ef6, 0x44801c84, 0x44801c84},
- {0x0000a5d4, 0x62825f56, 0x62825f56, 0x48801ce3, 0x48801ce3},
- {0x0000a5d8, 0x66827f56, 0x66827f56, 0x4c801ce5, 0x4c801ce5},
- {0x0000a5dc, 0x6a829f56, 0x6a829f56, 0x50801ce9, 0x50801ce9},
- {0x0000a5e0, 0x70849f56, 0x70849f56, 0x54801ceb, 0x54801ceb},
- {0x0000a5e4, 0x7584ff56, 0x7584ff56, 0x56801eec, 0x56801eec},
- {0x0000a5e8, 0x7584ff56, 0x7584ff56, 0x56801eec, 0x56801eec},
- {0x0000a5ec, 0x7584ff56, 0x7584ff56, 0x56801eec, 0x56801eec},
- {0x0000a5f0, 0x7584ff56, 0x7584ff56, 0x56801eec, 0x56801eec},
- {0x0000a5f4, 0x7584ff56, 0x7584ff56, 0x56801eec, 0x56801eec},
- {0x0000a5f8, 0x7584ff56, 0x7584ff56, 0x56801eec, 0x56801eec},
- {0x0000a5fc, 0x7584ff56, 0x7584ff56, 0x56801eec, 0x56801eec},
+ {0x0000a584, 0x04802222, 0x04802222, 0x04800002, 0x04800002},
+ {0x0000a588, 0x09802421, 0x09802421, 0x08800004, 0x08800004},
+ {0x0000a58c, 0x0d802621, 0x0d802621, 0x0b800200, 0x0b800200},
+ {0x0000a590, 0x13804620, 0x13804620, 0x0f800202, 0x0f800202},
+ {0x0000a594, 0x19804a20, 0x19804a20, 0x11800400, 0x11800400},
+ {0x0000a598, 0x1d804e20, 0x1d804e20, 0x15800402, 0x15800402},
+ {0x0000a59c, 0x21805420, 0x21805420, 0x19800404, 0x19800404},
+ {0x0000a5a0, 0x26805e20, 0x26805e20, 0x1b800603, 0x1b800603},
+ {0x0000a5a4, 0x2b805e40, 0x2b805e40, 0x1f800a02, 0x1f800a02},
+ {0x0000a5a8, 0x2f805e42, 0x2f805e42, 0x23800a04, 0x23800a04},
+ {0x0000a5ac, 0x33805e44, 0x33805e44, 0x26800a20, 0x26800a20},
+ {0x0000a5b0, 0x38805e65, 0x38805e65, 0x2a800e20, 0x2a800e20},
+ {0x0000a5b4, 0x3c805e69, 0x3c805e69, 0x2e800e22, 0x2e800e22},
+ {0x0000a5b8, 0x40805e6b, 0x40805e6b, 0x31800e24, 0x31800e24},
+ {0x0000a5bc, 0x44805e6d, 0x44805e6d, 0x34801640, 0x34801640},
+ {0x0000a5c0, 0x49805e72, 0x49805e72, 0x38801660, 0x38801660},
+ {0x0000a5c4, 0x4e805eb2, 0x4e805eb2, 0x3b801861, 0x3b801861},
+ {0x0000a5c8, 0x53805f12, 0x53805f12, 0x3e801a81, 0x3e801a81},
+ {0x0000a5cc, 0x59825eb2, 0x59825eb2, 0x42801a83, 0x42801a83},
+ {0x0000a5d0, 0x5e825f12, 0x5e825f12, 0x44801c84, 0x44801c84},
+ {0x0000a5d4, 0x61827f12, 0x61827f12, 0x48801ce3, 0x48801ce3},
+ {0x0000a5d8, 0x6782bf12, 0x6782bf12, 0x4c801ce5, 0x4c801ce5},
+ {0x0000a5dc, 0x6b82bf14, 0x6b82bf14, 0x50801ce9, 0x50801ce9},
+ {0x0000a5e0, 0x6f82bf16, 0x6f82bf16, 0x54801ceb, 0x54801ceb},
+ {0x0000a5e4, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec},
+ {0x0000a5e8, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec},
+ {0x0000a5ec, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec},
+ {0x0000a5f0, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec},
+ {0x0000a5f4, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec},
+ {0x0000a5f8, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec},
+ {0x0000a5fc, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec},
{0x00016044, 0x056db2e6, 0x056db2e6, 0x056db2e6, 0x056db2e6},
{0x00016048, 0xae480001, 0xae480001, 0xae480001, 0xae480001},
{0x00016068, 0x6eb6db6c, 0x6eb6db6c, 0x6eb6db6c, 0x6eb6db6c},
@@ -913,71 +913,71 @@ static const u32 ar9300Modes_high_power_tx_gain_table_2p0[][5] = {
static const u32 ar9300Modes_high_ob_db_tx_gain_table_2p0[][5] = {
/* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */
- {0x0000a410, 0x000050d9, 0x000050d9, 0x000050d9, 0x000050d9},
+ {0x0000a410, 0x000050d8, 0x000050d8, 0x000050d9, 0x000050d9},
{0x0000a500, 0x00002220, 0x00002220, 0x00000000, 0x00000000},
- {0x0000a504, 0x06002223, 0x06002223, 0x04000002, 0x04000002},
- {0x0000a508, 0x0a022220, 0x0a022220, 0x08000004, 0x08000004},
- {0x0000a50c, 0x0f022223, 0x0f022223, 0x0b000200, 0x0b000200},
- {0x0000a510, 0x14022620, 0x14022620, 0x0f000202, 0x0f000202},
- {0x0000a514, 0x18022622, 0x18022622, 0x11000400, 0x11000400},
- {0x0000a518, 0x1b022822, 0x1b022822, 0x15000402, 0x15000402},
- {0x0000a51c, 0x20022842, 0x20022842, 0x19000404, 0x19000404},
- {0x0000a520, 0x22022c41, 0x22022c41, 0x1b000603, 0x1b000603},
- {0x0000a524, 0x28023042, 0x28023042, 0x1f000a02, 0x1f000a02},
- {0x0000a528, 0x2c023044, 0x2c023044, 0x23000a04, 0x23000a04},
- {0x0000a52c, 0x2f023644, 0x2f023644, 0x26000a20, 0x26000a20},
- {0x0000a530, 0x34025643, 0x34025643, 0x2a000e20, 0x2a000e20},
- {0x0000a534, 0x38025a44, 0x38025a44, 0x2e000e22, 0x2e000e22},
- {0x0000a538, 0x3b025e45, 0x3b025e45, 0x31000e24, 0x31000e24},
- {0x0000a53c, 0x41025e4a, 0x41025e4a, 0x34001640, 0x34001640},
- {0x0000a540, 0x48025e6c, 0x48025e6c, 0x38001660, 0x38001660},
- {0x0000a544, 0x4e025e8e, 0x4e025e8e, 0x3b001861, 0x3b001861},
- {0x0000a548, 0x53025eb2, 0x53025eb2, 0x3e001a81, 0x3e001a81},
+ {0x0000a504, 0x04002222, 0x04002222, 0x04000002, 0x04000002},
+ {0x0000a508, 0x09002421, 0x09002421, 0x08000004, 0x08000004},
+ {0x0000a50c, 0x0d002621, 0x0d002621, 0x0b000200, 0x0b000200},
+ {0x0000a510, 0x13004620, 0x13004620, 0x0f000202, 0x0f000202},
+ {0x0000a514, 0x19004a20, 0x19004a20, 0x11000400, 0x11000400},
+ {0x0000a518, 0x1d004e20, 0x1d004e20, 0x15000402, 0x15000402},
+ {0x0000a51c, 0x21005420, 0x21005420, 0x19000404, 0x19000404},
+ {0x0000a520, 0x26005e20, 0x26005e20, 0x1b000603, 0x1b000603},
+ {0x0000a524, 0x2b005e40, 0x2b005e40, 0x1f000a02, 0x1f000a02},
+ {0x0000a528, 0x2f005e42, 0x2f005e42, 0x23000a04, 0x23000a04},
+ {0x0000a52c, 0x33005e44, 0x33005e44, 0x26000a20, 0x26000a20},
+ {0x0000a530, 0x38005e65, 0x38005e65, 0x2a000e20, 0x2a000e20},
+ {0x0000a534, 0x3c005e69, 0x3c005e69, 0x2e000e22, 0x2e000e22},
+ {0x0000a538, 0x40005e6b, 0x40005e6b, 0x31000e24, 0x31000e24},
+ {0x0000a53c, 0x44005e6d, 0x44005e6d, 0x34001640, 0x34001640},
+ {0x0000a540, 0x49005e72, 0x49005e72, 0x38001660, 0x38001660},
+ {0x0000a544, 0x4e005eb2, 0x4e005eb2, 0x3b001861, 0x3b001861},
+ {0x0000a548, 0x53005f12, 0x53005f12, 0x3e001a81, 0x3e001a81},
{0x0000a54c, 0x59025eb5, 0x59025eb5, 0x42001a83, 0x42001a83},
- {0x0000a550, 0x5f025ef6, 0x5f025ef6, 0x44001c84, 0x44001c84},
- {0x0000a554, 0x62025f56, 0x62025f56, 0x48001ce3, 0x48001ce3},
- {0x0000a558, 0x66027f56, 0x66027f56, 0x4c001ce5, 0x4c001ce5},
- {0x0000a55c, 0x6a029f56, 0x6a029f56, 0x50001ce9, 0x50001ce9},
- {0x0000a560, 0x70049f56, 0x70049f56, 0x54001ceb, 0x54001ceb},
- {0x0000a564, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec},
- {0x0000a568, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec},
- {0x0000a56c, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec},
- {0x0000a570, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec},
- {0x0000a574, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec},
- {0x0000a578, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec},
- {0x0000a57c, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec},
+ {0x0000a550, 0x5e025f12, 0x5e025f12, 0x44001c84, 0x44001c84},
+ {0x0000a554, 0x61027f12, 0x61027f12, 0x48001ce3, 0x48001ce3},
+ {0x0000a558, 0x6702bf12, 0x6702bf12, 0x4c001ce5, 0x4c001ce5},
+ {0x0000a55c, 0x6b02bf14, 0x6b02bf14, 0x50001ce9, 0x50001ce9},
+ {0x0000a560, 0x6f02bf16, 0x6f02bf16, 0x54001ceb, 0x54001ceb},
+ {0x0000a564, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec},
+ {0x0000a568, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec},
+ {0x0000a56c, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec},
+ {0x0000a570, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec},
+ {0x0000a574, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec},
+ {0x0000a578, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec},
+ {0x0000a57c, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec},
{0x0000a580, 0x00802220, 0x00802220, 0x00800000, 0x00800000},
- {0x0000a584, 0x06802223, 0x06802223, 0x04800002, 0x04800002},
- {0x0000a588, 0x0a822220, 0x0a822220, 0x08800004, 0x08800004},
- {0x0000a58c, 0x0f822223, 0x0f822223, 0x0b800200, 0x0b800200},
- {0x0000a590, 0x14822620, 0x14822620, 0x0f800202, 0x0f800202},
- {0x0000a594, 0x18822622, 0x18822622, 0x11800400, 0x11800400},
- {0x0000a598, 0x1b822822, 0x1b822822, 0x15800402, 0x15800402},
- {0x0000a59c, 0x20822842, 0x20822842, 0x19800404, 0x19800404},
- {0x0000a5a0, 0x22822c41, 0x22822c41, 0x1b800603, 0x1b800603},
- {0x0000a5a4, 0x28823042, 0x28823042, 0x1f800a02, 0x1f800a02},
- {0x0000a5a8, 0x2c823044, 0x2c823044, 0x23800a04, 0x23800a04},
- {0x0000a5ac, 0x2f823644, 0x2f823644, 0x26800a20, 0x26800a20},
- {0x0000a5b0, 0x34825643, 0x34825643, 0x2a800e20, 0x2a800e20},
- {0x0000a5b4, 0x38825a44, 0x38825a44, 0x2e800e22, 0x2e800e22},
- {0x0000a5b8, 0x3b825e45, 0x3b825e45, 0x31800e24, 0x31800e24},
- {0x0000a5bc, 0x41825e4a, 0x41825e4a, 0x34801640, 0x34801640},
- {0x0000a5c0, 0x48825e6c, 0x48825e6c, 0x38801660, 0x38801660},
- {0x0000a5c4, 0x4e825e8e, 0x4e825e8e, 0x3b801861, 0x3b801861},
- {0x0000a5c8, 0x53825eb2, 0x53825eb2, 0x3e801a81, 0x3e801a81},
- {0x0000a5cc, 0x59825eb5, 0x59825eb5, 0x42801a83, 0x42801a83},
- {0x0000a5d0, 0x5f825ef6, 0x5f825ef6, 0x44801c84, 0x44801c84},
- {0x0000a5d4, 0x62825f56, 0x62825f56, 0x48801ce3, 0x48801ce3},
- {0x0000a5d8, 0x66827f56, 0x66827f56, 0x4c801ce5, 0x4c801ce5},
- {0x0000a5dc, 0x6a829f56, 0x6a829f56, 0x50801ce9, 0x50801ce9},
- {0x0000a5e0, 0x70849f56, 0x70849f56, 0x54801ceb, 0x54801ceb},
- {0x0000a5e4, 0x7584ff56, 0x7584ff56, 0x56801eec, 0x56801eec},
- {0x0000a5e8, 0x7584ff56, 0x7584ff56, 0x56801eec, 0x56801eec},
- {0x0000a5ec, 0x7584ff56, 0x7584ff56, 0x56801eec, 0x56801eec},
- {0x0000a5f0, 0x7584ff56, 0x7584ff56, 0x56801eec, 0x56801eec},
- {0x0000a5f4, 0x7584ff56, 0x7584ff56, 0x56801eec, 0x56801eec},
- {0x0000a5f8, 0x7584ff56, 0x7584ff56, 0x56801eec, 0x56801eec},
- {0x0000a5fc, 0x7584ff56, 0x7584ff56, 0x56801eec, 0x56801eec},
+ {0x0000a584, 0x04802222, 0x04802222, 0x04800002, 0x04800002},
+ {0x0000a588, 0x09802421, 0x09802421, 0x08800004, 0x08800004},
+ {0x0000a58c, 0x0d802621, 0x0d802621, 0x0b800200, 0x0b800200},
+ {0x0000a590, 0x13804620, 0x13804620, 0x0f800202, 0x0f800202},
+ {0x0000a594, 0x19804a20, 0x19804a20, 0x11800400, 0x11800400},
+ {0x0000a598, 0x1d804e20, 0x1d804e20, 0x15800402, 0x15800402},
+ {0x0000a59c, 0x21805420, 0x21805420, 0x19800404, 0x19800404},
+ {0x0000a5a0, 0x26805e20, 0x26805e20, 0x1b800603, 0x1b800603},
+ {0x0000a5a4, 0x2b805e40, 0x2b805e40, 0x1f800a02, 0x1f800a02},
+ {0x0000a5a8, 0x2f805e42, 0x2f805e42, 0x23800a04, 0x23800a04},
+ {0x0000a5ac, 0x33805e44, 0x33805e44, 0x26800a20, 0x26800a20},
+ {0x0000a5b0, 0x38805e65, 0x38805e65, 0x2a800e20, 0x2a800e20},
+ {0x0000a5b4, 0x3c805e69, 0x3c805e69, 0x2e800e22, 0x2e800e22},
+ {0x0000a5b8, 0x40805e6b, 0x40805e6b, 0x31800e24, 0x31800e24},
+ {0x0000a5bc, 0x44805e6d, 0x44805e6d, 0x34801640, 0x34801640},
+ {0x0000a5c0, 0x49805e72, 0x49805e72, 0x38801660, 0x38801660},
+ {0x0000a5c4, 0x4e805eb2, 0x4e805eb2, 0x3b801861, 0x3b801861},
+ {0x0000a5c8, 0x53805f12, 0x53805f12, 0x3e801a81, 0x3e801a81},
+ {0x0000a5cc, 0x59825eb2, 0x59825eb2, 0x42801a83, 0x42801a83},
+ {0x0000a5d0, 0x5e825f12, 0x5e825f12, 0x44801c84, 0x44801c84},
+ {0x0000a5d4, 0x61827f12, 0x61827f12, 0x48801ce3, 0x48801ce3},
+ {0x0000a5d8, 0x6782bf12, 0x6782bf12, 0x4c801ce5, 0x4c801ce5},
+ {0x0000a5dc, 0x6b82bf14, 0x6b82bf14, 0x50801ce9, 0x50801ce9},
+ {0x0000a5e0, 0x6f82bf16, 0x6f82bf16, 0x54801ceb, 0x54801ceb},
+ {0x0000a5e4, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec},
+ {0x0000a5e8, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec},
+ {0x0000a5ec, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec},
+ {0x0000a5f0, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec},
+ {0x0000a5f4, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec},
+ {0x0000a5f8, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec},
+ {0x0000a5fc, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec},
{0x00016044, 0x056db2e4, 0x056db2e4, 0x056db2e4, 0x056db2e4},
{0x00016048, 0x8e480001, 0x8e480001, 0x8e480001, 0x8e480001},
{0x00016068, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
@@ -1781,4 +1781,4 @@ static const u32 ar9300PciePhy_clkreq_disable_L1_2p0[][2] = {
{0x00004044, 0x00000000},
};
-#endif /* INITVALS_9003_H */
+#endif /* INITVALS_9003_2P0_H */
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h b/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h
new file mode 100644
index 00000000000..ec98ab50748
--- /dev/null
+++ b/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h
@@ -0,0 +1,1785 @@
+/*
+ * Copyright (c) 2010 Atheros Communications Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef INITVALS_9003_2P2_H
+#define INITVALS_9003_2P2_H
+
+/* AR9003 2.2 */
+
+static const u32 ar9300_2p2_radio_postamble[][5] = {
+ /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */
+ {0x0001609c, 0x0dd08f29, 0x0dd08f29, 0x0b283f31, 0x0b283f31},
+ {0x000160ac, 0xa4653c00, 0xa4653c00, 0x24652800, 0x24652800},
+ {0x000160b0, 0x03284f3e, 0x03284f3e, 0x05d08f20, 0x05d08f20},
+ {0x0001610c, 0x08000000, 0x00000000, 0x00000000, 0x00000000},
+ {0x00016140, 0x10804008, 0x10804008, 0x50804008, 0x50804008},
+ {0x0001650c, 0x08000000, 0x00000000, 0x00000000, 0x00000000},
+ {0x00016540, 0x10804008, 0x10804008, 0x50804008, 0x50804008},
+ {0x0001690c, 0x08000000, 0x00000000, 0x00000000, 0x00000000},
+ {0x00016940, 0x10804008, 0x10804008, 0x50804008, 0x50804008},
+};
+
+static const u32 ar9300Modes_lowest_ob_db_tx_gain_table_2p2[][5] = {
+ /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */
+ {0x0000a410, 0x000050d9, 0x000050d9, 0x000050d9, 0x000050d9},
+ {0x0000a500, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+ {0x0000a504, 0x06000003, 0x06000003, 0x04000002, 0x04000002},
+ {0x0000a508, 0x0a000020, 0x0a000020, 0x08000004, 0x08000004},
+ {0x0000a50c, 0x10000023, 0x10000023, 0x0b000200, 0x0b000200},
+ {0x0000a510, 0x16000220, 0x16000220, 0x0f000202, 0x0f000202},
+ {0x0000a514, 0x1c000223, 0x1c000223, 0x12000400, 0x12000400},
+ {0x0000a518, 0x21002220, 0x21002220, 0x16000402, 0x16000402},
+ {0x0000a51c, 0x27002223, 0x27002223, 0x19000404, 0x19000404},
+ {0x0000a520, 0x2b022220, 0x2b022220, 0x1c000603, 0x1c000603},
+ {0x0000a524, 0x2f022222, 0x2f022222, 0x21000a02, 0x21000a02},
+ {0x0000a528, 0x34022225, 0x34022225, 0x25000a04, 0x25000a04},
+ {0x0000a52c, 0x3a02222a, 0x3a02222a, 0x28000a20, 0x28000a20},
+ {0x0000a530, 0x3e02222c, 0x3e02222c, 0x2c000e20, 0x2c000e20},
+ {0x0000a534, 0x4202242a, 0x4202242a, 0x30000e22, 0x30000e22},
+ {0x0000a538, 0x4702244a, 0x4702244a, 0x34000e24, 0x34000e24},
+ {0x0000a53c, 0x4b02244c, 0x4b02244c, 0x38001640, 0x38001640},
+ {0x0000a540, 0x4e02246c, 0x4e02246c, 0x3c001660, 0x3c001660},
+ {0x0000a544, 0x5302266c, 0x5302266c, 0x3f001861, 0x3f001861},
+ {0x0000a548, 0x5702286c, 0x5702286c, 0x43001a81, 0x43001a81},
+ {0x0000a54c, 0x5c02486b, 0x5c02486b, 0x47001a83, 0x47001a83},
+ {0x0000a550, 0x61024a6c, 0x61024a6c, 0x4a001c84, 0x4a001c84},
+ {0x0000a554, 0x66026a6c, 0x66026a6c, 0x4e001ce3, 0x4e001ce3},
+ {0x0000a558, 0x6b026e6c, 0x6b026e6c, 0x52001ce5, 0x52001ce5},
+ {0x0000a55c, 0x7002708c, 0x7002708c, 0x56001ce9, 0x56001ce9},
+ {0x0000a560, 0x7302b08a, 0x7302b08a, 0x5a001ceb, 0x5a001ceb},
+ {0x0000a564, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec},
+ {0x0000a568, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec},
+ {0x0000a56c, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec},
+ {0x0000a570, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec},
+ {0x0000a574, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec},
+ {0x0000a578, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec},
+ {0x0000a57c, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec},
+ {0x0000a580, 0x00800000, 0x00800000, 0x00800000, 0x00800000},
+ {0x0000a584, 0x06800003, 0x06800003, 0x04800002, 0x04800002},
+ {0x0000a588, 0x0a800020, 0x0a800020, 0x08800004, 0x08800004},
+ {0x0000a58c, 0x10800023, 0x10800023, 0x0b800200, 0x0b800200},
+ {0x0000a590, 0x16800220, 0x16800220, 0x0f800202, 0x0f800202},
+ {0x0000a594, 0x1c800223, 0x1c800223, 0x12800400, 0x12800400},
+ {0x0000a598, 0x21802220, 0x21802220, 0x16800402, 0x16800402},
+ {0x0000a59c, 0x27802223, 0x27802223, 0x19800404, 0x19800404},
+ {0x0000a5a0, 0x2b822220, 0x2b822220, 0x1c800603, 0x1c800603},
+ {0x0000a5a4, 0x2f822222, 0x2f822222, 0x21800a02, 0x21800a02},
+ {0x0000a5a8, 0x34822225, 0x34822225, 0x25800a04, 0x25800a04},
+ {0x0000a5ac, 0x3a82222a, 0x3a82222a, 0x28800a20, 0x28800a20},
+ {0x0000a5b0, 0x3e82222c, 0x3e82222c, 0x2c800e20, 0x2c800e20},
+ {0x0000a5b4, 0x4282242a, 0x4282242a, 0x30800e22, 0x30800e22},
+ {0x0000a5b8, 0x4782244a, 0x4782244a, 0x34800e24, 0x34800e24},
+ {0x0000a5bc, 0x4b82244c, 0x4b82244c, 0x38801640, 0x38801640},
+ {0x0000a5c0, 0x4e82246c, 0x4e82246c, 0x3c801660, 0x3c801660},
+ {0x0000a5c4, 0x5382266c, 0x5382266c, 0x3f801861, 0x3f801861},
+ {0x0000a5c8, 0x5782286c, 0x5782286c, 0x43801a81, 0x43801a81},
+ {0x0000a5cc, 0x5c82486b, 0x5c82486b, 0x47801a83, 0x47801a83},
+ {0x0000a5d0, 0x61824a6c, 0x61824a6c, 0x4a801c84, 0x4a801c84},
+ {0x0000a5d4, 0x66826a6c, 0x66826a6c, 0x4e801ce3, 0x4e801ce3},
+ {0x0000a5d8, 0x6b826e6c, 0x6b826e6c, 0x52801ce5, 0x52801ce5},
+ {0x0000a5dc, 0x7082708c, 0x7082708c, 0x56801ce9, 0x56801ce9},
+ {0x0000a5e0, 0x7382b08a, 0x7382b08a, 0x5a801ceb, 0x5a801ceb},
+ {0x0000a5e4, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec},
+ {0x0000a5e8, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec},
+ {0x0000a5ec, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec},
+ {0x0000a5f0, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec},
+ {0x0000a5f4, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec},
+ {0x0000a5f8, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec},
+ {0x0000a5fc, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec},
+ {0x00016044, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4},
+ {0x00016048, 0x62480001, 0x62480001, 0x62480001, 0x62480001},
+ {0x00016068, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
+ {0x00016444, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4},
+ {0x00016448, 0x62480001, 0x62480001, 0x62480001, 0x62480001},
+ {0x00016468, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
+ {0x00016844, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4},
+ {0x00016848, 0x62480001, 0x62480001, 0x62480001, 0x62480001},
+ {0x00016868, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
+};
+
+static const u32 ar9300Modes_fast_clock_2p2[][3] = {
+ /* Addr 5G_HT20 5G_HT40 */
+ {0x00001030, 0x00000268, 0x000004d0},
+ {0x00001070, 0x0000018c, 0x00000318},
+ {0x000010b0, 0x00000fd0, 0x00001fa0},
+ {0x00008014, 0x044c044c, 0x08980898},
+ {0x0000801c, 0x148ec02b, 0x148ec057},
+ {0x00008318, 0x000044c0, 0x00008980},
+ {0x00009e00, 0x03721821, 0x03721821},
+ {0x0000a230, 0x0000000b, 0x00000016},
+ {0x0000a254, 0x00000898, 0x00001130},
+};
+
+static const u32 ar9300_2p2_radio_core[][2] = {
+ /* Addr allmodes */
+ {0x00016000, 0x36db6db6},
+ {0x00016004, 0x6db6db40},
+ {0x00016008, 0x73f00000},
+ {0x0001600c, 0x00000000},
+ {0x00016040, 0x7f80fff8},
+ {0x0001604c, 0x76d005b5},
+ {0x00016050, 0x556cf031},
+ {0x00016054, 0x13449440},
+ {0x00016058, 0x0c51c92c},
+ {0x0001605c, 0x3db7fffc},
+ {0x00016060, 0xfffffffc},
+ {0x00016064, 0x000f0278},
+ {0x0001606c, 0x6db60000},
+ {0x00016080, 0x00000000},
+ {0x00016084, 0x0e48048c},
+ {0x00016088, 0x54214514},
+ {0x0001608c, 0x119f481e},
+ {0x00016090, 0x24926490},
+ {0x00016098, 0xd2888888},
+ {0x000160a0, 0x0a108ffe},
+ {0x000160a4, 0x812fc370},
+ {0x000160a8, 0x423c8000},
+ {0x000160b4, 0x92480080},
+ {0x000160c0, 0x00adb6d0},
+ {0x000160c4, 0x6db6db60},
+ {0x000160c8, 0x6db6db6c},
+ {0x000160cc, 0x01e6c000},
+ {0x00016100, 0x3fffbe01},
+ {0x00016104, 0xfff80000},
+ {0x00016108, 0x00080010},
+ {0x00016144, 0x02084080},
+ {0x00016148, 0x00000000},
+ {0x00016280, 0x058a0001},
+ {0x00016284, 0x3d840208},
+ {0x00016288, 0x05a20408},
+ {0x0001628c, 0x00038c07},
+ {0x00016290, 0x00000004},
+ {0x00016294, 0x458aa14f},
+ {0x00016380, 0x00000000},
+ {0x00016384, 0x00000000},
+ {0x00016388, 0x00800700},
+ {0x0001638c, 0x00800700},
+ {0x00016390, 0x00800700},
+ {0x00016394, 0x00000000},
+ {0x00016398, 0x00000000},
+ {0x0001639c, 0x00000000},
+ {0x000163a0, 0x00000001},
+ {0x000163a4, 0x00000001},
+ {0x000163a8, 0x00000000},
+ {0x000163ac, 0x00000000},
+ {0x000163b0, 0x00000000},
+ {0x000163b4, 0x00000000},
+ {0x000163b8, 0x00000000},
+ {0x000163bc, 0x00000000},
+ {0x000163c0, 0x000000a0},
+ {0x000163c4, 0x000c0000},
+ {0x000163c8, 0x14021402},
+ {0x000163cc, 0x00001402},
+ {0x000163d0, 0x00000000},
+ {0x000163d4, 0x00000000},
+ {0x00016400, 0x36db6db6},
+ {0x00016404, 0x6db6db40},
+ {0x00016408, 0x73f00000},
+ {0x0001640c, 0x00000000},
+ {0x00016440, 0x7f80fff8},
+ {0x0001644c, 0x76d005b5},
+ {0x00016450, 0x556cf031},
+ {0x00016454, 0x13449440},
+ {0x00016458, 0x0c51c92c},
+ {0x0001645c, 0x3db7fffc},
+ {0x00016460, 0xfffffffc},
+ {0x00016464, 0x000f0278},
+ {0x0001646c, 0x6db60000},
+ {0x00016500, 0x3fffbe01},
+ {0x00016504, 0xfff80000},
+ {0x00016508, 0x00080010},
+ {0x00016544, 0x02084080},
+ {0x00016548, 0x00000000},
+ {0x00016780, 0x00000000},
+ {0x00016784, 0x00000000},
+ {0x00016788, 0x00800700},
+ {0x0001678c, 0x00800700},
+ {0x00016790, 0x00800700},
+ {0x00016794, 0x00000000},
+ {0x00016798, 0x00000000},
+ {0x0001679c, 0x00000000},
+ {0x000167a0, 0x00000001},
+ {0x000167a4, 0x00000001},
+ {0x000167a8, 0x00000000},
+ {0x000167ac, 0x00000000},
+ {0x000167b0, 0x00000000},
+ {0x000167b4, 0x00000000},
+ {0x000167b8, 0x00000000},
+ {0x000167bc, 0x00000000},
+ {0x000167c0, 0x000000a0},
+ {0x000167c4, 0x000c0000},
+ {0x000167c8, 0x14021402},
+ {0x000167cc, 0x00001402},
+ {0x000167d0, 0x00000000},
+ {0x000167d4, 0x00000000},
+ {0x00016800, 0x36db6db6},
+ {0x00016804, 0x6db6db40},
+ {0x00016808, 0x73f00000},
+ {0x0001680c, 0x00000000},
+ {0x00016840, 0x7f80fff8},
+ {0x0001684c, 0x76d005b5},
+ {0x00016850, 0x556cf031},
+ {0x00016854, 0x13449440},
+ {0x00016858, 0x0c51c92c},
+ {0x0001685c, 0x3db7fffc},
+ {0x00016860, 0xfffffffc},
+ {0x00016864, 0x000f0278},
+ {0x0001686c, 0x6db60000},
+ {0x00016900, 0x3fffbe01},
+ {0x00016904, 0xfff80000},
+ {0x00016908, 0x00080010},
+ {0x00016944, 0x02084080},
+ {0x00016948, 0x00000000},
+ {0x00016b80, 0x00000000},
+ {0x00016b84, 0x00000000},
+ {0x00016b88, 0x00800700},
+ {0x00016b8c, 0x00800700},
+ {0x00016b90, 0x00800700},
+ {0x00016b94, 0x00000000},
+ {0x00016b98, 0x00000000},
+ {0x00016b9c, 0x00000000},
+ {0x00016ba0, 0x00000001},
+ {0x00016ba4, 0x00000001},
+ {0x00016ba8, 0x00000000},
+ {0x00016bac, 0x00000000},
+ {0x00016bb0, 0x00000000},
+ {0x00016bb4, 0x00000000},
+ {0x00016bb8, 0x00000000},
+ {0x00016bbc, 0x00000000},
+ {0x00016bc0, 0x000000a0},
+ {0x00016bc4, 0x000c0000},
+ {0x00016bc8, 0x14021402},
+ {0x00016bcc, 0x00001402},
+ {0x00016bd0, 0x00000000},
+ {0x00016bd4, 0x00000000},
+};
+
+static const u32 ar9300Common_rx_gain_table_merlin_2p2[][2] = {
+ /* Addr allmodes */
+ {0x0000a000, 0x02000101},
+ {0x0000a004, 0x02000102},
+ {0x0000a008, 0x02000103},
+ {0x0000a00c, 0x02000104},
+ {0x0000a010, 0x02000200},
+ {0x0000a014, 0x02000201},
+ {0x0000a018, 0x02000202},
+ {0x0000a01c, 0x02000203},
+ {0x0000a020, 0x02000204},
+ {0x0000a024, 0x02000205},
+ {0x0000a028, 0x02000208},
+ {0x0000a02c, 0x02000302},
+ {0x0000a030, 0x02000303},
+ {0x0000a034, 0x02000304},
+ {0x0000a038, 0x02000400},
+ {0x0000a03c, 0x02010300},
+ {0x0000a040, 0x02010301},
+ {0x0000a044, 0x02010302},
+ {0x0000a048, 0x02000500},
+ {0x0000a04c, 0x02010400},
+ {0x0000a050, 0x02020300},
+ {0x0000a054, 0x02020301},
+ {0x0000a058, 0x02020302},
+ {0x0000a05c, 0x02020303},
+ {0x0000a060, 0x02020400},
+ {0x0000a064, 0x02030300},
+ {0x0000a068, 0x02030301},
+ {0x0000a06c, 0x02030302},
+ {0x0000a070, 0x02030303},
+ {0x0000a074, 0x02030400},
+ {0x0000a078, 0x02040300},
+ {0x0000a07c, 0x02040301},
+ {0x0000a080, 0x02040302},
+ {0x0000a084, 0x02040303},
+ {0x0000a088, 0x02030500},
+ {0x0000a08c, 0x02040400},
+ {0x0000a090, 0x02050203},
+ {0x0000a094, 0x02050204},
+ {0x0000a098, 0x02050205},
+ {0x0000a09c, 0x02040500},
+ {0x0000a0a0, 0x02050301},
+ {0x0000a0a4, 0x02050302},
+ {0x0000a0a8, 0x02050303},
+ {0x0000a0ac, 0x02050400},
+ {0x0000a0b0, 0x02050401},
+ {0x0000a0b4, 0x02050402},
+ {0x0000a0b8, 0x02050403},
+ {0x0000a0bc, 0x02050500},
+ {0x0000a0c0, 0x02050501},
+ {0x0000a0c4, 0x02050502},
+ {0x0000a0c8, 0x02050503},
+ {0x0000a0cc, 0x02050504},
+ {0x0000a0d0, 0x02050600},
+ {0x0000a0d4, 0x02050601},
+ {0x0000a0d8, 0x02050602},
+ {0x0000a0dc, 0x02050603},
+ {0x0000a0e0, 0x02050604},
+ {0x0000a0e4, 0x02050700},
+ {0x0000a0e8, 0x02050701},
+ {0x0000a0ec, 0x02050702},
+ {0x0000a0f0, 0x02050703},
+ {0x0000a0f4, 0x02050704},
+ {0x0000a0f8, 0x02050705},
+ {0x0000a0fc, 0x02050708},
+ {0x0000a100, 0x02050709},
+ {0x0000a104, 0x0205070a},
+ {0x0000a108, 0x0205070b},
+ {0x0000a10c, 0x0205070c},
+ {0x0000a110, 0x0205070d},
+ {0x0000a114, 0x02050710},
+ {0x0000a118, 0x02050711},
+ {0x0000a11c, 0x02050712},
+ {0x0000a120, 0x02050713},
+ {0x0000a124, 0x02050714},
+ {0x0000a128, 0x02050715},
+ {0x0000a12c, 0x02050730},
+ {0x0000a130, 0x02050731},
+ {0x0000a134, 0x02050732},
+ {0x0000a138, 0x02050733},
+ {0x0000a13c, 0x02050734},
+ {0x0000a140, 0x02050735},
+ {0x0000a144, 0x02050750},
+ {0x0000a148, 0x02050751},
+ {0x0000a14c, 0x02050752},
+ {0x0000a150, 0x02050753},
+ {0x0000a154, 0x02050754},
+ {0x0000a158, 0x02050755},
+ {0x0000a15c, 0x02050770},
+ {0x0000a160, 0x02050771},
+ {0x0000a164, 0x02050772},
+ {0x0000a168, 0x02050773},
+ {0x0000a16c, 0x02050774},
+ {0x0000a170, 0x02050775},
+ {0x0000a174, 0x00000776},
+ {0x0000a178, 0x00000776},
+ {0x0000a17c, 0x00000776},
+ {0x0000a180, 0x00000776},
+ {0x0000a184, 0x00000776},
+ {0x0000a188, 0x00000776},
+ {0x0000a18c, 0x00000776},
+ {0x0000a190, 0x00000776},
+ {0x0000a194, 0x00000776},
+ {0x0000a198, 0x00000776},
+ {0x0000a19c, 0x00000776},
+ {0x0000a1a0, 0x00000776},
+ {0x0000a1a4, 0x00000776},
+ {0x0000a1a8, 0x00000776},
+ {0x0000a1ac, 0x00000776},
+ {0x0000a1b0, 0x00000776},
+ {0x0000a1b4, 0x00000776},
+ {0x0000a1b8, 0x00000776},
+ {0x0000a1bc, 0x00000776},
+ {0x0000a1c0, 0x00000776},
+ {0x0000a1c4, 0x00000776},
+ {0x0000a1c8, 0x00000776},
+ {0x0000a1cc, 0x00000776},
+ {0x0000a1d0, 0x00000776},
+ {0x0000a1d4, 0x00000776},
+ {0x0000a1d8, 0x00000776},
+ {0x0000a1dc, 0x00000776},
+ {0x0000a1e0, 0x00000776},
+ {0x0000a1e4, 0x00000776},
+ {0x0000a1e8, 0x00000776},
+ {0x0000a1ec, 0x00000776},
+ {0x0000a1f0, 0x00000776},
+ {0x0000a1f4, 0x00000776},
+ {0x0000a1f8, 0x00000776},
+ {0x0000a1fc, 0x00000776},
+ {0x0000b000, 0x02000101},
+ {0x0000b004, 0x02000102},
+ {0x0000b008, 0x02000103},
+ {0x0000b00c, 0x02000104},
+ {0x0000b010, 0x02000200},
+ {0x0000b014, 0x02000201},
+ {0x0000b018, 0x02000202},
+ {0x0000b01c, 0x02000203},
+ {0x0000b020, 0x02000204},
+ {0x0000b024, 0x02000205},
+ {0x0000b028, 0x02000208},
+ {0x0000b02c, 0x02000302},
+ {0x0000b030, 0x02000303},
+ {0x0000b034, 0x02000304},
+ {0x0000b038, 0x02000400},
+ {0x0000b03c, 0x02010300},
+ {0x0000b040, 0x02010301},
+ {0x0000b044, 0x02010302},
+ {0x0000b048, 0x02000500},
+ {0x0000b04c, 0x02010400},
+ {0x0000b050, 0x02020300},
+ {0x0000b054, 0x02020301},
+ {0x0000b058, 0x02020302},
+ {0x0000b05c, 0x02020303},
+ {0x0000b060, 0x02020400},
+ {0x0000b064, 0x02030300},
+ {0x0000b068, 0x02030301},
+ {0x0000b06c, 0x02030302},
+ {0x0000b070, 0x02030303},
+ {0x0000b074, 0x02030400},
+ {0x0000b078, 0x02040300},
+ {0x0000b07c, 0x02040301},
+ {0x0000b080, 0x02040302},
+ {0x0000b084, 0x02040303},
+ {0x0000b088, 0x02030500},
+ {0x0000b08c, 0x02040400},
+ {0x0000b090, 0x02050203},
+ {0x0000b094, 0x02050204},
+ {0x0000b098, 0x02050205},
+ {0x0000b09c, 0x02040500},
+ {0x0000b0a0, 0x02050301},
+ {0x0000b0a4, 0x02050302},
+ {0x0000b0a8, 0x02050303},
+ {0x0000b0ac, 0x02050400},
+ {0x0000b0b0, 0x02050401},
+ {0x0000b0b4, 0x02050402},
+ {0x0000b0b8, 0x02050403},
+ {0x0000b0bc, 0x02050500},
+ {0x0000b0c0, 0x02050501},
+ {0x0000b0c4, 0x02050502},
+ {0x0000b0c8, 0x02050503},
+ {0x0000b0cc, 0x02050504},
+ {0x0000b0d0, 0x02050600},
+ {0x0000b0d4, 0x02050601},
+ {0x0000b0d8, 0x02050602},
+ {0x0000b0dc, 0x02050603},
+ {0x0000b0e0, 0x02050604},
+ {0x0000b0e4, 0x02050700},
+ {0x0000b0e8, 0x02050701},
+ {0x0000b0ec, 0x02050702},
+ {0x0000b0f0, 0x02050703},
+ {0x0000b0f4, 0x02050704},
+ {0x0000b0f8, 0x02050705},
+ {0x0000b0fc, 0x02050708},
+ {0x0000b100, 0x02050709},
+ {0x0000b104, 0x0205070a},
+ {0x0000b108, 0x0205070b},
+ {0x0000b10c, 0x0205070c},
+ {0x0000b110, 0x0205070d},
+ {0x0000b114, 0x02050710},
+ {0x0000b118, 0x02050711},
+ {0x0000b11c, 0x02050712},
+ {0x0000b120, 0x02050713},
+ {0x0000b124, 0x02050714},
+ {0x0000b128, 0x02050715},
+ {0x0000b12c, 0x02050730},
+ {0x0000b130, 0x02050731},
+ {0x0000b134, 0x02050732},
+ {0x0000b138, 0x02050733},
+ {0x0000b13c, 0x02050734},
+ {0x0000b140, 0x02050735},
+ {0x0000b144, 0x02050750},
+ {0x0000b148, 0x02050751},
+ {0x0000b14c, 0x02050752},
+ {0x0000b150, 0x02050753},
+ {0x0000b154, 0x02050754},
+ {0x0000b158, 0x02050755},
+ {0x0000b15c, 0x02050770},
+ {0x0000b160, 0x02050771},
+ {0x0000b164, 0x02050772},
+ {0x0000b168, 0x02050773},
+ {0x0000b16c, 0x02050774},
+ {0x0000b170, 0x02050775},
+ {0x0000b174, 0x00000776},
+ {0x0000b178, 0x00000776},
+ {0x0000b17c, 0x00000776},
+ {0x0000b180, 0x00000776},
+ {0x0000b184, 0x00000776},
+ {0x0000b188, 0x00000776},
+ {0x0000b18c, 0x00000776},
+ {0x0000b190, 0x00000776},
+ {0x0000b194, 0x00000776},
+ {0x0000b198, 0x00000776},
+ {0x0000b19c, 0x00000776},
+ {0x0000b1a0, 0x00000776},
+ {0x0000b1a4, 0x00000776},
+ {0x0000b1a8, 0x00000776},
+ {0x0000b1ac, 0x00000776},
+ {0x0000b1b0, 0x00000776},
+ {0x0000b1b4, 0x00000776},
+ {0x0000b1b8, 0x00000776},
+ {0x0000b1bc, 0x00000776},
+ {0x0000b1c0, 0x00000776},
+ {0x0000b1c4, 0x00000776},
+ {0x0000b1c8, 0x00000776},
+ {0x0000b1cc, 0x00000776},
+ {0x0000b1d0, 0x00000776},
+ {0x0000b1d4, 0x00000776},
+ {0x0000b1d8, 0x00000776},
+ {0x0000b1dc, 0x00000776},
+ {0x0000b1e0, 0x00000776},
+ {0x0000b1e4, 0x00000776},
+ {0x0000b1e8, 0x00000776},
+ {0x0000b1ec, 0x00000776},
+ {0x0000b1f0, 0x00000776},
+ {0x0000b1f4, 0x00000776},
+ {0x0000b1f8, 0x00000776},
+ {0x0000b1fc, 0x00000776},
+};
+
+static const u32 ar9300_2p2_mac_postamble[][5] = {
+ /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */
+ {0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160},
+ {0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c},
+ {0x000010b0, 0x00000e60, 0x00001cc0, 0x00007c70, 0x00003e38},
+ {0x00008014, 0x03e803e8, 0x07d007d0, 0x10801600, 0x08400b00},
+ {0x0000801c, 0x128d8027, 0x128d804f, 0x12e00057, 0x12e0002b},
+ {0x00008120, 0x08f04800, 0x08f04800, 0x08f04810, 0x08f04810},
+ {0x000081d0, 0x00003210, 0x00003210, 0x0000320a, 0x0000320a},
+ {0x00008318, 0x00003e80, 0x00007d00, 0x00006880, 0x00003440},
+};
+
+static const u32 ar9300_2p2_soc_postamble[][5] = {
+ /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */
+ {0x00007010, 0x00000023, 0x00000023, 0x00000023, 0x00000023},
+};
+
+static const u32 ar9200_merlin_2p2_radio_core[][2] = {
+ /* Addr allmodes */
+ {0x00007800, 0x00040000},
+ {0x00007804, 0xdb005012},
+ {0x00007808, 0x04924914},
+ {0x0000780c, 0x21084210},
+ {0x00007810, 0x6d801300},
+ {0x00007814, 0x0019beff},
+ {0x00007818, 0x07e41000},
+ {0x0000781c, 0x00392000},
+ {0x00007820, 0x92592480},
+ {0x00007824, 0x00040000},
+ {0x00007828, 0xdb005012},
+ {0x0000782c, 0x04924914},
+ {0x00007830, 0x21084210},
+ {0x00007834, 0x6d801300},
+ {0x00007838, 0x0019beff},
+ {0x0000783c, 0x07e40000},
+ {0x00007840, 0x00392000},
+ {0x00007844, 0x92592480},
+ {0x00007848, 0x00100000},
+ {0x0000784c, 0x773f0567},
+ {0x00007850, 0x54214514},
+ {0x00007854, 0x12035828},
+ {0x00007858, 0x92592692},
+ {0x0000785c, 0x00000000},
+ {0x00007860, 0x56400000},
+ {0x00007864, 0x0a8e370e},
+ {0x00007868, 0xc0102850},
+ {0x0000786c, 0x812d4000},
+ {0x00007870, 0x807ec400},
+ {0x00007874, 0x001b6db0},
+ {0x00007878, 0x00376b63},
+ {0x0000787c, 0x06db6db6},
+ {0x00007880, 0x006d8000},
+ {0x00007884, 0xffeffffe},
+ {0x00007888, 0xffeffffe},
+ {0x0000788c, 0x00010000},
+ {0x00007890, 0x02060aeb},
+ {0x00007894, 0x5a108000},
+};
+
+static const u32 ar9300_2p2_baseband_postamble[][5] = {
+ /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */
+ {0x00009810, 0xd00a8005, 0xd00a8005, 0xd00a8011, 0xd00a8011},
+ {0x00009820, 0x206a022e, 0x206a022e, 0x206a012e, 0x206a012e},
+ {0x00009824, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0},
+ {0x00009828, 0x06903081, 0x06903081, 0x06903881, 0x06903881},
+ {0x0000982c, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4},
+ {0x00009830, 0x0000059c, 0x0000059c, 0x0000119c, 0x0000119c},
+ {0x00009c00, 0x000000c4, 0x000000c4, 0x000000c4, 0x000000c4},
+ {0x00009e00, 0x0372161e, 0x0372161e, 0x037216a0, 0x037216a0},
+ {0x00009e04, 0x00802020, 0x00802020, 0x00802020, 0x00802020},
+ {0x00009e0c, 0x6c4000e2, 0x6d4000e2, 0x6d4000e2, 0x6c4000e2},
+ {0x00009e10, 0x7ec88d2e, 0x7ec88d2e, 0x7ec84d2e, 0x7ec84d2e},
+ {0x00009e14, 0x31395d5e, 0x3139605e, 0x3139605e, 0x31395d5e},
+ {0x00009e18, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+ {0x00009e1c, 0x0001cf9c, 0x0001cf9c, 0x00021f9c, 0x00021f9c},
+ {0x00009e20, 0x000003b5, 0x000003b5, 0x000003ce, 0x000003ce},
+ {0x00009e2c, 0x0000001c, 0x0000001c, 0x00000021, 0x00000021},
+ {0x00009e44, 0x02321e27, 0x02321e27, 0x02291e27, 0x02291e27},
+ {0x00009e48, 0x5030201a, 0x5030201a, 0x50302012, 0x50302012},
+ {0x00009fc8, 0x0003f000, 0x0003f000, 0x0001a000, 0x0001a000},
+ {0x0000a204, 0x000037c0, 0x000037c4, 0x000037c4, 0x000037c0},
+ {0x0000a208, 0x00000104, 0x00000104, 0x00000004, 0x00000004},
+ {0x0000a230, 0x0000000a, 0x00000014, 0x00000016, 0x0000000b},
+ {0x0000a234, 0x00000fff, 0x10000fff, 0x10000fff, 0x00000fff},
+ {0x0000a238, 0xffb81018, 0xffb81018, 0xffb81018, 0xffb81018},
+ {0x0000a250, 0x00000000, 0x00000000, 0x00000210, 0x00000108},
+ {0x0000a254, 0x000007d0, 0x00000fa0, 0x00001130, 0x00000898},
+ {0x0000a258, 0x02020002, 0x02020002, 0x02020002, 0x02020002},
+ {0x0000a25c, 0x01000e0e, 0x01000e0e, 0x01000e0e, 0x01000e0e},
+ {0x0000a260, 0x0a021501, 0x0a021501, 0x3a021501, 0x3a021501},
+ {0x0000a264, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e},
+ {0x0000a280, 0x00000007, 0x00000007, 0x0000000b, 0x0000000b},
+ {0x0000a284, 0x00000000, 0x00000000, 0x00000150, 0x00000150},
+ {0x0000a288, 0x00000110, 0x00000110, 0x00000110, 0x00000110},
+ {0x0000a28c, 0x00022222, 0x00022222, 0x00022222, 0x00022222},
+ {0x0000a2c4, 0x00158d18, 0x00158d18, 0x00158d18, 0x00158d18},
+ {0x0000a2d0, 0x00071981, 0x00071981, 0x00071981, 0x00071982},
+ {0x0000a2d8, 0xf999a83a, 0xf999a83a, 0xf999a83a, 0xf999a83a},
+ {0x0000a358, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+ {0x0000a830, 0x0000019c, 0x0000019c, 0x0000019c, 0x0000019c},
+ {0x0000ae04, 0x00800000, 0x00800000, 0x00800000, 0x00800000},
+ {0x0000ae18, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+ {0x0000ae1c, 0x0000019c, 0x0000019c, 0x0000019c, 0x0000019c},
+ {0x0000ae20, 0x000001b5, 0x000001b5, 0x000001ce, 0x000001ce},
+ {0x0000b284, 0x00000000, 0x00000000, 0x00000150, 0x00000150},
+ {0x0000b830, 0x0000019c, 0x0000019c, 0x0000019c, 0x0000019c},
+ {0x0000be04, 0x00800000, 0x00800000, 0x00800000, 0x00800000},
+ {0x0000be18, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+ {0x0000be1c, 0x0000019c, 0x0000019c, 0x0000019c, 0x0000019c},
+ {0x0000be20, 0x000001b5, 0x000001b5, 0x000001ce, 0x000001ce},
+ {0x0000c284, 0x00000000, 0x00000000, 0x00000150, 0x00000150},
+};
+
+static const u32 ar9300_2p2_baseband_core[][2] = {
+ /* Addr allmodes */
+ {0x00009800, 0xafe68e30},
+ {0x00009804, 0xfd14e000},
+ {0x00009808, 0x9c0a9f6b},
+ {0x0000980c, 0x04900000},
+ {0x00009814, 0x9280c00a},
+ {0x00009818, 0x00000000},
+ {0x0000981c, 0x00020028},
+ {0x00009834, 0x5f3ca3de},
+ {0x00009838, 0x0108ecff},
+ {0x0000983c, 0x14750600},
+ {0x00009880, 0x201fff00},
+ {0x00009884, 0x00001042},
+ {0x000098a4, 0x00200400},
+ {0x000098b0, 0x52440bbe},
+ {0x000098d0, 0x004b6a8e},
+ {0x000098d4, 0x00000820},
+ {0x000098dc, 0x00000000},
+ {0x000098f0, 0x00000000},
+ {0x000098f4, 0x00000000},
+ {0x00009c04, 0xff55ff55},
+ {0x00009c08, 0x0320ff55},
+ {0x00009c0c, 0x00000000},
+ {0x00009c10, 0x00000000},
+ {0x00009c14, 0x00046384},
+ {0x00009c18, 0x05b6b440},
+ {0x00009c1c, 0x00b6b440},
+ {0x00009d00, 0xc080a333},
+ {0x00009d04, 0x40206c10},
+ {0x00009d08, 0x009c4060},
+ {0x00009d0c, 0x9883800a},
+ {0x00009d10, 0x01834061},
+ {0x00009d14, 0x00c0040b},
+ {0x00009d18, 0x00000000},
+ {0x00009e08, 0x0038230c},
+ {0x00009e24, 0x990bb515},
+ {0x00009e28, 0x0c6f0000},
+ {0x00009e30, 0x06336f77},
+ {0x00009e34, 0x6af6532f},
+ {0x00009e38, 0x0cc80c00},
+ {0x00009e3c, 0xcf946222},
+ {0x00009e40, 0x0d261820},
+ {0x00009e4c, 0x00001004},
+ {0x00009e50, 0x00ff03f1},
+ {0x00009e54, 0x00000000},
+ {0x00009fc0, 0x803e4788},
+ {0x00009fc4, 0x0001efb5},
+ {0x00009fcc, 0x40000014},
+ {0x00009fd0, 0x01193b93},
+ {0x0000a20c, 0x00000000},
+ {0x0000a220, 0x00000000},
+ {0x0000a224, 0x00000000},
+ {0x0000a228, 0x10002310},
+ {0x0000a22c, 0x01036a1e},
+ {0x0000a23c, 0x00000000},
+ {0x0000a244, 0x0c000000},
+ {0x0000a2a0, 0x00000001},
+ {0x0000a2c0, 0x00000001},
+ {0x0000a2c8, 0x00000000},
+ {0x0000a2cc, 0x18c43433},
+ {0x0000a2d4, 0x00000000},
+ {0x0000a2dc, 0x00000000},
+ {0x0000a2e0, 0x00000000},
+ {0x0000a2e4, 0x00000000},
+ {0x0000a2e8, 0x00000000},
+ {0x0000a2ec, 0x00000000},
+ {0x0000a2f0, 0x00000000},
+ {0x0000a2f4, 0x00000000},
+ {0x0000a2f8, 0x00000000},
+ {0x0000a344, 0x00000000},
+ {0x0000a34c, 0x00000000},
+ {0x0000a350, 0x0000a000},
+ {0x0000a364, 0x00000000},
+ {0x0000a370, 0x00000000},
+ {0x0000a390, 0x00000001},
+ {0x0000a394, 0x00000444},
+ {0x0000a398, 0x001f0e0f},
+ {0x0000a39c, 0x0075393f},
+ {0x0000a3a0, 0xb79f6427},
+ {0x0000a3a4, 0x00000000},
+ {0x0000a3a8, 0xaaaaaaaa},
+ {0x0000a3ac, 0x3c466478},
+ {0x0000a3c0, 0x20202020},
+ {0x0000a3c4, 0x22222220},
+ {0x0000a3c8, 0x20200020},
+ {0x0000a3cc, 0x20202020},
+ {0x0000a3d0, 0x20202020},
+ {0x0000a3d4, 0x20202020},
+ {0x0000a3d8, 0x20202020},
+ {0x0000a3dc, 0x20202020},
+ {0x0000a3e0, 0x20202020},
+ {0x0000a3e4, 0x20202020},
+ {0x0000a3e8, 0x20202020},
+ {0x0000a3ec, 0x20202020},
+ {0x0000a3f0, 0x00000000},
+ {0x0000a3f4, 0x00000246},
+ {0x0000a3f8, 0x0cdbd380},
+ {0x0000a3fc, 0x000f0f01},
+ {0x0000a400, 0x8fa91f01},
+ {0x0000a404, 0x00000000},
+ {0x0000a408, 0x0e79e5c6},
+ {0x0000a40c, 0x00820820},
+ {0x0000a414, 0x1ce739ce},
+ {0x0000a418, 0x2d001dce},
+ {0x0000a41c, 0x1ce739ce},
+ {0x0000a420, 0x000001ce},
+ {0x0000a424, 0x1ce739ce},
+ {0x0000a428, 0x000001ce},
+ {0x0000a42c, 0x1ce739ce},
+ {0x0000a430, 0x1ce739ce},
+ {0x0000a434, 0x00000000},
+ {0x0000a438, 0x00001801},
+ {0x0000a43c, 0x00000000},
+ {0x0000a440, 0x00000000},
+ {0x0000a444, 0x00000000},
+ {0x0000a448, 0x06000080},
+ {0x0000a44c, 0x00000001},
+ {0x0000a450, 0x00010000},
+ {0x0000a458, 0x00000000},
+ {0x0000a600, 0x00000000},
+ {0x0000a604, 0x00000000},
+ {0x0000a608, 0x00000000},
+ {0x0000a60c, 0x00000000},
+ {0x0000a610, 0x00000000},
+ {0x0000a614, 0x00000000},
+ {0x0000a618, 0x00000000},
+ {0x0000a61c, 0x00000000},
+ {0x0000a620, 0x00000000},
+ {0x0000a624, 0x00000000},
+ {0x0000a628, 0x00000000},
+ {0x0000a62c, 0x00000000},
+ {0x0000a630, 0x00000000},
+ {0x0000a634, 0x00000000},
+ {0x0000a638, 0x00000000},
+ {0x0000a63c, 0x00000000},
+ {0x0000a640, 0x00000000},
+ {0x0000a644, 0x3fad9d74},
+ {0x0000a648, 0x0048060a},
+ {0x0000a64c, 0x00000637},
+ {0x0000a670, 0x03020100},
+ {0x0000a674, 0x09080504},
+ {0x0000a678, 0x0d0c0b0a},
+ {0x0000a67c, 0x13121110},
+ {0x0000a680, 0x31301514},
+ {0x0000a684, 0x35343332},
+ {0x0000a688, 0x00000036},
+ {0x0000a690, 0x00000838},
+ {0x0000a7c0, 0x00000000},
+ {0x0000a7c4, 0xfffffffc},
+ {0x0000a7c8, 0x00000000},
+ {0x0000a7cc, 0x00000000},
+ {0x0000a7d0, 0x00000000},
+ {0x0000a7d4, 0x00000004},
+ {0x0000a7dc, 0x00000001},
+ {0x0000a8d0, 0x004b6a8e},
+ {0x0000a8d4, 0x00000820},
+ {0x0000a8dc, 0x00000000},
+ {0x0000a8f0, 0x00000000},
+ {0x0000a8f4, 0x00000000},
+ {0x0000b2d0, 0x00000080},
+ {0x0000b2d4, 0x00000000},
+ {0x0000b2dc, 0x00000000},
+ {0x0000b2e0, 0x00000000},
+ {0x0000b2e4, 0x00000000},
+ {0x0000b2e8, 0x00000000},
+ {0x0000b2ec, 0x00000000},
+ {0x0000b2f0, 0x00000000},
+ {0x0000b2f4, 0x00000000},
+ {0x0000b2f8, 0x00000000},
+ {0x0000b408, 0x0e79e5c0},
+ {0x0000b40c, 0x00820820},
+ {0x0000b420, 0x00000000},
+ {0x0000b8d0, 0x004b6a8e},
+ {0x0000b8d4, 0x00000820},
+ {0x0000b8dc, 0x00000000},
+ {0x0000b8f0, 0x00000000},
+ {0x0000b8f4, 0x00000000},
+ {0x0000c2d0, 0x00000080},
+ {0x0000c2d4, 0x00000000},
+ {0x0000c2dc, 0x00000000},
+ {0x0000c2e0, 0x00000000},
+ {0x0000c2e4, 0x00000000},
+ {0x0000c2e8, 0x00000000},
+ {0x0000c2ec, 0x00000000},
+ {0x0000c2f0, 0x00000000},
+ {0x0000c2f4, 0x00000000},
+ {0x0000c2f8, 0x00000000},
+ {0x0000c408, 0x0e79e5c0},
+ {0x0000c40c, 0x00820820},
+ {0x0000c420, 0x00000000},
+};
+
+static const u32 ar9300Modes_high_power_tx_gain_table_2p2[][5] = {
+ /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */
+ {0x0000a410, 0x000050d8, 0x000050d8, 0x000050d9, 0x000050d9},
+ {0x0000a500, 0x00002220, 0x00002220, 0x00000000, 0x00000000},
+ {0x0000a504, 0x04002222, 0x04002222, 0x04000002, 0x04000002},
+ {0x0000a508, 0x09002421, 0x09002421, 0x08000004, 0x08000004},
+ {0x0000a50c, 0x0d002621, 0x0d002621, 0x0b000200, 0x0b000200},
+ {0x0000a510, 0x13004620, 0x13004620, 0x0f000202, 0x0f000202},
+ {0x0000a514, 0x19004a20, 0x19004a20, 0x11000400, 0x11000400},
+ {0x0000a518, 0x1d004e20, 0x1d004e20, 0x15000402, 0x15000402},
+ {0x0000a51c, 0x21005420, 0x21005420, 0x19000404, 0x19000404},
+ {0x0000a520, 0x26005e20, 0x26005e20, 0x1b000603, 0x1b000603},
+ {0x0000a524, 0x2b005e40, 0x2b005e40, 0x1f000a02, 0x1f000a02},
+ {0x0000a528, 0x2f005e42, 0x2f005e42, 0x23000a04, 0x23000a04},
+ {0x0000a52c, 0x33005e44, 0x33005e44, 0x26000a20, 0x26000a20},
+ {0x0000a530, 0x38005e65, 0x38005e65, 0x2a000e20, 0x2a000e20},
+ {0x0000a534, 0x3c005e69, 0x3c005e69, 0x2e000e22, 0x2e000e22},
+ {0x0000a538, 0x40005e6b, 0x40005e6b, 0x31000e24, 0x31000e24},
+ {0x0000a53c, 0x44005e6d, 0x44005e6d, 0x34001640, 0x34001640},
+ {0x0000a540, 0x49005e72, 0x49005e72, 0x38001660, 0x38001660},
+ {0x0000a544, 0x4e005eb2, 0x4e005eb2, 0x3b001861, 0x3b001861},
+ {0x0000a548, 0x53005f12, 0x53005f12, 0x3e001a81, 0x3e001a81},
+ {0x0000a54c, 0x59025eb5, 0x59025eb5, 0x42001a83, 0x42001a83},
+ {0x0000a550, 0x5e025f12, 0x5e025f12, 0x44001c84, 0x44001c84},
+ {0x0000a554, 0x61027f12, 0x61027f12, 0x48001ce3, 0x48001ce3},
+ {0x0000a558, 0x6702bf12, 0x6702bf12, 0x4c001ce5, 0x4c001ce5},
+ {0x0000a55c, 0x6b02bf14, 0x6b02bf14, 0x50001ce9, 0x50001ce9},
+ {0x0000a560, 0x6f02bf16, 0x6f02bf16, 0x54001ceb, 0x54001ceb},
+ {0x0000a564, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec},
+ {0x0000a568, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec},
+ {0x0000a56c, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec},
+ {0x0000a570, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec},
+ {0x0000a574, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec},
+ {0x0000a578, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec},
+ {0x0000a57c, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec},
+ {0x0000a580, 0x00802220, 0x00802220, 0x00800000, 0x00800000},
+ {0x0000a584, 0x04802222, 0x04802222, 0x04800002, 0x04800002},
+ {0x0000a588, 0x09802421, 0x09802421, 0x08800004, 0x08800004},
+ {0x0000a58c, 0x0d802621, 0x0d802621, 0x0b800200, 0x0b800200},
+ {0x0000a590, 0x13804620, 0x13804620, 0x0f800202, 0x0f800202},
+ {0x0000a594, 0x19804a20, 0x19804a20, 0x11800400, 0x11800400},
+ {0x0000a598, 0x1d804e20, 0x1d804e20, 0x15800402, 0x15800402},
+ {0x0000a59c, 0x21805420, 0x21805420, 0x19800404, 0x19800404},
+ {0x0000a5a0, 0x26805e20, 0x26805e20, 0x1b800603, 0x1b800603},
+ {0x0000a5a4, 0x2b805e40, 0x2b805e40, 0x1f800a02, 0x1f800a02},
+ {0x0000a5a8, 0x2f805e42, 0x2f805e42, 0x23800a04, 0x23800a04},
+ {0x0000a5ac, 0x33805e44, 0x33805e44, 0x26800a20, 0x26800a20},
+ {0x0000a5b0, 0x38805e65, 0x38805e65, 0x2a800e20, 0x2a800e20},
+ {0x0000a5b4, 0x3c805e69, 0x3c805e69, 0x2e800e22, 0x2e800e22},
+ {0x0000a5b8, 0x40805e6b, 0x40805e6b, 0x31800e24, 0x31800e24},
+ {0x0000a5bc, 0x44805e6d, 0x44805e6d, 0x34801640, 0x34801640},
+ {0x0000a5c0, 0x49805e72, 0x49805e72, 0x38801660, 0x38801660},
+ {0x0000a5c4, 0x4e805eb2, 0x4e805eb2, 0x3b801861, 0x3b801861},
+ {0x0000a5c8, 0x53805f12, 0x53805f12, 0x3e801a81, 0x3e801a81},
+ {0x0000a5cc, 0x59825eb2, 0x59825eb2, 0x42801a83, 0x42801a83},
+ {0x0000a5d0, 0x5e825f12, 0x5e825f12, 0x44801c84, 0x44801c84},
+ {0x0000a5d4, 0x61827f12, 0x61827f12, 0x48801ce3, 0x48801ce3},
+ {0x0000a5d8, 0x6782bf12, 0x6782bf12, 0x4c801ce5, 0x4c801ce5},
+ {0x0000a5dc, 0x6b82bf14, 0x6b82bf14, 0x50801ce9, 0x50801ce9},
+ {0x0000a5e0, 0x6f82bf16, 0x6f82bf16, 0x54801ceb, 0x54801ceb},
+ {0x0000a5e4, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec},
+ {0x0000a5e8, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec},
+ {0x0000a5ec, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec},
+ {0x0000a5f0, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec},
+ {0x0000a5f4, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec},
+ {0x0000a5f8, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec},
+ {0x0000a5fc, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec},
+ {0x00016044, 0x056db2e6, 0x056db2e6, 0x056db2e6, 0x056db2e6},
+ {0x00016048, 0xae480001, 0xae480001, 0xae480001, 0xae480001},
+ {0x00016068, 0x6eb6db6c, 0x6eb6db6c, 0x6eb6db6c, 0x6eb6db6c},
+ {0x00016444, 0x056db2e6, 0x056db2e6, 0x056db2e6, 0x056db2e6},
+ {0x00016448, 0xae480001, 0xae480001, 0xae480001, 0xae480001},
+ {0x00016468, 0x6eb6db6c, 0x6eb6db6c, 0x6eb6db6c, 0x6eb6db6c},
+ {0x00016844, 0x056db2e6, 0x056db2e6, 0x056db2e6, 0x056db2e6},
+ {0x00016848, 0xae480001, 0xae480001, 0xae480001, 0xae480001},
+ {0x00016868, 0x6eb6db6c, 0x6eb6db6c, 0x6eb6db6c, 0x6eb6db6c},
+};
+
+static const u32 ar9300Modes_high_ob_db_tx_gain_table_2p2[][5] = {
+ /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */
+ {0x0000a410, 0x000050d8, 0x000050d8, 0x000050d9, 0x000050d9},
+ {0x0000a500, 0x00002220, 0x00002220, 0x00000000, 0x00000000},
+ {0x0000a504, 0x04002222, 0x04002222, 0x04000002, 0x04000002},
+ {0x0000a508, 0x09002421, 0x09002421, 0x08000004, 0x08000004},
+ {0x0000a50c, 0x0d002621, 0x0d002621, 0x0b000200, 0x0b000200},
+ {0x0000a510, 0x13004620, 0x13004620, 0x0f000202, 0x0f000202},
+ {0x0000a514, 0x19004a20, 0x19004a20, 0x11000400, 0x11000400},
+ {0x0000a518, 0x1d004e20, 0x1d004e20, 0x15000402, 0x15000402},
+ {0x0000a51c, 0x21005420, 0x21005420, 0x19000404, 0x19000404},
+ {0x0000a520, 0x26005e20, 0x26005e20, 0x1b000603, 0x1b000603},
+ {0x0000a524, 0x2b005e40, 0x2b005e40, 0x1f000a02, 0x1f000a02},
+ {0x0000a528, 0x2f005e42, 0x2f005e42, 0x23000a04, 0x23000a04},
+ {0x0000a52c, 0x33005e44, 0x33005e44, 0x26000a20, 0x26000a20},
+ {0x0000a530, 0x38005e65, 0x38005e65, 0x2a000e20, 0x2a000e20},
+ {0x0000a534, 0x3c005e69, 0x3c005e69, 0x2e000e22, 0x2e000e22},
+ {0x0000a538, 0x40005e6b, 0x40005e6b, 0x31000e24, 0x31000e24},
+ {0x0000a53c, 0x44005e6d, 0x44005e6d, 0x34001640, 0x34001640},
+ {0x0000a540, 0x49005e72, 0x49005e72, 0x38001660, 0x38001660},
+ {0x0000a544, 0x4e005eb2, 0x4e005eb2, 0x3b001861, 0x3b001861},
+ {0x0000a548, 0x53005f12, 0x53005f12, 0x3e001a81, 0x3e001a81},
+ {0x0000a54c, 0x59025eb5, 0x59025eb5, 0x42001a83, 0x42001a83},
+ {0x0000a550, 0x5e025f12, 0x5e025f12, 0x44001c84, 0x44001c84},
+ {0x0000a554, 0x61027f12, 0x61027f12, 0x48001ce3, 0x48001ce3},
+ {0x0000a558, 0x6702bf12, 0x6702bf12, 0x4c001ce5, 0x4c001ce5},
+ {0x0000a55c, 0x6b02bf14, 0x6b02bf14, 0x50001ce9, 0x50001ce9},
+ {0x0000a560, 0x6f02bf16, 0x6f02bf16, 0x54001ceb, 0x54001ceb},
+ {0x0000a564, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec},
+ {0x0000a568, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec},
+ {0x0000a56c, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec},
+ {0x0000a570, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec},
+ {0x0000a574, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec},
+ {0x0000a578, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec},
+ {0x0000a57c, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec},
+ {0x0000a580, 0x00802220, 0x00802220, 0x00800000, 0x00800000},
+ {0x0000a584, 0x04802222, 0x04802222, 0x04800002, 0x04800002},
+ {0x0000a588, 0x09802421, 0x09802421, 0x08800004, 0x08800004},
+ {0x0000a58c, 0x0d802621, 0x0d802621, 0x0b800200, 0x0b800200},
+ {0x0000a590, 0x13804620, 0x13804620, 0x0f800202, 0x0f800202},
+ {0x0000a594, 0x19804a20, 0x19804a20, 0x11800400, 0x11800400},
+ {0x0000a598, 0x1d804e20, 0x1d804e20, 0x15800402, 0x15800402},
+ {0x0000a59c, 0x21805420, 0x21805420, 0x19800404, 0x19800404},
+ {0x0000a5a0, 0x26805e20, 0x26805e20, 0x1b800603, 0x1b800603},
+ {0x0000a5a4, 0x2b805e40, 0x2b805e40, 0x1f800a02, 0x1f800a02},
+ {0x0000a5a8, 0x2f805e42, 0x2f805e42, 0x23800a04, 0x23800a04},
+ {0x0000a5ac, 0x33805e44, 0x33805e44, 0x26800a20, 0x26800a20},
+ {0x0000a5b0, 0x38805e65, 0x38805e65, 0x2a800e20, 0x2a800e20},
+ {0x0000a5b4, 0x3c805e69, 0x3c805e69, 0x2e800e22, 0x2e800e22},
+ {0x0000a5b8, 0x40805e6b, 0x40805e6b, 0x31800e24, 0x31800e24},
+ {0x0000a5bc, 0x44805e6d, 0x44805e6d, 0x34801640, 0x34801640},
+ {0x0000a5c0, 0x49805e72, 0x49805e72, 0x38801660, 0x38801660},
+ {0x0000a5c4, 0x4e805eb2, 0x4e805eb2, 0x3b801861, 0x3b801861},
+ {0x0000a5c8, 0x53805f12, 0x53805f12, 0x3e801a81, 0x3e801a81},
+ {0x0000a5cc, 0x59825eb2, 0x59825eb2, 0x42801a83, 0x42801a83},
+ {0x0000a5d0, 0x5e825f12, 0x5e825f12, 0x44801c84, 0x44801c84},
+ {0x0000a5d4, 0x61827f12, 0x61827f12, 0x48801ce3, 0x48801ce3},
+ {0x0000a5d8, 0x6782bf12, 0x6782bf12, 0x4c801ce5, 0x4c801ce5},
+ {0x0000a5dc, 0x6b82bf14, 0x6b82bf14, 0x50801ce9, 0x50801ce9},
+ {0x0000a5e0, 0x6f82bf16, 0x6f82bf16, 0x54801ceb, 0x54801ceb},
+ {0x0000a5e4, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec},
+ {0x0000a5e8, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec},
+ {0x0000a5ec, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec},
+ {0x0000a5f0, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec},
+ {0x0000a5f4, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec},
+ {0x0000a5f8, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec},
+ {0x0000a5fc, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec},
+ {0x00016044, 0x056db2e4, 0x056db2e4, 0x056db2e4, 0x056db2e4},
+ {0x00016048, 0x8e480001, 0x8e480001, 0x8e480001, 0x8e480001},
+ {0x00016068, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
+ {0x00016444, 0x056db2e4, 0x056db2e4, 0x056db2e4, 0x056db2e4},
+ {0x00016448, 0x8e480001, 0x8e480001, 0x8e480001, 0x8e480001},
+ {0x00016468, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
+ {0x00016844, 0x056db2e4, 0x056db2e4, 0x056db2e4, 0x056db2e4},
+ {0x00016848, 0x8e480001, 0x8e480001, 0x8e480001, 0x8e480001},
+ {0x00016868, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
+};
+
+static const u32 ar9300Common_rx_gain_table_2p2[][2] = {
+ /* Addr allmodes */
+ {0x0000a000, 0x00010000},
+ {0x0000a004, 0x00030002},
+ {0x0000a008, 0x00050004},
+ {0x0000a00c, 0x00810080},
+ {0x0000a010, 0x00830082},
+ {0x0000a014, 0x01810180},
+ {0x0000a018, 0x01830182},
+ {0x0000a01c, 0x01850184},
+ {0x0000a020, 0x01890188},
+ {0x0000a024, 0x018b018a},
+ {0x0000a028, 0x018d018c},
+ {0x0000a02c, 0x01910190},
+ {0x0000a030, 0x01930192},
+ {0x0000a034, 0x01950194},
+ {0x0000a038, 0x038a0196},
+ {0x0000a03c, 0x038c038b},
+ {0x0000a040, 0x0390038d},
+ {0x0000a044, 0x03920391},
+ {0x0000a048, 0x03940393},
+ {0x0000a04c, 0x03960395},
+ {0x0000a050, 0x00000000},
+ {0x0000a054, 0x00000000},
+ {0x0000a058, 0x00000000},
+ {0x0000a05c, 0x00000000},
+ {0x0000a060, 0x00000000},
+ {0x0000a064, 0x00000000},
+ {0x0000a068, 0x00000000},
+ {0x0000a06c, 0x00000000},
+ {0x0000a070, 0x00000000},
+ {0x0000a074, 0x00000000},
+ {0x0000a078, 0x00000000},
+ {0x0000a07c, 0x00000000},
+ {0x0000a080, 0x22222229},
+ {0x0000a084, 0x1d1d1d1d},
+ {0x0000a088, 0x1d1d1d1d},
+ {0x0000a08c, 0x1d1d1d1d},
+ {0x0000a090, 0x171d1d1d},
+ {0x0000a094, 0x11111717},
+ {0x0000a098, 0x00030311},
+ {0x0000a09c, 0x00000000},
+ {0x0000a0a0, 0x00000000},
+ {0x0000a0a4, 0x00000000},
+ {0x0000a0a8, 0x00000000},
+ {0x0000a0ac, 0x00000000},
+ {0x0000a0b0, 0x00000000},
+ {0x0000a0b4, 0x00000000},
+ {0x0000a0b8, 0x00000000},
+ {0x0000a0bc, 0x00000000},
+ {0x0000a0c0, 0x001f0000},
+ {0x0000a0c4, 0x01000101},
+ {0x0000a0c8, 0x011e011f},
+ {0x0000a0cc, 0x011c011d},
+ {0x0000a0d0, 0x02030204},
+ {0x0000a0d4, 0x02010202},
+ {0x0000a0d8, 0x021f0200},
+ {0x0000a0dc, 0x0302021e},
+ {0x0000a0e0, 0x03000301},
+ {0x0000a0e4, 0x031e031f},
+ {0x0000a0e8, 0x0402031d},
+ {0x0000a0ec, 0x04000401},
+ {0x0000a0f0, 0x041e041f},
+ {0x0000a0f4, 0x0502041d},
+ {0x0000a0f8, 0x05000501},
+ {0x0000a0fc, 0x051e051f},
+ {0x0000a100, 0x06010602},
+ {0x0000a104, 0x061f0600},
+ {0x0000a108, 0x061d061e},
+ {0x0000a10c, 0x07020703},
+ {0x0000a110, 0x07000701},
+ {0x0000a114, 0x00000000},
+ {0x0000a118, 0x00000000},
+ {0x0000a11c, 0x00000000},
+ {0x0000a120, 0x00000000},
+ {0x0000a124, 0x00000000},
+ {0x0000a128, 0x00000000},
+ {0x0000a12c, 0x00000000},
+ {0x0000a130, 0x00000000},
+ {0x0000a134, 0x00000000},
+ {0x0000a138, 0x00000000},
+ {0x0000a13c, 0x00000000},
+ {0x0000a140, 0x001f0000},
+ {0x0000a144, 0x01000101},
+ {0x0000a148, 0x011e011f},
+ {0x0000a14c, 0x011c011d},
+ {0x0000a150, 0x02030204},
+ {0x0000a154, 0x02010202},
+ {0x0000a158, 0x021f0200},
+ {0x0000a15c, 0x0302021e},
+ {0x0000a160, 0x03000301},
+ {0x0000a164, 0x031e031f},
+ {0x0000a168, 0x0402031d},
+ {0x0000a16c, 0x04000401},
+ {0x0000a170, 0x041e041f},
+ {0x0000a174, 0x0502041d},
+ {0x0000a178, 0x05000501},
+ {0x0000a17c, 0x051e051f},
+ {0x0000a180, 0x06010602},
+ {0x0000a184, 0x061f0600},
+ {0x0000a188, 0x061d061e},
+ {0x0000a18c, 0x07020703},
+ {0x0000a190, 0x07000701},
+ {0x0000a194, 0x00000000},
+ {0x0000a198, 0x00000000},
+ {0x0000a19c, 0x00000000},
+ {0x0000a1a0, 0x00000000},
+ {0x0000a1a4, 0x00000000},
+ {0x0000a1a8, 0x00000000},
+ {0x0000a1ac, 0x00000000},
+ {0x0000a1b0, 0x00000000},
+ {0x0000a1b4, 0x00000000},
+ {0x0000a1b8, 0x00000000},
+ {0x0000a1bc, 0x00000000},
+ {0x0000a1c0, 0x00000000},
+ {0x0000a1c4, 0x00000000},
+ {0x0000a1c8, 0x00000000},
+ {0x0000a1cc, 0x00000000},
+ {0x0000a1d0, 0x00000000},
+ {0x0000a1d4, 0x00000000},
+ {0x0000a1d8, 0x00000000},
+ {0x0000a1dc, 0x00000000},
+ {0x0000a1e0, 0x00000000},
+ {0x0000a1e4, 0x00000000},
+ {0x0000a1e8, 0x00000000},
+ {0x0000a1ec, 0x00000000},
+ {0x0000a1f0, 0x00000396},
+ {0x0000a1f4, 0x00000396},
+ {0x0000a1f8, 0x00000396},
+ {0x0000a1fc, 0x00000196},
+ {0x0000b000, 0x00010000},
+ {0x0000b004, 0x00030002},
+ {0x0000b008, 0x00050004},
+ {0x0000b00c, 0x00810080},
+ {0x0000b010, 0x00830082},
+ {0x0000b014, 0x01810180},
+ {0x0000b018, 0x01830182},
+ {0x0000b01c, 0x01850184},
+ {0x0000b020, 0x02810280},
+ {0x0000b024, 0x02830282},
+ {0x0000b028, 0x02850284},
+ {0x0000b02c, 0x02890288},
+ {0x0000b030, 0x028b028a},
+ {0x0000b034, 0x0388028c},
+ {0x0000b038, 0x038a0389},
+ {0x0000b03c, 0x038c038b},
+ {0x0000b040, 0x0390038d},
+ {0x0000b044, 0x03920391},
+ {0x0000b048, 0x03940393},
+ {0x0000b04c, 0x03960395},
+ {0x0000b050, 0x00000000},
+ {0x0000b054, 0x00000000},
+ {0x0000b058, 0x00000000},
+ {0x0000b05c, 0x00000000},
+ {0x0000b060, 0x00000000},
+ {0x0000b064, 0x00000000},
+ {0x0000b068, 0x00000000},
+ {0x0000b06c, 0x00000000},
+ {0x0000b070, 0x00000000},
+ {0x0000b074, 0x00000000},
+ {0x0000b078, 0x00000000},
+ {0x0000b07c, 0x00000000},
+ {0x0000b080, 0x32323232},
+ {0x0000b084, 0x2f2f3232},
+ {0x0000b088, 0x23282a2d},
+ {0x0000b08c, 0x1c1e2123},
+ {0x0000b090, 0x14171919},
+ {0x0000b094, 0x0e0e1214},
+ {0x0000b098, 0x03050707},
+ {0x0000b09c, 0x00030303},
+ {0x0000b0a0, 0x00000000},
+ {0x0000b0a4, 0x00000000},
+ {0x0000b0a8, 0x00000000},
+ {0x0000b0ac, 0x00000000},
+ {0x0000b0b0, 0x00000000},
+ {0x0000b0b4, 0x00000000},
+ {0x0000b0b8, 0x00000000},
+ {0x0000b0bc, 0x00000000},
+ {0x0000b0c0, 0x003f0020},
+ {0x0000b0c4, 0x00400041},
+ {0x0000b0c8, 0x0140005f},
+ {0x0000b0cc, 0x0160015f},
+ {0x0000b0d0, 0x017e017f},
+ {0x0000b0d4, 0x02410242},
+ {0x0000b0d8, 0x025f0240},
+ {0x0000b0dc, 0x027f0260},
+ {0x0000b0e0, 0x0341027e},
+ {0x0000b0e4, 0x035f0340},
+ {0x0000b0e8, 0x037f0360},
+ {0x0000b0ec, 0x04400441},
+ {0x0000b0f0, 0x0460045f},
+ {0x0000b0f4, 0x0541047f},
+ {0x0000b0f8, 0x055f0540},
+ {0x0000b0fc, 0x057f0560},
+ {0x0000b100, 0x06400641},
+ {0x0000b104, 0x0660065f},
+ {0x0000b108, 0x067e067f},
+ {0x0000b10c, 0x07410742},
+ {0x0000b110, 0x075f0740},
+ {0x0000b114, 0x077f0760},
+ {0x0000b118, 0x07800781},
+ {0x0000b11c, 0x07a0079f},
+ {0x0000b120, 0x07c107bf},
+ {0x0000b124, 0x000007c0},
+ {0x0000b128, 0x00000000},
+ {0x0000b12c, 0x00000000},
+ {0x0000b130, 0x00000000},
+ {0x0000b134, 0x00000000},
+ {0x0000b138, 0x00000000},
+ {0x0000b13c, 0x00000000},
+ {0x0000b140, 0x003f0020},
+ {0x0000b144, 0x00400041},
+ {0x0000b148, 0x0140005f},
+ {0x0000b14c, 0x0160015f},
+ {0x0000b150, 0x017e017f},
+ {0x0000b154, 0x02410242},
+ {0x0000b158, 0x025f0240},
+ {0x0000b15c, 0x027f0260},
+ {0x0000b160, 0x0341027e},
+ {0x0000b164, 0x035f0340},
+ {0x0000b168, 0x037f0360},
+ {0x0000b16c, 0x04400441},
+ {0x0000b170, 0x0460045f},
+ {0x0000b174, 0x0541047f},
+ {0x0000b178, 0x055f0540},
+ {0x0000b17c, 0x057f0560},
+ {0x0000b180, 0x06400641},
+ {0x0000b184, 0x0660065f},
+ {0x0000b188, 0x067e067f},
+ {0x0000b18c, 0x07410742},
+ {0x0000b190, 0x075f0740},
+ {0x0000b194, 0x077f0760},
+ {0x0000b198, 0x07800781},
+ {0x0000b19c, 0x07a0079f},
+ {0x0000b1a0, 0x07c107bf},
+ {0x0000b1a4, 0x000007c0},
+ {0x0000b1a8, 0x00000000},
+ {0x0000b1ac, 0x00000000},
+ {0x0000b1b0, 0x00000000},
+ {0x0000b1b4, 0x00000000},
+ {0x0000b1b8, 0x00000000},
+ {0x0000b1bc, 0x00000000},
+ {0x0000b1c0, 0x00000000},
+ {0x0000b1c4, 0x00000000},
+ {0x0000b1c8, 0x00000000},
+ {0x0000b1cc, 0x00000000},
+ {0x0000b1d0, 0x00000000},
+ {0x0000b1d4, 0x00000000},
+ {0x0000b1d8, 0x00000000},
+ {0x0000b1dc, 0x00000000},
+ {0x0000b1e0, 0x00000000},
+ {0x0000b1e4, 0x00000000},
+ {0x0000b1e8, 0x00000000},
+ {0x0000b1ec, 0x00000000},
+ {0x0000b1f0, 0x00000396},
+ {0x0000b1f4, 0x00000396},
+ {0x0000b1f8, 0x00000396},
+ {0x0000b1fc, 0x00000196},
+};
+
+static const u32 ar9300Modes_low_ob_db_tx_gain_table_2p2[][5] = {
+ /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */
+ {0x0000a410, 0x000050d9, 0x000050d9, 0x000050d9, 0x000050d9},
+ {0x0000a500, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+ {0x0000a504, 0x06000003, 0x06000003, 0x04000002, 0x04000002},
+ {0x0000a508, 0x0a000020, 0x0a000020, 0x08000004, 0x08000004},
+ {0x0000a50c, 0x10000023, 0x10000023, 0x0b000200, 0x0b000200},
+ {0x0000a510, 0x16000220, 0x16000220, 0x0f000202, 0x0f000202},
+ {0x0000a514, 0x1c000223, 0x1c000223, 0x12000400, 0x12000400},
+ {0x0000a518, 0x21002220, 0x21002220, 0x16000402, 0x16000402},
+ {0x0000a51c, 0x27002223, 0x27002223, 0x19000404, 0x19000404},
+ {0x0000a520, 0x2b022220, 0x2b022220, 0x1c000603, 0x1c000603},
+ {0x0000a524, 0x2f022222, 0x2f022222, 0x21000a02, 0x21000a02},
+ {0x0000a528, 0x34022225, 0x34022225, 0x25000a04, 0x25000a04},
+ {0x0000a52c, 0x3a02222a, 0x3a02222a, 0x28000a20, 0x28000a20},
+ {0x0000a530, 0x3e02222c, 0x3e02222c, 0x2c000e20, 0x2c000e20},
+ {0x0000a534, 0x4202242a, 0x4202242a, 0x30000e22, 0x30000e22},
+ {0x0000a538, 0x4702244a, 0x4702244a, 0x34000e24, 0x34000e24},
+ {0x0000a53c, 0x4b02244c, 0x4b02244c, 0x38001640, 0x38001640},
+ {0x0000a540, 0x4e02246c, 0x4e02246c, 0x3c001660, 0x3c001660},
+ {0x0000a544, 0x5302266c, 0x5302266c, 0x3f001861, 0x3f001861},
+ {0x0000a548, 0x5702286c, 0x5702286c, 0x43001a81, 0x43001a81},
+ {0x0000a54c, 0x5c02486b, 0x5c02486b, 0x47001a83, 0x47001a83},
+ {0x0000a550, 0x61024a6c, 0x61024a6c, 0x4a001c84, 0x4a001c84},
+ {0x0000a554, 0x66026a6c, 0x66026a6c, 0x4e001ce3, 0x4e001ce3},
+ {0x0000a558, 0x6b026e6c, 0x6b026e6c, 0x52001ce5, 0x52001ce5},
+ {0x0000a55c, 0x7002708c, 0x7002708c, 0x56001ce9, 0x56001ce9},
+ {0x0000a560, 0x7302b08a, 0x7302b08a, 0x5a001ceb, 0x5a001ceb},
+ {0x0000a564, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec},
+ {0x0000a568, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec},
+ {0x0000a56c, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec},
+ {0x0000a570, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec},
+ {0x0000a574, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec},
+ {0x0000a578, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec},
+ {0x0000a57c, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec},
+ {0x0000a580, 0x00800000, 0x00800000, 0x00800000, 0x00800000},
+ {0x0000a584, 0x06800003, 0x06800003, 0x04800002, 0x04800002},
+ {0x0000a588, 0x0a800020, 0x0a800020, 0x08800004, 0x08800004},
+ {0x0000a58c, 0x10800023, 0x10800023, 0x0b800200, 0x0b800200},
+ {0x0000a590, 0x16800220, 0x16800220, 0x0f800202, 0x0f800202},
+ {0x0000a594, 0x1c800223, 0x1c800223, 0x12800400, 0x12800400},
+ {0x0000a598, 0x21802220, 0x21802220, 0x16800402, 0x16800402},
+ {0x0000a59c, 0x27802223, 0x27802223, 0x19800404, 0x19800404},
+ {0x0000a5a0, 0x2b822220, 0x2b822220, 0x1c800603, 0x1c800603},
+ {0x0000a5a4, 0x2f822222, 0x2f822222, 0x21800a02, 0x21800a02},
+ {0x0000a5a8, 0x34822225, 0x34822225, 0x25800a04, 0x25800a04},
+ {0x0000a5ac, 0x3a82222a, 0x3a82222a, 0x28800a20, 0x28800a20},
+ {0x0000a5b0, 0x3e82222c, 0x3e82222c, 0x2c800e20, 0x2c800e20},
+ {0x0000a5b4, 0x4282242a, 0x4282242a, 0x30800e22, 0x30800e22},
+ {0x0000a5b8, 0x4782244a, 0x4782244a, 0x34800e24, 0x34800e24},
+ {0x0000a5bc, 0x4b82244c, 0x4b82244c, 0x38801640, 0x38801640},
+ {0x0000a5c0, 0x4e82246c, 0x4e82246c, 0x3c801660, 0x3c801660},
+ {0x0000a5c4, 0x5382266c, 0x5382266c, 0x3f801861, 0x3f801861},
+ {0x0000a5c8, 0x5782286c, 0x5782286c, 0x43801a81, 0x43801a81},
+ {0x0000a5cc, 0x5c82486b, 0x5c82486b, 0x47801a83, 0x47801a83},
+ {0x0000a5d0, 0x61824a6c, 0x61824a6c, 0x4a801c84, 0x4a801c84},
+ {0x0000a5d4, 0x66826a6c, 0x66826a6c, 0x4e801ce3, 0x4e801ce3},
+ {0x0000a5d8, 0x6b826e6c, 0x6b826e6c, 0x52801ce5, 0x52801ce5},
+ {0x0000a5dc, 0x7082708c, 0x7082708c, 0x56801ce9, 0x56801ce9},
+ {0x0000a5e0, 0x7382b08a, 0x7382b08a, 0x5a801ceb, 0x5a801ceb},
+ {0x0000a5e4, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec},
+ {0x0000a5e8, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec},
+ {0x0000a5ec, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec},
+ {0x0000a5f0, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec},
+ {0x0000a5f4, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec},
+ {0x0000a5f8, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec},
+ {0x0000a5fc, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec},
+ {0x00016044, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4},
+ {0x00016048, 0x66480001, 0x66480001, 0x66480001, 0x66480001},
+ {0x00016068, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
+ {0x00016444, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4},
+ {0x00016448, 0x66480001, 0x66480001, 0x66480001, 0x66480001},
+ {0x00016468, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
+ {0x00016844, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4},
+ {0x00016848, 0x66480001, 0x66480001, 0x66480001, 0x66480001},
+ {0x00016868, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
+};
+
+static const u32 ar9300_2p2_mac_core[][2] = {
+ /* Addr allmodes */
+ {0x00000008, 0x00000000},
+ {0x00000030, 0x00020085},
+ {0x00000034, 0x00000005},
+ {0x00000040, 0x00000000},
+ {0x00000044, 0x00000000},
+ {0x00000048, 0x00000008},
+ {0x0000004c, 0x00000010},
+ {0x00000050, 0x00000000},
+ {0x00001040, 0x002ffc0f},
+ {0x00001044, 0x002ffc0f},
+ {0x00001048, 0x002ffc0f},
+ {0x0000104c, 0x002ffc0f},
+ {0x00001050, 0x002ffc0f},
+ {0x00001054, 0x002ffc0f},
+ {0x00001058, 0x002ffc0f},
+ {0x0000105c, 0x002ffc0f},
+ {0x00001060, 0x002ffc0f},
+ {0x00001064, 0x002ffc0f},
+ {0x000010f0, 0x00000100},
+ {0x00001270, 0x00000000},
+ {0x000012b0, 0x00000000},
+ {0x000012f0, 0x00000000},
+ {0x0000143c, 0x00000000},
+ {0x0000147c, 0x00000000},
+ {0x00008000, 0x00000000},
+ {0x00008004, 0x00000000},
+ {0x00008008, 0x00000000},
+ {0x0000800c, 0x00000000},
+ {0x00008018, 0x00000000},
+ {0x00008020, 0x00000000},
+ {0x00008038, 0x00000000},
+ {0x0000803c, 0x00000000},
+ {0x00008040, 0x00000000},
+ {0x00008044, 0x00000000},
+ {0x00008048, 0x00000000},
+ {0x0000804c, 0xffffffff},
+ {0x00008054, 0x00000000},
+ {0x00008058, 0x00000000},
+ {0x0000805c, 0x000fc78f},
+ {0x00008060, 0x0000000f},
+ {0x00008064, 0x00000000},
+ {0x00008070, 0x00000310},
+ {0x00008074, 0x00000020},
+ {0x00008078, 0x00000000},
+ {0x0000809c, 0x0000000f},
+ {0x000080a0, 0x00000000},
+ {0x000080a4, 0x02ff0000},
+ {0x000080a8, 0x0e070605},
+ {0x000080ac, 0x0000000d},
+ {0x000080b0, 0x00000000},
+ {0x000080b4, 0x00000000},
+ {0x000080b8, 0x00000000},
+ {0x000080bc, 0x00000000},
+ {0x000080c0, 0x2a800000},
+ {0x000080c4, 0x06900168},
+ {0x000080c8, 0x13881c20},
+ {0x000080cc, 0x01f40000},
+ {0x000080d0, 0x00252500},
+ {0x000080d4, 0x00a00000},
+ {0x000080d8, 0x00400000},
+ {0x000080dc, 0x00000000},
+ {0x000080e0, 0xffffffff},
+ {0x000080e4, 0x0000ffff},
+ {0x000080e8, 0x3f3f3f3f},
+ {0x000080ec, 0x00000000},
+ {0x000080f0, 0x00000000},
+ {0x000080f4, 0x00000000},
+ {0x000080fc, 0x00020000},
+ {0x00008100, 0x00000000},
+ {0x00008108, 0x00000052},
+ {0x0000810c, 0x00000000},
+ {0x00008110, 0x00000000},
+ {0x00008114, 0x000007ff},
+ {0x00008118, 0x000000aa},
+ {0x0000811c, 0x00003210},
+ {0x00008124, 0x00000000},
+ {0x00008128, 0x00000000},
+ {0x0000812c, 0x00000000},
+ {0x00008130, 0x00000000},
+ {0x00008134, 0x00000000},
+ {0x00008138, 0x00000000},
+ {0x0000813c, 0x0000ffff},
+ {0x00008144, 0xffffffff},
+ {0x00008168, 0x00000000},
+ {0x0000816c, 0x00000000},
+ {0x00008170, 0x18486200},
+ {0x00008174, 0x33332210},
+ {0x00008178, 0x00000000},
+ {0x0000817c, 0x00020000},
+ {0x000081c0, 0x00000000},
+ {0x000081c4, 0x33332210},
+ {0x000081c8, 0x00000000},
+ {0x000081cc, 0x00000000},
+ {0x000081d4, 0x00000000},
+ {0x000081ec, 0x00000000},
+ {0x000081f0, 0x00000000},
+ {0x000081f4, 0x00000000},
+ {0x000081f8, 0x00000000},
+ {0x000081fc, 0x00000000},
+ {0x00008240, 0x00100000},
+ {0x00008244, 0x0010f424},
+ {0x00008248, 0x00000800},
+ {0x0000824c, 0x0001e848},
+ {0x00008250, 0x00000000},
+ {0x00008254, 0x00000000},
+ {0x00008258, 0x00000000},
+ {0x0000825c, 0x40000000},
+ {0x00008260, 0x00080922},
+ {0x00008264, 0x9bc00010},
+ {0x00008268, 0xffffffff},
+ {0x0000826c, 0x0000ffff},
+ {0x00008270, 0x00000000},
+ {0x00008274, 0x40000000},
+ {0x00008278, 0x003e4180},
+ {0x0000827c, 0x00000004},
+ {0x00008284, 0x0000002c},
+ {0x00008288, 0x0000002c},
+ {0x0000828c, 0x000000ff},
+ {0x00008294, 0x00000000},
+ {0x00008298, 0x00000000},
+ {0x0000829c, 0x00000000},
+ {0x00008300, 0x00000140},
+ {0x00008314, 0x00000000},
+ {0x0000831c, 0x0000010d},
+ {0x00008328, 0x00000000},
+ {0x0000832c, 0x00000007},
+ {0x00008330, 0x00000302},
+ {0x00008334, 0x00000700},
+ {0x00008338, 0x00ff0000},
+ {0x0000833c, 0x02400000},
+ {0x00008340, 0x000107ff},
+ {0x00008344, 0xaa48105b},
+ {0x00008348, 0x008f0000},
+ {0x0000835c, 0x00000000},
+ {0x00008360, 0xffffffff},
+ {0x00008364, 0xffffffff},
+ {0x00008368, 0x00000000},
+ {0x00008370, 0x00000000},
+ {0x00008374, 0x000000ff},
+ {0x00008378, 0x00000000},
+ {0x0000837c, 0x00000000},
+ {0x00008380, 0xffffffff},
+ {0x00008384, 0xffffffff},
+ {0x00008390, 0xffffffff},
+ {0x00008394, 0xffffffff},
+ {0x00008398, 0x00000000},
+ {0x0000839c, 0x00000000},
+ {0x000083a0, 0x00000000},
+ {0x000083a4, 0x0000fa14},
+ {0x000083a8, 0x000f0c00},
+ {0x000083ac, 0x33332210},
+ {0x000083b0, 0x33332210},
+ {0x000083b4, 0x33332210},
+ {0x000083b8, 0x33332210},
+ {0x000083bc, 0x00000000},
+ {0x000083c0, 0x00000000},
+ {0x000083c4, 0x00000000},
+ {0x000083c8, 0x00000000},
+ {0x000083cc, 0x00000200},
+ {0x000083d0, 0x000301ff},
+};
+
+static const u32 ar9300Common_wo_xlna_rx_gain_table_2p2[][2] = {
+ /* Addr allmodes */
+ {0x0000a000, 0x00010000},
+ {0x0000a004, 0x00030002},
+ {0x0000a008, 0x00050004},
+ {0x0000a00c, 0x00810080},
+ {0x0000a010, 0x00830082},
+ {0x0000a014, 0x01810180},
+ {0x0000a018, 0x01830182},
+ {0x0000a01c, 0x01850184},
+ {0x0000a020, 0x01890188},
+ {0x0000a024, 0x018b018a},
+ {0x0000a028, 0x018d018c},
+ {0x0000a02c, 0x03820190},
+ {0x0000a030, 0x03840383},
+ {0x0000a034, 0x03880385},
+ {0x0000a038, 0x038a0389},
+ {0x0000a03c, 0x038c038b},
+ {0x0000a040, 0x0390038d},
+ {0x0000a044, 0x03920391},
+ {0x0000a048, 0x03940393},
+ {0x0000a04c, 0x03960395},
+ {0x0000a050, 0x00000000},
+ {0x0000a054, 0x00000000},
+ {0x0000a058, 0x00000000},
+ {0x0000a05c, 0x00000000},
+ {0x0000a060, 0x00000000},
+ {0x0000a064, 0x00000000},
+ {0x0000a068, 0x00000000},
+ {0x0000a06c, 0x00000000},
+ {0x0000a070, 0x00000000},
+ {0x0000a074, 0x00000000},
+ {0x0000a078, 0x00000000},
+ {0x0000a07c, 0x00000000},
+ {0x0000a080, 0x29292929},
+ {0x0000a084, 0x29292929},
+ {0x0000a088, 0x29292929},
+ {0x0000a08c, 0x29292929},
+ {0x0000a090, 0x22292929},
+ {0x0000a094, 0x1d1d2222},
+ {0x0000a098, 0x0c111117},
+ {0x0000a09c, 0x00030303},
+ {0x0000a0a0, 0x00000000},
+ {0x0000a0a4, 0x00000000},
+ {0x0000a0a8, 0x00000000},
+ {0x0000a0ac, 0x00000000},
+ {0x0000a0b0, 0x00000000},
+ {0x0000a0b4, 0x00000000},
+ {0x0000a0b8, 0x00000000},
+ {0x0000a0bc, 0x00000000},
+ {0x0000a0c0, 0x001f0000},
+ {0x0000a0c4, 0x01000101},
+ {0x0000a0c8, 0x011e011f},
+ {0x0000a0cc, 0x011c011d},
+ {0x0000a0d0, 0x02030204},
+ {0x0000a0d4, 0x02010202},
+ {0x0000a0d8, 0x021f0200},
+ {0x0000a0dc, 0x0302021e},
+ {0x0000a0e0, 0x03000301},
+ {0x0000a0e4, 0x031e031f},
+ {0x0000a0e8, 0x0402031d},
+ {0x0000a0ec, 0x04000401},
+ {0x0000a0f0, 0x041e041f},
+ {0x0000a0f4, 0x0502041d},
+ {0x0000a0f8, 0x05000501},
+ {0x0000a0fc, 0x051e051f},
+ {0x0000a100, 0x06010602},
+ {0x0000a104, 0x061f0600},
+ {0x0000a108, 0x061d061e},
+ {0x0000a10c, 0x07020703},
+ {0x0000a110, 0x07000701},
+ {0x0000a114, 0x00000000},
+ {0x0000a118, 0x00000000},
+ {0x0000a11c, 0x00000000},
+ {0x0000a120, 0x00000000},
+ {0x0000a124, 0x00000000},
+ {0x0000a128, 0x00000000},
+ {0x0000a12c, 0x00000000},
+ {0x0000a130, 0x00000000},
+ {0x0000a134, 0x00000000},
+ {0x0000a138, 0x00000000},
+ {0x0000a13c, 0x00000000},
+ {0x0000a140, 0x001f0000},
+ {0x0000a144, 0x01000101},
+ {0x0000a148, 0x011e011f},
+ {0x0000a14c, 0x011c011d},
+ {0x0000a150, 0x02030204},
+ {0x0000a154, 0x02010202},
+ {0x0000a158, 0x021f0200},
+ {0x0000a15c, 0x0302021e},
+ {0x0000a160, 0x03000301},
+ {0x0000a164, 0x031e031f},
+ {0x0000a168, 0x0402031d},
+ {0x0000a16c, 0x04000401},
+ {0x0000a170, 0x041e041f},
+ {0x0000a174, 0x0502041d},
+ {0x0000a178, 0x05000501},
+ {0x0000a17c, 0x051e051f},
+ {0x0000a180, 0x06010602},
+ {0x0000a184, 0x061f0600},
+ {0x0000a188, 0x061d061e},
+ {0x0000a18c, 0x07020703},
+ {0x0000a190, 0x07000701},
+ {0x0000a194, 0x00000000},
+ {0x0000a198, 0x00000000},
+ {0x0000a19c, 0x00000000},
+ {0x0000a1a0, 0x00000000},
+ {0x0000a1a4, 0x00000000},
+ {0x0000a1a8, 0x00000000},
+ {0x0000a1ac, 0x00000000},
+ {0x0000a1b0, 0x00000000},
+ {0x0000a1b4, 0x00000000},
+ {0x0000a1b8, 0x00000000},
+ {0x0000a1bc, 0x00000000},
+ {0x0000a1c0, 0x00000000},
+ {0x0000a1c4, 0x00000000},
+ {0x0000a1c8, 0x00000000},
+ {0x0000a1cc, 0x00000000},
+ {0x0000a1d0, 0x00000000},
+ {0x0000a1d4, 0x00000000},
+ {0x0000a1d8, 0x00000000},
+ {0x0000a1dc, 0x00000000},
+ {0x0000a1e0, 0x00000000},
+ {0x0000a1e4, 0x00000000},
+ {0x0000a1e8, 0x00000000},
+ {0x0000a1ec, 0x00000000},
+ {0x0000a1f0, 0x00000396},
+ {0x0000a1f4, 0x00000396},
+ {0x0000a1f8, 0x00000396},
+ {0x0000a1fc, 0x00000196},
+ {0x0000b000, 0x00010000},
+ {0x0000b004, 0x00030002},
+ {0x0000b008, 0x00050004},
+ {0x0000b00c, 0x00810080},
+ {0x0000b010, 0x00830082},
+ {0x0000b014, 0x01810180},
+ {0x0000b018, 0x01830182},
+ {0x0000b01c, 0x01850184},
+ {0x0000b020, 0x02810280},
+ {0x0000b024, 0x02830282},
+ {0x0000b028, 0x02850284},
+ {0x0000b02c, 0x02890288},
+ {0x0000b030, 0x028b028a},
+ {0x0000b034, 0x0388028c},
+ {0x0000b038, 0x038a0389},
+ {0x0000b03c, 0x038c038b},
+ {0x0000b040, 0x0390038d},
+ {0x0000b044, 0x03920391},
+ {0x0000b048, 0x03940393},
+ {0x0000b04c, 0x03960395},
+ {0x0000b050, 0x00000000},
+ {0x0000b054, 0x00000000},
+ {0x0000b058, 0x00000000},
+ {0x0000b05c, 0x00000000},
+ {0x0000b060, 0x00000000},
+ {0x0000b064, 0x00000000},
+ {0x0000b068, 0x00000000},
+ {0x0000b06c, 0x00000000},
+ {0x0000b070, 0x00000000},
+ {0x0000b074, 0x00000000},
+ {0x0000b078, 0x00000000},
+ {0x0000b07c, 0x00000000},
+ {0x0000b080, 0x32323232},
+ {0x0000b084, 0x2f2f3232},
+ {0x0000b088, 0x23282a2d},
+ {0x0000b08c, 0x1c1e2123},
+ {0x0000b090, 0x14171919},
+ {0x0000b094, 0x0e0e1214},
+ {0x0000b098, 0x03050707},
+ {0x0000b09c, 0x00030303},
+ {0x0000b0a0, 0x00000000},
+ {0x0000b0a4, 0x00000000},
+ {0x0000b0a8, 0x00000000},
+ {0x0000b0ac, 0x00000000},
+ {0x0000b0b0, 0x00000000},
+ {0x0000b0b4, 0x00000000},
+ {0x0000b0b8, 0x00000000},
+ {0x0000b0bc, 0x00000000},
+ {0x0000b0c0, 0x003f0020},
+ {0x0000b0c4, 0x00400041},
+ {0x0000b0c8, 0x0140005f},
+ {0x0000b0cc, 0x0160015f},
+ {0x0000b0d0, 0x017e017f},
+ {0x0000b0d4, 0x02410242},
+ {0x0000b0d8, 0x025f0240},
+ {0x0000b0dc, 0x027f0260},
+ {0x0000b0e0, 0x0341027e},
+ {0x0000b0e4, 0x035f0340},
+ {0x0000b0e8, 0x037f0360},
+ {0x0000b0ec, 0x04400441},
+ {0x0000b0f0, 0x0460045f},
+ {0x0000b0f4, 0x0541047f},
+ {0x0000b0f8, 0x055f0540},
+ {0x0000b0fc, 0x057f0560},
+ {0x0000b100, 0x06400641},
+ {0x0000b104, 0x0660065f},
+ {0x0000b108, 0x067e067f},
+ {0x0000b10c, 0x07410742},
+ {0x0000b110, 0x075f0740},
+ {0x0000b114, 0x077f0760},
+ {0x0000b118, 0x07800781},
+ {0x0000b11c, 0x07a0079f},
+ {0x0000b120, 0x07c107bf},
+ {0x0000b124, 0x000007c0},
+ {0x0000b128, 0x00000000},
+ {0x0000b12c, 0x00000000},
+ {0x0000b130, 0x00000000},
+ {0x0000b134, 0x00000000},
+ {0x0000b138, 0x00000000},
+ {0x0000b13c, 0x00000000},
+ {0x0000b140, 0x003f0020},
+ {0x0000b144, 0x00400041},
+ {0x0000b148, 0x0140005f},
+ {0x0000b14c, 0x0160015f},
+ {0x0000b150, 0x017e017f},
+ {0x0000b154, 0x02410242},
+ {0x0000b158, 0x025f0240},
+ {0x0000b15c, 0x027f0260},
+ {0x0000b160, 0x0341027e},
+ {0x0000b164, 0x035f0340},
+ {0x0000b168, 0x037f0360},
+ {0x0000b16c, 0x04400441},
+ {0x0000b170, 0x0460045f},
+ {0x0000b174, 0x0541047f},
+ {0x0000b178, 0x055f0540},
+ {0x0000b17c, 0x057f0560},
+ {0x0000b180, 0x06400641},
+ {0x0000b184, 0x0660065f},
+ {0x0000b188, 0x067e067f},
+ {0x0000b18c, 0x07410742},
+ {0x0000b190, 0x075f0740},
+ {0x0000b194, 0x077f0760},
+ {0x0000b198, 0x07800781},
+ {0x0000b19c, 0x07a0079f},
+ {0x0000b1a0, 0x07c107bf},
+ {0x0000b1a4, 0x000007c0},
+ {0x0000b1a8, 0x00000000},
+ {0x0000b1ac, 0x00000000},
+ {0x0000b1b0, 0x00000000},
+ {0x0000b1b4, 0x00000000},
+ {0x0000b1b8, 0x00000000},
+ {0x0000b1bc, 0x00000000},
+ {0x0000b1c0, 0x00000000},
+ {0x0000b1c4, 0x00000000},
+ {0x0000b1c8, 0x00000000},
+ {0x0000b1cc, 0x00000000},
+ {0x0000b1d0, 0x00000000},
+ {0x0000b1d4, 0x00000000},
+ {0x0000b1d8, 0x00000000},
+ {0x0000b1dc, 0x00000000},
+ {0x0000b1e0, 0x00000000},
+ {0x0000b1e4, 0x00000000},
+ {0x0000b1e8, 0x00000000},
+ {0x0000b1ec, 0x00000000},
+ {0x0000b1f0, 0x00000396},
+ {0x0000b1f4, 0x00000396},
+ {0x0000b1f8, 0x00000396},
+ {0x0000b1fc, 0x00000196},
+};
+
+static const u32 ar9300_2p2_soc_preamble[][2] = {
+ /* Addr allmodes */
+ {0x000040a4, 0x00a0c1c9},
+ {0x00007008, 0x00000000},
+ {0x00007020, 0x00000000},
+ {0x00007034, 0x00000002},
+ {0x00007038, 0x000004c2},
+ {0x00007048, 0x00000008},
+};
+
+static const u32 ar9300PciePhy_pll_on_clkreq_disable_L1_2p2[][2] = {
+ /* Addr allmodes */
+ {0x00004040, 0x08212e5e},
+ {0x00004040, 0x0008003b},
+ {0x00004044, 0x00000000},
+};
+
+static const u32 ar9300PciePhy_clkreq_enable_L1_2p2[][2] = {
+ /* Addr allmodes */
+ {0x00004040, 0x08253e5e},
+ {0x00004040, 0x0008003b},
+ {0x00004044, 0x00000000},
+};
+
+static const u32 ar9300PciePhy_clkreq_disable_L1_2p2[][2] = {
+ /* Addr allmodes */
+ {0x00004040, 0x08213e5e},
+ {0x00004040, 0x0008003b},
+ {0x00004044, 0x00000000},
+};
+
+#endif /* INITVALS_9003_2P2_H */
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_calib.c b/drivers/net/wireless/ath/ath9k/ar9003_calib.c
index 56a9e5fa6d6..5a065039913 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_calib.c
+++ b/drivers/net/wireless/ath/ath9k/ar9003_calib.c
@@ -739,6 +739,12 @@ static bool ar9003_hw_init_cal(struct ath_hw *ah,
*/
ar9003_hw_set_chain_masks(ah, 0x7, 0x7);
+ /* Do Tx IQ Calibration */
+ ar9003_hw_tx_iq_cal(ah);
+ REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_DIS);
+ udelay(5);
+ REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_EN);
+
/* Calibrate the AGC */
REG_WRITE(ah, AR_PHY_AGC_CONTROL,
REG_READ(ah, AR_PHY_AGC_CONTROL) |
@@ -753,10 +759,6 @@ static bool ar9003_hw_init_cal(struct ath_hw *ah,
return false;
}
- /* Do Tx IQ Calibration */
- if (ah->config.tx_iq_calibration)
- ar9003_hw_tx_iq_cal(ah);
-
/* Revert chainmasks to their original values before NF cal */
ar9003_hw_set_chain_masks(ah, ah->rxchainmask, ah->txchainmask);
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c
index 23eb60ea545..ace8d2678b1 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c
+++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c
@@ -67,6 +67,7 @@ static const struct ar9300_eeprom ar9300_default = {
* bit2 - enable fastClock - enabled
* bit3 - enable doubling - enabled
* bit4 - enable internal regulator - disabled
+ * bit5 - enable pa predistortion - disabled
*/
.miscConfiguration = 0, /* bit0 - turn down drivestrength */
.eepromWriteEnableGpio = 3,
@@ -129,9 +130,11 @@ static const struct ar9300_eeprom ar9300_default = {
.txEndToRxOn = 0x2,
.txFrameToXpaOn = 0xe,
.thresh62 = 28,
- .futureModal = { /* [32] */
+ .papdRateMaskHt20 = LE32(0x80c080),
+ .papdRateMaskHt40 = LE32(0x80c080),
+ .futureModal = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0
},
},
.calFreqPier2G = {
@@ -326,9 +329,11 @@ static const struct ar9300_eeprom ar9300_default = {
.txEndToRxOn = 0x2,
.txFrameToXpaOn = 0xe,
.thresh62 = 28,
+ .papdRateMaskHt20 = LE32(0xf0e0e0),
+ .papdRateMaskHt40 = LE32(0xf0e0e0),
.futureModal = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0
},
},
.calFreqPier5G = {
@@ -644,6 +649,8 @@ static u32 ath9k_hw_ar9300_get_eeprom(struct ath_hw *ah,
return (pBase->featureEnable & 0x10) >> 4;
case EEP_SWREG:
return le32_to_cpu(pBase->swreg);
+ case EEP_PAPRD:
+ return !!(pBase->featureEnable & BIT(5));
default:
return 0;
}
@@ -944,7 +951,7 @@ static u8 ath9k_hw_ar9300_get_num_ant_config(struct ath_hw *ah,
return 1;
}
-static u16 ath9k_hw_ar9300_get_eeprom_antenna_cfg(struct ath_hw *ah,
+static u32 ath9k_hw_ar9300_get_eeprom_antenna_cfg(struct ath_hw *ah,
struct ath9k_channel *chan)
{
return -EINVAL;
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.h b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.h
index 23fb353c3bb..3c533bb983c 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.h
+++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.h
@@ -234,7 +234,9 @@ struct ar9300_modal_eep_header {
u8 txEndToRxOn;
u8 txFrameToXpaOn;
u8 thresh62;
- u8 futureModal[32];
+ __le32 papdRateMaskHt20;
+ __le32 papdRateMaskHt40;
+ u8 futureModal[24];
} __packed;
struct ar9300_cal_data_per_freq_op_loop {
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_hw.c b/drivers/net/wireless/ath/ath9k/ar9003_hw.c
index b15309caf1d..06416890910 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_hw.c
+++ b/drivers/net/wireless/ath/ath9k/ar9003_hw.c
@@ -16,7 +16,8 @@
#include "hw.h"
#include "ar9003_mac.h"
-#include "ar9003_initvals.h"
+#include "ar9003_2p0_initvals.h"
+#include "ar9003_2p2_initvals.h"
/* General hardware code for the AR9003 hadware family */
@@ -31,12 +32,8 @@ static bool ar9003_hw_macversion_supported(u32 macversion)
return false;
}
-/* AR9003 2.0 - new INI format (pre, core, post arrays per subsystem) */
-/*
- * XXX: move TX/RX gain INI to its own init_mode_gain_regs after
- * ensuring it does not affect hardware bring up
- */
-static void ar9003_hw_init_mode_regs(struct ath_hw *ah)
+/* AR9003 2.0 */
+static void ar9003_2p0_hw_init_mode_regs(struct ath_hw *ah)
{
/* mac */
INIT_INI_ARRAY(&ah->iniMac[ATH_INI_PRE], NULL, 0, 0);
@@ -106,27 +103,128 @@ static void ar9003_hw_init_mode_regs(struct ath_hw *ah)
3);
}
+/* AR9003 2.2 */
+static void ar9003_2p2_hw_init_mode_regs(struct ath_hw *ah)
+{
+ /* mac */
+ INIT_INI_ARRAY(&ah->iniMac[ATH_INI_PRE], NULL, 0, 0);
+ INIT_INI_ARRAY(&ah->iniMac[ATH_INI_CORE],
+ ar9300_2p2_mac_core,
+ ARRAY_SIZE(ar9300_2p2_mac_core), 2);
+ INIT_INI_ARRAY(&ah->iniMac[ATH_INI_POST],
+ ar9300_2p2_mac_postamble,
+ ARRAY_SIZE(ar9300_2p2_mac_postamble), 5);
+
+ /* bb */
+ INIT_INI_ARRAY(&ah->iniBB[ATH_INI_PRE], NULL, 0, 0);
+ INIT_INI_ARRAY(&ah->iniBB[ATH_INI_CORE],
+ ar9300_2p2_baseband_core,
+ ARRAY_SIZE(ar9300_2p2_baseband_core), 2);
+ INIT_INI_ARRAY(&ah->iniBB[ATH_INI_POST],
+ ar9300_2p2_baseband_postamble,
+ ARRAY_SIZE(ar9300_2p2_baseband_postamble), 5);
+
+ /* radio */
+ INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_PRE], NULL, 0, 0);
+ INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_CORE],
+ ar9300_2p2_radio_core,
+ ARRAY_SIZE(ar9300_2p2_radio_core), 2);
+ INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_POST],
+ ar9300_2p2_radio_postamble,
+ ARRAY_SIZE(ar9300_2p2_radio_postamble), 5);
+
+ /* soc */
+ INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_PRE],
+ ar9300_2p2_soc_preamble,
+ ARRAY_SIZE(ar9300_2p2_soc_preamble), 2);
+ INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_CORE], NULL, 0, 0);
+ INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_POST],
+ ar9300_2p2_soc_postamble,
+ ARRAY_SIZE(ar9300_2p2_soc_postamble), 5);
+
+ /* rx/tx gain */
+ INIT_INI_ARRAY(&ah->iniModesRxGain,
+ ar9300Common_rx_gain_table_2p2,
+ ARRAY_SIZE(ar9300Common_rx_gain_table_2p2), 2);
+ INIT_INI_ARRAY(&ah->iniModesTxGain,
+ ar9300Modes_lowest_ob_db_tx_gain_table_2p2,
+ ARRAY_SIZE(ar9300Modes_lowest_ob_db_tx_gain_table_2p2),
+ 5);
+
+ /* Load PCIE SERDES settings from INI */
+
+ /* Awake Setting */
+
+ INIT_INI_ARRAY(&ah->iniPcieSerdes,
+ ar9300PciePhy_pll_on_clkreq_disable_L1_2p2,
+ ARRAY_SIZE(ar9300PciePhy_pll_on_clkreq_disable_L1_2p2),
+ 2);
+
+ /* Sleep Setting */
+
+ INIT_INI_ARRAY(&ah->iniPcieSerdesLowPower,
+ ar9300PciePhy_clkreq_enable_L1_2p2,
+ ARRAY_SIZE(ar9300PciePhy_clkreq_enable_L1_2p2),
+ 2);
+
+ /* Fast clock modal settings */
+ INIT_INI_ARRAY(&ah->iniModesAdditional,
+ ar9300Modes_fast_clock_2p2,
+ ARRAY_SIZE(ar9300Modes_fast_clock_2p2),
+ 3);
+}
+
+/*
+ * The AR9003 family uses a new INI format (pre, core, post
+ * arrays per subsystem).
+ */
+static void ar9003_hw_init_mode_regs(struct ath_hw *ah)
+{
+ if (AR_SREV_9300_20(ah))
+ ar9003_2p0_hw_init_mode_regs(ah);
+ else
+ ar9003_2p2_hw_init_mode_regs(ah);
+}
+
static void ar9003_tx_gain_table_apply(struct ath_hw *ah)
{
switch (ar9003_hw_get_tx_gain_idx(ah)) {
case 0:
default:
- INIT_INI_ARRAY(&ah->iniModesTxGain,
- ar9300Modes_lowest_ob_db_tx_gain_table_2p0,
- ARRAY_SIZE(ar9300Modes_lowest_ob_db_tx_gain_table_2p0),
- 5);
+ if (AR_SREV_9300_20(ah))
+ INIT_INI_ARRAY(&ah->iniModesTxGain,
+ ar9300Modes_lowest_ob_db_tx_gain_table_2p0,
+ ARRAY_SIZE(ar9300Modes_lowest_ob_db_tx_gain_table_2p0),
+ 5);
+ else
+ INIT_INI_ARRAY(&ah->iniModesTxGain,
+ ar9300Modes_lowest_ob_db_tx_gain_table_2p2,
+ ARRAY_SIZE(ar9300Modes_lowest_ob_db_tx_gain_table_2p2),
+ 5);
break;
case 1:
- INIT_INI_ARRAY(&ah->iniModesTxGain,
- ar9300Modes_high_ob_db_tx_gain_table_2p0,
- ARRAY_SIZE(ar9300Modes_high_ob_db_tx_gain_table_2p0),
- 5);
+ if (AR_SREV_9300_20(ah))
+ INIT_INI_ARRAY(&ah->iniModesTxGain,
+ ar9300Modes_high_ob_db_tx_gain_table_2p0,
+ ARRAY_SIZE(ar9300Modes_high_ob_db_tx_gain_table_2p0),
+ 5);
+ else
+ INIT_INI_ARRAY(&ah->iniModesTxGain,
+ ar9300Modes_high_ob_db_tx_gain_table_2p2,
+ ARRAY_SIZE(ar9300Modes_high_ob_db_tx_gain_table_2p2),
+ 5);
break;
case 2:
- INIT_INI_ARRAY(&ah->iniModesTxGain,
- ar9300Modes_low_ob_db_tx_gain_table_2p0,
- ARRAY_SIZE(ar9300Modes_low_ob_db_tx_gain_table_2p0),
- 5);
+ if (AR_SREV_9300_20(ah))
+ INIT_INI_ARRAY(&ah->iniModesTxGain,
+ ar9300Modes_low_ob_db_tx_gain_table_2p0,
+ ARRAY_SIZE(ar9300Modes_low_ob_db_tx_gain_table_2p0),
+ 5);
+ else
+ INIT_INI_ARRAY(&ah->iniModesTxGain,
+ ar9300Modes_low_ob_db_tx_gain_table_2p2,
+ ARRAY_SIZE(ar9300Modes_low_ob_db_tx_gain_table_2p2),
+ 5);
break;
}
}
@@ -136,15 +234,28 @@ static void ar9003_rx_gain_table_apply(struct ath_hw *ah)
switch (ar9003_hw_get_rx_gain_idx(ah)) {
case 0:
default:
- INIT_INI_ARRAY(&ah->iniModesRxGain, ar9300Common_rx_gain_table_2p0,
- ARRAY_SIZE(ar9300Common_rx_gain_table_2p0),
- 2);
+ if (AR_SREV_9300_20(ah))
+ INIT_INI_ARRAY(&ah->iniModesRxGain,
+ ar9300Common_rx_gain_table_2p0,
+ ARRAY_SIZE(ar9300Common_rx_gain_table_2p0),
+ 2);
+ else
+ INIT_INI_ARRAY(&ah->iniModesRxGain,
+ ar9300Common_rx_gain_table_2p2,
+ ARRAY_SIZE(ar9300Common_rx_gain_table_2p2),
+ 2);
break;
case 1:
- INIT_INI_ARRAY(&ah->iniModesRxGain,
- ar9300Common_wo_xlna_rx_gain_table_2p0,
- ARRAY_SIZE(ar9300Common_wo_xlna_rx_gain_table_2p0),
- 2);
+ if (AR_SREV_9300_20(ah))
+ INIT_INI_ARRAY(&ah->iniModesRxGain,
+ ar9300Common_wo_xlna_rx_gain_table_2p0,
+ ARRAY_SIZE(ar9300Common_wo_xlna_rx_gain_table_2p0),
+ 2);
+ else
+ INIT_INI_ARRAY(&ah->iniModesRxGain,
+ ar9300Common_wo_xlna_rx_gain_table_2p2,
+ ARRAY_SIZE(ar9300Common_wo_xlna_rx_gain_table_2p2),
+ 2);
break;
}
}
@@ -184,6 +295,26 @@ static void ar9003_hw_configpcipowersave(struct ath_hw *ah,
/* Several PCIe massages to ensure proper behaviour */
if (ah->config.pcie_waen)
REG_WRITE(ah, AR_WA, ah->config.pcie_waen);
+ else
+ REG_WRITE(ah, AR_WA, ah->WARegVal);
+ }
+
+ /*
+ * Configire PCIE after Ini init. SERDES values now come from ini file
+ * This enables PCIe low power mode.
+ */
+ if (ah->config.pcieSerDesWrite) {
+ unsigned int i;
+ struct ar5416IniArray *array;
+
+ array = power_off ? &ah->iniPcieSerdes :
+ &ah->iniPcieSerdesLowPower;
+
+ for (i = 0; i < array->ia_rows; i++) {
+ REG_WRITE(ah,
+ INI_RA(array, i, 0),
+ INI_RA(array, i, 1));
+ }
}
}
@@ -202,4 +333,6 @@ void ar9003_hw_attach_ops(struct ath_hw *ah)
ar9003_hw_attach_phy_ops(ah);
ar9003_hw_attach_calib_ops(ah);
ar9003_hw_attach_mac_ops(ah);
+
+ ath9k_hw_attach_ani_ops_new(ah);
}
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_mac.c b/drivers/net/wireless/ath/ath9k/ar9003_mac.c
index 37ba37481a4..5b995bee70a 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_mac.c
+++ b/drivers/net/wireless/ath/ath9k/ar9003_mac.c
@@ -90,6 +90,8 @@ static bool ar9003_hw_get_isr(struct ath_hw *ah, enum ath9k_int *masked)
MAP_ISR_S2_CST);
mask2 |= ((isr2 & AR_ISR_S2_TSFOOR) >>
MAP_ISR_S2_TSFOOR);
+ mask2 |= ((isr2 & AR_ISR_S2_BB_WATCHDOG) >>
+ MAP_ISR_S2_BB_WATCHDOG);
if (!(pCap->hw_caps & ATH9K_HW_CAP_RAC_SUPPORTED)) {
REG_WRITE(ah, AR_ISR_S2, isr2);
@@ -167,6 +169,9 @@ static bool ar9003_hw_get_isr(struct ath_hw *ah, enum ath9k_int *masked)
(void) REG_READ(ah, AR_ISR);
}
+
+ if (*masked & ATH9K_INT_BB_WATCHDOG)
+ ar9003_hw_bb_watchdog_read(ah);
}
if (sync_cause) {
@@ -465,6 +470,14 @@ static void ar9003_hw_set11n_virtualmorefrag(struct ath_hw *ah, void *ds,
ads->ctl11 &= ~AR_VirtMoreFrag;
}
+void ar9003_hw_set_paprd_txdesc(struct ath_hw *ah, void *ds, u8 chains)
+{
+ struct ar9003_txc *ads = ds;
+
+ ads->ctl12 |= SM(chains, AR_PAPRDChainMask);
+}
+EXPORT_SYMBOL(ar9003_hw_set_paprd_txdesc);
+
void ar9003_hw_attach_mac_ops(struct ath_hw *hw)
{
struct ath_hw_ops *ops = ath9k_hw_ops(hw);
@@ -566,12 +579,39 @@ int ath9k_hw_process_rxdesc_edma(struct ath_hw *ah, struct ath_rx_status *rxs,
rxs->rs_flags |= ATH9K_RX_DECRYPT_BUSY;
if ((rxsp->status11 & AR_RxFrameOK) == 0) {
+ /*
+ * AR_CRCErr will bet set to true if we're on the last
+ * subframe and the AR_PostDelimCRCErr is caught.
+ * In a way this also gives us a guarantee that when
+ * (!(AR_CRCErr) && (AR_PostDelimCRCErr)) we cannot
+ * possibly be reviewing the last subframe. AR_CRCErr
+ * is the CRC of the actual data.
+ */
if (rxsp->status11 & AR_CRCErr) {
rxs->rs_status |= ATH9K_RXERR_CRC;
} else if (rxsp->status11 & AR_PHYErr) {
- rxs->rs_status |= ATH9K_RXERR_PHY;
phyerr = MS(rxsp->status11, AR_PHYErrCode);
- rxs->rs_phyerr = phyerr;
+ /*
+ * If we reach a point here where AR_PostDelimCRCErr is
+ * true it implies we're *not* on the last subframe. In
+ * in that case that we know already that the CRC of
+ * the frame was OK, and MAC would send an ACK for that
+ * subframe, even if we did get a phy error of type
+ * ATH9K_PHYERR_OFDM_RESTART. This is only applicable
+ * to frame that are prior to the last subframe.
+ * The AR_PostDelimCRCErr is the CRC for the MPDU
+ * delimiter, which contains the 4 reserved bits,
+ * the MPDU length (12 bits), and follows the MPDU
+ * delimiter for an A-MPDU subframe (0x4E = 'N' ASCII).
+ */
+ if ((phyerr == ATH9K_PHYERR_OFDM_RESTART) &&
+ (rxsp->status11 & AR_PostDelimCRCErr)) {
+ rxs->rs_phyerr = 0;
+ } else {
+ rxs->rs_status |= ATH9K_RXERR_PHY;
+ rxs->rs_phyerr = phyerr;
+ }
+
} else if (rxsp->status11 & AR_DecryptCRCErr) {
rxs->rs_status |= ATH9K_RXERR_DECRYPT;
} else if (rxsp->status11 & AR_MichaelErr) {
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_mac.h b/drivers/net/wireless/ath/ath9k/ar9003_mac.h
index f17558b1453..9f2cea70a84 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_mac.h
+++ b/drivers/net/wireless/ath/ath9k/ar9003_mac.h
@@ -33,13 +33,14 @@
#define AR_TxDescId_S 16
#define AR_TxPtrChkSum 0x0000ffff
-#define AR_TxTid 0xf0000000
-#define AR_TxTid_S 28
-
#define AR_LowRxChain 0x00004000
#define AR_Not_Sounding 0x20000000
+/* ctl 12 */
+#define AR_PAPRDChainMask 0x00000e00
+#define AR_PAPRDChainMask_S 9
+
#define MAP_ISR_S2_CST 6
#define MAP_ISR_S2_GTT 6
#define MAP_ISR_S2_TIM 3
@@ -47,6 +48,7 @@
#define MAP_ISR_S2_DTIMSYNC 7
#define MAP_ISR_S2_DTIM 7
#define MAP_ISR_S2_TSFOOR 4
+#define MAP_ISR_S2_BB_WATCHDOG 6
#define AR9003TXC_CONST(_ds) ((const struct ar9003_txc *) _ds)
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_paprd.c b/drivers/net/wireless/ath/ath9k/ar9003_paprd.c
new file mode 100644
index 00000000000..49e0c865ce5
--- /dev/null
+++ b/drivers/net/wireless/ath/ath9k/ar9003_paprd.c
@@ -0,0 +1,714 @@
+/*
+ * Copyright (c) 2010 Atheros Communications Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "hw.h"
+#include "ar9003_phy.h"
+
+void ar9003_paprd_enable(struct ath_hw *ah, bool val)
+{
+ REG_RMW_FIELD(ah, AR_PHY_PAPRD_CTRL0_B0,
+ AR_PHY_PAPRD_CTRL0_PAPRD_ENABLE, !!val);
+ REG_RMW_FIELD(ah, AR_PHY_PAPRD_CTRL0_B1,
+ AR_PHY_PAPRD_CTRL0_PAPRD_ENABLE, !!val);
+ REG_RMW_FIELD(ah, AR_PHY_PAPRD_CTRL0_B2,
+ AR_PHY_PAPRD_CTRL0_PAPRD_ENABLE, !!val);
+}
+EXPORT_SYMBOL(ar9003_paprd_enable);
+
+static void ar9003_paprd_setup_single_table(struct ath_hw *ah)
+{
+ struct ar9300_eeprom *eep = &ah->eeprom.ar9300_eep;
+ struct ar9300_modal_eep_header *hdr;
+ const u32 ctrl0[3] = {
+ AR_PHY_PAPRD_CTRL0_B0,
+ AR_PHY_PAPRD_CTRL0_B1,
+ AR_PHY_PAPRD_CTRL0_B2
+ };
+ const u32 ctrl1[3] = {
+ AR_PHY_PAPRD_CTRL1_B0,
+ AR_PHY_PAPRD_CTRL1_B1,
+ AR_PHY_PAPRD_CTRL1_B2
+ };
+ u32 am_mask, ht40_mask;
+ int i;
+
+ if (ah->curchan && IS_CHAN_5GHZ(ah->curchan))
+ hdr = &eep->modalHeader5G;
+ else
+ hdr = &eep->modalHeader2G;
+
+ am_mask = le32_to_cpu(hdr->papdRateMaskHt20);
+ ht40_mask = le32_to_cpu(hdr->papdRateMaskHt40);
+
+ REG_RMW_FIELD(ah, AR_PHY_PAPRD_AM2AM, AR_PHY_PAPRD_AM2AM_MASK, am_mask);
+ REG_RMW_FIELD(ah, AR_PHY_PAPRD_AM2PM, AR_PHY_PAPRD_AM2PM_MASK, am_mask);
+ REG_RMW_FIELD(ah, AR_PHY_PAPRD_HT40, AR_PHY_PAPRD_HT40_MASK, ht40_mask);
+
+ for (i = 0; i < 3; i++) {
+ REG_RMW_FIELD(ah, ctrl0[i],
+ AR_PHY_PAPRD_CTRL0_USE_SINGLE_TABLE_MASK, 1);
+ REG_RMW_FIELD(ah, ctrl1[i],
+ AR_PHY_PAPRD_CTRL1_ADAPTIVE_AM2PM_ENABLE, 1);
+ REG_RMW_FIELD(ah, ctrl1[i],
+ AR_PHY_PAPRD_CTRL1_ADAPTIVE_AM2AM_ENABLE, 1);
+ REG_RMW_FIELD(ah, ctrl1[i],
+ AR_PHY_PAPRD_CTRL1_ADAPTIVE_SCALING_ENA, 0);
+ REG_RMW_FIELD(ah, ctrl1[i],
+ AR_PHY_PAPRD_CTRL1_PA_GAIN_SCALE_FACT_MASK, 181);
+ REG_RMW_FIELD(ah, ctrl1[i],
+ AR_PHY_PAPRD_CTRL1_PAPRD_MAG_SCALE_FACT, 361);
+ REG_RMW_FIELD(ah, ctrl1[i],
+ AR_PHY_PAPRD_CTRL1_ADAPTIVE_SCALING_ENA, 0);
+ REG_RMW_FIELD(ah, ctrl0[i],
+ AR_PHY_PAPRD_CTRL0_PAPRD_MAG_THRSH, 3);
+ }
+
+ ar9003_paprd_enable(ah, false);
+
+ REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL1,
+ AR_PHY_PAPRD_TRAINER_CNTL1_CF_PAPRD_LB_SKIP, 0x30);
+ REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL1,
+ AR_PHY_PAPRD_TRAINER_CNTL1_CF_PAPRD_LB_ENABLE, 1);
+ REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL1,
+ AR_PHY_PAPRD_TRAINER_CNTL1_CF_PAPRD_TX_GAIN_FORCE, 1);
+ REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL1,
+ AR_PHY_PAPRD_TRAINER_CNTL1_CF_PAPRD_RX_BB_GAIN_FORCE, 0);
+ REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL1,
+ AR_PHY_PAPRD_TRAINER_CNTL1_CF_PAPRD_IQCORR_ENABLE, 0);
+ REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL1,
+ AR_PHY_PAPRD_TRAINER_CNTL1_CF_PAPRD_AGC2_SETTLING, 28);
+ REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL1,
+ AR_PHY_PAPRD_TRAINER_CNTL1_CF_CF_PAPRD_TRAIN_ENABLE, 1);
+ REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL2,
+ AR_PHY_PAPRD_TRAINER_CNTL2_CF_PAPRD_INIT_RX_BB_GAIN, 147);
+ REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL3,
+ AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_FINE_CORR_LEN, 4);
+ REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL3,
+ AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_COARSE_CORR_LEN, 4);
+ REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL3,
+ AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_NUM_CORR_STAGES, 7);
+ REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL3,
+ AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_MIN_LOOPBACK_DEL, 1);
+ REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL3,
+ AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_QUICK_DROP, -6);
+ REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL3,
+ AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_ADC_DESIRED_SIZE,
+ -15);
+ REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL3,
+ AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_BBTXMIX_DISABLE, 1);
+ REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL4,
+ AR_PHY_PAPRD_TRAINER_CNTL4_CF_PAPRD_SAFETY_DELTA, 0);
+ REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL4,
+ AR_PHY_PAPRD_TRAINER_CNTL4_CF_PAPRD_MIN_CORR, 400);
+ REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL4,
+ AR_PHY_PAPRD_TRAINER_CNTL4_CF_PAPRD_NUM_TRAIN_SAMPLES,
+ 100);
+ REG_RMW_FIELD(ah, AR_PHY_PAPRD_PRE_POST_SCALE_0_B0,
+ AR_PHY_PAPRD_PRE_POST_SCALING, 261376);
+ REG_RMW_FIELD(ah, AR_PHY_PAPRD_PRE_POST_SCALE_1_B0,
+ AR_PHY_PAPRD_PRE_POST_SCALING, 248079);
+ REG_RMW_FIELD(ah, AR_PHY_PAPRD_PRE_POST_SCALE_2_B0,
+ AR_PHY_PAPRD_PRE_POST_SCALING, 233759);
+ REG_RMW_FIELD(ah, AR_PHY_PAPRD_PRE_POST_SCALE_3_B0,
+ AR_PHY_PAPRD_PRE_POST_SCALING, 220464);
+ REG_RMW_FIELD(ah, AR_PHY_PAPRD_PRE_POST_SCALE_4_B0,
+ AR_PHY_PAPRD_PRE_POST_SCALING, 208194);
+ REG_RMW_FIELD(ah, AR_PHY_PAPRD_PRE_POST_SCALE_5_B0,
+ AR_PHY_PAPRD_PRE_POST_SCALING, 196949);
+ REG_RMW_FIELD(ah, AR_PHY_PAPRD_PRE_POST_SCALE_6_B0,
+ AR_PHY_PAPRD_PRE_POST_SCALING, 185706);
+ REG_RMW_FIELD(ah, AR_PHY_PAPRD_PRE_POST_SCALE_7_B0,
+ AR_PHY_PAPRD_PRE_POST_SCALING, 175487);
+}
+
+static void ar9003_paprd_get_gain_table(struct ath_hw *ah)
+{
+ u32 *entry = ah->paprd_gain_table_entries;
+ u8 *index = ah->paprd_gain_table_index;
+ u32 reg = AR_PHY_TXGAIN_TABLE;
+ int i;
+
+ memset(entry, 0, sizeof(ah->paprd_gain_table_entries));
+ memset(index, 0, sizeof(ah->paprd_gain_table_index));
+
+ for (i = 0; i < 32; i++) {
+ entry[i] = REG_READ(ah, reg);
+ index[i] = (entry[i] >> 24) & 0xff;
+ reg += 4;
+ }
+}
+
+static unsigned int ar9003_get_desired_gain(struct ath_hw *ah, int chain,
+ int target_power)
+{
+ int olpc_gain_delta = 0;
+ int alpha_therm, alpha_volt;
+ int therm_cal_value, volt_cal_value;
+ int therm_value, volt_value;
+ int thermal_gain_corr, voltage_gain_corr;
+ int desired_scale, desired_gain = 0;
+ u32 reg;
+
+ REG_CLR_BIT(ah, AR_PHY_PAPRD_TRAINER_STAT1,
+ AR_PHY_PAPRD_TRAINER_STAT1_PAPRD_TRAIN_DONE);
+ desired_scale = REG_READ_FIELD(ah, AR_PHY_TPC_12,
+ AR_PHY_TPC_12_DESIRED_SCALE_HT40_5);
+ alpha_therm = REG_READ_FIELD(ah, AR_PHY_TPC_19,
+ AR_PHY_TPC_19_ALPHA_THERM);
+ alpha_volt = REG_READ_FIELD(ah, AR_PHY_TPC_19,
+ AR_PHY_TPC_19_ALPHA_VOLT);
+ therm_cal_value = REG_READ_FIELD(ah, AR_PHY_TPC_18,
+ AR_PHY_TPC_18_THERM_CAL_VALUE);
+ volt_cal_value = REG_READ_FIELD(ah, AR_PHY_TPC_18,
+ AR_PHY_TPC_18_VOLT_CAL_VALUE);
+ therm_value = REG_READ_FIELD(ah, AR_PHY_BB_THERM_ADC_4,
+ AR_PHY_BB_THERM_ADC_4_LATEST_THERM_VALUE);
+ volt_value = REG_READ_FIELD(ah, AR_PHY_BB_THERM_ADC_4,
+ AR_PHY_BB_THERM_ADC_4_LATEST_VOLT_VALUE);
+
+ if (chain == 0)
+ reg = AR_PHY_TPC_11_B0;
+ else if (chain == 1)
+ reg = AR_PHY_TPC_11_B1;
+ else
+ reg = AR_PHY_TPC_11_B2;
+
+ olpc_gain_delta = REG_READ_FIELD(ah, reg,
+ AR_PHY_TPC_11_OLPC_GAIN_DELTA);
+
+ if (olpc_gain_delta >= 128)
+ olpc_gain_delta = olpc_gain_delta - 256;
+
+ thermal_gain_corr = (alpha_therm * (therm_value - therm_cal_value) +
+ (256 / 2)) / 256;
+ voltage_gain_corr = (alpha_volt * (volt_value - volt_cal_value) +
+ (128 / 2)) / 128;
+ desired_gain = target_power - olpc_gain_delta - thermal_gain_corr -
+ voltage_gain_corr + desired_scale;
+
+ return desired_gain;
+}
+
+static void ar9003_tx_force_gain(struct ath_hw *ah, unsigned int gain_index)
+{
+ int selected_gain_entry, txbb1dbgain, txbb6dbgain, txmxrgain;
+ int padrvgnA, padrvgnB, padrvgnC, padrvgnD;
+ u32 *gain_table_entries = ah->paprd_gain_table_entries;
+
+ selected_gain_entry = gain_table_entries[gain_index];
+ txbb1dbgain = selected_gain_entry & 0x7;
+ txbb6dbgain = (selected_gain_entry >> 3) & 0x3;
+ txmxrgain = (selected_gain_entry >> 5) & 0xf;
+ padrvgnA = (selected_gain_entry >> 9) & 0xf;
+ padrvgnB = (selected_gain_entry >> 13) & 0xf;
+ padrvgnC = (selected_gain_entry >> 17) & 0xf;
+ padrvgnD = (selected_gain_entry >> 21) & 0x3;
+
+ REG_RMW_FIELD(ah, AR_PHY_TX_FORCED_GAIN,
+ AR_PHY_TX_FORCED_GAIN_FORCED_TXBB1DBGAIN, txbb1dbgain);
+ REG_RMW_FIELD(ah, AR_PHY_TX_FORCED_GAIN,
+ AR_PHY_TX_FORCED_GAIN_FORCED_TXBB6DBGAIN, txbb6dbgain);
+ REG_RMW_FIELD(ah, AR_PHY_TX_FORCED_GAIN,
+ AR_PHY_TX_FORCED_GAIN_FORCED_TXMXRGAIN, txmxrgain);
+ REG_RMW_FIELD(ah, AR_PHY_TX_FORCED_GAIN,
+ AR_PHY_TX_FORCED_GAIN_FORCED_PADRVGNA, padrvgnA);
+ REG_RMW_FIELD(ah, AR_PHY_TX_FORCED_GAIN,
+ AR_PHY_TX_FORCED_GAIN_FORCED_PADRVGNB, padrvgnB);
+ REG_RMW_FIELD(ah, AR_PHY_TX_FORCED_GAIN,
+ AR_PHY_TX_FORCED_GAIN_FORCED_PADRVGNC, padrvgnC);
+ REG_RMW_FIELD(ah, AR_PHY_TX_FORCED_GAIN,
+ AR_PHY_TX_FORCED_GAIN_FORCED_PADRVGND, padrvgnD);
+ REG_RMW_FIELD(ah, AR_PHY_TX_FORCED_GAIN,
+ AR_PHY_TX_FORCED_GAIN_FORCED_ENABLE_PAL, 0);
+ REG_RMW_FIELD(ah, AR_PHY_TX_FORCED_GAIN,
+ AR_PHY_TX_FORCED_GAIN_FORCE_TX_GAIN, 0);
+ REG_RMW_FIELD(ah, AR_PHY_TPC_1, AR_PHY_TPC_1_FORCED_DAC_GAIN, 0);
+ REG_RMW_FIELD(ah, AR_PHY_TPC_1, AR_PHY_TPC_1_FORCE_DAC_GAIN, 0);
+}
+
+static inline int find_expn(int num)
+{
+ return fls(num) - 1;
+}
+
+static inline int find_proper_scale(int expn, int N)
+{
+ return (expn > N) ? expn - 10 : 0;
+}
+
+#define NUM_BIN 23
+
+static bool create_pa_curve(u32 *data_L, u32 *data_U, u32 *pa_table, u16 *gain)
+{
+ unsigned int thresh_accum_cnt;
+ int x_est[NUM_BIN + 1], Y[NUM_BIN + 1], theta[NUM_BIN + 1];
+ int PA_in[NUM_BIN + 1];
+ int B1_tmp[NUM_BIN + 1], B2_tmp[NUM_BIN + 1];
+ unsigned int B1_abs_max, B2_abs_max;
+ int max_index, scale_factor;
+ int y_est[NUM_BIN + 1];
+ int x_est_fxp1_nonlin, x_tilde[NUM_BIN + 1];
+ unsigned int x_tilde_abs;
+ int G_fxp, Y_intercept, order_x_by_y, M, I, L, sum_y_sqr, sum_y_quad;
+ int Q_x, Q_B1, Q_B2, beta_raw, alpha_raw, scale_B;
+ int Q_scale_B, Q_beta, Q_alpha, alpha, beta, order_1, order_2;
+ int order1_5x, order2_3x, order1_5x_rem, order2_3x_rem;
+ int y5, y3, tmp;
+ int theta_low_bin = 0;
+ int i;
+
+ /* disregard any bin that contains <= 16 samples */
+ thresh_accum_cnt = 16;
+ scale_factor = 5;
+ max_index = 0;
+ memset(theta, 0, sizeof(theta));
+ memset(x_est, 0, sizeof(x_est));
+ memset(Y, 0, sizeof(Y));
+ memset(y_est, 0, sizeof(y_est));
+ memset(x_tilde, 0, sizeof(x_tilde));
+
+ for (i = 0; i < NUM_BIN; i++) {
+ s32 accum_cnt, accum_tx, accum_rx, accum_ang;
+
+ /* number of samples */
+ accum_cnt = data_L[i] & 0xffff;
+
+ if (accum_cnt <= thresh_accum_cnt)
+ continue;
+
+ /* sum(tx amplitude) */
+ accum_tx = ((data_L[i] >> 16) & 0xffff) |
+ ((data_U[i] & 0x7ff) << 16);
+
+ /* sum(rx amplitude distance to lower bin edge) */
+ accum_rx = ((data_U[i] >> 11) & 0x1f) |
+ ((data_L[i + 23] & 0xffff) << 5);
+
+ /* sum(angles) */
+ accum_ang = ((data_L[i + 23] >> 16) & 0xffff) |
+ ((data_U[i + 23] & 0x7ff) << 16);
+
+ accum_tx <<= scale_factor;
+ accum_rx <<= scale_factor;
+ x_est[i + 1] = (((accum_tx + accum_cnt) / accum_cnt) + 32) >>
+ scale_factor;
+
+ Y[i + 1] = ((((accum_rx + accum_cnt) / accum_cnt) + 32) >>
+ scale_factor) +
+ (1 << scale_factor) * max_index + 16;
+
+ if (accum_ang >= (1 << 26))
+ accum_ang -= 1 << 27;
+
+ theta[i + 1] = ((accum_ang * (1 << scale_factor)) + accum_cnt) /
+ accum_cnt;
+
+ max_index++;
+ }
+
+ /*
+ * Find average theta of first 5 bin and all of those to same value.
+ * Curve is linear at that range.
+ */
+ for (i = 1; i < 6; i++)
+ theta_low_bin += theta[i];
+
+ theta_low_bin = theta_low_bin / 5;
+ for (i = 1; i < 6; i++)
+ theta[i] = theta_low_bin;
+
+ /* Set values at origin */
+ theta[0] = theta_low_bin;
+ for (i = 0; i <= max_index; i++)
+ theta[i] -= theta_low_bin;
+
+ x_est[0] = 0;
+ Y[0] = 0;
+ scale_factor = 8;
+
+ /* low signal gain */
+ if (x_est[6] == x_est[3])
+ return false;
+
+ G_fxp =
+ (((Y[6] - Y[3]) * 1 << scale_factor) +
+ (x_est[6] - x_est[3])) / (x_est[6] - x_est[3]);
+
+ Y_intercept =
+ (G_fxp * (x_est[0] - x_est[3]) +
+ (1 << scale_factor)) / (1 << scale_factor) + Y[3];
+
+ for (i = 0; i <= max_index; i++)
+ y_est[i] = Y[i] - Y_intercept;
+
+ for (i = 0; i <= 3; i++) {
+ y_est[i] = i * 32;
+
+ /* prevent division by zero */
+ if (G_fxp == 0)
+ return false;
+
+ x_est[i] = ((y_est[i] * 1 << scale_factor) + G_fxp) / G_fxp;
+ }
+
+ x_est_fxp1_nonlin =
+ x_est[max_index] - ((1 << scale_factor) * y_est[max_index] +
+ G_fxp) / G_fxp;
+
+ order_x_by_y =
+ (x_est_fxp1_nonlin + y_est[max_index]) / y_est[max_index];
+
+ if (order_x_by_y == 0)
+ M = 10;
+ else if (order_x_by_y == 1)
+ M = 9;
+ else
+ M = 8;
+
+ I = (max_index > 15) ? 7 : max_index >> 1;
+ L = max_index - I;
+ scale_factor = 8;
+ sum_y_sqr = 0;
+ sum_y_quad = 0;
+ x_tilde_abs = 0;
+
+ for (i = 0; i <= L; i++) {
+ unsigned int y_sqr;
+ unsigned int y_quad;
+ unsigned int tmp_abs;
+
+ /* prevent division by zero */
+ if (y_est[i + I] == 0)
+ return false;
+
+ x_est_fxp1_nonlin =
+ x_est[i + I] - ((1 << scale_factor) * y_est[i + I] +
+ G_fxp) / G_fxp;
+
+ x_tilde[i] =
+ (x_est_fxp1_nonlin * (1 << M) + y_est[i + I]) / y_est[i +
+ I];
+ x_tilde[i] =
+ (x_tilde[i] * (1 << M) + y_est[i + I]) / y_est[i + I];
+ x_tilde[i] =
+ (x_tilde[i] * (1 << M) + y_est[i + I]) / y_est[i + I];
+ y_sqr =
+ (y_est[i + I] * y_est[i + I] +
+ (scale_factor * scale_factor)) / (scale_factor *
+ scale_factor);
+ tmp_abs = abs(x_tilde[i]);
+ if (tmp_abs > x_tilde_abs)
+ x_tilde_abs = tmp_abs;
+
+ y_quad = y_sqr * y_sqr;
+ sum_y_sqr = sum_y_sqr + y_sqr;
+ sum_y_quad = sum_y_quad + y_quad;
+ B1_tmp[i] = y_sqr * (L + 1);
+ B2_tmp[i] = y_sqr;
+ }
+
+ B1_abs_max = 0;
+ B2_abs_max = 0;
+ for (i = 0; i <= L; i++) {
+ int abs_val;
+
+ B1_tmp[i] -= sum_y_sqr;
+ B2_tmp[i] = sum_y_quad - sum_y_sqr * B2_tmp[i];
+
+ abs_val = abs(B1_tmp[i]);
+ if (abs_val > B1_abs_max)
+ B1_abs_max = abs_val;
+
+ abs_val = abs(B2_tmp[i]);
+ if (abs_val > B2_abs_max)
+ B2_abs_max = abs_val;
+ }
+
+ Q_x = find_proper_scale(find_expn(x_tilde_abs), 10);
+ Q_B1 = find_proper_scale(find_expn(B1_abs_max), 10);
+ Q_B2 = find_proper_scale(find_expn(B2_abs_max), 10);
+
+ beta_raw = 0;
+ alpha_raw = 0;
+ for (i = 0; i <= L; i++) {
+ x_tilde[i] = x_tilde[i] / (1 << Q_x);
+ B1_tmp[i] = B1_tmp[i] / (1 << Q_B1);
+ B2_tmp[i] = B2_tmp[i] / (1 << Q_B2);
+ beta_raw = beta_raw + B1_tmp[i] * x_tilde[i];
+ alpha_raw = alpha_raw + B2_tmp[i] * x_tilde[i];
+ }
+
+ scale_B =
+ ((sum_y_quad / scale_factor) * (L + 1) -
+ (sum_y_sqr / scale_factor) * sum_y_sqr) * scale_factor;
+
+ Q_scale_B = find_proper_scale(find_expn(abs(scale_B)), 10);
+ scale_B = scale_B / (1 << Q_scale_B);
+ Q_beta = find_proper_scale(find_expn(abs(beta_raw)), 10);
+ Q_alpha = find_proper_scale(find_expn(abs(alpha_raw)), 10);
+ beta_raw = beta_raw / (1 << Q_beta);
+ alpha_raw = alpha_raw / (1 << Q_alpha);
+ alpha = (alpha_raw << 10) / scale_B;
+ beta = (beta_raw << 10) / scale_B;
+ order_1 = 3 * M - Q_x - Q_B1 - Q_beta + 10 + Q_scale_B;
+ order_2 = 3 * M - Q_x - Q_B2 - Q_alpha + 10 + Q_scale_B;
+ order1_5x = order_1 / 5;
+ order2_3x = order_2 / 3;
+ order1_5x_rem = order_1 - 5 * order1_5x;
+ order2_3x_rem = order_2 - 3 * order2_3x;
+
+ for (i = 0; i < PAPRD_TABLE_SZ; i++) {
+ tmp = i * 32;
+ y5 = ((beta * tmp) >> 6) >> order1_5x;
+ y5 = (y5 * tmp) >> order1_5x;
+ y5 = (y5 * tmp) >> order1_5x;
+ y5 = (y5 * tmp) >> order1_5x;
+ y5 = (y5 * tmp) >> order1_5x;
+ y5 = y5 >> order1_5x_rem;
+ y3 = (alpha * tmp) >> order2_3x;
+ y3 = (y3 * tmp) >> order2_3x;
+ y3 = (y3 * tmp) >> order2_3x;
+ y3 = y3 >> order2_3x_rem;
+ PA_in[i] = y5 + y3 + (256 * tmp) / G_fxp;
+
+ if (i >= 2) {
+ tmp = PA_in[i] - PA_in[i - 1];
+ if (tmp < 0)
+ PA_in[i] =
+ PA_in[i - 1] + (PA_in[i - 1] -
+ PA_in[i - 2]);
+ }
+
+ PA_in[i] = (PA_in[i] < 1400) ? PA_in[i] : 1400;
+ }
+
+ beta_raw = 0;
+ alpha_raw = 0;
+
+ for (i = 0; i <= L; i++) {
+ int theta_tilde =
+ ((theta[i + I] << M) + y_est[i + I]) / y_est[i + I];
+ theta_tilde =
+ ((theta_tilde << M) + y_est[i + I]) / y_est[i + I];
+ theta_tilde =
+ ((theta_tilde << M) + y_est[i + I]) / y_est[i + I];
+ beta_raw = beta_raw + B1_tmp[i] * theta_tilde;
+ alpha_raw = alpha_raw + B2_tmp[i] * theta_tilde;
+ }
+
+ Q_beta = find_proper_scale(find_expn(abs(beta_raw)), 10);
+ Q_alpha = find_proper_scale(find_expn(abs(alpha_raw)), 10);
+ beta_raw = beta_raw / (1 << Q_beta);
+ alpha_raw = alpha_raw / (1 << Q_alpha);
+
+ alpha = (alpha_raw << 10) / scale_B;
+ beta = (beta_raw << 10) / scale_B;
+ order_1 = 3 * M - Q_x - Q_B1 - Q_beta + 10 + Q_scale_B + 5;
+ order_2 = 3 * M - Q_x - Q_B2 - Q_alpha + 10 + Q_scale_B + 5;
+ order1_5x = order_1 / 5;
+ order2_3x = order_2 / 3;
+ order1_5x_rem = order_1 - 5 * order1_5x;
+ order2_3x_rem = order_2 - 3 * order2_3x;
+
+ for (i = 0; i < PAPRD_TABLE_SZ; i++) {
+ int PA_angle;
+
+ /* pa_table[4] is calculated from PA_angle for i=5 */
+ if (i == 4)
+ continue;
+
+ tmp = i * 32;
+ if (beta > 0)
+ y5 = (((beta * tmp - 64) >> 6) -
+ (1 << order1_5x)) / (1 << order1_5x);
+ else
+ y5 = ((((beta * tmp - 64) >> 6) +
+ (1 << order1_5x)) / (1 << order1_5x));
+
+ y5 = (y5 * tmp) / (1 << order1_5x);
+ y5 = (y5 * tmp) / (1 << order1_5x);
+ y5 = (y5 * tmp) / (1 << order1_5x);
+ y5 = (y5 * tmp) / (1 << order1_5x);
+ y5 = y5 / (1 << order1_5x_rem);
+
+ if (beta > 0)
+ y3 = (alpha * tmp -
+ (1 << order2_3x)) / (1 << order2_3x);
+ else
+ y3 = (alpha * tmp +
+ (1 << order2_3x)) / (1 << order2_3x);
+ y3 = (y3 * tmp) / (1 << order2_3x);
+ y3 = (y3 * tmp) / (1 << order2_3x);
+ y3 = y3 / (1 << order2_3x_rem);
+
+ if (i < 4) {
+ PA_angle = 0;
+ } else {
+ PA_angle = y5 + y3;
+ if (PA_angle < -150)
+ PA_angle = -150;
+ else if (PA_angle > 150)
+ PA_angle = 150;
+ }
+
+ pa_table[i] = ((PA_in[i] & 0x7ff) << 11) + (PA_angle & 0x7ff);
+ if (i == 5) {
+ PA_angle = (PA_angle + 2) >> 1;
+ pa_table[i - 1] = ((PA_in[i - 1] & 0x7ff) << 11) +
+ (PA_angle & 0x7ff);
+ }
+ }
+
+ *gain = G_fxp;
+ return true;
+}
+
+void ar9003_paprd_populate_single_table(struct ath_hw *ah,
+ struct ath9k_channel *chan, int chain)
+{
+ u32 *paprd_table_val = chan->pa_table[chain];
+ u32 small_signal_gain = chan->small_signal_gain[chain];
+ u32 training_power;
+ u32 reg = 0;
+ int i;
+
+ training_power =
+ REG_READ_FIELD(ah, AR_PHY_POWERTX_RATE5,
+ AR_PHY_POWERTX_RATE5_POWERTXHT20_0);
+ training_power -= 4;
+
+ if (chain == 0)
+ reg = AR_PHY_PAPRD_MEM_TAB_B0;
+ else if (chain == 1)
+ reg = AR_PHY_PAPRD_MEM_TAB_B1;
+ else if (chain == 2)
+ reg = AR_PHY_PAPRD_MEM_TAB_B2;
+
+ for (i = 0; i < PAPRD_TABLE_SZ; i++) {
+ REG_WRITE(ah, reg, paprd_table_val[i]);
+ reg = reg + 4;
+ }
+
+ if (chain == 0)
+ reg = AR_PHY_PA_GAIN123_B0;
+ else if (chain == 1)
+ reg = AR_PHY_PA_GAIN123_B1;
+ else
+ reg = AR_PHY_PA_GAIN123_B2;
+
+ REG_RMW_FIELD(ah, reg, AR_PHY_PA_GAIN123_PA_GAIN1, small_signal_gain);
+
+ REG_RMW_FIELD(ah, AR_PHY_PAPRD_CTRL1_B0,
+ AR_PHY_PAPRD_CTRL1_PAPRD_POWER_AT_AM2AM_CAL,
+ training_power);
+
+ REG_RMW_FIELD(ah, AR_PHY_PAPRD_CTRL1_B1,
+ AR_PHY_PAPRD_CTRL1_PAPRD_POWER_AT_AM2AM_CAL,
+ training_power);
+
+ REG_RMW_FIELD(ah, AR_PHY_PAPRD_CTRL1_B2,
+ AR_PHY_PAPRD_CTRL1_PAPRD_POWER_AT_AM2AM_CAL,
+ training_power);
+}
+EXPORT_SYMBOL(ar9003_paprd_populate_single_table);
+
+int ar9003_paprd_setup_gain_table(struct ath_hw *ah, int chain)
+{
+
+ unsigned int i, desired_gain, gain_index;
+ unsigned int train_power;
+
+ train_power = REG_READ_FIELD(ah, AR_PHY_POWERTX_RATE5,
+ AR_PHY_POWERTX_RATE5_POWERTXHT20_0);
+
+ train_power = train_power - 4;
+
+ desired_gain = ar9003_get_desired_gain(ah, chain, train_power);
+
+ gain_index = 0;
+ for (i = 0; i < 32; i++) {
+ if (ah->paprd_gain_table_index[i] >= desired_gain)
+ break;
+ gain_index++;
+ }
+
+ ar9003_tx_force_gain(ah, gain_index);
+
+ REG_CLR_BIT(ah, AR_PHY_PAPRD_TRAINER_STAT1,
+ AR_PHY_PAPRD_TRAINER_STAT1_PAPRD_TRAIN_DONE);
+
+ return 0;
+}
+EXPORT_SYMBOL(ar9003_paprd_setup_gain_table);
+
+int ar9003_paprd_create_curve(struct ath_hw *ah, struct ath9k_channel *chan,
+ int chain)
+{
+ u16 *small_signal_gain = &chan->small_signal_gain[chain];
+ u32 *pa_table = chan->pa_table[chain];
+ u32 *data_L, *data_U;
+ int i, status = 0;
+ u32 *buf;
+ u32 reg;
+
+ memset(chan->pa_table[chain], 0, sizeof(chan->pa_table[chain]));
+
+ buf = kmalloc(2 * 48 * sizeof(u32), GFP_ATOMIC);
+ if (!buf)
+ return -ENOMEM;
+
+ data_L = &buf[0];
+ data_U = &buf[48];
+
+ REG_CLR_BIT(ah, AR_PHY_CHAN_INFO_MEMORY,
+ AR_PHY_CHAN_INFO_MEMORY_CHANINFOMEM_S2_READ);
+
+ reg = AR_PHY_CHAN_INFO_TAB_0;
+ for (i = 0; i < 48; i++)
+ data_L[i] = REG_READ(ah, reg + (i << 2));
+
+ REG_SET_BIT(ah, AR_PHY_CHAN_INFO_MEMORY,
+ AR_PHY_CHAN_INFO_MEMORY_CHANINFOMEM_S2_READ);
+
+ for (i = 0; i < 48; i++)
+ data_U[i] = REG_READ(ah, reg + (i << 2));
+
+ if (!create_pa_curve(data_L, data_U, pa_table, small_signal_gain))
+ status = -2;
+
+ REG_CLR_BIT(ah, AR_PHY_PAPRD_TRAINER_STAT1,
+ AR_PHY_PAPRD_TRAINER_STAT1_PAPRD_TRAIN_DONE);
+
+ kfree(buf);
+
+ return status;
+}
+EXPORT_SYMBOL(ar9003_paprd_create_curve);
+
+int ar9003_paprd_init_table(struct ath_hw *ah)
+{
+ ar9003_paprd_setup_single_table(ah);
+ ar9003_paprd_get_gain_table(ah);
+ return 0;
+}
+EXPORT_SYMBOL(ar9003_paprd_init_table);
+
+bool ar9003_paprd_is_done(struct ath_hw *ah)
+{
+ return !!REG_READ_FIELD(ah, AR_PHY_PAPRD_TRAINER_STAT1,
+ AR_PHY_PAPRD_TRAINER_STAT1_PAPRD_TRAIN_DONE);
+}
+EXPORT_SYMBOL(ar9003_paprd_is_done);
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.c b/drivers/net/wireless/ath/ath9k/ar9003_phy.c
index 80431a2f6dc..a753a431bb1 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_phy.c
+++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.c
@@ -17,6 +17,28 @@
#include "hw.h"
#include "ar9003_phy.h"
+static const int firstep_table[] =
+/* level: 0 1 2 3 4 5 6 7 8 */
+ { -4, -2, 0, 2, 4, 6, 8, 10, 12 }; /* lvl 0-8, default 2 */
+
+static const int cycpwrThr1_table[] =
+/* level: 0 1 2 3 4 5 6 7 8 */
+ { -6, -4, -2, 0, 2, 4, 6, 8 }; /* lvl 0-7, default 3 */
+
+/*
+ * register values to turn OFDM weak signal detection OFF
+ */
+static const int m1ThreshLow_off = 127;
+static const int m2ThreshLow_off = 127;
+static const int m1Thresh_off = 127;
+static const int m2Thresh_off = 127;
+static const int m2CountThr_off = 31;
+static const int m2CountThrLow_off = 63;
+static const int m1ThreshLowExt_off = 127;
+static const int m2ThreshLowExt_off = 127;
+static const int m1ThreshExt_off = 127;
+static const int m2ThreshExt_off = 127;
+
/**
* ar9003_hw_set_channel - set channel on single-chip device
* @ah: atheros hardware structure
@@ -94,7 +116,7 @@ static int ar9003_hw_set_channel(struct ath_hw *ah, struct ath9k_channel *chan)
}
/**
- * ar9003_hw_spur_mitigate - convert baseband spur frequency
+ * ar9003_hw_spur_mitigate_mrc_cck - convert baseband spur frequency
* @ah: atheros hardware structure
* @chan:
*
@@ -521,15 +543,6 @@ static void ar9003_hw_prog_ini(struct ath_hw *ah,
u32 val = INI_RA(iniArr, i, column);
REG_WRITE(ah, reg, val);
-
- /*
- * Determine if this is a shift register value, and insert the
- * configured delay if so.
- */
- if (reg >= 0x16000 && reg < 0x17000
- && ah->config.analog_shiftreg)
- udelay(100);
-
DO_DELAY(regWrites);
}
}
@@ -732,71 +745,68 @@ static bool ar9003_hw_ani_control(struct ath_hw *ah,
{
struct ar5416AniState *aniState = ah->curani;
struct ath_common *common = ath9k_hw_common(ah);
+ struct ath9k_channel *chan = ah->curchan;
+ s32 value, value2;
switch (cmd & ah->ani_function) {
- case ATH9K_ANI_NOISE_IMMUNITY_LEVEL:{
- u32 level = param;
-
- if (level >= ARRAY_SIZE(ah->totalSizeDesired)) {
- ath_print(common, ATH_DBG_ANI,
- "level out of range (%u > %u)\n",
- level,
- (unsigned)ARRAY_SIZE(ah->totalSizeDesired));
- return false;
- }
-
- REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ,
- AR_PHY_DESIRED_SZ_TOT_DES,
- ah->totalSizeDesired[level]);
- REG_RMW_FIELD(ah, AR_PHY_AGC,
- AR_PHY_AGC_COARSE_LOW,
- ah->coarse_low[level]);
- REG_RMW_FIELD(ah, AR_PHY_AGC,
- AR_PHY_AGC_COARSE_HIGH,
- ah->coarse_high[level]);
- REG_RMW_FIELD(ah, AR_PHY_FIND_SIG,
- AR_PHY_FIND_SIG_FIRPWR, ah->firpwr[level]);
-
- if (level > aniState->noiseImmunityLevel)
- ah->stats.ast_ani_niup++;
- else if (level < aniState->noiseImmunityLevel)
- ah->stats.ast_ani_nidown++;
- aniState->noiseImmunityLevel = level;
- break;
- }
case ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION:{
- const int m1ThreshLow[] = { 127, 50 };
- const int m2ThreshLow[] = { 127, 40 };
- const int m1Thresh[] = { 127, 0x4d };
- const int m2Thresh[] = { 127, 0x40 };
- const int m2CountThr[] = { 31, 16 };
- const int m2CountThrLow[] = { 63, 48 };
+ /*
+ * on == 1 means ofdm weak signal detection is ON
+ * on == 1 is the default, for less noise immunity
+ *
+ * on == 0 means ofdm weak signal detection is OFF
+ * on == 0 means more noise imm
+ */
u32 on = param ? 1 : 0;
+ /*
+ * make register setting for default
+ * (weak sig detect ON) come from INI file
+ */
+ int m1ThreshLow = on ?
+ aniState->iniDef.m1ThreshLow : m1ThreshLow_off;
+ int m2ThreshLow = on ?
+ aniState->iniDef.m2ThreshLow : m2ThreshLow_off;
+ int m1Thresh = on ?
+ aniState->iniDef.m1Thresh : m1Thresh_off;
+ int m2Thresh = on ?
+ aniState->iniDef.m2Thresh : m2Thresh_off;
+ int m2CountThr = on ?
+ aniState->iniDef.m2CountThr : m2CountThr_off;
+ int m2CountThrLow = on ?
+ aniState->iniDef.m2CountThrLow : m2CountThrLow_off;
+ int m1ThreshLowExt = on ?
+ aniState->iniDef.m1ThreshLowExt : m1ThreshLowExt_off;
+ int m2ThreshLowExt = on ?
+ aniState->iniDef.m2ThreshLowExt : m2ThreshLowExt_off;
+ int m1ThreshExt = on ?
+ aniState->iniDef.m1ThreshExt : m1ThreshExt_off;
+ int m2ThreshExt = on ?
+ aniState->iniDef.m2ThreshExt : m2ThreshExt_off;
REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW,
AR_PHY_SFCORR_LOW_M1_THRESH_LOW,
- m1ThreshLow[on]);
+ m1ThreshLow);
REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW,
AR_PHY_SFCORR_LOW_M2_THRESH_LOW,
- m2ThreshLow[on]);
+ m2ThreshLow);
REG_RMW_FIELD(ah, AR_PHY_SFCORR,
- AR_PHY_SFCORR_M1_THRESH, m1Thresh[on]);
+ AR_PHY_SFCORR_M1_THRESH, m1Thresh);
REG_RMW_FIELD(ah, AR_PHY_SFCORR,
- AR_PHY_SFCORR_M2_THRESH, m2Thresh[on]);
+ AR_PHY_SFCORR_M2_THRESH, m2Thresh);
REG_RMW_FIELD(ah, AR_PHY_SFCORR,
- AR_PHY_SFCORR_M2COUNT_THR, m2CountThr[on]);
+ AR_PHY_SFCORR_M2COUNT_THR, m2CountThr);
REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW,
AR_PHY_SFCORR_LOW_M2COUNT_THR_LOW,
- m2CountThrLow[on]);
+ m2CountThrLow);
REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT,
- AR_PHY_SFCORR_EXT_M1_THRESH_LOW, m1ThreshLow[on]);
+ AR_PHY_SFCORR_EXT_M1_THRESH_LOW, m1ThreshLowExt);
REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT,
- AR_PHY_SFCORR_EXT_M2_THRESH_LOW, m2ThreshLow[on]);
+ AR_PHY_SFCORR_EXT_M2_THRESH_LOW, m2ThreshLowExt);
REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT,
- AR_PHY_SFCORR_EXT_M1_THRESH, m1Thresh[on]);
+ AR_PHY_SFCORR_EXT_M1_THRESH, m1ThreshExt);
REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT,
- AR_PHY_SFCORR_EXT_M2_THRESH, m2Thresh[on]);
+ AR_PHY_SFCORR_EXT_M2_THRESH, m2ThreshExt);
if (on)
REG_SET_BIT(ah, AR_PHY_SFCORR_LOW,
@@ -806,6 +816,12 @@ static bool ar9003_hw_ani_control(struct ath_hw *ah,
AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW);
if (!on != aniState->ofdmWeakSigDetectOff) {
+ ath_print(common, ATH_DBG_ANI,
+ "** ch %d: ofdm weak signal: %s=>%s\n",
+ chan->channel,
+ !aniState->ofdmWeakSigDetectOff ?
+ "on" : "off",
+ on ? "on" : "off");
if (on)
ah->stats.ast_ani_ofdmon++;
else
@@ -814,64 +830,167 @@ static bool ar9003_hw_ani_control(struct ath_hw *ah,
}
break;
}
- case ATH9K_ANI_CCK_WEAK_SIGNAL_THR:{
- const int weakSigThrCck[] = { 8, 6 };
- u32 high = param ? 1 : 0;
-
- REG_RMW_FIELD(ah, AR_PHY_CCK_DETECT,
- AR_PHY_CCK_DETECT_WEAK_SIG_THR_CCK,
- weakSigThrCck[high]);
- if (high != aniState->cckWeakSigThreshold) {
- if (high)
- ah->stats.ast_ani_cckhigh++;
- else
- ah->stats.ast_ani_ccklow++;
- aniState->cckWeakSigThreshold = high;
- }
- break;
- }
case ATH9K_ANI_FIRSTEP_LEVEL:{
- const int firstep[] = { 0, 4, 8 };
u32 level = param;
- if (level >= ARRAY_SIZE(firstep)) {
+ if (level >= ARRAY_SIZE(firstep_table)) {
ath_print(common, ATH_DBG_ANI,
- "level out of range (%u > %u)\n",
+ "ATH9K_ANI_FIRSTEP_LEVEL: level "
+ "out of range (%u > %u)\n",
level,
- (unsigned) ARRAY_SIZE(firstep));
+ (unsigned) ARRAY_SIZE(firstep_table));
return false;
}
+
+ /*
+ * make register setting relative to default
+ * from INI file & cap value
+ */
+ value = firstep_table[level] -
+ firstep_table[ATH9K_ANI_FIRSTEP_LVL_NEW] +
+ aniState->iniDef.firstep;
+ if (value < ATH9K_SIG_FIRSTEP_SETTING_MIN)
+ value = ATH9K_SIG_FIRSTEP_SETTING_MIN;
+ if (value > ATH9K_SIG_FIRSTEP_SETTING_MAX)
+ value = ATH9K_SIG_FIRSTEP_SETTING_MAX;
REG_RMW_FIELD(ah, AR_PHY_FIND_SIG,
AR_PHY_FIND_SIG_FIRSTEP,
- firstep[level]);
- if (level > aniState->firstepLevel)
- ah->stats.ast_ani_stepup++;
- else if (level < aniState->firstepLevel)
- ah->stats.ast_ani_stepdown++;
- aniState->firstepLevel = level;
+ value);
+ /*
+ * we need to set first step low register too
+ * make register setting relative to default
+ * from INI file & cap value
+ */
+ value2 = firstep_table[level] -
+ firstep_table[ATH9K_ANI_FIRSTEP_LVL_NEW] +
+ aniState->iniDef.firstepLow;
+ if (value2 < ATH9K_SIG_FIRSTEP_SETTING_MIN)
+ value2 = ATH9K_SIG_FIRSTEP_SETTING_MIN;
+ if (value2 > ATH9K_SIG_FIRSTEP_SETTING_MAX)
+ value2 = ATH9K_SIG_FIRSTEP_SETTING_MAX;
+
+ REG_RMW_FIELD(ah, AR_PHY_FIND_SIG_LOW,
+ AR_PHY_FIND_SIG_LOW_FIRSTEP_LOW, value2);
+
+ if (level != aniState->firstepLevel) {
+ ath_print(common, ATH_DBG_ANI,
+ "** ch %d: level %d=>%d[def:%d] "
+ "firstep[level]=%d ini=%d\n",
+ chan->channel,
+ aniState->firstepLevel,
+ level,
+ ATH9K_ANI_FIRSTEP_LVL_NEW,
+ value,
+ aniState->iniDef.firstep);
+ ath_print(common, ATH_DBG_ANI,
+ "** ch %d: level %d=>%d[def:%d] "
+ "firstep_low[level]=%d ini=%d\n",
+ chan->channel,
+ aniState->firstepLevel,
+ level,
+ ATH9K_ANI_FIRSTEP_LVL_NEW,
+ value2,
+ aniState->iniDef.firstepLow);
+ if (level > aniState->firstepLevel)
+ ah->stats.ast_ani_stepup++;
+ else if (level < aniState->firstepLevel)
+ ah->stats.ast_ani_stepdown++;
+ aniState->firstepLevel = level;
+ }
break;
}
case ATH9K_ANI_SPUR_IMMUNITY_LEVEL:{
- const int cycpwrThr1[] = { 2, 4, 6, 8, 10, 12, 14, 16 };
u32 level = param;
- if (level >= ARRAY_SIZE(cycpwrThr1)) {
+ if (level >= ARRAY_SIZE(cycpwrThr1_table)) {
ath_print(common, ATH_DBG_ANI,
- "level out of range (%u > %u)\n",
+ "ATH9K_ANI_SPUR_IMMUNITY_LEVEL: level "
+ "out of range (%u > %u)\n",
level,
- (unsigned) ARRAY_SIZE(cycpwrThr1));
+ (unsigned) ARRAY_SIZE(cycpwrThr1_table));
return false;
}
+ /*
+ * make register setting relative to default
+ * from INI file & cap value
+ */
+ value = cycpwrThr1_table[level] -
+ cycpwrThr1_table[ATH9K_ANI_SPUR_IMMUNE_LVL_NEW] +
+ aniState->iniDef.cycpwrThr1;
+ if (value < ATH9K_SIG_SPUR_IMM_SETTING_MIN)
+ value = ATH9K_SIG_SPUR_IMM_SETTING_MIN;
+ if (value > ATH9K_SIG_SPUR_IMM_SETTING_MAX)
+ value = ATH9K_SIG_SPUR_IMM_SETTING_MAX;
REG_RMW_FIELD(ah, AR_PHY_TIMING5,
AR_PHY_TIMING5_CYCPWR_THR1,
- cycpwrThr1[level]);
- if (level > aniState->spurImmunityLevel)
- ah->stats.ast_ani_spurup++;
- else if (level < aniState->spurImmunityLevel)
- ah->stats.ast_ani_spurdown++;
- aniState->spurImmunityLevel = level;
+ value);
+
+ /*
+ * set AR_PHY_EXT_CCA for extension channel
+ * make register setting relative to default
+ * from INI file & cap value
+ */
+ value2 = cycpwrThr1_table[level] -
+ cycpwrThr1_table[ATH9K_ANI_SPUR_IMMUNE_LVL_NEW] +
+ aniState->iniDef.cycpwrThr1Ext;
+ if (value2 < ATH9K_SIG_SPUR_IMM_SETTING_MIN)
+ value2 = ATH9K_SIG_SPUR_IMM_SETTING_MIN;
+ if (value2 > ATH9K_SIG_SPUR_IMM_SETTING_MAX)
+ value2 = ATH9K_SIG_SPUR_IMM_SETTING_MAX;
+ REG_RMW_FIELD(ah, AR_PHY_EXT_CCA,
+ AR_PHY_EXT_CYCPWR_THR1, value2);
+
+ if (level != aniState->spurImmunityLevel) {
+ ath_print(common, ATH_DBG_ANI,
+ "** ch %d: level %d=>%d[def:%d] "
+ "cycpwrThr1[level]=%d ini=%d\n",
+ chan->channel,
+ aniState->spurImmunityLevel,
+ level,
+ ATH9K_ANI_SPUR_IMMUNE_LVL_NEW,
+ value,
+ aniState->iniDef.cycpwrThr1);
+ ath_print(common, ATH_DBG_ANI,
+ "** ch %d: level %d=>%d[def:%d] "
+ "cycpwrThr1Ext[level]=%d ini=%d\n",
+ chan->channel,
+ aniState->spurImmunityLevel,
+ level,
+ ATH9K_ANI_SPUR_IMMUNE_LVL_NEW,
+ value2,
+ aniState->iniDef.cycpwrThr1Ext);
+ if (level > aniState->spurImmunityLevel)
+ ah->stats.ast_ani_spurup++;
+ else if (level < aniState->spurImmunityLevel)
+ ah->stats.ast_ani_spurdown++;
+ aniState->spurImmunityLevel = level;
+ }
break;
}
+ case ATH9K_ANI_MRC_CCK:{
+ /*
+ * is_on == 1 means MRC CCK ON (default, less noise imm)
+ * is_on == 0 means MRC CCK is OFF (more noise imm)
+ */
+ bool is_on = param ? 1 : 0;
+ REG_RMW_FIELD(ah, AR_PHY_MRC_CCK_CTRL,
+ AR_PHY_MRC_CCK_ENABLE, is_on);
+ REG_RMW_FIELD(ah, AR_PHY_MRC_CCK_CTRL,
+ AR_PHY_MRC_CCK_MUX_REG, is_on);
+ if (!is_on != aniState->mrcCCKOff) {
+ ath_print(common, ATH_DBG_ANI,
+ "** ch %d: MRC CCK: %s=>%s\n",
+ chan->channel,
+ !aniState->mrcCCKOff ? "on" : "off",
+ is_on ? "on" : "off");
+ if (is_on)
+ ah->stats.ast_ani_ccklow++;
+ else
+ ah->stats.ast_ani_cckhigh++;
+ aniState->mrcCCKOff = !is_on;
+ }
+ break;
+ }
case ATH9K_ANI_PRESENT:
break;
default:
@@ -880,158 +999,126 @@ static bool ar9003_hw_ani_control(struct ath_hw *ah,
return false;
}
- ath_print(common, ATH_DBG_ANI, "ANI parameters:\n");
ath_print(common, ATH_DBG_ANI,
- "noiseImmunityLevel=%d, spurImmunityLevel=%d, "
- "ofdmWeakSigDetectOff=%d\n",
- aniState->noiseImmunityLevel,
+ "ANI parameters: SI=%d, ofdmWS=%s FS=%d "
+ "MRCcck=%s listenTime=%d CC=%d listen=%d "
+ "ofdmErrs=%d cckErrs=%d\n",
aniState->spurImmunityLevel,
- !aniState->ofdmWeakSigDetectOff);
- ath_print(common, ATH_DBG_ANI,
- "cckWeakSigThreshold=%d, "
- "firstepLevel=%d, listenTime=%d\n",
- aniState->cckWeakSigThreshold,
+ !aniState->ofdmWeakSigDetectOff ? "on" : "off",
aniState->firstepLevel,
- aniState->listenTime);
- ath_print(common, ATH_DBG_ANI,
- "cycleCount=%d, ofdmPhyErrCount=%d, cckPhyErrCount=%d\n\n",
- aniState->cycleCount,
- aniState->ofdmPhyErrCount,
- aniState->cckPhyErrCount);
-
+ !aniState->mrcCCKOff ? "on" : "off",
+ aniState->listenTime,
+ aniState->cycleCount,
+ aniState->listenTime,
+ aniState->ofdmPhyErrCount,
+ aniState->cckPhyErrCount);
return true;
}
-static void ar9003_hw_nf_sanitize_2g(struct ath_hw *ah, s16 *nf)
-{
- struct ath_common *common = ath9k_hw_common(ah);
-
- if (*nf > ah->nf_2g_max) {
- ath_print(common, ATH_DBG_CALIBRATE,
- "2 GHz NF (%d) > MAX (%d), "
- "correcting to MAX",
- *nf, ah->nf_2g_max);
- *nf = ah->nf_2g_max;
- } else if (*nf < ah->nf_2g_min) {
- ath_print(common, ATH_DBG_CALIBRATE,
- "2 GHz NF (%d) < MIN (%d), "
- "correcting to MIN",
- *nf, ah->nf_2g_min);
- *nf = ah->nf_2g_min;
- }
-}
-
-static void ar9003_hw_nf_sanitize_5g(struct ath_hw *ah, s16 *nf)
-{
- struct ath_common *common = ath9k_hw_common(ah);
-
- if (*nf > ah->nf_5g_max) {
- ath_print(common, ATH_DBG_CALIBRATE,
- "5 GHz NF (%d) > MAX (%d), "
- "correcting to MAX",
- *nf, ah->nf_5g_max);
- *nf = ah->nf_5g_max;
- } else if (*nf < ah->nf_5g_min) {
- ath_print(common, ATH_DBG_CALIBRATE,
- "5 GHz NF (%d) < MIN (%d), "
- "correcting to MIN",
- *nf, ah->nf_5g_min);
- *nf = ah->nf_5g_min;
- }
-}
-
-static void ar9003_hw_nf_sanitize(struct ath_hw *ah, s16 *nf)
-{
- if (IS_CHAN_2GHZ(ah->curchan))
- ar9003_hw_nf_sanitize_2g(ah, nf);
- else
- ar9003_hw_nf_sanitize_5g(ah, nf);
-}
-
static void ar9003_hw_do_getnf(struct ath_hw *ah,
int16_t nfarray[NUM_NF_READINGS])
{
- struct ath_common *common = ath9k_hw_common(ah);
int16_t nf;
nf = MS(REG_READ(ah, AR_PHY_CCA_0), AR_PHY_MINCCA_PWR);
- if (nf & 0x100)
- nf = 0 - ((nf ^ 0x1ff) + 1);
- ar9003_hw_nf_sanitize(ah, &nf);
- ath_print(common, ATH_DBG_CALIBRATE,
- "NF calibrated [ctl] [chain 0] is %d\n", nf);
- nfarray[0] = nf;
+ nfarray[0] = sign_extend(nf, 9);
nf = MS(REG_READ(ah, AR_PHY_CCA_1), AR_PHY_CH1_MINCCA_PWR);
- if (nf & 0x100)
- nf = 0 - ((nf ^ 0x1ff) + 1);
- ar9003_hw_nf_sanitize(ah, &nf);
- ath_print(common, ATH_DBG_CALIBRATE,
- "NF calibrated [ctl] [chain 1] is %d\n", nf);
- nfarray[1] = nf;
+ nfarray[1] = sign_extend(nf, 9);
nf = MS(REG_READ(ah, AR_PHY_CCA_2), AR_PHY_CH2_MINCCA_PWR);
- if (nf & 0x100)
- nf = 0 - ((nf ^ 0x1ff) + 1);
- ar9003_hw_nf_sanitize(ah, &nf);
- ath_print(common, ATH_DBG_CALIBRATE,
- "NF calibrated [ctl] [chain 2] is %d\n", nf);
- nfarray[2] = nf;
+ nfarray[2] = sign_extend(nf, 9);
+
+ if (!IS_CHAN_HT40(ah->curchan))
+ return;
nf = MS(REG_READ(ah, AR_PHY_EXT_CCA), AR_PHY_EXT_MINCCA_PWR);
- if (nf & 0x100)
- nf = 0 - ((nf ^ 0x1ff) + 1);
- ar9003_hw_nf_sanitize(ah, &nf);
- ath_print(common, ATH_DBG_CALIBRATE,
- "NF calibrated [ext] [chain 0] is %d\n", nf);
- nfarray[3] = nf;
+ nfarray[3] = sign_extend(nf, 9);
nf = MS(REG_READ(ah, AR_PHY_EXT_CCA_1), AR_PHY_CH1_EXT_MINCCA_PWR);
- if (nf & 0x100)
- nf = 0 - ((nf ^ 0x1ff) + 1);
- ar9003_hw_nf_sanitize(ah, &nf);
- ath_print(common, ATH_DBG_CALIBRATE,
- "NF calibrated [ext] [chain 1] is %d\n", nf);
- nfarray[4] = nf;
+ nfarray[4] = sign_extend(nf, 9);
nf = MS(REG_READ(ah, AR_PHY_EXT_CCA_2), AR_PHY_CH2_EXT_MINCCA_PWR);
- if (nf & 0x100)
- nf = 0 - ((nf ^ 0x1ff) + 1);
- ar9003_hw_nf_sanitize(ah, &nf);
- ath_print(common, ATH_DBG_CALIBRATE,
- "NF calibrated [ext] [chain 2] is %d\n", nf);
- nfarray[5] = nf;
+ nfarray[5] = sign_extend(nf, 9);
}
-void ar9003_hw_set_nf_limits(struct ath_hw *ah)
+static void ar9003_hw_set_nf_limits(struct ath_hw *ah)
{
- ah->nf_2g_max = AR_PHY_CCA_MAX_GOOD_VAL_9300_2GHZ;
- ah->nf_2g_min = AR_PHY_CCA_MIN_GOOD_VAL_9300_2GHZ;
- ah->nf_5g_max = AR_PHY_CCA_MAX_GOOD_VAL_9300_5GHZ;
- ah->nf_5g_min = AR_PHY_CCA_MIN_GOOD_VAL_9300_5GHZ;
+ ah->nf_2g.max = AR_PHY_CCA_MAX_GOOD_VAL_9300_2GHZ;
+ ah->nf_2g.min = AR_PHY_CCA_MIN_GOOD_VAL_9300_2GHZ;
+ ah->nf_2g.nominal = AR_PHY_CCA_NOM_VAL_9300_2GHZ;
+ ah->nf_5g.max = AR_PHY_CCA_MAX_GOOD_VAL_9300_5GHZ;
+ ah->nf_5g.min = AR_PHY_CCA_MIN_GOOD_VAL_9300_5GHZ;
+ ah->nf_5g.nominal = AR_PHY_CCA_NOM_VAL_9300_5GHZ;
}
/*
- * Find out which of the RX chains are enabled
+ * Initialize the ANI register values with default (ini) values.
+ * This routine is called during a (full) hardware reset after
+ * all the registers are initialised from the INI.
*/
-static u32 ar9003_hw_get_rx_chainmask(struct ath_hw *ah)
+static void ar9003_hw_ani_cache_ini_regs(struct ath_hw *ah)
{
- u32 chain = REG_READ(ah, AR_PHY_RX_CHAINMASK);
- /*
- * The bits [2:0] indicate the rx chain mask and are to be
- * interpreted as follows:
- * 00x => Only chain 0 is enabled
- * 01x => Chain 1 and 0 enabled
- * 1xx => Chain 2,1 and 0 enabled
- */
- return chain & 0x7;
+ struct ar5416AniState *aniState;
+ struct ath_common *common = ath9k_hw_common(ah);
+ struct ath9k_channel *chan = ah->curchan;
+ struct ath9k_ani_default *iniDef;
+ int index;
+ u32 val;
+
+ index = ath9k_hw_get_ani_channel_idx(ah, chan);
+ aniState = &ah->ani[index];
+ ah->curani = aniState;
+ iniDef = &aniState->iniDef;
+
+ ath_print(common, ATH_DBG_ANI,
+ "ver %d.%d opmode %u chan %d Mhz/0x%x\n",
+ ah->hw_version.macVersion,
+ ah->hw_version.macRev,
+ ah->opmode,
+ chan->channel,
+ chan->channelFlags);
+
+ val = REG_READ(ah, AR_PHY_SFCORR);
+ iniDef->m1Thresh = MS(val, AR_PHY_SFCORR_M1_THRESH);
+ iniDef->m2Thresh = MS(val, AR_PHY_SFCORR_M2_THRESH);
+ iniDef->m2CountThr = MS(val, AR_PHY_SFCORR_M2COUNT_THR);
+
+ val = REG_READ(ah, AR_PHY_SFCORR_LOW);
+ iniDef->m1ThreshLow = MS(val, AR_PHY_SFCORR_LOW_M1_THRESH_LOW);
+ iniDef->m2ThreshLow = MS(val, AR_PHY_SFCORR_LOW_M2_THRESH_LOW);
+ iniDef->m2CountThrLow = MS(val, AR_PHY_SFCORR_LOW_M2COUNT_THR_LOW);
+
+ val = REG_READ(ah, AR_PHY_SFCORR_EXT);
+ iniDef->m1ThreshExt = MS(val, AR_PHY_SFCORR_EXT_M1_THRESH);
+ iniDef->m2ThreshExt = MS(val, AR_PHY_SFCORR_EXT_M2_THRESH);
+ iniDef->m1ThreshLowExt = MS(val, AR_PHY_SFCORR_EXT_M1_THRESH_LOW);
+ iniDef->m2ThreshLowExt = MS(val, AR_PHY_SFCORR_EXT_M2_THRESH_LOW);
+ iniDef->firstep = REG_READ_FIELD(ah,
+ AR_PHY_FIND_SIG,
+ AR_PHY_FIND_SIG_FIRSTEP);
+ iniDef->firstepLow = REG_READ_FIELD(ah,
+ AR_PHY_FIND_SIG_LOW,
+ AR_PHY_FIND_SIG_LOW_FIRSTEP_LOW);
+ iniDef->cycpwrThr1 = REG_READ_FIELD(ah,
+ AR_PHY_TIMING5,
+ AR_PHY_TIMING5_CYCPWR_THR1);
+ iniDef->cycpwrThr1Ext = REG_READ_FIELD(ah,
+ AR_PHY_EXT_CCA,
+ AR_PHY_EXT_CYCPWR_THR1);
+
+ /* these levels just got reset to defaults by the INI */
+ aniState->spurImmunityLevel = ATH9K_ANI_SPUR_IMMUNE_LVL_NEW;
+ aniState->firstepLevel = ATH9K_ANI_FIRSTEP_LVL_NEW;
+ aniState->ofdmWeakSigDetectOff = !ATH9K_ANI_USE_OFDM_WEAK_SIG;
+ aniState->mrcCCKOff = !ATH9K_ANI_ENABLE_MRC_CCK;
+
+ aniState->cycleCount = 0;
}
-static void ar9003_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan)
+void ar9003_hw_attach_phy_ops(struct ath_hw *ah)
{
- struct ath9k_nfcal_hist *h;
- unsigned i, j;
- int32_t val;
+ struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah);
const u32 ar9300_cca_regs[6] = {
AR_PHY_CCA_0,
AR_PHY_CCA_1,
@@ -1040,95 +1127,143 @@ static void ar9003_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan)
AR_PHY_EXT_CCA_1,
AR_PHY_EXT_CCA_2,
};
- u8 chainmask, rx_chain_status;
- struct ath_common *common = ath9k_hw_common(ah);
- rx_chain_status = ar9003_hw_get_rx_chainmask(ah);
+ priv_ops->rf_set_freq = ar9003_hw_set_channel;
+ priv_ops->spur_mitigate_freq = ar9003_hw_spur_mitigate;
+ priv_ops->compute_pll_control = ar9003_hw_compute_pll_control;
+ priv_ops->set_channel_regs = ar9003_hw_set_channel_regs;
+ priv_ops->init_bb = ar9003_hw_init_bb;
+ priv_ops->process_ini = ar9003_hw_process_ini;
+ priv_ops->set_rfmode = ar9003_hw_set_rfmode;
+ priv_ops->mark_phy_inactive = ar9003_hw_mark_phy_inactive;
+ priv_ops->set_delta_slope = ar9003_hw_set_delta_slope;
+ priv_ops->rfbus_req = ar9003_hw_rfbus_req;
+ priv_ops->rfbus_done = ar9003_hw_rfbus_done;
+ priv_ops->enable_rfkill = ar9003_hw_enable_rfkill;
+ priv_ops->set_diversity = ar9003_hw_set_diversity;
+ priv_ops->ani_control = ar9003_hw_ani_control;
+ priv_ops->do_getnf = ar9003_hw_do_getnf;
+ priv_ops->ani_cache_ini_regs = ar9003_hw_ani_cache_ini_regs;
- chainmask = 0x3F;
- h = ah->nfCalHist;
+ ar9003_hw_set_nf_limits(ah);
+ memcpy(ah->nf_regs, ar9300_cca_regs, sizeof(ah->nf_regs));
+}
- for (i = 0; i < NUM_NF_READINGS; i++) {
- if (chainmask & (1 << i)) {
- val = REG_READ(ah, ar9300_cca_regs[i]);
- val &= 0xFFFFFE00;
- val |= (((u32) (h[i].privNF) << 1) & 0x1ff);
- REG_WRITE(ah, ar9300_cca_regs[i], val);
- }
+void ar9003_hw_bb_watchdog_config(struct ath_hw *ah)
+{
+ struct ath_common *common = ath9k_hw_common(ah);
+ u32 idle_tmo_ms = ah->bb_watchdog_timeout_ms;
+ u32 val, idle_count;
+
+ if (!idle_tmo_ms) {
+ /* disable IRQ, disable chip-reset for BB panic */
+ REG_WRITE(ah, AR_PHY_WATCHDOG_CTL_2,
+ REG_READ(ah, AR_PHY_WATCHDOG_CTL_2) &
+ ~(AR_PHY_WATCHDOG_RST_ENABLE |
+ AR_PHY_WATCHDOG_IRQ_ENABLE));
+
+ /* disable watchdog in non-IDLE mode, disable in IDLE mode */
+ REG_WRITE(ah, AR_PHY_WATCHDOG_CTL_1,
+ REG_READ(ah, AR_PHY_WATCHDOG_CTL_1) &
+ ~(AR_PHY_WATCHDOG_NON_IDLE_ENABLE |
+ AR_PHY_WATCHDOG_IDLE_ENABLE));
+
+ ath_print(common, ATH_DBG_RESET, "Disabled BB Watchdog\n");
+ return;
}
+ /* enable IRQ, disable chip-reset for BB watchdog */
+ val = REG_READ(ah, AR_PHY_WATCHDOG_CTL_2) & AR_PHY_WATCHDOG_CNTL2_MASK;
+ REG_WRITE(ah, AR_PHY_WATCHDOG_CTL_2,
+ (val | AR_PHY_WATCHDOG_IRQ_ENABLE) &
+ ~AR_PHY_WATCHDOG_RST_ENABLE);
+
+ /* bound limit to 10 secs */
+ if (idle_tmo_ms > 10000)
+ idle_tmo_ms = 10000;
+
/*
- * Load software filtered NF value into baseband internal minCCApwr
- * variable.
+ * The time unit for watchdog event is 2^15 44/88MHz cycles.
+ *
+ * For HT20 we have a time unit of 2^15/44 MHz = .74 ms per tick
+ * For HT40 we have a time unit of 2^15/88 MHz = .37 ms per tick
+ *
+ * Given we use fast clock now in 5 GHz, these time units should
+ * be common for both 2 GHz and 5 GHz.
*/
- REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL,
- AR_PHY_AGC_CONTROL_ENABLE_NF);
- REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL,
- AR_PHY_AGC_CONTROL_NO_UPDATE_NF);
- REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NF);
+ idle_count = (100 * idle_tmo_ms) / 74;
+ if (ah->curchan && IS_CHAN_HT40(ah->curchan))
+ idle_count = (100 * idle_tmo_ms) / 37;
/*
- * Wait for load to complete, should be fast, a few 10s of us.
- * The max delay was changed from an original 250us to 10000us
- * since 250us often results in NF load timeout and causes deaf
- * condition during stress testing 12/12/2009
+ * enable watchdog in non-IDLE mode, disable in IDLE mode,
+ * set idle time-out.
*/
- for (j = 0; j < 1000; j++) {
- if ((REG_READ(ah, AR_PHY_AGC_CONTROL) &
- AR_PHY_AGC_CONTROL_NF) == 0)
- break;
- udelay(10);
- }
+ REG_WRITE(ah, AR_PHY_WATCHDOG_CTL_1,
+ AR_PHY_WATCHDOG_NON_IDLE_ENABLE |
+ AR_PHY_WATCHDOG_IDLE_MASK |
+ (AR_PHY_WATCHDOG_NON_IDLE_MASK & (idle_count << 2)));
+
+ ath_print(common, ATH_DBG_RESET,
+ "Enabled BB Watchdog timeout (%u ms)\n",
+ idle_tmo_ms);
+}
+void ar9003_hw_bb_watchdog_read(struct ath_hw *ah)
+{
/*
- * We timed out waiting for the noisefloor to load, probably due to an
- * in-progress rx. Simply return here and allow the load plenty of time
- * to complete before the next calibration interval. We need to avoid
- * trying to load -50 (which happens below) while the previous load is
- * still in progress as this can cause rx deafness. Instead by returning
- * here, the baseband nf cal will just be capped by our present
- * noisefloor until the next calibration timer.
+ * we want to avoid printing in ISR context so we save the
+ * watchdog status to be printed later in bottom half context.
*/
- if (j == 1000) {
- ath_print(common, ATH_DBG_ANY, "Timeout while waiting for nf "
- "to load: AR_PHY_AGC_CONTROL=0x%x\n",
- REG_READ(ah, AR_PHY_AGC_CONTROL));
- return;
- }
+ ah->bb_watchdog_last_status = REG_READ(ah, AR_PHY_WATCHDOG_STATUS);
/*
- * Restore maxCCAPower register parameter again so that we're not capped
- * by the median we just loaded. This will be initial (and max) value
- * of next noise floor calibration the baseband does.
+ * the watchdog timer should reset on status read but to be sure
+ * sure we write 0 to the watchdog status bit.
*/
- for (i = 0; i < NUM_NF_READINGS; i++) {
- if (chainmask & (1 << i)) {
- val = REG_READ(ah, ar9300_cca_regs[i]);
- val &= 0xFFFFFE00;
- val |= (((u32) (-50) << 1) & 0x1ff);
- REG_WRITE(ah, ar9300_cca_regs[i], val);
- }
- }
+ REG_WRITE(ah, AR_PHY_WATCHDOG_STATUS,
+ ah->bb_watchdog_last_status & ~AR_PHY_WATCHDOG_STATUS_CLR);
}
-void ar9003_hw_attach_phy_ops(struct ath_hw *ah)
+void ar9003_hw_bb_watchdog_dbg_info(struct ath_hw *ah)
{
- struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah);
+ struct ath_common *common = ath9k_hw_common(ah);
+ u32 rxc_pcnt = 0, rxf_pcnt = 0, txf_pcnt = 0, status;
- priv_ops->rf_set_freq = ar9003_hw_set_channel;
- priv_ops->spur_mitigate_freq = ar9003_hw_spur_mitigate;
- priv_ops->compute_pll_control = ar9003_hw_compute_pll_control;
- priv_ops->set_channel_regs = ar9003_hw_set_channel_regs;
- priv_ops->init_bb = ar9003_hw_init_bb;
- priv_ops->process_ini = ar9003_hw_process_ini;
- priv_ops->set_rfmode = ar9003_hw_set_rfmode;
- priv_ops->mark_phy_inactive = ar9003_hw_mark_phy_inactive;
- priv_ops->set_delta_slope = ar9003_hw_set_delta_slope;
- priv_ops->rfbus_req = ar9003_hw_rfbus_req;
- priv_ops->rfbus_done = ar9003_hw_rfbus_done;
- priv_ops->enable_rfkill = ar9003_hw_enable_rfkill;
- priv_ops->set_diversity = ar9003_hw_set_diversity;
- priv_ops->ani_control = ar9003_hw_ani_control;
- priv_ops->do_getnf = ar9003_hw_do_getnf;
- priv_ops->loadnf = ar9003_hw_loadnf;
+ if (likely(!(common->debug_mask & ATH_DBG_RESET)))
+ return;
+
+ status = ah->bb_watchdog_last_status;
+ ath_print(common, ATH_DBG_RESET,
+ "\n==== BB update: BB status=0x%08x ====\n", status);
+ ath_print(common, ATH_DBG_RESET,
+ "** BB state: wd=%u det=%u rdar=%u rOFDM=%d "
+ "rCCK=%u tOFDM=%u tCCK=%u agc=%u src=%u **\n",
+ MS(status, AR_PHY_WATCHDOG_INFO),
+ MS(status, AR_PHY_WATCHDOG_DET_HANG),
+ MS(status, AR_PHY_WATCHDOG_RADAR_SM),
+ MS(status, AR_PHY_WATCHDOG_RX_OFDM_SM),
+ MS(status, AR_PHY_WATCHDOG_RX_CCK_SM),
+ MS(status, AR_PHY_WATCHDOG_TX_OFDM_SM),
+ MS(status, AR_PHY_WATCHDOG_TX_CCK_SM),
+ MS(status, AR_PHY_WATCHDOG_AGC_SM),
+ MS(status,AR_PHY_WATCHDOG_SRCH_SM));
+
+ ath_print(common, ATH_DBG_RESET,
+ "** BB WD cntl: cntl1=0x%08x cntl2=0x%08x **\n",
+ REG_READ(ah, AR_PHY_WATCHDOG_CTL_1),
+ REG_READ(ah, AR_PHY_WATCHDOG_CTL_2));
+ ath_print(common, ATH_DBG_RESET,
+ "** BB mode: BB_gen_controls=0x%08x **\n",
+ REG_READ(ah, AR_PHY_GEN_CTRL));
+
+ if (ath9k_hw_GetMibCycleCountsPct(ah, &rxc_pcnt, &rxf_pcnt, &txf_pcnt))
+ ath_print(common, ATH_DBG_RESET,
+ "** BB busy times: rx_clear=%d%%, "
+ "rx_frame=%d%%, tx_frame=%d%% **\n",
+ rxc_pcnt, rxf_pcnt, txf_pcnt);
+
+ ath_print(common, ATH_DBG_RESET,
+ "==== BB update: done ====\n\n");
}
+EXPORT_SYMBOL(ar9003_hw_bb_watchdog_dbg_info);
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.h b/drivers/net/wireless/ath/ath9k/ar9003_phy.h
index f08cc8bda00..3394dfe52b4 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_phy.h
+++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.h
@@ -149,6 +149,8 @@
#define AR_PHY_EXT_CCA_THRESH62_S 16
#define AR_PHY_EXT_MINCCA_PWR 0x01FF0000
#define AR_PHY_EXT_MINCCA_PWR_S 16
+#define AR_PHY_EXT_CYCPWR_THR1 0x0000FE00L
+#define AR_PHY_EXT_CYCPWR_THR1_S 9
#define AR_PHY_TIMING5_CYCPWR_THR1 0x000000FE
#define AR_PHY_TIMING5_CYCPWR_THR1_S 1
#define AR_PHY_TIMING5_CYCPWR_THR1_ENABLE 0x00000001
@@ -283,6 +285,12 @@
#define AR_PHY_CCK_SPUR_MIT_CCK_SPUR_FREQ 0x1ffffe00
#define AR_PHY_CCK_SPUR_MIT_CCK_SPUR_FREQ_S 9
+#define AR_PHY_MRC_CCK_CTRL (AR_AGC_BASE + 0x1d0)
+#define AR_PHY_MRC_CCK_ENABLE 0x00000001
+#define AR_PHY_MRC_CCK_ENABLE_S 0
+#define AR_PHY_MRC_CCK_MUX_REG 0x00000002
+#define AR_PHY_MRC_CCK_MUX_REG_S 1
+
#define AR_PHY_RX_OCGAIN (AR_AGC_BASE + 0x200)
#define AR_PHY_CCA_NOM_VAL_9300_2GHZ -110
@@ -451,7 +459,11 @@
#define AR_PHY_TSTDAC (AR_SM_BASE + 0x168)
#define AR_PHY_CHAN_STATUS (AR_SM_BASE + 0x16c)
-#define AR_PHY_CHAN_INFO_MEMORY (AR_SM_BASE + 0x170)
+
+#define AR_PHY_CHAN_INFO_MEMORY (AR_SM_BASE + 0x170)
+#define AR_PHY_CHAN_INFO_MEMORY_CHANINFOMEM_S2_READ 0x00000008
+#define AR_PHY_CHAN_INFO_MEMORY_CHANINFOMEM_S2_READ_S 3
+
#define AR_PHY_CHNINFO_NOISEPWR (AR_SM_BASE + 0x174)
#define AR_PHY_CHNINFO_GAINDIFF (AR_SM_BASE + 0x178)
#define AR_PHY_CHNINFO_FINETIM (AR_SM_BASE + 0x17c)
@@ -467,30 +479,86 @@
#define AR_PHY_PWRTX_MAX (AR_SM_BASE + 0x1f0)
#define AR_PHY_POWER_TX_SUB (AR_SM_BASE + 0x1f4)
-#define AR_PHY_TPC_4_B0 (AR_SM_BASE + 0x204)
-#define AR_PHY_TPC_5_B0 (AR_SM_BASE + 0x208)
-#define AR_PHY_TPC_6_B0 (AR_SM_BASE + 0x20c)
-#define AR_PHY_TPC_11_B0 (AR_SM_BASE + 0x220)
-#define AR_PHY_TPC_18 (AR_SM_BASE + 0x23c)
-#define AR_PHY_TPC_19 (AR_SM_BASE + 0x240)
+#define AR_PHY_TPC_1 (AR_SM_BASE + 0x1f8)
+#define AR_PHY_TPC_1_FORCED_DAC_GAIN 0x0000003e
+#define AR_PHY_TPC_1_FORCED_DAC_GAIN_S 1
+#define AR_PHY_TPC_1_FORCE_DAC_GAIN 0x00000001
+#define AR_PHY_TPC_1_FORCE_DAC_GAIN_S 0
+
+#define AR_PHY_TPC_4_B0 (AR_SM_BASE + 0x204)
+#define AR_PHY_TPC_5_B0 (AR_SM_BASE + 0x208)
+#define AR_PHY_TPC_6_B0 (AR_SM_BASE + 0x20c)
+
+#define AR_PHY_TPC_11_B0 (AR_SM_BASE + 0x220)
+#define AR_PHY_TPC_11_B1 (AR_SM1_BASE + 0x220)
+#define AR_PHY_TPC_11_B2 (AR_SM2_BASE + 0x220)
+#define AR_PHY_TPC_11_OLPC_GAIN_DELTA 0x00ff0000
+#define AR_PHY_TPC_11_OLPC_GAIN_DELTA_S 16
+
+#define AR_PHY_TPC_12 (AR_SM_BASE + 0x224)
+#define AR_PHY_TPC_12_DESIRED_SCALE_HT40_5 0x3e000000
+#define AR_PHY_TPC_12_DESIRED_SCALE_HT40_5_S 25
+
+#define AR_PHY_TPC_18 (AR_SM_BASE + 0x23c)
+#define AR_PHY_TPC_18_THERM_CAL_VALUE 0x000000ff
+#define AR_PHY_TPC_18_THERM_CAL_VALUE_S 0
+#define AR_PHY_TPC_18_VOLT_CAL_VALUE 0x0000ff00
+#define AR_PHY_TPC_18_VOLT_CAL_VALUE_S 8
+
+#define AR_PHY_TPC_19 (AR_SM_BASE + 0x240)
+#define AR_PHY_TPC_19_ALPHA_VOLT 0x001f0000
+#define AR_PHY_TPC_19_ALPHA_VOLT_S 16
+#define AR_PHY_TPC_19_ALPHA_THERM 0xff
+#define AR_PHY_TPC_19_ALPHA_THERM_S 0
+
+#define AR_PHY_TX_FORCED_GAIN (AR_SM_BASE + 0x258)
+#define AR_PHY_TX_FORCED_GAIN_FORCE_TX_GAIN 0x00000001
+#define AR_PHY_TX_FORCED_GAIN_FORCE_TX_GAIN_S 0
+#define AR_PHY_TX_FORCED_GAIN_FORCED_TXBB1DBGAIN 0x0000000e
+#define AR_PHY_TX_FORCED_GAIN_FORCED_TXBB1DBGAIN_S 1
+#define AR_PHY_TX_FORCED_GAIN_FORCED_TXBB6DBGAIN 0x00000030
+#define AR_PHY_TX_FORCED_GAIN_FORCED_TXBB6DBGAIN_S 4
+#define AR_PHY_TX_FORCED_GAIN_FORCED_TXMXRGAIN 0x000003c0
+#define AR_PHY_TX_FORCED_GAIN_FORCED_TXMXRGAIN_S 6
+#define AR_PHY_TX_FORCED_GAIN_FORCED_PADRVGNA 0x00003c00
+#define AR_PHY_TX_FORCED_GAIN_FORCED_PADRVGNA_S 10
+#define AR_PHY_TX_FORCED_GAIN_FORCED_PADRVGNB 0x0003c000
+#define AR_PHY_TX_FORCED_GAIN_FORCED_PADRVGNB_S 14
+#define AR_PHY_TX_FORCED_GAIN_FORCED_PADRVGNC 0x003c0000
+#define AR_PHY_TX_FORCED_GAIN_FORCED_PADRVGNC_S 18
+#define AR_PHY_TX_FORCED_GAIN_FORCED_PADRVGND 0x00c00000
+#define AR_PHY_TX_FORCED_GAIN_FORCED_PADRVGND_S 22
+#define AR_PHY_TX_FORCED_GAIN_FORCED_ENABLE_PAL 0x01000000
+#define AR_PHY_TX_FORCED_GAIN_FORCED_ENABLE_PAL_S 24
-#define AR_PHY_TX_FORCED_GAIN (AR_SM_BASE + 0x258)
#define AR_PHY_PDADC_TAB_0 (AR_SM_BASE + 0x280)
+#define AR_PHY_TXGAIN_TABLE (AR_SM_BASE + 0x300)
+
#define AR_PHY_TX_IQCAL_CONTROL_1 (AR_SM_BASE + 0x448)
#define AR_PHY_TX_IQCAL_START (AR_SM_BASE + 0x440)
#define AR_PHY_TX_IQCAL_STATUS_B0 (AR_SM_BASE + 0x48c)
#define AR_PHY_TX_IQCAL_CORR_COEFF_01_B0 (AR_SM_BASE + 0x450)
-#define AR_PHY_PANIC_WD_STATUS (AR_SM_BASE + 0x5c0)
-#define AR_PHY_PANIC_WD_CTL_1 (AR_SM_BASE + 0x5c4)
-#define AR_PHY_PANIC_WD_CTL_2 (AR_SM_BASE + 0x5c8)
-#define AR_PHY_BT_CTL (AR_SM_BASE + 0x5cc)
+#define AR_PHY_WATCHDOG_STATUS (AR_SM_BASE + 0x5c0)
+#define AR_PHY_WATCHDOG_CTL_1 (AR_SM_BASE + 0x5c4)
+#define AR_PHY_WATCHDOG_CTL_2 (AR_SM_BASE + 0x5c8)
+#define AR_PHY_WATCHDOG_CTL (AR_SM_BASE + 0x5cc)
#define AR_PHY_ONLY_WARMRESET (AR_SM_BASE + 0x5d0)
#define AR_PHY_ONLY_CTL (AR_SM_BASE + 0x5d4)
#define AR_PHY_ECO_CTRL (AR_SM_BASE + 0x5dc)
-#define AR_PHY_BB_THERM_ADC_1 (AR_SM_BASE + 0x248)
+
+#define AR_PHY_BB_THERM_ADC_1 (AR_SM_BASE + 0x248)
+#define AR_PHY_BB_THERM_ADC_1_INIT_THERM 0x000000ff
+#define AR_PHY_BB_THERM_ADC_1_INIT_THERM_S 0
+
+#define AR_PHY_BB_THERM_ADC_4 (AR_SM_BASE + 0x254)
+#define AR_PHY_BB_THERM_ADC_4_LATEST_THERM_VALUE 0x000000ff
+#define AR_PHY_BB_THERM_ADC_4_LATEST_THERM_VALUE_S 0
+#define AR_PHY_BB_THERM_ADC_4_LATEST_VOLT_VALUE 0x0000ff00
+#define AR_PHY_BB_THERM_ADC_4_LATEST_VOLT_VALUE_S 8
+
#define AR_PHY_65NM_CH0_SYNTH4 0x1608c
#define AR_PHY_SYNTH4_LONG_SHIFT_SELECT 0x00000002
@@ -660,17 +728,9 @@
#define AR_PHY_TX_IQCAL_CORR_COEFF_01_COEFF_TABLE 0x00003fff
#define AR_PHY_TX_IQCAL_CORR_COEFF_01_COEFF_TABLE_S 0
-#define AR_PHY_TPC_18_THERM_CAL_VALUE 0xff
-#define AR_PHY_TPC_18_THERM_CAL_VALUE_S 0
-#define AR_PHY_TPC_19_ALPHA_THERM 0xff
-#define AR_PHY_TPC_19_ALPHA_THERM_S 0
-
#define AR_PHY_65NM_CH0_RXTX4_THERM_ON 0x10000000
#define AR_PHY_65NM_CH0_RXTX4_THERM_ON_S 28
-#define AR_PHY_BB_THERM_ADC_1_INIT_THERM 0x000000ff
-#define AR_PHY_BB_THERM_ADC_1_INIT_THERM_S 0
-
/*
* Channel 1 Register Map
*/
@@ -812,35 +872,173 @@
#define AR_PHY_CAL_MEAS_2_9300_10(_i) (AR_PHY_IQ_ADC_MEAS_2_B0_9300_10 + (AR_PHY_CHAIN_OFFSET * (_i)))
#define AR_PHY_CAL_MEAS_3_9300_10(_i) (AR_PHY_IQ_ADC_MEAS_3_B0_9300_10 + (AR_PHY_CHAIN_OFFSET * (_i)))
-#define AR_PHY_BB_PANIC_NON_IDLE_ENABLE 0x00000001
-#define AR_PHY_BB_PANIC_IDLE_ENABLE 0x00000002
-#define AR_PHY_BB_PANIC_IDLE_MASK 0xFFFF0000
-#define AR_PHY_BB_PANIC_NON_IDLE_MASK 0x0000FFFC
-
-#define AR_PHY_BB_PANIC_RST_ENABLE 0x00000002
-#define AR_PHY_BB_PANIC_IRQ_ENABLE 0x00000004
-#define AR_PHY_BB_PANIC_CNTL2_MASK 0xFFFFFFF9
-
-#define AR_PHY_BB_WD_STATUS 0x00000007
-#define AR_PHY_BB_WD_STATUS_S 0
-#define AR_PHY_BB_WD_DET_HANG 0x00000008
-#define AR_PHY_BB_WD_DET_HANG_S 3
-#define AR_PHY_BB_WD_RADAR_SM 0x000000F0
-#define AR_PHY_BB_WD_RADAR_SM_S 4
-#define AR_PHY_BB_WD_RX_OFDM_SM 0x00000F00
-#define AR_PHY_BB_WD_RX_OFDM_SM_S 8
-#define AR_PHY_BB_WD_RX_CCK_SM 0x0000F000
-#define AR_PHY_BB_WD_RX_CCK_SM_S 12
-#define AR_PHY_BB_WD_TX_OFDM_SM 0x000F0000
-#define AR_PHY_BB_WD_TX_OFDM_SM_S 16
-#define AR_PHY_BB_WD_TX_CCK_SM 0x00F00000
-#define AR_PHY_BB_WD_TX_CCK_SM_S 20
-#define AR_PHY_BB_WD_AGC_SM 0x0F000000
-#define AR_PHY_BB_WD_AGC_SM_S 24
-#define AR_PHY_BB_WD_SRCH_SM 0xF0000000
-#define AR_PHY_BB_WD_SRCH_SM_S 28
-
-#define AR_PHY_BB_WD_STATUS_CLR 0x00000008
+#define AR_PHY_WATCHDOG_NON_IDLE_ENABLE 0x00000001
+#define AR_PHY_WATCHDOG_IDLE_ENABLE 0x00000002
+#define AR_PHY_WATCHDOG_IDLE_MASK 0xFFFF0000
+#define AR_PHY_WATCHDOG_NON_IDLE_MASK 0x0000FFFC
+
+#define AR_PHY_WATCHDOG_RST_ENABLE 0x00000002
+#define AR_PHY_WATCHDOG_IRQ_ENABLE 0x00000004
+#define AR_PHY_WATCHDOG_CNTL2_MASK 0xFFFFFFF9
+
+#define AR_PHY_WATCHDOG_INFO 0x00000007
+#define AR_PHY_WATCHDOG_INFO_S 0
+#define AR_PHY_WATCHDOG_DET_HANG 0x00000008
+#define AR_PHY_WATCHDOG_DET_HANG_S 3
+#define AR_PHY_WATCHDOG_RADAR_SM 0x000000F0
+#define AR_PHY_WATCHDOG_RADAR_SM_S 4
+#define AR_PHY_WATCHDOG_RX_OFDM_SM 0x00000F00
+#define AR_PHY_WATCHDOG_RX_OFDM_SM_S 8
+#define AR_PHY_WATCHDOG_RX_CCK_SM 0x0000F000
+#define AR_PHY_WATCHDOG_RX_CCK_SM_S 12
+#define AR_PHY_WATCHDOG_TX_OFDM_SM 0x000F0000
+#define AR_PHY_WATCHDOG_TX_OFDM_SM_S 16
+#define AR_PHY_WATCHDOG_TX_CCK_SM 0x00F00000
+#define AR_PHY_WATCHDOG_TX_CCK_SM_S 20
+#define AR_PHY_WATCHDOG_AGC_SM 0x0F000000
+#define AR_PHY_WATCHDOG_AGC_SM_S 24
+#define AR_PHY_WATCHDOG_SRCH_SM 0xF0000000
+#define AR_PHY_WATCHDOG_SRCH_SM_S 28
+
+#define AR_PHY_WATCHDOG_STATUS_CLR 0x00000008
+
+/*
+ * PAPRD registers
+ */
+#define AR_PHY_XPA_TIMING_CTL (AR_SM_BASE + 0x64)
+
+#define AR_PHY_PAPRD_AM2AM (AR_CHAN_BASE + 0xe4)
+#define AR_PHY_PAPRD_AM2AM_MASK 0x01ffffff
+#define AR_PHY_PAPRD_AM2AM_MASK_S 0
+
+#define AR_PHY_PAPRD_AM2PM (AR_CHAN_BASE + 0xe8)
+#define AR_PHY_PAPRD_AM2PM_MASK 0x01ffffff
+#define AR_PHY_PAPRD_AM2PM_MASK_S 0
+
+#define AR_PHY_PAPRD_HT40 (AR_CHAN_BASE + 0xec)
+#define AR_PHY_PAPRD_HT40_MASK 0x01ffffff
+#define AR_PHY_PAPRD_HT40_MASK_S 0
+
+#define AR_PHY_PAPRD_CTRL0_B0 (AR_CHAN_BASE + 0xf0)
+#define AR_PHY_PAPRD_CTRL0_B1 (AR_CHAN1_BASE + 0xf0)
+#define AR_PHY_PAPRD_CTRL0_B2 (AR_CHAN2_BASE + 0xf0)
+#define AR_PHY_PAPRD_CTRL0_PAPRD_ENABLE 0x00000001
+#define AR_PHY_PAPRD_CTRL0_PAPRD_ENABLE_S 0
+#define AR_PHY_PAPRD_CTRL0_USE_SINGLE_TABLE_MASK 0x00000002
+#define AR_PHY_PAPRD_CTRL0_USE_SINGLE_TABLE_MASK_S 1
+#define AR_PHY_PAPRD_CTRL0_PAPRD_MAG_THRSH 0xf8000000
+#define AR_PHY_PAPRD_CTRL0_PAPRD_MAG_THRSH_S 27
+
+#define AR_PHY_PAPRD_CTRL1_B0 (AR_CHAN_BASE + 0xf4)
+#define AR_PHY_PAPRD_CTRL1_B1 (AR_CHAN1_BASE + 0xf4)
+#define AR_PHY_PAPRD_CTRL1_B2 (AR_CHAN2_BASE + 0xf4)
+#define AR_PHY_PAPRD_CTRL1_ADAPTIVE_SCALING_ENA 0x00000001
+#define AR_PHY_PAPRD_CTRL1_ADAPTIVE_SCALING_ENA_S 0
+#define AR_PHY_PAPRD_CTRL1_ADAPTIVE_AM2AM_ENABLE 0x00000002
+#define AR_PHY_PAPRD_CTRL1_ADAPTIVE_AM2AM_ENABLE_S 1
+#define AR_PHY_PAPRD_CTRL1_ADAPTIVE_AM2PM_ENABLE 0x00000004
+#define AR_PHY_PAPRD_CTRL1_ADAPTIVE_AM2PM_ENABLE_S 2
+#define AR_PHY_PAPRD_CTRL1_PAPRD_POWER_AT_AM2AM_CAL 0x000001f8
+#define AR_PHY_PAPRD_CTRL1_PAPRD_POWER_AT_AM2AM_CAL_S 3
+#define AR_PHY_PAPRD_CTRL1_PA_GAIN_SCALE_FACT_MASK 0x0001fe00
+#define AR_PHY_PAPRD_CTRL1_PA_GAIN_SCALE_FACT_MASK_S 9
+#define AR_PHY_PAPRD_CTRL1_PAPRD_MAG_SCALE_FACT 0x0ffe0000
+#define AR_PHY_PAPRD_CTRL1_PAPRD_MAG_SCALE_FACT_S 17
+
+#define AR_PHY_PAPRD_TRAINER_CNTL1 (AR_SM_BASE + 0x490)
+#define AR_PHY_PAPRD_TRAINER_CNTL1_CF_CF_PAPRD_TRAIN_ENABLE 0x00000001
+#define AR_PHY_PAPRD_TRAINER_CNTL1_CF_CF_PAPRD_TRAIN_ENABLE_S 0
+#define AR_PHY_PAPRD_TRAINER_CNTL1_CF_PAPRD_AGC2_SETTLING 0x0000007e
+#define AR_PHY_PAPRD_TRAINER_CNTL1_CF_PAPRD_AGC2_SETTLING_S 1
+#define AR_PHY_PAPRD_TRAINER_CNTL1_CF_PAPRD_IQCORR_ENABLE 0x00000100
+#define AR_PHY_PAPRD_TRAINER_CNTL1_CF_PAPRD_IQCORR_ENABLE_S 8
+#define AR_PHY_PAPRD_TRAINER_CNTL1_CF_PAPRD_RX_BB_GAIN_FORCE 0x00000200
+#define AR_PHY_PAPRD_TRAINER_CNTL1_CF_PAPRD_RX_BB_GAIN_FORCE_S 9
+#define AR_PHY_PAPRD_TRAINER_CNTL1_CF_PAPRD_TX_GAIN_FORCE 0x00000400
+#define AR_PHY_PAPRD_TRAINER_CNTL1_CF_PAPRD_TX_GAIN_FORCE_S 10
+#define AR_PHY_PAPRD_TRAINER_CNTL1_CF_PAPRD_LB_ENABLE 0x00000800
+#define AR_PHY_PAPRD_TRAINER_CNTL1_CF_PAPRD_LB_ENABLE_S 11
+#define AR_PHY_PAPRD_TRAINER_CNTL1_CF_PAPRD_LB_SKIP 0x0003f000
+#define AR_PHY_PAPRD_TRAINER_CNTL1_CF_PAPRD_LB_SKIP_S 12
+
+#define AR_PHY_PAPRD_TRAINER_CNTL2 (AR_SM_BASE + 0x494)
+#define AR_PHY_PAPRD_TRAINER_CNTL2_CF_PAPRD_INIT_RX_BB_GAIN 0xFFFFFFFF
+#define AR_PHY_PAPRD_TRAINER_CNTL2_CF_PAPRD_INIT_RX_BB_GAIN_S 0
+
+#define AR_PHY_PAPRD_TRAINER_CNTL3 (AR_SM_BASE + 0x498)
+#define AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_ADC_DESIRED_SIZE 0x0000003f
+#define AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_ADC_DESIRED_SIZE_S 0
+#define AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_QUICK_DROP 0x00000fc0
+#define AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_QUICK_DROP_S 6
+#define AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_MIN_LOOPBACK_DEL 0x0001f000
+#define AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_MIN_LOOPBACK_DEL_S 12
+#define AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_NUM_CORR_STAGES 0x000e0000
+#define AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_NUM_CORR_STAGES_S 17
+#define AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_COARSE_CORR_LEN 0x00f00000
+#define AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_COARSE_CORR_LEN_S 20
+#define AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_FINE_CORR_LEN 0x0f000000
+#define AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_FINE_CORR_LEN_S 24
+#define AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_BBTXMIX_DISABLE 0x20000000
+#define AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_BBTXMIX_DISABLE_S 29
+
+#define AR_PHY_PAPRD_TRAINER_CNTL4 (AR_SM_BASE + 0x49c)
+#define AR_PHY_PAPRD_TRAINER_CNTL4_CF_PAPRD_NUM_TRAIN_SAMPLES 0x03ff0000
+#define AR_PHY_PAPRD_TRAINER_CNTL4_CF_PAPRD_NUM_TRAIN_SAMPLES_S 16
+#define AR_PHY_PAPRD_TRAINER_CNTL4_CF_PAPRD_SAFETY_DELTA 0x0000f000
+#define AR_PHY_PAPRD_TRAINER_CNTL4_CF_PAPRD_SAFETY_DELTA_S 12
+#define AR_PHY_PAPRD_TRAINER_CNTL4_CF_PAPRD_MIN_CORR 0x00000fff
+#define AR_PHY_PAPRD_TRAINER_CNTL4_CF_PAPRD_MIN_CORR_S 0
+
+#define AR_PHY_PAPRD_PRE_POST_SCALE_0_B0 (AR_CHAN_BASE + 0x100)
+#define AR_PHY_PAPRD_PRE_POST_SCALE_1_B0 (AR_CHAN_BASE + 0x104)
+#define AR_PHY_PAPRD_PRE_POST_SCALE_2_B0 (AR_CHAN_BASE + 0x108)
+#define AR_PHY_PAPRD_PRE_POST_SCALE_3_B0 (AR_CHAN_BASE + 0x10c)
+#define AR_PHY_PAPRD_PRE_POST_SCALE_4_B0 (AR_CHAN_BASE + 0x110)
+#define AR_PHY_PAPRD_PRE_POST_SCALE_5_B0 (AR_CHAN_BASE + 0x114)
+#define AR_PHY_PAPRD_PRE_POST_SCALE_6_B0 (AR_CHAN_BASE + 0x118)
+#define AR_PHY_PAPRD_PRE_POST_SCALE_7_B0 (AR_CHAN_BASE + 0x11c)
+#define AR_PHY_PAPRD_PRE_POST_SCALING 0x3FFFF
+#define AR_PHY_PAPRD_PRE_POST_SCALING_S 0
+
+#define AR_PHY_PAPRD_TRAINER_STAT1 (AR_SM_BASE + 0x4a0)
+#define AR_PHY_PAPRD_TRAINER_STAT1_PAPRD_TRAIN_DONE 0x00000001
+#define AR_PHY_PAPRD_TRAINER_STAT1_PAPRD_TRAIN_DONE_S 0
+#define AR_PHY_PAPRD_TRAINER_STAT1_PAPRD_TRAIN_INCOMPLETE 0x00000002
+#define AR_PHY_PAPRD_TRAINER_STAT1_PAPRD_TRAIN_INCOMPLETE_S 1
+#define AR_PHY_PAPRD_TRAINER_STAT1_PAPRD_CORR_ERR 0x00000004
+#define AR_PHY_PAPRD_TRAINER_STAT1_PAPRD_CORR_ERR_S 2
+#define AR_PHY_PAPRD_TRAINER_STAT1_PAPRD_TRAIN_ACTIVE 0x00000008
+#define AR_PHY_PAPRD_TRAINER_STAT1_PAPRD_TRAIN_ACTIVE_S 3
+#define AR_PHY_PAPRD_TRAINER_STAT1_PAPRD_RX_GAIN_IDX 0x000001f0
+#define AR_PHY_PAPRD_TRAINER_STAT1_PAPRD_RX_GAIN_IDX_S 4
+#define AR_PHY_PAPRD_TRAINER_STAT1_PAPRD_AGC2_PWR 0x0001fe00
+#define AR_PHY_PAPRD_TRAINER_STAT1_PAPRD_AGC2_PWR_S 9
+
+#define AR_PHY_PAPRD_TRAINER_STAT2 (AR_SM_BASE + 0x4a4)
+#define AR_PHY_PAPRD_TRAINER_STAT2_PAPRD_FINE_VAL 0x0000ffff
+#define AR_PHY_PAPRD_TRAINER_STAT2_PAPRD_FINE_VAL_S 0
+#define AR_PHY_PAPRD_TRAINER_STAT2_PAPRD_COARSE_IDX 0x001f0000
+#define AR_PHY_PAPRD_TRAINER_STAT2_PAPRD_COARSE_IDX_S 16
+#define AR_PHY_PAPRD_TRAINER_STAT2_PAPRD_FINE_IDX 0x00600000
+#define AR_PHY_PAPRD_TRAINER_STAT2_PAPRD_FINE_IDX_S 21
+
+#define AR_PHY_PAPRD_TRAINER_STAT3 (AR_SM_BASE + 0x4a8)
+#define AR_PHY_PAPRD_TRAINER_STAT3_PAPRD_TRAIN_SAMPLES_CNT 0x000fffff
+#define AR_PHY_PAPRD_TRAINER_STAT3_PAPRD_TRAIN_SAMPLES_CNT_S 0
+
+#define AR_PHY_PAPRD_MEM_TAB_B0 (AR_CHAN_BASE + 0x120)
+#define AR_PHY_PAPRD_MEM_TAB_B1 (AR_CHAN1_BASE + 0x120)
+#define AR_PHY_PAPRD_MEM_TAB_B2 (AR_CHAN2_BASE + 0x120)
+
+#define AR_PHY_PA_GAIN123_B0 (AR_CHAN_BASE + 0xf8)
+#define AR_PHY_PA_GAIN123_B1 (AR_CHAN1_BASE + 0xf8)
+#define AR_PHY_PA_GAIN123_B2 (AR_CHAN2_BASE + 0xf8)
+#define AR_PHY_PA_GAIN123_PA_GAIN1 0x3FF
+#define AR_PHY_PA_GAIN123_PA_GAIN1_S 0
+
+#define AR_PHY_POWERTX_RATE5 (AR_SM_BASE + 0x1d0)
+#define AR_PHY_POWERTX_RATE5_POWERTXHT20_0 0x3F
+#define AR_PHY_POWERTX_RATE5_POWERTXHT20_0_S 0
void ar9003_hw_set_chain_masks(struct ath_hw *ah, u8 rx, u8 tx);
diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h
index 5ea87736a6a..998ae2c49ed 100644
--- a/drivers/net/wireless/ath/ath9k/ath9k.h
+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
@@ -20,6 +20,7 @@
#include <linux/etherdevice.h>
#include <linux/device.h>
#include <linux/leds.h>
+#include <linux/completion.h>
#include "debug.h"
#include "common.h"
@@ -136,6 +137,8 @@ void ath_descdma_cleanup(struct ath_softc *sc, struct ath_descdma *dd,
#define ATH_MAX_ANTENNA 3
#define ATH_RXBUF 512
#define ATH_TXBUF 512
+#define ATH_TXBUF_RESERVE 5
+#define ATH_MAX_QDEPTH (ATH_TXBUF / 4 - ATH_TXBUF_RESERVE)
#define ATH_TXMAXTRY 13
#define ATH_MGT_TXMAXTRY 4
@@ -192,6 +195,7 @@ enum ATH_AGGR_STATUS {
#define ATH_TXFIFO_DEPTH 8
struct ath_txq {
+ int axq_class;
u32 axq_qnum;
u32 *axq_link;
struct list_head axq_q;
@@ -206,6 +210,71 @@ struct ath_txq {
u8 txq_tailidx;
};
+struct ath_atx_ac {
+ int sched;
+ int qnum;
+ struct list_head list;
+ struct list_head tid_q;
+};
+
+struct ath_buf_state {
+ int bfs_nframes;
+ u16 bfs_al;
+ u16 bfs_frmlen;
+ int bfs_seqno;
+ int bfs_tidno;
+ int bfs_retries;
+ u8 bf_type;
+ u8 bfs_paprd;
+ unsigned long bfs_paprd_timestamp;
+ u32 bfs_keyix;
+ enum ath9k_key_type bfs_keytype;
+};
+
+struct ath_buf {
+ struct list_head list;
+ struct ath_buf *bf_lastbf; /* last buf of this unit (a frame or
+ an aggregate) */
+ struct ath_buf *bf_next; /* next subframe in the aggregate */
+ struct sk_buff *bf_mpdu; /* enclosing frame structure */
+ void *bf_desc; /* virtual addr of desc */
+ dma_addr_t bf_daddr; /* physical addr of desc */
+ dma_addr_t bf_buf_addr; /* physical addr of data buffer */
+ bool bf_stale;
+ bool bf_isnullfunc;
+ bool bf_tx_aborted;
+ u16 bf_flags;
+ struct ath_buf_state bf_state;
+ dma_addr_t bf_dmacontext;
+ struct ath_wiphy *aphy;
+};
+
+struct ath_atx_tid {
+ struct list_head list;
+ struct list_head buf_q;
+ struct ath_node *an;
+ struct ath_atx_ac *ac;
+ struct ath_buf *tx_buf[ATH_TID_MAX_BUFS];
+ u16 seq_start;
+ u16 seq_next;
+ u16 baw_size;
+ int tidno;
+ int baw_head; /* first un-acked tx buffer */
+ int baw_tail; /* next unused tx buffer slot */
+ int sched;
+ int paused;
+ u8 state;
+};
+
+struct ath_node {
+ struct ath_common *common;
+ struct ath_atx_tid tid[WME_NUM_TID];
+ struct ath_atx_ac ac[WME_NUM_AC];
+ u16 maxampdu;
+ u8 mpdudensity;
+ int last_rssi;
+};
+
#define AGGR_CLEANUP BIT(1)
#define AGGR_ADDBA_COMPLETE BIT(2)
#define AGGR_ADDBA_PROGRESS BIT(3)
@@ -214,6 +283,7 @@ struct ath_tx_control {
struct ath_txq *txq;
int if_id;
enum ath9k_internal_frame_type frame_type;
+ u8 paprd;
};
#define ATH_TX_ERROR 0x01
@@ -223,11 +293,12 @@ struct ath_tx_control {
struct ath_tx {
u16 seq_no;
u32 txqsetup;
- int hwq_map[ATH9K_WME_AC_VO+1];
+ int hwq_map[WME_NUM_AC];
spinlock_t txbuflock;
struct list_head txbuf;
struct ath_txq txq[ATH9K_NUM_TX_QUEUES];
struct ath_descdma txdma;
+ int pending_frames[WME_NUM_AC];
};
struct ath_rx_edma {
@@ -267,7 +338,6 @@ void ath_tx_node_cleanup(struct ath_softc *sc, struct ath_node *an);
void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq);
int ath_tx_init(struct ath_softc *sc, int nbufs);
void ath_tx_cleanup(struct ath_softc *sc);
-struct ath_txq *ath_test_get_txq(struct ath_softc *sc, struct sk_buff *skb);
int ath_txq_update(struct ath_softc *sc, int qnum,
struct ath9k_tx_queue_info *q);
int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb,
@@ -351,10 +421,15 @@ int ath_beaconq_config(struct ath_softc *sc);
#define ATH_STA_SHORT_CALINTERVAL 1000 /* 1 second */
#define ATH_AP_SHORT_CALINTERVAL 100 /* 100 ms */
-#define ATH_ANI_POLLINTERVAL 100 /* 100 ms */
+#define ATH_ANI_POLLINTERVAL_OLD 100 /* 100 ms */
+#define ATH_ANI_POLLINTERVAL_NEW 1000 /* 1000 ms */
#define ATH_LONG_CALINTERVAL 30000 /* 30 seconds */
#define ATH_RESTART_CALINTERVAL 1200000 /* 20 minutes */
+#define ATH_PAPRD_TIMEOUT 100 /* msecs */
+
+void ath_hw_check(struct work_struct *work);
+void ath_paprd_calibrate(struct work_struct *work);
void ath_ani_calibrate(unsigned long data);
/**********/
@@ -487,6 +562,9 @@ struct ath_softc {
spinlock_t sc_serial_rw;
spinlock_t sc_pm_lock;
struct mutex mutex;
+ struct work_struct paprd_work;
+ struct work_struct hw_check_work;
+ struct completion paprd_complete;
u32 intrstatus;
u32 sc_flags; /* SC_OP_* */
@@ -545,7 +623,6 @@ struct ath_wiphy {
void ath9k_tasklet(unsigned long data);
int ath_reset(struct ath_softc *sc, bool retry_tx);
-int ath_get_hal_qnum(u16 queue, struct ath_softc *sc);
int ath_get_mac80211_qnum(u32 queue, struct ath_softc *sc);
int ath_cabq_update(struct ath_softc *);
@@ -556,13 +633,12 @@ static inline void ath_read_cachesize(struct ath_common *common, int *csz)
extern struct ieee80211_ops ath9k_ops;
extern int modparam_nohwcrypt;
+extern int led_blink;
irqreturn_t ath_isr(int irq, void *dev);
int ath9k_init_device(u16 devid, struct ath_softc *sc, u16 subsysid,
const struct ath_bus_ops *bus_ops);
void ath9k_deinit_device(struct ath_softc *sc);
-const char *ath_mac_bb_name(u32 mac_bb_version);
-const char *ath_rf_name(u16 rf_version);
void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw);
void ath9k_update_ichannel(struct ath_softc *sc, struct ieee80211_hw *hw,
struct ath9k_channel *ichan);
@@ -611,9 +687,7 @@ bool ath9k_all_wiphys_idle(struct ath_softc *sc);
void ath9k_set_wiphy_idle(struct ath_wiphy *aphy, bool idle);
void ath_mac80211_stop_queue(struct ath_softc *sc, u16 skb_queue);
-void ath_mac80211_start_queue(struct ath_softc *sc, u16 skb_queue);
-
-int ath_tx_get_qnum(struct ath_softc *sc, int qtype, int haltype);
+bool ath_mac80211_start_queue(struct ath_softc *sc, u16 skb_queue);
void ath_start_rfkill_poll(struct ath_softc *sc);
extern void ath9k_rfkill_poll_state(struct ieee80211_hw *hw);
diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c
index f43d85a302c..4d4b22d52df 100644
--- a/drivers/net/wireless/ath/ath9k/beacon.c
+++ b/drivers/net/wireless/ath/ath9k/beacon.c
@@ -38,8 +38,7 @@ int ath_beaconq_config(struct ath_softc *sc)
qi.tqi_cwmax = 0;
} else {
/* Adhoc mode; important thing is to use 2x cwmin. */
- qnum = ath_tx_get_qnum(sc, ATH9K_TX_QUEUE_DATA,
- ATH9K_WME_AC_BE);
+ qnum = sc->tx.hwq_map[WME_AC_BE];
ath9k_hw_get_txq_props(ah, qnum, &qi_be);
qi.tqi_aifs = qi_be.tqi_aifs;
qi.tqi_cwmin = 4*qi_be.tqi_cwmin;
diff --git a/drivers/net/wireless/ath/ath9k/calib.c b/drivers/net/wireless/ath/ath9k/calib.c
index 07b8fa6fb62..139289e4e93 100644
--- a/drivers/net/wireless/ath/ath9k/calib.c
+++ b/drivers/net/wireless/ath/ath9k/calib.c
@@ -74,13 +74,8 @@ static void ath9k_hw_update_nfcal_hist_buffer(struct ath9k_nfcal_hist *h,
h[i].currIndex = 0;
if (h[i].invalidNFcount > 0) {
- if (nfarray[i] < AR_PHY_CCA_MIN_BAD_VALUE ||
- nfarray[i] > AR_PHY_CCA_MAX_HIGH_VALUE) {
- h[i].invalidNFcount = ATH9K_NF_CAL_HIST_MAX;
- } else {
- h[i].invalidNFcount--;
- h[i].privNF = nfarray[i];
- }
+ h[i].invalidNFcount--;
+ h[i].privNF = nfarray[i];
} else {
h[i].privNF =
ath9k_hw_get_nf_hist_mid(h[i].nfCalBuffer);
@@ -172,6 +167,116 @@ void ath9k_hw_start_nfcal(struct ath_hw *ah)
REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NF);
}
+void ath9k_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan)
+{
+ struct ath9k_nfcal_hist *h;
+ unsigned i, j;
+ int32_t val;
+ u8 chainmask = (ah->rxchainmask << 3) | ah->rxchainmask;
+ struct ath_common *common = ath9k_hw_common(ah);
+
+ h = ah->nfCalHist;
+
+ for (i = 0; i < NUM_NF_READINGS; i++) {
+ if (chainmask & (1 << i)) {
+ val = REG_READ(ah, ah->nf_regs[i]);
+ val &= 0xFFFFFE00;
+ val |= (((u32) (h[i].privNF) << 1) & 0x1ff);
+ REG_WRITE(ah, ah->nf_regs[i], val);
+ }
+ }
+
+ /*
+ * Load software filtered NF value into baseband internal minCCApwr
+ * variable.
+ */
+ REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL,
+ AR_PHY_AGC_CONTROL_ENABLE_NF);
+ REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL,
+ AR_PHY_AGC_CONTROL_NO_UPDATE_NF);
+ REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NF);
+
+ /*
+ * Wait for load to complete, should be fast, a few 10s of us.
+ * The max delay was changed from an original 250us to 10000us
+ * since 250us often results in NF load timeout and causes deaf
+ * condition during stress testing 12/12/2009
+ */
+ for (j = 0; j < 1000; j++) {
+ if ((REG_READ(ah, AR_PHY_AGC_CONTROL) &
+ AR_PHY_AGC_CONTROL_NF) == 0)
+ break;
+ udelay(10);
+ }
+
+ /*
+ * We timed out waiting for the noisefloor to load, probably due to an
+ * in-progress rx. Simply return here and allow the load plenty of time
+ * to complete before the next calibration interval. We need to avoid
+ * trying to load -50 (which happens below) while the previous load is
+ * still in progress as this can cause rx deafness. Instead by returning
+ * here, the baseband nf cal will just be capped by our present
+ * noisefloor until the next calibration timer.
+ */
+ if (j == 1000) {
+ ath_print(common, ATH_DBG_ANY, "Timeout while waiting for nf "
+ "to load: AR_PHY_AGC_CONTROL=0x%x\n",
+ REG_READ(ah, AR_PHY_AGC_CONTROL));
+ return;
+ }
+
+ /*
+ * Restore maxCCAPower register parameter again so that we're not capped
+ * by the median we just loaded. This will be initial (and max) value
+ * of next noise floor calibration the baseband does.
+ */
+ ENABLE_REGWRITE_BUFFER(ah);
+ for (i = 0; i < NUM_NF_READINGS; i++) {
+ if (chainmask & (1 << i)) {
+ val = REG_READ(ah, ah->nf_regs[i]);
+ val &= 0xFFFFFE00;
+ val |= (((u32) (-50) << 1) & 0x1ff);
+ REG_WRITE(ah, ah->nf_regs[i], val);
+ }
+ }
+ REGWRITE_BUFFER_FLUSH(ah);
+ DISABLE_REGWRITE_BUFFER(ah);
+}
+
+
+static void ath9k_hw_nf_sanitize(struct ath_hw *ah, s16 *nf)
+{
+ struct ath_common *common = ath9k_hw_common(ah);
+ struct ath_nf_limits *limit;
+ int i;
+
+ if (IS_CHAN_2GHZ(ah->curchan))
+ limit = &ah->nf_2g;
+ else
+ limit = &ah->nf_5g;
+
+ for (i = 0; i < NUM_NF_READINGS; i++) {
+ if (!nf[i])
+ continue;
+
+ ath_print(common, ATH_DBG_CALIBRATE,
+ "NF calibrated [%s] [chain %d] is %d\n",
+ (i >= 3 ? "ext" : "ctl"), i % 3, nf[i]);
+
+ if (nf[i] > limit->max) {
+ ath_print(common, ATH_DBG_CALIBRATE,
+ "NF[%d] (%d) > MAX (%d), correcting to MAX",
+ i, nf[i], limit->max);
+ nf[i] = limit->max;
+ } else if (nf[i] < limit->min) {
+ ath_print(common, ATH_DBG_CALIBRATE,
+ "NF[%d] (%d) < MIN (%d), correcting to NOM",
+ i, nf[i], limit->min);
+ nf[i] = limit->nominal;
+ }
+ }
+}
+
int16_t ath9k_hw_getnf(struct ath_hw *ah,
struct ath9k_channel *chan)
{
@@ -190,6 +295,7 @@ int16_t ath9k_hw_getnf(struct ath_hw *ah,
return chan->rawNoiseFloor;
} else {
ath9k_hw_do_getnf(ah, nfarray);
+ ath9k_hw_nf_sanitize(ah, nfarray);
nf = nfarray[0];
if (ath9k_hw_get_nf_thresh(ah, c->band, &nfThresh)
&& nf > nfThresh) {
@@ -211,25 +317,21 @@ int16_t ath9k_hw_getnf(struct ath_hw *ah,
void ath9k_init_nfcal_hist_buffer(struct ath_hw *ah)
{
+ struct ath_nf_limits *limit;
int i, j;
- s16 noise_floor;
-
- if (AR_SREV_9280(ah))
- noise_floor = AR_PHY_CCA_MAX_AR9280_GOOD_VALUE;
- else if (AR_SREV_9285(ah) || AR_SREV_9271(ah))
- noise_floor = AR_PHY_CCA_MAX_AR9285_GOOD_VALUE;
- else if (AR_SREV_9287(ah))
- noise_floor = AR_PHY_CCA_MAX_AR9287_GOOD_VALUE;
+
+ if (!ah->curchan || IS_CHAN_2GHZ(ah->curchan))
+ limit = &ah->nf_2g;
else
- noise_floor = AR_PHY_CCA_MAX_AR5416_GOOD_VALUE;
+ limit = &ah->nf_5g;
for (i = 0; i < NUM_NF_READINGS; i++) {
ah->nfCalHist[i].currIndex = 0;
- ah->nfCalHist[i].privNF = noise_floor;
+ ah->nfCalHist[i].privNF = limit->nominal;
ah->nfCalHist[i].invalidNFcount =
AR_PHY_CCA_FILTERWINDOW_LENGTH;
for (j = 0; j < ATH9K_NF_CAL_HIST_MAX; j++) {
- ah->nfCalHist[i].nfCalBuffer[j] = noise_floor;
+ ah->nfCalHist[i].nfCalBuffer[j] = limit->nominal;
}
}
}
diff --git a/drivers/net/wireless/ath/ath9k/calib.h b/drivers/net/wireless/ath/ath9k/calib.h
index 24538bdb912..cd60d09cdda 100644
--- a/drivers/net/wireless/ath/ath9k/calib.h
+++ b/drivers/net/wireless/ath/ath9k/calib.h
@@ -19,12 +19,6 @@
#include "hw.h"
-#define AR_PHY_CCA_MAX_AR5416_GOOD_VALUE -85
-#define AR_PHY_CCA_MAX_AR9280_GOOD_VALUE -112
-#define AR_PHY_CCA_MAX_AR9285_GOOD_VALUE -118
-#define AR_PHY_CCA_MAX_AR9287_GOOD_VALUE -118
-#define AR_PHY_CCA_MAX_HIGH_VALUE -62
-#define AR_PHY_CCA_MIN_BAD_VALUE -140
#define AR_PHY_CCA_FILTERWINDOW_LENGTH_INIT 3
#define AR_PHY_CCA_FILTERWINDOW_LENGTH 5
@@ -115,6 +109,7 @@ struct ath9k_pacal_info{
bool ath9k_hw_reset_calvalid(struct ath_hw *ah);
void ath9k_hw_start_nfcal(struct ath_hw *ah);
+void ath9k_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan);
int16_t ath9k_hw_getnf(struct ath_hw *ah,
struct ath9k_channel *chan);
void ath9k_init_nfcal_hist_buffer(struct ath_hw *ah);
diff --git a/drivers/net/wireless/ath/ath9k/common.c b/drivers/net/wireless/ath/ath9k/common.c
index 7707341cd0d..c86f7d3593a 100644
--- a/drivers/net/wireless/ath/ath9k/common.c
+++ b/drivers/net/wireless/ath/ath9k/common.c
@@ -27,270 +27,6 @@ MODULE_AUTHOR("Atheros Communications");
MODULE_DESCRIPTION("Shared library for Atheros wireless 802.11n LAN cards.");
MODULE_LICENSE("Dual BSD/GPL");
-/* Common RX processing */
-
-/* Assumes you've already done the endian to CPU conversion */
-static bool ath9k_rx_accept(struct ath_common *common,
- struct sk_buff *skb,
- struct ieee80211_rx_status *rxs,
- struct ath_rx_status *rx_stats,
- bool *decrypt_error)
-{
- struct ath_hw *ah = common->ah;
- struct ieee80211_hdr *hdr;
- __le16 fc;
-
- hdr = (struct ieee80211_hdr *) skb->data;
- fc = hdr->frame_control;
-
- if (!rx_stats->rs_datalen)
- return false;
- /*
- * rs_status follows rs_datalen so if rs_datalen is too large
- * we can take a hint that hardware corrupted it, so ignore
- * those frames.
- */
- if (rx_stats->rs_datalen > common->rx_bufsize)
- return false;
-
- /*
- * rs_more indicates chained descriptors which can be used
- * to link buffers together for a sort of scatter-gather
- * operation.
- * reject the frame, we don't support scatter-gather yet and
- * the frame is probably corrupt anyway
- */
- if (rx_stats->rs_more)
- return false;
-
- /*
- * The rx_stats->rs_status will not be set until the end of the
- * chained descriptors so it can be ignored if rs_more is set. The
- * rs_more will be false at the last element of the chained
- * descriptors.
- */
- if (rx_stats->rs_status != 0) {
- if (rx_stats->rs_status & ATH9K_RXERR_CRC)
- rxs->flag |= RX_FLAG_FAILED_FCS_CRC;
- if (rx_stats->rs_status & ATH9K_RXERR_PHY)
- return false;
-
- if (rx_stats->rs_status & ATH9K_RXERR_DECRYPT) {
- *decrypt_error = true;
- } else if (rx_stats->rs_status & ATH9K_RXERR_MIC) {
- if (ieee80211_is_ctl(fc))
- /*
- * Sometimes, we get invalid
- * MIC failures on valid control frames.
- * Remove these mic errors.
- */
- rx_stats->rs_status &= ~ATH9K_RXERR_MIC;
- else
- rxs->flag |= RX_FLAG_MMIC_ERROR;
- }
- /*
- * Reject error frames with the exception of
- * decryption and MIC failures. For monitor mode,
- * we also ignore the CRC error.
- */
- if (ah->opmode == NL80211_IFTYPE_MONITOR) {
- if (rx_stats->rs_status &
- ~(ATH9K_RXERR_DECRYPT | ATH9K_RXERR_MIC |
- ATH9K_RXERR_CRC))
- return false;
- } else {
- if (rx_stats->rs_status &
- ~(ATH9K_RXERR_DECRYPT | ATH9K_RXERR_MIC)) {
- return false;
- }
- }
- }
- return true;
-}
-
-static int ath9k_process_rate(struct ath_common *common,
- struct ieee80211_hw *hw,
- struct ath_rx_status *rx_stats,
- struct ieee80211_rx_status *rxs,
- struct sk_buff *skb)
-{
- struct ieee80211_supported_band *sband;
- enum ieee80211_band band;
- unsigned int i = 0;
-
- band = hw->conf.channel->band;
- sband = hw->wiphy->bands[band];
-
- if (rx_stats->rs_rate & 0x80) {
- /* HT rate */
- rxs->flag |= RX_FLAG_HT;
- if (rx_stats->rs_flags & ATH9K_RX_2040)
- rxs->flag |= RX_FLAG_40MHZ;
- if (rx_stats->rs_flags & ATH9K_RX_GI)
- rxs->flag |= RX_FLAG_SHORT_GI;
- rxs->rate_idx = rx_stats->rs_rate & 0x7f;
- return 0;
- }
-
- for (i = 0; i < sband->n_bitrates; i++) {
- if (sband->bitrates[i].hw_value == rx_stats->rs_rate) {
- rxs->rate_idx = i;
- return 0;
- }
- if (sband->bitrates[i].hw_value_short == rx_stats->rs_rate) {
- rxs->flag |= RX_FLAG_SHORTPRE;
- rxs->rate_idx = i;
- return 0;
- }
- }
-
- /*
- * No valid hardware bitrate found -- we should not get here
- * because hardware has already validated this frame as OK.
- */
- ath_print(common, ATH_DBG_XMIT, "unsupported hw bitrate detected "
- "0x%02x using 1 Mbit\n", rx_stats->rs_rate);
- if ((common->debug_mask & ATH_DBG_XMIT))
- print_hex_dump_bytes("", DUMP_PREFIX_NONE, skb->data, skb->len);
-
- return -EINVAL;
-}
-
-static void ath9k_process_rssi(struct ath_common *common,
- struct ieee80211_hw *hw,
- struct sk_buff *skb,
- struct ath_rx_status *rx_stats)
-{
- struct ath_hw *ah = common->ah;
- struct ieee80211_sta *sta;
- struct ieee80211_hdr *hdr;
- struct ath_node *an;
- int last_rssi = ATH_RSSI_DUMMY_MARKER;
- __le16 fc;
-
- hdr = (struct ieee80211_hdr *)skb->data;
- fc = hdr->frame_control;
-
- rcu_read_lock();
- /*
- * XXX: use ieee80211_find_sta! This requires quite a bit of work
- * under the current ath9k virtual wiphy implementation as we have
- * no way of tying a vif to wiphy. Typically vifs are attached to
- * at least one sdata of a wiphy on mac80211 but with ath9k virtual
- * wiphy you'd have to iterate over every wiphy and each sdata.
- */
- sta = ieee80211_find_sta_by_hw(hw, hdr->addr2);
- if (sta) {
- an = (struct ath_node *) sta->drv_priv;
- if (rx_stats->rs_rssi != ATH9K_RSSI_BAD &&
- !rx_stats->rs_moreaggr)
- ATH_RSSI_LPF(an->last_rssi, rx_stats->rs_rssi);
- last_rssi = an->last_rssi;
- }
- rcu_read_unlock();
-
- if (likely(last_rssi != ATH_RSSI_DUMMY_MARKER))
- rx_stats->rs_rssi = ATH_EP_RND(last_rssi,
- ATH_RSSI_EP_MULTIPLIER);
- if (rx_stats->rs_rssi < 0)
- rx_stats->rs_rssi = 0;
-
- /* Update Beacon RSSI, this is used by ANI. */
- if (ieee80211_is_beacon(fc))
- ah->stats.avgbrssi = rx_stats->rs_rssi;
-}
-
-/*
- * For Decrypt or Demic errors, we only mark packet status here and always push
- * up the frame up to let mac80211 handle the actual error case, be it no
- * decryption key or real decryption error. This let us keep statistics there.
- */
-int ath9k_cmn_rx_skb_preprocess(struct ath_common *common,
- struct ieee80211_hw *hw,
- struct sk_buff *skb,
- struct ath_rx_status *rx_stats,
- struct ieee80211_rx_status *rx_status,
- bool *decrypt_error)
-{
- struct ath_hw *ah = common->ah;
-
- memset(rx_status, 0, sizeof(struct ieee80211_rx_status));
-
- /*
- * everything but the rate is checked here, the rate check is done
- * separately to avoid doing two lookups for a rate for each frame.
- */
- if (!ath9k_rx_accept(common, skb, rx_status, rx_stats, decrypt_error))
- return -EINVAL;
-
- ath9k_process_rssi(common, hw, skb, rx_stats);
-
- if (ath9k_process_rate(common, hw, rx_stats, rx_status, skb))
- return -EINVAL;
-
- rx_status->mactime = ath9k_hw_extend_tsf(ah, rx_stats->rs_tstamp);
- rx_status->band = hw->conf.channel->band;
- rx_status->freq = hw->conf.channel->center_freq;
- rx_status->signal = ATH_DEFAULT_NOISE_FLOOR + rx_stats->rs_rssi;
- rx_status->antenna = rx_stats->rs_antenna;
- rx_status->flag |= RX_FLAG_TSFT;
-
- return 0;
-}
-EXPORT_SYMBOL(ath9k_cmn_rx_skb_preprocess);
-
-void ath9k_cmn_rx_skb_postprocess(struct ath_common *common,
- struct sk_buff *skb,
- struct ath_rx_status *rx_stats,
- struct ieee80211_rx_status *rxs,
- bool decrypt_error)
-{
- struct ath_hw *ah = common->ah;
- struct ieee80211_hdr *hdr;
- int hdrlen, padpos, padsize;
- u8 keyix;
- __le16 fc;
-
- /* see if any padding is done by the hw and remove it */
- hdr = (struct ieee80211_hdr *) skb->data;
- hdrlen = ieee80211_get_hdrlen_from_skb(skb);
- fc = hdr->frame_control;
- padpos = ath9k_cmn_padpos(hdr->frame_control);
-
- /* The MAC header is padded to have 32-bit boundary if the
- * packet payload is non-zero. The general calculation for
- * padsize would take into account odd header lengths:
- * padsize = (4 - padpos % 4) % 4; However, since only
- * even-length headers are used, padding can only be 0 or 2
- * bytes and we can optimize this a bit. In addition, we must
- * not try to remove padding from short control frames that do
- * not have payload. */
- padsize = padpos & 3;
- if (padsize && skb->len>=padpos+padsize+FCS_LEN) {
- memmove(skb->data + padsize, skb->data, padpos);
- skb_pull(skb, padsize);
- }
-
- keyix = rx_stats->rs_keyix;
-
- if (!(keyix == ATH9K_RXKEYIX_INVALID) && !decrypt_error &&
- ieee80211_has_protected(fc)) {
- rxs->flag |= RX_FLAG_DECRYPTED;
- } else if (ieee80211_has_protected(fc)
- && !decrypt_error && skb->len >= hdrlen + 4) {
- keyix = skb->data[hdrlen + 3] >> 6;
-
- if (test_bit(keyix, common->keymap))
- rxs->flag |= RX_FLAG_DECRYPTED;
- }
- if (ah->sw_mgmt_crypto &&
- (rxs->flag & RX_FLAG_DECRYPTED) &&
- ieee80211_is_mgmt(fc))
- /* Use software decrypt for management frames. */
- rxs->flag &= ~RX_FLAG_DECRYPTED;
-}
-EXPORT_SYMBOL(ath9k_cmn_rx_skb_postprocess);
-
int ath9k_cmn_padpos(__le16 frame_control)
{
int padpos = 24;
@@ -475,10 +211,14 @@ static int ath_reserve_key_cache_slot_tkip(struct ath_common *common)
return -1;
}
-static int ath_reserve_key_cache_slot(struct ath_common *common)
+static int ath_reserve_key_cache_slot(struct ath_common *common,
+ enum ieee80211_key_alg alg)
{
int i;
+ if (alg == ALG_TKIP)
+ return ath_reserve_key_cache_slot_tkip(common);
+
/* First, try to find slots that would not be available for TKIP. */
if (common->splitmic) {
for (i = IEEE80211_WEP_NKID; i < common->keymax / 4; i++) {
@@ -547,6 +287,7 @@ int ath9k_cmn_key_config(struct ath_common *common,
struct ath_hw *ah = common->ah;
struct ath9k_keyval hk;
const u8 *mac = NULL;
+ u8 gmac[ETH_ALEN];
int ret = 0;
int idx;
@@ -570,9 +311,27 @@ int ath9k_cmn_key_config(struct ath_common *common,
memcpy(hk.kv_val, key->key, key->keylen);
if (!(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) {
- /* For now, use the default keys for broadcast keys. This may
- * need to change with virtual interfaces. */
- idx = key->keyidx;
+ switch (vif->type) {
+ case NL80211_IFTYPE_AP:
+ memcpy(gmac, vif->addr, ETH_ALEN);
+ gmac[0] |= 0x01;
+ mac = gmac;
+ idx = ath_reserve_key_cache_slot(common, key->alg);
+ break;
+ case NL80211_IFTYPE_ADHOC:
+ if (!sta) {
+ idx = key->keyidx;
+ break;
+ }
+ memcpy(gmac, sta->addr, ETH_ALEN);
+ gmac[0] |= 0x01;
+ mac = gmac;
+ idx = ath_reserve_key_cache_slot(common, key->alg);
+ break;
+ default:
+ idx = key->keyidx;
+ break;
+ }
} else if (key->keyidx) {
if (WARN_ON(!sta))
return -EOPNOTSUPP;
@@ -589,14 +348,12 @@ int ath9k_cmn_key_config(struct ath_common *common,
return -EOPNOTSUPP;
mac = sta->addr;
- if (key->alg == ALG_TKIP)
- idx = ath_reserve_key_cache_slot_tkip(common);
- else
- idx = ath_reserve_key_cache_slot(common);
- if (idx < 0)
- return -ENOSPC; /* no free key cache entries */
+ idx = ath_reserve_key_cache_slot(common, key->alg);
}
+ if (idx < 0)
+ return -ENOSPC; /* no free key cache entries */
+
if (key->alg == ALG_TKIP)
ret = ath_setkey_tkip(common, idx, key->key, &hk, mac,
vif->type == NL80211_IFTYPE_AP);
@@ -644,6 +401,19 @@ void ath9k_cmn_key_delete(struct ath_common *common,
}
EXPORT_SYMBOL(ath9k_cmn_key_delete);
+int ath9k_cmn_count_streams(unsigned int chainmask, int max)
+{
+ int streams = 0;
+
+ do {
+ if (++streams == max)
+ break;
+ } while ((chainmask = chainmask & (chainmask - 1)));
+
+ return streams;
+}
+EXPORT_SYMBOL(ath9k_cmn_count_streams);
+
static int __init ath9k_cmn_init(void)
{
return 0;
diff --git a/drivers/net/wireless/ath/ath9k/common.h b/drivers/net/wireless/ath/ath9k/common.h
index e08f7e5a26e..97809d39c73 100644
--- a/drivers/net/wireless/ath/ath9k/common.h
+++ b/drivers/net/wireless/ath/ath9k/common.h
@@ -52,82 +52,6 @@
#define ATH_EP_RND(x, mul) \
((((x)%(mul)) >= ((mul)/2)) ? ((x) + ((mul) - 1)) / (mul) : (x)/(mul))
-struct ath_atx_ac {
- int sched;
- int qnum;
- struct list_head list;
- struct list_head tid_q;
-};
-
-struct ath_buf_state {
- int bfs_nframes;
- u16 bfs_al;
- u16 bfs_frmlen;
- int bfs_seqno;
- int bfs_tidno;
- int bfs_retries;
- u8 bf_type;
- u32 bfs_keyix;
- enum ath9k_key_type bfs_keytype;
-};
-
-struct ath_buf {
- struct list_head list;
- struct ath_buf *bf_lastbf; /* last buf of this unit (a frame or
- an aggregate) */
- struct ath_buf *bf_next; /* next subframe in the aggregate */
- struct sk_buff *bf_mpdu; /* enclosing frame structure */
- void *bf_desc; /* virtual addr of desc */
- dma_addr_t bf_daddr; /* physical addr of desc */
- dma_addr_t bf_buf_addr; /* physical addr of data buffer */
- bool bf_stale;
- bool bf_isnullfunc;
- bool bf_tx_aborted;
- u16 bf_flags;
- struct ath_buf_state bf_state;
- dma_addr_t bf_dmacontext;
- struct ath_wiphy *aphy;
-};
-
-struct ath_atx_tid {
- struct list_head list;
- struct list_head buf_q;
- struct ath_node *an;
- struct ath_atx_ac *ac;
- struct ath_buf *tx_buf[ATH_TID_MAX_BUFS];
- u16 seq_start;
- u16 seq_next;
- u16 baw_size;
- int tidno;
- int baw_head; /* first un-acked tx buffer */
- int baw_tail; /* next unused tx buffer slot */
- int sched;
- int paused;
- u8 state;
-};
-
-struct ath_node {
- struct ath_common *common;
- struct ath_atx_tid tid[WME_NUM_TID];
- struct ath_atx_ac ac[WME_NUM_AC];
- u16 maxampdu;
- u8 mpdudensity;
- int last_rssi;
-};
-
-int ath9k_cmn_rx_skb_preprocess(struct ath_common *common,
- struct ieee80211_hw *hw,
- struct sk_buff *skb,
- struct ath_rx_status *rx_stats,
- struct ieee80211_rx_status *rx_status,
- bool *decrypt_error);
-
-void ath9k_cmn_rx_skb_postprocess(struct ath_common *common,
- struct sk_buff *skb,
- struct ath_rx_status *rx_stats,
- struct ieee80211_rx_status *rxs,
- bool decrypt_error);
-
int ath9k_cmn_padpos(__le16 frame_control);
int ath9k_cmn_get_hw_crypto_keytype(struct sk_buff *skb);
void ath9k_cmn_update_ichannel(struct ieee80211_hw *hw,
@@ -140,3 +64,4 @@ int ath9k_cmn_key_config(struct ath_common *common,
struct ieee80211_key_conf *key);
void ath9k_cmn_key_delete(struct ath_common *common,
struct ieee80211_key_conf *key);
+int ath9k_cmn_count_streams(unsigned int chainmask, int max);
diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c
index 29898f8d189..54aae931424 100644
--- a/drivers/net/wireless/ath/ath9k/debug.c
+++ b/drivers/net/wireless/ath/ath9k/debug.c
@@ -42,7 +42,7 @@ static ssize_t read_file_debug(struct file *file, char __user *user_buf,
char buf[32];
unsigned int len;
- len = snprintf(buf, sizeof(buf), "0x%08x\n", common->debug_mask);
+ len = sprintf(buf, "0x%08x\n", common->debug_mask);
return simple_read_from_buffer(user_buf, count, ppos, buf, len);
}
@@ -57,7 +57,7 @@ static ssize_t write_file_debug(struct file *file, const char __user *user_buf,
len = min(count, sizeof(buf) - 1);
if (copy_from_user(buf, user_buf, len))
- return -EINVAL;
+ return -EFAULT;
buf[len] = '\0';
if (strict_strtoul(buf, 0, &mask))
@@ -86,7 +86,7 @@ static ssize_t read_file_tx_chainmask(struct file *file, char __user *user_buf,
char buf[32];
unsigned int len;
- len = snprintf(buf, sizeof(buf), "0x%08x\n", common->tx_chainmask);
+ len = sprintf(buf, "0x%08x\n", common->tx_chainmask);
return simple_read_from_buffer(user_buf, count, ppos, buf, len);
}
@@ -101,7 +101,7 @@ static ssize_t write_file_tx_chainmask(struct file *file, const char __user *use
len = min(count, sizeof(buf) - 1);
if (copy_from_user(buf, user_buf, len))
- return -EINVAL;
+ return -EFAULT;
buf[len] = '\0';
if (strict_strtoul(buf, 0, &mask))
@@ -128,7 +128,7 @@ static ssize_t read_file_rx_chainmask(struct file *file, char __user *user_buf,
char buf[32];
unsigned int len;
- len = snprintf(buf, sizeof(buf), "0x%08x\n", common->rx_chainmask);
+ len = sprintf(buf, "0x%08x\n", common->rx_chainmask);
return simple_read_from_buffer(user_buf, count, ppos, buf, len);
}
@@ -143,7 +143,7 @@ static ssize_t write_file_rx_chainmask(struct file *file, const char __user *use
len = min(count, sizeof(buf) - 1);
if (copy_from_user(buf, user_buf, len))
- return -EINVAL;
+ return -EFAULT;
buf[len] = '\0';
if (strict_strtoul(buf, 0, &mask))
@@ -176,7 +176,7 @@ static ssize_t read_file_dma(struct file *file, char __user *user_buf,
buf = kmalloc(DMA_BUF_LEN, GFP_KERNEL);
if (!buf)
- return 0;
+ return -ENOMEM;
ath9k_ps_wakeup(sc);
@@ -248,6 +248,9 @@ static ssize_t read_file_dma(struct file *file, char __user *user_buf,
ath9k_ps_restore(sc);
+ if (len > DMA_BUF_LEN)
+ len = DMA_BUF_LEN;
+
retval = simple_read_from_buffer(user_buf, count, ppos, buf, len);
kfree(buf);
return retval;
@@ -269,6 +272,8 @@ void ath_debug_stat_interrupt(struct ath_softc *sc, enum ath9k_int status)
sc->debug.stats.istats.rxlp++;
if (status & ATH9K_INT_RXHP)
sc->debug.stats.istats.rxhp++;
+ if (status & ATH9K_INT_BB_WATCHDOG)
+ sc->debug.stats.istats.bb_watchdog++;
} else {
if (status & ATH9K_INT_RX)
sc->debug.stats.istats.rxok++;
@@ -319,6 +324,9 @@ static ssize_t read_file_interrupt(struct file *file, char __user *user_buf,
"%8s: %10u\n", "RXLP", sc->debug.stats.istats.rxlp);
len += snprintf(buf + len, sizeof(buf) - len,
"%8s: %10u\n", "RXHP", sc->debug.stats.istats.rxhp);
+ len += snprintf(buf + len, sizeof(buf) - len,
+ "%8s: %10u\n", "WATCHDOG",
+ sc->debug.stats.istats.bb_watchdog);
} else {
len += snprintf(buf + len, sizeof(buf) - len,
"%8s: %10u\n", "RX", sc->debug.stats.istats.rxok);
@@ -358,6 +366,9 @@ static ssize_t read_file_interrupt(struct file *file, char __user *user_buf,
len += snprintf(buf + len, sizeof(buf) - len,
"%8s: %10u\n", "TOTAL", sc->debug.stats.istats.total);
+ if (len > sizeof(buf))
+ len = sizeof(buf);
+
return simple_read_from_buffer(user_buf, count, ppos, buf, len);
}
@@ -397,11 +408,10 @@ static ssize_t read_file_rcstat(struct file *file, char __user *user_buf,
if (sc->cur_rate_table == NULL)
return 0;
- max = 80 + sc->cur_rate_table->rate_cnt * 1024;
- buf = kmalloc(max + 1, GFP_KERNEL);
+ max = 80 + sc->cur_rate_table->rate_cnt * 1024 + 1;
+ buf = kmalloc(max, GFP_KERNEL);
if (buf == NULL)
- return 0;
- buf[max] = 0;
+ return -ENOMEM;
len += sprintf(buf, "%6s %6s %6s "
"%10s %10s %10s %10s\n",
@@ -443,6 +453,9 @@ static ssize_t read_file_rcstat(struct file *file, char __user *user_buf,
stats->per);
}
+ if (len > max)
+ len = max;
+
retval = simple_read_from_buffer(user_buf, count, ppos, buf, len);
kfree(buf);
return retval;
@@ -505,6 +518,9 @@ static ssize_t read_file_wiphy(struct file *file, char __user *user_buf,
len += snprintf(buf + len, sizeof(buf) - len,
"addrmask: %pM\n", addr);
+ if (len > sizeof(buf))
+ len = sizeof(buf);
+
return simple_read_from_buffer(user_buf, count, ppos, buf, len);
}
@@ -614,10 +630,10 @@ static const struct file_operations fops_wiphy = {
do { \
len += snprintf(buf + len, size - len, \
"%s%13u%11u%10u%10u\n", str, \
- sc->debug.stats.txstats[sc->tx.hwq_map[ATH9K_WME_AC_BE]].elem, \
- sc->debug.stats.txstats[sc->tx.hwq_map[ATH9K_WME_AC_BK]].elem, \
- sc->debug.stats.txstats[sc->tx.hwq_map[ATH9K_WME_AC_VI]].elem, \
- sc->debug.stats.txstats[sc->tx.hwq_map[ATH9K_WME_AC_VO]].elem); \
+ sc->debug.stats.txstats[sc->tx.hwq_map[WME_AC_BE]].elem, \
+ sc->debug.stats.txstats[sc->tx.hwq_map[WME_AC_BK]].elem, \
+ sc->debug.stats.txstats[sc->tx.hwq_map[WME_AC_VI]].elem, \
+ sc->debug.stats.txstats[sc->tx.hwq_map[WME_AC_VO]].elem); \
} while(0)
static ssize_t read_file_xmit(struct file *file, char __user *user_buf,
@@ -630,7 +646,7 @@ static ssize_t read_file_xmit(struct file *file, char __user *user_buf,
buf = kzalloc(size, GFP_KERNEL);
if (buf == NULL)
- return 0;
+ return -ENOMEM;
len += sprintf(buf, "%30s %10s%10s%10s\n\n", "BE", "BK", "VI", "VO");
@@ -648,6 +664,9 @@ static ssize_t read_file_xmit(struct file *file, char __user *user_buf,
PR("DATA Underrun: ", data_underrun);
PR("DELIM Underrun: ", delim_underrun);
+ if (len > size)
+ len = size;
+
retval = simple_read_from_buffer(user_buf, count, ppos, buf, len);
kfree(buf);
@@ -700,7 +719,7 @@ static ssize_t read_file_recv(struct file *file, char __user *user_buf,
buf = kzalloc(size, GFP_KERNEL);
if (buf == NULL)
- return 0;
+ return -ENOMEM;
len += snprintf(buf + len, size - len,
"%18s : %10u\n", "CRC ERR",
@@ -751,6 +770,9 @@ static ssize_t read_file_recv(struct file *file, char __user *user_buf,
PHY_ERR("HT-LENGTH", ATH9K_PHYERR_HT_LENGTH_ILLEGAL);
PHY_ERR("HT-RATE", ATH9K_PHYERR_HT_RATE_ILLEGAL);
+ if (len > size)
+ len = size;
+
retval = simple_read_from_buffer(user_buf, count, ppos, buf, len);
kfree(buf);
@@ -802,7 +824,7 @@ static ssize_t read_file_regidx(struct file *file, char __user *user_buf,
char buf[32];
unsigned int len;
- len = snprintf(buf, sizeof(buf), "0x%08x\n", sc->debug.regidx);
+ len = sprintf(buf, "0x%08x\n", sc->debug.regidx);
return simple_read_from_buffer(user_buf, count, ppos, buf, len);
}
@@ -816,7 +838,7 @@ static ssize_t write_file_regidx(struct file *file, const char __user *user_buf,
len = min(count, sizeof(buf) - 1);
if (copy_from_user(buf, user_buf, len))
- return -EINVAL;
+ return -EFAULT;
buf[len] = '\0';
if (strict_strtoul(buf, 0, &regidx))
@@ -843,7 +865,7 @@ static ssize_t read_file_regval(struct file *file, char __user *user_buf,
u32 regval;
regval = REG_READ_D(ah, sc->debug.regidx);
- len = snprintf(buf, sizeof(buf), "0x%08x\n", regval);
+ len = sprintf(buf, "0x%08x\n", regval);
return simple_read_from_buffer(user_buf, count, ppos, buf, len);
}
@@ -858,7 +880,7 @@ static ssize_t write_file_regval(struct file *file, const char __user *user_buf,
len = min(count, sizeof(buf) - 1);
if (copy_from_user(buf, user_buf, len))
- return -EINVAL;
+ return -EFAULT;
buf[len] = '\0';
if (strict_strtoul(buf, 0, &regval))
@@ -934,6 +956,10 @@ int ath9k_init_debug(struct ath_hw *ah)
sc->debug.debugfs_phy, sc, &fops_regval))
goto err;
+ if (!debugfs_create_bool("ignore_extcca", S_IRUSR | S_IWUSR,
+ sc->debug.debugfs_phy, &ah->config.cwm_ignore_extcca))
+ goto err;
+
sc->debug.regidx = 0;
return 0;
err:
diff --git a/drivers/net/wireless/ath/ath9k/debug.h b/drivers/net/wireless/ath/ath9k/debug.h
index 5147b8709e1..5d21704e87f 100644
--- a/drivers/net/wireless/ath/ath9k/debug.h
+++ b/drivers/net/wireless/ath/ath9k/debug.h
@@ -53,6 +53,7 @@ struct ath_buf;
* @cabend: RX End of CAB traffic
* @dtimsync: DTIM sync lossage
* @dtim: RX Beacon with DTIM
+ * @bb_watchdog: Baseband watchdog
*/
struct ath_interrupt_stats {
u32 total;
@@ -76,6 +77,7 @@ struct ath_interrupt_stats {
u32 cabend;
u32 dtimsync;
u32 dtim;
+ u32 bb_watchdog;
};
struct ath_rc_stats {
diff --git a/drivers/net/wireless/ath/ath9k/eeprom.c b/drivers/net/wireless/ath/ath9k/eeprom.c
index ca8704a9d7a..1266333f586 100644
--- a/drivers/net/wireless/ath/ath9k/eeprom.c
+++ b/drivers/net/wireless/ath/ath9k/eeprom.c
@@ -24,6 +24,14 @@ static inline u16 ath9k_hw_fbin2freq(u8 fbin, bool is2GHz)
return (u16) ((is2GHz) ? (2300 + fbin) : (4800 + 5 * fbin));
}
+void ath9k_hw_analog_shift_regwrite(struct ath_hw *ah, u32 reg, u32 val)
+{
+ REG_WRITE(ah, reg, val);
+
+ if (ah->config.analog_shiftreg)
+ udelay(100);
+}
+
void ath9k_hw_analog_shift_rmw(struct ath_hw *ah, u32 reg, u32 mask,
u32 shift, u32 val)
{
@@ -250,6 +258,27 @@ u16 ath9k_hw_get_max_edge_power(u16 freq, struct cal_ctl_edges *pRdEdgesPower,
return twiceMaxEdgePower;
}
+void ath9k_hw_update_regulatory_maxpower(struct ath_hw *ah)
+{
+ struct ath_common *common = ath9k_hw_common(ah);
+ struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah);
+
+ switch (ar5416_get_ntxchains(ah->txchainmask)) {
+ case 1:
+ break;
+ case 2:
+ regulatory->max_power_level += INCREASE_MAXPOW_BY_TWO_CHAIN;
+ break;
+ case 3:
+ regulatory->max_power_level += INCREASE_MAXPOW_BY_THREE_CHAIN;
+ break;
+ default:
+ ath_print(common, ATH_DBG_EEPROM,
+ "Invalid chainmask configuration\n");
+ break;
+ }
+}
+
int ath9k_hw_eeprom_init(struct ath_hw *ah)
{
int status;
diff --git a/drivers/net/wireless/ath/ath9k/eeprom.h b/drivers/net/wireless/ath/ath9k/eeprom.h
index 21354c15a9a..8750c558c22 100644
--- a/drivers/net/wireless/ath/ath9k/eeprom.h
+++ b/drivers/net/wireless/ath/ath9k/eeprom.h
@@ -263,7 +263,8 @@ enum eeprom_param {
EEP_PWR_TABLE_OFFSET,
EEP_DRIVE_STRENGTH,
EEP_INTERNAL_REGULATOR,
- EEP_SWREG
+ EEP_SWREG,
+ EEP_PAPRD,
};
enum ar5416_rates {
@@ -669,7 +670,7 @@ struct eeprom_ops {
int (*get_eeprom_ver)(struct ath_hw *hw);
int (*get_eeprom_rev)(struct ath_hw *hw);
u8 (*get_num_ant_config)(struct ath_hw *hw, enum ieee80211_band band);
- u16 (*get_eeprom_antenna_cfg)(struct ath_hw *hw,
+ u32 (*get_eeprom_antenna_cfg)(struct ath_hw *hw,
struct ath9k_channel *chan);
void (*set_board_values)(struct ath_hw *hw, struct ath9k_channel *chan);
void (*set_addac)(struct ath_hw *hw, struct ath9k_channel *chan);
@@ -679,6 +680,7 @@ struct eeprom_ops {
u16 (*get_spur_channel)(struct ath_hw *ah, u16 i, bool is2GHz);
};
+void ath9k_hw_analog_shift_regwrite(struct ath_hw *ah, u32 reg, u32 val);
void ath9k_hw_analog_shift_rmw(struct ath_hw *ah, u32 reg, u32 mask,
u32 shift, u32 val);
int16_t ath9k_hw_interpolate(u16 target, u16 srcLeft, u16 srcRight,
@@ -704,6 +706,7 @@ void ath9k_hw_get_target_powers(struct ath_hw *ah,
u16 numRates, bool isHt40Target);
u16 ath9k_hw_get_max_edge_power(u16 freq, struct cal_ctl_edges *pRdEdgesPower,
bool is2GHz, int num_band_edges);
+void ath9k_hw_update_regulatory_maxpower(struct ath_hw *ah);
int ath9k_hw_eeprom_init(struct ath_hw *ah);
#define ar5416_get_ntxchains(_txchainmask) \
diff --git a/drivers/net/wireless/ath/ath9k/eeprom_4k.c b/drivers/net/wireless/ath/ath9k/eeprom_4k.c
index 41a77d1bd43..9cccd12e8f2 100644
--- a/drivers/net/wireless/ath/ath9k/eeprom_4k.c
+++ b/drivers/net/wireless/ath/ath9k/eeprom_4k.c
@@ -222,7 +222,7 @@ static void ath9k_hw_get_4k_gain_boundaries_pdadcs(struct ath_hw *ah,
struct ath9k_channel *chan,
struct cal_data_per_freq_4k *pRawDataSet,
u8 *bChans, u16 availPiers,
- u16 tPdGainOverlap, int16_t *pMinCalPower,
+ u16 tPdGainOverlap,
u16 *pPdGainBoundaries, u8 *pPDADCValues,
u16 numXpdGains)
{
@@ -249,6 +249,7 @@ static void ath9k_hw_get_4k_gain_boundaries_pdadcs(struct ath_hw *ah,
struct chan_centers centers;
#define PD_GAIN_BOUNDARY_DEFAULT 58;
+ memset(&minPwrT4, 0, AR9287_NUM_PD_GAINS);
ath9k_hw_get_channel_centers(ah, chan, &centers);
for (numPiers = 0; numPiers < availPiers; numPiers++) {
@@ -307,8 +308,6 @@ static void ath9k_hw_get_4k_gain_boundaries_pdadcs(struct ath_hw *ah,
}
}
- *pMinCalPower = (int16_t)(minPwrT4[0] / 2);
-
k = 0;
for (i = 0; i < numXpdGains; i++) {
@@ -398,7 +397,6 @@ static void ath9k_hw_set_4k_power_cal_table(struct ath_hw *ah,
static u8 pdadcValues[AR5416_NUM_PDADC_VALUES];
u16 gainBoundaries[AR5416_EEP4K_PD_GAINS_IN_MASK];
u16 numPiers, i, j;
- int16_t tMinCalPower;
u16 numXpdGain, xpdMask;
u16 xpdGainValues[AR5416_EEP4K_NUM_PD_GAINS] = { 0, 0 };
u32 reg32, regOffset, regChainOffset;
@@ -451,7 +449,7 @@ static void ath9k_hw_set_4k_power_cal_table(struct ath_hw *ah,
ath9k_hw_get_4k_gain_boundaries_pdadcs(ah, chan,
pRawDataset, pCalBChans,
numPiers, pdGainOverlap_t2,
- &tMinCalPower, gainBoundaries,
+ gainBoundaries,
pdadcValues, numXpdGain);
ENABLE_REGWRITE_BUFFER(ah);
@@ -1149,13 +1147,13 @@ static void ath9k_hw_4k_set_board_values(struct ath_hw *ah,
}
}
-static u16 ath9k_hw_4k_get_eeprom_antenna_cfg(struct ath_hw *ah,
+static u32 ath9k_hw_4k_get_eeprom_antenna_cfg(struct ath_hw *ah,
struct ath9k_channel *chan)
{
struct ar5416_eeprom_4k *eep = &ah->eeprom.map4k;
struct modal_eep_4k_header *pModal = &eep->modalHeader;
- return pModal->antCtrlCommon & 0xFFFF;
+ return pModal->antCtrlCommon;
}
static u8 ath9k_hw_4k_get_num_ant_config(struct ath_hw *ah,
diff --git a/drivers/net/wireless/ath/ath9k/eeprom_9287.c b/drivers/net/wireless/ath/ath9k/eeprom_9287.c
index b471db5fb82..4a52cf03808 100644
--- a/drivers/net/wireless/ath/ath9k/eeprom_9287.c
+++ b/drivers/net/wireless/ath/ath9k/eeprom_9287.c
@@ -17,17 +17,19 @@
#include "hw.h"
#include "ar9002_phy.h"
-static int ath9k_hw_AR9287_get_eeprom_ver(struct ath_hw *ah)
+#define NUM_EEP_WORDS (sizeof(struct ar9287_eeprom) / sizeof(u16))
+
+static int ath9k_hw_ar9287_get_eeprom_ver(struct ath_hw *ah)
{
return (ah->eeprom.map9287.baseEepHeader.version >> 12) & 0xF;
}
-static int ath9k_hw_AR9287_get_eeprom_rev(struct ath_hw *ah)
+static int ath9k_hw_ar9287_get_eeprom_rev(struct ath_hw *ah)
{
return (ah->eeprom.map9287.baseEepHeader.version) & 0xFFF;
}
-static bool ath9k_hw_AR9287_fill_eeprom(struct ath_hw *ah)
+static bool ath9k_hw_ar9287_fill_eeprom(struct ath_hw *ah)
{
struct ar9287_eeprom *eep = &ah->eeprom.map9287;
struct ath_common *common = ath9k_hw_common(ah);
@@ -40,20 +42,20 @@ static bool ath9k_hw_AR9287_fill_eeprom(struct ath_hw *ah)
"Reading from EEPROM, not flash\n");
}
- for (addr = 0; addr < sizeof(struct ar9287_eeprom) / sizeof(u16);
- addr++) {
- if (!ath9k_hw_nvram_read(common,
- addr + eep_start_loc, eep_data)) {
+ for (addr = 0; addr < NUM_EEP_WORDS; addr++) {
+ if (!ath9k_hw_nvram_read(common, addr + eep_start_loc,
+ eep_data)) {
ath_print(common, ATH_DBG_EEPROM,
"Unable to read eeprom region\n");
return false;
}
eep_data++;
}
+
return true;
}
-static int ath9k_hw_AR9287_check_eeprom(struct ath_hw *ah)
+static int ath9k_hw_ar9287_check_eeprom(struct ath_hw *ah)
{
u32 sum = 0, el, integer;
u16 temp, word, magic, magic2, *eepdata;
@@ -63,8 +65,8 @@ static int ath9k_hw_AR9287_check_eeprom(struct ath_hw *ah)
struct ath_common *common = ath9k_hw_common(ah);
if (!ath9k_hw_use_flash(ah)) {
- if (!ath9k_hw_nvram_read(common,
- AR5416_EEPROM_MAGIC_OFFSET, &magic)) {
+ if (!ath9k_hw_nvram_read(common, AR5416_EEPROM_MAGIC_OFFSET,
+ &magic)) {
ath_print(common, ATH_DBG_FATAL,
"Reading Magic # failed\n");
return false;
@@ -72,6 +74,7 @@ static int ath9k_hw_AR9287_check_eeprom(struct ath_hw *ah)
ath_print(common, ATH_DBG_EEPROM,
"Read Magic = 0x%04X\n", magic);
+
if (magic != AR5416_EEPROM_MAGIC) {
magic2 = swab16(magic);
@@ -79,9 +82,7 @@ static int ath9k_hw_AR9287_check_eeprom(struct ath_hw *ah)
need_swap = true;
eepdata = (u16 *)(&ah->eeprom);
- for (addr = 0;
- addr < sizeof(struct ar9287_eeprom) / sizeof(u16);
- addr++) {
+ for (addr = 0; addr < NUM_EEP_WORDS; addr++) {
temp = swab16(*eepdata);
*eepdata = temp;
eepdata++;
@@ -89,13 +90,14 @@ static int ath9k_hw_AR9287_check_eeprom(struct ath_hw *ah)
} else {
ath_print(common, ATH_DBG_FATAL,
"Invalid EEPROM Magic. "
- "endianness mismatch.\n");
+ "Endianness mismatch.\n");
return -EINVAL;
}
}
}
- ath_print(common, ATH_DBG_EEPROM, "need_swap = %s.\n", need_swap ?
- "True" : "False");
+
+ ath_print(common, ATH_DBG_EEPROM, "need_swap = %s.\n",
+ need_swap ? "True" : "False");
if (need_swap)
el = swab16(ah->eeprom.map9287.baseEepHeader.length);
@@ -108,6 +110,7 @@ static int ath9k_hw_AR9287_check_eeprom(struct ath_hw *ah)
el = el / sizeof(u16);
eepdata = (u16 *)(&ah->eeprom);
+
for (i = 0; i < el; i++)
sum ^= *eepdata++;
@@ -161,7 +164,7 @@ static int ath9k_hw_AR9287_check_eeprom(struct ath_hw *ah)
return 0;
}
-static u32 ath9k_hw_AR9287_get_eeprom(struct ath_hw *ah,
+static u32 ath9k_hw_ar9287_get_eeprom(struct ath_hw *ah,
enum eeprom_param param)
{
struct ar9287_eeprom *eep = &ah->eeprom.map9287;
@@ -170,6 +173,7 @@ static u32 ath9k_hw_AR9287_get_eeprom(struct ath_hw *ah,
u16 ver_minor;
ver_minor = pBase->version & AR9287_EEP_VER_MINOR_MASK;
+
switch (param) {
case EEP_NFTHRESH_2:
return pModal->noiseFloorThreshCh[0];
@@ -214,29 +218,29 @@ static u32 ath9k_hw_AR9287_get_eeprom(struct ath_hw *ah,
}
}
-
-static void ath9k_hw_get_AR9287_gain_boundaries_pdadcs(struct ath_hw *ah,
- struct ath9k_channel *chan,
- struct cal_data_per_freq_ar9287 *pRawDataSet,
- u8 *bChans, u16 availPiers,
- u16 tPdGainOverlap, int16_t *pMinCalPower,
- u16 *pPdGainBoundaries, u8 *pPDADCValues,
- u16 numXpdGains)
+static void ath9k_hw_get_ar9287_gain_boundaries_pdadcs(struct ath_hw *ah,
+ struct ath9k_channel *chan,
+ struct cal_data_per_freq_ar9287 *pRawDataSet,
+ u8 *bChans, u16 availPiers,
+ u16 tPdGainOverlap,
+ u16 *pPdGainBoundaries,
+ u8 *pPDADCValues,
+ u16 numXpdGains)
{
-#define TMP_VAL_VPD_TABLE \
+#define TMP_VAL_VPD_TABLE \
((vpdTableI[i][sizeCurrVpdTable - 1] + (ss - maxIndex + 1) * vpdStep));
- int i, j, k;
- int16_t ss;
- u16 idxL = 0, idxR = 0, numPiers;
- u8 *pVpdL, *pVpdR, *pPwrL, *pPwrR;
- u8 minPwrT4[AR9287_NUM_PD_GAINS];
- u8 maxPwrT4[AR9287_NUM_PD_GAINS];
- int16_t vpdStep;
- int16_t tmpVal;
- u16 sizeCurrVpdTable, maxIndex, tgtIndex;
- bool match;
- int16_t minDelta = 0;
+ int i, j, k;
+ int16_t ss;
+ u16 idxL = 0, idxR = 0, numPiers;
+ u8 *pVpdL, *pVpdR, *pPwrL, *pPwrR;
+ u8 minPwrT4[AR9287_NUM_PD_GAINS];
+ u8 maxPwrT4[AR9287_NUM_PD_GAINS];
+ int16_t vpdStep;
+ int16_t tmpVal;
+ u16 sizeCurrVpdTable, maxIndex, tgtIndex;
+ bool match;
+ int16_t minDelta = 0;
struct chan_centers centers;
static u8 vpdTableL[AR5416_EEP4K_NUM_PD_GAINS]
[AR5416_MAX_PWR_RANGE_IN_HALF_DB];
@@ -245,6 +249,7 @@ static void ath9k_hw_get_AR9287_gain_boundaries_pdadcs(struct ath_hw *ah,
static u8 vpdTableI[AR5416_EEP4K_NUM_PD_GAINS]
[AR5416_MAX_PWR_RANGE_IN_HALF_DB];
+ memset(&minPwrT4, 0, AR9287_NUM_PD_GAINS);
ath9k_hw_get_channel_centers(ah, chan, &centers);
for (numPiers = 0; numPiers < availPiers; numPiers++) {
@@ -253,18 +258,18 @@ static void ath9k_hw_get_AR9287_gain_boundaries_pdadcs(struct ath_hw *ah,
}
match = ath9k_hw_get_lower_upper_index(
- (u8)FREQ2FBIN(centers.synth_center,
- IS_CHAN_2GHZ(chan)), bChans, numPiers,
- &idxL, &idxR);
+ (u8)FREQ2FBIN(centers.synth_center, IS_CHAN_2GHZ(chan)),
+ bChans, numPiers, &idxL, &idxR);
if (match) {
for (i = 0; i < numXpdGains; i++) {
minPwrT4[i] = pRawDataSet[idxL].pwrPdg[i][0];
maxPwrT4[i] = pRawDataSet[idxL].pwrPdg[i][4];
ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i],
- pRawDataSet[idxL].pwrPdg[i],
- pRawDataSet[idxL].vpdPdg[i],
- AR9287_PD_GAIN_ICEPTS, vpdTableI[i]);
+ pRawDataSet[idxL].pwrPdg[i],
+ pRawDataSet[idxL].vpdPdg[i],
+ AR9287_PD_GAIN_ICEPTS,
+ vpdTableI[i]);
}
} else {
for (i = 0; i < numXpdGains; i++) {
@@ -275,61 +280,58 @@ static void ath9k_hw_get_AR9287_gain_boundaries_pdadcs(struct ath_hw *ah,
minPwrT4[i] = max(pPwrL[0], pPwrR[0]);
- maxPwrT4[i] =
- min(pPwrL[AR9287_PD_GAIN_ICEPTS - 1],
- pPwrR[AR9287_PD_GAIN_ICEPTS - 1]);
+ maxPwrT4[i] = min(pPwrL[AR9287_PD_GAIN_ICEPTS - 1],
+ pPwrR[AR9287_PD_GAIN_ICEPTS - 1]);
ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i],
- pPwrL, pVpdL,
- AR9287_PD_GAIN_ICEPTS,
- vpdTableL[i]);
+ pPwrL, pVpdL,
+ AR9287_PD_GAIN_ICEPTS,
+ vpdTableL[i]);
ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i],
- pPwrR, pVpdR,
- AR9287_PD_GAIN_ICEPTS,
- vpdTableR[i]);
+ pPwrR, pVpdR,
+ AR9287_PD_GAIN_ICEPTS,
+ vpdTableR[i]);
for (j = 0; j <= (maxPwrT4[i] - minPwrT4[i]) / 2; j++) {
- vpdTableI[i][j] =
- (u8)(ath9k_hw_interpolate((u16)
- FREQ2FBIN(centers. synth_center,
- IS_CHAN_2GHZ(chan)),
- bChans[idxL], bChans[idxR],
- vpdTableL[i][j], vpdTableR[i][j]));
+ vpdTableI[i][j] = (u8)(ath9k_hw_interpolate(
+ (u16)FREQ2FBIN(centers. synth_center,
+ IS_CHAN_2GHZ(chan)),
+ bChans[idxL], bChans[idxR],
+ vpdTableL[i][j], vpdTableR[i][j]));
}
}
}
- *pMinCalPower = (int16_t)(minPwrT4[0] / 2);
k = 0;
+
for (i = 0; i < numXpdGains; i++) {
if (i == (numXpdGains - 1))
- pPdGainBoundaries[i] = (u16)(maxPwrT4[i] / 2);
+ pPdGainBoundaries[i] =
+ (u16)(maxPwrT4[i] / 2);
else
- pPdGainBoundaries[i] = (u16)((maxPwrT4[i] +
- minPwrT4[i+1]) / 4);
+ pPdGainBoundaries[i] =
+ (u16)((maxPwrT4[i] + minPwrT4[i+1]) / 4);
pPdGainBoundaries[i] = min((u16)AR5416_MAX_RATE_POWER,
- pPdGainBoundaries[i]);
+ pPdGainBoundaries[i]);
- if ((i == 0) && !AR_SREV_5416_20_OR_LATER(ah)) {
- minDelta = pPdGainBoundaries[0] - 23;
- pPdGainBoundaries[0] = 23;
- } else
- minDelta = 0;
+ minDelta = 0;
if (i == 0) {
if (AR_SREV_9280_10_OR_LATER(ah))
ss = (int16_t)(0 - (minPwrT4[i] / 2));
else
ss = 0;
- } else
+ } else {
ss = (int16_t)((pPdGainBoundaries[i-1] -
- (minPwrT4[i] / 2)) -
+ (minPwrT4[i] / 2)) -
tPdGainOverlap + 1 + minDelta);
+ }
vpdStep = (int16_t)(vpdTableI[i][1] - vpdTableI[i][0]);
vpdStep = (int16_t)((vpdStep < 1) ? 1 : vpdStep);
+
while ((ss < 0) && (k < (AR9287_NUM_PDADC_VALUES - 1))) {
tmpVal = (int16_t)(vpdTableI[i][0] + ss * vpdStep);
pPDADCValues[k++] = (u8)((tmpVal < 0) ? 0 : tmpVal);
@@ -348,12 +350,13 @@ static void ath9k_hw_get_AR9287_gain_boundaries_pdadcs(struct ath_hw *ah,
vpdStep = (int16_t)(vpdTableI[i][sizeCurrVpdTable - 1] -
vpdTableI[i][sizeCurrVpdTable - 2]);
vpdStep = (int16_t)((vpdStep < 1) ? 1 : vpdStep);
+
if (tgtIndex > maxIndex) {
while ((ss <= tgtIndex) &&
(k < (AR9287_NUM_PDADC_VALUES - 1))) {
tmpVal = (int16_t) TMP_VAL_VPD_TABLE;
- pPDADCValues[k++] = (u8)((tmpVal > 255) ?
- 255 : tmpVal);
+ pPDADCValues[k++] =
+ (u8)((tmpVal > 255) ? 255 : tmpVal);
ss++;
}
}
@@ -375,10 +378,9 @@ static void ath9k_hw_get_AR9287_gain_boundaries_pdadcs(struct ath_hw *ah,
static void ar9287_eeprom_get_tx_gain_index(struct ath_hw *ah,
struct ath9k_channel *chan,
struct cal_data_op_loop_ar9287 *pRawDatasetOpLoop,
- u8 *pCalChans, u16 availPiers,
- int8_t *pPwr)
+ u8 *pCalChans, u16 availPiers, int8_t *pPwr)
{
- u16 idxL = 0, idxR = 0, numPiers;
+ u16 idxL = 0, idxR = 0, numPiers;
bool match;
struct chan_centers centers;
@@ -390,15 +392,14 @@ static void ar9287_eeprom_get_tx_gain_index(struct ath_hw *ah,
}
match = ath9k_hw_get_lower_upper_index(
- (u8)FREQ2FBIN(centers.synth_center, IS_CHAN_2GHZ(chan)),
- pCalChans, numPiers,
- &idxL, &idxR);
+ (u8)FREQ2FBIN(centers.synth_center, IS_CHAN_2GHZ(chan)),
+ pCalChans, numPiers, &idxL, &idxR);
if (match) {
*pPwr = (int8_t) pRawDatasetOpLoop[idxL].pwrPdg[0][0];
} else {
*pPwr = ((int8_t) pRawDatasetOpLoop[idxL].pwrPdg[0][0] +
- (int8_t) pRawDatasetOpLoop[idxR].pwrPdg[0][0])/2;
+ (int8_t) pRawDatasetOpLoop[idxR].pwrPdg[0][0])/2;
}
}
@@ -409,16 +410,22 @@ static void ar9287_eeprom_olpc_set_pdadcs(struct ath_hw *ah,
u32 tmpVal;
u32 a;
+ /* Enable OLPC for chain 0 */
+
tmpVal = REG_READ(ah, 0xa270);
tmpVal = tmpVal & 0xFCFFFFFF;
tmpVal = tmpVal | (0x3 << 24);
REG_WRITE(ah, 0xa270, tmpVal);
+ /* Enable OLPC for chain 1 */
+
tmpVal = REG_READ(ah, 0xb270);
tmpVal = tmpVal & 0xFCFFFFFF;
tmpVal = tmpVal | (0x3 << 24);
REG_WRITE(ah, 0xb270, tmpVal);
+ /* Write the OLPC ref power for chain 0 */
+
if (chain == 0) {
tmpVal = REG_READ(ah, 0xa398);
tmpVal = tmpVal & 0xff00ffff;
@@ -427,6 +434,8 @@ static void ar9287_eeprom_olpc_set_pdadcs(struct ath_hw *ah,
REG_WRITE(ah, 0xa398, tmpVal);
}
+ /* Write the OLPC ref power for chain 1 */
+
if (chain == 1) {
tmpVal = REG_READ(ah, 0xb398);
tmpVal = tmpVal & 0xff00ffff;
@@ -436,28 +445,28 @@ static void ar9287_eeprom_olpc_set_pdadcs(struct ath_hw *ah,
}
}
-static void ath9k_hw_set_AR9287_power_cal_table(struct ath_hw *ah,
+static void ath9k_hw_set_ar9287_power_cal_table(struct ath_hw *ah,
struct ath9k_channel *chan,
int16_t *pTxPowerIndexOffset)
{
- struct ath_common *common = ath9k_hw_common(ah);
struct cal_data_per_freq_ar9287 *pRawDataset;
struct cal_data_op_loop_ar9287 *pRawDatasetOpenLoop;
- u8 *pCalBChans = NULL;
+ u8 *pCalBChans = NULL;
u16 pdGainOverlap_t2;
- u8 pdadcValues[AR9287_NUM_PDADC_VALUES];
+ u8 pdadcValues[AR9287_NUM_PDADC_VALUES];
u16 gainBoundaries[AR9287_PD_GAINS_IN_MASK];
u16 numPiers = 0, i, j;
- int16_t tMinCalPower;
u16 numXpdGain, xpdMask;
u16 xpdGainValues[AR9287_NUM_PD_GAINS] = {0, 0, 0, 0};
- u32 reg32, regOffset, regChainOffset;
- int16_t modalIdx, diff = 0;
+ u32 reg32, regOffset, regChainOffset, regval;
+ int16_t modalIdx, diff = 0;
struct ar9287_eeprom *pEepData = &ah->eeprom.map9287;
+
modalIdx = IS_CHAN_2GHZ(chan) ? 1 : 0;
xpdMask = pEepData->modalHeader.xpdGain;
+
if ((pEepData->baseEepHeader.version & AR9287_EEP_VER_MINOR_MASK) >=
- AR9287_EEP_MINOR_VER_2)
+ AR9287_EEP_MINOR_VER_2)
pdGainOverlap_t2 = pEepData->modalHeader.pdGainOverlap;
else
pdGainOverlap_t2 = (u16)(MS(REG_READ(ah, AR_PHY_TPCRG5),
@@ -466,15 +475,16 @@ static void ath9k_hw_set_AR9287_power_cal_table(struct ath_hw *ah,
if (IS_CHAN_2GHZ(chan)) {
pCalBChans = pEepData->calFreqPier2G;
numPiers = AR9287_NUM_2G_CAL_PIERS;
- if (ath9k_hw_AR9287_get_eeprom(ah, EEP_OL_PWRCTRL)) {
+ if (ath9k_hw_ar9287_get_eeprom(ah, EEP_OL_PWRCTRL)) {
pRawDatasetOpenLoop =
- (struct cal_data_op_loop_ar9287 *)
- pEepData->calPierData2G[0];
+ (struct cal_data_op_loop_ar9287 *)pEepData->calPierData2G[0];
ah->initPDADC = pRawDatasetOpenLoop->vpdPdg[0][0];
}
}
numXpdGain = 0;
+
+ /* Calculate the value of xpdgains from the xpdGain Mask */
for (i = 1; i <= AR9287_PD_GAINS_IN_MASK; i++) {
if ((xpdMask >> (AR9287_PD_GAINS_IN_MASK - i)) & 1) {
if (numXpdGain >= AR9287_NUM_PD_GAINS)
@@ -496,99 +506,79 @@ static void ath9k_hw_set_AR9287_power_cal_table(struct ath_hw *ah,
for (i = 0; i < AR9287_MAX_CHAINS; i++) {
regChainOffset = i * 0x1000;
+
if (pEepData->baseEepHeader.txMask & (1 << i)) {
- pRawDatasetOpenLoop = (struct cal_data_op_loop_ar9287 *)
- pEepData->calPierData2G[i];
- if (ath9k_hw_AR9287_get_eeprom(ah, EEP_OL_PWRCTRL)) {
+ pRawDatasetOpenLoop =
+ (struct cal_data_op_loop_ar9287 *)pEepData->calPierData2G[i];
+
+ if (ath9k_hw_ar9287_get_eeprom(ah, EEP_OL_PWRCTRL)) {
int8_t txPower;
ar9287_eeprom_get_tx_gain_index(ah, chan,
- pRawDatasetOpenLoop,
- pCalBChans, numPiers,
- &txPower);
+ pRawDatasetOpenLoop,
+ pCalBChans, numPiers,
+ &txPower);
ar9287_eeprom_olpc_set_pdadcs(ah, txPower, i);
} else {
pRawDataset =
(struct cal_data_per_freq_ar9287 *)
pEepData->calPierData2G[i];
- ath9k_hw_get_AR9287_gain_boundaries_pdadcs(
- ah, chan, pRawDataset,
- pCalBChans, numPiers,
- pdGainOverlap_t2,
- &tMinCalPower, gainBoundaries,
- pdadcValues, numXpdGain);
+
+ ath9k_hw_get_ar9287_gain_boundaries_pdadcs(ah, chan,
+ pRawDataset,
+ pCalBChans, numPiers,
+ pdGainOverlap_t2,
+ gainBoundaries,
+ pdadcValues,
+ numXpdGain);
}
if (i == 0) {
- if (!ath9k_hw_AR9287_get_eeprom(
- ah, EEP_OL_PWRCTRL)) {
- REG_WRITE(ah, AR_PHY_TPCRG5 +
- regChainOffset,
- SM(pdGainOverlap_t2,
- AR_PHY_TPCRG5_PD_GAIN_OVERLAP) |
- SM(gainBoundaries[0],
- AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_1)
- | SM(gainBoundaries[1],
- AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_2)
- | SM(gainBoundaries[2],
- AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_3)
- | SM(gainBoundaries[3],
- AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_4));
+ if (!ath9k_hw_ar9287_get_eeprom(ah,
+ EEP_OL_PWRCTRL)) {
+
+ regval = SM(pdGainOverlap_t2,
+ AR_PHY_TPCRG5_PD_GAIN_OVERLAP)
+ | SM(gainBoundaries[0],
+ AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_1)
+ | SM(gainBoundaries[1],
+ AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_2)
+ | SM(gainBoundaries[2],
+ AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_3)
+ | SM(gainBoundaries[3],
+ AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_4);
+
+ REG_WRITE(ah,
+ AR_PHY_TPCRG5 + regChainOffset,
+ regval);
}
}
if ((int32_t)AR9287_PWR_TABLE_OFFSET_DB !=
- pEepData->baseEepHeader.pwrTableOffset) {
- diff = (u16)
- (pEepData->baseEepHeader.pwrTableOffset
- - (int32_t)AR9287_PWR_TABLE_OFFSET_DB);
+ pEepData->baseEepHeader.pwrTableOffset) {
+ diff = (u16)(pEepData->baseEepHeader.pwrTableOffset -
+ (int32_t)AR9287_PWR_TABLE_OFFSET_DB);
diff *= 2;
- for (j = 0;
- j < ((u16)AR9287_NUM_PDADC_VALUES-diff);
- j++)
+ for (j = 0; j < ((u16)AR9287_NUM_PDADC_VALUES-diff); j++)
pdadcValues[j] = pdadcValues[j+diff];
for (j = (u16)(AR9287_NUM_PDADC_VALUES-diff);
j < AR9287_NUM_PDADC_VALUES; j++)
pdadcValues[j] =
- pdadcValues[
- AR9287_NUM_PDADC_VALUES-diff];
+ pdadcValues[AR9287_NUM_PDADC_VALUES-diff];
}
- if (!ath9k_hw_AR9287_get_eeprom(ah, EEP_OL_PWRCTRL)) {
- regOffset = AR_PHY_BASE + (672 << 2) +
- regChainOffset;
- for (j = 0; j < 32; j++) {
- reg32 = ((pdadcValues[4*j + 0]
- & 0xFF) << 0) |
- ((pdadcValues[4*j + 1]
- & 0xFF) << 8) |
- ((pdadcValues[4*j + 2]
- & 0xFF) << 16) |
- ((pdadcValues[4*j + 3]
- & 0xFF) << 24) ;
- REG_WRITE(ah, regOffset, reg32);
+ if (!ath9k_hw_ar9287_get_eeprom(ah, EEP_OL_PWRCTRL)) {
+ regOffset = AR_PHY_BASE +
+ (672 << 2) + regChainOffset;
- ath_print(common, ATH_DBG_EEPROM,
- "PDADC (%d,%4x): %4.4x "
- "%8.8x\n",
- i, regChainOffset, regOffset,
- reg32);
-
- ath_print(common, ATH_DBG_EEPROM,
- "PDADC: Chain %d | "
- "PDADC %3d Value %3d | "
- "PDADC %3d Value %3d | "
- "PDADC %3d Value %3d | "
- "PDADC %3d Value %3d |\n",
- i, 4 * j, pdadcValues[4 * j],
- 4 * j + 1,
- pdadcValues[4 * j + 1],
- 4 * j + 2,
- pdadcValues[4 * j + 2],
- 4 * j + 3,
- pdadcValues[4 * j + 3]);
+ for (j = 0; j < 32; j++) {
+ reg32 = ((pdadcValues[4*j + 0] & 0xFF) << 0)
+ | ((pdadcValues[4*j + 1] & 0xFF) << 8)
+ | ((pdadcValues[4*j + 2] & 0xFF) << 16)
+ | ((pdadcValues[4*j + 3] & 0xFF) << 24);
+ REG_WRITE(ah, regOffset, reg32);
regOffset += 4;
}
}
@@ -598,30 +588,45 @@ static void ath9k_hw_set_AR9287_power_cal_table(struct ath_hw *ah,
*pTxPowerIndexOffset = 0;
}
-static void ath9k_hw_set_AR9287_power_per_rate_table(struct ath_hw *ah,
- struct ath9k_channel *chan, int16_t *ratesArray, u16 cfgCtl,
- u16 AntennaReduction, u16 twiceMaxRegulatoryPower,
- u16 powerLimit)
+static void ath9k_hw_set_ar9287_power_per_rate_table(struct ath_hw *ah,
+ struct ath9k_channel *chan,
+ int16_t *ratesArray,
+ u16 cfgCtl,
+ u16 AntennaReduction,
+ u16 twiceMaxRegulatoryPower,
+ u16 powerLimit)
{
+#define CMP_CTL \
+ (((cfgCtl & ~CTL_MODE_M) | (pCtlMode[ctlMode] & CTL_MODE_M)) == \
+ pEepData->ctlIndex[i])
+
+#define CMP_NO_CTL \
+ (((cfgCtl & ~CTL_MODE_M) | (pCtlMode[ctlMode] & CTL_MODE_M)) == \
+ ((pEepData->ctlIndex[i] & CTL_MODE_M) | SD_NO_CTL))
+
#define REDUCE_SCALED_POWER_BY_TWO_CHAIN 6
#define REDUCE_SCALED_POWER_BY_THREE_CHAIN 10
+
struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah);
u16 twiceMaxEdgePower = AR5416_MAX_RATE_POWER;
static const u16 tpScaleReductionTable[5] =
{ 0, 3, 6, 9, AR5416_MAX_RATE_POWER };
int i;
- int16_t twiceLargestAntenna;
+ int16_t twiceLargestAntenna;
struct cal_ctl_data_ar9287 *rep;
struct cal_target_power_leg targetPowerOfdm = {0, {0, 0, 0, 0} },
targetPowerCck = {0, {0, 0, 0, 0} };
struct cal_target_power_leg targetPowerOfdmExt = {0, {0, 0, 0, 0} },
targetPowerCckExt = {0, {0, 0, 0, 0} };
- struct cal_target_power_ht targetPowerHt20,
+ struct cal_target_power_ht targetPowerHt20,
targetPowerHt40 = {0, {0, 0, 0, 0} };
u16 scaledPower = 0, minCtlPower, maxRegAllowedPower;
- u16 ctlModesFor11g[] =
- {CTL_11B, CTL_11G, CTL_2GHT20,
- CTL_11B_EXT, CTL_11G_EXT, CTL_2GHT40};
+ u16 ctlModesFor11g[] = {CTL_11B,
+ CTL_11G,
+ CTL_2GHT20,
+ CTL_11B_EXT,
+ CTL_11G_EXT,
+ CTL_2GHT40};
u16 numCtlModes = 0, *pCtlMode = NULL, ctlMode, freq;
struct chan_centers centers;
int tx_chainmask;
@@ -631,19 +636,28 @@ static void ath9k_hw_set_AR9287_power_per_rate_table(struct ath_hw *ah,
ath9k_hw_get_channel_centers(ah, chan, &centers);
+ /* Compute TxPower reduction due to Antenna Gain */
twiceLargestAntenna = max(pEepData->modalHeader.antennaGainCh[0],
pEepData->modalHeader.antennaGainCh[1]);
+ twiceLargestAntenna = (int16_t)min((AntennaReduction) -
+ twiceLargestAntenna, 0);
- twiceLargestAntenna = (int16_t)min((AntennaReduction) -
- twiceLargestAntenna, 0);
-
+ /*
+ * scaledPower is the minimum of the user input power level
+ * and the regulatory allowed power level.
+ */
maxRegAllowedPower = twiceMaxRegulatoryPower + twiceLargestAntenna;
+
if (regulatory->tp_scale != ATH9K_TP_SCALE_MAX)
maxRegAllowedPower -=
(tpScaleReductionTable[(regulatory->tp_scale)] * 2);
scaledPower = min(powerLimit, maxRegAllowedPower);
+ /*
+ * Reduce scaled Power by number of chains active
+ * to get the per chain tx power level.
+ */
switch (ar5416_get_ntxchains(tx_chainmask)) {
case 1:
break;
@@ -656,9 +670,14 @@ static void ath9k_hw_set_AR9287_power_per_rate_table(struct ath_hw *ah,
}
scaledPower = max((u16)0, scaledPower);
+ /*
+ * Get TX power from EEPROM.
+ */
if (IS_CHAN_2GHZ(chan)) {
+ /* CTL_11B, CTL_11G, CTL_2GHT20 */
numCtlModes =
ARRAY_SIZE(ctlModesFor11g) - SUB_NUM_CTL_MODES_AT_2G_40;
+
pCtlMode = ctlModesFor11g;
ath9k_hw_get_legacy_target_powers(ah, chan,
@@ -675,6 +694,7 @@ static void ath9k_hw_set_AR9287_power_per_rate_table(struct ath_hw *ah,
&targetPowerHt20, 8, false);
if (IS_CHAN_HT40(chan)) {
+ /* All 2G CTLs */
numCtlModes = ARRAY_SIZE(ctlModesFor11g);
ath9k_hw_get_target_powers(ah, chan,
pEepData->calTargetPower2GHT40,
@@ -692,8 +712,9 @@ static void ath9k_hw_set_AR9287_power_per_rate_table(struct ath_hw *ah,
}
for (ctlMode = 0; ctlMode < numCtlModes; ctlMode++) {
- bool isHt40CtlMode = (pCtlMode[ctlMode] == CTL_5GHT40) ||
- (pCtlMode[ctlMode] == CTL_2GHT40);
+ bool isHt40CtlMode =
+ (pCtlMode[ctlMode] == CTL_2GHT40) ? true : false;
+
if (isHt40CtlMode)
freq = centers.synth_center;
else if (pCtlMode[ctlMode] & EXT_ADDITIVE)
@@ -701,31 +722,28 @@ static void ath9k_hw_set_AR9287_power_per_rate_table(struct ath_hw *ah,
else
freq = centers.ctl_center;
- if (ah->eep_ops->get_eeprom_ver(ah) == 14 &&
- ah->eep_ops->get_eeprom_rev(ah) <= 2)
- twiceMaxEdgePower = AR5416_MAX_RATE_POWER;
-
+ /* Walk through the CTL indices stored in EEPROM */
for (i = 0; (i < AR9287_NUM_CTLS) && pEepData->ctlIndex[i]; i++) {
- if ((((cfgCtl & ~CTL_MODE_M) |
- (pCtlMode[ctlMode] & CTL_MODE_M)) ==
- pEepData->ctlIndex[i]) ||
- (((cfgCtl & ~CTL_MODE_M) |
- (pCtlMode[ctlMode] & CTL_MODE_M)) ==
- ((pEepData->ctlIndex[i] &
- CTL_MODE_M) | SD_NO_CTL))) {
+ struct cal_ctl_edges *pRdEdgesPower;
+ /*
+ * Compare test group from regulatory channel list
+ * with test mode from pCtlMode list
+ */
+ if (CMP_CTL || CMP_NO_CTL) {
rep = &(pEepData->ctlData[i]);
- twiceMinEdgePower = ath9k_hw_get_max_edge_power(
- freq,
- rep->ctlEdges[ar5416_get_ntxchains(
- tx_chainmask) - 1],
- IS_CHAN_2GHZ(chan), AR5416_NUM_BAND_EDGES);
-
- if ((cfgCtl & ~CTL_MODE_M) == SD_NO_CTL)
- twiceMaxEdgePower = min(
- twiceMaxEdgePower,
- twiceMinEdgePower);
- else {
+ pRdEdgesPower =
+ rep->ctlEdges[ar5416_get_ntxchains(tx_chainmask) - 1];
+
+ twiceMinEdgePower = ath9k_hw_get_max_edge_power(freq,
+ pRdEdgesPower,
+ IS_CHAN_2GHZ(chan),
+ AR5416_NUM_BAND_EDGES);
+
+ if ((cfgCtl & ~CTL_MODE_M) == SD_NO_CTL) {
+ twiceMaxEdgePower = min(twiceMaxEdgePower,
+ twiceMinEdgePower);
+ } else {
twiceMaxEdgePower = twiceMinEdgePower;
break;
}
@@ -734,55 +752,48 @@ static void ath9k_hw_set_AR9287_power_per_rate_table(struct ath_hw *ah,
minCtlPower = (u8)min(twiceMaxEdgePower, scaledPower);
+ /* Apply ctl mode to correct target power set */
switch (pCtlMode[ctlMode]) {
case CTL_11B:
- for (i = 0;
- i < ARRAY_SIZE(targetPowerCck.tPow2x);
- i++) {
- targetPowerCck.tPow2x[i] = (u8)min(
- (u16)targetPowerCck.tPow2x[i],
- minCtlPower);
+ for (i = 0; i < ARRAY_SIZE(targetPowerCck.tPow2x); i++) {
+ targetPowerCck.tPow2x[i] =
+ (u8)min((u16)targetPowerCck.tPow2x[i],
+ minCtlPower);
}
break;
case CTL_11A:
case CTL_11G:
- for (i = 0;
- i < ARRAY_SIZE(targetPowerOfdm.tPow2x);
- i++) {
- targetPowerOfdm.tPow2x[i] = (u8)min(
- (u16)targetPowerOfdm.tPow2x[i],
- minCtlPower);
+ for (i = 0; i < ARRAY_SIZE(targetPowerOfdm.tPow2x); i++) {
+ targetPowerOfdm.tPow2x[i] =
+ (u8)min((u16)targetPowerOfdm.tPow2x[i],
+ minCtlPower);
}
break;
case CTL_5GHT20:
case CTL_2GHT20:
- for (i = 0;
- i < ARRAY_SIZE(targetPowerHt20.tPow2x);
- i++) {
- targetPowerHt20.tPow2x[i] = (u8)min(
- (u16)targetPowerHt20.tPow2x[i],
- minCtlPower);
+ for (i = 0; i < ARRAY_SIZE(targetPowerHt20.tPow2x); i++) {
+ targetPowerHt20.tPow2x[i] =
+ (u8)min((u16)targetPowerHt20.tPow2x[i],
+ minCtlPower);
}
break;
case CTL_11B_EXT:
- targetPowerCckExt.tPow2x[0] = (u8)min(
- (u16)targetPowerCckExt.tPow2x[0],
- minCtlPower);
+ targetPowerCckExt.tPow2x[0] =
+ (u8)min((u16)targetPowerCckExt.tPow2x[0],
+ minCtlPower);
break;
case CTL_11A_EXT:
case CTL_11G_EXT:
- targetPowerOfdmExt.tPow2x[0] = (u8)min(
- (u16)targetPowerOfdmExt.tPow2x[0],
- minCtlPower);
+ targetPowerOfdmExt.tPow2x[0] =
+ (u8)min((u16)targetPowerOfdmExt.tPow2x[0],
+ minCtlPower);
break;
case CTL_5GHT40:
case CTL_2GHT40:
- for (i = 0;
- i < ARRAY_SIZE(targetPowerHt40.tPow2x);
- i++) {
- targetPowerHt40.tPow2x[i] = (u8)min(
- (u16)targetPowerHt40.tPow2x[i],
- minCtlPower);
+ for (i = 0; i < ARRAY_SIZE(targetPowerHt40.tPow2x); i++) {
+ targetPowerHt40.tPow2x[i] =
+ (u8)min((u16)targetPowerHt40.tPow2x[i],
+ minCtlPower);
}
break;
default:
@@ -790,12 +801,13 @@ static void ath9k_hw_set_AR9287_power_per_rate_table(struct ath_hw *ah,
}
}
+ /* Now set the rates array */
+
ratesArray[rate6mb] =
ratesArray[rate9mb] =
ratesArray[rate12mb] =
ratesArray[rate18mb] =
- ratesArray[rate24mb] =
- targetPowerOfdm.tPow2x[0];
+ ratesArray[rate24mb] = targetPowerOfdm.tPow2x[0];
ratesArray[rate36mb] = targetPowerOfdm.tPow2x[1];
ratesArray[rate48mb] = targetPowerOfdm.tPow2x[2];
@@ -807,12 +819,12 @@ static void ath9k_hw_set_AR9287_power_per_rate_table(struct ath_hw *ah,
if (IS_CHAN_2GHZ(chan)) {
ratesArray[rate1l] = targetPowerCck.tPow2x[0];
- ratesArray[rate2s] = ratesArray[rate2l] =
- targetPowerCck.tPow2x[1];
- ratesArray[rate5_5s] = ratesArray[rate5_5l] =
- targetPowerCck.tPow2x[2];
- ratesArray[rate11s] = ratesArray[rate11l] =
- targetPowerCck.tPow2x[3];
+ ratesArray[rate2s] =
+ ratesArray[rate2l] = targetPowerCck.tPow2x[1];
+ ratesArray[rate5_5s] =
+ ratesArray[rate5_5l] = targetPowerCck.tPow2x[2];
+ ratesArray[rate11s] =
+ ratesArray[rate11l] = targetPowerCck.tPow2x[3];
}
if (IS_CHAN_HT40(chan)) {
for (i = 0; i < ARRAY_SIZE(targetPowerHt40.tPow2x); i++)
@@ -821,28 +833,28 @@ static void ath9k_hw_set_AR9287_power_per_rate_table(struct ath_hw *ah,
ratesArray[rateDupOfdm] = targetPowerHt40.tPow2x[0];
ratesArray[rateDupCck] = targetPowerHt40.tPow2x[0];
ratesArray[rateExtOfdm] = targetPowerOfdmExt.tPow2x[0];
+
if (IS_CHAN_2GHZ(chan))
ratesArray[rateExtCck] = targetPowerCckExt.tPow2x[0];
}
+#undef CMP_CTL
+#undef CMP_NO_CTL
#undef REDUCE_SCALED_POWER_BY_TWO_CHAIN
#undef REDUCE_SCALED_POWER_BY_THREE_CHAIN
}
-static void ath9k_hw_AR9287_set_txpower(struct ath_hw *ah,
+static void ath9k_hw_ar9287_set_txpower(struct ath_hw *ah,
struct ath9k_channel *chan, u16 cfgCtl,
u8 twiceAntennaReduction,
u8 twiceMaxRegulatoryPower,
u8 powerLimit)
{
-#define INCREASE_MAXPOW_BY_TWO_CHAIN 6
-#define INCREASE_MAXPOW_BY_THREE_CHAIN 10
- struct ath_common *common = ath9k_hw_common(ah);
struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah);
struct ar9287_eeprom *pEepData = &ah->eeprom.map9287;
struct modal_eep_ar9287_header *pModal = &pEepData->modalHeader;
int16_t ratesArray[Ar5416RateSize];
- int16_t txPowerIndexOffset = 0;
+ int16_t txPowerIndexOffset = 0;
u8 ht40PowerIncForPdadc = 2;
int i;
@@ -852,13 +864,13 @@ static void ath9k_hw_AR9287_set_txpower(struct ath_hw *ah,
AR9287_EEP_MINOR_VER_2)
ht40PowerIncForPdadc = pModal->ht40PowerIncForPdadc;
- ath9k_hw_set_AR9287_power_per_rate_table(ah, chan,
+ ath9k_hw_set_ar9287_power_per_rate_table(ah, chan,
&ratesArray[0], cfgCtl,
twiceAntennaReduction,
twiceMaxRegulatoryPower,
powerLimit);
- ath9k_hw_set_AR9287_power_cal_table(ah, chan, &txPowerIndexOffset);
+ ath9k_hw_set_ar9287_power_cal_table(ah, chan, &txPowerIndexOffset);
for (i = 0; i < ARRAY_SIZE(ratesArray); i++) {
ratesArray[i] = (int16_t)(txPowerIndexOffset + ratesArray[i]);
@@ -871,6 +883,7 @@ static void ath9k_hw_AR9287_set_txpower(struct ath_hw *ah,
ratesArray[i] -= AR9287_PWR_TABLE_OFFSET_DB * 2;
}
+ /* OFDM power per rate */
REG_WRITE(ah, AR_PHY_POWER_TX_RATE1,
ATH9K_POW_SM(ratesArray[rate18mb], 24)
| ATH9K_POW_SM(ratesArray[rate12mb], 16)
@@ -883,6 +896,7 @@ static void ath9k_hw_AR9287_set_txpower(struct ath_hw *ah,
| ATH9K_POW_SM(ratesArray[rate36mb], 8)
| ATH9K_POW_SM(ratesArray[rate24mb], 0));
+ /* CCK power per rate */
if (IS_CHAN_2GHZ(chan)) {
REG_WRITE(ah, AR_PHY_POWER_TX_RATE3,
ATH9K_POW_SM(ratesArray[rate2s], 24)
@@ -896,6 +910,7 @@ static void ath9k_hw_AR9287_set_txpower(struct ath_hw *ah,
| ATH9K_POW_SM(ratesArray[rate5_5l], 0));
}
+ /* HT20 power per rate */
REG_WRITE(ah, AR_PHY_POWER_TX_RATE5,
ATH9K_POW_SM(ratesArray[rateHt20_3], 24)
| ATH9K_POW_SM(ratesArray[rateHt20_2], 16)
@@ -908,8 +923,9 @@ static void ath9k_hw_AR9287_set_txpower(struct ath_hw *ah,
| ATH9K_POW_SM(ratesArray[rateHt20_5], 8)
| ATH9K_POW_SM(ratesArray[rateHt20_4], 0));
+ /* HT40 power per rate */
if (IS_CHAN_HT40(chan)) {
- if (ath9k_hw_AR9287_get_eeprom(ah, EEP_OL_PWRCTRL)) {
+ if (ath9k_hw_ar9287_get_eeprom(ah, EEP_OL_PWRCTRL)) {
REG_WRITE(ah, AR_PHY_POWER_TX_RATE7,
ATH9K_POW_SM(ratesArray[rateHt40_3], 24)
| ATH9K_POW_SM(ratesArray[rateHt40_2], 16)
@@ -943,6 +959,7 @@ static void ath9k_hw_AR9287_set_txpower(struct ath_hw *ah,
ht40PowerIncForPdadc, 0));
}
+ /* Dup/Ext power per rate */
REG_WRITE(ah, AR_PHY_POWER_TX_RATE9,
ATH9K_POW_SM(ratesArray[rateExtOfdm], 24)
| ATH9K_POW_SM(ratesArray[rateExtCck], 16)
@@ -960,37 +977,20 @@ static void ath9k_hw_AR9287_set_txpower(struct ath_hw *ah,
ratesArray[i] + AR9287_PWR_TABLE_OFFSET_DB * 2;
else
regulatory->max_power_level = ratesArray[i];
-
- switch (ar5416_get_ntxchains(ah->txchainmask)) {
- case 1:
- break;
- case 2:
- regulatory->max_power_level +=
- INCREASE_MAXPOW_BY_TWO_CHAIN;
- break;
- case 3:
- regulatory->max_power_level +=
- INCREASE_MAXPOW_BY_THREE_CHAIN;
- break;
- default:
- ath_print(common, ATH_DBG_EEPROM,
- "Invalid chainmask configuration\n");
- break;
- }
}
-static void ath9k_hw_AR9287_set_addac(struct ath_hw *ah,
+static void ath9k_hw_ar9287_set_addac(struct ath_hw *ah,
struct ath9k_channel *chan)
{
}
-static void ath9k_hw_AR9287_set_board_values(struct ath_hw *ah,
+static void ath9k_hw_ar9287_set_board_values(struct ath_hw *ah,
struct ath9k_channel *chan)
{
struct ar9287_eeprom *eep = &ah->eeprom.map9287;
struct modal_eep_ar9287_header *pModal = &eep->modalHeader;
u16 antWrites[AR9287_ANT_16S];
- u32 regChainOffset;
+ u32 regChainOffset, regval;
u8 txRxAttenLocal;
int i, j, offset_num;
@@ -1077,42 +1077,37 @@ static void ath9k_hw_AR9287_set_board_values(struct ath_hw *ah,
REG_RMW_FIELD(ah, AR_PHY_EXT_CCA0,
AR_PHY_EXT_CCA0_THRESH62, pModal->thresh62);
- ath9k_hw_analog_shift_rmw(ah, AR9287_AN_RF2G3_CH0, AR9287_AN_RF2G3_DB1,
- AR9287_AN_RF2G3_DB1_S, pModal->db1);
- ath9k_hw_analog_shift_rmw(ah, AR9287_AN_RF2G3_CH0, AR9287_AN_RF2G3_DB2,
- AR9287_AN_RF2G3_DB2_S, pModal->db2);
- ath9k_hw_analog_shift_rmw(ah, AR9287_AN_RF2G3_CH0,
- AR9287_AN_RF2G3_OB_CCK,
- AR9287_AN_RF2G3_OB_CCK_S, pModal->ob_cck);
- ath9k_hw_analog_shift_rmw(ah, AR9287_AN_RF2G3_CH0,
- AR9287_AN_RF2G3_OB_PSK,
- AR9287_AN_RF2G3_OB_PSK_S, pModal->ob_psk);
- ath9k_hw_analog_shift_rmw(ah, AR9287_AN_RF2G3_CH0,
- AR9287_AN_RF2G3_OB_QAM,
- AR9287_AN_RF2G3_OB_QAM_S, pModal->ob_qam);
- ath9k_hw_analog_shift_rmw(ah, AR9287_AN_RF2G3_CH0,
- AR9287_AN_RF2G3_OB_PAL_OFF,
- AR9287_AN_RF2G3_OB_PAL_OFF_S,
- pModal->ob_pal_off);
-
- ath9k_hw_analog_shift_rmw(ah, AR9287_AN_RF2G3_CH1,
- AR9287_AN_RF2G3_DB1, AR9287_AN_RF2G3_DB1_S,
- pModal->db1);
- ath9k_hw_analog_shift_rmw(ah, AR9287_AN_RF2G3_CH1, AR9287_AN_RF2G3_DB2,
- AR9287_AN_RF2G3_DB2_S, pModal->db2);
- ath9k_hw_analog_shift_rmw(ah, AR9287_AN_RF2G3_CH1,
- AR9287_AN_RF2G3_OB_CCK,
- AR9287_AN_RF2G3_OB_CCK_S, pModal->ob_cck);
- ath9k_hw_analog_shift_rmw(ah, AR9287_AN_RF2G3_CH1,
- AR9287_AN_RF2G3_OB_PSK,
- AR9287_AN_RF2G3_OB_PSK_S, pModal->ob_psk);
- ath9k_hw_analog_shift_rmw(ah, AR9287_AN_RF2G3_CH1,
- AR9287_AN_RF2G3_OB_QAM,
- AR9287_AN_RF2G3_OB_QAM_S, pModal->ob_qam);
- ath9k_hw_analog_shift_rmw(ah, AR9287_AN_RF2G3_CH1,
- AR9287_AN_RF2G3_OB_PAL_OFF,
- AR9287_AN_RF2G3_OB_PAL_OFF_S,
- pModal->ob_pal_off);
+ regval = REG_READ(ah, AR9287_AN_RF2G3_CH0);
+ regval &= ~(AR9287_AN_RF2G3_DB1 |
+ AR9287_AN_RF2G3_DB2 |
+ AR9287_AN_RF2G3_OB_CCK |
+ AR9287_AN_RF2G3_OB_PSK |
+ AR9287_AN_RF2G3_OB_QAM |
+ AR9287_AN_RF2G3_OB_PAL_OFF);
+ regval |= (SM(pModal->db1, AR9287_AN_RF2G3_DB1) |
+ SM(pModal->db2, AR9287_AN_RF2G3_DB2) |
+ SM(pModal->ob_cck, AR9287_AN_RF2G3_OB_CCK) |
+ SM(pModal->ob_psk, AR9287_AN_RF2G3_OB_PSK) |
+ SM(pModal->ob_qam, AR9287_AN_RF2G3_OB_QAM) |
+ SM(pModal->ob_pal_off, AR9287_AN_RF2G3_OB_PAL_OFF));
+
+ ath9k_hw_analog_shift_regwrite(ah, AR9287_AN_RF2G3_CH0, regval);
+
+ regval = REG_READ(ah, AR9287_AN_RF2G3_CH1);
+ regval &= ~(AR9287_AN_RF2G3_DB1 |
+ AR9287_AN_RF2G3_DB2 |
+ AR9287_AN_RF2G3_OB_CCK |
+ AR9287_AN_RF2G3_OB_PSK |
+ AR9287_AN_RF2G3_OB_QAM |
+ AR9287_AN_RF2G3_OB_PAL_OFF);
+ regval |= (SM(pModal->db1, AR9287_AN_RF2G3_DB1) |
+ SM(pModal->db2, AR9287_AN_RF2G3_DB2) |
+ SM(pModal->ob_cck, AR9287_AN_RF2G3_OB_CCK) |
+ SM(pModal->ob_psk, AR9287_AN_RF2G3_OB_PSK) |
+ SM(pModal->ob_qam, AR9287_AN_RF2G3_OB_QAM) |
+ SM(pModal->ob_pal_off, AR9287_AN_RF2G3_OB_PAL_OFF));
+
+ ath9k_hw_analog_shift_regwrite(ah, AR9287_AN_RF2G3_CH1, regval);
REG_RMW_FIELD(ah, AR_PHY_RF_CTL2,
AR_PHY_TX_END_DATA_START, pModal->txFrameToDataStart);
@@ -1125,26 +1120,27 @@ static void ath9k_hw_AR9287_set_board_values(struct ath_hw *ah,
pModal->xpaBiasLvl);
}
-static u8 ath9k_hw_AR9287_get_num_ant_config(struct ath_hw *ah,
+static u8 ath9k_hw_ar9287_get_num_ant_config(struct ath_hw *ah,
enum ieee80211_band freq_band)
{
return 1;
}
-static u16 ath9k_hw_AR9287_get_eeprom_antenna_cfg(struct ath_hw *ah,
+static u32 ath9k_hw_ar9287_get_eeprom_antenna_cfg(struct ath_hw *ah,
struct ath9k_channel *chan)
{
struct ar9287_eeprom *eep = &ah->eeprom.map9287;
struct modal_eep_ar9287_header *pModal = &eep->modalHeader;
- return pModal->antCtrlCommon & 0xFFFF;
+ return pModal->antCtrlCommon;
}
-static u16 ath9k_hw_AR9287_get_spur_channel(struct ath_hw *ah,
+static u16 ath9k_hw_ar9287_get_spur_channel(struct ath_hw *ah,
u16 i, bool is2GHz)
{
#define EEP_MAP9287_SPURCHAN \
(ah->eeprom.map9287.modalHeader.spurChans[i].spurChan)
+
struct ath_common *common = ath9k_hw_common(ah);
u16 spur_val = AR_NO_SPUR;
@@ -1171,15 +1167,15 @@ static u16 ath9k_hw_AR9287_get_spur_channel(struct ath_hw *ah,
}
const struct eeprom_ops eep_ar9287_ops = {
- .check_eeprom = ath9k_hw_AR9287_check_eeprom,
- .get_eeprom = ath9k_hw_AR9287_get_eeprom,
- .fill_eeprom = ath9k_hw_AR9287_fill_eeprom,
- .get_eeprom_ver = ath9k_hw_AR9287_get_eeprom_ver,
- .get_eeprom_rev = ath9k_hw_AR9287_get_eeprom_rev,
- .get_num_ant_config = ath9k_hw_AR9287_get_num_ant_config,
- .get_eeprom_antenna_cfg = ath9k_hw_AR9287_get_eeprom_antenna_cfg,
- .set_board_values = ath9k_hw_AR9287_set_board_values,
- .set_addac = ath9k_hw_AR9287_set_addac,
- .set_txpower = ath9k_hw_AR9287_set_txpower,
- .get_spur_channel = ath9k_hw_AR9287_get_spur_channel
+ .check_eeprom = ath9k_hw_ar9287_check_eeprom,
+ .get_eeprom = ath9k_hw_ar9287_get_eeprom,
+ .fill_eeprom = ath9k_hw_ar9287_fill_eeprom,
+ .get_eeprom_ver = ath9k_hw_ar9287_get_eeprom_ver,
+ .get_eeprom_rev = ath9k_hw_ar9287_get_eeprom_rev,
+ .get_num_ant_config = ath9k_hw_ar9287_get_num_ant_config,
+ .get_eeprom_antenna_cfg = ath9k_hw_ar9287_get_eeprom_antenna_cfg,
+ .set_board_values = ath9k_hw_ar9287_set_board_values,
+ .set_addac = ath9k_hw_ar9287_set_addac,
+ .set_txpower = ath9k_hw_ar9287_set_txpower,
+ .get_spur_channel = ath9k_hw_ar9287_get_spur_channel
};
diff --git a/drivers/net/wireless/ath/ath9k/eeprom_def.c b/drivers/net/wireless/ath/ath9k/eeprom_def.c
index 7e1ed78d0e6..afa2b73ddbd 100644
--- a/drivers/net/wireless/ath/ath9k/eeprom_def.c
+++ b/drivers/net/wireless/ath/ath9k/eeprom_def.c
@@ -593,7 +593,7 @@ static void ath9k_hw_get_def_gain_boundaries_pdadcs(struct ath_hw *ah,
struct ath9k_channel *chan,
struct cal_data_per_freq *pRawDataSet,
u8 *bChans, u16 availPiers,
- u16 tPdGainOverlap, int16_t *pMinCalPower,
+ u16 tPdGainOverlap,
u16 *pPdGainBoundaries, u8 *pPDADCValues,
u16 numXpdGains)
{
@@ -617,6 +617,7 @@ static void ath9k_hw_get_def_gain_boundaries_pdadcs(struct ath_hw *ah,
int16_t minDelta = 0;
struct chan_centers centers;
+ memset(&minPwrT4, 0, AR9287_NUM_PD_GAINS);
ath9k_hw_get_channel_centers(ah, chan, &centers);
for (numPiers = 0; numPiers < availPiers; numPiers++) {
@@ -674,8 +675,6 @@ static void ath9k_hw_get_def_gain_boundaries_pdadcs(struct ath_hw *ah,
}
}
- *pMinCalPower = (int16_t)(minPwrT4[0] / 2);
-
k = 0;
for (i = 0; i < numXpdGains; i++) {
@@ -729,7 +728,7 @@ static void ath9k_hw_get_def_gain_boundaries_pdadcs(struct ath_hw *ah,
vpdTableI[i][sizeCurrVpdTable - 2]);
vpdStep = (int16_t)((vpdStep < 1) ? 1 : vpdStep);
- if (tgtIndex > maxIndex) {
+ if (tgtIndex >= maxIndex) {
while ((ss <= tgtIndex) &&
(k < (AR5416_NUM_PDADC_VALUES - 1))) {
tmpVal = (int16_t)((vpdTableI[i][sizeCurrVpdTable - 1] +
@@ -837,7 +836,7 @@ static void ath9k_hw_set_def_power_cal_table(struct ath_hw *ah,
static u8 pdadcValues[AR5416_NUM_PDADC_VALUES];
u16 gainBoundaries[AR5416_PD_GAINS_IN_MASK];
u16 numPiers, i, j;
- int16_t tMinCalPower, diff = 0;
+ int16_t diff = 0;
u16 numXpdGain, xpdMask;
u16 xpdGainValues[AR5416_NUM_PD_GAINS] = { 0, 0, 0, 0 };
u32 reg32, regOffset, regChainOffset;
@@ -922,7 +921,6 @@ static void ath9k_hw_set_def_power_cal_table(struct ath_hw *ah,
chan, pRawDataset,
pCalBChans, numPiers,
pdGainOverlap_t2,
- &tMinCalPower,
gainBoundaries,
pdadcValues,
numXpdGain);
@@ -1437,14 +1435,14 @@ static u8 ath9k_hw_def_get_num_ant_config(struct ath_hw *ah,
return num_ant_config;
}
-static u16 ath9k_hw_def_get_eeprom_antenna_cfg(struct ath_hw *ah,
+static u32 ath9k_hw_def_get_eeprom_antenna_cfg(struct ath_hw *ah,
struct ath9k_channel *chan)
{
struct ar5416_eeprom_def *eep = &ah->eeprom.def;
struct modal_eep_header *pModal =
&(eep->modalHeader[IS_CHAN_2GHZ(chan)]);
- return pModal->antCtrlCommon & 0xFFFF;
+ return pModal->antCtrlCommon;
}
static u16 ath9k_hw_def_get_spur_channel(struct ath_hw *ah, u16 i, bool is2GHz)
diff --git a/drivers/net/wireless/ath/ath9k/gpio.c b/drivers/net/wireless/ath/ath9k/gpio.c
index 0ee75e79fe3..3a8ee999da5 100644
--- a/drivers/net/wireless/ath/ath9k/gpio.c
+++ b/drivers/net/wireless/ath/ath9k/gpio.c
@@ -76,7 +76,8 @@ static void ath_led_brightness(struct led_classdev *led_cdev,
case LED_FULL:
if (led->led_type == ATH_LED_ASSOC) {
sc->sc_flags |= SC_OP_LED_ASSOCIATED;
- ieee80211_queue_delayed_work(sc->hw,
+ if (led_blink)
+ ieee80211_queue_delayed_work(sc->hw,
&sc->ath_led_blink_work, 0);
} else if (led->led_type == ATH_LED_RADIO) {
ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, 0);
@@ -143,7 +144,8 @@ void ath_init_leds(struct ath_softc *sc)
/* LED off, active low */
ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, 1);
- INIT_DELAYED_WORK(&sc->ath_led_blink_work, ath_led_blink_work);
+ if (led_blink)
+ INIT_DELAYED_WORK(&sc->ath_led_blink_work, ath_led_blink_work);
trigger = ieee80211_get_radio_led_name(sc->hw);
snprintf(sc->radio_led.name, sizeof(sc->radio_led.name),
@@ -180,7 +182,8 @@ void ath_init_leds(struct ath_softc *sc)
return;
fail:
- cancel_delayed_work_sync(&sc->ath_led_blink_work);
+ if (led_blink)
+ cancel_delayed_work_sync(&sc->ath_led_blink_work);
ath_deinit_leds(sc);
}
diff --git a/drivers/net/wireless/ath/ath9k/hif_usb.c b/drivers/net/wireless/ath/ath9k/hif_usb.c
index 23c15aa9fbd..61c1bee3f26 100644
--- a/drivers/net/wireless/ath/ath9k/hif_usb.c
+++ b/drivers/net/wireless/ath/ath9k/hif_usb.c
@@ -16,12 +16,27 @@
#include "htc.h"
-#define ATH9K_FW_USB_DEV(devid, fw) \
- { USB_DEVICE(0x0cf3, devid), .driver_info = (unsigned long) fw }
+/* identify firmware images */
+#define FIRMWARE_AR7010 "ar7010.fw"
+#define FIRMWARE_AR7010_1_1 "ar7010_1_1.fw"
+#define FIRMWARE_AR9271 "ar9271.fw"
+
+MODULE_FIRMWARE(FIRMWARE_AR7010);
+MODULE_FIRMWARE(FIRMWARE_AR7010_1_1);
+MODULE_FIRMWARE(FIRMWARE_AR9271);
static struct usb_device_id ath9k_hif_usb_ids[] = {
- ATH9K_FW_USB_DEV(0x9271, "ar9271.fw"),
- ATH9K_FW_USB_DEV(0x1006, "ar9271.fw"),
+ { USB_DEVICE(0x0cf3, 0x9271) }, /* Atheros */
+ { USB_DEVICE(0x0cf3, 0x1006) }, /* Atheros */
+ { USB_DEVICE(0x0cf3, 0x7010) }, /* Atheros */
+ { USB_DEVICE(0x0cf3, 0x7015) }, /* Atheros */
+ { USB_DEVICE(0x0846, 0x9030) }, /* Netgear N150 */
+ { USB_DEVICE(0x0846, 0x9018) }, /* Netgear WNDA3200 */
+ { USB_DEVICE(0x07D1, 0x3A10) }, /* Dlink Wireless 150 */
+ { USB_DEVICE(0x13D3, 0x3327) }, /* Azurewave */
+ { USB_DEVICE(0x13D3, 0x3328) }, /* Azurewave */
+ { USB_DEVICE(0x04CA, 0x4605) }, /* Liteon */
+ { USB_DEVICE(0x083A, 0xA704) }, /* SMC Networks */
{ },
};
@@ -760,6 +775,7 @@ static int ath9k_hif_usb_download_fw(struct hif_device_usb *hif_dev)
size_t len = hif_dev->firmware->size;
u32 addr = AR9271_FIRMWARE;
u8 *buf = kzalloc(4096, GFP_KERNEL);
+ u32 firm_offset;
if (!buf)
return -ENOMEM;
@@ -783,32 +799,37 @@ static int ath9k_hif_usb_download_fw(struct hif_device_usb *hif_dev)
}
kfree(buf);
+ if (hif_dev->device_id == 0x7010)
+ firm_offset = AR7010_FIRMWARE_TEXT;
+ else
+ firm_offset = AR9271_FIRMWARE_TEXT;
+
/*
* Issue FW download complete command to firmware.
*/
err = usb_control_msg(hif_dev->udev, usb_sndctrlpipe(hif_dev->udev, 0),
FIRMWARE_DOWNLOAD_COMP,
0x40 | USB_DIR_OUT,
- AR9271_FIRMWARE_TEXT >> 8, 0, NULL, 0, HZ);
+ firm_offset >> 8, 0, NULL, 0, HZ);
if (err)
return -EIO;
dev_info(&hif_dev->udev->dev, "ath9k_htc: Transferred FW: %s, size: %ld\n",
- "ar9271.fw", (unsigned long) hif_dev->firmware->size);
+ hif_dev->fw_name, (unsigned long) hif_dev->firmware->size);
return 0;
}
-static int ath9k_hif_usb_dev_init(struct hif_device_usb *hif_dev,
- const char *fw_name)
+static int ath9k_hif_usb_dev_init(struct hif_device_usb *hif_dev)
{
int ret;
/* Request firmware */
- ret = request_firmware(&hif_dev->firmware, fw_name, &hif_dev->udev->dev);
+ ret = request_firmware(&hif_dev->firmware, hif_dev->fw_name,
+ &hif_dev->udev->dev);
if (ret) {
dev_err(&hif_dev->udev->dev,
- "ath9k_htc: Firmware - %s not found\n", fw_name);
+ "ath9k_htc: Firmware - %s not found\n", hif_dev->fw_name);
goto err_fw_req;
}
@@ -824,7 +845,8 @@ static int ath9k_hif_usb_dev_init(struct hif_device_usb *hif_dev,
ret = ath9k_hif_usb_download_fw(hif_dev);
if (ret) {
dev_err(&hif_dev->udev->dev,
- "ath9k_htc: Firmware - %s download failed\n", fw_name);
+ "ath9k_htc: Firmware - %s download failed\n",
+ hif_dev->fw_name);
goto err_fw_download;
}
@@ -851,7 +873,6 @@ static int ath9k_hif_usb_probe(struct usb_interface *interface,
{
struct usb_device *udev = interface_to_usbdev(interface);
struct hif_device_usb *hif_dev;
- const char *fw_name = (const char *) id->driver_info;
int ret = 0;
hif_dev = kzalloc(sizeof(struct hif_device_usb), GFP_KERNEL);
@@ -876,7 +897,27 @@ static int ath9k_hif_usb_probe(struct usb_interface *interface,
goto err_htc_hw_alloc;
}
- ret = ath9k_hif_usb_dev_init(hif_dev, fw_name);
+ /* Find out which firmware to load */
+
+ switch(hif_dev->device_id) {
+ case 0x7010:
+ case 0x9018:
+ if (le16_to_cpu(udev->descriptor.bcdDevice) == 0x0202)
+ hif_dev->fw_name = FIRMWARE_AR7010_1_1;
+ else
+ hif_dev->fw_name = FIRMWARE_AR7010;
+ break;
+ default:
+ hif_dev->fw_name = FIRMWARE_AR9271;
+ break;
+ }
+
+ if (!hif_dev->fw_name) {
+ dev_err(&udev->dev, "Can't determine firmware !\n");
+ goto err_htc_hw_alloc;
+ }
+
+ ret = ath9k_hif_usb_dev_init(hif_dev);
if (ret) {
ret = -EINVAL;
goto err_hif_init_usb;
@@ -911,12 +952,10 @@ static void ath9k_hif_usb_reboot(struct usb_device *udev)
void *buf;
int ret;
- buf = kmalloc(4, GFP_KERNEL);
+ buf = kmemdup(&reboot_cmd, 4, GFP_KERNEL);
if (!buf)
return;
- memcpy(buf, &reboot_cmd, 4);
-
ret = usb_bulk_msg(udev, usb_sndbulkpipe(udev, USB_REG_OUT_PIPE),
buf, 4, NULL, HZ);
if (ret)
diff --git a/drivers/net/wireless/ath/ath9k/hif_usb.h b/drivers/net/wireless/ath/ath9k/hif_usb.h
index 0aca49b6fcb..2daf97b11c0 100644
--- a/drivers/net/wireless/ath/ath9k/hif_usb.h
+++ b/drivers/net/wireless/ath/ath9k/hif_usb.h
@@ -19,6 +19,7 @@
#define AR9271_FIRMWARE 0x501000
#define AR9271_FIRMWARE_TEXT 0x903000
+#define AR7010_FIRMWARE_TEXT 0x906000
#define FIRMWARE_DOWNLOAD 0x30
#define FIRMWARE_DOWNLOAD_COMP 0x31
@@ -90,6 +91,7 @@ struct hif_device_usb {
struct usb_anchor regout_submitted;
struct usb_anchor rx_submitted;
struct sk_buff *remain_skb;
+ const char *fw_name;
int rx_remain_len;
int rx_pkt_len;
int rx_transfer_len;
diff --git a/drivers/net/wireless/ath/ath9k/htc.h b/drivers/net/wireless/ath/ath9k/htc.h
index c251603ab03..3756400e6bf 100644
--- a/drivers/net/wireless/ath/ath9k/htc.h
+++ b/drivers/net/wireless/ath/ath9k/htc.h
@@ -223,15 +223,6 @@ struct ath9k_htc_sta {
enum tid_aggr_state tid_state[ATH9K_HTC_MAX_TID];
};
-struct ath9k_htc_aggr_work {
- u16 tid;
- u8 sta_addr[ETH_ALEN];
- struct ieee80211_hw *hw;
- struct ieee80211_vif *vif;
- enum ieee80211_ampdu_mlme_action action;
- struct mutex mutex;
-};
-
#define ATH9K_HTC_RXBUF 256
#define HTC_RX_FRAME_HEADER_SIZE 40
@@ -257,12 +248,15 @@ struct ath9k_htc_tx_ctl {
#define TX_STAT_INC(c) (hif_dev->htc_handle->drv_priv->debug.tx_stats.c++)
#define RX_STAT_INC(c) (hif_dev->htc_handle->drv_priv->debug.rx_stats.c++)
+#define TX_QSTAT_INC(q) (priv->debug.tx_stats.queue_stats[q]++)
+
struct ath_tx_stats {
u32 buf_queued;
u32 buf_completed;
u32 skb_queued;
u32 skb_completed;
u32 skb_dropped;
+ u32 queue_stats[WME_NUM_AC];
};
struct ath_rx_stats {
@@ -286,11 +280,14 @@ struct ath9k_debug {
#define TX_STAT_INC(c) do { } while (0)
#define RX_STAT_INC(c) do { } while (0)
+#define TX_QSTAT_INC(c) do { } while (0)
+
#endif /* CONFIG_ATH9K_HTC_DEBUGFS */
#define ATH_LED_PIN_DEF 1
#define ATH_LED_PIN_9287 8
#define ATH_LED_PIN_9271 15
+#define ATH_LED_PIN_7010 12
#define ATH_LED_ON_DURATION_IDLE 350 /* in msecs */
#define ATH_LED_OFF_DURATION_IDLE 250 /* in msecs */
@@ -326,11 +323,10 @@ struct htc_beacon_config {
#define OP_LED_ON BIT(4)
#define OP_PREAMBLE_SHORT BIT(5)
#define OP_PROTECT_ENABLE BIT(6)
-#define OP_TXAGGR BIT(7)
-#define OP_ASSOCIATED BIT(8)
-#define OP_ENABLE_BEACON BIT(9)
-#define OP_LED_DEINIT BIT(10)
-#define OP_UNPLUGGED BIT(11)
+#define OP_ASSOCIATED BIT(7)
+#define OP_ENABLE_BEACON BIT(8)
+#define OP_LED_DEINIT BIT(9)
+#define OP_UNPLUGGED BIT(10)
struct ath9k_htc_priv {
struct device *dev;
@@ -371,8 +367,6 @@ struct ath9k_htc_priv {
struct ath9k_htc_rx rx;
struct tasklet_struct tx_tasklet;
struct sk_buff_head tx_queue;
- struct ath9k_htc_aggr_work aggr_work;
- struct delayed_work ath9k_aggr_work;
struct delayed_work ath9k_ani_work;
struct work_struct ps_work;
@@ -390,13 +384,14 @@ struct ath9k_htc_priv {
int led_off_duration;
int led_on_cnt;
int led_off_cnt;
- int hwq_map[ATH9K_WME_AC_VO+1];
+
+ int beaconq;
+ int cabq;
+ int hwq_map[WME_NUM_AC];
#ifdef CONFIG_ATH9K_HTC_DEBUGFS
struct ath9k_debug debug;
#endif
- struct ath9k_htc_target_rate tgt_rate;
-
struct mutex mutex;
};
@@ -405,6 +400,7 @@ static inline void ath_read_cachesize(struct ath_common *common, int *csz)
common->bus_ops->read_cachesize(common, csz);
}
+void ath9k_htc_beaconq_config(struct ath9k_htc_priv *priv);
void ath9k_htc_beacon_config(struct ath9k_htc_priv *priv,
struct ieee80211_vif *vif);
void ath9k_htc_swba(struct ath9k_htc_priv *priv, u8 beacon_pending);
@@ -424,8 +420,8 @@ int ath9k_tx_init(struct ath9k_htc_priv *priv);
void ath9k_tx_tasklet(unsigned long data);
int ath9k_htc_tx_start(struct ath9k_htc_priv *priv, struct sk_buff *skb);
void ath9k_tx_cleanup(struct ath9k_htc_priv *priv);
-bool ath9k_htc_txq_setup(struct ath9k_htc_priv *priv,
- enum ath9k_tx_queue_subtype qtype);
+bool ath9k_htc_txq_setup(struct ath9k_htc_priv *priv, int subtype);
+int ath9k_htc_cabq_setup(struct ath9k_htc_priv *priv);
int get_hw_qnum(u16 queue, int *hwq_map);
int ath_htc_txq_update(struct ath9k_htc_priv *priv, int qnum,
struct ath9k_tx_queue_info *qinfo);
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c
index c10c7d002eb..bd1506e6910 100644
--- a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c
@@ -222,6 +222,29 @@ void ath9k_htc_swba(struct ath9k_htc_priv *priv, u8 beacon_pending)
spin_unlock_bh(&priv->beacon_lock);
}
+/* Currently, only for IBSS */
+void ath9k_htc_beaconq_config(struct ath9k_htc_priv *priv)
+{
+ struct ath_hw *ah = priv->ah;
+ struct ath9k_tx_queue_info qi, qi_be;
+ int qnum = priv->hwq_map[WME_AC_BE];
+
+ memset(&qi, 0, sizeof(struct ath9k_tx_queue_info));
+ memset(&qi_be, 0, sizeof(struct ath9k_tx_queue_info));
+
+ ath9k_hw_get_txq_props(ah, qnum, &qi_be);
+
+ qi.tqi_aifs = qi_be.tqi_aifs;
+ qi.tqi_cwmin = 4*qi_be.tqi_cwmin;
+ qi.tqi_cwmax = qi_be.tqi_cwmax;
+
+ if (!ath9k_hw_set_txq_props(ah, priv->beaconq, &qi)) {
+ ath_print(ath9k_hw_common(ah), ATH_DBG_FATAL,
+ "Unable to update beacon queue %u!\n", qnum);
+ } else {
+ ath9k_hw_resettxqueue(ah, priv->beaconq);
+ }
+}
void ath9k_htc_beacon_config(struct ath9k_htc_priv *priv,
struct ieee80211_vif *vif)
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_init.c b/drivers/net/wireless/ath/ath9k/htc_drv_init.c
index dc015077a8d..148b43317fd 100644
--- a/drivers/net/wireless/ath/ath9k/htc_drv_init.c
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_init.c
@@ -34,6 +34,13 @@ MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption");
.max_power = 20, \
}
+#define CHAN5G(_freq, _idx) { \
+ .band = IEEE80211_BAND_5GHZ, \
+ .center_freq = (_freq), \
+ .hw_value = (_idx), \
+ .max_power = 20, \
+}
+
static struct ieee80211_channel ath9k_2ghz_channels[] = {
CHAN2G(2412, 0), /* Channel 1 */
CHAN2G(2417, 1), /* Channel 2 */
@@ -51,6 +58,37 @@ static struct ieee80211_channel ath9k_2ghz_channels[] = {
CHAN2G(2484, 13), /* Channel 14 */
};
+static struct ieee80211_channel ath9k_5ghz_channels[] = {
+ /* _We_ call this UNII 1 */
+ CHAN5G(5180, 14), /* Channel 36 */
+ CHAN5G(5200, 15), /* Channel 40 */
+ CHAN5G(5220, 16), /* Channel 44 */
+ CHAN5G(5240, 17), /* Channel 48 */
+ /* _We_ call this UNII 2 */
+ CHAN5G(5260, 18), /* Channel 52 */
+ CHAN5G(5280, 19), /* Channel 56 */
+ CHAN5G(5300, 20), /* Channel 60 */
+ CHAN5G(5320, 21), /* Channel 64 */
+ /* _We_ call this "Middle band" */
+ CHAN5G(5500, 22), /* Channel 100 */
+ CHAN5G(5520, 23), /* Channel 104 */
+ CHAN5G(5540, 24), /* Channel 108 */
+ CHAN5G(5560, 25), /* Channel 112 */
+ CHAN5G(5580, 26), /* Channel 116 */
+ CHAN5G(5600, 27), /* Channel 120 */
+ CHAN5G(5620, 28), /* Channel 124 */
+ CHAN5G(5640, 29), /* Channel 128 */
+ CHAN5G(5660, 30), /* Channel 132 */
+ CHAN5G(5680, 31), /* Channel 136 */
+ CHAN5G(5700, 32), /* Channel 140 */
+ /* _We_ call this UNII 3 */
+ CHAN5G(5745, 33), /* Channel 149 */
+ CHAN5G(5765, 34), /* Channel 153 */
+ CHAN5G(5785, 35), /* Channel 157 */
+ CHAN5G(5805, 36), /* Channel 161 */
+ CHAN5G(5825, 37), /* Channel 165 */
+};
+
/* Atheros hardware rate code addition for short premble */
#define SHPCHECK(__hw_rate, __flags) \
((__flags & IEEE80211_RATE_SHORT_PREAMBLE) ? (__hw_rate | 0x04) : 0)
@@ -141,7 +179,7 @@ static inline int ath9k_htc_connect_svc(struct ath9k_htc_priv *priv,
return htc_connect_service(priv->htc, &req, ep_id);
}
-static int ath9k_init_htc_services(struct ath9k_htc_priv *priv)
+static int ath9k_init_htc_services(struct ath9k_htc_priv *priv, u16 devid)
{
int ret;
@@ -199,10 +237,28 @@ static int ath9k_init_htc_services(struct ath9k_htc_priv *priv)
if (ret)
goto err;
+ /*
+ * Setup required credits before initializing HTC.
+ * This is a bit hacky, but, since queuing is done in
+ * the HIF layer, shouldn't matter much.
+ */
+
+ switch(devid) {
+ case 0x7010:
+ case 0x9018:
+ priv->htc->credits = 45;
+ break;
+ default:
+ priv->htc->credits = 33;
+ }
+
ret = htc_init(priv->htc);
if (ret)
goto err;
+ dev_info(priv->dev, "ath9k_htc: HTC initialized with %d credits\n",
+ priv->htc->credits);
+
return 0;
err:
@@ -398,17 +454,43 @@ static const struct ath_bus_ops ath9k_usb_bus_ops = {
static void setup_ht_cap(struct ath9k_htc_priv *priv,
struct ieee80211_sta_ht_cap *ht_info)
{
+ struct ath_common *common = ath9k_hw_common(priv->ah);
+ u8 tx_streams, rx_streams;
+ int i;
+
ht_info->ht_supported = true;
ht_info->cap = IEEE80211_HT_CAP_SUP_WIDTH_20_40 |
IEEE80211_HT_CAP_SM_PS |
IEEE80211_HT_CAP_SGI_40 |
IEEE80211_HT_CAP_DSSSCCK40;
+ if (priv->ah->caps.hw_caps & ATH9K_HW_CAP_SGI_20)
+ ht_info->cap |= IEEE80211_HT_CAP_SGI_20;
+
+ ht_info->cap |= (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT);
+
ht_info->ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K;
ht_info->ampdu_density = IEEE80211_HT_MPDU_DENSITY_8;
memset(&ht_info->mcs, 0, sizeof(ht_info->mcs));
- ht_info->mcs.rx_mask[0] = 0xff;
+
+ /* ath9k_htc supports only 1 or 2 stream devices */
+ tx_streams = ath9k_cmn_count_streams(common->tx_chainmask, 2);
+ rx_streams = ath9k_cmn_count_streams(common->rx_chainmask, 2);
+
+ ath_print(common, ATH_DBG_CONFIG,
+ "TX streams %d, RX streams: %d\n",
+ tx_streams, rx_streams);
+
+ if (tx_streams != rx_streams) {
+ ht_info->mcs.tx_params |= IEEE80211_HT_MCS_TX_RX_DIFF;
+ ht_info->mcs.tx_params |= ((tx_streams - 1) <<
+ IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT);
+ }
+
+ for (i = 0; i < rx_streams; i++)
+ ht_info->mcs.rx_mask[i] = 0xff;
+
ht_info->mcs.tx_params |= IEEE80211_HT_MCS_TX_DEFINED;
}
@@ -420,23 +502,37 @@ static int ath9k_init_queues(struct ath9k_htc_priv *priv)
for (i = 0; i < ARRAY_SIZE(priv->hwq_map); i++)
priv->hwq_map[i] = -1;
- if (!ath9k_htc_txq_setup(priv, ATH9K_WME_AC_BE)) {
+ priv->beaconq = ath9k_hw_beaconq_setup(priv->ah);
+ if (priv->beaconq == -1) {
+ ath_print(common, ATH_DBG_FATAL,
+ "Unable to setup BEACON xmit queue\n");
+ goto err;
+ }
+
+ priv->cabq = ath9k_htc_cabq_setup(priv);
+ if (priv->cabq == -1) {
+ ath_print(common, ATH_DBG_FATAL,
+ "Unable to setup CAB xmit queue\n");
+ goto err;
+ }
+
+ if (!ath9k_htc_txq_setup(priv, WME_AC_BE)) {
ath_print(common, ATH_DBG_FATAL,
"Unable to setup xmit queue for BE traffic\n");
goto err;
}
- if (!ath9k_htc_txq_setup(priv, ATH9K_WME_AC_BK)) {
+ if (!ath9k_htc_txq_setup(priv, WME_AC_BK)) {
ath_print(common, ATH_DBG_FATAL,
"Unable to setup xmit queue for BK traffic\n");
goto err;
}
- if (!ath9k_htc_txq_setup(priv, ATH9K_WME_AC_VI)) {
+ if (!ath9k_htc_txq_setup(priv, WME_AC_VI)) {
ath_print(common, ATH_DBG_FATAL,
"Unable to setup xmit queue for VI traffic\n");
goto err;
}
- if (!ath9k_htc_txq_setup(priv, ATH9K_WME_AC_VO)) {
+ if (!ath9k_htc_txq_setup(priv, WME_AC_VO)) {
ath_print(common, ATH_DBG_FATAL,
"Unable to setup xmit queue for VO traffic\n");
goto err;
@@ -468,36 +564,6 @@ static void ath9k_init_crypto(struct ath9k_htc_priv *priv)
*/
for (i = 0; i < common->keymax; i++)
ath9k_hw_keyreset(priv->ah, (u16) i);
-
- if (ath9k_hw_getcapability(priv->ah, ATH9K_CAP_CIPHER,
- ATH9K_CIPHER_TKIP, NULL)) {
- /*
- * Whether we should enable h/w TKIP MIC.
- * XXX: if we don't support WME TKIP MIC, then we wouldn't
- * report WMM capable, so it's always safe to turn on
- * TKIP MIC in this case.
- */
- ath9k_hw_setcapability(priv->ah, ATH9K_CAP_TKIP_MIC, 0, 1, NULL);
- }
-
- /*
- * Check whether the separate key cache entries
- * are required to handle both tx+rx MIC keys.
- * With split mic keys the number of stations is limited
- * to 27 otherwise 59.
- */
- if (ath9k_hw_getcapability(priv->ah, ATH9K_CAP_CIPHER,
- ATH9K_CIPHER_TKIP, NULL)
- && ath9k_hw_getcapability(priv->ah, ATH9K_CAP_CIPHER,
- ATH9K_CIPHER_MIC, NULL)
- && ath9k_hw_getcapability(priv->ah, ATH9K_CAP_TKIP_SPLIT,
- 0, NULL))
- common->splitmic = 1;
-
- /* turn on mcast key search if possible */
- if (!ath9k_hw_getcapability(priv->ah, ATH9K_CAP_MCAST_KEYSRCH, 0, NULL))
- (void)ath9k_hw_setcapability(priv->ah, ATH9K_CAP_MCAST_KEYSRCH,
- 1, 1, NULL);
}
static void ath9k_init_channels_rates(struct ath9k_htc_priv *priv)
@@ -512,6 +578,17 @@ static void ath9k_init_channels_rates(struct ath9k_htc_priv *priv)
priv->sbands[IEEE80211_BAND_2GHZ].n_bitrates =
ARRAY_SIZE(ath9k_legacy_rates);
}
+
+ if (test_bit(ATH9K_MODE_11A, priv->ah->caps.wireless_modes)) {
+ priv->sbands[IEEE80211_BAND_5GHZ].channels = ath9k_5ghz_channels;
+ priv->sbands[IEEE80211_BAND_5GHZ].band = IEEE80211_BAND_5GHZ;
+ priv->sbands[IEEE80211_BAND_5GHZ].n_channels =
+ ARRAY_SIZE(ath9k_5ghz_channels);
+ priv->sbands[IEEE80211_BAND_5GHZ].bitrates =
+ ath9k_legacy_rates + 4;
+ priv->sbands[IEEE80211_BAND_5GHZ].n_bitrates =
+ ARRAY_SIZE(ath9k_legacy_rates) - 4;
+ }
}
static void ath9k_init_misc(struct ath9k_htc_priv *priv)
@@ -524,7 +601,6 @@ static void ath9k_init_misc(struct ath9k_htc_priv *priv)
if (priv->ah->caps.hw_caps & ATH9K_HW_CAP_BSSIDMASK)
memcpy(common->bssidmask, ath_bcast_mac, ETH_ALEN);
- priv->op_flags |= OP_TXAGGR;
priv->ah->opmode = NL80211_IFTYPE_STATION;
}
@@ -556,14 +632,12 @@ static int ath9k_init_priv(struct ath9k_htc_priv *priv, u16 devid)
spin_lock_init(&priv->beacon_lock);
spin_lock_init(&priv->tx_lock);
mutex_init(&priv->mutex);
- mutex_init(&priv->aggr_work.mutex);
mutex_init(&priv->htc_pm_lock);
tasklet_init(&priv->wmi_tasklet, ath9k_wmi_tasklet,
(unsigned long)priv);
tasklet_init(&priv->rx_tasklet, ath9k_rx_tasklet,
(unsigned long)priv);
tasklet_init(&priv->tx_tasklet, ath9k_tx_tasklet, (unsigned long)priv);
- INIT_DELAYED_WORK(&priv->ath9k_aggr_work, ath9k_htc_aggr_work);
INIT_DELAYED_WORK(&priv->ath9k_ani_work, ath9k_ani_work);
INIT_WORK(&priv->ps_work, ath9k_ps_work);
@@ -643,11 +717,17 @@ static void ath9k_set_hw_capab(struct ath9k_htc_priv *priv,
if (test_bit(ATH9K_MODE_11G, priv->ah->caps.wireless_modes))
hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
&priv->sbands[IEEE80211_BAND_2GHZ];
+ if (test_bit(ATH9K_MODE_11A, priv->ah->caps.wireless_modes))
+ hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
+ &priv->sbands[IEEE80211_BAND_5GHZ];
if (priv->ah->caps.hw_caps & ATH9K_HW_CAP_HT) {
if (test_bit(ATH9K_MODE_11G, priv->ah->caps.wireless_modes))
setup_ht_cap(priv,
&priv->sbands[IEEE80211_BAND_2GHZ].ht_cap);
+ if (test_bit(ATH9K_MODE_11A, priv->ah->caps.wireless_modes))
+ setup_ht_cap(priv,
+ &priv->sbands[IEEE80211_BAND_5GHZ].ht_cap);
}
SET_IEEE80211_PERM_ADDR(hw, common->macaddr);
@@ -747,7 +827,7 @@ int ath9k_htc_probe_device(struct htc_target *htc_handle, struct device *dev,
goto err_free;
}
- ret = ath9k_init_htc_services(priv);
+ ret = ath9k_init_htc_services(priv, devid);
if (ret)
goto err_init;
@@ -790,7 +870,8 @@ int ath9k_htc_resume(struct htc_target *htc_handle)
if (ret)
return ret;
- ret = ath9k_init_htc_services(htc_handle->drv_priv);
+ ret = ath9k_init_htc_services(htc_handle->drv_priv,
+ htc_handle->drv_priv->ah->hw_version.devid);
return ret;
}
#endif
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_main.c b/drivers/net/wireless/ath/ath9k/htc_drv_main.c
index 9d371c18eb4..cf9bcc67ade 100644
--- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c
@@ -27,13 +27,11 @@ static struct dentry *ath9k_debugfs_root;
static void ath_update_txpow(struct ath9k_htc_priv *priv)
{
struct ath_hw *ah = priv->ah;
- u32 txpow;
if (priv->curtxpow != priv->txpowlimit) {
ath9k_hw_set_txpowerlimit(ah, priv->txpowlimit);
/* read back in case value is clamped */
- ath9k_hw_getcapability(ah, ATH9K_CAP_TXPOW, 1, &txpow);
- priv->curtxpow = txpow;
+ priv->curtxpow = ath9k_hw_regulatory(ah)->power_limit;
}
}
@@ -325,142 +323,129 @@ static int ath9k_htc_update_cap_target(struct ath9k_htc_priv *priv)
tcap.flags_ext = 0x80601000;
tcap.ampdu_limit = 0xffff0000;
tcap.ampdu_subframes = 20;
- tcap.tx_chainmask_legacy = 1;
+ tcap.tx_chainmask_legacy = priv->ah->caps.tx_chainmask;
tcap.protmode = 1;
- tcap.tx_chainmask = 1;
+ tcap.tx_chainmask = priv->ah->caps.tx_chainmask;
WMI_CMD_BUF(WMI_TARGET_IC_UPDATE_CMDID, &tcap);
return ret;
}
-static int ath9k_htc_init_rate(struct ath9k_htc_priv *priv,
- struct ieee80211_vif *vif,
- struct ieee80211_sta *sta)
+static void ath9k_htc_setup_rate(struct ath9k_htc_priv *priv,
+ struct ieee80211_sta *sta,
+ struct ath9k_htc_target_rate *trate)
{
- struct ath_common *common = ath9k_hw_common(priv->ah);
struct ath9k_htc_sta *ista = (struct ath9k_htc_sta *) sta->drv_priv;
struct ieee80211_supported_band *sband;
- struct ath9k_htc_target_rate trate;
u32 caps = 0;
- u8 cmd_rsp;
- int i, j, ret;
+ int i, j;
- memset(&trate, 0, sizeof(trate));
-
- /* Only 2GHz is supported */
- sband = priv->hw->wiphy->bands[IEEE80211_BAND_2GHZ];
+ sband = priv->hw->wiphy->bands[priv->hw->conf.channel->band];
for (i = 0, j = 0; i < sband->n_bitrates; i++) {
if (sta->supp_rates[sband->band] & BIT(i)) {
- priv->tgt_rate.rates.legacy_rates.rs_rates[j]
+ trate->rates.legacy_rates.rs_rates[j]
= (sband->bitrates[i].bitrate * 2) / 10;
j++;
}
}
- priv->tgt_rate.rates.legacy_rates.rs_nrates = j;
+ trate->rates.legacy_rates.rs_nrates = j;
if (sta->ht_cap.ht_supported) {
for (i = 0, j = 0; i < 77; i++) {
if (sta->ht_cap.mcs.rx_mask[i/8] & (1<<(i%8)))
- priv->tgt_rate.rates.ht_rates.rs_rates[j++] = i;
+ trate->rates.ht_rates.rs_rates[j++] = i;
if (j == ATH_HTC_RATE_MAX)
break;
}
- priv->tgt_rate.rates.ht_rates.rs_nrates = j;
+ trate->rates.ht_rates.rs_nrates = j;
caps = WLAN_RC_HT_FLAG;
+ if (sta->ht_cap.mcs.rx_mask[1])
+ caps |= WLAN_RC_DS_FLAG;
if (sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40)
caps |= WLAN_RC_40_FLAG;
- if (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40)
+ if (conf_is_ht40(&priv->hw->conf) &&
+ (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40))
+ caps |= WLAN_RC_SGI_FLAG;
+ else if (conf_is_ht20(&priv->hw->conf) &&
+ (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20))
caps |= WLAN_RC_SGI_FLAG;
-
}
- priv->tgt_rate.sta_index = ista->index;
- priv->tgt_rate.isnew = 1;
- trate = priv->tgt_rate;
- priv->tgt_rate.capflags = cpu_to_be32(caps);
- trate.capflags = cpu_to_be32(caps);
+ trate->sta_index = ista->index;
+ trate->isnew = 1;
+ trate->capflags = cpu_to_be32(caps);
+}
- WMI_CMD_BUF(WMI_RC_RATE_UPDATE_CMDID, &trate);
+static int ath9k_htc_send_rate_cmd(struct ath9k_htc_priv *priv,
+ struct ath9k_htc_target_rate *trate)
+{
+ struct ath_common *common = ath9k_hw_common(priv->ah);
+ int ret;
+ u8 cmd_rsp;
+
+ WMI_CMD_BUF(WMI_RC_RATE_UPDATE_CMDID, trate);
if (ret) {
ath_print(common, ATH_DBG_FATAL,
"Unable to initialize Rate information on target\n");
- return ret;
}
- ath_print(common, ATH_DBG_CONFIG,
- "Updated target STA: %pM (caps: 0x%x)\n", sta->addr, caps);
- return 0;
+ return ret;
}
-static bool check_rc_update(struct ieee80211_hw *hw, bool *cw40)
+static void ath9k_htc_init_rate(struct ath9k_htc_priv *priv,
+ struct ieee80211_sta *sta)
{
- struct ath9k_htc_priv *priv = hw->priv;
- struct ieee80211_conf *conf = &hw->conf;
-
- if (!conf_is_ht(conf))
- return false;
-
- if (!(priv->op_flags & OP_ASSOCIATED) ||
- (priv->op_flags & OP_SCANNING))
- return false;
+ struct ath_common *common = ath9k_hw_common(priv->ah);
+ struct ath9k_htc_target_rate trate;
+ int ret;
- if (conf_is_ht40(conf)) {
- if (priv->ah->curchan->chanmode &
- (CHANNEL_HT40PLUS | CHANNEL_HT40MINUS)) {
- return false;
- } else {
- *cw40 = true;
- return true;
- }
- } else { /* ht20 */
- if (priv->ah->curchan->chanmode & CHANNEL_HT20)
- return false;
- else
- return true;
- }
+ memset(&trate, 0, sizeof(struct ath9k_htc_target_rate));
+ ath9k_htc_setup_rate(priv, sta, &trate);
+ ret = ath9k_htc_send_rate_cmd(priv, &trate);
+ if (!ret)
+ ath_print(common, ATH_DBG_CONFIG,
+ "Updated target sta: %pM, rate caps: 0x%X\n",
+ sta->addr, be32_to_cpu(trate.capflags));
}
-static void ath9k_htc_rc_update(struct ath9k_htc_priv *priv, bool is_cw40)
+static void ath9k_htc_update_rate(struct ath9k_htc_priv *priv,
+ struct ieee80211_vif *vif,
+ struct ieee80211_bss_conf *bss_conf)
{
- struct ath9k_htc_target_rate trate;
struct ath_common *common = ath9k_hw_common(priv->ah);
+ struct ath9k_htc_target_rate trate;
+ struct ieee80211_sta *sta;
int ret;
- u32 caps = be32_to_cpu(priv->tgt_rate.capflags);
- u8 cmd_rsp;
-
- memset(&trate, 0, sizeof(trate));
-
- trate = priv->tgt_rate;
-
- if (is_cw40)
- caps |= WLAN_RC_40_FLAG;
- else
- caps &= ~WLAN_RC_40_FLAG;
- priv->tgt_rate.capflags = cpu_to_be32(caps);
- trate.capflags = cpu_to_be32(caps);
+ memset(&trate, 0, sizeof(struct ath9k_htc_target_rate));
- WMI_CMD_BUF(WMI_RC_RATE_UPDATE_CMDID, &trate);
- if (ret) {
- ath_print(common, ATH_DBG_FATAL,
- "Unable to update Rate information on target\n");
+ rcu_read_lock();
+ sta = ieee80211_find_sta(vif, bss_conf->bssid);
+ if (!sta) {
+ rcu_read_unlock();
return;
}
+ ath9k_htc_setup_rate(priv, sta, &trate);
+ rcu_read_unlock();
- ath_print(common, ATH_DBG_CONFIG, "Rate control updated with "
- "caps:0x%x on target\n", priv->tgt_rate.capflags);
+ ret = ath9k_htc_send_rate_cmd(priv, &trate);
+ if (!ret)
+ ath_print(common, ATH_DBG_CONFIG,
+ "Updated target sta: %pM, rate caps: 0x%X\n",
+ bss_conf->bssid, be32_to_cpu(trate.capflags));
}
-static int ath9k_htc_aggr_oper(struct ath9k_htc_priv *priv,
- struct ieee80211_vif *vif,
- u8 *sta_addr, u8 tid, bool oper)
+static int ath9k_htc_tx_aggr_oper(struct ath9k_htc_priv *priv,
+ struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta,
+ enum ieee80211_ampdu_mlme_action action,
+ u16 tid)
{
struct ath_common *common = ath9k_hw_common(priv->ah);
struct ath9k_htc_target_aggr aggr;
- struct ieee80211_sta *sta = NULL;
struct ath9k_htc_sta *ista;
int ret = 0;
u8 cmd_rsp;
@@ -469,72 +454,28 @@ static int ath9k_htc_aggr_oper(struct ath9k_htc_priv *priv,
return -EINVAL;
memset(&aggr, 0, sizeof(struct ath9k_htc_target_aggr));
-
- rcu_read_lock();
-
- /* Check if we are able to retrieve the station */
- sta = ieee80211_find_sta(vif, sta_addr);
- if (!sta) {
- rcu_read_unlock();
- return -EINVAL;
- }
-
ista = (struct ath9k_htc_sta *) sta->drv_priv;
- if (oper)
- ista->tid_state[tid] = AGGR_START;
- else
- ista->tid_state[tid] = AGGR_STOP;
-
aggr.sta_index = ista->index;
-
- rcu_read_unlock();
-
- aggr.tidno = tid;
- aggr.aggr_enable = oper;
+ aggr.tidno = tid & 0xf;
+ aggr.aggr_enable = (action == IEEE80211_AMPDU_TX_START) ? true : false;
WMI_CMD_BUF(WMI_TX_AGGR_ENABLE_CMDID, &aggr);
if (ret)
ath_print(common, ATH_DBG_CONFIG,
"Unable to %s TX aggregation for (%pM, %d)\n",
- (oper) ? "start" : "stop", sta->addr, tid);
+ (aggr.aggr_enable) ? "start" : "stop", sta->addr, tid);
else
ath_print(common, ATH_DBG_CONFIG,
- "%s aggregation for (%pM, %d)\n",
- (oper) ? "Starting" : "Stopping", sta->addr, tid);
-
- return ret;
-}
+ "%s TX aggregation for (%pM, %d)\n",
+ (aggr.aggr_enable) ? "Starting" : "Stopping",
+ sta->addr, tid);
-void ath9k_htc_aggr_work(struct work_struct *work)
-{
- int ret = 0;
- struct ath9k_htc_priv *priv =
- container_of(work, struct ath9k_htc_priv,
- ath9k_aggr_work.work);
- struct ath9k_htc_aggr_work *wk = &priv->aggr_work;
-
- mutex_lock(&wk->mutex);
-
- switch (wk->action) {
- case IEEE80211_AMPDU_TX_START:
- ret = ath9k_htc_aggr_oper(priv, wk->vif, wk->sta_addr,
- wk->tid, true);
- if (!ret)
- ieee80211_start_tx_ba_cb(wk->vif, wk->sta_addr,
- wk->tid);
- break;
- case IEEE80211_AMPDU_TX_STOP:
- ath9k_htc_aggr_oper(priv, wk->vif, wk->sta_addr,
- wk->tid, false);
- ieee80211_stop_tx_ba_cb(wk->vif, wk->sta_addr, wk->tid);
- break;
- default:
- ath_print(ath9k_hw_common(priv->ah), ATH_DBG_FATAL,
- "Unknown AMPDU action\n");
- }
+ spin_lock_bh(&priv->tx_lock);
+ ista->tid_state[tid] = (aggr.aggr_enable && !ret) ? AGGR_START : AGGR_STOP;
+ spin_unlock_bh(&priv->tx_lock);
- mutex_unlock(&wk->mutex);
+ return ret;
}
/*********/
@@ -552,8 +493,7 @@ static int ath9k_debugfs_open(struct inode *inode, struct file *file)
static ssize_t read_file_tgt_stats(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos)
{
- struct ath9k_htc_priv *priv =
- (struct ath9k_htc_priv *) file->private_data;
+ struct ath9k_htc_priv *priv = file->private_data;
struct ath9k_htc_target_stats cmd_rsp;
char buf[512];
unsigned int len = 0;
@@ -584,6 +524,9 @@ static ssize_t read_file_tgt_stats(struct file *file, char __user *user_buf,
len += snprintf(buf + len, sizeof(buf) - len,
"%19s : %10u\n", "TX Rate", priv->debug.txrate);
+ if (len > sizeof(buf))
+ len = sizeof(buf);
+
return simple_read_from_buffer(user_buf, count, ppos, buf, len);
}
@@ -596,8 +539,7 @@ static const struct file_operations fops_tgt_stats = {
static ssize_t read_file_xmit(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos)
{
- struct ath9k_htc_priv *priv =
- (struct ath9k_htc_priv *) file->private_data;
+ struct ath9k_htc_priv *priv = file->private_data;
char buf[512];
unsigned int len = 0;
@@ -617,6 +559,22 @@ static ssize_t read_file_xmit(struct file *file, char __user *user_buf,
"%20s : %10u\n", "SKBs dropped",
priv->debug.tx_stats.skb_dropped);
+ len += snprintf(buf + len, sizeof(buf) - len,
+ "%20s : %10u\n", "BE queued",
+ priv->debug.tx_stats.queue_stats[WME_AC_BE]);
+ len += snprintf(buf + len, sizeof(buf) - len,
+ "%20s : %10u\n", "BK queued",
+ priv->debug.tx_stats.queue_stats[WME_AC_BK]);
+ len += snprintf(buf + len, sizeof(buf) - len,
+ "%20s : %10u\n", "VI queued",
+ priv->debug.tx_stats.queue_stats[WME_AC_VI]);
+ len += snprintf(buf + len, sizeof(buf) - len,
+ "%20s : %10u\n", "VO queued",
+ priv->debug.tx_stats.queue_stats[WME_AC_VO]);
+
+ if (len > sizeof(buf))
+ len = sizeof(buf);
+
return simple_read_from_buffer(user_buf, count, ppos, buf, len);
}
@@ -629,8 +587,7 @@ static const struct file_operations fops_xmit = {
static ssize_t read_file_recv(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos)
{
- struct ath9k_htc_priv *priv =
- (struct ath9k_htc_priv *) file->private_data;
+ struct ath9k_htc_priv *priv = file->private_data;
char buf[512];
unsigned int len = 0;
@@ -644,6 +601,9 @@ static ssize_t read_file_recv(struct file *file, char __user *user_buf,
"%20s : %10u\n", "SKBs Dropped",
priv->debug.rx_stats.skb_dropped);
+ if (len > sizeof(buf))
+ len = sizeof(buf);
+
return simple_read_from_buffer(user_buf, count, ppos, buf, len);
}
@@ -978,6 +938,8 @@ void ath9k_init_leds(struct ath9k_htc_priv *priv)
priv->ah->led_pin = ATH_LED_PIN_9287;
else if (AR_SREV_9271(priv->ah))
priv->ah->led_pin = ATH_LED_PIN_9271;
+ else if (AR_DEVID_7010(priv->ah))
+ priv->ah->led_pin = ATH_LED_PIN_7010;
else
priv->ah->led_pin = ATH_LED_PIN_DEF;
@@ -1054,6 +1016,95 @@ void ath9k_start_rfkill_poll(struct ath9k_htc_priv *priv)
wiphy_rfkill_start_polling(priv->hw->wiphy);
}
+static void ath9k_htc_radio_enable(struct ieee80211_hw *hw)
+{
+ struct ath9k_htc_priv *priv = hw->priv;
+ struct ath_hw *ah = priv->ah;
+ struct ath_common *common = ath9k_hw_common(ah);
+ int ret;
+ u8 cmd_rsp;
+
+ if (!ah->curchan)
+ ah->curchan = ath9k_cmn_get_curchannel(hw, ah);
+
+ /* Reset the HW */
+ ret = ath9k_hw_reset(ah, ah->curchan, false);
+ if (ret) {
+ ath_print(common, ATH_DBG_FATAL,
+ "Unable to reset hardware; reset status %d "
+ "(freq %u MHz)\n", ret, ah->curchan->channel);
+ }
+
+ ath_update_txpow(priv);
+
+ /* Start RX */
+ WMI_CMD(WMI_START_RECV_CMDID);
+ ath9k_host_rx_init(priv);
+
+ /* Start TX */
+ htc_start(priv->htc);
+ spin_lock_bh(&priv->tx_lock);
+ priv->tx_queues_stop = false;
+ spin_unlock_bh(&priv->tx_lock);
+ ieee80211_wake_queues(hw);
+
+ WMI_CMD(WMI_ENABLE_INTR_CMDID);
+
+ /* Enable LED */
+ ath9k_hw_cfg_output(ah, ah->led_pin,
+ AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
+ ath9k_hw_set_gpio(ah, ah->led_pin, 0);
+}
+
+static void ath9k_htc_radio_disable(struct ieee80211_hw *hw)
+{
+ struct ath9k_htc_priv *priv = hw->priv;
+ struct ath_hw *ah = priv->ah;
+ struct ath_common *common = ath9k_hw_common(ah);
+ int ret;
+ u8 cmd_rsp;
+
+ ath9k_htc_ps_wakeup(priv);
+
+ /* Disable LED */
+ ath9k_hw_set_gpio(ah, ah->led_pin, 1);
+ ath9k_hw_cfg_gpio_input(ah, ah->led_pin);
+
+ WMI_CMD(WMI_DISABLE_INTR_CMDID);
+
+ /* Stop TX */
+ ieee80211_stop_queues(hw);
+ htc_stop(priv->htc);
+ WMI_CMD(WMI_DRAIN_TXQ_ALL_CMDID);
+ skb_queue_purge(&priv->tx_queue);
+
+ /* Stop RX */
+ WMI_CMD(WMI_STOP_RECV_CMDID);
+
+ /*
+ * The MIB counters have to be disabled here,
+ * since the target doesn't do it.
+ */
+ ath9k_hw_disable_mib_counters(ah);
+
+ if (!ah->curchan)
+ ah->curchan = ath9k_cmn_get_curchannel(hw, ah);
+
+ /* Reset the HW */
+ ret = ath9k_hw_reset(ah, ah->curchan, false);
+ if (ret) {
+ ath_print(common, ATH_DBG_FATAL,
+ "Unable to reset hardware; reset status %d "
+ "(freq %u MHz)\n", ret, ah->curchan->channel);
+ }
+
+ /* Disable the PHY */
+ ath9k_hw_phy_disable(ah);
+
+ ath9k_htc_ps_restore(priv);
+ ath9k_htc_setpower(priv, ATH9K_PM_FULL_SLEEP);
+}
+
/**********************/
/* mac80211 Callbacks */
/**********************/
@@ -1099,7 +1150,7 @@ fail_tx:
return 0;
}
-static int ath9k_htc_radio_enable(struct ieee80211_hw *hw, bool led)
+static int ath9k_htc_start(struct ieee80211_hw *hw)
{
struct ath9k_htc_priv *priv = hw->priv;
struct ath_hw *ah = priv->ah;
@@ -1111,10 +1162,16 @@ static int ath9k_htc_radio_enable(struct ieee80211_hw *hw, bool led)
__be16 htc_mode;
u8 cmd_rsp;
+ mutex_lock(&priv->mutex);
+
ath_print(common, ATH_DBG_CONFIG,
"Starting driver with initial channel: %d MHz\n",
curchan->center_freq);
+ /* Ensure that HW is awake before flushing RX */
+ ath9k_htc_setpower(priv, ATH9K_PM_AWAKE);
+ WMI_CMD(WMI_FLUSH_RECV_CMDID);
+
/* setup initial channel */
init_channel = ath9k_cmn_get_curchannel(hw, ah);
@@ -1127,6 +1184,7 @@ static int ath9k_htc_radio_enable(struct ieee80211_hw *hw, bool led)
ath_print(common, ATH_DBG_FATAL,
"Unable to reset hardware; reset status %d "
"(freq %u MHz)\n", ret, curchan->center_freq);
+ mutex_unlock(&priv->mutex);
return ret;
}
@@ -1147,31 +1205,14 @@ static int ath9k_htc_radio_enable(struct ieee80211_hw *hw, bool led)
priv->tx_queues_stop = false;
spin_unlock_bh(&priv->tx_lock);
- if (led) {
- /* Enable LED */
- ath9k_hw_cfg_output(ah, ah->led_pin,
- AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
- ath9k_hw_set_gpio(ah, ah->led_pin, 0);
- }
-
ieee80211_wake_queues(hw);
- return ret;
-}
-
-static int ath9k_htc_start(struct ieee80211_hw *hw)
-{
- struct ath9k_htc_priv *priv = hw->priv;
- int ret = 0;
-
- mutex_lock(&priv->mutex);
- ret = ath9k_htc_radio_enable(hw, false);
mutex_unlock(&priv->mutex);
return ret;
}
-static void ath9k_htc_radio_disable(struct ieee80211_hw *hw, bool led)
+static void ath9k_htc_stop(struct ieee80211_hw *hw)
{
struct ath9k_htc_priv *priv = hw->priv;
struct ath_hw *ah = priv->ah;
@@ -1179,21 +1220,17 @@ static void ath9k_htc_radio_disable(struct ieee80211_hw *hw, bool led)
int ret = 0;
u8 cmd_rsp;
+ mutex_lock(&priv->mutex);
+
if (priv->op_flags & OP_INVALID) {
ath_print(common, ATH_DBG_ANY, "Device not present\n");
+ mutex_unlock(&priv->mutex);
return;
}
- if (led) {
- /* Disable LED */
- ath9k_hw_set_gpio(ah, ah->led_pin, 1);
- ath9k_hw_cfg_gpio_input(ah, ah->led_pin);
- }
-
/* Cancel all the running timers/work .. */
cancel_work_sync(&priv->ps_work);
cancel_delayed_work_sync(&priv->ath9k_ani_work);
- cancel_delayed_work_sync(&priv->ath9k_aggr_work);
cancel_delayed_work_sync(&priv->ath9k_led_blink_work);
ath9k_led_stop_brightness(priv);
@@ -1202,12 +1239,6 @@ static void ath9k_htc_radio_disable(struct ieee80211_hw *hw, bool led)
WMI_CMD(WMI_DISABLE_INTR_CMDID);
WMI_CMD(WMI_DRAIN_TXQ_ALL_CMDID);
WMI_CMD(WMI_STOP_RECV_CMDID);
- ath9k_hw_phy_disable(ah);
- ath9k_hw_disable(ah);
- ath9k_hw_configpcipowersave(ah, 1, 1);
- ath9k_htc_ps_restore(priv);
- ath9k_htc_setpower(priv, ATH9K_PM_FULL_SLEEP);
-
skb_queue_purge(&priv->tx_queue);
/* Remove monitor interface here */
@@ -1220,21 +1251,18 @@ static void ath9k_htc_radio_disable(struct ieee80211_hw *hw, bool led)
"Monitor interface removed\n");
}
+ ath9k_hw_phy_disable(ah);
+ ath9k_hw_disable(ah);
+ ath9k_hw_configpcipowersave(ah, 1, 1);
+ ath9k_htc_ps_restore(priv);
+ ath9k_htc_setpower(priv, ATH9K_PM_FULL_SLEEP);
+
priv->op_flags |= OP_INVALID;
ath_print(common, ATH_DBG_CONFIG, "Driver halt\n");
-}
-
-static void ath9k_htc_stop(struct ieee80211_hw *hw)
-{
- struct ath9k_htc_priv *priv = hw->priv;
-
- mutex_lock(&priv->mutex);
- ath9k_htc_radio_disable(hw, false);
mutex_unlock(&priv->mutex);
}
-
static int ath9k_htc_add_interface(struct ieee80211_hw *hw,
struct ieee80211_vif *vif)
{
@@ -1302,6 +1330,7 @@ static int ath9k_htc_add_interface(struct ieee80211_hw *hw,
out:
ath9k_htc_ps_restore(priv);
mutex_unlock(&priv->mutex);
+
return ret;
}
@@ -1318,6 +1347,7 @@ static void ath9k_htc_remove_interface(struct ieee80211_hw *hw,
ath_print(common, ATH_DBG_CONFIG, "Detach Interface\n");
mutex_lock(&priv->mutex);
+ ath9k_htc_ps_wakeup(priv);
memset(&hvif, 0, sizeof(struct ath9k_htc_target_vif));
memcpy(&hvif.myaddr, vif->addr, ETH_ALEN);
@@ -1328,6 +1358,7 @@ static void ath9k_htc_remove_interface(struct ieee80211_hw *hw,
ath9k_htc_remove_station(priv, vif, NULL);
priv->vif = NULL;
+ ath9k_htc_ps_restore(priv);
mutex_unlock(&priv->mutex);
}
@@ -1343,30 +1374,27 @@ static int ath9k_htc_config(struct ieee80211_hw *hw, u32 changed)
bool enable_radio = false;
bool idle = !!(conf->flags & IEEE80211_CONF_IDLE);
+ mutex_lock(&priv->htc_pm_lock);
if (!idle && priv->ps_idle)
enable_radio = true;
-
priv->ps_idle = idle;
+ mutex_unlock(&priv->htc_pm_lock);
if (enable_radio) {
- ath9k_htc_setpower(priv, ATH9K_PM_AWAKE);
- ath9k_htc_radio_enable(hw, true);
ath_print(common, ATH_DBG_CONFIG,
"not-idle: enabling radio\n");
+ ath9k_htc_setpower(priv, ATH9K_PM_AWAKE);
+ ath9k_htc_radio_enable(hw);
}
}
if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
struct ieee80211_channel *curchan = hw->conf.channel;
int pos = curchan->hw_value;
- bool is_cw40 = false;
ath_print(common, ATH_DBG_CONFIG, "Set channel: %d MHz\n",
curchan->center_freq);
- if (check_rc_update(hw, &is_cw40))
- ath9k_htc_rc_update(priv, is_cw40);
-
ath9k_cmn_update_ichannel(hw, &priv->ah->channels[pos]);
if (ath9k_htc_set_channel(priv, hw, &priv->ah->channels[pos]) < 0) {
@@ -1399,14 +1427,21 @@ static int ath9k_htc_config(struct ieee80211_hw *hw, u32 changed)
}
}
- if (priv->ps_idle) {
+ if (changed & IEEE80211_CONF_CHANGE_IDLE) {
+ mutex_lock(&priv->htc_pm_lock);
+ if (!priv->ps_idle) {
+ mutex_unlock(&priv->htc_pm_lock);
+ goto out;
+ }
+ mutex_unlock(&priv->htc_pm_lock);
+
ath_print(common, ATH_DBG_CONFIG,
"idle: disabling radio\n");
- ath9k_htc_radio_disable(hw, true);
+ ath9k_htc_radio_disable(hw);
}
+out:
mutex_unlock(&priv->mutex);
-
return 0;
}
@@ -1428,8 +1463,8 @@ static void ath9k_htc_configure_filter(struct ieee80211_hw *hw,
u32 rfilt;
mutex_lock(&priv->mutex);
-
ath9k_htc_ps_wakeup(priv);
+
changed_flags &= SUPPORTED_FILTERS;
*total_flags &= SUPPORTED_FILTERS;
@@ -1444,30 +1479,38 @@ static void ath9k_htc_configure_filter(struct ieee80211_hw *hw,
mutex_unlock(&priv->mutex);
}
-static void ath9k_htc_sta_notify(struct ieee80211_hw *hw,
- struct ieee80211_vif *vif,
- enum sta_notify_cmd cmd,
- struct ieee80211_sta *sta)
+static int ath9k_htc_sta_add(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta)
{
struct ath9k_htc_priv *priv = hw->priv;
int ret;
mutex_lock(&priv->mutex);
+ ath9k_htc_ps_wakeup(priv);
+ ret = ath9k_htc_add_station(priv, vif, sta);
+ if (!ret)
+ ath9k_htc_init_rate(priv, sta);
+ ath9k_htc_ps_restore(priv);
+ mutex_unlock(&priv->mutex);
- switch (cmd) {
- case STA_NOTIFY_ADD:
- ret = ath9k_htc_add_station(priv, vif, sta);
- if (!ret)
- ath9k_htc_init_rate(priv, vif, sta);
- break;
- case STA_NOTIFY_REMOVE:
- ath9k_htc_remove_station(priv, vif, sta);
- break;
- default:
- break;
- }
+ return ret;
+}
+
+static int ath9k_htc_sta_remove(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta)
+{
+ struct ath9k_htc_priv *priv = hw->priv;
+ int ret;
+ mutex_lock(&priv->mutex);
+ ath9k_htc_ps_wakeup(priv);
+ ret = ath9k_htc_remove_station(priv, vif, sta);
+ ath9k_htc_ps_restore(priv);
mutex_unlock(&priv->mutex);
+
+ return ret;
}
static int ath9k_htc_conf_tx(struct ieee80211_hw *hw, u16 queue,
@@ -1482,6 +1525,7 @@ static int ath9k_htc_conf_tx(struct ieee80211_hw *hw, u16 queue,
return 0;
mutex_lock(&priv->mutex);
+ ath9k_htc_ps_wakeup(priv);
memset(&qi, 0, sizeof(struct ath9k_tx_queue_info));
@@ -1499,9 +1543,16 @@ static int ath9k_htc_conf_tx(struct ieee80211_hw *hw, u16 queue,
params->cw_max, params->txop);
ret = ath_htc_txq_update(priv, qnum, &qi);
- if (ret)
+ if (ret) {
ath_print(common, ATH_DBG_FATAL, "TXQ Update failed\n");
+ goto out;
+ }
+ if ((priv->ah->opmode == NL80211_IFTYPE_ADHOC) &&
+ (qnum == priv->hwq_map[WME_AC_BE]))
+ ath9k_htc_beaconq_config(priv);
+out:
+ ath9k_htc_ps_restore(priv);
mutex_unlock(&priv->mutex);
return ret;
@@ -1574,7 +1625,6 @@ static void ath9k_htc_bss_info_changed(struct ieee80211_hw *hw,
ath_start_ani(priv);
} else {
priv->op_flags &= ~OP_ASSOCIATED;
- cancel_work_sync(&priv->ps_work);
cancel_delayed_work_sync(&priv->ath9k_ani_work);
}
}
@@ -1631,6 +1681,9 @@ static void ath9k_htc_bss_info_changed(struct ieee80211_hw *hw,
ath9k_hw_init_global_settings(ah);
}
+ if (changed & BSS_CHANGED_HT)
+ ath9k_htc_update_rate(priv, vif, bss_conf);
+
ath9k_htc_ps_restore(priv);
mutex_unlock(&priv->mutex);
}
@@ -1641,7 +1694,9 @@ static u64 ath9k_htc_get_tsf(struct ieee80211_hw *hw)
u64 tsf;
mutex_lock(&priv->mutex);
+ ath9k_htc_ps_wakeup(priv);
tsf = ath9k_hw_gettsf64(priv->ah);
+ ath9k_htc_ps_restore(priv);
mutex_unlock(&priv->mutex);
return tsf;
@@ -1652,7 +1707,9 @@ static void ath9k_htc_set_tsf(struct ieee80211_hw *hw, u64 tsf)
struct ath9k_htc_priv *priv = hw->priv;
mutex_lock(&priv->mutex);
+ ath9k_htc_ps_wakeup(priv);
ath9k_hw_settsf64(priv->ah, tsf);
+ ath9k_htc_ps_restore(priv);
mutex_unlock(&priv->mutex);
}
@@ -1660,11 +1717,11 @@ static void ath9k_htc_reset_tsf(struct ieee80211_hw *hw)
{
struct ath9k_htc_priv *priv = hw->priv;
- ath9k_htc_ps_wakeup(priv);
mutex_lock(&priv->mutex);
+ ath9k_htc_ps_wakeup(priv);
ath9k_hw_reset_tsf(priv->ah);
- mutex_unlock(&priv->mutex);
ath9k_htc_ps_restore(priv);
+ mutex_unlock(&priv->mutex);
}
static int ath9k_htc_ampdu_action(struct ieee80211_hw *hw,
@@ -1674,8 +1731,8 @@ static int ath9k_htc_ampdu_action(struct ieee80211_hw *hw,
u16 tid, u16 *ssn)
{
struct ath9k_htc_priv *priv = hw->priv;
- struct ath9k_htc_aggr_work *work = &priv->aggr_work;
struct ath9k_htc_sta *ista;
+ int ret = 0;
switch (action) {
case IEEE80211_AMPDU_RX_START:
@@ -1683,26 +1740,26 @@ static int ath9k_htc_ampdu_action(struct ieee80211_hw *hw,
case IEEE80211_AMPDU_RX_STOP:
break;
case IEEE80211_AMPDU_TX_START:
+ ret = ath9k_htc_tx_aggr_oper(priv, vif, sta, action, tid);
+ if (!ret)
+ ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid);
+ break;
case IEEE80211_AMPDU_TX_STOP:
- if (!(priv->op_flags & OP_TXAGGR))
- return -ENOTSUPP;
- memcpy(work->sta_addr, sta->addr, ETH_ALEN);
- work->hw = hw;
- work->vif = vif;
- work->action = action;
- work->tid = tid;
- ieee80211_queue_delayed_work(hw, &priv->ath9k_aggr_work, 0);
+ ath9k_htc_tx_aggr_oper(priv, vif, sta, action, tid);
+ ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
break;
case IEEE80211_AMPDU_TX_OPERATIONAL:
ista = (struct ath9k_htc_sta *) sta->drv_priv;
+ spin_lock_bh(&priv->tx_lock);
ista->tid_state[tid] = AGGR_OPERATIONAL;
+ spin_unlock_bh(&priv->tx_lock);
break;
default:
ath_print(ath9k_hw_common(priv->ah), ATH_DBG_FATAL,
"Unknown AMPDU action\n");
}
- return 0;
+ return ret;
}
static void ath9k_htc_sw_scan_start(struct ieee80211_hw *hw)
@@ -1722,8 +1779,8 @@ static void ath9k_htc_sw_scan_complete(struct ieee80211_hw *hw)
{
struct ath9k_htc_priv *priv = hw->priv;
- ath9k_htc_ps_wakeup(priv);
mutex_lock(&priv->mutex);
+ ath9k_htc_ps_wakeup(priv);
spin_lock_bh(&priv->beacon_lock);
priv->op_flags &= ~OP_SCANNING;
spin_unlock_bh(&priv->beacon_lock);
@@ -1731,8 +1788,8 @@ static void ath9k_htc_sw_scan_complete(struct ieee80211_hw *hw)
if (priv->op_flags & OP_ASSOCIATED)
ath9k_htc_beacon_config(priv, priv->vif);
ath_start_ani(priv);
- mutex_unlock(&priv->mutex);
ath9k_htc_ps_restore(priv);
+ mutex_unlock(&priv->mutex);
}
static int ath9k_htc_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
@@ -1746,8 +1803,10 @@ static void ath9k_htc_set_coverage_class(struct ieee80211_hw *hw,
struct ath9k_htc_priv *priv = hw->priv;
mutex_lock(&priv->mutex);
+ ath9k_htc_ps_wakeup(priv);
priv->ah->coverage_class = coverage_class;
ath9k_hw_init_global_settings(priv->ah);
+ ath9k_htc_ps_restore(priv);
mutex_unlock(&priv->mutex);
}
@@ -1759,7 +1818,8 @@ struct ieee80211_ops ath9k_htc_ops = {
.remove_interface = ath9k_htc_remove_interface,
.config = ath9k_htc_config,
.configure_filter = ath9k_htc_configure_filter,
- .sta_notify = ath9k_htc_sta_notify,
+ .sta_add = ath9k_htc_sta_add,
+ .sta_remove = ath9k_htc_sta_remove,
.conf_tx = ath9k_htc_conf_tx,
.bss_info_changed = ath9k_htc_bss_info_changed,
.set_key = ath9k_htc_set_key,
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c
index 2571b443ac8..bd0b4acc3ec 100644
--- a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c
@@ -20,19 +20,29 @@
/* TX */
/******/
+#define ATH9K_HTC_INIT_TXQ(subtype) do { \
+ qi.tqi_subtype = subtype; \
+ qi.tqi_aifs = ATH9K_TXQ_USEDEFAULT; \
+ qi.tqi_cwmin = ATH9K_TXQ_USEDEFAULT; \
+ qi.tqi_cwmax = ATH9K_TXQ_USEDEFAULT; \
+ qi.tqi_physCompBuf = 0; \
+ qi.tqi_qflags = TXQ_FLAG_TXEOLINT_ENABLE | \
+ TXQ_FLAG_TXDESCINT_ENABLE; \
+ } while (0)
+
int get_hw_qnum(u16 queue, int *hwq_map)
{
switch (queue) {
case 0:
- return hwq_map[ATH9K_WME_AC_VO];
+ return hwq_map[WME_AC_VO];
case 1:
- return hwq_map[ATH9K_WME_AC_VI];
+ return hwq_map[WME_AC_VI];
case 2:
- return hwq_map[ATH9K_WME_AC_BE];
+ return hwq_map[WME_AC_BE];
case 3:
- return hwq_map[ATH9K_WME_AC_BK];
+ return hwq_map[WME_AC_BK];
default:
- return hwq_map[ATH9K_WME_AC_BE];
+ return hwq_map[WME_AC_BE];
}
}
@@ -71,7 +81,7 @@ int ath9k_htc_tx_start(struct ath9k_htc_priv *priv, struct sk_buff *skb)
struct ath9k_htc_vif *avp;
struct ath9k_htc_tx_ctl tx_ctl;
enum htc_endpoint_id epid;
- u16 qnum, hw_qnum;
+ u16 qnum;
__le16 fc;
u8 *tx_fhdr;
u8 sta_idx;
@@ -131,20 +141,23 @@ int ath9k_htc_tx_start(struct ath9k_htc_priv *priv, struct sk_buff *skb)
memcpy(tx_fhdr, (u8 *) &tx_hdr, sizeof(tx_hdr));
qnum = skb_get_queue_mapping(skb);
- hw_qnum = get_hw_qnum(qnum, priv->hwq_map);
- switch (hw_qnum) {
+ switch (qnum) {
case 0:
- epid = priv->data_be_ep;
+ TX_QSTAT_INC(WME_AC_VO);
+ epid = priv->data_vo_ep;
break;
- case 2:
+ case 1:
+ TX_QSTAT_INC(WME_AC_VI);
epid = priv->data_vi_ep;
break;
- case 3:
- epid = priv->data_vo_ep;
+ case 2:
+ TX_QSTAT_INC(WME_AC_BE);
+ epid = priv->data_be_ep;
break;
- case 1:
+ case 3:
default:
+ TX_QSTAT_INC(WME_AC_BK);
epid = priv->data_bk_ep;
break;
}
@@ -174,6 +187,19 @@ int ath9k_htc_tx_start(struct ath9k_htc_priv *priv, struct sk_buff *skb)
return htc_send(priv->htc, skb, epid, &tx_ctl);
}
+static bool ath9k_htc_check_tx_aggr(struct ath9k_htc_priv *priv,
+ struct ath9k_htc_sta *ista, u8 tid)
+{
+ bool ret = false;
+
+ spin_lock_bh(&priv->tx_lock);
+ if ((tid < ATH9K_HTC_MAX_TID) && (ista->tid_state[tid] == AGGR_STOP))
+ ret = true;
+ spin_unlock_bh(&priv->tx_lock);
+
+ return ret;
+}
+
void ath9k_tx_tasklet(unsigned long data)
{
struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *)data;
@@ -203,8 +229,7 @@ void ath9k_tx_tasklet(unsigned long data)
/* Check if we need to start aggregation */
if (sta && conf_is_ht(&priv->hw->conf) &&
- (priv->op_flags & OP_TXAGGR)
- && !(skb->protocol == cpu_to_be16(ETH_P_PAE))) {
+ !(skb->protocol == cpu_to_be16(ETH_P_PAE))) {
if (ieee80211_is_data_qos(fc)) {
u8 *qc, tid;
struct ath9k_htc_sta *ista;
@@ -213,10 +238,11 @@ void ath9k_tx_tasklet(unsigned long data)
tid = qc[0] & 0xf;
ista = (struct ath9k_htc_sta *)sta->drv_priv;
- if ((tid < ATH9K_HTC_MAX_TID) &&
- ista->tid_state[tid] == AGGR_STOP) {
+ if (ath9k_htc_check_tx_aggr(priv, ista, tid)) {
ieee80211_start_tx_ba_session(sta, tid);
+ spin_lock_bh(&priv->tx_lock);
ista->tid_state[tid] = AGGR_PROGRESS;
+ spin_unlock_bh(&priv->tx_lock);
}
}
}
@@ -284,8 +310,7 @@ void ath9k_tx_cleanup(struct ath9k_htc_priv *priv)
}
-bool ath9k_htc_txq_setup(struct ath9k_htc_priv *priv,
- enum ath9k_tx_queue_subtype subtype)
+bool ath9k_htc_txq_setup(struct ath9k_htc_priv *priv, int subtype)
{
struct ath_hw *ah = priv->ah;
struct ath_common *common = ath9k_hw_common(ah);
@@ -293,13 +318,7 @@ bool ath9k_htc_txq_setup(struct ath9k_htc_priv *priv,
int qnum;
memset(&qi, 0, sizeof(qi));
-
- qi.tqi_subtype = subtype;
- qi.tqi_aifs = ATH9K_TXQ_USEDEFAULT;
- qi.tqi_cwmin = ATH9K_TXQ_USEDEFAULT;
- qi.tqi_cwmax = ATH9K_TXQ_USEDEFAULT;
- qi.tqi_physCompBuf = 0;
- qi.tqi_qflags = TXQ_FLAG_TXEOLINT_ENABLE | TXQ_FLAG_TXDESCINT_ENABLE;
+ ATH9K_HTC_INIT_TXQ(subtype);
qnum = ath9k_hw_setuptxqueue(priv->ah, ATH9K_TX_QUEUE_DATA, &qi);
if (qnum == -1)
@@ -317,6 +336,16 @@ bool ath9k_htc_txq_setup(struct ath9k_htc_priv *priv,
return true;
}
+int ath9k_htc_cabq_setup(struct ath9k_htc_priv *priv)
+{
+ struct ath9k_tx_queue_info qi;
+
+ memset(&qi, 0, sizeof(qi));
+ ATH9K_HTC_INIT_TXQ(0);
+
+ return ath9k_hw_setuptxqueue(priv->ah, ATH9K_TX_QUEUE_CAB, &qi);
+}
+
/******/
/* RX */
/******/
@@ -387,9 +416,6 @@ static void ath9k_htc_opmode_init(struct ath9k_htc_priv *priv)
/* configure operational mode */
ath9k_hw_setopmode(ah);
- /* Handle any link-level address change. */
- ath9k_hw_setmac(ah, common->macaddr);
-
/* calculate and install multicast filter */
mfilt[0] = mfilt[1] = ~0;
ath9k_hw_setmcastfilter(ah, mfilt[0], mfilt[1]);
@@ -399,7 +425,7 @@ void ath9k_host_rx_init(struct ath9k_htc_priv *priv)
{
ath9k_hw_rxena(priv->ah);
ath9k_htc_opmode_init(priv);
- ath9k_hw_startpcureceive(priv->ah);
+ ath9k_hw_startpcureceive(priv->ah, (priv->op_flags & OP_SCANNING));
priv->rx.last_rssi = ATH_RSSI_DUMMY_MARKER;
}
diff --git a/drivers/net/wireless/ath/ath9k/htc_hst.c b/drivers/net/wireless/ath/ath9k/htc_hst.c
index 064397fd738..705c0f342e1 100644
--- a/drivers/net/wireless/ath/ath9k/htc_hst.c
+++ b/drivers/net/wireless/ath/ath9k/htc_hst.c
@@ -89,7 +89,6 @@ static void htc_process_target_rdy(struct htc_target *target,
struct htc_endpoint *endpoint;
struct htc_ready_msg *htc_ready_msg = (struct htc_ready_msg *) buf;
- target->credits = be16_to_cpu(htc_ready_msg->credits);
target->credit_size = be16_to_cpu(htc_ready_msg->credit_size);
endpoint = &target->endpoint[ENDPOINT0];
@@ -159,7 +158,7 @@ static int htc_config_pipe_credits(struct htc_target *target)
cp_msg->message_id = cpu_to_be16(HTC_MSG_CONFIG_PIPE_ID);
cp_msg->pipe_id = USB_WLAN_TX_PIPE;
- cp_msg->credits = 28;
+ cp_msg->credits = target->credits;
target->htc_flags |= HTC_OP_CONFIG_PIPE_CREDITS;
diff --git a/drivers/net/wireless/ath/ath9k/hw-ops.h b/drivers/net/wireless/ath/ath9k/hw-ops.h
index 624422a8169..ffecbadaea4 100644
--- a/drivers/net/wireless/ath/ath9k/hw-ops.h
+++ b/drivers/net/wireless/ath/ath9k/hw-ops.h
@@ -128,6 +128,17 @@ static inline void ath9k_hw_set11n_virtualmorefrag(struct ath_hw *ah, void *ds,
ath9k_hw_ops(ah)->set11n_virtualmorefrag(ah, ds, vmf);
}
+static inline void ath9k_hw_procmibevent(struct ath_hw *ah)
+{
+ ath9k_hw_ops(ah)->ani_proc_mib_event(ah);
+}
+
+static inline void ath9k_hw_ani_monitor(struct ath_hw *ah,
+ struct ath9k_channel *chan)
+{
+ ath9k_hw_ops(ah)->ani_monitor(ah, chan);
+}
+
/* Private hardware call ops */
/* PHY ops */
@@ -253,12 +264,6 @@ static inline void ath9k_hw_do_getnf(struct ath_hw *ah,
ath9k_hw_private_ops(ah)->do_getnf(ah, nfarray);
}
-static inline void ath9k_hw_loadnf(struct ath_hw *ah,
- struct ath9k_channel *chan)
-{
- ath9k_hw_private_ops(ah)->loadnf(ah, chan);
-}
-
static inline bool ath9k_hw_init_cal(struct ath_hw *ah,
struct ath9k_channel *chan)
{
@@ -277,4 +282,9 @@ static inline bool ath9k_hw_iscal_supported(struct ath_hw *ah,
return ath9k_hw_private_ops(ah)->iscal_supported(ah, calType);
}
+static inline void ath9k_ani_reset(struct ath_hw *ah, bool is_scanning)
+{
+ ath9k_hw_private_ops(ah)->ani_reset(ah, is_scanning);
+}
+
#endif /* ATH9K_HW_OPS_H */
diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c
index c33f17dbe6f..8d291ccf5c8 100644
--- a/drivers/net/wireless/ath/ath9k/hw.c
+++ b/drivers/net/wireless/ath/ath9k/hw.c
@@ -23,11 +23,6 @@
#include "rc.h"
#include "ar9003_mac.h"
-#define ATH9K_CLOCK_RATE_CCK 22
-#define ATH9K_CLOCK_RATE_5GHZ_OFDM 40
-#define ATH9K_CLOCK_RATE_2GHZ_OFDM 44
-#define ATH9K_CLOCK_FAST_RATE_5GHZ_OFDM 44
-
static bool ath9k_hw_set_reset_reg(struct ath_hw *ah, u32 type);
MODULE_AUTHOR("Atheros Communications");
@@ -80,6 +75,15 @@ static void ath9k_hw_init_mode_gain_regs(struct ath_hw *ah)
ath9k_hw_private_ops(ah)->init_mode_gain_regs(ah);
}
+static void ath9k_hw_ani_cache_ini_regs(struct ath_hw *ah)
+{
+ /* You will not have this callback if using the old ANI */
+ if (!ath9k_hw_private_ops(ah)->ani_cache_ini_regs)
+ return;
+
+ ath9k_hw_private_ops(ah)->ani_cache_ini_regs(ah);
+}
+
/********************/
/* Helper Functions */
/********************/
@@ -371,13 +375,7 @@ static void ath9k_hw_init_config(struct ath_hw *ah)
ah->config.ofdm_trig_high = 500;
ah->config.cck_trig_high = 200;
ah->config.cck_trig_low = 100;
-
- /*
- * For now ANI is disabled for AR9003, it is still
- * being tested.
- */
- if (!AR_SREV_9300_20_OR_LATER(ah))
- ah->config.enable_ani = 1;
+ ah->config.enable_ani = true;
for (i = 0; i < AR_EEPROM_MODAL_SPURS; i++) {
ah->config.spurchans[i][0] = AR_NO_SPUR;
@@ -390,12 +388,7 @@ static void ath9k_hw_init_config(struct ath_hw *ah)
ah->config.ht_enable = 0;
ah->config.rx_intr_mitigation = true;
-
- /*
- * Tx IQ Calibration (ah->config.tx_iq_calibration) is only
- * used by AR9003, but it is showing reliability issues.
- * It will take a while to fix so this is currently disabled.
- */
+ ah->config.pcieSerDesWrite = true;
/*
* We need this for PCI devices only (Cardbus, PCI, miniPCI)
@@ -433,7 +426,9 @@ static void ath9k_hw_init_defaults(struct ath_hw *ah)
ah->ah_flags = AH_USE_EEPROM;
ah->atim_window = 0;
- ah->sta_id1_defaults = AR_STA_ID1_CRPT_MIC_ENABLE;
+ ah->sta_id1_defaults =
+ AR_STA_ID1_CRPT_MIC_ENABLE |
+ AR_STA_ID1_MCAST_KSRCH;
ah->beacon_interval = 100;
ah->enable_32kHz_clock = DONT_USE_32KHZ;
ah->slottime = (u32) -1;
@@ -537,7 +532,8 @@ static int __ath9k_hw_init(struct ath_hw *ah)
if (ah->config.serialize_regmode == SER_REG_MODE_AUTO) {
if (ah->hw_version.macVersion == AR_SREV_VERSION_5416_PCI ||
- (AR_SREV_9280(ah) && !ah->is_pciexpress)) {
+ ((AR_SREV_9160(ah) || AR_SREV_9280(ah)) &&
+ !ah->is_pciexpress)) {
ah->config.serialize_regmode =
SER_REG_MODE_ON;
} else {
@@ -571,28 +567,19 @@ static int __ath9k_hw_init(struct ath_hw *ah)
ah->ani_function = ATH9K_ANI_ALL;
if (AR_SREV_9280_10_OR_LATER(ah) && !AR_SREV_9300_20_OR_LATER(ah))
ah->ani_function &= ~ATH9K_ANI_NOISE_IMMUNITY_LEVEL;
+ if (!AR_SREV_9300_20_OR_LATER(ah))
+ ah->ani_function &= ~ATH9K_ANI_MRC_CCK;
ath9k_hw_init_mode_regs(ah);
/*
- * Configire PCIE after Ini init. SERDES values now come from ini file
- * This enables PCIe low power mode.
+ * Read back AR_WA into a permanent copy and set bits 14 and 17.
+ * We need to do this to avoid RMW of this register. We cannot
+ * read the reg when chip is asleep.
*/
- if (AR_SREV_9300_20_OR_LATER(ah)) {
- u32 regval;
- unsigned int i;
-
- /* Set Bits 16 and 17 in the AR_WA register. */
- regval = REG_READ(ah, AR_WA);
- regval |= 0x00030000;
- REG_WRITE(ah, AR_WA, regval);
-
- for (i = 0; i < ah->iniPcieSerdesLowPower.ia_rows; i++) {
- REG_WRITE(ah,
- INI_RA(&ah->iniPcieSerdesLowPower, i, 0),
- INI_RA(&ah->iniPcieSerdesLowPower, i, 1));
- }
- }
+ ah->WARegVal = REG_READ(ah, AR_WA);
+ ah->WARegVal |= (AR_WA_D3_L1_DISABLE |
+ AR_WA_ASPM_TIMER_BASED_DISABLE);
if (ah->is_pciexpress)
ath9k_hw_configpcipowersave(ah, 0, 0);
@@ -623,10 +610,8 @@ static int __ath9k_hw_init(struct ath_hw *ah)
else
ah->tx_trig_level = (AR_FTRIG_512B >> AR_FTRIG_S);
- if (AR_SREV_9300_20_OR_LATER(ah))
- ar9003_hw_set_nf_limits(ah);
-
ath9k_init_nfcal_hist_buffer(ah);
+ ah->bb_watchdog_timeout_ms = 25;
common->state = ATH_HW_INITIALIZED;
@@ -1012,6 +997,11 @@ static bool ath9k_hw_set_reset(struct ath_hw *ah, int type)
ENABLE_REGWRITE_BUFFER(ah);
+ if (AR_SREV_9300_20_OR_LATER(ah)) {
+ REG_WRITE(ah, AR_WA, ah->WARegVal);
+ udelay(10);
+ }
+
REG_WRITE(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_EN |
AR_RTC_FORCE_WAKE_ON_INT);
@@ -1066,6 +1056,11 @@ static bool ath9k_hw_set_reset_power_on(struct ath_hw *ah)
{
ENABLE_REGWRITE_BUFFER(ah);
+ if (AR_SREV_9300_20_OR_LATER(ah)) {
+ REG_WRITE(ah, AR_WA, ah->WARegVal);
+ udelay(10);
+ }
+
REG_WRITE(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_EN |
AR_RTC_FORCE_WAKE_ON_INT);
@@ -1073,6 +1068,7 @@ static bool ath9k_hw_set_reset_power_on(struct ath_hw *ah)
REG_WRITE(ah, AR_RC, AR_RC_AHB);
REG_WRITE(ah, AR_RTC_RESET, 0);
+ udelay(2);
REGWRITE_BUFFER_FLUSH(ah);
DISABLE_REGWRITE_BUFFER(ah);
@@ -1102,6 +1098,11 @@ static bool ath9k_hw_set_reset_power_on(struct ath_hw *ah)
static bool ath9k_hw_set_reset_reg(struct ath_hw *ah, u32 type)
{
+ if (AR_SREV_9300_20_OR_LATER(ah)) {
+ REG_WRITE(ah, AR_WA, ah->WARegVal);
+ udelay(10);
+ }
+
REG_WRITE(ah, AR_RTC_FORCE_WAKE,
AR_RTC_FORCE_WAKE_EN | AR_RTC_FORCE_WAKE_ON_INT);
@@ -1232,9 +1233,11 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
if (!ah->chip_fullsleep) {
ath9k_hw_abortpcurecv(ah);
- if (!ath9k_hw_stopdmarecv(ah))
+ if (!ath9k_hw_stopdmarecv(ah)) {
ath_print(common, ATH_DBG_XMIT,
"Failed to stop receive dma\n");
+ bChannelChange = false;
+ }
}
if (!ath9k_hw_setpower(ah, ATH9K_PM_AWAKE))
@@ -1265,7 +1268,8 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
macStaId1 = REG_READ(ah, AR_STA_ID1) & AR_STA_ID1_BASE_RATE_11B;
/* For chips on which RTC reset is done, save TSF before it gets cleared */
- if (AR_SREV_9280(ah) && ah->eep_ops->get_eeprom(ah, EEP_OL_PWRCTRL))
+ if (AR_SREV_9100(ah) ||
+ (AR_SREV_9280(ah) && ah->eep_ops->get_eeprom(ah, EEP_OL_PWRCTRL)))
tsf = ath9k_hw_gettsf64(ah);
saveLedState = REG_READ(ah, AR_CFG_LED) &
@@ -1297,16 +1301,30 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
}
/* Restore TSF */
- if (tsf && AR_SREV_9280(ah) && ah->eep_ops->get_eeprom(ah, EEP_OL_PWRCTRL))
+ if (tsf)
ath9k_hw_settsf64(ah, tsf);
if (AR_SREV_9280_10_OR_LATER(ah))
REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL, AR_GPIO_JTAG_DISABLE);
+ if (!AR_SREV_9300_20_OR_LATER(ah))
+ ar9002_hw_enable_async_fifo(ah);
+
r = ath9k_hw_process_ini(ah, chan);
if (r)
return r;
+ /*
+ * Some AR91xx SoC devices frequently fail to accept TSF writes
+ * right after the chip reset. When that happens, write a new
+ * value after the initvals have been applied, with an offset
+ * based on measured time difference
+ */
+ if (AR_SREV_9100(ah) && (ath9k_hw_gettsf64(ah) < tsf)) {
+ tsf += 1500;
+ ath9k_hw_settsf64(ah, tsf);
+ }
+
/* Setup MFP options for CCMP */
if (AR_SREV_9280_20_OR_LATER(ah)) {
/* Mask Retry(b11), PwrMgt(b12), MoreData(b13) to 0 in mgmt
@@ -1367,6 +1385,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
ath9k_hw_resettxqueue(ah, i);
ath9k_hw_init_interrupt_masks(ah, ah->opmode);
+ ath9k_hw_ani_cache_ini_regs(ah);
ath9k_hw_init_qos(ah);
if (ah->caps.hw_caps & ATH9K_HW_CAP_RFSILENT)
@@ -1375,7 +1394,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
ath9k_hw_init_global_settings(ah);
if (!AR_SREV_9300_20_OR_LATER(ah)) {
- ar9002_hw_enable_async_fifo(ah);
+ ar9002_hw_update_async_fifo(ah);
ar9002_hw_enable_wep_aggregation(ah);
}
@@ -1426,9 +1445,13 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
"Setting CFG 0x%x\n", REG_READ(ah, AR_CFG));
}
} else {
- /* Configure AR9271 target WLAN */
- if (AR_SREV_9271(ah))
- REG_WRITE(ah, AR_CFG, AR_CFG_SWRB | AR_CFG_SWTB);
+ if (common->bus_ops->ath_bus_type == ATH_USB) {
+ /* Configure AR9271 target WLAN */
+ if (AR_SREV_9271(ah))
+ REG_WRITE(ah, AR_CFG, AR_CFG_SWRB | AR_CFG_SWTB);
+ else
+ REG_WRITE(ah, AR_CFG, AR_CFG_SWTD | AR_CFG_SWRD);
+ }
#ifdef __BIG_ENDIAN
else
REG_WRITE(ah, AR_CFG, AR_CFG_SWTD | AR_CFG_SWRD);
@@ -1441,6 +1464,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
if (AR_SREV_9300_20_OR_LATER(ah)) {
ath9k_hw_loadnf(ah, curchan);
ath9k_hw_start_nfcal(ah);
+ ar9003_hw_bb_watchdog_config(ah);
}
return 0;
@@ -1486,9 +1510,10 @@ bool ath9k_hw_keyreset(struct ath_hw *ah, u16 entry)
}
EXPORT_SYMBOL(ath9k_hw_keyreset);
-bool ath9k_hw_keysetmac(struct ath_hw *ah, u16 entry, const u8 *mac)
+static bool ath9k_hw_keysetmac(struct ath_hw *ah, u16 entry, const u8 *mac)
{
u32 macHi, macLo;
+ u32 unicast_flag = AR_KEYTABLE_VALID;
if (entry >= ah->caps.keycache_size) {
ath_print(ath9k_hw_common(ah), ATH_DBG_FATAL,
@@ -1497,6 +1522,16 @@ bool ath9k_hw_keysetmac(struct ath_hw *ah, u16 entry, const u8 *mac)
}
if (mac != NULL) {
+ /*
+ * AR_KEYTABLE_VALID indicates that the address is a unicast
+ * address, which must match the transmitter address for
+ * decrypting frames.
+ * Not setting this bit allows the hardware to use the key
+ * for multicast frame decryption.
+ */
+ if (mac[0] & 0x01)
+ unicast_flag = 0;
+
macHi = (mac[5] << 8) | mac[4];
macLo = (mac[3] << 24) |
(mac[2] << 16) |
@@ -1509,11 +1544,10 @@ bool ath9k_hw_keysetmac(struct ath_hw *ah, u16 entry, const u8 *mac)
macLo = macHi = 0;
}
REG_WRITE(ah, AR_KEYTABLE_MAC0(entry), macLo);
- REG_WRITE(ah, AR_KEYTABLE_MAC1(entry), macHi | AR_KEYTABLE_VALID);
+ REG_WRITE(ah, AR_KEYTABLE_MAC1(entry), macHi | unicast_flag);
return true;
}
-EXPORT_SYMBOL(ath9k_hw_keysetmac);
bool ath9k_hw_set_keycache_entry(struct ath_hw *ah, u16 entry,
const struct ath9k_keyval *k,
@@ -1714,17 +1748,6 @@ bool ath9k_hw_set_keycache_entry(struct ath_hw *ah, u16 entry,
}
EXPORT_SYMBOL(ath9k_hw_set_keycache_entry);
-bool ath9k_hw_keyisvalid(struct ath_hw *ah, u16 entry)
-{
- if (entry < ah->caps.keycache_size) {
- u32 val = REG_READ(ah, AR_KEYTABLE_MAC1(entry));
- if (val & AR_KEYTABLE_VALID)
- return true;
- }
- return false;
-}
-EXPORT_SYMBOL(ath9k_hw_keyisvalid);
-
/******************************/
/* Power Management (Chipset) */
/******************************/
@@ -1751,6 +1774,11 @@ static void ath9k_set_power_sleep(struct ath_hw *ah, int setChip)
REG_CLR_BIT(ah, (AR_RTC_RESET),
AR_RTC_RESET_EN);
}
+
+ /* Clear Bit 14 of AR_WA after putting chip into Full Sleep mode. */
+ if (AR_SREV_9300_20_OR_LATER(ah))
+ REG_WRITE(ah, AR_WA,
+ ah->WARegVal & ~AR_WA_D3_L1_DISABLE);
}
/*
@@ -1777,6 +1805,10 @@ static void ath9k_set_power_network_sleep(struct ath_hw *ah, int setChip)
AR_RTC_FORCE_WAKE_EN);
}
}
+
+ /* Clear Bit 14 of AR_WA after putting chip into Net Sleep mode. */
+ if (AR_SREV_9300_20_OR_LATER(ah))
+ REG_WRITE(ah, AR_WA, ah->WARegVal & ~AR_WA_D3_L1_DISABLE);
}
static bool ath9k_hw_set_power_awake(struct ath_hw *ah, int setChip)
@@ -1784,6 +1816,12 @@ static bool ath9k_hw_set_power_awake(struct ath_hw *ah, int setChip)
u32 val;
int i;
+ /* Set Bits 14 and 17 of AR_WA before powering on the chip. */
+ if (AR_SREV_9300_20_OR_LATER(ah)) {
+ REG_WRITE(ah, AR_WA, ah->WARegVal);
+ udelay(10);
+ }
+
if (setChip) {
if ((REG_READ(ah, AR_RTC_STATUS) &
AR_RTC_STATUS_M) == AR_RTC_STATUS_SHUTDOWN) {
@@ -2138,6 +2176,8 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah)
if (AR_SREV_9271(ah))
pCap->num_gpio_pins = AR9271_NUM_GPIO;
+ else if (AR_DEVID_7010(ah))
+ pCap->num_gpio_pins = AR7010_NUM_GPIO;
else if (AR_SREV_9285_10_OR_LATER(ah))
pCap->num_gpio_pins = AR9285_NUM_GPIO;
else if (AR_SREV_9280_10_OR_LATER(ah))
@@ -2165,7 +2205,7 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah)
pCap->hw_caps |= ATH9K_HW_CAP_RFSILENT;
}
#endif
- if (AR_SREV_9271(ah))
+ if (AR_SREV_9271(ah) || AR_SREV_9300_20_OR_LATER(ah))
pCap->hw_caps |= ATH9K_HW_CAP_AUTOSLEEP;
else
pCap->hw_caps &= ~ATH9K_HW_CAP_AUTOSLEEP;
@@ -2220,6 +2260,8 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah)
pCap->rx_status_len = sizeof(struct ar9003_rxs);
pCap->tx_desc_len = sizeof(struct ar9003_txc);
pCap->txs_len = sizeof(struct ar9003_txs);
+ if (ah->eep_ops->get_eeprom(ah, EEP_PAPRD))
+ pCap->hw_caps |= ATH9K_HW_CAP_PAPRD;
} else {
pCap->tx_desc_len = sizeof(struct ath_desc);
if (AR_SREV_9280_20(ah) &&
@@ -2232,100 +2274,11 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah)
if (AR_SREV_9300_20_OR_LATER(ah))
pCap->hw_caps |= ATH9K_HW_CAP_RAC_SUPPORTED;
- return 0;
-}
-
-bool ath9k_hw_getcapability(struct ath_hw *ah, enum ath9k_capability_type type,
- u32 capability, u32 *result)
-{
- struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah);
- switch (type) {
- case ATH9K_CAP_CIPHER:
- switch (capability) {
- case ATH9K_CIPHER_AES_CCM:
- case ATH9K_CIPHER_AES_OCB:
- case ATH9K_CIPHER_TKIP:
- case ATH9K_CIPHER_WEP:
- case ATH9K_CIPHER_MIC:
- case ATH9K_CIPHER_CLR:
- return true;
- default:
- return false;
- }
- case ATH9K_CAP_TKIP_MIC:
- switch (capability) {
- case 0:
- return true;
- case 1:
- return (ah->sta_id1_defaults &
- AR_STA_ID1_CRPT_MIC_ENABLE) ? true :
- false;
- }
- case ATH9K_CAP_TKIP_SPLIT:
- return (ah->misc_mode & AR_PCU_MIC_NEW_LOC_ENA) ?
- false : true;
- case ATH9K_CAP_MCAST_KEYSRCH:
- switch (capability) {
- case 0:
- return true;
- case 1:
- if (REG_READ(ah, AR_STA_ID1) & AR_STA_ID1_ADHOC) {
- return false;
- } else {
- return (ah->sta_id1_defaults &
- AR_STA_ID1_MCAST_KSRCH) ? true :
- false;
- }
- }
- return false;
- case ATH9K_CAP_TXPOW:
- switch (capability) {
- case 0:
- return 0;
- case 1:
- *result = regulatory->power_limit;
- return 0;
- case 2:
- *result = regulatory->max_power_level;
- return 0;
- case 3:
- *result = regulatory->tp_scale;
- return 0;
- }
- return false;
- case ATH9K_CAP_DS:
- return (AR_SREV_9280_20_OR_LATER(ah) &&
- (ah->eep_ops->get_eeprom(ah, EEP_RC_CHAIN_MASK) == 1))
- ? false : true;
- default:
- return false;
- }
-}
-EXPORT_SYMBOL(ath9k_hw_getcapability);
+ if (AR_SREV_9287_10_OR_LATER(ah) || AR_SREV_9271(ah))
+ pCap->hw_caps |= ATH9K_HW_CAP_SGI_20;
-bool ath9k_hw_setcapability(struct ath_hw *ah, enum ath9k_capability_type type,
- u32 capability, u32 setting, int *status)
-{
- switch (type) {
- case ATH9K_CAP_TKIP_MIC:
- if (setting)
- ah->sta_id1_defaults |=
- AR_STA_ID1_CRPT_MIC_ENABLE;
- else
- ah->sta_id1_defaults &=
- ~AR_STA_ID1_CRPT_MIC_ENABLE;
- return true;
- case ATH9K_CAP_MCAST_KEYSRCH:
- if (setting)
- ah->sta_id1_defaults |= AR_STA_ID1_MCAST_KSRCH;
- else
- ah->sta_id1_defaults &= ~AR_STA_ID1_MCAST_KSRCH;
- return true;
- default:
- return false;
- }
+ return 0;
}
-EXPORT_SYMBOL(ath9k_hw_setcapability);
/****************************/
/* GPIO / RFKILL / Antennae */
@@ -2365,8 +2318,15 @@ void ath9k_hw_cfg_gpio_input(struct ath_hw *ah, u32 gpio)
BUG_ON(gpio >= ah->caps.num_gpio_pins);
- gpio_shift = gpio << 1;
+ if (AR_DEVID_7010(ah)) {
+ gpio_shift = gpio;
+ REG_RMW(ah, AR7010_GPIO_OE,
+ (AR7010_GPIO_OE_AS_INPUT << gpio_shift),
+ (AR7010_GPIO_OE_MASK << gpio_shift));
+ return;
+ }
+ gpio_shift = gpio << 1;
REG_RMW(ah,
AR_GPIO_OE_OUT,
(AR_GPIO_OE_OUT_DRV_NO << gpio_shift),
@@ -2382,7 +2342,11 @@ u32 ath9k_hw_gpio_get(struct ath_hw *ah, u32 gpio)
if (gpio >= ah->caps.num_gpio_pins)
return 0xffffffff;
- if (AR_SREV_9300_20_OR_LATER(ah))
+ if (AR_DEVID_7010(ah)) {
+ u32 val;
+ val = REG_READ(ah, AR7010_GPIO_IN);
+ return (MS(val, AR7010_GPIO_IN_VAL) & AR_GPIO_BIT(gpio)) == 0;
+ } else if (AR_SREV_9300_20_OR_LATER(ah))
return MS_REG_READ(AR9300, gpio) != 0;
else if (AR_SREV_9271(ah))
return MS_REG_READ(AR9271, gpio) != 0;
@@ -2402,10 +2366,16 @@ void ath9k_hw_cfg_output(struct ath_hw *ah, u32 gpio,
{
u32 gpio_shift;
- ath9k_hw_gpio_cfg_output_mux(ah, gpio, ah_signal_type);
+ if (AR_DEVID_7010(ah)) {
+ gpio_shift = gpio;
+ REG_RMW(ah, AR7010_GPIO_OE,
+ (AR7010_GPIO_OE_AS_OUTPUT << gpio_shift),
+ (AR7010_GPIO_OE_MASK << gpio_shift));
+ return;
+ }
+ ath9k_hw_gpio_cfg_output_mux(ah, gpio, ah_signal_type);
gpio_shift = 2 * gpio;
-
REG_RMW(ah,
AR_GPIO_OE_OUT,
(AR_GPIO_OE_OUT_DRV_ALL << gpio_shift),
@@ -2415,6 +2385,13 @@ EXPORT_SYMBOL(ath9k_hw_cfg_output);
void ath9k_hw_set_gpio(struct ath_hw *ah, u32 gpio, u32 val)
{
+ if (AR_DEVID_7010(ah)) {
+ val = val ? 0 : 1;
+ REG_RMW(ah, AR7010_GPIO_OUT, ((val&1) << gpio),
+ AR_GPIO_BIT(gpio));
+ return;
+ }
+
if (AR_SREV_9271(ah))
val = ~val;
@@ -2520,12 +2497,6 @@ void ath9k_hw_set_txpowerlimit(struct ath_hw *ah, u32 limit)
}
EXPORT_SYMBOL(ath9k_hw_set_txpowerlimit);
-void ath9k_hw_setmac(struct ath_hw *ah, const u8 *mac)
-{
- memcpy(ath9k_hw_common(ah)->macaddr, mac, ETH_ALEN);
-}
-EXPORT_SYMBOL(ath9k_hw_setmac);
-
void ath9k_hw_setopmode(struct ath_hw *ah)
{
ath9k_hw_set_operating_mode(ah, ah->opmode);
@@ -2598,21 +2569,6 @@ void ath9k_hw_set_tsfadjust(struct ath_hw *ah, u32 setting)
}
EXPORT_SYMBOL(ath9k_hw_set_tsfadjust);
-/*
- * Extend 15-bit time stamp from rx descriptor to
- * a full 64-bit TSF using the current h/w TSF.
-*/
-u64 ath9k_hw_extend_tsf(struct ath_hw *ah, u32 rstamp)
-{
- u64 tsf;
-
- tsf = ath9k_hw_gettsf64(ah);
- if ((tsf & 0x7fff) < rstamp)
- tsf -= 0x8000;
- return (tsf & ~0x7fff) | rstamp;
-}
-EXPORT_SYMBOL(ath9k_hw_extend_tsf);
-
void ath9k_hw_set11nmac2040(struct ath_hw *ah)
{
struct ieee80211_conf *conf = &ath9k_hw_common(ah)->hw->conf;
diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h
index 77245dff599..2d30efc0b94 100644
--- a/drivers/net/wireless/ath/ath9k/hw.h
+++ b/drivers/net/wireless/ath/ath9k/hw.h
@@ -158,6 +158,9 @@
#define ATH9K_HW_RX_HP_QDEPTH 16
#define ATH9K_HW_RX_LP_QDEPTH 128
+#define PAPRD_GAIN_TABLE_ENTRIES 32
+#define PAPRD_TABLE_SZ 24
+
enum ath_ini_subsys {
ATH_INI_PRE = 0,
ATH_INI_CORE,
@@ -199,15 +202,8 @@ enum ath9k_hw_caps {
ATH9K_HW_CAP_RAC_SUPPORTED = BIT(18),
ATH9K_HW_CAP_LDPC = BIT(19),
ATH9K_HW_CAP_FASTCLOCK = BIT(20),
-};
-
-enum ath9k_capability_type {
- ATH9K_CAP_CIPHER = 0,
- ATH9K_CAP_TKIP_MIC,
- ATH9K_CAP_TKIP_SPLIT,
- ATH9K_CAP_TXPOW,
- ATH9K_CAP_MCAST_KEYSRCH,
- ATH9K_CAP_DS
+ ATH9K_HW_CAP_SGI_20 = BIT(21),
+ ATH9K_HW_CAP_PAPRD = BIT(22),
};
struct ath9k_hw_capabilities {
@@ -237,8 +233,9 @@ struct ath9k_ops_config {
int sw_beacon_response_time;
int additional_swba_backoff;
int ack_6mb;
- int cwm_ignore_extcca;
+ u32 cwm_ignore_extcca;
u8 pcie_powersave_enable;
+ bool pcieSerDesWrite;
u8 pcie_clock_req;
u32 pcie_waen;
u8 analog_shiftreg;
@@ -262,10 +259,10 @@ struct ath9k_ops_config {
#define AR_BASE_FREQ_5GHZ 4900
#define AR_SPUR_FEEQ_BOUND_HT40 19
#define AR_SPUR_FEEQ_BOUND_HT20 10
- bool tx_iq_calibration; /* Only available for >= AR9003 */
int spurmode;
u16 spurchans[AR_EEPROM_MODAL_SPURS][2];
u8 max_txtrig_level;
+ u16 ani_poll_interval; /* ANI poll interval in ms */
};
enum ath9k_int {
@@ -279,6 +276,7 @@ enum ath9k_int {
ATH9K_INT_TX = 0x00000040,
ATH9K_INT_TXDESC = 0x00000080,
ATH9K_INT_TIM_TIMER = 0x00000100,
+ ATH9K_INT_BB_WATCHDOG = 0x00000400,
ATH9K_INT_TXURN = 0x00000800,
ATH9K_INT_MIB = 0x00001000,
ATH9K_INT_RXPHY = 0x00004000,
@@ -358,6 +356,9 @@ struct ath9k_channel {
int8_t iCoff;
int8_t qCoff;
int16_t rawNoiseFloor;
+ bool paprd_done;
+ u16 small_signal_gain[AR9300_MAX_CHAINS];
+ u32 pa_table[AR9300_MAX_CHAINS][PAPRD_TABLE_SZ];
};
#define IS_CHAN_G(_c) ((((_c)->channelFlags & (CHANNEL_G)) == CHANNEL_G) || \
@@ -459,7 +460,7 @@ struct ath9k_hw_version {
#define AR_GENTMR_BIT(_index) (1 << (_index))
/*
- * Using de Bruijin sequence to to look up 1's index in a 32 bit number
+ * Using de Bruijin sequence to look up 1's index in a 32 bit number
* debruijn32 = 0000 0111 0111 1100 1011 0101 0011 0001
*/
#define debruijn32 0x077CB531U
@@ -509,7 +510,17 @@ struct ath_gen_timer_table {
* AR_RTC_PLL_CONTROL for a given channel
* @setup_calibration: set up calibration
* @iscal_supported: used to query if a type of calibration is supported
- * @loadnf: load noise floor read from each chain on the CCA registers
+ *
+ * @ani_reset: reset ANI parameters to default values
+ * @ani_lower_immunity: lower the noise immunity level. The level controls
+ * the power-based packet detection on hardware. If a power jump is
+ * detected the adapter takes it as an indication that a packet has
+ * arrived. The level ranges from 0-5. Each level corresponds to a
+ * few dB more of noise immunity. If you have a strong time-varying
+ * interference that is causing false detections (OFDM timing errors or
+ * CCK timing errors) the level can be increased.
+ * @ani_cache_ini_regs: cache the values for ANI from the initial
+ * register settings through the register initialization.
*/
struct ath_hw_private_ops {
/* Calibration ops */
@@ -552,7 +563,11 @@ struct ath_hw_private_ops {
bool (*ani_control)(struct ath_hw *ah, enum ath9k_ani_cmd cmd,
int param);
void (*do_getnf)(struct ath_hw *ah, int16_t nfarray[NUM_NF_READINGS]);
- void (*loadnf)(struct ath_hw *ah, struct ath9k_channel *chan);
+
+ /* ANI */
+ void (*ani_reset)(struct ath_hw *ah, bool is_scanning);
+ void (*ani_lower_immunity)(struct ath_hw *ah);
+ void (*ani_cache_ini_regs)(struct ath_hw *ah);
};
/**
@@ -563,6 +578,11 @@ struct ath_hw_private_ops {
*
* @config_pci_powersave:
* @calibrate: periodic calibration for NF, ANI, IQ, ADC gain, ADC-DC
+ *
+ * @ani_proc_mib_event: process MIB events, this would happen upon specific ANI
+ * thresholds being reached or having overflowed.
+ * @ani_monitor: called periodically by the core driver to collect
+ * MIB stats and adjust ANI if specific thresholds have been reached.
*/
struct ath_hw_ops {
void (*config_pci_powersave)(struct ath_hw *ah,
@@ -603,6 +623,15 @@ struct ath_hw_ops {
u32 burstDuration);
void (*set11n_virtualmorefrag)(struct ath_hw *ah, void *ds,
u32 vmf);
+
+ void (*ani_proc_mib_event)(struct ath_hw *ah);
+ void (*ani_monitor)(struct ath_hw *ah, struct ath9k_channel *chan);
+};
+
+struct ath_nf_limits {
+ s16 max;
+ s16 min;
+ s16 nominal;
};
struct ath_hw {
@@ -626,10 +655,10 @@ struct ath_hw {
bool is_pciexpress;
bool need_an_top2_fixup;
u16 tx_trig_level;
- s16 nf_2g_max;
- s16 nf_2g_min;
- s16 nf_5g_max;
- s16 nf_5g_min;
+
+ u32 nf_regs[6];
+ struct ath_nf_limits nf_2g;
+ struct ath_nf_limits nf_5g;
u16 rfsilent;
u32 rfkill_gpio;
u32 rfkill_polarity;
@@ -789,6 +818,18 @@ struct ath_hw {
u32 ts_paddr_end;
u16 ts_tail;
u8 ts_size;
+
+ u32 bb_watchdog_last_status;
+ u32 bb_watchdog_timeout_ms; /* in ms, 0 to disable */
+
+ u32 paprd_gain_table_entries[PAPRD_GAIN_TABLE_ENTRIES];
+ u8 paprd_gain_table_index[PAPRD_GAIN_TABLE_ENTRIES];
+ /*
+ * Store the permanent value of Reg 0x4004in WARegVal
+ * so we dont have to R/M/W. We should not be reading
+ * this register when in sleep states.
+ */
+ u32 WARegVal;
};
static inline struct ath_common *ath9k_hw_common(struct ath_hw *ah)
@@ -811,6 +852,12 @@ static inline struct ath_hw_ops *ath9k_hw_ops(struct ath_hw *ah)
return &ah->ops;
}
+static inline int sign_extend(int val, const int nbits)
+{
+ int order = BIT(nbits-1);
+ return (val ^ order) - order;
+}
+
/* Initialization, Detach, Reset */
const char *ath9k_hw_probe(u16 vendorid, u16 devid);
void ath9k_hw_deinit(struct ath_hw *ah);
@@ -818,19 +865,13 @@ int ath9k_hw_init(struct ath_hw *ah);
int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
bool bChannelChange);
int ath9k_hw_fill_cap_info(struct ath_hw *ah);
-bool ath9k_hw_getcapability(struct ath_hw *ah, enum ath9k_capability_type type,
- u32 capability, u32 *result);
-bool ath9k_hw_setcapability(struct ath_hw *ah, enum ath9k_capability_type type,
- u32 capability, u32 setting, int *status);
u32 ath9k_regd_get_ctl(struct ath_regulatory *reg, struct ath9k_channel *chan);
/* Key Cache Management */
bool ath9k_hw_keyreset(struct ath_hw *ah, u16 entry);
-bool ath9k_hw_keysetmac(struct ath_hw *ah, u16 entry, const u8 *mac);
bool ath9k_hw_set_keycache_entry(struct ath_hw *ah, u16 entry,
const struct ath9k_keyval *k,
const u8 *mac);
-bool ath9k_hw_keyisvalid(struct ath_hw *ah, u16 entry);
/* GPIO / RFKILL / Antennae */
void ath9k_hw_cfg_gpio_input(struct ath_hw *ah, u32 gpio);
@@ -856,7 +897,6 @@ void ath9k_hw_setrxfilter(struct ath_hw *ah, u32 bits);
bool ath9k_hw_phy_disable(struct ath_hw *ah);
bool ath9k_hw_disable(struct ath_hw *ah);
void ath9k_hw_set_txpowerlimit(struct ath_hw *ah, u32 limit);
-void ath9k_hw_setmac(struct ath_hw *ah, const u8 *mac);
void ath9k_hw_setopmode(struct ath_hw *ah);
void ath9k_hw_setmcastfilter(struct ath_hw *ah, u32 filter0, u32 filter1);
void ath9k_hw_setbssidmask(struct ath_hw *ah);
@@ -865,7 +905,6 @@ u64 ath9k_hw_gettsf64(struct ath_hw *ah);
void ath9k_hw_settsf64(struct ath_hw *ah, u64 tsf64);
void ath9k_hw_reset_tsf(struct ath_hw *ah);
void ath9k_hw_set_tsfadjust(struct ath_hw *ah, u32 setting);
-u64 ath9k_hw_extend_tsf(struct ath_hw *ah, u32 rstamp);
void ath9k_hw_init_global_settings(struct ath_hw *ah);
void ath9k_hw_set11nmac2040(struct ath_hw *ah);
void ath9k_hw_beaconinit(struct ath_hw *ah, u32 next_beacon, u32 beacon_period);
@@ -907,13 +946,25 @@ void ath9k_hw_get_delta_slope_vals(struct ath_hw *ah, u32 coef_scaled,
void ar9002_hw_cck_chan14_spread(struct ath_hw *ah);
int ar9002_hw_rf_claim(struct ath_hw *ah);
void ar9002_hw_enable_async_fifo(struct ath_hw *ah);
+void ar9002_hw_update_async_fifo(struct ath_hw *ah);
void ar9002_hw_enable_wep_aggregation(struct ath_hw *ah);
/*
- * Code specifric to AR9003, we stuff these here to avoid callbacks
+ * Code specific to AR9003, we stuff these here to avoid callbacks
* for older families
*/
-void ar9003_hw_set_nf_limits(struct ath_hw *ah);
+void ar9003_hw_bb_watchdog_config(struct ath_hw *ah);
+void ar9003_hw_bb_watchdog_read(struct ath_hw *ah);
+void ar9003_hw_bb_watchdog_dbg_info(struct ath_hw *ah);
+void ar9003_paprd_enable(struct ath_hw *ah, bool val);
+void ar9003_paprd_populate_single_table(struct ath_hw *ah,
+ struct ath9k_channel *chan, int chain);
+int ar9003_paprd_create_curve(struct ath_hw *ah, struct ath9k_channel *chan,
+ int chain);
+int ar9003_paprd_setup_gain_table(struct ath_hw *ah, int chain);
+int ar9003_paprd_init_table(struct ath_hw *ah);
+bool ar9003_paprd_is_done(struct ath_hw *ah);
+void ar9003_hw_set_paprd_txdesc(struct ath_hw *ah, void *ds, u8 chains);
/* Hardware family op attach helpers */
void ar5008_hw_attach_phy_ops(struct ath_hw *ah);
@@ -926,8 +977,24 @@ void ar9003_hw_attach_calib_ops(struct ath_hw *ah);
void ar9002_hw_attach_ops(struct ath_hw *ah);
void ar9003_hw_attach_ops(struct ath_hw *ah);
+/*
+ * ANI work can be shared between all families but a next
+ * generation implementation of ANI will be used only for AR9003 only
+ * for now as the other families still need to be tested with the same
+ * next generation ANI. Feel free to start testing it though for the
+ * older families (AR5008, AR9001, AR9002) by using modparam_force_new_ani.
+ */
+extern int modparam_force_new_ani;
+void ath9k_hw_attach_ani_ops_old(struct ath_hw *ah);
+void ath9k_hw_attach_ani_ops_new(struct ath_hw *ah);
+
#define ATH_PCIE_CAP_LINK_CTRL 0x70
#define ATH_PCIE_CAP_LINK_L0S 1
#define ATH_PCIE_CAP_LINK_L1 2
+#define ATH9K_CLOCK_RATE_CCK 22
+#define ATH9K_CLOCK_RATE_5GHZ_OFDM 40
+#define ATH9K_CLOCK_RATE_2GHZ_OFDM 44
+#define ATH9K_CLOCK_FAST_RATE_5GHZ_OFDM 44
+
#endif
diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c
index d457cb3bd77..243c1775f34 100644
--- a/drivers/net/wireless/ath/ath9k/init.c
+++ b/drivers/net/wireless/ath/ath9k/init.c
@@ -33,6 +33,10 @@ int modparam_nohwcrypt;
module_param_named(nohwcrypt, modparam_nohwcrypt, int, 0444);
MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption");
+int led_blink = 1;
+module_param_named(blink, led_blink, int, 0444);
+MODULE_PARM_DESC(blink, "Enable LED blink on activity");
+
/* We use the hw_value as an index into our private channel structure */
#define CHAN2G(_freq, _idx) { \
@@ -175,18 +179,6 @@ static const struct ath_ops ath9k_common_ops = {
.write = ath9k_iowrite32,
};
-static int count_streams(unsigned int chainmask, int max)
-{
- int streams = 0;
-
- do {
- if (++streams == max)
- break;
- } while ((chainmask = chainmask & (chainmask - 1)));
-
- return streams;
-}
-
/**************************/
/* Initialization */
/**************************/
@@ -208,6 +200,9 @@ static void setup_ht_cap(struct ath_softc *sc,
if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_LDPC)
ht_info->cap |= IEEE80211_HT_CAP_LDPC_CODING;
+ if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_SGI_20)
+ ht_info->cap |= IEEE80211_HT_CAP_SGI_20;
+
ht_info->ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K;
ht_info->ampdu_density = IEEE80211_HT_MPDU_DENSITY_8;
@@ -224,8 +219,8 @@ static void setup_ht_cap(struct ath_softc *sc,
/* set up supported mcs set */
memset(&ht_info->mcs, 0, sizeof(ht_info->mcs));
- tx_streams = count_streams(common->tx_chainmask, max_streams);
- rx_streams = count_streams(common->rx_chainmask, max_streams);
+ tx_streams = ath9k_cmn_count_streams(common->tx_chainmask, max_streams);
+ rx_streams = ath9k_cmn_count_streams(common->rx_chainmask, max_streams);
ath_print(common, ATH_DBG_CONFIG,
"TX streams %d, RX streams: %d\n",
@@ -388,36 +383,14 @@ static void ath9k_init_crypto(struct ath_softc *sc)
for (i = 0; i < common->keymax; i++)
ath9k_hw_keyreset(sc->sc_ah, (u16) i);
- if (ath9k_hw_getcapability(sc->sc_ah, ATH9K_CAP_CIPHER,
- ATH9K_CIPHER_TKIP, NULL)) {
- /*
- * Whether we should enable h/w TKIP MIC.
- * XXX: if we don't support WME TKIP MIC, then we wouldn't
- * report WMM capable, so it's always safe to turn on
- * TKIP MIC in this case.
- */
- ath9k_hw_setcapability(sc->sc_ah, ATH9K_CAP_TKIP_MIC, 0, 1, NULL);
- }
-
/*
* Check whether the separate key cache entries
* are required to handle both tx+rx MIC keys.
* With split mic keys the number of stations is limited
* to 27 otherwise 59.
*/
- if (ath9k_hw_getcapability(sc->sc_ah, ATH9K_CAP_CIPHER,
- ATH9K_CIPHER_TKIP, NULL)
- && ath9k_hw_getcapability(sc->sc_ah, ATH9K_CAP_CIPHER,
- ATH9K_CIPHER_MIC, NULL)
- && ath9k_hw_getcapability(sc->sc_ah, ATH9K_CAP_TKIP_SPLIT,
- 0, NULL))
+ if (!(sc->sc_ah->misc_mode & AR_PCU_MIC_NEW_LOC_ENA))
common->splitmic = 1;
-
- /* turn on mcast key search if possible */
- if (!ath9k_hw_getcapability(sc->sc_ah, ATH9K_CAP_MCAST_KEYSRCH, 0, NULL))
- (void)ath9k_hw_setcapability(sc->sc_ah, ATH9K_CAP_MCAST_KEYSRCH,
- 1, 1, NULL);
-
}
static int ath9k_init_btcoex(struct ath_softc *sc)
@@ -435,7 +408,7 @@ static int ath9k_init_btcoex(struct ath_softc *sc)
r = ath_init_btcoex_timer(sc);
if (r)
return -1;
- qnum = ath_tx_get_qnum(sc, ATH9K_TX_QUEUE_DATA, ATH9K_WME_AC_BE);
+ qnum = sc->tx.hwq_map[WME_AC_BE];
ath9k_hw_init_btcoex_hw(sc->sc_ah, qnum);
sc->btcoex.bt_stomp_type = ATH_BTCOEX_STOMP_LOW;
break;
@@ -472,23 +445,23 @@ static int ath9k_init_queues(struct ath_softc *sc)
sc->config.cabqReadytime = ATH_CABQ_READY_TIME;
ath_cabq_update(sc);
- if (!ath_tx_setup(sc, ATH9K_WME_AC_BK)) {
+ if (!ath_tx_setup(sc, WME_AC_BK)) {
ath_print(common, ATH_DBG_FATAL,
"Unable to setup xmit queue for BK traffic\n");
goto err;
}
- if (!ath_tx_setup(sc, ATH9K_WME_AC_BE)) {
+ if (!ath_tx_setup(sc, WME_AC_BE)) {
ath_print(common, ATH_DBG_FATAL,
"Unable to setup xmit queue for BE traffic\n");
goto err;
}
- if (!ath_tx_setup(sc, ATH9K_WME_AC_VI)) {
+ if (!ath_tx_setup(sc, WME_AC_VI)) {
ath_print(common, ATH_DBG_FATAL,
"Unable to setup xmit queue for VI traffic\n");
goto err;
}
- if (!ath_tx_setup(sc, ATH9K_WME_AC_VO)) {
+ if (!ath_tx_setup(sc, WME_AC_VO)) {
ath_print(common, ATH_DBG_FATAL,
"Unable to setup xmit queue for VO traffic\n");
goto err;
@@ -745,6 +718,8 @@ int ath9k_init_device(u16 devid, struct ath_softc *sc, u16 subsysid,
goto error_world;
}
+ INIT_WORK(&sc->hw_check_work, ath_hw_check);
+ INIT_WORK(&sc->paprd_work, ath_paprd_calibrate);
INIT_WORK(&sc->chan_work, ath9k_wiphy_chan_work);
INIT_DELAYED_WORK(&sc->wiphy_work, ath9k_wiphy_work);
sc->wiphy_scheduler_int = msecs_to_jiffies(500);
@@ -812,12 +787,12 @@ void ath9k_deinit_device(struct ath_softc *sc)
ieee80211_unregister_hw(aphy->hw);
ieee80211_free_hw(aphy->hw);
}
- kfree(sc->sec_wiphy);
ieee80211_unregister_hw(hw);
ath_rx_cleanup(sc);
ath_tx_cleanup(sc);
ath9k_deinit_softc(sc);
+ kfree(sc->sec_wiphy);
}
void ath_descdma_cleanup(struct ath_softc *sc,
diff --git a/drivers/net/wireless/ath/ath9k/mac.c b/drivers/net/wireless/ath/ath9k/mac.c
index 0e425cb4bbb..e955bb9d98c 100644
--- a/drivers/net/wireless/ath/ath9k/mac.c
+++ b/drivers/net/wireless/ath/ath9k/mac.c
@@ -15,6 +15,7 @@
*/
#include "hw.h"
+#include "hw-ops.h"
static void ath9k_hw_set_txq_interrupts(struct ath_hw *ah,
struct ath9k_tx_queue_info *qi)
@@ -554,8 +555,13 @@ bool ath9k_hw_resettxqueue(struct ath_hw *ah, u32 q)
REGWRITE_BUFFER_FLUSH(ah);
DISABLE_REGWRITE_BUFFER(ah);
- /* cwmin and cwmax should be 0 for beacon queue */
- if (AR_SREV_9300_20_OR_LATER(ah)) {
+ /*
+ * cwmin and cwmax should be 0 for beacon queue
+ * but not for IBSS as we would create an imbalance
+ * on beaconing fairness for participating nodes.
+ */
+ if (AR_SREV_9300_20_OR_LATER(ah) &&
+ ah->opmode != NL80211_IFTYPE_ADHOC) {
REG_WRITE(ah, AR_DLCL_IFS(q), SM(0, AR_D_LCL_IFS_CWMIN)
| SM(0, AR_D_LCL_IFS_CWMAX)
| SM(qi->tqi_aifs, AR_D_LCL_IFS_AIFS));
@@ -756,11 +762,11 @@ void ath9k_hw_putrxbuf(struct ath_hw *ah, u32 rxdp)
}
EXPORT_SYMBOL(ath9k_hw_putrxbuf);
-void ath9k_hw_startpcureceive(struct ath_hw *ah)
+void ath9k_hw_startpcureceive(struct ath_hw *ah, bool is_scanning)
{
ath9k_enable_mib_counters(ah);
- ath9k_ani_reset(ah);
+ ath9k_ani_reset(ah, is_scanning);
REG_CLR_BIT(ah, AR_DIAG_SW, (AR_DIAG_RX_DIS | AR_DIAG_RX_ABORT));
}
diff --git a/drivers/net/wireless/ath/ath9k/mac.h b/drivers/net/wireless/ath/ath9k/mac.h
index 00f3e0c7528..2633896d399 100644
--- a/drivers/net/wireless/ath/ath9k/mac.h
+++ b/drivers/net/wireless/ath/ath9k/mac.h
@@ -485,6 +485,9 @@ struct ar5416_desc {
#define AR_TxRSSICombined 0xff000000
#define AR_TxRSSICombined_S 24
+#define AR_TxTid 0xf0000000
+#define AR_TxTid_S 28
+
#define AR_TxEVM0 ds_txstatus5
#define AR_TxEVM1 ds_txstatus6
#define AR_TxEVM2 ds_txstatus7
@@ -577,13 +580,8 @@ enum ath9k_tx_queue {
#define ATH9K_NUM_TX_QUEUES 10
-enum ath9k_tx_queue_subtype {
- ATH9K_WME_AC_BK = 0,
- ATH9K_WME_AC_BE,
- ATH9K_WME_AC_VI,
- ATH9K_WME_AC_VO,
- ATH9K_WME_UPSD
-};
+/* Used as a queue subtype instead of a WMM AC */
+#define ATH9K_WME_UPSD 4
enum ath9k_tx_queue_flags {
TXQ_FLAG_TXOKINT_ENABLE = 0x0001,
@@ -617,7 +615,7 @@ enum ath9k_pkt_type {
struct ath9k_tx_queue_info {
u32 tqi_ver;
enum ath9k_tx_queue tqi_type;
- enum ath9k_tx_queue_subtype tqi_subtype;
+ int tqi_subtype;
enum ath9k_tx_queue_flags tqi_qflags;
u32 tqi_priority;
u32 tqi_aifs;
@@ -715,7 +713,7 @@ void ath9k_hw_setuprxdesc(struct ath_hw *ah, struct ath_desc *ds,
u32 size, u32 flags);
bool ath9k_hw_setrxabort(struct ath_hw *ah, bool set);
void ath9k_hw_putrxbuf(struct ath_hw *ah, u32 rxdp);
-void ath9k_hw_startpcureceive(struct ath_hw *ah);
+void ath9k_hw_startpcureceive(struct ath_hw *ah, bool is_scanning);
void ath9k_hw_stoppcurecv(struct ath_hw *ah);
void ath9k_hw_abortpcurecv(struct ath_hw *ah);
bool ath9k_hw_stopdmarecv(struct ath_hw *ah);
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c
index 1e2a68ea935..0429dda0961 100644
--- a/drivers/net/wireless/ath/ath9k/main.c
+++ b/drivers/net/wireless/ath/ath9k/main.c
@@ -51,13 +51,11 @@ static void ath_cache_conf_rate(struct ath_softc *sc,
static void ath_update_txpow(struct ath_softc *sc)
{
struct ath_hw *ah = sc->sc_ah;
- u32 txpow;
if (sc->curtxpow != sc->config.txpowlimit) {
ath9k_hw_set_txpowerlimit(ah, sc->config.txpowlimit);
/* read back in case value is clamped */
- ath9k_hw_getcapability(ah, ATH9K_CAP_TXPOW, 1, &txpow);
- sc->curtxpow = txpow;
+ sc->curtxpow = ath9k_hw_regulatory(ah)->power_limit;
}
}
@@ -232,6 +230,114 @@ int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw,
return r;
}
+static void ath_paprd_activate(struct ath_softc *sc)
+{
+ struct ath_hw *ah = sc->sc_ah;
+ int chain;
+
+ if (!ah->curchan->paprd_done)
+ return;
+
+ ath9k_ps_wakeup(sc);
+ for (chain = 0; chain < AR9300_MAX_CHAINS; chain++) {
+ if (!(ah->caps.tx_chainmask & BIT(chain)))
+ continue;
+
+ ar9003_paprd_populate_single_table(ah, ah->curchan, chain);
+ }
+
+ ar9003_paprd_enable(ah, true);
+ ath9k_ps_restore(sc);
+}
+
+void ath_paprd_calibrate(struct work_struct *work)
+{
+ struct ath_softc *sc = container_of(work, struct ath_softc, paprd_work);
+ struct ieee80211_hw *hw = sc->hw;
+ struct ath_hw *ah = sc->sc_ah;
+ struct ieee80211_hdr *hdr;
+ struct sk_buff *skb = NULL;
+ struct ieee80211_tx_info *tx_info;
+ int band = hw->conf.channel->band;
+ struct ieee80211_supported_band *sband = &sc->sbands[band];
+ struct ath_tx_control txctl;
+ int qnum, ftype;
+ int chain_ok = 0;
+ int chain;
+ int len = 1800;
+ int time_left;
+ int i;
+
+ skb = alloc_skb(len, GFP_KERNEL);
+ if (!skb)
+ return;
+
+ tx_info = IEEE80211_SKB_CB(skb);
+
+ skb_put(skb, len);
+ memset(skb->data, 0, len);
+ hdr = (struct ieee80211_hdr *)skb->data;
+ ftype = IEEE80211_FTYPE_DATA | IEEE80211_STYPE_NULLFUNC;
+ hdr->frame_control = cpu_to_le16(ftype);
+ hdr->duration_id = cpu_to_le16(10);
+ memcpy(hdr->addr1, hw->wiphy->perm_addr, ETH_ALEN);
+ memcpy(hdr->addr2, hw->wiphy->perm_addr, ETH_ALEN);
+ memcpy(hdr->addr3, hw->wiphy->perm_addr, ETH_ALEN);
+
+ memset(&txctl, 0, sizeof(txctl));
+ qnum = sc->tx.hwq_map[WME_AC_BE];
+ txctl.txq = &sc->tx.txq[qnum];
+
+ ath9k_ps_wakeup(sc);
+ ar9003_paprd_init_table(ah);
+ for (chain = 0; chain < AR9300_MAX_CHAINS; chain++) {
+ if (!(ah->caps.tx_chainmask & BIT(chain)))
+ continue;
+
+ chain_ok = 0;
+ memset(tx_info, 0, sizeof(*tx_info));
+ tx_info->band = band;
+
+ for (i = 0; i < 4; i++) {
+ tx_info->control.rates[i].idx = sband->n_bitrates - 1;
+ tx_info->control.rates[i].count = 6;
+ }
+
+ init_completion(&sc->paprd_complete);
+ ar9003_paprd_setup_gain_table(ah, chain);
+ txctl.paprd = BIT(chain);
+ if (ath_tx_start(hw, skb, &txctl) != 0)
+ break;
+
+ time_left = wait_for_completion_timeout(&sc->paprd_complete,
+ msecs_to_jiffies(ATH_PAPRD_TIMEOUT));
+ if (!time_left) {
+ ath_print(ath9k_hw_common(ah), ATH_DBG_CALIBRATE,
+ "Timeout waiting for paprd training on "
+ "TX chain %d\n",
+ chain);
+ goto fail_paprd;
+ }
+
+ if (!ar9003_paprd_is_done(ah))
+ break;
+
+ if (ar9003_paprd_create_curve(ah, ah->curchan, chain) != 0)
+ break;
+
+ chain_ok = 1;
+ }
+ kfree_skb(skb);
+
+ if (chain_ok) {
+ ah->curchan->paprd_done = true;
+ ath_paprd_activate(sc);
+ }
+
+fail_paprd:
+ ath9k_ps_restore(sc);
+}
+
/*
* This routine performs the periodic noise floor calibration function
* that is used to adjust and optimize the chip performance. This
@@ -285,7 +391,8 @@ void ath_ani_calibrate(unsigned long data)
}
/* Verify whether we must check ANI */
- if ((timestamp - common->ani.checkani_timer) >= ATH_ANI_POLLINTERVAL) {
+ if ((timestamp - common->ani.checkani_timer) >=
+ ah->config.ani_poll_interval) {
aniflag = true;
common->ani.checkani_timer = timestamp;
}
@@ -326,15 +433,24 @@ set_timer:
*/
cal_interval = ATH_LONG_CALINTERVAL;
if (sc->sc_ah->config.enable_ani)
- cal_interval = min(cal_interval, (u32)ATH_ANI_POLLINTERVAL);
+ cal_interval = min(cal_interval,
+ (u32)ah->config.ani_poll_interval);
if (!common->ani.caldone)
cal_interval = min(cal_interval, (u32)short_cal_interval);
mod_timer(&common->ani.timer, jiffies + msecs_to_jiffies(cal_interval));
+ if ((sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_PAPRD) &&
+ !(sc->sc_flags & SC_OP_SCANNING)) {
+ if (!sc->sc_ah->curchan->paprd_done)
+ ieee80211_queue_work(sc->hw, &sc->paprd_work);
+ else
+ ath_paprd_activate(sc);
+ }
}
static void ath_start_ani(struct ath_common *common)
{
+ struct ath_hw *ah = common->ah;
unsigned long timestamp = jiffies_to_msecs(jiffies);
struct ath_softc *sc = (struct ath_softc *) common->priv;
@@ -346,7 +462,8 @@ static void ath_start_ani(struct ath_common *common)
common->ani.checkani_timer = timestamp;
mod_timer(&common->ani.timer,
- jiffies + msecs_to_jiffies(ATH_ANI_POLLINTERVAL));
+ jiffies +
+ msecs_to_jiffies((u32)ah->config.ani_poll_interval));
}
/*
@@ -398,6 +515,25 @@ static void ath_node_detach(struct ath_softc *sc, struct ieee80211_sta *sta)
ath_tx_node_cleanup(sc, an);
}
+void ath_hw_check(struct work_struct *work)
+{
+ struct ath_softc *sc = container_of(work, struct ath_softc, hw_check_work);
+ int i;
+
+ ath9k_ps_wakeup(sc);
+
+ for (i = 0; i < 3; i++) {
+ if (ath9k_hw_check_alive(sc->sc_ah))
+ goto out;
+
+ msleep(1);
+ }
+ ath_reset(sc, false);
+
+out:
+ ath9k_ps_restore(sc);
+}
+
void ath9k_tasklet(unsigned long data)
{
struct ath_softc *sc = (struct ath_softc *)data;
@@ -409,13 +545,15 @@ void ath9k_tasklet(unsigned long data)
ath9k_ps_wakeup(sc);
- if ((status & ATH9K_INT_FATAL) ||
- !ath9k_hw_check_alive(ah)) {
+ if (status & ATH9K_INT_FATAL) {
ath_reset(sc, false);
ath9k_ps_restore(sc);
return;
}
+ if (!ath9k_hw_check_alive(ah))
+ ieee80211_queue_work(sc->hw, &sc->hw_check_work);
+
if (ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)
rxmask = (ATH9K_INT_RXHP | ATH9K_INT_RXLP | ATH9K_INT_RXEOL |
ATH9K_INT_RXORN);
@@ -524,6 +662,12 @@ irqreturn_t ath_isr(int irq, void *dev)
!(ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)))
goto chip_reset;
+ if ((ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) &&
+ (status & ATH9K_INT_BB_WATCHDOG)) {
+ ar9003_hw_bb_watchdog_dbg_info(ah);
+ goto chip_reset;
+ }
+
if (status & ATH9K_INT_SWBA)
tasklet_schedule(&sc->bcon_tasklet);
@@ -619,234 +763,6 @@ static u32 ath_get_extchanmode(struct ath_softc *sc,
return chanmode;
}
-static int ath_setkey_tkip(struct ath_common *common, u16 keyix, const u8 *key,
- struct ath9k_keyval *hk, const u8 *addr,
- bool authenticator)
-{
- struct ath_hw *ah = common->ah;
- const u8 *key_rxmic;
- const u8 *key_txmic;
-
- key_txmic = key + NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY;
- key_rxmic = key + NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY;
-
- if (addr == NULL) {
- /*
- * Group key installation - only two key cache entries are used
- * regardless of splitmic capability since group key is only
- * used either for TX or RX.
- */
- if (authenticator) {
- memcpy(hk->kv_mic, key_txmic, sizeof(hk->kv_mic));
- memcpy(hk->kv_txmic, key_txmic, sizeof(hk->kv_mic));
- } else {
- memcpy(hk->kv_mic, key_rxmic, sizeof(hk->kv_mic));
- memcpy(hk->kv_txmic, key_rxmic, sizeof(hk->kv_mic));
- }
- return ath9k_hw_set_keycache_entry(ah, keyix, hk, addr);
- }
- if (!common->splitmic) {
- /* TX and RX keys share the same key cache entry. */
- memcpy(hk->kv_mic, key_rxmic, sizeof(hk->kv_mic));
- memcpy(hk->kv_txmic, key_txmic, sizeof(hk->kv_txmic));
- return ath9k_hw_set_keycache_entry(ah, keyix, hk, addr);
- }
-
- /* Separate key cache entries for TX and RX */
-
- /* TX key goes at first index, RX key at +32. */
- memcpy(hk->kv_mic, key_txmic, sizeof(hk->kv_mic));
- if (!ath9k_hw_set_keycache_entry(ah, keyix, hk, NULL)) {
- /* TX MIC entry failed. No need to proceed further */
- ath_print(common, ATH_DBG_FATAL,
- "Setting TX MIC Key Failed\n");
- return 0;
- }
-
- memcpy(hk->kv_mic, key_rxmic, sizeof(hk->kv_mic));
- /* XXX delete tx key on failure? */
- return ath9k_hw_set_keycache_entry(ah, keyix + 32, hk, addr);
-}
-
-static int ath_reserve_key_cache_slot_tkip(struct ath_common *common)
-{
- int i;
-
- for (i = IEEE80211_WEP_NKID; i < common->keymax / 2; i++) {
- if (test_bit(i, common->keymap) ||
- test_bit(i + 64, common->keymap))
- continue; /* At least one part of TKIP key allocated */
- if (common->splitmic &&
- (test_bit(i + 32, common->keymap) ||
- test_bit(i + 64 + 32, common->keymap)))
- continue; /* At least one part of TKIP key allocated */
-
- /* Found a free slot for a TKIP key */
- return i;
- }
- return -1;
-}
-
-static int ath_reserve_key_cache_slot(struct ath_common *common)
-{
- int i;
-
- /* First, try to find slots that would not be available for TKIP. */
- if (common->splitmic) {
- for (i = IEEE80211_WEP_NKID; i < common->keymax / 4; i++) {
- if (!test_bit(i, common->keymap) &&
- (test_bit(i + 32, common->keymap) ||
- test_bit(i + 64, common->keymap) ||
- test_bit(i + 64 + 32, common->keymap)))
- return i;
- if (!test_bit(i + 32, common->keymap) &&
- (test_bit(i, common->keymap) ||
- test_bit(i + 64, common->keymap) ||
- test_bit(i + 64 + 32, common->keymap)))
- return i + 32;
- if (!test_bit(i + 64, common->keymap) &&
- (test_bit(i , common->keymap) ||
- test_bit(i + 32, common->keymap) ||
- test_bit(i + 64 + 32, common->keymap)))
- return i + 64;
- if (!test_bit(i + 64 + 32, common->keymap) &&
- (test_bit(i, common->keymap) ||
- test_bit(i + 32, common->keymap) ||
- test_bit(i + 64, common->keymap)))
- return i + 64 + 32;
- }
- } else {
- for (i = IEEE80211_WEP_NKID; i < common->keymax / 2; i++) {
- if (!test_bit(i, common->keymap) &&
- test_bit(i + 64, common->keymap))
- return i;
- if (test_bit(i, common->keymap) &&
- !test_bit(i + 64, common->keymap))
- return i + 64;
- }
- }
-
- /* No partially used TKIP slots, pick any available slot */
- for (i = IEEE80211_WEP_NKID; i < common->keymax; i++) {
- /* Do not allow slots that could be needed for TKIP group keys
- * to be used. This limitation could be removed if we know that
- * TKIP will not be used. */
- if (i >= 64 && i < 64 + IEEE80211_WEP_NKID)
- continue;
- if (common->splitmic) {
- if (i >= 32 && i < 32 + IEEE80211_WEP_NKID)
- continue;
- if (i >= 64 + 32 && i < 64 + 32 + IEEE80211_WEP_NKID)
- continue;
- }
-
- if (!test_bit(i, common->keymap))
- return i; /* Found a free slot for a key */
- }
-
- /* No free slot found */
- return -1;
-}
-
-static int ath_key_config(struct ath_common *common,
- struct ieee80211_vif *vif,
- struct ieee80211_sta *sta,
- struct ieee80211_key_conf *key)
-{
- struct ath_hw *ah = common->ah;
- struct ath9k_keyval hk;
- const u8 *mac = NULL;
- int ret = 0;
- int idx;
-
- memset(&hk, 0, sizeof(hk));
-
- switch (key->alg) {
- case ALG_WEP:
- hk.kv_type = ATH9K_CIPHER_WEP;
- break;
- case ALG_TKIP:
- hk.kv_type = ATH9K_CIPHER_TKIP;
- break;
- case ALG_CCMP:
- hk.kv_type = ATH9K_CIPHER_AES_CCM;
- break;
- default:
- return -EOPNOTSUPP;
- }
-
- hk.kv_len = key->keylen;
- memcpy(hk.kv_val, key->key, key->keylen);
-
- if (!(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) {
- /* For now, use the default keys for broadcast keys. This may
- * need to change with virtual interfaces. */
- idx = key->keyidx;
- } else if (key->keyidx) {
- if (WARN_ON(!sta))
- return -EOPNOTSUPP;
- mac = sta->addr;
-
- if (vif->type != NL80211_IFTYPE_AP) {
- /* Only keyidx 0 should be used with unicast key, but
- * allow this for client mode for now. */
- idx = key->keyidx;
- } else
- return -EIO;
- } else {
- if (WARN_ON(!sta))
- return -EOPNOTSUPP;
- mac = sta->addr;
-
- if (key->alg == ALG_TKIP)
- idx = ath_reserve_key_cache_slot_tkip(common);
- else
- idx = ath_reserve_key_cache_slot(common);
- if (idx < 0)
- return -ENOSPC; /* no free key cache entries */
- }
-
- if (key->alg == ALG_TKIP)
- ret = ath_setkey_tkip(common, idx, key->key, &hk, mac,
- vif->type == NL80211_IFTYPE_AP);
- else
- ret = ath9k_hw_set_keycache_entry(ah, idx, &hk, mac);
-
- if (!ret)
- return -EIO;
-
- set_bit(idx, common->keymap);
- if (key->alg == ALG_TKIP) {
- set_bit(idx + 64, common->keymap);
- if (common->splitmic) {
- set_bit(idx + 32, common->keymap);
- set_bit(idx + 64 + 32, common->keymap);
- }
- }
-
- return idx;
-}
-
-static void ath_key_delete(struct ath_common *common, struct ieee80211_key_conf *key)
-{
- struct ath_hw *ah = common->ah;
-
- ath9k_hw_keyreset(ah, key->hw_key_idx);
- if (key->hw_key_idx < IEEE80211_WEP_NKID)
- return;
-
- clear_bit(key->hw_key_idx, common->keymap);
- if (key->alg != ALG_TKIP)
- return;
-
- clear_bit(key->hw_key_idx + 64, common->keymap);
- if (common->splitmic) {
- ath9k_hw_keyreset(ah, key->hw_key_idx + 32);
- clear_bit(key->hw_key_idx + 32, common->keymap);
- clear_bit(key->hw_key_idx + 64 + 32, common->keymap);
- }
-}
-
static void ath9k_bss_assoc_info(struct ath_softc *sc,
struct ieee80211_vif *vif,
struct ieee80211_bss_conf *bss_conf)
@@ -941,9 +857,14 @@ void ath_radio_disable(struct ath_softc *sc, struct ieee80211_hw *hw)
ath9k_ps_wakeup(sc);
ieee80211_stop_queues(hw);
- /* Disable LED */
- ath9k_hw_set_gpio(ah, ah->led_pin, 1);
- ath9k_hw_cfg_gpio_input(ah, ah->led_pin);
+ /*
+ * Keep the LED on when the radio is disabled
+ * during idle unassociated state.
+ */
+ if (!sc->ps_idle) {
+ ath9k_hw_set_gpio(ah, ah->led_pin, 1);
+ ath9k_hw_cfg_gpio_input(ah, ah->led_pin);
+ }
/* Disable interrupts */
ath9k_hw_set_interrupts(ah, 0);
@@ -1032,25 +953,25 @@ int ath_reset(struct ath_softc *sc, bool retry_tx)
return r;
}
-int ath_get_hal_qnum(u16 queue, struct ath_softc *sc)
+static int ath_get_hal_qnum(u16 queue, struct ath_softc *sc)
{
int qnum;
switch (queue) {
case 0:
- qnum = sc->tx.hwq_map[ATH9K_WME_AC_VO];
+ qnum = sc->tx.hwq_map[WME_AC_VO];
break;
case 1:
- qnum = sc->tx.hwq_map[ATH9K_WME_AC_VI];
+ qnum = sc->tx.hwq_map[WME_AC_VI];
break;
case 2:
- qnum = sc->tx.hwq_map[ATH9K_WME_AC_BE];
+ qnum = sc->tx.hwq_map[WME_AC_BE];
break;
case 3:
- qnum = sc->tx.hwq_map[ATH9K_WME_AC_BK];
+ qnum = sc->tx.hwq_map[WME_AC_BK];
break;
default:
- qnum = sc->tx.hwq_map[ATH9K_WME_AC_BE];
+ qnum = sc->tx.hwq_map[WME_AC_BE];
break;
}
@@ -1062,16 +983,16 @@ int ath_get_mac80211_qnum(u32 queue, struct ath_softc *sc)
int qnum;
switch (queue) {
- case ATH9K_WME_AC_VO:
+ case WME_AC_VO:
qnum = 0;
break;
- case ATH9K_WME_AC_VI:
+ case WME_AC_VI:
qnum = 1;
break;
- case ATH9K_WME_AC_BE:
+ case WME_AC_BE:
qnum = 2;
break;
- case ATH9K_WME_AC_BK:
+ case WME_AC_BK:
qnum = 3;
break;
default:
@@ -1201,7 +1122,9 @@ static int ath9k_start(struct ieee80211_hw *hw)
ATH9K_INT_GLOBAL;
if (ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)
- ah->imask |= ATH9K_INT_RXHP | ATH9K_INT_RXLP;
+ ah->imask |= ATH9K_INT_RXHP |
+ ATH9K_INT_RXLP |
+ ATH9K_INT_BB_WATCHDOG;
else
ah->imask |= ATH9K_INT_RX;
@@ -1251,6 +1174,7 @@ static int ath9k_tx(struct ieee80211_hw *hw,
struct ath_tx_control txctl;
int padpos, padsize;
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+ int qnum;
if (aphy->state != ATH_WIPHY_ACTIVE && aphy->state != ATH_WIPHY_SCAN) {
ath_print(common, ATH_DBG_XMIT,
@@ -1280,7 +1204,8 @@ static int ath9k_tx(struct ieee80211_hw *hw,
* completed and if needed, also for RX of buffered frames.
*/
ath9k_ps_wakeup(sc);
- ath9k_hw_setrxabort(sc->sc_ah, 0);
+ if (!(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_AUTOSLEEP))
+ ath9k_hw_setrxabort(sc->sc_ah, 0);
if (ieee80211_is_pspoll(hdr->frame_control)) {
ath_print(common, ATH_DBG_PS,
"Sending PS-Poll to pick a buffered frame\n");
@@ -1322,11 +1247,8 @@ static int ath9k_tx(struct ieee80211_hw *hw,
memmove(skb->data, skb->data + padsize, padpos);
}
- /* Check if a tx queue is available */
-
- txctl.txq = ath_test_get_txq(sc, skb);
- if (!txctl.txq)
- goto exit;
+ qnum = ath_get_hal_qnum(skb_get_queue_mapping(skb), sc);
+ txctl.txq = &sc->tx.txq[qnum];
ath_print(common, ATH_DBG_XMIT, "transmitting packet, skb: %p\n", skb);
@@ -1347,15 +1269,25 @@ static void ath9k_stop(struct ieee80211_hw *hw)
struct ath_softc *sc = aphy->sc;
struct ath_hw *ah = sc->sc_ah;
struct ath_common *common = ath9k_hw_common(ah);
+ int i;
mutex_lock(&sc->mutex);
aphy->state = ATH_WIPHY_INACTIVE;
- cancel_delayed_work_sync(&sc->ath_led_blink_work);
+ if (led_blink)
+ cancel_delayed_work_sync(&sc->ath_led_blink_work);
+
cancel_delayed_work_sync(&sc->tx_complete_work);
+ cancel_work_sync(&sc->paprd_work);
+ cancel_work_sync(&sc->hw_check_work);
+
+ for (i = 0; i < sc->num_sec_wiphy; i++) {
+ if (sc->sec_wiphy[i])
+ break;
+ }
- if (!sc->num_sec_wiphy) {
+ if (i == sc->num_sec_wiphy) {
cancel_delayed_work_sync(&sc->wiphy_work);
cancel_work_sync(&sc->chan_work);
}
@@ -1547,8 +1479,8 @@ void ath9k_enable_ps(struct ath_softc *sc)
ah->imask |= ATH9K_INT_TIM_TIMER;
ath9k_hw_set_interrupts(ah, ah->imask);
}
+ ath9k_hw_setrxabort(ah, 1);
}
- ath9k_hw_setrxabort(ah, 1);
}
static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
@@ -1785,7 +1717,7 @@ static int ath9k_conf_tx(struct ieee80211_hw *hw, u16 queue,
ath_print(common, ATH_DBG_FATAL, "TXQ Update failed\n");
if (sc->sc_ah->opmode == NL80211_IFTYPE_ADHOC)
- if ((qnum == sc->tx.hwq_map[ATH9K_WME_AC_BE]) && !ret)
+ if ((qnum == sc->tx.hwq_map[WME_AC_BE]) && !ret)
ath_beaconq_config(sc);
mutex_unlock(&sc->mutex);
@@ -1813,7 +1745,7 @@ static int ath9k_set_key(struct ieee80211_hw *hw,
switch (cmd) {
case SET_KEY:
- ret = ath_key_config(common, vif, sta, key);
+ ret = ath9k_cmn_key_config(common, vif, sta, key);
if (ret >= 0) {
key->hw_key_idx = ret;
/* push IV and Michael MIC generation to stack */
@@ -1826,7 +1758,7 @@ static int ath9k_set_key(struct ieee80211_hw *hw,
}
break;
case DISABLE_KEY:
- ath_key_delete(common, key);
+ ath9k_cmn_key_delete(common, key);
break;
default:
ret = -EINVAL;
@@ -1999,6 +1931,8 @@ static int ath9k_ampdu_action(struct ieee80211_hw *hw,
struct ath_softc *sc = aphy->sc;
int ret = 0;
+ local_bh_disable();
+
switch (action) {
case IEEE80211_AMPDU_RX_START:
if (!(sc->sc_flags & SC_OP_RXAGGR))
@@ -2028,6 +1962,8 @@ static int ath9k_ampdu_action(struct ieee80211_hw *hw,
"Unknown AMPDU action\n");
}
+ local_bh_enable();
+
return ret;
}
@@ -2058,11 +1994,12 @@ static void ath9k_sw_scan_start(struct ieee80211_hw *hw)
mutex_lock(&sc->mutex);
if (ath9k_wiphy_scanning(sc)) {
- printk(KERN_DEBUG "ath9k: Two wiphys trying to scan at the "
- "same time\n");
/*
- * Do not allow the concurrent scanning state for now. This
- * could be improved with scanning control moved into ath9k.
+ * There is a race here in mac80211 but fixing it requires
+ * we revisit how we handle the scan complete callback.
+ * After mac80211 fixes we will not have configured hardware
+ * to the home channel nor would we have configured the RX
+ * filter yet.
*/
mutex_unlock(&sc->mutex);
return;
@@ -2072,10 +2009,16 @@ static void ath9k_sw_scan_start(struct ieee80211_hw *hw)
ath9k_wiphy_pause_all_forced(sc, aphy);
sc->sc_flags |= SC_OP_SCANNING;
del_timer_sync(&common->ani.timer);
+ cancel_work_sync(&sc->paprd_work);
+ cancel_work_sync(&sc->hw_check_work);
cancel_delayed_work_sync(&sc->tx_complete_work);
mutex_unlock(&sc->mutex);
}
+/*
+ * XXX: this requires a revisit after the driver
+ * scan_complete gets moved to another place/removed in mac80211.
+ */
static void ath9k_sw_scan_complete(struct ieee80211_hw *hw)
{
struct ath_wiphy *aphy = hw->priv;
diff --git a/drivers/net/wireless/ath/ath9k/pci.c b/drivers/net/wireless/ath/ath9k/pci.c
index 1ec836cf1c0..b5b651413e7 100644
--- a/drivers/net/wireless/ath/ath9k/pci.c
+++ b/drivers/net/wireless/ath/ath9k/pci.c
@@ -28,6 +28,7 @@ static DEFINE_PCI_DEVICE_TABLE(ath_pci_id_table) = {
{ PCI_VDEVICE(ATHEROS, 0x002C) }, /* PCI-E 802.11n bonded out */
{ PCI_VDEVICE(ATHEROS, 0x002D) }, /* PCI */
{ PCI_VDEVICE(ATHEROS, 0x002E) }, /* PCI-E */
+ { PCI_VDEVICE(ATHEROS, 0x0030) }, /* PCI-E AR9300 */
{ 0 }
};
@@ -208,11 +209,8 @@ static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
}
ath9k_hw_name(sc->sc_ah, hw_name, sizeof(hw_name));
- printk(KERN_INFO
- "%s: %s mem=0x%lx, irq=%d\n",
- wiphy_name(hw->wiphy),
- hw_name,
- (unsigned long)mem, pdev->irq);
+ wiphy_info(hw->wiphy, "%s mem=0x%lx, irq=%d\n",
+ hw_name, (unsigned long)mem, pdev->irq);
return 0;
diff --git a/drivers/net/wireless/ath/ath9k/rc.c b/drivers/net/wireless/ath/ath9k/rc.c
index 8519452c95f..e49be733d54 100644
--- a/drivers/net/wireless/ath/ath9k/rc.c
+++ b/drivers/net/wireless/ath/ath9k/rc.c
@@ -20,93 +20,145 @@
#include "ath9k.h"
static const struct ath_rate_table ar5416_11na_ratetable = {
- 42,
+ 68,
8, /* MCS start */
{
- { VALID, VALID, WLAN_RC_PHY_OFDM, 6000, /* 6 Mb */
- 5400, 0, 12, 0, 0, 0, 0, 0 },
- { VALID, VALID, WLAN_RC_PHY_OFDM, 9000, /* 9 Mb */
- 7800, 1, 18, 0, 1, 1, 1, 1 },
- { VALID, VALID, WLAN_RC_PHY_OFDM, 12000, /* 12 Mb */
- 10000, 2, 24, 2, 2, 2, 2, 2 },
- { VALID, VALID, WLAN_RC_PHY_OFDM, 18000, /* 18 Mb */
- 13900, 3, 36, 2, 3, 3, 3, 3 },
- { VALID, VALID, WLAN_RC_PHY_OFDM, 24000, /* 24 Mb */
- 17300, 4, 48, 4, 4, 4, 4, 4 },
- { VALID, VALID, WLAN_RC_PHY_OFDM, 36000, /* 36 Mb */
- 23000, 5, 72, 4, 5, 5, 5, 5 },
- { VALID, VALID, WLAN_RC_PHY_OFDM, 48000, /* 48 Mb */
- 27400, 6, 96, 4, 6, 6, 6, 6 },
- { VALID, VALID, WLAN_RC_PHY_OFDM, 54000, /* 54 Mb */
- 29300, 7, 108, 4, 7, 7, 7, 7 },
- { VALID_2040, VALID_2040, WLAN_RC_PHY_HT_20_SS, 6500, /* 6.5 Mb */
- 6400, 0, 0, 0, 8, 24, 8, 24 },
- { VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 13000, /* 13 Mb */
- 12700, 1, 1, 2, 9, 25, 9, 25 },
- { VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 19500, /* 19.5 Mb */
- 18800, 2, 2, 2, 10, 26, 10, 26 },
- { VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 26000, /* 26 Mb */
- 25000, 3, 3, 4, 11, 27, 11, 27 },
- { VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 39000, /* 39 Mb */
- 36700, 4, 4, 4, 12, 28, 12, 28 },
- { INVALID, VALID_20, WLAN_RC_PHY_HT_20_SS, 52000, /* 52 Mb */
- 48100, 5, 5, 4, 13, 29, 13, 29 },
- { INVALID, VALID_20, WLAN_RC_PHY_HT_20_SS, 58500, /* 58.5 Mb */
- 53500, 6, 6, 4, 14, 30, 14, 30 },
- { INVALID, VALID_20, WLAN_RC_PHY_HT_20_SS, 65000, /* 65 Mb */
- 59000, 7, 7, 4, 15, 31, 15, 32 },
- { INVALID, INVALID, WLAN_RC_PHY_HT_20_DS, 13000, /* 13 Mb */
- 12700, 8, 8, 3, 16, 33, 16, 33 },
- { INVALID, INVALID, WLAN_RC_PHY_HT_20_DS, 26000, /* 26 Mb */
- 24800, 9, 9, 2, 17, 34, 17, 34 },
- { INVALID, INVALID, WLAN_RC_PHY_HT_20_DS, 39000, /* 39 Mb */
- 36600, 10, 10, 2, 18, 35, 18, 35 },
- { VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 52000, /* 52 Mb */
- 48100, 11, 11, 4, 19, 36, 19, 36 },
- { VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 78000, /* 78 Mb */
- 69500, 12, 12, 4, 20, 37, 20, 37 },
- { VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 104000, /* 104 Mb */
- 89500, 13, 13, 4, 21, 38, 21, 38 },
- { VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 117000, /* 117 Mb */
- 98900, 14, 14, 4, 22, 39, 22, 39 },
- { VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 130000, /* 130 Mb */
- 108300, 15, 15, 4, 23, 40, 23, 41 },
- { VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 13500, /* 13.5 Mb */
- 13200, 0, 0, 0, 8, 24, 24, 24 },
- { VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 27500, /* 27.0 Mb */
- 25900, 1, 1, 2, 9, 25, 25, 25 },
- { VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 40500, /* 40.5 Mb */
- 38600, 2, 2, 2, 10, 26, 26, 26 },
- { VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 54000, /* 54 Mb */
- 49800, 3, 3, 4, 11, 27, 27, 27 },
- { VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 81500, /* 81 Mb */
- 72200, 4, 4, 4, 12, 28, 28, 28 },
- { INVALID, VALID_40, WLAN_RC_PHY_HT_40_SS, 108000, /* 108 Mb */
- 92900, 5, 5, 4, 13, 29, 29, 29 },
- { INVALID, VALID_40, WLAN_RC_PHY_HT_40_SS, 121500, /* 121.5 Mb */
- 102700, 6, 6, 4, 14, 30, 30, 30 },
- { INVALID, VALID_40, WLAN_RC_PHY_HT_40_SS, 135000, /* 135 Mb */
- 112000, 7, 7, 4, 15, 31, 32, 32 },
- { INVALID, VALID_40, WLAN_RC_PHY_HT_40_SS_HGI, 150000, /* 150 Mb */
- 122000, 7, 7, 4, 15, 31, 32, 32 },
- { INVALID, INVALID, WLAN_RC_PHY_HT_40_DS, 27000, /* 27 Mb */
- 25800, 8, 8, 0, 16, 33, 33, 33 },
- { INVALID, INVALID, WLAN_RC_PHY_HT_40_DS, 54000, /* 54 Mb */
- 49800, 9, 9, 2, 17, 34, 34, 34 },
- { INVALID, INVALID, WLAN_RC_PHY_HT_40_DS, 81000, /* 81 Mb */
- 71900, 10, 10, 2, 18, 35, 35, 35 },
- { VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 108000, /* 108 Mb */
- 92500, 11, 11, 4, 19, 36, 36, 36 },
- { VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 162000, /* 162 Mb */
- 130300, 12, 12, 4, 20, 37, 37, 37 },
- { VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 216000, /* 216 Mb */
- 162800, 13, 13, 4, 21, 38, 38, 38 },
- { VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 243000, /* 243 Mb */
- 178200, 14, 14, 4, 22, 39, 39, 39 },
- { VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 270000, /* 270 Mb */
- 192100, 15, 15, 4, 23, 40, 41, 41 },
- { VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS_HGI, 300000, /* 300 Mb */
- 207000, 15, 15, 4, 23, 40, 41, 41 },
+ [0] = { RC_L_SDT, WLAN_RC_PHY_OFDM, 6000,
+ 5400, 0, 12, 0, 0, 0, 0 }, /* 6 Mb */
+ [1] = { RC_L_SDT, WLAN_RC_PHY_OFDM, 9000,
+ 7800, 1, 18, 0, 1, 1, 1 }, /* 9 Mb */
+ [2] = { RC_L_SDT, WLAN_RC_PHY_OFDM, 12000,
+ 10000, 2, 24, 2, 2, 2, 2 }, /* 12 Mb */
+ [3] = { RC_L_SDT, WLAN_RC_PHY_OFDM, 18000,
+ 13900, 3, 36, 2, 3, 3, 3 }, /* 18 Mb */
+ [4] = { RC_L_SDT, WLAN_RC_PHY_OFDM, 24000,
+ 17300, 4, 48, 4, 4, 4, 4 }, /* 24 Mb */
+ [5] = { RC_L_SDT, WLAN_RC_PHY_OFDM, 36000,
+ 23000, 5, 72, 4, 5, 5, 5 }, /* 36 Mb */
+ [6] = { RC_L_SDT, WLAN_RC_PHY_OFDM, 48000,
+ 27400, 6, 96, 4, 6, 6, 6 }, /* 48 Mb */
+ [7] = { RC_L_SDT, WLAN_RC_PHY_OFDM, 54000,
+ 29300, 7, 108, 4, 7, 7, 7 }, /* 54 Mb */
+ [8] = { RC_HT_SDT_2040, WLAN_RC_PHY_HT_20_SS, 6500,
+ 6400, 0, 0, 0, 38, 8, 38 }, /* 6.5 Mb */
+ [9] = { RC_HT_SDT_20, WLAN_RC_PHY_HT_20_SS, 13000,
+ 12700, 1, 1, 2, 39, 9, 39 }, /* 13 Mb */
+ [10] = { RC_HT_SDT_20, WLAN_RC_PHY_HT_20_SS, 19500,
+ 18800, 2, 2, 2, 40, 10, 40 }, /* 19.5 Mb */
+ [11] = { RC_HT_SD_20, WLAN_RC_PHY_HT_20_SS, 26000,
+ 25000, 3, 3, 4, 41, 11, 41 }, /* 26 Mb */
+ [12] = { RC_HT_SD_20, WLAN_RC_PHY_HT_20_SS, 39000,
+ 36700, 4, 4, 4, 42, 12, 42 }, /* 39 Mb */
+ [13] = { RC_HT_S_20, WLAN_RC_PHY_HT_20_SS, 52000,
+ 48100, 5, 5, 4, 43, 13, 43 }, /* 52 Mb */
+ [14] = { RC_HT_S_20, WLAN_RC_PHY_HT_20_SS, 58500,
+ 53500, 6, 6, 4, 44, 14, 44 }, /* 58.5 Mb */
+ [15] = { RC_HT_S_20, WLAN_RC_PHY_HT_20_SS, 65000,
+ 59000, 7, 7, 4, 45, 16, 46 }, /* 65 Mb */
+ [16] = { RC_HT_S_20, WLAN_RC_PHY_HT_20_SS_HGI, 72200,
+ 65400, 7, 7, 4, 45, 16, 46 }, /* 75 Mb */
+ [17] = { RC_INVALID, WLAN_RC_PHY_HT_20_DS, 13000,
+ 12700, 8, 8, 0, 47, 17, 47 }, /* 13 Mb */
+ [18] = { RC_HT_T_20, WLAN_RC_PHY_HT_20_DS, 26000,
+ 24800, 9, 9, 2, 48, 18, 48 }, /* 26 Mb */
+ [19] = { RC_HT_T_20, WLAN_RC_PHY_HT_20_DS, 39000,
+ 36600, 10, 10, 2, 49, 19, 49 }, /* 39 Mb */
+ [20] = { RC_HT_DT_20, WLAN_RC_PHY_HT_20_DS, 52000,
+ 48100, 11, 11, 4, 50, 20, 50 }, /* 52 Mb */
+ [21] = { RC_HT_DT_20, WLAN_RC_PHY_HT_20_DS, 78000,
+ 69500, 12, 12, 4, 51, 21, 51 }, /* 78 Mb */
+ [22] = { RC_HT_DT_20, WLAN_RC_PHY_HT_20_DS, 104000,
+ 89500, 13, 13, 4, 52, 22, 52 }, /* 104 Mb */
+ [23] = { RC_HT_DT_20, WLAN_RC_PHY_HT_20_DS, 117000,
+ 98900, 14, 14, 4, 53, 23, 53 }, /* 117 Mb */
+ [24] = { RC_HT_DT_20, WLAN_RC_PHY_HT_20_DS, 130000,
+ 108300, 15, 15, 4, 54, 25, 55 }, /* 130 Mb */
+ [25] = { RC_HT_DT_20, WLAN_RC_PHY_HT_20_DS_HGI, 144400,
+ 120000, 15, 15, 4, 54, 25, 55 }, /* 144.4 Mb */
+ [26] = { RC_INVALID, WLAN_RC_PHY_HT_20_TS, 19500,
+ 17400, 16, 16, 0, 56, 26, 56 }, /* 19.5 Mb */
+ [27] = { RC_INVALID, WLAN_RC_PHY_HT_20_TS, 39000,
+ 35100, 17, 17, 2, 57, 27, 57 }, /* 39 Mb */
+ [28] = { RC_INVALID, WLAN_RC_PHY_HT_20_TS, 58500,
+ 52600, 18, 18, 2, 58, 28, 58 }, /* 58.5 Mb */
+ [29] = { RC_INVALID, WLAN_RC_PHY_HT_20_TS, 78000,
+ 70400, 19, 19, 4, 59, 29, 59 }, /* 78 Mb */
+ [30] = { RC_INVALID, WLAN_RC_PHY_HT_20_TS, 117000,
+ 104900, 20, 20, 4, 60, 31, 61 }, /* 117 Mb */
+ [31] = { RC_INVALID, WLAN_RC_PHY_HT_20_TS_HGI, 130000,
+ 115800, 20, 20, 4, 60, 31, 61 }, /* 130 Mb*/
+ [32] = { RC_HT_T_20, WLAN_RC_PHY_HT_20_TS, 156000,
+ 137200, 21, 21, 4, 62, 33, 63 }, /* 156 Mb */
+ [33] = { RC_HT_T_20, WLAN_RC_PHY_HT_20_TS_HGI, 173300,
+ 151100, 21, 21, 4, 62, 33, 63 }, /* 173.3 Mb */
+ [34] = { RC_HT_T_20, WLAN_RC_PHY_HT_20_TS, 175500,
+ 152800, 22, 22, 4, 64, 35, 65 }, /* 175.5 Mb */
+ [35] = { RC_HT_T_20, WLAN_RC_PHY_HT_20_TS_HGI, 195000,
+ 168400, 22, 22, 4, 64, 35, 65 }, /* 195 Mb*/
+ [36] = { RC_HT_T_20, WLAN_RC_PHY_HT_20_TS, 195000,
+ 168400, 23, 23, 4, 66, 37, 67 }, /* 195 Mb */
+ [37] = { RC_HT_T_20, WLAN_RC_PHY_HT_20_TS_HGI, 216700,
+ 185000, 23, 23, 4, 66, 37, 67 }, /* 216.7 Mb */
+ [38] = { RC_HT_SDT_40, WLAN_RC_PHY_HT_40_SS, 13500,
+ 13200, 0, 0, 0, 38, 38, 38 }, /* 13.5 Mb*/
+ [39] = { RC_HT_SDT_40, WLAN_RC_PHY_HT_40_SS, 27500,
+ 25900, 1, 1, 2, 39, 39, 39 }, /* 27.0 Mb*/
+ [40] = { RC_HT_SDT_40, WLAN_RC_PHY_HT_40_SS, 40500,
+ 38600, 2, 2, 2, 40, 40, 40 }, /* 40.5 Mb*/
+ [41] = { RC_HT_SD_40, WLAN_RC_PHY_HT_40_SS, 54000,
+ 49800, 3, 3, 4, 41, 41, 41 }, /* 54 Mb */
+ [42] = { RC_HT_SD_40, WLAN_RC_PHY_HT_40_SS, 81500,
+ 72200, 4, 4, 4, 42, 42, 42 }, /* 81 Mb */
+ [43] = { RC_HT_S_40, WLAN_RC_PHY_HT_40_SS, 108000,
+ 92900, 5, 5, 4, 43, 43, 43 }, /* 108 Mb */
+ [44] = { RC_HT_S_40, WLAN_RC_PHY_HT_40_SS, 121500,
+ 102700, 6, 6, 4, 44, 44, 44 }, /* 121.5 Mb*/
+ [45] = { RC_HT_S_40, WLAN_RC_PHY_HT_40_SS, 135000,
+ 112000, 7, 7, 4, 45, 46, 46 }, /* 135 Mb */
+ [46] = { RC_HT_S_40, WLAN_RC_PHY_HT_40_SS_HGI, 150000,
+ 122000, 7, 7, 4, 45, 46, 46 }, /* 150 Mb */
+ [47] = { RC_INVALID, WLAN_RC_PHY_HT_40_DS, 27000,
+ 25800, 8, 8, 0, 47, 47, 47 }, /* 27 Mb */
+ [48] = { RC_HT_T_40, WLAN_RC_PHY_HT_40_DS, 54000,
+ 49800, 9, 9, 2, 48, 48, 48 }, /* 54 Mb */
+ [49] = { RC_HT_T_40, WLAN_RC_PHY_HT_40_DS, 81000,
+ 71900, 10, 10, 2, 49, 49, 49 }, /* 81 Mb */
+ [50] = { RC_HT_DT_40, WLAN_RC_PHY_HT_40_DS, 108000,
+ 92500, 11, 11, 4, 50, 50, 50 }, /* 108 Mb */
+ [51] = { RC_HT_DT_40, WLAN_RC_PHY_HT_40_DS, 162000,
+ 130300, 12, 12, 4, 51, 51, 51 }, /* 162 Mb */
+ [52] = { RC_HT_DT_40, WLAN_RC_PHY_HT_40_DS, 216000,
+ 162800, 13, 13, 4, 52, 52, 52 }, /* 216 Mb */
+ [53] = { RC_HT_DT_40, WLAN_RC_PHY_HT_40_DS, 243000,
+ 178200, 14, 14, 4, 53, 53, 53 }, /* 243 Mb */
+ [54] = { RC_HT_DT_40, WLAN_RC_PHY_HT_40_DS, 270000,
+ 192100, 15, 15, 4, 54, 55, 55 }, /* 270 Mb */
+ [55] = { RC_HT_DT_40, WLAN_RC_PHY_HT_40_DS_HGI, 300000,
+ 207000, 15, 15, 4, 54, 55, 55 }, /* 300 Mb */
+ [56] = { RC_INVALID, WLAN_RC_PHY_HT_40_TS, 40500,
+ 36100, 16, 16, 0, 56, 56, 56 }, /* 40.5 Mb */
+ [57] = { RC_INVALID, WLAN_RC_PHY_HT_40_TS, 81000,
+ 72900, 17, 17, 2, 57, 57, 57 }, /* 81 Mb */
+ [58] = { RC_INVALID, WLAN_RC_PHY_HT_40_TS, 121500,
+ 108300, 18, 18, 2, 58, 58, 58 }, /* 121.5 Mb */
+ [59] = { RC_INVALID, WLAN_RC_PHY_HT_40_TS, 162000,
+ 142000, 19, 19, 4, 59, 59, 59 }, /* 162 Mb */
+ [60] = { RC_INVALID, WLAN_RC_PHY_HT_40_TS, 243000,
+ 205100, 20, 20, 4, 60, 61, 61 }, /* 243 Mb */
+ [61] = { RC_INVALID, WLAN_RC_PHY_HT_40_TS_HGI, 270000,
+ 224700, 20, 20, 4, 60, 61, 61 }, /* 270 Mb */
+ [62] = { RC_HT_T_40, WLAN_RC_PHY_HT_40_TS, 324000,
+ 263100, 21, 21, 4, 62, 63, 63 }, /* 324 Mb */
+ [63] = { RC_HT_T_40, WLAN_RC_PHY_HT_40_TS_HGI, 360000,
+ 288000, 21, 21, 4, 62, 63, 63 }, /* 360 Mb */
+ [64] = { RC_HT_T_40, WLAN_RC_PHY_HT_40_TS, 364500,
+ 290700, 22, 22, 4, 64, 65, 65 }, /* 364.5 Mb */
+ [65] = { RC_HT_T_40, WLAN_RC_PHY_HT_40_TS_HGI, 405000,
+ 317200, 22, 22, 4, 64, 65, 65 }, /* 405 Mb */
+ [66] = { RC_HT_T_40, WLAN_RC_PHY_HT_40_TS, 405000,
+ 317200, 23, 23, 4, 66, 67, 67 }, /* 405 Mb */
+ [67] = { RC_HT_T_40, WLAN_RC_PHY_HT_40_TS_HGI, 450000,
+ 346400, 23, 23, 4, 66, 67, 67 }, /* 450 Mb */
},
50, /* probe interval */
WLAN_RC_HT_FLAG, /* Phy rates allowed initially */
@@ -116,101 +168,153 @@ static const struct ath_rate_table ar5416_11na_ratetable = {
* for HT are the 64K max aggregate limit */
static const struct ath_rate_table ar5416_11ng_ratetable = {
- 46,
+ 72,
12, /* MCS start */
{
- { VALID_ALL, VALID_ALL, WLAN_RC_PHY_CCK, 1000, /* 1 Mb */
- 900, 0, 2, 0, 0, 0, 0, 0 },
- { VALID_ALL, VALID_ALL, WLAN_RC_PHY_CCK, 2000, /* 2 Mb */
- 1900, 1, 4, 1, 1, 1, 1, 1 },
- { VALID_ALL, VALID_ALL, WLAN_RC_PHY_CCK, 5500, /* 5.5 Mb */
- 4900, 2, 11, 2, 2, 2, 2, 2 },
- { VALID_ALL, VALID_ALL, WLAN_RC_PHY_CCK, 11000, /* 11 Mb */
- 8100, 3, 22, 3, 3, 3, 3, 3 },
- { INVALID, INVALID, WLAN_RC_PHY_OFDM, 6000, /* 6 Mb */
- 5400, 4, 12, 4, 4, 4, 4, 4 },
- { INVALID, INVALID, WLAN_RC_PHY_OFDM, 9000, /* 9 Mb */
- 7800, 5, 18, 4, 5, 5, 5, 5 },
- { VALID, VALID, WLAN_RC_PHY_OFDM, 12000, /* 12 Mb */
- 10100, 6, 24, 6, 6, 6, 6, 6 },
- { VALID, VALID, WLAN_RC_PHY_OFDM, 18000, /* 18 Mb */
- 14100, 7, 36, 6, 7, 7, 7, 7 },
- { VALID, VALID, WLAN_RC_PHY_OFDM, 24000, /* 24 Mb */
- 17700, 8, 48, 8, 8, 8, 8, 8 },
- { VALID, VALID, WLAN_RC_PHY_OFDM, 36000, /* 36 Mb */
- 23700, 9, 72, 8, 9, 9, 9, 9 },
- { VALID, VALID, WLAN_RC_PHY_OFDM, 48000, /* 48 Mb */
- 27400, 10, 96, 8, 10, 10, 10, 10 },
- { VALID, VALID, WLAN_RC_PHY_OFDM, 54000, /* 54 Mb */
- 30900, 11, 108, 8, 11, 11, 11, 11 },
- { INVALID, INVALID, WLAN_RC_PHY_HT_20_SS, 6500, /* 6.5 Mb */
- 6400, 0, 0, 4, 12, 28, 12, 28 },
- { VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 13000, /* 13 Mb */
- 12700, 1, 1, 6, 13, 29, 13, 29 },
- { VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 19500, /* 19.5 Mb */
- 18800, 2, 2, 6, 14, 30, 14, 30 },
- { VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 26000, /* 26 Mb */
- 25000, 3, 3, 8, 15, 31, 15, 31 },
- { VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 39000, /* 39 Mb */
- 36700, 4, 4, 8, 16, 32, 16, 32 },
- { INVALID, VALID_20, WLAN_RC_PHY_HT_20_SS, 52000, /* 52 Mb */
- 48100, 5, 5, 8, 17, 33, 17, 33 },
- { INVALID, VALID_20, WLAN_RC_PHY_HT_20_SS, 58500, /* 58.5 Mb */
- 53500, 6, 6, 8, 18, 34, 18, 34 },
- { INVALID, VALID_20, WLAN_RC_PHY_HT_20_SS, 65000, /* 65 Mb */
- 59000, 7, 7, 8, 19, 35, 19, 36 },
- { INVALID, INVALID, WLAN_RC_PHY_HT_20_DS, 13000, /* 13 Mb */
- 12700, 8, 8, 4, 20, 37, 20, 37 },
- { INVALID, INVALID, WLAN_RC_PHY_HT_20_DS, 26000, /* 26 Mb */
- 24800, 9, 9, 6, 21, 38, 21, 38 },
- { INVALID, INVALID, WLAN_RC_PHY_HT_20_DS, 39000, /* 39 Mb */
- 36600, 10, 10, 6, 22, 39, 22, 39 },
- { VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 52000, /* 52 Mb */
- 48100, 11, 11, 8, 23, 40, 23, 40 },
- { VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 78000, /* 78 Mb */
- 69500, 12, 12, 8, 24, 41, 24, 41 },
- { VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 104000, /* 104 Mb */
- 89500, 13, 13, 8, 25, 42, 25, 42 },
- { VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 117000, /* 117 Mb */
- 98900, 14, 14, 8, 26, 43, 26, 44 },
- { VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 130000, /* 130 Mb */
- 108300, 15, 15, 8, 27, 44, 27, 45 },
- { VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 13500, /* 13.5 Mb */
- 13200, 0, 0, 8, 12, 28, 28, 28 },
- { VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 27500, /* 27.0 Mb */
- 25900, 1, 1, 8, 13, 29, 29, 29 },
- { VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 40500, /* 40.5 Mb */
- 38600, 2, 2, 8, 14, 30, 30, 30 },
- { VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 54000, /* 54 Mb */
- 49800, 3, 3, 8, 15, 31, 31, 31 },
- { VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 81500, /* 81 Mb */
- 72200, 4, 4, 8, 16, 32, 32, 32 },
- { INVALID, VALID_40, WLAN_RC_PHY_HT_40_SS, 108000, /* 108 Mb */
- 92900, 5, 5, 8, 17, 33, 33, 33 },
- { INVALID, VALID_40, WLAN_RC_PHY_HT_40_SS, 121500, /* 121.5 Mb */
- 102700, 6, 6, 8, 18, 34, 34, 34 },
- { INVALID, VALID_40, WLAN_RC_PHY_HT_40_SS, 135000, /* 135 Mb */
- 112000, 7, 7, 8, 19, 35, 36, 36 },
- { INVALID, VALID_40, WLAN_RC_PHY_HT_40_SS_HGI, 150000, /* 150 Mb */
- 122000, 7, 7, 8, 19, 35, 36, 36 },
- { INVALID, INVALID, WLAN_RC_PHY_HT_40_DS, 27000, /* 27 Mb */
- 25800, 8, 8, 8, 20, 37, 37, 37 },
- { INVALID, INVALID, WLAN_RC_PHY_HT_40_DS, 54000, /* 54 Mb */
- 49800, 9, 9, 8, 21, 38, 38, 38 },
- { INVALID, INVALID, WLAN_RC_PHY_HT_40_DS, 81000, /* 81 Mb */
- 71900, 10, 10, 8, 22, 39, 39, 39 },
- { VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 108000, /* 108 Mb */
- 92500, 11, 11, 8, 23, 40, 40, 40 },
- { VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 162000, /* 162 Mb */
- 130300, 12, 12, 8, 24, 41, 41, 41 },
- { VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 216000, /* 216 Mb */
- 162800, 13, 13, 8, 25, 42, 42, 42 },
- { VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 243000, /* 243 Mb */
- 178200, 14, 14, 8, 26, 43, 43, 43 },
- { VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 270000, /* 270 Mb */
- 192100, 15, 15, 8, 27, 44, 45, 45 },
- { VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS_HGI, 300000, /* 300 Mb */
- 207000, 15, 15, 8, 27, 44, 45, 45 },
+ [0] = { RC_ALL, WLAN_RC_PHY_CCK, 1000,
+ 900, 0, 2, 0, 0, 0, 0 }, /* 1 Mb */
+ [1] = { RC_ALL, WLAN_RC_PHY_CCK, 2000,
+ 1900, 1, 4, 1, 1, 1, 1 }, /* 2 Mb */
+ [2] = { RC_ALL, WLAN_RC_PHY_CCK, 5500,
+ 4900, 2, 11, 2, 2, 2, 2 }, /* 5.5 Mb */
+ [3] = { RC_ALL, WLAN_RC_PHY_CCK, 11000,
+ 8100, 3, 22, 3, 3, 3, 3 }, /* 11 Mb */
+ [4] = { RC_INVALID, WLAN_RC_PHY_OFDM, 6000,
+ 5400, 4, 12, 4, 4, 4, 4 }, /* 6 Mb */
+ [5] = { RC_INVALID, WLAN_RC_PHY_OFDM, 9000,
+ 7800, 5, 18, 4, 5, 5, 5 }, /* 9 Mb */
+ [6] = { RC_L_SDT, WLAN_RC_PHY_OFDM, 12000,
+ 10100, 6, 24, 6, 6, 6, 6 }, /* 12 Mb */
+ [7] = { RC_L_SDT, WLAN_RC_PHY_OFDM, 18000,
+ 14100, 7, 36, 6, 7, 7, 7 }, /* 18 Mb */
+ [8] = { RC_L_SDT, WLAN_RC_PHY_OFDM, 24000,
+ 17700, 8, 48, 8, 8, 8, 8 }, /* 24 Mb */
+ [9] = { RC_L_SDT, WLAN_RC_PHY_OFDM, 36000,
+ 23700, 9, 72, 8, 9, 9, 9 }, /* 36 Mb */
+ [10] = { RC_L_SDT, WLAN_RC_PHY_OFDM, 48000,
+ 27400, 10, 96, 8, 10, 10, 10 }, /* 48 Mb */
+ [11] = { RC_L_SDT, WLAN_RC_PHY_OFDM, 54000,
+ 30900, 11, 108, 8, 11, 11, 11 }, /* 54 Mb */
+ [12] = { RC_INVALID, WLAN_RC_PHY_HT_20_SS, 6500,
+ 6400, 0, 0, 4, 42, 12, 42 }, /* 6.5 Mb */
+ [13] = { RC_HT_SDT_20, WLAN_RC_PHY_HT_20_SS, 13000,
+ 12700, 1, 1, 6, 43, 13, 43 }, /* 13 Mb */
+ [14] = { RC_HT_SDT_20, WLAN_RC_PHY_HT_20_SS, 19500,
+ 18800, 2, 2, 6, 44, 14, 44 }, /* 19.5 Mb*/
+ [15] = { RC_HT_SD_20, WLAN_RC_PHY_HT_20_SS, 26000,
+ 25000, 3, 3, 8, 45, 15, 45 }, /* 26 Mb */
+ [16] = { RC_HT_SD_20, WLAN_RC_PHY_HT_20_SS, 39000,
+ 36700, 4, 4, 8, 46, 16, 46 }, /* 39 Mb */
+ [17] = { RC_HT_S_20, WLAN_RC_PHY_HT_20_SS, 52000,
+ 48100, 5, 5, 8, 47, 17, 47 }, /* 52 Mb */
+ [18] = { RC_HT_S_20, WLAN_RC_PHY_HT_20_SS, 58500,
+ 53500, 6, 6, 8, 48, 18, 48 }, /* 58.5 Mb */
+ [19] = { RC_HT_S_20, WLAN_RC_PHY_HT_20_SS, 65000,
+ 59000, 7, 7, 8, 49, 20, 50 }, /* 65 Mb */
+ [20] = { RC_HT_S_20, WLAN_RC_PHY_HT_20_SS_HGI, 72200,
+ 65400, 7, 7, 8, 49, 20, 50 }, /* 65 Mb*/
+ [21] = { RC_INVALID, WLAN_RC_PHY_HT_20_DS, 13000,
+ 12700, 8, 8, 4, 51, 21, 51 }, /* 13 Mb */
+ [22] = { RC_HT_T_20, WLAN_RC_PHY_HT_20_DS, 26000,
+ 24800, 9, 9, 6, 52, 22, 52 }, /* 26 Mb */
+ [23] = { RC_HT_T_20, WLAN_RC_PHY_HT_20_DS, 39000,
+ 36600, 10, 10, 6, 53, 23, 53 }, /* 39 Mb */
+ [24] = { RC_HT_DT_20, WLAN_RC_PHY_HT_20_DS, 52000,
+ 48100, 11, 11, 8, 54, 24, 54 }, /* 52 Mb */
+ [25] = { RC_HT_DT_20, WLAN_RC_PHY_HT_20_DS, 78000,
+ 69500, 12, 12, 8, 55, 25, 55 }, /* 78 Mb */
+ [26] = { RC_HT_DT_20, WLAN_RC_PHY_HT_20_DS, 104000,
+ 89500, 13, 13, 8, 56, 26, 56 }, /* 104 Mb */
+ [27] = { RC_HT_DT_20, WLAN_RC_PHY_HT_20_DS, 117000,
+ 98900, 14, 14, 8, 57, 27, 57 }, /* 117 Mb */
+ [28] = { RC_HT_DT_20, WLAN_RC_PHY_HT_20_DS, 130000,
+ 108300, 15, 15, 8, 58, 29, 59 }, /* 130 Mb */
+ [29] = { RC_HT_DT_20, WLAN_RC_PHY_HT_20_DS_HGI, 144400,
+ 120000, 15, 15, 8, 58, 29, 59 }, /* 144.4 Mb */
+ [30] = { RC_INVALID, WLAN_RC_PHY_HT_20_TS, 19500,
+ 17400, 16, 16, 4, 60, 30, 60 }, /* 19.5 Mb */
+ [31] = { RC_INVALID, WLAN_RC_PHY_HT_20_TS, 39000,
+ 35100, 17, 17, 6, 61, 31, 61 }, /* 39 Mb */
+ [32] = { RC_INVALID, WLAN_RC_PHY_HT_20_TS, 58500,
+ 52600, 18, 18, 6, 62, 32, 62 }, /* 58.5 Mb */
+ [33] = { RC_INVALID, WLAN_RC_PHY_HT_20_TS, 78000,
+ 70400, 19, 19, 8, 63, 33, 63 }, /* 78 Mb */
+ [34] = { RC_INVALID, WLAN_RC_PHY_HT_20_TS, 117000,
+ 104900, 20, 20, 8, 64, 35, 65 }, /* 117 Mb */
+ [35] = { RC_INVALID, WLAN_RC_PHY_HT_20_TS_HGI, 130000,
+ 115800, 20, 20, 8, 64, 35, 65 }, /* 130 Mb */
+ [36] = { RC_HT_T_20, WLAN_RC_PHY_HT_20_TS, 156000,
+ 137200, 21, 21, 8, 66, 37, 67 }, /* 156 Mb */
+ [37] = { RC_HT_T_20, WLAN_RC_PHY_HT_20_TS_HGI, 173300,
+ 151100, 21, 21, 8, 66, 37, 67 }, /* 173.3 Mb */
+ [38] = { RC_HT_T_20, WLAN_RC_PHY_HT_20_TS, 175500,
+ 152800, 22, 22, 8, 68, 39, 69 }, /* 175.5 Mb */
+ [39] = { RC_HT_T_20, WLAN_RC_PHY_HT_20_TS_HGI, 195000,
+ 168400, 22, 22, 8, 68, 39, 69 }, /* 195 Mb */
+ [40] = { RC_HT_T_20, WLAN_RC_PHY_HT_20_TS, 195000,
+ 168400, 23, 23, 8, 70, 41, 71 }, /* 195 Mb */
+ [41] = { RC_HT_T_20, WLAN_RC_PHY_HT_20_TS_HGI, 216700,
+ 185000, 23, 23, 8, 70, 41, 71 }, /* 216.7 Mb */
+ [42] = { RC_HT_SDT_40, WLAN_RC_PHY_HT_40_SS, 13500,
+ 13200, 0, 0, 8, 42, 42, 42 }, /* 13.5 Mb */
+ [43] = { RC_HT_SDT_40, WLAN_RC_PHY_HT_40_SS, 27500,
+ 25900, 1, 1, 8, 43, 43, 43 }, /* 27.0 Mb */
+ [44] = { RC_HT_SDT_40, WLAN_RC_PHY_HT_40_SS, 40500,
+ 38600, 2, 2, 8, 44, 44, 44 }, /* 40.5 Mb */
+ [45] = { RC_HT_SD_40, WLAN_RC_PHY_HT_40_SS, 54000,
+ 49800, 3, 3, 8, 45, 45, 45 }, /* 54 Mb */
+ [46] = { RC_HT_SD_40, WLAN_RC_PHY_HT_40_SS, 81500,
+ 72200, 4, 4, 8, 46, 46, 46 }, /* 81 Mb */
+ [47] = { RC_HT_S_40 , WLAN_RC_PHY_HT_40_SS, 108000,
+ 92900, 5, 5, 8, 47, 47, 47 }, /* 108 Mb */
+ [48] = { RC_HT_S_40, WLAN_RC_PHY_HT_40_SS, 121500,
+ 102700, 6, 6, 8, 48, 48, 48 }, /* 121.5 Mb */
+ [49] = { RC_HT_S_40, WLAN_RC_PHY_HT_40_SS, 135000,
+ 112000, 7, 7, 8, 49, 50, 50 }, /* 135 Mb */
+ [50] = { RC_HT_S_40, WLAN_RC_PHY_HT_40_SS_HGI, 150000,
+ 122000, 7, 7, 8, 49, 50, 50 }, /* 150 Mb */
+ [51] = { RC_INVALID, WLAN_RC_PHY_HT_40_DS, 27000,
+ 25800, 8, 8, 8, 51, 51, 51 }, /* 27 Mb */
+ [52] = { RC_HT_T_40, WLAN_RC_PHY_HT_40_DS, 54000,
+ 49800, 9, 9, 8, 52, 52, 52 }, /* 54 Mb */
+ [53] = { RC_HT_T_40, WLAN_RC_PHY_HT_40_DS, 81000,
+ 71900, 10, 10, 8, 53, 53, 53 }, /* 81 Mb */
+ [54] = { RC_HT_DT_40, WLAN_RC_PHY_HT_40_DS, 108000,
+ 92500, 11, 11, 8, 54, 54, 54 }, /* 108 Mb */
+ [55] = { RC_HT_DT_40, WLAN_RC_PHY_HT_40_DS, 162000,
+ 130300, 12, 12, 8, 55, 55, 55 }, /* 162 Mb */
+ [56] = { RC_HT_DT_40, WLAN_RC_PHY_HT_40_DS, 216000,
+ 162800, 13, 13, 8, 56, 56, 56 }, /* 216 Mb */
+ [57] = { RC_HT_DT_40, WLAN_RC_PHY_HT_40_DS, 243000,
+ 178200, 14, 14, 8, 57, 57, 57 }, /* 243 Mb */
+ [58] = { RC_HT_DT_40, WLAN_RC_PHY_HT_40_DS, 270000,
+ 192100, 15, 15, 8, 58, 59, 59 }, /* 270 Mb */
+ [59] = { RC_HT_DT_40, WLAN_RC_PHY_HT_40_DS_HGI, 300000,
+ 207000, 15, 15, 8, 58, 59, 59 }, /* 300 Mb */
+ [60] = { RC_INVALID, WLAN_RC_PHY_HT_40_TS, 40500,
+ 36100, 16, 16, 8, 60, 60, 60 }, /* 40.5 Mb */
+ [61] = { RC_INVALID, WLAN_RC_PHY_HT_40_TS, 81000,
+ 72900, 17, 17, 8, 61, 61, 61 }, /* 81 Mb */
+ [62] = { RC_INVALID, WLAN_RC_PHY_HT_40_TS, 121500,
+ 108300, 18, 18, 8, 62, 62, 62 }, /* 121.5 Mb */
+ [63] = { RC_INVALID, WLAN_RC_PHY_HT_40_TS, 162000,
+ 142000, 19, 19, 8, 63, 63, 63 }, /* 162 Mb */
+ [64] = { RC_INVALID, WLAN_RC_PHY_HT_40_TS, 243000,
+ 205100, 20, 20, 8, 64, 65, 65 }, /* 243 Mb */
+ [65] = { RC_INVALID, WLAN_RC_PHY_HT_40_TS_HGI, 270000,
+ 224700, 20, 20, 8, 64, 65, 65 }, /* 170 Mb */
+ [66] = { RC_HT_T_40, WLAN_RC_PHY_HT_40_TS, 324000,
+ 263100, 21, 21, 8, 66, 67, 67 }, /* 324 Mb */
+ [67] = { RC_HT_T_40, WLAN_RC_PHY_HT_40_TS_HGI, 360000,
+ 288000, 21, 21, 8, 66, 67, 67 }, /* 360 Mb */
+ [68] = { RC_HT_T_40, WLAN_RC_PHY_HT_40_TS, 364500,
+ 290700, 22, 22, 8, 68, 69, 69 }, /* 364.5 Mb */
+ [69] = { RC_HT_T_40, WLAN_RC_PHY_HT_40_TS_HGI, 405000,
+ 317200, 22, 22, 8, 68, 69, 69 }, /* 405 Mb */
+ [70] = { RC_HT_T_40, WLAN_RC_PHY_HT_40_TS, 405000,
+ 317200, 23, 23, 8, 70, 71, 71 }, /* 405 Mb */
+ [71] = { RC_HT_T_40, WLAN_RC_PHY_HT_40_TS_HGI, 450000,
+ 346400, 23, 23, 8, 70, 71, 71 }, /* 450 Mb */
},
50, /* probe interval */
WLAN_RC_HT_FLAG, /* Phy rates allowed initially */
@@ -220,22 +324,22 @@ static const struct ath_rate_table ar5416_11a_ratetable = {
8,
0,
{
- { VALID, VALID, WLAN_RC_PHY_OFDM, 6000, /* 6 Mb */
- 5400, 0, 12, 0, 0, 0 },
- { VALID, VALID, WLAN_RC_PHY_OFDM, 9000, /* 9 Mb */
- 7800, 1, 18, 0, 1, 0 },
- { VALID, VALID, WLAN_RC_PHY_OFDM, 12000, /* 12 Mb */
- 10000, 2, 24, 2, 2, 0 },
- { VALID, VALID, WLAN_RC_PHY_OFDM, 18000, /* 18 Mb */
- 13900, 3, 36, 2, 3, 0 },
- { VALID, VALID, WLAN_RC_PHY_OFDM, 24000, /* 24 Mb */
- 17300, 4, 48, 4, 4, 0 },
- { VALID, VALID, WLAN_RC_PHY_OFDM, 36000, /* 36 Mb */
- 23000, 5, 72, 4, 5, 0 },
- { VALID, VALID, WLAN_RC_PHY_OFDM, 48000, /* 48 Mb */
- 27400, 6, 96, 4, 6, 0 },
- { VALID, VALID, WLAN_RC_PHY_OFDM, 54000, /* 54 Mb */
- 29300, 7, 108, 4, 7, 0 },
+ { RC_L_SDT, WLAN_RC_PHY_OFDM, 6000, /* 6 Mb */
+ 5400, 0, 12, 0},
+ { RC_L_SDT, WLAN_RC_PHY_OFDM, 9000, /* 9 Mb */
+ 7800, 1, 18, 0},
+ { RC_L_SDT, WLAN_RC_PHY_OFDM, 12000, /* 12 Mb */
+ 10000, 2, 24, 2},
+ { RC_L_SDT, WLAN_RC_PHY_OFDM, 18000, /* 18 Mb */
+ 13900, 3, 36, 2},
+ { RC_L_SDT, WLAN_RC_PHY_OFDM, 24000, /* 24 Mb */
+ 17300, 4, 48, 4},
+ { RC_L_SDT, WLAN_RC_PHY_OFDM, 36000, /* 36 Mb */
+ 23000, 5, 72, 4},
+ { RC_L_SDT, WLAN_RC_PHY_OFDM, 48000, /* 48 Mb */
+ 27400, 6, 96, 4},
+ { RC_L_SDT, WLAN_RC_PHY_OFDM, 54000, /* 54 Mb */
+ 29300, 7, 108, 4},
},
50, /* probe interval */
0, /* Phy rates allowed initially */
@@ -245,30 +349,30 @@ static const struct ath_rate_table ar5416_11g_ratetable = {
12,
0,
{
- { VALID, VALID, WLAN_RC_PHY_CCK, 1000, /* 1 Mb */
- 900, 0, 2, 0, 0, 0 },
- { VALID, VALID, WLAN_RC_PHY_CCK, 2000, /* 2 Mb */
- 1900, 1, 4, 1, 1, 0 },
- { VALID, VALID, WLAN_RC_PHY_CCK, 5500, /* 5.5 Mb */
- 4900, 2, 11, 2, 2, 0 },
- { VALID, VALID, WLAN_RC_PHY_CCK, 11000, /* 11 Mb */
- 8100, 3, 22, 3, 3, 0 },
- { INVALID, INVALID, WLAN_RC_PHY_OFDM, 6000, /* 6 Mb */
- 5400, 4, 12, 4, 4, 0 },
- { INVALID, INVALID, WLAN_RC_PHY_OFDM, 9000, /* 9 Mb */
- 7800, 5, 18, 4, 5, 0 },
- { VALID, VALID, WLAN_RC_PHY_OFDM, 12000, /* 12 Mb */
- 10000, 6, 24, 6, 6, 0 },
- { VALID, VALID, WLAN_RC_PHY_OFDM, 18000, /* 18 Mb */
- 13900, 7, 36, 6, 7, 0 },
- { VALID, VALID, WLAN_RC_PHY_OFDM, 24000, /* 24 Mb */
- 17300, 8, 48, 8, 8, 0 },
- { VALID, VALID, WLAN_RC_PHY_OFDM, 36000, /* 36 Mb */
- 23000, 9, 72, 8, 9, 0 },
- { VALID, VALID, WLAN_RC_PHY_OFDM, 48000, /* 48 Mb */
- 27400, 10, 96, 8, 10, 0 },
- { VALID, VALID, WLAN_RC_PHY_OFDM, 54000, /* 54 Mb */
- 29300, 11, 108, 8, 11, 0 },
+ { RC_L_SDT, WLAN_RC_PHY_CCK, 1000, /* 1 Mb */
+ 900, 0, 2, 0},
+ { RC_L_SDT, WLAN_RC_PHY_CCK, 2000, /* 2 Mb */
+ 1900, 1, 4, 1},
+ { RC_L_SDT, WLAN_RC_PHY_CCK, 5500, /* 5.5 Mb */
+ 4900, 2, 11, 2},
+ { RC_L_SDT, WLAN_RC_PHY_CCK, 11000, /* 11 Mb */
+ 8100, 3, 22, 3},
+ { RC_INVALID, WLAN_RC_PHY_OFDM, 6000, /* 6 Mb */
+ 5400, 4, 12, 4},
+ { RC_INVALID, WLAN_RC_PHY_OFDM, 9000, /* 9 Mb */
+ 7800, 5, 18, 4},
+ { RC_L_SDT, WLAN_RC_PHY_OFDM, 12000, /* 12 Mb */
+ 10000, 6, 24, 6},
+ { RC_L_SDT, WLAN_RC_PHY_OFDM, 18000, /* 18 Mb */
+ 13900, 7, 36, 6},
+ { RC_L_SDT, WLAN_RC_PHY_OFDM, 24000, /* 24 Mb */
+ 17300, 8, 48, 8},
+ { RC_L_SDT, WLAN_RC_PHY_OFDM, 36000, /* 36 Mb */
+ 23000, 9, 72, 8},
+ { RC_L_SDT, WLAN_RC_PHY_OFDM, 48000, /* 48 Mb */
+ 27400, 10, 96, 8},
+ { RC_L_SDT, WLAN_RC_PHY_OFDM, 54000, /* 54 Mb */
+ 29300, 11, 108, 8},
},
50, /* probe interval */
0, /* Phy rates allowed initially */
@@ -338,7 +442,7 @@ static inline void ath_rc_set_valid_txmask(struct ath_rate_priv *ath_rc_priv,
u8 index, int valid_tx_rate)
{
BUG_ON(index > ath_rc_priv->rate_table_size);
- ath_rc_priv->valid_rate_index[index] = valid_tx_rate ? 1 : 0;
+ ath_rc_priv->valid_rate_index[index] = !!valid_tx_rate;
}
static inline
@@ -370,6 +474,8 @@ static int ath_rc_valid_phyrate(u32 phy, u32 capflag, int ignore_cw)
return 0;
if (WLAN_RC_PHY_DS(phy) && !(capflag & WLAN_RC_DS_FLAG))
return 0;
+ if (WLAN_RC_PHY_TS(phy) && !(capflag & WLAN_RC_TS_FLAG))
+ return 0;
if (WLAN_RC_PHY_SGI(phy) && !(capflag & WLAN_RC_SGI_FLAG))
return 0;
if (!ignore_cw && WLAN_RC_PHY_HT(phy))
@@ -400,13 +506,9 @@ static u8 ath_rc_init_validrates(struct ath_rate_priv *ath_rc_priv,
u32 capflag)
{
u8 i, hi = 0;
- u32 valid;
for (i = 0; i < rate_table->rate_cnt; i++) {
- valid = (!(ath_rc_priv->ht_cap & WLAN_RC_DS_FLAG) ?
- rate_table->info[i].valid_single_stream :
- rate_table->info[i].valid);
- if (valid == 1) {
+ if (rate_table->info[i].rate_flags & RC_LEGACY) {
u32 phy = rate_table->info[i].phy;
u8 valid_rate_count = 0;
@@ -418,7 +520,7 @@ static u8 ath_rc_init_validrates(struct ath_rate_priv *ath_rc_priv,
ath_rc_priv->valid_phy_rateidx[phy][valid_rate_count] = i;
ath_rc_priv->valid_phy_ratecnt[phy] += 1;
ath_rc_set_valid_txmask(ath_rc_priv, i, 1);
- hi = A_MAX(hi, i);
+ hi = i;
}
}
@@ -436,9 +538,7 @@ static u8 ath_rc_setvalid_rates(struct ath_rate_priv *ath_rc_priv,
for (i = 0; i < rateset->rs_nrates; i++) {
for (j = 0; j < rate_table->rate_cnt; j++) {
u32 phy = rate_table->info[j].phy;
- u32 valid = (!(ath_rc_priv->ht_cap & WLAN_RC_DS_FLAG) ?
- rate_table->info[j].valid_single_stream :
- rate_table->info[j].valid);
+ u16 rate_flags = rate_table->info[i].rate_flags;
u8 rate = rateset->rs_rates[i];
u8 dot11rate = rate_table->info[j].dot11rate;
@@ -447,8 +547,9 @@ static u8 ath_rc_setvalid_rates(struct ath_rate_priv *ath_rc_priv,
* (VALID/VALID_20/VALID_40) flags */
if ((rate == dot11rate) &&
- ((valid & WLAN_RC_CAP_MODE(capflag)) ==
- WLAN_RC_CAP_MODE(capflag)) &&
+ (rate_flags & WLAN_RC_CAP_MODE(capflag)) ==
+ WLAN_RC_CAP_MODE(capflag) &&
+ (rate_flags & WLAN_RC_CAP_STREAM(capflag)) &&
!WLAN_RC_PHY_HT(phy)) {
u8 valid_rate_count = 0;
@@ -482,14 +583,13 @@ static u8 ath_rc_setvalid_htrates(struct ath_rate_priv *ath_rc_priv,
for (i = 0; i < rateset->rs_nrates; i++) {
for (j = 0; j < rate_table->rate_cnt; j++) {
u32 phy = rate_table->info[j].phy;
- u32 valid = (!(ath_rc_priv->ht_cap & WLAN_RC_DS_FLAG) ?
- rate_table->info[j].valid_single_stream :
- rate_table->info[j].valid);
+ u16 rate_flags = rate_table->info[j].rate_flags;
u8 rate = rateset->rs_rates[i];
u8 dot11rate = rate_table->info[j].dot11rate;
if ((rate != dot11rate) || !WLAN_RC_PHY_HT(phy) ||
- !WLAN_RC_PHY_HT_VALID(valid, capflag))
+ !(rate_flags & WLAN_RC_CAP_STREAM(capflag)) ||
+ !WLAN_RC_PHY_HT_VALID(rate_flags, capflag))
continue;
if (!ath_rc_valid_phyrate(phy, capflag, 0))
@@ -585,12 +685,15 @@ static u8 ath_rc_get_highest_rix(struct ath_softc *sc,
if (rate > (ath_rc_priv->rate_table_size - 1))
rate = ath_rc_priv->rate_table_size - 1;
- if (rate_table->info[rate].valid &&
- (ath_rc_priv->ht_cap & WLAN_RC_DS_FLAG))
+ if (RC_TS_ONLY(rate_table->info[rate].rate_flags) &&
+ (ath_rc_priv->ht_cap & WLAN_RC_TS_FLAG))
+ return rate;
+
+ if (RC_DS_OR_LATER(rate_table->info[rate].rate_flags) &&
+ (ath_rc_priv->ht_cap & (WLAN_RC_DS_FLAG | WLAN_RC_TS_FLAG)))
return rate;
- if (rate_table->info[rate].valid_single_stream &&
- !(ath_rc_priv->ht_cap & WLAN_RC_DS_FLAG))
+ if (RC_SS_OR_LEGACY(rate_table->info[rate].rate_flags))
return rate;
/* This should not happen */
@@ -1003,12 +1106,19 @@ static void ath_rc_update_ht(struct ath_softc *sc,
static int ath_rc_get_rateindex(const struct ath_rate_table *rate_table,
struct ieee80211_tx_rate *rate)
{
- int rix;
+ int rix = 0, i = 0;
+ int mcs_rix_off[] = { 7, 15, 20, 21, 22, 23 };
if (!(rate->flags & IEEE80211_TX_RC_MCS))
return rate->idx;
- rix = rate->idx + rate_table->mcs_start;
+ while (rate->idx > mcs_rix_off[i] &&
+ i < sizeof(mcs_rix_off)/sizeof(int)) {
+ rix++; i++;
+ }
+
+ rix += rate->idx + rate_table->mcs_start;
+
if ((rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH) &&
(rate->flags & IEEE80211_TX_RC_SHORT_GI))
rix = rate_table->info[rix].ht_index;
@@ -1016,8 +1126,6 @@ static int ath_rc_get_rateindex(const struct ath_rate_table *rate_table,
rix = rate_table->info[rix].sgi_index;
else if (rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH)
rix = rate_table->info[rix].cw40index;
- else
- rix = rate_table->info[rix].base_index;
return rix;
}
@@ -1193,20 +1301,19 @@ static void ath_rc_init(struct ath_softc *sc,
}
static u8 ath_rc_build_ht_caps(struct ath_softc *sc, struct ieee80211_sta *sta,
- bool is_cw40, bool is_sgi40)
+ bool is_cw40, bool is_sgi)
{
u8 caps = 0;
if (sta->ht_cap.ht_supported) {
caps = WLAN_RC_HT_FLAG;
- if (sc->sc_ah->caps.tx_chainmask != 1 &&
- ath9k_hw_getcapability(sc->sc_ah, ATH9K_CAP_DS, 0, NULL)) {
- if (sta->ht_cap.mcs.rx_mask[1])
- caps |= WLAN_RC_DS_FLAG;
- }
+ if (sta->ht_cap.mcs.rx_mask[1] && sta->ht_cap.mcs.rx_mask[2])
+ caps |= WLAN_RC_TS_FLAG | WLAN_RC_DS_FLAG;
+ else if (sta->ht_cap.mcs.rx_mask[1])
+ caps |= WLAN_RC_DS_FLAG;
if (is_cw40)
caps |= WLAN_RC_40_FLAG;
- if (is_sgi40)
+ if (is_sgi)
caps |= WLAN_RC_SGI_FLAG;
}
@@ -1300,7 +1407,7 @@ static void ath_rate_init(void *priv, struct ieee80211_supported_band *sband,
struct ath_softc *sc = priv;
struct ath_rate_priv *ath_rc_priv = priv_sta;
const struct ath_rate_table *rate_table;
- bool is_cw40, is_sgi40;
+ bool is_cw40, is_sgi = false;
int i, j = 0;
for (i = 0; i < sband->n_bitrates; i++) {
@@ -1323,7 +1430,11 @@ static void ath_rate_init(void *priv, struct ieee80211_supported_band *sband,
}
is_cw40 = sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40;
- is_sgi40 = sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40;
+
+ if (is_cw40)
+ is_sgi = sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40;
+ else if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_SGI_20)
+ is_sgi = sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20;
/* Choose rate table first */
@@ -1336,7 +1447,7 @@ static void ath_rate_init(void *priv, struct ieee80211_supported_band *sband,
rate_table = hw_rate_table[sc->cur_rate_mode];
}
- ath_rc_priv->ht_cap = ath_rc_build_ht_caps(sc, sta, is_cw40, is_sgi40);
+ ath_rc_priv->ht_cap = ath_rc_build_ht_caps(sc, sta, is_cw40, is_sgi);
ath_rc_init(sc, priv_sta, sband, sta, rate_table);
}
@@ -1347,10 +1458,10 @@ static void ath_rate_update(void *priv, struct ieee80211_supported_band *sband,
struct ath_softc *sc = priv;
struct ath_rate_priv *ath_rc_priv = priv_sta;
const struct ath_rate_table *rate_table = NULL;
- bool oper_cw40 = false, oper_sgi40;
+ bool oper_cw40 = false, oper_sgi;
bool local_cw40 = (ath_rc_priv->ht_cap & WLAN_RC_40_FLAG) ?
true : false;
- bool local_sgi40 = (ath_rc_priv->ht_cap & WLAN_RC_SGI_FLAG) ?
+ bool local_sgi = (ath_rc_priv->ht_cap & WLAN_RC_SGI_FLAG) ?
true : false;
/* FIXME: Handle AP mode later when we support CWM */
@@ -1363,15 +1474,21 @@ static void ath_rate_update(void *priv, struct ieee80211_supported_band *sband,
oper_chan_type == NL80211_CHAN_HT40PLUS)
oper_cw40 = true;
- oper_sgi40 = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40) ?
- true : false;
+ if (oper_cw40)
+ oper_sgi = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40) ?
+ true : false;
+ else if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_SGI_20)
+ oper_sgi = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20) ?
+ true : false;
+ else
+ oper_sgi = false;
- if ((local_cw40 != oper_cw40) || (local_sgi40 != oper_sgi40)) {
+ if ((local_cw40 != oper_cw40) || (local_sgi != oper_sgi)) {
rate_table = ath_choose_rate_table(sc, sband->band,
sta->ht_cap.ht_supported,
oper_cw40);
ath_rc_priv->ht_cap = ath_rc_build_ht_caps(sc, sta,
- oper_cw40, oper_sgi40);
+ oper_cw40, oper_sgi);
ath_rc_init(sc, priv_sta, sband, sta, rate_table);
ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_CONFIG,
diff --git a/drivers/net/wireless/ath/ath9k/rc.h b/drivers/net/wireless/ath/ath9k/rc.h
index 3d8d40cdc99..dc108265450 100644
--- a/drivers/net/wireless/ath/ath9k/rc.h
+++ b/drivers/net/wireless/ath/ath9k/rc.h
@@ -24,32 +24,63 @@
struct ath_softc;
#define ATH_RATE_MAX 30
-#define RATE_TABLE_SIZE 64
+#define RATE_TABLE_SIZE 72
#define MAX_TX_RATE_PHY 48
-/* VALID_ALL - valid for 20/40/Legacy,
- * VALID - Legacy only,
- * VALID_20 - HT 20 only,
- * VALID_40 - HT 40 only */
-#define INVALID 0x0
-#define VALID 0x1
-#define VALID_20 0x2
-#define VALID_40 0x4
-#define VALID_2040 (VALID_20|VALID_40)
-#define VALID_ALL (VALID_2040|VALID)
+#define RC_INVALID 0x0000
+#define RC_LEGACY 0x0001
+#define RC_SS 0x0002
+#define RC_DS 0x0004
+#define RC_TS 0x0008
+#define RC_HT_20 0x0010
+#define RC_HT_40 0x0020
+
+#define RC_STREAM_MASK 0xe
+#define RC_DS_OR_LATER(f) ((((f) & RC_STREAM_MASK) == RC_DS) || \
+ (((f) & RC_STREAM_MASK) == (RC_DS | RC_TS)))
+#define RC_TS_ONLY(f) (((f) & RC_STREAM_MASK) == RC_TS)
+#define RC_SS_OR_LEGACY(f) ((f) & (RC_SS | RC_LEGACY))
+
+#define RC_HT_2040 (RC_HT_20 | RC_HT_40)
+#define RC_ALL_STREAM (RC_SS | RC_DS | RC_TS)
+#define RC_L_SD (RC_LEGACY | RC_SS | RC_DS)
+#define RC_L_SDT (RC_LEGACY | RC_SS | RC_DS | RC_TS)
+#define RC_HT_S_20 (RC_HT_20 | RC_SS)
+#define RC_HT_D_20 (RC_HT_20 | RC_DS)
+#define RC_HT_T_20 (RC_HT_20 | RC_TS)
+#define RC_HT_S_40 (RC_HT_40 | RC_SS)
+#define RC_HT_D_40 (RC_HT_40 | RC_DS)
+#define RC_HT_T_40 (RC_HT_40 | RC_TS)
+
+#define RC_HT_SD_20 (RC_HT_20 | RC_SS | RC_DS)
+#define RC_HT_DT_20 (RC_HT_20 | RC_DS | RC_TS)
+#define RC_HT_SD_40 (RC_HT_40 | RC_SS | RC_DS)
+#define RC_HT_DT_40 (RC_HT_40 | RC_DS | RC_TS)
+
+#define RC_HT_SD_2040 (RC_HT_2040 | RC_SS | RC_DS)
+#define RC_HT_SDT_2040 (RC_HT_2040 | RC_SS | RC_DS | RC_TS)
+
+#define RC_HT_SDT_20 (RC_HT_20 | RC_SS | RC_DS | RC_TS)
+#define RC_HT_SDT_40 (RC_HT_40 | RC_SS | RC_DS | RC_TS)
+
+#define RC_ALL (RC_LEGACY | RC_HT_2040 | RC_ALL_STREAM)
enum {
WLAN_RC_PHY_OFDM,
WLAN_RC_PHY_CCK,
WLAN_RC_PHY_HT_20_SS,
WLAN_RC_PHY_HT_20_DS,
+ WLAN_RC_PHY_HT_20_TS,
WLAN_RC_PHY_HT_40_SS,
WLAN_RC_PHY_HT_40_DS,
+ WLAN_RC_PHY_HT_40_TS,
WLAN_RC_PHY_HT_20_SS_HGI,
WLAN_RC_PHY_HT_20_DS_HGI,
+ WLAN_RC_PHY_HT_20_TS_HGI,
WLAN_RC_PHY_HT_40_SS_HGI,
WLAN_RC_PHY_HT_40_DS_HGI,
+ WLAN_RC_PHY_HT_40_TS_HGI,
WLAN_RC_PHY_MAX
};
@@ -57,36 +88,50 @@ enum {
|| (_phy == WLAN_RC_PHY_HT_40_DS) \
|| (_phy == WLAN_RC_PHY_HT_20_DS_HGI) \
|| (_phy == WLAN_RC_PHY_HT_40_DS_HGI))
+#define WLAN_RC_PHY_TS(_phy) ((_phy == WLAN_RC_PHY_HT_20_TS) \
+ || (_phy == WLAN_RC_PHY_HT_40_TS) \
+ || (_phy == WLAN_RC_PHY_HT_20_TS_HGI) \
+ || (_phy == WLAN_RC_PHY_HT_40_TS_HGI))
#define WLAN_RC_PHY_20(_phy) ((_phy == WLAN_RC_PHY_HT_20_SS) \
|| (_phy == WLAN_RC_PHY_HT_20_DS) \
+ || (_phy == WLAN_RC_PHY_HT_20_TS) \
|| (_phy == WLAN_RC_PHY_HT_20_SS_HGI) \
- || (_phy == WLAN_RC_PHY_HT_20_DS_HGI))
+ || (_phy == WLAN_RC_PHY_HT_20_DS_HGI) \
+ || (_phy == WLAN_RC_PHY_HT_20_TS_HGI))
#define WLAN_RC_PHY_40(_phy) ((_phy == WLAN_RC_PHY_HT_40_SS) \
|| (_phy == WLAN_RC_PHY_HT_40_DS) \
+ || (_phy == WLAN_RC_PHY_HT_40_TS) \
|| (_phy == WLAN_RC_PHY_HT_40_SS_HGI) \
- || (_phy == WLAN_RC_PHY_HT_40_DS_HGI))
+ || (_phy == WLAN_RC_PHY_HT_40_DS_HGI) \
+ || (_phy == WLAN_RC_PHY_HT_40_TS_HGI))
#define WLAN_RC_PHY_SGI(_phy) ((_phy == WLAN_RC_PHY_HT_20_SS_HGI) \
|| (_phy == WLAN_RC_PHY_HT_20_DS_HGI) \
+ || (_phy == WLAN_RC_PHY_HT_20_TS_HGI) \
|| (_phy == WLAN_RC_PHY_HT_40_SS_HGI) \
- || (_phy == WLAN_RC_PHY_HT_40_DS_HGI))
+ || (_phy == WLAN_RC_PHY_HT_40_DS_HGI) \
+ || (_phy == WLAN_RC_PHY_HT_40_TS_HGI))
#define WLAN_RC_PHY_HT(_phy) (_phy >= WLAN_RC_PHY_HT_20_SS)
#define WLAN_RC_CAP_MODE(capflag) (((capflag & WLAN_RC_HT_FLAG) ? \
- (capflag & WLAN_RC_40_FLAG) ? VALID_40 : VALID_20 : VALID))
+ ((capflag & WLAN_RC_40_FLAG) ? RC_HT_40 : RC_HT_20) : RC_LEGACY))
+
+#define WLAN_RC_CAP_STREAM(capflag) (((capflag & WLAN_RC_TS_FLAG) ? \
+ (RC_TS) : ((capflag & WLAN_RC_DS_FLAG) ? RC_DS : RC_SS)))
/* Return TRUE if flag supports HT20 && client supports HT20 or
* return TRUE if flag supports HT40 && client supports HT40.
* This is used becos some rates overlap between HT20/HT40.
*/
#define WLAN_RC_PHY_HT_VALID(flag, capflag) \
- (((flag & VALID_20) && !(capflag & WLAN_RC_40_FLAG)) || \
- ((flag & VALID_40) && (capflag & WLAN_RC_40_FLAG)))
+ (((flag & RC_HT_20) && !(capflag & WLAN_RC_40_FLAG)) || \
+ ((flag & RC_HT_40) && (capflag & WLAN_RC_40_FLAG)))
#define WLAN_RC_DS_FLAG (0x01)
-#define WLAN_RC_40_FLAG (0x02)
-#define WLAN_RC_SGI_FLAG (0x04)
-#define WLAN_RC_HT_FLAG (0x08)
+#define WLAN_RC_TS_FLAG (0x02)
+#define WLAN_RC_40_FLAG (0x04)
+#define WLAN_RC_SGI_FLAG (0x08)
+#define WLAN_RC_HT_FLAG (0x10)
/**
* struct ath_rate_table - Rate Control table
@@ -110,15 +155,13 @@ struct ath_rate_table {
int rate_cnt;
int mcs_start;
struct {
- u8 valid;
- u8 valid_single_stream;
+ u16 rate_flags;
u8 phy;
u32 ratekbps;
u32 user_ratekbps;
u8 ratecode;
u8 dot11rate;
u8 ctrl_rate;
- u8 base_index;
u8 cw40index;
u8 sgi_index;
u8 ht_index;
diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c
index e3e52913d83..da0cfe90c38 100644
--- a/drivers/net/wireless/ath/ath9k/recv.c
+++ b/drivers/net/wireless/ath/ath9k/recv.c
@@ -116,9 +116,6 @@ static void ath_opmode_init(struct ath_softc *sc)
/* configure operational mode */
ath9k_hw_setopmode(ah);
- /* Handle any link-level address change. */
- ath9k_hw_setmac(ah, common->macaddr);
-
/* calculate and install multicast filter */
mfilt[0] = mfilt[1] = ~0;
ath9k_hw_setmcastfilter(ah, mfilt[0], mfilt[1]);
@@ -295,7 +292,7 @@ static void ath_edma_start_recv(struct ath_softc *sc)
ath_opmode_init(sc);
- ath9k_hw_startpcureceive(sc->sc_ah);
+ ath9k_hw_startpcureceive(sc->sc_ah, (sc->sc_flags & SC_OP_SCANNING));
}
static void ath_edma_stop_recv(struct ath_softc *sc)
@@ -501,7 +498,7 @@ int ath_startrecv(struct ath_softc *sc)
start_recv:
spin_unlock_bh(&sc->rx.rxbuflock);
ath_opmode_init(sc);
- ath9k_hw_startpcureceive(ah);
+ ath9k_hw_startpcureceive(ah, (sc->sc_flags & SC_OP_SCANNING));
return 0;
}
@@ -700,12 +697,16 @@ static bool ath_edma_get_buffers(struct ath_softc *sc,
bf = SKB_CB_ATHBUF(skb);
BUG_ON(!bf);
- dma_sync_single_for_device(sc->dev, bf->bf_buf_addr,
+ dma_sync_single_for_cpu(sc->dev, bf->bf_buf_addr,
common->rx_bufsize, DMA_FROM_DEVICE);
ret = ath9k_hw_process_rxdesc_edma(ah, NULL, skb->data);
- if (ret == -EINPROGRESS)
+ if (ret == -EINPROGRESS) {
+ /*let device gain the buffer again*/
+ dma_sync_single_for_device(sc->dev, bf->bf_buf_addr,
+ common->rx_bufsize, DMA_FROM_DEVICE);
return false;
+ }
__skb_unlink(skb, &rx_edma->rx_fifo);
if (ret == -EINVAL) {
@@ -814,13 +815,263 @@ static struct ath_buf *ath_get_next_rx_buf(struct ath_softc *sc,
* 1. accessing the frame
* 2. requeueing the same buffer to h/w
*/
- dma_sync_single_for_device(sc->dev, bf->bf_buf_addr,
+ dma_sync_single_for_cpu(sc->dev, bf->bf_buf_addr,
common->rx_bufsize,
DMA_FROM_DEVICE);
return bf;
}
+/* Assumes you've already done the endian to CPU conversion */
+static bool ath9k_rx_accept(struct ath_common *common,
+ struct ieee80211_hdr *hdr,
+ struct ieee80211_rx_status *rxs,
+ struct ath_rx_status *rx_stats,
+ bool *decrypt_error)
+{
+ struct ath_hw *ah = common->ah;
+ __le16 fc;
+ u8 rx_status_len = ah->caps.rx_status_len;
+
+ fc = hdr->frame_control;
+
+ if (!rx_stats->rs_datalen)
+ return false;
+ /*
+ * rs_status follows rs_datalen so if rs_datalen is too large
+ * we can take a hint that hardware corrupted it, so ignore
+ * those frames.
+ */
+ if (rx_stats->rs_datalen > (common->rx_bufsize - rx_status_len))
+ return false;
+
+ /*
+ * rs_more indicates chained descriptors which can be used
+ * to link buffers together for a sort of scatter-gather
+ * operation.
+ * reject the frame, we don't support scatter-gather yet and
+ * the frame is probably corrupt anyway
+ */
+ if (rx_stats->rs_more)
+ return false;
+
+ /*
+ * The rx_stats->rs_status will not be set until the end of the
+ * chained descriptors so it can be ignored if rs_more is set. The
+ * rs_more will be false at the last element of the chained
+ * descriptors.
+ */
+ if (rx_stats->rs_status != 0) {
+ if (rx_stats->rs_status & ATH9K_RXERR_CRC)
+ rxs->flag |= RX_FLAG_FAILED_FCS_CRC;
+ if (rx_stats->rs_status & ATH9K_RXERR_PHY)
+ return false;
+
+ if (rx_stats->rs_status & ATH9K_RXERR_DECRYPT) {
+ *decrypt_error = true;
+ } else if (rx_stats->rs_status & ATH9K_RXERR_MIC) {
+ if (ieee80211_is_ctl(fc))
+ /*
+ * Sometimes, we get invalid
+ * MIC failures on valid control frames.
+ * Remove these mic errors.
+ */
+ rx_stats->rs_status &= ~ATH9K_RXERR_MIC;
+ else
+ rxs->flag |= RX_FLAG_MMIC_ERROR;
+ }
+ /*
+ * Reject error frames with the exception of
+ * decryption and MIC failures. For monitor mode,
+ * we also ignore the CRC error.
+ */
+ if (ah->opmode == NL80211_IFTYPE_MONITOR) {
+ if (rx_stats->rs_status &
+ ~(ATH9K_RXERR_DECRYPT | ATH9K_RXERR_MIC |
+ ATH9K_RXERR_CRC))
+ return false;
+ } else {
+ if (rx_stats->rs_status &
+ ~(ATH9K_RXERR_DECRYPT | ATH9K_RXERR_MIC)) {
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+static int ath9k_process_rate(struct ath_common *common,
+ struct ieee80211_hw *hw,
+ struct ath_rx_status *rx_stats,
+ struct ieee80211_rx_status *rxs)
+{
+ struct ieee80211_supported_band *sband;
+ enum ieee80211_band band;
+ unsigned int i = 0;
+
+ band = hw->conf.channel->band;
+ sband = hw->wiphy->bands[band];
+
+ if (rx_stats->rs_rate & 0x80) {
+ /* HT rate */
+ rxs->flag |= RX_FLAG_HT;
+ if (rx_stats->rs_flags & ATH9K_RX_2040)
+ rxs->flag |= RX_FLAG_40MHZ;
+ if (rx_stats->rs_flags & ATH9K_RX_GI)
+ rxs->flag |= RX_FLAG_SHORT_GI;
+ rxs->rate_idx = rx_stats->rs_rate & 0x7f;
+ return 0;
+ }
+
+ for (i = 0; i < sband->n_bitrates; i++) {
+ if (sband->bitrates[i].hw_value == rx_stats->rs_rate) {
+ rxs->rate_idx = i;
+ return 0;
+ }
+ if (sband->bitrates[i].hw_value_short == rx_stats->rs_rate) {
+ rxs->flag |= RX_FLAG_SHORTPRE;
+ rxs->rate_idx = i;
+ return 0;
+ }
+ }
+
+ /*
+ * No valid hardware bitrate found -- we should not get here
+ * because hardware has already validated this frame as OK.
+ */
+ ath_print(common, ATH_DBG_XMIT, "unsupported hw bitrate detected "
+ "0x%02x using 1 Mbit\n", rx_stats->rs_rate);
+
+ return -EINVAL;
+}
+
+static void ath9k_process_rssi(struct ath_common *common,
+ struct ieee80211_hw *hw,
+ struct ieee80211_hdr *hdr,
+ struct ath_rx_status *rx_stats)
+{
+ struct ath_hw *ah = common->ah;
+ struct ieee80211_sta *sta;
+ struct ath_node *an;
+ int last_rssi = ATH_RSSI_DUMMY_MARKER;
+ __le16 fc;
+
+ fc = hdr->frame_control;
+
+ rcu_read_lock();
+ /*
+ * XXX: use ieee80211_find_sta! This requires quite a bit of work
+ * under the current ath9k virtual wiphy implementation as we have
+ * no way of tying a vif to wiphy. Typically vifs are attached to
+ * at least one sdata of a wiphy on mac80211 but with ath9k virtual
+ * wiphy you'd have to iterate over every wiphy and each sdata.
+ */
+ sta = ieee80211_find_sta_by_hw(hw, hdr->addr2);
+ if (sta) {
+ an = (struct ath_node *) sta->drv_priv;
+ if (rx_stats->rs_rssi != ATH9K_RSSI_BAD &&
+ !rx_stats->rs_moreaggr)
+ ATH_RSSI_LPF(an->last_rssi, rx_stats->rs_rssi);
+ last_rssi = an->last_rssi;
+ }
+ rcu_read_unlock();
+
+ if (likely(last_rssi != ATH_RSSI_DUMMY_MARKER))
+ rx_stats->rs_rssi = ATH_EP_RND(last_rssi,
+ ATH_RSSI_EP_MULTIPLIER);
+ if (rx_stats->rs_rssi < 0)
+ rx_stats->rs_rssi = 0;
+
+ /* Update Beacon RSSI, this is used by ANI. */
+ if (ieee80211_is_beacon(fc))
+ ah->stats.avgbrssi = rx_stats->rs_rssi;
+}
+
+/*
+ * For Decrypt or Demic errors, we only mark packet status here and always push
+ * up the frame up to let mac80211 handle the actual error case, be it no
+ * decryption key or real decryption error. This let us keep statistics there.
+ */
+static int ath9k_rx_skb_preprocess(struct ath_common *common,
+ struct ieee80211_hw *hw,
+ struct ieee80211_hdr *hdr,
+ struct ath_rx_status *rx_stats,
+ struct ieee80211_rx_status *rx_status,
+ bool *decrypt_error)
+{
+ memset(rx_status, 0, sizeof(struct ieee80211_rx_status));
+
+ /*
+ * everything but the rate is checked here, the rate check is done
+ * separately to avoid doing two lookups for a rate for each frame.
+ */
+ if (!ath9k_rx_accept(common, hdr, rx_status, rx_stats, decrypt_error))
+ return -EINVAL;
+
+ ath9k_process_rssi(common, hw, hdr, rx_stats);
+
+ if (ath9k_process_rate(common, hw, rx_stats, rx_status))
+ return -EINVAL;
+
+ rx_status->band = hw->conf.channel->band;
+ rx_status->freq = hw->conf.channel->center_freq;
+ rx_status->signal = ATH_DEFAULT_NOISE_FLOOR + rx_stats->rs_rssi;
+ rx_status->antenna = rx_stats->rs_antenna;
+ rx_status->flag |= RX_FLAG_TSFT;
+
+ return 0;
+}
+
+static void ath9k_rx_skb_postprocess(struct ath_common *common,
+ struct sk_buff *skb,
+ struct ath_rx_status *rx_stats,
+ struct ieee80211_rx_status *rxs,
+ bool decrypt_error)
+{
+ struct ath_hw *ah = common->ah;
+ struct ieee80211_hdr *hdr;
+ int hdrlen, padpos, padsize;
+ u8 keyix;
+ __le16 fc;
+
+ /* see if any padding is done by the hw and remove it */
+ hdr = (struct ieee80211_hdr *) skb->data;
+ hdrlen = ieee80211_get_hdrlen_from_skb(skb);
+ fc = hdr->frame_control;
+ padpos = ath9k_cmn_padpos(hdr->frame_control);
+
+ /* The MAC header is padded to have 32-bit boundary if the
+ * packet payload is non-zero. The general calculation for
+ * padsize would take into account odd header lengths:
+ * padsize = (4 - padpos % 4) % 4; However, since only
+ * even-length headers are used, padding can only be 0 or 2
+ * bytes and we can optimize this a bit. In addition, we must
+ * not try to remove padding from short control frames that do
+ * not have payload. */
+ padsize = padpos & 3;
+ if (padsize && skb->len>=padpos+padsize+FCS_LEN) {
+ memmove(skb->data + padsize, skb->data, padpos);
+ skb_pull(skb, padsize);
+ }
+
+ keyix = rx_stats->rs_keyix;
+
+ if (!(keyix == ATH9K_RXKEYIX_INVALID) && !decrypt_error &&
+ ieee80211_has_protected(fc)) {
+ rxs->flag |= RX_FLAG_DECRYPTED;
+ } else if (ieee80211_has_protected(fc)
+ && !decrypt_error && skb->len >= hdrlen + 4) {
+ keyix = skb->data[hdrlen + 3] >> 6;
+
+ if (test_bit(keyix, common->keymap))
+ rxs->flag |= RX_FLAG_DECRYPTED;
+ }
+ if (ah->sw_mgmt_crypto &&
+ (rxs->flag & RX_FLAG_DECRYPTED) &&
+ ieee80211_is_mgmt(fc))
+ /* Use software decrypt for management frames. */
+ rxs->flag &= ~RX_FLAG_DECRYPTED;
+}
int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)
{
@@ -842,6 +1093,9 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)
enum ath9k_rx_qtype qtype;
bool edma = !!(ah->caps.hw_caps & ATH9K_HW_CAP_EDMA);
int dma_type;
+ u8 rx_status_len = ah->caps.rx_status_len;
+ u64 tsf = 0;
+ u32 tsf_lower = 0;
if (edma)
dma_type = DMA_BIDIRECTIONAL;
@@ -851,6 +1105,9 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)
qtype = hp ? ATH9K_RX_QUEUE_HP : ATH9K_RX_QUEUE_LP;
spin_lock_bh(&sc->rx.rxbuflock);
+ tsf = ath9k_hw_gettsf64(ah);
+ tsf_lower = tsf & 0xffffffff;
+
do {
/* If handling rx interrupt and flush is in progress => exit */
if ((sc->sc_flags & SC_OP_RXFLUSH) && (flush == 0))
@@ -869,7 +1126,7 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)
if (!skb)
continue;
- hdr = (struct ieee80211_hdr *) skb->data;
+ hdr = (struct ieee80211_hdr *) (skb->data + rx_status_len);
rxs = IEEE80211_SKB_RXCB(skb);
hw = ath_get_virt_hw(sc, hdr);
@@ -883,8 +1140,17 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)
if (flush)
goto requeue;
- retval = ath9k_cmn_rx_skb_preprocess(common, hw, skb, &rs,
- rxs, &decrypt_error);
+ rxs->mactime = (tsf & ~0xffffffffULL) | rs.rs_tstamp;
+ if (rs.rs_tstamp > tsf_lower &&
+ unlikely(rs.rs_tstamp - tsf_lower > 0x10000000))
+ rxs->mactime -= 0x100000000ULL;
+
+ if (rs.rs_tstamp < tsf_lower &&
+ unlikely(tsf_lower - rs.rs_tstamp > 0x10000000))
+ rxs->mactime += 0x100000000ULL;
+
+ retval = ath9k_rx_skb_preprocess(common, hw, hdr, &rs,
+ rxs, &decrypt_error);
if (retval)
goto requeue;
@@ -908,8 +1174,8 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)
if (ah->caps.rx_status_len)
skb_pull(skb, ah->caps.rx_status_len);
- ath9k_cmn_rx_skb_postprocess(common, skb, &rs,
- rxs, decrypt_error);
+ ath9k_rx_skb_postprocess(common, skb, &rs,
+ rxs, decrypt_error);
/* We will now give hardware our shiny new allocated skb */
bf->bf_mpdu = requeue_skb;
diff --git a/drivers/net/wireless/ath/ath9k/reg.h b/drivers/net/wireless/ath/ath9k/reg.h
index d4371a43bda..633e3d949ec 100644
--- a/drivers/net/wireless/ath/ath9k/reg.h
+++ b/drivers/net/wireless/ath/ath9k/reg.h
@@ -222,6 +222,7 @@
#define AR_ISR_S2 0x008c
#define AR_ISR_S2_QCU_TXURN 0x000003FF
+#define AR_ISR_S2_BB_WATCHDOG 0x00010000
#define AR_ISR_S2_CST 0x00400000
#define AR_ISR_S2_GTT 0x00800000
#define AR_ISR_S2_TIM 0x01000000
@@ -699,7 +700,15 @@
#define AR_RC_HOSTIF 0x00000100
#define AR_WA 0x4004
+#define AR_WA_BIT6 (1 << 6)
+#define AR_WA_BIT7 (1 << 7)
+#define AR_WA_BIT23 (1 << 23)
#define AR_WA_D3_L1_DISABLE (1 << 14)
+#define AR_WA_D3_TO_L1_DISABLE_REAL (1 << 16)
+#define AR_WA_ASPM_TIMER_BASED_DISABLE (1 << 17)
+#define AR_WA_RESET_EN (1 << 18) /* Sw Control to enable PCI-Reset to POR (bit 15) */
+#define AR_WA_ANALOG_SHIFT (1 << 20)
+#define AR_WA_POR_SHORT (1 << 21) /* PCI-E Phy reset control */
#define AR9285_WA_DEFAULT 0x004a050b
#define AR9280_WA_DEFAULT 0x0040073b
#define AR_WA_DEFAULT 0x0000073f
@@ -756,32 +765,33 @@
#define AR_SREV_REVISION2 0x00000F00
#define AR_SREV_REVISION2_S 8
-#define AR_SREV_VERSION_5416_PCI 0xD
-#define AR_SREV_VERSION_5416_PCIE 0xC
-#define AR_SREV_REVISION_5416_10 0
-#define AR_SREV_REVISION_5416_20 1
-#define AR_SREV_REVISION_5416_22 2
-#define AR_SREV_VERSION_9100 0x14
-#define AR_SREV_VERSION_9160 0x40
-#define AR_SREV_REVISION_9160_10 0
-#define AR_SREV_REVISION_9160_11 1
-#define AR_SREV_VERSION_9280 0x80
-#define AR_SREV_REVISION_9280_10 0
-#define AR_SREV_REVISION_9280_20 1
-#define AR_SREV_REVISION_9280_21 2
-#define AR_SREV_VERSION_9285 0xC0
-#define AR_SREV_REVISION_9285_10 0
-#define AR_SREV_REVISION_9285_11 1
-#define AR_SREV_REVISION_9285_12 2
-#define AR_SREV_VERSION_9287 0x180
-#define AR_SREV_REVISION_9287_10 0
-#define AR_SREV_REVISION_9287_11 1
-#define AR_SREV_REVISION_9287_12 2
-#define AR_SREV_VERSION_9271 0x140
-#define AR_SREV_REVISION_9271_10 0
-#define AR_SREV_REVISION_9271_11 1
-#define AR_SREV_VERSION_9300 0x1c0
-#define AR_SREV_REVISION_9300_20 2 /* 2.0 and 2.1 */
+#define AR_SREV_VERSION_5416_PCI 0xD
+#define AR_SREV_VERSION_5416_PCIE 0xC
+#define AR_SREV_REVISION_5416_10 0
+#define AR_SREV_REVISION_5416_20 1
+#define AR_SREV_REVISION_5416_22 2
+#define AR_SREV_VERSION_9100 0x14
+#define AR_SREV_VERSION_9160 0x40
+#define AR_SREV_REVISION_9160_10 0
+#define AR_SREV_REVISION_9160_11 1
+#define AR_SREV_VERSION_9280 0x80
+#define AR_SREV_REVISION_9280_10 0
+#define AR_SREV_REVISION_9280_20 1
+#define AR_SREV_REVISION_9280_21 2
+#define AR_SREV_VERSION_9285 0xC0
+#define AR_SREV_REVISION_9285_10 0
+#define AR_SREV_REVISION_9285_11 1
+#define AR_SREV_REVISION_9285_12 2
+#define AR_SREV_VERSION_9287 0x180
+#define AR_SREV_REVISION_9287_10 0
+#define AR_SREV_REVISION_9287_11 1
+#define AR_SREV_REVISION_9287_12 2
+#define AR_SREV_REVISION_9287_13 3
+#define AR_SREV_VERSION_9271 0x140
+#define AR_SREV_REVISION_9271_10 0
+#define AR_SREV_REVISION_9271_11 1
+#define AR_SREV_VERSION_9300 0x1c0
+#define AR_SREV_REVISION_9300_20 2 /* 2.0 and 2.1 */
#define AR_SREV_5416(_ah) \
(((_ah)->hw_version.macVersion == AR_SREV_VERSION_5416_PCI) || \
@@ -859,6 +869,11 @@
(((_ah)->hw_version.macVersion > AR_SREV_VERSION_9287) || \
(((_ah)->hw_version.macVersion == AR_SREV_VERSION_9287) && \
((_ah)->hw_version.macRev >= AR_SREV_REVISION_9287_12)))
+#define AR_SREV_9287_13_OR_LATER(_ah) \
+ (((_ah)->hw_version.macVersion > AR_SREV_VERSION_9287) || \
+ (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9287) && \
+ ((_ah)->hw_version.macRev >= AR_SREV_REVISION_9287_13)))
+
#define AR_SREV_9271(_ah) \
(((_ah))->hw_version.macVersion == AR_SREV_VERSION_9271)
#define AR_SREV_9271_10(_ah) \
@@ -867,6 +882,7 @@
#define AR_SREV_9271_11(_ah) \
(AR_SREV_9271(_ah) && \
((_ah)->hw_version.macRev == AR_SREV_REVISION_9271_11))
+
#define AR_SREV_9300(_ah) \
(((_ah)->hw_version.macVersion == AR_SREV_VERSION_9300))
#define AR_SREV_9300_20(_ah) \
@@ -881,6 +897,10 @@
(AR_SREV_9285_12_OR_LATER(_ah) && \
((REG_READ(_ah, AR_AN_SYNTH9) & 0x7) == 0x1))
+#define AR_DEVID_7010(_ah) \
+ (((_ah)->hw_version.devid == 0x7010) || \
+ ((_ah)->hw_version.devid == 0x9018))
+
#define AR_RADIO_SREV_MAJOR 0xf0
#define AR_RAD5133_SREV_MAJOR 0xc0
#define AR_RAD2133_SREV_MAJOR 0xd0
@@ -978,6 +998,7 @@ enum {
#define AR9287_NUM_GPIO 11
#define AR9271_NUM_GPIO 16
#define AR9300_NUM_GPIO 17
+#define AR7010_NUM_GPIO 16
#define AR_GPIO_IN_OUT 0x4048
#define AR_GPIO_IN_VAL 0x0FFFC000
@@ -992,6 +1013,8 @@ enum {
#define AR9271_GPIO_IN_VAL_S 16
#define AR9300_GPIO_IN_VAL 0x0001FFFF
#define AR9300_GPIO_IN_VAL_S 0
+#define AR7010_GPIO_IN_VAL 0x0000FFFF
+#define AR7010_GPIO_IN_VAL_S 0
#define AR_GPIO_OE_OUT (AR_SREV_9300_20_OR_LATER(ah) ? 0x4050 : 0x404c)
#define AR_GPIO_OE_OUT_DRV 0x3
@@ -1000,6 +1023,21 @@ enum {
#define AR_GPIO_OE_OUT_DRV_HI 0x2
#define AR_GPIO_OE_OUT_DRV_ALL 0x3
+#define AR7010_GPIO_OE 0x52000
+#define AR7010_GPIO_OE_MASK 0x1
+#define AR7010_GPIO_OE_AS_OUTPUT 0x0
+#define AR7010_GPIO_OE_AS_INPUT 0x1
+#define AR7010_GPIO_IN 0x52004
+#define AR7010_GPIO_OUT 0x52008
+#define AR7010_GPIO_SET 0x5200C
+#define AR7010_GPIO_CLEAR 0x52010
+#define AR7010_GPIO_INT 0x52014
+#define AR7010_GPIO_INT_TYPE 0x52018
+#define AR7010_GPIO_INT_POLARITY 0x5201C
+#define AR7010_GPIO_PENDING 0x52020
+#define AR7010_GPIO_INT_MASK 0x52024
+#define AR7010_GPIO_FUNCTION 0x52028
+
#define AR_GPIO_INTR_POL (AR_SREV_9300_20_OR_LATER(ah) ? 0x4058 : 0x4050)
#define AR_GPIO_INTR_POL_VAL 0x0001FFFF
#define AR_GPIO_INTR_POL_VAL_S 0
diff --git a/drivers/net/wireless/ath/ath9k/virtual.c b/drivers/net/wireless/ath/ath9k/virtual.c
index 105ad40968f..fd20241f57d 100644
--- a/drivers/net/wireless/ath/ath9k/virtual.c
+++ b/drivers/net/wireless/ath/ath9k/virtual.c
@@ -219,7 +219,7 @@ static int ath9k_send_nullfunc(struct ath_wiphy *aphy,
info->control.rates[1].idx = -1;
memset(&txctl, 0, sizeof(struct ath_tx_control));
- txctl.txq = &sc->tx.txq[sc->tx.hwq_map[ATH9K_WME_AC_VO]];
+ txctl.txq = &sc->tx.txq[sc->tx.hwq_map[WME_AC_VO]];
txctl.frame_type = ps ? ATH9K_IFT_PAUSE : ATH9K_IFT_UNPAUSE;
if (ath_tx_start(aphy->hw, skb, &txctl) != 0)
@@ -695,16 +695,18 @@ void ath9k_set_wiphy_idle(struct ath_wiphy *aphy, bool idle)
idle ? "idle" : "not-idle");
}
/* Only bother starting a queue on an active virtual wiphy */
-void ath_mac80211_start_queue(struct ath_softc *sc, u16 skb_queue)
+bool ath_mac80211_start_queue(struct ath_softc *sc, u16 skb_queue)
{
struct ieee80211_hw *hw = sc->pri_wiphy->hw;
unsigned int i;
+ bool txq_started = false;
spin_lock_bh(&sc->wiphy_lock);
/* Start the primary wiphy */
if (sc->pri_wiphy->state == ATH_WIPHY_ACTIVE) {
ieee80211_wake_queue(hw, skb_queue);
+ txq_started = true;
goto unlock;
}
@@ -718,11 +720,13 @@ void ath_mac80211_start_queue(struct ath_softc *sc, u16 skb_queue)
hw = aphy->hw;
ieee80211_wake_queue(hw, skb_queue);
+ txq_started = true;
break;
}
unlock:
spin_unlock_bh(&sc->wiphy_lock);
+ return txq_started;
}
/* Go ahead and propagate information to all virtual wiphys, it won't hurt */
diff --git a/drivers/net/wireless/ath/ath9k/wmi.c b/drivers/net/wireless/ath/ath9k/wmi.c
index e23172c9caa..6260faa658a 100644
--- a/drivers/net/wireless/ath/ath9k/wmi.c
+++ b/drivers/net/wireless/ath/ath9k/wmi.c
@@ -279,9 +279,6 @@ int ath9k_wmi_cmd(struct wmi *wmi, enum wmi_cmd_id cmd_id,
if (wmi->drv_priv->op_flags & OP_UNPLUGGED)
return 0;
- if (!wmi)
- return -EINVAL;
-
skb = alloc_skb(headroom + cmd_len, GFP_ATOMIC);
if (!skb)
return -ENOMEM;
diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c
index 859aa4ab076..501b72821b4 100644
--- a/drivers/net/wireless/ath/ath9k/xmit.c
+++ b/drivers/net/wireless/ath/ath9k/xmit.c
@@ -328,6 +328,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
u32 ba[WME_BA_BMP_SIZE >> 5];
int isaggr, txfail, txpending, sendbar = 0, needreset = 0, nbad = 0;
bool rc_update = true;
+ struct ieee80211_tx_rate rates[4];
skb = bf->bf_mpdu;
hdr = (struct ieee80211_hdr *)skb->data;
@@ -335,18 +336,44 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
tx_info = IEEE80211_SKB_CB(skb);
hw = bf->aphy->hw;
+ memcpy(rates, tx_info->control.rates, sizeof(rates));
+
rcu_read_lock();
/* XXX: use ieee80211_find_sta! */
sta = ieee80211_find_sta_by_hw(hw, hdr->addr1);
if (!sta) {
rcu_read_unlock();
+
+ INIT_LIST_HEAD(&bf_head);
+ while (bf) {
+ bf_next = bf->bf_next;
+
+ bf->bf_state.bf_type |= BUF_XRETRY;
+ if ((sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) ||
+ !bf->bf_stale || bf_next != NULL)
+ list_move_tail(&bf->list, &bf_head);
+
+ ath_tx_rc_status(bf, ts, 0, 0, false);
+ ath_tx_complete_buf(sc, bf, txq, &bf_head, ts,
+ 0, 0);
+
+ bf = bf_next;
+ }
return;
}
an = (struct ath_node *)sta->drv_priv;
tid = ATH_AN_2_TID(an, bf->bf_tidno);
+ /*
+ * The hardware occasionally sends a tx status for the wrong TID.
+ * In this case, the BA status cannot be considered valid and all
+ * subframes need to be retransmitted
+ */
+ if (bf->bf_tidno != ts->tid)
+ txok = false;
+
isaggr = bf_isaggr(bf);
memset(ba, 0, WME_BA_BMP_SIZE >> 3);
@@ -375,6 +402,9 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
txfail = txpending = 0;
bf_next = bf->bf_next;
+ skb = bf->bf_mpdu;
+ tx_info = IEEE80211_SKB_CB(skb);
+
if (ATH_BA_ISSET(ba, ATH_BA_INDEX(seq_st, bf->bf_seqno))) {
/* transmit completion, subframe is
* acked by block ack */
@@ -428,6 +458,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
spin_unlock_bh(&txq->axq_lock);
if (rc_update && (acked_cnt == 1 || txfail_cnt == 1)) {
+ memcpy(tx_info->control.rates, rates, sizeof(rates));
ath_tx_rc_status(bf, ts, nbad, txok, true);
rc_update = false;
} else {
@@ -487,6 +518,14 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
bf = bf_next;
}
+ /* prepend un-acked frames to the beginning of the pending frame queue */
+ if (!list_empty(&bf_pending)) {
+ spin_lock_bh(&txq->axq_lock);
+ list_splice(&bf_pending, &tid->buf_q);
+ ath_tx_queue_tid(txq, tid);
+ spin_unlock_bh(&txq->axq_lock);
+ }
+
if (tid->state & AGGR_CLEANUP) {
if (tid->baw_head == tid->baw_tail) {
tid->state &= ~AGGR_ADDBA_COMPLETE;
@@ -499,14 +538,6 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
return;
}
- /* prepend un-acked frames to the beginning of the pending frame queue */
- if (!list_empty(&bf_pending)) {
- spin_lock_bh(&txq->axq_lock);
- list_splice(&bf_pending, &tid->buf_q);
- ath_tx_queue_tid(txq, tid);
- spin_unlock_bh(&txq->axq_lock);
- }
-
rcu_read_unlock();
if (needreset)
@@ -941,6 +972,7 @@ struct ath_txq *ath_txq_setup(struct ath_softc *sc, int qtype, int subtype)
if (!ATH_TXQ_SETUP(sc, qnum)) {
struct ath_txq *txq = &sc->tx.txq[qnum];
+ txq->axq_class = subtype;
txq->axq_qnum = qnum;
txq->axq_link = NULL;
INIT_LIST_HEAD(&txq->axq_q);
@@ -958,58 +990,6 @@ struct ath_txq *ath_txq_setup(struct ath_softc *sc, int qtype, int subtype)
return &sc->tx.txq[qnum];
}
-int ath_tx_get_qnum(struct ath_softc *sc, int qtype, int haltype)
-{
- int qnum;
-
- switch (qtype) {
- case ATH9K_TX_QUEUE_DATA:
- if (haltype >= ARRAY_SIZE(sc->tx.hwq_map)) {
- ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_FATAL,
- "HAL AC %u out of range, max %zu!\n",
- haltype, ARRAY_SIZE(sc->tx.hwq_map));
- return -1;
- }
- qnum = sc->tx.hwq_map[haltype];
- break;
- case ATH9K_TX_QUEUE_BEACON:
- qnum = sc->beacon.beaconq;
- break;
- case ATH9K_TX_QUEUE_CAB:
- qnum = sc->beacon.cabq->axq_qnum;
- break;
- default:
- qnum = -1;
- }
- return qnum;
-}
-
-struct ath_txq *ath_test_get_txq(struct ath_softc *sc, struct sk_buff *skb)
-{
- struct ath_txq *txq = NULL;
- u16 skb_queue = skb_get_queue_mapping(skb);
- int qnum;
-
- qnum = ath_get_hal_qnum(skb_queue, sc);
- txq = &sc->tx.txq[qnum];
-
- spin_lock_bh(&txq->axq_lock);
-
- if (txq->axq_depth >= (ATH_TXBUF - 20)) {
- ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_XMIT,
- "TX queue: %d is full, depth: %d\n",
- qnum, txq->axq_depth);
- ath_mac80211_stop_queue(sc, skb_queue);
- txq->stopped = 1;
- spin_unlock_bh(&txq->axq_lock);
- return NULL;
- }
-
- spin_unlock_bh(&txq->axq_lock);
-
- return txq;
-}
-
int ath_txq_update(struct ath_softc *sc, int qnum,
struct ath9k_tx_queue_info *qinfo)
{
@@ -1688,12 +1668,15 @@ static int ath_tx_setup_buffer(struct ieee80211_hw *hw, struct ath_buf *bf,
bf->bf_frmlen -= padsize;
}
- if (conf_is_ht(&hw->conf)) {
+ if (!txctl->paprd && conf_is_ht(&hw->conf)) {
bf->bf_state.bf_type |= BUF_HT;
if (tx_info->flags & IEEE80211_TX_CTL_LDPC)
use_ldpc = true;
}
+ bf->bf_state.bfs_paprd = txctl->paprd;
+ if (txctl->paprd)
+ bf->bf_state.bfs_paprd_timestamp = jiffies;
bf->bf_flags = setup_tx_flags(skb, use_ldpc);
bf->bf_keytype = get_hw_crypto_keytype(skb);
@@ -1768,6 +1751,9 @@ static void ath_tx_start_dma(struct ath_softc *sc, struct ath_buf *bf,
bf->bf_buf_addr,
txctl->txq->axq_qnum);
+ if (bf->bf_state.bfs_paprd)
+ ar9003_hw_set_paprd_txdesc(ah, ds, bf->bf_state.bfs_paprd);
+
spin_lock_bh(&txctl->txq->axq_lock);
if (bf_isht(bf) && (sc->sc_flags & SC_OP_TXAGGR) &&
@@ -1809,8 +1795,9 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb,
struct ath_wiphy *aphy = hw->priv;
struct ath_softc *sc = aphy->sc;
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+ struct ath_txq *txq = txctl->txq;
struct ath_buf *bf;
- int r;
+ int q, r;
bf = ath_tx_get_buffer(sc);
if (!bf) {
@@ -1820,8 +1807,6 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb,
r = ath_tx_setup_buffer(hw, bf, skb, txctl);
if (unlikely(r)) {
- struct ath_txq *txq = txctl->txq;
-
ath_print(common, ATH_DBG_FATAL, "TX mem alloc failure\n");
/* upon ath_tx_processq() this TX queue will be resumed, we
@@ -1829,7 +1814,7 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb,
* we will at least have to run TX completionon one buffer
* on the queue */
spin_lock_bh(&txq->axq_lock);
- if (sc->tx.txq[txq->axq_qnum].axq_depth > 1) {
+ if (!txq->stopped && txq->axq_depth > 1) {
ath_mac80211_stop_queue(sc, skb_get_queue_mapping(skb));
txq->stopped = 1;
}
@@ -1840,6 +1825,17 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb,
return r;
}
+ q = skb_get_queue_mapping(skb);
+ if (q >= 4)
+ q = 0;
+
+ spin_lock_bh(&txq->axq_lock);
+ if (++sc->tx.pending_frames[q] > ATH_MAX_QDEPTH && !txq->stopped) {
+ ath_mac80211_stop_queue(sc, skb_get_queue_mapping(skb));
+ txq->stopped = 1;
+ }
+ spin_unlock_bh(&txq->axq_lock);
+
ath_tx_start_dma(sc, bf, txctl);
return 0;
@@ -1909,7 +1905,7 @@ static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb,
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
struct ieee80211_hdr * hdr = (struct ieee80211_hdr *)skb->data;
- int padpos, padsize;
+ int q, padpos, padsize;
ath_print(common, ATH_DBG_XMIT, "TX complete: skb: %p\n", skb);
@@ -1948,8 +1944,16 @@ static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb,
if (unlikely(tx_info->pad[0] & ATH_TX_INFO_FRAME_TYPE_INTERNAL))
ath9k_tx_status(hw, skb);
- else
+ else {
+ q = skb_get_queue_mapping(skb);
+ if (q >= 4)
+ q = 0;
+
+ if (--sc->tx.pending_frames[q] < 0)
+ sc->tx.pending_frames[q] = 0;
+
ieee80211_tx_status(hw, skb);
+ }
}
static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf,
@@ -1971,8 +1975,18 @@ static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf,
}
dma_unmap_single(sc->dev, bf->bf_dmacontext, skb->len, DMA_TO_DEVICE);
- ath_tx_complete(sc, skb, bf->aphy, tx_flags);
- ath_debug_stat_tx(sc, txq, bf, ts);
+
+ if (bf->bf_state.bfs_paprd) {
+ if (time_after(jiffies,
+ bf->bf_state.bfs_paprd_timestamp +
+ msecs_to_jiffies(ATH_PAPRD_TIMEOUT)))
+ dev_kfree_skb_any(skb);
+ else
+ complete(&sc->paprd_complete);
+ } else {
+ ath_tx_complete(sc, skb, bf->aphy, tx_flags);
+ ath_debug_stat_tx(sc, txq, bf, ts);
+ }
/*
* Return the list of ath_buf of this mpdu to free queue
@@ -2050,21 +2064,21 @@ static void ath_tx_rc_status(struct ath_buf *bf, struct ath_tx_status *ts,
tx_info->status.rates[i].idx = -1;
}
- tx_info->status.rates[tx_rateindex].count = bf->bf_retries + 1;
+ tx_info->status.rates[tx_rateindex].count = ts->ts_longretry + 1;
}
static void ath_wake_mac80211_queue(struct ath_softc *sc, struct ath_txq *txq)
{
int qnum;
+ qnum = ath_get_mac80211_qnum(txq->axq_class, sc);
+ if (qnum == -1)
+ return;
+
spin_lock_bh(&txq->axq_lock);
- if (txq->stopped &&
- sc->tx.txq[txq->axq_qnum].axq_depth <= (ATH_TXBUF - 20)) {
- qnum = ath_get_mac80211_qnum(txq->axq_qnum, sc);
- if (qnum != -1) {
- ath_mac80211_start_queue(sc, qnum);
+ if (txq->stopped && sc->tx.pending_frames[qnum] < ATH_MAX_QDEPTH) {
+ if (ath_mac80211_start_queue(sc, qnum))
txq->stopped = 0;
- }
}
spin_unlock_bh(&txq->axq_lock);
}
@@ -2161,7 +2175,6 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
* This frame is sent out as a single frame.
* Use hardware retry status for this frame.
*/
- bf->bf_retries = ts.ts_longretry;
if (ts.ts_status & ATH9K_TXERR_XRETRY)
bf->bf_state.bf_type |= BUF_XRETRY;
ath_tx_rc_status(bf, &ts, 0, txok, true);
@@ -2279,8 +2292,18 @@ void ath_tx_edma_tasklet(struct ath_softc *sc)
txok = !(txs.ts_status & ATH9K_TXERR_MASK);
+ /*
+ * Make sure null func frame is acked before configuring
+ * hw into ps mode.
+ */
+ if (bf->bf_isnullfunc && txok) {
+ if ((sc->ps_flags & PS_ENABLED))
+ ath9k_enable_ps(sc);
+ else
+ sc->ps_flags |= PS_NULLFUNC_COMPLETED;
+ }
+
if (!bf_isampdu(bf)) {
- bf->bf_retries = txs.ts_longretry;
if (txs.ts_status & ATH9K_TXERR_XRETRY)
bf->bf_state.bf_type |= BUF_XRETRY;
ath_tx_rc_status(bf, &txs, 0, txok, true);
@@ -2424,62 +2447,44 @@ void ath_tx_node_init(struct ath_softc *sc, struct ath_node *an)
for (acno = 0, ac = &an->ac[acno];
acno < WME_NUM_AC; acno++, ac++) {
ac->sched = false;
+ ac->qnum = sc->tx.hwq_map[acno];
INIT_LIST_HEAD(&ac->tid_q);
-
- switch (acno) {
- case WME_AC_BE:
- ac->qnum = ath_tx_get_qnum(sc,
- ATH9K_TX_QUEUE_DATA, ATH9K_WME_AC_BE);
- break;
- case WME_AC_BK:
- ac->qnum = ath_tx_get_qnum(sc,
- ATH9K_TX_QUEUE_DATA, ATH9K_WME_AC_BK);
- break;
- case WME_AC_VI:
- ac->qnum = ath_tx_get_qnum(sc,
- ATH9K_TX_QUEUE_DATA, ATH9K_WME_AC_VI);
- break;
- case WME_AC_VO:
- ac->qnum = ath_tx_get_qnum(sc,
- ATH9K_TX_QUEUE_DATA, ATH9K_WME_AC_VO);
- break;
- }
}
}
void ath_tx_node_cleanup(struct ath_softc *sc, struct ath_node *an)
{
- int i;
- struct ath_atx_ac *ac, *ac_tmp;
- struct ath_atx_tid *tid, *tid_tmp;
+ struct ath_atx_ac *ac;
+ struct ath_atx_tid *tid;
struct ath_txq *txq;
+ int i, tidno;
- for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {
- if (ATH_TXQ_SETUP(sc, i)) {
- txq = &sc->tx.txq[i];
+ for (tidno = 0, tid = &an->tid[tidno];
+ tidno < WME_NUM_TID; tidno++, tid++) {
+ i = tid->ac->qnum;
- spin_lock_bh(&txq->axq_lock);
+ if (!ATH_TXQ_SETUP(sc, i))
+ continue;
- list_for_each_entry_safe(ac,
- ac_tmp, &txq->axq_acq, list) {
- tid = list_first_entry(&ac->tid_q,
- struct ath_atx_tid, list);
- if (tid && tid->an != an)
- continue;
- list_del(&ac->list);
- ac->sched = false;
-
- list_for_each_entry_safe(tid,
- tid_tmp, &ac->tid_q, list) {
- list_del(&tid->list);
- tid->sched = false;
- ath_tid_drain(sc, txq, tid);
- tid->state &= ~AGGR_ADDBA_COMPLETE;
- tid->state &= ~AGGR_CLEANUP;
- }
- }
+ txq = &sc->tx.txq[i];
+ ac = tid->ac;
- spin_unlock_bh(&txq->axq_lock);
+ spin_lock_bh(&txq->axq_lock);
+
+ if (tid->sched) {
+ list_del(&tid->list);
+ tid->sched = false;
}
+
+ if (ac->sched) {
+ list_del(&ac->list);
+ tid->ac->sched = false;
+ }
+
+ ath_tid_drain(sc, txq, tid);
+ tid->state &= ~AGGR_ADDBA_COMPLETE;
+ tid->state &= ~AGGR_CLEANUP;
+
+ spin_unlock_bh(&txq->axq_lock);
}
}
diff --git a/drivers/net/wireless/atmel_cs.c b/drivers/net/wireless/atmel_cs.c
index c2746fc7f2b..3b632161c10 100644
--- a/drivers/net/wireless/atmel_cs.c
+++ b/drivers/net/wireless/atmel_cs.c
@@ -42,7 +42,6 @@
#include <linux/moduleparam.h>
#include <linux/device.h>
-#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/cistpl.h>
#include <pcmcia/cisreg.h>
@@ -191,25 +190,23 @@ static int atmel_config_check(struct pcmcia_device *p_dev,
p_dev->conf.Attributes |= CONF_ENABLE_IRQ;
/* IO window settings */
- p_dev->io.NumPorts1 = p_dev->io.NumPorts2 = 0;
+ p_dev->resource[0]->end = p_dev->resource[1]->end = 0;
if ((cfg->io.nwin > 0) || (dflt->io.nwin > 0)) {
cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt->io;
- p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
- if (!(io->flags & CISTPL_IO_8BIT))
- p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_16;
- if (!(io->flags & CISTPL_IO_16BIT))
- p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
- p_dev->io.BasePort1 = io->win[0].base;
- p_dev->io.NumPorts1 = io->win[0].len;
+ p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH;
+ p_dev->resource[0]->flags |=
+ pcmcia_io_cfg_data_width(io->flags);
+ p_dev->resource[0]->start = io->win[0].base;
+ p_dev->resource[0]->end = io->win[0].len;
if (io->nwin > 1) {
- p_dev->io.Attributes2 = p_dev->io.Attributes1;
- p_dev->io.BasePort2 = io->win[1].base;
- p_dev->io.NumPorts2 = io->win[1].len;
+ p_dev->resource[1]->flags = p_dev->resource[0]->flags;
+ p_dev->resource[1]->start = io->win[1].base;
+ p_dev->resource[1]->end = io->win[1].len;
}
}
/* This reserves IO space but doesn't actually enable it */
- return pcmcia_request_io(p_dev, &p_dev->io);
+ return pcmcia_request_io(p_dev);
}
static int atmel_config(struct pcmcia_device *link)
@@ -254,7 +251,7 @@ static int atmel_config(struct pcmcia_device *link)
((local_info_t*)link->priv)->eth_dev =
init_atmel_card(link->irq,
- link->io.BasePort1,
+ link->resource[0]->start,
did ? did->driver_info : ATMEL_FW_TYPE_NONE,
&link->dev,
card_present,
diff --git a/drivers/net/wireless/b43/b43.h b/drivers/net/wireless/b43/b43.h
index 3a003e6803a..8674a99356a 100644
--- a/drivers/net/wireless/b43/b43.h
+++ b/drivers/net/wireless/b43/b43.h
@@ -530,7 +530,7 @@ struct b43_fw_header {
/* Size of the data. For ucode and PCM this is in bytes.
* For IV this is number-of-ivs. */
__be32 size;
-} __attribute__((__packed__));
+} __packed;
/* Initial Value file format */
#define B43_IV_OFFSET_MASK 0x7FFF
@@ -540,8 +540,8 @@ struct b43_iv {
union {
__be16 d16;
__be32 d32;
- } data __attribute__((__packed__));
-} __attribute__((__packed__));
+ } data __packed;
+} __packed;
/* Data structures for DMA transmission, per 80211 core. */
diff --git a/drivers/net/wireless/b43/dma.c b/drivers/net/wireless/b43/dma.c
index fa40fdfea71..10d0aaf754c 100644
--- a/drivers/net/wireless/b43/dma.c
+++ b/drivers/net/wireless/b43/dma.c
@@ -333,11 +333,11 @@ static inline
dma_addr_t dmaaddr;
if (tx) {
- dmaaddr = ssb_dma_map_single(ring->dev->dev,
- buf, len, DMA_TO_DEVICE);
+ dmaaddr = dma_map_single(ring->dev->dev->dma_dev,
+ buf, len, DMA_TO_DEVICE);
} else {
- dmaaddr = ssb_dma_map_single(ring->dev->dev,
- buf, len, DMA_FROM_DEVICE);
+ dmaaddr = dma_map_single(ring->dev->dev->dma_dev,
+ buf, len, DMA_FROM_DEVICE);
}
return dmaaddr;
@@ -348,11 +348,11 @@ static inline
dma_addr_t addr, size_t len, int tx)
{
if (tx) {
- ssb_dma_unmap_single(ring->dev->dev,
- addr, len, DMA_TO_DEVICE);
+ dma_unmap_single(ring->dev->dev->dma_dev,
+ addr, len, DMA_TO_DEVICE);
} else {
- ssb_dma_unmap_single(ring->dev->dev,
- addr, len, DMA_FROM_DEVICE);
+ dma_unmap_single(ring->dev->dev->dma_dev,
+ addr, len, DMA_FROM_DEVICE);
}
}
@@ -361,7 +361,7 @@ static inline
dma_addr_t addr, size_t len)
{
B43_WARN_ON(ring->tx);
- ssb_dma_sync_single_for_cpu(ring->dev->dev,
+ dma_sync_single_for_cpu(ring->dev->dev->dma_dev,
addr, len, DMA_FROM_DEVICE);
}
@@ -370,8 +370,8 @@ static inline
dma_addr_t addr, size_t len)
{
B43_WARN_ON(ring->tx);
- ssb_dma_sync_single_for_device(ring->dev->dev,
- addr, len, DMA_FROM_DEVICE);
+ dma_sync_single_for_device(ring->dev->dev->dma_dev,
+ addr, len, DMA_FROM_DEVICE);
}
static inline
@@ -401,9 +401,9 @@ static int alloc_ringmemory(struct b43_dmaring *ring)
*/
if (ring->type == B43_DMA_64BIT)
flags |= GFP_DMA;
- ring->descbase = ssb_dma_alloc_consistent(ring->dev->dev,
- B43_DMA_RINGMEMSIZE,
- &(ring->dmabase), flags);
+ ring->descbase = dma_alloc_coherent(ring->dev->dev->dma_dev,
+ B43_DMA_RINGMEMSIZE,
+ &(ring->dmabase), flags);
if (!ring->descbase) {
b43err(ring->dev->wl, "DMA ringmemory allocation failed\n");
return -ENOMEM;
@@ -420,8 +420,8 @@ static void free_ringmemory(struct b43_dmaring *ring)
if (ring->type == B43_DMA_64BIT)
flags |= GFP_DMA;
- ssb_dma_free_consistent(ring->dev->dev, B43_DMA_RINGMEMSIZE,
- ring->descbase, ring->dmabase, flags);
+ dma_free_coherent(ring->dev->dev->dma_dev, B43_DMA_RINGMEMSIZE,
+ ring->descbase, ring->dmabase);
}
/* Reset the RX DMA channel */
@@ -528,7 +528,7 @@ static bool b43_dma_mapping_error(struct b43_dmaring *ring,
dma_addr_t addr,
size_t buffersize, bool dma_to_device)
{
- if (unlikely(ssb_dma_mapping_error(ring->dev->dev, addr)))
+ if (unlikely(dma_mapping_error(ring->dev->dev->dma_dev, addr)))
return 1;
switch (ring->type) {
@@ -874,10 +874,10 @@ struct b43_dmaring *b43_setup_dmaring(struct b43_wldev *dev,
goto err_kfree_meta;
/* test for ability to dma to txhdr_cache */
- dma_test = ssb_dma_map_single(dev->dev,
- ring->txhdr_cache,
- b43_txhdr_size(dev),
- DMA_TO_DEVICE);
+ dma_test = dma_map_single(dev->dev->dma_dev,
+ ring->txhdr_cache,
+ b43_txhdr_size(dev),
+ DMA_TO_DEVICE);
if (b43_dma_mapping_error(ring, dma_test,
b43_txhdr_size(dev), 1)) {
@@ -889,10 +889,10 @@ struct b43_dmaring *b43_setup_dmaring(struct b43_wldev *dev,
if (!ring->txhdr_cache)
goto err_kfree_meta;
- dma_test = ssb_dma_map_single(dev->dev,
- ring->txhdr_cache,
- b43_txhdr_size(dev),
- DMA_TO_DEVICE);
+ dma_test = dma_map_single(dev->dev->dma_dev,
+ ring->txhdr_cache,
+ b43_txhdr_size(dev),
+ DMA_TO_DEVICE);
if (b43_dma_mapping_error(ring, dma_test,
b43_txhdr_size(dev), 1)) {
@@ -903,9 +903,9 @@ struct b43_dmaring *b43_setup_dmaring(struct b43_wldev *dev,
}
}
- ssb_dma_unmap_single(dev->dev,
- dma_test, b43_txhdr_size(dev),
- DMA_TO_DEVICE);
+ dma_unmap_single(dev->dev->dma_dev,
+ dma_test, b43_txhdr_size(dev),
+ DMA_TO_DEVICE);
}
err = alloc_ringmemory(ring);
@@ -1018,9 +1018,12 @@ static int b43_dma_set_mask(struct b43_wldev *dev, u64 mask)
/* Try to set the DMA mask. If it fails, try falling back to a
* lower mask, as we can always also support a lower one. */
while (1) {
- err = ssb_dma_set_mask(dev->dev, mask);
- if (!err)
- break;
+ err = dma_set_mask(dev->dev->dma_dev, mask);
+ if (!err) {
+ err = dma_set_coherent_mask(dev->dev->dma_dev, mask);
+ if (!err)
+ break;
+ }
if (mask == DMA_BIT_MASK(64)) {
mask = DMA_BIT_MASK(32);
fallback = 1;
@@ -1221,14 +1224,14 @@ static int dma_tx_fragment(struct b43_dmaring *ring,
meta->dmaaddr = map_descbuffer(ring, skb->data, skb->len, 1);
/* create a bounce buffer in zone_dma on mapping failure. */
if (b43_dma_mapping_error(ring, meta->dmaaddr, skb->len, 1)) {
- priv_info->bouncebuffer = kmalloc(skb->len, GFP_ATOMIC | GFP_DMA);
+ priv_info->bouncebuffer = kmemdup(skb->data, skb->len,
+ GFP_ATOMIC | GFP_DMA);
if (!priv_info->bouncebuffer) {
ring->current_slot = old_top_slot;
ring->used_slots = old_used_slots;
err = -ENOMEM;
goto out_unmap_hdr;
}
- memcpy(priv_info->bouncebuffer, skb->data, skb->len);
meta->dmaaddr = map_descbuffer(ring, priv_info->bouncebuffer, skb->len, 1);
if (b43_dma_mapping_error(ring, meta->dmaaddr, skb->len, 1)) {
diff --git a/drivers/net/wireless/b43/dma.h b/drivers/net/wireless/b43/dma.h
index dc91944d602..a01c2100f16 100644
--- a/drivers/net/wireless/b43/dma.h
+++ b/drivers/net/wireless/b43/dma.h
@@ -67,7 +67,7 @@
struct b43_dmadesc32 {
__le32 control;
__le32 address;
-} __attribute__ ((__packed__));
+} __packed;
#define B43_DMA32_DCTL_BYTECNT 0x00001FFF
#define B43_DMA32_DCTL_ADDREXT_MASK 0x00030000
#define B43_DMA32_DCTL_ADDREXT_SHIFT 16
@@ -140,7 +140,7 @@ struct b43_dmadesc64 {
__le32 control1;
__le32 address_low;
__le32 address_high;
-} __attribute__ ((__packed__));
+} __packed;
#define B43_DMA64_DCTL0_DTABLEEND 0x10000000
#define B43_DMA64_DCTL0_IRQ 0x20000000
#define B43_DMA64_DCTL0_FRAMEEND 0x40000000
@@ -153,8 +153,8 @@ struct b43_dmadesc_generic {
union {
struct b43_dmadesc32 dma32;
struct b43_dmadesc64 dma64;
- } __attribute__ ((__packed__));
-} __attribute__ ((__packed__));
+ } __packed;
+} __packed;
/* Misc DMA constants */
#define B43_DMA_RINGMEMSIZE PAGE_SIZE
diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c
index 7965b70efba..20631ae2ddd 100644
--- a/drivers/net/wireless/b43/main.c
+++ b/drivers/net/wireless/b43/main.c
@@ -108,7 +108,7 @@ int b43_modparam_verbose = B43_VERBOSITY_DEFAULT;
module_param_named(verbose, b43_modparam_verbose, int, 0644);
MODULE_PARM_DESC(verbose, "Log message verbosity: 0=error, 1=warn, 2=info(default), 3=debug");
-int b43_modparam_pio = B43_PIO_DEFAULT;
+static int b43_modparam_pio = B43_PIO_DEFAULT;
module_param_named(pio, b43_modparam_pio, int, 0644);
MODULE_PARM_DESC(pio, "Use PIO accesses by default: 0=DMA, 1=PIO");
@@ -1804,7 +1804,7 @@ static void b43_do_interrupt_thread(struct b43_wldev *dev)
dma_reason[2], dma_reason[3],
dma_reason[4], dma_reason[5]);
b43err(dev->wl, "This device does not support DMA "
- "on your system. Please use PIO instead.\n");
+ "on your system. It will now be switched to PIO.\n");
/* Fall back to PIO transfers if we get fatal DMA errors! */
dev->use_pio = 1;
b43_controller_restart(dev, "DMA error");
diff --git a/drivers/net/wireless/b43/pcmcia.c b/drivers/net/wireless/b43/pcmcia.c
index 0e99b634267..dfbc41d431f 100644
--- a/drivers/net/wireless/b43/pcmcia.c
+++ b/drivers/net/wireless/b43/pcmcia.c
@@ -26,7 +26,6 @@
#include <linux/ssb/ssb.h>
#include <linux/slab.h>
-#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/cistpl.h>
#include <pcmcia/ciscode.h>
@@ -65,7 +64,6 @@ static int __devinit b43_pcmcia_probe(struct pcmcia_device *dev)
{
struct ssb_bus *ssb;
win_req_t win;
- memreq_t mem;
int err = -ENOMEM;
int res = 0;
@@ -78,12 +76,7 @@ static int __devinit b43_pcmcia_probe(struct pcmcia_device *dev)
dev->conf.Attributes = CONF_ENABLE_IRQ;
dev->conf.IntType = INT_MEMORY_AND_IO;
- dev->io.BasePort2 = 0;
- dev->io.NumPorts2 = 0;
- dev->io.Attributes2 = 0;
-
- win.Attributes = WIN_ADDR_SPACE_MEM | WIN_MEMORY_TYPE_CM |
- WIN_ENABLE | WIN_DATA_WIDTH_16 |
+ win.Attributes = WIN_ENABLE | WIN_DATA_WIDTH_16 |
WIN_USE_WAIT;
win.Base = 0;
win.Size = SSB_CORE_SIZE;
@@ -92,9 +85,7 @@ static int __devinit b43_pcmcia_probe(struct pcmcia_device *dev)
if (res != 0)
goto err_kfree_ssb;
- mem.CardOffset = 0;
- mem.Page = 0;
- res = pcmcia_map_mem_page(dev, dev->win, &mem);
+ res = pcmcia_map_mem_page(dev, dev->win, 0);
if (res != 0)
goto err_disable;
diff --git a/drivers/net/wireless/b43/phy_g.c b/drivers/net/wireless/b43/phy_g.c
index 29bf34ced86..0dc33b65e86 100644
--- a/drivers/net/wireless/b43/phy_g.c
+++ b/drivers/net/wireless/b43/phy_g.c
@@ -972,7 +972,7 @@ b43_radio_interference_mitigation_enable(struct b43_wldev *dev, int mode)
b43_phy_maskset(dev, 0x04A2, 0xFFF0, 0x000B);
if (phy->rev >= 3) {
- b43_phy_mask(dev, 0x048A, (u16)~0x8000);
+ b43_phy_mask(dev, 0x048A, 0x7FFF);
b43_phy_maskset(dev, 0x0415, 0x8000, 0x36D8);
b43_phy_maskset(dev, 0x0416, 0x8000, 0x36D8);
b43_phy_maskset(dev, 0x0417, 0xFE00, 0x016D);
diff --git a/drivers/net/wireless/b43/phy_lp.c b/drivers/net/wireless/b43/phy_lp.c
index c6afe9d9459..fd50eb11624 100644
--- a/drivers/net/wireless/b43/phy_lp.c
+++ b/drivers/net/wireless/b43/phy_lp.c
@@ -1145,7 +1145,7 @@ static void lpphy_write_tx_pctl_mode_to_hardware(struct b43_wldev *dev)
B43_WARN_ON(1);
}
b43_phy_maskset(dev, B43_LPPHY_TX_PWR_CTL_CMD,
- (u16)~B43_LPPHY_TX_PWR_CTL_CMD_MODE, ctl);
+ ~B43_LPPHY_TX_PWR_CTL_CMD_MODE & 0xFFFF, ctl);
}
static void lpphy_set_tx_power_control(struct b43_wldev *dev,
@@ -1522,11 +1522,11 @@ static void lpphy_tx_pctl_init_hw(struct b43_wldev *dev)
b43_phy_mask(dev, B43_LPPHY_TX_PWR_CTL_DELTAPWR_LIMIT, 0xFF);
b43_phy_write(dev, B43_LPPHY_TX_PWR_CTL_DELTAPWR_LIMIT, 0xA);
b43_phy_maskset(dev, B43_LPPHY_TX_PWR_CTL_CMD,
- (u16)~B43_LPPHY_TX_PWR_CTL_CMD_MODE,
+ ~B43_LPPHY_TX_PWR_CTL_CMD_MODE & 0xFFFF,
B43_LPPHY_TX_PWR_CTL_CMD_MODE_OFF);
b43_phy_mask(dev, B43_LPPHY_TX_PWR_CTL_NNUM, 0xF8FF);
b43_phy_maskset(dev, B43_LPPHY_TX_PWR_CTL_CMD,
- (u16)~B43_LPPHY_TX_PWR_CTL_CMD_MODE,
+ ~B43_LPPHY_TX_PWR_CTL_CMD_MODE & 0xFFFF,
B43_LPPHY_TX_PWR_CTL_CMD_MODE_SW);
if (dev->phy.rev < 2) {
@@ -2698,7 +2698,7 @@ static enum b43_txpwr_result b43_lpphy_op_recalc_txpower(struct b43_wldev *dev,
return B43_TXPWR_RES_DONE;
}
-void b43_lpphy_op_switch_analog(struct b43_wldev *dev, bool on)
+static void b43_lpphy_op_switch_analog(struct b43_wldev *dev, bool on)
{
if (on) {
b43_phy_mask(dev, B43_LPPHY_AFE_CTL_OVR, 0xfff8);
diff --git a/drivers/net/wireless/b43/phy_n.c b/drivers/net/wireless/b43/phy_n.c
index 3d6b3377596..5a725703770 100644
--- a/drivers/net/wireless/b43/phy_n.c
+++ b/drivers/net/wireless/b43/phy_n.c
@@ -509,7 +509,8 @@ static void b43_nphy_rx_cal_phy_setup(struct b43_wldev *dev, u8 core)
b43_phy_mask(dev, B43_NPHY_PAPD_EN0, ~0x0001);
b43_phy_mask(dev, B43_NPHY_PAPD_EN1, ~0x0001);
- b43_phy_maskset(dev, B43_NPHY_RFSEQCA, (u16)~B43_NPHY_RFSEQCA_RXDIS,
+ b43_phy_maskset(dev, B43_NPHY_RFSEQCA,
+ ~B43_NPHY_RFSEQCA_RXDIS & 0xFFFF,
((1 - core) << B43_NPHY_RFSEQCA_RXDIS_SHIFT));
b43_phy_maskset(dev, B43_NPHY_RFSEQCA, ~B43_NPHY_RFSEQCA_TXEN,
((1 - core) << B43_NPHY_RFSEQCA_TXEN_SHIFT));
@@ -762,7 +763,7 @@ static void b43_nphy_stop_playback(struct b43_wldev *dev)
if (tmp & 0x1)
b43_phy_set(dev, B43_NPHY_SAMP_CMD, B43_NPHY_SAMP_CMD_STOP);
else if (tmp & 0x2)
- b43_phy_mask(dev, B43_NPHY_IQLOCAL_CMDGCTL, (u16)~0x8000);
+ b43_phy_mask(dev, B43_NPHY_IQLOCAL_CMDGCTL, 0x7FFF);
b43_phy_mask(dev, B43_NPHY_SAMP_CMD, ~0x0004);
@@ -1009,7 +1010,7 @@ static void b43_nphy_gain_crtl_workarounds(struct b43_wldev *dev)
b43_nphy_set_rf_sequence(dev, 5,
rfseq_events, rfseq_delays, 3);
b43_phy_maskset(dev, B43_NPHY_OVER_DGAIN1,
- (u16)~B43_NPHY_OVER_DGAIN_CCKDGECV,
+ ~B43_NPHY_OVER_DGAIN_CCKDGECV & 0xFFFF,
0x5A << B43_NPHY_OVER_DGAIN_CCKDGECV_SHIFT);
if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ)
@@ -1116,7 +1117,7 @@ static void b43_nphy_workarounds(struct b43_wldev *dev)
b43_phy_write(dev, B43_NPHY_PHASETR_B2, 0x20);
b43_phy_mask(dev, B43_NPHY_PIL_DW1,
- (u16)~B43_NPHY_PIL_DW_64QAM);
+ ~B43_NPHY_PIL_DW_64QAM & 0xFFFF);
b43_phy_write(dev, B43_NPHY_TXF_20CO_S2B1, 0xB5);
b43_phy_write(dev, B43_NPHY_TXF_20CO_S2B2, 0xA4);
b43_phy_write(dev, B43_NPHY_TXF_20CO_S2B3, 0x00);
@@ -2455,7 +2456,8 @@ static void b43_nphy_tx_cal_phy_setup(struct b43_wldev *dev)
b43_phy_write(dev, B43_NPHY_AFECTL_OVER, tmp | 0x0600);
regs[4] = b43_phy_read(dev, B43_NPHY_BBCFG);
- b43_phy_mask(dev, B43_NPHY_BBCFG, (u16)~B43_NPHY_BBCFG_RSTRX);
+ b43_phy_mask(dev, B43_NPHY_BBCFG,
+ ~B43_NPHY_BBCFG_RSTRX & 0xFFFF);
tmp = b43_ntab_read(dev, B43_NTAB16(8, 3));
regs[5] = tmp;
@@ -2930,7 +2932,7 @@ static int b43_nphy_rev2_cal_rx_iq(struct b43_wldev *dev,
tmp[5] = b43_phy_read(dev, rfctl[1]);
b43_phy_maskset(dev, B43_NPHY_RFSEQCA,
- (u16)~B43_NPHY_RFSEQCA_RXDIS,
+ ~B43_NPHY_RFSEQCA_RXDIS & 0xFFFF,
((1 - i) << B43_NPHY_RFSEQCA_RXDIS_SHIFT));
b43_phy_maskset(dev, B43_NPHY_RFSEQCA, ~B43_NPHY_RFSEQCA_TXEN,
(1 - i));
@@ -3291,7 +3293,7 @@ static void b43_nphy_chanspec_setup(struct b43_wldev *dev,
b43_phy_mask(dev, B43_NPHY_BANDCTL, ~B43_NPHY_BANDCTL_5GHZ);
tmp32 = b43_read32(dev, B43_MMIO_PSM_PHY_HDR);
b43_write32(dev, B43_MMIO_PSM_PHY_HDR, tmp32 | 4);
- b43_phy_mask(dev, B43_PHY_B_BBCFG, (u16)~0xC000);
+ b43_phy_mask(dev, B43_PHY_B_BBCFG, 0x3FFF);
b43_write32(dev, B43_MMIO_PSM_PHY_HDR, tmp32);
}
diff --git a/drivers/net/wireless/b43/sdio.c b/drivers/net/wireless/b43/sdio.c
index 4e56b7bbceb..45933cf8e8c 100644
--- a/drivers/net/wireless/b43/sdio.c
+++ b/drivers/net/wireless/b43/sdio.c
@@ -182,6 +182,7 @@ static void b43_sdio_remove(struct sdio_func *func)
static const struct sdio_device_id b43_sdio_ids[] = {
{ SDIO_DEVICE(0x02d0, 0x044b) }, /* Nintendo Wii WLAN daughter card */
+ { SDIO_DEVICE(0x0092, 0x0004) }, /* C-guys, Inc. EW-CG1102GC */
{ },
};
diff --git a/drivers/net/wireless/b43/wa.c b/drivers/net/wireless/b43/wa.c
index 97c79161c20..9a335da65b4 100644
--- a/drivers/net/wireless/b43/wa.c
+++ b/drivers/net/wireless/b43/wa.c
@@ -382,7 +382,7 @@ static void b43_wa_altagc(struct b43_wldev *dev)
b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1, 3, 25);
}
- b43_phy_maskset(dev, B43_PHY_CCKSHIFTBITS_WA, (u16)~0xFF00, 0x5700);
+ b43_phy_maskset(dev, B43_PHY_CCKSHIFTBITS_WA, 0x00FF, 0x5700);
b43_phy_maskset(dev, B43_PHY_OFDM(0x1A), ~0x007F, 0x000F);
b43_phy_maskset(dev, B43_PHY_OFDM(0x1A), ~0x3F80, 0x2B80);
b43_phy_maskset(dev, B43_PHY_ANTWRSETT, 0xF0FF, 0x0300);
@@ -400,9 +400,9 @@ static void b43_wa_altagc(struct b43_wldev *dev)
b43_phy_maskset(dev, B43_PHY_OFDM(0x89), ~0x00FF, 0x0020);
b43_phy_maskset(dev, B43_PHY_OFDM(0x89), ~0x3F00, 0x0200);
b43_phy_maskset(dev, B43_PHY_OFDM(0x82), ~0x00FF, 0x002E);
- b43_phy_maskset(dev, B43_PHY_OFDM(0x96), (u16)~0xFF00, 0x1A00);
+ b43_phy_maskset(dev, B43_PHY_OFDM(0x96), 0x00FF, 0x1A00);
b43_phy_maskset(dev, B43_PHY_OFDM(0x81), ~0x00FF, 0x0028);
- b43_phy_maskset(dev, B43_PHY_OFDM(0x81), (u16)~0xFF00, 0x2C00);
+ b43_phy_maskset(dev, B43_PHY_OFDM(0x81), 0x00FF, 0x2C00);
if (phy->rev == 1) {
b43_phy_write(dev, B43_PHY_PEAK_COUNT, 0x092B);
b43_phy_maskset(dev, B43_PHY_OFDM(0x1B), ~0x001E, 0x0002);
@@ -412,7 +412,7 @@ static void b43_wa_altagc(struct b43_wldev *dev)
b43_phy_maskset(dev, B43_PHY_LPFGAINCTL, ~0x000F, 0x0004);
if (phy->rev >= 6) {
b43_phy_write(dev, B43_PHY_OFDM(0x22), 0x287A);
- b43_phy_maskset(dev, B43_PHY_LPFGAINCTL, (u16)~0xF000, 0x3000);
+ b43_phy_maskset(dev, B43_PHY_LPFGAINCTL, 0x0FFF, 0x3000);
}
}
b43_phy_maskset(dev, B43_PHY_DIVSRCHIDX, 0x8080, 0x7874);
diff --git a/drivers/net/wireless/b43/xmit.h b/drivers/net/wireless/b43/xmit.h
index d23ff9fe0c9..d4cf9b390af 100644
--- a/drivers/net/wireless/b43/xmit.h
+++ b/drivers/net/wireless/b43/xmit.h
@@ -10,8 +10,8 @@
union { \
__le32 data; \
__u8 raw[size]; \
- } __attribute__((__packed__)); \
- } __attribute__((__packed__))
+ } __packed; \
+ } __packed
/* struct b43_plcp_hdr4 */
_b43_declare_plcp_hdr(4);
@@ -57,7 +57,7 @@ struct b43_txhdr {
__u8 rts_frame[16]; /* The RTS frame (if used) */
PAD_BYTES(2);
struct b43_plcp_hdr6 plcp; /* Main PLCP header */
- } new_format __attribute__ ((__packed__));
+ } new_format __packed;
/* The old r351 format. */
struct {
@@ -68,10 +68,10 @@ struct b43_txhdr {
__u8 rts_frame[16]; /* The RTS frame (if used) */
PAD_BYTES(2);
struct b43_plcp_hdr6 plcp; /* Main PLCP header */
- } old_format __attribute__ ((__packed__));
+ } old_format __packed;
- } __attribute__ ((__packed__));
-} __attribute__ ((__packed__));
+ } __packed;
+} __packed;
/* MAC TX control */
#define B43_TXH_MAC_USEFBR 0x10000000 /* Use fallback rate for this AMPDU */
@@ -218,20 +218,20 @@ struct b43_rxhdr_fw4 {
struct {
__u8 jssi; /* PHY RX Status 1: JSSI */
__u8 sig_qual; /* PHY RX Status 1: Signal Quality */
- } __attribute__ ((__packed__));
+ } __packed;
/* RSSI for N-PHYs */
struct {
__s8 power0; /* PHY RX Status 1: Power 0 */
__s8 power1; /* PHY RX Status 1: Power 1 */
- } __attribute__ ((__packed__));
- } __attribute__ ((__packed__));
+ } __packed;
+ } __packed;
__le16 phy_status2; /* PHY RX Status 2 */
__le16 phy_status3; /* PHY RX Status 3 */
__le32 mac_status; /* MAC RX status */
__le16 mac_time;
__le16 channel;
-} __attribute__ ((__packed__));
+} __packed;
/* PHY RX Status 0 */
#define B43_RX_PHYST0_GAINCTL 0x4000 /* Gain Control */
diff --git a/drivers/net/wireless/b43legacy/b43legacy.h b/drivers/net/wireless/b43legacy/b43legacy.h
index 89fe2f972c7..c81b2f53b0c 100644
--- a/drivers/net/wireless/b43legacy/b43legacy.h
+++ b/drivers/net/wireless/b43legacy/b43legacy.h
@@ -372,7 +372,7 @@ struct b43legacy_fw_header {
/* Size of the data. For ucode and PCM this is in bytes.
* For IV this is number-of-ivs. */
__be32 size;
-} __attribute__((__packed__));
+} __packed;
/* Initial Value file format */
#define B43legacy_IV_OFFSET_MASK 0x7FFF
@@ -382,8 +382,8 @@ struct b43legacy_iv {
union {
__be16 d16;
__be32 d32;
- } data __attribute__((__packed__));
-} __attribute__((__packed__));
+ } data __packed;
+} __packed;
#define B43legacy_PHYMODE(phytype) (1 << (phytype))
#define B43legacy_PHYMODE_B B43legacy_PHYMODE \
diff --git a/drivers/net/wireless/b43legacy/dma.c b/drivers/net/wireless/b43legacy/dma.c
index e91520d0312..e03e01d0bc3 100644
--- a/drivers/net/wireless/b43legacy/dma.c
+++ b/drivers/net/wireless/b43legacy/dma.c
@@ -394,11 +394,11 @@ dma_addr_t map_descbuffer(struct b43legacy_dmaring *ring,
dma_addr_t dmaaddr;
if (tx)
- dmaaddr = ssb_dma_map_single(ring->dev->dev,
+ dmaaddr = dma_map_single(ring->dev->dev->dma_dev,
buf, len,
DMA_TO_DEVICE);
else
- dmaaddr = ssb_dma_map_single(ring->dev->dev,
+ dmaaddr = dma_map_single(ring->dev->dev->dma_dev,
buf, len,
DMA_FROM_DEVICE);
@@ -412,11 +412,11 @@ void unmap_descbuffer(struct b43legacy_dmaring *ring,
int tx)
{
if (tx)
- ssb_dma_unmap_single(ring->dev->dev,
+ dma_unmap_single(ring->dev->dev->dma_dev,
addr, len,
DMA_TO_DEVICE);
else
- ssb_dma_unmap_single(ring->dev->dev,
+ dma_unmap_single(ring->dev->dev->dma_dev,
addr, len,
DMA_FROM_DEVICE);
}
@@ -428,8 +428,8 @@ void sync_descbuffer_for_cpu(struct b43legacy_dmaring *ring,
{
B43legacy_WARN_ON(ring->tx);
- ssb_dma_sync_single_for_cpu(ring->dev->dev,
- addr, len, DMA_FROM_DEVICE);
+ dma_sync_single_for_cpu(ring->dev->dev->dma_dev,
+ addr, len, DMA_FROM_DEVICE);
}
static inline
@@ -439,8 +439,8 @@ void sync_descbuffer_for_device(struct b43legacy_dmaring *ring,
{
B43legacy_WARN_ON(ring->tx);
- ssb_dma_sync_single_for_device(ring->dev->dev,
- addr, len, DMA_FROM_DEVICE);
+ dma_sync_single_for_device(ring->dev->dev->dma_dev,
+ addr, len, DMA_FROM_DEVICE);
}
static inline
@@ -460,10 +460,10 @@ void free_descriptor_buffer(struct b43legacy_dmaring *ring,
static int alloc_ringmemory(struct b43legacy_dmaring *ring)
{
/* GFP flags must match the flags in free_ringmemory()! */
- ring->descbase = ssb_dma_alloc_consistent(ring->dev->dev,
- B43legacy_DMA_RINGMEMSIZE,
- &(ring->dmabase),
- GFP_KERNEL);
+ ring->descbase = dma_alloc_coherent(ring->dev->dev->dma_dev,
+ B43legacy_DMA_RINGMEMSIZE,
+ &(ring->dmabase),
+ GFP_KERNEL);
if (!ring->descbase) {
b43legacyerr(ring->dev->wl, "DMA ringmemory allocation"
" failed\n");
@@ -476,8 +476,8 @@ static int alloc_ringmemory(struct b43legacy_dmaring *ring)
static void free_ringmemory(struct b43legacy_dmaring *ring)
{
- ssb_dma_free_consistent(ring->dev->dev, B43legacy_DMA_RINGMEMSIZE,
- ring->descbase, ring->dmabase, GFP_KERNEL);
+ dma_free_coherent(ring->dev->dev->dma_dev, B43legacy_DMA_RINGMEMSIZE,
+ ring->descbase, ring->dmabase);
}
/* Reset the RX DMA channel */
@@ -589,7 +589,7 @@ static bool b43legacy_dma_mapping_error(struct b43legacy_dmaring *ring,
size_t buffersize,
bool dma_to_device)
{
- if (unlikely(ssb_dma_mapping_error(ring->dev->dev, addr)))
+ if (unlikely(dma_mapping_error(ring->dev->dev->dma_dev, addr)))
return 1;
switch (ring->type) {
@@ -906,7 +906,7 @@ struct b43legacy_dmaring *b43legacy_setup_dmaring(struct b43legacy_wldev *dev,
goto err_kfree_meta;
/* test for ability to dma to txhdr_cache */
- dma_test = ssb_dma_map_single(dev->dev, ring->txhdr_cache,
+ dma_test = dma_map_single(dev->dev->dma_dev, ring->txhdr_cache,
sizeof(struct b43legacy_txhdr_fw3),
DMA_TO_DEVICE);
@@ -920,7 +920,7 @@ struct b43legacy_dmaring *b43legacy_setup_dmaring(struct b43legacy_wldev *dev,
if (!ring->txhdr_cache)
goto err_kfree_meta;
- dma_test = ssb_dma_map_single(dev->dev,
+ dma_test = dma_map_single(dev->dev->dma_dev,
ring->txhdr_cache,
sizeof(struct b43legacy_txhdr_fw3),
DMA_TO_DEVICE);
@@ -930,9 +930,9 @@ struct b43legacy_dmaring *b43legacy_setup_dmaring(struct b43legacy_wldev *dev,
goto err_kfree_txhdr_cache;
}
- ssb_dma_unmap_single(dev->dev, dma_test,
- sizeof(struct b43legacy_txhdr_fw3),
- DMA_TO_DEVICE);
+ dma_unmap_single(dev->dev->dma_dev, dma_test,
+ sizeof(struct b43legacy_txhdr_fw3),
+ DMA_TO_DEVICE);
}
ring->nr_slots = nr_slots;
@@ -1040,9 +1040,12 @@ static int b43legacy_dma_set_mask(struct b43legacy_wldev *dev, u64 mask)
/* Try to set the DMA mask. If it fails, try falling back to a
* lower mask, as we can always also support a lower one. */
while (1) {
- err = ssb_dma_set_mask(dev->dev, mask);
- if (!err)
- break;
+ err = dma_set_mask(dev->dev->dma_dev, mask);
+ if (!err) {
+ err = dma_set_coherent_mask(dev->dev->dma_dev, mask);
+ if (!err)
+ break;
+ }
if (mask == DMA_BIT_MASK(64)) {
mask = DMA_BIT_MASK(32);
fallback = 1;
diff --git a/drivers/net/wireless/b43legacy/dma.h b/drivers/net/wireless/b43legacy/dma.h
index f9681041c2d..f89c3422628 100644
--- a/drivers/net/wireless/b43legacy/dma.h
+++ b/drivers/net/wireless/b43legacy/dma.h
@@ -72,7 +72,7 @@
struct b43legacy_dmadesc32 {
__le32 control;
__le32 address;
-} __attribute__((__packed__));
+} __packed;
#define B43legacy_DMA32_DCTL_BYTECNT 0x00001FFF
#define B43legacy_DMA32_DCTL_ADDREXT_MASK 0x00030000
#define B43legacy_DMA32_DCTL_ADDREXT_SHIFT 16
@@ -147,7 +147,7 @@ struct b43legacy_dmadesc64 {
__le32 control1;
__le32 address_low;
__le32 address_high;
-} __attribute__((__packed__));
+} __packed;
#define B43legacy_DMA64_DCTL0_DTABLEEND 0x10000000
#define B43legacy_DMA64_DCTL0_IRQ 0x20000000
#define B43legacy_DMA64_DCTL0_FRAMEEND 0x40000000
@@ -162,8 +162,8 @@ struct b43legacy_dmadesc_generic {
union {
struct b43legacy_dmadesc32 dma32;
struct b43legacy_dmadesc64 dma64;
- } __attribute__((__packed__));
-} __attribute__((__packed__));
+ } __packed;
+} __packed;
/* Misc DMA constants */
diff --git a/drivers/net/wireless/b43legacy/xmit.h b/drivers/net/wireless/b43legacy/xmit.h
index 91633087a20..289db00a4a7 100644
--- a/drivers/net/wireless/b43legacy/xmit.h
+++ b/drivers/net/wireless/b43legacy/xmit.h
@@ -9,8 +9,8 @@
union { \
__le32 data; \
__u8 raw[size]; \
- } __attribute__((__packed__)); \
- } __attribute__((__packed__))
+ } __packed; \
+ } __packed
/* struct b43legacy_plcp_hdr4 */
_b43legacy_declare_plcp_hdr(4);
@@ -39,7 +39,7 @@ struct b43legacy_txhdr_fw3 {
struct b43legacy_plcp_hdr6 rts_plcp; /* RTS PLCP */
__u8 rts_frame[18]; /* The RTS frame (if used) */
struct b43legacy_plcp_hdr6 plcp;
-} __attribute__((__packed__));
+} __packed;
/* MAC TX control */
#define B43legacy_TX4_MAC_KEYIDX 0x0FF00000 /* Security key index */
@@ -123,7 +123,7 @@ struct b43legacy_hwtxstatus {
__le16 seq;
u8 phy_stat;
PAD_BYTES(1);
-} __attribute__((__packed__));
+} __packed;
/* Receive header for v3 firmware. */
@@ -138,7 +138,7 @@ struct b43legacy_rxhdr_fw3 {
__le16 mac_status; /* MAC RX status */
__le16 mac_time;
__le16 channel;
-} __attribute__((__packed__));
+} __packed;
/* PHY RX Status 0 */
diff --git a/drivers/net/wireless/hostap/hostap_80211.h b/drivers/net/wireless/hostap/hostap_80211.h
index 7f9d8d976aa..ed98ce7c8f6 100644
--- a/drivers/net/wireless/hostap/hostap_80211.h
+++ b/drivers/net/wireless/hostap/hostap_80211.h
@@ -19,35 +19,35 @@ struct hostap_ieee80211_mgmt {
__le16 status_code;
/* possibly followed by Challenge text */
u8 variable[0];
- } __attribute__ ((packed)) auth;
+ } __packed auth;
struct {
__le16 reason_code;
- } __attribute__ ((packed)) deauth;
+ } __packed deauth;
struct {
__le16 capab_info;
__le16 listen_interval;
/* followed by SSID and Supported rates */
u8 variable[0];
- } __attribute__ ((packed)) assoc_req;
+ } __packed assoc_req;
struct {
__le16 capab_info;
__le16 status_code;
__le16 aid;
/* followed by Supported rates */
u8 variable[0];
- } __attribute__ ((packed)) assoc_resp, reassoc_resp;
+ } __packed assoc_resp, reassoc_resp;
struct {
__le16 capab_info;
__le16 listen_interval;
u8 current_ap[6];
/* followed by SSID and Supported rates */
u8 variable[0];
- } __attribute__ ((packed)) reassoc_req;
+ } __packed reassoc_req;
struct {
__le16 reason_code;
- } __attribute__ ((packed)) disassoc;
+ } __packed disassoc;
struct {
- } __attribute__ ((packed)) probe_req;
+ } __packed probe_req;
struct {
u8 timestamp[8];
__le16 beacon_int;
@@ -55,9 +55,9 @@ struct hostap_ieee80211_mgmt {
/* followed by some of SSID, Supported rates,
* FH Params, DS Params, CF Params, IBSS Params, TIM */
u8 variable[0];
- } __attribute__ ((packed)) beacon, probe_resp;
+ } __packed beacon, probe_resp;
} u;
-} __attribute__ ((packed));
+} __packed;
#define IEEE80211_MGMT_HDR_LEN 24
diff --git a/drivers/net/wireless/hostap/hostap_ap.c b/drivers/net/wireless/hostap/hostap_ap.c
index 231dbd77f5f..dbb986946e1 100644
--- a/drivers/net/wireless/hostap/hostap_ap.c
+++ b/drivers/net/wireless/hostap/hostap_ap.c
@@ -688,7 +688,7 @@ static void hostap_ap_tx_cb_assoc(struct sk_buff *skb, int ok, void *data)
struct ap_data *ap = data;
struct net_device *dev = ap->local->dev;
struct ieee80211_hdr *hdr;
- u16 fc, status;
+ u16 status;
__le16 *pos;
struct sta_info *sta = NULL;
char *txt = NULL;
@@ -699,7 +699,6 @@ static void hostap_ap_tx_cb_assoc(struct sk_buff *skb, int ok, void *data)
}
hdr = (struct ieee80211_hdr *) skb->data;
- fc = le16_to_cpu(hdr->frame_control);
if ((!ieee80211_is_assoc_resp(hdr->frame_control) &&
!ieee80211_is_reassoc_resp(hdr->frame_control)) ||
skb->len < IEEE80211_MGMT_HDR_LEN + 4) {
@@ -1225,7 +1224,7 @@ static void ap_crypt_init(struct ap_data *ap)
/* Generate challenge data for shared key authentication. IEEE 802.11 specifies
- * that WEP algorithm is used for generating challange. This should be unique,
+ * that WEP algorithm is used for generating challenge. This should be unique,
* but otherwise there is not really need for randomness etc. Initialize WEP
* with pseudo random key and then use increasing IV to get unique challenge
* streams.
diff --git a/drivers/net/wireless/hostap/hostap_common.h b/drivers/net/wireless/hostap/hostap_common.h
index 90b64b09200..4230102ac9e 100644
--- a/drivers/net/wireless/hostap/hostap_common.h
+++ b/drivers/net/wireless/hostap/hostap_common.h
@@ -179,7 +179,7 @@ struct hfa384x_comp_ident
__le16 variant;
__le16 major;
__le16 minor;
-} __attribute__ ((packed));
+} __packed;
#define HFA384X_COMP_ID_PRI 0x15
#define HFA384X_COMP_ID_STA 0x1f
@@ -192,14 +192,14 @@ struct hfa384x_sup_range
__le16 variant;
__le16 bottom;
__le16 top;
-} __attribute__ ((packed));
+} __packed;
struct hfa384x_build_id
{
__le16 pri_seq;
__le16 sec_seq;
-} __attribute__ ((packed));
+} __packed;
/* FD01 - Download Buffer */
struct hfa384x_rid_download_buffer
@@ -207,14 +207,14 @@ struct hfa384x_rid_download_buffer
__le16 page;
__le16 offset;
__le16 length;
-} __attribute__ ((packed));
+} __packed;
/* BSS connection quality (RID FD43 range, RID FD51 dBm-normalized) */
struct hfa384x_comms_quality {
__le16 comm_qual; /* 0 .. 92 */
__le16 signal_level; /* 27 .. 154 */
__le16 noise_level; /* 27 .. 154 */
-} __attribute__ ((packed));
+} __packed;
/* netdevice private ioctls (used, e.g., with iwpriv from user space) */
diff --git a/drivers/net/wireless/hostap/hostap_cs.c b/drivers/net/wireless/hostap/hostap_cs.c
index 29b31a694b5..ba54d1b04d2 100644
--- a/drivers/net/wireless/hostap/hostap_cs.c
+++ b/drivers/net/wireless/hostap/hostap_cs.c
@@ -12,7 +12,6 @@
#include <linux/wireless.h>
#include <net/iw_handler.h>
-#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/cistpl.h>
#include <pcmcia/cisreg.h>
@@ -23,7 +22,7 @@
#include "hostap_wlan.h"
-static dev_info_t dev_info = "hostap_cs";
+static char *dev_info = "hostap_cs";
MODULE_AUTHOR("Jouni Malinen");
MODULE_DESCRIPTION("Support for Intersil Prism2-based 802.11 wireless LAN "
@@ -225,27 +224,18 @@ static int prism2_pccard_card_present(local_info_t *local)
static void sandisk_set_iobase(local_info_t *local)
{
int res;
- conf_reg_t reg;
struct hostap_cs_priv *hw_priv = local->hw_priv;
- reg.Function = 0;
- reg.Action = CS_WRITE;
- reg.Offset = 0x10; /* 0x3f0 IO base 1 */
- reg.Value = hw_priv->link->io.BasePort1 & 0x00ff;
- res = pcmcia_access_configuration_register(hw_priv->link,
- &reg);
+ res = pcmcia_write_config_byte(hw_priv->link, 0x10,
+ hw_priv->link->resource[0]->start & 0x00ff);
if (res != 0) {
printk(KERN_DEBUG "Prism3 SanDisk - failed to set I/O base 0 -"
" res=%d\n", res);
}
udelay(10);
- reg.Function = 0;
- reg.Action = CS_WRITE;
- reg.Offset = 0x12; /* 0x3f2 IO base 2 */
- reg.Value = (hw_priv->link->io.BasePort1 & 0xff00) >> 8;
- res = pcmcia_access_configuration_register(hw_priv->link,
- &reg);
+ res = pcmcia_write_config_byte(hw_priv->link, 0x12,
+ (hw_priv->link->resource[0]->start >> 8) & 0x00ff);
if (res != 0) {
printk(KERN_DEBUG "Prism3 SanDisk - failed to set I/O base 1 -"
" res=%d\n", res);
@@ -271,12 +261,11 @@ static void sandisk_write_hcr(local_info_t *local, int hcr)
static int sandisk_enable_wireless(struct net_device *dev)
{
int res, ret = 0;
- conf_reg_t reg;
struct hostap_interface *iface = netdev_priv(dev);
local_info_t *local = iface->local;
struct hostap_cs_priv *hw_priv = local->hw_priv;
- if (hw_priv->link->io.NumPorts1 < 0x42) {
+ if (resource_size(hw_priv->link->resource[0]) < 0x42) {
/* Not enough ports to be SanDisk multi-function card */
ret = -ENODEV;
goto done;
@@ -298,12 +287,8 @@ static int sandisk_enable_wireless(struct net_device *dev)
" - using vendor-specific initialization\n", dev->name);
hw_priv->sandisk_connectplus = 1;
- reg.Function = 0;
- reg.Action = CS_WRITE;
- reg.Offset = CISREG_COR;
- reg.Value = COR_SOFT_RESET;
- res = pcmcia_access_configuration_register(hw_priv->link,
- &reg);
+ res = pcmcia_write_config_byte(hw_priv->link, CISREG_COR,
+ COR_SOFT_RESET);
if (res != 0) {
printk(KERN_DEBUG "%s: SanDisk - COR sreset failed (%d)\n",
dev->name, res);
@@ -311,16 +296,13 @@ static int sandisk_enable_wireless(struct net_device *dev)
}
mdelay(5);
- reg.Function = 0;
- reg.Action = CS_WRITE;
- reg.Offset = CISREG_COR;
/*
* Do not enable interrupts here to avoid some bogus events. Interrupts
* will be enabled during the first cor_sreset call.
*/
- reg.Value = COR_LEVEL_REQ | 0x8 | COR_ADDR_DECODE | COR_FUNC_ENA;
- res = pcmcia_access_configuration_register(hw_priv->link,
- &reg);
+ res = pcmcia_write_config_byte(hw_priv->link, CISREG_COR,
+ (COR_LEVEL_REQ | 0x8 | COR_ADDR_DECODE |
+ COR_FUNC_ENA));
if (res != 0) {
printk(KERN_DEBUG "%s: SanDisk - COR sreset failed (%d)\n",
dev->name, res);
@@ -343,30 +325,23 @@ done:
static void prism2_pccard_cor_sreset(local_info_t *local)
{
int res;
- conf_reg_t reg;
+ u8 val;
struct hostap_cs_priv *hw_priv = local->hw_priv;
if (!prism2_pccard_card_present(local))
return;
- reg.Function = 0;
- reg.Action = CS_READ;
- reg.Offset = CISREG_COR;
- reg.Value = 0;
- res = pcmcia_access_configuration_register(hw_priv->link,
- &reg);
+ res = pcmcia_read_config_byte(hw_priv->link, CISREG_COR, &val);
if (res != 0) {
printk(KERN_DEBUG "prism2_pccard_cor_sreset failed 1 (%d)\n",
res);
return;
}
printk(KERN_DEBUG "prism2_pccard_cor_sreset: original COR %02x\n",
- reg.Value);
+ val);
- reg.Action = CS_WRITE;
- reg.Value |= COR_SOFT_RESET;
- res = pcmcia_access_configuration_register(hw_priv->link,
- &reg);
+ val |= COR_SOFT_RESET;
+ res = pcmcia_write_config_byte(hw_priv->link, CISREG_COR, val);
if (res != 0) {
printk(KERN_DEBUG "prism2_pccard_cor_sreset failed 2 (%d)\n",
res);
@@ -375,11 +350,10 @@ static void prism2_pccard_cor_sreset(local_info_t *local)
mdelay(hw_priv->sandisk_connectplus ? 5 : 2);
- reg.Value &= ~COR_SOFT_RESET;
+ val &= ~COR_SOFT_RESET;
if (hw_priv->sandisk_connectplus)
- reg.Value |= COR_IREQ_ENA;
- res = pcmcia_access_configuration_register(hw_priv->link,
- &reg);
+ val |= COR_IREQ_ENA;
+ res = pcmcia_write_config_byte(hw_priv->link, CISREG_COR, val);
if (res != 0) {
printk(KERN_DEBUG "prism2_pccard_cor_sreset failed 3 (%d)\n",
res);
@@ -396,8 +370,7 @@ static void prism2_pccard_cor_sreset(local_info_t *local)
static void prism2_pccard_genesis_reset(local_info_t *local, int hcr)
{
int res;
- conf_reg_t reg;
- int old_cor;
+ u8 old_cor;
struct hostap_cs_priv *hw_priv = local->hw_priv;
if (!prism2_pccard_card_present(local))
@@ -408,25 +381,17 @@ static void prism2_pccard_genesis_reset(local_info_t *local, int hcr)
return;
}
- reg.Function = 0;
- reg.Action = CS_READ;
- reg.Offset = CISREG_COR;
- reg.Value = 0;
- res = pcmcia_access_configuration_register(hw_priv->link,
- &reg);
+ res = pcmcia_read_config_byte(hw_priv->link, CISREG_COR, &old_cor);
if (res != 0) {
printk(KERN_DEBUG "prism2_pccard_genesis_sreset failed 1 "
"(%d)\n", res);
return;
}
printk(KERN_DEBUG "prism2_pccard_genesis_sreset: original COR %02x\n",
- reg.Value);
- old_cor = reg.Value;
+ old_cor);
- reg.Action = CS_WRITE;
- reg.Value |= COR_SOFT_RESET;
- res = pcmcia_access_configuration_register(hw_priv->link,
- &reg);
+ res = pcmcia_write_config_byte(hw_priv->link, CISREG_COR,
+ old_cor | COR_SOFT_RESET);
if (res != 0) {
printk(KERN_DEBUG "prism2_pccard_genesis_sreset failed 2 "
"(%d)\n", res);
@@ -436,11 +401,7 @@ static void prism2_pccard_genesis_reset(local_info_t *local, int hcr)
mdelay(10);
/* Setup Genesis mode */
- reg.Action = CS_WRITE;
- reg.Value = hcr;
- reg.Offset = CISREG_CCSR;
- res = pcmcia_access_configuration_register(hw_priv->link,
- &reg);
+ res = pcmcia_write_config_byte(hw_priv->link, CISREG_CCSR, hcr);
if (res != 0) {
printk(KERN_DEBUG "prism2_pccard_genesis_sreset failed 3 "
"(%d)\n", res);
@@ -448,11 +409,8 @@ static void prism2_pccard_genesis_reset(local_info_t *local, int hcr)
}
mdelay(10);
- reg.Action = CS_WRITE;
- reg.Offset = CISREG_COR;
- reg.Value = old_cor & ~COR_SOFT_RESET;
- res = pcmcia_access_configuration_register(hw_priv->link,
- &reg);
+ res = pcmcia_write_config_byte(hw_priv->link, CISREG_COR,
+ old_cor & ~COR_SOFT_RESET);
if (res != 0) {
printk(KERN_DEBUG "prism2_pccard_genesis_sreset failed 4 "
"(%d)\n", res);
@@ -561,30 +519,24 @@ static int prism2_config_check(struct pcmcia_device *p_dev,
PDEBUG(DEBUG_EXTRA, "IO window settings: cfg->io.nwin=%d "
"dflt->io.nwin=%d\n",
cfg->io.nwin, dflt->io.nwin);
- p_dev->io.NumPorts1 = p_dev->io.NumPorts2 = 0;
+ p_dev->resource[0]->end = p_dev->resource[1]->end = 0;
if ((cfg->io.nwin > 0) || (dflt->io.nwin > 0)) {
cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt->io;
- p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
- PDEBUG(DEBUG_EXTRA, "io->flags = 0x%04X, "
- "io.base=0x%04x, len=%d\n", io->flags,
- io->win[0].base, io->win[0].len);
- if (!(io->flags & CISTPL_IO_8BIT))
- p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_16;
- if (!(io->flags & CISTPL_IO_16BIT))
- p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
- p_dev->io.IOAddrLines = io->flags &
- CISTPL_IO_LINES_MASK;
- p_dev->io.BasePort1 = io->win[0].base;
- p_dev->io.NumPorts1 = io->win[0].len;
+ p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH;
+ p_dev->resource[0]->flags |=
+ pcmcia_io_cfg_data_width(io->flags);
+ p_dev->io_lines = io->flags & CISTPL_IO_LINES_MASK;
+ p_dev->resource[0]->start = io->win[0].base;
+ p_dev->resource[0]->end = io->win[0].len;
if (io->nwin > 1) {
- p_dev->io.Attributes2 = p_dev->io.Attributes1;
- p_dev->io.BasePort2 = io->win[1].base;
- p_dev->io.NumPorts2 = io->win[1].len;
+ p_dev->resource[1]->flags = p_dev->resource[0]->flags;
+ p_dev->resource[1]->start = io->win[1].base;
+ p_dev->resource[1]->end = io->win[1].len;
}
}
/* This reserves IO space but doesn't actually enable it */
- return pcmcia_request_io(p_dev, &p_dev->io);
+ return pcmcia_request_io(p_dev);
}
static int prism2_config(struct pcmcia_device *link)
@@ -646,7 +598,7 @@ static int prism2_config(struct pcmcia_device *link)
goto failed_unlock;
dev->irq = link->irq;
- dev->base_addr = link->io.BasePort1;
+ dev->base_addr = link->resource[0]->start;
spin_unlock_irqrestore(&local->irq_init_lock, flags);
@@ -658,12 +610,10 @@ static int prism2_config(struct pcmcia_device *link)
link->conf.Vpp % 10);
if (link->conf.Attributes & CONF_ENABLE_IRQ)
printk(", irq %d", link->irq);
- if (link->io.NumPorts1)
- printk(", io 0x%04x-0x%04x", link->io.BasePort1,
- link->io.BasePort1+link->io.NumPorts1-1);
- if (link->io.NumPorts2)
- printk(" & 0x%04x-0x%04x", link->io.BasePort2,
- link->io.BasePort2+link->io.NumPorts2-1);
+ if (link->resource[0])
+ printk(" & %pR", link->resource[0]);
+ if (link->resource[1])
+ printk(" & %pR", link->resource[1]);
printk("\n");
local->shutdown = 0;
diff --git a/drivers/net/wireless/hostap/hostap_hw.c b/drivers/net/wireless/hostap/hostap_hw.c
index 2f999fc94f6..e9d9d622a9b 100644
--- a/drivers/net/wireless/hostap/hostap_hw.c
+++ b/drivers/net/wireless/hostap/hostap_hw.c
@@ -1896,7 +1896,7 @@ fail:
/* Some SMP systems have reported number of odd errors with hostap_pci. fid
* register has changed values between consecutive reads for an unknown reason.
* This should really not happen, so more debugging is needed. This test
- * version is a big slower, but it will detect most of such register changes
+ * version is a bit slower, but it will detect most of such register changes
* and will try to get the correct fid eventually. */
#define EXTRA_FID_READ_TESTS
diff --git a/drivers/net/wireless/hostap/hostap_main.c b/drivers/net/wireless/hostap/hostap_main.c
index eb57d1ea361..25a2722c8a9 100644
--- a/drivers/net/wireless/hostap/hostap_main.c
+++ b/drivers/net/wireless/hostap/hostap_main.c
@@ -186,7 +186,7 @@ int prism2_wds_add(local_info_t *local, u8 *remote_addr,
return -ENOBUFS;
/* verify that there is room for wds# postfix in the interface name */
- if (strlen(local->dev->name) > IFNAMSIZ - 5) {
+ if (strlen(local->dev->name) >= IFNAMSIZ - 5) {
printk(KERN_DEBUG "'%s' too long base device name\n",
local->dev->name);
return -EINVAL;
@@ -741,9 +741,7 @@ void hostap_set_multicast_list_queue(struct work_struct *work)
local_info_t *local =
container_of(work, local_info_t, set_multicast_list_queue);
struct net_device *dev = local->dev;
- struct hostap_interface *iface;
- iface = netdev_priv(dev);
if (hostap_set_word(dev, HFA384X_RID_PROMISCUOUSMODE,
local->is_promisc)) {
printk(KERN_INFO "%s: %sabling promiscuous mode failed\n",
diff --git a/drivers/net/wireless/hostap/hostap_wlan.h b/drivers/net/wireless/hostap/hostap_wlan.h
index 1ba33be98b2..1c66b3c1030 100644
--- a/drivers/net/wireless/hostap/hostap_wlan.h
+++ b/drivers/net/wireless/hostap/hostap_wlan.h
@@ -31,14 +31,14 @@ struct linux_wlan_ng_val {
u32 did;
u16 status, len;
u32 data;
-} __attribute__ ((packed));
+} __packed;
struct linux_wlan_ng_prism_hdr {
u32 msgcode, msglen;
char devname[16];
struct linux_wlan_ng_val hosttime, mactime, channel, rssi, sq, signal,
noise, rate, istx, frmlen;
-} __attribute__ ((packed));
+} __packed;
struct linux_wlan_ng_cap_hdr {
__be32 version;
@@ -55,7 +55,7 @@ struct linux_wlan_ng_cap_hdr {
__be32 ssi_noise;
__be32 preamble;
__be32 encoding;
-} __attribute__ ((packed));
+} __packed;
struct hostap_radiotap_rx {
struct ieee80211_radiotap_header hdr;
@@ -66,7 +66,7 @@ struct hostap_radiotap_rx {
__le16 chan_flags;
s8 dbm_antsignal;
s8 dbm_antnoise;
-} __attribute__ ((packed));
+} __packed;
#define LWNG_CAP_DID_BASE (4 | (1 << 6)) /* section 4, group 1 */
#define LWNG_CAPHDR_VERSION 0x80211001
@@ -97,7 +97,7 @@ struct hfa384x_rx_frame {
__be16 len;
/* followed by frame data; max 2304 bytes */
-} __attribute__ ((packed));
+} __packed;
struct hfa384x_tx_frame {
@@ -126,14 +126,14 @@ struct hfa384x_tx_frame {
__be16 len;
/* followed by frame data; max 2304 bytes */
-} __attribute__ ((packed));
+} __packed;
struct hfa384x_rid_hdr
{
__le16 len;
__le16 rid;
-} __attribute__ ((packed));
+} __packed;
/* Macro for converting signal levels (range 27 .. 154) to wireless ext
@@ -145,24 +145,24 @@ struct hfa384x_rid_hdr
struct hfa384x_scan_request {
__le16 channel_list;
__le16 txrate; /* HFA384X_RATES_* */
-} __attribute__ ((packed));
+} __packed;
struct hfa384x_hostscan_request {
__le16 channel_list;
__le16 txrate;
__le16 target_ssid_len;
u8 target_ssid[32];
-} __attribute__ ((packed));
+} __packed;
struct hfa384x_join_request {
u8 bssid[6];
__le16 channel;
-} __attribute__ ((packed));
+} __packed;
struct hfa384x_info_frame {
__le16 len;
__le16 type;
-} __attribute__ ((packed));
+} __packed;
struct hfa384x_comm_tallies {
__le16 tx_unicast_frames;
@@ -186,7 +186,7 @@ struct hfa384x_comm_tallies {
__le16 rx_discards_wep_undecryptable;
__le16 rx_message_in_msg_fragments;
__le16 rx_message_in_bad_msg_fragments;
-} __attribute__ ((packed));
+} __packed;
struct hfa384x_comm_tallies32 {
__le32 tx_unicast_frames;
@@ -210,7 +210,7 @@ struct hfa384x_comm_tallies32 {
__le32 rx_discards_wep_undecryptable;
__le32 rx_message_in_msg_fragments;
__le32 rx_message_in_bad_msg_fragments;
-} __attribute__ ((packed));
+} __packed;
struct hfa384x_scan_result_hdr {
__le16 reserved;
@@ -219,7 +219,7 @@ struct hfa384x_scan_result_hdr {
#define HFA384X_SCAN_HOST_INITIATED 1
#define HFA384X_SCAN_FIRMWARE_INITIATED 2
#define HFA384X_SCAN_INQUIRY_FROM_HOST 3
-} __attribute__ ((packed));
+} __packed;
#define HFA384X_SCAN_MAX_RESULTS 32
@@ -234,7 +234,7 @@ struct hfa384x_scan_result {
u8 ssid[32];
u8 sup_rates[10];
__le16 rate;
-} __attribute__ ((packed));
+} __packed;
struct hfa384x_hostscan_result {
__le16 chid;
@@ -248,7 +248,7 @@ struct hfa384x_hostscan_result {
u8 sup_rates[10];
__le16 rate;
__le16 atim;
-} __attribute__ ((packed));
+} __packed;
struct comm_tallies_sums {
unsigned int tx_unicast_frames;
diff --git a/drivers/net/wireless/ipw2x00/ipw2100.c b/drivers/net/wireless/ipw2x00/ipw2100.c
index 0bd4dfa59a8..c24c5efeae1 100644
--- a/drivers/net/wireless/ipw2x00/ipw2100.c
+++ b/drivers/net/wireless/ipw2x00/ipw2100.c
@@ -174,7 +174,7 @@ that only one external action is invoked at a time.
#define DRV_DESCRIPTION "Intel(R) PRO/Wireless 2100 Network Driver"
#define DRV_COPYRIGHT "Copyright(c) 2003-2006 Intel Corporation"
-struct pm_qos_request_list *ipw2100_pm_qos_req;
+static struct pm_qos_request_list ipw2100_pm_qos_req;
/* Debugging stuff */
#ifdef CONFIG_IPW2100_DEBUG
@@ -1741,7 +1741,7 @@ static int ipw2100_up(struct ipw2100_priv *priv, int deferred)
/* the ipw2100 hardware really doesn't want power management delays
* longer than 175usec
*/
- pm_qos_update_request(ipw2100_pm_qos_req, 175);
+ pm_qos_update_request(&ipw2100_pm_qos_req, 175);
/* If the interrupt is enabled, turn it off... */
spin_lock_irqsave(&priv->low_lock, flags);
@@ -1889,7 +1889,7 @@ static void ipw2100_down(struct ipw2100_priv *priv)
ipw2100_disable_interrupts(priv);
spin_unlock_irqrestore(&priv->low_lock, flags);
- pm_qos_update_request(ipw2100_pm_qos_req, PM_QOS_DEFAULT_VALUE);
+ pm_qos_update_request(&ipw2100_pm_qos_req, PM_QOS_DEFAULT_VALUE);
/* We have to signal any supplicant if we are disassociating */
if (associated)
@@ -3467,10 +3467,8 @@ static int ipw2100_msg_allocate(struct ipw2100_priv *priv)
dma_addr_t p;
priv->msg_buffers =
- (struct ipw2100_tx_packet *)kmalloc(IPW_COMMAND_POOL_SIZE *
- sizeof(struct
- ipw2100_tx_packet),
- GFP_KERNEL);
+ kmalloc(IPW_COMMAND_POOL_SIZE * sizeof(struct ipw2100_tx_packet),
+ GFP_KERNEL);
if (!priv->msg_buffers) {
printk(KERN_ERR DRV_NAME ": %s: PCI alloc failed for msg "
"buffers.\n", priv->net_dev->name);
@@ -4499,10 +4497,8 @@ static int ipw2100_tx_allocate(struct ipw2100_priv *priv)
}
priv->tx_buffers =
- (struct ipw2100_tx_packet *)kmalloc(TX_PENDED_QUEUE_LENGTH *
- sizeof(struct
- ipw2100_tx_packet),
- GFP_ATOMIC);
+ kmalloc(TX_PENDED_QUEUE_LENGTH * sizeof(struct ipw2100_tx_packet),
+ GFP_ATOMIC);
if (!priv->tx_buffers) {
printk(KERN_ERR DRV_NAME
": %s: alloc failed form tx buffers.\n",
@@ -4651,9 +4647,9 @@ static int ipw2100_rx_allocate(struct ipw2100_priv *priv)
/*
* allocate packets
*/
- priv->rx_buffers = (struct ipw2100_rx_packet *)
- kmalloc(RX_QUEUE_LENGTH * sizeof(struct ipw2100_rx_packet),
- GFP_KERNEL);
+ priv->rx_buffers = kmalloc(RX_QUEUE_LENGTH *
+ sizeof(struct ipw2100_rx_packet),
+ GFP_KERNEL);
if (!priv->rx_buffers) {
IPW_DEBUG_INFO("can't allocate rx packet buffer table\n");
@@ -5233,7 +5229,7 @@ struct security_info_params {
u8 auth_mode;
u8 replay_counters_number;
u8 unicast_using_group;
-} __attribute__ ((packed));
+} __packed;
static int ipw2100_set_security_information(struct ipw2100_priv *priv,
int auth_mode,
@@ -6669,8 +6665,8 @@ static int __init ipw2100_init(void)
if (ret)
goto out;
- ipw2100_pm_qos_req = pm_qos_add_request(PM_QOS_CPU_DMA_LATENCY,
- PM_QOS_DEFAULT_VALUE);
+ pm_qos_add_request(&ipw2100_pm_qos_req, PM_QOS_CPU_DMA_LATENCY,
+ PM_QOS_DEFAULT_VALUE);
#ifdef CONFIG_IPW2100_DEBUG
ipw2100_debug_level = debug;
ret = driver_create_file(&ipw2100_pci_driver.driver,
@@ -6692,7 +6688,7 @@ static void __exit ipw2100_exit(void)
&driver_attr_debug_level);
#endif
pci_unregister_driver(&ipw2100_pci_driver);
- pm_qos_remove_request(ipw2100_pm_qos_req);
+ pm_qos_remove_request(&ipw2100_pm_qos_req);
}
module_init(ipw2100_init);
@@ -8475,7 +8471,7 @@ struct ipw2100_fw_header {
short mode;
unsigned int fw_size;
unsigned int uc_size;
-} __attribute__ ((packed));
+} __packed;
static int ipw2100_mod_firmware_load(struct ipw2100_fw *fw)
{
diff --git a/drivers/net/wireless/ipw2x00/ipw2100.h b/drivers/net/wireless/ipw2x00/ipw2100.h
index 1eab0d698f4..838002b4881 100644
--- a/drivers/net/wireless/ipw2x00/ipw2100.h
+++ b/drivers/net/wireless/ipw2x00/ipw2100.h
@@ -164,7 +164,7 @@ struct bd_status {
} fields;
u8 field;
} info;
-} __attribute__ ((packed));
+} __packed;
struct ipw2100_bd {
u32 host_addr;
@@ -174,7 +174,7 @@ struct ipw2100_bd {
* 1st TBD) */
u8 num_fragments;
u8 reserved[6];
-} __attribute__ ((packed));
+} __packed;
#define IPW_BD_QUEUE_LENGTH(n) (1<<n)
#define IPW_BD_ALIGNMENT(L) (L*sizeof(struct ipw2100_bd))
@@ -232,7 +232,7 @@ struct ipw2100_status {
#define IPW_STATUS_FLAG_WEP_ENCRYPTED (1<<1)
#define IPW_STATUS_FLAG_CRC_ERROR (1<<2)
u8 rssi;
-} __attribute__ ((packed));
+} __packed;
struct ipw2100_status_queue {
/* driver (virtual) pointer to queue */
@@ -293,7 +293,7 @@ struct ipw2100_cmd_header {
u32 reserved1[3];
u32 *ordinal1_ptr;
u32 *ordinal2_ptr;
-} __attribute__ ((packed));
+} __packed;
struct ipw2100_data_header {
u32 host_command_reg;
@@ -307,7 +307,7 @@ struct ipw2100_data_header {
u8 src_addr[ETH_ALEN];
u8 dst_addr[ETH_ALEN];
u16 fragment_size;
-} __attribute__ ((packed));
+} __packed;
/* Host command data structure */
struct host_command {
@@ -316,7 +316,7 @@ struct host_command {
u32 host_command_sequence; // UNIQUE COMMAND NUMBER (ID)
u32 host_command_length; // LENGTH
u32 host_command_parameters[HOST_COMMAND_PARAMS_REG_LEN]; // COMMAND PARAMETERS
-} __attribute__ ((packed));
+} __packed;
typedef enum {
POWER_ON_RESET,
@@ -382,7 +382,7 @@ struct ipw2100_notification {
u32 hnhdr_size; /* size in bytes of data
or number of entries, if table.
Does NOT include header */
-} __attribute__ ((packed));
+} __packed;
#define MAX_KEY_SIZE 16
#define MAX_KEYS 8
@@ -814,7 +814,7 @@ struct ipw2100_rx {
struct ipw2100_notification notification;
struct ipw2100_cmd_header command;
} rx_data;
-} __attribute__ ((packed));
+} __packed;
/* Bit 0-7 are for 802.11b tx rates - . Bit 5-7 are reserved */
#define TX_RATE_1_MBIT 0x0001
diff --git a/drivers/net/wireless/ipw2x00/ipw2200.c b/drivers/net/wireless/ipw2x00/ipw2200.c
index 3aa3bb18f61..cb2552a6777 100644
--- a/drivers/net/wireless/ipw2x00/ipw2200.c
+++ b/drivers/net/wireless/ipw2x00/ipw2200.c
@@ -96,7 +96,7 @@ static int network_mode = 0;
static u32 ipw_debug_level;
static int associate;
static int auto_create = 1;
-static int led_support = 0;
+static int led_support = 1;
static int disable = 0;
static int bt_coexist = 0;
static int hwcrypto = 0;
@@ -6624,13 +6624,12 @@ static int ipw_wx_set_genie(struct net_device *dev,
return -EINVAL;
if (wrqu->data.length) {
- buf = kmalloc(wrqu->data.length, GFP_KERNEL);
+ buf = kmemdup(extra, wrqu->data.length, GFP_KERNEL);
if (buf == NULL) {
err = -ENOMEM;
goto out;
}
- memcpy(buf, extra, wrqu->data.length);
kfree(ieee->wpa_ie);
ieee->wpa_ie = buf;
ieee->wpa_ie_len = wrqu->data.length;
@@ -12083,7 +12082,7 @@ module_param(auto_create, int, 0444);
MODULE_PARM_DESC(auto_create, "auto create adhoc network (default on)");
module_param_named(led, led_support, int, 0444);
-MODULE_PARM_DESC(led, "enable led control on some systems (default 0 off)");
+MODULE_PARM_DESC(led, "enable led control on some systems (default 1 on)");
module_param(debug, int, 0444);
MODULE_PARM_DESC(debug, "debug output mask");
diff --git a/drivers/net/wireless/ipw2x00/ipw2200.h b/drivers/net/wireless/ipw2x00/ipw2200.h
index bf0eeb2e873..d7d049c7a4f 100644
--- a/drivers/net/wireless/ipw2x00/ipw2200.h
+++ b/drivers/net/wireless/ipw2x00/ipw2200.h
@@ -388,7 +388,7 @@ struct clx2_queue {
dma_addr_t dma_addr; /**< physical addr for BD's */
int low_mark; /**< low watermark, resume queue if free space more than this */
int high_mark; /**< high watermark, stop queue if free space less than this */
-} __attribute__ ((packed)); /* XXX */
+} __packed; /* XXX */
struct machdr32 {
__le16 frame_ctl;
@@ -399,7 +399,7 @@ struct machdr32 {
__le16 seq_ctrl; // more endians!
u8 addr4[MACADRR_BYTE_LEN];
__le16 qos_ctrl;
-} __attribute__ ((packed));
+} __packed;
struct machdr30 {
__le16 frame_ctl;
@@ -409,7 +409,7 @@ struct machdr30 {
u8 addr3[MACADRR_BYTE_LEN];
__le16 seq_ctrl; // more endians!
u8 addr4[MACADRR_BYTE_LEN];
-} __attribute__ ((packed));
+} __packed;
struct machdr26 {
__le16 frame_ctl;
@@ -419,7 +419,7 @@ struct machdr26 {
u8 addr3[MACADRR_BYTE_LEN];
__le16 seq_ctrl; // more endians!
__le16 qos_ctrl;
-} __attribute__ ((packed));
+} __packed;
struct machdr24 {
__le16 frame_ctl;
@@ -428,20 +428,20 @@ struct machdr24 {
u8 addr2[MACADRR_BYTE_LEN];
u8 addr3[MACADRR_BYTE_LEN];
__le16 seq_ctrl; // more endians!
-} __attribute__ ((packed));
+} __packed;
// TX TFD with 32 byte MAC Header
struct tx_tfd_32 {
struct machdr32 mchdr; // 32
__le32 uivplaceholder[2]; // 8
-} __attribute__ ((packed));
+} __packed;
// TX TFD with 30 byte MAC Header
struct tx_tfd_30 {
struct machdr30 mchdr; // 30
u8 reserved[2]; // 2
__le32 uivplaceholder[2]; // 8
-} __attribute__ ((packed));
+} __packed;
// tx tfd with 26 byte mac header
struct tx_tfd_26 {
@@ -449,14 +449,14 @@ struct tx_tfd_26 {
u8 reserved1[2]; // 2
__le32 uivplaceholder[2]; // 8
u8 reserved2[4]; // 4
-} __attribute__ ((packed));
+} __packed;
// tx tfd with 24 byte mac header
struct tx_tfd_24 {
struct machdr24 mchdr; // 24
__le32 uivplaceholder[2]; // 8
u8 reserved[8]; // 8
-} __attribute__ ((packed));
+} __packed;
#define DCT_WEP_KEY_FIELD_LENGTH 16
@@ -465,7 +465,7 @@ struct tfd_command {
u8 length;
__le16 reserved;
u8 payload[0];
-} __attribute__ ((packed));
+} __packed;
struct tfd_data {
/* Header */
@@ -504,14 +504,14 @@ struct tfd_data {
__le32 num_chunks;
__le32 chunk_ptr[NUM_TFD_CHUNKS];
__le16 chunk_len[NUM_TFD_CHUNKS];
-} __attribute__ ((packed));
+} __packed;
struct txrx_control_flags {
u8 message_type;
u8 rx_seq_num;
u8 control_bits;
u8 reserved;
-} __attribute__ ((packed));
+} __packed;
#define TFD_SIZE 128
#define TFD_CMD_IMMEDIATE_PAYLOAD_LENGTH (TFD_SIZE - sizeof(struct txrx_control_flags))
@@ -523,7 +523,7 @@ struct tfd_frame {
struct tfd_command cmd;
u8 raw[TFD_CMD_IMMEDIATE_PAYLOAD_LENGTH];
} u;
-} __attribute__ ((packed));
+} __packed;
typedef void destructor_func(const void *);
@@ -559,7 +559,7 @@ struct rate_histogram {
__le32 b[SUP_RATE_11B_MAX_NUM_CHANNELS];
__le32 g[SUP_RATE_11G_MAX_NUM_CHANNELS];
} failed;
-} __attribute__ ((packed));
+} __packed;
/* statistics command response */
struct ipw_cmd_stats {
@@ -586,13 +586,13 @@ struct ipw_cmd_stats {
__le16 rx_autodetec_no_ofdm;
__le16 rx_autodetec_no_barker;
__le16 reserved;
-} __attribute__ ((packed));
+} __packed;
struct notif_channel_result {
u8 channel_num;
struct ipw_cmd_stats stats;
u8 uReserved;
-} __attribute__ ((packed));
+} __packed;
#define SCAN_COMPLETED_STATUS_COMPLETE 1
#define SCAN_COMPLETED_STATUS_ABORTED 2
@@ -602,24 +602,24 @@ struct notif_scan_complete {
u8 num_channels;
u8 status;
u8 reserved;
-} __attribute__ ((packed));
+} __packed;
struct notif_frag_length {
__le16 frag_length;
__le16 reserved;
-} __attribute__ ((packed));
+} __packed;
struct notif_beacon_state {
__le32 state;
__le32 number;
-} __attribute__ ((packed));
+} __packed;
struct notif_tgi_tx_key {
u8 key_state;
u8 security_type;
u8 station_index;
u8 reserved;
-} __attribute__ ((packed));
+} __packed;
#define SILENCE_OVER_THRESH (1)
#define SILENCE_UNDER_THRESH (2)
@@ -631,25 +631,25 @@ struct notif_link_deterioration {
struct rate_histogram histogram;
u8 silence_notification_type; /* SILENCE_OVER/UNDER_THRESH */
__le16 silence_count;
-} __attribute__ ((packed));
+} __packed;
struct notif_association {
u8 state;
-} __attribute__ ((packed));
+} __packed;
struct notif_authenticate {
u8 state;
struct machdr24 addr;
__le16 status;
-} __attribute__ ((packed));
+} __packed;
struct notif_calibration {
u8 data[104];
-} __attribute__ ((packed));
+} __packed;
struct notif_noise {
__le32 value;
-} __attribute__ ((packed));
+} __packed;
struct ipw_rx_notification {
u8 reserved[8];
@@ -669,7 +669,7 @@ struct ipw_rx_notification {
struct notif_noise noise;
u8 raw[0];
} u;
-} __attribute__ ((packed));
+} __packed;
struct ipw_rx_frame {
__le32 reserved1;
@@ -692,14 +692,14 @@ struct ipw_rx_frame {
u8 rtscts_seen; // 0x1 RTS seen ; 0x2 CTS seen
__le16 length;
u8 data[0];
-} __attribute__ ((packed));
+} __packed;
struct ipw_rx_header {
u8 message_type;
u8 rx_seq_num;
u8 control_bits;
u8 reserved;
-} __attribute__ ((packed));
+} __packed;
struct ipw_rx_packet {
struct ipw_rx_header header;
@@ -707,7 +707,7 @@ struct ipw_rx_packet {
struct ipw_rx_frame frame;
struct ipw_rx_notification notification;
} u;
-} __attribute__ ((packed));
+} __packed;
#define IPW_RX_NOTIFICATION_SIZE sizeof(struct ipw_rx_header) + 12
#define IPW_RX_FRAME_SIZE (unsigned int)(sizeof(struct ipw_rx_header) + \
@@ -717,7 +717,7 @@ struct ipw_rx_mem_buffer {
dma_addr_t dma_addr;
struct sk_buff *skb;
struct list_head list;
-}; /* Not transferred over network, so not __attribute__ ((packed)) */
+}; /* Not transferred over network, so not __packed */
struct ipw_rx_queue {
struct ipw_rx_mem_buffer pool[RX_QUEUE_SIZE + RX_FREE_BUFFERS];
@@ -730,7 +730,7 @@ struct ipw_rx_queue {
struct list_head rx_free; /* Own an SKBs */
struct list_head rx_used; /* No SKB allocated */
spinlock_t lock;
-}; /* Not transferred over network, so not __attribute__ ((packed)) */
+}; /* Not transferred over network, so not __packed */
struct alive_command_responce {
u8 alive_command;
@@ -745,21 +745,21 @@ struct alive_command_responce {
__le16 reserved4;
u8 time_stamp[5]; /* month, day, year, hours, minutes */
u8 ucode_valid;
-} __attribute__ ((packed));
+} __packed;
#define IPW_MAX_RATES 12
struct ipw_rates {
u8 num_rates;
u8 rates[IPW_MAX_RATES];
-} __attribute__ ((packed));
+} __packed;
struct command_block {
unsigned int control;
u32 source_addr;
u32 dest_addr;
unsigned int status;
-} __attribute__ ((packed));
+} __packed;
#define CB_NUMBER_OF_ELEMENTS_SMALL 64
struct fw_image_desc {
@@ -792,7 +792,7 @@ struct ipw_sys_config {
u8 accept_all_mgmt_frames;
u8 pass_noise_stats_to_host;
u8 reserved3;
-} __attribute__ ((packed));
+} __packed;
struct ipw_multicast_addr {
u8 num_of_multicast_addresses;
@@ -801,7 +801,7 @@ struct ipw_multicast_addr {
u8 mac2[6];
u8 mac3[6];
u8 mac4[6];
-} __attribute__ ((packed));
+} __packed;
#define DCW_WEP_KEY_INDEX_MASK 0x03 /* bits [0:1] */
#define DCW_WEP_KEY_SEC_TYPE_MASK 0x30 /* bits [4:5] */
@@ -822,7 +822,7 @@ struct ipw_wep_key {
u8 key_index;
u8 key_size;
u8 key[16];
-} __attribute__ ((packed));
+} __packed;
struct ipw_tgi_tx_key {
u8 key_id;
@@ -831,7 +831,7 @@ struct ipw_tgi_tx_key {
u8 flags;
u8 key[16];
__le32 tx_counter[2];
-} __attribute__ ((packed));
+} __packed;
#define IPW_SCAN_CHANNELS 54
@@ -840,7 +840,7 @@ struct ipw_scan_request {
__le16 dwell_time;
u8 channels_list[IPW_SCAN_CHANNELS];
u8 channels_reserved[3];
-} __attribute__ ((packed));
+} __packed;
enum {
IPW_SCAN_PASSIVE_TILL_FIRST_BEACON_SCAN = 0,
@@ -857,7 +857,7 @@ struct ipw_scan_request_ext {
u8 scan_type[IPW_SCAN_CHANNELS / 2];
u8 reserved;
__le16 dwell_time[IPW_SCAN_TYPES];
-} __attribute__ ((packed));
+} __packed;
static inline u8 ipw_get_scan_type(struct ipw_scan_request_ext *scan, u8 index)
{
@@ -902,7 +902,7 @@ struct ipw_associate {
u8 smr;
u8 reserved1;
__le16 reserved2;
-} __attribute__ ((packed));
+} __packed;
struct ipw_supported_rates {
u8 ieee_mode;
@@ -910,36 +910,36 @@ struct ipw_supported_rates {
u8 purpose;
u8 reserved;
u8 supported_rates[IPW_MAX_RATES];
-} __attribute__ ((packed));
+} __packed;
struct ipw_rts_threshold {
__le16 rts_threshold;
__le16 reserved;
-} __attribute__ ((packed));
+} __packed;
struct ipw_frag_threshold {
__le16 frag_threshold;
__le16 reserved;
-} __attribute__ ((packed));
+} __packed;
struct ipw_retry_limit {
u8 short_retry_limit;
u8 long_retry_limit;
__le16 reserved;
-} __attribute__ ((packed));
+} __packed;
struct ipw_dino_config {
__le32 dino_config_addr;
__le16 dino_config_size;
u8 dino_response;
u8 reserved;
-} __attribute__ ((packed));
+} __packed;
struct ipw_aironet_info {
u8 id;
u8 length;
__le16 reserved;
-} __attribute__ ((packed));
+} __packed;
struct ipw_rx_key {
u8 station_index;
@@ -950,25 +950,25 @@ struct ipw_rx_key {
u8 station_address[6];
u8 key_index;
u8 reserved;
-} __attribute__ ((packed));
+} __packed;
struct ipw_country_channel_info {
u8 first_channel;
u8 no_channels;
s8 max_tx_power;
-} __attribute__ ((packed));
+} __packed;
struct ipw_country_info {
u8 id;
u8 length;
u8 country_str[3];
struct ipw_country_channel_info groups[7];
-} __attribute__ ((packed));
+} __packed;
struct ipw_channel_tx_power {
u8 channel_number;
s8 tx_power;
-} __attribute__ ((packed));
+} __packed;
#define SCAN_ASSOCIATED_INTERVAL (HZ)
#define SCAN_INTERVAL (HZ / 10)
@@ -979,18 +979,18 @@ struct ipw_tx_power {
u8 num_channels;
u8 ieee_mode;
struct ipw_channel_tx_power channels_tx_power[MAX_A_CHANNELS];
-} __attribute__ ((packed));
+} __packed;
struct ipw_rsn_capabilities {
u8 id;
u8 length;
__le16 version;
-} __attribute__ ((packed));
+} __packed;
struct ipw_sensitivity_calib {
__le16 beacon_rssi_raw;
__le16 reserved;
-} __attribute__ ((packed));
+} __packed;
/**
* Host command structure.
@@ -1019,7 +1019,7 @@ struct ipw_cmd { /* XXX */
* nParams=(len+3)/4+status_len
*/
u32 param[0];
-} __attribute__ ((packed));
+} __packed;
#define STATUS_HCMD_ACTIVE (1<<0) /**< host command in progress */
@@ -1114,7 +1114,7 @@ struct ipw_event { /* XXX */
u32 event;
u32 time;
u32 data;
-} __attribute__ ((packed));
+} __packed;
struct ipw_fw_error { /* XXX */
unsigned long jiffies;
@@ -1125,7 +1125,7 @@ struct ipw_fw_error { /* XXX */
struct ipw_error_elem *elem;
struct ipw_event *log;
u8 payload[0];
-} __attribute__ ((packed));
+} __packed;
#ifdef CONFIG_IPW2200_PROMISCUOUS
@@ -1170,7 +1170,7 @@ struct ipw_rt_hdr {
s8 rt_dbmnoise;
u8 rt_antenna; /* antenna number */
u8 payload[0]; /* payload... */
-} __attribute__ ((packed));
+} __packed;
#endif
struct ipw_priv {
@@ -1957,7 +1957,7 @@ enum {
struct ipw_fixed_rate {
__le16 tx_rates;
__le16 reserved;
-} __attribute__ ((packed));
+} __packed;
#define IPW_INDIRECT_ADDR_MASK (~0x3ul)
@@ -1966,14 +1966,14 @@ struct host_cmd {
u8 len;
u16 reserved;
u32 *param;
-} __attribute__ ((packed)); /* XXX */
+} __packed; /* XXX */
struct cmdlog_host_cmd {
u8 cmd;
u8 len;
__le16 reserved;
char param[124];
-} __attribute__ ((packed));
+} __packed;
struct ipw_cmd_log {
unsigned long jiffies;
diff --git a/drivers/net/wireless/ipw2x00/libipw.h b/drivers/net/wireless/ipw2x00/libipw.h
index 284b0e4cb81..70f5586d96b 100644
--- a/drivers/net/wireless/ipw2x00/libipw.h
+++ b/drivers/net/wireless/ipw2x00/libipw.h
@@ -154,7 +154,7 @@ struct libipw_snap_hdr {
u8 ctrl; /* always 0x03 */
u8 oui[P80211_OUI_LEN]; /* organizational universal id */
-} __attribute__ ((packed));
+} __packed;
#define SNAP_SIZE sizeof(struct libipw_snap_hdr)
@@ -323,7 +323,7 @@ struct libipw_security {
u8 keys[WEP_KEYS][SCM_KEY_LEN];
u8 level;
u16 flags;
-} __attribute__ ((packed));
+} __packed;
/*
@@ -347,7 +347,7 @@ struct libipw_hdr_1addr {
__le16 duration_id;
u8 addr1[ETH_ALEN];
u8 payload[0];
-} __attribute__ ((packed));
+} __packed;
struct libipw_hdr_2addr {
__le16 frame_ctl;
@@ -355,7 +355,7 @@ struct libipw_hdr_2addr {
u8 addr1[ETH_ALEN];
u8 addr2[ETH_ALEN];
u8 payload[0];
-} __attribute__ ((packed));
+} __packed;
struct libipw_hdr_3addr {
__le16 frame_ctl;
@@ -365,7 +365,7 @@ struct libipw_hdr_3addr {
u8 addr3[ETH_ALEN];
__le16 seq_ctl;
u8 payload[0];
-} __attribute__ ((packed));
+} __packed;
struct libipw_hdr_4addr {
__le16 frame_ctl;
@@ -376,7 +376,7 @@ struct libipw_hdr_4addr {
__le16 seq_ctl;
u8 addr4[ETH_ALEN];
u8 payload[0];
-} __attribute__ ((packed));
+} __packed;
struct libipw_hdr_3addrqos {
__le16 frame_ctl;
@@ -387,13 +387,13 @@ struct libipw_hdr_3addrqos {
__le16 seq_ctl;
u8 payload[0];
__le16 qos_ctl;
-} __attribute__ ((packed));
+} __packed;
struct libipw_info_element {
u8 id;
u8 len;
u8 data[0];
-} __attribute__ ((packed));
+} __packed;
/*
* These are the data types that can make up management packets
@@ -406,7 +406,7 @@ struct libipw_info_element {
u16 listen_interval;
struct {
u16 association_id:14, reserved:2;
- } __attribute__ ((packed));
+ } __packed;
u32 time_stamp[2];
u16 reason;
u16 status;
@@ -419,7 +419,7 @@ struct libipw_auth {
__le16 status;
/* challenge */
struct libipw_info_element info_element[0];
-} __attribute__ ((packed));
+} __packed;
struct libipw_channel_switch {
u8 id;
@@ -427,7 +427,7 @@ struct libipw_channel_switch {
u8 mode;
u8 channel;
u8 count;
-} __attribute__ ((packed));
+} __packed;
struct libipw_action {
struct libipw_hdr_3addr header;
@@ -441,12 +441,12 @@ struct libipw_action {
struct libipw_channel_switch channel_switch;
} format;
-} __attribute__ ((packed));
+} __packed;
struct libipw_disassoc {
struct libipw_hdr_3addr header;
__le16 reason;
-} __attribute__ ((packed));
+} __packed;
/* Alias deauth for disassoc */
#define libipw_deauth libipw_disassoc
@@ -455,7 +455,7 @@ struct libipw_probe_request {
struct libipw_hdr_3addr header;
/* SSID, supported rates */
struct libipw_info_element info_element[0];
-} __attribute__ ((packed));
+} __packed;
struct libipw_probe_response {
struct libipw_hdr_3addr header;
@@ -465,7 +465,7 @@ struct libipw_probe_response {
/* SSID, supported rates, FH params, DS params,
* CF params, IBSS params, TIM (if beacon), RSN */
struct libipw_info_element info_element[0];
-} __attribute__ ((packed));
+} __packed;
/* Alias beacon for probe_response */
#define libipw_beacon libipw_probe_response
@@ -476,7 +476,7 @@ struct libipw_assoc_request {
__le16 listen_interval;
/* SSID, supported rates, RSN */
struct libipw_info_element info_element[0];
-} __attribute__ ((packed));
+} __packed;
struct libipw_reassoc_request {
struct libipw_hdr_3addr header;
@@ -484,7 +484,7 @@ struct libipw_reassoc_request {
__le16 listen_interval;
u8 current_ap[ETH_ALEN];
struct libipw_info_element info_element[0];
-} __attribute__ ((packed));
+} __packed;
struct libipw_assoc_response {
struct libipw_hdr_3addr header;
@@ -493,7 +493,7 @@ struct libipw_assoc_response {
__le16 aid;
/* supported rates */
struct libipw_info_element info_element[0];
-} __attribute__ ((packed));
+} __packed;
struct libipw_txb {
u8 nr_frags;
@@ -555,19 +555,19 @@ struct libipw_qos_information_element {
u8 qui_subtype;
u8 version;
u8 ac_info;
-} __attribute__ ((packed));
+} __packed;
struct libipw_qos_ac_parameter {
u8 aci_aifsn;
u8 ecw_min_max;
__le16 tx_op_limit;
-} __attribute__ ((packed));
+} __packed;
struct libipw_qos_parameter_info {
struct libipw_qos_information_element info_element;
u8 reserved;
struct libipw_qos_ac_parameter ac_params_record[QOS_QUEUE_NUM];
-} __attribute__ ((packed));
+} __packed;
struct libipw_qos_parameters {
__le16 cw_min[QOS_QUEUE_NUM];
@@ -575,7 +575,7 @@ struct libipw_qos_parameters {
u8 aifs[QOS_QUEUE_NUM];
u8 flag[QOS_QUEUE_NUM];
__le16 tx_op_limit[QOS_QUEUE_NUM];
-} __attribute__ ((packed));
+} __packed;
struct libipw_qos_data {
struct libipw_qos_parameters parameters;
@@ -588,7 +588,7 @@ struct libipw_qos_data {
struct libipw_tim_parameters {
u8 tim_count;
u8 tim_period;
-} __attribute__ ((packed));
+} __packed;
/*******************************************************/
@@ -606,7 +606,7 @@ struct libipw_basic_report {
__le64 start_time;
__le16 duration;
u8 map;
-} __attribute__ ((packed));
+} __packed;
enum { /* libipw_measurement_request.mode */
/* Bit 0 is reserved */
@@ -627,7 +627,7 @@ struct libipw_measurement_params {
u8 channel;
__le64 start_time;
__le16 duration;
-} __attribute__ ((packed));
+} __packed;
struct libipw_measurement_request {
struct libipw_info_element ie;
@@ -635,7 +635,7 @@ struct libipw_measurement_request {
u8 mode;
u8 type;
struct libipw_measurement_params params[0];
-} __attribute__ ((packed));
+} __packed;
struct libipw_measurement_report {
struct libipw_info_element ie;
@@ -645,17 +645,17 @@ struct libipw_measurement_report {
union {
struct libipw_basic_report basic[0];
} u;
-} __attribute__ ((packed));
+} __packed;
struct libipw_tpc_report {
u8 transmit_power;
u8 link_margin;
-} __attribute__ ((packed));
+} __packed;
struct libipw_channel_map {
u8 channel;
u8 map;
-} __attribute__ ((packed));
+} __packed;
struct libipw_ibss_dfs {
struct libipw_info_element ie;
@@ -668,14 +668,14 @@ struct libipw_csa {
u8 mode;
u8 channel;
u8 count;
-} __attribute__ ((packed));
+} __packed;
struct libipw_quiet {
u8 count;
u8 period;
u8 duration;
u8 offset;
-} __attribute__ ((packed));
+} __packed;
struct libipw_network {
/* These entries are used to identify a unique network */
@@ -828,7 +828,6 @@ struct libipw_device {
int host_strip_iv_icv;
int host_open_frag;
- int host_build_iv;
int ieee802_1x; /* is IEEE 802.1X used */
/* WPA data */
diff --git a/drivers/net/wireless/ipw2x00/libipw_module.c b/drivers/net/wireless/ipw2x00/libipw_module.c
index 55965408ff3..32dee2ce5d3 100644
--- a/drivers/net/wireless/ipw2x00/libipw_module.c
+++ b/drivers/net/wireless/ipw2x00/libipw_module.c
@@ -62,8 +62,8 @@ MODULE_DESCRIPTION(DRV_DESCRIPTION);
MODULE_AUTHOR(DRV_COPYRIGHT);
MODULE_LICENSE("GPL");
-struct cfg80211_ops libipw_config_ops = { };
-void *libipw_wiphy_privid = &libipw_wiphy_privid;
+static struct cfg80211_ops libipw_config_ops = { };
+static void *libipw_wiphy_privid = &libipw_wiphy_privid;
static int libipw_networks_allocate(struct libipw_device *ieee)
{
diff --git a/drivers/net/wireless/ipw2x00/libipw_tx.c b/drivers/net/wireless/ipw2x00/libipw_tx.c
index da8beac7fcf..01c88a71abe 100644
--- a/drivers/net/wireless/ipw2x00/libipw_tx.c
+++ b/drivers/net/wireless/ipw2x00/libipw_tx.c
@@ -260,7 +260,7 @@ netdev_tx_t libipw_xmit(struct sk_buff *skb, struct net_device *dev)
int i, bytes_per_frag, nr_frags, bytes_last_frag, frag_size,
rts_required;
unsigned long flags;
- int encrypt, host_encrypt, host_encrypt_msdu, host_build_iv;
+ int encrypt, host_encrypt, host_encrypt_msdu;
__be16 ether_type;
int bytes, fc, hdr_len;
struct sk_buff *skb_frag;
@@ -301,7 +301,6 @@ netdev_tx_t libipw_xmit(struct sk_buff *skb, struct net_device *dev)
host_encrypt = ieee->host_encrypt && encrypt && crypt;
host_encrypt_msdu = ieee->host_encrypt_msdu && encrypt && crypt;
- host_build_iv = ieee->host_build_iv && encrypt && crypt;
if (!encrypt && ieee->ieee802_1x &&
ieee->drop_unencrypted && ether_type != htons(ETH_P_PAE)) {
@@ -313,7 +312,7 @@ netdev_tx_t libipw_xmit(struct sk_buff *skb, struct net_device *dev)
skb_copy_from_linear_data(skb, dest, ETH_ALEN);
skb_copy_from_linear_data_offset(skb, ETH_ALEN, src, ETH_ALEN);
- if (host_encrypt || host_build_iv)
+ if (host_encrypt)
fc = IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA |
IEEE80211_FCTL_PROTECTED;
else
@@ -467,7 +466,7 @@ netdev_tx_t libipw_xmit(struct sk_buff *skb, struct net_device *dev)
for (; i < nr_frags; i++) {
skb_frag = txb->fragments[i];
- if (host_encrypt || host_build_iv)
+ if (host_encrypt)
skb_reserve(skb_frag,
crypt->ops->extra_mpdu_prefix_len);
@@ -502,15 +501,6 @@ netdev_tx_t libipw_xmit(struct sk_buff *skb, struct net_device *dev)
* to insert the IV between the header and the payload */
if (host_encrypt)
libipw_encrypt_fragment(ieee, skb_frag, hdr_len);
- else if (host_build_iv) {
- atomic_inc(&crypt->refcnt);
- if (crypt->ops->build_iv)
- crypt->ops->build_iv(skb_frag, hdr_len,
- ieee->sec.keys[ieee->sec.active_key],
- ieee->sec.key_sizes[ieee->sec.active_key],
- crypt->priv);
- atomic_dec(&crypt->refcnt);
- }
if (ieee->config &
(CFG_LIBIPW_COMPUTE_FCS | CFG_LIBIPW_RESERVE_FCS))
diff --git a/drivers/net/wireless/ipw2x00/libipw_wx.c b/drivers/net/wireless/ipw2x00/libipw_wx.c
index 3633c6682e4..d7bd6cf00a8 100644
--- a/drivers/net/wireless/ipw2x00/libipw_wx.c
+++ b/drivers/net/wireless/ipw2x00/libipw_wx.c
@@ -320,7 +320,7 @@ int libipw_wx_set_encode(struct libipw_device *ieee,
};
int i, key, key_provided, len;
struct lib80211_crypt_data **crypt;
- int host_crypto = ieee->host_encrypt || ieee->host_decrypt || ieee->host_build_iv;
+ int host_crypto = ieee->host_encrypt || ieee->host_decrypt;
DECLARE_SSID_BUF(ssid);
LIBIPW_DEBUG_WX("SET_ENCODE\n");
@@ -411,10 +411,6 @@ int libipw_wx_set_encode(struct libipw_device *ieee,
/* If a new key was provided, set it up */
if (erq->length > 0) {
-#ifdef CONFIG_LIBIPW_DEBUG
- DECLARE_SSID_BUF(ssid);
-#endif
-
len = erq->length <= 5 ? 5 : 13;
memcpy(sec.keys[key], keybuf, erq->length);
if (len > erq->length)
diff --git a/drivers/net/wireless/iwlwifi/Kconfig b/drivers/net/wireless/iwlwifi/Kconfig
index dc8ed152766..a51e4da1bdf 100644
--- a/drivers/net/wireless/iwlwifi/Kconfig
+++ b/drivers/net/wireless/iwlwifi/Kconfig
@@ -30,9 +30,11 @@ config IWLWIFI_DEBUG
config IWLWIFI_DEBUGFS
bool "iwlagn debugfs support"
- depends on IWLWIFI && IWLWIFI_DEBUG && MAC80211_DEBUGFS
+ depends on IWLWIFI && MAC80211_DEBUGFS
---help---
- Enable creation of debugfs files for the iwlwifi drivers.
+ Enable creation of debugfs files for the iwlwifi drivers. This
+ is a low-impact option that allows getting insight into the
+ driver's state at runtime.
config IWLWIFI_DEVICE_TRACING
bool "iwlwifi device access tracing"
@@ -85,10 +87,15 @@ config IWL4965
This option enables support for Intel Wireless WiFi Link 4965AGN
config IWL5000
- bool "Intel Wireless WiFi 5000AGN; Intel WiFi Link 1000, 6000, and 6050 Series"
+ bool "Intel Wireless-N/Advanced-N/Ultimate-N WiFi Link"
depends on IWLAGN
---help---
- This option enables support for Intel Wireless WiFi Link 5000AGN Family
+ This option enables support for use with the following hardware:
+ Intel Wireless WiFi Link 6250AGN Adapter
+ Intel 6000 Series Wi-Fi Adapters (6200AGN and 6300AGN)
+ Intel WiFi Link 1000BGN
+ Intel Wireless WiFi 5150AGN
+ Intel Wireless WiFi 5100AGN, 5300AGN, and 5350AGN
config IWL3945
tristate "Intel PRO/Wireless 3945ABG/BG Network Connection (iwl3945)"
diff --git a/drivers/net/wireless/iwlwifi/Makefile b/drivers/net/wireless/iwlwifi/Makefile
index 7c723538551..728bb858ba9 100644
--- a/drivers/net/wireless/iwlwifi/Makefile
+++ b/drivers/net/wireless/iwlwifi/Makefile
@@ -1,6 +1,6 @@
obj-$(CONFIG_IWLWIFI) += iwlcore.o
iwlcore-objs := iwl-core.o iwl-eeprom.o iwl-hcmd.o iwl-power.o
-iwlcore-objs += iwl-rx.o iwl-tx.o iwl-sta.o iwl-calib.o
+iwlcore-objs += iwl-rx.o iwl-tx.o iwl-sta.o
iwlcore-objs += iwl-scan.o iwl-led.o
iwlcore-$(CONFIG_IWLWIFI_DEBUGFS) += iwl-debugfs.o
iwlcore-$(CONFIG_IWLWIFI_DEVICE_TRACING) += iwl-devtrace.o
@@ -11,7 +11,7 @@ CFLAGS_iwl-devtrace.o := -I$(src)
obj-$(CONFIG_IWLAGN) += iwlagn.o
iwlagn-objs := iwl-agn.o iwl-agn-rs.o iwl-agn-led.o iwl-agn-ict.o
iwlagn-objs += iwl-agn-ucode.o iwl-agn-hcmd.o iwl-agn-tx.o
-iwlagn-objs += iwl-agn-lib.o
+iwlagn-objs += iwl-agn-lib.o iwl-agn-rx.o iwl-agn-calib.o
iwlagn-$(CONFIG_IWLWIFI_DEBUGFS) += iwl-agn-debugfs.o
iwlagn-$(CONFIG_IWL4965) += iwl-4965.o
diff --git a/drivers/net/wireless/iwlwifi/iwl-1000.c b/drivers/net/wireless/iwlwifi/iwl-1000.c
index 6be2992f8f2..8848333bc3a 100644
--- a/drivers/net/wireless/iwlwifi/iwl-1000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-1000.c
@@ -129,8 +129,8 @@ static int iwl1000_hw_set_hw_params(struct iwl_priv *priv)
priv->cfg->num_of_queues *
sizeof(struct iwlagn_scd_bc_tbl);
priv->hw_params.tfd_size = sizeof(struct iwl_tfd);
- priv->hw_params.max_stations = IWL5000_STATION_COUNT;
- priv->hw_params.bcast_sta_id = IWL5000_BROADCAST_ID;
+ priv->hw_params.max_stations = IWLAGN_STATION_COUNT;
+ priv->hw_params.bcast_sta_id = IWLAGN_BROADCAST_ID;
priv->hw_params.max_data_size = IWLAGN_RTC_DATA_SIZE;
priv->hw_params.max_inst_size = IWLAGN_RTC_INST_SIZE;
@@ -157,6 +157,10 @@ static int iwl1000_hw_set_hw_params(struct iwl_priv *priv)
BIT(IWL_CALIB_TX_IQ) |
BIT(IWL_CALIB_TX_IQ_PERD) |
BIT(IWL_CALIB_BASE_BAND);
+ if (priv->cfg->need_dc_calib)
+ priv->hw_params.calib_init_cfg |= BIT(IWL_CALIB_DC);
+
+ priv->hw_params.beacon_time_tsf_bits = IWLAGN_EXT_BEACON_TIME_POS;
return 0;
}
@@ -213,14 +217,18 @@ static struct iwl_lib_ops iwl1000_lib = {
.set_ct_kill = iwl1000_set_ct_threshold,
},
.manage_ibss_station = iwlagn_manage_ibss_station,
+ .update_bcast_station = iwl_update_bcast_station,
.debugfs_ops = {
.rx_stats_read = iwl_ucode_rx_stats_read,
.tx_stats_read = iwl_ucode_tx_stats_read,
.general_stats_read = iwl_ucode_general_stats_read,
+ .bt_stats_read = iwl_ucode_bt_stats_read,
},
.recover_from_tx_stall = iwl_bg_monitor_recover,
.check_plcp_health = iwl_good_plcp_health,
.check_ack_health = iwl_good_ack_health,
+ .txfifo_flush = iwlagn_txfifo_flush,
+ .dev_txfifo_flush = iwlagn_dev_txfifo_flush,
};
static const struct iwl_ops iwl1000_ops = {
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-3945-debugfs.c
index 6a9c64a50e3..ef0835b01b6 100644
--- a/drivers/net/wireless/iwlwifi/iwl-3945-debugfs.c
+++ b/drivers/net/wireless/iwlwifi/iwl-3945-debugfs.c
@@ -28,6 +28,28 @@
#include "iwl-3945-debugfs.h"
+
+static int iwl3945_statistics_flag(struct iwl_priv *priv, char *buf, int bufsz)
+{
+ int p = 0;
+
+ p += scnprintf(buf + p, bufsz - p, "Statistics Flag(0x%X):\n",
+ le32_to_cpu(priv->_3945.statistics.flag));
+ if (le32_to_cpu(priv->_3945.statistics.flag) &
+ UCODE_STATISTICS_CLEAR_MSK)
+ p += scnprintf(buf + p, bufsz - p,
+ "\tStatistics have been cleared\n");
+ p += scnprintf(buf + p, bufsz - p, "\tOperational Frequency: %s\n",
+ (le32_to_cpu(priv->_3945.statistics.flag) &
+ UCODE_STATISTICS_FREQUENCY_MSK)
+ ? "2.4 GHz" : "5.2 GHz");
+ p += scnprintf(buf + p, bufsz - p, "\tTGj Narrow Band: %s\n",
+ (le32_to_cpu(priv->_3945.statistics.flag) &
+ UCODE_STATISTICS_NARROW_BAND_MSK)
+ ? "enabled" : "disabled");
+ return p;
+}
+
ssize_t iwl3945_ucode_rx_stats_read(struct file *file,
char __user *user_buf,
size_t count, loff_t *ppos)
@@ -70,7 +92,7 @@ ssize_t iwl3945_ucode_rx_stats_read(struct file *file,
max_cck = &priv->_3945.max_delta.rx.cck;
max_general = &priv->_3945.max_delta.rx.general;
- pos += iwl_dbgfs_statistics_flag(priv, buf, bufsz);
+ pos += iwl3945_statistics_flag(priv, buf, bufsz);
pos += scnprintf(buf + pos, bufsz - pos, "%-32s current"
"acumulative delta max\n",
"Statistics_Rx - OFDM:");
@@ -331,7 +353,7 @@ ssize_t iwl3945_ucode_tx_stats_read(struct file *file,
accum_tx = &priv->_3945.accum_statistics.tx;
delta_tx = &priv->_3945.delta_statistics.tx;
max_tx = &priv->_3945.max_delta.tx;
- pos += iwl_dbgfs_statistics_flag(priv, buf, bufsz);
+ pos += iwl3945_statistics_flag(priv, buf, bufsz);
pos += scnprintf(buf + pos, bufsz - pos, "%-32s current"
"acumulative delta max\n",
"Statistics_Tx:");
@@ -438,7 +460,7 @@ ssize_t iwl3945_ucode_general_stats_read(struct file *file,
accum_div = &priv->_3945.accum_statistics.general.div;
delta_div = &priv->_3945.delta_statistics.general.div;
max_div = &priv->_3945.max_delta.general.div;
- pos += iwl_dbgfs_statistics_flag(priv, buf, bufsz);
+ pos += iwl3945_statistics_flag(priv, buf, bufsz);
pos += scnprintf(buf + pos, bufsz - pos, "%-32s current"
"acumulative delta max\n",
"Statistics_General:");
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-fh.h b/drivers/net/wireless/iwlwifi/iwl-3945-fh.h
index 042f6bc0df1..2c9ed2b502a 100644
--- a/drivers/net/wireless/iwlwifi/iwl-3945-fh.h
+++ b/drivers/net/wireless/iwlwifi/iwl-3945-fh.h
@@ -175,13 +175,13 @@
struct iwl3945_tfd_tb {
__le32 addr;
__le32 len;
-} __attribute__ ((packed));
+} __packed;
struct iwl3945_tfd {
__le32 control_flags;
struct iwl3945_tfd_tb tbs[4];
u8 __pad[28];
-} __attribute__ ((packed));
+} __packed;
#endif /* __iwl_3945_fh_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-hw.h b/drivers/net/wireless/iwlwifi/iwl-3945-hw.h
index 91bcb4e3cdf..7c731a79363 100644
--- a/drivers/net/wireless/iwlwifi/iwl-3945-hw.h
+++ b/drivers/net/wireless/iwlwifi/iwl-3945-hw.h
@@ -96,7 +96,7 @@ struct iwl3945_eeprom_txpower_sample {
u8 gain_index; /* index into power (gain) setup table ... */
s8 power; /* ... for this pwr level for this chnl group */
u16 v_det; /* PA output voltage */
-} __attribute__ ((packed));
+} __packed;
/*
* Mappings of Tx power levels -> nominal radio/DSP gain table indexes.
@@ -117,7 +117,7 @@ struct iwl3945_eeprom_txpower_group {
u8 group_channel; /* "representative" channel # in this band */
s16 temperature; /* h/w temperature at factory calib this band
* (signed) */
-} __attribute__ ((packed));
+} __packed;
/*
* Temperature-based Tx-power compensation data, not band-specific.
@@ -131,7 +131,7 @@ struct iwl3945_eeprom_temperature_corr {
u32 Tc;
u32 Td;
u32 Te;
-} __attribute__ ((packed));
+} __packed;
/*
* EEPROM map
@@ -215,7 +215,7 @@ struct iwl3945_eeprom {
/* abs.ofs: 512 */
struct iwl3945_eeprom_temperature_corr corrections; /* abs.ofs: 832 */
u8 reserved16[172]; /* fill out to full 1024 byte block */
-} __attribute__ ((packed));
+} __packed;
#define IWL3945_EEPROM_IMG_SIZE 1024
@@ -274,7 +274,7 @@ static inline int iwl3945_hw_valid_rtc_data_addr(u32 addr)
* and &iwl3945_shared.rx_read_ptr[0] is provided to FH_RCSR_RPTR_ADDR(0) */
struct iwl3945_shared {
__le32 tx_base_ptr[8];
-} __attribute__ ((packed));
+} __packed;
static inline u8 iwl3945_hw_get_rate(__le16 rate_n_flags)
{
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c
index c44a303e62e..a07310fefcf 100644
--- a/drivers/net/wireless/iwlwifi/iwl-3945.c
+++ b/drivers/net/wireless/iwlwifi/iwl-3945.c
@@ -279,8 +279,8 @@ static void iwl3945_tx_queue_reclaim(struct iwl_priv *priv,
q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd)) {
tx_info = &txq->txb[txq->q.read_ptr];
- ieee80211_tx_status_irqsafe(priv->hw, tx_info->skb[0]);
- tx_info->skb[0] = NULL;
+ ieee80211_tx_status_irqsafe(priv->hw, tx_info->skb);
+ tx_info->skb = NULL;
priv->cfg->ops->lib->txq_free_tfd(priv, txq);
}
@@ -315,7 +315,7 @@ static void iwl3945_rx_reply_tx(struct iwl_priv *priv,
return;
}
- info = IEEE80211_SKB_CB(txq->txb[txq->q.read_ptr].skb[0]);
+ info = IEEE80211_SKB_CB(txq->txb[txq->q.read_ptr].skb);
ieee80211_tx_info_clear_status(info);
/* Fill the MRR chain with some info about on-chip retransmissions */
@@ -352,7 +352,7 @@ static void iwl3945_rx_reply_tx(struct iwl_priv *priv,
* RX handler implementations
*
*****************************************************************************/
-#ifdef CONFIG_IWLWIFI_DEBUG
+#ifdef CONFIG_IWLWIFI_DEBUGFS
/*
* based on the assumption of all statistics counter are in DWORD
* FIXME: This function is for debugging, do not deal with
@@ -406,6 +406,11 @@ static bool iwl3945_good_plcp_health(struct iwl_priv *priv,
unsigned int plcp_msec;
unsigned long plcp_received_jiffies;
+ if (priv->cfg->plcp_delta_threshold ==
+ IWL_MAX_PLCP_ERR_THRESHOLD_DISABLE) {
+ IWL_DEBUG_RADIO(priv, "plcp_err check disabled\n");
+ return rc;
+ }
memcpy(&current_stat, pkt->u.raw, sizeof(struct
iwl3945_notif_statistics));
/*
@@ -460,7 +465,7 @@ void iwl3945_hw_rx_statistics(struct iwl_priv *priv,
IWL_DEBUG_RX(priv, "Statistics notification received (%d vs %d).\n",
(int)sizeof(struct iwl3945_notif_statistics),
le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK);
-#ifdef CONFIG_IWLWIFI_DEBUG
+#ifdef CONFIG_IWLWIFI_DEBUGFS
iwl3945_accumulative_statistics(priv, (__le32 *)&pkt->u.raw);
#endif
iwl_recover_from_statistics(priv, pkt);
@@ -475,7 +480,7 @@ void iwl3945_reply_statistics(struct iwl_priv *priv,
__le32 *flag = (__le32 *)&pkt->u.raw;
if (le32_to_cpu(*flag) & UCODE_STATISTICS_CLEAR_MSK) {
-#ifdef CONFIG_IWLWIFI_DEBUG
+#ifdef CONFIG_IWLWIFI_DEBUGFS
memset(&priv->_3945.accum_statistics, 0,
sizeof(struct iwl3945_notif_statistics));
memset(&priv->_3945.delta_statistics, 0,
@@ -494,158 +499,6 @@ void iwl3945_reply_statistics(struct iwl_priv *priv,
* Misc. internal state and helper functions
*
******************************************************************************/
-#ifdef CONFIG_IWLWIFI_DEBUG
-
-/**
- * iwl3945_report_frame - dump frame to syslog during debug sessions
- *
- * You may hack this function to show different aspects of received frames,
- * including selective frame dumps.
- * group100 parameter selects whether to show 1 out of 100 good frames.
- */
-static void _iwl3945_dbg_report_frame(struct iwl_priv *priv,
- struct iwl_rx_packet *pkt,
- struct ieee80211_hdr *header, int group100)
-{
- u32 to_us;
- u32 print_summary = 0;
- u32 print_dump = 0; /* set to 1 to dump all frames' contents */
- u32 hundred = 0;
- u32 dataframe = 0;
- __le16 fc;
- u16 seq_ctl;
- u16 channel;
- u16 phy_flags;
- u16 length;
- u16 status;
- u16 bcn_tmr;
- u32 tsf_low;
- u64 tsf;
- u8 rssi;
- u8 agc;
- u16 sig_avg;
- u16 noise_diff;
- struct iwl3945_rx_frame_stats *rx_stats = IWL_RX_STATS(pkt);
- struct iwl3945_rx_frame_hdr *rx_hdr = IWL_RX_HDR(pkt);
- struct iwl3945_rx_frame_end *rx_end = IWL_RX_END(pkt);
- u8 *data = IWL_RX_DATA(pkt);
-
- /* MAC header */
- fc = header->frame_control;
- seq_ctl = le16_to_cpu(header->seq_ctrl);
-
- /* metadata */
- channel = le16_to_cpu(rx_hdr->channel);
- phy_flags = le16_to_cpu(rx_hdr->phy_flags);
- length = le16_to_cpu(rx_hdr->len);
-
- /* end-of-frame status and timestamp */
- status = le32_to_cpu(rx_end->status);
- bcn_tmr = le32_to_cpu(rx_end->beacon_timestamp);
- tsf_low = le64_to_cpu(rx_end->timestamp) & 0x0ffffffff;
- tsf = le64_to_cpu(rx_end->timestamp);
-
- /* signal statistics */
- rssi = rx_stats->rssi;
- agc = rx_stats->agc;
- sig_avg = le16_to_cpu(rx_stats->sig_avg);
- noise_diff = le16_to_cpu(rx_stats->noise_diff);
-
- to_us = !compare_ether_addr(header->addr1, priv->mac_addr);
-
- /* if data frame is to us and all is good,
- * (optionally) print summary for only 1 out of every 100 */
- if (to_us && (fc & ~cpu_to_le16(IEEE80211_FCTL_PROTECTED)) ==
- cpu_to_le16(IEEE80211_FCTL_FROMDS | IEEE80211_FTYPE_DATA)) {
- dataframe = 1;
- if (!group100)
- print_summary = 1; /* print each frame */
- else if (priv->framecnt_to_us < 100) {
- priv->framecnt_to_us++;
- print_summary = 0;
- } else {
- priv->framecnt_to_us = 0;
- print_summary = 1;
- hundred = 1;
- }
- } else {
- /* print summary for all other frames */
- print_summary = 1;
- }
-
- if (print_summary) {
- char *title;
- int rate;
-
- if (hundred)
- title = "100Frames";
- else if (ieee80211_has_retry(fc))
- title = "Retry";
- else if (ieee80211_is_assoc_resp(fc))
- title = "AscRsp";
- else if (ieee80211_is_reassoc_resp(fc))
- title = "RasRsp";
- else if (ieee80211_is_probe_resp(fc)) {
- title = "PrbRsp";
- print_dump = 1; /* dump frame contents */
- } else if (ieee80211_is_beacon(fc)) {
- title = "Beacon";
- print_dump = 1; /* dump frame contents */
- } else if (ieee80211_is_atim(fc))
- title = "ATIM";
- else if (ieee80211_is_auth(fc))
- title = "Auth";
- else if (ieee80211_is_deauth(fc))
- title = "DeAuth";
- else if (ieee80211_is_disassoc(fc))
- title = "DisAssoc";
- else
- title = "Frame";
-
- rate = iwl3945_hwrate_to_plcp_idx(rx_hdr->rate);
- if (rate == -1)
- rate = 0;
- else
- rate = iwl3945_rates[rate].ieee / 2;
-
- /* print frame summary.
- * MAC addresses show just the last byte (for brevity),
- * but you can hack it to show more, if you'd like to. */
- if (dataframe)
- IWL_DEBUG_RX(priv, "%s: mhd=0x%04x, dst=0x%02x, "
- "len=%u, rssi=%d, chnl=%d, rate=%d,\n",
- title, le16_to_cpu(fc), header->addr1[5],
- length, rssi, channel, rate);
- else {
- /* src/dst addresses assume managed mode */
- IWL_DEBUG_RX(priv, "%s: 0x%04x, dst=0x%02x, "
- "src=0x%02x, rssi=%u, tim=%lu usec, "
- "phy=0x%02x, chnl=%d\n",
- title, le16_to_cpu(fc), header->addr1[5],
- header->addr3[5], rssi,
- tsf_low - priv->scan_start_tsf,
- phy_flags, channel);
- }
- }
- if (print_dump)
- iwl_print_hex_dump(priv, IWL_DL_RX, data, length);
-}
-
-static void iwl3945_dbg_report_frame(struct iwl_priv *priv,
- struct iwl_rx_packet *pkt,
- struct ieee80211_hdr *header, int group100)
-{
- if (iwl_get_debug_level(priv) & IWL_DL_RX)
- _iwl3945_dbg_report_frame(priv, pkt, header, group100);
-}
-
-#else
-static inline void iwl3945_dbg_report_frame(struct iwl_priv *priv,
- struct iwl_rx_packet *pkt,
- struct ieee80211_hdr *header, int group100)
-{
-}
-#endif
/* This is necessary only for a number of statistics, see the caller. */
static int iwl3945_is_network_packet(struct iwl_priv *priv,
@@ -777,8 +630,6 @@ static void iwl3945_rx_reply_rx(struct iwl_priv *priv,
rx_status.signal, rx_status.signal,
rx_status.rate_idx);
- /* Set "1" to report good data frames in groups of 100 */
- iwl3945_dbg_report_frame(priv, pkt, header, 1);
iwl_dbg_log_rx_data_frame(priv, le16_to_cpu(rx_hdr->len), header);
if (network_packet) {
@@ -850,25 +701,28 @@ void iwl3945_hw_txq_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq)
/* Unmap tx_cmd */
if (counter)
pci_unmap_single(dev,
- pci_unmap_addr(&txq->meta[index], mapping),
- pci_unmap_len(&txq->meta[index], len),
+ dma_unmap_addr(&txq->meta[index], mapping),
+ dma_unmap_len(&txq->meta[index], len),
PCI_DMA_TODEVICE);
/* unmap chunks if any */
- for (i = 1; i < counter; i++) {
+ for (i = 1; i < counter; i++)
pci_unmap_single(dev, le32_to_cpu(tfd->tbs[i].addr),
le32_to_cpu(tfd->tbs[i].len), PCI_DMA_TODEVICE);
- if (txq->txb[txq->q.read_ptr].skb[0]) {
- struct sk_buff *skb = txq->txb[txq->q.read_ptr].skb[0];
- if (txq->txb[txq->q.read_ptr].skb[0]) {
- /* Can be called from interrupt context */
- dev_kfree_skb_any(skb);
- txq->txb[txq->q.read_ptr].skb[0] = NULL;
- }
+
+ /* free SKB */
+ if (txq->txb) {
+ struct sk_buff *skb;
+
+ skb = txq->txb[txq->q.read_ptr].skb;
+
+ /* can be called from irqs-disabled context */
+ if (skb) {
+ dev_kfree_skb_any(skb);
+ txq->txb[txq->q.read_ptr].skb = NULL;
}
}
- return ;
}
/**
@@ -947,8 +801,7 @@ void iwl3945_hw_build_tx_cmd_rate(struct iwl_priv *priv,
tx_cmd->supp_rates[1], tx_cmd->supp_rates[0]);
}
-static u8 iwl3945_sync_sta(struct iwl_priv *priv, int sta_id,
- u16 tx_rate, u8 flags)
+static u8 iwl3945_sync_sta(struct iwl_priv *priv, int sta_id, u16 tx_rate)
{
unsigned long flags_spin;
struct iwl_station_entry *station;
@@ -962,10 +815,9 @@ static u8 iwl3945_sync_sta(struct iwl_priv *priv, int sta_id,
station->sta.sta.modify_mask = STA_MODIFY_TX_RATE_MSK;
station->sta.rate_n_flags = cpu_to_le16(tx_rate);
station->sta.mode = STA_CONTROL_MODIFY_MSK;
-
+ iwl_send_add_sta(priv, &station->sta, CMD_ASYNC);
spin_unlock_irqrestore(&priv->sta_lock, flags_spin);
- iwl_send_add_sta(priv, &station->sta, flags);
IWL_DEBUG_RATE(priv, "SCALE sync station %d to rate %d\n",
sta_id, tx_rate);
return sta_id;
@@ -997,7 +849,7 @@ static int iwl3945_set_pwr_src(struct iwl_priv *priv, enum iwl_pwr_src src)
static int iwl3945_rx_init(struct iwl_priv *priv, struct iwl_rx_queue *rxq)
{
- iwl_write_direct32(priv, FH39_RCSR_RBD_BASE(0), rxq->dma_addr);
+ iwl_write_direct32(priv, FH39_RCSR_RBD_BASE(0), rxq->bd_dma);
iwl_write_direct32(priv, FH39_RCSR_RPTR_ADDR(0), rxq->rb_stts_dma);
iwl_write_direct32(priv, FH39_RCSR_WPTR(0), 0);
iwl_write_direct32(priv, FH39_RCSR_CONFIG(0),
@@ -2473,8 +2325,7 @@ static int iwl3945_manage_ibss_station(struct iwl_priv *priv,
iwl3945_sync_sta(priv, vif_priv->ibss_bssid_sta_id,
(priv->band == IEEE80211_BAND_5GHZ) ?
- IWL_RATE_6M_PLCP : IWL_RATE_1M_PLCP,
- CMD_ASYNC);
+ IWL_RATE_6M_PLCP : IWL_RATE_1M_PLCP);
iwl3945_rate_scale_init(priv->hw, vif_priv->ibss_bssid_sta_id);
return 0;
@@ -2590,6 +2441,7 @@ int iwl3945_hw_set_hw_params(struct iwl_priv *priv)
priv->hw_params.rx_wrt_ptr_reg = FH39_RSCSR_CHNL0_WPTR;
priv->hw_params.max_beacon_itrvl = IWL39_MAX_UCODE_BEACON_INTERVAL;
+ priv->hw_params.beacon_time_tsf_bits = IWL3945_EXT_BEACON_TIME_POS;
return 0;
}
diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-hw.h b/drivers/net/wireless/iwlwifi/iwl-4965-hw.h
index cd4b61ae25b..9166794eda0 100644
--- a/drivers/net/wireless/iwlwifi/iwl-4965-hw.h
+++ b/drivers/net/wireless/iwlwifi/iwl-4965-hw.h
@@ -787,6 +787,6 @@ enum {
struct iwl4965_scd_bc_tbl {
__le16 tfd_offset[TFD_QUEUE_BC_SIZE];
u8 pad[1024 - (TFD_QUEUE_BC_SIZE) * sizeof(__le16)];
-} __attribute__ ((packed));
+} __packed;
#endif /* !__iwl_4965_hw_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c
index d3afddae8d9..d6531ad3906 100644
--- a/drivers/net/wireless/iwlwifi/iwl-4965.c
+++ b/drivers/net/wireless/iwlwifi/iwl-4965.c
@@ -346,9 +346,19 @@ static void iwl4965_chain_noise_reset(struct iwl_priv *priv)
{
struct iwl_chain_noise_data *data = &(priv->chain_noise_data);
- if ((data->state == IWL_CHAIN_NOISE_ALIVE) && iwl_is_associated(priv)) {
+ if ((data->state == IWL_CHAIN_NOISE_ALIVE) &&
+ iwl_is_associated(priv)) {
struct iwl_calib_diff_gain_cmd cmd;
+ /* clear data for chain noise calibration algorithm */
+ data->chain_noise_a = 0;
+ data->chain_noise_b = 0;
+ data->chain_noise_c = 0;
+ data->chain_signal_a = 0;
+ data->chain_signal_b = 0;
+ data->chain_signal_c = 0;
+ data->beacon_count = 0;
+
memset(&cmd, 0, sizeof(cmd));
cmd.hdr.op_code = IWL_PHY_CALIBRATE_DIFF_GAIN_CMD;
cmd.diff_gain_a = 0;
@@ -419,13 +429,6 @@ static void iwl4965_gain_computation(struct iwl_priv *priv,
/* Mark so we run this algo only once! */
data->state = IWL_CHAIN_NOISE_CALIBRATED;
}
- data->chain_noise_a = 0;
- data->chain_noise_b = 0;
- data->chain_noise_c = 0;
- data->chain_signal_a = 0;
- data->chain_signal_b = 0;
- data->chain_signal_c = 0;
- data->beacon_count = 0;
}
static void iwl4965_bg_txpower_work(struct work_struct *work)
@@ -669,6 +672,7 @@ static int iwl4965_hw_set_hw_params(struct iwl_priv *priv)
priv->cfg->ops->lib->temp_ops.set_ct_kill(priv);
priv->hw_params.sens = &iwl4965_sensitivity;
+ priv->hw_params.beacon_time_tsf_bits = IWLAGN_EXT_BEACON_TIME_POS;
return 0;
}
@@ -1441,7 +1445,8 @@ static int iwl4965_send_rxon_assoc(struct iwl_priv *priv)
return ret;
}
-static int iwl4965_hw_channel_switch(struct iwl_priv *priv, u16 channel)
+static int iwl4965_hw_channel_switch(struct iwl_priv *priv,
+ struct ieee80211_channel_switch *ch_switch)
{
int rc;
u8 band = 0;
@@ -1449,11 +1454,14 @@ static int iwl4965_hw_channel_switch(struct iwl_priv *priv, u16 channel)
u8 ctrl_chan_high = 0;
struct iwl4965_channel_switch_cmd cmd;
const struct iwl_channel_info *ch_info;
-
+ u32 switch_time_in_usec, ucode_switch_time;
+ u16 ch;
+ u32 tsf_low;
+ u8 switch_count;
+ u16 beacon_interval = le16_to_cpu(priv->rxon_timing.beacon_interval);
+ struct ieee80211_vif *vif = priv->vif;
band = priv->band == IEEE80211_BAND_2GHZ;
- ch_info = iwl_get_channel_info(priv, priv->band, channel);
-
is_ht40 = is_ht40_channel(priv->staging_rxon.flags);
if (is_ht40 &&
@@ -1462,26 +1470,56 @@ static int iwl4965_hw_channel_switch(struct iwl_priv *priv, u16 channel)
cmd.band = band;
cmd.expect_beacon = 0;
- cmd.channel = cpu_to_le16(channel);
+ ch = ieee80211_frequency_to_channel(ch_switch->channel->center_freq);
+ cmd.channel = cpu_to_le16(ch);
cmd.rxon_flags = priv->staging_rxon.flags;
cmd.rxon_filter_flags = priv->staging_rxon.filter_flags;
- cmd.switch_time = cpu_to_le32(priv->ucode_beacon_time);
+ switch_count = ch_switch->count;
+ tsf_low = ch_switch->timestamp & 0x0ffffffff;
+ /*
+ * calculate the ucode channel switch time
+ * adding TSF as one of the factor for when to switch
+ */
+ if ((priv->ucode_beacon_time > tsf_low) && beacon_interval) {
+ if (switch_count > ((priv->ucode_beacon_time - tsf_low) /
+ beacon_interval)) {
+ switch_count -= (priv->ucode_beacon_time -
+ tsf_low) / beacon_interval;
+ } else
+ switch_count = 0;
+ }
+ if (switch_count <= 1)
+ cmd.switch_time = cpu_to_le32(priv->ucode_beacon_time);
+ else {
+ switch_time_in_usec =
+ vif->bss_conf.beacon_int * switch_count * TIME_UNIT;
+ ucode_switch_time = iwl_usecs_to_beacons(priv,
+ switch_time_in_usec,
+ beacon_interval);
+ cmd.switch_time = iwl_add_beacon_time(priv,
+ priv->ucode_beacon_time,
+ ucode_switch_time,
+ beacon_interval);
+ }
+ IWL_DEBUG_11H(priv, "uCode time for the switch is 0x%x\n",
+ cmd.switch_time);
+ ch_info = iwl_get_channel_info(priv, priv->band, ch);
if (ch_info)
cmd.expect_beacon = is_channel_radar(ch_info);
else {
IWL_ERR(priv, "invalid channel switch from %u to %u\n",
- priv->active_rxon.channel, channel);
+ priv->active_rxon.channel, ch);
return -EFAULT;
}
- rc = iwl4965_fill_txpower_tbl(priv, band, channel, is_ht40,
+ rc = iwl4965_fill_txpower_tbl(priv, band, ch, is_ht40,
ctrl_chan_high, &cmd.tx_power);
if (rc) {
IWL_DEBUG_11H(priv, "error:%d fill txpower_tbl\n", rc);
return rc;
}
- priv->switch_rxon.channel = cpu_to_le16(channel);
+ priv->switch_rxon.channel = cmd.channel;
priv->switch_rxon.switch_in_progress = true;
return iwl_send_cmd_pdu(priv, REPLY_CHANNEL_SWITCH, sizeof(cmd), &cmd);
@@ -1542,7 +1580,8 @@ static int iwl4965_hw_get_temperature(struct iwl_priv *priv)
u32 R4;
if (test_bit(STATUS_TEMPERATURE, &priv->status) &&
- (priv->statistics.flag & STATISTICS_REPLY_FLG_HT40_MODE_MSK)) {
+ (priv->_agn.statistics.flag &
+ STATISTICS_REPLY_FLG_HT40_MODE_MSK)) {
IWL_DEBUG_TEMP(priv, "Running HT40 temperature calibration\n");
R1 = (s32)le32_to_cpu(priv->card_alive_init.therm_r1[1]);
R2 = (s32)le32_to_cpu(priv->card_alive_init.therm_r2[1]);
@@ -1566,8 +1605,8 @@ static int iwl4965_hw_get_temperature(struct iwl_priv *priv)
if (!test_bit(STATUS_TEMPERATURE, &priv->status))
vt = sign_extend(R4, 23);
else
- vt = sign_extend(
- le32_to_cpu(priv->statistics.general.temperature), 23);
+ vt = sign_extend(le32_to_cpu(priv->_agn.statistics.
+ general.common.temperature), 23);
IWL_DEBUG_TEMP(priv, "Calib values R[1-3]: %d %d %d R4: %d\n", R1, R2, R3, vt);
@@ -1747,6 +1786,7 @@ static int iwl4965_txq_agg_enable(struct iwl_priv *priv, int txq_id,
{
unsigned long flags;
u16 ra_tid;
+ int ret;
if ((IWL49_FIRST_AMPDU_QUEUE > txq_id) ||
(IWL49_FIRST_AMPDU_QUEUE + priv->cfg->num_of_ampdu_queues
@@ -1762,7 +1802,9 @@ static int iwl4965_txq_agg_enable(struct iwl_priv *priv, int txq_id,
ra_tid = BUILD_RAxTID(sta_id, tid);
/* Modify device's station table to Tx this TID */
- iwl_sta_tx_modify_enable_tid(priv, sta_id, tid);
+ ret = iwl_sta_tx_modify_enable_tid(priv, sta_id, tid);
+ if (ret)
+ return ret;
spin_lock_irqsave(&priv->lock, flags);
@@ -1870,7 +1912,7 @@ static int iwl4965_tx_status_reply_tx(struct iwl_priv *priv,
IWL_DEBUG_TX_REPLY(priv, "FrameCnt = %d, StartIdx=%d idx=%d\n",
agg->frame_count, agg->start_idx, idx);
- info = IEEE80211_SKB_CB(priv->txq[txq_id].txb[idx].skb[0]);
+ info = IEEE80211_SKB_CB(priv->txq[txq_id].txb[idx].skb);
info->status.rates[0].count = tx_resp->failure_frame + 1;
info->flags &= ~IEEE80211_TX_CTL_AMPDU;
info->flags |= iwl_tx_status_to_mac80211(status);
@@ -2026,6 +2068,7 @@ static void iwl4965_rx_reply_tx(struct iwl_priv *priv,
int sta_id;
int freed;
u8 *qc = NULL;
+ unsigned long flags;
if ((index >= txq->q.n_bd) || (iwl_queue_used(&txq->q, index) == 0)) {
IWL_ERR(priv, "Read index for DMA queue txq_id (%d) index %d "
@@ -2035,7 +2078,7 @@ static void iwl4965_rx_reply_tx(struct iwl_priv *priv,
return;
}
- info = IEEE80211_SKB_CB(txq->txb[txq->q.read_ptr].skb[0]);
+ info = IEEE80211_SKB_CB(txq->txb[txq->q.read_ptr].skb);
memset(&info->status, 0, sizeof(info->status));
hdr = iwl_tx_queue_get_hdr(priv, txq_id, index);
@@ -2050,10 +2093,10 @@ static void iwl4965_rx_reply_tx(struct iwl_priv *priv,
return;
}
+ spin_lock_irqsave(&priv->sta_lock, flags);
if (txq->sched_retry) {
const u32 scd_ssn = iwl4965_get_scd_ssn(tx_resp);
struct iwl_ht_agg *agg = NULL;
-
WARN_ON(!qc);
agg = &priv->stations[sta_id].tid[tid].agg;
@@ -2110,6 +2153,8 @@ static void iwl4965_rx_reply_tx(struct iwl_priv *priv,
iwlagn_txq_check_empty(priv, sta_id, tid, txq_id);
iwl_check_abort_status(priv, tx_resp->frame_count, status);
+
+ spin_unlock_irqrestore(&priv->sta_lock, flags);
}
static int iwl4965_calc_rssi(struct iwl_priv *priv,
@@ -2235,11 +2280,14 @@ static struct iwl_lib_ops iwl4965_lib = {
.set_ct_kill = iwl4965_set_ct_threshold,
},
.manage_ibss_station = iwlagn_manage_ibss_station,
+ .update_bcast_station = iwl_update_bcast_station,
.debugfs_ops = {
.rx_stats_read = iwl_ucode_rx_stats_read,
.tx_stats_read = iwl_ucode_tx_stats_read,
.general_stats_read = iwl_ucode_general_stats_read,
+ .bt_stats_read = iwl_ucode_bt_stats_read,
},
+ .recover_from_tx_stall = iwl_bg_monitor_recover,
.check_plcp_health = iwl_good_plcp_health,
};
@@ -2285,7 +2333,7 @@ struct iwl_cfg iwl4965_agn_cfg = {
* Force use of chains B and C for scan RX on 5 GHz band
* because the device has off-channel reception on chain A.
*/
- .scan_antennas[IEEE80211_BAND_5GHZ] = ANT_BC,
+ .scan_rx_antennas[IEEE80211_BAND_5GHZ] = ANT_BC,
};
/* Module firmware */
diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c
index a28af7eb67e..8093ce2804f 100644
--- a/drivers/net/wireless/iwlwifi/iwl-5000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-5000.c
@@ -179,8 +179,8 @@ static int iwl5000_hw_set_hw_params(struct iwl_priv *priv)
priv->cfg->num_of_queues *
sizeof(struct iwlagn_scd_bc_tbl);
priv->hw_params.tfd_size = sizeof(struct iwl_tfd);
- priv->hw_params.max_stations = IWL5000_STATION_COUNT;
- priv->hw_params.bcast_sta_id = IWL5000_BROADCAST_ID;
+ priv->hw_params.max_stations = IWLAGN_STATION_COUNT;
+ priv->hw_params.bcast_sta_id = IWLAGN_BROADCAST_ID;
priv->hw_params.max_data_size = IWLAGN_RTC_DATA_SIZE;
priv->hw_params.max_inst_size = IWLAGN_RTC_INST_SIZE;
@@ -208,6 +208,8 @@ static int iwl5000_hw_set_hw_params(struct iwl_priv *priv)
BIT(IWL_CALIB_TX_IQ_PERD) |
BIT(IWL_CALIB_BASE_BAND);
+ priv->hw_params.beacon_time_tsf_bits = IWLAGN_EXT_BEACON_TIME_POS;
+
return 0;
}
@@ -224,8 +226,8 @@ static int iwl5150_hw_set_hw_params(struct iwl_priv *priv)
priv->cfg->num_of_queues *
sizeof(struct iwlagn_scd_bc_tbl);
priv->hw_params.tfd_size = sizeof(struct iwl_tfd);
- priv->hw_params.max_stations = IWL5000_STATION_COUNT;
- priv->hw_params.bcast_sta_id = IWL5000_BROADCAST_ID;
+ priv->hw_params.max_stations = IWLAGN_STATION_COUNT;
+ priv->hw_params.bcast_sta_id = IWLAGN_BROADCAST_ID;
priv->hw_params.max_data_size = IWLAGN_RTC_DATA_SIZE;
priv->hw_params.max_inst_size = IWLAGN_RTC_INST_SIZE;
@@ -247,10 +249,13 @@ static int iwl5150_hw_set_hw_params(struct iwl_priv *priv)
/* Set initial calibration set */
priv->hw_params.sens = &iwl5150_sensitivity;
priv->hw_params.calib_init_cfg =
- BIT(IWL_CALIB_DC) |
BIT(IWL_CALIB_LO) |
BIT(IWL_CALIB_TX_IQ) |
BIT(IWL_CALIB_BASE_BAND);
+ if (priv->cfg->need_dc_calib)
+ priv->hw_params.calib_init_cfg |= BIT(IWL_CALIB_DC);
+
+ priv->hw_params.beacon_time_tsf_bits = IWLAGN_EXT_BEACON_TIME_POS;
return 0;
}
@@ -260,40 +265,76 @@ static void iwl5150_temperature(struct iwl_priv *priv)
u32 vt = 0;
s32 offset = iwl_temp_calib_to_offset(priv);
- vt = le32_to_cpu(priv->statistics.general.temperature);
+ vt = le32_to_cpu(priv->_agn.statistics.general.common.temperature);
vt = vt / IWL_5150_VOLTAGE_TO_TEMPERATURE_COEFF + offset;
/* now vt hold the temperature in Kelvin */
priv->temperature = KELVIN_TO_CELSIUS(vt);
iwl_tt_handler(priv);
}
-static int iwl5000_hw_channel_switch(struct iwl_priv *priv, u16 channel)
+static int iwl5000_hw_channel_switch(struct iwl_priv *priv,
+ struct ieee80211_channel_switch *ch_switch)
{
struct iwl5000_channel_switch_cmd cmd;
const struct iwl_channel_info *ch_info;
+ u32 switch_time_in_usec, ucode_switch_time;
+ u16 ch;
+ u32 tsf_low;
+ u8 switch_count;
+ u16 beacon_interval = le16_to_cpu(priv->rxon_timing.beacon_interval);
+ struct ieee80211_vif *vif = priv->vif;
struct iwl_host_cmd hcmd = {
.id = REPLY_CHANNEL_SWITCH,
.len = sizeof(cmd),
- .flags = CMD_SIZE_HUGE,
+ .flags = CMD_SYNC,
.data = &cmd,
};
- IWL_DEBUG_11H(priv, "channel switch from %d to %d\n",
- priv->active_rxon.channel, channel);
cmd.band = priv->band == IEEE80211_BAND_2GHZ;
- cmd.channel = cpu_to_le16(channel);
+ ch = ieee80211_frequency_to_channel(ch_switch->channel->center_freq);
+ IWL_DEBUG_11H(priv, "channel switch from %d to %d\n",
+ priv->active_rxon.channel, ch);
+ cmd.channel = cpu_to_le16(ch);
cmd.rxon_flags = priv->staging_rxon.flags;
cmd.rxon_filter_flags = priv->staging_rxon.filter_flags;
- cmd.switch_time = cpu_to_le32(priv->ucode_beacon_time);
- ch_info = iwl_get_channel_info(priv, priv->band, channel);
+ switch_count = ch_switch->count;
+ tsf_low = ch_switch->timestamp & 0x0ffffffff;
+ /*
+ * calculate the ucode channel switch time
+ * adding TSF as one of the factor for when to switch
+ */
+ if ((priv->ucode_beacon_time > tsf_low) && beacon_interval) {
+ if (switch_count > ((priv->ucode_beacon_time - tsf_low) /
+ beacon_interval)) {
+ switch_count -= (priv->ucode_beacon_time -
+ tsf_low) / beacon_interval;
+ } else
+ switch_count = 0;
+ }
+ if (switch_count <= 1)
+ cmd.switch_time = cpu_to_le32(priv->ucode_beacon_time);
+ else {
+ switch_time_in_usec =
+ vif->bss_conf.beacon_int * switch_count * TIME_UNIT;
+ ucode_switch_time = iwl_usecs_to_beacons(priv,
+ switch_time_in_usec,
+ beacon_interval);
+ cmd.switch_time = iwl_add_beacon_time(priv,
+ priv->ucode_beacon_time,
+ ucode_switch_time,
+ beacon_interval);
+ }
+ IWL_DEBUG_11H(priv, "uCode time for the switch is 0x%x\n",
+ cmd.switch_time);
+ ch_info = iwl_get_channel_info(priv, priv->band, ch);
if (ch_info)
cmd.expect_beacon = is_channel_radar(ch_info);
else {
IWL_ERR(priv, "invalid channel switch from %u to %u\n",
- priv->active_rxon.channel, channel);
+ priv->active_rxon.channel, ch);
return -EFAULT;
}
- priv->switch_rxon.channel = cpu_to_le16(channel);
+ priv->switch_rxon.channel = cmd.channel;
priv->switch_rxon.switch_in_progress = true;
return iwl_send_cmd_sync(priv, &hcmd);
@@ -352,14 +393,18 @@ static struct iwl_lib_ops iwl5000_lib = {
.set_ct_kill = iwl5000_set_ct_threshold,
},
.manage_ibss_station = iwlagn_manage_ibss_station,
+ .update_bcast_station = iwl_update_bcast_station,
.debugfs_ops = {
.rx_stats_read = iwl_ucode_rx_stats_read,
.tx_stats_read = iwl_ucode_tx_stats_read,
.general_stats_read = iwl_ucode_general_stats_read,
+ .bt_stats_read = iwl_ucode_bt_stats_read,
},
.recover_from_tx_stall = iwl_bg_monitor_recover,
.check_plcp_health = iwl_good_plcp_health,
.check_ack_health = iwl_good_ack_health,
+ .txfifo_flush = iwlagn_txfifo_flush,
+ .dev_txfifo_flush = iwlagn_dev_txfifo_flush,
};
static struct iwl_lib_ops iwl5150_lib = {
@@ -414,6 +459,7 @@ static struct iwl_lib_ops iwl5150_lib = {
.set_ct_kill = iwl5150_set_ct_threshold,
},
.manage_ibss_station = iwlagn_manage_ibss_station,
+ .update_bcast_station = iwl_update_bcast_station,
.debugfs_ops = {
.rx_stats_read = iwl_ucode_rx_stats_read,
.tx_stats_read = iwl_ucode_tx_stats_read,
@@ -422,6 +468,8 @@ static struct iwl_lib_ops iwl5150_lib = {
.recover_from_tx_stall = iwl_bg_monitor_recover,
.check_plcp_health = iwl_good_plcp_health,
.check_ack_health = iwl_good_ack_health,
+ .txfifo_flush = iwlagn_txfifo_flush,
+ .dev_txfifo_flush = iwlagn_dev_txfifo_flush,
};
static const struct iwl_ops iwl5000_ops = {
@@ -620,6 +668,7 @@ struct iwl_cfg iwl5150_agn_cfg = {
.ucode_tracing = true,
.sensitivity_calib_by_driver = true,
.chain_noise_calib_by_driver = true,
+ .need_dc_calib = true,
};
struct iwl_cfg iwl5150_abg_cfg = {
@@ -649,6 +698,7 @@ struct iwl_cfg iwl5150_abg_cfg = {
.ucode_tracing = true,
.sensitivity_calib_by_driver = true,
.chain_noise_calib_by_driver = true,
+ .need_dc_calib = true,
};
MODULE_FIRMWARE(IWL5000_MODULE_FIRMWARE(IWL5000_UCODE_API_MAX));
diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c
index 9fbf54cd3e1..58270529a0e 100644
--- a/drivers/net/wireless/iwlwifi/iwl-6000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-6000.c
@@ -71,6 +71,10 @@
#define _IWL6000G2A_MODULE_FIRMWARE(api) IWL6000G2A_FW_PRE #api ".ucode"
#define IWL6000G2A_MODULE_FIRMWARE(api) _IWL6000G2A_MODULE_FIRMWARE(api)
+#define IWL6000G2B_FW_PRE "iwlwifi-6000g2b-"
+#define _IWL6000G2B_MODULE_FIRMWARE(api) IWL6000G2B_FW_PRE #api ".ucode"
+#define IWL6000G2B_MODULE_FIRMWARE(api) _IWL6000G2B_MODULE_FIRMWARE(api)
+
static void iwl6000_set_ct_threshold(struct iwl_priv *priv)
{
@@ -80,9 +84,10 @@ static void iwl6000_set_ct_threshold(struct iwl_priv *priv)
}
/* Indicate calibration version to uCode. */
-static void iwl6050_set_calib_version(struct iwl_priv *priv)
+static void iwl6000_set_calib_version(struct iwl_priv *priv)
{
- if (priv->cfg->ops->lib->eeprom_ops.calib_version(priv) >= 6)
+ if (priv->cfg->need_dc_calib &&
+ (priv->cfg->ops->lib->eeprom_ops.calib_version(priv) >= 6))
iwl_set_bit(priv, CSR_GP_DRIVER_REG,
CSR_GP_DRIVER_REG_BIT_CALIB_VERSION6);
}
@@ -155,8 +160,8 @@ static int iwl6000_hw_set_hw_params(struct iwl_priv *priv)
priv->cfg->num_of_queues *
sizeof(struct iwlagn_scd_bc_tbl);
priv->hw_params.tfd_size = sizeof(struct iwl_tfd);
- priv->hw_params.max_stations = IWL5000_STATION_COUNT;
- priv->hw_params.bcast_sta_id = IWL5000_BROADCAST_ID;
+ priv->hw_params.max_stations = IWLAGN_STATION_COUNT;
+ priv->hw_params.bcast_sta_id = IWLAGN_BROADCAST_ID;
priv->hw_params.max_data_size = IWL60_RTC_DATA_SIZE;
priv->hw_params.max_inst_size = IWL60_RTC_INST_SIZE;
@@ -182,83 +187,77 @@ static int iwl6000_hw_set_hw_params(struct iwl_priv *priv)
BIT(IWL_CALIB_LO) |
BIT(IWL_CALIB_TX_IQ) |
BIT(IWL_CALIB_BASE_BAND);
+ if (priv->cfg->need_dc_calib)
+ priv->hw_params.calib_init_cfg |= BIT(IWL_CALIB_DC);
- return 0;
-}
-
-static int iwl6050_hw_set_hw_params(struct iwl_priv *priv)
-{
- if (priv->cfg->mod_params->num_of_queues >= IWL_MIN_NUM_QUEUES &&
- priv->cfg->mod_params->num_of_queues <= IWLAGN_NUM_QUEUES)
- priv->cfg->num_of_queues =
- priv->cfg->mod_params->num_of_queues;
-
- priv->hw_params.max_txq_num = priv->cfg->num_of_queues;
- priv->hw_params.dma_chnl_num = FH50_TCSR_CHNL_NUM;
- priv->hw_params.scd_bc_tbls_size =
- priv->cfg->num_of_queues *
- sizeof(struct iwlagn_scd_bc_tbl);
- priv->hw_params.tfd_size = sizeof(struct iwl_tfd);
- priv->hw_params.max_stations = IWL5000_STATION_COUNT;
- priv->hw_params.bcast_sta_id = IWL5000_BROADCAST_ID;
-
- priv->hw_params.max_data_size = IWL60_RTC_DATA_SIZE;
- priv->hw_params.max_inst_size = IWL60_RTC_INST_SIZE;
-
- priv->hw_params.max_bsm_size = 0;
- priv->hw_params.ht40_channel = BIT(IEEE80211_BAND_2GHZ) |
- BIT(IEEE80211_BAND_5GHZ);
- priv->hw_params.rx_wrt_ptr_reg = FH_RSCSR_CHNL0_WPTR;
-
- priv->hw_params.tx_chains_num = num_of_ant(priv->cfg->valid_tx_ant);
- priv->hw_params.rx_chains_num = num_of_ant(priv->cfg->valid_rx_ant);
- priv->hw_params.valid_tx_ant = priv->cfg->valid_tx_ant;
- priv->hw_params.valid_rx_ant = priv->cfg->valid_rx_ant;
-
- if (priv->cfg->ops->lib->temp_ops.set_ct_kill)
- priv->cfg->ops->lib->temp_ops.set_ct_kill(priv);
-
- /* Set initial sensitivity parameters */
- /* Set initial calibration set */
- priv->hw_params.sens = &iwl6000_sensitivity;
- priv->hw_params.calib_init_cfg =
- BIT(IWL_CALIB_XTAL) |
- BIT(IWL_CALIB_DC) |
- BIT(IWL_CALIB_LO) |
- BIT(IWL_CALIB_TX_IQ) |
- BIT(IWL_CALIB_BASE_BAND);
+ priv->hw_params.beacon_time_tsf_bits = IWLAGN_EXT_BEACON_TIME_POS;
return 0;
}
-static int iwl6000_hw_channel_switch(struct iwl_priv *priv, u16 channel)
+static int iwl6000_hw_channel_switch(struct iwl_priv *priv,
+ struct ieee80211_channel_switch *ch_switch)
{
struct iwl6000_channel_switch_cmd cmd;
const struct iwl_channel_info *ch_info;
+ u32 switch_time_in_usec, ucode_switch_time;
+ u16 ch;
+ u32 tsf_low;
+ u8 switch_count;
+ u16 beacon_interval = le16_to_cpu(priv->rxon_timing.beacon_interval);
+ struct ieee80211_vif *vif = priv->vif;
struct iwl_host_cmd hcmd = {
.id = REPLY_CHANNEL_SWITCH,
.len = sizeof(cmd),
- .flags = CMD_SIZE_HUGE,
+ .flags = CMD_SYNC,
.data = &cmd,
};
- IWL_DEBUG_11H(priv, "channel switch from %d to %d\n",
- priv->active_rxon.channel, channel);
-
cmd.band = priv->band == IEEE80211_BAND_2GHZ;
- cmd.channel = cpu_to_le16(channel);
+ ch = ieee80211_frequency_to_channel(ch_switch->channel->center_freq);
+ IWL_DEBUG_11H(priv, "channel switch from %u to %u\n",
+ priv->active_rxon.channel, ch);
+ cmd.channel = cpu_to_le16(ch);
cmd.rxon_flags = priv->staging_rxon.flags;
cmd.rxon_filter_flags = priv->staging_rxon.filter_flags;
- cmd.switch_time = cpu_to_le32(priv->ucode_beacon_time);
- ch_info = iwl_get_channel_info(priv, priv->band, channel);
+ switch_count = ch_switch->count;
+ tsf_low = ch_switch->timestamp & 0x0ffffffff;
+ /*
+ * calculate the ucode channel switch time
+ * adding TSF as one of the factor for when to switch
+ */
+ if ((priv->ucode_beacon_time > tsf_low) && beacon_interval) {
+ if (switch_count > ((priv->ucode_beacon_time - tsf_low) /
+ beacon_interval)) {
+ switch_count -= (priv->ucode_beacon_time -
+ tsf_low) / beacon_interval;
+ } else
+ switch_count = 0;
+ }
+ if (switch_count <= 1)
+ cmd.switch_time = cpu_to_le32(priv->ucode_beacon_time);
+ else {
+ switch_time_in_usec =
+ vif->bss_conf.beacon_int * switch_count * TIME_UNIT;
+ ucode_switch_time = iwl_usecs_to_beacons(priv,
+ switch_time_in_usec,
+ beacon_interval);
+ cmd.switch_time = iwl_add_beacon_time(priv,
+ priv->ucode_beacon_time,
+ ucode_switch_time,
+ beacon_interval);
+ }
+ IWL_DEBUG_11H(priv, "uCode time for the switch is 0x%x\n",
+ cmd.switch_time);
+ ch_info = iwl_get_channel_info(priv, priv->band, ch);
if (ch_info)
cmd.expect_beacon = is_channel_radar(ch_info);
else {
IWL_ERR(priv, "invalid channel switch from %u to %u\n",
- priv->active_rxon.channel, channel);
+ priv->active_rxon.channel, ch);
return -EFAULT;
}
- priv->switch_rxon.channel = cpu_to_le16(channel);
+ priv->switch_rxon.channel = cmd.channel;
priv->switch_rxon.switch_in_progress = true;
return iwl_send_cmd_sync(priv, &hcmd);
@@ -316,16 +315,21 @@ static struct iwl_lib_ops iwl6000_lib = {
.temp_ops = {
.temperature = iwlagn_temperature,
.set_ct_kill = iwl6000_set_ct_threshold,
+ .set_calib_version = iwl6000_set_calib_version,
},
.manage_ibss_station = iwlagn_manage_ibss_station,
+ .update_bcast_station = iwl_update_bcast_station,
.debugfs_ops = {
.rx_stats_read = iwl_ucode_rx_stats_read,
.tx_stats_read = iwl_ucode_tx_stats_read,
.general_stats_read = iwl_ucode_general_stats_read,
+ .bt_stats_read = iwl_ucode_bt_stats_read,
},
.recover_from_tx_stall = iwl_bg_monitor_recover,
.check_plcp_health = iwl_good_plcp_health,
.check_ack_health = iwl_good_ack_health,
+ .txfifo_flush = iwlagn_txfifo_flush,
+ .dev_txfifo_flush = iwlagn_dev_txfifo_flush,
};
static const struct iwl_ops iwl6000_ops = {
@@ -335,79 +339,25 @@ static const struct iwl_ops iwl6000_ops = {
.led = &iwlagn_led_ops,
};
-static struct iwl_lib_ops iwl6050_lib = {
- .set_hw_params = iwl6050_hw_set_hw_params,
- .txq_update_byte_cnt_tbl = iwlagn_txq_update_byte_cnt_tbl,
- .txq_inval_byte_cnt_tbl = iwlagn_txq_inval_byte_cnt_tbl,
- .txq_set_sched = iwlagn_txq_set_sched,
- .txq_agg_enable = iwlagn_txq_agg_enable,
- .txq_agg_disable = iwlagn_txq_agg_disable,
- .txq_attach_buf_to_tfd = iwl_hw_txq_attach_buf_to_tfd,
- .txq_free_tfd = iwl_hw_txq_free_tfd,
- .txq_init = iwl_hw_tx_queue_init,
- .rx_handler_setup = iwlagn_rx_handler_setup,
- .setup_deferred_work = iwlagn_setup_deferred_work,
- .is_valid_rtc_data_addr = iwlagn_hw_valid_rtc_data_addr,
- .load_ucode = iwlagn_load_ucode,
- .dump_nic_event_log = iwl_dump_nic_event_log,
- .dump_nic_error_log = iwl_dump_nic_error_log,
- .dump_csr = iwl_dump_csr,
- .dump_fh = iwl_dump_fh,
- .init_alive_start = iwlagn_init_alive_start,
- .alive_notify = iwlagn_alive_notify,
- .send_tx_power = iwlagn_send_tx_power,
- .update_chain_flags = iwl_update_chain_flags,
- .set_channel_switch = iwl6000_hw_channel_switch,
- .apm_ops = {
- .init = iwl_apm_init,
- .stop = iwl_apm_stop,
- .config = iwl6000_nic_config,
- .set_pwr_src = iwl_set_pwr_src,
- },
- .eeprom_ops = {
- .regulatory_bands = {
- EEPROM_REG_BAND_1_CHANNELS,
- EEPROM_REG_BAND_2_CHANNELS,
- EEPROM_REG_BAND_3_CHANNELS,
- EEPROM_REG_BAND_4_CHANNELS,
- EEPROM_REG_BAND_5_CHANNELS,
- EEPROM_6000_REG_BAND_24_HT40_CHANNELS,
- EEPROM_REG_BAND_52_HT40_CHANNELS
- },
- .verify_signature = iwlcore_eeprom_verify_signature,
- .acquire_semaphore = iwlcore_eeprom_acquire_semaphore,
- .release_semaphore = iwlcore_eeprom_release_semaphore,
- .calib_version = iwlagn_eeprom_calib_version,
- .query_addr = iwlagn_eeprom_query_addr,
- .update_enhanced_txpower = iwlcore_eeprom_enhanced_txpower,
- },
- .post_associate = iwl_post_associate,
- .isr = iwl_isr_ict,
- .config_ap = iwl_config_ap,
- .temp_ops = {
- .temperature = iwlagn_temperature,
- .set_ct_kill = iwl6000_set_ct_threshold,
- .set_calib_version = iwl6050_set_calib_version,
- },
- .manage_ibss_station = iwlagn_manage_ibss_station,
- .debugfs_ops = {
- .rx_stats_read = iwl_ucode_rx_stats_read,
- .tx_stats_read = iwl_ucode_tx_stats_read,
- .general_stats_read = iwl_ucode_general_stats_read,
- },
- .recover_from_tx_stall = iwl_bg_monitor_recover,
- .check_plcp_health = iwl_good_plcp_health,
- .check_ack_health = iwl_good_ack_health,
+static void do_not_send_bt_config(struct iwl_priv *priv)
+{
+}
+
+static struct iwl_hcmd_ops iwl6000g2b_hcmd = {
+ .rxon_assoc = iwlagn_send_rxon_assoc,
+ .commit_rxon = iwl_commit_rxon,
+ .set_rxon_chain = iwl_set_rxon_chain,
+ .set_tx_ant = iwlagn_send_tx_ant_config,
+ .send_bt_config = do_not_send_bt_config,
};
-static const struct iwl_ops iwl6050_ops = {
- .lib = &iwl6050_lib,
- .hcmd = &iwlagn_hcmd,
+static const struct iwl_ops iwl6000g2b_ops = {
+ .lib = &iwl6000_lib,
+ .hcmd = &iwl6000g2b_hcmd,
.utils = &iwlagn_hcmd_utils,
.led = &iwlagn_led_ops,
};
-
struct iwl_cfg iwl6000g2a_2agn_cfg = {
.name = "6000 Series 2x2 AGN Gen2a",
.fw_name_pre = IWL6000G2A_FW_PRE,
@@ -443,6 +393,299 @@ struct iwl_cfg iwl6000g2a_2agn_cfg = {
.ucode_tracing = true,
.sensitivity_calib_by_driver = true,
.chain_noise_calib_by_driver = true,
+ .need_dc_calib = true,
+};
+
+struct iwl_cfg iwl6000g2a_2abg_cfg = {
+ .name = "6000 Series 2x2 ABG Gen2a",
+ .fw_name_pre = IWL6000G2A_FW_PRE,
+ .ucode_api_max = IWL6000G2_UCODE_API_MAX,
+ .ucode_api_min = IWL6000G2_UCODE_API_MIN,
+ .sku = IWL_SKU_A|IWL_SKU_G,
+ .ops = &iwl6000_ops,
+ .eeprom_size = OTP_LOW_IMAGE_SIZE,
+ .eeprom_ver = EEPROM_6000G2_EEPROM_VERSION,
+ .eeprom_calib_ver = EEPROM_6000G2_TX_POWER_VERSION,
+ .num_of_queues = IWLAGN_NUM_QUEUES,
+ .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES,
+ .mod_params = &iwlagn_mod_params,
+ .valid_tx_ant = ANT_AB,
+ .valid_rx_ant = ANT_AB,
+ .pll_cfg_val = 0,
+ .set_l0s = true,
+ .use_bsm = false,
+ .pa_type = IWL_PA_SYSTEM,
+ .max_ll_items = OTP_MAX_LL_ITEMS_6x00,
+ .shadow_ram_support = true,
+ .led_compensation = 51,
+ .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
+ .supports_idle = true,
+ .adv_thermal_throttle = true,
+ .support_ct_kill_exit = true,
+ .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
+ .chain_noise_scale = 1000,
+ .monitor_recover_period = IWL_MONITORING_PERIOD,
+ .max_event_log_size = 512,
+ .sensitivity_calib_by_driver = true,
+ .chain_noise_calib_by_driver = true,
+ .need_dc_calib = true,
+};
+
+struct iwl_cfg iwl6000g2a_2bg_cfg = {
+ .name = "6000 Series 2x2 BG Gen2a",
+ .fw_name_pre = IWL6000G2A_FW_PRE,
+ .ucode_api_max = IWL6000G2_UCODE_API_MAX,
+ .ucode_api_min = IWL6000G2_UCODE_API_MIN,
+ .sku = IWL_SKU_G,
+ .ops = &iwl6000_ops,
+ .eeprom_size = OTP_LOW_IMAGE_SIZE,
+ .eeprom_ver = EEPROM_6000G2_EEPROM_VERSION,
+ .eeprom_calib_ver = EEPROM_6000G2_TX_POWER_VERSION,
+ .num_of_queues = IWLAGN_NUM_QUEUES,
+ .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES,
+ .mod_params = &iwlagn_mod_params,
+ .valid_tx_ant = ANT_AB,
+ .valid_rx_ant = ANT_AB,
+ .pll_cfg_val = 0,
+ .set_l0s = true,
+ .use_bsm = false,
+ .pa_type = IWL_PA_SYSTEM,
+ .max_ll_items = OTP_MAX_LL_ITEMS_6x00,
+ .shadow_ram_support = true,
+ .led_compensation = 51,
+ .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
+ .supports_idle = true,
+ .adv_thermal_throttle = true,
+ .support_ct_kill_exit = true,
+ .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
+ .chain_noise_scale = 1000,
+ .monitor_recover_period = IWL_MONITORING_PERIOD,
+ .max_event_log_size = 512,
+ .sensitivity_calib_by_driver = true,
+ .chain_noise_calib_by_driver = true,
+ .need_dc_calib = true,
+};
+
+struct iwl_cfg iwl6000g2b_2agn_cfg = {
+ .name = "6000 Series 2x2 AGN Gen2b",
+ .fw_name_pre = IWL6000G2B_FW_PRE,
+ .ucode_api_max = IWL6000G2_UCODE_API_MAX,
+ .ucode_api_min = IWL6000G2_UCODE_API_MIN,
+ .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N,
+ .ops = &iwl6000g2b_ops,
+ .eeprom_size = OTP_LOW_IMAGE_SIZE,
+ .eeprom_ver = EEPROM_6000G2_EEPROM_VERSION,
+ .eeprom_calib_ver = EEPROM_6000G2_TX_POWER_VERSION,
+ .num_of_queues = IWLAGN_NUM_QUEUES,
+ .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES,
+ .mod_params = &iwlagn_mod_params,
+ .valid_tx_ant = ANT_AB,
+ .valid_rx_ant = ANT_AB,
+ .pll_cfg_val = 0,
+ .set_l0s = true,
+ .use_bsm = false,
+ .pa_type = IWL_PA_SYSTEM,
+ .max_ll_items = OTP_MAX_LL_ITEMS_6x00,
+ .shadow_ram_support = true,
+ .ht_greenfield_support = true,
+ .led_compensation = 51,
+ .use_rts_for_ht = true, /* use rts/cts protection */
+ .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
+ .supports_idle = true,
+ .adv_thermal_throttle = true,
+ .support_ct_kill_exit = true,
+ .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
+ .chain_noise_scale = 1000,
+ .monitor_recover_period = IWL_MONITORING_PERIOD,
+ .max_event_log_size = 512,
+ .sensitivity_calib_by_driver = true,
+ .chain_noise_calib_by_driver = true,
+ .need_dc_calib = true,
+ .bt_statistics = true,
+};
+
+struct iwl_cfg iwl6000g2b_2abg_cfg = {
+ .name = "6000 Series 2x2 ABG Gen2b",
+ .fw_name_pre = IWL6000G2B_FW_PRE,
+ .ucode_api_max = IWL6000G2_UCODE_API_MAX,
+ .ucode_api_min = IWL6000G2_UCODE_API_MIN,
+ .sku = IWL_SKU_A|IWL_SKU_G,
+ .ops = &iwl6000g2b_ops,
+ .eeprom_size = OTP_LOW_IMAGE_SIZE,
+ .eeprom_ver = EEPROM_6000G2_EEPROM_VERSION,
+ .eeprom_calib_ver = EEPROM_6000G2_TX_POWER_VERSION,
+ .num_of_queues = IWLAGN_NUM_QUEUES,
+ .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES,
+ .mod_params = &iwlagn_mod_params,
+ .valid_tx_ant = ANT_AB,
+ .valid_rx_ant = ANT_AB,
+ .pll_cfg_val = 0,
+ .set_l0s = true,
+ .use_bsm = false,
+ .pa_type = IWL_PA_SYSTEM,
+ .max_ll_items = OTP_MAX_LL_ITEMS_6x00,
+ .shadow_ram_support = true,
+ .led_compensation = 51,
+ .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
+ .supports_idle = true,
+ .adv_thermal_throttle = true,
+ .support_ct_kill_exit = true,
+ .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
+ .chain_noise_scale = 1000,
+ .monitor_recover_period = IWL_MONITORING_PERIOD,
+ .max_event_log_size = 512,
+ .sensitivity_calib_by_driver = true,
+ .chain_noise_calib_by_driver = true,
+ .need_dc_calib = true,
+ .bt_statistics = true,
+};
+
+struct iwl_cfg iwl6000g2b_2bgn_cfg = {
+ .name = "6000 Series 2x2 BGN Gen2b",
+ .fw_name_pre = IWL6000G2B_FW_PRE,
+ .ucode_api_max = IWL6000G2_UCODE_API_MAX,
+ .ucode_api_min = IWL6000G2_UCODE_API_MIN,
+ .sku = IWL_SKU_G|IWL_SKU_N,
+ .ops = &iwl6000g2b_ops,
+ .eeprom_size = OTP_LOW_IMAGE_SIZE,
+ .eeprom_ver = EEPROM_6000G2_EEPROM_VERSION,
+ .eeprom_calib_ver = EEPROM_6000G2_TX_POWER_VERSION,
+ .num_of_queues = IWLAGN_NUM_QUEUES,
+ .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES,
+ .mod_params = &iwlagn_mod_params,
+ .valid_tx_ant = ANT_AB,
+ .valid_rx_ant = ANT_AB,
+ .pll_cfg_val = 0,
+ .set_l0s = true,
+ .use_bsm = false,
+ .pa_type = IWL_PA_SYSTEM,
+ .max_ll_items = OTP_MAX_LL_ITEMS_6x00,
+ .shadow_ram_support = true,
+ .ht_greenfield_support = true,
+ .led_compensation = 51,
+ .use_rts_for_ht = true, /* use rts/cts protection */
+ .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
+ .supports_idle = true,
+ .adv_thermal_throttle = true,
+ .support_ct_kill_exit = true,
+ .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
+ .chain_noise_scale = 1000,
+ .monitor_recover_period = IWL_MONITORING_PERIOD,
+ .max_event_log_size = 512,
+ .sensitivity_calib_by_driver = true,
+ .chain_noise_calib_by_driver = true,
+ .need_dc_calib = true,
+ .bt_statistics = true,
+};
+
+struct iwl_cfg iwl6000g2b_2bg_cfg = {
+ .name = "6000 Series 2x2 BG Gen2b",
+ .fw_name_pre = IWL6000G2B_FW_PRE,
+ .ucode_api_max = IWL6000G2_UCODE_API_MAX,
+ .ucode_api_min = IWL6000G2_UCODE_API_MIN,
+ .sku = IWL_SKU_G,
+ .ops = &iwl6000g2b_ops,
+ .eeprom_size = OTP_LOW_IMAGE_SIZE,
+ .eeprom_ver = EEPROM_6000G2_EEPROM_VERSION,
+ .eeprom_calib_ver = EEPROM_6000G2_TX_POWER_VERSION,
+ .num_of_queues = IWLAGN_NUM_QUEUES,
+ .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES,
+ .mod_params = &iwlagn_mod_params,
+ .valid_tx_ant = ANT_AB,
+ .valid_rx_ant = ANT_AB,
+ .pll_cfg_val = 0,
+ .set_l0s = true,
+ .use_bsm = false,
+ .pa_type = IWL_PA_SYSTEM,
+ .max_ll_items = OTP_MAX_LL_ITEMS_6x00,
+ .shadow_ram_support = true,
+ .led_compensation = 51,
+ .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
+ .supports_idle = true,
+ .adv_thermal_throttle = true,
+ .support_ct_kill_exit = true,
+ .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
+ .chain_noise_scale = 1000,
+ .monitor_recover_period = IWL_MONITORING_PERIOD,
+ .max_event_log_size = 512,
+ .sensitivity_calib_by_driver = true,
+ .chain_noise_calib_by_driver = true,
+ .need_dc_calib = true,
+ .bt_statistics = true,
+};
+
+struct iwl_cfg iwl6000g2b_bgn_cfg = {
+ .name = "6000 Series 1x2 BGN Gen2b",
+ .fw_name_pre = IWL6000G2B_FW_PRE,
+ .ucode_api_max = IWL6000G2_UCODE_API_MAX,
+ .ucode_api_min = IWL6000G2_UCODE_API_MIN,
+ .sku = IWL_SKU_G|IWL_SKU_N,
+ .ops = &iwl6000g2b_ops,
+ .eeprom_size = OTP_LOW_IMAGE_SIZE,
+ .eeprom_ver = EEPROM_6000G2_EEPROM_VERSION,
+ .eeprom_calib_ver = EEPROM_6000G2_TX_POWER_VERSION,
+ .num_of_queues = IWLAGN_NUM_QUEUES,
+ .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES,
+ .mod_params = &iwlagn_mod_params,
+ .valid_tx_ant = ANT_A,
+ .valid_rx_ant = ANT_AB,
+ .pll_cfg_val = 0,
+ .set_l0s = true,
+ .use_bsm = false,
+ .pa_type = IWL_PA_SYSTEM,
+ .max_ll_items = OTP_MAX_LL_ITEMS_6x00,
+ .shadow_ram_support = true,
+ .ht_greenfield_support = true,
+ .led_compensation = 51,
+ .use_rts_for_ht = true, /* use rts/cts protection */
+ .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
+ .supports_idle = true,
+ .adv_thermal_throttle = true,
+ .support_ct_kill_exit = true,
+ .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
+ .chain_noise_scale = 1000,
+ .monitor_recover_period = IWL_MONITORING_PERIOD,
+ .max_event_log_size = 512,
+ .sensitivity_calib_by_driver = true,
+ .chain_noise_calib_by_driver = true,
+ .need_dc_calib = true,
+ .bt_statistics = true,
+};
+
+struct iwl_cfg iwl6000g2b_bg_cfg = {
+ .name = "6000 Series 1x2 BG Gen2b",
+ .fw_name_pre = IWL6000G2B_FW_PRE,
+ .ucode_api_max = IWL6000G2_UCODE_API_MAX,
+ .ucode_api_min = IWL6000G2_UCODE_API_MIN,
+ .sku = IWL_SKU_G,
+ .ops = &iwl6000g2b_ops,
+ .eeprom_size = OTP_LOW_IMAGE_SIZE,
+ .eeprom_ver = EEPROM_6000G2_EEPROM_VERSION,
+ .eeprom_calib_ver = EEPROM_6000G2_TX_POWER_VERSION,
+ .num_of_queues = IWLAGN_NUM_QUEUES,
+ .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES,
+ .mod_params = &iwlagn_mod_params,
+ .valid_tx_ant = ANT_A,
+ .valid_rx_ant = ANT_AB,
+ .pll_cfg_val = 0,
+ .set_l0s = true,
+ .use_bsm = false,
+ .pa_type = IWL_PA_SYSTEM,
+ .max_ll_items = OTP_MAX_LL_ITEMS_6x00,
+ .shadow_ram_support = true,
+ .led_compensation = 51,
+ .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
+ .supports_idle = true,
+ .adv_thermal_throttle = true,
+ .support_ct_kill_exit = true,
+ .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
+ .chain_noise_scale = 1000,
+ .monitor_recover_period = IWL_MONITORING_PERIOD,
+ .max_event_log_size = 512,
+ .sensitivity_calib_by_driver = true,
+ .chain_noise_calib_by_driver = true,
+ .need_dc_calib = true,
+ .bt_statistics = true,
};
/*
@@ -561,7 +804,7 @@ struct iwl_cfg iwl6050_2agn_cfg = {
.ucode_api_max = IWL6050_UCODE_API_MAX,
.ucode_api_min = IWL6050_UCODE_API_MIN,
.sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N,
- .ops = &iwl6050_ops,
+ .ops = &iwl6000_ops,
.eeprom_size = OTP_LOW_IMAGE_SIZE,
.eeprom_ver = EEPROM_6050_EEPROM_VERSION,
.eeprom_calib_ver = EEPROM_6050_TX_POWER_VERSION,
@@ -590,6 +833,45 @@ struct iwl_cfg iwl6050_2agn_cfg = {
.ucode_tracing = true,
.sensitivity_calib_by_driver = true,
.chain_noise_calib_by_driver = true,
+ .need_dc_calib = true,
+};
+
+struct iwl_cfg iwl6050g2_bgn_cfg = {
+ .name = "6050 Series 1x2 BGN Gen2",
+ .fw_name_pre = IWL6050_FW_PRE,
+ .ucode_api_max = IWL6050_UCODE_API_MAX,
+ .ucode_api_min = IWL6050_UCODE_API_MIN,
+ .sku = IWL_SKU_G|IWL_SKU_N,
+ .ops = &iwl6000_ops,
+ .eeprom_size = OTP_LOW_IMAGE_SIZE,
+ .eeprom_ver = EEPROM_6050G2_EEPROM_VERSION,
+ .eeprom_calib_ver = EEPROM_6050G2_TX_POWER_VERSION,
+ .num_of_queues = IWLAGN_NUM_QUEUES,
+ .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES,
+ .mod_params = &iwlagn_mod_params,
+ .valid_tx_ant = ANT_A,
+ .valid_rx_ant = ANT_AB,
+ .pll_cfg_val = 0,
+ .set_l0s = true,
+ .use_bsm = false,
+ .pa_type = IWL_PA_SYSTEM,
+ .max_ll_items = OTP_MAX_LL_ITEMS_6x50,
+ .shadow_ram_support = true,
+ .ht_greenfield_support = true,
+ .led_compensation = 51,
+ .use_rts_for_ht = true, /* use rts/cts protection */
+ .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
+ .supports_idle = true,
+ .adv_thermal_throttle = true,
+ .support_ct_kill_exit = true,
+ .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
+ .chain_noise_scale = 1500,
+ .monitor_recover_period = IWL_MONITORING_PERIOD,
+ .max_event_log_size = 1024,
+ .ucode_tracing = true,
+ .sensitivity_calib_by_driver = true,
+ .chain_noise_calib_by_driver = true,
+ .need_dc_calib = true,
};
struct iwl_cfg iwl6050_2abg_cfg = {
@@ -598,7 +880,7 @@ struct iwl_cfg iwl6050_2abg_cfg = {
.ucode_api_max = IWL6050_UCODE_API_MAX,
.ucode_api_min = IWL6050_UCODE_API_MIN,
.sku = IWL_SKU_A|IWL_SKU_G,
- .ops = &iwl6050_ops,
+ .ops = &iwl6000_ops,
.eeprom_size = OTP_LOW_IMAGE_SIZE,
.eeprom_ver = EEPROM_6050_EEPROM_VERSION,
.eeprom_calib_ver = EEPROM_6050_TX_POWER_VERSION,
@@ -625,6 +907,7 @@ struct iwl_cfg iwl6050_2abg_cfg = {
.ucode_tracing = true,
.sensitivity_calib_by_driver = true,
.chain_noise_calib_by_driver = true,
+ .need_dc_calib = true,
};
struct iwl_cfg iwl6000_3agn_cfg = {
@@ -667,3 +950,4 @@ struct iwl_cfg iwl6000_3agn_cfg = {
MODULE_FIRMWARE(IWL6000_MODULE_FIRMWARE(IWL6000_UCODE_API_MAX));
MODULE_FIRMWARE(IWL6050_MODULE_FIRMWARE(IWL6050_UCODE_API_MAX));
MODULE_FIRMWARE(IWL6000G2A_MODULE_FIRMWARE(IWL6000G2_UCODE_API_MAX));
+MODULE_FIRMWARE(IWL6000G2B_MODULE_FIRMWARE(IWL6000G2_UCODE_API_MAX));
diff --git a/drivers/net/wireless/iwlwifi/iwl-calib.c b/drivers/net/wireless/iwlwifi/iwl-agn-calib.c
index 7e822777321..c4c5691032a 100644
--- a/drivers/net/wireless/iwlwifi/iwl-calib.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-calib.c
@@ -96,17 +96,16 @@ int iwl_send_calib_results(struct iwl_priv *priv)
hcmd.len = priv->calib_results[i].buf_len;
hcmd.data = priv->calib_results[i].buf;
ret = iwl_send_cmd_sync(priv, &hcmd);
- if (ret)
- goto err;
+ if (ret) {
+ IWL_ERR(priv, "Error %d iteration %d\n",
+ ret, i);
+ break;
+ }
}
}
- return 0;
-err:
- IWL_ERR(priv, "Error %d iteration %d\n", ret, i);
return ret;
}
-EXPORT_SYMBOL(iwl_send_calib_results);
int iwl_calib_set(struct iwl_calib_result *res, const u8 *buf, int len)
{
@@ -121,7 +120,6 @@ int iwl_calib_set(struct iwl_calib_result *res, const u8 *buf, int len)
memcpy(res->buf, buf, len);
return 0;
}
-EXPORT_SYMBOL(iwl_calib_set);
void iwl_calib_free_results(struct iwl_priv *priv)
{
@@ -133,7 +131,6 @@ void iwl_calib_free_results(struct iwl_priv *priv)
priv->calib_results[i].buf_len = 0;
}
}
-EXPORT_SYMBOL(iwl_calib_free_results);
/*****************************************************************************
* RUNTIME calibrations framework
@@ -412,46 +409,34 @@ static int iwl_sens_auto_corr_ofdm(struct iwl_priv *priv,
return 0;
}
-/* Prepare a SENSITIVITY_CMD, send to uCode if values have changed */
-static int iwl_sensitivity_write(struct iwl_priv *priv)
+static void iwl_prepare_legacy_sensitivity_tbl(struct iwl_priv *priv,
+ struct iwl_sensitivity_data *data,
+ __le16 *tbl)
{
- struct iwl_sensitivity_cmd cmd ;
- struct iwl_sensitivity_data *data = NULL;
- struct iwl_host_cmd cmd_out = {
- .id = SENSITIVITY_CMD,
- .len = sizeof(struct iwl_sensitivity_cmd),
- .flags = CMD_ASYNC,
- .data = &cmd,
- };
-
- data = &(priv->sensitivity_data);
-
- memset(&cmd, 0, sizeof(cmd));
-
- cmd.table[HD_AUTO_CORR32_X4_TH_ADD_MIN_INDEX] =
+ tbl[HD_AUTO_CORR32_X4_TH_ADD_MIN_INDEX] =
cpu_to_le16((u16)data->auto_corr_ofdm);
- cmd.table[HD_AUTO_CORR32_X4_TH_ADD_MIN_MRC_INDEX] =
+ tbl[HD_AUTO_CORR32_X4_TH_ADD_MIN_MRC_INDEX] =
cpu_to_le16((u16)data->auto_corr_ofdm_mrc);
- cmd.table[HD_AUTO_CORR32_X1_TH_ADD_MIN_INDEX] =
+ tbl[HD_AUTO_CORR32_X1_TH_ADD_MIN_INDEX] =
cpu_to_le16((u16)data->auto_corr_ofdm_x1);
- cmd.table[HD_AUTO_CORR32_X1_TH_ADD_MIN_MRC_INDEX] =
+ tbl[HD_AUTO_CORR32_X1_TH_ADD_MIN_MRC_INDEX] =
cpu_to_le16((u16)data->auto_corr_ofdm_mrc_x1);
- cmd.table[HD_AUTO_CORR40_X4_TH_ADD_MIN_INDEX] =
+ tbl[HD_AUTO_CORR40_X4_TH_ADD_MIN_INDEX] =
cpu_to_le16((u16)data->auto_corr_cck);
- cmd.table[HD_AUTO_CORR40_X4_TH_ADD_MIN_MRC_INDEX] =
+ tbl[HD_AUTO_CORR40_X4_TH_ADD_MIN_MRC_INDEX] =
cpu_to_le16((u16)data->auto_corr_cck_mrc);
- cmd.table[HD_MIN_ENERGY_CCK_DET_INDEX] =
+ tbl[HD_MIN_ENERGY_CCK_DET_INDEX] =
cpu_to_le16((u16)data->nrg_th_cck);
- cmd.table[HD_MIN_ENERGY_OFDM_DET_INDEX] =
+ tbl[HD_MIN_ENERGY_OFDM_DET_INDEX] =
cpu_to_le16((u16)data->nrg_th_ofdm);
- cmd.table[HD_BARKER_CORR_TH_ADD_MIN_INDEX] =
+ tbl[HD_BARKER_CORR_TH_ADD_MIN_INDEX] =
cpu_to_le16(data->barker_corr_th_min);
- cmd.table[HD_BARKER_CORR_TH_ADD_MIN_MRC_INDEX] =
+ tbl[HD_BARKER_CORR_TH_ADD_MIN_MRC_INDEX] =
cpu_to_le16(data->barker_corr_th_min_mrc);
- cmd.table[HD_OFDM_ENERGY_TH_IN_INDEX] =
+ tbl[HD_OFDM_ENERGY_TH_IN_INDEX] =
cpu_to_le16(data->nrg_th_cca);
IWL_DEBUG_CALIB(priv, "ofdm: ac %u mrc %u x1 %u mrc_x1 %u thresh %u\n",
@@ -462,6 +447,25 @@ static int iwl_sensitivity_write(struct iwl_priv *priv)
IWL_DEBUG_CALIB(priv, "cck: ac %u mrc %u thresh %u\n",
data->auto_corr_cck, data->auto_corr_cck_mrc,
data->nrg_th_cck);
+}
+
+/* Prepare a SENSITIVITY_CMD, send to uCode if values have changed */
+static int iwl_sensitivity_write(struct iwl_priv *priv)
+{
+ struct iwl_sensitivity_cmd cmd;
+ struct iwl_sensitivity_data *data = NULL;
+ struct iwl_host_cmd cmd_out = {
+ .id = SENSITIVITY_CMD,
+ .len = sizeof(struct iwl_sensitivity_cmd),
+ .flags = CMD_ASYNC,
+ .data = &cmd,
+ };
+
+ data = &(priv->sensitivity_data);
+
+ memset(&cmd, 0, sizeof(cmd));
+
+ iwl_prepare_legacy_sensitivity_tbl(priv, data, &cmd.table[0]);
/* Update uCode's "work" table, and copy it to DSP */
cmd.control = SENSITIVITY_CMD_CONTROL_WORK_TABLE;
@@ -480,6 +484,70 @@ static int iwl_sensitivity_write(struct iwl_priv *priv)
return iwl_send_cmd(priv, &cmd_out);
}
+/* Prepare a SENSITIVITY_CMD, send to uCode if values have changed */
+static int iwl_enhance_sensitivity_write(struct iwl_priv *priv)
+{
+ struct iwl_enhance_sensitivity_cmd cmd;
+ struct iwl_sensitivity_data *data = NULL;
+ struct iwl_host_cmd cmd_out = {
+ .id = SENSITIVITY_CMD,
+ .len = sizeof(struct iwl_enhance_sensitivity_cmd),
+ .flags = CMD_ASYNC,
+ .data = &cmd,
+ };
+
+ data = &(priv->sensitivity_data);
+
+ memset(&cmd, 0, sizeof(cmd));
+
+ iwl_prepare_legacy_sensitivity_tbl(priv, data, &cmd.enhance_table[0]);
+
+ cmd.enhance_table[HD_INA_NON_SQUARE_DET_OFDM_INDEX] =
+ HD_INA_NON_SQUARE_DET_OFDM_DATA;
+ cmd.enhance_table[HD_INA_NON_SQUARE_DET_CCK_INDEX] =
+ HD_INA_NON_SQUARE_DET_CCK_DATA;
+ cmd.enhance_table[HD_CORR_11_INSTEAD_OF_CORR_9_EN_INDEX] =
+ HD_CORR_11_INSTEAD_OF_CORR_9_EN_DATA;
+ cmd.enhance_table[HD_OFDM_NON_SQUARE_DET_SLOPE_MRC_INDEX] =
+ HD_OFDM_NON_SQUARE_DET_SLOPE_MRC_DATA;
+ cmd.enhance_table[HD_OFDM_NON_SQUARE_DET_INTERCEPT_MRC_INDEX] =
+ HD_OFDM_NON_SQUARE_DET_INTERCEPT_MRC_DATA;
+ cmd.enhance_table[HD_OFDM_NON_SQUARE_DET_SLOPE_INDEX] =
+ HD_OFDM_NON_SQUARE_DET_SLOPE_DATA;
+ cmd.enhance_table[HD_OFDM_NON_SQUARE_DET_INTERCEPT_INDEX] =
+ HD_OFDM_NON_SQUARE_DET_INTERCEPT_DATA;
+ cmd.enhance_table[HD_CCK_NON_SQUARE_DET_SLOPE_MRC_INDEX] =
+ HD_CCK_NON_SQUARE_DET_SLOPE_MRC_DATA;
+ cmd.enhance_table[HD_CCK_NON_SQUARE_DET_INTERCEPT_MRC_INDEX] =
+ HD_CCK_NON_SQUARE_DET_INTERCEPT_MRC_DATA;
+ cmd.enhance_table[HD_CCK_NON_SQUARE_DET_SLOPE_INDEX] =
+ HD_CCK_NON_SQUARE_DET_SLOPE_DATA;
+ cmd.enhance_table[HD_CCK_NON_SQUARE_DET_INTERCEPT_INDEX] =
+ HD_CCK_NON_SQUARE_DET_INTERCEPT_DATA;
+
+ /* Update uCode's "work" table, and copy it to DSP */
+ cmd.control = SENSITIVITY_CMD_CONTROL_WORK_TABLE;
+
+ /* Don't send command to uCode if nothing has changed */
+ if (!memcmp(&cmd.enhance_table[0], &(priv->sensitivity_tbl[0]),
+ sizeof(u16)*HD_TABLE_SIZE) &&
+ !memcmp(&cmd.enhance_table[HD_INA_NON_SQUARE_DET_OFDM_INDEX],
+ &(priv->enhance_sensitivity_tbl[0]),
+ sizeof(u16)*ENHANCE_HD_TABLE_ENTRIES)) {
+ IWL_DEBUG_CALIB(priv, "No change in SENSITIVITY_CMD\n");
+ return 0;
+ }
+
+ /* Copy table for comparison next time */
+ memcpy(&(priv->sensitivity_tbl[0]), &(cmd.enhance_table[0]),
+ sizeof(u16)*HD_TABLE_SIZE);
+ memcpy(&(priv->enhance_sensitivity_tbl[0]),
+ &(cmd.enhance_table[HD_INA_NON_SQUARE_DET_OFDM_INDEX]),
+ sizeof(u16)*ENHANCE_HD_TABLE_ENTRIES);
+
+ return iwl_send_cmd(priv, &cmd_out);
+}
+
void iwl_init_sensitivity(struct iwl_priv *priv)
{
int ret = 0;
@@ -530,13 +598,14 @@ void iwl_init_sensitivity(struct iwl_priv *priv)
data->last_bad_plcp_cnt_cck = 0;
data->last_fa_cnt_cck = 0;
- ret |= iwl_sensitivity_write(priv);
+ if (priv->enhance_sensitivity_table)
+ ret |= iwl_enhance_sensitivity_write(priv);
+ else
+ ret |= iwl_sensitivity_write(priv);
IWL_DEBUG_CALIB(priv, "<<return 0x%X\n", ret);
}
-EXPORT_SYMBOL(iwl_init_sensitivity);
-void iwl_sensitivity_calibration(struct iwl_priv *priv,
- struct iwl_notif_statistics *resp)
+void iwl_sensitivity_calibration(struct iwl_priv *priv, void *resp)
{
u32 rx_enable_time;
u32 fa_cck;
@@ -546,8 +615,8 @@ void iwl_sensitivity_calibration(struct iwl_priv *priv,
u32 norm_fa_ofdm;
u32 norm_fa_cck;
struct iwl_sensitivity_data *data = NULL;
- struct statistics_rx_non_phy *rx_info = &(resp->rx.general);
- struct statistics_rx *statistics = &(resp->rx);
+ struct statistics_rx_non_phy *rx_info;
+ struct statistics_rx_phy *ofdm, *cck;
unsigned long flags;
struct statistics_general_data statis;
@@ -562,6 +631,16 @@ void iwl_sensitivity_calibration(struct iwl_priv *priv,
}
spin_lock_irqsave(&priv->lock, flags);
+ if (priv->cfg->bt_statistics) {
+ rx_info = &(((struct iwl_bt_notif_statistics *)resp)->
+ rx.general.common);
+ ofdm = &(((struct iwl_bt_notif_statistics *)resp)->rx.ofdm);
+ cck = &(((struct iwl_bt_notif_statistics *)resp)->rx.cck);
+ } else {
+ rx_info = &(((struct iwl_notif_statistics *)resp)->rx.general);
+ ofdm = &(((struct iwl_notif_statistics *)resp)->rx.ofdm);
+ cck = &(((struct iwl_notif_statistics *)resp)->rx.cck);
+ }
if (rx_info->interference_data_flag != INTERFERENCE_DATA_AVAILABLE) {
IWL_DEBUG_CALIB(priv, "<< invalid data.\n");
spin_unlock_irqrestore(&priv->lock, flags);
@@ -570,23 +649,23 @@ void iwl_sensitivity_calibration(struct iwl_priv *priv,
/* Extract Statistics: */
rx_enable_time = le32_to_cpu(rx_info->channel_load);
- fa_cck = le32_to_cpu(statistics->cck.false_alarm_cnt);
- fa_ofdm = le32_to_cpu(statistics->ofdm.false_alarm_cnt);
- bad_plcp_cck = le32_to_cpu(statistics->cck.plcp_err);
- bad_plcp_ofdm = le32_to_cpu(statistics->ofdm.plcp_err);
+ fa_cck = le32_to_cpu(cck->false_alarm_cnt);
+ fa_ofdm = le32_to_cpu(ofdm->false_alarm_cnt);
+ bad_plcp_cck = le32_to_cpu(cck->plcp_err);
+ bad_plcp_ofdm = le32_to_cpu(ofdm->plcp_err);
statis.beacon_silence_rssi_a =
- le32_to_cpu(statistics->general.beacon_silence_rssi_a);
+ le32_to_cpu(rx_info->beacon_silence_rssi_a);
statis.beacon_silence_rssi_b =
- le32_to_cpu(statistics->general.beacon_silence_rssi_b);
+ le32_to_cpu(rx_info->beacon_silence_rssi_b);
statis.beacon_silence_rssi_c =
- le32_to_cpu(statistics->general.beacon_silence_rssi_c);
+ le32_to_cpu(rx_info->beacon_silence_rssi_c);
statis.beacon_energy_a =
- le32_to_cpu(statistics->general.beacon_energy_a);
+ le32_to_cpu(rx_info->beacon_energy_a);
statis.beacon_energy_b =
- le32_to_cpu(statistics->general.beacon_energy_b);
+ le32_to_cpu(rx_info->beacon_energy_b);
statis.beacon_energy_c =
- le32_to_cpu(statistics->general.beacon_energy_c);
+ le32_to_cpu(rx_info->beacon_energy_c);
spin_unlock_irqrestore(&priv->lock, flags);
@@ -637,9 +716,11 @@ void iwl_sensitivity_calibration(struct iwl_priv *priv,
iwl_sens_auto_corr_ofdm(priv, norm_fa_ofdm, rx_enable_time);
iwl_sens_energy_cck(priv, norm_fa_cck, rx_enable_time, &statis);
- iwl_sensitivity_write(priv);
+ if (priv->enhance_sensitivity_table)
+ iwl_enhance_sensitivity_write(priv);
+ else
+ iwl_sensitivity_write(priv);
}
-EXPORT_SYMBOL(iwl_sensitivity_calibration);
static inline u8 find_first_chain(u8 mask)
{
@@ -656,8 +737,7 @@ static inline u8 find_first_chain(u8 mask)
* 1) Which antennas are connected.
* 2) Differential rx gain settings to balance the 3 receivers.
*/
-void iwl_chain_noise_calibration(struct iwl_priv *priv,
- struct iwl_notif_statistics *stat_resp)
+void iwl_chain_noise_calibration(struct iwl_priv *priv, void *stat_resp)
{
struct iwl_chain_noise_data *data = NULL;
@@ -681,7 +761,7 @@ void iwl_chain_noise_calibration(struct iwl_priv *priv,
u32 active_chains = 0;
u8 num_tx_chains;
unsigned long flags;
- struct statistics_rx_non_phy *rx_info = &(stat_resp->rx.general);
+ struct statistics_rx_non_phy *rx_info;
u8 first_chain;
if (priv->disable_chain_noise_cal)
@@ -700,6 +780,13 @@ void iwl_chain_noise_calibration(struct iwl_priv *priv,
}
spin_lock_irqsave(&priv->lock, flags);
+ if (priv->cfg->bt_statistics) {
+ rx_info = &(((struct iwl_bt_notif_statistics *)stat_resp)->
+ rx.general.common);
+ } else {
+ rx_info = &(((struct iwl_notif_statistics *)stat_resp)->
+ rx.general);
+ }
if (rx_info->interference_data_flag != INTERFERENCE_DATA_AVAILABLE) {
IWL_DEBUG_CALIB(priv, " << Interference data unavailable\n");
spin_unlock_irqrestore(&priv->lock, flags);
@@ -708,8 +795,19 @@ void iwl_chain_noise_calibration(struct iwl_priv *priv,
rxon_band24 = !!(priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK);
rxon_chnum = le16_to_cpu(priv->staging_rxon.channel);
- stat_band24 = !!(stat_resp->flag & STATISTICS_REPLY_FLG_BAND_24G_MSK);
- stat_chnum = le32_to_cpu(stat_resp->flag) >> 16;
+ if (priv->cfg->bt_statistics) {
+ stat_band24 = !!(((struct iwl_bt_notif_statistics *)
+ stat_resp)->flag &
+ STATISTICS_REPLY_FLG_BAND_24G_MSK);
+ stat_chnum = le32_to_cpu(((struct iwl_bt_notif_statistics *)
+ stat_resp)->flag) >> 16;
+ } else {
+ stat_band24 = !!(((struct iwl_notif_statistics *)
+ stat_resp)->flag &
+ STATISTICS_REPLY_FLG_BAND_24G_MSK);
+ stat_chnum = le32_to_cpu(((struct iwl_notif_statistics *)
+ stat_resp)->flag) >> 16;
+ }
/* Make sure we accumulate data for just the associated channel
* (even if scanning). */
@@ -846,6 +944,13 @@ void iwl_chain_noise_calibration(struct iwl_priv *priv,
}
}
+ if (active_chains != priv->hw_params.valid_rx_ant &&
+ active_chains != priv->chain_noise_data.active_chains)
+ IWL_DEBUG_CALIB(priv,
+ "Detected that not all antennas are connected! "
+ "Connected: %#x, valid: %#x.\n",
+ active_chains, priv->hw_params.valid_rx_ant);
+
/* Save for use within RXON, TX, SCAN commands, etc. */
priv->chain_noise_data.active_chains = active_chains;
IWL_DEBUG_CALIB(priv, "active_chains (bitwise) = 0x%x\n",
@@ -890,8 +995,6 @@ void iwl_chain_noise_calibration(struct iwl_priv *priv,
data->state = IWL_CHAIN_NOISE_DONE;
iwl_power_update_mode(priv, false);
}
-EXPORT_SYMBOL(iwl_chain_noise_calibration);
-
void iwl_reset_run_time_calib(struct iwl_priv *priv)
{
@@ -908,5 +1011,3 @@ void iwl_reset_run_time_calib(struct iwl_priv *priv)
* periodically after association */
iwl_send_statistics_request(priv, CMD_ASYNC, true);
}
-EXPORT_SYMBOL(iwl_reset_run_time_calib);
-
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-agn-debugfs.c
index 48c023b4ca3..f052c6d09b3 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-debugfs.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-debugfs.c
@@ -28,6 +28,30 @@
#include "iwl-agn-debugfs.h"
+static int iwl_statistics_flag(struct iwl_priv *priv, char *buf, int bufsz)
+{
+ int p = 0;
+ u32 flag;
+
+ if (priv->cfg->bt_statistics)
+ flag = le32_to_cpu(priv->_agn.statistics_bt.flag);
+ else
+ flag = le32_to_cpu(priv->_agn.statistics.flag);
+
+ p += scnprintf(buf + p, bufsz - p, "Statistics Flag(0x%X):\n", flag);
+ if (flag & UCODE_STATISTICS_CLEAR_MSK)
+ p += scnprintf(buf + p, bufsz - p,
+ "\tStatistics have been cleared\n");
+ p += scnprintf(buf + p, bufsz - p, "\tOperational Frequency: %s\n",
+ (flag & UCODE_STATISTICS_FREQUENCY_MSK)
+ ? "2.4 GHz" : "5.2 GHz");
+ p += scnprintf(buf + p, bufsz - p, "\tTGj Narrow Band: %s\n",
+ (flag & UCODE_STATISTICS_NARROW_BAND_MSK)
+ ? "enabled" : "disabled");
+
+ return p;
+}
+
ssize_t iwl_ucode_rx_stats_read(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos)
{
@@ -58,24 +82,45 @@ ssize_t iwl_ucode_rx_stats_read(struct file *file, char __user *user_buf,
* the last statistics notification from uCode
* might not reflect the current uCode activity
*/
- ofdm = &priv->statistics.rx.ofdm;
- cck = &priv->statistics.rx.cck;
- general = &priv->statistics.rx.general;
- ht = &priv->statistics.rx.ofdm_ht;
- accum_ofdm = &priv->accum_statistics.rx.ofdm;
- accum_cck = &priv->accum_statistics.rx.cck;
- accum_general = &priv->accum_statistics.rx.general;
- accum_ht = &priv->accum_statistics.rx.ofdm_ht;
- delta_ofdm = &priv->delta_statistics.rx.ofdm;
- delta_cck = &priv->delta_statistics.rx.cck;
- delta_general = &priv->delta_statistics.rx.general;
- delta_ht = &priv->delta_statistics.rx.ofdm_ht;
- max_ofdm = &priv->max_delta.rx.ofdm;
- max_cck = &priv->max_delta.rx.cck;
- max_general = &priv->max_delta.rx.general;
- max_ht = &priv->max_delta.rx.ofdm_ht;
-
- pos += iwl_dbgfs_statistics_flag(priv, buf, bufsz);
+ if (priv->cfg->bt_statistics) {
+ ofdm = &priv->_agn.statistics_bt.rx.ofdm;
+ cck = &priv->_agn.statistics_bt.rx.cck;
+ general = &priv->_agn.statistics_bt.rx.general.common;
+ ht = &priv->_agn.statistics_bt.rx.ofdm_ht;
+ accum_ofdm = &priv->_agn.accum_statistics_bt.rx.ofdm;
+ accum_cck = &priv->_agn.accum_statistics_bt.rx.cck;
+ accum_general =
+ &priv->_agn.accum_statistics_bt.rx.general.common;
+ accum_ht = &priv->_agn.accum_statistics_bt.rx.ofdm_ht;
+ delta_ofdm = &priv->_agn.delta_statistics_bt.rx.ofdm;
+ delta_cck = &priv->_agn.delta_statistics_bt.rx.cck;
+ delta_general =
+ &priv->_agn.delta_statistics_bt.rx.general.common;
+ delta_ht = &priv->_agn.delta_statistics_bt.rx.ofdm_ht;
+ max_ofdm = &priv->_agn.max_delta_bt.rx.ofdm;
+ max_cck = &priv->_agn.max_delta_bt.rx.cck;
+ max_general = &priv->_agn.max_delta_bt.rx.general.common;
+ max_ht = &priv->_agn.max_delta_bt.rx.ofdm_ht;
+ } else {
+ ofdm = &priv->_agn.statistics.rx.ofdm;
+ cck = &priv->_agn.statistics.rx.cck;
+ general = &priv->_agn.statistics.rx.general;
+ ht = &priv->_agn.statistics.rx.ofdm_ht;
+ accum_ofdm = &priv->_agn.accum_statistics.rx.ofdm;
+ accum_cck = &priv->_agn.accum_statistics.rx.cck;
+ accum_general = &priv->_agn.accum_statistics.rx.general;
+ accum_ht = &priv->_agn.accum_statistics.rx.ofdm_ht;
+ delta_ofdm = &priv->_agn.delta_statistics.rx.ofdm;
+ delta_cck = &priv->_agn.delta_statistics.rx.cck;
+ delta_general = &priv->_agn.delta_statistics.rx.general;
+ delta_ht = &priv->_agn.delta_statistics.rx.ofdm_ht;
+ max_ofdm = &priv->_agn.max_delta.rx.ofdm;
+ max_cck = &priv->_agn.max_delta.rx.cck;
+ max_general = &priv->_agn.max_delta.rx.general;
+ max_ht = &priv->_agn.max_delta.rx.ofdm_ht;
+ }
+
+ pos += iwl_statistics_flag(priv, buf, bufsz);
pos += scnprintf(buf + pos, bufsz - pos, "%-32s current"
"acumulative delta max\n",
"Statistics_Rx - OFDM:");
@@ -539,11 +584,19 @@ ssize_t iwl_ucode_tx_stats_read(struct file *file,
* the last statistics notification from uCode
* might not reflect the current uCode activity
*/
- tx = &priv->statistics.tx;
- accum_tx = &priv->accum_statistics.tx;
- delta_tx = &priv->delta_statistics.tx;
- max_tx = &priv->max_delta.tx;
- pos += iwl_dbgfs_statistics_flag(priv, buf, bufsz);
+ if (priv->cfg->bt_statistics) {
+ tx = &priv->_agn.statistics_bt.tx;
+ accum_tx = &priv->_agn.accum_statistics_bt.tx;
+ delta_tx = &priv->_agn.delta_statistics_bt.tx;
+ max_tx = &priv->_agn.max_delta_bt.tx;
+ } else {
+ tx = &priv->_agn.statistics.tx;
+ accum_tx = &priv->_agn.accum_statistics.tx;
+ delta_tx = &priv->_agn.delta_statistics.tx;
+ max_tx = &priv->_agn.max_delta.tx;
+ }
+
+ pos += iwl_statistics_flag(priv, buf, bufsz);
pos += scnprintf(buf + pos, bufsz - pos, "%-32s current"
"acumulative delta max\n",
"Statistics_Tx:");
@@ -738,8 +791,8 @@ ssize_t iwl_ucode_general_stats_read(struct file *file, char __user *user_buf,
char *buf;
int bufsz = sizeof(struct statistics_general) * 10 + 300;
ssize_t ret;
- struct statistics_general *general, *accum_general;
- struct statistics_general *delta_general, *max_general;
+ struct statistics_general_common *general, *accum_general;
+ struct statistics_general_common *delta_general, *max_general;
struct statistics_dbg *dbg, *accum_dbg, *delta_dbg, *max_dbg;
struct statistics_div *div, *accum_div, *delta_div, *max_div;
@@ -756,19 +809,35 @@ ssize_t iwl_ucode_general_stats_read(struct file *file, char __user *user_buf,
* the last statistics notification from uCode
* might not reflect the current uCode activity
*/
- general = &priv->statistics.general;
- dbg = &priv->statistics.general.dbg;
- div = &priv->statistics.general.div;
- accum_general = &priv->accum_statistics.general;
- delta_general = &priv->delta_statistics.general;
- max_general = &priv->max_delta.general;
- accum_dbg = &priv->accum_statistics.general.dbg;
- delta_dbg = &priv->delta_statistics.general.dbg;
- max_dbg = &priv->max_delta.general.dbg;
- accum_div = &priv->accum_statistics.general.div;
- delta_div = &priv->delta_statistics.general.div;
- max_div = &priv->max_delta.general.div;
- pos += iwl_dbgfs_statistics_flag(priv, buf, bufsz);
+ if (priv->cfg->bt_statistics) {
+ general = &priv->_agn.statistics_bt.general.common;
+ dbg = &priv->_agn.statistics_bt.general.common.dbg;
+ div = &priv->_agn.statistics_bt.general.common.div;
+ accum_general = &priv->_agn.accum_statistics_bt.general.common;
+ accum_dbg = &priv->_agn.accum_statistics_bt.general.common.dbg;
+ accum_div = &priv->_agn.accum_statistics_bt.general.common.div;
+ delta_general = &priv->_agn.delta_statistics_bt.general.common;
+ max_general = &priv->_agn.max_delta_bt.general.common;
+ delta_dbg = &priv->_agn.delta_statistics_bt.general.common.dbg;
+ max_dbg = &priv->_agn.max_delta_bt.general.common.dbg;
+ delta_div = &priv->_agn.delta_statistics_bt.general.common.div;
+ max_div = &priv->_agn.max_delta_bt.general.common.div;
+ } else {
+ general = &priv->_agn.statistics.general.common;
+ dbg = &priv->_agn.statistics.general.common.dbg;
+ div = &priv->_agn.statistics.general.common.div;
+ accum_general = &priv->_agn.accum_statistics.general.common;
+ accum_dbg = &priv->_agn.accum_statistics.general.common.dbg;
+ accum_div = &priv->_agn.accum_statistics.general.common.div;
+ delta_general = &priv->_agn.delta_statistics.general.common;
+ max_general = &priv->_agn.max_delta.general.common;
+ delta_dbg = &priv->_agn.delta_statistics.general.common.dbg;
+ max_dbg = &priv->_agn.max_delta.general.common.dbg;
+ delta_div = &priv->_agn.delta_statistics.general.common.div;
+ max_div = &priv->_agn.max_delta.general.common.div;
+ }
+
+ pos += iwl_statistics_flag(priv, buf, bufsz);
pos += scnprintf(buf + pos, bufsz - pos, "%-32s current"
"acumulative delta max\n",
"Statistics_General:");
@@ -792,6 +861,13 @@ ssize_t iwl_ucode_general_stats_read(struct file *file, char __user *user_buf,
delta_dbg->burst_count, max_dbg->burst_count);
pos += scnprintf(buf + pos, bufsz - pos,
" %-30s %10u %10u %10u %10u\n",
+ "wait_for_silence_timeout_count:",
+ le32_to_cpu(dbg->wait_for_silence_timeout_cnt),
+ accum_dbg->wait_for_silence_timeout_cnt,
+ delta_dbg->wait_for_silence_timeout_cnt,
+ max_dbg->wait_for_silence_timeout_cnt);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ " %-30s %10u %10u %10u %10u\n",
"sleep_time:",
le32_to_cpu(general->sleep_time),
accum_general->sleep_time,
@@ -848,3 +924,90 @@ ssize_t iwl_ucode_general_stats_read(struct file *file, char __user *user_buf,
kfree(buf);
return ret;
}
+
+ssize_t iwl_ucode_bt_stats_read(struct file *file,
+ char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
+ int pos = 0;
+ char *buf;
+ int bufsz = (sizeof(struct statistics_bt_activity) * 24) + 200;
+ ssize_t ret;
+ struct statistics_bt_activity *bt, *accum_bt;
+
+ if (!iwl_is_alive(priv))
+ return -EAGAIN;
+
+ /* make request to uCode to retrieve statistics information */
+ mutex_lock(&priv->mutex);
+ ret = iwl_send_statistics_request(priv, CMD_SYNC, false);
+ mutex_unlock(&priv->mutex);
+
+ if (ret) {
+ IWL_ERR(priv,
+ "Error sending statistics request: %zd\n", ret);
+ return -EAGAIN;
+ }
+ buf = kzalloc(bufsz, GFP_KERNEL);
+ if (!buf) {
+ IWL_ERR(priv, "Can not allocate Buffer\n");
+ return -ENOMEM;
+ }
+
+ /*
+ * the statistic information display here is based on
+ * the last statistics notification from uCode
+ * might not reflect the current uCode activity
+ */
+ bt = &priv->_agn.statistics_bt.general.activity;
+ accum_bt = &priv->_agn.accum_statistics_bt.general.activity;
+
+ pos += iwl_statistics_flag(priv, buf, bufsz);
+ pos += scnprintf(buf + pos, bufsz - pos, "Statistics_BT:\n");
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "\t\t\tcurrent\t\t\taccumulative\n");
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "hi_priority_tx_req_cnt:\t\t%u\t\t\t%u\n",
+ le32_to_cpu(bt->hi_priority_tx_req_cnt),
+ accum_bt->hi_priority_tx_req_cnt);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "hi_priority_tx_denied_cnt:\t%u\t\t\t%u\n",
+ le32_to_cpu(bt->hi_priority_tx_denied_cnt),
+ accum_bt->hi_priority_tx_denied_cnt);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "lo_priority_tx_req_cnt:\t\t%u\t\t\t%u\n",
+ le32_to_cpu(bt->lo_priority_tx_req_cnt),
+ accum_bt->lo_priority_tx_req_cnt);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "lo_priority_rx_denied_cnt:\t%u\t\t\t%u\n",
+ le32_to_cpu(bt->lo_priority_tx_denied_cnt),
+ accum_bt->lo_priority_tx_denied_cnt);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "hi_priority_rx_req_cnt:\t\t%u\t\t\t%u\n",
+ le32_to_cpu(bt->hi_priority_rx_req_cnt),
+ accum_bt->hi_priority_rx_req_cnt);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "hi_priority_rx_denied_cnt:\t%u\t\t\t%u\n",
+ le32_to_cpu(bt->hi_priority_rx_denied_cnt),
+ accum_bt->hi_priority_rx_denied_cnt);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "lo_priority_rx_req_cnt:\t\t%u\t\t\t%u\n",
+ le32_to_cpu(bt->lo_priority_rx_req_cnt),
+ accum_bt->lo_priority_rx_req_cnt);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "lo_priority_rx_denied_cnt:\t%u\t\t\t%u\n",
+ le32_to_cpu(bt->lo_priority_rx_denied_cnt),
+ accum_bt->lo_priority_rx_denied_cnt);
+
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "(rx)num_bt_kills:\t\t%u\t\t\t%u\n",
+ le32_to_cpu(priv->_agn.statistics_bt.rx.
+ general.num_bt_kills),
+ priv->_agn.accum_statistics_bt.rx.
+ general.num_bt_kills);
+
+ ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+ kfree(buf);
+ return ret;
+}
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-debugfs.h b/drivers/net/wireless/iwlwifi/iwl-agn-debugfs.h
index 59b1f25f0d8..bbdce5913ac 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-debugfs.h
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-debugfs.h
@@ -37,6 +37,8 @@ ssize_t iwl_ucode_tx_stats_read(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos);
ssize_t iwl_ucode_general_stats_read(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos);
+ssize_t iwl_ucode_bt_stats_read(struct file *file, char __user *user_buf,
+ size_t count, loff_t *ppos);
#else
static ssize_t iwl_ucode_rx_stats_read(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos)
@@ -53,4 +55,9 @@ static ssize_t iwl_ucode_general_stats_read(struct file *file, char __user *user
{
return 0;
}
+static ssize_t iwl_ucode_bt_stats_read(struct file *file, char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ return 0;
+}
#endif
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-hcmd.c b/drivers/net/wireless/iwlwifi/iwl-agn-hcmd.c
index 01658cf82d3..a7216dda978 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-hcmd.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-hcmd.c
@@ -37,7 +37,7 @@
#include "iwl-io.h"
#include "iwl-agn.h"
-static int iwlagn_send_rxon_assoc(struct iwl_priv *priv)
+int iwlagn_send_rxon_assoc(struct iwl_priv *priv)
{
int ret = 0;
struct iwl5000_rxon_assoc_cmd rxon_assoc;
@@ -84,7 +84,7 @@ static int iwlagn_send_rxon_assoc(struct iwl_priv *priv)
return ret;
}
-static int iwlagn_send_tx_ant_config(struct iwl_priv *priv, u8 valid_tx_ant)
+int iwlagn_send_tx_ant_config(struct iwl_priv *priv, u8 valid_tx_ant)
{
struct iwl_tx_ant_config_cmd tx_ant_cmd = {
.valid = cpu_to_le32(valid_tx_ant),
@@ -164,7 +164,7 @@ static void iwlagn_gain_computation(struct iwl_priv *priv,
memset(&cmd, 0, sizeof(cmd));
- cmd.hdr.op_code = IWL_PHY_CALIBRATE_CHAIN_NOISE_GAIN_CMD;
+ cmd.hdr.op_code = priv->_agn.phy_calib_chain_noise_gain_cmd;
cmd.hdr.first_group = 0;
cmd.hdr.groups_num = 1;
cmd.hdr.data_valid = 1;
@@ -176,14 +176,6 @@ static void iwlagn_gain_computation(struct iwl_priv *priv,
data->radio_write = 1;
data->state = IWL_CHAIN_NOISE_CALIBRATED;
}
-
- data->chain_noise_a = 0;
- data->chain_noise_b = 0;
- data->chain_noise_c = 0;
- data->chain_signal_a = 0;
- data->chain_signal_b = 0;
- data->chain_signal_c = 0;
- data->beacon_count = 0;
}
static void iwlagn_chain_noise_reset(struct iwl_priv *priv)
@@ -191,11 +183,21 @@ static void iwlagn_chain_noise_reset(struct iwl_priv *priv)
struct iwl_chain_noise_data *data = &priv->chain_noise_data;
int ret;
- if ((data->state == IWL_CHAIN_NOISE_ALIVE) && iwl_is_associated(priv)) {
+ if ((data->state == IWL_CHAIN_NOISE_ALIVE) &&
+ iwl_is_associated(priv)) {
struct iwl_calib_chain_noise_reset_cmd cmd;
- memset(&cmd, 0, sizeof(cmd));
- cmd.hdr.op_code = IWL_PHY_CALIBRATE_CHAIN_NOISE_RESET_CMD;
+ /* clear data for chain noise calibration algorithm */
+ data->chain_noise_a = 0;
+ data->chain_noise_b = 0;
+ data->chain_noise_c = 0;
+ data->chain_signal_a = 0;
+ data->chain_signal_b = 0;
+ data->chain_signal_c = 0;
+ data->beacon_count = 0;
+
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.hdr.op_code = priv->_agn.phy_calib_chain_noise_reset_cmd;
cmd.hdr.first_group = 0;
cmd.hdr.groups_num = 1;
cmd.hdr.data_valid = 1;
@@ -212,7 +214,7 @@ static void iwlagn_chain_noise_reset(struct iwl_priv *priv)
static void iwlagn_rts_tx_cmd_flag(struct ieee80211_tx_info *info,
__le32 *tx_flags)
{
- *tx_flags |= TX_CMD_FLG_RTS_CTS_MSK;
+ *tx_flags |= TX_CMD_FLG_PROT_REQUIRE_MSK;
}
/* Calc max signal level (dBm) among 3 possible receivers */
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-hw.h b/drivers/net/wireless/iwlwifi/iwl-agn-hw.h
index f9a3fbb6338..a52b82c8e7a 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-hw.h
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-hw.h
@@ -112,7 +112,7 @@
*/
struct iwlagn_scd_bc_tbl {
__le16 tfd_offset[TFD_QUEUE_BC_SIZE];
-} __attribute__ ((packed));
+} __packed;
#endif /* __iwl_agn_hw_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c
index 0f292a210ed..a1b6d202d57 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c
@@ -77,7 +77,7 @@ static int iwlagn_tx_status_reply_tx(struct iwl_priv *priv,
IWL_DEBUG_TX_REPLY(priv, "FrameCnt = %d, StartIdx=%d idx=%d\n",
agg->frame_count, agg->start_idx, idx);
- info = IEEE80211_SKB_CB(priv->txq[txq_id].txb[idx].skb[0]);
+ info = IEEE80211_SKB_CB(priv->txq[txq_id].txb[idx].skb);
info->status.rates[0].count = tx_resp->failure_frame + 1;
info->flags &= ~IEEE80211_TX_CTL_AMPDU;
info->flags |= iwl_tx_status_to_mac80211(status);
@@ -93,6 +93,12 @@ static int iwlagn_tx_status_reply_tx(struct iwl_priv *priv,
} else {
/* Two or more frames were attempted; expect block-ack */
u64 bitmap = 0;
+
+ /*
+ * Start is the lowest frame sent. It may not be the first
+ * frame in the batch; we figure this out dynamically during
+ * the following loop.
+ */
int start = agg->start_idx;
/* Construct bit-map of pending frames within Tx window */
@@ -131,25 +137,58 @@ static int iwlagn_tx_status_reply_tx(struct iwl_priv *priv,
IWL_DEBUG_TX_REPLY(priv, "AGG Frame i=%d idx %d seq=%d\n",
i, idx, SEQ_TO_SN(sc));
+ /*
+ * sh -> how many frames ahead of the starting frame is
+ * the current one?
+ *
+ * Note that all frames sent in the batch must be in a
+ * 64-frame window, so this number should be in [0,63].
+ * If outside of this window, then we've found a new
+ * "first" frame in the batch and need to change start.
+ */
sh = idx - start;
- if (sh > 64) {
- sh = (start - idx) + 0xff;
+
+ /*
+ * If >= 64, out of window. start must be at the front
+ * of the circular buffer, idx must be near the end of
+ * the buffer, and idx is the new "first" frame. Shift
+ * the indices around.
+ */
+ if (sh >= 64) {
+ /* Shift bitmap by start - idx, wrapped */
+ sh = 0x100 - idx + start;
bitmap = bitmap << sh;
+ /* Now idx is the new start so sh = 0 */
sh = 0;
start = idx;
- } else if (sh < -64)
- sh = 0xff - (start - idx);
- else if (sh < 0) {
+ /*
+ * If <= -64 then wraps the 256-pkt circular buffer
+ * (e.g., start = 255 and idx = 0, sh should be 1)
+ */
+ } else if (sh <= -64) {
+ sh = 0x100 - start + idx;
+ /*
+ * If < 0 but > -64, out of window. idx is before start
+ * but not wrapped. Shift the indices around.
+ */
+ } else if (sh < 0) {
+ /* Shift by how far start is ahead of idx */
sh = start - idx;
- start = idx;
bitmap = bitmap << sh;
+ /* Now idx is the new start so sh = 0 */
+ start = idx;
sh = 0;
}
+ /* Sequence number start + sh was sent in this batch */
bitmap |= 1ULL << sh;
IWL_DEBUG_TX_REPLY(priv, "start=%d bitmap=0x%llx\n",
start, (unsigned long long)bitmap);
}
+ /*
+ * Store the bitmap and possibly the new start, if we wrapped
+ * the buffer above
+ */
agg->bitmap = bitmap;
agg->start_idx = start;
IWL_DEBUG_TX_REPLY(priv, "Frames %d start_idx=%d bitmap=0x%llx\n",
@@ -166,7 +205,9 @@ void iwl_check_abort_status(struct iwl_priv *priv,
u8 frame_count, u32 status)
{
if (frame_count == 1 && status == TX_STATUS_FAIL_RFKILL_FLUSH) {
- IWL_ERR(priv, "TODO: Implement Tx flush command!!!\n");
+ IWL_ERR(priv, "Tx flush command to flush out all frames\n");
+ if (!test_bit(STATUS_EXIT_PENDING, &priv->status))
+ queue_work(priv->workqueue, &priv->tx_flush);
}
}
@@ -184,6 +225,7 @@ static void iwlagn_rx_reply_tx(struct iwl_priv *priv,
int tid;
int sta_id;
int freed;
+ unsigned long flags;
if ((index >= txq->q.n_bd) || (iwl_queue_used(&txq->q, index) == 0)) {
IWL_ERR(priv, "Read index for DMA queue txq_id (%d) index %d "
@@ -193,15 +235,16 @@ static void iwlagn_rx_reply_tx(struct iwl_priv *priv,
return;
}
- info = IEEE80211_SKB_CB(txq->txb[txq->q.read_ptr].skb[0]);
+ info = IEEE80211_SKB_CB(txq->txb[txq->q.read_ptr].skb);
memset(&info->status, 0, sizeof(info->status));
tid = (tx_resp->ra_tid & IWL50_TX_RES_TID_MSK) >> IWL50_TX_RES_TID_POS;
sta_id = (tx_resp->ra_tid & IWL50_TX_RES_RA_MSK) >> IWL50_TX_RES_RA_POS;
+ spin_lock_irqsave(&priv->sta_lock, flags);
if (txq->sched_retry) {
const u32 scd_ssn = iwlagn_get_scd_ssn(tx_resp);
- struct iwl_ht_agg *agg = NULL;
+ struct iwl_ht_agg *agg;
agg = &priv->stations[sta_id].tid[tid].agg;
@@ -256,6 +299,7 @@ static void iwlagn_rx_reply_tx(struct iwl_priv *priv,
iwlagn_txq_check_empty(priv, sta_id, tid, txq_id);
iwl_check_abort_status(priv, tx_resp->frame_count, status);
+ spin_unlock_irqrestore(&priv->sta_lock, flags);
}
void iwlagn_rx_handler_setup(struct iwl_priv *priv)
@@ -319,7 +363,8 @@ int iwlagn_send_tx_power(struct iwl_priv *priv)
void iwlagn_temperature(struct iwl_priv *priv)
{
/* store temperature from statistics (in Celsius) */
- priv->temperature = le32_to_cpu(priv->statistics.general.temperature);
+ priv->temperature =
+ le32_to_cpu(priv->_agn.statistics.general.common.temperature);
iwl_tt_handler(priv);
}
@@ -444,7 +489,7 @@ int iwlagn_rx_init(struct iwl_priv *priv, struct iwl_rx_queue *rxq)
/* Tell device where to find RBD circular buffer in DRAM */
iwl_write_direct32(priv, FH_RSCSR_CHNL0_RBDCB_BASE_REG,
- (u32)(rxq->dma_addr >> 8));
+ (u32)(rxq->bd_dma >> 8));
/* Tell device where in DRAM to update its Rx status */
iwl_write_direct32(priv, FH_RSCSR_CHNL0_STTS_WPTR_REG,
@@ -709,7 +754,7 @@ void iwlagn_rx_queue_free(struct iwl_priv *priv, struct iwl_rx_queue *rxq)
}
dma_free_coherent(&priv->pci_dev->dev, 4 * RX_QUEUE_SIZE, rxq->bd,
- rxq->dma_addr);
+ rxq->bd_dma);
dma_free_coherent(&priv->pci_dev->dev, sizeof(struct iwl_rb_status),
rxq->rb_stts, rxq->rb_stts_dma);
rxq->bd = NULL;
@@ -755,132 +800,6 @@ static inline int iwlagn_calc_rssi(struct iwl_priv *priv,
return priv->cfg->ops->utils->calc_rssi(priv, rx_resp);
}
-#ifdef CONFIG_IWLWIFI_DEBUG
-/**
- * iwlagn_dbg_report_frame - dump frame to syslog during debug sessions
- *
- * You may hack this function to show different aspects of received frames,
- * including selective frame dumps.
- * group100 parameter selects whether to show 1 out of 100 good data frames.
- * All beacon and probe response frames are printed.
- */
-static void iwlagn_dbg_report_frame(struct iwl_priv *priv,
- struct iwl_rx_phy_res *phy_res, u16 length,
- struct ieee80211_hdr *header, int group100)
-{
- u32 to_us;
- u32 print_summary = 0;
- u32 print_dump = 0; /* set to 1 to dump all frames' contents */
- u32 hundred = 0;
- u32 dataframe = 0;
- __le16 fc;
- u16 seq_ctl;
- u16 channel;
- u16 phy_flags;
- u32 rate_n_flags;
- u32 tsf_low;
- int rssi;
-
- if (likely(!(iwl_get_debug_level(priv) & IWL_DL_RX)))
- return;
-
- /* MAC header */
- fc = header->frame_control;
- seq_ctl = le16_to_cpu(header->seq_ctrl);
-
- /* metadata */
- channel = le16_to_cpu(phy_res->channel);
- phy_flags = le16_to_cpu(phy_res->phy_flags);
- rate_n_flags = le32_to_cpu(phy_res->rate_n_flags);
-
- /* signal statistics */
- rssi = iwlagn_calc_rssi(priv, phy_res);
- tsf_low = le64_to_cpu(phy_res->timestamp) & 0x0ffffffff;
-
- to_us = !compare_ether_addr(header->addr1, priv->mac_addr);
-
- /* if data frame is to us and all is good,
- * (optionally) print summary for only 1 out of every 100 */
- if (to_us && (fc & ~cpu_to_le16(IEEE80211_FCTL_PROTECTED)) ==
- cpu_to_le16(IEEE80211_FCTL_FROMDS | IEEE80211_FTYPE_DATA)) {
- dataframe = 1;
- if (!group100)
- print_summary = 1; /* print each frame */
- else if (priv->framecnt_to_us < 100) {
- priv->framecnt_to_us++;
- print_summary = 0;
- } else {
- priv->framecnt_to_us = 0;
- print_summary = 1;
- hundred = 1;
- }
- } else {
- /* print summary for all other frames */
- print_summary = 1;
- }
-
- if (print_summary) {
- char *title;
- int rate_idx;
- u32 bitrate;
-
- if (hundred)
- title = "100Frames";
- else if (ieee80211_has_retry(fc))
- title = "Retry";
- else if (ieee80211_is_assoc_resp(fc))
- title = "AscRsp";
- else if (ieee80211_is_reassoc_resp(fc))
- title = "RasRsp";
- else if (ieee80211_is_probe_resp(fc)) {
- title = "PrbRsp";
- print_dump = 1; /* dump frame contents */
- } else if (ieee80211_is_beacon(fc)) {
- title = "Beacon";
- print_dump = 1; /* dump frame contents */
- } else if (ieee80211_is_atim(fc))
- title = "ATIM";
- else if (ieee80211_is_auth(fc))
- title = "Auth";
- else if (ieee80211_is_deauth(fc))
- title = "DeAuth";
- else if (ieee80211_is_disassoc(fc))
- title = "DisAssoc";
- else
- title = "Frame";
-
- rate_idx = iwl_hwrate_to_plcp_idx(rate_n_flags);
- if (unlikely((rate_idx < 0) || (rate_idx >= IWL_RATE_COUNT))) {
- bitrate = 0;
- WARN_ON_ONCE(1);
- } else {
- bitrate = iwl_rates[rate_idx].ieee / 2;
- }
-
- /* print frame summary.
- * MAC addresses show just the last byte (for brevity),
- * but you can hack it to show more, if you'd like to. */
- if (dataframe)
- IWL_DEBUG_RX(priv, "%s: mhd=0x%04x, dst=0x%02x, "
- "len=%u, rssi=%d, chnl=%d, rate=%u,\n",
- title, le16_to_cpu(fc), header->addr1[5],
- length, rssi, channel, bitrate);
- else {
- /* src/dst addresses assume managed mode */
- IWL_DEBUG_RX(priv, "%s: 0x%04x, dst=0x%02x, src=0x%02x, "
- "len=%u, rssi=%d, tim=%lu usec, "
- "phy=0x%02x, chnl=%d\n",
- title, le16_to_cpu(fc), header->addr1[5],
- header->addr3[5], length, rssi,
- tsf_low - priv->scan_start_tsf,
- phy_flags, channel);
- }
- }
- if (print_dump)
- iwl_print_hex_dump(priv, IWL_DL_RX, header, length);
-}
-#endif
-
static u32 iwlagn_translate_rx_status(struct iwl_priv *priv, u32 decrypt_in)
{
u32 decrypt_out = 0;
@@ -988,7 +907,7 @@ void iwlagn_rx_reply_rx(struct iwl_priv *priv,
struct iwl_rx_packet *pkt = rxb_addr(rxb);
struct iwl_rx_phy_res *phy_res;
__le32 rx_pkt_status;
- struct iwl4965_rx_mpdu_res_start *amsdu;
+ struct iwl_rx_mpdu_res_start *amsdu;
u32 len;
u32 ampdu_status;
u32 rate_n_flags;
@@ -1017,7 +936,7 @@ void iwlagn_rx_reply_rx(struct iwl_priv *priv,
return;
}
phy_res = &priv->_agn.last_phy_res;
- amsdu = (struct iwl4965_rx_mpdu_res_start *)pkt->u.raw;
+ amsdu = (struct iwl_rx_mpdu_res_start *)pkt->u.raw;
header = (struct ieee80211_hdr *)(pkt->u.raw + sizeof(*amsdu));
len = le16_to_cpu(amsdu->byte_count);
rx_pkt_status = *(__le32 *)(pkt->u.raw + sizeof(*amsdu) + len);
@@ -1060,11 +979,6 @@ void iwlagn_rx_reply_rx(struct iwl_priv *priv,
/* Find max signal strength (dBm) among 3 antenna/receiver chains */
rx_status.signal = iwlagn_calc_rssi(priv, phy_res);
-#ifdef CONFIG_IWLWIFI_DEBUG
- /* Set "1" to report good data frames in groups of 100 */
- if (unlikely(iwl_get_debug_level(priv) & IWL_DL_RX))
- iwlagn_dbg_report_frame(priv, phy_res, len, header, 1);
-#endif
iwl_dbg_log_rx_data_frame(priv, len, header);
IWL_DEBUG_STATS_LIMIT(priv, "Rssi %d, TSF %llu\n",
rx_status.signal, (unsigned long long)rx_status.mactime);
@@ -1252,6 +1166,7 @@ void iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif)
bool is_active = false;
int chan_mod;
u8 active_chains;
+ u8 scan_tx_antennas = priv->hw_params.valid_tx_ant;
conf = ieee80211_get_hw_conf(priv->hw);
@@ -1319,7 +1234,10 @@ void iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif)
IWL_DEBUG_INFO(priv, "Scanning while associated...\n");
spin_lock_irqsave(&priv->lock, flags);
- interval = vif ? vif->bss_conf.beacon_int : 0;
+ if (priv->is_internal_short_scan)
+ interval = 0;
+ else
+ interval = vif->bss_conf.beacon_int;
spin_unlock_irqrestore(&priv->lock, flags);
scan->suspend_time = 0;
@@ -1403,11 +1321,14 @@ void iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif)
band = priv->scan_band;
- if (priv->cfg->scan_antennas[band])
- rx_ant = priv->cfg->scan_antennas[band];
+ if (priv->cfg->scan_rx_antennas[band])
+ rx_ant = priv->cfg->scan_rx_antennas[band];
+
+ if (priv->cfg->scan_tx_antennas[band])
+ scan_tx_antennas = priv->cfg->scan_tx_antennas[band];
- priv->scan_tx_ant[band] =
- iwl_toggle_tx_ant(priv, priv->scan_tx_ant[band]);
+ priv->scan_tx_ant[band] = iwl_toggle_tx_ant(priv, priv->scan_tx_ant[band],
+ scan_tx_antennas);
rate_flags |= iwl_ant_idx_to_flags(priv->scan_tx_ant[band]);
scan->tx_cmd.rate_n_flags = iwl_hw_set_rate_n_flags(rate, rate_flags);
@@ -1433,13 +1354,15 @@ void iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif)
if (!priv->is_internal_short_scan) {
cmd_len = iwl_fill_probe_req(priv,
(struct ieee80211_mgmt *)scan->data,
+ vif->addr,
priv->scan_request->ie,
priv->scan_request->ie_len,
IWL_MAX_SCAN_SIZE - sizeof(*scan));
} else {
+ /* use bcast addr, will not be transmitted but must be valid */
cmd_len = iwl_fill_probe_req(priv,
(struct ieee80211_mgmt *)scan->data,
- NULL, 0,
+ iwl_bcast_addr, NULL, 0,
IWL_MAX_SCAN_SIZE - sizeof(*scan));
}
@@ -1502,3 +1425,96 @@ int iwlagn_manage_ibss_station(struct iwl_priv *priv,
return iwl_remove_station(priv, vif_priv->ibss_bssid_sta_id,
vif->bss_conf.bssid);
}
+
+void iwl_free_tfds_in_queue(struct iwl_priv *priv,
+ int sta_id, int tid, int freed)
+{
+ WARN_ON(!spin_is_locked(&priv->sta_lock));
+
+ if (priv->stations[sta_id].tid[tid].tfds_in_queue >= freed)
+ priv->stations[sta_id].tid[tid].tfds_in_queue -= freed;
+ else {
+ IWL_DEBUG_TX(priv, "free more than tfds_in_queue (%u:%d)\n",
+ priv->stations[sta_id].tid[tid].tfds_in_queue,
+ freed);
+ priv->stations[sta_id].tid[tid].tfds_in_queue = 0;
+ }
+}
+
+#define IWL_FLUSH_WAIT_MS 2000
+
+int iwlagn_wait_tx_queue_empty(struct iwl_priv *priv)
+{
+ struct iwl_tx_queue *txq;
+ struct iwl_queue *q;
+ int cnt;
+ unsigned long now = jiffies;
+ int ret = 0;
+
+ /* waiting for all the tx frames complete might take a while */
+ for (cnt = 0; cnt < priv->hw_params.max_txq_num; cnt++) {
+ if (cnt == IWL_CMD_QUEUE_NUM)
+ continue;
+ txq = &priv->txq[cnt];
+ q = &txq->q;
+ while (q->read_ptr != q->write_ptr && !time_after(jiffies,
+ now + msecs_to_jiffies(IWL_FLUSH_WAIT_MS)))
+ msleep(1);
+
+ if (q->read_ptr != q->write_ptr) {
+ IWL_ERR(priv, "fail to flush all tx fifo queues\n");
+ ret = -ETIMEDOUT;
+ break;
+ }
+ }
+ return ret;
+}
+
+#define IWL_TX_QUEUE_MSK 0xfffff
+
+/**
+ * iwlagn_txfifo_flush: send REPLY_TXFIFO_FLUSH command to uCode
+ *
+ * pre-requirements:
+ * 1. acquire mutex before calling
+ * 2. make sure rf is on and not in exit state
+ */
+int iwlagn_txfifo_flush(struct iwl_priv *priv, u16 flush_control)
+{
+ struct iwl_txfifo_flush_cmd flush_cmd;
+ struct iwl_host_cmd cmd = {
+ .id = REPLY_TXFIFO_FLUSH,
+ .len = sizeof(struct iwl_txfifo_flush_cmd),
+ .flags = CMD_SYNC,
+ .data = &flush_cmd,
+ };
+
+ might_sleep();
+
+ memset(&flush_cmd, 0, sizeof(flush_cmd));
+ flush_cmd.fifo_control = IWL_TX_FIFO_VO_MSK | IWL_TX_FIFO_VI_MSK |
+ IWL_TX_FIFO_BE_MSK | IWL_TX_FIFO_BK_MSK;
+ if (priv->cfg->sku & IWL_SKU_N)
+ flush_cmd.fifo_control |= IWL_AGG_TX_QUEUE_MSK;
+
+ IWL_DEBUG_INFO(priv, "fifo queue control: 0X%x\n",
+ flush_cmd.fifo_control);
+ flush_cmd.flush_control = cpu_to_le16(flush_control);
+
+ return iwl_send_cmd(priv, &cmd);
+}
+
+void iwlagn_dev_txfifo_flush(struct iwl_priv *priv, u16 flush_control)
+{
+ mutex_lock(&priv->mutex);
+ ieee80211_stop_queues(priv->hw);
+ if (priv->cfg->ops->lib->txfifo_flush(priv, IWL_DROP_ALL)) {
+ IWL_ERR(priv, "flush request fail\n");
+ goto done;
+ }
+ IWL_DEBUG_INFO(priv, "wait transmit/flush all frames\n");
+ iwlagn_wait_tx_queue_empty(priv);
+done:
+ ieee80211_wake_queues(priv->hw);
+ mutex_unlock(&priv->mutex);
+}
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c
index cf4a95bae4f..35c86d22b14 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c
@@ -313,8 +313,7 @@ static int rs_tl_turn_on_agg_for_tid(struct iwl_priv *priv,
*/
IWL_DEBUG_HT(priv, "Fail start Tx agg on tid: %d\n",
tid);
- ieee80211_stop_tx_ba_session(sta, tid,
- WLAN_BACK_INITIATOR);
+ ieee80211_stop_tx_ba_session(sta, tid);
}
} else
IWL_ERR(priv, "Fail finding valid aggregation tid: %d\n", tid);
@@ -325,18 +324,11 @@ static void rs_tl_turn_on_agg(struct iwl_priv *priv, u8 tid,
struct iwl_lq_sta *lq_data,
struct ieee80211_sta *sta)
{
- if ((tid < TID_MAX_LOAD_COUNT) &&
- !rs_tl_turn_on_agg_for_tid(priv, lq_data, tid, sta)) {
- if (priv->cfg->use_rts_for_ht) {
- /*
- * switch to RTS/CTS if it is the prefer protection
- * method for HT traffic
- */
- IWL_DEBUG_HT(priv, "use RTS/CTS protection for HT\n");
- priv->staging_rxon.flags &= ~RXON_FLG_SELF_CTS_EN;
- iwlcore_commit_rxon(priv);
- }
- }
+ if (tid < TID_MAX_LOAD_COUNT)
+ rs_tl_turn_on_agg_for_tid(priv, lq_data, tid, sta);
+ else
+ IWL_ERR(priv, "tid exceeds max load count: %d/%d\n",
+ tid, TID_MAX_LOAD_COUNT);
}
static inline int get_num_of_ant_from_rate(u32 rate_n_flags)
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rx.c b/drivers/net/wireless/iwlwifi/iwl-agn-rx.c
new file mode 100644
index 00000000000..9490eced119
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-rx.c
@@ -0,0 +1,351 @@
+/******************************************************************************
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
+ * USA
+ *
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * Contact Information:
+ * Intel Linux Wireless <ilw@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ *****************************************************************************/
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+
+#include "iwl-dev.h"
+#include "iwl-core.h"
+#include "iwl-calib.h"
+#include "iwl-sta.h"
+#include "iwl-io.h"
+#include "iwl-helpers.h"
+#include "iwl-agn-hw.h"
+#include "iwl-agn.h"
+
+void iwl_rx_missed_beacon_notif(struct iwl_priv *priv,
+ struct iwl_rx_mem_buffer *rxb)
+
+{
+ struct iwl_rx_packet *pkt = rxb_addr(rxb);
+ struct iwl_missed_beacon_notif *missed_beacon;
+
+ missed_beacon = &pkt->u.missed_beacon;
+ if (le32_to_cpu(missed_beacon->consecutive_missed_beacons) >
+ priv->missed_beacon_threshold) {
+ IWL_DEBUG_CALIB(priv,
+ "missed bcn cnsq %d totl %d rcd %d expctd %d\n",
+ le32_to_cpu(missed_beacon->consecutive_missed_beacons),
+ le32_to_cpu(missed_beacon->total_missed_becons),
+ le32_to_cpu(missed_beacon->num_recvd_beacons),
+ le32_to_cpu(missed_beacon->num_expected_beacons));
+ if (!test_bit(STATUS_SCANNING, &priv->status))
+ iwl_init_sensitivity(priv);
+ }
+}
+
+/* Calculate noise level, based on measurements during network silence just
+ * before arriving beacon. This measurement can be done only if we know
+ * exactly when to expect beacons, therefore only when we're associated. */
+static void iwl_rx_calc_noise(struct iwl_priv *priv)
+{
+ struct statistics_rx_non_phy *rx_info;
+ int num_active_rx = 0;
+ int total_silence = 0;
+ int bcn_silence_a, bcn_silence_b, bcn_silence_c;
+ int last_rx_noise;
+
+ if (priv->cfg->bt_statistics)
+ rx_info = &(priv->_agn.statistics_bt.rx.general.common);
+ else
+ rx_info = &(priv->_agn.statistics.rx.general);
+ bcn_silence_a =
+ le32_to_cpu(rx_info->beacon_silence_rssi_a) & IN_BAND_FILTER;
+ bcn_silence_b =
+ le32_to_cpu(rx_info->beacon_silence_rssi_b) & IN_BAND_FILTER;
+ bcn_silence_c =
+ le32_to_cpu(rx_info->beacon_silence_rssi_c) & IN_BAND_FILTER;
+
+ if (bcn_silence_a) {
+ total_silence += bcn_silence_a;
+ num_active_rx++;
+ }
+ if (bcn_silence_b) {
+ total_silence += bcn_silence_b;
+ num_active_rx++;
+ }
+ if (bcn_silence_c) {
+ total_silence += bcn_silence_c;
+ num_active_rx++;
+ }
+
+ /* Average among active antennas */
+ if (num_active_rx)
+ last_rx_noise = (total_silence / num_active_rx) - 107;
+ else
+ last_rx_noise = IWL_NOISE_MEAS_NOT_AVAILABLE;
+
+ IWL_DEBUG_CALIB(priv, "inband silence a %u, b %u, c %u, dBm %d\n",
+ bcn_silence_a, bcn_silence_b, bcn_silence_c,
+ last_rx_noise);
+}
+
+#ifdef CONFIG_IWLWIFI_DEBUGFS
+/*
+ * based on the assumption of all statistics counter are in DWORD
+ * FIXME: This function is for debugging, do not deal with
+ * the case of counters roll-over.
+ */
+static void iwl_accumulative_statistics(struct iwl_priv *priv,
+ __le32 *stats)
+{
+ int i, size;
+ __le32 *prev_stats;
+ u32 *accum_stats;
+ u32 *delta, *max_delta;
+ struct statistics_general_common *general, *accum_general;
+ struct statistics_tx *tx, *accum_tx;
+
+ if (priv->cfg->bt_statistics) {
+ prev_stats = (__le32 *)&priv->_agn.statistics_bt;
+ accum_stats = (u32 *)&priv->_agn.accum_statistics_bt;
+ size = sizeof(struct iwl_bt_notif_statistics);
+ general = &priv->_agn.statistics_bt.general.common;
+ accum_general = &priv->_agn.accum_statistics_bt.general.common;
+ tx = &priv->_agn.statistics_bt.tx;
+ accum_tx = &priv->_agn.accum_statistics_bt.tx;
+ delta = (u32 *)&priv->_agn.delta_statistics_bt;
+ max_delta = (u32 *)&priv->_agn.max_delta_bt;
+ } else {
+ prev_stats = (__le32 *)&priv->_agn.statistics;
+ accum_stats = (u32 *)&priv->_agn.accum_statistics;
+ size = sizeof(struct iwl_notif_statistics);
+ general = &priv->_agn.statistics.general.common;
+ accum_general = &priv->_agn.accum_statistics.general.common;
+ tx = &priv->_agn.statistics.tx;
+ accum_tx = &priv->_agn.accum_statistics.tx;
+ delta = (u32 *)&priv->_agn.delta_statistics;
+ max_delta = (u32 *)&priv->_agn.max_delta;
+ }
+ for (i = sizeof(__le32); i < size;
+ i += sizeof(__le32), stats++, prev_stats++, delta++,
+ max_delta++, accum_stats++) {
+ if (le32_to_cpu(*stats) > le32_to_cpu(*prev_stats)) {
+ *delta = (le32_to_cpu(*stats) -
+ le32_to_cpu(*prev_stats));
+ *accum_stats += *delta;
+ if (*delta > *max_delta)
+ *max_delta = *delta;
+ }
+ }
+
+ /* reset accumulative statistics for "no-counter" type statistics */
+ accum_general->temperature = general->temperature;
+ accum_general->temperature_m = general->temperature_m;
+ accum_general->ttl_timestamp = general->ttl_timestamp;
+ accum_tx->tx_power.ant_a = tx->tx_power.ant_a;
+ accum_tx->tx_power.ant_b = tx->tx_power.ant_b;
+ accum_tx->tx_power.ant_c = tx->tx_power.ant_c;
+}
+#endif
+
+#define REG_RECALIB_PERIOD (60)
+
+/**
+ * iwl_good_plcp_health - checks for plcp error.
+ *
+ * When the plcp error is exceeding the thresholds, reset the radio
+ * to improve the throughput.
+ */
+bool iwl_good_plcp_health(struct iwl_priv *priv,
+ struct iwl_rx_packet *pkt)
+{
+ bool rc = true;
+ int combined_plcp_delta;
+ unsigned int plcp_msec;
+ unsigned long plcp_received_jiffies;
+
+ if (priv->cfg->plcp_delta_threshold ==
+ IWL_MAX_PLCP_ERR_THRESHOLD_DISABLE) {
+ IWL_DEBUG_RADIO(priv, "plcp_err check disabled\n");
+ return rc;
+ }
+
+ /*
+ * check for plcp_err and trigger radio reset if it exceeds
+ * the plcp error threshold plcp_delta.
+ */
+ plcp_received_jiffies = jiffies;
+ plcp_msec = jiffies_to_msecs((long) plcp_received_jiffies -
+ (long) priv->plcp_jiffies);
+ priv->plcp_jiffies = plcp_received_jiffies;
+ /*
+ * check to make sure plcp_msec is not 0 to prevent division
+ * by zero.
+ */
+ if (plcp_msec) {
+ struct statistics_rx_phy *ofdm;
+ struct statistics_rx_ht_phy *ofdm_ht;
+
+ if (priv->cfg->bt_statistics) {
+ ofdm = &pkt->u.stats_bt.rx.ofdm;
+ ofdm_ht = &pkt->u.stats_bt.rx.ofdm_ht;
+ combined_plcp_delta =
+ (le32_to_cpu(ofdm->plcp_err) -
+ le32_to_cpu(priv->_agn.statistics_bt.
+ rx.ofdm.plcp_err)) +
+ (le32_to_cpu(ofdm_ht->plcp_err) -
+ le32_to_cpu(priv->_agn.statistics_bt.
+ rx.ofdm_ht.plcp_err));
+ } else {
+ ofdm = &pkt->u.stats.rx.ofdm;
+ ofdm_ht = &pkt->u.stats.rx.ofdm_ht;
+ combined_plcp_delta =
+ (le32_to_cpu(ofdm->plcp_err) -
+ le32_to_cpu(priv->_agn.statistics.
+ rx.ofdm.plcp_err)) +
+ (le32_to_cpu(ofdm_ht->plcp_err) -
+ le32_to_cpu(priv->_agn.statistics.
+ rx.ofdm_ht.plcp_err));
+ }
+
+ if ((combined_plcp_delta > 0) &&
+ ((combined_plcp_delta * 100) / plcp_msec) >
+ priv->cfg->plcp_delta_threshold) {
+ /*
+ * if plcp_err exceed the threshold,
+ * the following data is printed in csv format:
+ * Text: plcp_err exceeded %d,
+ * Received ofdm.plcp_err,
+ * Current ofdm.plcp_err,
+ * Received ofdm_ht.plcp_err,
+ * Current ofdm_ht.plcp_err,
+ * combined_plcp_delta,
+ * plcp_msec
+ */
+ IWL_DEBUG_RADIO(priv, "plcp_err exceeded %u, "
+ "%u, %u, %u, %u, %d, %u mSecs\n",
+ priv->cfg->plcp_delta_threshold,
+ le32_to_cpu(ofdm->plcp_err),
+ le32_to_cpu(ofdm->plcp_err),
+ le32_to_cpu(ofdm_ht->plcp_err),
+ le32_to_cpu(ofdm_ht->plcp_err),
+ combined_plcp_delta, plcp_msec);
+
+ rc = false;
+ }
+ }
+ return rc;
+}
+
+void iwl_rx_statistics(struct iwl_priv *priv,
+ struct iwl_rx_mem_buffer *rxb)
+{
+ int change;
+ struct iwl_rx_packet *pkt = rxb_addr(rxb);
+
+ if (priv->cfg->bt_statistics) {
+ IWL_DEBUG_RX(priv,
+ "Statistics notification received (%d vs %d).\n",
+ (int)sizeof(struct iwl_bt_notif_statistics),
+ le32_to_cpu(pkt->len_n_flags) &
+ FH_RSCSR_FRAME_SIZE_MSK);
+
+ change = ((priv->_agn.statistics_bt.general.common.temperature !=
+ pkt->u.stats_bt.general.common.temperature) ||
+ ((priv->_agn.statistics_bt.flag &
+ STATISTICS_REPLY_FLG_HT40_MODE_MSK) !=
+ (pkt->u.stats_bt.flag &
+ STATISTICS_REPLY_FLG_HT40_MODE_MSK)));
+#ifdef CONFIG_IWLWIFI_DEBUGFS
+ iwl_accumulative_statistics(priv, (__le32 *)&pkt->u.stats_bt);
+#endif
+
+ } else {
+ IWL_DEBUG_RX(priv,
+ "Statistics notification received (%d vs %d).\n",
+ (int)sizeof(struct iwl_notif_statistics),
+ le32_to_cpu(pkt->len_n_flags) &
+ FH_RSCSR_FRAME_SIZE_MSK);
+
+ change = ((priv->_agn.statistics.general.common.temperature !=
+ pkt->u.stats.general.common.temperature) ||
+ ((priv->_agn.statistics.flag &
+ STATISTICS_REPLY_FLG_HT40_MODE_MSK) !=
+ (pkt->u.stats.flag &
+ STATISTICS_REPLY_FLG_HT40_MODE_MSK)));
+#ifdef CONFIG_IWLWIFI_DEBUGFS
+ iwl_accumulative_statistics(priv, (__le32 *)&pkt->u.stats);
+#endif
+
+ }
+
+ iwl_recover_from_statistics(priv, pkt);
+
+ if (priv->cfg->bt_statistics)
+ memcpy(&priv->_agn.statistics_bt, &pkt->u.stats_bt,
+ sizeof(priv->_agn.statistics_bt));
+ else
+ memcpy(&priv->_agn.statistics, &pkt->u.stats,
+ sizeof(priv->_agn.statistics));
+
+ set_bit(STATUS_STATISTICS, &priv->status);
+
+ /* Reschedule the statistics timer to occur in
+ * REG_RECALIB_PERIOD seconds to ensure we get a
+ * thermal update even if the uCode doesn't give
+ * us one */
+ mod_timer(&priv->statistics_periodic, jiffies +
+ msecs_to_jiffies(REG_RECALIB_PERIOD * 1000));
+
+ if (unlikely(!test_bit(STATUS_SCANNING, &priv->status)) &&
+ (pkt->hdr.cmd == STATISTICS_NOTIFICATION)) {
+ iwl_rx_calc_noise(priv);
+ queue_work(priv->workqueue, &priv->run_time_calib_work);
+ }
+ if (priv->cfg->ops->lib->temp_ops.temperature && change)
+ priv->cfg->ops->lib->temp_ops.temperature(priv);
+}
+
+void iwl_reply_statistics(struct iwl_priv *priv,
+ struct iwl_rx_mem_buffer *rxb)
+{
+ struct iwl_rx_packet *pkt = rxb_addr(rxb);
+
+ if (le32_to_cpu(pkt->u.stats.flag) & UCODE_STATISTICS_CLEAR_MSK) {
+#ifdef CONFIG_IWLWIFI_DEBUGFS
+ memset(&priv->_agn.accum_statistics, 0,
+ sizeof(struct iwl_notif_statistics));
+ memset(&priv->_agn.delta_statistics, 0,
+ sizeof(struct iwl_notif_statistics));
+ memset(&priv->_agn.max_delta, 0,
+ sizeof(struct iwl_notif_statistics));
+ memset(&priv->_agn.accum_statistics_bt, 0,
+ sizeof(struct iwl_bt_notif_statistics));
+ memset(&priv->_agn.delta_statistics_bt, 0,
+ sizeof(struct iwl_bt_notif_statistics));
+ memset(&priv->_agn.max_delta_bt, 0,
+ sizeof(struct iwl_bt_notif_statistics));
+#endif
+ IWL_DEBUG_RX(priv, "Statistics have been cleared\n");
+ }
+ iwl_rx_statistics(priv, rxb);
+}
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c
index 7d614c4d3c6..55a1b31fd09 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c
@@ -233,6 +233,7 @@ int iwlagn_txq_agg_enable(struct iwl_priv *priv, int txq_id,
{
unsigned long flags;
u16 ra_tid;
+ int ret;
if ((IWLAGN_FIRST_AMPDU_QUEUE > txq_id) ||
(IWLAGN_FIRST_AMPDU_QUEUE + priv->cfg->num_of_ampdu_queues
@@ -248,7 +249,9 @@ int iwlagn_txq_agg_enable(struct iwl_priv *priv, int txq_id,
ra_tid = BUILD_RAxTID(sta_id, tid);
/* Modify device's station table to Tx this TID */
- iwl_sta_tx_modify_enable_tid(priv, sta_id, tid);
+ ret = iwl_sta_tx_modify_enable_tid(priv, sta_id, tid);
+ if (ret)
+ return ret;
spin_lock_irqsave(&priv->lock, flags);
@@ -469,7 +472,8 @@ static void iwlagn_tx_cmd_build_rate(struct iwl_priv *priv,
}
/* Set up antennas */
- priv->mgmt_tx_ant = iwl_toggle_tx_ant(priv, priv->mgmt_tx_ant);
+ priv->mgmt_tx_ant = iwl_toggle_tx_ant(priv, priv->mgmt_tx_ant,
+ priv->hw_params.valid_tx_ant);
rate_flags |= iwl_ant_idx_to_flags(priv->mgmt_tx_ant);
/* Set the rate in the TX cmd */
@@ -567,10 +571,7 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
hdr_len = ieee80211_hdrlen(fc);
/* Find index into station table for destination station */
- if (!info->control.sta)
- sta_id = priv->hw_params.bcast_sta_id;
- else
- sta_id = iwl_sta_id(info->control.sta);
+ sta_id = iwl_sta_id_or_broadcast(priv, info->control.sta);
if (sta_id == IWL_INVALID_STATION) {
IWL_DEBUG_DROP(priv, "Dropping - INVALID STATION: %pM\n",
hdr->addr1);
@@ -598,11 +599,17 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
}
txq_id = get_queue_from_ac(skb_get_queue_mapping(skb));
+
+ /* irqs already disabled/saved above when locking priv->lock */
+ spin_lock(&priv->sta_lock);
+
if (ieee80211_is_data_qos(fc)) {
qc = ieee80211_get_qos_ctl(hdr);
tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK;
- if (unlikely(tid >= MAX_TID_COUNT))
+ if (WARN_ON_ONCE(tid >= MAX_TID_COUNT)) {
+ spin_unlock(&priv->sta_lock);
goto drop_unlock;
+ }
seq_number = priv->stations[sta_id].tid[tid].seq_number;
seq_number &= IEEE80211_SCTL_SEQ;
hdr->seq_ctrl = hdr->seq_ctrl &
@@ -620,15 +627,22 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
swq_id = txq->swq_id;
q = &txq->q;
- if (unlikely(iwl_queue_space(q) < q->high_mark))
+ if (unlikely(iwl_queue_space(q) < q->high_mark)) {
+ spin_unlock(&priv->sta_lock);
goto drop_unlock;
+ }
- if (ieee80211_is_data_qos(fc))
+ if (ieee80211_is_data_qos(fc)) {
priv->stations[sta_id].tid[tid].tfds_in_queue++;
+ if (!ieee80211_has_morefrags(fc))
+ priv->stations[sta_id].tid[tid].seq_number = seq_number;
+ }
+
+ spin_unlock(&priv->sta_lock);
/* Set up driver data for this TFD */
memset(&(txq->txb[q->write_ptr]), 0, sizeof(struct iwl_tx_info));
- txq->txb[q->write_ptr].skb[0] = skb;
+ txq->txb[q->write_ptr].skb = skb;
/* Set up first empty entry in queue's array of Tx/cmd buffers */
out_cmd = txq->cmd[q->write_ptr];
@@ -694,8 +708,8 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
txcmd_phys = pci_map_single(priv->pci_dev,
&out_cmd->hdr, len,
PCI_DMA_BIDIRECTIONAL);
- pci_unmap_addr_set(out_meta, mapping, txcmd_phys);
- pci_unmap_len_set(out_meta, len, len);
+ dma_unmap_addr_set(out_meta, mapping, txcmd_phys);
+ dma_unmap_len_set(out_meta, len, len);
/* Add buffer containing Tx command and MAC(!) header to TFD's
* first entry */
priv->cfg->ops->lib->txq_attach_buf_to_tfd(priv, txq,
@@ -703,8 +717,6 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
if (!ieee80211_has_morefrags(hdr->frame_control)) {
txq->need_update = 1;
- if (qc)
- priv->stations[sta_id].tid[tid].seq_number = seq_number;
} else {
wait_write_ptr = 1;
txq->need_update = 0;
@@ -938,9 +950,12 @@ void iwlagn_txq_ctx_stop(struct iwl_priv *priv)
/* Stop each Tx DMA channel, and wait for it to be idle */
for (ch = 0; ch < priv->hw_params.dma_chnl_num; ch++) {
iwl_write_direct32(priv, FH_TCSR_CHNL_TX_CONFIG_REG(ch), 0x0);
- iwl_poll_direct_bit(priv, FH_TSSR_TX_STATUS_REG,
+ if (iwl_poll_direct_bit(priv, FH_TSSR_TX_STATUS_REG,
FH_TSSR_TX_STATUS_REG_MSK_CHNL_IDLE(ch),
- 1000);
+ 1000))
+ IWL_ERR(priv, "Failing on timeout while stopping"
+ " DMA channel %d [0x%08x]", ch,
+ iwl_read_direct32(priv, FH_TSSR_TX_STATUS_REG));
}
spin_unlock_irqrestore(&priv->lock, flags);
}
@@ -1009,6 +1024,8 @@ int iwlagn_tx_agg_start(struct iwl_priv *priv, struct ieee80211_vif *vif,
if (ret)
return ret;
+ spin_lock_irqsave(&priv->sta_lock, flags);
+ tid_data = &priv->stations[sta_id].tid[tid];
if (tid_data->tfds_in_queue == 0) {
IWL_DEBUG_HT(priv, "HW queue is empty\n");
tid_data->agg.state = IWL_AGG_ON;
@@ -1018,6 +1035,7 @@ int iwlagn_tx_agg_start(struct iwl_priv *priv, struct ieee80211_vif *vif,
tid_data->tfds_in_queue);
tid_data->agg.state = IWL_EMPTYING_HW_QUEUE_ADDBA;
}
+ spin_unlock_irqrestore(&priv->sta_lock, flags);
return ret;
}
@@ -1040,11 +1058,14 @@ int iwlagn_tx_agg_stop(struct iwl_priv *priv, struct ieee80211_vif *vif,
return -ENXIO;
}
+ spin_lock_irqsave(&priv->sta_lock, flags);
+
if (priv->stations[sta_id].tid[tid].agg.state ==
IWL_EMPTYING_HW_QUEUE_ADDBA) {
IWL_DEBUG_HT(priv, "AGG stop before setup done\n");
ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
priv->stations[sta_id].tid[tid].agg.state = IWL_AGG_OFF;
+ spin_unlock_irqrestore(&priv->sta_lock, flags);
return 0;
}
@@ -1062,13 +1083,17 @@ int iwlagn_tx_agg_stop(struct iwl_priv *priv, struct ieee80211_vif *vif,
IWL_DEBUG_HT(priv, "Stopping a non empty AGG HW QUEUE\n");
priv->stations[sta_id].tid[tid].agg.state =
IWL_EMPTYING_HW_QUEUE_DELBA;
+ spin_unlock_irqrestore(&priv->sta_lock, flags);
return 0;
}
IWL_DEBUG_HT(priv, "HW queue is empty\n");
priv->stations[sta_id].tid[tid].agg.state = IWL_AGG_OFF;
- spin_lock_irqsave(&priv->lock, flags);
+ /* do not restore/save irqs */
+ spin_unlock(&priv->sta_lock);
+ spin_lock(&priv->lock);
+
/*
* the only reason this call can fail is queue number out of range,
* which can happen if uCode is reloaded and all the station
@@ -1092,6 +1117,8 @@ int iwlagn_txq_check_empty(struct iwl_priv *priv,
u8 *addr = priv->stations[sta_id].sta.sta.addr;
struct iwl_tid_data *tid_data = &priv->stations[sta_id].tid[tid];
+ WARN_ON(!spin_is_locked(&priv->sta_lock));
+
switch (priv->stations[sta_id].tid[tid].agg.state) {
case IWL_EMPTYING_HW_QUEUE_DELBA:
/* We are reclaiming the last packet of the */
@@ -1116,6 +1143,7 @@ int iwlagn_txq_check_empty(struct iwl_priv *priv,
}
break;
}
+
return 0;
}
@@ -1159,12 +1187,12 @@ int iwlagn_tx_queue_reclaim(struct iwl_priv *priv, int txq_id, int index)
q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd)) {
tx_info = &txq->txb[txq->q.read_ptr];
- iwlagn_tx_status(priv, tx_info->skb[0]);
+ iwlagn_tx_status(priv, tx_info->skb);
- hdr = (struct ieee80211_hdr *)tx_info->skb[0]->data;
+ hdr = (struct ieee80211_hdr *)tx_info->skb->data;
if (hdr && ieee80211_is_data_qos(hdr->frame_control))
nfreed++;
- tx_info->skb[0] = NULL;
+ tx_info->skb = NULL;
if (priv->cfg->ops->lib->txq_inval_byte_cnt_tbl)
priv->cfg->ops->lib->txq_inval_byte_cnt_tbl(priv, txq);
@@ -1188,7 +1216,7 @@ static int iwlagn_tx_status_reply_compressed_ba(struct iwl_priv *priv,
int i, sh, ack;
u16 seq_ctl = le16_to_cpu(ba_resp->seq_ctl);
u16 scd_flow = le16_to_cpu(ba_resp->scd_flow);
- u64 bitmap;
+ u64 bitmap, sent_bitmap;
int successes = 0;
struct ieee80211_tx_info *info;
@@ -1216,24 +1244,26 @@ static int iwlagn_tx_status_reply_compressed_ba(struct iwl_priv *priv,
/* check for success or failure according to the
* transmitted bitmap and block-ack bitmap */
- bitmap &= agg->bitmap;
+ sent_bitmap = bitmap & agg->bitmap;
/* For each frame attempted in aggregation,
* update driver's record of tx frame's status. */
- for (i = 0; i < agg->frame_count ; i++) {
- ack = bitmap & (1ULL << i);
- successes += !!ack;
+ i = 0;
+ while (sent_bitmap) {
+ ack = sent_bitmap & 1ULL;
+ successes += ack;
IWL_DEBUG_TX_REPLY(priv, "%s ON i=%d idx=%d raw=%d\n",
ack ? "ACK" : "NACK", i, (agg->start_idx + i) & 0xff,
agg->start_idx + i);
+ sent_bitmap >>= 1;
+ ++i;
}
- info = IEEE80211_SKB_CB(priv->txq[scd_flow].txb[agg->start_idx].skb[0]);
+ info = IEEE80211_SKB_CB(priv->txq[scd_flow].txb[agg->start_idx].skb);
memset(&info->status, 0, sizeof(info->status));
info->flags |= IEEE80211_TX_STAT_ACK;
info->flags |= IEEE80211_TX_STAT_AMPDU;
info->status.ampdu_ack_len = successes;
- info->status.ampdu_ack_map = bitmap;
info->status.ampdu_len = agg->frame_count;
iwlagn_hwrate_to_tx_control(priv, agg->rate_n_flags, info);
@@ -1281,6 +1311,7 @@ void iwlagn_rx_reply_compressed_ba(struct iwl_priv *priv,
int index;
int sta_id;
int tid;
+ unsigned long flags;
/* "flow" corresponds to Tx queue */
u16 scd_flow = le16_to_cpu(ba_resp->scd_flow);
@@ -1308,7 +1339,7 @@ void iwlagn_rx_reply_compressed_ba(struct iwl_priv *priv,
/* Find index just before block-ack window */
index = iwl_queue_dec_wrap(ba_resp_scd_ssn & 0xff, txq->q.n_bd);
- /* TODO: Need to get this copy more safely - now good for debug */
+ spin_lock_irqsave(&priv->sta_lock, flags);
IWL_DEBUG_TX_REPLY(priv, "REPLY_COMPRESSED_BA [%d] Received from %pM, "
"sta_id = %d\n",
@@ -1344,4 +1375,6 @@ void iwlagn_rx_reply_compressed_ba(struct iwl_priv *priv,
iwlagn_txq_check_empty(priv, sta_id, tid, scd_flow);
}
+
+ spin_unlock_irqrestore(&priv->sta_lock, flags);
}
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c b/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c
index 637286c396f..6f77441cb65 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c
@@ -423,3 +423,126 @@ int iwlagn_alive_notify(struct iwl_priv *priv)
return 0;
}
+
+
+/**
+ * iwl_verify_inst_sparse - verify runtime uCode image in card vs. host,
+ * using sample data 100 bytes apart. If these sample points are good,
+ * it's a pretty good bet that everything between them is good, too.
+ */
+static int iwlcore_verify_inst_sparse(struct iwl_priv *priv, __le32 *image, u32 len)
+{
+ u32 val;
+ int ret = 0;
+ u32 errcnt = 0;
+ u32 i;
+
+ IWL_DEBUG_INFO(priv, "ucode inst image size is %u\n", len);
+
+ for (i = 0; i < len; i += 100, image += 100/sizeof(u32)) {
+ /* read data comes through single port, auto-incr addr */
+ /* NOTE: Use the debugless read so we don't flood kernel log
+ * if IWL_DL_IO is set */
+ iwl_write_direct32(priv, HBUS_TARG_MEM_RADDR,
+ i + IWLAGN_RTC_INST_LOWER_BOUND);
+ val = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT);
+ if (val != le32_to_cpu(*image)) {
+ ret = -EIO;
+ errcnt++;
+ if (errcnt >= 3)
+ break;
+ }
+ }
+
+ return ret;
+}
+
+/**
+ * iwlcore_verify_inst_full - verify runtime uCode image in card vs. host,
+ * looking at all data.
+ */
+static int iwl_verify_inst_full(struct iwl_priv *priv, __le32 *image,
+ u32 len)
+{
+ u32 val;
+ u32 save_len = len;
+ int ret = 0;
+ u32 errcnt;
+
+ IWL_DEBUG_INFO(priv, "ucode inst image size is %u\n", len);
+
+ iwl_write_direct32(priv, HBUS_TARG_MEM_RADDR,
+ IWLAGN_RTC_INST_LOWER_BOUND);
+
+ errcnt = 0;
+ for (; len > 0; len -= sizeof(u32), image++) {
+ /* read data comes through single port, auto-incr addr */
+ /* NOTE: Use the debugless read so we don't flood kernel log
+ * if IWL_DL_IO is set */
+ val = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT);
+ if (val != le32_to_cpu(*image)) {
+ IWL_ERR(priv, "uCode INST section is invalid at "
+ "offset 0x%x, is 0x%x, s/b 0x%x\n",
+ save_len - len, val, le32_to_cpu(*image));
+ ret = -EIO;
+ errcnt++;
+ if (errcnt >= 20)
+ break;
+ }
+ }
+
+ if (!errcnt)
+ IWL_DEBUG_INFO(priv,
+ "ucode image in INSTRUCTION memory is good\n");
+
+ return ret;
+}
+
+/**
+ * iwl_verify_ucode - determine which instruction image is in SRAM,
+ * and verify its contents
+ */
+int iwl_verify_ucode(struct iwl_priv *priv)
+{
+ __le32 *image;
+ u32 len;
+ int ret;
+
+ /* Try bootstrap */
+ image = (__le32 *)priv->ucode_boot.v_addr;
+ len = priv->ucode_boot.len;
+ ret = iwlcore_verify_inst_sparse(priv, image, len);
+ if (!ret) {
+ IWL_DEBUG_INFO(priv, "Bootstrap uCode is good in inst SRAM\n");
+ return 0;
+ }
+
+ /* Try initialize */
+ image = (__le32 *)priv->ucode_init.v_addr;
+ len = priv->ucode_init.len;
+ ret = iwlcore_verify_inst_sparse(priv, image, len);
+ if (!ret) {
+ IWL_DEBUG_INFO(priv, "Initialize uCode is good in inst SRAM\n");
+ return 0;
+ }
+
+ /* Try runtime/protocol */
+ image = (__le32 *)priv->ucode_code.v_addr;
+ len = priv->ucode_code.len;
+ ret = iwlcore_verify_inst_sparse(priv, image, len);
+ if (!ret) {
+ IWL_DEBUG_INFO(priv, "Runtime uCode is good in inst SRAM\n");
+ return 0;
+ }
+
+ IWL_ERR(priv, "NO VALID UCODE IMAGE IN INSTRUCTION SRAM!!\n");
+
+ /* Since nothing seems to match, show first several data entries in
+ * instruction SRAM, so maybe visual inspection will give a clue.
+ * Selection of bootstrap image (vs. other images) is arbitrary. */
+ image = (__le32 *)priv->ucode_boot.v_addr;
+ len = priv->ucode_boot.len;
+ ret = iwl_verify_inst_full(priv, image, len);
+
+ return ret;
+}
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c
index 24aff654fa9..35337b1e7ca 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn.c
@@ -27,6 +27,8 @@
*
*****************************************************************************/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
@@ -120,7 +122,7 @@ int iwl_commit_rxon(struct iwl_priv *priv)
(priv->switch_rxon.channel != priv->staging_rxon.channel)) {
IWL_DEBUG_11H(priv, "abort channel switch on %d\n",
le16_to_cpu(priv->switch_rxon.channel));
- priv->switch_rxon.switch_in_progress = false;
+ iwl_chswitch_done(priv, false);
}
/* If we don't need to send a full RXON, we can use
@@ -292,9 +294,7 @@ static u32 iwl_fill_beacon_frame(struct iwl_priv *priv,
struct ieee80211_hdr *hdr,
int left)
{
- if (!iwl_is_associated(priv) || !priv->ibss_beacon ||
- ((priv->iw_mode != NL80211_IFTYPE_ADHOC) &&
- (priv->iw_mode != NL80211_IFTYPE_AP)))
+ if (!priv->ibss_beacon)
return 0;
if (priv->ibss_beacon->len > left)
@@ -367,7 +367,8 @@ static unsigned int iwl_hw_get_beacon_cmd(struct iwl_priv *priv,
/* Set up packet rate and flags */
rate = iwl_rate_get_lowest_plcp(priv);
- priv->mgmt_tx_ant = iwl_toggle_tx_ant(priv, priv->mgmt_tx_ant);
+ priv->mgmt_tx_ant = iwl_toggle_tx_ant(priv, priv->mgmt_tx_ant,
+ priv->hw_params.valid_tx_ant);
rate_flags = iwl_ant_idx_to_flags(priv->mgmt_tx_ant);
if ((rate >= IWL_FIRST_CCK_RATE) && (rate <= IWL_LAST_CCK_RATE))
rate_flags |= RATE_MCS_CCK_MSK;
@@ -474,18 +475,25 @@ void iwl_hw_txq_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq)
/* Unmap tx_cmd */
if (num_tbs)
pci_unmap_single(dev,
- pci_unmap_addr(&txq->meta[index], mapping),
- pci_unmap_len(&txq->meta[index], len),
+ dma_unmap_addr(&txq->meta[index], mapping),
+ dma_unmap_len(&txq->meta[index], len),
PCI_DMA_BIDIRECTIONAL);
/* Unmap chunks, if any. */
- for (i = 1; i < num_tbs; i++) {
+ for (i = 1; i < num_tbs; i++)
pci_unmap_single(dev, iwl_tfd_tb_get_addr(tfd, i),
iwl_tfd_tb_get_len(tfd, i), PCI_DMA_TODEVICE);
- if (txq->txb) {
- dev_kfree_skb(txq->txb[txq->q.read_ptr].skb[i - 1]);
- txq->txb[txq->q.read_ptr].skb[i - 1] = NULL;
+ /* free SKB */
+ if (txq->txb) {
+ struct sk_buff *skb;
+
+ skb = txq->txb[txq->q.read_ptr].skb;
+
+ /* can be called from irqs-disabled context */
+ if (skb) {
+ dev_kfree_skb_any(skb);
+ txq->txb[txq->q.read_ptr].skb = NULL;
}
}
}
@@ -851,6 +859,24 @@ int iwl_set_pwr_src(struct iwl_priv *priv, enum iwl_pwr_src src)
return 0;
}
+static void iwl_bg_tx_flush(struct work_struct *work)
+{
+ struct iwl_priv *priv =
+ container_of(work, struct iwl_priv, tx_flush);
+
+ if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+ return;
+
+ /* do nothing if rf-kill is on */
+ if (!iwl_is_ready_rf(priv))
+ return;
+
+ if (priv->cfg->ops->lib->txfifo_flush) {
+ IWL_DEBUG_INFO(priv, "device request: flush all tx frames\n");
+ iwlagn_dev_txfifo_flush(priv, IWL_DROP_ALL);
+ }
+}
+
/**
* iwl_setup_rx_handlers - Initialize Rx handler callbacks
*
@@ -933,6 +959,8 @@ void iwl_rx_handle(struct iwl_priv *priv)
fill_rx = 1;
while (i != r) {
+ int len;
+
rxb = rxq->queue[i];
/* If an RXB doesn't have a Rx queue slot associated with it,
@@ -947,8 +975,9 @@ void iwl_rx_handle(struct iwl_priv *priv)
PCI_DMA_FROMDEVICE);
pkt = rxb_addr(rxb);
- trace_iwlwifi_dev_rx(priv, pkt,
- le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK);
+ len = le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK;
+ len += sizeof(u32); /* account for status word */
+ trace_iwlwifi_dev_rx(priv, pkt, len);
/* Reclaim a command buffer only if this packet is a response
* to a (driver-originated) command.
@@ -1450,13 +1479,13 @@ bool iwl_good_ack_health(struct iwl_priv *priv,
actual_ack_cnt_delta =
le32_to_cpu(pkt->u.stats.tx.actual_ack_cnt) -
- le32_to_cpu(priv->statistics.tx.actual_ack_cnt);
+ le32_to_cpu(priv->_agn.statistics.tx.actual_ack_cnt);
expected_ack_cnt_delta =
le32_to_cpu(pkt->u.stats.tx.expected_ack_cnt) -
- le32_to_cpu(priv->statistics.tx.expected_ack_cnt);
+ le32_to_cpu(priv->_agn.statistics.tx.expected_ack_cnt);
ba_timeout_delta =
le32_to_cpu(pkt->u.stats.tx.agg.ba_timeout) -
- le32_to_cpu(priv->statistics.tx.agg.ba_timeout);
+ le32_to_cpu(priv->_agn.statistics.tx.agg.ba_timeout);
if ((priv->_agn.agg_tids_count > 0) &&
(expected_ack_cnt_delta > 0) &&
(((actual_ack_cnt_delta * 100) / expected_ack_cnt_delta)
@@ -1466,12 +1495,17 @@ bool iwl_good_ack_health(struct iwl_priv *priv,
" expected_ack_cnt = %d\n",
actual_ack_cnt_delta, expected_ack_cnt_delta);
-#ifdef CONFIG_IWLWIFI_DEBUG
+#ifdef CONFIG_IWLWIFI_DEBUGFS
+ /*
+ * This is ifdef'ed on DEBUGFS because otherwise the
+ * statistics aren't available. If DEBUGFS is set but
+ * DEBUG is not, these will just compile out.
+ */
IWL_DEBUG_RADIO(priv, "rx_detected_cnt delta = %d\n",
- priv->delta_statistics.tx.rx_detected_cnt);
+ priv->_agn.delta_statistics.tx.rx_detected_cnt);
IWL_DEBUG_RADIO(priv,
"ack_or_ba_timeout_collision delta = %d\n",
- priv->delta_statistics.tx.
+ priv->_agn.delta_statistics.tx.
ack_or_ba_timeout_collision);
#endif
IWL_DEBUG_RADIO(priv, "agg ba_timeout delta = %d\n",
@@ -1658,6 +1692,7 @@ static void iwl_nic_start(struct iwl_priv *priv)
struct iwlagn_ucode_capabilities {
u32 max_probe_length;
+ u32 standard_phy_calibration_size;
};
static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context);
@@ -1694,6 +1729,9 @@ struct iwlagn_firmware_pieces {
size_t inst_size, data_size, init_size, init_data_size, boot_size;
u32 build;
+
+ u32 init_evtlog_ptr, init_evtlog_size, init_errlog_ptr;
+ u32 inst_evtlog_ptr, inst_evtlog_size, inst_errlog_ptr;
};
static int iwlagn_load_legacy_firmware(struct iwl_priv *priv,
@@ -1787,12 +1825,20 @@ static int iwlagn_load_firmware(struct iwl_priv *priv,
const u8 *data;
int wanted_alternative = iwlagn_wanted_ucode_alternative, tmp;
u64 alternatives;
+ u32 tlv_len;
+ enum iwl_ucode_tlv_type tlv_type;
+ const u8 *tlv_data;
- if (len < sizeof(*ucode))
+ if (len < sizeof(*ucode)) {
+ IWL_ERR(priv, "uCode has invalid length: %zd\n", len);
return -EINVAL;
+ }
- if (ucode->magic != cpu_to_le32(IWL_TLV_UCODE_MAGIC))
+ if (ucode->magic != cpu_to_le32(IWL_TLV_UCODE_MAGIC)) {
+ IWL_ERR(priv, "invalid uCode magic: 0X%x\n",
+ le32_to_cpu(ucode->magic));
return -EINVAL;
+ }
/*
* Check which alternatives are present, and "downgrade"
@@ -1818,10 +1864,7 @@ static int iwlagn_load_firmware(struct iwl_priv *priv,
len -= sizeof(*ucode);
while (len >= sizeof(*tlv)) {
- u32 tlv_len;
- enum iwl_ucode_tlv_type tlv_type;
u16 tlv_alt;
- const u8 *tlv_data;
len -= sizeof(*tlv);
tlv = (void *)data;
@@ -1831,8 +1874,11 @@ static int iwlagn_load_firmware(struct iwl_priv *priv,
tlv_alt = le16_to_cpu(tlv->alternative);
tlv_data = tlv->data;
- if (len < tlv_len)
+ if (len < tlv_len) {
+ IWL_ERR(priv, "invalid TLV len: %zd/%u\n",
+ len, tlv_len);
return -EINVAL;
+ }
len -= ALIGN(tlv_len, 4);
data += sizeof(*tlv) + ALIGN(tlv_len, 4);
@@ -1866,20 +1912,77 @@ static int iwlagn_load_firmware(struct iwl_priv *priv,
pieces->boot_size = tlv_len;
break;
case IWL_UCODE_TLV_PROBE_MAX_LEN:
- if (tlv_len != 4)
- return -EINVAL;
+ if (tlv_len != sizeof(u32))
+ goto invalid_tlv_len;
capa->max_probe_length =
- le32_to_cpup((__le32 *)tlv_data);
+ le32_to_cpup((__le32 *)tlv_data);
+ break;
+ case IWL_UCODE_TLV_INIT_EVTLOG_PTR:
+ if (tlv_len != sizeof(u32))
+ goto invalid_tlv_len;
+ pieces->init_evtlog_ptr =
+ le32_to_cpup((__le32 *)tlv_data);
+ break;
+ case IWL_UCODE_TLV_INIT_EVTLOG_SIZE:
+ if (tlv_len != sizeof(u32))
+ goto invalid_tlv_len;
+ pieces->init_evtlog_size =
+ le32_to_cpup((__le32 *)tlv_data);
+ break;
+ case IWL_UCODE_TLV_INIT_ERRLOG_PTR:
+ if (tlv_len != sizeof(u32))
+ goto invalid_tlv_len;
+ pieces->init_errlog_ptr =
+ le32_to_cpup((__le32 *)tlv_data);
+ break;
+ case IWL_UCODE_TLV_RUNT_EVTLOG_PTR:
+ if (tlv_len != sizeof(u32))
+ goto invalid_tlv_len;
+ pieces->inst_evtlog_ptr =
+ le32_to_cpup((__le32 *)tlv_data);
+ break;
+ case IWL_UCODE_TLV_RUNT_EVTLOG_SIZE:
+ if (tlv_len != sizeof(u32))
+ goto invalid_tlv_len;
+ pieces->inst_evtlog_size =
+ le32_to_cpup((__le32 *)tlv_data);
+ break;
+ case IWL_UCODE_TLV_RUNT_ERRLOG_PTR:
+ if (tlv_len != sizeof(u32))
+ goto invalid_tlv_len;
+ pieces->inst_errlog_ptr =
+ le32_to_cpup((__le32 *)tlv_data);
+ break;
+ case IWL_UCODE_TLV_ENHANCE_SENS_TBL:
+ if (tlv_len)
+ goto invalid_tlv_len;
+ priv->enhance_sensitivity_table = true;
+ break;
+ case IWL_UCODE_TLV_PHY_CALIBRATION_SIZE:
+ if (tlv_len != sizeof(u32))
+ goto invalid_tlv_len;
+ capa->standard_phy_calibration_size =
+ le32_to_cpup((__le32 *)tlv_data);
break;
default:
+ IWL_WARN(priv, "unknown TLV: %d\n", tlv_type);
break;
}
}
- if (len)
+ if (len) {
+ IWL_ERR(priv, "invalid TLV after parsing: %zd\n", len);
+ iwl_print_hex_dump(priv, IWL_DL_FW, (u8 *)data, len);
return -EINVAL;
+ }
return 0;
+
+ invalid_tlv_len:
+ IWL_ERR(priv, "TLV %d has invalid size: %u\n", tlv_type, tlv_len);
+ iwl_print_hex_dump(priv, IWL_DL_FW, tlv_data, tlv_len);
+
+ return -EINVAL;
}
/**
@@ -1901,6 +2004,8 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context)
u32 build;
struct iwlagn_ucode_capabilities ucode_capa = {
.max_probe_length = 200,
+ .standard_phy_calibration_size =
+ IWL_MAX_STANDARD_PHY_CALIBRATE_TBL_SIZE,
};
memset(&pieces, 0, sizeof(pieces));
@@ -2063,6 +2168,26 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context)
goto err_pci_alloc;
}
+ /* Now that we can no longer fail, copy information */
+
+ /*
+ * The (size - 16) / 12 formula is based on the information recorded
+ * for each event, which is of mode 1 (including timestamp) for all
+ * new microcodes that include this information.
+ */
+ priv->_agn.init_evtlog_ptr = pieces.init_evtlog_ptr;
+ if (pieces.init_evtlog_size)
+ priv->_agn.init_evtlog_size = (pieces.init_evtlog_size - 16)/12;
+ else
+ priv->_agn.init_evtlog_size = priv->cfg->max_event_log_size;
+ priv->_agn.init_errlog_ptr = pieces.init_errlog_ptr;
+ priv->_agn.inst_evtlog_ptr = pieces.inst_evtlog_ptr;
+ if (pieces.inst_evtlog_size)
+ priv->_agn.inst_evtlog_size = (pieces.inst_evtlog_size - 16)/12;
+ else
+ priv->_agn.inst_evtlog_size = priv->cfg->max_event_log_size;
+ priv->_agn.inst_errlog_ptr = pieces.inst_errlog_ptr;
+
/* Copy images into buffers for card's bus-master reads ... */
/* Runtime instructions (first block of data in file) */
@@ -2102,6 +2227,20 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context)
pieces.boot_size);
memcpy(priv->ucode_boot.v_addr, pieces.boot, pieces.boot_size);
+ /*
+ * figure out the offset of chain noise reset and gain commands
+ * base on the size of standard phy calibration commands table size
+ */
+ if (ucode_capa.standard_phy_calibration_size >
+ IWL_MAX_PHY_CALIBRATE_TBL_SIZE)
+ ucode_capa.standard_phy_calibration_size =
+ IWL_MAX_STANDARD_PHY_CALIBRATE_TBL_SIZE;
+
+ priv->_agn.phy_calib_chain_noise_reset_cmd =
+ ucode_capa.standard_phy_calibration_size;
+ priv->_agn.phy_calib_chain_noise_gain_cmd =
+ ucode_capa.standard_phy_calibration_size + 1;
+
/**************************************************
* This is still part of probe() in a sense...
*
@@ -2172,17 +2311,41 @@ static const char *desc_lookup_text[] = {
"DEBUG_1",
"DEBUG_2",
"DEBUG_3",
- "ADVANCED SYSASSERT"
};
-static const char *desc_lookup(int i)
+static struct { char *name; u8 num; } advanced_lookup[] = {
+ { "NMI_INTERRUPT_WDG", 0x34 },
+ { "SYSASSERT", 0x35 },
+ { "UCODE_VERSION_MISMATCH", 0x37 },
+ { "BAD_COMMAND", 0x38 },
+ { "NMI_INTERRUPT_DATA_ACTION_PT", 0x3C },
+ { "FATAL_ERROR", 0x3D },
+ { "NMI_TRM_HW_ERR", 0x46 },
+ { "NMI_INTERRUPT_TRM", 0x4C },
+ { "NMI_INTERRUPT_BREAK_POINT", 0x54 },
+ { "NMI_INTERRUPT_WDG_RXF_FULL", 0x5C },
+ { "NMI_INTERRUPT_WDG_NO_RBD_RXF_FULL", 0x64 },
+ { "NMI_INTERRUPT_HOST", 0x66 },
+ { "NMI_INTERRUPT_ACTION_PT", 0x7C },
+ { "NMI_INTERRUPT_UNKNOWN", 0x84 },
+ { "NMI_INTERRUPT_INST_ACTION_PT", 0x86 },
+ { "ADVANCED_SYSASSERT", 0 },
+};
+
+static const char *desc_lookup(u32 num)
{
- int max = ARRAY_SIZE(desc_lookup_text) - 1;
+ int i;
+ int max = ARRAY_SIZE(desc_lookup_text);
- if (i < 0 || i > max)
- i = max;
+ if (num < max)
+ return desc_lookup_text[num];
- return desc_lookup_text[i];
+ max = ARRAY_SIZE(advanced_lookup) - 1;
+ for (i = 0; i < max; i++) {
+ if (advanced_lookup[i].num == num)
+ break;;
+ }
+ return advanced_lookup[i].name;
}
#define ERROR_START_OFFSET (1 * sizeof(u32))
@@ -2195,10 +2358,15 @@ void iwl_dump_nic_error_log(struct iwl_priv *priv)
u32 blink1, blink2, ilink1, ilink2;
u32 pc, hcmd;
- if (priv->ucode_type == UCODE_INIT)
+ if (priv->ucode_type == UCODE_INIT) {
base = le32_to_cpu(priv->card_alive_init.error_event_table_ptr);
- else
+ if (!base)
+ base = priv->_agn.init_errlog_ptr;
+ } else {
base = le32_to_cpu(priv->card_alive.error_event_table_ptr);
+ if (!base)
+ base = priv->_agn.inst_errlog_ptr;
+ }
if (!priv->cfg->ops->lib->is_valid_rtc_data_addr(base)) {
IWL_ERR(priv,
@@ -2230,9 +2398,9 @@ void iwl_dump_nic_error_log(struct iwl_priv *priv)
trace_iwlwifi_dev_ucode_error(priv, desc, time, data1, data2, line,
blink1, blink2, ilink1, ilink2);
- IWL_ERR(priv, "Desc Time "
+ IWL_ERR(priv, "Desc Time "
"data1 data2 line\n");
- IWL_ERR(priv, "%-28s (#%02d) %010u 0x%08X 0x%08X %u\n",
+ IWL_ERR(priv, "%-28s (0x%04X) %010u 0x%08X 0x%08X %u\n",
desc_lookup(desc), desc, time, data1, data2, line);
IWL_ERR(priv, "pc blink1 blink2 ilink1 ilink2 hcmd\n");
IWL_ERR(priv, "0x%05X 0x%05X 0x%05X 0x%05X 0x%05X 0x%05X\n",
@@ -2258,10 +2426,16 @@ static int iwl_print_event_log(struct iwl_priv *priv, u32 start_idx,
if (num_events == 0)
return pos;
- if (priv->ucode_type == UCODE_INIT)
+
+ if (priv->ucode_type == UCODE_INIT) {
base = le32_to_cpu(priv->card_alive_init.log_event_table_ptr);
- else
+ if (!base)
+ base = priv->_agn.init_evtlog_ptr;
+ } else {
base = le32_to_cpu(priv->card_alive.log_event_table_ptr);
+ if (!base)
+ base = priv->_agn.inst_evtlog_ptr;
+ }
if (mode == 0)
event_size = 2 * sizeof(u32);
@@ -2363,13 +2537,21 @@ int iwl_dump_nic_event_log(struct iwl_priv *priv, bool full_log,
u32 num_wraps; /* # times uCode wrapped to top of log */
u32 next_entry; /* index of next entry to be written by uCode */
u32 size; /* # entries that we'll print */
+ u32 logsize;
int pos = 0;
size_t bufsz = 0;
- if (priv->ucode_type == UCODE_INIT)
+ if (priv->ucode_type == UCODE_INIT) {
base = le32_to_cpu(priv->card_alive_init.log_event_table_ptr);
- else
+ logsize = priv->_agn.init_evtlog_size;
+ if (!base)
+ base = priv->_agn.init_evtlog_ptr;
+ } else {
base = le32_to_cpu(priv->card_alive.log_event_table_ptr);
+ logsize = priv->_agn.inst_evtlog_size;
+ if (!base)
+ base = priv->_agn.inst_evtlog_ptr;
+ }
if (!priv->cfg->ops->lib->is_valid_rtc_data_addr(base)) {
IWL_ERR(priv,
@@ -2384,16 +2566,16 @@ int iwl_dump_nic_event_log(struct iwl_priv *priv, bool full_log,
num_wraps = iwl_read_targ_mem(priv, base + (2 * sizeof(u32)));
next_entry = iwl_read_targ_mem(priv, base + (3 * sizeof(u32)));
- if (capacity > priv->cfg->max_event_log_size) {
+ if (capacity > logsize) {
IWL_ERR(priv, "Log capacity %d is bogus, limit to %d entries\n",
- capacity, priv->cfg->max_event_log_size);
- capacity = priv->cfg->max_event_log_size;
+ capacity, logsize);
+ capacity = logsize;
}
- if (next_entry > priv->cfg->max_event_log_size) {
+ if (next_entry > logsize) {
IWL_ERR(priv, "Log write index %d is bogus, limit to %d\n",
- next_entry, priv->cfg->max_event_log_size);
- next_entry = priv->cfg->max_event_log_size;
+ next_entry, logsize);
+ next_entry = logsize;
}
size = num_wraps ? capacity : next_entry;
@@ -2518,8 +2700,6 @@ static void iwl_alive_start(struct iwl_priv *priv)
if (priv->cfg->ops->hcmd->set_rxon_chain)
priv->cfg->ops->hcmd->set_rxon_chain(priv);
-
- memcpy(priv->staging_rxon.node_addr, priv->mac_addr, ETH_ALEN);
}
/* Configure Bluetooth device coexistence support */
@@ -2843,9 +3023,17 @@ static void iwl_bg_run_time_calib_work(struct work_struct *work)
}
if (priv->start_calib) {
- iwl_chain_noise_calibration(priv, &priv->statistics);
-
- iwl_sensitivity_calibration(priv, &priv->statistics);
+ if (priv->cfg->bt_statistics) {
+ iwl_chain_noise_calibration(priv,
+ (void *)&priv->_agn.statistics_bt);
+ iwl_sensitivity_calibration(priv,
+ (void *)&priv->_agn.statistics_bt);
+ } else {
+ iwl_chain_noise_calibration(priv,
+ (void *)&priv->_agn.statistics);
+ iwl_sensitivity_calibration(priv,
+ (void *)&priv->_agn.statistics);
+ }
}
mutex_unlock(&priv->mutex);
@@ -2934,20 +3122,16 @@ void iwl_post_associate(struct iwl_priv *priv, struct ieee80211_vif *vif)
IWL_DEBUG_ASSOC(priv, "assoc id %d beacon interval %d\n",
vif->bss_conf.aid, vif->bss_conf.beacon_int);
- if (vif->bss_conf.assoc_capability & WLAN_CAPABILITY_SHORT_PREAMBLE)
+ if (vif->bss_conf.use_short_preamble)
priv->staging_rxon.flags |= RXON_FLG_SHORT_PREAMBLE_MSK;
else
priv->staging_rxon.flags &= ~RXON_FLG_SHORT_PREAMBLE_MSK;
if (priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK) {
- if (vif->bss_conf.assoc_capability &
- WLAN_CAPABILITY_SHORT_SLOT_TIME)
+ if (vif->bss_conf.use_short_slot)
priv->staging_rxon.flags |= RXON_FLG_SHORT_SLOT_MSK;
else
priv->staging_rxon.flags &= ~RXON_FLG_SHORT_SLOT_MSK;
-
- if (vif->type == NL80211_IFTYPE_ADHOC)
- priv->staging_rxon.flags &= ~RXON_FLG_SHORT_SLOT_MSK;
}
iwlcore_commit_rxon(priv);
@@ -3173,8 +3357,7 @@ void iwl_config_ap(struct iwl_priv *priv, struct ieee80211_vif *vif)
priv->staging_rxon.assoc_id = 0;
- if (vif->bss_conf.assoc_capability &
- WLAN_CAPABILITY_SHORT_PREAMBLE)
+ if (vif->bss_conf.use_short_preamble)
priv->staging_rxon.flags |=
RXON_FLG_SHORT_PREAMBLE_MSK;
else
@@ -3182,17 +3365,12 @@ void iwl_config_ap(struct iwl_priv *priv, struct ieee80211_vif *vif)
~RXON_FLG_SHORT_PREAMBLE_MSK;
if (priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK) {
- if (vif->bss_conf.assoc_capability &
- WLAN_CAPABILITY_SHORT_SLOT_TIME)
+ if (vif->bss_conf.use_short_slot)
priv->staging_rxon.flags |=
RXON_FLG_SHORT_SLOT_MSK;
else
priv->staging_rxon.flags &=
~RXON_FLG_SHORT_SLOT_MSK;
-
- if (vif->type == NL80211_IFTYPE_ADHOC)
- priv->staging_rxon.flags &=
- ~RXON_FLG_SHORT_SLOT_MSK;
}
/* restore RXON assoc */
priv->staging_rxon.filter_flags |= RXON_FILTER_ASSOC_MSK;
@@ -3238,17 +3416,9 @@ static int iwl_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
return -EOPNOTSUPP;
}
- if (sta) {
- sta_id = iwl_sta_id(sta);
-
- if (sta_id == IWL_INVALID_STATION) {
- IWL_DEBUG_MAC80211(priv, "leave - %pM not in station map.\n",
- sta->addr);
- return -EINVAL;
- }
- } else {
- sta_id = priv->hw_params.bcast_sta_id;
- }
+ sta_id = iwl_sta_id_or_broadcast(priv, sta);
+ if (sta_id == IWL_INVALID_STATION)
+ return -EINVAL;
mutex_lock(&priv->mutex);
iwl_scan_cancel_timeout(priv, 100);
@@ -3294,13 +3464,32 @@ static int iwl_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
return ret;
}
+/*
+ * switch to RTS/CTS for TX
+ */
+static void iwl_enable_rts_cts(struct iwl_priv *priv)
+{
+
+ if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+ return;
+
+ priv->staging_rxon.flags &= ~RXON_FLG_SELF_CTS_EN;
+ if (!test_bit(STATUS_SCANNING, &priv->status)) {
+ IWL_DEBUG_INFO(priv, "use RTS/CTS protection\n");
+ iwlcore_commit_rxon(priv);
+ } else {
+ /* scanning, defer the request until scan completed */
+ IWL_DEBUG_INFO(priv, "defer setting RTS/CTS protection\n");
+ }
+}
+
static int iwl_mac_ampdu_action(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
enum ieee80211_ampdu_mlme_action action,
struct ieee80211_sta *sta, u16 tid, u16 *ssn)
{
struct iwl_priv *priv = hw->priv;
- int ret;
+ int ret = -EINVAL;
IWL_DEBUG_HT(priv, "A-MPDU action on addr %pM tid %d\n",
sta->addr, tid);
@@ -3308,17 +3497,19 @@ static int iwl_mac_ampdu_action(struct ieee80211_hw *hw,
if (!(priv->cfg->sku & IWL_SKU_N))
return -EACCES;
+ mutex_lock(&priv->mutex);
+
switch (action) {
case IEEE80211_AMPDU_RX_START:
IWL_DEBUG_HT(priv, "start Rx\n");
- return iwl_sta_rx_agg_start(priv, sta, tid, *ssn);
+ ret = iwl_sta_rx_agg_start(priv, sta, tid, *ssn);
+ break;
case IEEE80211_AMPDU_RX_STOP:
IWL_DEBUG_HT(priv, "stop Rx\n");
ret = iwl_sta_rx_agg_stop(priv, sta, tid);
if (test_bit(STATUS_EXIT_PENDING, &priv->status))
- return 0;
- else
- return ret;
+ ret = 0;
+ break;
case IEEE80211_AMPDU_TX_START:
IWL_DEBUG_HT(priv, "start Tx\n");
ret = iwlagn_tx_agg_start(priv, vif, sta, tid, ssn);
@@ -3327,7 +3518,7 @@ static int iwl_mac_ampdu_action(struct ieee80211_hw *hw,
IWL_DEBUG_HT(priv, "priv->_agn.agg_tids_count = %u\n",
priv->_agn.agg_tids_count);
}
- return ret;
+ break;
case IEEE80211_AMPDU_TX_STOP:
IWL_DEBUG_HT(priv, "stop Tx\n");
ret = iwlagn_tx_agg_stop(priv, vif, sta, tid);
@@ -3337,18 +3528,22 @@ static int iwl_mac_ampdu_action(struct ieee80211_hw *hw,
priv->_agn.agg_tids_count);
}
if (test_bit(STATUS_EXIT_PENDING, &priv->status))
- return 0;
- else
- return ret;
+ ret = 0;
+ break;
case IEEE80211_AMPDU_TX_OPERATIONAL:
- /* do nothing */
- return -EOPNOTSUPP;
- default:
- IWL_DEBUG_HT(priv, "unknown\n");
- return -EINVAL;
+ if (priv->cfg->use_rts_for_ht) {
+ /*
+ * switch to RTS/CTS if it is the prefer protection
+ * method for HT traffic
+ */
+ iwl_enable_rts_cts(priv);
+ }
+ ret = 0;
break;
}
- return 0;
+ mutex_unlock(&priv->mutex);
+
+ return ret;
}
static void iwl_mac_sta_notify(struct ieee80211_hw *hw,
@@ -3423,6 +3618,136 @@ static int iwlagn_mac_sta_add(struct ieee80211_hw *hw,
return 0;
}
+static void iwl_mac_channel_switch(struct ieee80211_hw *hw,
+ struct ieee80211_channel_switch *ch_switch)
+{
+ struct iwl_priv *priv = hw->priv;
+ const struct iwl_channel_info *ch_info;
+ struct ieee80211_conf *conf = &hw->conf;
+ struct iwl_ht_config *ht_conf = &priv->current_ht_config;
+ u16 ch;
+ unsigned long flags = 0;
+
+ IWL_DEBUG_MAC80211(priv, "enter\n");
+
+ if (iwl_is_rfkill(priv))
+ goto out_exit;
+
+ if (test_bit(STATUS_EXIT_PENDING, &priv->status) ||
+ test_bit(STATUS_SCANNING, &priv->status))
+ goto out_exit;
+
+ if (!iwl_is_associated(priv))
+ goto out_exit;
+
+ /* channel switch in progress */
+ if (priv->switch_rxon.switch_in_progress == true)
+ goto out_exit;
+
+ mutex_lock(&priv->mutex);
+ if (priv->cfg->ops->lib->set_channel_switch) {
+
+ ch = ieee80211_frequency_to_channel(
+ ch_switch->channel->center_freq);
+ if (le16_to_cpu(priv->active_rxon.channel) != ch) {
+ ch_info = iwl_get_channel_info(priv,
+ conf->channel->band,
+ ch);
+ if (!is_channel_valid(ch_info)) {
+ IWL_DEBUG_MAC80211(priv, "invalid channel\n");
+ goto out;
+ }
+ spin_lock_irqsave(&priv->lock, flags);
+
+ priv->current_ht_config.smps = conf->smps_mode;
+
+ /* Configure HT40 channels */
+ ht_conf->is_ht = conf_is_ht(conf);
+ if (ht_conf->is_ht) {
+ if (conf_is_ht40_minus(conf)) {
+ ht_conf->extension_chan_offset =
+ IEEE80211_HT_PARAM_CHA_SEC_BELOW;
+ ht_conf->is_40mhz = true;
+ } else if (conf_is_ht40_plus(conf)) {
+ ht_conf->extension_chan_offset =
+ IEEE80211_HT_PARAM_CHA_SEC_ABOVE;
+ ht_conf->is_40mhz = true;
+ } else {
+ ht_conf->extension_chan_offset =
+ IEEE80211_HT_PARAM_CHA_SEC_NONE;
+ ht_conf->is_40mhz = false;
+ }
+ } else
+ ht_conf->is_40mhz = false;
+
+ /* if we are switching from ht to 2.4 clear flags
+ * from any ht related info since 2.4 does not
+ * support ht */
+ if ((le16_to_cpu(priv->staging_rxon.channel) != ch))
+ priv->staging_rxon.flags = 0;
+
+ iwl_set_rxon_channel(priv, conf->channel);
+ iwl_set_rxon_ht(priv, ht_conf);
+ iwl_set_flags_for_band(priv, conf->channel->band,
+ priv->vif);
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ iwl_set_rate(priv);
+ /*
+ * at this point, staging_rxon has the
+ * configuration for channel switch
+ */
+ if (priv->cfg->ops->lib->set_channel_switch(priv,
+ ch_switch))
+ priv->switch_rxon.switch_in_progress = false;
+ }
+ }
+out:
+ mutex_unlock(&priv->mutex);
+out_exit:
+ if (!priv->switch_rxon.switch_in_progress)
+ ieee80211_chswitch_done(priv->vif, false);
+ IWL_DEBUG_MAC80211(priv, "leave\n");
+}
+
+static void iwl_mac_flush(struct ieee80211_hw *hw, bool drop)
+{
+ struct iwl_priv *priv = hw->priv;
+
+ mutex_lock(&priv->mutex);
+ IWL_DEBUG_MAC80211(priv, "enter\n");
+
+ /* do not support "flush" */
+ if (!priv->cfg->ops->lib->txfifo_flush)
+ goto done;
+
+ if (test_bit(STATUS_EXIT_PENDING, &priv->status)) {
+ IWL_DEBUG_TX(priv, "Aborting flush due to device shutdown\n");
+ goto done;
+ }
+ if (iwl_is_rfkill(priv)) {
+ IWL_DEBUG_TX(priv, "Aborting flush due to RF Kill\n");
+ goto done;
+ }
+
+ /*
+ * mac80211 will not push any more frames for transmit
+ * until the flush is completed
+ */
+ if (drop) {
+ IWL_DEBUG_MAC80211(priv, "send flush command\n");
+ if (priv->cfg->ops->lib->txfifo_flush(priv, IWL_DROP_ALL)) {
+ IWL_ERR(priv, "flush request fail\n");
+ goto done;
+ }
+ }
+ IWL_DEBUG_MAC80211(priv, "wait transmit/flush all frames\n");
+ iwlagn_wait_tx_queue_empty(priv);
+done:
+ mutex_unlock(&priv->mutex);
+ IWL_DEBUG_MAC80211(priv, "leave\n");
+}
+
/*****************************************************************************
*
* driver setup and teardown
@@ -3439,6 +3764,7 @@ static void iwl_setup_deferred_work(struct iwl_priv *priv)
INIT_WORK(&priv->rx_replenish, iwl_bg_rx_replenish);
INIT_WORK(&priv->beacon_update, iwl_bg_beacon_update);
INIT_WORK(&priv->run_time_calib_work, iwl_bg_run_time_calib_work);
+ INIT_WORK(&priv->tx_flush, iwl_bg_tx_flush);
INIT_DELAYED_WORK(&priv->init_alive_start, iwl_bg_init_alive_start);
INIT_DELAYED_WORK(&priv->alive_start, iwl_bg_alive_start);
@@ -3479,6 +3805,7 @@ static void iwl_cancel_deferred_work(struct iwl_priv *priv)
cancel_delayed_work(&priv->scan_check);
cancel_work_sync(&priv->start_internal_scan);
cancel_delayed_work(&priv->alive_start);
+ cancel_work_sync(&priv->run_time_calib_work);
cancel_work_sync(&priv->beacon_update);
del_timer_sync(&priv->statistics_periodic);
del_timer_sync(&priv->ucode_trace);
@@ -3594,6 +3921,8 @@ static struct ieee80211_ops iwl_hw_ops = {
.sta_notify = iwl_mac_sta_notify,
.sta_add = iwlagn_mac_sta_add,
.sta_remove = iwl_mac_sta_remove,
+ .channel_switch = iwl_mac_channel_switch,
+ .flush = iwl_mac_flush,
};
static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
@@ -3603,7 +3932,7 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
struct ieee80211_hw *hw;
struct iwl_cfg *cfg = (struct iwl_cfg *)(ent->driver_data);
unsigned long flags;
- u16 pci_cmd;
+ u16 pci_cmd, num_mac;
/************************
* 1. Allocating HW data
@@ -3633,9 +3962,6 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
priv->pci_dev = pdev;
priv->inta_mask = CSR_INI_SET_MASK;
-#ifdef CONFIG_IWLWIFI_DEBUG
- atomic_set(&priv->restrict_refcnt, 0);
-#endif
if (iwl_alloc_traffic_mem(priv))
IWL_ERR(priv, "Not enough memory to generate traffic log\n");
@@ -3724,9 +4050,17 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
goto out_free_eeprom;
/* extract MAC Address */
- iwl_eeprom_get_mac(priv, priv->mac_addr);
- IWL_DEBUG_INFO(priv, "MAC address: %pM\n", priv->mac_addr);
- SET_IEEE80211_PERM_ADDR(priv->hw, priv->mac_addr);
+ iwl_eeprom_get_mac(priv, priv->addresses[0].addr);
+ IWL_DEBUG_INFO(priv, "MAC address: %pM\n", priv->addresses[0].addr);
+ priv->hw->wiphy->addresses = priv->addresses;
+ priv->hw->wiphy->n_addresses = 1;
+ num_mac = iwl_eeprom_query16(priv, EEPROM_NUM_MAC_ADDRESS);
+ if (num_mac > 1) {
+ memcpy(priv->addresses[1].addr, priv->addresses[0].addr,
+ ETH_ALEN);
+ priv->addresses[1].addr[5]++;
+ priv->hw->wiphy->n_addresses++;
+ }
/************************
* 5. Setup HW constants
@@ -3993,6 +4327,47 @@ static DEFINE_PCI_DEVICE_TABLE(iwl_hw_card_ids) = {
{IWL_PCI_DEVICE(0x0082, 0x1201, iwl6000g2a_2agn_cfg)},
{IWL_PCI_DEVICE(0x0085, 0x1211, iwl6000g2a_2agn_cfg)},
{IWL_PCI_DEVICE(0x0082, 0x1221, iwl6000g2a_2agn_cfg)},
+ {IWL_PCI_DEVICE(0x0082, 0x1206, iwl6000g2a_2abg_cfg)},
+ {IWL_PCI_DEVICE(0x0085, 0x1216, iwl6000g2a_2abg_cfg)},
+ {IWL_PCI_DEVICE(0x0082, 0x1226, iwl6000g2a_2abg_cfg)},
+ {IWL_PCI_DEVICE(0x0082, 0x1207, iwl6000g2a_2bg_cfg)},
+ {IWL_PCI_DEVICE(0x0082, 0x1301, iwl6000g2a_2agn_cfg)},
+ {IWL_PCI_DEVICE(0x0082, 0x1306, iwl6000g2a_2abg_cfg)},
+ {IWL_PCI_DEVICE(0x0082, 0x1307, iwl6000g2a_2bg_cfg)},
+ {IWL_PCI_DEVICE(0x0082, 0x1321, iwl6000g2a_2agn_cfg)},
+ {IWL_PCI_DEVICE(0x0082, 0x1326, iwl6000g2a_2abg_cfg)},
+ {IWL_PCI_DEVICE(0x0085, 0x1311, iwl6000g2a_2agn_cfg)},
+ {IWL_PCI_DEVICE(0x0085, 0x1316, iwl6000g2a_2abg_cfg)},
+
+/* 6x00 Series Gen2b */
+ {IWL_PCI_DEVICE(0x008F, 0x5105, iwl6000g2b_bgn_cfg)},
+ {IWL_PCI_DEVICE(0x0090, 0x5115, iwl6000g2b_bgn_cfg)},
+ {IWL_PCI_DEVICE(0x008F, 0x5125, iwl6000g2b_bgn_cfg)},
+ {IWL_PCI_DEVICE(0x008F, 0x5107, iwl6000g2b_bg_cfg)},
+ {IWL_PCI_DEVICE(0x008F, 0x5201, iwl6000g2b_2agn_cfg)},
+ {IWL_PCI_DEVICE(0x0090, 0x5211, iwl6000g2b_2agn_cfg)},
+ {IWL_PCI_DEVICE(0x008F, 0x5221, iwl6000g2b_2agn_cfg)},
+ {IWL_PCI_DEVICE(0x008F, 0x5206, iwl6000g2b_2abg_cfg)},
+ {IWL_PCI_DEVICE(0x0090, 0x5216, iwl6000g2b_2abg_cfg)},
+ {IWL_PCI_DEVICE(0x008F, 0x5226, iwl6000g2b_2abg_cfg)},
+ {IWL_PCI_DEVICE(0x008F, 0x5207, iwl6000g2b_2bg_cfg)},
+ {IWL_PCI_DEVICE(0x008A, 0x5301, iwl6000g2b_bgn_cfg)},
+ {IWL_PCI_DEVICE(0x008A, 0x5305, iwl6000g2b_bgn_cfg)},
+ {IWL_PCI_DEVICE(0x008A, 0x5307, iwl6000g2b_bg_cfg)},
+ {IWL_PCI_DEVICE(0x008A, 0x5321, iwl6000g2b_bgn_cfg)},
+ {IWL_PCI_DEVICE(0x008A, 0x5325, iwl6000g2b_bgn_cfg)},
+ {IWL_PCI_DEVICE(0x008B, 0x5311, iwl6000g2b_bgn_cfg)},
+ {IWL_PCI_DEVICE(0x008B, 0x5315, iwl6000g2b_bgn_cfg)},
+ {IWL_PCI_DEVICE(0x0090, 0x5211, iwl6000g2b_2agn_cfg)},
+ {IWL_PCI_DEVICE(0x0090, 0x5215, iwl6000g2b_2bgn_cfg)},
+ {IWL_PCI_DEVICE(0x0090, 0x5216, iwl6000g2b_2abg_cfg)},
+ {IWL_PCI_DEVICE(0x0091, 0x5201, iwl6000g2b_2agn_cfg)},
+ {IWL_PCI_DEVICE(0x0091, 0x5205, iwl6000g2b_2bgn_cfg)},
+ {IWL_PCI_DEVICE(0x0091, 0x5206, iwl6000g2b_2abg_cfg)},
+ {IWL_PCI_DEVICE(0x0091, 0x5207, iwl6000g2b_2bg_cfg)},
+ {IWL_PCI_DEVICE(0x0091, 0x5221, iwl6000g2b_2agn_cfg)},
+ {IWL_PCI_DEVICE(0x0091, 0x5225, iwl6000g2b_2bgn_cfg)},
+ {IWL_PCI_DEVICE(0x0091, 0x5226, iwl6000g2b_2abg_cfg)},
/* 6x50 WiFi/WiMax Series */
{IWL_PCI_DEVICE(0x0087, 0x1301, iwl6050_2agn_cfg)},
@@ -4002,6 +4377,14 @@ static DEFINE_PCI_DEVICE_TABLE(iwl_hw_card_ids) = {
{IWL_PCI_DEVICE(0x0089, 0x1311, iwl6050_2agn_cfg)},
{IWL_PCI_DEVICE(0x0089, 0x1316, iwl6050_2abg_cfg)},
+/* 6x50 WiFi/WiMax Series Gen2 */
+ {IWL_PCI_DEVICE(0x0885, 0x1305, iwl6050g2_bgn_cfg)},
+ {IWL_PCI_DEVICE(0x0885, 0x1306, iwl6050g2_bgn_cfg)},
+ {IWL_PCI_DEVICE(0x0885, 0x1325, iwl6050g2_bgn_cfg)},
+ {IWL_PCI_DEVICE(0x0885, 0x1326, iwl6050g2_bgn_cfg)},
+ {IWL_PCI_DEVICE(0x0886, 0x1315, iwl6050g2_bgn_cfg)},
+ {IWL_PCI_DEVICE(0x0886, 0x1316, iwl6050g2_bgn_cfg)},
+
/* 1000 Series WiFi */
{IWL_PCI_DEVICE(0x0083, 0x1205, iwl1000_bgn_cfg)},
{IWL_PCI_DEVICE(0x0083, 0x1305, iwl1000_bgn_cfg)},
@@ -4036,19 +4419,18 @@ static int __init iwl_init(void)
{
int ret;
- printk(KERN_INFO DRV_NAME ": " DRV_DESCRIPTION ", " DRV_VERSION "\n");
- printk(KERN_INFO DRV_NAME ": " DRV_COPYRIGHT "\n");
+ pr_info(DRV_DESCRIPTION ", " DRV_VERSION "\n");
+ pr_info(DRV_COPYRIGHT "\n");
ret = iwlagn_rate_control_register();
if (ret) {
- printk(KERN_ERR DRV_NAME
- "Unable to register rate control algorithm: %d\n", ret);
+ pr_err("Unable to register rate control algorithm: %d\n", ret);
return ret;
}
ret = pci_register_driver(&iwl_driver);
if (ret) {
- printk(KERN_ERR DRV_NAME "Unable to initialize PCI module\n");
+ pr_err("Unable to initialize PCI module\n");
goto error_register;
}
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.h b/drivers/net/wireless/iwlwifi/iwl-agn.h
index 2d748053358..cc6464dc72e 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn.h
+++ b/drivers/net/wireless/iwlwifi/iwl-agn.h
@@ -65,6 +65,34 @@
#include "iwl-dev.h"
+/* configuration for the _agn devices */
+extern struct iwl_cfg iwl4965_agn_cfg;
+extern struct iwl_cfg iwl5300_agn_cfg;
+extern struct iwl_cfg iwl5100_agn_cfg;
+extern struct iwl_cfg iwl5350_agn_cfg;
+extern struct iwl_cfg iwl5100_bgn_cfg;
+extern struct iwl_cfg iwl5100_abg_cfg;
+extern struct iwl_cfg iwl5150_agn_cfg;
+extern struct iwl_cfg iwl5150_abg_cfg;
+extern struct iwl_cfg iwl6000g2a_2agn_cfg;
+extern struct iwl_cfg iwl6000g2a_2abg_cfg;
+extern struct iwl_cfg iwl6000g2a_2bg_cfg;
+extern struct iwl_cfg iwl6000g2b_bgn_cfg;
+extern struct iwl_cfg iwl6000g2b_bg_cfg;
+extern struct iwl_cfg iwl6000g2b_2agn_cfg;
+extern struct iwl_cfg iwl6000g2b_2abg_cfg;
+extern struct iwl_cfg iwl6000g2b_2bgn_cfg;
+extern struct iwl_cfg iwl6000g2b_2bg_cfg;
+extern struct iwl_cfg iwl6000i_2agn_cfg;
+extern struct iwl_cfg iwl6000i_2abg_cfg;
+extern struct iwl_cfg iwl6000i_2bg_cfg;
+extern struct iwl_cfg iwl6000_3agn_cfg;
+extern struct iwl_cfg iwl6050_2agn_cfg;
+extern struct iwl_cfg iwl6050_2abg_cfg;
+extern struct iwl_cfg iwl6050g2_bgn_cfg;
+extern struct iwl_cfg iwl1000_bgn_cfg;
+extern struct iwl_cfg iwl1000_bg_cfg;
+
extern struct iwl_mod_params iwlagn_mod_params;
extern struct iwl_hcmd_ops iwlagn_hcmd;
extern struct iwl_hcmd_utils_ops iwlagn_hcmd_utils;
@@ -93,6 +121,8 @@ int iwlagn_txq_agg_enable(struct iwl_priv *priv, int txq_id,
int iwlagn_txq_agg_disable(struct iwl_priv *priv, u16 txq_id,
u16 ssn_idx, u8 tx_fifo);
void iwlagn_txq_set_sched(struct iwl_priv *priv, u32 mask);
+void iwl_free_tfds_in_queue(struct iwl_priv *priv,
+ int sta_id, int tid, int freed);
/* uCode */
int iwlagn_load_ucode(struct iwl_priv *priv);
@@ -102,6 +132,7 @@ void iwlagn_rx_calib_complete(struct iwl_priv *priv,
struct iwl_rx_mem_buffer *rxb);
void iwlagn_init_alive_start(struct iwl_priv *priv);
int iwlagn_alive_notify(struct iwl_priv *priv);
+int iwl_verify_ucode(struct iwl_priv *priv);
/* lib */
void iwl_check_abort_status(struct iwl_priv *priv,
@@ -117,6 +148,9 @@ const u8 *iwlagn_eeprom_query_addr(const struct iwl_priv *priv,
void iwlagn_rx_queue_reset(struct iwl_priv *priv, struct iwl_rx_queue *rxq);
int iwlagn_rx_init(struct iwl_priv *priv, struct iwl_rx_queue *rxq);
int iwlagn_hw_nic_init(struct iwl_priv *priv);
+int iwlagn_wait_tx_queue_empty(struct iwl_priv *priv);
+int iwlagn_txfifo_flush(struct iwl_priv *priv, u16 flush_control);
+void iwlagn_dev_txfifo_flush(struct iwl_priv *priv, u16 flush_control);
/* rx */
void iwlagn_rx_queue_restock(struct iwl_priv *priv);
@@ -171,6 +205,16 @@ static inline bool iwl_is_tx_success(u32 status)
(status == TX_STATUS_DIRECT_DONE);
}
+/* rx */
+void iwl_rx_missed_beacon_notif(struct iwl_priv *priv,
+ struct iwl_rx_mem_buffer *rxb);
+bool iwl_good_plcp_health(struct iwl_priv *priv,
+ struct iwl_rx_packet *pkt);
+void iwl_rx_statistics(struct iwl_priv *priv,
+ struct iwl_rx_mem_buffer *rxb);
+void iwl_reply_statistics(struct iwl_priv *priv,
+ struct iwl_rx_mem_buffer *rxb);
+
/* scan */
void iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif);
@@ -178,4 +222,8 @@ void iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif);
int iwlagn_manage_ibss_station(struct iwl_priv *priv,
struct ieee80211_vif *vif, bool add);
+/* hcmd */
+int iwlagn_send_rxon_assoc(struct iwl_priv *priv);
+int iwlagn_send_tx_ant_config(struct iwl_priv *priv, u8 valid_tx_ant);
+
#endif /* __iwl_agn_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-calib.h b/drivers/net/wireless/iwlwifi/iwl-calib.h
index 2b7b1df83ba..ba9523fbb30 100644
--- a/drivers/net/wireless/iwlwifi/iwl-calib.h
+++ b/drivers/net/wireless/iwlwifi/iwl-calib.h
@@ -66,10 +66,8 @@
#include "iwl-core.h"
#include "iwl-commands.h"
-void iwl_chain_noise_calibration(struct iwl_priv *priv,
- struct iwl_notif_statistics *stat_resp);
-void iwl_sensitivity_calibration(struct iwl_priv *priv,
- struct iwl_notif_statistics *resp);
+void iwl_chain_noise_calibration(struct iwl_priv *priv, void *stat_resp);
+void iwl_sensitivity_calibration(struct iwl_priv *priv, void *resp);
void iwl_init_sensitivity(struct iwl_priv *priv);
void iwl_reset_run_time_calib(struct iwl_priv *priv);
diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h
index 9aab020c474..60725a5c1b6 100644
--- a/drivers/net/wireless/iwlwifi/iwl-commands.h
+++ b/drivers/net/wireless/iwlwifi/iwl-commands.h
@@ -95,8 +95,9 @@ enum {
/* Multi-Station support */
REPLY_ADD_STA = 0x18,
- REPLY_REMOVE_STA = 0x19, /* not used */
+ REPLY_REMOVE_STA = 0x19,
REPLY_REMOVE_ALL_STA = 0x1a, /* not used */
+ REPLY_TXFIFO_FLUSH = 0x1e,
/* Security */
REPLY_WEPKEY = 0x20,
@@ -227,7 +228,7 @@ struct iwl_cmd_header {
/* command or response/notification data follows immediately */
u8 data[0];
-} __attribute__ ((packed));
+} __packed;
/**
@@ -247,7 +248,7 @@ struct iwl_cmd_header {
struct iwl3945_tx_power {
u8 tx_gain; /* gain for analog radio */
u8 dsp_atten; /* gain for DSP */
-} __attribute__ ((packed));
+} __packed;
/**
* struct iwl3945_power_per_rate
@@ -258,7 +259,7 @@ struct iwl3945_power_per_rate {
u8 rate; /* plcp */
struct iwl3945_tx_power tpc;
u8 reserved;
-} __attribute__ ((packed));
+} __packed;
/**
* iwlagn rate_n_flags bit fields
@@ -389,7 +390,7 @@ union iwl4965_tx_power_dual_stream {
*/
struct tx_power_dual_stream {
__le32 dw;
-} __attribute__ ((packed));
+} __packed;
/**
* struct iwl4965_tx_power_db
@@ -398,7 +399,7 @@ struct tx_power_dual_stream {
*/
struct iwl4965_tx_power_db {
struct tx_power_dual_stream power_tbl[POWER_TABLE_NUM_ENTRIES];
-} __attribute__ ((packed));
+} __packed;
/**
* Command REPLY_TX_POWER_DBM_CMD = 0x98
@@ -412,7 +413,7 @@ struct iwl5000_tx_power_dbm_cmd {
u8 flags;
s8 srv_chan_lmt; /*in half-dBm (e.g. 30 = 15 dBm) */
u8 reserved;
-} __attribute__ ((packed));
+} __packed;
/**
* Command TX_ANT_CONFIGURATION_CMD = 0x98
@@ -422,7 +423,7 @@ struct iwl5000_tx_power_dbm_cmd {
*/
struct iwl_tx_ant_config_cmd {
__le32 valid;
-} __attribute__ ((packed));
+} __packed;
/******************************************************************************
* (0a)
@@ -478,7 +479,7 @@ struct iwl_init_alive_resp {
__le32 therm_r4[2]; /* signed */
__le32 tx_atten[5][2]; /* signed MIMO gain comp, 5 freq groups,
* 2 Tx chains */
-} __attribute__ ((packed));
+} __packed;
/**
@@ -570,7 +571,7 @@ struct iwl_alive_resp {
__le32 error_event_table_ptr; /* SRAM address for error log */
__le32 timestamp;
__le32 is_valid;
-} __attribute__ ((packed));
+} __packed;
/*
* REPLY_ERROR = 0x2 (response only, not a command)
@@ -582,7 +583,7 @@ struct iwl_error_resp {
__le16 bad_cmd_seq_num;
__le32 error_info;
__le64 timestamp;
-} __attribute__ ((packed));
+} __packed;
/******************************************************************************
* (1)
@@ -718,7 +719,7 @@ struct iwl3945_rxon_cmd {
__le32 filter_flags;
__le16 channel;
__le16 reserved5;
-} __attribute__ ((packed));
+} __packed;
struct iwl4965_rxon_cmd {
u8 node_addr[6];
@@ -738,7 +739,7 @@ struct iwl4965_rxon_cmd {
__le16 channel;
u8 ofdm_ht_single_stream_basic_rates;
u8 ofdm_ht_dual_stream_basic_rates;
-} __attribute__ ((packed));
+} __packed;
/* 5000 HW just extend this command */
struct iwl_rxon_cmd {
@@ -763,7 +764,7 @@ struct iwl_rxon_cmd {
u8 reserved5;
__le16 acquisition_data;
__le16 reserved6;
-} __attribute__ ((packed));
+} __packed;
/*
* REPLY_RXON_ASSOC = 0x11 (command, has simple generic response)
@@ -774,7 +775,7 @@ struct iwl3945_rxon_assoc_cmd {
u8 ofdm_basic_rates;
u8 cck_basic_rates;
__le16 reserved;
-} __attribute__ ((packed));
+} __packed;
struct iwl4965_rxon_assoc_cmd {
__le32 flags;
@@ -785,7 +786,7 @@ struct iwl4965_rxon_assoc_cmd {
u8 ofdm_ht_dual_stream_basic_rates;
__le16 rx_chain_select_flags;
__le16 reserved;
-} __attribute__ ((packed));
+} __packed;
struct iwl5000_rxon_assoc_cmd {
__le32 flags;
@@ -800,7 +801,7 @@ struct iwl5000_rxon_assoc_cmd {
__le16 rx_chain_select_flags;
__le16 acquisition_data;
__le32 reserved3;
-} __attribute__ ((packed));
+} __packed;
#define IWL_CONN_MAX_LISTEN_INTERVAL 10
#define IWL_MAX_UCODE_BEACON_INTERVAL 4 /* 4096 */
@@ -816,7 +817,7 @@ struct iwl_rxon_time_cmd {
__le32 beacon_init_val;
__le16 listen_interval;
__le16 reserved;
-} __attribute__ ((packed));
+} __packed;
/*
* REPLY_CHANNEL_SWITCH = 0x72 (command, has simple generic response)
@@ -829,7 +830,7 @@ struct iwl3945_channel_switch_cmd {
__le32 rxon_filter_flags;
__le32 switch_time;
struct iwl3945_power_per_rate power[IWL_MAX_RATES];
-} __attribute__ ((packed));
+} __packed;
struct iwl4965_channel_switch_cmd {
u8 band;
@@ -839,7 +840,7 @@ struct iwl4965_channel_switch_cmd {
__le32 rxon_filter_flags;
__le32 switch_time;
struct iwl4965_tx_power_db tx_power;
-} __attribute__ ((packed));
+} __packed;
/**
* struct iwl5000_channel_switch_cmd
@@ -860,7 +861,7 @@ struct iwl5000_channel_switch_cmd {
__le32 rxon_filter_flags;
__le32 switch_time;
__le32 reserved[2][IWL_PWR_NUM_HT_OFDM_ENTRIES + IWL_PWR_CCK_ENTRIES];
-} __attribute__ ((packed));
+} __packed;
/**
* struct iwl6000_channel_switch_cmd
@@ -881,7 +882,7 @@ struct iwl6000_channel_switch_cmd {
__le32 rxon_filter_flags;
__le32 switch_time;
__le32 reserved[3][IWL_PWR_NUM_HT_OFDM_ENTRIES + IWL_PWR_CCK_ENTRIES];
-} __attribute__ ((packed));
+} __packed;
/*
* CHANNEL_SWITCH_NOTIFICATION = 0x73 (notification only, not a command)
@@ -890,7 +891,7 @@ struct iwl_csa_notification {
__le16 band;
__le16 channel;
__le32 status; /* 0 - OK, 1 - fail */
-} __attribute__ ((packed));
+} __packed;
/******************************************************************************
* (2)
@@ -920,7 +921,7 @@ struct iwl_ac_qos {
u8 aifsn;
u8 reserved1;
__le16 edca_txop;
-} __attribute__ ((packed));
+} __packed;
/* QoS flags defines */
#define QOS_PARAM_FLG_UPDATE_EDCA_MSK cpu_to_le32(0x01)
@@ -939,7 +940,7 @@ struct iwl_ac_qos {
struct iwl_qosparam_cmd {
__le32 qos_flags;
struct iwl_ac_qos ac[AC_NUM];
-} __attribute__ ((packed));
+} __packed;
/******************************************************************************
* (3)
@@ -952,20 +953,19 @@ struct iwl_qosparam_cmd {
/* Special, dedicated locations within device's station table */
#define IWL_AP_ID 0
-#define IWL_MULTICAST_ID 1
#define IWL_STA_ID 2
#define IWL3945_BROADCAST_ID 24
#define IWL3945_STATION_COUNT 25
#define IWL4965_BROADCAST_ID 31
#define IWL4965_STATION_COUNT 32
-#define IWL5000_BROADCAST_ID 15
-#define IWL5000_STATION_COUNT 16
+#define IWLAGN_BROADCAST_ID 15
+#define IWLAGN_STATION_COUNT 16
#define IWL_STATION_COUNT 32 /* MAX(3945,4965)*/
#define IWL_INVALID_STATION 255
-#define STA_FLG_TX_RATE_MSK cpu_to_le32(1 << 2);
-#define STA_FLG_PWR_SAVE_MSK cpu_to_le32(1 << 8);
+#define STA_FLG_TX_RATE_MSK cpu_to_le32(1 << 2)
+#define STA_FLG_PWR_SAVE_MSK cpu_to_le32(1 << 8)
#define STA_FLG_RTS_MIMO_PROT_MSK cpu_to_le32(1 << 17)
#define STA_FLG_AGG_MPDU_8US_MSK cpu_to_le32(1 << 18)
#define STA_FLG_MAX_AGG_SIZE_POS (19)
@@ -1015,7 +1015,7 @@ struct iwl4965_keyinfo {
u8 key_offset;
u8 reserved2;
u8 key[16]; /* 16-byte unicast decryption key */
-} __attribute__ ((packed));
+} __packed;
/* 5000 */
struct iwl_keyinfo {
@@ -1029,7 +1029,7 @@ struct iwl_keyinfo {
__le64 tx_secur_seq_cnt;
__le64 hw_tkip_mic_rx_key;
__le64 hw_tkip_mic_tx_key;
-} __attribute__ ((packed));
+} __packed;
/**
* struct sta_id_modify
@@ -1049,7 +1049,7 @@ struct sta_id_modify {
u8 sta_id;
u8 modify_mask;
__le16 reserved2;
-} __attribute__ ((packed));
+} __packed;
/*
* REPLY_ADD_STA = 0x18 (command)
@@ -1103,7 +1103,7 @@ struct iwl3945_addsta_cmd {
/* Starting Sequence Number for added block-ack support.
* Set modify_mask bit STA_MODIFY_ADDBA_TID_MSK to use this field. */
__le16 add_immediate_ba_ssn;
-} __attribute__ ((packed));
+} __packed;
struct iwl4965_addsta_cmd {
u8 mode; /* 1: modify existing, 0: add new station */
@@ -1140,7 +1140,7 @@ struct iwl4965_addsta_cmd {
__le16 sleep_tx_count;
__le16 reserved2;
-} __attribute__ ((packed));
+} __packed;
/* 5000 */
struct iwl_addsta_cmd {
@@ -1178,7 +1178,7 @@ struct iwl_addsta_cmd {
__le16 sleep_tx_count;
__le16 reserved2;
-} __attribute__ ((packed));
+} __packed;
#define ADD_STA_SUCCESS_MSK 0x1
@@ -1190,7 +1190,7 @@ struct iwl_addsta_cmd {
*/
struct iwl_add_sta_resp {
u8 status; /* ADD_STA_* */
-} __attribute__ ((packed));
+} __packed;
#define REM_STA_SUCCESS_MSK 0x1
/*
@@ -1198,7 +1198,7 @@ struct iwl_add_sta_resp {
*/
struct iwl_rem_sta_resp {
u8 status;
-} __attribute__ ((packed));
+} __packed;
/*
* REPLY_REM_STA = 0x19 (command)
@@ -1208,7 +1208,44 @@ struct iwl_rem_sta_cmd {
u8 reserved[3];
u8 addr[ETH_ALEN]; /* MAC addr of the first station */
u8 reserved2[2];
-} __attribute__ ((packed));
+} __packed;
+
+#define IWL_TX_FIFO_BK_MSK cpu_to_le32(BIT(0))
+#define IWL_TX_FIFO_BE_MSK cpu_to_le32(BIT(1))
+#define IWL_TX_FIFO_VI_MSK cpu_to_le32(BIT(2))
+#define IWL_TX_FIFO_VO_MSK cpu_to_le32(BIT(3))
+#define IWL_AGG_TX_QUEUE_MSK cpu_to_le32(0xffc00)
+
+#define IWL_DROP_SINGLE 0
+#define IWL_DROP_SELECTED 1
+#define IWL_DROP_ALL 2
+
+/*
+ * REPLY_TXFIFO_FLUSH = 0x1e(command and response)
+ *
+ * When using full FIFO flush this command checks the scheduler HW block WR/RD
+ * pointers to check if all the frames were transferred by DMA into the
+ * relevant TX FIFO queue. Only when the DMA is finished and the queue is
+ * empty the command can finish.
+ * This command is used to flush the TXFIFO from transmit commands, it may
+ * operate on single or multiple queues, the command queue can't be flushed by
+ * this command. The command response is returned when all the queue flush
+ * operations are done. Each TX command flushed return response with the FLUSH
+ * status set in the TX response status. When FIFO flush operation is used,
+ * the flush operation ends when both the scheduler DMA done and TXFIFO empty
+ * are set.
+ *
+ * @fifo_control: bit mask for which queues to flush
+ * @flush_control: flush controls
+ * 0: Dump single MSDU
+ * 1: Dump multiple MSDU according to PS, INVALID STA, TTL, TID disable.
+ * 2: Dump all FIFO
+ */
+struct iwl_txfifo_flush_cmd {
+ __le32 fifo_control;
+ __le16 flush_control;
+ __le16 reserved;
+} __packed;
/*
* REPLY_WEP_KEY = 0x20
@@ -1220,7 +1257,7 @@ struct iwl_wep_key {
u8 key_size;
u8 reserved2[3];
u8 key[16];
-} __attribute__ ((packed));
+} __packed;
struct iwl_wep_cmd {
u8 num_keys;
@@ -1228,7 +1265,7 @@ struct iwl_wep_cmd {
u8 flags;
u8 reserved;
struct iwl_wep_key key[0];
-} __attribute__ ((packed));
+} __packed;
#define WEP_KEY_WEP_TYPE 1
#define WEP_KEYS_MAX 4
@@ -1282,7 +1319,7 @@ struct iwl3945_rx_frame_stats {
__le16 sig_avg;
__le16 noise_diff;
u8 payload[0];
-} __attribute__ ((packed));
+} __packed;
struct iwl3945_rx_frame_hdr {
__le16 channel;
@@ -1291,13 +1328,13 @@ struct iwl3945_rx_frame_hdr {
u8 rate;
__le16 len;
u8 payload[0];
-} __attribute__ ((packed));
+} __packed;
struct iwl3945_rx_frame_end {
__le32 status;
__le64 timestamp;
__le32 beacon_timestamp;
-} __attribute__ ((packed));
+} __packed;
/*
* REPLY_3945_RX = 0x1b (response only, not a command)
@@ -1311,7 +1348,7 @@ struct iwl3945_rx_frame {
struct iwl3945_rx_frame_stats stats;
struct iwl3945_rx_frame_hdr hdr;
struct iwl3945_rx_frame_end end;
-} __attribute__ ((packed));
+} __packed;
#define IWL39_RX_FRAME_SIZE (4 + sizeof(struct iwl3945_rx_frame))
@@ -1327,7 +1364,7 @@ struct iwl4965_rx_non_cfg_phy {
__le16 agc_info; /* agc code 0:6, agc dB 7:13, reserved 14:15 */
u8 rssi_info[6]; /* we use even entries, 0/2/4 for A/B/C rssi */
u8 pad[0];
-} __attribute__ ((packed));
+} __packed;
#define IWL50_RX_RES_PHY_CNT 8
@@ -1345,7 +1382,7 @@ struct iwl4965_rx_non_cfg_phy {
struct iwl5000_non_cfg_phy {
__le32 non_cfg_phy[IWL50_RX_RES_PHY_CNT]; /* up to 8 phy entries */
-} __attribute__ ((packed));
+} __packed;
/*
@@ -1365,12 +1402,12 @@ struct iwl_rx_phy_res {
__le32 rate_n_flags; /* RATE_MCS_* */
__le16 byte_count; /* frame's byte-count */
__le16 reserved3;
-} __attribute__ ((packed));
+} __packed;
-struct iwl4965_rx_mpdu_res_start {
+struct iwl_rx_mpdu_res_start {
__le16 byte_count;
__le16 reserved;
-} __attribute__ ((packed));
+} __packed;
/******************************************************************************
@@ -1400,18 +1437,27 @@ struct iwl4965_rx_mpdu_res_start {
/* REPLY_TX Tx flags field */
-/* 1: Use RTS/CTS protocol or CTS-to-self if spec allows it
+/*
+ * 1: Use RTS/CTS protocol or CTS-to-self if spec allows it
* before this frame. if CTS-to-self required check
- * RXON_FLG_SELF_CTS_EN status. */
-#define TX_CMD_FLG_RTS_CTS_MSK cpu_to_le32(1 << 0)
+ * RXON_FLG_SELF_CTS_EN status.
+ * unused in 3945/4965, used in 5000 series and after
+ */
+#define TX_CMD_FLG_PROT_REQUIRE_MSK cpu_to_le32(1 << 0)
-/* 1: Use Request-To-Send protocol before this frame.
- * Mutually exclusive vs. TX_CMD_FLG_CTS_MSK. */
+/*
+ * 1: Use Request-To-Send protocol before this frame.
+ * Mutually exclusive vs. TX_CMD_FLG_CTS_MSK.
+ * used in 3945/4965, unused in 5000 series and after
+ */
#define TX_CMD_FLG_RTS_MSK cpu_to_le32(1 << 1)
-/* 1: Transmit Clear-To-Send to self before this frame.
+/*
+ * 1: Transmit Clear-To-Send to self before this frame.
* Driver should set this for AUTH/DEAUTH/ASSOC-REQ/REASSOC mgmnt frames.
- * Mutually exclusive vs. TX_CMD_FLG_RTS_MSK. */
+ * Mutually exclusive vs. TX_CMD_FLG_RTS_MSK.
+ * used in 3945/4965, unused in 5000 series and after
+ */
#define TX_CMD_FLG_CTS_MSK cpu_to_le32(1 << 2)
/* 1: Expect ACK from receiving station
@@ -1431,8 +1477,11 @@ struct iwl4965_rx_mpdu_res_start {
* Set when Txing a block-ack request frame. Also set TX_CMD_FLG_ACK_MSK. */
#define TX_CMD_FLG_IMM_BA_RSP_MASK cpu_to_le32(1 << 6)
-/* 1: Frame requires full Tx-Op protection.
- * Set this if either RTS or CTS Tx Flag gets set. */
+/*
+ * 1: Frame requires full Tx-Op protection.
+ * Set this if either RTS or CTS Tx Flag gets set.
+ * used in 3945/4965, unused in 5000 series and after
+ */
#define TX_CMD_FLG_FULL_TXOP_PROT_MSK cpu_to_le32(1 << 7)
/* Tx antenna selection field; used only for 3945, reserved (0) for 4965.
@@ -1557,7 +1606,7 @@ struct iwl3945_tx_cmd {
*/
u8 payload[0];
struct ieee80211_hdr hdr[0];
-} __attribute__ ((packed));
+} __packed;
/*
* REPLY_TX = 0x1c (response)
@@ -1569,7 +1618,7 @@ struct iwl3945_tx_resp {
u8 rate;
__le32 wireless_media_time;
__le32 status; /* TX status */
-} __attribute__ ((packed));
+} __packed;
/*
@@ -1581,7 +1630,7 @@ struct iwl_dram_scratch {
u8 try_cnt; /* Tx attempts */
u8 bt_kill_cnt; /* Tx attempts blocked by Bluetooth device */
__le16 reserved;
-} __attribute__ ((packed));
+} __packed;
struct iwl_tx_cmd {
/*
@@ -1660,7 +1709,7 @@ struct iwl_tx_cmd {
*/
u8 payload[0];
struct ieee80211_hdr hdr[0];
-} __attribute__ ((packed));
+} __packed;
/* TX command response is sent after *3945* transmission attempts.
*
@@ -1826,7 +1875,7 @@ enum {
struct agg_tx_status {
__le16 status;
__le16 sequence;
-} __attribute__ ((packed));
+} __packed;
struct iwl4965_tx_resp {
u8 frame_count; /* 1 no aggregation, >1 aggregation */
@@ -1863,7 +1912,7 @@ struct iwl4965_tx_resp {
__le32 status;
struct agg_tx_status agg_status[0]; /* for each agg frame */
} u;
-} __attribute__ ((packed));
+} __packed;
/*
* definitions for initial rate index field
@@ -1927,7 +1976,7 @@ struct iwl5000_tx_resp {
*/
struct agg_tx_status status; /* TX status (in aggregation -
* status of 1st frame) */
-} __attribute__ ((packed));
+} __packed;
/*
* REPLY_COMPRESSED_BA = 0xc5 (response only, not a command)
*
@@ -1945,7 +1994,7 @@ struct iwl_compressed_ba_resp {
__le64 bitmap;
__le16 scd_flow;
__le16 scd_ssn;
-} __attribute__ ((packed));
+} __packed;
/*
* REPLY_TX_PWR_TABLE_CMD = 0x97 (command, has simple generic response)
@@ -1958,14 +2007,14 @@ struct iwl3945_txpowertable_cmd {
u8 reserved;
__le16 channel;
struct iwl3945_power_per_rate power[IWL_MAX_RATES];
-} __attribute__ ((packed));
+} __packed;
struct iwl4965_txpowertable_cmd {
u8 band; /* 0: 5 GHz, 1: 2.4 GHz */
u8 reserved;
__le16 channel;
struct iwl4965_tx_power_db tx_power;
-} __attribute__ ((packed));
+} __packed;
/**
@@ -1987,13 +2036,13 @@ struct iwl3945_rate_scaling_info {
__le16 rate_n_flags;
u8 try_cnt;
u8 next_rate_index;
-} __attribute__ ((packed));
+} __packed;
struct iwl3945_rate_scaling_cmd {
u8 table_id;
u8 reserved[3];
struct iwl3945_rate_scaling_info table[IWL_MAX_RATES];
-} __attribute__ ((packed));
+} __packed;
/*RS_NEW_API: only TLC_RTS remains and moved to bit 0 */
@@ -2040,7 +2089,7 @@ struct iwl_link_qual_general_params {
* TX FIFOs above 3 use same value (typically 0) as TX FIFO 3.
*/
u8 start_rate_index[LINK_QUAL_AC_NUM];
-} __attribute__ ((packed));
+} __packed;
#define LINK_QUAL_AGG_TIME_LIMIT_DEF (4000) /* 4 milliseconds */
#define LINK_QUAL_AGG_TIME_LIMIT_MAX (65535)
@@ -2081,7 +2130,7 @@ struct iwl_link_qual_agg_params {
u8 agg_frame_cnt_limit;
__le32 reserved;
-} __attribute__ ((packed));
+} __packed;
/*
* REPLY_TX_LINK_QUALITY_CMD = 0x4e (command, has simple generic response)
@@ -2287,7 +2336,7 @@ struct iwl_link_quality_cmd {
__le32 rate_n_flags; /* RATE_MCS_*, IWL_RATE_* */
} rs_table[LINK_QUAL_MAX_RETRY_NUM];
__le32 reserved2;
-} __attribute__ ((packed));
+} __packed;
/*
* BT configuration enable flags:
@@ -2328,7 +2377,7 @@ struct iwl_bt_cmd {
u8 reserved;
__le32 kill_ack_mask;
__le32 kill_cts_mask;
-} __attribute__ ((packed));
+} __packed;
/******************************************************************************
* (6)
@@ -2353,7 +2402,7 @@ struct iwl_measure_channel {
u8 channel; /* channel to measure */
u8 type; /* see enum iwl_measure_type */
__le16 reserved;
-} __attribute__ ((packed));
+} __packed;
/*
* REPLY_SPECTRUM_MEASUREMENT_CMD = 0x74 (command)
@@ -2372,7 +2421,7 @@ struct iwl_spectrum_cmd {
__le16 channel_count; /* minimum 1, maximum 10 */
__le16 reserved3;
struct iwl_measure_channel channels[10];
-} __attribute__ ((packed));
+} __packed;
/*
* REPLY_SPECTRUM_MEASUREMENT_CMD = 0x74 (response)
@@ -2383,7 +2432,7 @@ struct iwl_spectrum_resp {
__le16 status; /* 0 - command will be handled
* 1 - cannot handle (conflicts with another
* measurement) */
-} __attribute__ ((packed));
+} __packed;
enum iwl_measurement_state {
IWL_MEASUREMENT_START = 0,
@@ -2406,13 +2455,13 @@ enum iwl_measurement_status {
struct iwl_measurement_histogram {
__le32 ofdm[NUM_ELEMENTS_IN_HISTOGRAM]; /* in 0.8usec counts */
__le32 cck[NUM_ELEMENTS_IN_HISTOGRAM]; /* in 1usec counts */
-} __attribute__ ((packed));
+} __packed;
/* clear channel availability counters */
struct iwl_measurement_cca_counters {
__le32 ofdm;
__le32 cck;
-} __attribute__ ((packed));
+} __packed;
enum iwl_measure_type {
IWL_MEASURE_BASIC = (1 << 0),
@@ -2448,7 +2497,7 @@ struct iwl_spectrum_notification {
struct iwl_measurement_histogram histogram;
__le32 stop_time; /* lower 32-bits of TSF */
__le32 status; /* see iwl_measurement_status */
-} __attribute__ ((packed));
+} __packed;
/******************************************************************************
* (7)
@@ -2504,7 +2553,7 @@ struct iwl3945_powertable_cmd {
__le32 rx_data_timeout;
__le32 tx_data_timeout;
__le32 sleep_interval[IWL_POWER_VEC_SIZE];
-} __attribute__ ((packed));
+} __packed;
struct iwl_powertable_cmd {
__le16 flags;
@@ -2514,7 +2563,7 @@ struct iwl_powertable_cmd {
__le32 tx_data_timeout;
__le32 sleep_interval[IWL_POWER_VEC_SIZE];
__le32 keep_alive_beacons;
-} __attribute__ ((packed));
+} __packed;
/*
* PM_SLEEP_NOTIFICATION = 0x7A (notification only, not a command)
@@ -2527,7 +2576,7 @@ struct iwl_sleep_notification {
__le32 sleep_time;
__le32 tsf_low;
__le32 bcon_timer;
-} __attribute__ ((packed));
+} __packed;
/* Sleep states. 3945 and 4965 identical. */
enum {
@@ -2552,14 +2601,14 @@ enum {
#define CARD_STATE_CMD_HALT 0x02 /* Power down permanently */
struct iwl_card_state_cmd {
__le32 status; /* CARD_STATE_CMD_* request new power state */
-} __attribute__ ((packed));
+} __packed;
/*
* CARD_STATE_NOTIFICATION = 0xa1 (notification only, not a command)
*/
struct iwl_card_state_notif {
__le32 flags;
-} __attribute__ ((packed));
+} __packed;
#define HW_CARD_DISABLED 0x01
#define SW_CARD_DISABLED 0x02
@@ -2570,14 +2619,14 @@ struct iwl_ct_kill_config {
__le32 reserved;
__le32 critical_temperature_M;
__le32 critical_temperature_R;
-} __attribute__ ((packed));
+} __packed;
/* 1000, and 6x00 */
struct iwl_ct_kill_throttling_config {
__le32 critical_temperature_exit;
__le32 reserved;
__le32 critical_temperature_enter;
-} __attribute__ ((packed));
+} __packed;
/******************************************************************************
* (8)
@@ -2622,7 +2671,7 @@ struct iwl3945_scan_channel {
struct iwl3945_tx_power tpc;
__le16 active_dwell; /* in 1024-uSec TU (time units), typ 5-50 */
__le16 passive_dwell; /* in 1024-uSec TU (time units), typ 20-500 */
-} __attribute__ ((packed));
+} __packed;
/* set number of direct probes u8 type */
#define IWL39_SCAN_PROBE_MASK(n) ((BIT(n) | (BIT(n) - BIT(1))))
@@ -2641,7 +2690,7 @@ struct iwl_scan_channel {
u8 dsp_atten; /* gain for DSP */
__le16 active_dwell; /* in 1024-uSec TU (time units), typ 5-50 */
__le16 passive_dwell; /* in 1024-uSec TU (time units), typ 20-500 */
-} __attribute__ ((packed));
+} __packed;
/* set number of direct probes __le32 type */
#define IWL_SCAN_PROBE_MASK(n) cpu_to_le32((BIT(n) | (BIT(n) - BIT(1))))
@@ -2658,7 +2707,7 @@ struct iwl_ssid_ie {
u8 id;
u8 len;
u8 ssid[32];
-} __attribute__ ((packed));
+} __packed;
#define PROBE_OPTION_MAX_3945 4
#define PROBE_OPTION_MAX 20
@@ -2764,7 +2813,7 @@ struct iwl3945_scan_cmd {
* before requesting another scan.
*/
u8 data[0];
-} __attribute__ ((packed));
+} __packed;
struct iwl_scan_cmd {
__le16 len;
@@ -2808,7 +2857,7 @@ struct iwl_scan_cmd {
* before requesting another scan.
*/
u8 data[0];
-} __attribute__ ((packed));
+} __packed;
/* Can abort will notify by complete notification with abort status. */
#define CAN_ABORT_STATUS cpu_to_le32(0x1)
@@ -2820,7 +2869,7 @@ struct iwl_scan_cmd {
*/
struct iwl_scanreq_notification {
__le32 status; /* 1: okay, 2: cannot fulfill request */
-} __attribute__ ((packed));
+} __packed;
/*
* SCAN_START_NOTIFICATION = 0x82 (notification only, not a command)
@@ -2833,7 +2882,7 @@ struct iwl_scanstart_notification {
u8 band;
u8 reserved[2];
__le32 status;
-} __attribute__ ((packed));
+} __packed;
#define SCAN_OWNER_STATUS 0x1;
#define MEASURE_OWNER_STATUS 0x2;
@@ -2849,7 +2898,7 @@ struct iwl_scanresults_notification {
__le32 tsf_low;
__le32 tsf_high;
__le32 statistics[NUMBER_OF_STATISTICS];
-} __attribute__ ((packed));
+} __packed;
/*
* SCAN_COMPLETE_NOTIFICATION = 0x84 (notification only, not a command)
@@ -2861,7 +2910,7 @@ struct iwl_scancomplete_notification {
u8 last_channel;
__le32 tsf_low;
__le32 tsf_high;
-} __attribute__ ((packed));
+} __packed;
/******************************************************************************
@@ -2879,14 +2928,14 @@ struct iwl3945_beacon_notif {
__le32 low_tsf;
__le32 high_tsf;
__le32 ibss_mgr_status;
-} __attribute__ ((packed));
+} __packed;
struct iwl4965_beacon_notif {
struct iwl4965_tx_resp beacon_notify_hdr;
__le32 low_tsf;
__le32 high_tsf;
__le32 ibss_mgr_status;
-} __attribute__ ((packed));
+} __packed;
/*
* REPLY_TX_BEACON = 0x91 (command, has simple generic response)
@@ -2898,7 +2947,7 @@ struct iwl3945_tx_beacon_cmd {
u8 tim_size;
u8 reserved1;
struct ieee80211_hdr frame[0]; /* beacon frame */
-} __attribute__ ((packed));
+} __packed;
struct iwl_tx_beacon_cmd {
struct iwl_tx_cmd tx;
@@ -2906,7 +2955,7 @@ struct iwl_tx_beacon_cmd {
u8 tim_size;
u8 reserved1;
struct ieee80211_hdr frame[0]; /* beacon frame */
-} __attribute__ ((packed));
+} __packed;
/******************************************************************************
* (10)
@@ -2932,7 +2981,7 @@ struct rate_histogram {
__le32 b[SUP_RATE_11B_MAX_NUM_CHANNELS];
__le32 g[SUP_RATE_11G_MAX_NUM_CHANNELS];
} failed;
-} __attribute__ ((packed));
+} __packed;
/* statistics command response */
@@ -2952,7 +3001,7 @@ struct iwl39_statistics_rx_phy {
__le32 rxe_frame_limit_overrun;
__le32 sent_ack_cnt;
__le32 sent_cts_cnt;
-} __attribute__ ((packed));
+} __packed;
struct iwl39_statistics_rx_non_phy {
__le32 bogus_cts; /* CTS received when not expecting CTS */
@@ -2963,13 +3012,13 @@ struct iwl39_statistics_rx_non_phy {
* filtering process */
__le32 non_channel_beacons; /* beacons with our bss id but not on
* our serving channel */
-} __attribute__ ((packed));
+} __packed;
struct iwl39_statistics_rx {
struct iwl39_statistics_rx_phy ofdm;
struct iwl39_statistics_rx_phy cck;
struct iwl39_statistics_rx_non_phy general;
-} __attribute__ ((packed));
+} __packed;
struct iwl39_statistics_tx {
__le32 preamble_cnt;
@@ -2981,20 +3030,21 @@ struct iwl39_statistics_tx {
__le32 ack_timeout;
__le32 expected_ack_cnt;
__le32 actual_ack_cnt;
-} __attribute__ ((packed));
+} __packed;
struct statistics_dbg {
__le32 burst_check;
__le32 burst_count;
- __le32 reserved[4];
-} __attribute__ ((packed));
+ __le32 wait_for_silence_timeout_cnt;
+ __le32 reserved[3];
+} __packed;
struct iwl39_statistics_div {
__le32 tx_on_a;
__le32 tx_on_b;
__le32 exec_time;
__le32 probe_time;
-} __attribute__ ((packed));
+} __packed;
struct iwl39_statistics_general {
__le32 temperature;
@@ -3004,7 +3054,7 @@ struct iwl39_statistics_general {
__le32 slots_idle;
__le32 ttl_timestamp;
struct iwl39_statistics_div div;
-} __attribute__ ((packed));
+} __packed;
struct statistics_rx_phy {
__le32 ina_cnt;
@@ -3027,7 +3077,7 @@ struct statistics_rx_phy {
__le32 mh_format_err;
__le32 re_acq_main_rssi_sum;
__le32 reserved3;
-} __attribute__ ((packed));
+} __packed;
struct statistics_rx_ht_phy {
__le32 plcp_err;
@@ -3040,7 +3090,7 @@ struct statistics_rx_ht_phy {
__le32 agg_mpdu_cnt;
__le32 agg_cnt;
__le32 unsupport_mcs;
-} __attribute__ ((packed));
+} __packed;
#define INTERFERENCE_DATA_AVAILABLE cpu_to_le32(1)
@@ -3075,14 +3125,28 @@ struct statistics_rx_non_phy {
__le32 beacon_energy_a;
__le32 beacon_energy_b;
__le32 beacon_energy_c;
-} __attribute__ ((packed));
+} __packed;
+
+struct statistics_rx_non_phy_bt {
+ struct statistics_rx_non_phy common;
+ /* additional stats for bt */
+ __le32 num_bt_kills;
+ __le32 reserved[2];
+} __packed;
struct statistics_rx {
struct statistics_rx_phy ofdm;
struct statistics_rx_phy cck;
struct statistics_rx_non_phy general;
struct statistics_rx_ht_phy ofdm_ht;
-} __attribute__ ((packed));
+} __packed;
+
+struct statistics_rx_bt {
+ struct statistics_rx_phy ofdm;
+ struct statistics_rx_phy cck;
+ struct statistics_rx_non_phy_bt general;
+ struct statistics_rx_ht_phy ofdm_ht;
+} __packed;
/**
* struct statistics_tx_power - current tx power
@@ -3096,7 +3160,7 @@ struct statistics_tx_power {
u8 ant_b;
u8 ant_c;
u8 reserved;
-} __attribute__ ((packed));
+} __packed;
struct statistics_tx_non_phy_agg {
__le32 ba_timeout;
@@ -3109,7 +3173,7 @@ struct statistics_tx_non_phy_agg {
__le32 underrun;
__le32 bt_prio_kill;
__le32 rx_ba_rsp_cnt;
-} __attribute__ ((packed));
+} __packed;
struct statistics_tx {
__le32 preamble_cnt;
@@ -3134,7 +3198,7 @@ struct statistics_tx {
*/
struct statistics_tx_power tx_power;
__le32 reserved1;
-} __attribute__ ((packed));
+} __packed;
struct statistics_div {
@@ -3144,9 +3208,9 @@ struct statistics_div {
__le32 probe_time;
__le32 reserved1;
__le32 reserved2;
-} __attribute__ ((packed));
+} __packed;
-struct statistics_general {
+struct statistics_general_common {
__le32 temperature; /* radio temperature */
__le32 temperature_m; /* for 5000 and up, this is radio voltage */
struct statistics_dbg dbg;
@@ -3162,9 +3226,33 @@ struct statistics_general {
* in order to get out of bad PHY status
*/
__le32 num_of_sos_states;
+} __packed;
+
+struct statistics_bt_activity {
+ /* Tx statistics */
+ __le32 hi_priority_tx_req_cnt;
+ __le32 hi_priority_tx_denied_cnt;
+ __le32 lo_priority_tx_req_cnt;
+ __le32 lo_priority_tx_denied_cnt;
+ /* Rx statistics */
+ __le32 hi_priority_rx_req_cnt;
+ __le32 hi_priority_rx_denied_cnt;
+ __le32 lo_priority_rx_req_cnt;
+ __le32 lo_priority_rx_denied_cnt;
+} __packed;
+
+struct statistics_general {
+ struct statistics_general_common common;
__le32 reserved2;
__le32 reserved3;
-} __attribute__ ((packed));
+} __packed;
+
+struct statistics_general_bt {
+ struct statistics_general_common common;
+ struct statistics_bt_activity activity;
+ __le32 reserved2;
+ __le32 reserved3;
+} __packed;
#define UCODE_STATISTICS_CLEAR_MSK (0x1 << 0)
#define UCODE_STATISTICS_FREQUENCY_MSK (0x1 << 1)
@@ -3189,7 +3277,7 @@ struct statistics_general {
#define IWL_STATS_CONF_DISABLE_NOTIF cpu_to_le32(0x2)/* see above */
struct iwl_statistics_cmd {
__le32 configuration_flags; /* IWL_STATS_CONF_* */
-} __attribute__ ((packed));
+} __packed;
/*
* STATISTICS_NOTIFICATION = 0x9d (notification only, not a command)
@@ -3214,15 +3302,21 @@ struct iwl3945_notif_statistics {
struct iwl39_statistics_rx rx;
struct iwl39_statistics_tx tx;
struct iwl39_statistics_general general;
-} __attribute__ ((packed));
+} __packed;
struct iwl_notif_statistics {
__le32 flag;
struct statistics_rx rx;
struct statistics_tx tx;
struct statistics_general general;
-} __attribute__ ((packed));
+} __packed;
+struct iwl_bt_notif_statistics {
+ __le32 flag;
+ struct statistics_rx_bt rx;
+ struct statistics_tx tx;
+ struct statistics_general_bt general;
+} __packed;
/*
* MISSED_BEACONS_NOTIFICATION = 0xa2 (notification only, not a command)
@@ -3253,7 +3347,7 @@ struct iwl_missed_beacon_notif {
__le32 total_missed_becons;
__le32 num_expected_beacons;
__le32 num_recvd_beacons;
-} __attribute__ ((packed));
+} __packed;
/******************************************************************************
@@ -3441,6 +3535,41 @@ struct iwl_missed_beacon_notif {
#define HD_AUTO_CORR40_X4_TH_ADD_MIN_INDEX (9)
#define HD_OFDM_ENERGY_TH_IN_INDEX (10)
+/*
+ * Additional table entries in enhance SENSITIVITY_CMD
+ */
+#define HD_INA_NON_SQUARE_DET_OFDM_INDEX (11)
+#define HD_INA_NON_SQUARE_DET_CCK_INDEX (12)
+#define HD_CORR_11_INSTEAD_OF_CORR_9_EN_INDEX (13)
+#define HD_OFDM_NON_SQUARE_DET_SLOPE_MRC_INDEX (14)
+#define HD_OFDM_NON_SQUARE_DET_INTERCEPT_MRC_INDEX (15)
+#define HD_OFDM_NON_SQUARE_DET_SLOPE_INDEX (16)
+#define HD_OFDM_NON_SQUARE_DET_INTERCEPT_INDEX (17)
+#define HD_CCK_NON_SQUARE_DET_SLOPE_MRC_INDEX (18)
+#define HD_CCK_NON_SQUARE_DET_INTERCEPT_MRC_INDEX (19)
+#define HD_CCK_NON_SQUARE_DET_SLOPE_INDEX (20)
+#define HD_CCK_NON_SQUARE_DET_INTERCEPT_INDEX (21)
+#define HD_RESERVED (22)
+
+/* number of entries for enhanced tbl */
+#define ENHANCE_HD_TABLE_SIZE (23)
+
+/* number of additional entries for enhanced tbl */
+#define ENHANCE_HD_TABLE_ENTRIES (ENHANCE_HD_TABLE_SIZE - HD_TABLE_SIZE)
+
+#define HD_INA_NON_SQUARE_DET_OFDM_DATA cpu_to_le16(0)
+#define HD_INA_NON_SQUARE_DET_CCK_DATA cpu_to_le16(0)
+#define HD_CORR_11_INSTEAD_OF_CORR_9_EN_DATA cpu_to_le16(0)
+#define HD_OFDM_NON_SQUARE_DET_SLOPE_MRC_DATA cpu_to_le16(668)
+#define HD_OFDM_NON_SQUARE_DET_INTERCEPT_MRC_DATA cpu_to_le16(4)
+#define HD_OFDM_NON_SQUARE_DET_SLOPE_DATA cpu_to_le16(486)
+#define HD_OFDM_NON_SQUARE_DET_INTERCEPT_DATA cpu_to_le16(37)
+#define HD_CCK_NON_SQUARE_DET_SLOPE_MRC_DATA cpu_to_le16(853)
+#define HD_CCK_NON_SQUARE_DET_INTERCEPT_MRC_DATA cpu_to_le16(4)
+#define HD_CCK_NON_SQUARE_DET_SLOPE_DATA cpu_to_le16(476)
+#define HD_CCK_NON_SQUARE_DET_INTERCEPT_DATA cpu_to_le16(99)
+
+
/* Control field in struct iwl_sensitivity_cmd */
#define SENSITIVITY_CMD_CONTROL_DEFAULT_TABLE cpu_to_le16(0)
#define SENSITIVITY_CMD_CONTROL_WORK_TABLE cpu_to_le16(1)
@@ -3455,7 +3584,15 @@ struct iwl_missed_beacon_notif {
struct iwl_sensitivity_cmd {
__le16 control; /* always use "1" */
__le16 table[HD_TABLE_SIZE]; /* use HD_* as index */
-} __attribute__ ((packed));
+} __packed;
+
+/*
+ *
+ */
+struct iwl_enhance_sensitivity_cmd {
+ __le16 control; /* always use "1" */
+ __le16 enhance_table[ENHANCE_HD_TABLE_SIZE]; /* use HD_* as index */
+} __packed;
/**
@@ -3523,10 +3660,10 @@ enum {
IWL_PHY_CALIBRATE_CRYSTAL_FRQ_CMD = 15,
IWL_PHY_CALIBRATE_BASE_BAND_CMD = 16,
IWL_PHY_CALIBRATE_TX_IQ_PERD_CMD = 17,
- IWL_PHY_CALIBRATE_CHAIN_NOISE_RESET_CMD = 18,
- IWL_PHY_CALIBRATE_CHAIN_NOISE_GAIN_CMD = 19,
+ IWL_MAX_STANDARD_PHY_CALIBRATE_TBL_SIZE = 18,
};
+#define IWL_MAX_PHY_CALIBRATE_TBL_SIZE (253)
#define IWL_CALIB_INIT_CFG_ALL cpu_to_le32(0xffffffff)
@@ -3536,31 +3673,31 @@ struct iwl_calib_cfg_elmnt_s {
__le32 send_res;
__le32 apply_res;
__le32 reserved;
-} __attribute__ ((packed));
+} __packed;
struct iwl_calib_cfg_status_s {
struct iwl_calib_cfg_elmnt_s once;
struct iwl_calib_cfg_elmnt_s perd;
__le32 flags;
-} __attribute__ ((packed));
+} __packed;
struct iwl_calib_cfg_cmd {
struct iwl_calib_cfg_status_s ucd_calib_cfg;
struct iwl_calib_cfg_status_s drv_calib_cfg;
__le32 reserved1;
-} __attribute__ ((packed));
+} __packed;
struct iwl_calib_hdr {
u8 op_code;
u8 first_group;
u8 groups_num;
u8 data_valid;
-} __attribute__ ((packed));
+} __packed;
struct iwl_calib_cmd {
struct iwl_calib_hdr hdr;
u8 data[0];
-} __attribute__ ((packed));
+} __packed;
/* IWL_PHY_CALIBRATE_DIFF_GAIN_CMD (7) */
struct iwl_calib_diff_gain_cmd {
@@ -3569,14 +3706,14 @@ struct iwl_calib_diff_gain_cmd {
s8 diff_gain_b;
s8 diff_gain_c;
u8 reserved1;
-} __attribute__ ((packed));
+} __packed;
struct iwl_calib_xtal_freq_cmd {
struct iwl_calib_hdr hdr;
u8 cap_pin1;
u8 cap_pin2;
u8 pad[2];
-} __attribute__ ((packed));
+} __packed;
/* IWL_PHY_CALIBRATE_CHAIN_NOISE_RESET_CMD */
struct iwl_calib_chain_noise_reset_cmd {
@@ -3590,7 +3727,7 @@ struct iwl_calib_chain_noise_gain_cmd {
u8 delta_gain_1;
u8 delta_gain_2;
u8 pad[2];
-} __attribute__ ((packed));
+} __packed;
/******************************************************************************
* (12)
@@ -3613,7 +3750,7 @@ struct iwl_led_cmd {
u8 on; /* # intervals on while blinking;
* "0", regardless of "off", turns LED off */
u8 reserved;
-} __attribute__ ((packed));
+} __packed;
/*
* station priority table entries
@@ -3749,7 +3886,7 @@ struct iwl_wimax_coex_event_entry {
u8 win_medium_prio;
u8 reserved;
u8 flags;
-} __attribute__ ((packed));
+} __packed;
/* COEX flag masks */
@@ -3766,7 +3903,7 @@ struct iwl_wimax_coex_cmd {
u8 flags;
u8 reserved[3];
struct iwl_wimax_coex_event_entry sta_prio[COEX_NUM_OF_EVENTS];
-} __attribute__ ((packed));
+} __packed;
/*
* Coexistence MEDIUM NOTIFICATION
@@ -3795,7 +3932,7 @@ struct iwl_wimax_coex_cmd {
struct iwl_coex_medium_notification {
__le32 status;
__le32 events;
-} __attribute__ ((packed));
+} __packed;
/*
* Coexistence EVENT Command
@@ -3810,11 +3947,11 @@ struct iwl_coex_event_cmd {
u8 flags;
u8 event;
__le16 reserved;
-} __attribute__ ((packed));
+} __packed;
struct iwl_coex_event_resp {
__le32 status;
-} __attribute__ ((packed));
+} __packed;
/******************************************************************************
@@ -3851,6 +3988,7 @@ struct iwl_rx_packet {
struct iwl_sleep_notification sleep_notif;
struct iwl_spectrum_resp spectrum;
struct iwl_notif_statistics stats;
+ struct iwl_bt_notif_statistics stats_bt;
struct iwl_compressed_ba_resp compressed_ba;
struct iwl_missed_beacon_notif missed_beacon;
struct iwl_coex_medium_notification coex_medium_notif;
@@ -3858,7 +3996,7 @@ struct iwl_rx_packet {
__le32 status;
u8 raw[0];
} u;
-} __attribute__ ((packed));
+} __packed;
int iwl_agn_check_rxon_cmd(struct iwl_priv *priv);
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c
index 5bbc5298ef9..8024d44ce4b 100644
--- a/drivers/net/wireless/iwlwifi/iwl-core.c
+++ b/drivers/net/wireless/iwlwifi/iwl-core.c
@@ -141,13 +141,14 @@ int iwl_hwrate_to_plcp_idx(u32 rate_n_flags)
}
EXPORT_SYMBOL(iwl_hwrate_to_plcp_idx);
-u8 iwl_toggle_tx_ant(struct iwl_priv *priv, u8 ant)
+u8 iwl_toggle_tx_ant(struct iwl_priv *priv, u8 ant, u8 valid)
{
int i;
u8 ind = ant;
+
for (i = 0; i < RATE_ANT_NUM - 1; i++) {
ind = (ind + 1) < RATE_ANT_NUM ? ind + 1 : 0;
- if (priv->hw_params.valid_tx_ant & BIT(ind))
+ if (valid & BIT(ind))
return ind;
}
return ant;
@@ -169,7 +170,7 @@ struct ieee80211_hw *iwl_alloc_all(struct iwl_cfg *cfg,
struct ieee80211_hw *hw =
ieee80211_alloc_hw(sizeof(struct iwl_priv), hw_ops);
if (hw == NULL) {
- printk(KERN_ERR "%s: Can not allocate network device\n",
+ pr_err("%s: Can not allocate network device\n",
cfg->name);
goto out;
}
@@ -457,7 +458,7 @@ u8 iwl_is_ht40_tx_allowed(struct iwl_priv *priv,
if (!sta_ht_inf->ht_supported)
return 0;
}
-#ifdef CONFIG_IWLWIFI_DEBUG
+#ifdef CONFIG_IWLWIFI_DEBUGFS
if (priv->disable_ht40)
return 0;
#endif
@@ -506,11 +507,11 @@ void iwl_setup_rxon_timing(struct iwl_priv *priv, struct ieee80211_vif *vif)
}
beacon_int = iwl_adjust_beacon_interval(beacon_int,
- priv->hw_params.max_beacon_itrvl * 1024);
+ priv->hw_params.max_beacon_itrvl * TIME_UNIT);
priv->rxon_timing.beacon_interval = cpu_to_le16(beacon_int);
tsf = priv->timestamp; /* tsf is modifed by do_div: copy it */
- interval_tm = beacon_int * 1024;
+ interval_tm = beacon_int * TIME_UNIT;
rem = do_div(tsf, interval_tm);
priv->rxon_timing.beacon_init_val = cpu_to_le32(interval_tm - rem);
@@ -932,9 +933,9 @@ int iwl_set_rxon_channel(struct iwl_priv *priv, struct ieee80211_channel *ch)
}
EXPORT_SYMBOL(iwl_set_rxon_channel);
-static void iwl_set_flags_for_band(struct iwl_priv *priv,
- enum ieee80211_band band,
- struct ieee80211_vif *vif)
+void iwl_set_flags_for_band(struct iwl_priv *priv,
+ enum ieee80211_band band,
+ struct ieee80211_vif *vif)
{
if (band == IEEE80211_BAND_5GHZ) {
priv->staging_rxon.flags &=
@@ -943,19 +944,17 @@ static void iwl_set_flags_for_band(struct iwl_priv *priv,
priv->staging_rxon.flags |= RXON_FLG_SHORT_SLOT_MSK;
} else {
/* Copied from iwl_post_associate() */
- if (vif && vif->bss_conf.assoc_capability & WLAN_CAPABILITY_SHORT_SLOT_TIME)
+ if (vif && vif->bss_conf.use_short_slot)
priv->staging_rxon.flags |= RXON_FLG_SHORT_SLOT_MSK;
else
priv->staging_rxon.flags &= ~RXON_FLG_SHORT_SLOT_MSK;
- if (vif && vif->type == NL80211_IFTYPE_ADHOC)
- priv->staging_rxon.flags &= ~RXON_FLG_SHORT_SLOT_MSK;
-
priv->staging_rxon.flags |= RXON_FLG_BAND_24G_MSK;
priv->staging_rxon.flags |= RXON_FLG_AUTO_DETECT_MSK;
priv->staging_rxon.flags &= ~RXON_FLG_CCK_MSK;
}
}
+EXPORT_SYMBOL(iwl_set_flags_for_band);
/*
* initialize rxon structure with default values from eeprom
@@ -1021,15 +1020,17 @@ void iwl_connection_init_rx_config(struct iwl_priv *priv,
/* clear both MIX and PURE40 mode flag */
priv->staging_rxon.flags &= ~(RXON_FLG_CHANNEL_MODE_MIXED |
RXON_FLG_CHANNEL_MODE_PURE_40);
- memcpy(priv->staging_rxon.node_addr, priv->mac_addr, ETH_ALEN);
- memcpy(priv->staging_rxon.wlap_bssid_addr, priv->mac_addr, ETH_ALEN);
+
+ if (vif)
+ memcpy(priv->staging_rxon.node_addr, vif->addr, ETH_ALEN);
+
priv->staging_rxon.ofdm_ht_single_stream_basic_rates = 0xff;
priv->staging_rxon.ofdm_ht_dual_stream_basic_rates = 0xff;
priv->staging_rxon.ofdm_ht_triple_stream_basic_rates = 0xff;
}
EXPORT_SYMBOL(iwl_connection_init_rx_config);
-static void iwl_set_rate(struct iwl_priv *priv)
+void iwl_set_rate(struct iwl_priv *priv)
{
const struct ieee80211_supported_band *hw = NULL;
struct ieee80211_rate *rate;
@@ -1057,6 +1058,21 @@ static void iwl_set_rate(struct iwl_priv *priv)
priv->staging_rxon.ofdm_basic_rates =
(IWL_OFDM_BASIC_RATES_MASK >> IWL_FIRST_OFDM_RATE) & 0xFF;
}
+EXPORT_SYMBOL(iwl_set_rate);
+
+void iwl_chswitch_done(struct iwl_priv *priv, bool is_success)
+{
+ if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+ return;
+
+ if (priv->switch_rxon.switch_in_progress) {
+ ieee80211_chswitch_done(priv->vif, is_success);
+ mutex_lock(&priv->mutex);
+ priv->switch_rxon.switch_in_progress = false;
+ mutex_unlock(&priv->mutex);
+ }
+}
+EXPORT_SYMBOL(iwl_chswitch_done);
void iwl_rx_csa(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
{
@@ -1071,11 +1087,12 @@ void iwl_rx_csa(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
priv->staging_rxon.channel = csa->channel;
IWL_DEBUG_11H(priv, "CSA notif: channel %d\n",
le16_to_cpu(csa->channel));
- } else
+ iwl_chswitch_done(priv, true);
+ } else {
IWL_ERR(priv, "CSA notif (fail) : channel %d\n",
le16_to_cpu(csa->channel));
-
- priv->switch_rxon.switch_in_progress = false;
+ iwl_chswitch_done(priv, false);
+ }
}
}
EXPORT_SYMBOL(iwl_rx_csa);
@@ -1507,130 +1524,6 @@ int iwl_send_statistics_request(struct iwl_priv *priv, u8 flags, bool clear)
}
EXPORT_SYMBOL(iwl_send_statistics_request);
-/**
- * iwl_verify_inst_sparse - verify runtime uCode image in card vs. host,
- * using sample data 100 bytes apart. If these sample points are good,
- * it's a pretty good bet that everything between them is good, too.
- */
-static int iwlcore_verify_inst_sparse(struct iwl_priv *priv, __le32 *image, u32 len)
-{
- u32 val;
- int ret = 0;
- u32 errcnt = 0;
- u32 i;
-
- IWL_DEBUG_INFO(priv, "ucode inst image size is %u\n", len);
-
- for (i = 0; i < len; i += 100, image += 100/sizeof(u32)) {
- /* read data comes through single port, auto-incr addr */
- /* NOTE: Use the debugless read so we don't flood kernel log
- * if IWL_DL_IO is set */
- iwl_write_direct32(priv, HBUS_TARG_MEM_RADDR,
- i + IWL49_RTC_INST_LOWER_BOUND);
- val = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT);
- if (val != le32_to_cpu(*image)) {
- ret = -EIO;
- errcnt++;
- if (errcnt >= 3)
- break;
- }
- }
-
- return ret;
-}
-
-/**
- * iwlcore_verify_inst_full - verify runtime uCode image in card vs. host,
- * looking at all data.
- */
-static int iwl_verify_inst_full(struct iwl_priv *priv, __le32 *image,
- u32 len)
-{
- u32 val;
- u32 save_len = len;
- int ret = 0;
- u32 errcnt;
-
- IWL_DEBUG_INFO(priv, "ucode inst image size is %u\n", len);
-
- iwl_write_direct32(priv, HBUS_TARG_MEM_RADDR,
- IWL49_RTC_INST_LOWER_BOUND);
-
- errcnt = 0;
- for (; len > 0; len -= sizeof(u32), image++) {
- /* read data comes through single port, auto-incr addr */
- /* NOTE: Use the debugless read so we don't flood kernel log
- * if IWL_DL_IO is set */
- val = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT);
- if (val != le32_to_cpu(*image)) {
- IWL_ERR(priv, "uCode INST section is invalid at "
- "offset 0x%x, is 0x%x, s/b 0x%x\n",
- save_len - len, val, le32_to_cpu(*image));
- ret = -EIO;
- errcnt++;
- if (errcnt >= 20)
- break;
- }
- }
-
- if (!errcnt)
- IWL_DEBUG_INFO(priv,
- "ucode image in INSTRUCTION memory is good\n");
-
- return ret;
-}
-
-/**
- * iwl_verify_ucode - determine which instruction image is in SRAM,
- * and verify its contents
- */
-int iwl_verify_ucode(struct iwl_priv *priv)
-{
- __le32 *image;
- u32 len;
- int ret;
-
- /* Try bootstrap */
- image = (__le32 *)priv->ucode_boot.v_addr;
- len = priv->ucode_boot.len;
- ret = iwlcore_verify_inst_sparse(priv, image, len);
- if (!ret) {
- IWL_DEBUG_INFO(priv, "Bootstrap uCode is good in inst SRAM\n");
- return 0;
- }
-
- /* Try initialize */
- image = (__le32 *)priv->ucode_init.v_addr;
- len = priv->ucode_init.len;
- ret = iwlcore_verify_inst_sparse(priv, image, len);
- if (!ret) {
- IWL_DEBUG_INFO(priv, "Initialize uCode is good in inst SRAM\n");
- return 0;
- }
-
- /* Try runtime/protocol */
- image = (__le32 *)priv->ucode_code.v_addr;
- len = priv->ucode_code.len;
- ret = iwlcore_verify_inst_sparse(priv, image, len);
- if (!ret) {
- IWL_DEBUG_INFO(priv, "Runtime uCode is good in inst SRAM\n");
- return 0;
- }
-
- IWL_ERR(priv, "NO VALID UCODE IMAGE IN INSTRUCTION SRAM!!\n");
-
- /* Since nothing seems to match, show first several data entries in
- * instruction SRAM, so maybe visual inspection will give a clue.
- * Selection of bootstrap image (vs. other images) is arbitrary. */
- image = (__le32 *)priv->ucode_boot.v_addr;
- len = priv->ucode_boot.len;
- ret = iwl_verify_inst_full(priv, image, len);
-
- return ret;
-}
-EXPORT_SYMBOL(iwl_verify_ucode);
-
-
void iwl_rf_kill_ct_config(struct iwl_priv *priv)
{
struct iwl_ct_kill_config cmd;
@@ -1855,6 +1748,37 @@ static inline void iwl_set_no_assoc(struct iwl_priv *priv)
iwlcore_commit_rxon(priv);
}
+static int iwl_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb)
+{
+ struct iwl_priv *priv = hw->priv;
+ unsigned long flags;
+ __le64 timestamp;
+
+ IWL_DEBUG_MAC80211(priv, "enter\n");
+
+ if (!iwl_is_ready_rf(priv)) {
+ IWL_DEBUG_MAC80211(priv, "leave - RF not ready\n");
+ return -EIO;
+ }
+
+ spin_lock_irqsave(&priv->lock, flags);
+
+ if (priv->ibss_beacon)
+ dev_kfree_skb(priv->ibss_beacon);
+
+ priv->ibss_beacon = skb;
+
+ timestamp = ((struct ieee80211_mgmt *)skb->data)->u.beacon.timestamp;
+ priv->timestamp = le64_to_cpu(timestamp);
+
+ IWL_DEBUG_MAC80211(priv, "leave\n");
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ priv->cfg->ops->lib->post_associate(priv, priv->vif);
+
+ return 0;
+}
+
void iwl_bss_info_changed(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_bss_conf *bss_conf,
@@ -1870,6 +1794,15 @@ void iwl_bss_info_changed(struct ieee80211_hw *hw,
mutex_lock(&priv->mutex);
+ if (changes & BSS_CHANGED_QOS) {
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ priv->qos_data.qos_active = bss_conf->qos;
+ iwl_update_qos(priv);
+ spin_unlock_irqrestore(&priv->lock, flags);
+ }
+
if (changes & BSS_CHANGED_BEACON && vif->type == NL80211_IFTYPE_AP) {
dev_kfree_skb(priv->ibss_beacon);
priv->ibss_beacon = ieee80211_beacon_get(hw, vif);
@@ -2012,38 +1945,6 @@ void iwl_bss_info_changed(struct ieee80211_hw *hw,
}
EXPORT_SYMBOL(iwl_bss_info_changed);
-int iwl_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb)
-{
- struct iwl_priv *priv = hw->priv;
- unsigned long flags;
- __le64 timestamp;
-
- IWL_DEBUG_MAC80211(priv, "enter\n");
-
- if (!iwl_is_ready_rf(priv)) {
- IWL_DEBUG_MAC80211(priv, "leave - RF not ready\n");
- return -EIO;
- }
-
- spin_lock_irqsave(&priv->lock, flags);
-
- if (priv->ibss_beacon)
- dev_kfree_skb(priv->ibss_beacon);
-
- priv->ibss_beacon = skb;
-
- timestamp = ((struct ieee80211_mgmt *)skb->data)->u.beacon.timestamp;
- priv->timestamp = le64_to_cpu(timestamp);
-
- IWL_DEBUG_MAC80211(priv, "leave\n");
- spin_unlock_irqrestore(&priv->lock, flags);
-
- priv->cfg->ops->lib->post_associate(priv, priv->vif);
-
- return 0;
-}
-EXPORT_SYMBOL(iwl_mac_beacon_update);
-
static int iwl_set_mode(struct iwl_priv *priv, struct ieee80211_vif *vif)
{
iwl_connection_init_rx_config(priv, vif);
@@ -2051,8 +1952,6 @@ static int iwl_set_mode(struct iwl_priv *priv, struct ieee80211_vif *vif)
if (priv->cfg->ops->hcmd->set_rxon_chain)
priv->cfg->ops->hcmd->set_rxon_chain(priv);
- memcpy(priv->staging_rxon.node_addr, priv->mac_addr, ETH_ALEN);
-
return iwlcore_commit_rxon(priv);
}
@@ -2061,7 +1960,8 @@ int iwl_mac_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
struct iwl_priv *priv = hw->priv;
int err = 0;
- IWL_DEBUG_MAC80211(priv, "enter: type %d\n", vif->type);
+ IWL_DEBUG_MAC80211(priv, "enter: type %d, addr %pM\n",
+ vif->type, vif->addr);
mutex_lock(&priv->mutex);
@@ -2079,9 +1979,6 @@ int iwl_mac_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
priv->vif = vif;
priv->iw_mode = vif->type;
- IWL_DEBUG_MAC80211(priv, "Set %pM\n", vif->addr);
- memcpy(priv->mac_addr, vif->addr, ETH_ALEN);
-
err = iwl_set_mode(priv, vif);
if (err)
goto out_err;
@@ -2115,6 +2012,11 @@ void iwl_mac_remove_interface(struct ieee80211_hw *hw,
}
if (priv->vif == vif) {
priv->vif = NULL;
+ if (priv->scan_vif == vif) {
+ ieee80211_scan_completed(priv->hw, true);
+ priv->scan_vif = NULL;
+ priv->scan_request = NULL;
+ }
memset(priv->bssid, 0, ETH_ALEN);
}
mutex_unlock(&priv->mutex);
@@ -2215,22 +2117,10 @@ int iwl_mac_config(struct ieee80211_hw *hw, u32 changed)
iwl_set_flags_for_band(priv, conf->channel->band, priv->vif);
spin_unlock_irqrestore(&priv->lock, flags);
- if (iwl_is_associated(priv) &&
- (le16_to_cpu(priv->active_rxon.channel) != ch) &&
- priv->cfg->ops->lib->set_channel_switch) {
- iwl_set_rate(priv);
- /*
- * at this point, staging_rxon has the
- * configuration for channel switch
- */
- ret = priv->cfg->ops->lib->set_channel_switch(priv,
- ch);
- if (!ret) {
- iwl_print_rx_config_cmd(priv);
- goto out;
- }
- priv->switch_rxon.switch_in_progress = false;
- }
+
+ if (priv->cfg->ops->lib->update_bcast_station)
+ ret = priv->cfg->ops->lib->update_bcast_station(priv);
+
set_ch_out:
/* The list of supported rates and rate mask can be different
* for each band; since the band may have changed, reset
@@ -2252,15 +2142,6 @@ int iwl_mac_config(struct ieee80211_hw *hw, u32 changed)
iwl_set_tx_power(priv, conf->power_level, false);
}
- if (changed & IEEE80211_CONF_CHANGE_QOS) {
- bool qos_active = !!(conf->flags & IEEE80211_CONF_QOS);
-
- spin_lock_irqsave(&priv->lock, flags);
- priv->qos_data.qos_active = qos_active;
- iwl_update_qos(priv);
- spin_unlock_irqrestore(&priv->lock, flags);
- }
-
if (!iwl_is_ready(priv)) {
IWL_DEBUG_MAC80211(priv, "leave - not ready\n");
goto out;
@@ -2588,7 +2469,7 @@ void iwl_update_stats(struct iwl_priv *priv, bool is_tx, __le16 fc, u16 len)
EXPORT_SYMBOL(iwl_update_stats);
#endif
-const static char *get_csr_string(int cmd)
+static const char *get_csr_string(int cmd)
{
switch (cmd) {
IWL_CMD(CSR_HW_IF_CONFIG_REG);
@@ -2659,7 +2540,7 @@ void iwl_dump_csr(struct iwl_priv *priv)
}
EXPORT_SYMBOL(iwl_dump_csr);
-const static char *get_fh_string(int cmd)
+static const char *get_fh_string(int cmd)
{
switch (cmd) {
IWL_CMD(FH_RSCSR_CHNL0_STTS_WPTR_REG);
@@ -2745,7 +2626,7 @@ static void iwl_force_rf_reset(struct iwl_priv *priv)
}
-int iwl_force_reset(struct iwl_priv *priv, int mode)
+int iwl_force_reset(struct iwl_priv *priv, int mode, bool external)
{
struct iwl_force_reset *force_reset;
@@ -2758,12 +2639,14 @@ int iwl_force_reset(struct iwl_priv *priv, int mode)
}
force_reset = &priv->force_reset[mode];
force_reset->reset_request_count++;
- if (force_reset->last_force_reset_jiffies &&
- time_after(force_reset->last_force_reset_jiffies +
- force_reset->reset_duration, jiffies)) {
- IWL_DEBUG_INFO(priv, "force reset rejected\n");
- force_reset->reset_reject_count++;
- return -EAGAIN;
+ if (!external) {
+ if (force_reset->last_force_reset_jiffies &&
+ time_after(force_reset->last_force_reset_jiffies +
+ force_reset->reset_duration, jiffies)) {
+ IWL_DEBUG_INFO(priv, "force reset rejected\n");
+ force_reset->reset_reject_count++;
+ return -EAGAIN;
+ }
}
force_reset->reset_success_count++;
force_reset->last_force_reset_jiffies = jiffies;
@@ -2773,6 +2656,19 @@ int iwl_force_reset(struct iwl_priv *priv, int mode)
iwl_force_rf_reset(priv);
break;
case IWL_FW_RESET:
+ /*
+ * if the request is from external(ex: debugfs),
+ * then always perform the request in regardless the module
+ * parameter setting
+ * if the request is from internal (uCode error or driver
+ * detect failure), then fw_restart module parameter
+ * need to be check before performing firmware reload
+ */
+ if (!external && !priv->cfg->mod_params->restart_fw) {
+ IWL_DEBUG_INFO(priv, "Cancel firmware reload based on "
+ "module parameter setting\n");
+ break;
+ }
IWL_ERR(priv, "On demand firmware reload\n");
/* Set the FW error flag -- cleared on iwl_down */
set_bit(STATUS_FW_ERROR, &priv->status);
@@ -2831,7 +2727,7 @@ static int iwl_check_stuck_queue(struct iwl_priv *priv, int cnt)
"queue %d stuck %d time. Fw reload.\n",
q->id, q->repeat_same_read_ptr);
q->repeat_same_read_ptr = 0;
- iwl_force_reset(priv, IWL_FW_RESET);
+ iwl_force_reset(priv, IWL_FW_RESET, false);
} else {
q->repeat_same_read_ptr++;
IWL_DEBUG_RADIO(priv,
@@ -2881,6 +2777,61 @@ void iwl_bg_monitor_recover(unsigned long data)
}
EXPORT_SYMBOL(iwl_bg_monitor_recover);
+
+/*
+ * extended beacon time format
+ * time in usec will be changed into a 32-bit value in extended:internal format
+ * the extended part is the beacon counts
+ * the internal part is the time in usec within one beacon interval
+ */
+u32 iwl_usecs_to_beacons(struct iwl_priv *priv, u32 usec, u32 beacon_interval)
+{
+ u32 quot;
+ u32 rem;
+ u32 interval = beacon_interval * TIME_UNIT;
+
+ if (!interval || !usec)
+ return 0;
+
+ quot = (usec / interval) &
+ (iwl_beacon_time_mask_high(priv,
+ priv->hw_params.beacon_time_tsf_bits) >>
+ priv->hw_params.beacon_time_tsf_bits);
+ rem = (usec % interval) & iwl_beacon_time_mask_low(priv,
+ priv->hw_params.beacon_time_tsf_bits);
+
+ return (quot << priv->hw_params.beacon_time_tsf_bits) + rem;
+}
+EXPORT_SYMBOL(iwl_usecs_to_beacons);
+
+/* base is usually what we get from ucode with each received frame,
+ * the same as HW timer counter counting down
+ */
+__le32 iwl_add_beacon_time(struct iwl_priv *priv, u32 base,
+ u32 addon, u32 beacon_interval)
+{
+ u32 base_low = base & iwl_beacon_time_mask_low(priv,
+ priv->hw_params.beacon_time_tsf_bits);
+ u32 addon_low = addon & iwl_beacon_time_mask_low(priv,
+ priv->hw_params.beacon_time_tsf_bits);
+ u32 interval = beacon_interval * TIME_UNIT;
+ u32 res = (base & iwl_beacon_time_mask_high(priv,
+ priv->hw_params.beacon_time_tsf_bits)) +
+ (addon & iwl_beacon_time_mask_high(priv,
+ priv->hw_params.beacon_time_tsf_bits));
+
+ if (base_low > addon_low)
+ res += base_low - addon_low;
+ else if (base_low < addon_low) {
+ res += interval + base_low - addon_low;
+ res += (1 << priv->hw_params.beacon_time_tsf_bits);
+ } else
+ res += (1 << priv->hw_params.beacon_time_tsf_bits);
+
+ return cpu_to_le32(res);
+}
+EXPORT_SYMBOL(iwl_add_beacon_time);
+
#ifdef CONFIG_PM
int iwl_pci_suspend(struct pci_dev *pdev, pm_message_t state)
@@ -2908,6 +2859,7 @@ int iwl_pci_resume(struct pci_dev *pdev)
{
struct iwl_priv *priv = pci_get_drvdata(pdev);
int ret;
+ bool hw_rfkill = false;
/*
* We disable the RETRY_TIMEOUT register (0x41) to keep
@@ -2922,6 +2874,17 @@ int iwl_pci_resume(struct pci_dev *pdev)
pci_restore_state(pdev);
iwl_enable_interrupts(priv);
+ if (!(iwl_read32(priv, CSR_GP_CNTRL) &
+ CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW))
+ hw_rfkill = true;
+
+ if (hw_rfkill)
+ set_bit(STATUS_RF_KILL_HW, &priv->status);
+ else
+ clear_bit(STATUS_RF_KILL_HW, &priv->status);
+
+ wiphy_rfkill_set_hw_state(priv->hw->wiphy, hw_rfkill);
+
return 0;
}
EXPORT_SYMBOL(iwl_pci_resume);
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h
index 31775bd9c36..e9d23f2f869 100644
--- a/drivers/net/wireless/iwlwifi/iwl-core.h
+++ b/drivers/net/wireless/iwlwifi/iwl-core.h
@@ -79,6 +79,8 @@ struct iwl_cmd;
.subvendor = PCI_ANY_ID, .subdevice = (subdev), \
.driver_data = (kernel_ulong_t)&(cfg)
+#define TIME_UNIT 1024
+
#define IWL_SKU_G 0x1
#define IWL_SKU_A 0x2
#define IWL_SKU_N 0x8
@@ -123,6 +125,8 @@ struct iwl_debugfs_ops {
size_t count, loff_t *ppos);
ssize_t (*general_stats_read)(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos);
+ ssize_t (*bt_stats_read)(struct file *file, char __user *user_buf,
+ size_t count, loff_t *ppos);
};
struct iwl_temp_ops {
@@ -173,7 +177,8 @@ struct iwl_lib_ops {
void (*dump_nic_error_log)(struct iwl_priv *priv);
void (*dump_csr)(struct iwl_priv *priv);
int (*dump_fh)(struct iwl_priv *priv, char **buf, bool display);
- int (*set_channel_switch)(struct iwl_priv *priv, u16 channel);
+ int (*set_channel_switch)(struct iwl_priv *priv,
+ struct ieee80211_channel_switch *ch_switch);
/* power management */
struct iwl_apm_ops apm_ops;
@@ -193,6 +198,7 @@ struct iwl_lib_ops {
/* station management */
int (*manage_ibss_station)(struct iwl_priv *priv,
struct ieee80211_vif *vif, bool add);
+ int (*update_bcast_station)(struct iwl_priv *priv);
/* recover from tx queue stall */
void (*recover_from_tx_stall)(unsigned long data);
/* check for plcp health */
@@ -201,6 +207,9 @@ struct iwl_lib_ops {
/* check for ack health */
bool (*check_ack_health)(struct iwl_priv *priv,
struct iwl_rx_packet *pkt);
+ int (*txfifo_flush)(struct iwl_priv *priv, u16 flush_control);
+ void (*dev_txfifo_flush)(struct iwl_priv *priv, u16 flush_control);
+
struct iwl_debugfs_ops debugfs_ops;
};
@@ -325,7 +334,10 @@ struct iwl_cfg {
const bool ucode_tracing;
const bool sensitivity_calib_by_driver;
const bool chain_noise_calib_by_driver;
- u8 scan_antennas[IEEE80211_NUM_BANDS];
+ u8 scan_rx_antennas[IEEE80211_NUM_BANDS];
+ u8 scan_tx_antennas[IEEE80211_NUM_BANDS];
+ const bool need_dc_calib;
+ const bool bt_statistics;
};
/***************************
@@ -343,6 +355,9 @@ int iwl_check_rxon_cmd(struct iwl_priv *priv);
int iwl_full_rxon_required(struct iwl_priv *priv);
void iwl_set_rxon_chain(struct iwl_priv *priv);
int iwl_set_rxon_channel(struct iwl_priv *priv, struct ieee80211_channel *ch);
+void iwl_set_flags_for_band(struct iwl_priv *priv,
+ enum ieee80211_band band,
+ struct ieee80211_vif *vif);
u8 iwl_get_single_channel_number(struct iwl_priv *priv,
enum ieee80211_band band);
void iwl_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_config *ht_conf);
@@ -350,6 +365,7 @@ u8 iwl_is_ht40_tx_allowed(struct iwl_priv *priv,
struct ieee80211_sta_ht_cap *sta_ht_inf);
void iwl_connection_init_rx_config(struct iwl_priv *priv,
struct ieee80211_vif *vif);
+void iwl_set_rate(struct iwl_priv *priv);
int iwl_set_decrypted_flag(struct iwl_priv *priv,
struct ieee80211_hdr *hdr,
u32 decrypt_res,
@@ -364,7 +380,6 @@ void iwl_bss_info_changed(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_bss_conf *bss_conf,
u32 changes);
-int iwl_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb);
int iwl_commit_rxon(struct iwl_priv *priv);
int iwl_mac_add_interface(struct ieee80211_hw *hw,
struct ieee80211_vif *vif);
@@ -447,20 +462,11 @@ void iwl_rx_queue_update_write_ptr(struct iwl_priv *priv,
int iwl_rx_queue_space(const struct iwl_rx_queue *q);
void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb);
/* Handlers */
-void iwl_rx_missed_beacon_notif(struct iwl_priv *priv,
- struct iwl_rx_mem_buffer *rxb);
void iwl_rx_spectrum_measure_notif(struct iwl_priv *priv,
struct iwl_rx_mem_buffer *rxb);
-bool iwl_good_plcp_health(struct iwl_priv *priv,
- struct iwl_rx_packet *pkt);
-bool iwl_good_ack_health(struct iwl_priv *priv,
- struct iwl_rx_packet *pkt);
void iwl_recover_from_statistics(struct iwl_priv *priv,
struct iwl_rx_packet *pkt);
-void iwl_rx_statistics(struct iwl_priv *priv,
- struct iwl_rx_mem_buffer *rxb);
-void iwl_reply_statistics(struct iwl_priv *priv,
- struct iwl_rx_mem_buffer *rxb);
+void iwl_chswitch_done(struct iwl_priv *priv, bool is_success);
void iwl_rx_csa(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb);
/* TX helpers */
@@ -474,8 +480,6 @@ int iwl_hw_txq_attach_buf_to_tfd(struct iwl_priv *priv,
dma_addr_t addr, u16 len, u8 reset, u8 pad);
int iwl_hw_tx_queue_init(struct iwl_priv *priv,
struct iwl_tx_queue *txq);
-void iwl_free_tfds_in_queue(struct iwl_priv *priv,
- int sta_id, int tid, int freed);
void iwl_txq_update_write_ptr(struct iwl_priv *priv, struct iwl_tx_queue *txq);
int iwl_tx_queue_init(struct iwl_priv *priv, struct iwl_tx_queue *txq,
int slots_num, u32 txq_id);
@@ -495,7 +499,7 @@ int iwl_hwrate_to_plcp_idx(u32 rate_n_flags);
u8 iwl_rate_get_lowest_plcp(struct iwl_priv *priv);
-u8 iwl_toggle_tx_ant(struct iwl_priv *priv, u8 ant_idx);
+u8 iwl_toggle_tx_ant(struct iwl_priv *priv, u8 ant_idx, u8 valid);
static inline u32 iwl_ant_idx_to_flags(u8 ant_idx)
{
@@ -526,9 +530,9 @@ int iwl_mac_hw_scan(struct ieee80211_hw *hw,
struct cfg80211_scan_request *req);
void iwl_bg_start_internal_scan(struct work_struct *work);
void iwl_internal_short_hw_scan(struct iwl_priv *priv);
-int iwl_force_reset(struct iwl_priv *priv, int mode);
+int iwl_force_reset(struct iwl_priv *priv, int mode, bool external);
u16 iwl_fill_probe_req(struct iwl_priv *priv, struct ieee80211_mgmt *frame,
- const u8 *ie, int ie_len, int left);
+ const u8 *ta, const u8 *ie, int ie_len, int left);
void iwl_setup_rx_scan_handlers(struct iwl_priv *priv);
u16 iwl_get_active_dwell_time(struct iwl_priv *priv,
enum ieee80211_band band,
@@ -595,6 +599,9 @@ static inline u16 iwl_pcie_link_ctl(struct iwl_priv *priv)
}
void iwl_bg_monitor_recover(unsigned long data);
+u32 iwl_usecs_to_beacons(struct iwl_priv *priv, u32 usec, u32 beacon_interval);
+__le32 iwl_add_beacon_time(struct iwl_priv *priv, u32 base,
+ u32 addon, u32 beacon_interval);
#ifdef CONFIG_PM
int iwl_pci_suspend(struct pci_dev *pdev, pm_message_t state);
@@ -693,7 +700,6 @@ extern void iwl_rf_kill_ct_config(struct iwl_priv *priv);
extern void iwl_send_bt_config(struct iwl_priv *priv);
extern int iwl_send_statistics_request(struct iwl_priv *priv,
u8 flags, bool clear);
-extern int iwl_verify_ucode(struct iwl_priv *priv);
extern int iwl_send_lq_cmd(struct iwl_priv *priv,
struct iwl_link_quality_cmd *lq, u8 flags, bool init);
void iwl_apm_stop(struct iwl_priv *priv);
diff --git a/drivers/net/wireless/iwlwifi/iwl-csr.h b/drivers/net/wireless/iwlwifi/iwl-csr.h
index 254c35ae8b3..ecf98e7ac4e 100644
--- a/drivers/net/wireless/iwlwifi/iwl-csr.h
+++ b/drivers/net/wireless/iwlwifi/iwl-csr.h
@@ -298,6 +298,7 @@
#define CSR_HW_REV_TYPE_1000 (0x0000060)
#define CSR_HW_REV_TYPE_6x00 (0x0000070)
#define CSR_HW_REV_TYPE_6x50 (0x0000080)
+#define CSR_HW_REV_TYPE_6x50g2 (0x0000084)
#define CSR_HW_REV_TYPE_6x00g2 (0x00000B0)
#define CSR_HW_REV_TYPE_NONE (0x00000F0)
diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c
index 9659c5d01df..e96a1bb1278 100644
--- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c
+++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c
@@ -106,27 +106,6 @@ static const struct file_operations iwl_dbgfs_##name##_ops = { \
.open = iwl_dbgfs_open_file_generic, \
};
-int iwl_dbgfs_statistics_flag(struct iwl_priv *priv, char *buf, int bufsz)
-{
- int p = 0;
-
- p += scnprintf(buf + p, bufsz - p, "Statistics Flag(0x%X):\n",
- le32_to_cpu(priv->statistics.flag));
- if (le32_to_cpu(priv->statistics.flag) & UCODE_STATISTICS_CLEAR_MSK)
- p += scnprintf(buf + p, bufsz - p,
- "\tStatistics have been cleared\n");
- p += scnprintf(buf + p, bufsz - p, "\tOperational Frequency: %s\n",
- (le32_to_cpu(priv->statistics.flag) &
- UCODE_STATISTICS_FREQUENCY_MSK)
- ? "2.4 GHz" : "5.2 GHz");
- p += scnprintf(buf + p, bufsz - p, "\tTGj Narrow Band: %s\n",
- (le32_to_cpu(priv->statistics.flag) &
- UCODE_STATISTICS_NARROW_BAND_MSK)
- ? "enabled" : "disabled");
- return p;
-}
-EXPORT_SYMBOL(iwl_dbgfs_statistics_flag);
-
static ssize_t iwl_dbgfs_tx_statistics_read(struct file *file,
char __user *user_buf,
size_t count, loff_t *ppos) {
@@ -330,45 +309,35 @@ static ssize_t iwl_dbgfs_stations_read(struct file *file, char __user *user_buf,
for (i = 0; i < max_sta; i++) {
station = &priv->stations[i];
- if (station->used) {
- pos += scnprintf(buf + pos, bufsz - pos,
- "station %d:\ngeneral data:\n", i+1);
- pos += scnprintf(buf + pos, bufsz - pos, "id: %u\n",
- station->sta.sta.sta_id);
- pos += scnprintf(buf + pos, bufsz - pos, "mode: %u\n",
- station->sta.mode);
- pos += scnprintf(buf + pos, bufsz - pos,
- "flags: 0x%x\n",
- station->sta.station_flags_msk);
- pos += scnprintf(buf + pos, bufsz - pos, "tid data:\n");
- pos += scnprintf(buf + pos, bufsz - pos,
- "seq_num\t\ttxq_id");
- pos += scnprintf(buf + pos, bufsz - pos,
- "\tframe_count\twait_for_ba\t");
- pos += scnprintf(buf + pos, bufsz - pos,
- "start_idx\tbitmap0\t");
- pos += scnprintf(buf + pos, bufsz - pos,
- "bitmap1\trate_n_flags");
- pos += scnprintf(buf + pos, bufsz - pos, "\n");
+ if (!station->used)
+ continue;
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "station %d - addr: %pM, flags: %#x\n",
+ i, station->sta.sta.addr,
+ station->sta.station_flags_msk);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "TID\tseq_num\ttxq_id\tframes\ttfds\t");
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "start_idx\tbitmap\t\t\trate_n_flags\n");
- for (j = 0; j < MAX_TID_COUNT; j++) {
- pos += scnprintf(buf + pos, bufsz - pos,
- "[%d]:\t\t%u", j,
- station->tid[j].seq_number);
- pos += scnprintf(buf + pos, bufsz - pos,
- "\t%u\t\t%u\t\t%u\t\t",
- station->tid[j].agg.txq_id,
- station->tid[j].agg.frame_count,
- station->tid[j].agg.wait_for_ba);
+ for (j = 0; j < MAX_TID_COUNT; j++) {
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "%d:\t%#x\t%#x\t%u\t%u\t%u\t\t%#.16llx\t%#x",
+ j, station->tid[j].seq_number,
+ station->tid[j].agg.txq_id,
+ station->tid[j].agg.frame_count,
+ station->tid[j].tfds_in_queue,
+ station->tid[j].agg.start_idx,
+ station->tid[j].agg.bitmap,
+ station->tid[j].agg.rate_n_flags);
+
+ if (station->tid[j].agg.wait_for_ba)
pos += scnprintf(buf + pos, bufsz - pos,
- "%u\t%llu\t%u",
- station->tid[j].agg.start_idx,
- (unsigned long long)station->tid[j].agg.bitmap,
- station->tid[j].agg.rate_n_flags);
- pos += scnprintf(buf + pos, bufsz - pos, "\n");
- }
+ " - waitforba");
pos += scnprintf(buf + pos, bufsz - pos, "\n");
}
+
+ pos += scnprintf(buf + pos, bufsz - pos, "\n");
}
ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
@@ -1049,8 +1018,13 @@ static ssize_t iwl_dbgfs_rx_queue_read(struct file *file,
rxq->write);
pos += scnprintf(buf + pos, bufsz - pos, "free_count: %u\n",
rxq->free_count);
- pos += scnprintf(buf + pos, bufsz - pos, "closed_rb_num: %u\n",
+ if (rxq->rb_stts) {
+ pos += scnprintf(buf + pos, bufsz - pos, "closed_rb_num: %u\n",
le16_to_cpu(rxq->rb_stts->closed_rb_num) & 0x0FFF);
+ } else {
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "closed_rb_num: Not Allocated\n");
+ }
return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
}
@@ -1293,7 +1267,7 @@ static ssize_t iwl_dbgfs_ucode_tracing_read(struct file *file,
char __user *user_buf,
size_t count, loff_t *ppos) {
- struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
+ struct iwl_priv *priv = file->private_data;
int pos = 0;
char buf[128];
const size_t bufsz = sizeof(buf);
@@ -1343,7 +1317,7 @@ static ssize_t iwl_dbgfs_rxon_flags_read(struct file *file,
char __user *user_buf,
size_t count, loff_t *ppos) {
- struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
+ struct iwl_priv *priv = file->private_data;
int len = 0;
char buf[20];
@@ -1355,7 +1329,7 @@ static ssize_t iwl_dbgfs_rxon_filter_flags_read(struct file *file,
char __user *user_buf,
size_t count, loff_t *ppos) {
- struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
+ struct iwl_priv *priv = file->private_data;
int len = 0;
char buf[20];
@@ -1368,7 +1342,7 @@ static ssize_t iwl_dbgfs_fh_reg_read(struct file *file,
char __user *user_buf,
size_t count, loff_t *ppos)
{
- struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
+ struct iwl_priv *priv = file->private_data;
char *buf;
int pos = 0;
ssize_t ret = -EFAULT;
@@ -1430,7 +1404,7 @@ static ssize_t iwl_dbgfs_plcp_delta_read(struct file *file,
char __user *user_buf,
size_t count, loff_t *ppos) {
- struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
+ struct iwl_priv *priv = file->private_data;
int pos = 0;
char buf[12];
const size_t bufsz = sizeof(buf);
@@ -1456,10 +1430,10 @@ static ssize_t iwl_dbgfs_plcp_delta_write(struct file *file,
return -EFAULT;
if (sscanf(buf, "%d", &plcp) != 1)
return -EINVAL;
- if ((plcp <= IWL_MAX_PLCP_ERR_THRESHOLD_MIN) ||
+ if ((plcp < IWL_MAX_PLCP_ERR_THRESHOLD_MIN) ||
(plcp > IWL_MAX_PLCP_ERR_THRESHOLD_MAX))
priv->cfg->plcp_delta_threshold =
- IWL_MAX_PLCP_ERR_THRESHOLD_DEF;
+ IWL_MAX_PLCP_ERR_THRESHOLD_DISABLE;
else
priv->cfg->plcp_delta_threshold = plcp;
return count;
@@ -1513,7 +1487,7 @@ static ssize_t iwl_dbgfs_force_reset_write(struct file *file,
switch (reset) {
case IWL_RF_RESET:
case IWL_FW_RESET:
- ret = iwl_force_reset(priv, reset);
+ ret = iwl_force_reset(priv, reset, true);
break;
default:
return -EINVAL;
@@ -1521,6 +1495,40 @@ static ssize_t iwl_dbgfs_force_reset_write(struct file *file,
return ret ? ret : count;
}
+static ssize_t iwl_dbgfs_txfifo_flush_write(struct file *file,
+ const char __user *user_buf,
+ size_t count, loff_t *ppos) {
+
+ struct iwl_priv *priv = file->private_data;
+ char buf[8];
+ int buf_size;
+ int flush;
+
+ memset(buf, 0, sizeof(buf));
+ buf_size = min(count, sizeof(buf) - 1);
+ if (copy_from_user(buf, user_buf, buf_size))
+ return -EFAULT;
+ if (sscanf(buf, "%d", &flush) != 1)
+ return -EINVAL;
+
+ if (iwl_is_rfkill(priv))
+ return -EFAULT;
+
+ priv->cfg->ops->lib->dev_txfifo_flush(priv, IWL_DROP_ALL);
+
+ return count;
+}
+
+static ssize_t iwl_dbgfs_ucode_bt_stats_read(struct file *file,
+ char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
+
+ return priv->cfg->ops->lib->debugfs_ops.bt_stats_read(file,
+ user_buf, count, ppos);
+}
+
DEBUGFS_READ_FILE_OPS(rx_statistics);
DEBUGFS_READ_FILE_OPS(tx_statistics);
DEBUGFS_READ_WRITE_FILE_OPS(traffic_log);
@@ -1542,6 +1550,8 @@ DEBUGFS_READ_WRITE_FILE_OPS(plcp_delta);
DEBUGFS_READ_WRITE_FILE_OPS(force_reset);
DEBUGFS_READ_FILE_OPS(rxon_flags);
DEBUGFS_READ_FILE_OPS(rxon_filter_flags);
+DEBUGFS_WRITE_FILE_OPS(txfifo_flush);
+DEBUGFS_READ_FILE_OPS(ucode_bt_stats);
/*
* Create the debugfs files and directories
@@ -1600,6 +1610,8 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name)
DEBUGFS_ADD_FILE(ucode_rx_stats, dir_debug, S_IRUSR);
DEBUGFS_ADD_FILE(ucode_tx_stats, dir_debug, S_IRUSR);
DEBUGFS_ADD_FILE(ucode_general_stats, dir_debug, S_IRUSR);
+ if (priv->cfg->ops->lib->dev_txfifo_flush)
+ DEBUGFS_ADD_FILE(txfifo_flush, dir_debug, S_IWUSR);
if (priv->cfg->sensitivity_calib_by_driver)
DEBUGFS_ADD_FILE(sensitivity, dir_debug, S_IRUSR);
@@ -1607,6 +1619,8 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name)
DEBUGFS_ADD_FILE(chain_noise, dir_debug, S_IRUSR);
if (priv->cfg->ucode_tracing)
DEBUGFS_ADD_FILE(ucode_tracing, dir_debug, S_IWUSR | S_IRUSR);
+ if (priv->cfg->bt_statistics)
+ DEBUGFS_ADD_FILE(ucode_bt_stats, dir_debug, S_IRUSR);
DEBUGFS_ADD_FILE(rxon_flags, dir_debug, S_IWUSR);
DEBUGFS_ADD_FILE(rxon_filter_flags, dir_debug, S_IWUSR);
if (priv->cfg->sensitivity_calib_by_driver)
diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h
index f3f3473c5c7..f35bcad56e3 100644
--- a/drivers/net/wireless/iwlwifi/iwl-dev.h
+++ b/drivers/net/wireless/iwlwifi/iwl-dev.h
@@ -48,25 +48,6 @@
#include "iwl-power.h"
#include "iwl-agn-rs.h"
-/* configuration for the iwl4965 */
-extern struct iwl_cfg iwl4965_agn_cfg;
-extern struct iwl_cfg iwl5300_agn_cfg;
-extern struct iwl_cfg iwl5100_agn_cfg;
-extern struct iwl_cfg iwl5350_agn_cfg;
-extern struct iwl_cfg iwl5100_bgn_cfg;
-extern struct iwl_cfg iwl5100_abg_cfg;
-extern struct iwl_cfg iwl5150_agn_cfg;
-extern struct iwl_cfg iwl5150_abg_cfg;
-extern struct iwl_cfg iwl6000g2a_2agn_cfg;
-extern struct iwl_cfg iwl6000i_2agn_cfg;
-extern struct iwl_cfg iwl6000i_2abg_cfg;
-extern struct iwl_cfg iwl6000i_2bg_cfg;
-extern struct iwl_cfg iwl6000_3agn_cfg;
-extern struct iwl_cfg iwl6050_2agn_cfg;
-extern struct iwl_cfg iwl6050_2abg_cfg;
-extern struct iwl_cfg iwl1000_bgn_cfg;
-extern struct iwl_cfg iwl1000_bg_cfg;
-
struct iwl_tx_queue;
/* CT-KILL constants */
@@ -133,8 +114,8 @@ struct iwl_cmd_meta {
* structure is stored at the end of the shared queue memory. */
u32 flags;
- DECLARE_PCI_UNMAP_ADDR(mapping)
- DECLARE_PCI_UNMAP_LEN(len)
+ DEFINE_DMA_UNMAP_ADDR(mapping);
+ DEFINE_DMA_UNMAP_LEN(len);
};
/*
@@ -157,11 +138,11 @@ struct iwl_queue {
* space more than this */
int high_mark; /* high watermark, stop queue if free
* space less than this */
-} __attribute__ ((packed));
+} __packed;
/* One for each TFD */
struct iwl_tx_info {
- struct sk_buff *skb[IWL_NUM_OF_TBS - 1];
+ struct sk_buff *skb;
};
/**
@@ -343,8 +324,8 @@ struct iwl_device_cmd {
struct iwl_tx_cmd tx;
struct iwl6000_channel_switch_cmd chswitch;
u8 payload[DEF_CMD_PAYLOAD_SIZE];
- } __attribute__ ((packed)) cmd;
-} __attribute__ ((packed));
+ } __packed cmd;
+} __packed;
#define TFD_MAX_PAYLOAD_SIZE (sizeof(struct iwl_device_cmd))
@@ -367,7 +348,7 @@ struct iwl_host_cmd {
/**
* struct iwl_rx_queue - Rx queue
* @bd: driver's pointer to buffer of receive buffer descriptors (rbd)
- * @dma_addr: bus address of buffer of receive buffer descriptors (rbd)
+ * @bd_dma: bus address of buffer of receive buffer descriptors (rbd)
* @read: Shared index to newest available Rx buffer
* @write: Shared index to oldest written Rx packet
* @free_count: Number of pre-allocated buffers in rx_free
@@ -381,7 +362,7 @@ struct iwl_host_cmd {
*/
struct iwl_rx_queue {
__le32 *bd;
- dma_addr_t dma_addr;
+ dma_addr_t bd_dma;
struct iwl_rx_mem_buffer pool[RX_QUEUE_SIZE + RX_FREE_BUFFERS];
struct iwl_rx_mem_buffer *queue[RX_QUEUE_SIZE];
u32 read;
@@ -433,7 +414,7 @@ struct iwl_ht_agg {
struct iwl_tid_data {
- u16 seq_number;
+ u16 seq_number; /* agn only */
u16 tfds_in_queue;
struct iwl_ht_agg agg;
};
@@ -583,6 +564,14 @@ enum iwl_ucode_tlv_type {
IWL_UCODE_TLV_INIT_DATA = 4,
IWL_UCODE_TLV_BOOT = 5,
IWL_UCODE_TLV_PROBE_MAX_LEN = 6, /* a u32 value */
+ IWL_UCODE_TLV_RUNT_EVTLOG_PTR = 8,
+ IWL_UCODE_TLV_RUNT_EVTLOG_SIZE = 9,
+ IWL_UCODE_TLV_RUNT_ERRLOG_PTR = 10,
+ IWL_UCODE_TLV_INIT_EVTLOG_PTR = 11,
+ IWL_UCODE_TLV_INIT_EVTLOG_SIZE = 12,
+ IWL_UCODE_TLV_INIT_ERRLOG_PTR = 13,
+ IWL_UCODE_TLV_ENHANCE_SENS_TBL = 14,
+ IWL_UCODE_TLV_PHY_CALIBRATION_SIZE = 15,
};
struct iwl_ucode_tlv {
@@ -590,7 +579,7 @@ struct iwl_ucode_tlv {
__le16 alternative; /* see comment */
__le32 length; /* not including type/length fields */
u8 data[0];
-} __attribute__ ((packed));
+} __packed;
#define IWL_TLV_UCODE_MAGIC 0x0a4c5749
@@ -675,6 +664,7 @@ struct iwl_sensitivity_ranges {
* @sw_crypto: 0 for hw, 1 for sw
* @max_xxx_size: for ucode uses
* @ct_kill_threshold: temperature threshold
+ * @beacon_time_tsf_bits: number of valid tsf bits for beacon time
* @calib_init_cfg: setup initial calibrations for the hw
* @struct iwl_sensitivity_ranges: range of sensitivity values
*/
@@ -701,6 +691,7 @@ struct iwl_hw_params {
u32 ct_kill_threshold; /* value in hw-dependent units */
u32 ct_kill_exit_threshold; /* value in hw-dependent units */
/* for 1000, 6000 series and up */
+ u16 beacon_time_tsf_bits;
u32 calib_init_cfg;
const struct iwl_sensitivity_ranges *sens;
};
@@ -1047,11 +1038,12 @@ struct iwl_event_log {
* This is the threshold value of plcp error rate per 100mSecs. It is
* used to set and check for the validity of plcp_delta.
*/
-#define IWL_MAX_PLCP_ERR_THRESHOLD_MIN (0)
+#define IWL_MAX_PLCP_ERR_THRESHOLD_MIN (1)
#define IWL_MAX_PLCP_ERR_THRESHOLD_DEF (50)
#define IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF (100)
#define IWL_MAX_PLCP_ERR_EXT_LONG_THRESHOLD_DEF (200)
#define IWL_MAX_PLCP_ERR_THRESHOLD_MAX (255)
+#define IWL_MAX_PLCP_ERR_THRESHOLD_DISABLE (0)
#define IWL_DELAY_NEXT_FORCE_RF_RESET (HZ*3)
#define IWL_DELAY_NEXT_FORCE_FW_RELOAD (HZ*5)
@@ -1075,6 +1067,20 @@ struct iwl_force_reset {
unsigned long last_force_reset_jiffies;
};
+/* extend beacon time format bit shifting */
+/*
+ * for _3945 devices
+ * bits 31:24 - extended
+ * bits 23:0 - interval
+ */
+#define IWL3945_EXT_BEACON_TIME_POS 24
+/*
+ * for _agn devices
+ * bits 31:22 - extended
+ * bits 21:0 - interval
+ */
+#define IWLAGN_EXT_BEACON_TIME_POS 22
+
struct iwl_priv {
/* ieee device used by generic ieee processing code */
@@ -1109,7 +1115,7 @@ struct iwl_priv {
/* force reset */
struct iwl_force_reset force_reset[IWL_MAX_FORCE_RESET];
- /* we allocate array of iwl4965_channel_info for NIC's valid channels.
+ /* we allocate array of iwl_channel_info for NIC's valid channels.
* Access via channel # using indirect index array */
struct iwl_channel_info *channel_info; /* channel info array */
u8 channel_count; /* # of channels */
@@ -1127,6 +1133,7 @@ struct iwl_priv {
void *scan_cmd;
enum ieee80211_band scan_band;
struct cfg80211_scan_request *scan_request;
+ struct ieee80211_vif *scan_vif;
bool is_internal_short_scan;
u8 scan_tx_ant[IEEE80211_NUM_BANDS];
u8 mgmt_tx_ant;
@@ -1147,6 +1154,9 @@ struct iwl_priv {
u32 hw_wa_rev;
u8 rev_id;
+ /* EEPROM MAC addresses */
+ struct mac_address addresses[2];
+
/* uCode images, save to reload in case of failure */
int fw_index; /* firmware we're trying to load */
u32 ucode_ver; /* version of ucode, copy of
@@ -1174,7 +1184,7 @@ struct iwl_priv {
struct iwl_switch_rxon switch_rxon;
/* 1st responses from initialize and runtime uCode images.
- * 4965's initialize alive response contains some calibration data. */
+ * _agn's initialize alive response contains some calibration data. */
struct iwl_init_alive_resp card_alive_init;
struct iwl_alive_resp card_alive;
@@ -1188,7 +1198,9 @@ struct iwl_priv {
u8 start_calib;
struct iwl_sensitivity_data sensitivity_data;
struct iwl_chain_noise_data chain_noise_data;
+ bool enhance_sensitivity_table;
__le16 sensitivity_tbl[HD_TABLE_SIZE];
+ __le16 enhance_sensitivity_tbl[ENHANCE_HD_TABLE_ENTRIES];
struct iwl_ht_config current_ht_config;
@@ -1220,18 +1232,12 @@ struct iwl_priv {
struct iwl_power_mgr power_data;
struct iwl_tt_mgmt thermal_throttle;
- struct iwl_notif_statistics statistics;
-#ifdef CONFIG_IWLWIFI_DEBUG
- struct iwl_notif_statistics accum_statistics;
- struct iwl_notif_statistics delta_statistics;
- struct iwl_notif_statistics max_delta;
-#endif
-
/* context information */
u8 bssid[ETH_ALEN]; /* used only on 3945 but filled by core */
- u8 mac_addr[ETH_ALEN];
- /*station table variables */
+ /* station table variables */
+
+ /* Note: if lock and sta_lock are needed, lock must be acquired first */
spinlock_t sta_lock;
int num_stations;
struct iwl_station_entry stations[IWL_STATION_COUNT];
@@ -1273,7 +1279,7 @@ struct iwl_priv {
struct delayed_work rfkill_poll;
struct iwl3945_notif_statistics statistics;
-#ifdef CONFIG_IWLWIFI_DEBUG
+#ifdef CONFIG_IWLWIFI_DEBUGFS
struct iwl3945_notif_statistics accum_statistics;
struct iwl3945_notif_statistics delta_statistics;
struct iwl3945_notif_statistics max_delta;
@@ -1315,6 +1321,28 @@ struct iwl_priv {
bool last_phy_res_valid;
struct completion firmware_loading_complete;
+
+ u32 init_evtlog_ptr, init_evtlog_size, init_errlog_ptr;
+ u32 inst_evtlog_ptr, inst_evtlog_size, inst_errlog_ptr;
+
+ /*
+ * chain noise reset and gain commands are the
+ * two extra calibration commands follows the standard
+ * phy calibration commands
+ */
+ u8 phy_calib_chain_noise_reset_cmd;
+ u8 phy_calib_chain_noise_gain_cmd;
+
+ struct iwl_notif_statistics statistics;
+ struct iwl_bt_notif_statistics statistics_bt;
+#ifdef CONFIG_IWLWIFI_DEBUGFS
+ struct iwl_notif_statistics accum_statistics;
+ struct iwl_notif_statistics delta_statistics;
+ struct iwl_notif_statistics max_delta;
+ struct iwl_bt_notif_statistics accum_statistics_bt;
+ struct iwl_bt_notif_statistics delta_statistics_bt;
+ struct iwl_bt_notif_statistics max_delta_bt;
+#endif
} _agn;
#endif
};
@@ -1336,6 +1364,7 @@ struct iwl_priv {
struct work_struct ct_enter;
struct work_struct ct_exit;
struct work_struct start_internal_scan;
+ struct work_struct tx_flush;
struct tasklet_struct irq_tasklet;
@@ -1353,9 +1382,7 @@ struct iwl_priv {
/* debugging info */
u32 debug_level; /* per device debugging will override global
iwl_debug_level if set */
- u32 framecnt_to_us;
- atomic_t restrict_refcnt;
- bool disable_ht40;
+#endif /* CONFIG_IWLWIFI_DEBUG */
#ifdef CONFIG_IWLWIFI_DEBUGFS
/* debugfs */
u16 tx_traffic_idx;
@@ -1364,8 +1391,8 @@ struct iwl_priv {
u8 *rx_traffic;
struct dentry *debugfs_dir;
u32 dbgfs_sram_offset, dbgfs_sram_len;
+ bool disable_ht40;
#endif /* CONFIG_IWLWIFI_DEBUGFS */
-#endif /* CONFIG_IWLWIFI_DEBUG */
struct work_struct txpower_work;
u32 disable_sens_cal;
@@ -1419,9 +1446,9 @@ static inline u32 iwl_get_debug_level(struct iwl_priv *priv)
static inline struct ieee80211_hdr *iwl_tx_queue_get_hdr(struct iwl_priv *priv,
int txq_id, int idx)
{
- if (priv->txq[txq_id].txb[idx].skb[0])
+ if (priv->txq[txq_id].txb[idx].skb)
return (struct ieee80211_hdr *)priv->txq[txq_id].
- txb[idx].skb[0]->data;
+ txb[idx].skb->data;
return NULL;
}
diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.c b/drivers/net/wireless/iwlwifi/iwl-eeprom.c
index ee11452519e..a45d02e555c 100644
--- a/drivers/net/wireless/iwlwifi/iwl-eeprom.c
+++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.c
@@ -629,6 +629,9 @@ int iwl_eeprom_check_version(struct iwl_priv *priv)
calib_ver < priv->cfg->eeprom_calib_ver)
goto err;
+ IWL_INFO(priv, "device EEPROM VER=0x%x, CALIB=0x%x\n",
+ eeprom_ver, calib_ver);
+
return 0;
err:
IWL_ERR(priv, "Unsupported (too old) EEPROM VER=0x%x < 0x%x CALIB=0x%x < 0x%x\n",
diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.h b/drivers/net/wireless/iwlwifi/iwl-eeprom.h
index 95aa202c85e..a4772aff51f 100644
--- a/drivers/net/wireless/iwlwifi/iwl-eeprom.h
+++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.h
@@ -118,7 +118,7 @@ enum {
struct iwl_eeprom_channel {
u8 flags; /* EEPROM_CHANNEL_* flags copied from EEPROM */
s8 max_power_avg; /* max power (dBm) on this chnl, limit 31 */
-} __attribute__ ((packed));
+} __packed;
/**
* iwl_eeprom_enhanced_txpwr structure
@@ -144,7 +144,7 @@ struct iwl_eeprom_enhanced_txpwr {
s8 reserved;
s8 mimo2_max;
s8 mimo3_max;
-} __attribute__ ((packed));
+} __packed;
/* 3945 Specific */
#define EEPROM_3945_EEPROM_VERSION (0x2f)
@@ -276,6 +276,10 @@ struct iwl_eeprom_enhanced_txpwr {
#define EEPROM_6050_TX_POWER_VERSION (4)
#define EEPROM_6050_EEPROM_VERSION (0x532)
+/* 6x50g2 Specific */
+#define EEPROM_6050G2_TX_POWER_VERSION (6)
+#define EEPROM_6050G2_EEPROM_VERSION (0x553)
+
/* 6x00g2 Specific */
#define EEPROM_6000G2_TX_POWER_VERSION (6)
#define EEPROM_6000G2_EEPROM_VERSION (0x709)
@@ -312,7 +316,7 @@ struct iwl_eeprom_calib_measure {
u8 gain_idx; /* Index into gain table */
u8 actual_pow; /* Measured RF output power, half-dBm */
s8 pa_det; /* Power amp detector level (not used) */
-} __attribute__ ((packed));
+} __packed;
/*
@@ -328,7 +332,7 @@ struct iwl_eeprom_calib_ch_info {
struct iwl_eeprom_calib_measure
measurements[EEPROM_TX_POWER_TX_CHAINS]
[EEPROM_TX_POWER_MEASUREMENTS];
-} __attribute__ ((packed));
+} __packed;
/*
* txpower subband info.
@@ -345,7 +349,7 @@ struct iwl_eeprom_calib_subband_info {
u8 ch_to; /* channel number of highest channel in subband */
struct iwl_eeprom_calib_ch_info ch1;
struct iwl_eeprom_calib_ch_info ch2;
-} __attribute__ ((packed));
+} __packed;
/*
@@ -374,7 +378,7 @@ struct iwl_eeprom_calib_info {
__le16 voltage; /* signed */
struct iwl_eeprom_calib_subband_info
band_info[EEPROM_TX_POWER_BANDS];
-} __attribute__ ((packed));
+} __packed;
#define ADDRESS_MSK 0x0000FFFF
@@ -398,6 +402,7 @@ struct iwl_eeprom_calib_info {
#define EEPROM_WOWLAN_MODE (2*0x47) /* 2 bytes */
#define EEPROM_RADIO_CONFIG (2*0x48) /* 2 bytes */
#define EEPROM_3945_M_VERSION (2*0x4A) /* 1 bytes */
+#define EEPROM_NUM_MAC_ADDRESS (2*0x4C) /* 2 bytes */
/* The following masks are to be applied on EEPROM_RADIO_CONFIG */
#define EEPROM_RF_CFG_TYPE_MSK(x) (x & 0x3) /* bits 0-1 */
diff --git a/drivers/net/wireless/iwlwifi/iwl-fh.h b/drivers/net/wireless/iwlwifi/iwl-fh.h
index 113c3669b9c..55b8370bc6d 100644
--- a/drivers/net/wireless/iwlwifi/iwl-fh.h
+++ b/drivers/net/wireless/iwlwifi/iwl-fh.h
@@ -398,12 +398,7 @@
*/
#define FH_TSSR_TX_ERROR_REG (FH_TSSR_LOWER_BOUND + 0x018)
-#define FH_TSSR_TX_STATUS_REG_BIT_BUFS_EMPTY(_chnl) ((1 << (_chnl)) << 24)
-#define FH_TSSR_TX_STATUS_REG_BIT_NO_PEND_REQ(_chnl) ((1 << (_chnl)) << 16)
-
-#define FH_TSSR_TX_STATUS_REG_MSK_CHNL_IDLE(_chnl) \
- (FH_TSSR_TX_STATUS_REG_BIT_BUFS_EMPTY(_chnl) | \
- FH_TSSR_TX_STATUS_REG_BIT_NO_PEND_REQ(_chnl))
+#define FH_TSSR_TX_STATUS_REG_MSK_CHNL_IDLE(_chnl) ((1 << (_chnl)) << 16)
/* Tx service channels */
#define FH_SRVC_CHNL (9)
@@ -449,7 +444,7 @@ struct iwl_rb_status {
__le16 finished_rb_num;
__le16 finished_fr_nam;
__le32 __unused; /* 3945 only */
-} __attribute__ ((packed));
+} __packed;
#define TFD_QUEUE_SIZE_MAX (256)
@@ -475,7 +470,7 @@ static inline u8 iwl_get_dma_hi_addr(dma_addr_t addr)
struct iwl_tfd_tb {
__le32 lo;
__le16 hi_n_len;
-} __attribute__((packed));
+} __packed;
/**
* struct iwl_tfd
@@ -510,7 +505,7 @@ struct iwl_tfd {
u8 num_tbs;
struct iwl_tfd_tb tbs[IWL_NUM_OF_TBS];
__le32 __pad;
-} __attribute__ ((packed));
+} __packed;
/* Keep Warm Size */
#define IWL_KW_SIZE 0x1000 /* 4k */
diff --git a/drivers/net/wireless/iwlwifi/iwl-hcmd.c b/drivers/net/wireless/iwlwifi/iwl-hcmd.c
index 51f89e7ba68..258d059ef41 100644
--- a/drivers/net/wireless/iwlwifi/iwl-hcmd.c
+++ b/drivers/net/wireless/iwlwifi/iwl-hcmd.c
@@ -49,6 +49,7 @@ const char *get_cmd_string(u8 cmd)
IWL_CMD(REPLY_ADD_STA);
IWL_CMD(REPLY_REMOVE_STA);
IWL_CMD(REPLY_REMOVE_ALL_STA);
+ IWL_CMD(REPLY_TXFIFO_FLUSH);
IWL_CMD(REPLY_WEPKEY);
IWL_CMD(REPLY_3945_RX);
IWL_CMD(REPLY_TX);
diff --git a/drivers/net/wireless/iwlwifi/iwl-helpers.h b/drivers/net/wireless/iwlwifi/iwl-helpers.h
index 3ff6b9d25a1..621abe3c5af 100644
--- a/drivers/net/wireless/iwlwifi/iwl-helpers.h
+++ b/drivers/net/wireless/iwlwifi/iwl-helpers.h
@@ -92,6 +92,11 @@ static inline void iwl_free_fw_desc(struct pci_dev *pci_dev,
static inline int iwl_alloc_fw_desc(struct pci_dev *pci_dev,
struct fw_desc *desc)
{
+ if (!desc->len) {
+ desc->v_addr = NULL;
+ return -EINVAL;
+ }
+
desc->v_addr = dma_alloc_coherent(&pci_dev->dev, desc->len,
&desc->p_addr, GFP_KERNEL);
return (desc->v_addr != NULL) ? 0 : -ENOMEM;
@@ -170,4 +175,26 @@ static inline void iwl_enable_interrupts(struct iwl_priv *priv)
iwl_write32(priv, CSR_INT_MASK, priv->inta_mask);
}
+/**
+ * iwl_beacon_time_mask_low - mask of lower 32 bit of beacon time
+ * @priv -- pointer to iwl_priv data structure
+ * @tsf_bits -- number of bits need to shift for masking)
+ */
+static inline u32 iwl_beacon_time_mask_low(struct iwl_priv *priv,
+ u16 tsf_bits)
+{
+ return (1 << tsf_bits) - 1;
+}
+
+/**
+ * iwl_beacon_time_mask_high - mask of higher 32 bit of beacon time
+ * @priv -- pointer to iwl_priv data structure
+ * @tsf_bits -- number of bits need to shift for masking)
+ */
+static inline u32 iwl_beacon_time_mask_high(struct iwl_priv *priv,
+ u16 tsf_bits)
+{
+ return ((1 << (32 - tsf_bits)) - 1) << tsf_bits;
+}
+
#endif /* __iwl_helpers_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c
index 0a5d7cf2519..79773e353ba 100644
--- a/drivers/net/wireless/iwlwifi/iwl-rx.c
+++ b/drivers/net/wireless/iwlwifi/iwl-rx.c
@@ -175,7 +175,7 @@ int iwl_rx_queue_alloc(struct iwl_priv *priv)
INIT_LIST_HEAD(&rxq->rx_used);
/* Alloc the circular buffer of Read Buffer Descriptors (RBDs) */
- rxq->bd = dma_alloc_coherent(dev, 4 * RX_QUEUE_SIZE, &rxq->dma_addr,
+ rxq->bd = dma_alloc_coherent(dev, 4 * RX_QUEUE_SIZE, &rxq->bd_dma,
GFP_KERNEL);
if (!rxq->bd)
goto err_bd;
@@ -199,32 +199,12 @@ int iwl_rx_queue_alloc(struct iwl_priv *priv)
err_rb:
dma_free_coherent(&priv->pci_dev->dev, 4 * RX_QUEUE_SIZE, rxq->bd,
- rxq->dma_addr);
+ rxq->bd_dma);
err_bd:
return -ENOMEM;
}
EXPORT_SYMBOL(iwl_rx_queue_alloc);
-void iwl_rx_missed_beacon_notif(struct iwl_priv *priv,
- struct iwl_rx_mem_buffer *rxb)
-
-{
- struct iwl_rx_packet *pkt = rxb_addr(rxb);
- struct iwl_missed_beacon_notif *missed_beacon;
-
- missed_beacon = &pkt->u.missed_beacon;
- if (le32_to_cpu(missed_beacon->consecutive_missed_beacons) >
- priv->missed_beacon_threshold) {
- IWL_DEBUG_CALIB(priv, "missed bcn cnsq %d totl %d rcd %d expctd %d\n",
- le32_to_cpu(missed_beacon->consecutive_missed_beacons),
- le32_to_cpu(missed_beacon->total_missed_becons),
- le32_to_cpu(missed_beacon->num_recvd_beacons),
- le32_to_cpu(missed_beacon->num_expected_beacons));
- if (!test_bit(STATUS_SCANNING, &priv->status))
- iwl_init_sensitivity(priv);
- }
-}
-EXPORT_SYMBOL(iwl_rx_missed_beacon_notif);
void iwl_rx_spectrum_measure_notif(struct iwl_priv *priv,
struct iwl_rx_mem_buffer *rxb)
@@ -243,161 +223,6 @@ void iwl_rx_spectrum_measure_notif(struct iwl_priv *priv,
}
EXPORT_SYMBOL(iwl_rx_spectrum_measure_notif);
-
-
-/* Calculate noise level, based on measurements during network silence just
- * before arriving beacon. This measurement can be done only if we know
- * exactly when to expect beacons, therefore only when we're associated. */
-static void iwl_rx_calc_noise(struct iwl_priv *priv)
-{
- struct statistics_rx_non_phy *rx_info
- = &(priv->statistics.rx.general);
- int num_active_rx = 0;
- int total_silence = 0;
- int bcn_silence_a =
- le32_to_cpu(rx_info->beacon_silence_rssi_a) & IN_BAND_FILTER;
- int bcn_silence_b =
- le32_to_cpu(rx_info->beacon_silence_rssi_b) & IN_BAND_FILTER;
- int bcn_silence_c =
- le32_to_cpu(rx_info->beacon_silence_rssi_c) & IN_BAND_FILTER;
- int last_rx_noise;
-
- if (bcn_silence_a) {
- total_silence += bcn_silence_a;
- num_active_rx++;
- }
- if (bcn_silence_b) {
- total_silence += bcn_silence_b;
- num_active_rx++;
- }
- if (bcn_silence_c) {
- total_silence += bcn_silence_c;
- num_active_rx++;
- }
-
- /* Average among active antennas */
- if (num_active_rx)
- last_rx_noise = (total_silence / num_active_rx) - 107;
- else
- last_rx_noise = IWL_NOISE_MEAS_NOT_AVAILABLE;
-
- IWL_DEBUG_CALIB(priv, "inband silence a %u, b %u, c %u, dBm %d\n",
- bcn_silence_a, bcn_silence_b, bcn_silence_c,
- last_rx_noise);
-}
-
-#ifdef CONFIG_IWLWIFI_DEBUG
-/*
- * based on the assumption of all statistics counter are in DWORD
- * FIXME: This function is for debugging, do not deal with
- * the case of counters roll-over.
- */
-static void iwl_accumulative_statistics(struct iwl_priv *priv,
- __le32 *stats)
-{
- int i;
- __le32 *prev_stats;
- u32 *accum_stats;
- u32 *delta, *max_delta;
-
- prev_stats = (__le32 *)&priv->statistics;
- accum_stats = (u32 *)&priv->accum_statistics;
- delta = (u32 *)&priv->delta_statistics;
- max_delta = (u32 *)&priv->max_delta;
-
- for (i = sizeof(__le32); i < sizeof(struct iwl_notif_statistics);
- i += sizeof(__le32), stats++, prev_stats++, delta++,
- max_delta++, accum_stats++) {
- if (le32_to_cpu(*stats) > le32_to_cpu(*prev_stats)) {
- *delta = (le32_to_cpu(*stats) -
- le32_to_cpu(*prev_stats));
- *accum_stats += *delta;
- if (*delta > *max_delta)
- *max_delta = *delta;
- }
- }
-
- /* reset accumulative statistics for "no-counter" type statistics */
- priv->accum_statistics.general.temperature =
- priv->statistics.general.temperature;
- priv->accum_statistics.general.temperature_m =
- priv->statistics.general.temperature_m;
- priv->accum_statistics.general.ttl_timestamp =
- priv->statistics.general.ttl_timestamp;
- priv->accum_statistics.tx.tx_power.ant_a =
- priv->statistics.tx.tx_power.ant_a;
- priv->accum_statistics.tx.tx_power.ant_b =
- priv->statistics.tx.tx_power.ant_b;
- priv->accum_statistics.tx.tx_power.ant_c =
- priv->statistics.tx.tx_power.ant_c;
-}
-#endif
-
-#define REG_RECALIB_PERIOD (60)
-
-/**
- * iwl_good_plcp_health - checks for plcp error.
- *
- * When the plcp error is exceeding the thresholds, reset the radio
- * to improve the throughput.
- */
-bool iwl_good_plcp_health(struct iwl_priv *priv,
- struct iwl_rx_packet *pkt)
-{
- bool rc = true;
- int combined_plcp_delta;
- unsigned int plcp_msec;
- unsigned long plcp_received_jiffies;
-
- /*
- * check for plcp_err and trigger radio reset if it exceeds
- * the plcp error threshold plcp_delta.
- */
- plcp_received_jiffies = jiffies;
- plcp_msec = jiffies_to_msecs((long) plcp_received_jiffies -
- (long) priv->plcp_jiffies);
- priv->plcp_jiffies = plcp_received_jiffies;
- /*
- * check to make sure plcp_msec is not 0 to prevent division
- * by zero.
- */
- if (plcp_msec) {
- combined_plcp_delta =
- (le32_to_cpu(pkt->u.stats.rx.ofdm.plcp_err) -
- le32_to_cpu(priv->statistics.rx.ofdm.plcp_err)) +
- (le32_to_cpu(pkt->u.stats.rx.ofdm_ht.plcp_err) -
- le32_to_cpu(priv->statistics.rx.ofdm_ht.plcp_err));
-
- if ((combined_plcp_delta > 0) &&
- ((combined_plcp_delta * 100) / plcp_msec) >
- priv->cfg->plcp_delta_threshold) {
- /*
- * if plcp_err exceed the threshold,
- * the following data is printed in csv format:
- * Text: plcp_err exceeded %d,
- * Received ofdm.plcp_err,
- * Current ofdm.plcp_err,
- * Received ofdm_ht.plcp_err,
- * Current ofdm_ht.plcp_err,
- * combined_plcp_delta,
- * plcp_msec
- */
- IWL_DEBUG_RADIO(priv, "plcp_err exceeded %u, "
- "%u, %u, %u, %u, %d, %u mSecs\n",
- priv->cfg->plcp_delta_threshold,
- le32_to_cpu(pkt->u.stats.rx.ofdm.plcp_err),
- le32_to_cpu(priv->statistics.rx.ofdm.plcp_err),
- le32_to_cpu(pkt->u.stats.rx.ofdm_ht.plcp_err),
- le32_to_cpu(
- priv->statistics.rx.ofdm_ht.plcp_err),
- combined_plcp_delta, plcp_msec);
- rc = false;
- }
- }
- return rc;
-}
-EXPORT_SYMBOL(iwl_good_plcp_health);
-
void iwl_recover_from_statistics(struct iwl_priv *priv,
struct iwl_rx_packet *pkt)
{
@@ -413,7 +238,7 @@ void iwl_recover_from_statistics(struct iwl_priv *priv,
*/
IWL_ERR(priv, "low ack count detected, "
"restart firmware\n");
- if (!iwl_force_reset(priv, IWL_FW_RESET))
+ if (!iwl_force_reset(priv, IWL_FW_RESET, false))
return;
}
}
@@ -424,76 +249,13 @@ void iwl_recover_from_statistics(struct iwl_priv *priv,
* high plcp error detected
* reset Radio
*/
- iwl_force_reset(priv, IWL_RF_RESET);
+ iwl_force_reset(priv, IWL_RF_RESET, false);
}
}
}
}
EXPORT_SYMBOL(iwl_recover_from_statistics);
-void iwl_rx_statistics(struct iwl_priv *priv,
- struct iwl_rx_mem_buffer *rxb)
-{
- int change;
- struct iwl_rx_packet *pkt = rxb_addr(rxb);
-
-
- IWL_DEBUG_RX(priv, "Statistics notification received (%d vs %d).\n",
- (int)sizeof(priv->statistics),
- le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK);
-
- change = ((priv->statistics.general.temperature !=
- pkt->u.stats.general.temperature) ||
- ((priv->statistics.flag &
- STATISTICS_REPLY_FLG_HT40_MODE_MSK) !=
- (pkt->u.stats.flag & STATISTICS_REPLY_FLG_HT40_MODE_MSK)));
-
-#ifdef CONFIG_IWLWIFI_DEBUG
- iwl_accumulative_statistics(priv, (__le32 *)&pkt->u.stats);
-#endif
- iwl_recover_from_statistics(priv, pkt);
-
- memcpy(&priv->statistics, &pkt->u.stats, sizeof(priv->statistics));
-
- set_bit(STATUS_STATISTICS, &priv->status);
-
- /* Reschedule the statistics timer to occur in
- * REG_RECALIB_PERIOD seconds to ensure we get a
- * thermal update even if the uCode doesn't give
- * us one */
- mod_timer(&priv->statistics_periodic, jiffies +
- msecs_to_jiffies(REG_RECALIB_PERIOD * 1000));
-
- if (unlikely(!test_bit(STATUS_SCANNING, &priv->status)) &&
- (pkt->hdr.cmd == STATISTICS_NOTIFICATION)) {
- iwl_rx_calc_noise(priv);
- queue_work(priv->workqueue, &priv->run_time_calib_work);
- }
- if (priv->cfg->ops->lib->temp_ops.temperature && change)
- priv->cfg->ops->lib->temp_ops.temperature(priv);
-}
-EXPORT_SYMBOL(iwl_rx_statistics);
-
-void iwl_reply_statistics(struct iwl_priv *priv,
- struct iwl_rx_mem_buffer *rxb)
-{
- struct iwl_rx_packet *pkt = rxb_addr(rxb);
-
- if (le32_to_cpu(pkt->u.stats.flag) & UCODE_STATISTICS_CLEAR_MSK) {
-#ifdef CONFIG_IWLWIFI_DEBUG
- memset(&priv->accum_statistics, 0,
- sizeof(struct iwl_notif_statistics));
- memset(&priv->delta_statistics, 0,
- sizeof(struct iwl_notif_statistics));
- memset(&priv->max_delta, 0,
- sizeof(struct iwl_notif_statistics));
-#endif
- IWL_DEBUG_RX(priv, "Statistics have been cleared\n");
- }
- iwl_rx_statistics(priv, rxb);
-}
-EXPORT_SYMBOL(iwl_reply_statistics);
-
/*
* returns non-zero if packet should be dropped
*/
diff --git a/drivers/net/wireless/iwlwifi/iwl-scan.c b/drivers/net/wireless/iwlwifi/iwl-scan.c
index 386c5f96eff..b0c6b047390 100644
--- a/drivers/net/wireless/iwlwifi/iwl-scan.c
+++ b/drivers/net/wireless/iwlwifi/iwl-scan.c
@@ -333,7 +333,8 @@ int iwl_mac_hw_scan(struct ieee80211_hw *hw,
goto out_unlock;
}
- if (test_bit(STATUS_SCANNING, &priv->status)) {
+ if (test_bit(STATUS_SCANNING, &priv->status) &&
+ !priv->is_internal_short_scan) {
IWL_DEBUG_SCAN(priv, "Scan already in progress.\n");
ret = -EAGAIN;
goto out_unlock;
@@ -348,8 +349,16 @@ int iwl_mac_hw_scan(struct ieee80211_hw *hw,
/* mac80211 will only ask for one band at a time */
priv->scan_band = req->channels[0]->band;
priv->scan_request = req;
+ priv->scan_vif = vif;
- ret = iwl_scan_initiate(priv, vif);
+ /*
+ * If an internal scan is in progress, just set
+ * up the scan_request as per above.
+ */
+ if (priv->is_internal_short_scan)
+ ret = 0;
+ else
+ ret = iwl_scan_initiate(priv, vif);
IWL_DEBUG_MAC80211(priv, "leave\n");
@@ -420,11 +429,10 @@ void iwl_bg_scan_check(struct work_struct *data)
return;
mutex_lock(&priv->mutex);
- if (test_bit(STATUS_SCANNING, &priv->status) ||
- test_bit(STATUS_SCAN_ABORTING, &priv->status)) {
- IWL_DEBUG_SCAN(priv, "Scan completion watchdog resetting "
- "adapter (%dms)\n",
- jiffies_to_msecs(IWL_SCAN_CHECK_WATCHDOG));
+ if (test_bit(STATUS_SCANNING, &priv->status) &&
+ !test_bit(STATUS_SCAN_ABORTING, &priv->status)) {
+ IWL_DEBUG_SCAN(priv, "Scan completion watchdog (%dms)\n",
+ jiffies_to_msecs(IWL_SCAN_CHECK_WATCHDOG));
if (!test_bit(STATUS_EXIT_PENDING, &priv->status))
iwl_send_scan_abort(priv);
@@ -438,7 +446,7 @@ EXPORT_SYMBOL(iwl_bg_scan_check);
*/
u16 iwl_fill_probe_req(struct iwl_priv *priv, struct ieee80211_mgmt *frame,
- const u8 *ies, int ie_len, int left)
+ const u8 *ta, const u8 *ies, int ie_len, int left)
{
int len = 0;
u8 *pos = NULL;
@@ -451,7 +459,7 @@ u16 iwl_fill_probe_req(struct iwl_priv *priv, struct ieee80211_mgmt *frame,
frame->frame_control = cpu_to_le16(IEEE80211_STYPE_PROBE_REQ);
memcpy(frame->da, iwl_bcast_addr, ETH_ALEN);
- memcpy(frame->sa, priv->mac_addr, ETH_ALEN);
+ memcpy(frame->sa, ta, ETH_ALEN);
memcpy(frame->bssid, iwl_bcast_addr, ETH_ALEN);
frame->seq_ctrl = 0;
@@ -489,12 +497,11 @@ void iwl_bg_abort_scan(struct work_struct *work)
!test_bit(STATUS_GEO_CONFIGURED, &priv->status))
return;
- mutex_lock(&priv->mutex);
-
- cancel_delayed_work_sync(&priv->scan_check);
- set_bit(STATUS_SCAN_ABORTING, &priv->status);
- iwl_send_scan_abort(priv);
+ cancel_delayed_work(&priv->scan_check);
+ mutex_lock(&priv->mutex);
+ if (test_bit(STATUS_SCAN_ABORTING, &priv->status))
+ iwl_send_scan_abort(priv);
mutex_unlock(&priv->mutex);
}
EXPORT_SYMBOL(iwl_bg_abort_scan);
@@ -514,7 +521,30 @@ void iwl_bg_scan_completed(struct work_struct *work)
priv->is_internal_short_scan = false;
IWL_DEBUG_SCAN(priv, "internal short scan completed\n");
internal = true;
+ } else {
+ priv->scan_request = NULL;
+ priv->scan_vif = NULL;
}
+
+ if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+ goto out;
+
+ if (internal && priv->scan_request)
+ iwl_scan_initiate(priv, priv->scan_vif);
+
+ /* Since setting the TXPOWER may have been deferred while
+ * performing the scan, fire one off */
+ iwl_set_tx_power(priv, priv->tx_power_user_lmt, true);
+
+ /*
+ * Since setting the RXON may have been deferred while
+ * performing the scan, fire one off if needed
+ */
+ if (memcmp(&priv->active_rxon,
+ &priv->staging_rxon, sizeof(priv->staging_rxon)))
+ iwlcore_commit_rxon(priv);
+
+ out:
mutex_unlock(&priv->mutex);
/*
@@ -524,15 +554,6 @@ void iwl_bg_scan_completed(struct work_struct *work)
*/
if (!internal)
ieee80211_scan_completed(priv->hw, false);
-
- if (test_bit(STATUS_EXIT_PENDING, &priv->status))
- return;
-
- /* Since setting the TXPOWER may have been deferred while
- * performing the scan, fire one off */
- mutex_lock(&priv->mutex);
- iwl_set_tx_power(priv, priv->tx_power_user_lmt, true);
- mutex_unlock(&priv->mutex);
}
EXPORT_SYMBOL(iwl_bg_scan_completed);
diff --git a/drivers/net/wireless/iwlwifi/iwl-spectrum.h b/drivers/net/wireless/iwlwifi/iwl-spectrum.h
index af6babee289..c4ca0b5d77d 100644
--- a/drivers/net/wireless/iwlwifi/iwl-spectrum.h
+++ b/drivers/net/wireless/iwlwifi/iwl-spectrum.h
@@ -42,7 +42,7 @@ struct ieee80211_basic_report {
__le64 start_time;
__le16 duration;
u8 map;
-} __attribute__ ((packed));
+} __packed;
enum { /* ieee80211_measurement_request.mode */
/* Bit 0 is reserved */
@@ -63,13 +63,13 @@ struct ieee80211_measurement_params {
u8 channel;
__le64 start_time;
__le16 duration;
-} __attribute__ ((packed));
+} __packed;
struct ieee80211_info_element {
u8 id;
u8 len;
u8 data[0];
-} __attribute__ ((packed));
+} __packed;
struct ieee80211_measurement_request {
struct ieee80211_info_element ie;
@@ -77,7 +77,7 @@ struct ieee80211_measurement_request {
u8 mode;
u8 type;
struct ieee80211_measurement_params params[0];
-} __attribute__ ((packed));
+} __packed;
struct ieee80211_measurement_report {
struct ieee80211_info_element ie;
@@ -87,6 +87,6 @@ struct ieee80211_measurement_report {
union {
struct ieee80211_basic_report basic[0];
} u;
-} __attribute__ ((packed));
+} __packed;
#endif
diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.c b/drivers/net/wireless/iwlwifi/iwl-sta.c
index c27c13fbb1a..9511f03f07e 100644
--- a/drivers/net/wireless/iwlwifi/iwl-sta.c
+++ b/drivers/net/wireless/iwlwifi/iwl-sta.c
@@ -30,6 +30,7 @@
#include <net/mac80211.h>
#include <linux/etherdevice.h>
#include <linux/sched.h>
+#include <linux/lockdep.h>
#include "iwl-dev.h"
#include "iwl-core.h"
@@ -54,18 +55,19 @@ static void iwl_sta_ucode_activate(struct iwl_priv *priv, u8 sta_id)
}
}
-static void iwl_process_add_sta_resp(struct iwl_priv *priv,
- struct iwl_addsta_cmd *addsta,
- struct iwl_rx_packet *pkt,
- bool sync)
+static int iwl_process_add_sta_resp(struct iwl_priv *priv,
+ struct iwl_addsta_cmd *addsta,
+ struct iwl_rx_packet *pkt,
+ bool sync)
{
u8 sta_id = addsta->sta.sta_id;
unsigned long flags;
+ int ret = -EIO;
if (pkt->hdr.flags & IWL_CMD_FAILED_MSK) {
IWL_ERR(priv, "Bad return from REPLY_ADD_STA (0x%08X)\n",
pkt->hdr.flags);
- return;
+ return ret;
}
IWL_DEBUG_INFO(priv, "Processing response for adding station %u\n",
@@ -77,6 +79,7 @@ static void iwl_process_add_sta_resp(struct iwl_priv *priv,
case ADD_STA_SUCCESS_MSK:
IWL_DEBUG_INFO(priv, "REPLY_ADD_STA PASSED\n");
iwl_sta_ucode_activate(priv, sta_id);
+ ret = 0;
break;
case ADD_STA_NO_ROOM_IN_TABLE:
IWL_ERR(priv, "Adding station %d failed, no room in table.\n",
@@ -114,6 +117,8 @@ static void iwl_process_add_sta_resp(struct iwl_priv *priv,
STA_CONTROL_MODIFY_MSK ? "Modified" : "Added",
addsta->sta.addr);
spin_unlock_irqrestore(&priv->sta_lock, flags);
+
+ return ret;
}
static void iwl_add_sta_callback(struct iwl_priv *priv,
@@ -145,8 +150,10 @@ int iwl_send_add_sta(struct iwl_priv *priv,
if (flags & CMD_ASYNC)
cmd.callback = iwl_add_sta_callback;
- else
+ else {
cmd.flags |= CMD_WANT_SKB;
+ might_sleep();
+ }
cmd.len = priv->cfg->ops->utils->build_addsta_hcmd(sta, data);
ret = iwl_send_cmd(priv, &cmd);
@@ -156,7 +163,7 @@ int iwl_send_add_sta(struct iwl_priv *priv,
if (ret == 0) {
pkt = (struct iwl_rx_packet *)cmd.reply_page;
- iwl_process_add_sta_resp(priv, sta, pkt, true);
+ ret = iwl_process_add_sta_resp(priv, sta, pkt, true);
}
iwl_free_pages(priv, cmd.reply_page);
@@ -311,10 +318,10 @@ int iwl_add_station_common(struct iwl_priv *priv, const u8 *addr,
struct ieee80211_sta_ht_cap *ht_info,
u8 *sta_id_r)
{
- struct iwl_station_entry *station;
unsigned long flags_spin;
int ret = 0;
u8 sta_id;
+ struct iwl_addsta_cmd sta_cmd;
*sta_id_r = 0;
spin_lock_irqsave(&priv->sta_lock, flags_spin);
@@ -347,14 +354,15 @@ int iwl_add_station_common(struct iwl_priv *priv, const u8 *addr,
}
priv->stations[sta_id].used |= IWL_STA_UCODE_INPROGRESS;
- station = &priv->stations[sta_id];
+ memcpy(&sta_cmd, &priv->stations[sta_id].sta, sizeof(struct iwl_addsta_cmd));
spin_unlock_irqrestore(&priv->sta_lock, flags_spin);
/* Add station to device's station table */
- ret = iwl_send_add_sta(priv, &station->sta, CMD_SYNC);
+ ret = iwl_send_add_sta(priv, &sta_cmd, CMD_SYNC);
if (ret) {
- IWL_ERR(priv, "Adding station %pM failed.\n", station->sta.sta.addr);
spin_lock_irqsave(&priv->sta_lock, flags_spin);
+ IWL_ERR(priv, "Adding station %pM failed.\n",
+ priv->stations[sta_id].sta.sta.addr);
priv->stations[sta_id].used &= ~IWL_STA_DRIVER_ACTIVE;
priv->stations[sta_id].used &= ~IWL_STA_UCODE_INPROGRESS;
spin_unlock_irqrestore(&priv->sta_lock, flags_spin);
@@ -488,7 +496,7 @@ static void iwl_sta_ucode_deactivate(struct iwl_priv *priv, u8 sta_id)
}
static int iwl_send_remove_station(struct iwl_priv *priv,
- struct iwl_station_entry *station)
+ const u8 *addr, int sta_id)
{
struct iwl_rx_packet *pkt;
int ret;
@@ -505,7 +513,7 @@ static int iwl_send_remove_station(struct iwl_priv *priv,
memset(&rm_sta_cmd, 0, sizeof(rm_sta_cmd));
rm_sta_cmd.num_sta = 1;
- memcpy(&rm_sta_cmd.addr, &station->sta.sta.addr , ETH_ALEN);
+ memcpy(&rm_sta_cmd.addr, addr, ETH_ALEN);
cmd.flags |= CMD_WANT_SKB;
@@ -525,7 +533,7 @@ static int iwl_send_remove_station(struct iwl_priv *priv,
switch (pkt->u.rem_sta.status) {
case REM_STA_SUCCESS_MSK:
spin_lock_irqsave(&priv->sta_lock, flags_spin);
- iwl_sta_ucode_deactivate(priv, station->sta.sta.sta_id);
+ iwl_sta_ucode_deactivate(priv, sta_id);
spin_unlock_irqrestore(&priv->sta_lock, flags_spin);
IWL_DEBUG_ASSOC(priv, "REPLY_REMOVE_STA PASSED\n");
break;
@@ -546,7 +554,6 @@ static int iwl_send_remove_station(struct iwl_priv *priv,
int iwl_remove_station(struct iwl_priv *priv, const u8 sta_id,
const u8 *addr)
{
- struct iwl_station_entry *station;
unsigned long flags;
if (!iwl_is_ready(priv)) {
@@ -592,10 +599,9 @@ int iwl_remove_station(struct iwl_priv *priv, const u8 sta_id,
BUG_ON(priv->num_stations < 0);
- station = &priv->stations[sta_id];
spin_unlock_irqrestore(&priv->sta_lock, flags);
- return iwl_send_remove_station(priv, station);
+ return iwl_send_remove_station(priv, addr, sta_id);
out_err:
spin_unlock_irqrestore(&priv->sta_lock, flags);
return -EINVAL;
@@ -643,11 +649,13 @@ EXPORT_SYMBOL(iwl_clear_ucode_stations);
*/
void iwl_restore_stations(struct iwl_priv *priv)
{
- struct iwl_station_entry *station;
+ struct iwl_addsta_cmd sta_cmd;
+ struct iwl_link_quality_cmd lq;
unsigned long flags_spin;
int i;
bool found = false;
int ret;
+ bool send_lq;
if (!iwl_is_ready(priv)) {
IWL_DEBUG_INFO(priv, "Not ready yet, not restoring any stations.\n");
@@ -669,13 +677,20 @@ void iwl_restore_stations(struct iwl_priv *priv)
for (i = 0; i < priv->hw_params.max_stations; i++) {
if ((priv->stations[i].used & IWL_STA_UCODE_INPROGRESS)) {
+ memcpy(&sta_cmd, &priv->stations[i].sta,
+ sizeof(struct iwl_addsta_cmd));
+ send_lq = false;
+ if (priv->stations[i].lq) {
+ memcpy(&lq, priv->stations[i].lq,
+ sizeof(struct iwl_link_quality_cmd));
+ send_lq = true;
+ }
spin_unlock_irqrestore(&priv->sta_lock, flags_spin);
- station = &priv->stations[i];
- ret = iwl_send_add_sta(priv, &priv->stations[i].sta, CMD_SYNC);
+ ret = iwl_send_add_sta(priv, &sta_cmd, CMD_SYNC);
if (ret) {
- IWL_ERR(priv, "Adding station %pM failed.\n",
- station->sta.sta.addr);
spin_lock_irqsave(&priv->sta_lock, flags_spin);
+ IWL_ERR(priv, "Adding station %pM failed.\n",
+ priv->stations[i].sta.sta.addr);
priv->stations[i].used &= ~IWL_STA_DRIVER_ACTIVE;
priv->stations[i].used &= ~IWL_STA_UCODE_INPROGRESS;
spin_unlock_irqrestore(&priv->sta_lock, flags_spin);
@@ -684,8 +699,8 @@ void iwl_restore_stations(struct iwl_priv *priv)
* Rate scaling has already been initialized, send
* current LQ command
*/
- if (station->lq)
- iwl_send_lq_cmd(priv, station->lq, CMD_SYNC, true);
+ if (send_lq)
+ iwl_send_lq_cmd(priv, &lq, CMD_SYNC, true);
spin_lock_irqsave(&priv->sta_lock, flags_spin);
priv->stations[i].used &= ~IWL_STA_UCODE_INPROGRESS;
}
@@ -823,7 +838,9 @@ static int iwl_set_wep_dynamic_key_info(struct iwl_priv *priv,
{
unsigned long flags;
__le16 key_flags = 0;
- int ret;
+ struct iwl_addsta_cmd sta_cmd;
+
+ lockdep_assert_held(&priv->mutex);
keyconf->flags &= ~IEEE80211_KEY_FLAG_GENERATE_IV;
@@ -863,11 +880,10 @@ static int iwl_set_wep_dynamic_key_info(struct iwl_priv *priv,
priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK;
priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
- ret = iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC);
-
+ memcpy(&sta_cmd, &priv->stations[sta_id].sta, sizeof(struct iwl_addsta_cmd));
spin_unlock_irqrestore(&priv->sta_lock, flags);
- return ret;
+ return iwl_send_add_sta(priv, &sta_cmd, CMD_SYNC);
}
static int iwl_set_ccmp_dynamic_key_info(struct iwl_priv *priv,
@@ -876,7 +892,9 @@ static int iwl_set_ccmp_dynamic_key_info(struct iwl_priv *priv,
{
unsigned long flags;
__le16 key_flags = 0;
- int ret;
+ struct iwl_addsta_cmd sta_cmd;
+
+ lockdep_assert_held(&priv->mutex);
key_flags |= (STA_KEY_FLG_CCMP | STA_KEY_FLG_MAP_KEY_MSK);
key_flags |= cpu_to_le16(keyconf->keyidx << STA_KEY_FLG_KEYID_POS);
@@ -911,11 +929,10 @@ static int iwl_set_ccmp_dynamic_key_info(struct iwl_priv *priv,
priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK;
priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
- ret = iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC);
-
+ memcpy(&sta_cmd, &priv->stations[sta_id].sta, sizeof(struct iwl_addsta_cmd));
spin_unlock_irqrestore(&priv->sta_lock, flags);
- return ret;
+ return iwl_send_add_sta(priv, &sta_cmd, CMD_SYNC);
}
static int iwl_set_tkip_dynamic_key_info(struct iwl_priv *priv,
@@ -972,24 +989,16 @@ void iwl_update_tkip_key(struct iwl_priv *priv,
unsigned long flags;
int i;
- if (sta) {
- sta_id = iwl_sta_id(sta);
-
- if (sta_id == IWL_INVALID_STATION) {
- IWL_DEBUG_MAC80211(priv, "leave - %pM not initialised.\n",
- sta->addr);
- return;
- }
- } else
- sta_id = priv->hw_params.bcast_sta_id;
-
-
if (iwl_scan_cancel(priv)) {
/* cancel scan failed, just live w/ bad key and rely
briefly on SW decryption */
return;
}
+ sta_id = iwl_sta_id_or_broadcast(priv, sta);
+ if (sta_id == IWL_INVALID_STATION)
+ return;
+
spin_lock_irqsave(&priv->sta_lock, flags);
priv->stations[sta_id].sta.key.tkip_rx_tsc_byte2 = (u8) iv32;
@@ -1013,9 +1022,11 @@ int iwl_remove_dynamic_key(struct iwl_priv *priv,
u8 sta_id)
{
unsigned long flags;
- int ret = 0;
u16 key_flags;
u8 keyidx;
+ struct iwl_addsta_cmd sta_cmd;
+
+ lockdep_assert_held(&priv->mutex);
priv->key_mapping_key--;
@@ -1062,9 +1073,10 @@ int iwl_remove_dynamic_key(struct iwl_priv *priv,
spin_unlock_irqrestore(&priv->sta_lock, flags);
return 0;
}
- ret = iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC);
+ memcpy(&sta_cmd, &priv->stations[sta_id].sta, sizeof(struct iwl_addsta_cmd));
spin_unlock_irqrestore(&priv->sta_lock, flags);
- return ret;
+
+ return iwl_send_add_sta(priv, &sta_cmd, CMD_SYNC);
}
EXPORT_SYMBOL(iwl_remove_dynamic_key);
@@ -1073,6 +1085,8 @@ int iwl_set_dynamic_key(struct iwl_priv *priv,
{
int ret;
+ lockdep_assert_held(&priv->mutex);
+
priv->key_mapping_key++;
keyconf->hw_key_idx = HW_KEY_DYNAMIC;
@@ -1245,6 +1259,36 @@ int iwl_alloc_bcast_station(struct iwl_priv *priv, bool init_lq)
}
EXPORT_SYMBOL_GPL(iwl_alloc_bcast_station);
+/**
+ * iwl_update_bcast_station - update broadcast station's LQ command
+ *
+ * Only used by iwlagn. Placed here to have all bcast station management
+ * code together.
+ */
+int iwl_update_bcast_station(struct iwl_priv *priv)
+{
+ unsigned long flags;
+ struct iwl_link_quality_cmd *link_cmd;
+ u8 sta_id = priv->hw_params.bcast_sta_id;
+
+ link_cmd = iwl_sta_alloc_lq(priv, sta_id);
+ if (!link_cmd) {
+ IWL_ERR(priv, "Unable to initialize rate scaling for bcast station.\n");
+ return -ENOMEM;
+ }
+
+ spin_lock_irqsave(&priv->sta_lock, flags);
+ if (priv->stations[sta_id].lq)
+ kfree(priv->stations[sta_id].lq);
+ else
+ IWL_DEBUG_INFO(priv, "Bcast station rate scaling has not been initialized yet.\n");
+ priv->stations[sta_id].lq = link_cmd;
+ spin_unlock_irqrestore(&priv->sta_lock, flags);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(iwl_update_bcast_station);
+
void iwl_dealloc_bcast_station(struct iwl_priv *priv)
{
unsigned long flags;
@@ -1268,18 +1312,22 @@ EXPORT_SYMBOL_GPL(iwl_dealloc_bcast_station);
/**
* iwl_sta_tx_modify_enable_tid - Enable Tx for this TID in station table
*/
-void iwl_sta_tx_modify_enable_tid(struct iwl_priv *priv, int sta_id, int tid)
+int iwl_sta_tx_modify_enable_tid(struct iwl_priv *priv, int sta_id, int tid)
{
unsigned long flags;
+ struct iwl_addsta_cmd sta_cmd;
+
+ lockdep_assert_held(&priv->mutex);
/* Remove "disable" flag, to enable Tx for this TID */
spin_lock_irqsave(&priv->sta_lock, flags);
priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_TID_DISABLE_TX;
priv->stations[sta_id].sta.tid_disable_tx &= cpu_to_le16(~(1 << tid));
priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
+ memcpy(&sta_cmd, &priv->stations[sta_id].sta, sizeof(struct iwl_addsta_cmd));
spin_unlock_irqrestore(&priv->sta_lock, flags);
- iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC);
+ return iwl_send_add_sta(priv, &sta_cmd, CMD_SYNC);
}
EXPORT_SYMBOL(iwl_sta_tx_modify_enable_tid);
@@ -1288,6 +1336,9 @@ int iwl_sta_rx_agg_start(struct iwl_priv *priv, struct ieee80211_sta *sta,
{
unsigned long flags;
int sta_id;
+ struct iwl_addsta_cmd sta_cmd;
+
+ lockdep_assert_held(&priv->mutex);
sta_id = iwl_sta_id(sta);
if (sta_id == IWL_INVALID_STATION)
@@ -1299,10 +1350,10 @@ int iwl_sta_rx_agg_start(struct iwl_priv *priv, struct ieee80211_sta *sta,
priv->stations[sta_id].sta.add_immediate_ba_tid = (u8)tid;
priv->stations[sta_id].sta.add_immediate_ba_ssn = cpu_to_le16(ssn);
priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
+ memcpy(&sta_cmd, &priv->stations[sta_id].sta, sizeof(struct iwl_addsta_cmd));
spin_unlock_irqrestore(&priv->sta_lock, flags);
- return iwl_send_add_sta(priv, &priv->stations[sta_id].sta,
- CMD_ASYNC);
+ return iwl_send_add_sta(priv, &sta_cmd, CMD_SYNC);
}
EXPORT_SYMBOL(iwl_sta_rx_agg_start);
@@ -1311,6 +1362,9 @@ int iwl_sta_rx_agg_stop(struct iwl_priv *priv, struct ieee80211_sta *sta,
{
unsigned long flags;
int sta_id;
+ struct iwl_addsta_cmd sta_cmd;
+
+ lockdep_assert_held(&priv->mutex);
sta_id = iwl_sta_id(sta);
if (sta_id == IWL_INVALID_STATION) {
@@ -1323,10 +1377,10 @@ int iwl_sta_rx_agg_stop(struct iwl_priv *priv, struct ieee80211_sta *sta,
priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_DELBA_TID_MSK;
priv->stations[sta_id].sta.remove_immediate_ba_tid = (u8)tid;
priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
+ memcpy(&sta_cmd, &priv->stations[sta_id].sta, sizeof(struct iwl_addsta_cmd));
spin_unlock_irqrestore(&priv->sta_lock, flags);
- return iwl_send_add_sta(priv, &priv->stations[sta_id].sta,
- CMD_ASYNC);
+ return iwl_send_add_sta(priv, &sta_cmd, CMD_SYNC);
}
EXPORT_SYMBOL(iwl_sta_rx_agg_stop);
@@ -1340,9 +1394,9 @@ void iwl_sta_modify_ps_wake(struct iwl_priv *priv, int sta_id)
priv->stations[sta_id].sta.sta.modify_mask = 0;
priv->stations[sta_id].sta.sleep_tx_count = 0;
priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
+ iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC);
spin_unlock_irqrestore(&priv->sta_lock, flags);
- iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC);
}
EXPORT_SYMBOL(iwl_sta_modify_ps_wake);
@@ -1357,9 +1411,9 @@ void iwl_sta_modify_sleep_tx_count(struct iwl_priv *priv, int sta_id, int cnt)
STA_MODIFY_SLEEP_TX_COUNT_MSK;
priv->stations[sta_id].sta.sleep_tx_count = cpu_to_le16(cnt);
priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
+ iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC);
spin_unlock_irqrestore(&priv->sta_lock, flags);
- iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC);
}
EXPORT_SYMBOL(iwl_sta_modify_sleep_tx_count);
diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.h b/drivers/net/wireless/iwlwifi/iwl-sta.h
index dc43ebd1f1f..d38a350ba0b 100644
--- a/drivers/net/wireless/iwlwifi/iwl-sta.h
+++ b/drivers/net/wireless/iwlwifi/iwl-sta.h
@@ -60,6 +60,7 @@ void iwl_restore_stations(struct iwl_priv *priv);
void iwl_clear_ucode_stations(struct iwl_priv *priv);
int iwl_alloc_bcast_station(struct iwl_priv *priv, bool init_lq);
void iwl_dealloc_bcast_station(struct iwl_priv *priv);
+int iwl_update_bcast_station(struct iwl_priv *priv);
int iwl_get_free_ucode_key_index(struct iwl_priv *priv);
int iwl_send_add_sta(struct iwl_priv *priv,
struct iwl_addsta_cmd *sta, u8 flags);
@@ -73,7 +74,7 @@ int iwl_remove_station(struct iwl_priv *priv, const u8 sta_id,
const u8 *addr);
int iwl_mac_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
struct ieee80211_sta *sta);
-void iwl_sta_tx_modify_enable_tid(struct iwl_priv *priv, int sta_id, int tid);
+int iwl_sta_tx_modify_enable_tid(struct iwl_priv *priv, int sta_id, int tid);
int iwl_sta_rx_agg_start(struct iwl_priv *priv, struct ieee80211_sta *sta,
int tid, u16 ssn);
int iwl_sta_rx_agg_stop(struct iwl_priv *priv, struct ieee80211_sta *sta,
@@ -118,4 +119,33 @@ static inline int iwl_sta_id(struct ieee80211_sta *sta)
return ((struct iwl_station_priv_common *)sta->drv_priv)->sta_id;
}
+
+/**
+ * iwl_sta_id_or_broadcast - return sta_id or broadcast sta
+ * @priv: iwl priv
+ * @sta: mac80211 station
+ *
+ * In certain circumstances mac80211 passes a station pointer
+ * that may be %NULL, for example during TX or key setup. In
+ * that case, we need to use the broadcast station, so this
+ * inline wraps that pattern.
+ */
+static inline int iwl_sta_id_or_broadcast(struct iwl_priv *priv,
+ struct ieee80211_sta *sta)
+{
+ int sta_id;
+
+ if (!sta)
+ return priv->hw_params.bcast_sta_id;
+
+ sta_id = iwl_sta_id(sta);
+
+ /*
+ * mac80211 should not be passing a partially
+ * initialised station!
+ */
+ WARN_ON(sta_id == IWL_INVALID_STATION);
+
+ return sta_id;
+}
#endif /* __iwl_sta_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c
index 1ece2ea0977..a81989c0698 100644
--- a/drivers/net/wireless/iwlwifi/iwl-tx.c
+++ b/drivers/net/wireless/iwlwifi/iwl-tx.c
@@ -77,21 +77,6 @@ void iwl_txq_update_write_ptr(struct iwl_priv *priv, struct iwl_tx_queue *txq)
}
EXPORT_SYMBOL(iwl_txq_update_write_ptr);
-
-void iwl_free_tfds_in_queue(struct iwl_priv *priv,
- int sta_id, int tid, int freed)
-{
- if (priv->stations[sta_id].tid[tid].tfds_in_queue >= freed)
- priv->stations[sta_id].tid[tid].tfds_in_queue -= freed;
- else {
- IWL_DEBUG_TX(priv, "free more than tfds_in_queue (%u:%d)\n",
- priv->stations[sta_id].tid[tid].tfds_in_queue,
- freed);
- priv->stations[sta_id].tid[tid].tfds_in_queue = 0;
- }
-}
-EXPORT_SYMBOL(iwl_free_tfds_in_queue);
-
/**
* iwl_tx_queue_free - Deallocate DMA queue.
* @txq: Transmit queue to deallocate.
@@ -169,15 +154,15 @@ void iwl_cmd_queue_free(struct iwl_priv *priv)
}
pci_unmap_single(priv->pci_dev,
- pci_unmap_addr(&txq->meta[i], mapping),
- pci_unmap_len(&txq->meta[i], len),
+ dma_unmap_addr(&txq->meta[i], mapping),
+ dma_unmap_len(&txq->meta[i], len),
PCI_DMA_BIDIRECTIONAL);
}
if (huge) {
i = q->n_window;
pci_unmap_single(priv->pci_dev,
- pci_unmap_addr(&txq->meta[i], mapping),
- pci_unmap_len(&txq->meta[i], len),
+ dma_unmap_addr(&txq->meta[i], mapping),
+ dma_unmap_len(&txq->meta[i], len),
PCI_DMA_BIDIRECTIONAL);
}
@@ -287,7 +272,7 @@ static int iwl_tx_queue_alloc(struct iwl_priv *priv,
/* Driver private data, only for Tx (not command) queues,
* not shared with device. */
if (id != IWL_CMD_QUEUE_NUM) {
- txq->txb = kmalloc(sizeof(txq->txb[0]) *
+ txq->txb = kzalloc(sizeof(txq->txb[0]) *
TFD_QUEUE_SIZE_MAX, GFP_KERNEL);
if (!txq->txb) {
IWL_ERR(priv, "kmalloc for auxiliary BD "
@@ -531,8 +516,8 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
phys_addr = pci_map_single(priv->pci_dev, &out_cmd->hdr,
fix_size, PCI_DMA_BIDIRECTIONAL);
- pci_unmap_addr_set(out_meta, mapping, phys_addr);
- pci_unmap_len_set(out_meta, len, fix_size);
+ dma_unmap_addr_set(out_meta, mapping, phys_addr);
+ dma_unmap_len_set(out_meta, len, fix_size);
trace_iwlwifi_dev_hcmd(priv, &out_cmd->hdr, fix_size, cmd->flags);
@@ -626,8 +611,8 @@ void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
meta = &txq->meta[cmd_index];
pci_unmap_single(priv->pci_dev,
- pci_unmap_addr(meta, mapping),
- pci_unmap_len(meta, len),
+ dma_unmap_addr(meta, mapping),
+ dma_unmap_len(meta, len),
PCI_DMA_BIDIRECTIONAL);
/* Input error checking is done when commands are added to queue. */
diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c
index a27872de410..d24eb47d370 100644
--- a/drivers/net/wireless/iwlwifi/iwl3945-base.c
+++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c
@@ -27,6 +27,8 @@
*
*****************************************************************************/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
@@ -197,6 +199,7 @@ static int iwl3945_set_wep_dynamic_key_info(struct iwl_priv *priv,
static int iwl3945_clear_sta_key_info(struct iwl_priv *priv, u8 sta_id)
{
unsigned long flags;
+ struct iwl_addsta_cmd sta_cmd;
spin_lock_irqsave(&priv->sta_lock, flags);
memset(&priv->stations[sta_id].keyinfo, 0, sizeof(struct iwl_hw_key));
@@ -205,11 +208,11 @@ static int iwl3945_clear_sta_key_info(struct iwl_priv *priv, u8 sta_id)
priv->stations[sta_id].sta.key.key_flags = STA_KEY_FLG_NO_ENC;
priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK;
priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
+ memcpy(&sta_cmd, &priv->stations[sta_id].sta, sizeof(struct iwl_addsta_cmd));
spin_unlock_irqrestore(&priv->sta_lock, flags);
IWL_DEBUG_INFO(priv, "hwcrypto: clear ucode station key info\n");
- iwl_send_add_sta(priv, &priv->stations[sta_id].sta, 0);
- return 0;
+ return iwl_send_add_sta(priv, &sta_cmd, CMD_SYNC);
}
static int iwl3945_set_dynamic_key(struct iwl_priv *priv,
@@ -310,9 +313,7 @@ unsigned int iwl3945_fill_beacon_frame(struct iwl_priv *priv,
int left)
{
- if (!iwl_is_associated(priv) || !priv->ibss_beacon ||
- ((priv->iw_mode != NL80211_IFTYPE_ADHOC) &&
- (priv->iw_mode != NL80211_IFTYPE_AP)))
+ if (!iwl_is_associated(priv) || !priv->ibss_beacon)
return 0;
if (priv->ibss_beacon->len > left)
@@ -474,10 +475,8 @@ static int iwl3945_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
u8 unicast;
u8 sta_id;
u8 tid = 0;
- u16 seq_number = 0;
__le16 fc;
u8 wait_write_ptr = 0;
- u8 *qc = NULL;
unsigned long flags;
spin_lock_irqsave(&priv->lock, flags);
@@ -510,10 +509,7 @@ static int iwl3945_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
hdr_len = ieee80211_hdrlen(fc);
/* Find index into station table for destination station */
- if (!info->control.sta)
- sta_id = priv->hw_params.bcast_sta_id;
- else
- sta_id = iwl_sta_id(info->control.sta);
+ sta_id = iwl_sta_id_or_broadcast(priv, info->control.sta);
if (sta_id == IWL_INVALID_STATION) {
IWL_DEBUG_DROP(priv, "Dropping - INVALID STATION: %pM\n",
hdr->addr1);
@@ -523,16 +519,10 @@ static int iwl3945_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
IWL_DEBUG_RATE(priv, "station Id %d\n", sta_id);
if (ieee80211_is_data_qos(fc)) {
- qc = ieee80211_get_qos_ctl(hdr);
+ u8 *qc = ieee80211_get_qos_ctl(hdr);
tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK;
if (unlikely(tid >= MAX_TID_COUNT))
goto drop;
- seq_number = priv->stations[sta_id].tid[tid].seq_number &
- IEEE80211_SCTL_SEQ;
- hdr->seq_ctrl = cpu_to_le16(seq_number) |
- (hdr->seq_ctrl &
- cpu_to_le16(IEEE80211_SCTL_FRAG));
- seq_number += 0x10;
}
/* Descriptor for chosen Tx queue */
@@ -548,7 +538,7 @@ static int iwl3945_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
/* Set up driver data for this TFD */
memset(&(txq->txb[q->write_ptr]), 0, sizeof(struct iwl_tx_info));
- txq->txb[q->write_ptr].skb[0] = skb;
+ txq->txb[q->write_ptr].skb = skb;
/* Init first empty entry in queue's array of Tx/cmd buffers */
out_cmd = txq->cmd[idx];
@@ -591,8 +581,6 @@ static int iwl3945_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
if (!ieee80211_has_morefrags(hdr->frame_control)) {
txq->need_update = 1;
- if (qc)
- priv->stations[sta_id].tid[tid].seq_number = seq_number;
} else {
wait_write_ptr = 1;
txq->need_update = 0;
@@ -631,8 +619,8 @@ static int iwl3945_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
len, PCI_DMA_TODEVICE);
/* we do not map meta data ... so we can safely access address to
* provide to unmap command*/
- pci_unmap_addr_set(out_meta, mapping, txcmd_phys);
- pci_unmap_len_set(out_meta, len, len);
+ dma_unmap_addr_set(out_meta, mapping, txcmd_phys);
+ dma_unmap_len_set(out_meta, len, len);
/* Add buffer containing Tx command and MAC(!) header to TFD's
* first entry */
@@ -677,55 +665,6 @@ drop:
return -1;
}
-#define BEACON_TIME_MASK_LOW 0x00FFFFFF
-#define BEACON_TIME_MASK_HIGH 0xFF000000
-#define TIME_UNIT 1024
-
-/*
- * extended beacon time format
- * time in usec will be changed into a 32-bit value in 8:24 format
- * the high 1 byte is the beacon counts
- * the lower 3 bytes is the time in usec within one beacon interval
- */
-
-static u32 iwl3945_usecs_to_beacons(u32 usec, u32 beacon_interval)
-{
- u32 quot;
- u32 rem;
- u32 interval = beacon_interval * 1024;
-
- if (!interval || !usec)
- return 0;
-
- quot = (usec / interval) & (BEACON_TIME_MASK_HIGH >> 24);
- rem = (usec % interval) & BEACON_TIME_MASK_LOW;
-
- return (quot << 24) + rem;
-}
-
-/* base is usually what we get from ucode with each received frame,
- * the same as HW timer counter counting down
- */
-
-static __le32 iwl3945_add_beacon_time(u32 base, u32 addon, u32 beacon_interval)
-{
- u32 base_low = base & BEACON_TIME_MASK_LOW;
- u32 addon_low = addon & BEACON_TIME_MASK_LOW;
- u32 interval = beacon_interval * TIME_UNIT;
- u32 res = (base & BEACON_TIME_MASK_HIGH) +
- (addon & BEACON_TIME_MASK_HIGH);
-
- if (base_low > addon_low)
- res += base_low - addon_low;
- else if (base_low < addon_low) {
- res += interval + base_low - addon_low;
- res += (1 << 24);
- } else
- res += (1 << 24);
-
- return cpu_to_le32(res);
-}
-
static int iwl3945_get_measurement(struct iwl_priv *priv,
struct ieee80211_measurement_params *params,
u8 type)
@@ -743,8 +682,7 @@ static int iwl3945_get_measurement(struct iwl_priv *priv,
int duration = le16_to_cpu(params->duration);
if (iwl_is_associated(priv))
- add_time =
- iwl3945_usecs_to_beacons(
+ add_time = iwl_usecs_to_beacons(priv,
le64_to_cpu(params->start_time) - priv->_3945.last_tsf,
le16_to_cpu(priv->rxon_timing.beacon_interval));
@@ -759,8 +697,8 @@ static int iwl3945_get_measurement(struct iwl_priv *priv,
if (iwl_is_associated(priv))
spectrum.start_time =
- iwl3945_add_beacon_time(priv->_3945.last_beacon_time,
- add_time,
+ iwl_add_beacon_time(priv,
+ priv->_3945.last_beacon_time, add_time,
le16_to_cpu(priv->rxon_timing.beacon_interval));
else
spectrum.start_time = 0;
@@ -1233,7 +1171,7 @@ static void iwl3945_rx_queue_free(struct iwl_priv *priv, struct iwl_rx_queue *rx
}
dma_free_coherent(&priv->pci_dev->dev, 4 * RX_QUEUE_SIZE, rxq->bd,
- rxq->dma_addr);
+ rxq->bd_dma);
dma_free_coherent(&priv->pci_dev->dev, sizeof(struct iwl_rb_status),
rxq->rb_stts, rxq->rb_stts_dma);
rxq->bd = NULL;
@@ -1314,6 +1252,8 @@ static void iwl3945_rx_handle(struct iwl_priv *priv)
IWL_DEBUG_RX(priv, "r = %d, i = %d\n", r, i);
while (i != r) {
+ int len;
+
rxb = rxq->queue[i];
/* If an RXB doesn't have a Rx queue slot associated with it,
@@ -1328,8 +1268,9 @@ static void iwl3945_rx_handle(struct iwl_priv *priv)
PCI_DMA_FROMDEVICE);
pkt = rxb_addr(rxb);
- trace_iwlwifi_dev_rx(priv, pkt,
- le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK);
+ len = le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK;
+ len += sizeof(u32); /* account for status word */
+ trace_iwlwifi_dev_rx(priv, pkt, len);
/* Reclaim a command buffer only if this packet is a response
* to a (driver-originated) command.
@@ -1483,7 +1424,7 @@ void iwl3945_dump_nic_error_log(struct iwl_priv *priv)
iwl_read_targ_mem(priv, base + i + 6 * sizeof(u32));
IWL_ERR(priv,
- "%-13s (#%d) %010u 0x%05X 0x%05X 0x%05X 0x%05X %u\n\n",
+ "%-13s (0x%X) %010u 0x%05X 0x%05X 0x%05X 0x%05X %u\n\n",
desc_lookup(desc), desc, time, blink1, blink2,
ilink1, ilink2, data1);
trace_iwlwifi_dev_ucode_error(priv, desc, time, data1, 0,
@@ -2942,7 +2883,10 @@ void iwl3945_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif)
IWL_DEBUG_INFO(priv, "Scanning while associated...\n");
spin_lock_irqsave(&priv->lock, flags);
- interval = vif ? vif->bss_conf.beacon_int : 0;
+ if (priv->is_internal_short_scan)
+ interval = 0;
+ else
+ interval = vif->bss_conf.beacon_int;
spin_unlock_irqrestore(&priv->lock, flags);
scan->suspend_time = 0;
@@ -3022,14 +2966,16 @@ void iwl3945_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif)
scan->tx_cmd.len = cpu_to_le16(
iwl_fill_probe_req(priv,
(struct ieee80211_mgmt *)scan->data,
+ vif->addr,
priv->scan_request->ie,
priv->scan_request->ie_len,
IWL_MAX_SCAN_SIZE - sizeof(*scan)));
} else {
+ /* use bcast addr, will not be transmitted but must be valid */
scan->tx_cmd.len = cpu_to_le16(
iwl_fill_probe_req(priv,
(struct ieee80211_mgmt *)scan->data,
- NULL, 0,
+ iwl_bcast_addr, NULL, 0,
IWL_MAX_SCAN_SIZE - sizeof(*scan)));
}
/* select Rx antennas */
@@ -3158,19 +3104,16 @@ void iwl3945_post_associate(struct iwl_priv *priv, struct ieee80211_vif *vif)
IWL_DEBUG_ASSOC(priv, "assoc id %d beacon interval %d\n",
vif->bss_conf.aid, vif->bss_conf.beacon_int);
- if (vif->bss_conf.assoc_capability & WLAN_CAPABILITY_SHORT_PREAMBLE)
+ if (vif->bss_conf.use_short_preamble)
priv->staging_rxon.flags |= RXON_FLG_SHORT_PREAMBLE_MSK;
else
priv->staging_rxon.flags &= ~RXON_FLG_SHORT_PREAMBLE_MSK;
if (priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK) {
- if (vif->bss_conf.assoc_capability & WLAN_CAPABILITY_SHORT_SLOT_TIME)
+ if (vif->bss_conf.use_short_slot)
priv->staging_rxon.flags |= RXON_FLG_SHORT_SLOT_MSK;
else
priv->staging_rxon.flags &= ~RXON_FLG_SHORT_SLOT_MSK;
-
- if (vif->type == NL80211_IFTYPE_ADHOC)
- priv->staging_rxon.flags &= ~RXON_FLG_SHORT_SLOT_MSK;
}
iwlcore_commit_rxon(priv);
@@ -3334,8 +3277,7 @@ void iwl3945_config_ap(struct iwl_priv *priv, struct ieee80211_vif *vif)
priv->staging_rxon.assoc_id = 0;
- if (vif->bss_conf.assoc_capability &
- WLAN_CAPABILITY_SHORT_PREAMBLE)
+ if (vif->bss_conf.use_short_preamble)
priv->staging_rxon.flags |=
RXON_FLG_SHORT_PREAMBLE_MSK;
else
@@ -3343,17 +3285,12 @@ void iwl3945_config_ap(struct iwl_priv *priv, struct ieee80211_vif *vif)
~RXON_FLG_SHORT_PREAMBLE_MSK;
if (priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK) {
- if (vif->bss_conf.assoc_capability &
- WLAN_CAPABILITY_SHORT_SLOT_TIME)
+ if (vif->bss_conf.use_short_slot)
priv->staging_rxon.flags |=
RXON_FLG_SHORT_SLOT_MSK;
else
priv->staging_rxon.flags &=
~RXON_FLG_SHORT_SLOT_MSK;
-
- if (vif->type == NL80211_IFTYPE_ADHOC)
- priv->staging_rxon.flags &=
- ~RXON_FLG_SHORT_SLOT_MSK;
}
/* restore RXON assoc */
priv->staging_rxon.filter_flags |= RXON_FILTER_ASSOC_MSK;
@@ -3386,17 +3323,9 @@ static int iwl3945_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
static_key = !iwl_is_associated(priv);
if (!static_key) {
- if (!sta) {
- sta_id = priv->hw_params.bcast_sta_id;
- } else {
- sta_id = iwl_sta_id(sta);
- if (sta_id == IWL_INVALID_STATION) {
- IWL_DEBUG_MAC80211(priv,
- "leave - %pM not in station map.\n",
- sta->addr);
- return -EINVAL;
- }
- }
+ sta_id = iwl_sta_id_or_broadcast(priv, sta);
+ if (sta_id == IWL_INVALID_STATION)
+ return -EINVAL;
}
mutex_lock(&priv->mutex);
@@ -4006,7 +3935,7 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
* space for this driver's private structure */
hw = iwl_alloc_all(cfg, &iwl3945_hw_ops);
if (hw == NULL) {
- printk(KERN_ERR DRV_NAME "Can not allocate network device\n");
+ pr_err("Can not allocate network device\n");
err = -ENOMEM;
goto out;
}
@@ -4028,9 +3957,6 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
priv->pci_dev = pdev;
priv->inta_mask = CSR_INI_SET_MASK;
-#ifdef CONFIG_IWLWIFI_DEBUG
- atomic_set(&priv->restrict_refcnt, 0);
-#endif
if (iwl_alloc_traffic_mem(priv))
IWL_ERR(priv, "Not enough memory to generate traffic log\n");
@@ -4099,9 +4025,8 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
}
/* MAC Address location in EEPROM same for 3945/4965 */
eeprom = (struct iwl3945_eeprom *)priv->eeprom;
- memcpy(priv->mac_addr, eeprom->mac_address, ETH_ALEN);
- IWL_DEBUG_INFO(priv, "MAC address: %pM\n", priv->mac_addr);
- SET_IEEE80211_PERM_ADDR(priv->hw, priv->mac_addr);
+ IWL_DEBUG_INFO(priv, "MAC address: %pM\n", eeprom->mac_address);
+ SET_IEEE80211_PERM_ADDR(priv->hw, eeprom->mac_address);
/***********************
* 5. Setup HW Constants
@@ -4302,19 +4227,18 @@ static int __init iwl3945_init(void)
{
int ret;
- printk(KERN_INFO DRV_NAME ": " DRV_DESCRIPTION ", " DRV_VERSION "\n");
- printk(KERN_INFO DRV_NAME ": " DRV_COPYRIGHT "\n");
+ pr_info(DRV_DESCRIPTION ", " DRV_VERSION "\n");
+ pr_info(DRV_COPYRIGHT "\n");
ret = iwl3945_rate_control_register();
if (ret) {
- printk(KERN_ERR DRV_NAME
- "Unable to register rate control algorithm: %d\n", ret);
+ pr_err("Unable to register rate control algorithm: %d\n", ret);
return ret;
}
ret = pci_register_driver(&iwl3945_driver);
if (ret) {
- printk(KERN_ERR DRV_NAME "Unable to initialize PCI module\n");
+ pr_err("Unable to initialize PCI module\n");
goto error_register;
}
diff --git a/drivers/net/wireless/iwmc3200wifi/cfg80211.c b/drivers/net/wireless/iwmc3200wifi/cfg80211.c
index 902e95f70f6..60619678f4e 100644
--- a/drivers/net/wireless/iwmc3200wifi/cfg80211.c
+++ b/drivers/net/wireless/iwmc3200wifi/cfg80211.c
@@ -670,20 +670,24 @@ static int iwm_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev,
}
static int iwm_cfg80211_set_txpower(struct wiphy *wiphy,
- enum tx_power_setting type, int dbm)
+ enum nl80211_tx_power_setting type, int mbm)
{
struct iwm_priv *iwm = wiphy_to_iwm(wiphy);
int ret;
switch (type) {
- case TX_POWER_AUTOMATIC:
+ case NL80211_TX_POWER_AUTOMATIC:
return 0;
- case TX_POWER_FIXED:
+ case NL80211_TX_POWER_FIXED:
+ if (mbm < 0 || (mbm % 100))
+ return -EOPNOTSUPP;
+
if (!test_bit(IWM_STATUS_READY, &iwm->status))
return 0;
ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX,
- CFG_TX_PWR_LIMIT_USR, dbm * 2);
+ CFG_TX_PWR_LIMIT_USR,
+ MBM_TO_DBM(mbm) * 2);
if (ret < 0)
return ret;
diff --git a/drivers/net/wireless/iwmc3200wifi/commands.h b/drivers/net/wireless/iwmc3200wifi/commands.h
index 7e16bcf5997..6421689f5e8 100644
--- a/drivers/net/wireless/iwmc3200wifi/commands.h
+++ b/drivers/net/wireless/iwmc3200wifi/commands.h
@@ -56,7 +56,7 @@
struct iwm_umac_cmd_reset {
__le32 flags;
-} __attribute__ ((packed));
+} __packed;
#define UMAC_PARAM_TBL_ORD_FIX 0x0
#define UMAC_PARAM_TBL_ORD_VAR 0x1
@@ -220,37 +220,37 @@ struct iwm_umac_cmd_set_param_fix {
__le16 tbl;
__le16 key;
__le32 value;
-} __attribute__ ((packed));
+} __packed;
struct iwm_umac_cmd_set_param_var {
__le16 tbl;
__le16 key;
__le16 len;
__le16 reserved;
-} __attribute__ ((packed));
+} __packed;
struct iwm_umac_cmd_get_param {
__le16 tbl;
__le16 key;
-} __attribute__ ((packed));
+} __packed;
struct iwm_umac_cmd_get_param_resp {
__le16 tbl;
__le16 key;
__le16 len;
__le16 reserved;
-} __attribute__ ((packed));
+} __packed;
struct iwm_umac_cmd_eeprom_proxy_hdr {
__le32 type;
__le32 offset;
__le32 len;
-} __attribute__ ((packed));
+} __packed;
struct iwm_umac_cmd_eeprom_proxy {
struct iwm_umac_cmd_eeprom_proxy_hdr hdr;
u8 buf[0];
-} __attribute__ ((packed));
+} __packed;
#define IWM_UMAC_CMD_EEPROM_TYPE_READ 0x1
#define IWM_UMAC_CMD_EEPROM_TYPE_WRITE 0x2
@@ -267,13 +267,13 @@ struct iwm_umac_channel_info {
u8 reserved;
u8 flags;
__le32 channels_mask;
-} __attribute__ ((packed));
+} __packed;
struct iwm_umac_cmd_get_channel_list {
__le16 count;
__le16 reserved;
struct iwm_umac_channel_info ch[0];
-} __attribute__ ((packed));
+} __packed;
/* UMAC WiFi interface commands */
@@ -304,7 +304,7 @@ struct iwm_umac_ssid {
u8 ssid_len;
u8 ssid[IEEE80211_MAX_SSID_LEN];
u8 reserved[3];
-} __attribute__ ((packed));
+} __packed;
struct iwm_umac_cmd_scan_request {
struct iwm_umac_wifi_if hdr;
@@ -314,7 +314,7 @@ struct iwm_umac_cmd_scan_request {
u8 timeout; /* In seconds */
u8 reserved;
struct iwm_umac_ssid ssids[UMAC_WIFI_IF_PROBE_OPTION_MAX];
-} __attribute__ ((packed));
+} __packed;
#define UMAC_CIPHER_TYPE_NONE 0xFF
#define UMAC_CIPHER_TYPE_USE_GROUPCAST 0x00
@@ -357,7 +357,7 @@ struct iwm_umac_security {
u8 ucast_cipher;
u8 mcast_cipher;
u8 flags;
-} __attribute__ ((packed));
+} __packed;
struct iwm_umac_ibss {
u8 beacon_interval; /* in millisecond */
@@ -366,7 +366,7 @@ struct iwm_umac_ibss {
u8 band;
u8 channel;
u8 reserved[3];
-} __attribute__ ((packed));
+} __packed;
#define UMAC_MODE_BSS 0
#define UMAC_MODE_IBSS 1
@@ -385,13 +385,13 @@ struct iwm_umac_profile {
__le16 flags;
u8 wireless_mode;
u8 bss_num;
-} __attribute__ ((packed));
+} __packed;
struct iwm_umac_invalidate_profile {
struct iwm_umac_wifi_if hdr;
u8 reason;
u8 reserved[3];
-} __attribute__ ((packed));
+} __packed;
/* Encryption key commands */
struct iwm_umac_key_wep40 {
@@ -400,7 +400,7 @@ struct iwm_umac_key_wep40 {
u8 key[WLAN_KEY_LEN_WEP40];
u8 static_key;
u8 reserved[2];
-} __attribute__ ((packed));
+} __packed;
struct iwm_umac_key_wep104 {
struct iwm_umac_wifi_if hdr;
@@ -408,7 +408,7 @@ struct iwm_umac_key_wep104 {
u8 key[WLAN_KEY_LEN_WEP104];
u8 static_key;
u8 reserved[2];
-} __attribute__ ((packed));
+} __packed;
#define IWM_TKIP_KEY_SIZE 16
#define IWM_TKIP_MIC_SIZE 8
@@ -420,7 +420,7 @@ struct iwm_umac_key_tkip {
u8 tkip_key[IWM_TKIP_KEY_SIZE];
u8 mic_rx_key[IWM_TKIP_MIC_SIZE];
u8 mic_tx_key[IWM_TKIP_MIC_SIZE];
-} __attribute__ ((packed));
+} __packed;
struct iwm_umac_key_ccmp {
struct iwm_umac_wifi_if hdr;
@@ -428,27 +428,27 @@ struct iwm_umac_key_ccmp {
u8 iv_count[6];
u8 reserved[2];
u8 key[WLAN_KEY_LEN_CCMP];
-} __attribute__ ((packed));
+} __packed;
struct iwm_umac_key_remove {
struct iwm_umac_wifi_if hdr;
struct iwm_umac_key_hdr key_hdr;
-} __attribute__ ((packed));
+} __packed;
struct iwm_umac_tx_key_id {
struct iwm_umac_wifi_if hdr;
u8 key_idx;
u8 reserved[3];
-} __attribute__ ((packed));
+} __packed;
struct iwm_umac_pwr_trigger {
struct iwm_umac_wifi_if hdr;
__le32 reseved;
-} __attribute__ ((packed));
+} __packed;
struct iwm_umac_cmd_stats_req {
__le32 flags;
-} __attribute__ ((packed));
+} __packed;
struct iwm_umac_cmd_stop_resume_tx {
u8 flags;
@@ -456,7 +456,7 @@ struct iwm_umac_cmd_stop_resume_tx {
__le16 stop_resume_tid_msk;
__le16 last_seq_num[IWM_UMAC_TID_NR];
u16 reserved;
-} __attribute__ ((packed));
+} __packed;
#define IWM_CMD_PMKID_ADD 1
#define IWM_CMD_PMKID_DEL 2
@@ -468,7 +468,7 @@ struct iwm_umac_pmkid_update {
u8 bssid[ETH_ALEN];
__le16 reserved;
u8 pmkid[WLAN_PMKID_LEN];
-} __attribute__ ((packed));
+} __packed;
/* LMAC commands */
int iwm_read_mac(struct iwm_priv *iwm, u8 *mac);
diff --git a/drivers/net/wireless/iwmc3200wifi/hal.c b/drivers/net/wireless/iwmc3200wifi/hal.c
index 9531b18cf72..907ac890997 100644
--- a/drivers/net/wireless/iwmc3200wifi/hal.c
+++ b/drivers/net/wireless/iwmc3200wifi/hal.c
@@ -54,7 +54,7 @@
* LMAC. If you look at LMAC commands you'll se that they
* are actually regular iwlwifi target commands encapsulated
* into a special UMAC command called UMAC passthrough.
- * This is due to the fact the the host talks exclusively
+ * This is due to the fact the host talks exclusively
* to the UMAC and so there needs to be a special UMAC
* command for talking to the LMAC.
* This is how a wifi command is layed out:
diff --git a/drivers/net/wireless/iwmc3200wifi/iwm.h b/drivers/net/wireless/iwmc3200wifi/iwm.h
index 13266c3842f..51d7efa15ae 100644
--- a/drivers/net/wireless/iwmc3200wifi/iwm.h
+++ b/drivers/net/wireless/iwmc3200wifi/iwm.h
@@ -162,7 +162,7 @@ struct iwm_umac_key_hdr {
u8 mac[ETH_ALEN];
u8 key_idx;
u8 multicast; /* BCast encrypt & BCast decrypt of frames FROM mac */
-} __attribute__ ((packed));
+} __packed;
struct iwm_key {
struct iwm_umac_key_hdr hdr;
diff --git a/drivers/net/wireless/iwmc3200wifi/lmac.h b/drivers/net/wireless/iwmc3200wifi/lmac.h
index a855a99e49b..5ddcdf8c70c 100644
--- a/drivers/net/wireless/iwmc3200wifi/lmac.h
+++ b/drivers/net/wireless/iwmc3200wifi/lmac.h
@@ -43,7 +43,7 @@ struct iwm_lmac_hdr {
u8 id;
u8 flags;
__le16 seq_num;
-} __attribute__ ((packed));
+} __packed;
/* LMAC commands */
#define CALIB_CFG_FLAG_SEND_COMPLETE_NTFY_AFTER_MSK 0x1
@@ -54,23 +54,23 @@ struct iwm_lmac_cal_cfg_elt {
__le32 send_res; /* 1 for sending back results */
__le32 apply_res; /* 1 for applying calibration results to HW */
__le32 reserved;
-} __attribute__ ((packed));
+} __packed;
struct iwm_lmac_cal_cfg_status {
struct iwm_lmac_cal_cfg_elt init;
struct iwm_lmac_cal_cfg_elt periodic;
__le32 flags; /* CALIB_CFG_FLAG_SEND_COMPLETE_NTFY_AFTER_MSK */
-} __attribute__ ((packed));
+} __packed;
struct iwm_lmac_cal_cfg_cmd {
struct iwm_lmac_cal_cfg_status ucode_cfg;
struct iwm_lmac_cal_cfg_status driver_cfg;
__le32 reserved;
-} __attribute__ ((packed));
+} __packed;
struct iwm_lmac_cal_cfg_resp {
__le32 status;
-} __attribute__ ((packed));
+} __packed;
#define IWM_CARD_STATE_SW_HW_ENABLED 0x00
#define IWM_CARD_STATE_HW_DISABLED 0x01
@@ -80,7 +80,7 @@ struct iwm_lmac_cal_cfg_resp {
struct iwm_lmac_card_state {
__le32 flags;
-} __attribute__ ((packed));
+} __packed;
/**
* COEX_PRIORITY_TABLE_CMD
@@ -131,7 +131,7 @@ struct coex_event {
u8 win_med_prio;
u8 reserved;
u8 flags;
-} __attribute__ ((packed));
+} __packed;
#define COEX_FLAGS_STA_TABLE_VALID_MSK 0x1
#define COEX_FLAGS_UNASSOC_WAKEUP_UMASK_MSK 0x4
@@ -142,7 +142,7 @@ struct iwm_coex_prio_table_cmd {
u8 flags;
u8 reserved[3];
struct coex_event sta_prio[COEX_EVENTS_NUM];
-} __attribute__ ((packed));
+} __packed;
/* Coexistence definitions
*
@@ -192,7 +192,7 @@ struct iwm_ct_kill_cfg_cmd {
u32 exit_threshold;
u32 reserved;
u32 entry_threshold;
-} __attribute__ ((packed));
+} __packed;
/* LMAC OP CODES */
@@ -428,7 +428,7 @@ struct iwm_lmac_calib_hdr {
u8 first_grp;
u8 grp_num;
u8 all_data_valid;
-} __attribute__ ((packed));
+} __packed;
#define IWM_LMAC_CALIB_FREQ_GROUPS_NR 7
#define IWM_CALIB_FREQ_GROUPS_NR 5
@@ -437,20 +437,20 @@ struct iwm_lmac_calib_hdr {
struct iwm_calib_rxiq_entry {
u16 ptam_postdist_ars;
u16 ptam_postdist_arc;
-} __attribute__ ((packed));
+} __packed;
struct iwm_calib_rxiq_group {
struct iwm_calib_rxiq_entry mode[IWM_CALIB_DC_MODES_NR];
-} __attribute__ ((packed));
+} __packed;
struct iwm_lmac_calib_rxiq {
struct iwm_calib_rxiq_group group[IWM_LMAC_CALIB_FREQ_GROUPS_NR];
-} __attribute__ ((packed));
+} __packed;
struct iwm_calib_rxiq {
struct iwm_lmac_calib_hdr hdr;
struct iwm_calib_rxiq_group group[IWM_CALIB_FREQ_GROUPS_NR];
-} __attribute__ ((packed));
+} __packed;
#define LMAC_STA_ID_SEED 0x0f
#define LMAC_STA_ID_POS 0
@@ -463,7 +463,7 @@ struct iwm_lmac_power_report {
u8 pa_integ_res_A[3];
u8 pa_integ_res_B[3];
u8 pa_integ_res_C[3];
-} __attribute__ ((packed));
+} __packed;
struct iwm_lmac_tx_resp {
u8 frame_cnt; /* 1-no aggregation, greater then 1 - aggregation */
@@ -479,6 +479,6 @@ struct iwm_lmac_tx_resp {
u8 ra_tid;
__le16 frame_ctl;
__le32 status;
-} __attribute__ ((packed));
+} __packed;
#endif
diff --git a/drivers/net/wireless/iwmc3200wifi/rx.c b/drivers/net/wireless/iwmc3200wifi/rx.c
index e1184deca55..c02fcedea9f 100644
--- a/drivers/net/wireless/iwmc3200wifi/rx.c
+++ b/drivers/net/wireless/iwmc3200wifi/rx.c
@@ -321,14 +321,14 @@ iwm_rx_ticket_node_alloc(struct iwm_priv *iwm, struct iwm_rx_ticket *ticket)
return ERR_PTR(-ENOMEM);
}
- ticket_node->ticket = kzalloc(sizeof(struct iwm_rx_ticket), GFP_KERNEL);
+ ticket_node->ticket = kmemdup(ticket, sizeof(struct iwm_rx_ticket),
+ GFP_KERNEL);
if (!ticket_node->ticket) {
IWM_ERR(iwm, "Couldn't allocate RX ticket\n");
kfree(ticket_node);
return ERR_PTR(-ENOMEM);
}
- memcpy(ticket_node->ticket, ticket, sizeof(struct iwm_rx_ticket));
INIT_LIST_HEAD(&ticket_node->node);
return ticket_node;
diff --git a/drivers/net/wireless/iwmc3200wifi/umac.h b/drivers/net/wireless/iwmc3200wifi/umac.h
index 0cbba3ecc81..4a137d334a4 100644
--- a/drivers/net/wireless/iwmc3200wifi/umac.h
+++ b/drivers/net/wireless/iwmc3200wifi/umac.h
@@ -42,19 +42,19 @@
struct iwm_udma_in_hdr {
__le32 cmd;
__le32 size;
-} __attribute__ ((packed));
+} __packed;
struct iwm_udma_out_nonwifi_hdr {
__le32 cmd;
__le32 addr;
__le32 op1_sz;
__le32 op2;
-} __attribute__ ((packed));
+} __packed;
struct iwm_udma_out_wifi_hdr {
__le32 cmd;
__le32 meta_data;
-} __attribute__ ((packed));
+} __packed;
/* Sequence numbering */
#define UMAC_WIFI_SEQ_NUM_BASE 1
@@ -408,12 +408,12 @@ struct iwm_rx_ticket {
__le16 flags;
u8 payload_offset; /* includes: MAC header, pad, IV */
u8 tail_len; /* includes: MIC, ICV, CRC (w/o STATUS) */
-} __attribute__ ((packed));
+} __packed;
struct iwm_rx_mpdu_hdr {
__le16 len;
__le16 reserved;
-} __attribute__ ((packed));
+} __packed;
/* UMAC SW WIFI API */
@@ -421,31 +421,31 @@ struct iwm_dev_cmd_hdr {
u8 cmd;
u8 flags;
__le16 seq_num;
-} __attribute__ ((packed));
+} __packed;
struct iwm_umac_fw_cmd_hdr {
__le32 meta_data;
struct iwm_dev_cmd_hdr cmd;
-} __attribute__ ((packed));
+} __packed;
struct iwm_umac_wifi_out_hdr {
struct iwm_udma_out_wifi_hdr hw_hdr;
struct iwm_umac_fw_cmd_hdr sw_hdr;
-} __attribute__ ((packed));
+} __packed;
struct iwm_umac_nonwifi_out_hdr {
struct iwm_udma_out_nonwifi_hdr hw_hdr;
-} __attribute__ ((packed));
+} __packed;
struct iwm_umac_wifi_in_hdr {
struct iwm_udma_in_hdr hw_hdr;
struct iwm_umac_fw_cmd_hdr sw_hdr;
-} __attribute__ ((packed));
+} __packed;
struct iwm_umac_nonwifi_in_hdr {
struct iwm_udma_in_hdr hw_hdr;
__le32 time_stamp;
-} __attribute__ ((packed));
+} __packed;
#define IWM_UMAC_PAGE_SIZE 0x200
@@ -521,7 +521,7 @@ struct iwm_umac_notif_wifi_if {
u8 status;
u8 flags;
__le16 buf_size;
-} __attribute__ ((packed));
+} __packed;
#define UMAC_ROAM_REASON_FIRST_SELECTION 0x1
#define UMAC_ROAM_REASON_AP_DEAUTH 0x2
@@ -535,7 +535,7 @@ struct iwm_umac_notif_assoc_start {
__le32 roam_reason;
u8 bssid[ETH_ALEN];
u8 reserved[2];
-} __attribute__ ((packed));
+} __packed;
#define UMAC_ASSOC_COMPLETE_SUCCESS 0x0
#define UMAC_ASSOC_COMPLETE_FAILURE 0x1
@@ -546,7 +546,7 @@ struct iwm_umac_notif_assoc_complete {
u8 bssid[ETH_ALEN];
u8 band;
u8 channel;
-} __attribute__ ((packed));
+} __packed;
#define UMAC_PROFILE_INVALID_ASSOC_TIMEOUT 0x0
#define UMAC_PROFILE_INVALID_ROAM_TIMEOUT 0x1
@@ -556,7 +556,7 @@ struct iwm_umac_notif_assoc_complete {
struct iwm_umac_notif_profile_invalidate {
struct iwm_umac_notif_wifi_if mlme_hdr;
__le32 reason;
-} __attribute__ ((packed));
+} __packed;
#define UMAC_SCAN_RESULT_SUCCESS 0x0
#define UMAC_SCAN_RESULT_ABORTED 0x1
@@ -568,7 +568,7 @@ struct iwm_umac_notif_scan_complete {
__le32 type;
__le32 result;
u8 seq_num;
-} __attribute__ ((packed));
+} __packed;
#define UMAC_OPCODE_ADD_MODIFY 0x0
#define UMAC_OPCODE_REMOVE 0x1
@@ -582,7 +582,7 @@ struct iwm_umac_notif_sta_info {
u8 mac_addr[ETH_ALEN];
u8 sta_id; /* bits 0-3: station ID, bits 4-7: station color */
u8 flags;
-} __attribute__ ((packed));
+} __packed;
#define UMAC_BAND_2GHZ 0
#define UMAC_BAND_5GHZ 1
@@ -601,7 +601,7 @@ struct iwm_umac_notif_bss_info {
s8 rssi;
u8 reserved;
u8 frame_buf[1];
-} __attribute__ ((packed));
+} __packed;
#define IWM_BSS_REMOVE_INDEX_MSK 0x0fff
#define IWM_BSS_REMOVE_FLAGS_MSK 0xfc00
@@ -614,13 +614,13 @@ struct iwm_umac_notif_bss_removed {
struct iwm_umac_notif_wifi_if mlme_hdr;
__le32 count;
__le16 entries[0];
-} __attribute__ ((packed));
+} __packed;
struct iwm_umac_notif_mgt_frame {
struct iwm_umac_notif_wifi_if mlme_hdr;
__le16 len;
u8 frame[1];
-} __attribute__ ((packed));
+} __packed;
struct iwm_umac_notif_alive {
struct iwm_umac_wifi_in_hdr hdr;
@@ -630,13 +630,13 @@ struct iwm_umac_notif_alive {
__le16 reserved2;
__le16 page_grp_count;
__le32 page_grp_state[IWM_MACS_OUT_GROUPS];
-} __attribute__ ((packed));
+} __packed;
struct iwm_umac_notif_init_complete {
struct iwm_umac_wifi_in_hdr hdr;
__le16 status;
__le16 reserved;
-} __attribute__ ((packed));
+} __packed;
/* error categories */
enum {
@@ -667,12 +667,12 @@ struct iwm_fw_error_hdr {
__le32 dbm_buf_end;
__le32 dbm_buf_write_ptr;
__le32 dbm_buf_cycle_cnt;
-} __attribute__ ((packed));
+} __packed;
struct iwm_umac_notif_error {
struct iwm_umac_wifi_in_hdr hdr;
struct iwm_fw_error_hdr err;
-} __attribute__ ((packed));
+} __packed;
#define UMAC_DEALLOC_NTFY_CHANGES_CNT_POS 0
#define UMAC_DEALLOC_NTFY_CHANGES_CNT_SEED 0xff
@@ -687,20 +687,20 @@ struct iwm_umac_notif_page_dealloc {
struct iwm_umac_wifi_in_hdr hdr;
__le32 changes;
__le32 grp_info[IWM_MACS_OUT_GROUPS];
-} __attribute__ ((packed));
+} __packed;
struct iwm_umac_notif_wifi_status {
struct iwm_umac_wifi_in_hdr hdr;
__le16 status;
__le16 reserved;
-} __attribute__ ((packed));
+} __packed;
struct iwm_umac_notif_rx_ticket {
struct iwm_umac_wifi_in_hdr hdr;
u8 num_tickets;
u8 reserved[3];
struct iwm_rx_ticket tickets[1];
-} __attribute__ ((packed));
+} __packed;
/* Tx/Rx rates window (number of max of last update window per second) */
#define UMAC_NTF_RATE_SAMPLE_NR 4
@@ -758,7 +758,7 @@ struct iwm_umac_notif_stats {
__le32 roam_unassoc;
__le32 roam_deauth;
__le32 roam_ap_loadblance;
-} __attribute__ ((packed));
+} __packed;
#define UMAC_STOP_TX_FLAG 0x1
#define UMAC_RESUME_TX_FLAG 0x2
@@ -770,7 +770,7 @@ struct iwm_umac_notif_stop_resume_tx {
u8 flags; /* UMAC_*_TX_FLAG_* */
u8 sta_id;
__le16 stop_resume_tid_msk; /* tid bitmask */
-} __attribute__ ((packed));
+} __packed;
#define UMAC_MAX_NUM_PMKIDS 4
@@ -779,7 +779,7 @@ struct iwm_umac_wifi_if {
u8 oid;
u8 flags;
__le16 buf_size;
-} __attribute__ ((packed));
+} __packed;
#define IWM_SEQ_NUM_HOST_MSK 0x0000
#define IWM_SEQ_NUM_UMAC_MSK 0x4000
diff --git a/drivers/net/wireless/libertas/Makefile b/drivers/net/wireless/libertas/Makefile
index 45e870e3311..f7d01bfa2e4 100644
--- a/drivers/net/wireless/libertas/Makefile
+++ b/drivers/net/wireless/libertas/Makefile
@@ -1,4 +1,3 @@
-libertas-y += assoc.o
libertas-y += cfg.o
libertas-y += cmd.o
libertas-y += cmdresp.o
@@ -6,9 +5,7 @@ libertas-y += debugfs.o
libertas-y += ethtool.o
libertas-y += main.o
libertas-y += rx.o
-libertas-y += scan.o
libertas-y += tx.o
-libertas-y += wext.o
libertas-$(CONFIG_LIBERTAS_MESH) += mesh.o
usb8xxx-objs += if_usb.o
diff --git a/drivers/net/wireless/libertas/README b/drivers/net/wireless/libertas/README
index 2726c044430..60fd1afe89a 100644
--- a/drivers/net/wireless/libertas/README
+++ b/drivers/net/wireless/libertas/README
@@ -226,6 +226,18 @@ setuserscan
All entries in the scan table (not just the new scan data when keep=1)
will be displayed upon completion by use of the getscantable ioctl.
+hostsleep
+ This command is used to enable/disable host sleep.
+ Note: Host sleep parameters should be configured using
+ "ethtool -s ethX wol X" command before enabling host sleep.
+
+ Path: /sys/kernel/debug/libertas_wireless/ethX/
+
+ Usage:
+ cat hostsleep: reads the current hostsleep state
+ echo "1" > hostsleep : enable host sleep.
+ echo "0" > hostsleep : disable host sleep
+
========================
IWCONFIG COMMANDS
========================
diff --git a/drivers/net/wireless/libertas/assoc.c b/drivers/net/wireless/libertas/assoc.c
deleted file mode 100644
index aa06070e5ea..00000000000
--- a/drivers/net/wireless/libertas/assoc.c
+++ /dev/null
@@ -1,2264 +0,0 @@
-/* Copyright (C) 2006, Red Hat, Inc. */
-
-#include <linux/types.h>
-#include <linux/etherdevice.h>
-#include <linux/ieee80211.h>
-#include <linux/if_arp.h>
-#include <linux/slab.h>
-#include <net/lib80211.h>
-
-#include "assoc.h"
-#include "decl.h"
-#include "host.h"
-#include "scan.h"
-#include "cmd.h"
-
-static const u8 bssid_any[ETH_ALEN] __attribute__ ((aligned (2))) =
- { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
-static const u8 bssid_off[ETH_ALEN] __attribute__ ((aligned (2))) =
- { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
-
-/* The firmware needs the following bits masked out of the beacon-derived
- * capability field when associating/joining to a BSS:
- * 9 (QoS), 11 (APSD), 12 (unused), 14 (unused), 15 (unused)
- */
-#define CAPINFO_MASK (~(0xda00))
-
-/**
- * 802.11b/g supported bitrates (in 500Kb/s units)
- */
-u8 lbs_bg_rates[MAX_RATES] =
- { 0x02, 0x04, 0x0b, 0x16, 0x0c, 0x12, 0x18, 0x24, 0x30, 0x48, 0x60, 0x6c,
-0x00, 0x00 };
-
-
-static int assoc_helper_wep_keys(struct lbs_private *priv,
- struct assoc_request *assoc_req);
-
-/**
- * @brief This function finds common rates between rates and card rates.
- *
- * It will fill common rates in rates as output if found.
- *
- * NOTE: Setting the MSB of the basic rates need to be taken
- * care, either before or after calling this function
- *
- * @param priv A pointer to struct lbs_private structure
- * @param rates the buffer which keeps input and output
- * @param rates_size the size of rates buffer; new size of buffer on return,
- * which will be less than or equal to original rates_size
- *
- * @return 0 on success, or -1 on error
- */
-static int get_common_rates(struct lbs_private *priv,
- u8 *rates,
- u16 *rates_size)
-{
- int i, j;
- u8 intersection[MAX_RATES];
- u16 intersection_size;
- u16 num_rates = 0;
-
- intersection_size = min_t(u16, *rates_size, ARRAY_SIZE(intersection));
-
- /* Allow each rate from 'rates' that is supported by the hardware */
- for (i = 0; i < ARRAY_SIZE(lbs_bg_rates) && lbs_bg_rates[i]; i++) {
- for (j = 0; j < intersection_size && rates[j]; j++) {
- if (rates[j] == lbs_bg_rates[i])
- intersection[num_rates++] = rates[j];
- }
- }
-
- lbs_deb_hex(LBS_DEB_JOIN, "AP rates ", rates, *rates_size);
- lbs_deb_hex(LBS_DEB_JOIN, "card rates ", lbs_bg_rates,
- ARRAY_SIZE(lbs_bg_rates));
- lbs_deb_hex(LBS_DEB_JOIN, "common rates", intersection, num_rates);
- lbs_deb_join("TX data rate 0x%02x\n", priv->cur_rate);
-
- if (!priv->enablehwauto) {
- for (i = 0; i < num_rates; i++) {
- if (intersection[i] == priv->cur_rate)
- goto done;
- }
- lbs_pr_alert("Previously set fixed data rate %#x isn't "
- "compatible with the network.\n", priv->cur_rate);
- return -1;
- }
-
-done:
- memset(rates, 0, *rates_size);
- *rates_size = num_rates;
- memcpy(rates, intersection, num_rates);
- return 0;
-}
-
-
-/**
- * @brief Sets the MSB on basic rates as the firmware requires
- *
- * Scan through an array and set the MSB for basic data rates.
- *
- * @param rates buffer of data rates
- * @param len size of buffer
- */
-static void lbs_set_basic_rate_flags(u8 *rates, size_t len)
-{
- int i;
-
- for (i = 0; i < len; i++) {
- if (rates[i] == 0x02 || rates[i] == 0x04 ||
- rates[i] == 0x0b || rates[i] == 0x16)
- rates[i] |= 0x80;
- }
-}
-
-
-static u8 iw_auth_to_ieee_auth(u8 auth)
-{
- if (auth == IW_AUTH_ALG_OPEN_SYSTEM)
- return 0x00;
- else if (auth == IW_AUTH_ALG_SHARED_KEY)
- return 0x01;
- else if (auth == IW_AUTH_ALG_LEAP)
- return 0x80;
-
- lbs_deb_join("%s: invalid auth alg 0x%X\n", __func__, auth);
- return 0;
-}
-
-/**
- * @brief This function prepares the authenticate command. AUTHENTICATE only
- * sets the authentication suite for future associations, as the firmware
- * handles authentication internally during the ASSOCIATE command.
- *
- * @param priv A pointer to struct lbs_private structure
- * @param bssid The peer BSSID with which to authenticate
- * @param auth The authentication mode to use (from wireless.h)
- *
- * @return 0 or -1
- */
-static int lbs_set_authentication(struct lbs_private *priv, u8 bssid[6], u8 auth)
-{
- struct cmd_ds_802_11_authenticate cmd;
- int ret = -1;
-
- lbs_deb_enter(LBS_DEB_JOIN);
-
- cmd.hdr.size = cpu_to_le16(sizeof(cmd));
- memcpy(cmd.bssid, bssid, ETH_ALEN);
-
- cmd.authtype = iw_auth_to_ieee_auth(auth);
-
- lbs_deb_join("AUTH_CMD: BSSID %pM, auth 0x%x\n", bssid, cmd.authtype);
-
- ret = lbs_cmd_with_response(priv, CMD_802_11_AUTHENTICATE, &cmd);
-
- lbs_deb_leave_args(LBS_DEB_JOIN, "ret %d", ret);
- return ret;
-}
-
-
-int lbs_cmd_802_11_set_wep(struct lbs_private *priv, uint16_t cmd_action,
- struct assoc_request *assoc)
-{
- struct cmd_ds_802_11_set_wep cmd;
- int ret = 0;
-
- lbs_deb_enter(LBS_DEB_CMD);
-
- memset(&cmd, 0, sizeof(cmd));
- cmd.hdr.command = cpu_to_le16(CMD_802_11_SET_WEP);
- cmd.hdr.size = cpu_to_le16(sizeof(cmd));
-
- cmd.action = cpu_to_le16(cmd_action);
-
- if (cmd_action == CMD_ACT_ADD) {
- int i;
-
- /* default tx key index */
- cmd.keyindex = cpu_to_le16(assoc->wep_tx_keyidx &
- CMD_WEP_KEY_INDEX_MASK);
-
- /* Copy key types and material to host command structure */
- for (i = 0; i < 4; i++) {
- struct enc_key *pkey = &assoc->wep_keys[i];
-
- switch (pkey->len) {
- case KEY_LEN_WEP_40:
- cmd.keytype[i] = CMD_TYPE_WEP_40_BIT;
- memmove(cmd.keymaterial[i], pkey->key, pkey->len);
- lbs_deb_cmd("SET_WEP: add key %d (40 bit)\n", i);
- break;
- case KEY_LEN_WEP_104:
- cmd.keytype[i] = CMD_TYPE_WEP_104_BIT;
- memmove(cmd.keymaterial[i], pkey->key, pkey->len);
- lbs_deb_cmd("SET_WEP: add key %d (104 bit)\n", i);
- break;
- case 0:
- break;
- default:
- lbs_deb_cmd("SET_WEP: invalid key %d, length %d\n",
- i, pkey->len);
- ret = -1;
- goto done;
- break;
- }
- }
- } else if (cmd_action == CMD_ACT_REMOVE) {
- /* ACT_REMOVE clears _all_ WEP keys */
-
- /* default tx key index */
- cmd.keyindex = cpu_to_le16(priv->wep_tx_keyidx &
- CMD_WEP_KEY_INDEX_MASK);
- lbs_deb_cmd("SET_WEP: remove key %d\n", priv->wep_tx_keyidx);
- }
-
- ret = lbs_cmd_with_response(priv, CMD_802_11_SET_WEP, &cmd);
-done:
- lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
- return ret;
-}
-
-int lbs_cmd_802_11_enable_rsn(struct lbs_private *priv, uint16_t cmd_action,
- uint16_t *enable)
-{
- struct cmd_ds_802_11_enable_rsn cmd;
- int ret;
-
- lbs_deb_enter(LBS_DEB_CMD);
-
- cmd.hdr.size = cpu_to_le16(sizeof(cmd));
- cmd.action = cpu_to_le16(cmd_action);
-
- if (cmd_action == CMD_ACT_GET)
- cmd.enable = 0;
- else {
- if (*enable)
- cmd.enable = cpu_to_le16(CMD_ENABLE_RSN);
- else
- cmd.enable = cpu_to_le16(CMD_DISABLE_RSN);
- lbs_deb_cmd("ENABLE_RSN: %d\n", *enable);
- }
-
- ret = lbs_cmd_with_response(priv, CMD_802_11_ENABLE_RSN, &cmd);
- if (!ret && cmd_action == CMD_ACT_GET)
- *enable = le16_to_cpu(cmd.enable);
-
- lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
- return ret;
-}
-
-static void set_one_wpa_key(struct MrvlIEtype_keyParamSet *keyparam,
- struct enc_key *key)
-{
- lbs_deb_enter(LBS_DEB_CMD);
-
- if (key->flags & KEY_INFO_WPA_ENABLED)
- keyparam->keyinfo |= cpu_to_le16(KEY_INFO_WPA_ENABLED);
- if (key->flags & KEY_INFO_WPA_UNICAST)
- keyparam->keyinfo |= cpu_to_le16(KEY_INFO_WPA_UNICAST);
- if (key->flags & KEY_INFO_WPA_MCAST)
- keyparam->keyinfo |= cpu_to_le16(KEY_INFO_WPA_MCAST);
-
- keyparam->type = cpu_to_le16(TLV_TYPE_KEY_MATERIAL);
- keyparam->keytypeid = cpu_to_le16(key->type);
- keyparam->keylen = cpu_to_le16(key->len);
- memcpy(keyparam->key, key->key, key->len);
-
- /* Length field doesn't include the {type,length} header */
- keyparam->length = cpu_to_le16(sizeof(*keyparam) - 4);
- lbs_deb_leave(LBS_DEB_CMD);
-}
-
-int lbs_cmd_802_11_key_material(struct lbs_private *priv, uint16_t cmd_action,
- struct assoc_request *assoc)
-{
- struct cmd_ds_802_11_key_material cmd;
- int ret = 0;
- int index = 0;
-
- lbs_deb_enter(LBS_DEB_CMD);
-
- cmd.action = cpu_to_le16(cmd_action);
- cmd.hdr.size = cpu_to_le16(sizeof(cmd));
-
- if (cmd_action == CMD_ACT_GET) {
- cmd.hdr.size = cpu_to_le16(sizeof(struct cmd_header) + 2);
- } else {
- memset(cmd.keyParamSet, 0, sizeof(cmd.keyParamSet));
-
- if (test_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc->flags)) {
- set_one_wpa_key(&cmd.keyParamSet[index],
- &assoc->wpa_unicast_key);
- index++;
- }
-
- if (test_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc->flags)) {
- set_one_wpa_key(&cmd.keyParamSet[index],
- &assoc->wpa_mcast_key);
- index++;
- }
-
- /* The common header and as many keys as we included */
- cmd.hdr.size = cpu_to_le16(offsetof(typeof(cmd),
- keyParamSet[index]));
- }
- ret = lbs_cmd_with_response(priv, CMD_802_11_KEY_MATERIAL, &cmd);
- /* Copy the returned key to driver private data */
- if (!ret && cmd_action == CMD_ACT_GET) {
- void *buf_ptr = cmd.keyParamSet;
- void *resp_end = &(&cmd)[1];
-
- while (buf_ptr < resp_end) {
- struct MrvlIEtype_keyParamSet *keyparam = buf_ptr;
- struct enc_key *key;
- uint16_t param_set_len = le16_to_cpu(keyparam->length);
- uint16_t key_len = le16_to_cpu(keyparam->keylen);
- uint16_t key_flags = le16_to_cpu(keyparam->keyinfo);
- uint16_t key_type = le16_to_cpu(keyparam->keytypeid);
- void *end;
-
- end = (void *)keyparam + sizeof(keyparam->type)
- + sizeof(keyparam->length) + param_set_len;
-
- /* Make sure we don't access past the end of the IEs */
- if (end > resp_end)
- break;
-
- if (key_flags & KEY_INFO_WPA_UNICAST)
- key = &priv->wpa_unicast_key;
- else if (key_flags & KEY_INFO_WPA_MCAST)
- key = &priv->wpa_mcast_key;
- else
- break;
-
- /* Copy returned key into driver */
- memset(key, 0, sizeof(struct enc_key));
- if (key_len > sizeof(key->key))
- break;
- key->type = key_type;
- key->flags = key_flags;
- key->len = key_len;
- memcpy(key->key, keyparam->key, key->len);
-
- buf_ptr = end + 1;
- }
- }
-
- lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
- return ret;
-}
-
-static __le16 lbs_rate_to_fw_bitmap(int rate, int lower_rates_ok)
-{
-/* Bit Rate
-* 15:13 Reserved
-* 12 54 Mbps
-* 11 48 Mbps
-* 10 36 Mbps
-* 9 24 Mbps
-* 8 18 Mbps
-* 7 12 Mbps
-* 6 9 Mbps
-* 5 6 Mbps
-* 4 Reserved
-* 3 11 Mbps
-* 2 5.5 Mbps
-* 1 2 Mbps
-* 0 1 Mbps
-**/
-
- uint16_t ratemask;
- int i = lbs_data_rate_to_fw_index(rate);
- if (lower_rates_ok)
- ratemask = (0x1fef >> (12 - i));
- else
- ratemask = (1 << i);
- return cpu_to_le16(ratemask);
-}
-
-int lbs_cmd_802_11_rate_adapt_rateset(struct lbs_private *priv,
- uint16_t cmd_action)
-{
- struct cmd_ds_802_11_rate_adapt_rateset cmd;
- int ret;
-
- lbs_deb_enter(LBS_DEB_CMD);
-
- if (!priv->cur_rate && !priv->enablehwauto)
- return -EINVAL;
-
- cmd.hdr.size = cpu_to_le16(sizeof(cmd));
-
- cmd.action = cpu_to_le16(cmd_action);
- cmd.enablehwauto = cpu_to_le16(priv->enablehwauto);
- cmd.bitmap = lbs_rate_to_fw_bitmap(priv->cur_rate, priv->enablehwauto);
- ret = lbs_cmd_with_response(priv, CMD_802_11_RATE_ADAPT_RATESET, &cmd);
- if (!ret && cmd_action == CMD_ACT_GET)
- priv->enablehwauto = le16_to_cpu(cmd.enablehwauto);
-
- lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
- return ret;
-}
-
-/**
- * @brief Set the data rate
- *
- * @param priv A pointer to struct lbs_private structure
- * @param rate The desired data rate, or 0 to clear a locked rate
- *
- * @return 0 on success, error on failure
- */
-int lbs_set_data_rate(struct lbs_private *priv, u8 rate)
-{
- struct cmd_ds_802_11_data_rate cmd;
- int ret = 0;
-
- lbs_deb_enter(LBS_DEB_CMD);
-
- memset(&cmd, 0, sizeof(cmd));
- cmd.hdr.size = cpu_to_le16(sizeof(cmd));
-
- if (rate > 0) {
- cmd.action = cpu_to_le16(CMD_ACT_SET_TX_FIX_RATE);
- cmd.rates[0] = lbs_data_rate_to_fw_index(rate);
- if (cmd.rates[0] == 0) {
- lbs_deb_cmd("DATA_RATE: invalid requested rate of"
- " 0x%02X\n", rate);
- ret = 0;
- goto out;
- }
- lbs_deb_cmd("DATA_RATE: set fixed 0x%02X\n", cmd.rates[0]);
- } else {
- cmd.action = cpu_to_le16(CMD_ACT_SET_TX_AUTO);
- lbs_deb_cmd("DATA_RATE: setting auto\n");
- }
-
- ret = lbs_cmd_with_response(priv, CMD_802_11_DATA_RATE, &cmd);
- if (ret)
- goto out;
-
- lbs_deb_hex(LBS_DEB_CMD, "DATA_RATE_RESP", (u8 *) &cmd, sizeof(cmd));
-
- /* FIXME: get actual rates FW can do if this command actually returns
- * all data rates supported.
- */
- priv->cur_rate = lbs_fw_index_to_data_rate(cmd.rates[0]);
- lbs_deb_cmd("DATA_RATE: current rate is 0x%02x\n", priv->cur_rate);
-
-out:
- lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
- return ret;
-}
-
-
-int lbs_cmd_802_11_rssi(struct lbs_private *priv,
- struct cmd_ds_command *cmd)
-{
-
- lbs_deb_enter(LBS_DEB_CMD);
- cmd->command = cpu_to_le16(CMD_802_11_RSSI);
- cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_rssi) +
- sizeof(struct cmd_header));
- cmd->params.rssi.N = cpu_to_le16(DEFAULT_BCN_AVG_FACTOR);
-
- /* reset Beacon SNR/NF/RSSI values */
- priv->SNR[TYPE_BEACON][TYPE_NOAVG] = 0;
- priv->SNR[TYPE_BEACON][TYPE_AVG] = 0;
- priv->NF[TYPE_BEACON][TYPE_NOAVG] = 0;
- priv->NF[TYPE_BEACON][TYPE_AVG] = 0;
- priv->RSSI[TYPE_BEACON][TYPE_NOAVG] = 0;
- priv->RSSI[TYPE_BEACON][TYPE_AVG] = 0;
-
- lbs_deb_leave(LBS_DEB_CMD);
- return 0;
-}
-
-int lbs_ret_802_11_rssi(struct lbs_private *priv,
- struct cmd_ds_command *resp)
-{
- struct cmd_ds_802_11_rssi_rsp *rssirsp = &resp->params.rssirsp;
-
- lbs_deb_enter(LBS_DEB_CMD);
-
- /* store the non average value */
- priv->SNR[TYPE_BEACON][TYPE_NOAVG] = get_unaligned_le16(&rssirsp->SNR);
- priv->NF[TYPE_BEACON][TYPE_NOAVG] =
- get_unaligned_le16(&rssirsp->noisefloor);
-
- priv->SNR[TYPE_BEACON][TYPE_AVG] = get_unaligned_le16(&rssirsp->avgSNR);
- priv->NF[TYPE_BEACON][TYPE_AVG] =
- get_unaligned_le16(&rssirsp->avgnoisefloor);
-
- priv->RSSI[TYPE_BEACON][TYPE_NOAVG] =
- CAL_RSSI(priv->SNR[TYPE_BEACON][TYPE_NOAVG],
- priv->NF[TYPE_BEACON][TYPE_NOAVG]);
-
- priv->RSSI[TYPE_BEACON][TYPE_AVG] =
- CAL_RSSI(priv->SNR[TYPE_BEACON][TYPE_AVG] / AVG_SCALE,
- priv->NF[TYPE_BEACON][TYPE_AVG] / AVG_SCALE);
-
- lbs_deb_cmd("RSSI: beacon %d, avg %d\n",
- priv->RSSI[TYPE_BEACON][TYPE_NOAVG],
- priv->RSSI[TYPE_BEACON][TYPE_AVG]);
-
- lbs_deb_leave(LBS_DEB_CMD);
- return 0;
-}
-
-
-int lbs_cmd_bcn_ctrl(struct lbs_private *priv,
- struct cmd_ds_command *cmd,
- u16 cmd_action)
-{
- struct cmd_ds_802_11_beacon_control
- *bcn_ctrl = &cmd->params.bcn_ctrl;
-
- lbs_deb_enter(LBS_DEB_CMD);
- cmd->size =
- cpu_to_le16(sizeof(struct cmd_ds_802_11_beacon_control)
- + sizeof(struct cmd_header));
- cmd->command = cpu_to_le16(CMD_802_11_BEACON_CTRL);
-
- bcn_ctrl->action = cpu_to_le16(cmd_action);
- bcn_ctrl->beacon_enable = cpu_to_le16(priv->beacon_enable);
- bcn_ctrl->beacon_period = cpu_to_le16(priv->beacon_period);
-
- lbs_deb_leave(LBS_DEB_CMD);
- return 0;
-}
-
-int lbs_ret_802_11_bcn_ctrl(struct lbs_private *priv,
- struct cmd_ds_command *resp)
-{
- struct cmd_ds_802_11_beacon_control *bcn_ctrl =
- &resp->params.bcn_ctrl;
-
- lbs_deb_enter(LBS_DEB_CMD);
-
- if (bcn_ctrl->action == CMD_ACT_GET) {
- priv->beacon_enable = (u8) le16_to_cpu(bcn_ctrl->beacon_enable);
- priv->beacon_period = le16_to_cpu(bcn_ctrl->beacon_period);
- }
-
- lbs_deb_enter(LBS_DEB_CMD);
- return 0;
-}
-
-
-
-static int lbs_assoc_post(struct lbs_private *priv,
- struct cmd_ds_802_11_associate_response *resp)
-{
- int ret = 0;
- union iwreq_data wrqu;
- struct bss_descriptor *bss;
- u16 status_code;
-
- lbs_deb_enter(LBS_DEB_ASSOC);
-
- if (!priv->in_progress_assoc_req) {
- lbs_deb_assoc("ASSOC_RESP: no in-progress assoc request\n");
- ret = -1;
- goto done;
- }
- bss = &priv->in_progress_assoc_req->bss;
-
- /*
- * Older FW versions map the IEEE 802.11 Status Code in the association
- * response to the following values returned in resp->statuscode:
- *
- * IEEE Status Code Marvell Status Code
- * 0 -> 0x0000 ASSOC_RESULT_SUCCESS
- * 13 -> 0x0004 ASSOC_RESULT_AUTH_REFUSED
- * 14 -> 0x0004 ASSOC_RESULT_AUTH_REFUSED
- * 15 -> 0x0004 ASSOC_RESULT_AUTH_REFUSED
- * 16 -> 0x0004 ASSOC_RESULT_AUTH_REFUSED
- * others -> 0x0003 ASSOC_RESULT_REFUSED
- *
- * Other response codes:
- * 0x0001 -> ASSOC_RESULT_INVALID_PARAMETERS (unused)
- * 0x0002 -> ASSOC_RESULT_TIMEOUT (internal timer expired waiting for
- * association response from the AP)
- */
-
- status_code = le16_to_cpu(resp->statuscode);
- if (priv->fwrelease < 0x09000000) {
- switch (status_code) {
- case 0x00:
- break;
- case 0x01:
- lbs_deb_assoc("ASSOC_RESP: invalid parameters\n");
- break;
- case 0x02:
- lbs_deb_assoc("ASSOC_RESP: internal timer "
- "expired while waiting for the AP\n");
- break;
- case 0x03:
- lbs_deb_assoc("ASSOC_RESP: association "
- "refused by AP\n");
- break;
- case 0x04:
- lbs_deb_assoc("ASSOC_RESP: authentication "
- "refused by AP\n");
- break;
- default:
- lbs_deb_assoc("ASSOC_RESP: failure reason 0x%02x "
- " unknown\n", status_code);
- break;
- }
- } else {
- /* v9+ returns the AP's association response */
- lbs_deb_assoc("ASSOC_RESP: failure reason 0x%02x\n", status_code);
- }
-
- if (status_code) {
- lbs_mac_event_disconnected(priv);
- ret = status_code;
- goto done;
- }
-
- lbs_deb_hex(LBS_DEB_ASSOC, "ASSOC_RESP",
- (void *) (resp + sizeof (resp->hdr)),
- le16_to_cpu(resp->hdr.size) - sizeof (resp->hdr));
-
- /* Send a Media Connected event, according to the Spec */
- priv->connect_status = LBS_CONNECTED;
-
- /* Update current SSID and BSSID */
- memcpy(&priv->curbssparams.ssid, &bss->ssid, IEEE80211_MAX_SSID_LEN);
- priv->curbssparams.ssid_len = bss->ssid_len;
- memcpy(priv->curbssparams.bssid, bss->bssid, ETH_ALEN);
-
- priv->SNR[TYPE_RXPD][TYPE_AVG] = 0;
- priv->NF[TYPE_RXPD][TYPE_AVG] = 0;
-
- memset(priv->rawSNR, 0x00, sizeof(priv->rawSNR));
- memset(priv->rawNF, 0x00, sizeof(priv->rawNF));
- priv->nextSNRNF = 0;
- priv->numSNRNF = 0;
-
- netif_carrier_on(priv->dev);
- if (!priv->tx_pending_len)
- netif_wake_queue(priv->dev);
-
- memcpy(wrqu.ap_addr.sa_data, priv->curbssparams.bssid, ETH_ALEN);
- wrqu.ap_addr.sa_family = ARPHRD_ETHER;
- wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL);
-
-done:
- lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
- return ret;
-}
-
-/**
- * @brief This function prepares an association-class command.
- *
- * @param priv A pointer to struct lbs_private structure
- * @param assoc_req The association request describing the BSS to associate
- * or reassociate with
- * @param command The actual command, either CMD_802_11_ASSOCIATE or
- * CMD_802_11_REASSOCIATE
- *
- * @return 0 or -1
- */
-static int lbs_associate(struct lbs_private *priv,
- struct assoc_request *assoc_req,
- u16 command)
-{
- struct cmd_ds_802_11_associate cmd;
- int ret = 0;
- struct bss_descriptor *bss = &assoc_req->bss;
- u8 *pos = &(cmd.iebuf[0]);
- u16 tmpcap, tmplen, tmpauth;
- struct mrvl_ie_ssid_param_set *ssid;
- struct mrvl_ie_ds_param_set *ds;
- struct mrvl_ie_cf_param_set *cf;
- struct mrvl_ie_rates_param_set *rates;
- struct mrvl_ie_rsn_param_set *rsn;
- struct mrvl_ie_auth_type *auth;
-
- lbs_deb_enter(LBS_DEB_ASSOC);
-
- BUG_ON((command != CMD_802_11_ASSOCIATE) &&
- (command != CMD_802_11_REASSOCIATE));
-
- memset(&cmd, 0, sizeof(cmd));
- cmd.hdr.command = cpu_to_le16(command);
-
- /* Fill in static fields */
- memcpy(cmd.bssid, bss->bssid, ETH_ALEN);
- cmd.listeninterval = cpu_to_le16(MRVDRV_DEFAULT_LISTEN_INTERVAL);
-
- /* Capability info */
- tmpcap = (bss->capability & CAPINFO_MASK);
- if (bss->mode == IW_MODE_INFRA)
- tmpcap |= WLAN_CAPABILITY_ESS;
- cmd.capability = cpu_to_le16(tmpcap);
- lbs_deb_assoc("ASSOC_CMD: capability 0x%04x\n", tmpcap);
-
- /* SSID */
- ssid = (struct mrvl_ie_ssid_param_set *) pos;
- ssid->header.type = cpu_to_le16(TLV_TYPE_SSID);
- tmplen = bss->ssid_len;
- ssid->header.len = cpu_to_le16(tmplen);
- memcpy(ssid->ssid, bss->ssid, tmplen);
- pos += sizeof(ssid->header) + tmplen;
-
- ds = (struct mrvl_ie_ds_param_set *) pos;
- ds->header.type = cpu_to_le16(TLV_TYPE_PHY_DS);
- ds->header.len = cpu_to_le16(1);
- ds->channel = bss->phy.ds.channel;
- pos += sizeof(ds->header) + 1;
-
- cf = (struct mrvl_ie_cf_param_set *) pos;
- cf->header.type = cpu_to_le16(TLV_TYPE_CF);
- tmplen = sizeof(*cf) - sizeof (cf->header);
- cf->header.len = cpu_to_le16(tmplen);
- /* IE payload should be zeroed, firmware fills it in for us */
- pos += sizeof(*cf);
-
- rates = (struct mrvl_ie_rates_param_set *) pos;
- rates->header.type = cpu_to_le16(TLV_TYPE_RATES);
- tmplen = min_t(u16, ARRAY_SIZE(bss->rates), MAX_RATES);
- memcpy(&rates->rates, &bss->rates, tmplen);
- if (get_common_rates(priv, rates->rates, &tmplen)) {
- ret = -1;
- goto done;
- }
- pos += sizeof(rates->header) + tmplen;
- rates->header.len = cpu_to_le16(tmplen);
- lbs_deb_assoc("ASSOC_CMD: num rates %u\n", tmplen);
-
- /* Copy the infra. association rates into Current BSS state structure */
- memset(&priv->curbssparams.rates, 0, sizeof(priv->curbssparams.rates));
- memcpy(&priv->curbssparams.rates, &rates->rates, tmplen);
-
- /* Set MSB on basic rates as the firmware requires, but _after_
- * copying to current bss rates.
- */
- lbs_set_basic_rate_flags(rates->rates, tmplen);
-
- /* Firmware v9+ indicate authentication suites as a TLV */
- if (priv->fwrelease >= 0x09000000) {
- auth = (struct mrvl_ie_auth_type *) pos;
- auth->header.type = cpu_to_le16(TLV_TYPE_AUTH_TYPE);
- auth->header.len = cpu_to_le16(2);
- tmpauth = iw_auth_to_ieee_auth(priv->secinfo.auth_mode);
- auth->auth = cpu_to_le16(tmpauth);
- pos += sizeof(auth->header) + 2;
-
- lbs_deb_join("AUTH_CMD: BSSID %pM, auth 0x%x\n",
- bss->bssid, priv->secinfo.auth_mode);
- }
-
- /* WPA/WPA2 IEs */
- if (assoc_req->secinfo.WPAenabled || assoc_req->secinfo.WPA2enabled) {
- rsn = (struct mrvl_ie_rsn_param_set *) pos;
- /* WPA_IE or WPA2_IE */
- rsn->header.type = cpu_to_le16((u16) assoc_req->wpa_ie[0]);
- tmplen = (u16) assoc_req->wpa_ie[1];
- rsn->header.len = cpu_to_le16(tmplen);
- memcpy(rsn->rsnie, &assoc_req->wpa_ie[2], tmplen);
- lbs_deb_hex(LBS_DEB_JOIN, "ASSOC_CMD: WPA/RSN IE", (u8 *) rsn,
- sizeof(rsn->header) + tmplen);
- pos += sizeof(rsn->header) + tmplen;
- }
-
- cmd.hdr.size = cpu_to_le16((sizeof(cmd) - sizeof(cmd.iebuf)) +
- (u16)(pos - (u8 *) &cmd.iebuf));
-
- /* update curbssparams */
- priv->channel = bss->phy.ds.channel;
-
- ret = lbs_cmd_with_response(priv, command, &cmd);
- if (ret == 0) {
- ret = lbs_assoc_post(priv,
- (struct cmd_ds_802_11_associate_response *) &cmd);
- }
-
-done:
- lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
- return ret;
-}
-
-/**
- * @brief Associate to a specific BSS discovered in a scan
- *
- * @param priv A pointer to struct lbs_private structure
- * @param assoc_req The association request describing the BSS to associate with
- *
- * @return 0-success, otherwise fail
- */
-static int lbs_try_associate(struct lbs_private *priv,
- struct assoc_request *assoc_req)
-{
- int ret;
- u8 preamble = RADIO_PREAMBLE_LONG;
-
- lbs_deb_enter(LBS_DEB_ASSOC);
-
- /* FW v9 and higher indicate authentication suites as a TLV in the
- * association command, not as a separate authentication command.
- */
- if (priv->fwrelease < 0x09000000) {
- ret = lbs_set_authentication(priv, assoc_req->bss.bssid,
- priv->secinfo.auth_mode);
- if (ret)
- goto out;
- }
-
- /* Use short preamble only when both the BSS and firmware support it */
- if (assoc_req->bss.capability & WLAN_CAPABILITY_SHORT_PREAMBLE)
- preamble = RADIO_PREAMBLE_SHORT;
-
- ret = lbs_set_radio(priv, preamble, 1);
- if (ret)
- goto out;
-
- ret = lbs_associate(priv, assoc_req, CMD_802_11_ASSOCIATE);
- /* If the association fails with current auth mode, let's
- * try by changing the auth mode
- */
- if ((priv->authtype_auto) &&
- (ret == WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG) &&
- (assoc_req->secinfo.wep_enabled) &&
- (priv->connect_status != LBS_CONNECTED)) {
- if (priv->secinfo.auth_mode == IW_AUTH_ALG_OPEN_SYSTEM)
- priv->secinfo.auth_mode = IW_AUTH_ALG_SHARED_KEY;
- else
- priv->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM;
- if (!assoc_helper_wep_keys(priv, assoc_req))
- ret = lbs_associate(priv, assoc_req,
- CMD_802_11_ASSOCIATE);
- }
-
- if (ret)
- ret = -1;
-out:
- lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
- return ret;
-}
-
-static int lbs_adhoc_post(struct lbs_private *priv,
- struct cmd_ds_802_11_ad_hoc_result *resp)
-{
- int ret = 0;
- u16 command = le16_to_cpu(resp->hdr.command);
- u16 result = le16_to_cpu(resp->hdr.result);
- union iwreq_data wrqu;
- struct bss_descriptor *bss;
- DECLARE_SSID_BUF(ssid);
-
- lbs_deb_enter(LBS_DEB_JOIN);
-
- if (!priv->in_progress_assoc_req) {
- lbs_deb_join("ADHOC_RESP: no in-progress association "
- "request\n");
- ret = -1;
- goto done;
- }
- bss = &priv->in_progress_assoc_req->bss;
-
- /*
- * Join result code 0 --> SUCCESS
- */
- if (result) {
- lbs_deb_join("ADHOC_RESP: failed (result 0x%X)\n", result);
- if (priv->connect_status == LBS_CONNECTED)
- lbs_mac_event_disconnected(priv);
- ret = -1;
- goto done;
- }
-
- /* Send a Media Connected event, according to the Spec */
- priv->connect_status = LBS_CONNECTED;
-
- if (command == CMD_RET(CMD_802_11_AD_HOC_START)) {
- /* Update the created network descriptor with the new BSSID */
- memcpy(bss->bssid, resp->bssid, ETH_ALEN);
- }
-
- /* Set the BSSID from the joined/started descriptor */
- memcpy(&priv->curbssparams.bssid, bss->bssid, ETH_ALEN);
-
- /* Set the new SSID to current SSID */
- memcpy(&priv->curbssparams.ssid, &bss->ssid, IEEE80211_MAX_SSID_LEN);
- priv->curbssparams.ssid_len = bss->ssid_len;
-
- netif_carrier_on(priv->dev);
- if (!priv->tx_pending_len)
- netif_wake_queue(priv->dev);
-
- memset(&wrqu, 0, sizeof(wrqu));
- memcpy(wrqu.ap_addr.sa_data, priv->curbssparams.bssid, ETH_ALEN);
- wrqu.ap_addr.sa_family = ARPHRD_ETHER;
- wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL);
-
- lbs_deb_join("ADHOC_RESP: Joined/started '%s', BSSID %pM, channel %d\n",
- print_ssid(ssid, bss->ssid, bss->ssid_len),
- priv->curbssparams.bssid,
- priv->channel);
-
-done:
- lbs_deb_leave_args(LBS_DEB_JOIN, "ret %d", ret);
- return ret;
-}
-
-/**
- * @brief Join an adhoc network found in a previous scan
- *
- * @param priv A pointer to struct lbs_private structure
- * @param assoc_req The association request describing the BSS to join
- *
- * @return 0 on success, error on failure
- */
-static int lbs_adhoc_join(struct lbs_private *priv,
- struct assoc_request *assoc_req)
-{
- struct cmd_ds_802_11_ad_hoc_join cmd;
- struct bss_descriptor *bss = &assoc_req->bss;
- u8 preamble = RADIO_PREAMBLE_LONG;
- DECLARE_SSID_BUF(ssid);
- u16 ratesize = 0;
- int ret = 0;
-
- lbs_deb_enter(LBS_DEB_ASSOC);
-
- lbs_deb_join("current SSID '%s', ssid length %u\n",
- print_ssid(ssid, priv->curbssparams.ssid,
- priv->curbssparams.ssid_len),
- priv->curbssparams.ssid_len);
- lbs_deb_join("requested ssid '%s', ssid length %u\n",
- print_ssid(ssid, bss->ssid, bss->ssid_len),
- bss->ssid_len);
-
- /* check if the requested SSID is already joined */
- if (priv->curbssparams.ssid_len &&
- !lbs_ssid_cmp(priv->curbssparams.ssid,
- priv->curbssparams.ssid_len,
- bss->ssid, bss->ssid_len) &&
- (priv->mode == IW_MODE_ADHOC) &&
- (priv->connect_status == LBS_CONNECTED)) {
- union iwreq_data wrqu;
-
- lbs_deb_join("ADHOC_J_CMD: New ad-hoc SSID is the same as "
- "current, not attempting to re-join");
-
- /* Send the re-association event though, because the association
- * request really was successful, even if just a null-op.
- */
- memset(&wrqu, 0, sizeof(wrqu));
- memcpy(wrqu.ap_addr.sa_data, priv->curbssparams.bssid,
- ETH_ALEN);
- wrqu.ap_addr.sa_family = ARPHRD_ETHER;
- wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL);
- goto out;
- }
-
- /* Use short preamble only when both the BSS and firmware support it */
- if (bss->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) {
- lbs_deb_join("AdhocJoin: Short preamble\n");
- preamble = RADIO_PREAMBLE_SHORT;
- }
-
- ret = lbs_set_radio(priv, preamble, 1);
- if (ret)
- goto out;
-
- lbs_deb_join("AdhocJoin: channel = %d\n", assoc_req->channel);
- lbs_deb_join("AdhocJoin: band = %c\n", assoc_req->band);
-
- priv->adhoccreate = 0;
- priv->channel = bss->channel;
-
- /* Build the join command */
- memset(&cmd, 0, sizeof(cmd));
- cmd.hdr.size = cpu_to_le16(sizeof(cmd));
-
- cmd.bss.type = CMD_BSS_TYPE_IBSS;
- cmd.bss.beaconperiod = cpu_to_le16(bss->beaconperiod);
-
- memcpy(&cmd.bss.bssid, &bss->bssid, ETH_ALEN);
- memcpy(&cmd.bss.ssid, &bss->ssid, bss->ssid_len);
-
- memcpy(&cmd.bss.ds, &bss->phy.ds, sizeof(struct ieee_ie_ds_param_set));
-
- memcpy(&cmd.bss.ibss, &bss->ss.ibss,
- sizeof(struct ieee_ie_ibss_param_set));
-
- cmd.bss.capability = cpu_to_le16(bss->capability & CAPINFO_MASK);
- lbs_deb_join("ADHOC_J_CMD: tmpcap=%4X CAPINFO_MASK=%4X\n",
- bss->capability, CAPINFO_MASK);
-
- /* information on BSSID descriptor passed to FW */
- lbs_deb_join("ADHOC_J_CMD: BSSID = %pM, SSID = '%s'\n",
- cmd.bss.bssid, cmd.bss.ssid);
-
- /* Only v8 and below support setting these */
- if (priv->fwrelease < 0x09000000) {
- /* failtimeout */
- cmd.failtimeout = cpu_to_le16(MRVDRV_ASSOCIATION_TIME_OUT);
- /* probedelay */
- cmd.probedelay = cpu_to_le16(CMD_SCAN_PROBE_DELAY_TIME);
- }
-
- /* Copy Data rates from the rates recorded in scan response */
- memset(cmd.bss.rates, 0, sizeof(cmd.bss.rates));
- ratesize = min_t(u16, ARRAY_SIZE(cmd.bss.rates), ARRAY_SIZE (bss->rates));
- memcpy(cmd.bss.rates, bss->rates, ratesize);
- if (get_common_rates(priv, cmd.bss.rates, &ratesize)) {
- lbs_deb_join("ADHOC_JOIN: get_common_rates returned error.\n");
- ret = -1;
- goto out;
- }
-
- /* Copy the ad-hoc creation rates into Current BSS state structure */
- memset(&priv->curbssparams.rates, 0, sizeof(priv->curbssparams.rates));
- memcpy(&priv->curbssparams.rates, cmd.bss.rates, ratesize);
-
- /* Set MSB on basic rates as the firmware requires, but _after_
- * copying to current bss rates.
- */
- lbs_set_basic_rate_flags(cmd.bss.rates, ratesize);
-
- cmd.bss.ibss.atimwindow = bss->atimwindow;
-
- if (assoc_req->secinfo.wep_enabled) {
- u16 tmp = le16_to_cpu(cmd.bss.capability);
- tmp |= WLAN_CAPABILITY_PRIVACY;
- cmd.bss.capability = cpu_to_le16(tmp);
- }
-
- if (priv->psmode == LBS802_11POWERMODEMAX_PSP) {
- __le32 local_ps_mode = cpu_to_le32(LBS802_11POWERMODECAM);
-
- /* wake up first */
- ret = lbs_prepare_and_send_command(priv, CMD_802_11_PS_MODE,
- CMD_ACT_SET, 0, 0,
- &local_ps_mode);
- if (ret) {
- ret = -1;
- goto out;
- }
- }
-
- ret = lbs_cmd_with_response(priv, CMD_802_11_AD_HOC_JOIN, &cmd);
- if (ret == 0) {
- ret = lbs_adhoc_post(priv,
- (struct cmd_ds_802_11_ad_hoc_result *)&cmd);
- }
-
-out:
- lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
- return ret;
-}
-
-/**
- * @brief Start an Adhoc Network
- *
- * @param priv A pointer to struct lbs_private structure
- * @param assoc_req The association request describing the BSS to start
- *
- * @return 0 on success, error on failure
- */
-static int lbs_adhoc_start(struct lbs_private *priv,
- struct assoc_request *assoc_req)
-{
- struct cmd_ds_802_11_ad_hoc_start cmd;
- u8 preamble = RADIO_PREAMBLE_SHORT;
- size_t ratesize = 0;
- u16 tmpcap = 0;
- int ret = 0;
- DECLARE_SSID_BUF(ssid);
-
- lbs_deb_enter(LBS_DEB_ASSOC);
-
- ret = lbs_set_radio(priv, preamble, 1);
- if (ret)
- goto out;
-
- /* Build the start command */
- memset(&cmd, 0, sizeof(cmd));
- cmd.hdr.size = cpu_to_le16(sizeof(cmd));
-
- memcpy(cmd.ssid, assoc_req->ssid, assoc_req->ssid_len);
-
- lbs_deb_join("ADHOC_START: SSID '%s', ssid length %u\n",
- print_ssid(ssid, assoc_req->ssid, assoc_req->ssid_len),
- assoc_req->ssid_len);
-
- cmd.bsstype = CMD_BSS_TYPE_IBSS;
-
- if (priv->beacon_period == 0)
- priv->beacon_period = MRVDRV_BEACON_INTERVAL;
- cmd.beaconperiod = cpu_to_le16(priv->beacon_period);
-
- WARN_ON(!assoc_req->channel);
-
- /* set Physical parameter set */
- cmd.ds.header.id = WLAN_EID_DS_PARAMS;
- cmd.ds.header.len = 1;
- cmd.ds.channel = assoc_req->channel;
-
- /* set IBSS parameter set */
- cmd.ibss.header.id = WLAN_EID_IBSS_PARAMS;
- cmd.ibss.header.len = 2;
- cmd.ibss.atimwindow = cpu_to_le16(0);
-
- /* set capability info */
- tmpcap = WLAN_CAPABILITY_IBSS;
- if (assoc_req->secinfo.wep_enabled ||
- assoc_req->secinfo.WPAenabled ||
- assoc_req->secinfo.WPA2enabled) {
- lbs_deb_join("ADHOC_START: WEP/WPA enabled, privacy on\n");
- tmpcap |= WLAN_CAPABILITY_PRIVACY;
- } else
- lbs_deb_join("ADHOC_START: WEP disabled, privacy off\n");
-
- cmd.capability = cpu_to_le16(tmpcap);
-
- /* Only v8 and below support setting probe delay */
- if (priv->fwrelease < 0x09000000)
- cmd.probedelay = cpu_to_le16(CMD_SCAN_PROBE_DELAY_TIME);
-
- ratesize = min(sizeof(cmd.rates), sizeof(lbs_bg_rates));
- memcpy(cmd.rates, lbs_bg_rates, ratesize);
-
- /* Copy the ad-hoc creating rates into Current BSS state structure */
- memset(&priv->curbssparams.rates, 0, sizeof(priv->curbssparams.rates));
- memcpy(&priv->curbssparams.rates, &cmd.rates, ratesize);
-
- /* Set MSB on basic rates as the firmware requires, but _after_
- * copying to current bss rates.
- */
- lbs_set_basic_rate_flags(cmd.rates, ratesize);
-
- lbs_deb_join("ADHOC_START: rates=%02x %02x %02x %02x\n",
- cmd.rates[0], cmd.rates[1], cmd.rates[2], cmd.rates[3]);
-
- lbs_deb_join("ADHOC_START: Starting Ad-Hoc BSS on channel %d, band %d\n",
- assoc_req->channel, assoc_req->band);
-
- priv->adhoccreate = 1;
- priv->mode = IW_MODE_ADHOC;
-
- ret = lbs_cmd_with_response(priv, CMD_802_11_AD_HOC_START, &cmd);
- if (ret == 0)
- ret = lbs_adhoc_post(priv,
- (struct cmd_ds_802_11_ad_hoc_result *)&cmd);
-
-out:
- lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
- return ret;
-}
-
-/**
- * @brief Stop and Ad-Hoc network and exit Ad-Hoc mode
- *
- * @param priv A pointer to struct lbs_private structure
- * @return 0 on success, or an error
- */
-int lbs_adhoc_stop(struct lbs_private *priv)
-{
- struct cmd_ds_802_11_ad_hoc_stop cmd;
- int ret;
-
- lbs_deb_enter(LBS_DEB_JOIN);
-
- memset(&cmd, 0, sizeof (cmd));
- cmd.hdr.size = cpu_to_le16 (sizeof (cmd));
-
- ret = lbs_cmd_with_response(priv, CMD_802_11_AD_HOC_STOP, &cmd);
-
- /* Clean up everything even if there was an error */
- lbs_mac_event_disconnected(priv);
-
- lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
- return ret;
-}
-
-static inline int match_bss_no_security(struct lbs_802_11_security *secinfo,
- struct bss_descriptor *match_bss)
-{
- if (!secinfo->wep_enabled &&
- !secinfo->WPAenabled && !secinfo->WPA2enabled &&
- match_bss->wpa_ie[0] != WLAN_EID_GENERIC &&
- match_bss->rsn_ie[0] != WLAN_EID_RSN &&
- !(match_bss->capability & WLAN_CAPABILITY_PRIVACY))
- return 1;
- else
- return 0;
-}
-
-static inline int match_bss_static_wep(struct lbs_802_11_security *secinfo,
- struct bss_descriptor *match_bss)
-{
- if (secinfo->wep_enabled &&
- !secinfo->WPAenabled && !secinfo->WPA2enabled &&
- (match_bss->capability & WLAN_CAPABILITY_PRIVACY))
- return 1;
- else
- return 0;
-}
-
-static inline int match_bss_wpa(struct lbs_802_11_security *secinfo,
- struct bss_descriptor *match_bss)
-{
- if (!secinfo->wep_enabled && secinfo->WPAenabled &&
- (match_bss->wpa_ie[0] == WLAN_EID_GENERIC)
- /* privacy bit may NOT be set in some APs like LinkSys WRT54G
- && (match_bss->capability & WLAN_CAPABILITY_PRIVACY) */
- )
- return 1;
- else
- return 0;
-}
-
-static inline int match_bss_wpa2(struct lbs_802_11_security *secinfo,
- struct bss_descriptor *match_bss)
-{
- if (!secinfo->wep_enabled && secinfo->WPA2enabled &&
- (match_bss->rsn_ie[0] == WLAN_EID_RSN)
- /* privacy bit may NOT be set in some APs like LinkSys WRT54G
- (match_bss->capability & WLAN_CAPABILITY_PRIVACY) */
- )
- return 1;
- else
- return 0;
-}
-
-static inline int match_bss_dynamic_wep(struct lbs_802_11_security *secinfo,
- struct bss_descriptor *match_bss)
-{
- if (!secinfo->wep_enabled &&
- !secinfo->WPAenabled && !secinfo->WPA2enabled &&
- (match_bss->wpa_ie[0] != WLAN_EID_GENERIC) &&
- (match_bss->rsn_ie[0] != WLAN_EID_RSN) &&
- (match_bss->capability & WLAN_CAPABILITY_PRIVACY))
- return 1;
- else
- return 0;
-}
-
-/**
- * @brief Check if a scanned network compatible with the driver settings
- *
- * WEP WPA WPA2 ad-hoc encrypt Network
- * enabled enabled enabled AES mode privacy WPA WPA2 Compatible
- * 0 0 0 0 NONE 0 0 0 yes No security
- * 1 0 0 0 NONE 1 0 0 yes Static WEP
- * 0 1 0 0 x 1x 1 x yes WPA
- * 0 0 1 0 x 1x x 1 yes WPA2
- * 0 0 0 1 NONE 1 0 0 yes Ad-hoc AES
- * 0 0 0 0 !=NONE 1 0 0 yes Dynamic WEP
- *
- *
- * @param priv A pointer to struct lbs_private
- * @param index Index in scantable to check against current driver settings
- * @param mode Network mode: Infrastructure or IBSS
- *
- * @return Index in scantable, or error code if negative
- */
-static int is_network_compatible(struct lbs_private *priv,
- struct bss_descriptor *bss, uint8_t mode)
-{
- int matched = 0;
-
- lbs_deb_enter(LBS_DEB_SCAN);
-
- if (bss->mode != mode)
- goto done;
-
- matched = match_bss_no_security(&priv->secinfo, bss);
- if (matched)
- goto done;
- matched = match_bss_static_wep(&priv->secinfo, bss);
- if (matched)
- goto done;
- matched = match_bss_wpa(&priv->secinfo, bss);
- if (matched) {
- lbs_deb_scan("is_network_compatible() WPA: wpa_ie 0x%x "
- "wpa2_ie 0x%x WEP %s WPA %s WPA2 %s "
- "privacy 0x%x\n", bss->wpa_ie[0], bss->rsn_ie[0],
- priv->secinfo.wep_enabled ? "e" : "d",
- priv->secinfo.WPAenabled ? "e" : "d",
- priv->secinfo.WPA2enabled ? "e" : "d",
- (bss->capability & WLAN_CAPABILITY_PRIVACY));
- goto done;
- }
- matched = match_bss_wpa2(&priv->secinfo, bss);
- if (matched) {
- lbs_deb_scan("is_network_compatible() WPA2: wpa_ie 0x%x "
- "wpa2_ie 0x%x WEP %s WPA %s WPA2 %s "
- "privacy 0x%x\n", bss->wpa_ie[0], bss->rsn_ie[0],
- priv->secinfo.wep_enabled ? "e" : "d",
- priv->secinfo.WPAenabled ? "e" : "d",
- priv->secinfo.WPA2enabled ? "e" : "d",
- (bss->capability & WLAN_CAPABILITY_PRIVACY));
- goto done;
- }
- matched = match_bss_dynamic_wep(&priv->secinfo, bss);
- if (matched) {
- lbs_deb_scan("is_network_compatible() dynamic WEP: "
- "wpa_ie 0x%x wpa2_ie 0x%x privacy 0x%x\n",
- bss->wpa_ie[0], bss->rsn_ie[0],
- (bss->capability & WLAN_CAPABILITY_PRIVACY));
- goto done;
- }
-
- /* bss security settings don't match those configured on card */
- lbs_deb_scan("is_network_compatible() FAILED: wpa_ie 0x%x "
- "wpa2_ie 0x%x WEP %s WPA %s WPA2 %s privacy 0x%x\n",
- bss->wpa_ie[0], bss->rsn_ie[0],
- priv->secinfo.wep_enabled ? "e" : "d",
- priv->secinfo.WPAenabled ? "e" : "d",
- priv->secinfo.WPA2enabled ? "e" : "d",
- (bss->capability & WLAN_CAPABILITY_PRIVACY));
-
-done:
- lbs_deb_leave_args(LBS_DEB_SCAN, "matched: %d", matched);
- return matched;
-}
-
-/**
- * @brief This function finds a specific compatible BSSID in the scan list
- *
- * Used in association code
- *
- * @param priv A pointer to struct lbs_private
- * @param bssid BSSID to find in the scan list
- * @param mode Network mode: Infrastructure or IBSS
- *
- * @return index in BSSID list, or error return code (< 0)
- */
-static struct bss_descriptor *lbs_find_bssid_in_list(struct lbs_private *priv,
- uint8_t *bssid, uint8_t mode)
-{
- struct bss_descriptor *iter_bss;
- struct bss_descriptor *found_bss = NULL;
-
- lbs_deb_enter(LBS_DEB_SCAN);
-
- if (!bssid)
- goto out;
-
- lbs_deb_hex(LBS_DEB_SCAN, "looking for", bssid, ETH_ALEN);
-
- /* Look through the scan table for a compatible match. The loop will
- * continue past a matched bssid that is not compatible in case there
- * is an AP with multiple SSIDs assigned to the same BSSID
- */
- mutex_lock(&priv->lock);
- list_for_each_entry(iter_bss, &priv->network_list, list) {
- if (compare_ether_addr(iter_bss->bssid, bssid))
- continue; /* bssid doesn't match */
- switch (mode) {
- case IW_MODE_INFRA:
- case IW_MODE_ADHOC:
- if (!is_network_compatible(priv, iter_bss, mode))
- break;
- found_bss = iter_bss;
- break;
- default:
- found_bss = iter_bss;
- break;
- }
- }
- mutex_unlock(&priv->lock);
-
-out:
- lbs_deb_leave_args(LBS_DEB_SCAN, "found_bss %p", found_bss);
- return found_bss;
-}
-
-/**
- * @brief This function finds ssid in ssid list.
- *
- * Used in association code
- *
- * @param priv A pointer to struct lbs_private
- * @param ssid SSID to find in the list
- * @param bssid BSSID to qualify the SSID selection (if provided)
- * @param mode Network mode: Infrastructure or IBSS
- *
- * @return index in BSSID list
- */
-static struct bss_descriptor *lbs_find_ssid_in_list(struct lbs_private *priv,
- uint8_t *ssid, uint8_t ssid_len,
- uint8_t *bssid, uint8_t mode,
- int channel)
-{
- u32 bestrssi = 0;
- struct bss_descriptor *iter_bss = NULL;
- struct bss_descriptor *found_bss = NULL;
- struct bss_descriptor *tmp_oldest = NULL;
-
- lbs_deb_enter(LBS_DEB_SCAN);
-
- mutex_lock(&priv->lock);
-
- list_for_each_entry(iter_bss, &priv->network_list, list) {
- if (!tmp_oldest ||
- (iter_bss->last_scanned < tmp_oldest->last_scanned))
- tmp_oldest = iter_bss;
-
- if (lbs_ssid_cmp(iter_bss->ssid, iter_bss->ssid_len,
- ssid, ssid_len) != 0)
- continue; /* ssid doesn't match */
- if (bssid && compare_ether_addr(iter_bss->bssid, bssid) != 0)
- continue; /* bssid doesn't match */
- if ((channel > 0) && (iter_bss->channel != channel))
- continue; /* channel doesn't match */
-
- switch (mode) {
- case IW_MODE_INFRA:
- case IW_MODE_ADHOC:
- if (!is_network_compatible(priv, iter_bss, mode))
- break;
-
- if (bssid) {
- /* Found requested BSSID */
- found_bss = iter_bss;
- goto out;
- }
-
- if (SCAN_RSSI(iter_bss->rssi) > bestrssi) {
- bestrssi = SCAN_RSSI(iter_bss->rssi);
- found_bss = iter_bss;
- }
- break;
- case IW_MODE_AUTO:
- default:
- if (SCAN_RSSI(iter_bss->rssi) > bestrssi) {
- bestrssi = SCAN_RSSI(iter_bss->rssi);
- found_bss = iter_bss;
- }
- break;
- }
- }
-
-out:
- mutex_unlock(&priv->lock);
- lbs_deb_leave_args(LBS_DEB_SCAN, "found_bss %p", found_bss);
- return found_bss;
-}
-
-static int assoc_helper_essid(struct lbs_private *priv,
- struct assoc_request * assoc_req)
-{
- int ret = 0;
- struct bss_descriptor * bss;
- int channel = -1;
- DECLARE_SSID_BUF(ssid);
-
- lbs_deb_enter(LBS_DEB_ASSOC);
-
- /* FIXME: take channel into account when picking SSIDs if a channel
- * is set.
- */
-
- if (test_bit(ASSOC_FLAG_CHANNEL, &assoc_req->flags))
- channel = assoc_req->channel;
-
- lbs_deb_assoc("SSID '%s' requested\n",
- print_ssid(ssid, assoc_req->ssid, assoc_req->ssid_len));
- if (assoc_req->mode == IW_MODE_INFRA) {
- lbs_send_specific_ssid_scan(priv, assoc_req->ssid,
- assoc_req->ssid_len);
-
- bss = lbs_find_ssid_in_list(priv, assoc_req->ssid,
- assoc_req->ssid_len, NULL, IW_MODE_INFRA, channel);
- if (bss != NULL) {
- memcpy(&assoc_req->bss, bss, sizeof(struct bss_descriptor));
- ret = lbs_try_associate(priv, assoc_req);
- } else {
- lbs_deb_assoc("SSID not found; cannot associate\n");
- }
- } else if (assoc_req->mode == IW_MODE_ADHOC) {
- /* Scan for the network, do not save previous results. Stale
- * scan data will cause us to join a non-existant adhoc network
- */
- lbs_send_specific_ssid_scan(priv, assoc_req->ssid,
- assoc_req->ssid_len);
-
- /* Search for the requested SSID in the scan table */
- bss = lbs_find_ssid_in_list(priv, assoc_req->ssid,
- assoc_req->ssid_len, NULL, IW_MODE_ADHOC, channel);
- if (bss != NULL) {
- lbs_deb_assoc("SSID found, will join\n");
- memcpy(&assoc_req->bss, bss, sizeof(struct bss_descriptor));
- lbs_adhoc_join(priv, assoc_req);
- } else {
- /* else send START command */
- lbs_deb_assoc("SSID not found, creating adhoc network\n");
- memcpy(&assoc_req->bss.ssid, &assoc_req->ssid,
- IEEE80211_MAX_SSID_LEN);
- assoc_req->bss.ssid_len = assoc_req->ssid_len;
- lbs_adhoc_start(priv, assoc_req);
- }
- }
-
- lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
- return ret;
-}
-
-
-static int assoc_helper_bssid(struct lbs_private *priv,
- struct assoc_request * assoc_req)
-{
- int ret = 0;
- struct bss_descriptor * bss;
-
- lbs_deb_enter_args(LBS_DEB_ASSOC, "BSSID %pM", assoc_req->bssid);
-
- /* Search for index position in list for requested MAC */
- bss = lbs_find_bssid_in_list(priv, assoc_req->bssid,
- assoc_req->mode);
- if (bss == NULL) {
- lbs_deb_assoc("ASSOC: WAP: BSSID %pM not found, "
- "cannot associate.\n", assoc_req->bssid);
- goto out;
- }
-
- memcpy(&assoc_req->bss, bss, sizeof(struct bss_descriptor));
- if (assoc_req->mode == IW_MODE_INFRA) {
- ret = lbs_try_associate(priv, assoc_req);
- lbs_deb_assoc("ASSOC: lbs_try_associate(bssid) returned %d\n",
- ret);
- } else if (assoc_req->mode == IW_MODE_ADHOC) {
- lbs_adhoc_join(priv, assoc_req);
- }
-
-out:
- lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
- return ret;
-}
-
-
-static int assoc_helper_associate(struct lbs_private *priv,
- struct assoc_request * assoc_req)
-{
- int ret = 0, done = 0;
-
- lbs_deb_enter(LBS_DEB_ASSOC);
-
- /* If we're given and 'any' BSSID, try associating based on SSID */
-
- if (test_bit(ASSOC_FLAG_BSSID, &assoc_req->flags)) {
- if (compare_ether_addr(bssid_any, assoc_req->bssid) &&
- compare_ether_addr(bssid_off, assoc_req->bssid)) {
- ret = assoc_helper_bssid(priv, assoc_req);
- done = 1;
- }
- }
-
- if (!done && test_bit(ASSOC_FLAG_SSID, &assoc_req->flags)) {
- ret = assoc_helper_essid(priv, assoc_req);
- }
-
- lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
- return ret;
-}
-
-
-static int assoc_helper_mode(struct lbs_private *priv,
- struct assoc_request * assoc_req)
-{
- int ret = 0;
-
- lbs_deb_enter(LBS_DEB_ASSOC);
-
- if (assoc_req->mode == priv->mode)
- goto done;
-
- if (assoc_req->mode == IW_MODE_INFRA) {
- if (priv->psstate != PS_STATE_FULL_POWER)
- lbs_ps_wakeup(priv, CMD_OPTION_WAITFORRSP);
- priv->psmode = LBS802_11POWERMODECAM;
- }
-
- priv->mode = assoc_req->mode;
- ret = lbs_set_snmp_mib(priv, SNMP_MIB_OID_BSS_TYPE,
- assoc_req->mode == IW_MODE_ADHOC ? 2 : 1);
-
-done:
- lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
- return ret;
-}
-
-static int assoc_helper_channel(struct lbs_private *priv,
- struct assoc_request * assoc_req)
-{
- int ret = 0;
-
- lbs_deb_enter(LBS_DEB_ASSOC);
-
- ret = lbs_update_channel(priv);
- if (ret) {
- lbs_deb_assoc("ASSOC: channel: error getting channel.\n");
- goto done;
- }
-
- if (assoc_req->channel == priv->channel)
- goto done;
-
- if (priv->mesh_dev) {
- /* Change mesh channel first; 21.p21 firmware won't let
- you change channel otherwise (even though it'll return
- an error to this */
- lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_STOP,
- assoc_req->channel);
- }
-
- lbs_deb_assoc("ASSOC: channel: %d -> %d\n",
- priv->channel, assoc_req->channel);
-
- ret = lbs_set_channel(priv, assoc_req->channel);
- if (ret < 0)
- lbs_deb_assoc("ASSOC: channel: error setting channel.\n");
-
- /* FIXME: shouldn't need to grab the channel _again_ after setting
- * it since the firmware is supposed to return the new channel, but
- * whatever... */
- ret = lbs_update_channel(priv);
- if (ret) {
- lbs_deb_assoc("ASSOC: channel: error getting channel.\n");
- goto done;
- }
-
- if (assoc_req->channel != priv->channel) {
- lbs_deb_assoc("ASSOC: channel: failed to update channel to %d\n",
- assoc_req->channel);
- goto restore_mesh;
- }
-
- if (assoc_req->secinfo.wep_enabled &&
- (assoc_req->wep_keys[0].len || assoc_req->wep_keys[1].len ||
- assoc_req->wep_keys[2].len || assoc_req->wep_keys[3].len)) {
- /* Make sure WEP keys are re-sent to firmware */
- set_bit(ASSOC_FLAG_WEP_KEYS, &assoc_req->flags);
- }
-
- /* Must restart/rejoin adhoc networks after channel change */
- set_bit(ASSOC_FLAG_SSID, &assoc_req->flags);
-
- restore_mesh:
- if (priv->mesh_dev)
- lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START,
- priv->channel);
-
- done:
- lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
- return ret;
-}
-
-
-static int assoc_helper_wep_keys(struct lbs_private *priv,
- struct assoc_request *assoc_req)
-{
- int i;
- int ret = 0;
-
- lbs_deb_enter(LBS_DEB_ASSOC);
-
- /* Set or remove WEP keys */
- if (assoc_req->wep_keys[0].len || assoc_req->wep_keys[1].len ||
- assoc_req->wep_keys[2].len || assoc_req->wep_keys[3].len)
- ret = lbs_cmd_802_11_set_wep(priv, CMD_ACT_ADD, assoc_req);
- else
- ret = lbs_cmd_802_11_set_wep(priv, CMD_ACT_REMOVE, assoc_req);
-
- if (ret)
- goto out;
-
- /* enable/disable the MAC's WEP packet filter */
- if (assoc_req->secinfo.wep_enabled)
- priv->mac_control |= CMD_ACT_MAC_WEP_ENABLE;
- else
- priv->mac_control &= ~CMD_ACT_MAC_WEP_ENABLE;
-
- lbs_set_mac_control(priv);
-
- mutex_lock(&priv->lock);
-
- /* Copy WEP keys into priv wep key fields */
- for (i = 0; i < 4; i++) {
- memcpy(&priv->wep_keys[i], &assoc_req->wep_keys[i],
- sizeof(struct enc_key));
- }
- priv->wep_tx_keyidx = assoc_req->wep_tx_keyidx;
-
- mutex_unlock(&priv->lock);
-
-out:
- lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
- return ret;
-}
-
-static int assoc_helper_secinfo(struct lbs_private *priv,
- struct assoc_request * assoc_req)
-{
- int ret = 0;
- uint16_t do_wpa;
- uint16_t rsn = 0;
-
- lbs_deb_enter(LBS_DEB_ASSOC);
-
- memcpy(&priv->secinfo, &assoc_req->secinfo,
- sizeof(struct lbs_802_11_security));
-
- lbs_set_mac_control(priv);
-
- /* If RSN is already enabled, don't try to enable it again, since
- * ENABLE_RSN resets internal state machines and will clobber the
- * 4-way WPA handshake.
- */
-
- /* Get RSN enabled/disabled */
- ret = lbs_cmd_802_11_enable_rsn(priv, CMD_ACT_GET, &rsn);
- if (ret) {
- lbs_deb_assoc("Failed to get RSN status: %d\n", ret);
- goto out;
- }
-
- /* Don't re-enable RSN if it's already enabled */
- do_wpa = assoc_req->secinfo.WPAenabled || assoc_req->secinfo.WPA2enabled;
- if (do_wpa == rsn)
- goto out;
-
- /* Set RSN enabled/disabled */
- ret = lbs_cmd_802_11_enable_rsn(priv, CMD_ACT_SET, &do_wpa);
-
-out:
- lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
- return ret;
-}
-
-
-static int assoc_helper_wpa_keys(struct lbs_private *priv,
- struct assoc_request * assoc_req)
-{
- int ret = 0;
- unsigned int flags = assoc_req->flags;
-
- lbs_deb_enter(LBS_DEB_ASSOC);
-
- /* Work around older firmware bug where WPA unicast and multicast
- * keys must be set independently. Seen in SDIO parts with firmware
- * version 5.0.11p0.
- */
-
- if (test_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags)) {
- clear_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags);
- ret = lbs_cmd_802_11_key_material(priv, CMD_ACT_SET, assoc_req);
- assoc_req->flags = flags;
- }
-
- if (ret)
- goto out;
-
- memcpy(&priv->wpa_unicast_key, &assoc_req->wpa_unicast_key,
- sizeof(struct enc_key));
-
- if (test_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags)) {
- clear_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags);
-
- ret = lbs_cmd_802_11_key_material(priv, CMD_ACT_SET, assoc_req);
- assoc_req->flags = flags;
-
- memcpy(&priv->wpa_mcast_key, &assoc_req->wpa_mcast_key,
- sizeof(struct enc_key));
- }
-
-out:
- lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
- return ret;
-}
-
-
-static int assoc_helper_wpa_ie(struct lbs_private *priv,
- struct assoc_request * assoc_req)
-{
- int ret = 0;
-
- lbs_deb_enter(LBS_DEB_ASSOC);
-
- if (assoc_req->secinfo.WPAenabled || assoc_req->secinfo.WPA2enabled) {
- memcpy(&priv->wpa_ie, &assoc_req->wpa_ie, assoc_req->wpa_ie_len);
- priv->wpa_ie_len = assoc_req->wpa_ie_len;
- } else {
- memset(&priv->wpa_ie, 0, MAX_WPA_IE_LEN);
- priv->wpa_ie_len = 0;
- }
-
- lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
- return ret;
-}
-
-
-static int should_deauth_infrastructure(struct lbs_private *priv,
- struct assoc_request * assoc_req)
-{
- int ret = 0;
-
- if (priv->connect_status != LBS_CONNECTED)
- return 0;
-
- lbs_deb_enter(LBS_DEB_ASSOC);
- if (test_bit(ASSOC_FLAG_SSID, &assoc_req->flags)) {
- lbs_deb_assoc("Deauthenticating due to new SSID\n");
- ret = 1;
- goto out;
- }
-
- if (test_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags)) {
- if (priv->secinfo.auth_mode != assoc_req->secinfo.auth_mode) {
- lbs_deb_assoc("Deauthenticating due to new security\n");
- ret = 1;
- goto out;
- }
- }
-
- if (test_bit(ASSOC_FLAG_BSSID, &assoc_req->flags)) {
- lbs_deb_assoc("Deauthenticating due to new BSSID\n");
- ret = 1;
- goto out;
- }
-
- if (test_bit(ASSOC_FLAG_CHANNEL, &assoc_req->flags)) {
- lbs_deb_assoc("Deauthenticating due to channel switch\n");
- ret = 1;
- goto out;
- }
-
- /* FIXME: deal with 'auto' mode somehow */
- if (test_bit(ASSOC_FLAG_MODE, &assoc_req->flags)) {
- if (assoc_req->mode != IW_MODE_INFRA) {
- lbs_deb_assoc("Deauthenticating due to leaving "
- "infra mode\n");
- ret = 1;
- goto out;
- }
- }
-
-out:
- lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
- return ret;
-}
-
-
-static int should_stop_adhoc(struct lbs_private *priv,
- struct assoc_request * assoc_req)
-{
- lbs_deb_enter(LBS_DEB_ASSOC);
-
- if (priv->connect_status != LBS_CONNECTED)
- return 0;
-
- if (lbs_ssid_cmp(priv->curbssparams.ssid,
- priv->curbssparams.ssid_len,
- assoc_req->ssid, assoc_req->ssid_len) != 0)
- return 1;
-
- /* FIXME: deal with 'auto' mode somehow */
- if (test_bit(ASSOC_FLAG_MODE, &assoc_req->flags)) {
- if (assoc_req->mode != IW_MODE_ADHOC)
- return 1;
- }
-
- if (test_bit(ASSOC_FLAG_CHANNEL, &assoc_req->flags)) {
- if (assoc_req->channel != priv->channel)
- return 1;
- }
-
- lbs_deb_leave(LBS_DEB_ASSOC);
- return 0;
-}
-
-
-/**
- * @brief This function finds the best SSID in the Scan List
- *
- * Search the scan table for the best SSID that also matches the current
- * adapter network preference (infrastructure or adhoc)
- *
- * @param priv A pointer to struct lbs_private
- *
- * @return index in BSSID list
- */
-static struct bss_descriptor *lbs_find_best_ssid_in_list(
- struct lbs_private *priv, uint8_t mode)
-{
- uint8_t bestrssi = 0;
- struct bss_descriptor *iter_bss;
- struct bss_descriptor *best_bss = NULL;
-
- lbs_deb_enter(LBS_DEB_SCAN);
-
- mutex_lock(&priv->lock);
-
- list_for_each_entry(iter_bss, &priv->network_list, list) {
- switch (mode) {
- case IW_MODE_INFRA:
- case IW_MODE_ADHOC:
- if (!is_network_compatible(priv, iter_bss, mode))
- break;
- if (SCAN_RSSI(iter_bss->rssi) <= bestrssi)
- break;
- bestrssi = SCAN_RSSI(iter_bss->rssi);
- best_bss = iter_bss;
- break;
- case IW_MODE_AUTO:
- default:
- if (SCAN_RSSI(iter_bss->rssi) <= bestrssi)
- break;
- bestrssi = SCAN_RSSI(iter_bss->rssi);
- best_bss = iter_bss;
- break;
- }
- }
-
- mutex_unlock(&priv->lock);
- lbs_deb_leave_args(LBS_DEB_SCAN, "best_bss %p", best_bss);
- return best_bss;
-}
-
-/**
- * @brief Find the best AP
- *
- * Used from association worker.
- *
- * @param priv A pointer to struct lbs_private structure
- * @param pSSID A pointer to AP's ssid
- *
- * @return 0--success, otherwise--fail
- */
-static int lbs_find_best_network_ssid(struct lbs_private *priv,
- uint8_t *out_ssid, uint8_t *out_ssid_len, uint8_t preferred_mode,
- uint8_t *out_mode)
-{
- int ret = -1;
- struct bss_descriptor *found;
-
- lbs_deb_enter(LBS_DEB_SCAN);
-
- priv->scan_ssid_len = 0;
- lbs_scan_networks(priv, 1);
- if (priv->surpriseremoved)
- goto out;
-
- found = lbs_find_best_ssid_in_list(priv, preferred_mode);
- if (found && (found->ssid_len > 0)) {
- memcpy(out_ssid, &found->ssid, IEEE80211_MAX_SSID_LEN);
- *out_ssid_len = found->ssid_len;
- *out_mode = found->mode;
- ret = 0;
- }
-
-out:
- lbs_deb_leave_args(LBS_DEB_SCAN, "ret %d", ret);
- return ret;
-}
-
-
-void lbs_association_worker(struct work_struct *work)
-{
- struct lbs_private *priv = container_of(work, struct lbs_private,
- assoc_work.work);
- struct assoc_request * assoc_req = NULL;
- int ret = 0;
- int find_any_ssid = 0;
- DECLARE_SSID_BUF(ssid);
-
- lbs_deb_enter(LBS_DEB_ASSOC);
-
- mutex_lock(&priv->lock);
- assoc_req = priv->pending_assoc_req;
- priv->pending_assoc_req = NULL;
- priv->in_progress_assoc_req = assoc_req;
- mutex_unlock(&priv->lock);
-
- if (!assoc_req)
- goto done;
-
- lbs_deb_assoc(
- "Association Request:\n"
- " flags: 0x%08lx\n"
- " SSID: '%s'\n"
- " chann: %d\n"
- " band: %d\n"
- " mode: %d\n"
- " BSSID: %pM\n"
- " secinfo: %s%s%s\n"
- " auth_mode: %d\n",
- assoc_req->flags,
- print_ssid(ssid, assoc_req->ssid, assoc_req->ssid_len),
- assoc_req->channel, assoc_req->band, assoc_req->mode,
- assoc_req->bssid,
- assoc_req->secinfo.WPAenabled ? " WPA" : "",
- assoc_req->secinfo.WPA2enabled ? " WPA2" : "",
- assoc_req->secinfo.wep_enabled ? " WEP" : "",
- assoc_req->secinfo.auth_mode);
-
- /* If 'any' SSID was specified, find an SSID to associate with */
- if (test_bit(ASSOC_FLAG_SSID, &assoc_req->flags) &&
- !assoc_req->ssid_len)
- find_any_ssid = 1;
-
- /* But don't use 'any' SSID if there's a valid locked BSSID to use */
- if (test_bit(ASSOC_FLAG_BSSID, &assoc_req->flags)) {
- if (compare_ether_addr(assoc_req->bssid, bssid_any) &&
- compare_ether_addr(assoc_req->bssid, bssid_off))
- find_any_ssid = 0;
- }
-
- if (find_any_ssid) {
- u8 new_mode = assoc_req->mode;
-
- ret = lbs_find_best_network_ssid(priv, assoc_req->ssid,
- &assoc_req->ssid_len, assoc_req->mode, &new_mode);
- if (ret) {
- lbs_deb_assoc("Could not find best network\n");
- ret = -ENETUNREACH;
- goto out;
- }
-
- /* Ensure we switch to the mode of the AP */
- if (assoc_req->mode == IW_MODE_AUTO) {
- set_bit(ASSOC_FLAG_MODE, &assoc_req->flags);
- assoc_req->mode = new_mode;
- }
- }
-
- /*
- * Check if the attributes being changing require deauthentication
- * from the currently associated infrastructure access point.
- */
- if (priv->mode == IW_MODE_INFRA) {
- if (should_deauth_infrastructure(priv, assoc_req)) {
- ret = lbs_cmd_80211_deauthenticate(priv,
- priv->curbssparams.bssid,
- WLAN_REASON_DEAUTH_LEAVING);
- if (ret) {
- lbs_deb_assoc("Deauthentication due to new "
- "configuration request failed: %d\n",
- ret);
- }
- }
- } else if (priv->mode == IW_MODE_ADHOC) {
- if (should_stop_adhoc(priv, assoc_req)) {
- ret = lbs_adhoc_stop(priv);
- if (ret) {
- lbs_deb_assoc("Teardown of AdHoc network due to "
- "new configuration request failed: %d\n",
- ret);
- }
-
- }
- }
-
- /* Send the various configuration bits to the firmware */
- if (test_bit(ASSOC_FLAG_MODE, &assoc_req->flags)) {
- ret = assoc_helper_mode(priv, assoc_req);
- if (ret)
- goto out;
- }
-
- if (test_bit(ASSOC_FLAG_CHANNEL, &assoc_req->flags)) {
- ret = assoc_helper_channel(priv, assoc_req);
- if (ret)
- goto out;
- }
-
- if (test_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags)) {
- ret = assoc_helper_secinfo(priv, assoc_req);
- if (ret)
- goto out;
- }
-
- if (test_bit(ASSOC_FLAG_WPA_IE, &assoc_req->flags)) {
- ret = assoc_helper_wpa_ie(priv, assoc_req);
- if (ret)
- goto out;
- }
-
- /*
- * v10 FW wants WPA keys to be set/cleared before WEP key operations,
- * otherwise it will fail to correctly associate to WEP networks.
- * Other firmware versions don't appear to care.
- */
- if (test_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags) ||
- test_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags)) {
- ret = assoc_helper_wpa_keys(priv, assoc_req);
- if (ret)
- goto out;
- }
-
- if (test_bit(ASSOC_FLAG_WEP_KEYS, &assoc_req->flags) ||
- test_bit(ASSOC_FLAG_WEP_TX_KEYIDX, &assoc_req->flags)) {
- ret = assoc_helper_wep_keys(priv, assoc_req);
- if (ret)
- goto out;
- }
-
-
- /* SSID/BSSID should be the _last_ config option set, because they
- * trigger the association attempt.
- */
- if (test_bit(ASSOC_FLAG_BSSID, &assoc_req->flags) ||
- test_bit(ASSOC_FLAG_SSID, &assoc_req->flags)) {
- int success = 1;
-
- ret = assoc_helper_associate(priv, assoc_req);
- if (ret) {
- lbs_deb_assoc("ASSOC: association unsuccessful: %d\n",
- ret);
- success = 0;
- }
-
- if (priv->connect_status != LBS_CONNECTED) {
- lbs_deb_assoc("ASSOC: association unsuccessful, "
- "not connected\n");
- success = 0;
- }
-
- if (success) {
- lbs_deb_assoc("associated to %pM\n",
- priv->curbssparams.bssid);
- lbs_prepare_and_send_command(priv,
- CMD_802_11_RSSI,
- 0, CMD_OPTION_WAITFORRSP, 0, NULL);
- } else {
- ret = -1;
- }
- }
-
-out:
- if (ret) {
- lbs_deb_assoc("ASSOC: reconfiguration attempt unsuccessful: %d\n",
- ret);
- }
-
- mutex_lock(&priv->lock);
- priv->in_progress_assoc_req = NULL;
- mutex_unlock(&priv->lock);
- kfree(assoc_req);
-
-done:
- lbs_deb_leave(LBS_DEB_ASSOC);
-}
-
-
-/*
- * Caller MUST hold any necessary locks
- */
-struct assoc_request *lbs_get_association_request(struct lbs_private *priv)
-{
- struct assoc_request * assoc_req;
-
- lbs_deb_enter(LBS_DEB_ASSOC);
- if (!priv->pending_assoc_req) {
- priv->pending_assoc_req = kzalloc(sizeof(struct assoc_request),
- GFP_KERNEL);
- if (!priv->pending_assoc_req) {
- lbs_pr_info("Not enough memory to allocate association"
- " request!\n");
- return NULL;
- }
- }
-
- /* Copy current configuration attributes to the association request,
- * but don't overwrite any that are already set.
- */
- assoc_req = priv->pending_assoc_req;
- if (!test_bit(ASSOC_FLAG_SSID, &assoc_req->flags)) {
- memcpy(&assoc_req->ssid, &priv->curbssparams.ssid,
- IEEE80211_MAX_SSID_LEN);
- assoc_req->ssid_len = priv->curbssparams.ssid_len;
- }
-
- if (!test_bit(ASSOC_FLAG_CHANNEL, &assoc_req->flags))
- assoc_req->channel = priv->channel;
-
- if (!test_bit(ASSOC_FLAG_BAND, &assoc_req->flags))
- assoc_req->band = priv->curbssparams.band;
-
- if (!test_bit(ASSOC_FLAG_MODE, &assoc_req->flags))
- assoc_req->mode = priv->mode;
-
- if (!test_bit(ASSOC_FLAG_BSSID, &assoc_req->flags)) {
- memcpy(&assoc_req->bssid, priv->curbssparams.bssid,
- ETH_ALEN);
- }
-
- if (!test_bit(ASSOC_FLAG_WEP_KEYS, &assoc_req->flags)) {
- int i;
- for (i = 0; i < 4; i++) {
- memcpy(&assoc_req->wep_keys[i], &priv->wep_keys[i],
- sizeof(struct enc_key));
- }
- }
-
- if (!test_bit(ASSOC_FLAG_WEP_TX_KEYIDX, &assoc_req->flags))
- assoc_req->wep_tx_keyidx = priv->wep_tx_keyidx;
-
- if (!test_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags)) {
- memcpy(&assoc_req->wpa_mcast_key, &priv->wpa_mcast_key,
- sizeof(struct enc_key));
- }
-
- if (!test_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags)) {
- memcpy(&assoc_req->wpa_unicast_key, &priv->wpa_unicast_key,
- sizeof(struct enc_key));
- }
-
- if (!test_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags)) {
- memcpy(&assoc_req->secinfo, &priv->secinfo,
- sizeof(struct lbs_802_11_security));
- }
-
- if (!test_bit(ASSOC_FLAG_WPA_IE, &assoc_req->flags)) {
- memcpy(&assoc_req->wpa_ie, &priv->wpa_ie,
- MAX_WPA_IE_LEN);
- assoc_req->wpa_ie_len = priv->wpa_ie_len;
- }
-
- lbs_deb_leave(LBS_DEB_ASSOC);
- return assoc_req;
-}
-
-
-/**
- * @brief Deauthenticate from a specific BSS
- *
- * @param priv A pointer to struct lbs_private structure
- * @param bssid The specific BSS to deauthenticate from
- * @param reason The 802.11 sec. 7.3.1.7 Reason Code for deauthenticating
- *
- * @return 0 on success, error on failure
- */
-int lbs_cmd_80211_deauthenticate(struct lbs_private *priv, u8 bssid[ETH_ALEN],
- u16 reason)
-{
- struct cmd_ds_802_11_deauthenticate cmd;
- int ret;
-
- lbs_deb_enter(LBS_DEB_JOIN);
-
- memset(&cmd, 0, sizeof(cmd));
- cmd.hdr.size = cpu_to_le16(sizeof(cmd));
- memcpy(cmd.macaddr, &bssid[0], ETH_ALEN);
- cmd.reasoncode = cpu_to_le16(reason);
-
- ret = lbs_cmd_with_response(priv, CMD_802_11_DEAUTHENTICATE, &cmd);
-
- /* Clean up everything even if there was an error; can't assume that
- * we're still authenticated to the AP after trying to deauth.
- */
- lbs_mac_event_disconnected(priv);
-
- lbs_deb_leave(LBS_DEB_JOIN);
- return ret;
-}
-
diff --git a/drivers/net/wireless/libertas/assoc.h b/drivers/net/wireless/libertas/assoc.h
deleted file mode 100644
index 40621b789fc..00000000000
--- a/drivers/net/wireless/libertas/assoc.h
+++ /dev/null
@@ -1,155 +0,0 @@
-/* Copyright (C) 2006, Red Hat, Inc. */
-
-#ifndef _LBS_ASSOC_H_
-#define _LBS_ASSOC_H_
-
-
-#include "defs.h"
-#include "host.h"
-
-
-struct lbs_private;
-
-/*
- * In theory, the IE is limited to the IE length, 255,
- * but in practice 64 bytes are enough.
- */
-#define MAX_WPA_IE_LEN 64
-
-
-
-struct lbs_802_11_security {
- u8 WPAenabled;
- u8 WPA2enabled;
- u8 wep_enabled;
- u8 auth_mode;
- u32 key_mgmt;
-};
-
-/** Current Basic Service Set State Structure */
-struct current_bss_params {
- /** bssid */
- u8 bssid[ETH_ALEN];
- /** ssid */
- u8 ssid[IEEE80211_MAX_SSID_LEN + 1];
- u8 ssid_len;
-
- /** band */
- u8 band;
- /** channel is directly in priv->channel */
- /** zero-terminated array of supported data rates */
- u8 rates[MAX_RATES + 1];
-};
-
-/**
- * @brief Structure used to store information for each beacon/probe response
- */
-struct bss_descriptor {
- u8 bssid[ETH_ALEN];
-
- u8 ssid[IEEE80211_MAX_SSID_LEN + 1];
- u8 ssid_len;
-
- u16 capability;
- u32 rssi;
- u32 channel;
- u16 beaconperiod;
- __le16 atimwindow;
-
- /* IW_MODE_AUTO, IW_MODE_ADHOC, IW_MODE_INFRA */
- u8 mode;
-
- /* zero-terminated array of supported data rates */
- u8 rates[MAX_RATES + 1];
-
- unsigned long last_scanned;
-
- union ieee_phy_param_set phy;
- union ieee_ss_param_set ss;
-
- u8 wpa_ie[MAX_WPA_IE_LEN];
- size_t wpa_ie_len;
- u8 rsn_ie[MAX_WPA_IE_LEN];
- size_t rsn_ie_len;
-
- u8 mesh;
-
- struct list_head list;
-};
-
-/** Association request
- *
- * Encapsulates all the options that describe a specific assocation request
- * or configuration of the wireless card's radio, mode, and security settings.
- */
-struct assoc_request {
-#define ASSOC_FLAG_SSID 1
-#define ASSOC_FLAG_CHANNEL 2
-#define ASSOC_FLAG_BAND 3
-#define ASSOC_FLAG_MODE 4
-#define ASSOC_FLAG_BSSID 5
-#define ASSOC_FLAG_WEP_KEYS 6
-#define ASSOC_FLAG_WEP_TX_KEYIDX 7
-#define ASSOC_FLAG_WPA_MCAST_KEY 8
-#define ASSOC_FLAG_WPA_UCAST_KEY 9
-#define ASSOC_FLAG_SECINFO 10
-#define ASSOC_FLAG_WPA_IE 11
- unsigned long flags;
-
- u8 ssid[IEEE80211_MAX_SSID_LEN + 1];
- u8 ssid_len;
- u8 channel;
- u8 band;
- u8 mode;
- u8 bssid[ETH_ALEN] __attribute__ ((aligned (2)));
-
- /** WEP keys */
- struct enc_key wep_keys[4];
- u16 wep_tx_keyidx;
-
- /** WPA keys */
- struct enc_key wpa_mcast_key;
- struct enc_key wpa_unicast_key;
-
- struct lbs_802_11_security secinfo;
-
- /** WPA Information Elements*/
- u8 wpa_ie[MAX_WPA_IE_LEN];
- u8 wpa_ie_len;
-
- /* BSS to associate with for infrastructure of Ad-Hoc join */
- struct bss_descriptor bss;
-};
-
-
-extern u8 lbs_bg_rates[MAX_RATES];
-
-void lbs_association_worker(struct work_struct *work);
-struct assoc_request *lbs_get_association_request(struct lbs_private *priv);
-
-int lbs_adhoc_stop(struct lbs_private *priv);
-
-int lbs_cmd_80211_deauthenticate(struct lbs_private *priv,
- u8 bssid[ETH_ALEN], u16 reason);
-
-int lbs_cmd_802_11_rssi(struct lbs_private *priv,
- struct cmd_ds_command *cmd);
-int lbs_ret_802_11_rssi(struct lbs_private *priv,
- struct cmd_ds_command *resp);
-
-int lbs_cmd_bcn_ctrl(struct lbs_private *priv,
- struct cmd_ds_command *cmd,
- u16 cmd_action);
-int lbs_ret_802_11_bcn_ctrl(struct lbs_private *priv,
- struct cmd_ds_command *resp);
-
-int lbs_cmd_802_11_set_wep(struct lbs_private *priv, uint16_t cmd_action,
- struct assoc_request *assoc);
-
-int lbs_cmd_802_11_enable_rsn(struct lbs_private *priv, uint16_t cmd_action,
- uint16_t *enable);
-
-int lbs_cmd_802_11_key_material(struct lbs_private *priv, uint16_t cmd_action,
- struct assoc_request *assoc);
-
-#endif /* _LBS_ASSOC_H */
diff --git a/drivers/net/wireless/libertas/cfg.c b/drivers/net/wireless/libertas/cfg.c
index 9d5d3ccf08c..25f90276098 100644
--- a/drivers/net/wireless/libertas/cfg.c
+++ b/drivers/net/wireless/libertas/cfg.c
@@ -7,8 +7,11 @@
*/
#include <linux/slab.h>
+#include <linux/ieee80211.h>
#include <net/cfg80211.h>
+#include <asm/unaligned.h>
+#include "decl.h"
#include "cfg.h"
#include "cmd.h"
@@ -39,26 +42,27 @@ static struct ieee80211_channel lbs_2ghz_channels[] = {
CHAN2G(14, 2484, 0),
};
-#define RATETAB_ENT(_rate, _rateid, _flags) { \
- .bitrate = (_rate), \
- .hw_value = (_rateid), \
- .flags = (_flags), \
+#define RATETAB_ENT(_rate, _hw_value, _flags) { \
+ .bitrate = (_rate), \
+ .hw_value = (_hw_value), \
+ .flags = (_flags), \
}
+/* Table 6 in section 3.2.1.1 */
static struct ieee80211_rate lbs_rates[] = {
- RATETAB_ENT(10, 0x1, 0),
- RATETAB_ENT(20, 0x2, 0),
- RATETAB_ENT(55, 0x4, 0),
- RATETAB_ENT(110, 0x8, 0),
- RATETAB_ENT(60, 0x10, 0),
- RATETAB_ENT(90, 0x20, 0),
- RATETAB_ENT(120, 0x40, 0),
- RATETAB_ENT(180, 0x80, 0),
- RATETAB_ENT(240, 0x100, 0),
- RATETAB_ENT(360, 0x200, 0),
- RATETAB_ENT(480, 0x400, 0),
- RATETAB_ENT(540, 0x800, 0),
+ RATETAB_ENT(10, 0, 0),
+ RATETAB_ENT(20, 1, 0),
+ RATETAB_ENT(55, 2, 0),
+ RATETAB_ENT(110, 3, 0),
+ RATETAB_ENT(60, 9, 0),
+ RATETAB_ENT(90, 6, 0),
+ RATETAB_ENT(120, 7, 0),
+ RATETAB_ENT(180, 8, 0),
+ RATETAB_ENT(240, 9, 0),
+ RATETAB_ENT(360, 10, 0),
+ RATETAB_ENT(480, 11, 0),
+ RATETAB_ENT(540, 12, 0),
};
static struct ieee80211_supported_band lbs_band_2ghz = {
@@ -76,22 +80,1616 @@ static const u32 cipher_suites[] = {
WLAN_CIPHER_SUITE_CCMP,
};
+/* Time to stay on the channel */
+#define LBS_DWELL_PASSIVE 100
+#define LBS_DWELL_ACTIVE 40
+/***************************************************************************
+ * Misc utility functions
+ *
+ * TLVs are Marvell specific. They are very similar to IEs, they have the
+ * same structure: type, length, data*. The only difference: for IEs, the
+ * type and length are u8, but for TLVs they're __le16.
+ */
+
+/*
+ * Convert NL80211's auth_type to the one from Libertas, see chapter 5.9.1
+ * in the firmware spec
+ */
+static u8 lbs_auth_to_authtype(enum nl80211_auth_type auth_type)
+{
+ int ret = -ENOTSUPP;
+
+ switch (auth_type) {
+ case NL80211_AUTHTYPE_OPEN_SYSTEM:
+ case NL80211_AUTHTYPE_SHARED_KEY:
+ ret = auth_type;
+ break;
+ case NL80211_AUTHTYPE_AUTOMATIC:
+ ret = NL80211_AUTHTYPE_OPEN_SYSTEM;
+ break;
+ case NL80211_AUTHTYPE_NETWORK_EAP:
+ ret = 0x80;
+ break;
+ default:
+ /* silence compiler */
+ break;
+ }
+ return ret;
+}
+
+
+/* Various firmware commands need the list of supported rates, but with
+ the hight-bit set for basic rates */
+static int lbs_add_rates(u8 *rates)
+{
+ size_t i;
+
+ for (i = 0; i < ARRAY_SIZE(lbs_rates); i++) {
+ u8 rate = lbs_rates[i].bitrate / 5;
+ if (rate == 0x02 || rate == 0x04 ||
+ rate == 0x0b || rate == 0x16)
+ rate |= 0x80;
+ rates[i] = rate;
+ }
+ return ARRAY_SIZE(lbs_rates);
+}
+
+
+/***************************************************************************
+ * TLV utility functions
+ *
+ * TLVs are Marvell specific. They are very similar to IEs, they have the
+ * same structure: type, length, data*. The only difference: for IEs, the
+ * type and length are u8, but for TLVs they're __le16.
+ */
+
+
+/*
+ * Add ssid TLV
+ */
+#define LBS_MAX_SSID_TLV_SIZE \
+ (sizeof(struct mrvl_ie_header) \
+ + IEEE80211_MAX_SSID_LEN)
+
+static int lbs_add_ssid_tlv(u8 *tlv, const u8 *ssid, int ssid_len)
+{
+ struct mrvl_ie_ssid_param_set *ssid_tlv = (void *)tlv;
+
+ /*
+ * TLV-ID SSID 00 00
+ * length 06 00
+ * ssid 4d 4e 54 45 53 54
+ */
+ ssid_tlv->header.type = cpu_to_le16(TLV_TYPE_SSID);
+ ssid_tlv->header.len = cpu_to_le16(ssid_len);
+ memcpy(ssid_tlv->ssid, ssid, ssid_len);
+ return sizeof(ssid_tlv->header) + ssid_len;
+}
+
+
+/*
+ * Add channel list TLV (section 8.4.2)
+ *
+ * Actual channel data comes from priv->wdev->wiphy->channels.
+ */
+#define LBS_MAX_CHANNEL_LIST_TLV_SIZE \
+ (sizeof(struct mrvl_ie_header) \
+ + (LBS_SCAN_BEFORE_NAP * sizeof(struct chanscanparamset)))
+
+static int lbs_add_channel_list_tlv(struct lbs_private *priv, u8 *tlv,
+ int last_channel, int active_scan)
+{
+ int chanscanparamsize = sizeof(struct chanscanparamset) *
+ (last_channel - priv->scan_channel);
+
+ struct mrvl_ie_header *header = (void *) tlv;
+
+ /*
+ * TLV-ID CHANLIST 01 01
+ * length 0e 00
+ * channel 00 01 00 00 00 64 00
+ * radio type 00
+ * channel 01
+ * scan type 00
+ * min scan time 00 00
+ * max scan time 64 00
+ * channel 2 00 02 00 00 00 64 00
+ *
+ */
+
+ header->type = cpu_to_le16(TLV_TYPE_CHANLIST);
+ header->len = cpu_to_le16(chanscanparamsize);
+ tlv += sizeof(struct mrvl_ie_header);
+
+ /* lbs_deb_scan("scan: channels %d to %d\n", priv->scan_channel,
+ last_channel); */
+ memset(tlv, 0, chanscanparamsize);
+
+ while (priv->scan_channel < last_channel) {
+ struct chanscanparamset *param = (void *) tlv;
+
+ param->radiotype = CMD_SCAN_RADIO_TYPE_BG;
+ param->channumber =
+ priv->scan_req->channels[priv->scan_channel]->hw_value;
+ if (active_scan) {
+ param->maxscantime = cpu_to_le16(LBS_DWELL_ACTIVE);
+ } else {
+ param->chanscanmode.passivescan = 1;
+ param->maxscantime = cpu_to_le16(LBS_DWELL_PASSIVE);
+ }
+ tlv += sizeof(struct chanscanparamset);
+ priv->scan_channel++;
+ }
+ return sizeof(struct mrvl_ie_header) + chanscanparamsize;
+}
+
+
+/*
+ * Add rates TLV
+ *
+ * The rates are in lbs_bg_rates[], but for the 802.11b
+ * rates the high bit is set. We add this TLV only because
+ * there's a firmware which otherwise doesn't report all
+ * APs in range.
+ */
+#define LBS_MAX_RATES_TLV_SIZE \
+ (sizeof(struct mrvl_ie_header) \
+ + (ARRAY_SIZE(lbs_rates)))
+
+/* Adds a TLV with all rates the hardware supports */
+static int lbs_add_supported_rates_tlv(u8 *tlv)
+{
+ size_t i;
+ struct mrvl_ie_rates_param_set *rate_tlv = (void *)tlv;
+
+ /*
+ * TLV-ID RATES 01 00
+ * length 0e 00
+ * rates 82 84 8b 96 0c 12 18 24 30 48 60 6c
+ */
+ rate_tlv->header.type = cpu_to_le16(TLV_TYPE_RATES);
+ tlv += sizeof(rate_tlv->header);
+ i = lbs_add_rates(tlv);
+ tlv += i;
+ rate_tlv->header.len = cpu_to_le16(i);
+ return sizeof(rate_tlv->header) + i;
+}
+
+
+/*
+ * Adds a TLV with all rates the hardware *and* BSS supports.
+ */
+static int lbs_add_common_rates_tlv(u8 *tlv, struct cfg80211_bss *bss)
+{
+ struct mrvl_ie_rates_param_set *rate_tlv = (void *)tlv;
+ const u8 *rates_eid = ieee80211_bss_get_ie(bss, WLAN_EID_SUPP_RATES);
+ int n;
+
+ /*
+ * 01 00 TLV_TYPE_RATES
+ * 04 00 len
+ * 82 84 8b 96 rates
+ */
+ rate_tlv->header.type = cpu_to_le16(TLV_TYPE_RATES);
+ tlv += sizeof(rate_tlv->header);
+
+ if (!rates_eid) {
+ /* Fallback: add basic 802.11b rates */
+ *tlv++ = 0x82;
+ *tlv++ = 0x84;
+ *tlv++ = 0x8b;
+ *tlv++ = 0x96;
+ n = 4;
+ } else {
+ int hw, ap;
+ u8 ap_max = rates_eid[1];
+ n = 0;
+ for (hw = 0; hw < ARRAY_SIZE(lbs_rates); hw++) {
+ u8 hw_rate = lbs_rates[hw].bitrate / 5;
+ for (ap = 0; ap < ap_max; ap++) {
+ if (hw_rate == (rates_eid[ap+2] & 0x7f)) {
+ *tlv++ = rates_eid[ap+2];
+ n++;
+ }
+ }
+ }
+ }
+
+ rate_tlv->header.len = cpu_to_le16(n);
+ return sizeof(rate_tlv->header) + n;
+}
+
+
+/*
+ * Add auth type TLV.
+ *
+ * This is only needed for newer firmware (V9 and up).
+ */
+#define LBS_MAX_AUTH_TYPE_TLV_SIZE \
+ sizeof(struct mrvl_ie_auth_type)
+
+static int lbs_add_auth_type_tlv(u8 *tlv, enum nl80211_auth_type auth_type)
+{
+ struct mrvl_ie_auth_type *auth = (void *) tlv;
+
+ /*
+ * 1f 01 TLV_TYPE_AUTH_TYPE
+ * 01 00 len
+ * 01 auth type
+ */
+ auth->header.type = cpu_to_le16(TLV_TYPE_AUTH_TYPE);
+ auth->header.len = cpu_to_le16(sizeof(*auth)-sizeof(auth->header));
+ auth->auth = cpu_to_le16(lbs_auth_to_authtype(auth_type));
+ return sizeof(*auth);
+}
+
+
+/*
+ * Add channel (phy ds) TLV
+ */
+#define LBS_MAX_CHANNEL_TLV_SIZE \
+ sizeof(struct mrvl_ie_header)
+
+static int lbs_add_channel_tlv(u8 *tlv, u8 channel)
+{
+ struct mrvl_ie_ds_param_set *ds = (void *) tlv;
+
+ /*
+ * 03 00 TLV_TYPE_PHY_DS
+ * 01 00 len
+ * 06 channel
+ */
+ ds->header.type = cpu_to_le16(TLV_TYPE_PHY_DS);
+ ds->header.len = cpu_to_le16(sizeof(*ds)-sizeof(ds->header));
+ ds->channel = channel;
+ return sizeof(*ds);
+}
+
+
+/*
+ * Add (empty) CF param TLV of the form:
+ */
+#define LBS_MAX_CF_PARAM_TLV_SIZE \
+ sizeof(struct mrvl_ie_header)
+
+static int lbs_add_cf_param_tlv(u8 *tlv)
+{
+ struct mrvl_ie_cf_param_set *cf = (void *)tlv;
+
+ /*
+ * 04 00 TLV_TYPE_CF
+ * 06 00 len
+ * 00 cfpcnt
+ * 00 cfpperiod
+ * 00 00 cfpmaxduration
+ * 00 00 cfpdurationremaining
+ */
+ cf->header.type = cpu_to_le16(TLV_TYPE_CF);
+ cf->header.len = cpu_to_le16(sizeof(*cf)-sizeof(cf->header));
+ return sizeof(*cf);
+}
+
+/*
+ * Add WPA TLV
+ */
+#define LBS_MAX_WPA_TLV_SIZE \
+ (sizeof(struct mrvl_ie_header) \
+ + 128 /* TODO: I guessed the size */)
+
+static int lbs_add_wpa_tlv(u8 *tlv, const u8 *ie, u8 ie_len)
+{
+ size_t tlv_len;
+
+ /*
+ * We need just convert an IE to an TLV. IEs use u8 for the header,
+ * u8 type
+ * u8 len
+ * u8[] data
+ * but TLVs use __le16 instead:
+ * __le16 type
+ * __le16 len
+ * u8[] data
+ */
+ *tlv++ = *ie++;
+ *tlv++ = 0;
+ tlv_len = *tlv++ = *ie++;
+ *tlv++ = 0;
+ while (tlv_len--)
+ *tlv++ = *ie++;
+ /* the TLV is two bytes larger than the IE */
+ return ie_len + 2;
+}
+
+/***************************************************************************
+ * Set Channel
+ */
+
static int lbs_cfg_set_channel(struct wiphy *wiphy,
struct net_device *netdev,
- struct ieee80211_channel *chan,
+ struct ieee80211_channel *channel,
enum nl80211_channel_type channel_type)
{
struct lbs_private *priv = wiphy_priv(wiphy);
int ret = -ENOTSUPP;
- lbs_deb_enter_args(LBS_DEB_CFG80211, "freq %d, type %d", chan->center_freq, channel_type);
+ lbs_deb_enter_args(LBS_DEB_CFG80211, "freq %d, type %d",
+ channel->center_freq, channel_type);
if (channel_type != NL80211_CHAN_NO_HT)
goto out;
- ret = lbs_set_channel(priv, chan->hw_value);
+ ret = lbs_set_channel(priv, channel->hw_value);
+
+ out:
+ lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret);
+ return ret;
+}
+
+
+
+/***************************************************************************
+ * Scanning
+ */
+
+/*
+ * When scanning, the firmware doesn't send a nul packet with the power-safe
+ * bit to the AP. So we cannot stay away from our current channel too long,
+ * otherwise we loose data. So take a "nap" while scanning every other
+ * while.
+ */
+#define LBS_SCAN_BEFORE_NAP 4
+
+
+/*
+ * When the firmware reports back a scan-result, it gives us an "u8 rssi",
+ * which isn't really an RSSI, as it becomes larger when moving away from
+ * the AP. Anyway, we need to convert that into mBm.
+ */
+#define LBS_SCAN_RSSI_TO_MBM(rssi) \
+ ((-(int)rssi + 3)*100)
+
+static int lbs_ret_scan(struct lbs_private *priv, unsigned long dummy,
+ struct cmd_header *resp)
+{
+ struct cmd_ds_802_11_scan_rsp *scanresp = (void *)resp;
+ int bsssize;
+ const u8 *pos;
+ u16 nr_sets;
+ const u8 *tsfdesc;
+ int tsfsize;
+ int i;
+ int ret = -EILSEQ;
+
+ lbs_deb_enter(LBS_DEB_CFG80211);
+
+ bsssize = get_unaligned_le16(&scanresp->bssdescriptsize);
+ nr_sets = le16_to_cpu(resp->size);
+
+ /*
+ * The general layout of the scan response is described in chapter
+ * 5.7.1. Basically we have a common part, then any number of BSS
+ * descriptor sections. Finally we have section with the same number
+ * of TSFs.
+ *
+ * cmd_ds_802_11_scan_rsp
+ * cmd_header
+ * pos_size
+ * nr_sets
+ * bssdesc 1
+ * bssid
+ * rssi
+ * timestamp
+ * intvl
+ * capa
+ * IEs
+ * bssdesc 2
+ * bssdesc n
+ * MrvlIEtypes_TsfFimestamp_t
+ * TSF for BSS 1
+ * TSF for BSS 2
+ * TSF for BSS n
+ */
+
+ pos = scanresp->bssdesc_and_tlvbuffer;
+
+ tsfdesc = pos + bsssize;
+ tsfsize = 4 + 8 * scanresp->nr_sets;
+
+ /* Validity check: we expect a Marvell-Local TLV */
+ i = get_unaligned_le16(tsfdesc);
+ tsfdesc += 2;
+ if (i != TLV_TYPE_TSFTIMESTAMP)
+ goto done;
+ /* Validity check: the TLV holds TSF values with 8 bytes each, so
+ * the size in the TLV must match the nr_sets value */
+ i = get_unaligned_le16(tsfdesc);
+ tsfdesc += 2;
+ if (i / 8 != scanresp->nr_sets)
+ goto done;
+
+ for (i = 0; i < scanresp->nr_sets; i++) {
+ const u8 *bssid;
+ const u8 *ie;
+ int left;
+ int ielen;
+ int rssi;
+ u16 intvl;
+ u16 capa;
+ int chan_no = -1;
+ const u8 *ssid = NULL;
+ u8 ssid_len = 0;
+ DECLARE_SSID_BUF(ssid_buf);
+
+ int len = get_unaligned_le16(pos);
+ pos += 2;
+
+ /* BSSID */
+ bssid = pos;
+ pos += ETH_ALEN;
+ /* RSSI */
+ rssi = *pos++;
+ /* Packet time stamp */
+ pos += 8;
+ /* Beacon interval */
+ intvl = get_unaligned_le16(pos);
+ pos += 2;
+ /* Capabilities */
+ capa = get_unaligned_le16(pos);
+ pos += 2;
+
+ /* To find out the channel, we must parse the IEs */
+ ie = pos;
+ /* 6+1+8+2+2: size of BSSID, RSSI, time stamp, beacon
+ interval, capabilities */
+ ielen = left = len - (6 + 1 + 8 + 2 + 2);
+ while (left >= 2) {
+ u8 id, elen;
+ id = *pos++;
+ elen = *pos++;
+ left -= 2;
+ if (elen > left || elen == 0)
+ goto done;
+ if (id == WLAN_EID_DS_PARAMS)
+ chan_no = *pos;
+ if (id == WLAN_EID_SSID) {
+ ssid = pos;
+ ssid_len = elen;
+ }
+ left -= elen;
+ pos += elen;
+ }
+
+ /* No channel, no luck */
+ if (chan_no != -1) {
+ struct wiphy *wiphy = priv->wdev->wiphy;
+ int freq = ieee80211_channel_to_frequency(chan_no);
+ struct ieee80211_channel *channel =
+ ieee80211_get_channel(wiphy, freq);
+
+ lbs_deb_scan("scan: %pM, capa %04x, chan %2d, %s, "
+ "%d dBm\n",
+ bssid, capa, chan_no,
+ print_ssid(ssid_buf, ssid, ssid_len),
+ LBS_SCAN_RSSI_TO_MBM(rssi)/100);
+
+ if (channel ||
+ !(channel->flags & IEEE80211_CHAN_DISABLED))
+ cfg80211_inform_bss(wiphy, channel,
+ bssid, le64_to_cpu(*(__le64 *)tsfdesc),
+ capa, intvl, ie, ielen,
+ LBS_SCAN_RSSI_TO_MBM(rssi),
+ GFP_KERNEL);
+ }
+ tsfdesc += 8;
+ }
+ ret = 0;
+
+ done:
+ lbs_deb_leave_args(LBS_DEB_SCAN, "ret %d", ret);
+ return ret;
+}
+
+
+/*
+ * Our scan command contains a TLV, consting of a SSID TLV, a channel list
+ * TLV and a rates TLV. Determine the maximum size of them:
+ */
+#define LBS_SCAN_MAX_CMD_SIZE \
+ (sizeof(struct cmd_ds_802_11_scan) \
+ + LBS_MAX_SSID_TLV_SIZE \
+ + LBS_MAX_CHANNEL_LIST_TLV_SIZE \
+ + LBS_MAX_RATES_TLV_SIZE)
+
+/*
+ * Assumes priv->scan_req is initialized and valid
+ * Assumes priv->scan_channel is initialized
+ */
+static void lbs_scan_worker(struct work_struct *work)
+{
+ struct lbs_private *priv =
+ container_of(work, struct lbs_private, scan_work.work);
+ struct cmd_ds_802_11_scan *scan_cmd;
+ u8 *tlv; /* pointer into our current, growing TLV storage area */
+ int last_channel;
+ int running, carrier;
+
+ lbs_deb_enter(LBS_DEB_SCAN);
+
+ scan_cmd = kzalloc(LBS_SCAN_MAX_CMD_SIZE, GFP_KERNEL);
+ if (scan_cmd == NULL)
+ goto out_no_scan_cmd;
+
+ /* prepare fixed part of scan command */
+ scan_cmd->bsstype = CMD_BSS_TYPE_ANY;
+
+ /* stop network while we're away from our main channel */
+ running = !netif_queue_stopped(priv->dev);
+ carrier = netif_carrier_ok(priv->dev);
+ if (running)
+ netif_stop_queue(priv->dev);
+ if (carrier)
+ netif_carrier_off(priv->dev);
+
+ /* prepare fixed part of scan command */
+ tlv = scan_cmd->tlvbuffer;
+
+ /* add SSID TLV */
+ if (priv->scan_req->n_ssids)
+ tlv += lbs_add_ssid_tlv(tlv,
+ priv->scan_req->ssids[0].ssid,
+ priv->scan_req->ssids[0].ssid_len);
+
+ /* add channel TLVs */
+ last_channel = priv->scan_channel + LBS_SCAN_BEFORE_NAP;
+ if (last_channel > priv->scan_req->n_channels)
+ last_channel = priv->scan_req->n_channels;
+ tlv += lbs_add_channel_list_tlv(priv, tlv, last_channel,
+ priv->scan_req->n_ssids);
+
+ /* add rates TLV */
+ tlv += lbs_add_supported_rates_tlv(tlv);
+
+ if (priv->scan_channel < priv->scan_req->n_channels) {
+ cancel_delayed_work(&priv->scan_work);
+ queue_delayed_work(priv->work_thread, &priv->scan_work,
+ msecs_to_jiffies(300));
+ }
+
+ /* This is the final data we are about to send */
+ scan_cmd->hdr.size = cpu_to_le16(tlv - (u8 *)scan_cmd);
+ lbs_deb_hex(LBS_DEB_SCAN, "SCAN_CMD", (void *)scan_cmd,
+ sizeof(*scan_cmd));
+ lbs_deb_hex(LBS_DEB_SCAN, "SCAN_TLV", scan_cmd->tlvbuffer,
+ tlv - scan_cmd->tlvbuffer);
+
+ __lbs_cmd(priv, CMD_802_11_SCAN, &scan_cmd->hdr,
+ le16_to_cpu(scan_cmd->hdr.size),
+ lbs_ret_scan, 0);
+
+ if (priv->scan_channel >= priv->scan_req->n_channels) {
+ /* Mark scan done */
+ cfg80211_scan_done(priv->scan_req, false);
+ priv->scan_req = NULL;
+ }
+
+ /* Restart network */
+ if (carrier)
+ netif_carrier_on(priv->dev);
+ if (running && !priv->tx_pending_len)
+ netif_wake_queue(priv->dev);
+
+ kfree(scan_cmd);
+
+ out_no_scan_cmd:
+ lbs_deb_leave(LBS_DEB_SCAN);
+}
+
+
+static int lbs_cfg_scan(struct wiphy *wiphy,
+ struct net_device *dev,
+ struct cfg80211_scan_request *request)
+{
+ struct lbs_private *priv = wiphy_priv(wiphy);
+ int ret = 0;
+
+ lbs_deb_enter(LBS_DEB_CFG80211);
+
+ if (priv->scan_req || delayed_work_pending(&priv->scan_work)) {
+ /* old scan request not yet processed */
+ ret = -EAGAIN;
+ goto out;
+ }
+
+ lbs_deb_scan("scan: ssids %d, channels %d, ie_len %zd\n",
+ request->n_ssids, request->n_channels, request->ie_len);
+
+ priv->scan_channel = 0;
+ queue_delayed_work(priv->work_thread, &priv->scan_work,
+ msecs_to_jiffies(50));
+
+ if (priv->surpriseremoved)
+ ret = -EIO;
+
+ priv->scan_req = request;
+
+ out:
+ lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret);
+ return ret;
+}
+
+
+
+
+/***************************************************************************
+ * Events
+ */
+
+void lbs_send_disconnect_notification(struct lbs_private *priv)
+{
+ lbs_deb_enter(LBS_DEB_CFG80211);
+
+ cfg80211_disconnected(priv->dev,
+ 0,
+ NULL, 0,
+ GFP_KERNEL);
+
+ lbs_deb_leave(LBS_DEB_CFG80211);
+}
+
+void lbs_send_mic_failureevent(struct lbs_private *priv, u32 event)
+{
+ lbs_deb_enter(LBS_DEB_CFG80211);
+
+ cfg80211_michael_mic_failure(priv->dev,
+ priv->assoc_bss,
+ event == MACREG_INT_CODE_MIC_ERR_MULTICAST ?
+ NL80211_KEYTYPE_GROUP :
+ NL80211_KEYTYPE_PAIRWISE,
+ -1,
+ NULL,
+ GFP_KERNEL);
+
+ lbs_deb_leave(LBS_DEB_CFG80211);
+}
+
+
+
+
+/***************************************************************************
+ * Connect/disconnect
+ */
+
+
+/*
+ * This removes all WEP keys
+ */
+static int lbs_remove_wep_keys(struct lbs_private *priv)
+{
+ struct cmd_ds_802_11_set_wep cmd;
+ int ret;
+
+ lbs_deb_enter(LBS_DEB_CFG80211);
+
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.hdr.size = cpu_to_le16(sizeof(cmd));
+ cmd.keyindex = cpu_to_le16(priv->wep_tx_key);
+ cmd.action = cpu_to_le16(CMD_ACT_REMOVE);
+
+ ret = lbs_cmd_with_response(priv, CMD_802_11_SET_WEP, &cmd);
+
+ lbs_deb_leave(LBS_DEB_CFG80211);
+ return ret;
+}
+
+/*
+ * Set WEP keys
+ */
+static int lbs_set_wep_keys(struct lbs_private *priv)
+{
+ struct cmd_ds_802_11_set_wep cmd;
+ int i;
+ int ret;
+
+ lbs_deb_enter(LBS_DEB_CFG80211);
+
+ /*
+ * command 13 00
+ * size 50 00
+ * sequence xx xx
+ * result 00 00
+ * action 02 00 ACT_ADD
+ * transmit key 00 00
+ * type for key 1 01 WEP40
+ * type for key 2 00
+ * type for key 3 00
+ * type for key 4 00
+ * key 1 39 39 39 39 39 00 00 00
+ * 00 00 00 00 00 00 00 00
+ * key 2 00 00 00 00 00 00 00 00
+ * 00 00 00 00 00 00 00 00
+ * key 3 00 00 00 00 00 00 00 00
+ * 00 00 00 00 00 00 00 00
+ * key 4 00 00 00 00 00 00 00 00
+ */
+ if (priv->wep_key_len[0] || priv->wep_key_len[1] ||
+ priv->wep_key_len[2] || priv->wep_key_len[3]) {
+ /* Only set wep keys if we have at least one of them */
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.hdr.size = cpu_to_le16(sizeof(cmd));
+ cmd.keyindex = cpu_to_le16(priv->wep_tx_key);
+ cmd.action = cpu_to_le16(CMD_ACT_ADD);
+
+ for (i = 0; i < 4; i++) {
+ switch (priv->wep_key_len[i]) {
+ case WLAN_KEY_LEN_WEP40:
+ cmd.keytype[i] = CMD_TYPE_WEP_40_BIT;
+ break;
+ case WLAN_KEY_LEN_WEP104:
+ cmd.keytype[i] = CMD_TYPE_WEP_104_BIT;
+ break;
+ default:
+ cmd.keytype[i] = 0;
+ break;
+ }
+ memcpy(cmd.keymaterial[i], priv->wep_key[i],
+ priv->wep_key_len[i]);
+ }
+
+ ret = lbs_cmd_with_response(priv, CMD_802_11_SET_WEP, &cmd);
+ } else {
+ /* Otherwise remove all wep keys */
+ ret = lbs_remove_wep_keys(priv);
+ }
+
+ lbs_deb_leave(LBS_DEB_CFG80211);
+ return ret;
+}
+
+
+/*
+ * Enable/Disable RSN status
+ */
+static int lbs_enable_rsn(struct lbs_private *priv, int enable)
+{
+ struct cmd_ds_802_11_enable_rsn cmd;
+ int ret;
+
+ lbs_deb_enter_args(LBS_DEB_CFG80211, "%d", enable);
+
+ /*
+ * cmd 2f 00
+ * size 0c 00
+ * sequence xx xx
+ * result 00 00
+ * action 01 00 ACT_SET
+ * enable 01 00
+ */
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.hdr.size = cpu_to_le16(sizeof(cmd));
+ cmd.action = cpu_to_le16(CMD_ACT_SET);
+ cmd.enable = cpu_to_le16(enable);
+
+ ret = lbs_cmd_with_response(priv, CMD_802_11_ENABLE_RSN, &cmd);
+
+ lbs_deb_leave(LBS_DEB_CFG80211);
+ return ret;
+}
+
+
+/*
+ * Set WPA/WPA key material
+ */
+
+/* like "struct cmd_ds_802_11_key_material", but with cmd_header. Once we
+ * get rid of WEXT, this should go into host.h */
+
+struct cmd_key_material {
+ struct cmd_header hdr;
+
+ __le16 action;
+ struct MrvlIEtype_keyParamSet param;
+} __packed;
+
+static int lbs_set_key_material(struct lbs_private *priv,
+ int key_type,
+ int key_info,
+ u8 *key, u16 key_len)
+{
+ struct cmd_key_material cmd;
+ int ret;
+
+ lbs_deb_enter(LBS_DEB_CFG80211);
+
+ /*
+ * Example for WPA (TKIP):
+ *
+ * cmd 5e 00
+ * size 34 00
+ * sequence xx xx
+ * result 00 00
+ * action 01 00
+ * TLV type 00 01 key param
+ * length 00 26
+ * key type 01 00 TKIP
+ * key info 06 00 UNICAST | ENABLED
+ * key len 20 00
+ * key 32 bytes
+ */
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.hdr.size = cpu_to_le16(sizeof(cmd));
+ cmd.action = cpu_to_le16(CMD_ACT_SET);
+ cmd.param.type = cpu_to_le16(TLV_TYPE_KEY_MATERIAL);
+ cmd.param.length = cpu_to_le16(sizeof(cmd.param) - 4);
+ cmd.param.keytypeid = cpu_to_le16(key_type);
+ cmd.param.keyinfo = cpu_to_le16(key_info);
+ cmd.param.keylen = cpu_to_le16(key_len);
+ if (key && key_len)
+ memcpy(cmd.param.key, key, key_len);
+
+ ret = lbs_cmd_with_response(priv, CMD_802_11_KEY_MATERIAL, &cmd);
+
+ lbs_deb_leave(LBS_DEB_CFG80211);
+ return ret;
+}
+
+
+/*
+ * Sets the auth type (open, shared, etc) in the firmware. That
+ * we use CMD_802_11_AUTHENTICATE is misleading, this firmware
+ * command doesn't send an authentication frame at all, it just
+ * stores the auth_type.
+ */
+static int lbs_set_authtype(struct lbs_private *priv,
+ struct cfg80211_connect_params *sme)
+{
+ struct cmd_ds_802_11_authenticate cmd;
+ int ret;
+
+ lbs_deb_enter_args(LBS_DEB_CFG80211, "%d", sme->auth_type);
+
+ /*
+ * cmd 11 00
+ * size 19 00
+ * sequence xx xx
+ * result 00 00
+ * BSS id 00 13 19 80 da 30
+ * auth type 00
+ * reserved 00 00 00 00 00 00 00 00 00 00
+ */
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.hdr.size = cpu_to_le16(sizeof(cmd));
+ if (sme->bssid)
+ memcpy(cmd.bssid, sme->bssid, ETH_ALEN);
+ /* convert auth_type */
+ ret = lbs_auth_to_authtype(sme->auth_type);
+ if (ret < 0)
+ goto done;
+
+ cmd.authtype = ret;
+ ret = lbs_cmd_with_response(priv, CMD_802_11_AUTHENTICATE, &cmd);
+
+ done:
+ lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret);
+ return ret;
+}
+
+
+/*
+ * Create association request
+ */
+#define LBS_ASSOC_MAX_CMD_SIZE \
+ (sizeof(struct cmd_ds_802_11_associate) \
+ - 512 /* cmd_ds_802_11_associate.iebuf */ \
+ + LBS_MAX_SSID_TLV_SIZE \
+ + LBS_MAX_CHANNEL_TLV_SIZE \
+ + LBS_MAX_CF_PARAM_TLV_SIZE \
+ + LBS_MAX_AUTH_TYPE_TLV_SIZE \
+ + LBS_MAX_WPA_TLV_SIZE)
+
+static int lbs_associate(struct lbs_private *priv,
+ struct cfg80211_bss *bss,
+ struct cfg80211_connect_params *sme)
+{
+ struct cmd_ds_802_11_associate_response *resp;
+ struct cmd_ds_802_11_associate *cmd = kzalloc(LBS_ASSOC_MAX_CMD_SIZE,
+ GFP_KERNEL);
+ const u8 *ssid_eid;
+ size_t len, resp_ie_len;
+ int status;
+ int ret;
+ u8 *pos = &(cmd->iebuf[0]);
+
+ lbs_deb_enter(LBS_DEB_CFG80211);
+
+ if (!cmd) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ /*
+ * cmd 50 00
+ * length 34 00
+ * sequence xx xx
+ * result 00 00
+ * BSS id 00 13 19 80 da 30
+ * capabilities 11 00
+ * listen interval 0a 00
+ * beacon interval 00 00
+ * DTIM period 00
+ * TLVs xx (up to 512 bytes)
+ */
+ cmd->hdr.command = cpu_to_le16(CMD_802_11_ASSOCIATE);
+
+ /* Fill in static fields */
+ memcpy(cmd->bssid, bss->bssid, ETH_ALEN);
+ cmd->listeninterval = cpu_to_le16(MRVDRV_DEFAULT_LISTEN_INTERVAL);
+ cmd->capability = cpu_to_le16(bss->capability);
+
+ /* add SSID TLV */
+ ssid_eid = ieee80211_bss_get_ie(bss, WLAN_EID_SSID);
+ if (ssid_eid)
+ pos += lbs_add_ssid_tlv(pos, ssid_eid + 2, ssid_eid[1]);
+ else
+ lbs_deb_assoc("no SSID\n");
+
+ /* add DS param TLV */
+ if (bss->channel)
+ pos += lbs_add_channel_tlv(pos, bss->channel->hw_value);
+ else
+ lbs_deb_assoc("no channel\n");
+
+ /* add (empty) CF param TLV */
+ pos += lbs_add_cf_param_tlv(pos);
+
+ /* add rates TLV */
+ pos += lbs_add_common_rates_tlv(pos, bss);
+
+ /* add auth type TLV */
+ if (priv->fwrelease >= 0x09000000)
+ pos += lbs_add_auth_type_tlv(pos, sme->auth_type);
+
+ /* add WPA/WPA2 TLV */
+ if (sme->ie && sme->ie_len)
+ pos += lbs_add_wpa_tlv(pos, sme->ie, sme->ie_len);
+
+ len = (sizeof(*cmd) - sizeof(cmd->iebuf)) +
+ (u16)(pos - (u8 *) &cmd->iebuf);
+ cmd->hdr.size = cpu_to_le16(len);
+
+ /* store for later use */
+ memcpy(priv->assoc_bss, bss->bssid, ETH_ALEN);
+
+ ret = lbs_cmd_with_response(priv, CMD_802_11_ASSOCIATE, cmd);
+ if (ret)
+ goto done;
+
+
+ /* generate connect message to cfg80211 */
+
+ resp = (void *) cmd; /* recast for easier field access */
+ status = le16_to_cpu(resp->statuscode);
+
+ /* Convert statis code of old firmware */
+ if (priv->fwrelease < 0x09000000)
+ switch (status) {
+ case 0:
+ break;
+ case 1:
+ lbs_deb_assoc("invalid association parameters\n");
+ status = WLAN_STATUS_CAPS_UNSUPPORTED;
+ break;
+ case 2:
+ lbs_deb_assoc("timer expired while waiting for AP\n");
+ status = WLAN_STATUS_AUTH_TIMEOUT;
+ break;
+ case 3:
+ lbs_deb_assoc("association refused by AP\n");
+ status = WLAN_STATUS_ASSOC_DENIED_UNSPEC;
+ break;
+ case 4:
+ lbs_deb_assoc("authentication refused by AP\n");
+ status = WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION;
+ break;
+ default:
+ lbs_deb_assoc("association failure %d\n", status);
+ status = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ }
+
+ lbs_deb_assoc("status %d, capability 0x%04x\n", status,
+ le16_to_cpu(resp->capability));
+
+ resp_ie_len = le16_to_cpu(resp->hdr.size)
+ - sizeof(resp->hdr)
+ - 6;
+ cfg80211_connect_result(priv->dev,
+ priv->assoc_bss,
+ sme->ie, sme->ie_len,
+ resp->iebuf, resp_ie_len,
+ status,
+ GFP_KERNEL);
+
+ if (status == 0) {
+ /* TODO: get rid of priv->connect_status */
+ priv->connect_status = LBS_CONNECTED;
+ netif_carrier_on(priv->dev);
+ if (!priv->tx_pending_len)
+ netif_tx_wake_all_queues(priv->dev);
+ }
+
+
+done:
+ lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret);
+ return ret;
+}
+
+
+
+static int lbs_cfg_connect(struct wiphy *wiphy, struct net_device *dev,
+ struct cfg80211_connect_params *sme)
+{
+ struct lbs_private *priv = wiphy_priv(wiphy);
+ struct cfg80211_bss *bss = NULL;
+ int ret = 0;
+ u8 preamble = RADIO_PREAMBLE_SHORT;
+
+ lbs_deb_enter(LBS_DEB_CFG80211);
+
+ if (sme->bssid) {
+ bss = cfg80211_get_bss(wiphy, sme->channel, sme->bssid,
+ sme->ssid, sme->ssid_len,
+ WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS);
+ } else {
+ /*
+ * Here we have an impedance mismatch. The firmware command
+ * CMD_802_11_ASSOCIATE always needs a BSSID, it cannot
+ * connect otherwise. However, for the connect-API of
+ * cfg80211 the bssid is purely optional. We don't get one,
+ * except the user specifies one on the "iw" command line.
+ *
+ * If we don't got one, we could initiate a scan and look
+ * for the best matching cfg80211_bss entry.
+ *
+ * Or, better yet, net/wireless/sme.c get's rewritten into
+ * something more generally useful.
+ */
+ lbs_pr_err("TODO: no BSS specified\n");
+ ret = -ENOTSUPP;
+ goto done;
+ }
+
+
+ if (!bss) {
+ lbs_pr_err("assicate: bss %pM not in scan results\n",
+ sme->bssid);
+ ret = -ENOENT;
+ goto done;
+ }
+ lbs_deb_assoc("trying %pM", sme->bssid);
+ lbs_deb_assoc("cipher 0x%x, key index %d, key len %d\n",
+ sme->crypto.cipher_group,
+ sme->key_idx, sme->key_len);
+
+ /* As this is a new connection, clear locally stored WEP keys */
+ priv->wep_tx_key = 0;
+ memset(priv->wep_key, 0, sizeof(priv->wep_key));
+ memset(priv->wep_key_len, 0, sizeof(priv->wep_key_len));
+
+ /* set/remove WEP keys */
+ switch (sme->crypto.cipher_group) {
+ case WLAN_CIPHER_SUITE_WEP40:
+ case WLAN_CIPHER_SUITE_WEP104:
+ /* Store provided WEP keys in priv-> */
+ priv->wep_tx_key = sme->key_idx;
+ priv->wep_key_len[sme->key_idx] = sme->key_len;
+ memcpy(priv->wep_key[sme->key_idx], sme->key, sme->key_len);
+ /* Set WEP keys and WEP mode */
+ lbs_set_wep_keys(priv);
+ priv->mac_control |= CMD_ACT_MAC_WEP_ENABLE;
+ lbs_set_mac_control(priv);
+ /* No RSN mode for WEP */
+ lbs_enable_rsn(priv, 0);
+ break;
+ case 0: /* there's no WLAN_CIPHER_SUITE_NONE definition */
+ /*
+ * If we don't have no WEP, no WPA and no WPA2,
+ * we remove all keys like in the WPA/WPA2 setup,
+ * we just don't set RSN.
+ *
+ * Therefore: fall-throught
+ */
+ case WLAN_CIPHER_SUITE_TKIP:
+ case WLAN_CIPHER_SUITE_CCMP:
+ /* Remove WEP keys and WEP mode */
+ lbs_remove_wep_keys(priv);
+ priv->mac_control &= ~CMD_ACT_MAC_WEP_ENABLE;
+ lbs_set_mac_control(priv);
+
+ /* clear the WPA/WPA2 keys */
+ lbs_set_key_material(priv,
+ KEY_TYPE_ID_WEP, /* doesn't matter */
+ KEY_INFO_WPA_UNICAST,
+ NULL, 0);
+ lbs_set_key_material(priv,
+ KEY_TYPE_ID_WEP, /* doesn't matter */
+ KEY_INFO_WPA_MCAST,
+ NULL, 0);
+ /* RSN mode for WPA/WPA2 */
+ lbs_enable_rsn(priv, sme->crypto.cipher_group != 0);
+ break;
+ default:
+ lbs_pr_err("unsupported cipher group 0x%x\n",
+ sme->crypto.cipher_group);
+ ret = -ENOTSUPP;
+ goto done;
+ }
+
+ lbs_set_authtype(priv, sme);
+ lbs_set_radio(priv, preamble, 1);
+
+ /* Do the actual association */
+ lbs_associate(priv, bss, sme);
+
+ done:
+ if (bss)
+ cfg80211_put_bss(bss);
+ lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret);
+ return ret;
+}
+
+static int lbs_cfg_disconnect(struct wiphy *wiphy, struct net_device *dev,
+ u16 reason_code)
+{
+ struct lbs_private *priv = wiphy_priv(wiphy);
+ struct cmd_ds_802_11_deauthenticate cmd;
+
+ lbs_deb_enter_args(LBS_DEB_CFG80211, "reason_code %d", reason_code);
+
+ /* store for lbs_cfg_ret_disconnect() */
+ priv->disassoc_reason = reason_code;
+
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.hdr.size = cpu_to_le16(sizeof(cmd));
+ /* Mildly ugly to use a locally store my own BSSID ... */
+ memcpy(cmd.macaddr, &priv->assoc_bss, ETH_ALEN);
+ cmd.reasoncode = cpu_to_le16(reason_code);
+
+ if (lbs_cmd_with_response(priv, CMD_802_11_DEAUTHENTICATE, &cmd))
+ return -EFAULT;
+
+ cfg80211_disconnected(priv->dev,
+ priv->disassoc_reason,
+ NULL, 0,
+ GFP_KERNEL);
+ priv->connect_status = LBS_DISCONNECTED;
+
+ return 0;
+}
+
+
+static int lbs_cfg_set_default_key(struct wiphy *wiphy,
+ struct net_device *netdev,
+ u8 key_index)
+{
+ struct lbs_private *priv = wiphy_priv(wiphy);
+
+ lbs_deb_enter(LBS_DEB_CFG80211);
+
+ if (key_index != priv->wep_tx_key) {
+ lbs_deb_assoc("set_default_key: to %d\n", key_index);
+ priv->wep_tx_key = key_index;
+ lbs_set_wep_keys(priv);
+ }
+
+ return 0;
+}
+
+
+static int lbs_cfg_add_key(struct wiphy *wiphy, struct net_device *netdev,
+ u8 idx, const u8 *mac_addr,
+ struct key_params *params)
+{
+ struct lbs_private *priv = wiphy_priv(wiphy);
+ u16 key_info;
+ u16 key_type;
+ int ret = 0;
+
+ lbs_deb_enter(LBS_DEB_CFG80211);
+
+ lbs_deb_assoc("add_key: cipher 0x%x, mac_addr %pM\n",
+ params->cipher, mac_addr);
+ lbs_deb_assoc("add_key: key index %d, key len %d\n",
+ idx, params->key_len);
+ if (params->key_len)
+ lbs_deb_hex(LBS_DEB_CFG80211, "KEY",
+ params->key, params->key_len);
+
+ lbs_deb_assoc("add_key: seq len %d\n", params->seq_len);
+ if (params->seq_len)
+ lbs_deb_hex(LBS_DEB_CFG80211, "SEQ",
+ params->seq, params->seq_len);
+
+ switch (params->cipher) {
+ case WLAN_CIPHER_SUITE_WEP40:
+ case WLAN_CIPHER_SUITE_WEP104:
+ /* actually compare if something has changed ... */
+ if ((priv->wep_key_len[idx] != params->key_len) ||
+ memcmp(priv->wep_key[idx],
+ params->key, params->key_len) != 0) {
+ priv->wep_key_len[idx] = params->key_len;
+ memcpy(priv->wep_key[idx],
+ params->key, params->key_len);
+ lbs_set_wep_keys(priv);
+ }
+ break;
+ case WLAN_CIPHER_SUITE_TKIP:
+ case WLAN_CIPHER_SUITE_CCMP:
+ key_info = KEY_INFO_WPA_ENABLED | ((idx == 0)
+ ? KEY_INFO_WPA_UNICAST
+ : KEY_INFO_WPA_MCAST);
+ key_type = (params->cipher == WLAN_CIPHER_SUITE_TKIP)
+ ? KEY_TYPE_ID_TKIP
+ : KEY_TYPE_ID_AES;
+ lbs_set_key_material(priv,
+ key_type,
+ key_info,
+ params->key, params->key_len);
+ break;
+ default:
+ lbs_pr_err("unhandled cipher 0x%x\n", params->cipher);
+ ret = -ENOTSUPP;
+ break;
+ }
+
+ return ret;
+}
+
+
+static int lbs_cfg_del_key(struct wiphy *wiphy, struct net_device *netdev,
+ u8 key_index, const u8 *mac_addr)
+{
+
+ lbs_deb_enter(LBS_DEB_CFG80211);
+
+ lbs_deb_assoc("del_key: key_idx %d, mac_addr %pM\n",
+ key_index, mac_addr);
+
+#ifdef TODO
+ struct lbs_private *priv = wiphy_priv(wiphy);
+ /*
+ * I think can keep this a NO-OP, because:
+
+ * - we clear all keys whenever we do lbs_cfg_connect() anyway
+ * - neither "iw" nor "wpa_supplicant" won't call this during
+ * an ongoing connection
+ * - TODO: but I have to check if this is still true when
+ * I set the AP to periodic re-keying
+ * - we've not kzallec() something when we've added a key at
+ * lbs_cfg_connect() or lbs_cfg_add_key().
+ *
+ * This causes lbs_cfg_del_key() only called at disconnect time,
+ * where we'd just waste time deleting a key that is not going
+ * to be used anyway.
+ */
+ if (key_index < 3 && priv->wep_key_len[key_index]) {
+ priv->wep_key_len[key_index] = 0;
+ lbs_set_wep_keys(priv);
+ }
+#endif
+
+ return 0;
+}
+
+
+/***************************************************************************
+ * Get station
+ */
+
+static int lbs_cfg_get_station(struct wiphy *wiphy, struct net_device *dev,
+ u8 *mac, struct station_info *sinfo)
+{
+ struct lbs_private *priv = wiphy_priv(wiphy);
+ s8 signal, noise;
+ int ret;
+ size_t i;
+
+ lbs_deb_enter(LBS_DEB_CFG80211);
+
+ sinfo->filled |= STATION_INFO_TX_BYTES |
+ STATION_INFO_TX_PACKETS |
+ STATION_INFO_RX_BYTES |
+ STATION_INFO_RX_PACKETS;
+ sinfo->tx_bytes = priv->dev->stats.tx_bytes;
+ sinfo->tx_packets = priv->dev->stats.tx_packets;
+ sinfo->rx_bytes = priv->dev->stats.rx_bytes;
+ sinfo->rx_packets = priv->dev->stats.rx_packets;
+
+ /* Get current RSSI */
+ ret = lbs_get_rssi(priv, &signal, &noise);
+ if (ret == 0) {
+ sinfo->signal = signal;
+ sinfo->filled |= STATION_INFO_SIGNAL;
+ }
+
+ /* Convert priv->cur_rate from hw_value to NL80211 value */
+ for (i = 0; i < ARRAY_SIZE(lbs_rates); i++) {
+ if (priv->cur_rate == lbs_rates[i].hw_value) {
+ sinfo->txrate.legacy = lbs_rates[i].bitrate;
+ sinfo->filled |= STATION_INFO_TX_BITRATE;
+ break;
+ }
+ }
+
+ return 0;
+}
+
+
+
+
+/***************************************************************************
+ * "Site survey", here just current channel and noise level
+ */
+
+static int lbs_get_survey(struct wiphy *wiphy, struct net_device *dev,
+ int idx, struct survey_info *survey)
+{
+ struct lbs_private *priv = wiphy_priv(wiphy);
+ s8 signal, noise;
+ int ret;
+
+ if (idx != 0)
+ ret = -ENOENT;
+
+ lbs_deb_enter(LBS_DEB_CFG80211);
+
+ survey->channel = ieee80211_get_channel(wiphy,
+ ieee80211_channel_to_frequency(priv->channel));
+
+ ret = lbs_get_rssi(priv, &signal, &noise);
+ if (ret == 0) {
+ survey->filled = SURVEY_INFO_NOISE_DBM;
+ survey->noise = noise;
+ }
+
+ lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret);
+ return ret;
+}
+
+
+
+
+/***************************************************************************
+ * Change interface
+ */
+
+static int lbs_change_intf(struct wiphy *wiphy, struct net_device *dev,
+ enum nl80211_iftype type, u32 *flags,
+ struct vif_params *params)
+{
+ struct lbs_private *priv = wiphy_priv(wiphy);
+ int ret = 0;
+
+ lbs_deb_enter(LBS_DEB_CFG80211);
+
+ switch (type) {
+ case NL80211_IFTYPE_MONITOR:
+ ret = lbs_set_monitor_mode(priv, 1);
+ break;
+ case NL80211_IFTYPE_STATION:
+ if (priv->wdev->iftype == NL80211_IFTYPE_MONITOR)
+ ret = lbs_set_monitor_mode(priv, 0);
+ if (!ret)
+ ret = lbs_set_snmp_mib(priv, SNMP_MIB_OID_BSS_TYPE, 1);
+ break;
+ case NL80211_IFTYPE_ADHOC:
+ if (priv->wdev->iftype == NL80211_IFTYPE_MONITOR)
+ ret = lbs_set_monitor_mode(priv, 0);
+ if (!ret)
+ ret = lbs_set_snmp_mib(priv, SNMP_MIB_OID_BSS_TYPE, 2);
+ break;
+ default:
+ ret = -ENOTSUPP;
+ }
+
+ if (!ret)
+ priv->wdev->iftype = type;
+
+ lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret);
+ return ret;
+}
+
+
+
+/***************************************************************************
+ * IBSS (Ad-Hoc)
+ */
+
+/* The firmware needs the following bits masked out of the beacon-derived
+ * capability field when associating/joining to a BSS:
+ * 9 (QoS), 11 (APSD), 12 (unused), 14 (unused), 15 (unused)
+ */
+#define CAPINFO_MASK (~(0xda00))
+
+
+static void lbs_join_post(struct lbs_private *priv,
+ struct cfg80211_ibss_params *params,
+ u8 *bssid, u16 capability)
+{
+ u8 fake_ie[2 + IEEE80211_MAX_SSID_LEN + /* ssid */
+ 2 + 4 + /* basic rates */
+ 2 + 1 + /* DS parameter */
+ 2 + 2 + /* atim */
+ 2 + 8]; /* extended rates */
+ u8 *fake = fake_ie;
+
+ lbs_deb_enter(LBS_DEB_CFG80211);
+
+ /*
+ * For cfg80211_inform_bss, we'll need a fake IE, as we can't get
+ * the real IE from the firmware. So we fabricate a fake IE based on
+ * what the firmware actually sends (sniffed with wireshark).
+ */
+ /* Fake SSID IE */
+ *fake++ = WLAN_EID_SSID;
+ *fake++ = params->ssid_len;
+ memcpy(fake, params->ssid, params->ssid_len);
+ fake += params->ssid_len;
+ /* Fake supported basic rates IE */
+ *fake++ = WLAN_EID_SUPP_RATES;
+ *fake++ = 4;
+ *fake++ = 0x82;
+ *fake++ = 0x84;
+ *fake++ = 0x8b;
+ *fake++ = 0x96;
+ /* Fake DS channel IE */
+ *fake++ = WLAN_EID_DS_PARAMS;
+ *fake++ = 1;
+ *fake++ = params->channel->hw_value;
+ /* Fake IBSS params IE */
+ *fake++ = WLAN_EID_IBSS_PARAMS;
+ *fake++ = 2;
+ *fake++ = 0; /* ATIM=0 */
+ *fake++ = 0;
+ /* Fake extended rates IE, TODO: don't add this for 802.11b only,
+ * but I don't know how this could be checked */
+ *fake++ = WLAN_EID_EXT_SUPP_RATES;
+ *fake++ = 8;
+ *fake++ = 0x0c;
+ *fake++ = 0x12;
+ *fake++ = 0x18;
+ *fake++ = 0x24;
+ *fake++ = 0x30;
+ *fake++ = 0x48;
+ *fake++ = 0x60;
+ *fake++ = 0x6c;
+ lbs_deb_hex(LBS_DEB_CFG80211, "IE", fake_ie, fake - fake_ie);
+
+ cfg80211_inform_bss(priv->wdev->wiphy,
+ params->channel,
+ bssid,
+ 0,
+ capability,
+ params->beacon_interval,
+ fake_ie, fake - fake_ie,
+ 0, GFP_KERNEL);
+
+ memcpy(priv->wdev->ssid, params->ssid, params->ssid_len);
+ priv->wdev->ssid_len = params->ssid_len;
+
+ cfg80211_ibss_joined(priv->dev, bssid, GFP_KERNEL);
+
+ /* TODO: consider doing this at MACREG_INT_CODE_LINK_SENSED time */
+ priv->connect_status = LBS_CONNECTED;
+ netif_carrier_on(priv->dev);
+ if (!priv->tx_pending_len)
+ netif_wake_queue(priv->dev);
+
+ lbs_deb_leave(LBS_DEB_CFG80211);
+}
+
+static int lbs_ibss_join_existing(struct lbs_private *priv,
+ struct cfg80211_ibss_params *params,
+ struct cfg80211_bss *bss)
+{
+ const u8 *rates_eid = ieee80211_bss_get_ie(bss, WLAN_EID_SUPP_RATES);
+ struct cmd_ds_802_11_ad_hoc_join cmd;
+ u8 preamble = RADIO_PREAMBLE_SHORT;
+ int ret = 0;
+
+ lbs_deb_enter(LBS_DEB_CFG80211);
+
+ /* TODO: set preamble based on scan result */
+ ret = lbs_set_radio(priv, preamble, 1);
+ if (ret)
+ goto out;
+
+ /*
+ * Example CMD_802_11_AD_HOC_JOIN command:
+ *
+ * command 2c 00 CMD_802_11_AD_HOC_JOIN
+ * size 65 00
+ * sequence xx xx
+ * result 00 00
+ * bssid 02 27 27 97 2f 96
+ * ssid 49 42 53 53 00 00 00 00
+ * 00 00 00 00 00 00 00 00
+ * 00 00 00 00 00 00 00 00
+ * 00 00 00 00 00 00 00 00
+ * type 02 CMD_BSS_TYPE_IBSS
+ * beacon period 64 00
+ * dtim period 00
+ * timestamp 00 00 00 00 00 00 00 00
+ * localtime 00 00 00 00 00 00 00 00
+ * IE DS 03
+ * IE DS len 01
+ * IE DS channel 01
+ * reserveed 00 00 00 00
+ * IE IBSS 06
+ * IE IBSS len 02
+ * IE IBSS atim 00 00
+ * reserved 00 00 00 00
+ * capability 02 00
+ * rates 82 84 8b 96 0c 12 18 24 30 48 60 6c 00
+ * fail timeout ff 00
+ * probe delay 00 00
+ */
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.hdr.size = cpu_to_le16(sizeof(cmd));
+
+ memcpy(cmd.bss.bssid, bss->bssid, ETH_ALEN);
+ memcpy(cmd.bss.ssid, params->ssid, params->ssid_len);
+ cmd.bss.type = CMD_BSS_TYPE_IBSS;
+ cmd.bss.beaconperiod = cpu_to_le16(params->beacon_interval);
+ cmd.bss.ds.header.id = WLAN_EID_DS_PARAMS;
+ cmd.bss.ds.header.len = 1;
+ cmd.bss.ds.channel = params->channel->hw_value;
+ cmd.bss.ibss.header.id = WLAN_EID_IBSS_PARAMS;
+ cmd.bss.ibss.header.len = 2;
+ cmd.bss.ibss.atimwindow = 0;
+ cmd.bss.capability = cpu_to_le16(bss->capability & CAPINFO_MASK);
+
+ /* set rates to the intersection of our rates and the rates in the
+ bss */
+ if (!rates_eid) {
+ lbs_add_rates(cmd.bss.rates);
+ } else {
+ int hw, i;
+ u8 rates_max = rates_eid[1];
+ u8 *rates = cmd.bss.rates;
+ for (hw = 0; hw < ARRAY_SIZE(lbs_rates); hw++) {
+ u8 hw_rate = lbs_rates[hw].bitrate / 5;
+ for (i = 0; i < rates_max; i++) {
+ if (hw_rate == (rates_eid[i+2] & 0x7f)) {
+ u8 rate = rates_eid[i+2];
+ if (rate == 0x02 || rate == 0x04 ||
+ rate == 0x0b || rate == 0x16)
+ rate |= 0x80;
+ *rates++ = rate;
+ }
+ }
+ }
+ }
+
+ /* Only v8 and below support setting this */
+ if (MRVL_FW_MAJOR_REV(priv->fwrelease) <= 8) {
+ cmd.failtimeout = cpu_to_le16(MRVDRV_ASSOCIATION_TIME_OUT);
+ cmd.probedelay = cpu_to_le16(CMD_SCAN_PROBE_DELAY_TIME);
+ }
+ ret = lbs_cmd_with_response(priv, CMD_802_11_AD_HOC_JOIN, &cmd);
+ if (ret)
+ goto out;
+
+ /*
+ * This is a sample response to CMD_802_11_AD_HOC_JOIN:
+ *
+ * response 2c 80
+ * size 09 00
+ * sequence xx xx
+ * result 00 00
+ * reserved 00
+ */
+ lbs_join_post(priv, params, bss->bssid, bss->capability);
out:
lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret);
@@ -100,9 +1698,169 @@ static int lbs_cfg_set_channel(struct wiphy *wiphy,
+static int lbs_ibss_start_new(struct lbs_private *priv,
+ struct cfg80211_ibss_params *params)
+{
+ struct cmd_ds_802_11_ad_hoc_start cmd;
+ struct cmd_ds_802_11_ad_hoc_result *resp =
+ (struct cmd_ds_802_11_ad_hoc_result *) &cmd;
+ u8 preamble = RADIO_PREAMBLE_SHORT;
+ int ret = 0;
+ u16 capability;
+
+ lbs_deb_enter(LBS_DEB_CFG80211);
+
+ ret = lbs_set_radio(priv, preamble, 1);
+ if (ret)
+ goto out;
+
+ /*
+ * Example CMD_802_11_AD_HOC_START command:
+ *
+ * command 2b 00 CMD_802_11_AD_HOC_START
+ * size b1 00
+ * sequence xx xx
+ * result 00 00
+ * ssid 54 45 53 54 00 00 00 00
+ * 00 00 00 00 00 00 00 00
+ * 00 00 00 00 00 00 00 00
+ * 00 00 00 00 00 00 00 00
+ * bss type 02
+ * beacon period 64 00
+ * dtim period 00
+ * IE IBSS 06
+ * IE IBSS len 02
+ * IE IBSS atim 00 00
+ * reserved 00 00 00 00
+ * IE DS 03
+ * IE DS len 01
+ * IE DS channel 01
+ * reserved 00 00 00 00
+ * probe delay 00 00
+ * capability 02 00
+ * rates 82 84 8b 96 (basic rates with have bit 7 set)
+ * 0c 12 18 24 30 48 60 6c
+ * padding 100 bytes
+ */
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.hdr.size = cpu_to_le16(sizeof(cmd));
+ memcpy(cmd.ssid, params->ssid, params->ssid_len);
+ cmd.bsstype = CMD_BSS_TYPE_IBSS;
+ cmd.beaconperiod = cpu_to_le16(params->beacon_interval);
+ cmd.ibss.header.id = WLAN_EID_IBSS_PARAMS;
+ cmd.ibss.header.len = 2;
+ cmd.ibss.atimwindow = 0;
+ cmd.ds.header.id = WLAN_EID_DS_PARAMS;
+ cmd.ds.header.len = 1;
+ cmd.ds.channel = params->channel->hw_value;
+ /* Only v8 and below support setting probe delay */
+ if (MRVL_FW_MAJOR_REV(priv->fwrelease) <= 8)
+ cmd.probedelay = cpu_to_le16(CMD_SCAN_PROBE_DELAY_TIME);
+ /* TODO: mix in WLAN_CAPABILITY_PRIVACY */
+ capability = WLAN_CAPABILITY_IBSS;
+ cmd.capability = cpu_to_le16(capability);
+ lbs_add_rates(cmd.rates);
+
+
+ ret = lbs_cmd_with_response(priv, CMD_802_11_AD_HOC_START, &cmd);
+ if (ret)
+ goto out;
+
+ /*
+ * This is a sample response to CMD_802_11_AD_HOC_JOIN:
+ *
+ * response 2b 80
+ * size 14 00
+ * sequence xx xx
+ * result 00 00
+ * reserved 00
+ * bssid 02 2b 7b 0f 86 0e
+ */
+ lbs_join_post(priv, params, resp->bssid, capability);
+
+ out:
+ lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret);
+ return ret;
+}
+
+
+static int lbs_join_ibss(struct wiphy *wiphy, struct net_device *dev,
+ struct cfg80211_ibss_params *params)
+{
+ struct lbs_private *priv = wiphy_priv(wiphy);
+ int ret = 0;
+ struct cfg80211_bss *bss;
+ DECLARE_SSID_BUF(ssid_buf);
+
+ lbs_deb_enter(LBS_DEB_CFG80211);
+
+ if (!params->channel) {
+ ret = -ENOTSUPP;
+ goto out;
+ }
+
+ ret = lbs_set_channel(priv, params->channel->hw_value);
+ if (ret)
+ goto out;
+
+ /* Search if someone is beaconing. This assumes that the
+ * bss list is populated already */
+ bss = cfg80211_get_bss(wiphy, params->channel, params->bssid,
+ params->ssid, params->ssid_len,
+ WLAN_CAPABILITY_IBSS, WLAN_CAPABILITY_IBSS);
+
+ if (bss) {
+ ret = lbs_ibss_join_existing(priv, params, bss);
+ cfg80211_put_bss(bss);
+ } else
+ ret = lbs_ibss_start_new(priv, params);
+
+
+ out:
+ lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret);
+ return ret;
+}
+
+
+static int lbs_leave_ibss(struct wiphy *wiphy, struct net_device *dev)
+{
+ struct lbs_private *priv = wiphy_priv(wiphy);
+ struct cmd_ds_802_11_ad_hoc_stop cmd;
+ int ret = 0;
+
+ lbs_deb_enter(LBS_DEB_CFG80211);
+
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.hdr.size = cpu_to_le16(sizeof(cmd));
+ ret = lbs_cmd_with_response(priv, CMD_802_11_AD_HOC_STOP, &cmd);
+
+ /* TODO: consider doing this at MACREG_INT_CODE_ADHOC_BCN_LOST time */
+ lbs_mac_event_disconnected(priv);
+
+ lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret);
+ return ret;
+}
+
+
+
+
+/***************************************************************************
+ * Initialization
+ */
static struct cfg80211_ops lbs_cfg80211_ops = {
.set_channel = lbs_cfg_set_channel,
+ .scan = lbs_cfg_scan,
+ .connect = lbs_cfg_connect,
+ .disconnect = lbs_cfg_disconnect,
+ .add_key = lbs_cfg_add_key,
+ .del_key = lbs_cfg_del_key,
+ .set_default_key = lbs_cfg_set_default_key,
+ .get_station = lbs_cfg_get_station,
+ .dump_survey = lbs_get_survey,
+ .change_virtual_intf = lbs_change_intf,
+ .join_ibss = lbs_join_ibss,
+ .leave_ibss = lbs_leave_ibss,
};
@@ -142,6 +1900,36 @@ struct wireless_dev *lbs_cfg_alloc(struct device *dev)
}
+static void lbs_cfg_set_regulatory_hint(struct lbs_private *priv)
+{
+ struct region_code_mapping {
+ const char *cn;
+ int code;
+ };
+
+ /* Section 5.17.2 */
+ static struct region_code_mapping regmap[] = {
+ {"US ", 0x10}, /* US FCC */
+ {"CA ", 0x20}, /* Canada */
+ {"EU ", 0x30}, /* ETSI */
+ {"ES ", 0x31}, /* Spain */
+ {"FR ", 0x32}, /* France */
+ {"JP ", 0x40}, /* Japan */
+ };
+ size_t i;
+
+ lbs_deb_enter(LBS_DEB_CFG80211);
+
+ for (i = 0; i < ARRAY_SIZE(regmap); i++)
+ if (regmap[i].code == priv->regioncode) {
+ regulatory_hint(priv->wdev->wiphy, regmap[i].cn);
+ break;
+ }
+
+ lbs_deb_leave(LBS_DEB_CFG80211);
+}
+
+
/*
* This function get's called after lbs_setup_firmware() determined the
* firmware capabities. So we can setup the wiphy according to our
@@ -157,10 +1945,12 @@ int lbs_cfg_register(struct lbs_private *priv)
wdev->wiphy->max_scan_ssids = 1;
wdev->wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
- /* TODO: BIT(NL80211_IFTYPE_ADHOC); */
- wdev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION);
+ wdev->wiphy->interface_modes =
+ BIT(NL80211_IFTYPE_STATION) |
+ BIT(NL80211_IFTYPE_ADHOC);
+ if (lbs_rtap_supported(priv))
+ wdev->wiphy->interface_modes |= BIT(NL80211_IFTYPE_MONITOR);
- /* TODO: honor priv->regioncode */
wdev->wiphy->bands[IEEE80211_BAND_2GHZ] = &lbs_band_2ghz;
/*
@@ -169,6 +1959,7 @@ int lbs_cfg_register(struct lbs_private *priv)
*/
wdev->wiphy->cipher_suites = cipher_suites;
wdev->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
+ wdev->wiphy->reg_notifier = lbs_reg_notifier;
ret = wiphy_register(wdev->wiphy);
if (ret < 0)
@@ -180,10 +1971,36 @@ int lbs_cfg_register(struct lbs_private *priv)
if (ret)
lbs_pr_err("cannot register network device\n");
+ INIT_DELAYED_WORK(&priv->scan_work, lbs_scan_worker);
+
+ lbs_cfg_set_regulatory_hint(priv);
+
lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret);
return ret;
}
+int lbs_reg_notifier(struct wiphy *wiphy,
+ struct regulatory_request *request)
+{
+ struct lbs_private *priv = wiphy_priv(wiphy);
+ int ret;
+
+ lbs_deb_enter_args(LBS_DEB_CFG80211, "cfg80211 regulatory domain "
+ "callback for domain %c%c\n", request->alpha2[0],
+ request->alpha2[1]);
+
+ ret = lbs_set_11d_domain_info(priv, request, wiphy->bands);
+
+ lbs_deb_leave(LBS_DEB_CFG80211);
+ return ret;
+}
+
+void lbs_scan_deinit(struct lbs_private *priv)
+{
+ lbs_deb_enter(LBS_DEB_CFG80211);
+ cancel_delayed_work_sync(&priv->scan_work);
+}
+
void lbs_cfg_free(struct lbs_private *priv)
{
diff --git a/drivers/net/wireless/libertas/cfg.h b/drivers/net/wireless/libertas/cfg.h
index e09a193a34d..4f46bb744be 100644
--- a/drivers/net/wireless/libertas/cfg.h
+++ b/drivers/net/wireless/libertas/cfg.h
@@ -1,16 +1,21 @@
#ifndef __LBS_CFG80211_H__
#define __LBS_CFG80211_H__
-#include "dev.h"
+struct device;
+struct lbs_private;
+struct regulatory_request;
+struct wiphy;
struct wireless_dev *lbs_cfg_alloc(struct device *dev);
int lbs_cfg_register(struct lbs_private *priv);
void lbs_cfg_free(struct lbs_private *priv);
-int lbs_send_specific_ssid_scan(struct lbs_private *priv, u8 *ssid,
- u8 ssid_len);
-int lbs_scan_networks(struct lbs_private *priv, int full_scan);
-void lbs_cfg_scan_worker(struct work_struct *work);
+int lbs_reg_notifier(struct wiphy *wiphy,
+ struct regulatory_request *request);
+void lbs_send_disconnect_notification(struct lbs_private *priv);
+void lbs_send_mic_failureevent(struct lbs_private *priv, u32 event);
+
+void lbs_scan_deinit(struct lbs_private *priv);
#endif
diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c
index cdb9b9650d7..70745928f3f 100644
--- a/drivers/net/wireless/libertas/cmd.c
+++ b/drivers/net/wireless/libertas/cmd.c
@@ -6,18 +6,14 @@
#include <linux/kfifo.h>
#include <linux/sched.h>
#include <linux/slab.h>
+#include <linux/if_arp.h>
-#include "host.h"
#include "decl.h"
-#include "defs.h"
-#include "dev.h"
-#include "assoc.h"
-#include "wext.h"
-#include "scan.h"
+#include "cfg.h"
#include "cmd.h"
-
-static struct cmd_ctrl_node *lbs_get_cmd_ctrl_node(struct lbs_private *priv);
+#define CAL_NF(nf) ((s32)(-(s32)(nf)))
+#define CAL_RSSI(snr, nf) ((s32)((s32)(snr) + CAL_NF(nf)))
/**
* @brief Simple callback that copies response back into command
@@ -70,6 +66,8 @@ static u8 is_command_allowed_in_ps(u16 cmd)
switch (cmd) {
case CMD_802_11_RSSI:
return 1;
+ case CMD_802_11_HOST_SLEEP_CFG:
+ return 1;
default:
break;
}
@@ -77,30 +75,6 @@ static u8 is_command_allowed_in_ps(u16 cmd)
}
/**
- * @brief This function checks if the command is allowed.
- *
- * @param priv A pointer to lbs_private structure
- * @return allowed or not allowed.
- */
-
-static int lbs_is_cmd_allowed(struct lbs_private *priv)
-{
- int ret = 1;
-
- lbs_deb_enter(LBS_DEB_CMD);
-
- if (!priv->is_auto_deep_sleep_enabled) {
- if (priv->is_deep_sleep) {
- lbs_deb_cmd("command not allowed in deep sleep\n");
- ret = 0;
- }
- }
-
- lbs_deb_leave(LBS_DEB_CMD);
- return ret;
-}
-
-/**
* @brief Updates the hardware details like MAC address and regulatory region
*
* @param priv A pointer to struct lbs_private structure
@@ -175,16 +149,28 @@ int lbs_update_hw_spec(struct lbs_private *priv)
if (priv->mesh_dev)
memcpy(priv->mesh_dev->dev_addr, priv->current_addr, ETH_ALEN);
- if (lbs_set_regiontable(priv, priv->regioncode, 0)) {
- ret = -1;
- goto out;
- }
-
out:
lbs_deb_leave(LBS_DEB_CMD);
return ret;
}
+static int lbs_ret_host_sleep_cfg(struct lbs_private *priv, unsigned long dummy,
+ struct cmd_header *resp)
+{
+ lbs_deb_enter(LBS_DEB_CMD);
+ if (priv->is_host_sleep_activated) {
+ priv->is_host_sleep_configured = 0;
+ if (priv->psstate == PS_STATE_FULL_POWER) {
+ priv->is_host_sleep_activated = 0;
+ wake_up_interruptible(&priv->host_sleep_q);
+ }
+ } else {
+ priv->is_host_sleep_configured = 1;
+ }
+ lbs_deb_leave(LBS_DEB_CMD);
+ return 0;
+}
+
int lbs_host_sleep_cfg(struct lbs_private *priv, uint32_t criteria,
struct wol_config *p_wol_config)
{
@@ -202,12 +188,11 @@ int lbs_host_sleep_cfg(struct lbs_private *priv, uint32_t criteria,
else
cmd_config.wol_conf.action = CMD_ACT_ACTION_NONE;
- ret = lbs_cmd_with_response(priv, CMD_802_11_HOST_SLEEP_CFG, &cmd_config);
+ ret = __lbs_cmd(priv, CMD_802_11_HOST_SLEEP_CFG, &cmd_config.hdr,
+ le16_to_cpu(cmd_config.hdr.size),
+ lbs_ret_host_sleep_cfg, 0);
if (!ret) {
- if (criteria) {
- lbs_deb_cmd("Set WOL criteria to %x\n", criteria);
- priv->wol_criteria = criteria;
- } else
+ if (p_wol_config)
memcpy((uint8_t *) p_wol_config,
(uint8_t *)&cmd_config.wol_conf,
sizeof(struct wol_config));
@@ -219,42 +204,49 @@ int lbs_host_sleep_cfg(struct lbs_private *priv, uint32_t criteria,
}
EXPORT_SYMBOL_GPL(lbs_host_sleep_cfg);
-static int lbs_cmd_802_11_ps_mode(struct cmd_ds_command *cmd,
- u16 cmd_action)
+/**
+ * @brief Sets the Power Save mode
+ *
+ * @param priv A pointer to struct lbs_private structure
+ * @param cmd_action The Power Save operation (PS_MODE_ACTION_ENTER_PS or
+ * PS_MODE_ACTION_EXIT_PS)
+ * @param block Whether to block on a response or not
+ *
+ * @return 0 on success, error on failure
+ */
+int lbs_set_ps_mode(struct lbs_private *priv, u16 cmd_action, bool block)
{
- struct cmd_ds_802_11_ps_mode *psm = &cmd->params.psmode;
+ struct cmd_ds_802_11_ps_mode cmd;
+ int ret = 0;
lbs_deb_enter(LBS_DEB_CMD);
- cmd->command = cpu_to_le16(CMD_802_11_PS_MODE);
- cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_ps_mode) +
- sizeof(struct cmd_header));
- psm->action = cpu_to_le16(cmd_action);
- psm->multipledtim = 0;
- switch (cmd_action) {
- case CMD_SUBCMD_ENTER_PS:
- lbs_deb_cmd("PS command:" "SubCode- Enter PS\n");
-
- psm->locallisteninterval = 0;
- psm->nullpktinterval = 0;
- psm->multipledtim =
- cpu_to_le16(MRVDRV_DEFAULT_MULTIPLE_DTIM);
- break;
-
- case CMD_SUBCMD_EXIT_PS:
- lbs_deb_cmd("PS command:" "SubCode- Exit PS\n");
- break;
-
- case CMD_SUBCMD_SLEEP_CONFIRMED:
- lbs_deb_cmd("PS command: SubCode- sleep confirm\n");
- break;
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.hdr.size = cpu_to_le16(sizeof(cmd));
+ cmd.action = cpu_to_le16(cmd_action);
- default:
- break;
+ if (cmd_action == PS_MODE_ACTION_ENTER_PS) {
+ lbs_deb_cmd("PS_MODE: action ENTER_PS\n");
+ cmd.multipledtim = cpu_to_le16(1); /* Default DTIM multiple */
+ } else if (cmd_action == PS_MODE_ACTION_EXIT_PS) {
+ lbs_deb_cmd("PS_MODE: action EXIT_PS\n");
+ } else {
+ /* We don't handle CONFIRM_SLEEP here because it needs to
+ * be fastpathed to the firmware.
+ */
+ lbs_deb_cmd("PS_MODE: unknown action 0x%X\n", cmd_action);
+ ret = -EOPNOTSUPP;
+ goto out;
}
- lbs_deb_leave(LBS_DEB_CMD);
- return 0;
+ if (block)
+ ret = lbs_cmd_with_response(priv, CMD_802_11_PS_MODE, &cmd);
+ else
+ lbs_cmd_async(priv, CMD_802_11_PS_MODE, &cmd.hdr, sizeof (cmd));
+
+out:
+ lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
+ return ret;
}
int lbs_cmd_802_11_sleep_params(struct lbs_private *priv, uint16_t cmd_action,
@@ -353,6 +345,65 @@ int lbs_set_deep_sleep(struct lbs_private *priv, int deep_sleep)
return ret;
}
+static int lbs_ret_host_sleep_activate(struct lbs_private *priv,
+ unsigned long dummy,
+ struct cmd_header *cmd)
+{
+ lbs_deb_enter(LBS_DEB_FW);
+ priv->is_host_sleep_activated = 1;
+ wake_up_interruptible(&priv->host_sleep_q);
+ lbs_deb_leave(LBS_DEB_FW);
+ return 0;
+}
+
+int lbs_set_host_sleep(struct lbs_private *priv, int host_sleep)
+{
+ struct cmd_header cmd;
+ int ret = 0;
+ uint32_t criteria = EHS_REMOVE_WAKEUP;
+
+ lbs_deb_enter(LBS_DEB_CMD);
+
+ if (host_sleep) {
+ if (priv->is_host_sleep_activated != 1) {
+ memset(&cmd, 0, sizeof(cmd));
+ ret = lbs_host_sleep_cfg(priv, priv->wol_criteria,
+ (struct wol_config *)NULL);
+ if (ret) {
+ lbs_pr_info("Host sleep configuration failed: "
+ "%d\n", ret);
+ return ret;
+ }
+ if (priv->psstate == PS_STATE_FULL_POWER) {
+ ret = __lbs_cmd(priv,
+ CMD_802_11_HOST_SLEEP_ACTIVATE,
+ &cmd,
+ sizeof(cmd),
+ lbs_ret_host_sleep_activate, 0);
+ if (ret)
+ lbs_pr_info("HOST_SLEEP_ACTIVATE "
+ "failed: %d\n", ret);
+ }
+
+ if (!wait_event_interruptible_timeout(
+ priv->host_sleep_q,
+ priv->is_host_sleep_activated,
+ (10 * HZ))) {
+ lbs_pr_err("host_sleep_q: timer expired\n");
+ ret = -1;
+ }
+ } else {
+ lbs_pr_err("host sleep: already enabled\n");
+ }
+ } else {
+ if (priv->is_host_sleep_activated)
+ ret = lbs_host_sleep_cfg(priv, criteria,
+ (struct wol_config *)NULL);
+ }
+
+ return ret;
+}
+
/**
* @brief Set an SNMP MIB value
*
@@ -509,23 +560,35 @@ int lbs_set_tx_power(struct lbs_private *priv, s16 dbm)
return ret;
}
-static int lbs_cmd_802_11_monitor_mode(struct cmd_ds_command *cmd,
- u16 cmd_action, void *pdata_buf)
+/**
+ * @brief Enable or disable monitor mode (only implemented on OLPC usb8388 FW)
+ *
+ * @param priv A pointer to struct lbs_private structure
+ * @param enable 1 to enable monitor mode, 0 to disable
+ *
+ * @return 0 on success, error on failure
+ */
+int lbs_set_monitor_mode(struct lbs_private *priv, int enable)
{
- struct cmd_ds_802_11_monitor_mode *monitor = &cmd->params.monitor;
+ struct cmd_ds_802_11_monitor_mode cmd;
+ int ret;
+
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.hdr.size = cpu_to_le16(sizeof(cmd));
+ cmd.action = cpu_to_le16(CMD_ACT_SET);
+ if (enable)
+ cmd.mode = cpu_to_le16(0x1);
- cmd->command = cpu_to_le16(CMD_802_11_MONITOR_MODE);
- cmd->size =
- cpu_to_le16(sizeof(struct cmd_ds_802_11_monitor_mode) +
- sizeof(struct cmd_header));
+ lbs_deb_cmd("SET_MONITOR_MODE: %d\n", enable);
- monitor->action = cpu_to_le16(cmd_action);
- if (cmd_action == CMD_ACT_SET) {
- monitor->mode =
- cpu_to_le16((u16) (*(u32 *) pdata_buf));
+ ret = lbs_cmd_with_response(priv, CMD_802_11_MONITOR_MODE, &cmd);
+ if (ret == 0) {
+ priv->dev->type = enable ? ARPHRD_IEEE80211_RADIOTAP :
+ ARPHRD_ETHER;
}
- return 0;
+ lbs_deb_leave(LBS_DEB_CMD);
+ return ret;
}
/**
@@ -610,78 +673,242 @@ out:
return ret;
}
-static int lbs_cmd_reg_access(struct cmd_ds_command *cmdptr,
- u8 cmd_action, void *pdata_buf)
+/**
+ * @brief Get current RSSI and noise floor
+ *
+ * @param priv A pointer to struct lbs_private structure
+ * @param rssi On successful return, signal level in mBm
+ *
+ * @return The channel on success, error on failure
+ */
+int lbs_get_rssi(struct lbs_private *priv, s8 *rssi, s8 *nf)
{
- struct lbs_offset_value *offval;
+ struct cmd_ds_802_11_rssi cmd;
+ int ret = 0;
lbs_deb_enter(LBS_DEB_CMD);
- offval = (struct lbs_offset_value *)pdata_buf;
+ BUG_ON(rssi == NULL);
+ BUG_ON(nf == NULL);
- switch (le16_to_cpu(cmdptr->command)) {
- case CMD_MAC_REG_ACCESS:
- {
- struct cmd_ds_mac_reg_access *macreg;
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.hdr.size = cpu_to_le16(sizeof(cmd));
+ /* Average SNR over last 8 beacons */
+ cmd.n_or_snr = cpu_to_le16(8);
- cmdptr->size =
- cpu_to_le16(sizeof (struct cmd_ds_mac_reg_access)
- + sizeof(struct cmd_header));
- macreg =
- (struct cmd_ds_mac_reg_access *)&cmdptr->params.
- macreg;
+ ret = lbs_cmd_with_response(priv, CMD_802_11_RSSI, &cmd);
+ if (ret == 0) {
+ *nf = CAL_NF(le16_to_cpu(cmd.nf));
+ *rssi = CAL_RSSI(le16_to_cpu(cmd.n_or_snr), le16_to_cpu(cmd.nf));
+ }
- macreg->action = cpu_to_le16(cmd_action);
- macreg->offset = cpu_to_le16((u16) offval->offset);
- macreg->value = cpu_to_le32(offval->value);
+ lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
+ return ret;
+}
- break;
- }
+/**
+ * @brief Send regulatory and 802.11d domain information to the firmware
+ *
+ * @param priv pointer to struct lbs_private
+ * @param request cfg80211 regulatory request structure
+ * @param bands the device's supported bands and channels
+ *
+ * @return 0 on success, error code on failure
+*/
+int lbs_set_11d_domain_info(struct lbs_private *priv,
+ struct regulatory_request *request,
+ struct ieee80211_supported_band **bands)
+{
+ struct cmd_ds_802_11d_domain_info cmd;
+ struct mrvl_ie_domain_param_set *domain = &cmd.domain;
+ struct ieee80211_country_ie_triplet *t;
+ enum ieee80211_band band;
+ struct ieee80211_channel *ch;
+ u8 num_triplet = 0;
+ u8 num_parsed_chan = 0;
+ u8 first_channel = 0, next_chan = 0, max_pwr = 0;
+ u8 i, flag = 0;
+ size_t triplet_size;
+ int ret;
- case CMD_BBP_REG_ACCESS:
- {
- struct cmd_ds_bbp_reg_access *bbpreg;
+ lbs_deb_enter(LBS_DEB_11D);
- cmdptr->size =
- cpu_to_le16(sizeof
- (struct cmd_ds_bbp_reg_access)
- + sizeof(struct cmd_header));
- bbpreg =
- (struct cmd_ds_bbp_reg_access *)&cmdptr->params.
- bbpreg;
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.action = cpu_to_le16(CMD_ACT_SET);
- bbpreg->action = cpu_to_le16(cmd_action);
- bbpreg->offset = cpu_to_le16((u16) offval->offset);
- bbpreg->value = (u8) offval->value;
+ lbs_deb_11d("Setting country code '%c%c'\n",
+ request->alpha2[0], request->alpha2[1]);
- break;
- }
+ domain->header.type = cpu_to_le16(TLV_TYPE_DOMAIN);
- case CMD_RF_REG_ACCESS:
- {
- struct cmd_ds_rf_reg_access *rfreg;
+ /* Set country code */
+ domain->country_code[0] = request->alpha2[0];
+ domain->country_code[1] = request->alpha2[1];
+ domain->country_code[2] = ' ';
- cmdptr->size =
- cpu_to_le16(sizeof
- (struct cmd_ds_rf_reg_access) +
- sizeof(struct cmd_header));
- rfreg =
- (struct cmd_ds_rf_reg_access *)&cmdptr->params.
- rfreg;
+ /* Now set up the channel triplets; firmware is somewhat picky here
+ * and doesn't validate channel numbers and spans; hence it would
+ * interpret a triplet of (36, 4, 20) as channels 36, 37, 38, 39. Since
+ * the last 3 aren't valid channels, the driver is responsible for
+ * splitting that up into 4 triplet pairs of (36, 1, 20) + (40, 1, 20)
+ * etc.
+ */
+ for (band = 0;
+ (band < IEEE80211_NUM_BANDS) && (num_triplet < MAX_11D_TRIPLETS);
+ band++) {
+
+ if (!bands[band])
+ continue;
+
+ for (i = 0;
+ (i < bands[band]->n_channels) && (num_triplet < MAX_11D_TRIPLETS);
+ i++) {
+ ch = &bands[band]->channels[i];
+ if (ch->flags & IEEE80211_CHAN_DISABLED)
+ continue;
+
+ if (!flag) {
+ flag = 1;
+ next_chan = first_channel = (u32) ch->hw_value;
+ max_pwr = ch->max_power;
+ num_parsed_chan = 1;
+ continue;
+ }
- rfreg->action = cpu_to_le16(cmd_action);
- rfreg->offset = cpu_to_le16((u16) offval->offset);
- rfreg->value = (u8) offval->value;
+ if ((ch->hw_value == next_chan + 1) &&
+ (ch->max_power == max_pwr)) {
+ /* Consolidate adjacent channels */
+ next_chan++;
+ num_parsed_chan++;
+ } else {
+ /* Add this triplet */
+ lbs_deb_11d("11D triplet (%d, %d, %d)\n",
+ first_channel, num_parsed_chan,
+ max_pwr);
+ t = &domain->triplet[num_triplet];
+ t->chans.first_channel = first_channel;
+ t->chans.num_channels = num_parsed_chan;
+ t->chans.max_power = max_pwr;
+ num_triplet++;
+ flag = 0;
+ }
+ }
- break;
+ if (flag) {
+ /* Add last triplet */
+ lbs_deb_11d("11D triplet (%d, %d, %d)\n", first_channel,
+ num_parsed_chan, max_pwr);
+ t = &domain->triplet[num_triplet];
+ t->chans.first_channel = first_channel;
+ t->chans.num_channels = num_parsed_chan;
+ t->chans.max_power = max_pwr;
+ num_triplet++;
}
+ }
- default:
- break;
+ lbs_deb_11d("# triplets %d\n", num_triplet);
+
+ /* Set command header sizes */
+ triplet_size = num_triplet * sizeof(struct ieee80211_country_ie_triplet);
+ domain->header.len = cpu_to_le16(sizeof(domain->country_code) +
+ triplet_size);
+
+ lbs_deb_hex(LBS_DEB_11D, "802.11D domain param set",
+ (u8 *) &cmd.domain.country_code,
+ le16_to_cpu(domain->header.len));
+
+ cmd.hdr.size = cpu_to_le16(sizeof(cmd.hdr) +
+ sizeof(cmd.action) +
+ sizeof(cmd.domain.header) +
+ sizeof(cmd.domain.country_code) +
+ triplet_size);
+
+ ret = lbs_cmd_with_response(priv, CMD_802_11D_DOMAIN_INFO, &cmd);
+
+ lbs_deb_leave_args(LBS_DEB_11D, "ret %d", ret);
+ return ret;
+}
+
+/**
+ * @brief Read a MAC, Baseband, or RF register
+ *
+ * @param priv pointer to struct lbs_private
+ * @param cmd register command, one of CMD_MAC_REG_ACCESS,
+ * CMD_BBP_REG_ACCESS, or CMD_RF_REG_ACCESS
+ * @param offset byte offset of the register to get
+ * @param value on success, the value of the register at 'offset'
+ *
+ * @return 0 on success, error code on failure
+*/
+int lbs_get_reg(struct lbs_private *priv, u16 reg, u16 offset, u32 *value)
+{
+ struct cmd_ds_reg_access cmd;
+ int ret = 0;
+
+ lbs_deb_enter(LBS_DEB_CMD);
+
+ BUG_ON(value == NULL);
+
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.hdr.size = cpu_to_le16(sizeof(cmd));
+ cmd.action = cpu_to_le16(CMD_ACT_GET);
+
+ if (reg != CMD_MAC_REG_ACCESS &&
+ reg != CMD_BBP_REG_ACCESS &&
+ reg != CMD_RF_REG_ACCESS) {
+ ret = -EINVAL;
+ goto out;
}
- lbs_deb_leave(LBS_DEB_CMD);
- return 0;
+ ret = lbs_cmd_with_response(priv, reg, &cmd);
+ if (ret) {
+ if (reg == CMD_BBP_REG_ACCESS || reg == CMD_RF_REG_ACCESS)
+ *value = cmd.value.bbp_rf;
+ else if (reg == CMD_MAC_REG_ACCESS)
+ *value = le32_to_cpu(cmd.value.mac);
+ }
+
+out:
+ lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
+ return ret;
+}
+
+/**
+ * @brief Write a MAC, Baseband, or RF register
+ *
+ * @param priv pointer to struct lbs_private
+ * @param cmd register command, one of CMD_MAC_REG_ACCESS,
+ * CMD_BBP_REG_ACCESS, or CMD_RF_REG_ACCESS
+ * @param offset byte offset of the register to set
+ * @param value the value to write to the register at 'offset'
+ *
+ * @return 0 on success, error code on failure
+*/
+int lbs_set_reg(struct lbs_private *priv, u16 reg, u16 offset, u32 value)
+{
+ struct cmd_ds_reg_access cmd;
+ int ret = 0;
+
+ lbs_deb_enter(LBS_DEB_CMD);
+
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.hdr.size = cpu_to_le16(sizeof(cmd));
+ cmd.action = cpu_to_le16(CMD_ACT_SET);
+
+ if (reg == CMD_BBP_REG_ACCESS || reg == CMD_RF_REG_ACCESS)
+ cmd.value.bbp_rf = (u8) (value & 0xFF);
+ else if (reg == CMD_MAC_REG_ACCESS)
+ cmd.value.mac = cpu_to_le32(value);
+ else {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ ret = lbs_cmd_with_response(priv, reg, &cmd);
+
+out:
+ lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
+ return ret;
}
static void lbs_queue_cmd(struct lbs_private *priv,
@@ -704,14 +931,17 @@ static void lbs_queue_cmd(struct lbs_private *priv,
/* Exit_PS command needs to be queued in the header always. */
if (le16_to_cpu(cmdnode->cmdbuf->command) == CMD_802_11_PS_MODE) {
- struct cmd_ds_802_11_ps_mode *psm = (void *) &cmdnode->cmdbuf[1];
+ struct cmd_ds_802_11_ps_mode *psm = (void *) &cmdnode->cmdbuf;
- if (psm->action == cpu_to_le16(CMD_SUBCMD_EXIT_PS)) {
+ if (psm->action == cpu_to_le16(PS_MODE_ACTION_EXIT_PS)) {
if (priv->psstate != PS_STATE_FULL_POWER)
addtail = 0;
}
}
+ if (le16_to_cpu(cmdnode->cmdbuf->command) == CMD_802_11_WAKEUP_CONFIRM)
+ addtail = 0;
+
spin_lock_irqsave(&priv->driver_lock, flags);
if (addtail)
@@ -744,7 +974,6 @@ static void lbs_submit_command(struct lbs_private *priv,
spin_lock_irqsave(&priv->driver_lock, flags);
priv->cur_cmd = cmdnode;
- priv->cur_cmd_retcode = 0;
spin_unlock_irqrestore(&priv->driver_lock, flags);
cmdsize = le16_to_cpu(cmd->size);
@@ -817,9 +1046,6 @@ static void lbs_cleanup_and_insert_cmd(struct lbs_private *priv,
void lbs_complete_command(struct lbs_private *priv, struct cmd_ctrl_node *cmd,
int result)
{
- if (cmd == priv->cur_cmd)
- priv->cur_cmd_retcode = result;
-
cmd->result = result;
cmd->cmdwaitqwoken = 1;
wake_up_interruptible(&cmd->cmdwait_q);
@@ -887,175 +1113,6 @@ void lbs_set_mac_control(struct lbs_private *priv)
}
/**
- * @brief This function prepare the command before send to firmware.
- *
- * @param priv A pointer to struct lbs_private structure
- * @param cmd_no command number
- * @param cmd_action command action: GET or SET
- * @param wait_option wait option: wait response or not
- * @param cmd_oid cmd oid: treated as sub command
- * @param pdata_buf A pointer to informaion buffer
- * @return 0 or -1
- */
-int lbs_prepare_and_send_command(struct lbs_private *priv,
- u16 cmd_no,
- u16 cmd_action,
- u16 wait_option, u32 cmd_oid, void *pdata_buf)
-{
- int ret = 0;
- struct cmd_ctrl_node *cmdnode;
- struct cmd_ds_command *cmdptr;
- unsigned long flags;
-
- lbs_deb_enter(LBS_DEB_HOST);
-
- if (!priv) {
- lbs_deb_host("PREP_CMD: priv is NULL\n");
- ret = -1;
- goto done;
- }
-
- if (priv->surpriseremoved) {
- lbs_deb_host("PREP_CMD: card removed\n");
- ret = -1;
- goto done;
- }
-
- if (!lbs_is_cmd_allowed(priv)) {
- ret = -EBUSY;
- goto done;
- }
-
- cmdnode = lbs_get_cmd_ctrl_node(priv);
-
- if (cmdnode == NULL) {
- lbs_deb_host("PREP_CMD: cmdnode is NULL\n");
-
- /* Wake up main thread to execute next command */
- wake_up_interruptible(&priv->waitq);
- ret = -1;
- goto done;
- }
-
- cmdnode->callback = NULL;
- cmdnode->callback_arg = (unsigned long)pdata_buf;
-
- cmdptr = (struct cmd_ds_command *)cmdnode->cmdbuf;
-
- lbs_deb_host("PREP_CMD: command 0x%04x\n", cmd_no);
-
- /* Set sequence number, command and INT option */
- priv->seqnum++;
- cmdptr->seqnum = cpu_to_le16(priv->seqnum);
-
- cmdptr->command = cpu_to_le16(cmd_no);
- cmdptr->result = 0;
-
- switch (cmd_no) {
- case CMD_802_11_PS_MODE:
- ret = lbs_cmd_802_11_ps_mode(cmdptr, cmd_action);
- break;
-
- case CMD_MAC_REG_ACCESS:
- case CMD_BBP_REG_ACCESS:
- case CMD_RF_REG_ACCESS:
- ret = lbs_cmd_reg_access(cmdptr, cmd_action, pdata_buf);
- break;
-
- case CMD_802_11_MONITOR_MODE:
- ret = lbs_cmd_802_11_monitor_mode(cmdptr,
- cmd_action, pdata_buf);
- break;
-
- case CMD_802_11_RSSI:
- ret = lbs_cmd_802_11_rssi(priv, cmdptr);
- break;
-
- case CMD_802_11_SET_AFC:
- case CMD_802_11_GET_AFC:
-
- cmdptr->command = cpu_to_le16(cmd_no);
- cmdptr->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_afc) +
- sizeof(struct cmd_header));
-
- memmove(&cmdptr->params.afc,
- pdata_buf, sizeof(struct cmd_ds_802_11_afc));
-
- ret = 0;
- goto done;
-
- case CMD_802_11_TPC_CFG:
- cmdptr->command = cpu_to_le16(CMD_802_11_TPC_CFG);
- cmdptr->size =
- cpu_to_le16(sizeof(struct cmd_ds_802_11_tpc_cfg) +
- sizeof(struct cmd_header));
-
- memmove(&cmdptr->params.tpccfg,
- pdata_buf, sizeof(struct cmd_ds_802_11_tpc_cfg));
-
- ret = 0;
- break;
-
-#ifdef CONFIG_LIBERTAS_MESH
-
- case CMD_BT_ACCESS:
- ret = lbs_cmd_bt_access(cmdptr, cmd_action, pdata_buf);
- break;
-
- case CMD_FWT_ACCESS:
- ret = lbs_cmd_fwt_access(cmdptr, cmd_action, pdata_buf);
- break;
-
-#endif
-
- case CMD_802_11_BEACON_CTRL:
- ret = lbs_cmd_bcn_ctrl(priv, cmdptr, cmd_action);
- break;
- case CMD_802_11_DEEP_SLEEP:
- cmdptr->command = cpu_to_le16(CMD_802_11_DEEP_SLEEP);
- cmdptr->size = cpu_to_le16(sizeof(struct cmd_header));
- break;
- default:
- lbs_pr_err("PREP_CMD: unknown command 0x%04x\n", cmd_no);
- ret = -1;
- break;
- }
-
- /* return error, since the command preparation failed */
- if (ret != 0) {
- lbs_deb_host("PREP_CMD: command preparation failed\n");
- lbs_cleanup_and_insert_cmd(priv, cmdnode);
- ret = -1;
- goto done;
- }
-
- cmdnode->cmdwaitqwoken = 0;
-
- lbs_queue_cmd(priv, cmdnode);
- wake_up_interruptible(&priv->waitq);
-
- if (wait_option & CMD_OPTION_WAITFORRSP) {
- lbs_deb_host("PREP_CMD: wait for response\n");
- might_sleep();
- wait_event_interruptible(cmdnode->cmdwait_q,
- cmdnode->cmdwaitqwoken);
- }
-
- spin_lock_irqsave(&priv->driver_lock, flags);
- if (priv->cur_cmd_retcode) {
- lbs_deb_host("PREP_CMD: command failed with return code %d\n",
- priv->cur_cmd_retcode);
- priv->cur_cmd_retcode = 0;
- ret = -1;
- }
- spin_unlock_irqrestore(&priv->driver_lock, flags);
-
-done:
- lbs_deb_leave_args(LBS_DEB_HOST, "ret %d", ret);
- return ret;
-}
-
-/**
* @brief This function allocates the command buffer and link
* it to command free queue.
*
@@ -1148,7 +1205,7 @@ done:
* @param priv A pointer to struct lbs_private structure
* @return cmd_ctrl_node A pointer to cmd_ctrl_node structure or NULL
*/
-static struct cmd_ctrl_node *lbs_get_cmd_ctrl_node(struct lbs_private *priv)
+static struct cmd_ctrl_node *lbs_get_free_cmd_node(struct lbs_private *priv)
{
struct cmd_ctrl_node *tempnode;
unsigned long flags;
@@ -1231,10 +1288,10 @@ int lbs_execute_next_command(struct lbs_private *priv)
/*
* 1. Non-PS command:
* Queue it. set needtowakeup to TRUE if current state
- * is SLEEP, otherwise call lbs_ps_wakeup to send Exit_PS.
- * 2. PS command but not Exit_PS:
+ * is SLEEP, otherwise call send EXIT_PS.
+ * 2. PS command but not EXIT_PS:
* Ignore it.
- * 3. PS command Exit_PS:
+ * 3. PS command EXIT_PS:
* Set needtowakeup to TRUE if current state is SLEEP,
* otherwise send this command down to firmware
* immediately.
@@ -1248,8 +1305,11 @@ int lbs_execute_next_command(struct lbs_private *priv)
/* w/ new scheme, it will not reach here.
since it is blocked in main_thread. */
priv->needtowakeup = 1;
- } else
- lbs_ps_wakeup(priv, 0);
+ } else {
+ lbs_set_ps_mode(priv,
+ PS_MODE_ACTION_EXIT_PS,
+ false);
+ }
ret = 0;
goto done;
@@ -1264,7 +1324,7 @@ int lbs_execute_next_command(struct lbs_private *priv)
"EXEC_NEXT_CMD: PS cmd, action 0x%02x\n",
psm->action);
if (psm->action !=
- cpu_to_le16(CMD_SUBCMD_EXIT_PS)) {
+ cpu_to_le16(PS_MODE_ACTION_EXIT_PS)) {
lbs_deb_host(
"EXEC_NEXT_CMD: ignore ENTER_PS cmd\n");
list_del(&cmdnode->list);
@@ -1303,6 +1363,15 @@ int lbs_execute_next_command(struct lbs_private *priv)
* check if in power save mode, if yes, put the device back
* to PS mode
*/
+#ifdef TODO
+ /*
+ * This was the old code for libertas+wext. Someone that
+ * understands this beast should re-code it in a sane way.
+ *
+ * I actually don't understand why this is related to WPA
+ * and to connection status, shouldn't powering should be
+ * independ of such things?
+ */
if ((priv->psmode != LBS802_11POWERMODECAM) &&
(priv->psstate == PS_STATE_FULL_POWER) &&
((priv->connect_status == LBS_CONNECTED) ||
@@ -1315,15 +1384,19 @@ int lbs_execute_next_command(struct lbs_private *priv)
lbs_deb_host(
"EXEC_NEXT_CMD: WPA enabled and GTK_SET"
" go back to PS_SLEEP");
- lbs_ps_sleep(priv, 0);
+ lbs_set_ps_mode(priv,
+ PS_MODE_ACTION_ENTER_PS,
+ false);
}
} else {
lbs_deb_host(
"EXEC_NEXT_CMD: cmdpendingq empty, "
"go back to PS_SLEEP");
- lbs_ps_sleep(priv, 0);
+ lbs_set_ps_mode(priv, PS_MODE_ACTION_ENTER_PS,
+ false);
}
}
+#endif
}
ret = 0;
@@ -1353,6 +1426,11 @@ static void lbs_send_confirmsleep(struct lbs_private *priv)
/* We don't get a response on the sleep-confirmation */
priv->dnld_sent = DNLD_RES_RECEIVED;
+ if (priv->is_host_sleep_configured) {
+ priv->is_host_sleep_activated = 1;
+ wake_up_interruptible(&priv->host_sleep_q);
+ }
+
/* If nothing to do, go back to sleep (?) */
if (!kfifo_len(&priv->event_fifo) && !priv->resp_len[priv->resp_idx])
priv->psstate = PS_STATE_SLEEP;
@@ -1363,43 +1441,6 @@ out:
lbs_deb_leave(LBS_DEB_HOST);
}
-void lbs_ps_sleep(struct lbs_private *priv, int wait_option)
-{
- lbs_deb_enter(LBS_DEB_HOST);
-
- /*
- * PS is currently supported only in Infrastructure mode
- * Remove this check if it is to be supported in IBSS mode also
- */
-
- lbs_prepare_and_send_command(priv, CMD_802_11_PS_MODE,
- CMD_SUBCMD_ENTER_PS, wait_option, 0, NULL);
-
- lbs_deb_leave(LBS_DEB_HOST);
-}
-
-/**
- * @brief This function sends Exit_PS command to firmware.
- *
- * @param priv A pointer to struct lbs_private structure
- * @param wait_option wait response or not
- * @return n/a
- */
-void lbs_ps_wakeup(struct lbs_private *priv, int wait_option)
-{
- __le32 Localpsmode;
-
- lbs_deb_enter(LBS_DEB_HOST);
-
- Localpsmode = cpu_to_le32(LBS802_11POWERMODECAM);
-
- lbs_prepare_and_send_command(priv, CMD_802_11_PS_MODE,
- CMD_SUBCMD_EXIT_PS,
- wait_option, 0, &Localpsmode);
-
- lbs_deb_leave(LBS_DEB_HOST);
-}
-
/**
* @brief This function checks condition and prepares to
* send sleep confirm command to firmware if ok.
@@ -1524,12 +1565,18 @@ struct cmd_ctrl_node *__lbs_cmd_async(struct lbs_private *priv,
goto done;
}
- if (!lbs_is_cmd_allowed(priv)) {
- cmdnode = ERR_PTR(-EBUSY);
- goto done;
+ /* No commands are allowed in Deep Sleep until we toggle the GPIO
+ * to wake up the card and it has signaled that it's ready.
+ */
+ if (!priv->is_auto_deep_sleep_enabled) {
+ if (priv->is_deep_sleep) {
+ lbs_deb_cmd("command not allowed in deep sleep\n");
+ cmdnode = ERR_PTR(-EBUSY);
+ goto done;
+ }
}
- cmdnode = lbs_get_cmd_ctrl_node(priv);
+ cmdnode = lbs_get_free_cmd_node(priv);
if (cmdnode == NULL) {
lbs_deb_host("PREP_CMD: cmdnode is NULL\n");
diff --git a/drivers/net/wireless/libertas/cmd.h b/drivers/net/wireless/libertas/cmd.h
index cb4138a55fd..7109d6b717e 100644
--- a/drivers/net/wireless/libertas/cmd.h
+++ b/drivers/net/wireless/libertas/cmd.h
@@ -3,6 +3,8 @@
#ifndef _LBS_CMD_H_
#define _LBS_CMD_H_
+#include <net/cfg80211.h>
+
#include "host.h"
#include "dev.h"
@@ -37,11 +39,6 @@ struct cmd_ctrl_node {
#define lbs_cmd_with_response(priv, cmdnr, cmd) \
lbs_cmd(priv, cmdnr, cmd, lbs_cmd_copyback, (unsigned long) (cmd))
-int lbs_prepare_and_send_command(struct lbs_private *priv,
- u16 cmd_no,
- u16 cmd_action,
- u16 wait_option, u32 cmd_oid, void *pdata_buf);
-
void lbs_cmd_async(struct lbs_private *priv, uint16_t command,
struct cmd_header *in_cmd, int in_cmd_size);
@@ -92,10 +89,6 @@ int lbs_host_sleep_cfg(struct lbs_private *priv, uint32_t criteria,
int lbs_cmd_802_11_sleep_params(struct lbs_private *priv, uint16_t cmd_action,
struct sleep_params *sp);
-void lbs_ps_sleep(struct lbs_private *priv, int wait_option);
-
-void lbs_ps_wakeup(struct lbs_private *priv, int wait_option);
-
void lbs_ps_confirm_sleep(struct lbs_private *priv);
int lbs_set_radio(struct lbs_private *priv, u8 preamble, u8 radio_on);
@@ -127,4 +120,20 @@ int lbs_set_tx_power(struct lbs_private *priv, s16 dbm);
int lbs_set_deep_sleep(struct lbs_private *priv, int deep_sleep);
+int lbs_set_host_sleep(struct lbs_private *priv, int host_sleep);
+
+int lbs_set_monitor_mode(struct lbs_private *priv, int enable);
+
+int lbs_get_rssi(struct lbs_private *priv, s8 *snr, s8 *nf);
+
+int lbs_set_11d_domain_info(struct lbs_private *priv,
+ struct regulatory_request *request,
+ struct ieee80211_supported_band **bands);
+
+int lbs_get_reg(struct lbs_private *priv, u16 reg, u16 offset, u32 *value);
+
+int lbs_set_reg(struct lbs_private *priv, u16 reg, u16 offset, u32 value);
+
+int lbs_set_ps_mode(struct lbs_private *priv, u16 cmd_action, bool block);
+
#endif /* _LBS_CMD_H */
diff --git a/drivers/net/wireless/libertas/cmdresp.c b/drivers/net/wireless/libertas/cmdresp.c
index 88f7131d66e..5e95da9dcc2 100644
--- a/drivers/net/wireless/libertas/cmdresp.c
+++ b/drivers/net/wireless/libertas/cmdresp.c
@@ -5,18 +5,11 @@
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/sched.h>
-#include <linux/if_arp.h>
-#include <linux/netdevice.h>
#include <asm/unaligned.h>
-#include <net/iw_handler.h>
+#include <net/cfg80211.h>
-#include "host.h"
-#include "decl.h"
+#include "cfg.h"
#include "cmd.h"
-#include "defs.h"
-#include "dev.h"
-#include "assoc.h"
-#include "wext.h"
/**
* @brief This function handles disconnect event. it
@@ -38,7 +31,9 @@ void lbs_mac_event_disconnected(struct lbs_private *priv)
* It causes problem in the Supplicant
*/
msleep_interruptible(1000);
- lbs_send_disconnect_notification(priv);
+
+ if (priv->wdev->iftype == NL80211_IFTYPE_STATION)
+ lbs_send_disconnect_notification(priv);
/* report disconnect to upper layer */
netif_stop_queue(priv->dev);
@@ -49,141 +44,16 @@ void lbs_mac_event_disconnected(struct lbs_private *priv)
priv->currenttxskb = NULL;
priv->tx_pending_len = 0;
- /* reset SNR/NF/RSSI values */
- memset(priv->SNR, 0x00, sizeof(priv->SNR));
- memset(priv->NF, 0x00, sizeof(priv->NF));
- memset(priv->RSSI, 0x00, sizeof(priv->RSSI));
- memset(priv->rawSNR, 0x00, sizeof(priv->rawSNR));
- memset(priv->rawNF, 0x00, sizeof(priv->rawNF));
- priv->nextSNRNF = 0;
- priv->numSNRNF = 0;
priv->connect_status = LBS_DISCONNECTED;
- /* Clear out associated SSID and BSSID since connection is
- * no longer valid.
- */
- memset(&priv->curbssparams.bssid, 0, ETH_ALEN);
- memset(&priv->curbssparams.ssid, 0, IEEE80211_MAX_SSID_LEN);
- priv->curbssparams.ssid_len = 0;
-
if (priv->psstate != PS_STATE_FULL_POWER) {
/* make firmware to exit PS mode */
lbs_deb_cmd("disconnected, so exit PS mode\n");
- lbs_ps_wakeup(priv, 0);
+ lbs_set_ps_mode(priv, PS_MODE_ACTION_EXIT_PS, false);
}
lbs_deb_leave(LBS_DEB_ASSOC);
}
-static int lbs_ret_reg_access(struct lbs_private *priv,
- u16 type, struct cmd_ds_command *resp)
-{
- int ret = 0;
-
- lbs_deb_enter(LBS_DEB_CMD);
-
- switch (type) {
- case CMD_RET(CMD_MAC_REG_ACCESS):
- {
- struct cmd_ds_mac_reg_access *reg = &resp->params.macreg;
-
- priv->offsetvalue.offset = (u32)le16_to_cpu(reg->offset);
- priv->offsetvalue.value = le32_to_cpu(reg->value);
- break;
- }
-
- case CMD_RET(CMD_BBP_REG_ACCESS):
- {
- struct cmd_ds_bbp_reg_access *reg = &resp->params.bbpreg;
-
- priv->offsetvalue.offset = (u32)le16_to_cpu(reg->offset);
- priv->offsetvalue.value = reg->value;
- break;
- }
-
- case CMD_RET(CMD_RF_REG_ACCESS):
- {
- struct cmd_ds_rf_reg_access *reg = &resp->params.rfreg;
-
- priv->offsetvalue.offset = (u32)le16_to_cpu(reg->offset);
- priv->offsetvalue.value = reg->value;
- break;
- }
-
- default:
- ret = -1;
- }
-
- lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
- return ret;
-}
-
-static inline int handle_cmd_response(struct lbs_private *priv,
- struct cmd_header *cmd_response)
-{
- struct cmd_ds_command *resp = (struct cmd_ds_command *) cmd_response;
- int ret = 0;
- unsigned long flags;
- uint16_t respcmd = le16_to_cpu(resp->command);
-
- lbs_deb_enter(LBS_DEB_HOST);
-
- switch (respcmd) {
- case CMD_RET(CMD_MAC_REG_ACCESS):
- case CMD_RET(CMD_BBP_REG_ACCESS):
- case CMD_RET(CMD_RF_REG_ACCESS):
- ret = lbs_ret_reg_access(priv, respcmd, resp);
- break;
-
- case CMD_RET(CMD_802_11_SET_AFC):
- case CMD_RET(CMD_802_11_GET_AFC):
- spin_lock_irqsave(&priv->driver_lock, flags);
- memmove((void *)priv->cur_cmd->callback_arg, &resp->params.afc,
- sizeof(struct cmd_ds_802_11_afc));
- spin_unlock_irqrestore(&priv->driver_lock, flags);
-
- break;
-
- case CMD_RET(CMD_802_11_BEACON_STOP):
- break;
-
- case CMD_RET(CMD_802_11_RSSI):
- ret = lbs_ret_802_11_rssi(priv, resp);
- break;
-
- case CMD_RET(CMD_802_11_TPC_CFG):
- spin_lock_irqsave(&priv->driver_lock, flags);
- memmove((void *)priv->cur_cmd->callback_arg, &resp->params.tpccfg,
- sizeof(struct cmd_ds_802_11_tpc_cfg));
- spin_unlock_irqrestore(&priv->driver_lock, flags);
- break;
-
- case CMD_RET(CMD_BT_ACCESS):
- spin_lock_irqsave(&priv->driver_lock, flags);
- if (priv->cur_cmd->callback_arg)
- memcpy((void *)priv->cur_cmd->callback_arg,
- &resp->params.bt.addr1, 2 * ETH_ALEN);
- spin_unlock_irqrestore(&priv->driver_lock, flags);
- break;
- case CMD_RET(CMD_FWT_ACCESS):
- spin_lock_irqsave(&priv->driver_lock, flags);
- if (priv->cur_cmd->callback_arg)
- memcpy((void *)priv->cur_cmd->callback_arg, &resp->params.fwt,
- sizeof(resp->params.fwt));
- spin_unlock_irqrestore(&priv->driver_lock, flags);
- break;
- case CMD_RET(CMD_802_11_BEACON_CTRL):
- ret = lbs_ret_802_11_bcn_ctrl(priv, resp);
- break;
-
- default:
- lbs_pr_err("CMD_RESP: unknown cmd response 0x%04x\n",
- le16_to_cpu(resp->command));
- break;
- }
- lbs_deb_leave(LBS_DEB_HOST);
- return ret;
-}
-
int lbs_process_command_response(struct lbs_private *priv, u8 *data, u32 len)
{
uint16_t respcmd, curcmd;
@@ -242,9 +112,6 @@ int lbs_process_command_response(struct lbs_private *priv, u8 *data, u32 len)
del_timer(&priv->command_timer);
priv->cmd_timed_out = 0;
- /* Store the response code to cur_cmd_retcode. */
- priv->cur_cmd_retcode = result;
-
if (respcmd == CMD_RET(CMD_802_11_PS_MODE)) {
struct cmd_ds_802_11_ps_mode *psmode = (void *) &resp[1];
u16 action = le16_to_cpu(psmode->action);
@@ -261,10 +128,10 @@ int lbs_process_command_response(struct lbs_private *priv, u8 *data, u32 len)
* ad-hoc mode. It takes place in
* lbs_execute_next_command().
*/
- if (priv->mode == IW_MODE_ADHOC &&
- action == CMD_SUBCMD_ENTER_PS)
+ if (priv->wdev->iftype == NL80211_IFTYPE_MONITOR &&
+ action == PS_MODE_ACTION_ENTER_PS)
priv->psmode = LBS802_11POWERMODECAM;
- } else if (action == CMD_SUBCMD_ENTER_PS) {
+ } else if (action == PS_MODE_ACTION_ENTER_PS) {
priv->needtowakeup = 0;
priv->psstate = PS_STATE_AWAKE;
@@ -279,11 +146,12 @@ int lbs_process_command_response(struct lbs_private *priv, u8 *data, u32 len)
spin_unlock_irqrestore(&priv->driver_lock, flags);
mutex_unlock(&priv->lock);
- lbs_ps_wakeup(priv, 0);
+ lbs_set_ps_mode(priv, PS_MODE_ACTION_EXIT_PS,
+ false);
mutex_lock(&priv->lock);
spin_lock_irqsave(&priv->driver_lock, flags);
}
- } else if (action == CMD_SUBCMD_EXIT_PS) {
+ } else if (action == PS_MODE_ACTION_EXIT_PS) {
priv->needtowakeup = 0;
priv->psstate = PS_STATE_FULL_POWER;
lbs_deb_host("CMD_RESP: EXIT_PS command response\n");
@@ -324,8 +192,7 @@ int lbs_process_command_response(struct lbs_private *priv, u8 *data, u32 len)
if (priv->cur_cmd && priv->cur_cmd->callback) {
ret = priv->cur_cmd->callback(priv, priv->cur_cmd->callback_arg,
resp);
- } else
- ret = handle_cmd_response(priv, resp);
+ }
spin_lock_irqsave(&priv->driver_lock, flags);
@@ -341,32 +208,10 @@ done:
return ret;
}
-static int lbs_send_confirmwake(struct lbs_private *priv)
-{
- struct cmd_header cmd;
- int ret = 0;
-
- lbs_deb_enter(LBS_DEB_HOST);
-
- cmd.command = cpu_to_le16(CMD_802_11_WAKEUP_CONFIRM);
- cmd.size = cpu_to_le16(sizeof(cmd));
- cmd.seqnum = cpu_to_le16(++priv->seqnum);
- cmd.result = 0;
-
- lbs_deb_hex(LBS_DEB_HOST, "wake confirm", (u8 *) &cmd,
- sizeof(cmd));
-
- ret = priv->hw_host_to_card(priv, MVMS_CMD, (u8 *) &cmd, sizeof(cmd));
- if (ret)
- lbs_pr_alert("SEND_WAKEC_CMD: Host to Card failed for Confirm Wake\n");
-
- lbs_deb_leave_args(LBS_DEB_HOST, "ret %d", ret);
- return ret;
-}
-
int lbs_process_event(struct lbs_private *priv, u32 event)
{
int ret = 0;
+ struct cmd_header cmd;
lbs_deb_enter(LBS_DEB_CMD);
@@ -410,7 +255,10 @@ int lbs_process_event(struct lbs_private *priv, u32 event)
if (priv->reset_deep_sleep_wakeup)
priv->reset_deep_sleep_wakeup(priv);
priv->is_deep_sleep = 0;
- lbs_send_confirmwake(priv);
+ lbs_cmd_async(priv, CMD_802_11_WAKEUP_CONFIRM, &cmd,
+ sizeof(cmd));
+ priv->is_host_sleep_activated = 0;
+ wake_up_interruptible(&priv->host_sleep_q);
break;
case MACREG_INT_CODE_DEEP_SLEEP_AWAKE:
@@ -441,7 +289,7 @@ int lbs_process_event(struct lbs_private *priv, u32 event)
* in lbs_ps_wakeup()
*/
lbs_deb_cmd("waking up ...\n");
- lbs_ps_wakeup(priv, 0);
+ lbs_set_ps_mode(priv, PS_MODE_ACTION_EXIT_PS, false);
}
break;
diff --git a/drivers/net/wireless/libertas/debugfs.c b/drivers/net/wireless/libertas/debugfs.c
index de2caac11dd..651a79c8de8 100644
--- a/drivers/net/wireless/libertas/debugfs.c
+++ b/drivers/net/wireless/libertas/debugfs.c
@@ -1,18 +1,13 @@
-#include <linux/module.h>
#include <linux/dcache.h>
#include <linux/debugfs.h>
#include <linux/delay.h>
#include <linux/mm.h>
#include <linux/string.h>
#include <linux/slab.h>
-#include <net/iw_handler.h>
-#include <net/lib80211.h>
-#include "dev.h"
#include "decl.h"
-#include "host.h"
-#include "debugfs.h"
#include "cmd.h"
+#include "debugfs.h"
static struct dentry *lbs_dir;
static char *szStates[] = {
@@ -60,51 +55,6 @@ static ssize_t lbs_dev_info(struct file *file, char __user *userbuf,
return res;
}
-
-static ssize_t lbs_getscantable(struct file *file, char __user *userbuf,
- size_t count, loff_t *ppos)
-{
- struct lbs_private *priv = file->private_data;
- size_t pos = 0;
- int numscansdone = 0, res;
- unsigned long addr = get_zeroed_page(GFP_KERNEL);
- char *buf = (char *)addr;
- DECLARE_SSID_BUF(ssid);
- struct bss_descriptor * iter_bss;
- if (!buf)
- return -ENOMEM;
-
- pos += snprintf(buf+pos, len-pos,
- "# | ch | rssi | bssid | cap | Qual | SSID\n");
-
- mutex_lock(&priv->lock);
- list_for_each_entry (iter_bss, &priv->network_list, list) {
- u16 ibss = (iter_bss->capability & WLAN_CAPABILITY_IBSS);
- u16 privacy = (iter_bss->capability & WLAN_CAPABILITY_PRIVACY);
- u16 spectrum_mgmt = (iter_bss->capability & WLAN_CAPABILITY_SPECTRUM_MGMT);
-
- pos += snprintf(buf+pos, len-pos, "%02u| %03d | %04d | %pM |",
- numscansdone, iter_bss->channel, iter_bss->rssi,
- iter_bss->bssid);
- pos += snprintf(buf+pos, len-pos, " %04x-", iter_bss->capability);
- pos += snprintf(buf+pos, len-pos, "%c%c%c |",
- ibss ? 'A' : 'I', privacy ? 'P' : ' ',
- spectrum_mgmt ? 'S' : ' ');
- pos += snprintf(buf+pos, len-pos, " %04d |", SCAN_RSSI(iter_bss->rssi));
- pos += snprintf(buf+pos, len-pos, " %s\n",
- print_ssid(ssid, iter_bss->ssid,
- iter_bss->ssid_len));
-
- numscansdone++;
- }
- mutex_unlock(&priv->lock);
-
- res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
-
- free_page(addr);
- return res;
-}
-
static ssize_t lbs_sleepparams_write(struct file *file,
const char __user *user_buf, size_t count,
loff_t *ppos)
@@ -174,6 +124,70 @@ out_unlock:
return ret;
}
+static ssize_t lbs_host_sleep_write(struct file *file,
+ const char __user *user_buf, size_t count,
+ loff_t *ppos)
+{
+ struct lbs_private *priv = file->private_data;
+ ssize_t buf_size, ret;
+ int host_sleep;
+ unsigned long addr = get_zeroed_page(GFP_KERNEL);
+ char *buf = (char *)addr;
+ if (!buf)
+ return -ENOMEM;
+
+ buf_size = min(count, len - 1);
+ if (copy_from_user(buf, user_buf, buf_size)) {
+ ret = -EFAULT;
+ goto out_unlock;
+ }
+ ret = sscanf(buf, "%d", &host_sleep);
+ if (ret != 1) {
+ ret = -EINVAL;
+ goto out_unlock;
+ }
+
+ if (host_sleep == 0)
+ ret = lbs_set_host_sleep(priv, 0);
+ else if (host_sleep == 1) {
+ if (priv->wol_criteria == EHS_REMOVE_WAKEUP) {
+ lbs_pr_info("wake parameters not configured");
+ ret = -EINVAL;
+ goto out_unlock;
+ }
+ ret = lbs_set_host_sleep(priv, 1);
+ } else {
+ lbs_pr_err("invalid option\n");
+ ret = -EINVAL;
+ }
+
+ if (!ret)
+ ret = count;
+
+out_unlock:
+ free_page(addr);
+ return ret;
+}
+
+static ssize_t lbs_host_sleep_read(struct file *file, char __user *userbuf,
+ size_t count, loff_t *ppos)
+{
+ struct lbs_private *priv = file->private_data;
+ ssize_t ret;
+ size_t pos = 0;
+ unsigned long addr = get_zeroed_page(GFP_KERNEL);
+ char *buf = (char *)addr;
+ if (!buf)
+ return -ENOMEM;
+
+ pos += snprintf(buf, len, "%d\n", priv->is_host_sleep_activated);
+
+ ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
+
+ free_page(addr);
+ return ret;
+}
+
/*
* When calling CMD_802_11_SUBSCRIBE_EVENT with CMD_ACT_GET, me might
* get a bunch of vendor-specific TLVs (a.k.a. IEs) back from the
@@ -432,30 +446,24 @@ static ssize_t lbs_bcnmiss_write(struct file *file, const char __user *userbuf,
}
-
static ssize_t lbs_rdmac_read(struct file *file, char __user *userbuf,
size_t count, loff_t *ppos)
{
struct lbs_private *priv = file->private_data;
- struct lbs_offset_value offval;
ssize_t pos = 0;
int ret;
unsigned long addr = get_zeroed_page(GFP_KERNEL);
char *buf = (char *)addr;
+ u32 val = 0;
+
if (!buf)
return -ENOMEM;
- offval.offset = priv->mac_offset;
- offval.value = 0;
-
- ret = lbs_prepare_and_send_command(priv,
- CMD_MAC_REG_ACCESS, 0,
- CMD_OPTION_WAITFORRSP, 0, &offval);
+ ret = lbs_get_reg(priv, CMD_MAC_REG_ACCESS, priv->mac_offset, &val);
mdelay(10);
if (!ret) {
- pos += snprintf(buf+pos, len-pos, "MAC[0x%x] = 0x%08x\n",
- priv->mac_offset, priv->offsetvalue.value);
-
+ pos = snprintf(buf, len, "MAC[0x%x] = 0x%08x\n",
+ priv->mac_offset, val);
ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
}
free_page(addr);
@@ -493,7 +501,6 @@ static ssize_t lbs_wrmac_write(struct file *file,
struct lbs_private *priv = file->private_data;
ssize_t res, buf_size;
u32 offset, value;
- struct lbs_offset_value offval;
unsigned long addr = get_zeroed_page(GFP_KERNEL);
char *buf = (char *)addr;
if (!buf)
@@ -510,11 +517,7 @@ static ssize_t lbs_wrmac_write(struct file *file,
goto out_unlock;
}
- offval.offset = offset;
- offval.value = value;
- res = lbs_prepare_and_send_command(priv,
- CMD_MAC_REG_ACCESS, 1,
- CMD_OPTION_WAITFORRSP, 0, &offval);
+ res = lbs_set_reg(priv, CMD_MAC_REG_ACCESS, offset, value);
mdelay(10);
if (!res)
@@ -528,25 +531,20 @@ static ssize_t lbs_rdbbp_read(struct file *file, char __user *userbuf,
size_t count, loff_t *ppos)
{
struct lbs_private *priv = file->private_data;
- struct lbs_offset_value offval;
ssize_t pos = 0;
int ret;
unsigned long addr = get_zeroed_page(GFP_KERNEL);
char *buf = (char *)addr;
+ u32 val;
+
if (!buf)
return -ENOMEM;
- offval.offset = priv->bbp_offset;
- offval.value = 0;
-
- ret = lbs_prepare_and_send_command(priv,
- CMD_BBP_REG_ACCESS, 0,
- CMD_OPTION_WAITFORRSP, 0, &offval);
+ ret = lbs_get_reg(priv, CMD_BBP_REG_ACCESS, priv->bbp_offset, &val);
mdelay(10);
if (!ret) {
- pos += snprintf(buf+pos, len-pos, "BBP[0x%x] = 0x%08x\n",
- priv->bbp_offset, priv->offsetvalue.value);
-
+ pos = snprintf(buf, len, "BBP[0x%x] = 0x%08x\n",
+ priv->bbp_offset, val);
ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
}
free_page(addr);
@@ -585,7 +583,6 @@ static ssize_t lbs_wrbbp_write(struct file *file,
struct lbs_private *priv = file->private_data;
ssize_t res, buf_size;
u32 offset, value;
- struct lbs_offset_value offval;
unsigned long addr = get_zeroed_page(GFP_KERNEL);
char *buf = (char *)addr;
if (!buf)
@@ -602,11 +599,7 @@ static ssize_t lbs_wrbbp_write(struct file *file,
goto out_unlock;
}
- offval.offset = offset;
- offval.value = value;
- res = lbs_prepare_and_send_command(priv,
- CMD_BBP_REG_ACCESS, 1,
- CMD_OPTION_WAITFORRSP, 0, &offval);
+ res = lbs_set_reg(priv, CMD_BBP_REG_ACCESS, offset, value);
mdelay(10);
if (!res)
@@ -620,25 +613,20 @@ static ssize_t lbs_rdrf_read(struct file *file, char __user *userbuf,
size_t count, loff_t *ppos)
{
struct lbs_private *priv = file->private_data;
- struct lbs_offset_value offval;
ssize_t pos = 0;
int ret;
unsigned long addr = get_zeroed_page(GFP_KERNEL);
char *buf = (char *)addr;
+ u32 val;
+
if (!buf)
return -ENOMEM;
- offval.offset = priv->rf_offset;
- offval.value = 0;
-
- ret = lbs_prepare_and_send_command(priv,
- CMD_RF_REG_ACCESS, 0,
- CMD_OPTION_WAITFORRSP, 0, &offval);
+ ret = lbs_get_reg(priv, CMD_RF_REG_ACCESS, priv->rf_offset, &val);
mdelay(10);
if (!ret) {
- pos += snprintf(buf+pos, len-pos, "RF[0x%x] = 0x%08x\n",
- priv->rf_offset, priv->offsetvalue.value);
-
+ pos = snprintf(buf, len, "RF[0x%x] = 0x%08x\n",
+ priv->rf_offset, val);
ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
}
free_page(addr);
@@ -677,7 +665,6 @@ static ssize_t lbs_wrrf_write(struct file *file,
struct lbs_private *priv = file->private_data;
ssize_t res, buf_size;
u32 offset, value;
- struct lbs_offset_value offval;
unsigned long addr = get_zeroed_page(GFP_KERNEL);
char *buf = (char *)addr;
if (!buf)
@@ -694,11 +681,7 @@ static ssize_t lbs_wrrf_write(struct file *file,
goto out_unlock;
}
- offval.offset = offset;
- offval.value = value;
- res = lbs_prepare_and_send_command(priv,
- CMD_RF_REG_ACCESS, 1,
- CMD_OPTION_WAITFORRSP, 0, &offval);
+ res = lbs_set_reg(priv, CMD_RF_REG_ACCESS, offset, value);
mdelay(10);
if (!res)
@@ -723,10 +706,10 @@ struct lbs_debugfs_files {
static const struct lbs_debugfs_files debugfs_files[] = {
{ "info", 0444, FOPS(lbs_dev_info, write_file_dummy), },
- { "getscantable", 0444, FOPS(lbs_getscantable,
- write_file_dummy), },
{ "sleepparams", 0644, FOPS(lbs_sleepparams_read,
lbs_sleepparams_write), },
+ { "hostsleep", 0644, FOPS(lbs_host_sleep_read,
+ lbs_host_sleep_write), },
};
static const struct lbs_debugfs_files debugfs_events_files[] = {
@@ -891,7 +874,7 @@ static ssize_t lbs_debugfs_read(struct file *file, char __user *userbuf,
p = buf;
- d = (struct debug_data *)file->private_data;
+ d = file->private_data;
for (i = 0; i < num_of_items; i++) {
if (d[i].size == 1)
@@ -930,7 +913,7 @@ static ssize_t lbs_debugfs_write(struct file *f, const char __user *buf,
char *p0;
char *p1;
char *p2;
- struct debug_data *d = (struct debug_data *)f->private_data;
+ struct debug_data *d = f->private_data;
pdata = kmalloc(cnt, GFP_KERNEL);
if (pdata == NULL)
diff --git a/drivers/net/wireless/libertas/decl.h b/drivers/net/wireless/libertas/decl.h
index 709ffcad22a..1d141fefd76 100644
--- a/drivers/net/wireless/libertas/decl.h
+++ b/drivers/net/wireless/libertas/decl.h
@@ -1,3 +1,4 @@
+
/**
* This file contains declaration referring to
* functions defined in other source files
@@ -12,6 +13,7 @@
struct lbs_private;
struct sk_buff;
struct net_device;
+struct cmd_ds_command;
/* ethtool.c */
@@ -34,11 +36,13 @@ int lbs_start_card(struct lbs_private *priv);
void lbs_stop_card(struct lbs_private *priv);
void lbs_host_to_card_done(struct lbs_private *priv);
+int lbs_rtap_supported(struct lbs_private *priv);
+
int lbs_set_mac_address(struct net_device *dev, void *addr);
void lbs_set_multicast_list(struct net_device *dev);
int lbs_suspend(struct lbs_private *priv);
-void lbs_resume(struct lbs_private *priv);
+int lbs_resume(struct lbs_private *priv);
void lbs_queue_event(struct lbs_private *priv, u32 event);
void lbs_notify_command_response(struct lbs_private *priv, u8 resp_idx);
@@ -49,5 +53,4 @@ int lbs_exit_auto_deep_sleep(struct lbs_private *priv);
u32 lbs_fw_index_to_data_rate(u8 index);
u8 lbs_data_rate_to_fw_index(u32 rate);
-
#endif
diff --git a/drivers/net/wireless/libertas/defs.h b/drivers/net/wireless/libertas/defs.h
index ea3f10ef4e0..d00c728cec4 100644
--- a/drivers/net/wireless/libertas/defs.h
+++ b/drivers/net/wireless/libertas/defs.h
@@ -172,11 +172,6 @@ static inline void lbs_deb_hex(unsigned int grp, const char *prompt, u8 *buf, in
#define MRVDRV_MAX_BSS_DESCRIPTS 16
#define MRVDRV_MAX_REGION_CODE 6
-#define MRVDRV_IGNORE_MULTIPLE_DTIM 0xfffe
-#define MRVDRV_MIN_MULTIPLE_DTIM 1
-#define MRVDRV_MAX_MULTIPLE_DTIM 5
-#define MRVDRV_DEFAULT_MULTIPLE_DTIM 1
-
#define MRVDRV_DEFAULT_LISTEN_INTERVAL 10
#define MRVDRV_CHANNELS_PER_SCAN 4
@@ -301,19 +296,6 @@ static inline void lbs_deb_hex(unsigned int grp, const char *prompt, u8 *buf, in
#define BAND_G (0x02)
#define ALL_802_11_BANDS (BAND_B | BAND_G)
-/** MACRO DEFINITIONS */
-#define CAL_NF(NF) ((s32)(-(s32)(NF)))
-#define CAL_RSSI(SNR, NF) ((s32)((s32)(SNR) + CAL_NF(NF)))
-#define SCAN_RSSI(RSSI) (0x100 - ((u8)(RSSI)))
-
-#define DEFAULT_BCN_AVG_FACTOR 8
-#define DEFAULT_DATA_AVG_FACTOR 8
-#define AVG_SCALE 100
-#define CAL_AVG_SNR_NF(AVG, SNRNF, N) \
- (((AVG) == 0) ? ((u16)(SNRNF) * AVG_SCALE) : \
- ((((int)(AVG) * (N -1)) + ((u16)(SNRNF) * \
- AVG_SCALE)) / N))
-
#define MAX_RATES 14
#define MAX_LEDS 8
diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h
index a54880e4ad2..3c7e255e18c 100644
--- a/drivers/net/wireless/libertas/dev.h
+++ b/drivers/net/wireless/libertas/dev.h
@@ -7,8 +7,8 @@
#define _LBS_DEV_H_
#include "mesh.h"
-#include "scan.h"
-#include "assoc.h"
+#include "defs.h"
+#include "host.h"
#include <linux/kfifo.h>
@@ -29,7 +29,6 @@ struct lbs_private {
/* Basic networking */
struct net_device *dev;
u32 connect_status;
- int infra_open;
struct work_struct mcast_work;
u32 nr_of_multicastmacaddr;
u8 multicastlist[MRVDRV_MAX_MULTICAST_LIST_SIZE][ETH_ALEN];
@@ -37,6 +36,9 @@ struct lbs_private {
/* CFG80211 */
struct wireless_dev *wdev;
bool wiphy_registered;
+ struct cfg80211_scan_request *scan_req;
+ u8 assoc_bss[ETH_ALEN];
+ u8 disassoc_reason;
/* Mesh */
struct net_device *mesh_dev; /* Virtual device */
@@ -49,10 +51,6 @@ struct lbs_private {
u8 mesh_ssid_len;
#endif
- /* Monitor mode */
- struct net_device *rtap_net_dev;
- u32 monitormode;
-
/* Debugfs */
struct dentry *debugfs_dir;
struct dentry *debugfs_debug;
@@ -66,7 +64,6 @@ struct lbs_private {
u32 mac_offset;
u32 bbp_offset;
u32 rf_offset;
- struct lbs_offset_value offsetvalue;
/* Power management */
u16 psmode;
@@ -75,6 +72,7 @@ struct lbs_private {
/* Deep sleep */
int is_deep_sleep;
+ int deep_sleep_required;
int is_auto_deep_sleep_enabled;
int wakeup_dev_required;
int is_activity_detected;
@@ -82,6 +80,11 @@ struct lbs_private {
wait_queue_head_t ds_awake_q;
struct timer_list auto_deepsleep_timer;
+ /* Host sleep*/
+ int is_host_sleep_configured;
+ int is_host_sleep_activated;
+ wait_queue_head_t host_sleep_q;
+
/* Hardware access */
void *card;
u8 fw_ready;
@@ -108,12 +111,10 @@ struct lbs_private {
struct cmd_ctrl_node *cur_cmd;
struct list_head cmdfreeq; /* free command buffers */
struct list_head cmdpendingq; /* pending command buffers */
- wait_queue_head_t cmd_pending;
struct timer_list command_timer;
int cmd_timed_out;
/* Command responses sent from the hardware to the driver */
- int cur_cmd_retcode;
u8 resp_idx;
u8 resp_buf[2][LBS_UPLD_SIZE];
u32 resp_len[2];
@@ -127,14 +128,10 @@ struct lbs_private {
struct workqueue_struct *work_thread;
/** Encryption stuff */
- struct lbs_802_11_security secinfo;
- struct enc_key wpa_mcast_key;
- struct enc_key wpa_unicast_key;
- u8 wpa_ie[MAX_WPA_IE_LEN];
- u8 wpa_ie_len;
- u16 wep_tx_keyidx;
- struct enc_key wep_keys[4];
u8 authtype_auto;
+ u8 wep_tx_key;
+ u8 wep_key[4][WLAN_KEY_LEN_WEP104];
+ u8 wep_key_len[4];
/* Wake On LAN */
uint32_t wol_criteria;
@@ -155,6 +152,7 @@ struct lbs_private {
/* NIC/link operation characteristics */
u16 mac_control;
u8 radio_on;
+ u8 cur_rate;
u8 channel;
s16 txpower_cur;
s16 txpower_min;
@@ -163,42 +161,6 @@ struct lbs_private {
/** Scanning */
struct delayed_work scan_work;
int scan_channel;
- /* remember which channel was scanned last, != 0 if currently scanning */
- u8 scan_ssid[IEEE80211_MAX_SSID_LEN + 1];
- u8 scan_ssid_len;
-
- /* Associating */
- struct delayed_work assoc_work;
- struct current_bss_params curbssparams;
- u8 mode;
- struct list_head network_list;
- struct list_head network_free_list;
- struct bss_descriptor *networks;
- struct assoc_request * pending_assoc_req;
- struct assoc_request * in_progress_assoc_req;
- uint16_t enablehwauto;
-
- /* ADHOC */
- u16 beacon_period;
- u8 beacon_enable;
- u8 adhoccreate;
-
- /* WEXT */
- char name[DEV_NAME_LEN];
- u8 nodename[16];
- struct iw_statistics wstats;
- u8 cur_rate;
-#define MAX_REGION_CHANNEL_NUM 2
- struct region_channel region_channel[MAX_REGION_CHANNEL_NUM];
-
- /** Requested Signal Strength*/
- u16 SNR[MAX_TYPE_B][MAX_TYPE_AVG];
- u16 NF[MAX_TYPE_B][MAX_TYPE_AVG];
- u8 RSSI[MAX_TYPE_B][MAX_TYPE_AVG];
- u8 rawSNR[DEFAULT_DATA_AVG_FACTOR];
- u8 rawNF[DEFAULT_DATA_AVG_FACTOR];
- u16 nextSNRNF;
- u16 numSNRNF;
};
extern struct cmd_confirm_sleep confirm_sleep;
diff --git a/drivers/net/wireless/libertas/ethtool.c b/drivers/net/wireless/libertas/ethtool.c
index 3804a58d7f4..50193aac679 100644
--- a/drivers/net/wireless/libertas/ethtool.c
+++ b/drivers/net/wireless/libertas/ethtool.c
@@ -2,13 +2,8 @@
#include <linux/ethtool.h>
#include <linux/delay.h>
-#include "host.h"
#include "decl.h"
-#include "defs.h"
-#include "dev.h"
-#include "wext.h"
#include "cmd.h"
-#include "mesh.h"
static void lbs_ethtool_get_drvinfo(struct net_device *dev,
@@ -69,14 +64,11 @@ static void lbs_ethtool_get_wol(struct net_device *dev,
{
struct lbs_private *priv = dev->ml_priv;
- if (priv->wol_criteria == 0xffffffff) {
- /* Interface driver didn't configure wake */
- wol->supported = wol->wolopts = 0;
- return;
- }
-
wol->supported = WAKE_UCAST|WAKE_MCAST|WAKE_BCAST|WAKE_PHY;
+ if (priv->wol_criteria == EHS_REMOVE_WAKEUP)
+ return;
+
if (priv->wol_criteria & EHS_WAKE_ON_UNICAST_DATA)
wol->wolopts |= WAKE_UCAST;
if (priv->wol_criteria & EHS_WAKE_ON_MULTICAST_DATA)
@@ -91,23 +83,22 @@ static int lbs_ethtool_set_wol(struct net_device *dev,
struct ethtool_wolinfo *wol)
{
struct lbs_private *priv = dev->ml_priv;
- uint32_t criteria = 0;
if (wol->wolopts & ~(WAKE_UCAST|WAKE_MCAST|WAKE_BCAST|WAKE_PHY))
return -EOPNOTSUPP;
+ priv->wol_criteria = 0;
if (wol->wolopts & WAKE_UCAST)
- criteria |= EHS_WAKE_ON_UNICAST_DATA;
+ priv->wol_criteria |= EHS_WAKE_ON_UNICAST_DATA;
if (wol->wolopts & WAKE_MCAST)
- criteria |= EHS_WAKE_ON_MULTICAST_DATA;
+ priv->wol_criteria |= EHS_WAKE_ON_MULTICAST_DATA;
if (wol->wolopts & WAKE_BCAST)
- criteria |= EHS_WAKE_ON_BROADCAST_DATA;
+ priv->wol_criteria |= EHS_WAKE_ON_BROADCAST_DATA;
if (wol->wolopts & WAKE_PHY)
- criteria |= EHS_WAKE_ON_MAC_EVENT;
+ priv->wol_criteria |= EHS_WAKE_ON_MAC_EVENT;
if (wol->wolopts == 0)
- criteria |= EHS_REMOVE_WAKEUP;
-
- return lbs_host_sleep_cfg(priv, criteria, (struct wol_config *)NULL);
+ priv->wol_criteria |= EHS_REMOVE_WAKEUP;
+ return 0;
}
const struct ethtool_ops lbs_ethtool_ops = {
diff --git a/drivers/net/wireless/libertas/host.h b/drivers/net/wireless/libertas/host.h
index 3809c0b4946..5eac1351a02 100644
--- a/drivers/net/wireless/libertas/host.h
+++ b/drivers/net/wireless/libertas/host.h
@@ -94,11 +94,9 @@
#define CMD_802_11_BEACON_CTRL 0x00b0
/* For the IEEE Power Save */
-#define CMD_SUBCMD_ENTER_PS 0x0030
-#define CMD_SUBCMD_EXIT_PS 0x0031
-#define CMD_SUBCMD_SLEEP_CONFIRMED 0x0034
-#define CMD_SUBCMD_FULL_POWERDOWN 0x0035
-#define CMD_SUBCMD_FULL_POWERUP 0x0036
+#define PS_MODE_ACTION_ENTER_PS 0x0030
+#define PS_MODE_ACTION_EXIT_PS 0x0031
+#define PS_MODE_ACTION_SLEEP_CONFIRMED 0x0034
#define CMD_ENABLE_RSN 0x0001
#define CMD_DISABLE_RSN 0x0000
@@ -163,11 +161,6 @@
#define CMD_ACT_SET_TX_FIX_RATE 0x0001
#define CMD_ACT_GET_TX_RATE 0x0002
-/* Define action or option for CMD_802_11_PS_MODE */
-#define CMD_TYPE_CAM 0x0000
-#define CMD_TYPE_MAX_PSP 0x0001
-#define CMD_TYPE_FAST_PSP 0x0002
-
/* Options for CMD_802_11_FW_WAKE_METHOD */
#define CMD_WAKE_METHOD_UNCHANGED 0x0000
#define CMD_WAKE_METHOD_COMMAND_INT 0x0001
@@ -326,7 +319,7 @@ struct txpd {
u8 pktdelay_2ms;
/* reserved */
u8 reserved1;
-} __attribute__ ((packed));
+} __packed;
/* RxPD Descriptor */
struct rxpd {
@@ -339,8 +332,8 @@ struct rxpd {
u8 bss_type;
/* BSS number */
u8 bss_num;
- } __attribute__ ((packed)) bss;
- } __attribute__ ((packed)) u;
+ } __packed bss;
+ } __packed u;
/* SNR */
u8 snr;
@@ -366,14 +359,14 @@ struct rxpd {
/* Pkt Priority */
u8 priority;
u8 reserved[3];
-} __attribute__ ((packed));
+} __packed;
struct cmd_header {
__le16 command;
__le16 size;
__le16 seqnum;
__le16 result;
-} __attribute__ ((packed));
+} __packed;
/* Generic structure to hold all key types. */
struct enc_key {
@@ -387,7 +380,23 @@ struct enc_key {
struct lbs_offset_value {
u32 offset;
u32 value;
-} __attribute__ ((packed));
+} __packed;
+
+#define MAX_11D_TRIPLETS 83
+
+struct mrvl_ie_domain_param_set {
+ struct mrvl_ie_header header;
+
+ u8 country_code[3];
+ struct ieee80211_country_ie_triplet triplet[MAX_11D_TRIPLETS];
+} __packed;
+
+struct cmd_ds_802_11d_domain_info {
+ struct cmd_header hdr;
+
+ __le16 action;
+ struct mrvl_ie_domain_param_set domain;
+} __packed;
/*
* Define data structure for CMD_GET_HW_SPEC
@@ -426,7 +435,7 @@ struct cmd_ds_get_hw_spec {
/*FW/HW capability */
__le32 fwcapinfo;
-} __attribute__ ((packed));
+} __packed;
struct cmd_ds_802_11_subscribe_event {
struct cmd_header hdr;
@@ -440,7 +449,7 @@ struct cmd_ds_802_11_subscribe_event {
* bump this up a bit.
*/
uint8_t tlv[128];
-} __attribute__ ((packed));
+} __packed;
/*
* This scan handle Country Information IE(802.11d compliant)
@@ -452,7 +461,7 @@ struct cmd_ds_802_11_scan {
uint8_t bsstype;
uint8_t bssid[ETH_ALEN];
uint8_t tlvbuffer[0];
-} __attribute__ ((packed));
+} __packed;
struct cmd_ds_802_11_scan_rsp {
struct cmd_header hdr;
@@ -460,7 +469,7 @@ struct cmd_ds_802_11_scan_rsp {
__le16 bssdescriptsize;
uint8_t nr_sets;
uint8_t bssdesc_and_tlvbuffer[0];
-} __attribute__ ((packed));
+} __packed;
struct cmd_ds_802_11_get_log {
struct cmd_header hdr;
@@ -478,20 +487,20 @@ struct cmd_ds_802_11_get_log {
__le32 fcserror;
__le32 txframe;
__le32 wepundecryptable;
-} __attribute__ ((packed));
+} __packed;
struct cmd_ds_mac_control {
struct cmd_header hdr;
__le16 action;
u16 reserved;
-} __attribute__ ((packed));
+} __packed;
struct cmd_ds_mac_multicast_adr {
struct cmd_header hdr;
__le16 action;
__le16 nr_of_adrs;
u8 maclist[ETH_ALEN * MRVDRV_MAX_MULTICAST_LIST_SIZE];
-} __attribute__ ((packed));
+} __packed;
struct cmd_ds_802_11_authenticate {
struct cmd_header hdr;
@@ -499,14 +508,14 @@ struct cmd_ds_802_11_authenticate {
u8 bssid[ETH_ALEN];
u8 authtype;
u8 reserved[10];
-} __attribute__ ((packed));
+} __packed;
struct cmd_ds_802_11_deauthenticate {
struct cmd_header hdr;
u8 macaddr[ETH_ALEN];
__le16 reasoncode;
-} __attribute__ ((packed));
+} __packed;
struct cmd_ds_802_11_associate {
struct cmd_header hdr;
@@ -517,7 +526,7 @@ struct cmd_ds_802_11_associate {
__le16 bcnperiod;
u8 dtimperiod;
u8 iebuf[512]; /* Enough for required and most optional IEs */
-} __attribute__ ((packed));
+} __packed;
struct cmd_ds_802_11_associate_response {
struct cmd_header hdr;
@@ -526,7 +535,7 @@ struct cmd_ds_802_11_associate_response {
__le16 statuscode;
__le16 aid;
u8 iebuf[512];
-} __attribute__ ((packed));
+} __packed;
struct cmd_ds_802_11_set_wep {
struct cmd_header hdr;
@@ -540,7 +549,7 @@ struct cmd_ds_802_11_set_wep {
/* 40, 128bit or TXWEP */
uint8_t keytype[4];
uint8_t keymaterial[4][16];
-} __attribute__ ((packed));
+} __packed;
struct cmd_ds_802_11_snmp_mib {
struct cmd_header hdr;
@@ -549,40 +558,33 @@ struct cmd_ds_802_11_snmp_mib {
__le16 oid;
__le16 bufsize;
u8 value[128];
-} __attribute__ ((packed));
-
-struct cmd_ds_mac_reg_access {
- __le16 action;
- __le16 offset;
- __le32 value;
-} __attribute__ ((packed));
+} __packed;
-struct cmd_ds_bbp_reg_access {
- __le16 action;
- __le16 offset;
- u8 value;
- u8 reserved[3];
-} __attribute__ ((packed));
+struct cmd_ds_reg_access {
+ struct cmd_header hdr;
-struct cmd_ds_rf_reg_access {
__le16 action;
__le16 offset;
- u8 value;
- u8 reserved[3];
-} __attribute__ ((packed));
+ union {
+ u8 bbp_rf; /* for BBP and RF registers */
+ __le32 mac; /* for MAC registers */
+ } value;
+} __packed;
struct cmd_ds_802_11_radio_control {
struct cmd_header hdr;
__le16 action;
__le16 control;
-} __attribute__ ((packed));
+} __packed;
struct cmd_ds_802_11_beacon_control {
+ struct cmd_header hdr;
+
__le16 action;
__le16 beacon_enable;
__le16 beacon_period;
-} __attribute__ ((packed));
+} __packed;
struct cmd_ds_802_11_sleep_params {
struct cmd_header hdr;
@@ -607,7 +609,7 @@ struct cmd_ds_802_11_sleep_params {
/* reserved field, should be set to zero */
__le16 reserved;
-} __attribute__ ((packed));
+} __packed;
struct cmd_ds_802_11_rf_channel {
struct cmd_header hdr;
@@ -617,30 +619,30 @@ struct cmd_ds_802_11_rf_channel {
__le16 rftype; /* unused */
__le16 reserved; /* unused */
u8 channellist[32]; /* unused */
-} __attribute__ ((packed));
+} __packed;
struct cmd_ds_802_11_rssi {
- /* weighting factor */
- __le16 N;
+ struct cmd_header hdr;
- __le16 reserved_0;
- __le16 reserved_1;
- __le16 reserved_2;
-} __attribute__ ((packed));
+ /* request: number of beacons (N) to average the SNR and NF over
+ * response: SNR of most recent beacon
+ */
+ __le16 n_or_snr;
-struct cmd_ds_802_11_rssi_rsp {
- __le16 SNR;
- __le16 noisefloor;
- __le16 avgSNR;
- __le16 avgnoisefloor;
-} __attribute__ ((packed));
+ /* The following fields are only set in the response.
+ * In the request these are reserved and should be set to 0.
+ */
+ __le16 nf; /* most recent beacon noise floor */
+ __le16 avg_snr; /* average SNR weighted by N from request */
+ __le16 avg_nf; /* average noise floor weighted by N from request */
+} __packed;
struct cmd_ds_802_11_mac_address {
struct cmd_header hdr;
__le16 action;
u8 macadd[ETH_ALEN];
-} __attribute__ ((packed));
+} __packed;
struct cmd_ds_802_11_rf_tx_power {
struct cmd_header hdr;
@@ -649,34 +651,61 @@ struct cmd_ds_802_11_rf_tx_power {
__le16 curlevel;
s8 maxlevel;
s8 minlevel;
-} __attribute__ ((packed));
+} __packed;
+/* MONITOR_MODE only exists in OLPC v5 firmware */
struct cmd_ds_802_11_monitor_mode {
+ struct cmd_header hdr;
+
__le16 action;
__le16 mode;
-} __attribute__ ((packed));
+} __packed;
struct cmd_ds_set_boot2_ver {
struct cmd_header hdr;
__le16 action;
__le16 version;
-} __attribute__ ((packed));
+} __packed;
struct cmd_ds_802_11_fw_wake_method {
struct cmd_header hdr;
__le16 action;
__le16 method;
-} __attribute__ ((packed));
+} __packed;
struct cmd_ds_802_11_ps_mode {
+ struct cmd_header hdr;
+
__le16 action;
+
+ /* Interval for keepalive in PS mode:
+ * 0x0000 = don't change
+ * 0x001E = firmware default
+ * 0xFFFF = disable
+ */
__le16 nullpktinterval;
+
+ /* Number of DTIM intervals to wake up for:
+ * 0 = don't change
+ * 1 = firmware default
+ * 5 = max
+ */
__le16 multipledtim;
+
__le16 reserved;
__le16 locallisteninterval;
-} __attribute__ ((packed));
+
+ /* AdHoc awake period (FW v9+ only):
+ * 0 = don't change
+ * 1 = always awake (IEEE standard behavior)
+ * 2 - 31 = sleep for (n - 1) periods and awake for 1 period
+ * 32 - 254 = invalid
+ * 255 = sleep at each ATIM
+ */
+ __le16 adhoc_awake_period;
+} __packed;
struct cmd_confirm_sleep {
struct cmd_header hdr;
@@ -686,7 +715,7 @@ struct cmd_confirm_sleep {
__le16 multipledtim;
__le16 reserved;
__le16 locallisteninterval;
-} __attribute__ ((packed));
+} __packed;
struct cmd_ds_802_11_data_rate {
struct cmd_header hdr;
@@ -694,14 +723,14 @@ struct cmd_ds_802_11_data_rate {
__le16 action;
__le16 reserved;
u8 rates[MAX_RATES];
-} __attribute__ ((packed));
+} __packed;
struct cmd_ds_802_11_rate_adapt_rateset {
struct cmd_header hdr;
__le16 action;
__le16 enablehwauto;
__le16 bitmap;
-} __attribute__ ((packed));
+} __packed;
struct cmd_ds_802_11_ad_hoc_start {
struct cmd_header hdr;
@@ -718,14 +747,14 @@ struct cmd_ds_802_11_ad_hoc_start {
__le16 capability;
u8 rates[MAX_RATES];
u8 tlv_memory_size_pad[100];
-} __attribute__ ((packed));
+} __packed;
struct cmd_ds_802_11_ad_hoc_result {
struct cmd_header hdr;
u8 pad[3];
u8 bssid[ETH_ALEN];
-} __attribute__ ((packed));
+} __packed;
struct adhoc_bssdesc {
u8 bssid[ETH_ALEN];
@@ -746,7 +775,7 @@ struct adhoc_bssdesc {
* Adhoc join command and will cause a binary layout mismatch with
* the firmware
*/
-} __attribute__ ((packed));
+} __packed;
struct cmd_ds_802_11_ad_hoc_join {
struct cmd_header hdr;
@@ -754,18 +783,18 @@ struct cmd_ds_802_11_ad_hoc_join {
struct adhoc_bssdesc bss;
__le16 failtimeout; /* Reserved on v9 and later */
__le16 probedelay; /* Reserved on v9 and later */
-} __attribute__ ((packed));
+} __packed;
struct cmd_ds_802_11_ad_hoc_stop {
struct cmd_header hdr;
-} __attribute__ ((packed));
+} __packed;
struct cmd_ds_802_11_enable_rsn {
struct cmd_header hdr;
__le16 action;
__le16 enable;
-} __attribute__ ((packed));
+} __packed;
struct MrvlIEtype_keyParamSet {
/* type ID */
@@ -785,7 +814,7 @@ struct MrvlIEtype_keyParamSet {
/* key material of size keylen */
u8 key[32];
-} __attribute__ ((packed));
+} __packed;
#define MAX_WOL_RULES 16
@@ -797,7 +826,7 @@ struct host_wol_rule {
__le16 reserve;
__be32 sig_mask;
__be32 signature;
-} __attribute__ ((packed));
+} __packed;
struct wol_config {
uint8_t action;
@@ -805,7 +834,7 @@ struct wol_config {
uint8_t no_rules_in_cmd;
uint8_t result;
struct host_wol_rule rule[MAX_WOL_RULES];
-} __attribute__ ((packed));
+} __packed;
struct cmd_ds_host_sleep {
struct cmd_header hdr;
@@ -813,7 +842,7 @@ struct cmd_ds_host_sleep {
uint8_t gpio;
uint16_t gap;
struct wol_config wol_conf;
-} __attribute__ ((packed));
+} __packed;
@@ -822,7 +851,7 @@ struct cmd_ds_802_11_key_material {
__le16 action;
struct MrvlIEtype_keyParamSet keyParamSet[2];
-} __attribute__ ((packed));
+} __packed;
struct cmd_ds_802_11_eeprom_access {
struct cmd_header hdr;
@@ -832,7 +861,7 @@ struct cmd_ds_802_11_eeprom_access {
/* firmware says it returns a maximum of 20 bytes */
#define LBS_EEPROM_READ_LEN 20
u8 value[LBS_EEPROM_READ_LEN];
-} __attribute__ ((packed));
+} __packed;
struct cmd_ds_802_11_tpc_cfg {
struct cmd_header hdr;
@@ -843,7 +872,7 @@ struct cmd_ds_802_11_tpc_cfg {
int8_t P1;
int8_t P2;
uint8_t usesnr;
-} __attribute__ ((packed));
+} __packed;
struct cmd_ds_802_11_pa_cfg {
@@ -854,16 +883,21 @@ struct cmd_ds_802_11_pa_cfg {
int8_t P0;
int8_t P1;
int8_t P2;
-} __attribute__ ((packed));
+} __packed;
struct cmd_ds_802_11_led_ctrl {
+ struct cmd_header hdr;
+
__le16 action;
__le16 numled;
u8 data[256];
-} __attribute__ ((packed));
+} __packed;
+/* Automatic Frequency Control */
struct cmd_ds_802_11_afc {
+ struct cmd_header hdr;
+
__le16 afc_auto;
union {
struct {
@@ -875,24 +909,28 @@ struct cmd_ds_802_11_afc {
__le16 carrier_offset; /* signed */
};
};
-} __attribute__ ((packed));
+} __packed;
struct cmd_tx_rate_query {
__le16 txrate;
-} __attribute__ ((packed));
+} __packed;
struct cmd_ds_get_tsf {
__le64 tsfvalue;
-} __attribute__ ((packed));
+} __packed;
struct cmd_ds_bt_access {
+ struct cmd_header hdr;
+
__le16 action;
__le32 id;
u8 addr1[ETH_ALEN];
u8 addr2[ETH_ALEN];
-} __attribute__ ((packed));
+} __packed;
struct cmd_ds_fwt_access {
+ struct cmd_header hdr;
+
__le16 action;
__le32 id;
u8 valid;
@@ -910,7 +948,7 @@ struct cmd_ds_fwt_access {
__le32 snr;
__le32 references;
u8 prec[ETH_ALEN];
-} __attribute__ ((packed));
+} __packed;
struct cmd_ds_mesh_config {
struct cmd_header hdr;
@@ -920,43 +958,15 @@ struct cmd_ds_mesh_config {
__le16 type;
__le16 length;
u8 data[128]; /* last position reserved */
-} __attribute__ ((packed));
+} __packed;
struct cmd_ds_mesh_access {
struct cmd_header hdr;
__le16 action;
__le32 data[32]; /* last position reserved */
-} __attribute__ ((packed));
+} __packed;
/* Number of stats counters returned by the firmware */
#define MESH_STATS_NUM 8
-
-struct cmd_ds_command {
- /* command header */
- __le16 command;
- __le16 size;
- __le16 seqnum;
- __le16 result;
-
- /* command Body */
- union {
- struct cmd_ds_802_11_ps_mode psmode;
- struct cmd_ds_802_11_monitor_mode monitor;
- struct cmd_ds_802_11_rssi rssi;
- struct cmd_ds_802_11_rssi_rsp rssirsp;
- struct cmd_ds_mac_reg_access macreg;
- struct cmd_ds_bbp_reg_access bbpreg;
- struct cmd_ds_rf_reg_access rfreg;
-
- struct cmd_ds_802_11_tpc_cfg tpccfg;
- struct cmd_ds_802_11_afc afc;
- struct cmd_ds_802_11_led_ctrl ledgpio;
-
- struct cmd_ds_bt_access bt;
- struct cmd_ds_fwt_access fwt;
- struct cmd_ds_802_11_beacon_control bcn_ctrl;
- } params;
-} __attribute__ ((packed));
-
#endif
diff --git a/drivers/net/wireless/libertas/if_cs.c b/drivers/net/wireless/libertas/if_cs.c
index 08e4e390800..9c298396be5 100644
--- a/drivers/net/wireless/libertas/if_cs.c
+++ b/drivers/net/wireless/libertas/if_cs.c
@@ -28,7 +28,6 @@
#include <linux/firmware.h>
#include <linux/netdevice.h>
-#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/cistpl.h>
#include <pcmcia/ds.h>
@@ -802,9 +801,9 @@ static int if_cs_ioprobe(struct pcmcia_device *p_dev,
unsigned int vcc,
void *priv_data)
{
- p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
- p_dev->io.BasePort1 = cfg->io.win[0].base;
- p_dev->io.NumPorts1 = cfg->io.win[0].len;
+ p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO;
+ p_dev->resource[0]->start = cfg->io.win[0].base;
+ p_dev->resource[0]->end = cfg->io.win[0].len;
/* Do we need to allocate an interrupt? */
p_dev->conf.Attributes |= CONF_ENABLE_IRQ;
@@ -816,7 +815,7 @@ static int if_cs_ioprobe(struct pcmcia_device *p_dev,
}
/* This reserves IO space but doesn't actually enable it */
- return pcmcia_request_io(p_dev, &p_dev->io);
+ return pcmcia_request_io(p_dev);
}
static int if_cs_probe(struct pcmcia_device *p_dev)
@@ -854,7 +853,8 @@ static int if_cs_probe(struct pcmcia_device *p_dev)
goto out1;
/* Initialize io access */
- card->iobase = ioport_map(p_dev->io.BasePort1, p_dev->io.NumPorts1);
+ card->iobase = ioport_map(p_dev->resource[0]->start,
+ resource_size(p_dev->resource[0]));
if (!card->iobase) {
lbs_pr_err("error in ioport_map\n");
ret = -EIO;
@@ -873,9 +873,7 @@ static int if_cs_probe(struct pcmcia_device *p_dev)
}
/* Finally, report what we've done */
- lbs_deb_cs("irq %d, io 0x%04x-0x%04x\n",
- p_dev->irq, p_dev->io.BasePort1,
- p_dev->io.BasePort1 + p_dev->io.NumPorts1 - 1);
+ lbs_deb_cs("irq %d, io %pR", p_dev->irq, p_dev->resource[0]);
/*
* Most of the libertas cards can do unaligned register access, but some
diff --git a/drivers/net/wireless/libertas/if_sdio.c b/drivers/net/wireless/libertas/if_sdio.c
index 64dd345d30f..6e71346a755 100644
--- a/drivers/net/wireless/libertas/if_sdio.c
+++ b/drivers/net/wireless/libertas/if_sdio.c
@@ -1182,11 +1182,69 @@ static void if_sdio_remove(struct sdio_func *func)
lbs_deb_leave(LBS_DEB_SDIO);
}
+static int if_sdio_suspend(struct device *dev)
+{
+ struct sdio_func *func = dev_to_sdio_func(dev);
+ int ret;
+ struct if_sdio_card *card = sdio_get_drvdata(func);
+
+ mmc_pm_flag_t flags = sdio_get_host_pm_caps(func);
+
+ lbs_pr_info("%s: suspend: PM flags = 0x%x\n",
+ sdio_func_id(func), flags);
+
+ /* If we aren't being asked to wake on anything, we should bail out
+ * and let the SD stack power down the card.
+ */
+ if (card->priv->wol_criteria == EHS_REMOVE_WAKEUP) {
+ lbs_pr_info("Suspend without wake params -- "
+ "powering down card.");
+ return -ENOSYS;
+ }
+
+ if (!(flags & MMC_PM_KEEP_POWER)) {
+ lbs_pr_err("%s: cannot remain alive while host is suspended\n",
+ sdio_func_id(func));
+ return -ENOSYS;
+ }
+
+ ret = sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER);
+ if (ret)
+ return ret;
+
+ ret = lbs_suspend(card->priv);
+ if (ret)
+ return ret;
+
+ return sdio_set_host_pm_flags(func, MMC_PM_WAKE_SDIO_IRQ);
+}
+
+static int if_sdio_resume(struct device *dev)
+{
+ struct sdio_func *func = dev_to_sdio_func(dev);
+ struct if_sdio_card *card = sdio_get_drvdata(func);
+ int ret;
+
+ lbs_pr_info("%s: resume: we're back\n", sdio_func_id(func));
+
+ ret = lbs_resume(card->priv);
+
+ return ret;
+}
+
+static const struct dev_pm_ops if_sdio_pm_ops = {
+ .suspend = if_sdio_suspend,
+ .resume = if_sdio_resume,
+};
+
static struct sdio_driver if_sdio_driver = {
.name = "libertas_sdio",
.id_table = if_sdio_ids,
.probe = if_sdio_probe,
.remove = if_sdio_remove,
+ .drv = {
+ .pm = &if_sdio_pm_ops,
+ },
};
/*******************************************************************/
diff --git a/drivers/net/wireless/libertas/if_usb.c b/drivers/net/wireless/libertas/if_usb.c
index f41594c7ac1..07ece9d26c6 100644
--- a/drivers/net/wireless/libertas/if_usb.c
+++ b/drivers/net/wireless/libertas/if_usb.c
@@ -433,7 +433,7 @@ static int if_usb_send_fw_pkt(struct if_usb_card *cardp)
static int if_usb_reset_device(struct if_usb_card *cardp)
{
- struct cmd_ds_command *cmd = cardp->ep_out_buf + 4;
+ struct cmd_header *cmd = cardp->ep_out_buf + 4;
int ret;
lbs_deb_enter(LBS_DEB_USB);
@@ -441,7 +441,7 @@ static int if_usb_reset_device(struct if_usb_card *cardp)
*(__le32 *)cardp->ep_out_buf = cpu_to_le32(CMD_TYPE_REQUEST);
cmd->command = cpu_to_le16(CMD_802_11_RESET);
- cmd->size = cpu_to_le16(sizeof(struct cmd_header));
+ cmd->size = cpu_to_le16(sizeof(cmd));
cmd->result = cpu_to_le16(0);
cmd->seqnum = cpu_to_le16(0x5a5a);
usb_tx_block(cardp, cardp->ep_out_buf, 4 + sizeof(struct cmd_header));
@@ -613,16 +613,14 @@ static void if_usb_receive_fwload(struct urb *urb)
return;
}
- syncfwheader = kmalloc(sizeof(struct fwsyncheader), GFP_ATOMIC);
+ syncfwheader = kmemdup(skb->data + IPFIELD_ALIGN_OFFSET,
+ sizeof(struct fwsyncheader), GFP_ATOMIC);
if (!syncfwheader) {
lbs_deb_usbd(&cardp->udev->dev, "Failure to allocate syncfwheader\n");
kfree_skb(skb);
return;
}
- memcpy(syncfwheader, skb->data + IPFIELD_ALIGN_OFFSET,
- sizeof(struct fwsyncheader));
-
if (!syncfwheader->cmd) {
lbs_deb_usb2(&cardp->udev->dev, "FW received Blk with correct CRC\n");
lbs_deb_usb2(&cardp->udev->dev, "FW received Blk seqnum = %d\n",
@@ -1043,6 +1041,12 @@ static int if_usb_suspend(struct usb_interface *intf, pm_message_t message)
if (priv->psstate != PS_STATE_FULL_POWER)
return -1;
+ if (priv->wol_criteria == EHS_REMOVE_WAKEUP) {
+ lbs_pr_info("Suspend attempt without "
+ "configuring wake params!\n");
+ return -ENOSYS;
+ }
+
ret = lbs_suspend(priv);
if (ret)
goto out;
diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c
index d9b8ee130c4..258967144b9 100644
--- a/drivers/net/wireless/libertas/main.c
+++ b/drivers/net/wireless/libertas/main.c
@@ -11,20 +11,14 @@
#include <linux/if_arp.h>
#include <linux/kthread.h>
#include <linux/kfifo.h>
-#include <linux/stddef.h>
-#include <linux/ieee80211.h>
#include <linux/slab.h>
-#include <net/iw_handler.h>
#include <net/cfg80211.h>
#include "host.h"
#include "decl.h"
#include "dev.h"
-#include "wext.h"
#include "cfg.h"
#include "debugfs.h"
-#include "scan.h"
-#include "assoc.h"
#include "cmd.h"
#define DRIVER_RELEASE_VERSION "323.p0"
@@ -96,72 +90,6 @@ u8 lbs_data_rate_to_fw_index(u32 rate)
}
-static int lbs_add_rtap(struct lbs_private *priv);
-static void lbs_remove_rtap(struct lbs_private *priv);
-
-
-/**
- * Get function for sysfs attribute rtap
- */
-static ssize_t lbs_rtap_get(struct device *dev,
- struct device_attribute *attr, char * buf)
-{
- struct lbs_private *priv = to_net_dev(dev)->ml_priv;
- return snprintf(buf, 5, "0x%X\n", priv->monitormode);
-}
-
-/**
- * Set function for sysfs attribute rtap
- */
-static ssize_t lbs_rtap_set(struct device *dev,
- struct device_attribute *attr, const char * buf, size_t count)
-{
- int monitor_mode;
- struct lbs_private *priv = to_net_dev(dev)->ml_priv;
-
- sscanf(buf, "%x", &monitor_mode);
- if (monitor_mode) {
- if (priv->monitormode == monitor_mode)
- return strlen(buf);
- if (!priv->monitormode) {
- if (priv->infra_open || lbs_mesh_open(priv))
- return -EBUSY;
- if (priv->mode == IW_MODE_INFRA)
- lbs_cmd_80211_deauthenticate(priv,
- priv->curbssparams.bssid,
- WLAN_REASON_DEAUTH_LEAVING);
- else if (priv->mode == IW_MODE_ADHOC)
- lbs_adhoc_stop(priv);
- lbs_add_rtap(priv);
- }
- priv->monitormode = monitor_mode;
- } else {
- if (!priv->monitormode)
- return strlen(buf);
- priv->monitormode = 0;
- lbs_remove_rtap(priv);
-
- if (priv->currenttxskb) {
- dev_kfree_skb_any(priv->currenttxskb);
- priv->currenttxskb = NULL;
- }
-
- /* Wake queues, command thread, etc. */
- lbs_host_to_card_done(priv);
- }
-
- lbs_prepare_and_send_command(priv,
- CMD_802_11_MONITOR_MODE, CMD_ACT_SET,
- CMD_OPTION_WAITFORRSP, 0, &priv->monitormode);
- return strlen(buf);
-}
-
-/**
- * lbs_rtap attribute to be exported per ethX interface
- * through sysfs (/sys/class/net/ethX/lbs_rtap)
- */
-static DEVICE_ATTR(lbs_rtap, 0644, lbs_rtap_get, lbs_rtap_set );
-
/**
* @brief This function opens the ethX interface
*
@@ -177,13 +105,6 @@ static int lbs_dev_open(struct net_device *dev)
spin_lock_irq(&priv->driver_lock);
- if (priv->monitormode) {
- ret = -EBUSY;
- goto out;
- }
-
- priv->infra_open = 1;
-
if (priv->connect_status == LBS_CONNECTED)
netif_carrier_on(dev);
else
@@ -191,7 +112,6 @@ static int lbs_dev_open(struct net_device *dev)
if (!priv->tx_pending_len)
netif_wake_queue(dev);
- out:
spin_unlock_irq(&priv->driver_lock);
lbs_deb_leave_args(LBS_DEB_NET, "ret %d", ret);
@@ -211,7 +131,6 @@ static int lbs_eth_stop(struct net_device *dev)
lbs_deb_enter(LBS_DEB_NET);
spin_lock_irq(&priv->driver_lock);
- priv->infra_open = 0;
netif_stop_queue(dev);
spin_unlock_irq(&priv->driver_lock);
@@ -238,12 +157,7 @@ static void lbs_tx_timeout(struct net_device *dev)
to kick it somehow? */
lbs_host_to_card_done(priv);
- /* More often than not, this actually happens because the
- firmware has crapped itself -- rather than just a very
- busy medium. So send a harmless command, and if/when
- _that_ times out, we'll kick it in the head. */
- lbs_prepare_and_send_command(priv, CMD_802_11_RSSI, 0,
- 0, 0, NULL);
+ /* FIXME: reset the card */
lbs_deb_leave(LBS_DEB_TX);
}
@@ -588,12 +502,6 @@ static int lbs_thread(void *data)
if (!priv->dnld_sent && !priv->cur_cmd)
lbs_execute_next_command(priv);
- /* Wake-up command waiters which can't sleep in
- * lbs_prepare_and_send_command
- */
- if (!list_empty(&priv->cmdpendingq))
- wake_up_all(&priv->cmd_pending);
-
spin_lock_irq(&priv->driver_lock);
if (!priv->dnld_sent && priv->tx_pending_len > 0) {
int ret = priv->hw_host_to_card(priv, MVMS_DAT,
@@ -619,66 +527,58 @@ static int lbs_thread(void *data)
del_timer(&priv->command_timer);
del_timer(&priv->auto_deepsleep_timer);
- wake_up_all(&priv->cmd_pending);
lbs_deb_leave(LBS_DEB_THREAD);
return 0;
}
-static int lbs_suspend_callback(struct lbs_private *priv, unsigned long dummy,
- struct cmd_header *cmd)
-{
- lbs_deb_enter(LBS_DEB_FW);
-
- netif_device_detach(priv->dev);
- if (priv->mesh_dev)
- netif_device_detach(priv->mesh_dev);
-
- priv->fw_ready = 0;
- lbs_deb_leave(LBS_DEB_FW);
- return 0;
-}
-
int lbs_suspend(struct lbs_private *priv)
{
- struct cmd_header cmd;
int ret;
lbs_deb_enter(LBS_DEB_FW);
- if (priv->wol_criteria == 0xffffffff) {
- lbs_pr_info("Suspend attempt without configuring wake params!\n");
- return -EINVAL;
+ if (priv->is_deep_sleep) {
+ ret = lbs_set_deep_sleep(priv, 0);
+ if (ret) {
+ lbs_pr_err("deep sleep cancellation failed: %d\n", ret);
+ return ret;
+ }
+ priv->deep_sleep_required = 1;
}
- memset(&cmd, 0, sizeof(cmd));
+ ret = lbs_set_host_sleep(priv, 1);
- ret = __lbs_cmd(priv, CMD_802_11_HOST_SLEEP_ACTIVATE, &cmd,
- sizeof(cmd), lbs_suspend_callback, 0);
- if (ret)
- lbs_pr_info("HOST_SLEEP_ACTIVATE failed: %d\n", ret);
+ netif_device_detach(priv->dev);
+ if (priv->mesh_dev)
+ netif_device_detach(priv->mesh_dev);
lbs_deb_leave_args(LBS_DEB_FW, "ret %d", ret);
return ret;
}
EXPORT_SYMBOL_GPL(lbs_suspend);
-void lbs_resume(struct lbs_private *priv)
+int lbs_resume(struct lbs_private *priv)
{
- lbs_deb_enter(LBS_DEB_FW);
+ int ret;
- priv->fw_ready = 1;
+ lbs_deb_enter(LBS_DEB_FW);
- /* Firmware doesn't seem to give us RX packets any more
- until we send it some command. Might as well update */
- lbs_prepare_and_send_command(priv, CMD_802_11_RSSI, 0,
- 0, 0, NULL);
+ ret = lbs_set_host_sleep(priv, 0);
netif_device_attach(priv->dev);
if (priv->mesh_dev)
netif_device_attach(priv->mesh_dev);
- lbs_deb_leave(LBS_DEB_FW);
+ if (priv->deep_sleep_required) {
+ priv->deep_sleep_required = 0;
+ ret = lbs_set_deep_sleep(priv, 1);
+ if (ret)
+ lbs_pr_err("deep sleep activation failed: %d\n", ret);
+ }
+
+ lbs_deb_leave_args(LBS_DEB_FW, "ret %d", ret);
+ return ret;
}
EXPORT_SYMBOL_GPL(lbs_resume);
@@ -710,6 +610,9 @@ static int lbs_setup_firmware(struct lbs_private *priv)
priv->txpower_max = maxlevel;
}
+ /* Send cmd to FW to enable 11D function */
+ ret = lbs_set_snmp_mib(priv, SNMP_MIB_OID_11D_ENABLE, 1);
+
lbs_set_mac_control(priv);
done:
lbs_deb_leave_args(LBS_DEB_FW, "ret %d", ret);
@@ -748,7 +651,6 @@ out:
static void auto_deepsleep_timer_fn(unsigned long data)
{
struct lbs_private *priv = (struct lbs_private *)data;
- int ret;
lbs_deb_enter(LBS_DEB_CMD);
@@ -756,14 +658,15 @@ static void auto_deepsleep_timer_fn(unsigned long data)
priv->is_activity_detected = 0;
} else {
if (priv->is_auto_deep_sleep_enabled &&
- (!priv->wakeup_dev_required) &&
- (priv->connect_status != LBS_CONNECTED)) {
+ (!priv->wakeup_dev_required) &&
+ (priv->connect_status != LBS_CONNECTED)) {
+ struct cmd_header cmd;
+
lbs_deb_main("Entering auto deep sleep mode...\n");
- ret = lbs_prepare_and_send_command(priv,
- CMD_802_11_DEEP_SLEEP, 0,
- 0, 0, NULL);
- if (ret)
- lbs_pr_err("Enter Deep Sleep command failed\n");
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.size = cpu_to_le16(sizeof(cmd));
+ lbs_cmd_async(priv, CMD_802_11_DEEP_SLEEP, &cmd,
+ sizeof(cmd));
}
}
mod_timer(&priv->auto_deepsleep_timer , jiffies +
@@ -799,45 +702,27 @@ int lbs_exit_auto_deep_sleep(struct lbs_private *priv)
static int lbs_init_adapter(struct lbs_private *priv)
{
- size_t bufsize;
- int i, ret = 0;
+ int ret;
lbs_deb_enter(LBS_DEB_MAIN);
- /* Allocate buffer to store the BSSID list */
- bufsize = MAX_NETWORK_COUNT * sizeof(struct bss_descriptor);
- priv->networks = kzalloc(bufsize, GFP_KERNEL);
- if (!priv->networks) {
- lbs_pr_err("Out of memory allocating beacons\n");
- ret = -1;
- goto out;
- }
-
- /* Initialize scan result lists */
- INIT_LIST_HEAD(&priv->network_free_list);
- INIT_LIST_HEAD(&priv->network_list);
- for (i = 0; i < MAX_NETWORK_COUNT; i++) {
- list_add_tail(&priv->networks[i].list,
- &priv->network_free_list);
- }
-
memset(priv->current_addr, 0xff, ETH_ALEN);
priv->connect_status = LBS_DISCONNECTED;
- priv->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM;
- priv->mode = IW_MODE_INFRA;
priv->channel = DEFAULT_AD_HOC_CHANNEL;
priv->mac_control = CMD_ACT_MAC_RX_ON | CMD_ACT_MAC_TX_ON;
priv->radio_on = 1;
- priv->enablehwauto = 1;
priv->psmode = LBS802_11POWERMODECAM;
priv->psstate = PS_STATE_FULL_POWER;
priv->is_deep_sleep = 0;
priv->is_auto_deep_sleep_enabled = 0;
+ priv->deep_sleep_required = 0;
priv->wakeup_dev_required = 0;
init_waitqueue_head(&priv->ds_awake_q);
priv->authtype_auto = 1;
-
+ priv->is_host_sleep_configured = 0;
+ priv->is_host_sleep_activated = 0;
+ init_waitqueue_head(&priv->host_sleep_q);
mutex_init(&priv->lock);
setup_timer(&priv->command_timer, lbs_cmd_timeout_handler,
@@ -849,7 +734,6 @@ static int lbs_init_adapter(struct lbs_private *priv)
INIT_LIST_HEAD(&priv->cmdpendingq);
spin_lock_init(&priv->driver_lock);
- init_waitqueue_head(&priv->cmd_pending);
/* Allocate the command buffers */
if (lbs_allocate_cmd_buffer(priv)) {
@@ -881,8 +765,6 @@ static void lbs_free_adapter(struct lbs_private *priv)
kfifo_free(&priv->event_fifo);
del_timer(&priv->command_timer);
del_timer(&priv->auto_deepsleep_timer);
- kfree(priv->networks);
- priv->networks = NULL;
lbs_deb_leave(LBS_DEB_MAIN);
}
@@ -919,7 +801,7 @@ struct lbs_private *lbs_add_card(void *card, struct device *dmdev)
lbs_pr_err("cfg80211 init failed\n");
goto done;
}
- /* TODO? */
+
wdev->iftype = NL80211_IFTYPE_STATION;
priv = wdev_priv(wdev);
priv->wdev = wdev;
@@ -929,7 +811,6 @@ struct lbs_private *lbs_add_card(void *card, struct device *dmdev)
goto err_wdev;
}
- //TODO? dev = alloc_netdev_mq(0, "wlan%d", ether_setup, IWM_TX_QUEUES);
dev = alloc_netdev(0, "wlan%d", ether_setup);
if (!dev) {
dev_err(dmdev, "no memory for network device instance\n");
@@ -945,20 +826,10 @@ struct lbs_private *lbs_add_card(void *card, struct device *dmdev)
dev->netdev_ops = &lbs_netdev_ops;
dev->watchdog_timeo = 5 * HZ;
dev->ethtool_ops = &lbs_ethtool_ops;
-#ifdef WIRELESS_EXT
- dev->wireless_handlers = &lbs_handler_def;
-#endif
dev->flags |= IFF_BROADCAST | IFF_MULTICAST;
-
- // TODO: kzalloc + iwm_init_default_profile(iwm, iwm->umac_profile); ??
-
-
priv->card = card;
- priv->infra_open = 0;
-
- priv->rtap_net_dev = NULL;
strcpy(dev->name, "wlan%d");
lbs_deb_thread("Starting main thread...\n");
@@ -970,12 +841,11 @@ struct lbs_private *lbs_add_card(void *card, struct device *dmdev)
}
priv->work_thread = create_singlethread_workqueue("lbs_worker");
- INIT_DELAYED_WORK(&priv->assoc_work, lbs_association_worker);
- INIT_DELAYED_WORK(&priv->scan_work, lbs_scan_worker);
INIT_WORK(&priv->mcast_work, lbs_set_mcast_worker);
priv->wol_criteria = 0xffffffff;
priv->wol_gpio = 0xff;
+ priv->wol_gap = 20;
goto done;
@@ -1004,12 +874,10 @@ void lbs_remove_card(struct lbs_private *priv)
lbs_deb_enter(LBS_DEB_MAIN);
lbs_remove_mesh(priv);
- lbs_remove_rtap(priv);
+ lbs_scan_deinit(priv);
dev = priv->dev;
- cancel_delayed_work_sync(&priv->scan_work);
- cancel_delayed_work_sync(&priv->assoc_work);
cancel_work_sync(&priv->mcast_work);
/* worker thread destruction blocks on the in-flight command which
@@ -1021,16 +889,18 @@ void lbs_remove_card(struct lbs_private *priv)
if (priv->psmode == LBS802_11POWERMODEMAX_PSP) {
priv->psmode = LBS802_11POWERMODECAM;
- lbs_ps_wakeup(priv, CMD_OPTION_WAITFORRSP);
+ lbs_set_ps_mode(priv, PS_MODE_ACTION_EXIT_PS, true);
}
- lbs_send_disconnect_notification(priv);
-
if (priv->is_deep_sleep) {
priv->is_deep_sleep = 0;
wake_up_interruptible(&priv->ds_awake_q);
}
+ priv->is_host_sleep_configured = 0;
+ priv->is_host_sleep_activated = 0;
+ wake_up_interruptible(&priv->host_sleep_q);
+
/* Stop the thread servicing the interrupts */
priv->surpriseremoved = 1;
kthread_stop(priv->main_thread);
@@ -1046,7 +916,7 @@ void lbs_remove_card(struct lbs_private *priv)
EXPORT_SYMBOL_GPL(lbs_remove_card);
-static int lbs_rtap_supported(struct lbs_private *priv)
+int lbs_rtap_supported(struct lbs_private *priv)
{
if (MRVL_FW_MAJOR_REV(priv->fwrelease) == MRVL_FW_V5)
return 1;
@@ -1078,16 +948,6 @@ int lbs_start_card(struct lbs_private *priv)
lbs_init_mesh(priv);
- /*
- * While rtap isn't related to mesh, only mesh-enabled
- * firmware implements the rtap functionality via
- * CMD_802_11_MONITOR_MODE.
- */
- if (lbs_rtap_supported(priv)) {
- if (device_create_file(&dev->dev, &dev_attr_lbs_rtap))
- lbs_pr_err("cannot register lbs_rtap attribute\n");
- }
-
lbs_debugfs_init_one(priv, dev);
lbs_pr_info("%s: Marvell WLAN 802.11 adapter\n", dev->name);
@@ -1119,9 +979,6 @@ void lbs_stop_card(struct lbs_private *priv)
lbs_debugfs_remove_one(priv);
lbs_deinit_mesh(priv);
- if (lbs_rtap_supported(priv))
- device_remove_file(&dev->dev, &dev_attr_lbs_rtap);
-
/* Delete the timeout of the currently processing command */
del_timer_sync(&priv->command_timer);
del_timer_sync(&priv->auto_deepsleep_timer);
@@ -1195,7 +1052,7 @@ static int __init lbs_init_module(void)
memset(&confirm_sleep, 0, sizeof(confirm_sleep));
confirm_sleep.hdr.command = cpu_to_le16(CMD_802_11_PS_MODE);
confirm_sleep.hdr.size = cpu_to_le16(sizeof(confirm_sleep));
- confirm_sleep.action = cpu_to_le16(CMD_SUBCMD_SLEEP_CONFIRMED);
+ confirm_sleep.action = cpu_to_le16(PS_MODE_ACTION_SLEEP_CONFIRMED);
lbs_debugfs_init();
lbs_deb_leave(LBS_DEB_MAIN);
return 0;
@@ -1208,87 +1065,6 @@ static void __exit lbs_exit_module(void)
lbs_deb_leave(LBS_DEB_MAIN);
}
-/*
- * rtap interface support fuctions
- */
-
-static int lbs_rtap_open(struct net_device *dev)
-{
- /* Yes, _stop_ the queue. Because we don't support injection */
- lbs_deb_enter(LBS_DEB_MAIN);
- netif_carrier_off(dev);
- netif_stop_queue(dev);
- lbs_deb_leave(LBS_DEB_LEAVE);
- return 0;
-}
-
-static int lbs_rtap_stop(struct net_device *dev)
-{
- lbs_deb_enter(LBS_DEB_MAIN);
- lbs_deb_leave(LBS_DEB_MAIN);
- return 0;
-}
-
-static netdev_tx_t lbs_rtap_hard_start_xmit(struct sk_buff *skb,
- struct net_device *dev)
-{
- netif_stop_queue(dev);
- return NETDEV_TX_BUSY;
-}
-
-static void lbs_remove_rtap(struct lbs_private *priv)
-{
- lbs_deb_enter(LBS_DEB_MAIN);
- if (priv->rtap_net_dev == NULL)
- goto out;
- unregister_netdev(priv->rtap_net_dev);
- free_netdev(priv->rtap_net_dev);
- priv->rtap_net_dev = NULL;
-out:
- lbs_deb_leave(LBS_DEB_MAIN);
-}
-
-static const struct net_device_ops rtap_netdev_ops = {
- .ndo_open = lbs_rtap_open,
- .ndo_stop = lbs_rtap_stop,
- .ndo_start_xmit = lbs_rtap_hard_start_xmit,
-};
-
-static int lbs_add_rtap(struct lbs_private *priv)
-{
- int ret = 0;
- struct net_device *rtap_dev;
-
- lbs_deb_enter(LBS_DEB_MAIN);
- if (priv->rtap_net_dev) {
- ret = -EPERM;
- goto out;
- }
-
- rtap_dev = alloc_netdev(0, "rtap%d", ether_setup);
- if (rtap_dev == NULL) {
- ret = -ENOMEM;
- goto out;
- }
-
- memcpy(rtap_dev->dev_addr, priv->current_addr, ETH_ALEN);
- rtap_dev->type = ARPHRD_IEEE80211_RADIOTAP;
- rtap_dev->netdev_ops = &rtap_netdev_ops;
- rtap_dev->ml_priv = priv;
- SET_NETDEV_DEV(rtap_dev, priv->dev->dev.parent);
-
- ret = register_netdev(rtap_dev);
- if (ret) {
- free_netdev(rtap_dev);
- goto out;
- }
- priv->rtap_net_dev = rtap_dev;
-
-out:
- lbs_deb_leave_args(LBS_DEB_MAIN, "ret %d", ret);
- return ret;
-}
-
module_init(lbs_init_module);
module_exit(lbs_exit_module);
diff --git a/drivers/net/wireless/libertas/mesh.c b/drivers/net/wireless/libertas/mesh.c
index e385af1f458..194762ab014 100644
--- a/drivers/net/wireless/libertas/mesh.c
+++ b/drivers/net/wireless/libertas/mesh.c
@@ -5,6 +5,7 @@
#include <linux/if_arp.h>
#include <linux/kthread.h>
#include <linux/kfifo.h>
+#include <net/cfg80211.h>
#include "mesh.h"
#include "decl.h"
@@ -314,7 +315,7 @@ static int lbs_mesh_dev_open(struct net_device *dev)
spin_lock_irq(&priv->driver_lock);
- if (priv->monitormode) {
+ if (priv->wdev->iftype == NL80211_IFTYPE_MONITOR) {
ret = -EBUSY;
goto out;
}
@@ -369,9 +370,6 @@ int lbs_add_mesh(struct lbs_private *priv)
SET_NETDEV_DEV(priv->mesh_dev, priv->dev->dev.parent);
-#ifdef WIRELESS_EXT
- mesh_dev->wireless_handlers = &mesh_handler_def;
-#endif
mesh_dev->flags |= IFF_BROADCAST | IFF_MULTICAST;
/* Register virtual mesh interface */
ret = register_netdev(mesh_dev);
@@ -457,65 +455,189 @@ void lbs_mesh_set_txpd(struct lbs_private *priv,
* Mesh command handling
*/
-int lbs_cmd_bt_access(struct cmd_ds_command *cmd,
- u16 cmd_action, void *pdata_buf)
+/**
+ * @brief Add or delete Mesh Blinding Table entries
+ *
+ * @param priv A pointer to struct lbs_private structure
+ * @param add TRUE to add the entry, FALSE to delete it
+ * @param addr1 Destination address to blind or unblind
+ *
+ * @return 0 on success, error on failure
+ */
+int lbs_mesh_bt_add_del(struct lbs_private *priv, bool add, u8 *addr1)
{
- struct cmd_ds_bt_access *bt_access = &cmd->params.bt;
- lbs_deb_enter_args(LBS_DEB_CMD, "action %d", cmd_action);
+ struct cmd_ds_bt_access cmd;
+ int ret = 0;
- cmd->command = cpu_to_le16(CMD_BT_ACCESS);
- cmd->size = cpu_to_le16(sizeof(struct cmd_ds_bt_access) +
- sizeof(struct cmd_header));
- cmd->result = 0;
- bt_access->action = cpu_to_le16(cmd_action);
+ lbs_deb_enter(LBS_DEB_CMD);
- switch (cmd_action) {
- case CMD_ACT_BT_ACCESS_ADD:
- memcpy(bt_access->addr1, pdata_buf, 2 * ETH_ALEN);
+ BUG_ON(addr1 == NULL);
+
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.hdr.size = cpu_to_le16(sizeof(cmd));
+ memcpy(cmd.addr1, addr1, ETH_ALEN);
+ if (add) {
+ cmd.action = cpu_to_le16(CMD_ACT_BT_ACCESS_ADD);
lbs_deb_hex(LBS_DEB_MESH, "BT_ADD: blinded MAC addr",
- bt_access->addr1, 6);
- break;
- case CMD_ACT_BT_ACCESS_DEL:
- memcpy(bt_access->addr1, pdata_buf, 1 * ETH_ALEN);
+ addr1, ETH_ALEN);
+ } else {
+ cmd.action = cpu_to_le16(CMD_ACT_BT_ACCESS_DEL);
lbs_deb_hex(LBS_DEB_MESH, "BT_DEL: blinded MAC addr",
- bt_access->addr1, 6);
- break;
- case CMD_ACT_BT_ACCESS_LIST:
- bt_access->id = cpu_to_le32(*(u32 *) pdata_buf);
- break;
- case CMD_ACT_BT_ACCESS_RESET:
- break;
- case CMD_ACT_BT_ACCESS_SET_INVERT:
- bt_access->id = cpu_to_le32(*(u32 *) pdata_buf);
- break;
- case CMD_ACT_BT_ACCESS_GET_INVERT:
- break;
- default:
- break;
+ addr1, ETH_ALEN);
}
- lbs_deb_leave(LBS_DEB_CMD);
- return 0;
+
+ ret = lbs_cmd_with_response(priv, CMD_BT_ACCESS, &cmd);
+
+ lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
+ return ret;
}
-int lbs_cmd_fwt_access(struct cmd_ds_command *cmd,
- u16 cmd_action, void *pdata_buf)
+/**
+ * @brief Reset/clear the mesh blinding table
+ *
+ * @param priv A pointer to struct lbs_private structure
+ *
+ * @return 0 on success, error on failure
+ */
+int lbs_mesh_bt_reset(struct lbs_private *priv)
{
- struct cmd_ds_fwt_access *fwt_access = &cmd->params.fwt;
- lbs_deb_enter_args(LBS_DEB_CMD, "action %d", cmd_action);
+ struct cmd_ds_bt_access cmd;
+ int ret = 0;
- cmd->command = cpu_to_le16(CMD_FWT_ACCESS);
- cmd->size = cpu_to_le16(sizeof(struct cmd_ds_fwt_access) +
- sizeof(struct cmd_header));
- cmd->result = 0;
+ lbs_deb_enter(LBS_DEB_CMD);
- if (pdata_buf)
- memcpy(fwt_access, pdata_buf, sizeof(*fwt_access));
- else
- memset(fwt_access, 0, sizeof(*fwt_access));
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.hdr.size = cpu_to_le16(sizeof(cmd));
+ cmd.action = cpu_to_le16(CMD_ACT_BT_ACCESS_RESET);
- fwt_access->action = cpu_to_le16(cmd_action);
+ ret = lbs_cmd_with_response(priv, CMD_BT_ACCESS, &cmd);
- lbs_deb_leave(LBS_DEB_CMD);
+ lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
+ return ret;
+}
+
+/**
+ * @brief Gets the inverted status of the mesh blinding table
+ *
+ * Normally the firmware "blinds" or ignores traffic from mesh nodes in the
+ * table, but an inverted table allows *only* traffic from nodes listed in
+ * the table.
+ *
+ * @param priv A pointer to struct lbs_private structure
+ * @param invert On success, TRUE if the blinding table is inverted,
+ * FALSE if it is not inverted
+ *
+ * @return 0 on success, error on failure
+ */
+int lbs_mesh_bt_get_inverted(struct lbs_private *priv, bool *inverted)
+{
+ struct cmd_ds_bt_access cmd;
+ int ret = 0;
+
+ lbs_deb_enter(LBS_DEB_CMD);
+
+ BUG_ON(inverted == NULL);
+
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.hdr.size = cpu_to_le16(sizeof(cmd));
+ cmd.action = cpu_to_le16(CMD_ACT_BT_ACCESS_GET_INVERT);
+
+ ret = lbs_cmd_with_response(priv, CMD_BT_ACCESS, &cmd);
+ if (ret == 0)
+ *inverted = !!cmd.id;
+
+ lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
+ return ret;
+}
+
+/**
+ * @brief Sets the inverted status of the mesh blinding table
+ *
+ * Normally the firmware "blinds" or ignores traffic from mesh nodes in the
+ * table, but an inverted table allows *only* traffic from nodes listed in
+ * the table.
+ *
+ * @param priv A pointer to struct lbs_private structure
+ * @param invert TRUE to invert the blinding table (only traffic from
+ * listed nodes allowed), FALSE to return it
+ * to normal state (listed nodes ignored)
+ *
+ * @return 0 on success, error on failure
+ */
+int lbs_mesh_bt_set_inverted(struct lbs_private *priv, bool inverted)
+{
+ struct cmd_ds_bt_access cmd;
+ int ret = 0;
+
+ lbs_deb_enter(LBS_DEB_CMD);
+
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.hdr.size = cpu_to_le16(sizeof(cmd));
+ cmd.action = cpu_to_le16(CMD_ACT_BT_ACCESS_SET_INVERT);
+ cmd.id = !!inverted;
+
+ ret = lbs_cmd_with_response(priv, CMD_BT_ACCESS, &cmd);
+
+ lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
+ return ret;
+}
+
+/**
+ * @brief List an entry in the mesh blinding table
+ *
+ * @param priv A pointer to struct lbs_private structure
+ * @param id The ID of the entry to list
+ * @param addr1 MAC address associated with the table entry
+ *
+ * @return 0 on success, error on failure
+ */
+int lbs_mesh_bt_get_entry(struct lbs_private *priv, u32 id, u8 *addr1)
+{
+ struct cmd_ds_bt_access cmd;
+ int ret = 0;
+
+ lbs_deb_enter(LBS_DEB_CMD);
+
+ BUG_ON(addr1 == NULL);
+
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.hdr.size = cpu_to_le16(sizeof(cmd));
+ cmd.action = cpu_to_le16(CMD_ACT_BT_ACCESS_SET_INVERT);
+ cmd.id = cpu_to_le32(id);
+
+ ret = lbs_cmd_with_response(priv, CMD_BT_ACCESS, &cmd);
+ if (ret == 0)
+ memcpy(addr1, cmd.addr1, sizeof(cmd.addr1));
+
+ lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
+ return ret;
+}
+
+/**
+ * @brief Access the mesh forwarding table
+ *
+ * @param priv A pointer to struct lbs_private structure
+ * @param cmd_action The forwarding table action to perform
+ * @param cmd The pre-filled FWT_ACCESS command
+ *
+ * @return 0 on success and 'cmd' will be filled with the
+ * firmware's response
+ */
+int lbs_cmd_fwt_access(struct lbs_private *priv, u16 cmd_action,
+ struct cmd_ds_fwt_access *cmd)
+{
+ int ret;
+
+ lbs_deb_enter_args(LBS_DEB_CMD, "action %d", cmd_action);
+
+ cmd->hdr.command = cpu_to_le16(CMD_FWT_ACCESS);
+ cmd->hdr.size = cpu_to_le16(sizeof(struct cmd_ds_fwt_access));
+ cmd->hdr.result = 0;
+ cmd->action = cpu_to_le16(cmd_action);
+
+ ret = lbs_cmd_with_response(priv, CMD_FWT_ACCESS, cmd);
+
+ lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
return 0;
}
diff --git a/drivers/net/wireless/libertas/mesh.h b/drivers/net/wireless/libertas/mesh.h
index e2573303a32..afb2e8dead3 100644
--- a/drivers/net/wireless/libertas/mesh.h
+++ b/drivers/net/wireless/libertas/mesh.h
@@ -8,6 +8,7 @@
#include <net/iw_handler.h>
#include <net/lib80211.h>
+#include "host.h"
#ifdef CONFIG_LIBERTAS_MESH
@@ -51,10 +52,15 @@ struct cmd_ds_command;
struct cmd_ds_mesh_access;
struct cmd_ds_mesh_config;
-int lbs_cmd_bt_access(struct cmd_ds_command *cmd,
- u16 cmd_action, void *pdata_buf);
-int lbs_cmd_fwt_access(struct cmd_ds_command *cmd,
- u16 cmd_action, void *pdata_buf);
+int lbs_mesh_bt_add_del(struct lbs_private *priv, bool add, u8 *addr1);
+int lbs_mesh_bt_reset(struct lbs_private *priv);
+int lbs_mesh_bt_get_inverted(struct lbs_private *priv, bool *inverted);
+int lbs_mesh_bt_set_inverted(struct lbs_private *priv, bool inverted);
+int lbs_mesh_bt_get_entry(struct lbs_private *priv, u32 id, u8 *addr1);
+
+int lbs_cmd_fwt_access(struct lbs_private *priv, u16 cmd_action,
+ struct cmd_ds_fwt_access *cmd);
+
int lbs_mesh_access(struct lbs_private *priv, uint16_t cmd_action,
struct cmd_ds_mesh_access *cmd);
int lbs_mesh_config_send(struct lbs_private *priv,
@@ -70,11 +76,6 @@ void lbs_persist_config_init(struct net_device *net);
void lbs_persist_config_remove(struct net_device *net);
-/* WEXT handler */
-
-extern struct iw_handler_def mesh_handler_def;
-
-
/* Ethtool statistics */
struct ethtool_stats;
diff --git a/drivers/net/wireless/libertas/radiotap.h b/drivers/net/wireless/libertas/radiotap.h
index d16b26416e8..b3c8ea6d610 100644
--- a/drivers/net/wireless/libertas/radiotap.h
+++ b/drivers/net/wireless/libertas/radiotap.h
@@ -6,7 +6,7 @@ struct tx_radiotap_hdr {
u8 txpower;
u8 rts_retries;
u8 data_retries;
-} __attribute__ ((packed));
+} __packed;
#define TX_RADIOTAP_PRESENT ( \
(1 << IEEE80211_RADIOTAP_RATE) | \
@@ -34,7 +34,7 @@ struct rx_radiotap_hdr {
u8 flags;
u8 rate;
u8 antsignal;
-} __attribute__ ((packed));
+} __packed;
#define RX_RADIOTAP_PRESENT ( \
(1 << IEEE80211_RADIOTAP_FLAGS) | \
diff --git a/drivers/net/wireless/libertas/rx.c b/drivers/net/wireless/libertas/rx.c
index 7a377f5b766..a4d0bca9ef2 100644
--- a/drivers/net/wireless/libertas/rx.c
+++ b/drivers/net/wireless/libertas/rx.c
@@ -4,18 +4,19 @@
#include <linux/etherdevice.h>
#include <linux/slab.h>
#include <linux/types.h>
+#include <net/cfg80211.h>
+#include "defs.h"
#include "host.h"
#include "radiotap.h"
#include "decl.h"
#include "dev.h"
-#include "wext.h"
struct eth803hdr {
u8 dest_addr[6];
u8 src_addr[6];
u16 h803_len;
-} __attribute__ ((packed));
+} __packed;
struct rfc1042hdr {
u8 llc_dsap;
@@ -23,114 +24,22 @@ struct rfc1042hdr {
u8 llc_ctrl;
u8 snap_oui[3];
u16 snap_type;
-} __attribute__ ((packed));
+} __packed;
struct rxpackethdr {
struct eth803hdr eth803_hdr;
struct rfc1042hdr rfc1042_hdr;
-} __attribute__ ((packed));
+} __packed;
struct rx80211packethdr {
struct rxpd rx_pd;
void *eth80211_hdr;
-} __attribute__ ((packed));
+} __packed;
static int process_rxed_802_11_packet(struct lbs_private *priv,
struct sk_buff *skb);
/**
- * @brief This function computes the avgSNR .
- *
- * @param priv A pointer to struct lbs_private structure
- * @return avgSNR
- */
-static u8 lbs_getavgsnr(struct lbs_private *priv)
-{
- u8 i;
- u16 temp = 0;
- if (priv->numSNRNF == 0)
- return 0;
- for (i = 0; i < priv->numSNRNF; i++)
- temp += priv->rawSNR[i];
- return (u8) (temp / priv->numSNRNF);
-
-}
-
-/**
- * @brief This function computes the AvgNF
- *
- * @param priv A pointer to struct lbs_private structure
- * @return AvgNF
- */
-static u8 lbs_getavgnf(struct lbs_private *priv)
-{
- u8 i;
- u16 temp = 0;
- if (priv->numSNRNF == 0)
- return 0;
- for (i = 0; i < priv->numSNRNF; i++)
- temp += priv->rawNF[i];
- return (u8) (temp / priv->numSNRNF);
-
-}
-
-/**
- * @brief This function save the raw SNR/NF to our internel buffer
- *
- * @param priv A pointer to struct lbs_private structure
- * @param prxpd A pointer to rxpd structure of received packet
- * @return n/a
- */
-static void lbs_save_rawSNRNF(struct lbs_private *priv, struct rxpd *p_rx_pd)
-{
- if (priv->numSNRNF < DEFAULT_DATA_AVG_FACTOR)
- priv->numSNRNF++;
- priv->rawSNR[priv->nextSNRNF] = p_rx_pd->snr;
- priv->rawNF[priv->nextSNRNF] = p_rx_pd->nf;
- priv->nextSNRNF++;
- if (priv->nextSNRNF >= DEFAULT_DATA_AVG_FACTOR)
- priv->nextSNRNF = 0;
-}
-
-/**
- * @brief This function computes the RSSI in received packet.
- *
- * @param priv A pointer to struct lbs_private structure
- * @param prxpd A pointer to rxpd structure of received packet
- * @return n/a
- */
-static void lbs_compute_rssi(struct lbs_private *priv, struct rxpd *p_rx_pd)
-{
-
- lbs_deb_enter(LBS_DEB_RX);
-
- lbs_deb_rx("rxpd: SNR %d, NF %d\n", p_rx_pd->snr, p_rx_pd->nf);
- lbs_deb_rx("before computing SNR: SNR-avg = %d, NF-avg = %d\n",
- priv->SNR[TYPE_RXPD][TYPE_AVG] / AVG_SCALE,
- priv->NF[TYPE_RXPD][TYPE_AVG] / AVG_SCALE);
-
- priv->SNR[TYPE_RXPD][TYPE_NOAVG] = p_rx_pd->snr;
- priv->NF[TYPE_RXPD][TYPE_NOAVG] = p_rx_pd->nf;
- lbs_save_rawSNRNF(priv, p_rx_pd);
-
- priv->SNR[TYPE_RXPD][TYPE_AVG] = lbs_getavgsnr(priv) * AVG_SCALE;
- priv->NF[TYPE_RXPD][TYPE_AVG] = lbs_getavgnf(priv) * AVG_SCALE;
- lbs_deb_rx("after computing SNR: SNR-avg = %d, NF-avg = %d\n",
- priv->SNR[TYPE_RXPD][TYPE_AVG] / AVG_SCALE,
- priv->NF[TYPE_RXPD][TYPE_AVG] / AVG_SCALE);
-
- priv->RSSI[TYPE_RXPD][TYPE_NOAVG] =
- CAL_RSSI(priv->SNR[TYPE_RXPD][TYPE_NOAVG],
- priv->NF[TYPE_RXPD][TYPE_NOAVG]);
-
- priv->RSSI[TYPE_RXPD][TYPE_AVG] =
- CAL_RSSI(priv->SNR[TYPE_RXPD][TYPE_AVG] / AVG_SCALE,
- priv->NF[TYPE_RXPD][TYPE_AVG] / AVG_SCALE);
-
- lbs_deb_leave(LBS_DEB_RX);
-}
-
-/**
* @brief This function processes received packet and forwards it
* to kernel/upper layer
*
@@ -154,7 +63,7 @@ int lbs_process_rxed_packet(struct lbs_private *priv, struct sk_buff *skb)
skb->ip_summed = CHECKSUM_NONE;
- if (priv->monitormode)
+ if (priv->wdev->iftype == NL80211_IFTYPE_MONITOR)
return process_rxed_802_11_packet(priv, skb);
p_rx_pd = (struct rxpd *) skb->data;
@@ -225,13 +134,7 @@ int lbs_process_rxed_packet(struct lbs_private *priv, struct sk_buff *skb)
*/
skb_pull(skb, hdrchop);
- /* Take the data rate from the rxpd structure
- * only if the rate is auto
- */
- if (priv->enablehwauto)
- priv->cur_rate = lbs_fw_index_to_data_rate(p_rx_pd->rx_rate);
-
- lbs_compute_rssi(priv, p_rx_pd);
+ priv->cur_rate = lbs_fw_index_to_data_rate(p_rx_pd->rx_rate);
lbs_deb_rx("rx data: size of actual packet %d\n", skb->len);
dev->stats.rx_bytes += skb->len;
@@ -352,20 +255,18 @@ static int process_rxed_802_11_packet(struct lbs_private *priv,
pradiotap_hdr = (void *)skb_push(skb, sizeof(struct rx_radiotap_hdr));
memcpy(pradiotap_hdr, &radiotap_hdr, sizeof(struct rx_radiotap_hdr));
- /* Take the data rate from the rxpd structure
- * only if the rate is auto
- */
- if (priv->enablehwauto)
- priv->cur_rate = lbs_fw_index_to_data_rate(prxpd->rx_rate);
-
- lbs_compute_rssi(priv, prxpd);
+ priv->cur_rate = lbs_fw_index_to_data_rate(prxpd->rx_rate);
lbs_deb_rx("rx data: size of actual packet %d\n", skb->len);
dev->stats.rx_bytes += skb->len;
dev->stats.rx_packets++;
- skb->protocol = eth_type_trans(skb, priv->rtap_net_dev);
- netif_rx(skb);
+ skb->protocol = eth_type_trans(skb, priv->dev);
+
+ if (in_interrupt())
+ netif_rx(skb);
+ else
+ netif_rx_ni(skb);
ret = 0;
diff --git a/drivers/net/wireless/libertas/scan.c b/drivers/net/wireless/libertas/scan.c
deleted file mode 100644
index 24cd54b3a80..00000000000
--- a/drivers/net/wireless/libertas/scan.c
+++ /dev/null
@@ -1,1354 +0,0 @@
-/**
- * Functions implementing wlan scan IOCTL and firmware command APIs
- *
- * IOCTL handlers as well as command preperation and response routines
- * for sending scan commands to the firmware.
- */
-#include <linux/slab.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/etherdevice.h>
-#include <linux/if_arp.h>
-#include <asm/unaligned.h>
-#include <net/lib80211.h>
-
-#include "host.h"
-#include "dev.h"
-#include "scan.h"
-#include "assoc.h"
-#include "wext.h"
-#include "cmd.h"
-
-//! Approximate amount of data needed to pass a scan result back to iwlist
-#define MAX_SCAN_CELL_SIZE (IW_EV_ADDR_LEN \
- + IEEE80211_MAX_SSID_LEN \
- + IW_EV_UINT_LEN \
- + IW_EV_FREQ_LEN \
- + IW_EV_QUAL_LEN \
- + IEEE80211_MAX_SSID_LEN \
- + IW_EV_PARAM_LEN \
- + 40) /* 40 for WPAIE */
-
-//! Memory needed to store a max sized channel List TLV for a firmware scan
-#define CHAN_TLV_MAX_SIZE (sizeof(struct mrvl_ie_header) \
- + (MRVDRV_MAX_CHANNELS_PER_SCAN \
- * sizeof(struct chanscanparamset)))
-
-//! Memory needed to store a max number/size SSID TLV for a firmware scan
-#define SSID_TLV_MAX_SIZE (1 * sizeof(struct mrvl_ie_ssid_param_set))
-
-//! Maximum memory needed for a cmd_ds_802_11_scan with all TLVs at max
-#define MAX_SCAN_CFG_ALLOC (sizeof(struct cmd_ds_802_11_scan) \
- + CHAN_TLV_MAX_SIZE + SSID_TLV_MAX_SIZE)
-
-//! The maximum number of channels the firmware can scan per command
-#define MRVDRV_MAX_CHANNELS_PER_SCAN 14
-
-/**
- * @brief Number of channels to scan per firmware scan command issuance.
- *
- * Number restricted to prevent hitting the limit on the amount of scan data
- * returned in a single firmware scan command.
- */
-#define MRVDRV_CHANNELS_PER_SCAN_CMD 4
-
-//! Scan time specified in the channel TLV for each channel for passive scans
-#define MRVDRV_PASSIVE_SCAN_CHAN_TIME 100
-
-//! Scan time specified in the channel TLV for each channel for active scans
-#define MRVDRV_ACTIVE_SCAN_CHAN_TIME 100
-
-#define DEFAULT_MAX_SCAN_AGE (15 * HZ)
-
-static int lbs_ret_80211_scan(struct lbs_private *priv, unsigned long dummy,
- struct cmd_header *resp);
-
-/*********************************************************************/
-/* */
-/* Misc helper functions */
-/* */
-/*********************************************************************/
-
-/**
- * @brief Unsets the MSB on basic rates
- *
- * Scan through an array and unset the MSB for basic data rates.
- *
- * @param rates buffer of data rates
- * @param len size of buffer
- */
-static void lbs_unset_basic_rate_flags(u8 *rates, size_t len)
-{
- int i;
-
- for (i = 0; i < len; i++)
- rates[i] &= 0x7f;
-}
-
-
-static inline void clear_bss_descriptor(struct bss_descriptor *bss)
-{
- /* Don't blow away ->list, just BSS data */
- memset(bss, 0, offsetof(struct bss_descriptor, list));
-}
-
-/**
- * @brief Compare two SSIDs
- *
- * @param ssid1 A pointer to ssid to compare
- * @param ssid2 A pointer to ssid to compare
- *
- * @return 0: ssid is same, otherwise is different
- */
-int lbs_ssid_cmp(uint8_t *ssid1, uint8_t ssid1_len, uint8_t *ssid2,
- uint8_t ssid2_len)
-{
- if (ssid1_len != ssid2_len)
- return -1;
-
- return memcmp(ssid1, ssid2, ssid1_len);
-}
-
-static inline int is_same_network(struct bss_descriptor *src,
- struct bss_descriptor *dst)
-{
- /* A network is only a duplicate if the channel, BSSID, and ESSID
- * all match. We treat all <hidden> with the same BSSID and channel
- * as one network */
- return ((src->ssid_len == dst->ssid_len) &&
- (src->channel == dst->channel) &&
- !compare_ether_addr(src->bssid, dst->bssid) &&
- !memcmp(src->ssid, dst->ssid, src->ssid_len));
-}
-
-
-
-/*********************************************************************/
-/* */
-/* Region channel support */
-/* */
-/*********************************************************************/
-
-#define LBS_TX_PWR_DEFAULT 20 /*100mW */
-#define LBS_TX_PWR_US_DEFAULT 20 /*100mW */
-#define LBS_TX_PWR_JP_DEFAULT 16 /*50mW */
-#define LBS_TX_PWR_FR_DEFAULT 20 /*100mW */
-#define LBS_TX_PWR_EMEA_DEFAULT 20 /*100mW */
-
-/* Format { channel, frequency (MHz), maxtxpower } */
-/* band: 'B/G', region: USA FCC/Canada IC */
-static struct chan_freq_power channel_freq_power_US_BG[] = {
- {1, 2412, LBS_TX_PWR_US_DEFAULT},
- {2, 2417, LBS_TX_PWR_US_DEFAULT},
- {3, 2422, LBS_TX_PWR_US_DEFAULT},
- {4, 2427, LBS_TX_PWR_US_DEFAULT},
- {5, 2432, LBS_TX_PWR_US_DEFAULT},
- {6, 2437, LBS_TX_PWR_US_DEFAULT},
- {7, 2442, LBS_TX_PWR_US_DEFAULT},
- {8, 2447, LBS_TX_PWR_US_DEFAULT},
- {9, 2452, LBS_TX_PWR_US_DEFAULT},
- {10, 2457, LBS_TX_PWR_US_DEFAULT},
- {11, 2462, LBS_TX_PWR_US_DEFAULT}
-};
-
-/* band: 'B/G', region: Europe ETSI */
-static struct chan_freq_power channel_freq_power_EU_BG[] = {
- {1, 2412, LBS_TX_PWR_EMEA_DEFAULT},
- {2, 2417, LBS_TX_PWR_EMEA_DEFAULT},
- {3, 2422, LBS_TX_PWR_EMEA_DEFAULT},
- {4, 2427, LBS_TX_PWR_EMEA_DEFAULT},
- {5, 2432, LBS_TX_PWR_EMEA_DEFAULT},
- {6, 2437, LBS_TX_PWR_EMEA_DEFAULT},
- {7, 2442, LBS_TX_PWR_EMEA_DEFAULT},
- {8, 2447, LBS_TX_PWR_EMEA_DEFAULT},
- {9, 2452, LBS_TX_PWR_EMEA_DEFAULT},
- {10, 2457, LBS_TX_PWR_EMEA_DEFAULT},
- {11, 2462, LBS_TX_PWR_EMEA_DEFAULT},
- {12, 2467, LBS_TX_PWR_EMEA_DEFAULT},
- {13, 2472, LBS_TX_PWR_EMEA_DEFAULT}
-};
-
-/* band: 'B/G', region: Spain */
-static struct chan_freq_power channel_freq_power_SPN_BG[] = {
- {10, 2457, LBS_TX_PWR_DEFAULT},
- {11, 2462, LBS_TX_PWR_DEFAULT}
-};
-
-/* band: 'B/G', region: France */
-static struct chan_freq_power channel_freq_power_FR_BG[] = {
- {10, 2457, LBS_TX_PWR_FR_DEFAULT},
- {11, 2462, LBS_TX_PWR_FR_DEFAULT},
- {12, 2467, LBS_TX_PWR_FR_DEFAULT},
- {13, 2472, LBS_TX_PWR_FR_DEFAULT}
-};
-
-/* band: 'B/G', region: Japan */
-static struct chan_freq_power channel_freq_power_JPN_BG[] = {
- {1, 2412, LBS_TX_PWR_JP_DEFAULT},
- {2, 2417, LBS_TX_PWR_JP_DEFAULT},
- {3, 2422, LBS_TX_PWR_JP_DEFAULT},
- {4, 2427, LBS_TX_PWR_JP_DEFAULT},
- {5, 2432, LBS_TX_PWR_JP_DEFAULT},
- {6, 2437, LBS_TX_PWR_JP_DEFAULT},
- {7, 2442, LBS_TX_PWR_JP_DEFAULT},
- {8, 2447, LBS_TX_PWR_JP_DEFAULT},
- {9, 2452, LBS_TX_PWR_JP_DEFAULT},
- {10, 2457, LBS_TX_PWR_JP_DEFAULT},
- {11, 2462, LBS_TX_PWR_JP_DEFAULT},
- {12, 2467, LBS_TX_PWR_JP_DEFAULT},
- {13, 2472, LBS_TX_PWR_JP_DEFAULT},
- {14, 2484, LBS_TX_PWR_JP_DEFAULT}
-};
-
-/**
- * the structure for channel, frequency and power
- */
-struct region_cfp_table {
- u8 region;
- struct chan_freq_power *cfp_BG;
- int cfp_no_BG;
-};
-
-/**
- * the structure for the mapping between region and CFP
- */
-static struct region_cfp_table region_cfp_table[] = {
- {0x10, /*US FCC */
- channel_freq_power_US_BG,
- ARRAY_SIZE(channel_freq_power_US_BG),
- }
- ,
- {0x20, /*CANADA IC */
- channel_freq_power_US_BG,
- ARRAY_SIZE(channel_freq_power_US_BG),
- }
- ,
- {0x30, /*EU*/ channel_freq_power_EU_BG,
- ARRAY_SIZE(channel_freq_power_EU_BG),
- }
- ,
- {0x31, /*SPAIN*/ channel_freq_power_SPN_BG,
- ARRAY_SIZE(channel_freq_power_SPN_BG),
- }
- ,
- {0x32, /*FRANCE*/ channel_freq_power_FR_BG,
- ARRAY_SIZE(channel_freq_power_FR_BG),
- }
- ,
- {0x40, /*JAPAN*/ channel_freq_power_JPN_BG,
- ARRAY_SIZE(channel_freq_power_JPN_BG),
- }
- ,
-/*Add new region here */
-};
-
-/**
- * @brief This function finds the CFP in
- * region_cfp_table based on region and band parameter.
- *
- * @param region The region code
- * @param band The band
- * @param cfp_no A pointer to CFP number
- * @return A pointer to CFP
- */
-static struct chan_freq_power *lbs_get_region_cfp_table(u8 region, int *cfp_no)
-{
- int i, end;
-
- lbs_deb_enter(LBS_DEB_MAIN);
-
- end = ARRAY_SIZE(region_cfp_table);
-
- for (i = 0; i < end ; i++) {
- lbs_deb_main("region_cfp_table[i].region=%d\n",
- region_cfp_table[i].region);
- if (region_cfp_table[i].region == region) {
- *cfp_no = region_cfp_table[i].cfp_no_BG;
- lbs_deb_leave(LBS_DEB_MAIN);
- return region_cfp_table[i].cfp_BG;
- }
- }
-
- lbs_deb_leave_args(LBS_DEB_MAIN, "ret NULL");
- return NULL;
-}
-
-int lbs_set_regiontable(struct lbs_private *priv, u8 region, u8 band)
-{
- int ret = 0;
- int i = 0;
-
- struct chan_freq_power *cfp;
- int cfp_no;
-
- lbs_deb_enter(LBS_DEB_MAIN);
-
- memset(priv->region_channel, 0, sizeof(priv->region_channel));
-
- cfp = lbs_get_region_cfp_table(region, &cfp_no);
- if (cfp != NULL) {
- priv->region_channel[i].nrcfp = cfp_no;
- priv->region_channel[i].CFP = cfp;
- } else {
- lbs_deb_main("wrong region code %#x in band B/G\n",
- region);
- ret = -1;
- goto out;
- }
- priv->region_channel[i].valid = 1;
- priv->region_channel[i].region = region;
- priv->region_channel[i].band = band;
- i++;
-out:
- lbs_deb_leave_args(LBS_DEB_MAIN, "ret %d", ret);
- return ret;
-}
-
-
-
-
-/*********************************************************************/
-/* */
-/* Main scanning support */
-/* */
-/*********************************************************************/
-
-/**
- * @brief Create a channel list for the driver to scan based on region info
- *
- * Only used from lbs_scan_setup_scan_config()
- *
- * Use the driver region/band information to construct a comprehensive list
- * of channels to scan. This routine is used for any scan that is not
- * provided a specific channel list to scan.
- *
- * @param priv A pointer to struct lbs_private structure
- * @param scanchanlist Output parameter: resulting channel list to scan
- *
- * @return void
- */
-static int lbs_scan_create_channel_list(struct lbs_private *priv,
- struct chanscanparamset *scanchanlist)
-{
- struct region_channel *scanregion;
- struct chan_freq_power *cfp;
- int rgnidx;
- int chanidx;
- int nextchan;
- uint8_t scantype;
-
- chanidx = 0;
-
- /* Set the default scan type to the user specified type, will later
- * be changed to passive on a per channel basis if restricted by
- * regulatory requirements (11d or 11h)
- */
- scantype = CMD_SCAN_TYPE_ACTIVE;
-
- for (rgnidx = 0; rgnidx < ARRAY_SIZE(priv->region_channel); rgnidx++) {
- if (!priv->region_channel[rgnidx].valid)
- continue;
- scanregion = &priv->region_channel[rgnidx];
-
- for (nextchan = 0; nextchan < scanregion->nrcfp; nextchan++, chanidx++) {
- struct chanscanparamset *chan = &scanchanlist[chanidx];
-
- cfp = scanregion->CFP + nextchan;
-
- if (scanregion->band == BAND_B || scanregion->band == BAND_G)
- chan->radiotype = CMD_SCAN_RADIO_TYPE_BG;
-
- if (scantype == CMD_SCAN_TYPE_PASSIVE) {
- chan->maxscantime = cpu_to_le16(MRVDRV_PASSIVE_SCAN_CHAN_TIME);
- chan->chanscanmode.passivescan = 1;
- } else {
- chan->maxscantime = cpu_to_le16(MRVDRV_ACTIVE_SCAN_CHAN_TIME);
- chan->chanscanmode.passivescan = 0;
- }
-
- chan->channumber = cfp->channel;
- }
- }
- return chanidx;
-}
-
-/*
- * Add SSID TLV of the form:
- *
- * TLV-ID SSID 00 00
- * length 06 00
- * ssid 4d 4e 54 45 53 54
- */
-static int lbs_scan_add_ssid_tlv(struct lbs_private *priv, u8 *tlv)
-{
- struct mrvl_ie_ssid_param_set *ssid_tlv = (void *)tlv;
-
- ssid_tlv->header.type = cpu_to_le16(TLV_TYPE_SSID);
- ssid_tlv->header.len = cpu_to_le16(priv->scan_ssid_len);
- memcpy(ssid_tlv->ssid, priv->scan_ssid, priv->scan_ssid_len);
- return sizeof(ssid_tlv->header) + priv->scan_ssid_len;
-}
-
-/*
- * Add CHANLIST TLV of the form
- *
- * TLV-ID CHANLIST 01 01
- * length 5b 00
- * channel 1 00 01 00 00 00 64 00
- * radio type 00
- * channel 01
- * scan type 00
- * min scan time 00 00
- * max scan time 64 00
- * channel 2 00 02 00 00 00 64 00
- * channel 3 00 03 00 00 00 64 00
- * channel 4 00 04 00 00 00 64 00
- * channel 5 00 05 00 00 00 64 00
- * channel 6 00 06 00 00 00 64 00
- * channel 7 00 07 00 00 00 64 00
- * channel 8 00 08 00 00 00 64 00
- * channel 9 00 09 00 00 00 64 00
- * channel 10 00 0a 00 00 00 64 00
- * channel 11 00 0b 00 00 00 64 00
- * channel 12 00 0c 00 00 00 64 00
- * channel 13 00 0d 00 00 00 64 00
- *
- */
-static int lbs_scan_add_chanlist_tlv(uint8_t *tlv,
- struct chanscanparamset *chan_list,
- int chan_count)
-{
- size_t size = sizeof(struct chanscanparamset) *chan_count;
- struct mrvl_ie_chanlist_param_set *chan_tlv = (void *)tlv;
-
- chan_tlv->header.type = cpu_to_le16(TLV_TYPE_CHANLIST);
- memcpy(chan_tlv->chanscanparam, chan_list, size);
- chan_tlv->header.len = cpu_to_le16(size);
- return sizeof(chan_tlv->header) + size;
-}
-
-/*
- * Add RATES TLV of the form
- *
- * TLV-ID RATES 01 00
- * length 0e 00
- * rates 82 84 8b 96 0c 12 18 24 30 48 60 6c
- *
- * The rates are in lbs_bg_rates[], but for the 802.11b
- * rates the high bit isn't set.
- */
-static int lbs_scan_add_rates_tlv(uint8_t *tlv)
-{
- int i;
- struct mrvl_ie_rates_param_set *rate_tlv = (void *)tlv;
-
- rate_tlv->header.type = cpu_to_le16(TLV_TYPE_RATES);
- tlv += sizeof(rate_tlv->header);
- for (i = 0; i < MAX_RATES; i++) {
- *tlv = lbs_bg_rates[i];
- if (*tlv == 0)
- break;
- /* This code makes sure that the 802.11b rates (1 MBit/s, 2
- MBit/s, 5.5 MBit/s and 11 MBit/s get's the high bit set.
- Note that the values are MBit/s * 2, to mark them as
- basic rates so that the firmware likes it better */
- if (*tlv == 0x02 || *tlv == 0x04 ||
- *tlv == 0x0b || *tlv == 0x16)
- *tlv |= 0x80;
- tlv++;
- }
- rate_tlv->header.len = cpu_to_le16(i);
- return sizeof(rate_tlv->header) + i;
-}
-
-/*
- * Generate the CMD_802_11_SCAN command with the proper tlv
- * for a bunch of channels.
- */
-static int lbs_do_scan(struct lbs_private *priv, uint8_t bsstype,
- struct chanscanparamset *chan_list, int chan_count)
-{
- int ret = -ENOMEM;
- struct cmd_ds_802_11_scan *scan_cmd;
- uint8_t *tlv; /* pointer into our current, growing TLV storage area */
-
- lbs_deb_enter_args(LBS_DEB_SCAN, "bsstype %d, chanlist[].chan %d, chan_count %d",
- bsstype, chan_list ? chan_list[0].channumber : -1,
- chan_count);
-
- /* create the fixed part for scan command */
- scan_cmd = kzalloc(MAX_SCAN_CFG_ALLOC, GFP_KERNEL);
- if (scan_cmd == NULL)
- goto out;
-
- tlv = scan_cmd->tlvbuffer;
- /* TODO: do we need to scan for a specific BSSID?
- memcpy(scan_cmd->bssid, priv->scan_bssid, ETH_ALEN); */
- scan_cmd->bsstype = bsstype;
-
- /* add TLVs */
- if (priv->scan_ssid_len)
- tlv += lbs_scan_add_ssid_tlv(priv, tlv);
- if (chan_list && chan_count)
- tlv += lbs_scan_add_chanlist_tlv(tlv, chan_list, chan_count);
- tlv += lbs_scan_add_rates_tlv(tlv);
-
- /* This is the final data we are about to send */
- scan_cmd->hdr.size = cpu_to_le16(tlv - (uint8_t *)scan_cmd);
- lbs_deb_hex(LBS_DEB_SCAN, "SCAN_CMD", (void *)scan_cmd,
- sizeof(*scan_cmd));
- lbs_deb_hex(LBS_DEB_SCAN, "SCAN_TLV", scan_cmd->tlvbuffer,
- tlv - scan_cmd->tlvbuffer);
-
- ret = __lbs_cmd(priv, CMD_802_11_SCAN, &scan_cmd->hdr,
- le16_to_cpu(scan_cmd->hdr.size),
- lbs_ret_80211_scan, 0);
-
-out:
- kfree(scan_cmd);
- lbs_deb_leave_args(LBS_DEB_SCAN, "ret %d", ret);
- return ret;
-}
-
-/**
- * @brief Internal function used to start a scan based on an input config
- *
- * Use the input user scan configuration information when provided in
- * order to send the appropriate scan commands to firmware to populate or
- * update the internal driver scan table
- *
- * @param priv A pointer to struct lbs_private structure
- * @param full_scan Do a full-scan (blocking)
- *
- * @return 0 or < 0 if error
- */
-int lbs_scan_networks(struct lbs_private *priv, int full_scan)
-{
- int ret = -ENOMEM;
- struct chanscanparamset *chan_list;
- struct chanscanparamset *curr_chans;
- int chan_count;
- uint8_t bsstype = CMD_BSS_TYPE_ANY;
- int numchannels = MRVDRV_CHANNELS_PER_SCAN_CMD;
- union iwreq_data wrqu;
-#ifdef CONFIG_LIBERTAS_DEBUG
- struct bss_descriptor *iter;
- int i = 0;
- DECLARE_SSID_BUF(ssid);
-#endif
-
- lbs_deb_enter_args(LBS_DEB_SCAN, "full_scan %d", full_scan);
-
- /* Cancel any partial outstanding partial scans if this scan
- * is a full scan.
- */
- if (full_scan && delayed_work_pending(&priv->scan_work))
- cancel_delayed_work(&priv->scan_work);
-
- /* User-specified bsstype or channel list
- TODO: this can be implemented if some user-space application
- need the feature. Formerly, it was accessible from debugfs,
- but then nowhere used.
- if (user_cfg) {
- if (user_cfg->bsstype)
- bsstype = user_cfg->bsstype;
- } */
-
- lbs_deb_scan("numchannels %d, bsstype %d\n", numchannels, bsstype);
-
- /* Create list of channels to scan */
- chan_list = kzalloc(sizeof(struct chanscanparamset) *
- LBS_IOCTL_USER_SCAN_CHAN_MAX, GFP_KERNEL);
- if (!chan_list) {
- lbs_pr_alert("SCAN: chan_list empty\n");
- goto out;
- }
-
- /* We want to scan all channels */
- chan_count = lbs_scan_create_channel_list(priv, chan_list);
-
- netif_stop_queue(priv->dev);
- if (priv->mesh_dev)
- netif_stop_queue(priv->mesh_dev);
-
- /* Prepare to continue an interrupted scan */
- lbs_deb_scan("chan_count %d, scan_channel %d\n",
- chan_count, priv->scan_channel);
- curr_chans = chan_list;
- /* advance channel list by already-scanned-channels */
- if (priv->scan_channel > 0) {
- curr_chans += priv->scan_channel;
- chan_count -= priv->scan_channel;
- }
-
- /* Send scan command(s)
- * numchannels contains the number of channels we should maximally scan
- * chan_count is the total number of channels to scan
- */
-
- while (chan_count) {
- int to_scan = min(numchannels, chan_count);
- lbs_deb_scan("scanning %d of %d channels\n",
- to_scan, chan_count);
- ret = lbs_do_scan(priv, bsstype, curr_chans,
- to_scan);
- if (ret) {
- lbs_pr_err("SCAN_CMD failed\n");
- goto out2;
- }
- curr_chans += to_scan;
- chan_count -= to_scan;
-
- /* somehow schedule the next part of the scan */
- if (chan_count && !full_scan &&
- !priv->surpriseremoved) {
- /* -1 marks just that we're currently scanning */
- if (priv->scan_channel < 0)
- priv->scan_channel = to_scan;
- else
- priv->scan_channel += to_scan;
- cancel_delayed_work(&priv->scan_work);
- queue_delayed_work(priv->work_thread, &priv->scan_work,
- msecs_to_jiffies(300));
- /* skip over GIWSCAN event */
- goto out;
- }
-
- }
- memset(&wrqu, 0, sizeof(union iwreq_data));
- wireless_send_event(priv->dev, SIOCGIWSCAN, &wrqu, NULL);
-
-#ifdef CONFIG_LIBERTAS_DEBUG
- /* Dump the scan table */
- mutex_lock(&priv->lock);
- lbs_deb_scan("scan table:\n");
- list_for_each_entry(iter, &priv->network_list, list)
- lbs_deb_scan("%02d: BSSID %pM, RSSI %d, SSID '%s'\n",
- i++, iter->bssid, iter->rssi,
- print_ssid(ssid, iter->ssid, iter->ssid_len));
- mutex_unlock(&priv->lock);
-#endif
-
-out2:
- priv->scan_channel = 0;
-
-out:
- if (priv->connect_status == LBS_CONNECTED && !priv->tx_pending_len)
- netif_wake_queue(priv->dev);
-
- if (priv->mesh_dev && lbs_mesh_connected(priv) &&
- !priv->tx_pending_len)
- netif_wake_queue(priv->mesh_dev);
-
- kfree(chan_list);
-
- lbs_deb_leave_args(LBS_DEB_SCAN, "ret %d", ret);
- return ret;
-}
-
-void lbs_scan_worker(struct work_struct *work)
-{
- struct lbs_private *priv =
- container_of(work, struct lbs_private, scan_work.work);
-
- lbs_deb_enter(LBS_DEB_SCAN);
- lbs_scan_networks(priv, 0);
- lbs_deb_leave(LBS_DEB_SCAN);
-}
-
-
-/*********************************************************************/
-/* */
-/* Result interpretation */
-/* */
-/*********************************************************************/
-
-/**
- * @brief Interpret a BSS scan response returned from the firmware
- *
- * Parse the various fixed fields and IEs passed back for a a BSS probe
- * response or beacon from the scan command. Record information as needed
- * in the scan table struct bss_descriptor for that entry.
- *
- * @param bss Output parameter: Pointer to the BSS Entry
- *
- * @return 0 or -1
- */
-static int lbs_process_bss(struct bss_descriptor *bss,
- uint8_t **pbeaconinfo, int *bytesleft)
-{
- struct ieee_ie_fh_param_set *fh;
- struct ieee_ie_ds_param_set *ds;
- struct ieee_ie_cf_param_set *cf;
- struct ieee_ie_ibss_param_set *ibss;
- DECLARE_SSID_BUF(ssid);
- uint8_t *pos, *end, *p;
- uint8_t n_ex_rates = 0, got_basic_rates = 0, n_basic_rates = 0;
- uint16_t beaconsize = 0;
- int ret;
-
- lbs_deb_enter(LBS_DEB_SCAN);
-
- if (*bytesleft >= sizeof(beaconsize)) {
- /* Extract & convert beacon size from the command buffer */
- beaconsize = get_unaligned_le16(*pbeaconinfo);
- *bytesleft -= sizeof(beaconsize);
- *pbeaconinfo += sizeof(beaconsize);
- }
-
- if (beaconsize == 0 || beaconsize > *bytesleft) {
- *pbeaconinfo += *bytesleft;
- *bytesleft = 0;
- ret = -1;
- goto done;
- }
-
- /* Initialize the current working beacon pointer for this BSS iteration */
- pos = *pbeaconinfo;
- end = pos + beaconsize;
-
- /* Advance the return beacon pointer past the current beacon */
- *pbeaconinfo += beaconsize;
- *bytesleft -= beaconsize;
-
- memcpy(bss->bssid, pos, ETH_ALEN);
- lbs_deb_scan("process_bss: BSSID %pM\n", bss->bssid);
- pos += ETH_ALEN;
-
- if ((end - pos) < 12) {
- lbs_deb_scan("process_bss: Not enough bytes left\n");
- ret = -1;
- goto done;
- }
-
- /*
- * next 4 fields are RSSI, time stamp, beacon interval,
- * and capability information
- */
-
- /* RSSI is 1 byte long */
- bss->rssi = *pos;
- lbs_deb_scan("process_bss: RSSI %d\n", *pos);
- pos++;
-
- /* time stamp is 8 bytes long */
- pos += 8;
-
- /* beacon interval is 2 bytes long */
- bss->beaconperiod = get_unaligned_le16(pos);
- pos += 2;
-
- /* capability information is 2 bytes long */
- bss->capability = get_unaligned_le16(pos);
- lbs_deb_scan("process_bss: capabilities 0x%04x\n", bss->capability);
- pos += 2;
-
- if (bss->capability & WLAN_CAPABILITY_PRIVACY)
- lbs_deb_scan("process_bss: WEP enabled\n");
- if (bss->capability & WLAN_CAPABILITY_IBSS)
- bss->mode = IW_MODE_ADHOC;
- else
- bss->mode = IW_MODE_INFRA;
-
- /* rest of the current buffer are IE's */
- lbs_deb_scan("process_bss: IE len %zd\n", end - pos);
- lbs_deb_hex(LBS_DEB_SCAN, "process_bss: IE info", pos, end - pos);
-
- /* process variable IE */
- while (pos <= end - 2) {
- if (pos + pos[1] > end) {
- lbs_deb_scan("process_bss: error in processing IE, "
- "bytes left < IE length\n");
- break;
- }
-
- switch (pos[0]) {
- case WLAN_EID_SSID:
- bss->ssid_len = min_t(int, IEEE80211_MAX_SSID_LEN, pos[1]);
- memcpy(bss->ssid, pos + 2, bss->ssid_len);
- lbs_deb_scan("got SSID IE: '%s', len %u\n",
- print_ssid(ssid, bss->ssid, bss->ssid_len),
- bss->ssid_len);
- break;
-
- case WLAN_EID_SUPP_RATES:
- n_basic_rates = min_t(uint8_t, MAX_RATES, pos[1]);
- memcpy(bss->rates, pos + 2, n_basic_rates);
- got_basic_rates = 1;
- lbs_deb_scan("got RATES IE\n");
- break;
-
- case WLAN_EID_FH_PARAMS:
- fh = (struct ieee_ie_fh_param_set *) pos;
- memcpy(&bss->phy.fh, fh, sizeof(*fh));
- lbs_deb_scan("got FH IE\n");
- break;
-
- case WLAN_EID_DS_PARAMS:
- ds = (struct ieee_ie_ds_param_set *) pos;
- bss->channel = ds->channel;
- memcpy(&bss->phy.ds, ds, sizeof(*ds));
- lbs_deb_scan("got DS IE, channel %d\n", bss->channel);
- break;
-
- case WLAN_EID_CF_PARAMS:
- cf = (struct ieee_ie_cf_param_set *) pos;
- memcpy(&bss->ss.cf, cf, sizeof(*cf));
- lbs_deb_scan("got CF IE\n");
- break;
-
- case WLAN_EID_IBSS_PARAMS:
- ibss = (struct ieee_ie_ibss_param_set *) pos;
- bss->atimwindow = ibss->atimwindow;
- memcpy(&bss->ss.ibss, ibss, sizeof(*ibss));
- lbs_deb_scan("got IBSS IE\n");
- break;
-
- case WLAN_EID_EXT_SUPP_RATES:
- /* only process extended supported rate if data rate is
- * already found. Data rate IE should come before
- * extended supported rate IE
- */
- lbs_deb_scan("got RATESEX IE\n");
- if (!got_basic_rates) {
- lbs_deb_scan("... but ignoring it\n");
- break;
- }
-
- n_ex_rates = pos[1];
- if (n_basic_rates + n_ex_rates > MAX_RATES)
- n_ex_rates = MAX_RATES - n_basic_rates;
-
- p = bss->rates + n_basic_rates;
- memcpy(p, pos + 2, n_ex_rates);
- break;
-
- case WLAN_EID_GENERIC:
- if (pos[1] >= 4 &&
- pos[2] == 0x00 && pos[3] == 0x50 &&
- pos[4] == 0xf2 && pos[5] == 0x01) {
- bss->wpa_ie_len = min(pos[1] + 2, MAX_WPA_IE_LEN);
- memcpy(bss->wpa_ie, pos, bss->wpa_ie_len);
- lbs_deb_scan("got WPA IE\n");
- lbs_deb_hex(LBS_DEB_SCAN, "WPA IE", bss->wpa_ie,
- bss->wpa_ie_len);
- } else if (pos[1] >= MARVELL_MESH_IE_LENGTH &&
- pos[2] == 0x00 && pos[3] == 0x50 &&
- pos[4] == 0x43 && pos[5] == 0x04) {
- lbs_deb_scan("got mesh IE\n");
- bss->mesh = 1;
- } else {
- lbs_deb_scan("got generic IE: %02x:%02x:%02x:%02x, len %d\n",
- pos[2], pos[3],
- pos[4], pos[5],
- pos[1]);
- }
- break;
-
- case WLAN_EID_RSN:
- lbs_deb_scan("got RSN IE\n");
- bss->rsn_ie_len = min(pos[1] + 2, MAX_WPA_IE_LEN);
- memcpy(bss->rsn_ie, pos, bss->rsn_ie_len);
- lbs_deb_hex(LBS_DEB_SCAN, "process_bss: RSN_IE",
- bss->rsn_ie, bss->rsn_ie_len);
- break;
-
- default:
- lbs_deb_scan("got IE 0x%04x, len %d\n",
- pos[0], pos[1]);
- break;
- }
-
- pos += pos[1] + 2;
- }
-
- /* Timestamp */
- bss->last_scanned = jiffies;
- lbs_unset_basic_rate_flags(bss->rates, sizeof(bss->rates));
-
- ret = 0;
-
-done:
- lbs_deb_leave_args(LBS_DEB_SCAN, "ret %d", ret);
- return ret;
-}
-
-/**
- * @brief Send a scan command for all available channels filtered on a spec
- *
- * Used in association code and from debugfs
- *
- * @param priv A pointer to struct lbs_private structure
- * @param ssid A pointer to the SSID to scan for
- * @param ssid_len Length of the SSID
- *
- * @return 0-success, otherwise fail
- */
-int lbs_send_specific_ssid_scan(struct lbs_private *priv, uint8_t *ssid,
- uint8_t ssid_len)
-{
- DECLARE_SSID_BUF(ssid_buf);
- int ret = 0;
-
- lbs_deb_enter_args(LBS_DEB_SCAN, "SSID '%s'\n",
- print_ssid(ssid_buf, ssid, ssid_len));
-
- if (!ssid_len)
- goto out;
-
- memcpy(priv->scan_ssid, ssid, ssid_len);
- priv->scan_ssid_len = ssid_len;
-
- lbs_scan_networks(priv, 1);
- if (priv->surpriseremoved) {
- ret = -1;
- goto out;
- }
-
-out:
- lbs_deb_leave_args(LBS_DEB_SCAN, "ret %d", ret);
- return ret;
-}
-
-
-
-
-/*********************************************************************/
-/* */
-/* Support for Wireless Extensions */
-/* */
-/*********************************************************************/
-
-
-#define MAX_CUSTOM_LEN 64
-
-static inline char *lbs_translate_scan(struct lbs_private *priv,
- struct iw_request_info *info,
- char *start, char *stop,
- struct bss_descriptor *bss)
-{
- struct chan_freq_power *cfp;
- char *current_val; /* For rates */
- struct iw_event iwe; /* Temporary buffer */
- int j;
-#define PERFECT_RSSI ((uint8_t)50)
-#define WORST_RSSI ((uint8_t)0)
-#define RSSI_DIFF ((uint8_t)(PERFECT_RSSI - WORST_RSSI))
- uint8_t rssi;
-
- lbs_deb_enter(LBS_DEB_SCAN);
-
- cfp = lbs_find_cfp_by_band_and_channel(priv, 0, bss->channel);
- if (!cfp) {
- lbs_deb_scan("Invalid channel number %d\n", bss->channel);
- start = NULL;
- goto out;
- }
-
- /* First entry *MUST* be the BSSID */
- iwe.cmd = SIOCGIWAP;
- iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
- memcpy(iwe.u.ap_addr.sa_data, &bss->bssid, ETH_ALEN);
- start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_ADDR_LEN);
-
- /* SSID */
- iwe.cmd = SIOCGIWESSID;
- iwe.u.data.flags = 1;
- iwe.u.data.length = min((uint32_t) bss->ssid_len, (uint32_t) IEEE80211_MAX_SSID_LEN);
- start = iwe_stream_add_point(info, start, stop, &iwe, bss->ssid);
-
- /* Mode */
- iwe.cmd = SIOCGIWMODE;
- iwe.u.mode = bss->mode;
- start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_UINT_LEN);
-
- /* Frequency */
- iwe.cmd = SIOCGIWFREQ;
- iwe.u.freq.m = (long)cfp->freq * 100000;
- iwe.u.freq.e = 1;
- start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_FREQ_LEN);
-
- /* Add quality statistics */
- iwe.cmd = IWEVQUAL;
- iwe.u.qual.updated = IW_QUAL_ALL_UPDATED;
- iwe.u.qual.level = SCAN_RSSI(bss->rssi);
-
- rssi = iwe.u.qual.level - MRVDRV_NF_DEFAULT_SCAN_VALUE;
- iwe.u.qual.qual =
- (100 * RSSI_DIFF * RSSI_DIFF - (PERFECT_RSSI - rssi) *
- (15 * (RSSI_DIFF) + 62 * (PERFECT_RSSI - rssi))) /
- (RSSI_DIFF * RSSI_DIFF);
- if (iwe.u.qual.qual > 100)
- iwe.u.qual.qual = 100;
-
- if (priv->NF[TYPE_BEACON][TYPE_NOAVG] == 0) {
- iwe.u.qual.noise = MRVDRV_NF_DEFAULT_SCAN_VALUE;
- } else {
- iwe.u.qual.noise = CAL_NF(priv->NF[TYPE_BEACON][TYPE_NOAVG]);
- }
-
- /* Locally created ad-hoc BSSs won't have beacons if this is the
- * only station in the adhoc network; so get signal strength
- * from receive statistics.
- */
- if ((priv->mode == IW_MODE_ADHOC) && priv->adhoccreate
- && !lbs_ssid_cmp(priv->curbssparams.ssid,
- priv->curbssparams.ssid_len,
- bss->ssid, bss->ssid_len)) {
- int snr, nf;
- snr = priv->SNR[TYPE_RXPD][TYPE_AVG] / AVG_SCALE;
- nf = priv->NF[TYPE_RXPD][TYPE_AVG] / AVG_SCALE;
- iwe.u.qual.level = CAL_RSSI(snr, nf);
- }
- start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_QUAL_LEN);
-
- /* Add encryption capability */
- iwe.cmd = SIOCGIWENCODE;
- if (bss->capability & WLAN_CAPABILITY_PRIVACY) {
- iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
- } else {
- iwe.u.data.flags = IW_ENCODE_DISABLED;
- }
- iwe.u.data.length = 0;
- start = iwe_stream_add_point(info, start, stop, &iwe, bss->ssid);
-
- current_val = start + iwe_stream_lcp_len(info);
-
- iwe.cmd = SIOCGIWRATE;
- iwe.u.bitrate.fixed = 0;
- iwe.u.bitrate.disabled = 0;
- iwe.u.bitrate.value = 0;
-
- for (j = 0; j < ARRAY_SIZE(bss->rates) && bss->rates[j]; j++) {
- /* Bit rate given in 500 kb/s units */
- iwe.u.bitrate.value = bss->rates[j] * 500000;
- current_val = iwe_stream_add_value(info, start, current_val,
- stop, &iwe, IW_EV_PARAM_LEN);
- }
- if ((bss->mode == IW_MODE_ADHOC) && priv->adhoccreate
- && !lbs_ssid_cmp(priv->curbssparams.ssid,
- priv->curbssparams.ssid_len,
- bss->ssid, bss->ssid_len)) {
- iwe.u.bitrate.value = 22 * 500000;
- current_val = iwe_stream_add_value(info, start, current_val,
- stop, &iwe, IW_EV_PARAM_LEN);
- }
- /* Check if we added any event */
- if ((current_val - start) > iwe_stream_lcp_len(info))
- start = current_val;
-
- memset(&iwe, 0, sizeof(iwe));
- if (bss->wpa_ie_len) {
- char buf[MAX_WPA_IE_LEN];
- memcpy(buf, bss->wpa_ie, bss->wpa_ie_len);
- iwe.cmd = IWEVGENIE;
- iwe.u.data.length = bss->wpa_ie_len;
- start = iwe_stream_add_point(info, start, stop, &iwe, buf);
- }
-
- memset(&iwe, 0, sizeof(iwe));
- if (bss->rsn_ie_len) {
- char buf[MAX_WPA_IE_LEN];
- memcpy(buf, bss->rsn_ie, bss->rsn_ie_len);
- iwe.cmd = IWEVGENIE;
- iwe.u.data.length = bss->rsn_ie_len;
- start = iwe_stream_add_point(info, start, stop, &iwe, buf);
- }
-
- if (bss->mesh) {
- char custom[MAX_CUSTOM_LEN];
- char *p = custom;
-
- iwe.cmd = IWEVCUSTOM;
- p += snprintf(p, MAX_CUSTOM_LEN, "mesh-type: olpc");
- iwe.u.data.length = p - custom;
- if (iwe.u.data.length)
- start = iwe_stream_add_point(info, start, stop,
- &iwe, custom);
- }
-
-out:
- lbs_deb_leave_args(LBS_DEB_SCAN, "start %p", start);
- return start;
-}
-
-
-/**
- * @brief Handle Scan Network ioctl
- *
- * @param dev A pointer to net_device structure
- * @param info A pointer to iw_request_info structure
- * @param vwrq A pointer to iw_param structure
- * @param extra A pointer to extra data buf
- *
- * @return 0 --success, otherwise fail
- */
-int lbs_set_scan(struct net_device *dev, struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- DECLARE_SSID_BUF(ssid);
- struct lbs_private *priv = dev->ml_priv;
- int ret = 0;
-
- lbs_deb_enter(LBS_DEB_WEXT);
-
- if (!priv->radio_on) {
- ret = -EINVAL;
- goto out;
- }
-
- if (!netif_running(dev)) {
- ret = -ENETDOWN;
- goto out;
- }
-
- /* mac80211 does this:
- struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
- if (sdata->type != IEEE80211_IF_TYPE_xxx) {
- ret = -EOPNOTSUPP;
- goto out;
- }
- */
-
- if (wrqu->data.length == sizeof(struct iw_scan_req) &&
- wrqu->data.flags & IW_SCAN_THIS_ESSID) {
- struct iw_scan_req *req = (struct iw_scan_req *)extra;
- priv->scan_ssid_len = req->essid_len;
- memcpy(priv->scan_ssid, req->essid, priv->scan_ssid_len);
- lbs_deb_wext("set_scan, essid '%s'\n",
- print_ssid(ssid, priv->scan_ssid, priv->scan_ssid_len));
- } else {
- priv->scan_ssid_len = 0;
- }
-
- if (!delayed_work_pending(&priv->scan_work))
- queue_delayed_work(priv->work_thread, &priv->scan_work,
- msecs_to_jiffies(50));
- /* set marker that currently a scan is taking place */
- priv->scan_channel = -1;
-
- if (priv->surpriseremoved)
- ret = -EIO;
-
-out:
- lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
- return ret;
-}
-
-
-/**
- * @brief Handle Retrieve scan table ioctl
- *
- * @param dev A pointer to net_device structure
- * @param info A pointer to iw_request_info structure
- * @param dwrq A pointer to iw_point structure
- * @param extra A pointer to extra data buf
- *
- * @return 0 --success, otherwise fail
- */
-int lbs_get_scan(struct net_device *dev, struct iw_request_info *info,
- struct iw_point *dwrq, char *extra)
-{
-#define SCAN_ITEM_SIZE 128
- struct lbs_private *priv = dev->ml_priv;
- int err = 0;
- char *ev = extra;
- char *stop = ev + dwrq->length;
- struct bss_descriptor *iter_bss;
- struct bss_descriptor *safe;
-
- lbs_deb_enter(LBS_DEB_WEXT);
-
- /* iwlist should wait until the current scan is finished */
- if (priv->scan_channel)
- return -EAGAIN;
-
- /* Update RSSI if current BSS is a locally created ad-hoc BSS */
- if ((priv->mode == IW_MODE_ADHOC) && priv->adhoccreate) {
- err = lbs_prepare_and_send_command(priv, CMD_802_11_RSSI, 0,
- CMD_OPTION_WAITFORRSP, 0, NULL);
- if (err)
- goto out;
- }
-
- mutex_lock(&priv->lock);
- list_for_each_entry_safe (iter_bss, safe, &priv->network_list, list) {
- char *next_ev;
- unsigned long stale_time;
-
- if (stop - ev < SCAN_ITEM_SIZE) {
- err = -E2BIG;
- break;
- }
-
- /* For mesh device, list only mesh networks */
- if (dev == priv->mesh_dev && !iter_bss->mesh)
- continue;
-
- /* Prune old an old scan result */
- stale_time = iter_bss->last_scanned + DEFAULT_MAX_SCAN_AGE;
- if (time_after(jiffies, stale_time)) {
- list_move_tail(&iter_bss->list, &priv->network_free_list);
- clear_bss_descriptor(iter_bss);
- continue;
- }
-
- /* Translate to WE format this entry */
- next_ev = lbs_translate_scan(priv, info, ev, stop, iter_bss);
- if (next_ev == NULL)
- continue;
- ev = next_ev;
- }
- mutex_unlock(&priv->lock);
-
- dwrq->length = (ev - extra);
- dwrq->flags = 0;
-out:
- lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", err);
- return err;
-}
-
-
-
-
-/*********************************************************************/
-/* */
-/* Command execution */
-/* */
-/*********************************************************************/
-
-
-/**
- * @brief This function handles the command response of scan
- *
- * Called from handle_cmd_response() in cmdrespc.
- *
- * The response buffer for the scan command has the following
- * memory layout:
- *
- * .-----------------------------------------------------------.
- * | header (4 * sizeof(u16)): Standard command response hdr |
- * .-----------------------------------------------------------.
- * | bufsize (u16) : sizeof the BSS Description data |
- * .-----------------------------------------------------------.
- * | NumOfSet (u8) : Number of BSS Descs returned |
- * .-----------------------------------------------------------.
- * | BSSDescription data (variable, size given in bufsize) |
- * .-----------------------------------------------------------.
- * | TLV data (variable, size calculated using header->size, |
- * | bufsize and sizeof the fixed fields above) |
- * .-----------------------------------------------------------.
- *
- * @param priv A pointer to struct lbs_private structure
- * @param resp A pointer to cmd_ds_command
- *
- * @return 0 or -1
- */
-static int lbs_ret_80211_scan(struct lbs_private *priv, unsigned long dummy,
- struct cmd_header *resp)
-{
- struct cmd_ds_802_11_scan_rsp *scanresp = (void *)resp;
- struct bss_descriptor *iter_bss;
- struct bss_descriptor *safe;
- uint8_t *bssinfo;
- uint16_t scanrespsize;
- int bytesleft;
- int idx;
- int tlvbufsize;
- int ret;
-
- lbs_deb_enter(LBS_DEB_SCAN);
-
- /* Prune old entries from scan table */
- list_for_each_entry_safe (iter_bss, safe, &priv->network_list, list) {
- unsigned long stale_time = iter_bss->last_scanned + DEFAULT_MAX_SCAN_AGE;
- if (time_before(jiffies, stale_time))
- continue;
- list_move_tail (&iter_bss->list, &priv->network_free_list);
- clear_bss_descriptor(iter_bss);
- }
-
- if (scanresp->nr_sets > MAX_NETWORK_COUNT) {
- lbs_deb_scan("SCAN_RESP: too many scan results (%d, max %d)\n",
- scanresp->nr_sets, MAX_NETWORK_COUNT);
- ret = -1;
- goto done;
- }
-
- bytesleft = get_unaligned_le16(&scanresp->bssdescriptsize);
- lbs_deb_scan("SCAN_RESP: bssdescriptsize %d\n", bytesleft);
-
- scanrespsize = le16_to_cpu(resp->size);
- lbs_deb_scan("SCAN_RESP: scan results %d\n", scanresp->nr_sets);
-
- bssinfo = scanresp->bssdesc_and_tlvbuffer;
-
- /* The size of the TLV buffer is equal to the entire command response
- * size (scanrespsize) minus the fixed fields (sizeof()'s), the
- * BSS Descriptions (bssdescriptsize as bytesLef) and the command
- * response header (sizeof(struct cmd_header))
- */
- tlvbufsize = scanrespsize - (bytesleft + sizeof(scanresp->bssdescriptsize)
- + sizeof(scanresp->nr_sets)
- + sizeof(struct cmd_header));
-
- /*
- * Process each scan response returned (scanresp->nr_sets). Save
- * the information in the newbssentry and then insert into the
- * driver scan table either as an update to an existing entry
- * or as an addition at the end of the table
- */
- for (idx = 0; idx < scanresp->nr_sets && bytesleft; idx++) {
- struct bss_descriptor new;
- struct bss_descriptor *found = NULL;
- struct bss_descriptor *oldest = NULL;
-
- /* Process the data fields and IEs returned for this BSS */
- memset(&new, 0, sizeof (struct bss_descriptor));
- if (lbs_process_bss(&new, &bssinfo, &bytesleft) != 0) {
- /* error parsing the scan response, skipped */
- lbs_deb_scan("SCAN_RESP: process_bss returned ERROR\n");
- continue;
- }
-
- /* Try to find this bss in the scan table */
- list_for_each_entry (iter_bss, &priv->network_list, list) {
- if (is_same_network(iter_bss, &new)) {
- found = iter_bss;
- break;
- }
-
- if ((oldest == NULL) ||
- (iter_bss->last_scanned < oldest->last_scanned))
- oldest = iter_bss;
- }
-
- if (found) {
- /* found, clear it */
- clear_bss_descriptor(found);
- } else if (!list_empty(&priv->network_free_list)) {
- /* Pull one from the free list */
- found = list_entry(priv->network_free_list.next,
- struct bss_descriptor, list);
- list_move_tail(&found->list, &priv->network_list);
- } else if (oldest) {
- /* If there are no more slots, expire the oldest */
- found = oldest;
- clear_bss_descriptor(found);
- list_move_tail(&found->list, &priv->network_list);
- } else {
- continue;
- }
-
- lbs_deb_scan("SCAN_RESP: BSSID %pM\n", new.bssid);
-
- /* Copy the locally created newbssentry to the scan table */
- memcpy(found, &new, offsetof(struct bss_descriptor, list));
- }
-
- ret = 0;
-
-done:
- lbs_deb_leave_args(LBS_DEB_SCAN, "ret %d", ret);
- return ret;
-}
diff --git a/drivers/net/wireless/libertas/scan.h b/drivers/net/wireless/libertas/scan.h
deleted file mode 100644
index 8fb1706d752..00000000000
--- a/drivers/net/wireless/libertas/scan.h
+++ /dev/null
@@ -1,63 +0,0 @@
-/**
- * Interface for the wlan network scan routines
- *
- * Driver interface functions and type declarations for the scan module
- * implemented in scan.c.
- */
-#ifndef _LBS_SCAN_H
-#define _LBS_SCAN_H
-
-#include <net/iw_handler.h>
-
-struct lbs_private;
-
-#define MAX_NETWORK_COUNT 128
-
-/** Chan-freq-TxPower mapping table*/
-struct chan_freq_power {
- /** channel Number */
- u16 channel;
- /** frequency of this channel */
- u32 freq;
- /** Max allowed Tx power level */
- u16 maxtxpower;
- /** TRUE:channel unsupported; FLASE:supported*/
- u8 unsupported;
-};
-
-/** region-band mapping table*/
-struct region_channel {
- /** TRUE if this entry is valid */
- u8 valid;
- /** region code for US, Japan ... */
- u8 region;
- /** band B/G/A, used for BAND_CONFIG cmd */
- u8 band;
- /** Actual No. of elements in the array below */
- u8 nrcfp;
- /** chan-freq-txpower mapping table*/
- struct chan_freq_power *CFP;
-};
-
-/**
- * @brief Maximum number of channels that can be sent in a setuserscan ioctl
- */
-#define LBS_IOCTL_USER_SCAN_CHAN_MAX 50
-
-int lbs_ssid_cmp(u8 *ssid1, u8 ssid1_len, u8 *ssid2, u8 ssid2_len);
-
-int lbs_set_regiontable(struct lbs_private *priv, u8 region, u8 band);
-
-int lbs_send_specific_ssid_scan(struct lbs_private *priv, u8 *ssid,
- u8 ssid_len);
-
-int lbs_get_scan(struct net_device *dev, struct iw_request_info *info,
- struct iw_point *dwrq, char *extra);
-int lbs_set_scan(struct net_device *dev, struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra);
-
-int lbs_scan_networks(struct lbs_private *priv, int full_scan);
-
-void lbs_scan_worker(struct work_struct *work);
-
-#endif
diff --git a/drivers/net/wireless/libertas/tx.c b/drivers/net/wireless/libertas/tx.c
index a9bf658659e..8000ca6165d 100644
--- a/drivers/net/wireless/libertas/tx.c
+++ b/drivers/net/wireless/libertas/tx.c
@@ -4,13 +4,13 @@
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/sched.h>
+#include <net/cfg80211.h>
#include "host.h"
#include "radiotap.h"
#include "decl.h"
#include "defs.h"
#include "dev.h"
-#include "wext.h"
/**
* @brief This function converts Tx/Rx rates from IEEE80211_RADIOTAP_RATE
@@ -111,7 +111,7 @@ netdev_tx_t lbs_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
p802x_hdr = skb->data;
pkt_len = skb->len;
- if (dev == priv->rtap_net_dev) {
+ if (priv->wdev->iftype == NL80211_IFTYPE_MONITOR) {
struct tx_radiotap_hdr *rtap_hdr = (void *)skb->data;
/* set txpd fields from the radiotap header */
@@ -147,7 +147,7 @@ netdev_tx_t lbs_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
dev->stats.tx_packets++;
dev->stats.tx_bytes += skb->len;
- if (priv->monitormode) {
+ if (priv->wdev->iftype == NL80211_IFTYPE_MONITOR) {
/* Keep the skb to echo it back once Tx feedback is
received from FW */
skb_orphan(skb);
@@ -158,6 +158,7 @@ netdev_tx_t lbs_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
free:
dev_kfree_skb_any(skb);
}
+
unlock:
spin_unlock_irqrestore(&priv->driver_lock, flags);
wake_up(&priv->waitq);
@@ -179,7 +180,8 @@ void lbs_send_tx_feedback(struct lbs_private *priv, u32 try_count)
{
struct tx_radiotap_hdr *radiotap_hdr;
- if (!priv->monitormode || priv->currenttxskb == NULL)
+ if (priv->wdev->iftype != NL80211_IFTYPE_MONITOR ||
+ priv->currenttxskb == NULL)
return;
radiotap_hdr = (struct tx_radiotap_hdr *)priv->currenttxskb->data;
@@ -188,7 +190,7 @@ void lbs_send_tx_feedback(struct lbs_private *priv, u32 try_count)
(1 + priv->txretrycount - try_count) : 0;
priv->currenttxskb->protocol = eth_type_trans(priv->currenttxskb,
- priv->rtap_net_dev);
+ priv->dev);
netif_rx(priv->currenttxskb);
priv->currenttxskb = NULL;
diff --git a/drivers/net/wireless/libertas/types.h b/drivers/net/wireless/libertas/types.h
index 3e72c86ceca..462fbb4cb74 100644
--- a/drivers/net/wireless/libertas/types.h
+++ b/drivers/net/wireless/libertas/types.h
@@ -11,7 +11,7 @@
struct ieee_ie_header {
u8 id;
u8 len;
-} __attribute__ ((packed));
+} __packed;
struct ieee_ie_cf_param_set {
struct ieee_ie_header header;
@@ -20,19 +20,19 @@ struct ieee_ie_cf_param_set {
u8 cfpperiod;
__le16 cfpmaxduration;
__le16 cfpdurationremaining;
-} __attribute__ ((packed));
+} __packed;
struct ieee_ie_ibss_param_set {
struct ieee_ie_header header;
__le16 atimwindow;
-} __attribute__ ((packed));
+} __packed;
union ieee_ss_param_set {
struct ieee_ie_cf_param_set cf;
struct ieee_ie_ibss_param_set ibss;
-} __attribute__ ((packed));
+} __packed;
struct ieee_ie_fh_param_set {
struct ieee_ie_header header;
@@ -41,18 +41,18 @@ struct ieee_ie_fh_param_set {
u8 hopset;
u8 hoppattern;
u8 hopindex;
-} __attribute__ ((packed));
+} __packed;
struct ieee_ie_ds_param_set {
struct ieee_ie_header header;
u8 channel;
-} __attribute__ ((packed));
+} __packed;
union ieee_phy_param_set {
struct ieee_ie_fh_param_set fh;
struct ieee_ie_ds_param_set ds;
-} __attribute__ ((packed));
+} __packed;
/** TLV type ID definition */
#define PROPRIETARY_TLV_BASE_ID 0x0100
@@ -100,28 +100,28 @@ union ieee_phy_param_set {
struct mrvl_ie_header {
__le16 type;
__le16 len;
-} __attribute__ ((packed));
+} __packed;
struct mrvl_ie_data {
struct mrvl_ie_header header;
u8 Data[1];
-} __attribute__ ((packed));
+} __packed;
struct mrvl_ie_rates_param_set {
struct mrvl_ie_header header;
u8 rates[1];
-} __attribute__ ((packed));
+} __packed;
struct mrvl_ie_ssid_param_set {
struct mrvl_ie_header header;
u8 ssid[1];
-} __attribute__ ((packed));
+} __packed;
struct mrvl_ie_wildcard_ssid_param_set {
struct mrvl_ie_header header;
u8 MaxSsidlength;
u8 ssid[1];
-} __attribute__ ((packed));
+} __packed;
struct chanscanmode {
#ifdef __BIG_ENDIAN_BITFIELD
@@ -133,7 +133,7 @@ struct chanscanmode {
u8 disablechanfilt:1;
u8 reserved_2_7:6;
#endif
-} __attribute__ ((packed));
+} __packed;
struct chanscanparamset {
u8 radiotype;
@@ -141,12 +141,12 @@ struct chanscanparamset {
struct chanscanmode chanscanmode;
__le16 minscantime;
__le16 maxscantime;
-} __attribute__ ((packed));
+} __packed;
struct mrvl_ie_chanlist_param_set {
struct mrvl_ie_header header;
struct chanscanparamset chanscanparam[1];
-} __attribute__ ((packed));
+} __packed;
struct mrvl_ie_cf_param_set {
struct mrvl_ie_header header;
@@ -154,86 +154,86 @@ struct mrvl_ie_cf_param_set {
u8 cfpperiod;
__le16 cfpmaxduration;
__le16 cfpdurationremaining;
-} __attribute__ ((packed));
+} __packed;
struct mrvl_ie_ds_param_set {
struct mrvl_ie_header header;
u8 channel;
-} __attribute__ ((packed));
+} __packed;
struct mrvl_ie_rsn_param_set {
struct mrvl_ie_header header;
u8 rsnie[1];
-} __attribute__ ((packed));
+} __packed;
struct mrvl_ie_tsf_timestamp {
struct mrvl_ie_header header;
__le64 tsftable[1];
-} __attribute__ ((packed));
+} __packed;
/* v9 and later firmware only */
struct mrvl_ie_auth_type {
struct mrvl_ie_header header;
__le16 auth;
-} __attribute__ ((packed));
+} __packed;
/** Local Power capability */
struct mrvl_ie_power_capability {
struct mrvl_ie_header header;
s8 minpower;
s8 maxpower;
-} __attribute__ ((packed));
+} __packed;
/* used in CMD_802_11_SUBSCRIBE_EVENT for SNR, RSSI and Failure */
struct mrvl_ie_thresholds {
struct mrvl_ie_header header;
u8 value;
u8 freq;
-} __attribute__ ((packed));
+} __packed;
struct mrvl_ie_beacons_missed {
struct mrvl_ie_header header;
u8 beaconmissed;
u8 reserved;
-} __attribute__ ((packed));
+} __packed;
struct mrvl_ie_num_probes {
struct mrvl_ie_header header;
__le16 numprobes;
-} __attribute__ ((packed));
+} __packed;
struct mrvl_ie_bcast_probe {
struct mrvl_ie_header header;
__le16 bcastprobe;
-} __attribute__ ((packed));
+} __packed;
struct mrvl_ie_num_ssid_probe {
struct mrvl_ie_header header;
__le16 numssidprobe;
-} __attribute__ ((packed));
+} __packed;
struct led_pin {
u8 led;
u8 pin;
-} __attribute__ ((packed));
+} __packed;
struct mrvl_ie_ledgpio {
struct mrvl_ie_header header;
struct led_pin ledpin[1];
-} __attribute__ ((packed));
+} __packed;
struct led_bhv {
uint8_t firmwarestate;
uint8_t led;
uint8_t ledstate;
uint8_t ledarg;
-} __attribute__ ((packed));
+} __packed;
struct mrvl_ie_ledbhv {
struct mrvl_ie_header header;
struct led_bhv ledbhv[1];
-} __attribute__ ((packed));
+} __packed;
/* Meant to be packed as the value member of a struct ieee80211_info_element.
* Note that the len member of the ieee80211_info_element varies depending on
@@ -248,12 +248,12 @@ struct mrvl_meshie_val {
uint8_t mesh_capability;
uint8_t mesh_id_len;
uint8_t mesh_id[IEEE80211_MAX_SSID_LEN];
-} __attribute__ ((packed));
+} __packed;
struct mrvl_meshie {
u8 id, len;
struct mrvl_meshie_val val;
-} __attribute__ ((packed));
+} __packed;
struct mrvl_mesh_defaults {
__le32 bootflag;
@@ -261,6 +261,6 @@ struct mrvl_mesh_defaults {
uint8_t reserved;
__le16 channel;
struct mrvl_meshie meshie;
-} __attribute__ ((packed));
+} __packed;
#endif
diff --git a/drivers/net/wireless/libertas/wext.c b/drivers/net/wireless/libertas/wext.c
deleted file mode 100644
index f96a96031a5..00000000000
--- a/drivers/net/wireless/libertas/wext.c
+++ /dev/null
@@ -1,2353 +0,0 @@
-/**
- * This file contains ioctl functions
- */
-#include <linux/ctype.h>
-#include <linux/slab.h>
-#include <linux/delay.h>
-#include <linux/if.h>
-#include <linux/if_arp.h>
-#include <linux/wireless.h>
-#include <linux/bitops.h>
-
-#include <net/lib80211.h>
-#include <net/iw_handler.h>
-
-#include "host.h"
-#include "radiotap.h"
-#include "decl.h"
-#include "defs.h"
-#include "dev.h"
-#include "wext.h"
-#include "scan.h"
-#include "assoc.h"
-#include "cmd.h"
-
-
-static inline void lbs_postpone_association_work(struct lbs_private *priv)
-{
- if (priv->surpriseremoved)
- return;
- cancel_delayed_work(&priv->assoc_work);
- queue_delayed_work(priv->work_thread, &priv->assoc_work, HZ / 2);
-}
-
-static inline void lbs_do_association_work(struct lbs_private *priv)
-{
- if (priv->surpriseremoved)
- return;
- cancel_delayed_work(&priv->assoc_work);
- queue_delayed_work(priv->work_thread, &priv->assoc_work, 0);
-}
-
-static inline void lbs_cancel_association_work(struct lbs_private *priv)
-{
- cancel_delayed_work(&priv->assoc_work);
- kfree(priv->pending_assoc_req);
- priv->pending_assoc_req = NULL;
-}
-
-void lbs_send_disconnect_notification(struct lbs_private *priv)
-{
- union iwreq_data wrqu;
-
- memset(wrqu.ap_addr.sa_data, 0x00, ETH_ALEN);
- wrqu.ap_addr.sa_family = ARPHRD_ETHER;
- wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL);
-}
-
-static void lbs_send_iwevcustom_event(struct lbs_private *priv, s8 *str)
-{
- union iwreq_data iwrq;
- u8 buf[50];
-
- lbs_deb_enter(LBS_DEB_WEXT);
-
- memset(&iwrq, 0, sizeof(union iwreq_data));
- memset(buf, 0, sizeof(buf));
-
- snprintf(buf, sizeof(buf) - 1, "%s", str);
-
- iwrq.data.length = strlen(buf) + 1 + IW_EV_LCP_LEN;
-
- /* Send Event to upper layer */
- lbs_deb_wext("event indication string %s\n", (char *)buf);
- lbs_deb_wext("event indication length %d\n", iwrq.data.length);
- lbs_deb_wext("sending wireless event IWEVCUSTOM for %s\n", str);
-
- wireless_send_event(priv->dev, IWEVCUSTOM, &iwrq, buf);
-
- lbs_deb_leave(LBS_DEB_WEXT);
-}
-
-/**
- * @brief This function handles MIC failure event.
- *
- * @param priv A pointer to struct lbs_private structure
- * @para event the event id
- * @return n/a
- */
-void lbs_send_mic_failureevent(struct lbs_private *priv, u32 event)
-{
- char buf[50];
-
- lbs_deb_enter(LBS_DEB_CMD);
- memset(buf, 0, sizeof(buf));
-
- sprintf(buf, "%s", "MLME-MICHAELMICFAILURE.indication ");
-
- if (event == MACREG_INT_CODE_MIC_ERR_UNICAST)
- strcat(buf, "unicast ");
- else
- strcat(buf, "multicast ");
-
- lbs_send_iwevcustom_event(priv, buf);
- lbs_deb_leave(LBS_DEB_CMD);
-}
-
-/**
- * @brief Find the channel frequency power info with specific channel
- *
- * @param priv A pointer to struct lbs_private structure
- * @param band it can be BAND_A, BAND_G or BAND_B
- * @param channel the channel for looking
- * @return A pointer to struct chan_freq_power structure or NULL if not find.
- */
-struct chan_freq_power *lbs_find_cfp_by_band_and_channel(
- struct lbs_private *priv,
- u8 band,
- u16 channel)
-{
- struct chan_freq_power *cfp = NULL;
- struct region_channel *rc;
- int i, j;
-
- for (j = 0; !cfp && (j < ARRAY_SIZE(priv->region_channel)); j++) {
- rc = &priv->region_channel[j];
-
- if (!rc->valid || !rc->CFP)
- continue;
- if (rc->band != band)
- continue;
- for (i = 0; i < rc->nrcfp; i++) {
- if (rc->CFP[i].channel == channel) {
- cfp = &rc->CFP[i];
- break;
- }
- }
- }
-
- if (!cfp && channel)
- lbs_deb_wext("lbs_find_cfp_by_band_and_channel: can't find "
- "cfp by band %d / channel %d\n", band, channel);
-
- return cfp;
-}
-
-/**
- * @brief Find the channel frequency power info with specific frequency
- *
- * @param priv A pointer to struct lbs_private structure
- * @param band it can be BAND_A, BAND_G or BAND_B
- * @param freq the frequency for looking
- * @return A pointer to struct chan_freq_power structure or NULL if not find.
- */
-static struct chan_freq_power *find_cfp_by_band_and_freq(
- struct lbs_private *priv,
- u8 band,
- u32 freq)
-{
- struct chan_freq_power *cfp = NULL;
- struct region_channel *rc;
- int i, j;
-
- for (j = 0; !cfp && (j < ARRAY_SIZE(priv->region_channel)); j++) {
- rc = &priv->region_channel[j];
-
- if (!rc->valid || !rc->CFP)
- continue;
- if (rc->band != band)
- continue;
- for (i = 0; i < rc->nrcfp; i++) {
- if (rc->CFP[i].freq == freq) {
- cfp = &rc->CFP[i];
- break;
- }
- }
- }
-
- if (!cfp && freq)
- lbs_deb_wext("find_cfp_by_band_and_freql: can't find cfp by "
- "band %d / freq %d\n", band, freq);
-
- return cfp;
-}
-
-/**
- * @brief Copy active data rates based on adapter mode and status
- *
- * @param priv A pointer to struct lbs_private structure
- * @param rate The buf to return the active rates
- */
-static void copy_active_data_rates(struct lbs_private *priv, u8 *rates)
-{
- lbs_deb_enter(LBS_DEB_WEXT);
-
- if ((priv->connect_status != LBS_CONNECTED) &&
- !lbs_mesh_connected(priv))
- memcpy(rates, lbs_bg_rates, MAX_RATES);
- else
- memcpy(rates, priv->curbssparams.rates, MAX_RATES);
-
- lbs_deb_leave(LBS_DEB_WEXT);
-}
-
-static int lbs_get_name(struct net_device *dev, struct iw_request_info *info,
- char *cwrq, char *extra)
-{
-
- lbs_deb_enter(LBS_DEB_WEXT);
-
- /* We could add support for 802.11n here as needed. Jean II */
- snprintf(cwrq, IFNAMSIZ, "IEEE 802.11b/g");
-
- lbs_deb_leave(LBS_DEB_WEXT);
- return 0;
-}
-
-static int lbs_get_freq(struct net_device *dev, struct iw_request_info *info,
- struct iw_freq *fwrq, char *extra)
-{
- struct lbs_private *priv = dev->ml_priv;
- struct chan_freq_power *cfp;
-
- lbs_deb_enter(LBS_DEB_WEXT);
-
- cfp = lbs_find_cfp_by_band_and_channel(priv, 0,
- priv->channel);
-
- if (!cfp) {
- if (priv->channel)
- lbs_deb_wext("invalid channel %d\n",
- priv->channel);
- return -EINVAL;
- }
-
- fwrq->m = (long)cfp->freq * 100000;
- fwrq->e = 1;
-
- lbs_deb_wext("freq %u\n", fwrq->m);
- lbs_deb_leave(LBS_DEB_WEXT);
- return 0;
-}
-
-static int lbs_get_wap(struct net_device *dev, struct iw_request_info *info,
- struct sockaddr *awrq, char *extra)
-{
- struct lbs_private *priv = dev->ml_priv;
-
- lbs_deb_enter(LBS_DEB_WEXT);
-
- if (priv->connect_status == LBS_CONNECTED) {
- memcpy(awrq->sa_data, priv->curbssparams.bssid, ETH_ALEN);
- } else {
- memset(awrq->sa_data, 0, ETH_ALEN);
- }
- awrq->sa_family = ARPHRD_ETHER;
-
- lbs_deb_leave(LBS_DEB_WEXT);
- return 0;
-}
-
-static int lbs_set_nick(struct net_device *dev, struct iw_request_info *info,
- struct iw_point *dwrq, char *extra)
-{
- struct lbs_private *priv = dev->ml_priv;
-
- lbs_deb_enter(LBS_DEB_WEXT);
-
- /*
- * Check the size of the string
- */
-
- if (dwrq->length > 16) {
- return -E2BIG;
- }
-
- mutex_lock(&priv->lock);
- memset(priv->nodename, 0, sizeof(priv->nodename));
- memcpy(priv->nodename, extra, dwrq->length);
- mutex_unlock(&priv->lock);
-
- lbs_deb_leave(LBS_DEB_WEXT);
- return 0;
-}
-
-static int lbs_get_nick(struct net_device *dev, struct iw_request_info *info,
- struct iw_point *dwrq, char *extra)
-{
- struct lbs_private *priv = dev->ml_priv;
-
- lbs_deb_enter(LBS_DEB_WEXT);
-
- dwrq->length = strlen(priv->nodename);
- memcpy(extra, priv->nodename, dwrq->length);
- extra[dwrq->length] = '\0';
-
- dwrq->flags = 1; /* active */
-
- lbs_deb_leave(LBS_DEB_WEXT);
- return 0;
-}
-
-#ifdef CONFIG_LIBERTAS_MESH
-static int mesh_get_nick(struct net_device *dev, struct iw_request_info *info,
- struct iw_point *dwrq, char *extra)
-{
- struct lbs_private *priv = dev->ml_priv;
-
- lbs_deb_enter(LBS_DEB_WEXT);
-
- /* Use nickname to indicate that mesh is on */
-
- if (lbs_mesh_connected(priv)) {
- strncpy(extra, "Mesh", 12);
- extra[12] = '\0';
- dwrq->length = strlen(extra);
- }
-
- else {
- extra[0] = '\0';
- dwrq->length = 0;
- }
-
- lbs_deb_leave(LBS_DEB_WEXT);
- return 0;
-}
-#endif
-
-static int lbs_set_rts(struct net_device *dev, struct iw_request_info *info,
- struct iw_param *vwrq, char *extra)
-{
- int ret = 0;
- struct lbs_private *priv = dev->ml_priv;
- u32 val = vwrq->value;
-
- lbs_deb_enter(LBS_DEB_WEXT);
-
- if (vwrq->disabled)
- val = MRVDRV_RTS_MAX_VALUE;
-
- if (val > MRVDRV_RTS_MAX_VALUE) /* min rts value is 0 */
- return -EINVAL;
-
- ret = lbs_set_snmp_mib(priv, SNMP_MIB_OID_RTS_THRESHOLD, (u16) val);
-
- lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
- return ret;
-}
-
-static int lbs_get_rts(struct net_device *dev, struct iw_request_info *info,
- struct iw_param *vwrq, char *extra)
-{
- struct lbs_private *priv = dev->ml_priv;
- int ret = 0;
- u16 val = 0;
-
- lbs_deb_enter(LBS_DEB_WEXT);
-
- ret = lbs_get_snmp_mib(priv, SNMP_MIB_OID_RTS_THRESHOLD, &val);
- if (ret)
- goto out;
-
- vwrq->value = val;
- vwrq->disabled = val > MRVDRV_RTS_MAX_VALUE; /* min rts value is 0 */
- vwrq->fixed = 1;
-
-out:
- lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
- return ret;
-}
-
-static int lbs_set_frag(struct net_device *dev, struct iw_request_info *info,
- struct iw_param *vwrq, char *extra)
-{
- struct lbs_private *priv = dev->ml_priv;
- int ret = 0;
- u32 val = vwrq->value;
-
- lbs_deb_enter(LBS_DEB_WEXT);
-
- if (vwrq->disabled)
- val = MRVDRV_FRAG_MAX_VALUE;
-
- if (val < MRVDRV_FRAG_MIN_VALUE || val > MRVDRV_FRAG_MAX_VALUE)
- return -EINVAL;
-
- ret = lbs_set_snmp_mib(priv, SNMP_MIB_OID_FRAG_THRESHOLD, (u16) val);
-
- lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
- return ret;
-}
-
-static int lbs_get_frag(struct net_device *dev, struct iw_request_info *info,
- struct iw_param *vwrq, char *extra)
-{
- struct lbs_private *priv = dev->ml_priv;
- int ret = 0;
- u16 val = 0;
-
- lbs_deb_enter(LBS_DEB_WEXT);
-
- ret = lbs_get_snmp_mib(priv, SNMP_MIB_OID_FRAG_THRESHOLD, &val);
- if (ret)
- goto out;
-
- vwrq->value = val;
- vwrq->disabled = ((val < MRVDRV_FRAG_MIN_VALUE)
- || (val > MRVDRV_FRAG_MAX_VALUE));
- vwrq->fixed = 1;
-
-out:
- lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
- return ret;
-}
-
-static int lbs_get_mode(struct net_device *dev,
- struct iw_request_info *info, u32 * uwrq, char *extra)
-{
- struct lbs_private *priv = dev->ml_priv;
-
- lbs_deb_enter(LBS_DEB_WEXT);
-
- *uwrq = priv->mode;
-
- lbs_deb_leave(LBS_DEB_WEXT);
- return 0;
-}
-
-#ifdef CONFIG_LIBERTAS_MESH
-static int mesh_wlan_get_mode(struct net_device *dev,
- struct iw_request_info *info, u32 * uwrq,
- char *extra)
-{
- lbs_deb_enter(LBS_DEB_WEXT);
-
- *uwrq = IW_MODE_REPEAT;
-
- lbs_deb_leave(LBS_DEB_WEXT);
- return 0;
-}
-#endif
-
-static int lbs_get_txpow(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_param *vwrq, char *extra)
-{
- struct lbs_private *priv = dev->ml_priv;
- s16 curlevel = 0;
- int ret = 0;
-
- lbs_deb_enter(LBS_DEB_WEXT);
-
- if (!priv->radio_on) {
- lbs_deb_wext("tx power off\n");
- vwrq->value = 0;
- vwrq->disabled = 1;
- goto out;
- }
-
- ret = lbs_get_tx_power(priv, &curlevel, NULL, NULL);
- if (ret)
- goto out;
-
- lbs_deb_wext("tx power level %d dbm\n", curlevel);
- priv->txpower_cur = curlevel;
-
- vwrq->value = curlevel;
- vwrq->fixed = 1;
- vwrq->disabled = 0;
- vwrq->flags = IW_TXPOW_DBM;
-
-out:
- lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
- return ret;
-}
-
-static int lbs_set_retry(struct net_device *dev, struct iw_request_info *info,
- struct iw_param *vwrq, char *extra)
-{
- struct lbs_private *priv = dev->ml_priv;
- int ret = 0;
- u16 slimit = 0, llimit = 0;
-
- lbs_deb_enter(LBS_DEB_WEXT);
-
- if ((vwrq->flags & IW_RETRY_TYPE) != IW_RETRY_LIMIT)
- return -EOPNOTSUPP;
-
- /* The MAC has a 4-bit Total_Tx_Count register
- Total_Tx_Count = 1 + Tx_Retry_Count */
-#define TX_RETRY_MIN 0
-#define TX_RETRY_MAX 14
- if (vwrq->value < TX_RETRY_MIN || vwrq->value > TX_RETRY_MAX)
- return -EINVAL;
-
- /* Add 1 to convert retry count to try count */
- if (vwrq->flags & IW_RETRY_SHORT)
- slimit = (u16) (vwrq->value + 1);
- else if (vwrq->flags & IW_RETRY_LONG)
- llimit = (u16) (vwrq->value + 1);
- else
- slimit = llimit = (u16) (vwrq->value + 1); /* set both */
-
- if (llimit) {
- ret = lbs_set_snmp_mib(priv, SNMP_MIB_OID_LONG_RETRY_LIMIT,
- llimit);
- if (ret)
- goto out;
- }
-
- if (slimit) {
- /* txretrycount follows the short retry limit */
- priv->txretrycount = slimit;
- ret = lbs_set_snmp_mib(priv, SNMP_MIB_OID_SHORT_RETRY_LIMIT,
- slimit);
- if (ret)
- goto out;
- }
-
-out:
- lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
- return ret;
-}
-
-static int lbs_get_retry(struct net_device *dev, struct iw_request_info *info,
- struct iw_param *vwrq, char *extra)
-{
- struct lbs_private *priv = dev->ml_priv;
- int ret = 0;
- u16 val = 0;
-
- lbs_deb_enter(LBS_DEB_WEXT);
-
- vwrq->disabled = 0;
-
- if (vwrq->flags & IW_RETRY_LONG) {
- ret = lbs_get_snmp_mib(priv, SNMP_MIB_OID_LONG_RETRY_LIMIT, &val);
- if (ret)
- goto out;
-
- /* Subtract 1 to convert try count to retry count */
- vwrq->value = val - 1;
- vwrq->flags = IW_RETRY_LIMIT | IW_RETRY_LONG;
- } else {
- ret = lbs_get_snmp_mib(priv, SNMP_MIB_OID_SHORT_RETRY_LIMIT, &val);
- if (ret)
- goto out;
-
- /* txretry count follows the short retry limit */
- priv->txretrycount = val;
- /* Subtract 1 to convert try count to retry count */
- vwrq->value = val - 1;
- vwrq->flags = IW_RETRY_LIMIT | IW_RETRY_SHORT;
- }
-
-out:
- lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
- return ret;
-}
-
-static inline void sort_channels(struct iw_freq *freq, int num)
-{
- int i, j;
- struct iw_freq temp;
-
- for (i = 0; i < num; i++)
- for (j = i + 1; j < num; j++)
- if (freq[i].i > freq[j].i) {
- temp.i = freq[i].i;
- temp.m = freq[i].m;
-
- freq[i].i = freq[j].i;
- freq[i].m = freq[j].m;
-
- freq[j].i = temp.i;
- freq[j].m = temp.m;
- }
-}
-
-/* data rate listing
- MULTI_BANDS:
- abg a b b/g
- Infra G(12) A(8) B(4) G(12)
- Adhoc A+B(12) A(8) B(4) B(4)
-
- non-MULTI_BANDS:
- b b/g
- Infra B(4) G(12)
- Adhoc B(4) B(4)
- */
-/**
- * @brief Get Range Info
- *
- * @param dev A pointer to net_device structure
- * @param info A pointer to iw_request_info structure
- * @param vwrq A pointer to iw_param structure
- * @param extra A pointer to extra data buf
- * @return 0 --success, otherwise fail
- */
-static int lbs_get_range(struct net_device *dev, struct iw_request_info *info,
- struct iw_point *dwrq, char *extra)
-{
- int i, j;
- struct lbs_private *priv = dev->ml_priv;
- struct iw_range *range = (struct iw_range *)extra;
- struct chan_freq_power *cfp;
- u8 rates[MAX_RATES + 1];
-
- lbs_deb_enter(LBS_DEB_WEXT);
-
- dwrq->length = sizeof(struct iw_range);
- memset(range, 0, sizeof(struct iw_range));
-
- range->min_nwid = 0;
- range->max_nwid = 0;
-
- memset(rates, 0, sizeof(rates));
- copy_active_data_rates(priv, rates);
- range->num_bitrates = strnlen(rates, IW_MAX_BITRATES);
- for (i = 0; i < range->num_bitrates; i++)
- range->bitrate[i] = rates[i] * 500000;
- range->num_bitrates = i;
- lbs_deb_wext("IW_MAX_BITRATES %d, num_bitrates %d\n", IW_MAX_BITRATES,
- range->num_bitrates);
-
- range->num_frequency = 0;
-
- range->scan_capa = IW_SCAN_CAPA_ESSID;
-
- for (j = 0; (range->num_frequency < IW_MAX_FREQUENCIES)
- && (j < ARRAY_SIZE(priv->region_channel)); j++) {
- cfp = priv->region_channel[j].CFP;
- for (i = 0; (range->num_frequency < IW_MAX_FREQUENCIES)
- && priv->region_channel[j].valid
- && cfp
- && (i < priv->region_channel[j].nrcfp); i++) {
- range->freq[range->num_frequency].i =
- (long)cfp->channel;
- range->freq[range->num_frequency].m =
- (long)cfp->freq * 100000;
- range->freq[range->num_frequency].e = 1;
- cfp++;
- range->num_frequency++;
- }
- }
-
- lbs_deb_wext("IW_MAX_FREQUENCIES %d, num_frequency %d\n",
- IW_MAX_FREQUENCIES, range->num_frequency);
-
- range->num_channels = range->num_frequency;
-
- sort_channels(&range->freq[0], range->num_frequency);
-
- /*
- * Set an indication of the max TCP throughput in bit/s that we can
- * expect using this interface
- */
- if (i > 2)
- range->throughput = 5000 * 1000;
- else
- range->throughput = 1500 * 1000;
-
- range->min_rts = MRVDRV_RTS_MIN_VALUE;
- range->max_rts = MRVDRV_RTS_MAX_VALUE;
- range->min_frag = MRVDRV_FRAG_MIN_VALUE;
- range->max_frag = MRVDRV_FRAG_MAX_VALUE;
-
- range->encoding_size[0] = 5;
- range->encoding_size[1] = 13;
- range->num_encoding_sizes = 2;
- range->max_encoding_tokens = 4;
-
- /*
- * Right now we support only "iwconfig ethX power on|off"
- */
- range->pm_capa = IW_POWER_ON;
-
- /*
- * Minimum version we recommend
- */
- range->we_version_source = 15;
-
- /*
- * Version we are compiled with
- */
- range->we_version_compiled = WIRELESS_EXT;
-
- range->retry_capa = IW_RETRY_LIMIT;
- range->retry_flags = IW_RETRY_LIMIT | IW_RETRY_MAX;
-
- range->min_retry = TX_RETRY_MIN;
- range->max_retry = TX_RETRY_MAX;
-
- /*
- * Set the qual, level and noise range values
- */
- range->max_qual.qual = 100;
- range->max_qual.level = 0;
- range->max_qual.noise = 0;
- range->max_qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM;
-
- range->avg_qual.qual = 70;
- /* TODO: Find real 'good' to 'bad' threshold value for RSSI */
- range->avg_qual.level = 0;
- range->avg_qual.noise = 0;
- range->avg_qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM;
-
- range->sensitivity = 0;
-
- /* Setup the supported power level ranges */
- memset(range->txpower, 0, sizeof(range->txpower));
- range->txpower_capa = IW_TXPOW_DBM | IW_TXPOW_RANGE;
- range->txpower[0] = priv->txpower_min;
- range->txpower[1] = priv->txpower_max;
- range->num_txpower = 2;
-
- range->event_capa[0] = (IW_EVENT_CAPA_K_0 |
- IW_EVENT_CAPA_MASK(SIOCGIWAP) |
- IW_EVENT_CAPA_MASK(SIOCGIWSCAN));
- range->event_capa[1] = IW_EVENT_CAPA_K_1;
-
- if (priv->fwcapinfo & FW_CAPINFO_WPA) {
- range->enc_capa = IW_ENC_CAPA_WPA
- | IW_ENC_CAPA_WPA2
- | IW_ENC_CAPA_CIPHER_TKIP
- | IW_ENC_CAPA_CIPHER_CCMP;
- }
-
- lbs_deb_leave(LBS_DEB_WEXT);
- return 0;
-}
-
-static int lbs_set_power(struct net_device *dev, struct iw_request_info *info,
- struct iw_param *vwrq, char *extra)
-{
- struct lbs_private *priv = dev->ml_priv;
- int ret = 0;
-
- lbs_deb_enter(LBS_DEB_WEXT);
-
- if (!(priv->fwcapinfo & FW_CAPINFO_PS)) {
- if (vwrq->disabled)
- return 0;
- else
- return -EINVAL;
- }
-
- /* PS is currently supported only in Infrastructure mode
- * Remove this check if it is to be supported in IBSS mode also
- */
-
- if (vwrq->disabled) {
- priv->psmode = LBS802_11POWERMODECAM;
- if (priv->psstate != PS_STATE_FULL_POWER) {
- lbs_ps_wakeup(priv, CMD_OPTION_WAITFORRSP);
- }
-
- return 0;
- }
-
- if ((vwrq->flags & IW_POWER_TYPE) == IW_POWER_TIMEOUT) {
- lbs_deb_wext(
- "setting power timeout is not supported\n");
- return -EINVAL;
- } else if ((vwrq->flags & IW_POWER_TYPE) == IW_POWER_PERIOD) {
- vwrq->value = vwrq->value / 1000;
- if (!priv->enter_deep_sleep) {
- lbs_pr_err("deep sleep feature is not implemented "
- "for this interface driver\n");
- return -EINVAL;
- }
-
- if (priv->connect_status == LBS_CONNECTED) {
- if ((priv->is_auto_deep_sleep_enabled) &&
- (vwrq->value == -1000)) {
- lbs_exit_auto_deep_sleep(priv);
- return 0;
- } else {
- lbs_pr_err("can't use deep sleep cmd in "
- "connected state\n");
- return -EINVAL;
- }
- }
-
- if ((vwrq->value < 0) && (vwrq->value != -1000)) {
- lbs_pr_err("unknown option\n");
- return -EINVAL;
- }
-
- if (vwrq->value > 0) {
- if (!priv->is_auto_deep_sleep_enabled) {
- priv->is_activity_detected = 0;
- priv->auto_deep_sleep_timeout = vwrq->value;
- lbs_enter_auto_deep_sleep(priv);
- } else {
- priv->auto_deep_sleep_timeout = vwrq->value;
- lbs_deb_debugfs("auto deep sleep: "
- "already enabled\n");
- }
- return 0;
- } else {
- if (priv->is_auto_deep_sleep_enabled) {
- lbs_exit_auto_deep_sleep(priv);
- /* Try to exit deep sleep if auto */
- /*deep sleep disabled */
- ret = lbs_set_deep_sleep(priv, 0);
- }
- if (vwrq->value == 0)
- ret = lbs_set_deep_sleep(priv, 1);
- else if (vwrq->value == -1000)
- ret = lbs_set_deep_sleep(priv, 0);
- return ret;
- }
- }
-
- if (priv->psmode != LBS802_11POWERMODECAM) {
- return 0;
- }
-
- priv->psmode = LBS802_11POWERMODEMAX_PSP;
-
- if (priv->connect_status == LBS_CONNECTED) {
- lbs_ps_sleep(priv, CMD_OPTION_WAITFORRSP);
- }
-
- lbs_deb_leave(LBS_DEB_WEXT);
-
- return 0;
-}
-
-static int lbs_get_power(struct net_device *dev, struct iw_request_info *info,
- struct iw_param *vwrq, char *extra)
-{
- struct lbs_private *priv = dev->ml_priv;
-
- lbs_deb_enter(LBS_DEB_WEXT);
-
- vwrq->value = 0;
- vwrq->flags = 0;
- vwrq->disabled = priv->psmode == LBS802_11POWERMODECAM
- || priv->connect_status == LBS_DISCONNECTED;
-
- lbs_deb_leave(LBS_DEB_WEXT);
- return 0;
-}
-
-static struct iw_statistics *lbs_get_wireless_stats(struct net_device *dev)
-{
- enum {
- POOR = 30,
- FAIR = 60,
- GOOD = 80,
- VERY_GOOD = 90,
- EXCELLENT = 95,
- PERFECT = 100
- };
- struct lbs_private *priv = dev->ml_priv;
- u32 rssi_qual;
- u32 tx_qual;
- u32 quality = 0;
- int ret, stats_valid = 0;
- u8 rssi;
- u32 tx_retries;
- struct cmd_ds_802_11_get_log log;
-
- lbs_deb_enter(LBS_DEB_WEXT);
-
- priv->wstats.status = priv->mode;
-
- /* If we're not associated, all quality values are meaningless */
- if ((priv->connect_status != LBS_CONNECTED) &&
- !lbs_mesh_connected(priv))
- goto out;
-
- /* Quality by RSSI */
- priv->wstats.qual.level =
- CAL_RSSI(priv->SNR[TYPE_BEACON][TYPE_NOAVG],
- priv->NF[TYPE_BEACON][TYPE_NOAVG]);
-
- if (priv->NF[TYPE_BEACON][TYPE_NOAVG] == 0) {
- priv->wstats.qual.noise = MRVDRV_NF_DEFAULT_SCAN_VALUE;
- } else {
- priv->wstats.qual.noise =
- CAL_NF(priv->NF[TYPE_BEACON][TYPE_NOAVG]);
- }
-
- lbs_deb_wext("signal level %#x\n", priv->wstats.qual.level);
- lbs_deb_wext("noise %#x\n", priv->wstats.qual.noise);
-
- rssi = priv->wstats.qual.level - priv->wstats.qual.noise;
- if (rssi < 15)
- rssi_qual = rssi * POOR / 10;
- else if (rssi < 20)
- rssi_qual = (rssi - 15) * (FAIR - POOR) / 5 + POOR;
- else if (rssi < 30)
- rssi_qual = (rssi - 20) * (GOOD - FAIR) / 5 + FAIR;
- else if (rssi < 40)
- rssi_qual = (rssi - 30) * (VERY_GOOD - GOOD) /
- 10 + GOOD;
- else
- rssi_qual = (rssi - 40) * (PERFECT - VERY_GOOD) /
- 10 + VERY_GOOD;
- quality = rssi_qual;
-
- /* Quality by TX errors */
- priv->wstats.discard.retries = dev->stats.tx_errors;
-
- memset(&log, 0, sizeof(log));
- log.hdr.size = cpu_to_le16(sizeof(log));
- ret = lbs_cmd_with_response(priv, CMD_802_11_GET_LOG, &log);
- if (ret)
- goto out;
-
- tx_retries = le32_to_cpu(log.retry);
-
- if (tx_retries > 75)
- tx_qual = (90 - tx_retries) * POOR / 15;
- else if (tx_retries > 70)
- tx_qual = (75 - tx_retries) * (FAIR - POOR) / 5 + POOR;
- else if (tx_retries > 65)
- tx_qual = (70 - tx_retries) * (GOOD - FAIR) / 5 + FAIR;
- else if (tx_retries > 50)
- tx_qual = (65 - tx_retries) * (VERY_GOOD - GOOD) /
- 15 + GOOD;
- else
- tx_qual = (50 - tx_retries) *
- (PERFECT - VERY_GOOD) / 50 + VERY_GOOD;
- quality = min(quality, tx_qual);
-
- priv->wstats.discard.code = le32_to_cpu(log.wepundecryptable);
- priv->wstats.discard.retries = tx_retries;
- priv->wstats.discard.misc = le32_to_cpu(log.ackfailure);
-
- /* Calculate quality */
- priv->wstats.qual.qual = min_t(u8, quality, 100);
- priv->wstats.qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM;
- stats_valid = 1;
-
- /* update stats asynchronously for future calls */
- ret = lbs_prepare_and_send_command(priv, CMD_802_11_RSSI, 0,
- 0, 0, NULL);
- if (ret)
- lbs_pr_err("RSSI command failed\n");
-out:
- if (!stats_valid) {
- priv->wstats.miss.beacon = 0;
- priv->wstats.discard.retries = 0;
- priv->wstats.qual.qual = 0;
- priv->wstats.qual.level = 0;
- priv->wstats.qual.noise = 0;
- priv->wstats.qual.updated = IW_QUAL_ALL_UPDATED;
- priv->wstats.qual.updated |= IW_QUAL_NOISE_INVALID |
- IW_QUAL_QUAL_INVALID | IW_QUAL_LEVEL_INVALID;
- }
-
- lbs_deb_leave(LBS_DEB_WEXT);
- return &priv->wstats;
-
-
-}
-
-static int lbs_set_freq(struct net_device *dev, struct iw_request_info *info,
- struct iw_freq *fwrq, char *extra)
-{
- int ret = -EINVAL;
- struct lbs_private *priv = dev->ml_priv;
- struct chan_freq_power *cfp;
- struct assoc_request * assoc_req;
-
- lbs_deb_enter(LBS_DEB_WEXT);
-
- mutex_lock(&priv->lock);
- assoc_req = lbs_get_association_request(priv);
- if (!assoc_req) {
- ret = -ENOMEM;
- goto out;
- }
-
- /* If setting by frequency, convert to a channel */
- if (fwrq->e == 1) {
- long f = fwrq->m / 100000;
-
- cfp = find_cfp_by_band_and_freq(priv, 0, f);
- if (!cfp) {
- lbs_deb_wext("invalid freq %ld\n", f);
- goto out;
- }
-
- fwrq->e = 0;
- fwrq->m = (int) cfp->channel;
- }
-
- /* Setting by channel number */
- if (fwrq->m > 1000 || fwrq->e > 0) {
- goto out;
- }
-
- cfp = lbs_find_cfp_by_band_and_channel(priv, 0, fwrq->m);
- if (!cfp) {
- goto out;
- }
-
- assoc_req->channel = fwrq->m;
- ret = 0;
-
-out:
- if (ret == 0) {
- set_bit(ASSOC_FLAG_CHANNEL, &assoc_req->flags);
- lbs_postpone_association_work(priv);
- } else {
- lbs_cancel_association_work(priv);
- }
- mutex_unlock(&priv->lock);
-
- lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
- return ret;
-}
-
-#ifdef CONFIG_LIBERTAS_MESH
-static int lbs_mesh_set_freq(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_freq *fwrq, char *extra)
-{
- struct lbs_private *priv = dev->ml_priv;
- struct chan_freq_power *cfp;
- int ret = -EINVAL;
-
- lbs_deb_enter(LBS_DEB_WEXT);
-
- /* If setting by frequency, convert to a channel */
- if (fwrq->e == 1) {
- long f = fwrq->m / 100000;
-
- cfp = find_cfp_by_band_and_freq(priv, 0, f);
- if (!cfp) {
- lbs_deb_wext("invalid freq %ld\n", f);
- goto out;
- }
-
- fwrq->e = 0;
- fwrq->m = (int) cfp->channel;
- }
-
- /* Setting by channel number */
- if (fwrq->m > 1000 || fwrq->e > 0) {
- goto out;
- }
-
- cfp = lbs_find_cfp_by_band_and_channel(priv, 0, fwrq->m);
- if (!cfp) {
- goto out;
- }
-
- if (fwrq->m != priv->channel) {
- lbs_deb_wext("mesh channel change forces eth disconnect\n");
- if (priv->mode == IW_MODE_INFRA)
- lbs_cmd_80211_deauthenticate(priv,
- priv->curbssparams.bssid,
- WLAN_REASON_DEAUTH_LEAVING);
- else if (priv->mode == IW_MODE_ADHOC)
- lbs_adhoc_stop(priv);
- }
- lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, fwrq->m);
- lbs_update_channel(priv);
- ret = 0;
-
-out:
- lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
- return ret;
-}
-#endif
-
-static int lbs_set_rate(struct net_device *dev, struct iw_request_info *info,
- struct iw_param *vwrq, char *extra)
-{
- struct lbs_private *priv = dev->ml_priv;
- u8 new_rate = 0;
- int ret = -EINVAL;
- u8 rates[MAX_RATES + 1];
-
- lbs_deb_enter(LBS_DEB_WEXT);
-
- lbs_deb_wext("vwrq->value %d\n", vwrq->value);
- lbs_deb_wext("vwrq->fixed %d\n", vwrq->fixed);
-
- if (vwrq->fixed && vwrq->value == -1)
- goto out;
-
- /* Auto rate? */
- priv->enablehwauto = !vwrq->fixed;
-
- if (vwrq->value == -1)
- priv->cur_rate = 0;
- else {
- if (vwrq->value % 100000)
- goto out;
-
- new_rate = vwrq->value / 500000;
- priv->cur_rate = new_rate;
- /* the rest is only needed for lbs_set_data_rate() */
- memset(rates, 0, sizeof(rates));
- copy_active_data_rates(priv, rates);
- if (!memchr(rates, new_rate, sizeof(rates))) {
- lbs_pr_alert("fixed data rate 0x%X out of range\n",
- new_rate);
- goto out;
- }
- if (priv->fwrelease < 0x09000000) {
- ret = lbs_set_power_adapt_cfg(priv, 0,
- POW_ADAPT_DEFAULT_P0,
- POW_ADAPT_DEFAULT_P1,
- POW_ADAPT_DEFAULT_P2);
- if (ret)
- goto out;
- }
- ret = lbs_set_tpc_cfg(priv, 0, TPC_DEFAULT_P0, TPC_DEFAULT_P1,
- TPC_DEFAULT_P2, 1);
- if (ret)
- goto out;
- }
-
- /* Try the newer command first (Firmware Spec 5.1 and above) */
- ret = lbs_cmd_802_11_rate_adapt_rateset(priv, CMD_ACT_SET);
-
- /* Fallback to older version */
- if (ret)
- ret = lbs_set_data_rate(priv, new_rate);
-
-out:
- lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
- return ret;
-}
-
-static int lbs_get_rate(struct net_device *dev, struct iw_request_info *info,
- struct iw_param *vwrq, char *extra)
-{
- struct lbs_private *priv = dev->ml_priv;
-
- lbs_deb_enter(LBS_DEB_WEXT);
-
- if (priv->connect_status == LBS_CONNECTED) {
- vwrq->value = priv->cur_rate * 500000;
-
- if (priv->enablehwauto)
- vwrq->fixed = 0;
- else
- vwrq->fixed = 1;
-
- } else {
- vwrq->fixed = 0;
- vwrq->value = 0;
- }
-
- lbs_deb_leave(LBS_DEB_WEXT);
- return 0;
-}
-
-static int lbs_set_mode(struct net_device *dev,
- struct iw_request_info *info, u32 * uwrq, char *extra)
-{
- int ret = 0;
- struct lbs_private *priv = dev->ml_priv;
- struct assoc_request * assoc_req;
-
- lbs_deb_enter(LBS_DEB_WEXT);
-
- if ( (*uwrq != IW_MODE_ADHOC)
- && (*uwrq != IW_MODE_INFRA)
- && (*uwrq != IW_MODE_AUTO)) {
- lbs_deb_wext("Invalid mode: 0x%x\n", *uwrq);
- ret = -EINVAL;
- goto out;
- }
-
- mutex_lock(&priv->lock);
- assoc_req = lbs_get_association_request(priv);
- if (!assoc_req) {
- ret = -ENOMEM;
- lbs_cancel_association_work(priv);
- } else {
- assoc_req->mode = *uwrq;
- set_bit(ASSOC_FLAG_MODE, &assoc_req->flags);
- lbs_postpone_association_work(priv);
- lbs_deb_wext("Switching to mode: 0x%x\n", *uwrq);
- }
- mutex_unlock(&priv->lock);
-
-out:
- lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
- return ret;
-}
-
-
-/**
- * @brief Get Encryption key
- *
- * @param dev A pointer to net_device structure
- * @param info A pointer to iw_request_info structure
- * @param vwrq A pointer to iw_param structure
- * @param extra A pointer to extra data buf
- * @return 0 --success, otherwise fail
- */
-static int lbs_get_encode(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_point *dwrq, u8 * extra)
-{
- struct lbs_private *priv = dev->ml_priv;
- int index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
-
- lbs_deb_enter(LBS_DEB_WEXT);
-
- lbs_deb_wext("flags 0x%x, index %d, length %d, wep_tx_keyidx %d\n",
- dwrq->flags, index, dwrq->length, priv->wep_tx_keyidx);
-
- dwrq->flags = 0;
-
- /* Authentication method */
- switch (priv->secinfo.auth_mode) {
- case IW_AUTH_ALG_OPEN_SYSTEM:
- dwrq->flags = IW_ENCODE_OPEN;
- break;
-
- case IW_AUTH_ALG_SHARED_KEY:
- case IW_AUTH_ALG_LEAP:
- dwrq->flags = IW_ENCODE_RESTRICTED;
- break;
- default:
- dwrq->flags = IW_ENCODE_DISABLED | IW_ENCODE_OPEN;
- break;
- }
-
- memset(extra, 0, 16);
-
- mutex_lock(&priv->lock);
-
- /* Default to returning current transmit key */
- if (index < 0)
- index = priv->wep_tx_keyidx;
-
- if ((priv->wep_keys[index].len) && priv->secinfo.wep_enabled) {
- memcpy(extra, priv->wep_keys[index].key,
- priv->wep_keys[index].len);
- dwrq->length = priv->wep_keys[index].len;
-
- dwrq->flags |= (index + 1);
- /* Return WEP enabled */
- dwrq->flags &= ~IW_ENCODE_DISABLED;
- } else if ((priv->secinfo.WPAenabled)
- || (priv->secinfo.WPA2enabled)) {
- /* return WPA enabled */
- dwrq->flags &= ~IW_ENCODE_DISABLED;
- dwrq->flags |= IW_ENCODE_NOKEY;
- } else {
- dwrq->flags |= IW_ENCODE_DISABLED;
- }
-
- mutex_unlock(&priv->lock);
-
- lbs_deb_wext("key: %02x:%02x:%02x:%02x:%02x:%02x, keylen %d\n",
- extra[0], extra[1], extra[2],
- extra[3], extra[4], extra[5], dwrq->length);
-
- lbs_deb_wext("return flags 0x%x\n", dwrq->flags);
-
- lbs_deb_leave(LBS_DEB_WEXT);
- return 0;
-}
-
-/**
- * @brief Set Encryption key (internal)
- *
- * @param priv A pointer to private card structure
- * @param key_material A pointer to key material
- * @param key_length length of key material
- * @param index key index to set
- * @param set_tx_key Force set TX key (1 = yes, 0 = no)
- * @return 0 --success, otherwise fail
- */
-static int lbs_set_wep_key(struct assoc_request *assoc_req,
- const char *key_material,
- u16 key_length,
- u16 index,
- int set_tx_key)
-{
- int ret = 0;
- struct enc_key *pkey;
-
- lbs_deb_enter(LBS_DEB_WEXT);
-
- /* Paranoid validation of key index */
- if (index > 3) {
- ret = -EINVAL;
- goto out;
- }
-
- /* validate max key length */
- if (key_length > KEY_LEN_WEP_104) {
- ret = -EINVAL;
- goto out;
- }
-
- pkey = &assoc_req->wep_keys[index];
-
- if (key_length > 0) {
- memset(pkey, 0, sizeof(struct enc_key));
- pkey->type = KEY_TYPE_ID_WEP;
-
- /* Standardize the key length */
- pkey->len = (key_length > KEY_LEN_WEP_40) ?
- KEY_LEN_WEP_104 : KEY_LEN_WEP_40;
- memcpy(pkey->key, key_material, key_length);
- }
-
- if (set_tx_key) {
- /* Ensure the chosen key is valid */
- if (!pkey->len) {
- lbs_deb_wext("key not set, so cannot enable it\n");
- ret = -EINVAL;
- goto out;
- }
- assoc_req->wep_tx_keyidx = index;
- }
-
- assoc_req->secinfo.wep_enabled = 1;
-
-out:
- lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
- return ret;
-}
-
-static int validate_key_index(u16 def_index, u16 raw_index,
- u16 *out_index, u16 *is_default)
-{
- if (!out_index || !is_default)
- return -EINVAL;
-
- /* Verify index if present, otherwise use default TX key index */
- if (raw_index > 0) {
- if (raw_index > 4)
- return -EINVAL;
- *out_index = raw_index - 1;
- } else {
- *out_index = def_index;
- *is_default = 1;
- }
- return 0;
-}
-
-static void disable_wep(struct assoc_request *assoc_req)
-{
- int i;
-
- lbs_deb_enter(LBS_DEB_WEXT);
-
- /* Set Open System auth mode */
- assoc_req->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM;
-
- /* Clear WEP keys and mark WEP as disabled */
- assoc_req->secinfo.wep_enabled = 0;
- for (i = 0; i < 4; i++)
- assoc_req->wep_keys[i].len = 0;
-
- set_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags);
- set_bit(ASSOC_FLAG_WEP_KEYS, &assoc_req->flags);
-
- lbs_deb_leave(LBS_DEB_WEXT);
-}
-
-static void disable_wpa(struct assoc_request *assoc_req)
-{
- lbs_deb_enter(LBS_DEB_WEXT);
-
- memset(&assoc_req->wpa_mcast_key, 0, sizeof (struct enc_key));
- assoc_req->wpa_mcast_key.flags = KEY_INFO_WPA_MCAST;
- set_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags);
-
- memset(&assoc_req->wpa_unicast_key, 0, sizeof (struct enc_key));
- assoc_req->wpa_unicast_key.flags = KEY_INFO_WPA_UNICAST;
- set_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags);
-
- assoc_req->secinfo.WPAenabled = 0;
- assoc_req->secinfo.WPA2enabled = 0;
- set_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags);
-
- lbs_deb_leave(LBS_DEB_WEXT);
-}
-
-/**
- * @brief Set Encryption key
- *
- * @param dev A pointer to net_device structure
- * @param info A pointer to iw_request_info structure
- * @param vwrq A pointer to iw_param structure
- * @param extra A pointer to extra data buf
- * @return 0 --success, otherwise fail
- */
-static int lbs_set_encode(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_point *dwrq, char *extra)
-{
- int ret = 0;
- struct lbs_private *priv = dev->ml_priv;
- struct assoc_request * assoc_req;
- u16 is_default = 0, index = 0, set_tx_key = 0;
-
- lbs_deb_enter(LBS_DEB_WEXT);
-
- mutex_lock(&priv->lock);
- assoc_req = lbs_get_association_request(priv);
- if (!assoc_req) {
- ret = -ENOMEM;
- goto out;
- }
-
- if (dwrq->flags & IW_ENCODE_DISABLED) {
- disable_wep (assoc_req);
- disable_wpa (assoc_req);
- goto out;
- }
-
- ret = validate_key_index(assoc_req->wep_tx_keyidx,
- (dwrq->flags & IW_ENCODE_INDEX),
- &index, &is_default);
- if (ret) {
- ret = -EINVAL;
- goto out;
- }
-
- /* If WEP isn't enabled, or if there is no key data but a valid
- * index, set the TX key.
- */
- if (!assoc_req->secinfo.wep_enabled || (dwrq->length == 0 && !is_default))
- set_tx_key = 1;
-
- ret = lbs_set_wep_key(assoc_req, extra, dwrq->length, index, set_tx_key);
- if (ret)
- goto out;
-
- if (dwrq->length)
- set_bit(ASSOC_FLAG_WEP_KEYS, &assoc_req->flags);
- if (set_tx_key)
- set_bit(ASSOC_FLAG_WEP_TX_KEYIDX, &assoc_req->flags);
-
- if (dwrq->flags & IW_ENCODE_RESTRICTED) {
- priv->authtype_auto = 0;
- assoc_req->secinfo.auth_mode = IW_AUTH_ALG_SHARED_KEY;
- } else if (dwrq->flags & IW_ENCODE_OPEN) {
- priv->authtype_auto = 0;
- assoc_req->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM;
- }
-
-out:
- if (ret == 0) {
- set_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags);
- lbs_postpone_association_work(priv);
- } else {
- lbs_cancel_association_work(priv);
- }
- mutex_unlock(&priv->lock);
-
- lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
- return ret;
-}
-
-/**
- * @brief Get Extended Encryption key (WPA/802.1x and WEP)
- *
- * @param dev A pointer to net_device structure
- * @param info A pointer to iw_request_info structure
- * @param vwrq A pointer to iw_param structure
- * @param extra A pointer to extra data buf
- * @return 0 on success, otherwise failure
- */
-static int lbs_get_encodeext(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_point *dwrq,
- char *extra)
-{
- int ret = -EINVAL;
- struct lbs_private *priv = dev->ml_priv;
- struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
- int index, max_key_len;
-
- lbs_deb_enter(LBS_DEB_WEXT);
-
- max_key_len = dwrq->length - sizeof(*ext);
- if (max_key_len < 0)
- goto out;
-
- index = dwrq->flags & IW_ENCODE_INDEX;
- if (index) {
- if (index < 1 || index > 4)
- goto out;
- index--;
- } else {
- index = priv->wep_tx_keyidx;
- }
-
- if (!(ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) &&
- ext->alg != IW_ENCODE_ALG_WEP) {
- if (index != 0 || priv->mode != IW_MODE_INFRA)
- goto out;
- }
-
- dwrq->flags = index + 1;
- memset(ext, 0, sizeof(*ext));
-
- if ( !priv->secinfo.wep_enabled
- && !priv->secinfo.WPAenabled
- && !priv->secinfo.WPA2enabled) {
- ext->alg = IW_ENCODE_ALG_NONE;
- ext->key_len = 0;
- dwrq->flags |= IW_ENCODE_DISABLED;
- } else {
- u8 *key = NULL;
-
- if ( priv->secinfo.wep_enabled
- && !priv->secinfo.WPAenabled
- && !priv->secinfo.WPA2enabled) {
- /* WEP */
- ext->alg = IW_ENCODE_ALG_WEP;
- ext->key_len = priv->wep_keys[index].len;
- key = &priv->wep_keys[index].key[0];
- } else if ( !priv->secinfo.wep_enabled
- && (priv->secinfo.WPAenabled ||
- priv->secinfo.WPA2enabled)) {
- /* WPA */
- struct enc_key * pkey = NULL;
-
- if ( priv->wpa_mcast_key.len
- && (priv->wpa_mcast_key.flags & KEY_INFO_WPA_ENABLED))
- pkey = &priv->wpa_mcast_key;
- else if ( priv->wpa_unicast_key.len
- && (priv->wpa_unicast_key.flags & KEY_INFO_WPA_ENABLED))
- pkey = &priv->wpa_unicast_key;
-
- if (pkey) {
- if (pkey->type == KEY_TYPE_ID_AES) {
- ext->alg = IW_ENCODE_ALG_CCMP;
- } else {
- ext->alg = IW_ENCODE_ALG_TKIP;
- }
- ext->key_len = pkey->len;
- key = &pkey->key[0];
- } else {
- ext->alg = IW_ENCODE_ALG_TKIP;
- ext->key_len = 0;
- }
- } else {
- goto out;
- }
-
- if (ext->key_len > max_key_len) {
- ret = -E2BIG;
- goto out;
- }
-
- if (ext->key_len)
- memcpy(ext->key, key, ext->key_len);
- else
- dwrq->flags |= IW_ENCODE_NOKEY;
- dwrq->flags |= IW_ENCODE_ENABLED;
- }
- ret = 0;
-
-out:
- lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
- return ret;
-}
-
-/**
- * @brief Set Encryption key Extended (WPA/802.1x and WEP)
- *
- * @param dev A pointer to net_device structure
- * @param info A pointer to iw_request_info structure
- * @param vwrq A pointer to iw_param structure
- * @param extra A pointer to extra data buf
- * @return 0 --success, otherwise fail
- */
-static int lbs_set_encodeext(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_point *dwrq,
- char *extra)
-{
- int ret = 0;
- struct lbs_private *priv = dev->ml_priv;
- struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
- int alg = ext->alg;
- struct assoc_request * assoc_req;
-
- lbs_deb_enter(LBS_DEB_WEXT);
-
- mutex_lock(&priv->lock);
- assoc_req = lbs_get_association_request(priv);
- if (!assoc_req) {
- ret = -ENOMEM;
- goto out;
- }
-
- if ((alg == IW_ENCODE_ALG_NONE) || (dwrq->flags & IW_ENCODE_DISABLED)) {
- disable_wep (assoc_req);
- disable_wpa (assoc_req);
- } else if (alg == IW_ENCODE_ALG_WEP) {
- u16 is_default = 0, index, set_tx_key = 0;
-
- ret = validate_key_index(assoc_req->wep_tx_keyidx,
- (dwrq->flags & IW_ENCODE_INDEX),
- &index, &is_default);
- if (ret)
- goto out;
-
- /* If WEP isn't enabled, or if there is no key data but a valid
- * index, or if the set-TX-key flag was passed, set the TX key.
- */
- if ( !assoc_req->secinfo.wep_enabled
- || (dwrq->length == 0 && !is_default)
- || (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY))
- set_tx_key = 1;
-
- /* Copy key to driver */
- ret = lbs_set_wep_key(assoc_req, ext->key, ext->key_len, index,
- set_tx_key);
- if (ret)
- goto out;
-
- if (dwrq->flags & IW_ENCODE_RESTRICTED) {
- priv->authtype_auto = 0;
- assoc_req->secinfo.auth_mode = IW_AUTH_ALG_SHARED_KEY;
- } else if (dwrq->flags & IW_ENCODE_OPEN) {
- priv->authtype_auto = 0;
- assoc_req->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM;
- }
-
- /* Mark the various WEP bits as modified */
- set_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags);
- if (dwrq->length)
- set_bit(ASSOC_FLAG_WEP_KEYS, &assoc_req->flags);
- if (set_tx_key)
- set_bit(ASSOC_FLAG_WEP_TX_KEYIDX, &assoc_req->flags);
- } else if ((alg == IW_ENCODE_ALG_TKIP) || (alg == IW_ENCODE_ALG_CCMP)) {
- struct enc_key * pkey;
-
- /* validate key length */
- if (((alg == IW_ENCODE_ALG_TKIP)
- && (ext->key_len != KEY_LEN_WPA_TKIP))
- || ((alg == IW_ENCODE_ALG_CCMP)
- && (ext->key_len != KEY_LEN_WPA_AES))) {
- lbs_deb_wext("invalid size %d for key of alg "
- "type %d\n",
- ext->key_len,
- alg);
- ret = -EINVAL;
- goto out;
- }
-
- if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) {
- pkey = &assoc_req->wpa_mcast_key;
- set_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags);
- } else {
- pkey = &assoc_req->wpa_unicast_key;
- set_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags);
- }
-
- memset(pkey, 0, sizeof (struct enc_key));
- memcpy(pkey->key, ext->key, ext->key_len);
- pkey->len = ext->key_len;
- if (pkey->len)
- pkey->flags |= KEY_INFO_WPA_ENABLED;
-
- /* Do this after zeroing key structure */
- if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) {
- pkey->flags |= KEY_INFO_WPA_MCAST;
- } else {
- pkey->flags |= KEY_INFO_WPA_UNICAST;
- }
-
- if (alg == IW_ENCODE_ALG_TKIP) {
- pkey->type = KEY_TYPE_ID_TKIP;
- } else if (alg == IW_ENCODE_ALG_CCMP) {
- pkey->type = KEY_TYPE_ID_AES;
- }
-
- /* If WPA isn't enabled yet, do that now */
- if ( assoc_req->secinfo.WPAenabled == 0
- && assoc_req->secinfo.WPA2enabled == 0) {
- assoc_req->secinfo.WPAenabled = 1;
- assoc_req->secinfo.WPA2enabled = 1;
- set_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags);
- }
-
- /* Only disable wep if necessary: can't waste time here. */
- if (priv->mac_control & CMD_ACT_MAC_WEP_ENABLE)
- disable_wep(assoc_req);
- }
-
-out:
- if (ret == 0) {
- /* 802.1x and WPA rekeying must happen as quickly as possible,
- * especially during the 4-way handshake; thus if in
- * infrastructure mode, and either (a) 802.1x is enabled or
- * (b) WPA is being used, set the key right away.
- */
- if (assoc_req->mode == IW_MODE_INFRA &&
- ((assoc_req->secinfo.key_mgmt & IW_AUTH_KEY_MGMT_802_1X) ||
- (assoc_req->secinfo.key_mgmt & IW_AUTH_KEY_MGMT_PSK) ||
- assoc_req->secinfo.WPAenabled ||
- assoc_req->secinfo.WPA2enabled)) {
- lbs_do_association_work(priv);
- } else
- lbs_postpone_association_work(priv);
- } else {
- lbs_cancel_association_work(priv);
- }
- mutex_unlock(&priv->lock);
-
- lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
- return ret;
-}
-
-
-static int lbs_set_genie(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_point *dwrq,
- char *extra)
-{
- struct lbs_private *priv = dev->ml_priv;
- int ret = 0;
- struct assoc_request * assoc_req;
-
- lbs_deb_enter(LBS_DEB_WEXT);
-
- mutex_lock(&priv->lock);
- assoc_req = lbs_get_association_request(priv);
- if (!assoc_req) {
- ret = -ENOMEM;
- goto out;
- }
-
- if (dwrq->length > MAX_WPA_IE_LEN ||
- (dwrq->length && extra == NULL)) {
- ret = -EINVAL;
- goto out;
- }
-
- if (dwrq->length) {
- memcpy(&assoc_req->wpa_ie[0], extra, dwrq->length);
- assoc_req->wpa_ie_len = dwrq->length;
- } else {
- memset(&assoc_req->wpa_ie[0], 0, sizeof(priv->wpa_ie));
- assoc_req->wpa_ie_len = 0;
- }
-
-out:
- if (ret == 0) {
- set_bit(ASSOC_FLAG_WPA_IE, &assoc_req->flags);
- lbs_postpone_association_work(priv);
- } else {
- lbs_cancel_association_work(priv);
- }
- mutex_unlock(&priv->lock);
-
- lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
- return ret;
-}
-
-static int lbs_get_genie(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_point *dwrq,
- char *extra)
-{
- int ret = 0;
- struct lbs_private *priv = dev->ml_priv;
-
- lbs_deb_enter(LBS_DEB_WEXT);
-
- if (priv->wpa_ie_len == 0) {
- dwrq->length = 0;
- goto out;
- }
-
- if (dwrq->length < priv->wpa_ie_len) {
- ret = -E2BIG;
- goto out;
- }
-
- dwrq->length = priv->wpa_ie_len;
- memcpy(extra, &priv->wpa_ie[0], priv->wpa_ie_len);
-
-out:
- lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
- return ret;
-}
-
-
-static int lbs_set_auth(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_param *dwrq,
- char *extra)
-{
- struct lbs_private *priv = dev->ml_priv;
- struct assoc_request * assoc_req;
- int ret = 0;
- int updated = 0;
-
- lbs_deb_enter(LBS_DEB_WEXT);
-
- mutex_lock(&priv->lock);
- assoc_req = lbs_get_association_request(priv);
- if (!assoc_req) {
- ret = -ENOMEM;
- goto out;
- }
-
- switch (dwrq->flags & IW_AUTH_INDEX) {
- case IW_AUTH_PRIVACY_INVOKED:
- case IW_AUTH_RX_UNENCRYPTED_EAPOL:
- case IW_AUTH_TKIP_COUNTERMEASURES:
- case IW_AUTH_CIPHER_PAIRWISE:
- case IW_AUTH_CIPHER_GROUP:
- case IW_AUTH_DROP_UNENCRYPTED:
- /*
- * libertas does not use these parameters
- */
- break;
-
- case IW_AUTH_KEY_MGMT:
- assoc_req->secinfo.key_mgmt = dwrq->value;
- updated = 1;
- break;
-
- case IW_AUTH_WPA_VERSION:
- if (dwrq->value & IW_AUTH_WPA_VERSION_DISABLED) {
- assoc_req->secinfo.WPAenabled = 0;
- assoc_req->secinfo.WPA2enabled = 0;
- disable_wpa (assoc_req);
- }
- if (dwrq->value & IW_AUTH_WPA_VERSION_WPA) {
- assoc_req->secinfo.WPAenabled = 1;
- assoc_req->secinfo.wep_enabled = 0;
- assoc_req->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM;
- }
- if (dwrq->value & IW_AUTH_WPA_VERSION_WPA2) {
- assoc_req->secinfo.WPA2enabled = 1;
- assoc_req->secinfo.wep_enabled = 0;
- assoc_req->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM;
- }
- updated = 1;
- break;
-
- case IW_AUTH_80211_AUTH_ALG:
- if (dwrq->value & IW_AUTH_ALG_SHARED_KEY) {
- assoc_req->secinfo.auth_mode = IW_AUTH_ALG_SHARED_KEY;
- } else if (dwrq->value & IW_AUTH_ALG_OPEN_SYSTEM) {
- assoc_req->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM;
- } else if (dwrq->value & IW_AUTH_ALG_LEAP) {
- assoc_req->secinfo.auth_mode = IW_AUTH_ALG_LEAP;
- } else {
- ret = -EINVAL;
- }
- updated = 1;
- break;
-
- case IW_AUTH_WPA_ENABLED:
- if (dwrq->value) {
- if (!assoc_req->secinfo.WPAenabled &&
- !assoc_req->secinfo.WPA2enabled) {
- assoc_req->secinfo.WPAenabled = 1;
- assoc_req->secinfo.WPA2enabled = 1;
- assoc_req->secinfo.wep_enabled = 0;
- assoc_req->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM;
- }
- } else {
- assoc_req->secinfo.WPAenabled = 0;
- assoc_req->secinfo.WPA2enabled = 0;
- disable_wpa (assoc_req);
- }
- updated = 1;
- break;
-
- default:
- ret = -EOPNOTSUPP;
- break;
- }
-
-out:
- if (ret == 0) {
- if (updated)
- set_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags);
- lbs_postpone_association_work(priv);
- } else if (ret != -EOPNOTSUPP) {
- lbs_cancel_association_work(priv);
- }
- mutex_unlock(&priv->lock);
-
- lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
- return ret;
-}
-
-static int lbs_get_auth(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_param *dwrq,
- char *extra)
-{
- int ret = 0;
- struct lbs_private *priv = dev->ml_priv;
-
- lbs_deb_enter(LBS_DEB_WEXT);
-
- switch (dwrq->flags & IW_AUTH_INDEX) {
- case IW_AUTH_KEY_MGMT:
- dwrq->value = priv->secinfo.key_mgmt;
- break;
-
- case IW_AUTH_WPA_VERSION:
- dwrq->value = 0;
- if (priv->secinfo.WPAenabled)
- dwrq->value |= IW_AUTH_WPA_VERSION_WPA;
- if (priv->secinfo.WPA2enabled)
- dwrq->value |= IW_AUTH_WPA_VERSION_WPA2;
- if (!dwrq->value)
- dwrq->value |= IW_AUTH_WPA_VERSION_DISABLED;
- break;
-
- case IW_AUTH_80211_AUTH_ALG:
- dwrq->value = priv->secinfo.auth_mode;
- break;
-
- case IW_AUTH_WPA_ENABLED:
- if (priv->secinfo.WPAenabled && priv->secinfo.WPA2enabled)
- dwrq->value = 1;
- break;
-
- default:
- ret = -EOPNOTSUPP;
- }
-
- lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
- return ret;
-}
-
-
-static int lbs_set_txpow(struct net_device *dev, struct iw_request_info *info,
- struct iw_param *vwrq, char *extra)
-{
- int ret = 0;
- struct lbs_private *priv = dev->ml_priv;
- s16 dbm = (s16) vwrq->value;
-
- lbs_deb_enter(LBS_DEB_WEXT);
-
- if (vwrq->disabled) {
- lbs_set_radio(priv, RADIO_PREAMBLE_AUTO, 0);
- goto out;
- }
-
- if (vwrq->fixed == 0) {
- /* User requests automatic tx power control, however there are
- * many auto tx settings. For now use firmware defaults until
- * we come up with a good way to expose these to the user. */
- if (priv->fwrelease < 0x09000000) {
- ret = lbs_set_power_adapt_cfg(priv, 1,
- POW_ADAPT_DEFAULT_P0,
- POW_ADAPT_DEFAULT_P1,
- POW_ADAPT_DEFAULT_P2);
- if (ret)
- goto out;
- }
- ret = lbs_set_tpc_cfg(priv, 0, TPC_DEFAULT_P0, TPC_DEFAULT_P1,
- TPC_DEFAULT_P2, 1);
- if (ret)
- goto out;
- dbm = priv->txpower_max;
- } else {
- /* Userspace check in iwrange if it should use dBm or mW,
- * therefore this should never happen... Jean II */
- if ((vwrq->flags & IW_TXPOW_TYPE) != IW_TXPOW_DBM) {
- ret = -EOPNOTSUPP;
- goto out;
- }
-
- /* Validate requested power level against firmware allowed
- * levels */
- if (priv->txpower_min && (dbm < priv->txpower_min)) {
- ret = -EINVAL;
- goto out;
- }
-
- if (priv->txpower_max && (dbm > priv->txpower_max)) {
- ret = -EINVAL;
- goto out;
- }
- if (priv->fwrelease < 0x09000000) {
- ret = lbs_set_power_adapt_cfg(priv, 0,
- POW_ADAPT_DEFAULT_P0,
- POW_ADAPT_DEFAULT_P1,
- POW_ADAPT_DEFAULT_P2);
- if (ret)
- goto out;
- }
- ret = lbs_set_tpc_cfg(priv, 0, TPC_DEFAULT_P0, TPC_DEFAULT_P1,
- TPC_DEFAULT_P2, 1);
- if (ret)
- goto out;
- }
-
- /* If the radio was off, turn it on */
- if (!priv->radio_on) {
- ret = lbs_set_radio(priv, RADIO_PREAMBLE_AUTO, 1);
- if (ret)
- goto out;
- }
-
- lbs_deb_wext("txpower set %d dBm\n", dbm);
-
- ret = lbs_set_tx_power(priv, dbm);
-
-out:
- lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
- return ret;
-}
-
-static int lbs_get_essid(struct net_device *dev, struct iw_request_info *info,
- struct iw_point *dwrq, char *extra)
-{
- struct lbs_private *priv = dev->ml_priv;
-
- lbs_deb_enter(LBS_DEB_WEXT);
-
- /*
- * Note : if dwrq->flags != 0, we should get the relevant SSID from
- * the SSID list...
- */
-
- /*
- * Get the current SSID
- */
- if (priv->connect_status == LBS_CONNECTED) {
- memcpy(extra, priv->curbssparams.ssid,
- priv->curbssparams.ssid_len);
- } else {
- memset(extra, 0, 32);
- }
- /*
- * If none, we may want to get the one that was set
- */
-
- dwrq->length = priv->curbssparams.ssid_len;
-
- dwrq->flags = 1; /* active */
-
- lbs_deb_leave(LBS_DEB_WEXT);
- return 0;
-}
-
-static int lbs_set_essid(struct net_device *dev, struct iw_request_info *info,
- struct iw_point *dwrq, char *extra)
-{
- struct lbs_private *priv = dev->ml_priv;
- int ret = 0;
- u8 ssid[IEEE80211_MAX_SSID_LEN];
- u8 ssid_len = 0;
- struct assoc_request * assoc_req;
- int in_ssid_len = dwrq->length;
- DECLARE_SSID_BUF(ssid_buf);
-
- lbs_deb_enter(LBS_DEB_WEXT);
-
- if (!priv->radio_on) {
- ret = -EINVAL;
- goto out;
- }
-
- /* Check the size of the string */
- if (in_ssid_len > IEEE80211_MAX_SSID_LEN) {
- ret = -E2BIG;
- goto out;
- }
-
- memset(&ssid, 0, sizeof(ssid));
-
- if (!dwrq->flags || !in_ssid_len) {
- /* "any" SSID requested; leave SSID blank */
- } else {
- /* Specific SSID requested */
- memcpy(&ssid, extra, in_ssid_len);
- ssid_len = in_ssid_len;
- }
-
- if (!ssid_len) {
- lbs_deb_wext("requested any SSID\n");
- } else {
- lbs_deb_wext("requested SSID '%s'\n",
- print_ssid(ssid_buf, ssid, ssid_len));
- }
-
-out:
- mutex_lock(&priv->lock);
- if (ret == 0) {
- /* Get or create the current association request */
- assoc_req = lbs_get_association_request(priv);
- if (!assoc_req) {
- ret = -ENOMEM;
- } else {
- /* Copy the SSID to the association request */
- memcpy(&assoc_req->ssid, &ssid, IEEE80211_MAX_SSID_LEN);
- assoc_req->ssid_len = ssid_len;
- set_bit(ASSOC_FLAG_SSID, &assoc_req->flags);
- lbs_postpone_association_work(priv);
- }
- }
-
- /* Cancel the association request if there was an error */
- if (ret != 0) {
- lbs_cancel_association_work(priv);
- }
-
- mutex_unlock(&priv->lock);
-
- lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
- return ret;
-}
-
-#ifdef CONFIG_LIBERTAS_MESH
-static int lbs_mesh_get_essid(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_point *dwrq, char *extra)
-{
- struct lbs_private *priv = dev->ml_priv;
-
- lbs_deb_enter(LBS_DEB_WEXT);
-
- memcpy(extra, priv->mesh_ssid, priv->mesh_ssid_len);
-
- dwrq->length = priv->mesh_ssid_len;
-
- dwrq->flags = 1; /* active */
-
- lbs_deb_leave(LBS_DEB_WEXT);
- return 0;
-}
-
-static int lbs_mesh_set_essid(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_point *dwrq, char *extra)
-{
- struct lbs_private *priv = dev->ml_priv;
- int ret = 0;
-
- lbs_deb_enter(LBS_DEB_WEXT);
-
- if (!priv->radio_on) {
- ret = -EINVAL;
- goto out;
- }
-
- /* Check the size of the string */
- if (dwrq->length > IEEE80211_MAX_SSID_LEN) {
- ret = -E2BIG;
- goto out;
- }
-
- if (!dwrq->flags || !dwrq->length) {
- ret = -EINVAL;
- goto out;
- } else {
- /* Specific SSID requested */
- memcpy(priv->mesh_ssid, extra, dwrq->length);
- priv->mesh_ssid_len = dwrq->length;
- }
-
- lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START,
- priv->channel);
- out:
- lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
- return ret;
-}
-#endif
-
-/**
- * @brief Connect to the AP or Ad-hoc Network with specific bssid
- *
- * @param dev A pointer to net_device structure
- * @param info A pointer to iw_request_info structure
- * @param awrq A pointer to iw_param structure
- * @param extra A pointer to extra data buf
- * @return 0 --success, otherwise fail
- */
-static int lbs_set_wap(struct net_device *dev, struct iw_request_info *info,
- struct sockaddr *awrq, char *extra)
-{
- struct lbs_private *priv = dev->ml_priv;
- struct assoc_request * assoc_req;
- int ret = 0;
-
- lbs_deb_enter(LBS_DEB_WEXT);
-
- if (!priv->radio_on)
- return -EINVAL;
-
- if (awrq->sa_family != ARPHRD_ETHER)
- return -EINVAL;
-
- lbs_deb_wext("ASSOC: WAP: sa_data %pM\n", awrq->sa_data);
-
- mutex_lock(&priv->lock);
-
- /* Get or create the current association request */
- assoc_req = lbs_get_association_request(priv);
- if (!assoc_req) {
- lbs_cancel_association_work(priv);
- ret = -ENOMEM;
- } else {
- /* Copy the BSSID to the association request */
- memcpy(&assoc_req->bssid, awrq->sa_data, ETH_ALEN);
- set_bit(ASSOC_FLAG_BSSID, &assoc_req->flags);
- lbs_postpone_association_work(priv);
- }
-
- mutex_unlock(&priv->lock);
-
- return ret;
-}
-
-/*
- * iwconfig settable callbacks
- */
-static const iw_handler lbs_handler[] = {
- (iw_handler) NULL, /* SIOCSIWCOMMIT */
- (iw_handler) lbs_get_name, /* SIOCGIWNAME */
- (iw_handler) NULL, /* SIOCSIWNWID */
- (iw_handler) NULL, /* SIOCGIWNWID */
- (iw_handler) lbs_set_freq, /* SIOCSIWFREQ */
- (iw_handler) lbs_get_freq, /* SIOCGIWFREQ */
- (iw_handler) lbs_set_mode, /* SIOCSIWMODE */
- (iw_handler) lbs_get_mode, /* SIOCGIWMODE */
- (iw_handler) NULL, /* SIOCSIWSENS */
- (iw_handler) NULL, /* SIOCGIWSENS */
- (iw_handler) NULL, /* SIOCSIWRANGE */
- (iw_handler) lbs_get_range, /* SIOCGIWRANGE */
- (iw_handler) NULL, /* SIOCSIWPRIV */
- (iw_handler) NULL, /* SIOCGIWPRIV */
- (iw_handler) NULL, /* SIOCSIWSTATS */
- (iw_handler) NULL, /* SIOCGIWSTATS */
- iw_handler_set_spy, /* SIOCSIWSPY */
- iw_handler_get_spy, /* SIOCGIWSPY */
- iw_handler_set_thrspy, /* SIOCSIWTHRSPY */
- iw_handler_get_thrspy, /* SIOCGIWTHRSPY */
- (iw_handler) lbs_set_wap, /* SIOCSIWAP */
- (iw_handler) lbs_get_wap, /* SIOCGIWAP */
- (iw_handler) NULL, /* SIOCSIWMLME */
- (iw_handler) NULL, /* SIOCGIWAPLIST - deprecated */
- (iw_handler) lbs_set_scan, /* SIOCSIWSCAN */
- (iw_handler) lbs_get_scan, /* SIOCGIWSCAN */
- (iw_handler) lbs_set_essid, /* SIOCSIWESSID */
- (iw_handler) lbs_get_essid, /* SIOCGIWESSID */
- (iw_handler) lbs_set_nick, /* SIOCSIWNICKN */
- (iw_handler) lbs_get_nick, /* SIOCGIWNICKN */
- (iw_handler) NULL, /* -- hole -- */
- (iw_handler) NULL, /* -- hole -- */
- (iw_handler) lbs_set_rate, /* SIOCSIWRATE */
- (iw_handler) lbs_get_rate, /* SIOCGIWRATE */
- (iw_handler) lbs_set_rts, /* SIOCSIWRTS */
- (iw_handler) lbs_get_rts, /* SIOCGIWRTS */
- (iw_handler) lbs_set_frag, /* SIOCSIWFRAG */
- (iw_handler) lbs_get_frag, /* SIOCGIWFRAG */
- (iw_handler) lbs_set_txpow, /* SIOCSIWTXPOW */
- (iw_handler) lbs_get_txpow, /* SIOCGIWTXPOW */
- (iw_handler) lbs_set_retry, /* SIOCSIWRETRY */
- (iw_handler) lbs_get_retry, /* SIOCGIWRETRY */
- (iw_handler) lbs_set_encode, /* SIOCSIWENCODE */
- (iw_handler) lbs_get_encode, /* SIOCGIWENCODE */
- (iw_handler) lbs_set_power, /* SIOCSIWPOWER */
- (iw_handler) lbs_get_power, /* SIOCGIWPOWER */
- (iw_handler) NULL, /* -- hole -- */
- (iw_handler) NULL, /* -- hole -- */
- (iw_handler) lbs_set_genie, /* SIOCSIWGENIE */
- (iw_handler) lbs_get_genie, /* SIOCGIWGENIE */
- (iw_handler) lbs_set_auth, /* SIOCSIWAUTH */
- (iw_handler) lbs_get_auth, /* SIOCGIWAUTH */
- (iw_handler) lbs_set_encodeext,/* SIOCSIWENCODEEXT */
- (iw_handler) lbs_get_encodeext,/* SIOCGIWENCODEEXT */
- (iw_handler) NULL, /* SIOCSIWPMKSA */
-};
-struct iw_handler_def lbs_handler_def = {
- .num_standard = ARRAY_SIZE(lbs_handler),
- .standard = (iw_handler *) lbs_handler,
- .get_wireless_stats = lbs_get_wireless_stats,
-};
-
-#ifdef CONFIG_LIBERTAS_MESH
-static const iw_handler mesh_wlan_handler[] = {
- (iw_handler) NULL, /* SIOCSIWCOMMIT */
- (iw_handler) lbs_get_name, /* SIOCGIWNAME */
- (iw_handler) NULL, /* SIOCSIWNWID */
- (iw_handler) NULL, /* SIOCGIWNWID */
- (iw_handler) lbs_mesh_set_freq, /* SIOCSIWFREQ */
- (iw_handler) lbs_get_freq, /* SIOCGIWFREQ */
- (iw_handler) NULL, /* SIOCSIWMODE */
- (iw_handler) mesh_wlan_get_mode, /* SIOCGIWMODE */
- (iw_handler) NULL, /* SIOCSIWSENS */
- (iw_handler) NULL, /* SIOCGIWSENS */
- (iw_handler) NULL, /* SIOCSIWRANGE */
- (iw_handler) lbs_get_range, /* SIOCGIWRANGE */
- (iw_handler) NULL, /* SIOCSIWPRIV */
- (iw_handler) NULL, /* SIOCGIWPRIV */
- (iw_handler) NULL, /* SIOCSIWSTATS */
- (iw_handler) NULL, /* SIOCGIWSTATS */
- iw_handler_set_spy, /* SIOCSIWSPY */
- iw_handler_get_spy, /* SIOCGIWSPY */
- iw_handler_set_thrspy, /* SIOCSIWTHRSPY */
- iw_handler_get_thrspy, /* SIOCGIWTHRSPY */
- (iw_handler) NULL, /* SIOCSIWAP */
- (iw_handler) NULL, /* SIOCGIWAP */
- (iw_handler) NULL, /* SIOCSIWMLME */
- (iw_handler) NULL, /* SIOCGIWAPLIST - deprecated */
- (iw_handler) lbs_set_scan, /* SIOCSIWSCAN */
- (iw_handler) lbs_get_scan, /* SIOCGIWSCAN */
- (iw_handler) lbs_mesh_set_essid,/* SIOCSIWESSID */
- (iw_handler) lbs_mesh_get_essid,/* SIOCGIWESSID */
- (iw_handler) NULL, /* SIOCSIWNICKN */
- (iw_handler) mesh_get_nick, /* SIOCGIWNICKN */
- (iw_handler) NULL, /* -- hole -- */
- (iw_handler) NULL, /* -- hole -- */
- (iw_handler) lbs_set_rate, /* SIOCSIWRATE */
- (iw_handler) lbs_get_rate, /* SIOCGIWRATE */
- (iw_handler) lbs_set_rts, /* SIOCSIWRTS */
- (iw_handler) lbs_get_rts, /* SIOCGIWRTS */
- (iw_handler) lbs_set_frag, /* SIOCSIWFRAG */
- (iw_handler) lbs_get_frag, /* SIOCGIWFRAG */
- (iw_handler) lbs_set_txpow, /* SIOCSIWTXPOW */
- (iw_handler) lbs_get_txpow, /* SIOCGIWTXPOW */
- (iw_handler) lbs_set_retry, /* SIOCSIWRETRY */
- (iw_handler) lbs_get_retry, /* SIOCGIWRETRY */
- (iw_handler) lbs_set_encode, /* SIOCSIWENCODE */
- (iw_handler) lbs_get_encode, /* SIOCGIWENCODE */
- (iw_handler) lbs_set_power, /* SIOCSIWPOWER */
- (iw_handler) lbs_get_power, /* SIOCGIWPOWER */
- (iw_handler) NULL, /* -- hole -- */
- (iw_handler) NULL, /* -- hole -- */
- (iw_handler) lbs_set_genie, /* SIOCSIWGENIE */
- (iw_handler) lbs_get_genie, /* SIOCGIWGENIE */
- (iw_handler) lbs_set_auth, /* SIOCSIWAUTH */
- (iw_handler) lbs_get_auth, /* SIOCGIWAUTH */
- (iw_handler) lbs_set_encodeext,/* SIOCSIWENCODEEXT */
- (iw_handler) lbs_get_encodeext,/* SIOCGIWENCODEEXT */
- (iw_handler) NULL, /* SIOCSIWPMKSA */
-};
-
-struct iw_handler_def mesh_handler_def = {
- .num_standard = ARRAY_SIZE(mesh_wlan_handler),
- .standard = (iw_handler *) mesh_wlan_handler,
- .get_wireless_stats = lbs_get_wireless_stats,
-};
-#endif
diff --git a/drivers/net/wireless/libertas/wext.h b/drivers/net/wireless/libertas/wext.h
deleted file mode 100644
index f3f19fe8c6c..00000000000
--- a/drivers/net/wireless/libertas/wext.h
+++ /dev/null
@@ -1,17 +0,0 @@
-/**
- * This file contains definition for IOCTL call.
- */
-#ifndef _LBS_WEXT_H_
-#define _LBS_WEXT_H_
-
-void lbs_send_disconnect_notification(struct lbs_private *priv);
-void lbs_send_mic_failureevent(struct lbs_private *priv, u32 event);
-
-struct chan_freq_power *lbs_find_cfp_by_band_and_channel(
- struct lbs_private *priv,
- u8 band,
- u16 channel);
-
-extern struct iw_handler_def lbs_handler_def;
-
-#endif
diff --git a/drivers/net/wireless/libertas_tf/if_usb.c b/drivers/net/wireless/libertas_tf/if_usb.c
index c445500ffc6..b172f5d87a3 100644
--- a/drivers/net/wireless/libertas_tf/if_usb.c
+++ b/drivers/net/wireless/libertas_tf/if_usb.c
@@ -538,7 +538,8 @@ static void if_usb_receive_fwload(struct urb *urb)
return;
}
- syncfwheader = kmalloc(sizeof(struct fwsyncheader), GFP_ATOMIC);
+ syncfwheader = kmemdup(skb->data, sizeof(struct fwsyncheader),
+ GFP_ATOMIC);
if (!syncfwheader) {
lbtf_deb_usbd(&cardp->udev->dev, "Failure to allocate syncfwheader\n");
kfree_skb(skb);
@@ -546,8 +547,6 @@ static void if_usb_receive_fwload(struct urb *urb)
return;
}
- memcpy(syncfwheader, skb->data, sizeof(struct fwsyncheader));
-
if (!syncfwheader->cmd) {
lbtf_deb_usb2(&cardp->udev->dev, "FW received Blk with correct CRC\n");
lbtf_deb_usb2(&cardp->udev->dev, "FW received Blk seqnum = %d\n",
diff --git a/drivers/net/wireless/libertas_tf/libertas_tf.h b/drivers/net/wireless/libertas_tf/libertas_tf.h
index fbbaaae7a1a..ad77b92d0b4 100644
--- a/drivers/net/wireless/libertas_tf/libertas_tf.h
+++ b/drivers/net/wireless/libertas_tf/libertas_tf.h
@@ -253,6 +253,9 @@ struct lbtf_private {
u8 fw_ready;
u8 surpriseremoved;
struct sk_buff_head bc_ps_buf;
+
+ /* Most recently reported noise in dBm */
+ s8 noise;
};
/* 802.11-related definitions */
@@ -316,7 +319,7 @@ struct cmd_header {
__le16 size;
__le16 seqnum;
__le16 result;
-} __attribute__ ((packed));
+} __packed;
struct cmd_ctrl_node {
struct list_head list;
@@ -369,7 +372,7 @@ struct cmd_ds_get_hw_spec {
/*FW/HW capability */
__le32 fwcapinfo;
-} __attribute__ ((packed));
+} __packed;
struct cmd_ds_mac_control {
struct cmd_header hdr;
diff --git a/drivers/net/wireless/libertas_tf/main.c b/drivers/net/wireless/libertas_tf/main.c
index 817fffc0de4..9278b3c8ee3 100644
--- a/drivers/net/wireless/libertas_tf/main.c
+++ b/drivers/net/wireless/libertas_tf/main.c
@@ -525,6 +525,22 @@ static void lbtf_op_bss_info_changed(struct ieee80211_hw *hw,
lbtf_deb_leave(LBTF_DEB_MACOPS);
}
+static int lbtf_op_get_survey(struct ieee80211_hw *hw, int idx,
+ struct survey_info *survey)
+{
+ struct lbtf_private *priv = hw->priv;
+ struct ieee80211_conf *conf = &hw->conf;
+
+ if (idx != 0)
+ return -ENOENT;
+
+ survey->channel = conf->channel;
+ survey->filled = SURVEY_INFO_NOISE_DBM;
+ survey->noise = priv->noise;
+
+ return 0;
+}
+
static const struct ieee80211_ops lbtf_ops = {
.tx = lbtf_op_tx,
.start = lbtf_op_start,
@@ -535,6 +551,7 @@ static const struct ieee80211_ops lbtf_ops = {
.prepare_multicast = lbtf_op_prepare_multicast,
.configure_filter = lbtf_op_configure_filter,
.bss_info_changed = lbtf_op_bss_info_changed,
+ .get_survey = lbtf_op_get_survey,
};
int lbtf_rx(struct lbtf_private *priv, struct sk_buff *skb)
@@ -555,6 +572,7 @@ int lbtf_rx(struct lbtf_private *priv, struct sk_buff *skb)
stats.freq = priv->cur_freq;
stats.band = IEEE80211_BAND_2GHZ;
stats.signal = prxpd->snr;
+ priv->noise = prxpd->nf;
/* Marvell rate index has a hole at value 4 */
if (prxpd->rx_rate > 4)
--prxpd->rx_rate;
diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c
index 6f8cb3ee6fe..01ad7f77383 100644
--- a/drivers/net/wireless/mac80211_hwsim.c
+++ b/drivers/net/wireless/mac80211_hwsim.c
@@ -317,7 +317,7 @@ struct hwsim_radiotap_hdr {
u8 rt_rate;
__le16 rt_channel;
__le16 rt_chbitmask;
-} __attribute__ ((packed));
+} __packed;
static netdev_tx_t hwsim_mon_xmit(struct sk_buff *skb,
@@ -486,8 +486,7 @@ static bool mac80211_hwsim_tx_frame(struct ieee80211_hw *hw,
struct ieee80211_rx_status rx_status;
if (data->idle) {
- printk(KERN_DEBUG "%s: Trying to TX when idle - reject\n",
- wiphy_name(hw->wiphy));
+ wiphy_debug(hw->wiphy, "trying to tx when idle - reject\n");
return false;
}
@@ -576,7 +575,7 @@ static int mac80211_hwsim_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
static int mac80211_hwsim_start(struct ieee80211_hw *hw)
{
struct mac80211_hwsim_data *data = hw->priv;
- printk(KERN_DEBUG "%s:%s\n", wiphy_name(hw->wiphy), __func__);
+ wiphy_debug(hw->wiphy, "%s\n", __func__);
data->started = 1;
return 0;
}
@@ -587,16 +586,15 @@ static void mac80211_hwsim_stop(struct ieee80211_hw *hw)
struct mac80211_hwsim_data *data = hw->priv;
data->started = 0;
del_timer(&data->beacon_timer);
- printk(KERN_DEBUG "%s:%s\n", wiphy_name(hw->wiphy), __func__);
+ wiphy_debug(hw->wiphy, "%s\n", __func__);
}
static int mac80211_hwsim_add_interface(struct ieee80211_hw *hw,
struct ieee80211_vif *vif)
{
- printk(KERN_DEBUG "%s:%s (type=%d mac_addr=%pM)\n",
- wiphy_name(hw->wiphy), __func__, vif->type,
- vif->addr);
+ wiphy_debug(hw->wiphy, "%s (type=%d mac_addr=%pM)\n",
+ __func__, vif->type, vif->addr);
hwsim_set_magic(vif);
return 0;
}
@@ -605,9 +603,8 @@ static int mac80211_hwsim_add_interface(struct ieee80211_hw *hw,
static void mac80211_hwsim_remove_interface(
struct ieee80211_hw *hw, struct ieee80211_vif *vif)
{
- printk(KERN_DEBUG "%s:%s (type=%d mac_addr=%pM)\n",
- wiphy_name(hw->wiphy), __func__, vif->type,
- vif->addr);
+ wiphy_debug(hw->wiphy, "%s (type=%d mac_addr=%pM)\n",
+ __func__, vif->type, vif->addr);
hwsim_check_magic(vif);
hwsim_clear_magic(vif);
}
@@ -670,13 +667,14 @@ static int mac80211_hwsim_config(struct ieee80211_hw *hw, u32 changed)
[IEEE80211_SMPS_DYNAMIC] = "dynamic",
};
- printk(KERN_DEBUG "%s:%s (freq=%d/%s idle=%d ps=%d smps=%s)\n",
- wiphy_name(hw->wiphy), __func__,
- conf->channel->center_freq,
- hwsim_chantypes[conf->channel_type],
- !!(conf->flags & IEEE80211_CONF_IDLE),
- !!(conf->flags & IEEE80211_CONF_PS),
- smps_modes[conf->smps_mode]);
+ wiphy_debug(hw->wiphy,
+ "%s (freq=%d/%s idle=%d ps=%d smps=%s)\n",
+ __func__,
+ conf->channel->center_freq,
+ hwsim_chantypes[conf->channel_type],
+ !!(conf->flags & IEEE80211_CONF_IDLE),
+ !!(conf->flags & IEEE80211_CONF_PS),
+ smps_modes[conf->smps_mode]);
data->idle = !!(conf->flags & IEEE80211_CONF_IDLE);
@@ -696,7 +694,7 @@ static void mac80211_hwsim_configure_filter(struct ieee80211_hw *hw,
{
struct mac80211_hwsim_data *data = hw->priv;
- printk(KERN_DEBUG "%s:%s\n", wiphy_name(hw->wiphy), __func__);
+ wiphy_debug(hw->wiphy, "%s\n", __func__);
data->rx_filter = 0;
if (*total_flags & FIF_PROMISC_IN_BSS)
@@ -717,26 +715,23 @@ static void mac80211_hwsim_bss_info_changed(struct ieee80211_hw *hw,
hwsim_check_magic(vif);
- printk(KERN_DEBUG "%s:%s(changed=0x%x)\n",
- wiphy_name(hw->wiphy), __func__, changed);
+ wiphy_debug(hw->wiphy, "%s(changed=0x%x)\n", __func__, changed);
if (changed & BSS_CHANGED_BSSID) {
- printk(KERN_DEBUG "%s:%s: BSSID changed: %pM\n",
- wiphy_name(hw->wiphy), __func__,
- info->bssid);
+ wiphy_debug(hw->wiphy, "%s: BSSID changed: %pM\n",
+ __func__, info->bssid);
memcpy(vp->bssid, info->bssid, ETH_ALEN);
}
if (changed & BSS_CHANGED_ASSOC) {
- printk(KERN_DEBUG " %s: ASSOC: assoc=%d aid=%d\n",
- wiphy_name(hw->wiphy), info->assoc, info->aid);
+ wiphy_debug(hw->wiphy, " ASSOC: assoc=%d aid=%d\n",
+ info->assoc, info->aid);
vp->assoc = info->assoc;
vp->aid = info->aid;
}
if (changed & BSS_CHANGED_BEACON_INT) {
- printk(KERN_DEBUG " %s: BCNINT: %d\n",
- wiphy_name(hw->wiphy), info->beacon_int);
+ wiphy_debug(hw->wiphy, " BCNINT: %d\n", info->beacon_int);
data->beacon_int = 1024 * info->beacon_int / 1000 * HZ / 1000;
if (WARN_ON(!data->beacon_int))
data->beacon_int = 1;
@@ -746,31 +741,28 @@ static void mac80211_hwsim_bss_info_changed(struct ieee80211_hw *hw,
}
if (changed & BSS_CHANGED_ERP_CTS_PROT) {
- printk(KERN_DEBUG " %s: ERP_CTS_PROT: %d\n",
- wiphy_name(hw->wiphy), info->use_cts_prot);
+ wiphy_debug(hw->wiphy, " ERP_CTS_PROT: %d\n",
+ info->use_cts_prot);
}
if (changed & BSS_CHANGED_ERP_PREAMBLE) {
- printk(KERN_DEBUG " %s: ERP_PREAMBLE: %d\n",
- wiphy_name(hw->wiphy), info->use_short_preamble);
+ wiphy_debug(hw->wiphy, " ERP_PREAMBLE: %d\n",
+ info->use_short_preamble);
}
if (changed & BSS_CHANGED_ERP_SLOT) {
- printk(KERN_DEBUG " %s: ERP_SLOT: %d\n",
- wiphy_name(hw->wiphy), info->use_short_slot);
+ wiphy_debug(hw->wiphy, " ERP_SLOT: %d\n", info->use_short_slot);
}
if (changed & BSS_CHANGED_HT) {
- printk(KERN_DEBUG " %s: HT: op_mode=0x%x, chantype=%s\n",
- wiphy_name(hw->wiphy),
- info->ht_operation_mode,
- hwsim_chantypes[info->channel_type]);
+ wiphy_debug(hw->wiphy, " HT: op_mode=0x%x, chantype=%s\n",
+ info->ht_operation_mode,
+ hwsim_chantypes[info->channel_type]);
}
if (changed & BSS_CHANGED_BASIC_RATES) {
- printk(KERN_DEBUG " %s: BASIC_RATES: 0x%llx\n",
- wiphy_name(hw->wiphy),
- (unsigned long long) info->basic_rates);
+ wiphy_debug(hw->wiphy, " BASIC_RATES: 0x%llx\n",
+ (unsigned long long) info->basic_rates);
}
}
@@ -824,10 +816,11 @@ static int mac80211_hwsim_conf_tx(
struct ieee80211_hw *hw, u16 queue,
const struct ieee80211_tx_queue_params *params)
{
- printk(KERN_DEBUG "%s:%s (queue=%d txop=%d cw_min=%d cw_max=%d "
- "aifs=%d)\n",
- wiphy_name(hw->wiphy), __func__, queue,
- params->txop, params->cw_min, params->cw_max, params->aifs);
+ wiphy_debug(hw->wiphy,
+ "%s (queue=%d txop=%d cw_min=%d cw_max=%d aifs=%d)\n",
+ __func__, queue,
+ params->txop, params->cw_min,
+ params->cw_max, params->aifs);
return 0;
}
@@ -837,8 +830,7 @@ static int mac80211_hwsim_get_survey(
{
struct ieee80211_conf *conf = &hw->conf;
- printk(KERN_DEBUG "%s:%s (idx=%d)\n",
- wiphy_name(hw->wiphy), __func__, idx);
+ wiphy_debug(hw->wiphy, "%s (idx=%d)\n", __func__, idx);
if (idx != 0)
return -ENOENT;
@@ -1108,8 +1100,9 @@ static void hwsim_send_ps_poll(void *dat, u8 *mac, struct ieee80211_vif *vif)
if (!vp->assoc)
return;
- printk(KERN_DEBUG "%s:%s: send PS-Poll to %pM for aid %d\n",
- wiphy_name(data->hw->wiphy), __func__, vp->bssid, vp->aid);
+ wiphy_debug(data->hw->wiphy,
+ "%s: send PS-Poll to %pM for aid %d\n",
+ __func__, vp->bssid, vp->aid);
skb = dev_alloc_skb(sizeof(*pspoll));
if (!skb)
@@ -1137,8 +1130,9 @@ static void hwsim_send_nullfunc(struct mac80211_hwsim_data *data, u8 *mac,
if (!vp->assoc)
return;
- printk(KERN_DEBUG "%s:%s: send data::nullfunc to %pM ps=%d\n",
- wiphy_name(data->hw->wiphy), __func__, vp->bssid, ps);
+ wiphy_debug(data->hw->wiphy,
+ "%s: send data::nullfunc to %pM ps=%d\n",
+ __func__, vp->bssid, ps);
skb = dev_alloc_skb(sizeof(*hdr));
if (!skb)
@@ -1291,6 +1285,11 @@ static int __init init_mac80211_hwsim(void)
hw->wiphy->n_addresses = 2;
hw->wiphy->addresses = data->addresses;
+ if (fake_hw_scan) {
+ hw->wiphy->max_scan_ssids = 255;
+ hw->wiphy->max_scan_ie_len = IEEE80211_MAX_DATA_LEN;
+ }
+
hw->channel_change_time = 1;
hw->queues = 4;
hw->wiphy->interface_modes =
@@ -1468,9 +1467,8 @@ static int __init init_mac80211_hwsim(void)
break;
}
- printk(KERN_DEBUG "%s: hwaddr %pM registered\n",
- wiphy_name(hw->wiphy),
- hw->wiphy->perm_addr);
+ wiphy_debug(hw->wiphy, "hwaddr %pm registered\n",
+ hw->wiphy->perm_addr);
data->debugfs = debugfs_create_dir("hwsim",
hw->wiphy->debugfsdir);
diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c
index 808adb90909..d761ed2d8af 100644
--- a/drivers/net/wireless/mwl8k.c
+++ b/drivers/net/wireless/mwl8k.c
@@ -86,7 +86,7 @@ struct rxd_ops {
void (*rxd_init)(void *rxd, dma_addr_t next_dma_addr);
void (*rxd_refill)(void *rxd, dma_addr_t addr, int len);
int (*rxd_process)(void *rxd, struct ieee80211_rx_status *status,
- __le16 *qos);
+ __le16 *qos, s8 *noise);
};
struct mwl8k_device_info {
@@ -109,7 +109,7 @@ struct mwl8k_rx_queue {
dma_addr_t rxd_dma;
struct {
struct sk_buff *skb;
- DECLARE_PCI_UNMAP_ADDR(dma)
+ DEFINE_DMA_UNMAP_ADDR(dma);
} *buf;
};
@@ -207,6 +207,9 @@ struct mwl8k_priv {
/* Tasklet to perform RX. */
struct tasklet_struct poll_rx_task;
+
+ /* Most recently reported noise in dBm */
+ s8 noise;
};
/* Per interface specific private data */
@@ -314,13 +317,15 @@ static const struct ieee80211_rate mwl8k_rates_50[] = {
#define MWL8K_CMD_SET_NEW_STN 0x1111 /* per-vif */
#define MWL8K_CMD_UPDATE_STADB 0x1123
-static const char *mwl8k_cmd_name(u16 cmd, char *buf, int bufsize)
+static const char *mwl8k_cmd_name(__le16 cmd, char *buf, int bufsize)
{
+ u16 command = le16_to_cpu(cmd);
+
#define MWL8K_CMDNAME(x) case MWL8K_CMD_##x: do {\
snprintf(buf, bufsize, "%s", #x);\
return buf;\
} while (0)
- switch (cmd & ~0x8000) {
+ switch (command & ~0x8000) {
MWL8K_CMDNAME(CODE_DNLD);
MWL8K_CMDNAME(GET_HW_SPEC);
MWL8K_CMDNAME(SET_HW_SPEC);
@@ -426,7 +431,7 @@ struct mwl8k_cmd_pkt {
__u8 macid;
__le16 result;
char payload[0];
-} __attribute__((packed));
+} __packed;
/*
* Firmware loading.
@@ -632,7 +637,7 @@ struct mwl8k_dma_data {
__le16 fwlen;
struct ieee80211_hdr wh;
char data[0];
-} __attribute__((packed));
+} __packed;
/* Routines to add/remove DMA header from skb. */
static inline void mwl8k_remove_dma_header(struct sk_buff *skb, __le16 qos)
@@ -711,7 +716,7 @@ struct mwl8k_rxd_8366_ap {
__u8 rx_status;
__u8 channel;
__u8 rx_ctrl;
-} __attribute__((packed));
+} __packed;
#define MWL8K_8366_AP_RATE_INFO_MCS_FORMAT 0x80
#define MWL8K_8366_AP_RATE_INFO_40MHZ 0x40
@@ -739,7 +744,7 @@ static void mwl8k_rxd_8366_ap_refill(void *_rxd, dma_addr_t addr, int len)
static int
mwl8k_rxd_8366_ap_process(void *_rxd, struct ieee80211_rx_status *status,
- __le16 *qos)
+ __le16 *qos, s8 *noise)
{
struct mwl8k_rxd_8366_ap *rxd = _rxd;
@@ -750,6 +755,7 @@ mwl8k_rxd_8366_ap_process(void *_rxd, struct ieee80211_rx_status *status,
memset(status, 0, sizeof(*status));
status->signal = -rxd->rssi;
+ *noise = -rxd->noise_floor;
if (rxd->rate & MWL8K_8366_AP_RATE_INFO_MCS_FORMAT) {
status->flag |= RX_FLAG_HT;
@@ -806,7 +812,7 @@ struct mwl8k_rxd_sta {
__u8 rx_ctrl;
__u8 rx_status;
__u8 pad2[2];
-} __attribute__((packed));
+} __packed;
#define MWL8K_STA_RATE_INFO_SHORTPRE 0x8000
#define MWL8K_STA_RATE_INFO_ANTSELECT(x) (((x) >> 11) & 0x3)
@@ -837,7 +843,7 @@ static void mwl8k_rxd_sta_refill(void *_rxd, dma_addr_t addr, int len)
static int
mwl8k_rxd_sta_process(void *_rxd, struct ieee80211_rx_status *status,
- __le16 *qos)
+ __le16 *qos, s8 *noise)
{
struct mwl8k_rxd_sta *rxd = _rxd;
u16 rate_info;
@@ -851,6 +857,7 @@ mwl8k_rxd_sta_process(void *_rxd, struct ieee80211_rx_status *status,
memset(status, 0, sizeof(*status));
status->signal = -rxd->rssi;
+ *noise = -rxd->noise_level;
status->antenna = MWL8K_STA_RATE_INFO_ANTSELECT(rate_info);
status->rate_idx = MWL8K_STA_RATE_INFO_RATEID(rate_info);
@@ -903,16 +910,14 @@ static int mwl8k_rxq_init(struct ieee80211_hw *hw, int index)
rxq->rxd = pci_alloc_consistent(priv->pdev, size, &rxq->rxd_dma);
if (rxq->rxd == NULL) {
- printk(KERN_ERR "%s: failed to alloc RX descriptors\n",
- wiphy_name(hw->wiphy));
+ wiphy_err(hw->wiphy, "failed to alloc rx descriptors\n");
return -ENOMEM;
}
memset(rxq->rxd, 0, size);
rxq->buf = kmalloc(MWL8K_RX_DESCS * sizeof(*rxq->buf), GFP_KERNEL);
if (rxq->buf == NULL) {
- printk(KERN_ERR "%s: failed to alloc RX skbuff list\n",
- wiphy_name(hw->wiphy));
+ wiphy_err(hw->wiphy, "failed to alloc rx skbuff list\n");
pci_free_consistent(priv->pdev, size, rxq->rxd, rxq->rxd_dma);
return -ENOMEM;
}
@@ -963,7 +968,7 @@ static int rxq_refill(struct ieee80211_hw *hw, int index, int limit)
if (rxq->tail == MWL8K_RX_DESCS)
rxq->tail = 0;
rxq->buf[rx].skb = skb;
- pci_unmap_addr_set(&rxq->buf[rx], dma, addr);
+ dma_unmap_addr_set(&rxq->buf[rx], dma, addr);
rxd = rxq->rxd + (rx * priv->rxd_ops->rxd_size);
priv->rxd_ops->rxd_refill(rxd, addr, MWL8K_RX_MAXSZ);
@@ -984,9 +989,9 @@ static void mwl8k_rxq_deinit(struct ieee80211_hw *hw, int index)
for (i = 0; i < MWL8K_RX_DESCS; i++) {
if (rxq->buf[i].skb != NULL) {
pci_unmap_single(priv->pdev,
- pci_unmap_addr(&rxq->buf[i], dma),
+ dma_unmap_addr(&rxq->buf[i], dma),
MWL8K_RX_MAXSZ, PCI_DMA_FROMDEVICE);
- pci_unmap_addr_set(&rxq->buf[i], dma, 0);
+ dma_unmap_addr_set(&rxq->buf[i], dma, 0);
kfree_skb(rxq->buf[i].skb);
rxq->buf[i].skb = NULL;
@@ -1053,16 +1058,17 @@ static int rxq_process(struct ieee80211_hw *hw, int index, int limit)
rxd = rxq->rxd + (rxq->head * priv->rxd_ops->rxd_size);
- pkt_len = priv->rxd_ops->rxd_process(rxd, &status, &qos);
+ pkt_len = priv->rxd_ops->rxd_process(rxd, &status, &qos,
+ &priv->noise);
if (pkt_len < 0)
break;
rxq->buf[rxq->head].skb = NULL;
pci_unmap_single(priv->pdev,
- pci_unmap_addr(&rxq->buf[rxq->head], dma),
+ dma_unmap_addr(&rxq->buf[rxq->head], dma),
MWL8K_RX_MAXSZ, PCI_DMA_FROMDEVICE);
- pci_unmap_addr_set(&rxq->buf[rxq->head], dma, 0);
+ dma_unmap_addr_set(&rxq->buf[rxq->head], dma, 0);
rxq->head++;
if (rxq->head == MWL8K_RX_DESCS)
@@ -1120,7 +1126,7 @@ struct mwl8k_tx_desc {
__le16 rate_info;
__u8 peer_id;
__u8 tx_frag_cnt;
-} __attribute__((packed));
+} __packed;
#define MWL8K_TX_DESCS 128
@@ -1139,16 +1145,14 @@ static int mwl8k_txq_init(struct ieee80211_hw *hw, int index)
txq->txd = pci_alloc_consistent(priv->pdev, size, &txq->txd_dma);
if (txq->txd == NULL) {
- printk(KERN_ERR "%s: failed to alloc TX descriptors\n",
- wiphy_name(hw->wiphy));
+ wiphy_err(hw->wiphy, "failed to alloc tx descriptors\n");
return -ENOMEM;
}
memset(txq->txd, 0, size);
txq->skb = kmalloc(MWL8K_TX_DESCS * sizeof(*txq->skb), GFP_KERNEL);
if (txq->skb == NULL) {
- printk(KERN_ERR "%s: failed to alloc TX skbuff list\n",
- wiphy_name(hw->wiphy));
+ wiphy_err(hw->wiphy, "failed to alloc tx skbuff list\n");
pci_free_consistent(priv->pdev, size, txq->txd, txq->txd_dma);
return -ENOMEM;
}
@@ -1204,11 +1208,12 @@ static void mwl8k_dump_tx_rings(struct ieee80211_hw *hw)
unused++;
}
- printk(KERN_ERR "%s: txq[%d] len=%d head=%d tail=%d "
- "fw_owned=%d drv_owned=%d unused=%d\n",
- wiphy_name(hw->wiphy), i,
- txq->len, txq->head, txq->tail,
- fw_owned, drv_owned, unused);
+ wiphy_err(hw->wiphy,
+ "txq[%d] len=%d head=%d tail=%d "
+ "fw_owned=%d drv_owned=%d unused=%d\n",
+ i,
+ txq->len, txq->head, txq->tail,
+ fw_owned, drv_owned, unused);
}
}
@@ -1252,25 +1257,23 @@ static int mwl8k_tx_wait_empty(struct ieee80211_hw *hw)
if (timeout) {
WARN_ON(priv->pending_tx_pkts);
if (retry) {
- printk(KERN_NOTICE "%s: tx rings drained\n",
- wiphy_name(hw->wiphy));
+ wiphy_notice(hw->wiphy, "tx rings drained\n");
}
break;
}
if (priv->pending_tx_pkts < oldcount) {
- printk(KERN_NOTICE "%s: waiting for tx rings "
- "to drain (%d -> %d pkts)\n",
- wiphy_name(hw->wiphy), oldcount,
- priv->pending_tx_pkts);
+ wiphy_notice(hw->wiphy,
+ "waiting for tx rings to drain (%d -> %d pkts)\n",
+ oldcount, priv->pending_tx_pkts);
retry = 1;
continue;
}
priv->tx_wait = NULL;
- printk(KERN_ERR "%s: tx rings stuck for %d ms\n",
- wiphy_name(hw->wiphy), MWL8K_TX_WAIT_TIMEOUT_MS);
+ wiphy_err(hw->wiphy, "tx rings stuck for %d ms\n",
+ MWL8K_TX_WAIT_TIMEOUT_MS);
mwl8k_dump_tx_rings(hw);
rc = -ETIMEDOUT;
@@ -1421,8 +1424,8 @@ mwl8k_txq_xmit(struct ieee80211_hw *hw, int index, struct sk_buff *skb)
skb->len, PCI_DMA_TODEVICE);
if (pci_dma_mapping_error(priv->pdev, dma)) {
- printk(KERN_DEBUG "%s: failed to dma map skb, "
- "dropping TX frame.\n", wiphy_name(hw->wiphy));
+ wiphy_debug(hw->wiphy,
+ "failed to dma map skb, dropping TX frame.\n");
dev_kfree_skb(skb);
return NETDEV_TX_OK;
}
@@ -1538,7 +1541,7 @@ static int mwl8k_post_cmd(struct ieee80211_hw *hw, struct mwl8k_cmd_pkt *cmd)
unsigned long timeout = 0;
u8 buf[32];
- cmd->result = 0xffff;
+ cmd->result = (__force __le16) 0xffff;
dma_size = le16_to_cpu(cmd->length);
dma_addr = pci_map_single(priv->pdev, cmd, dma_size,
PCI_DMA_BIDIRECTIONAL);
@@ -1570,10 +1573,9 @@ static int mwl8k_post_cmd(struct ieee80211_hw *hw, struct mwl8k_cmd_pkt *cmd)
PCI_DMA_BIDIRECTIONAL);
if (!timeout) {
- printk(KERN_ERR "%s: Command %s timeout after %u ms\n",
- wiphy_name(hw->wiphy),
- mwl8k_cmd_name(cmd->code, buf, sizeof(buf)),
- MWL8K_CMD_TIMEOUT_MS);
+ wiphy_err(hw->wiphy, "command %s timeout after %u ms\n",
+ mwl8k_cmd_name(cmd->code, buf, sizeof(buf)),
+ MWL8K_CMD_TIMEOUT_MS);
rc = -ETIMEDOUT;
} else {
int ms;
@@ -1582,15 +1584,14 @@ static int mwl8k_post_cmd(struct ieee80211_hw *hw, struct mwl8k_cmd_pkt *cmd)
rc = cmd->result ? -EINVAL : 0;
if (rc)
- printk(KERN_ERR "%s: Command %s error 0x%x\n",
- wiphy_name(hw->wiphy),
- mwl8k_cmd_name(cmd->code, buf, sizeof(buf)),
- le16_to_cpu(cmd->result));
+ wiphy_err(hw->wiphy, "command %s error 0x%x\n",
+ mwl8k_cmd_name(cmd->code, buf, sizeof(buf)),
+ le16_to_cpu(cmd->result));
else if (ms > 2000)
- printk(KERN_NOTICE "%s: Command %s took %d ms\n",
- wiphy_name(hw->wiphy),
- mwl8k_cmd_name(cmd->code, buf, sizeof(buf)),
- ms);
+ wiphy_notice(hw->wiphy, "command %s took %d ms\n",
+ mwl8k_cmd_name(cmd->code,
+ buf, sizeof(buf)),
+ ms);
}
return rc;
@@ -1666,7 +1667,7 @@ struct mwl8k_cmd_get_hw_spec_sta {
__le32 caps2;
__le32 num_tx_desc_per_queue;
__le32 total_rxd;
-} __attribute__((packed));
+} __packed;
#define MWL8K_CAP_MAX_AMSDU 0x20000000
#define MWL8K_CAP_GREENFIELD 0x08000000
@@ -1810,7 +1811,7 @@ struct mwl8k_cmd_get_hw_spec_ap {
__le32 wcbbase1;
__le32 wcbbase2;
__le32 wcbbase3;
-} __attribute__((packed));
+} __packed;
static int mwl8k_cmd_get_hw_spec_ap(struct ieee80211_hw *hw)
{
@@ -1842,22 +1843,22 @@ static int mwl8k_cmd_get_hw_spec_ap(struct ieee80211_hw *hw)
priv->sta_macids_supported = 0x00000000;
off = le32_to_cpu(cmd->wcbbase0) & 0xffff;
- iowrite32(cpu_to_le32(priv->txq[0].txd_dma), priv->sram + off);
+ iowrite32(priv->txq[0].txd_dma, priv->sram + off);
off = le32_to_cpu(cmd->rxwrptr) & 0xffff;
- iowrite32(cpu_to_le32(priv->rxq[0].rxd_dma), priv->sram + off);
+ iowrite32(priv->rxq[0].rxd_dma, priv->sram + off);
off = le32_to_cpu(cmd->rxrdptr) & 0xffff;
- iowrite32(cpu_to_le32(priv->rxq[0].rxd_dma), priv->sram + off);
+ iowrite32(priv->rxq[0].rxd_dma, priv->sram + off);
off = le32_to_cpu(cmd->wcbbase1) & 0xffff;
- iowrite32(cpu_to_le32(priv->txq[1].txd_dma), priv->sram + off);
+ iowrite32(priv->txq[1].txd_dma, priv->sram + off);
off = le32_to_cpu(cmd->wcbbase2) & 0xffff;
- iowrite32(cpu_to_le32(priv->txq[2].txd_dma), priv->sram + off);
+ iowrite32(priv->txq[2].txd_dma, priv->sram + off);
off = le32_to_cpu(cmd->wcbbase3) & 0xffff;
- iowrite32(cpu_to_le32(priv->txq[3].txd_dma), priv->sram + off);
+ iowrite32(priv->txq[3].txd_dma, priv->sram + off);
}
kfree(cmd);
@@ -1883,7 +1884,7 @@ struct mwl8k_cmd_set_hw_spec {
__le32 flags;
__le32 num_tx_desc_per_queue;
__le32 total_rxd;
-} __attribute__((packed));
+} __packed;
#define MWL8K_SET_HW_SPEC_FLAG_HOST_DECR_MGMT 0x00000080
#define MWL8K_SET_HW_SPEC_FLAG_HOSTFORM_PROBERESP 0x00000020
@@ -1985,7 +1986,7 @@ __mwl8k_cmd_mac_multicast_adr(struct ieee80211_hw *hw, int allmulti,
struct mwl8k_cmd_get_stat {
struct mwl8k_cmd_pkt header;
__le32 stats[64];
-} __attribute__((packed));
+} __packed;
#define MWL8K_STAT_ACK_FAILURE 9
#define MWL8K_STAT_RTS_FAILURE 12
@@ -2029,7 +2030,7 @@ struct mwl8k_cmd_radio_control {
__le16 action;
__le16 control;
__le16 radio_on;
-} __attribute__((packed));
+} __packed;
static int
mwl8k_cmd_radio_control(struct ieee80211_hw *hw, bool enable, bool force)
@@ -2092,7 +2093,7 @@ struct mwl8k_cmd_rf_tx_power {
__le16 current_level;
__le16 reserved;
__le16 power_level_list[MWL8K_TX_POWER_LEVEL_TOTAL];
-} __attribute__((packed));
+} __packed;
static int mwl8k_cmd_rf_tx_power(struct ieee80211_hw *hw, int dBm)
{
@@ -2121,7 +2122,7 @@ struct mwl8k_cmd_rf_antenna {
struct mwl8k_cmd_pkt header;
__le16 antenna;
__le16 mode;
-} __attribute__((packed));
+} __packed;
#define MWL8K_RF_ANTENNA_RX 1
#define MWL8K_RF_ANTENNA_TX 2
@@ -2182,7 +2183,7 @@ static int mwl8k_cmd_set_beacon(struct ieee80211_hw *hw,
*/
struct mwl8k_cmd_set_pre_scan {
struct mwl8k_cmd_pkt header;
-} __attribute__((packed));
+} __packed;
static int mwl8k_cmd_set_pre_scan(struct ieee80211_hw *hw)
{
@@ -2209,7 +2210,7 @@ struct mwl8k_cmd_set_post_scan {
struct mwl8k_cmd_pkt header;
__le32 isibss;
__u8 bssid[ETH_ALEN];
-} __attribute__((packed));
+} __packed;
static int
mwl8k_cmd_set_post_scan(struct ieee80211_hw *hw, const __u8 *mac)
@@ -2240,7 +2241,7 @@ struct mwl8k_cmd_set_rf_channel {
__le16 action;
__u8 current_channel;
__le32 channel_flags;
-} __attribute__((packed));
+} __packed;
static int mwl8k_cmd_set_rf_channel(struct ieee80211_hw *hw,
struct ieee80211_conf *conf)
@@ -2293,7 +2294,7 @@ struct mwl8k_cmd_update_set_aid {
__u8 bssid[ETH_ALEN];
__le16 protection_mode;
__u8 supp_rates[14];
-} __attribute__((packed));
+} __packed;
static void legacy_rate_mask_to_array(u8 *rates, u32 mask)
{
@@ -2364,7 +2365,7 @@ struct mwl8k_cmd_set_rate {
/* Bitmap for supported MCS codes. */
__u8 mcs_set[16];
__u8 reserved[16];
-} __attribute__((packed));
+} __packed;
static int
mwl8k_cmd_set_rate(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
@@ -2397,7 +2398,7 @@ struct mwl8k_cmd_finalize_join {
struct mwl8k_cmd_pkt header;
__le32 sleep_interval; /* Number of beacon periods to sleep */
__u8 beacon_data[MWL8K_FJ_BEACON_MAXLEN];
-} __attribute__((packed));
+} __packed;
static int mwl8k_cmd_finalize_join(struct ieee80211_hw *hw, void *frame,
int framelen, int dtim)
@@ -2436,7 +2437,7 @@ struct mwl8k_cmd_set_rts_threshold {
struct mwl8k_cmd_pkt header;
__le16 action;
__le16 threshold;
-} __attribute__((packed));
+} __packed;
static int
mwl8k_cmd_set_rts_threshold(struct ieee80211_hw *hw, int rts_thresh)
@@ -2466,7 +2467,7 @@ struct mwl8k_cmd_set_slot {
struct mwl8k_cmd_pkt header;
__le16 action;
__u8 short_slot;
-} __attribute__((packed));
+} __packed;
static int mwl8k_cmd_set_slot(struct ieee80211_hw *hw, bool short_slot_time)
{
@@ -2528,7 +2529,7 @@ struct mwl8k_cmd_set_edca_params {
__u8 txq;
} sta;
};
-} __attribute__((packed));
+} __packed;
#define MWL8K_SET_EDCA_CW 0x01
#define MWL8K_SET_EDCA_TXOP 0x02
@@ -2579,7 +2580,7 @@ mwl8k_cmd_set_edca_params(struct ieee80211_hw *hw, __u8 qnum,
struct mwl8k_cmd_set_wmm_mode {
struct mwl8k_cmd_pkt header;
__le16 action;
-} __attribute__((packed));
+} __packed;
static int mwl8k_cmd_set_wmm_mode(struct ieee80211_hw *hw, bool enable)
{
@@ -2612,7 +2613,7 @@ struct mwl8k_cmd_mimo_config {
__le32 action;
__u8 rx_antenna_map;
__u8 tx_antenna_map;
-} __attribute__((packed));
+} __packed;
static int mwl8k_cmd_mimo_config(struct ieee80211_hw *hw, __u8 rx, __u8 tx)
{
@@ -2652,7 +2653,7 @@ struct mwl8k_cmd_use_fixed_rate_sta {
__le32 rate_type;
__le32 reserved1;
__le32 reserved2;
-} __attribute__((packed));
+} __packed;
#define MWL8K_USE_AUTO_RATE 0x0002
#define MWL8K_UCAST_RATE 0
@@ -2694,7 +2695,7 @@ struct mwl8k_cmd_use_fixed_rate_ap {
u8 multicast_rate;
u8 multicast_rate_type;
u8 management_rate;
-} __attribute__((packed));
+} __packed;
static int
mwl8k_cmd_use_fixed_rate_ap(struct ieee80211_hw *hw, int mcast, int mgmt)
@@ -2724,7 +2725,7 @@ mwl8k_cmd_use_fixed_rate_ap(struct ieee80211_hw *hw, int mcast, int mgmt)
struct mwl8k_cmd_enable_sniffer {
struct mwl8k_cmd_pkt header;
__le32 action;
-} __attribute__((packed));
+} __packed;
static int mwl8k_cmd_enable_sniffer(struct ieee80211_hw *hw, bool enable)
{
@@ -2757,7 +2758,7 @@ struct mwl8k_cmd_set_mac_addr {
} mbss;
__u8 mac_addr[ETH_ALEN];
};
-} __attribute__((packed));
+} __packed;
#define MWL8K_MAC_TYPE_PRIMARY_CLIENT 0
#define MWL8K_MAC_TYPE_SECONDARY_CLIENT 1
@@ -2812,7 +2813,7 @@ struct mwl8k_cmd_set_rate_adapt_mode {
struct mwl8k_cmd_pkt header;
__le16 action;
__le16 mode;
-} __attribute__((packed));
+} __packed;
static int mwl8k_cmd_set_rateadapt_mode(struct ieee80211_hw *hw, __u16 mode)
{
@@ -2840,7 +2841,7 @@ static int mwl8k_cmd_set_rateadapt_mode(struct ieee80211_hw *hw, __u16 mode)
struct mwl8k_cmd_bss_start {
struct mwl8k_cmd_pkt header;
__le32 enable;
-} __attribute__((packed));
+} __packed;
static int mwl8k_cmd_bss_start(struct ieee80211_hw *hw,
struct ieee80211_vif *vif, int enable)
@@ -2885,7 +2886,7 @@ struct mwl8k_cmd_set_new_stn {
__u8 add_qos_info;
__u8 is_qos_sta;
__le32 fw_sta_ptr;
-} __attribute__((packed));
+} __packed;
#define MWL8K_STA_ACTION_ADD 0
#define MWL8K_STA_ACTION_REMOVE 2
@@ -2978,7 +2979,7 @@ struct ewc_ht_info {
__le16 control1;
__le16 control2;
__le16 control3;
-} __attribute__((packed));
+} __packed;
struct peer_capability_info {
/* Peer type - AP vs. STA. */
@@ -3007,7 +3008,7 @@ struct peer_capability_info {
__u8 pad2;
__u8 station_id;
__le16 amsdu_enabled;
-} __attribute__((packed));
+} __packed;
struct mwl8k_cmd_update_stadb {
struct mwl8k_cmd_pkt header;
@@ -3022,7 +3023,7 @@ struct mwl8k_cmd_update_stadb {
/* Peer info - valid during add/update. */
struct peer_capability_info peer_info;
-} __attribute__((packed));
+} __packed;
#define MWL8K_STA_DB_MODIFY_ENTRY 1
#define MWL8K_STA_DB_DEL_ENTRY 2
@@ -3052,7 +3053,7 @@ static int mwl8k_cmd_update_stadb_add(struct ieee80211_hw *hw,
p->peer_type = MWL8K_PEER_TYPE_ACCESSPOINT;
p->basic_caps = cpu_to_le16(vif->bss_conf.assoc_capability);
p->ht_support = sta->ht_cap.ht_supported;
- p->ht_caps = sta->ht_cap.cap;
+ p->ht_caps = cpu_to_le16(sta->ht_cap.cap);
p->extended_ht_caps = (sta->ht_cap.ampdu_factor & 3) |
((sta->ht_cap.ampdu_density & 7) << 2);
if (hw->conf.channel->band == IEEE80211_BAND_2GHZ)
@@ -3190,8 +3191,8 @@ static int mwl8k_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
int rc;
if (!priv->radio_on) {
- printk(KERN_DEBUG "%s: dropped TX frame since radio "
- "disabled\n", wiphy_name(hw->wiphy));
+ wiphy_debug(hw->wiphy,
+ "dropped TX frame since radio disabled\n");
dev_kfree_skb(skb);
return NETDEV_TX_OK;
}
@@ -3209,8 +3210,7 @@ static int mwl8k_start(struct ieee80211_hw *hw)
rc = request_irq(priv->pdev->irq, mwl8k_interrupt,
IRQF_SHARED, MWL8K_NAME, hw);
if (rc) {
- printk(KERN_ERR "%s: failed to register IRQ handler\n",
- wiphy_name(hw->wiphy));
+ wiphy_err(hw->wiphy, "failed to register irq handler\n");
return -EIO;
}
@@ -3297,9 +3297,8 @@ static int mwl8k_add_interface(struct ieee80211_hw *hw,
* mode. (Sniffer mode is only used on STA firmware.)
*/
if (priv->sniffer_enabled) {
- printk(KERN_INFO "%s: unable to create STA "
- "interface due to sniffer mode being enabled\n",
- wiphy_name(hw->wiphy));
+ wiphy_info(hw->wiphy,
+ "unable to create STA interface because sniffer mode is enabled\n");
return -EINVAL;
}
@@ -3581,9 +3580,8 @@ mwl8k_configure_filter_sniffer(struct ieee80211_hw *hw,
*/
if (!list_empty(&priv->vif_list)) {
if (net_ratelimit())
- printk(KERN_INFO "%s: not enabling sniffer "
- "mode because STA interface is active\n",
- wiphy_name(hw->wiphy));
+ wiphy_info(hw->wiphy,
+ "not enabling sniffer mode because STA interface is active\n");
return 0;
}
@@ -3763,6 +3761,22 @@ static int mwl8k_get_stats(struct ieee80211_hw *hw,
return mwl8k_cmd_get_stat(hw, stats);
}
+static int mwl8k_get_survey(struct ieee80211_hw *hw, int idx,
+ struct survey_info *survey)
+{
+ struct mwl8k_priv *priv = hw->priv;
+ struct ieee80211_conf *conf = &hw->conf;
+
+ if (idx != 0)
+ return -ENOENT;
+
+ survey->channel = conf->channel;
+ survey->filled = SURVEY_INFO_NOISE_DBM;
+ survey->noise = priv->noise;
+
+ return 0;
+}
+
static int
mwl8k_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
enum ieee80211_ampdu_mlme_action action,
@@ -3794,6 +3808,7 @@ static const struct ieee80211_ops mwl8k_ops = {
.sta_remove = mwl8k_sta_remove,
.conf_tx = mwl8k_conf_tx,
.get_stats = mwl8k_get_stats,
+ .get_survey = mwl8k_get_survey,
.ampdu_action = mwl8k_ampdu_action,
};
@@ -3911,8 +3926,7 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev,
priv->sram = pci_iomap(pdev, 0, 0x10000);
if (priv->sram == NULL) {
- printk(KERN_ERR "%s: Cannot map device SRAM\n",
- wiphy_name(hw->wiphy));
+ wiphy_err(hw->wiphy, "cannot map device sram\n");
goto err_iounmap;
}
@@ -3924,8 +3938,7 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev,
if (priv->regs == NULL) {
priv->regs = pci_iomap(pdev, 2, 0x10000);
if (priv->regs == NULL) {
- printk(KERN_ERR "%s: Cannot map device registers\n",
- wiphy_name(hw->wiphy));
+ wiphy_err(hw->wiphy, "cannot map device registers\n");
goto err_iounmap;
}
}
@@ -3937,16 +3950,14 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev,
/* Ask userland hotplug daemon for the device firmware */
rc = mwl8k_request_firmware(priv);
if (rc) {
- printk(KERN_ERR "%s: Firmware files not found\n",
- wiphy_name(hw->wiphy));
+ wiphy_err(hw->wiphy, "firmware files not found\n");
goto err_stop_firmware;
}
/* Load firmware into hardware */
rc = mwl8k_load_firmware(hw);
if (rc) {
- printk(KERN_ERR "%s: Cannot start firmware\n",
- wiphy_name(hw->wiphy));
+ wiphy_err(hw->wiphy, "cannot start firmware\n");
goto err_stop_firmware;
}
@@ -3957,9 +3968,8 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev,
if (priv->ap_fw) {
priv->rxd_ops = priv->device_info->ap_rxd_ops;
if (priv->rxd_ops == NULL) {
- printk(KERN_ERR "%s: Driver does not have AP "
- "firmware image support for this hardware\n",
- wiphy_name(hw->wiphy));
+ wiphy_err(hw->wiphy,
+ "Driver does not have AP firmware image support for this hardware\n");
goto err_stop_firmware;
}
} else {
@@ -4037,8 +4047,7 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev,
rc = request_irq(priv->pdev->irq, mwl8k_interrupt,
IRQF_SHARED, MWL8K_NAME, hw);
if (rc) {
- printk(KERN_ERR "%s: failed to register IRQ handler\n",
- wiphy_name(hw->wiphy));
+ wiphy_err(hw->wiphy, "failed to register irq handler\n");
goto err_free_queues;
}
@@ -4058,8 +4067,7 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev,
rc = mwl8k_cmd_get_hw_spec_sta(hw);
}
if (rc) {
- printk(KERN_ERR "%s: Cannot initialise firmware\n",
- wiphy_name(hw->wiphy));
+ wiphy_err(hw->wiphy, "cannot initialise firmware\n");
goto err_free_irq;
}
@@ -4073,15 +4081,14 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev,
/* Turn radio off */
rc = mwl8k_cmd_radio_disable(hw);
if (rc) {
- printk(KERN_ERR "%s: Cannot disable\n", wiphy_name(hw->wiphy));
+ wiphy_err(hw->wiphy, "cannot disable\n");
goto err_free_irq;
}
/* Clear MAC address */
rc = mwl8k_cmd_set_mac_addr(hw, NULL, "\x00\x00\x00\x00\x00\x00");
if (rc) {
- printk(KERN_ERR "%s: Cannot clear MAC address\n",
- wiphy_name(hw->wiphy));
+ wiphy_err(hw->wiphy, "cannot clear mac address\n");
goto err_free_irq;
}
@@ -4091,17 +4098,16 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev,
rc = ieee80211_register_hw(hw);
if (rc) {
- printk(KERN_ERR "%s: Cannot register device\n",
- wiphy_name(hw->wiphy));
+ wiphy_err(hw->wiphy, "cannot register device\n");
goto err_free_queues;
}
- printk(KERN_INFO "%s: %s v%d, %pM, %s firmware %u.%u.%u.%u\n",
- wiphy_name(hw->wiphy), priv->device_info->part_name,
- priv->hw_rev, hw->wiphy->perm_addr,
- priv->ap_fw ? "AP" : "STA",
- (priv->fw_rev >> 24) & 0xff, (priv->fw_rev >> 16) & 0xff,
- (priv->fw_rev >> 8) & 0xff, priv->fw_rev & 0xff);
+ wiphy_info(hw->wiphy, "%s v%d, %pm, %s firmware %u.%u.%u.%u\n",
+ priv->device_info->part_name,
+ priv->hw_rev, hw->wiphy->perm_addr,
+ priv->ap_fw ? "AP" : "STA",
+ (priv->fw_rev >> 24) & 0xff, (priv->fw_rev >> 16) & 0xff,
+ (priv->fw_rev >> 8) & 0xff, priv->fw_rev & 0xff);
return 0;
diff --git a/drivers/net/wireless/orinoco/cfg.c b/drivers/net/wireless/orinoco/cfg.c
index 8c4169c227a..09fae2f0ea0 100644
--- a/drivers/net/wireless/orinoco/cfg.c
+++ b/drivers/net/wireless/orinoco/cfg.c
@@ -117,9 +117,8 @@ static int orinoco_change_vif(struct wiphy *wiphy, struct net_device *dev,
case NL80211_IFTYPE_MONITOR:
if (priv->broken_monitor && !force_monitor) {
- printk(KERN_WARNING "%s: Monitor mode support is "
- "buggy in this firmware, not enabling\n",
- wiphy_name(wiphy));
+ wiphy_warn(wiphy,
+ "Monitor mode support is buggy in this firmware, not enabling\n");
err = -EINVAL;
}
break;
diff --git a/drivers/net/wireless/orinoco/fw.c b/drivers/net/wireless/orinoco/fw.c
index 3e1947d097c..259d7585398 100644
--- a/drivers/net/wireless/orinoco/fw.c
+++ b/drivers/net/wireless/orinoco/fw.c
@@ -49,7 +49,7 @@ struct orinoco_fw_header {
__le32 pri_offset; /* Offset to primary plug data */
__le32 compat_offset; /* Offset to compatibility data*/
char signature[0]; /* FW signature length headersize-20 */
-} __attribute__ ((packed));
+} __packed;
/* Check the range of various header entries. Return a pointer to a
* description of the problem, or NULL if everything checks out. */
diff --git a/drivers/net/wireless/orinoco/hermes.h b/drivers/net/wireless/orinoco/hermes.h
index 9ca34e722b4..d9f18c11682 100644
--- a/drivers/net/wireless/orinoco/hermes.h
+++ b/drivers/net/wireless/orinoco/hermes.h
@@ -205,7 +205,7 @@ struct hermes_tx_descriptor {
u8 retry_count;
u8 tx_rate;
__le16 tx_control;
-} __attribute__ ((packed));
+} __packed;
#define HERMES_TXSTAT_RETRYERR (0x0001)
#define HERMES_TXSTAT_AGEDERR (0x0002)
@@ -254,7 +254,7 @@ struct hermes_tallies_frame {
/* Those last are probably not available in very old firmwares */
__le16 RxDiscards_WEPICVError;
__le16 RxDiscards_WEPExcluded;
-} __attribute__ ((packed));
+} __packed;
/* Grabbed from wlan-ng - Thanks Mark... - Jean II
* This is the result of a scan inquiry command */
@@ -271,7 +271,7 @@ struct prism2_scan_apinfo {
u8 rates[10]; /* Bit rate supported */
__le16 proberesp_rate; /* Data rate of the response frame */
__le16 atim; /* ATIM window time, Kus (hostscan only) */
-} __attribute__ ((packed));
+} __packed;
/* Same stuff for the Lucent/Agere card.
* Thanks to h1kari <h1kari AT dachb0den.com> - Jean II */
@@ -285,7 +285,7 @@ struct agere_scan_apinfo {
/* bits: 0-ess, 1-ibss, 4-privacy [wep] */
__le16 essid_len; /* ESSID length */
u8 essid[32]; /* ESSID of the network */
-} __attribute__ ((packed));
+} __packed;
/* Moustafa: Scan structure for Symbol cards */
struct symbol_scan_apinfo {
@@ -303,7 +303,7 @@ struct symbol_scan_apinfo {
__le16 basic_rates; /* Basic rates bitmask */
u8 unknown2[6]; /* Always FF:FF:FF:FF:00:00 */
u8 unknown3[8]; /* Always 0, appeared in f/w 3.91-68 */
-} __attribute__ ((packed));
+} __packed;
union hermes_scan_info {
struct agere_scan_apinfo a;
@@ -343,7 +343,7 @@ struct agere_ext_scan_info {
__le16 beacon_interval;
__le16 capabilities;
u8 data[0];
-} __attribute__ ((packed));
+} __packed;
#define HERMES_LINKSTATUS_NOT_CONNECTED (0x0000)
#define HERMES_LINKSTATUS_CONNECTED (0x0001)
@@ -355,7 +355,7 @@ struct agere_ext_scan_info {
struct hermes_linkstatus {
__le16 linkstatus; /* Link status */
-} __attribute__ ((packed));
+} __packed;
struct hermes_response {
u16 status, resp0, resp1, resp2;
@@ -365,11 +365,11 @@ struct hermes_response {
struct hermes_idstring {
__le16 len;
__le16 val[16];
-} __attribute__ ((packed));
+} __packed;
struct hermes_multicast {
u8 addr[HERMES_MAX_MULTICAST][ETH_ALEN];
-} __attribute__ ((packed));
+} __packed;
/* Timeouts */
#define HERMES_BAP_BUSY_TIMEOUT (10000) /* In iterations of ~1us */
diff --git a/drivers/net/wireless/orinoco/hermes_dld.c b/drivers/net/wireless/orinoco/hermes_dld.c
index 6da85e75fce..2b2b9a1a979 100644
--- a/drivers/net/wireless/orinoco/hermes_dld.c
+++ b/drivers/net/wireless/orinoco/hermes_dld.c
@@ -65,10 +65,10 @@ struct dblock {
__le32 addr; /* adapter address where to write the block */
__le16 len; /* length of the data only, in bytes */
char data[0]; /* data to be written */
-} __attribute__ ((packed));
+} __packed;
/*
- * Plug Data References are located in in the image after the last data
+ * Plug Data References are located in the image after the last data
* block. They refer to areas in the adapter memory where the plug data
* items with matching ID should be written.
*/
@@ -77,7 +77,7 @@ struct pdr {
__le32 addr; /* adapter address where to write the data */
__le32 len; /* expected length of the data, in bytes */
char next[0]; /* next PDR starts here */
-} __attribute__ ((packed));
+} __packed;
/*
* Plug Data Items are located in the EEPROM read from the adapter by
@@ -88,7 +88,7 @@ struct pdi {
__le16 len; /* length of ID and data, in words */
__le16 id; /* record ID */
char data[0]; /* plug data */
-} __attribute__ ((packed));
+} __packed;
/*** FW data block access functions ***/
@@ -317,7 +317,7 @@ static const struct { \
__le16 len; \
__le16 id; \
u8 val[length]; \
-} __attribute__ ((packed)) default_pdr_data_##pid = { \
+} __packed default_pdr_data_##pid = { \
cpu_to_le16((sizeof(default_pdr_data_##pid)/ \
sizeof(__le16)) - 1), \
cpu_to_le16(pid), \
diff --git a/drivers/net/wireless/orinoco/hw.c b/drivers/net/wireless/orinoco/hw.c
index 6fbd7885012..077baa86756 100644
--- a/drivers/net/wireless/orinoco/hw.c
+++ b/drivers/net/wireless/orinoco/hw.c
@@ -45,7 +45,7 @@ static const struct {
/* Firmware version encoding */
struct comp_id {
u16 id, variant, major, minor;
-} __attribute__ ((packed));
+} __packed;
static inline fwtype_t determine_firmware_type(struct comp_id *nic_id)
{
@@ -995,7 +995,7 @@ int __orinoco_hw_set_tkip_key(struct orinoco_private *priv, int key_idx,
u8 tx_mic[MIC_KEYLEN];
u8 rx_mic[MIC_KEYLEN];
u8 tsc[ORINOCO_SEQ_LEN];
- } __attribute__ ((packed)) buf;
+ } __packed buf;
hermes_t *hw = &priv->hw;
int ret;
int err;
@@ -1326,7 +1326,7 @@ int orinoco_hw_disassociate(struct orinoco_private *priv,
struct {
u8 addr[ETH_ALEN];
__le16 reason_code;
- } __attribute__ ((packed)) buf;
+ } __packed buf;
/* Currently only supported by WPA enabled Agere fw */
if (!priv->has_wpa)
diff --git a/drivers/net/wireless/orinoco/main.c b/drivers/net/wireless/orinoco/main.c
index ca71f08709b..e8e2d0f4763 100644
--- a/drivers/net/wireless/orinoco/main.c
+++ b/drivers/net/wireless/orinoco/main.c
@@ -172,7 +172,7 @@ struct hermes_txexc_data {
__le16 frame_ctl;
__le16 duration_id;
u8 addr1[ETH_ALEN];
-} __attribute__ ((packed));
+} __packed;
/* Rx frame header except compatibility 802.3 header */
struct hermes_rx_descriptor {
@@ -196,7 +196,7 @@ struct hermes_rx_descriptor {
/* Data length */
__le16 data_len;
-} __attribute__ ((packed));
+} __packed;
struct orinoco_rx_data {
struct hermes_rx_descriptor *desc;
@@ -390,7 +390,7 @@ int orinoco_process_xmit_skb(struct sk_buff *skb,
struct header_struct {
struct ethhdr eth; /* 802.3 header */
u8 encap[6]; /* 802.2 header */
- } __attribute__ ((packed)) hdr;
+ } __packed hdr;
int len = skb->len + sizeof(encaps_hdr) - (2 * ETH_ALEN);
if (skb_headroom(skb) < ENCAPS_OVERHEAD) {
@@ -1170,7 +1170,7 @@ static void orinoco_join_ap(struct work_struct *work)
struct join_req {
u8 bssid[ETH_ALEN];
__le16 channel;
- } __attribute__ ((packed)) req;
+ } __packed req;
const int atom_len = offsetof(struct prism2_scan_apinfo, atim);
struct prism2_scan_apinfo *atom = NULL;
int offset = 4;
@@ -1410,7 +1410,7 @@ void __orinoco_ev_info(struct net_device *dev, hermes_t *hw)
struct {
__le16 len;
__le16 type;
- } __attribute__ ((packed)) info;
+ } __packed info;
int len, type;
int err;
diff --git a/drivers/net/wireless/orinoco/orinoco.h b/drivers/net/wireless/orinoco/orinoco.h
index a6da86e0a70..255710ef082 100644
--- a/drivers/net/wireless/orinoco/orinoco.h
+++ b/drivers/net/wireless/orinoco/orinoco.h
@@ -32,7 +32,7 @@
struct orinoco_key {
__le16 len; /* always stored as little-endian */
char data[ORINOCO_MAX_KEY_SIZE];
-} __attribute__ ((packed));
+} __packed;
#define TKIP_KEYLEN 16
#define MIC_KEYLEN 8
diff --git a/drivers/net/wireless/orinoco/orinoco_cs.c b/drivers/net/wireless/orinoco/orinoco_cs.c
index b16d5db52a4..ef46a2d8853 100644
--- a/drivers/net/wireless/orinoco/orinoco_cs.c
+++ b/drivers/net/wireless/orinoco/orinoco_cs.c
@@ -17,7 +17,6 @@
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/delay.h>
-#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/cistpl.h>
#include <pcmcia/cisreg.h>
@@ -192,25 +191,23 @@ static int orinoco_cs_config_check(struct pcmcia_device *p_dev,
p_dev->conf.Attributes |= CONF_ENABLE_IRQ;
/* IO window settings */
- p_dev->io.NumPorts1 = p_dev->io.NumPorts2 = 0;
+ p_dev->resource[0]->end = p_dev->resource[1]->end = 0;
if ((cfg->io.nwin > 0) || (dflt->io.nwin > 0)) {
cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt->io;
- p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
- if (!(io->flags & CISTPL_IO_8BIT))
- p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_16;
- if (!(io->flags & CISTPL_IO_16BIT))
- p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
- p_dev->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK;
- p_dev->io.BasePort1 = io->win[0].base;
- p_dev->io.NumPorts1 = io->win[0].len;
+ p_dev->io_lines = io->flags & CISTPL_IO_LINES_MASK;
+ p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH;
+ p_dev->resource[0]->flags |=
+ pcmcia_io_cfg_data_width(io->flags);
+ p_dev->resource[0]->start = io->win[0].base;
+ p_dev->resource[0]->end = io->win[0].len;
if (io->nwin > 1) {
- p_dev->io.Attributes2 = p_dev->io.Attributes1;
- p_dev->io.BasePort2 = io->win[1].base;
- p_dev->io.NumPorts2 = io->win[1].len;
+ p_dev->resource[1]->flags = p_dev->resource[0]->flags;
+ p_dev->resource[1]->start = io->win[1].base;
+ p_dev->resource[1]->end = io->win[1].len;
}
/* This reserves IO space but doesn't actually enable it */
- if (pcmcia_request_io(p_dev, &p_dev->io) != 0)
+ if (pcmcia_request_io(p_dev) != 0)
goto next_entry;
}
return 0;
@@ -258,7 +255,8 @@ orinoco_cs_config(struct pcmcia_device *link)
/* We initialize the hermes structure before completing PCMCIA
* configuration just in case the interrupt handler gets
* called. */
- mem = ioport_map(link->io.BasePort1, link->io.NumPorts1);
+ mem = ioport_map(link->resource[0]->start,
+ resource_size(link->resource[0]));
if (!mem)
goto failed;
@@ -280,7 +278,7 @@ orinoco_cs_config(struct pcmcia_device *link)
}
/* Register an interface with the stack */
- if (orinoco_if_add(priv, link->io.BasePort1,
+ if (orinoco_if_add(priv, link->resource[0]->start,
link->irq, NULL) != 0) {
printk(KERN_ERR PFX "orinoco_if_add() failed\n");
goto failed;
diff --git a/drivers/net/wireless/orinoco/orinoco_usb.c b/drivers/net/wireless/orinoco/orinoco_usb.c
index 78f089baa8c..a38a7bd25f1 100644
--- a/drivers/net/wireless/orinoco/orinoco_usb.c
+++ b/drivers/net/wireless/orinoco/orinoco_usb.c
@@ -90,7 +90,7 @@ struct header_struct {
/* SNAP */
u8 oui[3];
__be16 ethertype;
-} __attribute__ ((packed));
+} __packed;
struct ez_usb_fw {
u16 size;
@@ -222,7 +222,7 @@ struct ezusb_packet {
__le16 hermes_len;
__le16 hermes_rid;
u8 data[0];
-} __attribute__ ((packed));
+} __packed;
/* Table of devices that work or may work with this driver */
static struct usb_device_id ezusb_table[] = {
@@ -356,12 +356,10 @@ static struct request_context *ezusb_alloc_ctx(struct ezusb_priv *upriv,
{
struct request_context *ctx;
- ctx = kmalloc(sizeof(*ctx), GFP_ATOMIC);
+ ctx = kzalloc(sizeof(*ctx), GFP_ATOMIC);
if (!ctx)
return NULL;
- memset(ctx, 0, sizeof(*ctx));
-
ctx->buf = kmalloc(BULK_BUF_SIZE, GFP_ATOMIC);
if (!ctx->buf) {
kfree(ctx);
@@ -1504,16 +1502,16 @@ static inline void ezusb_delete(struct ezusb_priv *upriv)
ezusb_ctx_complete(list_entry(item,
struct request_context, list));
- if (upriv->read_urb->status == -EINPROGRESS)
+ if (upriv->read_urb && upriv->read_urb->status == -EINPROGRESS)
printk(KERN_ERR PFX "Some URB in progress\n");
mutex_unlock(&upriv->mtx);
- kfree(upriv->read_urb->transfer_buffer);
- if (upriv->bap_buf != NULL)
- kfree(upriv->bap_buf);
- if (upriv->read_urb != NULL)
+ if (upriv->read_urb) {
+ kfree(upriv->read_urb->transfer_buffer);
usb_free_urb(upriv->read_urb);
+ }
+ kfree(upriv->bap_buf);
if (upriv->dev) {
struct orinoco_private *priv = ndev_priv(upriv->dev);
orinoco_if_del(priv);
diff --git a/drivers/net/wireless/orinoco/spectrum_cs.c b/drivers/net/wireless/orinoco/spectrum_cs.c
index b51a9adc80f..873877e17e1 100644
--- a/drivers/net/wireless/orinoco/spectrum_cs.c
+++ b/drivers/net/wireless/orinoco/spectrum_cs.c
@@ -25,7 +25,6 @@
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/delay.h>
-#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/cistpl.h>
#include <pcmcia/cisreg.h>
@@ -80,35 +79,27 @@ static int
spectrum_reset(struct pcmcia_device *link, int idle)
{
int ret;
- conf_reg_t reg;
- u_int save_cor;
+ u8 save_cor;
+ u8 ccsr;
/* Doing it if hardware is gone is guaranteed crash */
if (!pcmcia_dev_present(link))
return -ENODEV;
/* Save original COR value */
- reg.Function = 0;
- reg.Action = CS_READ;
- reg.Offset = CISREG_COR;
- ret = pcmcia_access_configuration_register(link, &reg);
+ ret = pcmcia_read_config_byte(link, CISREG_COR, &save_cor);
if (ret)
goto failed;
- save_cor = reg.Value;
/* Soft-Reset card */
- reg.Action = CS_WRITE;
- reg.Offset = CISREG_COR;
- reg.Value = (save_cor | COR_SOFT_RESET);
- ret = pcmcia_access_configuration_register(link, &reg);
+ ret = pcmcia_write_config_byte(link, CISREG_COR,
+ (save_cor | COR_SOFT_RESET));
if (ret)
goto failed;
udelay(1000);
/* Read CCSR */
- reg.Action = CS_READ;
- reg.Offset = CISREG_CCSR;
- ret = pcmcia_access_configuration_register(link, &reg);
+ ret = pcmcia_read_config_byte(link, CISREG_CCSR, &ccsr);
if (ret)
goto failed;
@@ -116,19 +107,15 @@ spectrum_reset(struct pcmcia_device *link, int idle)
* Start or stop the firmware. Memory width bit should be
* preserved from the value we've just read.
*/
- reg.Action = CS_WRITE;
- reg.Offset = CISREG_CCSR;
- reg.Value = (idle ? HCR_IDLE : HCR_RUN) | (reg.Value & HCR_MEM16);
- ret = pcmcia_access_configuration_register(link, &reg);
+ ccsr = (idle ? HCR_IDLE : HCR_RUN) | (ccsr & HCR_MEM16);
+ ret = pcmcia_write_config_byte(link, CISREG_CCSR, ccsr);
if (ret)
goto failed;
udelay(1000);
/* Restore original COR configuration index */
- reg.Action = CS_WRITE;
- reg.Offset = CISREG_COR;
- reg.Value = (save_cor & ~COR_SOFT_RESET);
- ret = pcmcia_access_configuration_register(link, &reg);
+ ret = pcmcia_write_config_byte(link, CISREG_COR,
+ (save_cor & ~COR_SOFT_RESET));
if (ret)
goto failed;
udelay(1000);
@@ -266,25 +253,23 @@ static int spectrum_cs_config_check(struct pcmcia_device *p_dev,
p_dev->conf.Attributes |= CONF_ENABLE_IRQ;
/* IO window settings */
- p_dev->io.NumPorts1 = p_dev->io.NumPorts2 = 0;
+ p_dev->resource[0]->end = p_dev->resource[1]->end = 0;
if ((cfg->io.nwin > 0) || (dflt->io.nwin > 0)) {
cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt->io;
- p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
- if (!(io->flags & CISTPL_IO_8BIT))
- p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_16;
- if (!(io->flags & CISTPL_IO_16BIT))
- p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
- p_dev->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK;
- p_dev->io.BasePort1 = io->win[0].base;
- p_dev->io.NumPorts1 = io->win[0].len;
+ p_dev->io_lines = io->flags & CISTPL_IO_LINES_MASK;
+ p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH;
+ p_dev->resource[0]->flags |=
+ pcmcia_io_cfg_data_width(io->flags);
+ p_dev->resource[0]->start = io->win[0].base;
+ p_dev->resource[0]->end = io->win[0].len;
if (io->nwin > 1) {
- p_dev->io.Attributes2 = p_dev->io.Attributes1;
- p_dev->io.BasePort2 = io->win[1].base;
- p_dev->io.NumPorts2 = io->win[1].len;
+ p_dev->resource[1]->flags = p_dev->resource[0]->flags;
+ p_dev->resource[1]->start = io->win[1].base;
+ p_dev->resource[1]->end = io->win[1].len;
}
/* This reserves IO space but doesn't actually enable it */
- if (pcmcia_request_io(p_dev, &p_dev->io) != 0)
+ if (pcmcia_request_io(p_dev) != 0)
goto next_entry;
}
return 0;
@@ -332,7 +317,8 @@ spectrum_cs_config(struct pcmcia_device *link)
/* We initialize the hermes structure before completing PCMCIA
* configuration just in case the interrupt handler gets
* called. */
- mem = ioport_map(link->io.BasePort1, link->io.NumPorts1);
+ mem = ioport_map(link->resource[0]->start,
+ resource_size(link->resource[0]));
if (!mem)
goto failed;
@@ -359,7 +345,7 @@ spectrum_cs_config(struct pcmcia_device *link)
}
/* Register an interface with the stack */
- if (orinoco_if_add(priv, link->io.BasePort1,
+ if (orinoco_if_add(priv, link->resource[0]->start,
link->irq, NULL) != 0) {
printk(KERN_ERR PFX "orinoco_if_add() failed\n");
goto failed;
diff --git a/drivers/net/wireless/orinoco/wext.c b/drivers/net/wireless/orinoco/wext.c
index 5775124e2ae..cf7be1eb612 100644
--- a/drivers/net/wireless/orinoco/wext.c
+++ b/drivers/net/wireless/orinoco/wext.c
@@ -128,7 +128,7 @@ static struct iw_statistics *orinoco_get_wireless_stats(struct net_device *dev)
} else {
struct {
__le16 qual, signal, noise, unused;
- } __attribute__ ((packed)) cq;
+ } __packed cq;
err = HERMES_READ_RECORD(hw, USER_BAP,
HERMES_RID_COMMSQUALITY, &cq);
@@ -993,11 +993,9 @@ static int orinoco_ioctl_set_genie(struct net_device *dev,
return -EINVAL;
if (wrqu->data.length) {
- buf = kmalloc(wrqu->data.length, GFP_KERNEL);
+ buf = kmemdup(extra, wrqu->data.length, GFP_KERNEL);
if (buf == NULL)
return -ENOMEM;
-
- memcpy(buf, extra, wrqu->data.length);
} else
buf = NULL;
diff --git a/drivers/net/wireless/p54/eeprom.c b/drivers/net/wireless/p54/eeprom.c
index 187e263b045..d687cb7f2a5 100644
--- a/drivers/net/wireless/p54/eeprom.c
+++ b/drivers/net/wireless/p54/eeprom.c
@@ -149,16 +149,15 @@ static int p54_generate_band(struct ieee80211_hw *dev,
continue;
if (list->channels[i].data != CHAN_HAS_ALL) {
- printk(KERN_ERR "%s:%s%s%s is/are missing for "
- "channel:%d [%d MHz].\n",
- wiphy_name(dev->wiphy),
- (list->channels[i].data & CHAN_HAS_CAL ? "" :
- " [iqauto calibration data]"),
- (list->channels[i].data & CHAN_HAS_LIMIT ? "" :
- " [output power limits]"),
- (list->channels[i].data & CHAN_HAS_CURVE ? "" :
- " [curve data]"),
- list->channels[i].index, list->channels[i].freq);
+ wiphy_err(dev->wiphy,
+ "%s%s%s is/are missing for channel:%d [%d MHz].\n",
+ (list->channels[i].data & CHAN_HAS_CAL ? "" :
+ " [iqauto calibration data]"),
+ (list->channels[i].data & CHAN_HAS_LIMIT ? "" :
+ " [output power limits]"),
+ (list->channels[i].data & CHAN_HAS_CURVE ? "" :
+ " [curve data]"),
+ list->channels[i].index, list->channels[i].freq);
continue;
}
@@ -168,9 +167,8 @@ static int p54_generate_band(struct ieee80211_hw *dev,
}
if (j == 0) {
- printk(KERN_ERR "%s: Disabling totally damaged %s band.\n",
- wiphy_name(dev->wiphy), (band == IEEE80211_BAND_2GHZ) ?
- "2 GHz" : "5 GHz");
+ wiphy_err(dev->wiphy, "disabling totally damaged %d GHz band\n",
+ (band == IEEE80211_BAND_2GHZ) ? 2 : 5);
ret = -ENODATA;
goto err_out;
@@ -244,9 +242,9 @@ static int p54_generate_channel_lists(struct ieee80211_hw *dev)
if ((priv->iq_autocal_len != priv->curve_data->entries) ||
(priv->iq_autocal_len != priv->output_limit->entries))
- printk(KERN_ERR "%s: Unsupported or damaged EEPROM detected. "
- "You may not be able to use all channels.\n",
- wiphy_name(dev->wiphy));
+ wiphy_err(dev->wiphy,
+ "Unsupported or damaged EEPROM detected. "
+ "You may not be able to use all channels.\n");
max_channel_num = max_t(unsigned int, priv->output_limit->entries,
priv->iq_autocal_len);
@@ -419,15 +417,14 @@ static void p54_parse_rssical(struct ieee80211_hw *dev, void *data, int len,
int i;
if (len != (entry_size * num_entries)) {
- printk(KERN_ERR "%s: unknown rssi calibration data packing "
- " type:(%x) len:%d.\n",
- wiphy_name(dev->wiphy), type, len);
+ wiphy_err(dev->wiphy,
+ "unknown rssi calibration data packing type:(%x) len:%d.\n",
+ type, len);
print_hex_dump_bytes("rssical:", DUMP_PREFIX_NONE,
data, len);
- printk(KERN_ERR "%s: please report this issue.\n",
- wiphy_name(dev->wiphy));
+ wiphy_err(dev->wiphy, "please report this issue.\n");
return;
}
@@ -445,15 +442,14 @@ static void p54_parse_default_country(struct ieee80211_hw *dev,
struct pda_country *country;
if (len != sizeof(*country)) {
- printk(KERN_ERR "%s: found possible invalid default country "
- "eeprom entry. (entry size: %d)\n",
- wiphy_name(dev->wiphy), len);
+ wiphy_err(dev->wiphy,
+ "found possible invalid default country eeprom entry. (entry size: %d)\n",
+ len);
print_hex_dump_bytes("country:", DUMP_PREFIX_NONE,
data, len);
- printk(KERN_ERR "%s: please report this issue.\n",
- wiphy_name(dev->wiphy));
+ wiphy_err(dev->wiphy, "please report this issue.\n");
return;
}
@@ -478,8 +474,8 @@ static int p54_convert_output_limits(struct ieee80211_hw *dev,
return -EINVAL;
if (data[0] != 0) {
- printk(KERN_ERR "%s: unknown output power db revision:%x\n",
- wiphy_name(dev->wiphy), data[0]);
+ wiphy_err(dev->wiphy, "unknown output power db revision:%x\n",
+ data[0]);
return -EINVAL;
}
@@ -587,10 +583,9 @@ int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len)
err = p54_convert_rev1(dev, curve_data);
break;
default:
- printk(KERN_ERR "%s: unknown curve data "
- "revision %d\n",
- wiphy_name(dev->wiphy),
- curve_data->cal_method_rev);
+ wiphy_err(dev->wiphy,
+ "unknown curve data revision %d\n",
+ curve_data->cal_method_rev);
err = -ENODEV;
break;
}
@@ -599,13 +594,13 @@ int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len)
}
break;
case PDR_PRISM_ZIF_TX_IQ_CALIBRATION:
- priv->iq_autocal = kmalloc(data_len, GFP_KERNEL);
+ priv->iq_autocal = kmemdup(entry->data, data_len,
+ GFP_KERNEL);
if (!priv->iq_autocal) {
err = -ENOMEM;
goto err;
}
- memcpy(priv->iq_autocal, entry->data, data_len);
priv->iq_autocal_len = data_len / sizeof(struct pda_iq_autocal_entry);
break;
case PDR_DEFAULT_COUNTRY:
@@ -672,8 +667,8 @@ int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len)
if (!synth || !priv->iq_autocal || !priv->output_limit ||
!priv->curve_data) {
- printk(KERN_ERR "%s: not all required entries found in eeprom!\n",
- wiphy_name(dev->wiphy));
+ wiphy_err(dev->wiphy,
+ "not all required entries found in eeprom!\n");
err = -EINVAL;
goto err;
}
@@ -699,15 +694,15 @@ int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len)
if (!is_valid_ether_addr(dev->wiphy->perm_addr)) {
u8 perm_addr[ETH_ALEN];
- printk(KERN_WARNING "%s: Invalid hwaddr! Using randomly generated MAC addr\n",
- wiphy_name(dev->wiphy));
+ wiphy_warn(dev->wiphy,
+ "invalid hwaddr! using randomly generated mac addr\n");
random_ether_addr(perm_addr);
SET_IEEE80211_PERM_ADDR(dev, perm_addr);
}
- printk(KERN_INFO "%s: hwaddr %pM, MAC:isl38%02x RF:%s\n",
- wiphy_name(dev->wiphy), dev->wiphy->perm_addr, priv->version,
- p54_rf_chips[priv->rxhw]);
+ wiphy_info(dev->wiphy, "hwaddr %pm, mac:isl38%02x rf:%s\n",
+ dev->wiphy->perm_addr, priv->version,
+ p54_rf_chips[priv->rxhw]);
return 0;
@@ -719,8 +714,7 @@ err:
priv->output_limit = NULL;
priv->curve_data = NULL;
- printk(KERN_ERR "%s: eeprom parse failed!\n",
- wiphy_name(dev->wiphy));
+ wiphy_err(dev->wiphy, "eeprom parse failed!\n");
return err;
}
EXPORT_SYMBOL_GPL(p54_parse_eeprom);
diff --git a/drivers/net/wireless/p54/fwio.c b/drivers/net/wireless/p54/fwio.c
index c43a5d461ab..47006bca485 100644
--- a/drivers/net/wireless/p54/fwio.c
+++ b/drivers/net/wireless/p54/fwio.c
@@ -62,16 +62,15 @@ int p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw)
case FW_LM20:
case FW_LM87: {
char *iftype = (char *)bootrec->data;
- printk(KERN_INFO "%s: p54 detected a LM%c%c "
- "firmware\n",
- wiphy_name(priv->hw->wiphy),
- iftype[2], iftype[3]);
+ wiphy_info(priv->hw->wiphy,
+ "p54 detected a LM%c%c firmware\n",
+ iftype[2], iftype[3]);
break;
}
case FW_FMAC:
default:
- printk(KERN_ERR "%s: unsupported firmware\n",
- wiphy_name(priv->hw->wiphy));
+ wiphy_err(priv->hw->wiphy,
+ "unsupported firmware\n");
return -ENODEV;
}
break;
@@ -125,15 +124,15 @@ int p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw)
}
if (fw_version)
- printk(KERN_INFO "%s: FW rev %s - Softmac protocol %x.%x\n",
- wiphy_name(priv->hw->wiphy), fw_version,
- priv->fw_var >> 8, priv->fw_var & 0xff);
+ wiphy_info(priv->hw->wiphy,
+ "fw rev %s - softmac protocol %x.%x\n",
+ fw_version, priv->fw_var >> 8, priv->fw_var & 0xff);
if (priv->fw_var < 0x500)
- printk(KERN_INFO "%s: you are using an obsolete firmware. "
- "visit http://wireless.kernel.org/en/users/Drivers/p54 "
- "and grab one for \"kernel >= 2.6.28\"!\n",
- wiphy_name(priv->hw->wiphy));
+ wiphy_info(priv->hw->wiphy,
+ "you are using an obsolete firmware. "
+ "visit http://wireless.kernel.org/en/users/Drivers/p54 "
+ "and grab one for \"kernel >= 2.6.28\"!\n");
if (priv->fw_var >= 0x300) {
/* Firmware supports QoS, use it! */
@@ -152,13 +151,14 @@ int p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw)
priv->hw->queues = P54_QUEUE_AC_NUM;
}
- printk(KERN_INFO "%s: cryptographic accelerator "
- "WEP:%s, TKIP:%s, CCMP:%s\n", wiphy_name(priv->hw->wiphy),
- (priv->privacy_caps & BR_DESC_PRIV_CAP_WEP) ? "YES" :
- "no", (priv->privacy_caps & (BR_DESC_PRIV_CAP_TKIP |
- BR_DESC_PRIV_CAP_MICHAEL)) ? "YES" : "no",
- (priv->privacy_caps & BR_DESC_PRIV_CAP_AESCCMP) ?
- "YES" : "no");
+ wiphy_info(priv->hw->wiphy,
+ "cryptographic accelerator WEP:%s, TKIP:%s, CCMP:%s\n",
+ (priv->privacy_caps & BR_DESC_PRIV_CAP_WEP) ? "YES" : "no",
+ (priv->privacy_caps &
+ (BR_DESC_PRIV_CAP_TKIP | BR_DESC_PRIV_CAP_MICHAEL))
+ ? "YES" : "no",
+ (priv->privacy_caps & BR_DESC_PRIV_CAP_AESCCMP)
+ ? "YES" : "no");
if (priv->rx_keycache_size) {
/*
@@ -247,8 +247,7 @@ int p54_download_eeprom(struct p54_common *priv, void *buf,
if (!wait_for_completion_interruptible_timeout(
&priv->eeprom_comp, HZ)) {
- printk(KERN_ERR "%s: device does not respond!\n",
- wiphy_name(priv->hw->wiphy));
+ wiphy_err(priv->hw->wiphy, "device does not respond!\n");
ret = -EBUSY;
}
priv->eeprom = NULL;
@@ -523,9 +522,9 @@ int p54_scan(struct p54_common *priv, u16 mode, u16 dwell)
return 0;
err:
- printk(KERN_ERR "%s: frequency change to channel %d failed.\n",
- wiphy_name(priv->hw->wiphy), ieee80211_frequency_to_channel(
- priv->hw->conf.channel->center_freq));
+ wiphy_err(priv->hw->wiphy, "frequency change to channel %d failed.\n",
+ ieee80211_frequency_to_channel(
+ priv->hw->conf.channel->center_freq));
dev_kfree_skb_any(skb);
return -EINVAL;
@@ -676,8 +675,8 @@ int p54_upload_key(struct p54_common *priv, u8 algo, int slot, u8 idx, u8 len,
break;
default:
- printk(KERN_ERR "%s: invalid cryptographic algorithm: %d\n",
- wiphy_name(priv->hw->wiphy), algo);
+ wiphy_err(priv->hw->wiphy,
+ "invalid cryptographic algorithm: %d\n", algo);
dev_kfree_skb(skb);
return -EINVAL;
}
diff --git a/drivers/net/wireless/p54/led.c b/drivers/net/wireless/p54/led.c
index 9575ac03363..ea91f5cce6b 100644
--- a/drivers/net/wireless/p54/led.c
+++ b/drivers/net/wireless/p54/led.c
@@ -57,8 +57,8 @@ static void p54_update_leds(struct work_struct *work)
err = p54_set_leds(priv);
if (err && net_ratelimit())
- printk(KERN_ERR "%s: failed to update LEDs (%d).\n",
- wiphy_name(priv->hw->wiphy), err);
+ wiphy_err(priv->hw->wiphy,
+ "failed to update leds (%d).\n", err);
if (rerun)
ieee80211_queue_delayed_work(priv->hw, &priv->led_work,
@@ -102,8 +102,8 @@ static int p54_register_led(struct p54_common *priv,
err = led_classdev_register(wiphy_dev(priv->hw->wiphy), &led->led_dev);
if (err)
- printk(KERN_ERR "%s: Failed to register %s LED.\n",
- wiphy_name(priv->hw->wiphy), name);
+ wiphy_err(priv->hw->wiphy,
+ "failed to register %s led.\n", name);
else
led->registered = 1;
diff --git a/drivers/net/wireless/p54/main.c b/drivers/net/wireless/p54/main.c
index c072f41747c..47db439b63b 100644
--- a/drivers/net/wireless/p54/main.c
+++ b/drivers/net/wireless/p54/main.c
@@ -507,6 +507,22 @@ out_unlock:
return ret;
}
+static int p54_get_survey(struct ieee80211_hw *dev, int idx,
+ struct survey_info *survey)
+{
+ struct p54_common *priv = dev->priv;
+ struct ieee80211_conf *conf = &dev->conf;
+
+ if (idx != 0)
+ return -ENOENT;
+
+ survey->channel = conf->channel;
+ survey->filled = SURVEY_INFO_NOISE_DBM;
+ survey->noise = clamp_t(s8, priv->noise, -128, 127);
+
+ return 0;
+}
+
static const struct ieee80211_ops p54_ops = {
.tx = p54_tx_80211,
.start = p54_start,
@@ -523,6 +539,7 @@ static const struct ieee80211_ops p54_ops = {
.configure_filter = p54_configure_filter,
.conf_tx = p54_conf_tx,
.get_stats = p54_get_stats,
+ .get_survey = p54_get_survey,
};
struct ieee80211_hw *p54_init_common(size_t priv_data_len)
diff --git a/drivers/net/wireless/p54/net2280.h b/drivers/net/wireless/p54/net2280.h
index 4915d9d5420..e3ed893b5aa 100644
--- a/drivers/net/wireless/p54/net2280.h
+++ b/drivers/net/wireless/p54/net2280.h
@@ -232,7 +232,7 @@ struct net2280_regs {
#define GPIO2_INTERRUPT 2
#define GPIO1_INTERRUPT 1
#define GPIO0_INTERRUPT 0
-} __attribute__ ((packed));
+} __packed;
/* usb control, BAR0 + 0x0080 */
struct net2280_usb_regs {
@@ -296,7 +296,7 @@ struct net2280_usb_regs {
#define FORCE_IMMEDIATE 7
#define OUR_USB_ADDRESS 0
__le32 ourconfig;
-} __attribute__ ((packed));
+} __packed;
/* pci control, BAR0 + 0x0100 */
struct net2280_pci_regs {
@@ -323,7 +323,7 @@ struct net2280_pci_regs {
#define PCI_ARBITER_CLEAR 2
#define PCI_EXTERNAL_ARBITER 1
#define PCI_HOST_MODE 0
-} __attribute__ ((packed));
+} __packed;
/* dma control, BAR0 + 0x0180 ... array of four structs like this,
* for channels 0..3. see also struct net2280_dma: descriptor
@@ -364,7 +364,7 @@ struct net2280_dma_regs { /* [11.7] */
__le32 dmaaddr;
__le32 dmadesc;
u32 _unused1;
-} __attribute__ ((packed));
+} __packed;
/* dedicated endpoint registers, BAR0 + 0x0200 */
@@ -374,7 +374,7 @@ struct net2280_dep_regs { /* [11.8] */
/* offset 0x0204, 0x0214, 0x224, 0x234, 0x244 */
__le32 dep_rsp;
u32 _unused[2];
-} __attribute__ ((packed));
+} __packed;
/* configurable endpoint registers, BAR0 + 0x0300 ... array of seven structs
* like this, for ep0 then the configurable endpoints A..F
@@ -437,16 +437,16 @@ struct net2280_ep_regs { /* [11.9] */
__le32 ep_avail;
__le32 ep_data;
u32 _unused0[2];
-} __attribute__ ((packed));
+} __packed;
struct net2280_reg_write {
__le16 port;
__le32 addr;
__le32 val;
-} __attribute__ ((packed));
+} __packed;
struct net2280_reg_read {
__le16 port;
__le32 addr;
-} __attribute__ ((packed));
+} __packed;
#endif /* NET2280_H */
diff --git a/drivers/net/wireless/p54/p54pci.c b/drivers/net/wireless/p54/p54pci.c
index a5ea89cde8c..822f8dc26e9 100644
--- a/drivers/net/wireless/p54/p54pci.c
+++ b/drivers/net/wireless/p54/p54pci.c
@@ -466,8 +466,7 @@ static int p54p_open(struct ieee80211_hw *dev)
P54P_READ(dev_int);
if (!wait_for_completion_interruptible_timeout(&priv->boot_comp, HZ)) {
- printk(KERN_ERR "%s: Cannot boot firmware!\n",
- wiphy_name(dev->wiphy));
+ wiphy_err(dev->wiphy, "cannot boot firmware!\n");
p54p_stop(dev);
return -ETIMEDOUT;
}
diff --git a/drivers/net/wireless/p54/p54pci.h b/drivers/net/wireless/p54/p54pci.h
index 2feead617a3..ee9bc62a4fa 100644
--- a/drivers/net/wireless/p54/p54pci.h
+++ b/drivers/net/wireless/p54/p54pci.h
@@ -65,7 +65,7 @@ struct p54p_csr {
u8 unused_6[1924];
u8 cardbus_cis[0x800];
u8 direct_mem_win[0x1000];
-} __attribute__ ((packed));
+} __packed;
/* usb backend only needs the register defines above */
#ifndef P54USB_H
@@ -74,7 +74,7 @@ struct p54p_desc {
__le32 device_addr;
__le16 len;
__le16 flags;
-} __attribute__ ((packed));
+} __packed;
struct p54p_ring_control {
__le32 host_idx[4];
@@ -83,7 +83,7 @@ struct p54p_ring_control {
struct p54p_desc tx_data[32];
struct p54p_desc rx_mgmt[4];
struct p54p_desc tx_mgmt[4];
-} __attribute__ ((packed));
+} __packed;
#define P54P_READ(r) (__force __le32)__raw_readl(&priv->map->r)
#define P54P_WRITE(r, val) __raw_writel((__force u32)(__le32)(val), &priv->map->r)
diff --git a/drivers/net/wireless/p54/p54spi.c b/drivers/net/wireless/p54/p54spi.c
index c8f09da1f84..087bf0698a5 100644
--- a/drivers/net/wireless/p54/p54spi.c
+++ b/drivers/net/wireless/p54/p54spi.c
@@ -697,9 +697,7 @@ static int __devexit p54spi_remove(struct spi_device *spi)
static struct spi_driver p54spi_driver = {
.driver = {
- /* use cx3110x name because board-n800.c uses that for the
- * SPI port */
- .name = "cx3110x",
+ .name = "p54spi",
.bus = &spi_bus_type,
.owner = THIS_MODULE,
},
@@ -733,3 +731,4 @@ module_exit(p54spi_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Christian Lamparter <chunkeey@web.de>");
MODULE_ALIAS("spi:cx3110x");
+MODULE_ALIAS("spi:p54spi");
diff --git a/drivers/net/wireless/p54/p54spi.h b/drivers/net/wireless/p54/p54spi.h
index 7fbe8d8fc67..dfaa62aaeb0 100644
--- a/drivers/net/wireless/p54/p54spi.h
+++ b/drivers/net/wireless/p54/p54spi.h
@@ -96,7 +96,7 @@ struct p54s_dma_regs {
__le16 cmd;
__le16 len;
__le32 addr;
-} __attribute__ ((packed));
+} __packed;
struct p54s_tx_info {
struct list_head tx_list;
diff --git a/drivers/net/wireless/p54/p54usb.c b/drivers/net/wireless/p54/p54usb.c
index 73073259f50..ad595958b7d 100644
--- a/drivers/net/wireless/p54/p54usb.c
+++ b/drivers/net/wireless/p54/p54usb.c
@@ -69,7 +69,8 @@ static struct usb_device_id p54u_table[] __devinitdata = {
{USB_DEVICE(0x0915, 0x2002)}, /* Cohiba Proto board */
{USB_DEVICE(0x0baf, 0x0118)}, /* U.S. Robotics U5 802.11g Adapter*/
{USB_DEVICE(0x0bf8, 0x1009)}, /* FUJITSU E-5400 USB D1700*/
- {USB_DEVICE(0x0cde, 0x0006)}, /* Medion MD40900 */
+ /* {USB_DEVICE(0x0cde, 0x0006)}, * Medion MD40900 already listed above,
+ * just noting it here for clarity */
{USB_DEVICE(0x0cde, 0x0008)}, /* Sagem XG703A */
{USB_DEVICE(0x0cde, 0x0015)}, /* Zcomax XG-705A */
{USB_DEVICE(0x0d8e, 0x3762)}, /* DLink DWL-G120 Cohiba */
@@ -434,10 +435,9 @@ static int p54u_firmware_reset_3887(struct ieee80211_hw *dev)
u8 *buf;
int ret;
- buf = kmalloc(4, GFP_KERNEL);
+ buf = kmemdup(p54u_romboot_3887, 4, GFP_KERNEL);
if (!buf)
return -ENOMEM;
- memcpy(buf, p54u_romboot_3887, 4);
ret = p54u_bulk_msg(priv, P54U_PIPE_DATA,
buf, 4);
kfree(buf);
diff --git a/drivers/net/wireless/p54/p54usb.h b/drivers/net/wireless/p54/p54usb.h
index e935b79f7f7..ed4034ade59 100644
--- a/drivers/net/wireless/p54/p54usb.h
+++ b/drivers/net/wireless/p54/p54usb.h
@@ -70,12 +70,12 @@ struct net2280_tx_hdr {
__le16 len;
__le16 follower; /* ? */
u8 padding[8];
-} __attribute__((packed));
+} __packed;
struct lm87_tx_hdr {
__le32 device_addr;
__le32 chksum;
-} __attribute__((packed));
+} __packed;
/* Some flags for the isl hardware registers controlling DMA inside the
* chip */
@@ -103,7 +103,7 @@ struct x2_header {
__le32 fw_load_addr;
__le32 fw_length;
__le32 crc;
-} __attribute__((packed));
+} __packed;
/* pipes 3 and 4 are not used by the driver */
#define P54U_PIPE_NUMBER 9
diff --git a/drivers/net/wireless/p54/txrx.c b/drivers/net/wireless/p54/txrx.c
index 4e6891099d4..427b46f558e 100644
--- a/drivers/net/wireless/p54/txrx.c
+++ b/drivers/net/wireless/p54/txrx.c
@@ -38,8 +38,8 @@ static void p54_dump_tx_queue(struct p54_common *priv)
u32 largest_hole = 0, free;
spin_lock_irqsave(&priv->tx_queue.lock, flags);
- printk(KERN_DEBUG "%s: / --- tx queue dump (%d entries) ---\n",
- wiphy_name(priv->hw->wiphy), skb_queue_len(&priv->tx_queue));
+ wiphy_debug(priv->hw->wiphy, "/ --- tx queue dump (%d entries) ---\n",
+ skb_queue_len(&priv->tx_queue));
prev_addr = priv->rx_start;
skb_queue_walk(&priv->tx_queue, skb) {
@@ -48,21 +48,23 @@ static void p54_dump_tx_queue(struct p54_common *priv)
hdr = (void *) skb->data;
free = range->start_addr - prev_addr;
- printk(KERN_DEBUG "%s: | [%02d] => [skb:%p skb_len:0x%04x "
- "hdr:{flags:%02x len:%04x req_id:%04x type:%02x} "
- "mem:{start:%04x end:%04x, free:%d}]\n",
- wiphy_name(priv->hw->wiphy), i++, skb, skb->len,
- le16_to_cpu(hdr->flags), le16_to_cpu(hdr->len),
- le32_to_cpu(hdr->req_id), le16_to_cpu(hdr->type),
- range->start_addr, range->end_addr, free);
+ wiphy_debug(priv->hw->wiphy,
+ "| [%02d] => [skb:%p skb_len:0x%04x "
+ "hdr:{flags:%02x len:%04x req_id:%04x type:%02x} "
+ "mem:{start:%04x end:%04x, free:%d}]\n",
+ i++, skb, skb->len,
+ le16_to_cpu(hdr->flags), le16_to_cpu(hdr->len),
+ le32_to_cpu(hdr->req_id), le16_to_cpu(hdr->type),
+ range->start_addr, range->end_addr, free);
prev_addr = range->end_addr;
largest_hole = max(largest_hole, free);
}
free = priv->rx_end - prev_addr;
largest_hole = max(largest_hole, free);
- printk(KERN_DEBUG "%s: \\ --- [free: %d], largest free block: %d ---\n",
- wiphy_name(priv->hw->wiphy), free, largest_hole);
+ wiphy_debug(priv->hw->wiphy,
+ "\\ --- [free: %d], largest free block: %d ---\n",
+ free, largest_hole);
spin_unlock_irqrestore(&priv->tx_queue.lock, flags);
}
#endif /* P54_MM_DEBUG */
@@ -538,8 +540,7 @@ static void p54_rx_trap(struct p54_common *priv, struct sk_buff *skb)
case P54_TRAP_BEACON_TX:
break;
case P54_TRAP_RADAR:
- printk(KERN_INFO "%s: radar (freq:%d MHz)\n",
- wiphy_name(priv->hw->wiphy), freq);
+ wiphy_info(priv->hw->wiphy, "radar (freq:%d mhz)\n", freq);
break;
case P54_TRAP_NO_BEACON:
if (priv->vif)
@@ -558,8 +559,8 @@ static void p54_rx_trap(struct p54_common *priv, struct sk_buff *skb)
wiphy_rfkill_set_hw_state(priv->hw->wiphy, false);
break;
default:
- printk(KERN_INFO "%s: received event:%x freq:%d\n",
- wiphy_name(priv->hw->wiphy), event, freq);
+ wiphy_info(priv->hw->wiphy, "received event:%x freq:%d\n",
+ event, freq);
break;
}
}
@@ -584,8 +585,9 @@ static int p54_rx_control(struct p54_common *priv, struct sk_buff *skb)
p54_rx_eeprom_readback(priv, skb);
break;
default:
- printk(KERN_DEBUG "%s: not handling 0x%02x type control frame\n",
- wiphy_name(priv->hw->wiphy), le16_to_cpu(hdr->type));
+ wiphy_debug(priv->hw->wiphy,
+ "not handling 0x%02x type control frame\n",
+ le16_to_cpu(hdr->type));
break;
}
return 0;
diff --git a/drivers/net/wireless/prism54/isl_ioctl.c b/drivers/net/wireless/prism54/isl_ioctl.c
index 8d1190c0f06..77cd65db850 100644
--- a/drivers/net/wireless/prism54/isl_ioctl.c
+++ b/drivers/net/wireless/prism54/isl_ioctl.c
@@ -2067,7 +2067,7 @@ send_simple_event(islpci_private *priv, const char *str)
memptr = kmalloc(IW_CUSTOM_MAX, GFP_KERNEL);
if (!memptr)
return;
- BUG_ON(n > IW_CUSTOM_MAX);
+ BUG_ON(n >= IW_CUSTOM_MAX);
wrqu.data.pointer = memptr;
wrqu.data.length = n;
strcpy(memptr, str);
@@ -2101,7 +2101,7 @@ struct ieee80211_beacon_phdr {
u8 timestamp[8];
u16 beacon_int;
u16 capab_info;
-} __attribute__ ((packed));
+} __packed;
#define WLAN_EID_GENERIC 0xdd
static u8 wpa_oid[4] = { 0x00, 0x50, 0xf2, 1 };
@@ -2751,14 +2751,9 @@ prism54_hostapd(struct net_device *ndev, struct iw_point *p)
p->length > PRISM2_HOSTAPD_MAX_BUF_SIZE || !p->pointer)
return -EINVAL;
- param = kmalloc(p->length, GFP_KERNEL);
- if (param == NULL)
- return -ENOMEM;
-
- if (copy_from_user(param, p->pointer, p->length)) {
- kfree(param);
- return -EFAULT;
- }
+ param = memdup_user(p->pointer, p->length);
+ if (IS_ERR(param))
+ return PTR_ERR(param);
switch (param->cmd) {
case PRISM2_SET_ENCRYPTION:
diff --git a/drivers/net/wireless/prism54/isl_oid.h b/drivers/net/wireless/prism54/isl_oid.h
index b7534c2869c..59e31258d45 100644
--- a/drivers/net/wireless/prism54/isl_oid.h
+++ b/drivers/net/wireless/prism54/isl_oid.h
@@ -29,20 +29,20 @@
struct obj_ssid {
u8 length;
char octets[33];
-} __attribute__ ((packed));
+} __packed;
struct obj_key {
u8 type; /* dot11_priv_t */
u8 length;
char key[32];
-} __attribute__ ((packed));
+} __packed;
struct obj_mlme {
u8 address[6];
u16 id;
u16 state;
u16 code;
-} __attribute__ ((packed));
+} __packed;
struct obj_mlmeex {
u8 address[6];
@@ -51,12 +51,12 @@ struct obj_mlmeex {
u16 code;
u16 size;
u8 data[0];
-} __attribute__ ((packed));
+} __packed;
struct obj_buffer {
u32 size;
u32 addr; /* 32bit bus address */
-} __attribute__ ((packed));
+} __packed;
struct obj_bss {
u8 address[6];
@@ -77,17 +77,17 @@ struct obj_bss {
short rates;
short basic_rates;
int:16; /* padding */
-} __attribute__ ((packed));
+} __packed;
struct obj_bsslist {
u32 nr;
struct obj_bss bsslist[0];
-} __attribute__ ((packed));
+} __packed;
struct obj_frequencies {
u16 nr;
u16 mhz[0];
-} __attribute__ ((packed));
+} __packed;
struct obj_attachment {
char type;
@@ -95,7 +95,7 @@ struct obj_attachment {
short id;
short size;
char data[0];
-} __attribute__((packed));
+} __packed;
/*
* in case everything's ok, the inlined function below will be
diff --git a/drivers/net/wireless/prism54/islpci_eth.h b/drivers/net/wireless/prism54/islpci_eth.h
index 54f9a4b7bf9..6ca30a5b7bf 100644
--- a/drivers/net/wireless/prism54/islpci_eth.h
+++ b/drivers/net/wireless/prism54/islpci_eth.h
@@ -34,13 +34,13 @@ struct rfmon_header {
__le16 unk3;
u8 rssi;
u8 padding[3];
-} __attribute__ ((packed));
+} __packed;
struct rx_annex_header {
u8 addr1[ETH_ALEN];
u8 addr2[ETH_ALEN];
struct rfmon_header rfmon;
-} __attribute__ ((packed));
+} __packed;
/* wlan-ng (and hopefully others) AVS header, version one. Fields in
* network byte order. */
diff --git a/drivers/net/wireless/prism54/islpci_mgt.h b/drivers/net/wireless/prism54/islpci_mgt.h
index 0b27e50fe0d..0db93db9b67 100644
--- a/drivers/net/wireless/prism54/islpci_mgt.h
+++ b/drivers/net/wireless/prism54/islpci_mgt.h
@@ -101,7 +101,7 @@ typedef struct {
u8 device_id;
u8 flags;
u32 length;
-} __attribute__ ((packed))
+} __packed
pimfor_header_t;
/* A received and interrupt-processed management frame, either for
diff --git a/drivers/net/wireless/ray_cs.c b/drivers/net/wireless/ray_cs.c
index abff8934db1..88560d0ae50 100644
--- a/drivers/net/wireless/ray_cs.c
+++ b/drivers/net/wireless/ray_cs.c
@@ -46,7 +46,6 @@
#include <linux/ethtool.h>
#include <linux/ieee80211.h>
-#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/cistpl.h>
#include <pcmcia/cisreg.h>
@@ -97,7 +96,6 @@ static iw_stats *ray_get_wireless_stats(struct net_device *dev);
static const struct iw_handler_def ray_handler_def;
/***** Prototypes for raylink functions **************************************/
-static int asc_to_int(char a);
static void authenticate(ray_dev_t *local);
static int build_auth_frame(ray_dev_t *local, UCHAR *dest, int auth_type);
static void authenticate_timeout(u_long);
@@ -316,9 +314,8 @@ static int ray_probe(struct pcmcia_device *p_dev)
local->finder = p_dev;
/* The io structure describes IO port mapping. None used here */
- p_dev->io.NumPorts1 = 0;
- p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
- p_dev->io.IOAddrLines = 5;
+ p_dev->resource[0]->end = 0;
+ p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_8;
/* General socket configuration */
p_dev->conf.Attributes = CONF_ENABLE_IRQ;
@@ -395,7 +392,6 @@ static int ray_config(struct pcmcia_device *link)
int ret = 0;
int i;
win_req_t req;
- memreq_t mem;
struct net_device *dev = (struct net_device *)link->priv;
ray_dev_t *local = netdev_priv(dev);
@@ -432,9 +428,7 @@ static int ray_config(struct pcmcia_device *link)
ret = pcmcia_request_window(link, &req, &link->win);
if (ret)
goto failed;
- mem.CardOffset = 0x0000;
- mem.Page = 0;
- ret = pcmcia_map_mem_page(link, link->win, &mem);
+ ret = pcmcia_map_mem_page(link, link->win, 0);
if (ret)
goto failed;
local->sram = ioremap(req.Base, req.Size);
@@ -448,9 +442,7 @@ static int ray_config(struct pcmcia_device *link)
ret = pcmcia_request_window(link, &req, &local->rmem_handle);
if (ret)
goto failed;
- mem.CardOffset = 0x8000;
- mem.Page = 0;
- ret = pcmcia_map_mem_page(link, local->rmem_handle, &mem);
+ ret = pcmcia_map_mem_page(link, local->rmem_handle, 0x8000);
if (ret)
goto failed;
local->rmem = ioremap(req.Base, req.Size);
@@ -464,9 +456,7 @@ static int ray_config(struct pcmcia_device *link)
ret = pcmcia_request_window(link, &req, &local->amem_handle);
if (ret)
goto failed;
- mem.CardOffset = 0x0000;
- mem.Page = 0;
- ret = pcmcia_map_mem_page(link, local->amem_handle, &mem);
+ ret = pcmcia_map_mem_page(link, local->amem_handle, 0);
if (ret)
goto failed;
local->amem = ioremap(req.Base, req.Size);
@@ -794,7 +784,6 @@ static void ray_release(struct pcmcia_device *link)
{
struct net_device *dev = link->priv;
ray_dev_t *local = netdev_priv(dev);
- int i;
dev_dbg(&link->dev, "ray_release\n");
@@ -803,13 +792,6 @@ static void ray_release(struct pcmcia_device *link)
iounmap(local->sram);
iounmap(local->rmem);
iounmap(local->amem);
- /* Do bother checking to see if these succeed or not */
- i = pcmcia_release_window(link, local->amem_handle);
- if (i != 0)
- dev_dbg(&link->dev, "ReleaseWindow(local->amem) ret = %x\n", i);
- i = pcmcia_release_window(link, local->rmem_handle);
- if (i != 0)
- dev_dbg(&link->dev, "ReleaseWindow(local->rmem) ret = %x\n", i);
pcmcia_disable_device(link);
dev_dbg(&link->dev, "ray_release ending\n");
@@ -1717,24 +1699,6 @@ static void authenticate_timeout(u_long data)
}
/*===========================================================================*/
-static int asc_to_int(char a)
-{
- if (a < '0')
- return -1;
- if (a <= '9')
- return (a - '0');
- if (a < 'A')
- return -1;
- if (a <= 'F')
- return (10 + a - 'A');
- if (a < 'a')
- return -1;
- if (a <= 'f')
- return (10 + a - 'a');
- return -1;
-}
-
-/*===========================================================================*/
static int parse_addr(char *in_str, UCHAR *out)
{
int len;
@@ -1754,14 +1718,14 @@ static int parse_addr(char *in_str, UCHAR *out)
i = 5;
while (j > 0) {
- if ((k = asc_to_int(in_str[j--])) != -1)
+ if ((k = hex_to_bin(in_str[j--])) != -1)
out[i] = k;
else
return 0;
if (j == 0)
break;
- if ((k = asc_to_int(in_str[j--])) != -1)
+ if ((k = hex_to_bin(in_str[j--])) != -1)
out[i] += k << 4;
else
return 0;
diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c
index 4bd61ee627c..719573bbbf8 100644
--- a/drivers/net/wireless/rndis_wlan.c
+++ b/drivers/net/wireless/rndis_wlan.c
@@ -238,19 +238,19 @@ struct ndis_80211_auth_request {
u8 bssid[6];
u8 padding[2];
__le32 flags;
-} __attribute__((packed));
+} __packed;
struct ndis_80211_pmkid_candidate {
u8 bssid[6];
u8 padding[2];
__le32 flags;
-} __attribute__((packed));
+} __packed;
struct ndis_80211_pmkid_cand_list {
__le32 version;
__le32 num_candidates;
struct ndis_80211_pmkid_candidate candidate_list[0];
-} __attribute__((packed));
+} __packed;
struct ndis_80211_status_indication {
__le32 status_type;
@@ -260,19 +260,19 @@ struct ndis_80211_status_indication {
struct ndis_80211_auth_request auth_request[0];
struct ndis_80211_pmkid_cand_list cand_list;
} u;
-} __attribute__((packed));
+} __packed;
struct ndis_80211_ssid {
__le32 length;
u8 essid[NDIS_802_11_LENGTH_SSID];
-} __attribute__((packed));
+} __packed;
struct ndis_80211_conf_freq_hop {
__le32 length;
__le32 hop_pattern;
__le32 hop_set;
__le32 dwell_time;
-} __attribute__((packed));
+} __packed;
struct ndis_80211_conf {
__le32 length;
@@ -280,7 +280,7 @@ struct ndis_80211_conf {
__le32 atim_window;
__le32 ds_config;
struct ndis_80211_conf_freq_hop fh_config;
-} __attribute__((packed));
+} __packed;
struct ndis_80211_bssid_ex {
__le32 length;
@@ -295,25 +295,25 @@ struct ndis_80211_bssid_ex {
u8 rates[NDIS_802_11_LENGTH_RATES_EX];
__le32 ie_length;
u8 ies[0];
-} __attribute__((packed));
+} __packed;
struct ndis_80211_bssid_list_ex {
__le32 num_items;
struct ndis_80211_bssid_ex bssid[0];
-} __attribute__((packed));
+} __packed;
struct ndis_80211_fixed_ies {
u8 timestamp[8];
__le16 beacon_interval;
__le16 capabilities;
-} __attribute__((packed));
+} __packed;
struct ndis_80211_wep_key {
__le32 size;
__le32 index;
__le32 length;
u8 material[32];
-} __attribute__((packed));
+} __packed;
struct ndis_80211_key {
__le32 size;
@@ -323,14 +323,14 @@ struct ndis_80211_key {
u8 padding[6];
u8 rsc[8];
u8 material[32];
-} __attribute__((packed));
+} __packed;
struct ndis_80211_remove_key {
__le32 size;
__le32 index;
u8 bssid[6];
u8 padding[2];
-} __attribute__((packed));
+} __packed;
struct ndis_config_param {
__le32 name_offs;
@@ -338,7 +338,7 @@ struct ndis_config_param {
__le32 type;
__le32 value_offs;
__le32 value_length;
-} __attribute__((packed));
+} __packed;
struct ndis_80211_assoc_info {
__le32 length;
@@ -358,12 +358,12 @@ struct ndis_80211_assoc_info {
} resp_ie;
__le32 resp_ie_length;
__le32 offset_resp_ies;
-} __attribute__((packed));
+} __packed;
struct ndis_80211_auth_encr_pair {
__le32 auth_mode;
__le32 encr_mode;
-} __attribute__((packed));
+} __packed;
struct ndis_80211_capability {
__le32 length;
@@ -371,7 +371,7 @@ struct ndis_80211_capability {
__le32 num_pmkids;
__le32 num_auth_encr_pair;
struct ndis_80211_auth_encr_pair auth_encr_pair[0];
-} __attribute__((packed));
+} __packed;
struct ndis_80211_bssid_info {
u8 bssid[6];
@@ -520,8 +520,9 @@ static int rndis_scan(struct wiphy *wiphy, struct net_device *dev,
static int rndis_set_wiphy_params(struct wiphy *wiphy, u32 changed);
-static int rndis_set_tx_power(struct wiphy *wiphy, enum tx_power_setting type,
- int dbm);
+static int rndis_set_tx_power(struct wiphy *wiphy,
+ enum nl80211_tx_power_setting type,
+ int mbm);
static int rndis_get_tx_power(struct wiphy *wiphy, int *dbm);
static int rndis_connect(struct wiphy *wiphy, struct net_device *dev,
@@ -1856,20 +1857,25 @@ static int rndis_set_wiphy_params(struct wiphy *wiphy, u32 changed)
return 0;
}
-static int rndis_set_tx_power(struct wiphy *wiphy, enum tx_power_setting type,
- int dbm)
+static int rndis_set_tx_power(struct wiphy *wiphy,
+ enum nl80211_tx_power_setting type,
+ int mbm)
{
struct rndis_wlan_private *priv = wiphy_priv(wiphy);
struct usbnet *usbdev = priv->usbdev;
- netdev_dbg(usbdev->net, "%s(): type:0x%x dbm:%i\n",
- __func__, type, dbm);
+ netdev_dbg(usbdev->net, "%s(): type:0x%x mbm:%i\n",
+ __func__, type, mbm);
+
+ if (mbm < 0 || (mbm % 100))
+ return -ENOTSUPP;
/* Device doesn't support changing txpower after initialization, only
* turn off/on radio. Support 'auto' mode and setting same dBm that is
* currently used.
*/
- if (type == TX_POWER_AUTOMATIC || dbm == get_bcm4320_power_dbm(priv)) {
+ if (type == NL80211_TX_POWER_AUTOMATIC ||
+ MBM_TO_DBM(mbm) == get_bcm4320_power_dbm(priv)) {
if (!priv->radio_on)
disassociate(usbdev, true); /* turn on radio */
@@ -2495,8 +2501,7 @@ static int rndis_flush_pmksa(struct wiphy *wiphy, struct net_device *netdev)
static void rndis_wlan_do_link_up_work(struct usbnet *usbdev)
{
struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
- struct ndis_80211_assoc_info *info;
- u8 assoc_buf[sizeof(*info) + IW_CUSTOM_MAX + 32];
+ struct ndis_80211_assoc_info *info = NULL;
u8 bssid[ETH_ALEN];
int resp_ie_len, req_ie_len;
u8 *req_ie, *resp_ie;
@@ -2515,23 +2520,43 @@ static void rndis_wlan_do_link_up_work(struct usbnet *usbdev)
resp_ie = NULL;
if (priv->infra_mode == NDIS_80211_INFRA_INFRA) {
- memset(assoc_buf, 0, sizeof(assoc_buf));
- info = (void *)assoc_buf;
+ info = kzalloc(CONTROL_BUFFER_SIZE, GFP_KERNEL);
+ if (!info) {
+ /* No memory? Try resume work later */
+ set_bit(WORK_LINK_UP, &priv->work_pending);
+ queue_work(priv->workqueue, &priv->work);
+ return;
+ }
- /* Get association info IEs from device and send them back to
- * userspace. */
- ret = get_association_info(usbdev, info, sizeof(assoc_buf));
+ /* Get association info IEs from device. */
+ ret = get_association_info(usbdev, info, CONTROL_BUFFER_SIZE);
if (!ret) {
req_ie_len = le32_to_cpu(info->req_ie_length);
if (req_ie_len > 0) {
offset = le32_to_cpu(info->offset_req_ies);
+
+ if (offset > CONTROL_BUFFER_SIZE)
+ offset = CONTROL_BUFFER_SIZE;
+
req_ie = (u8 *)info + offset;
+
+ if (offset + req_ie_len > CONTROL_BUFFER_SIZE)
+ req_ie_len =
+ CONTROL_BUFFER_SIZE - offset;
}
resp_ie_len = le32_to_cpu(info->resp_ie_length);
if (resp_ie_len > 0) {
offset = le32_to_cpu(info->offset_resp_ies);
+
+ if (offset > CONTROL_BUFFER_SIZE)
+ offset = CONTROL_BUFFER_SIZE;
+
resp_ie = (u8 *)info + offset;
+
+ if (offset + resp_ie_len > CONTROL_BUFFER_SIZE)
+ resp_ie_len =
+ CONTROL_BUFFER_SIZE - offset;
}
}
} else if (WARN_ON(priv->infra_mode != NDIS_80211_INFRA_ADHOC))
@@ -2563,6 +2588,9 @@ static void rndis_wlan_do_link_up_work(struct usbnet *usbdev)
} else if (priv->infra_mode == NDIS_80211_INFRA_ADHOC)
cfg80211_ibss_joined(usbdev->net, bssid, GFP_KERNEL);
+ if (info != NULL)
+ kfree(info);
+
priv->connected = true;
memcpy(priv->bssid, bssid, ETH_ALEN);
diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c
index ad2c98af7e9..5063e01410e 100644
--- a/drivers/net/wireless/rt2x00/rt2400pci.c
+++ b/drivers/net/wireless/rt2x00/rt2400pci.c
@@ -586,9 +586,11 @@ static void rt2400pci_link_stats(struct rt2x00_dev *rt2x00dev,
static inline void rt2400pci_set_vgc(struct rt2x00_dev *rt2x00dev,
struct link_qual *qual, u8 vgc_level)
{
- rt2400pci_bbp_write(rt2x00dev, 13, vgc_level);
- qual->vgc_level = vgc_level;
- qual->vgc_level_reg = vgc_level;
+ if (qual->vgc_level_reg != vgc_level) {
+ rt2400pci_bbp_write(rt2x00dev, 13, vgc_level);
+ qual->vgc_level = vgc_level;
+ qual->vgc_level_reg = vgc_level;
+ }
}
static void rt2400pci_reset_tuner(struct rt2x00_dev *rt2x00dev,
@@ -877,7 +879,8 @@ static void rt2400pci_toggle_rx(struct rt2x00_dev *rt2x00dev,
static void rt2400pci_toggle_irq(struct rt2x00_dev *rt2x00dev,
enum dev_state state)
{
- int mask = (state == STATE_RADIO_IRQ_OFF);
+ int mask = (state == STATE_RADIO_IRQ_OFF) ||
+ (state == STATE_RADIO_IRQ_OFF_ISR);
u32 reg;
/*
@@ -978,7 +981,9 @@ static int rt2400pci_set_device_state(struct rt2x00_dev *rt2x00dev,
rt2400pci_toggle_rx(rt2x00dev, state);
break;
case STATE_RADIO_IRQ_ON:
+ case STATE_RADIO_IRQ_ON_ISR:
case STATE_RADIO_IRQ_OFF:
+ case STATE_RADIO_IRQ_OFF_ISR:
rt2400pci_toggle_irq(rt2x00dev, state);
break;
case STATE_DEEP_SLEEP:
@@ -1076,9 +1081,6 @@ static void rt2400pci_write_beacon(struct queue_entry *entry,
struct txentry_desc *txdesc)
{
struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
- struct queue_entry_priv_pci *entry_priv = entry->priv_data;
- struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
- u32 word;
u32 reg;
/*
@@ -1091,9 +1093,15 @@ static void rt2400pci_write_beacon(struct queue_entry *entry,
rt2x00queue_map_txskb(rt2x00dev, entry->skb);
- rt2x00_desc_read(entry_priv->desc, 1, &word);
- rt2x00_set_field32(&word, TXD_W1_BUFFER_ADDRESS, skbdesc->skb_dma);
- rt2x00_desc_write(entry_priv->desc, 1, word);
+ /*
+ * Write the TX descriptor for the beacon.
+ */
+ rt2400pci_write_tx_desc(rt2x00dev, entry->skb, txdesc);
+
+ /*
+ * Dump beacon to userspace through debugfs.
+ */
+ rt2x00debug_dump_frame(rt2x00dev, DUMP_FRAME_BEACON, entry->skb);
/*
* Enable beaconing again.
@@ -1230,23 +1238,10 @@ static void rt2400pci_txdone(struct rt2x00_dev *rt2x00dev,
}
}
-static irqreturn_t rt2400pci_interrupt(int irq, void *dev_instance)
+static irqreturn_t rt2400pci_interrupt_thread(int irq, void *dev_instance)
{
struct rt2x00_dev *rt2x00dev = dev_instance;
- u32 reg;
-
- /*
- * Get the interrupt sources & saved to local variable.
- * Write register value back to clear pending interrupts.
- */
- rt2x00pci_register_read(rt2x00dev, CSR7, &reg);
- rt2x00pci_register_write(rt2x00dev, CSR7, reg);
-
- if (!reg)
- return IRQ_NONE;
-
- if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
- return IRQ_HANDLED;
+ u32 reg = rt2x00dev->irqvalue[0];
/*
* Handle interrupts, walk through all bits
@@ -1284,9 +1279,40 @@ static irqreturn_t rt2400pci_interrupt(int irq, void *dev_instance)
if (rt2x00_get_field32(reg, CSR7_TXDONE_TXRING))
rt2400pci_txdone(rt2x00dev, QID_AC_BK);
+ /* Enable interrupts again. */
+ rt2x00dev->ops->lib->set_device_state(rt2x00dev,
+ STATE_RADIO_IRQ_ON_ISR);
return IRQ_HANDLED;
}
+static irqreturn_t rt2400pci_interrupt(int irq, void *dev_instance)
+{
+ struct rt2x00_dev *rt2x00dev = dev_instance;
+ u32 reg;
+
+ /*
+ * Get the interrupt sources & saved to local variable.
+ * Write register value back to clear pending interrupts.
+ */
+ rt2x00pci_register_read(rt2x00dev, CSR7, &reg);
+ rt2x00pci_register_write(rt2x00dev, CSR7, reg);
+
+ if (!reg)
+ return IRQ_NONE;
+
+ if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
+ return IRQ_HANDLED;
+
+ /* Store irqvalues for use in the interrupt thread. */
+ rt2x00dev->irqvalue[0] = reg;
+
+ /* Disable interrupts, will be enabled again in the interrupt thread. */
+ rt2x00dev->ops->lib->set_device_state(rt2x00dev,
+ STATE_RADIO_IRQ_OFF_ISR);
+
+ return IRQ_WAKE_THREAD;
+}
+
/*
* Device probe functions.
*/
@@ -1396,8 +1422,8 @@ static int rt2400pci_init_eeprom(struct rt2x00_dev *rt2x00dev)
/*
* Check if the BBP tuning should be enabled.
*/
- if (!rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RX_AGCVGC_TUNING))
- __set_bit(CONFIG_DISABLE_LINK_TUNING, &rt2x00dev->flags);
+ if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RX_AGCVGC_TUNING))
+ __set_bit(DRIVER_SUPPORT_LINK_TUNING, &rt2x00dev->flags);
return 0;
}
@@ -1563,7 +1589,8 @@ static const struct ieee80211_ops rt2400pci_mac80211_ops = {
.remove_interface = rt2x00mac_remove_interface,
.config = rt2x00mac_config,
.configure_filter = rt2x00mac_configure_filter,
- .set_tim = rt2x00mac_set_tim,
+ .sw_scan_start = rt2x00mac_sw_scan_start,
+ .sw_scan_complete = rt2x00mac_sw_scan_complete,
.get_stats = rt2x00mac_get_stats,
.bss_info_changed = rt2x00mac_bss_info_changed,
.conf_tx = rt2400pci_conf_tx,
@@ -1574,6 +1601,7 @@ static const struct ieee80211_ops rt2400pci_mac80211_ops = {
static const struct rt2x00lib_ops rt2400pci_rt2x00_ops = {
.irq_handler = rt2400pci_interrupt,
+ .irq_handler_thread = rt2400pci_interrupt_thread,
.probe_hw = rt2400pci_probe_hw,
.initialize = rt2x00pci_initialize,
.uninitialize = rt2x00pci_uninitialize,
@@ -1585,7 +1613,6 @@ static const struct rt2x00lib_ops rt2400pci_rt2x00_ops = {
.reset_tuner = rt2400pci_reset_tuner,
.link_tuner = rt2400pci_link_tuner,
.write_tx_desc = rt2400pci_write_tx_desc,
- .write_tx_data = rt2x00pci_write_tx_data,
.write_beacon = rt2400pci_write_beacon,
.kick_tx_queue = rt2400pci_kick_tx_queue,
.kill_tx_queue = rt2400pci_kill_tx_queue,
diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c
index 41da3d218c6..c2a555d5376 100644
--- a/drivers/net/wireless/rt2x00/rt2500pci.c
+++ b/drivers/net/wireless/rt2x00/rt2500pci.c
@@ -626,6 +626,7 @@ static inline void rt2500pci_set_vgc(struct rt2x00_dev *rt2x00dev,
{
if (qual->vgc_level_reg != vgc_level) {
rt2500pci_bbp_write(rt2x00dev, 17, vgc_level);
+ qual->vgc_level = vgc_level;
qual->vgc_level_reg = vgc_level;
}
}
@@ -700,13 +701,10 @@ dynamic_cca_tune:
* R17 is inside the dynamic tuning range,
* start tuning the link based on the false cca counter.
*/
- if (qual->false_cca > 512 && qual->vgc_level_reg < 0x40) {
+ if (qual->false_cca > 512 && qual->vgc_level_reg < 0x40)
rt2500pci_set_vgc(rt2x00dev, qual, ++qual->vgc_level_reg);
- qual->vgc_level = qual->vgc_level_reg;
- } else if (qual->false_cca < 100 && qual->vgc_level_reg > 0x32) {
+ else if (qual->false_cca < 100 && qual->vgc_level_reg > 0x32)
rt2500pci_set_vgc(rt2x00dev, qual, --qual->vgc_level_reg);
- qual->vgc_level = qual->vgc_level_reg;
- }
}
/*
@@ -1035,7 +1033,8 @@ static void rt2500pci_toggle_rx(struct rt2x00_dev *rt2x00dev,
static void rt2500pci_toggle_irq(struct rt2x00_dev *rt2x00dev,
enum dev_state state)
{
- int mask = (state == STATE_RADIO_IRQ_OFF);
+ int mask = (state == STATE_RADIO_IRQ_OFF) ||
+ (state == STATE_RADIO_IRQ_OFF_ISR);
u32 reg;
/*
@@ -1136,7 +1135,9 @@ static int rt2500pci_set_device_state(struct rt2x00_dev *rt2x00dev,
rt2500pci_toggle_rx(rt2x00dev, state);
break;
case STATE_RADIO_IRQ_ON:
+ case STATE_RADIO_IRQ_ON_ISR:
case STATE_RADIO_IRQ_OFF:
+ case STATE_RADIO_IRQ_OFF_ISR:
rt2500pci_toggle_irq(rt2x00dev, state);
break;
case STATE_DEEP_SLEEP:
@@ -1233,9 +1234,6 @@ static void rt2500pci_write_beacon(struct queue_entry *entry,
struct txentry_desc *txdesc)
{
struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
- struct queue_entry_priv_pci *entry_priv = entry->priv_data;
- struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
- u32 word;
u32 reg;
/*
@@ -1248,9 +1246,15 @@ static void rt2500pci_write_beacon(struct queue_entry *entry,
rt2x00queue_map_txskb(rt2x00dev, entry->skb);
- rt2x00_desc_read(entry_priv->desc, 1, &word);
- rt2x00_set_field32(&word, TXD_W1_BUFFER_ADDRESS, skbdesc->skb_dma);
- rt2x00_desc_write(entry_priv->desc, 1, word);
+ /*
+ * Write the TX descriptor for the beacon.
+ */
+ rt2500pci_write_tx_desc(rt2x00dev, entry->skb, txdesc);
+
+ /*
+ * Dump beacon to userspace through debugfs.
+ */
+ rt2x00debug_dump_frame(rt2x00dev, DUMP_FRAME_BEACON, entry->skb);
/*
* Enable beaconing again.
@@ -1366,23 +1370,10 @@ static void rt2500pci_txdone(struct rt2x00_dev *rt2x00dev,
}
}
-static irqreturn_t rt2500pci_interrupt(int irq, void *dev_instance)
+static irqreturn_t rt2500pci_interrupt_thread(int irq, void *dev_instance)
{
struct rt2x00_dev *rt2x00dev = dev_instance;
- u32 reg;
-
- /*
- * Get the interrupt sources & saved to local variable.
- * Write register value back to clear pending interrupts.
- */
- rt2x00pci_register_read(rt2x00dev, CSR7, &reg);
- rt2x00pci_register_write(rt2x00dev, CSR7, reg);
-
- if (!reg)
- return IRQ_NONE;
-
- if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
- return IRQ_HANDLED;
+ u32 reg = rt2x00dev->irqvalue[0];
/*
* Handle interrupts, walk through all bits
@@ -1420,9 +1411,41 @@ static irqreturn_t rt2500pci_interrupt(int irq, void *dev_instance)
if (rt2x00_get_field32(reg, CSR7_TXDONE_TXRING))
rt2500pci_txdone(rt2x00dev, QID_AC_BK);
+ /* Enable interrupts again. */
+ rt2x00dev->ops->lib->set_device_state(rt2x00dev,
+ STATE_RADIO_IRQ_ON_ISR);
+
return IRQ_HANDLED;
}
+static irqreturn_t rt2500pci_interrupt(int irq, void *dev_instance)
+{
+ struct rt2x00_dev *rt2x00dev = dev_instance;
+ u32 reg;
+
+ /*
+ * Get the interrupt sources & saved to local variable.
+ * Write register value back to clear pending interrupts.
+ */
+ rt2x00pci_register_read(rt2x00dev, CSR7, &reg);
+ rt2x00pci_register_write(rt2x00dev, CSR7, reg);
+
+ if (!reg)
+ return IRQ_NONE;
+
+ if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
+ return IRQ_HANDLED;
+
+ /* Store irqvalues for use in the interrupt thread. */
+ rt2x00dev->irqvalue[0] = reg;
+
+ /* Disable interrupts, will be enabled again in the interrupt thread. */
+ rt2x00dev->ops->lib->set_device_state(rt2x00dev,
+ STATE_RADIO_IRQ_OFF_ISR);
+
+ return IRQ_WAKE_THREAD;
+}
+
/*
* Device probe functions.
*/
@@ -1554,9 +1577,8 @@ static int rt2500pci_init_eeprom(struct rt2x00_dev *rt2x00dev)
* Check if the BBP tuning should be enabled.
*/
rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC, &eeprom);
-
- if (rt2x00_get_field16(eeprom, EEPROM_NIC_DYN_BBP_TUNE))
- __set_bit(CONFIG_DISABLE_LINK_TUNING, &rt2x00dev->flags);
+ if (!rt2x00_get_field16(eeprom, EEPROM_NIC_DYN_BBP_TUNE))
+ __set_bit(DRIVER_SUPPORT_LINK_TUNING, &rt2x00dev->flags);
/*
* Read the RSSI <-> dBm offset information.
@@ -1861,7 +1883,8 @@ static const struct ieee80211_ops rt2500pci_mac80211_ops = {
.remove_interface = rt2x00mac_remove_interface,
.config = rt2x00mac_config,
.configure_filter = rt2x00mac_configure_filter,
- .set_tim = rt2x00mac_set_tim,
+ .sw_scan_start = rt2x00mac_sw_scan_start,
+ .sw_scan_complete = rt2x00mac_sw_scan_complete,
.get_stats = rt2x00mac_get_stats,
.bss_info_changed = rt2x00mac_bss_info_changed,
.conf_tx = rt2x00mac_conf_tx,
@@ -1872,6 +1895,7 @@ static const struct ieee80211_ops rt2500pci_mac80211_ops = {
static const struct rt2x00lib_ops rt2500pci_rt2x00_ops = {
.irq_handler = rt2500pci_interrupt,
+ .irq_handler_thread = rt2500pci_interrupt_thread,
.probe_hw = rt2500pci_probe_hw,
.initialize = rt2x00pci_initialize,
.uninitialize = rt2x00pci_uninitialize,
@@ -1883,7 +1907,6 @@ static const struct rt2x00lib_ops rt2500pci_rt2x00_ops = {
.reset_tuner = rt2500pci_reset_tuner,
.link_tuner = rt2500pci_link_tuner,
.write_tx_desc = rt2500pci_write_tx_desc,
- .write_tx_data = rt2x00pci_write_tx_data,
.write_beacon = rt2500pci_write_beacon,
.kick_tx_queue = rt2500pci_kick_tx_queue,
.kill_tx_queue = rt2500pci_kill_tx_queue,
diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c
index 9ae96a626e6..cdaf93f4826 100644
--- a/drivers/net/wireless/rt2x00/rt2500usb.c
+++ b/drivers/net/wireless/rt2x00/rt2500usb.c
@@ -345,12 +345,20 @@ static int rt2500usb_config_key(struct rt2x00_dev *rt2x00dev,
struct rt2x00lib_crypto *crypto,
struct ieee80211_key_conf *key)
{
- int timeout;
u32 mask;
u16 reg;
+ enum cipher curr_cipher;
if (crypto->cmd == SET_KEY) {
/*
+ * Disallow to set WEP key other than with index 0,
+ * it is known that not work at least on some hardware.
+ * SW crypto will be used in that case.
+ */
+ if (key->alg == ALG_WEP && key->keyidx != 0)
+ return -EOPNOTSUPP;
+
+ /*
* Pairwise key will always be entry 0, but this
* could collide with a shared key on the same
* position...
@@ -358,6 +366,7 @@ static int rt2500usb_config_key(struct rt2x00_dev *rt2x00dev,
mask = TXRX_CSR0_KEY_ID.bit_mask;
rt2500usb_register_read(rt2x00dev, TXRX_CSR0, &reg);
+ curr_cipher = rt2x00_get_field16(reg, TXRX_CSR0_ALGORITHM);
reg &= mask;
if (reg && reg == mask)
@@ -366,19 +375,17 @@ static int rt2500usb_config_key(struct rt2x00_dev *rt2x00dev,
reg = rt2x00_get_field16(reg, TXRX_CSR0_KEY_ID);
key->hw_key_idx += reg ? ffz(reg) : 0;
-
/*
- * The encryption key doesn't fit within the CSR cache,
- * this means we should allocate it separately and use
- * rt2x00usb_vendor_request() to send the key to the hardware.
+ * Hardware requires that all keys use the same cipher
+ * (e.g. TKIP-only, AES-only, but not TKIP+AES).
+ * If this is not the first key, compare the cipher with the
+ * first one and fall back to SW crypto if not the same.
*/
- reg = KEY_ENTRY(key->hw_key_idx);
- timeout = REGISTER_TIMEOUT32(sizeof(crypto->key));
- rt2x00usb_vendor_request_large_buff(rt2x00dev, USB_MULTI_WRITE,
- USB_VENDOR_REQUEST_OUT, reg,
- crypto->key,
- sizeof(crypto->key),
- timeout);
+ if (key->hw_key_idx > 0 && crypto->cipher != curr_cipher)
+ return -EOPNOTSUPP;
+
+ rt2500usb_register_multiwrite(rt2x00dev, KEY_ENTRY(key->hw_key_idx),
+ crypto->key, sizeof(crypto->key));
/*
* The driver does not support the IV/EIV generation
@@ -818,6 +825,7 @@ static int rt2500usb_init_registers(struct rt2x00_dev *rt2x00dev)
rt2500usb_register_write(rt2x00dev, MAC_CSR8, reg);
rt2500usb_register_read(rt2x00dev, TXRX_CSR0, &reg);
+ rt2x00_set_field16(&reg, TXRX_CSR0_ALGORITHM, CIPHER_NONE);
rt2x00_set_field16(&reg, TXRX_CSR0_IV_OFFSET, IEEE80211_HEADER);
rt2x00_set_field16(&reg, TXRX_CSR0_KEY_ID, 0);
rt2500usb_register_write(rt2x00dev, TXRX_CSR0, reg);
@@ -1005,7 +1013,9 @@ static int rt2500usb_set_device_state(struct rt2x00_dev *rt2x00dev,
rt2500usb_toggle_rx(rt2x00dev, state);
break;
case STATE_RADIO_IRQ_ON:
+ case STATE_RADIO_IRQ_ON_ISR:
case STATE_RADIO_IRQ_OFF:
+ case STATE_RADIO_IRQ_OFF_ISR:
/* No support, but no error either */
break;
case STATE_DEEP_SLEEP:
@@ -1034,7 +1044,7 @@ static void rt2500usb_write_tx_desc(struct rt2x00_dev *rt2x00dev,
struct txentry_desc *txdesc)
{
struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb);
- __le32 *txd = (__le32 *)(skb->data - TXD_DESC_SIZE);
+ __le32 *txd = (__le32 *) skb->data;
u32 word;
/*
@@ -1080,6 +1090,7 @@ static void rt2500usb_write_tx_desc(struct rt2x00_dev *rt2x00dev,
/*
* Register descriptor details in skb frame descriptor.
*/
+ skbdesc->flags |= SKBDESC_DESC_IN_SKB;
skbdesc->desc = txd;
skbdesc->desc_len = TXD_DESC_SIZE;
}
@@ -1108,9 +1119,20 @@ static void rt2500usb_write_beacon(struct queue_entry *entry,
rt2500usb_register_write(rt2x00dev, TXRX_CSR19, reg);
/*
- * Take the descriptor in front of the skb into account.
+ * Add space for the descriptor in front of the skb.
*/
skb_push(entry->skb, TXD_DESC_SIZE);
+ memset(entry->skb->data, 0, TXD_DESC_SIZE);
+
+ /*
+ * Write the TX descriptor for the beacon.
+ */
+ rt2500usb_write_tx_desc(rt2x00dev, entry->skb, txdesc);
+
+ /*
+ * Dump beacon to userspace through debugfs.
+ */
+ rt2x00debug_dump_frame(rt2x00dev, DUMP_FRAME_BEACON, entry->skb);
/*
* USB devices cannot blindly pass the skb->len as the
@@ -1460,13 +1482,6 @@ static int rt2500usb_init_eeprom(struct rt2x00_dev *rt2x00dev)
__set_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags);
/*
- * Check if the BBP tuning should be disabled.
- */
- rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC, &eeprom);
- if (rt2x00_get_field16(eeprom, EEPROM_NIC_DYN_BBP_TUNE))
- __set_bit(CONFIG_DISABLE_LINK_TUNING, &rt2x00dev->flags);
-
- /*
* Read the RSSI <-> dBm offset information.
*/
rt2x00_eeprom_read(rt2x00dev, EEPROM_CALIBRATE_OFFSET, &eeprom);
@@ -1732,7 +1747,7 @@ static int rt2500usb_probe_hw(struct rt2x00_dev *rt2x00dev)
__set_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags);
__set_bit(DRIVER_REQUIRE_COPY_IV, &rt2x00dev->flags);
}
- __set_bit(CONFIG_DISABLE_LINK_TUNING, &rt2x00dev->flags);
+ __set_bit(DRIVER_SUPPORT_WATCHDOG, &rt2x00dev->flags);
/*
* Set the rssi offset.
@@ -1752,6 +1767,8 @@ static const struct ieee80211_ops rt2500usb_mac80211_ops = {
.configure_filter = rt2x00mac_configure_filter,
.set_tim = rt2x00mac_set_tim,
.set_key = rt2x00mac_set_key,
+ .sw_scan_start = rt2x00mac_sw_scan_start,
+ .sw_scan_complete = rt2x00mac_sw_scan_complete,
.get_stats = rt2x00mac_get_stats,
.bss_info_changed = rt2x00mac_bss_info_changed,
.conf_tx = rt2x00mac_conf_tx,
@@ -1767,8 +1784,8 @@ static const struct rt2x00lib_ops rt2500usb_rt2x00_ops = {
.rfkill_poll = rt2500usb_rfkill_poll,
.link_stats = rt2500usb_link_stats,
.reset_tuner = rt2500usb_reset_tuner,
+ .watchdog = rt2x00usb_watchdog,
.write_tx_desc = rt2500usb_write_tx_desc,
- .write_tx_data = rt2x00usb_write_tx_data,
.write_beacon = rt2500usb_write_beacon,
.get_tx_data_len = rt2500usb_get_tx_data_len,
.kick_tx_queue = rt2x00usb_kick_tx_queue,
diff --git a/drivers/net/wireless/rt2x00/rt2800.h b/drivers/net/wireless/rt2x00/rt2800.h
index 2aa03751c34..ed4ebcdde7c 100644
--- a/drivers/net/wireless/rt2x00/rt2800.h
+++ b/drivers/net/wireless/rt2x00/rt2800.h
@@ -63,7 +63,6 @@
*/
#define REV_RT2860C 0x0100
#define REV_RT2860D 0x0101
-#define REV_RT2870D 0x0101
#define REV_RT2872E 0x0200
#define REV_RT3070E 0x0200
#define REV_RT3070F 0x0201
@@ -75,7 +74,7 @@
* Signal information.
* Default offset is required for RSSI <-> dBm conversion.
*/
-#define DEFAULT_RSSI_OFFSET 120 /* FIXME */
+#define DEFAULT_RSSI_OFFSET 120
/*
* Register layout information.
@@ -99,6 +98,21 @@
*/
/*
+ * E2PROM_CSR: PCI EEPROM control register.
+ * RELOAD: Write 1 to reload eeprom content.
+ * TYPE: 0: 93c46, 1:93c66.
+ * LOAD_STATUS: 1:loading, 0:done.
+ */
+#define E2PROM_CSR 0x0004
+#define E2PROM_CSR_DATA_CLOCK FIELD32(0x00000001)
+#define E2PROM_CSR_CHIP_SELECT FIELD32(0x00000002)
+#define E2PROM_CSR_DATA_IN FIELD32(0x00000004)
+#define E2PROM_CSR_DATA_OUT FIELD32(0x00000008)
+#define E2PROM_CSR_TYPE FIELD32(0x00000030)
+#define E2PROM_CSR_LOAD_STATUS FIELD32(0x00000040)
+#define E2PROM_CSR_RELOAD FIELD32(0x00000080)
+
+/*
* OPT_14: Unknown register used by rt3xxx devices.
*/
#define OPT_14_CSR 0x0114
@@ -322,6 +336,39 @@
#define RX_DRX_IDX 0x029c
/*
+ * USB_DMA_CFG
+ * RX_BULK_AGG_TIMEOUT: Rx Bulk Aggregation TimeOut in unit of 33ns.
+ * RX_BULK_AGG_LIMIT: Rx Bulk Aggregation Limit in unit of 256 bytes.
+ * PHY_CLEAR: phy watch dog enable.
+ * TX_CLEAR: Clear USB DMA TX path.
+ * TXOP_HALT: Halt TXOP count down when TX buffer is full.
+ * RX_BULK_AGG_EN: Enable Rx Bulk Aggregation.
+ * RX_BULK_EN: Enable USB DMA Rx.
+ * TX_BULK_EN: Enable USB DMA Tx.
+ * EP_OUT_VALID: OUT endpoint data valid.
+ * RX_BUSY: USB DMA RX FSM busy.
+ * TX_BUSY: USB DMA TX FSM busy.
+ */
+#define USB_DMA_CFG 0x02a0
+#define USB_DMA_CFG_RX_BULK_AGG_TIMEOUT FIELD32(0x000000ff)
+#define USB_DMA_CFG_RX_BULK_AGG_LIMIT FIELD32(0x0000ff00)
+#define USB_DMA_CFG_PHY_CLEAR FIELD32(0x00010000)
+#define USB_DMA_CFG_TX_CLEAR FIELD32(0x00080000)
+#define USB_DMA_CFG_TXOP_HALT FIELD32(0x00100000)
+#define USB_DMA_CFG_RX_BULK_AGG_EN FIELD32(0x00200000)
+#define USB_DMA_CFG_RX_BULK_EN FIELD32(0x00400000)
+#define USB_DMA_CFG_TX_BULK_EN FIELD32(0x00800000)
+#define USB_DMA_CFG_EP_OUT_VALID FIELD32(0x3f000000)
+#define USB_DMA_CFG_RX_BUSY FIELD32(0x40000000)
+#define USB_DMA_CFG_TX_BUSY FIELD32(0x80000000)
+
+/*
+ * US_CYC_CNT
+ */
+#define US_CYC_CNT 0x02a4
+#define US_CYC_CNT_CLOCK_CYCLE FIELD32(0x000000ff)
+
+/*
* PBF_SYS_CTRL
* HOST_RAM_WRITE: enable Host program ram write selection
*/
@@ -672,14 +719,20 @@
#define TBTT_TIMER 0x1124
/*
- * INT_TIMER_CFG:
+ * INT_TIMER_CFG: timer configuration
+ * PRE_TBTT_TIMER: leadtime to tbtt for pretbtt interrupt in units of 1/16 TU
+ * GP_TIMER: period of general purpose timer in units of 1/16 TU
*/
#define INT_TIMER_CFG 0x1128
+#define INT_TIMER_CFG_PRE_TBTT_TIMER FIELD32(0x0000ffff)
+#define INT_TIMER_CFG_GP_TIMER FIELD32(0xffff0000)
/*
* INT_TIMER_EN: GP-timer and pre-tbtt Int enable
*/
#define INT_TIMER_EN 0x112c
+#define INT_TIMER_EN_PRE_TBTT_TIMER FIELD32(0x00000001)
+#define INT_TIMER_EN_GP_TIMER FIELD32(0x00000002)
/*
* CH_IDLE_STA: channel idle time
@@ -756,6 +809,18 @@
#define EDCA_TID_AC_MAP 0x1310
/*
+ * TX_PWR_CFG:
+ */
+#define TX_PWR_CFG_RATE0 FIELD32(0x0000000f)
+#define TX_PWR_CFG_RATE1 FIELD32(0x000000f0)
+#define TX_PWR_CFG_RATE2 FIELD32(0x00000f00)
+#define TX_PWR_CFG_RATE3 FIELD32(0x0000f000)
+#define TX_PWR_CFG_RATE4 FIELD32(0x000f0000)
+#define TX_PWR_CFG_RATE5 FIELD32(0x00f00000)
+#define TX_PWR_CFG_RATE6 FIELD32(0x0f000000)
+#define TX_PWR_CFG_RATE7 FIELD32(0xf0000000)
+
+/*
* TX_PWR_CFG_0:
*/
#define TX_PWR_CFG_0 0x1314
@@ -1370,17 +1435,17 @@
struct mac_wcid_entry {
u8 mac[6];
u8 reserved[2];
-} __attribute__ ((packed));
+} __packed;
struct hw_key_entry {
u8 key[16];
u8 tx_mic[8];
u8 rx_mic[8];
-} __attribute__ ((packed));
+} __packed;
struct mac_iveiv_entry {
u8 iv[8];
-} __attribute__ ((packed));
+} __packed;
/*
* MAC_WCID_ATTRIBUTE:
@@ -1389,6 +1454,10 @@ struct mac_iveiv_entry {
#define MAC_WCID_ATTRIBUTE_CIPHER FIELD32(0x0000000e)
#define MAC_WCID_ATTRIBUTE_BSS_IDX FIELD32(0x00000070)
#define MAC_WCID_ATTRIBUTE_RX_WIUDF FIELD32(0x00000380)
+#define MAC_WCID_ATTRIBUTE_CIPHER_EXT FIELD32(0x00000400)
+#define MAC_WCID_ATTRIBUTE_BSS_IDX_EXT FIELD32(0x00000800)
+#define MAC_WCID_ATTRIBUTE_WAPI_MCBC FIELD32(0x00008000)
+#define MAC_WCID_ATTRIBUTE_WAPI_KEY_IDX FIELD32(0xff000000)
/*
* SHARED_KEY_MODE:
@@ -1510,7 +1579,9 @@ struct mac_iveiv_entry {
*/
/*
- * BBP 1: TX Antenna
+ * BBP 1: TX Antenna & Power
+ * POWER: 0 - normal, 1 - drop tx power by 6dBm, 2 - drop tx power by 12dBm,
+ * 3 - increase tx power by 6dBm
*/
#define BBP1_TX_POWER FIELD8(0x07)
#define BBP1_TX_ANTENNA FIELD8(0x18)
@@ -1800,9 +1871,15 @@ struct mac_iveiv_entry {
#define EEPROM_TXPOWER_A_2 FIELD16(0xff00)
/*
- * EEPROM TXpower byrate: 20MHZ power
+ * EEPROM TXPOWER by rate: tx power per tx rate for HT20 mode
*/
#define EEPROM_TXPOWER_BYRATE 0x006f
+#define EEPROM_TXPOWER_BYRATE_SIZE 9
+
+#define EEPROM_TXPOWER_BYRATE_RATE0 FIELD16(0x000f)
+#define EEPROM_TXPOWER_BYRATE_RATE1 FIELD16(0x00f0)
+#define EEPROM_TXPOWER_BYRATE_RATE2 FIELD16(0x0f00)
+#define EEPROM_TXPOWER_BYRATE_RATE3 FIELD16(0xf000)
/*
* EEPROM BBP.
diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c
index db4250d1c8b..b66e0fd8f0f 100644
--- a/drivers/net/wireless/rt2x00/rt2800lib.c
+++ b/drivers/net/wireless/rt2x00/rt2800lib.c
@@ -1,9 +1,9 @@
/*
+ Copyright (C) 2010 Ivo van Doorn <IvDoorn@gmail.com>
Copyright (C) 2009 Bartlomiej Zolnierkiewicz <bzolnier@gmail.com>
Copyright (C) 2009 Gertjan van Wingerde <gwingerde@gmail.com>
Based on the original rt2800pci.c and rt2800usb.c.
- Copyright (C) 2009 Ivo van Doorn <IvDoorn@gmail.com>
Copyright (C) 2009 Alban Browaeys <prahal@yahoo.com>
Copyright (C) 2009 Felix Fietkau <nbd@openwrt.org>
Copyright (C) 2009 Luis Correia <luis.f.correia@gmail.com>
@@ -33,21 +33,14 @@
Abstract: rt2800 generic device routines.
*/
+#include <linux/crc-ccitt.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include "rt2x00.h"
-#if defined(CONFIG_RT2X00_LIB_USB) || defined(CONFIG_RT2X00_LIB_USB_MODULE)
-#include "rt2x00usb.h"
-#endif
#include "rt2800lib.h"
#include "rt2800.h"
-#include "rt2800usb.h"
-
-MODULE_AUTHOR("Bartlomiej Zolnierkiewicz");
-MODULE_DESCRIPTION("rt2800 library");
-MODULE_LICENSE("GPL");
/*
* Register access.
@@ -107,8 +100,7 @@ static void rt2800_bbp_write(struct rt2x00_dev *rt2x00dev,
rt2x00_set_field32(&reg, BBP_CSR_CFG_REGNUM, word);
rt2x00_set_field32(&reg, BBP_CSR_CFG_BUSY, 1);
rt2x00_set_field32(&reg, BBP_CSR_CFG_READ_CONTROL, 0);
- if (rt2x00_is_pci(rt2x00dev) || rt2x00_is_soc(rt2x00dev))
- rt2x00_set_field32(&reg, BBP_CSR_CFG_BBP_RW_MODE, 1);
+ rt2x00_set_field32(&reg, BBP_CSR_CFG_BBP_RW_MODE, 1);
rt2800_register_write_lock(rt2x00dev, BBP_CSR_CFG, reg);
}
@@ -136,8 +128,7 @@ static void rt2800_bbp_read(struct rt2x00_dev *rt2x00dev,
rt2x00_set_field32(&reg, BBP_CSR_CFG_REGNUM, word);
rt2x00_set_field32(&reg, BBP_CSR_CFG_BUSY, 1);
rt2x00_set_field32(&reg, BBP_CSR_CFG_READ_CONTROL, 1);
- if (rt2x00_is_pci(rt2x00dev) || rt2x00_is_soc(rt2x00dev))
- rt2x00_set_field32(&reg, BBP_CSR_CFG_BBP_RW_MODE, 1);
+ rt2x00_set_field32(&reg, BBP_CSR_CFG_BBP_RW_MODE, 1);
rt2800_register_write_lock(rt2x00dev, BBP_CSR_CFG, reg);
@@ -282,9 +273,162 @@ int rt2800_wait_wpdma_ready(struct rt2x00_dev *rt2x00dev)
}
EXPORT_SYMBOL_GPL(rt2800_wait_wpdma_ready);
-void rt2800_write_txwi(struct sk_buff *skb, struct txentry_desc *txdesc)
+static bool rt2800_check_firmware_crc(const u8 *data, const size_t len)
+{
+ u16 fw_crc;
+ u16 crc;
+
+ /*
+ * The last 2 bytes in the firmware array are the crc checksum itself,
+ * this means that we should never pass those 2 bytes to the crc
+ * algorithm.
+ */
+ fw_crc = (data[len - 2] << 8 | data[len - 1]);
+
+ /*
+ * Use the crc ccitt algorithm.
+ * This will return the same value as the legacy driver which
+ * used bit ordering reversion on the both the firmware bytes
+ * before input input as well as on the final output.
+ * Obviously using crc ccitt directly is much more efficient.
+ */
+ crc = crc_ccitt(~0, data, len - 2);
+
+ /*
+ * There is a small difference between the crc-itu-t + bitrev and
+ * the crc-ccitt crc calculation. In the latter method the 2 bytes
+ * will be swapped, use swab16 to convert the crc to the correct
+ * value.
+ */
+ crc = swab16(crc);
+
+ return fw_crc == crc;
+}
+
+int rt2800_check_firmware(struct rt2x00_dev *rt2x00dev,
+ const u8 *data, const size_t len)
+{
+ size_t offset = 0;
+ size_t fw_len;
+ bool multiple;
+
+ /*
+ * PCI(e) & SOC devices require firmware with a length
+ * of 8kb. USB devices require firmware files with a length
+ * of 4kb. Certain USB chipsets however require different firmware,
+ * which Ralink only provides attached to the original firmware
+ * file. Thus for USB devices, firmware files have a length
+ * which is a multiple of 4kb.
+ */
+ if (rt2x00_is_usb(rt2x00dev)) {
+ fw_len = 4096;
+ multiple = true;
+ } else {
+ fw_len = 8192;
+ multiple = true;
+ }
+
+ /*
+ * Validate the firmware length
+ */
+ if (len != fw_len && (!multiple || (len % fw_len) != 0))
+ return FW_BAD_LENGTH;
+
+ /*
+ * Check if the chipset requires one of the upper parts
+ * of the firmware.
+ */
+ if (rt2x00_is_usb(rt2x00dev) &&
+ !rt2x00_rt(rt2x00dev, RT2860) &&
+ !rt2x00_rt(rt2x00dev, RT2872) &&
+ !rt2x00_rt(rt2x00dev, RT3070) &&
+ ((len / fw_len) == 1))
+ return FW_BAD_VERSION;
+
+ /*
+ * 8kb firmware files must be checked as if it were
+ * 2 separate firmware files.
+ */
+ while (offset < len) {
+ if (!rt2800_check_firmware_crc(data + offset, fw_len))
+ return FW_BAD_CRC;
+
+ offset += fw_len;
+ }
+
+ return FW_OK;
+}
+EXPORT_SYMBOL_GPL(rt2800_check_firmware);
+
+int rt2800_load_firmware(struct rt2x00_dev *rt2x00dev,
+ const u8 *data, const size_t len)
+{
+ unsigned int i;
+ u32 reg;
+
+ /*
+ * Wait for stable hardware.
+ */
+ for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
+ rt2800_register_read(rt2x00dev, MAC_CSR0, &reg);
+ if (reg && reg != ~0)
+ break;
+ msleep(1);
+ }
+
+ if (i == REGISTER_BUSY_COUNT) {
+ ERROR(rt2x00dev, "Unstable hardware.\n");
+ return -EBUSY;
+ }
+
+ if (rt2x00_is_pci(rt2x00dev))
+ rt2800_register_write(rt2x00dev, PWR_PIN_CFG, 0x00000002);
+
+ /*
+ * Disable DMA, will be reenabled later when enabling
+ * the radio.
+ */
+ rt2800_register_read(rt2x00dev, WPDMA_GLO_CFG, &reg);
+ rt2x00_set_field32(&reg, WPDMA_GLO_CFG_ENABLE_TX_DMA, 0);
+ rt2x00_set_field32(&reg, WPDMA_GLO_CFG_TX_DMA_BUSY, 0);
+ rt2x00_set_field32(&reg, WPDMA_GLO_CFG_ENABLE_RX_DMA, 0);
+ rt2x00_set_field32(&reg, WPDMA_GLO_CFG_RX_DMA_BUSY, 0);
+ rt2x00_set_field32(&reg, WPDMA_GLO_CFG_TX_WRITEBACK_DONE, 1);
+ rt2800_register_write(rt2x00dev, WPDMA_GLO_CFG, reg);
+
+ /*
+ * Write firmware to the device.
+ */
+ rt2800_drv_write_firmware(rt2x00dev, data, len);
+
+ /*
+ * Wait for device to stabilize.
+ */
+ for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
+ rt2800_register_read(rt2x00dev, PBF_SYS_CTRL, &reg);
+ if (rt2x00_get_field32(reg, PBF_SYS_CTRL_READY))
+ break;
+ msleep(1);
+ }
+
+ if (i == REGISTER_BUSY_COUNT) {
+ ERROR(rt2x00dev, "PBF system register not ready.\n");
+ return -EBUSY;
+ }
+
+ /*
+ * Initialize firmware.
+ */
+ rt2800_register_write(rt2x00dev, H2M_BBP_AGENT, 0);
+ rt2800_register_write(rt2x00dev, H2M_MAILBOX_CSR, 0);
+ msleep(1);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(rt2800_load_firmware);
+
+void rt2800_write_txwi(__le32 *txwi, struct txentry_desc *txdesc)
{
- __le32 *txwi = (__le32 *)(skb->data - TXWI_DESC_SIZE);
u32 word;
/*
@@ -336,9 +480,53 @@ void rt2800_write_txwi(struct sk_buff *skb, struct txentry_desc *txdesc)
}
EXPORT_SYMBOL_GPL(rt2800_write_txwi);
-void rt2800_process_rxwi(struct sk_buff *skb, struct rxdone_entry_desc *rxdesc)
+static int rt2800_agc_to_rssi(struct rt2x00_dev *rt2x00dev, int rxwi_w2)
{
- __le32 *rxwi = (__le32 *) skb->data;
+ int rssi0 = rt2x00_get_field32(rxwi_w2, RXWI_W2_RSSI0);
+ int rssi1 = rt2x00_get_field32(rxwi_w2, RXWI_W2_RSSI1);
+ int rssi2 = rt2x00_get_field32(rxwi_w2, RXWI_W2_RSSI2);
+ u16 eeprom;
+ u8 offset0;
+ u8 offset1;
+ u8 offset2;
+
+ if (rt2x00dev->rx_status.band == IEEE80211_BAND_2GHZ) {
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_BG, &eeprom);
+ offset0 = rt2x00_get_field16(eeprom, EEPROM_RSSI_BG_OFFSET0);
+ offset1 = rt2x00_get_field16(eeprom, EEPROM_RSSI_BG_OFFSET1);
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_BG2, &eeprom);
+ offset2 = rt2x00_get_field16(eeprom, EEPROM_RSSI_BG2_OFFSET2);
+ } else {
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_A, &eeprom);
+ offset0 = rt2x00_get_field16(eeprom, EEPROM_RSSI_A_OFFSET0);
+ offset1 = rt2x00_get_field16(eeprom, EEPROM_RSSI_A_OFFSET1);
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_A2, &eeprom);
+ offset2 = rt2x00_get_field16(eeprom, EEPROM_RSSI_A2_OFFSET2);
+ }
+
+ /*
+ * Convert the value from the descriptor into the RSSI value
+ * If the value in the descriptor is 0, it is considered invalid
+ * and the default (extremely low) rssi value is assumed
+ */
+ rssi0 = (rssi0) ? (-12 - offset0 - rt2x00dev->lna_gain - rssi0) : -128;
+ rssi1 = (rssi1) ? (-12 - offset1 - rt2x00dev->lna_gain - rssi1) : -128;
+ rssi2 = (rssi2) ? (-12 - offset2 - rt2x00dev->lna_gain - rssi2) : -128;
+
+ /*
+ * mac80211 only accepts a single RSSI value. Calculating the
+ * average doesn't deliver a fair answer either since -60:-60 would
+ * be considered equally good as -50:-70 while the second is the one
+ * which gives less energy...
+ */
+ rssi0 = max(rssi0, rssi1);
+ return max(rssi0, rssi2);
+}
+
+void rt2800_process_rxwi(struct queue_entry *entry,
+ struct rxdone_entry_desc *rxdesc)
+{
+ __le32 *rxwi = (__le32 *) entry->skb->data;
u32 word;
rt2x00_desc_read(rxwi, 0, &word);
@@ -369,17 +557,93 @@ void rt2800_process_rxwi(struct sk_buff *skb, struct rxdone_entry_desc *rxdesc)
rt2x00_desc_read(rxwi, 2, &word);
- rxdesc->rssi =
- (rt2x00_get_field32(word, RXWI_W2_RSSI0) +
- rt2x00_get_field32(word, RXWI_W2_RSSI1)) / 2;
+ /*
+ * Convert descriptor AGC value to RSSI value.
+ */
+ rxdesc->rssi = rt2800_agc_to_rssi(entry->queue->rt2x00dev, word);
/*
* Remove RXWI descriptor from start of buffer.
*/
- skb_pull(skb, RXWI_DESC_SIZE);
+ skb_pull(entry->skb, RXWI_DESC_SIZE);
}
EXPORT_SYMBOL_GPL(rt2800_process_rxwi);
+void rt2800_write_beacon(struct queue_entry *entry, struct txentry_desc *txdesc)
+{
+ struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
+ struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
+ unsigned int beacon_base;
+ u32 reg;
+
+ /*
+ * Disable beaconing while we are reloading the beacon data,
+ * otherwise we might be sending out invalid data.
+ */
+ rt2800_register_read(rt2x00dev, BCN_TIME_CFG, &reg);
+ rt2x00_set_field32(&reg, BCN_TIME_CFG_BEACON_GEN, 0);
+ rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg);
+
+ /*
+ * Add space for the TXWI in front of the skb.
+ */
+ skb_push(entry->skb, TXWI_DESC_SIZE);
+ memset(entry->skb, 0, TXWI_DESC_SIZE);
+
+ /*
+ * Register descriptor details in skb frame descriptor.
+ */
+ skbdesc->flags |= SKBDESC_DESC_IN_SKB;
+ skbdesc->desc = entry->skb->data;
+ skbdesc->desc_len = TXWI_DESC_SIZE;
+
+ /*
+ * Add the TXWI for the beacon to the skb.
+ */
+ rt2800_write_txwi((__le32 *)entry->skb->data, txdesc);
+
+ /*
+ * Dump beacon to userspace through debugfs.
+ */
+ rt2x00debug_dump_frame(rt2x00dev, DUMP_FRAME_BEACON, entry->skb);
+
+ /*
+ * Write entire beacon with TXWI to register.
+ */
+ beacon_base = HW_BEACON_OFFSET(entry->entry_idx);
+ rt2800_register_multiwrite(rt2x00dev, beacon_base,
+ entry->skb->data, entry->skb->len);
+
+ /*
+ * Enable beaconing again.
+ */
+ rt2x00_set_field32(&reg, BCN_TIME_CFG_TSF_TICKING, 1);
+ rt2x00_set_field32(&reg, BCN_TIME_CFG_TBTT_ENABLE, 1);
+ rt2x00_set_field32(&reg, BCN_TIME_CFG_BEACON_GEN, 1);
+ rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg);
+
+ /*
+ * Clean up beacon skb.
+ */
+ dev_kfree_skb_any(entry->skb);
+ entry->skb = NULL;
+}
+EXPORT_SYMBOL_GPL(rt2800_write_beacon);
+
+static void inline rt2800_clear_beacon(struct rt2x00_dev *rt2x00dev,
+ unsigned int beacon_base)
+{
+ int i;
+
+ /*
+ * For the Beacon base registers we only need to clear
+ * the whole TXWI which (when set to 0) will invalidate
+ * the entire beacon.
+ */
+ for (i = 0; i < TXWI_DESC_SIZE; i += sizeof(__le32))
+ rt2800_register_write(rt2x00dev, beacon_base + i, 0);
+}
+
#ifdef CONFIG_RT2X00_LIB_DEBUGFS
const struct rt2x00debug rt2800_rt2x00debug = {
.owner = THIS_MODULE,
@@ -502,15 +766,28 @@ static void rt2800_config_wcid_attr(struct rt2x00_dev *rt2x00dev,
offset = MAC_WCID_ATTR_ENTRY(key->hw_key_idx);
- rt2800_register_read(rt2x00dev, offset, &reg);
- rt2x00_set_field32(&reg, MAC_WCID_ATTRIBUTE_KEYTAB,
- !!(key->flags & IEEE80211_KEY_FLAG_PAIRWISE));
- rt2x00_set_field32(&reg, MAC_WCID_ATTRIBUTE_CIPHER,
- (crypto->cmd == SET_KEY) * crypto->cipher);
- rt2x00_set_field32(&reg, MAC_WCID_ATTRIBUTE_BSS_IDX,
- (crypto->cmd == SET_KEY) * crypto->bssidx);
- rt2x00_set_field32(&reg, MAC_WCID_ATTRIBUTE_RX_WIUDF, crypto->cipher);
- rt2800_register_write(rt2x00dev, offset, reg);
+ if (crypto->cmd == SET_KEY) {
+ rt2800_register_read(rt2x00dev, offset, &reg);
+ rt2x00_set_field32(&reg, MAC_WCID_ATTRIBUTE_KEYTAB,
+ !!(key->flags & IEEE80211_KEY_FLAG_PAIRWISE));
+ /*
+ * Both the cipher as the BSS Idx numbers are split in a main
+ * value of 3 bits, and a extended field for adding one additional
+ * bit to the value.
+ */
+ rt2x00_set_field32(&reg, MAC_WCID_ATTRIBUTE_CIPHER,
+ (crypto->cipher & 0x7));
+ rt2x00_set_field32(&reg, MAC_WCID_ATTRIBUTE_CIPHER_EXT,
+ (crypto->cipher & 0x8) >> 3);
+ rt2x00_set_field32(&reg, MAC_WCID_ATTRIBUTE_BSS_IDX,
+ (crypto->bssidx & 0x7));
+ rt2x00_set_field32(&reg, MAC_WCID_ATTRIBUTE_BSS_IDX_EXT,
+ (crypto->bssidx & 0x8) >> 3);
+ rt2x00_set_field32(&reg, MAC_WCID_ATTRIBUTE_RX_WIUDF, crypto->cipher);
+ rt2800_register_write(rt2x00dev, offset, reg);
+ } else {
+ rt2800_register_write(rt2x00dev, offset, 0);
+ }
offset = MAC_IVEIV_ENTRY(key->hw_key_idx);
@@ -668,19 +945,14 @@ EXPORT_SYMBOL_GPL(rt2800_config_filter);
void rt2800_config_intf(struct rt2x00_dev *rt2x00dev, struct rt2x00_intf *intf,
struct rt2x00intf_conf *conf, const unsigned int flags)
{
- unsigned int beacon_base;
u32 reg;
if (flags & CONFIG_UPDATE_TYPE) {
/*
* Clear current synchronisation setup.
- * For the Beacon base registers we only need to clear
- * the first byte since that byte contains the VALID and OWNER
- * bits which (when set to 0) will invalidate the entire beacon.
*/
- beacon_base = HW_BEACON_OFFSET(intf->beacon->entry_idx);
- rt2800_register_write(rt2x00dev, beacon_base, 0);
-
+ rt2800_clear_beacon(rt2x00dev,
+ HW_BEACON_OFFSET(intf->beacon->entry_idx));
/*
* Enable synchronisation.
*/
@@ -688,8 +960,18 @@ void rt2800_config_intf(struct rt2x00_dev *rt2x00dev, struct rt2x00_intf *intf,
rt2x00_set_field32(&reg, BCN_TIME_CFG_TSF_TICKING, 1);
rt2x00_set_field32(&reg, BCN_TIME_CFG_TSF_SYNC, conf->sync);
rt2x00_set_field32(&reg, BCN_TIME_CFG_TBTT_ENABLE,
- (conf->sync == TSF_SYNC_BEACON));
+ (conf->sync == TSF_SYNC_ADHOC ||
+ conf->sync == TSF_SYNC_AP_NONE));
rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg);
+
+ /*
+ * Enable pre tbtt interrupt for beaconing modes
+ */
+ rt2800_register_read(rt2x00dev, INT_TIMER_EN, &reg);
+ rt2x00_set_field32(&reg, INT_TIMER_EN_PRE_TBTT_TIMER,
+ (conf->sync == TSF_SYNC_AP_NONE));
+ rt2800_register_write(rt2x00dev, INT_TIMER_EN, reg);
+
}
if (flags & CONFIG_UPDATE_MAC) {
@@ -703,8 +985,8 @@ void rt2800_config_intf(struct rt2x00_dev *rt2x00dev, struct rt2x00_intf *intf,
if (flags & CONFIG_UPDATE_BSSID) {
reg = le32_to_cpu(conf->bssid[1]);
- rt2x00_set_field32(&reg, MAC_BSSID_DW1_BSS_ID_MASK, 0);
- rt2x00_set_field32(&reg, MAC_BSSID_DW1_BSS_BCN_NUM, 0);
+ rt2x00_set_field32(&reg, MAC_BSSID_DW1_BSS_ID_MASK, 3);
+ rt2x00_set_field32(&reg, MAC_BSSID_DW1_BSS_BCN_NUM, 7);
conf->bssid[1] = cpu_to_le32(reg);
rt2800_register_multiwrite(rt2x00dev, MAC_BSSID_DW0,
@@ -762,14 +1044,12 @@ void rt2800_config_ant(struct rt2x00_dev *rt2x00dev, struct antenna_setup *ant)
switch ((int)ant->tx) {
case 1:
rt2x00_set_field8(&r1, BBP1_TX_ANTENNA, 0);
- if (rt2x00_is_pci(rt2x00dev) || rt2x00_is_soc(rt2x00dev))
- rt2x00_set_field8(&r3, BBP3_RX_ANTENNA, 0);
break;
case 2:
rt2x00_set_field8(&r1, BBP1_TX_ANTENNA, 2);
break;
case 3:
- /* Do nothing */
+ rt2x00_set_field8(&r1, BBP1_TX_ANTENNA, 0);
break;
}
@@ -1016,66 +1296,115 @@ static void rt2800_config_channel(struct rt2x00_dev *rt2x00dev,
}
static void rt2800_config_txpower(struct rt2x00_dev *rt2x00dev,
- const int txpower)
+ const int max_txpower)
{
+ u8 txpower;
+ u8 max_value = (u8)max_txpower;
+ u16 eeprom;
+ int i;
u32 reg;
- u32 value = TXPOWER_G_TO_DEV(txpower);
u8 r1;
+ u32 offset;
+ /*
+ * set to normal tx power mode: +/- 0dBm
+ */
rt2800_bbp_read(rt2x00dev, 1, &r1);
- rt2x00_set_field8(&reg, BBP1_TX_POWER, 0);
+ rt2x00_set_field8(&r1, BBP1_TX_POWER, 0);
rt2800_bbp_write(rt2x00dev, 1, r1);
- rt2800_register_read(rt2x00dev, TX_PWR_CFG_0, &reg);
- rt2x00_set_field32(&reg, TX_PWR_CFG_0_1MBS, value);
- rt2x00_set_field32(&reg, TX_PWR_CFG_0_2MBS, value);
- rt2x00_set_field32(&reg, TX_PWR_CFG_0_55MBS, value);
- rt2x00_set_field32(&reg, TX_PWR_CFG_0_11MBS, value);
- rt2x00_set_field32(&reg, TX_PWR_CFG_0_6MBS, value);
- rt2x00_set_field32(&reg, TX_PWR_CFG_0_9MBS, value);
- rt2x00_set_field32(&reg, TX_PWR_CFG_0_12MBS, value);
- rt2x00_set_field32(&reg, TX_PWR_CFG_0_18MBS, value);
- rt2800_register_write(rt2x00dev, TX_PWR_CFG_0, reg);
-
- rt2800_register_read(rt2x00dev, TX_PWR_CFG_1, &reg);
- rt2x00_set_field32(&reg, TX_PWR_CFG_1_24MBS, value);
- rt2x00_set_field32(&reg, TX_PWR_CFG_1_36MBS, value);
- rt2x00_set_field32(&reg, TX_PWR_CFG_1_48MBS, value);
- rt2x00_set_field32(&reg, TX_PWR_CFG_1_54MBS, value);
- rt2x00_set_field32(&reg, TX_PWR_CFG_1_MCS0, value);
- rt2x00_set_field32(&reg, TX_PWR_CFG_1_MCS1, value);
- rt2x00_set_field32(&reg, TX_PWR_CFG_1_MCS2, value);
- rt2x00_set_field32(&reg, TX_PWR_CFG_1_MCS3, value);
- rt2800_register_write(rt2x00dev, TX_PWR_CFG_1, reg);
-
- rt2800_register_read(rt2x00dev, TX_PWR_CFG_2, &reg);
- rt2x00_set_field32(&reg, TX_PWR_CFG_2_MCS4, value);
- rt2x00_set_field32(&reg, TX_PWR_CFG_2_MCS5, value);
- rt2x00_set_field32(&reg, TX_PWR_CFG_2_MCS6, value);
- rt2x00_set_field32(&reg, TX_PWR_CFG_2_MCS7, value);
- rt2x00_set_field32(&reg, TX_PWR_CFG_2_MCS8, value);
- rt2x00_set_field32(&reg, TX_PWR_CFG_2_MCS9, value);
- rt2x00_set_field32(&reg, TX_PWR_CFG_2_MCS10, value);
- rt2x00_set_field32(&reg, TX_PWR_CFG_2_MCS11, value);
- rt2800_register_write(rt2x00dev, TX_PWR_CFG_2, reg);
-
- rt2800_register_read(rt2x00dev, TX_PWR_CFG_3, &reg);
- rt2x00_set_field32(&reg, TX_PWR_CFG_3_MCS12, value);
- rt2x00_set_field32(&reg, TX_PWR_CFG_3_MCS13, value);
- rt2x00_set_field32(&reg, TX_PWR_CFG_3_MCS14, value);
- rt2x00_set_field32(&reg, TX_PWR_CFG_3_MCS15, value);
- rt2x00_set_field32(&reg, TX_PWR_CFG_3_UKNOWN1, value);
- rt2x00_set_field32(&reg, TX_PWR_CFG_3_UKNOWN2, value);
- rt2x00_set_field32(&reg, TX_PWR_CFG_3_UKNOWN3, value);
- rt2x00_set_field32(&reg, TX_PWR_CFG_3_UKNOWN4, value);
- rt2800_register_write(rt2x00dev, TX_PWR_CFG_3, reg);
-
- rt2800_register_read(rt2x00dev, TX_PWR_CFG_4, &reg);
- rt2x00_set_field32(&reg, TX_PWR_CFG_4_UKNOWN5, value);
- rt2x00_set_field32(&reg, TX_PWR_CFG_4_UKNOWN6, value);
- rt2x00_set_field32(&reg, TX_PWR_CFG_4_UKNOWN7, value);
- rt2x00_set_field32(&reg, TX_PWR_CFG_4_UKNOWN8, value);
- rt2800_register_write(rt2x00dev, TX_PWR_CFG_4, reg);
+ /*
+ * The eeprom contains the tx power values for each rate. These
+ * values map to 100% tx power. Each 16bit word contains four tx
+ * power values and the order is the same as used in the TX_PWR_CFG
+ * registers.
+ */
+ offset = TX_PWR_CFG_0;
+
+ for (i = 0; i < EEPROM_TXPOWER_BYRATE_SIZE; i += 2) {
+ /* just to be safe */
+ if (offset > TX_PWR_CFG_4)
+ break;
+
+ rt2800_register_read(rt2x00dev, offset, &reg);
+
+ /* read the next four txpower values */
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_TXPOWER_BYRATE + i,
+ &eeprom);
+
+ /* TX_PWR_CFG_0: 1MBS, TX_PWR_CFG_1: 24MBS,
+ * TX_PWR_CFG_2: MCS4, TX_PWR_CFG_3: MCS12,
+ * TX_PWR_CFG_4: unknown */
+ txpower = rt2x00_get_field16(eeprom,
+ EEPROM_TXPOWER_BYRATE_RATE0);
+ rt2x00_set_field32(&reg, TX_PWR_CFG_RATE0,
+ min(txpower, max_value));
+
+ /* TX_PWR_CFG_0: 2MBS, TX_PWR_CFG_1: 36MBS,
+ * TX_PWR_CFG_2: MCS5, TX_PWR_CFG_3: MCS13,
+ * TX_PWR_CFG_4: unknown */
+ txpower = rt2x00_get_field16(eeprom,
+ EEPROM_TXPOWER_BYRATE_RATE1);
+ rt2x00_set_field32(&reg, TX_PWR_CFG_RATE1,
+ min(txpower, max_value));
+
+ /* TX_PWR_CFG_0: 55MBS, TX_PWR_CFG_1: 48MBS,
+ * TX_PWR_CFG_2: MCS6, TX_PWR_CFG_3: MCS14,
+ * TX_PWR_CFG_4: unknown */
+ txpower = rt2x00_get_field16(eeprom,
+ EEPROM_TXPOWER_BYRATE_RATE2);
+ rt2x00_set_field32(&reg, TX_PWR_CFG_RATE2,
+ min(txpower, max_value));
+
+ /* TX_PWR_CFG_0: 11MBS, TX_PWR_CFG_1: 54MBS,
+ * TX_PWR_CFG_2: MCS7, TX_PWR_CFG_3: MCS15,
+ * TX_PWR_CFG_4: unknown */
+ txpower = rt2x00_get_field16(eeprom,
+ EEPROM_TXPOWER_BYRATE_RATE3);
+ rt2x00_set_field32(&reg, TX_PWR_CFG_RATE3,
+ min(txpower, max_value));
+
+ /* read the next four txpower values */
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_TXPOWER_BYRATE + i + 1,
+ &eeprom);
+
+ /* TX_PWR_CFG_0: 6MBS, TX_PWR_CFG_1: MCS0,
+ * TX_PWR_CFG_2: MCS8, TX_PWR_CFG_3: unknown,
+ * TX_PWR_CFG_4: unknown */
+ txpower = rt2x00_get_field16(eeprom,
+ EEPROM_TXPOWER_BYRATE_RATE0);
+ rt2x00_set_field32(&reg, TX_PWR_CFG_RATE4,
+ min(txpower, max_value));
+
+ /* TX_PWR_CFG_0: 9MBS, TX_PWR_CFG_1: MCS1,
+ * TX_PWR_CFG_2: MCS9, TX_PWR_CFG_3: unknown,
+ * TX_PWR_CFG_4: unknown */
+ txpower = rt2x00_get_field16(eeprom,
+ EEPROM_TXPOWER_BYRATE_RATE1);
+ rt2x00_set_field32(&reg, TX_PWR_CFG_RATE5,
+ min(txpower, max_value));
+
+ /* TX_PWR_CFG_0: 12MBS, TX_PWR_CFG_1: MCS2,
+ * TX_PWR_CFG_2: MCS10, TX_PWR_CFG_3: unknown,
+ * TX_PWR_CFG_4: unknown */
+ txpower = rt2x00_get_field16(eeprom,
+ EEPROM_TXPOWER_BYRATE_RATE2);
+ rt2x00_set_field32(&reg, TX_PWR_CFG_RATE6,
+ min(txpower, max_value));
+
+ /* TX_PWR_CFG_0: 18MBS, TX_PWR_CFG_1: MCS3,
+ * TX_PWR_CFG_2: MCS11, TX_PWR_CFG_3: unknown,
+ * TX_PWR_CFG_4: unknown */
+ txpower = rt2x00_get_field16(eeprom,
+ EEPROM_TXPOWER_BYRATE_RATE3);
+ rt2x00_set_field32(&reg, TX_PWR_CFG_RATE7,
+ min(txpower, max_value));
+
+ rt2800_register_write(rt2x00dev, offset, reg);
+
+ /* next TX_PWR_CFG register */
+ offset += 4;
+ }
}
static void rt2800_config_retry_limit(struct rt2x00_dev *rt2x00dev,
@@ -1212,6 +1541,7 @@ int rt2800_init_registers(struct rt2x00_dev *rt2x00dev)
u32 reg;
u16 eeprom;
unsigned int i;
+ int ret;
rt2800_register_read(rt2x00dev, WPDMA_GLO_CFG, &reg);
rt2x00_set_field32(&reg, WPDMA_GLO_CFG_ENABLE_TX_DMA, 0);
@@ -1221,59 +1551,9 @@ int rt2800_init_registers(struct rt2x00_dev *rt2x00dev)
rt2x00_set_field32(&reg, WPDMA_GLO_CFG_TX_WRITEBACK_DONE, 1);
rt2800_register_write(rt2x00dev, WPDMA_GLO_CFG, reg);
- if (rt2x00_is_usb(rt2x00dev)) {
- /*
- * Wait until BBP and RF are ready.
- */
- for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
- rt2800_register_read(rt2x00dev, MAC_CSR0, &reg);
- if (reg && reg != ~0)
- break;
- msleep(1);
- }
-
- if (i == REGISTER_BUSY_COUNT) {
- ERROR(rt2x00dev, "Unstable hardware.\n");
- return -EBUSY;
- }
-
- rt2800_register_read(rt2x00dev, PBF_SYS_CTRL, &reg);
- rt2800_register_write(rt2x00dev, PBF_SYS_CTRL,
- reg & ~0x00002000);
- } else if (rt2x00_is_pci(rt2x00dev) || rt2x00_is_soc(rt2x00dev)) {
- /*
- * Reset DMA indexes
- */
- rt2800_register_read(rt2x00dev, WPDMA_RST_IDX, &reg);
- rt2x00_set_field32(&reg, WPDMA_RST_IDX_DTX_IDX0, 1);
- rt2x00_set_field32(&reg, WPDMA_RST_IDX_DTX_IDX1, 1);
- rt2x00_set_field32(&reg, WPDMA_RST_IDX_DTX_IDX2, 1);
- rt2x00_set_field32(&reg, WPDMA_RST_IDX_DTX_IDX3, 1);
- rt2x00_set_field32(&reg, WPDMA_RST_IDX_DTX_IDX4, 1);
- rt2x00_set_field32(&reg, WPDMA_RST_IDX_DTX_IDX5, 1);
- rt2x00_set_field32(&reg, WPDMA_RST_IDX_DRX_IDX0, 1);
- rt2800_register_write(rt2x00dev, WPDMA_RST_IDX, reg);
-
- rt2800_register_write(rt2x00dev, PBF_SYS_CTRL, 0x00000e1f);
- rt2800_register_write(rt2x00dev, PBF_SYS_CTRL, 0x00000e00);
-
- rt2800_register_write(rt2x00dev, PWR_PIN_CFG, 0x00000003);
- }
-
- rt2800_register_read(rt2x00dev, MAC_SYS_CTRL, &reg);
- rt2x00_set_field32(&reg, MAC_SYS_CTRL_RESET_CSR, 1);
- rt2x00_set_field32(&reg, MAC_SYS_CTRL_RESET_BBP, 1);
- rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, reg);
-
- if (rt2x00_is_usb(rt2x00dev)) {
- rt2800_register_write(rt2x00dev, USB_DMA_CFG, 0x00000000);
-#if defined(CONFIG_RT2X00_LIB_USB) || defined(CONFIG_RT2X00_LIB_USB_MODULE)
- rt2x00usb_vendor_request_sw(rt2x00dev, USB_DEVICE_MODE, 0,
- USB_MODE_RESET, REGISTER_TIMEOUT);
-#endif
- }
-
- rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, 0x00000000);
+ ret = rt2800_drv_init_registers(rt2x00dev);
+ if (ret)
+ return ret;
rt2800_register_read(rt2x00dev, BCN_OFFSET0, &reg);
rt2x00_set_field32(&reg, BCN_OFFSET0_BCN0, 0xe0); /* 0x3800 */
@@ -1295,7 +1575,7 @@ int rt2800_init_registers(struct rt2x00_dev *rt2x00dev)
rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, 0x00000000);
rt2800_register_read(rt2x00dev, BCN_TIME_CFG, &reg);
- rt2x00_set_field32(&reg, BCN_TIME_CFG_BEACON_INTERVAL, 0);
+ rt2x00_set_field32(&reg, BCN_TIME_CFG_BEACON_INTERVAL, 1600);
rt2x00_set_field32(&reg, BCN_TIME_CFG_TSF_TICKING, 0);
rt2x00_set_field32(&reg, BCN_TIME_CFG_TSF_SYNC, 0);
rt2x00_set_field32(&reg, BCN_TIME_CFG_TBTT_ENABLE, 0);
@@ -1328,7 +1608,6 @@ int rt2800_init_registers(struct rt2x00_dev *rt2x00dev)
} else {
rt2800_register_write(rt2x00dev, TX_SW_CFG2, 0x00000000);
}
- rt2800_register_write(rt2x00dev, TX_SW_CFG2, reg);
} else if (rt2x00_rt(rt2x00dev, RT3070)) {
rt2800_register_write(rt2x00dev, TX_SW_CFG0, 0x00000400);
@@ -1339,6 +1618,10 @@ int rt2800_init_registers(struct rt2x00_dev *rt2x00dev)
rt2800_register_write(rt2x00dev, TX_SW_CFG1, 0x00080606);
rt2800_register_write(rt2x00dev, TX_SW_CFG2, 0x00000000);
}
+ } else if (rt2800_is_305x_soc(rt2x00dev)) {
+ rt2800_register_write(rt2x00dev, TX_SW_CFG0, 0x00000400);
+ rt2800_register_write(rt2x00dev, TX_SW_CFG1, 0x00000000);
+ rt2800_register_write(rt2x00dev, TX_SW_CFG2, 0x0000001f);
} else {
rt2800_register_write(rt2x00dev, TX_SW_CFG0, 0x00000000);
rt2800_register_write(rt2x00dev, TX_SW_CFG1, 0x00080606);
@@ -1546,23 +1829,20 @@ int rt2800_init_registers(struct rt2x00_dev *rt2x00dev)
/*
* Clear all beacons
- * For the Beacon base registers we only need to clear
- * the first byte since that byte contains the VALID and OWNER
- * bits which (when set to 0) will invalidate the entire beacon.
- */
- rt2800_register_write(rt2x00dev, HW_BEACON_BASE0, 0);
- rt2800_register_write(rt2x00dev, HW_BEACON_BASE1, 0);
- rt2800_register_write(rt2x00dev, HW_BEACON_BASE2, 0);
- rt2800_register_write(rt2x00dev, HW_BEACON_BASE3, 0);
- rt2800_register_write(rt2x00dev, HW_BEACON_BASE4, 0);
- rt2800_register_write(rt2x00dev, HW_BEACON_BASE5, 0);
- rt2800_register_write(rt2x00dev, HW_BEACON_BASE6, 0);
- rt2800_register_write(rt2x00dev, HW_BEACON_BASE7, 0);
+ */
+ rt2800_clear_beacon(rt2x00dev, HW_BEACON_BASE0);
+ rt2800_clear_beacon(rt2x00dev, HW_BEACON_BASE1);
+ rt2800_clear_beacon(rt2x00dev, HW_BEACON_BASE2);
+ rt2800_clear_beacon(rt2x00dev, HW_BEACON_BASE3);
+ rt2800_clear_beacon(rt2x00dev, HW_BEACON_BASE4);
+ rt2800_clear_beacon(rt2x00dev, HW_BEACON_BASE5);
+ rt2800_clear_beacon(rt2x00dev, HW_BEACON_BASE6);
+ rt2800_clear_beacon(rt2x00dev, HW_BEACON_BASE7);
if (rt2x00_is_usb(rt2x00dev)) {
- rt2800_register_read(rt2x00dev, USB_CYC_CFG, &reg);
- rt2x00_set_field32(&reg, USB_CYC_CFG_CLOCK_CYCLE, 30);
- rt2800_register_write(rt2x00dev, USB_CYC_CFG, reg);
+ rt2800_register_read(rt2x00dev, US_CYC_CNT, &reg);
+ rt2x00_set_field32(&reg, US_CYC_CNT_CLOCK_CYCLE, 30);
+ rt2800_register_write(rt2x00dev, US_CYC_CNT, reg);
}
rt2800_register_read(rt2x00dev, HT_FBK_CFG0, &reg);
@@ -1617,6 +1897,13 @@ int rt2800_init_registers(struct rt2x00_dev *rt2x00dev)
rt2800_register_read(rt2x00dev, TX_STA_CNT1, &reg);
rt2800_register_read(rt2x00dev, TX_STA_CNT2, &reg);
+ /*
+ * Setup leadtime for pre tbtt interrupt to 6ms
+ */
+ rt2800_register_read(rt2x00dev, INT_TIMER_CFG, &reg);
+ rt2x00_set_field32(&reg, INT_TIMER_CFG_PRE_TBTT_TIMER, 6 << 4);
+ rt2800_register_write(rt2x00dev, INT_TIMER_CFG, reg);
+
return 0;
}
EXPORT_SYMBOL_GPL(rt2800_init_registers);
@@ -1706,8 +1993,7 @@ int rt2800_init_bbp(struct rt2x00_dev *rt2x00dev)
rt2800_bbp_write(rt2x00dev, 82, 0x62);
rt2800_bbp_write(rt2x00dev, 83, 0x6a);
- if (rt2x00_rt_rev(rt2x00dev, RT2860, REV_RT2860D) ||
- rt2x00_rt_rev(rt2x00dev, RT2870, REV_RT2870D))
+ if (rt2x00_rt_rev(rt2x00dev, RT2860, REV_RT2860D))
rt2800_bbp_write(rt2x00dev, 84, 0x19);
else
rt2800_bbp_write(rt2x00dev, 84, 0x99);
@@ -2013,8 +2299,7 @@ int rt2800_init_rfcsr(struct rt2x00_dev *rt2x00dev)
if (rt2x00_rt_rev_lt(rt2x00dev, RT3071, REV_RT3071E) ||
rt2x00_rt_rev_lt(rt2x00dev, RT3090, REV_RT3090E) ||
rt2x00_rt_rev_lt(rt2x00dev, RT3390, REV_RT3390E)) {
- rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC, &eeprom);
- if (rt2x00_get_field16(eeprom, EEPROM_NIC_EXTERNAL_LNA_BG))
+ if (test_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags))
rt2x00_set_field8(&rfcsr, RFCSR17_R, 1);
}
rt2x00_eeprom_read(rt2x00dev, EEPROM_TXMIXER_GAIN_BG, &eeprom);
@@ -2147,7 +2432,6 @@ int rt2800_validate_eeprom(struct rt2x00_dev *rt2x00dev)
rt2x00_eeprom_write(rt2x00dev, EEPROM_ANTENNA, word);
EEPROM(rt2x00dev, "Antenna: 0x%04x\n", word);
} else if (rt2x00_rt(rt2x00dev, RT2860) ||
- rt2x00_rt(rt2x00dev, RT2870) ||
rt2x00_rt(rt2x00dev, RT2872)) {
/*
* There is a max of 2 RX streams for RT28x0 series
@@ -2169,6 +2453,8 @@ int rt2800_validate_eeprom(struct rt2x00_dev *rt2x00dev)
rt2x00_set_field16(&word, EEPROM_NIC_WPS_PBC, 0);
rt2x00_set_field16(&word, EEPROM_NIC_BW40M_BG, 0);
rt2x00_set_field16(&word, EEPROM_NIC_BW40M_A, 0);
+ rt2x00_set_field16(&word, EEPROM_NIC_ANT_DIVERSITY, 0);
+ rt2x00_set_field16(&word, EEPROM_NIC_DAC_TEST, 0);
rt2x00_eeprom_write(rt2x00dev, EEPROM_NIC, word);
EEPROM(rt2x00dev, "NIC: 0x%04x\n", word);
}
@@ -2176,6 +2462,10 @@ int rt2800_validate_eeprom(struct rt2x00_dev *rt2x00dev)
rt2x00_eeprom_read(rt2x00dev, EEPROM_FREQ, &word);
if ((word & 0x00ff) == 0x00ff) {
rt2x00_set_field16(&word, EEPROM_FREQ_OFFSET, 0);
+ rt2x00_eeprom_write(rt2x00dev, EEPROM_FREQ, word);
+ EEPROM(rt2x00dev, "Freq: 0x%04x\n", word);
+ }
+ if ((word & 0xff00) == 0xff00) {
rt2x00_set_field16(&word, EEPROM_FREQ_LED_MODE,
LED_MODE_TXRX_ACTIVITY);
rt2x00_set_field16(&word, EEPROM_FREQ_LED_POLARITY, 0);
@@ -2183,7 +2473,7 @@ int rt2800_validate_eeprom(struct rt2x00_dev *rt2x00dev)
rt2x00_eeprom_write(rt2x00dev, EEPROM_LED1, 0x5555);
rt2x00_eeprom_write(rt2x00dev, EEPROM_LED2, 0x2221);
rt2x00_eeprom_write(rt2x00dev, EEPROM_LED3, 0xa9f8);
- EEPROM(rt2x00dev, "Freq: 0x%04x\n", word);
+ EEPROM(rt2x00dev, "Led Mode: 0x%04x\n", word);
}
/*
@@ -2251,7 +2541,6 @@ int rt2800_init_eeprom(struct rt2x00_dev *rt2x00dev)
value, rt2x00_get_field32(reg, MAC_CSR0_REVISION));
if (!rt2x00_rt(rt2x00dev, RT2860) &&
- !rt2x00_rt(rt2x00dev, RT2870) &&
!rt2x00_rt(rt2x00dev, RT2872) &&
!rt2x00_rt(rt2x00dev, RT2883) &&
!rt2x00_rt(rt2x00dev, RT3070) &&
@@ -2484,13 +2773,26 @@ int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
IEEE80211_HW_SIGNAL_DBM |
IEEE80211_HW_SUPPORTS_PS |
- IEEE80211_HW_PS_NULLFUNC_STACK;
+ IEEE80211_HW_PS_NULLFUNC_STACK |
+ IEEE80211_HW_AMPDU_AGGREGATION;
SET_IEEE80211_DEV(rt2x00dev->hw, rt2x00dev->dev);
SET_IEEE80211_PERM_ADDR(rt2x00dev->hw,
rt2x00_eeprom_addr(rt2x00dev,
EEPROM_MAC_ADDR_0));
+ /*
+ * As rt2800 has a global fallback table we cannot specify
+ * more then one tx rate per frame but since the hw will
+ * try several rates (based on the fallback table) we should
+ * still initialize max_rates to the maximum number of rates
+ * we are going to try. Otherwise mac80211 will truncate our
+ * reported tx rates and the rc algortihm will end up with
+ * incorrect data.
+ */
+ rt2x00dev->hw->max_rates = 7;
+ rt2x00dev->hw->max_rate_tries = 1;
+
rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &eeprom);
/*
@@ -2528,16 +2830,19 @@ int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
else
spec->ht.ht_supported = false;
- /*
- * Don't set IEEE80211_HT_CAP_SUP_WIDTH_20_40 for now as it causes
- * reception problems with HT40 capable 11n APs
- */
spec->ht.cap =
+ IEEE80211_HT_CAP_SUP_WIDTH_20_40 |
IEEE80211_HT_CAP_GRN_FLD |
IEEE80211_HT_CAP_SGI_20 |
- IEEE80211_HT_CAP_SGI_40 |
- IEEE80211_HT_CAP_TX_STBC |
- IEEE80211_HT_CAP_RX_STBC;
+ IEEE80211_HT_CAP_SGI_40;
+
+ if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_TXPATH) >= 2)
+ spec->ht.cap |= IEEE80211_HT_CAP_TX_STBC;
+
+ spec->ht.cap |=
+ rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RXPATH) <<
+ IEEE80211_HT_CAP_RX_STBC_SHIFT;
+
spec->ht.ampdu_factor = 3;
spec->ht.ampdu_density = 4;
spec->ht.mcs.tx_params =
@@ -2591,8 +2896,8 @@ EXPORT_SYMBOL_GPL(rt2800_probe_hw_mode);
/*
* IEEE80211 stack callback functions.
*/
-static void rt2800_get_tkip_seq(struct ieee80211_hw *hw, u8 hw_key_idx,
- u32 *iv32, u16 *iv16)
+void rt2800_get_tkip_seq(struct ieee80211_hw *hw, u8 hw_key_idx, u32 *iv32,
+ u16 *iv16)
{
struct rt2x00_dev *rt2x00dev = hw->priv;
struct mac_iveiv_entry iveiv_entry;
@@ -2605,8 +2910,9 @@ static void rt2800_get_tkip_seq(struct ieee80211_hw *hw, u8 hw_key_idx,
memcpy(iv16, &iveiv_entry.iv[0], sizeof(*iv16));
memcpy(iv32, &iveiv_entry.iv[4], sizeof(*iv32));
}
+EXPORT_SYMBOL_GPL(rt2800_get_tkip_seq);
-static int rt2800_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
+int rt2800_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
{
struct rt2x00_dev *rt2x00dev = hw->priv;
u32 reg;
@@ -2642,9 +2948,10 @@ static int rt2800_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
return 0;
}
+EXPORT_SYMBOL_GPL(rt2800_set_rts_threshold);
-static int rt2800_conf_tx(struct ieee80211_hw *hw, u16 queue_idx,
- const struct ieee80211_tx_queue_params *params)
+int rt2800_conf_tx(struct ieee80211_hw *hw, u16 queue_idx,
+ const struct ieee80211_tx_queue_params *params)
{
struct rt2x00_dev *rt2x00dev = hw->priv;
struct data_queue *queue;
@@ -2709,8 +3016,9 @@ static int rt2800_conf_tx(struct ieee80211_hw *hw, u16 queue_idx,
return 0;
}
+EXPORT_SYMBOL_GPL(rt2800_conf_tx);
-static u64 rt2800_get_tsf(struct ieee80211_hw *hw)
+u64 rt2800_get_tsf(struct ieee80211_hw *hw)
{
struct rt2x00_dev *rt2x00dev = hw->priv;
u64 tsf;
@@ -2723,23 +3031,37 @@ static u64 rt2800_get_tsf(struct ieee80211_hw *hw)
return tsf;
}
+EXPORT_SYMBOL_GPL(rt2800_get_tsf);
-const struct ieee80211_ops rt2800_mac80211_ops = {
- .tx = rt2x00mac_tx,
- .start = rt2x00mac_start,
- .stop = rt2x00mac_stop,
- .add_interface = rt2x00mac_add_interface,
- .remove_interface = rt2x00mac_remove_interface,
- .config = rt2x00mac_config,
- .configure_filter = rt2x00mac_configure_filter,
- .set_tim = rt2x00mac_set_tim,
- .set_key = rt2x00mac_set_key,
- .get_stats = rt2x00mac_get_stats,
- .get_tkip_seq = rt2800_get_tkip_seq,
- .set_rts_threshold = rt2800_set_rts_threshold,
- .bss_info_changed = rt2x00mac_bss_info_changed,
- .conf_tx = rt2800_conf_tx,
- .get_tsf = rt2800_get_tsf,
- .rfkill_poll = rt2x00mac_rfkill_poll,
-};
-EXPORT_SYMBOL_GPL(rt2800_mac80211_ops);
+int rt2800_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+ enum ieee80211_ampdu_mlme_action action,
+ struct ieee80211_sta *sta, u16 tid, u16 *ssn)
+{
+ int ret = 0;
+
+ switch (action) {
+ case IEEE80211_AMPDU_RX_START:
+ case IEEE80211_AMPDU_RX_STOP:
+ /* we don't support RX aggregation yet */
+ ret = -ENOTSUPP;
+ break;
+ case IEEE80211_AMPDU_TX_START:
+ ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid);
+ break;
+ case IEEE80211_AMPDU_TX_STOP:
+ ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
+ break;
+ case IEEE80211_AMPDU_TX_OPERATIONAL:
+ break;
+ default:
+ WARNING((struct rt2x00_dev *)hw->priv, "Unknown AMPDU action\n");
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(rt2800_ampdu_action);
+
+MODULE_AUTHOR(DRV_PROJECT ", Bartlomiej Zolnierkiewicz");
+MODULE_VERSION(DRV_VERSION);
+MODULE_DESCRIPTION("Ralink RT2800 library");
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/wireless/rt2x00/rt2800lib.h b/drivers/net/wireless/rt2x00/rt2800lib.h
index 94de999e229..091641e3c5e 100644
--- a/drivers/net/wireless/rt2x00/rt2800lib.h
+++ b/drivers/net/wireless/rt2x00/rt2800lib.h
@@ -40,13 +40,17 @@ struct rt2800_ops {
int (*regbusy_read)(struct rt2x00_dev *rt2x00dev,
const unsigned int offset,
const struct rt2x00_field32 field, u32 *reg);
+
+ int (*drv_write_firmware)(struct rt2x00_dev *rt2x00dev,
+ const u8 *data, const size_t len);
+ int (*drv_init_registers)(struct rt2x00_dev *rt2x00dev);
};
static inline void rt2800_register_read(struct rt2x00_dev *rt2x00dev,
const unsigned int offset,
u32 *value)
{
- const struct rt2800_ops *rt2800ops = rt2x00dev->priv;
+ const struct rt2800_ops *rt2800ops = rt2x00dev->ops->drv;
rt2800ops->register_read(rt2x00dev, offset, value);
}
@@ -55,7 +59,7 @@ static inline void rt2800_register_read_lock(struct rt2x00_dev *rt2x00dev,
const unsigned int offset,
u32 *value)
{
- const struct rt2800_ops *rt2800ops = rt2x00dev->priv;
+ const struct rt2800_ops *rt2800ops = rt2x00dev->ops->drv;
rt2800ops->register_read_lock(rt2x00dev, offset, value);
}
@@ -64,7 +68,7 @@ static inline void rt2800_register_write(struct rt2x00_dev *rt2x00dev,
const unsigned int offset,
u32 value)
{
- const struct rt2800_ops *rt2800ops = rt2x00dev->priv;
+ const struct rt2800_ops *rt2800ops = rt2x00dev->ops->drv;
rt2800ops->register_write(rt2x00dev, offset, value);
}
@@ -73,7 +77,7 @@ static inline void rt2800_register_write_lock(struct rt2x00_dev *rt2x00dev,
const unsigned int offset,
u32 value)
{
- const struct rt2800_ops *rt2800ops = rt2x00dev->priv;
+ const struct rt2800_ops *rt2800ops = rt2x00dev->ops->drv;
rt2800ops->register_write_lock(rt2x00dev, offset, value);
}
@@ -82,7 +86,7 @@ static inline void rt2800_register_multiread(struct rt2x00_dev *rt2x00dev,
const unsigned int offset,
void *value, const u32 length)
{
- const struct rt2800_ops *rt2800ops = rt2x00dev->priv;
+ const struct rt2800_ops *rt2800ops = rt2x00dev->ops->drv;
rt2800ops->register_multiread(rt2x00dev, offset, value, length);
}
@@ -92,7 +96,7 @@ static inline void rt2800_register_multiwrite(struct rt2x00_dev *rt2x00dev,
const void *value,
const u32 length)
{
- const struct rt2800_ops *rt2800ops = rt2x00dev->priv;
+ const struct rt2800_ops *rt2800ops = rt2x00dev->ops->drv;
rt2800ops->register_multiwrite(rt2x00dev, offset, value, length);
}
@@ -102,17 +106,39 @@ static inline int rt2800_regbusy_read(struct rt2x00_dev *rt2x00dev,
const struct rt2x00_field32 field,
u32 *reg)
{
- const struct rt2800_ops *rt2800ops = rt2x00dev->priv;
+ const struct rt2800_ops *rt2800ops = rt2x00dev->ops->drv;
return rt2800ops->regbusy_read(rt2x00dev, offset, field, reg);
}
+static inline int rt2800_drv_write_firmware(struct rt2x00_dev *rt2x00dev,
+ const u8 *data, const size_t len)
+{
+ const struct rt2800_ops *rt2800ops = rt2x00dev->ops->drv;
+
+ return rt2800ops->drv_write_firmware(rt2x00dev, data, len);
+}
+
+static inline int rt2800_drv_init_registers(struct rt2x00_dev *rt2x00dev)
+{
+ const struct rt2800_ops *rt2800ops = rt2x00dev->ops->drv;
+
+ return rt2800ops->drv_init_registers(rt2x00dev);
+}
+
void rt2800_mcu_request(struct rt2x00_dev *rt2x00dev,
const u8 command, const u8 token,
const u8 arg0, const u8 arg1);
-void rt2800_write_txwi(struct sk_buff *skb, struct txentry_desc *txdesc);
-void rt2800_process_rxwi(struct sk_buff *skb, struct rxdone_entry_desc *txdesc);
+int rt2800_check_firmware(struct rt2x00_dev *rt2x00dev,
+ const u8 *data, const size_t len);
+int rt2800_load_firmware(struct rt2x00_dev *rt2x00dev,
+ const u8 *data, const size_t len);
+
+void rt2800_write_txwi(__le32 *txwi, struct txentry_desc *txdesc);
+void rt2800_process_rxwi(struct queue_entry *entry, struct rxdone_entry_desc *txdesc);
+
+void rt2800_write_beacon(struct queue_entry *entry, struct txentry_desc *txdesc);
extern const struct rt2x00debug rt2800_rt2x00debug;
@@ -148,6 +174,14 @@ int rt2800_validate_eeprom(struct rt2x00_dev *rt2x00dev);
int rt2800_init_eeprom(struct rt2x00_dev *rt2x00dev);
int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev);
-extern const struct ieee80211_ops rt2800_mac80211_ops;
+void rt2800_get_tkip_seq(struct ieee80211_hw *hw, u8 hw_key_idx, u32 *iv32,
+ u16 *iv16);
+int rt2800_set_rts_threshold(struct ieee80211_hw *hw, u32 value);
+int rt2800_conf_tx(struct ieee80211_hw *hw, u16 queue_idx,
+ const struct ieee80211_tx_queue_params *params);
+u64 rt2800_get_tsf(struct ieee80211_hw *hw);
+int rt2800_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+ enum ieee80211_ampdu_mlme_action action,
+ struct ieee80211_sta *sta, u16 tid, u16 *ssn);
#endif /* RT2800LIB_H */
diff --git a/drivers/net/wireless/rt2x00/rt2800pci.c b/drivers/net/wireless/rt2x00/rt2800pci.c
index b2f23272c3a..39b3846fa34 100644
--- a/drivers/net/wireless/rt2x00/rt2800pci.c
+++ b/drivers/net/wireless/rt2x00/rt2800pci.c
@@ -31,7 +31,6 @@
Supported chipsets: RT2800E & RT2800ED.
*/
-#include <linux/crc-ccitt.h>
#include <linux/delay.h>
#include <linux/etherdevice.h>
#include <linux/init.h>
@@ -51,7 +50,7 @@
/*
* Allow hardware encryption to be disabled.
*/
-static int modparam_nohwcrypt = 1;
+static int modparam_nohwcrypt = 0;
module_param_named(nohwcrypt, modparam_nohwcrypt, bool, S_IRUGO);
MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption.");
@@ -139,8 +138,18 @@ static void rt2800pci_read_eeprom_pci(struct rt2x00_dev *rt2x00dev)
eeprom.data = rt2x00dev;
eeprom.register_read = rt2800pci_eepromregister_read;
eeprom.register_write = rt2800pci_eepromregister_write;
- eeprom.width = !rt2x00_get_field32(reg, E2PROM_CSR_TYPE) ?
- PCI_EEPROM_WIDTH_93C46 : PCI_EEPROM_WIDTH_93C66;
+ switch (rt2x00_get_field32(reg, E2PROM_CSR_TYPE))
+ {
+ case 0:
+ eeprom.width = PCI_EEPROM_WIDTH_93C46;
+ break;
+ case 1:
+ eeprom.width = PCI_EEPROM_WIDTH_93C66;
+ break;
+ default:
+ eeprom.width = PCI_EEPROM_WIDTH_93C86;
+ break;
+ }
eeprom.reg_data_in = 0;
eeprom.reg_data_out = 0;
eeprom.reg_data_clock = 0;
@@ -182,82 +191,14 @@ static char *rt2800pci_get_firmware_name(struct rt2x00_dev *rt2x00dev)
return FIRMWARE_RT2860;
}
-static int rt2800pci_check_firmware(struct rt2x00_dev *rt2x00dev,
+static int rt2800pci_write_firmware(struct rt2x00_dev *rt2x00dev,
const u8 *data, const size_t len)
{
- u16 fw_crc;
- u16 crc;
-
- /*
- * Only support 8kb firmware files.
- */
- if (len != 8192)
- return FW_BAD_LENGTH;
-
- /*
- * The last 2 bytes in the firmware array are the crc checksum itself,
- * this means that we should never pass those 2 bytes to the crc
- * algorithm.
- */
- fw_crc = (data[len - 2] << 8 | data[len - 1]);
-
- /*
- * Use the crc ccitt algorithm.
- * This will return the same value as the legacy driver which
- * used bit ordering reversion on the both the firmware bytes
- * before input input as well as on the final output.
- * Obviously using crc ccitt directly is much more efficient.
- */
- crc = crc_ccitt(~0, data, len - 2);
-
- /*
- * There is a small difference between the crc-itu-t + bitrev and
- * the crc-ccitt crc calculation. In the latter method the 2 bytes
- * will be swapped, use swab16 to convert the crc to the correct
- * value.
- */
- crc = swab16(crc);
-
- return (fw_crc == crc) ? FW_OK : FW_BAD_CRC;
-}
-
-static int rt2800pci_load_firmware(struct rt2x00_dev *rt2x00dev,
- const u8 *data, const size_t len)
-{
- unsigned int i;
u32 reg;
- /*
- * Wait for stable hardware.
- */
- for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
- rt2800_register_read(rt2x00dev, MAC_CSR0, &reg);
- if (reg && reg != ~0)
- break;
- msleep(1);
- }
-
- if (i == REGISTER_BUSY_COUNT) {
- ERROR(rt2x00dev, "Unstable hardware.\n");
- return -EBUSY;
- }
-
- rt2800_register_write(rt2x00dev, PWR_PIN_CFG, 0x00000002);
rt2800_register_write(rt2x00dev, AUTOWAKEUP_CFG, 0x00000000);
/*
- * Disable DMA, will be reenabled later when enabling
- * the radio.
- */
- rt2800_register_read(rt2x00dev, WPDMA_GLO_CFG, &reg);
- rt2x00_set_field32(&reg, WPDMA_GLO_CFG_ENABLE_TX_DMA, 0);
- rt2x00_set_field32(&reg, WPDMA_GLO_CFG_TX_DMA_BUSY, 0);
- rt2x00_set_field32(&reg, WPDMA_GLO_CFG_ENABLE_RX_DMA, 0);
- rt2x00_set_field32(&reg, WPDMA_GLO_CFG_RX_DMA_BUSY, 0);
- rt2x00_set_field32(&reg, WPDMA_GLO_CFG_TX_WRITEBACK_DONE, 1);
- rt2800_register_write(rt2x00dev, WPDMA_GLO_CFG, reg);
-
- /*
* enable Host program ram write selection
*/
reg = 0;
@@ -268,34 +209,11 @@ static int rt2800pci_load_firmware(struct rt2x00_dev *rt2x00dev,
* Write firmware to device.
*/
rt2800_register_multiwrite(rt2x00dev, FIRMWARE_IMAGE_BASE,
- data, len);
+ data, len);
rt2800_register_write(rt2x00dev, PBF_SYS_CTRL, 0x00000);
rt2800_register_write(rt2x00dev, PBF_SYS_CTRL, 0x00001);
- /*
- * Wait for device to stabilize.
- */
- for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
- rt2800_register_read(rt2x00dev, PBF_SYS_CTRL, &reg);
- if (rt2x00_get_field32(reg, PBF_SYS_CTRL_READY))
- break;
- msleep(1);
- }
-
- if (i == REGISTER_BUSY_COUNT) {
- ERROR(rt2x00dev, "PBF system register not ready.\n");
- return -EBUSY;
- }
-
- /*
- * Disable interrupts
- */
- rt2x00dev->ops->lib->set_device_state(rt2x00dev, STATE_RADIO_IRQ_OFF);
-
- /*
- * Initialize BBP R/W access agent
- */
rt2800_register_write(rt2x00dev, H2M_BBP_AGENT, 0);
rt2800_register_write(rt2x00dev, H2M_MAILBOX_CSR, 0);
@@ -412,7 +330,8 @@ static void rt2800pci_toggle_rx(struct rt2x00_dev *rt2x00dev,
static void rt2800pci_toggle_irq(struct rt2x00_dev *rt2x00dev,
enum dev_state state)
{
- int mask = (state == STATE_RADIO_IRQ_ON);
+ int mask = (state == STATE_RADIO_IRQ_ON) ||
+ (state == STATE_RADIO_IRQ_ON_ISR);
u32 reg;
/*
@@ -446,6 +365,38 @@ static void rt2800pci_toggle_irq(struct rt2x00_dev *rt2x00dev,
rt2800_register_write(rt2x00dev, INT_MASK_CSR, reg);
}
+static int rt2800pci_init_registers(struct rt2x00_dev *rt2x00dev)
+{
+ u32 reg;
+
+ /*
+ * Reset DMA indexes
+ */
+ rt2800_register_read(rt2x00dev, WPDMA_RST_IDX, &reg);
+ rt2x00_set_field32(&reg, WPDMA_RST_IDX_DTX_IDX0, 1);
+ rt2x00_set_field32(&reg, WPDMA_RST_IDX_DTX_IDX1, 1);
+ rt2x00_set_field32(&reg, WPDMA_RST_IDX_DTX_IDX2, 1);
+ rt2x00_set_field32(&reg, WPDMA_RST_IDX_DTX_IDX3, 1);
+ rt2x00_set_field32(&reg, WPDMA_RST_IDX_DTX_IDX4, 1);
+ rt2x00_set_field32(&reg, WPDMA_RST_IDX_DTX_IDX5, 1);
+ rt2x00_set_field32(&reg, WPDMA_RST_IDX_DRX_IDX0, 1);
+ rt2800_register_write(rt2x00dev, WPDMA_RST_IDX, reg);
+
+ rt2800_register_write(rt2x00dev, PBF_SYS_CTRL, 0x00000e1f);
+ rt2800_register_write(rt2x00dev, PBF_SYS_CTRL, 0x00000e00);
+
+ rt2800_register_write(rt2x00dev, PWR_PIN_CFG, 0x00000003);
+
+ rt2800_register_read(rt2x00dev, MAC_SYS_CTRL, &reg);
+ rt2x00_set_field32(&reg, MAC_SYS_CTRL_RESET_CSR, 1);
+ rt2x00_set_field32(&reg, MAC_SYS_CTRL_RESET_BBP, 1);
+ rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, reg);
+
+ rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, 0x00000000);
+
+ return 0;
+}
+
static int rt2800pci_enable_radio(struct rt2x00_dev *rt2x00dev)
{
u32 reg;
@@ -465,7 +416,7 @@ static int rt2800pci_enable_radio(struct rt2x00_dev *rt2x00dev)
/*
* Send signal to firmware during boot time.
*/
- rt2800_mcu_request(rt2x00dev, MCU_BOOT_SIGNAL, 0xff, 0, 0);
+ rt2800_mcu_request(rt2x00dev, MCU_BOOT_SIGNAL, 0, 0, 0);
/*
* Enable RX.
@@ -589,7 +540,9 @@ static int rt2800pci_set_device_state(struct rt2x00_dev *rt2x00dev,
rt2800pci_toggle_rx(rt2x00dev, state);
break;
case STATE_RADIO_IRQ_ON:
+ case STATE_RADIO_IRQ_ON_ISR:
case STATE_RADIO_IRQ_OFF:
+ case STATE_RADIO_IRQ_OFF_ISR:
rt2800pci_toggle_irq(rt2x00dev, state);
break;
case STATE_DEEP_SLEEP:
@@ -613,18 +566,12 @@ static int rt2800pci_set_device_state(struct rt2x00_dev *rt2x00dev,
/*
* TX descriptor initialization
*/
-static int rt2800pci_write_tx_data(struct queue_entry* entry,
- struct txentry_desc *txdesc)
+static void rt2800pci_write_tx_data(struct queue_entry* entry,
+ struct txentry_desc *txdesc)
{
- int ret;
-
- ret = rt2x00pci_write_tx_data(entry, txdesc);
- if (ret)
- return ret;
+ __le32 *txwi = (__le32 *) entry->skb->data;
- rt2800_write_txwi(entry->skb, txdesc);
-
- return 0;
+ rt2800_write_txwi(txwi, txdesc);
}
@@ -684,49 +631,6 @@ static void rt2800pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
/*
* TX data initialization
*/
-static void rt2800pci_write_beacon(struct queue_entry *entry,
- struct txentry_desc *txdesc)
-{
- struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
- unsigned int beacon_base;
- u32 reg;
-
- /*
- * Disable beaconing while we are reloading the beacon data,
- * otherwise we might be sending out invalid data.
- */
- rt2800_register_read(rt2x00dev, BCN_TIME_CFG, &reg);
- rt2x00_set_field32(&reg, BCN_TIME_CFG_BEACON_GEN, 0);
- rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg);
-
- /*
- * Add the TXWI for the beacon to the skb.
- */
- rt2800_write_txwi(entry->skb, txdesc);
- skb_push(entry->skb, TXWI_DESC_SIZE);
-
- /*
- * Write entire beacon with TXWI to register.
- */
- beacon_base = HW_BEACON_OFFSET(entry->entry_idx);
- rt2800_register_multiwrite(rt2x00dev, beacon_base,
- entry->skb->data, entry->skb->len);
-
- /*
- * Enable beaconing again.
- */
- rt2x00_set_field32(&reg, BCN_TIME_CFG_TSF_TICKING, 1);
- rt2x00_set_field32(&reg, BCN_TIME_CFG_TBTT_ENABLE, 1);
- rt2x00_set_field32(&reg, BCN_TIME_CFG_BEACON_GEN, 1);
- rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg);
-
- /*
- * Clean up beacon skb.
- */
- dev_kfree_skb_any(entry->skb);
- entry->skb = NULL;
-}
-
static void rt2800pci_kick_tx_queue(struct rt2x00_dev *rt2x00dev,
const enum data_queue_qid queue_idx)
{
@@ -812,7 +716,7 @@ static void rt2800pci_fill_rxdone(struct queue_entry *entry,
/*
* Process the RXWI structure that is at the start of the buffer.
*/
- rt2800_process_rxwi(entry->skb, rxdesc);
+ rt2800_process_rxwi(entry, rxdesc);
/*
* Set RX IDX in register to inform hardware that we have handled
@@ -832,29 +736,24 @@ static void rt2800pci_txdone(struct rt2x00_dev *rt2x00dev)
struct txdone_entry_desc txdesc;
u32 word;
u32 reg;
- u32 old_reg;
int wcid, ack, pid, tx_wcid, tx_ack, tx_pid;
u16 mcs, real_mcs;
+ int i;
/*
- * During each loop we will compare the freshly read
- * TX_STA_FIFO register value with the value read from
- * the previous loop. If the 2 values are equal then
- * we should stop processing because the chance it
- * quite big that the device has been unplugged and
- * we risk going into an endless loop.
+ * TX_STA_FIFO is a stack of X entries, hence read TX_STA_FIFO
+ * at most X times and also stop processing once the TX_STA_FIFO_VALID
+ * flag is not set anymore.
+ *
+ * The legacy drivers use X=TX_RING_SIZE but state in a comment
+ * that the TX_STA_FIFO stack has a size of 16. We stick to our
+ * tx ring size for now.
*/
- old_reg = 0;
-
- while (1) {
+ for (i = 0; i < TX_ENTRIES; i++) {
rt2800_register_read(rt2x00dev, TX_STA_FIFO, &reg);
if (!rt2x00_get_field32(reg, TX_STA_FIFO_VALID))
break;
- if (old_reg == reg)
- break;
- old_reg = reg;
-
wcid = rt2x00_get_field32(reg, TX_STA_FIFO_WCID);
ack = rt2x00_get_field32(reg, TX_STA_FIFO_TX_ACK_REQUIRED);
pid = rt2x00_get_field32(reg, TX_STA_FIFO_PID_TYPE);
@@ -880,8 +779,7 @@ static void rt2800pci_txdone(struct rt2x00_dev *rt2x00dev)
/* Check if we got a match by looking at WCID/ACK/PID
* fields */
- txwi = (__le32 *)(entry->skb->data -
- rt2x00dev->ops->extra_tx_headroom);
+ txwi = (__le32 *) entry->skb->data;
rt2x00_desc_read(txwi, 1, &word);
tx_wcid = rt2x00_get_field32(word, TXWI_W1_WIRELESS_CLI_ID);
@@ -923,8 +821,12 @@ static void rt2800pci_txdone(struct rt2x00_dev *rt2x00dev)
txdesc.retry = 7;
}
- __set_bit(TXDONE_FALLBACK, &txdesc.flags);
-
+ /*
+ * the frame was retried at least once
+ * -> hw used fallback rates
+ */
+ if (txdesc.retry)
+ __set_bit(TXDONE_FALLBACK, &txdesc.flags);
rt2x00lib_txdone(entry, &txdesc);
}
@@ -938,6 +840,48 @@ static void rt2800pci_wakeup(struct rt2x00_dev *rt2x00dev)
rt2800_config(rt2x00dev, &libconf, IEEE80211_CONF_CHANGE_PS);
}
+static irqreturn_t rt2800pci_interrupt_thread(int irq, void *dev_instance)
+{
+ struct rt2x00_dev *rt2x00dev = dev_instance;
+ u32 reg = rt2x00dev->irqvalue[0];
+
+ /*
+ * 1 - Pre TBTT interrupt.
+ */
+ if (rt2x00_get_field32(reg, INT_SOURCE_CSR_PRE_TBTT))
+ rt2x00lib_pretbtt(rt2x00dev);
+
+ /*
+ * 2 - Beacondone interrupt.
+ */
+ if (rt2x00_get_field32(reg, INT_SOURCE_CSR_TBTT))
+ rt2x00lib_beacondone(rt2x00dev);
+
+ /*
+ * 3 - Rx ring done interrupt.
+ */
+ if (rt2x00_get_field32(reg, INT_SOURCE_CSR_RX_DONE))
+ rt2x00pci_rxdone(rt2x00dev);
+
+ /*
+ * 4 - Tx done interrupt.
+ */
+ if (rt2x00_get_field32(reg, INT_SOURCE_CSR_TX_FIFO_STATUS))
+ rt2800pci_txdone(rt2x00dev);
+
+ /*
+ * 5 - Auto wakeup interrupt.
+ */
+ if (rt2x00_get_field32(reg, INT_SOURCE_CSR_AUTO_WAKEUP))
+ rt2800pci_wakeup(rt2x00dev);
+
+ /* Enable interrupts again. */
+ rt2x00dev->ops->lib->set_device_state(rt2x00dev,
+ STATE_RADIO_IRQ_ON_ISR);
+
+ return IRQ_HANDLED;
+}
+
static irqreturn_t rt2800pci_interrupt(int irq, void *dev_instance)
{
struct rt2x00_dev *rt2x00dev = dev_instance;
@@ -953,19 +897,15 @@ static irqreturn_t rt2800pci_interrupt(int irq, void *dev_instance)
if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
return IRQ_HANDLED;
- /*
- * 1 - Rx ring done interrupt.
- */
- if (rt2x00_get_field32(reg, INT_SOURCE_CSR_RX_DONE))
- rt2x00pci_rxdone(rt2x00dev);
+ /* Store irqvalue for use in the interrupt thread. */
+ rt2x00dev->irqvalue[0] = reg;
- if (rt2x00_get_field32(reg, INT_SOURCE_CSR_TX_FIFO_STATUS))
- rt2800pci_txdone(rt2x00dev);
+ /* Disable interrupts, will be enabled again in the interrupt thread. */
+ rt2x00dev->ops->lib->set_device_state(rt2x00dev,
+ STATE_RADIO_IRQ_OFF_ISR);
- if (rt2x00_get_field32(reg, INT_SOURCE_CSR_AUTO_WAKEUP))
- rt2800pci_wakeup(rt2x00dev);
- return IRQ_HANDLED;
+ return IRQ_WAKE_THREAD;
}
/*
@@ -986,24 +926,10 @@ static int rt2800pci_validate_eeprom(struct rt2x00_dev *rt2x00dev)
return rt2800_validate_eeprom(rt2x00dev);
}
-static const struct rt2800_ops rt2800pci_rt2800_ops = {
- .register_read = rt2x00pci_register_read,
- .register_read_lock = rt2x00pci_register_read, /* same for PCI */
- .register_write = rt2x00pci_register_write,
- .register_write_lock = rt2x00pci_register_write, /* same for PCI */
-
- .register_multiread = rt2x00pci_register_multiread,
- .register_multiwrite = rt2x00pci_register_multiwrite,
-
- .regbusy_read = rt2x00pci_regbusy_read,
-};
-
static int rt2800pci_probe_hw(struct rt2x00_dev *rt2x00dev)
{
int retval;
- rt2x00dev->priv = (void *)&rt2800pci_rt2800_ops;
-
/*
* Allocate eeprom data.
*/
@@ -1030,6 +956,12 @@ static int rt2800pci_probe_hw(struct rt2x00_dev *rt2x00dev)
__set_bit(DRIVER_SUPPORT_CONTROL_FILTER_PSPOLL, &rt2x00dev->flags);
/*
+ * This device has a pre tbtt interrupt and thus fetches
+ * a new beacon directly prior to transmission.
+ */
+ __set_bit(DRIVER_SUPPORT_PRE_TBTT_INTERRUPT, &rt2x00dev->flags);
+
+ /*
* This device requires firmware.
*/
if (!rt2x00_is_soc(rt2x00dev))
@@ -1038,6 +970,7 @@ static int rt2800pci_probe_hw(struct rt2x00_dev *rt2x00dev)
__set_bit(DRIVER_REQUIRE_L2PAD, &rt2x00dev->flags);
if (!modparam_nohwcrypt)
__set_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags);
+ __set_bit(DRIVER_SUPPORT_LINK_TUNING, &rt2x00dev->flags);
/*
* Set the rssi offset.
@@ -1047,12 +980,46 @@ static int rt2800pci_probe_hw(struct rt2x00_dev *rt2x00dev)
return 0;
}
+static const struct ieee80211_ops rt2800pci_mac80211_ops = {
+ .tx = rt2x00mac_tx,
+ .start = rt2x00mac_start,
+ .stop = rt2x00mac_stop,
+ .add_interface = rt2x00mac_add_interface,
+ .remove_interface = rt2x00mac_remove_interface,
+ .config = rt2x00mac_config,
+ .configure_filter = rt2x00mac_configure_filter,
+ .set_key = rt2x00mac_set_key,
+ .sw_scan_start = rt2x00mac_sw_scan_start,
+ .sw_scan_complete = rt2x00mac_sw_scan_complete,
+ .get_stats = rt2x00mac_get_stats,
+ .get_tkip_seq = rt2800_get_tkip_seq,
+ .set_rts_threshold = rt2800_set_rts_threshold,
+ .bss_info_changed = rt2x00mac_bss_info_changed,
+ .conf_tx = rt2800_conf_tx,
+ .get_tsf = rt2800_get_tsf,
+ .rfkill_poll = rt2x00mac_rfkill_poll,
+ .ampdu_action = rt2800_ampdu_action,
+};
+
+static const struct rt2800_ops rt2800pci_rt2800_ops = {
+ .register_read = rt2x00pci_register_read,
+ .register_read_lock = rt2x00pci_register_read, /* same for PCI */
+ .register_write = rt2x00pci_register_write,
+ .register_write_lock = rt2x00pci_register_write, /* same for PCI */
+ .register_multiread = rt2x00pci_register_multiread,
+ .register_multiwrite = rt2x00pci_register_multiwrite,
+ .regbusy_read = rt2x00pci_regbusy_read,
+ .drv_write_firmware = rt2800pci_write_firmware,
+ .drv_init_registers = rt2800pci_init_registers,
+};
+
static const struct rt2x00lib_ops rt2800pci_rt2x00_ops = {
.irq_handler = rt2800pci_interrupt,
+ .irq_handler_thread = rt2800pci_interrupt_thread,
.probe_hw = rt2800pci_probe_hw,
.get_firmware_name = rt2800pci_get_firmware_name,
- .check_firmware = rt2800pci_check_firmware,
- .load_firmware = rt2800pci_load_firmware,
+ .check_firmware = rt2800_check_firmware,
+ .load_firmware = rt2800_load_firmware,
.initialize = rt2x00pci_initialize,
.uninitialize = rt2x00pci_uninitialize,
.get_entry_state = rt2800pci_get_entry_state,
@@ -1064,7 +1031,7 @@ static const struct rt2x00lib_ops rt2800pci_rt2x00_ops = {
.link_tuner = rt2800_link_tuner,
.write_tx_desc = rt2800pci_write_tx_desc,
.write_tx_data = rt2800pci_write_tx_data,
- .write_beacon = rt2800pci_write_beacon,
+ .write_beacon = rt2800_write_beacon,
.kick_tx_queue = rt2800pci_kick_tx_queue,
.kill_tx_queue = rt2800pci_kill_tx_queue,
.fill_rxdone = rt2800pci_fill_rxdone,
@@ -1110,7 +1077,8 @@ static const struct rt2x00_ops rt2800pci_ops = {
.tx = &rt2800pci_queue_tx,
.bcn = &rt2800pci_queue_bcn,
.lib = &rt2800pci_rt2x00_ops,
- .hw = &rt2800_mac80211_ops,
+ .drv = &rt2800pci_rt2800_ops,
+ .hw = &rt2800pci_mac80211_ops,
#ifdef CONFIG_RT2X00_LIB_DEBUGFS
.debugfs = &rt2800_rt2x00debug,
#endif /* CONFIG_RT2X00_LIB_DEBUGFS */
diff --git a/drivers/net/wireless/rt2x00/rt2800pci.h b/drivers/net/wireless/rt2x00/rt2800pci.h
index afc8e7da27c..5a8dda9b5b5 100644
--- a/drivers/net/wireless/rt2x00/rt2800pci.h
+++ b/drivers/net/wireless/rt2x00/rt2800pci.h
@@ -35,25 +35,6 @@
#define RT2800PCI_H
/*
- * PCI registers.
- */
-
-/*
- * E2PROM_CSR: EEPROM control register.
- * RELOAD: Write 1 to reload eeprom content.
- * TYPE: 0: 93c46, 1:93c66.
- * LOAD_STATUS: 1:loading, 0:done.
- */
-#define E2PROM_CSR 0x0004
-#define E2PROM_CSR_DATA_CLOCK FIELD32(0x00000001)
-#define E2PROM_CSR_CHIP_SELECT FIELD32(0x00000002)
-#define E2PROM_CSR_DATA_IN FIELD32(0x00000004)
-#define E2PROM_CSR_DATA_OUT FIELD32(0x00000008)
-#define E2PROM_CSR_TYPE FIELD32(0x00000030)
-#define E2PROM_CSR_LOAD_STATUS FIELD32(0x00000040)
-#define E2PROM_CSR_RELOAD FIELD32(0x00000080)
-
-/*
* Queue register offset macros
*/
#define TX_QUEUE_REG_OFFSET 0x10
diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c
index 0f8b84b7224..5a2dfe87c6b 100644
--- a/drivers/net/wireless/rt2x00/rt2800usb.c
+++ b/drivers/net/wireless/rt2x00/rt2800usb.c
@@ -28,7 +28,6 @@
Supported chipsets: RT2800U.
*/
-#include <linux/crc-ccitt.h>
#include <linux/delay.h>
#include <linux/etherdevice.h>
#include <linux/init.h>
@@ -45,7 +44,7 @@
/*
* Allow hardware encryption to be disabled.
*/
-static int modparam_nohwcrypt = 1;
+static int modparam_nohwcrypt = 0;
module_param_named(nohwcrypt, modparam_nohwcrypt, bool, S_IRUGO);
MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption.");
@@ -57,84 +56,10 @@ static char *rt2800usb_get_firmware_name(struct rt2x00_dev *rt2x00dev)
return FIRMWARE_RT2870;
}
-static bool rt2800usb_check_crc(const u8 *data, const size_t len)
-{
- u16 fw_crc;
- u16 crc;
-
- /*
- * The last 2 bytes in the firmware array are the crc checksum itself,
- * this means that we should never pass those 2 bytes to the crc
- * algorithm.
- */
- fw_crc = (data[len - 2] << 8 | data[len - 1]);
-
- /*
- * Use the crc ccitt algorithm.
- * This will return the same value as the legacy driver which
- * used bit ordering reversion on the both the firmware bytes
- * before input input as well as on the final output.
- * Obviously using crc ccitt directly is much more efficient.
- */
- crc = crc_ccitt(~0, data, len - 2);
-
- /*
- * There is a small difference between the crc-itu-t + bitrev and
- * the crc-ccitt crc calculation. In the latter method the 2 bytes
- * will be swapped, use swab16 to convert the crc to the correct
- * value.
- */
- crc = swab16(crc);
-
- return fw_crc == crc;
-}
-
-static int rt2800usb_check_firmware(struct rt2x00_dev *rt2x00dev,
+static int rt2800usb_write_firmware(struct rt2x00_dev *rt2x00dev,
const u8 *data, const size_t len)
{
- size_t offset = 0;
-
- /*
- * Firmware files:
- * There are 2 variations of the rt2870 firmware.
- * a) size: 4kb
- * b) size: 8kb
- * Note that (b) contains 2 separate firmware blobs of 4k
- * within the file. The first blob is the same firmware as (a),
- * but the second blob is for the additional chipsets.
- */
- if (len != 4096 && len != 8192)
- return FW_BAD_LENGTH;
-
- /*
- * Check if we need the upper 4kb firmware data or not.
- */
- if ((len == 4096) &&
- !rt2x00_rt(rt2x00dev, RT2860) &&
- !rt2x00_rt(rt2x00dev, RT2872) &&
- !rt2x00_rt(rt2x00dev, RT3070))
- return FW_BAD_VERSION;
-
- /*
- * 8kb firmware files must be checked as if it were
- * 2 separate firmware files.
- */
- while (offset < len) {
- if (!rt2800usb_check_crc(data + offset, 4096))
- return FW_BAD_CRC;
-
- offset += 4096;
- }
-
- return FW_OK;
-}
-
-static int rt2800usb_load_firmware(struct rt2x00_dev *rt2x00dev,
- const u8 *data, const size_t len)
-{
- unsigned int i;
int status;
- u32 reg;
u32 offset;
u32 length;
@@ -152,28 +77,10 @@ static int rt2800usb_load_firmware(struct rt2x00_dev *rt2x00dev,
}
/*
- * Wait for stable hardware.
- */
- for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
- rt2800_register_read(rt2x00dev, MAC_CSR0, &reg);
- if (reg && reg != ~0)
- break;
- msleep(1);
- }
-
- if (i == REGISTER_BUSY_COUNT) {
- ERROR(rt2x00dev, "Unstable hardware.\n");
- return -EBUSY;
- }
-
- /*
* Write firmware to device.
*/
- rt2x00usb_vendor_request_large_buff(rt2x00dev, USB_MULTI_WRITE,
- USB_VENDOR_REQUEST_OUT,
- FIRMWARE_IMAGE_BASE,
- data + offset, length,
- REGISTER_TIMEOUT32(length));
+ rt2800_register_multiwrite(rt2x00dev, FIRMWARE_IMAGE_BASE,
+ data + offset, length);
rt2800_register_write(rt2x00dev, H2M_MAILBOX_CID, ~0);
rt2800_register_write(rt2x00dev, H2M_MAILBOX_STATUS, ~0);
@@ -196,7 +103,7 @@ static int rt2800usb_load_firmware(struct rt2x00_dev *rt2x00dev,
/*
* Send signal to firmware during boot time.
*/
- rt2800_mcu_request(rt2x00dev, MCU_BOOT_SIGNAL, 0xff, 0, 0);
+ rt2800_mcu_request(rt2x00dev, MCU_BOOT_SIGNAL, 0, 0, 0);
if (rt2x00_rt(rt2x00dev, RT3070) ||
rt2x00_rt(rt2x00dev, RT3071) ||
@@ -206,28 +113,6 @@ static int rt2800usb_load_firmware(struct rt2x00_dev *rt2x00dev,
udelay(10);
}
- /*
- * Wait for device to stabilize.
- */
- for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
- rt2800_register_read(rt2x00dev, PBF_SYS_CTRL, &reg);
- if (rt2x00_get_field32(reg, PBF_SYS_CTRL_READY))
- break;
- msleep(1);
- }
-
- if (i == REGISTER_BUSY_COUNT) {
- ERROR(rt2x00dev, "PBF system register not ready.\n");
- return -EBUSY;
- }
-
- /*
- * Initialize firmware.
- */
- rt2800_register_write(rt2x00dev, H2M_BBP_AGENT, 0);
- rt2800_register_write(rt2x00dev, H2M_MAILBOX_CSR, 0);
- msleep(1);
-
return 0;
}
@@ -246,6 +131,44 @@ static void rt2800usb_toggle_rx(struct rt2x00_dev *rt2x00dev,
rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, reg);
}
+static int rt2800usb_init_registers(struct rt2x00_dev *rt2x00dev)
+{
+ u32 reg;
+ int i;
+
+ /*
+ * Wait until BBP and RF are ready.
+ */
+ for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
+ rt2800_register_read(rt2x00dev, MAC_CSR0, &reg);
+ if (reg && reg != ~0)
+ break;
+ msleep(1);
+ }
+
+ if (i == REGISTER_BUSY_COUNT) {
+ ERROR(rt2x00dev, "Unstable hardware.\n");
+ return -EBUSY;
+ }
+
+ rt2800_register_read(rt2x00dev, PBF_SYS_CTRL, &reg);
+ rt2800_register_write(rt2x00dev, PBF_SYS_CTRL, reg & ~0x00002000);
+
+ rt2800_register_read(rt2x00dev, MAC_SYS_CTRL, &reg);
+ rt2x00_set_field32(&reg, MAC_SYS_CTRL_RESET_CSR, 1);
+ rt2x00_set_field32(&reg, MAC_SYS_CTRL_RESET_BBP, 1);
+ rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, reg);
+
+ rt2800_register_write(rt2x00dev, USB_DMA_CFG, 0x00000000);
+
+ rt2x00usb_vendor_request_sw(rt2x00dev, USB_DEVICE_MODE, 0,
+ USB_MODE_RESET, REGISTER_TIMEOUT);
+
+ rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, 0x00000000);
+
+ return 0;
+}
+
static int rt2800usb_enable_radio(struct rt2x00_dev *rt2x00dev)
{
u32 reg;
@@ -371,7 +294,9 @@ static int rt2800usb_set_device_state(struct rt2x00_dev *rt2x00dev,
rt2800usb_toggle_rx(rt2x00dev, state);
break;
case STATE_RADIO_IRQ_ON:
+ case STATE_RADIO_IRQ_ON_ISR:
case STATE_RADIO_IRQ_OFF:
+ case STATE_RADIO_IRQ_OFF_ISR:
/* No support, but no error either */
break;
case STATE_DEEP_SLEEP:
@@ -395,25 +320,29 @@ static int rt2800usb_set_device_state(struct rt2x00_dev *rt2x00dev,
/*
* TX descriptor initialization
*/
+static void rt2800usb_write_tx_data(struct queue_entry* entry,
+ struct txentry_desc *txdesc)
+{
+ __le32 *txwi = (__le32 *) (entry->skb->data + TXINFO_DESC_SIZE);
+
+ rt2800_write_txwi(txwi, txdesc);
+}
+
+
static void rt2800usb_write_tx_desc(struct rt2x00_dev *rt2x00dev,
struct sk_buff *skb,
struct txentry_desc *txdesc)
{
struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb);
- __le32 *txi = (__le32 *)(skb->data - TXWI_DESC_SIZE - TXINFO_DESC_SIZE);
+ __le32 *txi = (__le32 *) skb->data;
u32 word;
/*
- * Initialize TXWI descriptor
- */
- rt2800_write_txwi(skb, txdesc);
-
- /*
* Initialize TXINFO descriptor
*/
rt2x00_desc_read(txi, 0, &word);
rt2x00_set_field32(&word, TXINFO_W0_USB_DMA_TX_PKT_LEN,
- skb->len + TXWI_DESC_SIZE);
+ skb->len - TXINFO_DESC_SIZE);
rt2x00_set_field32(&word, TXINFO_W0_WIV,
!test_bit(ENTRY_TXD_ENCRYPT_IV, &txdesc->flags));
rt2x00_set_field32(&word, TXINFO_W0_QSEL, 2);
@@ -426,6 +355,7 @@ static void rt2800usb_write_tx_desc(struct rt2x00_dev *rt2x00dev,
/*
* Register descriptor details in skb frame descriptor.
*/
+ skbdesc->flags |= SKBDESC_DESC_IN_SKB;
skbdesc->desc = txi;
skbdesc->desc_len = TXINFO_DESC_SIZE + TXWI_DESC_SIZE;
}
@@ -433,51 +363,6 @@ static void rt2800usb_write_tx_desc(struct rt2x00_dev *rt2x00dev,
/*
* TX data initialization
*/
-static void rt2800usb_write_beacon(struct queue_entry *entry,
- struct txentry_desc *txdesc)
-{
- struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
- unsigned int beacon_base;
- u32 reg;
-
- /*
- * Disable beaconing while we are reloading the beacon data,
- * otherwise we might be sending out invalid data.
- */
- rt2800_register_read(rt2x00dev, BCN_TIME_CFG, &reg);
- rt2x00_set_field32(&reg, BCN_TIME_CFG_BEACON_GEN, 0);
- rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg);
-
- /*
- * Add the TXWI for the beacon to the skb.
- */
- rt2800_write_txwi(entry->skb, txdesc);
- skb_push(entry->skb, TXWI_DESC_SIZE);
-
- /*
- * Write entire beacon with descriptor to register.
- */
- beacon_base = HW_BEACON_OFFSET(entry->entry_idx);
- rt2x00usb_vendor_request_large_buff(rt2x00dev, USB_MULTI_WRITE,
- USB_VENDOR_REQUEST_OUT, beacon_base,
- entry->skb->data, entry->skb->len,
- REGISTER_TIMEOUT32(entry->skb->len));
-
- /*
- * Enable beaconing again.
- */
- rt2x00_set_field32(&reg, BCN_TIME_CFG_TSF_TICKING, 1);
- rt2x00_set_field32(&reg, BCN_TIME_CFG_TBTT_ENABLE, 1);
- rt2x00_set_field32(&reg, BCN_TIME_CFG_BEACON_GEN, 1);
- rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg);
-
- /*
- * Clean up the beacon skb.
- */
- dev_kfree_skb(entry->skb);
- entry->skb = NULL;
-}
-
static int rt2800usb_get_tx_data_len(struct queue_entry *entry)
{
int length;
@@ -568,7 +453,7 @@ static void rt2800usb_fill_rxdone(struct queue_entry *entry,
/*
* Process the RXWI structure.
*/
- rt2800_process_rxwi(entry->skb, rxdesc);
+ rt2800_process_rxwi(entry, rxdesc);
}
/*
@@ -585,24 +470,10 @@ static int rt2800usb_validate_eeprom(struct rt2x00_dev *rt2x00dev)
return rt2800_validate_eeprom(rt2x00dev);
}
-static const struct rt2800_ops rt2800usb_rt2800_ops = {
- .register_read = rt2x00usb_register_read,
- .register_read_lock = rt2x00usb_register_read_lock,
- .register_write = rt2x00usb_register_write,
- .register_write_lock = rt2x00usb_register_write_lock,
-
- .register_multiread = rt2x00usb_register_multiread,
- .register_multiwrite = rt2x00usb_register_multiwrite,
-
- .regbusy_read = rt2x00usb_regbusy_read,
-};
-
static int rt2800usb_probe_hw(struct rt2x00_dev *rt2x00dev)
{
int retval;
- rt2x00dev->priv = (void *)&rt2800usb_rt2800_ops;
-
/*
* Allocate eeprom data.
*/
@@ -635,6 +506,8 @@ static int rt2800usb_probe_hw(struct rt2x00_dev *rt2x00dev)
__set_bit(DRIVER_REQUIRE_L2PAD, &rt2x00dev->flags);
if (!modparam_nohwcrypt)
__set_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags);
+ __set_bit(DRIVER_SUPPORT_LINK_TUNING, &rt2x00dev->flags);
+ __set_bit(DRIVER_SUPPORT_WATCHDOG, &rt2x00dev->flags);
/*
* Set the rssi offset.
@@ -644,11 +517,45 @@ static int rt2800usb_probe_hw(struct rt2x00_dev *rt2x00dev)
return 0;
}
+static const struct ieee80211_ops rt2800usb_mac80211_ops = {
+ .tx = rt2x00mac_tx,
+ .start = rt2x00mac_start,
+ .stop = rt2x00mac_stop,
+ .add_interface = rt2x00mac_add_interface,
+ .remove_interface = rt2x00mac_remove_interface,
+ .config = rt2x00mac_config,
+ .configure_filter = rt2x00mac_configure_filter,
+ .set_tim = rt2x00mac_set_tim,
+ .set_key = rt2x00mac_set_key,
+ .sw_scan_start = rt2x00mac_sw_scan_start,
+ .sw_scan_complete = rt2x00mac_sw_scan_complete,
+ .get_stats = rt2x00mac_get_stats,
+ .get_tkip_seq = rt2800_get_tkip_seq,
+ .set_rts_threshold = rt2800_set_rts_threshold,
+ .bss_info_changed = rt2x00mac_bss_info_changed,
+ .conf_tx = rt2800_conf_tx,
+ .get_tsf = rt2800_get_tsf,
+ .rfkill_poll = rt2x00mac_rfkill_poll,
+ .ampdu_action = rt2800_ampdu_action,
+};
+
+static const struct rt2800_ops rt2800usb_rt2800_ops = {
+ .register_read = rt2x00usb_register_read,
+ .register_read_lock = rt2x00usb_register_read_lock,
+ .register_write = rt2x00usb_register_write,
+ .register_write_lock = rt2x00usb_register_write_lock,
+ .register_multiread = rt2x00usb_register_multiread,
+ .register_multiwrite = rt2x00usb_register_multiwrite,
+ .regbusy_read = rt2x00usb_regbusy_read,
+ .drv_write_firmware = rt2800usb_write_firmware,
+ .drv_init_registers = rt2800usb_init_registers,
+};
+
static const struct rt2x00lib_ops rt2800usb_rt2x00_ops = {
.probe_hw = rt2800usb_probe_hw,
.get_firmware_name = rt2800usb_get_firmware_name,
- .check_firmware = rt2800usb_check_firmware,
- .load_firmware = rt2800usb_load_firmware,
+ .check_firmware = rt2800_check_firmware,
+ .load_firmware = rt2800_load_firmware,
.initialize = rt2x00usb_initialize,
.uninitialize = rt2x00usb_uninitialize,
.clear_entry = rt2x00usb_clear_entry,
@@ -657,9 +564,10 @@ static const struct rt2x00lib_ops rt2800usb_rt2x00_ops = {
.link_stats = rt2800_link_stats,
.reset_tuner = rt2800_reset_tuner,
.link_tuner = rt2800_link_tuner,
+ .watchdog = rt2x00usb_watchdog,
.write_tx_desc = rt2800usb_write_tx_desc,
- .write_tx_data = rt2x00usb_write_tx_data,
- .write_beacon = rt2800usb_write_beacon,
+ .write_tx_data = rt2800usb_write_tx_data,
+ .write_beacon = rt2800_write_beacon,
.get_tx_data_len = rt2800usb_get_tx_data_len,
.kick_tx_queue = rt2x00usb_kick_tx_queue,
.kill_tx_queue = rt2x00usb_kill_tx_queue,
@@ -706,7 +614,8 @@ static const struct rt2x00_ops rt2800usb_ops = {
.tx = &rt2800usb_queue_tx,
.bcn = &rt2800usb_queue_bcn,
.lib = &rt2800usb_rt2x00_ops,
- .hw = &rt2800_mac80211_ops,
+ .drv = &rt2800usb_rt2800_ops,
+ .hw = &rt2800usb_mac80211_ops,
#ifdef CONFIG_RT2X00_LIB_DEBUGFS
.debugfs = &rt2800_rt2x00debug,
#endif /* CONFIG_RT2X00_LIB_DEBUGFS */
diff --git a/drivers/net/wireless/rt2x00/rt2800usb.h b/drivers/net/wireless/rt2x00/rt2800usb.h
index 2bca6a71a7f..0722badccf8 100644
--- a/drivers/net/wireless/rt2x00/rt2800usb.h
+++ b/drivers/net/wireless/rt2x00/rt2800usb.h
@@ -32,43 +32,6 @@
#define RT2800USB_H
/*
- * USB registers.
- */
-
-/*
- * USB_DMA_CFG
- * RX_BULK_AGG_TIMEOUT: Rx Bulk Aggregation TimeOut in unit of 33ns.
- * RX_BULK_AGG_LIMIT: Rx Bulk Aggregation Limit in unit of 256 bytes.
- * PHY_CLEAR: phy watch dog enable.
- * TX_CLEAR: Clear USB DMA TX path.
- * TXOP_HALT: Halt TXOP count down when TX buffer is full.
- * RX_BULK_AGG_EN: Enable Rx Bulk Aggregation.
- * RX_BULK_EN: Enable USB DMA Rx.
- * TX_BULK_EN: Enable USB DMA Tx.
- * EP_OUT_VALID: OUT endpoint data valid.
- * RX_BUSY: USB DMA RX FSM busy.
- * TX_BUSY: USB DMA TX FSM busy.
- */
-#define USB_DMA_CFG 0x02a0
-#define USB_DMA_CFG_RX_BULK_AGG_TIMEOUT FIELD32(0x000000ff)
-#define USB_DMA_CFG_RX_BULK_AGG_LIMIT FIELD32(0x0000ff00)
-#define USB_DMA_CFG_PHY_CLEAR FIELD32(0x00010000)
-#define USB_DMA_CFG_TX_CLEAR FIELD32(0x00080000)
-#define USB_DMA_CFG_TXOP_HALT FIELD32(0x00100000)
-#define USB_DMA_CFG_RX_BULK_AGG_EN FIELD32(0x00200000)
-#define USB_DMA_CFG_RX_BULK_EN FIELD32(0x00400000)
-#define USB_DMA_CFG_TX_BULK_EN FIELD32(0x00800000)
-#define USB_DMA_CFG_EP_OUT_VALID FIELD32(0x3f000000)
-#define USB_DMA_CFG_RX_BUSY FIELD32(0x40000000)
-#define USB_DMA_CFG_TX_BUSY FIELD32(0x80000000)
-
-/*
- * USB_CYC_CFG
- */
-#define USB_CYC_CFG 0x02a4
-#define USB_CYC_CFG_CLOCK_CYCLE FIELD32(0x000000ff)
-
-/*
* 8051 firmware image.
*/
#define FIRMWARE_RT2870 "rt2870.bin"
diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h
index 6c1ff4c15c8..c21af38cc5a 100644
--- a/drivers/net/wireless/rt2x00/rt2x00.h
+++ b/drivers/net/wireless/rt2x00/rt2x00.h
@@ -39,6 +39,7 @@
#include <net/mac80211.h>
#include "rt2x00debug.h"
+#include "rt2x00dump.h"
#include "rt2x00leds.h"
#include "rt2x00reg.h"
#include "rt2x00queue.h"
@@ -159,6 +160,7 @@ struct avg_val {
enum rt2x00_chip_intf {
RT2X00_CHIP_INTF_PCI,
+ RT2X00_CHIP_INTF_PCIE,
RT2X00_CHIP_INTF_USB,
RT2X00_CHIP_INTF_SOC,
};
@@ -175,8 +177,7 @@ struct rt2x00_chip {
#define RT2570 0x2570
#define RT2661 0x2661
#define RT2573 0x2573
-#define RT2860 0x2860 /* 2.4GHz PCI/CB */
-#define RT2870 0x2870
+#define RT2860 0x2860 /* 2.4GHz */
#define RT2872 0x2872 /* WSOC */
#define RT2883 0x2883 /* WSOC */
#define RT3070 0x3070
@@ -331,6 +332,11 @@ struct link {
* Work structure for scheduling periodic link tuning.
*/
struct delayed_work work;
+
+ /*
+ * Work structure for scheduling periodic watchdog monitoring.
+ */
+ struct delayed_work watchdog_work;
};
/*
@@ -509,6 +515,11 @@ struct rt2x00lib_ops {
irq_handler_t irq_handler;
/*
+ * Threaded Interrupt handlers.
+ */
+ irq_handler_t irq_handler_thread;
+
+ /*
* Device init handlers.
*/
int (*probe_hw) (struct rt2x00_dev *rt2x00dev);
@@ -542,6 +553,7 @@ struct rt2x00lib_ops {
struct link_qual *qual);
void (*link_tuner) (struct rt2x00_dev *rt2x00dev,
struct link_qual *qual, const u32 count);
+ void (*watchdog) (struct rt2x00_dev *rt2x00dev);
/*
* TX control handlers
@@ -549,8 +561,8 @@ struct rt2x00lib_ops {
void (*write_tx_desc) (struct rt2x00_dev *rt2x00dev,
struct sk_buff *skb,
struct txentry_desc *txdesc);
- int (*write_tx_data) (struct queue_entry *entry,
- struct txentry_desc *txdesc);
+ void (*write_tx_data) (struct queue_entry *entry,
+ struct txentry_desc *txdesc);
void (*write_beacon) (struct queue_entry *entry,
struct txentry_desc *txdesc);
int (*get_tx_data_len) (struct queue_entry *entry);
@@ -609,6 +621,7 @@ struct rt2x00_ops {
const struct data_queue_desc *bcn;
const struct data_queue_desc *atim;
const struct rt2x00lib_ops *lib;
+ const void *drv;
const struct ieee80211_ops *hw;
#ifdef CONFIG_RT2X00_LIB_DEBUGFS
const struct rt2x00debug *debugfs;
@@ -627,6 +640,7 @@ enum rt2x00_flags {
DEVICE_STATE_INITIALIZED,
DEVICE_STATE_STARTED,
DEVICE_STATE_ENABLED_RADIO,
+ DEVICE_STATE_SCANNING,
/*
* Driver requirements
@@ -645,6 +659,9 @@ enum rt2x00_flags {
CONFIG_SUPPORT_HW_CRYPTO,
DRIVER_SUPPORT_CONTROL_FILTERS,
DRIVER_SUPPORT_CONTROL_FILTER_PSPOLL,
+ DRIVER_SUPPORT_PRE_TBTT_INTERRUPT,
+ DRIVER_SUPPORT_LINK_TUNING,
+ DRIVER_SUPPORT_WATCHDOG,
/*
* Driver configuration
@@ -654,7 +671,6 @@ enum rt2x00_flags {
CONFIG_EXTERNAL_LNA_A,
CONFIG_EXTERNAL_LNA_BG,
CONFIG_DOUBLE_ANTENNA,
- CONFIG_DISABLE_LINK_TUNING,
CONFIG_CHANNEL_HT40,
};
@@ -862,9 +878,10 @@ struct rt2x00_dev {
const struct firmware *fw;
/*
- * Driver specific data.
+ * Interrupt values, stored between interrupt service routine
+ * and interrupt thread routine.
*/
- void *priv;
+ u32 irqvalue[2];
};
/*
@@ -978,7 +995,13 @@ static inline bool rt2x00_intf(struct rt2x00_dev *rt2x00dev,
static inline bool rt2x00_is_pci(struct rt2x00_dev *rt2x00dev)
{
- return rt2x00_intf(rt2x00dev, RT2X00_CHIP_INTF_PCI);
+ return rt2x00_intf(rt2x00dev, RT2X00_CHIP_INTF_PCI) ||
+ rt2x00_intf(rt2x00dev, RT2X00_CHIP_INTF_PCIE);
+}
+
+static inline bool rt2x00_is_pcie(struct rt2x00_dev *rt2x00dev)
+{
+ return rt2x00_intf(rt2x00dev, RT2X00_CHIP_INTF_PCIE);
}
static inline bool rt2x00_is_usb(struct rt2x00_dev *rt2x00dev)
@@ -999,6 +1022,13 @@ static inline bool rt2x00_is_soc(struct rt2x00_dev *rt2x00dev)
void rt2x00queue_map_txskb(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb);
/**
+ * rt2x00queue_unmap_skb - Unmap a skb from DMA.
+ * @rt2x00dev: Pointer to &struct rt2x00_dev.
+ * @skb: The skb to unmap.
+ */
+void rt2x00queue_unmap_skb(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb);
+
+/**
* rt2x00queue_get_queue - Convert queue index to queue pointer
* @rt2x00dev: Pointer to &struct rt2x00_dev.
* @queue: rt2x00 queue index (see &enum data_queue_qid).
@@ -1015,9 +1045,30 @@ struct queue_entry *rt2x00queue_get_entry(struct data_queue *queue,
enum queue_index index);
/*
+ * Debugfs handlers.
+ */
+/**
+ * rt2x00debug_dump_frame - Dump a frame to userspace through debugfs.
+ * @rt2x00dev: Pointer to &struct rt2x00_dev.
+ * @type: The type of frame that is being dumped.
+ * @skb: The skb containing the frame to be dumped.
+ */
+#ifdef CONFIG_RT2X00_LIB_DEBUGFS
+void rt2x00debug_dump_frame(struct rt2x00_dev *rt2x00dev,
+ enum rt2x00_dump_type type, struct sk_buff *skb);
+#else
+static inline void rt2x00debug_dump_frame(struct rt2x00_dev *rt2x00dev,
+ enum rt2x00_dump_type type,
+ struct sk_buff *skb)
+{
+}
+#endif /* CONFIG_RT2X00_LIB_DEBUGFS */
+
+/*
* Interrupt context handlers.
*/
void rt2x00lib_beacondone(struct rt2x00_dev *rt2x00dev);
+void rt2x00lib_pretbtt(struct rt2x00_dev *rt2x00dev);
void rt2x00lib_txdone(struct queue_entry *entry,
struct txdone_entry_desc *txdesc);
void rt2x00lib_rxdone(struct rt2x00_dev *rt2x00dev,
@@ -1047,6 +1098,8 @@ int rt2x00mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
#else
#define rt2x00mac_set_key NULL
#endif /* CONFIG_RT2X00_LIB_CRYPTO */
+void rt2x00mac_sw_scan_start(struct ieee80211_hw *hw);
+void rt2x00mac_sw_scan_complete(struct ieee80211_hw *hw);
int rt2x00mac_get_stats(struct ieee80211_hw *hw,
struct ieee80211_low_level_stats *stats);
void rt2x00mac_bss_info_changed(struct ieee80211_hw *hw,
diff --git a/drivers/net/wireless/rt2x00/rt2x00config.c b/drivers/net/wireless/rt2x00/rt2x00config.c
index 098315a271c..953dc4f2c6a 100644
--- a/drivers/net/wireless/rt2x00/rt2x00config.c
+++ b/drivers/net/wireless/rt2x00/rt2x00config.c
@@ -41,10 +41,12 @@ void rt2x00lib_config_intf(struct rt2x00_dev *rt2x00dev,
switch (type) {
case NL80211_IFTYPE_ADHOC:
+ conf.sync = TSF_SYNC_ADHOC;
+ break;
case NL80211_IFTYPE_AP:
case NL80211_IFTYPE_MESH_POINT:
case NL80211_IFTYPE_WDS:
- conf.sync = TSF_SYNC_BEACON;
+ conf.sync = TSF_SYNC_AP_NONE;
break;
case NL80211_IFTYPE_STATION:
conf.sync = TSF_SYNC_INFRA;
@@ -170,23 +172,27 @@ void rt2x00lib_config(struct rt2x00_dev *rt2x00dev,
unsigned int ieee80211_flags)
{
struct rt2x00lib_conf libconf;
+ u16 hw_value;
memset(&libconf, 0, sizeof(libconf));
libconf.conf = conf;
if (ieee80211_flags & IEEE80211_CONF_CHANGE_CHANNEL) {
- if (conf_is_ht40(conf))
+ if (conf_is_ht40(conf)) {
__set_bit(CONFIG_CHANNEL_HT40, &rt2x00dev->flags);
- else
+ hw_value = rt2x00ht_center_channel(rt2x00dev, conf);
+ } else {
__clear_bit(CONFIG_CHANNEL_HT40, &rt2x00dev->flags);
+ hw_value = conf->channel->hw_value;
+ }
memcpy(&libconf.rf,
- &rt2x00dev->spec.channels[conf->channel->hw_value],
+ &rt2x00dev->spec.channels[hw_value],
sizeof(libconf.rf));
memcpy(&libconf.channel,
- &rt2x00dev->spec.channels_info[conf->channel->hw_value],
+ &rt2x00dev->spec.channels_info[hw_value],
sizeof(libconf.channel));
}
diff --git a/drivers/net/wireless/rt2x00/rt2x00debug.c b/drivers/net/wireless/rt2x00/rt2x00debug.c
index e9fe93fd804..b0498e7e7aa 100644
--- a/drivers/net/wireless/rt2x00/rt2x00debug.c
+++ b/drivers/net/wireless/rt2x00/rt2x00debug.c
@@ -211,6 +211,7 @@ void rt2x00debug_dump_frame(struct rt2x00_dev *rt2x00dev,
if (!test_bit(FRAME_DUMP_FILE_OPEN, &intf->frame_dump_flags))
skb_queue_purge(&intf->frame_dump_skbqueue);
}
+EXPORT_SYMBOL_GPL(rt2x00debug_dump_frame);
static int rt2x00debug_file_open(struct inode *inode, struct file *file)
{
diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c
index f20d3eeeea7..585e8166f22 100644
--- a/drivers/net/wireless/rt2x00/rt2x00dev.c
+++ b/drivers/net/wireless/rt2x00/rt2x00dev.c
@@ -70,6 +70,11 @@ int rt2x00lib_enable_radio(struct rt2x00_dev *rt2x00dev)
rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_ON);
/*
+ * Start watchdog monitoring.
+ */
+ rt2x00link_start_watchdog(rt2x00dev);
+
+ /*
* Start the TX queues.
*/
ieee80211_wake_queues(rt2x00dev->hw);
@@ -89,6 +94,11 @@ void rt2x00lib_disable_radio(struct rt2x00_dev *rt2x00dev)
rt2x00queue_stop_queues(rt2x00dev);
/*
+ * Stop watchdog monitoring.
+ */
+ rt2x00link_stop_watchdog(rt2x00dev);
+
+ /*
* Disable RX.
*/
rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_OFF);
@@ -168,10 +178,32 @@ static void rt2x00lib_intf_scheduled(struct work_struct *work)
/*
* Interrupt context handlers.
*/
-static void rt2x00lib_beacondone_iter(void *data, u8 *mac,
- struct ieee80211_vif *vif)
+static void rt2x00lib_bc_buffer_iter(void *data, u8 *mac,
+ struct ieee80211_vif *vif)
{
- struct rt2x00_intf *intf = vif_to_intf(vif);
+ struct rt2x00_dev *rt2x00dev = data;
+ struct sk_buff *skb;
+
+ /*
+ * Only AP mode interfaces do broad- and multicast buffering
+ */
+ if (vif->type != NL80211_IFTYPE_AP)
+ return;
+
+ /*
+ * Send out buffered broad- and multicast frames
+ */
+ skb = ieee80211_get_buffered_bc(rt2x00dev->hw, vif);
+ while (skb) {
+ rt2x00mac_tx(rt2x00dev->hw, skb);
+ skb = ieee80211_get_buffered_bc(rt2x00dev->hw, vif);
+ }
+}
+
+static void rt2x00lib_beaconupdate_iter(void *data, u8 *mac,
+ struct ieee80211_vif *vif)
+{
+ struct rt2x00_dev *rt2x00dev = data;
if (vif->type != NL80211_IFTYPE_AP &&
vif->type != NL80211_IFTYPE_ADHOC &&
@@ -179,9 +211,7 @@ static void rt2x00lib_beacondone_iter(void *data, u8 *mac,
vif->type != NL80211_IFTYPE_WDS)
return;
- spin_lock(&intf->lock);
- intf->delayed_flags |= DELAYED_UPDATE_BEACON;
- spin_unlock(&intf->lock);
+ rt2x00queue_update_beacon(rt2x00dev, vif, true);
}
void rt2x00lib_beacondone(struct rt2x00_dev *rt2x00dev)
@@ -189,14 +219,37 @@ void rt2x00lib_beacondone(struct rt2x00_dev *rt2x00dev)
if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
return;
- ieee80211_iterate_active_interfaces_atomic(rt2x00dev->hw,
- rt2x00lib_beacondone_iter,
- rt2x00dev);
+ /* send buffered bc/mc frames out for every bssid */
+ ieee80211_iterate_active_interfaces(rt2x00dev->hw,
+ rt2x00lib_bc_buffer_iter,
+ rt2x00dev);
+ /*
+ * Devices with pre tbtt interrupt don't need to update the beacon
+ * here as they will fetch the next beacon directly prior to
+ * transmission.
+ */
+ if (test_bit(DRIVER_SUPPORT_PRE_TBTT_INTERRUPT, &rt2x00dev->flags))
+ return;
- ieee80211_queue_work(rt2x00dev->hw, &rt2x00dev->intf_work);
+ /* fetch next beacon */
+ ieee80211_iterate_active_interfaces(rt2x00dev->hw,
+ rt2x00lib_beaconupdate_iter,
+ rt2x00dev);
}
EXPORT_SYMBOL_GPL(rt2x00lib_beacondone);
+void rt2x00lib_pretbtt(struct rt2x00_dev *rt2x00dev)
+{
+ if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
+ return;
+
+ /* fetch next beacon */
+ ieee80211_iterate_active_interfaces(rt2x00dev->hw,
+ rt2x00lib_beaconupdate_iter,
+ rt2x00dev);
+}
+EXPORT_SYMBOL_GPL(rt2x00lib_pretbtt);
+
void rt2x00lib_txdone(struct queue_entry *entry,
struct txdone_entry_desc *txdesc)
{
@@ -216,6 +269,16 @@ void rt2x00lib_txdone(struct queue_entry *entry,
rt2x00queue_unmap_skb(rt2x00dev, entry->skb);
/*
+ * Remove the extra tx headroom from the skb.
+ */
+ skb_pull(entry->skb, rt2x00dev->ops->extra_tx_headroom);
+
+ /*
+ * Signal that the TX descriptor is no longer in the skb.
+ */
+ skbdesc->flags &= ~SKBDESC_DESC_IN_SKB;
+
+ /*
* Remove L2 padding which was added during
*/
if (test_bit(DRIVER_REQUIRE_L2PAD, &rt2x00dev->flags))
@@ -224,7 +287,7 @@ void rt2x00lib_txdone(struct queue_entry *entry,
/*
* If the IV/EIV data was stripped from the frame before it was
* passed to the hardware, we should now reinsert it again because
- * mac80211 will expect the the same data to be present it the
+ * mac80211 will expect the same data to be present it the
* frame as it was passed to us.
*/
if (test_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags))
@@ -241,8 +304,7 @@ void rt2x00lib_txdone(struct queue_entry *entry,
*/
success =
test_bit(TXDONE_SUCCESS, &txdesc->flags) ||
- test_bit(TXDONE_UNKNOWN, &txdesc->flags) ||
- test_bit(TXDONE_FALLBACK, &txdesc->flags);
+ test_bit(TXDONE_UNKNOWN, &txdesc->flags);
/*
* Update TX statistics.
@@ -264,11 +326,22 @@ void rt2x00lib_txdone(struct queue_entry *entry,
/*
* Frame was send with retries, hardware tried
* different rates to send out the frame, at each
- * retry it lowered the rate 1 step.
+ * retry it lowered the rate 1 step except when the
+ * lowest rate was used.
*/
for (i = 0; i < retry_rates && i < IEEE80211_TX_MAX_RATES; i++) {
tx_info->status.rates[i].idx = rate_idx - i;
tx_info->status.rates[i].flags = rate_flags;
+
+ if (rate_idx - i == 0) {
+ /*
+ * The lowest rate (index 0) was used until the
+ * number of max retries was reached.
+ */
+ tx_info->status.rates[i].count = retry_rates - i;
+ i++;
+ break;
+ }
tx_info->status.rates[i].count = 1;
}
if (i < (IEEE80211_TX_MAX_RATES - 1))
@@ -281,6 +354,21 @@ void rt2x00lib_txdone(struct queue_entry *entry,
rt2x00dev->low_level_stats.dot11ACKFailureCount++;
}
+ /*
+ * Every single frame has it's own tx status, hence report
+ * every frame as ampdu of size 1.
+ *
+ * TODO: if we can find out how many frames were aggregated
+ * by the hw we could provide the real ampdu_len to mac80211
+ * which would allow the rc algorithm to better decide on
+ * which rates are suitable.
+ */
+ if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) {
+ tx_info->flags |= IEEE80211_TX_STAT_AMPDU;
+ tx_info->status.ampdu_len = 1;
+ tx_info->status.ampdu_ack_len = success ? 1 : 0;
+ }
+
if (rate_flags & IEEE80211_TX_RC_USE_RTS_CTS) {
if (success)
rt2x00dev->low_level_stats.dot11RTSSuccessCount++;
@@ -295,9 +383,17 @@ void rt2x00lib_txdone(struct queue_entry *entry,
* send the status report back.
*/
if (!(skbdesc_flags & SKBDESC_NOT_MAC80211))
- ieee80211_tx_status_irqsafe(rt2x00dev->hw, entry->skb);
+ /*
+ * Only PCI and SOC devices process the tx status in process
+ * context. Hence use ieee80211_tx_status for PCI and SOC
+ * devices and stick to ieee80211_tx_status_irqsafe for USB.
+ */
+ if (rt2x00_is_usb(rt2x00dev))
+ ieee80211_tx_status_irqsafe(rt2x00dev->hw, entry->skb);
+ else
+ ieee80211_tx_status(rt2x00dev->hw, entry->skb);
else
- dev_kfree_skb_irq(entry->skb);
+ dev_kfree_skb_any(entry->skb);
/*
* Make this entry available for reuse.
@@ -444,7 +540,16 @@ void rt2x00lib_rxdone(struct rt2x00_dev *rt2x00dev,
*/
rt2x00debug_dump_frame(rt2x00dev, DUMP_FRAME_RXDONE, entry->skb);
memcpy(IEEE80211_SKB_RXCB(entry->skb), rx_status, sizeof(*rx_status));
- ieee80211_rx_irqsafe(rt2x00dev->hw, entry->skb);
+
+ /*
+ * Currently only PCI and SOC devices handle rx interrupts in process
+ * context. Hence, use ieee80211_rx_irqsafe for USB and ieee80211_rx_ni
+ * for PCI and SOC devices.
+ */
+ if (rt2x00_is_usb(rt2x00dev))
+ ieee80211_rx_irqsafe(rt2x00dev->hw, entry->skb);
+ else
+ ieee80211_rx_ni(rt2x00dev->hw, entry->skb);
/*
* Replace the skb with the freshly allocated one.
diff --git a/drivers/net/wireless/rt2x00/rt2x00dump.h b/drivers/net/wireless/rt2x00/rt2x00dump.h
index ed303b423e4..5d6e0b83151 100644
--- a/drivers/net/wireless/rt2x00/rt2x00dump.h
+++ b/drivers/net/wireless/rt2x00/rt2x00dump.h
@@ -20,7 +20,12 @@
/*
Module: rt2x00dump
- Abstract: Data structures for the rt2x00debug & userspace.
+ Abstract:
+ Data structures for the rt2x00debug & userspace.
+
+ The declarations in this file can be used by both rt2x00
+ and userspace and therefore should be kept together in
+ this file.
*/
#ifndef RT2X00DUMP_H
@@ -111,7 +116,7 @@ struct rt2x00dump_hdr {
__le16 chip_rt;
__le16 chip_rf;
- __le32 chip_rev;
+ __le16 chip_rev;
__le16 type;
__u8 queue_index;
diff --git a/drivers/net/wireless/rt2x00/rt2x00ht.c b/drivers/net/wireless/rt2x00/rt2x00ht.c
index 5a407602ce3..c004cd3a884 100644
--- a/drivers/net/wireless/rt2x00/rt2x00ht.c
+++ b/drivers/net/wireless/rt2x00/rt2x00ht.c
@@ -44,11 +44,22 @@ void rt2x00ht_create_tx_descriptor(struct queue_entry *entry,
txdesc->mpdu_density = 0;
txdesc->ba_size = 7; /* FIXME: What value is needed? */
- txdesc->stbc = 0; /* FIXME: What value is needed? */
- txdesc->mcs = rt2x00_get_rate_mcs(hwrate->mcs);
- if (txrate->flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE)
- txdesc->mcs |= 0x08;
+ txdesc->stbc =
+ (tx_info->flags & IEEE80211_TX_CTL_STBC) >> IEEE80211_TX_CTL_STBC_SHIFT;
+
+ /*
+ * If IEEE80211_TX_RC_MCS is set txrate->idx just contains the
+ * mcs rate to be used
+ */
+ if (txrate->flags & IEEE80211_TX_RC_MCS) {
+ txdesc->mcs = txrate->idx;
+ } else {
+ txdesc->mcs = rt2x00_get_rate_mcs(hwrate->mcs);
+ if (txrate->flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE)
+ txdesc->mcs |= 0x08;
+ }
+
/*
* Convert flags
@@ -84,3 +95,31 @@ void rt2x00ht_create_tx_descriptor(struct queue_entry *entry,
else
txdesc->txop = TXOP_HTTXOP;
}
+
+u16 rt2x00ht_center_channel(struct rt2x00_dev *rt2x00dev,
+ struct ieee80211_conf *conf)
+{
+ struct hw_mode_spec *spec = &rt2x00dev->spec;
+ int center_channel;
+ u16 i;
+
+ /*
+ * Initialize center channel to current channel.
+ */
+ center_channel = spec->channels[conf->channel->hw_value].channel;
+
+ /*
+ * Adjust center channel to HT40+ and HT40- operation.
+ */
+ if (conf_is_ht40_plus(conf))
+ center_channel += 2;
+ else if (conf_is_ht40_minus(conf))
+ center_channel -= (center_channel == 14) ? 1 : 2;
+
+ for (i = 0; i < spec->num_channels; i++)
+ if (spec->channels[i].channel == center_channel)
+ return i;
+
+ WARN_ON(1);
+ return conf->channel->hw_value;
+}
diff --git a/drivers/net/wireless/rt2x00/rt2x00lib.h b/drivers/net/wireless/rt2x00/rt2x00lib.h
index be2e37fb407..dc5c6574aaf 100644
--- a/drivers/net/wireless/rt2x00/rt2x00lib.h
+++ b/drivers/net/wireless/rt2x00/rt2x00lib.h
@@ -27,11 +27,10 @@
#ifndef RT2X00LIB_H
#define RT2X00LIB_H
-#include "rt2x00dump.h"
-
/*
* Interval defines
*/
+#define WATCHDOG_INTERVAL round_jiffies_relative(HZ)
#define LINK_TUNE_INTERVAL round_jiffies_relative(HZ)
/*
@@ -107,13 +106,6 @@ struct sk_buff *rt2x00queue_alloc_rxskb(struct rt2x00_dev *rt2x00dev,
struct queue_entry *entry);
/**
- * rt2x00queue_unmap_skb - Unmap a skb from DMA.
- * @rt2x00dev: Pointer to &struct rt2x00_dev.
- * @skb: The skb to unmap.
- */
-void rt2x00queue_unmap_skb(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb);
-
-/**
* rt2x00queue_free_skb - free a skb
* @rt2x00dev: Pointer to &struct rt2x00_dev.
* @skb: The skb to free.
@@ -266,11 +258,30 @@ void rt2x00link_stop_tuner(struct rt2x00_dev *rt2x00dev);
void rt2x00link_reset_tuner(struct rt2x00_dev *rt2x00dev, bool antenna);
/**
- * rt2x00link_register - Initialize link tuning functionality
+ * rt2x00link_start_watchdog - Start periodic watchdog monitoring
+ * @rt2x00dev: Pointer to &struct rt2x00_dev.
+ *
+ * This start the watchdog periodic work, this work will
+ *be executed periodically until &rt2x00link_stop_watchdog has
+ * been called.
+ */
+void rt2x00link_start_watchdog(struct rt2x00_dev *rt2x00dev);
+
+/**
+ * rt2x00link_stop_watchdog - Stop periodic watchdog monitoring
* @rt2x00dev: Pointer to &struct rt2x00_dev.
*
- * Initialize work structure and all link tuning related
- * parameters. This will not start the link tuning process itself.
+ * After this function completed the watchdog monitoring will not
+ * be running until &rt2x00link_start_watchdog is called.
+ */
+void rt2x00link_stop_watchdog(struct rt2x00_dev *rt2x00dev);
+
+/**
+ * rt2x00link_register - Initialize link tuning & watchdog functionality
+ * @rt2x00dev: Pointer to &struct rt2x00_dev.
+ *
+ * Initialize work structure and all link tuning and watchdog related
+ * parameters. This will not start the periodic work itself.
*/
void rt2x00link_register(struct rt2x00_dev *rt2x00dev);
@@ -296,8 +307,6 @@ static inline void rt2x00lib_free_firmware(struct rt2x00_dev *rt2x00dev)
#ifdef CONFIG_RT2X00_LIB_DEBUGFS
void rt2x00debug_register(struct rt2x00_dev *rt2x00dev);
void rt2x00debug_deregister(struct rt2x00_dev *rt2x00dev);
-void rt2x00debug_dump_frame(struct rt2x00_dev *rt2x00dev,
- enum rt2x00_dump_type type, struct sk_buff *skb);
void rt2x00debug_update_crypto(struct rt2x00_dev *rt2x00dev,
struct rxdone_entry_desc *rxdesc);
#else
@@ -309,12 +318,6 @@ static inline void rt2x00debug_deregister(struct rt2x00_dev *rt2x00dev)
{
}
-static inline void rt2x00debug_dump_frame(struct rt2x00_dev *rt2x00dev,
- enum rt2x00_dump_type type,
- struct sk_buff *skb)
-{
-}
-
static inline void rt2x00debug_update_crypto(struct rt2x00_dev *rt2x00dev,
struct rxdone_entry_desc *rxdesc)
{
@@ -384,12 +387,21 @@ static inline void rt2x00crypto_rx_insert_iv(struct sk_buff *skb,
void rt2x00ht_create_tx_descriptor(struct queue_entry *entry,
struct txentry_desc *txdesc,
const struct rt2x00_rate *hwrate);
+
+u16 rt2x00ht_center_channel(struct rt2x00_dev *rt2x00dev,
+ struct ieee80211_conf *conf);
#else
static inline void rt2x00ht_create_tx_descriptor(struct queue_entry *entry,
struct txentry_desc *txdesc,
const struct rt2x00_rate *hwrate)
{
}
+
+static inline u16 rt2x00ht_center_channel(struct rt2x00_dev *rt2x00dev,
+ struct ieee80211_conf *conf)
+{
+ return conf->channel->hw_value;
+}
#endif /* CONFIG_RT2X00_LIB_HT */
/*
diff --git a/drivers/net/wireless/rt2x00/rt2x00link.c b/drivers/net/wireless/rt2x00/rt2x00link.c
index 0efbf5a6c25..666cef3f847 100644
--- a/drivers/net/wireless/rt2x00/rt2x00link.c
+++ b/drivers/net/wireless/rt2x00/rt2x00link.c
@@ -271,11 +271,20 @@ void rt2x00link_start_tuner(struct rt2x00_dev *rt2x00dev)
/*
* Link tuning should only be performed when
- * an active sta or master interface exists.
- * Single monitor mode interfaces should never have
- * work with link tuners.
+ * an active sta interface exists. AP interfaces
+ * don't need link tuning and monitor mode interfaces
+ * should never have to work with link tuners.
*/
- if (!rt2x00dev->intf_ap_count && !rt2x00dev->intf_sta_count)
+ if (!rt2x00dev->intf_sta_count)
+ return;
+
+ /**
+ * While scanning, link tuning is disabled. By default
+ * the most sensitive settings will be used to make sure
+ * that all beacons and probe responses will be recieved
+ * during the scan.
+ */
+ if (test_bit(DEVICE_STATE_SCANNING, &rt2x00dev->flags))
return;
rt2x00link_reset_tuner(rt2x00dev, false);
@@ -293,6 +302,7 @@ void rt2x00link_stop_tuner(struct rt2x00_dev *rt2x00dev)
void rt2x00link_reset_tuner(struct rt2x00_dev *rt2x00dev, bool antenna)
{
struct link_qual *qual = &rt2x00dev->link.qual;
+ u8 vgc_level = qual->vgc_level_reg;
if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
return;
@@ -309,6 +319,13 @@ void rt2x00link_reset_tuner(struct rt2x00_dev *rt2x00dev, bool antenna)
memset(qual, 0, sizeof(*qual));
/*
+ * Restore the VGC level as stored in the registers,
+ * the driver can use this to determine if the register
+ * must be updated during reset or not.
+ */
+ qual->vgc_level_reg = vgc_level;
+
+ /*
* Reset the link tuner.
*/
rt2x00dev->ops->lib->reset_tuner(rt2x00dev, qual);
@@ -338,7 +355,8 @@ static void rt2x00link_tuner(struct work_struct *work)
* When the radio is shutting down we should
* immediately cease all link tuning.
*/
- if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
+ if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags) ||
+ test_bit(DEVICE_STATE_SCANNING, &rt2x00dev->flags))
return;
/*
@@ -359,10 +377,11 @@ static void rt2x00link_tuner(struct work_struct *work)
qual->rssi = link->avg_rssi.avg;
/*
- * Only perform the link tuning when Link tuning
- * has been enabled (This could have been disabled from the EEPROM).
+ * Check if link tuning is supported by the hardware, some hardware
+ * do not support link tuning at all, while other devices can disable
+ * the feature from the EEPROM.
*/
- if (!test_bit(CONFIG_DISABLE_LINK_TUNING, &rt2x00dev->flags))
+ if (test_bit(DRIVER_SUPPORT_LINK_TUNING, &rt2x00dev->flags))
rt2x00dev->ops->lib->link_tuner(rt2x00dev, qual, link->count);
/*
@@ -388,7 +407,45 @@ static void rt2x00link_tuner(struct work_struct *work)
&link->work, LINK_TUNE_INTERVAL);
}
+void rt2x00link_start_watchdog(struct rt2x00_dev *rt2x00dev)
+{
+ struct link *link = &rt2x00dev->link;
+
+ if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags) ||
+ !test_bit(DRIVER_SUPPORT_WATCHDOG, &rt2x00dev->flags))
+ return;
+
+ ieee80211_queue_delayed_work(rt2x00dev->hw,
+ &link->watchdog_work, WATCHDOG_INTERVAL);
+}
+
+void rt2x00link_stop_watchdog(struct rt2x00_dev *rt2x00dev)
+{
+ cancel_delayed_work_sync(&rt2x00dev->link.watchdog_work);
+}
+
+static void rt2x00link_watchdog(struct work_struct *work)
+{
+ struct rt2x00_dev *rt2x00dev =
+ container_of(work, struct rt2x00_dev, link.watchdog_work.work);
+ struct link *link = &rt2x00dev->link;
+
+ /*
+ * When the radio is shutting down we should
+ * immediately cease the watchdog monitoring.
+ */
+ if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
+ return;
+
+ rt2x00dev->ops->lib->watchdog(rt2x00dev);
+
+ if (test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags))
+ ieee80211_queue_delayed_work(rt2x00dev->hw,
+ &link->watchdog_work, WATCHDOG_INTERVAL);
+}
+
void rt2x00link_register(struct rt2x00_dev *rt2x00dev)
{
+ INIT_DELAYED_WORK(&rt2x00dev->link.watchdog_work, rt2x00link_watchdog);
INIT_DELAYED_WORK(&rt2x00dev->link.work, rt2x00link_tuner);
}
diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c
index abbd857ec75..235e037e650 100644
--- a/drivers/net/wireless/rt2x00/rt2x00mac.c
+++ b/drivers/net/wireless/rt2x00/rt2x00mac.c
@@ -273,16 +273,24 @@ int rt2x00mac_add_interface(struct ieee80211_hw *hw,
mutex_init(&intf->beacon_skb_mutex);
intf->beacon = entry;
- if (vif->type == NL80211_IFTYPE_AP)
- memcpy(&intf->bssid, vif->addr, ETH_ALEN);
- memcpy(&intf->mac, vif->addr, ETH_ALEN);
-
/*
* The MAC adddress must be configured after the device
* has been initialized. Otherwise the device can reset
* the MAC registers.
+ * The BSSID address must only be configured in AP mode,
+ * however we should not send an empty BSSID address for
+ * STA interfaces at this time, since this can cause
+ * invalid behavior in the device.
*/
- rt2x00lib_config_intf(rt2x00dev, intf, vif->type, intf->mac, NULL);
+ memcpy(&intf->mac, vif->addr, ETH_ALEN);
+ if (vif->type == NL80211_IFTYPE_AP) {
+ memcpy(&intf->bssid, vif->addr, ETH_ALEN);
+ rt2x00lib_config_intf(rt2x00dev, intf, vif->type,
+ intf->mac, intf->bssid);
+ } else {
+ rt2x00lib_config_intf(rt2x00dev, intf, vif->type,
+ intf->mac, NULL);
+ }
/*
* Some filters depend on the current working mode. We can force
@@ -346,9 +354,11 @@ int rt2x00mac_config(struct ieee80211_hw *hw, u32 changed)
/*
* Some configuration parameters (e.g. channel and antenna values) can
* only be set when the radio is enabled, but do require the RX to
- * be off.
+ * be off. During this period we should keep link tuning enabled,
+ * if for any reason the link tuner must be reset, this will be
+ * handled by rt2x00lib_config().
*/
- rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_OFF);
+ rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_OFF_LINK);
/*
* When we've just turned on the radio, we want to reprogram
@@ -366,7 +376,7 @@ int rt2x00mac_config(struct ieee80211_hw *hw, u32 changed)
rt2x00lib_config_antenna(rt2x00dev, rt2x00dev->default_ant);
/* Turn RX back on */
- rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_ON);
+ rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_ON_LINK);
return 0;
}
@@ -430,12 +440,36 @@ void rt2x00mac_configure_filter(struct ieee80211_hw *hw,
}
EXPORT_SYMBOL_GPL(rt2x00mac_configure_filter);
+static void rt2x00mac_set_tim_iter(void *data, u8 *mac,
+ struct ieee80211_vif *vif)
+{
+ struct rt2x00_intf *intf = vif_to_intf(vif);
+
+ if (vif->type != NL80211_IFTYPE_AP &&
+ vif->type != NL80211_IFTYPE_ADHOC &&
+ vif->type != NL80211_IFTYPE_MESH_POINT &&
+ vif->type != NL80211_IFTYPE_WDS)
+ return;
+
+ spin_lock(&intf->lock);
+ intf->delayed_flags |= DELAYED_UPDATE_BEACON;
+ spin_unlock(&intf->lock);
+}
+
int rt2x00mac_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta,
bool set)
{
struct rt2x00_dev *rt2x00dev = hw->priv;
- rt2x00lib_beacondone(rt2x00dev);
+ if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
+ return 0;
+
+ ieee80211_iterate_active_interfaces_atomic(rt2x00dev->hw,
+ rt2x00mac_set_tim_iter,
+ rt2x00dev);
+
+ /* queue work to upodate the beacon template */
+ ieee80211_queue_work(rt2x00dev->hw, &rt2x00dev->intf_work);
return 0;
}
EXPORT_SYMBOL_GPL(rt2x00mac_set_tim);
@@ -539,6 +573,22 @@ int rt2x00mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
EXPORT_SYMBOL_GPL(rt2x00mac_set_key);
#endif /* CONFIG_RT2X00_LIB_CRYPTO */
+void rt2x00mac_sw_scan_start(struct ieee80211_hw *hw)
+{
+ struct rt2x00_dev *rt2x00dev = hw->priv;
+ __set_bit(DEVICE_STATE_SCANNING, &rt2x00dev->flags);
+ rt2x00link_stop_tuner(rt2x00dev);
+}
+EXPORT_SYMBOL_GPL(rt2x00mac_sw_scan_start);
+
+void rt2x00mac_sw_scan_complete(struct ieee80211_hw *hw)
+{
+ struct rt2x00_dev *rt2x00dev = hw->priv;
+ __clear_bit(DEVICE_STATE_SCANNING, &rt2x00dev->flags);
+ rt2x00link_start_tuner(rt2x00dev);
+}
+EXPORT_SYMBOL_GPL(rt2x00mac_sw_scan_complete);
+
int rt2x00mac_get_stats(struct ieee80211_hw *hw,
struct ieee80211_low_level_stats *stats)
{
@@ -562,7 +612,6 @@ void rt2x00mac_bss_info_changed(struct ieee80211_hw *hw,
{
struct rt2x00_dev *rt2x00dev = hw->priv;
struct rt2x00_intf *intf = vif_to_intf(vif);
- int update_bssid = 0;
/*
* mac80211 might be calling this function while we are trying
@@ -577,10 +626,8 @@ void rt2x00mac_bss_info_changed(struct ieee80211_hw *hw,
* conf->bssid can be NULL if coming from the internal
* beacon update routine.
*/
- if (changes & BSS_CHANGED_BSSID) {
- update_bssid = 1;
+ if (changes & BSS_CHANGED_BSSID)
memcpy(&intf->bssid, bss_conf->bssid, ETH_ALEN);
- }
spin_unlock(&intf->lock);
@@ -592,7 +639,7 @@ void rt2x00mac_bss_info_changed(struct ieee80211_hw *hw,
*/
if (changes & BSS_CHANGED_BSSID)
rt2x00lib_config_intf(rt2x00dev, intf, vif->type, NULL,
- update_bssid ? bss_conf->bssid : NULL);
+ bss_conf->bssid);
/*
* Update the beacon.
diff --git a/drivers/net/wireless/rt2x00/rt2x00pci.c b/drivers/net/wireless/rt2x00/rt2x00pci.c
index f71eee67f97..19b262e1ddb 100644
--- a/drivers/net/wireless/rt2x00/rt2x00pci.c
+++ b/drivers/net/wireless/rt2x00/rt2x00pci.c
@@ -60,34 +60,6 @@ int rt2x00pci_regbusy_read(struct rt2x00_dev *rt2x00dev,
}
EXPORT_SYMBOL_GPL(rt2x00pci_regbusy_read);
-/*
- * TX data handlers.
- */
-int rt2x00pci_write_tx_data(struct queue_entry *entry,
- struct txentry_desc *txdesc)
-{
- struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
-
- /*
- * This should not happen, we already checked the entry
- * was ours. When the hardware disagrees there has been
- * a queue corruption!
- */
- if (unlikely(rt2x00dev->ops->lib->get_entry_state(entry))) {
- ERROR(rt2x00dev,
- "Corrupt queue %d, accessing entry which is not ours.\n"
- "Please file bug report to %s.\n",
- entry->queue->qid, DRV_PROJECT);
- return -EINVAL;
- }
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(rt2x00pci_write_tx_data);
-
-/*
- * TX/RX data handlers.
- */
void rt2x00pci_rxdone(struct rt2x00_dev *rt2x00dev)
{
struct data_queue *queue = rt2x00dev->rx;
@@ -181,8 +153,10 @@ int rt2x00pci_initialize(struct rt2x00_dev *rt2x00dev)
/*
* Register interrupt handler.
*/
- status = request_irq(rt2x00dev->irq, rt2x00dev->ops->lib->irq_handler,
- IRQF_SHARED, rt2x00dev->name, rt2x00dev);
+ status = request_threaded_irq(rt2x00dev->irq,
+ rt2x00dev->ops->lib->irq_handler,
+ rt2x00dev->ops->lib->irq_handler_thread,
+ IRQF_SHARED, rt2x00dev->name, rt2x00dev);
if (status) {
ERROR(rt2x00dev, "IRQ %d allocation failed (error %d).\n",
rt2x00dev->irq, status);
@@ -305,7 +279,10 @@ int rt2x00pci_probe(struct pci_dev *pci_dev, const struct pci_device_id *id)
rt2x00dev->irq = pci_dev->irq;
rt2x00dev->name = pci_name(pci_dev);
- rt2x00_set_chip_intf(rt2x00dev, RT2X00_CHIP_INTF_PCI);
+ if (pci_dev->is_pcie)
+ rt2x00_set_chip_intf(rt2x00dev, RT2X00_CHIP_INTF_PCIE);
+ else
+ rt2x00_set_chip_intf(rt2x00dev, RT2X00_CHIP_INTF_PCI);
retval = rt2x00pci_alloc_reg(rt2x00dev);
if (retval)
diff --git a/drivers/net/wireless/rt2x00/rt2x00pci.h b/drivers/net/wireless/rt2x00/rt2x00pci.h
index 51bcef3839c..b854d62ff99 100644
--- a/drivers/net/wireless/rt2x00/rt2x00pci.h
+++ b/drivers/net/wireless/rt2x00/rt2x00pci.h
@@ -86,16 +86,6 @@ int rt2x00pci_regbusy_read(struct rt2x00_dev *rt2x00dev,
u32 *reg);
/**
- * rt2x00pci_write_tx_data - Initialize data for TX operation
- * @entry: The entry where the frame is located
- *
- * This function will initialize the DMA and skb descriptor
- * to prepare the entry for the actual TX operation.
- */
-int rt2x00pci_write_tx_data(struct queue_entry *entry,
- struct txentry_desc *txdesc);
-
-/**
* struct queue_entry_priv_pci: Per entry PCI specific information
*
* @desc: Pointer to device descriptor
diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c
index 20dbdd6fb90..a3401d30105 100644
--- a/drivers/net/wireless/rt2x00/rt2x00queue.c
+++ b/drivers/net/wireless/rt2x00/rt2x00queue.c
@@ -100,21 +100,8 @@ void rt2x00queue_map_txskb(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb)
{
struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb);
- /*
- * If device has requested headroom, we should make sure that
- * is also mapped to the DMA so it can be used for transfering
- * additional descriptor information to the hardware.
- */
- skb_push(skb, rt2x00dev->ops->extra_tx_headroom);
-
skbdesc->skb_dma =
dma_map_single(rt2x00dev->dev, skb->data, skb->len, DMA_TO_DEVICE);
-
- /*
- * Restore data pointer to original location again.
- */
- skb_pull(skb, rt2x00dev->ops->extra_tx_headroom);
-
skbdesc->flags |= SKBDESC_DMA_MAPPED_TX;
}
EXPORT_SYMBOL_GPL(rt2x00queue_map_txskb);
@@ -130,16 +117,12 @@ void rt2x00queue_unmap_skb(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb)
}
if (skbdesc->flags & SKBDESC_DMA_MAPPED_TX) {
- /*
- * Add headroom to the skb length, it has been removed
- * by the driver, but it was actually mapped to DMA.
- */
- dma_unmap_single(rt2x00dev->dev, skbdesc->skb_dma,
- skb->len + rt2x00dev->ops->extra_tx_headroom,
+ dma_unmap_single(rt2x00dev->dev, skbdesc->skb_dma, skb->len,
DMA_TO_DEVICE);
skbdesc->flags &= ~SKBDESC_DMA_MAPPED_TX;
}
}
+EXPORT_SYMBOL_GPL(rt2x00queue_unmap_skb);
void rt2x00queue_free_skb(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb)
{
@@ -370,13 +353,18 @@ static void rt2x00queue_create_tx_descriptor(struct queue_entry *entry,
/*
* Check if more fragments are pending
*/
- if (ieee80211_has_morefrags(hdr->frame_control) ||
- (tx_info->flags & IEEE80211_TX_CTL_MORE_FRAMES)) {
+ if (ieee80211_has_morefrags(hdr->frame_control)) {
__set_bit(ENTRY_TXD_BURST, &txdesc->flags);
__set_bit(ENTRY_TXD_MORE_FRAG, &txdesc->flags);
}
/*
+ * Check if more frames (!= fragments) are pending
+ */
+ if (tx_info->flags & IEEE80211_TX_CTL_MORE_FRAMES)
+ __set_bit(ENTRY_TXD_BURST, &txdesc->flags);
+
+ /*
* Beacons and probe responses require the tsf timestamp
* to be inserted into the frame, except for a frame that has been injected
* through a monitor interface. This latter is needed for testing a
@@ -416,12 +404,51 @@ static void rt2x00queue_create_tx_descriptor(struct queue_entry *entry,
rt2x00queue_create_tx_descriptor_plcp(entry, txdesc, hwrate);
}
+static int rt2x00queue_write_tx_data(struct queue_entry *entry,
+ struct txentry_desc *txdesc)
+{
+ struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
+
+ /*
+ * This should not happen, we already checked the entry
+ * was ours. When the hardware disagrees there has been
+ * a queue corruption!
+ */
+ if (unlikely(rt2x00dev->ops->lib->get_entry_state &&
+ rt2x00dev->ops->lib->get_entry_state(entry))) {
+ ERROR(rt2x00dev,
+ "Corrupt queue %d, accessing entry which is not ours.\n"
+ "Please file bug report to %s.\n",
+ entry->queue->qid, DRV_PROJECT);
+ return -EINVAL;
+ }
+
+ /*
+ * Add the requested extra tx headroom in front of the skb.
+ */
+ skb_push(entry->skb, rt2x00dev->ops->extra_tx_headroom);
+ memset(entry->skb->data, 0, rt2x00dev->ops->extra_tx_headroom);
+
+ /*
+ * Call the driver's write_tx_data function, if it exists.
+ */
+ if (rt2x00dev->ops->lib->write_tx_data)
+ rt2x00dev->ops->lib->write_tx_data(entry, txdesc);
+
+ /*
+ * Map the skb to DMA.
+ */
+ if (test_bit(DRIVER_REQUIRE_DMA, &rt2x00dev->flags))
+ rt2x00queue_map_txskb(rt2x00dev, entry->skb);
+
+ return 0;
+}
+
static void rt2x00queue_write_tx_descriptor(struct queue_entry *entry,
struct txentry_desc *txdesc)
{
struct data_queue *queue = entry->queue;
struct rt2x00_dev *rt2x00dev = queue->rt2x00dev;
- enum rt2x00_dump_type dump_type;
rt2x00dev->ops->lib->write_tx_desc(rt2x00dev, entry->skb, txdesc);
@@ -429,9 +456,7 @@ static void rt2x00queue_write_tx_descriptor(struct queue_entry *entry,
* All processing on the frame has been completed, this means
* it is now ready to be dumped to userspace through debugfs.
*/
- dump_type = (txdesc->queue == QID_BEACON) ?
- DUMP_FRAME_BEACON : DUMP_FRAME_TX;
- rt2x00debug_dump_frame(rt2x00dev, dump_type, entry->skb);
+ rt2x00debug_dump_frame(rt2x00dev, DUMP_FRAME_TX, entry->skb);
}
static void rt2x00queue_kick_tx_queue(struct queue_entry *entry,
@@ -530,16 +555,12 @@ int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb,
* call failed. Since we always return NETDEV_TX_OK to mac80211,
* this frame will simply be dropped.
*/
- if (unlikely(queue->rt2x00dev->ops->lib->write_tx_data(entry,
- &txdesc))) {
+ if (unlikely(rt2x00queue_write_tx_data(entry, &txdesc))) {
clear_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags);
entry->skb = NULL;
return -EIO;
}
- if (test_bit(DRIVER_REQUIRE_DMA, &queue->rt2x00dev->flags))
- rt2x00queue_map_txskb(queue->rt2x00dev, skb);
-
set_bit(ENTRY_DATA_PENDING, &entry->flags);
rt2x00queue_index_inc(queue, Q_INDEX);
@@ -595,11 +616,6 @@ int rt2x00queue_update_beacon(struct rt2x00_dev *rt2x00dev,
skbdesc->entry = intf->beacon;
/*
- * Write TX descriptor into reserved room in front of the beacon.
- */
- rt2x00queue_write_tx_descriptor(intf->beacon, &txdesc);
-
- /*
* Send beacon to hardware and enable beacon genaration..
*/
rt2x00dev->ops->lib->write_beacon(intf->beacon, &txdesc);
@@ -672,9 +688,11 @@ void rt2x00queue_index_inc(struct data_queue *queue, enum queue_index index)
if (index == Q_INDEX) {
queue->length++;
+ queue->last_index = jiffies;
} else if (index == Q_INDEX_DONE) {
queue->length--;
queue->count++;
+ queue->last_index_done = jiffies;
}
spin_unlock_irqrestore(&queue->lock, irqflags);
@@ -688,6 +706,8 @@ static void rt2x00queue_reset(struct data_queue *queue)
queue->count = 0;
queue->length = 0;
+ queue->last_index = jiffies;
+ queue->last_index_done = jiffies;
memset(queue->index, 0, sizeof(queue->index));
spin_unlock_irqrestore(&queue->lock, irqflags);
diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.h b/drivers/net/wireless/rt2x00/rt2x00queue.h
index f79170849ad..191e7775a9c 100644
--- a/drivers/net/wireless/rt2x00/rt2x00queue.h
+++ b/drivers/net/wireless/rt2x00/rt2x00queue.h
@@ -213,9 +213,16 @@ struct rxdone_entry_desc {
/**
* enum txdone_entry_desc_flags: Flags for &struct txdone_entry_desc
*
+ * Every txdone report has to contain the basic result of the
+ * transmission, either &TXDONE_UNKNOWN, &TXDONE_SUCCESS or
+ * &TXDONE_FAILURE. The flag &TXDONE_FALLBACK can be used in
+ * conjunction with all of these flags but should only be set
+ * if retires > 0. The flag &TXDONE_EXCESSIVE_RETRY can only be used
+ * in conjunction with &TXDONE_FAILURE.
+ *
* @TXDONE_UNKNOWN: Hardware could not determine success of transmission.
* @TXDONE_SUCCESS: Frame was successfully send
- * @TXDONE_FALLBACK: Frame was successfully send using a fallback rate.
+ * @TXDONE_FALLBACK: Hardware used fallback rates for retries
* @TXDONE_FAILURE: Frame was not successfully send
* @TXDONE_EXCESSIVE_RETRY: In addition to &TXDONE_FAILURE, the
* frame transmission failed due to excessive retries.
@@ -439,6 +446,8 @@ struct data_queue {
enum data_queue_qid qid;
spinlock_t lock;
+ unsigned long last_index;
+ unsigned long last_index_done;
unsigned int count;
unsigned short limit;
unsigned short threshold;
@@ -592,6 +601,15 @@ static inline int rt2x00queue_threshold(struct data_queue *queue)
}
/**
+ * rt2x00queue_timeout - Check if a timeout occured for this queue
+ * @queue: Queue to check.
+ */
+static inline int rt2x00queue_timeout(struct data_queue *queue)
+{
+ return time_after(queue->last_index, queue->last_index_done + (HZ / 10));
+}
+
+/**
* _rt2x00_desc_read - Read a word from the hardware descriptor.
* @desc: Base descriptor address
* @word: Word index from where the descriptor should be read.
diff --git a/drivers/net/wireless/rt2x00/rt2x00reg.h b/drivers/net/wireless/rt2x00/rt2x00reg.h
index b9fe94873ee..cef94621cef 100644
--- a/drivers/net/wireless/rt2x00/rt2x00reg.h
+++ b/drivers/net/wireless/rt2x00/rt2x00reg.h
@@ -63,7 +63,8 @@ enum led_mode {
enum tsf_sync {
TSF_SYNC_NONE = 0,
TSF_SYNC_INFRA = 1,
- TSF_SYNC_BEACON = 2,
+ TSF_SYNC_ADHOC = 2,
+ TSF_SYNC_AP_NONE = 3,
};
/*
@@ -88,6 +89,8 @@ enum dev_state {
STATE_RADIO_RX_OFF_LINK,
STATE_RADIO_IRQ_ON,
STATE_RADIO_IRQ_OFF,
+ STATE_RADIO_IRQ_ON_ISR,
+ STATE_RADIO_IRQ_OFF_ISR,
};
/*
diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.c b/drivers/net/wireless/rt2x00/rt2x00usb.c
index bd1546ba7ad..ff3a36622d1 100644
--- a/drivers/net/wireless/rt2x00/rt2x00usb.c
+++ b/drivers/net/wireless/rt2x00/rt2x00usb.c
@@ -113,26 +113,6 @@ int rt2x00usb_vendor_request_buff(struct rt2x00_dev *rt2x00dev,
const u16 offset, void *buffer,
const u16 buffer_length, const int timeout)
{
- int status;
-
- mutex_lock(&rt2x00dev->csr_mutex);
-
- status = rt2x00usb_vendor_req_buff_lock(rt2x00dev, request,
- requesttype, offset, buffer,
- buffer_length, timeout);
-
- mutex_unlock(&rt2x00dev->csr_mutex);
-
- return status;
-}
-EXPORT_SYMBOL_GPL(rt2x00usb_vendor_request_buff);
-
-int rt2x00usb_vendor_request_large_buff(struct rt2x00_dev *rt2x00dev,
- const u8 request, const u8 requesttype,
- const u16 offset, const void *buffer,
- const u16 buffer_length,
- const int timeout)
-{
int status = 0;
unsigned char *tb;
u16 off, len, bsize;
@@ -157,7 +137,7 @@ int rt2x00usb_vendor_request_large_buff(struct rt2x00_dev *rt2x00dev,
return status;
}
-EXPORT_SYMBOL_GPL(rt2x00usb_vendor_request_large_buff);
+EXPORT_SYMBOL_GPL(rt2x00usb_vendor_request_buff);
int rt2x00usb_regbusy_read(struct rt2x00_dev *rt2x00dev,
const unsigned int offset,
@@ -216,48 +196,28 @@ static void rt2x00usb_interrupt_txdone(struct urb *urb)
rt2x00lib_txdone(entry, &txdesc);
}
-int rt2x00usb_write_tx_data(struct queue_entry *entry,
- struct txentry_desc *txdesc)
+static inline void rt2x00usb_kick_tx_entry(struct queue_entry *entry)
{
struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
struct usb_device *usb_dev = to_usb_device_intf(rt2x00dev->dev);
struct queue_entry_priv_usb *entry_priv = entry->priv_data;
u32 length;
- /*
- * Add the descriptor in front of the skb.
- */
- skb_push(entry->skb, entry->queue->desc_size);
- memset(entry->skb->data, 0, entry->queue->desc_size);
-
- /*
- * USB devices cannot blindly pass the skb->len as the
- * length of the data to usb_fill_bulk_urb. Pass the skb
- * to the driver to determine what the length should be.
- */
- length = rt2x00dev->ops->lib->get_tx_data_len(entry);
-
- usb_fill_bulk_urb(entry_priv->urb, usb_dev,
- usb_sndbulkpipe(usb_dev, entry->queue->usb_endpoint),
- entry->skb->data, length,
- rt2x00usb_interrupt_txdone, entry);
-
- /*
- * Make sure the skb->data pointer points to the frame, not the
- * descriptor.
- */
- skb_pull(entry->skb, entry->queue->desc_size);
+ if (test_and_clear_bit(ENTRY_DATA_PENDING, &entry->flags)) {
+ /*
+ * USB devices cannot blindly pass the skb->len as the
+ * length of the data to usb_fill_bulk_urb. Pass the skb
+ * to the driver to determine what the length should be.
+ */
+ length = rt2x00dev->ops->lib->get_tx_data_len(entry);
- return 0;
-}
-EXPORT_SYMBOL_GPL(rt2x00usb_write_tx_data);
+ usb_fill_bulk_urb(entry_priv->urb, usb_dev,
+ usb_sndbulkpipe(usb_dev, entry->queue->usb_endpoint),
+ entry->skb->data, length,
+ rt2x00usb_interrupt_txdone, entry);
-static inline void rt2x00usb_kick_tx_entry(struct queue_entry *entry)
-{
- struct queue_entry_priv_usb *entry_priv = entry->priv_data;
-
- if (test_and_clear_bit(ENTRY_DATA_PENDING, &entry->flags))
usb_submit_urb(entry_priv->urb, GFP_ATOMIC);
+ }
}
void rt2x00usb_kick_tx_queue(struct rt2x00_dev *rt2x00dev,
@@ -332,6 +292,56 @@ void rt2x00usb_kill_tx_queue(struct rt2x00_dev *rt2x00dev,
}
EXPORT_SYMBOL_GPL(rt2x00usb_kill_tx_queue);
+static void rt2x00usb_watchdog_reset_tx(struct data_queue *queue)
+{
+ struct queue_entry_priv_usb *entry_priv;
+ unsigned short threshold = queue->threshold;
+
+ WARNING(queue->rt2x00dev, "TX queue %d timed out, invoke reset", queue->qid);
+
+ /*
+ * Temporarily disable the TX queue, this will force mac80211
+ * to use the other queues until this queue has been restored.
+ *
+ * Set the queue threshold to the queue limit. This prevents the
+ * queue from being enabled during the txdone handler.
+ */
+ queue->threshold = queue->limit;
+ ieee80211_stop_queue(queue->rt2x00dev->hw, queue->qid);
+
+ /*
+ * Reset all currently uploaded TX frames.
+ */
+ while (!rt2x00queue_empty(queue)) {
+ entry_priv = rt2x00queue_get_entry(queue, Q_INDEX_DONE)->priv_data;
+ usb_kill_urb(entry_priv->urb);
+
+ /*
+ * We need a short delay here to wait for
+ * the URB to be canceled and invoked the tx_done handler.
+ */
+ udelay(200);
+ }
+
+ /*
+ * The queue has been reset, and mac80211 is allowed to use the
+ * queue again.
+ */
+ queue->threshold = threshold;
+ ieee80211_wake_queue(queue->rt2x00dev->hw, queue->qid);
+}
+
+void rt2x00usb_watchdog(struct rt2x00_dev *rt2x00dev)
+{
+ struct data_queue *queue;
+
+ tx_queue_for_each(rt2x00dev, queue) {
+ if (rt2x00queue_timeout(queue))
+ rt2x00usb_watchdog_reset_tx(queue);
+ }
+}
+EXPORT_SYMBOL_GPL(rt2x00usb_watchdog);
+
/*
* RX data handlers.
*/
diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.h b/drivers/net/wireless/rt2x00/rt2x00usb.h
index 621d0f82925..d3d3ddc4087 100644
--- a/drivers/net/wireless/rt2x00/rt2x00usb.h
+++ b/drivers/net/wireless/rt2x00/rt2x00usb.h
@@ -167,25 +167,6 @@ int rt2x00usb_vendor_req_buff_lock(struct rt2x00_dev *rt2x00dev,
const u16 buffer_length, const int timeout);
/**
- * rt2x00usb_vendor_request_large_buff - Send register command to device (buffered)
- * @rt2x00dev: Pointer to &struct rt2x00_dev
- * @request: USB vendor command (See &enum rt2x00usb_vendor_request)
- * @requesttype: Request type &USB_VENDOR_REQUEST_*
- * @offset: Register start offset to perform action on
- * @buffer: Buffer where information will be read/written to by device
- * @buffer_length: Size of &buffer
- * @timeout: Operation timeout
- *
- * This function is used to transfer register data in blocks larger
- * then CSR_CACHE_SIZE. Use for firmware upload, keys and beacons.
- */
-int rt2x00usb_vendor_request_large_buff(struct rt2x00_dev *rt2x00dev,
- const u8 request, const u8 requesttype,
- const u16 offset, const void *buffer,
- const u16 buffer_length,
- const int timeout);
-
-/**
* rt2x00usb_vendor_request_sw - Send single register command to device
* @rt2x00dev: Pointer to &struct rt2x00_dev
* @request: USB vendor command (See &enum rt2x00usb_vendor_request)
@@ -370,16 +351,6 @@ int rt2x00usb_regbusy_read(struct rt2x00_dev *rt2x00dev,
void rt2x00usb_disable_radio(struct rt2x00_dev *rt2x00dev);
/**
- * rt2x00usb_write_tx_data - Initialize URB for TX operation
- * @entry: The entry where the frame is located
- *
- * This function will initialize the URB and skb descriptor
- * to prepare the entry for the actual TX operation.
- */
-int rt2x00usb_write_tx_data(struct queue_entry *entry,
- struct txentry_desc *txdesc);
-
-/**
* struct queue_entry_priv_usb: Per entry USB specific information
*
* @urb: Urb structure used for device communication.
@@ -428,6 +399,16 @@ void rt2x00usb_kick_tx_queue(struct rt2x00_dev *rt2x00dev,
void rt2x00usb_kill_tx_queue(struct rt2x00_dev *rt2x00dev,
const enum data_queue_qid qid);
+/**
+ * rt2x00usb_watchdog - Watchdog for USB communication
+ * @rt2x00dev: Pointer to &struct rt2x00_dev
+ *
+ * Check the health of the USB communication and determine
+ * if timeouts have occured. If this is the case, this function
+ * will reset all communication to restore functionality again.
+ */
+void rt2x00usb_watchdog(struct rt2x00_dev *rt2x00dev);
+
/*
* Device initialization handlers.
*/
diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c
index 6a74baf4e93..e539c6cb636 100644
--- a/drivers/net/wireless/rt2x00/rt61pci.c
+++ b/drivers/net/wireless/rt2x00/rt61pci.c
@@ -931,6 +931,9 @@ static void rt61pci_config_retry_limit(struct rt2x00_dev *rt2x00dev,
u32 reg;
rt2x00pci_register_read(rt2x00dev, TXRX_CSR4, &reg);
+ rt2x00_set_field32(&reg, TXRX_CSR4_OFDM_TX_RATE_DOWN, 1);
+ rt2x00_set_field32(&reg, TXRX_CSR4_OFDM_TX_RATE_STEP, 0);
+ rt2x00_set_field32(&reg, TXRX_CSR4_OFDM_TX_FALLBACK_CCK, 0);
rt2x00_set_field32(&reg, TXRX_CSR4_LONG_RETRY_LIMIT,
libconf->conf->long_frame_max_tx_count);
rt2x00_set_field32(&reg, TXRX_CSR4_SHORT_RETRY_LIMIT,
@@ -1619,7 +1622,8 @@ static void rt61pci_toggle_rx(struct rt2x00_dev *rt2x00dev,
static void rt61pci_toggle_irq(struct rt2x00_dev *rt2x00dev,
enum dev_state state)
{
- int mask = (state == STATE_RADIO_IRQ_OFF);
+ int mask = (state == STATE_RADIO_IRQ_OFF) ||
+ (state == STATE_RADIO_IRQ_OFF_ISR);
u32 reg;
/*
@@ -1736,7 +1740,9 @@ static int rt61pci_set_device_state(struct rt2x00_dev *rt2x00dev,
rt61pci_toggle_rx(rt2x00dev, state);
break;
case STATE_RADIO_IRQ_ON:
+ case STATE_RADIO_IRQ_ON_ISR:
case STATE_RADIO_IRQ_OFF:
+ case STATE_RADIO_IRQ_OFF_ISR:
rt61pci_toggle_irq(rt2x00dev, state);
break;
case STATE_DEEP_SLEEP:
@@ -1874,6 +1880,16 @@ static void rt61pci_write_beacon(struct queue_entry *entry,
rt2x00pci_register_write(rt2x00dev, TXRX_CSR9, reg);
/*
+ * Write the TX descriptor for the beacon.
+ */
+ rt61pci_write_tx_desc(rt2x00dev, entry->skb, txdesc);
+
+ /*
+ * Dump beacon to userspace through debugfs.
+ */
+ rt2x00debug_dump_frame(rt2x00dev, DUMP_FRAME_BEACON, entry->skb);
+
+ /*
* Write entire beacon with descriptor to register.
*/
beacon_base = HW_BEACON_OFFSET(entry->entry_idx);
@@ -2039,29 +2055,24 @@ static void rt61pci_txdone(struct rt2x00_dev *rt2x00dev)
struct txdone_entry_desc txdesc;
u32 word;
u32 reg;
- u32 old_reg;
int type;
int index;
+ int i;
/*
- * During each loop we will compare the freshly read
- * STA_CSR4 register value with the value read from
- * the previous loop. If the 2 values are equal then
- * we should stop processing because the chance is
- * quite big that the device has been unplugged and
- * we risk going into an endless loop.
+ * TX_STA_FIFO is a stack of X entries, hence read TX_STA_FIFO
+ * at most X times and also stop processing once the TX_STA_FIFO_VALID
+ * flag is not set anymore.
+ *
+ * The legacy drivers use X=TX_RING_SIZE but state in a comment
+ * that the TX_STA_FIFO stack has a size of 16. We stick to our
+ * tx ring size for now.
*/
- old_reg = 0;
-
- while (1) {
+ for (i = 0; i < TX_ENTRIES; i++) {
rt2x00pci_register_read(rt2x00dev, STA_CSR4, &reg);
if (!rt2x00_get_field32(reg, STA_CSR4_VALID))
break;
- if (old_reg == reg)
- break;
- old_reg = reg;
-
/*
* Skip this entry when it contains an invalid
* queue identication number.
@@ -2120,6 +2131,13 @@ static void rt61pci_txdone(struct rt2x00_dev *rt2x00dev)
}
txdesc.retry = rt2x00_get_field32(reg, STA_CSR4_RETRY_COUNT);
+ /*
+ * the frame was retried at least once
+ * -> hw used fallback rates
+ */
+ if (txdesc.retry)
+ __set_bit(TXDONE_FALLBACK, &txdesc.flags);
+
rt2x00lib_txdone(entry, &txdesc);
}
}
@@ -2132,27 +2150,11 @@ static void rt61pci_wakeup(struct rt2x00_dev *rt2x00dev)
rt61pci_config(rt2x00dev, &libconf, IEEE80211_CONF_CHANGE_PS);
}
-static irqreturn_t rt61pci_interrupt(int irq, void *dev_instance)
+static irqreturn_t rt61pci_interrupt_thread(int irq, void *dev_instance)
{
struct rt2x00_dev *rt2x00dev = dev_instance;
- u32 reg_mcu;
- u32 reg;
-
- /*
- * Get the interrupt sources & saved to local variable.
- * Write register value back to clear pending interrupts.
- */
- rt2x00pci_register_read(rt2x00dev, MCU_INT_SOURCE_CSR, &reg_mcu);
- rt2x00pci_register_write(rt2x00dev, MCU_INT_SOURCE_CSR, reg_mcu);
-
- rt2x00pci_register_read(rt2x00dev, INT_SOURCE_CSR, &reg);
- rt2x00pci_register_write(rt2x00dev, INT_SOURCE_CSR, reg);
-
- if (!reg && !reg_mcu)
- return IRQ_NONE;
-
- if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
- return IRQ_HANDLED;
+ u32 reg = rt2x00dev->irqvalue[0];
+ u32 reg_mcu = rt2x00dev->irqvalue[1];
/*
* Handle interrupts, walk through all bits
@@ -2185,9 +2187,51 @@ static irqreturn_t rt61pci_interrupt(int irq, void *dev_instance)
if (rt2x00_get_field32(reg_mcu, MCU_INT_SOURCE_CSR_TWAKEUP))
rt61pci_wakeup(rt2x00dev);
+ /*
+ * 5 - Beacon done interrupt.
+ */
+ if (rt2x00_get_field32(reg, INT_SOURCE_CSR_BEACON_DONE))
+ rt2x00lib_beacondone(rt2x00dev);
+
+ /* Enable interrupts again. */
+ rt2x00dev->ops->lib->set_device_state(rt2x00dev,
+ STATE_RADIO_IRQ_ON_ISR);
return IRQ_HANDLED;
}
+
+static irqreturn_t rt61pci_interrupt(int irq, void *dev_instance)
+{
+ struct rt2x00_dev *rt2x00dev = dev_instance;
+ u32 reg_mcu;
+ u32 reg;
+
+ /*
+ * Get the interrupt sources & saved to local variable.
+ * Write register value back to clear pending interrupts.
+ */
+ rt2x00pci_register_read(rt2x00dev, MCU_INT_SOURCE_CSR, &reg_mcu);
+ rt2x00pci_register_write(rt2x00dev, MCU_INT_SOURCE_CSR, reg_mcu);
+
+ rt2x00pci_register_read(rt2x00dev, INT_SOURCE_CSR, &reg);
+ rt2x00pci_register_write(rt2x00dev, INT_SOURCE_CSR, reg);
+
+ if (!reg && !reg_mcu)
+ return IRQ_NONE;
+
+ if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
+ return IRQ_HANDLED;
+
+ /* Store irqvalues for use in the interrupt thread. */
+ rt2x00dev->irqvalue[0] = reg;
+ rt2x00dev->irqvalue[1] = reg_mcu;
+
+ /* Disable interrupts, will be enabled again in the interrupt thread. */
+ rt2x00dev->ops->lib->set_device_state(rt2x00dev,
+ STATE_RADIO_IRQ_OFF_ISR);
+ return IRQ_WAKE_THREAD;
+}
+
/*
* Device probe functions.
*/
@@ -2577,6 +2621,18 @@ static int rt61pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
EEPROM_MAC_ADDR_0));
/*
+ * As rt61 has a global fallback table we cannot specify
+ * more then one tx rate per frame but since the hw will
+ * try several rates (based on the fallback table) we should
+ * still initialize max_rates to the maximum number of rates
+ * we are going to try. Otherwise mac80211 will truncate our
+ * reported tx rates and the rc algortihm will end up with
+ * incorrect data.
+ */
+ rt2x00dev->hw->max_rates = 7;
+ rt2x00dev->hw->max_rate_tries = 1;
+
+ /*
* Initialize hw_mode information.
*/
spec->supported_bands = SUPPORT_BAND_2GHZ;
@@ -2657,6 +2713,7 @@ static int rt61pci_probe_hw(struct rt2x00_dev *rt2x00dev)
__set_bit(DRIVER_REQUIRE_DMA, &rt2x00dev->flags);
if (!modparam_nohwcrypt)
__set_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags);
+ __set_bit(DRIVER_SUPPORT_LINK_TUNING, &rt2x00dev->flags);
/*
* Set the rssi offset.
@@ -2748,8 +2805,9 @@ static const struct ieee80211_ops rt61pci_mac80211_ops = {
.remove_interface = rt2x00mac_remove_interface,
.config = rt2x00mac_config,
.configure_filter = rt2x00mac_configure_filter,
- .set_tim = rt2x00mac_set_tim,
.set_key = rt2x00mac_set_key,
+ .sw_scan_start = rt2x00mac_sw_scan_start,
+ .sw_scan_complete = rt2x00mac_sw_scan_complete,
.get_stats = rt2x00mac_get_stats,
.bss_info_changed = rt2x00mac_bss_info_changed,
.conf_tx = rt61pci_conf_tx,
@@ -2759,6 +2817,7 @@ static const struct ieee80211_ops rt61pci_mac80211_ops = {
static const struct rt2x00lib_ops rt61pci_rt2x00_ops = {
.irq_handler = rt61pci_interrupt,
+ .irq_handler_thread = rt61pci_interrupt_thread,
.probe_hw = rt61pci_probe_hw,
.get_firmware_name = rt61pci_get_firmware_name,
.check_firmware = rt61pci_check_firmware,
@@ -2773,7 +2832,6 @@ static const struct rt2x00lib_ops rt61pci_rt2x00_ops = {
.reset_tuner = rt61pci_reset_tuner,
.link_tuner = rt61pci_link_tuner,
.write_tx_desc = rt61pci_write_tx_desc,
- .write_tx_data = rt2x00pci_write_tx_data,
.write_beacon = rt61pci_write_beacon,
.kick_tx_queue = rt61pci_kick_tx_queue,
.kill_tx_queue = rt61pci_kill_tx_queue,
diff --git a/drivers/net/wireless/rt2x00/rt61pci.h b/drivers/net/wireless/rt2x00/rt61pci.h
index df80f1af22a..e2e728ab0b2 100644
--- a/drivers/net/wireless/rt2x00/rt61pci.h
+++ b/drivers/net/wireless/rt2x00/rt61pci.h
@@ -153,13 +153,13 @@ struct hw_key_entry {
u8 key[16];
u8 tx_mic[8];
u8 rx_mic[8];
-} __attribute__ ((packed));
+} __packed;
struct hw_pairwise_ta_entry {
u8 address[6];
u8 cipher;
u8 reserved;
-} __attribute__ ((packed));
+} __packed;
/*
* Other on-chip shared memory space.
diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c
index 6e0d82efe92..aa9de18fd41 100644
--- a/drivers/net/wireless/rt2x00/rt73usb.c
+++ b/drivers/net/wireless/rt2x00/rt73usb.c
@@ -270,7 +270,6 @@ static int rt73usb_config_shared_key(struct rt2x00_dev *rt2x00dev,
{
struct hw_key_entry key_entry;
struct rt2x00_field32 field;
- int timeout;
u32 mask;
u32 reg;
@@ -306,12 +305,8 @@ static int rt73usb_config_shared_key(struct rt2x00_dev *rt2x00dev,
sizeof(key_entry.rx_mic));
reg = SHARED_KEY_ENTRY(key->hw_key_idx);
- timeout = REGISTER_TIMEOUT32(sizeof(key_entry));
- rt2x00usb_vendor_request_large_buff(rt2x00dev, USB_MULTI_WRITE,
- USB_VENDOR_REQUEST_OUT, reg,
- &key_entry,
- sizeof(key_entry),
- timeout);
+ rt2x00usb_register_multiwrite(rt2x00dev, reg,
+ &key_entry, sizeof(key_entry));
/*
* The cipher types are stored over 2 registers.
@@ -372,7 +367,6 @@ static int rt73usb_config_pairwise_key(struct rt2x00_dev *rt2x00dev,
{
struct hw_pairwise_ta_entry addr_entry;
struct hw_key_entry key_entry;
- int timeout;
u32 mask;
u32 reg;
@@ -407,17 +401,11 @@ static int rt73usb_config_pairwise_key(struct rt2x00_dev *rt2x00dev,
sizeof(key_entry.rx_mic));
reg = PAIRWISE_KEY_ENTRY(key->hw_key_idx);
- timeout = REGISTER_TIMEOUT32(sizeof(key_entry));
- rt2x00usb_vendor_request_large_buff(rt2x00dev, USB_MULTI_WRITE,
- USB_VENDOR_REQUEST_OUT, reg,
- &key_entry,
- sizeof(key_entry),
- timeout);
+ rt2x00usb_register_multiwrite(rt2x00dev, reg,
+ &key_entry, sizeof(key_entry));
/*
* Send the address and cipher type to the hardware register.
- * This data fits within the CSR cache size, so we can use
- * rt2x00usb_register_multiwrite() directly.
*/
memset(&addr_entry, 0, sizeof(addr_entry));
memcpy(&addr_entry, crypto->address, ETH_ALEN);
@@ -828,6 +816,9 @@ static void rt73usb_config_retry_limit(struct rt2x00_dev *rt2x00dev,
u32 reg;
rt2x00usb_register_read(rt2x00dev, TXRX_CSR4, &reg);
+ rt2x00_set_field32(&reg, TXRX_CSR4_OFDM_TX_RATE_DOWN, 1);
+ rt2x00_set_field32(&reg, TXRX_CSR4_OFDM_TX_RATE_STEP, 0);
+ rt2x00_set_field32(&reg, TXRX_CSR4_OFDM_TX_FALLBACK_CCK, 0);
rt2x00_set_field32(&reg, TXRX_CSR4_LONG_RETRY_LIMIT,
libconf->conf->long_frame_max_tx_count);
rt2x00_set_field32(&reg, TXRX_CSR4_SHORT_RETRY_LIMIT,
@@ -1092,11 +1083,7 @@ static int rt73usb_load_firmware(struct rt2x00_dev *rt2x00dev,
/*
* Write firmware to device.
*/
- rt2x00usb_vendor_request_large_buff(rt2x00dev, USB_MULTI_WRITE,
- USB_VENDOR_REQUEST_OUT,
- FIRMWARE_IMAGE_BASE,
- data, len,
- REGISTER_TIMEOUT32(len));
+ rt2x00usb_register_multiwrite(rt2x00dev, FIRMWARE_IMAGE_BASE, data, len);
/*
* Send firmware request to device to load firmware,
@@ -1413,7 +1400,9 @@ static int rt73usb_set_device_state(struct rt2x00_dev *rt2x00dev,
rt73usb_toggle_rx(rt2x00dev, state);
break;
case STATE_RADIO_IRQ_ON:
+ case STATE_RADIO_IRQ_ON_ISR:
case STATE_RADIO_IRQ_OFF:
+ case STATE_RADIO_IRQ_OFF_ISR:
/* No support, but no error either */
break;
case STATE_DEEP_SLEEP:
@@ -1442,7 +1431,7 @@ static void rt73usb_write_tx_desc(struct rt2x00_dev *rt2x00dev,
struct txentry_desc *txdesc)
{
struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb);
- __le32 *txd = (__le32 *)(skb->data - TXD_DESC_SIZE);
+ __le32 *txd = (__le32 *) skb->data;
u32 word;
/*
@@ -1505,6 +1494,7 @@ static void rt73usb_write_tx_desc(struct rt2x00_dev *rt2x00dev,
/*
* Register descriptor details in skb frame descriptor.
*/
+ skbdesc->flags |= SKBDESC_DESC_IN_SKB;
skbdesc->desc = txd;
skbdesc->desc_len = TXD_DESC_SIZE;
}
@@ -1528,18 +1518,27 @@ static void rt73usb_write_beacon(struct queue_entry *entry,
rt2x00usb_register_write(rt2x00dev, TXRX_CSR9, reg);
/*
- * Take the descriptor in front of the skb into account.
+ * Add space for the descriptor in front of the skb.
*/
skb_push(entry->skb, TXD_DESC_SIZE);
+ memset(entry->skb->data, 0, TXD_DESC_SIZE);
+
+ /*
+ * Write the TX descriptor for the beacon.
+ */
+ rt73usb_write_tx_desc(rt2x00dev, entry->skb, txdesc);
+
+ /*
+ * Dump beacon to userspace through debugfs.
+ */
+ rt2x00debug_dump_frame(rt2x00dev, DUMP_FRAME_BEACON, entry->skb);
/*
* Write entire beacon with descriptor to register.
*/
beacon_base = HW_BEACON_OFFSET(entry->entry_idx);
- rt2x00usb_vendor_request_large_buff(rt2x00dev, USB_MULTI_WRITE,
- USB_VENDOR_REQUEST_OUT, beacon_base,
- entry->skb->data, entry->skb->len,
- REGISTER_TIMEOUT32(entry->skb->len));
+ rt2x00usb_register_multiwrite(rt2x00dev, beacon_base,
+ entry->skb->data, entry->skb->len);
/*
* Enable beaconing again.
@@ -2138,6 +2137,8 @@ static int rt73usb_probe_hw(struct rt2x00_dev *rt2x00dev)
__set_bit(DRIVER_REQUIRE_FIRMWARE, &rt2x00dev->flags);
if (!modparam_nohwcrypt)
__set_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags);
+ __set_bit(DRIVER_SUPPORT_LINK_TUNING, &rt2x00dev->flags);
+ __set_bit(DRIVER_SUPPORT_WATCHDOG, &rt2x00dev->flags);
/*
* Set the rssi offset.
@@ -2231,6 +2232,8 @@ static const struct ieee80211_ops rt73usb_mac80211_ops = {
.configure_filter = rt2x00mac_configure_filter,
.set_tim = rt2x00mac_set_tim,
.set_key = rt2x00mac_set_key,
+ .sw_scan_start = rt2x00mac_sw_scan_start,
+ .sw_scan_complete = rt2x00mac_sw_scan_complete,
.get_stats = rt2x00mac_get_stats,
.bss_info_changed = rt2x00mac_bss_info_changed,
.conf_tx = rt73usb_conf_tx,
@@ -2251,8 +2254,8 @@ static const struct rt2x00lib_ops rt73usb_rt2x00_ops = {
.link_stats = rt73usb_link_stats,
.reset_tuner = rt73usb_reset_tuner,
.link_tuner = rt73usb_link_tuner,
+ .watchdog = rt2x00usb_watchdog,
.write_tx_desc = rt73usb_write_tx_desc,
- .write_tx_data = rt2x00usb_write_tx_data,
.write_beacon = rt73usb_write_beacon,
.get_tx_data_len = rt73usb_get_tx_data_len,
.kick_tx_queue = rt2x00usb_kick_tx_queue,
diff --git a/drivers/net/wireless/rt2x00/rt73usb.h b/drivers/net/wireless/rt2x00/rt73usb.h
index 7abe7eb1455..44d5b2bebd3 100644
--- a/drivers/net/wireless/rt2x00/rt73usb.h
+++ b/drivers/net/wireless/rt2x00/rt73usb.h
@@ -108,13 +108,13 @@ struct hw_key_entry {
u8 key[16];
u8 tx_mic[8];
u8 rx_mic[8];
-} __attribute__ ((packed));
+} __packed;
struct hw_pairwise_ta_entry {
u8 address[6];
u8 cipher;
u8 reserved;
-} __attribute__ ((packed));
+} __packed;
/*
* Since NULL frame won't be that long (256 byte),
diff --git a/drivers/net/wireless/rtl818x/rtl8180.h b/drivers/net/wireless/rtl818x/rtl8180.h
index 4baf0cf0826..30523314da4 100644
--- a/drivers/net/wireless/rtl818x/rtl8180.h
+++ b/drivers/net/wireless/rtl818x/rtl8180.h
@@ -36,7 +36,7 @@ struct rtl8180_tx_desc {
u8 agc;
u8 flags2;
u32 reserved[2];
-} __attribute__ ((packed));
+} __packed;
struct rtl8180_rx_desc {
__le32 flags;
@@ -45,7 +45,7 @@ struct rtl8180_rx_desc {
__le32 rx_buf;
__le64 tsft;
};
-} __attribute__ ((packed));
+} __packed;
struct rtl8180_tx_ring {
struct rtl8180_tx_desc *desc;
diff --git a/drivers/net/wireless/rtl818x/rtl8180_dev.c b/drivers/net/wireless/rtl818x/rtl8180_dev.c
index 515817de290..1d8178563d7 100644
--- a/drivers/net/wireless/rtl818x/rtl8180_dev.c
+++ b/drivers/net/wireless/rtl818x/rtl8180_dev.c
@@ -103,6 +103,7 @@ static void rtl8180_handle_rx(struct ieee80211_hw *dev)
{
struct rtl8180_priv *priv = dev->priv;
unsigned int count = 32;
+ u8 signal, agc, sq;
while (count--) {
struct rtl8180_rx_desc *entry = &priv->rx_ring[priv->rx_idx];
@@ -130,10 +131,18 @@ static void rtl8180_handle_rx(struct ieee80211_hw *dev)
skb_put(skb, flags & 0xFFF);
rx_status.antenna = (flags2 >> 15) & 1;
- /* TODO: improve signal/rssi reporting */
- rx_status.signal = (flags2 >> 8) & 0x7F;
- /* XXX: is this correct? */
rx_status.rate_idx = (flags >> 20) & 0xF;
+ agc = (flags2 >> 17) & 0x7F;
+ if (priv->r8185) {
+ if (rx_status.rate_idx > 3)
+ signal = 90 - clamp_t(u8, agc, 25, 90);
+ else
+ signal = 95 - clamp_t(u8, agc, 30, 95);
+ } else {
+ sq = flags2 & 0xff;
+ signal = priv->rf->calc_rssi(agc, sq);
+ }
+ rx_status.signal = signal;
rx_status.freq = dev->conf.channel->center_freq;
rx_status.band = dev->conf.channel->band;
rx_status.mactime = le64_to_cpu(entry->tsft);
@@ -352,7 +361,7 @@ static int rtl8180_init_hw(struct ieee80211_hw *dev)
/* check success of reset */
if (rtl818x_ioread8(priv, &priv->map->CMD) & RTL818X_CMD_RESET) {
- printk(KERN_ERR "%s: reset timeout!\n", wiphy_name(dev->wiphy));
+ wiphy_err(dev->wiphy, "reset timeout!\n");
return -ETIMEDOUT;
}
@@ -436,8 +445,7 @@ static int rtl8180_init_rx_ring(struct ieee80211_hw *dev)
&priv->rx_ring_dma);
if (!priv->rx_ring || (unsigned long)priv->rx_ring & 0xFF) {
- printk(KERN_ERR "%s: Cannot allocate RX ring\n",
- wiphy_name(dev->wiphy));
+ wiphy_err(dev->wiphy, "cannot allocate rx ring\n");
return -ENOMEM;
}
@@ -494,8 +502,8 @@ static int rtl8180_init_tx_ring(struct ieee80211_hw *dev,
ring = pci_alloc_consistent(priv->pdev, sizeof(*ring) * entries, &dma);
if (!ring || (unsigned long)ring & 0xFF) {
- printk(KERN_ERR "%s: Cannot allocate TX ring (prio = %d)\n",
- wiphy_name(dev->wiphy), prio);
+ wiphy_err(dev->wiphy, "cannot allocate tx ring (prio = %d)\n",
+ prio);
return -ENOMEM;
}
@@ -560,8 +568,7 @@ static int rtl8180_start(struct ieee80211_hw *dev)
ret = request_irq(priv->pdev->irq, rtl8180_interrupt,
IRQF_SHARED, KBUILD_MODNAME, dev);
if (ret) {
- printk(KERN_ERR "%s: failed to register IRQ handler\n",
- wiphy_name(dev->wiphy));
+ wiphy_err(dev->wiphy, "failed to register irq handler\n");
goto err_free_rings;
}
@@ -671,7 +678,7 @@ static u64 rtl8180_get_tsf(struct ieee80211_hw *dev)
(u64)(rtl818x_ioread32(priv, &priv->map->TSFT[1])) << 32;
}
-void rtl8180_beacon_work(struct work_struct *work)
+static void rtl8180_beacon_work(struct work_struct *work)
{
struct rtl8180_vif *vif_priv =
container_of(work, struct rtl8180_vif, beacon_work.work);
@@ -1098,9 +1105,8 @@ static int __devinit rtl8180_probe(struct pci_dev *pdev,
goto err_iounmap;
}
- printk(KERN_INFO "%s: hwaddr %pM, %s + %s\n",
- wiphy_name(dev->wiphy), mac_addr,
- chip_name, priv->rf->name);
+ wiphy_info(dev->wiphy, "hwaddr %pm, %s + %s\n",
+ mac_addr, chip_name, priv->rf->name);
return 0;
diff --git a/drivers/net/wireless/rtl818x/rtl8180_grf5101.c b/drivers/net/wireless/rtl818x/rtl8180_grf5101.c
index 947ee55f18b..5cab9dfa8c0 100644
--- a/drivers/net/wireless/rtl818x/rtl8180_grf5101.c
+++ b/drivers/net/wireless/rtl818x/rtl8180_grf5101.c
@@ -69,6 +69,15 @@ static void grf5101_write_phy_antenna(struct ieee80211_hw *dev, short chan)
rtl8180_write_phy(dev, 0x10, ant);
}
+static u8 grf5101_rf_calc_rssi(u8 agc, u8 sq)
+{
+ if (agc > 60)
+ return 65;
+
+ /* TODO(?): just return agc (or agc + 5) to avoid mult / div */
+ return 65 * agc / 60;
+}
+
static void grf5101_rf_set_channel(struct ieee80211_hw *dev,
struct ieee80211_conf *conf)
{
@@ -176,5 +185,6 @@ const struct rtl818x_rf_ops grf5101_rf_ops = {
.name = "GCT",
.init = grf5101_rf_init,
.stop = grf5101_rf_stop,
- .set_chan = grf5101_rf_set_channel
+ .set_chan = grf5101_rf_set_channel,
+ .calc_rssi = grf5101_rf_calc_rssi,
};
diff --git a/drivers/net/wireless/rtl818x/rtl8180_max2820.c b/drivers/net/wireless/rtl818x/rtl8180_max2820.c
index 6c825fd7f3b..16c4655181c 100644
--- a/drivers/net/wireless/rtl818x/rtl8180_max2820.c
+++ b/drivers/net/wireless/rtl818x/rtl8180_max2820.c
@@ -74,6 +74,22 @@ static void max2820_write_phy_antenna(struct ieee80211_hw *dev, short chan)
rtl8180_write_phy(dev, 0x10, ant);
}
+static u8 max2820_rf_calc_rssi(u8 agc, u8 sq)
+{
+ bool odd;
+
+ odd = !!(agc & 1);
+
+ agc >>= 1;
+ if (odd)
+ agc += 76;
+ else
+ agc += 66;
+
+ /* TODO: change addends above to avoid mult / div below */
+ return 65 * agc / 100;
+}
+
static void max2820_rf_set_channel(struct ieee80211_hw *dev,
struct ieee80211_conf *conf)
{
@@ -148,5 +164,6 @@ const struct rtl818x_rf_ops max2820_rf_ops = {
.name = "Maxim",
.init = max2820_rf_init,
.stop = max2820_rf_stop,
- .set_chan = max2820_rf_set_channel
+ .set_chan = max2820_rf_set_channel,
+ .calc_rssi = max2820_rf_calc_rssi,
};
diff --git a/drivers/net/wireless/rtl818x/rtl8180_rtl8225.c b/drivers/net/wireless/rtl818x/rtl8180_rtl8225.c
index 4d2be0d9672..69e4d4745da 100644
--- a/drivers/net/wireless/rtl818x/rtl8180_rtl8225.c
+++ b/drivers/net/wireless/rtl818x/rtl8180_rtl8225.c
@@ -50,7 +50,10 @@ static void rtl8225_write(struct ieee80211_hw *dev, u8 addr, u16 data)
udelay(10);
for (i = 15; i >= 0; i--) {
- u16 reg = reg80 | !!(bangdata & (1 << i));
+ u16 reg = reg80;
+
+ if (bangdata & (1 << i))
+ reg |= 1;
if (i & 1)
rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg);
diff --git a/drivers/net/wireless/rtl818x/rtl8180_sa2400.c b/drivers/net/wireless/rtl818x/rtl8180_sa2400.c
index cea4e0ccb92..d064fcc5ec0 100644
--- a/drivers/net/wireless/rtl818x/rtl8180_sa2400.c
+++ b/drivers/net/wireless/rtl818x/rtl8180_sa2400.c
@@ -76,6 +76,31 @@ static void sa2400_write_phy_antenna(struct ieee80211_hw *dev, short chan)
}
+static u8 sa2400_rf_rssi_map[] = {
+ 0x64, 0x64, 0x63, 0x62, 0x61, 0x60, 0x5f, 0x5e,
+ 0x5d, 0x5c, 0x5b, 0x5a, 0x57, 0x54, 0x52, 0x50,
+ 0x4e, 0x4c, 0x4a, 0x48, 0x46, 0x44, 0x41, 0x3f,
+ 0x3c, 0x3a, 0x37, 0x36, 0x36, 0x1c, 0x1c, 0x1b,
+ 0x1b, 0x1a, 0x1a, 0x19, 0x19, 0x18, 0x18, 0x17,
+ 0x17, 0x16, 0x16, 0x15, 0x15, 0x14, 0x14, 0x13,
+ 0x13, 0x12, 0x12, 0x11, 0x11, 0x10, 0x10, 0x0f,
+ 0x0f, 0x0e, 0x0e, 0x0d, 0x0d, 0x0c, 0x0c, 0x0b,
+ 0x0b, 0x0a, 0x0a, 0x09, 0x09, 0x08, 0x08, 0x07,
+ 0x07, 0x06, 0x06, 0x05, 0x04, 0x03, 0x02,
+};
+
+static u8 sa2400_rf_calc_rssi(u8 agc, u8 sq)
+{
+ if (sq == 0x80)
+ return 1;
+
+ if (sq > 78)
+ return 32;
+
+ /* TODO: recalc sa2400_rf_rssi_map to avoid mult / div */
+ return 65 * sa2400_rf_rssi_map[sq] / 100;
+}
+
static void sa2400_rf_set_channel(struct ieee80211_hw *dev,
struct ieee80211_conf *conf)
{
@@ -198,5 +223,6 @@ const struct rtl818x_rf_ops sa2400_rf_ops = {
.name = "Philips",
.init = sa2400_rf_init,
.stop = sa2400_rf_stop,
- .set_chan = sa2400_rf_set_channel
+ .set_chan = sa2400_rf_set_channel,
+ .calc_rssi = sa2400_rf_calc_rssi,
};
diff --git a/drivers/net/wireless/rtl818x/rtl8187.h b/drivers/net/wireless/rtl818x/rtl8187.h
index 6bb32112e65..98878160a65 100644
--- a/drivers/net/wireless/rtl818x/rtl8187.h
+++ b/drivers/net/wireless/rtl818x/rtl8187.h
@@ -47,7 +47,7 @@ struct rtl8187_rx_hdr {
u8 agc;
u8 reserved;
__le64 mac_time;
-} __attribute__((packed));
+} __packed;
struct rtl8187b_rx_hdr {
__le32 flags;
@@ -59,7 +59,7 @@ struct rtl8187b_rx_hdr {
__le16 snr_long2end;
s8 pwdb_g12;
u8 fot;
-} __attribute__((packed));
+} __packed;
/* {rtl8187,rtl8187b}_tx_info is in skb */
@@ -68,7 +68,7 @@ struct rtl8187_tx_hdr {
__le16 rts_duration;
__le16 len;
__le32 retry;
-} __attribute__((packed));
+} __packed;
struct rtl8187b_tx_hdr {
__le32 flags;
@@ -80,7 +80,7 @@ struct rtl8187b_tx_hdr {
__le32 unused_3;
__le32 retry;
__le32 unused_4[2];
-} __attribute__((packed));
+} __packed;
enum {
DEVICE_RTL8187,
diff --git a/drivers/net/wireless/rtl818x/rtl8187_dev.c b/drivers/net/wireless/rtl818x/rtl8187_dev.c
index 891b8490e34..5738a55c1b0 100644
--- a/drivers/net/wireless/rtl818x/rtl8187_dev.c
+++ b/drivers/net/wireless/rtl818x/rtl8187_dev.c
@@ -573,7 +573,7 @@ static int rtl8187_cmd_reset(struct ieee80211_hw *dev)
} while (--i);
if (!i) {
- printk(KERN_ERR "%s: Reset timeout!\n", wiphy_name(dev->wiphy));
+ wiphy_err(dev->wiphy, "reset timeout!\n");
return -ETIMEDOUT;
}
@@ -589,8 +589,7 @@ static int rtl8187_cmd_reset(struct ieee80211_hw *dev)
} while (--i);
if (!i) {
- printk(KERN_ERR "%s: eeprom reset timeout!\n",
- wiphy_name(dev->wiphy));
+ wiphy_err(dev->wiphy, "eeprom reset timeout!\n");
return -ETIMEDOUT;
}
@@ -1527,9 +1526,9 @@ static int __devinit rtl8187_probe(struct usb_interface *intf,
mutex_init(&priv->conf_mutex);
skb_queue_head_init(&priv->b_tx_status.queue);
- printk(KERN_INFO "%s: hwaddr %pM, %s V%d + %s, rfkill mask %d\n",
- wiphy_name(dev->wiphy), mac_addr,
- chip_name, priv->asic_rev, priv->rf->name, priv->rfkill_mask);
+ wiphy_info(dev->wiphy, "hwaddr %pm, %s v%d + %s, rfkill mask %d\n",
+ mac_addr, chip_name, priv->asic_rev, priv->rf->name,
+ priv->rfkill_mask);
#ifdef CONFIG_RTL8187_LEDS
eeprom_93cx6_read(&eeprom, 0x3F, &reg);
diff --git a/drivers/net/wireless/rtl818x/rtl8187_rtl8225.c b/drivers/net/wireless/rtl818x/rtl8187_rtl8225.c
index a09819386a1..fd96f911232 100644
--- a/drivers/net/wireless/rtl818x/rtl8187_rtl8225.c
+++ b/drivers/net/wireless/rtl818x/rtl8187_rtl8225.c
@@ -366,8 +366,8 @@ static void rtl8225_rf_init(struct ieee80211_hw *dev)
rtl8225_write(dev, 0x02, 0x044d);
msleep(100);
if (!(rtl8225_read(dev, 6) & (1 << 7)))
- printk(KERN_WARNING "%s: RF Calibration Failed! %x\n",
- wiphy_name(dev->wiphy), rtl8225_read(dev, 6));
+ wiphy_warn(dev->wiphy, "rf calibration failed! %x\n",
+ rtl8225_read(dev, 6));
}
rtl8225_write(dev, 0x0, 0x127);
@@ -735,8 +735,8 @@ static void rtl8225z2_rf_init(struct ieee80211_hw *dev)
rtl8225_write(dev, 0x02, 0x044D);
msleep(100);
if (!(rtl8225_read(dev, 6) & (1 << 7)))
- printk(KERN_WARNING "%s: RF Calibration Failed! %x\n",
- wiphy_name(dev->wiphy), rtl8225_read(dev, 6));
+ wiphy_warn(dev->wiphy, "rf calibration failed! %x\n",
+ rtl8225_read(dev, 6));
}
msleep(200);
diff --git a/drivers/net/wireless/rtl818x/rtl818x.h b/drivers/net/wireless/rtl818x/rtl818x.h
index 8522490d2e2..1615f63b02f 100644
--- a/drivers/net/wireless/rtl818x/rtl818x.h
+++ b/drivers/net/wireless/rtl818x/rtl818x.h
@@ -185,7 +185,7 @@ struct rtl818x_csr {
u8 reserved_22[4];
__le16 TALLY_CNT;
u8 TALLY_SEL;
-} __attribute__((packed));
+} __packed;
struct rtl818x_rf_ops {
char *name;
@@ -193,6 +193,7 @@ struct rtl818x_rf_ops {
void (*stop)(struct ieee80211_hw *);
void (*set_chan)(struct ieee80211_hw *, struct ieee80211_conf *);
void (*conf_erp)(struct ieee80211_hw *, struct ieee80211_bss_conf *);
+ u8 (*calc_rssi)(u8 agc, u8 sq);
};
/**
diff --git a/drivers/net/wireless/wl12xx/Kconfig b/drivers/net/wireless/wl12xx/Kconfig
index 337fc7bec5a..2f98058be45 100644
--- a/drivers/net/wireless/wl12xx/Kconfig
+++ b/drivers/net/wireless/wl12xx/Kconfig
@@ -41,7 +41,7 @@ config WL1251_SDIO
config WL1271
tristate "TI wl1271 support"
- depends on WL12XX && SPI_MASTER && GENERIC_HARDIRQS
+ depends on WL12XX && GENERIC_HARDIRQS
depends on INET
select FW_LOADER
select CRC7
@@ -65,7 +65,7 @@ config WL1271_SPI
config WL1271_SDIO
tristate "TI wl1271 SDIO support"
- depends on WL1271 && MMC && ARM
+ depends on WL1271 && MMC
---help---
This module adds support for the SDIO interface of adapters using
TI wl1271 chipset. Select this if your platform is using
diff --git a/drivers/net/wireless/wl12xx/Makefile b/drivers/net/wireless/wl12xx/Makefile
index 27ddd2be0a9..078b4398ac1 100644
--- a/drivers/net/wireless/wl12xx/Makefile
+++ b/drivers/net/wireless/wl12xx/Makefile
@@ -10,7 +10,7 @@ obj-$(CONFIG_WL1251_SDIO) += wl1251_sdio.o
wl1271-objs = wl1271_main.o wl1271_cmd.o wl1271_io.o \
wl1271_event.o wl1271_tx.o wl1271_rx.o \
wl1271_ps.o wl1271_acx.o wl1271_boot.o \
- wl1271_init.o wl1271_debugfs.o
+ wl1271_init.o wl1271_debugfs.o wl1271_scan.o
wl1271-$(CONFIG_NL80211_TESTMODE) += wl1271_testmode.o
obj-$(CONFIG_WL1271) += wl1271.o
diff --git a/drivers/net/wireless/wl12xx/wl1251.h b/drivers/net/wireless/wl12xx/wl1251.h
index 4f5f02a26e6..6b942a28e6a 100644
--- a/drivers/net/wireless/wl12xx/wl1251.h
+++ b/drivers/net/wireless/wl12xx/wl1251.h
@@ -381,6 +381,9 @@ struct wl1251 {
u32 chip_id;
char fw_ver[21];
+
+ /* Most recently reported noise in dBm */
+ s8 noise;
};
int wl1251_plt_start(struct wl1251 *wl);
diff --git a/drivers/net/wireless/wl12xx/wl1251_acx.h b/drivers/net/wireless/wl12xx/wl1251_acx.h
index 26160c45784..842df310d92 100644
--- a/drivers/net/wireless/wl12xx/wl1251_acx.h
+++ b/drivers/net/wireless/wl12xx/wl1251_acx.h
@@ -60,7 +60,7 @@ struct acx_error_counter {
/* the number of missed sequence numbers in the squentially */
/* values of frames seq numbers */
u32 seq_num_miss;
-} __attribute__ ((packed));
+} __packed;
struct acx_revision {
struct acx_header header;
@@ -89,7 +89,7 @@ struct acx_revision {
* bits 24 - 31: Chip ID - The WiLink chip ID.
*/
u32 hw_version;
-} __attribute__ ((packed));
+} __packed;
enum wl1251_psm_mode {
/* Active mode */
@@ -111,7 +111,7 @@ struct acx_sleep_auth {
/* 2 - ELP mode: Deep / Max sleep*/
u8 sleep_auth;
u8 padding[3];
-} __attribute__ ((packed));
+} __packed;
enum {
HOSTIF_PCI_MASTER_HOST_INDIRECT,
@@ -159,7 +159,7 @@ struct acx_data_path_params {
* complete ring until an interrupt is generated.
*/
u32 tx_complete_timeout;
-} __attribute__ ((packed));
+} __packed;
struct acx_data_path_params_resp {
@@ -180,7 +180,7 @@ struct acx_data_path_params_resp {
u32 tx_control_addr;
u32 tx_complete_addr;
-} __attribute__ ((packed));
+} __packed;
#define TX_MSDU_LIFETIME_MIN 0
#define TX_MSDU_LIFETIME_MAX 3000
@@ -197,7 +197,7 @@ struct acx_rx_msdu_lifetime {
* firmware discards the MSDU.
*/
u32 lifetime;
-} __attribute__ ((packed));
+} __packed;
/*
* RX Config Options Table
@@ -285,7 +285,7 @@ struct acx_rx_config {
u32 config_options;
u32 filter_options;
-} __attribute__ ((packed));
+} __packed;
enum {
QOS_AC_BE = 0,
@@ -325,13 +325,13 @@ struct acx_tx_queue_qos_config {
/* Lowest memory blocks guaranteed for this queue */
u16 low_threshold;
-} __attribute__ ((packed));
+} __packed;
struct acx_packet_detection {
struct acx_header header;
u32 threshold;
-} __attribute__ ((packed));
+} __packed;
enum acx_slot_type {
@@ -349,7 +349,7 @@ struct acx_slot {
u8 wone_index; /* Reserved */
u8 slot_time;
u8 reserved[6];
-} __attribute__ ((packed));
+} __packed;
#define ADDRESS_GROUP_MAX (8)
@@ -362,7 +362,7 @@ struct acx_dot11_grp_addr_tbl {
u8 num_groups;
u8 pad[2];
u8 mac_table[ADDRESS_GROUP_MAX_LEN];
-} __attribute__ ((packed));
+} __packed;
#define RX_TIMEOUT_PS_POLL_MIN 0
@@ -388,7 +388,7 @@ struct acx_rx_timeout {
* from an UPSD enabled queue.
*/
u16 upsd_timeout;
-} __attribute__ ((packed));
+} __packed;
#define RTS_THRESHOLD_MIN 0
#define RTS_THRESHOLD_MAX 4096
@@ -399,7 +399,7 @@ struct acx_rts_threshold {
u16 threshold;
u8 pad[2];
-} __attribute__ ((packed));
+} __packed;
struct acx_beacon_filter_option {
struct acx_header header;
@@ -415,7 +415,7 @@ struct acx_beacon_filter_option {
*/
u8 max_num_beacons;
u8 pad[2];
-} __attribute__ ((packed));
+} __packed;
/*
* ACXBeaconFilterEntry (not 221)
@@ -461,7 +461,7 @@ struct acx_beacon_filter_ie_table {
u8 num_ie;
u8 table[BEACON_FILTER_TABLE_MAX_SIZE];
u8 pad[3];
-} __attribute__ ((packed));
+} __packed;
#define SYNCH_FAIL_DEFAULT_THRESHOLD 10 /* number of beacons */
#define NO_BEACON_DEFAULT_TIMEOUT (500) /* in microseconds */
@@ -494,7 +494,7 @@ struct acx_bt_wlan_coex {
*/
u8 enable;
u8 pad[3];
-} __attribute__ ((packed));
+} __packed;
#define PTA_ANTENNA_TYPE_DEF (0)
#define PTA_BT_HP_MAXTIME_DEF (2000)
@@ -648,7 +648,7 @@ struct acx_bt_wlan_coex_param {
/* range: 0 - 20 default: 1 */
u8 bt_hp_respected_num;
-} __attribute__ ((packed));
+} __packed;
#define CCA_THRSH_ENABLE_ENERGY_D 0x140A
#define CCA_THRSH_DISABLE_ENERGY_D 0xFFEF
@@ -660,7 +660,7 @@ struct acx_energy_detection {
u16 rx_cca_threshold;
u8 tx_energy_detection;
u8 pad;
-} __attribute__ ((packed));
+} __packed;
#define BCN_RX_TIMEOUT_DEF_VALUE 10000
#define BROADCAST_RX_TIMEOUT_DEF_VALUE 20000
@@ -679,14 +679,14 @@ struct acx_beacon_broadcast {
/* Consecutive PS Poll failures before updating the host */
u8 ps_poll_threshold;
u8 pad[2];
-} __attribute__ ((packed));
+} __packed;
struct acx_event_mask {
struct acx_header header;
u32 event_mask;
u32 high_event_mask; /* Unused */
-} __attribute__ ((packed));
+} __packed;
#define CFG_RX_FCS BIT(2)
#define CFG_RX_ALL_GOOD BIT(3)
@@ -729,7 +729,7 @@ struct acx_fw_gen_frame_rates {
u8 tx_ctrl_frame_mod; /* CCK_* or PBCC_* */
u8 tx_mgt_frame_rate;
u8 tx_mgt_frame_mod;
-} __attribute__ ((packed));
+} __packed;
/* STA MAC */
struct acx_dot11_station_id {
@@ -737,28 +737,28 @@ struct acx_dot11_station_id {
u8 mac[ETH_ALEN];
u8 pad[2];
-} __attribute__ ((packed));
+} __packed;
struct acx_feature_config {
struct acx_header header;
u32 options;
u32 data_flow_options;
-} __attribute__ ((packed));
+} __packed;
struct acx_current_tx_power {
struct acx_header header;
u8 current_tx_power;
u8 padding[3];
-} __attribute__ ((packed));
+} __packed;
struct acx_dot11_default_key {
struct acx_header header;
u8 id;
u8 pad[3];
-} __attribute__ ((packed));
+} __packed;
struct acx_tsf_info {
struct acx_header header;
@@ -769,7 +769,7 @@ struct acx_tsf_info {
u32 last_TBTT_lsb;
u8 last_dtim_count;
u8 pad[3];
-} __attribute__ ((packed));
+} __packed;
enum acx_wake_up_event {
WAKE_UP_EVENT_BEACON_BITMAP = 0x01, /* Wake on every Beacon*/
@@ -785,7 +785,7 @@ struct acx_wake_up_condition {
u8 wake_up_event; /* Only one bit can be set */
u8 listen_interval;
u8 pad[2];
-} __attribute__ ((packed));
+} __packed;
struct acx_aid {
struct acx_header header;
@@ -795,7 +795,7 @@ struct acx_aid {
*/
u16 aid;
u8 pad[2];
-} __attribute__ ((packed));
+} __packed;
enum acx_preamble_type {
ACX_PREAMBLE_LONG = 0,
@@ -811,7 +811,7 @@ struct acx_preamble {
*/
u8 preamble;
u8 padding[3];
-} __attribute__ ((packed));
+} __packed;
enum acx_ctsprotect_type {
CTSPROTECT_DISABLE = 0,
@@ -822,11 +822,11 @@ struct acx_ctsprotect {
struct acx_header header;
u8 ctsprotect;
u8 padding[3];
-} __attribute__ ((packed));
+} __packed;
struct acx_tx_statistics {
u32 internal_desc_overflow;
-} __attribute__ ((packed));
+} __packed;
struct acx_rx_statistics {
u32 out_of_mem;
@@ -837,14 +837,14 @@ struct acx_rx_statistics {
u32 xfr_hint_trig;
u32 path_reset;
u32 reset_counter;
-} __attribute__ ((packed));
+} __packed;
struct acx_dma_statistics {
u32 rx_requested;
u32 rx_errors;
u32 tx_requested;
u32 tx_errors;
-} __attribute__ ((packed));
+} __packed;
struct acx_isr_statistics {
/* host command complete */
@@ -903,7 +903,7 @@ struct acx_isr_statistics {
/* (INT_STS_ND & INT_TRIG_LOW_RSSI) */
u32 low_rssi;
-} __attribute__ ((packed));
+} __packed;
struct acx_wep_statistics {
/* WEP address keys configured */
@@ -925,7 +925,7 @@ struct acx_wep_statistics {
/* WEP decrypt interrupts */
u32 interrupt;
-} __attribute__ ((packed));
+} __packed;
#define ACX_MISSED_BEACONS_SPREAD 10
@@ -985,12 +985,12 @@ struct acx_pwr_statistics {
/* the number of beacons in awake mode */
u32 rcvd_awake_beacons;
-} __attribute__ ((packed));
+} __packed;
struct acx_mic_statistics {
u32 rx_pkts;
u32 calc_failure;
-} __attribute__ ((packed));
+} __packed;
struct acx_aes_statistics {
u32 encrypt_fail;
@@ -999,7 +999,7 @@ struct acx_aes_statistics {
u32 decrypt_packets;
u32 encrypt_interrupt;
u32 decrypt_interrupt;
-} __attribute__ ((packed));
+} __packed;
struct acx_event_statistics {
u32 heart_beat;
@@ -1010,7 +1010,7 @@ struct acx_event_statistics {
u32 oom_late;
u32 phy_transmit_error;
u32 tx_stuck;
-} __attribute__ ((packed));
+} __packed;
struct acx_ps_statistics {
u32 pspoll_timeouts;
@@ -1020,7 +1020,7 @@ struct acx_ps_statistics {
u32 pspoll_max_apturn;
u32 pspoll_utilization;
u32 upsd_utilization;
-} __attribute__ ((packed));
+} __packed;
struct acx_rxpipe_statistics {
u32 rx_prep_beacon_drop;
@@ -1028,7 +1028,7 @@ struct acx_rxpipe_statistics {
u32 beacon_buffer_thres_host_int_trig_rx_data;
u32 missed_beacon_host_int_trig_rx_data;
u32 tx_xfr_host_int_trig_rx_data;
-} __attribute__ ((packed));
+} __packed;
struct acx_statistics {
struct acx_header header;
@@ -1044,7 +1044,7 @@ struct acx_statistics {
struct acx_event_statistics event;
struct acx_ps_statistics ps;
struct acx_rxpipe_statistics rxpipe;
-} __attribute__ ((packed));
+} __packed;
#define ACX_MAX_RATE_CLASSES 8
#define ACX_RATE_MASK_UNSPECIFIED 0
@@ -1063,7 +1063,7 @@ struct acx_rate_policy {
u32 rate_class_cnt;
struct acx_rate_class rate_class[ACX_MAX_RATE_CLASSES];
-} __attribute__ ((packed));
+} __packed;
struct wl1251_acx_memory {
__le16 num_stations; /* number of STAs to be supported. */
@@ -1082,7 +1082,7 @@ struct wl1251_acx_memory {
u8 tx_min_mem_block_num;
u8 num_ssid_profiles;
__le16 debug_buffer_size;
-} __attribute__ ((packed));
+} __packed;
#define ACX_RX_DESC_MIN 1
@@ -1094,7 +1094,7 @@ struct wl1251_acx_rx_queue_config {
u8 type;
u8 priority;
__le32 dma_address;
-} __attribute__ ((packed));
+} __packed;
#define ACX_TX_DESC_MIN 1
#define ACX_TX_DESC_MAX 127
@@ -1103,7 +1103,7 @@ struct wl1251_acx_tx_queue_config {
u8 num_descs;
u8 pad[2];
u8 attributes;
-} __attribute__ ((packed));
+} __packed;
#define MAX_TX_QUEUE_CONFIGS 5
#define MAX_TX_QUEUES 4
@@ -1113,7 +1113,7 @@ struct wl1251_acx_config_memory {
struct wl1251_acx_memory mem_config;
struct wl1251_acx_rx_queue_config rx_queue_config;
struct wl1251_acx_tx_queue_config tx_queue_config[MAX_TX_QUEUE_CONFIGS];
-} __attribute__ ((packed));
+} __packed;
struct wl1251_acx_mem_map {
struct acx_header header;
@@ -1147,7 +1147,7 @@ struct wl1251_acx_mem_map {
/* Number of blocks FW allocated for RX packets */
u32 num_rx_mem_blocks;
-} __attribute__ ((packed));
+} __packed;
struct wl1251_acx_wr_tbtt_and_dtim {
@@ -1164,7 +1164,7 @@ struct wl1251_acx_wr_tbtt_and_dtim {
*/
u8 dtim;
u8 padding;
-} __attribute__ ((packed));
+} __packed;
struct wl1251_acx_ac_cfg {
struct acx_header header;
@@ -1194,7 +1194,7 @@ struct wl1251_acx_ac_cfg {
/* The TX Op Limit (in microseconds) for the access class. */
u16 txop_limit;
-} __attribute__ ((packed));
+} __packed;
enum wl1251_acx_channel_type {
@@ -1245,7 +1245,7 @@ struct wl1251_acx_tid_cfg {
/* not supported */
u32 apsdconf[2];
-} __attribute__ ((packed));
+} __packed;
/*************************************************************************
diff --git a/drivers/net/wireless/wl12xx/wl1251_boot.c b/drivers/net/wireless/wl12xx/wl1251_boot.c
index 2545123931e..65e0416be5b 100644
--- a/drivers/net/wireless/wl12xx/wl1251_boot.c
+++ b/drivers/net/wireless/wl12xx/wl1251_boot.c
@@ -225,7 +225,7 @@ static void wl1251_boot_set_ecpu_ctrl(struct wl1251 *wl, u32 flag)
int wl1251_boot_run_firmware(struct wl1251 *wl)
{
int loop, ret;
- u32 chip_id, interrupt;
+ u32 chip_id, acx_intr;
wl1251_boot_set_ecpu_ctrl(wl, ECPU_CONTROL_HALT);
@@ -242,15 +242,15 @@ int wl1251_boot_run_firmware(struct wl1251 *wl)
loop = 0;
while (loop++ < INIT_LOOP) {
udelay(INIT_LOOP_DELAY);
- interrupt = wl1251_reg_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR);
+ acx_intr = wl1251_reg_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR);
- if (interrupt == 0xffffffff) {
+ if (acx_intr == 0xffffffff) {
wl1251_error("error reading hardware complete "
"init indication");
return -EIO;
}
/* check that ACX_INTR_INIT_COMPLETE is enabled */
- else if (interrupt & WL1251_ACX_INTR_INIT_COMPLETE) {
+ else if (acx_intr & WL1251_ACX_INTR_INIT_COMPLETE) {
wl1251_reg_write32(wl, ACX_REG_INTERRUPT_ACK,
WL1251_ACX_INTR_INIT_COMPLETE);
break;
diff --git a/drivers/net/wireless/wl12xx/wl1251_cmd.h b/drivers/net/wireless/wl12xx/wl1251_cmd.h
index 4ad67cae94d..a9e4991369b 100644
--- a/drivers/net/wireless/wl12xx/wl1251_cmd.h
+++ b/drivers/net/wireless/wl12xx/wl1251_cmd.h
@@ -106,7 +106,7 @@ struct wl1251_cmd_header {
u16 status;
/* payload */
u8 data[0];
-} __attribute__ ((packed));
+} __packed;
struct wl1251_command {
struct wl1251_cmd_header header;
@@ -175,8 +175,8 @@ struct cmd_read_write_memory {
#define WL1251_SCAN_NUM_PROBES 3
struct wl1251_scan_parameters {
- u32 rx_config_options;
- u32 rx_filter_options;
+ __le32 rx_config_options;
+ __le32 rx_filter_options;
/*
* Scan options:
@@ -186,7 +186,7 @@ struct wl1251_scan_parameters {
* bit 2: voice mode, 0 for normal scan.
* bit 3: scan priority, 1 for high priority.
*/
- u16 scan_options;
+ __le16 scan_options;
/* Number of channels to scan */
u8 num_channels;
@@ -195,17 +195,17 @@ struct wl1251_scan_parameters {
u8 num_probe_requests;
/* Rate and modulation for probe requests */
- u16 tx_rate;
+ __le16 tx_rate;
u8 tid_trigger;
u8 ssid_len;
u8 ssid[32];
-} __attribute__ ((packed));
+} __packed;
struct wl1251_scan_ch_parameters {
- u32 min_duration; /* in TU */
- u32 max_duration; /* in TU */
+ __le32 min_duration; /* in TU */
+ __le32 max_duration; /* in TU */
u32 bssid_lsb;
u16 bssid_msb;
@@ -218,7 +218,7 @@ struct wl1251_scan_ch_parameters {
u8 tx_power_att;
u8 channel;
u8 pad[3];
-} __attribute__ ((packed));
+} __packed;
/* SCAN parameters */
#define SCAN_MAX_NUM_OF_CHANNELS 16
@@ -228,7 +228,7 @@ struct wl1251_cmd_scan {
struct wl1251_scan_parameters params;
struct wl1251_scan_ch_parameters channels[SCAN_MAX_NUM_OF_CHANNELS];
-} __attribute__ ((packed));
+} __packed;
enum {
BSS_TYPE_IBSS = 0,
@@ -276,14 +276,14 @@ struct cmd_join {
u8 tx_mgt_frame_rate; /* OBSOLETE */
u8 tx_mgt_frame_mod; /* OBSOLETE */
u8 reserved;
-} __attribute__ ((packed));
+} __packed;
struct cmd_enabledisable_path {
struct wl1251_cmd_header header;
u8 channel;
u8 padding[3];
-} __attribute__ ((packed));
+} __packed;
#define WL1251_MAX_TEMPLATE_SIZE 300
@@ -292,7 +292,7 @@ struct wl1251_cmd_packet_template {
__le16 size;
u8 data[0];
-} __attribute__ ((packed));
+} __packed;
#define TIM_ELE_ID 5
#define PARTIAL_VBM_MAX 251
@@ -304,7 +304,7 @@ struct wl1251_tim {
u8 dtim_period;
u8 bitmap_ctrl;
u8 pvb_field[PARTIAL_VBM_MAX]; /* Partial Virtual Bitmap */
-} __attribute__ ((packed));
+} __packed;
/* Virtual Bit Map update */
struct wl1251_cmd_vbm_update {
@@ -312,7 +312,7 @@ struct wl1251_cmd_vbm_update {
__le16 len;
u8 padding[2];
struct wl1251_tim tim;
-} __attribute__ ((packed));
+} __packed;
enum wl1251_cmd_ps_mode {
STATION_ACTIVE_MODE,
@@ -333,7 +333,7 @@ struct wl1251_cmd_ps_params {
u8 hang_over_period;
u16 null_data_rate;
u8 pad[2];
-} __attribute__ ((packed));
+} __packed;
struct wl1251_cmd_trigger_scan_to {
struct wl1251_cmd_header header;
@@ -411,7 +411,7 @@ struct wl1251_cmd_set_keys {
u8 key[MAX_KEY_SIZE];
u16 ac_seq_num16[NUM_ACCESS_CATEGORIES_COPY];
u32 ac_seq_num32[NUM_ACCESS_CATEGORIES_COPY];
-} __attribute__ ((packed));
+} __packed;
#endif /* __WL1251_CMD_H__ */
diff --git a/drivers/net/wireless/wl12xx/wl1251_event.h b/drivers/net/wireless/wl12xx/wl1251_event.h
index be0ac54d624..f48a2b66bc5 100644
--- a/drivers/net/wireless/wl12xx/wl1251_event.h
+++ b/drivers/net/wireless/wl12xx/wl1251_event.h
@@ -82,7 +82,7 @@ struct event_debug_report {
u32 report_1;
u32 report_2;
u32 report_3;
-} __attribute__ ((packed));
+} __packed;
struct event_mailbox {
u32 events_vector;
@@ -112,7 +112,7 @@ struct event_mailbox {
struct event_debug_report report;
u8 average_snr_level;
u8 padding[19];
-} __attribute__ ((packed));
+} __packed;
int wl1251_event_unmask(struct wl1251 *wl);
void wl1251_event_mbox_config(struct wl1251 *wl);
diff --git a/drivers/net/wireless/wl12xx/wl1251_main.c b/drivers/net/wireless/wl12xx/wl1251_main.c
index 00b24282fc7..861a5f33761 100644
--- a/drivers/net/wireless/wl12xx/wl1251_main.c
+++ b/drivers/net/wireless/wl12xx/wl1251_main.c
@@ -124,7 +124,7 @@ static int wl1251_fetch_nvs(struct wl1251 *wl)
}
wl->nvs_len = fw->size;
- wl->nvs = kmalloc(wl->nvs_len, GFP_KERNEL);
+ wl->nvs = kmemdup(fw->data, wl->nvs_len, GFP_KERNEL);
if (!wl->nvs) {
wl1251_error("could not allocate memory for the nvs file");
@@ -132,8 +132,6 @@ static int wl1251_fetch_nvs(struct wl1251 *wl)
goto out;
}
- memcpy(wl->nvs, fw->data, wl->nvs_len);
-
ret = 0;
out:
@@ -413,6 +411,7 @@ static int wl1251_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
static int wl1251_op_start(struct ieee80211_hw *hw)
{
struct wl1251 *wl = hw->priv;
+ struct wiphy *wiphy = hw->wiphy;
int ret = 0;
wl1251_debug(DEBUG_MAC80211, "mac80211 start");
@@ -446,6 +445,10 @@ static int wl1251_op_start(struct ieee80211_hw *hw)
wl1251_info("firmware booted (%s)", wl->fw_ver);
+ /* update hw/fw version info in wiphy struct */
+ wiphy->hw_version = wl->chip_id;
+ strncpy(wiphy->fw_version, wl->fw_ver, sizeof(wiphy->fw_version));
+
out:
if (ret < 0)
wl1251_power_off(wl);
@@ -1174,6 +1177,22 @@ out:
return ret;
}
+static int wl1251_op_get_survey(struct ieee80211_hw *hw, int idx,
+ struct survey_info *survey)
+{
+ struct wl1251 *wl = hw->priv;
+ struct ieee80211_conf *conf = &hw->conf;
+
+ if (idx != 0)
+ return -ENOENT;
+
+ survey->channel = conf->channel;
+ survey->filled = SURVEY_INFO_NOISE_DBM;
+ survey->noise = wl->noise;
+
+ return 0;
+}
+
/* can't be const, mac80211 writes to this */
static struct ieee80211_supported_band wl1251_band_2ghz = {
.channels = wl1251_channels,
@@ -1195,6 +1214,7 @@ static const struct ieee80211_ops wl1251_ops = {
.bss_info_changed = wl1251_op_bss_info_changed,
.set_rts_threshold = wl1251_op_set_rts_threshold,
.conf_tx = wl1251_op_conf_tx,
+ .get_survey = wl1251_op_get_survey,
};
static int wl1251_read_eeprom_byte(struct wl1251 *wl, off_t offset, u8 *data)
@@ -1419,5 +1439,4 @@ EXPORT_SYMBOL_GPL(wl1251_free_hw);
MODULE_DESCRIPTION("TI wl1251 Wireles LAN Driver Core");
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Kalle Valo <kalle.valo@nokia.com>");
-MODULE_ALIAS("spi:wl1251");
MODULE_FIRMWARE(WL1251_FW_NAME);
diff --git a/drivers/net/wireless/wl12xx/wl1251_rx.c b/drivers/net/wireless/wl12xx/wl1251_rx.c
index 851515836a7..1b6294b3b99 100644
--- a/drivers/net/wireless/wl12xx/wl1251_rx.c
+++ b/drivers/net/wireless/wl12xx/wl1251_rx.c
@@ -74,6 +74,12 @@ static void wl1251_rx_status(struct wl1251 *wl,
status->signal = desc->rssi;
+ /*
+ * FIXME: guessing that snr needs to be divided by two, otherwise
+ * the values don't make any sense
+ */
+ wl->noise = desc->rssi - desc->snr / 2;
+
status->freq = ieee80211_channel_to_frequency(desc->channel);
status->flag |= RX_FLAG_TSFT;
diff --git a/drivers/net/wireless/wl12xx/wl1251_rx.h b/drivers/net/wireless/wl12xx/wl1251_rx.h
index 563a3fde40f..da4e53406a0 100644
--- a/drivers/net/wireless/wl12xx/wl1251_rx.h
+++ b/drivers/net/wireless/wl12xx/wl1251_rx.h
@@ -117,7 +117,7 @@ struct wl1251_rx_descriptor {
s8 rssi; /* in dB */
u8 rcpi; /* in dB */
u8 snr; /* in dB */
-} __attribute__ ((packed));
+} __packed;
void wl1251_rx(struct wl1251 *wl);
diff --git a/drivers/net/wireless/wl12xx/wl1251_sdio.c b/drivers/net/wireless/wl12xx/wl1251_sdio.c
index c561332e700..b901b613565 100644
--- a/drivers/net/wireless/wl12xx/wl1251_sdio.c
+++ b/drivers/net/wireless/wl12xx/wl1251_sdio.c
@@ -37,11 +37,17 @@
#define SDIO_DEVICE_ID_TI_WL1251 0x9066
#endif
+struct wl1251_sdio {
+ struct sdio_func *func;
+ u32 elp_val;
+};
+
static struct wl12xx_platform_data *wl12xx_board_data;
static struct sdio_func *wl_to_func(struct wl1251 *wl)
{
- return wl->if_priv;
+ struct wl1251_sdio *wl_sdio = wl->if_priv;
+ return wl_sdio->func;
}
static void wl1251_sdio_interrupt(struct sdio_func *func)
@@ -90,10 +96,17 @@ static void wl1251_sdio_write(struct wl1251 *wl, int addr,
static void wl1251_sdio_read_elp(struct wl1251 *wl, int addr, u32 *val)
{
int ret = 0;
- struct sdio_func *func = wl_to_func(wl);
-
+ struct wl1251_sdio *wl_sdio = wl->if_priv;
+ struct sdio_func *func = wl_sdio->func;
+
+ /*
+ * The hardware only supports RAW (read after write) access for
+ * reading, regular sdio_readb won't work here (it interprets
+ * the unused bits of CMD52 as write data even if we send read
+ * request).
+ */
sdio_claim_host(func);
- *val = sdio_readb(func, addr, &ret);
+ *val = sdio_writeb_readb(func, wl_sdio->elp_val, addr, &ret);
sdio_release_host(func);
if (ret)
@@ -103,7 +116,8 @@ static void wl1251_sdio_read_elp(struct wl1251 *wl, int addr, u32 *val)
static void wl1251_sdio_write_elp(struct wl1251 *wl, int addr, u32 val)
{
int ret = 0;
- struct sdio_func *func = wl_to_func(wl);
+ struct wl1251_sdio *wl_sdio = wl->if_priv;
+ struct sdio_func *func = wl_sdio->func;
sdio_claim_host(func);
sdio_writeb(func, val, addr, &ret);
@@ -111,6 +125,8 @@ static void wl1251_sdio_write_elp(struct wl1251 *wl, int addr, u32 val)
if (ret)
wl1251_error("sdio_writeb failed (%d)", ret);
+ else
+ wl_sdio->elp_val = val;
}
static void wl1251_sdio_reset(struct wl1251 *wl)
@@ -197,6 +213,7 @@ static int wl1251_sdio_probe(struct sdio_func *func,
int ret;
struct wl1251 *wl;
struct ieee80211_hw *hw;
+ struct wl1251_sdio *wl_sdio;
hw = wl1251_alloc_hw();
if (IS_ERR(hw))
@@ -204,6 +221,12 @@ static int wl1251_sdio_probe(struct sdio_func *func,
wl = hw->priv;
+ wl_sdio = kzalloc(sizeof(*wl_sdio), GFP_KERNEL);
+ if (wl_sdio == NULL) {
+ ret = -ENOMEM;
+ goto out_free_hw;
+ }
+
sdio_claim_host(func);
ret = sdio_enable_func(func);
if (ret)
@@ -213,7 +236,8 @@ static int wl1251_sdio_probe(struct sdio_func *func,
sdio_release_host(func);
SET_IEEE80211_DEV(hw, &func->dev);
- wl->if_priv = func;
+ wl_sdio->func = func;
+ wl->if_priv = wl_sdio;
wl->if_ops = &wl1251_sdio_ops;
wl->set_power = wl1251_sdio_set_power;
@@ -259,6 +283,8 @@ disable:
sdio_disable_func(func);
release:
sdio_release_host(func);
+ kfree(wl_sdio);
+out_free_hw:
wl1251_free_hw(wl);
return ret;
}
@@ -266,9 +292,11 @@ release:
static void __devexit wl1251_sdio_remove(struct sdio_func *func)
{
struct wl1251 *wl = sdio_get_drvdata(func);
+ struct wl1251_sdio *wl_sdio = wl->if_priv;
if (wl->irq)
free_irq(wl->irq, wl);
+ kfree(wl_sdio);
wl1251_free_hw(wl);
sdio_claim_host(func);
diff --git a/drivers/net/wireless/wl12xx/wl1251_spi.c b/drivers/net/wireless/wl12xx/wl1251_spi.c
index e81474203a2..27fdfaaeb07 100644
--- a/drivers/net/wireless/wl12xx/wl1251_spi.c
+++ b/drivers/net/wireless/wl12xx/wl1251_spi.c
@@ -345,3 +345,4 @@ module_exit(wl1251_spi_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Kalle Valo <kalle.valo@nokia.com>");
+MODULE_ALIAS("spi:wl1251");
diff --git a/drivers/net/wireless/wl12xx/wl1251_tx.c b/drivers/net/wireless/wl12xx/wl1251_tx.c
index c8223185efd..a38ec199187 100644
--- a/drivers/net/wireless/wl12xx/wl1251_tx.c
+++ b/drivers/net/wireless/wl12xx/wl1251_tx.c
@@ -117,7 +117,7 @@ static void wl1251_tx_frag_block_num(struct tx_double_buffer_desc *tx_hdr)
frag_threshold = IEEE80211_MAX_FRAG_THRESHOLD;
tx_hdr->frag_threshold = cpu_to_le16(frag_threshold);
- payload_len = tx_hdr->length + MAX_MSDU_SECURITY_LENGTH;
+ payload_len = le16_to_cpu(tx_hdr->length) + MAX_MSDU_SECURITY_LENGTH;
if (payload_len > frag_threshold) {
mem_blocks_per_frag =
@@ -191,11 +191,13 @@ static int wl1251_tx_send_packet(struct wl1251 *wl, struct sk_buff *skb,
if (control->control.hw_key &&
control->control.hw_key->alg == ALG_TKIP) {
int hdrlen;
- u16 fc;
+ __le16 fc;
+ u16 length;
u8 *pos;
- fc = *(u16 *)(skb->data + sizeof(*tx_hdr));
- tx_hdr->length += WL1251_TKIP_IV_SPACE;
+ fc = *(__le16 *)(skb->data + sizeof(*tx_hdr));
+ length = le16_to_cpu(tx_hdr->length) + WL1251_TKIP_IV_SPACE;
+ tx_hdr->length = cpu_to_le16(length);
hdrlen = ieee80211_hdrlen(fc);
diff --git a/drivers/net/wireless/wl12xx/wl1251_tx.h b/drivers/net/wireless/wl12xx/wl1251_tx.h
index 55856c6bb97..f40eeb37f5a 100644
--- a/drivers/net/wireless/wl12xx/wl1251_tx.h
+++ b/drivers/net/wireless/wl12xx/wl1251_tx.h
@@ -109,12 +109,12 @@ struct tx_control {
unsigned xfer_pad:1;
unsigned reserved:7;
-} __attribute__ ((packed));
+} __packed;
struct tx_double_buffer_desc {
/* Length of payload, including headers. */
- u16 length;
+ __le16 length;
/*
* A bit mask that specifies the initial rate to be used
@@ -133,10 +133,10 @@ struct tx_double_buffer_desc {
* 0x0800 - 48Mbits
* 0x1000 - 54Mbits
*/
- u16 rate;
+ __le16 rate;
/* Time in us that a packet can spend in the target */
- u32 expiry_time;
+ __le32 expiry_time;
/* index of the TX queue used for this packet */
u8 xmit_queue;
@@ -150,13 +150,13 @@ struct tx_double_buffer_desc {
* The FW should cut the packet into fragments
* of this size.
*/
- u16 frag_threshold;
+ __le16 frag_threshold;
/* Numbers of HW queue blocks to be allocated */
u8 num_mem_blocks;
u8 reserved;
-} __attribute__ ((packed));
+} __packed;
enum {
TX_SUCCESS = 0,
@@ -208,7 +208,7 @@ struct tx_result {
/* See done_1 */
u8 done_2;
-} __attribute__ ((packed));
+} __packed;
static inline int wl1251_tx_get_queue(int queue)
{
diff --git a/drivers/net/wireless/wl12xx/wl1271.h b/drivers/net/wireless/wl12xx/wl1271.h
index 6f1b6b5640c..dd3cee6ea5b 100644
--- a/drivers/net/wireless/wl12xx/wl1271.h
+++ b/drivers/net/wireless/wl12xx/wl1271.h
@@ -33,6 +33,7 @@
#include <net/mac80211.h>
#include "wl1271_conf.h"
+#include "wl1271_ini.h"
#define DRIVER_NAME "wl1271"
#define DRIVER_PREFIX DRIVER_NAME ": "
@@ -116,33 +117,6 @@ enum {
#define WL1271_TX_SECURITY_LO16(s) ((u16)((s) & 0xffff))
#define WL1271_TX_SECURITY_HI32(s) ((u32)(((s) >> 16) & 0xffffffff))
-/* NVS data structure */
-#define WL1271_NVS_SECTION_SIZE 468
-
-#define WL1271_NVS_GENERAL_PARAMS_SIZE 57
-#define WL1271_NVS_GENERAL_PARAMS_SIZE_PADDED \
- (WL1271_NVS_GENERAL_PARAMS_SIZE + 1)
-#define WL1271_NVS_STAT_RADIO_PARAMS_SIZE 17
-#define WL1271_NVS_STAT_RADIO_PARAMS_SIZE_PADDED \
- (WL1271_NVS_STAT_RADIO_PARAMS_SIZE + 1)
-#define WL1271_NVS_DYN_RADIO_PARAMS_SIZE 65
-#define WL1271_NVS_DYN_RADIO_PARAMS_SIZE_PADDED \
- (WL1271_NVS_DYN_RADIO_PARAMS_SIZE + 1)
-#define WL1271_NVS_FEM_COUNT 2
-#define WL1271_NVS_INI_SPARE_SIZE 124
-
-struct wl1271_nvs_file {
- /* NVS section */
- u8 nvs[WL1271_NVS_SECTION_SIZE];
-
- /* INI section */
- u8 general_params[WL1271_NVS_GENERAL_PARAMS_SIZE_PADDED];
- u8 stat_radio_params[WL1271_NVS_STAT_RADIO_PARAMS_SIZE_PADDED];
- u8 dyn_radio_params[WL1271_NVS_FEM_COUNT]
- [WL1271_NVS_DYN_RADIO_PARAMS_SIZE_PADDED];
- u8 ini_spare[WL1271_NVS_INI_SPARE_SIZE];
-} __attribute__ ((packed));
-
/*
* Enable/disable 802.11a support for WL1273
*/
@@ -317,7 +291,7 @@ struct wl1271_fw_status {
__le32 tx_released_blks[NUM_TX_QUEUES];
__le32 fw_localtime;
__le32 padding[2];
-} __attribute__ ((packed));
+} __packed;
struct wl1271_rx_mem_pool_addr {
u32 addr;
@@ -325,12 +299,11 @@ struct wl1271_rx_mem_pool_addr {
};
struct wl1271_scan {
+ struct cfg80211_scan_request *req;
+ bool *scanned_ch;
u8 state;
u8 ssid[IW_ESSID_MAX_SIZE+1];
size_t ssid_len;
- u8 active;
- u8 high_prio;
- u8 probe_requests;
};
struct wl1271_if_operations {
@@ -368,13 +341,14 @@ struct wl1271 {
#define WL1271_FLAG_JOINED (2)
#define WL1271_FLAG_GPIO_POWER (3)
#define WL1271_FLAG_TX_QUEUE_STOPPED (4)
-#define WL1271_FLAG_SCANNING (5)
-#define WL1271_FLAG_IN_ELP (6)
-#define WL1271_FLAG_PSM (7)
-#define WL1271_FLAG_PSM_REQUESTED (8)
-#define WL1271_FLAG_IRQ_PENDING (9)
-#define WL1271_FLAG_IRQ_RUNNING (10)
-#define WL1271_FLAG_IDLE (11)
+#define WL1271_FLAG_IN_ELP (5)
+#define WL1271_FLAG_PSM (6)
+#define WL1271_FLAG_PSM_REQUESTED (7)
+#define WL1271_FLAG_IRQ_PENDING (8)
+#define WL1271_FLAG_IRQ_RUNNING (9)
+#define WL1271_FLAG_IDLE (10)
+#define WL1271_FLAG_IDLE_REQUESTED (11)
+#define WL1271_FLAG_PSPOLL_FAILURE (12)
unsigned long flags;
struct wl1271_partition_set part;
@@ -421,6 +395,7 @@ struct wl1271 {
/* Pending TX frames */
struct sk_buff *tx_frames[ACX_TX_DESCRIPTORS];
+ int tx_frames_cnt;
/* Security sequence number counters */
u8 tx_security_last_seq;
@@ -468,6 +443,10 @@ struct wl1271 {
struct completion *elp_compl;
struct delayed_work elp_work;
+ struct delayed_work pspoll_work;
+
+ /* counter for ps-poll delivery failures */
+ int ps_poll_failures;
/* retry counter for PSM entries */
u8 psm_entry_retry;
@@ -496,6 +475,9 @@ struct wl1271 {
bool sg_enabled;
struct list_head list;
+
+ /* Most recently reported noise in dBm */
+ s8 noise;
};
int wl1271_plt_start(struct wl1271 *wl);
diff --git a/drivers/net/wireless/wl12xx/wl1271_acx.c b/drivers/net/wireless/wl12xx/wl1271_acx.c
index e19e2f8f1e5..bb245f05af4 100644
--- a/drivers/net/wireless/wl12xx/wl1271_acx.c
+++ b/drivers/net/wireless/wl12xx/wl1271_acx.c
@@ -1075,8 +1075,7 @@ out:
return ret;
}
-int wl1271_acx_arp_ip_filter(struct wl1271 *wl, bool enable, u8 *address,
- u8 version)
+int wl1271_acx_arp_ip_filter(struct wl1271 *wl, bool enable, __be32 address)
{
struct wl1271_acx_arp_filter *acx;
int ret;
@@ -1089,17 +1088,11 @@ int wl1271_acx_arp_ip_filter(struct wl1271 *wl, bool enable, u8 *address,
goto out;
}
- acx->version = version;
+ acx->version = ACX_IPV4_VERSION;
acx->enable = enable;
- if (enable == true) {
- if (version == ACX_IPV4_VERSION)
- memcpy(acx->address, address, ACX_IPV4_ADDR_SIZE);
- else if (version == ACX_IPV6_VERSION)
- memcpy(acx->address, address, sizeof(acx->address));
- else
- wl1271_error("Invalid IP version");
- }
+ if (enable == true)
+ memcpy(acx->address, &address, ACX_IPV4_ADDR_SIZE);
ret = wl1271_cmd_configure(wl, ACX_ARP_IP_FILTER,
acx, sizeof(*acx));
@@ -1266,3 +1259,29 @@ out:
kfree(acx);
return ret;
}
+
+int wl1271_acx_tsf_info(struct wl1271 *wl, u64 *mactime)
+{
+ struct wl1271_acx_fw_tsf_information *tsf_info;
+ int ret;
+
+ tsf_info = kzalloc(sizeof(*tsf_info), GFP_KERNEL);
+ if (!tsf_info) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ ret = wl1271_cmd_interrogate(wl, ACX_TSF_INFO,
+ tsf_info, sizeof(*tsf_info));
+ if (ret < 0) {
+ wl1271_warning("acx tsf info interrogate failed");
+ goto out;
+ }
+
+ *mactime = le32_to_cpu(tsf_info->current_tsf_low) |
+ ((u64) le32_to_cpu(tsf_info->current_tsf_high) << 32);
+
+out:
+ kfree(tsf_info);
+ return ret;
+}
diff --git a/drivers/net/wireless/wl12xx/wl1271_acx.h b/drivers/net/wireless/wl12xx/wl1271_acx.h
index 420e7e2fc02..4235bc56f75 100644
--- a/drivers/net/wireless/wl12xx/wl1271_acx.h
+++ b/drivers/net/wireless/wl12xx/wl1271_acx.h
@@ -75,7 +75,7 @@ struct acx_header {
/* payload length (not including headers */
__le16 len;
-} __attribute__ ((packed));
+} __packed;
struct acx_error_counter {
struct acx_header header;
@@ -98,7 +98,7 @@ struct acx_error_counter {
/* the number of missed sequence numbers in the squentially */
/* values of frames seq numbers */
__le32 seq_num_miss;
-} __attribute__ ((packed));
+} __packed;
struct acx_revision {
struct acx_header header;
@@ -127,7 +127,7 @@ struct acx_revision {
* bits 24 - 31: Chip ID - The WiLink chip ID.
*/
__le32 hw_version;
-} __attribute__ ((packed));
+} __packed;
enum wl1271_psm_mode {
/* Active mode */
@@ -149,7 +149,7 @@ struct acx_sleep_auth {
/* 2 - ELP mode: Deep / Max sleep*/
u8 sleep_auth;
u8 padding[3];
-} __attribute__ ((packed));
+} __packed;
enum {
HOSTIF_PCI_MASTER_HOST_INDIRECT,
@@ -187,7 +187,7 @@ struct acx_rx_msdu_lifetime {
* firmware discards the MSDU.
*/
__le32 lifetime;
-} __attribute__ ((packed));
+} __packed;
/*
* RX Config Options Table
@@ -275,13 +275,13 @@ struct acx_rx_config {
__le32 config_options;
__le32 filter_options;
-} __attribute__ ((packed));
+} __packed;
struct acx_packet_detection {
struct acx_header header;
__le32 threshold;
-} __attribute__ ((packed));
+} __packed;
enum acx_slot_type {
@@ -299,7 +299,7 @@ struct acx_slot {
u8 wone_index; /* Reserved */
u8 slot_time;
u8 reserved[6];
-} __attribute__ ((packed));
+} __packed;
#define ACX_MC_ADDRESS_GROUP_MAX (8)
@@ -312,21 +312,21 @@ struct acx_dot11_grp_addr_tbl {
u8 num_groups;
u8 pad[2];
u8 mac_table[ADDRESS_GROUP_MAX_LEN];
-} __attribute__ ((packed));
+} __packed;
struct acx_rx_timeout {
struct acx_header header;
__le16 ps_poll_timeout;
__le16 upsd_timeout;
-} __attribute__ ((packed));
+} __packed;
struct acx_rts_threshold {
struct acx_header header;
__le16 threshold;
u8 pad[2];
-} __attribute__ ((packed));
+} __packed;
struct acx_beacon_filter_option {
struct acx_header header;
@@ -342,7 +342,7 @@ struct acx_beacon_filter_option {
*/
u8 max_num_beacons;
u8 pad[2];
-} __attribute__ ((packed));
+} __packed;
/*
* ACXBeaconFilterEntry (not 221)
@@ -383,21 +383,21 @@ struct acx_beacon_filter_ie_table {
u8 num_ie;
u8 pad[3];
u8 table[BEACON_FILTER_TABLE_MAX_SIZE];
-} __attribute__ ((packed));
+} __packed;
struct acx_conn_monit_params {
struct acx_header header;
__le32 synch_fail_thold; /* number of beacons missed */
__le32 bss_lose_timeout; /* number of TU's from synch fail */
-} __attribute__ ((packed));
+} __packed;
struct acx_bt_wlan_coex {
struct acx_header header;
u8 enable;
u8 pad[3];
-} __attribute__ ((packed));
+} __packed;
struct acx_bt_wlan_coex_param {
struct acx_header header;
@@ -405,7 +405,7 @@ struct acx_bt_wlan_coex_param {
__le32 params[CONF_SG_PARAMS_MAX];
u8 param_idx;
u8 padding[3];
-} __attribute__ ((packed));
+} __packed;
struct acx_dco_itrim_params {
struct acx_header header;
@@ -413,7 +413,7 @@ struct acx_dco_itrim_params {
u8 enable;
u8 padding[3];
__le32 timeout;
-} __attribute__ ((packed));
+} __packed;
struct acx_energy_detection {
struct acx_header header;
@@ -422,7 +422,7 @@ struct acx_energy_detection {
__le16 rx_cca_threshold;
u8 tx_energy_detection;
u8 pad;
-} __attribute__ ((packed));
+} __packed;
struct acx_beacon_broadcast {
struct acx_header header;
@@ -436,14 +436,14 @@ struct acx_beacon_broadcast {
/* Consecutive PS Poll failures before updating the host */
u8 ps_poll_threshold;
u8 pad[2];
-} __attribute__ ((packed));
+} __packed;
struct acx_event_mask {
struct acx_header header;
__le32 event_mask;
__le32 high_event_mask; /* Unused */
-} __attribute__ ((packed));
+} __packed;
#define CFG_RX_FCS BIT(2)
#define CFG_RX_ALL_GOOD BIT(3)
@@ -488,14 +488,14 @@ struct acx_feature_config {
__le32 options;
__le32 data_flow_options;
-} __attribute__ ((packed));
+} __packed;
struct acx_current_tx_power {
struct acx_header header;
u8 current_tx_power;
u8 padding[3];
-} __attribute__ ((packed));
+} __packed;
struct acx_wake_up_condition {
struct acx_header header;
@@ -503,7 +503,7 @@ struct acx_wake_up_condition {
u8 wake_up_event; /* Only one bit can be set */
u8 listen_interval;
u8 pad[2];
-} __attribute__ ((packed));
+} __packed;
struct acx_aid {
struct acx_header header;
@@ -513,7 +513,7 @@ struct acx_aid {
*/
__le16 aid;
u8 pad[2];
-} __attribute__ ((packed));
+} __packed;
enum acx_preamble_type {
ACX_PREAMBLE_LONG = 0,
@@ -529,7 +529,7 @@ struct acx_preamble {
*/
u8 preamble;
u8 padding[3];
-} __attribute__ ((packed));
+} __packed;
enum acx_ctsprotect_type {
CTSPROTECT_DISABLE = 0,
@@ -540,11 +540,11 @@ struct acx_ctsprotect {
struct acx_header header;
u8 ctsprotect;
u8 padding[3];
-} __attribute__ ((packed));
+} __packed;
struct acx_tx_statistics {
__le32 internal_desc_overflow;
-} __attribute__ ((packed));
+} __packed;
struct acx_rx_statistics {
__le32 out_of_mem;
@@ -555,14 +555,14 @@ struct acx_rx_statistics {
__le32 xfr_hint_trig;
__le32 path_reset;
__le32 reset_counter;
-} __attribute__ ((packed));
+} __packed;
struct acx_dma_statistics {
__le32 rx_requested;
__le32 rx_errors;
__le32 tx_requested;
__le32 tx_errors;
-} __attribute__ ((packed));
+} __packed;
struct acx_isr_statistics {
/* host command complete */
@@ -621,7 +621,7 @@ struct acx_isr_statistics {
/* (INT_STS_ND & INT_TRIG_LOW_RSSI) */
__le32 low_rssi;
-} __attribute__ ((packed));
+} __packed;
struct acx_wep_statistics {
/* WEP address keys configured */
@@ -643,7 +643,7 @@ struct acx_wep_statistics {
/* WEP decrypt interrupts */
__le32 interrupt;
-} __attribute__ ((packed));
+} __packed;
#define ACX_MISSED_BEACONS_SPREAD 10
@@ -703,12 +703,12 @@ struct acx_pwr_statistics {
/* the number of beacons in awake mode */
__le32 rcvd_awake_beacons;
-} __attribute__ ((packed));
+} __packed;
struct acx_mic_statistics {
__le32 rx_pkts;
__le32 calc_failure;
-} __attribute__ ((packed));
+} __packed;
struct acx_aes_statistics {
__le32 encrypt_fail;
@@ -717,7 +717,7 @@ struct acx_aes_statistics {
__le32 decrypt_packets;
__le32 encrypt_interrupt;
__le32 decrypt_interrupt;
-} __attribute__ ((packed));
+} __packed;
struct acx_event_statistics {
__le32 heart_beat;
@@ -728,7 +728,7 @@ struct acx_event_statistics {
__le32 oom_late;
__le32 phy_transmit_error;
__le32 tx_stuck;
-} __attribute__ ((packed));
+} __packed;
struct acx_ps_statistics {
__le32 pspoll_timeouts;
@@ -738,7 +738,7 @@ struct acx_ps_statistics {
__le32 pspoll_max_apturn;
__le32 pspoll_utilization;
__le32 upsd_utilization;
-} __attribute__ ((packed));
+} __packed;
struct acx_rxpipe_statistics {
__le32 rx_prep_beacon_drop;
@@ -746,7 +746,7 @@ struct acx_rxpipe_statistics {
__le32 beacon_buffer_thres_host_int_trig_rx_data;
__le32 missed_beacon_host_int_trig_rx_data;
__le32 tx_xfr_host_int_trig_rx_data;
-} __attribute__ ((packed));
+} __packed;
struct acx_statistics {
struct acx_header header;
@@ -762,7 +762,7 @@ struct acx_statistics {
struct acx_event_statistics event;
struct acx_ps_statistics ps;
struct acx_rxpipe_statistics rxpipe;
-} __attribute__ ((packed));
+} __packed;
struct acx_rate_class {
__le32 enabled_rates;
@@ -780,7 +780,7 @@ struct acx_rate_policy {
__le32 rate_class_cnt;
struct acx_rate_class rate_class[CONF_TX_MAX_RATE_CLASSES];
-} __attribute__ ((packed));
+} __packed;
struct acx_ac_cfg {
struct acx_header header;
@@ -790,7 +790,7 @@ struct acx_ac_cfg {
u8 aifsn;
u8 reserved;
__le16 tx_op_limit;
-} __attribute__ ((packed));
+} __packed;
struct acx_tid_config {
struct acx_header header;
@@ -801,19 +801,19 @@ struct acx_tid_config {
u8 ack_policy;
u8 padding[3];
__le32 apsd_conf[2];
-} __attribute__ ((packed));
+} __packed;
struct acx_frag_threshold {
struct acx_header header;
__le16 frag_threshold;
u8 padding[2];
-} __attribute__ ((packed));
+} __packed;
struct acx_tx_config_options {
struct acx_header header;
__le16 tx_compl_timeout; /* msec */
__le16 tx_compl_threshold; /* number of packets */
-} __attribute__ ((packed));
+} __packed;
#define ACX_RX_MEM_BLOCKS 70
#define ACX_TX_MIN_MEM_BLOCKS 40
@@ -828,7 +828,7 @@ struct wl1271_acx_config_memory {
u8 num_stations;
u8 num_ssid_profiles;
__le32 total_tx_descriptors;
-} __attribute__ ((packed));
+} __packed;
struct wl1271_acx_mem_map {
struct acx_header header;
@@ -872,7 +872,7 @@ struct wl1271_acx_mem_map {
u8 *rx_cbuf;
__le32 rx_ctrl;
__le32 tx_ctrl;
-} __attribute__ ((packed));
+} __packed;
struct wl1271_acx_rx_config_opt {
struct acx_header header;
@@ -882,7 +882,7 @@ struct wl1271_acx_rx_config_opt {
__le16 timeout;
u8 queue_type;
u8 reserved;
-} __attribute__ ((packed));
+} __packed;
struct wl1271_acx_bet_enable {
@@ -891,7 +891,7 @@ struct wl1271_acx_bet_enable {
u8 enable;
u8 max_consecutive;
u8 padding[2];
-} __attribute__ ((packed));
+} __packed;
#define ACX_IPV4_VERSION 4
#define ACX_IPV6_VERSION 6
@@ -905,7 +905,7 @@ struct wl1271_acx_arp_filter {
requests directed to this IP address will pass
through. For IPv4, the first four bytes are
used. */
-} __attribute__((packed));
+} __packed;
struct wl1271_acx_pm_config {
struct acx_header header;
@@ -913,14 +913,14 @@ struct wl1271_acx_pm_config {
__le32 host_clk_settling_time;
u8 host_fast_wakeup_support;
u8 padding[3];
-} __attribute__ ((packed));
+} __packed;
struct wl1271_acx_keep_alive_mode {
struct acx_header header;
u8 enabled;
u8 padding[3];
-} __attribute__ ((packed));
+} __packed;
enum {
ACX_KEEP_ALIVE_NO_TX = 0,
@@ -940,7 +940,7 @@ struct wl1271_acx_keep_alive_config {
u8 tpl_validation;
u8 trigger;
u8 padding;
-} __attribute__ ((packed));
+} __packed;
enum {
WL1271_ACX_TRIG_TYPE_LEVEL = 0,
@@ -993,6 +993,17 @@ struct wl1271_acx_rssi_snr_avg_weights {
u8 snr_data;
};
+struct wl1271_acx_fw_tsf_information {
+ struct acx_header header;
+
+ __le32 current_tsf_high;
+ __le32 current_tsf_low;
+ __le32 last_bttt_high;
+ __le32 last_tbtt_low;
+ u8 last_dtim_count;
+ u8 padding[3];
+} __packed;
+
enum {
ACX_WAKE_UP_CONDITIONS = 0x0002,
ACX_MEM_CFG = 0x0003,
@@ -1106,13 +1117,13 @@ int wl1271_acx_init_mem_config(struct wl1271 *wl);
int wl1271_acx_init_rx_interrupt(struct wl1271 *wl);
int wl1271_acx_smart_reflex(struct wl1271 *wl);
int wl1271_acx_bet_enable(struct wl1271 *wl, bool enable);
-int wl1271_acx_arp_ip_filter(struct wl1271 *wl, bool enable, u8 *address,
- u8 version);
+int wl1271_acx_arp_ip_filter(struct wl1271 *wl, bool enable, __be32 address);
int wl1271_acx_pm_config(struct wl1271 *wl);
int wl1271_acx_keep_alive_mode(struct wl1271 *wl, bool enable);
int wl1271_acx_keep_alive_config(struct wl1271 *wl, u8 index, u8 tpl_valid);
int wl1271_acx_rssi_snr_trigger(struct wl1271 *wl, bool enable,
s16 thold, u8 hyst);
int wl1271_acx_rssi_snr_avg_weights(struct wl1271 *wl);
+int wl1271_acx_tsf_info(struct wl1271 *wl, u64 *mactime);
#endif /* __WL1271_ACX_H__ */
diff --git a/drivers/net/wireless/wl12xx/wl1271_boot.c b/drivers/net/wireless/wl12xx/wl1271_boot.c
index 1a36d8a2196..f36430b0336 100644
--- a/drivers/net/wireless/wl12xx/wl1271_boot.c
+++ b/drivers/net/wireless/wl12xx/wl1271_boot.c
@@ -414,7 +414,9 @@ static int wl1271_boot_run_firmware(struct wl1271 *wl)
PS_REPORT_EVENT_ID |
JOIN_EVENT_COMPLETE_ID |
DISCONNECT_EVENT_COMPLETE_ID |
- RSSI_SNR_TRIGGER_0_EVENT_ID;
+ RSSI_SNR_TRIGGER_0_EVENT_ID |
+ PSPOLL_DELIVERY_FAILURE_EVENT_ID |
+ SOFT_GEMINI_SENSE_EVENT_ID;
ret = wl1271_event_unmask(wl);
if (ret < 0) {
diff --git a/drivers/net/wireless/wl12xx/wl1271_cmd.c b/drivers/net/wireless/wl12xx/wl1271_cmd.c
index 19393e236e2..ce503ddd5a4 100644
--- a/drivers/net/wireless/wl12xx/wl1271_cmd.c
+++ b/drivers/net/wireless/wl12xx/wl1271_cmd.c
@@ -104,100 +104,6 @@ out:
return ret;
}
-static int wl1271_cmd_cal_channel_tune(struct wl1271 *wl)
-{
- struct wl1271_cmd_cal_channel_tune *cmd;
- int ret = 0;
-
- cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
- if (!cmd)
- return -ENOMEM;
-
- cmd->test.id = TEST_CMD_CHANNEL_TUNE;
-
- cmd->band = WL1271_CHANNEL_TUNE_BAND_2_4;
- /* set up any channel, 7 is in the middle of the range */
- cmd->channel = 7;
-
- ret = wl1271_cmd_test(wl, cmd, sizeof(*cmd), 0);
- if (ret < 0)
- wl1271_warning("TEST_CMD_CHANNEL_TUNE failed");
-
- kfree(cmd);
- return ret;
-}
-
-static int wl1271_cmd_cal_update_ref_point(struct wl1271 *wl)
-{
- struct wl1271_cmd_cal_update_ref_point *cmd;
- int ret = 0;
-
- cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
- if (!cmd)
- return -ENOMEM;
-
- cmd->test.id = TEST_CMD_UPDATE_PD_REFERENCE_POINT;
-
- /* FIXME: still waiting for the correct values */
- cmd->ref_power = 0;
- cmd->ref_detector = 0;
-
- cmd->sub_band = WL1271_PD_REFERENCE_POINT_BAND_B_G;
-
- ret = wl1271_cmd_test(wl, cmd, sizeof(*cmd), 0);
- if (ret < 0)
- wl1271_warning("TEST_CMD_UPDATE_PD_REFERENCE_POINT failed");
-
- kfree(cmd);
- return ret;
-}
-
-static int wl1271_cmd_cal_p2g(struct wl1271 *wl)
-{
- struct wl1271_cmd_cal_p2g *cmd;
- int ret = 0;
-
- cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
- if (!cmd)
- return -ENOMEM;
-
- cmd->test.id = TEST_CMD_P2G_CAL;
-
- cmd->sub_band_mask = WL1271_CAL_P2G_BAND_B_G;
-
- ret = wl1271_cmd_test(wl, cmd, sizeof(*cmd), 0);
- if (ret < 0)
- wl1271_warning("TEST_CMD_P2G_CAL failed");
-
- kfree(cmd);
- return ret;
-}
-
-static int wl1271_cmd_cal(struct wl1271 *wl)
-{
- /*
- * FIXME: we must make sure that we're not sleeping when calibration
- * is done
- */
- int ret;
-
- wl1271_notice("performing tx calibration");
-
- ret = wl1271_cmd_cal_channel_tune(wl);
- if (ret < 0)
- return ret;
-
- ret = wl1271_cmd_cal_update_ref_point(wl);
- if (ret < 0)
- return ret;
-
- ret = wl1271_cmd_cal_p2g(wl);
- if (ret < 0)
- return ret;
-
- return ret;
-}
-
int wl1271_cmd_general_parms(struct wl1271 *wl)
{
struct wl1271_general_parms_cmd *gen_parms;
@@ -212,8 +118,8 @@ int wl1271_cmd_general_parms(struct wl1271 *wl)
gen_parms->test.id = TEST_CMD_INI_FILE_GENERAL_PARAM;
- memcpy(gen_parms->params, wl->nvs->general_params,
- WL1271_NVS_GENERAL_PARAMS_SIZE);
+ memcpy(&gen_parms->general_params, &wl->nvs->general_params,
+ sizeof(struct wl1271_ini_general_params));
ret = wl1271_cmd_test(wl, gen_parms, sizeof(*gen_parms), 0);
if (ret < 0)
@@ -226,7 +132,7 @@ int wl1271_cmd_general_parms(struct wl1271 *wl)
int wl1271_cmd_radio_parms(struct wl1271 *wl)
{
struct wl1271_radio_parms_cmd *radio_parms;
- struct conf_radio_parms *rparam = &wl->conf.init.radioparam;
+ struct wl1271_ini_general_params *gp = &wl->nvs->general_params;
int ret;
if (!wl->nvs)
@@ -238,13 +144,20 @@ int wl1271_cmd_radio_parms(struct wl1271 *wl)
radio_parms->test.id = TEST_CMD_INI_FILE_RADIO_PARAM;
- memcpy(radio_parms->stat_radio_params, wl->nvs->stat_radio_params,
- WL1271_NVS_STAT_RADIO_PARAMS_SIZE);
- memcpy(radio_parms->dyn_radio_params,
- wl->nvs->dyn_radio_params[rparam->fem],
- WL1271_NVS_DYN_RADIO_PARAMS_SIZE);
-
- /* FIXME: current NVS is missing 5GHz parameters */
+ /* 2.4GHz parameters */
+ memcpy(&radio_parms->static_params_2, &wl->nvs->stat_radio_params_2,
+ sizeof(struct wl1271_ini_band_params_2));
+ memcpy(&radio_parms->dyn_params_2,
+ &wl->nvs->dyn_radio_params_2[gp->tx_bip_fem_manufacturer].params,
+ sizeof(struct wl1271_ini_fem_params_2));
+
+ /* 5GHz parameters */
+ memcpy(&radio_parms->static_params_5,
+ &wl->nvs->stat_radio_params_5,
+ sizeof(struct wl1271_ini_band_params_5));
+ memcpy(&radio_parms->dyn_params_5,
+ &wl->nvs->dyn_radio_params_5[gp->tx_bip_fem_manufacturer].params,
+ sizeof(struct wl1271_ini_fem_params_5));
wl1271_dump(DEBUG_CMD, "TEST_CMD_INI_FILE_RADIO_PARAM: ",
radio_parms, sizeof(*radio_parms));
@@ -288,20 +201,10 @@ static int wl1271_cmd_wait_for_event(struct wl1271 *wl, u32 mask)
int wl1271_cmd_join(struct wl1271 *wl, u8 bss_type)
{
- static bool do_cal = true;
struct wl1271_cmd_join *join;
int ret, i;
u8 *bssid;
- /* FIXME: remove when we get calibration from the factory */
- if (do_cal) {
- ret = wl1271_cmd_cal(wl);
- if (ret < 0)
- wl1271_warning("couldn't calibrate");
- else
- do_cal = false;
- }
-
join = kzalloc(sizeof(*join), GFP_KERNEL);
if (!join) {
ret = -ENOMEM;
@@ -329,12 +232,6 @@ int wl1271_cmd_join(struct wl1271 *wl, u8 bss_type)
join->channel = wl->channel;
join->ssid_len = wl->ssid_len;
memcpy(join->ssid, wl->ssid, wl->ssid_len);
- join->ctrl = WL1271_JOIN_CMD_CTRL_TX_FLUSH;
-
- /* increment the session counter */
- wl->session_counter++;
- if (wl->session_counter >= SESSION_COUNTER_MAX)
- wl->session_counter = 0;
join->ctrl |= wl->session_counter << WL1271_JOIN_CMD_TX_SESSION_OFFSET;
@@ -517,7 +414,7 @@ int wl1271_cmd_ps_mode(struct wl1271 *wl, u8 ps_mode, bool send)
ps_params->send_null_data = send;
ps_params->retries = 5;
ps_params->hang_over_period = 1;
- ps_params->null_data_rate = cpu_to_le32(1); /* 1 Mbps */
+ ps_params->null_data_rate = cpu_to_le32(wl->basic_rate_set);
ret = wl1271_cmd_send(wl, CMD_SET_PS_MODE, ps_params,
sizeof(*ps_params), 0);
@@ -566,140 +463,6 @@ out:
return ret;
}
-int wl1271_cmd_scan(struct wl1271 *wl, const u8 *ssid, size_t ssid_len,
- const u8 *ie, size_t ie_len, u8 active_scan,
- u8 high_prio, u8 band, u8 probe_requests)
-{
-
- struct wl1271_cmd_trigger_scan_to *trigger = NULL;
- struct wl1271_cmd_scan *params = NULL;
- struct ieee80211_channel *channels;
- u32 rate;
- int i, j, n_ch, ret;
- u16 scan_options = 0;
- u8 ieee_band;
-
- if (band == WL1271_SCAN_BAND_2_4_GHZ) {
- ieee_band = IEEE80211_BAND_2GHZ;
- rate = wl->conf.tx.basic_rate;
- } else if (band == WL1271_SCAN_BAND_DUAL && wl1271_11a_enabled()) {
- ieee_band = IEEE80211_BAND_2GHZ;
- rate = wl->conf.tx.basic_rate;
- } else if (band == WL1271_SCAN_BAND_5_GHZ && wl1271_11a_enabled()) {
- ieee_band = IEEE80211_BAND_5GHZ;
- rate = wl->conf.tx.basic_rate_5;
- } else
- return -EINVAL;
-
- if (wl->hw->wiphy->bands[ieee_band]->channels == NULL)
- return -EINVAL;
-
- channels = wl->hw->wiphy->bands[ieee_band]->channels;
- n_ch = wl->hw->wiphy->bands[ieee_band]->n_channels;
-
- if (test_bit(WL1271_FLAG_SCANNING, &wl->flags))
- return -EINVAL;
-
- params = kzalloc(sizeof(*params), GFP_KERNEL);
- if (!params)
- return -ENOMEM;
-
- params->params.rx_config_options = cpu_to_le32(CFG_RX_ALL_GOOD);
- params->params.rx_filter_options =
- cpu_to_le32(CFG_RX_PRSP_EN | CFG_RX_MGMT_EN | CFG_RX_BCN_EN);
-
- if (!active_scan)
- scan_options |= WL1271_SCAN_OPT_PASSIVE;
- if (high_prio)
- scan_options |= WL1271_SCAN_OPT_PRIORITY_HIGH;
- params->params.scan_options = cpu_to_le16(scan_options);
-
- params->params.num_probe_requests = probe_requests;
- params->params.tx_rate = cpu_to_le32(rate);
- params->params.tid_trigger = 0;
- params->params.scan_tag = WL1271_SCAN_DEFAULT_TAG;
-
- if (band == WL1271_SCAN_BAND_DUAL)
- params->params.band = WL1271_SCAN_BAND_2_4_GHZ;
- else
- params->params.band = band;
-
- for (i = 0, j = 0; i < n_ch && i < WL1271_SCAN_MAX_CHANNELS; i++) {
- if (!(channels[i].flags & IEEE80211_CHAN_DISABLED)) {
- params->channels[j].min_duration =
- cpu_to_le32(WL1271_SCAN_CHAN_MIN_DURATION);
- params->channels[j].max_duration =
- cpu_to_le32(WL1271_SCAN_CHAN_MAX_DURATION);
- memset(&params->channels[j].bssid_lsb, 0xff, 4);
- memset(&params->channels[j].bssid_msb, 0xff, 2);
- params->channels[j].early_termination = 0;
- params->channels[j].tx_power_att =
- WL1271_SCAN_CURRENT_TX_PWR;
- params->channels[j].channel = channels[i].hw_value;
- j++;
- }
- }
-
- params->params.num_channels = j;
-
- if (ssid_len && ssid) {
- params->params.ssid_len = ssid_len;
- memcpy(params->params.ssid, ssid, ssid_len);
- }
-
- ret = wl1271_cmd_build_probe_req(wl, ssid, ssid_len,
- ie, ie_len, ieee_band);
- if (ret < 0) {
- wl1271_error("PROBE request template failed");
- goto out;
- }
-
- trigger = kzalloc(sizeof(*trigger), GFP_KERNEL);
- if (!trigger) {
- ret = -ENOMEM;
- goto out;
- }
-
- /* disable the timeout */
- trigger->timeout = 0;
-
- ret = wl1271_cmd_send(wl, CMD_TRIGGER_SCAN_TO, trigger,
- sizeof(*trigger), 0);
- if (ret < 0) {
- wl1271_error("trigger scan to failed for hw scan");
- goto out;
- }
-
- wl1271_dump(DEBUG_SCAN, "SCAN: ", params, sizeof(*params));
-
- set_bit(WL1271_FLAG_SCANNING, &wl->flags);
- if (wl1271_11a_enabled()) {
- wl->scan.state = band;
- if (band == WL1271_SCAN_BAND_DUAL) {
- wl->scan.active = active_scan;
- wl->scan.high_prio = high_prio;
- wl->scan.probe_requests = probe_requests;
- if (ssid_len && ssid) {
- wl->scan.ssid_len = ssid_len;
- memcpy(wl->scan.ssid, ssid, ssid_len);
- } else
- wl->scan.ssid_len = 0;
- }
- }
-
- ret = wl1271_cmd_send(wl, CMD_SCAN, params, sizeof(*params), 0);
- if (ret < 0) {
- wl1271_error("SCAN failed");
- clear_bit(WL1271_FLAG_SCANNING, &wl->flags);
- goto out;
- }
-
-out:
- kfree(params);
- kfree(trigger);
- return ret;
-}
-
int wl1271_cmd_template_set(struct wl1271 *wl, u16 template_id,
void *buf, size_t buf_len, int index, u32 rates)
{
@@ -804,7 +567,7 @@ int wl1271_cmd_build_ps_poll(struct wl1271 *wl, u16 aid)
goto out;
ret = wl1271_cmd_template_set(wl, CMD_TEMPL_PS_POLL, skb->data,
- skb->len, 0, wl->basic_rate);
+ skb->len, 0, wl->basic_rate_set);
out:
dev_kfree_skb(skb);
diff --git a/drivers/net/wireless/wl12xx/wl1271_cmd.h b/drivers/net/wireless/wl12xx/wl1271_cmd.h
index f2820b42a94..af577ee8eb0 100644
--- a/drivers/net/wireless/wl12xx/wl1271_cmd.h
+++ b/drivers/net/wireless/wl12xx/wl1271_cmd.h
@@ -41,9 +41,6 @@ int wl1271_cmd_data_path(struct wl1271 *wl, bool enable);
int wl1271_cmd_ps_mode(struct wl1271 *wl, u8 ps_mode, bool send);
int wl1271_cmd_read_memory(struct wl1271 *wl, u32 addr, void *answer,
size_t len);
-int wl1271_cmd_scan(struct wl1271 *wl, const u8 *ssid, size_t ssid_len,
- const u8 *ie, size_t ie_len, u8 active_scan,
- u8 high_prio, u8 band, u8 probe_requests);
int wl1271_cmd_template_set(struct wl1271 *wl, u16 template_id,
void *buf, size_t buf_len, int index, u32 rates);
int wl1271_cmd_build_null_data(struct wl1271 *wl);
@@ -136,14 +133,14 @@ struct wl1271_cmd_header {
__le16 status;
/* payload */
u8 data[0];
-} __attribute__ ((packed));
+} __packed;
#define WL1271_CMD_MAX_PARAMS 572
struct wl1271_command {
struct wl1271_cmd_header header;
u8 parameters[WL1271_CMD_MAX_PARAMS];
-} __attribute__ ((packed));
+} __packed;
enum {
CMD_MAILBOX_IDLE = 0,
@@ -196,7 +193,7 @@ struct cmd_read_write_memory {
of this field is the Host in WRITE command or the Wilink in READ
command. */
u8 value[MAX_READ_SIZE];
-} __attribute__ ((packed));
+} __packed;
#define CMDMBOX_HEADER_LEN 4
#define CMDMBOX_INFO_ELEM_HEADER_LEN 4
@@ -243,14 +240,14 @@ struct wl1271_cmd_join {
u8 ssid[IW_ESSID_MAX_SIZE];
u8 ctrl; /* JOIN_CMD_CTRL_* */
u8 reserved[3];
-} __attribute__ ((packed));
+} __packed;
struct cmd_enabledisable_path {
struct wl1271_cmd_header header;
u8 channel;
u8 padding[3];
-} __attribute__ ((packed));
+} __packed;
#define WL1271_RATE_AUTOMATIC 0
@@ -266,7 +263,7 @@ struct wl1271_cmd_template_set {
u8 aflags;
u8 reserved;
u8 template_data[WL1271_CMD_TEMPL_MAX_SIZE];
-} __attribute__ ((packed));
+} __packed;
#define TIM_ELE_ID 5
#define PARTIAL_VBM_MAX 251
@@ -278,7 +275,7 @@ struct wl1271_tim {
u8 dtim_period;
u8 bitmap_ctrl;
u8 pvb_field[PARTIAL_VBM_MAX]; /* Partial Virtual Bitmap */
-} __attribute__ ((packed));
+} __packed;
enum wl1271_cmd_ps_mode {
STATION_ACTIVE_MODE,
@@ -298,7 +295,7 @@ struct wl1271_cmd_ps_params {
*/
u8 hang_over_period;
__le32 null_data_rate;
-} __attribute__ ((packed));
+} __packed;
/* HW encryption keys */
#define NUM_ACCESS_CATEGORIES_COPY 4
@@ -348,77 +345,12 @@ struct wl1271_cmd_set_keys {
u8 key[MAX_KEY_SIZE];
__le16 ac_seq_num16[NUM_ACCESS_CATEGORIES_COPY];
__le32 ac_seq_num32[NUM_ACCESS_CATEGORIES_COPY];
-} __attribute__ ((packed));
-
-
-#define WL1271_SCAN_MAX_CHANNELS 24
-#define WL1271_SCAN_DEFAULT_TAG 1
-#define WL1271_SCAN_CURRENT_TX_PWR 0
-#define WL1271_SCAN_OPT_ACTIVE 0
-#define WL1271_SCAN_OPT_PASSIVE 1
-#define WL1271_SCAN_OPT_PRIORITY_HIGH 4
-#define WL1271_SCAN_CHAN_MIN_DURATION 30000 /* TU */
-#define WL1271_SCAN_CHAN_MAX_DURATION 60000 /* TU */
-#define WL1271_SCAN_BAND_2_4_GHZ 0
-#define WL1271_SCAN_BAND_5_GHZ 1
-#define WL1271_SCAN_BAND_DUAL 2
-
-struct basic_scan_params {
- __le32 rx_config_options;
- __le32 rx_filter_options;
- /* Scan option flags (WL1271_SCAN_OPT_*) */
- __le16 scan_options;
- /* Number of scan channels in the list (maximum 30) */
- u8 num_channels;
- /* This field indicates the number of probe requests to send
- per channel for an active scan */
- u8 num_probe_requests;
- /* Rate bit field for sending the probes */
- __le32 tx_rate;
- u8 tid_trigger;
- u8 ssid_len;
- /* in order to align */
- u8 padding1[2];
- u8 ssid[IW_ESSID_MAX_SIZE];
- /* Band to scan */
- u8 band;
- u8 use_ssid_list;
- u8 scan_tag;
- u8 padding2;
-} __attribute__ ((packed));
-
-struct basic_scan_channel_params {
- /* Duration in TU to wait for frames on a channel for active scan */
- __le32 min_duration;
- __le32 max_duration;
- __le32 bssid_lsb;
- __le16 bssid_msb;
- u8 early_termination;
- u8 tx_power_att;
- u8 channel;
- /* FW internal use only! */
- u8 dfs_candidate;
- u8 activity_detected;
- u8 pad;
-} __attribute__ ((packed));
-
-struct wl1271_cmd_scan {
- struct wl1271_cmd_header header;
-
- struct basic_scan_params params;
- struct basic_scan_channel_params channels[WL1271_SCAN_MAX_CHANNELS];
-} __attribute__ ((packed));
-
-struct wl1271_cmd_trigger_scan_to {
- struct wl1271_cmd_header header;
-
- __le32 timeout;
-} __attribute__ ((packed));
+} __packed;
struct wl1271_cmd_test_header {
u8 id;
u8 padding[3];
-} __attribute__ ((packed));
+} __packed;
enum wl1271_channel_tune_bands {
WL1271_CHANNEL_TUNE_BAND_2_4,
@@ -439,25 +371,31 @@ struct wl1271_general_parms_cmd {
struct wl1271_cmd_test_header test;
- u8 params[WL1271_NVS_GENERAL_PARAMS_SIZE];
- s8 reserved[23];
-} __attribute__ ((packed));
+ struct wl1271_ini_general_params general_params;
-#define WL1271_STAT_RADIO_PARAMS_5_SIZE 29
-#define WL1271_DYN_RADIO_PARAMS_5_SIZE 104
+ u8 sr_debug_table[WL1271_INI_MAX_SMART_REFLEX_PARAM];
+ u8 sr_sen_n_p;
+ u8 sr_sen_n_p_gain;
+ u8 sr_sen_nrn;
+ u8 sr_sen_prn;
+ u8 padding[3];
+} __packed;
struct wl1271_radio_parms_cmd {
struct wl1271_cmd_header header;
struct wl1271_cmd_test_header test;
- u8 stat_radio_params[WL1271_NVS_STAT_RADIO_PARAMS_SIZE];
- u8 stat_radio_params_5[WL1271_STAT_RADIO_PARAMS_5_SIZE];
+ /* Static radio parameters */
+ struct wl1271_ini_band_params_2 static_params_2;
+ struct wl1271_ini_band_params_5 static_params_5;
- u8 dyn_radio_params[WL1271_NVS_DYN_RADIO_PARAMS_SIZE];
- u8 reserved;
- u8 dyn_radio_params_5[WL1271_DYN_RADIO_PARAMS_5_SIZE];
-} __attribute__ ((packed));
+ /* Dynamic radio parameters */
+ struct wl1271_ini_fem_params_2 dyn_params_2;
+ u8 padding2;
+ struct wl1271_ini_fem_params_5 dyn_params_5;
+ u8 padding3[2];
+} __packed;
struct wl1271_cmd_cal_channel_tune {
struct wl1271_cmd_header header;
@@ -468,7 +406,7 @@ struct wl1271_cmd_cal_channel_tune {
u8 channel;
__le16 radio_status;
-} __attribute__ ((packed));
+} __packed;
struct wl1271_cmd_cal_update_ref_point {
struct wl1271_cmd_header header;
@@ -479,7 +417,7 @@ struct wl1271_cmd_cal_update_ref_point {
__le32 ref_detector;
u8 sub_band;
u8 padding[3];
-} __attribute__ ((packed));
+} __packed;
#define MAX_TLV_LENGTH 400
#define MAX_NVS_VERSION_LENGTH 12
@@ -501,7 +439,7 @@ struct wl1271_cmd_cal_p2g {
u8 sub_band_mask;
u8 padding2;
-} __attribute__ ((packed));
+} __packed;
/*
@@ -529,6 +467,6 @@ struct wl1271_cmd_disconnect {
u8 type;
u8 padding;
-} __attribute__ ((packed));
+} __packed;
#endif /* __WL1271_CMD_H__ */
diff --git a/drivers/net/wireless/wl12xx/wl1271_conf.h b/drivers/net/wireless/wl12xx/wl1271_conf.h
index d046d044b5b..0435ffda8f7 100644
--- a/drivers/net/wireless/wl12xx/wl1271_conf.h
+++ b/drivers/net/wireless/wl12xx/wl1271_conf.h
@@ -874,6 +874,13 @@ struct conf_conn_settings {
u8 ps_poll_threshold;
/*
+ * PS Poll failure recovery ACTIVE period length
+ *
+ * Range: u32 (ms)
+ */
+ u32 ps_poll_recovery_period;
+
+ /*
* Configuration of signal average weights.
*/
struct conf_sig_weights sig_weights;
@@ -948,14 +955,6 @@ struct conf_radio_parms {
u8 fem;
};
-struct conf_init_settings {
- /*
- * Configure radio parameters.
- */
- struct conf_radio_parms radioparam;
-
-};
-
struct conf_itrim_settings {
/* enable dco itrim */
u8 enable;
@@ -1022,7 +1021,6 @@ struct conf_drv_settings {
struct conf_rx_settings rx;
struct conf_tx_settings tx;
struct conf_conn_settings conn;
- struct conf_init_settings init;
struct conf_itrim_settings itrim;
struct conf_pm_config_settings pm_config;
struct conf_roam_trigger_settings roam_trigger;
diff --git a/drivers/net/wireless/wl12xx/wl1271_event.c b/drivers/net/wireless/wl12xx/wl1271_event.c
index cf37aa6eb13..25ce2cd5e3f 100644
--- a/drivers/net/wireless/wl12xx/wl1271_event.c
+++ b/drivers/net/wireless/wl12xx/wl1271_event.c
@@ -26,36 +26,64 @@
#include "wl1271_io.h"
#include "wl1271_event.h"
#include "wl1271_ps.h"
+#include "wl1271_scan.h"
#include "wl12xx_80211.h"
-static int wl1271_event_scan_complete(struct wl1271 *wl,
- struct event_mailbox *mbox)
+void wl1271_pspoll_work(struct work_struct *work)
{
- wl1271_debug(DEBUG_EVENT, "status: 0x%x",
- mbox->scheduled_scan_status);
-
- if (test_bit(WL1271_FLAG_SCANNING, &wl->flags)) {
- if (wl->scan.state == WL1271_SCAN_BAND_DUAL) {
- /* 2.4 GHz band scanned, scan 5 GHz band, pretend
- * to the wl1271_cmd_scan function that we are not
- * scanning as it checks that.
- */
- clear_bit(WL1271_FLAG_SCANNING, &wl->flags);
- /* FIXME: ie missing! */
- wl1271_cmd_scan(wl, wl->scan.ssid, wl->scan.ssid_len,
- NULL, 0,
- wl->scan.active,
- wl->scan.high_prio,
- WL1271_SCAN_BAND_5_GHZ,
- wl->scan.probe_requests);
- } else {
- mutex_unlock(&wl->mutex);
- ieee80211_scan_completed(wl->hw, false);
- mutex_lock(&wl->mutex);
- clear_bit(WL1271_FLAG_SCANNING, &wl->flags);
- }
+ struct delayed_work *dwork;
+ struct wl1271 *wl;
+
+ dwork = container_of(work, struct delayed_work, work);
+ wl = container_of(dwork, struct wl1271, pspoll_work);
+
+ wl1271_debug(DEBUG_EVENT, "pspoll work");
+
+ mutex_lock(&wl->mutex);
+
+ if (!test_and_clear_bit(WL1271_FLAG_PSPOLL_FAILURE, &wl->flags))
+ goto out;
+
+ if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
+ goto out;
+
+ /*
+ * if we end up here, then we were in powersave when the pspoll
+ * delivery failure occurred, and no-one changed state since, so
+ * we should go back to powersave.
+ */
+ wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE, true);
+
+out:
+ mutex_unlock(&wl->mutex);
+};
+
+static void wl1271_event_pspoll_delivery_fail(struct wl1271 *wl)
+{
+ int delay = wl->conf.conn.ps_poll_recovery_period;
+ int ret;
+
+ wl->ps_poll_failures++;
+ if (wl->ps_poll_failures == 1)
+ wl1271_info("AP with dysfunctional ps-poll, "
+ "trying to work around it.");
+
+ /* force active mode receive data from the AP */
+ if (test_bit(WL1271_FLAG_PSM, &wl->flags)) {
+ ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE, true);
+ if (ret < 0)
+ return;
+ set_bit(WL1271_FLAG_PSPOLL_FAILURE, &wl->flags);
+ ieee80211_queue_delayed_work(wl->hw, &wl->pspoll_work,
+ msecs_to_jiffies(delay));
}
- return 0;
+
+ /*
+ * If already in active mode, lets we should be getting data from
+ * the AP right away. If we enter PSM too fast after this, and data
+ * remains on the AP, we will get another event like this, and we'll
+ * go into active once more.
+ */
}
static int wl1271_event_ps_report(struct wl1271 *wl,
@@ -163,9 +191,19 @@ static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox)
wl1271_debug(DEBUG_EVENT, "vector: 0x%x", vector);
if (vector & SCAN_COMPLETE_EVENT_ID) {
- ret = wl1271_event_scan_complete(wl, mbox);
- if (ret < 0)
- return ret;
+ wl1271_debug(DEBUG_EVENT, "status: 0x%x",
+ mbox->scheduled_scan_status);
+
+ wl1271_scan_stm(wl);
+ }
+
+ /* disable dynamic PS when requested by the firmware */
+ if (vector & SOFT_GEMINI_SENSE_EVENT_ID &&
+ wl->bss_type == BSS_TYPE_STA_BSS) {
+ if (mbox->soft_gemini_sense_info)
+ ieee80211_disable_dyn_ps(wl->vif);
+ else
+ ieee80211_enable_dyn_ps(wl->vif);
}
/*
@@ -191,6 +229,9 @@ static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox)
return ret;
}
+ if (vector & PSPOLL_DELIVERY_FAILURE_EVENT_ID)
+ wl1271_event_pspoll_delivery_fail(wl);
+
if (vector & RSSI_SNR_TRIGGER_0_EVENT_ID) {
wl1271_debug(DEBUG_EVENT, "RSSI_SNR_TRIGGER_0_EVENT");
if (wl->vif)
diff --git a/drivers/net/wireless/wl12xx/wl1271_event.h b/drivers/net/wireless/wl12xx/wl1271_event.h
index 58371008f27..e4751667cf5 100644
--- a/drivers/net/wireless/wl12xx/wl1271_event.h
+++ b/drivers/net/wireless/wl12xx/wl1271_event.h
@@ -85,7 +85,7 @@ struct event_debug_report {
__le32 report_1;
__le32 report_2;
__le32 report_3;
-} __attribute__ ((packed));
+} __packed;
#define NUM_OF_RSSI_SNR_TRIGGERS 8
@@ -116,10 +116,11 @@ struct event_mailbox {
u8 ps_status;
u8 reserved_5[29];
-} __attribute__ ((packed));
+} __packed;
int wl1271_event_unmask(struct wl1271 *wl);
void wl1271_event_mbox_config(struct wl1271 *wl);
int wl1271_event_handle(struct wl1271 *wl, u8 mbox);
+void wl1271_pspoll_work(struct work_struct *work);
#endif
diff --git a/drivers/net/wireless/wl12xx/wl1271_ini.h b/drivers/net/wireless/wl12xx/wl1271_ini.h
new file mode 100644
index 00000000000..2313047d401
--- /dev/null
+++ b/drivers/net/wireless/wl12xx/wl1271_ini.h
@@ -0,0 +1,123 @@
+/*
+ * This file is part of wl1271
+ *
+ * Copyright (C) 2010 Nokia Corporation
+ *
+ * Contact: Luciano Coelho <luciano.coelho@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef __WL1271_INI_H__
+#define __WL1271_INI_H__
+
+#define WL1271_INI_MAX_SMART_REFLEX_PARAM 16
+
+struct wl1271_ini_general_params {
+ u8 ref_clock;
+ u8 settling_time;
+ u8 clk_valid_on_wakeup;
+ u8 dc2dc_mode;
+ u8 dual_mode_select;
+ u8 tx_bip_fem_auto_detect;
+ u8 tx_bip_fem_manufacturer;
+ u8 general_settings;
+ u8 sr_state;
+ u8 srf1[WL1271_INI_MAX_SMART_REFLEX_PARAM];
+ u8 srf2[WL1271_INI_MAX_SMART_REFLEX_PARAM];
+ u8 srf3[WL1271_INI_MAX_SMART_REFLEX_PARAM];
+} __packed;
+
+#define WL1271_INI_RSSI_PROCESS_COMPENS_SIZE 15
+
+struct wl1271_ini_band_params_2 {
+ u8 rx_trace_insertion_loss;
+ u8 tx_trace_loss;
+ u8 rx_rssi_process_compens[WL1271_INI_RSSI_PROCESS_COMPENS_SIZE];
+} __packed;
+
+#define WL1271_INI_RATE_GROUP_COUNT 6
+#define WL1271_INI_CHANNEL_COUNT_2 14
+
+struct wl1271_ini_fem_params_2 {
+ __le16 tx_bip_ref_pd_voltage;
+ u8 tx_bip_ref_power;
+ u8 tx_bip_ref_offset;
+ u8 tx_per_rate_pwr_limits_normal[WL1271_INI_RATE_GROUP_COUNT];
+ u8 tx_per_rate_pwr_limits_degraded[WL1271_INI_RATE_GROUP_COUNT];
+ u8 tx_per_rate_pwr_limits_extreme[WL1271_INI_RATE_GROUP_COUNT];
+ u8 tx_per_chan_pwr_limits_11b[WL1271_INI_CHANNEL_COUNT_2];
+ u8 tx_per_chan_pwr_limits_ofdm[WL1271_INI_CHANNEL_COUNT_2];
+ u8 tx_pd_vs_rate_offsets[WL1271_INI_RATE_GROUP_COUNT];
+ u8 tx_ibias[WL1271_INI_RATE_GROUP_COUNT];
+ u8 rx_fem_insertion_loss;
+ u8 degraded_low_to_normal_thr;
+ u8 normal_to_degraded_high_thr;
+} __packed;
+
+#define WL1271_INI_CHANNEL_COUNT_5 35
+#define WL1271_INI_SUB_BAND_COUNT_5 7
+
+struct wl1271_ini_band_params_5 {
+ u8 rx_trace_insertion_loss[WL1271_INI_SUB_BAND_COUNT_5];
+ u8 tx_trace_loss[WL1271_INI_SUB_BAND_COUNT_5];
+ u8 rx_rssi_process_compens[WL1271_INI_RSSI_PROCESS_COMPENS_SIZE];
+} __packed;
+
+struct wl1271_ini_fem_params_5 {
+ __le16 tx_bip_ref_pd_voltage[WL1271_INI_SUB_BAND_COUNT_5];
+ u8 tx_bip_ref_power[WL1271_INI_SUB_BAND_COUNT_5];
+ u8 tx_bip_ref_offset[WL1271_INI_SUB_BAND_COUNT_5];
+ u8 tx_per_rate_pwr_limits_normal[WL1271_INI_RATE_GROUP_COUNT];
+ u8 tx_per_rate_pwr_limits_degraded[WL1271_INI_RATE_GROUP_COUNT];
+ u8 tx_per_rate_pwr_limits_extreme[WL1271_INI_RATE_GROUP_COUNT];
+ u8 tx_per_chan_pwr_limits_ofdm[WL1271_INI_CHANNEL_COUNT_5];
+ u8 tx_pd_vs_rate_offsets[WL1271_INI_RATE_GROUP_COUNT];
+ u8 tx_ibias[WL1271_INI_RATE_GROUP_COUNT];
+ u8 rx_fem_insertion_loss[WL1271_INI_SUB_BAND_COUNT_5];
+ u8 degraded_low_to_normal_thr;
+ u8 normal_to_degraded_high_thr;
+} __packed;
+
+
+/* NVS data structure */
+#define WL1271_INI_NVS_SECTION_SIZE 468
+#define WL1271_INI_FEM_MODULE_COUNT 2
+
+#define WL1271_INI_LEGACY_NVS_FILE_SIZE 800
+
+struct wl1271_nvs_file {
+ /* NVS section */
+ u8 nvs[WL1271_INI_NVS_SECTION_SIZE];
+
+ /* INI section */
+ struct wl1271_ini_general_params general_params;
+ u8 padding1;
+ struct wl1271_ini_band_params_2 stat_radio_params_2;
+ u8 padding2;
+ struct {
+ struct wl1271_ini_fem_params_2 params;
+ u8 padding;
+ } dyn_radio_params_2[WL1271_INI_FEM_MODULE_COUNT];
+ struct wl1271_ini_band_params_5 stat_radio_params_5;
+ u8 padding3;
+ struct {
+ struct wl1271_ini_fem_params_5 params;
+ u8 padding;
+ } dyn_radio_params_5[WL1271_INI_FEM_MODULE_COUNT];
+} __packed;
+
+#endif
diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c
index b7d9137851a..9d68f0012f0 100644
--- a/drivers/net/wireless/wl12xx/wl1271_main.c
+++ b/drivers/net/wireless/wl12xx/wl1271_main.c
@@ -28,7 +28,6 @@
#include <linux/crc32.h>
#include <linux/etherdevice.h>
#include <linux/vmalloc.h>
-#include <linux/inetdevice.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
@@ -45,6 +44,7 @@
#include "wl1271_cmd.h"
#include "wl1271_boot.h"
#include "wl1271_testmode.h"
+#include "wl1271_scan.h"
#define WL1271_BOOT_RETRIES 3
@@ -55,7 +55,7 @@ static struct conf_drv_settings default_conf = {
[CONF_SG_HV3_MAX_OVERRIDE] = 0,
[CONF_SG_BT_NFS_SAMPLE_INTERVAL] = 400,
[CONF_SG_BT_LOAD_RATIO] = 50,
- [CONF_SG_AUTO_PS_MODE] = 0,
+ [CONF_SG_AUTO_PS_MODE] = 1,
[CONF_SG_AUTO_SCAN_PROBE_REQ] = 170,
[CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_HV3] = 50,
[CONF_SG_ANTENNA_CONFIGURATION] = 0,
@@ -234,18 +234,14 @@ static struct conf_drv_settings default_conf = {
.beacon_rx_timeout = 10000,
.broadcast_timeout = 20000,
.rx_broadcast_in_ps = 1,
- .ps_poll_threshold = 20,
+ .ps_poll_threshold = 10,
+ .ps_poll_recovery_period = 700,
.bet_enable = CONF_BET_MODE_ENABLE,
.bet_max_consecutive = 10,
.psm_entry_retries = 3,
.keep_alive_interval = 55000,
.max_listen_interval = 20,
},
- .init = {
- .radioparam = {
- .fem = 1,
- }
- },
.itrim = {
.enable = false,
.timeout = 50000,
@@ -566,14 +562,21 @@ static int wl1271_fetch_nvs(struct wl1271 *wl)
return ret;
}
- if (fw->size != sizeof(struct wl1271_nvs_file)) {
+ /*
+ * FIXME: the LEGACY NVS image support (NVS's missing the 5GHz band
+ * configurations) can be removed when those NVS files stop floating
+ * around.
+ */
+ if (fw->size != sizeof(struct wl1271_nvs_file) &&
+ (fw->size != WL1271_INI_LEGACY_NVS_FILE_SIZE ||
+ wl1271_11a_enabled())) {
wl1271_error("nvs size is not as expected: %zu != %zu",
fw->size, sizeof(struct wl1271_nvs_file));
ret = -EILSEQ;
goto out;
}
- wl->nvs = kmalloc(sizeof(struct wl1271_nvs_file), GFP_KERNEL);
+ wl->nvs = kmemdup(fw->data, sizeof(struct wl1271_nvs_file), GFP_KERNEL);
if (!wl->nvs) {
wl1271_error("could not allocate memory for the nvs file");
@@ -581,8 +584,6 @@ static int wl1271_fetch_nvs(struct wl1271 *wl)
goto out;
}
- memcpy(wl->nvs, fw->data, sizeof(struct wl1271_nvs_file));
-
out:
release_firmware(fw);
@@ -811,93 +812,6 @@ static int wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
return NETDEV_TX_OK;
}
-static int wl1271_dev_notify(struct notifier_block *me, unsigned long what,
- void *arg)
-{
- struct net_device *dev;
- struct wireless_dev *wdev;
- struct wiphy *wiphy;
- struct ieee80211_hw *hw;
- struct wl1271 *wl;
- struct wl1271 *wl_temp;
- struct in_device *idev;
- struct in_ifaddr *ifa = arg;
- int ret = 0;
-
- /* FIXME: this ugly function should probably be implemented in the
- * mac80211, and here should only be a simple callback handling actual
- * setting of the filters. Now we need to dig up references to
- * various structures to gain access to what we need.
- * Also, because of this, there is no "initial" setting of the filter
- * in "op_start", because we don't want to dig up struct net_device
- * there - the filter will be set upon first change of the interface
- * IP address. */
-
- dev = ifa->ifa_dev->dev;
-
- wdev = dev->ieee80211_ptr;
- if (wdev == NULL)
- return NOTIFY_DONE;
-
- wiphy = wdev->wiphy;
- if (wiphy == NULL)
- return NOTIFY_DONE;
-
- hw = wiphy_priv(wiphy);
- if (hw == NULL)
- return NOTIFY_DONE;
-
- /* Check that the interface is one supported by this driver. */
- wl_temp = hw->priv;
- list_for_each_entry(wl, &wl_list, list) {
- if (wl == wl_temp)
- break;
- }
- if (wl != wl_temp)
- return NOTIFY_DONE;
-
- /* Get the interface IP address for the device. "ifa" will become
- NULL if:
- - there is no IPV4 protocol address configured
- - there are multiple (virtual) IPV4 addresses configured
- When "ifa" is NULL, filtering will be disabled.
- */
- ifa = NULL;
- idev = dev->ip_ptr;
- if (idev)
- ifa = idev->ifa_list;
-
- if (ifa && ifa->ifa_next)
- ifa = NULL;
-
- mutex_lock(&wl->mutex);
-
- if (wl->state == WL1271_STATE_OFF)
- goto out;
-
- ret = wl1271_ps_elp_wakeup(wl, false);
- if (ret < 0)
- goto out;
- if (ifa)
- ret = wl1271_acx_arp_ip_filter(wl, true,
- (u8 *)&ifa->ifa_address,
- ACX_IPV4_VERSION);
- else
- ret = wl1271_acx_arp_ip_filter(wl, false, NULL,
- ACX_IPV4_VERSION);
- wl1271_ps_elp_sleep(wl);
-
-out:
- mutex_unlock(&wl->mutex);
-
- return NOTIFY_OK;
-}
-
-static struct notifier_block wl1271_dev_notifier = {
- .notifier_call = wl1271_dev_notify,
-};
-
-
static int wl1271_op_start(struct ieee80211_hw *hw)
{
wl1271_debug(DEBUG_MAC80211, "mac80211 start");
@@ -925,6 +839,7 @@ static int wl1271_op_add_interface(struct ieee80211_hw *hw,
struct ieee80211_vif *vif)
{
struct wl1271 *wl = hw->priv;
+ struct wiphy *wiphy = hw->wiphy;
int retries = WL1271_BOOT_RETRIES;
int ret = 0;
@@ -978,6 +893,12 @@ static int wl1271_op_add_interface(struct ieee80211_hw *hw,
wl->state = WL1271_STATE_ON;
wl1271_info("firmware booted (%s)", wl->chip.fw_ver);
+
+ /* update hw/fw version info in wiphy struct */
+ wiphy->hw_version = wl->chip.id;
+ strncpy(wiphy->fw_version, wl->chip.fw_ver,
+ sizeof(wiphy->fw_version));
+
goto out;
irq_disable:
@@ -1001,10 +922,8 @@ power_off:
out:
mutex_unlock(&wl->mutex);
- if (!ret) {
+ if (!ret)
list_add(&wl->list, &wl_list);
- register_inetaddr_notifier(&wl1271_dev_notifier);
- }
return ret;
}
@@ -1015,8 +934,6 @@ static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
struct wl1271 *wl = hw->priv;
int i;
- unregister_inetaddr_notifier(&wl1271_dev_notifier);
-
mutex_lock(&wl->mutex);
wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface");
@@ -1026,10 +943,17 @@ static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
WARN_ON(wl->state != WL1271_STATE_ON);
- if (test_and_clear_bit(WL1271_FLAG_SCANNING, &wl->flags)) {
+ /* enable dyn ps just in case (if left on due to fw crash etc) */
+ if (wl->bss_type == BSS_TYPE_STA_BSS)
+ ieee80211_enable_dyn_ps(wl->vif);
+
+ if (wl->scan.state != WL1271_SCAN_STATE_IDLE) {
mutex_unlock(&wl->mutex);
ieee80211_scan_completed(wl->hw, true);
mutex_lock(&wl->mutex);
+ wl->scan.state = WL1271_SCAN_STATE_IDLE;
+ kfree(wl->scan.scanned_ch);
+ wl->scan.scanned_ch = NULL;
}
wl->state = WL1271_STATE_OFF;
@@ -1040,11 +964,12 @@ static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
cancel_work_sync(&wl->irq_work);
cancel_work_sync(&wl->tx_work);
+ cancel_delayed_work_sync(&wl->pspoll_work);
mutex_lock(&wl->mutex);
/* let's notify MAC80211 about the remaining pending TX frames */
- wl1271_tx_flush(wl);
+ wl1271_tx_reset(wl);
wl1271_power_off(wl);
memset(wl->bssid, 0, ETH_ALEN);
@@ -1241,6 +1166,42 @@ static u32 wl1271_min_rate_get(struct wl1271 *wl)
return rate;
}
+static int wl1271_handle_idle(struct wl1271 *wl, bool idle)
+{
+ int ret;
+
+ if (idle) {
+ if (test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
+ ret = wl1271_unjoin(wl);
+ if (ret < 0)
+ goto out;
+ }
+ wl->rate_set = wl1271_min_rate_get(wl);
+ wl->sta_rate_set = 0;
+ ret = wl1271_acx_rate_policies(wl);
+ if (ret < 0)
+ goto out;
+ ret = wl1271_acx_keep_alive_config(
+ wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
+ ACX_KEEP_ALIVE_TPL_INVALID);
+ if (ret < 0)
+ goto out;
+ set_bit(WL1271_FLAG_IDLE, &wl->flags);
+ } else {
+ /* increment the session counter */
+ wl->session_counter++;
+ if (wl->session_counter >= SESSION_COUNTER_MAX)
+ wl->session_counter = 0;
+ ret = wl1271_dummy_join(wl);
+ if (ret < 0)
+ goto out;
+ clear_bit(WL1271_FLAG_IDLE, &wl->flags);
+ }
+
+out:
+ return ret;
+}
+
static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
{
struct wl1271 *wl = hw->priv;
@@ -1255,6 +1216,15 @@ static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
conf->power_level,
conf->flags & IEEE80211_CONF_IDLE ? "idle" : "in use");
+ /*
+ * mac80211 will go to idle nearly immediately after transmitting some
+ * frames, such as the deauth. To make sure those frames reach the air,
+ * wait here until the TX queue is fully flushed.
+ */
+ if ((changed & IEEE80211_CONF_CHANGE_IDLE) &&
+ (conf->flags & IEEE80211_CONF_IDLE))
+ wl1271_tx_flush(wl);
+
mutex_lock(&wl->mutex);
if (unlikely(wl->state == WL1271_STATE_OFF))
@@ -1295,24 +1265,18 @@ static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
}
if (changed & IEEE80211_CONF_CHANGE_IDLE) {
- if (conf->flags & IEEE80211_CONF_IDLE &&
- test_bit(WL1271_FLAG_JOINED, &wl->flags))
- wl1271_unjoin(wl);
- else if (!(conf->flags & IEEE80211_CONF_IDLE))
- wl1271_dummy_join(wl);
-
- if (conf->flags & IEEE80211_CONF_IDLE) {
- wl->rate_set = wl1271_min_rate_get(wl);
- wl->sta_rate_set = 0;
- wl1271_acx_rate_policies(wl);
- wl1271_acx_keep_alive_config(
- wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
- ACX_KEEP_ALIVE_TPL_INVALID);
- set_bit(WL1271_FLAG_IDLE, &wl->flags);
- } else
- clear_bit(WL1271_FLAG_IDLE, &wl->flags);
+ ret = wl1271_handle_idle(wl, conf->flags & IEEE80211_CONF_IDLE);
+ if (ret < 0)
+ wl1271_warning("idle mode change failed %d", ret);
}
+ /*
+ * if mac80211 changes the PSM mode, make sure the mode is not
+ * incorrectly changed after the pspoll failure active window.
+ */
+ if (changed & IEEE80211_CONF_CHANGE_PS)
+ clear_bit(WL1271_FLAG_PSPOLL_FAILURE, &wl->flags);
+
if (conf->flags & IEEE80211_CONF_PS &&
!test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
set_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
@@ -1595,13 +1559,9 @@ static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
goto out;
if (wl1271_11a_enabled())
- ret = wl1271_cmd_scan(hw->priv, ssid, len,
- req->ie, req->ie_len, 1, 0,
- WL1271_SCAN_BAND_DUAL, 3);
+ ret = wl1271_scan(hw->priv, ssid, len, req);
else
- ret = wl1271_cmd_scan(hw->priv, ssid, len,
- req->ie, req->ie_len, 1, 0,
- WL1271_SCAN_BAND_2_4_GHZ, 3);
+ ret = wl1271_scan(hw->priv, ssid, len, req);
wl1271_ps_elp_sleep(wl);
@@ -1774,6 +1734,8 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
wl->aid = bss_conf->aid;
set_assoc = true;
+ wl->ps_poll_failures = 0;
+
/*
* use basic rates from AP, and determine lowest rate
* to use with control frames.
@@ -1823,6 +1785,9 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
clear_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
wl->aid = 0;
+ /* re-enable dynamic ps - just in case */
+ ieee80211_enable_dyn_ps(wl->vif);
+
/* revert back to minimum rates for the current band */
wl1271_set_band_rate(wl);
wl->basic_rate = wl1271_min_rate_get(wl);
@@ -1871,6 +1836,19 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
}
}
+ if (changed & BSS_CHANGED_ARP_FILTER) {
+ __be32 addr = bss_conf->arp_addr_list[0];
+ WARN_ON(wl->bss_type != BSS_TYPE_STA_BSS);
+
+ if (bss_conf->arp_addr_cnt == 1 && bss_conf->arp_filter_enabled)
+ ret = wl1271_acx_arp_ip_filter(wl, true, addr);
+ else
+ ret = wl1271_acx_arp_ip_filter(wl, false, addr);
+
+ if (ret < 0)
+ goto out_sleep;
+ }
+
if (do_join) {
ret = wl1271_join(wl, set_assoc);
if (ret < 0) {
@@ -1929,6 +1907,48 @@ out:
return ret;
}
+static u64 wl1271_op_get_tsf(struct ieee80211_hw *hw)
+{
+
+ struct wl1271 *wl = hw->priv;
+ u64 mactime = ULLONG_MAX;
+ int ret;
+
+ wl1271_debug(DEBUG_MAC80211, "mac80211 get tsf");
+
+ mutex_lock(&wl->mutex);
+
+ ret = wl1271_ps_elp_wakeup(wl, false);
+ if (ret < 0)
+ goto out;
+
+ ret = wl1271_acx_tsf_info(wl, &mactime);
+ if (ret < 0)
+ goto out_sleep;
+
+out_sleep:
+ wl1271_ps_elp_sleep(wl);
+
+out:
+ mutex_unlock(&wl->mutex);
+ return mactime;
+}
+
+static int wl1271_op_get_survey(struct ieee80211_hw *hw, int idx,
+ struct survey_info *survey)
+{
+ struct wl1271 *wl = hw->priv;
+ struct ieee80211_conf *conf = &hw->conf;
+
+ if (idx != 0)
+ return -ENOENT;
+
+ survey->channel = conf->channel;
+ survey->filled = SURVEY_INFO_NOISE_DBM;
+ survey->noise = wl->noise;
+
+ return 0;
+}
/* can't be const, mac80211 writes to this */
static struct ieee80211_rate wl1271_rates[] = {
@@ -1991,7 +2011,7 @@ static struct ieee80211_channel wl1271_channels[] = {
};
/* mapping to indexes for wl1271_rates */
-const static u8 wl1271_rate_to_idx_2ghz[] = {
+static const u8 wl1271_rate_to_idx_2ghz[] = {
/* MCS rates are used only with 11n */
CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS7 */
CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS6 */
@@ -2103,7 +2123,7 @@ static struct ieee80211_channel wl1271_channels_5ghz[] = {
};
/* mapping to indexes for wl1271_rates_5ghz */
-const static u8 wl1271_rate_to_idx_5ghz[] = {
+static const u8 wl1271_rate_to_idx_5ghz[] = {
/* MCS rates are used only with 11n */
CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS7 */
CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS6 */
@@ -2139,7 +2159,7 @@ static struct ieee80211_supported_band wl1271_band_5ghz = {
.n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz),
};
-const static u8 *wl1271_band_rate_to_idx[] = {
+static const u8 *wl1271_band_rate_to_idx[] = {
[IEEE80211_BAND_2GHZ] = wl1271_rate_to_idx_2ghz,
[IEEE80211_BAND_5GHZ] = wl1271_rate_to_idx_5ghz
};
@@ -2158,6 +2178,8 @@ static const struct ieee80211_ops wl1271_ops = {
.bss_info_changed = wl1271_op_bss_info_changed,
.set_rts_threshold = wl1271_op_set_rts_threshold,
.conf_tx = wl1271_op_conf_tx,
+ .get_tsf = wl1271_op_get_tsf,
+ .get_survey = wl1271_op_get_survey,
CFG80211_TESTMODE_CMD(wl1271_tm_cmd)
};
@@ -2350,15 +2372,13 @@ struct ieee80211_hw *wl1271_alloc_hw(void)
goto err_hw_alloc;
}
- plat_dev = kmalloc(sizeof(wl1271_device), GFP_KERNEL);
+ plat_dev = kmemdup(&wl1271_device, sizeof(wl1271_device), GFP_KERNEL);
if (!plat_dev) {
wl1271_error("could not allocate platform_device");
ret = -ENOMEM;
goto err_plat_alloc;
}
- memcpy(plat_dev, &wl1271_device, sizeof(wl1271_device));
-
wl = hw->priv;
memset(wl, 0, sizeof(*wl));
@@ -2370,6 +2390,7 @@ struct ieee80211_hw *wl1271_alloc_hw(void)
skb_queue_head_init(&wl->tx_queue);
INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
+ INIT_DELAYED_WORK(&wl->pspoll_work, wl1271_pspoll_work);
wl->channel = WL1271_DEFAULT_CHANNEL;
wl->beacon_int = WL1271_DEFAULT_BEACON_INT;
wl->default_key = 0;
diff --git a/drivers/net/wireless/wl12xx/wl1271_rx.c b/drivers/net/wireless/wl12xx/wl1271_rx.c
index b98fb643fab..019aa79cd9d 100644
--- a/drivers/net/wireless/wl12xx/wl1271_rx.c
+++ b/drivers/net/wireless/wl12xx/wl1271_rx.c
@@ -53,13 +53,14 @@ static void wl1271_rx_status(struct wl1271 *wl,
status->band = wl->band;
status->rate_idx = wl1271_rate_to_idx(wl, desc->rate);
+ status->signal = desc->rssi;
+
/*
- * FIXME: Add mactime handling. For IBSS (ad-hoc) we need to get the
- * timestamp from the beacon (acx_tsf_info). In BSS mode (infra) we
- * only need the mactime for monitor mode. For now the mactime is
- * not valid, so RX_FLAG_TSFT should not be set
+ * FIXME: In wl1251, the SNR should be divided by two. In wl1271 we
+ * need to divide by two for now, but TI has been discussing about
+ * changing it. This needs to be rechecked.
*/
- status->signal = desc->rssi;
+ wl->noise = desc->rssi - (desc->snr >> 1);
status->freq = ieee80211_channel_to_frequency(desc->channel);
diff --git a/drivers/net/wireless/wl12xx/wl1271_rx.h b/drivers/net/wireless/wl12xx/wl1271_rx.h
index b89be4758e7..13a232333b1 100644
--- a/drivers/net/wireless/wl12xx/wl1271_rx.h
+++ b/drivers/net/wireless/wl12xx/wl1271_rx.h
@@ -113,7 +113,7 @@ struct wl1271_rx_descriptor {
u8 process_id;
u8 pad_len;
u8 reserved;
-} __attribute__ ((packed));
+} __packed;
void wl1271_rx(struct wl1271 *wl, struct wl1271_fw_status *status);
u8 wl1271_rate_to_idx(struct wl1271 *wl, int rate);
diff --git a/drivers/net/wireless/wl12xx/wl1271_scan.c b/drivers/net/wireless/wl12xx/wl1271_scan.c
new file mode 100644
index 00000000000..fec43eed8c5
--- /dev/null
+++ b/drivers/net/wireless/wl12xx/wl1271_scan.c
@@ -0,0 +1,257 @@
+/*
+ * This file is part of wl1271
+ *
+ * Copyright (C) 2009-2010 Nokia Corporation
+ *
+ * Contact: Luciano Coelho <luciano.coelho@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/ieee80211.h>
+
+#include "wl1271.h"
+#include "wl1271_cmd.h"
+#include "wl1271_scan.h"
+#include "wl1271_acx.h"
+
+static int wl1271_get_scan_channels(struct wl1271 *wl,
+ struct cfg80211_scan_request *req,
+ struct basic_scan_channel_params *channels,
+ enum ieee80211_band band, bool passive)
+{
+ int i, j;
+ u32 flags;
+
+ for (i = 0, j = 0;
+ i < req->n_channels && j < WL1271_SCAN_MAX_CHANNELS;
+ i++) {
+
+ flags = req->channels[i]->flags;
+
+ if (!wl->scan.scanned_ch[i] &&
+ !(flags & IEEE80211_CHAN_DISABLED) &&
+ ((!!(flags & IEEE80211_CHAN_PASSIVE_SCAN)) == passive) &&
+ (req->channels[i]->band == band)) {
+
+ wl1271_debug(DEBUG_SCAN, "band %d, center_freq %d ",
+ req->channels[i]->band,
+ req->channels[i]->center_freq);
+ wl1271_debug(DEBUG_SCAN, "hw_value %d, flags %X",
+ req->channels[i]->hw_value,
+ req->channels[i]->flags);
+ wl1271_debug(DEBUG_SCAN,
+ "max_antenna_gain %d, max_power %d",
+ req->channels[i]->max_antenna_gain,
+ req->channels[i]->max_power);
+ wl1271_debug(DEBUG_SCAN, "beacon_found %d",
+ req->channels[i]->beacon_found);
+
+ channels[j].min_duration =
+ cpu_to_le32(WL1271_SCAN_CHAN_MIN_DURATION);
+ channels[j].max_duration =
+ cpu_to_le32(WL1271_SCAN_CHAN_MAX_DURATION);
+ channels[j].early_termination = 0;
+ channels[j].tx_power_att = req->channels[i]->max_power;
+ channels[j].channel = req->channels[i]->hw_value;
+
+ memset(&channels[j].bssid_lsb, 0xff, 4);
+ memset(&channels[j].bssid_msb, 0xff, 2);
+
+ /* Mark the channels we already used */
+ wl->scan.scanned_ch[i] = true;
+
+ j++;
+ }
+ }
+
+ return j;
+}
+
+#define WL1271_NOTHING_TO_SCAN 1
+
+static int wl1271_scan_send(struct wl1271 *wl, enum ieee80211_band band,
+ bool passive, u32 basic_rate)
+{
+ struct wl1271_cmd_scan *cmd;
+ struct wl1271_cmd_trigger_scan_to *trigger;
+ int ret;
+ u16 scan_options = 0;
+
+ cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+ trigger = kzalloc(sizeof(*trigger), GFP_KERNEL);
+ if (!cmd || !trigger) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ /* We always use high priority scans */
+ scan_options = WL1271_SCAN_OPT_PRIORITY_HIGH;
+ if(passive)
+ scan_options |= WL1271_SCAN_OPT_PASSIVE;
+ cmd->params.scan_options = cpu_to_le16(scan_options);
+
+ cmd->params.n_ch = wl1271_get_scan_channels(wl, wl->scan.req,
+ cmd->channels,
+ band, passive);
+ if (cmd->params.n_ch == 0) {
+ ret = WL1271_NOTHING_TO_SCAN;
+ goto out;
+ }
+
+ cmd->params.tx_rate = cpu_to_le32(basic_rate);
+ cmd->params.rx_config_options = cpu_to_le32(CFG_RX_ALL_GOOD);
+ cmd->params.rx_filter_options =
+ cpu_to_le32(CFG_RX_PRSP_EN | CFG_RX_MGMT_EN | CFG_RX_BCN_EN);
+
+ cmd->params.n_probe_reqs = WL1271_SCAN_PROBE_REQS;
+ cmd->params.tx_rate = cpu_to_le32(basic_rate);
+ cmd->params.tid_trigger = 0;
+ cmd->params.scan_tag = WL1271_SCAN_DEFAULT_TAG;
+
+ if (band == IEEE80211_BAND_2GHZ)
+ cmd->params.band = WL1271_SCAN_BAND_2_4_GHZ;
+ else
+ cmd->params.band = WL1271_SCAN_BAND_5_GHZ;
+
+ if (wl->scan.ssid_len && wl->scan.ssid) {
+ cmd->params.ssid_len = wl->scan.ssid_len;
+ memcpy(cmd->params.ssid, wl->scan.ssid, wl->scan.ssid_len);
+ }
+
+ ret = wl1271_cmd_build_probe_req(wl, wl->scan.ssid, wl->scan.ssid_len,
+ wl->scan.req->ie, wl->scan.req->ie_len,
+ band);
+ if (ret < 0) {
+ wl1271_error("PROBE request template failed");
+ goto out;
+ }
+
+ /* disable the timeout */
+ trigger->timeout = 0;
+ ret = wl1271_cmd_send(wl, CMD_TRIGGER_SCAN_TO, trigger,
+ sizeof(*trigger), 0);
+ if (ret < 0) {
+ wl1271_error("trigger scan to failed for hw scan");
+ goto out;
+ }
+
+ wl1271_dump(DEBUG_SCAN, "SCAN: ", cmd, sizeof(*cmd));
+
+ ret = wl1271_cmd_send(wl, CMD_SCAN, cmd, sizeof(*cmd), 0);
+ if (ret < 0) {
+ wl1271_error("SCAN failed");
+ goto out;
+ }
+
+out:
+ kfree(cmd);
+ kfree(trigger);
+ return ret;
+}
+
+void wl1271_scan_stm(struct wl1271 *wl)
+{
+ int ret;
+
+ switch (wl->scan.state) {
+ case WL1271_SCAN_STATE_IDLE:
+ break;
+
+ case WL1271_SCAN_STATE_2GHZ_ACTIVE:
+ ret = wl1271_scan_send(wl, IEEE80211_BAND_2GHZ, false,
+ wl->conf.tx.basic_rate);
+ if (ret == WL1271_NOTHING_TO_SCAN) {
+ wl->scan.state = WL1271_SCAN_STATE_2GHZ_PASSIVE;
+ wl1271_scan_stm(wl);
+ }
+
+ break;
+
+ case WL1271_SCAN_STATE_2GHZ_PASSIVE:
+ ret = wl1271_scan_send(wl, IEEE80211_BAND_2GHZ, true,
+ wl->conf.tx.basic_rate);
+ if (ret == WL1271_NOTHING_TO_SCAN) {
+ if (wl1271_11a_enabled())
+ wl->scan.state = WL1271_SCAN_STATE_5GHZ_ACTIVE;
+ else
+ wl->scan.state = WL1271_SCAN_STATE_DONE;
+ wl1271_scan_stm(wl);
+ }
+
+ break;
+
+ case WL1271_SCAN_STATE_5GHZ_ACTIVE:
+ ret = wl1271_scan_send(wl, IEEE80211_BAND_5GHZ, false,
+ wl->conf.tx.basic_rate_5);
+ if (ret == WL1271_NOTHING_TO_SCAN) {
+ wl->scan.state = WL1271_SCAN_STATE_5GHZ_PASSIVE;
+ wl1271_scan_stm(wl);
+ }
+
+ break;
+
+ case WL1271_SCAN_STATE_5GHZ_PASSIVE:
+ ret = wl1271_scan_send(wl, IEEE80211_BAND_5GHZ, true,
+ wl->conf.tx.basic_rate_5);
+ if (ret == WL1271_NOTHING_TO_SCAN) {
+ wl->scan.state = WL1271_SCAN_STATE_DONE;
+ wl1271_scan_stm(wl);
+ }
+
+ break;
+
+ case WL1271_SCAN_STATE_DONE:
+ mutex_unlock(&wl->mutex);
+ ieee80211_scan_completed(wl->hw, false);
+ mutex_lock(&wl->mutex);
+
+ kfree(wl->scan.scanned_ch);
+ wl->scan.scanned_ch = NULL;
+
+ wl->scan.state = WL1271_SCAN_STATE_IDLE;
+ break;
+
+ default:
+ wl1271_error("invalid scan state");
+ break;
+ }
+}
+
+int wl1271_scan(struct wl1271 *wl, const u8 *ssid, size_t ssid_len,
+ struct cfg80211_scan_request *req)
+{
+ if (wl->scan.state != WL1271_SCAN_STATE_IDLE)
+ return -EBUSY;
+
+ wl->scan.state = WL1271_SCAN_STATE_2GHZ_ACTIVE;
+
+ if (ssid_len && ssid) {
+ wl->scan.ssid_len = ssid_len;
+ memcpy(wl->scan.ssid, ssid, ssid_len);
+ } else {
+ wl->scan.ssid_len = 0;
+ }
+
+ wl->scan.req = req;
+
+ wl->scan.scanned_ch = kzalloc(req->n_channels *
+ sizeof(*wl->scan.scanned_ch),
+ GFP_KERNEL);
+ wl1271_scan_stm(wl);
+
+ return 0;
+}
diff --git a/drivers/net/wireless/wl12xx/wl1271_scan.h b/drivers/net/wireless/wl12xx/wl1271_scan.h
new file mode 100644
index 00000000000..f1815700f5f
--- /dev/null
+++ b/drivers/net/wireless/wl12xx/wl1271_scan.h
@@ -0,0 +1,109 @@
+/*
+ * This file is part of wl1271
+ *
+ * Copyright (C) 2009-2010 Nokia Corporation
+ *
+ * Contact: Luciano Coelho <luciano.coelho@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef __WL1271_SCAN_H__
+#define __WL1271_SCAN_H__
+
+#include "wl1271.h"
+
+int wl1271_scan(struct wl1271 *wl, const u8 *ssid, size_t ssid_len,
+ struct cfg80211_scan_request *req);
+int wl1271_scan_build_probe_req(struct wl1271 *wl,
+ const u8 *ssid, size_t ssid_len,
+ const u8 *ie, size_t ie_len, u8 band);
+void wl1271_scan_stm(struct wl1271 *wl);
+
+#define WL1271_SCAN_MAX_CHANNELS 24
+#define WL1271_SCAN_DEFAULT_TAG 1
+#define WL1271_SCAN_CURRENT_TX_PWR 0
+#define WL1271_SCAN_OPT_ACTIVE 0
+#define WL1271_SCAN_OPT_PASSIVE 1
+#define WL1271_SCAN_OPT_PRIORITY_HIGH 4
+#define WL1271_SCAN_CHAN_MIN_DURATION 30000 /* TU */
+#define WL1271_SCAN_CHAN_MAX_DURATION 60000 /* TU */
+#define WL1271_SCAN_BAND_2_4_GHZ 0
+#define WL1271_SCAN_BAND_5_GHZ 1
+#define WL1271_SCAN_PROBE_REQS 3
+
+enum {
+ WL1271_SCAN_STATE_IDLE,
+ WL1271_SCAN_STATE_2GHZ_ACTIVE,
+ WL1271_SCAN_STATE_2GHZ_PASSIVE,
+ WL1271_SCAN_STATE_5GHZ_ACTIVE,
+ WL1271_SCAN_STATE_5GHZ_PASSIVE,
+ WL1271_SCAN_STATE_DONE
+};
+
+struct basic_scan_params {
+ __le32 rx_config_options;
+ __le32 rx_filter_options;
+ /* Scan option flags (WL1271_SCAN_OPT_*) */
+ __le16 scan_options;
+ /* Number of scan channels in the list (maximum 30) */
+ u8 n_ch;
+ /* This field indicates the number of probe requests to send
+ per channel for an active scan */
+ u8 n_probe_reqs;
+ /* Rate bit field for sending the probes */
+ __le32 tx_rate;
+ u8 tid_trigger;
+ u8 ssid_len;
+ /* in order to align */
+ u8 padding1[2];
+ u8 ssid[IW_ESSID_MAX_SIZE];
+ /* Band to scan */
+ u8 band;
+ u8 use_ssid_list;
+ u8 scan_tag;
+ u8 padding2;
+} __packed;
+
+struct basic_scan_channel_params {
+ /* Duration in TU to wait for frames on a channel for active scan */
+ __le32 min_duration;
+ __le32 max_duration;
+ __le32 bssid_lsb;
+ __le16 bssid_msb;
+ u8 early_termination;
+ u8 tx_power_att;
+ u8 channel;
+ /* FW internal use only! */
+ u8 dfs_candidate;
+ u8 activity_detected;
+ u8 pad;
+} __packed;
+
+struct wl1271_cmd_scan {
+ struct wl1271_cmd_header header;
+
+ struct basic_scan_params params;
+ struct basic_scan_channel_params channels[WL1271_SCAN_MAX_CHANNELS];
+} __packed;
+
+struct wl1271_cmd_trigger_scan_to {
+ struct wl1271_cmd_header header;
+
+ __le32 timeout;
+} __packed;
+
+#endif /* __WL1271_SCAN_H__ */
diff --git a/drivers/net/wireless/wl12xx/wl1271_sdio.c b/drivers/net/wireless/wl12xx/wl1271_sdio.c
index d3d6f302f70..7059b5cccf0 100644
--- a/drivers/net/wireless/wl12xx/wl1271_sdio.c
+++ b/drivers/net/wireless/wl12xx/wl1271_sdio.c
@@ -28,7 +28,7 @@
#include <linux/mmc/sdio_func.h>
#include <linux/mmc/sdio_ids.h>
#include <linux/mmc/card.h>
-#include <plat/gpio.h>
+#include <linux/gpio.h>
#include "wl1271.h"
#include "wl12xx_80211.h"
diff --git a/drivers/net/wireless/wl12xx/wl1271_spi.c b/drivers/net/wireless/wl12xx/wl1271_spi.c
index 5189b812f93..96d25fb5049 100644
--- a/drivers/net/wireless/wl12xx/wl1271_spi.c
+++ b/drivers/net/wireless/wl12xx/wl1271_spi.c
@@ -461,3 +461,4 @@ MODULE_LICENSE("GPL");
MODULE_AUTHOR("Luciano Coelho <luciano.coelho@nokia.com>");
MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");
MODULE_FIRMWARE(WL1271_FW_NAME);
+MODULE_ALIAS("spi:wl1271");
diff --git a/drivers/net/wireless/wl12xx/wl1271_testmode.c b/drivers/net/wireless/wl12xx/wl1271_testmode.c
index 554deb4d024..6e0952f79e9 100644
--- a/drivers/net/wireless/wl12xx/wl1271_testmode.c
+++ b/drivers/net/wireless/wl12xx/wl1271_testmode.c
@@ -199,7 +199,14 @@ static int wl1271_tm_cmd_nvs_push(struct wl1271 *wl, struct nlattr *tb[])
buf = nla_data(tb[WL1271_TM_ATTR_DATA]);
len = nla_len(tb[WL1271_TM_ATTR_DATA]);
- if (len != sizeof(struct wl1271_nvs_file)) {
+ /*
+ * FIXME: the LEGACY NVS image support (NVS's missing the 5GHz band
+ * configurations) can be removed when those NVS files stop floating
+ * around.
+ */
+ if (len != sizeof(struct wl1271_nvs_file) &&
+ (len != WL1271_INI_LEGACY_NVS_FILE_SIZE ||
+ wl1271_11a_enabled())) {
wl1271_error("nvs size is not as expected: %zu != %zu",
len, sizeof(struct wl1271_nvs_file));
return -EMSGSIZE;
@@ -209,7 +216,7 @@ static int wl1271_tm_cmd_nvs_push(struct wl1271 *wl, struct nlattr *tb[])
kfree(wl->nvs);
- wl->nvs = kmalloc(sizeof(struct wl1271_nvs_file), GFP_KERNEL);
+ wl->nvs = kzalloc(sizeof(struct wl1271_nvs_file), GFP_KERNEL);
if (!wl->nvs) {
wl1271_error("could not allocate memory for the nvs file");
ret = -ENOMEM;
diff --git a/drivers/net/wireless/wl12xx/wl1271_tx.c b/drivers/net/wireless/wl12xx/wl1271_tx.c
index 62db79508dd..c592cc2e9fe 100644
--- a/drivers/net/wireless/wl12xx/wl1271_tx.c
+++ b/drivers/net/wireless/wl12xx/wl1271_tx.c
@@ -36,6 +36,7 @@ static int wl1271_tx_id(struct wl1271 *wl, struct sk_buff *skb)
for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
if (wl->tx_frames[i] == NULL) {
wl->tx_frames[i] = skb;
+ wl->tx_frames_cnt++;
return i;
}
@@ -73,8 +74,10 @@ static int wl1271_tx_allocate(struct wl1271 *wl, struct sk_buff *skb, u32 extra)
wl1271_debug(DEBUG_TX,
"tx_allocate: size: %d, blocks: %d, id: %d",
total_len, total_blocks, id);
- } else
+ } else {
wl->tx_frames[id] = NULL;
+ wl->tx_frames_cnt--;
+ }
return ret;
}
@@ -358,6 +361,7 @@ static void wl1271_tx_complete_packet(struct wl1271 *wl,
/* return the packet to the stack */
ieee80211_tx_status(wl->hw, skb);
wl->tx_frames[result->id] = NULL;
+ wl->tx_frames_cnt--;
}
/* Called upon reception of a TX complete interrupt */
@@ -412,7 +416,7 @@ void wl1271_tx_complete(struct wl1271 *wl)
}
/* caller must hold wl->mutex */
-void wl1271_tx_flush(struct wl1271 *wl)
+void wl1271_tx_reset(struct wl1271 *wl)
{
int i;
struct sk_buff *skb;
@@ -421,7 +425,7 @@ void wl1271_tx_flush(struct wl1271 *wl)
/* control->flags = 0; FIXME */
while ((skb = skb_dequeue(&wl->tx_queue))) {
- wl1271_debug(DEBUG_TX, "flushing skb 0x%p", skb);
+ wl1271_debug(DEBUG_TX, "freeing skb 0x%p", skb);
ieee80211_tx_status(wl->hw, skb);
}
@@ -429,6 +433,32 @@ void wl1271_tx_flush(struct wl1271 *wl)
if (wl->tx_frames[i] != NULL) {
skb = wl->tx_frames[i];
wl->tx_frames[i] = NULL;
+ wl1271_debug(DEBUG_TX, "freeing skb 0x%p", skb);
ieee80211_tx_status(wl->hw, skb);
}
+ wl->tx_frames_cnt = 0;
+}
+
+#define WL1271_TX_FLUSH_TIMEOUT 500000
+
+/* caller must *NOT* hold wl->mutex */
+void wl1271_tx_flush(struct wl1271 *wl)
+{
+ unsigned long timeout;
+ timeout = jiffies + usecs_to_jiffies(WL1271_TX_FLUSH_TIMEOUT);
+
+ while (!time_after(jiffies, timeout)) {
+ mutex_lock(&wl->mutex);
+ wl1271_debug(DEBUG_TX, "flushing tx buffer: %d",
+ wl->tx_frames_cnt);
+ if ((wl->tx_frames_cnt == 0) &&
+ skb_queue_empty(&wl->tx_queue)) {
+ mutex_unlock(&wl->mutex);
+ return;
+ }
+ mutex_unlock(&wl->mutex);
+ msleep(1);
+ }
+
+ wl1271_warning("Unable to flush all TX buffers, timed out.");
}
diff --git a/drivers/net/wireless/wl12xx/wl1271_tx.h b/drivers/net/wireless/wl12xx/wl1271_tx.h
index 3b8b7ac253f..48bf92621c0 100644
--- a/drivers/net/wireless/wl12xx/wl1271_tx.h
+++ b/drivers/net/wireless/wl12xx/wl1271_tx.h
@@ -80,7 +80,7 @@ struct wl1271_tx_hw_descr {
/* Identifier of the remote STA in IBSS, 1 in infra-BSS */
u8 aid;
u8 reserved;
-} __attribute__ ((packed));
+} __packed;
enum wl1271_tx_hw_res_status {
TX_SUCCESS = 0,
@@ -115,13 +115,13 @@ struct wl1271_tx_hw_res_descr {
u8 rate_class_index;
/* for 4-byte alignment. */
u8 spare;
-} __attribute__ ((packed));
+} __packed;
struct wl1271_tx_hw_res_if {
__le32 tx_result_fw_counter;
__le32 tx_result_host_counter;
struct wl1271_tx_hw_res_descr tx_results_queue[TX_HW_RESULT_QUEUE_LEN];
-} __attribute__ ((packed));
+} __packed;
static inline int wl1271_tx_get_queue(int queue)
{
@@ -158,6 +158,7 @@ static inline int wl1271_tx_ac_to_tid(int ac)
void wl1271_tx_work(struct work_struct *work);
void wl1271_tx_complete(struct wl1271 *wl);
+void wl1271_tx_reset(struct wl1271 *wl);
void wl1271_tx_flush(struct wl1271 *wl);
u8 wl1271_rate_to_idx(struct wl1271 *wl, int rate);
u32 wl1271_tx_enabled_rates_get(struct wl1271 *wl, u32 rate_set);
diff --git a/drivers/net/wireless/wl12xx/wl12xx_80211.h b/drivers/net/wireless/wl12xx/wl12xx_80211.h
index 055d7bc6f59..18462802721 100644
--- a/drivers/net/wireless/wl12xx/wl12xx_80211.h
+++ b/drivers/net/wireless/wl12xx/wl12xx_80211.h
@@ -66,41 +66,41 @@ struct ieee80211_header {
u8 bssid[ETH_ALEN];
__le16 seq_ctl;
u8 payload[0];
-} __attribute__ ((packed));
+} __packed;
struct wl12xx_ie_header {
u8 id;
u8 len;
-} __attribute__ ((packed));
+} __packed;
/* IEs */
struct wl12xx_ie_ssid {
struct wl12xx_ie_header header;
char ssid[IW_ESSID_MAX_SIZE];
-} __attribute__ ((packed));
+} __packed;
struct wl12xx_ie_rates {
struct wl12xx_ie_header header;
u8 rates[MAX_SUPPORTED_RATES];
-} __attribute__ ((packed));
+} __packed;
struct wl12xx_ie_ds_params {
struct wl12xx_ie_header header;
u8 channel;
-} __attribute__ ((packed));
+} __packed;
struct country_triplet {
u8 channel;
u8 num_channels;
u8 max_tx_power;
-} __attribute__ ((packed));
+} __packed;
struct wl12xx_ie_country {
struct wl12xx_ie_header header;
u8 country_string[COUNTRY_STRING_LEN];
struct country_triplet triplets[MAX_COUNTRY_TRIPLETS];
-} __attribute__ ((packed));
+} __packed;
/* Templates */
@@ -115,30 +115,30 @@ struct wl12xx_beacon_template {
struct wl12xx_ie_rates ext_rates;
struct wl12xx_ie_ds_params ds_params;
struct wl12xx_ie_country country;
-} __attribute__ ((packed));
+} __packed;
struct wl12xx_null_data_template {
struct ieee80211_header header;
-} __attribute__ ((packed));
+} __packed;
struct wl12xx_ps_poll_template {
__le16 fc;
__le16 aid;
u8 bssid[ETH_ALEN];
u8 ta[ETH_ALEN];
-} __attribute__ ((packed));
+} __packed;
struct wl12xx_qos_null_data_template {
struct ieee80211_header header;
__le16 qos_ctl;
-} __attribute__ ((packed));
+} __packed;
struct wl12xx_probe_req_template {
struct ieee80211_header header;
struct wl12xx_ie_ssid ssid;
struct wl12xx_ie_rates rates;
struct wl12xx_ie_rates ext_rates;
-} __attribute__ ((packed));
+} __packed;
struct wl12xx_probe_resp_template {
@@ -151,6 +151,6 @@ struct wl12xx_probe_resp_template {
struct wl12xx_ie_rates ext_rates;
struct wl12xx_ie_ds_params ds_params;
struct wl12xx_ie_country country;
-} __attribute__ ((packed));
+} __packed;
#endif
diff --git a/drivers/net/wireless/wl3501.h b/drivers/net/wireless/wl3501.h
index 8816e371fd0..3fbfd19818f 100644
--- a/drivers/net/wireless/wl3501.h
+++ b/drivers/net/wireless/wl3501.h
@@ -231,12 +231,12 @@ struct iw_mgmt_info_element {
but sizeof(enum) > sizeof(u8) :-( */
u8 len;
u8 data[0];
-} __attribute__ ((packed));
+} __packed;
struct iw_mgmt_essid_pset {
struct iw_mgmt_info_element el;
u8 essid[IW_ESSID_MAX_SIZE];
-} __attribute__ ((packed));
+} __packed;
/*
* According to 802.11 Wireless Netowors, the definitive guide - O'Reilly
@@ -247,12 +247,12 @@ struct iw_mgmt_essid_pset {
struct iw_mgmt_data_rset {
struct iw_mgmt_info_element el;
u8 data_rate_labels[IW_DATA_RATE_MAX_LABELS];
-} __attribute__ ((packed));
+} __packed;
struct iw_mgmt_ds_pset {
struct iw_mgmt_info_element el;
u8 chan;
-} __attribute__ ((packed));
+} __packed;
struct iw_mgmt_cf_pset {
struct iw_mgmt_info_element el;
@@ -260,12 +260,12 @@ struct iw_mgmt_cf_pset {
u8 cfp_period;
u16 cfp_max_duration;
u16 cfp_dur_remaining;
-} __attribute__ ((packed));
+} __packed;
struct iw_mgmt_ibss_pset {
struct iw_mgmt_info_element el;
u16 atim_window;
-} __attribute__ ((packed));
+} __packed;
struct wl3501_tx_hdr {
u16 tx_cnt;
@@ -544,12 +544,12 @@ struct wl3501_80211_tx_plcp_hdr {
u8 service;
u16 len;
u16 crc16;
-} __attribute__ ((packed));
+} __packed;
struct wl3501_80211_tx_hdr {
struct wl3501_80211_tx_plcp_hdr pclp_hdr;
struct ieee80211_hdr mac_hdr;
-} __attribute__ ((packed));
+} __packed;
/*
Reserve the beginning Tx space for descriptor use.
diff --git a/drivers/net/wireless/wl3501_cs.c b/drivers/net/wireless/wl3501_cs.c
index 376c6b964a9..a1cc2d498a1 100644
--- a/drivers/net/wireless/wl3501_cs.c
+++ b/drivers/net/wireless/wl3501_cs.c
@@ -48,7 +48,6 @@
#include <net/iw_handler.h>
-#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/cistpl.h>
#include <pcmcia/cisreg.h>
@@ -89,13 +88,6 @@
static int wl3501_config(struct pcmcia_device *link);
static void wl3501_release(struct pcmcia_device *link);
-/*
- * The dev_info variable is the "key" that is used to match up this
- * device driver with appropriate cards, through the card configuration
- * database.
- */
-static dev_info_t wl3501_dev_info = "wl3501_cs";
-
static const struct {
int reg_domain;
int min, max, deflt;
@@ -1421,7 +1413,7 @@ static struct iw_statistics *wl3501_get_wireless_stats(struct net_device *dev)
static void wl3501_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
{
- strlcpy(info->driver, wl3501_dev_info, sizeof(info->driver));
+ strlcpy(info->driver, "wl3501_cs", sizeof(info->driver));
}
static const struct ethtool_ops ops = {
@@ -1892,9 +1884,8 @@ static int wl3501_probe(struct pcmcia_device *p_dev)
struct wl3501_card *this;
/* The io structure describes IO port mapping */
- p_dev->io.NumPorts1 = 16;
- p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
- p_dev->io.IOAddrLines = 5;
+ p_dev->resource[0]->end = 16;
+ p_dev->resource[0]->flags = IO_DATA_PATH_WIDTH_8;
/* General socket configuration */
p_dev->conf.Attributes = CONF_ENABLE_IRQ;
@@ -1940,13 +1931,14 @@ static int wl3501_config(struct pcmcia_device *link)
/* Try allocating IO ports. This tries a few fixed addresses. If you
* want, you can also read the card's config table to pick addresses --
* see the serial driver for an example. */
+ link->io_lines = 5;
for (j = 0x280; j < 0x400; j += 0x20) {
/* The '^0x300' is so that we probe 0x300-0x3ff first, then
* 0x200-0x2ff, and so on, because this seems safer */
- link->io.BasePort1 = j;
- link->io.BasePort2 = link->io.BasePort1 + 0x10;
- i = pcmcia_request_io(link, &link->io);
+ link->resource[0]->start = j;
+ link->resource[1]->start = link->resource[0]->start + 0x10;
+ i = pcmcia_request_io(link);
if (i == 0)
break;
}
@@ -1968,7 +1960,7 @@ static int wl3501_config(struct pcmcia_device *link)
goto failed;
dev->irq = link->irq;
- dev->base_addr = link->io.BasePort1;
+ dev->base_addr = link->resource[0]->start;
SET_NETDEV_DEV(dev, &link->dev);
if (register_netdev(dev)) {
printk(KERN_NOTICE "wl3501_cs: register_netdev() failed\n");
diff --git a/drivers/net/wireless/zd1211rw/zd_mac.c b/drivers/net/wireless/zd1211rw/zd_mac.c
index b0b666019a9..43307bd42a6 100644
--- a/drivers/net/wireless/zd1211rw/zd_mac.c
+++ b/drivers/net/wireless/zd1211rw/zd_mac.c
@@ -42,7 +42,8 @@ static struct zd_reg_alpha2_map reg_alpha2_map[] = {
{ ZD_REGDOMAIN_IC, "CA" },
{ ZD_REGDOMAIN_ETSI, "DE" }, /* Generic ETSI, use most restrictive */
{ ZD_REGDOMAIN_JAPAN, "JP" },
- { ZD_REGDOMAIN_JAPAN_ADD, "JP" },
+ { ZD_REGDOMAIN_JAPAN_2, "JP" },
+ { ZD_REGDOMAIN_JAPAN_3, "JP" },
{ ZD_REGDOMAIN_SPAIN, "ES" },
{ ZD_REGDOMAIN_FRANCE, "FR" },
};
@@ -855,7 +856,7 @@ int zd_mac_rx(struct ieee80211_hw *hw, const u8 *buffer, unsigned int length)
if (skb == NULL)
return -ENOMEM;
if (need_padding) {
- /* Make sure the the payload data is 4 byte aligned. */
+ /* Make sure the payload data is 4 byte aligned. */
skb_reserve(skb, 2);
}
diff --git a/drivers/net/wireless/zd1211rw/zd_mac.h b/drivers/net/wireless/zd1211rw/zd_mac.h
index 630c298a730..a6d86b996c7 100644
--- a/drivers/net/wireless/zd1211rw/zd_mac.h
+++ b/drivers/net/wireless/zd1211rw/zd_mac.h
@@ -35,7 +35,7 @@ struct zd_ctrlset {
__le16 current_length;
u8 service;
__le16 next_frame_length;
-} __attribute__((packed));
+} __packed;
#define ZD_CS_RESERVED_SIZE 25
@@ -106,7 +106,7 @@ struct zd_ctrlset {
struct rx_length_info {
__le16 length[3];
__le16 tag;
-} __attribute__((packed));
+} __packed;
#define RX_LENGTH_INFO_TAG 0x697e
@@ -117,7 +117,7 @@ struct rx_status {
u8 signal_quality_ofdm;
u8 decryption_type;
u8 frame_status;
-} __attribute__((packed));
+} __packed;
/* rx_status field decryption_type */
#define ZD_RX_NO_WEP 0
@@ -153,7 +153,7 @@ struct tx_status {
u8 mac[ETH_ALEN];
u8 retry;
u8 failure;
-} __attribute__((packed));
+} __packed;
enum mac_flags {
MAC_FIXED_CHANNEL = 0x01,
@@ -212,8 +212,9 @@ struct zd_mac {
#define ZD_REGDOMAIN_ETSI 0x30
#define ZD_REGDOMAIN_SPAIN 0x31
#define ZD_REGDOMAIN_FRANCE 0x32
-#define ZD_REGDOMAIN_JAPAN_ADD 0x40
+#define ZD_REGDOMAIN_JAPAN_2 0x40
#define ZD_REGDOMAIN_JAPAN 0x41
+#define ZD_REGDOMAIN_JAPAN_3 0x49
enum {
MIN_CHANNEL24 = 1,
@@ -225,7 +226,7 @@ enum {
struct ofdm_plcp_header {
u8 prefix[3];
__le16 service;
-} __attribute__((packed));
+} __packed;
static inline u8 zd_ofdm_plcp_header_rate(const struct ofdm_plcp_header *header)
{
@@ -252,7 +253,7 @@ struct cck_plcp_header {
u8 service;
__le16 length;
__le16 crc16;
-} __attribute__((packed));
+} __packed;
static inline u8 zd_cck_plcp_header_signal(const struct cck_plcp_header *header)
{
diff --git a/drivers/net/wireless/zd1211rw/zd_usb.c b/drivers/net/wireless/zd1211rw/zd_usb.c
index c257940b71b..818e1480ca9 100644
--- a/drivers/net/wireless/zd1211rw/zd_usb.c
+++ b/drivers/net/wireless/zd1211rw/zd_usb.c
@@ -844,7 +844,7 @@ out:
* @usb: a &struct zd_usb pointer
* @urb: URB to be freed
*
- * Frees the the transmission URB, which means to put it on the free URB
+ * Frees the transmission URB, which means to put it on the free URB
* list.
*/
static void free_tx_urb(struct zd_usb *usb, struct urb *urb)
diff --git a/drivers/net/wireless/zd1211rw/zd_usb.h b/drivers/net/wireless/zd1211rw/zd_usb.h
index 049f8b91f02..1b1655cb7cb 100644
--- a/drivers/net/wireless/zd1211rw/zd_usb.h
+++ b/drivers/net/wireless/zd1211rw/zd_usb.h
@@ -79,17 +79,17 @@ enum control_requests {
struct usb_req_read_regs {
__le16 id;
__le16 addr[0];
-} __attribute__((packed));
+} __packed;
struct reg_data {
__le16 addr;
__le16 value;
-} __attribute__((packed));
+} __packed;
struct usb_req_write_regs {
__le16 id;
struct reg_data reg_writes[0];
-} __attribute__((packed));
+} __packed;
enum {
RF_IF_LE = 0x02,
@@ -106,7 +106,7 @@ struct usb_req_rfwrite {
/* RF2595: 24 */
__le16 bit_values[0];
/* (CR203 & ~(RF_IF_LE | RF_CLK | RF_DATA)) | (bit ? RF_DATA : 0) */
-} __attribute__((packed));
+} __packed;
/* USB interrupt */
@@ -123,12 +123,12 @@ enum usb_int_flags {
struct usb_int_header {
u8 type; /* must always be 1 */
u8 id;
-} __attribute__((packed));
+} __packed;
struct usb_int_regs {
struct usb_int_header hdr;
struct reg_data regs[0];
-} __attribute__((packed));
+} __packed;
struct usb_int_retry_fail {
struct usb_int_header hdr;
@@ -136,7 +136,7 @@ struct usb_int_retry_fail {
u8 _dummy;
u8 addr[ETH_ALEN];
u8 ibss_wakeup_dest;
-} __attribute__((packed));
+} __packed;
struct read_regs_int {
struct completion completion;
diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c
index d504e2b6025..b50fedcef8a 100644
--- a/drivers/net/xen-netfront.c
+++ b/drivers/net/xen-netfront.c
@@ -1621,6 +1621,7 @@ static void backend_changed(struct xenbus_device *dev,
if (xennet_connect(netdev) != 0)
break;
xenbus_switch_state(dev, XenbusStateConnected);
+ netif_notify_peers(netdev);
break;
case XenbusStateClosing:
diff --git a/drivers/net/xilinx_emaclite.c b/drivers/net/xilinx_emaclite.c
index d04c5b26205..b2c2f391b29 100644
--- a/drivers/net/xilinx_emaclite.c
+++ b/drivers/net/xilinx_emaclite.c
@@ -20,7 +20,7 @@
#include <linux/skbuff.h>
#include <linux/io.h>
#include <linux/slab.h>
-
+#include <linux/of_address.h>
#include <linux/of_device.h>
#include <linux/of_platform.h>
#include <linux/of_mdio.h>
diff --git a/drivers/net/xtsonic.c b/drivers/net/xtsonic.c
index fdba9cb3a59..9f12026d98e 100644
--- a/drivers/net/xtsonic.c
+++ b/drivers/net/xtsonic.c
@@ -93,12 +93,20 @@ static unsigned short known_revisions[] =
static int xtsonic_open(struct net_device *dev)
{
- if (request_irq(dev->irq,sonic_interrupt,IRQF_DISABLED,"sonic",dev)) {
+ int retval;
+
+ retval = request_irq(dev->irq, sonic_interrupt, IRQF_DISABLED,
+ "sonic", dev);
+ if (retval) {
printk(KERN_ERR "%s: unable to get IRQ %d.\n",
dev->name, dev->irq);
return -EAGAIN;
}
- return sonic_open(dev);
+
+ retval = sonic_open(dev);
+ if (retval)
+ free_irq(dev->irq, dev);
+ return retval;
}
static int xtsonic_close(struct net_device *dev)
diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig
index 7cecc8fea9b..6acbff389ab 100644
--- a/drivers/of/Kconfig
+++ b/drivers/of/Kconfig
@@ -1,35 +1,61 @@
-config OF_FLATTREE
+config DTC
+ bool
+
+config OF
bool
+
+menu "Flattened Device Tree and Open Firmware support"
depends on OF
+config PROC_DEVICETREE
+ bool "Support for device tree in /proc"
+ depends on PROC_FS && !SPARC
+ help
+ This option adds a device-tree directory under /proc which contains
+ an image of the device tree that the kernel copies from Open
+ Firmware or other boot firmware. If unsure, say Y here.
+
+config OF_FLATTREE
+ bool
+ select DTC
+
config OF_DYNAMIC
def_bool y
- depends on OF && PPC_OF
+ depends on PPC_OF
+
+config OF_ADDRESS
+ def_bool y
+ depends on !SPARC
+
+config OF_IRQ
+ def_bool y
+ depends on !SPARC
config OF_DEVICE
def_bool y
- depends on OF && (SPARC || PPC_OF || MICROBLAZE)
config OF_GPIO
def_bool y
- depends on OF && (PPC_OF || MICROBLAZE) && GPIOLIB
+ depends on GPIOLIB && !SPARC
help
OpenFirmware GPIO accessors
config OF_I2C
def_tristate I2C
- depends on (PPC_OF || MICROBLAZE) && I2C
+ depends on I2C && !SPARC
help
OpenFirmware I2C accessors
config OF_SPI
def_tristate SPI
- depends on OF && (PPC_OF || MICROBLAZE) && SPI
+ depends on SPI && !SPARC
help
OpenFirmware SPI accessors
config OF_MDIO
def_tristate PHYLIB
- depends on OF && PHYLIB
+ depends on PHYLIB
help
OpenFirmware MDIO bus (Ethernet PHY) accessors
+
+endmenu # OF
diff --git a/drivers/of/Makefile b/drivers/of/Makefile
index f232cc98ce0..0052c405463 100644
--- a/drivers/of/Makefile
+++ b/drivers/of/Makefile
@@ -1,5 +1,7 @@
obj-y = base.o
obj-$(CONFIG_OF_FLATTREE) += fdt.o
+obj-$(CONFIG_OF_ADDRESS) += address.o
+obj-$(CONFIG_OF_IRQ) += irq.o
obj-$(CONFIG_OF_DEVICE) += device.o platform.o
obj-$(CONFIG_OF_GPIO) += gpio.o
obj-$(CONFIG_OF_I2C) += of_i2c.o
diff --git a/drivers/of/address.c b/drivers/of/address.c
new file mode 100644
index 00000000000..fcadb726d4f
--- /dev/null
+++ b/drivers/of/address.c
@@ -0,0 +1,595 @@
+
+#include <linux/io.h>
+#include <linux/ioport.h>
+#include <linux/module.h>
+#include <linux/of_address.h>
+#include <linux/pci_regs.h>
+#include <linux/string.h>
+
+/* Max address size we deal with */
+#define OF_MAX_ADDR_CELLS 4
+#define OF_CHECK_COUNTS(na, ns) ((na) > 0 && (na) <= OF_MAX_ADDR_CELLS && \
+ (ns) > 0)
+
+static struct of_bus *of_match_bus(struct device_node *np);
+static int __of_address_to_resource(struct device_node *dev, const u32 *addrp,
+ u64 size, unsigned int flags,
+ struct resource *r);
+
+/* Debug utility */
+#ifdef DEBUG
+static void of_dump_addr(const char *s, const u32 *addr, int na)
+{
+ printk(KERN_DEBUG "%s", s);
+ while (na--)
+ printk(" %08x", be32_to_cpu(*(addr++)));
+ printk("\n");
+}
+#else
+static void of_dump_addr(const char *s, const u32 *addr, int na) { }
+#endif
+
+/* Callbacks for bus specific translators */
+struct of_bus {
+ const char *name;
+ const char *addresses;
+ int (*match)(struct device_node *parent);
+ void (*count_cells)(struct device_node *child,
+ int *addrc, int *sizec);
+ u64 (*map)(u32 *addr, const u32 *range,
+ int na, int ns, int pna);
+ int (*translate)(u32 *addr, u64 offset, int na);
+ unsigned int (*get_flags)(const u32 *addr);
+};
+
+/*
+ * Default translator (generic bus)
+ */
+
+static void of_bus_default_count_cells(struct device_node *dev,
+ int *addrc, int *sizec)
+{
+ if (addrc)
+ *addrc = of_n_addr_cells(dev);
+ if (sizec)
+ *sizec = of_n_size_cells(dev);
+}
+
+static u64 of_bus_default_map(u32 *addr, const u32 *range,
+ int na, int ns, int pna)
+{
+ u64 cp, s, da;
+
+ cp = of_read_number(range, na);
+ s = of_read_number(range + na + pna, ns);
+ da = of_read_number(addr, na);
+
+ pr_debug("OF: default map, cp=%llx, s=%llx, da=%llx\n",
+ (unsigned long long)cp, (unsigned long long)s,
+ (unsigned long long)da);
+
+ if (da < cp || da >= (cp + s))
+ return OF_BAD_ADDR;
+ return da - cp;
+}
+
+static int of_bus_default_translate(u32 *addr, u64 offset, int na)
+{
+ u64 a = of_read_number(addr, na);
+ memset(addr, 0, na * 4);
+ a += offset;
+ if (na > 1)
+ addr[na - 2] = cpu_to_be32(a >> 32);
+ addr[na - 1] = cpu_to_be32(a & 0xffffffffu);
+
+ return 0;
+}
+
+static unsigned int of_bus_default_get_flags(const u32 *addr)
+{
+ return IORESOURCE_MEM;
+}
+
+#ifdef CONFIG_PCI
+/*
+ * PCI bus specific translator
+ */
+
+static int of_bus_pci_match(struct device_node *np)
+{
+ /* "vci" is for the /chaos bridge on 1st-gen PCI powermacs */
+ return !strcmp(np->type, "pci") || !strcmp(np->type, "vci");
+}
+
+static void of_bus_pci_count_cells(struct device_node *np,
+ int *addrc, int *sizec)
+{
+ if (addrc)
+ *addrc = 3;
+ if (sizec)
+ *sizec = 2;
+}
+
+static unsigned int of_bus_pci_get_flags(const u32 *addr)
+{
+ unsigned int flags = 0;
+ u32 w = addr[0];
+
+ switch((w >> 24) & 0x03) {
+ case 0x01:
+ flags |= IORESOURCE_IO;
+ break;
+ case 0x02: /* 32 bits */
+ case 0x03: /* 64 bits */
+ flags |= IORESOURCE_MEM;
+ break;
+ }
+ if (w & 0x40000000)
+ flags |= IORESOURCE_PREFETCH;
+ return flags;
+}
+
+static u64 of_bus_pci_map(u32 *addr, const u32 *range, int na, int ns, int pna)
+{
+ u64 cp, s, da;
+ unsigned int af, rf;
+
+ af = of_bus_pci_get_flags(addr);
+ rf = of_bus_pci_get_flags(range);
+
+ /* Check address type match */
+ if ((af ^ rf) & (IORESOURCE_MEM | IORESOURCE_IO))
+ return OF_BAD_ADDR;
+
+ /* Read address values, skipping high cell */
+ cp = of_read_number(range + 1, na - 1);
+ s = of_read_number(range + na + pna, ns);
+ da = of_read_number(addr + 1, na - 1);
+
+ pr_debug("OF: PCI map, cp=%llx, s=%llx, da=%llx\n",
+ (unsigned long long)cp, (unsigned long long)s,
+ (unsigned long long)da);
+
+ if (da < cp || da >= (cp + s))
+ return OF_BAD_ADDR;
+ return da - cp;
+}
+
+static int of_bus_pci_translate(u32 *addr, u64 offset, int na)
+{
+ return of_bus_default_translate(addr + 1, offset, na - 1);
+}
+
+const u32 *of_get_pci_address(struct device_node *dev, int bar_no, u64 *size,
+ unsigned int *flags)
+{
+ const u32 *prop;
+ unsigned int psize;
+ struct device_node *parent;
+ struct of_bus *bus;
+ int onesize, i, na, ns;
+
+ /* Get parent & match bus type */
+ parent = of_get_parent(dev);
+ if (parent == NULL)
+ return NULL;
+ bus = of_match_bus(parent);
+ if (strcmp(bus->name, "pci")) {
+ of_node_put(parent);
+ return NULL;
+ }
+ bus->count_cells(dev, &na, &ns);
+ of_node_put(parent);
+ if (!OF_CHECK_COUNTS(na, ns))
+ return NULL;
+
+ /* Get "reg" or "assigned-addresses" property */
+ prop = of_get_property(dev, bus->addresses, &psize);
+ if (prop == NULL)
+ return NULL;
+ psize /= 4;
+
+ onesize = na + ns;
+ for (i = 0; psize >= onesize; psize -= onesize, prop += onesize, i++) {
+ u32 val = be32_to_cpu(prop[0]);
+ if ((val & 0xff) == ((bar_no * 4) + PCI_BASE_ADDRESS_0)) {
+ if (size)
+ *size = of_read_number(prop + na, ns);
+ if (flags)
+ *flags = bus->get_flags(prop);
+ return prop;
+ }
+ }
+ return NULL;
+}
+EXPORT_SYMBOL(of_get_pci_address);
+
+int of_pci_address_to_resource(struct device_node *dev, int bar,
+ struct resource *r)
+{
+ const u32 *addrp;
+ u64 size;
+ unsigned int flags;
+
+ addrp = of_get_pci_address(dev, bar, &size, &flags);
+ if (addrp == NULL)
+ return -EINVAL;
+ return __of_address_to_resource(dev, addrp, size, flags, r);
+}
+EXPORT_SYMBOL_GPL(of_pci_address_to_resource);
+#endif /* CONFIG_PCI */
+
+/*
+ * ISA bus specific translator
+ */
+
+static int of_bus_isa_match(struct device_node *np)
+{
+ return !strcmp(np->name, "isa");
+}
+
+static void of_bus_isa_count_cells(struct device_node *child,
+ int *addrc, int *sizec)
+{
+ if (addrc)
+ *addrc = 2;
+ if (sizec)
+ *sizec = 1;
+}
+
+static u64 of_bus_isa_map(u32 *addr, const u32 *range, int na, int ns, int pna)
+{
+ u64 cp, s, da;
+
+ /* Check address type match */
+ if ((addr[0] ^ range[0]) & 0x00000001)
+ return OF_BAD_ADDR;
+
+ /* Read address values, skipping high cell */
+ cp = of_read_number(range + 1, na - 1);
+ s = of_read_number(range + na + pna, ns);
+ da = of_read_number(addr + 1, na - 1);
+
+ pr_debug("OF: ISA map, cp=%llx, s=%llx, da=%llx\n",
+ (unsigned long long)cp, (unsigned long long)s,
+ (unsigned long long)da);
+
+ if (da < cp || da >= (cp + s))
+ return OF_BAD_ADDR;
+ return da - cp;
+}
+
+static int of_bus_isa_translate(u32 *addr, u64 offset, int na)
+{
+ return of_bus_default_translate(addr + 1, offset, na - 1);
+}
+
+static unsigned int of_bus_isa_get_flags(const u32 *addr)
+{
+ unsigned int flags = 0;
+ u32 w = addr[0];
+
+ if (w & 1)
+ flags |= IORESOURCE_IO;
+ else
+ flags |= IORESOURCE_MEM;
+ return flags;
+}
+
+/*
+ * Array of bus specific translators
+ */
+
+static struct of_bus of_busses[] = {
+#ifdef CONFIG_PCI
+ /* PCI */
+ {
+ .name = "pci",
+ .addresses = "assigned-addresses",
+ .match = of_bus_pci_match,
+ .count_cells = of_bus_pci_count_cells,
+ .map = of_bus_pci_map,
+ .translate = of_bus_pci_translate,
+ .get_flags = of_bus_pci_get_flags,
+ },
+#endif /* CONFIG_PCI */
+ /* ISA */
+ {
+ .name = "isa",
+ .addresses = "reg",
+ .match = of_bus_isa_match,
+ .count_cells = of_bus_isa_count_cells,
+ .map = of_bus_isa_map,
+ .translate = of_bus_isa_translate,
+ .get_flags = of_bus_isa_get_flags,
+ },
+ /* Default */
+ {
+ .name = "default",
+ .addresses = "reg",
+ .match = NULL,
+ .count_cells = of_bus_default_count_cells,
+ .map = of_bus_default_map,
+ .translate = of_bus_default_translate,
+ .get_flags = of_bus_default_get_flags,
+ },
+};
+
+static struct of_bus *of_match_bus(struct device_node *np)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(of_busses); i++)
+ if (!of_busses[i].match || of_busses[i].match(np))
+ return &of_busses[i];
+ BUG();
+ return NULL;
+}
+
+static int of_translate_one(struct device_node *parent, struct of_bus *bus,
+ struct of_bus *pbus, u32 *addr,
+ int na, int ns, int pna, const char *rprop)
+{
+ const u32 *ranges;
+ unsigned int rlen;
+ int rone;
+ u64 offset = OF_BAD_ADDR;
+
+ /* Normally, an absence of a "ranges" property means we are
+ * crossing a non-translatable boundary, and thus the addresses
+ * below the current not cannot be converted to CPU physical ones.
+ * Unfortunately, while this is very clear in the spec, it's not
+ * what Apple understood, and they do have things like /uni-n or
+ * /ht nodes with no "ranges" property and a lot of perfectly
+ * useable mapped devices below them. Thus we treat the absence of
+ * "ranges" as equivalent to an empty "ranges" property which means
+ * a 1:1 translation at that level. It's up to the caller not to try
+ * to translate addresses that aren't supposed to be translated in
+ * the first place. --BenH.
+ *
+ * As far as we know, this damage only exists on Apple machines, so
+ * This code is only enabled on powerpc. --gcl
+ */
+ ranges = of_get_property(parent, rprop, &rlen);
+#if !defined(CONFIG_PPC)
+ if (ranges == NULL) {
+ pr_err("OF: no ranges; cannot translate\n");
+ return 1;
+ }
+#endif /* !defined(CONFIG_PPC) */
+ if (ranges == NULL || rlen == 0) {
+ offset = of_read_number(addr, na);
+ memset(addr, 0, pna * 4);
+ pr_debug("OF: empty ranges; 1:1 translation\n");
+ goto finish;
+ }
+
+ pr_debug("OF: walking ranges...\n");
+
+ /* Now walk through the ranges */
+ rlen /= 4;
+ rone = na + pna + ns;
+ for (; rlen >= rone; rlen -= rone, ranges += rone) {
+ offset = bus->map(addr, ranges, na, ns, pna);
+ if (offset != OF_BAD_ADDR)
+ break;
+ }
+ if (offset == OF_BAD_ADDR) {
+ pr_debug("OF: not found !\n");
+ return 1;
+ }
+ memcpy(addr, ranges + na, 4 * pna);
+
+ finish:
+ of_dump_addr("OF: parent translation for:", addr, pna);
+ pr_debug("OF: with offset: %llx\n", (unsigned long long)offset);
+
+ /* Translate it into parent bus space */
+ return pbus->translate(addr, offset, pna);
+}
+
+/*
+ * Translate an address from the device-tree into a CPU physical address,
+ * this walks up the tree and applies the various bus mappings on the
+ * way.
+ *
+ * Note: We consider that crossing any level with #size-cells == 0 to mean
+ * that translation is impossible (that is we are not dealing with a value
+ * that can be mapped to a cpu physical address). This is not really specified
+ * that way, but this is traditionally the way IBM at least do things
+ */
+u64 __of_translate_address(struct device_node *dev, const u32 *in_addr,
+ const char *rprop)
+{
+ struct device_node *parent = NULL;
+ struct of_bus *bus, *pbus;
+ u32 addr[OF_MAX_ADDR_CELLS];
+ int na, ns, pna, pns;
+ u64 result = OF_BAD_ADDR;
+
+ pr_debug("OF: ** translation for device %s **\n", dev->full_name);
+
+ /* Increase refcount at current level */
+ of_node_get(dev);
+
+ /* Get parent & match bus type */
+ parent = of_get_parent(dev);
+ if (parent == NULL)
+ goto bail;
+ bus = of_match_bus(parent);
+
+ /* Cound address cells & copy address locally */
+ bus->count_cells(dev, &na, &ns);
+ if (!OF_CHECK_COUNTS(na, ns)) {
+ printk(KERN_ERR "prom_parse: Bad cell count for %s\n",
+ dev->full_name);
+ goto bail;
+ }
+ memcpy(addr, in_addr, na * 4);
+
+ pr_debug("OF: bus is %s (na=%d, ns=%d) on %s\n",
+ bus->name, na, ns, parent->full_name);
+ of_dump_addr("OF: translating address:", addr, na);
+
+ /* Translate */
+ for (;;) {
+ /* Switch to parent bus */
+ of_node_put(dev);
+ dev = parent;
+ parent = of_get_parent(dev);
+
+ /* If root, we have finished */
+ if (parent == NULL) {
+ pr_debug("OF: reached root node\n");
+ result = of_read_number(addr, na);
+ break;
+ }
+
+ /* Get new parent bus and counts */
+ pbus = of_match_bus(parent);
+ pbus->count_cells(dev, &pna, &pns);
+ if (!OF_CHECK_COUNTS(pna, pns)) {
+ printk(KERN_ERR "prom_parse: Bad cell count for %s\n",
+ dev->full_name);
+ break;
+ }
+
+ pr_debug("OF: parent bus is %s (na=%d, ns=%d) on %s\n",
+ pbus->name, pna, pns, parent->full_name);
+
+ /* Apply bus translation */
+ if (of_translate_one(dev, bus, pbus, addr, na, ns, pna, rprop))
+ break;
+
+ /* Complete the move up one level */
+ na = pna;
+ ns = pns;
+ bus = pbus;
+
+ of_dump_addr("OF: one level translation:", addr, na);
+ }
+ bail:
+ of_node_put(parent);
+ of_node_put(dev);
+
+ return result;
+}
+
+u64 of_translate_address(struct device_node *dev, const u32 *in_addr)
+{
+ return __of_translate_address(dev, in_addr, "ranges");
+}
+EXPORT_SYMBOL(of_translate_address);
+
+u64 of_translate_dma_address(struct device_node *dev, const u32 *in_addr)
+{
+ return __of_translate_address(dev, in_addr, "dma-ranges");
+}
+EXPORT_SYMBOL(of_translate_dma_address);
+
+const u32 *of_get_address(struct device_node *dev, int index, u64 *size,
+ unsigned int *flags)
+{
+ const u32 *prop;
+ unsigned int psize;
+ struct device_node *parent;
+ struct of_bus *bus;
+ int onesize, i, na, ns;
+
+ /* Get parent & match bus type */
+ parent = of_get_parent(dev);
+ if (parent == NULL)
+ return NULL;
+ bus = of_match_bus(parent);
+ bus->count_cells(dev, &na, &ns);
+ of_node_put(parent);
+ if (!OF_CHECK_COUNTS(na, ns))
+ return NULL;
+
+ /* Get "reg" or "assigned-addresses" property */
+ prop = of_get_property(dev, bus->addresses, &psize);
+ if (prop == NULL)
+ return NULL;
+ psize /= 4;
+
+ onesize = na + ns;
+ for (i = 0; psize >= onesize; psize -= onesize, prop += onesize, i++)
+ if (i == index) {
+ if (size)
+ *size = of_read_number(prop + na, ns);
+ if (flags)
+ *flags = bus->get_flags(prop);
+ return prop;
+ }
+ return NULL;
+}
+EXPORT_SYMBOL(of_get_address);
+
+static int __of_address_to_resource(struct device_node *dev, const u32 *addrp,
+ u64 size, unsigned int flags,
+ struct resource *r)
+{
+ u64 taddr;
+
+ if ((flags & (IORESOURCE_IO | IORESOURCE_MEM)) == 0)
+ return -EINVAL;
+ taddr = of_translate_address(dev, addrp);
+ if (taddr == OF_BAD_ADDR)
+ return -EINVAL;
+ memset(r, 0, sizeof(struct resource));
+ if (flags & IORESOURCE_IO) {
+ unsigned long port;
+ port = pci_address_to_pio(taddr);
+ if (port == (unsigned long)-1)
+ return -EINVAL;
+ r->start = port;
+ r->end = port + size - 1;
+ } else {
+ r->start = taddr;
+ r->end = taddr + size - 1;
+ }
+ r->flags = flags;
+ r->name = dev->full_name;
+ return 0;
+}
+
+/**
+ * of_address_to_resource - Translate device tree address and return as resource
+ *
+ * Note that if your address is a PIO address, the conversion will fail if
+ * the physical address can't be internally converted to an IO token with
+ * pci_address_to_pio(), that is because it's either called to early or it
+ * can't be matched to any host bridge IO space
+ */
+int of_address_to_resource(struct device_node *dev, int index,
+ struct resource *r)
+{
+ const u32 *addrp;
+ u64 size;
+ unsigned int flags;
+
+ addrp = of_get_address(dev, index, &size, &flags);
+ if (addrp == NULL)
+ return -EINVAL;
+ return __of_address_to_resource(dev, addrp, size, flags, r);
+}
+EXPORT_SYMBOL_GPL(of_address_to_resource);
+
+
+/**
+ * of_iomap - Maps the memory mapped IO for a given device_node
+ * @device: the device whose io range will be mapped
+ * @index: index of the io range
+ *
+ * Returns a pointer to the mapped memory
+ */
+void __iomem *of_iomap(struct device_node *np, int index)
+{
+ struct resource res;
+
+ if (of_address_to_resource(np, index, &res))
+ return NULL;
+
+ return ioremap(res.start, 1 + res.end - res.start);
+}
+EXPORT_SYMBOL(of_iomap);
diff --git a/drivers/of/base.c b/drivers/of/base.c
index b5ad9740d8b..aa805250de7 100644
--- a/drivers/of/base.c
+++ b/drivers/of/base.c
@@ -545,74 +545,28 @@ struct device_node *of_find_matching_node(struct device_node *from,
EXPORT_SYMBOL(of_find_matching_node);
/**
- * of_modalias_table: Table of explicit compatible ==> modalias mappings
- *
- * This table allows particulare compatible property values to be mapped
- * to modalias strings. This is useful for busses which do not directly
- * understand the OF device tree but are populated based on data contained
- * within the device tree. SPI and I2C are the two current users of this
- * table.
- *
- * In most cases, devices do not need to be listed in this table because
- * the modalias value can be derived directly from the compatible table.
- * However, if for any reason a value cannot be derived, then this table
- * provides a method to override the implicit derivation.
- *
- * At the moment, a single table is used for all bus types because it is
- * assumed that the data size is small and that the compatible values
- * should already be distinct enough to differentiate between SPI, I2C
- * and other devices.
- */
-struct of_modalias_table {
- char *of_device;
- char *modalias;
-};
-static struct of_modalias_table of_modalias_table[] = {
- { "fsl,mcu-mpc8349emitx", "mcu-mpc8349emitx" },
- { "mmc-spi-slot", "mmc_spi" },
-};
-
-/**
* of_modalias_node - Lookup appropriate modalias for a device node
* @node: pointer to a device tree node
* @modalias: Pointer to buffer that modalias value will be copied into
* @len: Length of modalias value
*
- * Based on the value of the compatible property, this routine will determine
- * an appropriate modalias value for a particular device tree node. Two
- * separate methods are attempted to derive a modalias value.
+ * Based on the value of the compatible property, this routine will attempt
+ * to choose an appropriate modalias value for a particular device tree node.
+ * It does this by stripping the manufacturer prefix (as delimited by a ',')
+ * from the first entry in the compatible list property.
*
- * First method is to lookup the compatible value in of_modalias_table.
- * Second is to strip off the manufacturer prefix from the first
- * compatible entry and use the remainder as modalias
- *
- * This routine returns 0 on success
+ * This routine returns 0 on success, <0 on failure.
*/
int of_modalias_node(struct device_node *node, char *modalias, int len)
{
- int i, cplen;
- const char *compatible;
- const char *p;
-
- /* 1. search for exception list entry */
- for (i = 0; i < ARRAY_SIZE(of_modalias_table); i++) {
- compatible = of_modalias_table[i].of_device;
- if (!of_device_is_compatible(node, compatible))
- continue;
- strlcpy(modalias, of_modalias_table[i].modalias, len);
- return 0;
- }
+ const char *compatible, *p;
+ int cplen;
compatible = of_get_property(node, "compatible", &cplen);
- if (!compatible)
+ if (!compatible || strlen(compatible) > cplen)
return -ENODEV;
-
- /* 2. take first compatible entry and strip manufacturer */
p = strchr(compatible, ',');
- if (!p)
- return -ENODEV;
- p++;
- strlcpy(modalias, p, len);
+ strlcpy(modalias, p ? p + 1 : compatible, len);
return 0;
}
EXPORT_SYMBOL_GPL(of_modalias_node);
@@ -651,14 +605,14 @@ EXPORT_SYMBOL(of_find_node_by_phandle);
struct device_node *
of_parse_phandle(struct device_node *np, const char *phandle_name, int index)
{
- const phandle *phandle;
+ const __be32 *phandle;
int size;
phandle = of_get_property(np, phandle_name, &size);
if ((!phandle) || (size < sizeof(*phandle) * (index + 1)))
return NULL;
- return of_find_node_by_phandle(phandle[index]);
+ return of_find_node_by_phandle(be32_to_cpup(phandle + index));
}
EXPORT_SYMBOL(of_parse_phandle);
@@ -714,16 +668,16 @@ int of_parse_phandles_with_args(struct device_node *np, const char *list_name,
while (list < list_end) {
const __be32 *cells;
- const phandle *phandle;
+ phandle phandle;
- phandle = list++;
+ phandle = be32_to_cpup(list++);
args = list;
/* one cell hole in the list = <>; */
- if (!*phandle)
+ if (!phandle)
goto next;
- node = of_find_node_by_phandle(*phandle);
+ node = of_find_node_by_phandle(phandle);
if (!node) {
pr_debug("%s: could not find phandle\n",
np->full_name);
diff --git a/drivers/of/device.c b/drivers/of/device.c
index 7d18f8e0b01..0d8a0644f54 100644
--- a/drivers/of/device.c
+++ b/drivers/of/device.c
@@ -20,13 +20,13 @@
const struct of_device_id *of_match_device(const struct of_device_id *matches,
const struct device *dev)
{
- if (!dev->of_node)
+ if ((!matches) || (!dev->of_node))
return NULL;
return of_match_node(matches, dev->of_node);
}
EXPORT_SYMBOL(of_match_device);
-struct of_device *of_dev_get(struct of_device *dev)
+struct platform_device *of_dev_get(struct platform_device *dev)
{
struct device *tmp;
@@ -34,13 +34,13 @@ struct of_device *of_dev_get(struct of_device *dev)
return NULL;
tmp = get_device(&dev->dev);
if (tmp)
- return to_of_device(tmp);
+ return to_platform_device(tmp);
else
return NULL;
}
EXPORT_SYMBOL(of_dev_get);
-void of_dev_put(struct of_device *dev)
+void of_dev_put(struct platform_device *dev)
{
if (dev)
put_device(&dev->dev);
@@ -50,28 +50,25 @@ EXPORT_SYMBOL(of_dev_put);
static ssize_t devspec_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct of_device *ofdev;
+ struct platform_device *ofdev;
- ofdev = to_of_device(dev);
+ ofdev = to_platform_device(dev);
return sprintf(buf, "%s\n", ofdev->dev.of_node->full_name);
}
static ssize_t name_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct of_device *ofdev;
+ struct platform_device *ofdev;
- ofdev = to_of_device(dev);
+ ofdev = to_platform_device(dev);
return sprintf(buf, "%s\n", ofdev->dev.of_node->name);
}
static ssize_t modalias_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct of_device *ofdev = to_of_device(dev);
- ssize_t len = 0;
-
- len = of_device_get_modalias(ofdev, buf, PAGE_SIZE - 2);
+ ssize_t len = of_device_get_modalias(dev, buf, PAGE_SIZE - 2);
buf[len] = '\n';
buf[len+1] = 0;
return len+1;
@@ -93,20 +90,25 @@ struct device_attribute of_platform_device_attrs[] = {
*/
void of_release_dev(struct device *dev)
{
- struct of_device *ofdev;
+ struct platform_device *ofdev;
- ofdev = to_of_device(dev);
+ ofdev = to_platform_device(dev);
of_node_put(ofdev->dev.of_node);
kfree(ofdev);
}
EXPORT_SYMBOL(of_release_dev);
-int of_device_register(struct of_device *ofdev)
+int of_device_register(struct platform_device *ofdev)
{
BUG_ON(ofdev->dev.of_node == NULL);
device_initialize(&ofdev->dev);
+ /* name and id have to be set so that the platform bus doesn't get
+ * confused on matching */
+ ofdev->name = dev_name(&ofdev->dev);
+ ofdev->id = -1;
+
/* device_add will assume that this device is on the same node as
* the parent. If there is no parent defined, set the node
* explicitly */
@@ -117,25 +119,24 @@ int of_device_register(struct of_device *ofdev)
}
EXPORT_SYMBOL(of_device_register);
-void of_device_unregister(struct of_device *ofdev)
+void of_device_unregister(struct platform_device *ofdev)
{
device_unregister(&ofdev->dev);
}
EXPORT_SYMBOL(of_device_unregister);
-ssize_t of_device_get_modalias(struct of_device *ofdev,
- char *str, ssize_t len)
+ssize_t of_device_get_modalias(struct device *dev, char *str, ssize_t len)
{
const char *compat;
int cplen, i;
ssize_t tsize, csize, repend;
/* Name & Type */
- csize = snprintf(str, len, "of:N%sT%s", ofdev->dev.of_node->name,
- ofdev->dev.of_node->type);
+ csize = snprintf(str, len, "of:N%sT%s", dev->of_node->name,
+ dev->of_node->type);
/* Get compatible property if any */
- compat = of_get_property(ofdev->dev.of_node, "compatible", &cplen);
+ compat = of_get_property(dev->of_node, "compatible", &cplen);
if (!compat)
return csize;
@@ -170,3 +171,51 @@ ssize_t of_device_get_modalias(struct of_device *ofdev,
return tsize;
}
+
+/**
+ * of_device_uevent - Display OF related uevent information
+ */
+int of_device_uevent(struct device *dev, struct kobj_uevent_env *env)
+{
+ const char *compat;
+ int seen = 0, cplen, sl;
+
+ if ((!dev) || (!dev->of_node))
+ return -ENODEV;
+
+ if (add_uevent_var(env, "OF_NAME=%s", dev->of_node->name))
+ return -ENOMEM;
+
+ if (add_uevent_var(env, "OF_TYPE=%s", dev->of_node->type))
+ return -ENOMEM;
+
+ /* Since the compatible field can contain pretty much anything
+ * it's not really legal to split it out with commas. We split it
+ * up using a number of environment variables instead. */
+
+ compat = of_get_property(dev->of_node, "compatible", &cplen);
+ while (compat && *compat && cplen > 0) {
+ if (add_uevent_var(env, "OF_COMPATIBLE_%d=%s", seen, compat))
+ return -ENOMEM;
+
+ sl = strlen(compat) + 1;
+ compat += sl;
+ cplen -= sl;
+ seen++;
+ }
+
+ if (add_uevent_var(env, "OF_COMPATIBLE_N=%d", seen))
+ return -ENOMEM;
+
+ /* modalias is trickier, we add it in 2 steps */
+ if (add_uevent_var(env, "MODALIAS="))
+ return -ENOMEM;
+
+ sl = of_device_get_modalias(dev, &env->buf[env->buflen-1],
+ sizeof(env->buf) - env->buflen);
+ if (sl >= (sizeof(env->buf) - env->buflen))
+ return -ENOMEM;
+ env->buflen += sl;
+
+ return 0;
+}
diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c
index b6987bba855..65da5aec755 100644
--- a/drivers/of/fdt.c
+++ b/drivers/of/fdt.c
@@ -69,9 +69,9 @@ int __init of_scan_flat_dt(int (*it)(unsigned long node,
u32 sz = be32_to_cpup((__be32 *)p);
p += 8;
if (be32_to_cpu(initial_boot_params->version) < 0x10)
- p = _ALIGN(p, sz >= 8 ? 8 : 4);
+ p = ALIGN(p, sz >= 8 ? 8 : 4);
p += sz;
- p = _ALIGN(p, 4);
+ p = ALIGN(p, 4);
continue;
}
if (tag != OF_DT_BEGIN_NODE) {
@@ -80,7 +80,7 @@ int __init of_scan_flat_dt(int (*it)(unsigned long node,
}
depth++;
pathp = (char *)p;
- p = _ALIGN(p + strlen(pathp) + 1, 4);
+ p = ALIGN(p + strlen(pathp) + 1, 4);
if ((*pathp) == '/') {
char *lp, *np;
for (lp = NULL, np = pathp; *np; np++)
@@ -109,7 +109,7 @@ unsigned long __init of_get_flat_dt_root(void)
p += 4;
BUG_ON(be32_to_cpup((__be32 *)p) != OF_DT_BEGIN_NODE);
p += 4;
- return _ALIGN(p + strlen((char *)p) + 1, 4);
+ return ALIGN(p + strlen((char *)p) + 1, 4);
}
/**
@@ -138,7 +138,7 @@ void *__init of_get_flat_dt_prop(unsigned long node, const char *name,
noff = be32_to_cpup((__be32 *)(p + 4));
p += 8;
if (be32_to_cpu(initial_boot_params->version) < 0x10)
- p = _ALIGN(p, sz >= 8 ? 8 : 4);
+ p = ALIGN(p, sz >= 8 ? 8 : 4);
nstr = find_flat_dt_string(noff);
if (nstr == NULL) {
@@ -151,7 +151,7 @@ void *__init of_get_flat_dt_prop(unsigned long node, const char *name,
return (void *)p;
}
p += sz;
- p = _ALIGN(p, 4);
+ p = ALIGN(p, 4);
} while (1);
}
@@ -169,7 +169,7 @@ int __init of_flat_dt_is_compatible(unsigned long node, const char *compat)
if (cp == NULL)
return 0;
while (cplen > 0) {
- if (strncasecmp(cp, compat, strlen(compat)) == 0)
+ if (of_compat_cmp(cp, compat, strlen(compat)) == 0)
return 1;
l = strlen(cp) + 1;
cp += l;
@@ -184,7 +184,7 @@ static void *__init unflatten_dt_alloc(unsigned long *mem, unsigned long size,
{
void *res;
- *mem = _ALIGN(*mem, align);
+ *mem = ALIGN(*mem, align);
res = (void *)*mem;
*mem += size;
@@ -220,7 +220,7 @@ unsigned long __init unflatten_dt_node(unsigned long mem,
*p += 4;
pathp = (char *)*p;
l = allocl = strlen(pathp) + 1;
- *p = _ALIGN(*p + l, 4);
+ *p = ALIGN(*p + l, 4);
/* version 0x10 has a more compact unit name here instead of the full
* path. we accumulate the full path size using "fpsize", we'll rebuild
@@ -299,7 +299,7 @@ unsigned long __init unflatten_dt_node(unsigned long mem,
noff = be32_to_cpup((__be32 *)((*p) + 4));
*p += 8;
if (be32_to_cpu(initial_boot_params->version) < 0x10)
- *p = _ALIGN(*p, sz >= 8 ? 8 : 4);
+ *p = ALIGN(*p, sz >= 8 ? 8 : 4);
pname = find_flat_dt_string(noff);
if (pname == NULL) {
@@ -320,20 +320,20 @@ unsigned long __init unflatten_dt_node(unsigned long mem,
if ((strcmp(pname, "phandle") == 0) ||
(strcmp(pname, "linux,phandle") == 0)) {
if (np->phandle == 0)
- np->phandle = *((u32 *)*p);
+ np->phandle = be32_to_cpup((__be32*)*p);
}
/* And we process the "ibm,phandle" property
* used in pSeries dynamic device tree
* stuff */
if (strcmp(pname, "ibm,phandle") == 0)
- np->phandle = *((u32 *)*p);
+ np->phandle = be32_to_cpup((__be32 *)*p);
pp->name = pname;
pp->length = sz;
pp->value = (void *)*p;
*prev_pp = pp;
prev_pp = &pp->next;
}
- *p = _ALIGN((*p) + sz, 4);
+ *p = ALIGN((*p) + sz, 4);
}
/* with version 0x10 we may not have the name property, recreate
* it here from the unit name if absent
diff --git a/drivers/of/gpio.c b/drivers/of/gpio.c
index a1b31a4abae..905960338fb 100644
--- a/drivers/of/gpio.c
+++ b/drivers/of/gpio.c
@@ -11,13 +11,14 @@
* (at your option) any later version.
*/
-#include <linux/kernel.h>
+#include <linux/device.h>
#include <linux/errno.h>
+#include <linux/module.h>
#include <linux/io.h>
#include <linux/of.h>
-#include <linux/slab.h>
+#include <linux/of_address.h>
#include <linux/of_gpio.h>
-#include <asm/prom.h>
+#include <linux/slab.h>
/**
* of_get_gpio_flags - Get a GPIO number and flags to use with GPIO API
@@ -33,32 +34,32 @@ int of_get_gpio_flags(struct device_node *np, int index,
enum of_gpio_flags *flags)
{
int ret;
- struct device_node *gc;
- struct of_gpio_chip *of_gc = NULL;
+ struct device_node *gpio_np;
+ struct gpio_chip *gc;
int size;
const void *gpio_spec;
const __be32 *gpio_cells;
ret = of_parse_phandles_with_args(np, "gpios", "#gpio-cells", index,
- &gc, &gpio_spec);
+ &gpio_np, &gpio_spec);
if (ret) {
pr_debug("%s: can't parse gpios property\n", __func__);
goto err0;
}
- of_gc = gc->data;
- if (!of_gc) {
+ gc = of_node_to_gpiochip(gpio_np);
+ if (!gc) {
pr_debug("%s: gpio controller %s isn't registered\n",
- np->full_name, gc->full_name);
+ np->full_name, gpio_np->full_name);
ret = -ENODEV;
goto err1;
}
- gpio_cells = of_get_property(gc, "#gpio-cells", &size);
+ gpio_cells = of_get_property(gpio_np, "#gpio-cells", &size);
if (!gpio_cells || size != sizeof(*gpio_cells) ||
- be32_to_cpup(gpio_cells) != of_gc->gpio_cells) {
+ be32_to_cpup(gpio_cells) != gc->of_gpio_n_cells) {
pr_debug("%s: wrong #gpio-cells for %s\n",
- np->full_name, gc->full_name);
+ np->full_name, gpio_np->full_name);
ret = -EINVAL;
goto err1;
}
@@ -67,13 +68,13 @@ int of_get_gpio_flags(struct device_node *np, int index,
if (flags)
*flags = 0;
- ret = of_gc->xlate(of_gc, np, gpio_spec, flags);
+ ret = gc->of_xlate(gc, np, gpio_spec, flags);
if (ret < 0)
goto err1;
- ret += of_gc->gc.base;
+ ret += gc->base;
err1:
- of_node_put(gc);
+ of_node_put(gpio_np);
err0:
pr_debug("%s exited with status %d\n", __func__, ret);
return ret;
@@ -116,7 +117,7 @@ EXPORT_SYMBOL(of_gpio_count);
/**
* of_gpio_simple_xlate - translate gpio_spec to the GPIO number and flags
- * @of_gc: pointer to the of_gpio_chip structure
+ * @gc: pointer to the gpio_chip structure
* @np: device node of the GPIO chip
* @gpio_spec: gpio specifier as found in the device tree
* @flags: a flags pointer to fill in
@@ -125,8 +126,8 @@ EXPORT_SYMBOL(of_gpio_count);
* gpio chips. This function performs only one sanity check: whether gpio
* is less than ngpios (that is specified in the gpio_chip).
*/
-int of_gpio_simple_xlate(struct of_gpio_chip *of_gc, struct device_node *np,
- const void *gpio_spec, enum of_gpio_flags *flags)
+static int of_gpio_simple_xlate(struct gpio_chip *gc, struct device_node *np,
+ const void *gpio_spec, u32 *flags)
{
const __be32 *gpio = gpio_spec;
const u32 n = be32_to_cpup(gpio);
@@ -137,12 +138,12 @@ int of_gpio_simple_xlate(struct of_gpio_chip *of_gc, struct device_node *np,
* number and the flags from a single gpio cell -- this is possible,
* but not recommended).
*/
- if (of_gc->gpio_cells < 2) {
+ if (gc->of_gpio_n_cells < 2) {
WARN_ON(1);
return -EINVAL;
}
- if (n > of_gc->gc.ngpio)
+ if (n > gc->ngpio)
return -EINVAL;
if (flags)
@@ -150,7 +151,6 @@ int of_gpio_simple_xlate(struct of_gpio_chip *of_gc, struct device_node *np,
return n;
}
-EXPORT_SYMBOL(of_gpio_simple_xlate);
/**
* of_mm_gpiochip_add - Add memory mapped GPIO chip (bank)
@@ -161,10 +161,8 @@ EXPORT_SYMBOL(of_gpio_simple_xlate);
*
* 1) In the gpio_chip structure:
* - all the callbacks
- *
- * 2) In the of_gpio_chip structure:
- * - gpio_cells
- * - xlate callback (optional)
+ * - of_gpio_n_cells
+ * - of_xlate callback (optional)
*
* 3) In the of_mm_gpio_chip structure:
* - save_regs callback (optional)
@@ -177,8 +175,7 @@ int of_mm_gpiochip_add(struct device_node *np,
struct of_mm_gpio_chip *mm_gc)
{
int ret = -ENOMEM;
- struct of_gpio_chip *of_gc = &mm_gc->of_gc;
- struct gpio_chip *gc = &of_gc->gc;
+ struct gpio_chip *gc = &mm_gc->gc;
gc->label = kstrdup(np->full_name, GFP_KERNEL);
if (!gc->label)
@@ -190,26 +187,19 @@ int of_mm_gpiochip_add(struct device_node *np,
gc->base = -1;
- if (!of_gc->xlate)
- of_gc->xlate = of_gpio_simple_xlate;
-
if (mm_gc->save_regs)
mm_gc->save_regs(mm_gc);
- np->data = of_gc;
+ mm_gc->gc.of_node = np;
ret = gpiochip_add(gc);
if (ret)
goto err2;
- /* We don't want to lose the node and its ->data */
- of_node_get(np);
-
pr_debug("%s: registered as generic GPIO chip, base is %d\n",
np->full_name, gc->base);
return 0;
err2:
- np->data = NULL;
iounmap(mm_gc->regs);
err1:
kfree(gc->label);
@@ -219,3 +209,36 @@ err0:
return ret;
}
EXPORT_SYMBOL(of_mm_gpiochip_add);
+
+void of_gpiochip_add(struct gpio_chip *chip)
+{
+ if ((!chip->of_node) && (chip->dev))
+ chip->of_node = chip->dev->of_node;
+
+ if (!chip->of_node)
+ return;
+
+ if (!chip->of_xlate) {
+ chip->of_gpio_n_cells = 2;
+ chip->of_xlate = of_gpio_simple_xlate;
+ }
+
+ of_node_get(chip->of_node);
+}
+
+void of_gpiochip_remove(struct gpio_chip *chip)
+{
+ if (chip->of_node)
+ of_node_put(chip->of_node);
+}
+
+/* Private function for resolving node pointer to gpio_chip */
+static int of_gpiochip_is_match(struct gpio_chip *chip, void *data)
+{
+ return chip->of_node == data;
+}
+
+struct gpio_chip *of_node_to_gpiochip(struct device_node *np)
+{
+ return gpiochip_find(np, of_gpiochip_is_match);
+}
diff --git a/drivers/of/irq.c b/drivers/of/irq.c
new file mode 100644
index 00000000000..6e595e5a397
--- /dev/null
+++ b/drivers/of/irq.c
@@ -0,0 +1,349 @@
+/*
+ * Derived from arch/i386/kernel/irq.c
+ * Copyright (C) 1992 Linus Torvalds
+ * Adapted from arch/i386 by Gary Thomas
+ * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
+ * Updated and modified by Cort Dougan <cort@fsmlabs.com>
+ * Copyright (C) 1996-2001 Cort Dougan
+ * Adapted for Power Macintosh by Paul Mackerras
+ * Copyright (C) 1996 Paul Mackerras (paulus@cs.anu.edu.au)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify 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 file contains the code used to make IRQ descriptions in the
+ * device tree to actual irq numbers on an interrupt controller
+ * driver.
+ */
+
+#include <linux/errno.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_irq.h>
+#include <linux/string.h>
+
+/**
+ * irq_of_parse_and_map - Parse and map an interrupt into linux virq space
+ * @device: Device node of the device whose interrupt is to be mapped
+ * @index: Index of the interrupt to map
+ *
+ * This function is a wrapper that chains of_irq_map_one() and
+ * irq_create_of_mapping() to make things easier to callers
+ */
+unsigned int irq_of_parse_and_map(struct device_node *dev, int index)
+{
+ struct of_irq oirq;
+
+ if (of_irq_map_one(dev, index, &oirq))
+ return NO_IRQ;
+
+ return irq_create_of_mapping(oirq.controller, oirq.specifier,
+ oirq.size);
+}
+EXPORT_SYMBOL_GPL(irq_of_parse_and_map);
+
+/**
+ * of_irq_find_parent - Given a device node, find its interrupt parent node
+ * @child: pointer to device node
+ *
+ * Returns a pointer to the interrupt parent node, or NULL if the interrupt
+ * parent could not be determined.
+ */
+static struct device_node *of_irq_find_parent(struct device_node *child)
+{
+ struct device_node *p;
+ const __be32 *parp;
+
+ if (!of_node_get(child))
+ return NULL;
+
+ do {
+ parp = of_get_property(child, "interrupt-parent", NULL);
+ if (parp == NULL)
+ p = of_get_parent(child);
+ else {
+ if (of_irq_workarounds & OF_IMAP_NO_PHANDLE)
+ p = of_node_get(of_irq_dflt_pic);
+ else
+ p = of_find_node_by_phandle(be32_to_cpup(parp));
+ }
+ of_node_put(child);
+ child = p;
+ } while (p && of_get_property(p, "#interrupt-cells", NULL) == NULL);
+
+ return p;
+}
+
+/**
+ * of_irq_map_raw - Low level interrupt tree parsing
+ * @parent: the device interrupt parent
+ * @intspec: interrupt specifier ("interrupts" property of the device)
+ * @ointsize: size of the passed in interrupt specifier
+ * @addr: address specifier (start of "reg" property of the device)
+ * @out_irq: structure of_irq filled by this function
+ *
+ * Returns 0 on success and a negative number on error
+ *
+ * This function is a low-level interrupt tree walking function. It
+ * can be used to do a partial walk with synthetized reg and interrupts
+ * properties, for example when resolving PCI interrupts when no device
+ * node exist for the parent.
+ */
+int of_irq_map_raw(struct device_node *parent, const __be32 *intspec,
+ u32 ointsize, const __be32 *addr, struct of_irq *out_irq)
+{
+ struct device_node *ipar, *tnode, *old = NULL, *newpar = NULL;
+ const __be32 *tmp, *imap, *imask;
+ u32 intsize = 1, addrsize, newintsize = 0, newaddrsize = 0;
+ int imaplen, match, i;
+
+ pr_debug("of_irq_map_raw: par=%s,intspec=[0x%08x 0x%08x...],ointsize=%d\n",
+ parent->full_name, be32_to_cpup(intspec),
+ be32_to_cpup(intspec + 1), ointsize);
+
+ ipar = of_node_get(parent);
+
+ /* First get the #interrupt-cells property of the current cursor
+ * that tells us how to interpret the passed-in intspec. If there
+ * is none, we are nice and just walk up the tree
+ */
+ do {
+ tmp = of_get_property(ipar, "#interrupt-cells", NULL);
+ if (tmp != NULL) {
+ intsize = be32_to_cpu(*tmp);
+ break;
+ }
+ tnode = ipar;
+ ipar = of_irq_find_parent(ipar);
+ of_node_put(tnode);
+ } while (ipar);
+ if (ipar == NULL) {
+ pr_debug(" -> no parent found !\n");
+ goto fail;
+ }
+
+ pr_debug("of_irq_map_raw: ipar=%s, size=%d\n", ipar->full_name, intsize);
+
+ if (ointsize != intsize)
+ return -EINVAL;
+
+ /* Look for this #address-cells. We have to implement the old linux
+ * trick of looking for the parent here as some device-trees rely on it
+ */
+ old = of_node_get(ipar);
+ do {
+ tmp = of_get_property(old, "#address-cells", NULL);
+ tnode = of_get_parent(old);
+ of_node_put(old);
+ old = tnode;
+ } while (old && tmp == NULL);
+ of_node_put(old);
+ old = NULL;
+ addrsize = (tmp == NULL) ? 2 : be32_to_cpu(*tmp);
+
+ pr_debug(" -> addrsize=%d\n", addrsize);
+
+ /* Now start the actual "proper" walk of the interrupt tree */
+ while (ipar != NULL) {
+ /* Now check if cursor is an interrupt-controller and if it is
+ * then we are done
+ */
+ if (of_get_property(ipar, "interrupt-controller", NULL) !=
+ NULL) {
+ pr_debug(" -> got it !\n");
+ for (i = 0; i < intsize; i++)
+ out_irq->specifier[i] =
+ of_read_number(intspec +i, 1);
+ out_irq->size = intsize;
+ out_irq->controller = ipar;
+ of_node_put(old);
+ return 0;
+ }
+
+ /* Now look for an interrupt-map */
+ imap = of_get_property(ipar, "interrupt-map", &imaplen);
+ /* No interrupt map, check for an interrupt parent */
+ if (imap == NULL) {
+ pr_debug(" -> no map, getting parent\n");
+ newpar = of_irq_find_parent(ipar);
+ goto skiplevel;
+ }
+ imaplen /= sizeof(u32);
+
+ /* Look for a mask */
+ imask = of_get_property(ipar, "interrupt-map-mask", NULL);
+
+ /* If we were passed no "reg" property and we attempt to parse
+ * an interrupt-map, then #address-cells must be 0.
+ * Fail if it's not.
+ */
+ if (addr == NULL && addrsize != 0) {
+ pr_debug(" -> no reg passed in when needed !\n");
+ goto fail;
+ }
+
+ /* Parse interrupt-map */
+ match = 0;
+ while (imaplen > (addrsize + intsize + 1) && !match) {
+ /* Compare specifiers */
+ match = 1;
+ for (i = 0; i < addrsize && match; ++i) {
+ u32 mask = imask ? imask[i] : 0xffffffffu;
+ match = ((addr[i] ^ imap[i]) & mask) == 0;
+ }
+ for (; i < (addrsize + intsize) && match; ++i) {
+ u32 mask = imask ? imask[i] : 0xffffffffu;
+ match =
+ ((intspec[i-addrsize] ^ imap[i]) & mask) == 0;
+ }
+ imap += addrsize + intsize;
+ imaplen -= addrsize + intsize;
+
+ pr_debug(" -> match=%d (imaplen=%d)\n", match, imaplen);
+
+ /* Get the interrupt parent */
+ if (of_irq_workarounds & OF_IMAP_NO_PHANDLE)
+ newpar = of_node_get(of_irq_dflt_pic);
+ else
+ newpar = of_find_node_by_phandle(be32_to_cpup(imap));
+ imap++;
+ --imaplen;
+
+ /* Check if not found */
+ if (newpar == NULL) {
+ pr_debug(" -> imap parent not found !\n");
+ goto fail;
+ }
+
+ /* Get #interrupt-cells and #address-cells of new
+ * parent
+ */
+ tmp = of_get_property(newpar, "#interrupt-cells", NULL);
+ if (tmp == NULL) {
+ pr_debug(" -> parent lacks #interrupt-cells!\n");
+ goto fail;
+ }
+ newintsize = be32_to_cpu(*tmp);
+ tmp = of_get_property(newpar, "#address-cells", NULL);
+ newaddrsize = (tmp == NULL) ? 0 : be32_to_cpu(*tmp);
+
+ pr_debug(" -> newintsize=%d, newaddrsize=%d\n",
+ newintsize, newaddrsize);
+
+ /* Check for malformed properties */
+ if (imaplen < (newaddrsize + newintsize))
+ goto fail;
+
+ imap += newaddrsize + newintsize;
+ imaplen -= newaddrsize + newintsize;
+
+ pr_debug(" -> imaplen=%d\n", imaplen);
+ }
+ if (!match)
+ goto fail;
+
+ of_node_put(old);
+ old = of_node_get(newpar);
+ addrsize = newaddrsize;
+ intsize = newintsize;
+ intspec = imap - intsize;
+ addr = intspec - addrsize;
+
+ skiplevel:
+ /* Iterate again with new parent */
+ pr_debug(" -> new parent: %s\n", newpar ? newpar->full_name : "<>");
+ of_node_put(ipar);
+ ipar = newpar;
+ newpar = NULL;
+ }
+ fail:
+ of_node_put(ipar);
+ of_node_put(old);
+ of_node_put(newpar);
+
+ return -EINVAL;
+}
+EXPORT_SYMBOL_GPL(of_irq_map_raw);
+
+/**
+ * of_irq_map_one - Resolve an interrupt for a device
+ * @device: the device whose interrupt is to be resolved
+ * @index: index of the interrupt to resolve
+ * @out_irq: structure of_irq filled by this function
+ *
+ * This function resolves an interrupt, walking the tree, for a given
+ * device-tree node. It's the high level pendant to of_irq_map_raw().
+ */
+int of_irq_map_one(struct device_node *device, int index, struct of_irq *out_irq)
+{
+ struct device_node *p;
+ const __be32 *intspec, *tmp, *addr;
+ u32 intsize, intlen;
+ int res = -EINVAL;
+
+ pr_debug("of_irq_map_one: dev=%s, index=%d\n", device->full_name, index);
+
+ /* OldWorld mac stuff is "special", handle out of line */
+ if (of_irq_workarounds & OF_IMAP_OLDWORLD_MAC)
+ return of_irq_map_oldworld(device, index, out_irq);
+
+ /* Get the interrupts property */
+ intspec = of_get_property(device, "interrupts", &intlen);
+ if (intspec == NULL)
+ return -EINVAL;
+ intlen /= sizeof(*intspec);
+
+ pr_debug(" intspec=%d intlen=%d\n", be32_to_cpup(intspec), intlen);
+
+ /* Get the reg property (if any) */
+ addr = of_get_property(device, "reg", NULL);
+
+ /* Look for the interrupt parent. */
+ p = of_irq_find_parent(device);
+ if (p == NULL)
+ return -EINVAL;
+
+ /* Get size of interrupt specifier */
+ tmp = of_get_property(p, "#interrupt-cells", NULL);
+ if (tmp == NULL)
+ goto out;
+ intsize = be32_to_cpu(*tmp);
+
+ pr_debug(" intsize=%d intlen=%d\n", intsize, intlen);
+
+ /* Check index */
+ if ((index + 1) * intsize > intlen)
+ goto out;
+
+ /* Get new specifier and map it */
+ res = of_irq_map_raw(p, intspec + index * intsize, intsize,
+ addr, out_irq);
+ out:
+ of_node_put(p);
+ return res;
+}
+EXPORT_SYMBOL_GPL(of_irq_map_one);
+
+/**
+ * of_irq_to_resource - Decode a node's IRQ and return it as a resource
+ * @dev: pointer to device tree node
+ * @index: zero-based index of the irq
+ * @r: pointer to resource structure to return result into.
+ */
+int of_irq_to_resource(struct device_node *dev, int index, struct resource *r)
+{
+ int irq = irq_of_parse_and_map(dev, index);
+
+ /* Only dereference the resource if both the
+ * resource and the irq are valid. */
+ if (r && irq != NO_IRQ) {
+ r->start = r->end = irq;
+ r->flags = IORESOURCE_IRQ;
+ r->name = dev->full_name;
+ }
+
+ return irq;
+}
+EXPORT_SYMBOL_GPL(of_irq_to_resource);
diff --git a/drivers/of/of_i2c.c b/drivers/of/of_i2c.c
index ab6522c8e4f..0a694debd22 100644
--- a/drivers/of/of_i2c.c
+++ b/drivers/of/of_i2c.c
@@ -14,57 +14,65 @@
#include <linux/i2c.h>
#include <linux/of.h>
#include <linux/of_i2c.h>
+#include <linux/of_irq.h>
#include <linux/module.h>
-void of_register_i2c_devices(struct i2c_adapter *adap,
- struct device_node *adap_node)
+void of_i2c_register_devices(struct i2c_adapter *adap)
{
void *result;
struct device_node *node;
- for_each_child_of_node(adap_node, node) {
+ /* Only register child devices if the adapter has a node pointer set */
+ if (!adap->dev.of_node)
+ return;
+
+ dev_dbg(&adap->dev, "of_i2c: walking child nodes\n");
+
+ for_each_child_of_node(adap->dev.of_node, node) {
struct i2c_board_info info = {};
struct dev_archdata dev_ad = {};
const __be32 *addr;
int len;
- if (of_modalias_node(node, info.type, sizeof(info.type)) < 0)
+ dev_dbg(&adap->dev, "of_i2c: register %s\n", node->full_name);
+
+ if (of_modalias_node(node, info.type, sizeof(info.type)) < 0) {
+ dev_err(&adap->dev, "of_i2c: modalias failure on %s\n",
+ node->full_name);
continue;
+ }
addr = of_get_property(node, "reg", &len);
- if (!addr || len < sizeof(int) || *addr > (1 << 10) - 1) {
- printk(KERN_ERR
- "of-i2c: invalid i2c device entry\n");
+ if (!addr || (len < sizeof(int))) {
+ dev_err(&adap->dev, "of_i2c: invalid reg on %s\n",
+ node->full_name);
continue;
}
- info.irq = irq_of_parse_and_map(node, 0);
-
info.addr = be32_to_cpup(addr);
+ if (info.addr > (1 << 10) - 1) {
+ dev_err(&adap->dev, "of_i2c: invalid addr=%x on %s\n",
+ info.addr, node->full_name);
+ continue;
+ }
- info.of_node = node;
+ info.irq = irq_of_parse_and_map(node, 0);
+ info.of_node = of_node_get(node);
info.archdata = &dev_ad;
request_module("%s", info.type);
result = i2c_new_device(adap, &info);
if (result == NULL) {
- printk(KERN_ERR
- "of-i2c: Failed to load driver for %s\n",
- info.type);
+ dev_err(&adap->dev, "of_i2c: Failure registering %s\n",
+ node->full_name);
+ of_node_put(node);
irq_dispose_mapping(info.irq);
continue;
}
-
- /*
- * Get the node to not lose the dev_archdata->of_node.
- * Currently there is no way to put it back, as well as no
- * of_unregister_i2c_devices() call.
- */
- of_node_get(node);
}
}
-EXPORT_SYMBOL(of_register_i2c_devices);
+EXPORT_SYMBOL(of_i2c_register_devices);
static int of_dev_node_match(struct device *dev, void *data)
{
diff --git a/drivers/of/of_mdio.c b/drivers/of/of_mdio.c
index 42a6715f8e8..1fce00eb421 100644
--- a/drivers/of/of_mdio.c
+++ b/drivers/of/of_mdio.c
@@ -15,6 +15,7 @@
#include <linux/err.h>
#include <linux/phy.h>
#include <linux/of.h>
+#include <linux/of_irq.h>
#include <linux/of_mdio.h>
#include <linux/module.h>
diff --git a/drivers/of/of_spi.c b/drivers/of/of_spi.c
index 5fed7e3c7da..1dbce58a58b 100644
--- a/drivers/of/of_spi.c
+++ b/drivers/of/of_spi.c
@@ -9,17 +9,17 @@
#include <linux/of.h>
#include <linux/device.h>
#include <linux/spi/spi.h>
+#include <linux/of_irq.h>
#include <linux/of_spi.h>
/**
* of_register_spi_devices - Register child devices onto the SPI bus
* @master: Pointer to spi_master device
- * @np: parent node of SPI device nodes
*
- * Registers an spi_device for each child node of 'np' which has a 'reg'
+ * Registers an spi_device for each child node of master node which has a 'reg'
* property.
*/
-void of_register_spi_devices(struct spi_master *master, struct device_node *np)
+void of_register_spi_devices(struct spi_master *master)
{
struct spi_device *spi;
struct device_node *nc;
@@ -27,7 +27,10 @@ void of_register_spi_devices(struct spi_master *master, struct device_node *np)
int rc;
int len;
- for_each_child_of_node(np, nc) {
+ if (!master->dev.of_node)
+ return;
+
+ for_each_child_of_node(master->dev.of_node, nc) {
/* Alloc an spi_device */
spi = spi_alloc_device(master);
if (!spi) {
diff --git a/drivers/of/platform.c b/drivers/of/platform.c
index 7dacc1ebe91..bb72223c22a 100644
--- a/drivers/of/platform.c
+++ b/drivers/of/platform.c
@@ -14,8 +14,105 @@
#include <linux/errno.h>
#include <linux/module.h>
#include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include <linux/slab.h>
+#include <linux/of_address.h>
#include <linux/of_device.h>
+#include <linux/of_irq.h>
#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+
+static int of_dev_node_match(struct device *dev, void *data)
+{
+ return dev->of_node == data;
+}
+
+/**
+ * of_find_device_by_node - Find the platform_device associated with a node
+ * @np: Pointer to device tree node
+ *
+ * Returns platform_device pointer, or NULL if not found
+ */
+struct platform_device *of_find_device_by_node(struct device_node *np)
+{
+ struct device *dev;
+
+ dev = bus_find_device(&platform_bus_type, NULL, np, of_dev_node_match);
+ return dev ? to_platform_device(dev) : NULL;
+}
+EXPORT_SYMBOL(of_find_device_by_node);
+
+static int platform_driver_probe_shim(struct platform_device *pdev)
+{
+ struct platform_driver *pdrv;
+ struct of_platform_driver *ofpdrv;
+ const struct of_device_id *match;
+
+ pdrv = container_of(pdev->dev.driver, struct platform_driver, driver);
+ ofpdrv = container_of(pdrv, struct of_platform_driver, platform_driver);
+
+ /* There is an unlikely chance that an of_platform driver might match
+ * on a non-OF platform device. If so, then of_match_device() will
+ * come up empty. Return -EINVAL in this case so other drivers get
+ * the chance to bind. */
+ match = of_match_device(pdev->dev.driver->of_match_table, &pdev->dev);
+ return match ? ofpdrv->probe(pdev, match) : -EINVAL;
+}
+
+static void platform_driver_shutdown_shim(struct platform_device *pdev)
+{
+ struct platform_driver *pdrv;
+ struct of_platform_driver *ofpdrv;
+
+ pdrv = container_of(pdev->dev.driver, struct platform_driver, driver);
+ ofpdrv = container_of(pdrv, struct of_platform_driver, platform_driver);
+ ofpdrv->shutdown(pdev);
+}
+
+/**
+ * of_register_platform_driver
+ */
+int of_register_platform_driver(struct of_platform_driver *drv)
+{
+ char *of_name;
+
+ /* setup of_platform_driver to platform_driver adaptors */
+ drv->platform_driver.driver = drv->driver;
+
+ /* Prefix the driver name with 'of:' to avoid namespace collisions
+ * and bogus matches. There are some drivers in the tree that
+ * register both an of_platform_driver and a platform_driver with
+ * the same name. This is a temporary measure until they are all
+ * cleaned up --gcl July 29, 2010 */
+ of_name = kmalloc(strlen(drv->driver.name) + 5, GFP_KERNEL);
+ if (!of_name)
+ return -ENOMEM;
+ sprintf(of_name, "of:%s", drv->driver.name);
+ drv->platform_driver.driver.name = of_name;
+
+ if (drv->probe)
+ drv->platform_driver.probe = platform_driver_probe_shim;
+ drv->platform_driver.remove = drv->remove;
+ if (drv->shutdown)
+ drv->platform_driver.shutdown = platform_driver_shutdown_shim;
+ drv->platform_driver.suspend = drv->suspend;
+ drv->platform_driver.resume = drv->resume;
+
+ return platform_driver_register(&drv->platform_driver);
+}
+EXPORT_SYMBOL(of_register_platform_driver);
+
+void of_unregister_platform_driver(struct of_platform_driver *drv)
+{
+ platform_driver_unregister(&drv->platform_driver);
+ kfree(drv->platform_driver.driver.name);
+ drv->platform_driver.driver.name = NULL;
+}
+EXPORT_SYMBOL(of_unregister_platform_driver);
+
+#if defined(CONFIG_PPC_DCR)
+#include <asm/dcr.h>
+#endif
extern struct device_attribute of_platform_device_attrs[];
@@ -33,11 +130,11 @@ static int of_platform_device_probe(struct device *dev)
{
int error = -ENODEV;
struct of_platform_driver *drv;
- struct of_device *of_dev;
+ struct platform_device *of_dev;
const struct of_device_id *match;
drv = to_of_platform_driver(dev->driver);
- of_dev = to_of_device(dev);
+ of_dev = to_platform_device(dev);
if (!drv->probe)
return error;
@@ -55,7 +152,7 @@ static int of_platform_device_probe(struct device *dev)
static int of_platform_device_remove(struct device *dev)
{
- struct of_device *of_dev = to_of_device(dev);
+ struct platform_device *of_dev = to_platform_device(dev);
struct of_platform_driver *drv = to_of_platform_driver(dev->driver);
if (dev->driver && drv->remove)
@@ -65,7 +162,7 @@ static int of_platform_device_remove(struct device *dev)
static void of_platform_device_shutdown(struct device *dev)
{
- struct of_device *of_dev = to_of_device(dev);
+ struct platform_device *of_dev = to_platform_device(dev);
struct of_platform_driver *drv = to_of_platform_driver(dev->driver);
if (dev->driver && drv->shutdown)
@@ -76,7 +173,7 @@ static void of_platform_device_shutdown(struct device *dev)
static int of_platform_legacy_suspend(struct device *dev, pm_message_t mesg)
{
- struct of_device *of_dev = to_of_device(dev);
+ struct platform_device *of_dev = to_platform_device(dev);
struct of_platform_driver *drv = to_of_platform_driver(dev->driver);
int ret = 0;
@@ -87,7 +184,7 @@ static int of_platform_legacy_suspend(struct device *dev, pm_message_t mesg)
static int of_platform_legacy_resume(struct device *dev)
{
- struct of_device *of_dev = to_of_device(dev);
+ struct platform_device *of_dev = to_platform_device(dev);
struct of_platform_driver *drv = to_of_platform_driver(dev->driver);
int ret = 0;
@@ -384,15 +481,286 @@ int of_bus_type_init(struct bus_type *bus, const char *name)
int of_register_driver(struct of_platform_driver *drv, struct bus_type *bus)
{
- drv->driver.bus = bus;
+ /*
+ * Temporary: of_platform_bus used to be distinct from the platform
+ * bus. It isn't anymore, and so drivers on the platform bus need
+ * to be registered in a special way.
+ *
+ * After all of_platform_bus_type drivers are converted to
+ * platform_drivers, this exception can be removed.
+ */
+ if (bus == &platform_bus_type)
+ return of_register_platform_driver(drv);
/* register with core */
+ drv->driver.bus = bus;
return driver_register(&drv->driver);
}
EXPORT_SYMBOL(of_register_driver);
void of_unregister_driver(struct of_platform_driver *drv)
{
- driver_unregister(&drv->driver);
+ if (drv->driver.bus == &platform_bus_type)
+ of_unregister_platform_driver(drv);
+ else
+ driver_unregister(&drv->driver);
}
EXPORT_SYMBOL(of_unregister_driver);
+
+#if !defined(CONFIG_SPARC)
+/*
+ * The following routines scan a subtree and registers a device for
+ * each applicable node.
+ *
+ * Note: sparc doesn't use these routines because it has a different
+ * mechanism for creating devices from device tree nodes.
+ */
+
+/**
+ * of_device_make_bus_id - Use the device node data to assign a unique name
+ * @dev: pointer to device structure that is linked to a device tree node
+ *
+ * This routine will first try using either the dcr-reg or the reg property
+ * value to derive a unique name. As a last resort it will use the node
+ * name followed by a unique number.
+ */
+void of_device_make_bus_id(struct device *dev)
+{
+ static atomic_t bus_no_reg_magic;
+ struct device_node *node = dev->of_node;
+ const u32 *reg;
+ u64 addr;
+ int magic;
+
+#ifdef CONFIG_PPC_DCR
+ /*
+ * If it's a DCR based device, use 'd' for native DCRs
+ * and 'D' for MMIO DCRs.
+ */
+ reg = of_get_property(node, "dcr-reg", NULL);
+ if (reg) {
+#ifdef CONFIG_PPC_DCR_NATIVE
+ dev_set_name(dev, "d%x.%s", *reg, node->name);
+#else /* CONFIG_PPC_DCR_NATIVE */
+ u64 addr = of_translate_dcr_address(node, *reg, NULL);
+ if (addr != OF_BAD_ADDR) {
+ dev_set_name(dev, "D%llx.%s",
+ (unsigned long long)addr, node->name);
+ return;
+ }
+#endif /* !CONFIG_PPC_DCR_NATIVE */
+ }
+#endif /* CONFIG_PPC_DCR */
+
+ /*
+ * For MMIO, get the physical address
+ */
+ reg = of_get_property(node, "reg", NULL);
+ if (reg) {
+ addr = of_translate_address(node, reg);
+ if (addr != OF_BAD_ADDR) {
+ dev_set_name(dev, "%llx.%s",
+ (unsigned long long)addr, node->name);
+ return;
+ }
+ }
+
+ /*
+ * No BusID, use the node name and add a globally incremented
+ * counter (and pray...)
+ */
+ magic = atomic_add_return(1, &bus_no_reg_magic);
+ dev_set_name(dev, "%s.%d", node->name, magic - 1);
+}
+
+/**
+ * of_device_alloc - Allocate and initialize an of_device
+ * @np: device node to assign to device
+ * @bus_id: Name to assign to the device. May be null to use default name.
+ * @parent: Parent device.
+ */
+struct platform_device *of_device_alloc(struct device_node *np,
+ const char *bus_id,
+ struct device *parent)
+{
+ struct platform_device *dev;
+ int rc, i, num_reg = 0, num_irq = 0;
+ struct resource *res, temp_res;
+
+ /* First count how many resources are needed */
+ while (of_address_to_resource(np, num_reg, &temp_res) == 0)
+ num_reg++;
+ while (of_irq_to_resource(np, num_irq, &temp_res) != NO_IRQ)
+ num_irq++;
+
+ /* Allocate memory for both the struct device and the resource table */
+ dev = kzalloc(sizeof(*dev) + (sizeof(*res) * (num_reg + num_irq)),
+ GFP_KERNEL);
+ if (!dev)
+ return NULL;
+ res = (struct resource *) &dev[1];
+
+ /* Populate the resource table */
+ if (num_irq || num_reg) {
+ dev->num_resources = num_reg + num_irq;
+ dev->resource = res;
+ for (i = 0; i < num_reg; i++, res++) {
+ rc = of_address_to_resource(np, i, res);
+ WARN_ON(rc);
+ }
+ for (i = 0; i < num_irq; i++, res++) {
+ rc = of_irq_to_resource(np, i, res);
+ WARN_ON(rc == NO_IRQ);
+ }
+ }
+
+ dev->dev.of_node = of_node_get(np);
+#if defined(CONFIG_PPC) || defined(CONFIG_MICROBLAZE)
+ dev->dev.dma_mask = &dev->archdata.dma_mask;
+#endif
+ dev->dev.parent = parent;
+ dev->dev.release = of_release_dev;
+
+ if (bus_id)
+ dev_set_name(&dev->dev, "%s", bus_id);
+ else
+ of_device_make_bus_id(&dev->dev);
+
+ return dev;
+}
+EXPORT_SYMBOL(of_device_alloc);
+
+/**
+ * of_platform_device_create - Alloc, initialize and register an of_device
+ * @np: pointer to node to create device for
+ * @bus_id: name to assign device
+ * @parent: Linux device model parent device.
+ */
+struct platform_device *of_platform_device_create(struct device_node *np,
+ const char *bus_id,
+ struct device *parent)
+{
+ struct platform_device *dev;
+
+ dev = of_device_alloc(np, bus_id, parent);
+ if (!dev)
+ return NULL;
+
+#if defined(CONFIG_PPC) || defined(CONFIG_MICROBLAZE)
+ dev->archdata.dma_mask = 0xffffffffUL;
+#endif
+ dev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
+ dev->dev.bus = &platform_bus_type;
+
+ /* We do not fill the DMA ops for platform devices by default.
+ * This is currently the responsibility of the platform code
+ * to do such, possibly using a device notifier
+ */
+
+ if (of_device_register(dev) != 0) {
+ of_device_free(dev);
+ return NULL;
+ }
+
+ return dev;
+}
+EXPORT_SYMBOL(of_platform_device_create);
+
+/**
+ * of_platform_bus_create - Create an OF device for a bus node and all its
+ * children. Optionally recursively instantiate matching busses.
+ * @bus: device node of the bus to instantiate
+ * @matches: match table, NULL to use the default, OF_NO_DEEP_PROBE to
+ * disallow recursive creation of child busses
+ */
+static int of_platform_bus_create(const struct device_node *bus,
+ const struct of_device_id *matches,
+ struct device *parent)
+{
+ struct device_node *child;
+ struct platform_device *dev;
+ int rc = 0;
+
+ for_each_child_of_node(bus, child) {
+ pr_debug(" create child: %s\n", child->full_name);
+ dev = of_platform_device_create(child, NULL, parent);
+ if (dev == NULL)
+ rc = -ENOMEM;
+ else if (!of_match_node(matches, child))
+ continue;
+ if (rc == 0) {
+ pr_debug(" and sub busses\n");
+ rc = of_platform_bus_create(child, matches, &dev->dev);
+ }
+ if (rc) {
+ of_node_put(child);
+ break;
+ }
+ }
+ return rc;
+}
+
+/**
+ * of_platform_bus_probe - Probe the device-tree for platform busses
+ * @root: parent of the first level to probe or NULL for the root of the tree
+ * @matches: match table, NULL to use the default
+ * @parent: parent to hook devices from, NULL for toplevel
+ *
+ * Note that children of the provided root are not instantiated as devices
+ * unless the specified root itself matches the bus list and is not NULL.
+ */
+int of_platform_bus_probe(struct device_node *root,
+ const struct of_device_id *matches,
+ struct device *parent)
+{
+ struct device_node *child;
+ struct platform_device *dev;
+ int rc = 0;
+
+ if (WARN_ON(!matches || matches == OF_NO_DEEP_PROBE))
+ return -EINVAL;
+ if (root == NULL)
+ root = of_find_node_by_path("/");
+ else
+ of_node_get(root);
+ if (root == NULL)
+ return -EINVAL;
+
+ pr_debug("of_platform_bus_probe()\n");
+ pr_debug(" starting at: %s\n", root->full_name);
+
+ /* Do a self check of bus type, if there's a match, create
+ * children
+ */
+ if (of_match_node(matches, root)) {
+ pr_debug(" root match, create all sub devices\n");
+ dev = of_platform_device_create(root, NULL, parent);
+ if (dev == NULL) {
+ rc = -ENOMEM;
+ goto bail;
+ }
+ pr_debug(" create all sub busses\n");
+ rc = of_platform_bus_create(root, matches, &dev->dev);
+ goto bail;
+ }
+ for_each_child_of_node(root, child) {
+ if (!of_match_node(matches, child))
+ continue;
+
+ pr_debug(" match: %s\n", child->full_name);
+ dev = of_platform_device_create(child, NULL, parent);
+ if (dev == NULL)
+ rc = -ENOMEM;
+ else
+ rc = of_platform_bus_create(child, matches, &dev->dev);
+ if (rc) {
+ of_node_put(child);
+ break;
+ }
+ }
+ bail:
+ of_node_put(root);
+ return rc;
+}
+EXPORT_SYMBOL(of_platform_bus_probe);
+#endif /* !CONFIG_SPARC */
diff --git a/drivers/oprofile/event_buffer.c b/drivers/oprofile/event_buffer.c
index 5df60a6b677..dd87e86048b 100644
--- a/drivers/oprofile/event_buffer.c
+++ b/drivers/oprofile/event_buffer.c
@@ -135,7 +135,7 @@ static int event_buffer_open(struct inode *inode, struct file *file)
* echo 1 >/dev/oprofile/enable
*/
- return 0;
+ return nonseekable_open(inode, file);
fail:
dcookie_unregister(file->private_data);
@@ -205,4 +205,5 @@ const struct file_operations event_buffer_fops = {
.open = event_buffer_open,
.release = event_buffer_release,
.read = event_buffer_read,
+ .llseek = no_llseek,
};
diff --git a/drivers/parisc/ccio-dma.c b/drivers/parisc/ccio-dma.c
index f511e70d454..75a80e46b39 100644
--- a/drivers/parisc/ccio-dma.c
+++ b/drivers/parisc/ccio-dma.c
@@ -1241,10 +1241,10 @@ static struct parisc_driver ccio_driver = {
};
/**
- * ccio_ioc_init - Initalize the I/O Controller
+ * ccio_ioc_init - Initialize the I/O Controller
* @ioc: The I/O Controller.
*
- * Initalize the I/O Controller which includes setting up the
+ * Initialize the I/O Controller which includes setting up the
* I/O Page Directory, the resource map, and initalizing the
* U2/Uturn chip into virtual mode.
*/
diff --git a/drivers/parisc/led.c b/drivers/parisc/led.c
index d02be78a413..c5c14dd3734 100644
--- a/drivers/parisc/led.c
+++ b/drivers/parisc/led.c
@@ -357,12 +357,13 @@ static __inline__ int led_get_net_activity(void)
rcu_read_lock();
for_each_netdev_rcu(&init_net, dev) {
const struct net_device_stats *stats;
+ struct rtnl_link_stats64 temp;
struct in_device *in_dev = __in_dev_get_rcu(dev);
if (!in_dev || !in_dev->ifa_list)
continue;
if (ipv4_is_loopback(in_dev->ifa_list->ifa_local))
continue;
- stats = dev_get_stats(dev);
+ stats = dev_get_stats(dev, &temp);
rx_total += stats->rx_packets;
tx_total += stats->tx_packets;
}
diff --git a/drivers/parport/parport_cs.c b/drivers/parport/parport_cs.c
index fd8cfe95f0a..23e50f4a27c 100644
--- a/drivers/parport/parport_cs.c
+++ b/drivers/parport/parport_cs.c
@@ -48,7 +48,6 @@
#include <linux/parport.h>
#include <linux/parport_pc.h>
-#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/cistpl.h>
#include <pcmcia/ds.h>
@@ -102,8 +101,8 @@ static int parport_probe(struct pcmcia_device *link)
link->priv = info;
info->p_dev = link;
- link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
- link->io.Attributes2 = IO_DATA_PATH_WIDTH_8;
+ link->resource[0]->flags |= IO_DATA_PATH_WIDTH_8;
+ link->resource[1]->flags |= IO_DATA_PATH_WIDTH_8;
link->conf.Attributes = CONF_ENABLE_IRQ;
link->conf.IntType = INT_MEMORY_AND_IO;
@@ -144,16 +143,16 @@ static int parport_config_check(struct pcmcia_device *p_dev,
{
if ((cfg->io.nwin > 0) || (dflt->io.nwin > 0)) {
cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt->io;
+ p_dev->io_lines = io->flags & CISTPL_IO_LINES_MASK;
if (epp_mode)
p_dev->conf.ConfigIndex |= FORCE_EPP_MODE;
- p_dev->io.BasePort1 = io->win[0].base;
- p_dev->io.NumPorts1 = io->win[0].len;
- p_dev->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK;
+ p_dev->resource[0]->start = io->win[0].base;
+ p_dev->resource[0]->end = io->win[0].len;
if (io->nwin == 2) {
- p_dev->io.BasePort2 = io->win[1].base;
- p_dev->io.NumPorts2 = io->win[1].len;
+ p_dev->resource[1]->start = io->win[1].base;
+ p_dev->resource[1]->end = io->win[1].len;
}
- if (pcmcia_request_io(p_dev, &p_dev->io) != 0)
+ if (pcmcia_request_io(p_dev) != 0)
return -ENODEV;
return 0;
}
@@ -178,12 +177,14 @@ static int parport_config(struct pcmcia_device *link)
if (ret)
goto failed;
- p = parport_pc_probe_port(link->io.BasePort1, link->io.BasePort2,
+ p = parport_pc_probe_port(link->resource[0]->start,
+ link->resource[1]->start,
link->irq, PARPORT_DMA_NONE,
&link->dev, IRQF_SHARED);
if (p == NULL) {
printk(KERN_NOTICE "parport_cs: parport_pc_probe_port() at "
- "0x%3x, irq %u failed\n", link->io.BasePort1,
+ "0x%3x, irq %u failed\n",
+ (unsigned int) link->resource[0]->start,
link->irq);
goto failed;
}
diff --git a/drivers/parport/parport_sunbpp.c b/drivers/parport/parport_sunbpp.c
index 9a5b4b89416..210a6441a06 100644
--- a/drivers/parport/parport_sunbpp.c
+++ b/drivers/parport/parport_sunbpp.c
@@ -295,7 +295,7 @@ static int __devinit bpp_probe(struct of_device *op, const struct of_device_id *
void __iomem *base;
struct parport *p;
- irq = op->irqs[0];
+ irq = op->archdata.irqs[0];
base = of_ioremap(&op->resource[0], 0,
resource_size(&op->resource[0]),
"sunbpp");
@@ -393,12 +393,12 @@ static struct of_platform_driver bpp_sbus_driver = {
static int __init parport_sunbpp_init(void)
{
- return of_register_driver(&bpp_sbus_driver, &of_bus_type);
+ return of_register_platform_driver(&bpp_sbus_driver);
}
static void __exit parport_sunbpp_exit(void)
{
- of_unregister_driver(&bpp_sbus_driver);
+ of_unregister_platform_driver(&bpp_sbus_driver);
}
MODULE_AUTHOR("Derrick J Brashear");
diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile
index 0b51857fbaf..dc1aa092286 100644
--- a/drivers/pci/Makefile
+++ b/drivers/pci/Makefile
@@ -55,6 +55,9 @@ obj-$(CONFIG_MICROBLAZE) += setup-bus.o
#
obj-$(CONFIG_ACPI) += pci-acpi.o
+# SMBIOS provided firmware instance and labels
+obj-$(CONFIG_DMI) += pci-label.o
+
# Cardbus & CompactPCI use setup-bus
obj-$(CONFIG_HOTPLUG) += setup-bus.o
diff --git a/drivers/pci/bus.c b/drivers/pci/bus.c
index 628ea20a884..7f0af0e9b82 100644
--- a/drivers/pci/bus.c
+++ b/drivers/pci/bus.c
@@ -56,7 +56,7 @@ void pci_bus_remove_resources(struct pci_bus *bus)
int i;
for (i = 0; i < PCI_BRIDGE_RESOURCE_NUM; i++)
- bus->resource[i] = 0;
+ bus->resource[i] = NULL;
list_for_each_entry_safe(bus_res, tmp, &bus->resources, list) {
list_del(&bus_res->list);
@@ -240,6 +240,8 @@ void pci_enable_bridges(struct pci_bus *bus)
if (dev->subordinate) {
if (!pci_is_enabled(dev)) {
retval = pci_enable_device(dev);
+ if (retval)
+ dev_err(&dev->dev, "Error enabling bridge (%d), continuing\n", retval);
pci_set_master(dev);
}
pci_enable_bridges(dev->subordinate);
diff --git a/drivers/pci/hotplug/fakephp.c b/drivers/pci/hotplug/fakephp.c
index 5317e4d7d96..17d10e2e8fb 100644
--- a/drivers/pci/hotplug/fakephp.c
+++ b/drivers/pci/hotplug/fakephp.c
@@ -135,7 +135,7 @@ static int __init init_legacy(void)
struct pci_dev *pdev = NULL;
/* Add existing devices */
- while ((pdev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, pdev)))
+ for_each_pci_dev(pdev)
legacy_add_slot(pdev);
/* Be alerted of any new ones */
diff --git a/drivers/pci/hotplug/pciehp_pci.c b/drivers/pci/hotplug/pciehp_pci.c
index 2fce726758d..a4031dfe938 100644
--- a/drivers/pci/hotplug/pciehp_pci.c
+++ b/drivers/pci/hotplug/pciehp_pci.c
@@ -137,7 +137,7 @@ int pciehp_unconfigure_device(struct slot *p_slot)
"Cannot remove display device %s\n",
pci_name(temp));
pci_dev_put(temp);
- rc = EINVAL;
+ rc = -EINVAL;
break;
}
}
diff --git a/drivers/pci/hotplug/shpchp_hpc.c b/drivers/pci/hotplug/shpchp_hpc.c
index 5f5e8d2e355..d3985e7deab 100644
--- a/drivers/pci/hotplug/shpchp_hpc.c
+++ b/drivers/pci/hotplug/shpchp_hpc.c
@@ -113,7 +113,7 @@
#define CON_PFAULT_INTR_MASK (1 << 28)
#define MRL_CHANGE_SERR_MASK (1 << 29)
#define CON_PFAULT_SERR_MASK (1 << 30)
-#define SLOT_REG_RSVDZ_MASK (1 << 15) | (7 << 21)
+#define SLOT_REG_RSVDZ_MASK ((1 << 15) | (7 << 21))
/*
* SHPC Command Code definitnions
diff --git a/drivers/pci/hotplug/shpchp_pci.c b/drivers/pci/hotplug/shpchp_pci.c
index 8c3d3219f22..a2ccfcd3c29 100644
--- a/drivers/pci/hotplug/shpchp_pci.c
+++ b/drivers/pci/hotplug/shpchp_pci.c
@@ -60,12 +60,6 @@ int __ref shpchp_configure_device(struct slot *p_slot)
dev = pci_get_slot(parent, PCI_DEVFN(p_slot->device, fn));
if (!dev)
continue;
- if ((dev->class >> 16) == PCI_BASE_CLASS_DISPLAY) {
- ctrl_err(ctrl, "Cannot hot-add display device %s\n",
- pci_name(dev));
- pci_dev_put(dev);
- continue;
- }
if ((dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) ||
(dev->hdr_type == PCI_HEADER_TYPE_CARDBUS)) {
/* Find an unused bus number for the new bridge */
@@ -114,17 +108,11 @@ int shpchp_unconfigure_device(struct slot *p_slot)
ctrl_dbg(ctrl, "%s: domain:bus:dev = %04x:%02x:%02x\n",
__func__, pci_domain_nr(parent), p_slot->bus, p_slot->device);
- for (j=0; j<8 ; j++) {
- struct pci_dev* temp = pci_get_slot(parent,
+ for (j = 0; j < 8 ; j++) {
+ struct pci_dev *temp = pci_get_slot(parent,
(p_slot->device << 3) | j);
if (!temp)
continue;
- if ((temp->class >> 16) == PCI_BASE_CLASS_DISPLAY) {
- ctrl_err(ctrl, "Cannot remove display device %s\n",
- pci_name(temp));
- pci_dev_put(temp);
- continue;
- }
if (temp->hdr_type == PCI_HEADER_TYPE_BRIDGE) {
pci_read_config_byte(temp, PCI_BRIDGE_CONTROL, &bctl);
if (bctl & PCI_BRIDGE_CTL_VGA) {
@@ -132,7 +120,8 @@ int shpchp_unconfigure_device(struct slot *p_slot)
"Cannot remove display device %s\n",
pci_name(temp));
pci_dev_put(temp);
- continue;
+ rc = -EINVAL;
+ break;
}
}
pci_remove_bus_device(temp);
diff --git a/drivers/pci/intel-iommu.c b/drivers/pci/intel-iommu.c
index c9171be7456..6a5af18faf6 100644
--- a/drivers/pci/intel-iommu.c
+++ b/drivers/pci/intel-iommu.c
@@ -3698,6 +3698,8 @@ static int intel_iommu_domain_has_cap(struct iommu_domain *domain,
if (cap == IOMMU_CAP_CACHE_COHERENCY)
return dmar_domain->iommu_snooping;
+ if (cap == IOMMU_CAP_INTR_REMAP)
+ return intr_remapping_enabled;
return 0;
}
diff --git a/drivers/pci/intr_remapping.c b/drivers/pci/intr_remapping.c
index 1315ac688aa..1694a0e2845 100644
--- a/drivers/pci/intr_remapping.c
+++ b/drivers/pci/intr_remapping.c
@@ -311,8 +311,8 @@ int modify_irte(int irq, struct irte *irte_modified)
index = irq_iommu->irte_index + irq_iommu->sub_handle;
irte = &iommu->ir_table->base[index];
- set_64bit((unsigned long *)&irte->low, irte_modified->low);
- set_64bit((unsigned long *)&irte->high, irte_modified->high);
+ set_64bit(&irte->low, irte_modified->low);
+ set_64bit(&irte->high, irte_modified->high);
__iommu_flush_cache(iommu, irte, sizeof(*irte));
rc = qi_flush_iec(iommu, index, 0);
@@ -393,8 +393,8 @@ static int clear_entries(struct irq_2_iommu *irq_iommu)
end = start + (1 << irq_iommu->irte_mask);
for (entry = start; entry < end; entry++) {
- set_64bit((unsigned long *)&entry->low, 0);
- set_64bit((unsigned long *)&entry->high, 0);
+ set_64bit(&entry->low, 0);
+ set_64bit(&entry->high, 0);
}
return qi_flush_iec(iommu, index, irq_iommu->irte_mask);
diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c
index 77b68eaf021..69b7be33b3a 100644
--- a/drivers/pci/msi.c
+++ b/drivers/pci/msi.c
@@ -196,6 +196,9 @@ void unmask_msi_irq(unsigned int irq)
void read_msi_msg_desc(struct irq_desc *desc, struct msi_msg *msg)
{
struct msi_desc *entry = get_irq_desc_msi(desc);
+
+ BUG_ON(entry->dev->current_state != PCI_D0);
+
if (entry->msi_attrib.is_msix) {
void __iomem *base = entry->mask_base +
entry->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE;
@@ -229,10 +232,32 @@ void read_msi_msg(unsigned int irq, struct msi_msg *msg)
read_msi_msg_desc(desc, msg);
}
+void get_cached_msi_msg_desc(struct irq_desc *desc, struct msi_msg *msg)
+{
+ struct msi_desc *entry = get_irq_desc_msi(desc);
+
+ /* Assert that the cache is valid, assuming that
+ * valid messages are not all-zeroes. */
+ BUG_ON(!(entry->msg.address_hi | entry->msg.address_lo |
+ entry->msg.data));
+
+ *msg = entry->msg;
+}
+
+void get_cached_msi_msg(unsigned int irq, struct msi_msg *msg)
+{
+ struct irq_desc *desc = irq_to_desc(irq);
+
+ get_cached_msi_msg_desc(desc, msg);
+}
+
void write_msi_msg_desc(struct irq_desc *desc, struct msi_msg *msg)
{
struct msi_desc *entry = get_irq_desc_msi(desc);
- if (entry->msi_attrib.is_msix) {
+
+ if (entry->dev->current_state != PCI_D0) {
+ /* Don't touch the hardware now */
+ } else if (entry->msi_attrib.is_msix) {
void __iomem *base;
base = entry->mask_base +
entry->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE;
@@ -435,7 +460,7 @@ static int msi_capability_init(struct pci_dev *dev, int nvec)
static void __iomem *msix_map_region(struct pci_dev *dev, unsigned pos,
unsigned nr_entries)
{
- unsigned long phys_addr;
+ resource_size_t phys_addr;
u32 table_offset;
u8 bir;
diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c
index 2e7a3bf1382..24e19c594e5 100644
--- a/drivers/pci/pci-acpi.c
+++ b/drivers/pci/pci-acpi.c
@@ -48,6 +48,7 @@ static void pci_acpi_wake_dev(acpi_handle handle, u32 event, void *context)
if (event == ACPI_NOTIFY_DEVICE_WAKE && pci_dev) {
pci_check_pme_status(pci_dev);
pm_runtime_resume(&pci_dev->dev);
+ pci_wakeup_event(pci_dev);
if (pci_dev->subordinate)
pci_pme_wakeup_bus(pci_dev->subordinate);
}
@@ -295,14 +296,12 @@ static int acpi_dev_run_wake(struct device *phys_dev, bool enable)
if (!dev->wakeup.run_wake_count++) {
acpi_enable_wakeup_device_power(dev, ACPI_STATE_S0);
acpi_enable_gpe(dev->wakeup.gpe_device,
- dev->wakeup.gpe_number,
- ACPI_GPE_TYPE_RUNTIME);
+ dev->wakeup.gpe_number);
}
} else if (dev->wakeup.run_wake_count > 0) {
if (!--dev->wakeup.run_wake_count) {
acpi_disable_gpe(dev->wakeup.gpe_device,
- dev->wakeup.gpe_number,
- ACPI_GPE_TYPE_RUNTIME);
+ dev->wakeup.gpe_number);
acpi_disable_wakeup_device_power(dev);
}
} else {
diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c
index f9a0aec3abc..8a6f797de8e 100644
--- a/drivers/pci/pci-driver.c
+++ b/drivers/pci/pci-driver.c
@@ -289,8 +289,26 @@ struct drv_dev_and_id {
static long local_pci_probe(void *_ddi)
{
struct drv_dev_and_id *ddi = _ddi;
-
- return ddi->drv->probe(ddi->dev, ddi->id);
+ struct device *dev = &ddi->dev->dev;
+ int rc;
+
+ /* Unbound PCI devices are always set to disabled and suspended.
+ * During probe, the device is set to enabled and active and the
+ * usage count is incremented. If the driver supports runtime PM,
+ * it should call pm_runtime_put_noidle() in its probe routine and
+ * pm_runtime_get_noresume() in its remove routine.
+ */
+ pm_runtime_get_noresume(dev);
+ pm_runtime_set_active(dev);
+ pm_runtime_enable(dev);
+
+ rc = ddi->drv->probe(ddi->dev, ddi->id);
+ if (rc) {
+ pm_runtime_disable(dev);
+ pm_runtime_set_suspended(dev);
+ pm_runtime_put_noidle(dev);
+ }
+ return rc;
}
static int pci_call_probe(struct pci_driver *drv, struct pci_dev *dev,
@@ -369,11 +387,19 @@ static int pci_device_remove(struct device * dev)
struct pci_driver * drv = pci_dev->driver;
if (drv) {
- if (drv->remove)
+ if (drv->remove) {
+ pm_runtime_get_sync(dev);
drv->remove(pci_dev);
+ pm_runtime_put_noidle(dev);
+ }
pci_dev->driver = NULL;
}
+ /* Undo the runtime PM settings in local_pci_probe() */
+ pm_runtime_disable(dev);
+ pm_runtime_set_suspended(dev);
+ pm_runtime_put_noidle(dev);
+
/*
* If the device is still on, set the power state as "unknown",
* since it might change by the next time we load the driver.
diff --git a/drivers/pci/pci-label.c b/drivers/pci/pci-label.c
new file mode 100644
index 00000000000..90c0a729cd3
--- /dev/null
+++ b/drivers/pci/pci-label.c
@@ -0,0 +1,143 @@
+/*
+ * Purpose: Export the firmware instance and label associated with
+ * a pci device to sysfs
+ * Copyright (C) 2010 Dell Inc.
+ * by Narendra K <Narendra_K@dell.com>,
+ * Jordan Hargrave <Jordan_Hargrave@dell.com>
+ *
+ * SMBIOS defines type 41 for onboard pci devices. This code retrieves
+ * the instance number and string from the type 41 record and exports
+ * it to sysfs.
+ *
+ * Please see http://linux.dell.com/wiki/index.php/Oss/libnetdevname for more
+ * information.
+ */
+
+#include <linux/dmi.h>
+#include <linux/sysfs.h>
+#include <linux/pci.h>
+#include <linux/pci_ids.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include "pci.h"
+
+enum smbios_attr_enum {
+ SMBIOS_ATTR_NONE = 0,
+ SMBIOS_ATTR_LABEL_SHOW,
+ SMBIOS_ATTR_INSTANCE_SHOW,
+};
+
+static mode_t
+find_smbios_instance_string(struct pci_dev *pdev, char *buf,
+ enum smbios_attr_enum attribute)
+{
+ const struct dmi_device *dmi;
+ struct dmi_dev_onboard *donboard;
+ int bus;
+ int devfn;
+
+ bus = pdev->bus->number;
+ devfn = pdev->devfn;
+
+ dmi = NULL;
+ while ((dmi = dmi_find_device(DMI_DEV_TYPE_DEV_ONBOARD,
+ NULL, dmi)) != NULL) {
+ donboard = dmi->device_data;
+ if (donboard && donboard->bus == bus &&
+ donboard->devfn == devfn) {
+ if (buf) {
+ if (attribute == SMBIOS_ATTR_INSTANCE_SHOW)
+ return scnprintf(buf, PAGE_SIZE,
+ "%d\n",
+ donboard->instance);
+ else if (attribute == SMBIOS_ATTR_LABEL_SHOW)
+ return scnprintf(buf, PAGE_SIZE,
+ "%s\n",
+ dmi->name);
+ }
+ return strlen(dmi->name);
+ }
+ }
+ return 0;
+}
+
+static mode_t
+smbios_instance_string_exist(struct kobject *kobj, struct attribute *attr,
+ int n)
+{
+ struct device *dev;
+ struct pci_dev *pdev;
+
+ dev = container_of(kobj, struct device, kobj);
+ pdev = to_pci_dev(dev);
+
+ return find_smbios_instance_string(pdev, NULL, SMBIOS_ATTR_NONE) ?
+ S_IRUGO : 0;
+}
+
+static ssize_t
+smbioslabel_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct pci_dev *pdev;
+ pdev = to_pci_dev(dev);
+
+ return find_smbios_instance_string(pdev, buf,
+ SMBIOS_ATTR_LABEL_SHOW);
+}
+
+static ssize_t
+smbiosinstance_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct pci_dev *pdev;
+ pdev = to_pci_dev(dev);
+
+ return find_smbios_instance_string(pdev, buf,
+ SMBIOS_ATTR_INSTANCE_SHOW);
+}
+
+static struct device_attribute smbios_attr_label = {
+ .attr = {.name = "label", .mode = 0444},
+ .show = smbioslabel_show,
+};
+
+static struct device_attribute smbios_attr_instance = {
+ .attr = {.name = "index", .mode = 0444},
+ .show = smbiosinstance_show,
+};
+
+static struct attribute *smbios_attributes[] = {
+ &smbios_attr_label.attr,
+ &smbios_attr_instance.attr,
+ NULL,
+};
+
+static struct attribute_group smbios_attr_group = {
+ .attrs = smbios_attributes,
+ .is_visible = smbios_instance_string_exist,
+};
+
+static int
+pci_create_smbiosname_file(struct pci_dev *pdev)
+{
+ if (!sysfs_create_group(&pdev->dev.kobj, &smbios_attr_group))
+ return 0;
+ return -ENODEV;
+}
+
+static void
+pci_remove_smbiosname_file(struct pci_dev *pdev)
+{
+ sysfs_remove_group(&pdev->dev.kobj, &smbios_attr_group);
+}
+
+void pci_create_firmware_label_files(struct pci_dev *pdev)
+{
+ if (!pci_create_smbiosname_file(pdev))
+ ;
+}
+
+void pci_remove_firmware_label_files(struct pci_dev *pdev)
+{
+ pci_remove_smbiosname_file(pdev);
+}
diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c
index c9957f68ac9..b5a7d9bfcb2 100644
--- a/drivers/pci/pci-sysfs.c
+++ b/drivers/pci/pci-sysfs.c
@@ -734,7 +734,7 @@ pci_mmap_resource(struct kobject *kobj, struct bin_attribute *attr,
{
struct pci_dev *pdev = to_pci_dev(container_of(kobj,
struct device, kobj));
- struct resource *res = (struct resource *)attr->private;
+ struct resource *res = attr->private;
enum pci_mmap_state mmap_type;
resource_size_t start, end;
int i;
@@ -778,6 +778,70 @@ pci_mmap_resource_wc(struct file *filp, struct kobject *kobj,
return pci_mmap_resource(kobj, attr, vma, 1);
}
+static ssize_t
+pci_resource_io(struct file *filp, struct kobject *kobj,
+ struct bin_attribute *attr, char *buf,
+ loff_t off, size_t count, bool write)
+{
+ struct pci_dev *pdev = to_pci_dev(container_of(kobj,
+ struct device, kobj));
+ struct resource *res = attr->private;
+ unsigned long port = off;
+ int i;
+
+ for (i = 0; i < PCI_ROM_RESOURCE; i++)
+ if (res == &pdev->resource[i])
+ break;
+ if (i >= PCI_ROM_RESOURCE)
+ return -ENODEV;
+
+ port += pci_resource_start(pdev, i);
+
+ if (port > pci_resource_end(pdev, i))
+ return 0;
+
+ if (port + count - 1 > pci_resource_end(pdev, i))
+ return -EINVAL;
+
+ switch (count) {
+ case 1:
+ if (write)
+ outb(*(u8 *)buf, port);
+ else
+ *(u8 *)buf = inb(port);
+ return 1;
+ case 2:
+ if (write)
+ outw(*(u16 *)buf, port);
+ else
+ *(u16 *)buf = inw(port);
+ return 2;
+ case 4:
+ if (write)
+ outl(*(u32 *)buf, port);
+ else
+ *(u32 *)buf = inl(port);
+ return 4;
+ }
+ return -EINVAL;
+}
+
+static ssize_t
+pci_read_resource_io(struct file *filp, struct kobject *kobj,
+ struct bin_attribute *attr, char *buf,
+ loff_t off, size_t count)
+{
+ return pci_resource_io(filp, kobj, attr, buf, off, count, false);
+}
+
+static ssize_t
+pci_write_resource_io(struct file *filp, struct kobject *kobj,
+ struct bin_attribute *attr, char *buf,
+ loff_t off, size_t count)
+{
+ return pci_resource_io(filp, kobj, attr, buf, off, count, true);
+}
+
/**
* pci_remove_resource_files - cleanup resource files
* @pdev: dev to cleanup
@@ -828,6 +892,10 @@ static int pci_create_attr(struct pci_dev *pdev, int num, int write_combine)
sprintf(res_attr_name, "resource%d", num);
res_attr->mmap = pci_mmap_resource_uc;
}
+ if (pci_resource_flags(pdev, num) & IORESOURCE_IO) {
+ res_attr->read = pci_read_resource_io;
+ res_attr->write = pci_write_resource_io;
+ }
res_attr->attr.name = res_attr_name;
res_attr->attr.mode = S_IRUSR | S_IWUSR;
res_attr->size = pci_resource_len(pdev, num);
@@ -1097,6 +1165,8 @@ int __must_check pci_create_sysfs_dev_files (struct pci_dev *pdev)
if (retval)
goto err_vga_file;
+ pci_create_firmware_label_files(pdev);
+
return 0;
err_vga_file:
@@ -1164,6 +1234,9 @@ void pci_remove_sysfs_dev_files(struct pci_dev *pdev)
sysfs_remove_bin_file(&pdev->dev.kobj, pdev->rom_attr);
kfree(pdev->rom_attr);
}
+
+ pci_remove_firmware_label_files(pdev);
+
}
static int __init pci_sysfs_init(void)
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index 740fb4ea966..7fa3cbd742c 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -1275,6 +1275,22 @@ bool pci_check_pme_status(struct pci_dev *dev)
return ret;
}
+/*
+ * Time to wait before the system can be put into a sleep state after reporting
+ * a wakeup event signaled by a PCI device.
+ */
+#define PCI_WAKEUP_COOLDOWN 100
+
+/**
+ * pci_wakeup_event - Report a wakeup event related to a given PCI device.
+ * @dev: Device to report the wakeup event for.
+ */
+void pci_wakeup_event(struct pci_dev *dev)
+{
+ if (device_may_wakeup(&dev->dev))
+ pm_wakeup_event(&dev->dev, PCI_WAKEUP_COOLDOWN);
+}
+
/**
* pci_pme_wakeup - Wake up a PCI device if its PME Status bit is set.
* @dev: Device to handle.
@@ -1285,8 +1301,10 @@ bool pci_check_pme_status(struct pci_dev *dev)
*/
static int pci_pme_wakeup(struct pci_dev *dev, void *ign)
{
- if (pci_check_pme_status(dev))
+ if (pci_check_pme_status(dev)) {
pm_request_resume(&dev->dev);
+ pci_wakeup_event(dev);
+ }
return 0;
}
@@ -2294,21 +2312,17 @@ void pci_msi_off(struct pci_dev *dev)
}
EXPORT_SYMBOL_GPL(pci_msi_off);
-#ifndef HAVE_ARCH_PCI_SET_DMA_MAX_SEGMENT_SIZE
int pci_set_dma_max_seg_size(struct pci_dev *dev, unsigned int size)
{
return dma_set_max_seg_size(&dev->dev, size);
}
EXPORT_SYMBOL(pci_set_dma_max_seg_size);
-#endif
-#ifndef HAVE_ARCH_PCI_SET_DMA_SEGMENT_BOUNDARY
int pci_set_dma_seg_boundary(struct pci_dev *dev, unsigned long mask)
{
return dma_set_seg_boundary(&dev->dev, mask);
}
EXPORT_SYMBOL(pci_set_dma_seg_boundary);
-#endif
static int pcie_flr(struct pci_dev *dev, int probe)
{
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
index f8077b3c8c8..679c39de6a8 100644
--- a/drivers/pci/pci.h
+++ b/drivers/pci/pci.h
@@ -11,6 +11,15 @@
extern int pci_uevent(struct device *dev, struct kobj_uevent_env *env);
extern int pci_create_sysfs_dev_files(struct pci_dev *pdev);
extern void pci_remove_sysfs_dev_files(struct pci_dev *pdev);
+#ifndef CONFIG_DMI
+static inline void pci_create_firmware_label_files(struct pci_dev *pdev)
+{ return; }
+static inline void pci_remove_firmware_label_files(struct pci_dev *pdev)
+{ return; }
+#else
+extern void pci_create_firmware_label_files(struct pci_dev *pdev);
+extern void pci_remove_firmware_label_files(struct pci_dev *pdev);
+#endif
extern void pci_cleanup_rom(struct pci_dev *dev);
#ifdef HAVE_PCI_MMAP
extern int pci_mmap_fits(struct pci_dev *pdev, int resno,
@@ -56,6 +65,7 @@ extern void pci_update_current_state(struct pci_dev *dev, pci_power_t state);
extern void pci_disable_enabled_device(struct pci_dev *dev);
extern bool pci_check_pme_status(struct pci_dev *dev);
extern int pci_finish_runtime_suspend(struct pci_dev *dev);
+extern void pci_wakeup_event(struct pci_dev *dev);
extern int __pci_pme_wakeup(struct pci_dev *dev, void *ign);
extern void pci_pme_wakeup_bus(struct pci_bus *bus);
extern void pci_pm_init(struct pci_dev *dev);
diff --git a/drivers/pci/pcie/Kconfig b/drivers/pci/pcie/Kconfig
index b8b494b3e0d..dda70981b7a 100644
--- a/drivers/pci/pcie/Kconfig
+++ b/drivers/pci/pcie/Kconfig
@@ -31,14 +31,22 @@ source "drivers/pci/pcie/aer/Kconfig"
# PCI Express ASPM
#
config PCIEASPM
- bool "PCI Express ASPM support(Experimental)"
- depends on PCI && EXPERIMENTAL && PCIEPORTBUS
- default n
+ bool "PCI Express ASPM control" if EMBEDDED
+ depends on PCI && PCIEPORTBUS
+ default y
help
- This enables PCI Express ASPM (Active State Power Management) and
- Clock Power Management. ASPM supports state L0/L0s/L1.
+ This enables OS control over PCI Express ASPM (Active State
+ Power Management) and Clock Power Management. ASPM supports
+ state L0/L0s/L1.
- When in doubt, say N.
+ ASPM is initially set up the the firmware. With this option enabled,
+ Linux can modify this state in order to disable ASPM on known-bad
+ hardware or configurations and enable it when known-safe.
+
+ ASPM can be disabled or enabled at runtime via
+ /sys/module/pcie_aspm/parameters/policy
+
+ When in doubt, say Y.
config PCIEASPM_DEBUG
bool "Debug PCI Express ASPM"
depends on PCIEASPM
diff --git a/drivers/pci/pcie/aer/aerdrv_core.c b/drivers/pci/pcie/aer/aerdrv_core.c
index 8af4f619bba..fc0b5a93e1d 100644
--- a/drivers/pci/pcie/aer/aerdrv_core.c
+++ b/drivers/pci/pcie/aer/aerdrv_core.c
@@ -727,20 +727,21 @@ static void aer_isr_one_error(struct pcie_device *p_device,
static int get_e_source(struct aer_rpc *rpc, struct aer_err_source *e_src)
{
unsigned long flags;
- int ret = 0;
/* Lock access to Root error producer/consumer index */
spin_lock_irqsave(&rpc->e_lock, flags);
- if (rpc->prod_idx != rpc->cons_idx) {
- *e_src = rpc->e_sources[rpc->cons_idx];
- rpc->cons_idx++;
- if (rpc->cons_idx == AER_ERROR_SOURCES_MAX)
- rpc->cons_idx = 0;
- ret = 1;
+ if (rpc->prod_idx == rpc->cons_idx) {
+ spin_unlock_irqrestore(&rpc->e_lock, flags);
+ return 0;
}
+
+ *e_src = rpc->e_sources[rpc->cons_idx];
+ rpc->cons_idx++;
+ if (rpc->cons_idx == AER_ERROR_SOURCES_MAX)
+ rpc->cons_idx = 0;
spin_unlock_irqrestore(&rpc->e_lock, flags);
- return ret;
+ return 1;
}
/**
diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c
index be53d98fa38..71222814c1e 100644
--- a/drivers/pci/pcie/aspm.c
+++ b/drivers/pci/pcie/aspm.c
@@ -588,11 +588,23 @@ void pcie_aspm_init_link_state(struct pci_dev *pdev)
* update through pcie_aspm_cap_init().
*/
pcie_aspm_cap_init(link, blacklist);
- pcie_config_aspm_path(link);
/* Setup initial Clock PM state */
pcie_clkpm_cap_init(link, blacklist);
- pcie_set_clkpm(link, policy_to_clkpm_state(link));
+
+ /*
+ * At this stage drivers haven't had an opportunity to change the
+ * link policy setting. Enabling ASPM on broken hardware can cripple
+ * it even before the driver has had a chance to disable ASPM, so
+ * default to a safe level right now. If we're enabling ASPM beyond
+ * the BIOS's expectation, we'll do so once pci_enable_device() is
+ * called.
+ */
+ if (aspm_policy != POLICY_POWERSAVE) {
+ pcie_config_aspm_path(link);
+ pcie_set_clkpm(link, policy_to_clkpm_state(link));
+ }
+
unlock:
mutex_unlock(&aspm_lock);
out:
diff --git a/drivers/pci/pcie/pme/pcie_pme.c b/drivers/pci/pcie/pme/pcie_pme.c
index d672a0a6381..bbdea18693d 100644
--- a/drivers/pci/pcie/pme/pcie_pme.c
+++ b/drivers/pci/pcie/pme/pcie_pme.c
@@ -154,6 +154,7 @@ static bool pcie_pme_walk_bus(struct pci_bus *bus)
/* Skip PCIe devices in case we started from a root port. */
if (!pci_is_pcie(dev) && pci_check_pme_status(dev)) {
pm_request_resume(&dev->dev);
+ pci_wakeup_event(dev);
ret = true;
}
@@ -254,8 +255,10 @@ static void pcie_pme_handle_request(struct pci_dev *port, u16 req_id)
if (found) {
/* The device is there, but we have to check its PME status. */
found = pci_check_pme_status(dev);
- if (found)
+ if (found) {
pm_request_resume(&dev->dev);
+ pci_wakeup_event(dev);
+ }
pci_dev_put(dev);
} else if (devfn) {
/*
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index f4adba2d1dd..12625d90f8b 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -163,9 +163,16 @@ int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type,
struct resource *res, unsigned int pos)
{
u32 l, sz, mask;
+ u16 orig_cmd;
mask = type ? PCI_ROM_ADDRESS_MASK : ~0;
+ if (!dev->mmio_always_on) {
+ pci_read_config_word(dev, PCI_COMMAND, &orig_cmd);
+ pci_write_config_word(dev, PCI_COMMAND,
+ orig_cmd & ~(PCI_COMMAND_MEMORY | PCI_COMMAND_IO));
+ }
+
res->name = pci_name(dev);
pci_read_config_dword(dev, pos, &l);
@@ -173,6 +180,9 @@ int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type,
pci_read_config_dword(dev, pos, &sz);
pci_write_config_dword(dev, pos, l);
+ if (!dev->mmio_always_on)
+ pci_write_config_word(dev, PCI_COMMAND, orig_cmd);
+
/*
* All bits set in sz means the device isn't working properly.
* If the BAR isn't implemented, all bits must be 0. If it's a
diff --git a/drivers/pci/proc.c b/drivers/pci/proc.c
index 449e890267a..01f0306525a 100644
--- a/drivers/pci/proc.c
+++ b/drivers/pci/proc.c
@@ -431,8 +431,6 @@ int pci_proc_detach_device(struct pci_dev *dev)
struct proc_dir_entry *e;
if ((e = dev->procent)) {
- if (atomic_read(&e->count) > 1)
- return -EBUSY;
remove_proc_entry(e->name, dev->bus->procdir);
dev->procent = NULL;
}
@@ -485,9 +483,9 @@ static int __init pci_proc_init(void)
proc_create("devices", 0, proc_bus_pci_dir,
&proc_bus_pci_dev_operations);
proc_initialized = 1;
- while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {
+ for_each_pci_dev(dev)
pci_proc_attach_device(dev);
- }
+
return 0;
}
diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
index 477345d4164..89ed181cd90 100644
--- a/drivers/pci/quirks.c
+++ b/drivers/pci/quirks.c
@@ -91,6 +91,19 @@ static void __devinit quirk_resource_alignment(struct pci_dev *dev)
}
DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, quirk_resource_alignment);
+/*
+ * Decoding should be disabled for a PCI device during BAR sizing to avoid
+ * conflict. But doing so may cause problems on host bridge and perhaps other
+ * key system devices. For devices that need to have mmio decoding always-on,
+ * we need to set the dev->mmio_always_on bit.
+ */
+static void __devinit quirk_mmio_always_on(struct pci_dev *dev)
+{
+ if ((dev->class >> 8) == PCI_CLASS_BRIDGE_HOST)
+ dev->mmio_always_on = 1;
+}
+DECLARE_PCI_FIXUP_EARLY(PCI_ANY_ID, PCI_ANY_ID, quirk_mmio_always_on);
+
/* The Mellanox Tavor device gives false positive parity errors
* Mark this device with a broken_parity_status, to allow
* PCI scanning code to "skip" this now blacklisted device.
@@ -1459,6 +1472,7 @@ static void quirk_jmicron_ata(struct pci_dev *pdev)
switch (pdev->device) {
case PCI_DEVICE_ID_JMICRON_JMB360: /* SATA single port */
case PCI_DEVICE_ID_JMICRON_JMB362: /* SATA dual ports */
+ case PCI_DEVICE_ID_JMICRON_JMB364: /* SATA dual ports */
/* The controller should be in single function ahci mode */
conf1 |= 0x0002A100; /* Set 8, 13, 15, 17 */
break;
@@ -1470,6 +1484,7 @@ static void quirk_jmicron_ata(struct pci_dev *pdev)
/* Fall through */
case PCI_DEVICE_ID_JMICRON_JMB361:
case PCI_DEVICE_ID_JMICRON_JMB363:
+ case PCI_DEVICE_ID_JMICRON_JMB369:
/* Enable dual function mode, AHCI on fn 0, IDE fn1 */
/* Set the class codes correctly and then direct IDE 0 */
conf1 |= 0x00C2A1B3; /* Set 0, 1, 4, 5, 7, 8, 13, 15, 17, 22, 23 */
@@ -1496,16 +1511,20 @@ DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB360, qui
DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB361, quirk_jmicron_ata);
DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB362, quirk_jmicron_ata);
DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB363, quirk_jmicron_ata);
+DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB364, quirk_jmicron_ata);
DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB365, quirk_jmicron_ata);
DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB366, quirk_jmicron_ata);
DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB368, quirk_jmicron_ata);
+DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB369, quirk_jmicron_ata);
DECLARE_PCI_FIXUP_RESUME_EARLY(PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB360, quirk_jmicron_ata);
DECLARE_PCI_FIXUP_RESUME_EARLY(PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB361, quirk_jmicron_ata);
DECLARE_PCI_FIXUP_RESUME_EARLY(PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB362, quirk_jmicron_ata);
DECLARE_PCI_FIXUP_RESUME_EARLY(PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB363, quirk_jmicron_ata);
+DECLARE_PCI_FIXUP_RESUME_EARLY(PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB364, quirk_jmicron_ata);
DECLARE_PCI_FIXUP_RESUME_EARLY(PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB365, quirk_jmicron_ata);
DECLARE_PCI_FIXUP_RESUME_EARLY(PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB366, quirk_jmicron_ata);
DECLARE_PCI_FIXUP_RESUME_EARLY(PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB368, quirk_jmicron_ata);
+DECLARE_PCI_FIXUP_RESUME_EARLY(PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB369, quirk_jmicron_ata);
#endif
@@ -2115,6 +2134,7 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RS480, quirk_disabl
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_VT3336, quirk_disable_all_msi);
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_VT3351, quirk_disable_all_msi);
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_VT3364, quirk_disable_all_msi);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8380_0, quirk_disable_all_msi);
/* Disable MSI on chipsets that are known to not support it */
static void __devinit quirk_disable_msi(struct pci_dev *dev)
@@ -2126,12 +2146,29 @@ static void __devinit quirk_disable_msi(struct pci_dev *dev)
}
}
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8131_BRIDGE, quirk_disable_msi);
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, 0x9602, quirk_disable_msi);
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ASUSTEK, 0x9602, quirk_disable_msi);
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AI, 0x9602, quirk_disable_msi);
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, 0xa238, quirk_disable_msi);
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x5a3f, quirk_disable_msi);
+/*
+ * The APC bridge device in AMD 780 family northbridges has some random
+ * OEM subsystem ID in its vendor ID register (erratum 18), so instead
+ * we use the possible vendor/device IDs of the host bridge for the
+ * declared quirk, and search for the APC bridge by slot number.
+ */
+static void __devinit quirk_amd_780_apc_msi(struct pci_dev *host_bridge)
+{
+ struct pci_dev *apc_bridge;
+
+ apc_bridge = pci_get_slot(host_bridge->bus, PCI_DEVFN(1, 0));
+ if (apc_bridge) {
+ if (apc_bridge->device == 0x9602)
+ quirk_disable_msi(apc_bridge);
+ pci_dev_put(apc_bridge);
+ }
+}
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, 0x9600, quirk_amd_780_apc_msi);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, 0x9601, quirk_amd_780_apc_msi);
+
/* Go through the list of Hypertransport capabilities and
* return 1 if a HT MSI capability is found and enabled */
static int __devinit msi_ht_cap_enabled(struct pci_dev *dev)
@@ -2390,6 +2427,9 @@ static void __devinit __nv_msi_ht_cap_quirk(struct pci_dev *dev, int all)
int pos;
int found;
+ if (!pci_msi_enabled())
+ return;
+
/* check if there is HT MSI cap or enabled on this device */
found = ht_check_msi_mapping(dev);
@@ -2742,7 +2782,7 @@ static int __init pci_apply_final_quirks(void)
printk(KERN_DEBUG "PCI: CLS %u bytes\n",
pci_cache_line_size << 2);
- while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {
+ for_each_pci_dev(dev) {
pci_fixup_device(pci_fixup_final, dev);
/*
* If arch hasn't set it explicitly yet, use the CLS
diff --git a/drivers/pci/search.c b/drivers/pci/search.c
index 20d03f77228..9d75dc8ca60 100644
--- a/drivers/pci/search.c
+++ b/drivers/pci/search.c
@@ -169,7 +169,7 @@ struct pci_dev *pci_get_domain_bus_and_slot(int domain, unsigned int bus,
{
struct pci_dev *dev = NULL;
- while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {
+ for_each_pci_dev(dev) {
if (pci_domain_nr(dev->bus) == domain &&
(dev->bus->number == bus && dev->devfn == devfn))
return dev;
diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c
index 19b111383f6..66cb8f4cc5f 100644
--- a/drivers/pci/setup-bus.c
+++ b/drivers/pci/setup-bus.c
@@ -874,19 +874,16 @@ void pci_assign_unassigned_bridge_resources(struct pci_dev *bridge)
again:
pci_bus_size_bridges(parent);
__pci_bridge_assign_resources(bridge, &head);
- retval = pci_reenable_device(bridge);
- pci_set_master(bridge);
- pci_enable_bridges(parent);
tried_times++;
if (!head.next)
- return;
+ goto enable_all;
if (tried_times >= 2) {
/* still fail, don't need to try more */
free_failed_list(&head);
- return;
+ goto enable_all;
}
printk(KERN_DEBUG "PCI: No. %d try to assign unassigned res\n",
@@ -919,5 +916,10 @@ again:
free_failed_list(&head);
goto again;
+
+enable_all:
+ retval = pci_reenable_device(bridge);
+ pci_set_master(bridge);
+ pci_enable_bridges(parent);
}
EXPORT_SYMBOL_GPL(pci_assign_unassigned_bridge_resources);
diff --git a/drivers/pci/setup-irq.c b/drivers/pci/setup-irq.c
index aa795fd428d..eec9738f349 100644
--- a/drivers/pci/setup-irq.c
+++ b/drivers/pci/setup-irq.c
@@ -59,7 +59,6 @@ pci_fixup_irqs(u8 (*swizzle)(struct pci_dev *, u8 *),
int (*map_irq)(struct pci_dev *, u8, u8))
{
struct pci_dev *dev = NULL;
- while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {
+ for_each_pci_dev(dev)
pdev_fixup_irq(dev, swizzle, map_irq);
- }
}
diff --git a/drivers/pcmcia/Kconfig b/drivers/pcmcia/Kconfig
index d0f5ad30607..c988514eb55 100644
--- a/drivers/pcmcia/Kconfig
+++ b/drivers/pcmcia/Kconfig
@@ -157,11 +157,11 @@ config PCMCIA_M8XX
config PCMCIA_AU1X00
tristate "Au1x00 pcmcia support"
- depends on SOC_AU1X00 && PCMCIA
+ depends on MIPS_ALCHEMY && PCMCIA
config PCMCIA_ALCHEMY_DEVBOARD
tristate "Alchemy Db/Pb1xxx PCMCIA socket services"
- depends on SOC_AU1X00 && PCMCIA
+ depends on MIPS_ALCHEMY && PCMCIA
select 64BIT_PHYS_ADDR
help
Enable this driver of you want PCMCIA support on your Alchemy
diff --git a/drivers/pcmcia/Makefile b/drivers/pcmcia/Makefile
index d006e8beab9..7a2b1604bf1 100644
--- a/drivers/pcmcia/Makefile
+++ b/drivers/pcmcia/Makefile
@@ -7,7 +7,6 @@ pcmcia_core-$(CONFIG_CARDBUS) += cardbus.o
obj-$(CONFIG_PCCARD) += pcmcia_core.o
pcmcia-y += ds.o pcmcia_resource.o cistpl.o pcmcia_cis.o
-pcmcia-$(CONFIG_PCMCIA_IOCTL) += pcmcia_ioctl.o
obj-$(CONFIG_PCMCIA) += pcmcia.o
pcmcia_rsrc-y += rsrc_mgr.o
diff --git a/drivers/pcmcia/au1000_generic.h b/drivers/pcmcia/au1000_generic.h
index a324d329dea..67530cefcf3 100644
--- a/drivers/pcmcia/au1000_generic.h
+++ b/drivers/pcmcia/au1000_generic.h
@@ -23,7 +23,6 @@
/* include the world */
-#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/ss.h>
#include <pcmcia/cistpl.h>
diff --git a/drivers/pcmcia/au1000_pb1x00.c b/drivers/pcmcia/au1000_pb1x00.c
index 5a979cb8f3e..807f2d75dad 100644
--- a/drivers/pcmcia/au1000_pb1x00.c
+++ b/drivers/pcmcia/au1000_pb1x00.c
@@ -31,11 +31,9 @@
#include <linux/proc_fs.h>
#include <linux/types.h>
-#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/ss.h>
#include <pcmcia/cistpl.h>
-#include <pcmcia/bus_ops.h>
#include <asm/io.h>
#include <asm/irq.h>
diff --git a/drivers/pcmcia/cistpl.c b/drivers/pcmcia/cistpl.c
index 8844bc3e311..91414a0ddc4 100644
--- a/drivers/pcmcia/cistpl.c
+++ b/drivers/pcmcia/cistpl.c
@@ -27,7 +27,6 @@
#include <asm/byteorder.h>
#include <asm/unaligned.h>
-#include <pcmcia/cs_types.h>
#include <pcmcia/ss.h>
#include <pcmcia/cs.h>
#include <pcmcia/cisreg.h>
@@ -54,6 +53,9 @@ static const u_int exponent[] = {
/* Upper limit on reasonable # of tuples */
#define MAX_TUPLES 200
+/* Bits in IRQInfo1 field */
+#define IRQ_INFO2_VALID 0x10
+
/* 16-bit CIS? */
static int cis_width;
module_param(cis_width, int, 0444);
@@ -210,7 +212,7 @@ int pcmcia_read_cis_mem(struct pcmcia_socket *s, int attr, u_int addr,
* Probably only useful for writing one-byte registers. Must be called
* with ops_mutex held.
*/
-void pcmcia_write_cis_mem(struct pcmcia_socket *s, int attr, u_int addr,
+int pcmcia_write_cis_mem(struct pcmcia_socket *s, int attr, u_int addr,
u_int len, void *ptr)
{
void __iomem *sys, *end;
@@ -232,7 +234,7 @@ void pcmcia_write_cis_mem(struct pcmcia_socket *s, int attr, u_int addr,
((cis_width) ? MAP_16BIT : 0));
if (!sys) {
dev_dbg(&s->dev, "could not map memory\n");
- return; /* FIXME: Error */
+ return -EINVAL;
}
writeb(flags, sys+CISREG_ICTRL0);
@@ -257,7 +259,7 @@ void pcmcia_write_cis_mem(struct pcmcia_socket *s, int attr, u_int addr,
sys = set_cis_map(s, card_offset, flags);
if (!sys) {
dev_dbg(&s->dev, "could not map memory\n");
- return; /* FIXME: error */
+ return -EINVAL;
}
end = sys + s->map_size;
@@ -271,6 +273,7 @@ void pcmcia_write_cis_mem(struct pcmcia_socket *s, int attr, u_int addr,
addr = 0;
}
}
+ return 0;
}
diff --git a/drivers/pcmcia/cs.c b/drivers/pcmcia/cs.c
index 976d80706ea..2ec8ac97445 100644
--- a/drivers/pcmcia/cs.c
+++ b/drivers/pcmcia/cs.c
@@ -32,7 +32,6 @@
#include <asm/system.h>
#include <asm/irq.h>
-#include <pcmcia/cs_types.h>
#include <pcmcia/ss.h>
#include <pcmcia/cs.h>
#include <pcmcia/cistpl.h>
@@ -252,38 +251,6 @@ struct pcmcia_socket *pcmcia_get_socket_by_nr(unsigned int nr)
}
EXPORT_SYMBOL(pcmcia_get_socket_by_nr);
-/*
- * The central event handler. Send_event() sends an event to the
- * 16-bit subsystem, which then calls the relevant device drivers.
- * Parse_events() interprets the event bits from
- * a card status change report. Do_shutdown() handles the high
- * priority stuff associated with a card removal.
- */
-
-/* NOTE: send_event needs to be called with skt->sem held. */
-
-static int send_event(struct pcmcia_socket *s, event_t event, int priority)
-{
- int ret;
-
- if ((s->state & SOCKET_CARDBUS) && (event != CS_EVENT_CARD_REMOVAL))
- return 0;
-
- dev_dbg(&s->dev, "send_event(event %d, pri %d, callback 0x%p)\n",
- event, priority, s->callback);
-
- if (!s->callback)
- return 0;
- if (!try_module_get(s->callback->owner))
- return 0;
-
- ret = s->callback->event(s, event, priority);
-
- module_put(s->callback->owner);
-
- return ret;
-}
-
static int socket_reset(struct pcmcia_socket *skt)
{
int status, i;
@@ -326,7 +293,8 @@ static void socket_shutdown(struct pcmcia_socket *s)
dev_dbg(&s->dev, "shutdown\n");
- send_event(s, CS_EVENT_CARD_REMOVAL, CS_EVENT_PRI_HIGH);
+ if (s->callback)
+ s->callback->remove(s);
mutex_lock(&s->ops_mutex);
s->state &= SOCKET_INUSE | SOCKET_PRESENT;
@@ -477,7 +445,8 @@ static int socket_insert(struct pcmcia_socket *skt)
dev_dbg(&skt->dev, "insert done\n");
mutex_unlock(&skt->ops_mutex);
- send_event(skt, CS_EVENT_CARD_INSERTION, CS_EVENT_PRI_LOW);
+ if (!(skt->state & SOCKET_CARDBUS) && (skt->callback))
+ skt->callback->add(skt);
} else {
mutex_unlock(&skt->ops_mutex);
socket_shutdown(skt);
@@ -494,7 +463,6 @@ static int socket_suspend(struct pcmcia_socket *skt)
mutex_lock(&skt->ops_mutex);
skt->suspended_state = skt->state;
- send_event(skt, CS_EVENT_PM_SUSPEND, CS_EVENT_PRI_LOW);
skt->socket = dead_socket;
skt->ops->set_socket(skt, &skt->socket);
if (skt->ops->suspend)
@@ -555,8 +523,8 @@ static int socket_late_resume(struct pcmcia_socket *skt)
return 0;
}
#endif
-
- send_event(skt, CS_EVENT_PM_RESUME, CS_EVENT_PRI_LOW);
+ if (!(skt->state & SOCKET_CARDBUS) && (skt->callback))
+ skt->callback->early_resume(skt);
return 0;
}
@@ -654,16 +622,8 @@ static int pccardd(void *__skt)
spin_unlock_irqrestore(&skt->thread_lock, flags);
mutex_lock(&skt->skt_mutex);
- if (events) {
- if (events & SS_DETECT)
- socket_detect_change(skt);
- if (events & SS_BATDEAD)
- send_event(skt, CS_EVENT_BATTERY_DEAD, CS_EVENT_PRI_LOW);
- if (events & SS_BATWARN)
- send_event(skt, CS_EVENT_BATTERY_LOW, CS_EVENT_PRI_LOW);
- if (events & SS_READY)
- send_event(skt, CS_EVENT_READY_CHANGE, CS_EVENT_PRI_LOW);
- }
+ if (events & SS_DETECT)
+ socket_detect_change(skt);
if (sysfs_events) {
if (sysfs_events & PCMCIA_UEVENT_EJECT)
@@ -783,7 +743,7 @@ int pccard_register_pcmcia(struct pcmcia_socket *s, struct pcmcia_callback *c)
s->callback = c;
if ((s->state & (SOCKET_PRESENT|SOCKET_CARDBUS)) == SOCKET_PRESENT)
- send_event(s, CS_EVENT_CARD_INSERTION, CS_EVENT_PRI_LOW);
+ s->callback->add(s);
} else
s->callback = NULL;
err:
@@ -823,20 +783,13 @@ int pcmcia_reset_card(struct pcmcia_socket *skt)
break;
}
- ret = send_event(skt, CS_EVENT_RESET_REQUEST, CS_EVENT_PRI_LOW);
- if (ret == 0) {
- send_event(skt, CS_EVENT_RESET_PHYSICAL, CS_EVENT_PRI_LOW);
- if (skt->callback)
- skt->callback->suspend(skt);
- mutex_lock(&skt->ops_mutex);
- ret = socket_reset(skt);
- mutex_unlock(&skt->ops_mutex);
- if (ret == 0) {
- send_event(skt, CS_EVENT_CARD_RESET, CS_EVENT_PRI_LOW);
- if (skt->callback)
- skt->callback->resume(skt);
- }
- }
+ if (skt->callback)
+ skt->callback->suspend(skt);
+ mutex_lock(&skt->ops_mutex);
+ ret = socket_reset(skt);
+ mutex_unlock(&skt->ops_mutex);
+ if ((ret == 0) && (skt->callback))
+ skt->callback->resume(skt);
ret = 0;
} while (0);
diff --git a/drivers/pcmcia/cs_internal.h b/drivers/pcmcia/cs_internal.h
index 4126a75445e..da055dc14d9 100644
--- a/drivers/pcmcia/cs_internal.h
+++ b/drivers/pcmcia/cs_internal.h
@@ -10,7 +10,7 @@
* are Copyright (C) 1999 David A. Hinds. All Rights Reserved.
*
* (C) 1999 David A. Hinds
- * (C) 2003 - 2008 Dominik Brodowski
+ * (C) 2003 - 2010 Dominik Brodowski
*
*
* This file contains definitions _only_ needed by the PCMCIA core modules.
@@ -26,6 +26,9 @@
/* Flags in client state */
#define CLIENT_WIN_REQ(i) (0x1<<(i))
+/* Flag to access all functions */
+#define BIND_FN_ALL 0xff
+
/* Each card function gets one of these guys */
typedef struct config_t {
struct kref ref;
@@ -35,7 +38,10 @@ typedef struct config_t {
unsigned int ConfigBase;
unsigned char Status, Pin, Copy, Option, ExtStatus;
unsigned int CardValues;
- io_req_t io;
+
+ struct resource io[MAX_IO_WIN]; /* io ports */
+ struct resource mem[MAX_WIN]; /* mem areas */
+
struct {
u_int Attributes;
} irq;
@@ -56,18 +62,11 @@ struct pccard_resource_ops {
unsigned int attr,
unsigned int *base,
unsigned int num,
- unsigned int align);
+ unsigned int align,
+ struct resource **parent);
struct resource* (*find_mem) (unsigned long base, unsigned long num,
unsigned long align, int low,
struct pcmcia_socket *s);
- int (*add_io) (struct pcmcia_socket *s,
- unsigned int action,
- unsigned long r_start,
- unsigned long r_end);
- int (*add_mem) (struct pcmcia_socket *s,
- unsigned int action,
- unsigned long r_start,
- unsigned long r_end);
int (*init) (struct pcmcia_socket *s);
void (*exit) (struct pcmcia_socket *s);
};
@@ -114,11 +113,12 @@ void cb_free(struct pcmcia_socket *s);
struct pcmcia_callback{
struct module *owner;
- int (*event) (struct pcmcia_socket *s,
- event_t event, int priority);
+ int (*add) (struct pcmcia_socket *s);
+ int (*remove) (struct pcmcia_socket *s);
void (*requery) (struct pcmcia_socket *s);
int (*validate) (struct pcmcia_socket *s, unsigned int *i);
int (*suspend) (struct pcmcia_socket *s);
+ int (*early_resume) (struct pcmcia_socket *s);
int (*resume) (struct pcmcia_socket *s);
};
@@ -146,6 +146,8 @@ void pcmcia_put_socket(struct pcmcia_socket *skt);
/* ds.c */
extern struct bus_type pcmcia_bus_type;
+struct pcmcia_device;
+
/* pcmcia_resource.c */
extern int pcmcia_release_configuration(struct pcmcia_device *p_dev);
extern int pcmcia_validate_mem(struct pcmcia_socket *s);
@@ -163,8 +165,8 @@ extern struct bin_attribute pccard_cis_attr;
int pcmcia_read_cis_mem(struct pcmcia_socket *s, int attr,
u_int addr, u_int len, void *ptr);
-void pcmcia_write_cis_mem(struct pcmcia_socket *s, int attr,
- u_int addr, u_int len, void *ptr);
+int pcmcia_write_cis_mem(struct pcmcia_socket *s, int attr,
+ u_int addr, u_int len, void *ptr);
void release_cis_mem(struct pcmcia_socket *s);
void destroy_cis_cache(struct pcmcia_socket *s);
int pccard_read_tuple(struct pcmcia_socket *s, unsigned int function,
@@ -188,34 +190,4 @@ int pccard_get_next_tuple(struct pcmcia_socket *s, unsigned int function,
int pccard_get_tuple_data(struct pcmcia_socket *s, tuple_t *tuple);
-
-#ifdef CONFIG_PCMCIA_IOCTL
-/* ds.c */
-extern struct pcmcia_device *pcmcia_get_dev(struct pcmcia_device *p_dev);
-extern void pcmcia_put_dev(struct pcmcia_device *p_dev);
-
-struct pcmcia_device *pcmcia_device_add(struct pcmcia_socket *s,
- unsigned int function);
-
-/* pcmcia_ioctl.c */
-extern void __init pcmcia_setup_ioctl(void);
-extern void __exit pcmcia_cleanup_ioctl(void);
-extern void handle_event(struct pcmcia_socket *s, event_t event);
-extern int handle_request(struct pcmcia_socket *s, event_t event);
-
-#else /* CONFIG_PCMCIA_IOCTL */
-
-static inline void __init pcmcia_setup_ioctl(void) { return; }
-static inline void __exit pcmcia_cleanup_ioctl(void) { return; }
-static inline void handle_event(struct pcmcia_socket *s, event_t event)
-{
- return;
-}
-static inline int handle_request(struct pcmcia_socket *s, event_t event)
-{
- return 0;
-}
-
-#endif /* CONFIG_PCMCIA_IOCTL */
-
#endif /* _LINUX_CS_INTERNAL_H */
diff --git a/drivers/pcmcia/db1xxx_ss.c b/drivers/pcmcia/db1xxx_ss.c
index 0f4cc3f0002..27575e6378a 100644
--- a/drivers/pcmcia/db1xxx_ss.c
+++ b/drivers/pcmcia/db1xxx_ss.c
@@ -29,7 +29,6 @@
#include <linux/slab.h>
#include <linux/spinlock.h>
-#include <pcmcia/cs_types.h>
#include <pcmcia/ss.h>
#include <asm/mach-au1x00/au1000.h>
diff --git a/drivers/pcmcia/ds.c b/drivers/pcmcia/ds.c
index eac961463be..55570d9e1e4 100644
--- a/drivers/pcmcia/ds.c
+++ b/drivers/pcmcia/ds.c
@@ -10,7 +10,7 @@
* are Copyright (C) 1999 David A. Hinds. All Rights Reserved.
*
* (C) 1999 David A. Hinds
- * (C) 2003 - 2006 Dominik Brodowski
+ * (C) 2003 - 2010 Dominik Brodowski
*/
#include <linux/kernel.h>
@@ -26,7 +26,6 @@
#include <linux/dma-mapping.h>
#include <linux/slab.h>
-#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/cistpl.h>
#include <pcmcia/ds.h>
@@ -213,7 +212,7 @@ EXPORT_SYMBOL(pcmcia_unregister_driver);
/* pcmcia_device handling */
-struct pcmcia_device *pcmcia_get_dev(struct pcmcia_device *p_dev)
+static struct pcmcia_device *pcmcia_get_dev(struct pcmcia_device *p_dev)
{
struct device *tmp_dev;
tmp_dev = get_device(&p_dev->dev);
@@ -222,7 +221,7 @@ struct pcmcia_device *pcmcia_get_dev(struct pcmcia_device *p_dev)
return to_pcmcia_dev(tmp_dev);
}
-void pcmcia_put_dev(struct pcmcia_device *p_dev)
+static void pcmcia_put_dev(struct pcmcia_device *p_dev)
{
if (p_dev)
put_device(&p_dev->dev);
@@ -294,7 +293,7 @@ static int pcmcia_device_probe(struct device *dev)
}
mutex_lock(&s->ops_mutex);
- if ((s->pcmcia_state.has_pfc) &&
+ if ((s->pcmcia_pfc) &&
(p_dev->socket->device_count == 1) && (p_dev->device_no == 0))
pcmcia_parse_uevents(s, PCMCIA_UEVENT_REQUERY);
mutex_unlock(&s->ops_mutex);
@@ -359,7 +358,7 @@ static int pcmcia_device_remove(struct device *dev)
* pseudo multi-function card, we need to unbind
* all devices
*/
- if ((p_dev->socket->pcmcia_state.has_pfc) &&
+ if ((p_dev->socket->pcmcia_pfc) &&
(p_dev->socket->device_count > 0) &&
(p_dev->device_no == 0))
pcmcia_card_remove(p_dev->socket, p_dev);
@@ -477,7 +476,8 @@ static int pcmcia_device_query(struct pcmcia_device *p_dev)
}
-struct pcmcia_device *pcmcia_device_add(struct pcmcia_socket *s, unsigned int function)
+static struct pcmcia_device *pcmcia_device_add(struct pcmcia_socket *s,
+ unsigned int function)
{
struct pcmcia_device *p_dev, *tmp_dev;
int i;
@@ -531,7 +531,6 @@ struct pcmcia_device *pcmcia_device_add(struct pcmcia_socket *s, unsigned int fu
list_for_each_entry(tmp_dev, &s->devices_list, socket_device_list)
if (p_dev->func == tmp_dev->func) {
p_dev->function_config = tmp_dev->function_config;
- p_dev->io = tmp_dev->io;
p_dev->irq = tmp_dev->irq;
kref_get(&p_dev->function_config->ref);
}
@@ -544,15 +543,29 @@ struct pcmcia_device *pcmcia_device_add(struct pcmcia_socket *s, unsigned int fu
"IRQ setup failed -- device might not work\n");
if (!p_dev->function_config) {
+ config_t *c;
dev_dbg(&p_dev->dev, "creating config_t\n");
- p_dev->function_config = kzalloc(sizeof(struct config_t),
- GFP_KERNEL);
- if (!p_dev->function_config) {
+ c = kzalloc(sizeof(struct config_t), GFP_KERNEL);
+ if (!c) {
mutex_unlock(&s->ops_mutex);
goto err_unreg;
}
- kref_init(&p_dev->function_config->ref);
+ p_dev->function_config = c;
+ kref_init(&c->ref);
+ for (i = 0; i < MAX_IO_WIN; i++) {
+ c->io[i].name = p_dev->devname;
+ c->io[i].flags = IORESOURCE_IO;
+ }
+ for (i = 0; i< MAX_WIN; i++) {
+ c->mem[i].name = p_dev->devname;
+ c->mem[i].flags = IORESOURCE_MEM;
+ }
}
+ for (i = 0; i < MAX_IO_WIN; i++)
+ p_dev->resource[i] = &p_dev->function_config->io[i];
+ for (; i < (MAX_IO_WIN + MAX_WIN); i++)
+ p_dev->resource[i] = &p_dev->function_config->mem[i-MAX_IO_WIN];
+
mutex_unlock(&s->ops_mutex);
dev_printk(KERN_NOTICE, &p_dev->dev,
@@ -680,7 +693,7 @@ static void pcmcia_requery(struct pcmcia_socket *s)
* call pcmcia_device_add() -- which will fail if both
* devices are already registered. */
mutex_lock(&s->ops_mutex);
- has_pfc = s->pcmcia_state.has_pfc;
+ has_pfc = s->pcmcia_pfc;
mutex_unlock(&s->ops_mutex);
if (has_pfc)
pcmcia_device_add(s, 0);
@@ -812,7 +825,7 @@ static inline int pcmcia_devmatch(struct pcmcia_device *dev,
if (did->match_flags & PCMCIA_DEV_ID_MATCH_DEVICE_NO) {
dev_dbg(&dev->dev, "this is a pseudo-multi-function device\n");
mutex_lock(&dev->socket->ops_mutex);
- dev->socket->pcmcia_state.has_pfc = 1;
+ dev->socket->pcmcia_pfc = 1;
mutex_unlock(&dev->socket->ops_mutex);
if (dev->device_no != did->device_no)
return 0;
@@ -826,7 +839,7 @@ static inline int pcmcia_devmatch(struct pcmcia_device *dev,
/* if this is a pseudo-multi-function device,
* we need explicit matches */
- if (dev->socket->pcmcia_state.has_pfc)
+ if (dev->socket->pcmcia_pfc)
return 0;
if (dev->device_no)
return 0;
@@ -885,14 +898,6 @@ static int pcmcia_bus_match(struct device *dev, struct device_driver *drv)
}
mutex_unlock(&p_drv->dynids.lock);
-#ifdef CONFIG_PCMCIA_IOCTL
- /* matching by cardmgr */
- if (p_dev->cardmgr == p_drv) {
- dev_dbg(dev, "cardmgr matched to %s\n", drv->name);
- return 1;
- }
-#endif
-
while (did && did->match_flags) {
dev_dbg(dev, "trying to match to %s\n", drv->name);
if (pcmcia_devmatch(p_dev, did)) {
@@ -1006,6 +1011,18 @@ pcmcia_device_stringattr(prod_id2, prod_id[1]);
pcmcia_device_stringattr(prod_id3, prod_id[2]);
pcmcia_device_stringattr(prod_id4, prod_id[3]);
+static ssize_t pcmcia_show_resources(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct pcmcia_device *p_dev = to_pcmcia_dev(dev);
+ char *str = buf;
+ int i;
+
+ for (i = 0; i < PCMCIA_NUM_RESOURCES; i++)
+ str += sprintf(str, "%pr\n", p_dev->resource[i]);
+
+ return str - buf;
+}
static ssize_t pcmcia_show_pm_state(struct device *dev, struct device_attribute *attr, char *buf)
{
@@ -1076,6 +1093,7 @@ static ssize_t pcmcia_store_allow_func_id_match(struct device *dev,
static struct device_attribute pcmcia_dev_attrs[] = {
__ATTR(function, 0444, func_show, NULL),
__ATTR(pm_state, 0644, pcmcia_show_pm_state, pcmcia_store_pm_state),
+ __ATTR(resources, 0444, pcmcia_show_resources, NULL),
__ATTR_RO(func_id),
__ATTR_RO(manf_id),
__ATTR_RO(card_id),
@@ -1215,86 +1233,57 @@ static int pcmcia_bus_suspend(struct pcmcia_socket *skt)
return 0;
}
+static int pcmcia_bus_remove(struct pcmcia_socket *skt)
+{
+ atomic_set(&skt->present, 0);
+ pcmcia_card_remove(skt, NULL);
-/*======================================================================
+ mutex_lock(&skt->ops_mutex);
+ destroy_cis_cache(skt);
+ pcmcia_cleanup_irq(skt);
+ mutex_unlock(&skt->ops_mutex);
- The card status event handler.
+ return 0;
+}
-======================================================================*/
+static int pcmcia_bus_add(struct pcmcia_socket *skt)
+{
+ atomic_set(&skt->present, 1);
-/* Normally, the event is passed to individual drivers after
- * informing userspace. Only for CS_EVENT_CARD_REMOVAL this
- * is inversed to maintain historic compatibility.
- */
+ mutex_lock(&skt->ops_mutex);
+ skt->pcmcia_pfc = 0;
+ destroy_cis_cache(skt); /* to be on the safe side... */
+ mutex_unlock(&skt->ops_mutex);
-static int ds_event(struct pcmcia_socket *skt, event_t event, int priority)
-{
- struct pcmcia_socket *s = pcmcia_get_socket(skt);
+ pcmcia_card_add(skt);
- if (!s) {
- dev_printk(KERN_ERR, &skt->dev,
- "PCMCIA obtaining reference to socket " \
- "failed, event 0x%x lost!\n", event);
- return -ENODEV;
- }
+ return 0;
+}
- dev_dbg(&skt->dev, "ds_event(0x%06x, %d, 0x%p)\n",
- event, priority, skt);
+static int pcmcia_bus_early_resume(struct pcmcia_socket *skt)
+{
+ if (!verify_cis_cache(skt)) {
+ pcmcia_put_socket(skt);
+ return 0;
+ }
- switch (event) {
- case CS_EVENT_CARD_REMOVAL:
- atomic_set(&skt->present, 0);
- pcmcia_card_remove(skt, NULL);
- handle_event(skt, event);
- mutex_lock(&s->ops_mutex);
- destroy_cis_cache(s);
- pcmcia_cleanup_irq(s);
- mutex_unlock(&s->ops_mutex);
- break;
+ dev_dbg(&skt->dev, "cis mismatch - different card\n");
- case CS_EVENT_CARD_INSERTION:
- atomic_set(&skt->present, 1);
- mutex_lock(&s->ops_mutex);
- s->pcmcia_state.has_pfc = 0;
- destroy_cis_cache(s); /* to be on the safe side... */
- mutex_unlock(&s->ops_mutex);
- pcmcia_card_add(skt);
- handle_event(skt, event);
- break;
-
- case CS_EVENT_EJECTION_REQUEST:
- break;
-
- case CS_EVENT_PM_RESUME:
- if (verify_cis_cache(skt) != 0) {
- dev_dbg(&skt->dev, "cis mismatch - different card\n");
- /* first, remove the card */
- ds_event(skt, CS_EVENT_CARD_REMOVAL, CS_EVENT_PRI_HIGH);
- mutex_lock(&s->ops_mutex);
- destroy_cis_cache(skt);
- kfree(skt->fake_cis);
- skt->fake_cis = NULL;
- s->functions = 0;
- mutex_unlock(&s->ops_mutex);
- /* now, add the new card */
- ds_event(skt, CS_EVENT_CARD_INSERTION,
- CS_EVENT_PRI_LOW);
- }
- handle_event(skt, event);
- break;
+ /* first, remove the card */
+ pcmcia_bus_remove(skt);
- case CS_EVENT_PM_SUSPEND:
- case CS_EVENT_RESET_PHYSICAL:
- case CS_EVENT_CARD_RESET:
- default:
- handle_event(skt, event);
- break;
- }
+ mutex_lock(&skt->ops_mutex);
+ destroy_cis_cache(skt);
+ kfree(skt->fake_cis);
+ skt->fake_cis = NULL;
+ skt->functions = 0;
+ mutex_unlock(&skt->ops_mutex);
- pcmcia_put_socket(s);
+ /* now, add the new card */
+ pcmcia_bus_add(skt);
+ return 0;
+}
- return 0;
-} /* ds_event */
/*
* NOTE: This is racy. There's no guarantee the card will still be
@@ -1323,10 +1312,12 @@ EXPORT_SYMBOL(pcmcia_dev_present);
static struct pcmcia_callback pcmcia_bus_callback = {
.owner = THIS_MODULE,
- .event = ds_event,
+ .add = pcmcia_bus_add,
+ .remove = pcmcia_bus_remove,
.requery = pcmcia_requery,
.validate = pccard_validate_cis,
.suspend = pcmcia_bus_suspend,
+ .early_resume = pcmcia_bus_early_resume,
.resume = pcmcia_bus_resume,
};
@@ -1350,11 +1341,8 @@ static int __devinit pcmcia_bus_add_socket(struct device *dev,
return ret;
}
-#ifdef CONFIG_PCMCIA_IOCTL
- init_waitqueue_head(&socket->queue);
-#endif
INIT_LIST_HEAD(&socket->devices_list);
- memset(&socket->pcmcia_state, 0, sizeof(u8));
+ socket->pcmcia_pfc = 0;
socket->device_count = 0;
atomic_set(&socket->present, 0);
@@ -1429,8 +1417,6 @@ static int __init init_pcmcia_bus(void)
return ret;
}
- pcmcia_setup_ioctl();
-
return 0;
}
fs_initcall(init_pcmcia_bus); /* one level after subsys_initcall so that
@@ -1439,8 +1425,6 @@ fs_initcall(init_pcmcia_bus); /* one level after subsys_initcall so that
static void __exit exit_pcmcia_bus(void)
{
- pcmcia_cleanup_ioctl();
-
class_interface_unregister(&pcmcia_bus_interface);
bus_unregister(&pcmcia_bus_type);
diff --git a/drivers/pcmcia/i82092.c b/drivers/pcmcia/i82092.c
index 3003bb3dfcc..05d0879ce93 100644
--- a/drivers/pcmcia/i82092.c
+++ b/drivers/pcmcia/i82092.c
@@ -15,7 +15,6 @@
#include <linux/interrupt.h>
#include <linux/device.h>
-#include <pcmcia/cs_types.h>
#include <pcmcia/ss.h>
#include <pcmcia/cs.h>
diff --git a/drivers/pcmcia/i82365.c b/drivers/pcmcia/i82365.c
index 9e2a15628de..61746bd598b 100644
--- a/drivers/pcmcia/i82365.c
+++ b/drivers/pcmcia/i82365.c
@@ -50,7 +50,6 @@
#include <asm/io.h>
#include <asm/system.h>
-#include <pcmcia/cs_types.h>
#include <pcmcia/ss.h>
#include <pcmcia/cs.h>
diff --git a/drivers/pcmcia/m32r_cfc.c b/drivers/pcmcia/m32r_cfc.c
index 7e16ed8eb0a..24de4992586 100644
--- a/drivers/pcmcia/m32r_cfc.c
+++ b/drivers/pcmcia/m32r_cfc.c
@@ -26,7 +26,6 @@
#include <asm/io.h>
#include <asm/system.h>
-#include <pcmcia/cs_types.h>
#include <pcmcia/ss.h>
#include <pcmcia/cs.h>
diff --git a/drivers/pcmcia/m32r_pcc.c b/drivers/pcmcia/m32r_pcc.c
index 6c5c3f910d7..8e4723844ad 100644
--- a/drivers/pcmcia/m32r_pcc.c
+++ b/drivers/pcmcia/m32r_pcc.c
@@ -27,7 +27,6 @@
#include <asm/system.h>
#include <asm/addrspace.h>
-#include <pcmcia/cs_types.h>
#include <pcmcia/ss.h>
#include <pcmcia/cs.h>
diff --git a/drivers/pcmcia/m8xx_pcmcia.c b/drivers/pcmcia/m8xx_pcmcia.c
index 25e5e30a18a..f2f90a7d3e1 100644
--- a/drivers/pcmcia/m8xx_pcmcia.c
+++ b/drivers/pcmcia/m8xx_pcmcia.c
@@ -59,7 +59,6 @@
#include <asm/irq.h>
#include <asm/fs_pd.h>
-#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/ss.h>
diff --git a/drivers/pcmcia/pcmcia_cis.c b/drivers/pcmcia/pcmcia_cis.c
index 4a65eaf96b0..0ac54da1588 100644
--- a/drivers/pcmcia/pcmcia_cis.c
+++ b/drivers/pcmcia/pcmcia_cis.c
@@ -19,7 +19,6 @@
#include <linux/kernel.h>
#include <linux/netdevice.h>
-#include <pcmcia/cs_types.h>
#include <pcmcia/cisreg.h>
#include <pcmcia/cistpl.h>
#include <pcmcia/ss.h>
diff --git a/drivers/pcmcia/pcmcia_ioctl.c b/drivers/pcmcia/pcmcia_ioctl.c
deleted file mode 100644
index d007a2a0383..00000000000
--- a/drivers/pcmcia/pcmcia_ioctl.c
+++ /dev/null
@@ -1,1077 +0,0 @@
-/*
- * pcmcia_ioctl.c -- ioctl interface for cardmgr and cardctl
- *
- * 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 initial developer of the original code is David A. Hinds
- * <dahinds@users.sourceforge.net>. Portions created by David A. Hinds
- * are Copyright (C) 1999 David A. Hinds. All Rights Reserved.
- *
- * (C) 1999 David A. Hinds
- * (C) 2003 - 2004 Dominik Brodowski
- */
-
-/*
- * This file will go away soon.
- */
-
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/major.h>
-#include <linux/errno.h>
-#include <linux/ioctl.h>
-#include <linux/proc_fs.h>
-#include <linux/poll.h>
-#include <linux/pci.h>
-#include <linux/slab.h>
-#include <linux/seq_file.h>
-#include <linux/smp_lock.h>
-#include <linux/workqueue.h>
-
-#include <pcmcia/cs_types.h>
-#include <pcmcia/cs.h>
-#include <pcmcia/cistpl.h>
-#include <pcmcia/cisreg.h>
-#include <pcmcia/ds.h>
-#include <pcmcia/ss.h>
-
-#include "cs_internal.h"
-
-static int major_dev = -1;
-
-
-/* Device user information */
-#define MAX_EVENTS 32
-#define USER_MAGIC 0x7ea4
-#define CHECK_USER(u) \
- (((u) == NULL) || ((u)->user_magic != USER_MAGIC))
-
-typedef struct user_info_t {
- u_int user_magic;
- int event_head, event_tail;
- event_t event[MAX_EVENTS];
- struct user_info_t *next;
- struct pcmcia_socket *socket;
-} user_info_t;
-
-
-static struct pcmcia_device *get_pcmcia_device(struct pcmcia_socket *s,
- unsigned int function)
-{
- struct pcmcia_device *p_dev = NULL;
-
- mutex_lock(&s->ops_mutex);
- list_for_each_entry(p_dev, &s->devices_list, socket_device_list) {
- if (p_dev->func == function) {
- mutex_unlock(&s->ops_mutex);
- return pcmcia_get_dev(p_dev);
- }
- }
- mutex_unlock(&s->ops_mutex);
- return NULL;
-}
-
-/* backwards-compatible accessing of driver --- by name! */
-
-static struct pcmcia_driver *get_pcmcia_driver(dev_info_t *dev_info)
-{
- struct device_driver *drv;
- struct pcmcia_driver *p_drv;
-
- drv = driver_find((char *) dev_info, &pcmcia_bus_type);
- if (!drv)
- return NULL;
-
- p_drv = container_of(drv, struct pcmcia_driver, drv);
-
- return p_drv;
-}
-
-
-#ifdef CONFIG_PROC_FS
-static struct proc_dir_entry *proc_pccard;
-
-static int proc_read_drivers_callback(struct device_driver *driver, void *_m)
-{
- struct seq_file *m = _m;
- struct pcmcia_driver *p_drv = container_of(driver,
- struct pcmcia_driver, drv);
-
- seq_printf(m, "%-24.24s 1 %d\n", p_drv->drv.name,
-#ifdef CONFIG_MODULE_UNLOAD
- (p_drv->owner) ? module_refcount(p_drv->owner) : 1
-#else
- 1
-#endif
- );
- return 0;
-}
-
-static int pccard_drivers_proc_show(struct seq_file *m, void *v)
-{
- return bus_for_each_drv(&pcmcia_bus_type, NULL,
- m, proc_read_drivers_callback);
-}
-
-static int pccard_drivers_proc_open(struct inode *inode, struct file *file)
-{
- return single_open(file, pccard_drivers_proc_show, NULL);
-}
-
-static const struct file_operations pccard_drivers_proc_fops = {
- .owner = THIS_MODULE,
- .open = pccard_drivers_proc_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
-#endif
-
-
-#ifdef CONFIG_PCMCIA_PROBE
-
-static int adjust_irq(struct pcmcia_socket *s, adjust_t *adj)
-{
- int irq;
- u32 mask;
-
- irq = adj->resource.irq.IRQ;
- if ((irq < 0) || (irq > 15))
- return -EINVAL;
-
- if (adj->Action != REMOVE_MANAGED_RESOURCE)
- return 0;
-
- mask = 1 << irq;
-
- if (!(s->irq_mask & mask))
- return 0;
-
- s->irq_mask &= ~mask;
-
- return 0;
-}
-
-#else
-
-static inline int adjust_irq(struct pcmcia_socket *s, adjust_t *adj)
-{
- return 0;
-}
-
-#endif
-
-static int pcmcia_adjust_resource_info(adjust_t *adj)
-{
- struct pcmcia_socket *s;
- int ret = -ENOSYS;
-
- down_read(&pcmcia_socket_list_rwsem);
- list_for_each_entry(s, &pcmcia_socket_list, socket_list) {
-
- if (adj->Resource == RES_IRQ)
- ret = adjust_irq(s, adj);
-
- else if (s->resource_ops->add_io) {
- unsigned long begin, end;
-
- /* you can't use the old interface if the new
- * one was used before */
- mutex_lock(&s->ops_mutex);
- if ((s->resource_setup_new) &&
- !(s->resource_setup_old)) {
- mutex_unlock(&s->ops_mutex);
- continue;
- } else if (!(s->resource_setup_old))
- s->resource_setup_old = 1;
-
- switch (adj->Resource) {
- case RES_MEMORY_RANGE:
- begin = adj->resource.memory.Base;
- end = adj->resource.memory.Base + adj->resource.memory.Size - 1;
- if (s->resource_ops->add_mem)
- ret = s->resource_ops->add_mem(s, adj->Action, begin, end);
- case RES_IO_RANGE:
- begin = adj->resource.io.BasePort;
- end = adj->resource.io.BasePort + adj->resource.io.NumPorts - 1;
- if (s->resource_ops->add_io)
- ret = s->resource_ops->add_io(s, adj->Action, begin, end);
- }
- if (!ret) {
- /* as there's no way we know this is the
- * last call to adjust_resource_info, we
- * always need to assume this is the latest
- * one... */
- s->resource_setup_done = 1;
- }
- mutex_unlock(&s->ops_mutex);
- }
- }
- up_read(&pcmcia_socket_list_rwsem);
-
- return ret;
-}
-
-
-/** pcmcia_get_window
- */
-static int pcmcia_get_window(struct pcmcia_socket *s, window_handle_t *wh_out,
- window_handle_t wh, win_req_t *req)
-{
- pccard_mem_map *win;
- window_handle_t w;
-
- wh--;
- if (!s || !(s->state & SOCKET_PRESENT))
- return -ENODEV;
- if (wh >= MAX_WIN)
- return -EINVAL;
- for (w = wh; w < MAX_WIN; w++)
- if (s->state & SOCKET_WIN_REQ(w))
- break;
- if (w == MAX_WIN)
- return -EINVAL;
- win = &s->win[w];
- req->Base = win->res->start;
- req->Size = win->res->end - win->res->start + 1;
- req->AccessSpeed = win->speed;
- req->Attributes = 0;
- if (win->flags & MAP_ATTRIB)
- req->Attributes |= WIN_MEMORY_TYPE_AM;
- if (win->flags & MAP_ACTIVE)
- req->Attributes |= WIN_ENABLE;
- if (win->flags & MAP_16BIT)
- req->Attributes |= WIN_DATA_WIDTH_16;
- if (win->flags & MAP_USE_WAIT)
- req->Attributes |= WIN_USE_WAIT;
-
- *wh_out = w + 1;
- return 0;
-} /* pcmcia_get_window */
-
-
-/** pcmcia_get_mem_page
- *
- * Change the card address of an already open memory window.
- */
-static int pcmcia_get_mem_page(struct pcmcia_socket *skt, window_handle_t wh,
- memreq_t *req)
-{
- wh--;
- if (wh >= MAX_WIN)
- return -EINVAL;
-
- req->Page = 0;
- req->CardOffset = skt->win[wh].card_start;
- return 0;
-} /* pcmcia_get_mem_page */
-
-
-/** pccard_get_status
- *
- * Get the current socket state bits. We don't support the latched
- * SocketState yet: I haven't seen any point for it.
- */
-
-static int pccard_get_status(struct pcmcia_socket *s,
- struct pcmcia_device *p_dev,
- cs_status_t *status)
-{
- config_t *c;
- int val;
-
- s->ops->get_status(s, &val);
- status->CardState = status->SocketState = 0;
- status->CardState |= (val & SS_DETECT) ? CS_EVENT_CARD_DETECT : 0;
- status->CardState |= (val & SS_CARDBUS) ? CS_EVENT_CB_DETECT : 0;
- status->CardState |= (val & SS_3VCARD) ? CS_EVENT_3VCARD : 0;
- status->CardState |= (val & SS_XVCARD) ? CS_EVENT_XVCARD : 0;
- if (s->state & SOCKET_SUSPEND)
- status->CardState |= CS_EVENT_PM_SUSPEND;
- if (!(s->state & SOCKET_PRESENT))
- return -ENODEV;
-
- c = (p_dev) ? p_dev->function_config : NULL;
-
- if ((c != NULL) && (c->state & CONFIG_LOCKED) &&
- (c->IntType & (INT_MEMORY_AND_IO | INT_ZOOMED_VIDEO))) {
- u_char reg;
- if (c->CardValues & PRESENT_PIN_REPLACE) {
- mutex_lock(&s->ops_mutex);
- pcmcia_read_cis_mem(s, 1, (c->ConfigBase+CISREG_PRR)>>1, 1, &reg);
- mutex_unlock(&s->ops_mutex);
- status->CardState |=
- (reg & PRR_WP_STATUS) ? CS_EVENT_WRITE_PROTECT : 0;
- status->CardState |=
- (reg & PRR_READY_STATUS) ? CS_EVENT_READY_CHANGE : 0;
- status->CardState |=
- (reg & PRR_BVD2_STATUS) ? CS_EVENT_BATTERY_LOW : 0;
- status->CardState |=
- (reg & PRR_BVD1_STATUS) ? CS_EVENT_BATTERY_DEAD : 0;
- } else {
- /* No PRR? Then assume we're always ready */
- status->CardState |= CS_EVENT_READY_CHANGE;
- }
- if (c->CardValues & PRESENT_EXT_STATUS) {
- mutex_lock(&s->ops_mutex);
- pcmcia_read_cis_mem(s, 1, (c->ConfigBase+CISREG_ESR)>>1, 1, &reg);
- mutex_unlock(&s->ops_mutex);
- status->CardState |=
- (reg & ESR_REQ_ATTN) ? CS_EVENT_REQUEST_ATTENTION : 0;
- }
- return 0;
- }
- status->CardState |=
- (val & SS_WRPROT) ? CS_EVENT_WRITE_PROTECT : 0;
- status->CardState |=
- (val & SS_BATDEAD) ? CS_EVENT_BATTERY_DEAD : 0;
- status->CardState |=
- (val & SS_BATWARN) ? CS_EVENT_BATTERY_LOW : 0;
- status->CardState |=
- (val & SS_READY) ? CS_EVENT_READY_CHANGE : 0;
- return 0;
-} /* pccard_get_status */
-
-static int pccard_get_configuration_info(struct pcmcia_socket *s,
- struct pcmcia_device *p_dev,
- config_info_t *config)
-{
- config_t *c;
-
- if (!(s->state & SOCKET_PRESENT))
- return -ENODEV;
-
-
-#ifdef CONFIG_CARDBUS
- if (s->state & SOCKET_CARDBUS) {
- memset(config, 0, sizeof(config_info_t));
- config->Vcc = s->socket.Vcc;
- config->Vpp1 = config->Vpp2 = s->socket.Vpp;
- config->Option = s->cb_dev->subordinate->number;
- if (s->state & SOCKET_CARDBUS_CONFIG) {
- config->Attributes = CONF_VALID_CLIENT;
- config->IntType = INT_CARDBUS;
- config->AssignedIRQ = s->pcmcia_irq;
- if (config->AssignedIRQ)
- config->Attributes |= CONF_ENABLE_IRQ;
- if (s->io[0].res) {
- config->BasePort1 = s->io[0].res->start;
- config->NumPorts1 = s->io[0].res->end -
- config->BasePort1 + 1;
- }
- }
- return 0;
- }
-#endif
-
- if (p_dev) {
- c = p_dev->function_config;
- config->Function = p_dev->func;
- } else {
- c = NULL;
- config->Function = 0;
- }
-
- if ((c == NULL) || !(c->state & CONFIG_LOCKED)) {
- config->Attributes = 0;
- config->Vcc = s->socket.Vcc;
- config->Vpp1 = config->Vpp2 = s->socket.Vpp;
- return 0;
- }
-
- config->Attributes = c->Attributes | CONF_VALID_CLIENT;
- config->Vcc = s->socket.Vcc;
- config->Vpp1 = config->Vpp2 = s->socket.Vpp;
- config->IntType = c->IntType;
- config->ConfigBase = c->ConfigBase;
- config->Status = c->Status;
- config->Pin = c->Pin;
- config->Copy = c->Copy;
- config->Option = c->Option;
- config->ExtStatus = c->ExtStatus;
- config->Present = config->CardValues = c->CardValues;
- config->IRQAttributes = c->irq.Attributes;
- config->AssignedIRQ = s->pcmcia_irq;
- config->BasePort1 = c->io.BasePort1;
- config->NumPorts1 = c->io.NumPorts1;
- config->Attributes1 = c->io.Attributes1;
- config->BasePort2 = c->io.BasePort2;
- config->NumPorts2 = c->io.NumPorts2;
- config->Attributes2 = c->io.Attributes2;
- config->IOAddrLines = c->io.IOAddrLines;
-
- return 0;
-} /* pccard_get_configuration_info */
-
-
-/*======================================================================
-
- These manage a ring buffer of events pending for one user process
-
-======================================================================*/
-
-
-static int queue_empty(user_info_t *user)
-{
- return (user->event_head == user->event_tail);
-}
-
-static event_t get_queued_event(user_info_t *user)
-{
- user->event_tail = (user->event_tail+1) % MAX_EVENTS;
- return user->event[user->event_tail];
-}
-
-static void queue_event(user_info_t *user, event_t event)
-{
- user->event_head = (user->event_head+1) % MAX_EVENTS;
- if (user->event_head == user->event_tail)
- user->event_tail = (user->event_tail+1) % MAX_EVENTS;
- user->event[user->event_head] = event;
-}
-
-void handle_event(struct pcmcia_socket *s, event_t event)
-{
- user_info_t *user;
- for (user = s->user; user; user = user->next)
- queue_event(user, event);
- wake_up_interruptible(&s->queue);
-}
-
-
-/*======================================================================
-
- bind_request() and bind_device() are merged by now. Register_client()
- is called right at the end of bind_request(), during the driver's
- ->attach() call. Individual descriptions:
-
- bind_request() connects a socket to a particular client driver.
- It looks up the specified device ID in the list of registered
- drivers, binds it to the socket, and tries to create an instance
- of the device. unbind_request() deletes a driver instance.
-
- Bind_device() associates a device driver with a particular socket.
- It is normally called by Driver Services after it has identified
- a newly inserted card. An instance of that driver will then be
- eligible to register as a client of this socket.
-
- Register_client() uses the dev_info_t handle to match the
- caller with a socket. The driver must have already been bound
- to a socket with bind_device() -- in fact, bind_device()
- allocates the client structure that will be used.
-
-======================================================================*/
-
-static int bind_request(struct pcmcia_socket *s, bind_info_t *bind_info)
-{
- struct pcmcia_driver *p_drv;
- struct pcmcia_device *p_dev;
- int ret = 0;
-
- s = pcmcia_get_socket(s);
- if (!s)
- return -EINVAL;
-
- pr_debug("bind_request(%d, '%s')\n", s->sock,
- (char *)bind_info->dev_info);
-
- p_drv = get_pcmcia_driver(&bind_info->dev_info);
- if (!p_drv) {
- ret = -EINVAL;
- goto err_put;
- }
-
- if (!try_module_get(p_drv->owner)) {
- ret = -EINVAL;
- goto err_put_driver;
- }
-
- mutex_lock(&s->ops_mutex);
- list_for_each_entry(p_dev, &s->devices_list, socket_device_list) {
- if (p_dev->func == bind_info->function) {
- if ((p_dev->dev.driver == &p_drv->drv)) {
- if (p_dev->cardmgr) {
- /* if there's already a device
- * registered, and it was registered
- * by userspace before, we need to
- * return the "instance". */
- mutex_unlock(&s->ops_mutex);
- bind_info->instance = p_dev;
- ret = -EBUSY;
- goto err_put_module;
- } else {
- /* the correct driver managed to bind
- * itself magically to the correct
- * device. */
- mutex_unlock(&s->ops_mutex);
- p_dev->cardmgr = p_drv;
- ret = 0;
- goto err_put_module;
- }
- } else if (!p_dev->dev.driver) {
- /* there's already a device available where
- * no device has been bound to yet. So we don't
- * need to register a device! */
- mutex_unlock(&s->ops_mutex);
- goto rescan;
- }
- }
- }
- mutex_unlock(&s->ops_mutex);
-
- p_dev = pcmcia_device_add(s, bind_info->function);
- if (!p_dev) {
- ret = -EIO;
- goto err_put_module;
- }
-
-rescan:
- p_dev->cardmgr = p_drv;
-
- /* if a driver is already running, we can abort */
- if (p_dev->dev.driver)
- goto err_put_module;
-
- /*
- * Prevent this racing with a card insertion.
- */
- mutex_lock(&s->skt_mutex);
- ret = bus_rescan_devices(&pcmcia_bus_type);
- mutex_unlock(&s->skt_mutex);
- if (ret)
- goto err_put_module;
-
- /* check whether the driver indeed matched. I don't care if this
- * is racy or not, because it can only happen on cardmgr access
- * paths...
- */
- if (!(p_dev->dev.driver == &p_drv->drv))
- p_dev->cardmgr = NULL;
-
- err_put_module:
- module_put(p_drv->owner);
- err_put_driver:
- put_driver(&p_drv->drv);
- err_put:
- pcmcia_put_socket(s);
-
- return ret;
-} /* bind_request */
-
-#ifdef CONFIG_CARDBUS
-
-static struct pci_bus *pcmcia_lookup_bus(struct pcmcia_socket *s)
-{
- if (!s || !(s->state & SOCKET_CARDBUS))
- return NULL;
-
- return s->cb_dev->subordinate;
-}
-#endif
-
-static int get_device_info(struct pcmcia_socket *s, bind_info_t *bind_info, int first)
-{
- struct pcmcia_device *p_dev;
- struct pcmcia_driver *p_drv;
- int ret = 0;
-
-#ifdef CONFIG_CARDBUS
- /*
- * Some unbelievably ugly code to associate the PCI cardbus
- * device and its driver with the PCMCIA "bind" information.
- */
- {
- struct pci_bus *bus;
-
- bus = pcmcia_lookup_bus(s);
- if (bus) {
- struct list_head *list;
- struct pci_dev *dev = NULL;
-
- list = bus->devices.next;
- while (list != &bus->devices) {
- struct pci_dev *pdev = pci_dev_b(list);
- list = list->next;
-
- if (first) {
- dev = pdev;
- break;
- }
-
- /* Try to handle "next" here some way? */
- }
- if (dev && dev->driver) {
- strlcpy(bind_info->name, dev->driver->name, DEV_NAME_LEN);
- bind_info->major = 0;
- bind_info->minor = 0;
- bind_info->next = NULL;
- return 0;
- }
- }
- }
-#endif
-
- mutex_lock(&s->ops_mutex);
- list_for_each_entry(p_dev, &s->devices_list, socket_device_list) {
- if (p_dev->func == bind_info->function) {
- p_dev = pcmcia_get_dev(p_dev);
- if (!p_dev)
- continue;
- goto found;
- }
- }
- mutex_unlock(&s->ops_mutex);
- return -ENODEV;
-
- found:
- mutex_unlock(&s->ops_mutex);
-
- p_drv = to_pcmcia_drv(p_dev->dev.driver);
- if (p_drv && !p_dev->_locked) {
- ret = -EAGAIN;
- goto err_put;
- }
-
- if (!first) {
- ret = -ENODEV;
- goto err_put;
- }
-
- strlcpy(bind_info->name, dev_name(&p_dev->dev), DEV_NAME_LEN);
- bind_info->next = NULL;
-
- err_put:
- pcmcia_put_dev(p_dev);
- return ret;
-} /* get_device_info */
-
-
-static int ds_open(struct inode *inode, struct file *file)
-{
- socket_t i = iminor(inode);
- struct pcmcia_socket *s;
- user_info_t *user;
- static int warning_printed;
- int ret = 0;
-
- pr_debug("ds_open(socket %d)\n", i);
-
- lock_kernel();
- s = pcmcia_get_socket_by_nr(i);
- if (!s) {
- ret = -ENODEV;
- goto out;
- }
- s = pcmcia_get_socket(s);
- if (!s) {
- ret = -ENODEV;
- goto out;
- }
-
- if ((file->f_flags & O_ACCMODE) != O_RDONLY) {
- if (s->pcmcia_state.busy) {
- pcmcia_put_socket(s);
- ret = -EBUSY;
- goto out;
- }
- else
- s->pcmcia_state.busy = 1;
- }
-
- user = kmalloc(sizeof(user_info_t), GFP_KERNEL);
- if (!user) {
- pcmcia_put_socket(s);
- ret = -ENOMEM;
- goto out;
- }
- user->event_tail = user->event_head = 0;
- user->next = s->user;
- user->user_magic = USER_MAGIC;
- user->socket = s;
- s->user = user;
- file->private_data = user;
-
- if (!warning_printed) {
- printk(KERN_INFO "pcmcia: Detected deprecated PCMCIA ioctl "
- "usage from process: %s.\n", current->comm);
- printk(KERN_INFO "pcmcia: This interface will soon be removed from "
- "the kernel; please expect breakage unless you upgrade "
- "to new tools.\n");
- printk(KERN_INFO "pcmcia: see http://www.kernel.org/pub/linux/"
- "utils/kernel/pcmcia/pcmcia.html for details.\n");
- warning_printed = 1;
- }
-
- if (atomic_read(&s->present))
- queue_event(user, CS_EVENT_CARD_INSERTION);
-out:
- unlock_kernel();
- return ret;
-} /* ds_open */
-
-/*====================================================================*/
-
-static int ds_release(struct inode *inode, struct file *file)
-{
- struct pcmcia_socket *s;
- user_info_t *user, **link;
-
- pr_debug("ds_release(socket %d)\n", iminor(inode));
-
- user = file->private_data;
- if (CHECK_USER(user))
- goto out;
-
- s = user->socket;
-
- /* Unlink user data structure */
- if ((file->f_flags & O_ACCMODE) != O_RDONLY)
- s->pcmcia_state.busy = 0;
-
- file->private_data = NULL;
- for (link = &s->user; *link; link = &(*link)->next)
- if (*link == user)
- break;
- if (link == NULL)
- goto out;
- *link = user->next;
- user->user_magic = 0;
- kfree(user);
- pcmcia_put_socket(s);
-out:
- return 0;
-} /* ds_release */
-
-/*====================================================================*/
-
-static ssize_t ds_read(struct file *file, char __user *buf,
- size_t count, loff_t *ppos)
-{
- struct pcmcia_socket *s;
- user_info_t *user;
- int ret;
-
- pr_debug("ds_read(socket %d)\n", iminor(file->f_path.dentry->d_inode));
-
- if (count < 4)
- return -EINVAL;
-
- user = file->private_data;
- if (CHECK_USER(user))
- return -EIO;
-
- s = user->socket;
- ret = wait_event_interruptible(s->queue, !queue_empty(user));
- if (ret == 0)
- ret = put_user(get_queued_event(user), (int __user *)buf) ? -EFAULT : 4;
-
- return ret;
-} /* ds_read */
-
-/*====================================================================*/
-
-static ssize_t ds_write(struct file *file, const char __user *buf,
- size_t count, loff_t *ppos)
-{
- pr_debug("ds_write(socket %d)\n", iminor(file->f_path.dentry->d_inode));
-
- if (count != 4)
- return -EINVAL;
- if ((file->f_flags & O_ACCMODE) == O_RDONLY)
- return -EBADF;
-
- return -EIO;
-} /* ds_write */
-
-/*====================================================================*/
-
-/* No kernel lock - fine */
-static u_int ds_poll(struct file *file, poll_table *wait)
-{
- struct pcmcia_socket *s;
- user_info_t *user;
-
- pr_debug("ds_poll(socket %d)\n", iminor(file->f_path.dentry->d_inode));
-
- user = file->private_data;
- if (CHECK_USER(user))
- return POLLERR;
- s = user->socket;
- /*
- * We don't check for a dead socket here since that
- * will send cardmgr into an endless spin.
- */
- poll_wait(file, &s->queue, wait);
- if (!queue_empty(user))
- return POLLIN | POLLRDNORM;
- return 0;
-} /* ds_poll */
-
-/*====================================================================*/
-
-static int ds_ioctl(struct file *file, u_int cmd, u_long arg)
-{
- struct pcmcia_socket *s;
- void __user *uarg = (char __user *)arg;
- u_int size;
- int ret, err;
- ds_ioctl_arg_t *buf;
- user_info_t *user;
-
- pr_debug("ds_ioctl(socket %d, %#x, %#lx)\n", iminor(inode), cmd, arg);
-
- user = file->private_data;
- if (CHECK_USER(user))
- return -EIO;
-
- s = user->socket;
-
- size = (cmd & IOCSIZE_MASK) >> IOCSIZE_SHIFT;
- if (size > sizeof(ds_ioctl_arg_t))
- return -EINVAL;
-
- /* Permission check */
- if (!(cmd & IOC_OUT) && !capable(CAP_SYS_ADMIN))
- return -EPERM;
-
- if (cmd & IOC_IN) {
- if (!access_ok(VERIFY_READ, uarg, size)) {
- pr_debug("ds_ioctl(): verify_read = %d\n", -EFAULT);
- return -EFAULT;
- }
- }
- if (cmd & IOC_OUT) {
- if (!access_ok(VERIFY_WRITE, uarg, size)) {
- pr_debug("ds_ioctl(): verify_write = %d\n", -EFAULT);
- return -EFAULT;
- }
- }
- buf = kmalloc(sizeof(ds_ioctl_arg_t), GFP_KERNEL);
- if (!buf)
- return -ENOMEM;
-
- err = ret = 0;
-
- if (cmd & IOC_IN) {
- if (__copy_from_user((char *)buf, uarg, size)) {
- err = -EFAULT;
- goto free_out;
- }
- }
-
- switch (cmd) {
- case DS_ADJUST_RESOURCE_INFO:
- ret = pcmcia_adjust_resource_info(&buf->adjust);
- break;
- case DS_GET_CONFIGURATION_INFO:
- if (buf->config.Function &&
- (buf->config.Function >= s->functions))
- ret = -EINVAL;
- else {
- struct pcmcia_device *p_dev = get_pcmcia_device(s, buf->config.Function);
- ret = pccard_get_configuration_info(s, p_dev, &buf->config);
- pcmcia_put_dev(p_dev);
- }
- break;
- case DS_GET_FIRST_TUPLE:
- mutex_lock(&s->skt_mutex);
- pcmcia_validate_mem(s);
- mutex_unlock(&s->skt_mutex);
- ret = pccard_get_first_tuple(s, BIND_FN_ALL, &buf->tuple);
- break;
- case DS_GET_NEXT_TUPLE:
- ret = pccard_get_next_tuple(s, BIND_FN_ALL, &buf->tuple);
- break;
- case DS_GET_TUPLE_DATA:
- buf->tuple.TupleData = buf->tuple_parse.data;
- buf->tuple.TupleDataMax = sizeof(buf->tuple_parse.data);
- ret = pccard_get_tuple_data(s, &buf->tuple);
- break;
- case DS_PARSE_TUPLE:
- buf->tuple.TupleData = buf->tuple_parse.data;
- ret = pcmcia_parse_tuple(&buf->tuple, &buf->tuple_parse.parse);
- break;
- case DS_RESET_CARD:
- ret = pcmcia_reset_card(s);
- break;
- case DS_GET_STATUS:
- if (buf->status.Function &&
- (buf->status.Function >= s->functions))
- ret = -EINVAL;
- else {
- struct pcmcia_device *p_dev = get_pcmcia_device(s, buf->status.Function);
- ret = pccard_get_status(s, p_dev, &buf->status);
- pcmcia_put_dev(p_dev);
- }
- break;
- case DS_VALIDATE_CIS:
- mutex_lock(&s->skt_mutex);
- pcmcia_validate_mem(s);
- mutex_unlock(&s->skt_mutex);
- ret = pccard_validate_cis(s, &buf->cisinfo.Chains);
- break;
- case DS_SUSPEND_CARD:
- pcmcia_parse_uevents(s, PCMCIA_UEVENT_SUSPEND);
- break;
- case DS_RESUME_CARD:
- pcmcia_parse_uevents(s, PCMCIA_UEVENT_RESUME);
- break;
- case DS_EJECT_CARD:
- pcmcia_parse_uevents(s, PCMCIA_UEVENT_EJECT);
- break;
- case DS_INSERT_CARD:
- pcmcia_parse_uevents(s, PCMCIA_UEVENT_INSERT);
- break;
- case DS_ACCESS_CONFIGURATION_REGISTER:
- if ((buf->conf_reg.Action == CS_WRITE) && !capable(CAP_SYS_ADMIN)) {
- err = -EPERM;
- goto free_out;
- }
-
- ret = -EINVAL;
-
- if (!(buf->conf_reg.Function &&
- (buf->conf_reg.Function >= s->functions))) {
- struct pcmcia_device *p_dev = get_pcmcia_device(s, buf->conf_reg.Function);
- if (p_dev) {
- ret = pcmcia_access_configuration_register(p_dev, &buf->conf_reg);
- pcmcia_put_dev(p_dev);
- }
- }
- break;
- case DS_GET_FIRST_REGION:
- case DS_GET_NEXT_REGION:
- case DS_BIND_MTD:
- if (!capable(CAP_SYS_ADMIN)) {
- err = -EPERM;
- goto free_out;
- } else {
- printk_once(KERN_WARNING
- "2.6. kernels use pcmciamtd instead of memory_cs.c and do not require special\n");
- printk_once(KERN_WARNING "MTD handling any more.\n");
- }
- err = -EINVAL;
- goto free_out;
- break;
- case DS_GET_FIRST_WINDOW:
- ret = pcmcia_get_window(s, &buf->win_info.handle, 1,
- &buf->win_info.window);
- break;
- case DS_GET_NEXT_WINDOW:
- ret = pcmcia_get_window(s, &buf->win_info.handle,
- buf->win_info.handle + 1, &buf->win_info.window);
- break;
- case DS_GET_MEM_PAGE:
- ret = pcmcia_get_mem_page(s, buf->win_info.handle,
- &buf->win_info.map);
- break;
- case DS_REPLACE_CIS:
- ret = pcmcia_replace_cis(s, buf->cisdump.Data, buf->cisdump.Length);
- break;
- case DS_BIND_REQUEST:
- if (!capable(CAP_SYS_ADMIN)) {
- err = -EPERM;
- goto free_out;
- }
- err = bind_request(s, &buf->bind_info);
- break;
- case DS_GET_DEVICE_INFO:
- err = get_device_info(s, &buf->bind_info, 1);
- break;
- case DS_GET_NEXT_DEVICE:
- err = get_device_info(s, &buf->bind_info, 0);
- break;
- case DS_UNBIND_REQUEST:
- err = 0;
- break;
- default:
- err = -EINVAL;
- }
-
- if ((err == 0) && (ret != 0)) {
- pr_debug("ds_ioctl: ret = %d\n", ret);
- switch (ret) {
- case -ENODEV:
- case -EINVAL:
- case -EBUSY:
- case -ENOSYS:
- err = ret;
- break;
- case -ENOMEM:
- err = -ENOSPC; break;
- case -ENOSPC:
- err = -ENODATA; break;
- default:
- err = -EIO; break;
- }
- }
-
- if (cmd & IOC_OUT) {
- if (__copy_to_user(uarg, (char *)buf, size))
- err = -EFAULT;
- }
-
-free_out:
- kfree(buf);
- return err;
-} /* ds_ioctl */
-
-static long ds_unlocked_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
-{
- int ret;
-
- lock_kernel();
- ret = ds_ioctl(file, cmd, arg);
- unlock_kernel();
-
- return ret;
-}
-
-
-/*====================================================================*/
-
-static const struct file_operations ds_fops = {
- .owner = THIS_MODULE,
- .open = ds_open,
- .release = ds_release,
- .unlocked_ioctl = ds_unlocked_ioctl,
- .read = ds_read,
- .write = ds_write,
- .poll = ds_poll,
-};
-
-void __init pcmcia_setup_ioctl(void)
-{
- int i;
-
- /* Set up character device for user mode clients */
- i = register_chrdev(0, "pcmcia", &ds_fops);
- if (i < 0)
- printk(KERN_NOTICE "unable to find a free device # for "
- "Driver Services (error=%d)\n", i);
- else
- major_dev = i;
-
-#ifdef CONFIG_PROC_FS
- proc_pccard = proc_mkdir("bus/pccard", NULL);
- if (proc_pccard)
- proc_create("drivers", 0, proc_pccard, &pccard_drivers_proc_fops);
-#endif
-}
-
-
-void __exit pcmcia_cleanup_ioctl(void)
-{
-#ifdef CONFIG_PROC_FS
- if (proc_pccard) {
- remove_proc_entry("drivers", proc_pccard);
- remove_proc_entry("bus/pccard", NULL);
- }
-#endif
- if (major_dev != -1)
- unregister_chrdev(major_dev, "pcmcia");
-}
diff --git a/drivers/pcmcia/pcmcia_resource.c b/drivers/pcmcia/pcmcia_resource.c
index a4cd9adfcbc..54aa1c238cb 100644
--- a/drivers/pcmcia/pcmcia_resource.c
+++ b/drivers/pcmcia/pcmcia_resource.c
@@ -25,7 +25,6 @@
#include <asm/irq.h>
-#include <pcmcia/cs_types.h>
#include <pcmcia/ss.h>
#include <pcmcia/cs.h>
#include <pcmcia/cistpl.h>
@@ -57,77 +56,107 @@ struct resource *pcmcia_find_mem_region(u_long base, u_long num, u_long align,
}
+static void release_io_space(struct pcmcia_socket *s, struct resource *res)
+{
+ resource_size_t num = resource_size(res);
+ int i;
+
+ dev_dbg(&s->dev, "release_io_space for %pR\n", res);
+
+ for (i = 0; i < MAX_IO_WIN; i++) {
+ if (!s->io[i].res)
+ continue;
+ if ((s->io[i].res->start <= res->start) &&
+ (s->io[i].res->end >= res->end)) {
+ s->io[i].InUse -= num;
+ if (res->parent)
+ release_resource(res);
+ res->start = res->end = 0;
+ res->flags = IORESOURCE_IO;
+ /* Free the window if no one else is using it */
+ if (s->io[i].InUse == 0) {
+ release_resource(s->io[i].res);
+ kfree(s->io[i].res);
+ s->io[i].res = NULL;
+ }
+ }
+ }
+} /* release_io_space */
+
/** alloc_io_space
*
* Special stuff for managing IO windows, because they are scarce
*/
-
-static int alloc_io_space(struct pcmcia_socket *s, u_int attr,
- unsigned int *base, unsigned int num, u_int lines)
+static int alloc_io_space(struct pcmcia_socket *s, struct resource *res,
+ unsigned int lines)
{
unsigned int align;
+ unsigned int base = res->start;
+ unsigned int num = res->end;
+ int ret;
- align = (*base) ? (lines ? 1<<lines : 0) : 1;
+ res->flags |= IORESOURCE_IO;
+
+ dev_dbg(&s->dev, "alloc_io_space request for %pR, %d lines\n",
+ res, lines);
+
+ align = base ? (lines ? 1<<lines : 0) : 1;
if (align && (align < num)) {
- if (*base) {
- dev_dbg(&s->dev, "odd IO request: num %#x align %#x\n",
- num, align);
+ if (base) {
+ dev_dbg(&s->dev, "odd IO request\n");
align = 0;
} else
while (align && (align < num))
align <<= 1;
}
- if (*base & ~(align-1)) {
- dev_dbg(&s->dev, "odd IO request: base %#x align %#x\n",
- *base, align);
+ if (base & ~(align-1)) {
+ dev_dbg(&s->dev, "odd IO request\n");
align = 0;
}
- return s->resource_ops->find_io(s, attr, base, num, align);
-} /* alloc_io_space */
-
+ ret = s->resource_ops->find_io(s, res->flags, &base, num, align,
+ &res->parent);
+ if (ret) {
+ dev_dbg(&s->dev, "alloc_io_space request failed (%d)\n", ret);
+ return -EINVAL;
+ }
-static void release_io_space(struct pcmcia_socket *s, unsigned int base,
- unsigned int num)
-{
- int i;
+ res->start = base;
+ res->end = res->start + num - 1;
- for (i = 0; i < MAX_IO_WIN; i++) {
- if (!s->io[i].res)
- continue;
- if ((s->io[i].res->start <= base) &&
- (s->io[i].res->end >= base+num-1)) {
- s->io[i].InUse -= num;
- /* Free the window if no one else is using it */
- if (s->io[i].InUse == 0) {
- release_resource(s->io[i].res);
- kfree(s->io[i].res);
- s->io[i].res = NULL;
- }
+ if (res->parent) {
+ ret = request_resource(res->parent, res);
+ if (ret) {
+ dev_warn(&s->dev,
+ "request_resource %pR failed: %d\n", res, ret);
+ res->parent = NULL;
+ release_io_space(s, res);
}
}
-} /* release_io_space */
+ dev_dbg(&s->dev, "alloc_io_space request result %d: %pR\n", ret, res);
+ return ret;
+} /* alloc_io_space */
-/** pccard_access_configuration_register
+/**
+ * pcmcia_access_config() - read or write card configuration registers
*
- * Access_configuration_register() reads and writes configuration
- * registers in attribute memory. Memory window 0 is reserved for
- * this and the tuple reading services.
+ * pcmcia_access_config() reads and writes configuration registers in
+ * attribute memory. Memory window 0 is reserved for this and the tuple
+ * reading services. Drivers must use pcmcia_read_config_byte() or
+ * pcmcia_write_config_byte().
*/
-
-int pcmcia_access_configuration_register(struct pcmcia_device *p_dev,
- conf_reg_t *reg)
+static int pcmcia_access_config(struct pcmcia_device *p_dev,
+ off_t where, u8 *val,
+ int (*accessf) (struct pcmcia_socket *s,
+ int attr, unsigned int addr,
+ unsigned int len, void *ptr))
{
struct pcmcia_socket *s;
config_t *c;
int addr;
- u_char val;
int ret = 0;
- if (!p_dev || !p_dev->function_config)
- return -EINVAL;
-
s = p_dev->socket;
mutex_lock(&s->ops_mutex);
@@ -139,44 +168,57 @@ int pcmcia_access_configuration_register(struct pcmcia_device *p_dev,
return -EACCES;
}
- addr = (c->ConfigBase + reg->Offset) >> 1;
+ addr = (c->ConfigBase + where) >> 1;
+
+ ret = accessf(s, 1, addr, 1, val);
- switch (reg->Action) {
- case CS_READ:
- ret = pcmcia_read_cis_mem(s, 1, addr, 1, &val);
- reg->Value = val;
- break;
- case CS_WRITE:
- val = reg->Value;
- pcmcia_write_cis_mem(s, 1, addr, 1, &val);
- break;
- default:
- dev_dbg(&s->dev, "Invalid conf register request\n");
- ret = -EINVAL;
- break;
- }
mutex_unlock(&s->ops_mutex);
+
return ret;
-} /* pcmcia_access_configuration_register */
-EXPORT_SYMBOL(pcmcia_access_configuration_register);
+} /* pcmcia_access_config */
+
+
+/**
+ * pcmcia_read_config_byte() - read a byte from a card configuration register
+ *
+ * pcmcia_read_config_byte() reads a byte from a configuration register in
+ * attribute memory.
+ */
+int pcmcia_read_config_byte(struct pcmcia_device *p_dev, off_t where, u8 *val)
+{
+ return pcmcia_access_config(p_dev, where, val, pcmcia_read_cis_mem);
+}
+EXPORT_SYMBOL(pcmcia_read_config_byte);
+
+
+/**
+ * pcmcia_write_config_byte() - write a byte to a card configuration register
+ *
+ * pcmcia_write_config_byte() writes a byte to a configuration register in
+ * attribute memory.
+ */
+int pcmcia_write_config_byte(struct pcmcia_device *p_dev, off_t where, u8 val)
+{
+ return pcmcia_access_config(p_dev, where, &val, pcmcia_write_cis_mem);
+}
+EXPORT_SYMBOL(pcmcia_write_config_byte);
int pcmcia_map_mem_page(struct pcmcia_device *p_dev, window_handle_t wh,
- memreq_t *req)
+ unsigned int offset)
{
struct pcmcia_socket *s = p_dev->socket;
+ struct resource *res = wh;
+ unsigned int w;
int ret;
- wh--;
- if (wh >= MAX_WIN)
+ w = ((res->flags & IORESOURCE_BITS & WIN_FLAGS_REQ) >> 2) - 1;
+ if (w >= MAX_WIN)
return -EINVAL;
- if (req->Page != 0) {
- dev_dbg(&s->dev, "failure: requested page is zero\n");
- return -EINVAL;
- }
+
mutex_lock(&s->ops_mutex);
- s->win[wh].card_start = req->CardOffset;
- ret = s->ops->set_mem_map(s, &s->win[wh]);
+ s->win[w].card_start = offset;
+ ret = s->ops->set_mem_map(s, &s->win[w]);
if (ret)
dev_warn(&s->dev, "failed to set_mem_map\n");
mutex_unlock(&s->ops_mutex);
@@ -316,31 +358,25 @@ int pcmcia_release_configuration(struct pcmcia_device *p_dev)
* don't bother checking the port ranges against the current socket
* values.
*/
-static int pcmcia_release_io(struct pcmcia_device *p_dev, io_req_t *req)
+static int pcmcia_release_io(struct pcmcia_device *p_dev)
{
struct pcmcia_socket *s = p_dev->socket;
int ret = -EINVAL;
config_t *c;
mutex_lock(&s->ops_mutex);
- c = p_dev->function_config;
-
if (!p_dev->_io)
goto out;
- p_dev->_io = 0;
+ c = p_dev->function_config;
- if ((c->io.BasePort1 != req->BasePort1) ||
- (c->io.NumPorts1 != req->NumPorts1) ||
- (c->io.BasePort2 != req->BasePort2) ||
- (c->io.NumPorts2 != req->NumPorts2))
- goto out;
+ release_io_space(s, &c->io[0]);
- c->state &= ~CONFIG_IO_REQ;
+ if (c->io[1].end)
+ release_io_space(s, &c->io[1]);
- release_io_space(s, req->BasePort1, req->NumPorts1);
- if (req->NumPorts2)
- release_io_space(s, req->BasePort2, req->NumPorts2);
+ p_dev->_io = 0;
+ c->state &= ~CONFIG_IO_REQ;
out:
mutex_unlock(&s->ops_mutex);
@@ -349,19 +385,22 @@ out:
} /* pcmcia_release_io */
-int pcmcia_release_window(struct pcmcia_device *p_dev, window_handle_t wh)
+int pcmcia_release_window(struct pcmcia_device *p_dev, struct resource *res)
{
struct pcmcia_socket *s = p_dev->socket;
pccard_mem_map *win;
+ unsigned int w;
+
+ dev_dbg(&p_dev->dev, "releasing window %pR\n", res);
- wh--;
- if (wh >= MAX_WIN)
+ w = ((res->flags & IORESOURCE_BITS & WIN_FLAGS_REQ) >> 2) - 1;
+ if (w >= MAX_WIN)
return -EINVAL;
mutex_lock(&s->ops_mutex);
- win = &s->win[wh];
+ win = &s->win[w];
- if (!(p_dev->_win & CLIENT_WIN_REQ(wh))) {
+ if (!(p_dev->_win & CLIENT_WIN_REQ(w))) {
dev_dbg(&s->dev, "not releasing unknown window\n");
mutex_unlock(&s->ops_mutex);
return -EINVAL;
@@ -370,15 +409,16 @@ int pcmcia_release_window(struct pcmcia_device *p_dev, window_handle_t wh)
/* Shut down memory window */
win->flags &= ~MAP_ACTIVE;
s->ops->set_mem_map(s, win);
- s->state &= ~SOCKET_WIN_REQ(wh);
+ s->state &= ~SOCKET_WIN_REQ(w);
/* Release system memory */
if (win->res) {
+ release_resource(res);
release_resource(win->res);
kfree(win->res);
win->res = NULL;
}
- p_dev->_win &= ~CLIENT_WIN_REQ(wh);
+ p_dev->_win &= ~CLIENT_WIN_REQ(w);
mutex_unlock(&s->ops_mutex);
return 0;
@@ -473,13 +513,13 @@ int pcmcia_request_configuration(struct pcmcia_device *p_dev,
pcmcia_write_cis_mem(s, 1, (base + CISREG_ESR)>>1, 1, &c->ExtStatus);
}
if (req->Present & PRESENT_IOBASE_0) {
- u_char b = c->io.BasePort1 & 0xff;
+ u8 b = c->io[0].start & 0xff;
pcmcia_write_cis_mem(s, 1, (base + CISREG_IOBASE_0)>>1, 1, &b);
- b = (c->io.BasePort1 >> 8) & 0xff;
+ b = (c->io[0].start >> 8) & 0xff;
pcmcia_write_cis_mem(s, 1, (base + CISREG_IOBASE_1)>>1, 1, &b);
}
if (req->Present & PRESENT_IOSIZE) {
- u_char b = c->io.NumPorts1 + c->io.NumPorts2 - 1;
+ u8 b = resource_size(&c->io[0]) + resource_size(&c->io[1]) - 1;
pcmcia_write_cis_mem(s, 1, (base + CISREG_IOSIZE)>>1, 1, &b);
}
@@ -513,28 +553,29 @@ int pcmcia_request_configuration(struct pcmcia_device *p_dev,
EXPORT_SYMBOL(pcmcia_request_configuration);
-/** pcmcia_request_io
+/**
+ * pcmcia_request_io() - attempt to reserve port ranges for PCMCIA devices
*
- * Request_io() reserves ranges of port addresses for a socket.
- * I have not implemented range sharing or alias addressing.
+ * pcmcia_request_io() attepts to reserve the IO port ranges specified in
+ * &struct pcmcia_device @p_dev->resource[0] and @p_dev->resource[1]. The
+ * "start" value is the requested start of the IO port resource; "end"
+ * reflects the number of ports requested. The number of IO lines requested
+ * is specified in &struct pcmcia_device @p_dev->io_lines.
*/
-int pcmcia_request_io(struct pcmcia_device *p_dev, io_req_t *req)
+int pcmcia_request_io(struct pcmcia_device *p_dev)
{
struct pcmcia_socket *s = p_dev->socket;
- config_t *c;
+ config_t *c = p_dev->function_config;
int ret = -EINVAL;
mutex_lock(&s->ops_mutex);
+ dev_dbg(&s->dev, "pcmcia_request_io: %pR , %pR", &c->io[0], &c->io[1]);
if (!(s->state & SOCKET_PRESENT)) {
- dev_dbg(&s->dev, "No card present\n");
+ dev_dbg(&s->dev, "pcmcia_request_io: No card present\n");
goto out;
}
- if (!req)
- goto out;
-
- c = p_dev->function_config;
if (c->state & CONFIG_LOCKED) {
dev_dbg(&s->dev, "Configuration is locked\n");
goto out;
@@ -543,40 +584,25 @@ int pcmcia_request_io(struct pcmcia_device *p_dev, io_req_t *req)
dev_dbg(&s->dev, "IO already configured\n");
goto out;
}
- if (req->Attributes1 & (IO_SHARED | IO_FORCE_ALIAS_ACCESS)) {
- dev_dbg(&s->dev, "bad attribute setting for IO region 1\n");
- goto out;
- }
- if ((req->NumPorts2 > 0) &&
- (req->Attributes2 & (IO_SHARED | IO_FORCE_ALIAS_ACCESS))) {
- dev_dbg(&s->dev, "bad attribute setting for IO region 2\n");
- goto out;
- }
- dev_dbg(&s->dev, "trying to allocate resource 1\n");
- ret = alloc_io_space(s, req->Attributes1, &req->BasePort1,
- req->NumPorts1, req->IOAddrLines);
- if (ret) {
- dev_dbg(&s->dev, "allocation of resource 1 failed\n");
+ ret = alloc_io_space(s, &c->io[0], p_dev->io_lines);
+ if (ret)
goto out;
- }
- if (req->NumPorts2) {
- dev_dbg(&s->dev, "trying to allocate resource 2\n");
- ret = alloc_io_space(s, req->Attributes2, &req->BasePort2,
- req->NumPorts2, req->IOAddrLines);
+ if (c->io[1].end) {
+ ret = alloc_io_space(s, &c->io[1], p_dev->io_lines);
if (ret) {
- dev_dbg(&s->dev, "allocation of resource 2 failed\n");
- release_io_space(s, req->BasePort1, req->NumPorts1);
+ release_io_space(s, &c->io[0]);
goto out;
}
- }
+ } else
+ c->io[1].start = 0;
- c->io = *req;
c->state |= CONFIG_IO_REQ;
p_dev->_io = 1;
- dev_dbg(&s->dev, "allocating resources succeeded: %d\n", ret);
+ dev_dbg(&s->dev, "pcmcia_request_io succeeded: %pR , %pR",
+ &c->io[0], &c->io[1]);
out:
mutex_unlock(&s->ops_mutex);
@@ -651,7 +677,7 @@ EXPORT_SYMBOL(__pcmcia_request_exclusive_irq);
#ifdef CONFIG_PCMCIA_PROBE
/* mask of IRQs already reserved by other cards, we should avoid using them */
-static u8 pcmcia_used_irq[NR_IRQS];
+static u8 pcmcia_used_irq[32];
static irqreturn_t test_action(int cpl, void *dev_id)
{
@@ -674,6 +700,9 @@ static int pcmcia_setup_isa_irq(struct pcmcia_device *p_dev, int type)
for (try = 0; try < 64; try++) {
irq = try % 32;
+ if (irq > NR_IRQS)
+ continue;
+
/* marked as available by driver, not blocked by userspace? */
if (!((mask >> irq) & 1))
continue;
@@ -767,23 +796,18 @@ int pcmcia_request_window(struct pcmcia_device *p_dev, win_req_t *req, window_ha
struct pcmcia_socket *s = p_dev->socket;
pccard_mem_map *win;
u_long align;
+ struct resource *res;
int w;
if (!(s->state & SOCKET_PRESENT)) {
dev_dbg(&s->dev, "No card present\n");
return -ENODEV;
}
- if (req->Attributes & (WIN_PAGED | WIN_SHARED)) {
- dev_dbg(&s->dev, "bad attribute setting for iomem region\n");
- return -EINVAL;
- }
/* Window size defaults to smallest available */
if (req->Size == 0)
req->Size = s->map_size;
- align = (((s->features & SS_CAP_MEM_ALIGN) ||
- (req->Attributes & WIN_STRICT_ALIGN)) ?
- req->Size : s->map_size);
+ align = (s->features & SS_CAP_MEM_ALIGN) ? req->Size : s->map_size;
if (req->Size & (s->map_size-1)) {
dev_dbg(&s->dev, "invalid map size\n");
return -EINVAL;
@@ -797,20 +821,21 @@ int pcmcia_request_window(struct pcmcia_device *p_dev, win_req_t *req, window_ha
align = 0;
/* Allocate system memory window */
+ mutex_lock(&s->ops_mutex);
for (w = 0; w < MAX_WIN; w++)
if (!(s->state & SOCKET_WIN_REQ(w)))
break;
if (w == MAX_WIN) {
dev_dbg(&s->dev, "all windows are used already\n");
+ mutex_unlock(&s->ops_mutex);
return -EINVAL;
}
- mutex_lock(&s->ops_mutex);
win = &s->win[w];
if (!(s->features & SS_CAP_STATIC_MAP)) {
win->res = pcmcia_find_mem_region(req->Base, req->Size, align,
- (req->Attributes & WIN_MAP_BELOW_1MB), s);
+ 0, s);
if (!win->res) {
dev_dbg(&s->dev, "allocating mem region failed\n");
mutex_unlock(&s->ops_mutex);
@@ -821,16 +846,8 @@ int pcmcia_request_window(struct pcmcia_device *p_dev, win_req_t *req, window_ha
/* Configure the socket controller */
win->map = w+1;
- win->flags = 0;
+ win->flags = req->Attributes;
win->speed = req->AccessSpeed;
- if (req->Attributes & WIN_MEMORY_TYPE)
- win->flags |= MAP_ATTRIB;
- if (req->Attributes & WIN_ENABLE)
- win->flags |= MAP_ACTIVE;
- if (req->Attributes & WIN_DATA_WIDTH_16)
- win->flags |= MAP_16BIT;
- if (req->Attributes & WIN_USE_WAIT)
- win->flags |= MAP_USE_WAIT;
win->card_start = 0;
if (s->ops->set_mem_map(s, win) != 0) {
@@ -846,8 +863,21 @@ int pcmcia_request_window(struct pcmcia_device *p_dev, win_req_t *req, window_ha
else
req->Base = win->res->start;
+ /* convert to new-style resources */
+ res = p_dev->resource[w + MAX_IO_WIN];
+ res->start = req->Base;
+ res->end = req->Base + req->Size - 1;
+ res->flags &= ~IORESOURCE_BITS;
+ res->flags |= (req->Attributes & WIN_FLAGS_MAP) | (win->map << 2);
+ res->flags |= IORESOURCE_MEM;
+ res->parent = win->res;
+ if (win->res)
+ request_resource(&iomem_resource, res);
+
+ dev_dbg(&s->dev, "request_window results in %pR\n", res);
+
mutex_unlock(&s->ops_mutex);
- *wh = w + 1;
+ *wh = res;
return 0;
} /* pcmcia_request_window */
@@ -855,13 +885,18 @@ EXPORT_SYMBOL(pcmcia_request_window);
void pcmcia_disable_device(struct pcmcia_device *p_dev)
{
+ int i;
+ for (i = 0; i < MAX_WIN; i++) {
+ struct resource *res = p_dev->resource[MAX_IO_WIN + i];
+ if (res->flags & WIN_FLAGS_REQ)
+ pcmcia_release_window(p_dev, res);
+ }
+
pcmcia_release_configuration(p_dev);
- pcmcia_release_io(p_dev, &p_dev->io);
+ pcmcia_release_io(p_dev);
if (p_dev->_irq) {
free_irq(p_dev->irq, p_dev->priv);
p_dev->_irq = 0;
}
- if (p_dev->win)
- pcmcia_release_window(p_dev, p_dev->win);
}
EXPORT_SYMBOL(pcmcia_disable_device);
diff --git a/drivers/pcmcia/pd6729.c b/drivers/pcmcia/pd6729.c
index b61a13663a0..b8a869af0f4 100644
--- a/drivers/pcmcia/pd6729.c
+++ b/drivers/pcmcia/pd6729.c
@@ -17,7 +17,6 @@
#include <linux/device.h>
#include <linux/io.h>
-#include <pcmcia/cs_types.h>
#include <pcmcia/ss.h>
#include <pcmcia/cs.h>
diff --git a/drivers/pcmcia/pxa2xx_base.c b/drivers/pcmcia/pxa2xx_base.c
index f370476d541..ae07b4db8a6 100644
--- a/drivers/pcmcia/pxa2xx_base.c
+++ b/drivers/pcmcia/pxa2xx_base.c
@@ -32,7 +32,6 @@
#include <mach/pxa2xx-regs.h>
#include <asm/mach-types.h>
-#include <pcmcia/cs_types.h>
#include <pcmcia/ss.h>
#include <pcmcia/cistpl.h>
diff --git a/drivers/pcmcia/rsrc_iodyn.c b/drivers/pcmcia/rsrc_iodyn.c
index d0bf3502106..8510c35d295 100644
--- a/drivers/pcmcia/rsrc_iodyn.c
+++ b/drivers/pcmcia/rsrc_iodyn.c
@@ -16,7 +16,6 @@
#include <linux/module.h>
#include <linux/kernel.h>
-#include <pcmcia/cs_types.h>
#include <pcmcia/ss.h>
#include <pcmcia/cs.h>
#include <pcmcia/cistpl.h>
@@ -88,7 +87,7 @@ static struct resource *__iodyn_find_io_region(struct pcmcia_socket *s,
static int iodyn_find_io(struct pcmcia_socket *s, unsigned int attr,
unsigned int *base, unsigned int num,
- unsigned int align)
+ unsigned int align, struct resource **parent)
{
int i, ret = 0;
@@ -129,6 +128,7 @@ static int iodyn_find_io(struct pcmcia_socket *s, unsigned int attr,
((res->flags & ~IORESOURCE_BITS) |
(attr & IORESOURCE_BITS));
s->io[i].InUse = num;
+ *parent = res;
return 0;
}
@@ -140,6 +140,7 @@ static int iodyn_find_io(struct pcmcia_socket *s, unsigned int attr,
continue;
*base = try;
s->io[i].InUse += num;
+ *parent = res;
return 0;
}
@@ -152,6 +153,7 @@ static int iodyn_find_io(struct pcmcia_socket *s, unsigned int attr,
continue;
*base = try;
s->io[i].InUse += num;
+ *parent = res;
return 0;
}
}
@@ -164,8 +166,6 @@ struct pccard_resource_ops pccard_iodyn_ops = {
.validate_mem = NULL,
.find_io = iodyn_find_io,
.find_mem = NULL,
- .add_io = NULL,
- .add_mem = NULL,
.init = static_init,
.exit = NULL,
};
diff --git a/drivers/pcmcia/rsrc_mgr.c b/drivers/pcmcia/rsrc_mgr.c
index 142efac3c38..4e80421fd90 100644
--- a/drivers/pcmcia/rsrc_mgr.c
+++ b/drivers/pcmcia/rsrc_mgr.c
@@ -16,7 +16,6 @@
#include <linux/module.h>
#include <linux/kernel.h>
-#include <pcmcia/cs_types.h>
#include <pcmcia/ss.h>
#include <pcmcia/cs.h>
#include <pcmcia/cistpl.h>
@@ -48,11 +47,12 @@ struct resource *pcmcia_make_resource(unsigned long start, unsigned long end,
static int static_find_io(struct pcmcia_socket *s, unsigned int attr,
unsigned int *base, unsigned int num,
- unsigned int align)
+ unsigned int align, struct resource **parent)
{
if (!s->io_offset)
return -EINVAL;
*base = s->io_offset | (*base & 0x0fff);
+ *parent = NULL;
return 0;
}
@@ -62,8 +62,6 @@ struct pccard_resource_ops pccard_static_ops = {
.validate_mem = NULL,
.find_io = static_find_io,
.find_mem = NULL,
- .add_io = NULL,
- .add_mem = NULL,
.init = static_init,
.exit = NULL,
};
diff --git a/drivers/pcmcia/rsrc_nonstatic.c b/drivers/pcmcia/rsrc_nonstatic.c
index dcd1a4ad3d6..96f348b35fd 100644
--- a/drivers/pcmcia/rsrc_nonstatic.c
+++ b/drivers/pcmcia/rsrc_nonstatic.c
@@ -28,7 +28,6 @@
#include <asm/irq.h>
-#include <pcmcia/cs_types.h>
#include <pcmcia/ss.h>
#include <pcmcia/cs.h>
#include <pcmcia/cistpl.h>
@@ -64,6 +63,9 @@ struct socket_data {
#define MEM_PROBE_LOW (1 << 0)
#define MEM_PROBE_HIGH (1 << 1)
+/* Action field */
+#define REMOVE_MANAGED_RESOURCE 1
+#define ADD_MANAGED_RESOURCE 2
/*======================================================================
@@ -716,7 +718,7 @@ static struct resource *__nonstatic_find_io_region(struct pcmcia_socket *s,
static int nonstatic_find_io(struct pcmcia_socket *s, unsigned int attr,
unsigned int *base, unsigned int num,
- unsigned int align)
+ unsigned int align, struct resource **parent)
{
int i, ret = 0;
@@ -758,6 +760,7 @@ static int nonstatic_find_io(struct pcmcia_socket *s, unsigned int attr,
((res->flags & ~IORESOURCE_BITS) |
(attr & IORESOURCE_BITS));
s->io[i].InUse = num;
+ *parent = res;
return 0;
}
@@ -773,6 +776,7 @@ static int nonstatic_find_io(struct pcmcia_socket *s, unsigned int attr,
continue;
*base = try;
s->io[i].InUse += num;
+ *parent = res;
return 0;
}
}
@@ -791,6 +795,7 @@ static int nonstatic_find_io(struct pcmcia_socket *s, unsigned int attr,
continue;
*base = try;
s->io[i].InUse += num;
+ *parent = res;
return 0;
}
}
@@ -1055,8 +1060,6 @@ struct pccard_resource_ops pccard_nonstatic_ops = {
.validate_mem = pcmcia_nonstatic_validate_mem,
.find_io = nonstatic_find_io,
.find_mem = nonstatic_find_mem_region,
- .add_io = adjust_io,
- .add_mem = adjust_memory,
.init = nonstatic_init,
.exit = nonstatic_release_resource_db,
};
@@ -1115,8 +1118,6 @@ static ssize_t store_io_db(struct device *dev,
mutex_lock(&s->ops_mutex);
ret = adjust_io(s, add, start_addr, end_addr);
- if (!ret)
- s->resource_setup_new = 1;
mutex_unlock(&s->ops_mutex);
return ret ? ret : count;
@@ -1183,8 +1184,6 @@ static ssize_t store_mem_db(struct device *dev,
mutex_lock(&s->ops_mutex);
ret = adjust_memory(s, add, start_addr, end_addr);
- if (!ret)
- s->resource_setup_new = 1;
mutex_unlock(&s->ops_mutex);
return ret ? ret : count;
diff --git a/drivers/pcmcia/sa1100_generic.c b/drivers/pcmcia/sa1100_generic.c
index edbd8c47262..e0985148029 100644
--- a/drivers/pcmcia/sa1100_generic.c
+++ b/drivers/pcmcia/sa1100_generic.c
@@ -35,7 +35,6 @@
#include <linux/slab.h>
#include <linux/platform_device.h>
-#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/ss.h>
diff --git a/drivers/pcmcia/sa11xx_base.c b/drivers/pcmcia/sa11xx_base.c
index fa28d8911b0..0c62fe31a40 100644
--- a/drivers/pcmcia/sa11xx_base.c
+++ b/drivers/pcmcia/sa11xx_base.c
@@ -231,7 +231,7 @@ int sa11xx_drv_pcmcia_probe(struct device *dev, struct pcmcia_low_level *ops,
sinfo->nskt = nr;
- /* Initiliaze processor specific parameters */
+ /* Initialize processor specific parameters */
for (i = 0; i < nr; i++) {
skt = &sinfo->skt[i];
diff --git a/drivers/pcmcia/soc_common.h b/drivers/pcmcia/soc_common.h
index e40824ce6b0..3fba3a67912 100644
--- a/drivers/pcmcia/soc_common.h
+++ b/drivers/pcmcia/soc_common.h
@@ -11,7 +11,6 @@
/* include the world */
#include <linux/cpufreq.h>
-#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/ss.h>
#include <pcmcia/cistpl.h>
diff --git a/drivers/pcmcia/socket_sysfs.c b/drivers/pcmcia/socket_sysfs.c
index 80e36bc407d..cb0d3ace18b 100644
--- a/drivers/pcmcia/socket_sysfs.c
+++ b/drivers/pcmcia/socket_sysfs.c
@@ -26,7 +26,6 @@
#include <asm/system.h>
#include <asm/irq.h>
-#include <pcmcia/cs_types.h>
#include <pcmcia/ss.h>
#include <pcmcia/cs.h>
#include <pcmcia/cistpl.h>
diff --git a/drivers/pcmcia/tcic.c b/drivers/pcmcia/tcic.c
index 56004a1b5bb..be0d841c7eb 100644
--- a/drivers/pcmcia/tcic.c
+++ b/drivers/pcmcia/tcic.c
@@ -49,7 +49,6 @@
#include <asm/io.h>
#include <asm/system.h>
-#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/ss.h>
#include "tcic.h"
diff --git a/drivers/pcmcia/xxs1500_ss.c b/drivers/pcmcia/xxs1500_ss.c
index 201ccfa1e97..fa88c360c37 100644
--- a/drivers/pcmcia/xxs1500_ss.c
+++ b/drivers/pcmcia/xxs1500_ss.c
@@ -17,7 +17,6 @@
#include <linux/slab.h>
#include <linux/spinlock.h>
-#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/ss.h>
#include <pcmcia/cistpl.h>
diff --git a/drivers/pcmcia/yenta_socket.c b/drivers/pcmcia/yenta_socket.c
index f1d41374eea..414d9a6f9a3 100644
--- a/drivers/pcmcia/yenta_socket.c
+++ b/drivers/pcmcia/yenta_socket.c
@@ -19,7 +19,6 @@
#include <linux/io.h>
#include <linux/slab.h>
-#include <pcmcia/cs_types.h>
#include <pcmcia/ss.h>
#include <pcmcia/cs.h>
diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
index 3e1b8a28871..79baa6368f7 100644
--- a/drivers/platform/x86/Kconfig
+++ b/drivers/platform/x86/Kconfig
@@ -5,6 +5,7 @@
menuconfig X86_PLATFORM_DEVICES
bool "X86 Platform Specific Device Drivers"
default y
+ depends on X86
---help---
Say Y here to get to see options for device drivers for various
x86 platforms, including vendor-specific laptop extension drivers.
@@ -151,6 +152,7 @@ config MSI_LAPTOP
depends on ACPI
depends on BACKLIGHT_CLASS_DEVICE
depends on RFKILL
+ depends on SERIO_I8042
---help---
This is a driver for laptops built by MSI (MICRO-STAR
INTERNATIONAL):
@@ -181,6 +183,8 @@ config COMPAL_LAPTOP
depends on ACPI
depends on BACKLIGHT_CLASS_DEVICE
depends on RFKILL
+ depends on HWMON
+ depends on POWER_SUPPLY
---help---
This is a driver for laptops built by Compal:
@@ -520,6 +524,7 @@ config TOSHIBA_BT_RFKILL
config ACPI_CMPC
tristate "CMPC Laptop Extras"
depends on X86 && ACPI
+ depends on RFKILL || RFKILL=n
select INPUT
select BACKLIGHT_CLASS_DEVICE
default n
@@ -537,4 +542,43 @@ config INTEL_SCU_IPC
some embedded Intel x86 platforms. This is not needed for PC-type
machines.
+config GPIO_INTEL_PMIC
+ bool "Intel PMIC GPIO support"
+ depends on INTEL_SCU_IPC && GPIOLIB
+ ---help---
+ Say Y here to support GPIO via the SCU IPC interface
+ on Intel MID platforms.
+
+config RAR_REGISTER
+ bool "Restricted Access Region Register Driver"
+ depends on PCI && X86_MRST
+ default n
+ ---help---
+ This driver allows other kernel drivers access to the
+ contents of the restricted access region control registers.
+
+ The restricted access region control registers
+ (rar_registers) are used to pass address and
+ locking information on restricted access regions
+ to other drivers that use restricted access regions.
+
+ The restricted access regions are regions of memory
+ on the Intel MID Platform that are not accessible to
+ the x86 processor, but are accessible to dedicated
+ processors on board peripheral devices.
+
+ The purpose of the restricted access regions is to
+ protect sensitive data from compromise by unauthorized
+ programs running on the x86 processor.
+
+config INTEL_IPS
+ tristate "Intel Intelligent Power Sharing"
+ depends on ACPI
+ ---help---
+ Intel Calpella platforms support dynamic power sharing between the
+ CPU and GPU, maximizing performance in a given TDP. This driver,
+ along with the CPU frequency and i915 drivers, provides that
+ functionality. If in doubt, say Y here; it will only load on
+ supported platforms.
+
endif # X86_PLATFORM_DEVICES
diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile
index 8770bfe7143..4744c7744ff 100644
--- a/drivers/platform/x86/Makefile
+++ b/drivers/platform/x86/Makefile
@@ -26,3 +26,7 @@ obj-$(CONFIG_TOPSTAR_LAPTOP) += topstar-laptop.o
obj-$(CONFIG_ACPI_TOSHIBA) += toshiba_acpi.o
obj-$(CONFIG_TOSHIBA_BT_RFKILL) += toshiba_bluetooth.o
obj-$(CONFIG_INTEL_SCU_IPC) += intel_scu_ipc.o
+obj-$(CONFIG_RAR_REGISTER) += intel_rar_register.o
+obj-$(CONFIG_INTEL_IPS) += intel_ips.o
+obj-$(CONFIG_GPIO_INTEL_PMIC) += intel_pmic_gpio.o
+
diff --git a/drivers/platform/x86/acer-wmi.c b/drivers/platform/x86/acer-wmi.c
index 1ea6c434d33..2badee2fdee 100644
--- a/drivers/platform/x86/acer-wmi.c
+++ b/drivers/platform/x86/acer-wmi.c
@@ -50,17 +50,6 @@ MODULE_LICENSE("GPL");
#define ACER_INFO KERN_INFO ACER_LOGPREFIX
/*
- * The following defines quirks to get some specific functions to work
- * which are known to not be supported over ACPI-WMI (such as the mail LED
- * on WMID based Acer's)
- */
-struct acer_quirks {
- const char *vendor;
- const char *model;
- u16 quirks;
-};
-
-/*
* Magic Number
* Meaning is unknown - this number is required for writing to ACPI for AMW0
* (it's also used in acerhk when directly accessing the BIOS)
@@ -200,7 +189,7 @@ static void set_quirks(void)
static int dmi_matched(const struct dmi_system_id *dmi)
{
quirks = dmi->driver_data;
- return 0;
+ return 1;
}
static struct quirk_entry quirk_unknown = {
@@ -555,6 +544,7 @@ static acpi_status AMW0_find_mailled(void)
obj->buffer.length == sizeof(struct wmab_ret)) {
ret = *((struct wmab_ret *) obj->buffer.pointer);
} else {
+ kfree(out.pointer);
return AE_ERROR;
}
@@ -570,7 +560,7 @@ static acpi_status AMW0_set_capabilities(void)
{
struct wmab_args args;
struct wmab_ret ret;
- acpi_status status = AE_OK;
+ acpi_status status;
struct acpi_buffer out = { ACPI_ALLOCATE_BUFFER, NULL };
union acpi_object *obj;
@@ -593,12 +583,13 @@ static acpi_status AMW0_set_capabilities(void)
if (ACPI_FAILURE(status))
return status;
- obj = (union acpi_object *) out.pointer;
+ obj = out.pointer;
if (obj && obj->type == ACPI_TYPE_BUFFER &&
obj->buffer.length == sizeof(struct wmab_ret)) {
ret = *((struct wmab_ret *) obj->buffer.pointer);
} else {
- return AE_ERROR;
+ status = AE_ERROR;
+ goto out;
}
if (ret.eax & 0x1)
@@ -607,23 +598,26 @@ static acpi_status AMW0_set_capabilities(void)
args.ebx = 2 << 8;
args.ebx |= ACER_AMW0_BLUETOOTH_MASK;
+ /*
+ * It's ok to use existing buffer for next wmab_execute call.
+ * But we need to kfree(out.pointer) if next wmab_execute fail.
+ */
status = wmab_execute(&args, &out);
if (ACPI_FAILURE(status))
- return status;
+ goto out;
obj = (union acpi_object *) out.pointer;
if (obj && obj->type == ACPI_TYPE_BUFFER
&& obj->buffer.length == sizeof(struct wmab_ret)) {
ret = *((struct wmab_ret *) obj->buffer.pointer);
} else {
- return AE_ERROR;
+ status = AE_ERROR;
+ goto out;
}
if (ret.eax & 0x1)
interface->capability |= ACER_CAP_BLUETOOTH;
- kfree(out.pointer);
-
/*
* This appears to be safe to enable, since all Wistron based laptops
* appear to use the same EC register for brightness, even if they
@@ -632,7 +626,10 @@ static acpi_status AMW0_set_capabilities(void)
if (quirks->brightness >= 0)
interface->capability |= ACER_CAP_BRIGHTNESS;
- return AE_OK;
+ status = AE_OK;
+out:
+ kfree(out.pointer);
+ return status;
}
static struct wmi_interface AMW0_interface = {
@@ -772,6 +769,7 @@ static acpi_status WMID_set_capabilities(void)
obj->buffer.length == sizeof(u32)) {
devices = *((u32 *) obj->buffer.pointer);
} else {
+ kfree(out.pointer);
return AE_ERROR;
}
@@ -788,6 +786,7 @@ static acpi_status WMID_set_capabilities(void)
if (!(devices & 0x20))
max_brightness = 0x9;
+ kfree(out.pointer);
return status;
}
@@ -1084,8 +1083,7 @@ static ssize_t show_interface(struct device *dev, struct device_attribute *attr,
}
}
-static DEVICE_ATTR(interface, S_IWUGO | S_IRUGO | S_IWUSR,
- show_interface, NULL);
+static DEVICE_ATTR(interface, S_IRUGO, show_interface, NULL);
/*
* debugfs functions
@@ -1095,6 +1093,7 @@ static u32 get_wmid_devices(void)
struct acpi_buffer out = {ACPI_ALLOCATE_BUFFER, NULL};
union acpi_object *obj;
acpi_status status;
+ u32 devices = 0;
status = wmi_query_block(WMID_GUID2, 1, &out);
if (ACPI_FAILURE(status))
@@ -1103,10 +1102,11 @@ static u32 get_wmid_devices(void)
obj = (union acpi_object *) out.pointer;
if (obj && obj->type == ACPI_TYPE_BUFFER &&
obj->buffer.length == sizeof(u32)) {
- return *((u32 *) obj->buffer.pointer);
- } else {
- return 0;
+ devices = *((u32 *) obj->buffer.pointer);
}
+
+ kfree(out.pointer);
+ return devices;
}
/*
@@ -1327,22 +1327,31 @@ static int __init acer_wmi_init(void)
"generic video driver\n");
}
- if (platform_driver_register(&acer_platform_driver)) {
+ err = platform_driver_register(&acer_platform_driver);
+ if (err) {
printk(ACER_ERR "Unable to register platform driver.\n");
goto error_platform_register;
}
+
acer_platform_device = platform_device_alloc("acer-wmi", -1);
- platform_device_add(acer_platform_device);
+ if (!acer_platform_device) {
+ err = -ENOMEM;
+ goto error_device_alloc;
+ }
+
+ err = platform_device_add(acer_platform_device);
+ if (err)
+ goto error_device_add;
err = create_sysfs();
if (err)
- return err;
+ goto error_create_sys;
if (wmi_has_guid(WMID_GUID2)) {
interface->debug.wmid_devices = get_wmid_devices();
err = create_debugfs();
if (err)
- return err;
+ goto error_create_debugfs;
}
/* Override any initial settings with values from the commandline */
@@ -1350,15 +1359,23 @@ static int __init acer_wmi_init(void)
return 0;
+error_create_debugfs:
+ remove_sysfs(acer_platform_device);
+error_create_sys:
+ platform_device_del(acer_platform_device);
+error_device_add:
+ platform_device_put(acer_platform_device);
+error_device_alloc:
+ platform_driver_unregister(&acer_platform_driver);
error_platform_register:
- return -ENODEV;
+ return err;
}
static void __exit acer_wmi_exit(void)
{
remove_sysfs(acer_platform_device);
remove_debugfs();
- platform_device_del(acer_platform_device);
+ platform_device_unregister(acer_platform_device);
platform_driver_unregister(&acer_platform_driver);
printk(ACER_INFO "Acer Laptop WMI Extras unloaded\n");
diff --git a/drivers/platform/x86/acerhdf.c b/drivers/platform/x86/acerhdf.c
index 7b2384d674d..60f9cfcac93 100644
--- a/drivers/platform/x86/acerhdf.c
+++ b/drivers/platform/x86/acerhdf.c
@@ -52,7 +52,7 @@
*/
#undef START_IN_KERNEL_MODE
-#define DRV_VER "0.5.22"
+#define DRV_VER "0.5.24"
/*
* According to the Atom N270 datasheet,
@@ -92,9 +92,9 @@ static unsigned int fanstate = ACERHDF_FAN_AUTO;
static char force_bios[16];
static char force_product[16];
static unsigned int prev_interval;
-struct thermal_zone_device *thz_dev;
-struct thermal_cooling_device *cl_dev;
-struct platform_device *acerhdf_dev;
+static struct thermal_zone_device *thz_dev;
+static struct thermal_cooling_device *cl_dev;
+static struct platform_device *acerhdf_dev;
module_param(kernelmode, uint, 0);
MODULE_PARM_DESC(kernelmode, "Kernel mode fan control on / off");
@@ -112,14 +112,12 @@ module_param_string(force_product, force_product, 16, 0);
MODULE_PARM_DESC(force_product, "Force BIOS product and omit BIOS check");
/*
- * cmd_off: to switch the fan completely off
- * chk_off: to check if the fan is off
+ * cmd_off: to switch the fan completely off and check if the fan is off
* cmd_auto: to set the BIOS in control of the fan. The BIOS regulates then
* the fan speed depending on the temperature
*/
struct fancmd {
u8 cmd_off;
- u8 chk_off;
u8 cmd_auto;
};
@@ -136,47 +134,81 @@ struct bios_settings_t {
/* Register addresses and values for different BIOS versions */
static const struct bios_settings_t bios_tbl[] = {
/* AOA110 */
- {"Acer", "AOA110", "v0.3109", 0x55, 0x58, {0x1f, 0x1f, 0x00} },
- {"Acer", "AOA110", "v0.3114", 0x55, 0x58, {0x1f, 0x1f, 0x00} },
- {"Acer", "AOA110", "v0.3301", 0x55, 0x58, {0xaf, 0xaf, 0x00} },
- {"Acer", "AOA110", "v0.3304", 0x55, 0x58, {0xaf, 0xaf, 0x00} },
- {"Acer", "AOA110", "v0.3305", 0x55, 0x58, {0xaf, 0xaf, 0x00} },
- {"Acer", "AOA110", "v0.3307", 0x55, 0x58, {0xaf, 0xaf, 0x00} },
- {"Acer", "AOA110", "v0.3308", 0x55, 0x58, {0x21, 0x21, 0x00} },
- {"Acer", "AOA110", "v0.3309", 0x55, 0x58, {0x21, 0x21, 0x00} },
- {"Acer", "AOA110", "v0.3310", 0x55, 0x58, {0x21, 0x21, 0x00} },
+ {"Acer", "AOA110", "v0.3109", 0x55, 0x58, {0x1f, 0x00} },
+ {"Acer", "AOA110", "v0.3114", 0x55, 0x58, {0x1f, 0x00} },
+ {"Acer", "AOA110", "v0.3301", 0x55, 0x58, {0xaf, 0x00} },
+ {"Acer", "AOA110", "v0.3304", 0x55, 0x58, {0xaf, 0x00} },
+ {"Acer", "AOA110", "v0.3305", 0x55, 0x58, {0xaf, 0x00} },
+ {"Acer", "AOA110", "v0.3307", 0x55, 0x58, {0xaf, 0x00} },
+ {"Acer", "AOA110", "v0.3308", 0x55, 0x58, {0x21, 0x00} },
+ {"Acer", "AOA110", "v0.3309", 0x55, 0x58, {0x21, 0x00} },
+ {"Acer", "AOA110", "v0.3310", 0x55, 0x58, {0x21, 0x00} },
/* AOA150 */
- {"Acer", "AOA150", "v0.3114", 0x55, 0x58, {0x20, 0x20, 0x00} },
- {"Acer", "AOA150", "v0.3301", 0x55, 0x58, {0x20, 0x20, 0x00} },
- {"Acer", "AOA150", "v0.3304", 0x55, 0x58, {0x20, 0x20, 0x00} },
- {"Acer", "AOA150", "v0.3305", 0x55, 0x58, {0x20, 0x20, 0x00} },
- {"Acer", "AOA150", "v0.3307", 0x55, 0x58, {0x20, 0x20, 0x00} },
- {"Acer", "AOA150", "v0.3308", 0x55, 0x58, {0x20, 0x20, 0x00} },
- {"Acer", "AOA150", "v0.3309", 0x55, 0x58, {0x20, 0x20, 0x00} },
- {"Acer", "AOA150", "v0.3310", 0x55, 0x58, {0x20, 0x20, 0x00} },
+ {"Acer", "AOA150", "v0.3114", 0x55, 0x58, {0x1f, 0x00} },
+ {"Acer", "AOA150", "v0.3301", 0x55, 0x58, {0x20, 0x00} },
+ {"Acer", "AOA150", "v0.3304", 0x55, 0x58, {0x20, 0x00} },
+ {"Acer", "AOA150", "v0.3305", 0x55, 0x58, {0x20, 0x00} },
+ {"Acer", "AOA150", "v0.3307", 0x55, 0x58, {0x20, 0x00} },
+ {"Acer", "AOA150", "v0.3308", 0x55, 0x58, {0x20, 0x00} },
+ {"Acer", "AOA150", "v0.3309", 0x55, 0x58, {0x20, 0x00} },
+ {"Acer", "AOA150", "v0.3310", 0x55, 0x58, {0x20, 0x00} },
/* Acer 1410 */
- {"Acer", "Aspire 1410", "v0.3120", 0x55, 0x58, {0x9e, 0x9e, 0x00} },
- {"Acer", "Aspire 1410", "v1.3303", 0x55, 0x58, {0x9e, 0x9e, 0x00} },
+ {"Acer", "Aspire 1410", "v0.3108", 0x55, 0x58, {0x9e, 0x00} },
+ {"Acer", "Aspire 1410", "v0.3113", 0x55, 0x58, {0x9e, 0x00} },
+ {"Acer", "Aspire 1410", "v0.3115", 0x55, 0x58, {0x9e, 0x00} },
+ {"Acer", "Aspire 1410", "v0.3117", 0x55, 0x58, {0x9e, 0x00} },
+ {"Acer", "Aspire 1410", "v0.3119", 0x55, 0x58, {0x9e, 0x00} },
+ {"Acer", "Aspire 1410", "v0.3120", 0x55, 0x58, {0x9e, 0x00} },
+ {"Acer", "Aspire 1410", "v1.3204", 0x55, 0x58, {0x9e, 0x00} },
+ {"Acer", "Aspire 1410", "v1.3303", 0x55, 0x58, {0x9e, 0x00} },
+ {"Acer", "Aspire 1410", "v1.3308", 0x55, 0x58, {0x9e, 0x00} },
+ {"Acer", "Aspire 1410", "v1.3310", 0x55, 0x58, {0x9e, 0x00} },
/* Acer 1810xx */
- {"Acer", "Aspire 1810TZ", "v0.3120", 0x55, 0x58, {0x9e, 0x9e, 0x00} },
- {"Acer", "Aspire 1810T", "v0.3120", 0x55, 0x58, {0x9e, 0x9e, 0x00} },
- {"Acer", "Aspire 1810T", "v1.3303", 0x55, 0x58, {0x9e, 0x9e, 0x00} },
- {"Acer", "Aspire 1810TZ", "v1.3303", 0x55, 0x58, {0x9e, 0x9e, 0x00} },
+ {"Acer", "Aspire 1810TZ", "v0.3108", 0x55, 0x58, {0x9e, 0x00} },
+ {"Acer", "Aspire 1810T", "v0.3108", 0x55, 0x58, {0x9e, 0x00} },
+ {"Acer", "Aspire 1810TZ", "v0.3113", 0x55, 0x58, {0x9e, 0x00} },
+ {"Acer", "Aspire 1810T", "v0.3113", 0x55, 0x58, {0x9e, 0x00} },
+ {"Acer", "Aspire 1810TZ", "v0.3115", 0x55, 0x58, {0x9e, 0x00} },
+ {"Acer", "Aspire 1810T", "v0.3115", 0x55, 0x58, {0x9e, 0x00} },
+ {"Acer", "Aspire 1810TZ", "v0.3117", 0x55, 0x58, {0x9e, 0x00} },
+ {"Acer", "Aspire 1810T", "v0.3117", 0x55, 0x58, {0x9e, 0x00} },
+ {"Acer", "Aspire 1810TZ", "v0.3119", 0x55, 0x58, {0x9e, 0x00} },
+ {"Acer", "Aspire 1810T", "v0.3119", 0x55, 0x58, {0x9e, 0x00} },
+ {"Acer", "Aspire 1810TZ", "v0.3120", 0x55, 0x58, {0x9e, 0x00} },
+ {"Acer", "Aspire 1810T", "v0.3120", 0x55, 0x58, {0x9e, 0x00} },
+ {"Acer", "Aspire 1810TZ", "v1.3204", 0x55, 0x58, {0x9e, 0x00} },
+ {"Acer", "Aspire 1810T", "v1.3204", 0x55, 0x58, {0x9e, 0x00} },
+ {"Acer", "Aspire 1810TZ", "v1.3303", 0x55, 0x58, {0x9e, 0x00} },
+ {"Acer", "Aspire 1810T", "v1.3303", 0x55, 0x58, {0x9e, 0x00} },
+ {"Acer", "Aspire 1810TZ", "v1.3308", 0x55, 0x58, {0x9e, 0x00} },
+ {"Acer", "Aspire 1810T", "v1.3308", 0x55, 0x58, {0x9e, 0x00} },
+ {"Acer", "Aspire 1810TZ", "v1.3310", 0x55, 0x58, {0x9e, 0x00} },
+ {"Acer", "Aspire 1810T", "v1.3310", 0x55, 0x58, {0x9e, 0x00} },
+ /* Acer 531 */
+ {"Acer", "AO531h", "v0.3201", 0x55, 0x58, {0x20, 0x00} },
/* Gateway */
- {"Gateway", "AOA110", "v0.3103", 0x55, 0x58, {0x21, 0x21, 0x00} },
- {"Gateway", "AOA150", "v0.3103", 0x55, 0x58, {0x20, 0x20, 0x00} },
- {"Gateway", "LT31", "v1.3103", 0x55, 0x58, {0x10, 0x0f, 0x00} },
- {"Gateway", "LT31", "v1.3201", 0x55, 0x58, {0x10, 0x0f, 0x00} },
- {"Gateway", "LT31", "v1.3302", 0x55, 0x58, {0x10, 0x0f, 0x00} },
+ {"Gateway", "AOA110", "v0.3103", 0x55, 0x58, {0x21, 0x00} },
+ {"Gateway", "AOA150", "v0.3103", 0x55, 0x58, {0x20, 0x00} },
+ {"Gateway", "LT31", "v1.3103", 0x55, 0x58, {0x9e, 0x00} },
+ {"Gateway", "LT31", "v1.3201", 0x55, 0x58, {0x9e, 0x00} },
+ {"Gateway", "LT31", "v1.3302", 0x55, 0x58, {0x9e, 0x00} },
/* Packard Bell */
- {"Packard Bell", "DOA150", "v0.3104", 0x55, 0x58, {0x21, 0x21, 0x00} },
- {"Packard Bell", "DOA150", "v0.3105", 0x55, 0x58, {0x20, 0x20, 0x00} },
- {"Packard Bell", "AOA110", "v0.3105", 0x55, 0x58, {0x21, 0x21, 0x00} },
- {"Packard Bell", "AOA150", "v0.3105", 0x55, 0x58, {0x20, 0x20, 0x00} },
- {"Packard Bell", "DOTMU", "v1.3303", 0x55, 0x58, {0x9e, 0x9e, 0x00} },
- {"Packard Bell", "DOTMU", "v0.3120", 0x55, 0x58, {0x9e, 0x9e, 0x00} },
+ {"Packard Bell", "DOA150", "v0.3104", 0x55, 0x58, {0x21, 0x00} },
+ {"Packard Bell", "DOA150", "v0.3105", 0x55, 0x58, {0x20, 0x00} },
+ {"Packard Bell", "AOA110", "v0.3105", 0x55, 0x58, {0x21, 0x00} },
+ {"Packard Bell", "AOA150", "v0.3105", 0x55, 0x58, {0x20, 0x00} },
+ {"Packard Bell", "DOTMU", "v1.3303", 0x55, 0x58, {0x9e, 0x00} },
+ {"Packard Bell", "DOTMU", "v0.3120", 0x55, 0x58, {0x9e, 0x00} },
+ {"Packard Bell", "DOTMU", "v0.3108", 0x55, 0x58, {0x9e, 0x00} },
+ {"Packard Bell", "DOTMU", "v0.3113", 0x55, 0x58, {0x9e, 0x00} },
+ {"Packard Bell", "DOTMU", "v0.3115", 0x55, 0x58, {0x9e, 0x00} },
+ {"Packard Bell", "DOTMU", "v0.3117", 0x55, 0x58, {0x9e, 0x00} },
+ {"Packard Bell", "DOTMU", "v0.3119", 0x55, 0x58, {0x9e, 0x00} },
+ {"Packard Bell", "DOTMU", "v1.3204", 0x55, 0x58, {0x9e, 0x00} },
+ {"Packard Bell", "DOTMA", "v1.3201", 0x55, 0x58, {0x9e, 0x00} },
+ {"Packard Bell", "DOTMA", "v1.3302", 0x55, 0x58, {0x9e, 0x00} },
/* pewpew-terminator */
- {"", "", "", 0, 0, {0, 0, 0} }
+ {"", "", "", 0, 0, {0, 0} }
};
static const struct bios_settings_t *bios_cfg __read_mostly;
@@ -200,7 +232,7 @@ static int acerhdf_get_fanstate(int *state)
if (ec_read(bios_cfg->fanreg, &fan))
return -EINVAL;
- if (fan != bios_cfg->cmd.chk_off)
+ if (fan != bios_cfg->cmd.cmd_off)
*state = ACERHDF_FAN_AUTO;
else
*state = ACERHDF_FAN_OFF;
@@ -374,7 +406,7 @@ static int acerhdf_get_crit_temp(struct thermal_zone_device *thermal,
}
/* bind callback functions to thermalzone */
-struct thermal_zone_device_ops acerhdf_dev_ops = {
+static struct thermal_zone_device_ops acerhdf_dev_ops = {
.bind = acerhdf_bind,
.unbind = acerhdf_unbind,
.get_temp = acerhdf_get_ec_temp,
@@ -449,7 +481,7 @@ err_out:
}
/* bind fan callbacks to fan device */
-struct thermal_cooling_device_ops acerhdf_cooling_ops = {
+static struct thermal_cooling_device_ops acerhdf_cooling_ops = {
.get_max_state = acerhdf_get_max_state,
.get_cur_state = acerhdf_get_cur_state,
.set_cur_state = acerhdf_set_cur_state,
@@ -518,6 +550,10 @@ static int acerhdf_check_hardware(void)
version = dmi_get_system_info(DMI_BIOS_VERSION);
product = dmi_get_system_info(DMI_PRODUCT_NAME);
+ if (!vendor || !version || !product) {
+ pr_err("error getting hardware information\n");
+ return -EINVAL;
+ }
pr_info("Acer Aspire One Fan driver, v.%s\n", DRV_VER);
@@ -579,17 +615,26 @@ static int acerhdf_register_platform(void)
return err;
acerhdf_dev = platform_device_alloc("acerhdf", -1);
- platform_device_add(acerhdf_dev);
+ if (!acerhdf_dev) {
+ err = -ENOMEM;
+ goto err_device_alloc;
+ }
+ err = platform_device_add(acerhdf_dev);
+ if (err)
+ goto err_device_add;
return 0;
+
+err_device_add:
+ platform_device_put(acerhdf_dev);
+err_device_alloc:
+ platform_driver_unregister(&acerhdf_driver);
+ return err;
}
static void acerhdf_unregister_platform(void)
{
- if (!acerhdf_dev)
- return;
-
- platform_device_del(acerhdf_dev);
+ platform_device_unregister(acerhdf_dev);
platform_driver_unregister(&acerhdf_driver);
}
@@ -633,7 +678,7 @@ static int __init acerhdf_init(void)
err = acerhdf_register_platform();
if (err)
- goto err_unreg;
+ goto out_err;
err = acerhdf_register_thermal();
if (err)
@@ -646,7 +691,7 @@ err_unreg:
acerhdf_unregister_platform();
out_err:
- return -ENODEV;
+ return err;
}
static void __exit acerhdf_exit(void)
@@ -662,11 +707,13 @@ MODULE_DESCRIPTION("Aspire One temperature and fan driver");
MODULE_ALIAS("dmi:*:*Acer*:pnAOA*:");
MODULE_ALIAS("dmi:*:*Acer*:pnAspire 1410*:");
MODULE_ALIAS("dmi:*:*Acer*:pnAspire 1810*:");
+MODULE_ALIAS("dmi:*:*Acer*:pnAO531*:");
MODULE_ALIAS("dmi:*:*Gateway*:pnAOA*:");
MODULE_ALIAS("dmi:*:*Gateway*:pnLT31*:");
MODULE_ALIAS("dmi:*:*Packard Bell*:pnAOA*:");
MODULE_ALIAS("dmi:*:*Packard Bell*:pnDOA*:");
MODULE_ALIAS("dmi:*:*Packard Bell*:pnDOTMU*:");
+MODULE_ALIAS("dmi:*:*Packard Bell*:pnDOTMA*:");
module_init(acerhdf_init);
module_exit(acerhdf_exit);
diff --git a/drivers/platform/x86/asus-laptop.c b/drivers/platform/x86/asus-laptop.c
index efe8f638890..b756e07d41b 100644
--- a/drivers/platform/x86/asus-laptop.c
+++ b/drivers/platform/x86/asus-laptop.c
@@ -76,18 +76,18 @@ MODULE_LICENSE("GPL");
* So, if something doesn't work as you want, just try other values =)
*/
static uint wapf = 1;
-module_param(wapf, uint, 0644);
+module_param(wapf, uint, 0444);
MODULE_PARM_DESC(wapf, "WAPF value");
static int wlan_status = 1;
static int bluetooth_status = 1;
-module_param(wlan_status, int, 0644);
+module_param(wlan_status, int, 0444);
MODULE_PARM_DESC(wlan_status, "Set the wireless status on boot "
"(0 = disabled, 1 = enabled, -1 = don't do anything). "
"default is 1");
-module_param(bluetooth_status, int, 0644);
+module_param(bluetooth_status, int, 0444);
MODULE_PARM_DESC(bluetooth_status, "Set the wireless status on boot "
"(0 = disabled, 1 = enabled, -1 = don't do anything). "
"default is 1");
@@ -297,7 +297,7 @@ static int write_acpi_int_ret(acpi_handle handle, const char *method, int val,
acpi_status status;
if (!handle)
- return 0;
+ return -1;
params.count = 1;
params.pointer = &in_obj;
@@ -796,10 +796,11 @@ static ssize_t store_ledd(struct device *dev, struct device_attribute *attr,
rv = parse_arg(buf, count, &value);
if (rv > 0) {
- if (write_acpi_int(asus->handle, METHOD_LEDD, value))
+ if (write_acpi_int(asus->handle, METHOD_LEDD, value)) {
pr_warning("LED display write failed\n");
- else
- asus->ledd_status = (u32) value;
+ return -ENODEV;
+ }
+ asus->ledd_status = (u32) value;
}
return rv;
}
@@ -1123,7 +1124,7 @@ static int asus_input_init(struct asus_laptop *asus)
input = input_allocate_device();
if (!input) {
pr_info("Unable to allocate input device\n");
- return 0;
+ return -ENOMEM;
}
input->name = "Asus Laptop extra buttons";
input->phys = ASUS_LAPTOP_FILE "/input0";
@@ -1134,20 +1135,20 @@ static int asus_input_init(struct asus_laptop *asus)
error = sparse_keymap_setup(input, asus_keymap, NULL);
if (error) {
pr_err("Unable to setup input device keymap\n");
- goto err_keymap;
+ goto err_free_dev;
}
error = input_register_device(input);
if (error) {
pr_info("Unable to register input device\n");
- goto err_device;
+ goto err_free_keymap;
}
asus->inputdev = input;
return 0;
-err_keymap:
+err_free_keymap:
sparse_keymap_free(input);
-err_device:
+err_free_dev:
input_free_device(input);
return error;
}
@@ -1397,8 +1398,10 @@ static int asus_laptop_get_info(struct asus_laptop *asus)
}
}
asus->name = kstrdup(string, GFP_KERNEL);
- if (!asus->name)
+ if (!asus->name) {
+ kfree(buffer.pointer);
return -ENOMEM;
+ }
if (*string)
pr_notice(" %s model detected\n", string);
diff --git a/drivers/platform/x86/asus_acpi.c b/drivers/platform/x86/asus_acpi.c
index 92fd30c9379..e058c2ba2a1 100644
--- a/drivers/platform/x86/asus_acpi.c
+++ b/drivers/platform/x86/asus_acpi.c
@@ -1330,6 +1330,9 @@ static int asus_hotk_get_info(void)
hotk->model = P30;
printk(KERN_NOTICE
" Samsung P30 detected, supported\n");
+ hotk->methods = &model_conf[hotk->model];
+ kfree(model);
+ return 0;
} else {
hotk->model = M2E;
printk(KERN_NOTICE " unsupported model %s, trying "
@@ -1339,8 +1342,6 @@ static int asus_hotk_get_info(void)
kfree(model);
return -ENODEV;
}
- hotk->methods = &model_conf[hotk->model];
- return AE_OK;
}
hotk->methods = &model_conf[hotk->model];
printk(KERN_NOTICE " %s model detected, supported\n", string);
@@ -1374,7 +1375,7 @@ static int asus_hotk_get_info(void)
kfree(model);
- return AE_OK;
+ return 0;
}
static int asus_hotk_check(void)
diff --git a/drivers/platform/x86/classmate-laptop.c b/drivers/platform/x86/classmate-laptop.c
index 3bf399fe2bb..341cbfef93e 100644
--- a/drivers/platform/x86/classmate-laptop.c
+++ b/drivers/platform/x86/classmate-laptop.c
@@ -208,7 +208,7 @@ static ssize_t cmpc_accel_sensitivity_store(struct device *dev,
return strnlen(buf, count);
}
-struct device_attribute cmpc_accel_sensitivity_attr = {
+static struct device_attribute cmpc_accel_sensitivity_attr = {
.attr = { .name = "sensitivity", .mode = 0660 },
.show = cmpc_accel_sensitivity_show,
.store = cmpc_accel_sensitivity_store
@@ -573,16 +573,17 @@ static int cmpc_ipml_add(struct acpi_device *acpi)
ipml->rf = rfkill_alloc("cmpc_rfkill", &acpi->dev, RFKILL_TYPE_WLAN,
&cmpc_rfkill_ops, acpi->handle);
- /* rfkill_alloc may fail if RFKILL is disabled. We should still work
- * anyway. */
- if (!IS_ERR(ipml->rf)) {
+ /*
+ * If RFKILL is disabled, rfkill_alloc will return ERR_PTR(-ENODEV).
+ * This is OK, however, since all other uses of the device will not
+ * derefence it.
+ */
+ if (ipml->rf) {
retval = rfkill_register(ipml->rf);
if (retval) {
rfkill_destroy(ipml->rf);
ipml->rf = NULL;
}
- } else {
- ipml->rf = NULL;
}
dev_set_drvdata(&acpi->dev, ipml);
diff --git a/drivers/platform/x86/compal-laptop.c b/drivers/platform/x86/compal-laptop.c
index 71ff1545a93..d071ce05632 100644
--- a/drivers/platform/x86/compal-laptop.c
+++ b/drivers/platform/x86/compal-laptop.c
@@ -24,17 +24,50 @@
*/
/*
- * comapl-laptop.c - Compal laptop support.
+ * compal-laptop.c - Compal laptop support.
+ *
+ * This driver exports a few files in /sys/devices/platform/compal-laptop/:
+ * wake_up_XXX Whether or not we listen to such wake up events (rw)
+ *
+ * In addition to these platform device attributes the driver
+ * registers itself in the Linux backlight control, power_supply, rfkill
+ * and hwmon subsystem and is available to userspace under:
+ *
+ * /sys/class/backlight/compal-laptop/
+ * /sys/class/power_supply/compal-laptop/
+ * /sys/class/rfkill/rfkillX/
+ * /sys/class/hwmon/hwmonX/
+ *
+ * Notes on the power_supply battery interface:
+ * - the "minimum" design voltage is *the* design voltage
+ * - the ambient temperature is the average battery temperature
+ * and the value is an educated guess (see commented code below)
*
- * The driver registers itself with the rfkill subsystem and
- * the Linux backlight control subsystem.
*
* This driver might work on other laptops produced by Compal. If you
* want to try it you can pass force=1 as argument to the module which
* will force it to load even when the DMI data doesn't identify the
- * laptop as FL9x.
+ * laptop as compatible.
+ *
+ * Lots of data available at:
+ * http://service1.marasst.com/Compal/JHL90_91/Service%20Manual/
+ * JHL90%20service%20manual-Final-0725.pdf
+ *
+ *
+ *
+ * Support for the Compal JHL90 added by Roald Frederickx
+ * (roald.frederickx@gmail.com):
+ * Driver got large revision. Added functionalities: backlight
+ * power, wake_on_XXX, a hwmon and power_supply interface.
+ *
+ * In case this gets merged into the kernel source: I want to dedicate this
+ * to Kasper Meerts, the awesome guy who showed me Linux and C!
*/
+/* NOTE: currently the wake_on_XXX, hwmon and power_supply interfaces are
+ * only enabled on a JHL90 board until it is verified that they work on the
+ * other boards too. See the extra_features variable. */
+
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
@@ -43,71 +76,296 @@
#include <linux/backlight.h>
#include <linux/platform_device.h>
#include <linux/rfkill.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/power_supply.h>
+#include <linux/fb.h>
+
+
+/* ======= */
+/* Defines */
+/* ======= */
+#define DRIVER_NAME "compal-laptop"
+#define DRIVER_VERSION "0.2.7"
+
+#define BACKLIGHT_LEVEL_ADDR 0xB9
+#define BACKLIGHT_LEVEL_MAX 7
+#define BACKLIGHT_STATE_ADDR 0x59
+#define BACKLIGHT_STATE_ON_DATA 0xE1
+#define BACKLIGHT_STATE_OFF_DATA 0xE2
+
+#define WAKE_UP_ADDR 0xA4
+#define WAKE_UP_PME (1 << 0)
+#define WAKE_UP_MODEM (1 << 1)
+#define WAKE_UP_LAN (1 << 2)
+#define WAKE_UP_WLAN (1 << 4)
+#define WAKE_UP_KEY (1 << 6)
+#define WAKE_UP_MOUSE (1 << 7)
+
+#define WIRELESS_ADDR 0xBB
+#define WIRELESS_WLAN (1 << 0)
+#define WIRELESS_BT (1 << 1)
+#define WIRELESS_WLAN_EXISTS (1 << 2)
+#define WIRELESS_BT_EXISTS (1 << 3)
+#define WIRELESS_KILLSWITCH (1 << 4)
+
+#define PWM_ADDRESS 0x46
+#define PWM_DISABLE_ADDR 0x59
+#define PWM_DISABLE_DATA 0xA5
+#define PWM_ENABLE_ADDR 0x59
+#define PWM_ENABLE_DATA 0xA8
+
+#define FAN_ADDRESS 0x46
+#define FAN_DATA 0x81
+#define FAN_FULL_ON_CMD 0x59 /* Doesn't seem to work. Just */
+#define FAN_FULL_ON_ENABLE 0x76 /* force the pwm signal to its */
+#define FAN_FULL_ON_DISABLE 0x77 /* maximum value instead */
+
+#define TEMP_CPU 0xB0
+#define TEMP_CPU_LOCAL 0xB1
+#define TEMP_CPU_DTS 0xB5
+#define TEMP_NORTHBRIDGE 0xB6
+#define TEMP_VGA 0xB4
+#define TEMP_SKIN 0xB2
+
+#define BAT_MANUFACTURER_NAME_ADDR 0x10
+#define BAT_MANUFACTURER_NAME_LEN 9
+#define BAT_MODEL_NAME_ADDR 0x19
+#define BAT_MODEL_NAME_LEN 6
+#define BAT_SERIAL_NUMBER_ADDR 0xC4
+#define BAT_SERIAL_NUMBER_LEN 5
+#define BAT_CHARGE_NOW 0xC2
+#define BAT_CHARGE_DESIGN 0xCA
+#define BAT_VOLTAGE_NOW 0xC6
+#define BAT_VOLTAGE_DESIGN 0xC8
+#define BAT_CURRENT_NOW 0xD0
+#define BAT_CURRENT_AVG 0xD2
+#define BAT_POWER 0xD4
+#define BAT_CAPACITY 0xCE
+#define BAT_TEMP 0xD6
+#define BAT_TEMP_AVG 0xD7
+#define BAT_STATUS0 0xC1
+#define BAT_STATUS1 0xF0
+#define BAT_STATUS2 0xF1
+#define BAT_STOP_CHARGE1 0xF2
+#define BAT_STOP_CHARGE2 0xF3
+
+#define BAT_S0_DISCHARGE (1 << 0)
+#define BAT_S0_DISCHRG_CRITICAL (1 << 2)
+#define BAT_S0_LOW (1 << 3)
+#define BAT_S0_CHARGING (1 << 1)
+#define BAT_S0_AC (1 << 7)
+#define BAT_S1_EXISTS (1 << 0)
+#define BAT_S1_FULL (1 << 1)
+#define BAT_S1_EMPTY (1 << 2)
+#define BAT_S1_LiION_OR_NiMH (1 << 7)
+#define BAT_S2_LOW_LOW (1 << 0)
+#define BAT_STOP_CHRG1_BAD_CELL (1 << 1)
+#define BAT_STOP_CHRG1_COMM_FAIL (1 << 2)
+#define BAT_STOP_CHRG1_OVERVOLTAGE (1 << 6)
+#define BAT_STOP_CHRG1_OVERTEMPERATURE (1 << 7)
+
+
+/* ======= */
+/* Structs */
+/* ======= */
+struct compal_data{
+ /* Fan control */
+ struct device *hwmon_dev;
+ int pwm_enable; /* 0:full on, 1:set by pwm1, 2:control by moterboard */
+ unsigned char curr_pwm;
+
+ /* Power supply */
+ struct power_supply psy;
+ struct power_supply_info psy_info;
+ char bat_model_name[BAT_MODEL_NAME_LEN + 1];
+ char bat_manufacturer_name[BAT_MANUFACTURER_NAME_LEN + 1];
+ char bat_serial_number[BAT_SERIAL_NUMBER_LEN + 1];
+};
-#define COMPAL_DRIVER_VERSION "0.2.6"
-#define COMPAL_LCD_LEVEL_MAX 8
+/* =============== */
+/* General globals */
+/* =============== */
+static int force;
+module_param(force, bool, 0);
+MODULE_PARM_DESC(force, "Force driver load, ignore DMI data");
-#define COMPAL_EC_COMMAND_WIRELESS 0xBB
-#define COMPAL_EC_COMMAND_LCD_LEVEL 0xB9
+/* Support for the wake_on_XXX, hwmon and power_supply interface. Currently
+ * only gets enabled on a JHL90 board. Might work with the others too */
+static bool extra_features;
+
+/* Nasty stuff. For some reason the fan control is very un-linear. I've
+ * come up with these values by looping through the possible inputs and
+ * watching the output of address 0x4F (do an ec_transaction writing 0x33
+ * into 0x4F and read a few bytes from the output, like so:
+ * u8 writeData = 0x33;
+ * ec_transaction(0x4F, &writeData, 1, buffer, 32, 0);
+ * That address is labled "fan1 table information" in the service manual.
+ * It should be clear which value in 'buffer' changes). This seems to be
+ * related to fan speed. It isn't a proper 'realtime' fan speed value
+ * though, because physically stopping or speeding up the fan doesn't
+ * change it. It might be the average voltage or current of the pwm output.
+ * Nevertheless, it is more fine-grained than the actual RPM reading */
+static const unsigned char pwm_lookup_table[256] = {
+ 0, 0, 0, 1, 1, 1, 2, 253, 254, 3, 3, 3, 4, 4, 4, 5, 5, 5, 6, 6, 6,
+ 7, 7, 7, 8, 86, 86, 9, 9, 9, 10, 10, 10, 11, 92, 92, 12, 12, 95,
+ 13, 66, 66, 14, 14, 98, 15, 15, 15, 16, 16, 67, 17, 17, 72, 18, 70,
+ 75, 19, 90, 90, 73, 73, 73, 21, 21, 91, 91, 91, 96, 23, 94, 94, 94,
+ 94, 94, 94, 94, 94, 94, 94, 141, 141, 238, 223, 192, 139, 139, 139,
+ 139, 139, 142, 142, 142, 142, 142, 78, 78, 78, 78, 78, 76, 76, 76,
+ 76, 76, 79, 79, 79, 79, 79, 79, 79, 20, 20, 20, 20, 20, 22, 22, 22,
+ 22, 22, 24, 24, 24, 24, 24, 24, 219, 219, 219, 219, 219, 219, 219,
+ 219, 27, 27, 188, 188, 28, 28, 28, 29, 186, 186, 186, 186, 186,
+ 186, 186, 186, 186, 186, 31, 31, 31, 31, 31, 32, 32, 32, 41, 33,
+ 33, 33, 33, 33, 252, 252, 34, 34, 34, 43, 35, 35, 35, 36, 36, 38,
+ 206, 206, 206, 206, 206, 206, 206, 206, 206, 37, 37, 37, 46, 46,
+ 47, 47, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 48, 48,
+ 48, 48, 48, 40, 40, 40, 49, 42, 42, 42, 42, 42, 42, 42, 42, 44,
+ 189, 189, 189, 189, 54, 54, 45, 45, 45, 45, 45, 45, 45, 45, 251,
+ 191, 199, 199, 199, 199, 199, 215, 215, 215, 215, 187, 187, 187,
+ 187, 187, 193, 50
+};
-#define KILLSWITCH_MASK 0x10
-#define WLAN_MASK 0x01
-#define BT_MASK 0x02
-static struct rfkill *wifi_rfkill;
-static struct rfkill *bt_rfkill;
-static struct platform_device *compal_device;
-static int force;
-module_param(force, bool, 0);
-MODULE_PARM_DESC(force, "Force driver load, ignore DMI data");
-/* Hardware access */
+/* ========================= */
+/* Hardware access functions */
+/* ========================= */
+/* General access */
+static u8 ec_read_u8(u8 addr)
+{
+ u8 value;
+ ec_read(addr, &value);
+ return value;
+}
+
+static s8 ec_read_s8(u8 addr)
+{
+ return (s8)ec_read_u8(addr);
+}
+
+static u16 ec_read_u16(u8 addr)
+{
+ int hi, lo;
+ lo = ec_read_u8(addr);
+ hi = ec_read_u8(addr + 1);
+ return (hi << 8) + lo;
+}
+
+static s16 ec_read_s16(u8 addr)
+{
+ return (s16) ec_read_u16(addr);
+}
-static int set_lcd_level(int level)
+static void ec_read_sequence(u8 addr, u8 *buf, int len)
{
- if (level < 0 || level >= COMPAL_LCD_LEVEL_MAX)
+ int i;
+ for (i = 0; i < len; i++)
+ ec_read(addr + i, buf + i);
+}
+
+
+/* Backlight access */
+static int set_backlight_level(int level)
+{
+ if (level < 0 || level > BACKLIGHT_LEVEL_MAX)
return -EINVAL;
- ec_write(COMPAL_EC_COMMAND_LCD_LEVEL, level);
+ ec_write(BACKLIGHT_LEVEL_ADDR, level);
- return 0;
+ return 1;
+}
+
+static int get_backlight_level(void)
+{
+ return (int) ec_read_u8(BACKLIGHT_LEVEL_ADDR);
}
-static int get_lcd_level(void)
+static void set_backlight_state(bool on)
{
- u8 result;
+ u8 data = on ? BACKLIGHT_STATE_ON_DATA : BACKLIGHT_STATE_OFF_DATA;
+ ec_transaction(BACKLIGHT_STATE_ADDR, &data, 1, NULL, 0, 0);
+}
+
+
+/* Fan control access */
+static void pwm_enable_control(void)
+{
+ unsigned char writeData = PWM_ENABLE_DATA;
+ ec_transaction(PWM_ENABLE_ADDR, &writeData, 1, NULL, 0, 0);
+}
+
+static void pwm_disable_control(void)
+{
+ unsigned char writeData = PWM_DISABLE_DATA;
+ ec_transaction(PWM_DISABLE_ADDR, &writeData, 1, NULL, 0, 0);
+}
- ec_read(COMPAL_EC_COMMAND_LCD_LEVEL, &result);
+static void set_pwm(int pwm)
+{
+ ec_transaction(PWM_ADDRESS, &pwm_lookup_table[pwm], 1, NULL, 0, 0);
+}
+
+static int get_fan_rpm(void)
+{
+ u8 value, data = FAN_DATA;
+ ec_transaction(FAN_ADDRESS, &data, 1, &value, 1, 0);
+ return 100 * (int)value;
+}
+
+
+
+
+/* =================== */
+/* Interface functions */
+/* =================== */
+
+/* Backlight interface */
+static int bl_get_brightness(struct backlight_device *b)
+{
+ return get_backlight_level();
+}
+
+static int bl_update_status(struct backlight_device *b)
+{
+ int ret = set_backlight_level(b->props.brightness);
+ if (ret)
+ return ret;
- return (int) result;
+ set_backlight_state((b->props.power == FB_BLANK_UNBLANK)
+ && !(b->props.state & BL_CORE_SUSPENDED)
+ && !(b->props.state & BL_CORE_FBBLANK));
+ return 0;
}
+static const struct backlight_ops compalbl_ops = {
+ .get_brightness = bl_get_brightness,
+ .update_status = bl_update_status,
+};
+
+
+/* Wireless interface */
static int compal_rfkill_set(void *data, bool blocked)
{
unsigned long radio = (unsigned long) data;
- u8 result, value;
-
- ec_read(COMPAL_EC_COMMAND_WIRELESS, &result);
+ u8 result = ec_read_u8(WIRELESS_ADDR);
+ u8 value;
if (!blocked)
value = (u8) (result | radio);
else
value = (u8) (result & ~radio);
- ec_write(COMPAL_EC_COMMAND_WIRELESS, value);
+ ec_write(WIRELESS_ADDR, value);
return 0;
}
static void compal_rfkill_poll(struct rfkill *rfkill, void *data)
{
- u8 result;
- bool hw_blocked;
-
- ec_read(COMPAL_EC_COMMAND_WIRELESS, &result);
-
- hw_blocked = !(result & KILLSWITCH_MASK);
+ u8 result = ec_read_u8(WIRELESS_ADDR);
+ bool hw_blocked = !(result & WIRELESS_KILLSWITCH);
rfkill_set_hw_state(rfkill, hw_blocked);
}
@@ -116,80 +374,404 @@ static const struct rfkill_ops compal_rfkill_ops = {
.set_block = compal_rfkill_set,
};
-static int setup_rfkill(void)
+
+/* Wake_up interface */
+#define SIMPLE_MASKED_STORE_SHOW(NAME, ADDR, MASK) \
+static ssize_t NAME##_show(struct device *dev, \
+ struct device_attribute *attr, char *buf) \
+{ \
+ return sprintf(buf, "%d\n", ((ec_read_u8(ADDR) & MASK) != 0)); \
+} \
+static ssize_t NAME##_store(struct device *dev, \
+ struct device_attribute *attr, const char *buf, size_t count) \
+{ \
+ int state; \
+ u8 old_val = ec_read_u8(ADDR); \
+ if (sscanf(buf, "%d", &state) != 1 || (state < 0 || state > 1)) \
+ return -EINVAL; \
+ ec_write(ADDR, state ? (old_val | MASK) : (old_val & ~MASK)); \
+ return count; \
+}
+
+SIMPLE_MASKED_STORE_SHOW(wake_up_pme, WAKE_UP_ADDR, WAKE_UP_PME)
+SIMPLE_MASKED_STORE_SHOW(wake_up_modem, WAKE_UP_ADDR, WAKE_UP_MODEM)
+SIMPLE_MASKED_STORE_SHOW(wake_up_lan, WAKE_UP_ADDR, WAKE_UP_LAN)
+SIMPLE_MASKED_STORE_SHOW(wake_up_wlan, WAKE_UP_ADDR, WAKE_UP_WLAN)
+SIMPLE_MASKED_STORE_SHOW(wake_up_key, WAKE_UP_ADDR, WAKE_UP_KEY)
+SIMPLE_MASKED_STORE_SHOW(wake_up_mouse, WAKE_UP_ADDR, WAKE_UP_MOUSE)
+
+
+/* General hwmon interface */
+static ssize_t hwmon_name_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
- int ret;
+ return sprintf(buf, "%s\n", DRIVER_NAME);
+}
- wifi_rfkill = rfkill_alloc("compal-wifi", &compal_device->dev,
- RFKILL_TYPE_WLAN, &compal_rfkill_ops,
- (void *) WLAN_MASK);
- if (!wifi_rfkill)
- return -ENOMEM;
- ret = rfkill_register(wifi_rfkill);
- if (ret)
- goto err_wifi;
+/* Fan control interface */
+static ssize_t pwm_enable_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct compal_data *data = dev_get_drvdata(dev);
+ return sprintf(buf, "%d\n", data->pwm_enable);
+}
- bt_rfkill = rfkill_alloc("compal-bluetooth", &compal_device->dev,
- RFKILL_TYPE_BLUETOOTH, &compal_rfkill_ops,
- (void *) BT_MASK);
- if (!bt_rfkill) {
- ret = -ENOMEM;
- goto err_allocate_bt;
+static ssize_t pwm_enable_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct compal_data *data = dev_get_drvdata(dev);
+ long val;
+ int err;
+ err = strict_strtol(buf, 10, &val);
+ if (err)
+ return err;
+ if (val < 0)
+ return -EINVAL;
+
+ data->pwm_enable = val;
+
+ switch (val) {
+ case 0: /* Full speed */
+ pwm_enable_control();
+ set_pwm(255);
+ break;
+ case 1: /* As set by pwm1 */
+ pwm_enable_control();
+ set_pwm(data->curr_pwm);
+ break;
+ default: /* Control by motherboard */
+ pwm_disable_control();
+ break;
}
- ret = rfkill_register(bt_rfkill);
- if (ret)
- goto err_register_bt;
- return 0;
+ return count;
+}
-err_register_bt:
- rfkill_destroy(bt_rfkill);
+static ssize_t pwm_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct compal_data *data = dev_get_drvdata(dev);
+ return sprintf(buf, "%hhu\n", data->curr_pwm);
+}
-err_allocate_bt:
- rfkill_unregister(wifi_rfkill);
+static ssize_t pwm_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct compal_data *data = dev_get_drvdata(dev);
+ long val;
+ int err;
+ err = strict_strtol(buf, 10, &val);
+ if (err)
+ return err;
+ if (val < 0 || val > 255)
+ return -EINVAL;
-err_wifi:
- rfkill_destroy(wifi_rfkill);
+ data->curr_pwm = val;
- return ret;
+ if (data->pwm_enable != 1)
+ return count;
+ set_pwm(val);
+
+ return count;
}
-/* Backlight device stuff */
+static ssize_t fan_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ return sprintf(buf, "%d\n", get_fan_rpm());
+}
-static int bl_get_brightness(struct backlight_device *b)
+
+/* Temperature interface */
+#define TEMPERATURE_SHOW_TEMP_AND_LABEL(POSTFIX, ADDRESS, LABEL) \
+static ssize_t temp_##POSTFIX(struct device *dev, \
+ struct device_attribute *attr, char *buf) \
+{ \
+ return sprintf(buf, "%d\n", 1000 * (int)ec_read_s8(ADDRESS)); \
+} \
+static ssize_t label_##POSTFIX(struct device *dev, \
+ struct device_attribute *attr, char *buf) \
+{ \
+ return sprintf(buf, "%s\n", LABEL); \
+}
+
+/* Labels as in service guide */
+TEMPERATURE_SHOW_TEMP_AND_LABEL(cpu, TEMP_CPU, "CPU_TEMP");
+TEMPERATURE_SHOW_TEMP_AND_LABEL(cpu_local, TEMP_CPU_LOCAL, "CPU_TEMP_LOCAL");
+TEMPERATURE_SHOW_TEMP_AND_LABEL(cpu_DTS, TEMP_CPU_DTS, "CPU_DTS");
+TEMPERATURE_SHOW_TEMP_AND_LABEL(northbridge,TEMP_NORTHBRIDGE,"NorthBridge");
+TEMPERATURE_SHOW_TEMP_AND_LABEL(vga, TEMP_VGA, "VGA_TEMP");
+TEMPERATURE_SHOW_TEMP_AND_LABEL(SKIN, TEMP_SKIN, "SKIN_TEMP90");
+
+
+/* Power supply interface */
+static int bat_status(void)
+{
+ u8 status0 = ec_read_u8(BAT_STATUS0);
+ u8 status1 = ec_read_u8(BAT_STATUS1);
+
+ if (status0 & BAT_S0_CHARGING)
+ return POWER_SUPPLY_STATUS_CHARGING;
+ if (status0 & BAT_S0_DISCHARGE)
+ return POWER_SUPPLY_STATUS_DISCHARGING;
+ if (status1 & BAT_S1_FULL)
+ return POWER_SUPPLY_STATUS_FULL;
+ return POWER_SUPPLY_STATUS_NOT_CHARGING;
+}
+
+static int bat_health(void)
{
- return get_lcd_level();
+ u8 status = ec_read_u8(BAT_STOP_CHARGE1);
+
+ if (status & BAT_STOP_CHRG1_OVERTEMPERATURE)
+ return POWER_SUPPLY_HEALTH_OVERHEAT;
+ if (status & BAT_STOP_CHRG1_OVERVOLTAGE)
+ return POWER_SUPPLY_HEALTH_OVERVOLTAGE;
+ if (status & BAT_STOP_CHRG1_BAD_CELL)
+ return POWER_SUPPLY_HEALTH_DEAD;
+ if (status & BAT_STOP_CHRG1_COMM_FAIL)
+ return POWER_SUPPLY_HEALTH_UNKNOWN;
+ return POWER_SUPPLY_HEALTH_GOOD;
}
+static int bat_is_present(void)
+{
+ u8 status = ec_read_u8(BAT_STATUS2);
+ return ((status & BAT_S1_EXISTS) != 0);
+}
-static int bl_update_status(struct backlight_device *b)
+static int bat_technology(void)
{
- return set_lcd_level(b->props.brightness);
+ u8 status = ec_read_u8(BAT_STATUS1);
+
+ if (status & BAT_S1_LiION_OR_NiMH)
+ return POWER_SUPPLY_TECHNOLOGY_LION;
+ return POWER_SUPPLY_TECHNOLOGY_NiMH;
}
-static struct backlight_ops compalbl_ops = {
- .get_brightness = bl_get_brightness,
- .update_status = bl_update_status,
-};
+static int bat_capacity_level(void)
+{
+ u8 status0 = ec_read_u8(BAT_STATUS0);
+ u8 status1 = ec_read_u8(BAT_STATUS1);
+ u8 status2 = ec_read_u8(BAT_STATUS2);
+
+ if (status0 & BAT_S0_DISCHRG_CRITICAL
+ || status1 & BAT_S1_EMPTY
+ || status2 & BAT_S2_LOW_LOW)
+ return POWER_SUPPLY_CAPACITY_LEVEL_CRITICAL;
+ if (status0 & BAT_S0_LOW)
+ return POWER_SUPPLY_CAPACITY_LEVEL_LOW;
+ if (status1 & BAT_S1_FULL)
+ return POWER_SUPPLY_CAPACITY_LEVEL_FULL;
+ return POWER_SUPPLY_CAPACITY_LEVEL_NORMAL;
+}
+
+static int bat_get_property(struct power_supply *psy,
+ enum power_supply_property psp,
+ union power_supply_propval *val)
+{
+ struct compal_data *data;
+ data = container_of(psy, struct compal_data, psy);
+
+ switch (psp) {
+ case POWER_SUPPLY_PROP_STATUS:
+ val->intval = bat_status();
+ break;
+ case POWER_SUPPLY_PROP_HEALTH:
+ val->intval = bat_health();
+ break;
+ case POWER_SUPPLY_PROP_PRESENT:
+ val->intval = bat_is_present();
+ break;
+ case POWER_SUPPLY_PROP_TECHNOLOGY:
+ val->intval = bat_technology();
+ break;
+ case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN: /* THE design voltage... */
+ val->intval = ec_read_u16(BAT_VOLTAGE_DESIGN) * 1000;
+ break;
+ case POWER_SUPPLY_PROP_VOLTAGE_NOW:
+ val->intval = ec_read_u16(BAT_VOLTAGE_NOW) * 1000;
+ break;
+ case POWER_SUPPLY_PROP_CURRENT_NOW:
+ val->intval = ec_read_s16(BAT_CURRENT_NOW) * 1000;
+ break;
+ case POWER_SUPPLY_PROP_CURRENT_AVG:
+ val->intval = ec_read_s16(BAT_CURRENT_AVG) * 1000;
+ break;
+ case POWER_SUPPLY_PROP_POWER_NOW:
+ val->intval = ec_read_u8(BAT_POWER) * 1000000;
+ break;
+ case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN:
+ val->intval = ec_read_u16(BAT_CHARGE_DESIGN) * 1000;
+ break;
+ case POWER_SUPPLY_PROP_CHARGE_NOW:
+ val->intval = ec_read_u16(BAT_CHARGE_NOW) * 1000;
+ break;
+ case POWER_SUPPLY_PROP_CAPACITY:
+ val->intval = ec_read_u8(BAT_CAPACITY);
+ break;
+ case POWER_SUPPLY_PROP_CAPACITY_LEVEL:
+ val->intval = bat_capacity_level();
+ break;
+ /* It smees that BAT_TEMP_AVG is a (2's complement?) value showing
+ * the number of degrees, whereas BAT_TEMP is somewhat more
+ * complicated. It looks like this is a negative nember with a
+ * 100/256 divider and an offset of 222. Both were determined
+ * experimentally by comparing BAT_TEMP and BAT_TEMP_AVG. */
+ case POWER_SUPPLY_PROP_TEMP:
+ val->intval = ((222 - (int)ec_read_u8(BAT_TEMP)) * 1000) >> 8;
+ break;
+ case POWER_SUPPLY_PROP_TEMP_AMBIENT: /* Ambient, Avg, ... same thing */
+ val->intval = ec_read_s8(BAT_TEMP_AVG) * 10;
+ break;
+ /* Neither the model name nor manufacturer name work for me. */
+ case POWER_SUPPLY_PROP_MODEL_NAME:
+ val->strval = data->bat_model_name;
+ break;
+ case POWER_SUPPLY_PROP_MANUFACTURER:
+ val->strval = data->bat_manufacturer_name;
+ break;
+ case POWER_SUPPLY_PROP_SERIAL_NUMBER:
+ val->strval = data->bat_serial_number;
+ break;
+ default:
+ break;
+ }
+ return 0;
+}
-static struct backlight_device *compalbl_device;
+
+
+/* ============== */
+/* Driver Globals */
+/* ============== */
+static DEVICE_ATTR(wake_up_pme,
+ 0644, wake_up_pme_show, wake_up_pme_store);
+static DEVICE_ATTR(wake_up_modem,
+ 0644, wake_up_modem_show, wake_up_modem_store);
+static DEVICE_ATTR(wake_up_lan,
+ 0644, wake_up_lan_show, wake_up_lan_store);
+static DEVICE_ATTR(wake_up_wlan,
+ 0644, wake_up_wlan_show, wake_up_wlan_store);
+static DEVICE_ATTR(wake_up_key,
+ 0644, wake_up_key_show, wake_up_key_store);
+static DEVICE_ATTR(wake_up_mouse,
+ 0644, wake_up_mouse_show, wake_up_mouse_store);
+
+static SENSOR_DEVICE_ATTR(name, S_IRUGO, hwmon_name_show, NULL, 1);
+static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, fan_show, NULL, 1);
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, temp_cpu, NULL, 1);
+static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, temp_cpu_local, NULL, 1);
+static SENSOR_DEVICE_ATTR(temp3_input, S_IRUGO, temp_cpu_DTS, NULL, 1);
+static SENSOR_DEVICE_ATTR(temp4_input, S_IRUGO, temp_northbridge, NULL, 1);
+static SENSOR_DEVICE_ATTR(temp5_input, S_IRUGO, temp_vga, NULL, 1);
+static SENSOR_DEVICE_ATTR(temp6_input, S_IRUGO, temp_SKIN, NULL, 1);
+static SENSOR_DEVICE_ATTR(temp1_label, S_IRUGO, label_cpu, NULL, 1);
+static SENSOR_DEVICE_ATTR(temp2_label, S_IRUGO, label_cpu_local, NULL, 1);
+static SENSOR_DEVICE_ATTR(temp3_label, S_IRUGO, label_cpu_DTS, NULL, 1);
+static SENSOR_DEVICE_ATTR(temp4_label, S_IRUGO, label_northbridge, NULL, 1);
+static SENSOR_DEVICE_ATTR(temp5_label, S_IRUGO, label_vga, NULL, 1);
+static SENSOR_DEVICE_ATTR(temp6_label, S_IRUGO, label_SKIN, NULL, 1);
+static SENSOR_DEVICE_ATTR(pwm1, S_IRUGO | S_IWUSR, pwm_show, pwm_store, 1);
+static SENSOR_DEVICE_ATTR(pwm1_enable,
+ S_IRUGO | S_IWUSR, pwm_enable_show, pwm_enable_store, 0);
+
+static struct attribute *compal_attributes[] = {
+ &dev_attr_wake_up_pme.attr,
+ &dev_attr_wake_up_modem.attr,
+ &dev_attr_wake_up_lan.attr,
+ &dev_attr_wake_up_wlan.attr,
+ &dev_attr_wake_up_key.attr,
+ &dev_attr_wake_up_mouse.attr,
+ /* Maybe put the sensor-stuff in a separate hwmon-driver? That way,
+ * the hwmon sysfs won't be cluttered with the above files. */
+ &sensor_dev_attr_name.dev_attr.attr,
+ &sensor_dev_attr_pwm1_enable.dev_attr.attr,
+ &sensor_dev_attr_pwm1.dev_attr.attr,
+ &sensor_dev_attr_fan1_input.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_temp4_input.dev_attr.attr,
+ &sensor_dev_attr_temp5_input.dev_attr.attr,
+ &sensor_dev_attr_temp6_input.dev_attr.attr,
+ &sensor_dev_attr_temp1_label.dev_attr.attr,
+ &sensor_dev_attr_temp2_label.dev_attr.attr,
+ &sensor_dev_attr_temp3_label.dev_attr.attr,
+ &sensor_dev_attr_temp4_label.dev_attr.attr,
+ &sensor_dev_attr_temp5_label.dev_attr.attr,
+ &sensor_dev_attr_temp6_label.dev_attr.attr,
+ NULL
+};
+
+static struct attribute_group compal_attribute_group = {
+ .attrs = compal_attributes
+};
+
+static int __devinit compal_probe(struct platform_device *);
+static int __devexit compal_remove(struct platform_device *);
static struct platform_driver compal_driver = {
.driver = {
- .name = "compal-laptop",
+ .name = DRIVER_NAME,
.owner = THIS_MODULE,
- }
+ },
+ .probe = compal_probe,
+ .remove = __devexit_p(compal_remove)
};
-/* Initialization */
+static enum power_supply_property compal_bat_properties[] = {
+ POWER_SUPPLY_PROP_STATUS,
+ POWER_SUPPLY_PROP_HEALTH,
+ POWER_SUPPLY_PROP_PRESENT,
+ POWER_SUPPLY_PROP_TECHNOLOGY,
+ POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,
+ POWER_SUPPLY_PROP_VOLTAGE_NOW,
+ POWER_SUPPLY_PROP_CURRENT_NOW,
+ POWER_SUPPLY_PROP_CURRENT_AVG,
+ POWER_SUPPLY_PROP_POWER_NOW,
+ POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
+ POWER_SUPPLY_PROP_CHARGE_NOW,
+ POWER_SUPPLY_PROP_CAPACITY,
+ POWER_SUPPLY_PROP_CAPACITY_LEVEL,
+ POWER_SUPPLY_PROP_TEMP,
+ POWER_SUPPLY_PROP_TEMP_AMBIENT,
+ POWER_SUPPLY_PROP_MODEL_NAME,
+ POWER_SUPPLY_PROP_MANUFACTURER,
+ POWER_SUPPLY_PROP_SERIAL_NUMBER,
+};
+
+static struct backlight_device *compalbl_device;
+
+static struct platform_device *compal_device;
+
+static struct rfkill *wifi_rfkill;
+static struct rfkill *bt_rfkill;
+
+
+
+
+
+/* =================================== */
+/* Initialization & clean-up functions */
+/* =================================== */
static int dmi_check_cb(const struct dmi_system_id *id)
{
- printk(KERN_INFO "compal-laptop: Identified laptop model '%s'.\n",
+ printk(KERN_INFO DRIVER_NAME": Identified laptop model '%s'\n",
id->ident);
+ extra_features = false;
+ return 0;
+}
+static int dmi_check_cb_extra(const struct dmi_system_id *id)
+{
+ printk(KERN_INFO DRIVER_NAME": Identified laptop model '%s', "
+ "enabling extra features\n",
+ id->ident);
+ extra_features = true;
return 0;
}
@@ -274,27 +856,106 @@ static struct dmi_system_id __initdata compal_dmi_table[] = {
},
.callback = dmi_check_cb
},
-
+ {
+ .ident = "JHL90",
+ .matches = {
+ DMI_MATCH(DMI_BOARD_NAME, "JHL90"),
+ DMI_MATCH(DMI_BOARD_VERSION, "REFERENCE"),
+ },
+ .callback = dmi_check_cb_extra
+ },
{ }
};
+static void initialize_power_supply_data(struct compal_data *data)
+{
+ data->psy.name = DRIVER_NAME;
+ data->psy.type = POWER_SUPPLY_TYPE_BATTERY;
+ data->psy.properties = compal_bat_properties;
+ data->psy.num_properties = ARRAY_SIZE(compal_bat_properties);
+ data->psy.get_property = bat_get_property;
+
+ ec_read_sequence(BAT_MANUFACTURER_NAME_ADDR,
+ data->bat_manufacturer_name,
+ BAT_MANUFACTURER_NAME_LEN);
+ data->bat_manufacturer_name[BAT_MANUFACTURER_NAME_LEN] = 0;
+
+ ec_read_sequence(BAT_MODEL_NAME_ADDR,
+ data->bat_model_name,
+ BAT_MODEL_NAME_LEN);
+ data->bat_model_name[BAT_MODEL_NAME_LEN] = 0;
+
+ scnprintf(data->bat_serial_number, BAT_SERIAL_NUMBER_LEN + 1, "%d",
+ ec_read_u16(BAT_SERIAL_NUMBER_ADDR));
+}
+
+static void initialize_fan_control_data(struct compal_data *data)
+{
+ data->pwm_enable = 2; /* Keep motherboard in control for now */
+ data->curr_pwm = 255; /* Try not to cause a CPU_on_fire exception
+ if we take over... */
+}
+
+static int setup_rfkill(void)
+{
+ int ret;
+
+ wifi_rfkill = rfkill_alloc("compal-wifi", &compal_device->dev,
+ RFKILL_TYPE_WLAN, &compal_rfkill_ops,
+ (void *) WIRELESS_WLAN);
+ if (!wifi_rfkill)
+ return -ENOMEM;
+
+ ret = rfkill_register(wifi_rfkill);
+ if (ret)
+ goto err_wifi;
+
+ bt_rfkill = rfkill_alloc("compal-bluetooth", &compal_device->dev,
+ RFKILL_TYPE_BLUETOOTH, &compal_rfkill_ops,
+ (void *) WIRELESS_BT);
+ if (!bt_rfkill) {
+ ret = -ENOMEM;
+ goto err_allocate_bt;
+ }
+ ret = rfkill_register(bt_rfkill);
+ if (ret)
+ goto err_register_bt;
+
+ return 0;
+
+err_register_bt:
+ rfkill_destroy(bt_rfkill);
+
+err_allocate_bt:
+ rfkill_unregister(wifi_rfkill);
+
+err_wifi:
+ rfkill_destroy(wifi_rfkill);
+
+ return ret;
+}
+
static int __init compal_init(void)
{
int ret;
- if (acpi_disabled)
+ if (acpi_disabled) {
+ printk(KERN_ERR DRIVER_NAME": ACPI needs to be enabled for "
+ "this driver to work!\n");
return -ENODEV;
+ }
- if (!force && !dmi_check_system(compal_dmi_table))
+ if (!force && !dmi_check_system(compal_dmi_table)) {
+ printk(KERN_ERR DRIVER_NAME": Motherboard not recognized (You "
+ "could try the module's force-parameter)");
return -ENODEV;
-
- /* Register backlight stuff */
+ }
if (!acpi_video_backlight_support()) {
struct backlight_properties props;
memset(&props, 0, sizeof(struct backlight_properties));
- props.max_brightness = COMPAL_LCD_LEVEL_MAX - 1;
- compalbl_device = backlight_device_register("compal-laptop",
+ props.max_brightness = BACKLIGHT_LEVEL_MAX;
+ compalbl_device = backlight_device_register(DRIVER_NAME,
NULL, NULL,
&compalbl_ops,
&props);
@@ -304,67 +965,122 @@ static int __init compal_init(void)
ret = platform_driver_register(&compal_driver);
if (ret)
- goto fail_backlight;
+ goto err_backlight;
- /* Register platform stuff */
-
- compal_device = platform_device_alloc("compal-laptop", -1);
+ compal_device = platform_device_alloc(DRIVER_NAME, -1);
if (!compal_device) {
ret = -ENOMEM;
- goto fail_platform_driver;
+ goto err_platform_driver;
}
- ret = platform_device_add(compal_device);
+ ret = platform_device_add(compal_device); /* This calls compal_probe */
if (ret)
- goto fail_platform_device;
+ goto err_platform_device;
ret = setup_rfkill();
if (ret)
- goto fail_rfkill;
-
- printk(KERN_INFO "compal-laptop: driver "COMPAL_DRIVER_VERSION
- " successfully loaded.\n");
+ goto err_rfkill;
+ printk(KERN_INFO DRIVER_NAME": Driver "DRIVER_VERSION
+ " successfully loaded\n");
return 0;
-fail_rfkill:
+err_rfkill:
platform_device_del(compal_device);
-fail_platform_device:
-
+err_platform_device:
platform_device_put(compal_device);
-fail_platform_driver:
-
+err_platform_driver:
platform_driver_unregister(&compal_driver);
-fail_backlight:
-
+err_backlight:
backlight_device_unregister(compalbl_device);
return ret;
}
-static void __exit compal_cleanup(void)
+static int __devinit compal_probe(struct platform_device *pdev)
{
+ int err;
+ struct compal_data *data;
+
+ if (!extra_features)
+ return 0;
+
+ /* Fan control */
+ data = kzalloc(sizeof(struct compal_data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ initialize_fan_control_data(data);
+
+ err = sysfs_create_group(&pdev->dev.kobj, &compal_attribute_group);
+ if (err)
+ return err;
+
+ data->hwmon_dev = hwmon_device_register(&pdev->dev);
+ if (IS_ERR(data->hwmon_dev)) {
+ err = PTR_ERR(data->hwmon_dev);
+ sysfs_remove_group(&pdev->dev.kobj,
+ &compal_attribute_group);
+ kfree(data);
+ return err;
+ }
+
+ /* Power supply */
+ initialize_power_supply_data(data);
+ power_supply_register(&compal_device->dev, &data->psy);
+
+ platform_set_drvdata(pdev, data);
+
+ return 0;
+}
+static void __exit compal_cleanup(void)
+{
platform_device_unregister(compal_device);
platform_driver_unregister(&compal_driver);
backlight_device_unregister(compalbl_device);
rfkill_unregister(wifi_rfkill);
- rfkill_destroy(wifi_rfkill);
rfkill_unregister(bt_rfkill);
+ rfkill_destroy(wifi_rfkill);
rfkill_destroy(bt_rfkill);
- printk(KERN_INFO "compal-laptop: driver unloaded.\n");
+ printk(KERN_INFO DRIVER_NAME": Driver unloaded\n");
}
+static int __devexit compal_remove(struct platform_device *pdev)
+{
+ struct compal_data *data;
+
+ if (!extra_features)
+ return 0;
+
+ printk(KERN_INFO DRIVER_NAME": Unloading: resetting fan control "
+ "to motherboard\n");
+ pwm_disable_control();
+
+ data = platform_get_drvdata(pdev);
+ hwmon_device_unregister(data->hwmon_dev);
+ power_supply_unregister(&data->psy);
+
+ platform_set_drvdata(pdev, NULL);
+ kfree(data);
+
+ sysfs_remove_group(&pdev->dev.kobj, &compal_attribute_group);
+
+ return 0;
+}
+
+
module_init(compal_init);
module_exit(compal_cleanup);
MODULE_AUTHOR("Cezary Jackiewicz");
+MODULE_AUTHOR("Roald Frederickx (roald.frederickx@gmail.com)");
MODULE_DESCRIPTION("Compal Laptop Support");
-MODULE_VERSION(COMPAL_DRIVER_VERSION);
+MODULE_VERSION(DRIVER_VERSION);
MODULE_LICENSE("GPL");
MODULE_ALIAS("dmi:*:rnIFL90:rvrIFT00:*");
@@ -372,6 +1088,7 @@ MODULE_ALIAS("dmi:*:rnIFL90:rvrREFERENCE:*");
MODULE_ALIAS("dmi:*:rnIFL91:rvrIFT00:*");
MODULE_ALIAS("dmi:*:rnJFL92:rvrIFT00:*");
MODULE_ALIAS("dmi:*:rnIFT00:rvrIFT00:*");
+MODULE_ALIAS("dmi:*:rnJHL90:rvrREFERENCE:*");
MODULE_ALIAS("dmi:*:svnDellInc.:pnInspiron910:*");
MODULE_ALIAS("dmi:*:svnDellInc.:pnInspiron1010:*");
MODULE_ALIAS("dmi:*:svnDellInc.:pnInspiron1011:*");
diff --git a/drivers/platform/x86/dell-laptop.c b/drivers/platform/x86/dell-laptop.c
index 661e3ac4d5b..b41ed5cab3e 100644
--- a/drivers/platform/x86/dell-laptop.c
+++ b/drivers/platform/x86/dell-laptop.c
@@ -83,6 +83,12 @@ static const struct dmi_system_id __initdata dell_device_table[] = {
},
},
{
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+ DMI_MATCH(DMI_CHASSIS_TYPE, "9"), /*Laptop*/
+ },
+ },
+ {
.ident = "Dell Computer Corporation",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"),
@@ -467,7 +473,7 @@ static struct backlight_ops dell_ops = {
.update_status = dell_send_intensity,
};
-bool dell_laptop_i8042_filter(unsigned char data, unsigned char str,
+static bool dell_laptop_i8042_filter(unsigned char data, unsigned char str,
struct serio *port)
{
static bool extended;
@@ -621,4 +627,5 @@ MODULE_AUTHOR("Matthew Garrett <mjg@redhat.com>");
MODULE_DESCRIPTION("Dell laptop driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS("dmi:*svnDellInc.:*:ct8:*");
+MODULE_ALIAS("dmi:*svnDellInc.:*:ct9:*");
MODULE_ALIAS("dmi:*svnDellComputerCorporation.:*:ct8:*");
diff --git a/drivers/platform/x86/dell-wmi.c b/drivers/platform/x86/dell-wmi.c
index 66f53c3c35e..08fb70f6d9b 100644
--- a/drivers/platform/x86/dell-wmi.c
+++ b/drivers/platform/x86/dell-wmi.c
@@ -221,7 +221,7 @@ static void dell_wmi_notify(u32 value, void *context)
return;
}
- if (dell_new_hk_type)
+ if (dell_new_hk_type || buffer_entry[1] == 0x0)
reported_key = (int)buffer_entry[2];
else
reported_key = (int)buffer_entry[1] & 0xffff;
@@ -339,13 +339,18 @@ static int __init dell_wmi_init(void)
acpi_video = acpi_video_backlight_support();
err = dell_wmi_input_setup();
- if (err)
+ if (err) {
+ if (dell_new_hk_type)
+ kfree(dell_wmi_keymap);
return err;
+ }
status = wmi_install_notify_handler(DELL_EVENT_GUID,
dell_wmi_notify, NULL);
if (ACPI_FAILURE(status)) {
input_unregister_device(dell_wmi_input_dev);
+ if (dell_new_hk_type)
+ kfree(dell_wmi_keymap);
printk(KERN_ERR
"dell-wmi: Unable to register notify handler - %d\n",
status);
@@ -359,6 +364,8 @@ static void __exit dell_wmi_exit(void)
{
wmi_remove_notify_handler(DELL_EVENT_GUID);
input_unregister_device(dell_wmi_input_dev);
+ if (dell_new_hk_type)
+ kfree(dell_wmi_keymap);
}
module_init(dell_wmi_init);
diff --git a/drivers/platform/x86/eeepc-laptop.c b/drivers/platform/x86/eeepc-laptop.c
index 0306174ba87..6b8e06206c4 100644
--- a/drivers/platform/x86/eeepc-laptop.c
+++ b/drivers/platform/x86/eeepc-laptop.c
@@ -53,7 +53,7 @@ MODULE_LICENSE("GPL");
static bool hotplug_disabled;
-module_param(hotplug_disabled, bool, 0644);
+module_param(hotplug_disabled, bool, 0444);
MODULE_PARM_DESC(hotplug_disabled,
"Disable hotplug for wireless device. "
"If your laptop need that, please report to "
diff --git a/drivers/platform/x86/fujitsu-laptop.c b/drivers/platform/x86/fujitsu-laptop.c
index e325aeb37d2..f44cd2620ff 100644
--- a/drivers/platform/x86/fujitsu-laptop.c
+++ b/drivers/platform/x86/fujitsu-laptop.c
@@ -182,7 +182,7 @@ static enum led_brightness logolamp_get(struct led_classdev *cdev);
static void logolamp_set(struct led_classdev *cdev,
enum led_brightness brightness);
-struct led_classdev logolamp_led = {
+static struct led_classdev logolamp_led = {
.name = "fujitsu::logolamp",
.brightness_get = logolamp_get,
.brightness_set = logolamp_set
@@ -192,7 +192,7 @@ static enum led_brightness kblamps_get(struct led_classdev *cdev);
static void kblamps_set(struct led_classdev *cdev,
enum led_brightness brightness);
-struct led_classdev kblamps_led = {
+static struct led_classdev kblamps_led = {
.name = "fujitsu::kblamps",
.brightness_get = kblamps_get,
.brightness_set = kblamps_set
@@ -603,7 +603,7 @@ static int dmi_check_cb_s6410(const struct dmi_system_id *id)
dmi_check_cb_common(id);
fujitsu->keycode1 = KEY_SCREENLOCK; /* "Lock" */
fujitsu->keycode2 = KEY_HELP; /* "Mobility Center" */
- return 0;
+ return 1;
}
static int dmi_check_cb_s6420(const struct dmi_system_id *id)
@@ -611,7 +611,7 @@ static int dmi_check_cb_s6420(const struct dmi_system_id *id)
dmi_check_cb_common(id);
fujitsu->keycode1 = KEY_SCREENLOCK; /* "Lock" */
fujitsu->keycode2 = KEY_HELP; /* "Mobility Center" */
- return 0;
+ return 1;
}
static int dmi_check_cb_p8010(const struct dmi_system_id *id)
@@ -620,7 +620,7 @@ static int dmi_check_cb_p8010(const struct dmi_system_id *id)
fujitsu->keycode1 = KEY_HELP; /* "Support" */
fujitsu->keycode3 = KEY_SWITCHVIDEOMODE; /* "Presentation" */
fujitsu->keycode4 = KEY_WWW; /* "Internet" */
- return 0;
+ return 1;
}
static struct dmi_system_id fujitsu_dmi_table[] = {
@@ -725,6 +725,7 @@ static int acpi_fujitsu_add(struct acpi_device *device)
err_unregister_input_dev:
input_unregister_device(input);
+ input = NULL;
err_free_input_dev:
input_free_device(input);
err_stop:
@@ -738,8 +739,6 @@ static int acpi_fujitsu_remove(struct acpi_device *device, int type)
input_unregister_device(input);
- input_free_device(input);
-
fujitsu->acpi_handle = NULL;
return 0;
@@ -930,6 +929,7 @@ static int acpi_fujitsu_hotkey_add(struct acpi_device *device)
err_unregister_input_dev:
input_unregister_device(input);
+ input = NULL;
err_free_input_dev:
input_free_device(input);
err_free_fifo:
@@ -953,8 +953,6 @@ static int acpi_fujitsu_hotkey_remove(struct acpi_device *device, int type)
input_unregister_device(input);
- input_free_device(input);
-
kfifo_free(&fujitsu_hotkey->fifo);
fujitsu_hotkey->acpi_handle = NULL;
diff --git a/drivers/platform/x86/hp-wmi.c b/drivers/platform/x86/hp-wmi.c
index 51c07a05a7b..f1551637498 100644
--- a/drivers/platform/x86/hp-wmi.c
+++ b/drivers/platform/x86/hp-wmi.c
@@ -29,7 +29,6 @@
#include <linux/slab.h>
#include <linux/types.h>
#include <linux/input.h>
-#include <acpi/acpi_drivers.h>
#include <linux/platform_device.h>
#include <linux/acpi.h>
#include <linux/rfkill.h>
@@ -52,12 +51,25 @@ MODULE_ALIAS("wmi:5FB7F034-2C63-45e9-BE91-3D44E2C707E4");
#define HPWMI_WIRELESS_QUERY 0x5
#define HPWMI_HOTKEY_QUERY 0xc
+#define PREFIX "HP WMI: "
+#define UNIMP "Unimplemented "
+
enum hp_wmi_radio {
HPWMI_WIFI = 0,
HPWMI_BLUETOOTH = 1,
HPWMI_WWAN = 2,
};
+enum hp_wmi_event_ids {
+ HPWMI_DOCK_EVENT = 1,
+ HPWMI_PARK_HDD = 2,
+ HPWMI_SMART_ADAPTER = 3,
+ HPWMI_BEZEL_BUTTON = 4,
+ HPWMI_WIRELESS = 5,
+ HPWMI_CPU_BATTERY_THROTTLE = 6,
+ HPWMI_LOCK_SWITCH = 7,
+};
+
static int __devinit hp_wmi_bios_setup(struct platform_device *device);
static int __exit hp_wmi_bios_remove(struct platform_device *device);
static int hp_wmi_resume_handler(struct device *device);
@@ -67,13 +79,12 @@ struct bios_args {
u32 command;
u32 commandtype;
u32 datasize;
- u32 data;
+ char *data;
};
struct bios_return {
u32 sigpass;
u32 return_code;
- u32 value;
};
struct key_entry {
@@ -88,6 +99,7 @@ static struct key_entry hp_wmi_keymap[] = {
{KE_KEY, 0x02, KEY_BRIGHTNESSUP},
{KE_KEY, 0x03, KEY_BRIGHTNESSDOWN},
{KE_KEY, 0x20e6, KEY_PROG1},
+ {KE_KEY, 0x20e8, KEY_MEDIA},
{KE_KEY, 0x2142, KEY_MEDIA},
{KE_KEY, 0x213b, KEY_INFO},
{KE_KEY, 0x2169, KEY_DIRECTION},
@@ -117,7 +129,27 @@ static struct platform_driver hp_wmi_driver = {
.remove = hp_wmi_bios_remove,
};
-static int hp_wmi_perform_query(int query, int write, int value)
+/*
+ * hp_wmi_perform_query
+ *
+ * query: The commandtype -> What should be queried
+ * write: The command -> 0 read, 1 write, 3 ODM specific
+ * buffer: Buffer used as input and/or output
+ * buffersize: Size of buffer
+ *
+ * returns zero on success
+ * an HP WMI query specific error code (which is positive)
+ * -EINVAL if the query was not successful at all
+ * -EINVAL if the output buffer size exceeds buffersize
+ *
+ * Note: The buffersize must at least be the maximum of the input and output
+ * size. E.g. Battery info query (0x7) is defined to have 1 byte input
+ * and 128 byte output. The caller would do:
+ * buffer = kzalloc(128, GFP_KERNEL);
+ * ret = hp_wmi_perform_query(0x7, 0, buffer, 128)
+ */
+static int hp_wmi_perform_query(int query, int write, char *buffer,
+ int buffersize)
{
struct bios_return bios_return;
acpi_status status;
@@ -126,8 +158,8 @@ static int hp_wmi_perform_query(int query, int write, int value)
.signature = 0x55434553,
.command = write ? 0x2 : 0x1,
.commandtype = query,
- .datasize = write ? 0x4 : 0,
- .data = value,
+ .datasize = buffersize,
+ .data = buffer,
};
struct acpi_buffer input = { sizeof(struct bios_args), &args };
struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
@@ -144,54 +176,90 @@ static int hp_wmi_perform_query(int query, int write, int value)
}
bios_return = *((struct bios_return *)obj->buffer.pointer);
+
+ if (bios_return.return_code) {
+ printk(KERN_WARNING PREFIX "Query %d returned %d\n", query,
+ bios_return.return_code);
+ kfree(obj);
+ return bios_return.return_code;
+ }
+ if (obj->buffer.length - sizeof(bios_return) > buffersize) {
+ kfree(obj);
+ return -EINVAL;
+ }
+
+ memset(buffer, 0, buffersize);
+ memcpy(buffer,
+ ((char *)obj->buffer.pointer) + sizeof(struct bios_return),
+ obj->buffer.length - sizeof(bios_return));
kfree(obj);
- if (bios_return.return_code > 0)
- return bios_return.return_code * -1;
- else
- return bios_return.value;
+ return 0;
}
static int hp_wmi_display_state(void)
{
- return hp_wmi_perform_query(HPWMI_DISPLAY_QUERY, 0, 0);
+ int state;
+ int ret = hp_wmi_perform_query(HPWMI_DISPLAY_QUERY, 0, (char *)&state,
+ sizeof(state));
+ if (ret)
+ return -EINVAL;
+ return state;
}
static int hp_wmi_hddtemp_state(void)
{
- return hp_wmi_perform_query(HPWMI_HDDTEMP_QUERY, 0, 0);
+ int state;
+ int ret = hp_wmi_perform_query(HPWMI_HDDTEMP_QUERY, 0, (char *)&state,
+ sizeof(state));
+ if (ret)
+ return -EINVAL;
+ return state;
}
static int hp_wmi_als_state(void)
{
- return hp_wmi_perform_query(HPWMI_ALS_QUERY, 0, 0);
+ int state;
+ int ret = hp_wmi_perform_query(HPWMI_ALS_QUERY, 0, (char *)&state,
+ sizeof(state));
+ if (ret)
+ return -EINVAL;
+ return state;
}
static int hp_wmi_dock_state(void)
{
- int ret = hp_wmi_perform_query(HPWMI_HARDWARE_QUERY, 0, 0);
+ int state;
+ int ret = hp_wmi_perform_query(HPWMI_HARDWARE_QUERY, 0, (char *)&state,
+ sizeof(state));
- if (ret < 0)
- return ret;
+ if (ret)
+ return -EINVAL;
- return ret & 0x1;
+ return state & 0x1;
}
static int hp_wmi_tablet_state(void)
{
- int ret = hp_wmi_perform_query(HPWMI_HARDWARE_QUERY, 0, 0);
-
- if (ret < 0)
+ int state;
+ int ret = hp_wmi_perform_query(HPWMI_HARDWARE_QUERY, 0, (char *)&state,
+ sizeof(state));
+ if (ret)
return ret;
- return (ret & 0x4) ? 1 : 0;
+ return (state & 0x4) ? 1 : 0;
}
static int hp_wmi_set_block(void *data, bool blocked)
{
enum hp_wmi_radio r = (enum hp_wmi_radio) data;
int query = BIT(r + 8) | ((!blocked) << r);
+ int ret;
- return hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 1, query);
+ ret = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 1,
+ (char *)&query, sizeof(query));
+ if (ret)
+ return -EINVAL;
+ return 0;
}
static const struct rfkill_ops hp_wmi_rfkill_ops = {
@@ -200,8 +268,13 @@ static const struct rfkill_ops hp_wmi_rfkill_ops = {
static bool hp_wmi_get_sw_state(enum hp_wmi_radio r)
{
- int wireless = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0, 0);
- int mask = 0x200 << (r * 8);
+ int wireless;
+ int mask;
+ hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0,
+ (char *)&wireless, sizeof(wireless));
+ /* TBD: Pass error */
+
+ mask = 0x200 << (r * 8);
if (wireless & mask)
return false;
@@ -211,8 +284,13 @@ static bool hp_wmi_get_sw_state(enum hp_wmi_radio r)
static bool hp_wmi_get_hw_state(enum hp_wmi_radio r)
{
- int wireless = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0, 0);
- int mask = 0x800 << (r * 8);
+ int wireless;
+ int mask;
+ hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0,
+ (char *)&wireless, sizeof(wireless));
+ /* TBD: Pass error */
+
+ mask = 0x800 << (r * 8);
if (wireless & mask)
return false;
@@ -269,7 +347,11 @@ static ssize_t set_als(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
u32 tmp = simple_strtoul(buf, NULL, 10);
- hp_wmi_perform_query(HPWMI_ALS_QUERY, 1, tmp);
+ int ret = hp_wmi_perform_query(HPWMI_ALS_QUERY, 1, (char *)&tmp,
+ sizeof(tmp));
+ if (ret)
+ return -EINVAL;
+
return count;
}
@@ -338,47 +420,82 @@ static void hp_wmi_notify(u32 value, void *context)
struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL };
static struct key_entry *key;
union acpi_object *obj;
- int eventcode;
+ u32 event_id, event_data;
+ int key_code, ret;
+ u32 *location;
acpi_status status;
status = wmi_get_event_data(value, &response);
if (status != AE_OK) {
- printk(KERN_INFO "hp-wmi: bad event status 0x%x\n", status);
+ printk(KERN_INFO PREFIX "bad event status 0x%x\n", status);
return;
}
obj = (union acpi_object *)response.pointer;
- if (!obj || obj->type != ACPI_TYPE_BUFFER || obj->buffer.length != 8) {
- printk(KERN_INFO "HP WMI: Unknown response received\n");
+ if (!obj)
+ return;
+ if (obj->type != ACPI_TYPE_BUFFER) {
+ printk(KERN_INFO "hp-wmi: Unknown response received %d\n",
+ obj->type);
kfree(obj);
return;
}
- eventcode = *((u8 *) obj->buffer.pointer);
+ /*
+ * Depending on ACPI version the concatenation of id and event data
+ * inside _WED function will result in a 8 or 16 byte buffer.
+ */
+ location = (u32 *)obj->buffer.pointer;
+ if (obj->buffer.length == 8) {
+ event_id = *location;
+ event_data = *(location + 1);
+ } else if (obj->buffer.length == 16) {
+ event_id = *location;
+ event_data = *(location + 2);
+ } else {
+ printk(KERN_INFO "hp-wmi: Unknown buffer length %d\n",
+ obj->buffer.length);
+ kfree(obj);
+ return;
+ }
kfree(obj);
- if (eventcode == 0x4)
- eventcode = hp_wmi_perform_query(HPWMI_HOTKEY_QUERY, 0,
- 0);
- key = hp_wmi_get_entry_by_scancode(eventcode);
- if (key) {
- switch (key->type) {
- case KE_KEY:
- input_report_key(hp_wmi_input_dev,
- key->keycode, 1);
- input_sync(hp_wmi_input_dev);
- input_report_key(hp_wmi_input_dev,
- key->keycode, 0);
- input_sync(hp_wmi_input_dev);
- break;
- }
- } else if (eventcode == 0x1) {
+
+ switch (event_id) {
+ case HPWMI_DOCK_EVENT:
input_report_switch(hp_wmi_input_dev, SW_DOCK,
hp_wmi_dock_state());
input_report_switch(hp_wmi_input_dev, SW_TABLET_MODE,
hp_wmi_tablet_state());
input_sync(hp_wmi_input_dev);
- } else if (eventcode == 0x5) {
+ break;
+ case HPWMI_PARK_HDD:
+ break;
+ case HPWMI_SMART_ADAPTER:
+ break;
+ case HPWMI_BEZEL_BUTTON:
+ ret = hp_wmi_perform_query(HPWMI_HOTKEY_QUERY, 0,
+ (char *)&key_code,
+ sizeof(key_code));
+ if (ret)
+ break;
+ key = hp_wmi_get_entry_by_scancode(key_code);
+ if (key) {
+ switch (key->type) {
+ case KE_KEY:
+ input_report_key(hp_wmi_input_dev,
+ key->keycode, 1);
+ input_sync(hp_wmi_input_dev);
+ input_report_key(hp_wmi_input_dev,
+ key->keycode, 0);
+ input_sync(hp_wmi_input_dev);
+ break;
+ }
+ } else
+ printk(KERN_INFO PREFIX "Unknown key code - 0x%x\n",
+ key_code);
+ break;
+ case HPWMI_WIRELESS:
if (wifi_rfkill)
rfkill_set_states(wifi_rfkill,
hp_wmi_get_sw_state(HPWMI_WIFI),
@@ -391,9 +508,18 @@ static void hp_wmi_notify(u32 value, void *context)
rfkill_set_states(wwan_rfkill,
hp_wmi_get_sw_state(HPWMI_WWAN),
hp_wmi_get_hw_state(HPWMI_WWAN));
- } else
- printk(KERN_INFO "HP WMI: Unknown key pressed - %x\n",
- eventcode);
+ break;
+ case HPWMI_CPU_BATTERY_THROTTLE:
+ printk(KERN_INFO PREFIX UNIMP "CPU throttle because of 3 Cell"
+ " battery event detected\n");
+ break;
+ case HPWMI_LOCK_SWITCH:
+ break;
+ default:
+ printk(KERN_INFO PREFIX "Unknown event_id - %d - 0x%x\n",
+ event_id, event_data);
+ break;
+ }
}
static int __init hp_wmi_input_setup(void)
@@ -402,6 +528,8 @@ static int __init hp_wmi_input_setup(void)
int err;
hp_wmi_input_dev = input_allocate_device();
+ if (!hp_wmi_input_dev)
+ return -ENOMEM;
hp_wmi_input_dev->name = "HP WMI hotkeys";
hp_wmi_input_dev->phys = "wmi/input0";
@@ -450,7 +578,12 @@ static void cleanup_sysfs(struct platform_device *device)
static int __devinit hp_wmi_bios_setup(struct platform_device *device)
{
int err;
- int wireless = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0, 0);
+ int wireless;
+
+ err = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0, (char *)&wireless,
+ sizeof(wireless));
+ if (err)
+ return err;
err = device_create_file(&device->dev, &dev_attr_display);
if (err)
@@ -581,27 +714,51 @@ static int hp_wmi_resume_handler(struct device *device)
static int __init hp_wmi_init(void)
{
int err;
+ int event_capable = wmi_has_guid(HPWMI_EVENT_GUID);
+ int bios_capable = wmi_has_guid(HPWMI_BIOS_GUID);
- if (wmi_has_guid(HPWMI_EVENT_GUID)) {
+ if (event_capable) {
err = wmi_install_notify_handler(HPWMI_EVENT_GUID,
hp_wmi_notify, NULL);
- if (ACPI_SUCCESS(err))
- hp_wmi_input_setup();
+ if (ACPI_FAILURE(err))
+ return -EINVAL;
+ err = hp_wmi_input_setup();
+ if (err) {
+ wmi_remove_notify_handler(HPWMI_EVENT_GUID);
+ return err;
+ }
}
- if (wmi_has_guid(HPWMI_BIOS_GUID)) {
+ if (bios_capable) {
err = platform_driver_register(&hp_wmi_driver);
if (err)
- return 0;
+ goto err_driver_reg;
hp_wmi_platform_dev = platform_device_alloc("hp-wmi", -1);
if (!hp_wmi_platform_dev) {
- platform_driver_unregister(&hp_wmi_driver);
- return 0;
+ err = -ENOMEM;
+ goto err_device_alloc;
}
- platform_device_add(hp_wmi_platform_dev);
+ err = platform_device_add(hp_wmi_platform_dev);
+ if (err)
+ goto err_device_add;
}
+ if (!bios_capable && !event_capable)
+ return -ENODEV;
+
return 0;
+
+err_device_add:
+ platform_device_put(hp_wmi_platform_dev);
+err_device_alloc:
+ platform_driver_unregister(&hp_wmi_driver);
+err_driver_reg:
+ if (wmi_has_guid(HPWMI_EVENT_GUID)) {
+ input_unregister_device(hp_wmi_input_dev);
+ wmi_remove_notify_handler(HPWMI_EVENT_GUID);
+ }
+
+ return err;
}
static void __exit hp_wmi_exit(void)
@@ -611,7 +768,7 @@ static void __exit hp_wmi_exit(void)
input_unregister_device(hp_wmi_input_dev);
}
if (hp_wmi_platform_dev) {
- platform_device_del(hp_wmi_platform_dev);
+ platform_device_unregister(hp_wmi_platform_dev);
platform_driver_unregister(&hp_wmi_driver);
}
}
diff --git a/drivers/platform/x86/intel_ips.c b/drivers/platform/x86/intel_ips.c
new file mode 100644
index 00000000000..afe82e50dfe
--- /dev/null
+++ b/drivers/platform/x86/intel_ips.c
@@ -0,0 +1,1660 @@
+/*
+ * Copyright (c) 2009-2010 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.
+ *
+ * The full GNU General Public License is included in this distribution in
+ * the file called "COPYING".
+ *
+ * Authors:
+ * Jesse Barnes <jbarnes@virtuousgeek.org>
+ */
+
+/*
+ * Some Intel Ibex Peak based platforms support so-called "intelligent
+ * power sharing", which allows the CPU and GPU to cooperate to maximize
+ * performance within a given TDP (thermal design point). This driver
+ * performs the coordination between the CPU and GPU, monitors thermal and
+ * power statistics in the platform, and initializes power monitoring
+ * hardware. It also provides a few tunables to control behavior. Its
+ * primary purpose is to safely allow CPU and GPU turbo modes to be enabled
+ * by tracking power and thermal budget; secondarily it can boost turbo
+ * performance by allocating more power or thermal budget to the CPU or GPU
+ * based on available headroom and activity.
+ *
+ * The basic algorithm is driven by a 5s moving average of tempurature. If
+ * thermal headroom is available, the CPU and/or GPU power clamps may be
+ * adjusted upwards. If we hit the thermal ceiling or a thermal trigger,
+ * we scale back the clamp. Aside from trigger events (when we're critically
+ * close or over our TDP) we don't adjust the clamps more than once every
+ * five seconds.
+ *
+ * The thermal device (device 31, function 6) has a set of registers that
+ * are updated by the ME firmware. The ME should also take the clamp values
+ * written to those registers and write them to the CPU, but we currently
+ * bypass that functionality and write the CPU MSR directly.
+ *
+ * UNSUPPORTED:
+ * - dual MCP configs
+ *
+ * TODO:
+ * - handle CPU hotplug
+ * - provide turbo enable/disable api
+ * - make sure we can write turbo enable/disable reg based on MISC_EN
+ *
+ * Related documents:
+ * - CDI 403777, 403778 - Auburndale EDS vol 1 & 2
+ * - CDI 401376 - Ibex Peak EDS
+ * - ref 26037, 26641 - IPS BIOS spec
+ * - ref 26489 - Nehalem BIOS writer's guide
+ * - ref 26921 - Ibex Peak BIOS Specification
+ */
+
+#include <linux/debugfs.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/kthread.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/sched.h>
+#include <linux/seq_file.h>
+#include <linux/string.h>
+#include <linux/tick.h>
+#include <linux/timer.h>
+#include <drm/i915_drm.h>
+#include <asm/msr.h>
+#include <asm/processor.h>
+
+#define PCI_DEVICE_ID_INTEL_THERMAL_SENSOR 0x3b32
+
+/*
+ * Package level MSRs for monitor/control
+ */
+#define PLATFORM_INFO 0xce
+#define PLATFORM_TDP (1<<29)
+#define PLATFORM_RATIO (1<<28)
+
+#define IA32_MISC_ENABLE 0x1a0
+#define IA32_MISC_TURBO_EN (1ULL<<38)
+
+#define TURBO_POWER_CURRENT_LIMIT 0x1ac
+#define TURBO_TDC_OVR_EN (1UL<<31)
+#define TURBO_TDC_MASK (0x000000007fff0000UL)
+#define TURBO_TDC_SHIFT (16)
+#define TURBO_TDP_OVR_EN (1UL<<15)
+#define TURBO_TDP_MASK (0x0000000000003fffUL)
+
+/*
+ * Core/thread MSRs for monitoring
+ */
+#define IA32_PERF_CTL 0x199
+#define IA32_PERF_TURBO_DIS (1ULL<<32)
+
+/*
+ * Thermal PCI device regs
+ */
+#define THM_CFG_TBAR 0x10
+#define THM_CFG_TBAR_HI 0x14
+
+#define THM_TSIU 0x00
+#define THM_TSE 0x01
+#define TSE_EN 0xb8
+#define THM_TSS 0x02
+#define THM_TSTR 0x03
+#define THM_TSTTP 0x04
+#define THM_TSCO 0x08
+#define THM_TSES 0x0c
+#define THM_TSGPEN 0x0d
+#define TSGPEN_HOT_LOHI (1<<1)
+#define TSGPEN_CRIT_LOHI (1<<2)
+#define THM_TSPC 0x0e
+#define THM_PPEC 0x10
+#define THM_CTA 0x12
+#define THM_PTA 0x14
+#define PTA_SLOPE_MASK (0xff00)
+#define PTA_SLOPE_SHIFT 8
+#define PTA_OFFSET_MASK (0x00ff)
+#define THM_MGTA 0x16
+#define MGTA_SLOPE_MASK (0xff00)
+#define MGTA_SLOPE_SHIFT 8
+#define MGTA_OFFSET_MASK (0x00ff)
+#define THM_TRC 0x1a
+#define TRC_CORE2_EN (1<<15)
+#define TRC_THM_EN (1<<12)
+#define TRC_C6_WAR (1<<8)
+#define TRC_CORE1_EN (1<<7)
+#define TRC_CORE_PWR (1<<6)
+#define TRC_PCH_EN (1<<5)
+#define TRC_MCH_EN (1<<4)
+#define TRC_DIMM4 (1<<3)
+#define TRC_DIMM3 (1<<2)
+#define TRC_DIMM2 (1<<1)
+#define TRC_DIMM1 (1<<0)
+#define THM_TES 0x20
+#define THM_TEN 0x21
+#define TEN_UPDATE_EN 1
+#define THM_PSC 0x24
+#define PSC_NTG (1<<0) /* No GFX turbo support */
+#define PSC_NTPC (1<<1) /* No CPU turbo support */
+#define PSC_PP_DEF (0<<2) /* Perf policy up to driver */
+#define PSP_PP_PC (1<<2) /* BIOS prefers CPU perf */
+#define PSP_PP_BAL (2<<2) /* BIOS wants balanced perf */
+#define PSP_PP_GFX (3<<2) /* BIOS prefers GFX perf */
+#define PSP_PBRT (1<<4) /* BIOS run time support */
+#define THM_CTV1 0x30
+#define CTV_TEMP_ERROR (1<<15)
+#define CTV_TEMP_MASK 0x3f
+#define CTV_
+#define THM_CTV2 0x32
+#define THM_CEC 0x34 /* undocumented power accumulator in joules */
+#define THM_AE 0x3f
+#define THM_HTS 0x50 /* 32 bits */
+#define HTS_PCPL_MASK (0x7fe00000)
+#define HTS_PCPL_SHIFT 21
+#define HTS_GPL_MASK (0x001ff000)
+#define HTS_GPL_SHIFT 12
+#define HTS_PP_MASK (0x00000c00)
+#define HTS_PP_SHIFT 10
+#define HTS_PP_DEF 0
+#define HTS_PP_PROC 1
+#define HTS_PP_BAL 2
+#define HTS_PP_GFX 3
+#define HTS_PCTD_DIS (1<<9)
+#define HTS_GTD_DIS (1<<8)
+#define HTS_PTL_MASK (0x000000fe)
+#define HTS_PTL_SHIFT 1
+#define HTS_NVV (1<<0)
+#define THM_HTSHI 0x54 /* 16 bits */
+#define HTS2_PPL_MASK (0x03ff)
+#define HTS2_PRST_MASK (0x3c00)
+#define HTS2_PRST_SHIFT 10
+#define HTS2_PRST_UNLOADED 0
+#define HTS2_PRST_RUNNING 1
+#define HTS2_PRST_TDISOP 2 /* turbo disabled due to power */
+#define HTS2_PRST_TDISHT 3 /* turbo disabled due to high temp */
+#define HTS2_PRST_TDISUSR 4 /* user disabled turbo */
+#define HTS2_PRST_TDISPLAT 5 /* platform disabled turbo */
+#define HTS2_PRST_TDISPM 6 /* power management disabled turbo */
+#define HTS2_PRST_TDISERR 7 /* some kind of error disabled turbo */
+#define THM_PTL 0x56
+#define THM_MGTV 0x58
+#define TV_MASK 0x000000000000ff00
+#define TV_SHIFT 8
+#define THM_PTV 0x60
+#define PTV_MASK 0x00ff
+#define THM_MMGPC 0x64
+#define THM_MPPC 0x66
+#define THM_MPCPC 0x68
+#define THM_TSPIEN 0x82
+#define TSPIEN_AUX_LOHI (1<<0)
+#define TSPIEN_HOT_LOHI (1<<1)
+#define TSPIEN_CRIT_LOHI (1<<2)
+#define TSPIEN_AUX2_LOHI (1<<3)
+#define THM_TSLOCK 0x83
+#define THM_ATR 0x84
+#define THM_TOF 0x87
+#define THM_STS 0x98
+#define STS_PCPL_MASK (0x7fe00000)
+#define STS_PCPL_SHIFT 21
+#define STS_GPL_MASK (0x001ff000)
+#define STS_GPL_SHIFT 12
+#define STS_PP_MASK (0x00000c00)
+#define STS_PP_SHIFT 10
+#define STS_PP_DEF 0
+#define STS_PP_PROC 1
+#define STS_PP_BAL 2
+#define STS_PP_GFX 3
+#define STS_PCTD_DIS (1<<9)
+#define STS_GTD_DIS (1<<8)
+#define STS_PTL_MASK (0x000000fe)
+#define STS_PTL_SHIFT 1
+#define STS_NVV (1<<0)
+#define THM_SEC 0x9c
+#define SEC_ACK (1<<0)
+#define THM_TC3 0xa4
+#define THM_TC1 0xa8
+#define STS_PPL_MASK (0x0003ff00)
+#define STS_PPL_SHIFT 16
+#define THM_TC2 0xac
+#define THM_DTV 0xb0
+#define THM_ITV 0xd8
+#define ITV_ME_SEQNO_MASK 0x000f0000 /* ME should update every ~200ms */
+#define ITV_ME_SEQNO_SHIFT (16)
+#define ITV_MCH_TEMP_MASK 0x0000ff00
+#define ITV_MCH_TEMP_SHIFT (8)
+#define ITV_PCH_TEMP_MASK 0x000000ff
+
+#define thm_readb(off) readb(ips->regmap + (off))
+#define thm_readw(off) readw(ips->regmap + (off))
+#define thm_readl(off) readl(ips->regmap + (off))
+#define thm_readq(off) readq(ips->regmap + (off))
+
+#define thm_writeb(off, val) writeb((val), ips->regmap + (off))
+#define thm_writew(off, val) writew((val), ips->regmap + (off))
+#define thm_writel(off, val) writel((val), ips->regmap + (off))
+
+static const int IPS_ADJUST_PERIOD = 5000; /* ms */
+
+/* For initial average collection */
+static const int IPS_SAMPLE_PERIOD = 200; /* ms */
+static const int IPS_SAMPLE_WINDOW = 5000; /* 5s moving window of samples */
+#define IPS_SAMPLE_COUNT (IPS_SAMPLE_WINDOW / IPS_SAMPLE_PERIOD)
+
+/* Per-SKU limits */
+struct ips_mcp_limits {
+ int cpu_family;
+ int cpu_model; /* includes extended model... */
+ int mcp_power_limit; /* mW units */
+ int core_power_limit;
+ int mch_power_limit;
+ int core_temp_limit; /* degrees C */
+ int mch_temp_limit;
+};
+
+/* Max temps are -10 degrees C to avoid PROCHOT# */
+
+struct ips_mcp_limits ips_sv_limits = {
+ .mcp_power_limit = 35000,
+ .core_power_limit = 29000,
+ .mch_power_limit = 20000,
+ .core_temp_limit = 95,
+ .mch_temp_limit = 90
+};
+
+struct ips_mcp_limits ips_lv_limits = {
+ .mcp_power_limit = 25000,
+ .core_power_limit = 21000,
+ .mch_power_limit = 13000,
+ .core_temp_limit = 95,
+ .mch_temp_limit = 90
+};
+
+struct ips_mcp_limits ips_ulv_limits = {
+ .mcp_power_limit = 18000,
+ .core_power_limit = 14000,
+ .mch_power_limit = 11000,
+ .core_temp_limit = 95,
+ .mch_temp_limit = 90
+};
+
+struct ips_driver {
+ struct pci_dev *dev;
+ void *regmap;
+ struct task_struct *monitor;
+ struct task_struct *adjust;
+ struct dentry *debug_root;
+
+ /* Average CPU core temps (all averages in .01 degrees C for precision) */
+ u16 ctv1_avg_temp;
+ u16 ctv2_avg_temp;
+ /* GMCH average */
+ u16 mch_avg_temp;
+ /* Average for the CPU (both cores?) */
+ u16 mcp_avg_temp;
+ /* Average power consumption (in mW) */
+ u32 cpu_avg_power;
+ u32 mch_avg_power;
+
+ /* Offset values */
+ u16 cta_val;
+ u16 pta_val;
+ u16 mgta_val;
+
+ /* Maximums & prefs, protected by turbo status lock */
+ spinlock_t turbo_status_lock;
+ u16 mcp_temp_limit;
+ u16 mcp_power_limit;
+ u16 core_power_limit;
+ u16 mch_power_limit;
+ bool cpu_turbo_enabled;
+ bool __cpu_turbo_on;
+ bool gpu_turbo_enabled;
+ bool __gpu_turbo_on;
+ bool gpu_preferred;
+ bool poll_turbo_status;
+ bool second_cpu;
+ struct ips_mcp_limits *limits;
+
+ /* Optional MCH interfaces for if i915 is in use */
+ unsigned long (*read_mch_val)(void);
+ bool (*gpu_raise)(void);
+ bool (*gpu_lower)(void);
+ bool (*gpu_busy)(void);
+ bool (*gpu_turbo_disable)(void);
+
+ /* For restoration at unload */
+ u64 orig_turbo_limit;
+ u64 orig_turbo_ratios;
+};
+
+/**
+ * ips_cpu_busy - is CPU busy?
+ * @ips: IPS driver struct
+ *
+ * Check CPU for load to see whether we should increase its thermal budget.
+ *
+ * RETURNS:
+ * True if the CPU could use more power, false otherwise.
+ */
+static bool ips_cpu_busy(struct ips_driver *ips)
+{
+ if ((avenrun[0] >> FSHIFT) > 1)
+ return true;
+
+ return false;
+}
+
+/**
+ * ips_cpu_raise - raise CPU power clamp
+ * @ips: IPS driver struct
+ *
+ * Raise the CPU power clamp by %IPS_CPU_STEP, in accordance with TDP for
+ * this platform.
+ *
+ * We do this by adjusting the TURBO_POWER_CURRENT_LIMIT MSR upwards (as
+ * long as we haven't hit the TDP limit for the SKU).
+ */
+static void ips_cpu_raise(struct ips_driver *ips)
+{
+ u64 turbo_override;
+ u16 cur_tdp_limit, new_tdp_limit;
+
+ if (!ips->cpu_turbo_enabled)
+ return;
+
+ rdmsrl(TURBO_POWER_CURRENT_LIMIT, turbo_override);
+
+ cur_tdp_limit = turbo_override & TURBO_TDP_MASK;
+ new_tdp_limit = cur_tdp_limit + 8; /* 1W increase */
+
+ /* Clamp to SKU TDP limit */
+ if (((new_tdp_limit * 10) / 8) > ips->core_power_limit)
+ new_tdp_limit = cur_tdp_limit;
+
+ thm_writew(THM_MPCPC, (new_tdp_limit * 10) / 8);
+
+ turbo_override |= TURBO_TDC_OVR_EN | TURBO_TDC_OVR_EN;
+ wrmsrl(TURBO_POWER_CURRENT_LIMIT, turbo_override);
+
+ turbo_override &= ~TURBO_TDP_MASK;
+ turbo_override |= new_tdp_limit;
+
+ wrmsrl(TURBO_POWER_CURRENT_LIMIT, turbo_override);
+}
+
+/**
+ * ips_cpu_lower - lower CPU power clamp
+ * @ips: IPS driver struct
+ *
+ * Lower CPU power clamp b %IPS_CPU_STEP if possible.
+ *
+ * We do this by adjusting the TURBO_POWER_CURRENT_LIMIT MSR down, going
+ * as low as the platform limits will allow (though we could go lower there
+ * wouldn't be much point).
+ */
+static void ips_cpu_lower(struct ips_driver *ips)
+{
+ u64 turbo_override;
+ u16 cur_limit, new_limit;
+
+ rdmsrl(TURBO_POWER_CURRENT_LIMIT, turbo_override);
+
+ cur_limit = turbo_override & TURBO_TDP_MASK;
+ new_limit = cur_limit - 8; /* 1W decrease */
+
+ /* Clamp to SKU TDP limit */
+ if (((new_limit * 10) / 8) < (ips->orig_turbo_limit & TURBO_TDP_MASK))
+ new_limit = ips->orig_turbo_limit & TURBO_TDP_MASK;
+
+ thm_writew(THM_MPCPC, (new_limit * 10) / 8);
+
+ turbo_override |= TURBO_TDC_OVR_EN | TURBO_TDC_OVR_EN;
+ wrmsrl(TURBO_POWER_CURRENT_LIMIT, turbo_override);
+
+ turbo_override &= ~TURBO_TDP_MASK;
+ turbo_override |= new_limit;
+
+ wrmsrl(TURBO_POWER_CURRENT_LIMIT, turbo_override);
+}
+
+/**
+ * do_enable_cpu_turbo - internal turbo enable function
+ * @data: unused
+ *
+ * Internal function for actually updating MSRs. When we enable/disable
+ * turbo, we need to do it on each CPU; this function is the one called
+ * by on_each_cpu() when needed.
+ */
+static void do_enable_cpu_turbo(void *data)
+{
+ u64 perf_ctl;
+
+ rdmsrl(IA32_PERF_CTL, perf_ctl);
+ if (perf_ctl & IA32_PERF_TURBO_DIS) {
+ perf_ctl &= ~IA32_PERF_TURBO_DIS;
+ wrmsrl(IA32_PERF_CTL, perf_ctl);
+ }
+}
+
+/**
+ * ips_enable_cpu_turbo - enable turbo mode on all CPUs
+ * @ips: IPS driver struct
+ *
+ * Enable turbo mode by clearing the disable bit in IA32_PERF_CTL on
+ * all logical threads.
+ */
+static void ips_enable_cpu_turbo(struct ips_driver *ips)
+{
+ /* Already on, no need to mess with MSRs */
+ if (ips->__cpu_turbo_on)
+ return;
+
+ on_each_cpu(do_enable_cpu_turbo, ips, 1);
+
+ ips->__cpu_turbo_on = true;
+}
+
+/**
+ * do_disable_cpu_turbo - internal turbo disable function
+ * @data: unused
+ *
+ * Internal function for actually updating MSRs. When we enable/disable
+ * turbo, we need to do it on each CPU; this function is the one called
+ * by on_each_cpu() when needed.
+ */
+static void do_disable_cpu_turbo(void *data)
+{
+ u64 perf_ctl;
+
+ rdmsrl(IA32_PERF_CTL, perf_ctl);
+ if (!(perf_ctl & IA32_PERF_TURBO_DIS)) {
+ perf_ctl |= IA32_PERF_TURBO_DIS;
+ wrmsrl(IA32_PERF_CTL, perf_ctl);
+ }
+}
+
+/**
+ * ips_disable_cpu_turbo - disable turbo mode on all CPUs
+ * @ips: IPS driver struct
+ *
+ * Disable turbo mode by setting the disable bit in IA32_PERF_CTL on
+ * all logical threads.
+ */
+static void ips_disable_cpu_turbo(struct ips_driver *ips)
+{
+ /* Already off, leave it */
+ if (!ips->__cpu_turbo_on)
+ return;
+
+ on_each_cpu(do_disable_cpu_turbo, ips, 1);
+
+ ips->__cpu_turbo_on = false;
+}
+
+/**
+ * ips_gpu_busy - is GPU busy?
+ * @ips: IPS driver struct
+ *
+ * Check GPU for load to see whether we should increase its thermal budget.
+ * We need to call into the i915 driver in this case.
+ *
+ * RETURNS:
+ * True if the GPU could use more power, false otherwise.
+ */
+static bool ips_gpu_busy(struct ips_driver *ips)
+{
+ if (!ips->gpu_turbo_enabled)
+ return false;
+
+ return ips->gpu_busy();
+}
+
+/**
+ * ips_gpu_raise - raise GPU power clamp
+ * @ips: IPS driver struct
+ *
+ * Raise the GPU frequency/power if possible. We need to call into the
+ * i915 driver in this case.
+ */
+static void ips_gpu_raise(struct ips_driver *ips)
+{
+ if (!ips->gpu_turbo_enabled)
+ return;
+
+ if (!ips->gpu_raise())
+ ips->gpu_turbo_enabled = false;
+
+ return;
+}
+
+/**
+ * ips_gpu_lower - lower GPU power clamp
+ * @ips: IPS driver struct
+ *
+ * Lower GPU frequency/power if possible. Need to call i915.
+ */
+static void ips_gpu_lower(struct ips_driver *ips)
+{
+ if (!ips->gpu_turbo_enabled)
+ return;
+
+ if (!ips->gpu_lower())
+ ips->gpu_turbo_enabled = false;
+
+ return;
+}
+
+/**
+ * ips_enable_gpu_turbo - notify the gfx driver turbo is available
+ * @ips: IPS driver struct
+ *
+ * Call into the graphics driver indicating that it can safely use
+ * turbo mode.
+ */
+static void ips_enable_gpu_turbo(struct ips_driver *ips)
+{
+ if (ips->__gpu_turbo_on)
+ return;
+ ips->__gpu_turbo_on = true;
+}
+
+/**
+ * ips_disable_gpu_turbo - notify the gfx driver to disable turbo mode
+ * @ips: IPS driver struct
+ *
+ * Request that the graphics driver disable turbo mode.
+ */
+static void ips_disable_gpu_turbo(struct ips_driver *ips)
+{
+ /* Avoid calling i915 if turbo is already disabled */
+ if (!ips->__gpu_turbo_on)
+ return;
+
+ if (!ips->gpu_turbo_disable())
+ dev_err(&ips->dev->dev, "failed to disable graphis turbo\n");
+ else
+ ips->__gpu_turbo_on = false;
+}
+
+/**
+ * mcp_exceeded - check whether we're outside our thermal & power limits
+ * @ips: IPS driver struct
+ *
+ * Check whether the MCP is over its thermal or power budget.
+ */
+static bool mcp_exceeded(struct ips_driver *ips)
+{
+ unsigned long flags;
+ bool ret = false;
+
+ spin_lock_irqsave(&ips->turbo_status_lock, flags);
+ if (ips->mcp_avg_temp > (ips->mcp_temp_limit * 100))
+ ret = true;
+ if (ips->cpu_avg_power + ips->mch_avg_power > ips->mcp_power_limit)
+ ret = true;
+ spin_unlock_irqrestore(&ips->turbo_status_lock, flags);
+
+ if (ret)
+ dev_info(&ips->dev->dev,
+ "MCP power or thermal limit exceeded\n");
+
+ return ret;
+}
+
+/**
+ * cpu_exceeded - check whether a CPU core is outside its limits
+ * @ips: IPS driver struct
+ * @cpu: CPU number to check
+ *
+ * Check a given CPU's average temp or power is over its limit.
+ */
+static bool cpu_exceeded(struct ips_driver *ips, int cpu)
+{
+ unsigned long flags;
+ int avg;
+ bool ret = false;
+
+ spin_lock_irqsave(&ips->turbo_status_lock, flags);
+ avg = cpu ? ips->ctv2_avg_temp : ips->ctv1_avg_temp;
+ if (avg > (ips->limits->core_temp_limit * 100))
+ ret = true;
+ if (ips->cpu_avg_power > ips->core_power_limit * 100)
+ ret = true;
+ spin_unlock_irqrestore(&ips->turbo_status_lock, flags);
+
+ if (ret)
+ dev_info(&ips->dev->dev,
+ "CPU power or thermal limit exceeded\n");
+
+ return ret;
+}
+
+/**
+ * mch_exceeded - check whether the GPU is over budget
+ * @ips: IPS driver struct
+ *
+ * Check the MCH temp & power against their maximums.
+ */
+static bool mch_exceeded(struct ips_driver *ips)
+{
+ unsigned long flags;
+ bool ret = false;
+
+ spin_lock_irqsave(&ips->turbo_status_lock, flags);
+ if (ips->mch_avg_temp > (ips->limits->mch_temp_limit * 100))
+ ret = true;
+ if (ips->mch_avg_power > ips->mch_power_limit)
+ ret = true;
+ spin_unlock_irqrestore(&ips->turbo_status_lock, flags);
+
+ return ret;
+}
+
+/**
+ * update_turbo_limits - get various limits & settings from regs
+ * @ips: IPS driver struct
+ *
+ * Update the IPS power & temp limits, along with turbo enable flags,
+ * based on latest register contents.
+ *
+ * Used at init time and for runtime BIOS support, which requires polling
+ * the regs for updates (as a result of AC->DC transition for example).
+ *
+ * LOCKING:
+ * Caller must hold turbo_status_lock (outside of init)
+ */
+static void update_turbo_limits(struct ips_driver *ips)
+{
+ u32 hts = thm_readl(THM_HTS);
+
+ ips->cpu_turbo_enabled = !(hts & HTS_PCTD_DIS);
+ ips->gpu_turbo_enabled = !(hts & HTS_GTD_DIS);
+ ips->core_power_limit = thm_readw(THM_MPCPC);
+ ips->mch_power_limit = thm_readw(THM_MMGPC);
+ ips->mcp_temp_limit = thm_readw(THM_PTL);
+ ips->mcp_power_limit = thm_readw(THM_MPPC);
+
+ /* Ignore BIOS CPU vs GPU pref */
+}
+
+/**
+ * ips_adjust - adjust power clamp based on thermal state
+ * @data: ips driver structure
+ *
+ * Wake up every 5s or so and check whether we should adjust the power clamp.
+ * Check CPU and GPU load to determine which needs adjustment. There are
+ * several things to consider here:
+ * - do we need to adjust up or down?
+ * - is CPU busy?
+ * - is GPU busy?
+ * - is CPU in turbo?
+ * - is GPU in turbo?
+ * - is CPU or GPU preferred? (CPU is default)
+ *
+ * So, given the above, we do the following:
+ * - up (TDP available)
+ * - CPU not busy, GPU not busy - nothing
+ * - CPU busy, GPU not busy - adjust CPU up
+ * - CPU not busy, GPU busy - adjust GPU up
+ * - CPU busy, GPU busy - adjust preferred unit up, taking headroom from
+ * non-preferred unit if necessary
+ * - down (at TDP limit)
+ * - adjust both CPU and GPU down if possible
+ *
+ cpu+ gpu+ cpu+gpu- cpu-gpu+ cpu-gpu-
+cpu < gpu < cpu+gpu+ cpu+ gpu+ nothing
+cpu < gpu >= cpu+gpu-(mcp<) cpu+gpu-(mcp<) gpu- gpu-
+cpu >= gpu < cpu-gpu+(mcp<) cpu- cpu-gpu+(mcp<) cpu-
+cpu >= gpu >= cpu-gpu- cpu-gpu- cpu-gpu- cpu-gpu-
+ *
+ */
+static int ips_adjust(void *data)
+{
+ struct ips_driver *ips = data;
+ unsigned long flags;
+
+ dev_dbg(&ips->dev->dev, "starting ips-adjust thread\n");
+
+ /*
+ * Adjust CPU and GPU clamps every 5s if needed. Doing it more
+ * often isn't recommended due to ME interaction.
+ */
+ do {
+ bool cpu_busy = ips_cpu_busy(ips);
+ bool gpu_busy = ips_gpu_busy(ips);
+
+ spin_lock_irqsave(&ips->turbo_status_lock, flags);
+ if (ips->poll_turbo_status)
+ update_turbo_limits(ips);
+ spin_unlock_irqrestore(&ips->turbo_status_lock, flags);
+
+ /* Update turbo status if necessary */
+ if (ips->cpu_turbo_enabled)
+ ips_enable_cpu_turbo(ips);
+ else
+ ips_disable_cpu_turbo(ips);
+
+ if (ips->gpu_turbo_enabled)
+ ips_enable_gpu_turbo(ips);
+ else
+ ips_disable_gpu_turbo(ips);
+
+ /* We're outside our comfort zone, crank them down */
+ if (mcp_exceeded(ips)) {
+ ips_cpu_lower(ips);
+ ips_gpu_lower(ips);
+ goto sleep;
+ }
+
+ if (!cpu_exceeded(ips, 0) && cpu_busy)
+ ips_cpu_raise(ips);
+ else
+ ips_cpu_lower(ips);
+
+ if (!mch_exceeded(ips) && gpu_busy)
+ ips_gpu_raise(ips);
+ else
+ ips_gpu_lower(ips);
+
+sleep:
+ schedule_timeout_interruptible(msecs_to_jiffies(IPS_ADJUST_PERIOD));
+ } while (!kthread_should_stop());
+
+ dev_dbg(&ips->dev->dev, "ips-adjust thread stopped\n");
+
+ return 0;
+}
+
+/*
+ * Helpers for reading out temp/power values and calculating their
+ * averages for the decision making and monitoring functions.
+ */
+
+static u16 calc_avg_temp(struct ips_driver *ips, u16 *array)
+{
+ u64 total = 0;
+ int i;
+ u16 avg;
+
+ for (i = 0; i < IPS_SAMPLE_COUNT; i++)
+ total += (u64)(array[i] * 100);
+
+ do_div(total, IPS_SAMPLE_COUNT);
+
+ avg = (u16)total;
+
+ return avg;
+}
+
+static u16 read_mgtv(struct ips_driver *ips)
+{
+ u16 ret;
+ u64 slope, offset;
+ u64 val;
+
+ val = thm_readq(THM_MGTV);
+ val = (val & TV_MASK) >> TV_SHIFT;
+
+ slope = offset = thm_readw(THM_MGTA);
+ slope = (slope & MGTA_SLOPE_MASK) >> MGTA_SLOPE_SHIFT;
+ offset = offset & MGTA_OFFSET_MASK;
+
+ ret = ((val * slope + 0x40) >> 7) + offset;
+
+ return 0; /* MCH temp reporting buggy */
+}
+
+static u16 read_ptv(struct ips_driver *ips)
+{
+ u16 val, slope, offset;
+
+ slope = (ips->pta_val & PTA_SLOPE_MASK) >> PTA_SLOPE_SHIFT;
+ offset = ips->pta_val & PTA_OFFSET_MASK;
+
+ val = thm_readw(THM_PTV) & PTV_MASK;
+
+ return val;
+}
+
+static u16 read_ctv(struct ips_driver *ips, int cpu)
+{
+ int reg = cpu ? THM_CTV2 : THM_CTV1;
+ u16 val;
+
+ val = thm_readw(reg);
+ if (!(val & CTV_TEMP_ERROR))
+ val = (val) >> 6; /* discard fractional component */
+ else
+ val = 0;
+
+ return val;
+}
+
+static u32 get_cpu_power(struct ips_driver *ips, u32 *last, int period)
+{
+ u32 val;
+ u32 ret;
+
+ /*
+ * CEC is in joules/65535. Take difference over time to
+ * get watts.
+ */
+ val = thm_readl(THM_CEC);
+
+ /* period is in ms and we want mW */
+ ret = (((val - *last) * 1000) / period);
+ ret = (ret * 1000) / 65535;
+ *last = val;
+
+ return ret;
+}
+
+static const u16 temp_decay_factor = 2;
+static u16 update_average_temp(u16 avg, u16 val)
+{
+ u16 ret;
+
+ /* Multiply by 100 for extra precision */
+ ret = (val * 100 / temp_decay_factor) +
+ (((temp_decay_factor - 1) * avg) / temp_decay_factor);
+ return ret;
+}
+
+static const u16 power_decay_factor = 2;
+static u16 update_average_power(u32 avg, u32 val)
+{
+ u32 ret;
+
+ ret = (val / power_decay_factor) +
+ (((power_decay_factor - 1) * avg) / power_decay_factor);
+
+ return ret;
+}
+
+static u32 calc_avg_power(struct ips_driver *ips, u32 *array)
+{
+ u64 total = 0;
+ u32 avg;
+ int i;
+
+ for (i = 0; i < IPS_SAMPLE_COUNT; i++)
+ total += array[i];
+
+ do_div(total, IPS_SAMPLE_COUNT);
+ avg = (u32)total;
+
+ return avg;
+}
+
+static void monitor_timeout(unsigned long arg)
+{
+ wake_up_process((struct task_struct *)arg);
+}
+
+/**
+ * ips_monitor - temp/power monitoring thread
+ * @data: ips driver structure
+ *
+ * This is the main function for the IPS driver. It monitors power and
+ * tempurature in the MCP and adjusts CPU and GPU power clams accordingly.
+ *
+ * We keep a 5s moving average of power consumption and tempurature. Using
+ * that data, along with CPU vs GPU preference, we adjust the power clamps
+ * up or down.
+ */
+static int ips_monitor(void *data)
+{
+ struct ips_driver *ips = data;
+ struct timer_list timer;
+ unsigned long seqno_timestamp, expire, last_msecs, last_sample_period;
+ int i;
+ u32 *cpu_samples, *mchp_samples, old_cpu_power;
+ u16 *mcp_samples, *ctv1_samples, *ctv2_samples, *mch_samples;
+ u8 cur_seqno, last_seqno;
+
+ mcp_samples = kzalloc(sizeof(u16) * IPS_SAMPLE_COUNT, GFP_KERNEL);
+ ctv1_samples = kzalloc(sizeof(u16) * IPS_SAMPLE_COUNT, GFP_KERNEL);
+ ctv2_samples = kzalloc(sizeof(u16) * IPS_SAMPLE_COUNT, GFP_KERNEL);
+ mch_samples = kzalloc(sizeof(u16) * IPS_SAMPLE_COUNT, GFP_KERNEL);
+ cpu_samples = kzalloc(sizeof(u32) * IPS_SAMPLE_COUNT, GFP_KERNEL);
+ mchp_samples = kzalloc(sizeof(u32) * IPS_SAMPLE_COUNT, GFP_KERNEL);
+ if (!mcp_samples || !ctv1_samples || !ctv2_samples || !mch_samples ||
+ !cpu_samples || !mchp_samples) {
+ dev_err(&ips->dev->dev,
+ "failed to allocate sample array, ips disabled\n");
+ kfree(mcp_samples);
+ kfree(ctv1_samples);
+ kfree(ctv2_samples);
+ kfree(mch_samples);
+ kfree(cpu_samples);
+ kfree(mchp_samples);
+ kthread_stop(ips->adjust);
+ return -ENOMEM;
+ }
+
+ last_seqno = (thm_readl(THM_ITV) & ITV_ME_SEQNO_MASK) >>
+ ITV_ME_SEQNO_SHIFT;
+ seqno_timestamp = get_jiffies_64();
+
+ old_cpu_power = thm_readl(THM_CEC) / 65535;
+ schedule_timeout_interruptible(msecs_to_jiffies(IPS_SAMPLE_PERIOD));
+
+ /* Collect an initial average */
+ for (i = 0; i < IPS_SAMPLE_COUNT; i++) {
+ u32 mchp, cpu_power;
+ u16 val;
+
+ mcp_samples[i] = read_ptv(ips);
+
+ val = read_ctv(ips, 0);
+ ctv1_samples[i] = val;
+
+ val = read_ctv(ips, 1);
+ ctv2_samples[i] = val;
+
+ val = read_mgtv(ips);
+ mch_samples[i] = val;
+
+ cpu_power = get_cpu_power(ips, &old_cpu_power,
+ IPS_SAMPLE_PERIOD);
+ cpu_samples[i] = cpu_power;
+
+ if (ips->read_mch_val) {
+ mchp = ips->read_mch_val();
+ mchp_samples[i] = mchp;
+ }
+
+ schedule_timeout_interruptible(msecs_to_jiffies(IPS_SAMPLE_PERIOD));
+ if (kthread_should_stop())
+ break;
+ }
+
+ ips->mcp_avg_temp = calc_avg_temp(ips, mcp_samples);
+ ips->ctv1_avg_temp = calc_avg_temp(ips, ctv1_samples);
+ ips->ctv2_avg_temp = calc_avg_temp(ips, ctv2_samples);
+ ips->mch_avg_temp = calc_avg_temp(ips, mch_samples);
+ ips->cpu_avg_power = calc_avg_power(ips, cpu_samples);
+ ips->mch_avg_power = calc_avg_power(ips, mchp_samples);
+ kfree(mcp_samples);
+ kfree(ctv1_samples);
+ kfree(ctv2_samples);
+ kfree(mch_samples);
+ kfree(cpu_samples);
+ kfree(mchp_samples);
+
+ /* Start the adjustment thread now that we have data */
+ wake_up_process(ips->adjust);
+
+ /*
+ * Ok, now we have an initial avg. From here on out, we track the
+ * running avg using a decaying average calculation. This allows
+ * us to reduce the sample frequency if the CPU and GPU are idle.
+ */
+ old_cpu_power = thm_readl(THM_CEC);
+ schedule_timeout_interruptible(msecs_to_jiffies(IPS_SAMPLE_PERIOD));
+ last_sample_period = IPS_SAMPLE_PERIOD;
+
+ setup_deferrable_timer_on_stack(&timer, monitor_timeout,
+ (unsigned long)current);
+ do {
+ u32 cpu_val, mch_val;
+ u16 val;
+
+ /* MCP itself */
+ val = read_ptv(ips);
+ ips->mcp_avg_temp = update_average_temp(ips->mcp_avg_temp, val);
+
+ /* Processor 0 */
+ val = read_ctv(ips, 0);
+ ips->ctv1_avg_temp =
+ update_average_temp(ips->ctv1_avg_temp, val);
+ /* Power */
+ cpu_val = get_cpu_power(ips, &old_cpu_power,
+ last_sample_period);
+ ips->cpu_avg_power =
+ update_average_power(ips->cpu_avg_power, cpu_val);
+
+ if (ips->second_cpu) {
+ /* Processor 1 */
+ val = read_ctv(ips, 1);
+ ips->ctv2_avg_temp =
+ update_average_temp(ips->ctv2_avg_temp, val);
+ }
+
+ /* MCH */
+ val = read_mgtv(ips);
+ ips->mch_avg_temp = update_average_temp(ips->mch_avg_temp, val);
+ /* Power */
+ if (ips->read_mch_val) {
+ mch_val = ips->read_mch_val();
+ ips->mch_avg_power =
+ update_average_power(ips->mch_avg_power,
+ mch_val);
+ }
+
+ /*
+ * Make sure ME is updating thermal regs.
+ * Note:
+ * If it's been more than a second since the last update,
+ * the ME is probably hung.
+ */
+ cur_seqno = (thm_readl(THM_ITV) & ITV_ME_SEQNO_MASK) >>
+ ITV_ME_SEQNO_SHIFT;
+ if (cur_seqno == last_seqno &&
+ time_after(jiffies, seqno_timestamp + HZ)) {
+ dev_warn(&ips->dev->dev, "ME failed to update for more than 1s, likely hung\n");
+ } else {
+ seqno_timestamp = get_jiffies_64();
+ last_seqno = cur_seqno;
+ }
+
+ last_msecs = jiffies_to_msecs(jiffies);
+ expire = jiffies + msecs_to_jiffies(IPS_SAMPLE_PERIOD);
+
+ __set_current_state(TASK_UNINTERRUPTIBLE);
+ mod_timer(&timer, expire);
+ schedule();
+
+ /* Calculate actual sample period for power averaging */
+ last_sample_period = jiffies_to_msecs(jiffies) - last_msecs;
+ if (!last_sample_period)
+ last_sample_period = 1;
+ } while (!kthread_should_stop());
+
+ del_timer_sync(&timer);
+ destroy_timer_on_stack(&timer);
+
+ dev_dbg(&ips->dev->dev, "ips-monitor thread stopped\n");
+
+ return 0;
+}
+
+#if 0
+#define THM_DUMPW(reg) \
+ { \
+ u16 val = thm_readw(reg); \
+ dev_dbg(&ips->dev->dev, #reg ": 0x%04x\n", val); \
+ }
+#define THM_DUMPL(reg) \
+ { \
+ u32 val = thm_readl(reg); \
+ dev_dbg(&ips->dev->dev, #reg ": 0x%08x\n", val); \
+ }
+#define THM_DUMPQ(reg) \
+ { \
+ u64 val = thm_readq(reg); \
+ dev_dbg(&ips->dev->dev, #reg ": 0x%016x\n", val); \
+ }
+
+static void dump_thermal_info(struct ips_driver *ips)
+{
+ u16 ptl;
+
+ ptl = thm_readw(THM_PTL);
+ dev_dbg(&ips->dev->dev, "Processor temp limit: %d\n", ptl);
+
+ THM_DUMPW(THM_CTA);
+ THM_DUMPW(THM_TRC);
+ THM_DUMPW(THM_CTV1);
+ THM_DUMPL(THM_STS);
+ THM_DUMPW(THM_PTV);
+ THM_DUMPQ(THM_MGTV);
+}
+#endif
+
+/**
+ * ips_irq_handler - handle temperature triggers and other IPS events
+ * @irq: irq number
+ * @arg: unused
+ *
+ * Handle temperature limit trigger events, generally by lowering the clamps.
+ * If we're at a critical limit, we clamp back to the lowest possible value
+ * to prevent emergency shutdown.
+ */
+static irqreturn_t ips_irq_handler(int irq, void *arg)
+{
+ struct ips_driver *ips = arg;
+ u8 tses = thm_readb(THM_TSES);
+ u8 tes = thm_readb(THM_TES);
+
+ if (!tses && !tes)
+ return IRQ_NONE;
+
+ dev_info(&ips->dev->dev, "TSES: 0x%02x\n", tses);
+ dev_info(&ips->dev->dev, "TES: 0x%02x\n", tes);
+
+ /* STS update from EC? */
+ if (tes & 1) {
+ u32 sts, tc1;
+
+ sts = thm_readl(THM_STS);
+ tc1 = thm_readl(THM_TC1);
+
+ if (sts & STS_NVV) {
+ spin_lock(&ips->turbo_status_lock);
+ ips->core_power_limit = (sts & STS_PCPL_MASK) >>
+ STS_PCPL_SHIFT;
+ ips->mch_power_limit = (sts & STS_GPL_MASK) >>
+ STS_GPL_SHIFT;
+ /* ignore EC CPU vs GPU pref */
+ ips->cpu_turbo_enabled = !(sts & STS_PCTD_DIS);
+ ips->gpu_turbo_enabled = !(sts & STS_GTD_DIS);
+ ips->mcp_temp_limit = (sts & STS_PTL_MASK) >>
+ STS_PTL_SHIFT;
+ ips->mcp_power_limit = (tc1 & STS_PPL_MASK) >>
+ STS_PPL_SHIFT;
+ spin_unlock(&ips->turbo_status_lock);
+
+ thm_writeb(THM_SEC, SEC_ACK);
+ }
+ thm_writeb(THM_TES, tes);
+ }
+
+ /* Thermal trip */
+ if (tses) {
+ dev_warn(&ips->dev->dev,
+ "thermal trip occurred, tses: 0x%04x\n", tses);
+ thm_writeb(THM_TSES, tses);
+ }
+
+ return IRQ_HANDLED;
+}
+
+#ifndef CONFIG_DEBUG_FS
+static void ips_debugfs_init(struct ips_driver *ips) { return; }
+static void ips_debugfs_cleanup(struct ips_driver *ips) { return; }
+#else
+
+/* Expose current state and limits in debugfs if possible */
+
+struct ips_debugfs_node {
+ struct ips_driver *ips;
+ char *name;
+ int (*show)(struct seq_file *m, void *data);
+};
+
+static int show_cpu_temp(struct seq_file *m, void *data)
+{
+ struct ips_driver *ips = m->private;
+
+ seq_printf(m, "%d.%02d\n", ips->ctv1_avg_temp / 100,
+ ips->ctv1_avg_temp % 100);
+
+ return 0;
+}
+
+static int show_cpu_power(struct seq_file *m, void *data)
+{
+ struct ips_driver *ips = m->private;
+
+ seq_printf(m, "%dmW\n", ips->cpu_avg_power);
+
+ return 0;
+}
+
+static int show_cpu_clamp(struct seq_file *m, void *data)
+{
+ u64 turbo_override;
+ int tdp, tdc;
+
+ rdmsrl(TURBO_POWER_CURRENT_LIMIT, turbo_override);
+
+ tdp = (int)(turbo_override & TURBO_TDP_MASK);
+ tdc = (int)((turbo_override & TURBO_TDC_MASK) >> TURBO_TDC_SHIFT);
+
+ /* Convert to .1W/A units */
+ tdp = tdp * 10 / 8;
+ tdc = tdc * 10 / 8;
+
+ /* Watts Amperes */
+ seq_printf(m, "%d.%dW %d.%dA\n", tdp / 10, tdp % 10,
+ tdc / 10, tdc % 10);
+
+ return 0;
+}
+
+static int show_mch_temp(struct seq_file *m, void *data)
+{
+ struct ips_driver *ips = m->private;
+
+ seq_printf(m, "%d.%02d\n", ips->mch_avg_temp / 100,
+ ips->mch_avg_temp % 100);
+
+ return 0;
+}
+
+static int show_mch_power(struct seq_file *m, void *data)
+{
+ struct ips_driver *ips = m->private;
+
+ seq_printf(m, "%dmW\n", ips->mch_avg_power);
+
+ return 0;
+}
+
+static struct ips_debugfs_node ips_debug_files[] = {
+ { NULL, "cpu_temp", show_cpu_temp },
+ { NULL, "cpu_power", show_cpu_power },
+ { NULL, "cpu_clamp", show_cpu_clamp },
+ { NULL, "mch_temp", show_mch_temp },
+ { NULL, "mch_power", show_mch_power },
+};
+
+static int ips_debugfs_open(struct inode *inode, struct file *file)
+{
+ struct ips_debugfs_node *node = inode->i_private;
+
+ return single_open(file, node->show, node->ips);
+}
+
+static const struct file_operations ips_debugfs_ops = {
+ .owner = THIS_MODULE,
+ .open = ips_debugfs_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static void ips_debugfs_cleanup(struct ips_driver *ips)
+{
+ if (ips->debug_root)
+ debugfs_remove_recursive(ips->debug_root);
+ return;
+}
+
+static void ips_debugfs_init(struct ips_driver *ips)
+{
+ int i;
+
+ ips->debug_root = debugfs_create_dir("ips", NULL);
+ if (!ips->debug_root) {
+ dev_err(&ips->dev->dev,
+ "failed to create debugfs entries: %ld\n",
+ PTR_ERR(ips->debug_root));
+ return;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(ips_debug_files); i++) {
+ struct dentry *ent;
+ struct ips_debugfs_node *node = &ips_debug_files[i];
+
+ node->ips = ips;
+ ent = debugfs_create_file(node->name, S_IFREG | S_IRUGO,
+ ips->debug_root, node,
+ &ips_debugfs_ops);
+ if (!ent) {
+ dev_err(&ips->dev->dev,
+ "failed to create debug file: %ld\n",
+ PTR_ERR(ent));
+ goto err_cleanup;
+ }
+ }
+
+ return;
+
+err_cleanup:
+ ips_debugfs_cleanup(ips);
+ return;
+}
+#endif /* CONFIG_DEBUG_FS */
+
+/**
+ * ips_detect_cpu - detect whether CPU supports IPS
+ *
+ * Walk our list and see if we're on a supported CPU. If we find one,
+ * return the limits for it.
+ */
+static struct ips_mcp_limits *ips_detect_cpu(struct ips_driver *ips)
+{
+ u64 turbo_power, misc_en;
+ struct ips_mcp_limits *limits = NULL;
+ u16 tdp;
+
+ if (!(boot_cpu_data.x86 == 6 && boot_cpu_data.x86_model == 37)) {
+ dev_info(&ips->dev->dev, "Non-IPS CPU detected.\n");
+ goto out;
+ }
+
+ rdmsrl(IA32_MISC_ENABLE, misc_en);
+ /*
+ * If the turbo enable bit isn't set, we shouldn't try to enable/disable
+ * turbo manually or we'll get an illegal MSR access, even though
+ * turbo will still be available.
+ */
+ if (!(misc_en & IA32_MISC_TURBO_EN))
+ ; /* add turbo MSR write allowed flag if necessary */
+
+ if (strstr(boot_cpu_data.x86_model_id, "CPU M"))
+ limits = &ips_sv_limits;
+ else if (strstr(boot_cpu_data.x86_model_id, "CPU L"))
+ limits = &ips_lv_limits;
+ else if (strstr(boot_cpu_data.x86_model_id, "CPU U"))
+ limits = &ips_ulv_limits;
+ else
+ dev_info(&ips->dev->dev, "No CPUID match found.\n");
+
+ rdmsrl(TURBO_POWER_CURRENT_LIMIT, turbo_power);
+ tdp = turbo_power & TURBO_TDP_MASK;
+
+ /* Sanity check TDP against CPU */
+ if (limits->mcp_power_limit != (tdp / 8) * 1000) {
+ dev_warn(&ips->dev->dev, "Warning: CPU TDP doesn't match expected value (found %d, expected %d)\n",
+ tdp / 8, limits->mcp_power_limit / 1000);
+ }
+
+out:
+ return limits;
+}
+
+/**
+ * ips_get_i915_syms - try to get GPU control methods from i915 driver
+ * @ips: IPS driver
+ *
+ * The i915 driver exports several interfaces to allow the IPS driver to
+ * monitor and control graphics turbo mode. If we can find them, we can
+ * enable graphics turbo, otherwise we must disable it to avoid exceeding
+ * thermal and power limits in the MCP.
+ */
+static bool ips_get_i915_syms(struct ips_driver *ips)
+{
+ ips->read_mch_val = symbol_get(i915_read_mch_val);
+ if (!ips->read_mch_val)
+ goto out_err;
+ ips->gpu_raise = symbol_get(i915_gpu_raise);
+ if (!ips->gpu_raise)
+ goto out_put_mch;
+ ips->gpu_lower = symbol_get(i915_gpu_lower);
+ if (!ips->gpu_lower)
+ goto out_put_raise;
+ ips->gpu_busy = symbol_get(i915_gpu_busy);
+ if (!ips->gpu_busy)
+ goto out_put_lower;
+ ips->gpu_turbo_disable = symbol_get(i915_gpu_turbo_disable);
+ if (!ips->gpu_turbo_disable)
+ goto out_put_busy;
+
+ return true;
+
+out_put_busy:
+ symbol_put(i915_gpu_turbo_disable);
+out_put_lower:
+ symbol_put(i915_gpu_lower);
+out_put_raise:
+ symbol_put(i915_gpu_raise);
+out_put_mch:
+ symbol_put(i915_read_mch_val);
+out_err:
+ return false;
+}
+
+static DEFINE_PCI_DEVICE_TABLE(ips_id_table) = {
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL,
+ PCI_DEVICE_ID_INTEL_THERMAL_SENSOR), },
+ { 0, }
+};
+
+MODULE_DEVICE_TABLE(pci, ips_id_table);
+
+static int ips_probe(struct pci_dev *dev, const struct pci_device_id *id)
+{
+ u64 platform_info;
+ struct ips_driver *ips;
+ u32 hts;
+ int ret = 0;
+ u16 htshi, trc, trc_required_mask;
+ u8 tse;
+
+ ips = kzalloc(sizeof(struct ips_driver), GFP_KERNEL);
+ if (!ips)
+ return -ENOMEM;
+
+ pci_set_drvdata(dev, ips);
+ ips->dev = dev;
+
+ ips->limits = ips_detect_cpu(ips);
+ if (!ips->limits) {
+ dev_info(&dev->dev, "IPS not supported on this CPU\n");
+ ret = -ENXIO;
+ goto error_free;
+ }
+
+ spin_lock_init(&ips->turbo_status_lock);
+
+ if (!pci_resource_start(dev, 0)) {
+ dev_err(&dev->dev, "TBAR not assigned, aborting\n");
+ ret = -ENXIO;
+ goto error_free;
+ }
+
+ ret = pci_request_regions(dev, "ips thermal sensor");
+ if (ret) {
+ dev_err(&dev->dev, "thermal resource busy, aborting\n");
+ goto error_free;
+ }
+
+ ret = pci_enable_device(dev);
+ if (ret) {
+ dev_err(&dev->dev, "can't enable PCI device, aborting\n");
+ goto error_free;
+ }
+
+ ips->regmap = ioremap(pci_resource_start(dev, 0),
+ pci_resource_len(dev, 0));
+ if (!ips->regmap) {
+ dev_err(&dev->dev, "failed to map thermal regs, aborting\n");
+ ret = -EBUSY;
+ goto error_release;
+ }
+
+ tse = thm_readb(THM_TSE);
+ if (tse != TSE_EN) {
+ dev_err(&dev->dev, "thermal device not enabled (0x%02x), aborting\n", tse);
+ ret = -ENXIO;
+ goto error_unmap;
+ }
+
+ trc = thm_readw(THM_TRC);
+ trc_required_mask = TRC_CORE1_EN | TRC_CORE_PWR | TRC_MCH_EN;
+ if ((trc & trc_required_mask) != trc_required_mask) {
+ dev_err(&dev->dev, "thermal reporting for required devices not enabled, aborting\n");
+ ret = -ENXIO;
+ goto error_unmap;
+ }
+
+ if (trc & TRC_CORE2_EN)
+ ips->second_cpu = true;
+
+ update_turbo_limits(ips);
+ dev_dbg(&dev->dev, "max cpu power clamp: %dW\n",
+ ips->mcp_power_limit / 10);
+ dev_dbg(&dev->dev, "max core power clamp: %dW\n",
+ ips->core_power_limit / 10);
+ /* BIOS may update limits at runtime */
+ if (thm_readl(THM_PSC) & PSP_PBRT)
+ ips->poll_turbo_status = true;
+
+ if (!ips_get_i915_syms(ips)) {
+ dev_err(&dev->dev, "failed to get i915 symbols, graphics turbo disabled\n");
+ ips->gpu_turbo_enabled = false;
+ } else {
+ dev_dbg(&dev->dev, "graphics turbo enabled\n");
+ ips->gpu_turbo_enabled = true;
+ }
+
+ /*
+ * Check PLATFORM_INFO MSR to make sure this chip is
+ * turbo capable.
+ */
+ rdmsrl(PLATFORM_INFO, platform_info);
+ if (!(platform_info & PLATFORM_TDP)) {
+ dev_err(&dev->dev, "platform indicates TDP override unavailable, aborting\n");
+ ret = -ENODEV;
+ goto error_unmap;
+ }
+
+ /*
+ * IRQ handler for ME interaction
+ * Note: don't use MSI here as the PCH has bugs.
+ */
+ pci_disable_msi(dev);
+ ret = request_irq(dev->irq, ips_irq_handler, IRQF_SHARED, "ips",
+ ips);
+ if (ret) {
+ dev_err(&dev->dev, "request irq failed, aborting\n");
+ goto error_unmap;
+ }
+
+ /* Enable aux, hot & critical interrupts */
+ thm_writeb(THM_TSPIEN, TSPIEN_AUX2_LOHI | TSPIEN_CRIT_LOHI |
+ TSPIEN_HOT_LOHI | TSPIEN_AUX_LOHI);
+ thm_writeb(THM_TEN, TEN_UPDATE_EN);
+
+ /* Collect adjustment values */
+ ips->cta_val = thm_readw(THM_CTA);
+ ips->pta_val = thm_readw(THM_PTA);
+ ips->mgta_val = thm_readw(THM_MGTA);
+
+ /* Save turbo limits & ratios */
+ rdmsrl(TURBO_POWER_CURRENT_LIMIT, ips->orig_turbo_limit);
+
+ ips_enable_cpu_turbo(ips);
+ ips->cpu_turbo_enabled = true;
+
+ /* Set up the work queue and monitor/adjust threads */
+ ips->monitor = kthread_run(ips_monitor, ips, "ips-monitor");
+ if (IS_ERR(ips->monitor)) {
+ dev_err(&dev->dev,
+ "failed to create thermal monitor thread, aborting\n");
+ ret = -ENOMEM;
+ goto error_free_irq;
+ }
+
+ ips->adjust = kthread_create(ips_adjust, ips, "ips-adjust");
+ if (IS_ERR(ips->adjust)) {
+ dev_err(&dev->dev,
+ "failed to create thermal adjust thread, aborting\n");
+ ret = -ENOMEM;
+ goto error_thread_cleanup;
+ }
+
+ hts = (ips->core_power_limit << HTS_PCPL_SHIFT) |
+ (ips->mcp_temp_limit << HTS_PTL_SHIFT) | HTS_NVV;
+ htshi = HTS2_PRST_RUNNING << HTS2_PRST_SHIFT;
+
+ thm_writew(THM_HTSHI, htshi);
+ thm_writel(THM_HTS, hts);
+
+ ips_debugfs_init(ips);
+
+ dev_info(&dev->dev, "IPS driver initialized, MCP temp limit %d\n",
+ ips->mcp_temp_limit);
+ return ret;
+
+error_thread_cleanup:
+ kthread_stop(ips->monitor);
+error_free_irq:
+ free_irq(ips->dev->irq, ips);
+error_unmap:
+ iounmap(ips->regmap);
+error_release:
+ pci_release_regions(dev);
+error_free:
+ kfree(ips);
+ return ret;
+}
+
+static void ips_remove(struct pci_dev *dev)
+{
+ struct ips_driver *ips = pci_get_drvdata(dev);
+ u64 turbo_override;
+
+ if (!ips)
+ return;
+
+ ips_debugfs_cleanup(ips);
+
+ /* Release i915 driver */
+ if (ips->read_mch_val)
+ symbol_put(i915_read_mch_val);
+ if (ips->gpu_raise)
+ symbol_put(i915_gpu_raise);
+ if (ips->gpu_lower)
+ symbol_put(i915_gpu_lower);
+ if (ips->gpu_busy)
+ symbol_put(i915_gpu_busy);
+ if (ips->gpu_turbo_disable)
+ symbol_put(i915_gpu_turbo_disable);
+
+ rdmsrl(TURBO_POWER_CURRENT_LIMIT, turbo_override);
+ turbo_override &= ~(TURBO_TDC_OVR_EN | TURBO_TDP_OVR_EN);
+ wrmsrl(TURBO_POWER_CURRENT_LIMIT, turbo_override);
+ wrmsrl(TURBO_POWER_CURRENT_LIMIT, ips->orig_turbo_limit);
+
+ free_irq(ips->dev->irq, ips);
+ if (ips->adjust)
+ kthread_stop(ips->adjust);
+ if (ips->monitor)
+ kthread_stop(ips->monitor);
+ iounmap(ips->regmap);
+ pci_release_regions(dev);
+ kfree(ips);
+ dev_dbg(&dev->dev, "IPS driver removed\n");
+}
+
+#ifdef CONFIG_PM
+static int ips_suspend(struct pci_dev *dev, pm_message_t state)
+{
+ return 0;
+}
+
+static int ips_resume(struct pci_dev *dev)
+{
+ return 0;
+}
+#else
+#define ips_suspend NULL
+#define ips_resume NULL
+#endif /* CONFIG_PM */
+
+static void ips_shutdown(struct pci_dev *dev)
+{
+}
+
+static struct pci_driver ips_pci_driver = {
+ .name = "intel ips",
+ .id_table = ips_id_table,
+ .probe = ips_probe,
+ .remove = ips_remove,
+ .suspend = ips_suspend,
+ .resume = ips_resume,
+ .shutdown = ips_shutdown,
+};
+
+static int __init ips_init(void)
+{
+ return pci_register_driver(&ips_pci_driver);
+}
+module_init(ips_init);
+
+static void ips_exit(void)
+{
+ pci_unregister_driver(&ips_pci_driver);
+ return;
+}
+module_exit(ips_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Jesse Barnes <jbarnes@virtuousgeek.org>");
+MODULE_DESCRIPTION("Intelligent Power Sharing Driver");
diff --git a/drivers/platform/x86/intel_menlow.c b/drivers/platform/x86/intel_menlow.c
index 2f795ce2b93..eacd5da7dd2 100644
--- a/drivers/platform/x86/intel_menlow.c
+++ b/drivers/platform/x86/intel_menlow.c
@@ -53,6 +53,8 @@ MODULE_LICENSE("GPL");
#define MEMORY_ARG_CUR_BANDWIDTH 1
#define MEMORY_ARG_MAX_BANDWIDTH 0
+static void intel_menlow_unregister_sensor(void);
+
/*
* GTHS returning 'n' would mean that [0,n-1] states are supported
* In that case max_cstate would be n-1
@@ -406,8 +408,10 @@ static int intel_menlow_add_one_attribute(char *name, int mode, void *show,
attr->handle = handle;
result = device_create_file(dev, &attr->attr);
- if (result)
+ if (result) {
+ kfree(attr);
return result;
+ }
mutex_lock(&intel_menlow_attr_lock);
list_add_tail(&attr->node, &intel_menlow_attr_list);
@@ -431,11 +435,11 @@ static acpi_status intel_menlow_register_sensor(acpi_handle handle, u32 lvl,
/* _TZ must have the AUX0/1 methods */
status = acpi_get_handle(handle, GET_AUX0, &dummy);
if (ACPI_FAILURE(status))
- goto not_found;
+ return (status == AE_NOT_FOUND) ? AE_OK : status;
status = acpi_get_handle(handle, SET_AUX0, &dummy);
if (ACPI_FAILURE(status))
- goto not_found;
+ return (status == AE_NOT_FOUND) ? AE_OK : status;
result = intel_menlow_add_one_attribute("aux0", 0644,
aux0_show, aux0_store,
@@ -445,17 +449,19 @@ static acpi_status intel_menlow_register_sensor(acpi_handle handle, u32 lvl,
status = acpi_get_handle(handle, GET_AUX1, &dummy);
if (ACPI_FAILURE(status))
- goto not_found;
+ goto aux1_not_found;
status = acpi_get_handle(handle, SET_AUX1, &dummy);
if (ACPI_FAILURE(status))
- goto not_found;
+ goto aux1_not_found;
result = intel_menlow_add_one_attribute("aux1", 0644,
aux1_show, aux1_store,
&thermal->device, handle);
- if (result)
+ if (result) {
+ intel_menlow_unregister_sensor();
return AE_ERROR;
+ }
/*
* create the "dabney_enabled" attribute which means the user app
@@ -465,14 +471,17 @@ static acpi_status intel_menlow_register_sensor(acpi_handle handle, u32 lvl,
result = intel_menlow_add_one_attribute("bios_enabled", 0444,
bios_enabled_show, NULL,
&thermal->device, handle);
- if (result)
+ if (result) {
+ intel_menlow_unregister_sensor();
return AE_ERROR;
+ }
- not_found:
+ aux1_not_found:
if (status == AE_NOT_FOUND)
return AE_OK;
- else
- return status;
+
+ intel_menlow_unregister_sensor();
+ return status;
}
static void intel_menlow_unregister_sensor(void)
@@ -513,8 +522,10 @@ static int __init intel_menlow_module_init(void)
status = acpi_walk_namespace(ACPI_TYPE_THERMAL, ACPI_ROOT_OBJECT,
ACPI_UINT32_MAX,
intel_menlow_register_sensor, NULL, NULL, NULL);
- if (ACPI_FAILURE(status))
+ if (ACPI_FAILURE(status)) {
+ acpi_bus_unregister_driver(&intel_menlow_memory_driver);
return -ENODEV;
+ }
return 0;
}
diff --git a/drivers/platform/x86/intel_pmic_gpio.c b/drivers/platform/x86/intel_pmic_gpio.c
new file mode 100644
index 00000000000..5cdcff65391
--- /dev/null
+++ b/drivers/platform/x86/intel_pmic_gpio.c
@@ -0,0 +1,340 @@
+/* Moorestown PMIC GPIO (access through IPC) driver
+ * Copyright (c) 2008 - 2009, Intel 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.
+ *
+ * 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.
+ */
+
+/* Supports:
+ * Moorestown platform PMIC chip
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/stddef.h>
+#include <linux/slab.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/gpio.h>
+#include <linux/interrupt.h>
+#include <asm/intel_scu_ipc.h>
+#include <linux/device.h>
+#include <linux/intel_pmic_gpio.h>
+#include <linux/platform_device.h>
+
+#define DRIVER_NAME "pmic_gpio"
+
+/* register offset that IPC driver should use
+ * 8 GPIO + 8 GPOSW (6 controllable) + 8GPO
+ */
+enum pmic_gpio_register {
+ GPIO0 = 0xE0,
+ GPIO7 = 0xE7,
+ GPIOINT = 0xE8,
+ GPOSWCTL0 = 0xEC,
+ GPOSWCTL5 = 0xF1,
+ GPO = 0xF4,
+};
+
+/* bits definition for GPIO & GPOSW */
+#define GPIO_DRV 0x01
+#define GPIO_DIR 0x02
+#define GPIO_DIN 0x04
+#define GPIO_DOU 0x08
+#define GPIO_INTCTL 0x30
+#define GPIO_DBC 0xc0
+
+#define GPOSW_DRV 0x01
+#define GPOSW_DOU 0x08
+#define GPOSW_RDRV 0x30
+
+
+#define NUM_GPIO 24
+
+struct pmic_gpio_irq {
+ spinlock_t lock;
+ u32 trigger[NUM_GPIO];
+ u32 dirty;
+ struct work_struct work;
+};
+
+
+struct pmic_gpio {
+ struct gpio_chip chip;
+ struct pmic_gpio_irq irqtypes;
+ void *gpiointr;
+ int irq;
+ unsigned irq_base;
+};
+
+static void pmic_program_irqtype(int gpio, int type)
+{
+ if (type & IRQ_TYPE_EDGE_RISING)
+ intel_scu_ipc_update_register(GPIO0 + gpio, 0x20, 0x20);
+ else
+ intel_scu_ipc_update_register(GPIO0 + gpio, 0x00, 0x20);
+
+ if (type & IRQ_TYPE_EDGE_FALLING)
+ intel_scu_ipc_update_register(GPIO0 + gpio, 0x10, 0x10);
+ else
+ intel_scu_ipc_update_register(GPIO0 + gpio, 0x00, 0x10);
+};
+
+static void pmic_irqtype_work(struct work_struct *work)
+{
+ struct pmic_gpio_irq *t =
+ container_of(work, struct pmic_gpio_irq, work);
+ unsigned long flags;
+ int i;
+ u16 type;
+
+ spin_lock_irqsave(&t->lock, flags);
+ /* As we drop the lock, we may need multiple scans if we race the
+ pmic_irq_type function */
+ while (t->dirty) {
+ /*
+ * For each pin that has the dirty bit set send an IPC
+ * message to configure the hardware via the PMIC
+ */
+ for (i = 0; i < NUM_GPIO; i++) {
+ if (!(t->dirty & (1 << i)))
+ continue;
+ t->dirty &= ~(1 << i);
+ /* We can't trust the array entry or dirty
+ once the lock is dropped */
+ type = t->trigger[i];
+ spin_unlock_irqrestore(&t->lock, flags);
+ pmic_program_irqtype(i, type);
+ spin_lock_irqsave(&t->lock, flags);
+ }
+ }
+ spin_unlock_irqrestore(&t->lock, flags);
+}
+
+static int pmic_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
+{
+ if (offset > 8) {
+ printk(KERN_ERR
+ "%s: only pin 0-7 support input\n", __func__);
+ return -1;/* we only have 8 GPIO can use as input */
+ }
+ return intel_scu_ipc_update_register(GPIO0 + offset,
+ GPIO_DIR, GPIO_DIR);
+}
+
+static int pmic_gpio_direction_output(struct gpio_chip *chip,
+ unsigned offset, int value)
+{
+ int rc = 0;
+
+ if (offset < 8)/* it is GPIO */
+ rc = intel_scu_ipc_update_register(GPIO0 + offset,
+ GPIO_DRV | GPIO_DOU | GPIO_DIR,
+ GPIO_DRV | (value ? GPIO_DOU : 0));
+ else if (offset < 16)/* it is GPOSW */
+ rc = intel_scu_ipc_update_register(GPOSWCTL0 + offset - 8,
+ GPOSW_DRV | GPOSW_DOU | GPOSW_RDRV,
+ GPOSW_DRV | (value ? GPOSW_DOU : 0));
+ else if (offset > 15 && offset < 24)/* it is GPO */
+ rc = intel_scu_ipc_update_register(GPO,
+ 1 << (offset - 16),
+ value ? 1 << (offset - 16) : 0);
+ else {
+ printk(KERN_ERR
+ "%s: invalid PMIC GPIO pin %d!\n", __func__, offset);
+ WARN_ON(1);
+ }
+
+ return rc;
+}
+
+static int pmic_gpio_get(struct gpio_chip *chip, unsigned offset)
+{
+ u8 r;
+ int ret;
+
+ /* we only have 8 GPIO pins we can use as input */
+ if (offset > 8)
+ return -EOPNOTSUPP;
+ ret = intel_scu_ipc_ioread8(GPIO0 + offset, &r);
+ if (ret < 0)
+ return ret;
+ return r & GPIO_DIN;
+}
+
+static void pmic_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
+{
+ if (offset < 8)/* it is GPIO */
+ intel_scu_ipc_update_register(GPIO0 + offset,
+ GPIO_DRV | GPIO_DOU,
+ GPIO_DRV | (value ? GPIO_DOU : 0));
+ else if (offset < 16)/* it is GPOSW */
+ intel_scu_ipc_update_register(GPOSWCTL0 + offset - 8,
+ GPOSW_DRV | GPOSW_DOU | GPOSW_RDRV,
+ GPOSW_DRV | (value ? GPOSW_DOU : 0));
+ else if (offset > 15 && offset < 24) /* it is GPO */
+ intel_scu_ipc_update_register(GPO,
+ 1 << (offset - 16),
+ value ? 1 << (offset - 16) : 0);
+}
+
+static int pmic_irq_type(unsigned irq, unsigned type)
+{
+ struct pmic_gpio *pg = get_irq_chip_data(irq);
+ u32 gpio = irq - pg->irq_base;
+ unsigned long flags;
+
+ if (gpio > pg->chip.ngpio)
+ return -EINVAL;
+
+ spin_lock_irqsave(&pg->irqtypes.lock, flags);
+ pg->irqtypes.trigger[gpio] = type;
+ pg->irqtypes.dirty |= (1 << gpio);
+ spin_unlock_irqrestore(&pg->irqtypes.lock, flags);
+ schedule_work(&pg->irqtypes.work);
+ return 0;
+}
+
+
+
+static int pmic_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
+{
+ struct pmic_gpio *pg = container_of(chip, struct pmic_gpio, chip);
+
+ return pg->irq_base + offset;
+}
+
+/* the gpiointr register is read-clear, so just do nothing. */
+static void pmic_irq_unmask(unsigned irq)
+{
+};
+
+static void pmic_irq_mask(unsigned irq)
+{
+};
+
+static struct irq_chip pmic_irqchip = {
+ .name = "PMIC-GPIO",
+ .mask = pmic_irq_mask,
+ .unmask = pmic_irq_unmask,
+ .set_type = pmic_irq_type,
+};
+
+static void pmic_irq_handler(unsigned irq, struct irq_desc *desc)
+{
+ struct pmic_gpio *pg = (struct pmic_gpio *)get_irq_data(irq);
+ u8 intsts = *((u8 *)pg->gpiointr + 4);
+ int gpio;
+
+ for (gpio = 0; gpio < 8; gpio++) {
+ if (intsts & (1 << gpio)) {
+ pr_debug("pmic pin %d triggered\n", gpio);
+ generic_handle_irq(pg->irq_base + gpio);
+ }
+ }
+ desc->chip->eoi(irq);
+}
+
+static int __devinit platform_pmic_gpio_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ int irq = platform_get_irq(pdev, 0);
+ struct intel_pmic_gpio_platform_data *pdata = dev->platform_data;
+
+ struct pmic_gpio *pg;
+ int retval;
+ int i;
+
+ if (irq < 0) {
+ dev_dbg(dev, "no IRQ line\n");
+ return -EINVAL;
+ }
+
+ if (!pdata || !pdata->gpio_base || !pdata->irq_base) {
+ dev_dbg(dev, "incorrect or missing platform data\n");
+ return -EINVAL;
+ }
+
+ pg = kzalloc(sizeof(*pg), GFP_KERNEL);
+ if (!pg)
+ return -ENOMEM;
+
+ dev_set_drvdata(dev, pg);
+
+ pg->irq = irq;
+ /* setting up SRAM mapping for GPIOINT register */
+ pg->gpiointr = ioremap_nocache(pdata->gpiointr, 8);
+ if (!pg->gpiointr) {
+ printk(KERN_ERR "%s: Can not map GPIOINT.\n", __func__);
+ retval = -EINVAL;
+ goto err2;
+ }
+ pg->irq_base = pdata->irq_base;
+ pg->chip.label = "intel_pmic";
+ pg->chip.direction_input = pmic_gpio_direction_input;
+ pg->chip.direction_output = pmic_gpio_direction_output;
+ pg->chip.get = pmic_gpio_get;
+ pg->chip.set = pmic_gpio_set;
+ pg->chip.to_irq = pmic_gpio_to_irq;
+ pg->chip.base = pdata->gpio_base;
+ pg->chip.ngpio = NUM_GPIO;
+ pg->chip.can_sleep = 1;
+ pg->chip.dev = dev;
+
+ INIT_WORK(&pg->irqtypes.work, pmic_irqtype_work);
+ spin_lock_init(&pg->irqtypes.lock);
+
+ pg->chip.dev = dev;
+ retval = gpiochip_add(&pg->chip);
+ if (retval) {
+ printk(KERN_ERR "%s: Can not add pmic gpio chip.\n", __func__);
+ goto err;
+ }
+ set_irq_data(pg->irq, pg);
+ set_irq_chained_handler(pg->irq, pmic_irq_handler);
+ for (i = 0; i < 8; i++) {
+ set_irq_chip_and_handler_name(i + pg->irq_base, &pmic_irqchip,
+ handle_simple_irq, "demux");
+ set_irq_chip_data(i + pg->irq_base, pg);
+ }
+ return 0;
+err:
+ iounmap(pg->gpiointr);
+err2:
+ kfree(pg);
+ return retval;
+}
+
+/* at the same time, register a platform driver
+ * this supports the sfi 0.81 fw */
+static struct platform_driver platform_pmic_gpio_driver = {
+ .driver = {
+ .name = DRIVER_NAME,
+ .owner = THIS_MODULE,
+ },
+ .probe = platform_pmic_gpio_probe,
+};
+
+static int __init platform_pmic_gpio_init(void)
+{
+ return platform_driver_register(&platform_pmic_gpio_driver);
+}
+
+subsys_initcall(platform_pmic_gpio_init);
+
+MODULE_AUTHOR("Alek Du <alek.du@intel.com>");
+MODULE_DESCRIPTION("Intel Moorestown PMIC GPIO driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/rar_register/rar_register.c b/drivers/platform/x86/intel_rar_register.c
index 618503f422e..73f8e6d7266 100644
--- a/drivers/staging/rar_register/rar_register.c
+++ b/drivers/platform/x86/intel_rar_register.c
@@ -40,15 +40,12 @@
* Initial publish
*/
-#define DEBUG 1
-
-#include "rar_register.h"
-
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/spinlock.h>
#include <linux/device.h>
#include <linux/kernel.h>
+#include <linux/rar_register.h>
/* === Lincroft Message Bus Interface === */
#define LNC_MCR_OFFSET 0xD0 /* Message Control Register */
@@ -155,7 +152,6 @@ static struct rar_device *_rar_to_device(int rar, int *off)
return NULL;
}
-
/**
* rar_to_device - return the device handling this RAR
* @rar: RAR number
@@ -496,7 +492,7 @@ EXPORT_SYMBOL(rar_lock);
* a driver that do require a valid RAR address. One of those
* steps would be to call rar_get_address()
*
- * This function return 0 on success an error code on failure.
+ * This function return 0 on success or an error code on failure.
*/
int register_rar(int num, int (*callback)(unsigned long data),
unsigned long data)
diff --git a/drivers/platform/x86/intel_scu_ipc.c b/drivers/platform/x86/intel_scu_ipc.c
index bb2f1fba637..943f9084dcb 100644
--- a/drivers/platform/x86/intel_scu_ipc.c
+++ b/drivers/platform/x86/intel_scu_ipc.c
@@ -23,7 +23,7 @@
#include <linux/pm.h>
#include <linux/pci.h>
#include <linux/interrupt.h>
-#include <asm/setup.h>
+#include <asm/mrst.h>
#include <asm/intel_scu_ipc.h>
/* IPC defines the following message types */
@@ -38,10 +38,6 @@
#define IPC_CMD_PCNTRL_R 1 /* Register read */
#define IPC_CMD_PCNTRL_M 2 /* Register read-modify-write */
-/* Miscelaneous Command ids */
-#define IPC_CMD_INDIRECT_RD 2 /* 32bit indirect read */
-#define IPC_CMD_INDIRECT_WR 5 /* 32bit indirect write */
-
/*
* IPC register summary
*
@@ -62,8 +58,8 @@
#define IPC_BASE_ADDR 0xFF11C000 /* IPC1 base register address */
#define IPC_MAX_ADDR 0x100 /* Maximum IPC regisers */
-#define IPC_WWBUF_SIZE 16 /* IPC Write buffer Size */
-#define IPC_RWBUF_SIZE 16 /* IPC Read buffer Size */
+#define IPC_WWBUF_SIZE 20 /* IPC Write buffer Size */
+#define IPC_RWBUF_SIZE 20 /* IPC Read buffer Size */
#define IPC_I2C_BASE 0xFF12B000 /* I2C control register base address */
#define IPC_I2C_MAX_ADDR 0x10 /* Maximum I2C regisers */
@@ -78,12 +74,7 @@ struct intel_scu_ipc_dev {
static struct intel_scu_ipc_dev ipcdev; /* Only one for now */
-static int platform = 1;
-module_param(platform, int, 0);
-MODULE_PARM_DESC(platform, "1 for moorestown platform");
-
-
-
+static int platform; /* Platform type */
/*
* IPC Read Buffer (Read Only):
@@ -119,24 +110,6 @@ static inline void ipc_data_writel(u32 data, u32 offset) /* Write ipc data */
}
/*
- * IPC destination Pointer (Write Only):
- * Use content as pointer for destination write
- */
-static inline void ipc_write_dptr(u32 data) /* Write dptr data */
-{
- writel(data, ipcdev.ipc_base + 0x0C);
-}
-
-/*
- * IPC Source Pointer (Write Only):
- * Use content as pointer for read location
-*/
-static inline void ipc_write_sptr(u32 data) /* Write dptr data */
-{
- writel(data, ipcdev.ipc_base + 0x08);
-}
-
-/*
* Status Register (Read Only):
* Driver will read this register to get the ready/busy status of the IPC
* block and error status of the IPC command that was just processed by SCU
@@ -154,7 +127,7 @@ static inline u8 ipc_data_readb(u32 offset) /* Read ipc byte data */
return readb(ipcdev.ipc_base + IPC_READ_BUFFER + offset);
}
-static inline u8 ipc_data_readl(u32 offset) /* Read ipc u32 data */
+static inline u32 ipc_data_readl(u32 offset) /* Read ipc u32 data */
{
return readl(ipcdev.ipc_base + IPC_READ_BUFFER + offset);
}
@@ -175,62 +148,73 @@ static inline int busy_loop(void) /* Wait till scu status is busy */
return -ETIMEDOUT;
}
}
- return (status >> 1) & 1;
+ if ((status >> 1) & 1)
+ return -EIO;
+
+ return 0;
}
/* Read/Write power control(PMIC in Langwell, MSIC in PenWell) registers */
static int pwr_reg_rdwr(u16 *addr, u8 *data, u32 count, u32 op, u32 id)
{
- int nc;
+ int i, nc, bytes, d;
u32 offset = 0;
u32 err = 0;
- u8 cbuf[IPC_WWBUF_SIZE] = { '\0' };
+ u8 cbuf[IPC_WWBUF_SIZE] = { };
u32 *wbuf = (u32 *)&cbuf;
mutex_lock(&ipclock);
+
+ memset(cbuf, 0, sizeof(cbuf));
+
if (ipcdev.pdev == NULL) {
mutex_unlock(&ipclock);
return -ENODEV;
}
- if (platform == 1) {
- /* Entry is 4 bytes for read/write, 5 bytes for read modify */
- for (nc = 0; nc < count; nc++) {
+ if (platform != MRST_CPU_CHIP_PENWELL) {
+ bytes = 0;
+ d = 0;
+ for (i = 0; i < count; i++) {
+ cbuf[bytes++] = addr[i];
+ cbuf[bytes++] = addr[i] >> 8;
+ if (id != IPC_CMD_PCNTRL_R)
+ cbuf[bytes++] = data[d++];
+ if (id == IPC_CMD_PCNTRL_M)
+ cbuf[bytes++] = data[d++];
+ }
+ for (i = 0; i < bytes; i += 4)
+ ipc_data_writel(wbuf[i/4], i);
+ ipc_command(bytes << 16 | id << 12 | 0 << 8 | op);
+ } else {
+ for (nc = 0; nc < count; nc++, offset += 2) {
cbuf[offset] = addr[nc];
cbuf[offset + 1] = addr[nc] >> 8;
- if (id != IPC_CMD_PCNTRL_R)
- cbuf[offset + 2] = data[nc];
- if (id == IPC_CMD_PCNTRL_M) {
- cbuf[offset + 3] = data[nc + 1];
- offset += 1;
- }
- offset += 3;
}
- for (nc = 0, offset = 0; nc < count; nc++, offset += 4)
- ipc_data_writel(wbuf[nc], offset); /* Write wbuff */
- } else {
- for (nc = 0, offset = 0; nc < count; nc++, offset += 2)
- ipc_data_writel(addr[nc], offset); /* Write addresses */
- if (id != IPC_CMD_PCNTRL_R) {
- for (nc = 0; nc < count; nc++, offset++)
- ipc_data_writel(data[nc], offset); /* Write data */
- if (id == IPC_CMD_PCNTRL_M)
- ipc_data_writel(data[nc + 1], offset); /* Mask value*/
+ if (id == IPC_CMD_PCNTRL_R) {
+ for (nc = 0, offset = 0; nc < count; nc++, offset += 4)
+ ipc_data_writel(wbuf[nc], offset);
+ ipc_command((count*2) << 16 | id << 12 | 0 << 8 | op);
+ } else if (id == IPC_CMD_PCNTRL_W) {
+ for (nc = 0; nc < count; nc++, offset += 1)
+ cbuf[offset] = data[nc];
+ for (nc = 0, offset = 0; nc < count; nc++, offset += 4)
+ ipc_data_writel(wbuf[nc], offset);
+ ipc_command((count*3) << 16 | id << 12 | 0 << 8 | op);
+ } else if (id == IPC_CMD_PCNTRL_M) {
+ cbuf[offset] = data[0];
+ cbuf[offset + 1] = data[1];
+ ipc_data_writel(wbuf[0], 0); /* Write wbuff */
+ ipc_command(4 << 16 | id << 12 | 0 << 8 | op);
}
}
- if (id != IPC_CMD_PCNTRL_M)
- ipc_command((count * 3) << 16 | id << 12 | 0 << 8 | op);
- else
- ipc_command((count * 4) << 16 | id << 12 | 0 << 8 | op);
-
err = busy_loop();
-
if (id == IPC_CMD_PCNTRL_R) { /* Read rbuf */
/* Workaround: values are read as 0 without memcpy_fromio */
- memcpy_fromio(cbuf, ipcdev.ipc_base + IPC_READ_BUFFER, 16);
- if (platform == 1) {
+ memcpy_fromio(cbuf, ipcdev.ipc_base + 0x90, 16);
+ if (platform != MRST_CPU_CHIP_PENWELL) {
for (nc = 0, offset = 2; nc < count; nc++, offset += 3)
data[nc] = ipc_data_readb(offset);
} else {
@@ -405,70 +389,6 @@ int intel_scu_ipc_update_register(u16 addr, u8 bits, u8 mask)
EXPORT_SYMBOL(intel_scu_ipc_update_register);
/**
- * intel_scu_ipc_register_read - 32bit indirect read
- * @addr: register address
- * @value: 32bit value return
- *
- * Performs IA 32 bit indirect read, returns 0 on success, or an
- * error code.
- *
- * Can be used when SCCB(System Controller Configuration Block) register
- * HRIM(Honor Restricted IPC Messages) is set (bit 23)
- *
- * This function may sleep. Locking for SCU accesses is handled for
- * the caller.
- */
-int intel_scu_ipc_register_read(u32 addr, u32 *value)
-{
- u32 err = 0;
-
- mutex_lock(&ipclock);
- if (ipcdev.pdev == NULL) {
- mutex_unlock(&ipclock);
- return -ENODEV;
- }
- ipc_write_sptr(addr);
- ipc_command(4 << 16 | IPC_CMD_INDIRECT_RD);
- err = busy_loop();
- *value = ipc_data_readl(0);
- mutex_unlock(&ipclock);
- return err;
-}
-EXPORT_SYMBOL(intel_scu_ipc_register_read);
-
-/**
- * intel_scu_ipc_register_write - 32bit indirect write
- * @addr: register address
- * @value: 32bit value to write
- *
- * Performs IA 32 bit indirect write, returns 0 on success, or an
- * error code.
- *
- * Can be used when SCCB(System Controller Configuration Block) register
- * HRIM(Honor Restricted IPC Messages) is set (bit 23)
- *
- * This function may sleep. Locking for SCU accesses is handled for
- * the caller.
- */
-int intel_scu_ipc_register_write(u32 addr, u32 value)
-{
- u32 err = 0;
-
- mutex_lock(&ipclock);
- if (ipcdev.pdev == NULL) {
- mutex_unlock(&ipclock);
- return -ENODEV;
- }
- ipc_write_dptr(addr);
- ipc_data_writel(value, 0);
- ipc_command(4 << 16 | IPC_CMD_INDIRECT_WR);
- err = busy_loop();
- mutex_unlock(&ipclock);
- return err;
-}
-EXPORT_SYMBOL(intel_scu_ipc_register_write);
-
-/**
* intel_scu_ipc_simple_command - send a simple command
* @cmd: command
* @sub: sub type
@@ -524,7 +444,7 @@ int intel_scu_ipc_command(int cmd, int sub, u32 *in, int inlen,
for (i = 0; i < inlen; i++)
ipc_data_writel(*in++, 4 * i);
- ipc_command((sub << 12) | cmd | (inlen << 18));
+ ipc_command((inlen << 16) | (sub << 12) | cmd);
err = busy_loop();
for (i = 0; i < outlen; i++)
@@ -803,6 +723,7 @@ static void ipc_remove(struct pci_dev *pdev)
static const struct pci_device_id pci_ids[] = {
{PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x080e)},
+ {PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x082a)},
{ 0,}
};
MODULE_DEVICE_TABLE(pci, pci_ids);
@@ -817,6 +738,9 @@ static struct pci_driver ipc_driver = {
static int __init intel_scu_ipc_init(void)
{
+ platform = mrst_identify_cpu();
+ if (platform == 0)
+ return -ENODEV;
return pci_register_driver(&ipc_driver);
}
diff --git a/drivers/platform/x86/msi-laptop.c b/drivers/platform/x86/msi-laptop.c
index afd762b58ad..7e9bb6df9d3 100644
--- a/drivers/platform/x86/msi-laptop.c
+++ b/drivers/platform/x86/msi-laptop.c
@@ -434,7 +434,7 @@ static int dmi_check_cb(const struct dmi_system_id *id)
{
printk(KERN_INFO "msi-laptop: Identified laptop model '%s'.\n",
id->ident);
- return 0;
+ return 1;
}
static struct dmi_system_id __initdata msi_dmi_table[] = {
@@ -562,15 +562,15 @@ static int rfkill_threeg_set(void *data, bool blocked)
return 0;
}
-static struct rfkill_ops rfkill_bluetooth_ops = {
+static const struct rfkill_ops rfkill_bluetooth_ops = {
.set_block = rfkill_bluetooth_set
};
-static struct rfkill_ops rfkill_wlan_ops = {
+static const struct rfkill_ops rfkill_wlan_ops = {
.set_block = rfkill_wlan_set
};
-static struct rfkill_ops rfkill_threeg_ops = {
+static const struct rfkill_ops rfkill_threeg_ops = {
.set_block = rfkill_threeg_set
};
diff --git a/drivers/platform/x86/msi-wmi.c b/drivers/platform/x86/msi-wmi.c
index d1736009636..42a5469a245 100644
--- a/drivers/platform/x86/msi-wmi.c
+++ b/drivers/platform/x86/msi-wmi.c
@@ -57,7 +57,7 @@ static struct key_entry msi_wmi_keymap[] = {
};
static ktime_t last_pressed[ARRAY_SIZE(msi_wmi_keymap) - 1];
-struct backlight_device *backlight;
+static struct backlight_device *backlight;
static int backlight_map[] = { 0x00, 0x33, 0x66, 0x99, 0xCC, 0xFF };
diff --git a/drivers/platform/x86/panasonic-laptop.c b/drivers/platform/x86/panasonic-laptop.c
index 2fb9a32926f..ec01c3d8fc5 100644
--- a/drivers/platform/x86/panasonic-laptop.c
+++ b/drivers/platform/x86/panasonic-laptop.c
@@ -248,7 +248,7 @@ static int acpi_pcc_write_sset(struct pcc_acpi *pcc, int func, int val)
status = acpi_evaluate_object(pcc->handle, METHOD_HKEY_SSET,
&params, NULL);
- return status == AE_OK;
+ return (status == AE_OK) ? 0 : -EIO;
}
static inline int acpi_pcc_get_sqty(struct acpi_device *device)
@@ -586,7 +586,6 @@ static int acpi_pcc_init_input(struct pcc_acpi *pcc)
static int acpi_pcc_hotkey_resume(struct acpi_device *device)
{
struct pcc_acpi *pcc = acpi_driver_data(device);
- acpi_status status = AE_OK;
if (device == NULL || pcc == NULL)
return -EINVAL;
@@ -594,9 +593,7 @@ static int acpi_pcc_hotkey_resume(struct acpi_device *device)
ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Sticky mode restore: %d\n",
pcc->sticky_mode));
- status = acpi_pcc_write_sset(pcc, SINF_STICKY_KEY, pcc->sticky_mode);
-
- return status == AE_OK ? 0 : -EINVAL;
+ return acpi_pcc_write_sset(pcc, SINF_STICKY_KEY, pcc->sticky_mode);
}
static int acpi_pcc_hotkey_add(struct acpi_device *device)
diff --git a/drivers/platform/x86/sony-laptop.c b/drivers/platform/x86/sony-laptop.c
index 1387c5f9c24..e3154ff7a39 100644
--- a/drivers/platform/x86/sony-laptop.c
+++ b/drivers/platform/x86/sony-laptop.c
@@ -561,8 +561,7 @@ static void sony_pf_remove(void)
if (!atomic_dec_and_test(&sony_pf_users))
return;
- platform_device_del(sony_pf_device);
- platform_device_put(sony_pf_device);
+ platform_device_unregister(sony_pf_device);
platform_driver_unregister(&sony_pf_driver);
}
@@ -1196,9 +1195,13 @@ static void sony_nc_rfkill_setup(struct acpi_device *device)
}
device_enum = (union acpi_object *) buffer.pointer;
- if (!device_enum || device_enum->type != ACPI_TYPE_BUFFER) {
- printk(KERN_ERR "Invalid SN06 return object 0x%.2x\n",
- device_enum->type);
+ if (!device_enum) {
+ pr_err("Invalid SN06 return object\n");
+ goto out_no_enum;
+ }
+ if (device_enum->type != ACPI_TYPE_BUFFER) {
+ pr_err("Invalid SN06 return object type 0x%.2x\n",
+ device_enum->type);
goto out_no_enum;
}
diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c
index 4bdb13796e2..5d6119bed00 100644
--- a/drivers/platform/x86/thinkpad_acpi.c
+++ b/drivers/platform/x86/thinkpad_acpi.c
@@ -5838,75 +5838,6 @@ static struct ibm_struct thermal_driver_data = {
};
/*************************************************************************
- * EC Dump subdriver
- */
-
-static u8 ecdump_regs[256];
-
-static int ecdump_read(struct seq_file *m)
-{
- int i, j;
- u8 v;
-
- seq_printf(m, "EC "
- " +00 +01 +02 +03 +04 +05 +06 +07"
- " +08 +09 +0a +0b +0c +0d +0e +0f\n");
- for (i = 0; i < 256; i += 16) {
- seq_printf(m, "EC 0x%02x:", i);
- for (j = 0; j < 16; j++) {
- if (!acpi_ec_read(i + j, &v))
- break;
- if (v != ecdump_regs[i + j])
- seq_printf(m, " *%02x", v);
- else
- seq_printf(m, " %02x", v);
- ecdump_regs[i + j] = v;
- }
- seq_putc(m, '\n');
- if (j != 16)
- break;
- }
-
- /* These are way too dangerous to advertise openly... */
-#if 0
- seq_printf(m, "commands:\t0x<offset> 0x<value>"
- " (<offset> is 00-ff, <value> is 00-ff)\n");
- seq_printf(m, "commands:\t0x<offset> <value> "
- " (<offset> is 00-ff, <value> is 0-255)\n");
-#endif
- return 0;
-}
-
-static int ecdump_write(char *buf)
-{
- char *cmd;
- int i, v;
-
- while ((cmd = next_cmd(&buf))) {
- if (sscanf(cmd, "0x%x 0x%x", &i, &v) == 2) {
- /* i and v set */
- } else if (sscanf(cmd, "0x%x %u", &i, &v) == 2) {
- /* i and v set */
- } else
- return -EINVAL;
- if (i >= 0 && i < 256 && v >= 0 && v < 256) {
- if (!acpi_ec_write(i, v))
- return -EIO;
- } else
- return -EINVAL;
- }
-
- return 0;
-}
-
-static struct ibm_struct ecdump_driver_data = {
- .name = "ecdump",
- .read = ecdump_read,
- .write = ecdump_write,
- .flags.experimental = 1,
-};
-
-/*************************************************************************
* Backlight/brightness subdriver
*/
@@ -8883,9 +8814,6 @@ static struct ibm_init_struct ibms_init[] __initdata = {
.data = &thermal_driver_data,
},
{
- .data = &ecdump_driver_data,
- },
- {
.init = brightness_init,
.data = &brightness_driver_data,
},
@@ -8993,7 +8921,6 @@ TPACPI_PARAM(light);
TPACPI_PARAM(cmos);
TPACPI_PARAM(led);
TPACPI_PARAM(beep);
-TPACPI_PARAM(ecdump);
TPACPI_PARAM(brightness);
TPACPI_PARAM(volume);
TPACPI_PARAM(fan);
diff --git a/drivers/platform/x86/toshiba_acpi.c b/drivers/platform/x86/toshiba_acpi.c
index 37aa1479855..7d67a45bb2b 100644
--- a/drivers/platform/x86/toshiba_acpi.c
+++ b/drivers/platform/x86/toshiba_acpi.c
@@ -4,6 +4,7 @@
*
* Copyright (C) 2002-2004 John Belmonte
* Copyright (C) 2008 Philip Langdale
+ * Copyright (C) 2010 Pierre Ducroquet
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -47,6 +48,7 @@
#include <linux/platform_device.h>
#include <linux/rfkill.h>
#include <linux/input.h>
+#include <linux/leds.h>
#include <linux/slab.h>
#include <asm/uaccess.h>
@@ -129,6 +131,8 @@ enum {KE_KEY, KE_END};
static struct key_entry toshiba_acpi_keymap[] = {
{KE_KEY, 0x101, KEY_MUTE},
+ {KE_KEY, 0x102, KEY_ZOOMOUT},
+ {KE_KEY, 0x103, KEY_ZOOMIN},
{KE_KEY, 0x13b, KEY_COFFEE},
{KE_KEY, 0x13c, KEY_BATTERY},
{KE_KEY, 0x13d, KEY_SLEEP},
@@ -285,6 +289,7 @@ struct toshiba_acpi_dev {
struct platform_device *p_dev;
struct rfkill *bt_rfk;
struct input_dev *hotkey_dev;
+ int illumination_installed;
acpi_handle handle;
const char *bt_name;
@@ -292,6 +297,110 @@ struct toshiba_acpi_dev {
struct mutex mutex;
};
+/* Illumination support */
+static int toshiba_illumination_available(void)
+{
+ u32 in[HCI_WORDS] = { 0, 0, 0, 0, 0, 0 };
+ u32 out[HCI_WORDS];
+ acpi_status status;
+
+ in[0] = 0xf100;
+ status = hci_raw(in, out);
+ if (ACPI_FAILURE(status)) {
+ printk(MY_INFO "Illumination device not available\n");
+ return 0;
+ }
+ in[0] = 0xf400;
+ status = hci_raw(in, out);
+ return 1;
+}
+
+static void toshiba_illumination_set(struct led_classdev *cdev,
+ enum led_brightness brightness)
+{
+ u32 in[HCI_WORDS] = { 0, 0, 0, 0, 0, 0 };
+ u32 out[HCI_WORDS];
+ acpi_status status;
+
+ /* First request : initialize communication. */
+ in[0] = 0xf100;
+ status = hci_raw(in, out);
+ if (ACPI_FAILURE(status)) {
+ printk(MY_INFO "Illumination device not available\n");
+ return;
+ }
+
+ if (brightness) {
+ /* Switch the illumination on */
+ in[0] = 0xf400;
+ in[1] = 0x14e;
+ in[2] = 1;
+ status = hci_raw(in, out);
+ if (ACPI_FAILURE(status)) {
+ printk(MY_INFO "ACPI call for illumination failed.\n");
+ return;
+ }
+ } else {
+ /* Switch the illumination off */
+ in[0] = 0xf400;
+ in[1] = 0x14e;
+ in[2] = 0;
+ status = hci_raw(in, out);
+ if (ACPI_FAILURE(status)) {
+ printk(MY_INFO "ACPI call for illumination failed.\n");
+ return;
+ }
+ }
+
+ /* Last request : close communication. */
+ in[0] = 0xf200;
+ in[1] = 0;
+ in[2] = 0;
+ hci_raw(in, out);
+}
+
+static enum led_brightness toshiba_illumination_get(struct led_classdev *cdev)
+{
+ u32 in[HCI_WORDS] = { 0, 0, 0, 0, 0, 0 };
+ u32 out[HCI_WORDS];
+ acpi_status status;
+ enum led_brightness result;
+
+ /* First request : initialize communication. */
+ in[0] = 0xf100;
+ status = hci_raw(in, out);
+ if (ACPI_FAILURE(status)) {
+ printk(MY_INFO "Illumination device not available\n");
+ return LED_OFF;
+ }
+
+ /* Check the illumination */
+ in[0] = 0xf300;
+ in[1] = 0x14e;
+ status = hci_raw(in, out);
+ if (ACPI_FAILURE(status)) {
+ printk(MY_INFO "ACPI call for illumination failed.\n");
+ return LED_OFF;
+ }
+
+ result = out[2] ? LED_FULL : LED_OFF;
+
+ /* Last request : close communication. */
+ in[0] = 0xf200;
+ in[1] = 0;
+ in[2] = 0;
+ hci_raw(in, out);
+
+ return result;
+}
+
+static struct led_classdev toshiba_led = {
+ .name = "toshiba::illumination",
+ .max_brightness = 1,
+ .brightness_set = toshiba_illumination_set,
+ .brightness_get = toshiba_illumination_get,
+};
+
static struct toshiba_acpi_dev toshiba_acpi = {
.bt_name = "Toshiba Bluetooth",
};
@@ -720,25 +829,22 @@ static const struct file_operations version_proc_fops = {
#define PROC_TOSHIBA "toshiba"
-static acpi_status __init add_device(void)
+static void __init create_toshiba_proc_entries(void)
{
proc_create("lcd", S_IRUGO | S_IWUSR, toshiba_proc_dir, &lcd_proc_fops);
proc_create("video", S_IRUGO | S_IWUSR, toshiba_proc_dir, &video_proc_fops);
proc_create("fan", S_IRUGO | S_IWUSR, toshiba_proc_dir, &fan_proc_fops);
proc_create("keys", S_IRUGO | S_IWUSR, toshiba_proc_dir, &keys_proc_fops);
proc_create("version", S_IRUGO, toshiba_proc_dir, &version_proc_fops);
-
- return AE_OK;
}
-static acpi_status remove_device(void)
+static void remove_toshiba_proc_entries(void)
{
remove_proc_entry("lcd", toshiba_proc_dir);
remove_proc_entry("video", toshiba_proc_dir);
remove_proc_entry("fan", toshiba_proc_dir);
remove_proc_entry("keys", toshiba_proc_dir);
remove_proc_entry("version", toshiba_proc_dir);
- return AE_OK;
}
static struct backlight_ops toshiba_backlight_data = {
@@ -906,7 +1012,7 @@ static void toshiba_acpi_exit(void)
if (toshiba_backlight_device)
backlight_device_unregister(toshiba_backlight_device);
- remove_device();
+ remove_toshiba_proc_entries();
if (toshiba_proc_dir)
remove_proc_entry(PROC_TOSHIBA, acpi_root_dir);
@@ -914,6 +1020,9 @@ static void toshiba_acpi_exit(void)
acpi_remove_notify_handler(toshiba_acpi.handle, ACPI_DEVICE_NOTIFY,
toshiba_acpi_notify);
+ if (toshiba_acpi.illumination_installed)
+ led_classdev_unregister(&toshiba_led);
+
platform_device_unregister(toshiba_acpi.p_dev);
return;
@@ -921,7 +1030,6 @@ static void toshiba_acpi_exit(void)
static int __init toshiba_acpi_init(void)
{
- acpi_status status = AE_OK;
u32 hci_result;
bool bt_present;
int ret = 0;
@@ -969,11 +1077,7 @@ static int __init toshiba_acpi_init(void)
toshiba_acpi_exit();
return -ENODEV;
} else {
- status = add_device();
- if (ACPI_FAILURE(status)) {
- toshiba_acpi_exit();
- return -ENODEV;
- }
+ create_toshiba_proc_entries();
}
props.max_brightness = HCI_LCD_BRIGHTNESS_LEVELS - 1;
@@ -1013,6 +1117,13 @@ static int __init toshiba_acpi_init(void)
}
}
+ toshiba_acpi.illumination_installed = 0;
+ if (toshiba_illumination_available()) {
+ if (!led_classdev_register(&(toshiba_acpi.p_dev->dev),
+ &toshiba_led))
+ toshiba_acpi.illumination_installed = 1;
+ }
+
return 0;
}
diff --git a/drivers/platform/x86/wmi.c b/drivers/platform/x86/wmi.c
index e4eaa14ed98..b2978a04317 100644
--- a/drivers/platform/x86/wmi.c
+++ b/drivers/platform/x86/wmi.c
@@ -518,8 +518,13 @@ static void wmi_notify_debug(u32 value, void *context)
{
struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL };
union acpi_object *obj;
+ acpi_status status;
- wmi_get_event_data(value, &response);
+ status = wmi_get_event_data(value, &response);
+ if (status != AE_OK) {
+ printk(KERN_INFO "wmi: bad event status 0x%x\n", status);
+ return;
+ }
obj = (union acpi_object *)response.pointer;
@@ -543,6 +548,7 @@ static void wmi_notify_debug(u32 value, void *context)
default:
printk("object type 0x%X\n", obj->type);
}
+ kfree(obj);
}
/**
@@ -804,7 +810,7 @@ static bool guid_already_parsed(const char *guid_string)
/*
* Parse the _WDG method for the GUID data blocks
*/
-static __init acpi_status parse_wdg(acpi_handle handle)
+static acpi_status parse_wdg(acpi_handle handle)
{
struct acpi_buffer out = {ACPI_ALLOCATE_BUFFER, NULL};
union acpi_object *obj;
@@ -827,8 +833,10 @@ static __init acpi_status parse_wdg(acpi_handle handle)
total = obj->buffer.length / sizeof(struct guid_block);
gblock = kmemdup(obj->buffer.pointer, obj->buffer.length, GFP_KERNEL);
- if (!gblock)
- return AE_NO_MEMORY;
+ if (!gblock) {
+ status = AE_NO_MEMORY;
+ goto out_free_pointer;
+ }
for (i = 0; i < total; i++) {
/*
@@ -848,8 +856,10 @@ static __init acpi_status parse_wdg(acpi_handle handle)
wmi_dump_wdg(&gblock[i]);
wblock = kzalloc(sizeof(struct wmi_block), GFP_KERNEL);
- if (!wblock)
- return AE_NO_MEMORY;
+ if (!wblock) {
+ status = AE_NO_MEMORY;
+ goto out_free_gblock;
+ }
wblock->gblock = gblock[i];
wblock->handle = handle;
@@ -860,8 +870,10 @@ static __init acpi_status parse_wdg(acpi_handle handle)
list_add_tail(&wblock->list, &wmi_blocks.list);
}
- kfree(out.pointer);
+out_free_gblock:
kfree(gblock);
+out_free_pointer:
+ kfree(out.pointer);
return status;
}
@@ -947,7 +959,7 @@ static int acpi_wmi_remove(struct acpi_device *device, int type)
return 0;
}
-static int __init acpi_wmi_add(struct acpi_device *device)
+static int acpi_wmi_add(struct acpi_device *device)
{
acpi_status status;
int result = 0;
diff --git a/drivers/pnp/core.c b/drivers/pnp/core.c
index 5dba90995d9..88b3cde5259 100644
--- a/drivers/pnp/core.c
+++ b/drivers/pnp/core.c
@@ -164,6 +164,9 @@ int __pnp_add_device(struct pnp_dev *dev)
list_add_tail(&dev->global_list, &pnp_global);
list_add_tail(&dev->protocol_list, &dev->protocol->devices);
spin_unlock(&pnp_lock);
+ if (dev->protocol->can_wakeup)
+ device_set_wakeup_capable(&dev->dev,
+ dev->protocol->can_wakeup(dev));
return device_register(&dev->dev);
}
diff --git a/drivers/pnp/pnpacpi/core.c b/drivers/pnp/pnpacpi/core.c
index f7ff628b7d9..dc4e32e031e 100644
--- a/drivers/pnp/pnpacpi/core.c
+++ b/drivers/pnp/pnpacpi/core.c
@@ -122,17 +122,37 @@ static int pnpacpi_disable_resources(struct pnp_dev *dev)
}
#ifdef CONFIG_ACPI_SLEEP
+static bool pnpacpi_can_wakeup(struct pnp_dev *dev)
+{
+ struct acpi_device *acpi_dev = dev->data;
+ acpi_handle handle = acpi_dev->handle;
+
+ return acpi_bus_can_wakeup(handle);
+}
+
static int pnpacpi_suspend(struct pnp_dev *dev, pm_message_t state)
{
struct acpi_device *acpi_dev = dev->data;
acpi_handle handle = acpi_dev->handle;
int power_state;
+ if (device_can_wakeup(&dev->dev)) {
+ int rc = acpi_pm_device_sleep_wake(&dev->dev,
+ device_may_wakeup(&dev->dev));
+
+ if (rc)
+ return rc;
+ }
power_state = acpi_pm_device_sleep_state(&dev->dev, NULL);
if (power_state < 0)
power_state = (state.event == PM_EVENT_ON) ?
ACPI_STATE_D0 : ACPI_STATE_D3;
+ /* acpi_bus_set_power() often fails (keyboard port can't be
+ * powered-down?), and in any case, our return value is ignored
+ * by pnp_bus_suspend(). Hence we don't revert the wakeup
+ * setting if the set_power fails.
+ */
return acpi_bus_set_power(handle, power_state);
}
@@ -141,6 +161,8 @@ static int pnpacpi_resume(struct pnp_dev *dev)
struct acpi_device *acpi_dev = dev->data;
acpi_handle handle = acpi_dev->handle;
+ if (device_may_wakeup(&dev->dev))
+ acpi_pm_device_sleep_wake(&dev->dev, false);
return acpi_bus_set_power(handle, ACPI_STATE_D0);
}
#endif
@@ -151,6 +173,7 @@ struct pnp_protocol pnpacpi_protocol = {
.set = pnpacpi_set_resources,
.disable = pnpacpi_disable_resources,
#ifdef CONFIG_ACPI_SLEEP
+ .can_wakeup = pnpacpi_can_wakeup,
.suspend = pnpacpi_suspend,
.resume = pnpacpi_resume,
#endif
diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig
index 8e9ba177d81..1e5506be39b 100644
--- a/drivers/power/Kconfig
+++ b/drivers/power/Kconfig
@@ -142,4 +142,15 @@ config CHARGER_PCF50633
help
Say Y to include support for NXP PCF50633 Main Battery Charger.
+config BATTERY_JZ4740
+ tristate "Ingenic JZ4740 battery"
+ depends on MACH_JZ4740
+ depends on MFD_JZ4740_ADC
+ help
+ Say Y to enable support for the battery on Ingenic JZ4740 based
+ boards.
+
+ This driver can be build as a module. If so, the module will be
+ called jz4740-battery.
+
endif # POWER_SUPPLY
diff --git a/drivers/power/Makefile b/drivers/power/Makefile
index 00050809a6c..cf95009d9bc 100644
--- a/drivers/power/Makefile
+++ b/drivers/power/Makefile
@@ -34,3 +34,4 @@ obj-$(CONFIG_BATTERY_DA9030) += da9030_battery.o
obj-$(CONFIG_BATTERY_MAX17040) += max17040_battery.o
obj-$(CONFIG_BATTERY_Z2) += z2_battery.o
obj-$(CONFIG_CHARGER_PCF50633) += pcf50633-charger.o
+obj-$(CONFIG_BATTERY_JZ4740) += jz4740-battery.o
diff --git a/drivers/power/jz4740-battery.c b/drivers/power/jz4740-battery.c
new file mode 100644
index 00000000000..20c4b952e9b
--- /dev/null
+++ b/drivers/power/jz4740-battery.c
@@ -0,0 +1,445 @@
+/*
+ * Battery measurement code for Ingenic JZ SOC.
+ *
+ * Copyright (C) 2009 Jiejing Zhang <kzjeef@gmail.com>
+ * Copyright (C) 2010, Lars-Peter Clausen <lars@metafoo.de>
+ *
+ * based on tosa_battery.c
+ *
+ * Copyright (C) 2008 Marek Vasut <marek.vasut@gmail.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/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+#include <linux/delay.h>
+#include <linux/gpio.h>
+#include <linux/mfd/core.h>
+#include <linux/power_supply.h>
+
+#include <linux/power/jz4740-battery.h>
+#include <linux/jz4740-adc.h>
+
+struct jz_battery {
+ struct jz_battery_platform_data *pdata;
+ struct platform_device *pdev;
+
+ struct resource *mem;
+ void __iomem *base;
+
+ int irq;
+ int charge_irq;
+
+ struct mfd_cell *cell;
+
+ int status;
+ long voltage;
+
+ struct completion read_completion;
+
+ struct power_supply battery;
+ struct delayed_work work;
+};
+
+static inline struct jz_battery *psy_to_jz_battery(struct power_supply *psy)
+{
+ return container_of(psy, struct jz_battery, battery);
+}
+
+static irqreturn_t jz_battery_irq_handler(int irq, void *devid)
+{
+ struct jz_battery *battery = devid;
+
+ complete(&battery->read_completion);
+ return IRQ_HANDLED;
+}
+
+static long jz_battery_read_voltage(struct jz_battery *battery)
+{
+ unsigned long t;
+ unsigned long val;
+ long voltage;
+
+ INIT_COMPLETION(battery->read_completion);
+
+ enable_irq(battery->irq);
+ battery->cell->enable(battery->pdev);
+
+ t = wait_for_completion_interruptible_timeout(&battery->read_completion,
+ HZ);
+
+ if (t > 0) {
+ val = readw(battery->base) & 0xfff;
+
+ if (battery->pdata->info.voltage_max_design <= 2500000)
+ val = (val * 78125UL) >> 7UL;
+ else
+ val = ((val * 924375UL) >> 9UL) + 33000;
+ voltage = (long)val;
+ } else {
+ voltage = t ? t : -ETIMEDOUT;
+ }
+
+ battery->cell->disable(battery->pdev);
+ disable_irq(battery->irq);
+
+ return voltage;
+}
+
+static int jz_battery_get_capacity(struct power_supply *psy)
+{
+ struct jz_battery *jz_battery = psy_to_jz_battery(psy);
+ struct power_supply_info *info = &jz_battery->pdata->info;
+ long voltage;
+ int ret;
+ int voltage_span;
+
+ voltage = jz_battery_read_voltage(jz_battery);
+
+ if (voltage < 0)
+ return voltage;
+
+ voltage_span = info->voltage_max_design - info->voltage_min_design;
+ ret = ((voltage - info->voltage_min_design) * 100) / voltage_span;
+
+ if (ret > 100)
+ ret = 100;
+ else if (ret < 0)
+ ret = 0;
+
+ return ret;
+}
+
+static int jz_battery_get_property(struct power_supply *psy,
+ enum power_supply_property psp, union power_supply_propval *val)
+{
+ struct jz_battery *jz_battery = psy_to_jz_battery(psy);
+ struct power_supply_info *info = &jz_battery->pdata->info;
+ long voltage;
+
+ switch (psp) {
+ case POWER_SUPPLY_PROP_STATUS:
+ val->intval = jz_battery->status;
+ break;
+ case POWER_SUPPLY_PROP_TECHNOLOGY:
+ val->intval = jz_battery->pdata->info.technology;
+ break;
+ case POWER_SUPPLY_PROP_HEALTH:
+ voltage = jz_battery_read_voltage(jz_battery);
+ if (voltage < info->voltage_min_design)
+ val->intval = POWER_SUPPLY_HEALTH_DEAD;
+ else
+ val->intval = POWER_SUPPLY_HEALTH_GOOD;
+ break;
+ case POWER_SUPPLY_PROP_CAPACITY:
+ val->intval = jz_battery_get_capacity(psy);
+ break;
+ case POWER_SUPPLY_PROP_VOLTAGE_NOW:
+ val->intval = jz_battery_read_voltage(jz_battery);
+ if (val->intval < 0)
+ return val->intval;
+ break;
+ case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN:
+ val->intval = info->voltage_max_design;
+ break;
+ case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN:
+ val->intval = info->voltage_min_design;
+ break;
+ case POWER_SUPPLY_PROP_PRESENT:
+ val->intval = 1;
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static void jz_battery_external_power_changed(struct power_supply *psy)
+{
+ struct jz_battery *jz_battery = psy_to_jz_battery(psy);
+
+ cancel_delayed_work(&jz_battery->work);
+ schedule_delayed_work(&jz_battery->work, 0);
+}
+
+static irqreturn_t jz_battery_charge_irq(int irq, void *data)
+{
+ struct jz_battery *jz_battery = data;
+
+ cancel_delayed_work(&jz_battery->work);
+ schedule_delayed_work(&jz_battery->work, 0);
+
+ return IRQ_HANDLED;
+}
+
+static void jz_battery_update(struct jz_battery *jz_battery)
+{
+ int status;
+ long voltage;
+ bool has_changed = false;
+ int is_charging;
+
+ if (gpio_is_valid(jz_battery->pdata->gpio_charge)) {
+ is_charging = gpio_get_value(jz_battery->pdata->gpio_charge);
+ is_charging ^= jz_battery->pdata->gpio_charge_active_low;
+ if (is_charging)
+ status = POWER_SUPPLY_STATUS_CHARGING;
+ else
+ status = POWER_SUPPLY_STATUS_NOT_CHARGING;
+
+ if (status != jz_battery->status) {
+ jz_battery->status = status;
+ has_changed = true;
+ }
+ }
+
+ voltage = jz_battery_read_voltage(jz_battery);
+ if (abs(voltage - jz_battery->voltage) < 50000) {
+ jz_battery->voltage = voltage;
+ has_changed = true;
+ }
+
+ if (has_changed)
+ power_supply_changed(&jz_battery->battery);
+}
+
+static enum power_supply_property jz_battery_properties[] = {
+ POWER_SUPPLY_PROP_STATUS,
+ POWER_SUPPLY_PROP_TECHNOLOGY,
+ POWER_SUPPLY_PROP_HEALTH,
+ POWER_SUPPLY_PROP_CAPACITY,
+ POWER_SUPPLY_PROP_VOLTAGE_NOW,
+ POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN,
+ POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,
+ POWER_SUPPLY_PROP_PRESENT,
+};
+
+static void jz_battery_work(struct work_struct *work)
+{
+ /* Too small interval will increase system workload */
+ const int interval = HZ * 30;
+ struct jz_battery *jz_battery = container_of(work, struct jz_battery,
+ work.work);
+
+ jz_battery_update(jz_battery);
+ schedule_delayed_work(&jz_battery->work, interval);
+}
+
+static int __devinit jz_battery_probe(struct platform_device *pdev)
+{
+ int ret = 0;
+ struct jz_battery_platform_data *pdata = pdev->dev.parent->platform_data;
+ struct jz_battery *jz_battery;
+ struct power_supply *battery;
+
+ jz_battery = kzalloc(sizeof(*jz_battery), GFP_KERNEL);
+ if (!jz_battery) {
+ dev_err(&pdev->dev, "Failed to allocate driver structure\n");
+ return -ENOMEM;
+ }
+
+ jz_battery->cell = pdev->dev.platform_data;
+
+ jz_battery->irq = platform_get_irq(pdev, 0);
+ if (jz_battery->irq < 0) {
+ ret = jz_battery->irq;
+ dev_err(&pdev->dev, "Failed to get platform irq: %d\n", ret);
+ goto err_free;
+ }
+
+ jz_battery->mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!jz_battery->mem) {
+ ret = -ENOENT;
+ dev_err(&pdev->dev, "Failed to get platform mmio resource\n");
+ goto err_free;
+ }
+
+ jz_battery->mem = request_mem_region(jz_battery->mem->start,
+ resource_size(jz_battery->mem), pdev->name);
+ if (!jz_battery->mem) {
+ ret = -EBUSY;
+ dev_err(&pdev->dev, "Failed to request mmio memory region\n");
+ goto err_free;
+ }
+
+ jz_battery->base = ioremap_nocache(jz_battery->mem->start,
+ resource_size(jz_battery->mem));
+ if (!jz_battery->base) {
+ ret = -EBUSY;
+ dev_err(&pdev->dev, "Failed to ioremap mmio memory\n");
+ goto err_release_mem_region;
+ }
+
+ battery = &jz_battery->battery;
+ battery->name = pdata->info.name;
+ battery->type = POWER_SUPPLY_TYPE_BATTERY;
+ battery->properties = jz_battery_properties;
+ battery->num_properties = ARRAY_SIZE(jz_battery_properties);
+ battery->get_property = jz_battery_get_property;
+ battery->external_power_changed = jz_battery_external_power_changed;
+ battery->use_for_apm = 1;
+
+ jz_battery->pdata = pdata;
+ jz_battery->pdev = pdev;
+
+ init_completion(&jz_battery->read_completion);
+
+ INIT_DELAYED_WORK(&jz_battery->work, jz_battery_work);
+
+ ret = request_irq(jz_battery->irq, jz_battery_irq_handler, 0, pdev->name,
+ jz_battery);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to request irq %d\n", ret);
+ goto err_iounmap;
+ }
+ disable_irq(jz_battery->irq);
+
+ if (gpio_is_valid(pdata->gpio_charge)) {
+ ret = gpio_request(pdata->gpio_charge, dev_name(&pdev->dev));
+ if (ret) {
+ dev_err(&pdev->dev, "charger state gpio request failed.\n");
+ goto err_free_irq;
+ }
+ ret = gpio_direction_input(pdata->gpio_charge);
+ if (ret) {
+ dev_err(&pdev->dev, "charger state gpio set direction failed.\n");
+ goto err_free_gpio;
+ }
+
+ jz_battery->charge_irq = gpio_to_irq(pdata->gpio_charge);
+
+ if (jz_battery->charge_irq >= 0) {
+ ret = request_irq(jz_battery->charge_irq,
+ jz_battery_charge_irq,
+ IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
+ dev_name(&pdev->dev), jz_battery);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to request charge irq: %d\n", ret);
+ goto err_free_gpio;
+ }
+ }
+ } else {
+ jz_battery->charge_irq = -1;
+ }
+
+ if (jz_battery->pdata->info.voltage_max_design <= 2500000)
+ jz4740_adc_set_config(pdev->dev.parent, JZ_ADC_CONFIG_BAT_MB,
+ JZ_ADC_CONFIG_BAT_MB);
+ else
+ jz4740_adc_set_config(pdev->dev.parent, JZ_ADC_CONFIG_BAT_MB, 0);
+
+ ret = power_supply_register(&pdev->dev, &jz_battery->battery);
+ if (ret) {
+ dev_err(&pdev->dev, "power supply battery register failed.\n");
+ goto err_free_charge_irq;
+ }
+
+ platform_set_drvdata(pdev, jz_battery);
+ schedule_delayed_work(&jz_battery->work, 0);
+
+ return 0;
+
+err_free_charge_irq:
+ if (jz_battery->charge_irq >= 0)
+ free_irq(jz_battery->charge_irq, jz_battery);
+err_free_gpio:
+ if (gpio_is_valid(pdata->gpio_charge))
+ gpio_free(jz_battery->pdata->gpio_charge);
+err_free_irq:
+ free_irq(jz_battery->irq, jz_battery);
+err_iounmap:
+ platform_set_drvdata(pdev, NULL);
+ iounmap(jz_battery->base);
+err_release_mem_region:
+ release_mem_region(jz_battery->mem->start, resource_size(jz_battery->mem));
+err_free:
+ kfree(jz_battery);
+ return ret;
+}
+
+static int __devexit jz_battery_remove(struct platform_device *pdev)
+{
+ struct jz_battery *jz_battery = platform_get_drvdata(pdev);
+
+ cancel_delayed_work_sync(&jz_battery->work);
+
+ if (gpio_is_valid(jz_battery->pdata->gpio_charge)) {
+ if (jz_battery->charge_irq >= 0)
+ free_irq(jz_battery->charge_irq, jz_battery);
+ gpio_free(jz_battery->pdata->gpio_charge);
+ }
+
+ power_supply_unregister(&jz_battery->battery);
+
+ free_irq(jz_battery->irq, jz_battery);
+
+ iounmap(jz_battery->base);
+ release_mem_region(jz_battery->mem->start, resource_size(jz_battery->mem));
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int jz_battery_suspend(struct device *dev)
+{
+ struct jz_battery *jz_battery = dev_get_drvdata(dev);
+
+ cancel_delayed_work_sync(&jz_battery->work);
+ jz_battery->status = POWER_SUPPLY_STATUS_UNKNOWN;
+
+ return 0;
+}
+
+static int jz_battery_resume(struct device *dev)
+{
+ struct jz_battery *jz_battery = dev_get_drvdata(dev);
+
+ schedule_delayed_work(&jz_battery->work, 0);
+
+ return 0;
+}
+
+static const struct dev_pm_ops jz_battery_pm_ops = {
+ .suspend = jz_battery_suspend,
+ .resume = jz_battery_resume,
+};
+
+#define JZ_BATTERY_PM_OPS (&jz_battery_pm_ops)
+#else
+#define JZ_BATTERY_PM_OPS NULL
+#endif
+
+static struct platform_driver jz_battery_driver = {
+ .probe = jz_battery_probe,
+ .remove = __devexit_p(jz_battery_remove),
+ .driver = {
+ .name = "jz4740-battery",
+ .owner = THIS_MODULE,
+ .pm = JZ_BATTERY_PM_OPS,
+ },
+};
+
+static int __init jz_battery_init(void)
+{
+ return platform_driver_register(&jz_battery_driver);
+}
+module_init(jz_battery_init);
+
+static void __exit jz_battery_exit(void)
+{
+ platform_driver_unregister(&jz_battery_driver);
+}
+module_exit(jz_battery_exit);
+
+MODULE_ALIAS("platform:jz4740-battery");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
+MODULE_DESCRIPTION("JZ4740 SoC battery driver");
diff --git a/drivers/rapidio/rio.c b/drivers/rapidio/rio.c
index 08fa453af97..74e9d22d95f 100644
--- a/drivers/rapidio/rio.c
+++ b/drivers/rapidio/rio.c
@@ -808,7 +808,7 @@ int rio_std_route_add_entry(struct rio_mport *mport, u16 destid, u8 hopcount,
/**
* rio_std_route_get_entry - Read switch route table entry (port number)
- * assosiated with specified destID using standard registers defined in RIO
+ * associated with specified destID using standard registers defined in RIO
* specification rev.1.3
* @mport: Master port to issue transaction
* @destid: Destination ID of the device
diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index 2248087b9be..422a709d271 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -1025,7 +1025,6 @@ static struct regulator *create_regulator(struct regulator_dev *rdev,
if (regulator->dev_attr.attr.name == NULL)
goto attr_name_err;
- regulator->dev_attr.attr.owner = THIS_MODULE;
regulator->dev_attr.attr.mode = 0444;
regulator->dev_attr.show = device_requested_uA_show;
err = device_create_file(dev, &regulator->dev_attr);
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index 10ba12c8c5e..4301a6c7ed3 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -774,7 +774,7 @@ config RTC_DRV_AT91SAM9_GPBR
config RTC_DRV_AU1XXX
tristate "Au1xxx Counter0 RTC support"
- depends on SOC_AU1X00
+ depends on MIPS_ALCHEMY
help
This is a driver for the Au1xxx on-chip Counter0 (Time-Of-Year
counter) to be used as a RTC.
@@ -905,4 +905,15 @@ config RTC_DRV_MPC5121
This driver can also be built as a module. If so, the module
will be called rtc-mpc5121.
+config RTC_DRV_JZ4740
+ tristate "Ingenic JZ4740 SoC"
+ depends on RTC_CLASS
+ depends on MACH_JZ4740
+ help
+ If you say yes here you get support for the Ingenic JZ4740 SoC RTC
+ controller.
+
+ This driver can also be buillt as a module. If so, the module
+ will be called rtc-jz4740.
+
endif # RTC_CLASS
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
index 5adbba7cf89..fedf9bb3659 100644
--- a/drivers/rtc/Makefile
+++ b/drivers/rtc/Makefile
@@ -47,6 +47,7 @@ obj-$(CONFIG_RTC_DRV_EP93XX) += rtc-ep93xx.o
obj-$(CONFIG_RTC_DRV_FM3130) += rtc-fm3130.o
obj-$(CONFIG_RTC_DRV_GENERIC) += rtc-generic.o
obj-$(CONFIG_RTC_DRV_ISL1208) += rtc-isl1208.o
+obj-$(CONFIG_RTC_DRV_JZ4740) += rtc-jz4740.o
obj-$(CONFIG_RTC_DRV_M41T80) += rtc-m41t80.o
obj-$(CONFIG_RTC_DRV_M41T94) += rtc-m41t94.o
obj-$(CONFIG_RTC_DRV_M48T35) += rtc-m48t35.o
diff --git a/drivers/rtc/rtc-fm3130.c b/drivers/rtc/rtc-fm3130.c
index ff6fce61ea4..e4de8f37ae4 100644
--- a/drivers/rtc/rtc-fm3130.c
+++ b/drivers/rtc/rtc-fm3130.c
@@ -104,7 +104,7 @@ static int fm3130_get_time(struct device *dev, struct rtc_time *t)
if (!fm3130->data_valid) {
/* We have invalid data in RTC, probably due
to battery faults or other problems. Return EIO
- for now, it will allow us to set data later insted
+ for now, it will allow us to set data later instead
of error during probing which disables device */
return -EIO;
}
diff --git a/drivers/rtc/rtc-jz4740.c b/drivers/rtc/rtc-jz4740.c
new file mode 100644
index 00000000000..2619d57b91d
--- /dev/null
+++ b/drivers/rtc/rtc-jz4740.c
@@ -0,0 +1,345 @@
+/*
+ * Copyright (C) 2009-2010, Lars-Peter Clausen <lars@metafoo.de>
+ * JZ4740 SoC RTC 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.
+ *
+ * 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/platform_device.h>
+#include <linux/rtc.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+
+#define JZ_REG_RTC_CTRL 0x00
+#define JZ_REG_RTC_SEC 0x04
+#define JZ_REG_RTC_SEC_ALARM 0x08
+#define JZ_REG_RTC_REGULATOR 0x0C
+#define JZ_REG_RTC_HIBERNATE 0x20
+#define JZ_REG_RTC_SCRATCHPAD 0x34
+
+#define JZ_RTC_CTRL_WRDY BIT(7)
+#define JZ_RTC_CTRL_1HZ BIT(6)
+#define JZ_RTC_CTRL_1HZ_IRQ BIT(5)
+#define JZ_RTC_CTRL_AF BIT(4)
+#define JZ_RTC_CTRL_AF_IRQ BIT(3)
+#define JZ_RTC_CTRL_AE BIT(2)
+#define JZ_RTC_CTRL_ENABLE BIT(0)
+
+struct jz4740_rtc {
+ struct resource *mem;
+ void __iomem *base;
+
+ struct rtc_device *rtc;
+
+ unsigned int irq;
+
+ spinlock_t lock;
+};
+
+static inline uint32_t jz4740_rtc_reg_read(struct jz4740_rtc *rtc, size_t reg)
+{
+ return readl(rtc->base + reg);
+}
+
+static int jz4740_rtc_wait_write_ready(struct jz4740_rtc *rtc)
+{
+ uint32_t ctrl;
+ int timeout = 1000;
+
+ do {
+ ctrl = jz4740_rtc_reg_read(rtc, JZ_REG_RTC_CTRL);
+ } while (!(ctrl & JZ_RTC_CTRL_WRDY) && --timeout);
+
+ return timeout ? 0 : -EIO;
+}
+
+static inline int jz4740_rtc_reg_write(struct jz4740_rtc *rtc, size_t reg,
+ uint32_t val)
+{
+ int ret;
+ ret = jz4740_rtc_wait_write_ready(rtc);
+ if (ret == 0)
+ writel(val, rtc->base + reg);
+
+ return ret;
+}
+
+static int jz4740_rtc_ctrl_set_bits(struct jz4740_rtc *rtc, uint32_t mask,
+ bool set)
+{
+ int ret;
+ unsigned long flags;
+ uint32_t ctrl;
+
+ spin_lock_irqsave(&rtc->lock, flags);
+
+ ctrl = jz4740_rtc_reg_read(rtc, JZ_REG_RTC_CTRL);
+
+ /* Don't clear interrupt flags by accident */
+ ctrl |= JZ_RTC_CTRL_1HZ | JZ_RTC_CTRL_AF;
+
+ if (set)
+ ctrl |= mask;
+ else
+ ctrl &= ~mask;
+
+ ret = jz4740_rtc_reg_write(rtc, JZ_REG_RTC_CTRL, ctrl);
+
+ spin_unlock_irqrestore(&rtc->lock, flags);
+
+ return ret;
+}
+
+static int jz4740_rtc_read_time(struct device *dev, struct rtc_time *time)
+{
+ struct jz4740_rtc *rtc = dev_get_drvdata(dev);
+ uint32_t secs, secs2;
+ int timeout = 5;
+
+ /* If the seconds register is read while it is updated, it can contain a
+ * bogus value. This can be avoided by making sure that two consecutive
+ * reads have the same value.
+ */
+ secs = jz4740_rtc_reg_read(rtc, JZ_REG_RTC_SEC);
+ secs2 = jz4740_rtc_reg_read(rtc, JZ_REG_RTC_SEC);
+
+ while (secs != secs2 && --timeout) {
+ secs = secs2;
+ secs2 = jz4740_rtc_reg_read(rtc, JZ_REG_RTC_SEC);
+ }
+
+ if (timeout == 0)
+ return -EIO;
+
+ rtc_time_to_tm(secs, time);
+
+ return rtc_valid_tm(time);
+}
+
+static int jz4740_rtc_set_mmss(struct device *dev, unsigned long secs)
+{
+ struct jz4740_rtc *rtc = dev_get_drvdata(dev);
+
+ return jz4740_rtc_reg_write(rtc, JZ_REG_RTC_SEC, secs);
+}
+
+static int jz4740_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+ struct jz4740_rtc *rtc = dev_get_drvdata(dev);
+ uint32_t secs;
+ uint32_t ctrl;
+
+ secs = jz4740_rtc_reg_read(rtc, JZ_REG_RTC_SEC_ALARM);
+
+ ctrl = jz4740_rtc_reg_read(rtc, JZ_REG_RTC_CTRL);
+
+ alrm->enabled = !!(ctrl & JZ_RTC_CTRL_AE);
+ alrm->pending = !!(ctrl & JZ_RTC_CTRL_AF);
+
+ rtc_time_to_tm(secs, &alrm->time);
+
+ return rtc_valid_tm(&alrm->time);
+}
+
+static int jz4740_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+ int ret;
+ struct jz4740_rtc *rtc = dev_get_drvdata(dev);
+ unsigned long secs;
+
+ rtc_tm_to_time(&alrm->time, &secs);
+
+ ret = jz4740_rtc_reg_write(rtc, JZ_REG_RTC_SEC_ALARM, secs);
+ if (!ret)
+ ret = jz4740_rtc_ctrl_set_bits(rtc, JZ_RTC_CTRL_AE, alrm->enabled);
+
+ return ret;
+}
+
+static int jz4740_rtc_update_irq_enable(struct device *dev, unsigned int enable)
+{
+ struct jz4740_rtc *rtc = dev_get_drvdata(dev);
+ return jz4740_rtc_ctrl_set_bits(rtc, JZ_RTC_CTRL_1HZ_IRQ, enable);
+}
+
+static int jz4740_rtc_alarm_irq_enable(struct device *dev, unsigned int enable)
+{
+ struct jz4740_rtc *rtc = dev_get_drvdata(dev);
+ return jz4740_rtc_ctrl_set_bits(rtc, JZ_RTC_CTRL_AF_IRQ, enable);
+}
+
+static struct rtc_class_ops jz4740_rtc_ops = {
+ .read_time = jz4740_rtc_read_time,
+ .set_mmss = jz4740_rtc_set_mmss,
+ .read_alarm = jz4740_rtc_read_alarm,
+ .set_alarm = jz4740_rtc_set_alarm,
+ .update_irq_enable = jz4740_rtc_update_irq_enable,
+ .alarm_irq_enable = jz4740_rtc_alarm_irq_enable,
+};
+
+static irqreturn_t jz4740_rtc_irq(int irq, void *data)
+{
+ struct jz4740_rtc *rtc = data;
+ uint32_t ctrl;
+ unsigned long events = 0;
+
+ ctrl = jz4740_rtc_reg_read(rtc, JZ_REG_RTC_CTRL);
+
+ if (ctrl & JZ_RTC_CTRL_1HZ)
+ events |= (RTC_UF | RTC_IRQF);
+
+ if (ctrl & JZ_RTC_CTRL_AF)
+ events |= (RTC_AF | RTC_IRQF);
+
+ rtc_update_irq(rtc->rtc, 1, events);
+
+ jz4740_rtc_ctrl_set_bits(rtc, JZ_RTC_CTRL_1HZ | JZ_RTC_CTRL_AF, false);
+
+ return IRQ_HANDLED;
+}
+
+void jz4740_rtc_poweroff(struct device *dev)
+{
+ struct jz4740_rtc *rtc = dev_get_drvdata(dev);
+ jz4740_rtc_reg_write(rtc, JZ_REG_RTC_HIBERNATE, 1);
+}
+EXPORT_SYMBOL_GPL(jz4740_rtc_poweroff);
+
+static int __devinit jz4740_rtc_probe(struct platform_device *pdev)
+{
+ int ret;
+ struct jz4740_rtc *rtc;
+ uint32_t scratchpad;
+
+ rtc = kzalloc(sizeof(*rtc), GFP_KERNEL);
+ if (!rtc)
+ return -ENOMEM;
+
+ rtc->irq = platform_get_irq(pdev, 0);
+ if (rtc->irq < 0) {
+ ret = -ENOENT;
+ dev_err(&pdev->dev, "Failed to get platform irq\n");
+ goto err_free;
+ }
+
+ rtc->mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!rtc->mem) {
+ ret = -ENOENT;
+ dev_err(&pdev->dev, "Failed to get platform mmio memory\n");
+ goto err_free;
+ }
+
+ rtc->mem = request_mem_region(rtc->mem->start, resource_size(rtc->mem),
+ pdev->name);
+ if (!rtc->mem) {
+ ret = -EBUSY;
+ dev_err(&pdev->dev, "Failed to request mmio memory region\n");
+ goto err_free;
+ }
+
+ rtc->base = ioremap_nocache(rtc->mem->start, resource_size(rtc->mem));
+ if (!rtc->base) {
+ ret = -EBUSY;
+ dev_err(&pdev->dev, "Failed to ioremap mmio memory\n");
+ goto err_release_mem_region;
+ }
+
+ spin_lock_init(&rtc->lock);
+
+ platform_set_drvdata(pdev, rtc);
+
+ rtc->rtc = rtc_device_register(pdev->name, &pdev->dev, &jz4740_rtc_ops,
+ THIS_MODULE);
+ if (IS_ERR(rtc->rtc)) {
+ ret = PTR_ERR(rtc->rtc);
+ dev_err(&pdev->dev, "Failed to register rtc device: %d\n", ret);
+ goto err_iounmap;
+ }
+
+ ret = request_irq(rtc->irq, jz4740_rtc_irq, 0,
+ pdev->name, rtc);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to request rtc irq: %d\n", ret);
+ goto err_unregister_rtc;
+ }
+
+ scratchpad = jz4740_rtc_reg_read(rtc, JZ_REG_RTC_SCRATCHPAD);
+ if (scratchpad != 0x12345678) {
+ ret = jz4740_rtc_reg_write(rtc, JZ_REG_RTC_SCRATCHPAD, 0x12345678);
+ ret = jz4740_rtc_reg_write(rtc, JZ_REG_RTC_SEC, 0);
+ if (ret) {
+ dev_err(&pdev->dev, "Could not write write to RTC registers\n");
+ goto err_free_irq;
+ }
+ }
+
+ return 0;
+
+err_free_irq:
+ free_irq(rtc->irq, rtc);
+err_unregister_rtc:
+ rtc_device_unregister(rtc->rtc);
+err_iounmap:
+ platform_set_drvdata(pdev, NULL);
+ iounmap(rtc->base);
+err_release_mem_region:
+ release_mem_region(rtc->mem->start, resource_size(rtc->mem));
+err_free:
+ kfree(rtc);
+
+ return ret;
+}
+
+static int __devexit jz4740_rtc_remove(struct platform_device *pdev)
+{
+ struct jz4740_rtc *rtc = platform_get_drvdata(pdev);
+
+ free_irq(rtc->irq, rtc);
+
+ rtc_device_unregister(rtc->rtc);
+
+ iounmap(rtc->base);
+ release_mem_region(rtc->mem->start, resource_size(rtc->mem));
+
+ kfree(rtc);
+
+ platform_set_drvdata(pdev, NULL);
+
+ return 0;
+}
+
+struct platform_driver jz4740_rtc_driver = {
+ .probe = jz4740_rtc_probe,
+ .remove = __devexit_p(jz4740_rtc_remove),
+ .driver = {
+ .name = "jz4740-rtc",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init jz4740_rtc_init(void)
+{
+ return platform_driver_register(&jz4740_rtc_driver);
+}
+module_init(jz4740_rtc_init);
+
+static void __exit jz4740_rtc_exit(void)
+{
+ platform_driver_unregister(&jz4740_rtc_driver);
+}
+module_exit(jz4740_rtc_exit);
+
+MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("RTC driver for the JZ4740 SoC\n");
+MODULE_ALIAS("platform:jz4740-rtc");
diff --git a/drivers/rtc/rtc-rx8025.c b/drivers/rtc/rtc-rx8025.c
index 789f62f9b47..1146e3522d3 100644
--- a/drivers/rtc/rtc-rx8025.c
+++ b/drivers/rtc/rtc-rx8025.c
@@ -461,7 +461,7 @@ static struct rtc_class_ops rx8025_rtc_ops = {
* Clock precision adjustment support
*
* According to the RX8025 SA/NB application manual the frequency and
- * temperature charateristics can be approximated using the following
+ * temperature characteristics can be approximated using the following
* equation:
*
* df = a * (ut - t)**2
diff --git a/drivers/s390/cio/qdio_setup.c b/drivers/s390/cio/qdio_setup.c
index 6326b67c45d..34c7e4046df 100644
--- a/drivers/s390/cio/qdio_setup.c
+++ b/drivers/s390/cio/qdio_setup.c
@@ -368,6 +368,8 @@ static void setup_qib(struct qdio_irq *irq_ptr,
if (qebsm_possible())
irq_ptr->qib.rflags |= QIB_RFLAGS_ENABLE_QEBSM;
+ irq_ptr->qib.rflags |= init_data->qib_rflags;
+
irq_ptr->qib.qfmt = init_data->q_format;
if (init_data->no_input_qs)
irq_ptr->qib.isliba =
diff --git a/drivers/s390/net/claw.c b/drivers/s390/net/claw.c
index 147bb1a69ab..a75ed3083a6 100644
--- a/drivers/s390/net/claw.c
+++ b/drivers/s390/net/claw.c
@@ -295,7 +295,7 @@ claw_driver_group_store(struct device_driver *ddrv, const char *buf,
int err;
err = ccwgroup_create_from_string(claw_root_dev,
claw_group_driver.driver_id,
- &claw_ccw_driver, 3, buf);
+ &claw_ccw_driver, 2, buf);
return err ? err : count;
}
diff --git a/drivers/s390/net/qeth_core.h b/drivers/s390/net/qeth_core.h
index 7a44c38aaf6..d1257768be9 100644
--- a/drivers/s390/net/qeth_core.h
+++ b/drivers/s390/net/qeth_core.h
@@ -40,11 +40,7 @@
*/
enum qeth_dbf_names {
QETH_DBF_SETUP,
- QETH_DBF_QERR,
- QETH_DBF_TRACE,
QETH_DBF_MSG,
- QETH_DBF_SENSE,
- QETH_DBF_MISC,
QETH_DBF_CTRL,
QETH_DBF_INFOS /* must be last element */
};
@@ -71,7 +67,19 @@ struct qeth_dbf_info {
debug_sprintf_event(qeth_dbf[QETH_DBF_MSG].id, level, text)
#define QETH_DBF_TEXT_(name, level, text...) \
- qeth_dbf_longtext(QETH_DBF_##name, level, text)
+ qeth_dbf_longtext(qeth_dbf[QETH_DBF_##name].id, level, text)
+
+#define QETH_CARD_TEXT(card, level, text) \
+ debug_text_event(card->debug, level, text)
+
+#define QETH_CARD_HEX(card, level, addr, len) \
+ debug_event(card->debug, level, (void *)(addr), len)
+
+#define QETH_CARD_MESSAGE(card, text...) \
+ debug_sprintf_event(card->debug, level, text)
+
+#define QETH_CARD_TEXT_(card, level, text...) \
+ qeth_dbf_longtext(card->debug, level, text)
#define SENSE_COMMAND_REJECT_BYTE 0
#define SENSE_COMMAND_REJECT_FLAG 0x80
@@ -180,8 +188,7 @@ static inline int qeth_is_ipa_enabled(struct qeth_ipa_info *ipa,
qeth_is_enabled6(c, f) : qeth_is_enabled(c, f))
#define QETH_IDX_FUNC_LEVEL_OSD 0x0101
-#define QETH_IDX_FUNC_LEVEL_IQD_ENA_IPAT 0x4108
-#define QETH_IDX_FUNC_LEVEL_IQD_DIS_IPAT 0x5108
+#define QETH_IDX_FUNC_LEVEL_IQD 0x4108
#define QETH_MODELLIST_ARRAY \
{{0x1731, 0x01, 0x1732, QETH_CARD_TYPE_OSD, QETH_MAX_QUEUES, 0}, \
@@ -733,12 +740,15 @@ struct qeth_card {
struct qeth_qdio_info qdio;
struct qeth_perf_stats perf_stats;
int use_hard_stop;
+ int read_or_write_problem;
struct qeth_osn_info osn_info;
struct qeth_discipline discipline;
atomic_t force_alloc_skb;
struct service_level qeth_service_level;
struct qdio_ssqd_desc ssqd;
+ debug_info_t *debug;
struct mutex conf_mutex;
+ struct mutex discipline_mutex;
};
struct qeth_card_list_struct {
@@ -857,9 +867,10 @@ void qeth_core_get_ethtool_stats(struct net_device *,
struct ethtool_stats *, u64 *);
void qeth_core_get_strings(struct net_device *, u32, u8 *);
void qeth_core_get_drvinfo(struct net_device *, struct ethtool_drvinfo *);
-void qeth_dbf_longtext(enum qeth_dbf_names dbf_nix, int level, char *text, ...);
+void qeth_dbf_longtext(debug_info_t *id, int level, char *text, ...);
int qeth_core_ethtool_get_settings(struct net_device *, struct ethtool_cmd *);
int qeth_set_access_ctrl_online(struct qeth_card *card);
+int qeth_hdr_chk_and_bounce(struct sk_buff *, int);
/* exports for OSN */
int qeth_osn_assist(struct net_device *, void *, int);
diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c
index 13ef46b9d38..3a5a18a0fc2 100644
--- a/drivers/s390/net/qeth_core_main.c
+++ b/drivers/s390/net/qeth_core_main.c
@@ -32,16 +32,8 @@ struct qeth_dbf_info qeth_dbf[QETH_DBF_INFOS] = {
/* N P A M L V H */
[QETH_DBF_SETUP] = {"qeth_setup",
8, 1, 8, 5, &debug_hex_ascii_view, NULL},
- [QETH_DBF_QERR] = {"qeth_qerr",
- 2, 1, 8, 2, &debug_hex_ascii_view, NULL},
- [QETH_DBF_TRACE] = {"qeth_trace",
- 4, 1, 8, 3, &debug_hex_ascii_view, NULL},
[QETH_DBF_MSG] = {"qeth_msg",
8, 1, 128, 3, &debug_sprintf_view, NULL},
- [QETH_DBF_SENSE] = {"qeth_sense",
- 2, 1, 64, 2, &debug_hex_ascii_view, NULL},
- [QETH_DBF_MISC] = {"qeth_misc",
- 2, 1, 256, 2, &debug_hex_ascii_view, NULL},
[QETH_DBF_CTRL] = {"qeth_control",
8, 1, QETH_DBF_CTRL_LEN, 5, &debug_hex_ascii_view, NULL},
};
@@ -65,48 +57,6 @@ static void qeth_free_buffer_pool(struct qeth_card *);
static int qeth_qdio_establish(struct qeth_card *);
-static inline void __qeth_fill_buffer_frag(struct sk_buff *skb,
- struct qdio_buffer *buffer, int is_tso,
- int *next_element_to_fill)
-{
- struct skb_frag_struct *frag;
- int fragno;
- unsigned long addr;
- int element, cnt, dlen;
-
- fragno = skb_shinfo(skb)->nr_frags;
- element = *next_element_to_fill;
- dlen = 0;
-
- if (is_tso)
- buffer->element[element].flags =
- SBAL_FLAGS_MIDDLE_FRAG;
- else
- buffer->element[element].flags =
- SBAL_FLAGS_FIRST_FRAG;
- dlen = skb->len - skb->data_len;
- if (dlen) {
- buffer->element[element].addr = skb->data;
- buffer->element[element].length = dlen;
- element++;
- }
- for (cnt = 0; cnt < fragno; cnt++) {
- frag = &skb_shinfo(skb)->frags[cnt];
- addr = (page_to_pfn(frag->page) << PAGE_SHIFT) +
- frag->page_offset;
- buffer->element[element].addr = (char *)addr;
- buffer->element[element].length = frag->size;
- if (cnt < (fragno - 1))
- buffer->element[element].flags =
- SBAL_FLAGS_MIDDLE_FRAG;
- else
- buffer->element[element].flags =
- SBAL_FLAGS_LAST_FRAG;
- element++;
- }
- *next_element_to_fill = element;
-}
-
static inline const char *qeth_get_cardname(struct qeth_card *card)
{
if (card->info.guestlan) {
@@ -232,7 +182,7 @@ void qeth_clear_working_pool_list(struct qeth_card *card)
{
struct qeth_buffer_pool_entry *pool_entry, *tmp;
- QETH_DBF_TEXT(TRACE, 5, "clwrklst");
+ QETH_CARD_TEXT(card, 5, "clwrklst");
list_for_each_entry_safe(pool_entry, tmp,
&card->qdio.in_buf_pool.entry_list, list){
list_del(&pool_entry->list);
@@ -246,7 +196,7 @@ static int qeth_alloc_buffer_pool(struct qeth_card *card)
void *ptr;
int i, j;
- QETH_DBF_TEXT(TRACE, 5, "alocpool");
+ QETH_CARD_TEXT(card, 5, "alocpool");
for (i = 0; i < card->qdio.init_pool.buf_count; ++i) {
pool_entry = kmalloc(sizeof(*pool_entry), GFP_KERNEL);
if (!pool_entry) {
@@ -273,7 +223,7 @@ static int qeth_alloc_buffer_pool(struct qeth_card *card)
int qeth_realloc_buffer_pool(struct qeth_card *card, int bufcnt)
{
- QETH_DBF_TEXT(TRACE, 2, "realcbp");
+ QETH_CARD_TEXT(card, 2, "realcbp");
if ((card->state != CARD_STATE_DOWN) &&
(card->state != CARD_STATE_RECOVER))
@@ -293,7 +243,7 @@ static int qeth_issue_next_read(struct qeth_card *card)
int rc;
struct qeth_cmd_buffer *iob;
- QETH_DBF_TEXT(TRACE, 5, "issnxrd");
+ QETH_CARD_TEXT(card, 5, "issnxrd");
if (card->read.state != CH_STATE_UP)
return -EIO;
iob = qeth_get_buffer(&card->read);
@@ -305,13 +255,14 @@ static int qeth_issue_next_read(struct qeth_card *card)
return -ENOMEM;
}
qeth_setup_ccw(&card->read, iob->data, QETH_BUFSIZE);
- QETH_DBF_TEXT(TRACE, 6, "noirqpnd");
+ QETH_CARD_TEXT(card, 6, "noirqpnd");
rc = ccw_device_start(card->read.ccwdev, &card->read.ccw,
(addr_t) iob, 0, 0);
if (rc) {
QETH_DBF_MESSAGE(2, "%s error in starting next read ccw! "
"rc=%i\n", dev_name(&card->gdev->dev), rc);
atomic_set(&card->read.irq_pending, 0);
+ card->read_or_write_problem = 1;
qeth_schedule_recovery(card);
wake_up(&card->wait_q);
}
@@ -364,7 +315,7 @@ static struct qeth_ipa_cmd *qeth_check_ipa_data(struct qeth_card *card,
{
struct qeth_ipa_cmd *cmd = NULL;
- QETH_DBF_TEXT(TRACE, 5, "chkipad");
+ QETH_CARD_TEXT(card, 5, "chkipad");
if (IS_IPA(iob->data)) {
cmd = (struct qeth_ipa_cmd *) PDU_ENCAPSULATION(iob->data);
if (IS_IPA_REPLY(cmd)) {
@@ -400,10 +351,10 @@ static struct qeth_ipa_cmd *qeth_check_ipa_data(struct qeth_card *card,
case IPA_CMD_MODCCID:
return cmd;
case IPA_CMD_REGISTER_LOCAL_ADDR:
- QETH_DBF_TEXT(TRACE, 3, "irla");
+ QETH_CARD_TEXT(card, 3, "irla");
break;
case IPA_CMD_UNREGISTER_LOCAL_ADDR:
- QETH_DBF_TEXT(TRACE, 3, "urla");
+ QETH_CARD_TEXT(card, 3, "urla");
break;
default:
QETH_DBF_MESSAGE(2, "Received data is IPA "
@@ -420,7 +371,7 @@ void qeth_clear_ipacmd_list(struct qeth_card *card)
struct qeth_reply *reply, *r;
unsigned long flags;
- QETH_DBF_TEXT(TRACE, 4, "clipalst");
+ QETH_CARD_TEXT(card, 4, "clipalst");
spin_lock_irqsave(&card->lock, flags);
list_for_each_entry_safe(reply, r, &card->cmd_waiter_list, list) {
@@ -432,6 +383,7 @@ void qeth_clear_ipacmd_list(struct qeth_card *card)
qeth_put_reply(reply);
}
spin_unlock_irqrestore(&card->lock, flags);
+ atomic_set(&card->write.irq_pending, 0);
}
EXPORT_SYMBOL_GPL(qeth_clear_ipacmd_list);
@@ -448,9 +400,9 @@ static int qeth_check_idx_response(struct qeth_card *card,
buffer[4],
((buffer[4] == 0x22) ?
" -- try another portname" : ""));
- QETH_DBF_TEXT(TRACE, 2, "ckidxres");
- QETH_DBF_TEXT(TRACE, 2, " idxterm");
- QETH_DBF_TEXT_(TRACE, 2, " rc%d", -EIO);
+ QETH_CARD_TEXT(card, 2, "ckidxres");
+ QETH_CARD_TEXT(card, 2, " idxterm");
+ QETH_CARD_TEXT_(card, 2, " rc%d", -EIO);
if (buffer[4] == 0xf6) {
dev_err(&card->gdev->dev,
"The qeth device is not configured "
@@ -467,8 +419,8 @@ static void qeth_setup_ccw(struct qeth_channel *channel, unsigned char *iob,
{
struct qeth_card *card;
- QETH_DBF_TEXT(TRACE, 4, "setupccw");
card = CARD_FROM_CDEV(channel->ccwdev);
+ QETH_CARD_TEXT(card, 4, "setupccw");
if (channel == &card->read)
memcpy(&channel->ccw, READ_CCW, sizeof(struct ccw1));
else
@@ -481,7 +433,7 @@ static struct qeth_cmd_buffer *__qeth_get_buffer(struct qeth_channel *channel)
{
__u8 index;
- QETH_DBF_TEXT(TRACE, 6, "getbuff");
+ QETH_CARD_TEXT(CARD_FROM_CDEV(channel->ccwdev), 6, "getbuff");
index = channel->io_buf_no;
do {
if (channel->iob[index].state == BUF_STATE_FREE) {
@@ -502,7 +454,7 @@ void qeth_release_buffer(struct qeth_channel *channel,
{
unsigned long flags;
- QETH_DBF_TEXT(TRACE, 6, "relbuff");
+ QETH_CARD_TEXT(CARD_FROM_CDEV(channel->ccwdev), 6, "relbuff");
spin_lock_irqsave(&channel->iob_lock, flags);
memset(iob->data, 0, QETH_BUFSIZE);
iob->state = BUF_STATE_FREE;
@@ -553,9 +505,8 @@ static void qeth_send_control_data_cb(struct qeth_channel *channel,
int keep_reply;
int rc = 0;
- QETH_DBF_TEXT(TRACE, 4, "sndctlcb");
-
card = CARD_FROM_CDEV(channel->ccwdev);
+ QETH_CARD_TEXT(card, 4, "sndctlcb");
rc = qeth_check_idx_response(card, iob->data);
switch (rc) {
case 0:
@@ -563,6 +514,7 @@ static void qeth_send_control_data_cb(struct qeth_channel *channel,
case -EIO:
qeth_clear_ipacmd_list(card);
qeth_schedule_recovery(card);
+ /* fall through */
default:
goto out;
}
@@ -722,7 +674,7 @@ EXPORT_SYMBOL_GPL(qeth_do_run_thread);
void qeth_schedule_recovery(struct qeth_card *card)
{
- QETH_DBF_TEXT(TRACE, 2, "startrec");
+ QETH_CARD_TEXT(card, 2, "startrec");
if (qeth_set_thread_start_bit(card, QETH_RECOVER_THREAD) == 0)
schedule_work(&card->kernel_thread_starter);
}
@@ -732,15 +684,17 @@ static int qeth_get_problem(struct ccw_device *cdev, struct irb *irb)
{
int dstat, cstat;
char *sense;
+ struct qeth_card *card;
sense = (char *) irb->ecw;
cstat = irb->scsw.cmd.cstat;
dstat = irb->scsw.cmd.dstat;
+ card = CARD_FROM_CDEV(cdev);
if (cstat & (SCHN_STAT_CHN_CTRL_CHK | SCHN_STAT_INTF_CTRL_CHK |
SCHN_STAT_CHN_DATA_CHK | SCHN_STAT_CHAIN_CHECK |
SCHN_STAT_PROT_CHECK | SCHN_STAT_PROG_CHECK)) {
- QETH_DBF_TEXT(TRACE, 2, "CGENCHK");
+ QETH_CARD_TEXT(card, 2, "CGENCHK");
dev_warn(&cdev->dev, "The qeth device driver "
"failed to recover an error on the device\n");
QETH_DBF_MESSAGE(2, "%s check on device dstat=x%x, cstat=x%x\n",
@@ -753,23 +707,23 @@ static int qeth_get_problem(struct ccw_device *cdev, struct irb *irb)
if (dstat & DEV_STAT_UNIT_CHECK) {
if (sense[SENSE_RESETTING_EVENT_BYTE] &
SENSE_RESETTING_EVENT_FLAG) {
- QETH_DBF_TEXT(TRACE, 2, "REVIND");
+ QETH_CARD_TEXT(card, 2, "REVIND");
return 1;
}
if (sense[SENSE_COMMAND_REJECT_BYTE] &
SENSE_COMMAND_REJECT_FLAG) {
- QETH_DBF_TEXT(TRACE, 2, "CMDREJi");
+ QETH_CARD_TEXT(card, 2, "CMDREJi");
return 1;
}
if ((sense[2] == 0xaf) && (sense[3] == 0xfe)) {
- QETH_DBF_TEXT(TRACE, 2, "AFFE");
+ QETH_CARD_TEXT(card, 2, "AFFE");
return 1;
}
if ((!sense[0]) && (!sense[1]) && (!sense[2]) && (!sense[3])) {
- QETH_DBF_TEXT(TRACE, 2, "ZEROSEN");
+ QETH_CARD_TEXT(card, 2, "ZEROSEN");
return 0;
}
- QETH_DBF_TEXT(TRACE, 2, "DGENCHK");
+ QETH_CARD_TEXT(card, 2, "DGENCHK");
return 1;
}
return 0;
@@ -778,6 +732,10 @@ static int qeth_get_problem(struct ccw_device *cdev, struct irb *irb)
static long __qeth_check_irb_error(struct ccw_device *cdev,
unsigned long intparm, struct irb *irb)
{
+ struct qeth_card *card;
+
+ card = CARD_FROM_CDEV(cdev);
+
if (!IS_ERR(irb))
return 0;
@@ -785,17 +743,15 @@ static long __qeth_check_irb_error(struct ccw_device *cdev,
case -EIO:
QETH_DBF_MESSAGE(2, "%s i/o-error on device\n",
dev_name(&cdev->dev));
- QETH_DBF_TEXT(TRACE, 2, "ckirberr");
- QETH_DBF_TEXT_(TRACE, 2, " rc%d", -EIO);
+ QETH_CARD_TEXT(card, 2, "ckirberr");
+ QETH_CARD_TEXT_(card, 2, " rc%d", -EIO);
break;
case -ETIMEDOUT:
dev_warn(&cdev->dev, "A hardware operation timed out"
" on the device\n");
- QETH_DBF_TEXT(TRACE, 2, "ckirberr");
- QETH_DBF_TEXT_(TRACE, 2, " rc%d", -ETIMEDOUT);
+ QETH_CARD_TEXT(card, 2, "ckirberr");
+ QETH_CARD_TEXT_(card, 2, " rc%d", -ETIMEDOUT);
if (intparm == QETH_RCD_PARM) {
- struct qeth_card *card = CARD_FROM_CDEV(cdev);
-
if (card && (card->data.ccwdev == cdev)) {
card->data.state = CH_STATE_DOWN;
wake_up(&card->wait_q);
@@ -805,8 +761,8 @@ static long __qeth_check_irb_error(struct ccw_device *cdev,
default:
QETH_DBF_MESSAGE(2, "%s unknown error %ld on device\n",
dev_name(&cdev->dev), PTR_ERR(irb));
- QETH_DBF_TEXT(TRACE, 2, "ckirberr");
- QETH_DBF_TEXT(TRACE, 2, " rc???");
+ QETH_CARD_TEXT(card, 2, "ckirberr");
+ QETH_CARD_TEXT(card, 2, " rc???");
}
return PTR_ERR(irb);
}
@@ -822,8 +778,6 @@ static void qeth_irq(struct ccw_device *cdev, unsigned long intparm,
struct qeth_cmd_buffer *iob;
__u8 index;
- QETH_DBF_TEXT(TRACE, 5, "irq");
-
if (__qeth_check_irb_error(cdev, intparm, irb))
return;
cstat = irb->scsw.cmd.cstat;
@@ -833,15 +787,17 @@ static void qeth_irq(struct ccw_device *cdev, unsigned long intparm,
if (!card)
return;
+ QETH_CARD_TEXT(card, 5, "irq");
+
if (card->read.ccwdev == cdev) {
channel = &card->read;
- QETH_DBF_TEXT(TRACE, 5, "read");
+ QETH_CARD_TEXT(card, 5, "read");
} else if (card->write.ccwdev == cdev) {
channel = &card->write;
- QETH_DBF_TEXT(TRACE, 5, "write");
+ QETH_CARD_TEXT(card, 5, "write");
} else {
channel = &card->data;
- QETH_DBF_TEXT(TRACE, 5, "data");
+ QETH_CARD_TEXT(card, 5, "data");
}
atomic_set(&channel->irq_pending, 0);
@@ -857,12 +813,12 @@ static void qeth_irq(struct ccw_device *cdev, unsigned long intparm,
goto out;
if (intparm == QETH_CLEAR_CHANNEL_PARM) {
- QETH_DBF_TEXT(TRACE, 6, "clrchpar");
+ QETH_CARD_TEXT(card, 6, "clrchpar");
/* we don't have to handle this further */
intparm = 0;
}
if (intparm == QETH_HALT_CHANNEL_PARM) {
- QETH_DBF_TEXT(TRACE, 6, "hltchpar");
+ QETH_CARD_TEXT(card, 6, "hltchpar");
/* we don't have to handle this further */
intparm = 0;
}
@@ -963,7 +919,7 @@ void qeth_clear_qdio_buffers(struct qeth_card *card)
{
int i, j;
- QETH_DBF_TEXT(TRACE, 2, "clearqdbf");
+ QETH_CARD_TEXT(card, 2, "clearqdbf");
/* clear outbound buffers to free skbs */
for (i = 0; i < card->qdio.no_out_queues; ++i)
if (card->qdio.out_qs[i]) {
@@ -978,7 +934,6 @@ static void qeth_free_buffer_pool(struct qeth_card *card)
{
struct qeth_buffer_pool_entry *pool_entry, *tmp;
int i = 0;
- QETH_DBF_TEXT(TRACE, 5, "freepool");
list_for_each_entry_safe(pool_entry, tmp,
&card->qdio.init_pool.entry_list, init_list){
for (i = 0; i < QETH_MAX_BUFFER_ELEMENTS(card); ++i)
@@ -992,7 +947,6 @@ static void qeth_free_qdio_buffers(struct qeth_card *card)
{
int i, j;
- QETH_DBF_TEXT(TRACE, 2, "freeqdbf");
if (atomic_xchg(&card->qdio.state, QETH_QDIO_UNINITIALIZED) ==
QETH_QDIO_UNINITIALIZED)
return;
@@ -1089,7 +1043,7 @@ static int qeth_do_start_thread(struct qeth_card *card, unsigned long thread)
int rc = 0;
spin_lock_irqsave(&card->thread_mask_lock, flags);
- QETH_DBF_TEXT_(TRACE, 4, " %02x%02x%02x",
+ QETH_CARD_TEXT_(card, 4, " %02x%02x%02x",
(u8) card->thread_start_mask,
(u8) card->thread_allowed_mask,
(u8) card->thread_running_mask);
@@ -1102,7 +1056,7 @@ static void qeth_start_kernel_thread(struct work_struct *work)
{
struct qeth_card *card = container_of(work, struct qeth_card,
kernel_thread_starter);
- QETH_DBF_TEXT(TRACE , 2, "strthrd");
+ QETH_CARD_TEXT(card , 2, "strthrd");
if (card->read.state != CH_STATE_UP &&
card->write.state != CH_STATE_UP)
@@ -1124,6 +1078,7 @@ static int qeth_setup_card(struct qeth_card *card)
card->state = CARD_STATE_DOWN;
card->lan_online = 0;
card->use_hard_stop = 0;
+ card->read_or_write_problem = 0;
card->dev = NULL;
spin_lock_init(&card->vlanlock);
spin_lock_init(&card->mclock);
@@ -1132,6 +1087,7 @@ static int qeth_setup_card(struct qeth_card *card)
spin_lock_init(&card->ip_lock);
spin_lock_init(&card->thread_mask_lock);
mutex_init(&card->conf_mutex);
+ mutex_init(&card->discipline_mutex);
card->thread_start_mask = 0;
card->thread_allowed_mask = 0;
card->thread_running_mask = 0;
@@ -1229,8 +1185,8 @@ static int qeth_clear_channel(struct qeth_channel *channel)
struct qeth_card *card;
int rc;
- QETH_DBF_TEXT(TRACE, 3, "clearch");
card = CARD_FROM_CDEV(channel->ccwdev);
+ QETH_CARD_TEXT(card, 3, "clearch");
spin_lock_irqsave(get_ccwdev_lock(channel->ccwdev), flags);
rc = ccw_device_clear(channel->ccwdev, QETH_CLEAR_CHANNEL_PARM);
spin_unlock_irqrestore(get_ccwdev_lock(channel->ccwdev), flags);
@@ -1253,8 +1209,8 @@ static int qeth_halt_channel(struct qeth_channel *channel)
struct qeth_card *card;
int rc;
- QETH_DBF_TEXT(TRACE, 3, "haltch");
card = CARD_FROM_CDEV(channel->ccwdev);
+ QETH_CARD_TEXT(card, 3, "haltch");
spin_lock_irqsave(get_ccwdev_lock(channel->ccwdev), flags);
rc = ccw_device_halt(channel->ccwdev, QETH_HALT_CHANNEL_PARM);
spin_unlock_irqrestore(get_ccwdev_lock(channel->ccwdev), flags);
@@ -1274,7 +1230,7 @@ static int qeth_halt_channels(struct qeth_card *card)
{
int rc1 = 0, rc2 = 0, rc3 = 0;
- QETH_DBF_TEXT(TRACE, 3, "haltchs");
+ QETH_CARD_TEXT(card, 3, "haltchs");
rc1 = qeth_halt_channel(&card->read);
rc2 = qeth_halt_channel(&card->write);
rc3 = qeth_halt_channel(&card->data);
@@ -1289,7 +1245,7 @@ static int qeth_clear_channels(struct qeth_card *card)
{
int rc1 = 0, rc2 = 0, rc3 = 0;
- QETH_DBF_TEXT(TRACE, 3, "clearchs");
+ QETH_CARD_TEXT(card, 3, "clearchs");
rc1 = qeth_clear_channel(&card->read);
rc2 = qeth_clear_channel(&card->write);
rc3 = qeth_clear_channel(&card->data);
@@ -1304,8 +1260,7 @@ static int qeth_clear_halt_card(struct qeth_card *card, int halt)
{
int rc = 0;
- QETH_DBF_TEXT(TRACE, 3, "clhacrd");
- QETH_DBF_HEX(TRACE, 3, &card, sizeof(void *));
+ QETH_CARD_TEXT(card, 3, "clhacrd");
if (halt)
rc = qeth_halt_channels(card);
@@ -1318,7 +1273,7 @@ int qeth_qdio_clear_card(struct qeth_card *card, int use_halt)
{
int rc = 0;
- QETH_DBF_TEXT(TRACE, 3, "qdioclr");
+ QETH_CARD_TEXT(card, 3, "qdioclr");
switch (atomic_cmpxchg(&card->qdio.state, QETH_QDIO_ESTABLISHED,
QETH_QDIO_CLEANING)) {
case QETH_QDIO_ESTABLISHED:
@@ -1329,7 +1284,7 @@ int qeth_qdio_clear_card(struct qeth_card *card, int use_halt)
rc = qdio_shutdown(CARD_DDEV(card),
QDIO_FLAG_CLEANUP_USING_CLEAR);
if (rc)
- QETH_DBF_TEXT_(TRACE, 3, "1err%d", rc);
+ QETH_CARD_TEXT_(card, 3, "1err%d", rc);
qdio_free(CARD_DDEV(card));
atomic_set(&card->qdio.state, QETH_QDIO_ALLOCATED);
break;
@@ -1340,7 +1295,7 @@ int qeth_qdio_clear_card(struct qeth_card *card, int use_halt)
}
rc = qeth_clear_halt_card(card, use_halt);
if (rc)
- QETH_DBF_TEXT_(TRACE, 3, "2err%d", rc);
+ QETH_CARD_TEXT_(card, 3, "2err%d", rc);
card->state = CARD_STATE_DOWN;
return rc;
}
@@ -1432,14 +1387,10 @@ static void qeth_init_func_level(struct qeth_card *card)
{
switch (card->info.type) {
case QETH_CARD_TYPE_IQD:
- if (card->ipato.enabled)
- card->info.func_level =
- QETH_IDX_FUNC_LEVEL_IQD_ENA_IPAT;
- else
- card->info.func_level =
- QETH_IDX_FUNC_LEVEL_IQD_DIS_IPAT;
+ card->info.func_level = QETH_IDX_FUNC_LEVEL_IQD;
break;
case QETH_CARD_TYPE_OSD:
+ case QETH_CARD_TYPE_OSN:
card->info.func_level = QETH_IDX_FUNC_LEVEL_OSD;
break;
default:
@@ -1637,15 +1588,18 @@ static void qeth_idx_read_cb(struct qeth_channel *channel,
"host\n");
break;
case QETH_IDX_ACT_ERR_AUTH:
+ case QETH_IDX_ACT_ERR_AUTH_USER:
dev_err(&card->read.ccwdev->dev,
"Setting the device online failed because of "
- "insufficient LPAR authorization\n");
+ "insufficient authorization\n");
break;
default:
QETH_DBF_MESSAGE(2, "%s IDX_ACTIVATE on read channel:"
" negative reply\n",
dev_name(&card->read.ccwdev->dev));
}
+ QETH_CARD_TEXT_(card, 2, "idxread%c",
+ QETH_IDX_ACT_CAUSE_CODE(iob->data));
goto out;
}
@@ -1705,8 +1659,12 @@ int qeth_send_control_data(struct qeth_card *card, int len,
unsigned long timeout, event_timeout;
struct qeth_ipa_cmd *cmd;
- QETH_DBF_TEXT(TRACE, 2, "sendctl");
+ QETH_CARD_TEXT(card, 2, "sendctl");
+ if (card->read_or_write_problem) {
+ qeth_release_buffer(iob->channel, iob);
+ return -EIO;
+ }
reply = qeth_alloc_reply(card);
if (!reply) {
return -ENOMEM;
@@ -1732,7 +1690,7 @@ int qeth_send_control_data(struct qeth_card *card, int len,
event_timeout = QETH_TIMEOUT;
timeout = jiffies + event_timeout;
- QETH_DBF_TEXT(TRACE, 6, "noirqpnd");
+ QETH_CARD_TEXT(card, 6, "noirqpnd");
spin_lock_irqsave(get_ccwdev_lock(card->write.ccwdev), flags);
rc = ccw_device_start(card->write.ccwdev, &card->write.ccw,
(addr_t) iob, 0, 0);
@@ -1741,7 +1699,7 @@ int qeth_send_control_data(struct qeth_card *card, int len,
QETH_DBF_MESSAGE(2, "%s qeth_send_control_data: "
"ccw_device_start rc = %i\n",
dev_name(&card->write.ccwdev->dev), rc);
- QETH_DBF_TEXT_(TRACE, 2, " err%d", rc);
+ QETH_CARD_TEXT_(card, 2, " err%d", rc);
spin_lock_irqsave(&card->lock, flags);
list_del_init(&reply->list);
qeth_put_reply(reply);
@@ -1778,6 +1736,9 @@ time_err:
spin_unlock_irqrestore(&reply->card->lock, flags);
reply->rc = -ETIME;
atomic_inc(&reply->received);
+ atomic_set(&card->write.irq_pending, 0);
+ qeth_release_buffer(iob->channel, iob);
+ card->write.buf_no = (card->write.buf_no + 1) % QETH_CMD_BUFFER_NO;
wake_up(&reply->wait_q);
rc = reply->rc;
qeth_put_reply(reply);
@@ -1978,7 +1939,7 @@ static int qeth_ulp_enable_cb(struct qeth_card *card, struct qeth_reply *reply,
card->info.link_type = link_type;
} else
card->info.link_type = 0;
- QETH_DBF_TEXT_(SETUP, 2, "link%d", link_type);
+ QETH_DBF_TEXT_(SETUP, 2, "link%d", card->info.link_type);
QETH_DBF_TEXT_(SETUP, 2, " rc%d", iob->rc);
return 0;
}
@@ -2035,7 +1996,7 @@ static int qeth_ulp_setup_cb(struct qeth_card *card, struct qeth_reply *reply,
QETH_DBF_TEXT(SETUP, 2, "olmlimit");
dev_err(&card->gdev->dev, "A connection could not be "
"established because of an OLM limit\n");
- rc = -EMLINK;
+ iob->rc = -EMLINK;
}
QETH_DBF_TEXT_(SETUP, 2, " rc%d", iob->rc);
return rc;
@@ -2335,7 +2296,7 @@ static void qeth_initialize_working_pool_list(struct qeth_card *card)
{
struct qeth_buffer_pool_entry *entry;
- QETH_DBF_TEXT(TRACE, 5, "inwrklst");
+ QETH_CARD_TEXT(card, 5, "inwrklst");
list_for_each_entry(entry,
&card->qdio.init_pool.entry_list, init_list) {
@@ -2522,7 +2483,7 @@ int qeth_send_ipa_cmd(struct qeth_card *card, struct qeth_cmd_buffer *iob,
int rc;
char prot_type;
- QETH_DBF_TEXT(TRACE, 4, "sendipa");
+ QETH_CARD_TEXT(card, 4, "sendipa");
if (card->options.layer2)
if (card->info.type == QETH_CARD_TYPE_OSN)
@@ -2534,6 +2495,10 @@ int qeth_send_ipa_cmd(struct qeth_card *card, struct qeth_cmd_buffer *iob,
qeth_prepare_ipa_cmd(card, iob, prot_type);
rc = qeth_send_control_data(card, IPA_CMD_LENGTH,
iob, reply_cb, reply_param);
+ if (rc == -ETIME) {
+ qeth_clear_ipacmd_list(card);
+ qeth_schedule_recovery(card);
+ }
return rc;
}
EXPORT_SYMBOL_GPL(qeth_send_ipa_cmd);
@@ -2582,7 +2547,7 @@ int qeth_default_setadapterparms_cb(struct qeth_card *card,
{
struct qeth_ipa_cmd *cmd;
- QETH_DBF_TEXT(TRACE, 4, "defadpcb");
+ QETH_CARD_TEXT(card, 4, "defadpcb");
cmd = (struct qeth_ipa_cmd *) data;
if (cmd->hdr.return_code == 0)
@@ -2597,7 +2562,7 @@ static int qeth_query_setadapterparms_cb(struct qeth_card *card,
{
struct qeth_ipa_cmd *cmd;
- QETH_DBF_TEXT(TRACE, 3, "quyadpcb");
+ QETH_CARD_TEXT(card, 3, "quyadpcb");
cmd = (struct qeth_ipa_cmd *) data;
if (cmd->data.setadapterparms.data.query_cmds_supp.lan_type & 0x7f) {
@@ -2633,7 +2598,7 @@ int qeth_query_setadapterparms(struct qeth_card *card)
int rc;
struct qeth_cmd_buffer *iob;
- QETH_DBF_TEXT(TRACE, 3, "queryadp");
+ QETH_CARD_TEXT(card, 3, "queryadp");
iob = qeth_get_adapter_cmd(card, IPA_SETADP_QUERY_COMMANDS_SUPPORTED,
sizeof(struct qeth_ipacmd_setadpparms));
rc = qeth_send_ipa_cmd(card, iob, qeth_query_setadapterparms_cb, NULL);
@@ -2645,13 +2610,12 @@ int qeth_check_qdio_errors(struct qeth_card *card, struct qdio_buffer *buf,
unsigned int qdio_error, const char *dbftext)
{
if (qdio_error) {
- QETH_DBF_TEXT(TRACE, 2, dbftext);
- QETH_DBF_TEXT(QERR, 2, dbftext);
- QETH_DBF_TEXT_(QERR, 2, " F15=%02X",
+ QETH_CARD_TEXT(card, 2, dbftext);
+ QETH_CARD_TEXT_(card, 2, " F15=%02X",
buf->element[15].flags & 0xff);
- QETH_DBF_TEXT_(QERR, 2, " F14=%02X",
+ QETH_CARD_TEXT_(card, 2, " F14=%02X",
buf->element[14].flags & 0xff);
- QETH_DBF_TEXT_(QERR, 2, " qerr=%X", qdio_error);
+ QETH_CARD_TEXT_(card, 2, " qerr=%X", qdio_error);
if ((buf->element[15].flags & 0xff) == 0x12) {
card->stats.rx_dropped++;
return 0;
@@ -2717,8 +2681,7 @@ void qeth_queue_input_buffer(struct qeth_card *card, int index)
if (rc) {
dev_warn(&card->gdev->dev,
"QDIO reported an error, rc=%i\n", rc);
- QETH_DBF_TEXT(TRACE, 2, "qinberr");
- QETH_DBF_TEXT_(TRACE, 2, "%s", CARD_BUS_ID(card));
+ QETH_CARD_TEXT(card, 2, "qinberr");
}
queue->next_buf_to_init = (queue->next_buf_to_init + count) %
QDIO_MAX_BUFFERS_PER_Q;
@@ -2731,7 +2694,7 @@ static int qeth_handle_send_error(struct qeth_card *card,
{
int sbalf15 = buffer->buffer->element[15].flags & 0xff;
- QETH_DBF_TEXT(TRACE, 6, "hdsnderr");
+ QETH_CARD_TEXT(card, 6, "hdsnderr");
if (card->info.type == QETH_CARD_TYPE_IQD) {
if (sbalf15 == 0) {
qdio_err = 0;
@@ -2747,9 +2710,8 @@ static int qeth_handle_send_error(struct qeth_card *card,
if ((sbalf15 >= 15) && (sbalf15 <= 31))
return QETH_SEND_ERROR_RETRY;
- QETH_DBF_TEXT(TRACE, 1, "lnkfail");
- QETH_DBF_TEXT_(TRACE, 1, "%s", CARD_BUS_ID(card));
- QETH_DBF_TEXT_(TRACE, 1, "%04x %02x",
+ QETH_CARD_TEXT(card, 1, "lnkfail");
+ QETH_CARD_TEXT_(card, 1, "%04x %02x",
(u16)qdio_err, (u8)sbalf15);
return QETH_SEND_ERROR_LINK_FAILURE;
}
@@ -2764,7 +2726,7 @@ static void qeth_switch_to_packing_if_needed(struct qeth_qdio_out_q *queue)
if (atomic_read(&queue->used_buffers)
>= QETH_HIGH_WATERMARK_PACK){
/* switch non-PACKING -> PACKING */
- QETH_DBF_TEXT(TRACE, 6, "np->pack");
+ QETH_CARD_TEXT(queue->card, 6, "np->pack");
if (queue->card->options.performance_stats)
queue->card->perf_stats.sc_dp_p++;
queue->do_pack = 1;
@@ -2787,7 +2749,7 @@ static int qeth_switch_to_nonpacking_if_needed(struct qeth_qdio_out_q *queue)
if (atomic_read(&queue->used_buffers)
<= QETH_LOW_WATERMARK_PACK) {
/* switch PACKING -> non-PACKING */
- QETH_DBF_TEXT(TRACE, 6, "pack->np");
+ QETH_CARD_TEXT(queue->card, 6, "pack->np");
if (queue->card->options.performance_stats)
queue->card->perf_stats.sc_p_dp++;
queue->do_pack = 0;
@@ -2896,9 +2858,8 @@ static void qeth_flush_buffers(struct qeth_qdio_out_q *queue, int index,
/* ignore temporary SIGA errors without busy condition */
if (rc == QDIO_ERROR_SIGA_TARGET)
return;
- QETH_DBF_TEXT(TRACE, 2, "flushbuf");
- QETH_DBF_TEXT_(TRACE, 2, " err%d", rc);
- QETH_DBF_TEXT_(TRACE, 2, "%s", CARD_DDEV_ID(queue->card));
+ QETH_CARD_TEXT(queue->card, 2, "flushbuf");
+ QETH_CARD_TEXT_(queue->card, 2, " err%d", rc);
/* this must not happen under normal circumstances. if it
* happens something is really wrong -> recover */
@@ -2960,10 +2921,9 @@ void qeth_qdio_output_handler(struct ccw_device *ccwdev,
int i;
unsigned qeth_send_err;
- QETH_DBF_TEXT(TRACE, 6, "qdouhdl");
+ QETH_CARD_TEXT(card, 6, "qdouhdl");
if (qdio_error & QDIO_ERROR_ACTIVATE_CHECK_CONDITION) {
- QETH_DBF_TEXT(TRACE, 2, "achkcond");
- QETH_DBF_TEXT_(TRACE, 2, "%s", CARD_BUS_ID(card));
+ QETH_CARD_TEXT(card, 2, "achkcond");
netif_stop_queue(card->dev);
qeth_schedule_recovery(card);
return;
@@ -3033,13 +2993,11 @@ EXPORT_SYMBOL_GPL(qeth_get_priority_queue);
int qeth_get_elements_no(struct qeth_card *card, void *hdr,
struct sk_buff *skb, int elems)
{
- int elements_needed = 0;
+ int dlen = skb->len - skb->data_len;
+ int elements_needed = PFN_UP((unsigned long)skb->data + dlen - 1) -
+ PFN_DOWN((unsigned long)skb->data);
- if (skb_shinfo(skb)->nr_frags > 0)
- elements_needed = (skb_shinfo(skb)->nr_frags + 1);
- if (elements_needed == 0)
- elements_needed = 1 + (((((unsigned long) skb->data) %
- PAGE_SIZE) + skb->len) >> PAGE_SHIFT);
+ elements_needed += skb_shinfo(skb)->nr_frags;
if ((elements_needed + elems) > QETH_MAX_BUFFER_ELEMENTS(card)) {
QETH_DBF_MESSAGE(2, "Invalid size of IP packet "
"(Number=%d / Length=%d). Discarded.\n",
@@ -3050,15 +3008,35 @@ int qeth_get_elements_no(struct qeth_card *card, void *hdr,
}
EXPORT_SYMBOL_GPL(qeth_get_elements_no);
+int qeth_hdr_chk_and_bounce(struct sk_buff *skb, int len)
+{
+ int hroom, inpage, rest;
+
+ if (((unsigned long)skb->data & PAGE_MASK) !=
+ (((unsigned long)skb->data + len - 1) & PAGE_MASK)) {
+ hroom = skb_headroom(skb);
+ inpage = PAGE_SIZE - ((unsigned long) skb->data % PAGE_SIZE);
+ rest = len - inpage;
+ if (rest > hroom)
+ return 1;
+ memmove(skb->data - rest, skb->data, skb->len - skb->data_len);
+ skb->data -= rest;
+ QETH_DBF_MESSAGE(2, "skb bounce len: %d rest: %d\n", len, rest);
+ }
+ return 0;
+}
+EXPORT_SYMBOL_GPL(qeth_hdr_chk_and_bounce);
+
static inline void __qeth_fill_buffer(struct sk_buff *skb,
struct qdio_buffer *buffer, int is_tso, int *next_element_to_fill,
int offset)
{
- int length = skb->len;
+ int length = skb->len - skb->data_len;
int length_here;
int element;
char *data;
- int first_lap ;
+ int first_lap, cnt;
+ struct skb_frag_struct *frag;
element = *next_element_to_fill;
data = skb->data;
@@ -3081,10 +3059,14 @@ static inline void __qeth_fill_buffer(struct sk_buff *skb,
length -= length_here;
if (!length) {
if (first_lap)
- buffer->element[element].flags = 0;
+ if (skb_shinfo(skb)->nr_frags)
+ buffer->element[element].flags =
+ SBAL_FLAGS_FIRST_FRAG;
+ else
+ buffer->element[element].flags = 0;
else
buffer->element[element].flags =
- SBAL_FLAGS_LAST_FRAG;
+ SBAL_FLAGS_MIDDLE_FRAG;
} else {
if (first_lap)
buffer->element[element].flags =
@@ -3097,6 +3079,18 @@ static inline void __qeth_fill_buffer(struct sk_buff *skb,
element++;
first_lap = 0;
}
+
+ for (cnt = 0; cnt < skb_shinfo(skb)->nr_frags; cnt++) {
+ frag = &skb_shinfo(skb)->frags[cnt];
+ buffer->element[element].addr = (char *)page_to_phys(frag->page)
+ + frag->page_offset;
+ buffer->element[element].length = frag->size;
+ buffer->element[element].flags = SBAL_FLAGS_MIDDLE_FRAG;
+ element++;
+ }
+
+ if (buffer->element[element - 1].flags)
+ buffer->element[element - 1].flags = SBAL_FLAGS_LAST_FRAG;
*next_element_to_fill = element;
}
@@ -3137,20 +3131,16 @@ static inline int qeth_fill_buffer(struct qeth_qdio_out_q *queue,
buf->next_element_to_fill++;
}
- if (skb_shinfo(skb)->nr_frags == 0)
- __qeth_fill_buffer(skb, buffer, large_send,
- (int *)&buf->next_element_to_fill, offset);
- else
- __qeth_fill_buffer_frag(skb, buffer, large_send,
- (int *)&buf->next_element_to_fill);
+ __qeth_fill_buffer(skb, buffer, large_send,
+ (int *)&buf->next_element_to_fill, offset);
if (!queue->do_pack) {
- QETH_DBF_TEXT(TRACE, 6, "fillbfnp");
+ QETH_CARD_TEXT(queue->card, 6, "fillbfnp");
/* set state to PRIMED -> will be flushed */
atomic_set(&buf->state, QETH_QDIO_BUF_PRIMED);
flush_cnt = 1;
} else {
- QETH_DBF_TEXT(TRACE, 6, "fillbfpa");
+ QETH_CARD_TEXT(queue->card, 6, "fillbfpa");
if (queue->card->options.performance_stats)
queue->card->perf_stats.skbs_sent_pack++;
if (buf->next_element_to_fill >=
@@ -3210,7 +3200,7 @@ int qeth_do_send_packet_fast(struct qeth_card *card,
rc = dev_queue_xmit(skb);
} else {
dev_kfree_skb_any(skb);
- QETH_DBF_TEXT(QERR, 2, "qrdrop");
+ QETH_CARD_TEXT(card, 2, "qrdrop");
}
}
return 0;
@@ -3312,14 +3302,14 @@ static int qeth_setadp_promisc_mode_cb(struct qeth_card *card,
struct qeth_ipa_cmd *cmd;
struct qeth_ipacmd_setadpparms *setparms;
- QETH_DBF_TEXT(TRACE, 4, "prmadpcb");
+ QETH_CARD_TEXT(card, 4, "prmadpcb");
cmd = (struct qeth_ipa_cmd *) data;
setparms = &(cmd->data.setadapterparms);
qeth_default_setadapterparms_cb(card, reply, (unsigned long)cmd);
if (cmd->hdr.return_code) {
- QETH_DBF_TEXT_(TRACE, 4, "prmrc%2.2x", cmd->hdr.return_code);
+ QETH_CARD_TEXT_(card, 4, "prmrc%2.2x", cmd->hdr.return_code);
setparms->data.mode = SET_PROMISC_MODE_OFF;
}
card->info.promisc_mode = setparms->data.mode;
@@ -3333,7 +3323,7 @@ void qeth_setadp_promisc_mode(struct qeth_card *card)
struct qeth_cmd_buffer *iob;
struct qeth_ipa_cmd *cmd;
- QETH_DBF_TEXT(TRACE, 4, "setprom");
+ QETH_CARD_TEXT(card, 4, "setprom");
if (((dev->flags & IFF_PROMISC) &&
(card->info.promisc_mode == SET_PROMISC_MODE_ON)) ||
@@ -3343,7 +3333,7 @@ void qeth_setadp_promisc_mode(struct qeth_card *card)
mode = SET_PROMISC_MODE_OFF;
if (dev->flags & IFF_PROMISC)
mode = SET_PROMISC_MODE_ON;
- QETH_DBF_TEXT_(TRACE, 4, "mode:%x", mode);
+ QETH_CARD_TEXT_(card, 4, "mode:%x", mode);
iob = qeth_get_adapter_cmd(card, IPA_SETADP_SET_PROMISC_MODE,
sizeof(struct qeth_ipacmd_setadpparms));
@@ -3360,9 +3350,9 @@ int qeth_change_mtu(struct net_device *dev, int new_mtu)
card = dev->ml_priv;
- QETH_DBF_TEXT(TRACE, 4, "chgmtu");
+ QETH_CARD_TEXT(card, 4, "chgmtu");
sprintf(dbf_text, "%8x", new_mtu);
- QETH_DBF_TEXT(TRACE, 4, dbf_text);
+ QETH_CARD_TEXT(card, 4, dbf_text);
if (new_mtu < 64)
return -EINVAL;
@@ -3382,7 +3372,7 @@ struct net_device_stats *qeth_get_stats(struct net_device *dev)
card = dev->ml_priv;
- QETH_DBF_TEXT(TRACE, 5, "getstat");
+ QETH_CARD_TEXT(card, 5, "getstat");
return &card->stats;
}
@@ -3393,7 +3383,7 @@ static int qeth_setadpparms_change_macaddr_cb(struct qeth_card *card,
{
struct qeth_ipa_cmd *cmd;
- QETH_DBF_TEXT(TRACE, 4, "chgmaccb");
+ QETH_CARD_TEXT(card, 4, "chgmaccb");
cmd = (struct qeth_ipa_cmd *) data;
if (!card->options.layer2 ||
@@ -3413,7 +3403,7 @@ int qeth_setadpparms_change_macaddr(struct qeth_card *card)
struct qeth_cmd_buffer *iob;
struct qeth_ipa_cmd *cmd;
- QETH_DBF_TEXT(TRACE, 4, "chgmac");
+ QETH_CARD_TEXT(card, 4, "chgmac");
iob = qeth_get_adapter_cmd(card, IPA_SETADP_ALTER_MAC_ADDRESS,
sizeof(struct qeth_ipacmd_setadpparms));
@@ -3433,9 +3423,8 @@ static int qeth_setadpparms_set_access_ctrl_cb(struct qeth_card *card,
{
struct qeth_ipa_cmd *cmd;
struct qeth_set_access_ctrl *access_ctrl_req;
- int rc;
- QETH_DBF_TEXT(TRACE, 4, "setaccb");
+ QETH_CARD_TEXT(card, 4, "setaccb");
cmd = (struct qeth_ipa_cmd *) data;
access_ctrl_req = &cmd->data.setadapterparms.data.set_access_ctrl;
@@ -3460,7 +3449,6 @@ static int qeth_setadpparms_set_access_ctrl_cb(struct qeth_card *card,
card->gdev->dev.kobj.name,
access_ctrl_req->subcmd_code,
cmd->data.setadapterparms.hdr.return_code);
- rc = 0;
break;
}
case SET_ACCESS_CTRL_RC_NOT_SUPPORTED:
@@ -3474,7 +3462,6 @@ static int qeth_setadpparms_set_access_ctrl_cb(struct qeth_card *card,
/* ensure isolation mode is "none" */
card->options.isolation = ISOLATION_MODE_NONE;
- rc = -EOPNOTSUPP;
break;
}
case SET_ACCESS_CTRL_RC_NONE_SHARED_ADAPTER:
@@ -3489,7 +3476,6 @@ static int qeth_setadpparms_set_access_ctrl_cb(struct qeth_card *card,
/* ensure isolation mode is "none" */
card->options.isolation = ISOLATION_MODE_NONE;
- rc = -EOPNOTSUPP;
break;
}
case SET_ACCESS_CTRL_RC_ACTIVE_CHECKSUM_OFF:
@@ -3503,7 +3489,6 @@ static int qeth_setadpparms_set_access_ctrl_cb(struct qeth_card *card,
/* ensure isolation mode is "none" */
card->options.isolation = ISOLATION_MODE_NONE;
- rc = -EPERM;
break;
}
default:
@@ -3517,12 +3502,11 @@ static int qeth_setadpparms_set_access_ctrl_cb(struct qeth_card *card,
/* ensure isolation mode is "none" */
card->options.isolation = ISOLATION_MODE_NONE;
- rc = 0;
break;
}
}
qeth_default_setadapterparms_cb(card, reply, (unsigned long) cmd);
- return rc;
+ return 0;
}
static int qeth_setadpparms_set_access_ctrl(struct qeth_card *card,
@@ -3533,7 +3517,7 @@ static int qeth_setadpparms_set_access_ctrl(struct qeth_card *card,
struct qeth_ipa_cmd *cmd;
struct qeth_set_access_ctrl *access_ctrl_req;
- QETH_DBF_TEXT(TRACE, 4, "setacctl");
+ QETH_CARD_TEXT(card, 4, "setacctl");
QETH_DBF_TEXT_(SETUP, 2, "setacctl");
QETH_DBF_TEXT_(SETUP, 2, "%s", card->gdev->dev.kobj.name);
@@ -3555,7 +3539,7 @@ int qeth_set_access_ctrl_online(struct qeth_card *card)
{
int rc = 0;
- QETH_DBF_TEXT(TRACE, 4, "setactlo");
+ QETH_CARD_TEXT(card, 4, "setactlo");
if ((card->info.type == QETH_CARD_TYPE_OSD ||
card->info.type == QETH_CARD_TYPE_OSX) &&
@@ -3583,8 +3567,8 @@ void qeth_tx_timeout(struct net_device *dev)
{
struct qeth_card *card;
- QETH_DBF_TEXT(TRACE, 4, "txtimeo");
card = dev->ml_priv;
+ QETH_CARD_TEXT(card, 4, "txtimeo");
card->stats.tx_errors++;
qeth_schedule_recovery(card);
}
@@ -3663,7 +3647,7 @@ static int qeth_send_ipa_snmp_cmd(struct qeth_card *card,
{
u16 s1, s2;
- QETH_DBF_TEXT(TRACE, 4, "sendsnmp");
+ QETH_CARD_TEXT(card, 4, "sendsnmp");
memcpy(iob->data, IPA_PDU_HEADER, IPA_PDU_HEADER_SIZE);
memcpy(QETH_IPA_CMD_DEST_ADDR(iob->data),
@@ -3688,7 +3672,7 @@ static int qeth_snmp_command_cb(struct qeth_card *card,
unsigned char *data;
__u16 data_len;
- QETH_DBF_TEXT(TRACE, 3, "snpcmdcb");
+ QETH_CARD_TEXT(card, 3, "snpcmdcb");
cmd = (struct qeth_ipa_cmd *) sdata;
data = (unsigned char *)((char *)cmd - reply->offset);
@@ -3696,13 +3680,13 @@ static int qeth_snmp_command_cb(struct qeth_card *card,
snmp = &cmd->data.setadapterparms.data.snmp;
if (cmd->hdr.return_code) {
- QETH_DBF_TEXT_(TRACE, 4, "scer1%i", cmd->hdr.return_code);
+ QETH_CARD_TEXT_(card, 4, "scer1%i", cmd->hdr.return_code);
return 0;
}
if (cmd->data.setadapterparms.hdr.return_code) {
cmd->hdr.return_code =
cmd->data.setadapterparms.hdr.return_code;
- QETH_DBF_TEXT_(TRACE, 4, "scer2%i", cmd->hdr.return_code);
+ QETH_CARD_TEXT_(card, 4, "scer2%i", cmd->hdr.return_code);
return 0;
}
data_len = *((__u16 *)QETH_IPA_PDU_LEN_PDU1(data));
@@ -3713,13 +3697,13 @@ static int qeth_snmp_command_cb(struct qeth_card *card,
/* check if there is enough room in userspace */
if ((qinfo->udata_len - qinfo->udata_offset) < data_len) {
- QETH_DBF_TEXT_(TRACE, 4, "scer3%i", -ENOMEM);
+ QETH_CARD_TEXT_(card, 4, "scer3%i", -ENOMEM);
cmd->hdr.return_code = -ENOMEM;
return 0;
}
- QETH_DBF_TEXT_(TRACE, 4, "snore%i",
+ QETH_CARD_TEXT_(card, 4, "snore%i",
cmd->data.setadapterparms.hdr.used_total);
- QETH_DBF_TEXT_(TRACE, 4, "sseqn%i",
+ QETH_CARD_TEXT_(card, 4, "sseqn%i",
cmd->data.setadapterparms.hdr.seq_no);
/*copy entries to user buffer*/
if (cmd->data.setadapterparms.hdr.seq_no == 1) {
@@ -3733,9 +3717,9 @@ static int qeth_snmp_command_cb(struct qeth_card *card,
}
qinfo->udata_offset += data_len;
/* check if all replies received ... */
- QETH_DBF_TEXT_(TRACE, 4, "srtot%i",
+ QETH_CARD_TEXT_(card, 4, "srtot%i",
cmd->data.setadapterparms.hdr.used_total);
- QETH_DBF_TEXT_(TRACE, 4, "srseq%i",
+ QETH_CARD_TEXT_(card, 4, "srseq%i",
cmd->data.setadapterparms.hdr.seq_no);
if (cmd->data.setadapterparms.hdr.seq_no <
cmd->data.setadapterparms.hdr.used_total)
@@ -3752,7 +3736,7 @@ int qeth_snmp_command(struct qeth_card *card, char __user *udata)
struct qeth_arp_query_info qinfo = {0, };
int rc = 0;
- QETH_DBF_TEXT(TRACE, 3, "snmpcmd");
+ QETH_CARD_TEXT(card, 3, "snmpcmd");
if (card->info.guestlan)
return -EOPNOTSUPP;
@@ -3764,15 +3748,10 @@ int qeth_snmp_command(struct qeth_card *card, char __user *udata)
/* skip 4 bytes (data_len struct member) to get req_len */
if (copy_from_user(&req_len, udata + sizeof(int), sizeof(int)))
return -EFAULT;
- ureq = kmalloc(req_len+sizeof(struct qeth_snmp_ureq_hdr), GFP_KERNEL);
- if (!ureq) {
- QETH_DBF_TEXT(TRACE, 2, "snmpnome");
- return -ENOMEM;
- }
- if (copy_from_user(ureq, udata,
- req_len + sizeof(struct qeth_snmp_ureq_hdr))) {
- kfree(ureq);
- return -EFAULT;
+ ureq = memdup_user(udata, req_len + sizeof(struct qeth_snmp_ureq_hdr));
+ if (IS_ERR(ureq)) {
+ QETH_CARD_TEXT(card, 2, "snmpnome");
+ return PTR_ERR(ureq);
}
qinfo.udata_len = ureq->hdr.data_len;
qinfo.udata = kzalloc(qinfo.udata_len, GFP_KERNEL);
@@ -3991,6 +3970,7 @@ retriable:
else
goto retry;
}
+ card->read_or_write_problem = 0;
rc = qeth_mpc_initialize(card);
if (rc) {
QETH_DBF_TEXT_(SETUP, 2, "5err%d", rc);
@@ -4120,13 +4100,8 @@ struct sk_buff *qeth_core_get_next_skb(struct qeth_card *card,
skb_len -= data_len;
if (skb_len) {
if (qeth_is_last_sbale(element)) {
- QETH_DBF_TEXT(TRACE, 4, "unexeob");
- QETH_DBF_TEXT_(TRACE, 4, "%s",
- CARD_BUS_ID(card));
- QETH_DBF_TEXT(QERR, 2, "unexeob");
- QETH_DBF_TEXT_(QERR, 2, "%s",
- CARD_BUS_ID(card));
- QETH_DBF_HEX(MISC, 4, buffer, sizeof(*buffer));
+ QETH_CARD_TEXT(card, 4, "unexeob");
+ QETH_CARD_HEX(card, 2, buffer, sizeof(void *));
dev_kfree_skb_any(skb);
card->stats.rx_errors++;
return NULL;
@@ -4147,8 +4122,7 @@ struct sk_buff *qeth_core_get_next_skb(struct qeth_card *card,
return skb;
no_mem:
if (net_ratelimit()) {
- QETH_DBF_TEXT(TRACE, 2, "noskbmem");
- QETH_DBF_TEXT_(TRACE, 2, "%s", CARD_BUS_ID(card));
+ QETH_CARD_TEXT(card, 2, "noskbmem");
}
card->stats.rx_dropped++;
return NULL;
@@ -4164,17 +4138,17 @@ static void qeth_unregister_dbf_views(void)
}
}
-void qeth_dbf_longtext(enum qeth_dbf_names dbf_nix, int level, char *fmt, ...)
+void qeth_dbf_longtext(debug_info_t *id, int level, char *fmt, ...)
{
char dbf_txt_buf[32];
va_list args;
- if (level > (qeth_dbf[dbf_nix].id)->level)
+ if (level > id->level)
return;
va_start(args, fmt);
vsnprintf(dbf_txt_buf, sizeof(dbf_txt_buf), fmt, args);
va_end(args);
- debug_text_event(qeth_dbf[dbf_nix].id, level, dbf_txt_buf);
+ debug_text_event(id, level, dbf_txt_buf);
}
EXPORT_SYMBOL_GPL(qeth_dbf_longtext);
@@ -4282,6 +4256,7 @@ static int qeth_core_probe_device(struct ccwgroup_device *gdev)
struct device *dev;
int rc;
unsigned long flags;
+ char dbf_name[20];
QETH_DBF_TEXT(SETUP, 2, "probedev");
@@ -4297,6 +4272,17 @@ static int qeth_core_probe_device(struct ccwgroup_device *gdev)
rc = -ENOMEM;
goto err_dev;
}
+
+ snprintf(dbf_name, sizeof(dbf_name), "qeth_card_%s",
+ dev_name(&gdev->dev));
+ card->debug = debug_register(dbf_name, 2, 1, 8);
+ if (!card->debug) {
+ QETH_DBF_TEXT_(SETUP, 2, "%s", "qcdbf");
+ rc = -ENOMEM;
+ goto err_card;
+ }
+ debug_register_view(card->debug, &debug_hex_ascii_view);
+
card->read.ccwdev = gdev->cdev[0];
card->write.ccwdev = gdev->cdev[1];
card->data.ccwdev = gdev->cdev[2];
@@ -4309,12 +4295,12 @@ static int qeth_core_probe_device(struct ccwgroup_device *gdev)
rc = qeth_determine_card_type(card);
if (rc) {
QETH_DBF_TEXT_(SETUP, 2, "3err%d", rc);
- goto err_card;
+ goto err_dbf;
}
rc = qeth_setup_card(card);
if (rc) {
QETH_DBF_TEXT_(SETUP, 2, "2err%d", rc);
- goto err_card;
+ goto err_dbf;
}
if (card->info.type == QETH_CARD_TYPE_OSN)
@@ -4322,7 +4308,7 @@ static int qeth_core_probe_device(struct ccwgroup_device *gdev)
else
rc = qeth_core_create_device_attributes(dev);
if (rc)
- goto err_card;
+ goto err_dbf;
switch (card->info.type) {
case QETH_CARD_TYPE_OSN:
case QETH_CARD_TYPE_OSM:
@@ -4352,6 +4338,8 @@ err_attr:
qeth_core_remove_osn_attributes(dev);
else
qeth_core_remove_device_attributes(dev);
+err_dbf:
+ debug_unregister(card->debug);
err_card:
qeth_core_free_card(card);
err_dev:
@@ -4365,16 +4353,19 @@ static void qeth_core_remove_device(struct ccwgroup_device *gdev)
struct qeth_card *card = dev_get_drvdata(&gdev->dev);
QETH_DBF_TEXT(SETUP, 2, "removedv");
- if (card->discipline.ccwgdriver) {
- card->discipline.ccwgdriver->remove(gdev);
- qeth_core_free_discipline(card);
- }
if (card->info.type == QETH_CARD_TYPE_OSN) {
qeth_core_remove_osn_attributes(&gdev->dev);
} else {
qeth_core_remove_device_attributes(&gdev->dev);
}
+
+ if (card->discipline.ccwgdriver) {
+ card->discipline.ccwgdriver->remove(gdev);
+ qeth_core_free_discipline(card);
+ }
+
+ debug_unregister(card->debug);
write_lock_irqsave(&qeth_core_card_list.rwlock, flags);
list_del(&card->list);
write_unlock_irqrestore(&qeth_core_card_list.rwlock, flags);
diff --git a/drivers/s390/net/qeth_core_mpc.h b/drivers/s390/net/qeth_core_mpc.h
index f9ed24de751..e37dd8c4bf4 100644
--- a/drivers/s390/net/qeth_core_mpc.h
+++ b/drivers/s390/net/qeth_core_mpc.h
@@ -616,8 +616,9 @@ extern unsigned char IDX_ACTIVATE_WRITE[];
#define QETH_IS_IDX_ACT_POS_REPLY(buffer) (((buffer)[0x08] & 3) == 2)
#define QETH_IDX_REPLY_LEVEL(buffer) (buffer + 0x12)
#define QETH_IDX_ACT_CAUSE_CODE(buffer) (buffer)[0x09]
-#define QETH_IDX_ACT_ERR_EXCL 0x19
-#define QETH_IDX_ACT_ERR_AUTH 0x1E
+#define QETH_IDX_ACT_ERR_EXCL 0x19
+#define QETH_IDX_ACT_ERR_AUTH 0x1E
+#define QETH_IDX_ACT_ERR_AUTH_USER 0x20
#define PDU_ENCAPSULATION(buffer) \
(buffer + *(buffer + (*(buffer + 0x0b)) + \
diff --git a/drivers/s390/net/qeth_core_sys.c b/drivers/s390/net/qeth_core_sys.c
index 2eb022ff261..42fa783a70c 100644
--- a/drivers/s390/net/qeth_core_sys.c
+++ b/drivers/s390/net/qeth_core_sys.c
@@ -411,7 +411,7 @@ static ssize_t qeth_dev_layer2_store(struct device *dev,
if (!card)
return -EINVAL;
- mutex_lock(&card->conf_mutex);
+ mutex_lock(&card->discipline_mutex);
if (card->state != CARD_STATE_DOWN) {
rc = -EPERM;
goto out;
@@ -433,6 +433,7 @@ static ssize_t qeth_dev_layer2_store(struct device *dev,
if (card->options.layer2 == newdis)
goto out;
else {
+ card->info.mac_bits = 0;
if (card->discipline.ccwgdriver) {
card->discipline.ccwgdriver->remove(card->gdev);
qeth_core_free_discipline(card);
@@ -445,7 +446,7 @@ static ssize_t qeth_dev_layer2_store(struct device *dev,
rc = card->discipline.ccwgdriver->probe(card->gdev);
out:
- mutex_unlock(&card->conf_mutex);
+ mutex_unlock(&card->discipline_mutex);
return rc ? rc : count;
}
diff --git a/drivers/s390/net/qeth_l2_main.c b/drivers/s390/net/qeth_l2_main.c
index d43f57a4ac6..830d63524d6 100644
--- a/drivers/s390/net/qeth_l2_main.c
+++ b/drivers/s390/net/qeth_l2_main.c
@@ -79,7 +79,7 @@ static int qeth_l2_do_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
rc = -EOPNOTSUPP;
}
if (rc)
- QETH_DBF_TEXT_(TRACE, 2, "ioce%d", rc);
+ QETH_CARD_TEXT_(card, 2, "ioce%d", rc);
return rc;
}
@@ -130,7 +130,7 @@ static int qeth_l2_send_setgroupmac_cb(struct qeth_card *card,
struct qeth_ipa_cmd *cmd;
__u8 *mac;
- QETH_DBF_TEXT(TRACE, 2, "L2Sgmacb");
+ QETH_CARD_TEXT(card, 2, "L2Sgmacb");
cmd = (struct qeth_ipa_cmd *) data;
mac = &cmd->data.setdelmac.mac[0];
/* MAC already registered, needed in couple/uncouple case */
@@ -147,7 +147,7 @@ static int qeth_l2_send_setgroupmac_cb(struct qeth_card *card,
static int qeth_l2_send_setgroupmac(struct qeth_card *card, __u8 *mac)
{
- QETH_DBF_TEXT(TRACE, 2, "L2Sgmac");
+ QETH_CARD_TEXT(card, 2, "L2Sgmac");
return qeth_l2_send_setdelmac(card, mac, IPA_CMD_SETGMAC,
qeth_l2_send_setgroupmac_cb);
}
@@ -159,7 +159,7 @@ static int qeth_l2_send_delgroupmac_cb(struct qeth_card *card,
struct qeth_ipa_cmd *cmd;
__u8 *mac;
- QETH_DBF_TEXT(TRACE, 2, "L2Dgmacb");
+ QETH_CARD_TEXT(card, 2, "L2Dgmacb");
cmd = (struct qeth_ipa_cmd *) data;
mac = &cmd->data.setdelmac.mac[0];
if (cmd->hdr.return_code)
@@ -170,7 +170,7 @@ static int qeth_l2_send_delgroupmac_cb(struct qeth_card *card,
static int qeth_l2_send_delgroupmac(struct qeth_card *card, __u8 *mac)
{
- QETH_DBF_TEXT(TRACE, 2, "L2Dgmac");
+ QETH_CARD_TEXT(card, 2, "L2Dgmac");
return qeth_l2_send_setdelmac(card, mac, IPA_CMD_DELGMAC,
qeth_l2_send_delgroupmac_cb);
}
@@ -262,15 +262,14 @@ static int qeth_l2_send_setdelvlan_cb(struct qeth_card *card,
{
struct qeth_ipa_cmd *cmd;
- QETH_DBF_TEXT(TRACE, 2, "L2sdvcb");
+ QETH_CARD_TEXT(card, 2, "L2sdvcb");
cmd = (struct qeth_ipa_cmd *) data;
if (cmd->hdr.return_code) {
QETH_DBF_MESSAGE(2, "Error in processing VLAN %i on %s: 0x%x. "
"Continuing\n", cmd->data.setdelvlan.vlan_id,
QETH_CARD_IFNAME(card), cmd->hdr.return_code);
- QETH_DBF_TEXT_(TRACE, 2, "L2VL%4x", cmd->hdr.command);
- QETH_DBF_TEXT_(TRACE, 2, "L2%s", CARD_BUS_ID(card));
- QETH_DBF_TEXT_(TRACE, 2, "err%d", cmd->hdr.return_code);
+ QETH_CARD_TEXT_(card, 2, "L2VL%4x", cmd->hdr.command);
+ QETH_CARD_TEXT_(card, 2, "err%d", cmd->hdr.return_code);
}
return 0;
}
@@ -281,7 +280,7 @@ static int qeth_l2_send_setdelvlan(struct qeth_card *card, __u16 i,
struct qeth_ipa_cmd *cmd;
struct qeth_cmd_buffer *iob;
- QETH_DBF_TEXT_(TRACE, 4, "L2sdv%x", ipacmd);
+ QETH_CARD_TEXT_(card, 4, "L2sdv%x", ipacmd);
iob = qeth_get_ipacmd_buffer(card, ipacmd, QETH_PROT_IPV4);
cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE);
cmd->data.setdelvlan.vlan_id = i;
@@ -292,7 +291,7 @@ static int qeth_l2_send_setdelvlan(struct qeth_card *card, __u16 i,
static void qeth_l2_process_vlans(struct qeth_card *card, int clear)
{
struct qeth_vlan_vid *id;
- QETH_DBF_TEXT(TRACE, 3, "L2prcvln");
+ QETH_CARD_TEXT(card, 3, "L2prcvln");
spin_lock_bh(&card->vlanlock);
list_for_each_entry(id, &card->vid_list, list) {
if (clear)
@@ -310,13 +309,13 @@ static void qeth_l2_vlan_rx_add_vid(struct net_device *dev, unsigned short vid)
struct qeth_card *card = dev->ml_priv;
struct qeth_vlan_vid *id;
- QETH_DBF_TEXT_(TRACE, 4, "aid:%d", vid);
+ QETH_CARD_TEXT_(card, 4, "aid:%d", vid);
if (card->info.type == QETH_CARD_TYPE_OSM) {
- QETH_DBF_TEXT(TRACE, 3, "aidOSM");
+ QETH_CARD_TEXT(card, 3, "aidOSM");
return;
}
if (qeth_wait_for_threads(card, QETH_RECOVER_THREAD)) {
- QETH_DBF_TEXT(TRACE, 3, "aidREC");
+ QETH_CARD_TEXT(card, 3, "aidREC");
return;
}
id = kmalloc(sizeof(struct qeth_vlan_vid), GFP_ATOMIC);
@@ -334,13 +333,13 @@ static void qeth_l2_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid)
struct qeth_vlan_vid *id, *tmpid = NULL;
struct qeth_card *card = dev->ml_priv;
- QETH_DBF_TEXT_(TRACE, 4, "kid:%d", vid);
+ QETH_CARD_TEXT_(card, 4, "kid:%d", vid);
if (card->info.type == QETH_CARD_TYPE_OSM) {
- QETH_DBF_TEXT(TRACE, 3, "kidOSM");
+ QETH_CARD_TEXT(card, 3, "kidOSM");
return;
}
if (qeth_wait_for_threads(card, QETH_RECOVER_THREAD)) {
- QETH_DBF_TEXT(TRACE, 3, "kidREC");
+ QETH_CARD_TEXT(card, 3, "kidREC");
return;
}
spin_lock_bh(&card->vlanlock);
@@ -456,7 +455,7 @@ static void qeth_l2_process_inbound_buffer(struct qeth_card *card,
/* else unknown */
default:
dev_kfree_skb_any(skb);
- QETH_DBF_TEXT(TRACE, 3, "inbunkno");
+ QETH_CARD_TEXT(card, 3, "inbunkno");
QETH_DBF_HEX(CTRL, 3, hdr, QETH_DBF_CTRL_LEN);
continue;
}
@@ -474,7 +473,7 @@ static int qeth_l2_send_setdelmac(struct qeth_card *card, __u8 *mac,
struct qeth_ipa_cmd *cmd;
struct qeth_cmd_buffer *iob;
- QETH_DBF_TEXT(TRACE, 2, "L2sdmac");
+ QETH_CARD_TEXT(card, 2, "L2sdmac");
iob = qeth_get_ipacmd_buffer(card, ipacmd, QETH_PROT_IPV4);
cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE);
cmd->data.setdelmac.mac_length = OSA_ADDR_LEN;
@@ -488,10 +487,10 @@ static int qeth_l2_send_setmac_cb(struct qeth_card *card,
{
struct qeth_ipa_cmd *cmd;
- QETH_DBF_TEXT(TRACE, 2, "L2Smaccb");
+ QETH_CARD_TEXT(card, 2, "L2Smaccb");
cmd = (struct qeth_ipa_cmd *) data;
if (cmd->hdr.return_code) {
- QETH_DBF_TEXT_(TRACE, 2, "L2er%x", cmd->hdr.return_code);
+ QETH_CARD_TEXT_(card, 2, "L2er%x", cmd->hdr.return_code);
card->info.mac_bits &= ~QETH_LAYER2_MAC_REGISTERED;
switch (cmd->hdr.return_code) {
case IPA_RC_L2_DUP_MAC:
@@ -523,7 +522,7 @@ static int qeth_l2_send_setmac_cb(struct qeth_card *card,
static int qeth_l2_send_setmac(struct qeth_card *card, __u8 *mac)
{
- QETH_DBF_TEXT(TRACE, 2, "L2Setmac");
+ QETH_CARD_TEXT(card, 2, "L2Setmac");
return qeth_l2_send_setdelmac(card, mac, IPA_CMD_SETVMAC,
qeth_l2_send_setmac_cb);
}
@@ -534,10 +533,10 @@ static int qeth_l2_send_delmac_cb(struct qeth_card *card,
{
struct qeth_ipa_cmd *cmd;
- QETH_DBF_TEXT(TRACE, 2, "L2Dmaccb");
+ QETH_CARD_TEXT(card, 2, "L2Dmaccb");
cmd = (struct qeth_ipa_cmd *) data;
if (cmd->hdr.return_code) {
- QETH_DBF_TEXT_(TRACE, 2, "err%d", cmd->hdr.return_code);
+ QETH_CARD_TEXT_(card, 2, "err%d", cmd->hdr.return_code);
cmd->hdr.return_code = -EIO;
return 0;
}
@@ -548,7 +547,7 @@ static int qeth_l2_send_delmac_cb(struct qeth_card *card,
static int qeth_l2_send_delmac(struct qeth_card *card, __u8 *mac)
{
- QETH_DBF_TEXT(TRACE, 2, "L2Delmac");
+ QETH_CARD_TEXT(card, 2, "L2Delmac");
if (!(card->info.mac_bits & QETH_LAYER2_MAC_REGISTERED))
return 0;
return qeth_l2_send_setdelmac(card, mac, IPA_CMD_DELVMAC,
@@ -594,23 +593,22 @@ static int qeth_l2_set_mac_address(struct net_device *dev, void *p)
struct qeth_card *card = dev->ml_priv;
int rc = 0;
- QETH_DBF_TEXT(TRACE, 3, "setmac");
+ QETH_CARD_TEXT(card, 3, "setmac");
if (qeth_l2_verify_dev(dev) != QETH_REAL_CARD) {
- QETH_DBF_TEXT(TRACE, 3, "setmcINV");
+ QETH_CARD_TEXT(card, 3, "setmcINV");
return -EOPNOTSUPP;
}
if (card->info.type == QETH_CARD_TYPE_OSN ||
card->info.type == QETH_CARD_TYPE_OSM ||
card->info.type == QETH_CARD_TYPE_OSX) {
- QETH_DBF_TEXT(TRACE, 3, "setmcTYP");
+ QETH_CARD_TEXT(card, 3, "setmcTYP");
return -EOPNOTSUPP;
}
- QETH_DBF_TEXT_(TRACE, 3, "%s", CARD_BUS_ID(card));
- QETH_DBF_HEX(TRACE, 3, addr->sa_data, OSA_ADDR_LEN);
+ QETH_CARD_HEX(card, 3, addr->sa_data, OSA_ADDR_LEN);
if (qeth_wait_for_threads(card, QETH_RECOVER_THREAD)) {
- QETH_DBF_TEXT(TRACE, 3, "setmcREC");
+ QETH_CARD_TEXT(card, 3, "setmcREC");
return -ERESTARTSYS;
}
rc = qeth_l2_send_delmac(card, &card->dev->dev_addr[0]);
@@ -627,7 +625,7 @@ static void qeth_l2_set_multicast_list(struct net_device *dev)
if (card->info.type == QETH_CARD_TYPE_OSN)
return ;
- QETH_DBF_TEXT(TRACE, 3, "setmulti");
+ QETH_CARD_TEXT(card, 3, "setmulti");
if (qeth_threads_running(card, QETH_RECOVER_THREAD) &&
(card->state != CARD_STATE_UP))
return;
@@ -714,10 +712,13 @@ static int qeth_l2_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
goto tx_drop;
}
- if (card->info.type != QETH_CARD_TYPE_IQD)
+ if (card->info.type != QETH_CARD_TYPE_IQD) {
+ if (qeth_hdr_chk_and_bounce(new_skb,
+ sizeof(struct qeth_hdr_layer2)))
+ goto tx_drop;
rc = qeth_do_send_packet(card, queue, new_skb, hdr,
elements);
- else
+ } else
rc = qeth_do_send_packet_fast(card, queue, new_skb, hdr,
elements, data_offset, hd_len);
if (!rc) {
@@ -771,11 +772,10 @@ static void qeth_l2_qdio_input_handler(struct ccw_device *ccwdev,
card->perf_stats.inbound_start_time = qeth_get_micros();
}
if (qdio_err & QDIO_ERROR_ACTIVATE_CHECK_CONDITION) {
- QETH_DBF_TEXT(TRACE, 1, "qdinchk");
- QETH_DBF_TEXT_(TRACE, 1, "%s", CARD_BUS_ID(card));
- QETH_DBF_TEXT_(TRACE, 1, "%04X%04X", first_element,
+ QETH_CARD_TEXT(card, 1, "qdinchk");
+ QETH_CARD_TEXT_(card, 1, "%04X%04X", first_element,
count);
- QETH_DBF_TEXT_(TRACE, 1, "%04X", queue);
+ QETH_CARD_TEXT_(card, 1, "%04X", queue);
qeth_schedule_recovery(card);
return;
}
@@ -799,13 +799,13 @@ static int qeth_l2_open(struct net_device *dev)
{
struct qeth_card *card = dev->ml_priv;
- QETH_DBF_TEXT(TRACE, 4, "qethopen");
+ QETH_CARD_TEXT(card, 4, "qethopen");
if (card->state != CARD_STATE_SOFTSETUP)
return -ENODEV;
if ((card->info.type != QETH_CARD_TYPE_OSN) &&
(!(card->info.mac_bits & QETH_LAYER2_MAC_REGISTERED))) {
- QETH_DBF_TEXT(TRACE, 4, "nomacadr");
+ QETH_CARD_TEXT(card, 4, "nomacadr");
return -EPERM;
}
card->data.state = CH_STATE_UP;
@@ -822,7 +822,7 @@ static int qeth_l2_stop(struct net_device *dev)
{
struct qeth_card *card = dev->ml_priv;
- QETH_DBF_TEXT(TRACE, 4, "qethstop");
+ QETH_CARD_TEXT(card, 4, "qethstop");
netif_tx_disable(dev);
if (card->state == CARD_STATE_UP)
card->state = CARD_STATE_SOFTSETUP;
@@ -860,8 +860,6 @@ static void qeth_l2_remove_device(struct ccwgroup_device *cgdev)
unregister_netdev(card->dev);
card->dev = NULL;
}
-
- qeth_l2_del_all_mc(card);
return;
}
@@ -935,6 +933,7 @@ static int __qeth_l2_set_online(struct ccwgroup_device *gdev, int recovery_mode)
enum qeth_card_states recover_flag;
BUG_ON(!card);
+ mutex_lock(&card->discipline_mutex);
mutex_lock(&card->conf_mutex);
QETH_DBF_TEXT(SETUP, 2, "setonlin");
QETH_DBF_HEX(SETUP, 2, &card, sizeof(void *));
@@ -1012,6 +1011,7 @@ static int __qeth_l2_set_online(struct ccwgroup_device *gdev, int recovery_mode)
kobject_uevent(&gdev->dev.kobj, KOBJ_CHANGE);
out:
mutex_unlock(&card->conf_mutex);
+ mutex_unlock(&card->discipline_mutex);
return 0;
out_remove:
@@ -1025,6 +1025,7 @@ out_remove:
else
card->state = CARD_STATE_DOWN;
mutex_unlock(&card->conf_mutex);
+ mutex_unlock(&card->discipline_mutex);
return rc;
}
@@ -1040,6 +1041,7 @@ static int __qeth_l2_set_offline(struct ccwgroup_device *cgdev,
int rc = 0, rc2 = 0, rc3 = 0;
enum qeth_card_states recover_flag;
+ mutex_lock(&card->discipline_mutex);
mutex_lock(&card->conf_mutex);
QETH_DBF_TEXT(SETUP, 3, "setoffl");
QETH_DBF_HEX(SETUP, 3, &card, sizeof(void *));
@@ -1060,6 +1062,7 @@ static int __qeth_l2_set_offline(struct ccwgroup_device *cgdev,
/* let user_space know that device is offline */
kobject_uevent(&cgdev->dev.kobj, KOBJ_CHANGE);
mutex_unlock(&card->conf_mutex);
+ mutex_unlock(&card->discipline_mutex);
return 0;
}
@@ -1074,11 +1077,10 @@ static int qeth_l2_recover(void *ptr)
int rc = 0;
card = (struct qeth_card *) ptr;
- QETH_DBF_TEXT(TRACE, 2, "recover1");
- QETH_DBF_HEX(TRACE, 2, &card, sizeof(void *));
+ QETH_CARD_TEXT(card, 2, "recover1");
if (!qeth_do_run_thread(card, QETH_RECOVER_THREAD))
return 0;
- QETH_DBF_TEXT(TRACE, 2, "recover2");
+ QETH_CARD_TEXT(card, 2, "recover2");
dev_warn(&card->gdev->dev,
"A recovery process has been started for the device\n");
card->use_hard_stop = 1;
@@ -1181,12 +1183,12 @@ static int qeth_osn_send_control_data(struct qeth_card *card, int len,
unsigned long flags;
int rc = 0;
- QETH_DBF_TEXT(TRACE, 5, "osndctrd");
+ QETH_CARD_TEXT(card, 5, "osndctrd");
wait_event(card->wait_q,
atomic_cmpxchg(&card->write.irq_pending, 0, 1) == 0);
qeth_prepare_control_data(card, len, iob);
- QETH_DBF_TEXT(TRACE, 6, "osnoirqp");
+ QETH_CARD_TEXT(card, 6, "osnoirqp");
spin_lock_irqsave(get_ccwdev_lock(card->write.ccwdev), flags);
rc = ccw_device_start(card->write.ccwdev, &card->write.ccw,
(addr_t) iob, 0, 0);
@@ -1194,7 +1196,7 @@ static int qeth_osn_send_control_data(struct qeth_card *card, int len,
if (rc) {
QETH_DBF_MESSAGE(2, "qeth_osn_send_control_data: "
"ccw_device_start rc = %i\n", rc);
- QETH_DBF_TEXT_(TRACE, 2, " err%d", rc);
+ QETH_CARD_TEXT_(card, 2, " err%d", rc);
qeth_release_buffer(iob->channel, iob);
atomic_set(&card->write.irq_pending, 0);
wake_up(&card->wait_q);
@@ -1207,7 +1209,7 @@ static int qeth_osn_send_ipa_cmd(struct qeth_card *card,
{
u16 s1, s2;
- QETH_DBF_TEXT(TRACE, 4, "osndipa");
+ QETH_CARD_TEXT(card, 4, "osndipa");
qeth_prepare_ipa_cmd(card, iob, QETH_PROT_OSN2);
s1 = (u16)(IPA_PDU_HEADER_SIZE + data_len);
@@ -1225,12 +1227,12 @@ int qeth_osn_assist(struct net_device *dev, void *data, int data_len)
struct qeth_card *card;
int rc;
- QETH_DBF_TEXT(TRACE, 2, "osnsdmc");
if (!dev)
return -ENODEV;
card = dev->ml_priv;
if (!card)
return -ENODEV;
+ QETH_CARD_TEXT(card, 2, "osnsdmc");
if ((card->state != CARD_STATE_UP) &&
(card->state != CARD_STATE_SOFTSETUP))
return -ENODEV;
@@ -1247,13 +1249,13 @@ int qeth_osn_register(unsigned char *read_dev_no, struct net_device **dev,
{
struct qeth_card *card;
- QETH_DBF_TEXT(TRACE, 2, "osnreg");
*dev = qeth_l2_netdev_by_devno(read_dev_no);
if (*dev == NULL)
return -ENODEV;
card = (*dev)->ml_priv;
if (!card)
return -ENODEV;
+ QETH_CARD_TEXT(card, 2, "osnreg");
if ((assist_cb == NULL) || (data_cb == NULL))
return -EINVAL;
card->osn_info.assist_cb = assist_cb;
@@ -1266,12 +1268,12 @@ void qeth_osn_deregister(struct net_device *dev)
{
struct qeth_card *card;
- QETH_DBF_TEXT(TRACE, 2, "osndereg");
if (!dev)
return;
card = dev->ml_priv;
if (!card)
return;
+ QETH_CARD_TEXT(card, 2, "osndereg");
card->osn_info.assist_cb = NULL;
card->osn_info.data_cb = NULL;
return;
diff --git a/drivers/s390/net/qeth_l3.h b/drivers/s390/net/qeth_l3.h
index 8447d233d0b..e705b27ec7d 100644
--- a/drivers/s390/net/qeth_l3.h
+++ b/drivers/s390/net/qeth_l3.h
@@ -64,5 +64,6 @@ void qeth_l3_del_rxip(struct qeth_card *card, enum qeth_prot_versions,
const u8 *);
int qeth_l3_set_large_send(struct qeth_card *, enum qeth_large_send_types);
int qeth_l3_set_rx_csum(struct qeth_card *, enum qeth_checksum_types);
+int qeth_l3_is_addr_covered_by_ipato(struct qeth_card *, struct qeth_ipaddr *);
#endif /* __QETH_L3_H__ */
diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c
index 61adae21a46..e22ae248f61 100644
--- a/drivers/s390/net/qeth_l3_main.c
+++ b/drivers/s390/net/qeth_l3_main.c
@@ -195,7 +195,7 @@ static void qeth_l3_convert_addr_to_bits(u8 *addr, u8 *bits, int len)
}
}
-static int qeth_l3_is_addr_covered_by_ipato(struct qeth_card *card,
+int qeth_l3_is_addr_covered_by_ipato(struct qeth_card *card,
struct qeth_ipaddr *addr)
{
struct qeth_ipato_entry *ipatoe;
@@ -287,7 +287,7 @@ static int __qeth_l3_insert_ip_todo(struct qeth_card *card,
addr->users += add ? 1 : -1;
if (add && (addr->type == QETH_IP_TYPE_NORMAL) &&
qeth_l3_is_addr_covered_by_ipato(card, addr)) {
- QETH_DBF_TEXT(TRACE, 2, "tkovaddr");
+ QETH_CARD_TEXT(card, 2, "tkovaddr");
addr->set_flags |= QETH_IPA_SETIP_TAKEOVER_FLAG;
}
list_add_tail(&addr->entry, card->ip_tbd_list);
@@ -301,13 +301,13 @@ static int qeth_l3_delete_ip(struct qeth_card *card, struct qeth_ipaddr *addr)
unsigned long flags;
int rc = 0;
- QETH_DBF_TEXT(TRACE, 4, "delip");
+ QETH_CARD_TEXT(card, 4, "delip");
if (addr->proto == QETH_PROT_IPV4)
- QETH_DBF_HEX(TRACE, 4, &addr->u.a4.addr, 4);
+ QETH_CARD_HEX(card, 4, &addr->u.a4.addr, 4);
else {
- QETH_DBF_HEX(TRACE, 4, &addr->u.a6.addr, 8);
- QETH_DBF_HEX(TRACE, 4, ((char *)&addr->u.a6.addr) + 8, 8);
+ QETH_CARD_HEX(card, 4, &addr->u.a6.addr, 8);
+ QETH_CARD_HEX(card, 4, ((char *)&addr->u.a6.addr) + 8, 8);
}
spin_lock_irqsave(&card->ip_lock, flags);
rc = __qeth_l3_insert_ip_todo(card, addr, 0);
@@ -320,12 +320,12 @@ static int qeth_l3_add_ip(struct qeth_card *card, struct qeth_ipaddr *addr)
unsigned long flags;
int rc = 0;
- QETH_DBF_TEXT(TRACE, 4, "addip");
+ QETH_CARD_TEXT(card, 4, "addip");
if (addr->proto == QETH_PROT_IPV4)
- QETH_DBF_HEX(TRACE, 4, &addr->u.a4.addr, 4);
+ QETH_CARD_HEX(card, 4, &addr->u.a4.addr, 4);
else {
- QETH_DBF_HEX(TRACE, 4, &addr->u.a6.addr, 8);
- QETH_DBF_HEX(TRACE, 4, ((char *)&addr->u.a6.addr) + 8, 8);
+ QETH_CARD_HEX(card, 4, &addr->u.a6.addr, 8);
+ QETH_CARD_HEX(card, 4, ((char *)&addr->u.a6.addr) + 8, 8);
}
spin_lock_irqsave(&card->ip_lock, flags);
rc = __qeth_l3_insert_ip_todo(card, addr, 1);
@@ -353,10 +353,10 @@ static void qeth_l3_delete_mc_addresses(struct qeth_card *card)
struct qeth_ipaddr *iptodo;
unsigned long flags;
- QETH_DBF_TEXT(TRACE, 4, "delmc");
+ QETH_CARD_TEXT(card, 4, "delmc");
iptodo = qeth_l3_get_addr_buffer(QETH_PROT_IPV4);
if (!iptodo) {
- QETH_DBF_TEXT(TRACE, 2, "dmcnomem");
+ QETH_CARD_TEXT(card, 2, "dmcnomem");
return;
}
iptodo->type = QETH_IP_TYPE_DEL_ALL_MC;
@@ -457,8 +457,8 @@ static void qeth_l3_set_ip_addr_list(struct qeth_card *card)
unsigned long flags;
int rc;
- QETH_DBF_TEXT(TRACE, 2, "sdiplist");
- QETH_DBF_HEX(TRACE, 2, &card, sizeof(void *));
+ QETH_CARD_TEXT(card, 2, "sdiplist");
+ QETH_CARD_HEX(card, 2, &card, sizeof(void *));
if (card->options.sniffer)
return;
@@ -466,7 +466,7 @@ static void qeth_l3_set_ip_addr_list(struct qeth_card *card)
tbd_list = card->ip_tbd_list;
card->ip_tbd_list = kmalloc(sizeof(struct list_head), GFP_ATOMIC);
if (!card->ip_tbd_list) {
- QETH_DBF_TEXT(TRACE, 0, "silnomem");
+ QETH_CARD_TEXT(card, 0, "silnomem");
card->ip_tbd_list = tbd_list;
spin_unlock_irqrestore(&card->ip_lock, flags);
return;
@@ -517,7 +517,7 @@ static void qeth_l3_clear_ip_list(struct qeth_card *card, int clean,
struct qeth_ipaddr *addr, *tmp;
unsigned long flags;
- QETH_DBF_TEXT(TRACE, 4, "clearip");
+ QETH_CARD_TEXT(card, 4, "clearip");
if (recover && card->options.sniffer)
return;
spin_lock_irqsave(&card->ip_lock, flags);
@@ -577,7 +577,7 @@ static int qeth_l3_send_setdelmc(struct qeth_card *card,
struct qeth_cmd_buffer *iob;
struct qeth_ipa_cmd *cmd;
- QETH_DBF_TEXT(TRACE, 4, "setdelmc");
+ QETH_CARD_TEXT(card, 4, "setdelmc");
iob = qeth_get_ipacmd_buffer(card, ipacmd, addr->proto);
cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE);
@@ -615,8 +615,8 @@ static int qeth_l3_send_setdelip(struct qeth_card *card,
struct qeth_ipa_cmd *cmd;
__u8 netmask[16];
- QETH_DBF_TEXT(TRACE, 4, "setdelip");
- QETH_DBF_TEXT_(TRACE, 4, "flags%02X", flags);
+ QETH_CARD_TEXT(card, 4, "setdelip");
+ QETH_CARD_TEXT_(card, 4, "flags%02X", flags);
iob = qeth_get_ipacmd_buffer(card, ipacmd, addr->proto);
cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE);
@@ -645,7 +645,7 @@ static int qeth_l3_send_setrouting(struct qeth_card *card,
struct qeth_ipa_cmd *cmd;
struct qeth_cmd_buffer *iob;
- QETH_DBF_TEXT(TRACE, 4, "setroutg");
+ QETH_CARD_TEXT(card, 4, "setroutg");
iob = qeth_get_ipacmd_buffer(card, IPA_CMD_SETRTG, prot);
cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE);
cmd->data.setrtg.type = (type);
@@ -689,7 +689,7 @@ int qeth_l3_setrouting_v4(struct qeth_card *card)
{
int rc;
- QETH_DBF_TEXT(TRACE, 3, "setrtg4");
+ QETH_CARD_TEXT(card, 3, "setrtg4");
qeth_l3_correct_routing_type(card, &card->options.route4.type,
QETH_PROT_IPV4);
@@ -709,7 +709,7 @@ int qeth_l3_setrouting_v6(struct qeth_card *card)
{
int rc = 0;
- QETH_DBF_TEXT(TRACE, 3, "setrtg6");
+ QETH_CARD_TEXT(card, 3, "setrtg6");
#ifdef CONFIG_QETH_IPV6
if (!qeth_is_supported(card, IPA_IPV6))
@@ -753,7 +753,7 @@ int qeth_l3_add_ipato_entry(struct qeth_card *card,
unsigned long flags;
int rc = 0;
- QETH_DBF_TEXT(TRACE, 2, "addipato");
+ QETH_CARD_TEXT(card, 2, "addipato");
spin_lock_irqsave(&card->ip_lock, flags);
list_for_each_entry(ipatoe, &card->ipato.entries, entry) {
if (ipatoe->proto != new->proto)
@@ -778,7 +778,7 @@ void qeth_l3_del_ipato_entry(struct qeth_card *card,
struct qeth_ipato_entry *ipatoe, *tmp;
unsigned long flags;
- QETH_DBF_TEXT(TRACE, 2, "delipato");
+ QETH_CARD_TEXT(card, 2, "delipato");
spin_lock_irqsave(&card->ip_lock, flags);
list_for_each_entry_safe(ipatoe, tmp, &card->ipato.entries, entry) {
if (ipatoe->proto != proto)
@@ -806,11 +806,11 @@ int qeth_l3_add_vipa(struct qeth_card *card, enum qeth_prot_versions proto,
ipaddr = qeth_l3_get_addr_buffer(proto);
if (ipaddr) {
if (proto == QETH_PROT_IPV4) {
- QETH_DBF_TEXT(TRACE, 2, "addvipa4");
+ QETH_CARD_TEXT(card, 2, "addvipa4");
memcpy(&ipaddr->u.a4.addr, addr, 4);
ipaddr->u.a4.mask = 0;
} else if (proto == QETH_PROT_IPV6) {
- QETH_DBF_TEXT(TRACE, 2, "addvipa6");
+ QETH_CARD_TEXT(card, 2, "addvipa6");
memcpy(&ipaddr->u.a6.addr, addr, 16);
ipaddr->u.a6.pfxlen = 0;
}
@@ -841,11 +841,11 @@ void qeth_l3_del_vipa(struct qeth_card *card, enum qeth_prot_versions proto,
ipaddr = qeth_l3_get_addr_buffer(proto);
if (ipaddr) {
if (proto == QETH_PROT_IPV4) {
- QETH_DBF_TEXT(TRACE, 2, "delvipa4");
+ QETH_CARD_TEXT(card, 2, "delvipa4");
memcpy(&ipaddr->u.a4.addr, addr, 4);
ipaddr->u.a4.mask = 0;
} else if (proto == QETH_PROT_IPV6) {
- QETH_DBF_TEXT(TRACE, 2, "delvipa6");
+ QETH_CARD_TEXT(card, 2, "delvipa6");
memcpy(&ipaddr->u.a6.addr, addr, 16);
ipaddr->u.a6.pfxlen = 0;
}
@@ -870,11 +870,11 @@ int qeth_l3_add_rxip(struct qeth_card *card, enum qeth_prot_versions proto,
ipaddr = qeth_l3_get_addr_buffer(proto);
if (ipaddr) {
if (proto == QETH_PROT_IPV4) {
- QETH_DBF_TEXT(TRACE, 2, "addrxip4");
+ QETH_CARD_TEXT(card, 2, "addrxip4");
memcpy(&ipaddr->u.a4.addr, addr, 4);
ipaddr->u.a4.mask = 0;
} else if (proto == QETH_PROT_IPV6) {
- QETH_DBF_TEXT(TRACE, 2, "addrxip6");
+ QETH_CARD_TEXT(card, 2, "addrxip6");
memcpy(&ipaddr->u.a6.addr, addr, 16);
ipaddr->u.a6.pfxlen = 0;
}
@@ -905,11 +905,11 @@ void qeth_l3_del_rxip(struct qeth_card *card, enum qeth_prot_versions proto,
ipaddr = qeth_l3_get_addr_buffer(proto);
if (ipaddr) {
if (proto == QETH_PROT_IPV4) {
- QETH_DBF_TEXT(TRACE, 2, "addrxip4");
+ QETH_CARD_TEXT(card, 2, "addrxip4");
memcpy(&ipaddr->u.a4.addr, addr, 4);
ipaddr->u.a4.mask = 0;
} else if (proto == QETH_PROT_IPV6) {
- QETH_DBF_TEXT(TRACE, 2, "addrxip6");
+ QETH_CARD_TEXT(card, 2, "addrxip6");
memcpy(&ipaddr->u.a6.addr, addr, 16);
ipaddr->u.a6.pfxlen = 0;
}
@@ -929,15 +929,15 @@ static int qeth_l3_register_addr_entry(struct qeth_card *card,
int cnt = 3;
if (addr->proto == QETH_PROT_IPV4) {
- QETH_DBF_TEXT(TRACE, 2, "setaddr4");
- QETH_DBF_HEX(TRACE, 3, &addr->u.a4.addr, sizeof(int));
+ QETH_CARD_TEXT(card, 2, "setaddr4");
+ QETH_CARD_HEX(card, 3, &addr->u.a4.addr, sizeof(int));
} else if (addr->proto == QETH_PROT_IPV6) {
- QETH_DBF_TEXT(TRACE, 2, "setaddr6");
- QETH_DBF_HEX(TRACE, 3, &addr->u.a6.addr, 8);
- QETH_DBF_HEX(TRACE, 3, ((char *)&addr->u.a6.addr) + 8, 8);
+ QETH_CARD_TEXT(card, 2, "setaddr6");
+ QETH_CARD_HEX(card, 3, &addr->u.a6.addr, 8);
+ QETH_CARD_HEX(card, 3, ((char *)&addr->u.a6.addr) + 8, 8);
} else {
- QETH_DBF_TEXT(TRACE, 2, "setaddr?");
- QETH_DBF_HEX(TRACE, 3, addr, sizeof(struct qeth_ipaddr));
+ QETH_CARD_TEXT(card, 2, "setaddr?");
+ QETH_CARD_HEX(card, 3, addr, sizeof(struct qeth_ipaddr));
}
do {
if (addr->is_multicast)
@@ -946,10 +946,10 @@ static int qeth_l3_register_addr_entry(struct qeth_card *card,
rc = qeth_l3_send_setdelip(card, addr, IPA_CMD_SETIP,
addr->set_flags);
if (rc)
- QETH_DBF_TEXT(TRACE, 2, "failed");
+ QETH_CARD_TEXT(card, 2, "failed");
} while ((--cnt > 0) && rc);
if (rc) {
- QETH_DBF_TEXT(TRACE, 2, "FAILED");
+ QETH_CARD_TEXT(card, 2, "FAILED");
qeth_l3_ipaddr_to_string(addr->proto, (u8 *)&addr->u, buf);
dev_warn(&card->gdev->dev,
"Registering IP address %s failed\n", buf);
@@ -963,15 +963,15 @@ static int qeth_l3_deregister_addr_entry(struct qeth_card *card,
int rc = 0;
if (addr->proto == QETH_PROT_IPV4) {
- QETH_DBF_TEXT(TRACE, 2, "deladdr4");
- QETH_DBF_HEX(TRACE, 3, &addr->u.a4.addr, sizeof(int));
+ QETH_CARD_TEXT(card, 2, "deladdr4");
+ QETH_CARD_HEX(card, 3, &addr->u.a4.addr, sizeof(int));
} else if (addr->proto == QETH_PROT_IPV6) {
- QETH_DBF_TEXT(TRACE, 2, "deladdr6");
- QETH_DBF_HEX(TRACE, 3, &addr->u.a6.addr, 8);
- QETH_DBF_HEX(TRACE, 3, ((char *)&addr->u.a6.addr) + 8, 8);
+ QETH_CARD_TEXT(card, 2, "deladdr6");
+ QETH_CARD_HEX(card, 3, &addr->u.a6.addr, 8);
+ QETH_CARD_HEX(card, 3, ((char *)&addr->u.a6.addr) + 8, 8);
} else {
- QETH_DBF_TEXT(TRACE, 2, "deladdr?");
- QETH_DBF_HEX(TRACE, 3, addr, sizeof(struct qeth_ipaddr));
+ QETH_CARD_TEXT(card, 2, "deladdr?");
+ QETH_CARD_HEX(card, 3, addr, sizeof(struct qeth_ipaddr));
}
if (addr->is_multicast)
rc = qeth_l3_send_setdelmc(card, addr, IPA_CMD_DELIPM);
@@ -979,7 +979,7 @@ static int qeth_l3_deregister_addr_entry(struct qeth_card *card,
rc = qeth_l3_send_setdelip(card, addr, IPA_CMD_DELIP,
addr->del_flags);
if (rc)
- QETH_DBF_TEXT(TRACE, 2, "failed");
+ QETH_CARD_TEXT(card, 2, "failed");
return rc;
}
@@ -1012,7 +1012,7 @@ static int qeth_l3_send_setadp_mode(struct qeth_card *card, __u32 command,
struct qeth_cmd_buffer *iob;
struct qeth_ipa_cmd *cmd;
- QETH_DBF_TEXT(TRACE, 4, "adpmode");
+ QETH_CARD_TEXT(card, 4, "adpmode");
iob = qeth_get_adapter_cmd(card, command,
sizeof(struct qeth_ipacmd_setadpparms));
@@ -1027,7 +1027,7 @@ static int qeth_l3_setadapter_hstr(struct qeth_card *card)
{
int rc;
- QETH_DBF_TEXT(TRACE, 4, "adphstr");
+ QETH_CARD_TEXT(card, 4, "adphstr");
if (qeth_adp_supported(card, IPA_SETADP_SET_BROADCAST_MODE)) {
rc = qeth_l3_send_setadp_mode(card,
@@ -1093,7 +1093,7 @@ static int qeth_l3_default_setassparms_cb(struct qeth_card *card,
{
struct qeth_ipa_cmd *cmd;
- QETH_DBF_TEXT(TRACE, 4, "defadpcb");
+ QETH_CARD_TEXT(card, 4, "defadpcb");
cmd = (struct qeth_ipa_cmd *) data;
if (cmd->hdr.return_code == 0) {
@@ -1106,13 +1106,13 @@ static int qeth_l3_default_setassparms_cb(struct qeth_card *card,
if (cmd->data.setassparms.hdr.assist_no == IPA_INBOUND_CHECKSUM &&
cmd->data.setassparms.hdr.command_code == IPA_CMD_ASS_START) {
card->info.csum_mask = cmd->data.setassparms.data.flags_32bit;
- QETH_DBF_TEXT_(TRACE, 3, "csum:%d", card->info.csum_mask);
+ QETH_CARD_TEXT_(card, 3, "csum:%d", card->info.csum_mask);
}
if (cmd->data.setassparms.hdr.assist_no == IPA_OUTBOUND_CHECKSUM &&
cmd->data.setassparms.hdr.command_code == IPA_CMD_ASS_START) {
card->info.tx_csum_mask =
cmd->data.setassparms.data.flags_32bit;
- QETH_DBF_TEXT_(TRACE, 3, "tcsu:%d", card->info.tx_csum_mask);
+ QETH_CARD_TEXT_(card, 3, "tcsu:%d", card->info.tx_csum_mask);
}
return 0;
@@ -1125,7 +1125,7 @@ static struct qeth_cmd_buffer *qeth_l3_get_setassparms_cmd(
struct qeth_cmd_buffer *iob;
struct qeth_ipa_cmd *cmd;
- QETH_DBF_TEXT(TRACE, 4, "getasscm");
+ QETH_CARD_TEXT(card, 4, "getasscm");
iob = qeth_get_ipacmd_buffer(card, IPA_CMD_SETASSPARMS, prot);
cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE);
@@ -1147,7 +1147,7 @@ static int qeth_l3_send_setassparms(struct qeth_card *card,
int rc;
struct qeth_ipa_cmd *cmd;
- QETH_DBF_TEXT(TRACE, 4, "sendassp");
+ QETH_CARD_TEXT(card, 4, "sendassp");
cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE);
if (len <= sizeof(__u32))
@@ -1166,7 +1166,7 @@ static int qeth_l3_send_simple_setassparms_ipv6(struct qeth_card *card,
int rc;
struct qeth_cmd_buffer *iob;
- QETH_DBF_TEXT(TRACE, 4, "simassp6");
+ QETH_CARD_TEXT(card, 4, "simassp6");
iob = qeth_l3_get_setassparms_cmd(card, ipa_func, cmd_code,
0, QETH_PROT_IPV6);
rc = qeth_l3_send_setassparms(card, iob, 0, 0,
@@ -1182,7 +1182,7 @@ static int qeth_l3_send_simple_setassparms(struct qeth_card *card,
int length = 0;
struct qeth_cmd_buffer *iob;
- QETH_DBF_TEXT(TRACE, 4, "simassp4");
+ QETH_CARD_TEXT(card, 4, "simassp4");
if (data)
length = sizeof(__u32);
iob = qeth_l3_get_setassparms_cmd(card, ipa_func, cmd_code,
@@ -1196,7 +1196,7 @@ static int qeth_l3_start_ipa_arp_processing(struct qeth_card *card)
{
int rc;
- QETH_DBF_TEXT(TRACE, 3, "ipaarp");
+ QETH_CARD_TEXT(card, 3, "ipaarp");
if (!qeth_is_supported(card, IPA_ARP_PROCESSING)) {
dev_info(&card->gdev->dev,
@@ -1218,7 +1218,7 @@ static int qeth_l3_start_ipa_ip_fragmentation(struct qeth_card *card)
{
int rc;
- QETH_DBF_TEXT(TRACE, 3, "ipaipfrg");
+ QETH_CARD_TEXT(card, 3, "ipaipfrg");
if (!qeth_is_supported(card, IPA_IP_FRAGMENTATION)) {
dev_info(&card->gdev->dev,
@@ -1243,7 +1243,7 @@ static int qeth_l3_start_ipa_source_mac(struct qeth_card *card)
{
int rc;
- QETH_DBF_TEXT(TRACE, 3, "stsrcmac");
+ QETH_CARD_TEXT(card, 3, "stsrcmac");
if (!qeth_is_supported(card, IPA_SOURCE_MAC)) {
dev_info(&card->gdev->dev,
@@ -1265,7 +1265,7 @@ static int qeth_l3_start_ipa_vlan(struct qeth_card *card)
{
int rc = 0;
- QETH_DBF_TEXT(TRACE, 3, "strtvlan");
+ QETH_CARD_TEXT(card, 3, "strtvlan");
if (!qeth_is_supported(card, IPA_FULL_VLAN)) {
dev_info(&card->gdev->dev,
@@ -1289,7 +1289,7 @@ static int qeth_l3_start_ipa_multicast(struct qeth_card *card)
{
int rc;
- QETH_DBF_TEXT(TRACE, 3, "stmcast");
+ QETH_CARD_TEXT(card, 3, "stmcast");
if (!qeth_is_supported(card, IPA_MULTICASTING)) {
dev_info(&card->gdev->dev,
@@ -1349,7 +1349,7 @@ static int qeth_l3_softsetup_ipv6(struct qeth_card *card)
{
int rc;
- QETH_DBF_TEXT(TRACE, 3, "softipv6");
+ QETH_CARD_TEXT(card, 3, "softipv6");
if (card->info.type == QETH_CARD_TYPE_IQD)
goto out;
@@ -1395,7 +1395,7 @@ static int qeth_l3_start_ipa_ipv6(struct qeth_card *card)
{
int rc = 0;
- QETH_DBF_TEXT(TRACE, 3, "strtipv6");
+ QETH_CARD_TEXT(card, 3, "strtipv6");
if (!qeth_is_supported(card, IPA_IPV6)) {
dev_info(&card->gdev->dev,
@@ -1412,7 +1412,7 @@ static int qeth_l3_start_ipa_broadcast(struct qeth_card *card)
{
int rc;
- QETH_DBF_TEXT(TRACE, 3, "stbrdcst");
+ QETH_CARD_TEXT(card, 3, "stbrdcst");
card->info.broadcast_capable = 0;
if (!qeth_is_supported(card, IPA_FILTERING)) {
dev_info(&card->gdev->dev,
@@ -1512,7 +1512,7 @@ static int qeth_l3_start_ipa_checksum(struct qeth_card *card)
{
int rc = 0;
- QETH_DBF_TEXT(TRACE, 3, "strtcsum");
+ QETH_CARD_TEXT(card, 3, "strtcsum");
if (card->options.checksum_type == NO_CHECKSUMMING) {
dev_info(&card->gdev->dev,
@@ -1569,7 +1569,7 @@ static int qeth_l3_start_ipa_tso(struct qeth_card *card)
{
int rc;
- QETH_DBF_TEXT(TRACE, 3, "sttso");
+ QETH_CARD_TEXT(card, 3, "sttso");
if (!qeth_is_supported(card, IPA_OUTBOUND_TSO)) {
dev_info(&card->gdev->dev,
@@ -1596,7 +1596,7 @@ static int qeth_l3_start_ipa_tso(struct qeth_card *card)
static int qeth_l3_start_ipassists(struct qeth_card *card)
{
- QETH_DBF_TEXT(TRACE, 3, "strtipas");
+ QETH_CARD_TEXT(card, 3, "strtipas");
qeth_set_access_ctrl_online(card); /* go on*/
qeth_l3_start_ipa_arp_processing(card); /* go on*/
@@ -1619,7 +1619,7 @@ static int qeth_l3_put_unique_id(struct qeth_card *card)
struct qeth_cmd_buffer *iob;
struct qeth_ipa_cmd *cmd;
- QETH_DBF_TEXT(TRACE, 2, "puniqeid");
+ QETH_CARD_TEXT(card, 2, "puniqeid");
if ((card->info.unique_id & UNIQUE_ID_NOT_BY_CARD) ==
UNIQUE_ID_NOT_BY_CARD)
@@ -1723,7 +1723,7 @@ qeth_diags_trace_cb(struct qeth_card *card, struct qeth_reply *reply,
cmd = (struct qeth_ipa_cmd *)data;
rc = cmd->hdr.return_code;
if (rc)
- QETH_DBF_TEXT_(TRACE, 2, "dxter%x", rc);
+ QETH_CARD_TEXT_(card, 2, "dxter%x", rc);
switch (cmd->data.diagass.action) {
case QETH_DIAGS_CMD_TRACE_QUERY:
break;
@@ -1800,7 +1800,7 @@ static void qeth_l3_add_mc(struct qeth_card *card, struct in_device *in4_dev)
struct ip_mc_list *im4;
char buf[MAX_ADDR_LEN];
- QETH_DBF_TEXT(TRACE, 4, "addmc");
+ QETH_CARD_TEXT(card, 4, "addmc");
for (im4 = in4_dev->mc_list; im4; im4 = im4->next) {
qeth_l3_get_mac_for_ipm(im4->multiaddr, buf, in4_dev->dev);
ipm = qeth_l3_get_addr_buffer(QETH_PROT_IPV4);
@@ -1820,7 +1820,7 @@ static void qeth_l3_add_vlan_mc(struct qeth_card *card)
struct vlan_group *vg;
int i;
- QETH_DBF_TEXT(TRACE, 4, "addmcvl");
+ QETH_CARD_TEXT(card, 4, "addmcvl");
if (!qeth_is_supported(card, IPA_FULL_VLAN) || (card->vlangrp == NULL))
return;
@@ -1844,7 +1844,7 @@ static void qeth_l3_add_multicast_ipv4(struct qeth_card *card)
{
struct in_device *in4_dev;
- QETH_DBF_TEXT(TRACE, 4, "chkmcv4");
+ QETH_CARD_TEXT(card, 4, "chkmcv4");
in4_dev = in_dev_get(card->dev);
if (in4_dev == NULL)
return;
@@ -1862,7 +1862,7 @@ static void qeth_l3_add_mc6(struct qeth_card *card, struct inet6_dev *in6_dev)
struct ifmcaddr6 *im6;
char buf[MAX_ADDR_LEN];
- QETH_DBF_TEXT(TRACE, 4, "addmc6");
+ QETH_CARD_TEXT(card, 4, "addmc6");
for (im6 = in6_dev->mc_list; im6 != NULL; im6 = im6->next) {
ndisc_mc_map(&im6->mca_addr, buf, in6_dev->dev, 0);
ipm = qeth_l3_get_addr_buffer(QETH_PROT_IPV6);
@@ -1883,7 +1883,7 @@ static void qeth_l3_add_vlan_mc6(struct qeth_card *card)
struct vlan_group *vg;
int i;
- QETH_DBF_TEXT(TRACE, 4, "admc6vl");
+ QETH_CARD_TEXT(card, 4, "admc6vl");
if (!qeth_is_supported(card, IPA_FULL_VLAN) || (card->vlangrp == NULL))
return;
@@ -1907,7 +1907,7 @@ static void qeth_l3_add_multicast_ipv6(struct qeth_card *card)
{
struct inet6_dev *in6_dev;
- QETH_DBF_TEXT(TRACE, 4, "chkmcv6");
+ QETH_CARD_TEXT(card, 4, "chkmcv6");
if (!qeth_is_supported(card, IPA_IPV6))
return ;
in6_dev = in6_dev_get(card->dev);
@@ -1928,7 +1928,7 @@ static void qeth_l3_free_vlan_addresses4(struct qeth_card *card,
struct in_ifaddr *ifa;
struct qeth_ipaddr *addr;
- QETH_DBF_TEXT(TRACE, 4, "frvaddr4");
+ QETH_CARD_TEXT(card, 4, "frvaddr4");
in_dev = in_dev_get(vlan_group_get_device(card->vlangrp, vid));
if (!in_dev)
@@ -1954,7 +1954,7 @@ static void qeth_l3_free_vlan_addresses6(struct qeth_card *card,
struct inet6_ifaddr *ifa;
struct qeth_ipaddr *addr;
- QETH_DBF_TEXT(TRACE, 4, "frvaddr6");
+ QETH_CARD_TEXT(card, 4, "frvaddr6");
in6_dev = in6_dev_get(vlan_group_get_device(card->vlangrp, vid));
if (!in6_dev)
@@ -1989,7 +1989,7 @@ static void qeth_l3_vlan_rx_register(struct net_device *dev,
struct qeth_card *card = dev->ml_priv;
unsigned long flags;
- QETH_DBF_TEXT(TRACE, 4, "vlanreg");
+ QETH_CARD_TEXT(card, 4, "vlanreg");
spin_lock_irqsave(&card->vlanlock, flags);
card->vlangrp = grp;
spin_unlock_irqrestore(&card->vlanlock, flags);
@@ -2005,9 +2005,9 @@ static void qeth_l3_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid)
struct qeth_card *card = dev->ml_priv;
unsigned long flags;
- QETH_DBF_TEXT_(TRACE, 4, "kid:%d", vid);
+ QETH_CARD_TEXT_(card, 4, "kid:%d", vid);
if (qeth_wait_for_threads(card, QETH_RECOVER_THREAD)) {
- QETH_DBF_TEXT(TRACE, 3, "kidREC");
+ QETH_CARD_TEXT(card, 3, "kidREC");
return;
}
spin_lock_irqsave(&card->vlanlock, flags);
@@ -2162,7 +2162,7 @@ static void qeth_l3_process_inbound_buffer(struct qeth_card *card,
break;
default:
dev_kfree_skb_any(skb);
- QETH_DBF_TEXT(TRACE, 3, "inbunkno");
+ QETH_CARD_TEXT(card, 3, "inbunkno");
QETH_DBF_HEX(CTRL, 3, hdr, QETH_DBF_CTRL_LEN);
continue;
}
@@ -2229,7 +2229,8 @@ static struct qeth_card *qeth_l3_get_card_from_dev(struct net_device *dev)
card = vlan_dev_real_dev(dev)->ml_priv;
if (card && card->options.layer2)
card = NULL;
- QETH_DBF_TEXT_(TRACE, 4, "%d", rc);
+ if (card)
+ QETH_CARD_TEXT_(card, 4, "%d", rc);
return card ;
}
@@ -2307,10 +2308,10 @@ qeth_l3_handle_promisc_mode(struct qeth_card *card)
} else if (card->options.sniffer && /* HiperSockets trace */
qeth_adp_supported(card, IPA_SETADP_SET_DIAG_ASSIST)) {
if (dev->flags & IFF_PROMISC) {
- QETH_DBF_TEXT(TRACE, 3, "+promisc");
+ QETH_CARD_TEXT(card, 3, "+promisc");
qeth_diags_trace(card, QETH_DIAGS_CMD_TRACE_ENABLE);
} else {
- QETH_DBF_TEXT(TRACE, 3, "-promisc");
+ QETH_CARD_TEXT(card, 3, "-promisc");
qeth_diags_trace(card, QETH_DIAGS_CMD_TRACE_DISABLE);
}
}
@@ -2320,7 +2321,7 @@ static void qeth_l3_set_multicast_list(struct net_device *dev)
{
struct qeth_card *card = dev->ml_priv;
- QETH_DBF_TEXT(TRACE, 3, "setmulti");
+ QETH_CARD_TEXT(card, 3, "setmulti");
if (qeth_threads_running(card, QETH_RECOVER_THREAD) &&
(card->state != CARD_STATE_UP))
return;
@@ -2365,7 +2366,7 @@ static int qeth_l3_arp_set_no_entries(struct qeth_card *card, int no_entries)
int tmp;
int rc;
- QETH_DBF_TEXT(TRACE, 3, "arpstnoe");
+ QETH_CARD_TEXT(card, 3, "arpstnoe");
/*
* currently GuestLAN only supports the ARP assist function
@@ -2417,17 +2418,17 @@ static int qeth_l3_arp_query_cb(struct qeth_card *card,
int uentry_size;
int i;
- QETH_DBF_TEXT(TRACE, 4, "arpquecb");
+ QETH_CARD_TEXT(card, 4, "arpquecb");
qinfo = (struct qeth_arp_query_info *) reply->param;
cmd = (struct qeth_ipa_cmd *) data;
if (cmd->hdr.return_code) {
- QETH_DBF_TEXT_(TRACE, 4, "qaer1%i", cmd->hdr.return_code);
+ QETH_CARD_TEXT_(card, 4, "qaer1%i", cmd->hdr.return_code);
return 0;
}
if (cmd->data.setassparms.hdr.return_code) {
cmd->hdr.return_code = cmd->data.setassparms.hdr.return_code;
- QETH_DBF_TEXT_(TRACE, 4, "qaer2%i", cmd->hdr.return_code);
+ QETH_CARD_TEXT_(card, 4, "qaer2%i", cmd->hdr.return_code);
return 0;
}
qdata = &cmd->data.setassparms.data.query_arp;
@@ -2449,14 +2450,14 @@ static int qeth_l3_arp_query_cb(struct qeth_card *card,
/* check if there is enough room in userspace */
if ((qinfo->udata_len - qinfo->udata_offset) <
qdata->no_entries * uentry_size){
- QETH_DBF_TEXT_(TRACE, 4, "qaer3%i", -ENOMEM);
+ QETH_CARD_TEXT_(card, 4, "qaer3%i", -ENOMEM);
cmd->hdr.return_code = -ENOMEM;
goto out_error;
}
- QETH_DBF_TEXT_(TRACE, 4, "anore%i",
+ QETH_CARD_TEXT_(card, 4, "anore%i",
cmd->data.setassparms.hdr.number_of_replies);
- QETH_DBF_TEXT_(TRACE, 4, "aseqn%i", cmd->data.setassparms.hdr.seq_no);
- QETH_DBF_TEXT_(TRACE, 4, "anoen%i", qdata->no_entries);
+ QETH_CARD_TEXT_(card, 4, "aseqn%i", cmd->data.setassparms.hdr.seq_no);
+ QETH_CARD_TEXT_(card, 4, "anoen%i", qdata->no_entries);
if (qinfo->mask_bits & QETH_QARP_STRIP_ENTRIES) {
/* strip off "media specific information" */
@@ -2492,7 +2493,7 @@ static int qeth_l3_send_ipa_arp_cmd(struct qeth_card *card,
unsigned long),
void *reply_param)
{
- QETH_DBF_TEXT(TRACE, 4, "sendarp");
+ QETH_CARD_TEXT(card, 4, "sendarp");
memcpy(iob->data, IPA_PDU_HEADER, IPA_PDU_HEADER_SIZE);
memcpy(QETH_IPA_CMD_DEST_ADDR(iob->data),
@@ -2508,7 +2509,7 @@ static int qeth_l3_arp_query(struct qeth_card *card, char __user *udata)
int tmp;
int rc;
- QETH_DBF_TEXT(TRACE, 3, "arpquery");
+ QETH_CARD_TEXT(card, 3, "arpquery");
if (!qeth_is_supported(card,/*IPA_QUERY_ARP_ADDR_INFO*/
IPA_ARP_PROCESSING)) {
@@ -2551,7 +2552,7 @@ static int qeth_l3_arp_add_entry(struct qeth_card *card,
int tmp;
int rc;
- QETH_DBF_TEXT(TRACE, 3, "arpadent");
+ QETH_CARD_TEXT(card, 3, "arpadent");
/*
* currently GuestLAN only supports the ARP assist function
@@ -2590,7 +2591,7 @@ static int qeth_l3_arp_remove_entry(struct qeth_card *card,
int tmp;
int rc;
- QETH_DBF_TEXT(TRACE, 3, "arprment");
+ QETH_CARD_TEXT(card, 3, "arprment");
/*
* currently GuestLAN only supports the ARP assist function
@@ -2626,7 +2627,7 @@ static int qeth_l3_arp_flush_cache(struct qeth_card *card)
int rc;
int tmp;
- QETH_DBF_TEXT(TRACE, 3, "arpflush");
+ QETH_CARD_TEXT(card, 3, "arpflush");
/*
* currently GuestLAN only supports the ARP assist function
@@ -2734,7 +2735,7 @@ static int qeth_l3_do_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
rc = -EOPNOTSUPP;
}
if (rc)
- QETH_DBF_TEXT_(TRACE, 2, "ioce%d", rc);
+ QETH_CARD_TEXT_(card, 2, "ioce%d", rc);
return rc;
}
@@ -2903,19 +2904,11 @@ static inline int qeth_l3_tso_elements(struct sk_buff *skb)
unsigned long tcpd = (unsigned long)tcp_hdr(skb) +
tcp_hdr(skb)->doff * 4;
int tcpd_len = skb->len - (tcpd - (unsigned long)skb->data);
- int elements = PFN_UP(tcpd + tcpd_len) - PFN_DOWN(tcpd);
+ int elements = PFN_UP(tcpd + tcpd_len - 1) - PFN_DOWN(tcpd);
elements += skb_shinfo(skb)->nr_frags;
return elements;
}
-static inline int qeth_l3_tso_check(struct sk_buff *skb)
-{
- int len = ((unsigned long)tcp_hdr(skb) + tcp_hdr(skb)->doff * 4) -
- (unsigned long)skb->data;
- return (((unsigned long)skb->data & PAGE_MASK) !=
- (((unsigned long)skb->data + len) & PAGE_MASK));
-}
-
static int qeth_l3_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
int rc;
@@ -3015,8 +3008,6 @@ static int qeth_l3_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
(cast_type == RTN_UNSPEC)) {
hdr = (struct qeth_hdr *)skb_push(new_skb,
sizeof(struct qeth_hdr_tso));
- if (qeth_l3_tso_check(new_skb))
- QETH_DBF_MESSAGE(2, "tso skb misaligned\n");
memset(hdr, 0, sizeof(struct qeth_hdr_tso));
qeth_l3_fill_header(card, hdr, new_skb, ipv, cast_type);
qeth_tso_fill_header(card, hdr, new_skb);
@@ -3047,10 +3038,20 @@ static int qeth_l3_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
elements_needed += elems;
nr_frags = skb_shinfo(new_skb)->nr_frags;
- if (card->info.type != QETH_CARD_TYPE_IQD)
+ if (card->info.type != QETH_CARD_TYPE_IQD) {
+ int len;
+ if (large_send == QETH_LARGE_SEND_TSO)
+ len = ((unsigned long)tcp_hdr(new_skb) +
+ tcp_hdr(new_skb)->doff * 4) -
+ (unsigned long)new_skb->data;
+ else
+ len = sizeof(struct qeth_hdr_layer3);
+
+ if (qeth_hdr_chk_and_bounce(new_skb, len))
+ goto tx_drop;
rc = qeth_do_send_packet(card, queue, new_skb, hdr,
elements_needed);
- else
+ } else
rc = qeth_do_send_packet_fast(card, queue, new_skb, hdr,
elements_needed, data_offset, 0);
@@ -3103,7 +3104,7 @@ static int qeth_l3_open(struct net_device *dev)
{
struct qeth_card *card = dev->ml_priv;
- QETH_DBF_TEXT(TRACE, 4, "qethopen");
+ QETH_CARD_TEXT(card, 4, "qethopen");
if (card->state != CARD_STATE_SOFTSETUP)
return -ENODEV;
card->data.state = CH_STATE_UP;
@@ -3119,7 +3120,7 @@ static int qeth_l3_stop(struct net_device *dev)
{
struct qeth_card *card = dev->ml_priv;
- QETH_DBF_TEXT(TRACE, 4, "qethstop");
+ QETH_CARD_TEXT(card, 4, "qethstop");
netif_tx_disable(dev);
if (card->state == CARD_STATE_UP)
card->state = CARD_STATE_SOFTSETUP;
@@ -3312,11 +3313,10 @@ static void qeth_l3_qdio_input_handler(struct ccw_device *ccwdev,
card->perf_stats.inbound_start_time = qeth_get_micros();
}
if (qdio_err & QDIO_ERROR_ACTIVATE_CHECK_CONDITION) {
- QETH_DBF_TEXT(TRACE, 1, "qdinchk");
- QETH_DBF_TEXT_(TRACE, 1, "%s", CARD_BUS_ID(card));
- QETH_DBF_TEXT_(TRACE, 1, "%04X%04X",
+ QETH_CARD_TEXT(card, 1, "qdinchk");
+ QETH_CARD_TEXT_(card, 1, "%04X%04X",
first_element, count);
- QETH_DBF_TEXT_(TRACE, 1, "%04X", queue);
+ QETH_CARD_TEXT_(card, 1, "%04X", queue);
qeth_schedule_recovery(card);
return;
}
@@ -3354,6 +3354,8 @@ static void qeth_l3_remove_device(struct ccwgroup_device *cgdev)
{
struct qeth_card *card = dev_get_drvdata(&cgdev->dev);
+ qeth_l3_remove_device_attributes(&cgdev->dev);
+
qeth_set_allowed_threads(card, 0, 1);
wait_event(card->wait_q, qeth_threads_running(card, 0xffffffff) == 0);
@@ -3367,7 +3369,6 @@ static void qeth_l3_remove_device(struct ccwgroup_device *cgdev)
card->dev = NULL;
}
- qeth_l3_remove_device_attributes(&cgdev->dev);
qeth_l3_clear_ip_list(card, 0, 0);
qeth_l3_clear_ipato_list(card);
return;
@@ -3380,6 +3381,7 @@ static int __qeth_l3_set_online(struct ccwgroup_device *gdev, int recovery_mode)
enum qeth_card_states recover_flag;
BUG_ON(!card);
+ mutex_lock(&card->discipline_mutex);
mutex_lock(&card->conf_mutex);
QETH_DBF_TEXT(SETUP, 2, "setonlin");
QETH_DBF_HEX(SETUP, 2, &card, sizeof(void *));
@@ -3461,6 +3463,7 @@ static int __qeth_l3_set_online(struct ccwgroup_device *gdev, int recovery_mode)
kobject_uevent(&gdev->dev.kobj, KOBJ_CHANGE);
out:
mutex_unlock(&card->conf_mutex);
+ mutex_unlock(&card->discipline_mutex);
return 0;
out_remove:
card->use_hard_stop = 1;
@@ -3473,6 +3476,7 @@ out_remove:
else
card->state = CARD_STATE_DOWN;
mutex_unlock(&card->conf_mutex);
+ mutex_unlock(&card->discipline_mutex);
return rc;
}
@@ -3488,6 +3492,7 @@ static int __qeth_l3_set_offline(struct ccwgroup_device *cgdev,
int rc = 0, rc2 = 0, rc3 = 0;
enum qeth_card_states recover_flag;
+ mutex_lock(&card->discipline_mutex);
mutex_lock(&card->conf_mutex);
QETH_DBF_TEXT(SETUP, 3, "setoffl");
QETH_DBF_HEX(SETUP, 3, &card, sizeof(void *));
@@ -3508,6 +3513,7 @@ static int __qeth_l3_set_offline(struct ccwgroup_device *cgdev,
/* let user_space know that device is offline */
kobject_uevent(&cgdev->dev.kobj, KOBJ_CHANGE);
mutex_unlock(&card->conf_mutex);
+ mutex_unlock(&card->discipline_mutex);
return 0;
}
@@ -3522,11 +3528,11 @@ static int qeth_l3_recover(void *ptr)
int rc = 0;
card = (struct qeth_card *) ptr;
- QETH_DBF_TEXT(TRACE, 2, "recover1");
- QETH_DBF_HEX(TRACE, 2, &card, sizeof(void *));
+ QETH_CARD_TEXT(card, 2, "recover1");
+ QETH_CARD_HEX(card, 2, &card, sizeof(void *));
if (!qeth_do_run_thread(card, QETH_RECOVER_THREAD))
return 0;
- QETH_DBF_TEXT(TRACE, 2, "recover2");
+ QETH_CARD_TEXT(card, 2, "recover2");
dev_warn(&card->gdev->dev,
"A recovery process has been started for the device\n");
card->use_hard_stop = 1;
@@ -3624,8 +3630,8 @@ static int qeth_l3_ip_event(struct notifier_block *this,
if (dev_net(dev) != &init_net)
return NOTIFY_DONE;
- QETH_DBF_TEXT(TRACE, 3, "ipevent");
card = qeth_l3_get_card_from_dev(dev);
+ QETH_CARD_TEXT(card, 3, "ipevent");
if (!card)
return NOTIFY_DONE;
@@ -3671,11 +3677,11 @@ static int qeth_l3_ip6_event(struct notifier_block *this,
struct qeth_ipaddr *addr;
struct qeth_card *card;
- QETH_DBF_TEXT(TRACE, 3, "ip6event");
card = qeth_l3_get_card_from_dev(dev);
if (!card)
return NOTIFY_DONE;
+ QETH_CARD_TEXT(card, 3, "ip6event");
if (!qeth_is_supported(card, IPA_IPV6))
return NOTIFY_DONE;
@@ -3714,7 +3720,7 @@ static int qeth_l3_register_notifiers(void)
{
int rc;
- QETH_DBF_TEXT(TRACE, 5, "regnotif");
+ QETH_DBF_TEXT(SETUP, 5, "regnotif");
rc = register_inetaddr_notifier(&qeth_l3_ip_notifier);
if (rc)
return rc;
@@ -3733,7 +3739,7 @@ static int qeth_l3_register_notifiers(void)
static void qeth_l3_unregister_notifiers(void)
{
- QETH_DBF_TEXT(TRACE, 5, "unregnot");
+ QETH_DBF_TEXT(SETUP, 5, "unregnot");
BUG_ON(unregister_inetaddr_notifier(&qeth_l3_ip_notifier));
#ifdef CONFIG_QETH_IPV6
BUG_ON(unregister_inet6addr_notifier(&qeth_l3_ip6_notifier));
diff --git a/drivers/s390/net/qeth_l3_sys.c b/drivers/s390/net/qeth_l3_sys.c
index fb5318b30e9..67cfa68dcf1 100644
--- a/drivers/s390/net/qeth_l3_sys.c
+++ b/drivers/s390/net/qeth_l3_sys.c
@@ -479,6 +479,7 @@ static ssize_t qeth_l3_dev_ipato_enable_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
struct qeth_card *card = dev_get_drvdata(dev);
+ struct qeth_ipaddr *tmpipa, *t;
char *tmp;
int rc = 0;
@@ -497,8 +498,21 @@ static ssize_t qeth_l3_dev_ipato_enable_store(struct device *dev,
card->ipato.enabled = (card->ipato.enabled)? 0 : 1;
} else if (!strcmp(tmp, "1")) {
card->ipato.enabled = 1;
+ list_for_each_entry_safe(tmpipa, t, card->ip_tbd_list, entry) {
+ if ((tmpipa->type == QETH_IP_TYPE_NORMAL) &&
+ qeth_l3_is_addr_covered_by_ipato(card, tmpipa))
+ tmpipa->set_flags |=
+ QETH_IPA_SETIP_TAKEOVER_FLAG;
+ }
+
} else if (!strcmp(tmp, "0")) {
card->ipato.enabled = 0;
+ list_for_each_entry_safe(tmpipa, t, card->ip_tbd_list, entry) {
+ if (tmpipa->set_flags &
+ QETH_IPA_SETIP_TAKEOVER_FLAG)
+ tmpipa->set_flags &=
+ ~QETH_IPA_SETIP_TAKEOVER_FLAG;
+ }
} else
rc = -EINVAL;
out:
diff --git a/drivers/s390/net/smsgiucv.c b/drivers/s390/net/smsgiucv.c
index 70491274da1..65e1cf10494 100644
--- a/drivers/s390/net/smsgiucv.c
+++ b/drivers/s390/net/smsgiucv.c
@@ -47,6 +47,7 @@ static struct device *smsg_dev;
static DEFINE_SPINLOCK(smsg_list_lock);
static LIST_HEAD(smsg_list);
+static int iucv_path_connected;
static int smsg_path_pending(struct iucv_path *, u8 ipvmid[8], u8 ipuser[16]);
static void smsg_message_pending(struct iucv_path *, struct iucv_message *);
@@ -142,8 +143,10 @@ static int smsg_pm_freeze(struct device *dev)
#ifdef CONFIG_PM_DEBUG
printk(KERN_WARNING "smsg_pm_freeze\n");
#endif
- if (smsg_path)
+ if (smsg_path && iucv_path_connected) {
iucv_path_sever(smsg_path, NULL);
+ iucv_path_connected = 0;
+ }
return 0;
}
@@ -154,7 +157,7 @@ static int smsg_pm_restore_thaw(struct device *dev)
#ifdef CONFIG_PM_DEBUG
printk(KERN_WARNING "smsg_pm_restore_thaw\n");
#endif
- if (smsg_path) {
+ if (smsg_path && iucv_path_connected) {
memset(smsg_path, 0, sizeof(*smsg_path));
smsg_path->msglim = 255;
smsg_path->flags = 0;
@@ -165,6 +168,8 @@ static int smsg_pm_restore_thaw(struct device *dev)
printk(KERN_ERR
"iucv_path_connect returned with rc %i\n", rc);
#endif
+ if (!rc)
+ iucv_path_connected = 1;
cpcmd("SET SMSG IUCV", NULL, 0, NULL);
}
return 0;
@@ -214,6 +219,8 @@ static int __init smsg_init(void)
NULL, NULL, NULL);
if (rc)
goto out_free_path;
+ else
+ iucv_path_connected = 1;
smsg_dev = kzalloc(sizeof(struct device), GFP_KERNEL);
if (!smsg_dev) {
rc = -ENOMEM;
diff --git a/drivers/s390/scsi/zfcp_aux.c b/drivers/s390/scsi/zfcp_aux.c
index e331df2122f..96fa1f53639 100644
--- a/drivers/s390/scsi/zfcp_aux.c
+++ b/drivers/s390/scsi/zfcp_aux.c
@@ -98,13 +98,11 @@ static void __init zfcp_init_device_setup(char *devstr)
u64 wwpn, lun;
/* duplicate devstr and keep the original for sysfs presentation*/
- str_saved = kmalloc(strlen(devstr) + 1, GFP_KERNEL);
+ str_saved = kstrdup(devstr, GFP_KERNEL);
str = str_saved;
if (!str)
return;
- strcpy(str, devstr);
-
token = strsep(&str, ",");
if (!token || strlen(token) >= ZFCP_BUS_ID_SIZE)
goto err_out;
@@ -314,7 +312,7 @@ struct zfcp_unit *zfcp_unit_enqueue(struct zfcp_port *port, u64 fcp_lun)
}
retval = -EINVAL;
- INIT_WORK(&unit->scsi_work, zfcp_scsi_scan);
+ INIT_WORK(&unit->scsi_work, zfcp_scsi_scan_work);
spin_lock_init(&unit->latencies.lock);
unit->latencies.write.channel.min = 0xFFFFFFFF;
@@ -526,6 +524,10 @@ struct zfcp_adapter *zfcp_adapter_enqueue(struct ccw_device *ccw_device)
rwlock_init(&adapter->port_list_lock);
INIT_LIST_HEAD(&adapter->port_list);
+ INIT_LIST_HEAD(&adapter->events.list);
+ INIT_WORK(&adapter->events.work, zfcp_fc_post_event);
+ spin_lock_init(&adapter->events.list_lock);
+
init_waitqueue_head(&adapter->erp_ready_wq);
init_waitqueue_head(&adapter->erp_done_wqh);
diff --git a/drivers/s390/scsi/zfcp_cfdc.c b/drivers/s390/scsi/zfcp_cfdc.c
index 1a2db0a3573..fcbd2b756da 100644
--- a/drivers/s390/scsi/zfcp_cfdc.c
+++ b/drivers/s390/scsi/zfcp_cfdc.c
@@ -189,18 +189,12 @@ static long zfcp_cfdc_dev_ioctl(struct file *file, unsigned int command,
if (!fsf_cfdc)
return -ENOMEM;
- data = kmalloc(sizeof(struct zfcp_cfdc_data), GFP_KERNEL);
- if (!data) {
- retval = -ENOMEM;
+ data = memdup_user(data_user, sizeof(*data_user));
+ if (IS_ERR(data)) {
+ retval = PTR_ERR(data);
goto no_mem_sense;
}
- retval = copy_from_user(data, data_user, sizeof(*data));
- if (retval) {
- retval = -EFAULT;
- goto free_buffer;
- }
-
if (data->signature != 0xCFDCACDF) {
retval = -EINVAL;
goto free_buffer;
diff --git a/drivers/s390/scsi/zfcp_dbf.c b/drivers/s390/scsi/zfcp_dbf.c
index 075852f6968..a86117b0d6e 100644
--- a/drivers/s390/scsi/zfcp_dbf.c
+++ b/drivers/s390/scsi/zfcp_dbf.c
@@ -155,6 +155,8 @@ void _zfcp_dbf_hba_fsf_response(const char *tag2, int level,
if (scsi_cmnd) {
response->u.fcp.cmnd = (unsigned long)scsi_cmnd;
response->u.fcp.serial = scsi_cmnd->serial_number;
+ response->u.fcp.data_dir =
+ qtcb->bottom.io.data_direction;
}
break;
@@ -326,6 +328,7 @@ static void zfcp_dbf_hba_view_response(char **p,
case FSF_QTCB_FCP_CMND:
if (r->fsf_req_status & ZFCP_STATUS_FSFREQ_TASK_MANAGEMENT)
break;
+ zfcp_dbf_out(p, "data_direction", "0x%04x", r->u.fcp.data_dir);
zfcp_dbf_out(p, "scsi_cmnd", "0x%0Lx", r->u.fcp.cmnd);
zfcp_dbf_out(p, "scsi_serial", "0x%016Lx", r->u.fcp.serial);
*p += sprintf(*p, "\n");
@@ -1005,7 +1008,7 @@ int zfcp_dbf_adapter_register(struct zfcp_adapter *adapter)
char dbf_name[DEBUG_MAX_NAME_LEN];
struct zfcp_dbf *dbf;
- dbf = kmalloc(sizeof(struct zfcp_dbf), GFP_KERNEL);
+ dbf = kzalloc(sizeof(struct zfcp_dbf), GFP_KERNEL);
if (!dbf)
return -ENOMEM;
diff --git a/drivers/s390/scsi/zfcp_dbf.h b/drivers/s390/scsi/zfcp_dbf.h
index 457e046f2d2..2bcc3403126 100644
--- a/drivers/s390/scsi/zfcp_dbf.h
+++ b/drivers/s390/scsi/zfcp_dbf.h
@@ -111,6 +111,7 @@ struct zfcp_dbf_hba_record_response {
struct {
u64 cmnd;
u64 serial;
+ u32 data_dir;
} fcp;
struct {
u64 wwpn;
diff --git a/drivers/s390/scsi/zfcp_def.h b/drivers/s390/scsi/zfcp_def.h
index 9fa1b064893..e1c6b6e05a7 100644
--- a/drivers/s390/scsi/zfcp_def.h
+++ b/drivers/s390/scsi/zfcp_def.h
@@ -37,6 +37,7 @@
#include <asm/ebcdic.h>
#include <asm/sysinfo.h>
#include "zfcp_fsf.h"
+#include "zfcp_fc.h"
#include "zfcp_qdio.h"
struct zfcp_reqlist;
@@ -72,10 +73,12 @@ struct zfcp_reqlist;
/* adapter status */
#define ZFCP_STATUS_ADAPTER_QDIOUP 0x00000002
+#define ZFCP_STATUS_ADAPTER_SIOSL_ISSUED 0x00000004
#define ZFCP_STATUS_ADAPTER_XCONFIG_OK 0x00000008
#define ZFCP_STATUS_ADAPTER_HOST_CON_INIT 0x00000010
#define ZFCP_STATUS_ADAPTER_ERP_PENDING 0x00000100
#define ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED 0x00000200
+#define ZFCP_STATUS_ADAPTER_DATA_DIV_ENABLED 0x00000400
/* remote port status */
#define ZFCP_STATUS_PORT_PHYS_OPEN 0x00000001
@@ -190,6 +193,7 @@ struct zfcp_adapter {
struct service_level service_level;
struct workqueue_struct *work_queue;
struct device_dma_parameters dma_parms;
+ struct zfcp_fc_events events;
};
struct zfcp_port {
@@ -212,6 +216,7 @@ struct zfcp_port {
struct work_struct test_link_work;
struct work_struct rport_work;
enum { RPORT_NONE, RPORT_ADD, RPORT_DEL } rport_task;
+ unsigned int starget_id;
};
struct zfcp_unit {
diff --git a/drivers/s390/scsi/zfcp_erp.c b/drivers/s390/scsi/zfcp_erp.c
index fd068bc1bd0..160b432c907 100644
--- a/drivers/s390/scsi/zfcp_erp.c
+++ b/drivers/s390/scsi/zfcp_erp.c
@@ -141,9 +141,13 @@ static int zfcp_erp_required_act(int want, struct zfcp_adapter *adapter,
if (!(p_status & ZFCP_STATUS_COMMON_UNBLOCKED))
need = ZFCP_ERP_ACTION_REOPEN_PORT;
/* fall through */
- case ZFCP_ERP_ACTION_REOPEN_PORT:
case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED:
p_status = atomic_read(&port->status);
+ if (!(p_status & ZFCP_STATUS_COMMON_OPEN))
+ need = ZFCP_ERP_ACTION_REOPEN_PORT;
+ /* fall through */
+ case ZFCP_ERP_ACTION_REOPEN_PORT:
+ p_status = atomic_read(&port->status);
if (p_status & ZFCP_STATUS_COMMON_ERP_INUSE)
return 0;
a_status = atomic_read(&adapter->status);
@@ -893,8 +897,7 @@ static int zfcp_erp_port_strategy_open_common(struct zfcp_erp_action *act)
}
if (port->d_id && !(p_status & ZFCP_STATUS_COMMON_NOESC)) {
port->d_id = 0;
- _zfcp_erp_port_reopen(port, 0, "erpsoc1", NULL);
- return ZFCP_ERP_EXIT;
+ return ZFCP_ERP_FAILED;
}
/* fall through otherwise */
}
@@ -1188,19 +1191,14 @@ static void zfcp_erp_action_cleanup(struct zfcp_erp_action *act, int result)
switch (act->action) {
case ZFCP_ERP_ACTION_REOPEN_UNIT:
- if ((result == ZFCP_ERP_SUCCEEDED) && !unit->device) {
- get_device(&unit->dev);
- if (scsi_queue_work(unit->port->adapter->scsi_host,
- &unit->scsi_work) <= 0)
- put_device(&unit->dev);
- }
put_device(&unit->dev);
break;
- case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED:
case ZFCP_ERP_ACTION_REOPEN_PORT:
if (result == ZFCP_ERP_SUCCEEDED)
zfcp_scsi_schedule_rport_register(port);
+ /* fall through */
+ case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED:
put_device(&port->dev);
break;
@@ -1247,6 +1245,11 @@ static int zfcp_erp_strategy(struct zfcp_erp_action *erp_action)
goto unlock;
}
+ if (erp_action->status & ZFCP_STATUS_ERP_TIMEDOUT) {
+ retval = ZFCP_ERP_FAILED;
+ goto check_target;
+ }
+
zfcp_erp_action_to_running(erp_action);
/* no lock to allow for blocking operations */
@@ -1279,6 +1282,7 @@ static int zfcp_erp_strategy(struct zfcp_erp_action *erp_action)
goto unlock;
}
+check_target:
retval = zfcp_erp_strategy_check_target(erp_action, retval);
zfcp_erp_action_dequeue(erp_action);
retval = zfcp_erp_strategy_statechange(erp_action, retval);
diff --git a/drivers/s390/scsi/zfcp_ext.h b/drivers/s390/scsi/zfcp_ext.h
index 48a8f93b72f..3b93239c6f6 100644
--- a/drivers/s390/scsi/zfcp_ext.h
+++ b/drivers/s390/scsi/zfcp_ext.h
@@ -96,6 +96,9 @@ extern void zfcp_erp_adapter_access_changed(struct zfcp_adapter *, char *,
extern void zfcp_erp_timeout_handler(unsigned long);
/* zfcp_fc.c */
+extern void zfcp_fc_enqueue_event(struct zfcp_adapter *,
+ enum fc_host_event_code event_code, u32);
+extern void zfcp_fc_post_event(struct work_struct *);
extern void zfcp_fc_scan_ports(struct work_struct *);
extern void zfcp_fc_incoming_els(struct zfcp_fsf_req *);
extern void zfcp_fc_port_did_lookup(struct work_struct *);
@@ -146,9 +149,10 @@ extern void zfcp_qdio_destroy(struct zfcp_qdio *);
extern int zfcp_qdio_sbal_get(struct zfcp_qdio *);
extern int zfcp_qdio_send(struct zfcp_qdio *, struct zfcp_qdio_req *);
extern int zfcp_qdio_sbals_from_sg(struct zfcp_qdio *, struct zfcp_qdio_req *,
- struct scatterlist *, int);
+ struct scatterlist *);
extern int zfcp_qdio_open(struct zfcp_qdio *);
extern void zfcp_qdio_close(struct zfcp_qdio *);
+extern void zfcp_qdio_siosl(struct zfcp_adapter *);
/* zfcp_scsi.c */
extern struct zfcp_data zfcp_data;
@@ -159,7 +163,10 @@ extern void zfcp_scsi_rport_work(struct work_struct *);
extern void zfcp_scsi_schedule_rport_register(struct zfcp_port *);
extern void zfcp_scsi_schedule_rport_block(struct zfcp_port *);
extern void zfcp_scsi_schedule_rports_block(struct zfcp_adapter *);
-extern void zfcp_scsi_scan(struct work_struct *);
+extern void zfcp_scsi_scan(struct zfcp_unit *);
+extern void zfcp_scsi_scan_work(struct work_struct *);
+extern void zfcp_scsi_set_prot(struct zfcp_adapter *);
+extern void zfcp_scsi_dif_sense_error(struct scsi_cmnd *, int);
/* zfcp_sysfs.c */
extern struct attribute_group zfcp_sysfs_unit_attrs;
diff --git a/drivers/s390/scsi/zfcp_fc.c b/drivers/s390/scsi/zfcp_fc.c
index 6f8ab43a485..6f3ed2b9a34 100644
--- a/drivers/s390/scsi/zfcp_fc.c
+++ b/drivers/s390/scsi/zfcp_fc.c
@@ -23,6 +23,58 @@ static u32 zfcp_fc_rscn_range_mask[] = {
[ELS_ADDR_FMT_FAB] = 0x000000,
};
+/**
+ * zfcp_fc_post_event - post event to userspace via fc_transport
+ * @work: work struct with enqueued events
+ */
+void zfcp_fc_post_event(struct work_struct *work)
+{
+ struct zfcp_fc_event *event = NULL, *tmp = NULL;
+ LIST_HEAD(tmp_lh);
+ struct zfcp_fc_events *events = container_of(work,
+ struct zfcp_fc_events, work);
+ struct zfcp_adapter *adapter = container_of(events, struct zfcp_adapter,
+ events);
+
+ spin_lock_bh(&events->list_lock);
+ list_splice_init(&events->list, &tmp_lh);
+ spin_unlock_bh(&events->list_lock);
+
+ list_for_each_entry_safe(event, tmp, &tmp_lh, list) {
+ fc_host_post_event(adapter->scsi_host, fc_get_event_number(),
+ event->code, event->data);
+ list_del(&event->list);
+ kfree(event);
+ }
+
+}
+
+/**
+ * zfcp_fc_enqueue_event - safely enqueue FC HBA API event from irq context
+ * @adapter: The adapter where to enqueue the event
+ * @event_code: The event code (as defined in fc_host_event_code in
+ * scsi_transport_fc.h)
+ * @event_data: The event data (e.g. n_port page in case of els)
+ */
+void zfcp_fc_enqueue_event(struct zfcp_adapter *adapter,
+ enum fc_host_event_code event_code, u32 event_data)
+{
+ struct zfcp_fc_event *event;
+
+ event = kmalloc(sizeof(struct zfcp_fc_event), GFP_ATOMIC);
+ if (!event)
+ return;
+
+ event->code = event_code;
+ event->data = event_data;
+
+ spin_lock(&adapter->events.list_lock);
+ list_add_tail(&event->list, &adapter->events.list);
+ spin_unlock(&adapter->events.list_lock);
+
+ queue_work(adapter->work_queue, &adapter->events.work);
+}
+
static int zfcp_fc_wka_port_get(struct zfcp_fc_wka_port *wka_port)
{
if (mutex_lock_interruptible(&wka_port->mutex))
@@ -148,6 +200,8 @@ static void zfcp_fc_incoming_rscn(struct zfcp_fsf_req *fsf_req)
afmt = page->rscn_page_flags & ELS_RSCN_ADDR_FMT_MASK;
_zfcp_fc_incoming_rscn(fsf_req, zfcp_fc_rscn_range_mask[afmt],
page);
+ zfcp_fc_enqueue_event(fsf_req->adapter, FCH_EVT_RSCN,
+ *(u32 *)page);
}
queue_work(fsf_req->adapter->work_queue, &fsf_req->adapter->scan_work);
}
diff --git a/drivers/s390/scsi/zfcp_fc.h b/drivers/s390/scsi/zfcp_fc.h
index 0747b087390..938d5036016 100644
--- a/drivers/s390/scsi/zfcp_fc.h
+++ b/drivers/s390/scsi/zfcp_fc.h
@@ -30,6 +30,30 @@
#define ZFCP_FC_CTELS_TMO (2 * FC_DEF_R_A_TOV / 1000)
/**
+ * struct zfcp_fc_event - FC HBAAPI event for internal queueing from irq context
+ * @code: Event code
+ * @data: Event data
+ * @list: list_head for zfcp_fc_events list
+ */
+struct zfcp_fc_event {
+ enum fc_host_event_code code;
+ u32 data;
+ struct list_head list;
+};
+
+/**
+ * struct zfcp_fc_events - Infrastructure for posting FC events from irq context
+ * @list: List for queueing of events from irq context to workqueue
+ * @list_lock: Lock for event list
+ * @work: work_struct for forwarding events in workqueue
+*/
+struct zfcp_fc_events {
+ struct list_head list;
+ spinlock_t list_lock;
+ struct work_struct work;
+};
+
+/**
* struct zfcp_fc_gid_pn_req - container for ct header plus gid_pn request
* @ct_hdr: FC GS common transport header
* @gid_pn: GID_PN request
@@ -196,6 +220,9 @@ void zfcp_fc_scsi_to_fcp(struct fcp_cmnd *fcp, struct scsi_cmnd *scsi)
memcpy(fcp->fc_cdb, scsi->cmnd, scsi->cmd_len);
fcp->fc_dl = scsi_bufflen(scsi);
+
+ if (scsi_get_prot_type(scsi) == SCSI_PROT_DIF_TYPE1)
+ fcp->fc_dl += fcp->fc_dl / scsi->device->sector_size * 8;
}
/**
diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c
index 71663fb7731..9d1d7d1842c 100644
--- a/drivers/s390/scsi/zfcp_fsf.c
+++ b/drivers/s390/scsi/zfcp_fsf.c
@@ -21,6 +21,7 @@
static void zfcp_fsf_request_timeout_handler(unsigned long data)
{
struct zfcp_adapter *adapter = (struct zfcp_adapter *) data;
+ zfcp_qdio_siosl(adapter);
zfcp_erp_adapter_reopen(adapter, ZFCP_STATUS_COMMON_ERP_FAILED,
"fsrth_1", NULL);
}
@@ -274,6 +275,7 @@ static void zfcp_fsf_status_read_handler(struct zfcp_fsf_req *req)
break;
case FSF_STATUS_READ_LINK_DOWN:
zfcp_fsf_status_read_link_down(req);
+ zfcp_fc_enqueue_event(adapter, FCH_EVT_LINKDOWN, 0);
break;
case FSF_STATUS_READ_LINK_UP:
dev_info(&adapter->ccw_device->dev,
@@ -286,6 +288,8 @@ static void zfcp_fsf_status_read_handler(struct zfcp_fsf_req *req)
ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED |
ZFCP_STATUS_COMMON_ERP_FAILED,
"fssrh_2", req);
+ zfcp_fc_enqueue_event(adapter, FCH_EVT_LINKUP, 0);
+
break;
case FSF_STATUS_READ_NOTIFICATION_LOST:
if (sr_buf->status_subtype & FSF_STATUS_READ_SUB_ACT_UPDATED)
@@ -323,6 +327,7 @@ static void zfcp_fsf_fsfstatus_qual_eval(struct zfcp_fsf_req *req)
dev_err(&req->adapter->ccw_device->dev,
"The FCP adapter reported a problem "
"that cannot be recovered\n");
+ zfcp_qdio_siosl(req->adapter);
zfcp_erp_adapter_shutdown(req->adapter, 0, "fsfsqe1", req);
break;
}
@@ -413,6 +418,7 @@ static void zfcp_fsf_protstatus_eval(struct zfcp_fsf_req *req)
dev_err(&adapter->ccw_device->dev,
"0x%x is not a valid transfer protocol status\n",
qtcb->prefix.prot_status);
+ zfcp_qdio_siosl(adapter);
zfcp_erp_adapter_shutdown(adapter, 0, "fspse_9", req);
}
req->status |= ZFCP_STATUS_FSFREQ_ERROR;
@@ -495,7 +501,7 @@ static int zfcp_fsf_exchange_config_evaluate(struct zfcp_fsf_req *req)
fc_host_supported_classes(shost) = FC_COS_CLASS2 | FC_COS_CLASS3;
adapter->hydra_version = bottom->adapter_type;
- adapter->timer_ticks = bottom->timer_interval;
+ adapter->timer_ticks = bottom->timer_interval & ZFCP_FSF_TIMER_INT_MASK;
adapter->stat_read_buf_num = max(bottom->status_read_buf_num,
(u16)FSF_STATUS_READS_RECOM);
@@ -523,6 +529,8 @@ static int zfcp_fsf_exchange_config_evaluate(struct zfcp_fsf_req *req)
return -EIO;
}
+ zfcp_scsi_set_prot(adapter);
+
return 0;
}
@@ -732,7 +740,7 @@ static int zfcp_fsf_req_send(struct zfcp_fsf_req *req)
zfcp_reqlist_add(adapter->req_list, req);
- req->qdio_req.qdio_outb_usage = atomic_read(&qdio->req_q.count);
+ req->qdio_req.qdio_outb_usage = atomic_read(&qdio->req_q_free);
req->issued = get_clock();
if (zfcp_qdio_send(qdio, &req->qdio_req)) {
del_timer(&req->timer);
@@ -959,8 +967,7 @@ static void zfcp_fsf_setup_ct_els_unchained(struct zfcp_qdio *qdio,
static int zfcp_fsf_setup_ct_els_sbals(struct zfcp_fsf_req *req,
struct scatterlist *sg_req,
- struct scatterlist *sg_resp,
- int max_sbals)
+ struct scatterlist *sg_resp)
{
struct zfcp_adapter *adapter = req->adapter;
u32 feat = adapter->adapter_features;
@@ -983,18 +990,19 @@ static int zfcp_fsf_setup_ct_els_sbals(struct zfcp_fsf_req *req,
return 0;
}
- bytes = zfcp_qdio_sbals_from_sg(adapter->qdio, &req->qdio_req,
- sg_req, max_sbals);
+ bytes = zfcp_qdio_sbals_from_sg(adapter->qdio, &req->qdio_req, sg_req);
if (bytes <= 0)
return -EIO;
+ zfcp_qdio_set_sbale_last(adapter->qdio, &req->qdio_req);
req->qtcb->bottom.support.req_buf_length = bytes;
zfcp_qdio_skip_to_last_sbale(&req->qdio_req);
bytes = zfcp_qdio_sbals_from_sg(adapter->qdio, &req->qdio_req,
- sg_resp, max_sbals);
+ sg_resp);
req->qtcb->bottom.support.resp_buf_length = bytes;
if (bytes <= 0)
return -EIO;
+ zfcp_qdio_set_sbale_last(adapter->qdio, &req->qdio_req);
return 0;
}
@@ -1002,11 +1010,11 @@ static int zfcp_fsf_setup_ct_els_sbals(struct zfcp_fsf_req *req,
static int zfcp_fsf_setup_ct_els(struct zfcp_fsf_req *req,
struct scatterlist *sg_req,
struct scatterlist *sg_resp,
- int max_sbals, unsigned int timeout)
+ unsigned int timeout)
{
int ret;
- ret = zfcp_fsf_setup_ct_els_sbals(req, sg_req, sg_resp, max_sbals);
+ ret = zfcp_fsf_setup_ct_els_sbals(req, sg_req, sg_resp);
if (ret)
return ret;
@@ -1046,8 +1054,7 @@ int zfcp_fsf_send_ct(struct zfcp_fc_wka_port *wka_port,
}
req->status |= ZFCP_STATUS_FSFREQ_CLEANUP;
- ret = zfcp_fsf_setup_ct_els(req, ct->req, ct->resp,
- ZFCP_FSF_MAX_SBALS_PER_REQ, timeout);
+ ret = zfcp_fsf_setup_ct_els(req, ct->req, ct->resp, timeout);
if (ret)
goto failed_send;
@@ -1143,7 +1150,10 @@ int zfcp_fsf_send_els(struct zfcp_adapter *adapter, u32 d_id,
}
req->status |= ZFCP_STATUS_FSFREQ_CLEANUP;
- ret = zfcp_fsf_setup_ct_els(req, els->req, els->resp, 2, timeout);
+
+ zfcp_qdio_sbal_limit(qdio, &req->qdio_req, 2);
+
+ ret = zfcp_fsf_setup_ct_els(req, els->req, els->resp, timeout);
if (ret)
goto failed_send;
@@ -2025,7 +2035,7 @@ static void zfcp_fsf_req_trace(struct zfcp_fsf_req *req, struct scsi_cmnd *scsi)
blktrc.magic = ZFCP_BLK_DRV_DATA_MAGIC;
if (req->status & ZFCP_STATUS_FSFREQ_ERROR)
blktrc.flags |= ZFCP_BLK_REQ_ERROR;
- blktrc.inb_usage = req->qdio_req.qdio_inb_usage;
+ blktrc.inb_usage = 0;
blktrc.outb_usage = req->qdio_req.qdio_outb_usage;
if (req->adapter->adapter_features & FSF_FEATURE_MEASUREMENT_DATA &&
@@ -2035,9 +2045,13 @@ static void zfcp_fsf_req_trace(struct zfcp_fsf_req *req, struct scsi_cmnd *scsi)
blktrc.fabric_lat = lat_in->fabric_lat * ticks;
switch (req->qtcb->bottom.io.data_direction) {
+ case FSF_DATADIR_DIF_READ_STRIP:
+ case FSF_DATADIR_DIF_READ_CONVERT:
case FSF_DATADIR_READ:
lat = &unit->latencies.read;
break;
+ case FSF_DATADIR_DIF_WRITE_INSERT:
+ case FSF_DATADIR_DIF_WRITE_CONVERT:
case FSF_DATADIR_WRITE:
lat = &unit->latencies.write;
break;
@@ -2078,6 +2092,21 @@ static void zfcp_fsf_send_fcp_command_task_handler(struct zfcp_fsf_req *req)
goto skip_fsfstatus;
}
+ switch (req->qtcb->header.fsf_status) {
+ case FSF_INCONSISTENT_PROT_DATA:
+ case FSF_INVALID_PROT_PARM:
+ set_host_byte(scpnt, DID_ERROR);
+ goto skip_fsfstatus;
+ case FSF_BLOCK_GUARD_CHECK_FAILURE:
+ zfcp_scsi_dif_sense_error(scpnt, 0x1);
+ goto skip_fsfstatus;
+ case FSF_APP_TAG_CHECK_FAILURE:
+ zfcp_scsi_dif_sense_error(scpnt, 0x2);
+ goto skip_fsfstatus;
+ case FSF_REF_TAG_CHECK_FAILURE:
+ zfcp_scsi_dif_sense_error(scpnt, 0x3);
+ goto skip_fsfstatus;
+ }
fcp_rsp = (struct fcp_resp_with_ext *) &req->qtcb->bottom.io.fcp_rsp;
zfcp_fc_eval_fcp_rsp(fcp_rsp, scpnt);
@@ -2187,6 +2216,44 @@ skip_fsfstatus:
}
}
+static int zfcp_fsf_set_data_dir(struct scsi_cmnd *scsi_cmnd, u32 *data_dir)
+{
+ switch (scsi_get_prot_op(scsi_cmnd)) {
+ case SCSI_PROT_NORMAL:
+ switch (scsi_cmnd->sc_data_direction) {
+ case DMA_NONE:
+ *data_dir = FSF_DATADIR_CMND;
+ break;
+ case DMA_FROM_DEVICE:
+ *data_dir = FSF_DATADIR_READ;
+ break;
+ case DMA_TO_DEVICE:
+ *data_dir = FSF_DATADIR_WRITE;
+ break;
+ case DMA_BIDIRECTIONAL:
+ return -EINVAL;
+ }
+ break;
+
+ case SCSI_PROT_READ_STRIP:
+ *data_dir = FSF_DATADIR_DIF_READ_STRIP;
+ break;
+ case SCSI_PROT_WRITE_INSERT:
+ *data_dir = FSF_DATADIR_DIF_WRITE_INSERT;
+ break;
+ case SCSI_PROT_READ_PASS:
+ *data_dir = FSF_DATADIR_DIF_READ_CONVERT;
+ break;
+ case SCSI_PROT_WRITE_PASS:
+ *data_dir = FSF_DATADIR_DIF_WRITE_CONVERT;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
/**
* zfcp_fsf_send_fcp_command_task - initiate an FCP command (for a SCSI command)
* @unit: unit where command is sent to
@@ -2198,16 +2265,17 @@ int zfcp_fsf_send_fcp_command_task(struct zfcp_unit *unit,
struct zfcp_fsf_req *req;
struct fcp_cmnd *fcp_cmnd;
unsigned int sbtype = SBAL_FLAGS0_TYPE_READ;
- int real_bytes, retval = -EIO;
+ int real_bytes, retval = -EIO, dix_bytes = 0;
struct zfcp_adapter *adapter = unit->port->adapter;
struct zfcp_qdio *qdio = adapter->qdio;
+ struct fsf_qtcb_bottom_io *io;
if (unlikely(!(atomic_read(&unit->status) &
ZFCP_STATUS_COMMON_UNBLOCKED)))
return -EBUSY;
spin_lock(&qdio->req_q_lock);
- if (atomic_read(&qdio->req_q.count) <= 0) {
+ if (atomic_read(&qdio->req_q_free) <= 0) {
atomic_inc(&qdio->req_q_full);
goto out;
}
@@ -2223,56 +2291,45 @@ int zfcp_fsf_send_fcp_command_task(struct zfcp_unit *unit,
goto out;
}
+ scsi_cmnd->host_scribble = (unsigned char *) req->req_id;
+
+ io = &req->qtcb->bottom.io;
req->status |= ZFCP_STATUS_FSFREQ_CLEANUP;
req->unit = unit;
req->data = scsi_cmnd;
req->handler = zfcp_fsf_send_fcp_command_handler;
req->qtcb->header.lun_handle = unit->handle;
req->qtcb->header.port_handle = unit->port->handle;
- req->qtcb->bottom.io.service_class = FSF_CLASS_3;
- req->qtcb->bottom.io.fcp_cmnd_length = FCP_CMND_LEN;
+ io->service_class = FSF_CLASS_3;
+ io->fcp_cmnd_length = FCP_CMND_LEN;
- scsi_cmnd->host_scribble = (unsigned char *) req->req_id;
-
- /*
- * set depending on data direction:
- * data direction bits in SBALE (SB Type)
- * data direction bits in QTCB
- */
- switch (scsi_cmnd->sc_data_direction) {
- case DMA_NONE:
- req->qtcb->bottom.io.data_direction = FSF_DATADIR_CMND;
- break;
- case DMA_FROM_DEVICE:
- req->qtcb->bottom.io.data_direction = FSF_DATADIR_READ;
- break;
- case DMA_TO_DEVICE:
- req->qtcb->bottom.io.data_direction = FSF_DATADIR_WRITE;
- break;
- case DMA_BIDIRECTIONAL:
- goto failed_scsi_cmnd;
+ if (scsi_get_prot_op(scsi_cmnd) != SCSI_PROT_NORMAL) {
+ io->data_block_length = scsi_cmnd->device->sector_size;
+ io->ref_tag_value = scsi_get_lba(scsi_cmnd) & 0xFFFFFFFF;
}
+ zfcp_fsf_set_data_dir(scsi_cmnd, &io->data_direction);
+
get_device(&unit->dev);
fcp_cmnd = (struct fcp_cmnd *) &req->qtcb->bottom.io.fcp_cmnd;
zfcp_fc_scsi_to_fcp(fcp_cmnd, scsi_cmnd);
+ if (scsi_prot_sg_count(scsi_cmnd)) {
+ zfcp_qdio_set_data_div(qdio, &req->qdio_req,
+ scsi_prot_sg_count(scsi_cmnd));
+ dix_bytes = zfcp_qdio_sbals_from_sg(qdio, &req->qdio_req,
+ scsi_prot_sglist(scsi_cmnd));
+ io->prot_data_length = dix_bytes;
+ }
+
real_bytes = zfcp_qdio_sbals_from_sg(qdio, &req->qdio_req,
- scsi_sglist(scsi_cmnd),
- ZFCP_FSF_MAX_SBALS_PER_REQ);
- if (unlikely(real_bytes < 0)) {
- if (req->qdio_req.sbal_number >= ZFCP_FSF_MAX_SBALS_PER_REQ) {
- dev_err(&adapter->ccw_device->dev,
- "Oversize data package, unit 0x%016Lx "
- "on port 0x%016Lx closed\n",
- (unsigned long long)unit->fcp_lun,
- (unsigned long long)unit->port->wwpn);
- zfcp_erp_unit_shutdown(unit, 0, "fssfct1", req);
- retval = -EINVAL;
- }
+ scsi_sglist(scsi_cmnd));
+
+ if (unlikely(real_bytes < 0) || unlikely(dix_bytes < 0))
goto failed_scsi_cmnd;
- }
+
+ zfcp_qdio_set_sbale_last(adapter->qdio, &req->qdio_req);
retval = zfcp_fsf_req_send(req);
if (unlikely(retval))
@@ -2391,13 +2448,13 @@ struct zfcp_fsf_req *zfcp_fsf_control_file(struct zfcp_adapter *adapter,
bottom->operation_subtype = FSF_CFDC_OPERATION_SUBTYPE;
bottom->option = fsf_cfdc->option;
- bytes = zfcp_qdio_sbals_from_sg(qdio, &req->qdio_req,
- fsf_cfdc->sg,
- ZFCP_FSF_MAX_SBALS_PER_REQ);
+ bytes = zfcp_qdio_sbals_from_sg(qdio, &req->qdio_req, fsf_cfdc->sg);
+
if (bytes != ZFCP_CFDC_MAX_SIZE) {
zfcp_fsf_req_free(req);
goto out;
}
+ zfcp_qdio_set_sbale_last(adapter->qdio, &req->qdio_req);
zfcp_fsf_start_timer(req, ZFCP_FSF_REQUEST_TIMEOUT);
retval = zfcp_fsf_req_send(req);
@@ -2419,7 +2476,7 @@ out:
void zfcp_fsf_reqid_check(struct zfcp_qdio *qdio, int sbal_idx)
{
struct zfcp_adapter *adapter = qdio->adapter;
- struct qdio_buffer *sbal = qdio->resp_q.sbal[sbal_idx];
+ struct qdio_buffer *sbal = qdio->res_q[sbal_idx];
struct qdio_buffer_element *sbale;
struct zfcp_fsf_req *fsf_req;
unsigned long req_id;
@@ -2431,17 +2488,17 @@ void zfcp_fsf_reqid_check(struct zfcp_qdio *qdio, int sbal_idx)
req_id = (unsigned long) sbale->addr;
fsf_req = zfcp_reqlist_find_rm(adapter->req_list, req_id);
- if (!fsf_req)
+ if (!fsf_req) {
/*
* Unknown request means that we have potentially memory
* corruption and must stop the machine immediately.
*/
+ zfcp_qdio_siosl(adapter);
panic("error: unknown req_id (%lx) on adapter %s.\n",
req_id, dev_name(&adapter->ccw_device->dev));
+ }
fsf_req->qdio_req.sbal_response = sbal_idx;
- fsf_req->qdio_req.qdio_inb_usage =
- atomic_read(&qdio->resp_q.count);
zfcp_fsf_req_complete(fsf_req);
if (likely(sbale->flags & SBAL_FLAGS_LAST_ENTRY))
diff --git a/drivers/s390/scsi/zfcp_fsf.h b/drivers/s390/scsi/zfcp_fsf.h
index 519083fd6e8..db8c85382dc 100644
--- a/drivers/s390/scsi/zfcp_fsf.h
+++ b/drivers/s390/scsi/zfcp_fsf.h
@@ -80,11 +80,15 @@
#define FSF_REQUEST_SIZE_TOO_LARGE 0x00000061
#define FSF_RESPONSE_SIZE_TOO_LARGE 0x00000062
#define FSF_SBAL_MISMATCH 0x00000063
+#define FSF_INCONSISTENT_PROT_DATA 0x00000070
+#define FSF_INVALID_PROT_PARM 0x00000071
+#define FSF_BLOCK_GUARD_CHECK_FAILURE 0x00000081
+#define FSF_APP_TAG_CHECK_FAILURE 0x00000082
+#define FSF_REF_TAG_CHECK_FAILURE 0x00000083
#define FSF_ADAPTER_STATUS_AVAILABLE 0x000000AD
#define FSF_UNKNOWN_COMMAND 0x000000E2
#define FSF_UNKNOWN_OP_SUBTYPE 0x000000E3
#define FSF_INVALID_COMMAND_OPTION 0x000000E5
-/* #define FSF_ERROR 0x000000FF */
#define FSF_PROT_STATUS_QUAL_SIZE 16
#define FSF_STATUS_QUALIFIER_SIZE 16
@@ -147,18 +151,17 @@
#define FSF_DATADIR_WRITE 0x00000001
#define FSF_DATADIR_READ 0x00000002
#define FSF_DATADIR_CMND 0x00000004
+#define FSF_DATADIR_DIF_WRITE_INSERT 0x00000009
+#define FSF_DATADIR_DIF_READ_STRIP 0x0000000a
+#define FSF_DATADIR_DIF_WRITE_CONVERT 0x0000000b
+#define FSF_DATADIR_DIF_READ_CONVERT 0X0000000c
+
+/* data protection control flags */
+#define FSF_APP_TAG_CHECK_ENABLE 0x10
/* fc service class */
#define FSF_CLASS_3 0x00000003
-/* SBAL chaining */
-#define ZFCP_FSF_MAX_SBALS_PER_REQ 36
-
-/* max. number of (data buffer) SBALEs in largest SBAL chain
- * request ID + QTCB in SBALE 0 + 1 of first SBAL in chain */
-#define ZFCP_FSF_MAX_SBALES_PER_REQ \
- (ZFCP_FSF_MAX_SBALS_PER_REQ * ZFCP_QDIO_MAX_SBALES_PER_SBAL - 2)
-
/* logging space behind QTCB */
#define FSF_QTCB_LOG_SIZE 1024
@@ -170,6 +173,8 @@
#define FSF_FEATURE_ELS_CT_CHAINED_SBALS 0x00000020
#define FSF_FEATURE_UPDATE_ALERT 0x00000100
#define FSF_FEATURE_MEASUREMENT_DATA 0x00000200
+#define FSF_FEATURE_DIF_PROT_TYPE1 0x00010000
+#define FSF_FEATURE_DIX_PROT_TCPIP 0x00020000
/* host connection features */
#define FSF_FEATURE_NPIV_MODE 0x00000001
@@ -324,9 +329,14 @@ struct fsf_qtcb_header {
struct fsf_qtcb_bottom_io {
u32 data_direction;
u32 service_class;
- u8 res1[8];
+ u8 res1;
+ u8 data_prot_flags;
+ u16 app_tag_value;
+ u32 ref_tag_value;
u32 fcp_cmnd_length;
- u8 res2[12];
+ u32 data_block_length;
+ u32 prot_data_length;
+ u8 res2[4];
u8 fcp_cmnd[FSF_FCP_CMND_SIZE];
u8 fcp_rsp[FSF_FCP_RSP_SIZE];
u8 res3[64];
@@ -352,6 +362,8 @@ struct fsf_qtcb_bottom_support {
u8 els[256];
} __attribute__ ((packed));
+#define ZFCP_FSF_TIMER_INT_MASK 0x3FFF
+
struct fsf_qtcb_bottom_config {
u32 lic_version;
u32 feature_selection;
diff --git a/drivers/s390/scsi/zfcp_qdio.c b/drivers/s390/scsi/zfcp_qdio.c
index 6fa5e045317..b2635759721 100644
--- a/drivers/s390/scsi/zfcp_qdio.c
+++ b/drivers/s390/scsi/zfcp_qdio.c
@@ -30,12 +30,15 @@ static int zfcp_qdio_buffers_enqueue(struct qdio_buffer **sbal)
return 0;
}
-static void zfcp_qdio_handler_error(struct zfcp_qdio *qdio, char *id)
+static void zfcp_qdio_handler_error(struct zfcp_qdio *qdio, char *id,
+ unsigned int qdio_err)
{
struct zfcp_adapter *adapter = qdio->adapter;
dev_warn(&adapter->ccw_device->dev, "A QDIO problem occurred\n");
+ if (qdio_err & QDIO_ERROR_SLSB_STATE)
+ zfcp_qdio_siosl(adapter);
zfcp_erp_adapter_reopen(adapter,
ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED |
ZFCP_STATUS_COMMON_ERP_FAILED, id, NULL);
@@ -55,72 +58,47 @@ static void zfcp_qdio_zero_sbals(struct qdio_buffer *sbal[], int first, int cnt)
static inline void zfcp_qdio_account(struct zfcp_qdio *qdio)
{
unsigned long long now, span;
- int free, used;
+ int used;
spin_lock(&qdio->stat_lock);
now = get_clock_monotonic();
span = (now - qdio->req_q_time) >> 12;
- free = atomic_read(&qdio->req_q.count);
- used = QDIO_MAX_BUFFERS_PER_Q - free;
+ used = QDIO_MAX_BUFFERS_PER_Q - atomic_read(&qdio->req_q_free);
qdio->req_q_util += used * span;
qdio->req_q_time = now;
spin_unlock(&qdio->stat_lock);
}
static void zfcp_qdio_int_req(struct ccw_device *cdev, unsigned int qdio_err,
- int queue_no, int first, int count,
+ int queue_no, int idx, int count,
unsigned long parm)
{
struct zfcp_qdio *qdio = (struct zfcp_qdio *) parm;
- struct zfcp_qdio_queue *queue = &qdio->req_q;
if (unlikely(qdio_err)) {
- zfcp_dbf_hba_qdio(qdio->adapter->dbf, qdio_err, first,
- count);
- zfcp_qdio_handler_error(qdio, "qdireq1");
+ zfcp_dbf_hba_qdio(qdio->adapter->dbf, qdio_err, idx, count);
+ zfcp_qdio_handler_error(qdio, "qdireq1", qdio_err);
return;
}
/* cleanup all SBALs being program-owned now */
- zfcp_qdio_zero_sbals(queue->sbal, first, count);
+ zfcp_qdio_zero_sbals(qdio->req_q, idx, count);
zfcp_qdio_account(qdio);
- atomic_add(count, &queue->count);
+ atomic_add(count, &qdio->req_q_free);
wake_up(&qdio->req_q_wq);
}
-static void zfcp_qdio_resp_put_back(struct zfcp_qdio *qdio, int processed)
-{
- struct zfcp_qdio_queue *queue = &qdio->resp_q;
- struct ccw_device *cdev = qdio->adapter->ccw_device;
- u8 count, start = queue->first;
- unsigned int retval;
-
- count = atomic_read(&queue->count) + processed;
-
- retval = do_QDIO(cdev, QDIO_FLAG_SYNC_INPUT, 0, start, count);
-
- if (unlikely(retval)) {
- atomic_set(&queue->count, count);
- zfcp_erp_adapter_reopen(qdio->adapter, 0, "qdrpb_1", NULL);
- } else {
- queue->first += count;
- queue->first %= QDIO_MAX_BUFFERS_PER_Q;
- atomic_set(&queue->count, 0);
- }
-}
-
static void zfcp_qdio_int_resp(struct ccw_device *cdev, unsigned int qdio_err,
- int queue_no, int first, int count,
+ int queue_no, int idx, int count,
unsigned long parm)
{
struct zfcp_qdio *qdio = (struct zfcp_qdio *) parm;
int sbal_idx, sbal_no;
if (unlikely(qdio_err)) {
- zfcp_dbf_hba_qdio(qdio->adapter->dbf, qdio_err, first,
- count);
- zfcp_qdio_handler_error(qdio, "qdires1");
+ zfcp_dbf_hba_qdio(qdio->adapter->dbf, qdio_err, idx, count);
+ zfcp_qdio_handler_error(qdio, "qdires1", qdio_err);
return;
}
@@ -129,25 +107,16 @@ static void zfcp_qdio_int_resp(struct ccw_device *cdev, unsigned int qdio_err,
* returned by QDIO layer
*/
for (sbal_no = 0; sbal_no < count; sbal_no++) {
- sbal_idx = (first + sbal_no) % QDIO_MAX_BUFFERS_PER_Q;
+ sbal_idx = (idx + sbal_no) % QDIO_MAX_BUFFERS_PER_Q;
/* go through all SBALEs of SBAL */
zfcp_fsf_reqid_check(qdio, sbal_idx);
}
/*
- * put range of SBALs back to response queue
- * (including SBALs which have already been free before)
+ * put SBALs back to response queue
*/
- zfcp_qdio_resp_put_back(qdio, count);
-}
-
-static void zfcp_qdio_sbal_limit(struct zfcp_qdio *qdio,
- struct zfcp_qdio_req *q_req, int max_sbals)
-{
- int count = atomic_read(&qdio->req_q.count);
- count = min(count, max_sbals);
- q_req->sbal_limit = (q_req->sbal_first + count - 1)
- % QDIO_MAX_BUFFERS_PER_Q;
+ if (do_QDIO(cdev, QDIO_FLAG_SYNC_INPUT, 0, idx, count))
+ zfcp_erp_adapter_reopen(qdio->adapter, 0, "qdires2", NULL);
}
static struct qdio_buffer_element *
@@ -173,6 +142,7 @@ zfcp_qdio_sbal_chain(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req)
/* keep this requests number of SBALs up-to-date */
q_req->sbal_number++;
+ BUG_ON(q_req->sbal_number > ZFCP_QDIO_MAX_SBALS_PER_REQ);
/* start at first SBALE of new SBAL */
q_req->sbale_curr = 0;
@@ -193,17 +163,6 @@ zfcp_qdio_sbale_next(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req)
return zfcp_qdio_sbale_curr(qdio, q_req);
}
-static void zfcp_qdio_undo_sbals(struct zfcp_qdio *qdio,
- struct zfcp_qdio_req *q_req)
-{
- struct qdio_buffer **sbal = qdio->req_q.sbal;
- int first = q_req->sbal_first;
- int last = q_req->sbal_last;
- int count = (last - first + QDIO_MAX_BUFFERS_PER_Q) %
- QDIO_MAX_BUFFERS_PER_Q + 1;
- zfcp_qdio_zero_sbals(sbal, first, count);
-}
-
/**
* zfcp_qdio_sbals_from_sg - fill SBALs from scatter-gather list
* @qdio: pointer to struct zfcp_qdio
@@ -213,14 +172,11 @@ static void zfcp_qdio_undo_sbals(struct zfcp_qdio *qdio,
* Returns: number of bytes, or error (negativ)
*/
int zfcp_qdio_sbals_from_sg(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req,
- struct scatterlist *sg, int max_sbals)
+ struct scatterlist *sg)
{
struct qdio_buffer_element *sbale;
int bytes = 0;
- /* figure out last allowed SBAL */
- zfcp_qdio_sbal_limit(qdio, q_req, max_sbals);
-
/* set storage-block type for this request */
sbale = zfcp_qdio_sbale_req(qdio, q_req);
sbale->flags |= q_req->sbtype;
@@ -229,7 +185,8 @@ int zfcp_qdio_sbals_from_sg(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req,
sbale = zfcp_qdio_sbale_next(qdio, q_req);
if (!sbale) {
atomic_inc(&qdio->req_q_full);
- zfcp_qdio_undo_sbals(qdio, q_req);
+ zfcp_qdio_zero_sbals(qdio->req_q, q_req->sbal_first,
+ q_req->sbal_number);
return -EINVAL;
}
@@ -239,19 +196,13 @@ int zfcp_qdio_sbals_from_sg(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req,
bytes += sg->length;
}
- /* assume that no other SBALEs are to follow in the same SBAL */
- sbale = zfcp_qdio_sbale_curr(qdio, q_req);
- sbale->flags |= SBAL_FLAGS_LAST_ENTRY;
-
return bytes;
}
static int zfcp_qdio_sbal_check(struct zfcp_qdio *qdio)
{
- struct zfcp_qdio_queue *req_q = &qdio->req_q;
-
spin_lock_bh(&qdio->req_q_lock);
- if (atomic_read(&req_q->count) ||
+ if (atomic_read(&qdio->req_q_free) ||
!(atomic_read(&qdio->adapter->status) & ZFCP_STATUS_ADAPTER_QDIOUP))
return 1;
spin_unlock_bh(&qdio->req_q_lock);
@@ -300,25 +251,25 @@ int zfcp_qdio_sbal_get(struct zfcp_qdio *qdio)
*/
int zfcp_qdio_send(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req)
{
- struct zfcp_qdio_queue *req_q = &qdio->req_q;
- int first = q_req->sbal_first;
- int count = q_req->sbal_number;
int retval;
- unsigned int qdio_flags = QDIO_FLAG_SYNC_OUTPUT;
+ u8 sbal_number = q_req->sbal_number;
zfcp_qdio_account(qdio);
- retval = do_QDIO(qdio->adapter->ccw_device, qdio_flags, 0, first,
- count);
+ retval = do_QDIO(qdio->adapter->ccw_device, QDIO_FLAG_SYNC_OUTPUT, 0,
+ q_req->sbal_first, sbal_number);
+
if (unlikely(retval)) {
- zfcp_qdio_zero_sbals(req_q->sbal, first, count);
+ zfcp_qdio_zero_sbals(qdio->req_q, q_req->sbal_first,
+ sbal_number);
return retval;
}
/* account for transferred buffers */
- atomic_sub(count, &req_q->count);
- req_q->first += count;
- req_q->first %= QDIO_MAX_BUFFERS_PER_Q;
+ atomic_sub(sbal_number, &qdio->req_q_free);
+ qdio->req_q_idx += sbal_number;
+ qdio->req_q_idx %= QDIO_MAX_BUFFERS_PER_Q;
+
return 0;
}
@@ -331,6 +282,7 @@ static void zfcp_qdio_setup_init_data(struct qdio_initialize *id,
id->q_format = QDIO_ZFCP_QFMT;
memcpy(id->adapter_name, dev_name(&id->cdev->dev), 8);
ASCEBC(id->adapter_name, 8);
+ id->qib_rflags = QIB_RFLAGS_ENABLE_DATA_DIV;
id->qib_param_field_format = 0;
id->qib_param_field = NULL;
id->input_slib_elements = NULL;
@@ -340,10 +292,10 @@ static void zfcp_qdio_setup_init_data(struct qdio_initialize *id,
id->input_handler = zfcp_qdio_int_resp;
id->output_handler = zfcp_qdio_int_req;
id->int_parm = (unsigned long) qdio;
- id->input_sbal_addr_array = (void **) (qdio->resp_q.sbal);
- id->output_sbal_addr_array = (void **) (qdio->req_q.sbal);
-
+ id->input_sbal_addr_array = (void **) (qdio->res_q);
+ id->output_sbal_addr_array = (void **) (qdio->req_q);
}
+
/**
* zfcp_qdio_allocate - allocate queue memory and initialize QDIO data
* @adapter: pointer to struct zfcp_adapter
@@ -354,8 +306,8 @@ static int zfcp_qdio_allocate(struct zfcp_qdio *qdio)
{
struct qdio_initialize init_data;
- if (zfcp_qdio_buffers_enqueue(qdio->req_q.sbal) ||
- zfcp_qdio_buffers_enqueue(qdio->resp_q.sbal))
+ if (zfcp_qdio_buffers_enqueue(qdio->req_q) ||
+ zfcp_qdio_buffers_enqueue(qdio->res_q))
return -ENOMEM;
zfcp_qdio_setup_init_data(&init_data, qdio);
@@ -369,34 +321,30 @@ static int zfcp_qdio_allocate(struct zfcp_qdio *qdio)
*/
void zfcp_qdio_close(struct zfcp_qdio *qdio)
{
- struct zfcp_qdio_queue *req_q;
- int first, count;
+ struct zfcp_adapter *adapter = qdio->adapter;
+ int idx, count;
- if (!(atomic_read(&qdio->adapter->status) & ZFCP_STATUS_ADAPTER_QDIOUP))
+ if (!(atomic_read(&adapter->status) & ZFCP_STATUS_ADAPTER_QDIOUP))
return;
/* clear QDIOUP flag, thus do_QDIO is not called during qdio_shutdown */
- req_q = &qdio->req_q;
spin_lock_bh(&qdio->req_q_lock);
- atomic_clear_mask(ZFCP_STATUS_ADAPTER_QDIOUP, &qdio->adapter->status);
+ atomic_clear_mask(ZFCP_STATUS_ADAPTER_QDIOUP, &adapter->status);
spin_unlock_bh(&qdio->req_q_lock);
wake_up(&qdio->req_q_wq);
- qdio_shutdown(qdio->adapter->ccw_device,
- QDIO_FLAG_CLEANUP_USING_CLEAR);
+ qdio_shutdown(adapter->ccw_device, QDIO_FLAG_CLEANUP_USING_CLEAR);
/* cleanup used outbound sbals */
- count = atomic_read(&req_q->count);
+ count = atomic_read(&qdio->req_q_free);
if (count < QDIO_MAX_BUFFERS_PER_Q) {
- first = (req_q->first + count) % QDIO_MAX_BUFFERS_PER_Q;
+ idx = (qdio->req_q_idx + count) % QDIO_MAX_BUFFERS_PER_Q;
count = QDIO_MAX_BUFFERS_PER_Q - count;
- zfcp_qdio_zero_sbals(req_q->sbal, first, count);
+ zfcp_qdio_zero_sbals(qdio->req_q, idx, count);
}
- req_q->first = 0;
- atomic_set(&req_q->count, 0);
- qdio->resp_q.first = 0;
- atomic_set(&qdio->resp_q.count, 0);
+ qdio->req_q_idx = 0;
+ atomic_set(&qdio->req_q_free, 0);
}
/**
@@ -408,34 +356,45 @@ int zfcp_qdio_open(struct zfcp_qdio *qdio)
{
struct qdio_buffer_element *sbale;
struct qdio_initialize init_data;
- struct ccw_device *cdev = qdio->adapter->ccw_device;
+ struct zfcp_adapter *adapter = qdio->adapter;
+ struct ccw_device *cdev = adapter->ccw_device;
+ struct qdio_ssqd_desc ssqd;
int cc;
- if (atomic_read(&qdio->adapter->status) & ZFCP_STATUS_ADAPTER_QDIOUP)
+ if (atomic_read(&adapter->status) & ZFCP_STATUS_ADAPTER_QDIOUP)
return -EIO;
+ atomic_clear_mask(ZFCP_STATUS_ADAPTER_SIOSL_ISSUED,
+ &qdio->adapter->status);
+
zfcp_qdio_setup_init_data(&init_data, qdio);
if (qdio_establish(&init_data))
goto failed_establish;
+ if (qdio_get_ssqd_desc(init_data.cdev, &ssqd))
+ goto failed_qdio;
+
+ if (ssqd.qdioac2 & CHSC_AC2_DATA_DIV_ENABLED)
+ atomic_set_mask(ZFCP_STATUS_ADAPTER_DATA_DIV_ENABLED,
+ &qdio->adapter->status);
+
if (qdio_activate(cdev))
goto failed_qdio;
for (cc = 0; cc < QDIO_MAX_BUFFERS_PER_Q; cc++) {
- sbale = &(qdio->resp_q.sbal[cc]->element[0]);
+ sbale = &(qdio->res_q[cc]->element[0]);
sbale->length = 0;
sbale->flags = SBAL_FLAGS_LAST_ENTRY;
sbale->addr = NULL;
}
- if (do_QDIO(cdev, QDIO_FLAG_SYNC_INPUT, 0, 0,
- QDIO_MAX_BUFFERS_PER_Q))
+ if (do_QDIO(cdev, QDIO_FLAG_SYNC_INPUT, 0, 0, QDIO_MAX_BUFFERS_PER_Q))
goto failed_qdio;
/* set index of first avalable SBALS / number of available SBALS */
- qdio->req_q.first = 0;
- atomic_set(&qdio->req_q.count, QDIO_MAX_BUFFERS_PER_Q);
+ qdio->req_q_idx = 0;
+ atomic_set(&qdio->req_q_free, QDIO_MAX_BUFFERS_PER_Q);
return 0;
@@ -449,7 +408,6 @@ failed_establish:
void zfcp_qdio_destroy(struct zfcp_qdio *qdio)
{
- struct qdio_buffer **sbal_req, **sbal_resp;
int p;
if (!qdio)
@@ -458,12 +416,9 @@ void zfcp_qdio_destroy(struct zfcp_qdio *qdio)
if (qdio->adapter->ccw_device)
qdio_free(qdio->adapter->ccw_device);
- sbal_req = qdio->req_q.sbal;
- sbal_resp = qdio->resp_q.sbal;
-
for (p = 0; p < QDIO_MAX_BUFFERS_PER_Q; p += QBUFF_PER_PAGE) {
- free_page((unsigned long) sbal_req[p]);
- free_page((unsigned long) sbal_resp[p]);
+ free_page((unsigned long) qdio->req_q[p]);
+ free_page((unsigned long) qdio->res_q[p]);
}
kfree(qdio);
@@ -491,3 +446,26 @@ int zfcp_qdio_setup(struct zfcp_adapter *adapter)
return 0;
}
+/**
+ * zfcp_qdio_siosl - Trigger logging in FCP channel
+ * @adapter: The zfcp_adapter where to trigger logging
+ *
+ * Call the cio siosl function to trigger hardware logging. This
+ * wrapper function sets a flag to ensure hardware logging is only
+ * triggered once before going through qdio shutdown.
+ *
+ * The triggers are always run from qdio tasklet context, so no
+ * additional synchronization is necessary.
+ */
+void zfcp_qdio_siosl(struct zfcp_adapter *adapter)
+{
+ int rc;
+
+ if (atomic_read(&adapter->status) & ZFCP_STATUS_ADAPTER_SIOSL_ISSUED)
+ return;
+
+ rc = ccw_device_siosl(adapter->ccw_device);
+ if (!rc)
+ atomic_set_mask(ZFCP_STATUS_ADAPTER_SIOSL_ISSUED,
+ &adapter->status);
+}
diff --git a/drivers/s390/scsi/zfcp_qdio.h b/drivers/s390/scsi/zfcp_qdio.h
index 138fba577b4..2297d8d3e94 100644
--- a/drivers/s390/scsi/zfcp_qdio.h
+++ b/drivers/s390/scsi/zfcp_qdio.h
@@ -19,22 +19,20 @@
/* index of last SBALE (with respect to DMQ bug workaround) */
#define ZFCP_QDIO_LAST_SBALE_PER_SBAL (ZFCP_QDIO_MAX_SBALES_PER_SBAL - 1)
-/**
- * struct zfcp_qdio_queue - qdio queue buffer, zfcp index and free count
- * @sbal: qdio buffers
- * @first: index of next free buffer in queue
- * @count: number of free buffers in queue
- */
-struct zfcp_qdio_queue {
- struct qdio_buffer *sbal[QDIO_MAX_BUFFERS_PER_Q];
- u8 first;
- atomic_t count;
-};
+/* Max SBALS for chaining */
+#define ZFCP_QDIO_MAX_SBALS_PER_REQ 36
+
+/* max. number of (data buffer) SBALEs in largest SBAL chain
+ * request ID + QTCB in SBALE 0 + 1 of first SBAL in chain */
+#define ZFCP_QDIO_MAX_SBALES_PER_REQ \
+ (ZFCP_QDIO_MAX_SBALS_PER_REQ * ZFCP_QDIO_MAX_SBALES_PER_SBAL - 2)
/**
* struct zfcp_qdio - basic qdio data structure
- * @resp_q: response queue
+ * @res_q: response queue
* @req_q: request queue
+ * @req_q_idx: index of next free buffer
+ * @req_q_free: number of free buffers in queue
* @stat_lock: lock to protect req_q_util and req_q_time
* @req_q_lock: lock to serialize access to request queue
* @req_q_time: time of last fill level change
@@ -44,8 +42,10 @@ struct zfcp_qdio_queue {
* @adapter: adapter used in conjunction with this qdio structure
*/
struct zfcp_qdio {
- struct zfcp_qdio_queue resp_q;
- struct zfcp_qdio_queue req_q;
+ struct qdio_buffer *res_q[QDIO_MAX_BUFFERS_PER_Q];
+ struct qdio_buffer *req_q[QDIO_MAX_BUFFERS_PER_Q];
+ u8 req_q_idx;
+ atomic_t req_q_free;
spinlock_t stat_lock;
spinlock_t req_q_lock;
unsigned long long req_q_time;
@@ -65,7 +65,6 @@ struct zfcp_qdio {
* @sbale_curr: current sbale at creation of this request
* @sbal_response: sbal used in interrupt
* @qdio_outb_usage: usage of outbound queue
- * @qdio_inb_usage: usage of inbound queue
*/
struct zfcp_qdio_req {
u32 sbtype;
@@ -76,22 +75,9 @@ struct zfcp_qdio_req {
u8 sbale_curr;
u8 sbal_response;
u16 qdio_outb_usage;
- u16 qdio_inb_usage;
};
/**
- * zfcp_qdio_sbale - return pointer to sbale in qdio queue
- * @q: queue where to find sbal
- * @sbal_idx: sbal index in queue
- * @sbale_idx: sbale index in sbal
- */
-static inline struct qdio_buffer_element *
-zfcp_qdio_sbale(struct zfcp_qdio_queue *q, int sbal_idx, int sbale_idx)
-{
- return &q->sbal[sbal_idx]->element[sbale_idx];
-}
-
-/**
* zfcp_qdio_sbale_req - return pointer to sbale on req_q for a request
* @qdio: pointer to struct zfcp_qdio
* @q_rec: pointer to struct zfcp_qdio_req
@@ -100,7 +86,7 @@ zfcp_qdio_sbale(struct zfcp_qdio_queue *q, int sbal_idx, int sbale_idx)
static inline struct qdio_buffer_element *
zfcp_qdio_sbale_req(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req)
{
- return zfcp_qdio_sbale(&qdio->req_q, q_req->sbal_last, 0);
+ return &qdio->req_q[q_req->sbal_last]->element[0];
}
/**
@@ -112,8 +98,7 @@ zfcp_qdio_sbale_req(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req)
static inline struct qdio_buffer_element *
zfcp_qdio_sbale_curr(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req)
{
- return zfcp_qdio_sbale(&qdio->req_q, q_req->sbal_last,
- q_req->sbale_curr);
+ return &qdio->req_q[q_req->sbal_last]->element[q_req->sbale_curr];
}
/**
@@ -134,21 +119,25 @@ void zfcp_qdio_req_init(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req,
unsigned long req_id, u32 sbtype, void *data, u32 len)
{
struct qdio_buffer_element *sbale;
+ int count = min(atomic_read(&qdio->req_q_free),
+ ZFCP_QDIO_MAX_SBALS_PER_REQ);
- q_req->sbal_first = q_req->sbal_last = qdio->req_q.first;
+ q_req->sbal_first = q_req->sbal_last = qdio->req_q_idx;
q_req->sbal_number = 1;
q_req->sbtype = sbtype;
+ q_req->sbale_curr = 1;
+ q_req->sbal_limit = (q_req->sbal_first + count - 1)
+ % QDIO_MAX_BUFFERS_PER_Q;
sbale = zfcp_qdio_sbale_req(qdio, q_req);
sbale->addr = (void *) req_id;
- sbale->flags |= SBAL_FLAGS0_COMMAND;
- sbale->flags |= sbtype;
+ sbale->flags = SBAL_FLAGS0_COMMAND | sbtype;
- q_req->sbale_curr = 1;
+ if (unlikely(!data))
+ return;
sbale++;
sbale->addr = data;
- if (likely(data))
- sbale->length = len;
+ sbale->length = len;
}
/**
@@ -210,4 +199,36 @@ void zfcp_qdio_skip_to_last_sbale(struct zfcp_qdio_req *q_req)
q_req->sbale_curr = ZFCP_QDIO_LAST_SBALE_PER_SBAL;
}
+/**
+ * zfcp_qdio_sbal_limit - set the sbal limit for a request in q_req
+ * @qdio: pointer to struct zfcp_qdio
+ * @q_req: The current zfcp_qdio_req
+ * @max_sbals: maximum number of SBALs allowed
+ */
+static inline
+void zfcp_qdio_sbal_limit(struct zfcp_qdio *qdio,
+ struct zfcp_qdio_req *q_req, int max_sbals)
+{
+ int count = min(atomic_read(&qdio->req_q_free), max_sbals);
+
+ q_req->sbal_limit = (q_req->sbal_first + count - 1) %
+ QDIO_MAX_BUFFERS_PER_Q;
+}
+
+/**
+ * zfcp_qdio_set_data_div - set data division count
+ * @qdio: pointer to struct zfcp_qdio
+ * @q_req: The current zfcp_qdio_req
+ * @count: The data division count
+ */
+static inline
+void zfcp_qdio_set_data_div(struct zfcp_qdio *qdio,
+ struct zfcp_qdio_req *q_req, u32 count)
+{
+ struct qdio_buffer_element *sbale;
+
+ sbale = &qdio->req_q[q_req->sbal_first]->element[0];
+ sbale->length = count;
+}
+
#endif /* ZFCP_QDIO_H */
diff --git a/drivers/s390/scsi/zfcp_scsi.c b/drivers/s390/scsi/zfcp_scsi.c
index be5d2c60453..cb000c9833b 100644
--- a/drivers/s390/scsi/zfcp_scsi.c
+++ b/drivers/s390/scsi/zfcp_scsi.c
@@ -12,6 +12,7 @@
#include <linux/types.h>
#include <linux/slab.h>
#include <scsi/fc/fc_fcp.h>
+#include <scsi/scsi_eh.h>
#include <asm/atomic.h>
#include "zfcp_ext.h"
#include "zfcp_dbf.h"
@@ -22,6 +23,13 @@ static unsigned int default_depth = 32;
module_param_named(queue_depth, default_depth, uint, 0600);
MODULE_PARM_DESC(queue_depth, "Default queue depth for new SCSI devices");
+static bool enable_dif;
+
+#ifdef CONFIG_ZFCP_DIF
+module_param_named(dif, enable_dif, bool, 0600);
+MODULE_PARM_DESC(dif, "Enable DIF/DIX data integrity support");
+#endif
+
static int zfcp_scsi_change_queue_depth(struct scsi_device *sdev, int depth,
int reason)
{
@@ -506,8 +514,10 @@ static void zfcp_set_rport_dev_loss_tmo(struct fc_rport *rport, u32 timeout)
* @rport: The FC rport where to teminate I/O
*
* Abort all pending SCSI commands for a port by closing the
- * port. Using a reopen avoiding a conflict with a shutdown
- * overwriting a reopen.
+ * port. Using a reopen avoids a conflict with a shutdown
+ * overwriting a reopen. The "forced" ensures that a disappeared port
+ * is not opened again as valid due to the cached plogi data in
+ * non-NPIV mode.
*/
static void zfcp_scsi_terminate_rport_io(struct fc_rport *rport)
{
@@ -519,11 +529,25 @@ static void zfcp_scsi_terminate_rport_io(struct fc_rport *rport)
port = zfcp_get_port_by_wwpn(adapter, rport->port_name);
if (port) {
- zfcp_erp_port_reopen(port, 0, "sctrpi1", NULL);
+ zfcp_erp_port_forced_reopen(port, 0, "sctrpi1", NULL);
put_device(&port->dev);
}
}
+static void zfcp_scsi_queue_unit_register(struct zfcp_port *port)
+{
+ struct zfcp_unit *unit;
+
+ read_lock_irq(&port->unit_list_lock);
+ list_for_each_entry(unit, &port->unit_list, list) {
+ get_device(&unit->dev);
+ if (scsi_queue_work(port->adapter->scsi_host,
+ &unit->scsi_work) <= 0)
+ put_device(&unit->dev);
+ }
+ read_unlock_irq(&port->unit_list_lock);
+}
+
static void zfcp_scsi_rport_register(struct zfcp_port *port)
{
struct fc_rport_identifiers ids;
@@ -548,6 +572,9 @@ static void zfcp_scsi_rport_register(struct zfcp_port *port)
rport->maxframe_size = port->maxframe_size;
rport->supported_classes = port->supported_classes;
port->rport = rport;
+ port->starget_id = rport->scsi_target_id;
+
+ zfcp_scsi_queue_unit_register(port);
}
static void zfcp_scsi_rport_block(struct zfcp_port *port)
@@ -610,24 +637,74 @@ void zfcp_scsi_rport_work(struct work_struct *work)
put_device(&port->dev);
}
-
-void zfcp_scsi_scan(struct work_struct *work)
+/**
+ * zfcp_scsi_scan - Register LUN with SCSI midlayer
+ * @unit: The LUN/unit to register
+ */
+void zfcp_scsi_scan(struct zfcp_unit *unit)
{
- struct zfcp_unit *unit = container_of(work, struct zfcp_unit,
- scsi_work);
- struct fc_rport *rport;
-
- flush_work(&unit->port->rport_work);
- rport = unit->port->rport;
+ struct fc_rport *rport = unit->port->rport;
if (rport && rport->port_state == FC_PORTSTATE_ONLINE)
scsi_scan_target(&rport->dev, 0, rport->scsi_target_id,
scsilun_to_int((struct scsi_lun *)
&unit->fcp_lun), 0);
+}
+void zfcp_scsi_scan_work(struct work_struct *work)
+{
+ struct zfcp_unit *unit = container_of(work, struct zfcp_unit,
+ scsi_work);
+
+ zfcp_scsi_scan(unit);
put_device(&unit->dev);
}
+/**
+ * zfcp_scsi_set_prot - Configure DIF/DIX support in scsi_host
+ * @adapter: The adapter where to configure DIF/DIX for the SCSI host
+ */
+void zfcp_scsi_set_prot(struct zfcp_adapter *adapter)
+{
+ unsigned int mask = 0;
+ unsigned int data_div;
+ struct Scsi_Host *shost = adapter->scsi_host;
+
+ data_div = atomic_read(&adapter->status) &
+ ZFCP_STATUS_ADAPTER_DATA_DIV_ENABLED;
+
+ if (enable_dif &&
+ adapter->adapter_features & FSF_FEATURE_DIF_PROT_TYPE1)
+ mask |= SHOST_DIF_TYPE1_PROTECTION;
+
+ if (enable_dif && data_div &&
+ adapter->adapter_features & FSF_FEATURE_DIX_PROT_TCPIP) {
+ mask |= SHOST_DIX_TYPE1_PROTECTION;
+ scsi_host_set_guard(shost, SHOST_DIX_GUARD_IP);
+ shost->sg_tablesize = ZFCP_QDIO_MAX_SBALES_PER_REQ / 2;
+ shost->max_sectors = ZFCP_QDIO_MAX_SBALES_PER_REQ * 8 / 2;
+ }
+
+ scsi_host_set_prot(shost, mask);
+}
+
+/**
+ * zfcp_scsi_dif_sense_error - Report DIF/DIX error as driver sense error
+ * @scmd: The SCSI command to report the error for
+ * @ascq: The ASCQ to put in the sense buffer
+ *
+ * See the error handling in sd_done for the sense codes used here.
+ * Set DID_SOFT_ERROR to retry the request, if possible.
+ */
+void zfcp_scsi_dif_sense_error(struct scsi_cmnd *scmd, int ascq)
+{
+ scsi_build_sense_buffer(1, scmd->sense_buffer,
+ ILLEGAL_REQUEST, 0x10, ascq);
+ set_driver_byte(scmd, DRIVER_SENSE);
+ scmd->result |= SAM_STAT_CHECK_CONDITION;
+ set_host_byte(scmd, DID_SOFT_ERROR);
+}
+
struct fc_function_template zfcp_transport_functions = {
.show_starget_port_id = 1,
.show_starget_port_name = 1,
@@ -677,11 +754,11 @@ struct zfcp_data zfcp_data = {
.eh_host_reset_handler = zfcp_scsi_eh_host_reset_handler,
.can_queue = 4096,
.this_id = -1,
- .sg_tablesize = ZFCP_FSF_MAX_SBALES_PER_REQ,
+ .sg_tablesize = ZFCP_QDIO_MAX_SBALES_PER_REQ,
.cmd_per_lun = 1,
.use_clustering = 1,
.sdev_attrs = zfcp_sysfs_sdev_attrs,
- .max_sectors = (ZFCP_FSF_MAX_SBALES_PER_REQ * 8),
+ .max_sectors = (ZFCP_QDIO_MAX_SBALES_PER_REQ * 8),
.dma_boundary = ZFCP_QDIO_SBALE_LEN - 1,
.shost_attrs = zfcp_sysfs_shost_attrs,
},
diff --git a/drivers/s390/scsi/zfcp_sysfs.c b/drivers/s390/scsi/zfcp_sysfs.c
index f5f60698dc4..b4561c86e23 100644
--- a/drivers/s390/scsi/zfcp_sysfs.c
+++ b/drivers/s390/scsi/zfcp_sysfs.c
@@ -275,7 +275,7 @@ static ssize_t zfcp_sysfs_unit_add_store(struct device *dev,
zfcp_erp_unit_reopen(unit, 0, "syuas_1", NULL);
zfcp_erp_wait(unit->port->adapter);
- flush_work(&unit->scsi_work);
+ zfcp_scsi_scan(unit);
out:
put_device(&port->dev);
return retval ? retval : (ssize_t) count;
@@ -290,6 +290,7 @@ static ssize_t zfcp_sysfs_unit_remove_store(struct device *dev,
struct zfcp_unit *unit;
u64 fcp_lun;
int retval = -EINVAL;
+ struct scsi_device *sdev;
if (!(port && get_device(&port->dev)))
return -EBUSY;
@@ -303,8 +304,13 @@ static ssize_t zfcp_sysfs_unit_remove_store(struct device *dev,
else
retval = 0;
- /* wait for possible timeout during SCSI probe */
- flush_work(&unit->scsi_work);
+ sdev = scsi_device_lookup(port->adapter->scsi_host, 0,
+ port->starget_id,
+ scsilun_to_int((struct scsi_lun *)&fcp_lun));
+ if (sdev) {
+ scsi_remove_device(sdev);
+ scsi_device_put(sdev);
+ }
write_lock_irq(&port->unit_list_lock);
list_del(&unit->list);
diff --git a/drivers/sbus/char/bbc_i2c.c b/drivers/sbus/char/bbc_i2c.c
index 8bfdd63a1fc..3e89c313e98 100644
--- a/drivers/sbus/char/bbc_i2c.c
+++ b/drivers/sbus/char/bbc_i2c.c
@@ -317,7 +317,7 @@ static struct bbc_i2c_bus * __init attach_one_i2c(struct of_device *op, int inde
bp->waiting = 0;
init_waitqueue_head(&bp->wq);
- if (request_irq(op->irqs[0], bbc_i2c_interrupt,
+ if (request_irq(op->archdata.irqs[0], bbc_i2c_interrupt,
IRQF_SHARED, "bbc_i2c", bp))
goto fail;
@@ -373,7 +373,7 @@ static int __devinit bbc_i2c_probe(struct of_device *op,
err = bbc_envctrl_init(bp);
if (err) {
- free_irq(op->irqs[0], bp);
+ free_irq(op->archdata.irqs[0], bp);
if (bp->i2c_bussel_reg)
of_iounmap(&op->resource[0], bp->i2c_bussel_reg, 1);
if (bp->i2c_control_regs)
@@ -392,7 +392,7 @@ static int __devexit bbc_i2c_remove(struct of_device *op)
bbc_envctrl_cleanup(bp);
- free_irq(op->irqs[0], bp);
+ free_irq(op->archdata.irqs[0], bp);
if (bp->i2c_bussel_reg)
of_iounmap(&op->resource[0], bp->i2c_bussel_reg, 1);
@@ -425,12 +425,12 @@ static struct of_platform_driver bbc_i2c_driver = {
static int __init bbc_i2c_init(void)
{
- return of_register_driver(&bbc_i2c_driver, &of_bus_type);
+ return of_register_platform_driver(&bbc_i2c_driver);
}
static void __exit bbc_i2c_exit(void)
{
- of_unregister_driver(&bbc_i2c_driver);
+ of_unregister_platform_driver(&bbc_i2c_driver);
}
module_init(bbc_i2c_init);
diff --git a/drivers/sbus/char/display7seg.c b/drivers/sbus/char/display7seg.c
index 7baf1b64403..47db97583ea 100644
--- a/drivers/sbus/char/display7seg.c
+++ b/drivers/sbus/char/display7seg.c
@@ -13,7 +13,7 @@
#include <linux/miscdevice.h>
#include <linux/ioport.h> /* request_region */
#include <linux/slab.h>
-#include <linux/smp_lock.h>
+#include <linux/mutex.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <asm/atomic.h>
@@ -26,6 +26,7 @@
#define DRIVER_NAME "d7s"
#define PFX DRIVER_NAME ": "
+static DEFINE_MUTEX(d7s_mutex);
static int sol_compat = 0; /* Solaris compatibility mode */
/* Solaris compatibility flag -
@@ -74,7 +75,6 @@ static int d7s_open(struct inode *inode, struct file *f)
{
if (D7S_MINOR != iminor(inode))
return -ENODEV;
- cycle_kernel_lock();
atomic_inc(&d7s_users);
return 0;
}
@@ -110,7 +110,7 @@ static long d7s_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
if (D7S_MINOR != iminor(file->f_path.dentry->d_inode))
return -ENODEV;
- lock_kernel();
+ mutex_lock(&d7s_mutex);
switch (cmd) {
case D7SIOCWR:
/* assign device register values we mask-out D7S_FLIP
@@ -151,7 +151,7 @@ static long d7s_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
writeb(regs, p->regs);
break;
};
- unlock_kernel();
+ mutex_unlock(&d7s_mutex);
return error;
}
@@ -277,12 +277,12 @@ static struct of_platform_driver d7s_driver = {
static int __init d7s_init(void)
{
- return of_register_driver(&d7s_driver, &of_bus_type);
+ return of_register_platform_driver(&d7s_driver);
}
static void __exit d7s_exit(void)
{
- of_unregister_driver(&d7s_driver);
+ of_unregister_platform_driver(&d7s_driver);
}
module_init(d7s_init);
diff --git a/drivers/sbus/char/envctrl.c b/drivers/sbus/char/envctrl.c
index c8166ecf527..3c27f45e2b6 100644
--- a/drivers/sbus/char/envctrl.c
+++ b/drivers/sbus/char/envctrl.c
@@ -27,7 +27,6 @@
#include <linux/kmod.h>
#include <linux/reboot.h>
#include <linux/slab.h>
-#include <linux/smp_lock.h>
#include <linux/of.h>
#include <linux/of_device.h>
@@ -699,7 +698,6 @@ envctrl_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
static int
envctrl_open(struct inode *inode, struct file *file)
{
- cycle_kernel_lock();
file->private_data = NULL;
return 0;
}
@@ -1142,12 +1140,12 @@ static struct of_platform_driver envctrl_driver = {
static int __init envctrl_init(void)
{
- return of_register_driver(&envctrl_driver, &of_bus_type);
+ return of_register_platform_driver(&envctrl_driver);
}
static void __exit envctrl_exit(void)
{
- of_unregister_driver(&envctrl_driver);
+ of_unregister_platform_driver(&envctrl_driver);
}
module_init(envctrl_init);
diff --git a/drivers/sbus/char/flash.c b/drivers/sbus/char/flash.c
index 368d66294d8..8bb31c584b6 100644
--- a/drivers/sbus/char/flash.c
+++ b/drivers/sbus/char/flash.c
@@ -10,7 +10,7 @@
#include <linux/fcntl.h>
#include <linux/poll.h>
#include <linux/init.h>
-#include <linux/smp_lock.h>
+#include <linux/mutex.h>
#include <linux/spinlock.h>
#include <linux/mm.h>
#include <linux/of.h>
@@ -22,6 +22,7 @@
#include <asm/io.h>
#include <asm/upa.h>
+static DEFINE_MUTEX(flash_mutex);
static DEFINE_SPINLOCK(flash_lock);
static struct {
unsigned long read_base; /* Physical read address */
@@ -80,7 +81,7 @@ flash_mmap(struct file *file, struct vm_area_struct *vma)
static long long
flash_llseek(struct file *file, long long offset, int origin)
{
- lock_kernel();
+ mutex_lock(&flash_mutex);
switch (origin) {
case 0:
file->f_pos = offset;
@@ -94,10 +95,10 @@ flash_llseek(struct file *file, long long offset, int origin)
file->f_pos = flash.read_size;
break;
default:
- unlock_kernel();
+ mutex_unlock(&flash_mutex);
return -EINVAL;
}
- unlock_kernel();
+ mutex_unlock(&flash_mutex);
return file->f_pos;
}
@@ -125,13 +126,13 @@ flash_read(struct file * file, char __user * buf,
static int
flash_open(struct inode *inode, struct file *file)
{
- lock_kernel();
+ mutex_lock(&flash_mutex);
if (test_and_set_bit(0, (void *)&flash.busy) != 0) {
- unlock_kernel();
+ mutex_unlock(&flash_mutex);
return -EBUSY;
}
- unlock_kernel();
+ mutex_unlock(&flash_mutex);
return 0;
}
@@ -218,12 +219,12 @@ static struct of_platform_driver flash_driver = {
static int __init flash_init(void)
{
- return of_register_driver(&flash_driver, &of_bus_type);
+ return of_register_platform_driver(&flash_driver);
}
static void __exit flash_cleanup(void)
{
- of_unregister_driver(&flash_driver);
+ of_unregister_platform_driver(&flash_driver);
}
module_init(flash_init);
diff --git a/drivers/sbus/char/openprom.c b/drivers/sbus/char/openprom.c
index aacbe14e2e7..8d6e508222b 100644
--- a/drivers/sbus/char/openprom.c
+++ b/drivers/sbus/char/openprom.c
@@ -33,7 +33,7 @@
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/slab.h>
-#include <linux/smp_lock.h>
+#include <linux/mutex.h>
#include <linux/string.h>
#include <linux/miscdevice.h>
#include <linux/init.h>
@@ -61,6 +61,7 @@ typedef struct openprom_private_data
} DATA;
/* ID of the PROM node containing all of the EEPROM options. */
+static DEFINE_MUTEX(openprom_mutex);
static struct device_node *options_node;
/*
@@ -316,7 +317,7 @@ static long openprom_sunos_ioctl(struct file * file,
if (bufsize < 0)
return bufsize;
- lock_kernel();
+ mutex_lock(&openprom_mutex);
switch (cmd) {
case OPROMGETOPT:
@@ -367,7 +368,7 @@ static long openprom_sunos_ioctl(struct file * file,
}
kfree(opp);
- unlock_kernel();
+ mutex_unlock(&openprom_mutex);
return error;
}
@@ -558,7 +559,7 @@ static int openprom_bsd_ioctl(struct file * file,
void __user *argp = (void __user *)arg;
int err;
- lock_kernel();
+ mutex_lock(&openprom_mutex);
switch (cmd) {
case OPIOCGET:
err = opiocget(argp, data);
@@ -589,7 +590,7 @@ static int openprom_bsd_ioctl(struct file * file,
err = -EINVAL;
break;
};
- unlock_kernel();
+ mutex_unlock(&openprom_mutex);
return err;
}
@@ -697,11 +698,11 @@ static int openprom_open(struct inode * inode, struct file * file)
if (!data)
return -ENOMEM;
- lock_kernel();
+ mutex_lock(&openprom_mutex);
data->current_node = of_find_node_by_path("/");
data->lastnode = data->current_node;
file->private_data = (void *) data;
- unlock_kernel();
+ mutex_unlock(&openprom_mutex);
return 0;
}
diff --git a/drivers/sbus/char/uctrl.c b/drivers/sbus/char/uctrl.c
index 5f253665a1d..41eb6725ff5 100644
--- a/drivers/sbus/char/uctrl.c
+++ b/drivers/sbus/char/uctrl.c
@@ -9,7 +9,7 @@
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/slab.h>
-#include <linux/smp_lock.h>
+#include <linux/mutex.h>
#include <linux/ioport.h>
#include <linux/init.h>
#include <linux/miscdevice.h>
@@ -72,6 +72,7 @@ struct ts102_regs {
#define UCTRL_STAT_RXNE_STA 0x04 /* receive FIFO not empty status */
#define UCTRL_STAT_RXO_STA 0x08 /* receive FIFO overflow status */
+static DEFINE_MUTEX(uctrl_mutex);
static const char *uctrl_extstatus[16] = {
"main power available",
"internal battery attached",
@@ -210,10 +211,10 @@ uctrl_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
static int
uctrl_open(struct inode *inode, struct file *file)
{
- lock_kernel();
+ mutex_lock(&uctrl_mutex);
uctrl_get_event_status(global_driver);
uctrl_get_external_status(global_driver);
- unlock_kernel();
+ mutex_unlock(&uctrl_mutex);
return 0;
}
@@ -367,7 +368,7 @@ static int __devinit uctrl_probe(struct of_device *op,
goto out_free;
}
- p->irq = op->irqs[0];
+ p->irq = op->archdata.irqs[0];
err = request_irq(p->irq, uctrl_interrupt, 0, "uctrl", p);
if (err) {
printk(KERN_ERR "uctrl: Unable to register irq.\n");
@@ -437,12 +438,12 @@ static struct of_platform_driver uctrl_driver = {
static int __init uctrl_init(void)
{
- return of_register_driver(&uctrl_driver, &of_bus_type);
+ return of_register_platform_driver(&uctrl_driver);
}
static void __exit uctrl_exit(void)
{
- of_unregister_driver(&uctrl_driver);
+ of_unregister_platform_driver(&uctrl_driver);
}
module_init(uctrl_init);
diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig
index 75f2336807c..158284f0573 100644
--- a/drivers/scsi/Kconfig
+++ b/drivers/scsi/Kconfig
@@ -1847,6 +1847,10 @@ config ZFCP
called zfcp. If you want to compile it as a module, say M here
and read <file:Documentation/kbuild/modules.txt>.
+config ZFCP_DIF
+ tristate "T10 DIF/DIX support for the zfcp driver (EXPERIMENTAL)"
+ depends on ZFCP && EXPERIMENTAL
+
config SCSI_PMCRAID
tristate "PMC SIERRA Linux MaxRAID adapter support"
depends on PCI && SCSI
diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile
index 1c7ac49be64..2a3fca2eca6 100644
--- a/drivers/scsi/Makefile
+++ b/drivers/scsi/Makefile
@@ -163,6 +163,7 @@ scsi_mod-$(CONFIG_SCSI_NETLINK) += scsi_netlink.o
scsi_mod-$(CONFIG_SYSCTL) += scsi_sysctl.o
scsi_mod-$(CONFIG_SCSI_PROC_FS) += scsi_proc.o
scsi_mod-y += scsi_trace.o
+scsi_mod-$(CONFIG_PM_OPS) += scsi_pm.o
scsi_tgt-y += scsi_tgt_lib.o scsi_tgt_if.o
diff --git a/drivers/scsi/aacraid/linit.c b/drivers/scsi/aacraid/linit.c
index 33898b61fdb..cad6f9abaeb 100644
--- a/drivers/scsi/aacraid/linit.c
+++ b/drivers/scsi/aacraid/linit.c
@@ -1091,6 +1091,7 @@ static int __devinit aac_probe_one(struct pci_dev *pdev,
struct list_head *insert = &aac_devices;
int error = -ENODEV;
int unique_id = 0;
+ u64 dmamask;
list_for_each_entry(aac, &aac_devices, entry) {
if (aac->id > unique_id)
@@ -1104,17 +1105,18 @@ static int __devinit aac_probe_one(struct pci_dev *pdev,
goto out;
error = -ENODEV;
- if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32)) ||
- pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)))
- goto out_disable_pdev;
/*
* If the quirk31 bit is set, the adapter needs adapter
* to driver communication memory to be allocated below 2gig
*/
if (aac_drivers[index].quirks & AAC_QUIRK_31BIT)
- if (pci_set_dma_mask(pdev, DMA_BIT_MASK(31)) ||
- pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(31)))
- goto out_disable_pdev;
+ dmamask = DMA_BIT_MASK(31);
+ else
+ dmamask = DMA_BIT_MASK(32);
+
+ if (pci_set_dma_mask(pdev, dmamask) ||
+ pci_set_consistent_dma_mask(pdev, dmamask))
+ goto out_disable_pdev;
pci_set_master(pdev);
diff --git a/drivers/scsi/advansys.c b/drivers/scsi/advansys.c
index 7f87979da22..0ec3da6f3e1 100644
--- a/drivers/scsi/advansys.c
+++ b/drivers/scsi/advansys.c
@@ -9717,7 +9717,7 @@ static ushort __devinit AscInitAscDvcVar(ASC_DVC_VAR *asc_dvc)
asc_dvc->bug_fix_cntl = 0;
asc_dvc->pci_fix_asyn_xfer = 0;
asc_dvc->pci_fix_asyn_xfer_always = 0;
- /* asc_dvc->init_state initalized in AscInitGetConfig(). */
+ /* asc_dvc->init_state initialized in AscInitGetConfig(). */
asc_dvc->sdtr_done = 0;
asc_dvc->cur_total_qng = 0;
asc_dvc->is_in_int = 0;
diff --git a/drivers/scsi/aic7xxx/aic7770.c b/drivers/scsi/aic7xxx/aic7770.c
index 6d86a9be538..5000bd69c13 100644
--- a/drivers/scsi/aic7xxx/aic7770.c
+++ b/drivers/scsi/aic7xxx/aic7770.c
@@ -170,7 +170,7 @@ aic7770_config(struct ahc_softc *ahc, struct aic7770_identity *entry, u_int io)
case 15:
break;
default:
- printf("aic7770_config: invalid irq setting %d\n", intdef);
+ printk("aic7770_config: invalid irq setting %d\n", intdef);
return (ENXIO);
}
@@ -221,7 +221,7 @@ aic7770_config(struct ahc_softc *ahc, struct aic7770_identity *entry, u_int io)
break;
}
if (have_seeprom == 0) {
- free(ahc->seep_config, M_DEVBUF);
+ kfree(ahc->seep_config);
ahc->seep_config = NULL;
}
@@ -293,7 +293,7 @@ aha2840_load_seeprom(struct ahc_softc *ahc)
sc = ahc->seep_config;
if (bootverbose)
- printf("%s: Reading SEEPROM...", ahc_name(ahc));
+ printk("%s: Reading SEEPROM...", ahc_name(ahc));
have_seeprom = ahc_read_seeprom(&sd, (uint16_t *)sc,
/*start_addr*/0, sizeof(*sc)/2);
@@ -301,16 +301,16 @@ aha2840_load_seeprom(struct ahc_softc *ahc)
if (ahc_verify_cksum(sc) == 0) {
if(bootverbose)
- printf ("checksum error\n");
+ printk ("checksum error\n");
have_seeprom = 0;
} else if (bootverbose) {
- printf("done.\n");
+ printk("done.\n");
}
}
if (!have_seeprom) {
if (bootverbose)
- printf("%s: No SEEPROM available\n", ahc_name(ahc));
+ printk("%s: No SEEPROM available\n", ahc_name(ahc));
ahc->flags |= AHC_USEDEFAULTS;
} else {
/*
diff --git a/drivers/scsi/aic7xxx/aic7770_osm.c b/drivers/scsi/aic7xxx/aic7770_osm.c
index f220e5e436a..0cb8ef64b5c 100644
--- a/drivers/scsi/aic7xxx/aic7770_osm.c
+++ b/drivers/scsi/aic7xxx/aic7770_osm.c
@@ -85,7 +85,7 @@ aic7770_probe(struct device *dev)
int error;
sprintf(buf, "ahc_eisa:%d", eisaBase >> 12);
- name = malloc(strlen(buf) + 1, M_DEVBUF, M_NOWAIT);
+ name = kmalloc(strlen(buf) + 1, GFP_ATOMIC);
if (name == NULL)
return (ENOMEM);
strcpy(name, buf);
diff --git a/drivers/scsi/aic7xxx/aic79xx_core.c b/drivers/scsi/aic7xxx/aic79xx_core.c
index 78971db5b60..3233bf56443 100644
--- a/drivers/scsi/aic7xxx/aic79xx_core.c
+++ b/drivers/scsi/aic7xxx/aic79xx_core.c
@@ -289,7 +289,7 @@ ahd_set_modes(struct ahd_softc *ahd, ahd_mode src, ahd_mode dst)
|| ahd->dst_mode == AHD_MODE_UNKNOWN)
panic("Setting mode prior to saving it.\n");
if ((ahd_debug & AHD_SHOW_MODEPTR) != 0)
- printf("%s: Setting mode 0x%x\n", ahd_name(ahd),
+ printk("%s: Setting mode 0x%x\n", ahd_name(ahd),
ahd_build_mode_state(ahd, src, dst));
#endif
ahd_outb(ahd, MODE_PTR, ahd_build_mode_state(ahd, src, dst));
@@ -307,7 +307,7 @@ ahd_update_modes(struct ahd_softc *ahd)
mode_ptr = ahd_inb(ahd, MODE_PTR);
#ifdef AHD_DEBUG
if ((ahd_debug & AHD_SHOW_MODEPTR) != 0)
- printf("Reading mode 0x%x\n", mode_ptr);
+ printk("Reading mode 0x%x\n", mode_ptr);
#endif
ahd_extract_mode_state(ahd, mode_ptr, &src, &dst);
ahd_known_modes(ahd, src, dst);
@@ -877,7 +877,7 @@ ahd_queue_scb(struct ahd_softc *ahd, struct scb *scb)
uint64_t host_dataptr;
host_dataptr = ahd_le64toh(scb->hscb->dataptr);
- printf("%s: Queueing SCB %d:0x%x bus addr 0x%x - 0x%x%x/0x%x\n",
+ printk("%s: Queueing SCB %d:0x%x bus addr 0x%x - 0x%x%x/0x%x\n",
ahd_name(ahd),
SCB_GET_TAG(scb), scb->hscb->scsiid,
ahd_le32toh(scb->hscb->hscb_busaddr),
@@ -1174,7 +1174,7 @@ ahd_clear_fifo(struct ahd_softc *ahd, u_int fifo)
#ifdef AHD_DEBUG
if ((ahd_debug & AHD_SHOW_FIFOS) != 0)
- printf("%s: Clearing FIFO %d\n", ahd_name(ahd), fifo);
+ printk("%s: Clearing FIFO %d\n", ahd_name(ahd), fifo);
#endif
saved_modes = ahd_save_modes(ahd);
ahd_set_modes(ahd, fifo, fifo);
@@ -1215,7 +1215,7 @@ ahd_flush_qoutfifo(struct ahd_softc *ahd)
scbid = ahd_inw(ahd, GSFIFO);
scb = ahd_lookup_scb(ahd, scbid);
if (scb == NULL) {
- printf("%s: Warning - GSFIFO SCB %d invalid\n",
+ printk("%s: Warning - GSFIFO SCB %d invalid\n",
ahd_name(ahd), scbid);
continue;
}
@@ -1339,7 +1339,7 @@ rescan_fifos:
next_scbid = ahd_inw_scbram(ahd, SCB_NEXT_COMPLETE);
scb = ahd_lookup_scb(ahd, scbid);
if (scb == NULL) {
- printf("%s: Warning - DMA-up and complete "
+ printk("%s: Warning - DMA-up and complete "
"SCB %d invalid\n", ahd_name(ahd), scbid);
continue;
}
@@ -1360,7 +1360,7 @@ rescan_fifos:
next_scbid = ahd_inw_scbram(ahd, SCB_NEXT_COMPLETE);
scb = ahd_lookup_scb(ahd, scbid);
if (scb == NULL) {
- printf("%s: Warning - Complete Qfrz SCB %d invalid\n",
+ printk("%s: Warning - Complete Qfrz SCB %d invalid\n",
ahd_name(ahd), scbid);
continue;
}
@@ -1377,7 +1377,7 @@ rescan_fifos:
next_scbid = ahd_inw_scbram(ahd, SCB_NEXT_COMPLETE);
scb = ahd_lookup_scb(ahd, scbid);
if (scb == NULL) {
- printf("%s: Warning - Complete SCB %d invalid\n",
+ printk("%s: Warning - Complete SCB %d invalid\n",
ahd_name(ahd), scbid);
continue;
}
@@ -1682,7 +1682,7 @@ ahd_run_qoutfifo(struct ahd_softc *ahd)
scb_index = ahd_le16toh(completion->tag);
scb = ahd_lookup_scb(ahd, scb_index);
if (scb == NULL) {
- printf("%s: WARNING no command for scb %d "
+ printk("%s: WARNING no command for scb %d "
"(cmdcmplt)\nQOUTPOS = %d\n",
ahd_name(ahd), scb_index,
ahd->qoutfifonext);
@@ -1714,7 +1714,7 @@ ahd_handle_hwerrint(struct ahd_softc *ahd)
error = ahd_inb(ahd, ERROR);
for (i = 0; i < num_errors; i++) {
if ((error & ahd_hard_errors[i].errno) != 0)
- printf("%s: hwerrint, %s\n",
+ printk("%s: hwerrint, %s\n",
ahd_name(ahd), ahd_hard_errors[i].errmesg);
}
@@ -1747,7 +1747,7 @@ ahd_dump_sglist(struct scb *scb)
addr = ahd_le64toh(sg_list[i].addr);
len = ahd_le32toh(sg_list[i].len);
- printf("sg[%d] - Addr 0x%x%x : Length %d%s\n",
+ printk("sg[%d] - Addr 0x%x%x : Length %d%s\n",
i,
(uint32_t)((addr >> 32) & 0xFFFFFFFF),
(uint32_t)(addr & 0xFFFFFFFF),
@@ -1763,7 +1763,7 @@ ahd_dump_sglist(struct scb *scb)
uint32_t len;
len = ahd_le32toh(sg_list[i].len);
- printf("sg[%d] - Addr 0x%x%x : Length %d%s\n",
+ printk("sg[%d] - Addr 0x%x%x : Length %d%s\n",
i,
(len & AHD_SG_HIGH_ADDR_MASK) >> 24,
ahd_le32toh(sg_list[i].addr),
@@ -1802,7 +1802,7 @@ ahd_handle_seqint(struct ahd_softc *ahd, u_int intstat)
ahd_update_modes(ahd);
#ifdef AHD_DEBUG
if ((ahd_debug & AHD_SHOW_MISC) != 0)
- printf("%s: Handle Seqint Called for code %d\n",
+ printk("%s: Handle Seqint Called for code %d\n",
ahd_name(ahd), seqintcode);
#endif
switch (seqintcode) {
@@ -1836,18 +1836,18 @@ ahd_handle_seqint(struct ahd_softc *ahd, u_int intstat)
*/
#ifdef AHD_DEBUG
if ((ahd_debug & AHD_SHOW_RECOVERY) != 0)
- printf("%s: Assuming LQIPHASE_NLQ with "
+ printk("%s: Assuming LQIPHASE_NLQ with "
"P0 assertion\n", ahd_name(ahd));
#endif
}
#ifdef AHD_DEBUG
if ((ahd_debug & AHD_SHOW_RECOVERY) != 0)
- printf("%s: Entering NONPACK\n", ahd_name(ahd));
+ printk("%s: Entering NONPACK\n", ahd_name(ahd));
#endif
break;
}
case INVALID_SEQINT:
- printf("%s: Invalid Sequencer interrupt occurred, "
+ printk("%s: Invalid Sequencer interrupt occurred, "
"resetting channel.\n",
ahd_name(ahd));
#ifdef AHD_DEBUG
@@ -1866,8 +1866,8 @@ ahd_handle_seqint(struct ahd_softc *ahd, u_int intstat)
if (scb != NULL)
ahd_print_path(ahd, scb);
else
- printf("%s: ", ahd_name(ahd));
- printf("SCB %d Packetized Status Overrun", scbid);
+ printk("%s: ", ahd_name(ahd));
+ printk("SCB %d Packetized Status Overrun", scbid);
ahd_dump_card_state(ahd);
ahd_reset_channel(ahd, 'A', /*Initiate Reset*/TRUE);
break;
@@ -1881,7 +1881,7 @@ ahd_handle_seqint(struct ahd_softc *ahd, u_int intstat)
scb = ahd_lookup_scb(ahd, scbid);
if (scb == NULL) {
ahd_dump_card_state(ahd);
- printf("CFG4ISTAT: Free SCB %d referenced", scbid);
+ printk("CFG4ISTAT: Free SCB %d referenced", scbid);
panic("For safety");
}
ahd_outq(ahd, HADDR, scb->sense_busaddr);
@@ -1896,7 +1896,7 @@ ahd_handle_seqint(struct ahd_softc *ahd, u_int intstat)
u_int bus_phase;
bus_phase = ahd_inb(ahd, SCSISIGI) & PHASE_MASK;
- printf("%s: ILLEGAL_PHASE 0x%x\n",
+ printk("%s: ILLEGAL_PHASE 0x%x\n",
ahd_name(ahd), bus_phase);
switch (bus_phase) {
@@ -1908,7 +1908,7 @@ ahd_handle_seqint(struct ahd_softc *ahd, u_int intstat)
case P_STATUS:
case P_MESGIN:
ahd_reset_channel(ahd, 'A', /*Initiate Reset*/TRUE);
- printf("%s: Issued Bus Reset.\n", ahd_name(ahd));
+ printk("%s: Issued Bus Reset.\n", ahd_name(ahd));
break;
case P_COMMAND:
{
@@ -1933,7 +1933,7 @@ ahd_handle_seqint(struct ahd_softc *ahd, u_int intstat)
scbid = ahd_get_scbptr(ahd);
scb = ahd_lookup_scb(ahd, scbid);
if (scb == NULL) {
- printf("Invalid phase with no valid SCB. "
+ printk("Invalid phase with no valid SCB. "
"Resetting bus.\n");
ahd_reset_channel(ahd, 'A',
/*Initiate Reset*/TRUE);
@@ -1997,7 +1997,7 @@ ahd_handle_seqint(struct ahd_softc *ahd, u_int intstat)
#ifdef AHD_DEBUG
if ((ahd_debug & AHD_SHOW_RECOVERY) != 0) {
ahd_print_path(ahd, scb);
- printf("Unexpected command phase from "
+ printk("Unexpected command phase from "
"packetized target\n");
}
#endif
@@ -2013,7 +2013,7 @@ ahd_handle_seqint(struct ahd_softc *ahd, u_int intstat)
#ifdef AHD_DEBUG
if ((ahd_debug & AHD_SHOW_RECOVERY) != 0) {
- printf("%s: CFG4OVERRUN mode = %x\n", ahd_name(ahd),
+ printk("%s: CFG4OVERRUN mode = %x\n", ahd_name(ahd),
ahd_inb(ahd, MODE_PTR));
}
#endif
@@ -2049,7 +2049,7 @@ ahd_handle_seqint(struct ahd_softc *ahd, u_int intstat)
{
#ifdef AHD_DEBUG
if ((ahd_debug & AHD_SHOW_RECOVERY) != 0) {
- printf("%s: PDATA_REINIT - DFCNTRL = 0x%x "
+ printk("%s: PDATA_REINIT - DFCNTRL = 0x%x "
"SG_CACHE_SHADOW = 0x%x\n",
ahd_name(ahd), ahd_inb(ahd, DFCNTRL),
ahd_inb(ahd, SG_CACHE_SHADOW));
@@ -2082,7 +2082,7 @@ ahd_handle_seqint(struct ahd_softc *ahd, u_int intstat)
bus_phase = ahd_inb(ahd, SCSISIGI) & PHASE_MASK;
if (bus_phase != P_MESGIN
&& bus_phase != P_MESGOUT) {
- printf("ahd_intr: HOST_MSG_LOOP bad "
+ printk("ahd_intr: HOST_MSG_LOOP bad "
"phase 0x%x\n", bus_phase);
/*
* Probably transitioned to bus free before
@@ -2131,29 +2131,29 @@ ahd_handle_seqint(struct ahd_softc *ahd, u_int intstat)
AHD_ASSERT_MODES(ahd, AHD_MODE_SCSI_MSK, AHD_MODE_SCSI_MSK);
ahd_outb(ahd, SCSISEQ0, ahd_inb(ahd, SCSISEQ0) & ~ENSELO);
- printf("%s:%c:%d: no active SCB for reconnecting "
+ printk("%s:%c:%d: no active SCB for reconnecting "
"target - issuing BUS DEVICE RESET\n",
ahd_name(ahd), 'A', ahd_inb(ahd, SELID) >> 4);
- printf("SAVED_SCSIID == 0x%x, SAVED_LUN == 0x%x, "
+ printk("SAVED_SCSIID == 0x%x, SAVED_LUN == 0x%x, "
"REG0 == 0x%x ACCUM = 0x%x\n",
ahd_inb(ahd, SAVED_SCSIID), ahd_inb(ahd, SAVED_LUN),
ahd_inw(ahd, REG0), ahd_inb(ahd, ACCUM));
- printf("SEQ_FLAGS == 0x%x, SCBPTR == 0x%x, BTT == 0x%x, "
+ printk("SEQ_FLAGS == 0x%x, SCBPTR == 0x%x, BTT == 0x%x, "
"SINDEX == 0x%x\n",
ahd_inb(ahd, SEQ_FLAGS), ahd_get_scbptr(ahd),
ahd_find_busy_tcl(ahd,
BUILD_TCL(ahd_inb(ahd, SAVED_SCSIID),
ahd_inb(ahd, SAVED_LUN))),
ahd_inw(ahd, SINDEX));
- printf("SELID == 0x%x, SCB_SCSIID == 0x%x, SCB_LUN == 0x%x, "
+ printk("SELID == 0x%x, SCB_SCSIID == 0x%x, SCB_LUN == 0x%x, "
"SCB_CONTROL == 0x%x\n",
ahd_inb(ahd, SELID), ahd_inb_scbram(ahd, SCB_SCSIID),
ahd_inb_scbram(ahd, SCB_LUN),
ahd_inb_scbram(ahd, SCB_CONTROL));
- printf("SCSIBUS[0] == 0x%x, SCSISIGI == 0x%x\n",
+ printk("SCSIBUS[0] == 0x%x, SCSISIGI == 0x%x\n",
ahd_inb(ahd, SCSIBUS), ahd_inb(ahd, SCSISIGI));
- printf("SXFRCTL0 == 0x%x\n", ahd_inb(ahd, SXFRCTL0));
- printf("SEQCTL0 == 0x%x\n", ahd_inb(ahd, SEQCTL0));
+ printk("SXFRCTL0 == 0x%x\n", ahd_inb(ahd, SXFRCTL0));
+ printk("SEQCTL0 == 0x%x\n", ahd_inb(ahd, SEQCTL0));
ahd_dump_card_state(ahd);
ahd->msgout_buf[0] = MSG_BUS_DEV_RESET;
ahd->msgout_len = 1;
@@ -2181,7 +2181,7 @@ ahd_handle_seqint(struct ahd_softc *ahd, u_int intstat)
u_int lastphase;
lastphase = ahd_inb(ahd, LASTPHASE);
- printf("%s:%c:%d: unknown scsi bus phase %x, "
+ printk("%s:%c:%d: unknown scsi bus phase %x, "
"lastphase = 0x%x. Attempting to continue\n",
ahd_name(ahd), 'A',
SCSIID_TARGET(ahd, ahd_inb(ahd, SAVED_SCSIID)),
@@ -2193,7 +2193,7 @@ ahd_handle_seqint(struct ahd_softc *ahd, u_int intstat)
u_int lastphase;
lastphase = ahd_inb(ahd, LASTPHASE);
- printf("%s:%c:%d: Missed busfree. "
+ printk("%s:%c:%d: Missed busfree. "
"Lastphase = 0x%x, Curphase = 0x%x\n",
ahd_name(ahd), 'A',
SCSIID_TARGET(ahd, ahd_inb(ahd, SAVED_SCSIID)),
@@ -2223,11 +2223,11 @@ ahd_handle_seqint(struct ahd_softc *ahd, u_int intstat)
lastphase = ahd_inb(ahd, LASTPHASE);
if ((ahd_debug & AHD_SHOW_RECOVERY) != 0) {
ahd_print_path(ahd, scb);
- printf("data overrun detected %s. Tag == 0x%x.\n",
+ printk("data overrun detected %s. Tag == 0x%x.\n",
ahd_lookup_phase_entry(lastphase)->phasemsg,
SCB_GET_TAG(scb));
ahd_print_path(ahd, scb);
- printf("%s seen Data Phase. Length = %ld. "
+ printk("%s seen Data Phase. Length = %ld. "
"NumSGs = %d.\n",
ahd_inb(ahd, SEQ_FLAGS) & DPHASE
? "Have" : "Haven't",
@@ -2252,7 +2252,7 @@ ahd_handle_seqint(struct ahd_softc *ahd, u_int intstat)
u_int scbid;
ahd_fetch_devinfo(ahd, &devinfo);
- printf("%s:%c:%d:%d: Attempt to issue message failed\n",
+ printk("%s:%c:%d:%d: Attempt to issue message failed\n",
ahd_name(ahd), devinfo.channel, devinfo.target,
devinfo.lun);
scbid = ahd_get_scbptr(ahd);
@@ -2285,7 +2285,7 @@ ahd_handle_seqint(struct ahd_softc *ahd, u_int intstat)
cam_status error;
ahd_print_path(ahd, scb);
- printf("Task Management Func 0x%x Complete\n",
+ printk("Task Management Func 0x%x Complete\n",
scb->hscb->task_management);
lun = CAM_LUN_WILDCARD;
tag = SCB_LIST_NULL;
@@ -2341,7 +2341,7 @@ ahd_handle_seqint(struct ahd_softc *ahd, u_int intstat)
* the QINFIFO if it is still there.
*/
ahd_print_path(ahd, scb);
- printf("SCB completes before TMF\n");
+ printk("SCB completes before TMF\n");
/*
* Handle losing the race. Wait until any
* current selection completes. We will then
@@ -2366,7 +2366,7 @@ ahd_handle_seqint(struct ahd_softc *ahd, u_int intstat)
case TRACEPOINT1:
case TRACEPOINT2:
case TRACEPOINT3:
- printf("%s: Tracepoint %d\n", ahd_name(ahd),
+ printk("%s: Tracepoint %d\n", ahd_name(ahd),
seqintcode - TRACEPOINT0);
break;
case NO_SEQINT:
@@ -2375,7 +2375,7 @@ ahd_handle_seqint(struct ahd_softc *ahd, u_int intstat)
ahd_handle_hwerrint(ahd);
break;
default:
- printf("%s: Unexpected SEQINTCODE %d\n", ahd_name(ahd),
+ printk("%s: Unexpected SEQINTCODE %d\n", ahd_name(ahd),
seqintcode);
break;
}
@@ -2440,7 +2440,7 @@ ahd_handle_scsiint(struct ahd_softc *ahd, u_int intstat)
u_int now_lvd;
now_lvd = ahd_inb(ahd, SBLKCTL) & ENAB40;
- printf("%s: Transceiver State Has Changed to %s mode\n",
+ printk("%s: Transceiver State Has Changed to %s mode\n",
ahd_name(ahd), now_lvd ? "LVD" : "SE");
ahd_outb(ahd, CLRSINT0, CLRIOERR);
/*
@@ -2452,12 +2452,12 @@ ahd_handle_scsiint(struct ahd_softc *ahd, u_int intstat)
ahd_unpause(ahd);
} else if ((status0 & OVERRUN) != 0) {
- printf("%s: SCSI offset overrun detected. Resetting bus.\n",
+ printk("%s: SCSI offset overrun detected. Resetting bus.\n",
ahd_name(ahd));
ahd_reset_channel(ahd, 'A', /*Initiate Reset*/TRUE);
} else if ((status & SCSIRSTI) != 0) {
- printf("%s: Someone reset channel A\n", ahd_name(ahd));
+ printk("%s: Someone reset channel A\n", ahd_name(ahd));
ahd_reset_channel(ahd, 'A', /*Initiate Reset*/FALSE);
} else if ((status & SCSIPERR) != 0) {
@@ -2467,7 +2467,7 @@ ahd_handle_scsiint(struct ahd_softc *ahd, u_int intstat)
ahd_handle_transmission_error(ahd);
} else if (lqostat0 != 0) {
- printf("%s: lqostat0 == 0x%x!\n", ahd_name(ahd), lqostat0);
+ printk("%s: lqostat0 == 0x%x!\n", ahd_name(ahd), lqostat0);
ahd_outb(ahd, CLRLQOINT0, lqostat0);
if ((ahd->bugs & AHD_CLRLQO_AUTOCLR_BUG) != 0)
ahd_outb(ahd, CLRLQOINT1, 0);
@@ -2497,7 +2497,7 @@ ahd_handle_scsiint(struct ahd_softc *ahd, u_int intstat)
scbid = ahd_inw(ahd, WAITING_TID_HEAD);
scb = ahd_lookup_scb(ahd, scbid);
if (scb == NULL) {
- printf("%s: ahd_intr - referenced scb not "
+ printk("%s: ahd_intr - referenced scb not "
"valid during SELTO scb(0x%x)\n",
ahd_name(ahd), scbid);
ahd_dump_card_state(ahd);
@@ -2506,7 +2506,7 @@ ahd_handle_scsiint(struct ahd_softc *ahd, u_int intstat)
#ifdef AHD_DEBUG
if ((ahd_debug & AHD_SHOW_SELTO) != 0) {
ahd_print_path(ahd, scb);
- printf("Saw Selection Timeout for SCB 0x%x\n",
+ printk("Saw Selection Timeout for SCB 0x%x\n",
scbid);
}
#endif
@@ -2534,7 +2534,7 @@ ahd_handle_scsiint(struct ahd_softc *ahd, u_int intstat)
ahd_iocell_first_selection(ahd);
ahd_unpause(ahd);
} else if (status3 != 0) {
- printf("%s: SCSI Cell parity error SSTAT3 == 0x%x\n",
+ printk("%s: SCSI Cell parity error SSTAT3 == 0x%x\n",
ahd_name(ahd), status3);
ahd_outb(ahd, CLRSINT3, status3);
} else if ((lqistat1 & (LQIPHASE_LQ|LQIPHASE_NLQ)) != 0) {
@@ -2587,7 +2587,7 @@ ahd_handle_scsiint(struct ahd_softc *ahd, u_int intstat)
scbid = ahd_get_scbptr(ahd);
scb = ahd_lookup_scb(ahd, scbid);
if (scb == NULL) {
- printf("%s: Invalid SCB %d in DFF%d "
+ printk("%s: Invalid SCB %d in DFF%d "
"during unexpected busfree\n",
ahd_name(ahd), scbid, mode);
packetized = 0;
@@ -2620,7 +2620,7 @@ ahd_handle_scsiint(struct ahd_softc *ahd, u_int intstat)
#ifdef AHD_DEBUG
if ((ahd_debug & AHD_SHOW_MISC) != 0)
- printf("Saw Busfree. Busfreetime = 0x%x.\n",
+ printk("Saw Busfree. Busfreetime = 0x%x.\n",
busfreetime);
#endif
/*
@@ -2661,7 +2661,7 @@ ahd_handle_scsiint(struct ahd_softc *ahd, u_int intstat)
ahd_unpause(ahd);
}
} else {
- printf("%s: Missing case in ahd_handle_scsiint. status = %x\n",
+ printk("%s: Missing case in ahd_handle_scsiint. status = %x\n",
ahd_name(ahd), status);
ahd_dump_card_state(ahd);
ahd_clear_intstat(ahd);
@@ -2697,7 +2697,7 @@ ahd_handle_transmission_error(struct ahd_softc *ahd)
|| (lqistate == 0x29)) {
#ifdef AHD_DEBUG
if ((ahd_debug & AHD_SHOW_RECOVERY) != 0) {
- printf("%s: NLQCRC found via LQISTATE\n",
+ printk("%s: NLQCRC found via LQISTATE\n",
ahd_name(ahd));
}
#endif
@@ -2729,18 +2729,18 @@ ahd_handle_transmission_error(struct ahd_softc *ahd)
cur_col = 0;
if (silent == FALSE) {
- printf("%s: Transmission error detected\n", ahd_name(ahd));
+ printk("%s: Transmission error detected\n", ahd_name(ahd));
ahd_lqistat1_print(lqistat1, &cur_col, 50);
ahd_lastphase_print(lastphase, &cur_col, 50);
ahd_scsisigi_print(curphase, &cur_col, 50);
ahd_perrdiag_print(perrdiag, &cur_col, 50);
- printf("\n");
+ printk("\n");
ahd_dump_card_state(ahd);
}
if ((lqistat1 & (LQIOVERI_LQ|LQIOVERI_NLQ)) != 0) {
if (silent == FALSE) {
- printf("%s: Gross protocol error during incoming "
+ printk("%s: Gross protocol error during incoming "
"packet. lqistat1 == 0x%x. Resetting bus.\n",
ahd_name(ahd), lqistat1);
}
@@ -2769,7 +2769,7 @@ ahd_handle_transmission_error(struct ahd_softc *ahd)
* (SPI4R09 10.7.3.3.3)
*/
ahd_outb(ahd, LQCTL2, LQIRETRY);
- printf("LQIRetry for LQICRCI_LQ to release ACK\n");
+ printk("LQIRetry for LQICRCI_LQ to release ACK\n");
} else if ((lqistat1 & LQICRCI_NLQ) != 0) {
/*
* We detected a CRC error in a NON-LQ packet.
@@ -2817,22 +2817,22 @@ ahd_handle_transmission_error(struct ahd_softc *ahd)
* Busfree detection is enabled.
*/
if (silent == FALSE)
- printf("LQICRC_NLQ\n");
+ printk("LQICRC_NLQ\n");
if (scb == NULL) {
- printf("%s: No SCB valid for LQICRC_NLQ. "
+ printk("%s: No SCB valid for LQICRC_NLQ. "
"Resetting bus\n", ahd_name(ahd));
ahd_reset_channel(ahd, 'A', /*Initiate Reset*/TRUE);
return;
}
} else if ((lqistat1 & LQIBADLQI) != 0) {
- printf("Need to handle BADLQI!\n");
+ printk("Need to handle BADLQI!\n");
ahd_reset_channel(ahd, 'A', /*Initiate Reset*/TRUE);
return;
} else if ((perrdiag & (PARITYERR|PREVPHASE)) == PARITYERR) {
if ((curphase & ~P_DATAIN_DT) != 0) {
/* Ack the byte. So we can continue. */
if (silent == FALSE)
- printf("Acking %s to clear perror\n",
+ printk("Acking %s to clear perror\n",
ahd_lookup_phase_entry(curphase)->phasemsg);
ahd_inb(ahd, SCSIDAT);
}
@@ -2877,10 +2877,10 @@ ahd_handle_lqiphase_error(struct ahd_softc *ahd, u_int lqistat1)
if ((ahd_inb(ahd, SCSISIGO) & ATNO) != 0
&& (ahd_inb(ahd, MDFFSTAT) & DLZERO) != 0) {
if ((lqistat1 & LQIPHASE_LQ) != 0) {
- printf("LQIRETRY for LQIPHASE_LQ\n");
+ printk("LQIRETRY for LQIPHASE_LQ\n");
ahd_outb(ahd, LQCTL2, LQIRETRY);
} else if ((lqistat1 & LQIPHASE_NLQ) != 0) {
- printf("LQIRETRY for LQIPHASE_NLQ\n");
+ printk("LQIRETRY for LQIPHASE_NLQ\n");
ahd_outb(ahd, LQCTL2, LQIRETRY);
} else
panic("ahd_handle_lqiphase_error: No phase errors\n");
@@ -2888,7 +2888,7 @@ ahd_handle_lqiphase_error(struct ahd_softc *ahd, u_int lqistat1)
ahd_outb(ahd, CLRINT, CLRSCSIINT);
ahd_unpause(ahd);
} else {
- printf("Reseting Channel for LQI Phase error\n");
+ printk("Reseting Channel for LQI Phase error\n");
ahd_dump_card_state(ahd);
ahd_reset_channel(ahd, 'A', /*Initiate Reset*/TRUE);
}
@@ -2976,7 +2976,7 @@ ahd_handle_pkt_busfree(struct ahd_softc *ahd, u_int busfreetime)
if (scb->crc_retry_count < AHD_MAX_LQ_CRC_ERRORS) {
if (SCB_IS_SILENT(scb) == FALSE) {
ahd_print_path(ahd, scb);
- printf("Probable outgoing LQ CRC error. "
+ printk("Probable outgoing LQ CRC error. "
"Retrying command\n");
}
scb->crc_retry_count++;
@@ -2998,7 +2998,7 @@ ahd_handle_pkt_busfree(struct ahd_softc *ahd, u_int busfreetime)
ahd_outb(ahd, CLRSINT1, CLRSCSIPERR|CLRBUSFREE);
#ifdef AHD_DEBUG
if ((ahd_debug & AHD_SHOW_MASKED_ERRORS) != 0)
- printf("%s: Parity on last REQ detected "
+ printk("%s: Parity on last REQ detected "
"during busfree phase.\n",
ahd_name(ahd));
#endif
@@ -3012,7 +3012,7 @@ ahd_handle_pkt_busfree(struct ahd_softc *ahd, u_int busfreetime)
scbid = ahd_get_scbptr(ahd);
scb = ahd_lookup_scb(ahd, scbid);
ahd_print_path(ahd, scb);
- printf("Unexpected PKT busfree condition\n");
+ printk("Unexpected PKT busfree condition\n");
ahd_dump_card_state(ahd);
ahd_abort_scbs(ahd, SCB_GET_TARGET(ahd, scb), 'A',
SCB_GET_LUN(scb), SCB_GET_TAG(scb),
@@ -3021,7 +3021,7 @@ ahd_handle_pkt_busfree(struct ahd_softc *ahd, u_int busfreetime)
/* Return restarting the sequencer. */
return (1);
}
- printf("%s: Unexpected PKT busfree condition\n", ahd_name(ahd));
+ printk("%s: Unexpected PKT busfree condition\n", ahd_name(ahd));
ahd_dump_card_state(ahd);
/* Restart the sequencer. */
return (1);
@@ -3076,14 +3076,14 @@ ahd_handle_nonpkt_busfree(struct ahd_softc *ahd)
if (scb == NULL) {
ahd_print_devinfo(ahd, &devinfo);
- printf("Abort for unidentified "
+ printk("Abort for unidentified "
"connection completed.\n");
/* restart the sequencer. */
return (1);
}
sent_msg = ahd->msgout_buf[ahd->msgout_index - 1];
ahd_print_path(ahd, scb);
- printf("SCB %d - Abort%s Completed.\n",
+ printk("SCB %d - Abort%s Completed.\n",
SCB_GET_TAG(scb),
sent_msg == MSG_ABORT_TAG ? "" : " Tag");
@@ -3109,7 +3109,7 @@ ahd_handle_nonpkt_busfree(struct ahd_softc *ahd)
found = ahd_abort_scbs(ahd, target, 'A', saved_lun,
tag, ROLE_INITIATOR,
CAM_REQ_ABORTED);
- printf("found == 0x%x\n", found);
+ printk("found == 0x%x\n", found);
printerror = 0;
} else if (ahd_sent_msg(ahd, AHDMSG_1B,
MSG_BUS_DEV_RESET, TRUE)) {
@@ -3147,7 +3147,7 @@ ahd_handle_nonpkt_busfree(struct ahd_softc *ahd)
*/
#ifdef AHD_DEBUG
if ((ahd_debug & AHD_SHOW_MESSAGES) != 0)
- printf("PPR negotiation rejected busfree.\n");
+ printk("PPR negotiation rejected busfree.\n");
#endif
tinfo = ahd_fetch_transinfo(ahd, devinfo.channel,
devinfo.our_scsiid,
@@ -3191,7 +3191,7 @@ ahd_handle_nonpkt_busfree(struct ahd_softc *ahd)
*/
#ifdef AHD_DEBUG
if ((ahd_debug & AHD_SHOW_MESSAGES) != 0)
- printf("WDTR negotiation rejected busfree.\n");
+ printk("WDTR negotiation rejected busfree.\n");
#endif
ahd_set_width(ahd, &devinfo,
MSG_EXT_WDTR_BUS_8_BIT,
@@ -3216,7 +3216,7 @@ ahd_handle_nonpkt_busfree(struct ahd_softc *ahd)
*/
#ifdef AHD_DEBUG
if ((ahd_debug & AHD_SHOW_MESSAGES) != 0)
- printf("SDTR negotiation rejected busfree.\n");
+ printk("SDTR negotiation rejected busfree.\n");
#endif
ahd_set_syncrate(ahd, &devinfo,
/*period*/0, /*offset*/0,
@@ -3240,7 +3240,7 @@ ahd_handle_nonpkt_busfree(struct ahd_softc *ahd)
#ifdef AHD_DEBUG
if ((ahd_debug & AHD_SHOW_MESSAGES) != 0)
- printf("Expected IDE Busfree\n");
+ printk("Expected IDE Busfree\n");
#endif
printerror = 0;
} else if ((ahd->msg_flags & MSG_FLAG_EXPECT_QASREJ_BUSFREE)
@@ -3249,7 +3249,7 @@ ahd_handle_nonpkt_busfree(struct ahd_softc *ahd)
#ifdef AHD_DEBUG
if ((ahd_debug & AHD_SHOW_MESSAGES) != 0)
- printf("Expected QAS Reject Busfree\n");
+ printk("Expected QAS Reject Busfree\n");
#endif
printerror = 0;
}
@@ -3275,7 +3275,7 @@ ahd_handle_nonpkt_busfree(struct ahd_softc *ahd)
} else {
#ifdef AHD_DEBUG
if ((ahd_debug & AHD_SHOW_MESSAGES) != 0)
- printf("PPR Negotiation Busfree.\n");
+ printk("PPR Negotiation Busfree.\n");
#endif
ahd_done(ahd, scb);
}
@@ -3302,9 +3302,9 @@ ahd_handle_nonpkt_busfree(struct ahd_softc *ahd)
* We had not fully identified this connection,
* so we cannot abort anything.
*/
- printf("%s: ", ahd_name(ahd));
+ printk("%s: ", ahd_name(ahd));
}
- printf("Unexpected busfree %s, %d SCBs aborted, "
+ printk("Unexpected busfree %s, %d SCBs aborted, "
"PRGMCNT == 0x%x\n",
ahd_lookup_phase_entry(lastphase)->phasemsg,
aborted,
@@ -3342,7 +3342,7 @@ ahd_handle_proto_violation(struct ahd_softc *ahd)
* to match.
*/
ahd_print_devinfo(ahd, &devinfo);
- printf("Target did not send an IDENTIFY message. "
+ printk("Target did not send an IDENTIFY message. "
"LASTPHASE = 0x%x.\n", lastphase);
scb = NULL;
} else if (scb == NULL) {
@@ -3351,13 +3351,13 @@ ahd_handle_proto_violation(struct ahd_softc *ahd)
* transaction. Print an error and reset the bus.
*/
ahd_print_devinfo(ahd, &devinfo);
- printf("No SCB found during protocol violation\n");
+ printk("No SCB found during protocol violation\n");
goto proto_violation_reset;
} else {
ahd_set_transaction_status(scb, CAM_SEQUENCE_FAIL);
if ((seq_flags & NO_CDB_SENT) != 0) {
ahd_print_path(ahd, scb);
- printf("No or incomplete CDB sent to device.\n");
+ printk("No or incomplete CDB sent to device.\n");
} else if ((ahd_inb_scbram(ahd, SCB_CONTROL)
& STATUS_RCVD) == 0) {
/*
@@ -3368,10 +3368,10 @@ ahd_handle_proto_violation(struct ahd_softc *ahd)
* message.
*/
ahd_print_path(ahd, scb);
- printf("Completed command without status.\n");
+ printk("Completed command without status.\n");
} else {
ahd_print_path(ahd, scb);
- printf("Unknown protocol violation.\n");
+ printk("Unknown protocol violation.\n");
ahd_dump_card_state(ahd);
}
}
@@ -3385,7 +3385,7 @@ proto_violation_reset:
* it away with a bus reset.
*/
found = ahd_reset_channel(ahd, 'A', TRUE);
- printf("%s: Issued Channel %c Bus Reset. "
+ printk("%s: Issued Channel %c Bus Reset. "
"%d SCBs aborted\n", ahd_name(ahd), 'A', found);
} else {
/*
@@ -3407,7 +3407,7 @@ proto_violation_reset:
ahd_print_path(ahd, scb);
scb->flags |= SCB_ABORT;
}
- printf("Protocol violation %s. Attempting to abort.\n",
+ printk("Protocol violation %s. Attempting to abort.\n",
ahd_lookup_phase_entry(curphase)->phasemsg);
}
}
@@ -3425,7 +3425,7 @@ ahd_force_renegotiation(struct ahd_softc *ahd, struct ahd_devinfo *devinfo)
#ifdef AHD_DEBUG
if ((ahd_debug & AHD_SHOW_MESSAGES) != 0) {
ahd_print_devinfo(ahd, devinfo);
- printf("Forcing renegotiation\n");
+ printk("Forcing renegotiation\n");
}
#endif
targ_info = ahd_fetch_transinfo(ahd,
@@ -3486,7 +3486,7 @@ ahd_clear_critical_section(struct ahd_softc *ahd)
break;
if (steps > AHD_MAX_STEPS) {
- printf("%s: Infinite loop in critical section\n"
+ printk("%s: Infinite loop in critical section\n"
"%s: First Instruction 0x%x now 0x%x\n",
ahd_name(ahd), ahd_name(ahd), first_instr,
seqaddr);
@@ -3497,7 +3497,7 @@ ahd_clear_critical_section(struct ahd_softc *ahd)
steps++;
#ifdef AHD_DEBUG
if ((ahd_debug & AHD_SHOW_MISC) != 0)
- printf("%s: Single stepping at 0x%x\n", ahd_name(ahd),
+ printk("%s: Single stepping at 0x%x\n", ahd_name(ahd),
seqaddr);
#endif
if (stepping == FALSE) {
@@ -3601,16 +3601,16 @@ ahd_print_scb(struct scb *scb)
int i;
hscb = scb->hscb;
- printf("scb:%p control:0x%x scsiid:0x%x lun:%d cdb_len:%d\n",
+ printk("scb:%p control:0x%x scsiid:0x%x lun:%d cdb_len:%d\n",
(void *)scb,
hscb->control,
hscb->scsiid,
hscb->lun,
hscb->cdb_len);
- printf("Shared Data: ");
+ printk("Shared Data: ");
for (i = 0; i < sizeof(hscb->shared_data.idata.cdb); i++)
- printf("%#02x", hscb->shared_data.idata.cdb[i]);
- printf(" dataptr:%#x%x datacnt:%#x sgptr:%#x tag:%#x\n",
+ printk("%#02x", hscb->shared_data.idata.cdb[i]);
+ printk(" dataptr:%#x%x datacnt:%#x sgptr:%#x tag:%#x\n",
(uint32_t)((ahd_le64toh(hscb->dataptr) >> 32) & 0xFFFFFFFF),
(uint32_t)(ahd_le64toh(hscb->dataptr) & 0xFFFFFFFF),
ahd_le32toh(hscb->datacnt),
@@ -3637,7 +3637,7 @@ ahd_alloc_tstate(struct ahd_softc *ahd, u_int scsi_id, char channel)
&& ahd->enabled_targets[scsi_id] != master_tstate)
panic("%s: ahd_alloc_tstate - Target already allocated",
ahd_name(ahd));
- tstate = malloc(sizeof(*tstate), M_DEVBUF, M_NOWAIT);
+ tstate = kmalloc(sizeof(*tstate), GFP_ATOMIC);
if (tstate == NULL)
return (NULL);
@@ -3682,7 +3682,7 @@ ahd_free_tstate(struct ahd_softc *ahd, u_int scsi_id, char channel, int force)
tstate = ahd->enabled_targets[scsi_id];
if (tstate != NULL)
- free(tstate, M_DEVBUF);
+ kfree(tstate);
ahd->enabled_targets[scsi_id] = NULL;
}
#endif
@@ -3942,37 +3942,37 @@ ahd_set_syncrate(struct ahd_softc *ahd, struct ahd_devinfo *devinfo,
if (offset != 0) {
int options;
- printf("%s: target %d synchronous with "
+ printk("%s: target %d synchronous with "
"period = 0x%x, offset = 0x%x",
ahd_name(ahd), devinfo->target,
period, offset);
options = 0;
if ((ppr_options & MSG_EXT_PPR_RD_STRM) != 0) {
- printf("(RDSTRM");
+ printk("(RDSTRM");
options++;
}
if ((ppr_options & MSG_EXT_PPR_DT_REQ) != 0) {
- printf("%s", options ? "|DT" : "(DT");
+ printk("%s", options ? "|DT" : "(DT");
options++;
}
if ((ppr_options & MSG_EXT_PPR_IU_REQ) != 0) {
- printf("%s", options ? "|IU" : "(IU");
+ printk("%s", options ? "|IU" : "(IU");
options++;
}
if ((ppr_options & MSG_EXT_PPR_RTI) != 0) {
- printf("%s", options ? "|RTI" : "(RTI");
+ printk("%s", options ? "|RTI" : "(RTI");
options++;
}
if ((ppr_options & MSG_EXT_PPR_QAS_REQ) != 0) {
- printf("%s", options ? "|QAS" : "(QAS");
+ printk("%s", options ? "|QAS" : "(QAS");
options++;
}
if (options != 0)
- printf(")\n");
+ printk(")\n");
else
- printf("\n");
+ printk("\n");
} else {
- printf("%s: target %d using "
+ printk("%s: target %d using "
"asynchronous transfers%s\n",
ahd_name(ahd), devinfo->target,
(ppr_options & MSG_EXT_PPR_QAS_REQ) != 0
@@ -4000,7 +4000,7 @@ ahd_set_syncrate(struct ahd_softc *ahd, struct ahd_devinfo *devinfo,
#ifdef AHD_DEBUG
if ((ahd_debug & AHD_SHOW_MESSAGES) != 0) {
ahd_print_devinfo(ahd, devinfo);
- printf("Expecting IU Change busfree\n");
+ printk("Expecting IU Change busfree\n");
}
#endif
ahd->msg_flags |= MSG_FLAG_EXPECT_PPR_BUSFREE
@@ -4009,7 +4009,7 @@ ahd_set_syncrate(struct ahd_softc *ahd, struct ahd_devinfo *devinfo,
if ((old_ppr & MSG_EXT_PPR_IU_REQ) != 0) {
#ifdef AHD_DEBUG
if ((ahd_debug & AHD_SHOW_MESSAGES) != 0)
- printf("PPR with IU_REQ outstanding\n");
+ printk("PPR with IU_REQ outstanding\n");
#endif
ahd->msg_flags |= MSG_FLAG_EXPECT_PPR_BUSFREE;
}
@@ -4061,7 +4061,7 @@ ahd_set_width(struct ahd_softc *ahd, struct ahd_devinfo *devinfo,
ahd_send_async(ahd, devinfo->channel, devinfo->target,
CAM_LUN_WILDCARD, AC_TRANSFER_NEG);
if (bootverbose) {
- printf("%s: target %d using %dbit transfers\n",
+ printk("%s: target %d using %dbit transfers\n",
ahd_name(ahd), devinfo->target,
8 * (0x01 << width));
}
@@ -4337,7 +4337,7 @@ ahd_fetch_devinfo(struct ahd_softc *ahd, struct ahd_devinfo *devinfo)
void
ahd_print_devinfo(struct ahd_softc *ahd, struct ahd_devinfo *devinfo)
{
- printf("%s:%c:%d:%d: ", ahd_name(ahd), 'A',
+ printk("%s:%c:%d:%d: ", ahd_name(ahd), 'A',
devinfo->target, devinfo->lun);
}
@@ -4419,11 +4419,11 @@ ahd_setup_initiator_msgout(struct ahd_softc *ahd, struct ahd_devinfo *devinfo,
ahd->msg_type = MSG_TYPE_INITIATOR_MSGOUT;
#ifdef AHD_DEBUG
if ((ahd_debug & AHD_SHOW_MESSAGES) != 0)
- printf("Setting up for Parity Error delivery\n");
+ printk("Setting up for Parity Error delivery\n");
#endif
return;
} else if (scb == NULL) {
- printf("%s: WARNING. No pending message for "
+ printk("%s: WARNING. No pending message for "
"I_T msgin. Issuing NO-OP\n", ahd_name(ahd));
ahd->msgout_buf[ahd->msgout_index++] = MSG_NOOP;
ahd->msgout_len++;
@@ -4454,7 +4454,7 @@ ahd_setup_initiator_msgout(struct ahd_softc *ahd, struct ahd_devinfo *devinfo,
ahd->msgout_buf[ahd->msgout_index++] = MSG_BUS_DEV_RESET;
ahd->msgout_len++;
ahd_print_path(ahd, scb);
- printf("Bus Device Reset Message Sent\n");
+ printk("Bus Device Reset Message Sent\n");
/*
* Clear our selection hardware in advance of
* the busfree. We may have an entry in the waiting
@@ -4472,7 +4472,7 @@ ahd_setup_initiator_msgout(struct ahd_softc *ahd, struct ahd_devinfo *devinfo,
}
ahd->msgout_len++;
ahd_print_path(ahd, scb);
- printf("Abort%s Message Sent\n",
+ printk("Abort%s Message Sent\n",
(scb->hscb->control & TAG_ENB) != 0 ? " Tag" : "");
/*
* Clear our selection hardware in advance of
@@ -4493,9 +4493,9 @@ ahd_setup_initiator_msgout(struct ahd_softc *ahd, struct ahd_devinfo *devinfo,
*/
ahd_outb(ahd, SCSISEQ0, 0);
} else {
- printf("ahd_intr: AWAITING_MSG for an SCB that "
+ printk("ahd_intr: AWAITING_MSG for an SCB that "
"does not have a waiting message\n");
- printf("SCSIID = %x, target_mask = %x\n", scb->hscb->scsiid,
+ printk("SCSIID = %x, target_mask = %x\n", scb->hscb->scsiid,
devinfo->target_mask);
panic("SCB = %d, SCB Control = %x:%x, MSG_OUT = %x "
"SCB flags = %x", SCB_GET_TAG(scb), scb->hscb->control,
@@ -4577,7 +4577,7 @@ ahd_build_transfer_msg(struct ahd_softc *ahd, struct ahd_devinfo *devinfo)
if (bootverbose) {
ahd_print_devinfo(ahd, devinfo);
- printf("Ensuring async\n");
+ printk("Ensuring async\n");
}
}
/* Target initiated PPR is not allowed in the SCSI spec */
@@ -4624,7 +4624,7 @@ ahd_construct_sdtr(struct ahd_softc *ahd, struct ahd_devinfo *devinfo,
ahd->msgout_buf + ahd->msgout_index, period, offset);
ahd->msgout_len += 5;
if (bootverbose) {
- printf("(%s:%c:%d:%d): Sending SDTR period %x, offset %x\n",
+ printk("(%s:%c:%d:%d): Sending SDTR period %x, offset %x\n",
ahd_name(ahd), devinfo->channel, devinfo->target,
devinfo->lun, period, offset);
}
@@ -4642,7 +4642,7 @@ ahd_construct_wdtr(struct ahd_softc *ahd, struct ahd_devinfo *devinfo,
ahd->msgout_buf + ahd->msgout_index, bus_width);
ahd->msgout_len += 4;
if (bootverbose) {
- printf("(%s:%c:%d:%d): Sending WDTR %x\n",
+ printk("(%s:%c:%d:%d): Sending WDTR %x\n",
ahd_name(ahd), devinfo->channel, devinfo->target,
devinfo->lun, bus_width);
}
@@ -4671,7 +4671,7 @@ ahd_construct_ppr(struct ahd_softc *ahd, struct ahd_devinfo *devinfo,
bus_width, ppr_options);
ahd->msgout_len += 8;
if (bootverbose) {
- printf("(%s:%c:%d:%d): Sending PPR bus_width %x, period %x, "
+ printk("(%s:%c:%d:%d): Sending PPR bus_width %x, period %x, "
"offset %x, ppr_options %x\n", ahd_name(ahd),
devinfo->channel, devinfo->target, devinfo->lun,
bus_width, period, offset, ppr_options);
@@ -4721,7 +4721,7 @@ ahd_handle_message_phase(struct ahd_softc *ahd)
bus_phase = ahd_inb(ahd, LASTPHASE);
if ((ahd_inb(ahd, LQISTAT2) & LQIPHASE_OUTPKT) != 0) {
- printf("LQIRETRY for LQIPHASE_OUTPKT\n");
+ printk("LQIRETRY for LQIPHASE_OUTPKT\n");
ahd_outb(ahd, LQCTL2, LQIRETRY);
}
reswitch:
@@ -4738,14 +4738,14 @@ reswitch:
#ifdef AHD_DEBUG
if ((ahd_debug & AHD_SHOW_MESSAGES) != 0) {
ahd_print_devinfo(ahd, &devinfo);
- printf("INITIATOR_MSG_OUT");
+ printk("INITIATOR_MSG_OUT");
}
#endif
phasemis = bus_phase != P_MESGOUT;
if (phasemis) {
#ifdef AHD_DEBUG
if ((ahd_debug & AHD_SHOW_MESSAGES) != 0) {
- printf(" PHASEMIS %s\n",
+ printk(" PHASEMIS %s\n",
ahd_lookup_phase_entry(bus_phase)
->phasemsg);
}
@@ -4772,7 +4772,7 @@ reswitch:
ahd_outb(ahd, CLRSINT1, CLRREQINIT);
#ifdef AHD_DEBUG
if ((ahd_debug & AHD_SHOW_MESSAGES) != 0)
- printf(" byte 0x%x\n", ahd->send_msg_perror);
+ printk(" byte 0x%x\n", ahd->send_msg_perror);
#endif
/*
* If we are notifying the target of a CRC error
@@ -4813,7 +4813,7 @@ reswitch:
ahd_outb(ahd, CLRSINT1, CLRREQINIT);
#ifdef AHD_DEBUG
if ((ahd_debug & AHD_SHOW_MESSAGES) != 0)
- printf(" byte 0x%x\n",
+ printk(" byte 0x%x\n",
ahd->msgout_buf[ahd->msgout_index]);
#endif
ahd_outb(ahd, RETURN_2, ahd->msgout_buf[ahd->msgout_index++]);
@@ -4828,14 +4828,14 @@ reswitch:
#ifdef AHD_DEBUG
if ((ahd_debug & AHD_SHOW_MESSAGES) != 0) {
ahd_print_devinfo(ahd, &devinfo);
- printf("INITIATOR_MSG_IN");
+ printk("INITIATOR_MSG_IN");
}
#endif
phasemis = bus_phase != P_MESGIN;
if (phasemis) {
#ifdef AHD_DEBUG
if ((ahd_debug & AHD_SHOW_MESSAGES) != 0) {
- printf(" PHASEMIS %s\n",
+ printk(" PHASEMIS %s\n",
ahd_lookup_phase_entry(bus_phase)
->phasemsg);
}
@@ -4856,7 +4856,7 @@ reswitch:
ahd->msgin_buf[ahd->msgin_index] = ahd_inb(ahd, SCSIBUS);
#ifdef AHD_DEBUG
if ((ahd_debug & AHD_SHOW_MESSAGES) != 0)
- printf(" byte 0x%x\n",
+ printk(" byte 0x%x\n",
ahd->msgin_buf[ahd->msgin_index]);
#endif
@@ -4878,7 +4878,7 @@ reswitch:
#ifdef AHD_DEBUG
if ((ahd_debug & AHD_SHOW_MESSAGES) != 0) {
ahd_print_devinfo(ahd, &devinfo);
- printf("Asserting ATN for response\n");
+ printk("Asserting ATN for response\n");
}
#endif
ahd_assert_atn(ahd);
@@ -5026,7 +5026,7 @@ reswitch:
if (end_session) {
if ((ahd->msg_flags & MSG_FLAG_PACKETIZED) != 0) {
- printf("%s: Returning to Idle Loop\n",
+ printk("%s: Returning to Idle Loop\n",
ahd_name(ahd));
ahd_clear_msg_state(ahd);
@@ -5178,7 +5178,7 @@ ahd_parse_msg(struct ahd_softc *ahd, struct ahd_devinfo *devinfo)
ahd_validate_offset(ahd, tinfo, period, &offset,
tinfo->curr.width, devinfo->role);
if (bootverbose) {
- printf("(%s:%c:%d:%d): Received "
+ printk("(%s:%c:%d:%d): Received "
"SDTR period %x, offset %x\n\t"
"Filtered to period %x, offset %x\n",
ahd_name(ahd), devinfo->channel,
@@ -5208,7 +5208,7 @@ ahd_parse_msg(struct ahd_softc *ahd, struct ahd_devinfo *devinfo)
*/
if (bootverbose
&& devinfo->role == ROLE_INITIATOR) {
- printf("(%s:%c:%d:%d): Target "
+ printk("(%s:%c:%d:%d): Target "
"Initiated SDTR\n",
ahd_name(ahd), devinfo->channel,
devinfo->target, devinfo->lun);
@@ -5250,7 +5250,7 @@ ahd_parse_msg(struct ahd_softc *ahd, struct ahd_devinfo *devinfo)
ahd_validate_width(ahd, tinfo, &bus_width,
devinfo->role);
if (bootverbose) {
- printf("(%s:%c:%d:%d): Received WDTR "
+ printk("(%s:%c:%d:%d): Received WDTR "
"%x filtered to %x\n",
ahd_name(ahd), devinfo->channel,
devinfo->target, devinfo->lun,
@@ -5266,7 +5266,7 @@ ahd_parse_msg(struct ahd_softc *ahd, struct ahd_devinfo *devinfo)
*/
if (saved_width > bus_width) {
reject = TRUE;
- printf("(%s:%c:%d:%d): requested %dBit "
+ printk("(%s:%c:%d:%d): requested %dBit "
"transfers. Rejecting...\n",
ahd_name(ahd), devinfo->channel,
devinfo->target, devinfo->lun,
@@ -5279,7 +5279,7 @@ ahd_parse_msg(struct ahd_softc *ahd, struct ahd_devinfo *devinfo)
*/
if (bootverbose
&& devinfo->role == ROLE_INITIATOR) {
- printf("(%s:%c:%d:%d): Target "
+ printk("(%s:%c:%d:%d): Target "
"Initiated WDTR\n",
ahd_name(ahd), devinfo->channel,
devinfo->target, devinfo->lun);
@@ -5391,12 +5391,12 @@ ahd_parse_msg(struct ahd_softc *ahd, struct ahd_devinfo *devinfo)
}
} else {
if (devinfo->role != ROLE_TARGET)
- printf("(%s:%c:%d:%d): Target "
+ printk("(%s:%c:%d:%d): Target "
"Initiated PPR\n",
ahd_name(ahd), devinfo->channel,
devinfo->target, devinfo->lun);
else
- printf("(%s:%c:%d:%d): Initiator "
+ printk("(%s:%c:%d:%d): Initiator "
"Initiated PPR\n",
ahd_name(ahd), devinfo->channel,
devinfo->target, devinfo->lun);
@@ -5408,7 +5408,7 @@ ahd_parse_msg(struct ahd_softc *ahd, struct ahd_devinfo *devinfo)
response = TRUE;
}
if (bootverbose) {
- printf("(%s:%c:%d:%d): Received PPR width %x, "
+ printk("(%s:%c:%d:%d): Received PPR width %x, "
"period %x, offset %x,options %x\n"
"\tFiltered to width %x, period %x, "
"offset %x, options %x\n",
@@ -5484,7 +5484,7 @@ ahd_parse_msg(struct ahd_softc *ahd, struct ahd_devinfo *devinfo)
case MSG_QAS_REQUEST:
#ifdef AHD_DEBUG
if ((ahd_debug & AHD_SHOW_MESSAGES) != 0)
- printf("%s: QAS request. SCSISIGI == 0x%x\n",
+ printk("%s: QAS request. SCSISIGI == 0x%x\n",
ahd_name(ahd), ahd_inb(ahd, SCSISIGI));
#endif
ahd->msg_flags |= MSG_FLAG_EXPECT_QASREJ_BUSFREE;
@@ -5549,7 +5549,7 @@ ahd_handle_msg_reject(struct ahd_softc *ahd, struct ahd_devinfo *devinfo)
* off these options.
*/
if (bootverbose) {
- printf("(%s:%c:%d:%d): PPR Rejected. "
+ printk("(%s:%c:%d:%d): PPR Rejected. "
"Trying simple U160 PPR\n",
ahd_name(ahd), devinfo->channel,
devinfo->target, devinfo->lun);
@@ -5564,7 +5564,7 @@ ahd_handle_msg_reject(struct ahd_softc *ahd, struct ahd_devinfo *devinfo)
* Attempt to negotiate SPI-2 style.
*/
if (bootverbose) {
- printf("(%s:%c:%d:%d): PPR Rejected. "
+ printk("(%s:%c:%d:%d): PPR Rejected. "
"Trying WDTR/SDTR\n",
ahd_name(ahd), devinfo->channel,
devinfo->target, devinfo->lun);
@@ -5581,7 +5581,7 @@ ahd_handle_msg_reject(struct ahd_softc *ahd, struct ahd_devinfo *devinfo)
} else if (ahd_sent_msg(ahd, AHDMSG_EXT, MSG_EXT_WDTR, /*full*/FALSE)) {
/* note 8bit xfers */
- printf("(%s:%c:%d:%d): refuses WIDE negotiation. Using "
+ printk("(%s:%c:%d:%d): refuses WIDE negotiation. Using "
"8bit transfers\n", ahd_name(ahd),
devinfo->channel, devinfo->target, devinfo->lun);
ahd_set_width(ahd, devinfo, MSG_EXT_WDTR_BUS_8_BIT,
@@ -5609,7 +5609,7 @@ ahd_handle_msg_reject(struct ahd_softc *ahd, struct ahd_devinfo *devinfo)
/*offset*/0, /*ppr_options*/0,
AHD_TRANS_ACTIVE|AHD_TRANS_GOAL,
/*paused*/TRUE);
- printf("(%s:%c:%d:%d): refuses synchronous negotiation. "
+ printk("(%s:%c:%d:%d): refuses synchronous negotiation. "
"Using asynchronous transfers\n",
ahd_name(ahd), devinfo->channel,
devinfo->target, devinfo->lun);
@@ -5620,13 +5620,13 @@ ahd_handle_msg_reject(struct ahd_softc *ahd, struct ahd_devinfo *devinfo)
tag_type = (scb->hscb->control & MSG_SIMPLE_TASK);
if (tag_type == MSG_SIMPLE_TASK) {
- printf("(%s:%c:%d:%d): refuses tagged commands. "
+ printk("(%s:%c:%d:%d): refuses tagged commands. "
"Performing non-tagged I/O\n", ahd_name(ahd),
devinfo->channel, devinfo->target, devinfo->lun);
ahd_set_tags(ahd, scb->io_ctx, devinfo, AHD_QUEUE_NONE);
mask = ~0x23;
} else {
- printf("(%s:%c:%d:%d): refuses %s tagged commands. "
+ printk("(%s:%c:%d:%d): refuses %s tagged commands. "
"Performing simple queue tagged I/O only\n",
ahd_name(ahd), devinfo->channel, devinfo->target,
devinfo->lun, tag_type == MSG_ORDERED_TASK
@@ -5677,7 +5677,7 @@ ahd_handle_msg_reject(struct ahd_softc *ahd, struct ahd_devinfo *devinfo)
/*
* Otherwise, we ignore it.
*/
- printf("%s:%c:%d: Message reject for %x -- ignored\n",
+ printk("%s:%c:%d: Message reject for %x -- ignored\n",
ahd_name(ahd), devinfo->channel, devinfo->target,
last_msg);
}
@@ -5864,7 +5864,7 @@ ahd_reinitialize_dataptrs(struct ahd_softc *ahd)
ahd_delay(100);
if (wait == 0) {
ahd_print_path(ahd, scb);
- printf("ahd_reinitialize_dataptrs: Forcing FIFO free.\n");
+ printk("ahd_reinitialize_dataptrs: Forcing FIFO free.\n");
ahd_outb(ahd, DFFSXFRCTL, RSTCHN|CLRSHCNT);
}
saved_modes = ahd_save_modes(ahd);
@@ -5978,7 +5978,7 @@ ahd_handle_devreset(struct ahd_softc *ahd, struct ahd_devinfo *devinfo,
CAM_LUN_WILDCARD, AC_SENT_BDR);
if (message != NULL && bootverbose)
- printf("%s: %s on %c:%d. %d SCBs aborted\n", ahd_name(ahd),
+ printk("%s: %s on %c:%d. %d SCBs aborted\n", ahd_name(ahd),
message, devinfo->channel, devinfo->target, found);
}
@@ -6074,23 +6074,22 @@ ahd_alloc(void *platform_arg, char *name)
struct ahd_softc *ahd;
#ifndef __FreeBSD__
- ahd = malloc(sizeof(*ahd), M_DEVBUF, M_NOWAIT);
+ ahd = kmalloc(sizeof(*ahd), GFP_ATOMIC);
if (!ahd) {
- printf("aic7xxx: cannot malloc softc!\n");
- free(name, M_DEVBUF);
+ printk("aic7xxx: cannot malloc softc!\n");
+ kfree(name);
return NULL;
}
#else
ahd = device_get_softc((device_t)platform_arg);
#endif
memset(ahd, 0, sizeof(*ahd));
- ahd->seep_config = malloc(sizeof(*ahd->seep_config),
- M_DEVBUF, M_NOWAIT);
+ ahd->seep_config = kmalloc(sizeof(*ahd->seep_config), GFP_ATOMIC);
if (ahd->seep_config == NULL) {
#ifndef __FreeBSD__
- free(ahd, M_DEVBUF);
+ kfree(ahd);
#endif
- free(name, M_DEVBUF);
+ kfree(name);
return (NULL);
}
LIST_INIT(&ahd->pending_scbs);
@@ -6120,7 +6119,7 @@ ahd_alloc(void *platform_arg, char *name)
}
#ifdef AHD_DEBUG
if ((ahd_debug & AHD_SHOW_MEMORY) != 0) {
- printf("%s: scb size = 0x%x, hscb size = 0x%x\n",
+ printk("%s: scb size = 0x%x, hscb size = 0x%x\n",
ahd_name(ahd), (u_int)sizeof(struct scb),
(u_int)sizeof(struct hardware_scb));
}
@@ -6147,7 +6146,7 @@ void
ahd_set_name(struct ahd_softc *ahd, char *name)
{
if (ahd->name != NULL)
- free(ahd->name, M_DEVBUF);
+ kfree(ahd->name);
ahd->name = name;
}
@@ -6201,27 +6200,27 @@ ahd_free(struct ahd_softc *ahd)
lstate = tstate->enabled_luns[j];
if (lstate != NULL) {
xpt_free_path(lstate->path);
- free(lstate, M_DEVBUF);
+ kfree(lstate);
}
}
#endif
- free(tstate, M_DEVBUF);
+ kfree(tstate);
}
}
#ifdef AHD_TARGET_MODE
if (ahd->black_hole != NULL) {
xpt_free_path(ahd->black_hole->path);
- free(ahd->black_hole, M_DEVBUF);
+ kfree(ahd->black_hole);
}
#endif
if (ahd->name != NULL)
- free(ahd->name, M_DEVBUF);
+ kfree(ahd->name);
if (ahd->seep_config != NULL)
- free(ahd->seep_config, M_DEVBUF);
+ kfree(ahd->seep_config);
if (ahd->saved_stack != NULL)
- free(ahd->saved_stack, M_DEVBUF);
+ kfree(ahd->saved_stack);
#ifndef __FreeBSD__
- free(ahd, M_DEVBUF);
+ kfree(ahd);
#endif
return;
}
@@ -6300,7 +6299,7 @@ ahd_reset(struct ahd_softc *ahd, int reinit)
} while (--wait && !(ahd_inb(ahd, HCNTRL) & CHIPRSTACK));
if (wait == 0) {
- printf("%s: WARNING - Failed chip reset! "
+ printk("%s: WARNING - Failed chip reset! "
"Trying to initialize anyway.\n", ahd_name(ahd));
}
ahd_outb(ahd, HCNTRL, ahd->pause);
@@ -6422,7 +6421,7 @@ ahd_init_scbdata(struct ahd_softc *ahd)
/* Determine the number of hardware SCBs and initialize them */
scb_data->maxhscbs = ahd_probe_scbs(ahd);
if (scb_data->maxhscbs == 0) {
- printf("%s: No SCB space found\n", ahd_name(ahd));
+ printk("%s: No SCB space found\n", ahd_name(ahd));
return (ENXIO);
}
@@ -6465,7 +6464,7 @@ ahd_init_scbdata(struct ahd_softc *ahd)
}
#ifdef AHD_DEBUG
if ((ahd_debug & AHD_SHOW_MEMORY) != 0)
- printf("%s: ahd_sglist_allocsize = 0x%x\n", ahd_name(ahd),
+ printk("%s: ahd_sglist_allocsize = 0x%x\n", ahd_name(ahd),
ahd_sglist_allocsize(ahd));
#endif
@@ -6489,7 +6488,7 @@ ahd_init_scbdata(struct ahd_softc *ahd)
ahd_alloc_scbs(ahd);
if (scb_data->numscbs == 0) {
- printf("%s: ahd_init_scbdata - "
+ printk("%s: ahd_init_scbdata - "
"Unable to allocate initial scbs\n",
ahd_name(ahd));
goto error_exit;
@@ -6564,7 +6563,7 @@ ahd_fini_scbdata(struct ahd_softc *ahd)
sns_map->dmamap);
ahd_dmamem_free(ahd, scb_data->sense_dmat,
sns_map->vaddr, sns_map->dmamap);
- free(sns_map, M_DEVBUF);
+ kfree(sns_map);
}
ahd_dma_tag_destroy(ahd, scb_data->sense_dmat);
/* FALLTHROUGH */
@@ -6579,7 +6578,7 @@ ahd_fini_scbdata(struct ahd_softc *ahd)
sg_map->dmamap);
ahd_dmamem_free(ahd, scb_data->sg_dmat,
sg_map->vaddr, sg_map->dmamap);
- free(sg_map, M_DEVBUF);
+ kfree(sg_map);
}
ahd_dma_tag_destroy(ahd, scb_data->sg_dmat);
/* FALLTHROUGH */
@@ -6594,7 +6593,7 @@ ahd_fini_scbdata(struct ahd_softc *ahd)
hscb_map->dmamap);
ahd_dmamem_free(ahd, scb_data->hscb_dmat,
hscb_map->vaddr, hscb_map->dmamap);
- free(hscb_map, M_DEVBUF);
+ kfree(hscb_map);
}
ahd_dma_tag_destroy(ahd, scb_data->hscb_dmat);
/* FALLTHROUGH */
@@ -6624,7 +6623,7 @@ ahd_setup_iocell_workaround(struct ahd_softc *ahd)
ahd_outb(ahd, SIMODE0, ahd_inb(ahd, SIMODE0) | (ENSELDO|ENSELDI));
#ifdef AHD_DEBUG
if ((ahd_debug & AHD_SHOW_MISC) != 0)
- printf("%s: Setting up iocell workaround\n", ahd_name(ahd));
+ printk("%s: Setting up iocell workaround\n", ahd_name(ahd));
#endif
ahd_restore_modes(ahd, saved_modes);
ahd->flags &= ~AHD_HAD_FIRST_SEL;
@@ -6644,14 +6643,14 @@ ahd_iocell_first_selection(struct ahd_softc *ahd)
ahd_set_modes(ahd, AHD_MODE_CFG, AHD_MODE_CFG);
#ifdef AHD_DEBUG
if ((ahd_debug & AHD_SHOW_MISC) != 0)
- printf("%s: iocell first selection\n", ahd_name(ahd));
+ printk("%s: iocell first selection\n", ahd_name(ahd));
#endif
if ((sblkctl & ENAB40) != 0) {
ahd_outb(ahd, DSPDATACTL,
ahd_inb(ahd, DSPDATACTL) & ~BYPASSENAB);
#ifdef AHD_DEBUG
if ((ahd_debug & AHD_SHOW_MISC) != 0)
- printf("%s: BYPASS now disabled\n", ahd_name(ahd));
+ printk("%s: BYPASS now disabled\n", ahd_name(ahd));
#endif
}
ahd_outb(ahd, SIMODE0, ahd_inb(ahd, SIMODE0) & ~(ENSELDO|ENSELDI));
@@ -6833,7 +6832,7 @@ ahd_alloc_scbs(struct ahd_softc *ahd)
hscb = &((struct hardware_scb *)hscb_map->vaddr)[offset];
hscb_busaddr = hscb_map->physaddr + (offset * sizeof(*hscb));
} else {
- hscb_map = malloc(sizeof(*hscb_map), M_DEVBUF, M_NOWAIT);
+ hscb_map = kmalloc(sizeof(*hscb_map), GFP_ATOMIC);
if (hscb_map == NULL)
return;
@@ -6842,7 +6841,7 @@ ahd_alloc_scbs(struct ahd_softc *ahd)
if (ahd_dmamem_alloc(ahd, scb_data->hscb_dmat,
(void **)&hscb_map->vaddr,
BUS_DMA_NOWAIT, &hscb_map->dmamap) != 0) {
- free(hscb_map, M_DEVBUF);
+ kfree(hscb_map);
return;
}
@@ -6866,7 +6865,7 @@ ahd_alloc_scbs(struct ahd_softc *ahd)
segs = sg_map->vaddr + offset;
sg_busaddr = sg_map->physaddr + offset;
} else {
- sg_map = malloc(sizeof(*sg_map), M_DEVBUF, M_NOWAIT);
+ sg_map = kmalloc(sizeof(*sg_map), GFP_ATOMIC);
if (sg_map == NULL)
return;
@@ -6875,7 +6874,7 @@ ahd_alloc_scbs(struct ahd_softc *ahd)
if (ahd_dmamem_alloc(ahd, scb_data->sg_dmat,
(void **)&sg_map->vaddr,
BUS_DMA_NOWAIT, &sg_map->dmamap) != 0) {
- free(sg_map, M_DEVBUF);
+ kfree(sg_map);
return;
}
@@ -6891,7 +6890,7 @@ ahd_alloc_scbs(struct ahd_softc *ahd)
ahd_sglist_allocsize(ahd) / ahd_sglist_size(ahd);
#ifdef AHD_DEBUG
if (ahd_debug & AHD_SHOW_MEMORY)
- printf("Mapped SG data\n");
+ printk("Mapped SG data\n");
#endif
}
@@ -6903,7 +6902,7 @@ ahd_alloc_scbs(struct ahd_softc *ahd)
sense_data = sense_map->vaddr + offset;
sense_busaddr = sense_map->physaddr + offset;
} else {
- sense_map = malloc(sizeof(*sense_map), M_DEVBUF, M_NOWAIT);
+ sense_map = kmalloc(sizeof(*sense_map), GFP_ATOMIC);
if (sense_map == NULL)
return;
@@ -6912,7 +6911,7 @@ ahd_alloc_scbs(struct ahd_softc *ahd)
if (ahd_dmamem_alloc(ahd, scb_data->sense_dmat,
(void **)&sense_map->vaddr,
BUS_DMA_NOWAIT, &sense_map->dmamap) != 0) {
- free(sense_map, M_DEVBUF);
+ kfree(sense_map);
return;
}
@@ -6927,7 +6926,7 @@ ahd_alloc_scbs(struct ahd_softc *ahd)
scb_data->sense_left = PAGE_SIZE / AHD_SENSE_BUFSIZE;
#ifdef AHD_DEBUG
if (ahd_debug & AHD_SHOW_MEMORY)
- printf("Mapped sense data\n");
+ printk("Mapped sense data\n");
#endif
}
@@ -6941,15 +6940,13 @@ ahd_alloc_scbs(struct ahd_softc *ahd)
int error;
#endif
- next_scb = (struct scb *)malloc(sizeof(*next_scb),
- M_DEVBUF, M_NOWAIT);
+ next_scb = kmalloc(sizeof(*next_scb), GFP_ATOMIC);
if (next_scb == NULL)
break;
- pdata = (struct scb_platform_data *)malloc(sizeof(*pdata),
- M_DEVBUF, M_NOWAIT);
+ pdata = kmalloc(sizeof(*pdata), GFP_ATOMIC);
if (pdata == NULL) {
- free(next_scb, M_DEVBUF);
+ kfree(next_scb);
break;
}
next_scb->platform_data = pdata;
@@ -6979,8 +6976,8 @@ ahd_alloc_scbs(struct ahd_softc *ahd)
error = ahd_dmamap_create(ahd, ahd->buffer_dmat, /*flags*/0,
&next_scb->dmamap);
if (error != 0) {
- free(next_scb, M_DEVBUF);
- free(pdata, M_DEVBUF);
+ kfree(next_scb);
+ kfree(pdata);
break;
}
#endif
@@ -7077,8 +7074,7 @@ ahd_init(struct ahd_softc *ahd)
AHD_ASSERT_MODES(ahd, AHD_MODE_SCSI_MSK, AHD_MODE_SCSI_MSK);
ahd->stack_size = ahd_probe_stack_size(ahd);
- ahd->saved_stack = malloc(ahd->stack_size * sizeof(uint16_t),
- M_DEVBUF, M_NOWAIT);
+ ahd->saved_stack = kmalloc(ahd->stack_size * sizeof(uint16_t), GFP_ATOMIC);
if (ahd->saved_stack == NULL)
return (ENOMEM);
@@ -7224,20 +7220,20 @@ ahd_init(struct ahd_softc *ahd)
error = ahd_write_flexport(ahd, FLXADDR_ROMSTAT_CURSENSECTL,
CURSENSE_ENB);
if (error != 0) {
- printf("%s: current sensing timeout 1\n", ahd_name(ahd));
+ printk("%s: current sensing timeout 1\n", ahd_name(ahd));
goto init_done;
}
for (i = 20, fstat = FLX_FSTAT_BUSY;
(fstat & FLX_FSTAT_BUSY) != 0 && i; i--) {
error = ahd_read_flexport(ahd, FLXADDR_FLEXSTAT, &fstat);
if (error != 0) {
- printf("%s: current sensing timeout 2\n",
+ printk("%s: current sensing timeout 2\n",
ahd_name(ahd));
goto init_done;
}
}
if (i == 0) {
- printf("%s: Timedout during current-sensing test\n",
+ printk("%s: Timedout during current-sensing test\n",
ahd_name(ahd));
goto init_done;
}
@@ -7245,7 +7241,7 @@ ahd_init(struct ahd_softc *ahd)
/* Latch Current Sensing status. */
error = ahd_read_flexport(ahd, FLXADDR_CURRENT_STAT, &current_sensing);
if (error != 0) {
- printf("%s: current sensing timeout 3\n", ahd_name(ahd));
+ printk("%s: current sensing timeout 3\n", ahd_name(ahd));
goto init_done;
}
@@ -7254,7 +7250,7 @@ ahd_init(struct ahd_softc *ahd)
#ifdef AHD_DEBUG
if ((ahd_debug & AHD_SHOW_TERMCTL) != 0) {
- printf("%s: current_sensing == 0x%x\n",
+ printk("%s: current_sensing == 0x%x\n",
ahd_name(ahd), current_sensing);
}
#endif
@@ -7271,13 +7267,13 @@ ahd_init(struct ahd_softc *ahd)
case FLX_CSTAT_OKAY:
if (warn_user == 0 && bootverbose == 0)
break;
- printf("%s: %s Channel %s\n", ahd_name(ahd),
+ printk("%s: %s Channel %s\n", ahd_name(ahd),
channel_strings[i], termstat_strings[term_stat]);
break;
}
}
if (warn_user) {
- printf("%s: WARNING. Termination is not configured correctly.\n"
+ printk("%s: WARNING. Termination is not configured correctly.\n"
"%s: WARNING. SCSI bus operations may FAIL.\n",
ahd_name(ahd), ahd_name(ahd));
}
@@ -7393,7 +7389,7 @@ ahd_chip_init(struct ahd_softc *ahd)
}
#ifdef AHD_DEBUG
if ((ahd_debug & AHD_SHOW_MISC) != 0)
- printf("%s: WRTBIASCTL now 0x%x\n", ahd_name(ahd),
+ printk("%s: WRTBIASCTL now 0x%x\n", ahd_name(ahd),
WRTBIASCTL_HP_DEFAULT);
#endif
}
@@ -7622,9 +7618,9 @@ ahd_chip_init(struct ahd_softc *ahd)
ahd_outb(ahd, NEGCONOPTS, negodat3);
negodat3 = ahd_inb(ahd, NEGCONOPTS);
if (!(negodat3 & ENSLOWCRC))
- printf("aic79xx: failed to set the SLOWCRC bit\n");
+ printk("aic79xx: failed to set the SLOWCRC bit\n");
else
- printf("aic79xx: SLOWCRC bit set\n");
+ printk("aic79xx: SLOWCRC bit set\n");
}
}
@@ -7646,7 +7642,7 @@ ahd_default_config(struct ahd_softc *ahd)
* data for any target mode initiator.
*/
if (ahd_alloc_tstate(ahd, ahd->our_id, 'A') == NULL) {
- printf("%s: unable to allocate ahd_tmode_tstate. "
+ printk("%s: unable to allocate ahd_tmode_tstate. "
"Failing attach\n", ahd_name(ahd));
return (ENOMEM);
}
@@ -7725,7 +7721,7 @@ ahd_parse_cfgdata(struct ahd_softc *ahd, struct seeprom_config *sc)
* data for any target mode initiator.
*/
if (ahd_alloc_tstate(ahd, ahd->our_id, 'A') == NULL) {
- printf("%s: unable to allocate ahd_tmode_tstate. "
+ printk("%s: unable to allocate ahd_tmode_tstate. "
"Failing attach\n", ahd_name(ahd));
return (ENOMEM);
}
@@ -7795,7 +7791,7 @@ ahd_parse_cfgdata(struct ahd_softc *ahd, struct seeprom_config *sc)
user_tinfo->width = MSG_EXT_WDTR_BUS_8_BIT;
#ifdef AHD_DEBUG
if ((ahd_debug & AHD_SHOW_MISC) != 0)
- printf("(%d): %x:%x:%x:%x\n", targ, user_tinfo->width,
+ printk("(%d): %x:%x:%x:%x\n", targ, user_tinfo->width,
user_tinfo->period, user_tinfo->offset,
user_tinfo->ppr_options);
#endif
@@ -7951,7 +7947,7 @@ ahd_pause_and_flushwork(struct ahd_softc *ahd)
|| (ahd_inb(ahd, SSTAT0) & (SELDO|SELINGO)) != 0));
if (maxloops == 0) {
- printf("Infinite interrupt loop, INTSTAT = %x",
+ printk("Infinite interrupt loop, INTSTAT = %x",
ahd_inb(ahd, INTSTAT));
}
ahd->qfreeze_cnt++;
@@ -8241,7 +8237,7 @@ ahd_search_qinfifo(struct ahd_softc *ahd, int target, char channel,
prev_scb = NULL;
if (action == SEARCH_PRINT) {
- printf("qinstart = %d qinfifonext = %d\nQINFIFO:",
+ printk("qinstart = %d qinfifonext = %d\nQINFIFO:",
qinstart, ahd->qinfifonext);
}
@@ -8256,7 +8252,7 @@ ahd_search_qinfifo(struct ahd_softc *ahd, int target, char channel,
while (qinpos != qintail) {
scb = ahd_lookup_scb(ahd, ahd->qinfifo[qinpos]);
if (scb == NULL) {
- printf("qinpos = %d, SCB index = %d\n",
+ printk("qinpos = %d, SCB index = %d\n",
qinpos, ahd->qinfifo[qinpos]);
panic("Loop 1\n");
}
@@ -8269,13 +8265,13 @@ ahd_search_qinfifo(struct ahd_softc *ahd, int target, char channel,
switch (action) {
case SEARCH_COMPLETE:
if ((scb->flags & SCB_ACTIVE) == 0)
- printf("Inactive SCB in qinfifo\n");
+ printk("Inactive SCB in qinfifo\n");
ahd_done_with_status(ahd, scb, status);
/* FALLTHROUGH */
case SEARCH_REMOVE:
break;
case SEARCH_PRINT:
- printf(" 0x%x", ahd->qinfifo[qinpos]);
+ printk(" 0x%x", ahd->qinfifo[qinpos]);
/* FALLTHROUGH */
case SEARCH_COUNT:
ahd_qinfifo_requeue(ahd, prev_scb, scb);
@@ -8292,7 +8288,7 @@ ahd_search_qinfifo(struct ahd_softc *ahd, int target, char channel,
ahd_set_hnscb_qoff(ahd, ahd->qinfifonext);
if (action == SEARCH_PRINT)
- printf("\nWAITING_TID_QUEUES:\n");
+ printk("\nWAITING_TID_QUEUES:\n");
/*
* Search waiting for selection lists. We traverse the
@@ -8320,7 +8316,7 @@ ahd_search_qinfifo(struct ahd_softc *ahd, int target, char channel,
panic("TID LIST LOOP");
if (scbid >= ahd->scb_data.numscbs) {
- printf("%s: Waiting TID List inconsistency. "
+ printk("%s: Waiting TID List inconsistency. "
"SCB index == 0x%x, yet numscbs == 0x%x.",
ahd_name(ahd), scbid, ahd->scb_data.numscbs);
ahd_dump_card_state(ahd);
@@ -8328,7 +8324,7 @@ ahd_search_qinfifo(struct ahd_softc *ahd, int target, char channel,
}
scb = ahd_lookup_scb(ahd, scbid);
if (scb == NULL) {
- printf("%s: SCB = 0x%x Not Active!\n",
+ printk("%s: SCB = 0x%x Not Active!\n",
ahd_name(ahd), scbid);
panic("Waiting TID List traversal\n");
}
@@ -8344,7 +8340,7 @@ ahd_search_qinfifo(struct ahd_softc *ahd, int target, char channel,
* We found a list of scbs that needs to be searched.
*/
if (action == SEARCH_PRINT)
- printf(" %d ( ", SCB_GET_TARGET(ahd, scb));
+ printk(" %d ( ", SCB_GET_TARGET(ahd, scb));
tid_head = scbid;
found += ahd_search_scb_list(ahd, target, channel,
lun, tag, role, status,
@@ -8365,14 +8361,14 @@ ahd_search_qinfifo(struct ahd_softc *ahd, int target, char channel,
switch (action) {
case SEARCH_COMPLETE:
if ((mk_msg_scb->flags & SCB_ACTIVE) == 0)
- printf("Inactive SCB pending MK_MSG\n");
+ printk("Inactive SCB pending MK_MSG\n");
ahd_done_with_status(ahd, mk_msg_scb, status);
/* FALLTHROUGH */
case SEARCH_REMOVE:
{
u_int tail_offset;
- printf("Removing MK_MSG scb\n");
+ printk("Removing MK_MSG scb\n");
/*
* Reset our tail to the tail of the
@@ -8390,7 +8386,7 @@ ahd_search_qinfifo(struct ahd_softc *ahd, int target, char channel,
break;
}
case SEARCH_PRINT:
- printf(" 0x%x", SCB_GET_TAG(scb));
+ printk(" 0x%x", SCB_GET_TAG(scb));
/* FALLTHROUGH */
case SEARCH_COUNT:
break;
@@ -8407,7 +8403,7 @@ ahd_search_qinfifo(struct ahd_softc *ahd, int target, char channel,
* queue with a pending MK_MESSAGE scb, we
* must queue the MK_MESSAGE scb.
*/
- printf("Queueing mk_msg_scb\n");
+ printk("Queueing mk_msg_scb\n");
tid_head = ahd_inw(ahd, MK_MESSAGE_SCB);
seq_flags2 &= ~PENDING_MK_MESSAGE;
ahd_outb(ahd, SEQ_FLAGS2, seq_flags2);
@@ -8418,7 +8414,7 @@ ahd_search_qinfifo(struct ahd_softc *ahd, int target, char channel,
if (!SCBID_IS_NULL(tid_head))
tid_prev = tid_head;
if (action == SEARCH_PRINT)
- printf(")\n");
+ printk(")\n");
}
/* Restore saved state. */
@@ -8446,7 +8442,7 @@ ahd_search_scb_list(struct ahd_softc *ahd, int target, char channel,
*list_tail = SCB_LIST_NULL;
for (scbid = next; !SCBID_IS_NULL(scbid); scbid = next) {
if (scbid >= ahd->scb_data.numscbs) {
- printf("%s:SCB List inconsistency. "
+ printk("%s:SCB List inconsistency. "
"SCB == 0x%x, yet numscbs == 0x%x.",
ahd_name(ahd), scbid, ahd->scb_data.numscbs);
ahd_dump_card_state(ahd);
@@ -8454,7 +8450,7 @@ ahd_search_scb_list(struct ahd_softc *ahd, int target, char channel,
}
scb = ahd_lookup_scb(ahd, scbid);
if (scb == NULL) {
- printf("%s: SCB = %d Not Active!\n",
+ printk("%s: SCB = %d Not Active!\n",
ahd_name(ahd), scbid);
panic("Waiting List traversal\n");
}
@@ -8470,7 +8466,7 @@ ahd_search_scb_list(struct ahd_softc *ahd, int target, char channel,
switch (action) {
case SEARCH_COMPLETE:
if ((scb->flags & SCB_ACTIVE) == 0)
- printf("Inactive SCB in Waiting List\n");
+ printk("Inactive SCB in Waiting List\n");
ahd_done_with_status(ahd, scb, status);
/* FALLTHROUGH */
case SEARCH_REMOVE:
@@ -8480,7 +8476,7 @@ ahd_search_scb_list(struct ahd_softc *ahd, int target, char channel,
*list_head = next;
break;
case SEARCH_PRINT:
- printf("0x%x ", scbid);
+ printk("0x%x ", scbid);
case SEARCH_COUNT:
prev = scbid;
break;
@@ -8668,7 +8664,7 @@ ahd_abort_scbs(struct ahd_softc *ahd, int target, char channel,
if (ahd_get_transaction_status(scbp) != CAM_REQ_CMP)
ahd_freeze_scb(scbp);
if ((scbp->flags & SCB_ACTIVE) == 0)
- printf("Inactive SCB on pending list\n");
+ printk("Inactive SCB on pending list\n");
ahd_done(ahd, scbp);
found++;
}
@@ -8725,7 +8721,7 @@ ahd_reset_channel(struct ahd_softc *ahd, char channel, int initiate_reset)
* Check if the last bus reset is cleared
*/
if (ahd->flags & AHD_BUS_RESET_ACTIVE) {
- printf("%s: bus reset still active\n",
+ printk("%s: bus reset still active\n",
ahd_name(ahd));
return 0;
}
@@ -8900,7 +8896,7 @@ ahd_stat_timer(void *arg)
ahd_enable_coalescing(ahd, enint_coal);
#ifdef AHD_DEBUG
if ((ahd_debug & AHD_SHOW_INT_COALESCING) != 0)
- printf("%s: Interrupt coalescing "
+ printk("%s: Interrupt coalescing "
"now %sabled. Cmds %d\n",
ahd_name(ahd),
(enint_coal & ENINT_COALESCE) ? "en" : "dis",
@@ -8975,9 +8971,9 @@ ahd_handle_scsi_status(struct ahd_softc *ahd, struct scb *scb)
#ifdef AHD_DEBUG
if ((ahd_debug & AHD_SHOW_SENSE) != 0) {
ahd_print_path(ahd, scb);
- printf("SCB 0x%x Received PKT Status of 0x%x\n",
+ printk("SCB 0x%x Received PKT Status of 0x%x\n",
SCB_GET_TAG(scb), siu->status);
- printf("\tflags = 0x%x, sense len = 0x%x, "
+ printk("\tflags = 0x%x, sense len = 0x%x, "
"pktfail = 0x%x\n",
siu->flags, scsi_4btoul(siu->sense_length),
scsi_4btoul(siu->pkt_failures_length));
@@ -8986,27 +8982,27 @@ ahd_handle_scsi_status(struct ahd_softc *ahd, struct scb *scb)
if ((siu->flags & SIU_RSPVALID) != 0) {
ahd_print_path(ahd, scb);
if (scsi_4btoul(siu->pkt_failures_length) < 4) {
- printf("Unable to parse pkt_failures\n");
+ printk("Unable to parse pkt_failures\n");
} else {
switch (SIU_PKTFAIL_CODE(siu)) {
case SIU_PFC_NONE:
- printf("No packet failure found\n");
+ printk("No packet failure found\n");
break;
case SIU_PFC_CIU_FIELDS_INVALID:
- printf("Invalid Command IU Field\n");
+ printk("Invalid Command IU Field\n");
break;
case SIU_PFC_TMF_NOT_SUPPORTED:
- printf("TMF not supportd\n");
+ printk("TMF not supportd\n");
break;
case SIU_PFC_TMF_FAILED:
- printf("TMF failed\n");
+ printk("TMF failed\n");
break;
case SIU_PFC_INVALID_TYPE_CODE:
- printf("Invalid L_Q Type code\n");
+ printk("Invalid L_Q Type code\n");
break;
case SIU_PFC_ILLEGAL_REQUEST:
- printf("Illegal request\n");
+ printk("Illegal request\n");
default:
break;
}
@@ -9019,7 +9015,7 @@ ahd_handle_scsi_status(struct ahd_softc *ahd, struct scb *scb)
scb->flags |= SCB_PKT_SENSE;
#ifdef AHD_DEBUG
if ((ahd_debug & AHD_SHOW_SENSE) != 0)
- printf("Sense data available\n");
+ printk("Sense data available\n");
#endif
}
ahd_done(ahd, scb);
@@ -9037,7 +9033,7 @@ ahd_handle_scsi_status(struct ahd_softc *ahd, struct scb *scb)
#ifdef AHD_DEBUG
if (ahd_debug & AHD_SHOW_SENSE) {
ahd_print_path(ahd, scb);
- printf("SCB %d: requests Check Status\n",
+ printk("SCB %d: requests Check Status\n",
SCB_GET_TAG(scb));
}
#endif
@@ -9065,7 +9061,7 @@ ahd_handle_scsi_status(struct ahd_softc *ahd, struct scb *scb)
#ifdef AHD_DEBUG
if (ahd_debug & AHD_SHOW_SENSE) {
ahd_print_path(ahd, scb);
- printf("Sending Sense\n");
+ printk("Sending Sense\n");
}
#endif
scb->sg_count = 0;
@@ -9117,7 +9113,7 @@ ahd_handle_scsi_status(struct ahd_softc *ahd, struct scb *scb)
break;
}
case SCSI_STATUS_OK:
- printf("%s: Interrupted for staus of 0???\n",
+ printk("%s: Interrupted for staus of 0???\n",
ahd_name(ahd));
/* FALLTHROUGH */
default:
@@ -9192,7 +9188,7 @@ ahd_calc_residual(struct ahd_softc *ahd, struct scb *scb)
return;
} else if ((resid_sgptr & SG_OVERRUN_RESID) != 0) {
ahd_print_path(ahd, scb);
- printf("data overrun detected Tag == 0x%x.\n",
+ printk("data overrun detected Tag == 0x%x.\n",
SCB_GET_TAG(scb));
ahd_freeze_devq(ahd, scb);
ahd_set_transaction_status(scb, CAM_DATA_RUN_ERR);
@@ -9232,7 +9228,7 @@ ahd_calc_residual(struct ahd_softc *ahd, struct scb *scb)
#ifdef AHD_DEBUG
if ((ahd_debug & AHD_SHOW_MISC) != 0) {
ahd_print_path(ahd, scb);
- printf("Handled %sResidual of %d bytes\n",
+ printk("Handled %sResidual of %d bytes\n",
(scb->flags & SCB_SENSE) ? "Sense " : "", resid);
}
#endif
@@ -9272,7 +9268,7 @@ ahd_queue_lstate_event(struct ahd_softc *ahd, struct ahd_tmode_lstate *lstate,
if (pending == AHD_TMODE_EVENT_BUFFER_SIZE) {
xpt_print_path(lstate->path);
- printf("immediate event %x:%x lost\n",
+ printk("immediate event %x:%x lost\n",
lstate->event_buffer[lstate->event_r_idx].event_type,
lstate->event_buffer[lstate->event_r_idx].event_arg);
lstate->event_r_idx++;
@@ -9344,7 +9340,7 @@ ahd_dumpseq(struct ahd_softc* ahd)
uint8_t ins_bytes[4];
ahd_insb(ahd, SEQRAM, ins_bytes, 4);
- printf("0x%08x\n", ins_bytes[0] << 24
+ printk("0x%08x\n", ins_bytes[0] << 24
| ins_bytes[1] << 16
| ins_bytes[2] << 8
| ins_bytes[3]);
@@ -9372,7 +9368,7 @@ ahd_loadseq(struct ahd_softc *ahd)
uint8_t download_consts[DOWNLOAD_CONST_COUNT];
if (bootverbose)
- printf("%s: Downloading Sequencer Program...",
+ printk("%s: Downloading Sequencer Program...",
ahd_name(ahd));
#if DOWNLOAD_CONST_COUNT != 8
@@ -9498,7 +9494,7 @@ ahd_loadseq(struct ahd_softc *ahd)
if (cs_count != 0) {
cs_count *= sizeof(struct cs);
- ahd->critical_sections = malloc(cs_count, M_DEVBUF, M_NOWAIT);
+ ahd->critical_sections = kmalloc(cs_count, GFP_ATOMIC);
if (ahd->critical_sections == NULL)
panic("ahd_loadseq: Could not malloc");
memcpy(ahd->critical_sections, cs_table, cs_count);
@@ -9506,8 +9502,8 @@ ahd_loadseq(struct ahd_softc *ahd)
ahd_outb(ahd, SEQCTL0, PERRORDIS|FAILDIS|FASTMODE);
if (bootverbose) {
- printf(" %d instructions downloaded\n", downloaded);
- printf("%s: Features 0x%x, Bugs 0x%x, Flags 0x%x\n",
+ printk(" %d instructions downloaded\n", downloaded);
+ printk("%s: Features 0x%x, Bugs 0x%x, Flags 0x%x\n",
ahd_name(ahd), ahd->features, ahd->bugs, ahd->flags);
}
}
@@ -9690,12 +9686,12 @@ ahd_print_register(const ahd_reg_parse_entry_t *table, u_int num_entries,
u_int printed_mask;
if (cur_column != NULL && *cur_column >= wrap_point) {
- printf("\n");
+ printk("\n");
*cur_column = 0;
}
- printed = printf("%s[0x%x]", name, value);
+ printed = printk("%s[0x%x]", name, value);
if (table == NULL) {
- printed += printf(" ");
+ printed += printk(" ");
*cur_column += printed;
return (printed);
}
@@ -9710,7 +9706,7 @@ ahd_print_register(const ahd_reg_parse_entry_t *table, u_int num_entries,
== table[entry].mask))
continue;
- printed += printf("%s%s",
+ printed += printk("%s%s",
printed_mask == 0 ? ":(" : "|",
table[entry].name);
printed_mask |= table[entry].mask;
@@ -9721,9 +9717,9 @@ ahd_print_register(const ahd_reg_parse_entry_t *table, u_int num_entries,
break;
}
if (printed_mask != 0)
- printed += printf(") ");
+ printed += printk(") ");
else
- printed += printf(" ");
+ printed += printk(" ");
if (cur_column != NULL)
*cur_column += printed;
return (printed);
@@ -9749,17 +9745,17 @@ ahd_dump_card_state(struct ahd_softc *ahd)
}
saved_modes = ahd_save_modes(ahd);
ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI);
- printf(">>>>>>>>>>>>>>>>>> Dump Card State Begins <<<<<<<<<<<<<<<<<\n"
+ printk(">>>>>>>>>>>>>>>>>> Dump Card State Begins <<<<<<<<<<<<<<<<<\n"
"%s: Dumping Card State at program address 0x%x Mode 0x%x\n",
ahd_name(ahd),
ahd_inw(ahd, CURADDR),
ahd_build_mode_state(ahd, ahd->saved_src_mode,
ahd->saved_dst_mode));
if (paused)
- printf("Card was paused\n");
+ printk("Card was paused\n");
if (ahd_check_cmdcmpltqueues(ahd))
- printf("Completions are pending\n");
+ printk("Completions are pending\n");
/*
* Mode independent registers.
@@ -9801,8 +9797,8 @@ ahd_dump_card_state(struct ahd_softc *ahd)
ahd_lqostat0_print(ahd_inb(ahd, LQOSTAT0), &cur_col, 50);
ahd_lqostat1_print(ahd_inb(ahd, LQOSTAT1), &cur_col, 50);
ahd_lqostat2_print(ahd_inb(ahd, LQOSTAT2), &cur_col, 50);
- printf("\n");
- printf("\nSCB Count = %d CMDS_PENDING = %d LASTSCB 0x%x "
+ printk("\n");
+ printk("\nSCB Count = %d CMDS_PENDING = %d LASTSCB 0x%x "
"CURRSCB 0x%x NEXTSCB 0x%x\n",
ahd->scb_data.numscbs, ahd_inw(ahd, CMDS_PENDING),
ahd_inw(ahd, LASTSCB), ahd_inw(ahd, CURRSCB),
@@ -9813,12 +9809,12 @@ ahd_dump_card_state(struct ahd_softc *ahd)
CAM_LUN_WILDCARD, SCB_LIST_NULL,
ROLE_UNKNOWN, /*status*/0, SEARCH_PRINT);
saved_scb_index = ahd_get_scbptr(ahd);
- printf("Pending list:");
+ printk("Pending list:");
i = 0;
LIST_FOREACH(scb, &ahd->pending_scbs, pending_links) {
if (i++ > AHD_SCB_MAX)
break;
- cur_col = printf("\n%3d FIFO_USE[0x%x] ", SCB_GET_TAG(scb),
+ cur_col = printk("\n%3d FIFO_USE[0x%x] ", SCB_GET_TAG(scb),
ahd_inb_scbram(ahd, SCB_FIFO_USE_COUNT));
ahd_set_scbptr(ahd, SCB_GET_TAG(scb));
ahd_scb_control_print(ahd_inb_scbram(ahd, SCB_CONTROL),
@@ -9826,16 +9822,16 @@ ahd_dump_card_state(struct ahd_softc *ahd)
ahd_scb_scsiid_print(ahd_inb_scbram(ahd, SCB_SCSIID),
&cur_col, 60);
}
- printf("\nTotal %d\n", i);
+ printk("\nTotal %d\n", i);
- printf("Kernel Free SCB list: ");
+ printk("Kernel Free SCB list: ");
i = 0;
TAILQ_FOREACH(scb, &ahd->scb_data.free_scbs, links.tqe) {
struct scb *list_scb;
list_scb = scb;
do {
- printf("%d ", SCB_GET_TAG(list_scb));
+ printk("%d ", SCB_GET_TAG(list_scb));
list_scb = LIST_NEXT(list_scb, collision_links);
} while (list_scb && i++ < AHD_SCB_MAX);
}
@@ -9843,49 +9839,49 @@ ahd_dump_card_state(struct ahd_softc *ahd)
LIST_FOREACH(scb, &ahd->scb_data.any_dev_free_scb_list, links.le) {
if (i++ > AHD_SCB_MAX)
break;
- printf("%d ", SCB_GET_TAG(scb));
+ printk("%d ", SCB_GET_TAG(scb));
}
- printf("\n");
+ printk("\n");
- printf("Sequencer Complete DMA-inprog list: ");
+ printk("Sequencer Complete DMA-inprog list: ");
scb_index = ahd_inw(ahd, COMPLETE_SCB_DMAINPROG_HEAD);
i = 0;
while (!SCBID_IS_NULL(scb_index) && i++ < AHD_SCB_MAX) {
ahd_set_scbptr(ahd, scb_index);
- printf("%d ", scb_index);
+ printk("%d ", scb_index);
scb_index = ahd_inw_scbram(ahd, SCB_NEXT_COMPLETE);
}
- printf("\n");
+ printk("\n");
- printf("Sequencer Complete list: ");
+ printk("Sequencer Complete list: ");
scb_index = ahd_inw(ahd, COMPLETE_SCB_HEAD);
i = 0;
while (!SCBID_IS_NULL(scb_index) && i++ < AHD_SCB_MAX) {
ahd_set_scbptr(ahd, scb_index);
- printf("%d ", scb_index);
+ printk("%d ", scb_index);
scb_index = ahd_inw_scbram(ahd, SCB_NEXT_COMPLETE);
}
- printf("\n");
+ printk("\n");
- printf("Sequencer DMA-Up and Complete list: ");
+ printk("Sequencer DMA-Up and Complete list: ");
scb_index = ahd_inw(ahd, COMPLETE_DMA_SCB_HEAD);
i = 0;
while (!SCBID_IS_NULL(scb_index) && i++ < AHD_SCB_MAX) {
ahd_set_scbptr(ahd, scb_index);
- printf("%d ", scb_index);
+ printk("%d ", scb_index);
scb_index = ahd_inw_scbram(ahd, SCB_NEXT_COMPLETE);
}
- printf("\n");
- printf("Sequencer On QFreeze and Complete list: ");
+ printk("\n");
+ printk("Sequencer On QFreeze and Complete list: ");
scb_index = ahd_inw(ahd, COMPLETE_ON_QFREEZE_HEAD);
i = 0;
while (!SCBID_IS_NULL(scb_index) && i++ < AHD_SCB_MAX) {
ahd_set_scbptr(ahd, scb_index);
- printf("%d ", scb_index);
+ printk("%d ", scb_index);
scb_index = ahd_inw_scbram(ahd, SCB_NEXT_COMPLETE);
}
- printf("\n");
+ printk("\n");
ahd_set_scbptr(ahd, saved_scb_index);
dffstat = ahd_inb(ahd, DFFSTAT);
for (i = 0; i < 2; i++) {
@@ -9896,7 +9892,7 @@ ahd_dump_card_state(struct ahd_softc *ahd)
ahd_set_modes(ahd, AHD_MODE_DFF0 + i, AHD_MODE_DFF0 + i);
fifo_scbptr = ahd_get_scbptr(ahd);
- printf("\n\n%s: FIFO%d %s, LONGJMP == 0x%x, SCB 0x%x\n",
+ printk("\n\n%s: FIFO%d %s, LONGJMP == 0x%x, SCB 0x%x\n",
ahd_name(ahd), i,
(dffstat & (FIFO0FREE << i)) ? "Free" : "Active",
ahd_inw(ahd, LONGJMP_ADDR), fifo_scbptr);
@@ -9912,20 +9908,20 @@ ahd_dump_card_state(struct ahd_softc *ahd)
ahd_soffcnt_print(ahd_inb(ahd, SOFFCNT), &cur_col, 50);
ahd_mdffstat_print(ahd_inb(ahd, MDFFSTAT), &cur_col, 50);
if (cur_col > 50) {
- printf("\n");
+ printk("\n");
cur_col = 0;
}
- cur_col += printf("SHADDR = 0x%x%x, SHCNT = 0x%x ",
+ cur_col += printk("SHADDR = 0x%x%x, SHCNT = 0x%x ",
ahd_inl(ahd, SHADDR+4),
ahd_inl(ahd, SHADDR),
(ahd_inb(ahd, SHCNT)
| (ahd_inb(ahd, SHCNT + 1) << 8)
| (ahd_inb(ahd, SHCNT + 2) << 16)));
if (cur_col > 50) {
- printf("\n");
+ printk("\n");
cur_col = 0;
}
- cur_col += printf("HADDR = 0x%x%x, HCNT = 0x%x ",
+ cur_col += printk("HADDR = 0x%x%x, HCNT = 0x%x ",
ahd_inl(ahd, HADDR+4),
ahd_inl(ahd, HADDR),
(ahd_inb(ahd, HCNT)
@@ -9940,52 +9936,52 @@ ahd_dump_card_state(struct ahd_softc *ahd)
}
#endif
}
- printf("\nLQIN: ");
+ printk("\nLQIN: ");
for (i = 0; i < 20; i++)
- printf("0x%x ", ahd_inb(ahd, LQIN + i));
- printf("\n");
+ printk("0x%x ", ahd_inb(ahd, LQIN + i));
+ printk("\n");
ahd_set_modes(ahd, AHD_MODE_CFG, AHD_MODE_CFG);
- printf("%s: LQISTATE = 0x%x, LQOSTATE = 0x%x, OPTIONMODE = 0x%x\n",
+ printk("%s: LQISTATE = 0x%x, LQOSTATE = 0x%x, OPTIONMODE = 0x%x\n",
ahd_name(ahd), ahd_inb(ahd, LQISTATE), ahd_inb(ahd, LQOSTATE),
ahd_inb(ahd, OPTIONMODE));
- printf("%s: OS_SPACE_CNT = 0x%x MAXCMDCNT = 0x%x\n",
+ printk("%s: OS_SPACE_CNT = 0x%x MAXCMDCNT = 0x%x\n",
ahd_name(ahd), ahd_inb(ahd, OS_SPACE_CNT),
ahd_inb(ahd, MAXCMDCNT));
- printf("%s: SAVED_SCSIID = 0x%x SAVED_LUN = 0x%x\n",
+ printk("%s: SAVED_SCSIID = 0x%x SAVED_LUN = 0x%x\n",
ahd_name(ahd), ahd_inb(ahd, SAVED_SCSIID),
ahd_inb(ahd, SAVED_LUN));
ahd_simode0_print(ahd_inb(ahd, SIMODE0), &cur_col, 50);
- printf("\n");
+ printk("\n");
ahd_set_modes(ahd, AHD_MODE_CCHAN, AHD_MODE_CCHAN);
cur_col = 0;
ahd_ccscbctl_print(ahd_inb(ahd, CCSCBCTL), &cur_col, 50);
- printf("\n");
+ printk("\n");
ahd_set_modes(ahd, ahd->saved_src_mode, ahd->saved_dst_mode);
- printf("%s: REG0 == 0x%x, SINDEX = 0x%x, DINDEX = 0x%x\n",
+ printk("%s: REG0 == 0x%x, SINDEX = 0x%x, DINDEX = 0x%x\n",
ahd_name(ahd), ahd_inw(ahd, REG0), ahd_inw(ahd, SINDEX),
ahd_inw(ahd, DINDEX));
- printf("%s: SCBPTR == 0x%x, SCB_NEXT == 0x%x, SCB_NEXT2 == 0x%x\n",
+ printk("%s: SCBPTR == 0x%x, SCB_NEXT == 0x%x, SCB_NEXT2 == 0x%x\n",
ahd_name(ahd), ahd_get_scbptr(ahd),
ahd_inw_scbram(ahd, SCB_NEXT),
ahd_inw_scbram(ahd, SCB_NEXT2));
- printf("CDB %x %x %x %x %x %x\n",
+ printk("CDB %x %x %x %x %x %x\n",
ahd_inb_scbram(ahd, SCB_CDB_STORE),
ahd_inb_scbram(ahd, SCB_CDB_STORE+1),
ahd_inb_scbram(ahd, SCB_CDB_STORE+2),
ahd_inb_scbram(ahd, SCB_CDB_STORE+3),
ahd_inb_scbram(ahd, SCB_CDB_STORE+4),
ahd_inb_scbram(ahd, SCB_CDB_STORE+5));
- printf("STACK:");
+ printk("STACK:");
for (i = 0; i < ahd->stack_size; i++) {
ahd->saved_stack[i] =
ahd_inb(ahd, STACK)|(ahd_inb(ahd, STACK) << 8);
- printf(" 0x%x", ahd->saved_stack[i]);
+ printk(" 0x%x", ahd->saved_stack[i]);
}
for (i = ahd->stack_size-1; i >= 0; i--) {
ahd_outb(ahd, STACK, ahd->saved_stack[i] & 0xFF);
ahd_outb(ahd, STACK, (ahd->saved_stack[i] >> 8) & 0xFF);
}
- printf("\n<<<<<<<<<<<<<<<<< Dump Card State Ends >>>>>>>>>>>>>>>>>>\n");
+ printk("\n<<<<<<<<<<<<<<<<< Dump Card State Ends >>>>>>>>>>>>>>>>>>\n");
ahd_restore_modes(ahd, saved_modes);
if (paused == 0)
ahd_unpause(ahd);
@@ -10004,8 +10000,8 @@ ahd_dump_scbs(struct ahd_softc *ahd)
saved_scb_index = ahd_get_scbptr(ahd);
for (i = 0; i < AHD_SCB_MAX; i++) {
ahd_set_scbptr(ahd, i);
- printf("%3d", i);
- printf("(CTRL 0x%x ID 0x%x N 0x%x N2 0x%x SG 0x%x, RSG 0x%x)\n",
+ printk("%3d", i);
+ printk("(CTRL 0x%x ID 0x%x N 0x%x N2 0x%x SG 0x%x, RSG 0x%x)\n",
ahd_inb_scbram(ahd, SCB_CONTROL),
ahd_inb_scbram(ahd, SCB_SCSIID),
ahd_inw_scbram(ahd, SCB_NEXT),
@@ -10013,7 +10009,7 @@ ahd_dump_scbs(struct ahd_softc *ahd)
ahd_inl_scbram(ahd, SCB_SGPTR),
ahd_inl_scbram(ahd, SCB_RESIDUAL_SGPTR));
}
- printf("\n");
+ printk("\n");
ahd_set_scbptr(ahd, saved_scb_index);
ahd_restore_modes(ahd, saved_modes);
}
@@ -10383,7 +10379,7 @@ ahd_handle_en_lun(struct ahd_softc *ahd, struct cam_sim *sim, union ccb *ccb)
&& ccb->ccb_h.target_id != CAM_TARGET_WILDCARD) {
u_long s;
- printf("Configuring Target Mode\n");
+ printk("Configuring Target Mode\n");
ahd_lock(ahd, &s);
if (LIST_FIRST(&ahd->pending_scbs) != NULL) {
ccb->ccb_h.status = CAM_BUSY;
@@ -10412,7 +10408,7 @@ ahd_handle_en_lun(struct ahd_softc *ahd, struct cam_sim *sim, union ccb *ccb)
/* Are we already enabled?? */
if (lstate != NULL) {
xpt_print_path(ccb->ccb_h.path);
- printf("Lun already enabled\n");
+ printk("Lun already enabled\n");
ccb->ccb_h.status = CAM_LUN_ALRDY_ENA;
return;
}
@@ -10424,7 +10420,7 @@ ahd_handle_en_lun(struct ahd_softc *ahd, struct cam_sim *sim, union ccb *ccb)
* specific commands.
*/
ccb->ccb_h.status = CAM_REQ_INVALID;
- printf("Non-zero Group Codes\n");
+ printk("Non-zero Group Codes\n");
return;
}
@@ -10436,15 +10432,15 @@ ahd_handle_en_lun(struct ahd_softc *ahd, struct cam_sim *sim, union ccb *ccb)
tstate = ahd_alloc_tstate(ahd, target, channel);
if (tstate == NULL) {
xpt_print_path(ccb->ccb_h.path);
- printf("Couldn't allocate tstate\n");
+ printk("Couldn't allocate tstate\n");
ccb->ccb_h.status = CAM_RESRC_UNAVAIL;
return;
}
}
- lstate = malloc(sizeof(*lstate), M_DEVBUF, M_NOWAIT);
+ lstate = kmalloc(sizeof(*lstate), GFP_ATOMIC);
if (lstate == NULL) {
xpt_print_path(ccb->ccb_h.path);
- printf("Couldn't allocate lstate\n");
+ printk("Couldn't allocate lstate\n");
ccb->ccb_h.status = CAM_RESRC_UNAVAIL;
return;
}
@@ -10454,9 +10450,9 @@ ahd_handle_en_lun(struct ahd_softc *ahd, struct cam_sim *sim, union ccb *ccb)
xpt_path_target_id(ccb->ccb_h.path),
xpt_path_lun_id(ccb->ccb_h.path));
if (status != CAM_REQ_CMP) {
- free(lstate, M_DEVBUF);
+ kfree(lstate);
xpt_print_path(ccb->ccb_h.path);
- printf("Couldn't allocate path\n");
+ printk("Couldn't allocate path\n");
ccb->ccb_h.status = CAM_RESRC_UNAVAIL;
return;
}
@@ -10524,7 +10520,7 @@ ahd_handle_en_lun(struct ahd_softc *ahd, struct cam_sim *sim, union ccb *ccb)
ahd_unlock(ahd, &s);
ccb->ccb_h.status = CAM_REQ_CMP;
xpt_print_path(ccb->ccb_h.path);
- printf("Lun now enabled for target mode\n");
+ printk("Lun now enabled for target mode\n");
} else {
struct scb *scb;
int i, empty;
@@ -10543,7 +10539,7 @@ ahd_handle_en_lun(struct ahd_softc *ahd, struct cam_sim *sim, union ccb *ccb)
ccbh = &scb->io_ctx->ccb_h;
if (ccbh->func_code == XPT_CONT_TARGET_IO
&& !xpt_path_comp(ccbh->path, ccb->ccb_h.path)){
- printf("CTIO pending\n");
+ printk("CTIO pending\n");
ccb->ccb_h.status = CAM_REQ_INVALID;
ahd_unlock(ahd, &s);
return;
@@ -10551,12 +10547,12 @@ ahd_handle_en_lun(struct ahd_softc *ahd, struct cam_sim *sim, union ccb *ccb)
}
if (SLIST_FIRST(&lstate->accept_tios) != NULL) {
- printf("ATIOs pending\n");
+ printk("ATIOs pending\n");
ccb->ccb_h.status = CAM_REQ_INVALID;
}
if (SLIST_FIRST(&lstate->immed_notifies) != NULL) {
- printf("INOTs pending\n");
+ printk("INOTs pending\n");
ccb->ccb_h.status = CAM_REQ_INVALID;
}
@@ -10566,9 +10562,9 @@ ahd_handle_en_lun(struct ahd_softc *ahd, struct cam_sim *sim, union ccb *ccb)
}
xpt_print_path(ccb->ccb_h.path);
- printf("Target mode disabled\n");
+ printk("Target mode disabled\n");
xpt_free_path(lstate->path);
- free(lstate, M_DEVBUF);
+ kfree(lstate);
ahd_pause(ahd);
/* Can we clean up the target too? */
@@ -10615,7 +10611,7 @@ ahd_handle_en_lun(struct ahd_softc *ahd, struct cam_sim *sim, union ccb *ccb)
ahd_outb(ahd, SCSISEQ1, scsiseq1);
if ((ahd->features & AHD_MULTIROLE) == 0) {
- printf("Configuring Initiator Mode\n");
+ printk("Configuring Initiator Mode\n");
ahd->flags &= ~AHD_TARGETROLE;
ahd->flags |= AHD_INITIATORROLE;
ahd_pause(ahd);
@@ -10749,7 +10745,7 @@ ahd_handle_target_cmd(struct ahd_softc *ahd, struct target_cmd *cmd)
ahd->flags &= ~AHD_TQINFIFO_BLOCKED;
#ifdef AHD_DEBUG
if ((ahd_debug & AHD_SHOW_TQIN) != 0)
- printf("Incoming command from %d for %d:%d%s\n",
+ printk("Incoming command from %d for %d:%d%s\n",
initiator, target, lun,
lstate == ahd->black_hole ? "(Black Holed)" : "");
#endif
@@ -10796,7 +10792,7 @@ ahd_handle_target_cmd(struct ahd_softc *ahd, struct target_cmd *cmd)
default:
/* Only copy the opcode. */
atio->cdb_len = 1;
- printf("Reserved or VU command code type encountered\n");
+ printk("Reserved or VU command code type encountered\n");
break;
}
@@ -10813,7 +10809,7 @@ ahd_handle_target_cmd(struct ahd_softc *ahd, struct target_cmd *cmd)
*/
#ifdef AHD_DEBUG
if ((ahd_debug & AHD_SHOW_TQIN) != 0)
- printf("Received Immediate Command %d:%d:%d - %p\n",
+ printk("Received Immediate Command %d:%d:%d - %p\n",
initiator, target, lun, ahd->pending_device);
#endif
ahd->pending_device = lstate;
diff --git a/drivers/scsi/aic7xxx/aic79xx_osm.c b/drivers/scsi/aic7xxx/aic79xx_osm.c
index 4c41332a354..88ad8482ef5 100644
--- a/drivers/scsi/aic7xxx/aic79xx_osm.c
+++ b/drivers/scsi/aic7xxx/aic79xx_osm.c
@@ -674,7 +674,7 @@ ahd_linux_slave_alloc(struct scsi_device *sdev)
struct ahd_linux_device *dev;
if (bootverbose)
- printf("%s: Slave Alloc %d\n", ahd_name(ahd), sdev->id);
+ printk("%s: Slave Alloc %d\n", ahd_name(ahd), sdev->id);
dev = scsi_transport_device_data(sdev);
memset(dev, 0, sizeof(*dev));
@@ -798,10 +798,10 @@ ahd_linux_dev_reset(struct scsi_cmnd *cmd)
scmd_printk(KERN_INFO, cmd,
"Attempting to queue a TARGET RESET message:");
- printf("CDB:");
+ printk("CDB:");
for (cdb_byte = 0; cdb_byte < cmd->cmd_len; cdb_byte++)
- printf(" 0x%x", cmd->cmnd[cdb_byte]);
- printf("\n");
+ printk(" 0x%x", cmd->cmnd[cdb_byte]);
+ printk("\n");
/*
* Determine if we currently own this command.
@@ -857,16 +857,16 @@ ahd_linux_dev_reset(struct scsi_cmnd *cmd)
ahd->platform_data->eh_done = &done;
ahd_unlock(ahd, &flags);
- printf("%s: Device reset code sleeping\n", ahd_name(ahd));
+ printk("%s: Device reset code sleeping\n", ahd_name(ahd));
if (!wait_for_completion_timeout(&done, 5 * HZ)) {
ahd_lock(ahd, &flags);
ahd->platform_data->eh_done = NULL;
ahd_unlock(ahd, &flags);
- printf("%s: Device reset timer expired (active %d)\n",
+ printk("%s: Device reset timer expired (active %d)\n",
ahd_name(ahd), dev->active);
retval = FAILED;
}
- printf("%s: Device reset returning 0x%x\n", ahd_name(ahd), retval);
+ printk("%s: Device reset returning 0x%x\n", ahd_name(ahd), retval);
return (retval);
}
@@ -884,7 +884,7 @@ ahd_linux_bus_reset(struct scsi_cmnd *cmd)
ahd = *(struct ahd_softc **)cmd->device->host->hostdata;
#ifdef AHD_DEBUG
if ((ahd_debug & AHD_SHOW_RECOVERY) != 0)
- printf("%s: Bus reset called for cmd %p\n",
+ printk("%s: Bus reset called for cmd %p\n",
ahd_name(ahd), cmd);
#endif
ahd_lock(ahd, &flags);
@@ -894,7 +894,7 @@ ahd_linux_bus_reset(struct scsi_cmnd *cmd)
ahd_unlock(ahd, &flags);
if (bootverbose)
- printf("%s: SCSI bus reset delivered. "
+ printk("%s: SCSI bus reset delivered. "
"%d SCBs aborted.\n", ahd_name(ahd), found);
return (SUCCESS);
@@ -935,7 +935,7 @@ ahd_dma_tag_create(struct ahd_softc *ahd, bus_dma_tag_t parent,
{
bus_dma_tag_t dmat;
- dmat = malloc(sizeof(*dmat), M_DEVBUF, M_NOWAIT);
+ dmat = kmalloc(sizeof(*dmat), GFP_ATOMIC);
if (dmat == NULL)
return (ENOMEM);
@@ -956,7 +956,7 @@ ahd_dma_tag_create(struct ahd_softc *ahd, bus_dma_tag_t parent,
void
ahd_dma_tag_destroy(struct ahd_softc *ahd, bus_dma_tag_t dmat)
{
- free(dmat, M_DEVBUF);
+ kfree(dmat);
}
int
@@ -1019,7 +1019,7 @@ ahd_linux_setup_iocell_info(u_long index, int instance, int targ, int32_t value)
iocell_info = (uint8_t*)&aic79xx_iocell_info[instance];
iocell_info[index] = value & 0xFFFF;
if (bootverbose)
- printf("iocell[%d:%ld] = %d\n", instance, index, value);
+ printk("iocell[%d:%ld] = %d\n", instance, index, value);
}
}
@@ -1029,7 +1029,7 @@ ahd_linux_setup_tag_info_global(char *p)
int tags, i, j;
tags = simple_strtoul(p + 1, NULL, 0) & 0xff;
- printf("Setting Global Tags= %d\n", tags);
+ printk("Setting Global Tags= %d\n", tags);
for (i = 0; i < ARRAY_SIZE(aic79xx_tag_info); i++) {
for (j = 0; j < AHD_NUM_TARGETS; j++) {
@@ -1047,7 +1047,7 @@ ahd_linux_setup_tag_info(u_long arg, int instance, int targ, int32_t value)
&& (targ < AHD_NUM_TARGETS)) {
aic79xx_tag_info[instance].tag_commands[targ] = value & 0x1FF;
if (bootverbose)
- printf("tag_info[%d:%d] = %d\n", instance, targ, value);
+ printk("tag_info[%d:%d] = %d\n", instance, targ, value);
}
}
@@ -1088,7 +1088,7 @@ ahd_parse_brace_option(char *opt_name, char *opt_arg, char *end, int depth,
if (targ == -1)
targ = 0;
} else {
- printf("Malformed Option %s\n",
+ printk("Malformed Option %s\n",
opt_name);
done = TRUE;
}
@@ -1246,7 +1246,7 @@ ahd_linux_register_host(struct ahd_softc *ahd, struct scsi_host_template *templa
ahd_set_unit(ahd, ahd_linux_unit++);
ahd_unlock(ahd, &s);
sprintf(buf, "scsi%d", host->host_no);
- new_name = malloc(strlen(buf) + 1, M_DEVBUF, M_NOWAIT);
+ new_name = kmalloc(strlen(buf) + 1, GFP_ATOMIC);
if (new_name != NULL) {
strcpy(new_name, buf);
ahd_set_name(ahd, new_name);
@@ -1322,7 +1322,7 @@ int
ahd_platform_alloc(struct ahd_softc *ahd, void *platform_arg)
{
ahd->platform_data =
- malloc(sizeof(struct ahd_platform_data), M_DEVBUF, M_NOWAIT);
+ kmalloc(sizeof(struct ahd_platform_data), GFP_ATOMIC);
if (ahd->platform_data == NULL)
return (ENOMEM);
memset(ahd->platform_data, 0, sizeof(struct ahd_platform_data));
@@ -1364,7 +1364,7 @@ ahd_platform_free(struct ahd_softc *ahd)
if (ahd->platform_data->host)
scsi_host_put(ahd->platform_data->host);
- free(ahd->platform_data, M_DEVBUF);
+ kfree(ahd->platform_data);
}
}
@@ -1502,7 +1502,7 @@ ahd_linux_user_tagdepth(struct ahd_softc *ahd, struct ahd_devinfo *devinfo)
if (ahd->unit >= ARRAY_SIZE(aic79xx_tag_info)) {
if (warned_user == 0) {
- printf(KERN_WARNING
+ printk(KERN_WARNING
"aic79xx: WARNING: Insufficient tag_info instances\n"
"aic79xx: for installed controllers. Using defaults\n"
"aic79xx: Please update the aic79xx_tag_info array in\n"
@@ -1544,7 +1544,7 @@ ahd_linux_device_queue_depth(struct scsi_device *sdev)
ahd_send_async(ahd, devinfo.channel, devinfo.target,
devinfo.lun, AC_TRANSFER_NEG);
ahd_print_devinfo(ahd, &devinfo);
- printf("Tagged Queuing enabled. Depth %d\n", tags);
+ printk("Tagged Queuing enabled. Depth %d\n", tags);
} else {
ahd_platform_set_tags(ahd, sdev, &devinfo, AHD_QUEUE_NONE);
ahd_send_async(ahd, devinfo.channel, devinfo.target,
@@ -1794,7 +1794,7 @@ ahd_done(struct ahd_softc *ahd, struct scb *scb)
struct ahd_linux_device *dev;
if ((scb->flags & SCB_ACTIVE) == 0) {
- printf("SCB %d done'd twice\n", SCB_GET_TAG(scb));
+ printk("SCB %d done'd twice\n", SCB_GET_TAG(scb));
ahd_dump_card_state(ahd);
panic("Stopping for safety");
}
@@ -1825,7 +1825,7 @@ ahd_done(struct ahd_softc *ahd, struct scb *scb)
#ifdef AHD_DEBUG
if ((ahd_debug & AHD_SHOW_MISC) != 0) {
ahd_print_path(ahd, scb);
- printf("Set CAM_UNCOR_PARITY\n");
+ printk("Set CAM_UNCOR_PARITY\n");
}
#endif
ahd_set_transaction_status(scb, CAM_UNCOR_PARITY);
@@ -1843,12 +1843,12 @@ ahd_done(struct ahd_softc *ahd, struct scb *scb)
u_int i;
ahd_print_path(ahd, scb);
- printf("CDB:");
+ printk("CDB:");
for (i = 0; i < scb->io_ctx->cmd_len; i++)
- printf(" 0x%x", scb->io_ctx->cmnd[i]);
- printf("\n");
+ printk(" 0x%x", scb->io_ctx->cmnd[i]);
+ printk("\n");
ahd_print_path(ahd, scb);
- printf("Saw underflow (%ld of %ld bytes). "
+ printk("Saw underflow (%ld of %ld bytes). "
"Treated as error\n",
ahd_get_residual(scb),
ahd_get_transfer_length(scb));
@@ -1881,7 +1881,7 @@ ahd_done(struct ahd_softc *ahd, struct scb *scb)
dev->commands_since_idle_or_otag = 0;
if ((scb->flags & SCB_RECOVERY_SCB) != 0) {
- printf("Recovery SCB completes\n");
+ printk("Recovery SCB completes\n");
if (ahd_get_transaction_status(scb) == CAM_BDR_SENT
|| ahd_get_transaction_status(scb) == CAM_REQ_ABORTED)
ahd_set_transaction_status(scb, CAM_CMD_TIMEOUT);
@@ -1963,14 +1963,14 @@ ahd_linux_handle_scsi_status(struct ahd_softc *ahd,
if (ahd_debug & AHD_SHOW_SENSE) {
int i;
- printf("Copied %d bytes of sense data at %d:",
+ printk("Copied %d bytes of sense data at %d:",
sense_size, sense_offset);
for (i = 0; i < sense_size; i++) {
if ((i & 0xF) == 0)
- printf("\n");
- printf("0x%x ", cmd->sense_buffer[i]);
+ printk("\n");
+ printk("0x%x ", cmd->sense_buffer[i]);
}
- printf("\n");
+ printk("\n");
}
#endif
}
@@ -1995,7 +1995,7 @@ ahd_linux_handle_scsi_status(struct ahd_softc *ahd,
#ifdef AHD_DEBUG
if ((ahd_debug & AHD_SHOW_QFULL) != 0) {
ahd_print_path(ahd, scb);
- printf("Dropping tag count to %d\n",
+ printk("Dropping tag count to %d\n",
dev->active);
}
#endif
@@ -2014,7 +2014,7 @@ ahd_linux_handle_scsi_status(struct ahd_softc *ahd,
== AHD_LOCK_TAGS_COUNT) {
dev->maxtags = dev->active;
ahd_print_path(ahd, scb);
- printf("Locking max tag count at %d\n",
+ printk("Locking max tag count at %d\n",
dev->active);
}
} else {
@@ -2138,7 +2138,7 @@ ahd_linux_queue_cmd_complete(struct ahd_softc *ahd, struct scsi_cmnd *cmd)
}
if (do_fallback) {
- printf("%s: device overrun (status %x) on %d:%d:%d\n",
+ printk("%s: device overrun (status %x) on %d:%d:%d\n",
ahd_name(ahd), status, cmd->device->channel,
cmd->device->id, cmd->device->lun);
}
@@ -2187,10 +2187,10 @@ ahd_linux_queue_abort_cmd(struct scsi_cmnd *cmd)
scmd_printk(KERN_INFO, cmd,
"Attempting to queue an ABORT message:");
- printf("CDB:");
+ printk("CDB:");
for (cdb_byte = 0; cdb_byte < cmd->cmd_len; cdb_byte++)
- printf(" 0x%x", cmd->cmnd[cdb_byte]);
- printf("\n");
+ printk(" 0x%x", cmd->cmnd[cdb_byte]);
+ printk("\n");
ahd_lock(ahd, &flags);
@@ -2249,7 +2249,7 @@ ahd_linux_queue_abort_cmd(struct scsi_cmnd *cmd)
goto no_cmd;
}
- printf("%s: At time of recovery, card was %spaused\n",
+ printk("%s: At time of recovery, card was %spaused\n",
ahd_name(ahd), was_paused ? "" : "not ");
ahd_dump_card_state(ahd);
@@ -2260,7 +2260,7 @@ ahd_linux_queue_abort_cmd(struct scsi_cmnd *cmd)
pending_scb->hscb->tag,
ROLE_INITIATOR, CAM_REQ_ABORTED,
SEARCH_COMPLETE) > 0) {
- printf("%s:%d:%d:%d: Cmd aborted from QINFIFO\n",
+ printk("%s:%d:%d:%d: Cmd aborted from QINFIFO\n",
ahd_name(ahd), cmd->device->channel,
cmd->device->id, cmd->device->lun);
retval = SUCCESS;
@@ -2355,7 +2355,7 @@ ahd_linux_queue_abort_cmd(struct scsi_cmnd *cmd)
ahd_qinfifo_requeue_tail(ahd, pending_scb);
ahd_set_scbptr(ahd, saved_scbptr);
ahd_print_path(ahd, pending_scb);
- printf("Device is disconnected, re-queuing SCB\n");
+ printk("Device is disconnected, re-queuing SCB\n");
wait = TRUE;
} else {
scmd_printk(KERN_INFO, cmd, "Unable to deliver message\n");
@@ -2380,21 +2380,21 @@ done:
ahd->platform_data->eh_done = &done;
ahd_unlock(ahd, &flags);
- printf("%s: Recovery code sleeping\n", ahd_name(ahd));
+ printk("%s: Recovery code sleeping\n", ahd_name(ahd));
if (!wait_for_completion_timeout(&done, 5 * HZ)) {
ahd_lock(ahd, &flags);
ahd->platform_data->eh_done = NULL;
ahd_unlock(ahd, &flags);
- printf("%s: Timer Expired (active %d)\n",
+ printk("%s: Timer Expired (active %d)\n",
ahd_name(ahd), dev->active);
retval = FAILED;
}
- printf("Recovery code awake\n");
+ printk("Recovery code awake\n");
} else
ahd_unlock(ahd, &flags);
if (retval != SUCCESS)
- printf("%s: Command abort returning 0x%x\n",
+ printk("%s: Command abort returning 0x%x\n",
ahd_name(ahd), retval);
return retval;
@@ -2431,7 +2431,7 @@ static void ahd_linux_set_period(struct scsi_target *starget, int period)
#ifdef AHD_DEBUG
if ((ahd_debug & AHD_SHOW_DV) != 0)
- printf("%s: set period to %d\n", ahd_name(ahd), period);
+ printk("%s: set period to %d\n", ahd_name(ahd), period);
#endif
if (offset == 0)
offset = MAX_OFFSET;
@@ -2484,7 +2484,7 @@ static void ahd_linux_set_offset(struct scsi_target *starget, int offset)
#ifdef AHD_DEBUG
if ((ahd_debug & AHD_SHOW_DV) != 0)
- printf("%s: set offset to %d\n", ahd_name(ahd), offset);
+ printk("%s: set offset to %d\n", ahd_name(ahd), offset);
#endif
ahd_compile_devinfo(&devinfo, shost->this_id, starget->id, 0,
@@ -2520,7 +2520,7 @@ static void ahd_linux_set_dt(struct scsi_target *starget, int dt)
#ifdef AHD_DEBUG
if ((ahd_debug & AHD_SHOW_DV) != 0)
- printf("%s: %s DT\n", ahd_name(ahd),
+ printk("%s: %s DT\n", ahd_name(ahd),
dt ? "enabling" : "disabling");
#endif
if (dt && spi_max_width(starget)) {
@@ -2562,7 +2562,7 @@ static void ahd_linux_set_qas(struct scsi_target *starget, int qas)
#ifdef AHD_DEBUG
if ((ahd_debug & AHD_SHOW_DV) != 0)
- printf("%s: %s QAS\n", ahd_name(ahd),
+ printk("%s: %s QAS\n", ahd_name(ahd),
qas ? "enabling" : "disabling");
#endif
@@ -2601,7 +2601,7 @@ static void ahd_linux_set_iu(struct scsi_target *starget, int iu)
#ifdef AHD_DEBUG
if ((ahd_debug & AHD_SHOW_DV) != 0)
- printf("%s: %s IU\n", ahd_name(ahd),
+ printk("%s: %s IU\n", ahd_name(ahd),
iu ? "enabling" : "disabling");
#endif
@@ -2641,7 +2641,7 @@ static void ahd_linux_set_rd_strm(struct scsi_target *starget, int rdstrm)
#ifdef AHD_DEBUG
if ((ahd_debug & AHD_SHOW_DV) != 0)
- printf("%s: %s Read Streaming\n", ahd_name(ahd),
+ printk("%s: %s Read Streaming\n", ahd_name(ahd),
rdstrm ? "enabling" : "disabling");
#endif
@@ -2677,7 +2677,7 @@ static void ahd_linux_set_wr_flow(struct scsi_target *starget, int wrflow)
#ifdef AHD_DEBUG
if ((ahd_debug & AHD_SHOW_DV) != 0)
- printf("%s: %s Write Flow Control\n", ahd_name(ahd),
+ printk("%s: %s Write Flow Control\n", ahd_name(ahd),
wrflow ? "enabling" : "disabling");
#endif
@@ -2714,14 +2714,14 @@ static void ahd_linux_set_rti(struct scsi_target *starget, int rti)
if ((ahd->features & AHD_RTI) == 0) {
#ifdef AHD_DEBUG
if ((ahd_debug & AHD_SHOW_DV) != 0)
- printf("%s: RTI not available\n", ahd_name(ahd));
+ printk("%s: RTI not available\n", ahd_name(ahd));
#endif
return;
}
#ifdef AHD_DEBUG
if ((ahd_debug & AHD_SHOW_DV) != 0)
- printf("%s: %s RTI\n", ahd_name(ahd),
+ printk("%s: %s RTI\n", ahd_name(ahd),
rti ? "enabling" : "disabling");
#endif
@@ -2757,7 +2757,7 @@ static void ahd_linux_set_pcomp_en(struct scsi_target *starget, int pcomp)
#ifdef AHD_DEBUG
if ((ahd_debug & AHD_SHOW_DV) != 0)
- printf("%s: %s Precompensation\n", ahd_name(ahd),
+ printk("%s: %s Precompensation\n", ahd_name(ahd),
pcomp ? "Enable" : "Disable");
#endif
diff --git a/drivers/scsi/aic7xxx/aic79xx_osm.h b/drivers/scsi/aic7xxx/aic79xx_osm.h
index 55c1fe07969..28e43498cdf 100644
--- a/drivers/scsi/aic7xxx/aic79xx_osm.h
+++ b/drivers/scsi/aic7xxx/aic79xx_osm.h
@@ -363,13 +363,6 @@ struct ahd_platform_data {
resource_size_t mem_busaddr; /* Mem Base Addr */
};
-/************************** OS Utility Wrappers *******************************/
-#define printf printk
-#define M_NOWAIT GFP_ATOMIC
-#define M_WAITOK 0
-#define malloc(size, type, flags) kmalloc(size, flags)
-#define free(ptr, type) kfree(ptr)
-
void ahd_delay(long);
/***************************** Low Level I/O **********************************/
diff --git a/drivers/scsi/aic7xxx/aic79xx_osm_pci.c b/drivers/scsi/aic7xxx/aic79xx_osm_pci.c
index 8f686122d54..3c85873b14b 100644
--- a/drivers/scsi/aic7xxx/aic79xx_osm_pci.c
+++ b/drivers/scsi/aic7xxx/aic79xx_osm_pci.c
@@ -178,7 +178,7 @@ ahd_linux_pci_dev_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
ahd_get_pci_bus(pci),
ahd_get_pci_slot(pci),
ahd_get_pci_function(pci));
- name = malloc(strlen(buf) + 1, M_DEVBUF, M_NOWAIT);
+ name = kmalloc(strlen(buf) + 1, GFP_ATOMIC);
if (name == NULL)
return (-ENOMEM);
strcpy(name, buf);
@@ -333,7 +333,7 @@ ahd_pci_map_registers(struct ahd_softc *ahd)
if (ahd_pci_test_register_access(ahd) != 0) {
- printf("aic79xx: PCI Device %d:%d:%d "
+ printk("aic79xx: PCI Device %d:%d:%d "
"failed memory mapped test. Using PIO.\n",
ahd_get_pci_bus(ahd->dev_softc),
ahd_get_pci_slot(ahd->dev_softc),
@@ -346,7 +346,7 @@ ahd_pci_map_registers(struct ahd_softc *ahd)
} else
command |= PCIM_CMD_MEMEN;
} else if (bootverbose) {
- printf("aic79xx: PCI%d:%d:%d MEM region 0x%llx "
+ printk("aic79xx: PCI%d:%d:%d MEM region 0x%llx "
"unavailable. Cannot memory map device.\n",
ahd_get_pci_bus(ahd->dev_softc),
ahd_get_pci_slot(ahd->dev_softc),
@@ -365,7 +365,7 @@ ahd_pci_map_registers(struct ahd_softc *ahd)
ahd->bshs[1].ioport = (u_long)base2;
command |= PCIM_CMD_PORTEN;
} else {
- printf("aic79xx: PCI%d:%d:%d IO regions 0x%llx and "
+ printk("aic79xx: PCI%d:%d:%d IO regions 0x%llx and "
"0x%llx unavailable. Cannot map device.\n",
ahd_get_pci_bus(ahd->dev_softc),
ahd_get_pci_slot(ahd->dev_softc),
diff --git a/drivers/scsi/aic7xxx/aic79xx_pci.c b/drivers/scsi/aic7xxx/aic79xx_pci.c
index 90a04a37b4f..14b5f8d0e7f 100644
--- a/drivers/scsi/aic7xxx/aic79xx_pci.c
+++ b/drivers/scsi/aic7xxx/aic79xx_pci.c
@@ -338,7 +338,7 @@ ahd_pci_config(struct ahd_softc *ahd, const struct ahd_pci_identity *entry)
*/
if ((ahd->flags & (AHD_39BIT_ADDRESSING|AHD_64BIT_ADDRESSING)) != 0) {
if (bootverbose)
- printf("%s: Enabling 39Bit Addressing\n",
+ printk("%s: Enabling 39Bit Addressing\n",
ahd_name(ahd));
devconfig = ahd_pci_read_config(ahd->dev_softc,
DEVCONFIG, /*bytes*/4);
@@ -528,7 +528,7 @@ ahd_check_extport(struct ahd_softc *ahd)
* Fetch VPD for this function and parse it.
*/
if (bootverbose)
- printf("%s: Reading VPD from SEEPROM...",
+ printk("%s: Reading VPD from SEEPROM...",
ahd_name(ahd));
/* Address is always in units of 16bit words */
@@ -541,12 +541,12 @@ ahd_check_extport(struct ahd_softc *ahd)
if (error == 0)
error = ahd_parse_vpddata(ahd, &vpd);
if (bootverbose)
- printf("%s: VPD parsing %s\n",
+ printk("%s: VPD parsing %s\n",
ahd_name(ahd),
error == 0 ? "successful" : "failed");
if (bootverbose)
- printf("%s: Reading SEEPROM...", ahd_name(ahd));
+ printk("%s: Reading SEEPROM...", ahd_name(ahd));
/* Address is always in units of 16bit words */
start_addr = (sizeof(*sc) / 2) * (ahd->channel - 'A');
@@ -556,16 +556,16 @@ ahd_check_extport(struct ahd_softc *ahd)
/*bytestream*/FALSE);
if (error != 0) {
- printf("Unable to read SEEPROM\n");
+ printk("Unable to read SEEPROM\n");
have_seeprom = 0;
} else {
have_seeprom = ahd_verify_cksum(sc);
if (bootverbose) {
if (have_seeprom == 0)
- printf ("checksum error\n");
+ printk ("checksum error\n");
else
- printf ("done.\n");
+ printk ("done.\n");
}
}
ahd_release_seeprom(ahd);
@@ -615,21 +615,21 @@ ahd_check_extport(struct ahd_softc *ahd)
uint16_t *sc_data;
int i;
- printf("%s: Seeprom Contents:", ahd_name(ahd));
+ printk("%s: Seeprom Contents:", ahd_name(ahd));
sc_data = (uint16_t *)sc;
for (i = 0; i < (sizeof(*sc)); i += 2)
- printf("\n\t0x%.4x", sc_data[i]);
- printf("\n");
+ printk("\n\t0x%.4x", sc_data[i]);
+ printk("\n");
}
#endif
if (!have_seeprom) {
if (bootverbose)
- printf("%s: No SEEPROM available.\n", ahd_name(ahd));
+ printk("%s: No SEEPROM available.\n", ahd_name(ahd));
ahd->flags |= AHD_USEDEFAULTS;
error = ahd_default_config(ahd);
adapter_control = CFAUTOTERM|CFSEAUTOTERM;
- free(ahd->seep_config, M_DEVBUF);
+ kfree(ahd->seep_config);
ahd->seep_config = NULL;
} else {
error = ahd_parse_cfgdata(ahd, sc);
@@ -656,7 +656,7 @@ ahd_configure_termination(struct ahd_softc *ahd, u_int adapter_control)
if ((ahd->flags & AHD_STPWLEVEL_A) != 0)
devconfig |= STPWLEVEL;
if (bootverbose)
- printf("%s: STPWLEVEL is %s\n",
+ printk("%s: STPWLEVEL is %s\n",
ahd_name(ahd), (devconfig & STPWLEVEL) ? "on" : "off");
ahd_pci_write_config(ahd->dev_softc, DEVCONFIG, devconfig, /*bytes*/4);
@@ -671,7 +671,7 @@ ahd_configure_termination(struct ahd_softc *ahd, u_int adapter_control)
error = ahd_read_flexport(ahd, FLXADDR_TERMCTL, &termctl);
if ((adapter_control & CFAUTOTERM) == 0) {
if (bootverbose)
- printf("%s: Manual Primary Termination\n",
+ printk("%s: Manual Primary Termination\n",
ahd_name(ahd));
termctl &= ~(FLX_TERMCTL_ENPRILOW|FLX_TERMCTL_ENPRIHIGH);
if ((adapter_control & CFSTERM) != 0)
@@ -679,14 +679,14 @@ ahd_configure_termination(struct ahd_softc *ahd, u_int adapter_control)
if ((adapter_control & CFWSTERM) != 0)
termctl |= FLX_TERMCTL_ENPRIHIGH;
} else if (error != 0) {
- printf("%s: Primary Auto-Term Sensing failed! "
+ printk("%s: Primary Auto-Term Sensing failed! "
"Using Defaults.\n", ahd_name(ahd));
termctl = FLX_TERMCTL_ENPRILOW|FLX_TERMCTL_ENPRIHIGH;
}
if ((adapter_control & CFSEAUTOTERM) == 0) {
if (bootverbose)
- printf("%s: Manual Secondary Termination\n",
+ printk("%s: Manual Secondary Termination\n",
ahd_name(ahd));
termctl &= ~(FLX_TERMCTL_ENSECLOW|FLX_TERMCTL_ENSECHIGH);
if ((adapter_control & CFSELOWTERM) != 0)
@@ -694,7 +694,7 @@ ahd_configure_termination(struct ahd_softc *ahd, u_int adapter_control)
if ((adapter_control & CFSEHIGHTERM) != 0)
termctl |= FLX_TERMCTL_ENSECHIGH;
} else if (error != 0) {
- printf("%s: Secondary Auto-Term Sensing failed! "
+ printk("%s: Secondary Auto-Term Sensing failed! "
"Using Defaults.\n", ahd_name(ahd));
termctl |= FLX_TERMCTL_ENSECLOW|FLX_TERMCTL_ENSECHIGH;
}
@@ -714,22 +714,22 @@ ahd_configure_termination(struct ahd_softc *ahd, u_int adapter_control)
error = ahd_write_flexport(ahd, FLXADDR_TERMCTL, termctl);
if (error != 0) {
- printf("%s: Unable to set termination settings!\n",
+ printk("%s: Unable to set termination settings!\n",
ahd_name(ahd));
} else if (bootverbose) {
- printf("%s: Primary High byte termination %sabled\n",
+ printk("%s: Primary High byte termination %sabled\n",
ahd_name(ahd),
(termctl & FLX_TERMCTL_ENPRIHIGH) ? "En" : "Dis");
- printf("%s: Primary Low byte termination %sabled\n",
+ printk("%s: Primary Low byte termination %sabled\n",
ahd_name(ahd),
(termctl & FLX_TERMCTL_ENPRILOW) ? "En" : "Dis");
- printf("%s: Secondary High byte termination %sabled\n",
+ printk("%s: Secondary High byte termination %sabled\n",
ahd_name(ahd),
(termctl & FLX_TERMCTL_ENSECHIGH) ? "En" : "Dis");
- printf("%s: Secondary Low byte termination %sabled\n",
+ printk("%s: Secondary Low byte termination %sabled\n",
ahd_name(ahd),
(termctl & FLX_TERMCTL_ENSECLOW) ? "En" : "Dis");
}
@@ -805,7 +805,7 @@ ahd_pci_intr(struct ahd_softc *ahd)
if ((intstat & PCIINT) == 0)
return;
- printf("%s: PCI error Interrupt\n", ahd_name(ahd));
+ printk("%s: PCI error Interrupt\n", ahd_name(ahd));
saved_modes = ahd_save_modes(ahd);
ahd_dump_card_state(ahd);
ahd_set_modes(ahd, AHD_MODE_CFG, AHD_MODE_CFG);
@@ -832,7 +832,7 @@ ahd_pci_intr(struct ahd_softc *ahd)
s = pci_status_strings[bit];
if (i == 7/*TARG*/ && bit == 3)
s = "%s: Signaled Target Abort\n";
- printf(s, ahd_name(ahd), pci_status_source[i]);
+ printk(s, ahd_name(ahd), pci_status_source[i]);
}
}
}
@@ -862,7 +862,7 @@ ahd_pci_split_intr(struct ahd_softc *ahd, u_int intstat)
*/
pcix_status = ahd_pci_read_config(ahd->dev_softc, PCIXR_STATUS,
/*bytes*/2);
- printf("%s: PCI Split Interrupt - PCI-X status = 0x%x\n",
+ printk("%s: PCI Split Interrupt - PCI-X status = 0x%x\n",
ahd_name(ahd), pcix_status);
saved_modes = ahd_save_modes(ahd);
for (i = 0; i < 4; i++) {
@@ -891,7 +891,7 @@ ahd_pci_split_intr(struct ahd_softc *ahd, u_int intstat)
static const char *s;
s = split_status_strings[bit];
- printf(s, ahd_name(ahd),
+ printk(s, ahd_name(ahd),
split_status_source[i]);
}
@@ -902,7 +902,7 @@ ahd_pci_split_intr(struct ahd_softc *ahd, u_int intstat)
static const char *s;
s = split_status_strings[bit];
- printf(s, ahd_name(ahd), "SG");
+ printk(s, ahd_name(ahd), "SG");
}
}
}
@@ -950,7 +950,7 @@ ahd_aic790X_setup(struct ahd_softc *ahd)
pci = ahd->dev_softc;
rev = ahd_pci_read_config(pci, PCIR_REVID, /*bytes*/1);
if (rev < ID_AIC7902_PCI_REV_A4) {
- printf("%s: Unable to attach to unsupported chip revision %d\n",
+ printk("%s: Unable to attach to unsupported chip revision %d\n",
ahd_name(ahd), rev);
ahd_pci_write_config(pci, PCIR_COMMAND, 0, /*bytes*/2);
return (ENXIO);
diff --git a/drivers/scsi/aic7xxx/aic79xx_proc.c b/drivers/scsi/aic7xxx/aic79xx_proc.c
index 014bed716e7..59c85d5a153 100644
--- a/drivers/scsi/aic7xxx/aic79xx_proc.c
+++ b/drivers/scsi/aic7xxx/aic79xx_proc.c
@@ -272,33 +272,32 @@ ahd_proc_write_seeprom(struct ahd_softc *ahd, char *buffer, int length)
saved_modes = ahd_save_modes(ahd);
ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI);
if (length != sizeof(struct seeprom_config)) {
- printf("ahd_proc_write_seeprom: incorrect buffer size\n");
+ printk("ahd_proc_write_seeprom: incorrect buffer size\n");
goto done;
}
have_seeprom = ahd_verify_cksum((struct seeprom_config*)buffer);
if (have_seeprom == 0) {
- printf("ahd_proc_write_seeprom: cksum verification failed\n");
+ printk("ahd_proc_write_seeprom: cksum verification failed\n");
goto done;
}
have_seeprom = ahd_acquire_seeprom(ahd);
if (!have_seeprom) {
- printf("ahd_proc_write_seeprom: No Serial EEPROM\n");
+ printk("ahd_proc_write_seeprom: No Serial EEPROM\n");
goto done;
} else {
u_int start_addr;
if (ahd->seep_config == NULL) {
- ahd->seep_config = malloc(sizeof(*ahd->seep_config),
- M_DEVBUF, M_NOWAIT);
+ ahd->seep_config = kmalloc(sizeof(*ahd->seep_config), GFP_ATOMIC);
if (ahd->seep_config == NULL) {
- printf("aic79xx: Unable to allocate serial "
+ printk("aic79xx: Unable to allocate serial "
"eeprom buffer. Write failing\n");
goto done;
}
}
- printf("aic79xx: Writing Serial EEPROM\n");
+ printk("aic79xx: Writing Serial EEPROM\n");
start_addr = 32 * (ahd->channel - 'A');
ahd_write_seeprom(ahd, (u_int16_t *)buffer, start_addr,
sizeof(struct seeprom_config)/2);
diff --git a/drivers/scsi/aic7xxx/aic7xxx_93cx6.c b/drivers/scsi/aic7xxx/aic7xxx_93cx6.c
index dd11999b77b..9e85a7ef9c8 100644
--- a/drivers/scsi/aic7xxx/aic7xxx_93cx6.c
+++ b/drivers/scsi/aic7xxx/aic7xxx_93cx6.c
@@ -207,14 +207,14 @@ ahc_read_seeprom(struct seeprom_descriptor *sd, uint16_t *buf,
reset_seeprom(sd);
}
#ifdef AHC_DUMP_EEPROM
- printf("\nSerial EEPROM:\n\t");
+ printk("\nSerial EEPROM:\n\t");
for (k = 0; k < count; k = k + 1) {
if (((k % 8) == 0) && (k != 0)) {
- printf ("\n\t");
+ printk(KERN_CONT "\n\t");
}
- printf (" 0x%x", buf[k]);
+ printk(KERN_CONT " 0x%x", buf[k]);
}
- printf ("\n");
+ printk(KERN_CONT "\n");
#endif
return (1);
}
@@ -240,7 +240,7 @@ ahc_write_seeprom(struct seeprom_descriptor *sd, uint16_t *buf,
ewen = &seeprom_long_ewen;
ewds = &seeprom_long_ewds;
} else {
- printf("ahc_write_seeprom: unsupported seeprom type %d\n",
+ printk("ahc_write_seeprom: unsupported seeprom type %d\n",
sd->sd_chip);
return (0);
}
diff --git a/drivers/scsi/aic7xxx/aic7xxx_core.c b/drivers/scsi/aic7xxx/aic7xxx_core.c
index 45aa728a76b..3f5a542a779 100644
--- a/drivers/scsi/aic7xxx/aic7xxx_core.c
+++ b/drivers/scsi/aic7xxx/aic7xxx_core.c
@@ -910,7 +910,7 @@ ahc_run_qoutfifo(struct ahc_softc *ahc)
scb = ahc_lookup_scb(ahc, scb_index);
if (scb == NULL) {
- printf("%s: WARNING no command for scb %d "
+ printk("%s: WARNING no command for scb %d "
"(cmdcmplt)\nQOUTPOS = %d\n",
ahc_name(ahc), scb_index,
(ahc->qoutfifonext - 1) & 0xFF);
@@ -964,7 +964,7 @@ ahc_handle_brkadrint(struct ahc_softc *ahc)
error = ahc_inb(ahc, ERROR);
for (i = 0; error != 1 && i < num_errors; i++)
error >>= 1;
- printf("%s: brkadrint, %s at seqaddr = 0x%x\n",
+ printk("%s: brkadrint, %s at seqaddr = 0x%x\n",
ahc_name(ahc), ahc_hard_errors[i].errmesg,
ahc_inb(ahc, SEQADDR0) |
(ahc_inb(ahc, SEQADDR1) << 8));
@@ -1021,7 +1021,7 @@ ahc_handle_seqint(struct ahc_softc *ahc, u_int intstat)
scb = ahc_lookup_scb(ahc, scb_index);
if (scb == NULL) {
ahc_print_devinfo(ahc, &devinfo);
- printf("ahc_intr - referenced scb "
+ printk("ahc_intr - referenced scb "
"not valid during seqint 0x%x scb(%d)\n",
intstat, scb_index);
ahc_dump_card_state(ahc);
@@ -1049,7 +1049,7 @@ ahc_handle_seqint(struct ahc_softc *ahc, u_int intstat)
ahc_set_scsi_status(scb, hscb->shared_data.status.scsi_status);
switch (hscb->shared_data.status.scsi_status) {
case SCSI_STATUS_OK:
- printf("%s: Interrupted for staus of 0???\n",
+ printk("%s: Interrupted for staus of 0???\n",
ahc_name(ahc));
break;
case SCSI_STATUS_CMD_TERMINATED:
@@ -1063,7 +1063,7 @@ ahc_handle_seqint(struct ahc_softc *ahc, u_int intstat)
#ifdef AHC_DEBUG
if (ahc_debug & AHC_SHOW_SENSE) {
ahc_print_path(ahc, scb);
- printf("SCB %d: requests Check Status\n",
+ printk("SCB %d: requests Check Status\n",
scb->hscb->tag);
}
#endif
@@ -1086,7 +1086,7 @@ ahc_handle_seqint(struct ahc_softc *ahc, u_int intstat)
#ifdef AHC_DEBUG
if (ahc_debug & AHC_SHOW_SENSE) {
ahc_print_path(ahc, scb);
- printf("Sending Sense\n");
+ printk("Sending Sense\n");
}
#endif
sg->addr = ahc_get_sense_bufaddr(ahc, scb);
@@ -1162,29 +1162,29 @@ ahc_handle_seqint(struct ahc_softc *ahc, u_int intstat)
ahc_outb(ahc, SCSISEQ,
ahc_inb(ahc, SCSISEQ) & (ENSELI|ENRSELI|ENAUTOATNP));
- printf("%s:%c:%d: no active SCB for reconnecting "
+ printk("%s:%c:%d: no active SCB for reconnecting "
"target - issuing BUS DEVICE RESET\n",
ahc_name(ahc), devinfo.channel, devinfo.target);
- printf("SAVED_SCSIID == 0x%x, SAVED_LUN == 0x%x, "
+ printk("SAVED_SCSIID == 0x%x, SAVED_LUN == 0x%x, "
"ARG_1 == 0x%x ACCUM = 0x%x\n",
ahc_inb(ahc, SAVED_SCSIID), ahc_inb(ahc, SAVED_LUN),
ahc_inb(ahc, ARG_1), ahc_inb(ahc, ACCUM));
- printf("SEQ_FLAGS == 0x%x, SCBPTR == 0x%x, BTT == 0x%x, "
+ printk("SEQ_FLAGS == 0x%x, SCBPTR == 0x%x, BTT == 0x%x, "
"SINDEX == 0x%x\n",
ahc_inb(ahc, SEQ_FLAGS), ahc_inb(ahc, SCBPTR),
ahc_index_busy_tcl(ahc,
BUILD_TCL(ahc_inb(ahc, SAVED_SCSIID),
ahc_inb(ahc, SAVED_LUN))),
ahc_inb(ahc, SINDEX));
- printf("SCSIID == 0x%x, SCB_SCSIID == 0x%x, SCB_LUN == 0x%x, "
+ printk("SCSIID == 0x%x, SCB_SCSIID == 0x%x, SCB_LUN == 0x%x, "
"SCB_TAG == 0x%x, SCB_CONTROL == 0x%x\n",
ahc_inb(ahc, SCSIID), ahc_inb(ahc, SCB_SCSIID),
ahc_inb(ahc, SCB_LUN), ahc_inb(ahc, SCB_TAG),
ahc_inb(ahc, SCB_CONTROL));
- printf("SCSIBUSL == 0x%x, SCSISIGI == 0x%x\n",
+ printk("SCSIBUSL == 0x%x, SCSISIGI == 0x%x\n",
ahc_inb(ahc, SCSIBUSL), ahc_inb(ahc, SCSISIGI));
- printf("SXFRCTL0 == 0x%x\n", ahc_inb(ahc, SXFRCTL0));
- printf("SEQCTL == 0x%x\n", ahc_inb(ahc, SEQCTL));
+ printk("SXFRCTL0 == 0x%x\n", ahc_inb(ahc, SXFRCTL0));
+ printk("SEQCTL == 0x%x\n", ahc_inb(ahc, SEQCTL));
ahc_dump_card_state(ahc);
ahc->msgout_buf[0] = MSG_BUS_DEV_RESET;
ahc->msgout_len = 1;
@@ -1197,7 +1197,7 @@ ahc_handle_seqint(struct ahc_softc *ahc, u_int intstat)
case SEND_REJECT:
{
u_int rejbyte = ahc_inb(ahc, ACCUM);
- printf("%s:%c:%d: Warning - unknown message received from "
+ printk("%s:%c:%d: Warning - unknown message received from "
"target (0x%x). Rejecting\n",
ahc_name(ahc), devinfo.channel, devinfo.target, rejbyte);
break;
@@ -1218,7 +1218,7 @@ ahc_handle_seqint(struct ahc_softc *ahc, u_int intstat)
u_int lastphase;
lastphase = ahc_inb(ahc, LASTPHASE);
- printf("%s:%c:%d: unknown scsi bus phase %x, "
+ printk("%s:%c:%d: unknown scsi bus phase %x, "
"lastphase = 0x%x. Attempting to continue\n",
ahc_name(ahc), devinfo.channel, devinfo.target,
lastphase, ahc_inb(ahc, SCSISIGI));
@@ -1229,7 +1229,7 @@ ahc_handle_seqint(struct ahc_softc *ahc, u_int intstat)
u_int lastphase;
lastphase = ahc_inb(ahc, LASTPHASE);
- printf("%s:%c:%d: Missed busfree. "
+ printk("%s:%c:%d: Missed busfree. "
"Lastphase = 0x%x, Curphase = 0x%x\n",
ahc_name(ahc), devinfo.channel, devinfo.target,
lastphase, ahc_inb(ahc, SCSISIGI));
@@ -1257,7 +1257,7 @@ ahc_handle_seqint(struct ahc_softc *ahc, u_int intstat)
bus_phase = ahc_inb(ahc, SCSISIGI) & PHASE_MASK;
if (bus_phase != P_MESGIN
&& bus_phase != P_MESGOUT) {
- printf("ahc_intr: HOST_MSG_LOOP bad "
+ printk("ahc_intr: HOST_MSG_LOOP bad "
"phase 0x%x\n",
bus_phase);
/*
@@ -1359,7 +1359,7 @@ ahc_handle_seqint(struct ahc_softc *ahc, u_int intstat)
u_int scb_index;
ahc_print_devinfo(ahc, &devinfo);
- printf("Unable to clear parity error. "
+ printk("Unable to clear parity error. "
"Resetting bus.\n");
scb_index = ahc_inb(ahc, SCB_TAG);
scb = ahc_lookup_scb(ahc, scb_index);
@@ -1395,18 +1395,18 @@ ahc_handle_seqint(struct ahc_softc *ahc, u_int intstat)
break;
}
ahc_print_path(ahc, scb);
- printf("data overrun detected %s."
+ printk("data overrun detected %s."
" Tag == 0x%x.\n",
ahc_phase_table[i].phasemsg,
scb->hscb->tag);
ahc_print_path(ahc, scb);
- printf("%s seen Data Phase. Length = %ld. NumSGs = %d.\n",
+ printk("%s seen Data Phase. Length = %ld. NumSGs = %d.\n",
ahc_inb(ahc, SEQ_FLAGS) & DPHASE ? "Have" : "Haven't",
ahc_get_transfer_length(scb), scb->sg_count);
if (scb->sg_count > 0) {
for (i = 0; i < scb->sg_count; i++) {
- printf("sg[%d] - Addr 0x%x%x : Length %d\n",
+ printk("sg[%d] - Addr 0x%x%x : Length %d\n",
i,
(ahc_le32toh(scb->sg_list[i].len) >> 24
& SG_HIGH_ADDR_BITS),
@@ -1453,7 +1453,7 @@ ahc_handle_seqint(struct ahc_softc *ahc, u_int intstat)
{
u_int scbindex;
- printf("%s:%c:%d:%d: Attempt to issue message failed\n",
+ printk("%s:%c:%d:%d: Attempt to issue message failed\n",
ahc_name(ahc), devinfo.channel, devinfo.target,
devinfo.lun);
scbindex = ahc_inb(ahc, SCB_TAG);
@@ -1473,7 +1473,7 @@ ahc_handle_seqint(struct ahc_softc *ahc, u_int intstat)
}
case NO_FREE_SCB:
{
- printf("%s: No free or disconnected SCBs\n", ahc_name(ahc));
+ printk("%s: No free or disconnected SCBs\n", ahc_name(ahc));
ahc_dump_card_state(ahc);
panic("for safety");
break;
@@ -1483,7 +1483,7 @@ ahc_handle_seqint(struct ahc_softc *ahc, u_int intstat)
u_int scbptr;
scbptr = ahc_inb(ahc, SCBPTR);
- printf("Bogus TAG after DMA. SCBPTR %d, tag %d, our tag %d\n",
+ printk("Bogus TAG after DMA. SCBPTR %d, tag %d, our tag %d\n",
scbptr, ahc_inb(ahc, ARG_1),
ahc->scb_data->hscbs[scbptr].tag);
ahc_dump_card_state(ahc);
@@ -1492,12 +1492,12 @@ ahc_handle_seqint(struct ahc_softc *ahc, u_int intstat)
}
case OUT_OF_RANGE:
{
- printf("%s: BTT calculation out of range\n", ahc_name(ahc));
- printf("SAVED_SCSIID == 0x%x, SAVED_LUN == 0x%x, "
+ printk("%s: BTT calculation out of range\n", ahc_name(ahc));
+ printk("SAVED_SCSIID == 0x%x, SAVED_LUN == 0x%x, "
"ARG_1 == 0x%x ACCUM = 0x%x\n",
ahc_inb(ahc, SAVED_SCSIID), ahc_inb(ahc, SAVED_LUN),
ahc_inb(ahc, ARG_1), ahc_inb(ahc, ACCUM));
- printf("SEQ_FLAGS == 0x%x, SCBPTR == 0x%x, BTT == 0x%x, "
+ printk("SEQ_FLAGS == 0x%x, SCBPTR == 0x%x, BTT == 0x%x, "
"SINDEX == 0x%x\n, A == 0x%x\n",
ahc_inb(ahc, SEQ_FLAGS), ahc_inb(ahc, SCBPTR),
ahc_index_busy_tcl(ahc,
@@ -1505,19 +1505,19 @@ ahc_handle_seqint(struct ahc_softc *ahc, u_int intstat)
ahc_inb(ahc, SAVED_LUN))),
ahc_inb(ahc, SINDEX),
ahc_inb(ahc, ACCUM));
- printf("SCSIID == 0x%x, SCB_SCSIID == 0x%x, SCB_LUN == 0x%x, "
+ printk("SCSIID == 0x%x, SCB_SCSIID == 0x%x, SCB_LUN == 0x%x, "
"SCB_TAG == 0x%x, SCB_CONTROL == 0x%x\n",
ahc_inb(ahc, SCSIID), ahc_inb(ahc, SCB_SCSIID),
ahc_inb(ahc, SCB_LUN), ahc_inb(ahc, SCB_TAG),
ahc_inb(ahc, SCB_CONTROL));
- printf("SCSIBUSL == 0x%x, SCSISIGI == 0x%x\n",
+ printk("SCSIBUSL == 0x%x, SCSISIGI == 0x%x\n",
ahc_inb(ahc, SCSIBUSL), ahc_inb(ahc, SCSISIGI));
ahc_dump_card_state(ahc);
panic("for safety");
break;
}
default:
- printf("ahc_intr: seqint, "
+ printk("ahc_intr: seqint, "
"intstat == 0x%x, scsisigi = 0x%x\n",
intstat, ahc_inb(ahc, SCSISIGI));
break;
@@ -1562,7 +1562,7 @@ ahc_handle_scsiint(struct ahc_softc *ahc, u_int intstat)
intr_channel = (cur_channel == 'A') ? 'B' : 'A';
}
if (status == 0) {
- printf("%s: Spurious SCSI interrupt\n", ahc_name(ahc));
+ printk("%s: Spurious SCSI interrupt\n", ahc_name(ahc));
ahc_outb(ahc, CLRINT, CLRSCSIINT);
ahc_unpause(ahc);
return;
@@ -1583,7 +1583,7 @@ ahc_handle_scsiint(struct ahc_softc *ahc, u_int intstat)
int now_lvd;
now_lvd = ahc_inb(ahc, SBLKCTL) & ENAB40;
- printf("%s: Transceiver State Has Changed to %s mode\n",
+ printk("%s: Transceiver State Has Changed to %s mode\n",
ahc_name(ahc), now_lvd ? "LVD" : "SE");
ahc_outb(ahc, CLRSINT0, CLRIOERR);
/*
@@ -1599,7 +1599,7 @@ ahc_handle_scsiint(struct ahc_softc *ahc, u_int intstat)
ahc_reset_channel(ahc, intr_channel,
/*Initiate Reset*/now_lvd == 0);
} else if ((status & SCSIRSTI) != 0) {
- printf("%s: Someone reset channel %c\n",
+ printk("%s: Someone reset channel %c\n",
ahc_name(ahc), intr_channel);
if (intr_channel != cur_channel)
ahc_outb(ahc, SBLKCTL, ahc_inb(ahc, SBLKCTL) ^ SELBUSB);
@@ -1659,26 +1659,26 @@ ahc_handle_scsiint(struct ahc_softc *ahc, u_int intstat)
ahc_print_path(ahc, scb);
scb->flags |= SCB_TRANSMISSION_ERROR;
} else
- printf("%s:%c:%d: ", ahc_name(ahc), intr_channel,
+ printk("%s:%c:%d: ", ahc_name(ahc), intr_channel,
SCSIID_TARGET(ahc, ahc_inb(ahc, SAVED_SCSIID)));
scsirate = ahc_inb(ahc, SCSIRATE);
if (silent == FALSE) {
- printf("parity error detected %s. "
+ printk("parity error detected %s. "
"SEQADDR(0x%x) SCSIRATE(0x%x)\n",
ahc_phase_table[i].phasemsg,
ahc_inw(ahc, SEQADDR0),
scsirate);
if ((ahc->features & AHC_DT) != 0) {
if ((sstat2 & CRCVALERR) != 0)
- printf("\tCRC Value Mismatch\n");
+ printk("\tCRC Value Mismatch\n");
if ((sstat2 & CRCENDERR) != 0)
- printf("\tNo terminal CRC packet "
+ printk("\tNo terminal CRC packet "
"recevied\n");
if ((sstat2 & CRCREQERR) != 0)
- printf("\tIllegal CRC packet "
+ printk("\tIllegal CRC packet "
"request\n");
if ((sstat2 & DUAL_EDGE_ERR) != 0)
- printf("\tUnexpected %sDT Data Phase\n",
+ printk("\tUnexpected %sDT Data Phase\n",
(scsirate & SINGLE_EDGE)
? "" : "non-");
}
@@ -1746,7 +1746,7 @@ ahc_handle_scsiint(struct ahc_softc *ahc, u_int intstat)
scb = ahc_lookup_scb(ahc, scb_index);
if (scb == NULL) {
- printf("%s: ahc_intr - referenced scb not "
+ printk("%s: ahc_intr - referenced scb not "
"valid during SELTO scb(%d, %d)\n",
ahc_name(ahc), scbptr, scb_index);
ahc_dump_card_state(ahc);
@@ -1755,7 +1755,7 @@ ahc_handle_scsiint(struct ahc_softc *ahc, u_int intstat)
#ifdef AHC_DEBUG
if ((ahc_debug & AHC_SHOW_SELTO) != 0) {
ahc_print_path(ahc, scb);
- printf("Saw Selection Timeout for SCB 0x%x\n",
+ printk("Saw Selection Timeout for SCB 0x%x\n",
scb_index);
}
#endif
@@ -1831,7 +1831,7 @@ ahc_handle_scsiint(struct ahc_softc *ahc, u_int intstat)
== MSG_ABORT_TAG)
tag = scb->hscb->tag;
ahc_print_path(ahc, scb);
- printf("SCB %d - Abort%s Completed.\n",
+ printk("SCB %d - Abort%s Completed.\n",
scb->hscb->tag, tag == SCB_LIST_NULL ?
"" : " Tag");
ahc_abort_scbs(ahc, target, channel,
@@ -1934,7 +1934,7 @@ ahc_handle_scsiint(struct ahc_softc *ahc, u_int intstat)
* We had not fully identified this connection,
* so we cannot abort anything.
*/
- printf("%s: ", ahc_name(ahc));
+ printk("%s: ", ahc_name(ahc));
}
for (i = 0; i < num_phases; i++) {
if (lastphase == ahc_phase_table[i].phase)
@@ -1949,7 +1949,7 @@ ahc_handle_scsiint(struct ahc_softc *ahc, u_int intstat)
*/
ahc_force_renegotiation(ahc, &devinfo);
}
- printf("Unexpected busfree %s\n"
+ printk("Unexpected busfree %s\n"
"SEQADDR == 0x%x\n",
ahc_phase_table[i].phasemsg,
ahc_inb(ahc, SEQADDR0)
@@ -1958,7 +1958,7 @@ ahc_handle_scsiint(struct ahc_softc *ahc, u_int intstat)
ahc_outb(ahc, CLRINT, CLRSCSIINT);
ahc_restart(ahc);
} else {
- printf("%s: Missing case in ahc_handle_scsiint. status = %x\n",
+ printk("%s: Missing case in ahc_handle_scsiint. status = %x\n",
ahc_name(ahc), status);
ahc_outb(ahc, CLRINT, CLRSCSIINT);
}
@@ -2025,7 +2025,7 @@ ahc_clear_critical_section(struct ahc_softc *ahc)
break;
if (steps > AHC_MAX_STEPS) {
- printf("%s: Infinite loop in critical section\n",
+ printk("%s: Infinite loop in critical section\n",
ahc_name(ahc));
ahc_dump_card_state(ahc);
panic("critical section loop");
@@ -2104,23 +2104,23 @@ ahc_print_scb(struct scb *scb)
struct hardware_scb *hscb = scb->hscb;
- printf("scb:%p control:0x%x scsiid:0x%x lun:%d cdb_len:%d\n",
+ printk("scb:%p control:0x%x scsiid:0x%x lun:%d cdb_len:%d\n",
(void *)scb,
hscb->control,
hscb->scsiid,
hscb->lun,
hscb->cdb_len);
- printf("Shared Data: ");
+ printk("Shared Data: ");
for (i = 0; i < sizeof(hscb->shared_data.cdb); i++)
- printf("%#02x", hscb->shared_data.cdb[i]);
- printf(" dataptr:%#x datacnt:%#x sgptr:%#x tag:%#x\n",
+ printk("%#02x", hscb->shared_data.cdb[i]);
+ printk(" dataptr:%#x datacnt:%#x sgptr:%#x tag:%#x\n",
ahc_le32toh(hscb->dataptr),
ahc_le32toh(hscb->datacnt),
ahc_le32toh(hscb->sgptr),
hscb->tag);
if (scb->sg_count > 0) {
for (i = 0; i < scb->sg_count; i++) {
- printf("sg[%d] - Addr 0x%x%x : Length %d\n",
+ printk("sg[%d] - Addr 0x%x%x : Length %d\n",
i,
(ahc_le32toh(scb->sg_list[i].len) >> 24
& SG_HIGH_ADDR_BITS),
@@ -2152,8 +2152,7 @@ ahc_alloc_tstate(struct ahc_softc *ahc, u_int scsi_id, char channel)
&& ahc->enabled_targets[scsi_id] != master_tstate)
panic("%s: ahc_alloc_tstate - Target already allocated",
ahc_name(ahc));
- tstate = (struct ahc_tmode_tstate*)malloc(sizeof(*tstate),
- M_DEVBUF, M_NOWAIT);
+ tstate = kmalloc(sizeof(*tstate), GFP_ATOMIC);
if (tstate == NULL)
return (NULL);
@@ -2202,7 +2201,7 @@ ahc_free_tstate(struct ahc_softc *ahc, u_int scsi_id, char channel, int force)
scsi_id += 8;
tstate = ahc->enabled_targets[scsi_id];
if (tstate != NULL)
- free(tstate, M_DEVBUF);
+ kfree(tstate);
ahc->enabled_targets[scsi_id] = NULL;
}
#endif
@@ -2589,13 +2588,13 @@ ahc_set_syncrate(struct ahc_softc *ahc, struct ahc_devinfo *devinfo,
CAM_LUN_WILDCARD, AC_TRANSFER_NEG);
if (bootverbose) {
if (offset != 0) {
- printf("%s: target %d synchronous at %sMHz%s, "
+ printk("%s: target %d synchronous at %sMHz%s, "
"offset = 0x%x\n", ahc_name(ahc),
devinfo->target, syncrate->rate,
(ppr_options & MSG_EXT_PPR_DT_REQ)
? " DT" : "", offset);
} else {
- printf("%s: target %d using "
+ printk("%s: target %d using "
"asynchronous transfers\n",
ahc_name(ahc), devinfo->target);
}
@@ -2658,7 +2657,7 @@ ahc_set_width(struct ahc_softc *ahc, struct ahc_devinfo *devinfo,
ahc_send_async(ahc, devinfo->channel, devinfo->target,
CAM_LUN_WILDCARD, AC_TRANSFER_NEG);
if (bootverbose) {
- printf("%s: target %d using %dbit transfers\n",
+ printk("%s: target %d using %dbit transfers\n",
ahc_name(ahc), devinfo->target,
8 * (0x01 << width));
}
@@ -2835,7 +2834,7 @@ ahc_compile_devinfo(struct ahc_devinfo *devinfo, u_int our_id, u_int target,
void
ahc_print_devinfo(struct ahc_softc *ahc, struct ahc_devinfo *devinfo)
{
- printf("%s:%c:%d:%d: ", ahc_name(ahc), devinfo->channel,
+ printk("%s:%c:%d:%d: ", ahc_name(ahc), devinfo->channel,
devinfo->target, devinfo->lun);
}
@@ -2907,7 +2906,7 @@ ahc_setup_initiator_msgout(struct ahc_softc *ahc, struct ahc_devinfo *devinfo,
ahc->msgout_buf[ahc->msgout_index++] = MSG_BUS_DEV_RESET;
ahc->msgout_len++;
ahc_print_path(ahc, scb);
- printf("Bus Device Reset Message Sent\n");
+ printk("Bus Device Reset Message Sent\n");
/*
* Clear our selection hardware in advance of
* the busfree. We may have an entry in the waiting
@@ -2923,7 +2922,7 @@ ahc_setup_initiator_msgout(struct ahc_softc *ahc, struct ahc_devinfo *devinfo,
ahc->msgout_buf[ahc->msgout_index++] = MSG_ABORT;
ahc->msgout_len++;
ahc_print_path(ahc, scb);
- printf("Abort%s Message Sent\n",
+ printk("Abort%s Message Sent\n",
(scb->hscb->control & TAG_ENB) != 0 ? " Tag" : "");
/*
* Clear our selection hardware in advance of
@@ -2936,9 +2935,9 @@ ahc_setup_initiator_msgout(struct ahc_softc *ahc, struct ahc_devinfo *devinfo,
} else if ((scb->flags & (SCB_AUTO_NEGOTIATE|SCB_NEGOTIATE)) != 0) {
ahc_build_transfer_msg(ahc, devinfo);
} else {
- printf("ahc_intr: AWAITING_MSG for an SCB that "
+ printk("ahc_intr: AWAITING_MSG for an SCB that "
"does not have a waiting message\n");
- printf("SCSIID = %x, target_mask = %x\n", scb->hscb->scsiid,
+ printk("SCSIID = %x, target_mask = %x\n", scb->hscb->scsiid,
devinfo->target_mask);
panic("SCB = %d, SCB Control = %x, MSG_OUT = %x "
"SCB flags = %x", scb->hscb->tag, scb->hscb->control,
@@ -3019,7 +3018,7 @@ ahc_build_transfer_msg(struct ahc_softc *ahc, struct ahc_devinfo *devinfo)
if (bootverbose) {
ahc_print_devinfo(ahc, devinfo);
- printf("Ensuring async\n");
+ printk("Ensuring async\n");
}
}
@@ -3067,7 +3066,7 @@ ahc_construct_sdtr(struct ahc_softc *ahc, struct ahc_devinfo *devinfo,
ahc->msgout_buf + ahc->msgout_index, period, offset);
ahc->msgout_len += 5;
if (bootverbose) {
- printf("(%s:%c:%d:%d): Sending SDTR period %x, offset %x\n",
+ printk("(%s:%c:%d:%d): Sending SDTR period %x, offset %x\n",
ahc_name(ahc), devinfo->channel, devinfo->target,
devinfo->lun, period, offset);
}
@@ -3085,7 +3084,7 @@ ahc_construct_wdtr(struct ahc_softc *ahc, struct ahc_devinfo *devinfo,
ahc->msgout_buf + ahc->msgout_index, bus_width);
ahc->msgout_len += 4;
if (bootverbose) {
- printf("(%s:%c:%d:%d): Sending WDTR %x\n",
+ printk("(%s:%c:%d:%d): Sending WDTR %x\n",
ahc_name(ahc), devinfo->channel, devinfo->target,
devinfo->lun, bus_width);
}
@@ -3107,7 +3106,7 @@ ahc_construct_ppr(struct ahc_softc *ahc, struct ahc_devinfo *devinfo,
bus_width, ppr_options);
ahc->msgout_len += 8;
if (bootverbose) {
- printf("(%s:%c:%d:%d): Sending PPR bus_width %x, period %x, "
+ printk("(%s:%c:%d:%d): Sending PPR bus_width %x, period %x, "
"offset %x, ppr_options %x\n", ahc_name(ahc),
devinfo->channel, devinfo->target, devinfo->lun,
bus_width, period, offset, ppr_options);
@@ -3160,7 +3159,7 @@ ahc_handle_proto_violation(struct ahc_softc *ahc)
* to match.
*/
ahc_print_devinfo(ahc, &devinfo);
- printf("Target did not send an IDENTIFY message. "
+ printk("Target did not send an IDENTIFY message. "
"LASTPHASE = 0x%x.\n", lastphase);
scb = NULL;
} else if (scb == NULL) {
@@ -3169,13 +3168,13 @@ ahc_handle_proto_violation(struct ahc_softc *ahc)
* transaction. Print an error and reset the bus.
*/
ahc_print_devinfo(ahc, &devinfo);
- printf("No SCB found during protocol violation\n");
+ printk("No SCB found during protocol violation\n");
goto proto_violation_reset;
} else {
ahc_set_transaction_status(scb, CAM_SEQUENCE_FAIL);
if ((seq_flags & NO_CDB_SENT) != 0) {
ahc_print_path(ahc, scb);
- printf("No or incomplete CDB sent to device.\n");
+ printk("No or incomplete CDB sent to device.\n");
} else if ((ahc_inb(ahc, SCB_CONTROL) & STATUS_RCVD) == 0) {
/*
* The target never bothered to provide status to
@@ -3185,10 +3184,10 @@ ahc_handle_proto_violation(struct ahc_softc *ahc)
* message.
*/
ahc_print_path(ahc, scb);
- printf("Completed command without status.\n");
+ printk("Completed command without status.\n");
} else {
ahc_print_path(ahc, scb);
- printf("Unknown protocol violation.\n");
+ printk("Unknown protocol violation.\n");
ahc_dump_card_state(ahc);
}
}
@@ -3202,7 +3201,7 @@ proto_violation_reset:
* it away with a bus reset.
*/
found = ahc_reset_channel(ahc, 'A', TRUE);
- printf("%s: Issued Channel %c Bus Reset. "
+ printk("%s: Issued Channel %c Bus Reset. "
"%d SCBs aborted\n", ahc_name(ahc), 'A', found);
} else {
/*
@@ -3224,7 +3223,7 @@ proto_violation_reset:
ahc_print_path(ahc, scb);
scb->flags |= SCB_ABORT;
}
- printf("Protocol violation %s. Attempting to abort.\n",
+ printk("Protocol violation %s. Attempting to abort.\n",
ahc_lookup_phase_entry(curphase)->phasemsg);
}
}
@@ -3257,14 +3256,14 @@ reswitch:
#ifdef AHC_DEBUG
if ((ahc_debug & AHC_SHOW_MESSAGES) != 0) {
ahc_print_devinfo(ahc, &devinfo);
- printf("INITIATOR_MSG_OUT");
+ printk("INITIATOR_MSG_OUT");
}
#endif
phasemis = bus_phase != P_MESGOUT;
if (phasemis) {
#ifdef AHC_DEBUG
if ((ahc_debug & AHC_SHOW_MESSAGES) != 0) {
- printf(" PHASEMIS %s\n",
+ printk(" PHASEMIS %s\n",
ahc_lookup_phase_entry(bus_phase)
->phasemsg);
}
@@ -3291,7 +3290,7 @@ reswitch:
ahc_outb(ahc, CLRSINT1, CLRREQINIT);
#ifdef AHC_DEBUG
if ((ahc_debug & AHC_SHOW_MESSAGES) != 0)
- printf(" byte 0x%x\n", ahc->send_msg_perror);
+ printk(" byte 0x%x\n", ahc->send_msg_perror);
#endif
ahc_outb(ahc, SCSIDATL, MSG_PARITY_ERROR);
break;
@@ -3321,7 +3320,7 @@ reswitch:
ahc_outb(ahc, CLRSINT1, CLRREQINIT);
#ifdef AHC_DEBUG
if ((ahc_debug & AHC_SHOW_MESSAGES) != 0)
- printf(" byte 0x%x\n",
+ printk(" byte 0x%x\n",
ahc->msgout_buf[ahc->msgout_index]);
#endif
ahc_outb(ahc, SCSIDATL, ahc->msgout_buf[ahc->msgout_index++]);
@@ -3335,14 +3334,14 @@ reswitch:
#ifdef AHC_DEBUG
if ((ahc_debug & AHC_SHOW_MESSAGES) != 0) {
ahc_print_devinfo(ahc, &devinfo);
- printf("INITIATOR_MSG_IN");
+ printk("INITIATOR_MSG_IN");
}
#endif
phasemis = bus_phase != P_MESGIN;
if (phasemis) {
#ifdef AHC_DEBUG
if ((ahc_debug & AHC_SHOW_MESSAGES) != 0) {
- printf(" PHASEMIS %s\n",
+ printk(" PHASEMIS %s\n",
ahc_lookup_phase_entry(bus_phase)
->phasemsg);
}
@@ -3363,7 +3362,7 @@ reswitch:
ahc->msgin_buf[ahc->msgin_index] = ahc_inb(ahc, SCSIBUSL);
#ifdef AHC_DEBUG
if ((ahc_debug & AHC_SHOW_MESSAGES) != 0)
- printf(" byte 0x%x\n",
+ printk(" byte 0x%x\n",
ahc->msgin_buf[ahc->msgin_index]);
#endif
@@ -3385,7 +3384,7 @@ reswitch:
#ifdef AHC_DEBUG
if ((ahc_debug & AHC_SHOW_MESSAGES) != 0) {
ahc_print_devinfo(ahc, &devinfo);
- printf("Asserting ATN for response\n");
+ printk("Asserting ATN for response\n");
}
#endif
ahc_assert_atn(ahc);
@@ -3666,7 +3665,7 @@ ahc_parse_msg(struct ahc_softc *ahc, struct ahc_devinfo *devinfo)
targ_scsirate & WIDEXFER,
devinfo->role);
if (bootverbose) {
- printf("(%s:%c:%d:%d): Received "
+ printk("(%s:%c:%d:%d): Received "
"SDTR period %x, offset %x\n\t"
"Filtered to period %x, offset %x\n",
ahc_name(ahc), devinfo->channel,
@@ -3697,7 +3696,7 @@ ahc_parse_msg(struct ahc_softc *ahc, struct ahc_devinfo *devinfo)
*/
if (bootverbose
&& devinfo->role == ROLE_INITIATOR) {
- printf("(%s:%c:%d:%d): Target "
+ printk("(%s:%c:%d:%d): Target "
"Initiated SDTR\n",
ahc_name(ahc), devinfo->channel,
devinfo->target, devinfo->lun);
@@ -3739,7 +3738,7 @@ ahc_parse_msg(struct ahc_softc *ahc, struct ahc_devinfo *devinfo)
ahc_validate_width(ahc, tinfo, &bus_width,
devinfo->role);
if (bootverbose) {
- printf("(%s:%c:%d:%d): Received WDTR "
+ printk("(%s:%c:%d:%d): Received WDTR "
"%x filtered to %x\n",
ahc_name(ahc), devinfo->channel,
devinfo->target, devinfo->lun,
@@ -3755,7 +3754,7 @@ ahc_parse_msg(struct ahc_softc *ahc, struct ahc_devinfo *devinfo)
*/
if (saved_width > bus_width) {
reject = TRUE;
- printf("(%s:%c:%d:%d): requested %dBit "
+ printk("(%s:%c:%d:%d): requested %dBit "
"transfers. Rejecting...\n",
ahc_name(ahc), devinfo->channel,
devinfo->target, devinfo->lun,
@@ -3768,7 +3767,7 @@ ahc_parse_msg(struct ahc_softc *ahc, struct ahc_devinfo *devinfo)
*/
if (bootverbose
&& devinfo->role == ROLE_INITIATOR) {
- printf("(%s:%c:%d:%d): Target "
+ printk("(%s:%c:%d:%d): Target "
"Initiated WDTR\n",
ahc_name(ahc), devinfo->channel,
devinfo->target, devinfo->lun);
@@ -3886,12 +3885,12 @@ ahc_parse_msg(struct ahc_softc *ahc, struct ahc_devinfo *devinfo)
}
} else {
if (devinfo->role != ROLE_TARGET)
- printf("(%s:%c:%d:%d): Target "
+ printk("(%s:%c:%d:%d): Target "
"Initiated PPR\n",
ahc_name(ahc), devinfo->channel,
devinfo->target, devinfo->lun);
else
- printf("(%s:%c:%d:%d): Initiator "
+ printk("(%s:%c:%d:%d): Initiator "
"Initiated PPR\n",
ahc_name(ahc), devinfo->channel,
devinfo->target, devinfo->lun);
@@ -3903,7 +3902,7 @@ ahc_parse_msg(struct ahc_softc *ahc, struct ahc_devinfo *devinfo)
response = TRUE;
}
if (bootverbose) {
- printf("(%s:%c:%d:%d): Received PPR width %x, "
+ printk("(%s:%c:%d:%d): Received PPR width %x, "
"period %x, offset %x,options %x\n"
"\tFiltered to width %x, period %x, "
"offset %x, options %x\n",
@@ -4033,7 +4032,7 @@ ahc_handle_msg_reject(struct ahc_softc *ahc, struct ahc_devinfo *devinfo)
* Attempt to negotiate SPI-2 style.
*/
if (bootverbose) {
- printf("(%s:%c:%d:%d): PPR Rejected. "
+ printk("(%s:%c:%d:%d): PPR Rejected. "
"Trying WDTR/SDTR\n",
ahc_name(ahc), devinfo->channel,
devinfo->target, devinfo->lun);
@@ -4049,7 +4048,7 @@ ahc_handle_msg_reject(struct ahc_softc *ahc, struct ahc_devinfo *devinfo)
} else if (ahc_sent_msg(ahc, AHCMSG_EXT, MSG_EXT_WDTR, /*full*/FALSE)) {
/* note 8bit xfers */
- printf("(%s:%c:%d:%d): refuses WIDE negotiation. Using "
+ printk("(%s:%c:%d:%d): refuses WIDE negotiation. Using "
"8bit transfers\n", ahc_name(ahc),
devinfo->channel, devinfo->target, devinfo->lun);
ahc_set_width(ahc, devinfo, MSG_EXT_WDTR_BUS_8_BIT,
@@ -4077,7 +4076,7 @@ ahc_handle_msg_reject(struct ahc_softc *ahc, struct ahc_devinfo *devinfo)
/*offset*/0, /*ppr_options*/0,
AHC_TRANS_ACTIVE|AHC_TRANS_GOAL,
/*paused*/TRUE);
- printf("(%s:%c:%d:%d): refuses synchronous negotiation. "
+ printk("(%s:%c:%d:%d): refuses synchronous negotiation. "
"Using asynchronous transfers\n",
ahc_name(ahc), devinfo->channel,
devinfo->target, devinfo->lun);
@@ -4088,13 +4087,13 @@ ahc_handle_msg_reject(struct ahc_softc *ahc, struct ahc_devinfo *devinfo)
tag_type = (scb->hscb->control & MSG_SIMPLE_TASK);
if (tag_type == MSG_SIMPLE_TASK) {
- printf("(%s:%c:%d:%d): refuses tagged commands. "
+ printk("(%s:%c:%d:%d): refuses tagged commands. "
"Performing non-tagged I/O\n", ahc_name(ahc),
devinfo->channel, devinfo->target, devinfo->lun);
ahc_set_tags(ahc, scb->io_ctx, devinfo, AHC_QUEUE_NONE);
mask = ~0x23;
} else {
- printf("(%s:%c:%d:%d): refuses %s tagged commands. "
+ printk("(%s:%c:%d:%d): refuses %s tagged commands. "
"Performing simple queue tagged I/O only\n",
ahc_name(ahc), devinfo->channel, devinfo->target,
devinfo->lun, tag_type == MSG_ORDERED_TASK
@@ -4144,7 +4143,7 @@ ahc_handle_msg_reject(struct ahc_softc *ahc, struct ahc_devinfo *devinfo)
/*
* Otherwise, we ignore it.
*/
- printf("%s:%c:%d: Message reject for %x -- ignored\n",
+ printk("%s:%c:%d: Message reject for %x -- ignored\n",
ahc_name(ahc), devinfo->channel, devinfo->target,
last_msg);
}
@@ -4369,7 +4368,7 @@ ahc_handle_devreset(struct ahc_softc *ahc, struct ahc_devinfo *devinfo,
if (message != NULL
&& (verbose_level <= bootverbose))
- printf("%s: %s on %c:%d. %d SCBs aborted\n", ahc_name(ahc),
+ printk("%s: %s on %c:%d. %d SCBs aborted\n", ahc_name(ahc),
message, devinfo->channel, devinfo->target, found);
}
@@ -4408,23 +4407,22 @@ ahc_alloc(void *platform_arg, char *name)
int i;
#ifndef __FreeBSD__
- ahc = malloc(sizeof(*ahc), M_DEVBUF, M_NOWAIT);
+ ahc = kmalloc(sizeof(*ahc), GFP_ATOMIC);
if (!ahc) {
- printf("aic7xxx: cannot malloc softc!\n");
- free(name, M_DEVBUF);
+ printk("aic7xxx: cannot malloc softc!\n");
+ kfree(name);
return NULL;
}
#else
ahc = device_get_softc((device_t)platform_arg);
#endif
memset(ahc, 0, sizeof(*ahc));
- ahc->seep_config = malloc(sizeof(*ahc->seep_config),
- M_DEVBUF, M_NOWAIT);
+ ahc->seep_config = kmalloc(sizeof(*ahc->seep_config), GFP_ATOMIC);
if (ahc->seep_config == NULL) {
#ifndef __FreeBSD__
- free(ahc, M_DEVBUF);
+ kfree(ahc);
#endif
- free(name, M_DEVBUF);
+ kfree(name);
return (NULL);
}
LIST_INIT(&ahc->pending_scbs);
@@ -4466,8 +4464,7 @@ ahc_softc_init(struct ahc_softc *ahc)
ahc->pause = ahc->unpause | PAUSE;
/* XXX The shared scb data stuff should be deprecated */
if (ahc->scb_data == NULL) {
- ahc->scb_data = malloc(sizeof(*ahc->scb_data),
- M_DEVBUF, M_NOWAIT);
+ ahc->scb_data = kmalloc(sizeof(*ahc->scb_data), GFP_ATOMIC);
if (ahc->scb_data == NULL)
return (ENOMEM);
memset(ahc->scb_data, 0, sizeof(*ahc->scb_data));
@@ -4486,7 +4483,7 @@ void
ahc_set_name(struct ahc_softc *ahc, char *name)
{
if (ahc->name != NULL)
- free(ahc->name, M_DEVBUF);
+ kfree(ahc->name);
ahc->name = name;
}
@@ -4540,25 +4537,25 @@ ahc_free(struct ahc_softc *ahc)
lstate = tstate->enabled_luns[j];
if (lstate != NULL) {
xpt_free_path(lstate->path);
- free(lstate, M_DEVBUF);
+ kfree(lstate);
}
}
#endif
- free(tstate, M_DEVBUF);
+ kfree(tstate);
}
}
#ifdef AHC_TARGET_MODE
if (ahc->black_hole != NULL) {
xpt_free_path(ahc->black_hole->path);
- free(ahc->black_hole, M_DEVBUF);
+ kfree(ahc->black_hole);
}
#endif
if (ahc->name != NULL)
- free(ahc->name, M_DEVBUF);
+ kfree(ahc->name);
if (ahc->seep_config != NULL)
- free(ahc->seep_config, M_DEVBUF);
+ kfree(ahc->seep_config);
#ifndef __FreeBSD__
- free(ahc, M_DEVBUF);
+ kfree(ahc);
#endif
return;
}
@@ -4633,7 +4630,7 @@ ahc_reset(struct ahc_softc *ahc, int reinit)
} while (--wait && !(ahc_inb(ahc, HCNTRL) & CHIPRSTACK));
if (wait == 0) {
- printf("%s: WARNING - Failed chip reset! "
+ printk("%s: WARNING - Failed chip reset! "
"Trying to initialize anyway.\n", ahc_name(ahc));
}
ahc_outb(ahc, HCNTRL, ahc->pause);
@@ -4656,7 +4653,7 @@ ahc_reset(struct ahc_softc *ahc, int reinit)
ahc->features |= AHC_TWIN;
break;
default:
- printf(" Unsupported adapter type. Ignoring\n");
+ printk(" Unsupported adapter type. Ignoring\n");
return(-1);
}
@@ -4783,9 +4780,7 @@ ahc_init_scbdata(struct ahc_softc *ahc)
SLIST_INIT(&scb_data->sg_maps);
/* Allocate SCB resources */
- scb_data->scbarray =
- (struct scb *)malloc(sizeof(struct scb) * AHC_SCB_MAX_ALLOC,
- M_DEVBUF, M_NOWAIT);
+ scb_data->scbarray = (struct scb *)kmalloc(sizeof(struct scb) * AHC_SCB_MAX_ALLOC, GFP_ATOMIC);
if (scb_data->scbarray == NULL)
return (ENOMEM);
memset(scb_data->scbarray, 0, sizeof(struct scb) * AHC_SCB_MAX_ALLOC);
@@ -4794,7 +4789,7 @@ ahc_init_scbdata(struct ahc_softc *ahc)
scb_data->maxhscbs = ahc_probe_scbs(ahc);
if (ahc->scb_data->maxhscbs == 0) {
- printf("%s: No SCB space found\n", ahc_name(ahc));
+ printk("%s: No SCB space found\n", ahc_name(ahc));
return (ENXIO);
}
@@ -4892,7 +4887,7 @@ ahc_init_scbdata(struct ahc_softc *ahc)
ahc_alloc_scbs(ahc);
if (scb_data->numscbs == 0) {
- printf("%s: ahc_init_scbdata - "
+ printk("%s: ahc_init_scbdata - "
"Unable to allocate initial scbs\n",
ahc_name(ahc));
goto error_exit;
@@ -4935,7 +4930,7 @@ ahc_fini_scbdata(struct ahc_softc *ahc)
ahc_dmamem_free(ahc, scb_data->sg_dmat,
sg_map->sg_vaddr,
sg_map->sg_dmamap);
- free(sg_map, M_DEVBUF);
+ kfree(sg_map);
}
ahc_dma_tag_destroy(ahc, scb_data->sg_dmat);
}
@@ -4964,7 +4959,7 @@ ahc_fini_scbdata(struct ahc_softc *ahc)
break;
}
if (scb_data->scbarray != NULL)
- free(scb_data->scbarray, M_DEVBUF);
+ kfree(scb_data->scbarray);
}
static void
@@ -4985,7 +4980,7 @@ ahc_alloc_scbs(struct ahc_softc *ahc)
next_scb = &scb_data->scbarray[scb_data->numscbs];
- sg_map = malloc(sizeof(*sg_map), M_DEVBUF, M_NOWAIT);
+ sg_map = kmalloc(sizeof(*sg_map), GFP_ATOMIC);
if (sg_map == NULL)
return;
@@ -4994,7 +4989,7 @@ ahc_alloc_scbs(struct ahc_softc *ahc)
if (ahc_dmamem_alloc(ahc, scb_data->sg_dmat,
(void **)&sg_map->sg_vaddr,
BUS_DMA_NOWAIT, &sg_map->sg_dmamap) != 0) {
- free(sg_map, M_DEVBUF);
+ kfree(sg_map);
return;
}
@@ -5014,8 +5009,7 @@ ahc_alloc_scbs(struct ahc_softc *ahc)
#ifndef __linux__
int error;
#endif
- pdata = (struct scb_platform_data *)malloc(sizeof(*pdata),
- M_DEVBUF, M_NOWAIT);
+ pdata = kmalloc(sizeof(*pdata), GFP_ATOMIC);
if (pdata == NULL)
break;
next_scb->platform_data = pdata;
@@ -5244,7 +5238,7 @@ ahc_chip_init(struct ahc_softc *ahc)
* in "fast" mode.
*/
if (bootverbose)
- printf("%s: Downloading Sequencer Program...",
+ printk("%s: Downloading Sequencer Program...",
ahc_name(ahc));
error = ahc_loadseq(ahc);
@@ -5290,22 +5284,22 @@ ahc_init(struct ahc_softc *ahc)
#endif
#ifdef AHC_PRINT_SRAM
- printf("Scratch Ram:");
+ printk("Scratch Ram:");
for (i = 0x20; i < 0x5f; i++) {
if (((i % 8) == 0) && (i != 0)) {
- printf ("\n ");
+ printk ("\n ");
}
- printf (" 0x%x", ahc_inb(ahc, i));
+ printk (" 0x%x", ahc_inb(ahc, i));
}
if ((ahc->features & AHC_MORE_SRAM) != 0) {
for (i = 0x70; i < 0x7f; i++) {
if (((i % 8) == 0) && (i != 0)) {
- printf ("\n ");
+ printk ("\n ");
}
- printf (" 0x%x", ahc_inb(ahc, i));
+ printk (" 0x%x", ahc_inb(ahc, i));
}
}
- printf ("\n");
+ printk ("\n");
/*
* Reading uninitialized scratch ram may
* generate parity errors.
@@ -5419,14 +5413,14 @@ ahc_init(struct ahc_softc *ahc)
* data for any target mode initiator.
*/
if (ahc_alloc_tstate(ahc, ahc->our_id, 'A') == NULL) {
- printf("%s: unable to allocate ahc_tmode_tstate. "
+ printk("%s: unable to allocate ahc_tmode_tstate. "
"Failing attach\n", ahc_name(ahc));
return (ENOMEM);
}
if ((ahc->features & AHC_TWIN) != 0) {
if (ahc_alloc_tstate(ahc, ahc->our_id_b, 'B') == NULL) {
- printf("%s: unable to allocate ahc_tmode_tstate. "
+ printk("%s: unable to allocate ahc_tmode_tstate. "
"Failing attach\n", ahc_name(ahc));
return (ENOMEM);
}
@@ -5440,7 +5434,7 @@ ahc_init(struct ahc_softc *ahc)
#ifdef AHC_DEBUG
if (ahc_debug & AHC_SHOW_MISC) {
- printf("%s: hardware scb %u bytes; kernel scb %u bytes; "
+ printk("%s: hardware scb %u bytes; kernel scb %u bytes; "
"ahc_dma %u bytes\n",
ahc_name(ahc),
(u_int)sizeof(struct hardware_scb),
@@ -5470,7 +5464,7 @@ ahc_init(struct ahc_softc *ahc)
/* Grab the disconnection disable table and invert it for our needs */
if ((ahc->flags & AHC_USEDEFAULTS) != 0) {
- printf("%s: Host Adapter Bios disabled. Using default SCSI "
+ printk("%s: Host Adapter Bios disabled. Using default SCSI "
"device parameters\n", ahc_name(ahc));
ahc->flags |= AHC_EXTENDED_TRANS_A|AHC_EXTENDED_TRANS_B|
AHC_TERM_ENB_A|AHC_TERM_ENB_B;
@@ -5651,7 +5645,7 @@ ahc_pause_and_flushwork(struct ahc_softc *ahc)
&& ((intstat & INT_PEND) != 0
|| (ahc_inb(ahc, SSTAT0) & (SELDO|SELINGO)) != 0));
if (maxloops == 0) {
- printf("Infinite interrupt loop, INTSTAT = %x",
+ printk("Infinite interrupt loop, INTSTAT = %x",
ahc_inb(ahc, INTSTAT));
}
ahc_platform_flushwork(ahc);
@@ -5910,7 +5904,7 @@ ahc_search_qinfifo(struct ahc_softc *ahc, int target, char channel,
while (qinpos != qintail) {
scb = ahc_lookup_scb(ahc, ahc->qinfifo[qinpos]);
if (scb == NULL) {
- printf("qinpos = %d, SCB index = %d\n",
+ printk("qinpos = %d, SCB index = %d\n",
qinpos, ahc->qinfifo[qinpos]);
panic("Loop 1\n");
}
@@ -5933,7 +5927,7 @@ ahc_search_qinfifo(struct ahc_softc *ahc, int target, char channel,
if (cstat != CAM_REQ_CMP)
ahc_freeze_scb(scb);
if ((scb->flags & SCB_ACTIVE) == 0)
- printf("Inactive SCB in qinfifo\n");
+ printk("Inactive SCB in qinfifo\n");
ahc_done(ahc, scb);
/* FALLTHROUGH */
@@ -5976,7 +5970,7 @@ ahc_search_qinfifo(struct ahc_softc *ahc, int target, char channel,
scb = ahc_lookup_scb(ahc, ahc->qinfifo[qinstart]);
if (scb == NULL) {
- printf("found = %d, qinstart = %d, qinfifionext = %d\n",
+ printk("found = %d, qinstart = %d, qinfifionext = %d\n",
found, qinstart, ahc->qinfifonext);
panic("First/Second Qinfifo fixup\n");
}
@@ -6014,7 +6008,7 @@ ahc_search_qinfifo(struct ahc_softc *ahc, int target, char channel,
ahc_outb(ahc, SCBPTR, next);
scb_index = ahc_inb(ahc, SCB_TAG);
if (scb_index >= ahc->scb_data->numscbs) {
- printf("Waiting List inconsistency. "
+ printk("Waiting List inconsistency. "
"SCB index == %d, yet numscbs == %d.",
scb_index, ahc->scb_data->numscbs);
ahc_dump_card_state(ahc);
@@ -6022,7 +6016,7 @@ ahc_search_qinfifo(struct ahc_softc *ahc, int target, char channel,
}
scb = ahc_lookup_scb(ahc, scb_index);
if (scb == NULL) {
- printf("scb_index = %d, next = %d\n",
+ printk("scb_index = %d, next = %d\n",
scb_index, next);
panic("Waiting List traversal\n");
}
@@ -6046,7 +6040,7 @@ ahc_search_qinfifo(struct ahc_softc *ahc, int target, char channel,
if (cstat != CAM_REQ_CMP)
ahc_freeze_scb(scb);
if ((scb->flags & SCB_ACTIVE) == 0)
- printf("Inactive SCB in Waiting List\n");
+ printk("Inactive SCB in Waiting List\n");
ahc_done(ahc, scb);
/* FALLTHROUGH */
}
@@ -6153,7 +6147,7 @@ ahc_search_untagged_queues(struct ahc_softc *ahc, ahc_io_ctx_t ctx,
if (cstat != CAM_REQ_CMP)
ahc_freeze_scb(scb);
if ((scb->flags & SCB_ACTIVE) == 0)
- printf("Inactive SCB in untaggedQ\n");
+ printk("Inactive SCB in untaggedQ\n");
ahc_done(ahc, scb);
break;
}
@@ -6200,7 +6194,7 @@ ahc_search_disc_list(struct ahc_softc *ahc, int target, char channel,
ahc_outb(ahc, SCBPTR, next);
scb_index = ahc_inb(ahc, SCB_TAG);
if (scb_index >= ahc->scb_data->numscbs) {
- printf("Disconnected List inconsistency. "
+ printk("Disconnected List inconsistency. "
"SCB index == %d, yet numscbs == %d.",
scb_index, ahc->scb_data->numscbs);
ahc_dump_card_state(ahc);
@@ -6456,7 +6450,7 @@ ahc_abort_scbs(struct ahc_softc *ahc, int target, char channel,
if (ahc_get_transaction_status(scbp) != CAM_REQ_CMP)
ahc_freeze_scb(scbp);
if ((scbp->flags & SCB_ACTIVE) == 0)
- printf("Inactive SCB on pending list\n");
+ printk("Inactive SCB on pending list\n");
ahc_done(ahc, scbp);
found++;
}
@@ -6734,7 +6728,7 @@ ahc_calc_residual(struct ahc_softc *ahc, struct scb *scb)
#ifdef AHC_DEBUG
if ((ahc_debug & AHC_SHOW_MISC) != 0) {
ahc_print_path(ahc, scb);
- printf("Handled %sResidual of %d bytes\n",
+ printk("Handled %sResidual of %d bytes\n",
(scb->flags & SCB_SENSE) ? "Sense " : "", resid);
}
#endif
@@ -6774,7 +6768,7 @@ ahc_queue_lstate_event(struct ahc_softc *ahc, struct ahc_tmode_lstate *lstate,
if (pending == AHC_TMODE_EVENT_BUFFER_SIZE) {
xpt_print_path(lstate->path);
- printf("immediate event %x:%x lost\n",
+ printk("immediate event %x:%x lost\n",
lstate->event_buffer[lstate->event_r_idx].event_type,
lstate->event_buffer[lstate->event_r_idx].event_arg);
lstate->event_r_idx++;
@@ -6844,7 +6838,7 @@ ahc_dumpseq(struct ahc_softc* ahc)
uint8_t ins_bytes[4];
ahc_insb(ahc, SEQRAM, ins_bytes, 4);
- printf("0x%08x\n", ins_bytes[0] << 24
+ printk("0x%08x\n", ins_bytes[0] << 24
| ins_bytes[1] << 16
| ins_bytes[2] << 8
| ins_bytes[3]);
@@ -6912,7 +6906,7 @@ ahc_loadseq(struct ahc_softc *ahc)
* storage capacity for this chip. Fail
* the load.
*/
- printf("\n%s: Program too large for instruction memory "
+ printk("\n%s: Program too large for instruction memory "
"size of %d!\n", ahc_name(ahc),
ahc->instruction_ram_size);
return (ENOMEM);
@@ -6947,7 +6941,7 @@ ahc_loadseq(struct ahc_softc *ahc)
if (cs_count != 0) {
cs_count *= sizeof(struct cs);
- ahc->critical_sections = malloc(cs_count, M_DEVBUF, M_NOWAIT);
+ ahc->critical_sections = kmalloc(cs_count, GFP_ATOMIC);
if (ahc->critical_sections == NULL)
panic("ahc_loadseq: Could not malloc");
memcpy(ahc->critical_sections, cs_table, cs_count);
@@ -6955,8 +6949,8 @@ ahc_loadseq(struct ahc_softc *ahc)
ahc_outb(ahc, SEQCTL, PERRORDIS|FAILDIS|FASTMODE);
if (bootverbose) {
- printf(" %d instructions downloaded\n", downloaded);
- printf("%s: Features 0x%x, Bugs 0x%x, Flags 0x%x\n",
+ printk(" %d instructions downloaded\n", downloaded);
+ printk("%s: Features 0x%x, Bugs 0x%x, Flags 0x%x\n",
ahc_name(ahc), ahc->features, ahc->bugs, ahc->flags);
}
return (0);
@@ -7132,12 +7126,12 @@ ahc_print_register(const ahc_reg_parse_entry_t *table, u_int num_entries,
u_int printed_mask;
if (cur_column != NULL && *cur_column >= wrap_point) {
- printf("\n");
+ printk("\n");
*cur_column = 0;
}
- printed = printf("%s[0x%x]", name, value);
+ printed = printk("%s[0x%x]", name, value);
if (table == NULL) {
- printed += printf(" ");
+ printed += printk(" ");
*cur_column += printed;
return (printed);
}
@@ -7152,7 +7146,7 @@ ahc_print_register(const ahc_reg_parse_entry_t *table, u_int num_entries,
== table[entry].mask))
continue;
- printed += printf("%s%s",
+ printed += printk("%s%s",
printed_mask == 0 ? ":(" : "|",
table[entry].name);
printed_mask |= table[entry].mask;
@@ -7163,9 +7157,9 @@ ahc_print_register(const ahc_reg_parse_entry_t *table, u_int num_entries,
break;
}
if (printed_mask != 0)
- printed += printf(") ");
+ printed += printk(") ");
else
- printed += printf(" ");
+ printed += printk(" ");
if (cur_column != NULL)
*cur_column += printed;
return (printed);
@@ -7197,16 +7191,16 @@ ahc_dump_card_state(struct ahc_softc *ahc)
saved_scbptr = ahc_inb(ahc, SCBPTR);
last_phase = ahc_inb(ahc, LASTPHASE);
- printf(">>>>>>>>>>>>>>>>>> Dump Card State Begins <<<<<<<<<<<<<<<<<\n"
+ printk(">>>>>>>>>>>>>>>>>> Dump Card State Begins <<<<<<<<<<<<<<<<<\n"
"%s: Dumping Card State %s, at SEQADDR 0x%x\n",
ahc_name(ahc), ahc_lookup_phase_entry(last_phase)->phasemsg,
ahc_inb(ahc, SEQADDR0) | (ahc_inb(ahc, SEQADDR1) << 8));
if (paused)
- printf("Card was paused\n");
- printf("ACCUM = 0x%x, SINDEX = 0x%x, DINDEX = 0x%x, ARG_2 = 0x%x\n",
+ printk("Card was paused\n");
+ printk("ACCUM = 0x%x, SINDEX = 0x%x, DINDEX = 0x%x, ARG_2 = 0x%x\n",
ahc_inb(ahc, ACCUM), ahc_inb(ahc, SINDEX), ahc_inb(ahc, DINDEX),
ahc_inb(ahc, ARG_2));
- printf("HCNT = 0x%x SCBPTR = 0x%x\n", ahc_inb(ahc, HCNT),
+ printk("HCNT = 0x%x SCBPTR = 0x%x\n", ahc_inb(ahc, HCNT),
ahc_inb(ahc, SCBPTR));
cur_col = 0;
if ((ahc->features & AHC_DT) != 0)
@@ -7230,15 +7224,15 @@ ahc_dump_card_state(struct ahc_softc *ahc)
ahc_dfcntrl_print(ahc_inb(ahc, DFCNTRL), &cur_col, 50);
ahc_dfstatus_print(ahc_inb(ahc, DFSTATUS), &cur_col, 50);
if (cur_col != 0)
- printf("\n");
- printf("STACK:");
+ printk("\n");
+ printk("STACK:");
for (i = 0; i < STACK_SIZE; i++)
- printf(" 0x%x", ahc_inb(ahc, STACK)|(ahc_inb(ahc, STACK) << 8));
- printf("\nSCB count = %d\n", ahc->scb_data->numscbs);
- printf("Kernel NEXTQSCB = %d\n", ahc->next_queued_scb->hscb->tag);
- printf("Card NEXTQSCB = %d\n", ahc_inb(ahc, NEXT_QUEUED_SCB));
+ printk(" 0x%x", ahc_inb(ahc, STACK)|(ahc_inb(ahc, STACK) << 8));
+ printk("\nSCB count = %d\n", ahc->scb_data->numscbs);
+ printk("Kernel NEXTQSCB = %d\n", ahc->next_queued_scb->hscb->tag);
+ printk("Card NEXTQSCB = %d\n", ahc_inb(ahc, NEXT_QUEUED_SCB));
/* QINFIFO */
- printf("QINFIFO entries: ");
+ printk("QINFIFO entries: ");
if ((ahc->features & AHC_QUEUE_REGS) != 0) {
qinpos = ahc_inb(ahc, SNSCB_QOFF);
ahc_outb(ahc, SNSCB_QOFF, qinpos);
@@ -7246,109 +7240,109 @@ ahc_dump_card_state(struct ahc_softc *ahc)
qinpos = ahc_inb(ahc, QINPOS);
qintail = ahc->qinfifonext;
while (qinpos != qintail) {
- printf("%d ", ahc->qinfifo[qinpos]);
+ printk("%d ", ahc->qinfifo[qinpos]);
qinpos++;
}
- printf("\n");
+ printk("\n");
- printf("Waiting Queue entries: ");
+ printk("Waiting Queue entries: ");
scb_index = ahc_inb(ahc, WAITING_SCBH);
i = 0;
while (scb_index != SCB_LIST_NULL && i++ < 256) {
ahc_outb(ahc, SCBPTR, scb_index);
- printf("%d:%d ", scb_index, ahc_inb(ahc, SCB_TAG));
+ printk("%d:%d ", scb_index, ahc_inb(ahc, SCB_TAG));
scb_index = ahc_inb(ahc, SCB_NEXT);
}
- printf("\n");
+ printk("\n");
- printf("Disconnected Queue entries: ");
+ printk("Disconnected Queue entries: ");
scb_index = ahc_inb(ahc, DISCONNECTED_SCBH);
i = 0;
while (scb_index != SCB_LIST_NULL && i++ < 256) {
ahc_outb(ahc, SCBPTR, scb_index);
- printf("%d:%d ", scb_index, ahc_inb(ahc, SCB_TAG));
+ printk("%d:%d ", scb_index, ahc_inb(ahc, SCB_TAG));
scb_index = ahc_inb(ahc, SCB_NEXT);
}
- printf("\n");
+ printk("\n");
ahc_sync_qoutfifo(ahc, BUS_DMASYNC_POSTREAD);
- printf("QOUTFIFO entries: ");
+ printk("QOUTFIFO entries: ");
qoutpos = ahc->qoutfifonext;
i = 0;
while (ahc->qoutfifo[qoutpos] != SCB_LIST_NULL && i++ < 256) {
- printf("%d ", ahc->qoutfifo[qoutpos]);
+ printk("%d ", ahc->qoutfifo[qoutpos]);
qoutpos++;
}
- printf("\n");
+ printk("\n");
- printf("Sequencer Free SCB List: ");
+ printk("Sequencer Free SCB List: ");
scb_index = ahc_inb(ahc, FREE_SCBH);
i = 0;
while (scb_index != SCB_LIST_NULL && i++ < 256) {
ahc_outb(ahc, SCBPTR, scb_index);
- printf("%d ", scb_index);
+ printk("%d ", scb_index);
scb_index = ahc_inb(ahc, SCB_NEXT);
}
- printf("\n");
+ printk("\n");
- printf("Sequencer SCB Info: ");
+ printk("Sequencer SCB Info: ");
for (i = 0; i < ahc->scb_data->maxhscbs; i++) {
ahc_outb(ahc, SCBPTR, i);
- cur_col = printf("\n%3d ", i);
+ cur_col = printk("\n%3d ", i);
ahc_scb_control_print(ahc_inb(ahc, SCB_CONTROL), &cur_col, 60);
ahc_scb_scsiid_print(ahc_inb(ahc, SCB_SCSIID), &cur_col, 60);
ahc_scb_lun_print(ahc_inb(ahc, SCB_LUN), &cur_col, 60);
ahc_scb_tag_print(ahc_inb(ahc, SCB_TAG), &cur_col, 60);
}
- printf("\n");
+ printk("\n");
- printf("Pending list: ");
+ printk("Pending list: ");
i = 0;
LIST_FOREACH(scb, &ahc->pending_scbs, pending_links) {
if (i++ > 256)
break;
- cur_col = printf("\n%3d ", scb->hscb->tag);
+ cur_col = printk("\n%3d ", scb->hscb->tag);
ahc_scb_control_print(scb->hscb->control, &cur_col, 60);
ahc_scb_scsiid_print(scb->hscb->scsiid, &cur_col, 60);
ahc_scb_lun_print(scb->hscb->lun, &cur_col, 60);
if ((ahc->flags & AHC_PAGESCBS) == 0) {
ahc_outb(ahc, SCBPTR, scb->hscb->tag);
- printf("(");
+ printk("(");
ahc_scb_control_print(ahc_inb(ahc, SCB_CONTROL),
&cur_col, 60);
ahc_scb_tag_print(ahc_inb(ahc, SCB_TAG), &cur_col, 60);
- printf(")");
+ printk(")");
}
}
- printf("\n");
+ printk("\n");
- printf("Kernel Free SCB list: ");
+ printk("Kernel Free SCB list: ");
i = 0;
SLIST_FOREACH(scb, &ahc->scb_data->free_scbs, links.sle) {
if (i++ > 256)
break;
- printf("%d ", scb->hscb->tag);
+ printk("%d ", scb->hscb->tag);
}
- printf("\n");
+ printk("\n");
maxtarget = (ahc->features & (AHC_WIDE|AHC_TWIN)) ? 15 : 7;
for (target = 0; target <= maxtarget; target++) {
untagged_q = &ahc->untagged_queues[target];
if (TAILQ_FIRST(untagged_q) == NULL)
continue;
- printf("Untagged Q(%d): ", target);
+ printk("Untagged Q(%d): ", target);
i = 0;
TAILQ_FOREACH(scb, untagged_q, links.tqe) {
if (i++ > 256)
break;
- printf("%d ", scb->hscb->tag);
+ printk("%d ", scb->hscb->tag);
}
- printf("\n");
+ printk("\n");
}
ahc_platform_dump_card_state(ahc);
- printf("\n<<<<<<<<<<<<<<<<< Dump Card State Ends >>>>>>>>>>>>>>>>>>\n");
+ printk("\n<<<<<<<<<<<<<<<<< Dump Card State Ends >>>>>>>>>>>>>>>>>>\n");
ahc_outb(ahc, SCBPTR, saved_scbptr);
if (paused == 0)
ahc_unpause(ahc);
@@ -7489,7 +7483,7 @@ ahc_handle_en_lun(struct ahc_softc *ahc, struct cam_sim *sim, union ccb *ccb)
u_long s;
ahc_flag saved_flags;
- printf("Configuring Target Mode\n");
+ printk("Configuring Target Mode\n");
ahc_lock(ahc, &s);
if (LIST_FIRST(&ahc->pending_scbs) != NULL) {
ccb->ccb_h.status = CAM_BUSY;
@@ -7535,7 +7529,7 @@ ahc_handle_en_lun(struct ahc_softc *ahc, struct cam_sim *sim, union ccb *ccb)
/* Are we already enabled?? */
if (lstate != NULL) {
xpt_print_path(ccb->ccb_h.path);
- printf("Lun already enabled\n");
+ printk("Lun already enabled\n");
ccb->ccb_h.status = CAM_LUN_ALRDY_ENA;
return;
}
@@ -7547,7 +7541,7 @@ ahc_handle_en_lun(struct ahc_softc *ahc, struct cam_sim *sim, union ccb *ccb)
* specific commands.
*/
ccb->ccb_h.status = CAM_REQ_INVALID;
- printf("Non-zero Group Codes\n");
+ printk("Non-zero Group Codes\n");
return;
}
@@ -7559,15 +7553,15 @@ ahc_handle_en_lun(struct ahc_softc *ahc, struct cam_sim *sim, union ccb *ccb)
tstate = ahc_alloc_tstate(ahc, target, channel);
if (tstate == NULL) {
xpt_print_path(ccb->ccb_h.path);
- printf("Couldn't allocate tstate\n");
+ printk("Couldn't allocate tstate\n");
ccb->ccb_h.status = CAM_RESRC_UNAVAIL;
return;
}
}
- lstate = malloc(sizeof(*lstate), M_DEVBUF, M_NOWAIT);
+ lstate = kmalloc(sizeof(*lstate), GFP_ATOMIC);
if (lstate == NULL) {
xpt_print_path(ccb->ccb_h.path);
- printf("Couldn't allocate lstate\n");
+ printk("Couldn't allocate lstate\n");
ccb->ccb_h.status = CAM_RESRC_UNAVAIL;
return;
}
@@ -7577,9 +7571,9 @@ ahc_handle_en_lun(struct ahc_softc *ahc, struct cam_sim *sim, union ccb *ccb)
xpt_path_target_id(ccb->ccb_h.path),
xpt_path_lun_id(ccb->ccb_h.path));
if (status != CAM_REQ_CMP) {
- free(lstate, M_DEVBUF);
+ kfree(lstate);
xpt_print_path(ccb->ccb_h.path);
- printf("Couldn't allocate path\n");
+ printk("Couldn't allocate path\n");
ccb->ccb_h.status = CAM_RESRC_UNAVAIL;
return;
}
@@ -7654,7 +7648,7 @@ ahc_handle_en_lun(struct ahc_softc *ahc, struct cam_sim *sim, union ccb *ccb)
ahc_unlock(ahc, &s);
ccb->ccb_h.status = CAM_REQ_CMP;
xpt_print_path(ccb->ccb_h.path);
- printf("Lun now enabled for target mode\n");
+ printk("Lun now enabled for target mode\n");
} else {
struct scb *scb;
int i, empty;
@@ -7673,7 +7667,7 @@ ahc_handle_en_lun(struct ahc_softc *ahc, struct cam_sim *sim, union ccb *ccb)
ccbh = &scb->io_ctx->ccb_h;
if (ccbh->func_code == XPT_CONT_TARGET_IO
&& !xpt_path_comp(ccbh->path, ccb->ccb_h.path)){
- printf("CTIO pending\n");
+ printk("CTIO pending\n");
ccb->ccb_h.status = CAM_REQ_INVALID;
ahc_unlock(ahc, &s);
return;
@@ -7681,12 +7675,12 @@ ahc_handle_en_lun(struct ahc_softc *ahc, struct cam_sim *sim, union ccb *ccb)
}
if (SLIST_FIRST(&lstate->accept_tios) != NULL) {
- printf("ATIOs pending\n");
+ printk("ATIOs pending\n");
ccb->ccb_h.status = CAM_REQ_INVALID;
}
if (SLIST_FIRST(&lstate->immed_notifies) != NULL) {
- printf("INOTs pending\n");
+ printk("INOTs pending\n");
ccb->ccb_h.status = CAM_REQ_INVALID;
}
@@ -7696,9 +7690,9 @@ ahc_handle_en_lun(struct ahc_softc *ahc, struct cam_sim *sim, union ccb *ccb)
}
xpt_print_path(ccb->ccb_h.path);
- printf("Target mode disabled\n");
+ printk("Target mode disabled\n");
xpt_free_path(lstate->path);
- free(lstate, M_DEVBUF);
+ kfree(lstate);
ahc_pause(ahc);
/* Can we clean up the target too? */
@@ -7750,7 +7744,7 @@ ahc_handle_en_lun(struct ahc_softc *ahc, struct cam_sim *sim, union ccb *ccb)
ahc_outb(ahc, SCSISEQ, scsiseq);
if ((ahc->features & AHC_MULTIROLE) == 0) {
- printf("Configuring Initiator Mode\n");
+ printk("Configuring Initiator Mode\n");
ahc->flags &= ~AHC_TARGETROLE;
ahc->flags |= AHC_INITIATORROLE;
/*
@@ -7897,12 +7891,12 @@ ahc_handle_target_cmd(struct ahc_softc *ahc, struct target_cmd *cmd)
* Wait for more ATIOs from the peripheral driver for this lun.
*/
if (bootverbose)
- printf("%s: ATIOs exhausted\n", ahc_name(ahc));
+ printk("%s: ATIOs exhausted\n", ahc_name(ahc));
return (1);
} else
ahc->flags &= ~AHC_TQINFIFO_BLOCKED;
#if 0
- printf("Incoming command from %d for %d:%d%s\n",
+ printk("Incoming command from %d for %d:%d%s\n",
initiator, target, lun,
lstate == ahc->black_hole ? "(Black Holed)" : "");
#endif
@@ -7949,7 +7943,7 @@ ahc_handle_target_cmd(struct ahc_softc *ahc, struct target_cmd *cmd)
default:
/* Only copy the opcode. */
atio->cdb_len = 1;
- printf("Reserved or VU command code type encountered\n");
+ printk("Reserved or VU command code type encountered\n");
break;
}
@@ -7965,7 +7959,7 @@ ahc_handle_target_cmd(struct ahc_softc *ahc, struct target_cmd *cmd)
* to this accept tio.
*/
#if 0
- printf("Received Immediate Command %d:%d:%d - %p\n",
+ printk("Received Immediate Command %d:%d:%d - %p\n",
initiator, target, lun, ahc->pending_device);
#endif
ahc->pending_device = lstate;
diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm.c b/drivers/scsi/aic7xxx/aic7xxx_osm.c
index 5e42dac2350..aeea7a61478 100644
--- a/drivers/scsi/aic7xxx/aic7xxx_osm.c
+++ b/drivers/scsi/aic7xxx/aic7xxx_osm.c
@@ -653,7 +653,7 @@ ahc_linux_slave_alloc(struct scsi_device *sdev)
struct ahc_linux_device *dev;
if (bootverbose)
- printf("%s: Slave Alloc %d\n", ahc_name(ahc), sdev->id);
+ printk("%s: Slave Alloc %d\n", ahc_name(ahc), sdev->id);
dev = scsi_transport_device_data(sdev);
memset(dev, 0, sizeof(*dev));
@@ -755,7 +755,7 @@ ahc_linux_abort(struct scsi_cmnd *cmd)
error = ahc_linux_queue_recovery_cmd(cmd, SCB_ABORT);
if (error != 0)
- printf("aic7xxx_abort returns 0x%x\n", error);
+ printk("aic7xxx_abort returns 0x%x\n", error);
return (error);
}
@@ -769,7 +769,7 @@ ahc_linux_dev_reset(struct scsi_cmnd *cmd)
error = ahc_linux_queue_recovery_cmd(cmd, SCB_DEVICE_RESET);
if (error != 0)
- printf("aic7xxx_dev_reset returns 0x%x\n", error);
+ printk("aic7xxx_dev_reset returns 0x%x\n", error);
return (error);
}
@@ -791,7 +791,7 @@ ahc_linux_bus_reset(struct scsi_cmnd *cmd)
ahc_unlock(ahc, &flags);
if (bootverbose)
- printf("%s: SCSI bus reset delivered. "
+ printk("%s: SCSI bus reset delivered. "
"%d SCBs aborted.\n", ahc_name(ahc), found);
return SUCCESS;
@@ -840,7 +840,7 @@ ahc_dma_tag_create(struct ahc_softc *ahc, bus_dma_tag_t parent,
{
bus_dma_tag_t dmat;
- dmat = malloc(sizeof(*dmat), M_DEVBUF, M_NOWAIT);
+ dmat = kmalloc(sizeof(*dmat), GFP_ATOMIC);
if (dmat == NULL)
return (ENOMEM);
@@ -861,7 +861,7 @@ ahc_dma_tag_create(struct ahc_softc *ahc, bus_dma_tag_t parent,
void
ahc_dma_tag_destroy(struct ahc_softc *ahc, bus_dma_tag_t dmat)
{
- free(dmat, M_DEVBUF);
+ kfree(dmat);
}
int
@@ -918,7 +918,7 @@ ahc_linux_setup_tag_info_global(char *p)
int tags, i, j;
tags = simple_strtoul(p + 1, NULL, 0) & 0xff;
- printf("Setting Global Tags= %d\n", tags);
+ printk("Setting Global Tags= %d\n", tags);
for (i = 0; i < ARRAY_SIZE(aic7xxx_tag_info); i++) {
for (j = 0; j < AHC_NUM_TARGETS; j++) {
@@ -936,7 +936,7 @@ ahc_linux_setup_tag_info(u_long arg, int instance, int targ, int32_t value)
&& (targ < AHC_NUM_TARGETS)) {
aic7xxx_tag_info[instance].tag_commands[targ] = value & 0xff;
if (bootverbose)
- printf("tag_info[%d:%d] = %d\n", instance, targ, value);
+ printk("tag_info[%d:%d] = %d\n", instance, targ, value);
}
}
@@ -977,7 +977,7 @@ ahc_parse_brace_option(char *opt_name, char *opt_arg, char *end, int depth,
if (targ == -1)
targ = 0;
} else {
- printf("Malformed Option %s\n",
+ printk("Malformed Option %s\n",
opt_name);
done = TRUE;
}
@@ -1120,7 +1120,7 @@ ahc_linux_register_host(struct ahc_softc *ahc, struct scsi_host_template *templa
ahc_set_unit(ahc, ahc_linux_unit++);
ahc_unlock(ahc, &s);
sprintf(buf, "scsi%d", host->host_no);
- new_name = malloc(strlen(buf) + 1, M_DEVBUF, M_NOWAIT);
+ new_name = kmalloc(strlen(buf) + 1, GFP_ATOMIC);
if (new_name != NULL) {
strcpy(new_name, buf);
ahc_set_name(ahc, new_name);
@@ -1220,7 +1220,7 @@ ahc_platform_alloc(struct ahc_softc *ahc, void *platform_arg)
{
ahc->platform_data =
- malloc(sizeof(struct ahc_platform_data), M_DEVBUF, M_NOWAIT);
+ kmalloc(sizeof(struct ahc_platform_data), GFP_ATOMIC);
if (ahc->platform_data == NULL)
return (ENOMEM);
memset(ahc->platform_data, 0, sizeof(struct ahc_platform_data));
@@ -1264,7 +1264,7 @@ ahc_platform_free(struct ahc_softc *ahc)
if (ahc->platform_data->host)
scsi_host_put(ahc->platform_data->host);
- free(ahc->platform_data, M_DEVBUF);
+ kfree(ahc->platform_data);
}
}
@@ -1378,7 +1378,7 @@ ahc_linux_user_tagdepth(struct ahc_softc *ahc, struct ahc_devinfo *devinfo)
if (ahc->unit >= ARRAY_SIZE(aic7xxx_tag_info)) {
if (warned_user == 0) {
- printf(KERN_WARNING
+ printk(KERN_WARNING
"aic7xxx: WARNING: Insufficient tag_info instances\n"
"aic7xxx: for installed controllers. Using defaults\n"
"aic7xxx: Please update the aic7xxx_tag_info array in\n"
@@ -1421,7 +1421,7 @@ ahc_linux_device_queue_depth(struct scsi_device *sdev)
ahc_send_async(ahc, devinfo.channel, devinfo.target,
devinfo.lun, AC_TRANSFER_NEG);
ahc_print_devinfo(ahc, &devinfo);
- printf("Tagged Queuing enabled. Depth %d\n", tags);
+ printk("Tagged Queuing enabled. Depth %d\n", tags);
} else {
ahc_platform_set_tags(ahc, sdev, &devinfo, AHC_QUEUE_NONE);
ahc_send_async(ahc, devinfo.channel, devinfo.target,
@@ -1735,7 +1735,7 @@ ahc_done(struct ahc_softc *ahc, struct scb *scb)
* not have been dispatched to the controller, so
* only check the SCB_ACTIVE flag for tagged transactions.
*/
- printf("SCB %d done'd twice\n", scb->hscb->tag);
+ printk("SCB %d done'd twice\n", scb->hscb->tag);
ahc_dump_card_state(ahc);
panic("Stopping for safety");
}
@@ -1765,7 +1765,7 @@ ahc_done(struct ahc_softc *ahc, struct scb *scb)
#ifdef AHC_DEBUG
if ((ahc_debug & AHC_SHOW_MISC) != 0) {
ahc_print_path(ahc, scb);
- printf("Set CAM_UNCOR_PARITY\n");
+ printk("Set CAM_UNCOR_PARITY\n");
}
#endif
ahc_set_transaction_status(scb, CAM_UNCOR_PARITY);
@@ -1783,12 +1783,12 @@ ahc_done(struct ahc_softc *ahc, struct scb *scb)
u_int i;
ahc_print_path(ahc, scb);
- printf("CDB:");
+ printk("CDB:");
for (i = 0; i < scb->io_ctx->cmd_len; i++)
- printf(" 0x%x", scb->io_ctx->cmnd[i]);
- printf("\n");
+ printk(" 0x%x", scb->io_ctx->cmnd[i]);
+ printk("\n");
ahc_print_path(ahc, scb);
- printf("Saw underflow (%ld of %ld bytes). "
+ printk("Saw underflow (%ld of %ld bytes). "
"Treated as error\n",
ahc_get_residual(scb),
ahc_get_transfer_length(scb));
@@ -1821,7 +1821,7 @@ ahc_done(struct ahc_softc *ahc, struct scb *scb)
dev->commands_since_idle_or_otag = 0;
if ((scb->flags & SCB_RECOVERY_SCB) != 0) {
- printf("Recovery SCB completes\n");
+ printk("Recovery SCB completes\n");
if (ahc_get_transaction_status(scb) == CAM_BDR_SENT
|| ahc_get_transaction_status(scb) == CAM_REQ_ABORTED)
ahc_set_transaction_status(scb, CAM_CMD_TIMEOUT);
@@ -1886,14 +1886,14 @@ ahc_linux_handle_scsi_status(struct ahc_softc *ahc,
if (ahc_debug & AHC_SHOW_SENSE) {
int i;
- printf("Copied %d bytes of sense data:",
+ printk("Copied %d bytes of sense data:",
sense_size);
for (i = 0; i < sense_size; i++) {
if ((i & 0xF) == 0)
- printf("\n");
- printf("0x%x ", cmd->sense_buffer[i]);
+ printk("\n");
+ printk("0x%x ", cmd->sense_buffer[i]);
}
- printf("\n");
+ printk("\n");
}
#endif
}
@@ -1918,7 +1918,7 @@ ahc_linux_handle_scsi_status(struct ahc_softc *ahc,
dev->openings = 0;
/*
ahc_print_path(ahc, scb);
- printf("Dropping tag count to %d\n", dev->active);
+ printk("Dropping tag count to %d\n", dev->active);
*/
if (dev->active == dev->tags_on_last_queuefull) {
@@ -1935,7 +1935,7 @@ ahc_linux_handle_scsi_status(struct ahc_softc *ahc,
== AHC_LOCK_TAGS_COUNT) {
dev->maxtags = dev->active;
ahc_print_path(ahc, scb);
- printf("Locking max tag count at %d\n",
+ printk("Locking max tag count at %d\n",
dev->active);
}
} else {
@@ -2100,10 +2100,10 @@ ahc_linux_queue_recovery_cmd(struct scsi_cmnd *cmd, scb_flag flag)
scmd_printk(KERN_INFO, cmd, "Attempting to queue a%s message\n",
flag == SCB_ABORT ? "n ABORT" : " TARGET RESET");
- printf("CDB:");
+ printk("CDB:");
for (cdb_byte = 0; cdb_byte < cmd->cmd_len; cdb_byte++)
- printf(" 0x%x", cmd->cmnd[cdb_byte]);
- printf("\n");
+ printk(" 0x%x", cmd->cmnd[cdb_byte]);
+ printk("\n");
ahc_lock(ahc, &flags);
@@ -2121,7 +2121,7 @@ ahc_linux_queue_recovery_cmd(struct scsi_cmnd *cmd, scb_flag flag)
* No target device for this command exists,
* so we must not still own the command.
*/
- printf("%s:%d:%d:%d: Is not an active device\n",
+ printk("%s:%d:%d:%d: Is not an active device\n",
ahc_name(ahc), cmd->device->channel, cmd->device->id,
cmd->device->lun);
retval = SUCCESS;
@@ -2133,7 +2133,7 @@ ahc_linux_queue_recovery_cmd(struct scsi_cmnd *cmd, scb_flag flag)
cmd->device->channel + 'A',
cmd->device->lun,
CAM_REQ_ABORTED, SEARCH_COMPLETE) != 0) {
- printf("%s:%d:%d:%d: Command found on untagged queue\n",
+ printk("%s:%d:%d:%d: Command found on untagged queue\n",
ahc_name(ahc), cmd->device->channel, cmd->device->id,
cmd->device->lun);
retval = SUCCESS;
@@ -2187,7 +2187,7 @@ ahc_linux_queue_recovery_cmd(struct scsi_cmnd *cmd, scb_flag flag)
goto no_cmd;
}
- printf("%s: At time of recovery, card was %spaused\n",
+ printk("%s: At time of recovery, card was %spaused\n",
ahc_name(ahc), was_paused ? "" : "not ");
ahc_dump_card_state(ahc);
@@ -2199,7 +2199,7 @@ ahc_linux_queue_recovery_cmd(struct scsi_cmnd *cmd, scb_flag flag)
pending_scb->hscb->tag,
ROLE_INITIATOR, CAM_REQ_ABORTED,
SEARCH_COMPLETE) > 0) {
- printf("%s:%d:%d:%d: Cmd aborted from QINFIFO\n",
+ printk("%s:%d:%d:%d: Cmd aborted from QINFIFO\n",
ahc_name(ahc), cmd->device->channel,
cmd->device->id, cmd->device->lun);
retval = SUCCESS;
@@ -2313,7 +2313,7 @@ ahc_linux_queue_recovery_cmd(struct scsi_cmnd *cmd, scb_flag flag)
ahc_qinfifo_requeue_tail(ahc, pending_scb);
ahc_outb(ahc, SCBPTR, saved_scbptr);
ahc_print_path(ahc, pending_scb);
- printf("Device is disconnected, re-queuing SCB\n");
+ printk("Device is disconnected, re-queuing SCB\n");
wait = TRUE;
} else {
scmd_printk(KERN_INFO, cmd, "Unable to deliver message\n");
@@ -2338,16 +2338,16 @@ done:
ahc->platform_data->eh_done = &done;
ahc_unlock(ahc, &flags);
- printf("Recovery code sleeping\n");
+ printk("Recovery code sleeping\n");
if (!wait_for_completion_timeout(&done, 5 * HZ)) {
ahc_lock(ahc, &flags);
ahc->platform_data->eh_done = NULL;
ahc_unlock(ahc, &flags);
- printf("Timer Expired\n");
+ printk("Timer Expired\n");
retval = FAILED;
}
- printf("Recovery code awake\n");
+ printk("Recovery code awake\n");
} else
ahc_unlock(ahc, &flags);
return (retval);
diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm.h b/drivers/scsi/aic7xxx/aic7xxx_osm.h
index 56f07e527b4..bca0fb83f55 100644
--- a/drivers/scsi/aic7xxx/aic7xxx_osm.h
+++ b/drivers/scsi/aic7xxx/aic7xxx_osm.h
@@ -368,13 +368,6 @@ struct ahc_platform_data {
resource_size_t mem_busaddr; /* Mem Base Addr */
};
-/************************** OS Utility Wrappers *******************************/
-#define printf printk
-#define M_NOWAIT GFP_ATOMIC
-#define M_WAITOK 0
-#define malloc(size, type, flags) kmalloc(size, flags)
-#define free(ptr, type) kfree(ptr)
-
void ahc_delay(long);
diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c b/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c
index 78fc70c24e0..ee05e841075 100644
--- a/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c
+++ b/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c
@@ -225,7 +225,7 @@ ahc_linux_pci_dev_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
ahc_get_pci_bus(pci),
ahc_get_pci_slot(pci),
ahc_get_pci_function(pci));
- name = malloc(strlen(buf) + 1, M_DEVBUF, M_NOWAIT);
+ name = kmalloc(strlen(buf) + 1, GFP_ATOMIC);
if (name == NULL)
return (-ENOMEM);
strcpy(name, buf);
@@ -412,7 +412,7 @@ ahc_pci_map_registers(struct ahc_softc *ahc)
*/
if (ahc_pci_test_register_access(ahc) != 0) {
- printf("aic7xxx: PCI Device %d:%d:%d "
+ printk("aic7xxx: PCI Device %d:%d:%d "
"failed memory mapped test. Using PIO.\n",
ahc_get_pci_bus(ahc->dev_softc),
ahc_get_pci_slot(ahc->dev_softc),
@@ -425,7 +425,7 @@ ahc_pci_map_registers(struct ahc_softc *ahc)
} else
command |= PCIM_CMD_MEMEN;
} else {
- printf("aic7xxx: PCI%d:%d:%d MEM region 0x%llx "
+ printk("aic7xxx: PCI%d:%d:%d MEM region 0x%llx "
"unavailable. Cannot memory map device.\n",
ahc_get_pci_bus(ahc->dev_softc),
ahc_get_pci_slot(ahc->dev_softc),
@@ -444,7 +444,7 @@ ahc_pci_map_registers(struct ahc_softc *ahc)
ahc->bsh.ioport = (u_long)base;
command |= PCIM_CMD_PORTEN;
} else {
- printf("aic7xxx: PCI%d:%d:%d IO region 0x%llx[0..255] "
+ printk("aic7xxx: PCI%d:%d:%d IO region 0x%llx[0..255] "
"unavailable. Cannot map device.\n",
ahc_get_pci_bus(ahc->dev_softc),
ahc_get_pci_slot(ahc->dev_softc),
diff --git a/drivers/scsi/aic7xxx/aic7xxx_pci.c b/drivers/scsi/aic7xxx/aic7xxx_pci.c
index 27014b9de12..2b11a427236 100644
--- a/drivers/scsi/aic7xxx/aic7xxx_pci.c
+++ b/drivers/scsi/aic7xxx/aic7xxx_pci.c
@@ -752,7 +752,7 @@ ahc_pci_config(struct ahc_softc *ahc, const struct ahc_pci_identity *entry)
if ((ahc->flags & AHC_39BIT_ADDRESSING) != 0) {
if (bootverbose)
- printf("%s: Enabling 39Bit Addressing\n",
+ printk("%s: Enabling 39Bit Addressing\n",
ahc_name(ahc));
devconfig |= DACEN;
}
@@ -896,7 +896,7 @@ ahc_pci_config(struct ahc_softc *ahc, const struct ahc_pci_identity *entry)
/* See if someone else set us up already */
if ((ahc->flags & AHC_NO_BIOS_INIT) == 0
&& scsiseq != 0) {
- printf("%s: Using left over BIOS settings\n",
+ printk("%s: Using left over BIOS settings\n",
ahc_name(ahc));
ahc->flags &= ~AHC_USEDEFAULTS;
ahc->flags |= AHC_BIOS_ENABLED;
@@ -1155,7 +1155,7 @@ done:
ahc_outb(ahc, CLRINT, CLRPARERR);
ahc_outb(ahc, CLRINT, CLRBRKADRINT);
if (bootverbose && enable) {
- printf("%s: External SRAM, %s access%s, %dbytes/SCB\n",
+ printk("%s: External SRAM, %s access%s, %dbytes/SCB\n",
ahc_name(ahc), fast ? "fast" : "slow",
pcheck ? ", parity checking enabled" : "",
large ? 64 : 32);
@@ -1292,7 +1292,7 @@ check_extport(struct ahc_softc *ahc, u_int *sxfrctl1)
if (have_seeprom) {
if (bootverbose)
- printf("%s: Reading SEEPROM...", ahc_name(ahc));
+ printk("%s: Reading SEEPROM...", ahc_name(ahc));
for (;;) {
u_int start_addr;
@@ -1309,9 +1309,9 @@ check_extport(struct ahc_softc *ahc, u_int *sxfrctl1)
if (have_seeprom != 0 || sd.sd_chip == C56_66) {
if (bootverbose) {
if (have_seeprom == 0)
- printf ("checksum error\n");
+ printk ("checksum error\n");
else
- printf ("done.\n");
+ printk ("done.\n");
}
break;
}
@@ -1362,9 +1362,9 @@ check_extport(struct ahc_softc *ahc, u_int *sxfrctl1)
if (!have_seeprom) {
if (bootverbose)
- printf("%s: No SEEPROM available.\n", ahc_name(ahc));
+ printk("%s: No SEEPROM available.\n", ahc_name(ahc));
ahc->flags |= AHC_USEDEFAULTS;
- free(ahc->seep_config, M_DEVBUF);
+ kfree(ahc->seep_config);
ahc->seep_config = NULL;
sc = NULL;
} else {
@@ -1399,7 +1399,7 @@ check_extport(struct ahc_softc *ahc, u_int *sxfrctl1)
if ((sc->adapter_control & CFSTERM) != 0)
*sxfrctl1 |= STPWEN;
if (bootverbose)
- printf("%s: Low byte termination %sabled\n",
+ printk("%s: Low byte termination %sabled\n",
ahc_name(ahc),
(*sxfrctl1 & STPWEN) ? "en" : "dis");
}
@@ -1569,7 +1569,7 @@ configure_termination(struct ahc_softc *ahc,
&eeprom_present);
if ((adapter_control & CFSEAUTOTERM) == 0) {
if (bootverbose)
- printf("%s: Manual SE Termination\n",
+ printk("%s: Manual SE Termination\n",
ahc_name(ahc));
enableSEC_low = (adapter_control & CFSELOWTERM);
enableSEC_high =
@@ -1577,7 +1577,7 @@ configure_termination(struct ahc_softc *ahc,
}
if ((adapter_control & CFAUTOTERM) == 0) {
if (bootverbose)
- printf("%s: Manual LVD Termination\n",
+ printk("%s: Manual LVD Termination\n",
ahc_name(ahc));
enablePRI_low = (adapter_control & CFSTERM);
enablePRI_high = (adapter_control & CFWSTERM);
@@ -1604,19 +1604,19 @@ configure_termination(struct ahc_softc *ahc,
if (bootverbose
&& (ahc->features & AHC_ULTRA2) == 0) {
- printf("%s: internal 50 cable %s present",
+ printk("%s: internal 50 cable %s present",
ahc_name(ahc),
internal50_present ? "is":"not");
if ((ahc->features & AHC_WIDE) != 0)
- printf(", internal 68 cable %s present",
+ printk(", internal 68 cable %s present",
internal68_present ? "is":"not");
- printf("\n%s: external cable %s present\n",
+ printk("\n%s: external cable %s present\n",
ahc_name(ahc),
externalcable_present ? "is":"not");
}
if (bootverbose)
- printf("%s: BIOS eeprom %s present\n",
+ printk("%s: BIOS eeprom %s present\n",
ahc_name(ahc), eeprom_present ? "is" : "not");
if ((ahc->flags & AHC_INT50_SPEEDFLEX) != 0) {
@@ -1642,7 +1642,7 @@ configure_termination(struct ahc_softc *ahc,
&& (internal50_present != 0)
&& (internal68_present != 0)
&& (externalcable_present != 0)) {
- printf("%s: Illegal cable configuration!!. "
+ printk("%s: Illegal cable configuration!!. "
"Only two connectors on the "
"adapter may be used at a "
"time!\n", ahc_name(ahc));
@@ -1664,10 +1664,10 @@ configure_termination(struct ahc_softc *ahc,
brddat |= BRDDAT6;
if (bootverbose) {
if ((ahc->flags & AHC_INT50_SPEEDFLEX) != 0)
- printf("%s: 68 pin termination "
+ printk("%s: 68 pin termination "
"Enabled\n", ahc_name(ahc));
else
- printf("%s: %sHigh byte termination "
+ printk("%s: %sHigh byte termination "
"Enabled\n", ahc_name(ahc),
enableSEC_high ? "Secondary "
: "");
@@ -1683,10 +1683,10 @@ configure_termination(struct ahc_softc *ahc,
*sxfrctl1 |= STPWEN;
if (bootverbose) {
if ((ahc->flags & AHC_INT50_SPEEDFLEX) != 0)
- printf("%s: 50 pin termination "
+ printk("%s: 50 pin termination "
"Enabled\n", ahc_name(ahc));
else
- printf("%s: %sLow byte termination "
+ printk("%s: %sLow byte termination "
"Enabled\n", ahc_name(ahc),
enableSEC_low ? "Secondary "
: "");
@@ -1696,7 +1696,7 @@ configure_termination(struct ahc_softc *ahc,
if (enablePRI_low != 0) {
*sxfrctl1 |= STPWEN;
if (bootverbose)
- printf("%s: Primary Low Byte termination "
+ printk("%s: Primary Low Byte termination "
"Enabled\n", ahc_name(ahc));
}
@@ -1709,7 +1709,7 @@ configure_termination(struct ahc_softc *ahc,
if (enablePRI_high != 0) {
brddat |= BRDDAT4;
if (bootverbose)
- printf("%s: Primary High Byte "
+ printk("%s: Primary High Byte "
"termination Enabled\n",
ahc_name(ahc));
}
@@ -1721,7 +1721,7 @@ configure_termination(struct ahc_softc *ahc,
*sxfrctl1 |= STPWEN;
if (bootverbose)
- printf("%s: %sLow byte termination Enabled\n",
+ printk("%s: %sLow byte termination Enabled\n",
ahc_name(ahc),
(ahc->features & AHC_ULTRA2) ? "Primary "
: "");
@@ -1731,7 +1731,7 @@ configure_termination(struct ahc_softc *ahc,
&& (ahc->features & AHC_WIDE) != 0) {
brddat |= BRDDAT6;
if (bootverbose)
- printf("%s: %sHigh byte termination Enabled\n",
+ printk("%s: %sHigh byte termination Enabled\n",
ahc_name(ahc),
(ahc->features & AHC_ULTRA2)
? "Secondary " : "");
@@ -1937,29 +1937,29 @@ ahc_pci_intr(struct ahc_softc *ahc)
status1 = ahc_pci_read_config(ahc->dev_softc,
PCIR_STATUS + 1, /*bytes*/1);
- printf("%s: PCI error Interrupt at seqaddr = 0x%x\n",
+ printk("%s: PCI error Interrupt at seqaddr = 0x%x\n",
ahc_name(ahc),
ahc_inb(ahc, SEQADDR0) | (ahc_inb(ahc, SEQADDR1) << 8));
if (status1 & DPE) {
ahc->pci_target_perr_count++;
- printf("%s: Data Parity Error Detected during address "
+ printk("%s: Data Parity Error Detected during address "
"or write data phase\n", ahc_name(ahc));
}
if (status1 & SSE) {
- printf("%s: Signal System Error Detected\n", ahc_name(ahc));
+ printk("%s: Signal System Error Detected\n", ahc_name(ahc));
}
if (status1 & RMA) {
- printf("%s: Received a Master Abort\n", ahc_name(ahc));
+ printk("%s: Received a Master Abort\n", ahc_name(ahc));
}
if (status1 & RTA) {
- printf("%s: Received a Target Abort\n", ahc_name(ahc));
+ printk("%s: Received a Target Abort\n", ahc_name(ahc));
}
if (status1 & STA) {
- printf("%s: Signaled a Target Abort\n", ahc_name(ahc));
+ printk("%s: Signaled a Target Abort\n", ahc_name(ahc));
}
if (status1 & DPR) {
- printf("%s: Data Parity Error has been reported via PERR#\n",
+ printk("%s: Data Parity Error has been reported via PERR#\n",
ahc_name(ahc));
}
@@ -1968,14 +1968,14 @@ ahc_pci_intr(struct ahc_softc *ahc)
status1, /*bytes*/1);
if ((status1 & (DPE|SSE|RMA|RTA|STA|DPR)) == 0) {
- printf("%s: Latched PCIERR interrupt with "
+ printk("%s: Latched PCIERR interrupt with "
"no status bits set\n", ahc_name(ahc));
} else {
ahc_outb(ahc, CLRINT, CLRPARERR);
}
if (ahc->pci_target_perr_count > AHC_PCI_TARGET_PERR_THRESH) {
- printf(
+ printk(
"%s: WARNING WARNING WARNING WARNING\n"
"%s: Too many PCI parity errors observed as a target.\n"
"%s: Some device on this bus is generating bad parity.\n"
@@ -2386,7 +2386,7 @@ ahc_aha29160C_setup(struct ahc_softc *ahc)
static int
ahc_raid_setup(struct ahc_softc *ahc)
{
- printf("RAID functionality unsupported\n");
+ printk("RAID functionality unsupported\n");
return (ENXIO);
}
@@ -2404,7 +2404,7 @@ ahc_aha394XX_setup(struct ahc_softc *ahc)
ahc->channel = 'B';
break;
default:
- printf("adapter at unexpected slot %d\n"
+ printk("adapter at unexpected slot %d\n"
"unable to map to a channel\n",
ahc_get_pci_slot(pci));
ahc->channel = 'A';
@@ -2429,7 +2429,7 @@ ahc_aha398XX_setup(struct ahc_softc *ahc)
ahc->channel = 'C';
break;
default:
- printf("adapter at unexpected slot %d\n"
+ printk("adapter at unexpected slot %d\n"
"unable to map to a channel\n",
ahc_get_pci_slot(pci));
ahc->channel = 'A';
@@ -2459,7 +2459,7 @@ ahc_aha494XX_setup(struct ahc_softc *ahc)
ahc->channel = 'D';
break;
default:
- printf("adapter at unexpected slot %d\n"
+ printk("adapter at unexpected slot %d\n"
"unable to map to a channel\n",
ahc_get_pci_slot(pci));
ahc->channel = 'A';
diff --git a/drivers/scsi/aic7xxx/aic7xxx_proc.c b/drivers/scsi/aic7xxx/aic7xxx_proc.c
index e92991a7c48..f2525f8ed1c 100644
--- a/drivers/scsi/aic7xxx/aic7xxx_proc.c
+++ b/drivers/scsi/aic7xxx/aic7xxx_proc.c
@@ -248,13 +248,13 @@ ahc_proc_write_seeprom(struct ahc_softc *ahc, char *buffer, int length)
ahc_pause(ahc);
if (length != sizeof(struct seeprom_config)) {
- printf("ahc_proc_write_seeprom: incorrect buffer size\n");
+ printk("ahc_proc_write_seeprom: incorrect buffer size\n");
goto done;
}
have_seeprom = ahc_verify_cksum((struct seeprom_config*)buffer);
if (have_seeprom == 0) {
- printf("ahc_proc_write_seeprom: cksum verification failed\n");
+ printk("ahc_proc_write_seeprom: cksum verification failed\n");
goto done;
}
@@ -290,26 +290,25 @@ ahc_proc_write_seeprom(struct ahc_softc *ahc, char *buffer, int length)
sd.sd_DI = DI_2840;
have_seeprom = TRUE;
} else {
- printf("ahc_proc_write_seeprom: unsupported adapter type\n");
+ printk("ahc_proc_write_seeprom: unsupported adapter type\n");
goto done;
}
if (!have_seeprom) {
- printf("ahc_proc_write_seeprom: No Serial EEPROM\n");
+ printk("ahc_proc_write_seeprom: No Serial EEPROM\n");
goto done;
} else {
u_int start_addr;
if (ahc->seep_config == NULL) {
- ahc->seep_config = malloc(sizeof(*ahc->seep_config),
- M_DEVBUF, M_NOWAIT);
+ ahc->seep_config = kmalloc(sizeof(*ahc->seep_config), GFP_ATOMIC);
if (ahc->seep_config == NULL) {
- printf("aic7xxx: Unable to allocate serial "
+ printk("aic7xxx: Unable to allocate serial "
"eeprom buffer. Write failing\n");
goto done;
}
}
- printf("aic7xxx: Writing Serial EEPROM\n");
+ printk("aic7xxx: Writing Serial EEPROM\n");
start_addr = 32 * (ahc->channel - 'A');
ahc_write_seeprom(&sd, (u_int16_t *)buffer, start_addr,
sizeof(struct seeprom_config)/2);
diff --git a/drivers/scsi/aic7xxx_old/aic7xxx.seq b/drivers/scsi/aic7xxx_old/aic7xxx.seq
index f6fc4b75b5a..5997e7c3a19 100644
--- a/drivers/scsi/aic7xxx_old/aic7xxx.seq
+++ b/drivers/scsi/aic7xxx_old/aic7xxx.seq
@@ -615,7 +615,7 @@ ultra2_dmafifoflush:
* went empty and the next bit of data is copied from
* the SCSI fifo into the PCI fifo. It should only
* come on when both FIFOs (meaning the entire FIFO
- * chain) are emtpy. Since it can take up to 4 cycles
+ * chain) are empty. Since it can take up to 4 cycles
* for new data to be copied from the SCSI fifo into
* the PCI fifo, testing for FIFOEMP status for 4
* extra times gives the needed time for any
diff --git a/drivers/scsi/aic94xx/aic94xx_seq.c b/drivers/scsi/aic94xx/aic94xx_seq.c
index d01dcc62b39..74374618010 100644
--- a/drivers/scsi/aic94xx/aic94xx_seq.c
+++ b/drivers/scsi/aic94xx/aic94xx_seq.c
@@ -588,7 +588,7 @@ static void asd_init_cseq_mdp(struct asd_ha_struct *asd_ha)
* asd_init_cseq_scratch -- setup and init CSEQ
* @asd_ha: pointer to host adapter structure
*
- * Setup and initialize Central sequencers. Initialiaze the mode
+ * Setup and initialize Central sequencers. Initialize the mode
* independent and dependent scratch page to the default settings.
*/
static void asd_init_cseq_scratch(struct asd_ha_struct *asd_ha)
@@ -782,7 +782,7 @@ static void asd_init_lseq_mdp(struct asd_ha_struct *asd_ha, int lseq)
asd_write_reg_word(asd_ha, LmSEQ_OOB_INT_ENABLES(lseq), 0);
/*
* Set the desired interval between transmissions of the NOTIFY
- * (ENABLE SPINUP) primitive. Must be initilized to val - 1.
+ * (ENABLE SPINUP) primitive. Must be initialized to val - 1.
*/
asd_write_reg_word(asd_ha, LmSEQ_NOTIFY_TIMER_TIMEOUT(lseq),
ASD_NOTIFY_TIMEOUT - 1);
diff --git a/drivers/scsi/aic94xx/aic94xx_task.c b/drivers/scsi/aic94xx/aic94xx_task.c
index 75d20f72501..532d212b6b2 100644
--- a/drivers/scsi/aic94xx/aic94xx_task.c
+++ b/drivers/scsi/aic94xx/aic94xx_task.c
@@ -223,7 +223,7 @@ Again:
switch (opcode) {
case TC_NO_ERROR:
ts->resp = SAS_TASK_COMPLETE;
- ts->stat = SAM_GOOD;
+ ts->stat = SAM_STAT_GOOD;
break;
case TC_UNDERRUN:
ts->resp = SAS_TASK_COMPLETE;
diff --git a/drivers/scsi/arcmsr/arcmsr.h b/drivers/scsi/arcmsr/arcmsr.h
index ce5371b3cdd..475c31ae985 100644
--- a/drivers/scsi/arcmsr/arcmsr.h
+++ b/drivers/scsi/arcmsr/arcmsr.h
@@ -43,21 +43,27 @@
*******************************************************************************
*/
#include <linux/interrupt.h>
-
struct device_attribute;
/*The limit of outstanding scsi command that firmware can handle*/
#define ARCMSR_MAX_OUTSTANDING_CMD 256
#define ARCMSR_MAX_FREECCB_NUM 320
-#define ARCMSR_DRIVER_VERSION "Driver Version 1.20.00.15 2008/11/03"
+#define ARCMSR_DRIVER_VERSION "Driver Version 1.20.00.15 2010/02/02"
#define ARCMSR_SCSI_INITIATOR_ID 255
#define ARCMSR_MAX_XFER_SECTORS 512
#define ARCMSR_MAX_XFER_SECTORS_B 4096
+#define ARCMSR_MAX_XFER_SECTORS_C 304
#define ARCMSR_MAX_TARGETID 17
#define ARCMSR_MAX_TARGETLUN 8
#define ARCMSR_MAX_CMD_PERLUN ARCMSR_MAX_OUTSTANDING_CMD
#define ARCMSR_MAX_QBUFFER 4096
-#define ARCMSR_MAX_SG_ENTRIES 38
+#define ARCMSR_DEFAULT_SG_ENTRIES 38
#define ARCMSR_MAX_HBB_POSTQUEUE 264
+#define ARCMSR_MAX_XFER_LEN 0x26000 /* 152K */
+#define ARCMSR_CDB_SG_PAGE_LENGTH 256
+#define SCSI_CMD_ARECA_SPECIFIC 0xE1
+#ifndef PCI_DEVICE_ID_ARECA_1880
+#define PCI_DEVICE_ID_ARECA_1880 0x1880
+ #endif
/*
**********************************************************************************
**
@@ -132,35 +138,28 @@ struct CMD_MESSAGE_FIELD
#define ARCMSR_MESSAGE_FLUSH_ADAPTER_CACHE \
ARECA_SATA_RAID | FUNCTION_FLUSH_ADAPTER_CACHE
/* ARECA IOCTL ReturnCode */
-#define ARCMSR_MESSAGE_RETURNCODE_OK 0x00000001
-#define ARCMSR_MESSAGE_RETURNCODE_ERROR 0x00000006
-#define ARCMSR_MESSAGE_RETURNCODE_3F 0x0000003F
+#define ARCMSR_MESSAGE_RETURNCODE_OK 0x00000001
+#define ARCMSR_MESSAGE_RETURNCODE_ERROR 0x00000006
+#define ARCMSR_MESSAGE_RETURNCODE_3F 0x0000003F
#define ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON 0x00000088
/*
*************************************************************
** structure for holding DMA address data
*************************************************************
*/
+#define IS_DMA64 (sizeof(dma_addr_t) == 8)
#define IS_SG64_ADDR 0x01000000 /* bit24 */
struct SG32ENTRY
{
__le32 length;
__le32 address;
-};
+}__attribute__ ((packed));
struct SG64ENTRY
{
__le32 length;
__le32 address;
__le32 addresshigh;
-};
-struct SGENTRY_UNION
-{
- union
- {
- struct SG32ENTRY sg32entry;
- struct SG64ENTRY sg64entry;
- }u;
-};
+}__attribute__ ((packed));
/*
********************************************************************
** Q Buffer of IOP Message Transfer
@@ -187,6 +186,9 @@ struct FIRMWARE_INFO
char model[8]; /*15, 60-67*/
char firmware_ver[16]; /*17, 68-83*/
char device_map[16]; /*21, 84-99*/
+ uint32_t cfgVersion; /*25,100-103 Added for checking of new firmware capability*/
+ uint8_t cfgSerial[16]; /*26,104-119*/
+ uint32_t cfgPicStatus; /*30,120-123*/
};
/* signature of set and get firmware config */
#define ARCMSR_SIGNATURE_GET_CONFIG 0x87974060
@@ -210,9 +212,15 @@ struct FIRMWARE_INFO
#define ARCMSR_CCBPOST_FLAG_SGL_BSIZE 0x80000000
#define ARCMSR_CCBPOST_FLAG_IAM_BIOS 0x40000000
#define ARCMSR_CCBREPLY_FLAG_IAM_BIOS 0x40000000
-#define ARCMSR_CCBREPLY_FLAG_ERROR 0x10000000
+#define ARCMSR_CCBREPLY_FLAG_ERROR_MODE0 0x10000000
+#define ARCMSR_CCBREPLY_FLAG_ERROR_MODE1 0x00000001
/* outbound firmware ok */
#define ARCMSR_OUTBOUND_MESG1_FIRMWARE_OK 0x80000000
+/* ARC-1680 Bus Reset*/
+#define ARCMSR_ARC1680_BUS_RESET 0x00000003
+/* ARC-1880 Bus Reset*/
+#define ARCMSR_ARC1880_RESET_ADAPTER 0x00000024
+#define ARCMSR_ARC1880_DiagWrite_ENABLE 0x00000080
/*
************************************************************************
@@ -264,11 +272,66 @@ struct FIRMWARE_INFO
/* data tunnel buffer between user space program and its firmware */
/* user space data to iop 128bytes */
-#define ARCMSR_IOCTL_WBUFFER 0x0000fe00
+#define ARCMSR_MESSAGE_WBUFFER 0x0000fe00
/* iop data to user space 128bytes */
-#define ARCMSR_IOCTL_RBUFFER 0x0000ff00
+#define ARCMSR_MESSAGE_RBUFFER 0x0000ff00
/* iop message_rwbuffer for message command */
-#define ARCMSR_MSGCODE_RWBUFFER 0x0000fa00
+#define ARCMSR_MESSAGE_RWBUFFER 0x0000fa00
+/*
+************************************************************************
+** SPEC. for Areca HBC adapter
+************************************************************************
+*/
+#define ARCMSR_HBC_ISR_THROTTLING_LEVEL 12
+#define ARCMSR_HBC_ISR_MAX_DONE_QUEUE 20
+/* Host Interrupt Mask */
+#define ARCMSR_HBCMU_UTILITY_A_ISR_MASK 0x00000001 /* When clear, the Utility_A interrupt routes to the host.*/
+#define ARCMSR_HBCMU_OUTBOUND_DOORBELL_ISR_MASK 0x00000004 /* When clear, the General Outbound Doorbell interrupt routes to the host.*/
+#define ARCMSR_HBCMU_OUTBOUND_POSTQUEUE_ISR_MASK 0x00000008 /* When clear, the Outbound Post List FIFO Not Empty interrupt routes to the host.*/
+#define ARCMSR_HBCMU_ALL_INTMASKENABLE 0x0000000D /* disable all ISR */
+/* Host Interrupt Status */
+#define ARCMSR_HBCMU_UTILITY_A_ISR 0x00000001
+ /*
+ ** Set when the Utility_A Interrupt bit is set in the Outbound Doorbell Register.
+ ** It clears by writing a 1 to the Utility_A bit in the Outbound Doorbell Clear Register or through automatic clearing (if enabled).
+ */
+#define ARCMSR_HBCMU_OUTBOUND_DOORBELL_ISR 0x00000004
+ /*
+ ** Set if Outbound Doorbell register bits 30:1 have a non-zero
+ ** value. This bit clears only when Outbound Doorbell bits
+ ** 30:1 are ALL clear. Only a write to the Outbound Doorbell
+ ** Clear register clears bits in the Outbound Doorbell register.
+ */
+#define ARCMSR_HBCMU_OUTBOUND_POSTQUEUE_ISR 0x00000008
+ /*
+ ** Set whenever the Outbound Post List Producer/Consumer
+ ** Register (FIFO) is not empty. It clears when the Outbound
+ ** Post List FIFO is empty.
+ */
+#define ARCMSR_HBCMU_SAS_ALL_INT 0x00000010
+ /*
+ ** This bit indicates a SAS interrupt from a source external to
+ ** the PCIe core. This bit is not maskable.
+ */
+ /* DoorBell*/
+#define ARCMSR_HBCMU_DRV2IOP_DATA_WRITE_OK 0x00000002
+#define ARCMSR_HBCMU_DRV2IOP_DATA_READ_OK 0x00000004
+ /*inbound message 0 ready*/
+#define ARCMSR_HBCMU_DRV2IOP_MESSAGE_CMD_DONE 0x00000008
+ /*more than 12 request completed in a time*/
+#define ARCMSR_HBCMU_DRV2IOP_POSTQUEUE_THROTTLING 0x00000010
+#define ARCMSR_HBCMU_IOP2DRV_DATA_WRITE_OK 0x00000002
+ /*outbound DATA WRITE isr door bell clear*/
+#define ARCMSR_HBCMU_IOP2DRV_DATA_WRITE_DOORBELL_CLEAR 0x00000002
+#define ARCMSR_HBCMU_IOP2DRV_DATA_READ_OK 0x00000004
+ /*outbound DATA READ isr door bell clear*/
+#define ARCMSR_HBCMU_IOP2DRV_DATA_READ_DOORBELL_CLEAR 0x00000004
+ /*outbound message 0 ready*/
+#define ARCMSR_HBCMU_IOP2DRV_MESSAGE_CMD_DONE 0x00000008
+ /*outbound message cmd isr door bell clear*/
+#define ARCMSR_HBCMU_IOP2DRV_MESSAGE_CMD_DONE_DOORBELL_CLEAR 0x00000008
+ /*ARCMSR_HBAMU_MESSAGE_FIRMWARE_OK*/
+#define ARCMSR_HBCMU_MESSAGE_FIRMWARE_OK 0x80000000
/*
*******************************************************************************
** ARECA SCSI COMMAND DESCRIPTOR BLOCK size 0x1F8 (504)
@@ -290,7 +353,7 @@ struct ARCMSR_CDB
#define ARCMSR_CDB_FLAG_HEADQ 0x08
#define ARCMSR_CDB_FLAG_ORDEREDQ 0x10
- uint8_t Reserved1;
+ uint8_t msgPages;
uint32_t Context;
uint32_t DataLength;
uint8_t Cdb[16];
@@ -303,8 +366,8 @@ struct ARCMSR_CDB
uint8_t SenseData[15];
union
{
- struct SG32ENTRY sg32entry[ARCMSR_MAX_SG_ENTRIES];
- struct SG64ENTRY sg64entry[ARCMSR_MAX_SG_ENTRIES];
+ struct SG32ENTRY sg32entry[1];
+ struct SG64ENTRY sg64entry[1];
} u;
};
/*
@@ -344,15 +407,89 @@ struct MessageUnit_B
uint32_t done_qbuffer[ARCMSR_MAX_HBB_POSTQUEUE];
uint32_t postq_index;
uint32_t doneq_index;
- uint32_t __iomem *drv2iop_doorbell_reg;
- uint32_t __iomem *drv2iop_doorbell_mask_reg;
- uint32_t __iomem *iop2drv_doorbell_reg;
- uint32_t __iomem *iop2drv_doorbell_mask_reg;
- uint32_t __iomem *msgcode_rwbuffer_reg;
- uint32_t __iomem *ioctl_wbuffer_reg;
- uint32_t __iomem *ioctl_rbuffer_reg;
+ uint32_t __iomem *drv2iop_doorbell;
+ uint32_t __iomem *drv2iop_doorbell_mask;
+ uint32_t __iomem *iop2drv_doorbell;
+ uint32_t __iomem *iop2drv_doorbell_mask;
+ uint32_t __iomem *message_rwbuffer;
+ uint32_t __iomem *message_wbuffer;
+ uint32_t __iomem *message_rbuffer;
+};
+/*
+*********************************************************************
+** LSI
+*********************************************************************
+*/
+struct MessageUnit_C{
+ uint32_t message_unit_status; /*0000 0003*/
+ uint32_t slave_error_attribute; /*0004 0007*/
+ uint32_t slave_error_address; /*0008 000B*/
+ uint32_t posted_outbound_doorbell; /*000C 000F*/
+ uint32_t master_error_attribute; /*0010 0013*/
+ uint32_t master_error_address_low; /*0014 0017*/
+ uint32_t master_error_address_high; /*0018 001B*/
+ uint32_t hcb_size; /*001C 001F*/
+ uint32_t inbound_doorbell; /*0020 0023*/
+ uint32_t diagnostic_rw_data; /*0024 0027*/
+ uint32_t diagnostic_rw_address_low; /*0028 002B*/
+ uint32_t diagnostic_rw_address_high; /*002C 002F*/
+ uint32_t host_int_status; /*0030 0033*/
+ uint32_t host_int_mask; /*0034 0037*/
+ uint32_t dcr_data; /*0038 003B*/
+ uint32_t dcr_address; /*003C 003F*/
+ uint32_t inbound_queueport; /*0040 0043*/
+ uint32_t outbound_queueport; /*0044 0047*/
+ uint32_t hcb_pci_address_low; /*0048 004B*/
+ uint32_t hcb_pci_address_high; /*004C 004F*/
+ uint32_t iop_int_status; /*0050 0053*/
+ uint32_t iop_int_mask; /*0054 0057*/
+ uint32_t iop_inbound_queue_port; /*0058 005B*/
+ uint32_t iop_outbound_queue_port; /*005C 005F*/
+ uint32_t inbound_free_list_index; /*0060 0063*/
+ uint32_t inbound_post_list_index; /*0064 0067*/
+ uint32_t outbound_free_list_index; /*0068 006B*/
+ uint32_t outbound_post_list_index; /*006C 006F*/
+ uint32_t inbound_doorbell_clear; /*0070 0073*/
+ uint32_t i2o_message_unit_control; /*0074 0077*/
+ uint32_t last_used_message_source_address_low; /*0078 007B*/
+ uint32_t last_used_message_source_address_high; /*007C 007F*/
+ uint32_t pull_mode_data_byte_count[4]; /*0080 008F*/
+ uint32_t message_dest_address_index; /*0090 0093*/
+ uint32_t done_queue_not_empty_int_counter_timer; /*0094 0097*/
+ uint32_t utility_A_int_counter_timer; /*0098 009B*/
+ uint32_t outbound_doorbell; /*009C 009F*/
+ uint32_t outbound_doorbell_clear; /*00A0 00A3*/
+ uint32_t message_source_address_index; /*00A4 00A7*/
+ uint32_t message_done_queue_index; /*00A8 00AB*/
+ uint32_t reserved0; /*00AC 00AF*/
+ uint32_t inbound_msgaddr0; /*00B0 00B3*/
+ uint32_t inbound_msgaddr1; /*00B4 00B7*/
+ uint32_t outbound_msgaddr0; /*00B8 00BB*/
+ uint32_t outbound_msgaddr1; /*00BC 00BF*/
+ uint32_t inbound_queueport_low; /*00C0 00C3*/
+ uint32_t inbound_queueport_high; /*00C4 00C7*/
+ uint32_t outbound_queueport_low; /*00C8 00CB*/
+ uint32_t outbound_queueport_high; /*00CC 00CF*/
+ uint32_t iop_inbound_queue_port_low; /*00D0 00D3*/
+ uint32_t iop_inbound_queue_port_high; /*00D4 00D7*/
+ uint32_t iop_outbound_queue_port_low; /*00D8 00DB*/
+ uint32_t iop_outbound_queue_port_high; /*00DC 00DF*/
+ uint32_t message_dest_queue_port_low; /*00E0 00E3*/
+ uint32_t message_dest_queue_port_high; /*00E4 00E7*/
+ uint32_t last_used_message_dest_address_low; /*00E8 00EB*/
+ uint32_t last_used_message_dest_address_high; /*00EC 00EF*/
+ uint32_t message_done_queue_base_address_low; /*00F0 00F3*/
+ uint32_t message_done_queue_base_address_high; /*00F4 00F7*/
+ uint32_t host_diagnostic; /*00F8 00FB*/
+ uint32_t write_sequence; /*00FC 00FF*/
+ uint32_t reserved1[34]; /*0100 0187*/
+ uint32_t reserved2[1950]; /*0188 1FFF*/
+ uint32_t message_wbuffer[32]; /*2000 207F*/
+ uint32_t reserved3[32]; /*2080 20FF*/
+ uint32_t message_rbuffer[32]; /*2100 217F*/
+ uint32_t reserved4[32]; /*2180 21FF*/
+ uint32_t msgcode_rwbuffer[256]; /*2200 23FF*/
};
-
/*
*******************************************************************************
** Adapter Control Block
@@ -370,14 +507,20 @@ struct AdapterControlBlock
unsigned long vir2phy_offset;
/* Offset is used in making arc cdb physical to virtual calculations */
uint32_t outbound_int_enable;
-
+ uint32_t cdb_phyaddr_hi32;
+ uint32_t reg_mu_acc_handle0;
+ spinlock_t eh_lock;
+ spinlock_t ccblist_lock;
union {
- struct MessageUnit_A __iomem * pmuA;
- struct MessageUnit_B * pmuB;
+ struct MessageUnit_A __iomem *pmuA;
+ struct MessageUnit_B *pmuB;
+ struct MessageUnit_C __iomem *pmuC;
};
/* message unit ATU inbound base address0 */
-
+ void __iomem *mem_base0;
+ void __iomem *mem_base1;
uint32_t acb_flags;
+ u16 dev_id;
uint8_t adapter_index;
#define ACB_F_SCSISTOPADAPTER 0x0001
#define ACB_F_MSG_STOP_BGRB 0x0002
@@ -392,8 +535,11 @@ struct AdapterControlBlock
/* message clear rqbuffer */
#define ACB_F_MESSAGE_WQBUFFER_READED 0x0040
#define ACB_F_BUS_RESET 0x0080
+ #define ACB_F_BUS_HANG_ON 0x0800/* need hardware reset bus */
+
#define ACB_F_IOP_INITED 0x0100
/* iop init */
+ #define ACB_F_ABORT 0x0200
#define ACB_F_FIRMWARE_TRAP 0x0400
struct CommandControlBlock * pccb_pool[ARCMSR_MAX_FREECCB_NUM];
/* used for memory free */
@@ -408,7 +554,8 @@ struct AdapterControlBlock
/* dma_coherent used for memory free */
dma_addr_t dma_coherent_handle;
/* dma_coherent_handle used for memory free */
-
+ dma_addr_t dma_coherent_handle_hbb_mu;
+ unsigned int uncache_size;
uint8_t rqbuffer[ARCMSR_MAX_QBUFFER];
/* data collection buffer for read from 80331 */
int32_t rqbuf_firstindex;
@@ -432,14 +579,18 @@ struct AdapterControlBlock
uint32_t firm_numbers_queue;
uint32_t firm_sdram_size;
uint32_t firm_hd_channels;
- char firm_model[12];
- char firm_version[20];
+ uint32_t firm_cfg_version;
+ char firm_model[12];
+ char firm_version[20];
char device_map[20]; /*21,84-99*/
struct work_struct arcmsr_do_message_isr_bh;
struct timer_list eternal_timer;
- unsigned short fw_state;
+ unsigned short fw_flag;
+ #define FW_NORMAL 0x0000
+ #define FW_BOG 0x0001
+ #define FW_DEADLOCK 0x0010
atomic_t rq_map_token;
- int ante_token_value;
+ atomic_t ante_token_value;
};/* HW_DEVICE_EXTENSION */
/*
*******************************************************************************
@@ -447,67 +598,33 @@ struct AdapterControlBlock
** this CCB length must be 32 bytes boundary
*******************************************************************************
*/
-struct CommandControlBlock
-{
- struct ARCMSR_CDB arcmsr_cdb;
- /*
- ** 0-503 (size of CDB = 504):
- ** arcmsr messenger scsi command descriptor size 504 bytes
- */
- uint32_t cdb_shifted_phyaddr;
- /* 504-507 */
- uint32_t reserved1;
- /* 508-511 */
-#if BITS_PER_LONG == 64
+struct CommandControlBlock{
+ /*x32:sizeof struct_CCB=(32+60)byte, x64:sizeof struct_CCB=(64+60)byte*/
+ struct list_head list; /*x32: 8byte, x64: 16byte*/
+ struct scsi_cmnd *pcmd; /*8 bytes pointer of linux scsi command */
+ struct AdapterControlBlock *acb; /*x32: 4byte, x64: 8byte*/
+ uint32_t cdb_phyaddr_pattern; /*x32: 4byte, x64: 4byte*/
+ uint32_t arc_cdb_size; /*x32:4byte,x64:4byte*/
+ uint16_t ccb_flags; /*x32: 2byte, x64: 2byte*/
+ #define CCB_FLAG_READ 0x0000
+ #define CCB_FLAG_WRITE 0x0001
+ #define CCB_FLAG_ERROR 0x0002
+ #define CCB_FLAG_FLUSHCACHE 0x0004
+ #define CCB_FLAG_MASTER_ABORTED 0x0008
+ uint16_t startdone; /*x32:2byte,x32:2byte*/
+ #define ARCMSR_CCB_DONE 0x0000
+ #define ARCMSR_CCB_START 0x55AA
+ #define ARCMSR_CCB_ABORTED 0xAA55
+ #define ARCMSR_CCB_ILLEGAL 0xFFFF
+ #if BITS_PER_LONG == 64
/* ======================512+64 bytes======================== */
- struct list_head list;
- /* 512-527 16 bytes next/prev ptrs for ccb lists */
- struct scsi_cmnd * pcmd;
- /* 528-535 8 bytes pointer of linux scsi command */
- struct AdapterControlBlock * acb;
- /* 536-543 8 bytes pointer of acb */
-
- uint16_t ccb_flags;
- /* 544-545 */
- #define CCB_FLAG_READ 0x0000
- #define CCB_FLAG_WRITE 0x0001
- #define CCB_FLAG_ERROR 0x0002
- #define CCB_FLAG_FLUSHCACHE 0x0004
- #define CCB_FLAG_MASTER_ABORTED 0x0008
- uint16_t startdone;
- /* 546-547 */
- #define ARCMSR_CCB_DONE 0x0000
- #define ARCMSR_CCB_START 0x55AA
- #define ARCMSR_CCB_ABORTED 0xAA55
- #define ARCMSR_CCB_ILLEGAL 0xFFFF
- uint32_t reserved2[7];
- /* 548-551 552-555 556-559 560-563 564-567 568-571 572-575 */
-#else
+ uint32_t reserved[5]; /*24 byte*/
+ #else
/* ======================512+32 bytes======================== */
- struct list_head list;
- /* 512-519 8 bytes next/prev ptrs for ccb lists */
- struct scsi_cmnd * pcmd;
- /* 520-523 4 bytes pointer of linux scsi command */
- struct AdapterControlBlock * acb;
- /* 524-527 4 bytes pointer of acb */
-
- uint16_t ccb_flags;
- /* 528-529 */
- #define CCB_FLAG_READ 0x0000
- #define CCB_FLAG_WRITE 0x0001
- #define CCB_FLAG_ERROR 0x0002
- #define CCB_FLAG_FLUSHCACHE 0x0004
- #define CCB_FLAG_MASTER_ABORTED 0x0008
- uint16_t startdone;
- /* 530-531 */
- #define ARCMSR_CCB_DONE 0x0000
- #define ARCMSR_CCB_START 0x55AA
- #define ARCMSR_CCB_ABORTED 0xAA55
- #define ARCMSR_CCB_ILLEGAL 0xFFFF
- uint32_t reserved2[3];
- /* 532-535 536-539 540-543 */
-#endif
- /* ========================================================== */
+ uint32_t reserved; /*8 byte*/
+ #endif
+ /* ======================================================= */
+ struct ARCMSR_CDB arcmsr_cdb;
};
/*
*******************************************************************************
diff --git a/drivers/scsi/arcmsr/arcmsr_attr.c b/drivers/scsi/arcmsr/arcmsr_attr.c
index 07fdfe57e38..a4e04c50c43 100644
--- a/drivers/scsi/arcmsr/arcmsr_attr.c
+++ b/drivers/scsi/arcmsr/arcmsr_attr.c
@@ -192,7 +192,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,
@@ -202,7 +201,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,
@@ -212,7 +210,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 ffa54792bb3..95a895dd4f1 100644
--- a/drivers/scsi/arcmsr/arcmsr_hba.c
+++ b/drivers/scsi/arcmsr/arcmsr_hba.c
@@ -58,7 +58,6 @@
#include <linux/timer.h>
#include <linux/pci.h>
#include <linux/aer.h>
-#include <linux/slab.h>
#include <asm/dma.h>
#include <asm/io.h>
#include <asm/system.h>
@@ -71,20 +70,13 @@
#include <scsi/scsi_transport.h>
#include <scsi/scsicam.h>
#include "arcmsr.h"
-
-#ifdef CONFIG_SCSI_ARCMSR_RESET
- static int sleeptime = 20;
- static int retrycount = 12;
- module_param(sleeptime, int, S_IRUGO|S_IWUSR);
- MODULE_PARM_DESC(sleeptime, "The waiting period for FW ready while bus reset");
- module_param(retrycount, int, S_IRUGO|S_IWUSR);
- MODULE_PARM_DESC(retrycount, "The retry count for FW ready while bus reset");
-#endif
-MODULE_AUTHOR("Erich Chen <support@areca.com.tw>");
-MODULE_DESCRIPTION("ARECA (ARC11xx/12xx/13xx/16xx) SATA/SAS RAID Host Bus Adapter");
+MODULE_AUTHOR("Nick Cheng <support@areca.com.tw>");
+MODULE_DESCRIPTION("ARECA (ARC11xx/12xx/16xx/1880) SATA/SAS RAID Host Bus Adapter");
MODULE_LICENSE("Dual BSD/GPL");
MODULE_VERSION(ARCMSR_DRIVER_VERSION);
-
+static int sleeptime = 10;
+static int retrycount = 30;
+wait_queue_head_t wait_q;
static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb,
struct scsi_cmnd *cmd);
static int arcmsr_iop_confirm(struct AdapterControlBlock *acb);
@@ -107,10 +99,12 @@ static void arcmsr_flush_hbb_cache(struct AdapterControlBlock *acb);
static void arcmsr_request_device_map(unsigned long pacb);
static void arcmsr_request_hba_device_map(struct AdapterControlBlock *acb);
static void arcmsr_request_hbb_device_map(struct AdapterControlBlock *acb);
+static void arcmsr_request_hbc_device_map(struct AdapterControlBlock *acb);
static void arcmsr_message_isr_bh_fn(struct work_struct *work);
-static void *arcmsr_get_firmware_spec(struct AdapterControlBlock *acb, int mode);
+static bool arcmsr_get_firmware_spec(struct AdapterControlBlock *acb);
static void arcmsr_start_adapter_bgrb(struct AdapterControlBlock *acb);
-
+static void arcmsr_hbc_message_isr(struct AdapterControlBlock *pACB);
+static void arcmsr_hardware_reset(struct AdapterControlBlock *acb);
static const char *arcmsr_info(struct Scsi_Host *);
static irqreturn_t arcmsr_interrupt(struct AdapterControlBlock *acb);
static int arcmsr_adjust_disk_queue_depth(struct scsi_device *sdev,
@@ -127,18 +121,18 @@ static int arcmsr_adjust_disk_queue_depth(struct scsi_device *sdev,
static struct scsi_host_template arcmsr_scsi_host_template = {
.module = THIS_MODULE,
- .name = "ARCMSR ARECA SATA/SAS RAID Host Bus Adapter"
- ARCMSR_DRIVER_VERSION,
+ .name = "ARCMSR ARECA SATA/SAS RAID Controller"
+ ARCMSR_DRIVER_VERSION,
.info = arcmsr_info,
.queuecommand = arcmsr_queue_command,
- .eh_abort_handler = arcmsr_abort,
+ .eh_abort_handler = arcmsr_abort,
.eh_bus_reset_handler = arcmsr_bus_reset,
.bios_param = arcmsr_bios_param,
.change_queue_depth = arcmsr_adjust_disk_queue_depth,
- .can_queue = ARCMSR_MAX_OUTSTANDING_CMD,
- .this_id = ARCMSR_SCSI_INITIATOR_ID,
- .sg_tablesize = ARCMSR_MAX_SG_ENTRIES,
- .max_sectors = ARCMSR_MAX_XFER_SECTORS,
+ .can_queue = ARCMSR_MAX_FREECCB_NUM,
+ .this_id = ARCMSR_SCSI_INITIATOR_ID,
+ .sg_tablesize = ARCMSR_DEFAULT_SG_ENTRIES,
+ .max_sectors = ARCMSR_MAX_XFER_SECTORS_C,
.cmd_per_lun = ARCMSR_MAX_CMD_PERLUN,
.use_clustering = ENABLE_CLUSTERING,
.shost_attrs = arcmsr_host_attrs,
@@ -162,26 +156,125 @@ static struct pci_device_id arcmsr_device_id_table[] = {
{PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1381)},
{PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1680)},
{PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1681)},
+ {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1880)},
{0, 0}, /* Terminating entry */
};
MODULE_DEVICE_TABLE(pci, arcmsr_device_id_table);
static struct pci_driver arcmsr_pci_driver = {
.name = "arcmsr",
- .id_table = arcmsr_device_id_table,
+ .id_table = arcmsr_device_id_table,
.probe = arcmsr_probe,
.remove = arcmsr_remove,
.shutdown = arcmsr_shutdown,
};
+/*
+****************************************************************************
+****************************************************************************
+*/
+int arcmsr_sleep_for_bus_reset(struct scsi_cmnd *cmd)
+{
+ struct Scsi_Host *shost = NULL;
+ int i, isleep;
+ shost = cmd->device->host;
+ isleep = sleeptime / 10;
+ if (isleep > 0) {
+ for (i = 0; i < isleep; i++) {
+ msleep(10000);
+ }
+ }
+
+ isleep = sleeptime % 10;
+ if (isleep > 0) {
+ msleep(isleep*1000);
+ }
+ printk(KERN_NOTICE "wake-up\n");
+ return 0;
+}
+
+static void arcmsr_free_hbb_mu(struct AdapterControlBlock *acb)
+{
+ switch (acb->adapter_type) {
+ case ACB_ADAPTER_TYPE_A:
+ case ACB_ADAPTER_TYPE_C:
+ break;
+ case ACB_ADAPTER_TYPE_B:{
+ dma_free_coherent(&acb->pdev->dev,
+ sizeof(struct MessageUnit_B),
+ acb->pmuB, acb->dma_coherent_handle_hbb_mu);
+ }
+ }
+}
+
+static bool arcmsr_remap_pciregion(struct AdapterControlBlock *acb)
+{
+ struct pci_dev *pdev = acb->pdev;
+ switch (acb->adapter_type){
+ case ACB_ADAPTER_TYPE_A:{
+ acb->pmuA = ioremap(pci_resource_start(pdev,0), pci_resource_len(pdev,0));
+ if (!acb->pmuA) {
+ printk(KERN_NOTICE "arcmsr%d: memory mapping region fail \n", acb->host->host_no);
+ return false;
+ }
+ break;
+ }
+ case ACB_ADAPTER_TYPE_B:{
+ void __iomem *mem_base0, *mem_base1;
+ mem_base0 = ioremap(pci_resource_start(pdev, 0), pci_resource_len(pdev, 0));
+ if (!mem_base0) {
+ printk(KERN_NOTICE "arcmsr%d: memory mapping region fail \n", acb->host->host_no);
+ return false;
+ }
+ mem_base1 = ioremap(pci_resource_start(pdev, 2), pci_resource_len(pdev, 2));
+ if (!mem_base1) {
+ iounmap(mem_base0);
+ printk(KERN_NOTICE "arcmsr%d: memory mapping region fail \n", acb->host->host_no);
+ return false;
+ }
+ acb->mem_base0 = mem_base0;
+ acb->mem_base1 = mem_base1;
+ break;
+ }
+ case ACB_ADAPTER_TYPE_C:{
+ acb->pmuC = ioremap_nocache(pci_resource_start(pdev, 1), pci_resource_len(pdev, 1));
+ if (!acb->pmuC) {
+ printk(KERN_NOTICE "arcmsr%d: memory mapping region fail \n", acb->host->host_no);
+ return false;
+ }
+ if (readl(&acb->pmuC->outbound_doorbell) & ARCMSR_HBCMU_IOP2DRV_MESSAGE_CMD_DONE) {
+ writel(ARCMSR_HBCMU_IOP2DRV_MESSAGE_CMD_DONE_DOORBELL_CLEAR, &acb->pmuC->outbound_doorbell_clear);/*clear interrupt*/
+ return true;
+ }
+ break;
+ }
+ }
+ return true;
+}
+
+static void arcmsr_unmap_pciregion(struct AdapterControlBlock *acb)
+{
+ switch (acb->adapter_type) {
+ case ACB_ADAPTER_TYPE_A:{
+ iounmap(acb->pmuA);
+ }
+ break;
+ case ACB_ADAPTER_TYPE_B:{
+ iounmap(acb->mem_base0);
+ iounmap(acb->mem_base1);
+ }
+
+ break;
+ case ACB_ADAPTER_TYPE_C:{
+ iounmap(acb->pmuC);
+ }
+ }
+}
static irqreturn_t arcmsr_do_interrupt(int irq, void *dev_id)
{
irqreturn_t handle_state;
struct AdapterControlBlock *acb = dev_id;
- spin_lock(acb->host->host_lock);
handle_state = arcmsr_interrupt(acb);
- spin_unlock(acb->host->host_lock);
-
return handle_state;
}
@@ -218,181 +311,228 @@ static void arcmsr_define_adapter_type(struct AdapterControlBlock *acb)
struct pci_dev *pdev = acb->pdev;
u16 dev_id;
pci_read_config_word(pdev, PCI_DEVICE_ID, &dev_id);
+ acb->dev_id = dev_id;
switch (dev_id) {
- case 0x1201 : {
+ case 0x1880: {
+ acb->adapter_type = ACB_ADAPTER_TYPE_C;
+ }
+ break;
+ case 0x1201: {
acb->adapter_type = ACB_ADAPTER_TYPE_B;
}
break;
- default : acb->adapter_type = ACB_ADAPTER_TYPE_A;
+ default: acb->adapter_type = ACB_ADAPTER_TYPE_A;
}
-}
+}
-static int arcmsr_alloc_ccb_pool(struct AdapterControlBlock *acb)
+static uint8_t arcmsr_hba_wait_msgint_ready(struct AdapterControlBlock *acb)
{
+ struct MessageUnit_A __iomem *reg = acb->pmuA;
+ uint32_t Index;
+ uint8_t Retries = 0x00;
+ do {
+ for (Index = 0; Index < 100; Index++) {
+ if (readl(&reg->outbound_intstatus) &
+ ARCMSR_MU_OUTBOUND_MESSAGE0_INT) {
+ writel(ARCMSR_MU_OUTBOUND_MESSAGE0_INT,
+ &reg->outbound_intstatus);
+ return true;
+ }
+ msleep(10);
+ }/*max 1 seconds*/
- switch (acb->adapter_type) {
-
- case ACB_ADAPTER_TYPE_A: {
- struct pci_dev *pdev = acb->pdev;
- void *dma_coherent;
- dma_addr_t dma_coherent_handle, dma_addr;
- struct CommandControlBlock *ccb_tmp;
- int i, j;
+ } while (Retries++ < 20);/*max 20 sec*/
+ return false;
+}
- acb->pmuA = ioremap(pci_resource_start(pdev, 0), pci_resource_len(pdev, 0));
- if (!acb->pmuA) {
- printk(KERN_NOTICE "arcmsr%d: memory mapping region fail \n",
- acb->host->host_no);
- return -ENOMEM;
- }
+static uint8_t arcmsr_hbb_wait_msgint_ready(struct AdapterControlBlock *acb)
+{
+ struct MessageUnit_B *reg = acb->pmuB;
+ uint32_t Index;
+ uint8_t Retries = 0x00;
+ do {
+ for (Index = 0; Index < 100; Index++) {
+ if (readl(reg->iop2drv_doorbell)
+ & ARCMSR_IOP2DRV_MESSAGE_CMD_DONE) {
+ writel(ARCMSR_MESSAGE_INT_CLEAR_PATTERN
+ , reg->iop2drv_doorbell);
+ writel(ARCMSR_DRV2IOP_END_OF_INTERRUPT, reg->drv2iop_doorbell);
+ return true;
+ }
+ msleep(10);
+ }/*max 1 seconds*/
- dma_coherent = dma_alloc_coherent(&pdev->dev,
- ARCMSR_MAX_FREECCB_NUM *
- sizeof (struct CommandControlBlock) + 0x20,
- &dma_coherent_handle, GFP_KERNEL);
+ } while (Retries++ < 20);/*max 20 sec*/
+ return false;
+}
- if (!dma_coherent) {
- iounmap(acb->pmuA);
- return -ENOMEM;
+static uint8_t arcmsr_hbc_wait_msgint_ready(struct AdapterControlBlock *pACB)
+{
+ struct MessageUnit_C *phbcmu = (struct MessageUnit_C *)pACB->pmuC;
+ unsigned char Retries = 0x00;
+ uint32_t Index;
+ do {
+ for (Index = 0; Index < 100; Index++) {
+ if (readl(&phbcmu->outbound_doorbell) & ARCMSR_HBCMU_IOP2DRV_MESSAGE_CMD_DONE) {
+ writel(ARCMSR_HBCMU_IOP2DRV_MESSAGE_CMD_DONE_DOORBELL_CLEAR, &phbcmu->outbound_doorbell_clear);/*clear interrupt*/
+ return true;
+ }
+ /* one us delay */
+ msleep(10);
+ } /*max 1 seconds*/
+ } while (Retries++ < 20); /*max 20 sec*/
+ return false;
+}
+static void arcmsr_flush_hba_cache(struct AdapterControlBlock *acb)
+{
+ struct MessageUnit_A __iomem *reg = acb->pmuA;
+ int retry_count = 30;
+ writel(ARCMSR_INBOUND_MESG0_FLUSH_CACHE, &reg->inbound_msgaddr0);
+ do {
+ if (arcmsr_hba_wait_msgint_ready(acb))
+ break;
+ else {
+ retry_count--;
+ printk(KERN_NOTICE "arcmsr%d: wait 'flush adapter cache' \
+ timeout, retry count down = %d \n", acb->host->host_no, retry_count);
}
+ } while (retry_count != 0);
+}
- acb->dma_coherent = dma_coherent;
- acb->dma_coherent_handle = dma_coherent_handle;
-
- if (((unsigned long)dma_coherent & 0x1F)) {
- dma_coherent = dma_coherent +
- (0x20 - ((unsigned long)dma_coherent & 0x1F));
- dma_coherent_handle = dma_coherent_handle +
- (0x20 - ((unsigned long)dma_coherent_handle & 0x1F));
+static void arcmsr_flush_hbb_cache(struct AdapterControlBlock *acb)
+{
+ struct MessageUnit_B *reg = acb->pmuB;
+ int retry_count = 30;
+ writel(ARCMSR_MESSAGE_FLUSH_CACHE, reg->drv2iop_doorbell);
+ do {
+ if (arcmsr_hbb_wait_msgint_ready(acb))
+ break;
+ else {
+ retry_count--;
+ printk(KERN_NOTICE "arcmsr%d: wait 'flush adapter cache' \
+ timeout,retry count down = %d \n", acb->host->host_no, retry_count);
}
+ } while (retry_count != 0);
+}
- dma_addr = dma_coherent_handle;
- ccb_tmp = (struct CommandControlBlock *)dma_coherent;
- for (i = 0; i < ARCMSR_MAX_FREECCB_NUM; i++) {
- ccb_tmp->cdb_shifted_phyaddr = dma_addr >> 5;
- ccb_tmp->acb = acb;
- acb->pccb_pool[i] = ccb_tmp;
- list_add_tail(&ccb_tmp->list, &acb->ccb_free_list);
- dma_addr = dma_addr + sizeof(struct CommandControlBlock);
- ccb_tmp++;
+static void arcmsr_flush_hbc_cache(struct AdapterControlBlock *pACB)
+{
+ struct MessageUnit_C *reg = (struct MessageUnit_C *)pACB->pmuC;
+ int retry_count = 30;/* enlarge wait flush adapter cache time: 10 minute */
+ writel(ARCMSR_INBOUND_MESG0_FLUSH_CACHE, &reg->inbound_msgaddr0);
+ writel(ARCMSR_HBCMU_DRV2IOP_MESSAGE_CMD_DONE, &reg->inbound_doorbell);
+ do {
+ if (arcmsr_hbc_wait_msgint_ready(pACB)) {
+ break;
+ } else {
+ retry_count--;
+ printk(KERN_NOTICE "arcmsr%d: wait 'flush adapter cache' \
+ timeout,retry count down = %d \n", pACB->host->host_no, retry_count);
}
+ } while (retry_count != 0);
+ return;
+}
+static void arcmsr_flush_adapter_cache(struct AdapterControlBlock *acb)
+{
+ switch (acb->adapter_type) {
- acb->vir2phy_offset = (unsigned long)ccb_tmp -(unsigned long)dma_addr;
- for (i = 0; i < ARCMSR_MAX_TARGETID; i++)
- for (j = 0; j < ARCMSR_MAX_TARGETLUN; j++)
- acb->devstate[i][j] = ARECA_RAID_GONE;
+ case ACB_ADAPTER_TYPE_A: {
+ arcmsr_flush_hba_cache(acb);
}
break;
case ACB_ADAPTER_TYPE_B: {
-
- struct pci_dev *pdev = acb->pdev;
- struct MessageUnit_B *reg;
- void __iomem *mem_base0, *mem_base1;
- void *dma_coherent;
- dma_addr_t dma_coherent_handle, dma_addr;
- struct CommandControlBlock *ccb_tmp;
- int i, j;
-
- dma_coherent = dma_alloc_coherent(&pdev->dev,
- ((ARCMSR_MAX_FREECCB_NUM *
- sizeof(struct CommandControlBlock) + 0x20) +
- sizeof(struct MessageUnit_B)),
- &dma_coherent_handle, GFP_KERNEL);
- if (!dma_coherent)
- return -ENOMEM;
-
- acb->dma_coherent = dma_coherent;
- acb->dma_coherent_handle = dma_coherent_handle;
-
- if (((unsigned long)dma_coherent & 0x1F)) {
- dma_coherent = dma_coherent +
- (0x20 - ((unsigned long)dma_coherent & 0x1F));
- dma_coherent_handle = dma_coherent_handle +
- (0x20 - ((unsigned long)dma_coherent_handle & 0x1F));
- }
-
- dma_addr = dma_coherent_handle;
- ccb_tmp = (struct CommandControlBlock *)dma_coherent;
- for (i = 0; i < ARCMSR_MAX_FREECCB_NUM; i++) {
- ccb_tmp->cdb_shifted_phyaddr = dma_addr >> 5;
- ccb_tmp->acb = acb;
- acb->pccb_pool[i] = ccb_tmp;
- list_add_tail(&ccb_tmp->list, &acb->ccb_free_list);
- dma_addr = dma_addr + sizeof(struct CommandControlBlock);
- ccb_tmp++;
- }
-
- reg = (struct MessageUnit_B *)(dma_coherent +
- ARCMSR_MAX_FREECCB_NUM * sizeof(struct CommandControlBlock));
- acb->pmuB = reg;
- mem_base0 = ioremap(pci_resource_start(pdev, 0),
- pci_resource_len(pdev, 0));
- if (!mem_base0)
- goto out;
-
- mem_base1 = ioremap(pci_resource_start(pdev, 2),
- pci_resource_len(pdev, 2));
- if (!mem_base1) {
- iounmap(mem_base0);
- goto out;
- }
-
- reg->drv2iop_doorbell_reg = mem_base0 + ARCMSR_DRV2IOP_DOORBELL;
- reg->drv2iop_doorbell_mask_reg = mem_base0 +
- ARCMSR_DRV2IOP_DOORBELL_MASK;
- reg->iop2drv_doorbell_reg = mem_base0 + ARCMSR_IOP2DRV_DOORBELL;
- reg->iop2drv_doorbell_mask_reg = mem_base0 +
- ARCMSR_IOP2DRV_DOORBELL_MASK;
- reg->ioctl_wbuffer_reg = mem_base1 + ARCMSR_IOCTL_WBUFFER;
- reg->ioctl_rbuffer_reg = mem_base1 + ARCMSR_IOCTL_RBUFFER;
- reg->msgcode_rwbuffer_reg = mem_base1 + ARCMSR_MSGCODE_RWBUFFER;
-
- acb->vir2phy_offset = (unsigned long)ccb_tmp -(unsigned long)dma_addr;
- for (i = 0; i < ARCMSR_MAX_TARGETID; i++)
- for (j = 0; j < ARCMSR_MAX_TARGETLUN; j++)
- acb->devstate[i][j] = ARECA_RAID_GOOD;
+ arcmsr_flush_hbb_cache(acb);
}
break;
+ case ACB_ADAPTER_TYPE_C: {
+ arcmsr_flush_hbc_cache(acb);
+ }
}
- return 0;
-
-out:
- dma_free_coherent(&acb->pdev->dev,
- (ARCMSR_MAX_FREECCB_NUM * sizeof(struct CommandControlBlock) + 0x20 +
- sizeof(struct MessageUnit_B)), acb->dma_coherent, acb->dma_coherent_handle);
- return -ENOMEM;
}
-static void arcmsr_message_isr_bh_fn(struct work_struct *work)
+
+static int arcmsr_alloc_ccb_pool(struct AdapterControlBlock *acb)
{
- struct AdapterControlBlock *acb = container_of(work, struct AdapterControlBlock, arcmsr_do_message_isr_bh);
+ struct pci_dev *pdev = acb->pdev;
+ void *dma_coherent;
+ dma_addr_t dma_coherent_handle;
+ struct CommandControlBlock *ccb_tmp;
+ int i = 0, j = 0;
+ dma_addr_t cdb_phyaddr;
+ unsigned long roundup_ccbsize = 0, offset;
+ unsigned long max_xfer_len;
+ unsigned long max_sg_entrys;
+ uint32_t firm_config_version;
+ for (i = 0; i < ARCMSR_MAX_TARGETID; i++)
+ for (j = 0; j < ARCMSR_MAX_TARGETLUN; j++)
+ acb->devstate[i][j] = ARECA_RAID_GONE;
+
+ max_xfer_len = ARCMSR_MAX_XFER_LEN;
+ max_sg_entrys = ARCMSR_DEFAULT_SG_ENTRIES;
+ firm_config_version = acb->firm_cfg_version;
+ if((firm_config_version & 0xFF) >= 3){
+ max_xfer_len = (ARCMSR_CDB_SG_PAGE_LENGTH << ((firm_config_version >> 8) & 0xFF)) * 1024;/* max 4M byte */
+ max_sg_entrys = (max_xfer_len/4096);
+ }
+ acb->host->max_sectors = max_xfer_len/512;
+ acb->host->sg_tablesize = max_sg_entrys;
+ roundup_ccbsize = roundup(sizeof(struct CommandControlBlock) + (max_sg_entrys - 1) * sizeof(struct SG64ENTRY), 32);
+ acb->uncache_size = roundup_ccbsize * ARCMSR_MAX_FREECCB_NUM + 32;
+ dma_coherent = dma_alloc_coherent(&pdev->dev, acb->uncache_size, &dma_coherent_handle, GFP_KERNEL);
+ if(!dma_coherent){
+ printk(KERN_NOTICE "arcmsr%d: dma_alloc_coherent got error \n", acb->host->host_no);
+ return -ENOMEM;
+ }
+ acb->dma_coherent = dma_coherent;
+ acb->dma_coherent_handle = dma_coherent_handle;
+ memset(dma_coherent, 0, acb->uncache_size);
+ offset = roundup((unsigned long)dma_coherent, 32) - (unsigned long)dma_coherent;
+ dma_coherent_handle = dma_coherent_handle + offset;
+ dma_coherent = (struct CommandControlBlock *)dma_coherent + offset;
+ ccb_tmp = dma_coherent;
+ acb->vir2phy_offset = (unsigned long)dma_coherent - (unsigned long)dma_coherent_handle;
+ for(i = 0; i < ARCMSR_MAX_FREECCB_NUM; i++){
+ cdb_phyaddr = dma_coherent_handle + offsetof(struct CommandControlBlock, arcmsr_cdb);
+ ccb_tmp->cdb_phyaddr_pattern = ((acb->adapter_type == ACB_ADAPTER_TYPE_C) ? cdb_phyaddr : (cdb_phyaddr >> 5));
+ acb->pccb_pool[i] = ccb_tmp;
+ ccb_tmp->acb = acb;
+ INIT_LIST_HEAD(&ccb_tmp->list);
+ list_add_tail(&ccb_tmp->list, &acb->ccb_free_list);
+ ccb_tmp = (struct CommandControlBlock *)((unsigned long)ccb_tmp + roundup_ccbsize);
+ dma_coherent_handle = dma_coherent_handle + roundup_ccbsize;
+ }
+ return 0;
+}
+static void arcmsr_message_isr_bh_fn(struct work_struct *work)
+{
+ struct AdapterControlBlock *acb = container_of(work,struct AdapterControlBlock, arcmsr_do_message_isr_bh);
switch (acb->adapter_type) {
case ACB_ADAPTER_TYPE_A: {
struct MessageUnit_A __iomem *reg = acb->pmuA;
char *acb_dev_map = (char *)acb->device_map;
- uint32_t __iomem *signature = (uint32_t __iomem *) (&reg->message_rwbuffer[0]);
- char __iomem *devicemap = (char __iomem *) (&reg->message_rwbuffer[21]);
+ uint32_t __iomem *signature = (uint32_t __iomem*) (&reg->message_rwbuffer[0]);
+ char __iomem *devicemap = (char __iomem*) (&reg->message_rwbuffer[21]);
int target, lun;
struct scsi_device *psdev;
char diff;
atomic_inc(&acb->rq_map_token);
if (readl(signature) == ARCMSR_SIGNATURE_GET_CONFIG) {
- for (target = 0; target < ARCMSR_MAX_TARGETID - 1; target++) {
+ for(target = 0; target < ARCMSR_MAX_TARGETID -1; target++) {
diff = (*acb_dev_map)^readb(devicemap);
if (diff != 0) {
char temp;
*acb_dev_map = readb(devicemap);
- temp = *acb_dev_map;
- for (lun = 0; lun < ARCMSR_MAX_TARGETLUN; lun++) {
- if ((temp & 0x01) == 1 && (diff & 0x01) == 1) {
+ temp =*acb_dev_map;
+ for(lun = 0; lun < ARCMSR_MAX_TARGETLUN; lun++) {
+ if((temp & 0x01)==1 && (diff & 0x01) == 1) {
scsi_add_device(acb->host, 0, target, lun);
- } else if ((temp & 0x01) == 0 && (diff & 0x01) == 1) {
+ }else if((temp & 0x01) == 0 && (diff & 0x01) == 1) {
psdev = scsi_device_lookup(acb->host, 0, target, lun);
- if (psdev != NULL) {
+ if (psdev != NULL ) {
scsi_remove_device(psdev);
scsi_device_put(psdev);
}
@@ -411,8 +551,45 @@ static void arcmsr_message_isr_bh_fn(struct work_struct *work)
case ACB_ADAPTER_TYPE_B: {
struct MessageUnit_B *reg = acb->pmuB;
char *acb_dev_map = (char *)acb->device_map;
- uint32_t __iomem *signature = (uint32_t __iomem *)(&reg->msgcode_rwbuffer_reg[0]);
- char __iomem *devicemap = (char __iomem *)(&reg->msgcode_rwbuffer_reg[21]);
+ uint32_t __iomem *signature = (uint32_t __iomem*)(&reg->message_rwbuffer[0]);
+ char __iomem *devicemap = (char __iomem*)(&reg->message_rwbuffer[21]);
+ int target, lun;
+ struct scsi_device *psdev;
+ char diff;
+
+ atomic_inc(&acb->rq_map_token);
+ if (readl(signature) == ARCMSR_SIGNATURE_GET_CONFIG) {
+ for(target = 0; target < ARCMSR_MAX_TARGETID -1; target++) {
+ diff = (*acb_dev_map)^readb(devicemap);
+ if (diff != 0) {
+ char temp;
+ *acb_dev_map = readb(devicemap);
+ temp =*acb_dev_map;
+ for(lun = 0; lun < ARCMSR_MAX_TARGETLUN; lun++) {
+ if((temp & 0x01)==1 && (diff & 0x01) == 1) {
+ scsi_add_device(acb->host, 0, target, lun);
+ }else if((temp & 0x01) == 0 && (diff & 0x01) == 1) {
+ psdev = scsi_device_lookup(acb->host, 0, target, lun);
+ if (psdev != NULL ) {
+ scsi_remove_device(psdev);
+ scsi_device_put(psdev);
+ }
+ }
+ temp >>= 1;
+ diff >>= 1;
+ }
+ }
+ devicemap++;
+ acb_dev_map++;
+ }
+ }
+ }
+ break;
+ case ACB_ADAPTER_TYPE_C: {
+ struct MessageUnit_C *reg = acb->pmuC;
+ char *acb_dev_map = (char *)acb->device_map;
+ uint32_t __iomem *signature = (uint32_t __iomem *)(&reg->msgcode_rwbuffer[0]);
+ char __iomem *devicemap = (char __iomem *)(&reg->msgcode_rwbuffer[21]);
int target, lun;
struct scsi_device *psdev;
char diff;
@@ -447,185 +624,152 @@ static void arcmsr_message_isr_bh_fn(struct work_struct *work)
}
}
-static int arcmsr_probe(struct pci_dev *pdev,
- const struct pci_device_id *id)
+static int arcmsr_probe(struct pci_dev *pdev, const struct pci_device_id *id)
{
struct Scsi_Host *host;
struct AdapterControlBlock *acb;
- uint8_t bus, dev_fun;
+ uint8_t bus,dev_fun;
int error;
-
error = pci_enable_device(pdev);
- if (error)
- goto out;
- pci_set_master(pdev);
-
- host = scsi_host_alloc(&arcmsr_scsi_host_template,
- sizeof(struct AdapterControlBlock));
- if (!host) {
- error = -ENOMEM;
- goto out_disable_device;
+ if(error){
+ return -ENODEV;
+ }
+ host = scsi_host_alloc(&arcmsr_scsi_host_template, sizeof(struct AdapterControlBlock));
+ if(!host){
+ goto pci_disable_dev;
}
- acb = (struct AdapterControlBlock *)host->hostdata;
- memset(acb, 0, sizeof (struct AdapterControlBlock));
-
error = pci_set_dma_mask(pdev, DMA_BIT_MASK(64));
- if (error) {
+ if(error){
error = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
- if (error) {
+ if(error){
printk(KERN_WARNING
"scsi%d: No suitable DMA mask available\n",
host->host_no);
- goto out_host_put;
+ goto scsi_host_release;
}
}
+ init_waitqueue_head(&wait_q);
bus = pdev->bus->number;
dev_fun = pdev->devfn;
- acb->host = host;
+ acb = (struct AdapterControlBlock *) host->hostdata;
+ memset(acb,0,sizeof(struct AdapterControlBlock));
acb->pdev = pdev;
- host->max_sectors = ARCMSR_MAX_XFER_SECTORS;
+ acb->host = host;
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->max_id = ARCMSR_MAX_TARGETID; /*16:8*/
+ host->max_cmd_len = 16; /*this is issue of 64bit LBA ,over 2T byte*/
+ 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;
+ pci_set_drvdata(pdev, host);
+ pci_set_master(pdev);
error = pci_request_regions(pdev, "arcmsr");
- if (error) {
- goto out_host_put;
+ if(error){
+ goto scsi_host_release;
}
- arcmsr_define_adapter_type(acb);
-
+ spin_lock_init(&acb->eh_lock);
+ spin_lock_init(&acb->ccblist_lock);
acb->acb_flags |= (ACB_F_MESSAGE_WQBUFFER_CLEARED |
- ACB_F_MESSAGE_RQBUFFER_CLEARED |
- ACB_F_MESSAGE_WQBUFFER_READED);
+ ACB_F_MESSAGE_RQBUFFER_CLEARED |
+ ACB_F_MESSAGE_WQBUFFER_READED);
acb->acb_flags &= ~ACB_F_SCSISTOPADAPTER;
INIT_LIST_HEAD(&acb->ccb_free_list);
- INIT_WORK(&acb->arcmsr_do_message_isr_bh, arcmsr_message_isr_bh_fn);
+ arcmsr_define_adapter_type(acb);
+ error = arcmsr_remap_pciregion(acb);
+ if(!error){
+ goto pci_release_regs;
+ }
+ error = arcmsr_get_firmware_spec(acb);
+ if(!error){
+ goto unmap_pci_region;
+ }
error = arcmsr_alloc_ccb_pool(acb);
- if (error)
- goto out_release_regions;
-
+ if(error){
+ goto free_hbb_mu;
+ }
arcmsr_iop_init(acb);
- error = request_irq(pdev->irq, arcmsr_do_interrupt,
- IRQF_SHARED, "arcmsr", acb);
- if (error)
- goto out_free_ccb_pool;
-
- 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)
- goto out_free_irq;
-
- error = arcmsr_alloc_sysfs_attr(acb);
- if (error)
- goto out_free_sysfs;
-
- scsi_scan_host(host);
- #ifdef CONFIG_SCSI_ARCMSR_AER
- pci_enable_pcie_error_reporting(pdev);
- #endif
+ if(error){
+ goto RAID_controller_stop;
+ }
+ error = request_irq(pdev->irq, arcmsr_do_interrupt, IRQF_SHARED, "arcmsr", acb);
+ if(error){
+ goto scsi_host_remove;
+ }
+ host->irq = pdev->irq;
+ scsi_scan_host(host);
+ INIT_WORK(&acb->arcmsr_do_message_isr_bh, arcmsr_message_isr_bh_fn);
atomic_set(&acb->rq_map_token, 16);
- acb->fw_state = true;
+ atomic_set(&acb->ante_token_value, 16);
+ acb->fw_flag = FW_NORMAL;
init_timer(&acb->eternal_timer);
- acb->eternal_timer.expires = jiffies + msecs_to_jiffies(10*HZ);
+ acb->eternal_timer.expires = jiffies + msecs_to_jiffies(6 * HZ);
acb->eternal_timer.data = (unsigned long) acb;
acb->eternal_timer.function = &arcmsr_request_device_map;
add_timer(&acb->eternal_timer);
-
+ if(arcmsr_alloc_sysfs_attr(acb))
+ goto out_free_sysfs;
return 0;
- out_free_sysfs:
- out_free_irq:
- free_irq(pdev->irq, acb);
- out_free_ccb_pool:
+out_free_sysfs:
+scsi_host_remove:
+ scsi_remove_host(host);
+RAID_controller_stop:
+ arcmsr_stop_adapter_bgrb(acb);
+ arcmsr_flush_adapter_cache(acb);
arcmsr_free_ccb_pool(acb);
- out_release_regions:
+free_hbb_mu:
+ arcmsr_free_hbb_mu(acb);
+unmap_pci_region:
+ arcmsr_unmap_pciregion(acb);
+pci_release_regs:
pci_release_regions(pdev);
- out_host_put:
+scsi_host_release:
scsi_host_put(host);
- out_disable_device:
+pci_disable_dev:
pci_disable_device(pdev);
- out:
- return error;
-}
-
-static uint8_t arcmsr_hba_wait_msgint_ready(struct AdapterControlBlock *acb)
-{
- struct MessageUnit_A __iomem *reg = acb->pmuA;
- uint32_t Index;
- uint8_t Retries = 0x00;
-
- do {
- for (Index = 0; Index < 100; Index++) {
- if (readl(&reg->outbound_intstatus) &
- ARCMSR_MU_OUTBOUND_MESSAGE0_INT) {
- writel(ARCMSR_MU_OUTBOUND_MESSAGE0_INT,
- &reg->outbound_intstatus);
- return 0x00;
- }
- msleep(10);
- }/*max 1 seconds*/
-
- } while (Retries++ < 20);/*max 20 sec*/
- return 0xff;
-}
-
-static uint8_t arcmsr_hbb_wait_msgint_ready(struct AdapterControlBlock *acb)
-{
- struct MessageUnit_B *reg = acb->pmuB;
- uint32_t Index;
- uint8_t Retries = 0x00;
-
- do {
- for (Index = 0; Index < 100; Index++) {
- if (readl(reg->iop2drv_doorbell_reg)
- & ARCMSR_IOP2DRV_MESSAGE_CMD_DONE) {
- writel(ARCMSR_MESSAGE_INT_CLEAR_PATTERN
- , reg->iop2drv_doorbell_reg);
- writel(ARCMSR_DRV2IOP_END_OF_INTERRUPT, reg->drv2iop_doorbell_reg);
- return 0x00;
- }
- msleep(10);
- }/*max 1 seconds*/
-
- } while (Retries++ < 20);/*max 20 sec*/
- return 0xff;
+ return -ENODEV;
}
static uint8_t arcmsr_abort_hba_allcmd(struct AdapterControlBlock *acb)
{
struct MessageUnit_A __iomem *reg = acb->pmuA;
-
writel(ARCMSR_INBOUND_MESG0_ABORT_CMD, &reg->inbound_msgaddr0);
- if (arcmsr_hba_wait_msgint_ready(acb)) {
+ if (!arcmsr_hba_wait_msgint_ready(acb)) {
printk(KERN_NOTICE
"arcmsr%d: wait 'abort all outstanding command' timeout \n"
, acb->host->host_no);
- return 0xff;
+ return false;
}
- return 0x00;
+ return true;
}
static uint8_t arcmsr_abort_hbb_allcmd(struct AdapterControlBlock *acb)
{
struct MessageUnit_B *reg = acb->pmuB;
- writel(ARCMSR_MESSAGE_ABORT_CMD, reg->drv2iop_doorbell_reg);
- if (arcmsr_hbb_wait_msgint_ready(acb)) {
+ writel(ARCMSR_MESSAGE_ABORT_CMD, reg->drv2iop_doorbell);
+ if (!arcmsr_hbb_wait_msgint_ready(acb)) {
printk(KERN_NOTICE
"arcmsr%d: wait 'abort all outstanding command' timeout \n"
, acb->host->host_no);
- return 0xff;
+ return false;
}
- return 0x00;
+ return true;
+}
+static uint8_t arcmsr_abort_hbc_allcmd(struct AdapterControlBlock *pACB)
+{
+ struct MessageUnit_C *reg = (struct MessageUnit_C *)pACB->pmuC;
+ writel(ARCMSR_INBOUND_MESG0_ABORT_CMD, &reg->inbound_msgaddr0);
+ writel(ARCMSR_HBCMU_DRV2IOP_MESSAGE_CMD_DONE, &reg->inbound_doorbell);
+ if (!arcmsr_hbc_wait_msgint_ready(pACB)) {
+ printk(KERN_NOTICE
+ "arcmsr%d: wait 'abort all outstanding command' timeout \n"
+ , pACB->host->host_no);
+ return false;
+ }
+ return true;
}
-
static uint8_t arcmsr_abort_allcmd(struct AdapterControlBlock *acb)
{
uint8_t rtnval = 0;
@@ -638,10 +782,26 @@ static uint8_t arcmsr_abort_allcmd(struct AdapterControlBlock *acb)
case ACB_ADAPTER_TYPE_B: {
rtnval = arcmsr_abort_hbb_allcmd(acb);
}
+ break;
+
+ case ACB_ADAPTER_TYPE_C: {
+ rtnval = arcmsr_abort_hbc_allcmd(acb);
+ }
}
return rtnval;
}
+static bool arcmsr_hbb_enable_driver_mode(struct AdapterControlBlock *pacb)
+{
+ struct MessageUnit_B *reg = pacb->pmuB;
+ writel(ARCMSR_MESSAGE_START_DRIVER_MODE, reg->drv2iop_doorbell);
+ if (!arcmsr_hbb_wait_msgint_ready(pacb)) {
+ printk(KERN_ERR "arcmsr%d: can't set driver mode. \n", pacb->host->host_no);
+ return false;
+ }
+ return true;
+}
+
static void arcmsr_pci_unmap_dma(struct CommandControlBlock *ccb)
{
struct scsi_cmnd *pcmd = ccb->pcmd;
@@ -649,75 +809,25 @@ static void arcmsr_pci_unmap_dma(struct CommandControlBlock *ccb)
scsi_dma_unmap(pcmd);
}
-static void arcmsr_ccb_complete(struct CommandControlBlock *ccb, int stand_flag)
+static void arcmsr_ccb_complete(struct CommandControlBlock *ccb)
{
struct AdapterControlBlock *acb = ccb->acb;
struct scsi_cmnd *pcmd = ccb->pcmd;
-
+ unsigned long flags;
+ atomic_dec(&acb->ccboutstandingcount);
arcmsr_pci_unmap_dma(ccb);
- if (stand_flag == 1)
- atomic_dec(&acb->ccboutstandingcount);
ccb->startdone = ARCMSR_CCB_DONE;
- ccb->ccb_flags = 0;
+ spin_lock_irqsave(&acb->ccblist_lock, flags);
list_add_tail(&ccb->list, &acb->ccb_free_list);
+ spin_unlock_irqrestore(&acb->ccblist_lock, flags);
pcmd->scsi_done(pcmd);
}
-static void arcmsr_flush_hba_cache(struct AdapterControlBlock *acb)
-{
- struct MessageUnit_A __iomem *reg = acb->pmuA;
- int retry_count = 30;
-
- writel(ARCMSR_INBOUND_MESG0_FLUSH_CACHE, &reg->inbound_msgaddr0);
- do {
- if (!arcmsr_hba_wait_msgint_ready(acb))
- break;
- else {
- retry_count--;
- printk(KERN_NOTICE "arcmsr%d: wait 'flush adapter cache' \
- timeout, retry count down = %d \n", acb->host->host_no, retry_count);
- }
- } while (retry_count != 0);
-}
-
-static void arcmsr_flush_hbb_cache(struct AdapterControlBlock *acb)
-{
- struct MessageUnit_B *reg = acb->pmuB;
- int retry_count = 30;
-
- writel(ARCMSR_MESSAGE_FLUSH_CACHE, reg->drv2iop_doorbell_reg);
- do {
- if (!arcmsr_hbb_wait_msgint_ready(acb))
- break;
- else {
- retry_count--;
- printk(KERN_NOTICE "arcmsr%d: wait 'flush adapter cache' \
- timeout,retry count down = %d \n", acb->host->host_no, retry_count);
- }
- } while (retry_count != 0);
-}
-
-static void arcmsr_flush_adapter_cache(struct AdapterControlBlock *acb)
-{
- switch (acb->adapter_type) {
-
- case ACB_ADAPTER_TYPE_A: {
- arcmsr_flush_hba_cache(acb);
- }
- break;
-
- case ACB_ADAPTER_TYPE_B: {
- arcmsr_flush_hbb_cache(acb);
- }
- }
-}
-
static void arcmsr_report_sense_info(struct CommandControlBlock *ccb)
{
struct scsi_cmnd *pcmd = ccb->pcmd;
struct SENSE_DATA *sensebuffer = (struct SENSE_DATA *)pcmd->sense_buffer;
-
pcmd->result = DID_OK << 16;
if (sensebuffer) {
int sense_data_length =
@@ -733,8 +843,7 @@ static void arcmsr_report_sense_info(struct CommandControlBlock *ccb)
static u32 arcmsr_disable_outbound_ints(struct AdapterControlBlock *acb)
{
u32 orig_mask = 0;
- switch (acb->adapter_type) {
-
+ switch (acb->adapter_type) {
case ACB_ADAPTER_TYPE_A : {
struct MessageUnit_A __iomem *reg = acb->pmuA;
orig_mask = readl(&reg->outbound_intmask);
@@ -742,35 +851,40 @@ static u32 arcmsr_disable_outbound_ints(struct AdapterControlBlock *acb)
&reg->outbound_intmask);
}
break;
-
case ACB_ADAPTER_TYPE_B : {
struct MessageUnit_B *reg = acb->pmuB;
- orig_mask = readl(reg->iop2drv_doorbell_mask_reg);
- writel(0, reg->iop2drv_doorbell_mask_reg);
+ orig_mask = readl(reg->iop2drv_doorbell_mask);
+ writel(0, reg->iop2drv_doorbell_mask);
+ }
+ break;
+ case ACB_ADAPTER_TYPE_C:{
+ struct MessageUnit_C *reg = (struct MessageUnit_C *)acb->pmuC;
+ /* disable all outbound interrupt */
+ orig_mask = readl(&reg->host_int_mask); /* disable outbound message0 int */
+ writel(orig_mask|ARCMSR_HBCMU_ALL_INTMASKENABLE, &reg->host_int_mask);
}
break;
}
return orig_mask;
}
-static void arcmsr_report_ccb_state(struct AdapterControlBlock *acb, \
- struct CommandControlBlock *ccb, uint32_t flag_ccb)
+static void arcmsr_report_ccb_state(struct AdapterControlBlock *acb,
+ struct CommandControlBlock *ccb, bool error)
{
-
uint8_t id, lun;
id = ccb->pcmd->device->id;
lun = ccb->pcmd->device->lun;
- if (!(flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR)) {
+ if (!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 {
+ arcmsr_ccb_complete(ccb);
+ }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);
+ arcmsr_ccb_complete(ccb);
}
break;
@@ -779,49 +893,49 @@ static void arcmsr_report_ccb_state(struct AdapterControlBlock *acb, \
case ARCMSR_DEV_INIT_FAIL: {
acb->devstate[id][lun] = ARECA_RAID_GONE;
ccb->pcmd->result = DID_BAD_TARGET << 16;
- arcmsr_ccb_complete(ccb, 1);
+ arcmsr_ccb_complete(ccb);
}
break;
case ARCMSR_DEV_CHECK_CONDITION: {
acb->devstate[id][lun] = ARECA_RAID_GOOD;
arcmsr_report_sense_info(ccb);
- arcmsr_ccb_complete(ccb, 1);
+ arcmsr_ccb_complete(ccb);
}
break;
default:
- printk(KERN_NOTICE
- "arcmsr%d: scsi id = %d lun = %d"
- " isr get 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_NO_CONNECT << 16;
- arcmsr_ccb_complete(ccb, 1);
+ printk(KERN_NOTICE
+ "arcmsr%d: scsi id = %d lun = %d isr get 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_NO_CONNECT << 16;
+ arcmsr_ccb_complete(ccb);
break;
}
}
}
-static void arcmsr_drain_donequeue(struct AdapterControlBlock *acb, uint32_t flag_ccb)
+static void arcmsr_drain_donequeue(struct AdapterControlBlock *acb, struct CommandControlBlock *pCCB, bool error)
{
- struct CommandControlBlock *ccb;
-
- ccb = (struct CommandControlBlock *)(acb->vir2phy_offset + (flag_ccb << 5));
- if ((ccb->acb != acb) || (ccb->startdone != ARCMSR_CCB_START)) {
- if (ccb->startdone == ARCMSR_CCB_ABORTED) {
- struct scsi_cmnd *abortcmd = ccb->pcmd;
+ int id, lun;
+ if ((pCCB->acb != acb) || (pCCB->startdone != ARCMSR_CCB_START)) {
+ if (pCCB->startdone == ARCMSR_CCB_ABORTED) {
+ struct scsi_cmnd *abortcmd = pCCB->pcmd;
if (abortcmd) {
+ id = abortcmd->device->id;
+ lun = abortcmd->device->lun;
abortcmd->result |= DID_ABORT << 16;
- arcmsr_ccb_complete(ccb, 1);
- printk(KERN_NOTICE "arcmsr%d: ccb ='0x%p' \
- isr got aborted command \n", acb->host->host_no, ccb);
+ arcmsr_ccb_complete(pCCB);
+ printk(KERN_NOTICE "arcmsr%d: pCCB ='0x%p' isr got aborted command \n",
+ acb->host->host_no, pCCB);
}
+ return;
}
printk(KERN_NOTICE "arcmsr%d: isr get an illegal ccb command \
done acb = '0x%p'"
@@ -829,20 +943,22 @@ static void arcmsr_drain_donequeue(struct AdapterControlBlock *acb, uint32_t fla
" ccboutstandingcount = %d \n"
, acb->host->host_no
, acb
- , ccb
- , ccb->acb
- , ccb->startdone
+ , pCCB
+ , pCCB->acb
+ , pCCB->startdone
, atomic_read(&acb->ccboutstandingcount));
+ return;
}
- else
- arcmsr_report_ccb_state(acb, ccb, flag_ccb);
+ arcmsr_report_ccb_state(acb, pCCB, error);
}
static void arcmsr_done4abort_postqueue(struct AdapterControlBlock *acb)
{
int i = 0;
uint32_t flag_ccb;
-
+ struct ARCMSR_CDB *pARCMSR_CDB;
+ bool error;
+ struct CommandControlBlock *pCCB;
switch (acb->adapter_type) {
case ACB_ADAPTER_TYPE_A: {
@@ -852,9 +968,12 @@ static void arcmsr_done4abort_postqueue(struct AdapterControlBlock *acb)
acb->outbound_int_enable;
/*clear and abort all outbound posted Q*/
writel(outbound_intstatus, &reg->outbound_intstatus);/*clear interrupt*/
- while (((flag_ccb = readl(&reg->outbound_queueport)) != 0xFFFFFFFF)
+ while(((flag_ccb = readl(&reg->outbound_queueport)) != 0xFFFFFFFF)
&& (i++ < ARCMSR_MAX_OUTSTANDING_CMD)) {
- arcmsr_drain_donequeue(acb, flag_ccb);
+ pARCMSR_CDB = (struct ARCMSR_CDB *)(acb->vir2phy_offset + (flag_ccb << 5));/*frame must be 32 bytes aligned*/
+ pCCB = container_of(pARCMSR_CDB, struct CommandControlBlock, arcmsr_cdb);
+ error = (flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR_MODE0) ? true : false;
+ arcmsr_drain_donequeue(acb, pCCB, error);
}
}
break;
@@ -862,17 +981,37 @@ static void arcmsr_done4abort_postqueue(struct AdapterControlBlock *acb)
case ACB_ADAPTER_TYPE_B: {
struct MessageUnit_B *reg = acb->pmuB;
/*clear all outbound posted Q*/
+ writel(ARCMSR_DOORBELL_INT_CLEAR_PATTERN, &reg->iop2drv_doorbell); /* clear doorbell interrupt */
for (i = 0; i < ARCMSR_MAX_HBB_POSTQUEUE; i++) {
if ((flag_ccb = readl(&reg->done_qbuffer[i])) != 0) {
writel(0, &reg->done_qbuffer[i]);
- arcmsr_drain_donequeue(acb, flag_ccb);
+ pARCMSR_CDB = (struct ARCMSR_CDB *)(acb->vir2phy_offset+(flag_ccb << 5));/*frame must be 32 bytes aligned*/
+ pCCB = container_of(pARCMSR_CDB, struct CommandControlBlock, arcmsr_cdb);
+ error = (flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR_MODE0) ? true : false;
+ arcmsr_drain_donequeue(acb, pCCB, error);
}
- writel(0, &reg->post_qbuffer[i]);
+ reg->post_qbuffer[i] = 0;
}
reg->doneq_index = 0;
reg->postq_index = 0;
}
break;
+ case ACB_ADAPTER_TYPE_C: {
+ struct MessageUnit_C *reg = acb->pmuC;
+ struct ARCMSR_CDB *pARCMSR_CDB;
+ uint32_t flag_ccb, ccb_cdb_phy;
+ bool error;
+ struct CommandControlBlock *pCCB;
+ while ((readl(&reg->host_int_status) & ARCMSR_HBCMU_OUTBOUND_POSTQUEUE_ISR) && (i++ < ARCMSR_MAX_OUTSTANDING_CMD)) {
+ /*need to do*/
+ flag_ccb = readl(&reg->outbound_queueport_low);
+ ccb_cdb_phy = (flag_ccb & 0xFFFFFFF0);
+ pARCMSR_CDB = (struct ARCMSR_CDB *)(acb->vir2phy_offset+ccb_cdb_phy);/*frame must be 32 bytes aligned*/
+ pCCB = container_of(pARCMSR_CDB, struct CommandControlBlock, arcmsr_cdb);
+ error = (flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR_MODE1) ? true : false;
+ arcmsr_drain_donequeue(acb, pCCB, error);
+ }
+ }
}
}
static void arcmsr_remove(struct pci_dev *pdev)
@@ -887,11 +1026,11 @@ static void arcmsr_remove(struct pci_dev *pdev)
del_timer_sync(&acb->eternal_timer);
arcmsr_disable_outbound_ints(acb);
arcmsr_stop_adapter_bgrb(acb);
- arcmsr_flush_adapter_cache(acb);
+ arcmsr_flush_adapter_cache(acb);
acb->acb_flags |= ACB_F_SCSISTOPADAPTER;
acb->acb_flags &= ~ACB_F_IOP_INITED;
- for (poll_count = 0; poll_count < ARCMSR_MAX_OUTSTANDING_CMD; poll_count++) {
+ for (poll_count = 0; poll_count < ARCMSR_MAX_OUTSTANDING_CMD; poll_count++){
if (!atomic_read(&acb->ccboutstandingcount))
break;
arcmsr_interrupt(acb);/* FIXME: need spinlock */
@@ -908,17 +1047,16 @@ static void arcmsr_remove(struct pci_dev *pdev)
if (ccb->startdone == ARCMSR_CCB_START) {
ccb->startdone = ARCMSR_CCB_ABORTED;
ccb->pcmd->result = DID_ABORT << 16;
- arcmsr_ccb_complete(ccb, 1);
+ arcmsr_ccb_complete(ccb);
}
}
}
-
free_irq(pdev->irq, acb);
arcmsr_free_ccb_pool(acb);
+ arcmsr_free_hbb_mu(acb);
+ arcmsr_unmap_pciregion(acb);
pci_release_regions(pdev);
-
scsi_host_put(host);
-
pci_disable_device(pdev);
pci_set_drvdata(pdev, NULL);
}
@@ -938,7 +1076,6 @@ static void arcmsr_shutdown(struct pci_dev *pdev)
static int arcmsr_module_init(void)
{
int error = 0;
-
error = pci_register_driver(&arcmsr_pci_driver);
return error;
}
@@ -954,10 +1091,9 @@ static void arcmsr_enable_outbound_ints(struct AdapterControlBlock *acb,
u32 intmask_org)
{
u32 mask;
-
switch (acb->adapter_type) {
- case ACB_ADAPTER_TYPE_A : {
+ case ACB_ADAPTER_TYPE_A: {
struct MessageUnit_A __iomem *reg = acb->pmuA;
mask = intmask_org & ~(ARCMSR_MU_OUTBOUND_POSTQUEUE_INTMASKENABLE |
ARCMSR_MU_OUTBOUND_DOORBELL_INTMASKENABLE|
@@ -967,15 +1103,22 @@ static void arcmsr_enable_outbound_ints(struct AdapterControlBlock *acb,
}
break;
- case ACB_ADAPTER_TYPE_B : {
+ case ACB_ADAPTER_TYPE_B: {
struct MessageUnit_B *reg = acb->pmuB;
mask = intmask_org | (ARCMSR_IOP2DRV_DATA_WRITE_OK |
ARCMSR_IOP2DRV_DATA_READ_OK |
ARCMSR_IOP2DRV_CDB_DONE |
ARCMSR_IOP2DRV_MESSAGE_CMD_DONE);
- writel(mask, reg->iop2drv_doorbell_mask_reg);
+ writel(mask, reg->iop2drv_doorbell_mask);
acb->outbound_int_enable = (intmask_org | mask) & 0x0000000f;
}
+ break;
+ case ACB_ADAPTER_TYPE_C: {
+ struct MessageUnit_C *reg = acb->pmuC;
+ mask = ~(ARCMSR_HBCMU_UTILITY_A_ISR_MASK | ARCMSR_HBCMU_OUTBOUND_DOORBELL_ISR_MASK|ARCMSR_HBCMU_OUTBOUND_POSTQUEUE_ISR_MASK);
+ writel(intmask_org & mask, &reg->host_int_mask);
+ acb->outbound_int_enable = ~(intmask_org & mask) & 0x0000000f;
+ }
}
}
@@ -986,80 +1129,70 @@ static int arcmsr_build_ccb(struct AdapterControlBlock *acb,
int8_t *psge = (int8_t *)&arcmsr_cdb->u;
__le32 address_lo, address_hi;
int arccdbsize = 0x30;
+ __le32 length = 0;
+ int i;
+ struct scatterlist *sg;
int nseg;
-
ccb->pcmd = pcmd;
memset(arcmsr_cdb, 0, sizeof(struct ARCMSR_CDB));
- arcmsr_cdb->Bus = 0;
arcmsr_cdb->TargetID = pcmd->device->id;
arcmsr_cdb->LUN = pcmd->device->lun;
arcmsr_cdb->Function = 1;
- arcmsr_cdb->CdbLength = (uint8_t)pcmd->cmd_len;
- arcmsr_cdb->Context = (unsigned long)arcmsr_cdb;
+ arcmsr_cdb->Context = 0;
memcpy(arcmsr_cdb->Cdb, pcmd->cmnd, pcmd->cmd_len);
nseg = scsi_dma_map(pcmd);
- if (nseg > ARCMSR_MAX_SG_ENTRIES)
+ if (unlikely(nseg > acb->host->sg_tablesize || nseg < 0))
return FAILED;
- BUG_ON(nseg < 0);
-
- if (nseg) {
- __le32 length;
- int i, cdb_sgcount = 0;
- struct scatterlist *sg;
-
- /* map stor port SG list to our iop SG List. */
- scsi_for_each_sg(pcmd, sg, nseg, i) {
- /* Get the physical address of the current data pointer */
- 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;
-
- pdma_sg->address = address_lo;
- pdma_sg->length = length;
- psge += sizeof (struct SG32ENTRY);
- arccdbsize += sizeof (struct SG32ENTRY);
- } else {
- struct SG64ENTRY *pdma_sg = (struct SG64ENTRY *)psge;
+ scsi_for_each_sg(pcmd, sg, nseg, i) {
+ /* Get the physical address of the current data pointer */
+ 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;
+
+ pdma_sg->address = address_lo;
+ pdma_sg->length = length;
+ psge += sizeof (struct SG32ENTRY);
+ arccdbsize += sizeof (struct SG32ENTRY);
+ } else {
+ struct SG64ENTRY *pdma_sg = (struct SG64ENTRY *)psge;
- pdma_sg->addresshigh = address_hi;
- pdma_sg->address = address_lo;
- pdma_sg->length = length|cpu_to_le32(IS_SG64_ADDR);
- psge += sizeof (struct SG64ENTRY);
- arccdbsize += sizeof (struct SG64ENTRY);
- }
- cdb_sgcount++;
+ pdma_sg->addresshigh = address_hi;
+ pdma_sg->address = address_lo;
+ pdma_sg->length = length|cpu_to_le32(IS_SG64_ADDR);
+ psge += sizeof (struct SG64ENTRY);
+ arccdbsize += sizeof (struct SG64ENTRY);
}
- arcmsr_cdb->sgcount = (uint8_t)cdb_sgcount;
- arcmsr_cdb->DataLength = scsi_bufflen(pcmd);
- if ( arccdbsize > 256)
- arcmsr_cdb->Flags |= ARCMSR_CDB_FLAG_SGL_BSIZE;
}
- if (pcmd->sc_data_direction == DMA_TO_DEVICE ) {
+ arcmsr_cdb->sgcount = (uint8_t)nseg;
+ arcmsr_cdb->DataLength = scsi_bufflen(pcmd);
+ arcmsr_cdb->msgPages = arccdbsize/0x100 + (arccdbsize % 0x100 ? 1 : 0);
+ if ( arccdbsize > 256)
+ arcmsr_cdb->Flags |= ARCMSR_CDB_FLAG_SGL_BSIZE;
+ if (pcmd->cmnd[0]|WRITE_6 || pcmd->cmnd[0]|WRITE_10 || pcmd->cmnd[0]|WRITE_12 ){
arcmsr_cdb->Flags |= ARCMSR_CDB_FLAG_WRITE;
- ccb->ccb_flags |= CCB_FLAG_WRITE;
}
+ ccb->arc_cdb_size = arccdbsize;
return SUCCESS;
}
static void arcmsr_post_ccb(struct AdapterControlBlock *acb, struct CommandControlBlock *ccb)
{
- uint32_t cdb_shifted_phyaddr = ccb->cdb_shifted_phyaddr;
+ uint32_t cdb_phyaddr_pattern = ccb->cdb_phyaddr_pattern;
struct ARCMSR_CDB *arcmsr_cdb = (struct ARCMSR_CDB *)&ccb->arcmsr_cdb;
atomic_inc(&acb->ccboutstandingcount);
ccb->startdone = ARCMSR_CCB_START;
-
switch (acb->adapter_type) {
case ACB_ADAPTER_TYPE_A: {
struct MessageUnit_A __iomem *reg = acb->pmuA;
if (arcmsr_cdb->Flags & ARCMSR_CDB_FLAG_SGL_BSIZE)
- writel(cdb_shifted_phyaddr | ARCMSR_CCBPOST_FLAG_SGL_BSIZE,
+ writel(cdb_phyaddr_pattern | ARCMSR_CCBPOST_FLAG_SGL_BSIZE,
&reg->inbound_queueport);
else {
- writel(cdb_shifted_phyaddr, &reg->inbound_queueport);
+ writel(cdb_phyaddr_pattern, &reg->inbound_queueport);
}
}
break;
@@ -1071,18 +1204,30 @@ static void arcmsr_post_ccb(struct AdapterControlBlock *acb, struct CommandContr
ending_index = ((index + 1) % ARCMSR_MAX_HBB_POSTQUEUE);
writel(0, &reg->post_qbuffer[ending_index]);
if (arcmsr_cdb->Flags & ARCMSR_CDB_FLAG_SGL_BSIZE) {
- writel(cdb_shifted_phyaddr | ARCMSR_CCBPOST_FLAG_SGL_BSIZE,\
+ writel(cdb_phyaddr_pattern | ARCMSR_CCBPOST_FLAG_SGL_BSIZE,\
&reg->post_qbuffer[index]);
- }
- else {
- writel(cdb_shifted_phyaddr, &reg->post_qbuffer[index]);
+ } else {
+ writel(cdb_phyaddr_pattern, &reg->post_qbuffer[index]);
}
index++;
index %= ARCMSR_MAX_HBB_POSTQUEUE;/*if last index number set it to 0 */
reg->postq_index = index;
- writel(ARCMSR_DRV2IOP_CDB_POSTED, reg->drv2iop_doorbell_reg);
+ writel(ARCMSR_DRV2IOP_CDB_POSTED, reg->drv2iop_doorbell);
}
break;
+ case ACB_ADAPTER_TYPE_C: {
+ struct MessageUnit_C *phbcmu = (struct MessageUnit_C *)acb->pmuC;
+ uint32_t ccb_post_stamp, arc_cdb_size;
+
+ arc_cdb_size = (ccb->arc_cdb_size > 0x300) ? 0x300 : ccb->arc_cdb_size;
+ ccb_post_stamp = (cdb_phyaddr_pattern | ((arc_cdb_size - 1) >> 6) | 1);
+ if (acb->cdb_phyaddr_hi32) {
+ writel(acb->cdb_phyaddr_hi32, &phbcmu->inbound_queueport_high);
+ writel(ccb_post_stamp, &phbcmu->inbound_queueport_low);
+ } else {
+ writel(ccb_post_stamp, &phbcmu->inbound_queueport_low);
+ }
+ }
}
}
@@ -1091,8 +1236,7 @@ static void arcmsr_stop_hba_bgrb(struct AdapterControlBlock *acb)
struct MessageUnit_A __iomem *reg = acb->pmuA;
acb->acb_flags &= ~ACB_F_MSG_START_BGRB;
writel(ARCMSR_INBOUND_MESG0_STOP_BGRB, &reg->inbound_msgaddr0);
-
- if (arcmsr_hba_wait_msgint_ready(acb)) {
+ if (!arcmsr_hba_wait_msgint_ready(acb)) {
printk(KERN_NOTICE
"arcmsr%d: wait 'stop adapter background rebulid' timeout \n"
, acb->host->host_no);
@@ -1103,15 +1247,28 @@ static void arcmsr_stop_hbb_bgrb(struct AdapterControlBlock *acb)
{
struct MessageUnit_B *reg = acb->pmuB;
acb->acb_flags &= ~ACB_F_MSG_START_BGRB;
- writel(ARCMSR_MESSAGE_STOP_BGRB, reg->drv2iop_doorbell_reg);
+ writel(ARCMSR_MESSAGE_STOP_BGRB, reg->drv2iop_doorbell);
- if (arcmsr_hbb_wait_msgint_ready(acb)) {
+ if (!arcmsr_hbb_wait_msgint_ready(acb)) {
printk(KERN_NOTICE
"arcmsr%d: wait 'stop adapter background rebulid' timeout \n"
, acb->host->host_no);
}
}
+static void arcmsr_stop_hbc_bgrb(struct AdapterControlBlock *pACB)
+{
+ struct MessageUnit_C *reg = (struct MessageUnit_C *)pACB->pmuC;
+ pACB->acb_flags &= ~ACB_F_MSG_START_BGRB;
+ writel(ARCMSR_INBOUND_MESG0_STOP_BGRB, &reg->inbound_msgaddr0);
+ writel(ARCMSR_HBCMU_DRV2IOP_MESSAGE_CMD_DONE, &reg->inbound_doorbell);
+ if (!arcmsr_hbc_wait_msgint_ready(pACB)) {
+ printk(KERN_NOTICE
+ "arcmsr%d: wait 'stop adapter background rebulid' timeout \n"
+ , pACB->host->host_no);
+ }
+ return;
+}
static void arcmsr_stop_adapter_bgrb(struct AdapterControlBlock *acb)
{
switch (acb->adapter_type) {
@@ -1124,30 +1281,15 @@ static void arcmsr_stop_adapter_bgrb(struct AdapterControlBlock *acb)
arcmsr_stop_hbb_bgrb(acb);
}
break;
+ case ACB_ADAPTER_TYPE_C: {
+ arcmsr_stop_hbc_bgrb(acb);
+ }
}
}
static void arcmsr_free_ccb_pool(struct AdapterControlBlock *acb)
{
- switch (acb->adapter_type) {
- case ACB_ADAPTER_TYPE_A: {
- iounmap(acb->pmuA);
- dma_free_coherent(&acb->pdev->dev,
- ARCMSR_MAX_FREECCB_NUM * sizeof (struct CommandControlBlock) + 0x20,
- acb->dma_coherent,
- acb->dma_coherent_handle);
- break;
- }
- case ACB_ADAPTER_TYPE_B: {
- struct MessageUnit_B *reg = acb->pmuB;
- iounmap((u8 *)reg->drv2iop_doorbell_reg - ARCMSR_DRV2IOP_DOORBELL);
- iounmap((u8 *)reg->ioctl_wbuffer_reg - ARCMSR_IOCTL_WBUFFER);
- dma_free_coherent(&acb->pdev->dev,
- (ARCMSR_MAX_FREECCB_NUM * sizeof(struct CommandControlBlock) + 0x20 +
- sizeof(struct MessageUnit_B)), acb->dma_coherent, acb->dma_coherent_handle);
- }
- }
-
+ dma_free_coherent(&acb->pdev->dev, acb->uncache_size, acb->dma_coherent, acb->dma_coherent_handle);
}
void arcmsr_iop_message_read(struct AdapterControlBlock *acb)
@@ -1161,9 +1303,13 @@ void arcmsr_iop_message_read(struct AdapterControlBlock *acb)
case ACB_ADAPTER_TYPE_B: {
struct MessageUnit_B *reg = acb->pmuB;
- writel(ARCMSR_DRV2IOP_DATA_READ_OK, reg->drv2iop_doorbell_reg);
+ writel(ARCMSR_DRV2IOP_DATA_READ_OK, reg->drv2iop_doorbell);
}
break;
+ case ACB_ADAPTER_TYPE_C: {
+ struct MessageUnit_C __iomem *reg = acb->pmuC;
+ writel(ARCMSR_HBCMU_DRV2IOP_DATA_READ_OK, &reg->inbound_doorbell);
+ }
}
}
@@ -1186,7 +1332,16 @@ static void arcmsr_iop_message_wrote(struct AdapterControlBlock *acb)
** push inbound doorbell tell iop, driver data write ok
** and wait reply on next hwinterrupt for next Qbuffer post
*/
- writel(ARCMSR_DRV2IOP_DATA_WRITE_OK, reg->drv2iop_doorbell_reg);
+ writel(ARCMSR_DRV2IOP_DATA_WRITE_OK, reg->drv2iop_doorbell);
+ }
+ break;
+ case ACB_ADAPTER_TYPE_C: {
+ struct MessageUnit_C __iomem *reg = acb->pmuC;
+ /*
+ ** push inbound doorbell tell iop, driver data write ok
+ ** and wait reply on next hwinterrupt for next Qbuffer post
+ */
+ writel(ARCMSR_HBCMU_DRV2IOP_DATA_WRITE_OK, &reg->inbound_doorbell);
}
break;
}
@@ -1195,7 +1350,6 @@ static void arcmsr_iop_message_wrote(struct AdapterControlBlock *acb)
struct QBUFFER __iomem *arcmsr_get_iop_rqbuffer(struct AdapterControlBlock *acb)
{
struct QBUFFER __iomem *qbuffer = NULL;
-
switch (acb->adapter_type) {
case ACB_ADAPTER_TYPE_A: {
@@ -1206,9 +1360,13 @@ struct QBUFFER __iomem *arcmsr_get_iop_rqbuffer(struct AdapterControlBlock *acb)
case ACB_ADAPTER_TYPE_B: {
struct MessageUnit_B *reg = acb->pmuB;
- qbuffer = (struct QBUFFER __iomem *)reg->ioctl_rbuffer_reg;
+ qbuffer = (struct QBUFFER __iomem *)reg->message_rbuffer;
}
break;
+ case ACB_ADAPTER_TYPE_C: {
+ struct MessageUnit_C *phbcmu = (struct MessageUnit_C *)acb->pmuC;
+ qbuffer = (struct QBUFFER __iomem *)&phbcmu->message_rbuffer;
+ }
}
return qbuffer;
}
@@ -1216,7 +1374,6 @@ struct QBUFFER __iomem *arcmsr_get_iop_rqbuffer(struct AdapterControlBlock *acb)
static struct QBUFFER __iomem *arcmsr_get_iop_wqbuffer(struct AdapterControlBlock *acb)
{
struct QBUFFER __iomem *pqbuffer = NULL;
-
switch (acb->adapter_type) {
case ACB_ADAPTER_TYPE_A: {
@@ -1227,9 +1384,14 @@ static struct QBUFFER __iomem *arcmsr_get_iop_wqbuffer(struct AdapterControlBloc
case ACB_ADAPTER_TYPE_B: {
struct MessageUnit_B *reg = acb->pmuB;
- pqbuffer = (struct QBUFFER __iomem *)reg->ioctl_wbuffer_reg;
+ pqbuffer = (struct QBUFFER __iomem *)reg->message_wbuffer;
}
break;
+ case ACB_ADAPTER_TYPE_C: {
+ struct MessageUnit_C *reg = (struct MessageUnit_C *)acb->pmuC;
+ pqbuffer = (struct QBUFFER __iomem *)&reg->message_wbuffer;
+ }
+
}
return pqbuffer;
}
@@ -1240,19 +1402,18 @@ static void arcmsr_iop2drv_data_wrote_handle(struct AdapterControlBlock *acb)
struct QBUFFER *pQbuffer;
uint8_t __iomem *iop_data;
int32_t my_empty_len, iop_len, rqbuf_firstindex, rqbuf_lastindex;
-
rqbuf_lastindex = acb->rqbuf_lastindex;
rqbuf_firstindex = acb->rqbuf_firstindex;
prbuffer = arcmsr_get_iop_rqbuffer(acb);
iop_data = (uint8_t __iomem *)prbuffer->data;
iop_len = prbuffer->data_len;
- my_empty_len = (rqbuf_firstindex - rqbuf_lastindex -1)&(ARCMSR_MAX_QBUFFER -1);
+ my_empty_len = (rqbuf_firstindex - rqbuf_lastindex - 1) & (ARCMSR_MAX_QBUFFER - 1);
if (my_empty_len >= iop_len)
{
while (iop_len > 0) {
pQbuffer = (struct QBUFFER *)&acb->rqbuffer[rqbuf_lastindex];
- memcpy(pQbuffer, iop_data,1);
+ memcpy(pQbuffer, iop_data, 1);
rqbuf_lastindex++;
rqbuf_lastindex %= ARCMSR_MAX_QBUFFER;
iop_data++;
@@ -1303,25 +1464,52 @@ static void arcmsr_hba_doorbell_isr(struct AdapterControlBlock *acb)
{
uint32_t outbound_doorbell;
struct MessageUnit_A __iomem *reg = acb->pmuA;
-
outbound_doorbell = readl(&reg->outbound_doorbell);
writel(outbound_doorbell, &reg->outbound_doorbell);
if (outbound_doorbell & ARCMSR_OUTBOUND_IOP331_DATA_WRITE_OK) {
arcmsr_iop2drv_data_wrote_handle(acb);
}
- if (outbound_doorbell & ARCMSR_OUTBOUND_IOP331_DATA_READ_OK) {
+ if (outbound_doorbell & ARCMSR_OUTBOUND_IOP331_DATA_READ_OK) {
arcmsr_iop2drv_data_read_handle(acb);
}
}
-
+static void arcmsr_hbc_doorbell_isr(struct AdapterControlBlock *pACB)
+{
+ uint32_t outbound_doorbell;
+ struct MessageUnit_C *reg = (struct MessageUnit_C *)pACB->pmuC;
+ /*
+ *******************************************************************
+ ** Maybe here we need to check wrqbuffer_lock is lock or not
+ ** DOORBELL: din! don!
+ ** check if there are any mail need to pack from firmware
+ *******************************************************************
+ */
+ outbound_doorbell = readl(&reg->outbound_doorbell);
+ writel(outbound_doorbell, &reg->outbound_doorbell_clear);/*clear interrupt*/
+ if (outbound_doorbell & ARCMSR_HBCMU_IOP2DRV_DATA_WRITE_OK) {
+ arcmsr_iop2drv_data_wrote_handle(pACB);
+ }
+ if (outbound_doorbell & ARCMSR_HBCMU_IOP2DRV_DATA_READ_OK) {
+ arcmsr_iop2drv_data_read_handle(pACB);
+ }
+ if (outbound_doorbell & ARCMSR_HBCMU_IOP2DRV_MESSAGE_CMD_DONE) {
+ arcmsr_hbc_message_isr(pACB); /* messenger of "driver to iop commands" */
+ }
+ return;
+}
static void arcmsr_hba_postqueue_isr(struct AdapterControlBlock *acb)
{
uint32_t flag_ccb;
struct MessageUnit_A __iomem *reg = acb->pmuA;
-
+ struct ARCMSR_CDB *pARCMSR_CDB;
+ struct CommandControlBlock *pCCB;
+ bool error;
while ((flag_ccb = readl(&reg->outbound_queueport)) != 0xFFFFFFFF) {
- arcmsr_drain_donequeue(acb, flag_ccb);
+ pARCMSR_CDB = (struct ARCMSR_CDB *)(acb->vir2phy_offset + (flag_ccb << 5));/*frame must be 32 bytes aligned*/
+ pCCB = container_of(pARCMSR_CDB, struct CommandControlBlock, arcmsr_cdb);
+ error = (flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR_MODE0) ? true : false;
+ arcmsr_drain_donequeue(acb, pCCB, error);
}
}
@@ -1330,29 +1518,62 @@ static void arcmsr_hbb_postqueue_isr(struct AdapterControlBlock *acb)
uint32_t index;
uint32_t flag_ccb;
struct MessageUnit_B *reg = acb->pmuB;
-
+ struct ARCMSR_CDB *pARCMSR_CDB;
+ struct CommandControlBlock *pCCB;
+ bool error;
index = reg->doneq_index;
-
while ((flag_ccb = readl(&reg->done_qbuffer[index])) != 0) {
writel(0, &reg->done_qbuffer[index]);
- arcmsr_drain_donequeue(acb, flag_ccb);
+ pARCMSR_CDB = (struct ARCMSR_CDB *)(acb->vir2phy_offset+(flag_ccb << 5));/*frame must be 32 bytes aligned*/
+ pCCB = container_of(pARCMSR_CDB, struct CommandControlBlock, arcmsr_cdb);
+ error = (flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR_MODE0) ? true : false;
+ arcmsr_drain_donequeue(acb, pCCB, error);
index++;
index %= ARCMSR_MAX_HBB_POSTQUEUE;
reg->doneq_index = index;
}
}
+
+static void arcmsr_hbc_postqueue_isr(struct AdapterControlBlock *acb)
+{
+ struct MessageUnit_C *phbcmu;
+ struct ARCMSR_CDB *arcmsr_cdb;
+ struct CommandControlBlock *ccb;
+ uint32_t flag_ccb, ccb_cdb_phy, throttling = 0;
+ int error;
+
+ phbcmu = (struct MessageUnit_C *)acb->pmuC;
+ /* areca cdb command done */
+ /* Use correct offset and size for syncing */
+
+ while (readl(&phbcmu->host_int_status) &
+ ARCMSR_HBCMU_OUTBOUND_POSTQUEUE_ISR){
+ /* check if command done with no error*/
+ flag_ccb = readl(&phbcmu->outbound_queueport_low);
+ ccb_cdb_phy = (flag_ccb & 0xFFFFFFF0);/*frame must be 32 bytes aligned*/
+ arcmsr_cdb = (struct ARCMSR_CDB *)(acb->vir2phy_offset + ccb_cdb_phy);
+ ccb = container_of(arcmsr_cdb, struct CommandControlBlock, arcmsr_cdb);
+ error = (flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR_MODE1) ? true : false;
+ /* check if command done with no error */
+ arcmsr_drain_donequeue(acb, ccb, error);
+ if (throttling == ARCMSR_HBC_ISR_THROTTLING_LEVEL) {
+ writel(ARCMSR_HBCMU_DRV2IOP_POSTQUEUE_THROTTLING, &phbcmu->inbound_doorbell);
+ break;
+ }
+ throttling++;
+ }
+}
/*
**********************************************************************************
** Handle a message interrupt
**
-** The only message interrupt we expect is in response to a query for the current adapter config.
+** The only message interrupt we expect is in response to a query for the current adapter config.
** We want this in order to compare the drivemap so that we can detect newly-attached drives.
**********************************************************************************
*/
static void arcmsr_hba_message_isr(struct AdapterControlBlock *acb)
{
struct MessageUnit_A *reg = acb->pmuA;
-
/*clear interrupt and message state*/
writel(ARCMSR_MU_OUTBOUND_MESSAGE0_INT, &reg->outbound_intstatus);
schedule_work(&acb->arcmsr_do_message_isr_bh);
@@ -1362,16 +1583,32 @@ static void arcmsr_hbb_message_isr(struct AdapterControlBlock *acb)
struct MessageUnit_B *reg = acb->pmuB;
/*clear interrupt and message state*/
- writel(ARCMSR_MESSAGE_INT_CLEAR_PATTERN, reg->iop2drv_doorbell_reg);
+ writel(ARCMSR_MESSAGE_INT_CLEAR_PATTERN, reg->iop2drv_doorbell);
+ schedule_work(&acb->arcmsr_do_message_isr_bh);
+}
+/*
+**********************************************************************************
+** Handle a message interrupt
+**
+** The only message interrupt we expect is in response to a query for the
+** current adapter config.
+** We want this in order to compare the drivemap so that we can detect newly-attached drives.
+**********************************************************************************
+*/
+static void arcmsr_hbc_message_isr(struct AdapterControlBlock *acb)
+{
+ struct MessageUnit_C *reg = acb->pmuC;
+ /*clear interrupt and message state*/
+ writel(ARCMSR_HBCMU_IOP2DRV_MESSAGE_CMD_DONE_DOORBELL_CLEAR, &reg->outbound_doorbell_clear);
schedule_work(&acb->arcmsr_do_message_isr_bh);
}
+
static int arcmsr_handle_hba_isr(struct AdapterControlBlock *acb)
{
uint32_t outbound_intstatus;
struct MessageUnit_A __iomem *reg = acb->pmuA;
-
outbound_intstatus = readl(&reg->outbound_intstatus) &
- acb->outbound_int_enable;
+ acb->outbound_int_enable;
if (!(outbound_intstatus & ARCMSR_MU_OUTBOUND_HANDLE_INT)) {
return 1;
}
@@ -1382,7 +1619,7 @@ static int arcmsr_handle_hba_isr(struct AdapterControlBlock *acb)
if (outbound_intstatus & ARCMSR_MU_OUTBOUND_POSTQUEUE_INT) {
arcmsr_hba_postqueue_isr(acb);
}
- if (outbound_intstatus & ARCMSR_MU_OUTBOUND_MESSAGE0_INT) {
+ if(outbound_intstatus & ARCMSR_MU_OUTBOUND_MESSAGE0_INT) {
/* messenger of "driver to iop commands" */
arcmsr_hba_message_isr(acb);
}
@@ -1393,18 +1630,17 @@ static int arcmsr_handle_hbb_isr(struct AdapterControlBlock *acb)
{
uint32_t outbound_doorbell;
struct MessageUnit_B *reg = acb->pmuB;
-
- outbound_doorbell = readl(reg->iop2drv_doorbell_reg) &
- acb->outbound_int_enable;
+ outbound_doorbell = readl(reg->iop2drv_doorbell) &
+ acb->outbound_int_enable;
if (!outbound_doorbell)
return 1;
- writel(~outbound_doorbell, reg->iop2drv_doorbell_reg);
+ writel(~outbound_doorbell, reg->iop2drv_doorbell);
/*in case the last action of doorbell interrupt clearance is cached,
this action can push HW to write down the clear bit*/
- readl(reg->iop2drv_doorbell_reg);
- writel(ARCMSR_DRV2IOP_END_OF_INTERRUPT, reg->drv2iop_doorbell_reg);
- if (outbound_doorbell & ARCMSR_IOP2DRV_DATA_WRITE_OK) {
+ readl(reg->iop2drv_doorbell);
+ writel(ARCMSR_DRV2IOP_END_OF_INTERRUPT, reg->drv2iop_doorbell);
+ if (outbound_doorbell & ARCMSR_IOP2DRV_DATA_WRITE_OK) {
arcmsr_iop2drv_data_wrote_handle(acb);
}
if (outbound_doorbell & ARCMSR_IOP2DRV_DATA_READ_OK) {
@@ -1413,14 +1649,37 @@ static int arcmsr_handle_hbb_isr(struct AdapterControlBlock *acb)
if (outbound_doorbell & ARCMSR_IOP2DRV_CDB_DONE) {
arcmsr_hbb_postqueue_isr(acb);
}
- if (outbound_doorbell & ARCMSR_IOP2DRV_MESSAGE_CMD_DONE) {
+ if(outbound_doorbell & ARCMSR_IOP2DRV_MESSAGE_CMD_DONE) {
/* messenger of "driver to iop commands" */
arcmsr_hbb_message_isr(acb);
}
-
return 0;
}
+static int arcmsr_handle_hbc_isr(struct AdapterControlBlock *pACB)
+{
+ uint32_t host_interrupt_status;
+ struct MessageUnit_C *phbcmu = (struct MessageUnit_C *)pACB->pmuC;
+ /*
+ *********************************************
+ ** check outbound intstatus
+ *********************************************
+ */
+ host_interrupt_status = readl(&phbcmu->host_int_status);
+ if (!host_interrupt_status) {
+ /*it must be share irq*/
+ return 1;
+ }
+ /* MU ioctl transfer doorbell interrupts*/
+ if (host_interrupt_status & ARCMSR_HBCMU_OUTBOUND_DOORBELL_ISR) {
+ arcmsr_hbc_doorbell_isr(pACB); /* messenger of "ioctl message read write" */
+ }
+ /* MU post queue interrupts*/
+ if (host_interrupt_status & ARCMSR_HBCMU_OUTBOUND_POSTQUEUE_ISR) {
+ arcmsr_hbc_postqueue_isr(pACB); /* messenger of "scsi commands" */
+ }
+ return 0;
+}
static irqreturn_t arcmsr_interrupt(struct AdapterControlBlock *acb)
{
switch (acb->adapter_type) {
@@ -1437,6 +1696,11 @@ static irqreturn_t arcmsr_interrupt(struct AdapterControlBlock *acb)
}
}
break;
+ case ACB_ADAPTER_TYPE_C: {
+ if (arcmsr_handle_hbc_isr(acb)) {
+ return IRQ_NONE;
+ }
+ }
}
return IRQ_HANDLED;
}
@@ -1463,7 +1727,6 @@ void arcmsr_post_ioctldata2iop(struct AdapterControlBlock *acb)
struct QBUFFER __iomem *pwbuffer;
uint8_t __iomem *iop_data;
int32_t allxfer_len = 0;
-
pwbuffer = arcmsr_get_iop_wqbuffer(acb);
iop_data = (uint8_t __iomem *)pwbuffer->data;
if (acb->acb_flags & ACB_F_MESSAGE_WQBUFFER_READED) {
@@ -1496,7 +1759,6 @@ static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb,
(uint32_t ) cmd->cmnd[7] << 8 |
(uint32_t ) cmd->cmnd[8];
/* 4 bytes: Areca io control code */
-
sg = scsi_sglist(cmd);
buffer = kmap_atomic(sg_page(sg), KM_IRQ0) + sg->offset;
if (scsi_sg_count(cmd) > 1) {
@@ -1522,13 +1784,7 @@ static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb,
retvalue = ARCMSR_MESSAGE_FAIL;
goto message_out;
}
-
- if (!acb->fw_state) {
- pcmdmessagefld->cmdmessage.ReturnCode =
- ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON;
- goto message_out;
- }
-
+
ptmpQbuffer = ver_addr;
while ((acb->rqbuf_firstindex != acb->rqbuf_lastindex)
&& (allxfer_len < 1031)) {
@@ -1560,7 +1816,11 @@ static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb,
}
memcpy(pcmdmessagefld->messagedatabuffer, ver_addr, allxfer_len);
pcmdmessagefld->cmdmessage.Length = allxfer_len;
- pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_OK;
+ if(acb->fw_flag == FW_DEADLOCK) {
+ pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON;
+ }else{
+ pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_OK;
+ }
kfree(ver_addr);
}
break;
@@ -1575,12 +1835,13 @@ static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb,
retvalue = ARCMSR_MESSAGE_FAIL;
goto message_out;
}
- if (!acb->fw_state) {
- pcmdmessagefld->cmdmessage.ReturnCode =
+ if(acb->fw_flag == FW_DEADLOCK) {
+ pcmdmessagefld->cmdmessage.ReturnCode =
ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON;
- goto message_out;
+ }else{
+ pcmdmessagefld->cmdmessage.ReturnCode =
+ ARCMSR_MESSAGE_RETURNCODE_OK;
}
-
ptmpuserbuffer = ver_addr;
user_len = pcmdmessagefld->cmdmessage.Length;
memcpy(ptmpuserbuffer, pcmdmessagefld->messagedatabuffer, user_len);
@@ -1633,12 +1894,6 @@ static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb,
case ARCMSR_MESSAGE_CLEAR_RQBUFFER: {
uint8_t *pQbuffer = acb->rqbuffer;
- if (!acb->fw_state) {
- pcmdmessagefld->cmdmessage.ReturnCode =
- ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON;
- goto message_out;
- }
-
if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) {
acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW;
arcmsr_iop_message_read(acb);
@@ -1647,16 +1902,24 @@ static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb,
acb->rqbuf_firstindex = 0;
acb->rqbuf_lastindex = 0;
memset(pQbuffer, 0, ARCMSR_MAX_QBUFFER);
- pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_OK;
+ if(acb->fw_flag == FW_DEADLOCK) {
+ pcmdmessagefld->cmdmessage.ReturnCode =
+ ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON;
+ }else{
+ pcmdmessagefld->cmdmessage.ReturnCode =
+ ARCMSR_MESSAGE_RETURNCODE_OK;
+ }
}
break;
case ARCMSR_MESSAGE_CLEAR_WQBUFFER: {
uint8_t *pQbuffer = acb->wqbuffer;
- if (!acb->fw_state) {
+ if(acb->fw_flag == FW_DEADLOCK) {
pcmdmessagefld->cmdmessage.ReturnCode =
ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON;
- goto message_out;
+ }else{
+ pcmdmessagefld->cmdmessage.ReturnCode =
+ ARCMSR_MESSAGE_RETURNCODE_OK;
}
if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) {
@@ -1669,18 +1932,11 @@ static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb,
acb->wqbuf_firstindex = 0;
acb->wqbuf_lastindex = 0;
memset(pQbuffer, 0, ARCMSR_MAX_QBUFFER);
- pcmdmessagefld->cmdmessage.ReturnCode =
- ARCMSR_MESSAGE_RETURNCODE_OK;
}
break;
case ARCMSR_MESSAGE_CLEAR_ALLQBUFFER: {
uint8_t *pQbuffer;
- if (!acb->fw_state) {
- pcmdmessagefld->cmdmessage.ReturnCode =
- ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON;
- goto message_out;
- }
if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) {
acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW;
@@ -1698,47 +1954,52 @@ static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb,
memset(pQbuffer, 0, sizeof(struct QBUFFER));
pQbuffer = acb->wqbuffer;
memset(pQbuffer, 0, sizeof(struct QBUFFER));
- pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_OK;
+ if(acb->fw_flag == FW_DEADLOCK) {
+ pcmdmessagefld->cmdmessage.ReturnCode =
+ ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON;
+ }else{
+ pcmdmessagefld->cmdmessage.ReturnCode =
+ ARCMSR_MESSAGE_RETURNCODE_OK;
+ }
}
break;
case ARCMSR_MESSAGE_RETURN_CODE_3F: {
- if (!acb->fw_state) {
+ if(acb->fw_flag == FW_DEADLOCK) {
pcmdmessagefld->cmdmessage.ReturnCode =
ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON;
- goto message_out;
- }
- pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_3F;
+ }else{
+ pcmdmessagefld->cmdmessage.ReturnCode =
+ ARCMSR_MESSAGE_RETURNCODE_3F;
}
break;
-
+ }
case ARCMSR_MESSAGE_SAY_HELLO: {
int8_t *hello_string = "Hello! I am ARCMSR";
- if (!acb->fw_state) {
+ if(acb->fw_flag == FW_DEADLOCK) {
pcmdmessagefld->cmdmessage.ReturnCode =
ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON;
- goto message_out;
+ }else{
+ pcmdmessagefld->cmdmessage.ReturnCode =
+ ARCMSR_MESSAGE_RETURNCODE_OK;
}
memcpy(pcmdmessagefld->messagedatabuffer, hello_string
, (int16_t)strlen(hello_string));
- pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_OK;
}
break;
case ARCMSR_MESSAGE_SAY_GOODBYE:
- if (!acb->fw_state) {
+ if(acb->fw_flag == FW_DEADLOCK) {
pcmdmessagefld->cmdmessage.ReturnCode =
ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON;
- goto message_out;
}
arcmsr_iop_parking(acb);
break;
case ARCMSR_MESSAGE_FLUSH_ADAPTER_CACHE:
- if (!acb->fw_state) {
+ if(acb->fw_flag == FW_DEADLOCK) {
pcmdmessagefld->cmdmessage.ReturnCode =
ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON;
- goto message_out;
}
arcmsr_flush_adapter_cache(acb);
break;
@@ -1756,11 +2017,16 @@ static struct CommandControlBlock *arcmsr_get_freeccb(struct AdapterControlBlock
{
struct list_head *head = &acb->ccb_free_list;
struct CommandControlBlock *ccb = NULL;
-
+ unsigned long flags;
+ spin_lock_irqsave(&acb->ccblist_lock, flags);
if (!list_empty(head)) {
ccb = list_entry(head->next, struct CommandControlBlock, list);
- list_del(head->next);
+ list_del_init(&ccb->list);
+ }else{
+ spin_unlock_irqrestore(&acb->ccblist_lock, flags);
+ return 0;
}
+ spin_unlock_irqrestore(&acb->ccblist_lock, flags);
return ccb;
}
@@ -1826,83 +2092,29 @@ static int arcmsr_queue_command(struct scsi_cmnd *cmd,
cmd->scsi_done = done;
cmd->host_scribble = NULL;
cmd->result = 0;
-
- if ((scsicmd == SYNCHRONIZE_CACHE) || (scsicmd == SEND_DIAGNOSTIC)) {
- if (acb->devstate[target][lun] == ARECA_RAID_GONE) {
- cmd->result = (DID_NO_CONNECT << 16);
+ if ((scsicmd == SYNCHRONIZE_CACHE) ||(scsicmd == SEND_DIAGNOSTIC)){
+ if(acb->devstate[target][lun] == ARECA_RAID_GONE) {
+ cmd->result = (DID_NO_CONNECT << 16);
}
cmd->scsi_done(cmd);
return 0;
}
-
- if (acb->acb_flags & ACB_F_BUS_RESET) {
- switch (acb->adapter_type) {
- case ACB_ADAPTER_TYPE_A: {
- struct MessageUnit_A __iomem *reg = acb->pmuA;
- uint32_t intmask_org, outbound_doorbell;
-
- if ((readl(&reg->outbound_msgaddr1) &
- ARCMSR_OUTBOUND_MESG1_FIRMWARE_OK) == 0) {
- printk(KERN_NOTICE "arcmsr%d: bus reset and return busy\n",
- acb->host->host_no);
- return SCSI_MLQUEUE_HOST_BUSY;
- }
-
- acb->acb_flags &= ~ACB_F_FIRMWARE_TRAP;
- printk(KERN_NOTICE "arcmsr%d: hardware bus reset and reset ok\n",
- acb->host->host_no);
- /* disable all outbound interrupt */
- intmask_org = arcmsr_disable_outbound_ints(acb);
- arcmsr_get_firmware_spec(acb, 1);
- /*start background rebuild*/
- arcmsr_start_adapter_bgrb(acb);
- /* clear Qbuffer if door bell ringed */
- outbound_doorbell = readl(&reg->outbound_doorbell);
- /*clear interrupt */
- writel(outbound_doorbell, &reg->outbound_doorbell);
- writel(ARCMSR_INBOUND_DRIVER_DATA_READ_OK,
- &reg->inbound_doorbell);
- /* enable outbound Post Queue,outbound doorbell Interrupt */
- arcmsr_enable_outbound_ints(acb, intmask_org);
- acb->acb_flags |= ACB_F_IOP_INITED;
- acb->acb_flags &= ~ACB_F_BUS_RESET;
- }
- break;
- case ACB_ADAPTER_TYPE_B: {
- }
- }
- }
-
if (target == 16) {
/* virtual device for iop message transfer */
arcmsr_handle_virtual_command(acb, cmd);
return 0;
}
- if (acb->devstate[target][lun] == ARECA_RAID_GONE) {
- uint8_t block_cmd;
-
- block_cmd = cmd->cmnd[0] & 0x0f;
- if (block_cmd == 0x08 || block_cmd == 0x0a) {
- printk(KERN_NOTICE
- "arcmsr%d: block 'read/write'"
- "command with gone raid volume"
- " Cmd = %2x, TargetId = %d, Lun = %d \n"
- , acb->host->host_no
- , cmd->cmnd[0]
- , target, lun);
- cmd->result = (DID_NO_CONNECT << 16);
- cmd->scsi_done(cmd);
- return 0;
- }
- }
if (atomic_read(&acb->ccboutstandingcount) >=
ARCMSR_MAX_OUTSTANDING_CMD)
return SCSI_MLQUEUE_HOST_BUSY;
-
+ if ((scsicmd == SCSI_CMD_ARECA_SPECIFIC)) {
+ printk(KERN_NOTICE "Receiveing SCSI_CMD_ARECA_SPECIFIC command..\n");
+ return 0;
+ }
ccb = arcmsr_get_freeccb(acb);
if (!ccb)
return SCSI_MLQUEUE_HOST_BUSY;
- if ( arcmsr_build_ccb( acb, ccb, cmd ) == FAILED ) {
+ if (arcmsr_build_ccb( acb, ccb, cmd ) == FAILED) {
cmd->result = (DID_ERROR << 16) | (RESERVATION_CONFLICT << 1);
cmd->scsi_done(cmd);
return 0;
@@ -1911,7 +2123,7 @@ static int arcmsr_queue_command(struct scsi_cmnd *cmd,
return 0;
}
-static void *arcmsr_get_hba_config(struct AdapterControlBlock *acb, int mode)
+static bool arcmsr_get_hba_config(struct AdapterControlBlock *acb)
{
struct MessageUnit_A __iomem *reg = acb->pmuA;
char *acb_firm_model = acb->firm_model;
@@ -1919,19 +2131,16 @@ static void *arcmsr_get_hba_config(struct AdapterControlBlock *acb, int mode)
char *acb_device_map = acb->device_map;
char __iomem *iop_firm_model = (char __iomem *)(&reg->message_rwbuffer[15]);
char __iomem *iop_firm_version = (char __iomem *)(&reg->message_rwbuffer[17]);
- char __iomem *iop_device_map = (char __iomem *) (&reg->message_rwbuffer[21]);
+ char __iomem *iop_device_map = (char __iomem *)(&reg->message_rwbuffer[21]);
int count;
-
writel(ARCMSR_INBOUND_MESG0_GET_CONFIG, &reg->inbound_msgaddr0);
- if (arcmsr_hba_wait_msgint_ready(acb)) {
+ if (!arcmsr_hba_wait_msgint_ready(acb)) {
printk(KERN_NOTICE "arcmsr%d: wait 'get adapter firmware \
miscellaneous data' timeout \n", acb->host->host_no);
- return NULL;
+ return false;
}
-
- if (mode == 1) {
count = 8;
- while (count) {
+ while (count){
*acb_firm_model = readb(iop_firm_model);
acb_firm_model++;
iop_firm_model++;
@@ -1939,138 +2148,213 @@ static void *arcmsr_get_hba_config(struct AdapterControlBlock *acb, int mode)
}
count = 16;
- while (count) {
+ while (count){
*acb_firm_version = readb(iop_firm_version);
acb_firm_version++;
iop_firm_version++;
count--;
}
- count = 16;
- while (count) {
- *acb_device_map = readb(iop_device_map);
- acb_device_map++;
- iop_device_map++;
- count--;
- }
-
- printk(KERN_INFO "ARECA RAID ADAPTER%d: FIRMWARE VERSION %s \n"
- , acb->host->host_no
- , acb->firm_version);
- acb->signature = readl(&reg->message_rwbuffer[0]);
+ count=16;
+ while(count){
+ *acb_device_map = readb(iop_device_map);
+ acb_device_map++;
+ iop_device_map++;
+ count--;
+ }
+ printk(KERN_NOTICE "Areca RAID Controller%d: F/W %s & Model %s\n",
+ acb->host->host_no,
+ acb->firm_version,
+ acb->firm_model);
+ acb->signature = readl(&reg->message_rwbuffer[0]);
acb->firm_request_len = readl(&reg->message_rwbuffer[1]);
acb->firm_numbers_queue = readl(&reg->message_rwbuffer[2]);
acb->firm_sdram_size = readl(&reg->message_rwbuffer[3]);
acb->firm_hd_channels = readl(&reg->message_rwbuffer[4]);
+ acb->firm_cfg_version = readl(&reg->message_rwbuffer[25]); /*firm_cfg_version,25,100-103*/
+ return true;
}
- return reg->message_rwbuffer;
-}
-static void __iomem *arcmsr_get_hbb_config(struct AdapterControlBlock *acb, int mode)
+static bool arcmsr_get_hbb_config(struct AdapterControlBlock *acb)
{
struct MessageUnit_B *reg = acb->pmuB;
- uint32_t __iomem *lrwbuffer = reg->msgcode_rwbuffer_reg;
+ struct pci_dev *pdev = acb->pdev;
+ void *dma_coherent;
+ dma_addr_t dma_coherent_handle;
char *acb_firm_model = acb->firm_model;
char *acb_firm_version = acb->firm_version;
char *acb_device_map = acb->device_map;
- char __iomem *iop_firm_model = (char __iomem *)(&lrwbuffer[15]);
+ char __iomem *iop_firm_model;
/*firm_model,15,60-67*/
- char __iomem *iop_firm_version = (char __iomem *)(&lrwbuffer[17]);
+ char __iomem *iop_firm_version;
/*firm_version,17,68-83*/
- char __iomem *iop_device_map = (char __iomem *) (&lrwbuffer[21]);
+ char __iomem *iop_device_map;
/*firm_version,21,84-99*/
int count;
-
- writel(ARCMSR_MESSAGE_GET_CONFIG, reg->drv2iop_doorbell_reg);
- if (arcmsr_hbb_wait_msgint_ready(acb)) {
+ dma_coherent = dma_alloc_coherent(&pdev->dev, sizeof(struct MessageUnit_B), &dma_coherent_handle, GFP_KERNEL);
+ if (!dma_coherent){
+ printk(KERN_NOTICE "arcmsr%d: dma_alloc_coherent got error for hbb mu\n", acb->host->host_no);
+ return false;
+ }
+ acb->dma_coherent_handle_hbb_mu = dma_coherent_handle;
+ reg = (struct MessageUnit_B *)dma_coherent;
+ acb->pmuB = reg;
+ reg->drv2iop_doorbell= (uint32_t __iomem *)((unsigned long)acb->mem_base0 + ARCMSR_DRV2IOP_DOORBELL);
+ reg->drv2iop_doorbell_mask = (uint32_t __iomem *)((unsigned long)acb->mem_base0 + ARCMSR_DRV2IOP_DOORBELL_MASK);
+ reg->iop2drv_doorbell = (uint32_t __iomem *)((unsigned long)acb->mem_base0 + ARCMSR_IOP2DRV_DOORBELL);
+ reg->iop2drv_doorbell_mask = (uint32_t __iomem *)((unsigned long)acb->mem_base0 + ARCMSR_IOP2DRV_DOORBELL_MASK);
+ reg->message_wbuffer = (uint32_t __iomem *)((unsigned long)acb->mem_base1 + ARCMSR_MESSAGE_WBUFFER);
+ reg->message_rbuffer = (uint32_t __iomem *)((unsigned long)acb->mem_base1 + ARCMSR_MESSAGE_RBUFFER);
+ reg->message_rwbuffer = (uint32_t __iomem *)((unsigned long)acb->mem_base1 + ARCMSR_MESSAGE_RWBUFFER);
+ iop_firm_model = (char __iomem *)(&reg->message_rwbuffer[15]); /*firm_model,15,60-67*/
+ iop_firm_version = (char __iomem *)(&reg->message_rwbuffer[17]); /*firm_version,17,68-83*/
+ iop_device_map = (char __iomem *)(&reg->message_rwbuffer[21]); /*firm_version,21,84-99*/
+
+ writel(ARCMSR_MESSAGE_GET_CONFIG, reg->drv2iop_doorbell);
+ if (!arcmsr_hbb_wait_msgint_ready(acb)) {
printk(KERN_NOTICE "arcmsr%d: wait 'get adapter firmware \
miscellaneous data' timeout \n", acb->host->host_no);
- return NULL;
+ return false;
}
-
- if (mode == 1) {
count = 8;
- while (count)
- {
+ while (count){
*acb_firm_model = readb(iop_firm_model);
acb_firm_model++;
iop_firm_model++;
count--;
}
-
count = 16;
- while (count)
- {
+ while (count){
*acb_firm_version = readb(iop_firm_version);
acb_firm_version++;
iop_firm_version++;
count--;
}
- count = 16;
- while (count) {
- *acb_device_map = readb(iop_device_map);
- acb_device_map++;
- iop_device_map++;
- count--;
- }
-
- printk(KERN_INFO "ARECA RAID ADAPTER%d: FIRMWARE VERSION %s \n",
- acb->host->host_no,
- acb->firm_version);
+ count = 16;
+ while(count){
+ *acb_device_map = readb(iop_device_map);
+ acb_device_map++;
+ iop_device_map++;
+ count--;
+ }
+
+ printk(KERN_NOTICE "Areca RAID Controller%d: F/W %s & Model %s\n",
+ acb->host->host_no,
+ acb->firm_version,
+ acb->firm_model);
- acb->signature = readl(lrwbuffer++);
- /*firm_signature,1,00-03*/
- acb->firm_request_len = readl(lrwbuffer++);
+ acb->signature = readl(&reg->message_rwbuffer[1]);
+ /*firm_signature,1,00-03*/
+ acb->firm_request_len = readl(&reg->message_rwbuffer[2]);
/*firm_request_len,1,04-07*/
- acb->firm_numbers_queue = readl(lrwbuffer++);
+ acb->firm_numbers_queue = readl(&reg->message_rwbuffer[3]);
/*firm_numbers_queue,2,08-11*/
- acb->firm_sdram_size = readl(lrwbuffer++);
+ acb->firm_sdram_size = readl(&reg->message_rwbuffer[4]);
/*firm_sdram_size,3,12-15*/
- acb->firm_hd_channels = readl(lrwbuffer);
+ acb->firm_hd_channels = readl(&reg->message_rwbuffer[5]);
/*firm_ide_channels,4,16-19*/
+ acb->firm_cfg_version = readl(&reg->message_rwbuffer[25]); /*firm_cfg_version,25,100-103*/
+ /*firm_ide_channels,4,16-19*/
+ return true;
}
- return reg->msgcode_rwbuffer_reg;
-}
-static void *arcmsr_get_firmware_spec(struct AdapterControlBlock *acb, int mode)
-{
- void *rtnval = 0;
- switch (acb->adapter_type) {
- case ACB_ADAPTER_TYPE_A: {
- rtnval = arcmsr_get_hba_config(acb, mode);
- }
- break;
- case ACB_ADAPTER_TYPE_B: {
- rtnval = arcmsr_get_hbb_config(acb, mode);
+static bool arcmsr_get_hbc_config(struct AdapterControlBlock *pACB)
+{
+ uint32_t intmask_org, Index, firmware_state = 0;
+ struct MessageUnit_C *reg = pACB->pmuC;
+ char *acb_firm_model = pACB->firm_model;
+ char *acb_firm_version = pACB->firm_version;
+ char *iop_firm_model = (char *)(&reg->msgcode_rwbuffer[15]); /*firm_model,15,60-67*/
+ char *iop_firm_version = (char *)(&reg->msgcode_rwbuffer[17]); /*firm_version,17,68-83*/
+ int count;
+ /* disable all outbound interrupt */
+ intmask_org = readl(&reg->host_int_mask); /* disable outbound message0 int */
+ writel(intmask_org|ARCMSR_HBCMU_ALL_INTMASKENABLE, &reg->host_int_mask);
+ /* wait firmware ready */
+ do {
+ firmware_state = readl(&reg->outbound_msgaddr1);
+ } while ((firmware_state & ARCMSR_HBCMU_MESSAGE_FIRMWARE_OK) == 0);
+ /* post "get config" instruction */
+ writel(ARCMSR_INBOUND_MESG0_GET_CONFIG, &reg->inbound_msgaddr0);
+ writel(ARCMSR_HBCMU_DRV2IOP_MESSAGE_CMD_DONE, &reg->inbound_doorbell);
+ /* wait message ready */
+ for (Index = 0; Index < 2000; Index++) {
+ if (readl(&reg->outbound_doorbell) & ARCMSR_HBCMU_IOP2DRV_MESSAGE_CMD_DONE) {
+ writel(ARCMSR_HBCMU_IOP2DRV_MESSAGE_CMD_DONE_DOORBELL_CLEAR, &reg->outbound_doorbell_clear);/*clear interrupt*/
+ break;
}
- break;
+ udelay(10);
+ } /*max 1 seconds*/
+ if (Index >= 2000) {
+ printk(KERN_NOTICE "arcmsr%d: wait 'get adapter firmware \
+ miscellaneous data' timeout \n", pACB->host->host_no);
+ return false;
}
- return rtnval;
+ count = 8;
+ while (count) {
+ *acb_firm_model = readb(iop_firm_model);
+ acb_firm_model++;
+ iop_firm_model++;
+ count--;
+ }
+ count = 16;
+ while (count) {
+ *acb_firm_version = readb(iop_firm_version);
+ acb_firm_version++;
+ iop_firm_version++;
+ count--;
+ }
+ printk(KERN_NOTICE "Areca RAID Controller%d: F/W %s & Model %s\n",
+ pACB->host->host_no,
+ pACB->firm_version,
+ pACB->firm_model);
+ pACB->firm_request_len = readl(&reg->msgcode_rwbuffer[1]); /*firm_request_len,1,04-07*/
+ pACB->firm_numbers_queue = readl(&reg->msgcode_rwbuffer[2]); /*firm_numbers_queue,2,08-11*/
+ pACB->firm_sdram_size = readl(&reg->msgcode_rwbuffer[3]); /*firm_sdram_size,3,12-15*/
+ pACB->firm_hd_channels = readl(&reg->msgcode_rwbuffer[4]); /*firm_ide_channels,4,16-19*/
+ pACB->firm_cfg_version = readl(&reg->msgcode_rwbuffer[25]); /*firm_cfg_version,25,100-103*/
+ /*all interrupt service will be enable at arcmsr_iop_init*/
+ return true;
+}
+static bool arcmsr_get_firmware_spec(struct AdapterControlBlock *acb)
+{
+ if (acb->adapter_type == ACB_ADAPTER_TYPE_A)
+ return arcmsr_get_hba_config(acb);
+ else if (acb->adapter_type == ACB_ADAPTER_TYPE_B)
+ return arcmsr_get_hbb_config(acb);
+ else
+ return arcmsr_get_hbc_config(acb);
}
-static void arcmsr_polling_hba_ccbdone(struct AdapterControlBlock *acb,
+static int arcmsr_polling_hba_ccbdone(struct AdapterControlBlock *acb,
struct CommandControlBlock *poll_ccb)
{
struct MessageUnit_A __iomem *reg = acb->pmuA;
struct CommandControlBlock *ccb;
+ struct ARCMSR_CDB *arcmsr_cdb;
uint32_t flag_ccb, outbound_intstatus, poll_ccb_done = 0, poll_count = 0;
-
+ int rtn;
+ bool error;
polling_hba_ccb_retry:
poll_count++;
outbound_intstatus = readl(&reg->outbound_intstatus) & acb->outbound_int_enable;
writel(outbound_intstatus, &reg->outbound_intstatus);/*clear interrupt*/
while (1) {
if ((flag_ccb = readl(&reg->outbound_queueport)) == 0xFFFFFFFF) {
- if (poll_ccb_done)
+ if (poll_ccb_done){
+ rtn = SUCCESS;
break;
- else {
+ }else {
msleep(25);
- if (poll_count > 100)
+ if (poll_count > 100){
+ rtn = FAILED;
break;
+ }
goto polling_hba_ccb_retry;
}
}
- ccb = (struct CommandControlBlock *)(acb->vir2phy_offset + (flag_ccb << 5));
+ arcmsr_cdb = (struct ARCMSR_CDB *)(acb->vir2phy_offset + (flag_ccb << 5));
+ ccb = container_of(arcmsr_cdb, struct CommandControlBlock, arcmsr_cdb);
poll_ccb_done = (ccb == poll_ccb) ? 1:0;
if ((ccb->acb != acb) || (ccb->startdone != ARCMSR_CCB_START)) {
if ((ccb->startdone == ARCMSR_CCB_ABORTED) || (ccb == poll_ccb)) {
@@ -2081,8 +2365,7 @@ static void arcmsr_polling_hba_ccbdone(struct AdapterControlBlock *acb,
, ccb->pcmd->device->lun
, ccb);
ccb->pcmd->result = DID_ABORT << 16;
- arcmsr_ccb_complete(ccb, 1);
- poll_ccb_done = 1;
+ arcmsr_ccb_complete(ccb);
continue;
}
printk(KERN_NOTICE "arcmsr%d: polling get an illegal ccb"
@@ -2093,86 +2376,156 @@ static void arcmsr_polling_hba_ccbdone(struct AdapterControlBlock *acb,
, atomic_read(&acb->ccboutstandingcount));
continue;
}
- arcmsr_report_ccb_state(acb, ccb, flag_ccb);
+ error = (flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR_MODE0) ? true : false;
+ arcmsr_report_ccb_state(acb, ccb, error);
}
+ return rtn;
}
-static void arcmsr_polling_hbb_ccbdone(struct AdapterControlBlock *acb,
+static int arcmsr_polling_hbb_ccbdone(struct AdapterControlBlock *acb,
struct CommandControlBlock *poll_ccb)
{
- struct MessageUnit_B *reg = acb->pmuB;
- struct CommandControlBlock *ccb;
- uint32_t flag_ccb, poll_ccb_done = 0, poll_count = 0;
- int index;
-
+ struct MessageUnit_B *reg = acb->pmuB;
+ struct ARCMSR_CDB *arcmsr_cdb;
+ struct CommandControlBlock *ccb;
+ uint32_t flag_ccb, poll_ccb_done = 0, poll_count = 0;
+ int index, rtn;
+ bool error;
polling_hbb_ccb_retry:
- poll_count++;
- /* clear doorbell interrupt */
- writel(ARCMSR_DOORBELL_INT_CLEAR_PATTERN, reg->iop2drv_doorbell_reg);
- while (1) {
- index = reg->doneq_index;
- if ((flag_ccb = readl(&reg->done_qbuffer[index])) == 0) {
- if (poll_ccb_done)
+ poll_count++;
+ /* clear doorbell interrupt */
+ writel(ARCMSR_DOORBELL_INT_CLEAR_PATTERN, reg->iop2drv_doorbell);
+ while(1){
+ index = reg->doneq_index;
+ if ((flag_ccb = readl(&reg->done_qbuffer[index])) == 0) {
+ if (poll_ccb_done){
+ rtn = SUCCESS;
+ break;
+ }else {
+ msleep(25);
+ if (poll_count > 100){
+ rtn = FAILED;
break;
- else {
- msleep(25);
- if (poll_count > 100)
- break;
- goto polling_hbb_ccb_retry;
}
+ goto polling_hbb_ccb_retry;
+ }
+ }
+ writel(0, &reg->done_qbuffer[index]);
+ index++;
+ /*if last index number set it to 0 */
+ index %= ARCMSR_MAX_HBB_POSTQUEUE;
+ reg->doneq_index = index;
+ /* check if command done with no error*/
+ arcmsr_cdb = (struct ARCMSR_CDB *)(acb->vir2phy_offset + (flag_ccb << 5));
+ ccb = container_of(arcmsr_cdb, struct CommandControlBlock, arcmsr_cdb);
+ poll_ccb_done = (ccb == poll_ccb) ? 1:0;
+ if ((ccb->acb != acb) || (ccb->startdone != ARCMSR_CCB_START)) {
+ if ((ccb->startdone == ARCMSR_CCB_ABORTED) || (ccb == poll_ccb)) {
+ printk(KERN_NOTICE "arcmsr%d: scsi id = %d lun = %d ccb = '0x%p'"
+ " poll command abort successfully \n"
+ ,acb->host->host_no
+ ,ccb->pcmd->device->id
+ ,ccb->pcmd->device->lun
+ ,ccb);
+ ccb->pcmd->result = DID_ABORT << 16;
+ arcmsr_ccb_complete(ccb);
+ continue;
}
- writel(0, &reg->done_qbuffer[index]);
- index++;
- /*if last index number set it to 0 */
- index %= ARCMSR_MAX_HBB_POSTQUEUE;
- reg->doneq_index = index;
- /* check ifcommand done with no error*/
- ccb = (struct CommandControlBlock *)\
- (acb->vir2phy_offset + (flag_ccb << 5));/*frame must be 32 bytes aligned*/
- poll_ccb_done = (ccb == poll_ccb) ? 1:0;
- if ((ccb->acb != acb) || (ccb->startdone != ARCMSR_CCB_START)) {
- if ((ccb->startdone == ARCMSR_CCB_ABORTED) || (ccb == poll_ccb)) {
- printk(KERN_NOTICE "arcmsr%d: \
- scsi id = %d lun = %d ccb = '0x%p' poll command abort successfully \n"
- ,acb->host->host_no
- ,ccb->pcmd->device->id
- ,ccb->pcmd->device->lun
- ,ccb);
- ccb->pcmd->result = DID_ABORT << 16;
- arcmsr_ccb_complete(ccb, 1);
- continue;
+ 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;
+ }
+ error = (flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR_MODE0) ? true : false;
+ arcmsr_report_ccb_state(acb, ccb, error);
+ }
+ return rtn;
+}
+
+static int arcmsr_polling_hbc_ccbdone(struct AdapterControlBlock *acb, struct CommandControlBlock *poll_ccb)
+{
+ struct MessageUnit_C *reg = (struct MessageUnit_C *)acb->pmuC;
+ uint32_t flag_ccb, ccb_cdb_phy;
+ struct ARCMSR_CDB *arcmsr_cdb;
+ bool error;
+ struct CommandControlBlock *pCCB;
+ uint32_t poll_ccb_done = 0, poll_count = 0;
+ int rtn;
+polling_hbc_ccb_retry:
+ poll_count++;
+ while (1) {
+ if ((readl(&reg->host_int_status) & ARCMSR_HBCMU_OUTBOUND_POSTQUEUE_ISR) == 0) {
+ if (poll_ccb_done) {
+ rtn = SUCCESS;
+ break;
+ } else {
+ msleep(25);
+ if (poll_count > 100) {
+ rtn = FAILED;
+ break;
}
- printk(KERN_NOTICE "arcmsr%d: polling get an illegal ccb"
- " command done ccb = '0x%p'"
- "ccboutstandingcount = %d \n"
+ goto polling_hbc_ccb_retry;
+ }
+ }
+ flag_ccb = readl(&reg->outbound_queueport_low);
+ ccb_cdb_phy = (flag_ccb & 0xFFFFFFF0);
+ arcmsr_cdb = (struct ARCMSR_CDB *)(acb->vir2phy_offset + ccb_cdb_phy);/*frame must be 32 bytes aligned*/
+ pCCB = container_of(arcmsr_cdb, struct CommandControlBlock, arcmsr_cdb);
+ poll_ccb_done = (pCCB == poll_ccb) ? 1 : 0;
+ /* check ifcommand done with no error*/
+ if ((pCCB->acb != acb) || (pCCB->startdone != ARCMSR_CCB_START)) {
+ if (pCCB->startdone == ARCMSR_CCB_ABORTED) {
+ printk(KERN_NOTICE "arcmsr%d: scsi id = %d lun = %d ccb = '0x%p'"
+ " poll command abort successfully \n"
, acb->host->host_no
- , ccb
- , atomic_read(&acb->ccboutstandingcount));
+ , pCCB->pcmd->device->id
+ , pCCB->pcmd->device->lun
+ , pCCB);
+ pCCB->pcmd->result = DID_ABORT << 16;
+ arcmsr_ccb_complete(pCCB);
continue;
}
- arcmsr_report_ccb_state(acb, ccb, flag_ccb);
- } /*drain reply FIFO*/
+ printk(KERN_NOTICE "arcmsr%d: polling get an illegal ccb"
+ " command done ccb = '0x%p'"
+ "ccboutstandingcount = %d \n"
+ , acb->host->host_no
+ , pCCB
+ , atomic_read(&acb->ccboutstandingcount));
+ continue;
+ }
+ error = (flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR_MODE1) ? true : false;
+ arcmsr_report_ccb_state(acb, pCCB, error);
+ }
+ return rtn;
}
-
-static void arcmsr_polling_ccbdone(struct AdapterControlBlock *acb,
+static int arcmsr_polling_ccbdone(struct AdapterControlBlock *acb,
struct CommandControlBlock *poll_ccb)
{
+ int rtn = 0;
switch (acb->adapter_type) {
case ACB_ADAPTER_TYPE_A: {
- arcmsr_polling_hba_ccbdone(acb,poll_ccb);
+ rtn = arcmsr_polling_hba_ccbdone(acb, poll_ccb);
}
break;
case ACB_ADAPTER_TYPE_B: {
- arcmsr_polling_hbb_ccbdone(acb,poll_ccb);
+ rtn = arcmsr_polling_hbb_ccbdone(acb, poll_ccb);
+ }
+ break;
+ case ACB_ADAPTER_TYPE_C: {
+ rtn = arcmsr_polling_hbc_ccbdone(acb, poll_ccb);
}
}
+ return rtn;
}
static int arcmsr_iop_confirm(struct AdapterControlBlock *acb)
{
- uint32_t cdb_phyaddr, ccb_phyaddr_hi32;
+ uint32_t cdb_phyaddr, cdb_phyaddr_hi32;
dma_addr_t dma_coherent_handle;
/*
********************************************************************
@@ -2182,7 +2535,8 @@ static int arcmsr_iop_confirm(struct AdapterControlBlock *acb)
*/
dma_coherent_handle = acb->dma_coherent_handle;
cdb_phyaddr = (uint32_t)(dma_coherent_handle);
- ccb_phyaddr_hi32 = (uint32_t)((cdb_phyaddr >> 16) >> 16);
+ cdb_phyaddr_hi32 = (uint32_t)((cdb_phyaddr >> 16) >> 16);
+ acb->cdb_phyaddr_hi32 = cdb_phyaddr_hi32;
/*
***********************************************************************
** if adapter type B, set window of "post command Q"
@@ -2191,16 +2545,16 @@ static int arcmsr_iop_confirm(struct AdapterControlBlock *acb)
switch (acb->adapter_type) {
case ACB_ADAPTER_TYPE_A: {
- if (ccb_phyaddr_hi32 != 0) {
+ if (cdb_phyaddr_hi32 != 0) {
struct MessageUnit_A __iomem *reg = acb->pmuA;
uint32_t intmask_org;
intmask_org = arcmsr_disable_outbound_ints(acb);
writel(ARCMSR_SIGNATURE_SET_CONFIG, \
&reg->message_rwbuffer[0]);
- writel(ccb_phyaddr_hi32, &reg->message_rwbuffer[1]);
+ writel(cdb_phyaddr_hi32, &reg->message_rwbuffer[1]);
writel(ARCMSR_INBOUND_MESG0_SET_CONFIG, \
&reg->inbound_msgaddr0);
- if (arcmsr_hba_wait_msgint_ready(acb)) {
+ if (!arcmsr_hba_wait_msgint_ready(acb)) {
printk(KERN_NOTICE "arcmsr%d: ""set ccb high \
part physical address timeout\n",
acb->host->host_no);
@@ -2220,19 +2574,18 @@ static int arcmsr_iop_confirm(struct AdapterControlBlock *acb)
intmask_org = arcmsr_disable_outbound_ints(acb);
reg->postq_index = 0;
reg->doneq_index = 0;
- writel(ARCMSR_MESSAGE_SET_POST_WINDOW, reg->drv2iop_doorbell_reg);
- if (arcmsr_hbb_wait_msgint_ready(acb)) {
+ writel(ARCMSR_MESSAGE_SET_POST_WINDOW, reg->drv2iop_doorbell);
+ if (!arcmsr_hbb_wait_msgint_ready(acb)) {
printk(KERN_NOTICE "arcmsr%d:can not set diver mode\n", \
acb->host->host_no);
return 1;
}
- post_queue_phyaddr = cdb_phyaddr + ARCMSR_MAX_FREECCB_NUM * \
- sizeof(struct CommandControlBlock) + offsetof(struct MessageUnit_B, post_qbuffer) ;
- rwbuffer = reg->msgcode_rwbuffer_reg;
+ post_queue_phyaddr = acb->dma_coherent_handle_hbb_mu;
+ rwbuffer = reg->message_rwbuffer;
/* driver "set config" signature */
writel(ARCMSR_SIGNATURE_SET_CONFIG, rwbuffer++);
/* normal should be zero */
- writel(ccb_phyaddr_hi32, rwbuffer++);
+ writel(cdb_phyaddr_hi32, rwbuffer++);
/* postQ size (256 + 8)*4 */
writel(post_queue_phyaddr, rwbuffer++);
/* doneQ size (256 + 8)*4 */
@@ -2240,22 +2593,37 @@ static int arcmsr_iop_confirm(struct AdapterControlBlock *acb)
/* ccb maxQ size must be --> [(256 + 8)*4]*/
writel(1056, rwbuffer);
- writel(ARCMSR_MESSAGE_SET_CONFIG, reg->drv2iop_doorbell_reg);
- if (arcmsr_hbb_wait_msgint_ready(acb)) {
+ writel(ARCMSR_MESSAGE_SET_CONFIG, reg->drv2iop_doorbell);
+ if (!arcmsr_hbb_wait_msgint_ready(acb)) {
printk(KERN_NOTICE "arcmsr%d: 'set command Q window' \
timeout \n",acb->host->host_no);
return 1;
}
-
- writel(ARCMSR_MESSAGE_START_DRIVER_MODE, reg->drv2iop_doorbell_reg);
- if (arcmsr_hbb_wait_msgint_ready(acb)) {
- printk(KERN_NOTICE "arcmsr%d: 'can not set diver mode \n"\
- ,acb->host->host_no);
- return 1;
- }
+ arcmsr_hbb_enable_driver_mode(acb);
arcmsr_enable_outbound_ints(acb, intmask_org);
}
break;
+ case ACB_ADAPTER_TYPE_C: {
+ if (cdb_phyaddr_hi32 != 0) {
+ struct MessageUnit_C *reg = (struct MessageUnit_C *)acb->pmuC;
+
+ if (cdb_phyaddr_hi32 != 0) {
+ unsigned char Retries = 0x00;
+ do {
+ printk(KERN_NOTICE "arcmsr%d: cdb_phyaddr_hi32=0x%x \n", acb->adapter_index, cdb_phyaddr_hi32);
+ } while (Retries++ < 100);
+ }
+ writel(ARCMSR_SIGNATURE_SET_CONFIG, &reg->msgcode_rwbuffer[0]);
+ writel(cdb_phyaddr_hi32, &reg->msgcode_rwbuffer[1]);
+ writel(ARCMSR_INBOUND_MESG0_SET_CONFIG, &reg->inbound_msgaddr0);
+ writel(ARCMSR_HBCMU_DRV2IOP_MESSAGE_CMD_DONE, &reg->inbound_doorbell);
+ if (!arcmsr_hbc_wait_msgint_ready(acb)) {
+ printk(KERN_NOTICE "arcmsr%d: 'set command Q window' \
+ timeout \n", acb->host->host_no);
+ return 1;
+ }
+ }
+ }
}
return 0;
}
@@ -2263,7 +2631,6 @@ static int arcmsr_iop_confirm(struct AdapterControlBlock *acb)
static void arcmsr_wait_firmware_ready(struct AdapterControlBlock *acb)
{
uint32_t firmware_state = 0;
-
switch (acb->adapter_type) {
case ACB_ADAPTER_TYPE_A: {
@@ -2277,62 +2644,81 @@ static void arcmsr_wait_firmware_ready(struct AdapterControlBlock *acb)
case ACB_ADAPTER_TYPE_B: {
struct MessageUnit_B *reg = acb->pmuB;
do {
- firmware_state = readl(reg->iop2drv_doorbell_reg);
+ firmware_state = readl(reg->iop2drv_doorbell);
} while ((firmware_state & ARCMSR_MESSAGE_FIRMWARE_OK) == 0);
- writel(ARCMSR_DRV2IOP_END_OF_INTERRUPT, reg->drv2iop_doorbell_reg);
+ writel(ARCMSR_DRV2IOP_END_OF_INTERRUPT, reg->drv2iop_doorbell);
}
break;
+ case ACB_ADAPTER_TYPE_C: {
+ struct MessageUnit_C *reg = (struct MessageUnit_C *)acb->pmuC;
+ do {
+ firmware_state = readl(&reg->outbound_msgaddr1);
+ } while ((firmware_state & ARCMSR_HBCMU_MESSAGE_FIRMWARE_OK) == 0);
+ }
}
}
static void arcmsr_request_hba_device_map(struct AdapterControlBlock *acb)
{
struct MessageUnit_A __iomem *reg = acb->pmuA;
-
- if (unlikely(atomic_read(&acb->rq_map_token) == 0)) {
- acb->fw_state = false;
+ if (unlikely(atomic_read(&acb->rq_map_token) == 0) || ((acb->acb_flags & ACB_F_BUS_RESET) != 0 ) || ((acb->acb_flags & ACB_F_ABORT) != 0 )){
+ return;
} else {
- /*to prevent rq_map_token from changing by other interrupt, then
- avoid the dead-lock*/
- acb->fw_state = true;
- atomic_dec(&acb->rq_map_token);
- if (!(acb->fw_state) ||
- (acb->ante_token_value == atomic_read(&acb->rq_map_token))) {
+ acb->fw_flag = FW_NORMAL;
+ if (atomic_read(&acb->ante_token_value) == atomic_read(&acb->rq_map_token)){
atomic_set(&acb->rq_map_token, 16);
}
- acb->ante_token_value = atomic_read(&acb->rq_map_token);
+ atomic_set(&acb->ante_token_value, atomic_read(&acb->rq_map_token));
+ if (atomic_dec_and_test(&acb->rq_map_token))
+ return;
writel(ARCMSR_INBOUND_MESG0_GET_CONFIG, &reg->inbound_msgaddr0);
+ mod_timer(&acb->eternal_timer, jiffies + msecs_to_jiffies(6 * HZ));
}
- mod_timer(&acb->eternal_timer, jiffies + msecs_to_jiffies(6000));
return;
}
static void arcmsr_request_hbb_device_map(struct AdapterControlBlock *acb)
{
struct MessageUnit_B __iomem *reg = acb->pmuB;
+ if (unlikely(atomic_read(&acb->rq_map_token) == 0) || ((acb->acb_flags & ACB_F_BUS_RESET) != 0 ) || ((acb->acb_flags & ACB_F_ABORT) != 0 )){
+ return;
+ } else {
+ acb->fw_flag = FW_NORMAL;
+ if (atomic_read(&acb->ante_token_value) == atomic_read(&acb->rq_map_token)) {
+ atomic_set(&acb->rq_map_token,16);
+ }
+ atomic_set(&acb->ante_token_value, atomic_read(&acb->rq_map_token));
+ if(atomic_dec_and_test(&acb->rq_map_token))
+ return;
+ writel(ARCMSR_MESSAGE_GET_CONFIG, reg->drv2iop_doorbell);
+ mod_timer(&acb->eternal_timer, jiffies + msecs_to_jiffies(6 * HZ));
+ }
+ return;
+}
- if (unlikely(atomic_read(&acb->rq_map_token) == 0)) {
- acb->fw_state = false;
+static void arcmsr_request_hbc_device_map(struct AdapterControlBlock *acb)
+{
+ struct MessageUnit_C __iomem *reg = acb->pmuC;
+ if (unlikely(atomic_read(&acb->rq_map_token) == 0) || ((acb->acb_flags & ACB_F_BUS_RESET) != 0) || ((acb->acb_flags & ACB_F_ABORT) != 0)) {
+ return;
} else {
- /*to prevent rq_map_token from changing by other interrupt, then
- avoid the dead-lock*/
- acb->fw_state = true;
- atomic_dec(&acb->rq_map_token);
- if (!(acb->fw_state) ||
- (acb->ante_token_value == atomic_read(&acb->rq_map_token))) {
+ acb->fw_flag = FW_NORMAL;
+ if (atomic_read(&acb->ante_token_value) == atomic_read(&acb->rq_map_token)) {
atomic_set(&acb->rq_map_token, 16);
}
- acb->ante_token_value = atomic_read(&acb->rq_map_token);
- writel(ARCMSR_MESSAGE_GET_CONFIG, reg->drv2iop_doorbell_reg);
+ atomic_set(&acb->ante_token_value, atomic_read(&acb->rq_map_token));
+ if (atomic_dec_and_test(&acb->rq_map_token))
+ return;
+ writel(ARCMSR_INBOUND_MESG0_GET_CONFIG, &reg->inbound_msgaddr0);
+ writel(ARCMSR_HBCMU_DRV2IOP_MESSAGE_CMD_DONE, &reg->inbound_doorbell);
+ mod_timer(&acb->eternal_timer, jiffies + msecs_to_jiffies(6 * HZ));
}
- mod_timer(&acb->eternal_timer, jiffies + msecs_to_jiffies(6000));
return;
}
static void arcmsr_request_device_map(unsigned long pacb)
{
struct AdapterControlBlock *acb = (struct AdapterControlBlock *)pacb;
-
switch (acb->adapter_type) {
case ACB_ADAPTER_TYPE_A: {
arcmsr_request_hba_device_map(acb);
@@ -2342,6 +2728,9 @@ static void arcmsr_request_device_map(unsigned long pacb)
arcmsr_request_hbb_device_map(acb);
}
break;
+ case ACB_ADAPTER_TYPE_C: {
+ arcmsr_request_hbc_device_map(acb);
+ }
}
}
@@ -2350,7 +2739,7 @@ static void arcmsr_start_hba_bgrb(struct AdapterControlBlock *acb)
struct MessageUnit_A __iomem *reg = acb->pmuA;
acb->acb_flags |= ACB_F_MSG_START_BGRB;
writel(ARCMSR_INBOUND_MESG0_START_BGRB, &reg->inbound_msgaddr0);
- if (arcmsr_hba_wait_msgint_ready(acb)) {
+ if (!arcmsr_hba_wait_msgint_ready(acb)) {
printk(KERN_NOTICE "arcmsr%d: wait 'start adapter background \
rebulid' timeout \n", acb->host->host_no);
}
@@ -2360,13 +2749,25 @@ static void arcmsr_start_hbb_bgrb(struct AdapterControlBlock *acb)
{
struct MessageUnit_B *reg = acb->pmuB;
acb->acb_flags |= ACB_F_MSG_START_BGRB;
- writel(ARCMSR_MESSAGE_START_BGRB, reg->drv2iop_doorbell_reg);
- if (arcmsr_hbb_wait_msgint_ready(acb)) {
+ writel(ARCMSR_MESSAGE_START_BGRB, reg->drv2iop_doorbell);
+ if (!arcmsr_hbb_wait_msgint_ready(acb)) {
printk(KERN_NOTICE "arcmsr%d: wait 'start adapter background \
rebulid' timeout \n",acb->host->host_no);
}
}
+static void arcmsr_start_hbc_bgrb(struct AdapterControlBlock *pACB)
+{
+ struct MessageUnit_C *phbcmu = (struct MessageUnit_C *)pACB->pmuC;
+ pACB->acb_flags |= ACB_F_MSG_START_BGRB;
+ writel(ARCMSR_INBOUND_MESG0_START_BGRB, &phbcmu->inbound_msgaddr0);
+ writel(ARCMSR_HBCMU_DRV2IOP_MESSAGE_CMD_DONE, &phbcmu->inbound_doorbell);
+ if (!arcmsr_hbc_wait_msgint_ready(pACB)) {
+ printk(KERN_NOTICE "arcmsr%d: wait 'start adapter background \
+ rebulid' timeout \n", pACB->host->host_no);
+ }
+ return;
+}
static void arcmsr_start_adapter_bgrb(struct AdapterControlBlock *acb)
{
switch (acb->adapter_type) {
@@ -2376,6 +2777,8 @@ static void arcmsr_start_adapter_bgrb(struct AdapterControlBlock *acb)
case ACB_ADAPTER_TYPE_B:
arcmsr_start_hbb_bgrb(acb);
break;
+ case ACB_ADAPTER_TYPE_C:
+ arcmsr_start_hbc_bgrb(acb);
}
}
@@ -2396,11 +2799,19 @@ static void arcmsr_clear_doorbell_queue_buffer(struct AdapterControlBlock *acb)
case ACB_ADAPTER_TYPE_B: {
struct MessageUnit_B *reg = acb->pmuB;
/*clear interrupt and message state*/
- writel(ARCMSR_MESSAGE_INT_CLEAR_PATTERN, reg->iop2drv_doorbell_reg);
- writel(ARCMSR_DRV2IOP_DATA_READ_OK, reg->drv2iop_doorbell_reg);
+ writel(ARCMSR_MESSAGE_INT_CLEAR_PATTERN, reg->iop2drv_doorbell);
+ writel(ARCMSR_DRV2IOP_DATA_READ_OK, reg->drv2iop_doorbell);
/* let IOP know data has been read */
}
break;
+ case ACB_ADAPTER_TYPE_C: {
+ struct MessageUnit_C *reg = (struct MessageUnit_C *)acb->pmuC;
+ uint32_t outbound_doorbell;
+ /* empty doorbell Qbuffer if door bell ringed */
+ outbound_doorbell = readl(&reg->outbound_doorbell);
+ writel(outbound_doorbell, &reg->outbound_doorbell_clear);
+ writel(ARCMSR_HBCMU_DRV2IOP_DATA_READ_OK, &reg->inbound_doorbell);
+ }
}
}
@@ -2412,13 +2823,15 @@ static void arcmsr_enable_eoi_mode(struct AdapterControlBlock *acb)
case ACB_ADAPTER_TYPE_B:
{
struct MessageUnit_B *reg = acb->pmuB;
- writel(ARCMSR_MESSAGE_ACTIVE_EOI_MODE, reg->drv2iop_doorbell_reg);
- if(arcmsr_hbb_wait_msgint_ready(acb)) {
+ writel(ARCMSR_MESSAGE_ACTIVE_EOI_MODE, reg->drv2iop_doorbell);
+ if (!arcmsr_hbb_wait_msgint_ready(acb)) {
printk(KERN_NOTICE "ARCMSR IOP enables EOI_MODE TIMEOUT");
return;
}
}
break;
+ case ACB_ADAPTER_TYPE_C:
+ return;
}
return;
}
@@ -2426,15 +2839,33 @@ static void arcmsr_enable_eoi_mode(struct AdapterControlBlock *acb)
static void arcmsr_hardware_reset(struct AdapterControlBlock *acb)
{
uint8_t value[64];
- int i;
-
+ int i, count = 0;
+ struct MessageUnit_A __iomem *pmuA = acb->pmuA;
+ struct MessageUnit_C __iomem *pmuC = acb->pmuC;
+ u32 temp = 0;
/* backup pci config data */
+ printk(KERN_NOTICE "arcmsr%d: executing hw bus reset .....\n", acb->host->host_no);
for (i = 0; i < 64; i++) {
pci_read_config_byte(acb->pdev, i, &value[i]);
}
/* hardware reset signal */
- pci_write_config_byte(acb->pdev, 0x84, 0x20);
- msleep(1000);
+ if ((acb->dev_id == 0x1680)) {
+ writel(ARCMSR_ARC1680_BUS_RESET, &pmuA->reserved1[0]);
+ } else if ((acb->dev_id == 0x1880)) {
+ do {
+ count++;
+ writel(0xF, &pmuC->write_sequence);
+ writel(0x4, &pmuC->write_sequence);
+ writel(0xB, &pmuC->write_sequence);
+ writel(0x2, &pmuC->write_sequence);
+ writel(0x7, &pmuC->write_sequence);
+ writel(0xD, &pmuC->write_sequence);
+ } while ((((temp = readl(&pmuC->host_diagnostic)) | ARCMSR_ARC1880_DiagWrite_ENABLE) == 0) && (count < 5));
+ writel(ARCMSR_ARC1880_RESET_ADAPTER, &pmuC->host_diagnostic);
+ } else {
+ pci_write_config_byte(acb->pdev, 0x84, 0x20);
+ }
+ msleep(2000);
/* write back pci config data */
for (i = 0; i < 64; i++) {
pci_write_config_byte(acb->pdev, i, value[i]);
@@ -2442,50 +2873,13 @@ static void arcmsr_hardware_reset(struct AdapterControlBlock *acb)
msleep(1000);
return;
}
-/*
-****************************************************************************
-****************************************************************************
-*/
-#ifdef CONFIG_SCSI_ARCMSR_RESET
- int arcmsr_sleep_for_bus_reset(struct scsi_cmnd *cmd)
- {
- struct Scsi_Host *shost = NULL;
- spinlock_t *host_lock = NULL;
- int i, isleep;
-
- shost = cmd->device->host;
- host_lock = shost->host_lock;
-
- printk(KERN_NOTICE "Host %d bus reset over, sleep %d seconds (busy %d, can queue %d) ...........\n",
- shost->host_no, sleeptime, shost->host_busy, shost->can_queue);
- isleep = sleeptime / 10;
- spin_unlock_irq(host_lock);
- if (isleep > 0) {
- for (i = 0; i < isleep; i++) {
- msleep(10000);
- printk(KERN_NOTICE "^%d^\n", i);
- }
- }
-
- isleep = sleeptime % 10;
- if (isleep > 0) {
- msleep(isleep * 1000);
- printk(KERN_NOTICE "^v^\n");
- }
- spin_lock_irq(host_lock);
- printk(KERN_NOTICE "***** wake up *****\n");
- return 0;
- }
-#endif
static void arcmsr_iop_init(struct AdapterControlBlock *acb)
{
uint32_t intmask_org;
-
- /* disable all outbound interrupt */
- intmask_org = arcmsr_disable_outbound_ints(acb);
+ /* disable all outbound interrupt */
+ intmask_org = arcmsr_disable_outbound_ints(acb);
arcmsr_wait_firmware_ready(acb);
arcmsr_iop_confirm(acb);
- arcmsr_get_firmware_spec(acb, 1);
/*start background rebuild*/
arcmsr_start_adapter_bgrb(acb);
/* empty doorbell Qbuffer if door bell ringed */
@@ -2502,20 +2896,17 @@ static uint8_t arcmsr_iop_reset(struct AdapterControlBlock *acb)
uint32_t intmask_org;
uint8_t rtnval = 0x00;
int i = 0;
-
if (atomic_read(&acb->ccboutstandingcount) != 0) {
/* disable all outbound interrupt */
intmask_org = arcmsr_disable_outbound_ints(acb);
/* talk to iop 331 outstanding command aborted */
rtnval = arcmsr_abort_allcmd(acb);
- /* wait for 3 sec for all command aborted*/
- ssleep(3);
/* clear all outbound posted Q */
arcmsr_done4abort_postqueue(acb);
for (i = 0; i < ARCMSR_MAX_FREECCB_NUM; i++) {
ccb = acb->pccb_pool[i];
if (ccb->startdone == ARCMSR_CCB_START) {
- arcmsr_ccb_complete(ccb, 1);
+ arcmsr_ccb_complete(ccb);
}
}
atomic_set(&acb->ccboutstandingcount, 0);
@@ -2530,94 +2921,190 @@ static int arcmsr_bus_reset(struct scsi_cmnd *cmd)
{
struct AdapterControlBlock *acb =
(struct AdapterControlBlock *)cmd->device->host->hostdata;
- int retry = 0;
-
- if (acb->acb_flags & ACB_F_BUS_RESET)
- return SUCCESS;
-
- printk(KERN_NOTICE "arcmsr%d: bus reset ..... \n", acb->adapter_index);
- acb->acb_flags |= ACB_F_BUS_RESET;
+ uint32_t intmask_org, outbound_doorbell;
+ int retry_count = 0;
+ int rtn = FAILED;
+ acb = (struct AdapterControlBlock *) cmd->device->host->hostdata;
+ printk(KERN_ERR "arcmsr: executing bus reset eh.....num_resets = %d, num_aborts = %d \n", acb->num_resets, acb->num_aborts);
acb->num_resets++;
- while (atomic_read(&acb->ccboutstandingcount) != 0 && retry < 4) {
- arcmsr_interrupt(acb);
- retry++;
- }
- if (arcmsr_iop_reset(acb)) {
- switch (acb->adapter_type) {
- case ACB_ADAPTER_TYPE_A: {
- printk(KERN_NOTICE "arcmsr%d: do hardware bus reset, num_resets = %d num_aborts = %d \n",
- acb->adapter_index, acb->num_resets, acb->num_aborts);
- arcmsr_hardware_reset(acb);
- acb->acb_flags |= ACB_F_FIRMWARE_TRAP;
- acb->acb_flags &= ~ACB_F_IOP_INITED;
- #ifdef CONFIG_SCSI_ARCMSR_RESET
- struct MessageUnit_A __iomem *reg = acb->pmuA;
- uint32_t intmask_org, outbound_doorbell;
- int retry_count = 0;
+ switch(acb->adapter_type){
+ case ACB_ADAPTER_TYPE_A:{
+ if (acb->acb_flags & ACB_F_BUS_RESET){
+ long timeout;
+ printk(KERN_ERR "arcmsr: there is an bus reset eh proceeding.......\n");
+ timeout = wait_event_timeout(wait_q, (acb->acb_flags & ACB_F_BUS_RESET) == 0, 220*HZ);
+ if (timeout) {
+ return SUCCESS;
+ }
+ }
+ acb->acb_flags |= ACB_F_BUS_RESET;
+ if (!arcmsr_iop_reset(acb)) {
+ struct MessageUnit_A __iomem *reg;
+ reg = acb->pmuA;
+ arcmsr_hardware_reset(acb);
+ acb->acb_flags &= ~ACB_F_IOP_INITED;
sleep_again:
- arcmsr_sleep_for_bus_reset(cmd);
- if ((readl(&reg->outbound_msgaddr1) &
- ARCMSR_OUTBOUND_MESG1_FIRMWARE_OK) == 0) {
- printk(KERN_NOTICE "arcmsr%d: hardware bus reset and return busy, retry=%d \n",
- acb->host->host_no, retry_count);
- if (retry_count > retrycount) {
- printk(KERN_NOTICE "arcmsr%d: hardware bus reset and return busy, retry aborted \n",
- acb->host->host_no);
- return SUCCESS;
+ arcmsr_sleep_for_bus_reset(cmd);
+ if ((readl(&reg->outbound_msgaddr1) & ARCMSR_OUTBOUND_MESG1_FIRMWARE_OK) == 0) {
+ printk(KERN_ERR "arcmsr%d: waiting for hw bus reset return, retry=%d \n", acb->host->host_no, retry_count);
+ if (retry_count > retrycount) {
+ acb->fw_flag = FW_DEADLOCK;
+ printk(KERN_ERR "arcmsr%d: waiting for hw bus reset return, RETRY TERMINATED!! \n", acb->host->host_no);
+ return FAILED;
+ }
+ retry_count++;
+ goto sleep_again;
+ }
+ acb->acb_flags |= ACB_F_IOP_INITED;
+ /* disable all outbound interrupt */
+ intmask_org = arcmsr_disable_outbound_ints(acb);
+ arcmsr_get_firmware_spec(acb);
+ arcmsr_start_adapter_bgrb(acb);
+ /* clear Qbuffer if door bell ringed */
+ outbound_doorbell = readl(&reg->outbound_doorbell);
+ writel(outbound_doorbell, &reg->outbound_doorbell); /*clear interrupt */
+ writel(ARCMSR_INBOUND_DRIVER_DATA_READ_OK, &reg->inbound_doorbell);
+ /* enable outbound Post Queue,outbound doorbell Interrupt */
+ arcmsr_enable_outbound_ints(acb, intmask_org);
+ atomic_set(&acb->rq_map_token, 16);
+ atomic_set(&acb->ante_token_value, 16);
+ acb->fw_flag = FW_NORMAL;
+ init_timer(&acb->eternal_timer);
+ acb->eternal_timer.expires = jiffies + msecs_to_jiffies(6*HZ);
+ acb->eternal_timer.data = (unsigned long) acb;
+ acb->eternal_timer.function = &arcmsr_request_device_map;
+ add_timer(&acb->eternal_timer);
+ acb->acb_flags &= ~ACB_F_BUS_RESET;
+ rtn = SUCCESS;
+ printk(KERN_ERR "arcmsr: scsi bus reset eh returns with success\n");
+ } else {
+ acb->acb_flags &= ~ACB_F_BUS_RESET;
+ if (atomic_read(&acb->rq_map_token) == 0) {
+ atomic_set(&acb->rq_map_token, 16);
+ atomic_set(&acb->ante_token_value, 16);
+ acb->fw_flag = FW_NORMAL;
+ init_timer(&acb->eternal_timer);
+ acb->eternal_timer.expires = jiffies + msecs_to_jiffies(6*HZ);
+ acb->eternal_timer.data = (unsigned long) acb;
+ acb->eternal_timer.function = &arcmsr_request_device_map;
+ add_timer(&acb->eternal_timer);
+ } else {
+ atomic_set(&acb->rq_map_token, 16);
+ atomic_set(&acb->ante_token_value, 16);
+ acb->fw_flag = FW_NORMAL;
+ mod_timer(&acb->eternal_timer, jiffies + msecs_to_jiffies(6*HZ));
+ }
+ rtn = SUCCESS;
}
- retry_count++;
- goto sleep_again;
+ break;
+ }
+ case ACB_ADAPTER_TYPE_B:{
+ acb->acb_flags |= ACB_F_BUS_RESET;
+ if (!arcmsr_iop_reset(acb)) {
+ acb->acb_flags &= ~ACB_F_BUS_RESET;
+ rtn = FAILED;
+ } else {
+ acb->acb_flags &= ~ACB_F_BUS_RESET;
+ if (atomic_read(&acb->rq_map_token) == 0) {
+ atomic_set(&acb->rq_map_token, 16);
+ atomic_set(&acb->ante_token_value, 16);
+ acb->fw_flag = FW_NORMAL;
+ init_timer(&acb->eternal_timer);
+ acb->eternal_timer.expires = jiffies + msecs_to_jiffies(6*HZ);
+ acb->eternal_timer.data = (unsigned long) acb;
+ acb->eternal_timer.function = &arcmsr_request_device_map;
+ add_timer(&acb->eternal_timer);
+ } else {
+ atomic_set(&acb->rq_map_token, 16);
+ atomic_set(&acb->ante_token_value, 16);
+ acb->fw_flag = FW_NORMAL;
+ mod_timer(&acb->eternal_timer, jiffies + msecs_to_jiffies(6*HZ));
+ }
+ rtn = SUCCESS;
}
- acb->acb_flags &= ~ACB_F_FIRMWARE_TRAP;
- acb->acb_flags |= ACB_F_IOP_INITED;
- acb->acb_flags &= ~ACB_F_BUS_RESET;
- printk(KERN_NOTICE "arcmsr%d: hardware bus reset and reset ok \n",
- acb->host->host_no);
- /* disable all outbound interrupt */
- intmask_org = arcmsr_disable_outbound_ints(acb);
- arcmsr_get_firmware_spec(acb, 1);
- /*start background rebuild*/
- arcmsr_start_adapter_bgrb(acb);
- /* clear Qbuffer if door bell ringed */
- outbound_doorbell = readl(&reg->outbound_doorbell);
- writel(outbound_doorbell, &reg->outbound_doorbell); /*clear interrupt */
- writel(ARCMSR_INBOUND_DRIVER_DATA_READ_OK, &reg->inbound_doorbell);
- /* enable outbound Post Queue,outbound doorbell Interrupt */
- arcmsr_enable_outbound_ints(acb, intmask_org);
- atomic_set(&acb->rq_map_token, 16);
- init_timer(&acb->eternal_timer);
- acb->eternal_timer.expires = jiffies + msecs_to_jiffies(20*HZ);
- acb->eternal_timer.data = (unsigned long) acb;
- acb->eternal_timer.function = &arcmsr_request_device_map;
- add_timer(&acb->eternal_timer);
- #endif
+ break;
}
+ case ACB_ADAPTER_TYPE_C:{
+ if (acb->acb_flags & ACB_F_BUS_RESET) {
+ long timeout;
+ printk(KERN_ERR "arcmsr: there is an bus reset eh proceeding.......\n");
+ timeout = wait_event_timeout(wait_q, (acb->acb_flags & ACB_F_BUS_RESET) == 0, 220*HZ);
+ if (timeout) {
+ return SUCCESS;
+ }
+ }
+ acb->acb_flags |= ACB_F_BUS_RESET;
+ if (!arcmsr_iop_reset(acb)) {
+ struct MessageUnit_C __iomem *reg;
+ reg = acb->pmuC;
+ arcmsr_hardware_reset(acb);
+ acb->acb_flags &= ~ACB_F_IOP_INITED;
+sleep:
+ arcmsr_sleep_for_bus_reset(cmd);
+ if ((readl(&reg->host_diagnostic) & 0x04) != 0) {
+ printk(KERN_ERR "arcmsr%d: waiting for hw bus reset return, retry=%d \n", acb->host->host_no, retry_count);
+ if (retry_count > retrycount) {
+ acb->fw_flag = FW_DEADLOCK;
+ printk(KERN_ERR "arcmsr%d: waiting for hw bus reset return, RETRY TERMINATED!! \n", acb->host->host_no);
+ return FAILED;
+ }
+ retry_count++;
+ goto sleep;
+ }
+ acb->acb_flags |= ACB_F_IOP_INITED;
+ /* disable all outbound interrupt */
+ intmask_org = arcmsr_disable_outbound_ints(acb);
+ arcmsr_get_firmware_spec(acb);
+ arcmsr_start_adapter_bgrb(acb);
+ /* clear Qbuffer if door bell ringed */
+ outbound_doorbell = readl(&reg->outbound_doorbell);
+ writel(outbound_doorbell, &reg->outbound_doorbell_clear); /*clear interrupt */
+ writel(ARCMSR_HBCMU_DRV2IOP_DATA_READ_OK, &reg->inbound_doorbell);
+ /* enable outbound Post Queue,outbound doorbell Interrupt */
+ arcmsr_enable_outbound_ints(acb, intmask_org);
+ atomic_set(&acb->rq_map_token, 16);
+ atomic_set(&acb->ante_token_value, 16);
+ acb->fw_flag = FW_NORMAL;
+ init_timer(&acb->eternal_timer);
+ acb->eternal_timer.expires = jiffies + msecs_to_jiffies(6 * HZ);
+ acb->eternal_timer.data = (unsigned long) acb;
+ acb->eternal_timer.function = &arcmsr_request_device_map;
+ add_timer(&acb->eternal_timer);
+ acb->acb_flags &= ~ACB_F_BUS_RESET;
+ rtn = SUCCESS;
+ printk(KERN_ERR "arcmsr: scsi bus reset eh returns with success\n");
+ } else {
+ acb->acb_flags &= ~ACB_F_BUS_RESET;
+ if (atomic_read(&acb->rq_map_token) == 0) {
+ atomic_set(&acb->rq_map_token, 16);
+ atomic_set(&acb->ante_token_value, 16);
+ acb->fw_flag = FW_NORMAL;
+ init_timer(&acb->eternal_timer);
+ acb->eternal_timer.expires = jiffies + msecs_to_jiffies(6*HZ);
+ acb->eternal_timer.data = (unsigned long) acb;
+ acb->eternal_timer.function = &arcmsr_request_device_map;
+ add_timer(&acb->eternal_timer);
+ } else {
+ atomic_set(&acb->rq_map_token, 16);
+ atomic_set(&acb->ante_token_value, 16);
+ acb->fw_flag = FW_NORMAL;
+ mod_timer(&acb->eternal_timer, jiffies + msecs_to_jiffies(6*HZ));
+ }
+ rtn = SUCCESS;
+ }
break;
- case ACB_ADAPTER_TYPE_B: {
- }
}
- } else {
- acb->acb_flags &= ~ACB_F_BUS_RESET;
}
- return SUCCESS;
+ return rtn;
}
-static void arcmsr_abort_one_cmd(struct AdapterControlBlock *acb,
+static int arcmsr_abort_one_cmd(struct AdapterControlBlock *acb,
struct CommandControlBlock *ccb)
{
- u32 intmask;
-
- ccb->startdone = ARCMSR_CCB_ABORTED;
-
- /*
- ** Wait for 3 sec for all command done.
- */
- ssleep(3);
-
- intmask = arcmsr_disable_outbound_ints(acb);
- arcmsr_polling_ccbdone(acb, ccb);
- arcmsr_enable_outbound_ints(acb, intmask);
+ int rtn;
+ rtn = arcmsr_polling_ccbdone(acb, ccb);
+ return rtn;
}
static int arcmsr_abort(struct scsi_cmnd *cmd)
@@ -2625,10 +3112,11 @@ static int arcmsr_abort(struct scsi_cmnd *cmd)
struct AdapterControlBlock *acb =
(struct AdapterControlBlock *)cmd->device->host->hostdata;
int i = 0;
-
+ int rtn = FAILED;
printk(KERN_NOTICE
"arcmsr%d: abort device command of scsi id = %d lun = %d \n",
acb->host->host_no, cmd->device->id, cmd->device->lun);
+ acb->acb_flags |= ACB_F_ABORT;
acb->num_aborts++;
/*
************************************************
@@ -2637,17 +3125,18 @@ static int arcmsr_abort(struct scsi_cmnd *cmd)
************************************************
*/
if (!atomic_read(&acb->ccboutstandingcount))
- return SUCCESS;
+ return rtn;
for (i = 0; i < ARCMSR_MAX_FREECCB_NUM; i++) {
struct CommandControlBlock *ccb = acb->pccb_pool[i];
if (ccb->startdone == ARCMSR_CCB_START && ccb->pcmd == cmd) {
- arcmsr_abort_one_cmd(acb, ccb);
+ ccb->startdone = ARCMSR_CCB_ABORTED;
+ rtn = arcmsr_abort_one_cmd(acb, ccb);
break;
}
}
-
- return SUCCESS;
+ acb->acb_flags &= ~ACB_F_ABORT;
+ return rtn;
}
static const char *arcmsr_info(struct Scsi_Host *host)
@@ -2657,7 +3146,6 @@ static const char *arcmsr_info(struct Scsi_Host *host)
static char buf[256];
char *type;
int raid6 = 1;
-
switch (acb->pdev->device) {
case PCI_DEVICE_ID_ARECA_1110:
case PCI_DEVICE_ID_ARECA_1200:
@@ -2681,6 +3169,7 @@ static const char *arcmsr_info(struct Scsi_Host *host)
case PCI_DEVICE_ID_ARECA_1381:
case PCI_DEVICE_ID_ARECA_1680:
case PCI_DEVICE_ID_ARECA_1681:
+ case PCI_DEVICE_ID_ARECA_1880:
type = "SAS";
break;
default:
diff --git a/drivers/scsi/be2iscsi/Kconfig b/drivers/scsi/be2iscsi/Kconfig
index 2952fcd008e..84c275fb9f6 100644
--- a/drivers/scsi/be2iscsi/Kconfig
+++ b/drivers/scsi/be2iscsi/Kconfig
@@ -1,6 +1,6 @@
config BE2ISCSI
tristate "ServerEngines' 10Gbps iSCSI - BladeEngine 2"
- depends on PCI && SCSI
+ depends on PCI && SCSI && NET
select SCSI_ISCSI_ATTRS
help
diff --git a/drivers/scsi/be2iscsi/be.h b/drivers/scsi/be2iscsi/be.h
index 136b49cea79..1cb8a5e85c7 100644
--- a/drivers/scsi/be2iscsi/be.h
+++ b/drivers/scsi/be2iscsi/be.h
@@ -128,8 +128,8 @@ struct be_ctrl_info {
#define mcc_timeout 120000 /* 5s timeout */
/* Returns number of pages spanned by the data starting at the given addr */
-#define PAGES_4K_SPANNED(_address, size) \
- ((u32)((((size_t)(_address) & (PAGE_SIZE_4K - 1)) + \
+#define PAGES_4K_SPANNED(_address, size) \
+ ((u32)((((size_t)(_address) & (PAGE_SIZE_4K - 1)) + \
(size) + (PAGE_SIZE_4K - 1)) >> PAGE_SHIFT_4K))
/* Byte offset into the page corresponding to given address */
@@ -137,7 +137,7 @@ struct be_ctrl_info {
((size_t)(addr) & (PAGE_SIZE_4K-1))
/* Returns bit offset within a DWORD of a bitfield */
-#define AMAP_BIT_OFFSET(_struct, field) \
+#define AMAP_BIT_OFFSET(_struct, field) \
(((size_t)&(((_struct *)0)->field))%32)
/* Returns the bit mask of the field that is NOT shifted into location. */
diff --git a/drivers/scsi/be2iscsi/be_cmds.c b/drivers/scsi/be2iscsi/be_cmds.c
index cda6642c736..7c7537335c8 100644
--- a/drivers/scsi/be2iscsi/be_cmds.c
+++ b/drivers/scsi/be2iscsi/be_cmds.c
@@ -19,6 +19,86 @@
#include "be_mgmt.h"
#include "be_main.h"
+int beiscsi_pci_soft_reset(struct beiscsi_hba *phba)
+{
+ u32 sreset;
+ u8 *pci_reset_offset = 0;
+ u8 *pci_online0_offset = 0;
+ u8 *pci_online1_offset = 0;
+ u32 pconline0 = 0;
+ u32 pconline1 = 0;
+ u32 i;
+
+ pci_reset_offset = (u8 *)phba->pci_va + BE2_SOFT_RESET;
+ pci_online0_offset = (u8 *)phba->pci_va + BE2_PCI_ONLINE0;
+ pci_online1_offset = (u8 *)phba->pci_va + BE2_PCI_ONLINE1;
+ sreset = readl((void *)pci_reset_offset);
+ sreset |= BE2_SET_RESET;
+ writel(sreset, (void *)pci_reset_offset);
+
+ i = 0;
+ while (sreset & BE2_SET_RESET) {
+ if (i > 64)
+ break;
+ msleep(100);
+ sreset = readl((void *)pci_reset_offset);
+ i++;
+ }
+
+ if (sreset & BE2_SET_RESET) {
+ printk(KERN_ERR "Soft Reset did not deassert\n");
+ return -EIO;
+ }
+ pconline1 = BE2_MPU_IRAM_ONLINE;
+ writel(pconline0, (void *)pci_online0_offset);
+ writel(pconline1, (void *)pci_online1_offset);
+
+ sreset = BE2_SET_RESET;
+ writel(sreset, (void *)pci_reset_offset);
+
+ i = 0;
+ while (sreset & BE2_SET_RESET) {
+ if (i > 64)
+ break;
+ msleep(1);
+ sreset = readl((void *)pci_reset_offset);
+ i++;
+ }
+ if (sreset & BE2_SET_RESET) {
+ printk(KERN_ERR "MPU Online Soft Reset did not deassert\n");
+ return -EIO;
+ }
+ return 0;
+}
+
+int be_chk_reset_complete(struct beiscsi_hba *phba)
+{
+ unsigned int num_loop;
+ u8 *mpu_sem = 0;
+ u32 status;
+
+ num_loop = 1000;
+ mpu_sem = (u8 *)phba->csr_va + MPU_EP_SEMAPHORE;
+ msleep(5000);
+
+ while (num_loop) {
+ status = readl((void *)mpu_sem);
+
+ if ((status & 0x80000000) || (status & 0x0000FFFF) == 0xC000)
+ break;
+ msleep(60);
+ num_loop--;
+ }
+
+ if ((status & 0x80000000) || (!num_loop)) {
+ printk(KERN_ERR "Failed in be_chk_reset_complete"
+ "status = 0x%x\n", status);
+ return -EIO;
+ }
+
+ return 0;
+}
+
void be_mcc_notify(struct beiscsi_hba *phba)
{
struct be_queue_info *mccq = &phba->ctrl.mcc_obj.q;
@@ -98,7 +178,7 @@ static int be_mcc_compl_process(struct be_ctrl_info *ctrl,
dev_err(&ctrl->pdev->dev,
"error in cmd completion: status(compl/extd)=%d/%d\n",
compl_status, extd_status);
- return -1;
+ return -EBUSY;
}
return 0;
}
@@ -151,20 +231,20 @@ void beiscsi_async_link_state_process(struct beiscsi_hba *phba,
{
switch (evt->port_link_status) {
case ASYNC_EVENT_LINK_DOWN:
- SE_DEBUG(DBG_LVL_1, "Link Down on Physical Port %d \n",
- evt->physical_port);
+ SE_DEBUG(DBG_LVL_1, "Link Down on Physical Port %d\n",
+ evt->physical_port);
phba->state |= BE_ADAPTER_LINK_DOWN;
iscsi_host_for_each_session(phba->shost,
be2iscsi_fail_session);
break;
case ASYNC_EVENT_LINK_UP:
phba->state = BE_ADAPTER_UP;
- SE_DEBUG(DBG_LVL_1, "Link UP on Physical Port %d \n",
+ SE_DEBUG(DBG_LVL_1, "Link UP on Physical Port %d\n",
evt->physical_port);
break;
default:
SE_DEBUG(DBG_LVL_1, "Unexpected Async Notification %d on"
- "Physical Port %d \n",
+ "Physical Port %d\n",
evt->port_link_status,
evt->physical_port);
}
@@ -199,7 +279,7 @@ int beiscsi_process_mcc(struct beiscsi_hba *phba)
else
SE_DEBUG(DBG_LVL_1,
" Unsupported Async Event, flags"
- " = 0x%08x \n", compl->flags);
+ " = 0x%08x\n", compl->flags);
} else if (compl->flags & CQE_FLAGS_COMPLETED_MASK) {
status = be_mcc_compl_process(ctrl, compl);
@@ -231,7 +311,7 @@ static int be_mcc_wait_compl(struct beiscsi_hba *phba)
}
if (i == mcc_timeout) {
dev_err(&phba->pcidev->dev, "mccq poll timed out\n");
- return -1;
+ return -EBUSY;
}
return 0;
}
@@ -257,7 +337,7 @@ static int be_mbox_db_ready_wait(struct be_ctrl_info *ctrl)
if (cnt > 6000000) {
dev_err(&ctrl->pdev->dev, "mbox_db poll timed out\n");
- return -1;
+ return -EBUSY;
}
if (cnt > 50) {
@@ -286,7 +366,7 @@ int be_mbox_notify(struct be_ctrl_info *ctrl)
status = be_mbox_db_ready_wait(ctrl);
if (status != 0) {
- SE_DEBUG(DBG_LVL_1, " be_mbox_db_ready_wait failed 1\n");
+ SE_DEBUG(DBG_LVL_1, " be_mbox_db_ready_wait failed\n");
return status;
}
val = 0;
@@ -297,19 +377,19 @@ int be_mbox_notify(struct be_ctrl_info *ctrl)
status = be_mbox_db_ready_wait(ctrl);
if (status != 0) {
- SE_DEBUG(DBG_LVL_1, " be_mbox_db_ready_wait failed 2\n");
+ SE_DEBUG(DBG_LVL_1, " be_mbox_db_ready_wait failed\n");
return status;
}
if (be_mcc_compl_is_new(compl)) {
status = be_mcc_compl_process(ctrl, &mbox->compl);
be_mcc_compl_use(compl);
if (status) {
- SE_DEBUG(DBG_LVL_1, "After be_mcc_compl_process \n");
+ SE_DEBUG(DBG_LVL_1, "After be_mcc_compl_process\n");
return status;
}
} else {
dev_err(&ctrl->pdev->dev, "invalid mailbox completion\n");
- return -1;
+ return -EBUSY;
}
return 0;
}
@@ -355,7 +435,7 @@ static int be_mbox_notify_wait(struct beiscsi_hba *phba)
return status;
} else {
dev_err(&phba->pcidev->dev, "invalid mailbox completion\n");
- return -1;
+ return -EBUSY;
}
return 0;
}
@@ -500,7 +580,7 @@ int be_cmd_fw_initialize(struct be_ctrl_info *ctrl)
status = be_mbox_notify(ctrl);
if (status)
- SE_DEBUG(DBG_LVL_1, "be_cmd_fw_initialize Failed \n");
+ SE_DEBUG(DBG_LVL_1, "be_cmd_fw_initialize Failed\n");
spin_unlock(&ctrl->mbox_lock);
return status;
@@ -517,7 +597,7 @@ int beiscsi_cmd_cq_create(struct be_ctrl_info *ctrl,
void *ctxt = &req->context;
int status;
- SE_DEBUG(DBG_LVL_8, "In beiscsi_cmd_cq_create \n");
+ SE_DEBUG(DBG_LVL_8, "In beiscsi_cmd_cq_create\n");
spin_lock(&ctrl->mbox_lock);
memset(wrb, 0, sizeof(*wrb));
@@ -550,7 +630,7 @@ int beiscsi_cmd_cq_create(struct be_ctrl_info *ctrl,
cq->id = le16_to_cpu(resp->cq_id);
cq->created = true;
} else
- SE_DEBUG(DBG_LVL_1, "In be_cmd_cq_create, status=ox%08x \n",
+ SE_DEBUG(DBG_LVL_1, "In be_cmd_cq_create, status=ox%08x\n",
status);
spin_unlock(&ctrl->mbox_lock);
@@ -619,7 +699,7 @@ int beiscsi_cmd_q_destroy(struct be_ctrl_info *ctrl, struct be_queue_info *q,
u8 subsys = 0, opcode = 0;
int status;
- SE_DEBUG(DBG_LVL_8, "In beiscsi_cmd_q_destroy \n");
+ SE_DEBUG(DBG_LVL_8, "In beiscsi_cmd_q_destroy\n");
spin_lock(&ctrl->mbox_lock);
memset(wrb, 0, sizeof(*wrb));
be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0);
@@ -652,7 +732,7 @@ int beiscsi_cmd_q_destroy(struct be_ctrl_info *ctrl, struct be_queue_info *q,
default:
spin_unlock(&ctrl->mbox_lock);
BUG();
- return -1;
+ return -ENXIO;
}
be_cmd_hdr_prepare(&req->hdr, subsys, opcode, sizeof(*req));
if (queue_type != QTYPE_SGL)
diff --git a/drivers/scsi/be2iscsi/be_cmds.h b/drivers/scsi/be2iscsi/be_cmds.h
index 49fcc787ee8..40641d0845f 100644
--- a/drivers/scsi/be2iscsi/be_cmds.h
+++ b/drivers/scsi/be2iscsi/be_cmds.h
@@ -47,8 +47,8 @@ struct be_mcc_wrb {
#define CQE_FLAGS_VALID_MASK (1 << 31)
#define CQE_FLAGS_ASYNC_MASK (1 << 30)
-#define CQE_FLAGS_COMPLETED_MASK (1 << 28)
-#define CQE_FLAGS_CONSUMED_MASK (1 << 27)
+#define CQE_FLAGS_COMPLETED_MASK (1 << 28)
+#define CQE_FLAGS_CONSUMED_MASK (1 << 27)
/* Completion Status */
#define MCC_STATUS_SUCCESS 0x0
@@ -56,7 +56,7 @@ struct be_mcc_wrb {
#define CQE_STATUS_COMPL_MASK 0xFFFF
#define CQE_STATUS_COMPL_SHIFT 0 /* bits 0 - 15 */
#define CQE_STATUS_EXTD_MASK 0xFFFF
-#define CQE_STATUS_EXTD_SHIFT 0 /* bits 0 - 15 */
+#define CQE_STATUS_EXTD_SHIFT 16 /* bits 0 - 15 */
struct be_mcc_compl {
u32 status; /* dword 0 */
@@ -143,14 +143,14 @@ struct be_mcc_mailbox {
*/
#define OPCODE_COMMON_CQ_CREATE 12
#define OPCODE_COMMON_EQ_CREATE 13
-#define OPCODE_COMMON_MCC_CREATE 21
-#define OPCODE_COMMON_GET_CNTL_ATTRIBUTES 32
+#define OPCODE_COMMON_MCC_CREATE 21
+#define OPCODE_COMMON_GET_CNTL_ATTRIBUTES 32
#define OPCODE_COMMON_GET_FW_VERSION 35
#define OPCODE_COMMON_MODIFY_EQ_DELAY 41
#define OPCODE_COMMON_FIRMWARE_CONFIG 42
-#define OPCODE_COMMON_MCC_DESTROY 53
-#define OPCODE_COMMON_CQ_DESTROY 54
-#define OPCODE_COMMON_EQ_DESTROY 55
+#define OPCODE_COMMON_MCC_DESTROY 53
+#define OPCODE_COMMON_CQ_DESTROY 54
+#define OPCODE_COMMON_EQ_DESTROY 55
#define OPCODE_COMMON_QUERY_FIRMWARE_CONFIG 58
#define OPCODE_COMMON_FUNCTION_RESET 61
@@ -164,9 +164,9 @@ struct be_mcc_mailbox {
#define OPCODE_COMMON_ISCSI_NTWK_GET_NIC_CONFIG 7
#define OPCODE_COMMON_ISCSI_SET_FRAGNUM_BITS_FOR_SGL_CRA 61
#define OPCODE_COMMON_ISCSI_DEFQ_CREATE 64
-#define OPCODE_COMMON_ISCSI_DEFQ_DESTROY 65
+#define OPCODE_COMMON_ISCSI_DEFQ_DESTROY 65
#define OPCODE_COMMON_ISCSI_WRBQ_CREATE 66
-#define OPCODE_COMMON_ISCSI_WRBQ_DESTROY 67
+#define OPCODE_COMMON_ISCSI_WRBQ_DESTROY 67
struct be_cmd_req_hdr {
u8 opcode; /* dword 0 */
@@ -423,7 +423,7 @@ int beiscsi_cmd_mccq_create(struct beiscsi_hba *phba,
struct be_queue_info *cq);
int be_poll_mcc(struct be_ctrl_info *ctrl);
-unsigned char mgmt_check_supported_fw(struct be_ctrl_info *ctrl,
+int mgmt_check_supported_fw(struct be_ctrl_info *ctrl,
struct beiscsi_hba *phba);
unsigned int be_cmd_get_mac_addr(struct beiscsi_hba *phba);
void free_mcc_tag(struct be_ctrl_info *ctrl, unsigned int tag);
@@ -875,7 +875,7 @@ struct be_fw_cfg {
*/
#define UNSOL_HDR_NOTIFY 28 /* Unsolicited header notify.*/
#define UNSOL_DATA_NOTIFY 29 /* Unsolicited data notify.*/
-#define UNSOL_DATA_DIGEST_ERROR_NOTIFY 30 /* Unsolicited data digest
+#define UNSOL_DATA_DIGEST_ERROR_NOTIFY 30 /* Unsolicited data digest
* error notify.
*/
#define DRIVERMSG_NOTIFY 31 /* TCP acknowledge based
@@ -901,6 +901,9 @@ struct be_fw_cfg {
* the cxn
*/
+int beiscsi_pci_soft_reset(struct beiscsi_hba *phba);
+int be_chk_reset_complete(struct beiscsi_hba *phba);
+
void be_wrb_hdr_prepare(struct be_mcc_wrb *wrb, int payload_len,
bool embedded, u8 sge_cnt);
diff --git a/drivers/scsi/be2iscsi/be_iscsi.c b/drivers/scsi/be2iscsi/be_iscsi.c
index c3928cb8b04..6d63e7b312c 100644
--- a/drivers/scsi/be2iscsi/be_iscsi.c
+++ b/drivers/scsi/be2iscsi/be_iscsi.c
@@ -52,7 +52,7 @@ struct iscsi_cls_session *beiscsi_session_create(struct iscsi_endpoint *ep,
SE_DEBUG(DBG_LVL_8, "In beiscsi_session_create\n");
if (!ep) {
- SE_DEBUG(DBG_LVL_1, "beiscsi_session_create: invalid ep \n");
+ SE_DEBUG(DBG_LVL_1, "beiscsi_session_create: invalid ep\n");
return NULL;
}
beiscsi_ep = ep->dd_data;
@@ -157,7 +157,7 @@ static int beiscsi_bindconn_cid(struct beiscsi_hba *phba,
"Connection table already occupied. Detected clash\n");
return -EINVAL;
} else {
- SE_DEBUG(DBG_LVL_8, "phba->conn_table[%d]=%p(beiscsi_conn) \n",
+ SE_DEBUG(DBG_LVL_8, "phba->conn_table[%d]=%p(beiscsi_conn)\n",
cid, beiscsi_conn);
phba->conn_table[cid] = beiscsi_conn;
}
@@ -196,7 +196,7 @@ int beiscsi_conn_bind(struct iscsi_cls_session *cls_session,
if (beiscsi_ep->phba != phba) {
SE_DEBUG(DBG_LVL_8,
- "beiscsi_ep->hba=%p not equal to phba=%p \n",
+ "beiscsi_ep->hba=%p not equal to phba=%p\n",
beiscsi_ep->phba, phba);
return -EEXIST;
}
@@ -204,7 +204,7 @@ int beiscsi_conn_bind(struct iscsi_cls_session *cls_session,
beiscsi_conn->beiscsi_conn_cid = beiscsi_ep->ep_cid;
beiscsi_conn->ep = beiscsi_ep;
beiscsi_ep->conn = beiscsi_conn;
- SE_DEBUG(DBG_LVL_8, "beiscsi_conn=%p conn=%p ep_cid=%d \n",
+ SE_DEBUG(DBG_LVL_8, "beiscsi_conn=%p conn=%p ep_cid=%d\n",
beiscsi_conn, conn, beiscsi_ep->ep_cid);
return beiscsi_bindconn_cid(phba, beiscsi_conn, beiscsi_ep->ep_cid);
}
@@ -230,7 +230,7 @@ int beiscsi_conn_get_param(struct iscsi_cls_conn *cls_conn,
if (!beiscsi_ep) {
SE_DEBUG(DBG_LVL_1,
"In beiscsi_conn_get_param , no beiscsi_ep\n");
- return -1;
+ return -ENODEV;
}
switch (param) {
@@ -277,6 +277,10 @@ int beiscsi_set_param(struct iscsi_cls_conn *cls_conn,
if (session->max_burst > 262144)
session->max_burst = 262144;
break;
+ case ISCSI_PARAM_MAX_XMIT_DLENGTH:
+ if ((conn->max_xmit_dlength > 65536) ||
+ (conn->max_xmit_dlength == 0))
+ conn->max_xmit_dlength = 65536;
default:
return 0;
}
@@ -308,8 +312,8 @@ int beiscsi_get_host_param(struct Scsi_Host *shost,
case ISCSI_HOST_PARAM_HWADDRESS:
tag = be_cmd_get_mac_addr(phba);
if (!tag) {
- SE_DEBUG(DBG_LVL_1, "be_cmd_get_mac_addr Failed \n");
- return -1;
+ SE_DEBUG(DBG_LVL_1, "be_cmd_get_mac_addr Failed\n");
+ return -EAGAIN;
} else
wait_event_interruptible(phba->ctrl.mcc_wait[tag],
phba->ctrl.mcc_numtag[tag]);
@@ -319,10 +323,10 @@ int beiscsi_get_host_param(struct Scsi_Host *shost,
status = phba->ctrl.mcc_numtag[tag] & 0x000000FF;
if (status || extd_status) {
SE_DEBUG(DBG_LVL_1, "be_cmd_get_mac_addr Failed"
- " status = %d extd_status = %d \n",
+ " status = %d extd_status = %d\n",
status, extd_status);
free_mcc_tag(&phba->ctrl, tag);
- return -1;
+ return -EAGAIN;
} else {
wrb = queue_get_wrb(mccq, wrb_num);
free_mcc_tag(&phba->ctrl, tag);
@@ -442,6 +446,31 @@ static int beiscsi_get_cid(struct beiscsi_hba *phba)
}
/**
+ * beiscsi_put_cid - Free the cid
+ * @phba: The phba for which the cid is being freed
+ * @cid: The cid to free
+ */
+static void beiscsi_put_cid(struct beiscsi_hba *phba, unsigned short cid)
+{
+ phba->avlbl_cids++;
+ phba->cid_array[phba->cid_free++] = cid;
+ if (phba->cid_free == phba->params.cxns_per_ctrl)
+ phba->cid_free = 0;
+}
+
+/**
+ * beiscsi_free_ep - free endpoint
+ * @ep: pointer to iscsi endpoint structure
+ */
+static void beiscsi_free_ep(struct beiscsi_endpoint *beiscsi_ep)
+{
+ struct beiscsi_hba *phba = beiscsi_ep->phba;
+
+ beiscsi_put_cid(phba, beiscsi_ep->ep_cid);
+ beiscsi_ep->phba = NULL;
+}
+
+/**
* beiscsi_open_conn - Ask FW to open a TCP connection
* @ep: endpoint to be used
* @src_addr: The source IP address
@@ -459,8 +488,9 @@ static int beiscsi_open_conn(struct iscsi_endpoint *ep,
struct be_mcc_wrb *wrb;
struct tcp_connect_and_offload_out *ptcpcnct_out;
unsigned short status, extd_status;
+ struct be_dma_mem nonemb_cmd;
unsigned int tag, wrb_num;
- int ret = -1;
+ int ret = -ENOMEM;
SE_DEBUG(DBG_LVL_8, "In beiscsi_open_conn\n");
beiscsi_ep->ep_cid = beiscsi_get_cid(phba);
@@ -468,22 +498,39 @@ static int beiscsi_open_conn(struct iscsi_endpoint *ep,
SE_DEBUG(DBG_LVL_1, "No free cid available\n");
return ret;
}
- SE_DEBUG(DBG_LVL_8, "In beiscsi_open_conn, ep_cid=%d ",
+ SE_DEBUG(DBG_LVL_8, "In beiscsi_open_conn, ep_cid=%d\n",
beiscsi_ep->ep_cid);
phba->ep_array[beiscsi_ep->ep_cid -
phba->fw_config.iscsi_cid_start] = ep;
if (beiscsi_ep->ep_cid > (phba->fw_config.iscsi_cid_start +
phba->params.cxns_per_ctrl * 2)) {
SE_DEBUG(DBG_LVL_1, "Failed in allocate iscsi cid\n");
- return ret;
+ beiscsi_put_cid(phba, beiscsi_ep->ep_cid);
+ goto free_ep;
}
beiscsi_ep->cid_vld = 0;
- tag = mgmt_open_connection(phba, dst_addr, beiscsi_ep);
+ nonemb_cmd.va = pci_alloc_consistent(phba->ctrl.pdev,
+ sizeof(struct tcp_connect_and_offload_in),
+ &nonemb_cmd.dma);
+ if (nonemb_cmd.va == NULL) {
+ SE_DEBUG(DBG_LVL_1,
+ "Failed to allocate memory for mgmt_open_connection"
+ "\n");
+ beiscsi_put_cid(phba, beiscsi_ep->ep_cid);
+ return -ENOMEM;
+ }
+ nonemb_cmd.size = sizeof(struct tcp_connect_and_offload_in);
+ memset(nonemb_cmd.va, 0, nonemb_cmd.size);
+ tag = mgmt_open_connection(phba, dst_addr, beiscsi_ep, &nonemb_cmd);
if (!tag) {
SE_DEBUG(DBG_LVL_1,
- "mgmt_open_connection Failed for cid=%d \n",
+ "mgmt_open_connection Failed for cid=%d\n",
beiscsi_ep->ep_cid);
+ beiscsi_put_cid(phba, beiscsi_ep->ep_cid);
+ pci_free_consistent(phba->ctrl.pdev, nonemb_cmd.size,
+ nonemb_cmd.va, nonemb_cmd.dma);
+ return -EAGAIN;
} else {
wait_event_interruptible(phba->ctrl.mcc_wait[tag],
phba->ctrl.mcc_numtag[tag]);
@@ -493,46 +540,31 @@ static int beiscsi_open_conn(struct iscsi_endpoint *ep,
status = phba->ctrl.mcc_numtag[tag] & 0x000000FF;
if (status || extd_status) {
SE_DEBUG(DBG_LVL_1, "mgmt_open_connection Failed"
- " status = %d extd_status = %d \n",
+ " status = %d extd_status = %d\n",
status, extd_status);
+ beiscsi_put_cid(phba, beiscsi_ep->ep_cid);
free_mcc_tag(&phba->ctrl, tag);
- return -1;
+ pci_free_consistent(phba->ctrl.pdev, nonemb_cmd.size,
+ nonemb_cmd.va, nonemb_cmd.dma);
+ goto free_ep;
} else {
wrb = queue_get_wrb(mccq, wrb_num);
free_mcc_tag(&phba->ctrl, tag);
- ptcpcnct_out = embedded_payload(wrb);
+ ptcpcnct_out = embedded_payload(wrb);
beiscsi_ep = ep->dd_data;
beiscsi_ep->fw_handle = ptcpcnct_out->connection_handle;
beiscsi_ep->cid_vld = 1;
SE_DEBUG(DBG_LVL_8, "mgmt_open_connection Success\n");
}
+ beiscsi_put_cid(phba, beiscsi_ep->ep_cid);
+ pci_free_consistent(phba->ctrl.pdev, nonemb_cmd.size,
+ nonemb_cmd.va, nonemb_cmd.dma);
return 0;
-}
-
-/**
- * beiscsi_put_cid - Free the cid
- * @phba: The phba for which the cid is being freed
- * @cid: The cid to free
- */
-static void beiscsi_put_cid(struct beiscsi_hba *phba, unsigned short cid)
-{
- phba->avlbl_cids++;
- phba->cid_array[phba->cid_free++] = cid;
- if (phba->cid_free == phba->params.cxns_per_ctrl)
- phba->cid_free = 0;
-}
-
-/**
- * beiscsi_free_ep - free endpoint
- * @ep: pointer to iscsi endpoint structure
- */
-static void beiscsi_free_ep(struct beiscsi_endpoint *beiscsi_ep)
-{
- struct beiscsi_hba *phba = beiscsi_ep->phba;
- beiscsi_put_cid(phba, beiscsi_ep->ep_cid);
- beiscsi_ep->phba = NULL;
+free_ep:
+ beiscsi_free_ep(beiscsi_ep);
+ return -EBUSY;
}
/**
@@ -552,18 +584,18 @@ beiscsi_ep_connect(struct Scsi_Host *shost, struct sockaddr *dst_addr,
struct iscsi_endpoint *ep;
int ret;
- SE_DEBUG(DBG_LVL_8, "In beiscsi_ep_connect \n");
+ SE_DEBUG(DBG_LVL_8, "In beiscsi_ep_connect\n");
if (shost)
phba = iscsi_host_priv(shost);
else {
ret = -ENXIO;
- SE_DEBUG(DBG_LVL_1, "shost is NULL \n");
+ SE_DEBUG(DBG_LVL_1, "shost is NULL\n");
return ERR_PTR(ret);
}
if (phba->state != BE_ADAPTER_UP) {
ret = -EBUSY;
- SE_DEBUG(DBG_LVL_1, "The Adapter state is Not UP \n");
+ SE_DEBUG(DBG_LVL_1, "The Adapter state is Not UP\n");
return ERR_PTR(ret);
}
@@ -576,16 +608,16 @@ beiscsi_ep_connect(struct Scsi_Host *shost, struct sockaddr *dst_addr,
beiscsi_ep = ep->dd_data;
beiscsi_ep->phba = phba;
beiscsi_ep->openiscsi_ep = ep;
- if (beiscsi_open_conn(ep, NULL, dst_addr, non_blocking)) {
- SE_DEBUG(DBG_LVL_1, "Failed in beiscsi_open_conn \n");
- ret = -ENOMEM;
+ ret = beiscsi_open_conn(ep, NULL, dst_addr, non_blocking);
+ if (ret) {
+ SE_DEBUG(DBG_LVL_1, "Failed in beiscsi_open_conn\n");
goto free_ep;
}
return ep;
free_ep:
- beiscsi_free_ep(beiscsi_ep);
+ iscsi_destroy_endpoint(ep);
return ERR_PTR(ret);
}
@@ -620,9 +652,9 @@ static int beiscsi_close_conn(struct beiscsi_endpoint *beiscsi_ep, int flag)
tag = mgmt_upload_connection(phba, beiscsi_ep->ep_cid, flag);
if (!tag) {
- SE_DEBUG(DBG_LVL_8, "upload failed for cid 0x%x",
+ SE_DEBUG(DBG_LVL_8, "upload failed for cid 0x%x\n",
beiscsi_ep->ep_cid);
- ret = -1;
+ ret = -EAGAIN;
} else {
wait_event_interruptible(phba->ctrl.mcc_wait[tag],
phba->ctrl.mcc_numtag[tag]);
@@ -632,30 +664,6 @@ static int beiscsi_close_conn(struct beiscsi_endpoint *beiscsi_ep, int flag)
}
/**
- * beiscsi_ep_disconnect - Tears down the TCP connection
- * @ep: endpoint to be used
- *
- * Tears down the TCP connection
- */
-void beiscsi_ep_disconnect(struct iscsi_endpoint *ep)
-{
- struct beiscsi_conn *beiscsi_conn;
- struct beiscsi_endpoint *beiscsi_ep;
- struct beiscsi_hba *phba;
-
- beiscsi_ep = ep->dd_data;
- phba = beiscsi_ep->phba;
- SE_DEBUG(DBG_LVL_8, "In beiscsi_ep_disconnect for ep_cid = %d\n",
- beiscsi_ep->ep_cid);
-
- if (beiscsi_ep->conn) {
- beiscsi_conn = beiscsi_ep->conn;
- iscsi_suspend_queue(beiscsi_conn->conn);
- }
-
-}
-
-/**
* beiscsi_unbind_conn_to_cid - Unbind the beiscsi_conn from phba conn table
* @phba: The phba instance
* @cid: The cid to free
@@ -666,50 +674,57 @@ static int beiscsi_unbind_conn_to_cid(struct beiscsi_hba *phba,
if (phba->conn_table[cid])
phba->conn_table[cid] = NULL;
else {
- SE_DEBUG(DBG_LVL_8, "Connection table Not occupied. \n");
+ SE_DEBUG(DBG_LVL_8, "Connection table Not occupied.\n");
return -EINVAL;
}
return 0;
}
/**
- * beiscsi_conn_stop - Invalidate and stop the connection
- * @cls_conn: pointer to get iscsi_conn
- * @flag: The type of connection closure
+ * beiscsi_ep_disconnect - Tears down the TCP connection
+ * @ep: endpoint to be used
+ *
+ * Tears down the TCP connection
*/
-void beiscsi_conn_stop(struct iscsi_cls_conn *cls_conn, int flag)
+void beiscsi_ep_disconnect(struct iscsi_endpoint *ep)
{
- struct iscsi_conn *conn = cls_conn->dd_data;
- struct beiscsi_conn *beiscsi_conn = conn->dd_data;
+ struct beiscsi_conn *beiscsi_conn;
struct beiscsi_endpoint *beiscsi_ep;
- struct iscsi_session *session = conn->session;
- struct Scsi_Host *shost = iscsi_session_to_shost(session->cls_session);
- struct beiscsi_hba *phba = iscsi_host_priv(shost);
+ struct beiscsi_hba *phba;
unsigned int tag;
unsigned short savecfg_flag = CMD_ISCSI_SESSION_SAVE_CFG_ON_FLASH;
- beiscsi_ep = beiscsi_conn->ep;
- if (!beiscsi_ep) {
- SE_DEBUG(DBG_LVL_8, "In beiscsi_conn_stop , no beiscsi_ep\n");
+ beiscsi_ep = ep->dd_data;
+ phba = beiscsi_ep->phba;
+ SE_DEBUG(DBG_LVL_8, "In beiscsi_ep_disconnect for ep_cid = %d\n",
+ beiscsi_ep->ep_cid);
+
+ if (!beiscsi_ep->conn) {
+ SE_DEBUG(DBG_LVL_8, "In beiscsi_ep_disconnect, no "
+ "beiscsi_ep\n");
return;
}
- SE_DEBUG(DBG_LVL_8, "In beiscsi_conn_stop ep_cid = %d\n",
- beiscsi_ep->ep_cid);
+ beiscsi_conn = beiscsi_ep->conn;
+ iscsi_suspend_queue(beiscsi_conn->conn);
+
+ SE_DEBUG(DBG_LVL_8, "In beiscsi_ep_disconnect ep_cid = %d\n",
+ beiscsi_ep->ep_cid);
+
tag = mgmt_invalidate_connection(phba, beiscsi_ep,
beiscsi_ep->ep_cid, 1,
savecfg_flag);
if (!tag) {
SE_DEBUG(DBG_LVL_1,
- "mgmt_invalidate_connection Failed for cid=%d \n",
+ "mgmt_invalidate_connection Failed for cid=%d\n",
beiscsi_ep->ep_cid);
} else {
wait_event_interruptible(phba->ctrl.mcc_wait[tag],
phba->ctrl.mcc_numtag[tag]);
free_mcc_tag(&phba->ctrl, tag);
}
+
beiscsi_close_conn(beiscsi_ep, CONNECTION_UPLOAD_GRACEFUL);
beiscsi_free_ep(beiscsi_ep);
- iscsi_destroy_endpoint(beiscsi_ep->openiscsi_ep);
beiscsi_unbind_conn_to_cid(phba, beiscsi_ep->ep_cid);
- iscsi_conn_stop(cls_conn, flag);
+ iscsi_destroy_endpoint(beiscsi_ep->openiscsi_ep);
}
diff --git a/drivers/scsi/be2iscsi/be_iscsi.h b/drivers/scsi/be2iscsi/be_iscsi.h
index 1f512c28cbf..870cdb2a73e 100644
--- a/drivers/scsi/be2iscsi/be_iscsi.h
+++ b/drivers/scsi/be2iscsi/be_iscsi.h
@@ -59,8 +59,6 @@ int beiscsi_set_param(struct iscsi_cls_conn *cls_conn,
int beiscsi_conn_start(struct iscsi_cls_conn *cls_conn);
-void beiscsi_conn_stop(struct iscsi_cls_conn *cls_conn, int flag);
-
struct iscsi_endpoint *beiscsi_ep_connect(struct Scsi_Host *shost,
struct sockaddr *dst_addr,
int non_blocking);
diff --git a/drivers/scsi/be2iscsi/be_main.c b/drivers/scsi/be2iscsi/be_main.c
index dd5b105f8f4..7436c5ad569 100644
--- a/drivers/scsi/be2iscsi/be_main.c
+++ b/drivers/scsi/be2iscsi/be_main.c
@@ -41,6 +41,8 @@
static unsigned int be_iopoll_budget = 10;
static unsigned int be_max_phys_size = 64;
static unsigned int enable_msix = 1;
+static unsigned int gcrashmode = 0;
+static unsigned int num_hba = 0;
MODULE_DEVICE_TABLE(pci, beiscsi_pci_id_table);
MODULE_DESCRIPTION(DRV_DESC " " BUILD_STR);
@@ -69,6 +71,7 @@ static int beiscsi_eh_abort(struct scsi_cmnd *sc)
struct beiscsi_hba *phba;
struct iscsi_session *session;
struct invalidate_command_table *inv_tbl;
+ struct be_dma_mem nonemb_cmd;
unsigned int cid, tag, num_invalidate;
cls_session = starget_to_session(scsi_target(sc->device));
@@ -99,18 +102,34 @@ static int beiscsi_eh_abort(struct scsi_cmnd *sc)
inv_tbl->cid = cid;
inv_tbl->icd = aborted_io_task->psgl_handle->sgl_index;
num_invalidate = 1;
- tag = mgmt_invalidate_icds(phba, inv_tbl, num_invalidate, cid);
+ nonemb_cmd.va = pci_alloc_consistent(phba->ctrl.pdev,
+ sizeof(struct invalidate_commands_params_in),
+ &nonemb_cmd.dma);
+ if (nonemb_cmd.va == NULL) {
+ SE_DEBUG(DBG_LVL_1,
+ "Failed to allocate memory for"
+ "mgmt_invalidate_icds\n");
+ return FAILED;
+ }
+ nonemb_cmd.size = sizeof(struct invalidate_commands_params_in);
+
+ tag = mgmt_invalidate_icds(phba, inv_tbl, num_invalidate,
+ cid, &nonemb_cmd);
if (!tag) {
shost_printk(KERN_WARNING, phba->shost,
"mgmt_invalidate_icds could not be"
" submitted\n");
+ pci_free_consistent(phba->ctrl.pdev, nonemb_cmd.size,
+ nonemb_cmd.va, nonemb_cmd.dma);
+
return FAILED;
} else {
wait_event_interruptible(phba->ctrl.mcc_wait[tag],
phba->ctrl.mcc_numtag[tag]);
free_mcc_tag(&phba->ctrl, tag);
}
-
+ pci_free_consistent(phba->ctrl.pdev, nonemb_cmd.size,
+ nonemb_cmd.va, nonemb_cmd.dma);
return iscsi_eh_abort(sc);
}
@@ -124,6 +143,7 @@ static int beiscsi_eh_device_reset(struct scsi_cmnd *sc)
struct iscsi_session *session;
struct iscsi_cls_session *cls_session;
struct invalidate_command_table *inv_tbl;
+ struct be_dma_mem nonemb_cmd;
unsigned int cid, tag, i, num_invalidate;
int rc = FAILED;
@@ -158,18 +178,33 @@ static int beiscsi_eh_device_reset(struct scsi_cmnd *sc)
spin_unlock_bh(&session->lock);
inv_tbl = phba->inv_tbl;
- tag = mgmt_invalidate_icds(phba, inv_tbl, num_invalidate, cid);
+ nonemb_cmd.va = pci_alloc_consistent(phba->ctrl.pdev,
+ sizeof(struct invalidate_commands_params_in),
+ &nonemb_cmd.dma);
+ if (nonemb_cmd.va == NULL) {
+ SE_DEBUG(DBG_LVL_1,
+ "Failed to allocate memory for"
+ "mgmt_invalidate_icds\n");
+ return FAILED;
+ }
+ nonemb_cmd.size = sizeof(struct invalidate_commands_params_in);
+ memset(nonemb_cmd.va, 0, nonemb_cmd.size);
+ tag = mgmt_invalidate_icds(phba, inv_tbl, num_invalidate,
+ cid, &nonemb_cmd);
if (!tag) {
shost_printk(KERN_WARNING, phba->shost,
"mgmt_invalidate_icds could not be"
" submitted\n");
+ pci_free_consistent(phba->ctrl.pdev, nonemb_cmd.size,
+ nonemb_cmd.va, nonemb_cmd.dma);
return FAILED;
} else {
wait_event_interruptible(phba->ctrl.mcc_wait[tag],
phba->ctrl.mcc_numtag[tag]);
free_mcc_tag(&phba->ctrl, tag);
}
-
+ pci_free_consistent(phba->ctrl.pdev, nonemb_cmd.size,
+ nonemb_cmd.va, nonemb_cmd.dma);
return iscsi_eh_device_reset(sc);
unlock:
spin_unlock_bh(&session->lock);
@@ -216,7 +251,7 @@ static struct beiscsi_hba *beiscsi_hba_alloc(struct pci_dev *pcidev)
shost = iscsi_host_alloc(&beiscsi_sht, sizeof(*phba), 0);
if (!shost) {
dev_err(&pcidev->dev, "beiscsi_hba_alloc -"
- "iscsi_host_alloc failed \n");
+ "iscsi_host_alloc failed\n");
return NULL;
}
shost->dma_boundary = pcidev->dma_mask;
@@ -371,7 +406,7 @@ static void beiscsi_get_params(struct beiscsi_hba *phba)
+ BE2_TMFS) / 512) + 1) * 512;
phba->params.num_eq_entries = (phba->params.num_eq_entries < 1024)
? 1024 : phba->params.num_eq_entries;
- SE_DEBUG(DBG_LVL_8, "phba->params.num_eq_entries=%d \n",
+ SE_DEBUG(DBG_LVL_8, "phba->params.num_eq_entries=%d\n",
phba->params.num_eq_entries);
phba->params.num_cq_entries =
(((BE2_CMDS_PER_CXN * 2 + phba->fw_config.iscsi_cid_count * 2
@@ -616,7 +651,7 @@ static int beiscsi_init_irqs(struct beiscsi_hba *phba)
struct pci_dev *pcidev = phba->pcidev;
struct hwi_controller *phwi_ctrlr;
struct hwi_context_memory *phwi_context;
- int ret, msix_vec, i = 0;
+ int ret, msix_vec, i, j;
char desc[32];
phwi_ctrlr = phba->phwi_ctrlr;
@@ -628,10 +663,25 @@ static int beiscsi_init_irqs(struct beiscsi_hba *phba)
msix_vec = phba->msix_entries[i].vector;
ret = request_irq(msix_vec, be_isr_msix, 0, desc,
&phwi_context->be_eq[i]);
+ if (ret) {
+ shost_printk(KERN_ERR, phba->shost,
+ "beiscsi_init_irqs-Failed to"
+ "register msix for i = %d\n", i);
+ if (!i)
+ return ret;
+ goto free_msix_irqs;
+ }
}
msix_vec = phba->msix_entries[i].vector;
ret = request_irq(msix_vec, be_isr_mcc, 0, "beiscsi_msix_mcc",
&phwi_context->be_eq[i]);
+ if (ret) {
+ shost_printk(KERN_ERR, phba->shost, "beiscsi_init_irqs-"
+ "Failed to register beiscsi_msix_mcc\n");
+ i++;
+ goto free_msix_irqs;
+ }
+
} else {
ret = request_irq(pcidev->irq, be_isr, IRQF_SHARED,
"beiscsi", phba);
@@ -642,6 +692,10 @@ static int beiscsi_init_irqs(struct beiscsi_hba *phba)
}
}
return 0;
+free_msix_irqs:
+ for (j = i - 1; j == 0; j++)
+ free_irq(msix_vec, &phwi_context->be_eq[j]);
+ return ret;
}
static void hwi_ring_cq_db(struct beiscsi_hba *phba,
@@ -692,7 +746,7 @@ beiscsi_process_async_pdu(struct beiscsi_conn *beiscsi_conn,
break;
default:
shost_printk(KERN_WARNING, phba->shost,
- "Unrecognized opcode 0x%x in async msg \n",
+ "Unrecognized opcode 0x%x in async msg\n",
(ppdu->
dw[offsetof(struct amap_pdu_base, opcode) / 32]
& PDUBASE_OPCODE_MASK));
@@ -711,7 +765,7 @@ static struct sgl_handle *alloc_io_sgl_handle(struct beiscsi_hba *phba)
if (phba->io_sgl_hndl_avbl) {
SE_DEBUG(DBG_LVL_8,
- "In alloc_io_sgl_handle,io_sgl_alloc_index=%d \n",
+ "In alloc_io_sgl_handle,io_sgl_alloc_index=%d\n",
phba->io_sgl_alloc_index);
psgl_handle = phba->io_sgl_hndl_base[phba->
io_sgl_alloc_index];
@@ -730,7 +784,7 @@ static struct sgl_handle *alloc_io_sgl_handle(struct beiscsi_hba *phba)
static void
free_io_sgl_handle(struct beiscsi_hba *phba, struct sgl_handle *psgl_handle)
{
- SE_DEBUG(DBG_LVL_8, "In free_,io_sgl_free_index=%d \n",
+ SE_DEBUG(DBG_LVL_8, "In free_,io_sgl_free_index=%d\n",
phba->io_sgl_free_index);
if (phba->io_sgl_hndl_base[phba->io_sgl_free_index]) {
/*
@@ -739,7 +793,7 @@ free_io_sgl_handle(struct beiscsi_hba *phba, struct sgl_handle *psgl_handle)
*/
SE_DEBUG(DBG_LVL_8,
"Double Free in IO SGL io_sgl_free_index=%d,"
- "value there=%p \n", phba->io_sgl_free_index,
+ "value there=%p\n", phba->io_sgl_free_index,
phba->io_sgl_hndl_base[phba->io_sgl_free_index]);
return;
}
@@ -804,7 +858,7 @@ free_wrb_handle(struct beiscsi_hba *phba, struct hwi_wrb_context *pwrb_context,
SE_DEBUG(DBG_LVL_8,
"FREE WRB: pwrb_handle=%p free_index=0x%x"
- "wrb_handles_available=%d \n",
+ "wrb_handles_available=%d\n",
pwrb_handle, pwrb_context->free_index,
pwrb_context->wrb_handles_available);
}
@@ -816,7 +870,7 @@ static struct sgl_handle *alloc_mgmt_sgl_handle(struct beiscsi_hba *phba)
if (phba->eh_sgl_hndl_avbl) {
psgl_handle = phba->eh_sgl_hndl_base[phba->eh_sgl_alloc_index];
phba->eh_sgl_hndl_base[phba->eh_sgl_alloc_index] = NULL;
- SE_DEBUG(DBG_LVL_8, "mgmt_sgl_alloc_index=%d=0x%x \n",
+ SE_DEBUG(DBG_LVL_8, "mgmt_sgl_alloc_index=%d=0x%x\n",
phba->eh_sgl_alloc_index, phba->eh_sgl_alloc_index);
phba->eh_sgl_hndl_avbl--;
if (phba->eh_sgl_alloc_index ==
@@ -834,7 +888,7 @@ void
free_mgmt_sgl_handle(struct beiscsi_hba *phba, struct sgl_handle *psgl_handle)
{
- SE_DEBUG(DBG_LVL_8, "In free_mgmt_sgl_handle,eh_sgl_free_index=%d \n",
+ SE_DEBUG(DBG_LVL_8, "In free_mgmt_sgl_handle,eh_sgl_free_index=%d\n",
phba->eh_sgl_free_index);
if (phba->eh_sgl_hndl_base[phba->eh_sgl_free_index]) {
/*
@@ -842,7 +896,7 @@ free_mgmt_sgl_handle(struct beiscsi_hba *phba, struct sgl_handle *psgl_handle)
* failed in xmit_task or alloc_pdu.
*/
SE_DEBUG(DBG_LVL_8,
- "Double Free in eh SGL ,eh_sgl_free_index=%d \n",
+ "Double Free in eh SGL ,eh_sgl_free_index=%d\n",
phba->eh_sgl_free_index);
return;
}
@@ -1081,7 +1135,7 @@ static void hwi_complete_cmd(struct beiscsi_conn *beiscsi_conn,
case HWH_TYPE_LOGIN:
SE_DEBUG(DBG_LVL_1,
"\t\t No HWH_TYPE_LOGIN Expected in hwi_complete_cmd"
- "- Solicited path \n");
+ "- Solicited path\n");
break;
case HWH_TYPE_NOP:
@@ -1164,7 +1218,7 @@ hwi_get_async_handle(struct beiscsi_hba *phba,
default:
pbusy_list = NULL;
shost_printk(KERN_WARNING, phba->shost,
- "Unexpected code=%d \n",
+ "Unexpected code=%d\n",
pdpdu_cqe->dw[offsetof(struct amap_i_t_dpdu_cqe,
code) / 32] & PDUCQE_CODE_MASK);
return NULL;
@@ -1552,7 +1606,7 @@ static void beiscsi_process_mcc_isr(struct beiscsi_hba *phba)
else
SE_DEBUG(DBG_LVL_1,
" Unsupported Async Event, flags"
- " = 0x%08x \n", mcc_compl->flags);
+ " = 0x%08x\n", mcc_compl->flags);
} else if (mcc_compl->flags & CQE_FLAGS_COMPLETED_MASK) {
be_mcc_compl_process_isr(&phba->ctrl, mcc_compl);
atomic_dec(&phba->ctrl.mcc_obj.q.used);
@@ -1611,7 +1665,7 @@ static unsigned int beiscsi_process_cq(struct be_eq_obj *pbe_eq)
hwi_complete_cmd(beiscsi_conn, phba, sol);
break;
case DRIVERMSG_NOTIFY:
- SE_DEBUG(DBG_LVL_8, "Received DRIVERMSG_NOTIFY \n");
+ SE_DEBUG(DBG_LVL_8, "Received DRIVERMSG_NOTIFY\n");
dmsg = (struct dmsg_cqe *)sol;
hwi_complete_drvr_msgs(beiscsi_conn, phba, sol);
break;
@@ -1782,9 +1836,9 @@ hwi_write_sgl(struct iscsi_wrb *pwrb, struct scatterlist *sg,
sg_len = sg_dma_len(sg);
addr = (u64) sg_dma_address(sg);
AMAP_SET_BITS(struct amap_iscsi_wrb, sge0_addr_lo, pwrb,
- (addr & 0xFFFFFFFF));
+ ((u32)(addr & 0xFFFFFFFF)));
AMAP_SET_BITS(struct amap_iscsi_wrb, sge0_addr_hi, pwrb,
- (addr >> 32));
+ ((u32)(addr >> 32)));
AMAP_SET_BITS(struct amap_iscsi_wrb, sge0_len, pwrb,
sg_len);
sge_len = sg_len;
@@ -1794,9 +1848,9 @@ hwi_write_sgl(struct iscsi_wrb *pwrb, struct scatterlist *sg,
sg_len = sg_dma_len(sg);
addr = (u64) sg_dma_address(sg);
AMAP_SET_BITS(struct amap_iscsi_wrb, sge1_addr_lo, pwrb,
- (addr & 0xFFFFFFFF));
+ ((u32)(addr & 0xFFFFFFFF)));
AMAP_SET_BITS(struct amap_iscsi_wrb, sge1_addr_hi, pwrb,
- (addr >> 32));
+ ((u32)(addr >> 32)));
AMAP_SET_BITS(struct amap_iscsi_wrb, sge1_len, pwrb,
sg_len);
}
@@ -1872,9 +1926,9 @@ static void hwi_write_buffer(struct iscsi_wrb *pwrb, struct iscsi_task *task)
addr = 0;
}
AMAP_SET_BITS(struct amap_iscsi_wrb, sge0_addr_lo, pwrb,
- (addr & 0xFFFFFFFF));
+ ((u32)(addr & 0xFFFFFFFF)));
AMAP_SET_BITS(struct amap_iscsi_wrb, sge0_addr_hi, pwrb,
- (addr >> 32));
+ ((u32)(addr >> 32)));
AMAP_SET_BITS(struct amap_iscsi_wrb, sge0_len, pwrb,
task->data_count);
@@ -1904,9 +1958,9 @@ static void hwi_write_buffer(struct iscsi_wrb *pwrb, struct iscsi_task *task)
psgl++;
if (task->data) {
AMAP_SET_BITS(struct amap_iscsi_sge, addr_lo, psgl,
- (addr & 0xFFFFFFFF));
+ ((u32)(addr & 0xFFFFFFFF)));
AMAP_SET_BITS(struct amap_iscsi_sge, addr_hi, psgl,
- (addr >> 32));
+ ((u32)(addr >> 32)));
}
AMAP_SET_BITS(struct amap_iscsi_sge, len, psgl, 0x106);
}
@@ -2054,7 +2108,8 @@ free_mem:
mem_descr->mem_array[j - 1].size,
mem_descr->mem_array[j - 1].
virtual_address,
- mem_descr->mem_array[j - 1].
+ (unsigned long)mem_descr->
+ mem_array[j - 1].
bus_address.u.a64.address);
}
if (i) {
@@ -2223,10 +2278,10 @@ static void hwi_init_async_pdu_ctx(struct beiscsi_hba *phba)
if (mem_descr->mem_array[0].virtual_address) {
SE_DEBUG(DBG_LVL_8,
"hwi_init_async_pdu_ctx HWI_MEM_ASYNC_HEADER_BUF"
- "va=%p \n", mem_descr->mem_array[0].virtual_address);
+ "va=%p\n", mem_descr->mem_array[0].virtual_address);
} else
shost_printk(KERN_WARNING, phba->shost,
- "No Virtual address \n");
+ "No Virtual address\n");
pasync_ctx->async_header.va_base =
mem_descr->mem_array[0].virtual_address;
@@ -2239,10 +2294,10 @@ static void hwi_init_async_pdu_ctx(struct beiscsi_hba *phba)
if (mem_descr->mem_array[0].virtual_address) {
SE_DEBUG(DBG_LVL_8,
"hwi_init_async_pdu_ctx HWI_MEM_ASYNC_HEADER_RING"
- "va=%p \n", mem_descr->mem_array[0].virtual_address);
+ "va=%p\n", mem_descr->mem_array[0].virtual_address);
} else
shost_printk(KERN_WARNING, phba->shost,
- "No Virtual address \n");
+ "No Virtual address\n");
pasync_ctx->async_header.ring_base =
mem_descr->mem_array[0].virtual_address;
@@ -2251,10 +2306,10 @@ static void hwi_init_async_pdu_ctx(struct beiscsi_hba *phba)
if (mem_descr->mem_array[0].virtual_address) {
SE_DEBUG(DBG_LVL_8,
"hwi_init_async_pdu_ctx HWI_MEM_ASYNC_HEADER_HANDLE"
- "va=%p \n", mem_descr->mem_array[0].virtual_address);
+ "va=%p\n", mem_descr->mem_array[0].virtual_address);
} else
shost_printk(KERN_WARNING, phba->shost,
- "No Virtual address \n");
+ "No Virtual address\n");
pasync_ctx->async_header.handle_base =
mem_descr->mem_array[0].virtual_address;
@@ -2266,10 +2321,10 @@ static void hwi_init_async_pdu_ctx(struct beiscsi_hba *phba)
if (mem_descr->mem_array[0].virtual_address) {
SE_DEBUG(DBG_LVL_8,
"hwi_init_async_pdu_ctx HWI_MEM_ASYNC_DATA_BUF"
- "va=%p \n", mem_descr->mem_array[0].virtual_address);
+ "va=%p\n", mem_descr->mem_array[0].virtual_address);
} else
shost_printk(KERN_WARNING, phba->shost,
- "No Virtual address \n");
+ "No Virtual address\n");
pasync_ctx->async_data.va_base =
mem_descr->mem_array[0].virtual_address;
pasync_ctx->async_data.pa_base.u.a64.address =
@@ -2280,10 +2335,10 @@ static void hwi_init_async_pdu_ctx(struct beiscsi_hba *phba)
if (mem_descr->mem_array[0].virtual_address) {
SE_DEBUG(DBG_LVL_8,
"hwi_init_async_pdu_ctx HWI_MEM_ASYNC_DATA_RING"
- "va=%p \n", mem_descr->mem_array[0].virtual_address);
+ "va=%p\n", mem_descr->mem_array[0].virtual_address);
} else
shost_printk(KERN_WARNING, phba->shost,
- "No Virtual address \n");
+ "No Virtual address\n");
pasync_ctx->async_data.ring_base =
mem_descr->mem_array[0].virtual_address;
@@ -2292,7 +2347,7 @@ static void hwi_init_async_pdu_ctx(struct beiscsi_hba *phba)
mem_descr += HWI_MEM_ASYNC_DATA_HANDLE;
if (!mem_descr->mem_array[0].virtual_address)
shost_printk(KERN_WARNING, phba->shost,
- "No Virtual address \n");
+ "No Virtual address\n");
pasync_ctx->async_data.handle_base =
mem_descr->mem_array[0].virtual_address;
@@ -2364,7 +2419,7 @@ be_sgl_create_contiguous(void *virtual_address,
WARN_ON(!sgl);
sgl->va = virtual_address;
- sgl->dma = physical_address;
+ sgl->dma = (unsigned long)physical_address;
sgl->size = length;
return 0;
@@ -2447,7 +2502,7 @@ static int beiscsi_create_eqs(struct beiscsi_hba *phba,
sizeof(struct be_eq_entry), eq_vaddress);
if (ret) {
shost_printk(KERN_ERR, phba->shost,
- "be_fill_queue Failed for EQ \n");
+ "be_fill_queue Failed for EQ\n");
goto create_eq_error;
}
@@ -2457,7 +2512,7 @@ static int beiscsi_create_eqs(struct beiscsi_hba *phba,
if (ret) {
shost_printk(KERN_ERR, phba->shost,
"beiscsi_cmd_eq_create"
- "Failedfor EQ \n");
+ "Failedfor EQ\n");
goto create_eq_error;
}
SE_DEBUG(DBG_LVL_8, "eqid = %d\n", phwi_context->be_eq[i].q.id);
@@ -2505,7 +2560,7 @@ static int beiscsi_create_cqs(struct beiscsi_hba *phba,
sizeof(struct sol_cqe), cq_vaddress);
if (ret) {
shost_printk(KERN_ERR, phba->shost,
- "be_fill_queue Failed for ISCSI CQ \n");
+ "be_fill_queue Failed for ISCSI CQ\n");
goto create_cq_error;
}
@@ -2515,7 +2570,7 @@ static int beiscsi_create_cqs(struct beiscsi_hba *phba,
if (ret) {
shost_printk(KERN_ERR, phba->shost,
"beiscsi_cmd_eq_create"
- "Failed for ISCSI CQ \n");
+ "Failed for ISCSI CQ\n");
goto create_cq_error;
}
SE_DEBUG(DBG_LVL_8, "iscsi cq_id is %d for eq_id %d\n",
@@ -2565,7 +2620,8 @@ beiscsi_create_def_hdr(struct beiscsi_hba *phba,
"be_fill_queue Failed for DEF PDU HDR\n");
return ret;
}
- mem->dma = mem_descr->mem_array[idx].bus_address.u.a64.address;
+ mem->dma = (unsigned long)mem_descr->mem_array[idx].
+ bus_address.u.a64.address;
ret = be_cmd_create_default_pdu_queue(&phba->ctrl, cq, dq,
def_pdu_ring_sz,
phba->params.defpdu_hdr_sz);
@@ -2609,7 +2665,8 @@ beiscsi_create_def_data(struct beiscsi_hba *phba,
"be_fill_queue Failed for DEF PDU DATA\n");
return ret;
}
- mem->dma = mem_descr->mem_array[idx].bus_address.u.a64.address;
+ mem->dma = (unsigned long)mem_descr->mem_array[idx].
+ bus_address.u.a64.address;
ret = be_cmd_create_default_pdu_queue(&phba->ctrl, cq, dataq,
def_pdu_ring_sz,
phba->params.defpdu_data_sz);
@@ -2623,7 +2680,7 @@ beiscsi_create_def_data(struct beiscsi_hba *phba,
SE_DEBUG(DBG_LVL_8, "iscsi def data id is %d\n",
phwi_context->be_def_dataq.id);
hwi_post_async_buffers(phba, 0);
- SE_DEBUG(DBG_LVL_8, "DEFAULT PDU DATA RING CREATED \n");
+ SE_DEBUG(DBG_LVL_8, "DEFAULT PDU DATA RING CREATED\n");
return 0;
}
@@ -2655,7 +2712,7 @@ beiscsi_post_pages(struct beiscsi_hba *phba)
}
pm_arr++;
}
- SE_DEBUG(DBG_LVL_8, "POSTED PAGES \n");
+ SE_DEBUG(DBG_LVL_8, "POSTED PAGES\n");
return 0;
}
@@ -2678,7 +2735,7 @@ static int be_queue_alloc(struct beiscsi_hba *phba, struct be_queue_info *q,
mem->size = len * entry_size;
mem->va = pci_alloc_consistent(phba->pcidev, mem->size, &mem->dma);
if (!mem->va)
- return -1;
+ return -ENOMEM;
memset(mem->va, 0, mem->size);
return 0;
}
@@ -2750,6 +2807,7 @@ beiscsi_create_wrb_rings(struct beiscsi_hba *phba,
if (status != 0) {
shost_printk(KERN_ERR, phba->shost,
"wrbq create failed.");
+ kfree(pwrb_arr);
return status;
}
phwi_ctrlr->wrb_context[i * 2].cid = phwi_context->be_wrbq[i].
@@ -2873,7 +2931,7 @@ mcc_cq_destroy:
mcc_cq_free:
be_queue_free(phba, cq);
err:
- return -1;
+ return -ENOMEM;
}
static int find_num_cpus(void)
@@ -2884,7 +2942,7 @@ static int find_num_cpus(void)
if (num_cpus >= MAX_CPUS)
num_cpus = MAX_CPUS - 1;
- SE_DEBUG(DBG_LVL_8, "num_cpus = %d \n", num_cpus);
+ SE_DEBUG(DBG_LVL_8, "num_cpus = %d\n", num_cpus);
return num_cpus;
}
@@ -2907,7 +2965,7 @@ static int hwi_init_port(struct beiscsi_hba *phba)
status = beiscsi_create_eqs(phba, phwi_context);
if (status != 0) {
- shost_printk(KERN_ERR, phba->shost, "EQ not created \n");
+ shost_printk(KERN_ERR, phba->shost, "EQ not created\n");
goto error;
}
@@ -2918,7 +2976,7 @@ static int hwi_init_port(struct beiscsi_hba *phba)
status = mgmt_check_supported_fw(ctrl, phba);
if (status != 0) {
shost_printk(KERN_ERR, phba->shost,
- "Unsupported fw version \n");
+ "Unsupported fw version\n");
goto error;
}
@@ -2974,7 +3032,7 @@ static int hwi_init_controller(struct beiscsi_hba *phba)
if (1 == phba->init_mem[HWI_MEM_ADDN_CONTEXT].num_elements) {
phwi_ctrlr->phwi_ctxt = (struct hwi_context_memory *)phba->
init_mem[HWI_MEM_ADDN_CONTEXT].mem_array[0].virtual_address;
- SE_DEBUG(DBG_LVL_8, " phwi_ctrlr->phwi_ctxt=%p \n",
+ SE_DEBUG(DBG_LVL_8, " phwi_ctrlr->phwi_ctxt=%p\n",
phwi_ctrlr->phwi_ctxt);
} else {
shost_printk(KERN_ERR, phba->shost,
@@ -3007,8 +3065,8 @@ static void beiscsi_free_mem(struct beiscsi_hba *phba)
pci_free_consistent(phba->pcidev,
mem_descr->mem_array[j - 1].size,
mem_descr->mem_array[j - 1].virtual_address,
- mem_descr->mem_array[j - 1].bus_address.
- u.a64.address);
+ (unsigned long)mem_descr->mem_array[j - 1].
+ bus_address.u.a64.address);
}
kfree(mem_descr->mem_array);
mem_descr++;
@@ -3024,7 +3082,7 @@ static int beiscsi_init_controller(struct beiscsi_hba *phba)
ret = beiscsi_get_memory(phba);
if (ret < 0) {
shost_printk(KERN_ERR, phba->shost, "beiscsi_dev_probe -"
- "Failed in beiscsi_alloc_memory \n");
+ "Failed in beiscsi_alloc_memory\n");
return ret;
}
@@ -3101,12 +3159,12 @@ static int beiscsi_init_sgl_handle(struct beiscsi_hba *phba)
}
SE_DEBUG(DBG_LVL_8,
"phba->io_sgl_hndl_avbl=%d"
- "phba->eh_sgl_hndl_avbl=%d \n",
+ "phba->eh_sgl_hndl_avbl=%d\n",
phba->io_sgl_hndl_avbl,
phba->eh_sgl_hndl_avbl);
mem_descr_sg = phba->init_mem;
mem_descr_sg += HWI_MEM_SGE;
- SE_DEBUG(DBG_LVL_8, "\n mem_descr_sg->num_elements=%d \n",
+ SE_DEBUG(DBG_LVL_8, "\n mem_descr_sg->num_elements=%d\n",
mem_descr_sg->num_elements);
arr_index = 0;
idx = 0;
@@ -3155,7 +3213,7 @@ static int hba_setup_cid_tbls(struct beiscsi_hba *phba)
if (!phba->ep_array) {
shost_printk(KERN_ERR, phba->shost,
"Failed to allocate memory in "
- "hba_setup_cid_tbls \n");
+ "hba_setup_cid_tbls\n");
kfree(phba->cid_array);
return -ENOMEM;
}
@@ -3168,7 +3226,7 @@ static int hba_setup_cid_tbls(struct beiscsi_hba *phba)
return 0;
}
-static unsigned char hwi_enable_intr(struct beiscsi_hba *phba)
+static void hwi_enable_intr(struct beiscsi_hba *phba)
{
struct be_ctrl_info *ctrl = &phba->ctrl;
struct hwi_controller *phwi_ctrlr;
@@ -3184,26 +3242,25 @@ static unsigned char hwi_enable_intr(struct beiscsi_hba *phba)
addr = (u8 __iomem *) ((u8 __iomem *) ctrl->pcicfg +
PCICFG_MEMBAR_CTRL_INT_CTRL_OFFSET);
reg = ioread32(addr);
- SE_DEBUG(DBG_LVL_8, "reg =x%08x \n", reg);
+ SE_DEBUG(DBG_LVL_8, "reg =x%08x\n", reg);
enabled = reg & MEMBAR_CTRL_INT_CTRL_HOSTINTR_MASK;
if (!enabled) {
reg |= MEMBAR_CTRL_INT_CTRL_HOSTINTR_MASK;
- SE_DEBUG(DBG_LVL_8, "reg =x%08x addr=%p \n", reg, addr);
+ SE_DEBUG(DBG_LVL_8, "reg =x%08x addr=%p\n", reg, addr);
iowrite32(reg, addr);
if (!phba->msix_enabled) {
eq = &phwi_context->be_eq[0].q;
- SE_DEBUG(DBG_LVL_8, "eq->id=%d \n", eq->id);
+ SE_DEBUG(DBG_LVL_8, "eq->id=%d\n", eq->id);
hwi_ring_eq_db(phba, eq->id, 0, 0, 1, 1);
} else {
for (i = 0; i <= phba->num_cpus; i++) {
eq = &phwi_context->be_eq[i].q;
- SE_DEBUG(DBG_LVL_8, "eq->id=%d \n", eq->id);
+ SE_DEBUG(DBG_LVL_8, "eq->id=%d\n", eq->id);
hwi_ring_eq_db(phba, eq->id, 0, 0, 1, 1);
}
}
}
- return true;
}
static void hwi_disable_intr(struct beiscsi_hba *phba)
@@ -3219,7 +3276,7 @@ static void hwi_disable_intr(struct beiscsi_hba *phba)
iowrite32(reg, addr);
} else
shost_printk(KERN_WARNING, phba->shost,
- "In hwi_disable_intr, Already Disabled \n");
+ "In hwi_disable_intr, Already Disabled\n");
}
static int beiscsi_init_port(struct beiscsi_hba *phba)
@@ -3230,14 +3287,14 @@ static int beiscsi_init_port(struct beiscsi_hba *phba)
if (ret < 0) {
shost_printk(KERN_ERR, phba->shost,
"beiscsi_dev_probe - Failed in"
- "beiscsi_init_controller \n");
+ "beiscsi_init_controller\n");
return ret;
}
ret = beiscsi_init_sgl_handle(phba);
if (ret < 0) {
shost_printk(KERN_ERR, phba->shost,
"beiscsi_dev_probe - Failed in"
- "beiscsi_init_sgl_handle \n");
+ "beiscsi_init_sgl_handle\n");
goto do_cleanup_ctrlr;
}
@@ -3291,12 +3348,12 @@ static void hwi_purge_eq(struct beiscsi_hba *phba)
static void beiscsi_clean_port(struct beiscsi_hba *phba)
{
- unsigned char mgmt_status;
+ int mgmt_status;
mgmt_status = mgmt_epfw_cleanup(phba, CMD_CONNECTION_CHUTE_0);
if (mgmt_status)
shost_printk(KERN_WARNING, phba->shost,
- "mgmt_epfw_cleanup FAILED \n");
+ "mgmt_epfw_cleanup FAILED\n");
hwi_purge_eq(phba);
hwi_cleanup(phba);
@@ -3428,14 +3485,12 @@ static int beiscsi_alloc_pdu(struct iscsi_task *task, uint8_t opcode)
return -ENOMEM;
io_task->bhs_pa.u.a64.address = paddr;
io_task->libiscsi_itt = (itt_t)task->itt;
- io_task->pwrb_handle = alloc_wrb_handle(phba,
- beiscsi_conn->beiscsi_conn_cid -
- phba->fw_config.iscsi_cid_start
- );
io_task->conn = beiscsi_conn;
task->hdr = (struct iscsi_hdr *)&io_task->cmd_bhs->iscsi_hdr;
task->hdr_max = sizeof(struct be_cmd_bhs);
+ io_task->psgl_handle = NULL;
+ io_task->psgl_handle = NULL;
if (task->sc) {
spin_lock(&phba->io_sgl_lock);
@@ -3443,6 +3498,11 @@ static int beiscsi_alloc_pdu(struct iscsi_task *task, uint8_t opcode)
spin_unlock(&phba->io_sgl_lock);
if (!io_task->psgl_handle)
goto free_hndls;
+ io_task->pwrb_handle = alloc_wrb_handle(phba,
+ beiscsi_conn->beiscsi_conn_cid -
+ phba->fw_config.iscsi_cid_start);
+ if (!io_task->pwrb_handle)
+ goto free_io_hndls;
} else {
io_task->scsi_cmnd = NULL;
if ((opcode & ISCSI_OPCODE_MASK) == ISCSI_OP_LOGIN) {
@@ -3457,9 +3517,20 @@ static int beiscsi_alloc_pdu(struct iscsi_task *task, uint8_t opcode)
beiscsi_conn->login_in_progress = 1;
beiscsi_conn->plogin_sgl_handle =
io_task->psgl_handle;
+ io_task->pwrb_handle =
+ alloc_wrb_handle(phba,
+ beiscsi_conn->beiscsi_conn_cid -
+ phba->fw_config.iscsi_cid_start);
+ if (!io_task->pwrb_handle)
+ goto free_io_hndls;
+ beiscsi_conn->plogin_wrb_handle =
+ io_task->pwrb_handle;
+
} else {
io_task->psgl_handle =
beiscsi_conn->plogin_sgl_handle;
+ io_task->pwrb_handle =
+ beiscsi_conn->plogin_wrb_handle;
}
} else {
spin_lock(&phba->mgmt_sgl_lock);
@@ -3467,6 +3538,13 @@ static int beiscsi_alloc_pdu(struct iscsi_task *task, uint8_t opcode)
spin_unlock(&phba->mgmt_sgl_lock);
if (!io_task->psgl_handle)
goto free_hndls;
+ io_task->pwrb_handle =
+ alloc_wrb_handle(phba,
+ beiscsi_conn->beiscsi_conn_cid -
+ phba->fw_config.iscsi_cid_start);
+ if (!io_task->pwrb_handle)
+ goto free_mgmt_hndls;
+
}
}
itt = (itt_t) cpu_to_be32(((unsigned int)io_task->pwrb_handle->
@@ -3477,16 +3555,26 @@ static int beiscsi_alloc_pdu(struct iscsi_task *task, uint8_t opcode)
io_task->cmd_bhs->iscsi_hdr.itt = itt;
return 0;
+free_io_hndls:
+ spin_lock(&phba->io_sgl_lock);
+ free_io_sgl_handle(phba, io_task->psgl_handle);
+ spin_unlock(&phba->io_sgl_lock);
+ goto free_hndls;
+free_mgmt_hndls:
+ spin_lock(&phba->mgmt_sgl_lock);
+ free_mgmt_sgl_handle(phba, io_task->psgl_handle);
+ spin_unlock(&phba->mgmt_sgl_lock);
free_hndls:
phwi_ctrlr = phba->phwi_ctrlr;
pwrb_context = &phwi_ctrlr->wrb_context[
beiscsi_conn->beiscsi_conn_cid -
phba->fw_config.iscsi_cid_start];
- free_wrb_handle(phba, pwrb_context, io_task->pwrb_handle);
+ if (io_task->pwrb_handle)
+ free_wrb_handle(phba, pwrb_context, io_task->pwrb_handle);
io_task->pwrb_handle = NULL;
pci_pool_free(beiscsi_sess->bhs_pool, io_task->cmd_bhs,
io_task->bhs_pa.u.a64.address);
- SE_DEBUG(DBG_LVL_1, "Alloc of SGL_ICD Failed \n");
+ SE_DEBUG(DBG_LVL_1, "Alloc of SGL_ICD Failed\n");
return -ENOMEM;
}
@@ -3653,7 +3741,7 @@ static int beiscsi_mtask(struct iscsi_task *task)
break;
default:
- SE_DEBUG(DBG_LVL_1, "opcode =%d Not supported \n",
+ SE_DEBUG(DBG_LVL_1, "opcode =%d Not supported\n",
task->hdr->opcode & ISCSI_OPCODE_MASK);
return -EINVAL;
}
@@ -3689,13 +3777,11 @@ static int beiscsi_task_xmit(struct iscsi_task *task)
SE_DEBUG(DBG_LVL_1, " scsi_dma_map Failed\n")
return num_sg;
}
- SE_DEBUG(DBG_LVL_4, "xferlen=0x%08x scmd=%p num_sg=%d sernum=%lu\n",
- (scsi_bufflen(sc)), sc, num_sg, sc->serial_number);
xferlen = scsi_bufflen(sc);
sg = scsi_sglist(sc);
if (sc->sc_data_direction == DMA_TO_DEVICE) {
writedir = 1;
- SE_DEBUG(DBG_LVL_4, "task->imm_count=0x%08x \n",
+ SE_DEBUG(DBG_LVL_4, "task->imm_count=0x%08x\n",
task->imm_count);
} else
writedir = 0;
@@ -3709,10 +3795,12 @@ static void beiscsi_remove(struct pci_dev *pcidev)
struct hwi_context_memory *phwi_context;
struct be_eq_obj *pbe_eq;
unsigned int i, msix_vec;
+ u8 *real_offset = 0;
+ u32 value = 0;
phba = (struct beiscsi_hba *)pci_get_drvdata(pcidev);
if (!phba) {
- dev_err(&pcidev->dev, "beiscsi_remove called with no phba \n");
+ dev_err(&pcidev->dev, "beiscsi_remove called with no phba\n");
return;
}
@@ -3737,6 +3825,14 @@ static void beiscsi_remove(struct pci_dev *pcidev)
beiscsi_clean_port(phba);
beiscsi_free_mem(phba);
+ real_offset = (u8 *)phba->csr_va + MPU_EP_SEMAPHORE;
+
+ value = readl((void *)real_offset);
+
+ if (value & 0x00010000) {
+ value &= 0xfffeffff;
+ writel(value, (void *)real_offset);
+ }
beiscsi_unmap_pci_function(phba);
pci_free_consistent(phba->pcidev,
phba->ctrl.mbox_mem_alloced.size,
@@ -3769,19 +3865,21 @@ static int __devinit beiscsi_dev_probe(struct pci_dev *pcidev,
struct hwi_controller *phwi_ctrlr;
struct hwi_context_memory *phwi_context;
struct be_eq_obj *pbe_eq;
- int ret, msix_vec, num_cpus, i;
+ int ret, num_cpus, i;
+ u8 *real_offset = 0;
+ u32 value = 0;
ret = beiscsi_enable_pci(pcidev);
if (ret < 0) {
- shost_printk(KERN_ERR, phba->shost, "beiscsi_dev_probe-"
- "Failed to enable pci device \n");
+ dev_err(&pcidev->dev, "beiscsi_dev_probe-"
+ " Failed to enable pci device\n");
return ret;
}
phba = beiscsi_hba_alloc(pcidev);
if (!phba) {
dev_err(&pcidev->dev, "beiscsi_dev_probe-"
- " Failed in beiscsi_hba_alloc \n");
+ " Failed in beiscsi_hba_alloc\n");
goto disable_pci;
}
@@ -3804,7 +3902,7 @@ static int __devinit beiscsi_dev_probe(struct pci_dev *pcidev,
else
num_cpus = 1;
phba->num_cpus = num_cpus;
- SE_DEBUG(DBG_LVL_8, "num_cpus = %d \n", phba->num_cpus);
+ SE_DEBUG(DBG_LVL_8, "num_cpus = %d\n", phba->num_cpus);
if (enable_msix)
beiscsi_msix_enable(phba);
@@ -3815,6 +3913,33 @@ static int __devinit beiscsi_dev_probe(struct pci_dev *pcidev,
goto hba_free;
}
+ if (!num_hba) {
+ real_offset = (u8 *)phba->csr_va + MPU_EP_SEMAPHORE;
+ value = readl((void *)real_offset);
+ if (value & 0x00010000) {
+ gcrashmode++;
+ shost_printk(KERN_ERR, phba->shost,
+ "Loading Driver in crashdump mode\n");
+ ret = beiscsi_pci_soft_reset(phba);
+ if (ret) {
+ shost_printk(KERN_ERR, phba->shost,
+ "Reset Failed. Aborting Crashdump\n");
+ goto hba_free;
+ }
+ ret = be_chk_reset_complete(phba);
+ if (ret) {
+ shost_printk(KERN_ERR, phba->shost,
+ "Failed to get out of reset."
+ "Aborting Crashdump\n");
+ goto hba_free;
+ }
+ } else {
+ value |= 0x00010000;
+ writel(value, (void *)real_offset);
+ num_hba++;
+ }
+ }
+
spin_lock_init(&phba->io_sgl_lock);
spin_lock_init(&phba->mgmt_sgl_lock);
spin_lock_init(&phba->isr_lock);
@@ -3870,25 +3995,10 @@ static int __devinit beiscsi_dev_probe(struct pci_dev *pcidev,
"Failed to beiscsi_init_irqs\n");
goto free_blkenbld;
}
- ret = hwi_enable_intr(phba);
- if (ret < 0) {
- shost_printk(KERN_ERR, phba->shost, "beiscsi_dev_probe-"
- "Failed to hwi_enable_intr\n");
- goto free_ctrlr;
- }
- SE_DEBUG(DBG_LVL_8, "\n\n\n SUCCESS - DRIVER LOADED \n\n\n");
+ hwi_enable_intr(phba);
+ SE_DEBUG(DBG_LVL_8, "\n\n\n SUCCESS - DRIVER LOADED\n\n\n");
return 0;
-free_ctrlr:
- if (phba->msix_enabled) {
- for (i = 0; i <= phba->num_cpus; i++) {
- msix_vec = phba->msix_entries[i].vector;
- free_irq(msix_vec, &phwi_context->be_eq[i]);
- }
- } else
- if (phba->pcidev->irq)
- free_irq(phba->pcidev->irq, phba);
- pci_disable_msix(phba->pcidev);
free_blkenbld:
destroy_workqueue(phba->wq);
if (blk_iopoll_enabled)
@@ -3900,12 +4010,23 @@ free_twq:
beiscsi_clean_port(phba);
beiscsi_free_mem(phba);
free_port:
+ real_offset = (u8 *)phba->csr_va + MPU_EP_SEMAPHORE;
+
+ value = readl((void *)real_offset);
+
+ if (value & 0x00010000) {
+ value &= 0xfffeffff;
+ writel(value, (void *)real_offset);
+ }
+
pci_free_consistent(phba->pcidev,
phba->ctrl.mbox_mem_alloced.size,
phba->ctrl.mbox_mem_alloced.va,
phba->ctrl.mbox_mem_alloced.dma);
beiscsi_unmap_pci_function(phba);
hba_free:
+ if (phba->msix_enabled)
+ pci_disable_msix(phba->pcidev);
iscsi_host_remove(phba->shost);
pci_dev_put(phba->pcidev);
iscsi_host_free(phba->shost);
@@ -3955,7 +4076,7 @@ struct iscsi_transport beiscsi_iscsi_transport = {
.get_session_param = iscsi_session_get_param,
.get_host_param = beiscsi_get_host_param,
.start_conn = beiscsi_conn_start,
- .stop_conn = beiscsi_conn_stop,
+ .stop_conn = iscsi_conn_stop,
.send_pdu = iscsi_conn_send_pdu,
.xmit_task = beiscsi_task_xmit,
.cleanup_task = beiscsi_cleanup_task,
@@ -3988,7 +4109,7 @@ static int __init beiscsi_module_init(void)
"transport.\n");
return -ENOMEM;
}
- SE_DEBUG(DBG_LVL_8, "In beiscsi_module_init, tt=%p \n",
+ SE_DEBUG(DBG_LVL_8, "In beiscsi_module_init, tt=%p\n",
&beiscsi_iscsi_transport);
ret = pci_register_driver(&beiscsi_pci_driver);
diff --git a/drivers/scsi/be2iscsi/be_main.h b/drivers/scsi/be2iscsi/be_main.h
index 87ec21280a3..c643bb3736f 100644
--- a/drivers/scsi/be2iscsi/be_main.h
+++ b/drivers/scsi/be2iscsi/be_main.h
@@ -23,6 +23,7 @@
#include <linux/kernel.h>
#include <linux/pci.h>
+#include <linux/if_ether.h>
#include <linux/in.h>
#include <scsi/scsi.h>
#include <scsi/scsi_cmnd.h>
@@ -39,7 +40,7 @@
"Linux iSCSI Driver version" BUILD_STR
#define DRV_DESC BE_NAME " " "Driver"
-#define BE_VENDOR_ID 0x19A2
+#define BE_VENDOR_ID 0x19A2
/* DEVICE ID's for BE2 */
#define BE_DEVICE_ID1 0x212
#define OC_DEVICE_ID1 0x702
@@ -68,8 +69,15 @@
#define BEISCSI_NUM_MAX_LUN 256 /* scsi_host->max_lun */
#define BEISCSI_NUM_DEVICES_SUPPORTED 0x01
#define BEISCSI_MAX_FRAGS_INIT 192
-#define BE_NUM_MSIX_ENTRIES 1
-#define MPU_EP_SEMAPHORE 0xac
+#define BE_NUM_MSIX_ENTRIES 1
+
+#define MPU_EP_CONTROL 0
+#define MPU_EP_SEMAPHORE 0xac
+#define BE2_SOFT_RESET 0x5c
+#define BE2_PCI_ONLINE0 0xb0
+#define BE2_PCI_ONLINE1 0xb4
+#define BE2_SET_RESET 0x80
+#define BE2_MPU_IRAM_ONLINE 0x00000080
#define BE_SENSE_INFO_SIZE 258
#define BE_ISCSI_PDU_HEADER_SIZE 64
@@ -105,7 +113,7 @@ do { \
#define HWI_GET_ASYNC_PDU_CTX(phwi) (phwi->phwi_ctxt->pasync_ctx)
/********* Memory BAR register ************/
-#define PCICFG_MEMBAR_CTRL_INT_CTRL_OFFSET 0xfc
+#define PCICFG_MEMBAR_CTRL_INT_CTRL_OFFSET 0xfc
/**
* Host Interrupt Enable, if set interrupts are enabled although "PCI Interrupt
* Disable" may still globally block interrupts in addition to individual
@@ -116,7 +124,7 @@ do { \
#define MEMBAR_CTRL_INT_CTRL_HOSTINTR_MASK (1 << 29) /* bit 29 */
/********* ISR0 Register offset **********/
-#define CEV_ISR0_OFFSET 0xC18
+#define CEV_ISR0_OFFSET 0xC18
#define CEV_ISR_SIZE 4
/**
@@ -139,12 +147,12 @@ do { \
#define DB_EQ_REARM_SHIFT (29) /* bit 29 */
/********* Compl Q door bell *************/
-#define DB_CQ_OFFSET 0x120
+#define DB_CQ_OFFSET 0x120
#define DB_CQ_RING_ID_MASK 0x3FF /* bits 0 - 9 */
/* Number of event entries processed */
-#define DB_CQ_NUM_POPPED_SHIFT (16) /* bits 16 - 28 */
+#define DB_CQ_NUM_POPPED_SHIFT (16) /* bits 16 - 28 */
/* Rearm bit */
-#define DB_CQ_REARM_SHIFT (29) /* bit 29 */
+#define DB_CQ_REARM_SHIFT (29) /* bit 29 */
#define GET_HWI_CONTROLLER_WS(pc) (pc->phwi_ctrlr)
#define HWI_GET_DEF_BUFQ_ID(pc) (((struct hwi_controller *)\
@@ -161,12 +169,12 @@ enum be_mem_enum {
HWI_MEM_WRBH,
HWI_MEM_SGLH,
HWI_MEM_SGE,
- HWI_MEM_ASYNC_HEADER_BUF, /* 5 */
+ HWI_MEM_ASYNC_HEADER_BUF, /* 5 */
HWI_MEM_ASYNC_DATA_BUF,
HWI_MEM_ASYNC_HEADER_RING,
HWI_MEM_ASYNC_DATA_RING,
HWI_MEM_ASYNC_HEADER_HANDLE,
- HWI_MEM_ASYNC_DATA_HANDLE, /* 10 */
+ HWI_MEM_ASYNC_DATA_HANDLE, /* 10 */
HWI_MEM_ASYNC_PDU_CONTEXT,
ISCSI_MEM_GLOBAL_HEADER,
SE_MEM_MAX
@@ -352,6 +360,7 @@ struct beiscsi_conn {
u32 beiscsi_conn_cid;
struct beiscsi_endpoint *ep;
unsigned short login_in_progress;
+ struct wrb_handle *plogin_wrb_handle;
struct sgl_handle *plogin_sgl_handle;
struct beiscsi_session *beiscsi_sess;
struct iscsi_task *task;
diff --git a/drivers/scsi/be2iscsi/be_mgmt.c b/drivers/scsi/be2iscsi/be_mgmt.c
index 350cbeaae16..3f3fab91a7d 100644
--- a/drivers/scsi/be2iscsi/be_mgmt.c
+++ b/drivers/scsi/be2iscsi/be_mgmt.c
@@ -21,7 +21,7 @@
#include "be_mgmt.h"
#include "be_iscsi.h"
-unsigned char mgmt_get_fw_config(struct be_ctrl_info *ctrl,
+int mgmt_get_fw_config(struct be_ctrl_info *ctrl,
struct beiscsi_hba *phba)
{
struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem);
@@ -50,7 +50,7 @@ unsigned char mgmt_get_fw_config(struct be_ctrl_info *ctrl,
pfw_cfg->ulp[0].sq_count;
if (phba->fw_config.iscsi_cid_count > (BE2_MAX_SESSIONS / 2)) {
SE_DEBUG(DBG_LVL_8,
- "FW reported MAX CXNS as %d \t"
+ "FW reported MAX CXNS as %d\t"
"Max Supported = %d.\n",
phba->fw_config.iscsi_cid_count,
BE2_MAX_SESSIONS);
@@ -58,14 +58,14 @@ unsigned char mgmt_get_fw_config(struct be_ctrl_info *ctrl,
}
} else {
shost_printk(KERN_WARNING, phba->shost,
- "Failed in mgmt_get_fw_config \n");
+ "Failed in mgmt_get_fw_config\n");
}
spin_unlock(&ctrl->mbox_lock);
return status;
}
-unsigned char mgmt_check_supported_fw(struct be_ctrl_info *ctrl,
+int mgmt_check_supported_fw(struct be_ctrl_info *ctrl,
struct beiscsi_hba *phba)
{
struct be_dma_mem nonemb_cmd;
@@ -81,7 +81,7 @@ unsigned char mgmt_check_supported_fw(struct be_ctrl_info *ctrl,
SE_DEBUG(DBG_LVL_1,
"Failed to allocate memory for mgmt_check_supported_fw"
"\n");
- return -1;
+ return -ENOMEM;
}
nonemb_cmd.size = sizeof(struct be_mgmt_controller_attributes);
req = nonemb_cmd.va;
@@ -117,8 +117,7 @@ unsigned char mgmt_check_supported_fw(struct be_ctrl_info *ctrl,
return status;
}
-
-unsigned char mgmt_epfw_cleanup(struct beiscsi_hba *phba, unsigned short chute)
+int mgmt_epfw_cleanup(struct beiscsi_hba *phba, unsigned short chute)
{
struct be_ctrl_info *ctrl = &phba->ctrl;
struct be_mcc_wrb *wrb = wrb_from_mccq(phba);
@@ -144,11 +143,12 @@ unsigned char mgmt_epfw_cleanup(struct beiscsi_hba *phba, unsigned short chute)
return status;
}
-unsigned char mgmt_invalidate_icds(struct beiscsi_hba *phba,
+unsigned int mgmt_invalidate_icds(struct beiscsi_hba *phba,
struct invalidate_command_table *inv_tbl,
- unsigned int num_invalidate, unsigned int cid)
+ unsigned int num_invalidate, unsigned int cid,
+ struct be_dma_mem *nonemb_cmd)
+
{
- struct be_dma_mem nonemb_cmd;
struct be_ctrl_info *ctrl = &phba->ctrl;
struct be_mcc_wrb *wrb;
struct be_sge *sge;
@@ -162,17 +162,7 @@ unsigned char mgmt_invalidate_icds(struct beiscsi_hba *phba,
return tag;
}
- nonemb_cmd.va = pci_alloc_consistent(ctrl->pdev,
- sizeof(struct invalidate_commands_params_in),
- &nonemb_cmd.dma);
- if (nonemb_cmd.va == NULL) {
- SE_DEBUG(DBG_LVL_1,
- "Failed to allocate memory for mgmt_invalidate_icds\n");
- spin_unlock(&ctrl->mbox_lock);
- return 0;
- }
- nonemb_cmd.size = sizeof(struct invalidate_commands_params_in);
- req = nonemb_cmd.va;
+ req = nonemb_cmd->va;
memset(req, 0, sizeof(*req));
wrb = wrb_from_mccq(phba);
sge = nonembedded_sgl(wrb);
@@ -190,19 +180,16 @@ unsigned char mgmt_invalidate_icds(struct beiscsi_hba *phba,
req->icd_count++;
inv_tbl++;
}
- sge->pa_hi = cpu_to_le32(upper_32_bits(nonemb_cmd.dma));
- sge->pa_lo = cpu_to_le32(nonemb_cmd.dma & 0xFFFFFFFF);
- sge->len = cpu_to_le32(nonemb_cmd.size);
+ sge->pa_hi = cpu_to_le32(upper_32_bits(nonemb_cmd->dma));
+ sge->pa_lo = cpu_to_le32(nonemb_cmd->dma & 0xFFFFFFFF);
+ sge->len = cpu_to_le32(nonemb_cmd->size);
be_mcc_notify(phba);
spin_unlock(&ctrl->mbox_lock);
- if (nonemb_cmd.va)
- pci_free_consistent(ctrl->pdev, nonemb_cmd.size,
- nonemb_cmd.va, nonemb_cmd.dma);
return tag;
}
-unsigned char mgmt_invalidate_connection(struct beiscsi_hba *phba,
+unsigned int mgmt_invalidate_connection(struct beiscsi_hba *phba,
struct beiscsi_endpoint *beiscsi_ep,
unsigned short cid,
unsigned short issue_reset,
@@ -239,7 +226,7 @@ unsigned char mgmt_invalidate_connection(struct beiscsi_hba *phba,
return tag;
}
-unsigned char mgmt_upload_connection(struct beiscsi_hba *phba,
+unsigned int mgmt_upload_connection(struct beiscsi_hba *phba,
unsigned short cid, unsigned int upload_flag)
{
struct be_ctrl_info *ctrl = &phba->ctrl;
@@ -269,7 +256,9 @@ unsigned char mgmt_upload_connection(struct beiscsi_hba *phba,
int mgmt_open_connection(struct beiscsi_hba *phba,
struct sockaddr *dst_addr,
- struct beiscsi_endpoint *beiscsi_ep)
+ struct beiscsi_endpoint *beiscsi_ep,
+ struct be_dma_mem *nonemb_cmd)
+
{
struct hwi_controller *phwi_ctrlr;
struct hwi_context_memory *phwi_context;
@@ -285,6 +274,7 @@ int mgmt_open_connection(struct beiscsi_hba *phba,
unsigned int tag = 0;
unsigned int i;
unsigned short cid = beiscsi_ep->ep_cid;
+ struct be_sge *sge;
phwi_ctrlr = phba->phwi_ctrlr;
phwi_context = phwi_ctrlr->phwi_ctxt;
@@ -300,10 +290,14 @@ int mgmt_open_connection(struct beiscsi_hba *phba,
return tag;
}
wrb = wrb_from_mccq(phba);
- req = embedded_payload(wrb);
+ memset(wrb, 0, sizeof(*wrb));
+ sge = nonembedded_sgl(wrb);
+
+ req = nonemb_cmd->va;
+ memset(req, 0, sizeof(*req));
wrb->tag0 |= tag;
- be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0);
+ be_wrb_hdr_prepare(wrb, sizeof(*req), true, 1);
be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ISCSI,
OPCODE_COMMON_ISCSI_TCP_CONNECT_AND_OFFLOAD,
sizeof(*req));
@@ -331,6 +325,7 @@ int mgmt_open_connection(struct beiscsi_hba *phba,
shost_printk(KERN_ERR, phba->shost, "unknown addr family %d\n",
dst_addr->sa_family);
spin_unlock(&ctrl->mbox_lock);
+ free_mcc_tag(&phba->ctrl, tag);
return -EINVAL;
}
@@ -339,13 +334,16 @@ int mgmt_open_connection(struct beiscsi_hba *phba,
if (phba->nxt_cqid == phba->num_cpus)
phba->nxt_cqid = 0;
req->cq_id = phwi_context->be_cq[i].id;
- SE_DEBUG(DBG_LVL_8, "i=%d cq_id=%d \n", i, req->cq_id);
+ SE_DEBUG(DBG_LVL_8, "i=%d cq_id=%d\n", i, req->cq_id);
req->defq_id = def_hdr_id;
req->hdr_ring_id = def_hdr_id;
req->data_ring_id = def_data_id;
req->do_offload = 1;
req->dataout_template_pa.lo = ptemplate_address->lo;
req->dataout_template_pa.hi = ptemplate_address->hi;
+ sge->pa_hi = cpu_to_le32(upper_32_bits(nonemb_cmd->dma));
+ sge->pa_lo = cpu_to_le32(nonemb_cmd->dma & 0xFFFFFFFF);
+ sge->len = cpu_to_le32(nonemb_cmd->size);
be_mcc_notify(phba);
spin_unlock(&ctrl->mbox_lock);
return tag;
diff --git a/drivers/scsi/be2iscsi/be_mgmt.h b/drivers/scsi/be2iscsi/be_mgmt.h
index 3d316b82feb..b9acedf7865 100644
--- a/drivers/scsi/be2iscsi/be_mgmt.h
+++ b/drivers/scsi/be2iscsi/be_mgmt.h
@@ -86,16 +86,19 @@ struct mcc_wrb {
struct mcc_wrb_payload payload;
};
-unsigned char mgmt_epfw_cleanup(struct beiscsi_hba *phba, unsigned short chute);
-int mgmt_open_connection(struct beiscsi_hba *phba, struct sockaddr *dst_addr,
- struct beiscsi_endpoint *beiscsi_ep);
+int mgmt_epfw_cleanup(struct beiscsi_hba *phba, unsigned short chute);
+int mgmt_open_connection(struct beiscsi_hba *phba,
+ struct sockaddr *dst_addr,
+ struct beiscsi_endpoint *beiscsi_ep,
+ struct be_dma_mem *nonemb_cmd);
-unsigned char mgmt_upload_connection(struct beiscsi_hba *phba,
+unsigned int mgmt_upload_connection(struct beiscsi_hba *phba,
unsigned short cid,
unsigned int upload_flag);
-unsigned char mgmt_invalidate_icds(struct beiscsi_hba *phba,
+unsigned int mgmt_invalidate_icds(struct beiscsi_hba *phba,
struct invalidate_command_table *inv_tbl,
- unsigned int num_invalidate, unsigned int cid);
+ unsigned int num_invalidate, unsigned int cid,
+ struct be_dma_mem *nonemb_cmd);
struct iscsi_invalidate_connection_params_in {
struct be_cmd_req_hdr hdr;
@@ -237,10 +240,10 @@ struct beiscsi_endpoint {
u16 cid_vld;
};
-unsigned char mgmt_get_fw_config(struct be_ctrl_info *ctrl,
+int mgmt_get_fw_config(struct be_ctrl_info *ctrl,
struct beiscsi_hba *phba);
-unsigned char mgmt_invalidate_connection(struct beiscsi_hba *phba,
+unsigned int mgmt_invalidate_connection(struct beiscsi_hba *phba,
struct beiscsi_endpoint *beiscsi_ep,
unsigned short cid,
unsigned short issue_reset,
diff --git a/drivers/scsi/bfa/Makefile b/drivers/scsi/bfa/Makefile
index 17e06cae71b..ac3fdf02d5f 100644
--- a/drivers/scsi/bfa/Makefile
+++ b/drivers/scsi/bfa/Makefile
@@ -1,7 +1,7 @@
obj-$(CONFIG_SCSI_BFA_FC) := bfa.o
bfa-y := bfad.o bfad_intr.o bfad_os.o bfad_im.o bfad_attr.o bfad_fwimg.o
-
+bfa-y += bfad_debugfs.o
bfa-y += bfa_core.o bfa_ioc.o bfa_ioc_ct.o bfa_ioc_cb.o bfa_iocfc.o bfa_fcxp.o
bfa-y += bfa_lps.o bfa_hw_cb.o bfa_hw_ct.o bfa_intr.o bfa_timer.o bfa_rport.o
bfa-y += bfa_fcport.o bfa_port.o bfa_uf.o bfa_sgpg.o bfa_module.o bfa_ioim.o
diff --git a/drivers/scsi/bfa/bfa_cb_ioim_macros.h b/drivers/scsi/bfa/bfa_cb_ioim_macros.h
index 53a616f5f50..3906ed92696 100644
--- a/drivers/scsi/bfa/bfa_cb_ioim_macros.h
+++ b/drivers/scsi/bfa/bfa_cb_ioim_macros.h
@@ -171,6 +171,11 @@ bfa_cb_ioim_get_cdblen(struct bfad_ioim_s *dio)
return cmnd->cmd_len;
}
-
+/**
+ * Assign queue to be used for the I/O request. This value depends on whether
+ * the driver wants to use the queues via any specific algorithm. Currently,
+ * this is not supported.
+ */
+#define bfa_cb_ioim_get_reqq(__dio) BFA_FALSE
#endif /* __BFA_HCB_IOIM_MACROS_H__ */
diff --git a/drivers/scsi/bfa/bfa_core.c b/drivers/scsi/bfa/bfa_core.c
index 3a7b3f88932..76fa5c5b40d 100644
--- a/drivers/scsi/bfa/bfa_core.c
+++ b/drivers/scsi/bfa/bfa_core.c
@@ -333,9 +333,10 @@ bfa_get_pciids(struct bfa_pciid_s **pciids, int *npciids)
{BFA_PCI_VENDOR_ID_BROCADE, BFA_PCI_DEVICE_ID_FC_8G2P},
{BFA_PCI_VENDOR_ID_BROCADE, BFA_PCI_DEVICE_ID_FC_8G1P},
{BFA_PCI_VENDOR_ID_BROCADE, BFA_PCI_DEVICE_ID_CT},
+ {BFA_PCI_VENDOR_ID_BROCADE, BFA_PCI_DEVICE_ID_CT_FC},
};
- *npciids = sizeof(__pciids) / sizeof(__pciids[0]);
+ *npciids = ARRAY_SIZE(__pciids);
*pciids = __pciids;
}
diff --git a/drivers/scsi/bfa/bfa_fcpim.c b/drivers/scsi/bfa/bfa_fcpim.c
index 790c945aeae..8c703d8dc94 100644
--- a/drivers/scsi/bfa/bfa_fcpim.c
+++ b/drivers/scsi/bfa/bfa_fcpim.c
@@ -80,11 +80,6 @@ bfa_fcpim_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg,
}
static void
-bfa_fcpim_initdone(struct bfa_s *bfa)
-{
-}
-
-static void
bfa_fcpim_detach(struct bfa_s *bfa)
{
struct bfa_fcpim_mod_s *fcpim = BFA_FCPIM_MOD(bfa);
@@ -172,4 +167,28 @@ bfa_fcpim_qdepth_get(struct bfa_s *bfa)
return fcpim->q_depth;
}
+void
+bfa_fcpim_update_ioredirect(struct bfa_s *bfa)
+{
+ bfa_boolean_t ioredirect;
+
+ /*
+ * IO redirection is turned off when QoS is enabled and vice versa
+ */
+ ioredirect = bfa_fcport_is_qos_enabled(bfa) ? BFA_FALSE : BFA_TRUE;
+ /*
+ * Notify the bfad module of a possible state change in
+ * IO redirection capability, due to a QoS state change. bfad will
+ * check on the support for io redirection and update the
+ * fcpim's ioredirect state accordingly.
+ */
+ bfa_cb_ioredirect_state_change((void *)(bfa->bfad), ioredirect);
+}
+
+void
+bfa_fcpim_set_ioredirect(struct bfa_s *bfa, bfa_boolean_t state)
+{
+ struct bfa_fcpim_mod_s *fcpim = BFA_FCPIM_MOD(bfa);
+ fcpim->ioredirect = state;
+}
diff --git a/drivers/scsi/bfa/bfa_fcpim_priv.h b/drivers/scsi/bfa/bfa_fcpim_priv.h
index 5cf418460f7..762516cb5cb 100644
--- a/drivers/scsi/bfa/bfa_fcpim_priv.h
+++ b/drivers/scsi/bfa/bfa_fcpim_priv.h
@@ -49,7 +49,8 @@ struct bfa_fcpim_mod_s {
int num_tskim_reqs;
u32 path_tov;
u16 q_depth;
- u16 rsvd;
+ u8 reqq; /* Request queue to be used */
+ u8 rsvd;
struct list_head itnim_q; /* queue of active itnim */
struct list_head ioim_free_q; /* free IO resources */
struct list_head ioim_resfree_q; /* IOs waiting for f/w */
@@ -58,6 +59,7 @@ struct bfa_fcpim_mod_s {
u32 ios_active; /* current active IOs */
u32 delay_comp;
struct bfa_fcpim_stats_s stats;
+ bfa_boolean_t ioredirect;
};
struct bfa_ioim_s;
@@ -82,6 +84,7 @@ struct bfa_ioim_s {
struct bfa_cb_qe_s hcb_qe; /* bfa callback qelem */
bfa_cb_cbfn_t io_cbfn; /* IO completion handler */
struct bfa_ioim_sp_s *iosp; /* slow-path IO handling */
+ u8 reqq; /* Request queue for I/O */
};
struct bfa_ioim_sp_s {
@@ -141,6 +144,7 @@ struct bfa_itnim_s {
struct bfa_reqq_wait_s reqq_wait; /* to wait for room in reqq */
struct bfa_fcpim_mod_s *fcpim; /* fcpim module */
struct bfa_itnim_hal_stats_s stats;
+ struct bfa_itnim_latency_s io_latency;
};
#define bfa_itnim_is_online(_itnim) ((_itnim)->is_online)
diff --git a/drivers/scsi/bfa/bfa_fcport.c b/drivers/scsi/bfa/bfa_fcport.c
index c589488db0c..f0933d8d1ed 100644
--- a/drivers/scsi/bfa/bfa_fcport.c
+++ b/drivers/scsi/bfa/bfa_fcport.c
@@ -18,6 +18,7 @@
#include <bfa.h>
#include <bfa_svc.h>
#include <bfi/bfi_pport.h>
+#include <bfi/bfi_pbc.h>
#include <cs/bfa_debug.h>
#include <aen/bfa_aen.h>
#include <cs/bfa_plog.h>
@@ -310,10 +311,12 @@ bfa_fcport_sm_linkdown(struct bfa_fcport_s *fcport,
if (!bfa_ioc_get_fcmode(&fcport->bfa->ioc)) {
- bfa_trc(fcport->bfa, pevent->link_state.fcf.fipenabled);
- bfa_trc(fcport->bfa, pevent->link_state.fcf.fipfailed);
+ bfa_trc(fcport->bfa,
+ pevent->link_state.vc_fcf.fcf.fipenabled);
+ bfa_trc(fcport->bfa,
+ pevent->link_state.vc_fcf.fcf.fipfailed);
- if (pevent->link_state.fcf.fipfailed)
+ if (pevent->link_state.vc_fcf.fcf.fipfailed)
bfa_plog_str(fcport->bfa->plog, BFA_PL_MID_HAL,
BFA_PL_EID_FIP_FCF_DISC, 0,
"FIP FCF Discovery Failed");
@@ -888,6 +891,7 @@ bfa_fcport_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg,
struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa);
struct bfa_pport_cfg_s *port_cfg = &fcport->cfg;
struct bfa_fcport_ln_s *ln = &fcport->ln;
+ struct bfa_timeval_s tv;
bfa_os_memset(fcport, 0, sizeof(struct bfa_fcport_s));
fcport->bfa = bfa;
@@ -899,6 +903,12 @@ bfa_fcport_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg,
bfa_sm_set_state(ln, bfa_fcport_ln_sm_dn);
/**
+ * initialize time stamp for stats reset
+ */
+ bfa_os_gettimeofday(&tv);
+ fcport->stats_reset_time = tv.tv_sec;
+
+ /**
* initialize and set default configuration
*/
port_cfg->topology = BFA_PPORT_TOPOLOGY_P2P;
@@ -912,25 +922,6 @@ bfa_fcport_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg,
}
static void
-bfa_fcport_initdone(struct bfa_s *bfa)
-{
- struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa);
-
- /**
- * Initialize port attributes from IOC hardware data.
- */
- bfa_fcport_set_wwns(fcport);
- if (fcport->cfg.maxfrsize == 0)
- fcport->cfg.maxfrsize = bfa_ioc_maxfrsize(&bfa->ioc);
- fcport->cfg.rx_bbcredit = bfa_ioc_rx_bbcredit(&bfa->ioc);
- fcport->speed_sup = bfa_ioc_speed_sup(&bfa->ioc);
-
- bfa_assert(fcport->cfg.maxfrsize);
- bfa_assert(fcport->cfg.rx_bbcredit);
- bfa_assert(fcport->speed_sup);
-}
-
-static void
bfa_fcport_detach(struct bfa_s *bfa)
{
}
@@ -971,14 +962,15 @@ bfa_fcport_update_linkinfo(struct bfa_fcport_s *fcport)
fcport->topology = pevent->link_state.topology;
if (fcport->topology == BFA_PPORT_TOPOLOGY_LOOP)
- fcport->myalpa =
- pevent->link_state.tl.loop_info.myalpa;
+ fcport->myalpa = 0;
/*
* QoS Details
*/
bfa_os_assign(fcport->qos_attr, pevent->link_state.qos_attr);
- bfa_os_assign(fcport->qos_vc_attr, pevent->link_state.qos_vc_attr);
+ bfa_os_assign(fcport->qos_vc_attr,
+ pevent->link_state.vc_fcf.qos_vc_attr);
+
bfa_trc(fcport->bfa, fcport->speed);
bfa_trc(fcport->bfa, fcport->topology);
@@ -1145,16 +1137,22 @@ __bfa_cb_fcport_stats_get(void *cbarg, bfa_boolean_t complete)
if (complete) {
if (fcport->stats_status == BFA_STATUS_OK) {
+ struct bfa_timeval_s tv;
/* Swap FC QoS or FCoE stats */
- if (bfa_ioc_get_fcmode(&fcport->bfa->ioc))
+ if (bfa_ioc_get_fcmode(&fcport->bfa->ioc)) {
bfa_fcport_qos_stats_swap(
&fcport->stats_ret->fcqos,
&fcport->stats->fcqos);
- else
+ } else {
bfa_fcport_fcoe_stats_swap(
&fcport->stats_ret->fcoe,
&fcport->stats->fcoe);
+
+ bfa_os_gettimeofday(&tv);
+ fcport->stats_ret->fcoe.secs_reset =
+ tv.tv_sec - fcport->stats_reset_time;
+ }
}
fcport->stats_cbfn(fcport->stats_cbarg, fcport->stats_status);
} else {
@@ -1210,6 +1208,14 @@ __bfa_cb_fcport_stats_clr(void *cbarg, bfa_boolean_t complete)
struct bfa_fcport_s *fcport = cbarg;
if (complete) {
+ struct bfa_timeval_s tv;
+
+ /**
+ * re-initialize time stamp for stats reset
+ */
+ bfa_os_gettimeofday(&tv);
+ fcport->stats_reset_time = tv.tv_sec;
+
fcport->stats_cbfn(fcport->stats_cbarg, fcport->stats_status);
} else {
fcport->stats_busy = BFA_FALSE;
@@ -1263,6 +1269,29 @@ bfa_fcport_send_stats_clear(void *cbarg)
*/
/**
+ * Called to initialize port attributes
+ */
+void
+bfa_fcport_init(struct bfa_s *bfa)
+{
+ struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa);
+
+ /**
+ * Initialize port attributes from IOC hardware data.
+ */
+ bfa_fcport_set_wwns(fcport);
+ if (fcport->cfg.maxfrsize == 0)
+ fcport->cfg.maxfrsize = bfa_ioc_maxfrsize(&bfa->ioc);
+ fcport->cfg.rx_bbcredit = bfa_ioc_rx_bbcredit(&bfa->ioc);
+ fcport->speed_sup = bfa_ioc_speed_sup(&bfa->ioc);
+
+ bfa_assert(fcport->cfg.maxfrsize);
+ bfa_assert(fcport->cfg.rx_bbcredit);
+ bfa_assert(fcport->speed_sup);
+}
+
+
+/**
* Firmware message handler.
*/
void
@@ -1355,6 +1384,17 @@ bfa_status_t
bfa_fcport_enable(struct bfa_s *bfa)
{
struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa);
+ struct bfa_iocfc_s *iocfc = &bfa->iocfc;
+ struct bfi_iocfc_cfgrsp_s *cfgrsp = iocfc->cfgrsp;
+
+ /* if port is PBC disabled, return error */
+ if (cfgrsp->pbc_cfg.port_enabled == BFI_PBC_PORT_DISABLED) {
+ bfa_trc(bfa, fcport->pwwn);
+ return BFA_STATUS_PBC;
+ }
+
+ if (bfa_ioc_is_disabled(&bfa->ioc))
+ return BFA_STATUS_IOC_DISABLED;
if (fcport->diag_busy)
return BFA_STATUS_DIAG_BUSY;
@@ -1369,6 +1409,16 @@ bfa_fcport_enable(struct bfa_s *bfa)
bfa_status_t
bfa_fcport_disable(struct bfa_s *bfa)
{
+ struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa);
+ struct bfa_iocfc_s *iocfc = &bfa->iocfc;
+ struct bfi_iocfc_cfgrsp_s *cfgrsp = iocfc->cfgrsp;
+
+ /* if port is PBC disabled, return error */
+ if (cfgrsp->pbc_cfg.port_enabled == BFI_PBC_PORT_DISABLED) {
+ bfa_trc(bfa, fcport->pwwn);
+ return BFA_STATUS_PBC;
+ }
+
bfa_sm_send_event(BFA_FCPORT_MOD(bfa), BFA_FCPORT_SM_DISABLE);
return BFA_STATUS_OK;
}
@@ -1559,12 +1609,17 @@ void
bfa_fcport_get_attr(struct bfa_s *bfa, struct bfa_pport_attr_s *attr)
{
struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa);
+ struct bfa_iocfc_s *iocfc = &bfa->iocfc;
+ struct bfi_iocfc_cfgrsp_s *cfgrsp = iocfc->cfgrsp;
bfa_os_memset(attr, 0, sizeof(struct bfa_pport_attr_s));
attr->nwwn = fcport->nwwn;
attr->pwwn = fcport->pwwn;
+ attr->factorypwwn = bfa_ioc_get_mfg_pwwn(&bfa->ioc);
+ attr->factorynwwn = bfa_ioc_get_mfg_nwwn(&bfa->ioc);
+
bfa_os_memcpy(&attr->pport_cfg, &fcport->cfg,
sizeof(struct bfa_pport_cfg_s));
/*
@@ -1590,11 +1645,18 @@ bfa_fcport_get_attr(struct bfa_s *bfa, struct bfa_pport_attr_s *attr)
attr->pport_cfg.path_tov = bfa_fcpim_path_tov_get(bfa);
attr->pport_cfg.q_depth = bfa_fcpim_qdepth_get(bfa);
- attr->port_state = bfa_sm_to_state(hal_pport_sm_table, fcport->sm);
- if (bfa_ioc_is_disabled(&fcport->bfa->ioc))
- attr->port_state = BFA_PPORT_ST_IOCDIS;
- else if (bfa_ioc_fw_mismatch(&fcport->bfa->ioc))
- attr->port_state = BFA_PPORT_ST_FWMISMATCH;
+
+ /* PBC Disabled State */
+ if (cfgrsp->pbc_cfg.port_enabled == BFI_PBC_PORT_DISABLED)
+ attr->port_state = BFA_PPORT_ST_PREBOOT_DISABLED;
+ else {
+ attr->port_state = bfa_sm_to_state(
+ hal_pport_sm_table, fcport->sm);
+ if (bfa_ioc_is_disabled(&fcport->bfa->ioc))
+ attr->port_state = BFA_PPORT_ST_IOCDIS;
+ else if (bfa_ioc_fw_mismatch(&fcport->bfa->ioc))
+ attr->port_state = BFA_PPORT_ST_FWMISMATCH;
+ }
}
#define BFA_FCPORT_STATS_TOV 1000
@@ -1801,8 +1863,13 @@ bfa_fcport_cfg_qos(struct bfa_s *bfa, bfa_boolean_t on_off)
bfa_trc(bfa, ioc_type);
- if (ioc_type == BFA_IOC_TYPE_FC)
+ if (ioc_type == BFA_IOC_TYPE_FC) {
fcport->cfg.qos_enabled = on_off;
+ /**
+ * Notify fcpim of the change in QoS state
+ */
+ bfa_fcpim_update_ioredirect(bfa);
+ }
}
void
@@ -1886,4 +1953,10 @@ bfa_fcport_is_linkup(struct bfa_s *bfa)
return bfa_sm_cmp_state(BFA_FCPORT_MOD(bfa), bfa_fcport_sm_linkup);
}
+bfa_boolean_t
+bfa_fcport_is_qos_enabled(struct bfa_s *bfa)
+{
+ struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa);
+ return fcport->cfg.qos_enabled;
+}
diff --git a/drivers/scsi/bfa/bfa_fcs.c b/drivers/scsi/bfa/bfa_fcs.c
index 3516172c597..d1a99209bf5 100644
--- a/drivers/scsi/bfa/bfa_fcs.c
+++ b/drivers/scsi/bfa/bfa_fcs.c
@@ -86,7 +86,7 @@ bfa_fcs_attach(struct bfa_fcs_s *fcs, struct bfa_s *bfa, struct bfad_s *bfad,
bfa_attach_fcs(bfa);
fcbuild_init();
- for (i = 0; i < sizeof(fcs_modules) / sizeof(fcs_modules[0]); i++) {
+ for (i = 0; i < ARRAY_SIZE(fcs_modules); i++) {
mod = &fcs_modules[i];
if (mod->attach)
mod->attach(fcs);
@@ -99,14 +99,22 @@ bfa_fcs_attach(struct bfa_fcs_s *fcs, struct bfa_s *bfa, struct bfad_s *bfad,
void
bfa_fcs_init(struct bfa_fcs_s *fcs)
{
- int i;
+ int i, npbc_vports;
struct bfa_fcs_mod_s *mod;
+ struct bfi_pbc_vport_s pbc_vports[BFI_PBC_MAX_VPORTS];
- for (i = 0; i < sizeof(fcs_modules) / sizeof(fcs_modules[0]); i++) {
+ for (i = 0; i < ARRAY_SIZE(fcs_modules); i++) {
mod = &fcs_modules[i];
if (mod->modinit)
mod->modinit(fcs);
}
+ /* Initialize pbc vports */
+ if (!fcs->min_cfg) {
+ npbc_vports =
+ bfa_iocfc_get_pbc_vports(fcs->bfa, pbc_vports);
+ for (i = 0; i < npbc_vports; i++)
+ bfa_fcb_pbc_vport_create(fcs->bfa->bfad, pbc_vports[i]);
+ }
}
/**
@@ -163,13 +171,11 @@ void
bfa_fcs_exit(struct bfa_fcs_s *fcs)
{
struct bfa_fcs_mod_s *mod;
- int nmods, i;
+ int i;
bfa_wc_init(&fcs->wc, bfa_fcs_exit_comp, fcs);
- nmods = sizeof(fcs_modules) / sizeof(fcs_modules[0]);
-
- for (i = 0; i < nmods; i++) {
+ for (i = 0; i < ARRAY_SIZE(fcs_modules); i++) {
mod = &fcs_modules[i];
if (mod->modexit) {
diff --git a/drivers/scsi/bfa/bfa_fcs_lport.c b/drivers/scsi/bfa/bfa_fcs_lport.c
index 7c1251c682d..35df20e68a5 100644
--- a/drivers/scsi/bfa/bfa_fcs_lport.c
+++ b/drivers/scsi/bfa/bfa_fcs_lport.c
@@ -135,6 +135,9 @@ bfa_fcs_port_sm_init(struct bfa_fcs_port_s *port, enum bfa_fcs_port_event event)
bfa_fcs_port_deleted(port);
break;
+ case BFA_FCS_PORT_SM_OFFLINE:
+ break;
+
default:
bfa_sm_fault(port->fcs, event);
}
diff --git a/drivers/scsi/bfa/bfa_fcxp.c b/drivers/scsi/bfa/bfa_fcxp.c
index cf0ad678268..8258f88bfee 100644
--- a/drivers/scsi/bfa/bfa_fcxp.c
+++ b/drivers/scsi/bfa/bfa_fcxp.c
@@ -149,11 +149,6 @@ bfa_fcxp_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg,
}
static void
-bfa_fcxp_initdone(struct bfa_s *bfa)
-{
-}
-
-static void
bfa_fcxp_detach(struct bfa_s *bfa)
{
}
@@ -225,7 +220,7 @@ bfa_fcxp_null_comp(void *bfad_fcxp, struct bfa_fcxp_s *fcxp, void *cbarg,
bfa_status_t req_status, u32 rsp_len,
u32 resid_len, struct fchs_s *rsp_fchs)
{
- /**discarded fcxp completion */
+ /* discarded fcxp completion */
}
static void
@@ -527,11 +522,8 @@ bfa_fcxp_alloc(void *caller, struct bfa_s *bfa, int nreq_sgles,
if (nreq_sgles > BFI_SGE_INLINE) {
nreq_sgpg = BFA_SGPG_NPAGE(nreq_sgles);
- if (bfa_sgpg_malloc
- (bfa, &fcxp->req_sgpg_q, nreq_sgpg)
+ if (bfa_sgpg_malloc(bfa, &fcxp->req_sgpg_q, nreq_sgpg)
!= BFA_STATUS_OK) {
- /* bfa_sgpg_wait(bfa, &fcxp->req_sgpg_wqe,
- nreq_sgpg); */
/*
* TODO
*/
@@ -685,7 +677,7 @@ bfa_fcxp_send(struct bfa_fcxp_s *fcxp, struct bfa_rport_s *rport,
fcxp->send_cbarg = cbarg;
/**
- * If no room in CPE queue, wait for
+ * If no room in CPE queue, wait for space in request queue
*/
send_req = bfa_reqq_next(bfa, BFA_REQQ_FCXP);
if (!send_req) {
diff --git a/drivers/scsi/bfa/bfa_fwimg_priv.h b/drivers/scsi/bfa/bfa_fwimg_priv.h
index 1ec1355924d..d33e19e5439 100644
--- a/drivers/scsi/bfa/bfa_fwimg_priv.h
+++ b/drivers/scsi/bfa/bfa_fwimg_priv.h
@@ -21,11 +21,24 @@
#define BFI_FLASH_CHUNK_SZ 256 /* Flash chunk size */
#define BFI_FLASH_CHUNK_SZ_WORDS (BFI_FLASH_CHUNK_SZ/sizeof(u32))
-extern u32 *bfi_image_ct_get_chunk(u32 off);
-extern u32 bfi_image_ct_size;
-extern u32 *bfi_image_cb_get_chunk(u32 off);
-extern u32 bfi_image_cb_size;
-extern u32 *bfi_image_cb;
-extern u32 *bfi_image_ct;
+/**
+ * BFI FW image type
+ */
+enum {
+ BFI_IMAGE_CB_FC,
+ BFI_IMAGE_CT_FC,
+ BFI_IMAGE_CT_CNA,
+ BFI_IMAGE_MAX,
+};
+
+extern u32 *bfi_image_get_chunk(int type, uint32_t off);
+extern u32 bfi_image_get_size(int type);
+extern u32 bfi_image_ct_fc_size;
+extern u32 bfi_image_ct_cna_size;
+extern u32 bfi_image_cb_fc_size;
+extern u32 *bfi_image_ct_fc;
+extern u32 *bfi_image_ct_cna;
+extern u32 *bfi_image_cb_fc;
+
#endif /* __BFA_FWIMG_PRIV_H__ */
diff --git a/drivers/scsi/bfa/bfa_hw_cb.c b/drivers/scsi/bfa/bfa_hw_cb.c
index 871a4e28575..edfd729445c 100644
--- a/drivers/scsi/bfa/bfa_hw_cb.c
+++ b/drivers/scsi/bfa/bfa_hw_cb.c
@@ -152,4 +152,9 @@ bfa_hwcb_isr_mode_set(struct bfa_s *bfa, bfa_boolean_t msix)
bfa->iocfc.hwif.hw_rspq_ack = bfa_hwcb_rspq_ack_msix;
}
-
+void
+bfa_hwcb_msix_get_rme_range(struct bfa_s *bfa, u32 *start, u32 *end)
+{
+ *start = BFA_MSIX_RME_Q0;
+ *end = BFA_MSIX_RME_Q7;
+}
diff --git a/drivers/scsi/bfa/bfa_hw_ct.c b/drivers/scsi/bfa/bfa_hw_ct.c
index 76ceb9a4bf2..a357fb3066f 100644
--- a/drivers/scsi/bfa/bfa_hw_ct.c
+++ b/drivers/scsi/bfa/bfa_hw_ct.c
@@ -168,4 +168,9 @@ bfa_hwct_isr_mode_set(struct bfa_s *bfa, bfa_boolean_t msix)
bfa_ioc_isr_mode_set(&bfa->ioc, msix);
}
-
+void
+bfa_hwct_msix_get_rme_range(struct bfa_s *bfa, u32 *start, u32 *end)
+{
+ *start = BFA_MSIX_RME_Q0;
+ *end = BFA_MSIX_RME_Q3;
+}
diff --git a/drivers/scsi/bfa/bfa_intr.c b/drivers/scsi/bfa/bfa_intr.c
index 0eba3f930d5..493678889b2 100644
--- a/drivers/scsi/bfa/bfa_intr.c
+++ b/drivers/scsi/bfa/bfa_intr.c
@@ -134,6 +134,7 @@ bfa_isr_enable(struct bfa_s *bfa)
bfa_reg_write(bfa->iocfc.bfa_regs.intr_status, intr_unmask);
bfa_reg_write(bfa->iocfc.bfa_regs.intr_mask, ~intr_unmask);
+ bfa->iocfc.intr_mask = ~intr_unmask;
bfa_isr_mode_set(bfa, bfa->msix.nvecs != 0);
}
diff --git a/drivers/scsi/bfa/bfa_ioc.c b/drivers/scsi/bfa/bfa_ioc.c
index e038bc9769f..8e78f20110a 100644
--- a/drivers/scsi/bfa/bfa_ioc.c
+++ b/drivers/scsi/bfa/bfa_ioc.c
@@ -59,22 +59,18 @@ BFA_TRC_FILE(CNA, IOC);
((__ioc)->ioc_hwif->ioc_firmware_lock(__ioc))
#define bfa_ioc_firmware_unlock(__ioc) \
((__ioc)->ioc_hwif->ioc_firmware_unlock(__ioc))
-#define bfa_ioc_fwimg_get_chunk(__ioc, __off) \
- ((__ioc)->ioc_hwif->ioc_fwimg_get_chunk(__ioc, __off))
-#define bfa_ioc_fwimg_get_size(__ioc) \
- ((__ioc)->ioc_hwif->ioc_fwimg_get_size(__ioc))
#define bfa_ioc_reg_init(__ioc) ((__ioc)->ioc_hwif->ioc_reg_init(__ioc))
#define bfa_ioc_map_port(__ioc) ((__ioc)->ioc_hwif->ioc_map_port(__ioc))
#define bfa_ioc_notify_hbfail(__ioc) \
((__ioc)->ioc_hwif->ioc_notify_hbfail(__ioc))
+#define bfa_ioc_is_optrom(__ioc) \
+ (bfi_image_get_size(BFA_IOC_FWIMG_TYPE(__ioc)) < BFA_IOC_FWIMG_MINSZ)
bfa_boolean_t bfa_auto_recover = BFA_TRUE;
/*
* forward declarations
*/
-static void bfa_ioc_aen_post(struct bfa_ioc_s *bfa,
- enum bfa_ioc_aen_event event);
static void bfa_ioc_hw_sem_get(struct bfa_ioc_s *ioc);
static void bfa_ioc_hw_sem_get_cancel(struct bfa_ioc_s *ioc);
static void bfa_ioc_hwinit(struct bfa_ioc_s *ioc, bfa_boolean_t force);
@@ -88,6 +84,7 @@ static void bfa_ioc_reset(struct bfa_ioc_s *ioc, bfa_boolean_t force);
static void bfa_ioc_mbox_poll(struct bfa_ioc_s *ioc);
static void bfa_ioc_mbox_hbfail(struct bfa_ioc_s *ioc);
static void bfa_ioc_recover(struct bfa_ioc_s *ioc);
+static void bfa_ioc_check_attr_wwns(struct bfa_ioc_s *ioc);
static void bfa_ioc_disable_comp(struct bfa_ioc_s *ioc);
static void bfa_ioc_lpu_stop(struct bfa_ioc_s *ioc);
@@ -433,6 +430,7 @@ bfa_ioc_sm_getattr(struct bfa_ioc_s *ioc, enum ioc_event event)
switch (event) {
case IOC_E_FWRSP_GETATTR:
bfa_ioc_timer_stop(ioc);
+ bfa_ioc_check_attr_wwns(ioc);
bfa_fsm_set_state(ioc, bfa_ioc_sm_op);
break;
@@ -879,8 +877,8 @@ bfa_ioc_fwver_cmp(struct bfa_ioc_s *ioc, struct bfi_ioc_image_hdr_s *fwhdr)
struct bfi_ioc_image_hdr_s *drv_fwhdr;
int i;
- drv_fwhdr =
- (struct bfi_ioc_image_hdr_s *)bfa_ioc_fwimg_get_chunk(ioc, 0);
+ drv_fwhdr = (struct bfi_ioc_image_hdr_s *)
+ bfi_image_get_chunk(BFA_IOC_FWIMG_TYPE(ioc), 0);
for (i = 0; i < BFI_IOC_MD5SUM_SZ; i++) {
if (fwhdr->md5sum[i] != drv_fwhdr->md5sum[i]) {
@@ -907,12 +905,13 @@ bfa_ioc_fwver_valid(struct bfa_ioc_s *ioc)
/**
* If bios/efi boot (flash based) -- return true
*/
- if (bfa_ioc_fwimg_get_size(ioc) < BFA_IOC_FWIMG_MINSZ)
+ if (bfa_ioc_is_optrom(ioc))
return BFA_TRUE;
bfa_ioc_fwver_get(ioc, &fwhdr);
- drv_fwhdr =
- (struct bfi_ioc_image_hdr_s *)bfa_ioc_fwimg_get_chunk(ioc, 0);
+ drv_fwhdr = (struct bfi_ioc_image_hdr_s *)
+ bfi_image_get_chunk(BFA_IOC_FWIMG_TYPE(ioc), 0);
+
if (fwhdr.signature != drv_fwhdr->signature) {
bfa_trc(ioc, fwhdr.signature);
@@ -980,8 +979,13 @@ bfa_ioc_hwinit(struct bfa_ioc_s *ioc, bfa_boolean_t force)
/**
* If IOC function is disabled and firmware version is same,
* just re-enable IOC.
+ *
+ * If option rom, IOC must not be in operational state. With
+ * convergence, IOC will be in operational state when 2nd driver
+ * is loaded.
*/
- if (ioc_fwstate == BFI_IOC_DISABLED || ioc_fwstate == BFI_IOC_OP) {
+ if (ioc_fwstate == BFI_IOC_DISABLED ||
+ (!bfa_ioc_is_optrom(ioc) && ioc_fwstate == BFI_IOC_OP)) {
bfa_trc(ioc, ioc_fwstate);
/**
@@ -1125,21 +1129,22 @@ bfa_ioc_download_fw(struct bfa_ioc_s *ioc, u32 boot_type,
/**
* Flash based firmware boot
*/
- bfa_trc(ioc, bfa_ioc_fwimg_get_size(ioc));
- if (bfa_ioc_fwimg_get_size(ioc) < BFA_IOC_FWIMG_MINSZ)
+ bfa_trc(ioc, bfi_image_get_size(BFA_IOC_FWIMG_TYPE(ioc)));
+ if (bfa_ioc_is_optrom(ioc))
boot_type = BFI_BOOT_TYPE_FLASH;
- fwimg = bfa_ioc_fwimg_get_chunk(ioc, chunkno);
+ fwimg = bfi_image_get_chunk(BFA_IOC_FWIMG_TYPE(ioc), chunkno);
+
pgnum = bfa_ioc_smem_pgnum(ioc, loff);
pgoff = bfa_ioc_smem_pgoff(ioc, loff);
bfa_reg_write(ioc->ioc_regs.host_page_num_fn, pgnum);
- for (i = 0; i < bfa_ioc_fwimg_get_size(ioc); i++) {
+ for (i = 0; i < bfi_image_get_size(BFA_IOC_FWIMG_TYPE(ioc)); i++) {
if (BFA_IOC_FLASH_CHUNK_NO(i) != chunkno) {
chunkno = BFA_IOC_FLASH_CHUNK_NO(i);
- fwimg = bfa_ioc_fwimg_get_chunk(ioc,
+ fwimg = bfi_image_get_chunk(BFA_IOC_FWIMG_TYPE(ioc),
BFA_IOC_FLASH_CHUNK_ADDR(chunkno));
}
@@ -1188,6 +1193,7 @@ bfa_ioc_getattr_reply(struct bfa_ioc_s *ioc)
struct bfi_ioc_attr_s *attr = ioc->attr;
attr->adapter_prop = bfa_os_ntohl(attr->adapter_prop);
+ attr->card_type = bfa_os_ntohl(attr->card_type);
attr->maxfrsize = bfa_os_ntohs(attr->maxfrsize);
bfa_fsm_send_event(ioc, IOC_E_FWRSP_GETATTR);
@@ -1282,6 +1288,7 @@ bfa_ioc_boot(struct bfa_ioc_s *ioc, u32 boot_type, u32 boot_param)
bfa_reg_write((rb + BFA_IOC1_STATE_REG), BFI_IOC_INITING);
}
+ bfa_ioc_msgflush(ioc);
bfa_ioc_download_fw(ioc, boot_type, boot_param);
/**
@@ -1416,7 +1423,7 @@ bfa_ioc_pci_init(struct bfa_ioc_s *ioc, struct bfa_pcidev_s *pcidev,
{
ioc->ioc_mc = mc;
ioc->pcidev = *pcidev;
- ioc->ctdev = (ioc->pcidev.device_id == BFA_PCI_DEVICE_ID_CT);
+ ioc->ctdev = bfa_asic_id_ct(ioc->pcidev.device_id);
ioc->cna = ioc->ctdev && !ioc->fcmode;
/**
@@ -1607,6 +1614,13 @@ bfa_ioc_error_isr(struct bfa_ioc_s *ioc)
bfa_fsm_send_event(ioc, IOC_E_HWERROR);
}
+void
+bfa_ioc_set_fcmode(struct bfa_ioc_s *ioc)
+{
+ ioc->fcmode = BFA_TRUE;
+ ioc->port_id = bfa_ioc_pcifn(ioc);
+}
+
#ifndef BFA_BIOS_BUILD
/**
@@ -1696,6 +1710,9 @@ bfa_ioc_get_adapter_attr(struct bfa_ioc_s *ioc,
/* For now, model descr uses same model string */
bfa_ioc_get_adapter_model(ioc, ad_attr->model_descr);
+ ad_attr->card_type = ioc_attr->card_type;
+ ad_attr->is_mezz = bfa_mfg_is_mezz(ioc_attr->card_type);
+
if (BFI_ADAPTER_IS_SPECIAL(ioc_attr->adapter_prop))
ad_attr->prototype = 1;
else
@@ -1779,28 +1796,17 @@ void
bfa_ioc_get_adapter_model(struct bfa_ioc_s *ioc, char *model)
{
struct bfi_ioc_attr_s *ioc_attr;
- u8 nports;
- u8 max_speed;
bfa_assert(model);
bfa_os_memset((void *)model, 0, BFA_ADAPTER_MODEL_NAME_LEN);
ioc_attr = ioc->attr;
- nports = bfa_ioc_get_nports(ioc);
- max_speed = bfa_ioc_speed_sup(ioc);
-
/**
* model name
*/
- if (max_speed == 10) {
- strcpy(model, "BR-10?0");
- model[5] = '0' + nports;
- } else {
- strcpy(model, "Brocade-??5");
- model[8] = '0' + max_speed;
- model[9] = '0' + nports;
- }
+ snprintf(model, BFA_ADAPTER_MODEL_NAME_LEN, "%s-%u",
+ BFA_MFG_NAME, ioc_attr->card_type);
}
enum bfa_ioc_state
@@ -1827,78 +1833,54 @@ bfa_ioc_get_attr(struct bfa_ioc_s *ioc, struct bfa_ioc_attr_s *ioc_attr)
}
/**
- * hal_wwn_public
+ * bfa_wwn_public
*/
wwn_t
bfa_ioc_get_pwwn(struct bfa_ioc_s *ioc)
{
- union {
- wwn_t wwn;
- u8 byte[sizeof(wwn_t)];
- }
- w;
-
- w.wwn = ioc->attr->mfg_wwn;
-
- if (bfa_ioc_portid(ioc) == 1)
- w.byte[7]++;
-
- return w.wwn;
+ return ioc->attr->pwwn;
}
wwn_t
bfa_ioc_get_nwwn(struct bfa_ioc_s *ioc)
{
- union {
- wwn_t wwn;
- u8 byte[sizeof(wwn_t)];
- }
- w;
-
- w.wwn = ioc->attr->mfg_wwn;
-
- if (bfa_ioc_portid(ioc) == 1)
- w.byte[7]++;
+ return ioc->attr->nwwn;
+}
- w.byte[0] = 0x20;
+u64
+bfa_ioc_get_adid(struct bfa_ioc_s *ioc)
+{
+ return ioc->attr->mfg_pwwn;
+}
- return w.wwn;
+mac_t
+bfa_ioc_get_mac(struct bfa_ioc_s *ioc)
+{
+ /*
+ * Currently mfg mac is used as FCoE enode mac (not configured by PBC)
+ */
+ if (bfa_ioc_get_type(ioc) == BFA_IOC_TYPE_FCoE)
+ return bfa_ioc_get_mfg_mac(ioc);
+ else
+ return ioc->attr->mac;
}
wwn_t
-bfa_ioc_get_wwn_naa5(struct bfa_ioc_s *ioc, u16 inst)
+bfa_ioc_get_mfg_pwwn(struct bfa_ioc_s *ioc)
{
- union {
- wwn_t wwn;
- u8 byte[sizeof(wwn_t)];
- }
- w , w5;
-
- bfa_trc(ioc, inst);
-
- w.wwn = ioc->attr->mfg_wwn;
- w5.byte[0] = 0x50 | w.byte[2] >> 4;
- w5.byte[1] = w.byte[2] << 4 | w.byte[3] >> 4;
- w5.byte[2] = w.byte[3] << 4 | w.byte[4] >> 4;
- w5.byte[3] = w.byte[4] << 4 | w.byte[5] >> 4;
- w5.byte[4] = w.byte[5] << 4 | w.byte[6] >> 4;
- w5.byte[5] = w.byte[6] << 4 | w.byte[7] >> 4;
- w5.byte[6] = w.byte[7] << 4 | (inst & 0x0f00) >> 8;
- w5.byte[7] = (inst & 0xff);
-
- return w5.wwn;
+ return ioc->attr->mfg_pwwn;
}
-u64
-bfa_ioc_get_adid(struct bfa_ioc_s *ioc)
+wwn_t
+bfa_ioc_get_mfg_nwwn(struct bfa_ioc_s *ioc)
{
- return ioc->attr->mfg_wwn;
+ return ioc->attr->mfg_nwwn;
}
mac_t
-bfa_ioc_get_mac(struct bfa_ioc_s *ioc)
+bfa_ioc_get_mfg_mac(struct bfa_ioc_s *ioc)
{
- mac_t mac;
+ mac_t mac;
mac = ioc->attr->mfg_mac;
mac.mac[MAC_ADDRLEN - 1] += bfa_ioc_pcifn(ioc);
@@ -1906,23 +1888,16 @@ bfa_ioc_get_mac(struct bfa_ioc_s *ioc)
return mac;
}
-void
-bfa_ioc_set_fcmode(struct bfa_ioc_s *ioc)
-{
- ioc->fcmode = BFA_TRUE;
- ioc->port_id = bfa_ioc_pcifn(ioc);
-}
-
bfa_boolean_t
bfa_ioc_get_fcmode(struct bfa_ioc_s *ioc)
{
- return ioc->fcmode || (ioc->pcidev.device_id != BFA_PCI_DEVICE_ID_CT);
+ return ioc->fcmode || !bfa_asic_id_ct(ioc->pcidev.device_id);
}
/**
* Send AEN notification
*/
-static void
+void
bfa_ioc_aen_post(struct bfa_ioc_s *ioc, enum bfa_ioc_aen_event event)
{
union bfa_aen_data_u aen_data;
@@ -2070,19 +2045,16 @@ bfa_ioc_recover(struct bfa_ioc_s *ioc)
bfa_fsm_send_event(ioc, IOC_E_HBFAIL);
}
-#else
-
static void
-bfa_ioc_aen_post(struct bfa_ioc_s *ioc, enum bfa_ioc_aen_event event)
+bfa_ioc_check_attr_wwns(struct bfa_ioc_s *ioc)
{
-}
+ if (bfa_ioc_get_type(ioc) == BFA_IOC_TYPE_LL)
+ return;
-static void
-bfa_ioc_recover(struct bfa_ioc_s *ioc)
-{
- bfa_assert(0);
+ if (ioc->attr->nwwn == 0)
+ bfa_ioc_aen_post(ioc, BFA_IOC_AEN_INVALID_NWWN);
+ if (ioc->attr->pwwn == 0)
+ bfa_ioc_aen_post(ioc, BFA_IOC_AEN_INVALID_PWWN);
}
#endif
-
-
diff --git a/drivers/scsi/bfa/bfa_ioc.h b/drivers/scsi/bfa/bfa_ioc.h
index d0804406ea1..cae05b251c9 100644
--- a/drivers/scsi/bfa/bfa_ioc.h
+++ b/drivers/scsi/bfa/bfa_ioc.h
@@ -186,9 +186,6 @@ struct bfa_ioc_hwif_s {
bfa_status_t (*ioc_pll_init) (struct bfa_ioc_s *ioc);
bfa_boolean_t (*ioc_firmware_lock) (struct bfa_ioc_s *ioc);
void (*ioc_firmware_unlock) (struct bfa_ioc_s *ioc);
- u32 * (*ioc_fwimg_get_chunk) (struct bfa_ioc_s *ioc,
- u32 off);
- u32 (*ioc_fwimg_get_size) (struct bfa_ioc_s *ioc);
void (*ioc_reg_init) (struct bfa_ioc_s *ioc);
void (*ioc_map_port) (struct bfa_ioc_s *ioc);
void (*ioc_isr_mode_set) (struct bfa_ioc_s *ioc,
@@ -214,6 +211,10 @@ struct bfa_ioc_hwif_s {
#define bfa_ioc_stats(_ioc, _stats) ((_ioc)->stats._stats++)
#define BFA_IOC_FWIMG_MINSZ (16 * 1024)
+#define BFA_IOC_FWIMG_TYPE(__ioc) \
+ (((__ioc)->ctdev) ? \
+ (((__ioc)->fcmode) ? BFI_IMAGE_CT_FC : BFI_IMAGE_CT_CNA) : \
+ BFI_IMAGE_CB_FC)
#define BFA_IOC_FLASH_CHUNK_NO(off) (off / BFI_FLASH_CHUNK_SZ_WORDS)
#define BFA_IOC_FLASH_OFFSET_IN_CHUNK(off) (off % BFI_FLASH_CHUNK_SZ_WORDS)
@@ -296,14 +297,17 @@ void bfa_ioc_fwver_get(struct bfa_ioc_s *ioc,
struct bfi_ioc_image_hdr_s *fwhdr);
bfa_boolean_t bfa_ioc_fwver_cmp(struct bfa_ioc_s *ioc,
struct bfi_ioc_image_hdr_s *fwhdr);
+void bfa_ioc_aen_post(struct bfa_ioc_s *ioc, enum bfa_ioc_aen_event event);
/*
* bfa mfg wwn API functions
*/
wwn_t bfa_ioc_get_pwwn(struct bfa_ioc_s *ioc);
wwn_t bfa_ioc_get_nwwn(struct bfa_ioc_s *ioc);
-wwn_t bfa_ioc_get_wwn_naa5(struct bfa_ioc_s *ioc, u16 inst);
mac_t bfa_ioc_get_mac(struct bfa_ioc_s *ioc);
+wwn_t bfa_ioc_get_mfg_pwwn(struct bfa_ioc_s *ioc);
+wwn_t bfa_ioc_get_mfg_nwwn(struct bfa_ioc_s *ioc);
+mac_t bfa_ioc_get_mfg_mac(struct bfa_ioc_s *ioc);
u64 bfa_ioc_get_adid(struct bfa_ioc_s *ioc);
#endif /* __BFA_IOC_H__ */
diff --git a/drivers/scsi/bfa/bfa_ioc_cb.c b/drivers/scsi/bfa/bfa_ioc_cb.c
index 3ce85319f73..324bdde7ea2 100644
--- a/drivers/scsi/bfa/bfa_ioc_cb.c
+++ b/drivers/scsi/bfa/bfa_ioc_cb.c
@@ -33,26 +33,13 @@ BFA_TRC_FILE(CNA, IOC_CB);
static bfa_status_t bfa_ioc_cb_pll_init(struct bfa_ioc_s *ioc);
static bfa_boolean_t bfa_ioc_cb_firmware_lock(struct bfa_ioc_s *ioc);
static void bfa_ioc_cb_firmware_unlock(struct bfa_ioc_s *ioc);
-static u32 *bfa_ioc_cb_fwimg_get_chunk(struct bfa_ioc_s *ioc, u32 off);
-static u32 bfa_ioc_cb_fwimg_get_size(struct bfa_ioc_s *ioc);
static void bfa_ioc_cb_reg_init(struct bfa_ioc_s *ioc);
static void bfa_ioc_cb_map_port(struct bfa_ioc_s *ioc);
static void bfa_ioc_cb_isr_mode_set(struct bfa_ioc_s *ioc, bfa_boolean_t msix);
static void bfa_ioc_cb_notify_hbfail(struct bfa_ioc_s *ioc);
static void bfa_ioc_cb_ownership_reset(struct bfa_ioc_s *ioc);
-struct bfa_ioc_hwif_s hwif_cb = {
- bfa_ioc_cb_pll_init,
- bfa_ioc_cb_firmware_lock,
- bfa_ioc_cb_firmware_unlock,
- bfa_ioc_cb_fwimg_get_chunk,
- bfa_ioc_cb_fwimg_get_size,
- bfa_ioc_cb_reg_init,
- bfa_ioc_cb_map_port,
- bfa_ioc_cb_isr_mode_set,
- bfa_ioc_cb_notify_hbfail,
- bfa_ioc_cb_ownership_reset,
-};
+struct bfa_ioc_hwif_s hwif_cb;
/**
* Called from bfa_ioc_attach() to map asic specific calls.
@@ -60,19 +47,16 @@ struct bfa_ioc_hwif_s hwif_cb = {
void
bfa_ioc_set_cb_hwif(struct bfa_ioc_s *ioc)
{
- ioc->ioc_hwif = &hwif_cb;
-}
-
-static u32 *
-bfa_ioc_cb_fwimg_get_chunk(struct bfa_ioc_s *ioc, u32 off)
-{
- return bfi_image_cb_get_chunk(off);
-}
+ hwif_cb.ioc_pll_init = bfa_ioc_cb_pll_init;
+ hwif_cb.ioc_firmware_lock = bfa_ioc_cb_firmware_lock;
+ hwif_cb.ioc_firmware_unlock = bfa_ioc_cb_firmware_unlock;
+ hwif_cb.ioc_reg_init = bfa_ioc_cb_reg_init;
+ hwif_cb.ioc_map_port = bfa_ioc_cb_map_port;
+ hwif_cb.ioc_isr_mode_set = bfa_ioc_cb_isr_mode_set;
+ hwif_cb.ioc_notify_hbfail = bfa_ioc_cb_notify_hbfail;
+ hwif_cb.ioc_ownership_reset = bfa_ioc_cb_ownership_reset;
-static u32
-bfa_ioc_cb_fwimg_get_size(struct bfa_ioc_s *ioc)
-{
- return bfi_image_cb_size;
+ ioc->ioc_hwif = &hwif_cb;
}
/**
diff --git a/drivers/scsi/bfa/bfa_ioc_ct.c b/drivers/scsi/bfa/bfa_ioc_ct.c
index 20b58ad5f95..68f027da001 100644
--- a/drivers/scsi/bfa/bfa_ioc_ct.c
+++ b/drivers/scsi/bfa/bfa_ioc_ct.c
@@ -33,27 +33,13 @@ BFA_TRC_FILE(CNA, IOC_CT);
static bfa_status_t bfa_ioc_ct_pll_init(struct bfa_ioc_s *ioc);
static bfa_boolean_t bfa_ioc_ct_firmware_lock(struct bfa_ioc_s *ioc);
static void bfa_ioc_ct_firmware_unlock(struct bfa_ioc_s *ioc);
-static u32* bfa_ioc_ct_fwimg_get_chunk(struct bfa_ioc_s *ioc,
- u32 off);
-static u32 bfa_ioc_ct_fwimg_get_size(struct bfa_ioc_s *ioc);
static void bfa_ioc_ct_reg_init(struct bfa_ioc_s *ioc);
static void bfa_ioc_ct_map_port(struct bfa_ioc_s *ioc);
static void bfa_ioc_ct_isr_mode_set(struct bfa_ioc_s *ioc, bfa_boolean_t msix);
static void bfa_ioc_ct_notify_hbfail(struct bfa_ioc_s *ioc);
static void bfa_ioc_ct_ownership_reset(struct bfa_ioc_s *ioc);
-struct bfa_ioc_hwif_s hwif_ct = {
- bfa_ioc_ct_pll_init,
- bfa_ioc_ct_firmware_lock,
- bfa_ioc_ct_firmware_unlock,
- bfa_ioc_ct_fwimg_get_chunk,
- bfa_ioc_ct_fwimg_get_size,
- bfa_ioc_ct_reg_init,
- bfa_ioc_ct_map_port,
- bfa_ioc_ct_isr_mode_set,
- bfa_ioc_ct_notify_hbfail,
- bfa_ioc_ct_ownership_reset,
-};
+struct bfa_ioc_hwif_s hwif_ct;
/**
* Called from bfa_ioc_attach() to map asic specific calls.
@@ -61,19 +47,16 @@ struct bfa_ioc_hwif_s hwif_ct = {
void
bfa_ioc_set_ct_hwif(struct bfa_ioc_s *ioc)
{
- ioc->ioc_hwif = &hwif_ct;
-}
+ hwif_ct.ioc_pll_init = bfa_ioc_ct_pll_init;
+ hwif_ct.ioc_firmware_lock = bfa_ioc_ct_firmware_lock;
+ hwif_ct.ioc_firmware_unlock = bfa_ioc_ct_firmware_unlock;
+ hwif_ct.ioc_reg_init = bfa_ioc_ct_reg_init;
+ hwif_ct.ioc_map_port = bfa_ioc_ct_map_port;
+ hwif_ct.ioc_isr_mode_set = bfa_ioc_ct_isr_mode_set;
+ hwif_ct.ioc_notify_hbfail = bfa_ioc_ct_notify_hbfail;
+ hwif_ct.ioc_ownership_reset = bfa_ioc_ct_ownership_reset;
-static u32*
-bfa_ioc_ct_fwimg_get_chunk(struct bfa_ioc_s *ioc, u32 off)
-{
- return bfi_image_ct_get_chunk(off);
-}
-
-static u32
-bfa_ioc_ct_fwimg_get_size(struct bfa_ioc_s *ioc)
-{
- return bfi_image_ct_size;
+ ioc->ioc_hwif = &hwif_ct;
}
/**
@@ -95,7 +78,7 @@ bfa_ioc_ct_firmware_lock(struct bfa_ioc_s *ioc)
/**
* If bios boot (flash based) -- do not increment usage count
*/
- if (bfa_ioc_ct_fwimg_get_size(ioc) < BFA_IOC_FWIMG_MINSZ)
+ if (bfi_image_get_size(BFA_IOC_FWIMG_TYPE(ioc)) < BFA_IOC_FWIMG_MINSZ)
return BFA_TRUE;
bfa_ioc_sem_get(ioc->ioc_regs.ioc_usage_sem_reg);
@@ -146,9 +129,14 @@ bfa_ioc_ct_firmware_unlock(struct bfa_ioc_s *ioc)
/**
* Firmware lock is relevant only for CNA.
+ */
+ if (!ioc->cna)
+ return;
+
+ /**
* If bios boot (flash based) -- do not decrement usage count
*/
- if (!ioc->cna || bfa_ioc_ct_fwimg_get_size(ioc) < BFA_IOC_FWIMG_MINSZ)
+ if (bfi_image_get_size(BFA_IOC_FWIMG_TYPE(ioc)) < BFA_IOC_FWIMG_MINSZ)
return;
/**
@@ -388,10 +376,35 @@ bfa_ioc_ct_pll_init(struct bfa_ioc_s *ioc)
bfa_reg_write(ioc->ioc_regs.app_pll_fast_ctl_reg, pll_fclk |
__APP_PLL_425_ENABLE);
+ /**
+ * PSS memory reset is asserted at power-on-reset. Need to clear
+ * this before running EDRAM BISTR
+ */
+ if (ioc->cna) {
+ bfa_reg_write((rb + PMM_1T_RESET_REG_P0), __PMM_1T_RESET_P);
+ bfa_reg_write((rb + PMM_1T_RESET_REG_P1), __PMM_1T_RESET_P);
+ }
+
+ r32 = bfa_reg_read((rb + PSS_CTL_REG));
+ r32 &= ~__PSS_LMEM_RESET;
+ bfa_reg_write((rb + PSS_CTL_REG), r32);
+ bfa_os_udelay(1000);
+
+ if (ioc->cna) {
+ bfa_reg_write((rb + PMM_1T_RESET_REG_P0), 0);
+ bfa_reg_write((rb + PMM_1T_RESET_REG_P1), 0);
+ }
+
bfa_reg_write((rb + MBIST_CTL_REG), __EDRAM_BISTR_START);
bfa_os_udelay(1000);
r32 = bfa_reg_read((rb + MBIST_STAT_REG));
bfa_trc(ioc, r32);
+
+ /**
+ * Clear BISTR
+ */
+ bfa_reg_write((rb + MBIST_CTL_REG), 0);
+
/*
* release semaphore.
*/
diff --git a/drivers/scsi/bfa/bfa_iocfc.c b/drivers/scsi/bfa/bfa_iocfc.c
index a76de2669bf..90820be9986 100644
--- a/drivers/scsi/bfa/bfa_iocfc.c
+++ b/drivers/scsi/bfa/bfa_iocfc.c
@@ -113,7 +113,6 @@ bfa_iocfc_send_cfg(void *bfa_arg)
bfa_assert(cfg->fwcfg.num_cqs <= BFI_IOC_MAX_CQS);
bfa_trc(bfa, cfg->fwcfg.num_cqs);
- iocfc->cfgdone = BFA_FALSE;
bfa_iocfc_reset_queues(bfa);
/**
@@ -145,6 +144,15 @@ bfa_iocfc_send_cfg(void *bfa_arg)
}
/**
+ * Enable interrupt coalescing if it is driver init path
+ * and not ioc disable/enable path.
+ */
+ if (!iocfc->cfgdone)
+ cfg_info->intr_attr.coalesce = BFA_TRUE;
+
+ iocfc->cfgdone = BFA_FALSE;
+
+ /**
* dma map IOC configuration itself
*/
bfi_h2i_set(cfg_req.mh, BFI_MC_IOCFC, BFI_IOCFC_H2I_CFG_REQ,
@@ -170,7 +178,7 @@ bfa_iocfc_init_mem(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg,
/**
* Initialize chip specific handlers.
*/
- if (bfa_ioc_devid(&bfa->ioc) == BFA_PCI_DEVICE_ID_CT) {
+ if (bfa_asic_id_ct(bfa_ioc_devid(&bfa->ioc))) {
iocfc->hwif.hw_reginit = bfa_hwct_reginit;
iocfc->hwif.hw_reqq_ack = bfa_hwct_reqq_ack;
iocfc->hwif.hw_rspq_ack = bfa_hwct_rspq_ack;
@@ -179,6 +187,7 @@ bfa_iocfc_init_mem(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg,
iocfc->hwif.hw_msix_uninstall = bfa_hwct_msix_uninstall;
iocfc->hwif.hw_isr_mode_set = bfa_hwct_isr_mode_set;
iocfc->hwif.hw_msix_getvecs = bfa_hwct_msix_getvecs;
+ iocfc->hwif.hw_msix_get_rme_range = bfa_hwct_msix_get_rme_range;
} else {
iocfc->hwif.hw_reginit = bfa_hwcb_reginit;
iocfc->hwif.hw_reqq_ack = bfa_hwcb_reqq_ack;
@@ -188,6 +197,7 @@ bfa_iocfc_init_mem(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg,
iocfc->hwif.hw_msix_uninstall = bfa_hwcb_msix_uninstall;
iocfc->hwif.hw_isr_mode_set = bfa_hwcb_isr_mode_set;
iocfc->hwif.hw_msix_getvecs = bfa_hwcb_msix_getvecs;
+ iocfc->hwif.hw_msix_get_rme_range = bfa_hwcb_msix_get_rme_range;
}
iocfc->hwif.hw_reginit(bfa);
@@ -291,18 +301,6 @@ bfa_iocfc_mem_claim(struct bfa_s *bfa, struct bfa_iocfc_cfg_s *cfg,
}
/**
- * BFA submodules initialization completion notification.
- */
-static void
-bfa_iocfc_initdone_submod(struct bfa_s *bfa)
-{
- int i;
-
- for (i = 0; hal_mods[i]; i++)
- hal_mods[i]->initdone(bfa);
-}
-
-/**
* Start BFA submodules.
*/
static void
@@ -376,7 +374,6 @@ bfa_iocfc_cfgrsp(struct bfa_s *bfa)
struct bfa_iocfc_s *iocfc = &bfa->iocfc;
struct bfi_iocfc_cfgrsp_s *cfgrsp = iocfc->cfgrsp;
struct bfa_iocfc_fwcfg_s *fwcfg = &cfgrsp->fwcfg;
- struct bfi_iocfc_cfg_s *cfginfo = iocfc->cfginfo;
fwcfg->num_cqs = fwcfg->num_cqs;
fwcfg->num_ioim_reqs = bfa_os_ntohs(fwcfg->num_ioim_reqs);
@@ -385,15 +382,13 @@ bfa_iocfc_cfgrsp(struct bfa_s *bfa)
fwcfg->num_uf_bufs = bfa_os_ntohs(fwcfg->num_uf_bufs);
fwcfg->num_rports = bfa_os_ntohs(fwcfg->num_rports);
- cfginfo->intr_attr.coalesce = cfgrsp->intr_attr.coalesce;
- cfginfo->intr_attr.delay = bfa_os_ntohs(cfgrsp->intr_attr.delay);
- cfginfo->intr_attr.latency = bfa_os_ntohs(cfgrsp->intr_attr.latency);
-
iocfc->cfgdone = BFA_TRUE;
/**
* Configuration is complete - initialize/start submodules
*/
+ bfa_fcport_init(bfa);
+
if (iocfc->action == BFA_IOCFC_ACT_INIT)
bfa_cb_queue(bfa, &iocfc->init_hcb_qe, bfa_iocfc_init_cb, bfa);
else
@@ -531,7 +526,6 @@ bfa_iocfc_enable_cbfn(void *bfa_arg, enum bfa_status status)
return;
}
- bfa_iocfc_initdone_submod(bfa);
bfa_iocfc_send_cfg(bfa);
}
@@ -625,9 +619,9 @@ bfa_iocfc_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg,
bfa->trcmod, bfa->aen, bfa->logm);
/**
- * Choose FC (ssid: 0x1C) v/s FCoE (ssid: 0x14) mode.
+ * Set FC mode for BFA_PCI_DEVICE_ID_CT_FC.
*/
- if (0)
+ if (pcidev->device_id == BFA_PCI_DEVICE_ID_CT_FC)
bfa_ioc_set_fcmode(&bfa->ioc);
bfa_ioc_pci_init(&bfa->ioc, pcidev, BFI_MC_IOCFC);
@@ -748,10 +742,20 @@ bfa_adapter_get_id(struct bfa_s *bfa)
void
bfa_iocfc_get_attr(struct bfa_s *bfa, struct bfa_iocfc_attr_s *attr)
{
- struct bfa_iocfc_s *iocfc = &bfa->iocfc;
+ struct bfa_iocfc_s *iocfc = &bfa->iocfc;
+
+ attr->intr_attr.coalesce = iocfc->cfginfo->intr_attr.coalesce;
+
+ attr->intr_attr.delay = iocfc->cfginfo->intr_attr.delay ?
+ bfa_os_ntohs(iocfc->cfginfo->intr_attr.delay) :
+ bfa_os_ntohs(iocfc->cfgrsp->intr_attr.delay);
+
+ attr->intr_attr.latency = iocfc->cfginfo->intr_attr.latency ?
+ bfa_os_ntohs(iocfc->cfginfo->intr_attr.latency) :
+ bfa_os_ntohs(iocfc->cfgrsp->intr_attr.latency);
+
+ attr->config = iocfc->cfg;
- attr->intr_attr = iocfc->cfginfo->intr_attr;
- attr->config = iocfc->cfg;
}
bfa_status_t
@@ -760,7 +764,10 @@ bfa_iocfc_israttr_set(struct bfa_s *bfa, struct bfa_iocfc_intr_attr_s *attr)
struct bfa_iocfc_s *iocfc = &bfa->iocfc;
struct bfi_iocfc_set_intr_req_s *m;
- iocfc->cfginfo->intr_attr = *attr;
+ iocfc->cfginfo->intr_attr.coalesce = attr->coalesce;
+ iocfc->cfginfo->intr_attr.delay = bfa_os_htons(attr->delay);
+ iocfc->cfginfo->intr_attr.latency = bfa_os_htons(attr->latency);
+
if (!bfa_iocfc_is_operational(bfa))
return BFA_STATUS_OK;
@@ -770,9 +777,10 @@ bfa_iocfc_israttr_set(struct bfa_s *bfa, struct bfa_iocfc_intr_attr_s *attr)
bfi_h2i_set(m->mh, BFI_MC_IOCFC, BFI_IOCFC_H2I_SET_INTR_REQ,
bfa_lpuid(bfa));
- m->coalesce = attr->coalesce;
- m->delay = bfa_os_htons(attr->delay);
- m->latency = bfa_os_htons(attr->latency);
+ m->coalesce = iocfc->cfginfo->intr_attr.coalesce;
+ m->delay = iocfc->cfginfo->intr_attr.delay;
+ m->latency = iocfc->cfginfo->intr_attr.latency;
+
bfa_trc(bfa, attr->delay);
bfa_trc(bfa, attr->latency);
@@ -872,15 +880,48 @@ bfa_iocfc_is_operational(struct bfa_s *bfa)
* Return boot target port wwns -- read from boot information in flash.
*/
void
-bfa_iocfc_get_bootwwns(struct bfa_s *bfa, u8 *nwwns, wwn_t **wwns)
+bfa_iocfc_get_bootwwns(struct bfa_s *bfa, u8 *nwwns, wwn_t *wwns)
{
- struct bfa_iocfc_s *iocfc = &bfa->iocfc;
- struct bfi_iocfc_cfgrsp_s *cfgrsp = iocfc->cfgrsp;
+ struct bfa_iocfc_s *iocfc = &bfa->iocfc;
+ struct bfi_iocfc_cfgrsp_s *cfgrsp = iocfc->cfgrsp;
+ int i;
+
+ if (cfgrsp->pbc_cfg.boot_enabled && cfgrsp->pbc_cfg.nbluns) {
+ bfa_trc(bfa, cfgrsp->pbc_cfg.nbluns);
+ *nwwns = cfgrsp->pbc_cfg.nbluns;
+ for (i = 0; i < cfgrsp->pbc_cfg.nbluns; i++)
+ wwns[i] = cfgrsp->pbc_cfg.blun[i].tgt_pwwn;
+
+ return;
+ }
*nwwns = cfgrsp->bootwwns.nwwns;
- *wwns = cfgrsp->bootwwns.wwn;
+ memcpy(wwns, cfgrsp->bootwwns.wwn, sizeof(cfgrsp->bootwwns.wwn));
+}
+
+void
+bfa_iocfc_get_pbc_boot_cfg(struct bfa_s *bfa, struct bfa_boot_pbc_s *pbcfg)
+{
+ struct bfa_iocfc_s *iocfc = &bfa->iocfc;
+ struct bfi_iocfc_cfgrsp_s *cfgrsp = iocfc->cfgrsp;
+
+ pbcfg->enable = cfgrsp->pbc_cfg.boot_enabled;
+ pbcfg->nbluns = cfgrsp->pbc_cfg.nbluns;
+ pbcfg->speed = cfgrsp->pbc_cfg.port_speed;
+ memcpy(pbcfg->pblun, cfgrsp->pbc_cfg.blun, sizeof(pbcfg->pblun));
}
+int
+bfa_iocfc_get_pbc_vports(struct bfa_s *bfa, struct bfi_pbc_vport_s *pbc_vport)
+{
+ struct bfa_iocfc_s *iocfc = &bfa->iocfc;
+ struct bfi_iocfc_cfgrsp_s *cfgrsp = iocfc->cfgrsp;
+
+ memcpy(pbc_vport, cfgrsp->pbc_cfg.vport, sizeof(cfgrsp->pbc_cfg.vport));
+ return cfgrsp->pbc_cfg.nvports;
+}
+
+
#endif
diff --git a/drivers/scsi/bfa/bfa_iocfc.h b/drivers/scsi/bfa/bfa_iocfc.h
index fbb4bdc9d60..74a6a048d1f 100644
--- a/drivers/scsi/bfa/bfa_iocfc.h
+++ b/drivers/scsi/bfa/bfa_iocfc.h
@@ -21,6 +21,7 @@
#include <bfa_ioc.h>
#include <bfa.h>
#include <bfi/bfi_iocfc.h>
+#include <bfi/bfi_pbc.h>
#include <bfa_callback_priv.h>
#define BFA_REQQ_NELEMS_MIN (4)
@@ -62,6 +63,8 @@ struct bfa_hwif_s {
void (*hw_isr_mode_set)(struct bfa_s *bfa, bfa_boolean_t msix);
void (*hw_msix_getvecs)(struct bfa_s *bfa, u32 *vecmap,
u32 *nvecs, u32 *maxvec);
+ void (*hw_msix_get_rme_range) (struct bfa_s *bfa, u32 *start,
+ u32 *end);
};
typedef void (*bfa_cb_iocfc_t) (void *cbarg, enum bfa_status status);
@@ -103,7 +106,8 @@ struct bfa_iocfc_s {
struct bfa_hwif_s hwif;
bfa_cb_iocfc_t updateq_cbfn; /* bios callback function */
- void *updateq_cbarg; /* bios callback arg */
+ void *updateq_cbarg; /* bios callback arg */
+ u32 intr_mask;
};
#define bfa_lpuid(__bfa) bfa_ioc_portid(&(__bfa)->ioc)
@@ -116,7 +120,10 @@ struct bfa_iocfc_s {
#define bfa_isr_mode_set(__bfa, __msix) \
((__bfa)->iocfc.hwif.hw_isr_mode_set(__bfa, __msix))
#define bfa_msix_getvecs(__bfa, __vecmap, __nvecs, __maxvec) \
- (__bfa)->iocfc.hwif.hw_msix_getvecs(__bfa, __vecmap, __nvecs, __maxvec)
+ ((__bfa)->iocfc.hwif.hw_msix_getvecs(__bfa, __vecmap, \
+ __nvecs, __maxvec))
+#define bfa_msix_get_rme_range(__bfa, __start, __end) \
+ ((__bfa)->iocfc.hwif.hw_msix_get_rme_range(__bfa, __start, __end))
/*
* FC specific IOC functions.
@@ -152,6 +159,7 @@ void bfa_hwcb_msix_uninstall(struct bfa_s *bfa);
void bfa_hwcb_isr_mode_set(struct bfa_s *bfa, bfa_boolean_t msix);
void bfa_hwcb_msix_getvecs(struct bfa_s *bfa, u32 *vecmap,
u32 *nvecs, u32 *maxvec);
+void bfa_hwcb_msix_get_rme_range(struct bfa_s *bfa, u32 *start, u32 *end);
void bfa_hwct_reginit(struct bfa_s *bfa);
void bfa_hwct_reqq_ack(struct bfa_s *bfa, int rspq);
void bfa_hwct_rspq_ack(struct bfa_s *bfa, int rspq);
@@ -161,11 +169,16 @@ void bfa_hwct_msix_uninstall(struct bfa_s *bfa);
void bfa_hwct_isr_mode_set(struct bfa_s *bfa, bfa_boolean_t msix);
void bfa_hwct_msix_getvecs(struct bfa_s *bfa, u32 *vecmap,
u32 *nvecs, u32 *maxvec);
+void bfa_hwct_msix_get_rme_range(struct bfa_s *bfa, u32 *start, u32 *end);
void bfa_com_meminfo(bfa_boolean_t mincfg, u32 *dm_len);
void bfa_com_attach(struct bfa_s *bfa, struct bfa_meminfo_s *mi,
bfa_boolean_t mincfg);
-void bfa_iocfc_get_bootwwns(struct bfa_s *bfa, u8 *nwwns, wwn_t **wwns);
+void bfa_iocfc_get_bootwwns(struct bfa_s *bfa, u8 *nwwns, wwn_t *wwns);
+void bfa_iocfc_get_pbc_boot_cfg(struct bfa_s *bfa,
+ struct bfa_boot_pbc_s *pbcfg);
+int bfa_iocfc_get_pbc_vports(struct bfa_s *bfa,
+ struct bfi_pbc_vport_s *pbc_vport);
#endif /* __BFA_IOCFC_H__ */
diff --git a/drivers/scsi/bfa/bfa_ioim.c b/drivers/scsi/bfa/bfa_ioim.c
index 687f3d6e252..bdfdc19915f 100644
--- a/drivers/scsi/bfa/bfa_ioim.c
+++ b/drivers/scsi/bfa/bfa_ioim.c
@@ -133,6 +133,8 @@ bfa_ioim_sm_uninit(struct bfa_ioim_s *ioim, enum bfa_ioim_event event)
case BFA_IOIM_SM_IOTOV:
bfa_sm_set_state(ioim, bfa_ioim_sm_hcb);
+ list_del(&ioim->qe);
+ list_add_tail(&ioim->qe, &ioim->fcpim->ioim_comp_q);
bfa_cb_queue(ioim->bfa, &ioim->hcb_qe,
__bfa_cb_ioim_pathtov, ioim);
break;
@@ -182,6 +184,8 @@ bfa_ioim_sm_sgalloc(struct bfa_ioim_s *ioim, enum bfa_ioim_event event)
case BFA_IOIM_SM_ABORT:
bfa_sm_set_state(ioim, bfa_ioim_sm_hcb);
bfa_sgpg_wcancel(ioim->bfa, &ioim->iosp->sgpg_wqe);
+ list_del(&ioim->qe);
+ list_add_tail(&ioim->qe, &ioim->fcpim->ioim_comp_q);
bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, __bfa_cb_ioim_abort,
ioim);
break;
@@ -189,6 +193,8 @@ bfa_ioim_sm_sgalloc(struct bfa_ioim_s *ioim, enum bfa_ioim_event event)
case BFA_IOIM_SM_HWFAIL:
bfa_sm_set_state(ioim, bfa_ioim_sm_hcb);
bfa_sgpg_wcancel(ioim->bfa, &ioim->iosp->sgpg_wqe);
+ list_del(&ioim->qe);
+ list_add_tail(&ioim->qe, &ioim->fcpim->ioim_comp_q);
bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, __bfa_cb_ioim_failed,
ioim);
break;
@@ -210,18 +216,24 @@ bfa_ioim_sm_active(struct bfa_ioim_s *ioim, enum bfa_ioim_event event)
switch (event) {
case BFA_IOIM_SM_COMP_GOOD:
bfa_sm_set_state(ioim, bfa_ioim_sm_hcb);
+ list_del(&ioim->qe);
+ list_add_tail(&ioim->qe, &ioim->fcpim->ioim_comp_q);
bfa_cb_queue(ioim->bfa, &ioim->hcb_qe,
__bfa_cb_ioim_good_comp, ioim);
break;
case BFA_IOIM_SM_COMP:
bfa_sm_set_state(ioim, bfa_ioim_sm_hcb);
+ list_del(&ioim->qe);
+ list_add_tail(&ioim->qe, &ioim->fcpim->ioim_comp_q);
bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, __bfa_cb_ioim_comp,
ioim);
break;
case BFA_IOIM_SM_DONE:
bfa_sm_set_state(ioim, bfa_ioim_sm_hcb_free);
+ list_del(&ioim->qe);
+ list_add_tail(&ioim->qe, &ioim->fcpim->ioim_comp_q);
bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, __bfa_cb_ioim_comp,
ioim);
break;
@@ -234,8 +246,8 @@ bfa_ioim_sm_active(struct bfa_ioim_s *ioim, enum bfa_ioim_event event)
bfa_sm_set_state(ioim, bfa_ioim_sm_abort);
else {
bfa_sm_set_state(ioim, bfa_ioim_sm_abort_qfull);
- bfa_reqq_wait(ioim->bfa, ioim->itnim->reqq,
- &ioim->iosp->reqq_wait);
+ bfa_reqq_wait(ioim->bfa, ioim->reqq,
+ &ioim->iosp->reqq_wait);
}
break;
@@ -247,13 +259,15 @@ bfa_ioim_sm_active(struct bfa_ioim_s *ioim, enum bfa_ioim_event event)
bfa_sm_set_state(ioim, bfa_ioim_sm_cleanup);
else {
bfa_sm_set_state(ioim, bfa_ioim_sm_cleanup_qfull);
- bfa_reqq_wait(ioim->bfa, ioim->itnim->reqq,
- &ioim->iosp->reqq_wait);
+ bfa_reqq_wait(ioim->bfa, ioim->reqq,
+ &ioim->iosp->reqq_wait);
}
break;
case BFA_IOIM_SM_HWFAIL:
bfa_sm_set_state(ioim, bfa_ioim_sm_hcb);
+ list_del(&ioim->qe);
+ list_add_tail(&ioim->qe, &ioim->fcpim->ioim_comp_q);
bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, __bfa_cb_ioim_failed,
ioim);
break;
@@ -287,12 +301,16 @@ bfa_ioim_sm_abort(struct bfa_ioim_s *ioim, enum bfa_ioim_event event)
case BFA_IOIM_SM_ABORT_COMP:
bfa_sm_set_state(ioim, bfa_ioim_sm_hcb);
+ list_del(&ioim->qe);
+ list_add_tail(&ioim->qe, &ioim->fcpim->ioim_comp_q);
bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, __bfa_cb_ioim_abort,
ioim);
break;
case BFA_IOIM_SM_COMP_UTAG:
bfa_sm_set_state(ioim, bfa_ioim_sm_hcb);
+ list_del(&ioim->qe);
+ list_add_tail(&ioim->qe, &ioim->fcpim->ioim_comp_q);
bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, __bfa_cb_ioim_abort,
ioim);
break;
@@ -305,13 +323,15 @@ bfa_ioim_sm_abort(struct bfa_ioim_s *ioim, enum bfa_ioim_event event)
bfa_sm_set_state(ioim, bfa_ioim_sm_cleanup);
else {
bfa_sm_set_state(ioim, bfa_ioim_sm_cleanup_qfull);
- bfa_reqq_wait(ioim->bfa, ioim->itnim->reqq,
+ bfa_reqq_wait(ioim->bfa, ioim->reqq,
&ioim->iosp->reqq_wait);
}
break;
case BFA_IOIM_SM_HWFAIL:
bfa_sm_set_state(ioim, bfa_ioim_sm_hcb);
+ list_del(&ioim->qe);
+ list_add_tail(&ioim->qe, &ioim->fcpim->ioim_comp_q);
bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, __bfa_cb_ioim_failed,
ioim);
break;
@@ -365,6 +385,8 @@ bfa_ioim_sm_cleanup(struct bfa_ioim_s *ioim, enum bfa_ioim_event event)
case BFA_IOIM_SM_HWFAIL:
bfa_sm_set_state(ioim, bfa_ioim_sm_hcb);
+ list_del(&ioim->qe);
+ list_add_tail(&ioim->qe, &ioim->fcpim->ioim_comp_q);
bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, __bfa_cb_ioim_failed,
ioim);
break;
@@ -399,6 +421,8 @@ bfa_ioim_sm_qfull(struct bfa_ioim_s *ioim, enum bfa_ioim_event event)
case BFA_IOIM_SM_ABORT:
bfa_sm_set_state(ioim, bfa_ioim_sm_hcb);
bfa_reqq_wcancel(&ioim->iosp->reqq_wait);
+ list_del(&ioim->qe);
+ list_add_tail(&ioim->qe, &ioim->fcpim->ioim_comp_q);
bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, __bfa_cb_ioim_abort,
ioim);
break;
@@ -414,6 +438,8 @@ bfa_ioim_sm_qfull(struct bfa_ioim_s *ioim, enum bfa_ioim_event event)
case BFA_IOIM_SM_HWFAIL:
bfa_sm_set_state(ioim, bfa_ioim_sm_hcb);
bfa_reqq_wcancel(&ioim->iosp->reqq_wait);
+ list_del(&ioim->qe);
+ list_add_tail(&ioim->qe, &ioim->fcpim->ioim_comp_q);
bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, __bfa_cb_ioim_failed,
ioim);
break;
@@ -448,6 +474,8 @@ bfa_ioim_sm_abort_qfull(struct bfa_ioim_s *ioim, enum bfa_ioim_event event)
case BFA_IOIM_SM_COMP:
bfa_sm_set_state(ioim, bfa_ioim_sm_hcb);
bfa_reqq_wcancel(&ioim->iosp->reqq_wait);
+ list_del(&ioim->qe);
+ list_add_tail(&ioim->qe, &ioim->fcpim->ioim_comp_q);
bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, __bfa_cb_ioim_abort,
ioim);
break;
@@ -455,6 +483,8 @@ bfa_ioim_sm_abort_qfull(struct bfa_ioim_s *ioim, enum bfa_ioim_event event)
case BFA_IOIM_SM_DONE:
bfa_sm_set_state(ioim, bfa_ioim_sm_hcb_free);
bfa_reqq_wcancel(&ioim->iosp->reqq_wait);
+ list_del(&ioim->qe);
+ list_add_tail(&ioim->qe, &ioim->fcpim->ioim_comp_q);
bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, __bfa_cb_ioim_abort,
ioim);
break;
@@ -462,6 +492,8 @@ bfa_ioim_sm_abort_qfull(struct bfa_ioim_s *ioim, enum bfa_ioim_event event)
case BFA_IOIM_SM_HWFAIL:
bfa_sm_set_state(ioim, bfa_ioim_sm_hcb);
bfa_reqq_wcancel(&ioim->iosp->reqq_wait);
+ list_del(&ioim->qe);
+ list_add_tail(&ioim->qe, &ioim->fcpim->ioim_comp_q);
bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, __bfa_cb_ioim_failed,
ioim);
break;
@@ -488,7 +520,7 @@ bfa_ioim_sm_cleanup_qfull(struct bfa_ioim_s *ioim, enum bfa_ioim_event event)
case BFA_IOIM_SM_ABORT:
/**
- * IO is alraedy being cleaned up implicitly
+ * IO is already being cleaned up implicitly
*/
ioim->io_cbfn = __bfa_cb_ioim_abort;
break;
@@ -511,6 +543,8 @@ bfa_ioim_sm_cleanup_qfull(struct bfa_ioim_s *ioim, enum bfa_ioim_event event)
case BFA_IOIM_SM_HWFAIL:
bfa_sm_set_state(ioim, bfa_ioim_sm_hcb);
bfa_reqq_wcancel(&ioim->iosp->reqq_wait);
+ list_del(&ioim->qe);
+ list_add_tail(&ioim->qe, &ioim->fcpim->ioim_comp_q);
bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, __bfa_cb_ioim_failed,
ioim);
break;
@@ -738,9 +772,9 @@ bfa_ioim_send_ioreq(struct bfa_ioim_s *ioim)
/**
* check for room in queue to send request now
*/
- m = bfa_reqq_next(ioim->bfa, itnim->reqq);
+ m = bfa_reqq_next(ioim->bfa, ioim->reqq);
if (!m) {
- bfa_reqq_wait(ioim->bfa, ioim->itnim->reqq,
+ bfa_reqq_wait(ioim->bfa, ioim->reqq,
&ioim->iosp->reqq_wait);
return BFA_FALSE;
}
@@ -832,7 +866,7 @@ bfa_ioim_send_ioreq(struct bfa_ioim_s *ioim)
/**
* queue I/O message to firmware
*/
- bfa_reqq_produce(ioim->bfa, itnim->reqq);
+ bfa_reqq_produce(ioim->bfa, ioim->reqq);
return BFA_TRUE;
}
@@ -930,14 +964,13 @@ bfa_ioim_sgpg_setup(struct bfa_ioim_s *ioim)
static bfa_boolean_t
bfa_ioim_send_abort(struct bfa_ioim_s *ioim)
{
- struct bfa_itnim_s *itnim = ioim->itnim;
struct bfi_ioim_abort_req_s *m;
enum bfi_ioim_h2i msgop;
/**
* check for room in queue to send request now
*/
- m = bfa_reqq_next(ioim->bfa, itnim->reqq);
+ m = bfa_reqq_next(ioim->bfa, ioim->reqq);
if (!m)
return BFA_FALSE;
@@ -956,7 +989,7 @@ bfa_ioim_send_abort(struct bfa_ioim_s *ioim)
/**
* queue I/O message to firmware
*/
- bfa_reqq_produce(ioim->bfa, itnim->reqq);
+ bfa_reqq_produce(ioim->bfa, ioim->reqq);
return BFA_TRUE;
}
@@ -1306,6 +1339,14 @@ void
bfa_ioim_start(struct bfa_ioim_s *ioim)
{
bfa_trc_fp(ioim->bfa, ioim->iotag);
+
+ /**
+ * Obtain the queue over which this request has to be issued
+ */
+ ioim->reqq = bfa_fcpim_ioredirect_enabled(ioim->bfa) ?
+ bfa_cb_ioim_get_reqq(ioim->dio) :
+ bfa_itnim_get_reqq(ioim);
+
bfa_sm_send_event(ioim, BFA_IOIM_SM_START);
}
diff --git a/drivers/scsi/bfa/bfa_log_module.c b/drivers/scsi/bfa/bfa_log_module.c
index 5c154d341d6..cf577ef7cb9 100644
--- a/drivers/scsi/bfa/bfa_log_module.c
+++ b/drivers/scsi/bfa/bfa_log_module.c
@@ -110,6 +110,27 @@ struct bfa_log_msgdef_s bfa_log_msg_array[] = {
"Running firmware version is incompatible with the driver version.",
(0), 0},
+{BFA_AEN_IOC_FWCFG_ERROR, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG,
+ BFA_LOG_CRITICAL, "BFA_AEN_IOC_FWCFG_ERROR",
+ "Link initialization failed due to firmware configuration read error:"
+ " WWN = %s.",
+ ((BFA_LOG_S << BFA_LOG_ARG0) | 0), 1},
+
+{BFA_AEN_IOC_INVALID_VENDOR, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG,
+ BFA_LOG_ERROR, "BFA_AEN_IOC_INVALID_VENDOR",
+ "Unsupported switch vendor. Link initialization failed: WWN = %s.",
+ ((BFA_LOG_S << BFA_LOG_ARG0) | 0), 1},
+
+{BFA_AEN_IOC_INVALID_NWWN, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG,
+ BFA_LOG_ERROR, "BFA_AEN_IOC_INVALID_NWWN",
+ "Invalid NWWN. Link initialization failed: NWWN = 00:00:00:00:00:00:00:00.",
+ (0), 0},
+
+{BFA_AEN_IOC_INVALID_PWWN, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG,
+ BFA_LOG_ERROR, "BFA_AEN_IOC_INVALID_PWWN",
+ "Invalid PWWN. Link initialization failed: PWWN = 00:00:00:00:00:00:00:00.",
+ (0), 0},
+
@@ -347,6 +368,22 @@ struct bfa_log_msgdef_s bfa_log_msg_array[] = {
((BFA_LOG_S << BFA_LOG_ARG0) | (BFA_LOG_D << BFA_LOG_ARG1) |
(BFA_LOG_D << BFA_LOG_ARG2) | 0), 3},
+{BFA_LOG_HAL_DRIVER_ERROR, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG,
+ BFA_LOG_INFO, "HAL_DRIVER_ERROR",
+ "%s",
+ ((BFA_LOG_S << BFA_LOG_ARG0) | 0), 1},
+
+{BFA_LOG_HAL_DRIVER_CONFIG_ERROR,
+ BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_INFO,
+ "HAL_DRIVER_CONFIG_ERROR",
+ "%s",
+ ((BFA_LOG_S << BFA_LOG_ARG0) | 0), 1},
+
+{BFA_LOG_HAL_MBOX_ERROR, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG,
+ BFA_LOG_INFO, "HAL_MBOX_ERROR",
+ "%s",
+ ((BFA_LOG_S << BFA_LOG_ARG0) | 0), 1},
+
@@ -412,6 +449,55 @@ struct bfa_log_msgdef_s bfa_log_msg_array[] = {
((BFA_LOG_D << BFA_LOG_ARG0) | (BFA_LOG_P << BFA_LOG_ARG1) |
(BFA_LOG_X << BFA_LOG_ARG2) | 0), 3},
+{BFA_LOG_LINUX_DRIVER_CONFIG_ERROR,
+ BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_INFO,
+ "LINUX_DRIVER_CONFIG_ERROR",
+ "%s",
+ ((BFA_LOG_S << BFA_LOG_ARG0) | 0), 1},
+
+{BFA_LOG_LINUX_BNA_STATE_MACHINE,
+ BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_INFO,
+ "LINUX_BNA_STATE_MACHINE",
+ "%s",
+ ((BFA_LOG_S << BFA_LOG_ARG0) | 0), 1},
+
+{BFA_LOG_LINUX_IOC_ERROR, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG,
+ BFA_LOG_INFO, "LINUX_IOC_ERROR",
+ "%s",
+ ((BFA_LOG_S << BFA_LOG_ARG0) | 0), 1},
+
+{BFA_LOG_LINUX_RESOURCE_ALLOC_ERROR,
+ BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_INFO,
+ "LINUX_RESOURCE_ALLOC_ERROR",
+ "%s",
+ ((BFA_LOG_S << BFA_LOG_ARG0) | 0), 1},
+
+{BFA_LOG_LINUX_RING_BUFFER_ERROR,
+ BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_INFO,
+ "LINUX_RING_BUFFER_ERROR",
+ "%s",
+ ((BFA_LOG_S << BFA_LOG_ARG0) | 0), 1},
+
+{BFA_LOG_LINUX_DRIVER_ERROR, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG,
+ BFA_LOG_ERROR, "LINUX_DRIVER_ERROR",
+ "%s",
+ ((BFA_LOG_S << BFA_LOG_ARG0) | 0), 1},
+
+{BFA_LOG_LINUX_DRIVER_INFO, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG,
+ BFA_LOG_INFO, "LINUX_DRIVER_INFO",
+ "%s",
+ ((BFA_LOG_S << BFA_LOG_ARG0) | 0), 1},
+
+{BFA_LOG_LINUX_DRIVER_DIAG, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG,
+ BFA_LOG_INFO, "LINUX_DRIVER_DIAG",
+ "%s",
+ ((BFA_LOG_S << BFA_LOG_ARG0) | 0), 1},
+
+{BFA_LOG_LINUX_DRIVER_AEN, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG,
+ BFA_LOG_INFO, "LINUX_DRIVER_AEN",
+ "%s",
+ ((BFA_LOG_S << BFA_LOG_ARG0) | 0), 1},
+
diff --git a/drivers/scsi/bfa/bfa_lps.c b/drivers/scsi/bfa/bfa_lps.c
index ad06f618909..acabb44f092 100644
--- a/drivers/scsi/bfa/bfa_lps.c
+++ b/drivers/scsi/bfa/bfa_lps.c
@@ -41,7 +41,6 @@ static void bfa_lps_attach(struct bfa_s *bfa, void *bfad,
struct bfa_iocfc_cfg_s *cfg,
struct bfa_meminfo_s *meminfo,
struct bfa_pcidev_s *pcidev);
-static void bfa_lps_initdone(struct bfa_s *bfa);
static void bfa_lps_detach(struct bfa_s *bfa);
static void bfa_lps_start(struct bfa_s *bfa);
static void bfa_lps_stop(struct bfa_s *bfa);
@@ -347,11 +346,6 @@ bfa_lps_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg,
}
static void
-bfa_lps_initdone(struct bfa_s *bfa)
-{
-}
-
-static void
bfa_lps_detach(struct bfa_s *bfa)
{
}
diff --git a/drivers/scsi/bfa/bfa_port.c b/drivers/scsi/bfa/bfa_port.c
index cab19028361..c7e69f1e56e 100644
--- a/drivers/scsi/bfa/bfa_port.c
+++ b/drivers/scsi/bfa/bfa_port.c
@@ -102,9 +102,14 @@ bfa_port_get_stats_isr(struct bfa_port_s *port, bfa_status_t status)
port->stats_busy = BFA_FALSE;
if (status == BFA_STATUS_OK) {
+ struct bfa_timeval_s tv;
+
memcpy(port->stats, port->stats_dma.kva,
sizeof(union bfa_pport_stats_u));
bfa_port_stats_swap(port, port->stats);
+
+ bfa_os_gettimeofday(&tv);
+ port->stats->fc.secs_reset = tv.tv_sec - port->stats_reset_time;
}
if (port->stats_cbfn) {
@@ -125,9 +130,17 @@ bfa_port_get_stats_isr(struct bfa_port_s *port, bfa_status_t status)
static void
bfa_port_clear_stats_isr(struct bfa_port_s *port, bfa_status_t status)
{
+ struct bfa_timeval_s tv;
+
port->stats_status = status;
port->stats_busy = BFA_FALSE;
+ /**
+ * re-initialize time stamp for stats reset
+ */
+ bfa_os_gettimeofday(&tv);
+ port->stats_reset_time = tv.tv_sec;
+
if (port->stats_cbfn) {
port->stats_cbfn(port->stats_cbarg, status);
port->stats_cbfn = NULL;
@@ -394,7 +407,7 @@ bfa_port_hbfail(void *arg)
*/
if (port->stats_busy) {
if (port->stats_cbfn)
- port->stats_cbfn(port->dev, BFA_STATUS_FAILED);
+ port->stats_cbfn(port->stats_cbarg, BFA_STATUS_FAILED);
port->stats_cbfn = NULL;
port->stats_busy = BFA_FALSE;
}
@@ -404,7 +417,7 @@ bfa_port_hbfail(void *arg)
*/
if (port->endis_pending) {
if (port->endis_cbfn)
- port->endis_cbfn(port->dev, BFA_STATUS_FAILED);
+ port->endis_cbfn(port->endis_cbarg, BFA_STATUS_FAILED);
port->endis_cbfn = NULL;
port->endis_pending = BFA_FALSE;
}
@@ -428,6 +441,8 @@ void
bfa_port_attach(struct bfa_port_s *port, struct bfa_ioc_s *ioc, void *dev,
struct bfa_trc_mod_s *trcmod, struct bfa_log_mod_s *logmod)
{
+ struct bfa_timeval_s tv;
+
bfa_assert(port);
port->dev = dev;
@@ -435,13 +450,21 @@ bfa_port_attach(struct bfa_port_s *port, struct bfa_ioc_s *ioc, void *dev,
port->trcmod = trcmod;
port->logmod = logmod;
- port->stats_busy = port->endis_pending = BFA_FALSE;
- port->stats_cbfn = port->endis_cbfn = NULL;
+ port->stats_busy = BFA_FALSE;
+ port->endis_pending = BFA_FALSE;
+ port->stats_cbfn = NULL;
+ port->endis_cbfn = NULL;
bfa_ioc_mbox_regisr(port->ioc, BFI_MC_PORT, bfa_port_isr, port);
bfa_ioc_hbfail_init(&port->hbfail, bfa_port_hbfail, port);
bfa_ioc_hbfail_register(port->ioc, &port->hbfail);
+ /**
+ * initialize time stamp for stats reset
+ */
+ bfa_os_gettimeofday(&tv);
+ port->stats_reset_time = tv.tv_sec;
+
bfa_trc(port, 0);
}
diff --git a/drivers/scsi/bfa/bfa_port_priv.h b/drivers/scsi/bfa/bfa_port_priv.h
index 40e256ec67f..c9ebe0426fa 100644
--- a/drivers/scsi/bfa/bfa_port_priv.h
+++ b/drivers/scsi/bfa/bfa_port_priv.h
@@ -75,8 +75,9 @@ struct bfa_fcport_s {
bfa_status_t stats_status; /* stats/statsclr status */
bfa_boolean_t stats_busy; /* outstanding stats/statsclr */
bfa_boolean_t stats_qfull;
+ u32 stats_reset_time; /* stats reset time stamp */
bfa_cb_pport_t stats_cbfn; /* driver callback function */
- void *stats_cbarg; /* *!< user callback arg */
+ void *stats_cbarg; /* user callback arg */
bfa_boolean_t diag_busy; /* diag busy status */
bfa_boolean_t beacon; /* port beacon status */
bfa_boolean_t link_e2e_beacon; /* link beacon status */
@@ -87,5 +88,7 @@ struct bfa_fcport_s {
/*
* public functions
*/
-void bfa_fcport_isr(struct bfa_s *bfa, struct bfi_msg_s *msg);
+void bfa_fcport_init(struct bfa_s *bfa);
+void bfa_fcport_isr(struct bfa_s *bfa, struct bfi_msg_s *msg);
+
#endif /* __BFA_PORT_PRIV_H__ */
diff --git a/drivers/scsi/bfa/bfa_priv.h b/drivers/scsi/bfa/bfa_priv.h
index be80fc7e1b0..bf4939b1676 100644
--- a/drivers/scsi/bfa/bfa_priv.h
+++ b/drivers/scsi/bfa/bfa_priv.h
@@ -37,7 +37,6 @@
void *bfad, struct bfa_iocfc_cfg_s *cfg, \
struct bfa_meminfo_s *meminfo, \
struct bfa_pcidev_s *pcidev); \
- static void bfa_ ## __mod ## _initdone(struct bfa_s *bfa); \
static void bfa_ ## __mod ## _detach(struct bfa_s *bfa); \
static void bfa_ ## __mod ## _start(struct bfa_s *bfa); \
static void bfa_ ## __mod ## _stop(struct bfa_s *bfa); \
@@ -47,7 +46,6 @@
struct bfa_module_s hal_mod_ ## __mod = { \
bfa_ ## __mod ## _meminfo, \
bfa_ ## __mod ## _attach, \
- bfa_ ## __mod ## _initdone, \
bfa_ ## __mod ## _detach, \
bfa_ ## __mod ## _start, \
bfa_ ## __mod ## _stop, \
@@ -69,7 +67,6 @@ struct bfa_module_s {
struct bfa_iocfc_cfg_s *cfg,
struct bfa_meminfo_s *meminfo,
struct bfa_pcidev_s *pcidev);
- void (*initdone) (struct bfa_s *bfa);
void (*detach) (struct bfa_s *bfa);
void (*start) (struct bfa_s *bfa);
void (*stop) (struct bfa_s *bfa);
diff --git a/drivers/scsi/bfa/bfa_rport.c b/drivers/scsi/bfa/bfa_rport.c
index 7c509fa244e..ccd0680f6f1 100644
--- a/drivers/scsi/bfa/bfa_rport.c
+++ b/drivers/scsi/bfa/bfa_rport.c
@@ -636,11 +636,6 @@ bfa_rport_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg,
}
static void
-bfa_rport_initdone(struct bfa_s *bfa)
-{
-}
-
-static void
bfa_rport_detach(struct bfa_s *bfa)
{
}
diff --git a/drivers/scsi/bfa/bfa_sgpg.c b/drivers/scsi/bfa/bfa_sgpg.c
index 279d8f9b890..ae452c42e40 100644
--- a/drivers/scsi/bfa/bfa_sgpg.c
+++ b/drivers/scsi/bfa/bfa_sgpg.c
@@ -94,11 +94,6 @@ bfa_sgpg_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg,
}
static void
-bfa_sgpg_initdone(struct bfa_s *bfa)
-{
-}
-
-static void
bfa_sgpg_detach(struct bfa_s *bfa)
{
}
diff --git a/drivers/scsi/bfa/bfa_uf.c b/drivers/scsi/bfa/bfa_uf.c
index 4b3c2417d18..b9a9a686ef6 100644
--- a/drivers/scsi/bfa/bfa_uf.c
+++ b/drivers/scsi/bfa/bfa_uf.c
@@ -170,11 +170,6 @@ bfa_uf_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg,
}
static void
-bfa_uf_initdone(struct bfa_s *bfa)
-{
-}
-
-static void
bfa_uf_detach(struct bfa_s *bfa)
{
}
@@ -256,7 +251,10 @@ uf_recv(struct bfa_s *bfa, struct bfi_uf_frm_rcvd_s *m)
(struct fchs_s *) buf, pld_w0);
}
- bfa_cb_queue(bfa, &uf->hcb_qe, __bfa_cb_uf_recv, uf);
+ if (bfa->fcs)
+ __bfa_cb_uf_recv(uf, BFA_TRUE);
+ else
+ bfa_cb_queue(bfa, &uf->hcb_qe, __bfa_cb_uf_recv, uf);
}
static void
diff --git a/drivers/scsi/bfa/bfad.c b/drivers/scsi/bfa/bfad.c
index d4fc4287ebd..915a29d6c7a 100644
--- a/drivers/scsi/bfa/bfad.c
+++ b/drivers/scsi/bfa/bfad.c
@@ -54,31 +54,62 @@ static int bfa_io_max_sge = BFAD_IO_MAX_SGE;
static int log_level = BFA_LOG_WARNING;
static int ioc_auto_recover = BFA_TRUE;
static int ipfc_enable = BFA_FALSE;
-static int ipfc_mtu = -1;
static int fdmi_enable = BFA_TRUE;
int bfa_lun_queue_depth = BFAD_LUN_QUEUE_DEPTH;
int bfa_linkup_delay = -1;
+int bfa_debugfs_enable = 1;
module_param(os_name, charp, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(os_name, "OS name of the hba host machine");
module_param(os_patch, charp, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(os_patch, "OS patch level of the hba host machine");
module_param(host_name, charp, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(host_name, "Hostname of the hba host machine");
module_param(num_rports, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(num_rports, "Max number of rports supported per port"
+ " (physical/logical), default=1024");
module_param(num_ios, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(num_ios, "Max number of ioim requests, default=2000");
module_param(num_tms, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(num_tms, "Max number of task im requests, default=128");
module_param(num_fcxps, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(num_fcxps, "Max number of fcxp requests, default=64");
module_param(num_ufbufs, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(num_ufbufs, "Max number of unsolicited frame buffers,"
+ " default=64");
module_param(reqq_size, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(reqq_size, "Max number of request queue elements,"
+ " default=256");
module_param(rspq_size, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(rspq_size, "Max number of response queue elements,"
+ " default=64");
module_param(num_sgpgs, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(num_sgpgs, "Number of scatter/gather pages, default=2048");
module_param(rport_del_timeout, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(rport_del_timeout, "Rport delete timeout, default=90 secs,"
+ " Range[>0]");
module_param(bfa_lun_queue_depth, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(bfa_lun_queue_depth, "Lun queue depth, default=32,"
+ " Range[>0]");
module_param(bfa_io_max_sge, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(bfa_io_max_sge, "Max io scatter/gather elements, default=255");
module_param(log_level, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(log_level, "Driver log level, default=3,"
+ " Range[Critical:1|Error:2|Warning:3|Info:4]");
module_param(ioc_auto_recover, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(ioc_auto_recover, "IOC auto recovery, default=1,"
+ " Range[off:0|on:1]");
module_param(ipfc_enable, int, S_IRUGO | S_IWUSR);
-module_param(ipfc_mtu, int, S_IRUGO | S_IWUSR);
-module_param(fdmi_enable, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(ipfc_enable, "Enable IPoFC, default=0, Range[off:0|on:1]");
module_param(bfa_linkup_delay, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(bfa_linkup_delay, "Link up delay, default=30 secs for boot"
+ " port. Otherwise Range[>0]");
+module_param(fdmi_enable, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(fdmi_enable, "Enables fdmi registration, default=1,"
+ " Range[false:0|true:1]");
+module_param(bfa_debugfs_enable, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(bfa_debugfs_enable, "Enables debugfs feature, default=1,"
+ " Range[false:0|true:1]");
/*
* Stores the module parm num_sgpgs value;
@@ -322,7 +353,31 @@ ext:
return rc;
}
+/**
+ * @brief
+ * FCS PBC VPORT Create
+ */
+void
+bfa_fcb_pbc_vport_create(struct bfad_s *bfad, struct bfi_pbc_vport_s pbc_vport)
+{
+
+ struct bfad_pcfg_s *pcfg;
+ pcfg = kzalloc(sizeof(struct bfad_pcfg_s), GFP_ATOMIC);
+ if (!pcfg) {
+ bfa_trc(bfad, 0);
+ return;
+ }
+
+ pcfg->port_cfg.roles = BFA_PORT_ROLE_FCP_IM;
+ pcfg->port_cfg.pwwn = pbc_vport.vp_pwwn;
+ pcfg->port_cfg.nwwn = pbc_vport.vp_nwwn;
+ pcfg->port_cfg.preboot_vp = BFA_TRUE;
+
+ list_add_tail(&pcfg->list_entry, &bfad->pbc_pcfg_list);
+
+ return;
+}
void
bfad_hal_mem_release(struct bfad_s *bfad)
@@ -481,10 +536,10 @@ ext:
*/
bfa_status_t
bfad_vport_create(struct bfad_s *bfad, u16 vf_id,
- struct bfa_port_cfg_s *port_cfg, struct device *dev)
+ struct bfa_port_cfg_s *port_cfg, struct device *dev)
{
struct bfad_vport_s *vport;
- int rc = BFA_STATUS_OK;
+ int rc = BFA_STATUS_OK;
unsigned long flags;
struct completion fcomp;
@@ -496,8 +551,12 @@ bfad_vport_create(struct bfad_s *bfad, u16 vf_id,
vport->drv_port.bfad = bfad;
spin_lock_irqsave(&bfad->bfad_lock, flags);
- rc = bfa_fcs_vport_create(&vport->fcs_vport, &bfad->bfa_fcs, vf_id,
- port_cfg, vport);
+ if (port_cfg->preboot_vp == BFA_TRUE)
+ rc = bfa_fcs_pbc_vport_create(&vport->fcs_vport,
+ &bfad->bfa_fcs, vf_id, port_cfg, vport);
+ else
+ rc = bfa_fcs_vport_create(&vport->fcs_vport,
+ &bfad->bfa_fcs, vf_id, port_cfg, vport);
spin_unlock_irqrestore(&bfad->bfad_lock, flags);
if (rc != BFA_STATUS_OK)
@@ -848,6 +907,10 @@ bfad_cfg_pport(struct bfad_s *bfad, enum bfa_port_role role)
bfad->pport.roles |= BFA_PORT_ROLE_FCP_IM;
}
+ /* Setup the debugfs node for this scsi_host */
+ if (bfa_debugfs_enable)
+ bfad_debugfs_init(&bfad->pport);
+
bfad->bfad_flags |= BFAD_CFG_PPORT_DONE;
out:
@@ -857,6 +920,10 @@ out:
void
bfad_uncfg_pport(struct bfad_s *bfad)
{
+ /* Remove the debugfs node for this scsi_host */
+ kfree(bfad->regdata);
+ bfad_debugfs_exit(&bfad->pport);
+
if ((bfad->pport.roles & BFA_PORT_ROLE_FCP_IPFC) && ipfc_enable) {
bfad_ipfc_port_delete(bfad, &bfad->pport);
bfad->pport.roles &= ~BFA_PORT_ROLE_FCP_IPFC;
@@ -884,6 +951,7 @@ bfa_status_t
bfad_start_ops(struct bfad_s *bfad)
{
int retval;
+ struct bfad_pcfg_s *pcfg, *pcfg_new;
/* PPORT FCS config */
bfad_fcs_port_cfg(bfad);
@@ -901,6 +969,27 @@ bfad_start_ops(struct bfad_s *bfad)
bfad_drv_start(bfad);
+ /* pbc vport creation */
+ list_for_each_entry_safe(pcfg, pcfg_new, &bfad->pbc_pcfg_list,
+ list_entry) {
+ struct fc_vport_identifiers vid;
+ struct fc_vport *fc_vport;
+
+ memset(&vid, 0, sizeof(vid));
+ vid.roles = FC_PORT_ROLE_FCP_INITIATOR;
+ vid.vport_type = FC_PORTTYPE_NPIV;
+ vid.disable = false;
+ vid.node_name = wwn_to_u64((u8 *)&pcfg->port_cfg.nwwn);
+ vid.port_name = wwn_to_u64((u8 *)&pcfg->port_cfg.pwwn);
+ fc_vport = fc_vport_create(bfad->pport.im_port->shost, 0, &vid);
+ if (!fc_vport)
+ printk(KERN_WARNING "bfad%d: failed to create pbc vport"
+ " %llx\n", bfad->inst_no, vid.port_name);
+ list_del(&pcfg->list_entry);
+ kfree(pcfg);
+
+ }
+
/*
* If bfa_linkup_delay is set to -1 default; try to retrive the
* value using the bfad_os_get_linkup_delay(); else use the
@@ -928,7 +1017,7 @@ out_cfg_pport_failure:
}
int
-bfad_worker (void *ptr)
+bfad_worker(void *ptr)
{
struct bfad_s *bfad;
unsigned long flags;
@@ -1031,6 +1120,7 @@ bfad_pci_probe(struct pci_dev *pdev, const struct pci_device_id *pid)
bfad->ref_count = 0;
bfad->pport.bfad = bfad;
+ INIT_LIST_HEAD(&bfad->pbc_pcfg_list);
bfad->bfad_tsk = kthread_create(bfad_worker, (void *) bfad, "%s",
"bfad_worker");
@@ -1172,6 +1262,14 @@ static struct pci_device_id bfad_id_table[] = {
.class = (PCI_CLASS_SERIAL_FIBER << 8),
.class_mask = ~0,
},
+ {
+ .vendor = BFA_PCI_VENDOR_ID_BROCADE,
+ .device = BFA_PCI_DEVICE_ID_CT_FC,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .class = (PCI_CLASS_SERIAL_FIBER << 8),
+ .class_mask = ~0,
+ },
{0, 0},
};
diff --git a/drivers/scsi/bfa/bfad_attr.c b/drivers/scsi/bfa/bfad_attr.c
index e477bfbfa7d..0818eb07ef8 100644
--- a/drivers/scsi/bfa/bfad_attr.c
+++ b/drivers/scsi/bfa/bfad_attr.c
@@ -373,47 +373,53 @@ bfad_im_vport_create(struct fc_vport *fc_vport, bool disable)
(struct bfad_im_port_s *) shost->hostdata[0];
struct bfad_s *bfad = im_port->bfad;
struct bfa_port_cfg_s port_cfg;
+ struct bfad_pcfg_s *pcfg;
int status = 0, rc;
unsigned long flags;
memset(&port_cfg, 0, sizeof(port_cfg));
-
- port_cfg.pwwn = wwn_to_u64((u8 *) &fc_vport->port_name);
- port_cfg.nwwn = wwn_to_u64((u8 *) &fc_vport->node_name);
-
+ u64_to_wwn(fc_vport->node_name, (u8 *)&port_cfg.nwwn);
+ u64_to_wwn(fc_vport->port_name, (u8 *)&port_cfg.pwwn);
if (strlen(vname) > 0)
strcpy((char *)&port_cfg.sym_name, vname);
-
port_cfg.roles = BFA_PORT_ROLE_FCP_IM;
- rc = bfad_vport_create(bfad, 0, &port_cfg, &fc_vport->dev);
+ spin_lock_irqsave(&bfad->bfad_lock, flags);
+ list_for_each_entry(pcfg, &bfad->pbc_pcfg_list, list_entry) {
+ if (port_cfg.pwwn == pcfg->port_cfg.pwwn) {
+ port_cfg.preboot_vp = pcfg->port_cfg.preboot_vp;
+ break;
+ }
+ }
+ spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+
+ rc = bfad_vport_create(bfad, 0, &port_cfg, &fc_vport->dev);
if (rc == BFA_STATUS_OK) {
- struct bfad_vport_s *vport;
+ struct bfad_vport_s *vport;
struct bfa_fcs_vport_s *fcs_vport;
struct Scsi_Host *vshost;
spin_lock_irqsave(&bfad->bfad_lock, flags);
fcs_vport = bfa_fcs_vport_lookup(&bfad->bfa_fcs, 0,
port_cfg.pwwn);
- if (fcs_vport == NULL) {
- spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+ spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+ if (fcs_vport == NULL)
return VPCERR_BAD_WWN;
- }
fc_vport_set_state(fc_vport, FC_VPORT_ACTIVE);
if (disable) {
+ spin_lock_irqsave(&bfad->bfad_lock, flags);
bfa_fcs_vport_stop(fcs_vport);
+ spin_unlock_irqrestore(&bfad->bfad_lock, flags);
fc_vport_set_state(fc_vport, FC_VPORT_DISABLED);
}
- spin_unlock_irqrestore(&bfad->bfad_lock, flags);
vport = fcs_vport->vport_drv;
vshost = vport->drv_port.im_port->shost;
- fc_host_node_name(vshost) = wwn_to_u64((u8 *) &port_cfg.nwwn);
- fc_host_port_name(vshost) = wwn_to_u64((u8 *) &port_cfg.pwwn);
+ fc_host_node_name(vshost) = wwn_to_u64((u8 *)&port_cfg.nwwn);
+ fc_host_port_name(vshost) = wwn_to_u64((u8 *)&port_cfg.pwwn);
fc_vport->dd_data = vport;
vport->drv_port.im_port->fc_vport = fc_vport;
-
} else if (rc == BFA_STATUS_INVALID_WWN)
return VPCERR_BAD_WWN;
else if (rc == BFA_STATUS_VPORT_EXISTS)
@@ -422,7 +428,7 @@ bfad_im_vport_create(struct fc_vport *fc_vport, bool disable)
return VPCERR_NO_FABRIC_SUPP;
else if (rc == BFA_STATUS_VPORT_WWN_BP)
return VPCERR_BAD_WWN;
- else
+ else
return FC_VPORT_FAILED;
return status;
@@ -449,7 +455,7 @@ bfad_im_vport_delete(struct fc_vport *fc_vport)
port = im_port->port;
vshost = vport->drv_port.im_port->shost;
- pwwn = wwn_to_u64((u8 *) &fc_host_port_name(vshost));
+ u64_to_wwn(fc_host_port_name(vshost), (u8 *)&pwwn);
spin_lock_irqsave(&bfad->bfad_lock, flags);
fcs_vport = bfa_fcs_vport_lookup(&bfad->bfa_fcs, 0, pwwn);
@@ -467,6 +473,12 @@ bfad_im_vport_delete(struct fc_vport *fc_vport)
rc = bfa_fcs_vport_delete(&vport->fcs_vport);
spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+ if (rc == BFA_STATUS_PBC) {
+ vport->drv_port.flags &= ~BFAD_PORT_DELETE;
+ vport->comp_del = NULL;
+ return -1;
+ }
+
wait_for_completion(vport->comp_del);
free_scsi_host:
@@ -490,7 +502,7 @@ bfad_im_vport_disable(struct fc_vport *fc_vport, bool disable)
vport = (struct bfad_vport_s *)fc_vport->dd_data;
bfad = vport->drv_port.bfad;
vshost = vport->drv_port.im_port->shost;
- pwwn = wwn_to_u64((u8 *) &fc_vport->port_name);
+ u64_to_wwn(fc_host_port_name(vshost), (u8 *)&pwwn);
spin_lock_irqsave(&bfad->bfad_lock, flags);
fcs_vport = bfa_fcs_vport_lookup(&bfad->bfa_fcs, 0, pwwn);
diff --git a/drivers/scsi/bfa/bfad_debugfs.c b/drivers/scsi/bfa/bfad_debugfs.c
new file mode 100644
index 00000000000..4b82f12aad6
--- /dev/null
+++ b/drivers/scsi/bfa/bfad_debugfs.c
@@ -0,0 +1,547 @@
+/*
+ * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) 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.
+ */
+
+#include <linux/debugfs.h>
+
+#include <bfad_drv.h>
+#include <bfad_im.h>
+
+/*
+ * BFA debufs interface
+ *
+ * To access the interface, debugfs file system should be mounted
+ * if not already mounted using:
+ * mount -t debugfs none /sys/kernel/debug
+ *
+ * BFA Hierarchy:
+ * - bfa/host#
+ * where the host number corresponds to the one under /sys/class/scsi_host/host#
+ *
+ * Debugging service available per host:
+ * fwtrc: To collect current firmware trace.
+ * drvtrc: To collect current driver trace
+ * fwsave: To collect last saved fw trace as a result of firmware crash.
+ * regwr: To write one word to chip register
+ * regrd: To read one or more words from chip register.
+ */
+
+struct bfad_debug_info {
+ char *debug_buffer;
+ void *i_private;
+ int buffer_len;
+};
+
+static int
+bfad_debugfs_open_drvtrc(struct inode *inode, struct file *file)
+{
+ struct bfad_port_s *port = inode->i_private;
+ struct bfad_s *bfad = port->bfad;
+ struct bfad_debug_info *debug;
+
+ debug = kzalloc(sizeof(struct bfad_debug_info), GFP_KERNEL);
+ if (!debug)
+ return -ENOMEM;
+
+ debug->debug_buffer = (void *) bfad->trcmod;
+ debug->buffer_len = sizeof(struct bfa_trc_mod_s);
+
+ file->private_data = debug;
+
+ return 0;
+}
+
+static int
+bfad_debugfs_open_fwtrc(struct inode *inode, struct file *file)
+{
+ struct bfad_port_s *port = inode->i_private;
+ struct bfad_s *bfad = port->bfad;
+ struct bfad_debug_info *fw_debug;
+ unsigned long flags;
+ int rc;
+
+ fw_debug = kzalloc(sizeof(struct bfad_debug_info), GFP_KERNEL);
+ if (!fw_debug)
+ return -ENOMEM;
+
+ fw_debug->buffer_len = sizeof(struct bfa_trc_mod_s);
+
+ fw_debug->debug_buffer = vmalloc(fw_debug->buffer_len);
+ if (!fw_debug->debug_buffer) {
+ kfree(fw_debug);
+ printk(KERN_INFO "bfad[%d]: Failed to allocate fwtrc buffer\n",
+ bfad->inst_no);
+ return -ENOMEM;
+ }
+
+ memset(fw_debug->debug_buffer, 0, fw_debug->buffer_len);
+
+ spin_lock_irqsave(&bfad->bfad_lock, flags);
+ rc = bfa_debug_fwtrc(&bfad->bfa,
+ fw_debug->debug_buffer,
+ &fw_debug->buffer_len);
+ spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+ if (rc != BFA_STATUS_OK) {
+ vfree(fw_debug->debug_buffer);
+ fw_debug->debug_buffer = NULL;
+ kfree(fw_debug);
+ printk(KERN_INFO "bfad[%d]: Failed to collect fwtrc\n",
+ bfad->inst_no);
+ return -ENOMEM;
+ }
+
+ file->private_data = fw_debug;
+
+ return 0;
+}
+
+static int
+bfad_debugfs_open_fwsave(struct inode *inode, struct file *file)
+{
+ struct bfad_port_s *port = inode->i_private;
+ struct bfad_s *bfad = port->bfad;
+ struct bfad_debug_info *fw_debug;
+ unsigned long flags;
+ int rc;
+
+ fw_debug = kzalloc(sizeof(struct bfad_debug_info), GFP_KERNEL);
+ if (!fw_debug)
+ return -ENOMEM;
+
+ fw_debug->buffer_len = sizeof(struct bfa_trc_mod_s);
+
+ fw_debug->debug_buffer = vmalloc(fw_debug->buffer_len);
+ if (!fw_debug->debug_buffer) {
+ kfree(fw_debug);
+ printk(KERN_INFO "bfad[%d]: Failed to allocate fwsave buffer\n",
+ bfad->inst_no);
+ return -ENOMEM;
+ }
+
+ memset(fw_debug->debug_buffer, 0, fw_debug->buffer_len);
+
+ spin_lock_irqsave(&bfad->bfad_lock, flags);
+ rc = bfa_debug_fwsave(&bfad->bfa,
+ fw_debug->debug_buffer,
+ &fw_debug->buffer_len);
+ spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+ if (rc != BFA_STATUS_OK) {
+ vfree(fw_debug->debug_buffer);
+ fw_debug->debug_buffer = NULL;
+ kfree(fw_debug);
+ printk(KERN_INFO "bfad[%d]: Failed to collect fwsave\n",
+ bfad->inst_no);
+ return -ENOMEM;
+ }
+
+ file->private_data = fw_debug;
+
+ return 0;
+}
+
+static int
+bfad_debugfs_open_reg(struct inode *inode, struct file *file)
+{
+ struct bfad_debug_info *reg_debug;
+
+ reg_debug = kzalloc(sizeof(struct bfad_debug_info), GFP_KERNEL);
+ if (!reg_debug)
+ return -ENOMEM;
+
+ reg_debug->i_private = inode->i_private;
+
+ file->private_data = reg_debug;
+
+ return 0;
+}
+
+/* Changes the current file position */
+static loff_t
+bfad_debugfs_lseek(struct file *file, loff_t offset, int orig)
+{
+ struct bfad_debug_info *debug;
+ loff_t pos = file->f_pos;
+
+ debug = file->private_data;
+
+ switch (orig) {
+ case 0:
+ file->f_pos = offset;
+ break;
+ case 1:
+ file->f_pos += offset;
+ break;
+ case 2:
+ file->f_pos = debug->buffer_len - offset;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (file->f_pos < 0 || file->f_pos > debug->buffer_len) {
+ file->f_pos = pos;
+ return -EINVAL;
+ }
+
+ return file->f_pos;
+}
+
+static ssize_t
+bfad_debugfs_read(struct file *file, char __user *buf,
+ size_t nbytes, loff_t *pos)
+{
+ struct bfad_debug_info *debug = file->private_data;
+
+ if (!debug || !debug->debug_buffer)
+ return 0;
+
+ return memory_read_from_buffer(buf, nbytes, pos,
+ debug->debug_buffer, debug->buffer_len);
+}
+
+#define BFA_REG_CT_ADDRSZ (0x40000)
+#define BFA_REG_CB_ADDRSZ (0x20000)
+#define BFA_REG_ADDRSZ(__bfa) \
+ ((bfa_ioc_devid(&(__bfa)->ioc) == BFA_PCI_DEVICE_ID_CT) ? \
+ BFA_REG_CT_ADDRSZ : BFA_REG_CB_ADDRSZ)
+#define BFA_REG_ADDRMSK(__bfa) ((uint32_t)(BFA_REG_ADDRSZ(__bfa) - 1))
+
+static bfa_status_t
+bfad_reg_offset_check(struct bfa_s *bfa, u32 offset, u32 len)
+{
+ u8 area;
+
+ /* check [16:15] */
+ area = (offset >> 15) & 0x7;
+ if (area == 0) {
+ /* PCIe core register */
+ if ((offset + (len<<2)) > 0x8000) /* 8k dwords or 32KB */
+ return BFA_STATUS_EINVAL;
+ } else if (area == 0x1) {
+ /* CB 32 KB memory page */
+ if ((offset + (len<<2)) > 0x10000) /* 8k dwords or 32KB */
+ return BFA_STATUS_EINVAL;
+ } else {
+ /* CB register space 64KB */
+ if ((offset + (len<<2)) > BFA_REG_ADDRMSK(bfa))
+ return BFA_STATUS_EINVAL;
+ }
+ return BFA_STATUS_OK;
+}
+
+static ssize_t
+bfad_debugfs_read_regrd(struct file *file, char __user *buf,
+ size_t nbytes, loff_t *pos)
+{
+ struct bfad_debug_info *regrd_debug = file->private_data;
+ struct bfad_port_s *port = (struct bfad_port_s *)regrd_debug->i_private;
+ struct bfad_s *bfad = port->bfad;
+ ssize_t rc;
+
+ if (!bfad->regdata)
+ return 0;
+
+ rc = memory_read_from_buffer(buf, nbytes, pos,
+ bfad->regdata, bfad->reglen);
+
+ if ((*pos + nbytes) >= bfad->reglen) {
+ kfree(bfad->regdata);
+ bfad->regdata = NULL;
+ bfad->reglen = 0;
+ }
+
+ return rc;
+}
+
+static ssize_t
+bfad_debugfs_write_regrd(struct file *file, const char __user *buf,
+ size_t nbytes, loff_t *ppos)
+{
+ struct bfad_debug_info *regrd_debug = file->private_data;
+ struct bfad_port_s *port = (struct bfad_port_s *)regrd_debug->i_private;
+ struct bfad_s *bfad = port->bfad;
+ struct bfa_s *bfa = &bfad->bfa;
+ struct bfa_ioc_s *ioc = &bfa->ioc;
+ int addr, len, rc, i;
+ u32 *regbuf;
+ void __iomem *rb, *reg_addr;
+ unsigned long flags;
+
+ rc = sscanf(buf, "%x:%x", &addr, &len);
+ if (rc < 2) {
+ printk(KERN_INFO
+ "bfad[%d]: %s failed to read user buf\n",
+ bfad->inst_no, __func__);
+ return -EINVAL;
+ }
+
+ kfree(bfad->regdata);
+ bfad->regdata = NULL;
+ bfad->reglen = 0;
+
+ bfad->regdata = kzalloc(len << 2, GFP_KERNEL);
+ if (!bfad->regdata) {
+ printk(KERN_INFO "bfad[%d]: Failed to allocate regrd buffer\n",
+ bfad->inst_no);
+ return -ENOMEM;
+ }
+
+ bfad->reglen = len << 2;
+ rb = bfa_ioc_bar0(ioc);
+ addr &= BFA_REG_ADDRMSK(bfa);
+
+ /* offset and len sanity check */
+ rc = bfad_reg_offset_check(bfa, addr, len);
+ if (rc) {
+ printk(KERN_INFO "bfad[%d]: Failed reg offset check\n",
+ bfad->inst_no);
+ kfree(bfad->regdata);
+ bfad->regdata = NULL;
+ bfad->reglen = 0;
+ return -EINVAL;
+ }
+
+ reg_addr = rb + addr;
+ regbuf = (u32 *)bfad->regdata;
+ spin_lock_irqsave(&bfad->bfad_lock, flags);
+ for (i = 0; i < len; i++) {
+ *regbuf = bfa_reg_read(reg_addr);
+ regbuf++;
+ reg_addr += sizeof(u32);
+ }
+ spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+
+ return nbytes;
+}
+
+static ssize_t
+bfad_debugfs_write_regwr(struct file *file, const char __user *buf,
+ size_t nbytes, loff_t *ppos)
+{
+ struct bfad_debug_info *debug = file->private_data;
+ struct bfad_port_s *port = (struct bfad_port_s *)debug->i_private;
+ struct bfad_s *bfad = port->bfad;
+ struct bfa_s *bfa = &bfad->bfa;
+ struct bfa_ioc_s *ioc = &bfa->ioc;
+ int addr, val, rc;
+ void __iomem *reg_addr;
+ unsigned long flags;
+
+ rc = sscanf(buf, "%x:%x", &addr, &val);
+ if (rc < 2) {
+ printk(KERN_INFO
+ "bfad[%d]: %s failed to read user buf\n",
+ bfad->inst_no, __func__);
+ return -EINVAL;
+ }
+
+ addr &= BFA_REG_ADDRMSK(bfa); /* offset only 17 bit and word align */
+
+ /* offset and len sanity check */
+ rc = bfad_reg_offset_check(bfa, addr, 1);
+ if (rc) {
+ printk(KERN_INFO
+ "bfad[%d]: Failed reg offset check\n",
+ bfad->inst_no);
+ return -EINVAL;
+ }
+
+ reg_addr = (uint32_t *) ((uint8_t *) bfa_ioc_bar0(ioc) + addr);
+ spin_lock_irqsave(&bfad->bfad_lock, flags);
+ bfa_reg_write(reg_addr, val);
+ spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+
+ return nbytes;
+}
+
+static int
+bfad_debugfs_release(struct inode *inode, struct file *file)
+{
+ struct bfad_debug_info *debug = file->private_data;
+
+ if (!debug)
+ return 0;
+
+ file->private_data = NULL;
+ kfree(debug);
+ return 0;
+}
+
+static int
+bfad_debugfs_release_fwtrc(struct inode *inode, struct file *file)
+{
+ struct bfad_debug_info *fw_debug = file->private_data;
+
+ if (!fw_debug)
+ return 0;
+
+ if (fw_debug->debug_buffer)
+ vfree(fw_debug->debug_buffer);
+
+ file->private_data = NULL;
+ kfree(fw_debug);
+ return 0;
+}
+
+static const struct file_operations bfad_debugfs_op_drvtrc = {
+ .owner = THIS_MODULE,
+ .open = bfad_debugfs_open_drvtrc,
+ .llseek = bfad_debugfs_lseek,
+ .read = bfad_debugfs_read,
+ .release = bfad_debugfs_release,
+};
+
+static const struct file_operations bfad_debugfs_op_fwtrc = {
+ .owner = THIS_MODULE,
+ .open = bfad_debugfs_open_fwtrc,
+ .llseek = bfad_debugfs_lseek,
+ .read = bfad_debugfs_read,
+ .release = bfad_debugfs_release_fwtrc,
+};
+
+static const struct file_operations bfad_debugfs_op_fwsave = {
+ .owner = THIS_MODULE,
+ .open = bfad_debugfs_open_fwsave,
+ .llseek = bfad_debugfs_lseek,
+ .read = bfad_debugfs_read,
+ .release = bfad_debugfs_release_fwtrc,
+};
+
+static const struct file_operations bfad_debugfs_op_regrd = {
+ .owner = THIS_MODULE,
+ .open = bfad_debugfs_open_reg,
+ .llseek = bfad_debugfs_lseek,
+ .read = bfad_debugfs_read_regrd,
+ .write = bfad_debugfs_write_regrd,
+ .release = bfad_debugfs_release,
+};
+
+static const struct file_operations bfad_debugfs_op_regwr = {
+ .owner = THIS_MODULE,
+ .open = bfad_debugfs_open_reg,
+ .llseek = bfad_debugfs_lseek,
+ .write = bfad_debugfs_write_regwr,
+ .release = bfad_debugfs_release,
+};
+
+struct bfad_debugfs_entry {
+ const char *name;
+ mode_t mode;
+ const struct file_operations *fops;
+};
+
+static const struct bfad_debugfs_entry bfad_debugfs_files[] = {
+ { "drvtrc", S_IFREG|S_IRUGO, &bfad_debugfs_op_drvtrc, },
+ { "fwtrc", S_IFREG|S_IRUGO, &bfad_debugfs_op_fwtrc, },
+ { "fwsave", S_IFREG|S_IRUGO, &bfad_debugfs_op_fwsave, },
+ { "regrd", S_IFREG|S_IRUGO|S_IWUSR, &bfad_debugfs_op_regrd, },
+ { "regwr", S_IFREG|S_IWUSR, &bfad_debugfs_op_regwr, },
+};
+
+static struct dentry *bfa_debugfs_root;
+static atomic_t bfa_debugfs_port_count;
+
+inline void
+bfad_debugfs_init(struct bfad_port_s *port)
+{
+ struct bfad_im_port_s *im_port = port->im_port;
+ struct bfad_s *bfad = im_port->bfad;
+ struct Scsi_Host *shost = im_port->shost;
+ const struct bfad_debugfs_entry *file;
+ char name[16];
+ int i;
+
+ if (!bfa_debugfs_enable)
+ return;
+
+ /* Setup the BFA debugfs root directory*/
+ if (!bfa_debugfs_root) {
+ bfa_debugfs_root = debugfs_create_dir("bfa", NULL);
+ atomic_set(&bfa_debugfs_port_count, 0);
+ if (!bfa_debugfs_root) {
+ printk(KERN_WARNING
+ "BFA debugfs root dir creation failed\n");
+ goto err;
+ }
+ }
+
+ /*
+ * Setup the host# directory for the port,
+ * corresponds to the scsi_host num of this port.
+ */
+ snprintf(name, sizeof(name), "host%d", shost->host_no);
+ if (!port->port_debugfs_root) {
+ port->port_debugfs_root =
+ debugfs_create_dir(name, bfa_debugfs_root);
+ if (!port->port_debugfs_root) {
+ printk(KERN_WARNING
+ "BFA host root dir creation failed\n");
+ goto err;
+ }
+
+ atomic_inc(&bfa_debugfs_port_count);
+
+ for (i = 0; i < ARRAY_SIZE(bfad_debugfs_files); i++) {
+ file = &bfad_debugfs_files[i];
+ bfad->bfad_dentry_files[i] =
+ debugfs_create_file(file->name,
+ file->mode,
+ port->port_debugfs_root,
+ port,
+ file->fops);
+ if (!bfad->bfad_dentry_files[i]) {
+ printk(KERN_WARNING
+ "BFA host%d: create %s entry failed\n",
+ shost->host_no, file->name);
+ goto err;
+ }
+ }
+ }
+
+err:
+ return;
+}
+
+inline void
+bfad_debugfs_exit(struct bfad_port_s *port)
+{
+ struct bfad_im_port_s *im_port = port->im_port;
+ struct bfad_s *bfad = im_port->bfad;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(bfad_debugfs_files); i++) {
+ if (bfad->bfad_dentry_files[i]) {
+ debugfs_remove(bfad->bfad_dentry_files[i]);
+ bfad->bfad_dentry_files[i] = NULL;
+ }
+ }
+
+ /*
+ * Remove the host# directory for the port,
+ * corresponds to the scsi_host num of this port.
+ */
+ if (port->port_debugfs_root) {
+ debugfs_remove(port->port_debugfs_root);
+ port->port_debugfs_root = NULL;
+ atomic_dec(&bfa_debugfs_port_count);
+ }
+
+ /* Remove the BFA debugfs root directory */
+ if (atomic_read(&bfa_debugfs_port_count) == 0) {
+ debugfs_remove(bfa_debugfs_root);
+ bfa_debugfs_root = NULL;
+ }
+}
diff --git a/drivers/scsi/bfa/bfad_drv.h b/drivers/scsi/bfa/bfad_drv.h
index 6c920c1b53a..465b8b86ec9 100644
--- a/drivers/scsi/bfa/bfad_drv.h
+++ b/drivers/scsi/bfa/bfad_drv.h
@@ -46,7 +46,7 @@
#ifdef BFA_DRIVER_VERSION
#define BFAD_DRIVER_VERSION BFA_DRIVER_VERSION
#else
-#define BFAD_DRIVER_VERSION "2.1.2.1"
+#define BFAD_DRIVER_VERSION "2.2.2.1"
#endif
@@ -111,6 +111,9 @@ struct bfad_port_s {
struct bfad_im_port_s *im_port; /* IM specific data */
struct bfad_tm_port_s *tm_port; /* TM specific data */
struct bfad_ipfc_port_s *ipfc_port; /* IPFC specific data */
+
+ /* port debugfs specific data */
+ struct dentry *port_debugfs_root;
};
/*
@@ -120,6 +123,8 @@ struct bfad_vport_s {
struct bfad_port_s drv_port;
struct bfa_fcs_vport_s fcs_vport;
struct completion *comp_del;
+ struct list_head list_entry;
+ struct bfa_port_cfg_s port_cfg;
};
/*
@@ -139,18 +144,6 @@ struct bfad_cfg_param_s {
u32 binding_method;
};
-union bfad_tmp_buf {
- /* From struct bfa_adapter_attr_s */
- char manufacturer[BFA_ADAPTER_MFG_NAME_LEN];
- char serial_num[BFA_ADAPTER_SERIAL_NUM_LEN];
- char model[BFA_ADAPTER_MODEL_NAME_LEN];
- char fw_ver[BFA_VERSION_LEN];
- char optrom_ver[BFA_VERSION_LEN];
-
- /* From struct bfa_ioc_pci_attr_s */
- u8 chip_rev[BFA_IOC_CHIP_REV_LEN]; /* chip revision */
-};
-
/*
* BFAD (PCI function) data structure
*/
@@ -193,8 +186,18 @@ struct bfad_s {
struct bfa_plog_s plog_buf;
int ref_count;
bfa_boolean_t ipfc_enabled;
- union bfad_tmp_buf tmp_buf;
struct fc_host_statistics link_stats;
+ struct list_head pbc_pcfg_list;
+ atomic_t wq_reqcnt;
+ /* debugfs specific data */
+ char *regdata;
+ u32 reglen;
+ struct dentry *bfad_dentry_files[5];
+};
+
+struct bfad_pcfg_s {
+ struct list_head list_entry;
+ struct bfa_port_cfg_s port_cfg;
};
/*
@@ -280,7 +283,9 @@ void bfad_drv_uninit(struct bfad_s *bfad);
void bfad_drv_log_level_set(struct bfad_s *bfad);
bfa_status_t bfad_fc4_module_init(void);
void bfad_fc4_module_exit(void);
-int bfad_worker (void *ptr);
+int bfad_worker(void *ptr);
+void bfad_debugfs_init(struct bfad_port_s *port);
+void bfad_debugfs_exit(struct bfad_port_s *port);
void bfad_pci_remove(struct pci_dev *pdev);
int bfad_pci_probe(struct pci_dev *pdev, const struct pci_device_id *pid);
@@ -293,6 +298,7 @@ extern struct list_head bfad_list;
extern int bfa_lun_queue_depth;
extern int bfad_supported_fc4s;
extern int bfa_linkup_delay;
+extern int bfa_debugfs_enable;
extern struct mutex bfad_mutex;
#endif /* __BFAD_DRV_H__ */
diff --git a/drivers/scsi/bfa/bfad_fwimg.c b/drivers/scsi/bfa/bfad_fwimg.c
index 2ad65f275a9..1baca1a1208 100644
--- a/drivers/scsi/bfa/bfad_fwimg.c
+++ b/drivers/scsi/bfa/bfad_fwimg.c
@@ -33,16 +33,20 @@
#include <bfa_fwimg_priv.h>
#include <bfa.h>
-u32 bfi_image_ct_size;
-u32 bfi_image_cb_size;
-u32 *bfi_image_ct;
-u32 *bfi_image_cb;
+u32 bfi_image_ct_fc_size;
+u32 bfi_image_ct_cna_size;
+u32 bfi_image_cb_fc_size;
+u32 *bfi_image_ct_fc;
+u32 *bfi_image_ct_cna;
+u32 *bfi_image_cb_fc;
-#define BFAD_FW_FILE_CT "ctfw.bin"
-#define BFAD_FW_FILE_CB "cbfw.bin"
-MODULE_FIRMWARE(BFAD_FW_FILE_CT);
-MODULE_FIRMWARE(BFAD_FW_FILE_CB);
+#define BFAD_FW_FILE_CT_FC "ctfw_fc.bin"
+#define BFAD_FW_FILE_CT_CNA "ctfw_cna.bin"
+#define BFAD_FW_FILE_CB_FC "cbfw_fc.bin"
+MODULE_FIRMWARE(BFAD_FW_FILE_CT_FC);
+MODULE_FIRMWARE(BFAD_FW_FILE_CT_CNA);
+MODULE_FIRMWARE(BFAD_FW_FILE_CB_FC);
u32 *
bfad_read_firmware(struct pci_dev *pdev, u32 **bfi_image,
@@ -74,24 +78,54 @@ error:
u32 *
bfad_get_firmware_buf(struct pci_dev *pdev)
{
- if (pdev->device == BFA_PCI_DEVICE_ID_CT) {
- if (bfi_image_ct_size == 0)
- bfad_read_firmware(pdev, &bfi_image_ct,
- &bfi_image_ct_size, BFAD_FW_FILE_CT);
- return bfi_image_ct;
+ if (pdev->device == BFA_PCI_DEVICE_ID_CT_FC) {
+ if (bfi_image_ct_fc_size == 0)
+ bfad_read_firmware(pdev, &bfi_image_ct_fc,
+ &bfi_image_ct_fc_size, BFAD_FW_FILE_CT_FC);
+ return bfi_image_ct_fc;
+ } else if (pdev->device == BFA_PCI_DEVICE_ID_CT) {
+ if (bfi_image_ct_cna_size == 0)
+ bfad_read_firmware(pdev, &bfi_image_ct_cna,
+ &bfi_image_ct_cna_size, BFAD_FW_FILE_CT_CNA);
+ return bfi_image_ct_cna;
} else {
- if (bfi_image_cb_size == 0)
- bfad_read_firmware(pdev, &bfi_image_cb,
- &bfi_image_cb_size, BFAD_FW_FILE_CB);
- return bfi_image_cb;
+ if (bfi_image_cb_fc_size == 0)
+ bfad_read_firmware(pdev, &bfi_image_cb_fc,
+ &bfi_image_cb_fc_size, BFAD_FW_FILE_CB_FC);
+ return bfi_image_cb_fc;
}
}
u32 *
-bfi_image_ct_get_chunk(u32 off)
-{ return (u32 *)(bfi_image_ct + off); }
+bfi_image_ct_fc_get_chunk(u32 off)
+{ return (u32 *)(bfi_image_ct_fc + off); }
u32 *
-bfi_image_cb_get_chunk(u32 off)
-{ return (u32 *)(bfi_image_cb + off); }
+bfi_image_ct_cna_get_chunk(u32 off)
+{ return (u32 *)(bfi_image_ct_cna + off); }
+u32 *
+bfi_image_cb_fc_get_chunk(u32 off)
+{ return (u32 *)(bfi_image_cb_fc + off); }
+
+uint32_t *
+bfi_image_get_chunk(int type, uint32_t off)
+{
+ switch (type) {
+ case BFI_IMAGE_CT_FC: return bfi_image_ct_fc_get_chunk(off); break;
+ case BFI_IMAGE_CT_CNA: return bfi_image_ct_cna_get_chunk(off); break;
+ case BFI_IMAGE_CB_FC: return bfi_image_cb_fc_get_chunk(off); break;
+ default: return 0; break;
+ }
+}
+
+uint32_t
+bfi_image_get_size(int type)
+{
+ switch (type) {
+ case BFI_IMAGE_CT_FC: return bfi_image_ct_fc_size; break;
+ case BFI_IMAGE_CT_CNA: return bfi_image_ct_cna_size; break;
+ case BFI_IMAGE_CB_FC: return bfi_image_cb_fc_size; break;
+ default: return 0; break;
+ }
+}
diff --git a/drivers/scsi/bfa/bfad_im.c b/drivers/scsi/bfa/bfad_im.c
index 5b7cf539e50..678120b7046 100644
--- a/drivers/scsi/bfa/bfad_im.c
+++ b/drivers/scsi/bfa/bfad_im.c
@@ -554,7 +554,7 @@ bfad_im_scsi_host_alloc(struct bfad_s *bfad, struct bfad_im_port_s *im_port,
im_port->shost->transportt =
bfad_im_scsi_vport_transport_template;
- error = scsi_add_host(im_port->shost, dev);
+ error = scsi_add_host_with_dma(im_port->shost, dev, &bfad->pcidev->dev);
if (error) {
printk(KERN_WARNING "scsi_add_host failure %d\n", error);
goto out_fc_rel;
@@ -567,6 +567,7 @@ bfad_im_scsi_host_alloc(struct bfad_s *bfad, struct bfad_im_port_s *im_port,
out_fc_rel:
scsi_host_put(im_port->shost);
+ im_port->shost = NULL;
out_free_idr:
mutex_lock(&bfad_mutex);
idr_remove(&bfad_im_port_index, im_port->idr_id);
@@ -597,10 +598,12 @@ bfad_im_port_delete_handler(struct work_struct *work)
{
struct bfad_im_port_s *im_port =
container_of(work, struct bfad_im_port_s, port_delete_work);
+ struct bfad_s *bfad = im_port->bfad;
if (im_port->port->pvb_type != BFAD_PORT_PHYS_BASE) {
im_port->flags |= BFAD_PORT_DELETE;
fc_vport_terminate(im_port->fc_vport);
+ atomic_dec(&bfad->wq_reqcnt);
}
}
@@ -633,8 +636,11 @@ bfad_im_port_delete(struct bfad_s *bfad, struct bfad_port_s *port)
{
struct bfad_im_port_s *im_port = port->im_port;
- queue_work(bfad->im->drv_workq,
+ if (im_port->port->pvb_type != BFAD_PORT_PHYS_BASE) {
+ atomic_inc(&bfad->wq_reqcnt);
+ queue_work(bfad->im->drv_workq,
&im_port->port_delete_work);
+ }
}
void
@@ -695,12 +701,27 @@ void
bfad_im_probe_undo(struct bfad_s *bfad)
{
if (bfad->im) {
+ while (atomic_read(&bfad->wq_reqcnt)) {
+ printk(KERN_INFO "bfa %s: waiting workq processing,"
+ " wq_reqcnt:%x\n", bfad->pci_name,
+ atomic_read(&bfad->wq_reqcnt));
+ schedule_timeout_uninterruptible(HZ);
+ }
bfad_os_destroy_workq(bfad->im);
kfree(bfad->im);
bfad->im = NULL;
}
}
+/**
+ * Call back function to handle IO redirection state change
+ */
+void
+bfa_cb_ioredirect_state_change(void *hcb_bfad, bfa_boolean_t ioredirect)
+{
+ /* Do nothing */
+}
+
struct Scsi_Host *
bfad_os_scsi_host_alloc(struct bfad_im_port_s *im_port, struct bfad_s *bfad)
{
@@ -1204,9 +1225,9 @@ int
bfad_os_get_linkup_delay(struct bfad_s *bfad)
{
- u8 nwwns = 0;
- wwn_t *wwns;
- int ldelay;
+ u8 nwwns = 0;
+ wwn_t wwns[BFA_PREBOOT_BOOTLUN_MAX];
+ int ldelay;
/*
* Querying for the boot target port wwns
@@ -1215,7 +1236,7 @@ bfad_os_get_linkup_delay(struct bfad_s *bfad)
* else => local boot machine set bfa_linkup_delay = 10
*/
- bfa_iocfc_get_bootwwns(&bfad->bfa, &nwwns, &wwns);
+ bfa_iocfc_get_bootwwns(&bfad->bfa, &nwwns, wwns);
if (nwwns > 0) {
/* If boot over SAN; linkup_delay = 30sec */
diff --git a/drivers/scsi/bfa/bfad_im_compat.h b/drivers/scsi/bfa/bfad_im_compat.h
index b36be15044a..0a122abbbe8 100644
--- a/drivers/scsi/bfa/bfad_im_compat.h
+++ b/drivers/scsi/bfa/bfad_im_compat.h
@@ -18,9 +18,6 @@
#ifndef __BFAD_IM_COMPAT_H__
#define __BFAD_IM_COMPAT_H__
-extern u32 *bfi_image_buf;
-extern u32 bfi_image_size;
-
extern struct device_attribute *bfad_im_host_attrs[];
extern struct device_attribute *bfad_im_vport_attrs[];
@@ -37,10 +34,12 @@ bfad_load_fwimg(struct pci_dev *pdev)
static inline void
bfad_free_fwimg(void)
{
- if (bfi_image_ct_size && bfi_image_ct)
- vfree(bfi_image_ct);
- if (bfi_image_cb_size && bfi_image_cb)
- vfree(bfi_image_cb);
+ if (bfi_image_ct_fc_size && bfi_image_ct_fc)
+ vfree(bfi_image_ct_fc);
+ if (bfi_image_ct_cna_size && bfi_image_ct_cna)
+ vfree(bfi_image_ct_cna);
+ if (bfi_image_cb_fc_size && bfi_image_cb_fc)
+ vfree(bfi_image_cb_fc);
}
#endif
diff --git a/drivers/scsi/bfa/bfad_intr.c b/drivers/scsi/bfa/bfad_intr.c
index 2b7dbecbebc..56a351584f0 100644
--- a/drivers/scsi/bfa/bfad_intr.c
+++ b/drivers/scsi/bfa/bfad_intr.c
@@ -26,7 +26,11 @@ BFA_TRC_FILE(LDRV, INTR);
static int msix_disable_cb;
static int msix_disable_ct;
module_param(msix_disable_cb, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(msix_disable_cb, "Disable MSIX for Brocade-415/425/815/825"
+ " cards, default=0, Range[false:0|true:1]");
module_param(msix_disable_ct, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(msix_disable_ct, "Disable MSIX for Brocade-1010/1020/804"
+ " cards, default=0, Range[false:0|true:1]");
/**
* Line based interrupt handler.
*/
@@ -151,8 +155,8 @@ bfad_setup_intr(struct bfad_s *bfad)
/* Set up the msix entry table */
bfad_init_msix_entry(bfad, msix_entries, mask, max_bit);
- if ((pdev->device == BFA_PCI_DEVICE_ID_CT && !msix_disable_ct) ||
- (pdev->device != BFA_PCI_DEVICE_ID_CT && !msix_disable_cb)) {
+ if ((bfa_asic_id_ct(pdev->device) && !msix_disable_ct) ||
+ (!bfa_asic_id_ct(pdev->device) && !msix_disable_cb)) {
error = pci_enable_msix(bfad->pcidev, msix_entries, bfad->nvec);
if (error) {
diff --git a/drivers/scsi/bfa/fabric.c b/drivers/scsi/bfa/fabric.c
index 8166e9745ec..ddd4ba9317e 100644
--- a/drivers/scsi/bfa/fabric.c
+++ b/drivers/scsi/bfa/fabric.c
@@ -789,7 +789,7 @@ bfa_fcs_fabric_delete(struct bfa_fcs_fabric_s *fabric)
list_for_each_safe(qe, qen, &fabric->vport_q) {
vport = (struct bfa_fcs_vport_s *)qe;
- bfa_fcs_vport_delete(vport);
+ bfa_fcs_vport_fcs_delete(vport);
}
bfa_fcs_port_delete(&fabric->bport);
@@ -1027,6 +1027,32 @@ bfa_fcs_fabric_vport_count(struct bfa_fcs_fabric_s *fabric)
return fabric->num_vports;
}
+/*
+ * Get OUI of the attached switch.
+ *
+ * Note : Use of this function should be avoided as much as possible.
+ * This function should be used only if there is any requirement
+ * to check for FOS version below 6.3.
+ * To check if the attached fabric is a brocade fabric, use
+ * bfa_lps_is_brcd_fabric() which works for FOS versions 6.3
+ * or above only.
+ */
+
+u16
+bfa_fcs_fabric_get_switch_oui(struct bfa_fcs_fabric_s *fabric)
+{
+ wwn_t fab_nwwn;
+ u8 *tmp;
+ u16 oui;
+
+ fab_nwwn = bfa_lps_get_peer_nwwn(fabric->lps);
+
+ tmp = (uint8_t *)&fab_nwwn;
+ oui = (tmp[3] << 8) | tmp[4];
+
+ return oui;
+}
+
/**
* Unsolicited frame receive handling.
*/
@@ -1271,6 +1297,22 @@ bfa_fcs_fabric_set_fabric_name(struct bfa_fcs_fabric_s *fabric,
}
/**
+ *
+ * @param[in] fabric - fabric
+ * @param[in] node_symname -
+ * Caller allocated buffer to receive the symbolic name
+ *
+ * @return - none
+ */
+void
+bfa_fcs_get_sym_name(const struct bfa_fcs_s *fcs, char *node_symname)
+{
+ bfa_os_memcpy(node_symname,
+ fcs->fabric.bport.port_cfg.sym_name.symname,
+ BFA_SYMNAME_MAXLEN);
+}
+
+/**
* Not used by FCS.
*/
void
diff --git a/drivers/scsi/bfa/fcpim.c b/drivers/scsi/bfa/fcpim.c
index 8ae4a2cfa85..6b8976ad22f 100644
--- a/drivers/scsi/bfa/fcpim.c
+++ b/drivers/scsi/bfa/fcpim.c
@@ -110,6 +110,7 @@ bfa_fcs_itnim_sm_offline(struct bfa_fcs_itnim_s *itnim,
switch (event) {
case BFA_FCS_ITNIM_SM_ONLINE:
bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_prli_send);
+ itnim->prli_retries = 0;
bfa_fcs_itnim_send_prli(itnim, NULL);
break;
@@ -174,8 +175,12 @@ bfa_fcs_itnim_sm_prli(struct bfa_fcs_itnim_s *itnim,
switch (event) {
case BFA_FCS_ITNIM_SM_RSP_OK:
- bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_hcb_online);
- bfa_itnim_online(itnim->bfa_itnim, itnim->seq_rec);
+ if (itnim->rport->scsi_function == BFA_RPORT_INITIATOR) {
+ bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_initiator);
+ } else {
+ bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_hcb_online);
+ bfa_itnim_online(itnim->bfa_itnim, itnim->seq_rec);
+ }
break;
case BFA_FCS_ITNIM_SM_RSP_ERROR:
@@ -193,9 +198,7 @@ bfa_fcs_itnim_sm_prli(struct bfa_fcs_itnim_s *itnim,
case BFA_FCS_ITNIM_SM_INITIATOR:
bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_initiator);
- /*
- * dont discard fcxp. accept will reach same state
- */
+ bfa_fcxp_discard(itnim->fcxp);
break;
case BFA_FCS_ITNIM_SM_DELETE:
@@ -218,8 +221,16 @@ bfa_fcs_itnim_sm_prli_retry(struct bfa_fcs_itnim_s *itnim,
switch (event) {
case BFA_FCS_ITNIM_SM_TIMEOUT:
- bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_prli_send);
- bfa_fcs_itnim_send_prli(itnim, NULL);
+ if (itnim->prli_retries < BFA_FCS_RPORT_MAX_RETRIES) {
+ itnim->prli_retries++;
+ bfa_trc(itnim->fcs, itnim->prli_retries);
+ bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_prli_send);
+ bfa_fcs_itnim_send_prli(itnim, NULL);
+ } else {
+ /* invoke target offline */
+ bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline);
+ bfa_fcs_rport_logo_imp(itnim->rport);
+ }
break;
case BFA_FCS_ITNIM_SM_OFFLINE:
@@ -422,7 +433,7 @@ bfa_fcs_itnim_send_prli(void *itnim_cbarg, struct bfa_fcxp_s *fcxp_alloced)
bfa_fcxp_send(fcxp, rport->bfa_rport, port->fabric->vf_id, port->lp_tag,
BFA_FALSE, FC_CLASS_3, len, &fchs,
bfa_fcs_itnim_prli_response, (void *)itnim, FC_MAX_PDUSZ,
- FC_RA_TOV);
+ FC_ELS_TOV);
itnim->stats.prli_sent++;
bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_FRMSENT);
@@ -467,7 +478,7 @@ bfa_fcs_itnim_prli_response(void *fcsarg, struct bfa_fcxp_s *fcxp, void *cbarg,
BFA_RPORT_INITIATOR;
itnim->stats.prli_rsp_acc++;
bfa_sm_send_event(itnim,
- BFA_FCS_ITNIM_SM_INITIATOR);
+ BFA_FCS_ITNIM_SM_RSP_OK);
return;
}
@@ -738,6 +749,7 @@ bfa_fcs_itnim_attr_get(struct bfa_fcs_port_s *port, wwn_t rpwwn,
attr->rec_support = itnim->rec_support;
attr->conf_comp = itnim->conf_comp;
attr->task_retry_id = itnim->task_retry_id;
+ bfa_os_memset(&attr->io_latency, 0, sizeof(struct bfa_itnim_latency_s));
return BFA_STATUS_OK;
}
@@ -793,7 +805,7 @@ bfa_fcs_fcpim_uf_recv(struct bfa_fcs_itnim_s *itnim, struct fchs_s *fchs,
switch (els_cmd->els_code) {
case FC_ELS_PRLO:
- /* bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_PRLO); */
+ bfa_fcs_rport_prlo(itnim->rport, fchs->ox_id);
break;
default:
diff --git a/drivers/scsi/bfa/fcs_fabric.h b/drivers/scsi/bfa/fcs_fabric.h
index 244c3f00c50..432ab8ab8c3 100644
--- a/drivers/scsi/bfa/fcs_fabric.h
+++ b/drivers/scsi/bfa/fcs_fabric.h
@@ -26,6 +26,8 @@
#include <fcs/bfa_fcs_vport.h>
#include <fcs/bfa_fcs_lport.h>
+#define BFA_FCS_BRCD_SWITCH_OUI 0x051e
+
/*
* fcs friend functions: only between fcs modules
*/
@@ -60,4 +62,7 @@ void bfa_fcs_auth_finished(struct bfa_fcs_fabric_s *fabric,
void bfa_fcs_fabric_set_fabric_name(struct bfa_fcs_fabric_s *fabric,
wwn_t fabric_name);
+u16 bfa_fcs_fabric_get_switch_oui(struct bfa_fcs_fabric_s *fabric);
+void bfa_fcs_get_sym_name(const struct bfa_fcs_s *fcs, char *node_symname);
+
#endif /* __FCS_FABRIC_H__ */
diff --git a/drivers/scsi/bfa/fcs_rport.h b/drivers/scsi/bfa/fcs_rport.h
index 9c8d1d29238..e634fb7a69b 100644
--- a/drivers/scsi/bfa/fcs_rport.h
+++ b/drivers/scsi/bfa/fcs_rport.h
@@ -24,6 +24,8 @@
#include <fcs/bfa_fcs_rport.h>
+#define BFA_FCS_RPORT_MAX_RETRIES (5)
+
void bfa_fcs_rport_uf_recv(struct bfa_fcs_rport_s *rport, struct fchs_s *fchs,
u16 len);
void bfa_fcs_rport_scn(struct bfa_fcs_rport_s *rport);
@@ -41,6 +43,7 @@ void bfa_fcs_rport_plogi_create(struct bfa_fcs_port_s *port,
void bfa_fcs_rport_plogi(struct bfa_fcs_rport_s *rport, struct fchs_s *fchs,
struct fc_logi_s *plogi);
void bfa_fcs_rport_logo_imp(struct bfa_fcs_rport_s *rport);
+void bfa_fcs_rport_prlo(struct bfa_fcs_rport_s *rport, uint16_t ox_id);
void bfa_fcs_rport_itnim_ack(struct bfa_fcs_rport_s *rport);
void bfa_fcs_rport_itntm_ack(struct bfa_fcs_rport_s *rport);
void bfa_fcs_rport_tin_ack(struct bfa_fcs_rport_s *rport);
diff --git a/drivers/scsi/bfa/fcs_vport.h b/drivers/scsi/bfa/fcs_vport.h
index 13c32ebf946..bb647a4a5dd 100644
--- a/drivers/scsi/bfa/fcs_vport.h
+++ b/drivers/scsi/bfa/fcs_vport.h
@@ -26,6 +26,7 @@ void bfa_fcs_vport_cleanup(struct bfa_fcs_vport_s *vport);
void bfa_fcs_vport_online(struct bfa_fcs_vport_s *vport);
void bfa_fcs_vport_offline(struct bfa_fcs_vport_s *vport);
void bfa_fcs_vport_delete_comp(struct bfa_fcs_vport_s *vport);
+void bfa_fcs_vport_fcs_delete(struct bfa_fcs_vport_s *vport);
#endif /* __FCS_VPORT_H__ */
diff --git a/drivers/scsi/bfa/fdmi.c b/drivers/scsi/bfa/fdmi.c
index 8f17076d1a8..2b50eabf4b1 100644
--- a/drivers/scsi/bfa/fdmi.c
+++ b/drivers/scsi/bfa/fdmi.c
@@ -532,7 +532,7 @@ bfa_fcs_port_fdmi_send_rhba(void *fdmi_cbarg, struct bfa_fcxp_s *fcxp_alloced)
bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE,
FC_CLASS_3, (len + attr_len), &fchs,
bfa_fcs_port_fdmi_rhba_response, (void *)fdmi,
- FC_MAX_PDUSZ, FC_RA_TOV);
+ FC_MAX_PDUSZ, FC_FCCT_TOV);
bfa_sm_send_event(fdmi, FDMISM_EVENT_RHBA_SENT);
}
@@ -823,7 +823,7 @@ bfa_fcs_port_fdmi_send_rprt(void *fdmi_cbarg, struct bfa_fcxp_s *fcxp_alloced)
bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE,
FC_CLASS_3, len + attr_len, &fchs,
bfa_fcs_port_fdmi_rprt_response, (void *)fdmi,
- FC_MAX_PDUSZ, FC_RA_TOV);
+ FC_MAX_PDUSZ, FC_FCCT_TOV);
bfa_sm_send_event(fdmi, FDMISM_EVENT_RPRT_SENT);
}
@@ -1043,7 +1043,7 @@ bfa_fcs_port_fdmi_send_rpa(void *fdmi_cbarg, struct bfa_fcxp_s *fcxp_alloced)
bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE,
FC_CLASS_3, len + attr_len, &fchs,
bfa_fcs_port_fdmi_rpa_response, (void *)fdmi,
- FC_MAX_PDUSZ, FC_RA_TOV);
+ FC_MAX_PDUSZ, FC_FCCT_TOV);
bfa_sm_send_event(fdmi, FDMISM_EVENT_RPA_SENT);
}
diff --git a/drivers/scsi/bfa/include/aen/bfa_aen_ioc.h b/drivers/scsi/bfa/include/aen/bfa_aen_ioc.h
index 71378b446b6..4daf96faa26 100644
--- a/drivers/scsi/bfa/include/aen/bfa_aen_ioc.h
+++ b/drivers/scsi/bfa/include/aen/bfa_aen_ioc.h
@@ -32,6 +32,14 @@
BFA_LOG_CREATE_ID(BFA_AEN_CAT_IOC, BFA_IOC_AEN_DISABLE)
#define BFA_AEN_IOC_FWMISMATCH \
BFA_LOG_CREATE_ID(BFA_AEN_CAT_IOC, BFA_IOC_AEN_FWMISMATCH)
+#define BFA_AEN_IOC_FWCFG_ERROR \
+ BFA_LOG_CREATE_ID(BFA_AEN_CAT_IOC, BFA_IOC_AEN_FWCFG_ERROR)
+#define BFA_AEN_IOC_INVALID_VENDOR \
+ BFA_LOG_CREATE_ID(BFA_AEN_CAT_IOC, BFA_IOC_AEN_INVALID_VENDOR)
+#define BFA_AEN_IOC_INVALID_NWWN \
+ BFA_LOG_CREATE_ID(BFA_AEN_CAT_IOC, BFA_IOC_AEN_INVALID_NWWN)
+#define BFA_AEN_IOC_INVALID_PWWN \
+ BFA_LOG_CREATE_ID(BFA_AEN_CAT_IOC, BFA_IOC_AEN_INVALID_PWWN)
#endif
diff --git a/drivers/scsi/bfa/include/bfa.h b/drivers/scsi/bfa/include/bfa.h
index 1f5966cfbd1..d52b32f5695 100644
--- a/drivers/scsi/bfa/include/bfa.h
+++ b/drivers/scsi/bfa/include/bfa.h
@@ -126,6 +126,10 @@ struct bfa_sge_s {
bfa_ioc_get_type(&(__bfa)->ioc)
#define bfa_get_mac(__bfa) \
bfa_ioc_get_mac(&(__bfa)->ioc)
+#define bfa_get_mfg_mac(__bfa) \
+ bfa_ioc_get_mfg_mac(&(__bfa)->ioc)
+#define bfa_get_fw_clock_res(__bfa) \
+ ((__bfa)->iocfc.cfgrsp->fwcfg.fw_tick_res)
/*
* bfa API functions
diff --git a/drivers/scsi/bfa/include/bfa_fcpim.h b/drivers/scsi/bfa/include/bfa_fcpim.h
index 04789795fa5..4bc9453081d 100644
--- a/drivers/scsi/bfa/include/bfa_fcpim.h
+++ b/drivers/scsi/bfa/include/bfa_fcpim.h
@@ -42,6 +42,24 @@ u16 bfa_fcpim_qdepth_get(struct bfa_s *bfa);
bfa_status_t bfa_fcpim_get_modstats(struct bfa_s *bfa,
struct bfa_fcpim_stats_s *modstats);
bfa_status_t bfa_fcpim_clr_modstats(struct bfa_s *bfa);
+void bfa_fcpim_set_ioredirect(struct bfa_s *bfa, bfa_boolean_t state);
+void bfa_fcpim_update_ioredirect(struct bfa_s *bfa);
+void bfa_cb_ioredirect_state_change(void *hcb_bfad, bfa_boolean_t ioredirect);
+
+#define bfa_fcpim_ioredirect_enabled(__bfa) \
+ (((struct bfa_fcpim_mod_s *)(BFA_FCPIM_MOD(__bfa)))->ioredirect)
+
+#define bfa_fcpim_get_next_reqq(__bfa, __qid) \
+{ \
+ struct bfa_fcpim_mod_s *__fcpim = BFA_FCPIM_MOD(__bfa); \
+ __fcpim->reqq++; \
+ __fcpim->reqq &= (BFI_IOC_MAX_CQS - 1); \
+ *(__qid) = __fcpim->reqq; \
+}
+
+#define bfa_iocfc_map_msg_to_qid(__msg, __qid) \
+ *(__qid) = (u8)((__msg) & (BFI_IOC_MAX_CQS - 1));
+
/*
* bfa itnim API functions
@@ -56,6 +74,7 @@ void bfa_itnim_get_stats(struct bfa_itnim_s *itnim,
struct bfa_itnim_hal_stats_s *stats);
void bfa_itnim_clear_stats(struct bfa_itnim_s *itnim);
+#define bfa_itnim_get_reqq(__ioim) (((struct bfa_ioim_s *)__ioim)->itnim->reqq)
/**
* BFA completion callback for bfa_itnim_online().
@@ -156,4 +175,3 @@ void bfa_cb_tskim_done(void *bfad, struct bfad_tskim_s *dtsk,
enum bfi_tskim_status tsk_status);
#endif /* __BFA_FCPIM_H__ */
-
diff --git a/drivers/scsi/bfa/include/bfa_svc.h b/drivers/scsi/bfa/include/bfa_svc.h
index 1349b99a3c6..7840943d73b 100644
--- a/drivers/scsi/bfa/include/bfa_svc.h
+++ b/drivers/scsi/bfa/include/bfa_svc.h
@@ -215,6 +215,7 @@ bfa_status_t bfa_fcport_get_stats(struct bfa_s *bfa,
bfa_cb_pport_t cbfn, void *cbarg);
bfa_status_t bfa_fcport_clear_stats(struct bfa_s *bfa, bfa_cb_pport_t cbfn,
void *cbarg);
+bfa_boolean_t bfa_fcport_is_qos_enabled(struct bfa_s *bfa);
/*
* bfa rport API functions
diff --git a/drivers/scsi/bfa/include/bfi/bfi_ctreg.h b/drivers/scsi/bfa/include/bfi/bfi_ctreg.h
index 57a8497105a..c0ef5a93b79 100644
--- a/drivers/scsi/bfa/include/bfi/bfi_ctreg.h
+++ b/drivers/scsi/bfa/include/bfi/bfi_ctreg.h
@@ -455,6 +455,9 @@ enum {
#define __PSS_LPU0_RAM_ERR 0x00000001
#define ERR_SET_REG 0x00018818
#define __PSS_ERR_STATUS_SET 0x003fffff
+#define PMM_1T_RESET_REG_P0 0x0002381c
+#define __PMM_1T_RESET_P 0x00000001
+#define PMM_1T_RESET_REG_P1 0x00023c1c
#define HQM_QSET0_RXQ_DRBL_P0 0x00038000
#define __RXQ0_ADD_VECTORS_P 0x80000000
#define __RXQ0_STOP_P 0x40000000
diff --git a/drivers/scsi/bfa/include/bfi/bfi_ioc.h b/drivers/scsi/bfa/include/bfi/bfi_ioc.h
index a0158aac002..450ded6e9bc 100644
--- a/drivers/scsi/bfa/include/bfi/bfi_ioc.h
+++ b/drivers/scsi/bfa/include/bfi/bfi_ioc.h
@@ -48,9 +48,14 @@ struct bfi_ioc_getattr_req_s {
};
struct bfi_ioc_attr_s {
- wwn_t mfg_wwn;
- mac_t mfg_mac;
- u16 rsvd_a;
+ wwn_t mfg_pwwn; /* Mfg port wwn */
+ wwn_t mfg_nwwn; /* Mfg node wwn */
+ mac_t mfg_mac; /* Mfg mac */
+ u16 rsvd_a;
+ wwn_t pwwn;
+ wwn_t nwwn;
+ mac_t mac; /* PBC or Mfg mac */
+ u16 rsvd_b;
char brcd_serialnum[STRSZ(BFA_MFG_SERIALNUM_SIZE)];
u8 pcie_gen;
u8 pcie_lanes_orig;
@@ -58,11 +63,12 @@ struct bfi_ioc_attr_s {
u8 rx_bbcredit; /* receive buffer credits */
u32 adapter_prop; /* adapter properties */
u16 maxfrsize; /* max receive frame size */
- char asic_rev;
- u8 rsvd_b;
- char fw_version[BFA_VERSION_LEN];
- char optrom_version[BFA_VERSION_LEN];
+ char asic_rev;
+ u8 rsvd_c;
+ char fw_version[BFA_VERSION_LEN];
+ char optrom_version[BFA_VERSION_LEN];
struct bfa_mfg_vpd_s vpd;
+ u32 card_type; /* card type */
};
/**
diff --git a/drivers/scsi/bfa/include/bfi/bfi_iocfc.h b/drivers/scsi/bfa/include/bfi/bfi_iocfc.h
index c3760df7257..ccdfcc5d7e0 100644
--- a/drivers/scsi/bfa/include/bfi/bfi_iocfc.h
+++ b/drivers/scsi/bfa/include/bfi/bfi_iocfc.h
@@ -19,6 +19,7 @@
#define __BFI_IOCFC_H__
#include "bfi.h"
+#include <bfi/bfi_pbc.h>
#include <defs/bfa_defs_ioc.h>
#include <defs/bfa_defs_iocfc.h>
#include <defs/bfa_defs_boot.h>
@@ -78,6 +79,7 @@ struct bfi_iocfc_cfgrsp_s {
struct bfa_iocfc_fwcfg_s fwcfg;
struct bfa_iocfc_intr_attr_s intr_attr;
struct bfi_iocfc_bootwwns bootwwns;
+ struct bfi_pbc_s pbc_cfg;
};
/**
diff --git a/drivers/scsi/bfa/include/bfi/bfi_pbc.h b/drivers/scsi/bfa/include/bfi/bfi_pbc.h
new file mode 100644
index 00000000000..88a4154c30c
--- /dev/null
+++ b/drivers/scsi/bfa/include/bfi/bfi_pbc.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) 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.
+ */
+
+#ifndef __BFI_PBC_H__
+#define __BFI_PBC_H__
+
+#pragma pack(1)
+
+#define BFI_PBC_MAX_BLUNS 8
+#define BFI_PBC_MAX_VPORTS 16
+
+#define BFI_PBC_PORT_DISABLED 2
+/**
+ * PBC boot lun configuration
+ */
+struct bfi_pbc_blun_s {
+ wwn_t tgt_pwwn;
+ lun_t tgt_lun;
+};
+
+/**
+ * PBC virtual port configuration
+ */
+struct bfi_pbc_vport_s {
+ wwn_t vp_pwwn;
+ wwn_t vp_nwwn;
+};
+
+/**
+ * BFI pre-boot configuration information
+ */
+struct bfi_pbc_s {
+ u8 port_enabled;
+ u8 boot_enabled;
+ u8 nbluns;
+ u8 nvports;
+ u8 port_speed;
+ u8 rsvd_a;
+ u16 hss;
+ wwn_t pbc_pwwn;
+ wwn_t pbc_nwwn;
+ struct bfi_pbc_blun_s blun[BFI_PBC_MAX_BLUNS];
+ struct bfi_pbc_vport_s vport[BFI_PBC_MAX_VPORTS];
+};
+
+#pragma pack()
+
+#endif /* __BFI_PBC_H__ */
diff --git a/drivers/scsi/bfa/include/cna/port/bfa_port.h b/drivers/scsi/bfa/include/cna/port/bfa_port.h
index 7cbf17d3141..d7babaf9784 100644
--- a/drivers/scsi/bfa/include/cna/port/bfa_port.h
+++ b/drivers/scsi/bfa/include/cna/port/bfa_port.h
@@ -37,6 +37,7 @@ struct bfa_port_s {
bfa_port_stats_cbfn_t stats_cbfn;
void *stats_cbarg;
bfa_status_t stats_status;
+ u32 stats_reset_time;
union bfa_pport_stats_u *stats;
struct bfa_dma_s stats_dma;
bfa_boolean_t endis_pending;
diff --git a/drivers/scsi/bfa/include/cs/bfa_debug.h b/drivers/scsi/bfa/include/cs/bfa_debug.h
index 441be86b1b0..75a911ea793 100644
--- a/drivers/scsi/bfa/include/cs/bfa_debug.h
+++ b/drivers/scsi/bfa/include/cs/bfa_debug.h
@@ -28,7 +28,8 @@
} while (0)
#define bfa_sm_fault(__mod, __event) do { \
- bfa_sm_panic((__mod)->logm, __LINE__, __FILE__, __event); \
+ bfa_trc(__mod, (((uint32_t)0xDEAD << 16) | __event)); \
+ bfa_sm_panic((__mod)->logm, __LINE__, __FILE__, __event); \
} while (0)
#ifndef BFA_PERF_BUILD
diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_adapter.h b/drivers/scsi/bfa/include/defs/bfa_defs_adapter.h
index 8c208fc8e32..aea0360d67d 100644
--- a/drivers/scsi/bfa/include/defs/bfa_defs_adapter.h
+++ b/drivers/scsi/bfa/include/defs/bfa_defs_adapter.h
@@ -39,7 +39,7 @@ enum {
struct bfa_adapter_attr_s {
char manufacturer[BFA_ADAPTER_MFG_NAME_LEN];
char serial_num[BFA_ADAPTER_SERIAL_NUM_LEN];
- u32 rsvd1;
+ u32 card_type;
char model[BFA_ADAPTER_MODEL_NAME_LEN];
char model_descr[BFA_ADAPTER_MODEL_DESCR_LEN];
wwn_t pwwn;
@@ -60,6 +60,7 @@ struct bfa_adapter_attr_s {
u8 pcie_lanes_orig;
u8 pcie_lanes;
u8 cna_capable;
+ u8 is_mezz;
};
/**
diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_auth.h b/drivers/scsi/bfa/include/defs/bfa_defs_auth.h
index 45df3282091..f56ed871bb9 100644
--- a/drivers/scsi/bfa/include/defs/bfa_defs_auth.h
+++ b/drivers/scsi/bfa/include/defs/bfa_defs_auth.h
@@ -125,10 +125,10 @@ struct bfa_auth_attr_s {
enum bfa_auth_status status;
enum bfa_auth_algo algo;
enum bfa_auth_group dh_grp;
- u16 rjt_code;
- u16 rjt_code_exp;
+ enum bfa_auth_rej_code rjt_code;
+ enum bfa_auth_rej_code_exp rjt_code_exp;
u8 secret_set;
- u8 resv[7];
+ u8 resv[3];
};
#endif /* __BFA_DEFS_AUTH_H__ */
diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_boot.h b/drivers/scsi/bfa/include/defs/bfa_defs_boot.h
index 6f4aa528354..0fca10b6ad1 100644
--- a/drivers/scsi/bfa/include/defs/bfa_defs_boot.h
+++ b/drivers/scsi/bfa/include/defs/bfa_defs_boot.h
@@ -24,6 +24,8 @@
enum {
BFA_BOOT_BOOTLUN_MAX = 4, /* maximum boot lun per IOC */
+ BFA_PREBOOT_BOOTLUN_MAX = 8, /* maximum preboot lun per IOC */
+
};
#define BOOT_CFG_REV1 1
@@ -67,5 +69,13 @@ struct bfa_boot_cfg_s {
struct bfa_boot_bootlun_s blun_disc[BFA_BOOT_BOOTLUN_MAX];
};
+struct bfa_boot_pbc_s {
+ u8 enable; /* enable/disable SAN boot */
+ u8 speed; /* boot speed settings */
+ u8 topology; /* boot topology setting */
+ u8 rsvd1;
+ u32 nbluns; /* number of boot luns */
+ struct bfa_boot_bootlun_s pblun[BFA_PREBOOT_BOOTLUN_MAX];
+};
#endif /* __BFA_DEFS_BOOT_H__ */
diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_driver.h b/drivers/scsi/bfa/include/defs/bfa_defs_driver.h
index 50382dd2ab4..7d00d00d396 100644
--- a/drivers/scsi/bfa/include/defs/bfa_defs_driver.h
+++ b/drivers/scsi/bfa/include/defs/bfa_defs_driver.h
@@ -29,7 +29,7 @@ struct bfa_driver_stats_s {
u16 tm_target_reset;
u16 tm_bus_reset;
u16 ioc_restart; /* IOC restart count */
- u16 io_pending; /* outstanding io count per-IOC */
+ u16 rsvd;
u64 control_req;
u64 input_req;
u64 output_req;
diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_fcport.h b/drivers/scsi/bfa/include/defs/bfa_defs_fcport.h
index a07ef4a3cd7..af86a639643 100644
--- a/drivers/scsi/bfa/include/defs/bfa_defs_fcport.h
+++ b/drivers/scsi/bfa/include/defs/bfa_defs_fcport.h
@@ -48,7 +48,7 @@ struct bfa_fcoe_stats_s {
u64 disc_fcf_unavail; /* Discovery FCF not avail */
u64 linksvc_unsupp; /* FIP link service req unsupp. */
u64 linksvc_err; /* FIP link service req errors */
- u64 logo_req; /* FIP logo */
+ u64 logo_req; /* FIP logos received */
u64 clrvlink_req; /* Clear virtual link requests */
u64 op_unsupp; /* FIP operation unsupp. */
u64 untagged; /* FIP untagged frames */
@@ -64,21 +64,15 @@ struct bfa_fcoe_stats_s {
u64 txf_timeout; /* Tx timeouts */
u64 txf_parity_errors; /* Transmit parity err */
u64 txf_fid_parity_errors; /* Transmit FID parity err */
- u64 tx_pause; /* Tx pause frames */
- u64 tx_zero_pause; /* Tx zero pause frames */
- u64 tx_first_pause; /* Tx first pause frames */
- u64 rx_pause; /* Rx pause frames */
- u64 rx_zero_pause; /* Rx zero pause frames */
- u64 rx_first_pause; /* Rx first pause frames */
- u64 rxf_ucast_octets; /* Rx unicast octets */
- u64 rxf_ucast; /* Rx unicast frames */
- u64 rxf_ucast_vlan; /* Rx unicast vlan frames */
- u64 rxf_mcast_octets; /* Rx multicast octets */
- u64 rxf_mcast; /* Rx multicast frames */
- u64 rxf_mcast_vlan; /* Rx multicast vlan frames */
- u64 rxf_bcast_octets; /* Rx broadcast octests */
- u64 rxf_bcast; /* Rx broadcast frames */
- u64 rxf_bcast_vlan; /* Rx broadcast vlan frames */
+ u64 rxf_ucast_octets; /* Rx FCoE unicast octets */
+ u64 rxf_ucast; /* Rx FCoE unicast frames */
+ u64 rxf_ucast_vlan; /* Rx FCoE unicast vlan frames */
+ u64 rxf_mcast_octets; /* Rx FCoE multicast octets */
+ u64 rxf_mcast; /* Rx FCoE multicast frames */
+ u64 rxf_mcast_vlan; /* Rx FCoE multicast vlan frames */
+ u64 rxf_bcast_octets; /* Rx FCoE broadcast octets */
+ u64 rxf_bcast; /* Rx FCoE broadcast frames */
+ u64 rxf_bcast_vlan; /* Rx FCoE broadcast vlan frames */
};
/**
diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_ioc.h b/drivers/scsi/bfa/include/defs/bfa_defs_ioc.h
index 8d8e6a96653..add0a05d941 100644
--- a/drivers/scsi/bfa/include/defs/bfa_defs_ioc.h
+++ b/drivers/scsi/bfa/include/defs/bfa_defs_ioc.h
@@ -126,7 +126,7 @@ struct bfa_ioc_attr_s {
struct bfa_ioc_driver_attr_s driver_attr; /* driver attr */
struct bfa_ioc_pci_attr_s pci_attr;
u8 port_id; /* port number */
- u8 rsvd[7]; /*!< 64bit align */
+ u8 rsvd[7]; /* 64bit align */
};
/**
@@ -138,6 +138,11 @@ enum bfa_ioc_aen_event {
BFA_IOC_AEN_ENABLE = 3, /* IOC enabled event */
BFA_IOC_AEN_DISABLE = 4, /* IOC disabled event */
BFA_IOC_AEN_FWMISMATCH = 5, /* IOC firmware mismatch */
+ BFA_IOC_AEN_FWCFG_ERROR = 6, /* IOC firmware config error */
+ BFA_IOC_AEN_INVALID_VENDOR = 7,
+ BFA_IOC_AEN_INVALID_NWWN = 8, /* Zero NWWN */
+ BFA_IOC_AEN_INVALID_PWWN = 9 /* Zero PWWN */
+
};
/**
diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_iocfc.h b/drivers/scsi/bfa/include/defs/bfa_defs_iocfc.h
index c290fb13d2d..31e728a631e 100644
--- a/drivers/scsi/bfa/include/defs/bfa_defs_iocfc.h
+++ b/drivers/scsi/bfa/include/defs/bfa_defs_iocfc.h
@@ -51,8 +51,10 @@ struct bfa_iocfc_fwcfg_s {
u16 num_tsktm_reqs; /* TM task management requests*/
u16 num_fcxp_reqs; /* unassisted FC exchanges */
u16 num_uf_bufs; /* unsolicited recv buffers */
- u8 num_cqs;
- u8 rsvd[5];
+ u8 num_cqs;
+ u8 fw_tick_res; /*!< FW clock resolution in ms */
+ u8 rsvd[4];
+
};
struct bfa_iocfc_drvcfg_s {
@@ -176,10 +178,10 @@ struct bfa_fw_port_fpg_stats_s {
u32 nos_rx;
u32 lip_rx;
u32 arbf0_rx;
+ u32 arb_rx;
u32 mrk_rx;
u32 const_mrk_rx;
u32 prim_unknown;
- u32 rsvd;
};
@@ -200,6 +202,8 @@ struct bfa_fw_port_lksm_stats_s {
u32 lrr_tx; /* No. of times LRR tx started */
u32 ols_tx; /* No. of times OLS tx started */
u32 nos_tx; /* No. of times NOS tx started */
+ u32 hwsm_lrr_rx; /* No. of times LRR rx-ed by HWSM */
+ u32 hwsm_lr_rx; /* No. of times LR rx-ed by HWSM */
};
@@ -239,7 +243,7 @@ struct bfa_fw_fip_stats_s {
u32 disc_fcf_unavail; /* Discovery FCF Not Avail. */
u32 linksvc_unsupp; /* Unsupported link service req */
u32 linksvc_err; /* Parse error in link service req */
- u32 logo_req; /* Number of FIP logos received */
+ u32 logo_req; /* FIP logos received */
u32 clrvlink_req; /* Clear virtual link req */
u32 op_unsupp; /* Unsupported FIP operation */
u32 untagged; /* Untagged frames (ignored) */
diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_itnim.h b/drivers/scsi/bfa/include/defs/bfa_defs_itnim.h
index 2ec769903d2..d77788b3999 100644
--- a/drivers/scsi/bfa/include/defs/bfa_defs_itnim.h
+++ b/drivers/scsi/bfa/include/defs/bfa_defs_itnim.h
@@ -34,6 +34,15 @@ enum bfa_itnim_state {
BFA_ITNIM_INITIATIOR = 7, /* initiator */
};
+struct bfa_itnim_latency_s {
+ u32 min;
+ u32 max;
+ u32 count;
+ u32 clock_res;
+ u32 avg;
+ u32 rsvd;
+};
+
struct bfa_itnim_hal_stats_s {
u32 onlines; /* ITN nexus onlines (PRLI done) */
u32 offlines; /* ITN Nexus offlines */
@@ -91,6 +100,7 @@ struct bfa_itnim_attr_s {
u8 task_retry_id; /* task retry ident support */
u8 rec_support; /* REC supported */
u8 conf_comp; /* confirmed completion supp */
+ struct bfa_itnim_latency_s io_latency; /* IO latency */
};
/**
diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_mfg.h b/drivers/scsi/bfa/include/defs/bfa_defs_mfg.h
index c5bd9c36ad4..d22fb790964 100644
--- a/drivers/scsi/bfa/include/defs/bfa_defs_mfg.h
+++ b/drivers/scsi/bfa/include/defs/bfa_defs_mfg.h
@@ -45,26 +45,6 @@
#define BFA_MFG_CHKSUM_SIZE 16
/**
- * Manufacturing block encrypted version
- */
-#define BFA_MFG_ENC_VER 2
-
-/**
- * Manufacturing block version 1 length
- */
-#define BFA_MFG_VER1_LEN 128
-
-/**
- * Manufacturing block header length
- */
-#define BFA_MFG_HDR_LEN 4
-
-/**
- * Checksum size
- */
-#define BFA_MFG_CHKSUM_SIZE 16
-
-/**
* Manufacturing block format
*/
#define BFA_MFG_SERIALNUM_SIZE 11
@@ -86,6 +66,9 @@ enum {
BFA_MFG_TYPE_FC4P1 = 415, /* 4G 1port FC card */
BFA_MFG_TYPE_CNA10P2 = 1020, /* 10G 2port CNA card */
BFA_MFG_TYPE_CNA10P1 = 1010, /* 10G 1port CNA card */
+ BFA_MFG_TYPE_JAYHAWK = 804, /* Jayhawk mezz card */
+ BFA_MFG_TYPE_WANCHESE = 1007, /* Wanchese mezz card */
+ BFA_MFG_TYPE_INVALID = 0, /* Invalid card type */
};
#pragma pack(1)
@@ -95,6 +78,24 @@ enum {
*/
#define bfa_mfg_type2port_num(card_type) (((card_type) / 10) % 10)
+/**
+ * Check if Mezz card
+ */
+#define bfa_mfg_is_mezz(type) (( \
+ (type) == BFA_MFG_TYPE_JAYHAWK || \
+ (type) == BFA_MFG_TYPE_WANCHESE))
+
+/**
+ * Check if card type valid
+ */
+#define bfa_mfg_is_card_type_valid(type) (( \
+ (type) == BFA_MFG_TYPE_FC8P2 || \
+ (type) == BFA_MFG_TYPE_FC8P1 || \
+ (type) == BFA_MFG_TYPE_FC4P2 || \
+ (type) == BFA_MFG_TYPE_FC4P1 || \
+ (type) == BFA_MFG_TYPE_CNA10P2 || \
+ (type) == BFA_MFG_TYPE_CNA10P1 || \
+ bfa_mfg_is_mezz(type)))
/**
* All numerical fields are in big-endian format.
diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_pci.h b/drivers/scsi/bfa/include/defs/bfa_defs_pci.h
index c9b83321694..ea7d89bbc0b 100644
--- a/drivers/scsi/bfa/include/defs/bfa_defs_pci.h
+++ b/drivers/scsi/bfa/include/defs/bfa_defs_pci.h
@@ -26,8 +26,13 @@ enum {
BFA_PCI_DEVICE_ID_FC_8G2P = 0x13,
BFA_PCI_DEVICE_ID_FC_8G1P = 0x17,
BFA_PCI_DEVICE_ID_CT = 0x14,
+ BFA_PCI_DEVICE_ID_CT_FC = 0x21,
};
+#define bfa_asic_id_ct(devid) \
+ ((devid) == BFA_PCI_DEVICE_ID_CT || \
+ (devid) == BFA_PCI_DEVICE_ID_CT_FC)
+
/**
* PCI sub-system device and vendor ID information
*/
@@ -35,7 +40,9 @@ enum {
BFA_PCI_FCOE_SSDEVICE_ID = 0x14,
};
-#define BFA_PCI_ACCESS_RANGES 1 /* Maximum number of device address ranges
- * mapped through different BAR(s). */
+/**
+ * Maximum number of device address ranges mapped through different BAR(s)
+ */
+#define BFA_PCI_ACCESS_RANGES 1
#endif /* __BFA_DEFS_PCI_H__ */
diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_port.h b/drivers/scsi/bfa/include/defs/bfa_defs_port.h
index 501bc9739d9..ebdf0d1731a 100644
--- a/drivers/scsi/bfa/include/defs/bfa_defs_port.h
+++ b/drivers/scsi/bfa/include/defs/bfa_defs_port.h
@@ -50,12 +50,12 @@ enum bfa_port_role {
* FCS port configuration.
*/
struct bfa_port_cfg_s {
- wwn_t pwwn; /* port wwn */
- wwn_t nwwn; /* node wwn */
- struct bfa_port_symname_s sym_name; /* vm port symbolic name */
- enum bfa_port_role roles; /* FCS port roles */
- u32 rsvd;
- u8 tag[16]; /* opaque tag from application */
+ wwn_t pwwn; /* port wwn */
+ wwn_t nwwn; /* node wwn */
+ struct bfa_port_symname_s sym_name; /* vm port symbolic name */
+ bfa_boolean_t preboot_vp; /* vport created from PBC */
+ enum bfa_port_role roles; /* FCS port roles */
+ u8 tag[16]; /* opaque tag from application */
};
/**
@@ -159,7 +159,7 @@ struct bfa_port_stats_s {
u32 ms_plogi_rsp_err;
u32 ms_plogi_acc_err;
u32 ms_plogi_accepts;
- u32 ms_rejects; /* NS command rejects */
+ u32 ms_rejects; /* MS command rejects */
u32 ms_plogi_unknown_rsp;
u32 ms_plogi_alloc_wait;
diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_pport.h b/drivers/scsi/bfa/include/defs/bfa_defs_pport.h
index 26e5cc78095..2de675839c2 100644
--- a/drivers/scsi/bfa/include/defs/bfa_defs_pport.h
+++ b/drivers/scsi/bfa/include/defs/bfa_defs_pport.h
@@ -38,6 +38,7 @@ enum bfa_pport_states {
BFA_PPORT_ST_IOCDOWN = 10,
BFA_PPORT_ST_IOCDIS = 11,
BFA_PPORT_ST_FWMISMATCH = 12,
+ BFA_PPORT_ST_PREBOOT_DISABLED = 13,
BFA_PPORT_ST_MAX_STATE,
};
@@ -203,6 +204,8 @@ struct bfa_pport_attr_s {
*/
wwn_t nwwn; /* node wwn */
wwn_t pwwn; /* port wwn */
+ wwn_t factorynwwn; /* factory node wwn */
+ wwn_t factorypwwn; /* factory port wwn */
enum fc_cos cos_supported; /* supported class of services */
u32 rsvd;
struct fc_symname_s port_symname; /* port symbolic name */
@@ -243,7 +246,7 @@ struct bfa_pport_fc_stats_s {
u64 secs_reset; /* Seconds since stats is reset */
u64 tx_frames; /* Tx frames */
u64 tx_words; /* Tx words */
- u64 tx_lip; /* TX LIP */
+ u64 tx_lip; /* Tx LIP */
u64 tx_nos; /* Tx NOS */
u64 tx_ols; /* Tx OLS */
u64 tx_lr; /* Tx LR */
@@ -309,7 +312,7 @@ struct bfa_pport_eth_stats_s {
u64 rx_zero_pause; /* Rx zero pause */
u64 tx_pause; /* Tx pause */
u64 tx_zero_pause; /* Tx zero pause */
- u64 rx_fcoe_pause; /* Rx fcoe pause */
+ u64 rx_fcoe_pause; /* Rx FCoE pause */
u64 rx_fcoe_zero_pause; /* Rx FCoE zero pause */
u64 tx_fcoe_pause; /* Tx FCoE pause */
u64 tx_fcoe_zero_pause; /* Tx FCoE zero pause */
@@ -381,26 +384,10 @@ struct bfa_pport_link_s {
u8 trunked; /* Trunked or not (1 or 0) */
u8 resvd[3];
struct bfa_qos_attr_s qos_attr; /* QoS Attributes */
- struct bfa_qos_vc_attr_s qos_vc_attr; /* VC info from ELP */
union {
- struct {
- u8 tmaster;/* Trunk Master or
- * not (1 or 0) */
- u8 tlinks; /* Trunk links bitmap
- * (linkup) */
- u8 resv1; /* Reserved */
- } trunk_info;
-
- struct {
- u8 myalpa; /* alpa claimed */
- u8 login_req; /* Login required or
- * not (1 or 0) */
- u8 alpabm_val;/* alpa bitmap valid
- * or not (1 or 0) */
- struct fc_alpabm_s alpabm; /* alpa bitmap */
- } loop_info;
- } tl;
- struct bfa_fcport_fcf_s fcf; /*!< FCF information (for FCoE) */
+ struct bfa_qos_vc_attr_s qos_vc_attr; /* VC info from ELP */
+ struct bfa_fcport_fcf_s fcf; /* FCF information (for FCoE) */
+ } vc_fcf;
};
#endif /* __BFA_DEFS_PPORT_H__ */
diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_status.h b/drivers/scsi/bfa/include/defs/bfa_defs_status.h
index ec78b4cb121..6eb4e62096f 100644
--- a/drivers/scsi/bfa/include/defs/bfa_defs_status.h
+++ b/drivers/scsi/bfa/include/defs/bfa_defs_status.h
@@ -84,8 +84,9 @@ enum bfa_status {
BFA_STATUS_BADFRMHDR = 48, /* Bad frame header */
BFA_STATUS_BADFRMSZ = 49, /* Bad frame size check and replace
* SFP/cable */
- BFA_STATUS_MISSINGFRM = 50, /* Missing frame check and replace
- * SFP/cable */
+ BFA_STATUS_MISSINGFRM = 50, /* Missing frame check and replace
+ * SFP/cable or for Mezz card check and
+ * replace pass through module */
BFA_STATUS_LINKTIMEOUT = 51, /* Link timeout check and replace
* SFP/cable */
BFA_STATUS_NO_FCPIM_NEXUS = 52, /* No FCP Nexus exists with the
@@ -173,7 +174,7 @@ enum bfa_status {
BFA_STATUS_LEDTEST_OP = 109, /* LED test is operating */
BFA_STATUS_CEE_NOT_DN = 110, /* eth port is not at down state, please
* bring down first */
- BFA_STATUS_10G_SPD = 111, /* Speed setting not valid for 10G HBA */
+ BFA_STATUS_10G_SPD = 111, /* Speed setting not valid for 10G CNA */
BFA_STATUS_IM_INV_TEAM_NAME = 112, /* Invalid team name */
BFA_STATUS_IM_DUP_TEAM_NAME = 113, /* Given team name already
* exists */
@@ -213,12 +214,13 @@ enum bfa_status {
* loaded */
BFA_STATUS_CARD_TYPE_MISMATCH = 131, /* Card type mismatch */
BFA_STATUS_BAD_ASICBLK = 132, /* Bad ASIC block */
- BFA_STATUS_NO_DRIVER = 133, /* Brocade adapter/driver not installed or loaded */
- BFA_STATUS_INVALID_MAC = 134, /* Invalid mac address */
+ BFA_STATUS_NO_DRIVER = 133, /* Brocade adapter/driver not installed
+ * or loaded */
+ BFA_STATUS_INVALID_MAC = 134, /* Invalid MAC address */
BFA_STATUS_IM_NO_VLAN = 135, /* No VLANs configured on the adapter */
BFA_STATUS_IM_ETH_LB_FAILED = 136, /* Ethernet loopback test failed */
- BFA_STATUS_IM_PVID_REMOVE = 137, /* Cannot remove port vlan (PVID) */
- BFA_STATUS_IM_PVID_EDIT = 138, /* Cannot edit port vlan (PVID) */
+ BFA_STATUS_IM_PVID_REMOVE = 137, /* Cannot remove port VLAN (PVID) */
+ BFA_STATUS_IM_PVID_EDIT = 138, /* Cannot edit port VLAN (PVID) */
BFA_STATUS_CNA_NO_BOOT = 139, /* Boot upload not allowed for CNA */
BFA_STATUS_IM_PVID_NON_ZERO = 140, /* Port VLAN ID (PVID) is Set to
* Non-Zero Value */
@@ -232,14 +234,15 @@ enum bfa_status {
BFA_STATUS_INSUFFICIENT_PERMS = 144, /* User doesn't have sufficient
* permissions to execute the BCU
* application */
- BFA_STATUS_IM_INV_VLAN_NAME = 145, /* Invalid/Reserved Vlan name
+ BFA_STATUS_IM_INV_VLAN_NAME = 145, /* Invalid/Reserved VLAN name
* string. The name is not allowed
- * for the normal Vlans */
+ * for the normal VLAN */
BFA_STATUS_CMD_NOTSUPP_CNA = 146, /* Command not supported for CNA */
- BFA_STATUS_IM_PASSTHRU_EDIT = 147, /* Can not edit passthru vlan id */
- BFA_STATUS_IM_BIND_FAILED = 148, /*! < IM Driver bind operation
+ BFA_STATUS_IM_PASSTHRU_EDIT = 147, /* Can not edit passthrough VLAN
+ * id */
+ BFA_STATUS_IM_BIND_FAILED = 148, /* IM Driver bind operation
* failed */
- BFA_STATUS_IM_UNBIND_FAILED = 149, /* ! < IM Driver unbind operation
+ BFA_STATUS_IM_UNBIND_FAILED = 149, /* IM Driver unbind operation
* failed */
BFA_STATUS_IM_PORT_IN_TEAM = 150, /* Port is already part of the
* team */
@@ -249,7 +252,24 @@ enum bfa_status {
BFA_STATUS_IM_TEAM_CFG_NOT_ALLOWED = 153, /* Given settings are not
* allowed for the current
* Teaming mode */
- BFA_STATUS_MAX_VAL /* Unknown error code */
+ BFA_STATUS_PBC = 154, /* Operation not allowed for pre-boot
+ * configuration */
+ BFA_STATUS_DEVID_MISSING = 155, /* Boot image is not for the adapter(s)
+ * installed */
+ BFA_STATUS_BAD_FWCFG = 156, /* Bad firmware configuration */
+ BFA_STATUS_CREATE_FILE = 157, /* Failed to create temporary file */
+ BFA_STATUS_INVALID_VENDOR = 158, /* Invalid switch vendor */
+ BFA_STATUS_SFP_NOT_READY = 159, /* SFP info is not ready. Retry */
+ BFA_STATUS_NO_TOPOLOGY_FOR_CNA = 160, /* Topology command not
+ * applicable to CNA */
+ BFA_STATUS_BOOT_CODE_UPDATED = 161, /* reboot -- -r is needed after
+ * boot code updated */
+ BFA_STATUS_BOOT_VERSION = 162, /* Boot code version not compatible with
+ * the driver installed */
+ BFA_STATUS_CARDTYPE_MISSING = 163, /* Boot image is not for the
+ * adapter(s) installed */
+ BFA_STATUS_INVALID_CARDTYPE = 164, /* Invalid card type provided */
+ BFA_STATUS_MAX_VAL /* Unknown error code */
};
#define bfa_status_t enum bfa_status
diff --git a/drivers/scsi/bfa/include/fcb/bfa_fcb_vport.h b/drivers/scsi/bfa/include/fcb/bfa_fcb_vport.h
index a39f474c2fc..cfd6ba7c47e 100644
--- a/drivers/scsi/bfa/include/fcb/bfa_fcb_vport.h
+++ b/drivers/scsi/bfa/include/fcb/bfa_fcb_vport.h
@@ -40,7 +40,8 @@ struct bfad_vport_s;
*
* @return None
*/
-void bfa_fcb_vport_delete(struct bfad_vport_s *vport_drv);
+void bfa_fcb_vport_delete(struct bfad_vport_s *vport_drv);
+void bfa_fcb_pbc_vport_create(struct bfad_s *bfad, struct bfi_pbc_vport_s);
diff --git a/drivers/scsi/bfa/include/fcs/bfa_fcs.h b/drivers/scsi/bfa/include/fcs/bfa_fcs.h
index f2fd35fdee2..54e5b81ab2a 100644
--- a/drivers/scsi/bfa/include/fcs/bfa_fcs.h
+++ b/drivers/scsi/bfa/include/fcs/bfa_fcs.h
@@ -61,8 +61,8 @@ struct bfa_fcs_s {
/*
* bfa fcs API functions
*/
-void bfa_fcs_attach(struct bfa_fcs_s *fcs, struct bfa_s *bfa, struct bfad_s *bfad,
- bfa_boolean_t min_cfg);
+void bfa_fcs_attach(struct bfa_fcs_s *fcs, struct bfa_s *bfa,
+ struct bfad_s *bfad, bfa_boolean_t min_cfg);
void bfa_fcs_init(struct bfa_fcs_s *fcs);
void bfa_fcs_driver_info_init(struct bfa_fcs_s *fcs,
struct bfa_fcs_driver_info_s *driver_info);
diff --git a/drivers/scsi/bfa/include/fcs/bfa_fcs_fcpim.h b/drivers/scsi/bfa/include/fcs/bfa_fcs_fcpim.h
index e719f2c3eb3..9a35ecf5cdf 100644
--- a/drivers/scsi/bfa/include/fcs/bfa_fcs_fcpim.h
+++ b/drivers/scsi/bfa/include/fcs/bfa_fcs_fcpim.h
@@ -41,6 +41,7 @@ struct bfa_fcs_itnim_s {
struct bfa_fcs_s *fcs; /* fcs instance */
struct bfa_timer_s timer; /* timer functions */
struct bfa_itnim_s *bfa_itnim; /* BFA itnim struct */
+ u32 prli_retries; /* max prli retry attempts */
bfa_boolean_t seq_rec; /* seq recovery support */
bfa_boolean_t rec_support; /* REC supported */
bfa_boolean_t conf_comp; /* FCP_CONF support */
diff --git a/drivers/scsi/bfa/include/fcs/bfa_fcs_rport.h b/drivers/scsi/bfa/include/fcs/bfa_fcs_rport.h
index 702b95b76c2..3027fc6c772 100644
--- a/drivers/scsi/bfa/include/fcs/bfa_fcs_rport.h
+++ b/drivers/scsi/bfa/include/fcs/bfa_fcs_rport.h
@@ -58,6 +58,7 @@ struct bfa_fcs_rport_s {
u16 reply_oxid; /* OX_ID of inbound requests */
enum fc_cos fc_cos; /* FC classes of service supp */
bfa_boolean_t cisc; /* CISC capable device */
+ bfa_boolean_t prlo; /* processing prlo or LOGO */
wwn_t pwwn; /* port wwn of rport */
wwn_t nwwn; /* node wwn of rport */
struct bfa_rport_symname_s psym_name; /* port symbolic name */
diff --git a/drivers/scsi/bfa/include/fcs/bfa_fcs_vport.h b/drivers/scsi/bfa/include/fcs/bfa_fcs_vport.h
index cd33f2cd5c3..0af26243086 100644
--- a/drivers/scsi/bfa/include/fcs/bfa_fcs_vport.h
+++ b/drivers/scsi/bfa/include/fcs/bfa_fcs_vport.h
@@ -49,6 +49,10 @@ bfa_status_t bfa_fcs_vport_create(struct bfa_fcs_vport_s *vport,
struct bfa_fcs_s *fcs, u16 vf_id,
struct bfa_port_cfg_s *port_cfg,
struct bfad_vport_s *vport_drv);
+bfa_status_t bfa_fcs_pbc_vport_create(struct bfa_fcs_vport_s *vport,
+ struct bfa_fcs_s *fcs, uint16_t vf_id,
+ struct bfa_port_cfg_s *port_cfg,
+ struct bfad_vport_s *vport_drv);
bfa_status_t bfa_fcs_vport_delete(struct bfa_fcs_vport_s *vport);
bfa_status_t bfa_fcs_vport_start(struct bfa_fcs_vport_s *vport);
bfa_status_t bfa_fcs_vport_stop(struct bfa_fcs_vport_s *vport);
diff --git a/drivers/scsi/bfa/include/log/bfa_log_linux.h b/drivers/scsi/bfa/include/log/bfa_log_linux.h
index bd451db4c30..44bc89768bd 100644
--- a/drivers/scsi/bfa/include/log/bfa_log_linux.h
+++ b/drivers/scsi/bfa/include/log/bfa_log_linux.h
@@ -53,8 +53,10 @@
(((u32) BFA_LOG_LINUX_ID << BFA_LOG_MODID_OFFSET) | 16)
#define BFA_LOG_LINUX_DRIVER_ERROR \
(((u32) BFA_LOG_LINUX_ID << BFA_LOG_MODID_OFFSET) | 17)
-#define BFA_LOG_LINUX_DRIVER_DIAG \
+#define BFA_LOG_LINUX_DRIVER_INFO \
(((u32) BFA_LOG_LINUX_ID << BFA_LOG_MODID_OFFSET) | 18)
-#define BFA_LOG_LINUX_DRIVER_AEN \
+#define BFA_LOG_LINUX_DRIVER_DIAG \
(((u32) BFA_LOG_LINUX_ID << BFA_LOG_MODID_OFFSET) | 19)
+#define BFA_LOG_LINUX_DRIVER_AEN \
+ (((u32) BFA_LOG_LINUX_ID << BFA_LOG_MODID_OFFSET) | 20)
#endif
diff --git a/drivers/scsi/bfa/include/protocol/fc.h b/drivers/scsi/bfa/include/protocol/fc.h
index 8d1038035a7..436dd7c5643 100644
--- a/drivers/scsi/bfa/include/protocol/fc.h
+++ b/drivers/scsi/bfa/include/protocol/fc.h
@@ -1080,6 +1080,7 @@ struct fc_alpabm_s{
#define FC_REC_TOV (FC_ED_TOV + 1)
#define FC_RA_TOV 10
#define FC_ELS_TOV (2 * FC_RA_TOV)
+#define FC_FCCT_TOV (3 * FC_RA_TOV)
/*
* virtual fabric related defines
diff --git a/drivers/scsi/bfa/lport_api.c b/drivers/scsi/bfa/lport_api.c
index d3907d184e2..72b3f508d0e 100644
--- a/drivers/scsi/bfa/lport_api.c
+++ b/drivers/scsi/bfa/lport_api.c
@@ -137,6 +137,8 @@ bfa_fcs_port_get_rports(struct bfa_fcs_port_s *port, wwn_t rport_wwns[],
/*
* Iterate's through all the rport's in the given port to
* determine the maximum operating speed.
+ *
+ * To be used in TRL Functionality only
*/
enum bfa_pport_speed
bfa_fcs_port_get_rport_max_speed(struct bfa_fcs_port_s *port)
@@ -146,7 +148,8 @@ bfa_fcs_port_get_rport_max_speed(struct bfa_fcs_port_s *port)
struct bfa_fcs_s *fcs;
enum bfa_pport_speed max_speed = 0;
struct bfa_pport_attr_s pport_attr;
- enum bfa_pport_speed pport_speed;
+ enum bfa_pport_speed pport_speed, rport_speed;
+ bfa_boolean_t trl_enabled = bfa_fcport_is_ratelim(port->fcs->bfa);
if (port == NULL)
return 0;
@@ -164,19 +167,28 @@ bfa_fcs_port_get_rport_max_speed(struct bfa_fcs_port_s *port)
qe = bfa_q_first(qh);
while (qe != qh) {
- rport = (struct bfa_fcs_rport_s *)qe;
- if ((bfa_os_ntoh3b(rport->pid) > 0xFFF000)
- || (bfa_fcs_rport_get_state(rport) == BFA_RPORT_OFFLINE)) {
+ rport = (struct bfa_fcs_rport_s *) qe;
+ if ((bfa_os_ntoh3b(rport->pid) > 0xFFF000) ||
+ (bfa_fcs_rport_get_state(rport) ==
+ BFA_RPORT_OFFLINE)) {
qe = bfa_q_next(qe);
continue;
}
- if ((rport->rpf.rpsc_speed == BFA_PPORT_SPEED_8GBPS)
- || (rport->rpf.rpsc_speed > pport_speed)) {
- max_speed = rport->rpf.rpsc_speed;
+ rport_speed = rport->rpf.rpsc_speed;
+ if ((trl_enabled) && (rport_speed ==
+ BFA_PPORT_SPEED_UNKNOWN)) {
+ /* Use default ratelim speed setting */
+ rport_speed =
+ bfa_fcport_get_ratelim_speed(port->fcs->bfa);
+ }
+
+ if ((rport_speed == BFA_PPORT_SPEED_8GBPS) ||
+ (rport_speed > pport_speed)) {
+ max_speed = rport_speed;
break;
- } else if (rport->rpf.rpsc_speed > max_speed) {
- max_speed = rport->rpf.rpsc_speed;
+ } else if (rport_speed > max_speed) {
+ max_speed = rport_speed;
}
qe = bfa_q_next(qe);
diff --git a/drivers/scsi/bfa/ms.c b/drivers/scsi/bfa/ms.c
index 5e8c8dee6c9..1d579ef2612 100644
--- a/drivers/scsi/bfa/ms.c
+++ b/drivers/scsi/bfa/ms.c
@@ -157,6 +157,7 @@ bfa_fcs_port_ms_sm_plogi(struct bfa_fcs_port_ms_s *ms, enum port_ms_event event)
* Start timer for a delayed retry
*/
bfa_sm_set_state(ms, bfa_fcs_port_ms_sm_plogi_retry);
+ ms->port->stats.ms_retries++;
bfa_timer_start(BFA_FCS_GET_HAL_FROM_PORT(ms->port), &ms->timer,
bfa_fcs_port_ms_timeout, ms,
BFA_FCS_RETRY_TIMEOUT);
@@ -279,6 +280,7 @@ bfa_fcs_port_ms_sm_gmal(struct bfa_fcs_port_ms_s *ms, enum port_ms_event event)
*/
if (ms->retry_cnt++ < BFA_FCS_MS_CMD_MAX_RETRIES) {
bfa_sm_set_state(ms, bfa_fcs_port_ms_sm_gmal_retry);
+ ms->port->stats.ms_retries++;
bfa_timer_start(BFA_FCS_GET_HAL_FROM_PORT(ms->port),
&ms->timer, bfa_fcs_port_ms_timeout, ms,
BFA_FCS_RETRY_TIMEOUT);
@@ -359,7 +361,7 @@ bfa_fcs_port_ms_send_gmal(void *ms_cbarg, struct bfa_fcxp_s *fcxp_alloced)
bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE,
FC_CLASS_3, len, &fchs, bfa_fcs_port_ms_gmal_response,
- (void *)ms, FC_MAX_PDUSZ, FC_RA_TOV);
+ (void *)ms, FC_MAX_PDUSZ, FC_FCCT_TOV);
bfa_sm_send_event(ms, MSSM_EVENT_FCXP_SENT);
}
@@ -479,6 +481,7 @@ bfa_fcs_port_ms_sm_gfn(struct bfa_fcs_port_ms_s *ms, enum port_ms_event event)
*/
if (ms->retry_cnt++ < BFA_FCS_MS_CMD_MAX_RETRIES) {
bfa_sm_set_state(ms, bfa_fcs_port_ms_sm_gfn_retry);
+ ms->port->stats.ms_retries++;
bfa_timer_start(BFA_FCS_GET_HAL_FROM_PORT(ms->port),
&ms->timer, bfa_fcs_port_ms_timeout, ms,
BFA_FCS_RETRY_TIMEOUT);
@@ -557,7 +560,7 @@ bfa_fcs_port_ms_send_gfn(void *ms_cbarg, struct bfa_fcxp_s *fcxp_alloced)
bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE,
FC_CLASS_3, len, &fchs, bfa_fcs_port_ms_gfn_response,
- (void *)ms, FC_MAX_PDUSZ, FC_RA_TOV);
+ (void *)ms, FC_MAX_PDUSZ, FC_FCCT_TOV);
bfa_sm_send_event(ms, MSSM_EVENT_FCXP_SENT);
}
@@ -637,7 +640,7 @@ bfa_fcs_port_ms_send_plogi(void *ms_cbarg, struct bfa_fcxp_s *fcxp_alloced)
bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE,
FC_CLASS_3, len, &fchs, bfa_fcs_port_ms_plogi_response,
- (void *)ms, FC_MAX_PDUSZ, FC_RA_TOV);
+ (void *)ms, FC_MAX_PDUSZ, FC_ELS_TOV);
port->stats.ms_plogi_sent++;
bfa_sm_send_event(ms, MSSM_EVENT_FCXP_SENT);
diff --git a/drivers/scsi/bfa/ns.c b/drivers/scsi/bfa/ns.c
index d20dd7e1574..ae0edcc86ed 100644
--- a/drivers/scsi/bfa/ns.c
+++ b/drivers/scsi/bfa/ns.c
@@ -664,7 +664,7 @@ bfa_fcs_port_ns_send_plogi(void *ns_cbarg, struct bfa_fcxp_s *fcxp_alloced)
bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE,
FC_CLASS_3, len, &fchs, bfa_fcs_port_ns_plogi_response,
- (void *)ns, FC_MAX_PDUSZ, FC_RA_TOV);
+ (void *)ns, FC_MAX_PDUSZ, FC_ELS_TOV);
port->stats.ns_plogi_sent++;
bfa_sm_send_event(ns, NSSM_EVENT_PLOGI_SENT);
@@ -791,7 +791,7 @@ bfa_fcs_port_ns_send_rspn_id(void *ns_cbarg, struct bfa_fcxp_s *fcxp_alloced)
bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE,
FC_CLASS_3, len, &fchs, bfa_fcs_port_ns_rspn_id_response,
- (void *)ns, FC_MAX_PDUSZ, FC_RA_TOV);
+ (void *)ns, FC_MAX_PDUSZ, FC_FCCT_TOV);
port->stats.ns_rspnid_sent++;
@@ -865,7 +865,7 @@ bfa_fcs_port_ns_send_rft_id(void *ns_cbarg, struct bfa_fcxp_s *fcxp_alloced)
bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE,
FC_CLASS_3, len, &fchs, bfa_fcs_port_ns_rft_id_response,
- (void *)ns, FC_MAX_PDUSZ, FC_RA_TOV);
+ (void *)ns, FC_MAX_PDUSZ, FC_FCCT_TOV);
port->stats.ns_rftid_sent++;
bfa_sm_send_event(ns, NSSM_EVENT_RFTID_SENT);
@@ -943,7 +943,7 @@ bfa_fcs_port_ns_send_rff_id(void *ns_cbarg, struct bfa_fcxp_s *fcxp_alloced)
bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE,
FC_CLASS_3, len, &fchs, bfa_fcs_port_ns_rff_id_response,
- (void *)ns, FC_MAX_PDUSZ, FC_RA_TOV);
+ (void *)ns, FC_MAX_PDUSZ, FC_FCCT_TOV);
port->stats.ns_rffid_sent++;
bfa_sm_send_event(ns, NSSM_EVENT_RFFID_SENT);
@@ -1029,7 +1029,7 @@ bfa_fcs_port_ns_send_gid_ft(void *ns_cbarg, struct bfa_fcxp_s *fcxp_alloced)
bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE,
FC_CLASS_3, len, &fchs, bfa_fcs_port_ns_gid_ft_response,
(void *)ns, bfa_fcxp_get_maxrsp(port->fcs->bfa),
- FC_RA_TOV);
+ FC_FCCT_TOV);
port->stats.ns_gidft_sent++;
@@ -1228,10 +1228,10 @@ bfa_fcs_port_ns_boot_target_disc(struct bfa_fcs_port_s *port)
struct bfa_fcs_rport_s *rport;
u8 nwwns;
- wwn_t *wwns;
+ wwn_t wwns[BFA_PREBOOT_BOOTLUN_MAX];
int ii;
- bfa_iocfc_get_bootwwns(port->fcs->bfa, &nwwns, &wwns);
+ bfa_iocfc_get_bootwwns(port->fcs->bfa, &nwwns, wwns);
for (ii = 0; ii < nwwns; ++ii) {
rport = bfa_fcs_rport_create_by_wwn(port, wwns[ii]);
diff --git a/drivers/scsi/bfa/rport.c b/drivers/scsi/bfa/rport.c
index 7b096f2e383..9b4c2c9a644 100644
--- a/drivers/scsi/bfa/rport.c
+++ b/drivers/scsi/bfa/rport.c
@@ -36,8 +36,6 @@
BFA_TRC_FILE(FCS, RPORT);
-#define BFA_FCS_RPORT_MAX_RETRIES (5)
-
/* In millisecs */
static u32 bfa_fcs_rport_del_timeout =
BFA_FCS_RPORT_DEF_DEL_TIMEOUT * 1000;
@@ -95,6 +93,7 @@ static void bfa_fcs_rport_send_ls_rjt(struct bfa_fcs_rport_s *rport,
u8 reason_code_expl);
static void bfa_fcs_rport_process_adisc(struct bfa_fcs_rport_s *rport,
struct fchs_s *rx_fchs, u16 len);
+static void bfa_fcs_rport_send_prlo_acc(struct bfa_fcs_rport_s *rport);
/**
* fcs_rport_sm FCS rport state machine events
*/
@@ -115,7 +114,8 @@ enum rport_event {
RPSM_EVENT_HCB_OFFLINE = 13, /* BFA rport offline callback */
RPSM_EVENT_FC4_OFFLINE = 14, /* FC-4 offline complete */
RPSM_EVENT_ADDRESS_CHANGE = 15, /* Rport's PID has changed */
- RPSM_EVENT_ADDRESS_DISC = 16 /* Need to Discover rport's PID */
+ RPSM_EVENT_ADDRESS_DISC = 16, /* Need to Discover rport's PID */
+ RPSM_EVENT_PRLO_RCVD = 17, /* PRLO from remote device */
};
static void bfa_fcs_rport_sm_uninit(struct bfa_fcs_rport_s *rport,
@@ -356,8 +356,8 @@ bfa_fcs_rport_sm_plogi_retry(struct bfa_fcs_rport_s *rport,
*/
case RPSM_EVENT_TIMEOUT:
- rport->plogi_retries++;
if (rport->plogi_retries < BFA_FCS_RPORT_MAX_RETRIES) {
+ rport->plogi_retries++;
bfa_sm_set_state(rport, bfa_fcs_rport_sm_plogi_sending);
bfa_fcs_rport_send_plogi(rport, NULL);
} else {
@@ -375,6 +375,7 @@ bfa_fcs_rport_sm_plogi_retry(struct bfa_fcs_rport_s *rport,
bfa_fcs_rport_free(rport);
break;
+ case RPSM_EVENT_PRLO_RCVD:
case RPSM_EVENT_LOGO_RCVD:
break;
@@ -430,6 +431,13 @@ bfa_fcs_rport_sm_plogi(struct bfa_fcs_rport_s *rport, enum rport_event event)
case RPSM_EVENT_LOGO_RCVD:
bfa_fcs_rport_send_logo_acc(rport);
+ /*
+ * !! fall through !!
+ */
+ case RPSM_EVENT_PRLO_RCVD:
+ if (rport->prlo == BFA_TRUE)
+ bfa_fcs_rport_send_prlo_acc(rport);
+
bfa_fcxp_discard(rport->fcxp);
/*
* !! fall through !!
@@ -504,6 +512,9 @@ bfa_fcs_rport_sm_hal_online(struct bfa_fcs_rport_s *rport,
bfa_fcs_rport_online_action(rport);
break;
+ case RPSM_EVENT_PRLO_RCVD:
+ break;
+
case RPSM_EVENT_LOGO_RCVD:
bfa_sm_set_state(rport, bfa_fcs_rport_sm_hcb_logorcv);
bfa_rport_offline(rport->bfa_rport);
@@ -582,6 +593,7 @@ bfa_fcs_rport_sm_online(struct bfa_fcs_rport_s *rport, enum rport_event event)
break;
case RPSM_EVENT_LOGO_RCVD:
+ case RPSM_EVENT_PRLO_RCVD:
bfa_sm_set_state(rport, bfa_fcs_rport_sm_fc4_logorcv);
bfa_fcs_rport_offline_action(rport);
break;
@@ -624,6 +636,7 @@ bfa_fcs_rport_sm_nsquery_sending(struct bfa_fcs_rport_s *rport,
break;
case RPSM_EVENT_LOGO_RCVD:
+ case RPSM_EVENT_PRLO_RCVD:
bfa_sm_set_state(rport, bfa_fcs_rport_sm_fc4_logorcv);
bfa_fcxp_walloc_cancel(rport->fcs->bfa, &rport->fcxp_wqe);
bfa_fcs_rport_offline_action(rport);
@@ -690,6 +703,7 @@ bfa_fcs_rport_sm_nsquery(struct bfa_fcs_rport_s *rport, enum rport_event event)
break;
case RPSM_EVENT_LOGO_RCVD:
+ case RPSM_EVENT_PRLO_RCVD:
bfa_sm_set_state(rport, bfa_fcs_rport_sm_fc4_logorcv);
bfa_fcxp_discard(rport->fcxp);
bfa_fcs_rport_offline_action(rport);
@@ -740,6 +754,7 @@ bfa_fcs_rport_sm_adisc_sending(struct bfa_fcs_rport_s *rport,
break;
case RPSM_EVENT_LOGO_RCVD:
+ case RPSM_EVENT_PRLO_RCVD:
bfa_sm_set_state(rport, bfa_fcs_rport_sm_fc4_logorcv);
bfa_fcxp_walloc_cancel(rport->fcs->bfa, &rport->fcxp_wqe);
bfa_fcs_rport_offline_action(rport);
@@ -811,6 +826,7 @@ bfa_fcs_rport_sm_adisc(struct bfa_fcs_rport_s *rport, enum rport_event event)
break;
case RPSM_EVENT_LOGO_RCVD:
+ case RPSM_EVENT_PRLO_RCVD:
bfa_sm_set_state(rport, bfa_fcs_rport_sm_fc4_logorcv);
bfa_fcxp_discard(rport->fcxp);
bfa_fcs_rport_offline_action(rport);
@@ -843,6 +859,7 @@ bfa_fcs_rport_sm_fc4_logorcv(struct bfa_fcs_rport_s *rport,
break;
case RPSM_EVENT_LOGO_RCVD:
+ case RPSM_EVENT_PRLO_RCVD:
case RPSM_EVENT_ADDRESS_CHANGE:
break;
@@ -894,6 +911,7 @@ bfa_fcs_rport_sm_fc4_offline(struct bfa_fcs_rport_s *rport,
case RPSM_EVENT_SCN:
case RPSM_EVENT_LOGO_IMP:
case RPSM_EVENT_LOGO_RCVD:
+ case RPSM_EVENT_PRLO_RCVD:
case RPSM_EVENT_ADDRESS_CHANGE:
/**
* rport is already going offline.
@@ -953,6 +971,7 @@ bfa_fcs_rport_sm_hcb_offline(struct bfa_fcs_rport_s *rport,
case RPSM_EVENT_SCN:
case RPSM_EVENT_LOGO_RCVD:
+ case RPSM_EVENT_PRLO_RCVD:
/**
* Ignore, already offline.
*/
@@ -978,8 +997,11 @@ bfa_fcs_rport_sm_hcb_logorcv(struct bfa_fcs_rport_s *rport,
switch (event) {
case RPSM_EVENT_HCB_OFFLINE:
case RPSM_EVENT_ADDRESS_CHANGE:
- if (rport->pid)
+ if (rport->pid && (rport->prlo == BFA_TRUE))
+ bfa_fcs_rport_send_prlo_acc(rport);
+ if (rport->pid && (rport->prlo == BFA_FALSE))
bfa_fcs_rport_send_logo_acc(rport);
+
/*
* If the lport is online and if the rport is not a well known
* address port, we try to re-discover the r-port.
@@ -1013,6 +1035,7 @@ bfa_fcs_rport_sm_hcb_logorcv(struct bfa_fcs_rport_s *rport,
break;
case RPSM_EVENT_LOGO_RCVD:
+ case RPSM_EVENT_PRLO_RCVD:
/**
* Ignore - already processing a LOGO.
*/
@@ -1042,6 +1065,7 @@ bfa_fcs_rport_sm_hcb_logosend(struct bfa_fcs_rport_s *rport,
break;
case RPSM_EVENT_LOGO_RCVD:
+ case RPSM_EVENT_PRLO_RCVD:
case RPSM_EVENT_ADDRESS_CHANGE:
break;
@@ -1075,6 +1099,7 @@ bfa_fcs_rport_sm_logo_sending(struct bfa_fcs_rport_s *rport,
break;
case RPSM_EVENT_LOGO_RCVD:
+ case RPSM_EVENT_PRLO_RCVD:
bfa_sm_set_state(rport, bfa_fcs_rport_sm_uninit);
bfa_fcxp_walloc_cancel(rport->fcs->bfa, &rport->fcxp_wqe);
bfa_fcs_rport_free(rport);
@@ -1123,6 +1148,7 @@ bfa_fcs_rport_sm_offline(struct bfa_fcs_rport_s *rport, enum rport_event event)
break;
case RPSM_EVENT_LOGO_RCVD:
+ case RPSM_EVENT_PRLO_RCVD:
case RPSM_EVENT_LOGO_IMP:
break;
@@ -1174,6 +1200,7 @@ bfa_fcs_rport_sm_nsdisc_sending(struct bfa_fcs_rport_s *rport,
case RPSM_EVENT_SCN:
case RPSM_EVENT_LOGO_RCVD:
+ case RPSM_EVENT_PRLO_RCVD:
case RPSM_EVENT_PLOGI_SEND:
break;
@@ -1250,6 +1277,10 @@ bfa_fcs_rport_sm_nsdisc_retry(struct bfa_fcs_rport_s *rport,
bfa_fcs_rport_send_logo_acc(rport);
break;
+ case RPSM_EVENT_PRLO_RCVD:
+ bfa_fcs_rport_send_prlo_acc(rport);
+ break;
+
case RPSM_EVENT_PLOGI_COMP:
bfa_sm_set_state(rport, bfa_fcs_rport_sm_hal_online);
bfa_timer_stop(&rport->timer);
@@ -1322,6 +1353,10 @@ bfa_fcs_rport_sm_nsdisc_sent(struct bfa_fcs_rport_s *rport,
bfa_fcs_rport_del_timeout);
break;
+ case RPSM_EVENT_PRLO_RCVD:
+ bfa_fcs_rport_send_prlo_acc(rport);
+ break;
+
case RPSM_EVENT_SCN:
/**
* ignore, wait for NS query response
@@ -1378,7 +1413,7 @@ bfa_fcs_rport_send_plogi(void *rport_cbarg, struct bfa_fcxp_s *fcxp_alloced)
bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE,
FC_CLASS_3, len, &fchs, bfa_fcs_rport_plogi_response,
- (void *)rport, FC_MAX_PDUSZ, FC_RA_TOV);
+ (void *)rport, FC_MAX_PDUSZ, FC_ELS_TOV);
rport->stats.plogis++;
bfa_sm_send_event(rport, RPSM_EVENT_FCXP_SENT);
@@ -1519,7 +1554,7 @@ bfa_fcs_rport_send_adisc(void *rport_cbarg, struct bfa_fcxp_s *fcxp_alloced)
bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE,
FC_CLASS_3, len, &fchs, bfa_fcs_rport_adisc_response,
- rport, FC_MAX_PDUSZ, FC_RA_TOV);
+ rport, FC_MAX_PDUSZ, FC_ELS_TOV);
rport->stats.adisc_sent++;
bfa_sm_send_event(rport, RPSM_EVENT_FCXP_SENT);
@@ -1580,7 +1615,7 @@ bfa_fcs_rport_send_gidpn(void *rport_cbarg, struct bfa_fcxp_s *fcxp_alloced)
bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE,
FC_CLASS_3, len, &fchs, bfa_fcs_rport_gidpn_response,
- (void *)rport, FC_MAX_PDUSZ, FC_RA_TOV);
+ (void *)rport, FC_MAX_PDUSZ, FC_FCCT_TOV);
bfa_sm_send_event(rport, RPSM_EVENT_FCXP_SENT);
}
@@ -1692,7 +1727,7 @@ bfa_fcs_rport_send_logo(void *rport_cbarg, struct bfa_fcxp_s *fcxp_alloced)
bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE,
FC_CLASS_3, len, &fchs, NULL, rport, FC_MAX_PDUSZ,
- FC_ED_TOV);
+ FC_ELS_TOV);
rport->stats.logos++;
bfa_fcxp_discard(rport->fcxp);
@@ -2184,6 +2219,7 @@ bfa_fcs_rport_process_logo(struct bfa_fcs_rport_s *rport, struct fchs_s *fchs)
rport->reply_oxid = fchs->ox_id;
bfa_trc(rport->fcs, rport->reply_oxid);
+ rport->prlo = BFA_FALSE;
rport->stats.logo_rcvd++;
bfa_sm_send_event(rport, RPSM_EVENT_LOGO_RCVD);
}
@@ -2553,6 +2589,30 @@ bfa_fcs_rport_uf_recv(struct bfa_fcs_rport_s *rport, struct fchs_s *fchs,
}
}
+/* Send best case acc to prlo */
+static void
+bfa_fcs_rport_send_prlo_acc(struct bfa_fcs_rport_s *rport)
+{
+ struct bfa_fcs_port_s *port = rport->port;
+ struct fchs_s fchs;
+ struct bfa_fcxp_s *fcxp;
+ int len;
+
+ bfa_trc(rport->fcs, rport->pid);
+
+ fcxp = bfa_fcs_fcxp_alloc(port->fcs);
+ if (!fcxp)
+ return;
+
+ len = fc_prlo_acc_build(&fchs, bfa_fcxp_get_reqbuf(fcxp),
+ rport->pid, bfa_fcs_port_get_fcid(port),
+ rport->reply_oxid, 0);
+
+ bfa_fcxp_send(fcxp, rport->bfa_rport, port->fabric->vf_id,
+ port->lp_tag, BFA_FALSE, FC_CLASS_3, len, &fchs,
+ NULL, NULL, FC_MAX_PDUSZ, 0);
+}
+
/*
* Send a LS reject
*/
@@ -2604,3 +2664,13 @@ bfa_fcs_rport_set_del_timeout(u8 rport_tmo)
if (rport_tmo > 0)
bfa_fcs_rport_del_timeout = rport_tmo * 1000;
}
+
+void
+bfa_fcs_rport_prlo(struct bfa_fcs_rport_s *rport, uint16_t ox_id)
+{
+ bfa_trc(rport->fcs, rport->pid);
+
+ rport->prlo = BFA_TRUE;
+ rport->reply_oxid = ox_id;
+ bfa_sm_send_event(rport, RPSM_EVENT_PRLO_RCVD);
+}
diff --git a/drivers/scsi/bfa/rport_api.c b/drivers/scsi/bfa/rport_api.c
index a441f41d2a6..15e0c470afd 100644
--- a/drivers/scsi/bfa/rport_api.c
+++ b/drivers/scsi/bfa/rport_api.c
@@ -83,6 +83,7 @@ bfa_fcs_rport_get_attr(struct bfa_fcs_rport_s *rport,
{
struct bfa_rport_qos_attr_s qos_attr;
struct bfa_fcs_port_s *port = rport->port;
+ enum bfa_pport_speed rport_speed = rport->rpf.rpsc_speed;
bfa_os_memset(rport_attr, 0, sizeof(struct bfa_rport_attr_s));
@@ -102,10 +103,14 @@ bfa_fcs_rport_get_attr(struct bfa_fcs_rport_s *rport,
rport_attr->qos_attr = qos_attr;
rport_attr->trl_enforced = BFA_FALSE;
+
if (bfa_fcport_is_ratelim(port->fcs->bfa)) {
- if ((rport->rpf.rpsc_speed == BFA_PPORT_SPEED_UNKNOWN) ||
- (rport->rpf.rpsc_speed <
- bfa_fcs_port_get_rport_max_speed(port)))
+ if (rport_speed == BFA_PPORT_SPEED_UNKNOWN) {
+ /* Use default ratelim speed setting */
+ rport_speed =
+ bfa_fcport_get_ratelim_speed(rport->fcs->bfa);
+ }
+ if (rport_speed < bfa_fcs_port_get_rport_max_speed(port))
rport_attr->trl_enforced = BFA_TRUE;
}
diff --git a/drivers/scsi/bfa/rport_ftrs.c b/drivers/scsi/bfa/rport_ftrs.c
index ae7bba67ae2..f2a9361ce9a 100644
--- a/drivers/scsi/bfa/rport_ftrs.c
+++ b/drivers/scsi/bfa/rport_ftrs.c
@@ -73,6 +73,7 @@ static void
bfa_fcs_rpf_sm_uninit(struct bfa_fcs_rpf_s *rpf, enum rpf_event event)
{
struct bfa_fcs_rport_s *rport = rpf->rport;
+ struct bfa_fcs_fabric_s *fabric = &rport->fcs->fabric;
bfa_trc(rport->fcs, rport->pwwn);
bfa_trc(rport->fcs, rport->pid);
@@ -80,12 +81,16 @@ bfa_fcs_rpf_sm_uninit(struct bfa_fcs_rpf_s *rpf, enum rpf_event event)
switch (event) {
case RPFSM_EVENT_RPORT_ONLINE:
- if (!BFA_FCS_PID_IS_WKA(rport->pid)) {
+ /* Send RPSC2 to a Brocade fabric only. */
+ if ((!BFA_FCS_PID_IS_WKA(rport->pid)) &&
+ ((bfa_lps_is_brcd_fabric(rport->port->fabric->lps)) ||
+ (bfa_fcs_fabric_get_switch_oui(fabric) ==
+ BFA_FCS_BRCD_SWITCH_OUI))) {
bfa_sm_set_state(rpf, bfa_fcs_rpf_sm_rpsc_sending);
rpf->rpsc_retries = 0;
bfa_fcs_rpf_send_rpsc2(rpf, NULL);
- break;
- };
+ }
+ break;
case RPFSM_EVENT_RPORT_OFFLINE:
break;
@@ -269,6 +274,7 @@ void bfa_fcs_rpf_rport_offline(struct bfa_fcs_rport_s *rport)
if (__fcs_min_cfg(rport->port->fcs))
return;
+ rport->rpf.rpsc_speed = 0;
bfa_sm_send_event(&rport->rpf, RPFSM_EVENT_RPORT_OFFLINE);
}
@@ -307,7 +313,7 @@ bfa_fcs_rpf_send_rpsc2(void *rpf_cbarg, struct bfa_fcxp_s *fcxp_alloced)
bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE,
FC_CLASS_3, len, &fchs, bfa_fcs_rpf_rpsc2_response,
- rpf, FC_MAX_PDUSZ, FC_RA_TOV);
+ rpf, FC_MAX_PDUSZ, FC_ELS_TOV);
rport->stats.rpsc_sent++;
bfa_sm_send_event(rpf, RPFSM_EVENT_FCXP_SENT);
diff --git a/drivers/scsi/bfa/scn.c b/drivers/scsi/bfa/scn.c
index 8fe09ba88a9..8a60129e630 100644
--- a/drivers/scsi/bfa/scn.c
+++ b/drivers/scsi/bfa/scn.c
@@ -218,7 +218,7 @@ bfa_fcs_port_scn_send_scr(void *scn_cbarg, struct bfa_fcxp_s *fcxp_alloced)
bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE,
FC_CLASS_3, len, &fchs, bfa_fcs_port_scn_scr_response,
- (void *)scn, FC_MAX_PDUSZ, FC_RA_TOV);
+ (void *)scn, FC_MAX_PDUSZ, FC_ELS_TOV);
bfa_sm_send_event(scn, SCNSM_EVENT_SCR_SENT);
}
diff --git a/drivers/scsi/bfa/vport.c b/drivers/scsi/bfa/vport.c
index 27cd619a227..b378ec79d38 100644
--- a/drivers/scsi/bfa/vport.c
+++ b/drivers/scsi/bfa/vport.c
@@ -218,9 +218,9 @@ bfa_fcs_vport_sm_fdisc(struct bfa_fcs_vport_s *vport,
switch (event) {
case BFA_FCS_VPORT_SM_DELETE:
- bfa_sm_set_state(vport, bfa_fcs_vport_sm_logo);
+ bfa_sm_set_state(vport, bfa_fcs_vport_sm_cleanup);
bfa_lps_discard(vport->lps);
- bfa_fcs_vport_do_logo(vport);
+ bfa_fcs_port_delete(&vport->lport);
break;
case BFA_FCS_VPORT_SM_OFFLINE:
@@ -357,8 +357,9 @@ bfa_fcs_vport_sm_error(struct bfa_fcs_vport_s *vport,
switch (event) {
case BFA_FCS_VPORT_SM_DELETE:
- bfa_sm_set_state(vport, bfa_fcs_vport_sm_uninit);
- bfa_fcs_vport_free(vport);
+ bfa_sm_set_state(vport, bfa_fcs_vport_sm_cleanup);
+ bfa_fcs_port_delete(&vport->lport);
+
break;
default:
@@ -594,6 +595,15 @@ bfa_fcs_vport_cleanup(struct bfa_fcs_vport_s *vport)
}
/**
+ * delete notification from fabric SM. To be invoked from within FCS.
+ */
+void
+bfa_fcs_vport_fcs_delete(struct bfa_fcs_vport_s *vport)
+{
+ bfa_sm_send_event(vport, BFA_FCS_VPORT_SM_DELETE);
+}
+
+/**
* Delete completion callback from associated lport
*/
void
@@ -646,6 +656,7 @@ bfa_fcs_vport_create(struct bfa_fcs_vport_s *vport, struct bfa_fcs_s *fcs,
return BFA_STATUS_VPORT_MAX;
vport->vport_drv = vport_drv;
+ vport_cfg->preboot_vp = BFA_FALSE;
bfa_sm_set_state(vport, bfa_fcs_vport_sm_uninit);
bfa_fcs_lport_attach(&vport->lport, fcs, vf_id, vport);
@@ -657,6 +668,36 @@ bfa_fcs_vport_create(struct bfa_fcs_vport_s *vport, struct bfa_fcs_s *fcs,
}
/**
+ * Use this function to instantiate a new FCS PBC vport object. This
+ * function will not trigger any HW initialization process (which will be
+ * done in vport_start() call)
+ *
+ * param[in] vport - pointer to bfa_fcs_vport_t. This space
+ * needs to be allocated by the driver.
+ * param[in] fcs - FCS instance
+ * param[in] vport_cfg - vport configuration
+ * param[in] vf_id - VF_ID if vport is created within a VF.
+ * FC_VF_ID_NULL to specify base fabric.
+ * param[in] vport_drv - Opaque handle back to the driver's vport
+ * structure
+ *
+ * retval BFA_STATUS_OK - on success.
+ * retval BFA_STATUS_FAILED - on failure.
+ */
+bfa_status_t
+bfa_fcs_pbc_vport_create(struct bfa_fcs_vport_s *vport, struct bfa_fcs_s *fcs,
+ uint16_t vf_id, struct bfa_port_cfg_s *vport_cfg,
+ struct bfad_vport_s *vport_drv)
+{
+ bfa_status_t rc;
+
+ rc = bfa_fcs_vport_create(vport, fcs, vf_id, vport_cfg, vport_drv);
+ vport->lport.port_cfg.preboot_vp = BFA_TRUE;
+
+ return rc;
+}
+
+/**
* Use this function initialize the vport.
*
* @param[in] vport - pointer to bfa_fcs_vport_t.
@@ -692,6 +733,8 @@ bfa_fcs_vport_stop(struct bfa_fcs_vport_s *vport)
* Use this function to delete a vport object. Fabric object should
* be stopped before this function call.
*
+ * Donot invoke this from within FCS
+ *
* param[in] vport - pointer to bfa_fcs_vport_t.
*
* return None
@@ -699,6 +742,9 @@ bfa_fcs_vport_stop(struct bfa_fcs_vport_s *vport)
bfa_status_t
bfa_fcs_vport_delete(struct bfa_fcs_vport_s *vport)
{
+ if (vport->lport.port_cfg.preboot_vp)
+ return BFA_STATUS_PBC;
+
bfa_sm_send_event(vport, BFA_FCS_VPORT_SM_DELETE);
return BFA_STATUS_OK;
@@ -789,7 +835,7 @@ bfa_cb_lps_fdisc_comp(void *bfad, void *uarg, bfa_status_t status)
switch (status) {
case BFA_STATUS_OK:
/*
- * Initialiaze the V-Port fields
+ * Initialize the V-Port fields
*/
__vport_fcid(vport) = bfa_lps_get_pid(vport->lps);
vport->vport_stats.fdisc_accepts++;
diff --git a/drivers/scsi/bnx2i/bnx2i.h b/drivers/scsi/bnx2i/bnx2i.h
index 6b624e767d3..00c033511cb 100644
--- a/drivers/scsi/bnx2i/bnx2i.h
+++ b/drivers/scsi/bnx2i/bnx2i.h
@@ -295,16 +295,21 @@ struct iscsi_cid_queue {
* @max_cqes: CQ size
* @num_ccell: number of command cells per connection
* @ofld_conns_active: active connection list
+ * @eh_wait: wait queue for the endpoint to shutdown
* @max_active_conns: max offload connections supported by this device
* @cid_que: iscsi cid queue
* @ep_rdwr_lock: read / write lock to synchronize various ep lists
* @ep_ofld_list: connection list for pending offload completion
+ * @ep_active_list: connection list for active offload endpoints
* @ep_destroy_list: connection list for pending offload completion
* @mp_bd_tbl: BD table to be used with middle path requests
* @mp_bd_dma: DMA address of 'mp_bd_tbl' memory buffer
* @dummy_buffer: Dummy buffer to be used with zero length scsicmd reqs
* @dummy_buf_dma: DMA address of 'dummy_buffer' memory buffer
* @lock: lock to synchonize access to hba structure
+ * @hba_shutdown_tmo: Timeout value to shutdown each connection
+ * @conn_teardown_tmo: Timeout value to tear down each connection
+ * @conn_ctx_destroy_tmo: Timeout value to destroy context of each connection
* @pci_did: PCI device ID
* @pci_vid: PCI vendor ID
* @pci_sdid: PCI subsystem device ID
@@ -369,6 +374,7 @@ struct bnx2i_hba {
rwlock_t ep_rdwr_lock;
struct list_head ep_ofld_list;
+ struct list_head ep_active_list;
struct list_head ep_destroy_list;
/*
@@ -383,6 +389,8 @@ struct bnx2i_hba {
struct mutex net_dev_lock;/* sync net device access */
int hba_shutdown_tmo;
+ int conn_teardown_tmo;
+ int conn_ctx_destroy_tmo;
/*
* PCI related info.
*/
@@ -631,6 +639,8 @@ enum {
EP_STATE_CLEANUP_CMPL = 0x800,
EP_STATE_TCP_FIN_RCVD = 0x1000,
EP_STATE_TCP_RST_RCVD = 0x2000,
+ EP_STATE_LOGOUT_SENT = 0x4000,
+ EP_STATE_LOGOUT_RESP_RCVD = 0x8000,
EP_STATE_PG_OFLD_FAILED = 0x1000000,
EP_STATE_ULP_UPDATE_FAILED = 0x2000000,
EP_STATE_CLEANUP_FAILED = 0x4000000,
@@ -645,6 +655,7 @@ enum {
* @link: list head to link elements
* @hba: adapter to which this connection belongs
* @conn: iscsi connection this EP is linked to
+ * @cls_ep: associated iSCSI endpoint pointer
* @sess: iscsi session this EP is linked to
* @cm_sk: cnic sock struct
* @hba_age: age to detect if 'iscsid' issues ep_disconnect()
@@ -664,6 +675,7 @@ struct bnx2i_endpoint {
struct list_head link;
struct bnx2i_hba *hba;
struct bnx2i_conn *conn;
+ struct iscsi_endpoint *cls_ep;
struct cnic_sock *cm_sk;
u32 hba_age;
u32 state;
@@ -766,6 +778,8 @@ extern struct bnx2i_endpoint *bnx2i_find_ep_in_destroy_list(
extern int bnx2i_map_ep_dbell_regs(struct bnx2i_endpoint *ep);
extern void bnx2i_arm_cq_event_coalescing(struct bnx2i_endpoint *ep, u8 action);
+extern int bnx2i_hw_ep_disconnect(struct bnx2i_endpoint *bnx2i_ep);
+
/* Debug related function prototypes */
extern void bnx2i_print_pend_cmd_queue(struct bnx2i_conn *conn);
extern void bnx2i_print_active_cmd_queue(struct bnx2i_conn *conn);
diff --git a/drivers/scsi/bnx2i/bnx2i_hwi.c b/drivers/scsi/bnx2i/bnx2i_hwi.c
index 3a66ca24c7b..d23fc256d58 100644
--- a/drivers/scsi/bnx2i/bnx2i_hwi.c
+++ b/drivers/scsi/bnx2i/bnx2i_hwi.c
@@ -562,6 +562,8 @@ int bnx2i_send_iscsi_logout(struct bnx2i_conn *bnx2i_conn,
logout_wqe->num_bds = 1;
logout_wqe->cq_index = 0; /* CQ# used for completion, 5771x only */
+ bnx2i_conn->ep->state = EP_STATE_LOGOUT_SENT;
+
bnx2i_ring_dbell_update_sq_params(bnx2i_conn, 1);
return 0;
}
@@ -1482,6 +1484,8 @@ static int bnx2i_process_logout_resp(struct iscsi_session *session,
resp_hdr->t2retain = cpu_to_be32(logout->time_to_retain);
__iscsi_complete_pdu(conn, (struct iscsi_hdr *)resp_hdr, NULL, 0);
+
+ bnx2i_conn->ep->state = EP_STATE_LOGOUT_RESP_RCVD;
done:
spin_unlock(&session->lock);
return 0;
diff --git a/drivers/scsi/bnx2i/bnx2i_init.c b/drivers/scsi/bnx2i/bnx2i_init.c
index af6a00a600f..a796f565f38 100644
--- a/drivers/scsi/bnx2i/bnx2i_init.c
+++ b/drivers/scsi/bnx2i/bnx2i_init.c
@@ -17,8 +17,8 @@ static struct list_head adapter_list = LIST_HEAD_INIT(adapter_list);
static u32 adapter_count;
#define DRV_MODULE_NAME "bnx2i"
-#define DRV_MODULE_VERSION "2.1.1"
-#define DRV_MODULE_RELDATE "Mar 24, 2010"
+#define DRV_MODULE_VERSION "2.1.2"
+#define DRV_MODULE_RELDATE "Jun 28, 2010"
static char version[] __devinitdata =
"Broadcom NetXtreme II iSCSI Driver " DRV_MODULE_NAME \
@@ -176,6 +176,9 @@ void bnx2i_start(void *handle)
void bnx2i_stop(void *handle)
{
struct bnx2i_hba *hba = handle;
+ struct list_head *pos, *tmp;
+ struct bnx2i_endpoint *bnx2i_ep;
+ int conns_active;
/* check if cleanup happened in GOING_DOWN context */
if (!test_and_clear_bit(ADAPTER_STATE_GOING_DOWN,
@@ -187,9 +190,33 @@ void bnx2i_stop(void *handle)
* control returns to network driver. So it is required to cleanup and
* release all connection resources before returning from this routine.
*/
- wait_event_interruptible_timeout(hba->eh_wait,
- (hba->ofld_conns_active == 0),
- hba->hba_shutdown_tmo);
+ while (hba->ofld_conns_active) {
+ conns_active = hba->ofld_conns_active;
+ wait_event_interruptible_timeout(hba->eh_wait,
+ (hba->ofld_conns_active != conns_active),
+ hba->hba_shutdown_tmo);
+ if (hba->ofld_conns_active == conns_active)
+ break;
+ }
+ if (hba->ofld_conns_active) {
+ /* Stage to force the disconnection
+ * This is the case where the daemon is either slow or
+ * not present
+ */
+ printk(KERN_ALERT "bnx2i: Wait timeout, force all eps "
+ "to disconnect (%d)\n", hba->ofld_conns_active);
+ mutex_lock(&hba->net_dev_lock);
+ list_for_each_safe(pos, tmp, &hba->ep_active_list) {
+ bnx2i_ep = list_entry(pos, struct bnx2i_endpoint, link);
+ /* Clean up the chip only */
+ bnx2i_hw_ep_disconnect(bnx2i_ep);
+ }
+ mutex_unlock(&hba->net_dev_lock);
+ if (hba->ofld_conns_active)
+ printk(KERN_ERR "bnx2i: EP disconnect timeout (%d)!\n",
+ hba->ofld_conns_active);
+ }
+
/* This flag should be cleared last so that ep_disconnect() gracefully
* cleans up connection context
*/
diff --git a/drivers/scsi/bnx2i/bnx2i_iscsi.c b/drivers/scsi/bnx2i/bnx2i_iscsi.c
index fa68ab34b99..a46ccc380ab 100644
--- a/drivers/scsi/bnx2i/bnx2i_iscsi.c
+++ b/drivers/scsi/bnx2i/bnx2i_iscsi.c
@@ -386,6 +386,7 @@ static struct iscsi_endpoint *bnx2i_alloc_ep(struct bnx2i_hba *hba)
}
bnx2i_ep = ep->dd_data;
+ bnx2i_ep->cls_ep = ep;
INIT_LIST_HEAD(&bnx2i_ep->link);
bnx2i_ep->state = EP_STATE_IDLE;
bnx2i_ep->ep_iscsi_cid = (u16) -1;
@@ -678,7 +679,6 @@ bnx2i_find_ep_in_ofld_list(struct bnx2i_hba *hba, u32 iscsi_cid)
return ep;
}
-
/**
* bnx2i_find_ep_in_destroy_list - find iscsi_cid in destroy list
* @hba: pointer to adapter instance
@@ -709,6 +709,38 @@ bnx2i_find_ep_in_destroy_list(struct bnx2i_hba *hba, u32 iscsi_cid)
}
/**
+ * bnx2i_ep_active_list_add - add an entry to ep active list
+ * @hba: pointer to adapter instance
+ * @ep: pointer to endpoint (transport indentifier) structure
+ *
+ * current active conn queue manager
+ */
+static void bnx2i_ep_active_list_add(struct bnx2i_hba *hba,
+ struct bnx2i_endpoint *ep)
+{
+ write_lock_bh(&hba->ep_rdwr_lock);
+ list_add_tail(&ep->link, &hba->ep_active_list);
+ write_unlock_bh(&hba->ep_rdwr_lock);
+}
+
+
+/**
+ * bnx2i_ep_active_list_del - deletes an entry to ep active list
+ * @hba: pointer to adapter instance
+ * @ep: pointer to endpoint (transport indentifier) structure
+ *
+ * current active conn queue manager
+ */
+static void bnx2i_ep_active_list_del(struct bnx2i_hba *hba,
+ struct bnx2i_endpoint *ep)
+{
+ write_lock_bh(&hba->ep_rdwr_lock);
+ list_del_init(&ep->link);
+ write_unlock_bh(&hba->ep_rdwr_lock);
+}
+
+
+/**
* bnx2i_setup_host_queue_size - assigns shost->can_queue param
* @hba: pointer to adapter instance
* @shost: scsi host pointer
@@ -784,6 +816,7 @@ struct bnx2i_hba *bnx2i_alloc_hba(struct cnic_dev *cnic)
goto mp_bdt_mem_err;
INIT_LIST_HEAD(&hba->ep_ofld_list);
+ INIT_LIST_HEAD(&hba->ep_active_list);
INIT_LIST_HEAD(&hba->ep_destroy_list);
rwlock_init(&hba->ep_rdwr_lock);
@@ -821,10 +854,15 @@ struct bnx2i_hba *bnx2i_alloc_hba(struct cnic_dev *cnic)
spin_lock_init(&hba->lock);
mutex_init(&hba->net_dev_lock);
init_waitqueue_head(&hba->eh_wait);
- if (test_bit(BNX2I_NX2_DEV_57710, &hba->cnic_dev_type))
- hba->hba_shutdown_tmo = 240 * HZ;
- else /* 5706/5708/5709 */
- hba->hba_shutdown_tmo = 30 * HZ;
+ if (test_bit(BNX2I_NX2_DEV_57710, &hba->cnic_dev_type)) {
+ hba->hba_shutdown_tmo = 20 * HZ;
+ hba->conn_teardown_tmo = 20 * HZ;
+ hba->conn_ctx_destroy_tmo = 6 * HZ;
+ } else { /* 5706/5708/5709 */
+ hba->hba_shutdown_tmo = 20 * HZ;
+ hba->conn_teardown_tmo = 10 * HZ;
+ hba->conn_ctx_destroy_tmo = 2 * HZ;
+ }
if (iscsi_host_add(shost, &hba->pcidev->dev))
goto free_dump_mem;
@@ -857,6 +895,7 @@ void bnx2i_free_hba(struct bnx2i_hba *hba)
iscsi_host_remove(shost);
INIT_LIST_HEAD(&hba->ep_ofld_list);
+ INIT_LIST_HEAD(&hba->ep_active_list);
INIT_LIST_HEAD(&hba->ep_destroy_list);
pci_dev_put(hba->pcidev);
@@ -1461,6 +1500,26 @@ static int bnx2i_host_get_param(struct Scsi_Host *shost,
case ISCSI_HOST_PARAM_NETDEV_NAME:
len = sprintf(buf, "%s\n", hba->netdev->name);
break;
+ case ISCSI_HOST_PARAM_IPADDRESS: {
+ struct list_head *active_list = &hba->ep_active_list;
+
+ read_lock_bh(&hba->ep_rdwr_lock);
+ if (!list_empty(&hba->ep_active_list)) {
+ struct bnx2i_endpoint *bnx2i_ep;
+ struct cnic_sock *csk;
+
+ bnx2i_ep = list_first_entry(active_list,
+ struct bnx2i_endpoint,
+ link);
+ csk = bnx2i_ep->cm_sk;
+ if (test_bit(SK_F_IPV6, &csk->flags))
+ len = sprintf(buf, "%pI6\n", csk->src_ip);
+ else
+ len = sprintf(buf, "%pI4\n", csk->src_ip);
+ }
+ read_unlock_bh(&hba->ep_rdwr_lock);
+ break;
+ }
default:
return iscsi_host_get_param(shost, param, buf);
}
@@ -1599,7 +1658,7 @@ static int bnx2i_tear_down_conn(struct bnx2i_hba *hba,
ep->state = EP_STATE_CLEANUP_START;
init_timer(&ep->ofld_timer);
- ep->ofld_timer.expires = 10*HZ + jiffies;
+ ep->ofld_timer.expires = hba->conn_ctx_destroy_tmo + jiffies;
ep->ofld_timer.function = bnx2i_ep_ofld_timer;
ep->ofld_timer.data = (unsigned long) ep;
add_timer(&ep->ofld_timer);
@@ -1665,10 +1724,11 @@ static struct iscsi_endpoint *bnx2i_ep_connect(struct Scsi_Host *shost,
if (!hba || test_bit(ADAPTER_STATE_GOING_DOWN, &hba->adapter_state)) {
rc = -EINVAL;
- goto check_busy;
+ goto nohba;
}
cnic = hba->cnic;
+ mutex_lock(&hba->net_dev_lock);
ep = bnx2i_alloc_ep(hba);
if (!ep) {
rc = -ENOMEM;
@@ -1676,7 +1736,6 @@ static struct iscsi_endpoint *bnx2i_ep_connect(struct Scsi_Host *shost,
}
bnx2i_ep = ep->dd_data;
- mutex_lock(&hba->net_dev_lock);
if (bnx2i_adapter_ready(hba)) {
rc = -EPERM;
goto net_if_down;
@@ -1754,15 +1813,19 @@ static struct iscsi_endpoint *bnx2i_ep_connect(struct Scsi_Host *shost,
goto conn_failed;
} else
rc = cnic->cm_connect(bnx2i_ep->cm_sk, &saddr);
-
if (rc)
goto release_ep;
+ bnx2i_ep_active_list_add(hba, bnx2i_ep);
+
if (bnx2i_map_ep_dbell_regs(bnx2i_ep))
- goto release_ep;
+ goto del_active_ep;
+
mutex_unlock(&hba->net_dev_lock);
return ep;
+del_active_ep:
+ bnx2i_ep_active_list_del(hba, bnx2i_ep);
release_ep:
if (bnx2i_tear_down_conn(hba, bnx2i_ep)) {
mutex_unlock(&hba->net_dev_lock);
@@ -1774,8 +1837,9 @@ iscsi_cid_err:
bnx2i_free_qp_resc(hba, bnx2i_ep);
qp_resc_err:
bnx2i_free_ep(ep);
- mutex_unlock(&hba->net_dev_lock);
check_busy:
+ mutex_unlock(&hba->net_dev_lock);
+nohba:
bnx2i_unreg_dev_all();
return ERR_PTR(rc);
}
@@ -1846,6 +1910,8 @@ static int bnx2i_ep_tcp_conn_active(struct bnx2i_endpoint *bnx2i_ep)
case EP_STATE_ULP_UPDATE_START:
case EP_STATE_ULP_UPDATE_COMPL:
case EP_STATE_TCP_FIN_RCVD:
+ case EP_STATE_LOGOUT_SENT:
+ case EP_STATE_LOGOUT_RESP_RCVD:
case EP_STATE_ULP_UPDATE_FAILED:
ret = 1;
break;
@@ -1866,9 +1932,96 @@ static int bnx2i_ep_tcp_conn_active(struct bnx2i_endpoint *bnx2i_ep)
}
+/*
+ * bnx2i_hw_ep_disconnect - executes TCP connection teardown process in the hw
+ * @ep: TCP connection (bnx2i endpoint) handle
+ *
+ * executes TCP connection teardown process
+ */
+int bnx2i_hw_ep_disconnect(struct bnx2i_endpoint *bnx2i_ep)
+{
+ struct bnx2i_hba *hba = bnx2i_ep->hba;
+ struct cnic_dev *cnic;
+ struct iscsi_session *session = NULL;
+ struct iscsi_conn *conn = NULL;
+ int ret = 0;
+ int close = 0;
+ int close_ret = 0;
+
+ if (!hba)
+ return 0;
+
+ cnic = hba->cnic;
+ if (!cnic)
+ return 0;
+
+ if (!bnx2i_ep_tcp_conn_active(bnx2i_ep))
+ goto destroy_conn;
+
+ if (bnx2i_ep->conn) {
+ conn = bnx2i_ep->conn->cls_conn->dd_data;
+ session = conn->session;
+ }
+
+ init_timer(&bnx2i_ep->ofld_timer);
+ bnx2i_ep->ofld_timer.expires = hba->conn_teardown_tmo + jiffies;
+ bnx2i_ep->ofld_timer.function = bnx2i_ep_ofld_timer;
+ bnx2i_ep->ofld_timer.data = (unsigned long) bnx2i_ep;
+ add_timer(&bnx2i_ep->ofld_timer);
+
+ if (!test_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic))
+ goto out;
+
+ if (session) {
+ spin_lock_bh(&session->lock);
+ if (bnx2i_ep->state != EP_STATE_TCP_FIN_RCVD) {
+ if (session->state == ISCSI_STATE_LOGGING_OUT) {
+ if (bnx2i_ep->state == EP_STATE_LOGOUT_SENT) {
+ /* Logout sent, but no resp */
+ printk(KERN_ALERT "bnx2i - WARNING "
+ "logout response was not "
+ "received!\n");
+ } else if (bnx2i_ep->state ==
+ EP_STATE_LOGOUT_RESP_RCVD)
+ close = 1;
+ }
+ } else
+ close = 1;
+
+ spin_unlock_bh(&session->lock);
+ }
+
+ bnx2i_ep->state = EP_STATE_DISCONN_START;
+
+ if (close)
+ close_ret = cnic->cm_close(bnx2i_ep->cm_sk);
+ else
+ close_ret = cnic->cm_abort(bnx2i_ep->cm_sk);
+
+ if (close_ret)
+ bnx2i_ep->state = EP_STATE_DISCONN_COMPL;
+
+ /* wait for option-2 conn teardown */
+ wait_event_interruptible(bnx2i_ep->ofld_wait,
+ bnx2i_ep->state != EP_STATE_DISCONN_START);
+
+ if (signal_pending(current))
+ flush_signals(current);
+ del_timer_sync(&bnx2i_ep->ofld_timer);
+
+destroy_conn:
+ bnx2i_ep_active_list_del(hba, bnx2i_ep);
+ if (bnx2i_tear_down_conn(hba, bnx2i_ep))
+ ret = -EINVAL;
+out:
+ bnx2i_ep->state = EP_STATE_IDLE;
+ return ret;
+}
+
+
/**
* bnx2i_ep_disconnect - executes TCP connection teardown process
- * @ep: TCP connection (endpoint) handle
+ * @ep: TCP connection (iscsi endpoint) handle
*
* executes TCP connection teardown process
*/
@@ -1876,9 +2029,7 @@ static void bnx2i_ep_disconnect(struct iscsi_endpoint *ep)
{
struct bnx2i_endpoint *bnx2i_ep;
struct bnx2i_conn *bnx2i_conn = NULL;
- struct iscsi_session *session = NULL;
- struct iscsi_conn *conn;
- struct cnic_dev *cnic;
+ struct iscsi_conn *conn = NULL;
struct bnx2i_hba *hba;
bnx2i_ep = ep->dd_data;
@@ -1894,72 +2045,34 @@ static void bnx2i_ep_disconnect(struct iscsi_endpoint *ep)
if (bnx2i_ep->conn) {
bnx2i_conn = bnx2i_ep->conn;
conn = bnx2i_conn->cls_conn->dd_data;
- session = conn->session;
-
iscsi_suspend_queue(conn);
}
-
hba = bnx2i_ep->hba;
- if (bnx2i_ep->state == EP_STATE_IDLE)
- goto return_bnx2i_ep;
- cnic = hba->cnic;
mutex_lock(&hba->net_dev_lock);
+ if (bnx2i_ep->state == EP_STATE_IDLE)
+ goto return_bnx2i_ep;
+
if (!test_bit(ADAPTER_STATE_UP, &hba->adapter_state))
goto free_resc;
- if (bnx2i_ep->hba_age != hba->age)
- goto free_resc;
-
- if (!bnx2i_ep_tcp_conn_active(bnx2i_ep))
- goto destory_conn;
-
- bnx2i_ep->state = EP_STATE_DISCONN_START;
-
- init_timer(&bnx2i_ep->ofld_timer);
- bnx2i_ep->ofld_timer.expires = 10*HZ + jiffies;
- bnx2i_ep->ofld_timer.function = bnx2i_ep_ofld_timer;
- bnx2i_ep->ofld_timer.data = (unsigned long) bnx2i_ep;
- add_timer(&bnx2i_ep->ofld_timer);
- if (test_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic)) {
- int close = 0;
-
- if (session) {
- spin_lock_bh(&session->lock);
- if (session->state == ISCSI_STATE_LOGGING_OUT)
- close = 1;
- spin_unlock_bh(&session->lock);
- }
- if (close)
- cnic->cm_close(bnx2i_ep->cm_sk);
- else
- cnic->cm_abort(bnx2i_ep->cm_sk);
- } else
+ if (bnx2i_ep->hba_age != hba->age)
goto free_resc;
- /* wait for option-2 conn teardown */
- wait_event_interruptible(bnx2i_ep->ofld_wait,
- bnx2i_ep->state != EP_STATE_DISCONN_START);
-
- if (signal_pending(current))
- flush_signals(current);
- del_timer_sync(&bnx2i_ep->ofld_timer);
-
-destory_conn:
- if (bnx2i_tear_down_conn(hba, bnx2i_ep)) {
+ /* Do all chip cleanup here */
+ if (bnx2i_hw_ep_disconnect(bnx2i_ep)) {
mutex_unlock(&hba->net_dev_lock);
return;
}
free_resc:
- mutex_unlock(&hba->net_dev_lock);
bnx2i_free_qp_resc(hba, bnx2i_ep);
return_bnx2i_ep:
if (bnx2i_conn)
bnx2i_conn->ep = NULL;
bnx2i_free_ep(ep);
-
+ mutex_unlock(&hba->net_dev_lock);
if (!hba->ofld_conns_active)
bnx2i_unreg_dev_all();
@@ -2038,7 +2151,8 @@ struct iscsi_transport bnx2i_iscsi_transport = {
ISCSI_LU_RESET_TMO | ISCSI_TGT_RESET_TMO |
ISCSI_PING_TMO | ISCSI_RECV_TMO |
ISCSI_IFACE_NAME | ISCSI_INITIATOR_NAME,
- .host_param_mask = ISCSI_HOST_HWADDRESS | ISCSI_HOST_NETDEV_NAME,
+ .host_param_mask = ISCSI_HOST_HWADDRESS | ISCSI_HOST_IPADDRESS |
+ ISCSI_HOST_NETDEV_NAME,
.create_session = bnx2i_session_create,
.destroy_session = bnx2i_session_destroy,
.create_conn = bnx2i_conn_create,
diff --git a/drivers/scsi/cxgb3i/cxgb3i_ddp.c b/drivers/scsi/cxgb3i/cxgb3i_ddp.c
index b58d9134ac1..be0e23042c7 100644
--- a/drivers/scsi/cxgb3i/cxgb3i_ddp.c
+++ b/drivers/scsi/cxgb3i/cxgb3i_ddp.c
@@ -499,6 +499,7 @@ static int setup_conn_pgidx(struct t3cdev *tdev, unsigned int tid, int pg_idx,
/* set up ulp submode and page size */
req = (struct cpl_set_tcb_field *)skb_put(skb, sizeof(*req));
req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD));
+ req->wr.wr_lo = 0;
OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_SET_TCB_FIELD, tid));
req->reply = V_NO_REPLY(reply ? 0 : 1);
req->cpu_idx = 0;
@@ -564,6 +565,7 @@ int cxgb3i_setup_conn_digest(struct t3cdev *tdev, unsigned int tid,
/* set up ulp submode and page size */
req = (struct cpl_set_tcb_field *)skb_put(skb, sizeof(*req));
req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD));
+ req->wr.wr_lo = 0;
OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_SET_TCB_FIELD, tid));
req->reply = V_NO_REPLY(reply ? 0 : 1);
req->cpu_idx = 0;
diff --git a/drivers/scsi/cxgb3i/cxgb3i_offload.c b/drivers/scsi/cxgb3i/cxgb3i_offload.c
index a175be9c496..3ee13cf9556 100644
--- a/drivers/scsi/cxgb3i/cxgb3i_offload.c
+++ b/drivers/scsi/cxgb3i/cxgb3i_offload.c
@@ -264,6 +264,7 @@ static void make_act_open_req(struct s3_conn *c3cn, struct sk_buff *skb,
skb->priority = CPL_PRIORITY_SETUP;
req = (struct cpl_act_open_req *)__skb_put(skb, sizeof(*req));
req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD));
+ req->wr.wr_lo = 0;
OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_ACT_OPEN_REQ, atid));
req->local_port = c3cn->saddr.sin_port;
req->peer_port = c3cn->daddr.sin_port;
@@ -273,6 +274,7 @@ static void make_act_open_req(struct s3_conn *c3cn, struct sk_buff *skb,
V_TX_CHANNEL(e->smt_idx));
req->opt0l = htonl(calc_opt0l(c3cn));
req->params = 0;
+ req->opt2 = 0;
}
static void fail_act_open(struct s3_conn *c3cn, int errno)
@@ -379,6 +381,7 @@ static void send_abort_req(struct s3_conn *c3cn)
c3cn->cpl_abort_req = NULL;
req = (struct cpl_abort_req *)skb->head;
+ memset(req, 0, sizeof(*req));
skb->priority = CPL_PRIORITY_DATA;
set_arp_failure_handler(skb, abort_arp_failure);
@@ -406,6 +409,7 @@ static void send_abort_rpl(struct s3_conn *c3cn, int rst_status)
c3cn->cpl_abort_rpl = NULL;
skb->priority = CPL_PRIORITY_DATA;
+ memset(rpl, 0, sizeof(*rpl));
rpl->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_OFLD_HOST_ABORT_CON_RPL));
rpl->wr.wr_lo = htonl(V_WR_TID(c3cn->tid));
OPCODE_TID(rpl) = htonl(MK_OPCODE_TID(CPL_ABORT_RPL, c3cn->tid));
@@ -430,6 +434,7 @@ static u32 send_rx_credits(struct s3_conn *c3cn, u32 credits, u32 dack)
req = (struct cpl_rx_data_ack *)__skb_put(skb, sizeof(*req));
req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD));
+ req->wr.wr_lo = 0;
OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_RX_DATA_ACK, c3cn->tid));
req->credit_dack = htonl(dack | V_RX_CREDITS(credits));
skb->priority = CPL_PRIORITY_ACK;
@@ -1587,7 +1592,7 @@ cxgb3i_find_dev(struct net_device *dev, __be32 ipaddr)
err = ip_route_output_key(dev ? dev_net(dev) : &init_net, &rt, &fl);
if (!err)
- return (&rt->u.dst)->dev;
+ return (&rt->dst)->dev;
return NULL;
}
@@ -1649,7 +1654,7 @@ int cxgb3i_c3cn_connect(struct net_device *dev, struct s3_conn *c3cn,
c3cn->saddr.sin_addr.s_addr = rt->rt_src;
/* now commit destination to connection */
- c3cn->dst_cache = &rt->u.dst;
+ c3cn->dst_cache = &rt->dst;
/* try to establish an offloaded connection */
dev = cxgb3_egress_dev(c3cn->dst_cache->dev, c3cn, 0);
diff --git a/drivers/scsi/device_handler/scsi_dh_rdac.c b/drivers/scsi/device_handler/scsi_dh_rdac.c
index 5b683e42954..b9bcfa4c7d2 100644
--- a/drivers/scsi/device_handler/scsi_dh_rdac.c
+++ b/drivers/scsi/device_handler/scsi_dh_rdac.c
@@ -768,6 +768,7 @@ static const struct scsi_dh_devlist rdac_dev_list[] = {
{"DELL", "MD3000i"},
{"DELL", "MD32xx"},
{"DELL", "MD32xxi"},
+ {"DELL", "MD36xxi"},
{"LSI", "INF-01-00"},
{"ENGENIO", "INF-01-00"},
{"STK", "FLEXLINE 380"},
diff --git a/drivers/scsi/dpt_i2o.c b/drivers/scsi/dpt_i2o.c
index b0c576f84b2..ffc1edf5e80 100644
--- a/drivers/scsi/dpt_i2o.c
+++ b/drivers/scsi/dpt_i2o.c
@@ -1290,7 +1290,7 @@ static int adpt_i2o_post_wait(adpt_hba* pHba, u32* msg, int len, int timeout)
ulong flags = 0;
struct adpt_i2o_post_wait_data *p1, *p2;
struct adpt_i2o_post_wait_data *wait_data =
- kmalloc(sizeof(struct adpt_i2o_post_wait_data),GFP_KERNEL);
+ kmalloc(sizeof(struct adpt_i2o_post_wait_data), GFP_ATOMIC);
DECLARE_WAITQUEUE(wait, current);
if (!wait_data)
@@ -2640,6 +2640,13 @@ static s32 adpt_i2o_reparse_lct(adpt_hba* pHba)
continue;
}
bus_no = buf[0]>>16;
+ if (bus_no >= MAX_CHANNEL) { /* Something wrong skip it */
+ printk(KERN_WARNING
+ "%s: Channel number %d out of range\n",
+ pHba->name, bus_no);
+ continue;
+ }
+
scsi_id = buf[1];
scsi_lun = (buf[2]>>8 )&0xff;
pDev = pHba->channel[bus_no].device[scsi_id];
@@ -2651,7 +2658,8 @@ static s32 adpt_i2o_reparse_lct(adpt_hba* pHba)
pDev = pDev->next_lun;
}
if(!pDev ) { // Something new add it
- d = kmalloc(sizeof(struct i2o_device), GFP_KERNEL);
+ d = kmalloc(sizeof(struct i2o_device),
+ GFP_ATOMIC);
if(d==NULL)
{
printk(KERN_CRIT "Out of memory for I2O device data.\n");
@@ -2667,13 +2675,11 @@ static s32 adpt_i2o_reparse_lct(adpt_hba* pHba)
adpt_i2o_report_hba_unit(pHba, d);
adpt_i2o_install_device(pHba, d);
- if(bus_no >= MAX_CHANNEL) { // Something wrong skip it
- printk(KERN_WARNING"%s: Channel number %d out of range \n", pHba->name, bus_no);
- continue;
- }
pDev = pHba->channel[bus_no].device[scsi_id];
if( pDev == NULL){
- pDev = kzalloc(sizeof(struct adpt_device),GFP_KERNEL);
+ pDev =
+ kzalloc(sizeof(struct adpt_device),
+ GFP_ATOMIC);
if(pDev == NULL) {
return -ENOMEM;
}
@@ -2682,7 +2688,9 @@ static s32 adpt_i2o_reparse_lct(adpt_hba* pHba)
while (pDev->next_lun) {
pDev = pDev->next_lun;
}
- pDev = pDev->next_lun = kzalloc(sizeof(struct adpt_device),GFP_KERNEL);
+ pDev = pDev->next_lun =
+ kzalloc(sizeof(struct adpt_device),
+ GFP_ATOMIC);
if(pDev == NULL) {
return -ENOMEM;
}
@@ -3127,7 +3135,7 @@ static int adpt_i2o_lct_get(adpt_hba* pHba)
if (pHba->lct == NULL) {
pHba->lct = dma_alloc_coherent(&pHba->pDev->dev,
pHba->lct_size, &pHba->lct_pa,
- GFP_KERNEL);
+ GFP_ATOMIC);
if(pHba->lct == NULL) {
printk(KERN_CRIT "%s: Lct Get failed. Out of memory.\n",
pHba->name);
diff --git a/drivers/scsi/fcoe/fcoe.c b/drivers/scsi/fcoe/fcoe.c
index 44a07593de5..844d618b84b 100644
--- a/drivers/scsi/fcoe/fcoe.c
+++ b/drivers/scsi/fcoe/fcoe.c
@@ -117,9 +117,14 @@ static void fcoe_recv_frame(struct sk_buff *skb);
static void fcoe_get_lesb(struct fc_lport *, struct fc_els_lesb *);
-module_param_call(create, fcoe_create, NULL, NULL, S_IWUSR);
+module_param_call(create, fcoe_create, NULL, (void *)FIP_MODE_AUTO, S_IWUSR);
__MODULE_PARM_TYPE(create, "string");
MODULE_PARM_DESC(create, " Creates fcoe instance on a ethernet interface");
+module_param_call(create_vn2vn, fcoe_create, NULL,
+ (void *)FIP_MODE_VN2VN, S_IWUSR);
+__MODULE_PARM_TYPE(create_vn2vn, "string");
+MODULE_PARM_DESC(create_vn2vn, " Creates a VN_node to VN_node FCoE instance "
+ "on an Ethernet interface");
module_param_call(destroy, fcoe_destroy, NULL, NULL, S_IWUSR);
__MODULE_PARM_TYPE(destroy, "string");
MODULE_PARM_DESC(destroy, " Destroys fcoe instance on a ethernet interface");
@@ -315,7 +320,11 @@ static int fcoe_interface_setup(struct fcoe_interface *fcoe,
dev_uc_add(netdev, flogi_maddr);
if (fip->spma)
dev_uc_add(netdev, fip->ctl_src_addr);
- dev_mc_add(netdev, FIP_ALL_ENODE_MACS);
+ if (fip->mode == FIP_MODE_VN2VN) {
+ dev_mc_add(netdev, FIP_ALL_VN2VN_MACS);
+ dev_mc_add(netdev, FIP_ALL_P2P_MACS);
+ } else
+ dev_mc_add(netdev, FIP_ALL_ENODE_MACS);
/*
* setup the receive function from ethernet driver
@@ -337,10 +346,12 @@ static int fcoe_interface_setup(struct fcoe_interface *fcoe,
/**
* fcoe_interface_create() - Create a FCoE interface on a net device
* @netdev: The net device to create the FCoE interface on
+ * @fip_mode: The mode to use for FIP
*
* Returns: pointer to a struct fcoe_interface or NULL on error
*/
-static struct fcoe_interface *fcoe_interface_create(struct net_device *netdev)
+static struct fcoe_interface *fcoe_interface_create(struct net_device *netdev,
+ enum fip_state fip_mode)
{
struct fcoe_interface *fcoe;
int err;
@@ -357,7 +368,7 @@ static struct fcoe_interface *fcoe_interface_create(struct net_device *netdev)
/*
* Initialize FIP.
*/
- fcoe_ctlr_init(&fcoe->ctlr);
+ fcoe_ctlr_init(&fcoe->ctlr, fip_mode);
fcoe->ctlr.send = fcoe_fip_send;
fcoe->ctlr.update_mac = fcoe_update_src_mac;
fcoe->ctlr.get_src_addr = fcoe_get_src_mac;
@@ -401,7 +412,11 @@ void fcoe_interface_cleanup(struct fcoe_interface *fcoe)
dev_uc_del(netdev, flogi_maddr);
if (fip->spma)
dev_uc_del(netdev, fip->ctl_src_addr);
- dev_mc_del(netdev, FIP_ALL_ENODE_MACS);
+ if (fip->mode == FIP_MODE_VN2VN) {
+ dev_mc_del(netdev, FIP_ALL_VN2VN_MACS);
+ dev_mc_del(netdev, FIP_ALL_P2P_MACS);
+ } else
+ dev_mc_del(netdev, FIP_ALL_ENODE_MACS);
/* Tell the LLD we are done w/ FCoE */
ops = netdev->netdev_ops;
@@ -574,6 +589,50 @@ static int fcoe_get_wwn(struct net_device *netdev, u64 *wwn, int type)
}
/**
+ * fcoe_netdev_features_change - Updates the lport's offload flags based
+ * on the LLD netdev's FCoE feature flags
+ */
+static void fcoe_netdev_features_change(struct fc_lport *lport,
+ struct net_device *netdev)
+{
+ mutex_lock(&lport->lp_mutex);
+
+ if (netdev->features & NETIF_F_SG)
+ lport->sg_supp = 1;
+ else
+ lport->sg_supp = 0;
+
+ if (netdev->features & NETIF_F_FCOE_CRC) {
+ lport->crc_offload = 1;
+ FCOE_NETDEV_DBG(netdev, "Supports FCCRC offload\n");
+ } else {
+ lport->crc_offload = 0;
+ }
+
+ if (netdev->features & NETIF_F_FSO) {
+ lport->seq_offload = 1;
+ lport->lso_max = netdev->gso_max_size;
+ FCOE_NETDEV_DBG(netdev, "Supports LSO for max len 0x%x\n",
+ lport->lso_max);
+ } else {
+ lport->seq_offload = 0;
+ lport->lso_max = 0;
+ }
+
+ if (netdev->fcoe_ddp_xid) {
+ lport->lro_enabled = 1;
+ lport->lro_xid = netdev->fcoe_ddp_xid;
+ FCOE_NETDEV_DBG(netdev, "Supports LRO for max xid 0x%x\n",
+ lport->lro_xid);
+ } else {
+ lport->lro_enabled = 0;
+ lport->lro_xid = 0;
+ }
+
+ mutex_unlock(&lport->lp_mutex);
+}
+
+/**
* fcoe_netdev_config() - Set up net devive for SW FCoE
* @lport: The local port that is associated with the net device
* @netdev: The associated net device
@@ -588,7 +647,6 @@ static int fcoe_netdev_config(struct fc_lport *lport, struct net_device *netdev)
u64 wwnn, wwpn;
struct fcoe_interface *fcoe;
struct fcoe_port *port;
- int vid = 0;
/* Setup lport private data to point to fcoe softc */
port = lport_priv(lport);
@@ -609,25 +667,8 @@ static int fcoe_netdev_config(struct fc_lport *lport, struct net_device *netdev)
return -EINVAL;
/* offload features support */
- if (netdev->features & NETIF_F_SG)
- lport->sg_supp = 1;
+ fcoe_netdev_features_change(lport, netdev);
- if (netdev->features & NETIF_F_FCOE_CRC) {
- lport->crc_offload = 1;
- FCOE_NETDEV_DBG(netdev, "Supports FCCRC offload\n");
- }
- if (netdev->features & NETIF_F_FSO) {
- lport->seq_offload = 1;
- lport->lso_max = netdev->gso_max_size;
- FCOE_NETDEV_DBG(netdev, "Supports LSO for max len 0x%x\n",
- lport->lso_max);
- }
- if (netdev->fcoe_ddp_xid) {
- lport->lro_enabled = 1;
- lport->lro_xid = netdev->fcoe_ddp_xid;
- FCOE_NETDEV_DBG(netdev, "Supports LRO for max xid 0x%x\n",
- lport->lro_xid);
- }
skb_queue_head_init(&port->fcoe_pending_queue);
port->fcoe_pending_queue_active = 0;
setup_timer(&port->timer, fcoe_queue_timer, (unsigned long)lport);
@@ -635,20 +676,12 @@ static int fcoe_netdev_config(struct fc_lport *lport, struct net_device *netdev)
fcoe_link_speed_update(lport);
if (!lport->vport) {
- /*
- * Use NAA 1&2 (FC-FS Rev. 2.0, Sec. 15) to generate WWNN/WWPN:
- * For WWNN, we use NAA 1 w/ bit 27-16 of word 0 as 0.
- * For WWPN, we use NAA 2 w/ bit 27-16 of word 0 from VLAN ID
- */
- if (netdev->priv_flags & IFF_802_1Q_VLAN)
- vid = vlan_dev_vlan_id(netdev);
-
if (fcoe_get_wwn(netdev, &wwnn, NETDEV_FCOE_WWNN))
wwnn = fcoe_wwn_from_mac(fcoe->ctlr.ctl_src_addr, 1, 0);
fc_set_wwnn(lport, wwnn);
if (fcoe_get_wwn(netdev, &wwpn, NETDEV_FCOE_WWPN))
wwpn = fcoe_wwn_from_mac(fcoe->ctlr.ctl_src_addr,
- 2, vid);
+ 2, 0);
fc_set_wwpn(lport, wwpn);
}
@@ -967,7 +1000,7 @@ static struct fc_lport *fcoe_if_create(struct fcoe_interface *fcoe,
}
/* Initialize the library */
- rc = fcoe_libfc_config(lport, &fcoe_libfc_fcn_templ);
+ rc = fcoe_libfc_config(lport, &fcoe->ctlr, &fcoe_libfc_fcn_templ, 1);
if (rc) {
FCOE_NETDEV_DBG(netdev, "Could not configure libfc for the "
"interface\n");
@@ -1210,6 +1243,8 @@ int fcoe_rcv(struct sk_buff *skb, struct net_device *netdev,
struct fcoe_interface *fcoe;
struct fc_frame_header *fh;
struct fcoe_percpu_s *fps;
+ struct fcoe_port *port;
+ struct ethhdr *eh;
unsigned int cpu;
fcoe = container_of(ptype, struct fcoe_interface, fcoe_packet_type);
@@ -1227,9 +1262,21 @@ int fcoe_rcv(struct sk_buff *skb, struct net_device *netdev,
skb_tail_pointer(skb), skb_end_pointer(skb),
skb->csum, skb->dev ? skb->dev->name : "<NULL>");
- /* check for FCOE packet type */
- if (unlikely(eth_hdr(skb)->h_proto != htons(ETH_P_FCOE))) {
- FCOE_NETDEV_DBG(netdev, "Wrong FC type frame");
+ /* check for mac addresses */
+ eh = eth_hdr(skb);
+ port = lport_priv(lport);
+ if (compare_ether_addr(eh->h_dest, port->data_src_addr) &&
+ compare_ether_addr(eh->h_dest, fcoe->ctlr.ctl_src_addr) &&
+ compare_ether_addr(eh->h_dest, (u8[6])FC_FCOE_FLOGI_MAC)) {
+ FCOE_NETDEV_DBG(netdev, "wrong destination mac address:%pM\n",
+ eh->h_dest);
+ goto err;
+ }
+
+ if (is_fip_mode(&fcoe->ctlr) &&
+ compare_ether_addr(eh->h_source, fcoe->ctlr.dest_addr)) {
+ FCOE_NETDEV_DBG(netdev, "wrong source mac address:%pM\n",
+ eh->h_source);
goto err;
}
@@ -1512,11 +1559,9 @@ int fcoe_xmit(struct fc_lport *lport, struct fc_frame *fp)
/* fill up mac and fcoe headers */
eh = eth_hdr(skb);
eh->h_proto = htons(ETH_P_FCOE);
+ memcpy(eh->h_dest, fcoe->ctlr.dest_addr, ETH_ALEN);
if (fcoe->ctlr.map_dest)
- fc_fcoe_set_mac(eh->h_dest, fh->fh_d_id);
- else
- /* insert GW address */
- memcpy(eh->h_dest, fcoe->ctlr.dest_addr, ETH_ALEN);
+ memcpy(eh->h_dest + 3, fh->fh_d_id, 3);
if (unlikely(fcoe->ctlr.flogi_oxid != FC_XID_UNKNOWN))
memcpy(eh->h_source, fcoe->ctlr.ctl_src_addr, ETH_ALEN);
@@ -1834,6 +1879,9 @@ static int fcoe_device_notification(struct notifier_block *notifier,
schedule_work(&port->destroy_work);
goto out;
break;
+ case NETDEV_FEAT_CHANGE:
+ fcoe_netdev_features_change(lport, netdev);
+ break;
default:
FCOE_NETDEV_DBG(netdev, "Unknown event %ld "
"from netdev netlink\n", event);
@@ -1918,8 +1966,8 @@ static int fcoe_disable(const char *buffer, struct kernel_param *kp)
rtnl_unlock();
if (fcoe) {
- fc_fabric_logoff(fcoe->ctlr.lp);
fcoe_ctlr_link_down(&fcoe->ctlr);
+ fcoe_clean_pending_queue(fcoe->ctlr.lp);
} else
rc = -ENODEV;
@@ -1972,12 +2020,10 @@ static int fcoe_enable(const char *buffer, struct kernel_param *kp)
fcoe = fcoe_hostlist_lookup_port(netdev);
rtnl_unlock();
- if (fcoe) {
- if (!fcoe_link_ok(fcoe->ctlr.lp))
- fcoe_ctlr_link_up(&fcoe->ctlr);
- rc = fc_fabric_login(fcoe->ctlr.lp);
- } else
+ if (!fcoe)
rc = -ENODEV;
+ else if (!fcoe_link_ok(fcoe->ctlr.lp))
+ fcoe_ctlr_link_up(&fcoe->ctlr);
dev_put(netdev);
out_nodev:
@@ -2031,8 +2077,8 @@ static int fcoe_destroy(const char *buffer, struct kernel_param *kp)
rc = -ENODEV;
goto out_putdev;
}
- list_del(&fcoe->list);
fcoe_interface_cleanup(fcoe);
+ list_del(&fcoe->list);
/* RTNL mutex is dropped by fcoe_if_destroy */
fcoe_if_destroy(fcoe->ctlr.lp);
@@ -2070,6 +2116,7 @@ static void fcoe_destroy_work(struct work_struct *work)
*/
static int fcoe_create(const char *buffer, struct kernel_param *kp)
{
+ enum fip_state fip_mode = (enum fip_state)(long)kp->arg;
int rc;
struct fcoe_interface *fcoe;
struct fc_lport *lport;
@@ -2111,7 +2158,7 @@ static int fcoe_create(const char *buffer, struct kernel_param *kp)
goto out_putdev;
}
- fcoe = fcoe_interface_create(netdev);
+ fcoe = fcoe_interface_create(netdev, fip_mode);
if (!fcoe) {
rc = -ENOMEM;
goto out_putdev;
@@ -2452,7 +2499,7 @@ module_exit(fcoe_exit);
* @fp: response frame, or error encoded in a pointer (timeout)
* @arg: pointer the the fcoe_ctlr structure
*
- * This handles MAC address managment for FCoE, then passes control on to
+ * This handles MAC address management for FCoE, then passes control on to
* the libfc FLOGI response handler.
*/
static void fcoe_flogi_resp(struct fc_seq *seq, struct fc_frame *fp, void *arg)
@@ -2484,7 +2531,7 @@ done:
* @fp: response frame, or error encoded in a pointer (timeout)
* @arg: pointer the the fcoe_ctlr structure
*
- * This handles MAC address managment for FCoE, then passes control on to
+ * This handles MAC address management for FCoE, then passes control on to
* the libfc LOGO response handler.
*/
static void fcoe_logo_resp(struct fc_seq *seq, struct fc_frame *fp, void *arg)
@@ -2521,6 +2568,8 @@ static struct fc_seq *fcoe_elsct_send(struct fc_lport *lport, u32 did,
switch (op) {
case ELS_FLOGI:
case ELS_FDISC:
+ if (lport->point_to_multipoint)
+ break;
return fc_elsct_send(lport, did, fp, op, fcoe_flogi_resp,
fip, timeout);
case ELS_LOGO:
@@ -2653,6 +2702,7 @@ static void fcoe_get_lesb(struct fc_lport *lport,
u32 lfc, vlfc, mdac;
struct fcoe_dev_stats *devst;
struct fcoe_fc_els_lesb *lesb;
+ struct rtnl_link_stats64 temp;
struct net_device *netdev = fcoe_netdev(lport);
lfc = 0;
@@ -2669,7 +2719,7 @@ static void fcoe_get_lesb(struct fc_lport *lport,
lesb->lesb_link_fail = htonl(lfc);
lesb->lesb_vlink_fail = htonl(vlfc);
lesb->lesb_miss_fka = htonl(mdac);
- lesb->lesb_fcs_error = htonl(dev_get_stats(netdev)->rx_crc_errors);
+ lesb->lesb_fcs_error = htonl(dev_get_stats(netdev, &temp)->rx_crc_errors);
}
/**
diff --git a/drivers/scsi/fcoe/libfcoe.c b/drivers/scsi/fcoe/libfcoe.c
index 50aaa4bcfc5..aa503d83092 100644
--- a/drivers/scsi/fcoe/libfcoe.c
+++ b/drivers/scsi/fcoe/libfcoe.c
@@ -39,6 +39,7 @@
#include <scsi/fc/fc_fip.h>
#include <scsi/fc/fc_encaps.h>
#include <scsi/fc/fc_fcoe.h>
+#include <scsi/fc/fc_fcp.h>
#include <scsi/libfc.h>
#include <scsi/libfcoe.h>
@@ -54,7 +55,15 @@ static void fcoe_ctlr_timeout(unsigned long);
static void fcoe_ctlr_timer_work(struct work_struct *);
static void fcoe_ctlr_recv_work(struct work_struct *);
+static void fcoe_ctlr_vn_start(struct fcoe_ctlr *);
+static int fcoe_ctlr_vn_recv(struct fcoe_ctlr *, struct sk_buff *);
+static void fcoe_ctlr_vn_timeout(struct fcoe_ctlr *);
+static int fcoe_ctlr_vn_lookup(struct fcoe_ctlr *, u32, u8 *);
+
static u8 fcoe_all_fcfs[ETH_ALEN] = FIP_ALL_FCF_MACS;
+static u8 fcoe_all_enode[ETH_ALEN] = FIP_ALL_ENODE_MACS;
+static u8 fcoe_all_vn2vn[ETH_ALEN] = FIP_ALL_VN2VN_MACS;
+static u8 fcoe_all_p2p[ETH_ALEN] = FIP_ALL_P2P_MACS;
unsigned int libfcoe_debug_logging;
module_param_named(debug_logging, libfcoe_debug_logging, int, S_IRUGO|S_IWUSR);
@@ -80,6 +89,45 @@ do { \
printk(KERN_INFO "host%d: fip: " fmt, \
(fip)->lp->host->host_no, ##args);)
+static const char *fcoe_ctlr_states[] = {
+ [FIP_ST_DISABLED] = "DISABLED",
+ [FIP_ST_LINK_WAIT] = "LINK_WAIT",
+ [FIP_ST_AUTO] = "AUTO",
+ [FIP_ST_NON_FIP] = "NON_FIP",
+ [FIP_ST_ENABLED] = "ENABLED",
+ [FIP_ST_VNMP_START] = "VNMP_START",
+ [FIP_ST_VNMP_PROBE1] = "VNMP_PROBE1",
+ [FIP_ST_VNMP_PROBE2] = "VNMP_PROBE2",
+ [FIP_ST_VNMP_CLAIM] = "VNMP_CLAIM",
+ [FIP_ST_VNMP_UP] = "VNMP_UP",
+};
+
+static const char *fcoe_ctlr_state(enum fip_state state)
+{
+ const char *cp = "unknown";
+
+ if (state < ARRAY_SIZE(fcoe_ctlr_states))
+ cp = fcoe_ctlr_states[state];
+ if (!cp)
+ cp = "unknown";
+ return cp;
+}
+
+/**
+ * fcoe_ctlr_set_state() - Set and do debug printing for the new FIP state.
+ * @fip: The FCoE controller
+ * @state: The new state
+ */
+static void fcoe_ctlr_set_state(struct fcoe_ctlr *fip, enum fip_state state)
+{
+ if (state == fip->state)
+ return;
+ if (fip->lp)
+ LIBFCOE_FIP_DBG(fip, "state %s -> %s\n",
+ fcoe_ctlr_state(fip->state), fcoe_ctlr_state(state));
+ fip->state = state;
+}
+
/**
* fcoe_ctlr_mtu_valid() - Check if a FCF's MTU is valid
* @fcf: The FCF to check
@@ -105,15 +153,29 @@ static inline int fcoe_ctlr_fcf_usable(struct fcoe_fcf *fcf)
}
/**
+ * fcoe_ctlr_map_dest() - Set flag and OUI for mapping destination addresses
+ * @fip: The FCoE controller
+ */
+static void fcoe_ctlr_map_dest(struct fcoe_ctlr *fip)
+{
+ if (fip->mode == FIP_MODE_VN2VN)
+ hton24(fip->dest_addr, FIP_VN_FC_MAP);
+ else
+ hton24(fip->dest_addr, FIP_DEF_FC_MAP);
+ hton24(fip->dest_addr + 3, 0);
+ fip->map_dest = 1;
+}
+
+/**
* fcoe_ctlr_init() - Initialize the FCoE Controller instance
* @fip: The FCoE controller to initialize
*/
-void fcoe_ctlr_init(struct fcoe_ctlr *fip)
+void fcoe_ctlr_init(struct fcoe_ctlr *fip, enum fip_state mode)
{
- fip->state = FIP_ST_LINK_WAIT;
- fip->mode = FIP_ST_AUTO;
+ fcoe_ctlr_set_state(fip, FIP_ST_LINK_WAIT);
+ fip->mode = mode;
INIT_LIST_HEAD(&fip->fcfs);
- spin_lock_init(&fip->lock);
+ mutex_init(&fip->ctlr_mutex);
fip->flogi_oxid = FC_XID_UNKNOWN;
setup_timer(&fip->timer, fcoe_ctlr_timeout, (unsigned long)fip);
INIT_WORK(&fip->timer_work, fcoe_ctlr_timer_work);
@@ -159,10 +221,10 @@ void fcoe_ctlr_destroy(struct fcoe_ctlr *fip)
cancel_work_sync(&fip->recv_work);
skb_queue_purge(&fip->fip_recv_list);
- spin_lock_bh(&fip->lock);
- fip->state = FIP_ST_DISABLED;
+ mutex_lock(&fip->ctlr_mutex);
+ fcoe_ctlr_set_state(fip, FIP_ST_DISABLED);
fcoe_ctlr_reset_fcfs(fip);
- spin_unlock_bh(&fip->lock);
+ mutex_unlock(&fip->ctlr_mutex);
del_timer_sync(&fip->timer);
cancel_work_sync(&fip->timer_work);
}
@@ -255,19 +317,33 @@ static void fcoe_ctlr_solicit(struct fcoe_ctlr *fip, struct fcoe_fcf *fcf)
*/
void fcoe_ctlr_link_up(struct fcoe_ctlr *fip)
{
- spin_lock_bh(&fip->lock);
+ mutex_lock(&fip->ctlr_mutex);
if (fip->state == FIP_ST_NON_FIP || fip->state == FIP_ST_AUTO) {
- spin_unlock_bh(&fip->lock);
+ mutex_unlock(&fip->ctlr_mutex);
fc_linkup(fip->lp);
} else if (fip->state == FIP_ST_LINK_WAIT) {
- fip->state = fip->mode;
- spin_unlock_bh(&fip->lock);
- if (fip->state == FIP_ST_AUTO)
+ fcoe_ctlr_set_state(fip, fip->mode);
+ switch (fip->mode) {
+ default:
+ LIBFCOE_FIP_DBG(fip, "invalid mode %d\n", fip->mode);
+ /* fall-through */
+ case FIP_MODE_AUTO:
LIBFCOE_FIP_DBG(fip, "%s", "setting AUTO mode.\n");
- fc_linkup(fip->lp);
- fcoe_ctlr_solicit(fip, NULL);
+ /* fall-through */
+ case FIP_MODE_FABRIC:
+ case FIP_MODE_NON_FIP:
+ mutex_unlock(&fip->ctlr_mutex);
+ fc_linkup(fip->lp);
+ fcoe_ctlr_solicit(fip, NULL);
+ break;
+ case FIP_MODE_VN2VN:
+ fcoe_ctlr_vn_start(fip);
+ mutex_unlock(&fip->ctlr_mutex);
+ fc_linkup(fip->lp);
+ break;
+ }
} else
- spin_unlock_bh(&fip->lock);
+ mutex_unlock(&fip->ctlr_mutex);
}
EXPORT_SYMBOL(fcoe_ctlr_link_up);
@@ -283,7 +359,7 @@ static void fcoe_ctlr_reset(struct fcoe_ctlr *fip)
fip->port_ka_time = 0;
fip->sol_time = 0;
fip->flogi_oxid = FC_XID_UNKNOWN;
- fip->map_dest = 0;
+ fcoe_ctlr_map_dest(fip);
}
/**
@@ -300,11 +376,11 @@ int fcoe_ctlr_link_down(struct fcoe_ctlr *fip)
int link_dropped;
LIBFCOE_FIP_DBG(fip, "link down.\n");
- spin_lock_bh(&fip->lock);
+ mutex_lock(&fip->ctlr_mutex);
fcoe_ctlr_reset(fip);
link_dropped = fip->state != FIP_ST_LINK_WAIT;
- fip->state = FIP_ST_LINK_WAIT;
- spin_unlock_bh(&fip->lock);
+ fcoe_ctlr_set_state(fip, FIP_ST_LINK_WAIT);
+ mutex_unlock(&fip->ctlr_mutex);
if (link_dropped)
fc_linkdown(fip->lp);
@@ -343,7 +419,7 @@ static void fcoe_ctlr_send_keep_alive(struct fcoe_ctlr *fip,
fcf = fip->sel_fcf;
lp = fip->lp;
- if (!fcf || !lp->port_id)
+ if (!fcf || (ports && !lp->port_id))
return;
len = sizeof(*kal) + ports * sizeof(*vn);
@@ -389,6 +465,7 @@ static void fcoe_ctlr_send_keep_alive(struct fcoe_ctlr *fip,
* @fip: The FCoE controller for the ELS frame
* @dtype: The FIP descriptor type for the frame
* @skb: The FCoE ELS frame including FC header but no FCoE headers
+ * @d_id: The destination port ID.
*
* Returns non-zero error code on failure.
*
@@ -399,58 +476,75 @@ static void fcoe_ctlr_send_keep_alive(struct fcoe_ctlr *fip,
* Ethernet header. The tailroom is for the FIP MAC descriptor.
*/
static int fcoe_ctlr_encaps(struct fcoe_ctlr *fip, struct fc_lport *lport,
- u8 dtype, struct sk_buff *skb)
+ u8 dtype, struct sk_buff *skb, u32 d_id)
{
struct fip_encaps_head {
struct ethhdr eth;
struct fip_header fip;
struct fip_encaps encaps;
} __attribute__((packed)) *cap;
+ struct fc_frame_header *fh;
struct fip_mac_desc *mac;
struct fcoe_fcf *fcf;
size_t dlen;
u16 fip_flags;
+ u8 op;
- fcf = fip->sel_fcf;
- if (!fcf)
- return -ENODEV;
-
- /* set flags according to both FCF and lport's capability on SPMA */
- fip_flags = fcf->flags;
- fip_flags &= fip->spma ? FIP_FL_SPMA | FIP_FL_FPMA : FIP_FL_FPMA;
- if (!fip_flags)
- return -ENODEV;
-
+ fh = (struct fc_frame_header *)skb->data;
+ op = *(u8 *)(fh + 1);
dlen = sizeof(struct fip_encaps) + skb->len; /* len before push */
cap = (struct fip_encaps_head *)skb_push(skb, sizeof(*cap));
-
memset(cap, 0, sizeof(*cap));
- memcpy(cap->eth.h_dest, fcf->fcf_mac, ETH_ALEN);
+
+ if (lport->point_to_multipoint) {
+ if (fcoe_ctlr_vn_lookup(fip, d_id, cap->eth.h_dest))
+ return -ENODEV;
+ fip_flags = 0;
+ } else {
+ fcf = fip->sel_fcf;
+ if (!fcf)
+ return -ENODEV;
+ fip_flags = fcf->flags;
+ fip_flags &= fip->spma ? FIP_FL_SPMA | FIP_FL_FPMA :
+ FIP_FL_FPMA;
+ if (!fip_flags)
+ return -ENODEV;
+ memcpy(cap->eth.h_dest, fcf->fcf_mac, ETH_ALEN);
+ }
memcpy(cap->eth.h_source, fip->ctl_src_addr, ETH_ALEN);
cap->eth.h_proto = htons(ETH_P_FIP);
cap->fip.fip_ver = FIP_VER_ENCAPS(FIP_VER);
cap->fip.fip_op = htons(FIP_OP_LS);
- cap->fip.fip_subcode = FIP_SC_REQ;
- cap->fip.fip_dl_len = htons((dlen + sizeof(*mac)) / FIP_BPW);
+ if (op == ELS_LS_ACC || op == ELS_LS_RJT)
+ cap->fip.fip_subcode = FIP_SC_REP;
+ else
+ cap->fip.fip_subcode = FIP_SC_REQ;
cap->fip.fip_flags = htons(fip_flags);
cap->encaps.fd_desc.fip_dtype = dtype;
cap->encaps.fd_desc.fip_dlen = dlen / FIP_BPW;
- mac = (struct fip_mac_desc *)skb_put(skb, sizeof(*mac));
- memset(mac, 0, sizeof(*mac));
- mac->fd_desc.fip_dtype = FIP_DT_MAC;
- mac->fd_desc.fip_dlen = sizeof(*mac) / FIP_BPW;
- if (dtype != FIP_DT_FLOGI && dtype != FIP_DT_FDISC) {
- memcpy(mac->fd_mac, fip->get_src_addr(lport), ETH_ALEN);
- } else if (fip_flags & FIP_FL_SPMA) {
- LIBFCOE_FIP_DBG(fip, "FLOGI/FDISC sent with SPMA\n");
- memcpy(mac->fd_mac, fip->ctl_src_addr, ETH_ALEN);
- } else {
- LIBFCOE_FIP_DBG(fip, "FLOGI/FDISC sent with FPMA\n");
- /* FPMA only FLOGI must leave the MAC desc set to all 0s */
+ if (op != ELS_LS_RJT) {
+ dlen += sizeof(*mac);
+ mac = (struct fip_mac_desc *)skb_put(skb, sizeof(*mac));
+ memset(mac, 0, sizeof(*mac));
+ mac->fd_desc.fip_dtype = FIP_DT_MAC;
+ mac->fd_desc.fip_dlen = sizeof(*mac) / FIP_BPW;
+ if (dtype != FIP_DT_FLOGI && dtype != FIP_DT_FDISC) {
+ memcpy(mac->fd_mac, fip->get_src_addr(lport), ETH_ALEN);
+ } else if (fip->mode == FIP_MODE_VN2VN) {
+ hton24(mac->fd_mac, FIP_VN_FC_MAP);
+ hton24(mac->fd_mac + 3, fip->port_id);
+ } else if (fip_flags & FIP_FL_SPMA) {
+ LIBFCOE_FIP_DBG(fip, "FLOGI/FDISC sent with SPMA\n");
+ memcpy(mac->fd_mac, fip->ctl_src_addr, ETH_ALEN);
+ } else {
+ LIBFCOE_FIP_DBG(fip, "FLOGI/FDISC sent with FPMA\n");
+ /* FPMA only FLOGI. Must leave the MAC desc zeroed. */
+ }
}
+ cap->fip.fip_dl_len = htons(dlen / FIP_BPW);
skb->protocol = htons(ETH_P_FIP);
skb_reset_mac_header(skb);
@@ -469,19 +563,22 @@ static int fcoe_ctlr_encaps(struct fcoe_ctlr *fip, struct fc_lport *lport,
*
* The caller must check that the length is a multiple of 4.
* The SKB must have enough headroom (28 bytes) and tailroom (8 bytes).
+ * The the skb must also be an fc_frame.
*/
int fcoe_ctlr_els_send(struct fcoe_ctlr *fip, struct fc_lport *lport,
struct sk_buff *skb)
{
+ struct fc_frame *fp;
struct fc_frame_header *fh;
u16 old_xid;
u8 op;
u8 mac[ETH_ALEN];
+ fp = container_of(skb, struct fc_frame, skb);
fh = (struct fc_frame_header *)skb->data;
op = *(u8 *)(fh + 1);
- if (op == ELS_FLOGI) {
+ if (op == ELS_FLOGI && fip->mode != FIP_MODE_VN2VN) {
old_xid = fip->flogi_oxid;
fip->flogi_oxid = ntohs(fh->fh_ox_id);
if (fip->state == FIP_ST_AUTO) {
@@ -490,18 +587,17 @@ int fcoe_ctlr_els_send(struct fcoe_ctlr *fip, struct fc_lport *lport,
fip->flogi_count++;
if (fip->flogi_count < 3)
goto drop;
- fip->map_dest = 1;
+ fcoe_ctlr_map_dest(fip);
return 0;
}
if (fip->state == FIP_ST_NON_FIP)
- fip->map_dest = 1;
+ fcoe_ctlr_map_dest(fip);
}
if (fip->state == FIP_ST_NON_FIP)
return 0;
- if (!fip->sel_fcf)
+ if (!fip->sel_fcf && fip->mode != FIP_MODE_VN2VN)
goto drop;
-
switch (op) {
case ELS_FLOGI:
op = FIP_DT_FLOGI;
@@ -512,36 +608,49 @@ int fcoe_ctlr_els_send(struct fcoe_ctlr *fip, struct fc_lport *lport,
op = FIP_DT_FDISC;
break;
case ELS_LOGO:
- if (fip->state != FIP_ST_ENABLED)
- return 0;
- if (ntoh24(fh->fh_d_id) != FC_FID_FLOGI)
- return 0;
+ if (fip->mode == FIP_MODE_VN2VN) {
+ if (fip->state != FIP_ST_VNMP_UP)
+ return -EINVAL;
+ if (ntoh24(fh->fh_d_id) == FC_FID_FLOGI)
+ return -EINVAL;
+ } else {
+ if (fip->state != FIP_ST_ENABLED)
+ return 0;
+ if (ntoh24(fh->fh_d_id) != FC_FID_FLOGI)
+ return 0;
+ }
op = FIP_DT_LOGO;
break;
case ELS_LS_ACC:
- if (fip->flogi_oxid == FC_XID_UNKNOWN)
- return 0;
- if (!ntoh24(fh->fh_s_id))
- return 0;
- if (fip->state == FIP_ST_AUTO)
- return 0;
/*
- * Here we must've gotten an SID by accepting an FLOGI
+ * If non-FIP, we may have gotten an SID by accepting an FLOGI
* from a point-to-point connection. Switch to using
* the source mac based on the SID. The destination
* MAC in this case would have been set by receving the
* FLOGI.
*/
- fip->flogi_oxid = FC_XID_UNKNOWN;
- fc_fcoe_set_mac(mac, fh->fh_d_id);
- fip->update_mac(lport, mac);
+ if (fip->state == FIP_ST_NON_FIP) {
+ if (fip->flogi_oxid == FC_XID_UNKNOWN)
+ return 0;
+ fip->flogi_oxid = FC_XID_UNKNOWN;
+ fc_fcoe_set_mac(mac, fh->fh_d_id);
+ fip->update_mac(lport, mac);
+ }
+ /* fall through */
+ case ELS_LS_RJT:
+ op = fr_encaps(fp);
+ if (op)
+ break;
return 0;
default:
- if (fip->state != FIP_ST_ENABLED)
+ if (fip->state != FIP_ST_ENABLED &&
+ fip->state != FIP_ST_VNMP_UP)
goto drop;
return 0;
}
- if (fcoe_ctlr_encaps(fip, lport, op, skb))
+ LIBFCOE_FIP_DBG(fip, "els_send op %u d_id %x\n",
+ op, ntoh24(fh->fh_d_id));
+ if (fcoe_ctlr_encaps(fip, lport, op, skb, ntoh24(fh->fh_d_id)))
goto drop;
fip->send(fip, skb);
return -EINPROGRESS;
@@ -557,60 +666,66 @@ EXPORT_SYMBOL(fcoe_ctlr_els_send);
*
* Called with lock held and preemption disabled.
*
- * An FCF is considered old if we have missed three advertisements.
- * That is, there have been no valid advertisement from it for three
- * times its keep-alive period including fuzz.
+ * An FCF is considered old if we have missed two advertisements.
+ * That is, there have been no valid advertisement from it for 2.5
+ * times its keep-alive period.
*
* In addition, determine the time when an FCF selection can occur.
*
* Also, increment the MissDiscAdvCount when no advertisement is received
* for the corresponding FCF for 1.5 * FKA_ADV_PERIOD (FC-BB-5 LESB).
+ *
+ * Returns the time in jiffies for the next call.
*/
-static void fcoe_ctlr_age_fcfs(struct fcoe_ctlr *fip)
+static unsigned long fcoe_ctlr_age_fcfs(struct fcoe_ctlr *fip)
{
struct fcoe_fcf *fcf;
struct fcoe_fcf *next;
+ unsigned long next_timer = jiffies + msecs_to_jiffies(FIP_VN_KA_PERIOD);
+ unsigned long deadline;
unsigned long sel_time = 0;
- unsigned long mda_time = 0;
struct fcoe_dev_stats *stats;
+ stats = per_cpu_ptr(fip->lp->dev_stats, get_cpu());
+
list_for_each_entry_safe(fcf, next, &fip->fcfs, list) {
- mda_time = fcf->fka_period + (fcf->fka_period >> 1);
- if ((fip->sel_fcf == fcf) &&
- (time_after(jiffies, fcf->time + mda_time))) {
- mod_timer(&fip->timer, jiffies + mda_time);
- stats = per_cpu_ptr(fip->lp->dev_stats,
- smp_processor_id());
- stats->MissDiscAdvCount++;
- printk(KERN_INFO "libfcoe: host%d: Missing Discovery "
- "Advertisement for fab %16.16llx count %lld\n",
- fip->lp->host->host_no, fcf->fabric_name,
- stats->MissDiscAdvCount);
+ deadline = fcf->time + fcf->fka_period + fcf->fka_period / 2;
+ if (fip->sel_fcf == fcf) {
+ if (time_after(jiffies, deadline)) {
+ stats->MissDiscAdvCount++;
+ printk(KERN_INFO "libfcoe: host%d: "
+ "Missing Discovery Advertisement "
+ "for fab %16.16llx count %lld\n",
+ fip->lp->host->host_no, fcf->fabric_name,
+ stats->MissDiscAdvCount);
+ } else if (time_after(next_timer, deadline))
+ next_timer = deadline;
}
- if (time_after(jiffies, fcf->time + fcf->fka_period * 3 +
- msecs_to_jiffies(FIP_FCF_FUZZ * 3))) {
+
+ deadline += fcf->fka_period;
+ if (time_after_eq(jiffies, deadline)) {
if (fip->sel_fcf == fcf)
fip->sel_fcf = NULL;
list_del(&fcf->list);
WARN_ON(!fip->fcf_count);
fip->fcf_count--;
kfree(fcf);
- stats = per_cpu_ptr(fip->lp->dev_stats,
- smp_processor_id());
stats->VLinkFailureCount++;
- } else if (fcoe_ctlr_mtu_valid(fcf) &&
- (!sel_time || time_before(sel_time, fcf->time))) {
- sel_time = fcf->time;
+ } else {
+ if (time_after(next_timer, deadline))
+ next_timer = deadline;
+ if (fcoe_ctlr_mtu_valid(fcf) &&
+ (!sel_time || time_before(sel_time, fcf->time)))
+ sel_time = fcf->time;
}
}
- if (sel_time) {
+ put_cpu();
+ if (sel_time && !fip->sel_fcf && !fip->sel_time) {
sel_time += msecs_to_jiffies(FCOE_CTLR_START_DELAY);
fip->sel_time = sel_time;
- if (time_before(sel_time, fip->timer.expires))
- mod_timer(&fip->timer, sel_time);
- } else {
- fip->sel_time = 0;
}
+
+ return next_timer;
}
/**
@@ -633,6 +748,7 @@ static int fcoe_ctlr_parse_adv(struct fcoe_ctlr *fip,
unsigned long t;
size_t rlen;
size_t dlen;
+ u32 desc_mask;
memset(fcf, 0, sizeof(*fcf));
fcf->fka_period = msecs_to_jiffies(FCOE_CTLR_DEF_FKA);
@@ -640,6 +756,12 @@ static int fcoe_ctlr_parse_adv(struct fcoe_ctlr *fip,
fiph = (struct fip_header *)skb->data;
fcf->flags = ntohs(fiph->fip_flags);
+ /*
+ * mask of required descriptors. validating each one clears its bit.
+ */
+ desc_mask = BIT(FIP_DT_PRI) | BIT(FIP_DT_MAC) | BIT(FIP_DT_NAME) |
+ BIT(FIP_DT_FAB) | BIT(FIP_DT_FKA);
+
rlen = ntohs(fiph->fip_dl_len) * 4;
if (rlen + sizeof(*fiph) > skb->len)
return -EINVAL;
@@ -649,11 +771,19 @@ static int fcoe_ctlr_parse_adv(struct fcoe_ctlr *fip,
dlen = desc->fip_dlen * FIP_BPW;
if (dlen < sizeof(*desc) || dlen > rlen)
return -EINVAL;
+ /* Drop Adv if there are duplicate critical descriptors */
+ if ((desc->fip_dtype < 32) &&
+ !(desc_mask & 1U << desc->fip_dtype)) {
+ LIBFCOE_FIP_DBG(fip, "Duplicate Critical "
+ "Descriptors in FIP adv\n");
+ return -EINVAL;
+ }
switch (desc->fip_dtype) {
case FIP_DT_PRI:
if (dlen != sizeof(struct fip_pri_desc))
goto len_err;
fcf->pri = ((struct fip_pri_desc *)desc)->fd_pri;
+ desc_mask &= ~BIT(FIP_DT_PRI);
break;
case FIP_DT_MAC:
if (dlen != sizeof(struct fip_mac_desc))
@@ -662,16 +792,19 @@ static int fcoe_ctlr_parse_adv(struct fcoe_ctlr *fip,
((struct fip_mac_desc *)desc)->fd_mac,
ETH_ALEN);
if (!is_valid_ether_addr(fcf->fcf_mac)) {
- LIBFCOE_FIP_DBG(fip, "Invalid MAC address "
- "in FIP adv\n");
+ LIBFCOE_FIP_DBG(fip,
+ "Invalid MAC addr %pM in FIP adv\n",
+ fcf->fcf_mac);
return -EINVAL;
}
+ desc_mask &= ~BIT(FIP_DT_MAC);
break;
case FIP_DT_NAME:
if (dlen != sizeof(struct fip_wwn_desc))
goto len_err;
wwn = (struct fip_wwn_desc *)desc;
fcf->switch_name = get_unaligned_be64(&wwn->fd_wwn);
+ desc_mask &= ~BIT(FIP_DT_NAME);
break;
case FIP_DT_FAB:
if (dlen != sizeof(struct fip_fab_desc))
@@ -680,6 +813,7 @@ static int fcoe_ctlr_parse_adv(struct fcoe_ctlr *fip,
fcf->fabric_name = get_unaligned_be64(&fab->fd_wwn);
fcf->vfid = ntohs(fab->fd_vfid);
fcf->fc_map = ntoh24(fab->fd_map);
+ desc_mask &= ~BIT(FIP_DT_FAB);
break;
case FIP_DT_FKA:
if (dlen != sizeof(struct fip_fka_desc))
@@ -690,6 +824,7 @@ static int fcoe_ctlr_parse_adv(struct fcoe_ctlr *fip,
t = ntohl(fka->fd_fka_period);
if (t >= FCOE_CTLR_MIN_FKA)
fcf->fka_period = msecs_to_jiffies(t);
+ desc_mask &= ~BIT(FIP_DT_FKA);
break;
case FIP_DT_MAP_OUI:
case FIP_DT_FCOE_SIZE:
@@ -703,15 +838,20 @@ static int fcoe_ctlr_parse_adv(struct fcoe_ctlr *fip,
/* standard says ignore unknown descriptors >= 128 */
if (desc->fip_dtype < FIP_DT_VENDOR_BASE)
return -EINVAL;
- continue;
+ break;
}
desc = (struct fip_desc *)((char *)desc + dlen);
rlen -= dlen;
}
if (!fcf->fc_map || (fcf->fc_map & 0x10000))
return -EINVAL;
- if (!fcf->switch_name || !fcf->fabric_name)
+ if (!fcf->switch_name)
+ return -EINVAL;
+ if (desc_mask) {
+ LIBFCOE_FIP_DBG(fip, "adv missing descriptors mask %x\n",
+ desc_mask);
return -EINVAL;
+ }
return 0;
len_err:
@@ -737,7 +877,7 @@ static void fcoe_ctlr_recv_adv(struct fcoe_ctlr *fip, struct sk_buff *skb)
if (fcoe_ctlr_parse_adv(fip, skb, &new))
return;
- spin_lock_bh(&fip->lock);
+ mutex_lock(&fip->ctlr_mutex);
first = list_empty(&fip->fcfs);
found = NULL;
list_for_each_entry(fcf, &fip->fcfs, list) {
@@ -762,18 +902,21 @@ static void fcoe_ctlr_recv_adv(struct fcoe_ctlr *fip, struct sk_buff *skb)
list_add(&fcf->list, &fip->fcfs);
} else {
/*
- * Flags in advertisements are ignored once the FCF is
- * selected. Flags in unsolicited advertisements are
- * ignored after a usable solicited advertisement
- * has been received.
+ * Update the FCF's keep-alive descriptor flags.
+ * Other flag changes from new advertisements are
+ * ignored after a solicited advertisement is
+ * received and the FCF is selectable (usable).
*/
- if (fcf == fip->sel_fcf) {
+ fcf->fd_flags = new.fd_flags;
+ if (!fcoe_ctlr_fcf_usable(fcf))
+ fcf->flags = new.flags;
+
+ if (fcf == fip->sel_fcf && !fcf->fd_flags) {
fip->ctlr_ka_time -= fcf->fka_period;
fip->ctlr_ka_time += new.fka_period;
if (time_before(fip->ctlr_ka_time, fip->timer.expires))
mod_timer(&fip->timer, fip->ctlr_ka_time);
- } else if (!fcoe_ctlr_fcf_usable(fcf))
- fcf->flags = new.flags;
+ }
fcf->fka_period = new.fka_period;
memcpy(fcf->fcf_mac, new.fcf_mac, ETH_ALEN);
}
@@ -805,7 +948,7 @@ static void fcoe_ctlr_recv_adv(struct fcoe_ctlr *fip, struct sk_buff *skb)
* If this is the first validated FCF, note the time and
* set a timer to trigger selection.
*/
- if (mtu_valid && !fip->sel_time && fcoe_ctlr_fcf_usable(fcf)) {
+ if (mtu_valid && !fip->sel_fcf && fcoe_ctlr_fcf_usable(fcf)) {
fip->sel_time = jiffies +
msecs_to_jiffies(FCOE_CTLR_START_DELAY);
if (!timer_pending(&fip->timer) ||
@@ -813,7 +956,7 @@ static void fcoe_ctlr_recv_adv(struct fcoe_ctlr *fip, struct sk_buff *skb)
mod_timer(&fip->timer, fip->sel_time);
}
out:
- spin_unlock_bh(&fip->lock);
+ mutex_unlock(&fip->ctlr_mutex);
}
/**
@@ -837,6 +980,8 @@ static void fcoe_ctlr_recv_els(struct fcoe_ctlr *fip, struct sk_buff *skb)
size_t els_len = 0;
size_t rlen;
size_t dlen;
+ u32 desc_mask = 0;
+ u32 desc_cnt = 0;
fiph = (struct fip_header *)skb->data;
sub = fiph->fip_subcode;
@@ -849,27 +994,42 @@ static void fcoe_ctlr_recv_els(struct fcoe_ctlr *fip, struct sk_buff *skb)
desc = (struct fip_desc *)(fiph + 1);
while (rlen > 0) {
+ desc_cnt++;
dlen = desc->fip_dlen * FIP_BPW;
if (dlen < sizeof(*desc) || dlen > rlen)
goto drop;
+ /* Drop ELS if there are duplicate critical descriptors */
+ if (desc->fip_dtype < 32) {
+ if (desc_mask & 1U << desc->fip_dtype) {
+ LIBFCOE_FIP_DBG(fip, "Duplicate Critical "
+ "Descriptors in FIP ELS\n");
+ goto drop;
+ }
+ desc_mask |= (1 << desc->fip_dtype);
+ }
switch (desc->fip_dtype) {
case FIP_DT_MAC:
+ if (desc_cnt == 1) {
+ LIBFCOE_FIP_DBG(fip, "FIP descriptors "
+ "received out of order\n");
+ goto drop;
+ }
+
if (dlen != sizeof(struct fip_mac_desc))
goto len_err;
memcpy(granted_mac,
((struct fip_mac_desc *)desc)->fd_mac,
ETH_ALEN);
- if (!is_valid_ether_addr(granted_mac)) {
- LIBFCOE_FIP_DBG(fip, "Invalid MAC address "
- "in FIP ELS\n");
- goto drop;
- }
- memcpy(fr_cb(fp)->granted_mac, granted_mac, ETH_ALEN);
break;
case FIP_DT_FLOGI:
case FIP_DT_FDISC:
case FIP_DT_LOGO:
case FIP_DT_ELP:
+ if (desc_cnt != 1) {
+ LIBFCOE_FIP_DBG(fip, "FIP descriptors "
+ "received out of order\n");
+ goto drop;
+ }
if (fh)
goto drop;
if (dlen < sizeof(*els) + sizeof(*fh) + 1)
@@ -885,7 +1045,12 @@ static void fcoe_ctlr_recv_els(struct fcoe_ctlr *fip, struct sk_buff *skb)
/* standard says ignore unknown descriptors >= 128 */
if (desc->fip_dtype < FIP_DT_VENDOR_BASE)
goto drop;
- continue;
+ if (desc_cnt <= 2) {
+ LIBFCOE_FIP_DBG(fip, "FIP descriptors "
+ "received out of order\n");
+ goto drop;
+ }
+ break;
}
desc = (struct fip_desc *)((char *)desc + dlen);
rlen -= dlen;
@@ -895,10 +1060,27 @@ static void fcoe_ctlr_recv_els(struct fcoe_ctlr *fip, struct sk_buff *skb)
goto drop;
els_op = *(u8 *)(fh + 1);
- if (els_dtype == FIP_DT_FLOGI && sub == FIP_SC_REP &&
- fip->flogi_oxid == ntohs(fh->fh_ox_id) &&
- els_op == ELS_LS_ACC && is_valid_ether_addr(granted_mac))
- fip->flogi_oxid = FC_XID_UNKNOWN;
+ if ((els_dtype == FIP_DT_FLOGI || els_dtype == FIP_DT_FDISC) &&
+ sub == FIP_SC_REP && els_op == ELS_LS_ACC &&
+ fip->mode != FIP_MODE_VN2VN) {
+ if (!is_valid_ether_addr(granted_mac)) {
+ LIBFCOE_FIP_DBG(fip,
+ "Invalid MAC address %pM in FIP ELS\n",
+ granted_mac);
+ goto drop;
+ }
+ memcpy(fr_cb(fp)->granted_mac, granted_mac, ETH_ALEN);
+
+ if (fip->flogi_oxid == ntohs(fh->fh_ox_id))
+ fip->flogi_oxid = FC_XID_UNKNOWN;
+ }
+
+ if ((desc_cnt == 0) || ((els_op != ELS_LS_RJT) &&
+ (!(1U << FIP_DT_MAC & desc_mask)))) {
+ LIBFCOE_FIP_DBG(fip, "Missing critical descriptors "
+ "in FIP ELS\n");
+ goto drop;
+ }
/*
* Convert skb into an fc_frame containing only the ELS.
@@ -910,6 +1092,7 @@ static void fcoe_ctlr_recv_els(struct fcoe_ctlr *fip, struct sk_buff *skb)
fr_sof(fp) = FC_SOF_I3;
fr_eof(fp) = FC_EOF_T;
fr_dev(fp) = lport;
+ fr_encaps(fp) = els_dtype;
stats = per_cpu_ptr(lport->dev_stats, get_cpu());
stats->RxFrames++;
@@ -945,7 +1128,9 @@ static void fcoe_ctlr_recv_clr_vlink(struct fcoe_ctlr *fip,
size_t dlen;
struct fcoe_fcf *fcf = fip->sel_fcf;
struct fc_lport *lport = fip->lp;
- u32 desc_mask;
+ struct fc_lport *vn_port = NULL;
+ u32 desc_mask;
+ int is_vn_port = 0;
LIBFCOE_FIP_DBG(fip, "Clear Virtual Link received\n");
@@ -963,6 +1148,13 @@ static void fcoe_ctlr_recv_clr_vlink(struct fcoe_ctlr *fip,
dlen = desc->fip_dlen * FIP_BPW;
if (dlen > rlen)
return;
+ /* Drop CVL if there are duplicate critical descriptors */
+ if ((desc->fip_dtype < 32) &&
+ !(desc_mask & 1U << desc->fip_dtype)) {
+ LIBFCOE_FIP_DBG(fip, "Duplicate Critical "
+ "Descriptors in FIP CVL\n");
+ return;
+ }
switch (desc->fip_dtype) {
case FIP_DT_MAC:
mp = (struct fip_mac_desc *)desc;
@@ -987,8 +1179,26 @@ static void fcoe_ctlr_recv_clr_vlink(struct fcoe_ctlr *fip,
if (compare_ether_addr(vp->fd_mac,
fip->get_src_addr(lport)) == 0 &&
get_unaligned_be64(&vp->fd_wwpn) == lport->wwpn &&
- ntoh24(vp->fd_fc_id) == lport->port_id)
+ ntoh24(vp->fd_fc_id) == lport->port_id) {
desc_mask &= ~BIT(FIP_DT_VN_ID);
+ break;
+ }
+ /* check if clr_vlink is for NPIV port */
+ mutex_lock(&lport->lp_mutex);
+ list_for_each_entry(vn_port, &lport->vports, list) {
+ if (compare_ether_addr(vp->fd_mac,
+ fip->get_src_addr(vn_port)) == 0 &&
+ (get_unaligned_be64(&vp->fd_wwpn)
+ == vn_port->wwpn) &&
+ (ntoh24(vp->fd_fc_id) ==
+ fc_host_port_id(vn_port->host))) {
+ desc_mask &= ~BIT(FIP_DT_VN_ID);
+ is_vn_port = 1;
+ break;
+ }
+ }
+ mutex_unlock(&lport->lp_mutex);
+
break;
default:
/* standard says ignore unknown descriptors >= 128 */
@@ -1009,14 +1219,19 @@ static void fcoe_ctlr_recv_clr_vlink(struct fcoe_ctlr *fip,
} else {
LIBFCOE_FIP_DBG(fip, "performing Clear Virtual Link\n");
- spin_lock_bh(&fip->lock);
- per_cpu_ptr(lport->dev_stats,
- smp_processor_id())->VLinkFailureCount++;
- fcoe_ctlr_reset(fip);
- spin_unlock_bh(&fip->lock);
-
- fc_lport_reset(fip->lp);
- fcoe_ctlr_solicit(fip, NULL);
+ if (is_vn_port)
+ fc_lport_reset(vn_port);
+ else {
+ mutex_lock(&fip->ctlr_mutex);
+ per_cpu_ptr(lport->dev_stats,
+ get_cpu())->VLinkFailureCount++;
+ put_cpu();
+ fcoe_ctlr_reset(fip);
+ mutex_unlock(&fip->ctlr_mutex);
+
+ fc_lport_reset(fip->lp);
+ fcoe_ctlr_solicit(fip, NULL);
+ }
}
}
@@ -1054,8 +1269,13 @@ static int fcoe_ctlr_recv_handler(struct fcoe_ctlr *fip, struct sk_buff *skb)
if (skb->len < sizeof(*fiph))
goto drop;
eh = eth_hdr(skb);
- if (compare_ether_addr(eh->h_dest, fip->ctl_src_addr) &&
- compare_ether_addr(eh->h_dest, FIP_ALL_ENODE_MACS))
+ if (fip->mode == FIP_MODE_VN2VN) {
+ if (compare_ether_addr(eh->h_dest, fip->ctl_src_addr) &&
+ compare_ether_addr(eh->h_dest, fcoe_all_vn2vn) &&
+ compare_ether_addr(eh->h_dest, fcoe_all_p2p))
+ goto drop;
+ } else if (compare_ether_addr(eh->h_dest, fip->ctl_src_addr) &&
+ compare_ether_addr(eh->h_dest, fcoe_all_enode))
goto drop;
fiph = (struct fip_header *)skb->data;
op = ntohs(fiph->fip_op);
@@ -1066,22 +1286,31 @@ static int fcoe_ctlr_recv_handler(struct fcoe_ctlr *fip, struct sk_buff *skb)
if (ntohs(fiph->fip_dl_len) * FIP_BPW + sizeof(*fiph) > skb->len)
goto drop;
- spin_lock_bh(&fip->lock);
+ mutex_lock(&fip->ctlr_mutex);
state = fip->state;
if (state == FIP_ST_AUTO) {
fip->map_dest = 0;
- fip->state = FIP_ST_ENABLED;
+ fcoe_ctlr_set_state(fip, FIP_ST_ENABLED);
state = FIP_ST_ENABLED;
LIBFCOE_FIP_DBG(fip, "Using FIP mode\n");
}
- spin_unlock_bh(&fip->lock);
- if (state != FIP_ST_ENABLED)
+ mutex_unlock(&fip->ctlr_mutex);
+
+ if (fip->mode == FIP_MODE_VN2VN && op == FIP_OP_VN2VN)
+ return fcoe_ctlr_vn_recv(fip, skb);
+
+ if (state != FIP_ST_ENABLED && state != FIP_ST_VNMP_UP &&
+ state != FIP_ST_VNMP_CLAIM)
goto drop;
if (op == FIP_OP_LS) {
fcoe_ctlr_recv_els(fip, skb); /* consumes skb */
return 0;
}
+
+ if (state != FIP_ST_ENABLED)
+ goto drop;
+
if (op == FIP_OP_DISC && sub == FIP_SC_ADV)
fcoe_ctlr_recv_adv(fip, skb);
else if (op == FIP_OP_CTRL && sub == FIP_SC_CLR_VLINK)
@@ -1140,30 +1369,53 @@ static void fcoe_ctlr_select(struct fcoe_ctlr *fip)
/**
* fcoe_ctlr_timeout() - FIP timeout handler
* @arg: The FCoE controller that timed out
- *
- * Ages FCFs. Triggers FCF selection if possible. Sends keep-alives.
*/
static void fcoe_ctlr_timeout(unsigned long arg)
{
struct fcoe_ctlr *fip = (struct fcoe_ctlr *)arg;
+
+ schedule_work(&fip->timer_work);
+}
+
+/**
+ * fcoe_ctlr_timer_work() - Worker thread function for timer work
+ * @work: Handle to a FCoE controller
+ *
+ * Ages FCFs. Triggers FCF selection if possible.
+ * Sends keep-alives and resets.
+ */
+static void fcoe_ctlr_timer_work(struct work_struct *work)
+{
+ struct fcoe_ctlr *fip;
+ struct fc_lport *vport;
+ u8 *mac;
+ u8 reset = 0;
+ u8 send_ctlr_ka = 0;
+ u8 send_port_ka = 0;
struct fcoe_fcf *sel;
struct fcoe_fcf *fcf;
- unsigned long next_timer = jiffies + msecs_to_jiffies(FIP_VN_KA_PERIOD);
+ unsigned long next_timer;
- spin_lock_bh(&fip->lock);
+ fip = container_of(work, struct fcoe_ctlr, timer_work);
+ if (fip->mode == FIP_MODE_VN2VN)
+ return fcoe_ctlr_vn_timeout(fip);
+ mutex_lock(&fip->ctlr_mutex);
if (fip->state == FIP_ST_DISABLED) {
- spin_unlock_bh(&fip->lock);
+ mutex_unlock(&fip->ctlr_mutex);
return;
}
fcf = fip->sel_fcf;
- fcoe_ctlr_age_fcfs(fip);
+ next_timer = fcoe_ctlr_age_fcfs(fip);
sel = fip->sel_fcf;
- if (!sel && fip->sel_time && time_after_eq(jiffies, fip->sel_time)) {
- fcoe_ctlr_select(fip);
- sel = fip->sel_fcf;
- fip->sel_time = 0;
+ if (!sel && fip->sel_time) {
+ if (time_after_eq(jiffies, fip->sel_time)) {
+ fcoe_ctlr_select(fip);
+ sel = fip->sel_fcf;
+ fip->sel_time = 0;
+ } else if (time_after(next_timer, fip->sel_time))
+ next_timer = fip->sel_time;
}
if (sel != fcf) {
@@ -1173,23 +1425,25 @@ static void fcoe_ctlr_timeout(unsigned long arg)
"Fibre-Channel Forwarder MAC %pM\n",
fip->lp->host->host_no, sel->fcf_mac);
memcpy(fip->dest_addr, sel->fcf_mac, ETH_ALEN);
+ fip->map_dest = 0;
fip->port_ka_time = jiffies +
msecs_to_jiffies(FIP_VN_KA_PERIOD);
fip->ctlr_ka_time = jiffies + sel->fka_period;
+ if (time_after(next_timer, fip->ctlr_ka_time))
+ next_timer = fip->ctlr_ka_time;
} else {
printk(KERN_NOTICE "libfcoe: host%d: "
"FIP Fibre-Channel Forwarder timed out. "
"Starting FCF discovery.\n",
fip->lp->host->host_no);
- fip->reset_req = 1;
- schedule_work(&fip->timer_work);
+ reset = 1;
}
}
if (sel && !sel->fd_flags) {
if (time_after_eq(jiffies, fip->ctlr_ka_time)) {
fip->ctlr_ka_time = jiffies + sel->fka_period;
- fip->send_ctlr_ka = 1;
+ send_ctlr_ka = 1;
}
if (time_after(next_timer, fip->ctlr_ka_time))
next_timer = fip->ctlr_ka_time;
@@ -1197,50 +1451,25 @@ static void fcoe_ctlr_timeout(unsigned long arg)
if (time_after_eq(jiffies, fip->port_ka_time)) {
fip->port_ka_time = jiffies +
msecs_to_jiffies(FIP_VN_KA_PERIOD);
- fip->send_port_ka = 1;
+ send_port_ka = 1;
}
if (time_after(next_timer, fip->port_ka_time))
next_timer = fip->port_ka_time;
- mod_timer(&fip->timer, next_timer);
- } else if (fip->sel_time) {
- next_timer = fip->sel_time +
- msecs_to_jiffies(FCOE_CTLR_START_DELAY);
- mod_timer(&fip->timer, next_timer);
}
- if (fip->send_ctlr_ka || fip->send_port_ka)
- schedule_work(&fip->timer_work);
- spin_unlock_bh(&fip->lock);
-}
-
-/**
- * fcoe_ctlr_timer_work() - Worker thread function for timer work
- * @work: Handle to a FCoE controller
- *
- * Sends keep-alives and resets which must not
- * be called from the timer directly, since they use a mutex.
- */
-static void fcoe_ctlr_timer_work(struct work_struct *work)
-{
- struct fcoe_ctlr *fip;
- struct fc_lport *vport;
- u8 *mac;
- int reset;
-
- fip = container_of(work, struct fcoe_ctlr, timer_work);
- spin_lock_bh(&fip->lock);
- reset = fip->reset_req;
- fip->reset_req = 0;
- spin_unlock_bh(&fip->lock);
+ if (!list_empty(&fip->fcfs))
+ mod_timer(&fip->timer, next_timer);
+ mutex_unlock(&fip->ctlr_mutex);
- if (reset)
+ if (reset) {
fc_lport_reset(fip->lp);
+ /* restart things with a solicitation */
+ fcoe_ctlr_solicit(fip, NULL);
+ }
- if (fip->send_ctlr_ka) {
- fip->send_ctlr_ka = 0;
+ if (send_ctlr_ka)
fcoe_ctlr_send_keep_alive(fip, NULL, 0, fip->ctl_src_addr);
- }
- if (fip->send_port_ka) {
- fip->send_port_ka = 0;
+
+ if (send_port_ka) {
mutex_lock(&fip->lp->lp_mutex);
mac = fip->get_src_addr(fip->lp);
fcoe_ctlr_send_keep_alive(fip, fip->lp, 1, mac);
@@ -1297,12 +1526,12 @@ int fcoe_ctlr_recv_flogi(struct fcoe_ctlr *fip, struct fc_lport *lport,
if (op == ELS_LS_ACC && fh->fh_r_ctl == FC_RCTL_ELS_REP &&
fip->flogi_oxid == ntohs(fh->fh_ox_id)) {
- spin_lock_bh(&fip->lock);
+ mutex_lock(&fip->ctlr_mutex);
if (fip->state != FIP_ST_AUTO && fip->state != FIP_ST_NON_FIP) {
- spin_unlock_bh(&fip->lock);
+ mutex_unlock(&fip->ctlr_mutex);
return -EINVAL;
}
- fip->state = FIP_ST_NON_FIP;
+ fcoe_ctlr_set_state(fip, FIP_ST_NON_FIP);
LIBFCOE_FIP_DBG(fip,
"received FLOGI LS_ACC using non-FIP mode\n");
@@ -1313,28 +1542,28 @@ int fcoe_ctlr_recv_flogi(struct fcoe_ctlr *fip, struct fc_lport *lport,
* Otherwise we use the FCoE gateway addr
*/
if (!compare_ether_addr(sa, (u8[6])FC_FCOE_FLOGI_MAC)) {
- fip->map_dest = 1;
+ fcoe_ctlr_map_dest(fip);
} else {
memcpy(fip->dest_addr, sa, ETH_ALEN);
fip->map_dest = 0;
}
fip->flogi_oxid = FC_XID_UNKNOWN;
- spin_unlock_bh(&fip->lock);
+ mutex_unlock(&fip->ctlr_mutex);
fc_fcoe_set_mac(fr_cb(fp)->granted_mac, fh->fh_d_id);
} else if (op == ELS_FLOGI && fh->fh_r_ctl == FC_RCTL_ELS_REQ && sa) {
/*
* Save source MAC for point-to-point responses.
*/
- spin_lock_bh(&fip->lock);
+ mutex_lock(&fip->ctlr_mutex);
if (fip->state == FIP_ST_AUTO || fip->state == FIP_ST_NON_FIP) {
memcpy(fip->dest_addr, sa, ETH_ALEN);
fip->map_dest = 0;
if (fip->state == FIP_ST_AUTO)
LIBFCOE_FIP_DBG(fip, "received non-FIP FLOGI. "
"Setting non-FIP mode\n");
- fip->state = FIP_ST_NON_FIP;
+ fcoe_ctlr_set_state(fip, FIP_ST_NON_FIP);
}
- spin_unlock_bh(&fip->lock);
+ mutex_unlock(&fip->ctlr_mutex);
}
return 0;
}
@@ -1382,26 +1611,916 @@ u64 fcoe_wwn_from_mac(unsigned char mac[MAX_ADDR_LEN],
EXPORT_SYMBOL_GPL(fcoe_wwn_from_mac);
/**
+ * fcoe_ctlr_rport() - return the fcoe_rport for a given fc_rport_priv
+ * @rdata: libfc remote port
+ */
+static inline struct fcoe_rport *fcoe_ctlr_rport(struct fc_rport_priv *rdata)
+{
+ return (struct fcoe_rport *)(rdata + 1);
+}
+
+/**
+ * fcoe_ctlr_vn_send() - Send a FIP VN2VN Probe Request or Reply.
+ * @fip: The FCoE controller
+ * @sub: sub-opcode for probe request, reply, or advertisement.
+ * @dest: The destination Ethernet MAC address
+ * @min_len: minimum size of the Ethernet payload to be sent
+ */
+static void fcoe_ctlr_vn_send(struct fcoe_ctlr *fip,
+ enum fip_vn2vn_subcode sub,
+ const u8 *dest, size_t min_len)
+{
+ struct sk_buff *skb;
+ struct fip_frame {
+ struct ethhdr eth;
+ struct fip_header fip;
+ struct fip_mac_desc mac;
+ struct fip_wwn_desc wwnn;
+ struct fip_vn_desc vn;
+ } __attribute__((packed)) *frame;
+ struct fip_fc4_feat *ff;
+ struct fip_size_desc *size;
+ u32 fcp_feat;
+ size_t len;
+ size_t dlen;
+
+ len = sizeof(*frame);
+ dlen = 0;
+ if (sub == FIP_SC_VN_CLAIM_NOTIFY || sub == FIP_SC_VN_CLAIM_REP) {
+ dlen = sizeof(struct fip_fc4_feat) +
+ sizeof(struct fip_size_desc);
+ len += dlen;
+ }
+ dlen += sizeof(frame->mac) + sizeof(frame->wwnn) + sizeof(frame->vn);
+ len = max(len, min_len + sizeof(struct ethhdr));
+
+ skb = dev_alloc_skb(len);
+ if (!skb)
+ return;
+
+ frame = (struct fip_frame *)skb->data;
+ memset(frame, 0, len);
+ memcpy(frame->eth.h_dest, dest, ETH_ALEN);
+ memcpy(frame->eth.h_source, fip->ctl_src_addr, ETH_ALEN);
+ frame->eth.h_proto = htons(ETH_P_FIP);
+
+ frame->fip.fip_ver = FIP_VER_ENCAPS(FIP_VER);
+ frame->fip.fip_op = htons(FIP_OP_VN2VN);
+ frame->fip.fip_subcode = sub;
+ frame->fip.fip_dl_len = htons(dlen / FIP_BPW);
+
+ frame->mac.fd_desc.fip_dtype = FIP_DT_MAC;
+ frame->mac.fd_desc.fip_dlen = sizeof(frame->mac) / FIP_BPW;
+ memcpy(frame->mac.fd_mac, fip->ctl_src_addr, ETH_ALEN);
+
+ frame->wwnn.fd_desc.fip_dtype = FIP_DT_NAME;
+ frame->wwnn.fd_desc.fip_dlen = sizeof(frame->wwnn) / FIP_BPW;
+ put_unaligned_be64(fip->lp->wwnn, &frame->wwnn.fd_wwn);
+
+ frame->vn.fd_desc.fip_dtype = FIP_DT_VN_ID;
+ frame->vn.fd_desc.fip_dlen = sizeof(frame->vn) / FIP_BPW;
+ hton24(frame->vn.fd_mac, FIP_VN_FC_MAP);
+ hton24(frame->vn.fd_mac + 3, fip->port_id);
+ hton24(frame->vn.fd_fc_id, fip->port_id);
+ put_unaligned_be64(fip->lp->wwpn, &frame->vn.fd_wwpn);
+
+ /*
+ * For claims, add FC-4 features.
+ * TBD: Add interface to get fc-4 types and features from libfc.
+ */
+ if (sub == FIP_SC_VN_CLAIM_NOTIFY || sub == FIP_SC_VN_CLAIM_REP) {
+ ff = (struct fip_fc4_feat *)(frame + 1);
+ ff->fd_desc.fip_dtype = FIP_DT_FC4F;
+ ff->fd_desc.fip_dlen = sizeof(*ff) / FIP_BPW;
+ ff->fd_fts = fip->lp->fcts;
+
+ fcp_feat = 0;
+ if (fip->lp->service_params & FCP_SPPF_INIT_FCN)
+ fcp_feat |= FCP_FEAT_INIT;
+ if (fip->lp->service_params & FCP_SPPF_TARG_FCN)
+ fcp_feat |= FCP_FEAT_TARG;
+ fcp_feat <<= (FC_TYPE_FCP * 4) % 32;
+ ff->fd_ff.fd_feat[FC_TYPE_FCP * 4 / 32] = htonl(fcp_feat);
+
+ size = (struct fip_size_desc *)(ff + 1);
+ size->fd_desc.fip_dtype = FIP_DT_FCOE_SIZE;
+ size->fd_desc.fip_dlen = sizeof(*size) / FIP_BPW;
+ size->fd_size = htons(fcoe_ctlr_fcoe_size(fip));
+ }
+
+ skb_put(skb, len);
+ skb->protocol = htons(ETH_P_FIP);
+ skb_reset_mac_header(skb);
+ skb_reset_network_header(skb);
+
+ fip->send(fip, skb);
+}
+
+/**
+ * fcoe_ctlr_vn_rport_callback - Event handler for rport events.
+ * @lport: The lport which is receiving the event
+ * @rdata: remote port private data
+ * @event: The event that occured
+ *
+ * Locking Note: The rport lock must not be held when calling this function.
+ */
+static void fcoe_ctlr_vn_rport_callback(struct fc_lport *lport,
+ struct fc_rport_priv *rdata,
+ enum fc_rport_event event)
+{
+ struct fcoe_ctlr *fip = lport->disc.priv;
+ struct fcoe_rport *frport = fcoe_ctlr_rport(rdata);
+
+ LIBFCOE_FIP_DBG(fip, "vn_rport_callback %x event %d\n",
+ rdata->ids.port_id, event);
+
+ mutex_lock(&fip->ctlr_mutex);
+ switch (event) {
+ case RPORT_EV_READY:
+ frport->login_count = 0;
+ break;
+ case RPORT_EV_LOGO:
+ case RPORT_EV_FAILED:
+ case RPORT_EV_STOP:
+ frport->login_count++;
+ if (frport->login_count > FCOE_CTLR_VN2VN_LOGIN_LIMIT) {
+ LIBFCOE_FIP_DBG(fip,
+ "rport FLOGI limited port_id %6.6x\n",
+ rdata->ids.port_id);
+ lport->tt.rport_logoff(rdata);
+ }
+ break;
+ default:
+ break;
+ }
+ mutex_unlock(&fip->ctlr_mutex);
+}
+
+static struct fc_rport_operations fcoe_ctlr_vn_rport_ops = {
+ .event_callback = fcoe_ctlr_vn_rport_callback,
+};
+
+/**
+ * fcoe_ctlr_disc_stop_locked() - stop discovery in VN2VN mode
+ * @fip: The FCoE controller
+ *
+ * Called with ctlr_mutex held.
+ */
+static void fcoe_ctlr_disc_stop_locked(struct fc_lport *lport)
+{
+ mutex_lock(&lport->disc.disc_mutex);
+ lport->disc.disc_callback = NULL;
+ mutex_unlock(&lport->disc.disc_mutex);
+}
+
+/**
+ * fcoe_ctlr_disc_stop() - stop discovery in VN2VN mode
+ * @fip: The FCoE controller
+ *
+ * Called through the local port template for discovery.
+ * Called without the ctlr_mutex held.
+ */
+static void fcoe_ctlr_disc_stop(struct fc_lport *lport)
+{
+ struct fcoe_ctlr *fip = lport->disc.priv;
+
+ mutex_lock(&fip->ctlr_mutex);
+ fcoe_ctlr_disc_stop_locked(lport);
+ mutex_unlock(&fip->ctlr_mutex);
+}
+
+/**
+ * fcoe_ctlr_disc_stop_final() - stop discovery for shutdown in VN2VN mode
+ * @fip: The FCoE controller
+ *
+ * Called through the local port template for discovery.
+ * Called without the ctlr_mutex held.
+ */
+static void fcoe_ctlr_disc_stop_final(struct fc_lport *lport)
+{
+ fcoe_ctlr_disc_stop(lport);
+ lport->tt.rport_flush_queue();
+ synchronize_rcu();
+}
+
+/**
+ * fcoe_ctlr_vn_restart() - VN2VN probe restart with new port_id
+ * @fip: The FCoE controller
+ *
+ * Called with fcoe_ctlr lock held.
+ */
+static void fcoe_ctlr_vn_restart(struct fcoe_ctlr *fip)
+{
+ unsigned long wait;
+ u32 port_id;
+
+ fcoe_ctlr_disc_stop_locked(fip->lp);
+
+ /*
+ * Get proposed port ID.
+ * If this is the first try after link up, use any previous port_id.
+ * If there was none, use the low bits of the port_name.
+ * On subsequent tries, get the next random one.
+ * Don't use reserved IDs, use another non-zero value, just as random.
+ */
+ port_id = fip->port_id;
+ if (fip->probe_tries)
+ port_id = prandom32(&fip->rnd_state) & 0xffff;
+ else if (!port_id)
+ port_id = fip->lp->wwpn & 0xffff;
+ if (!port_id || port_id == 0xffff)
+ port_id = 1;
+ fip->port_id = port_id;
+
+ if (fip->probe_tries < FIP_VN_RLIM_COUNT) {
+ fip->probe_tries++;
+ wait = random32() % FIP_VN_PROBE_WAIT;
+ } else
+ wait = FIP_VN_RLIM_INT;
+ mod_timer(&fip->timer, jiffies + msecs_to_jiffies(wait));
+ fcoe_ctlr_set_state(fip, FIP_ST_VNMP_START);
+}
+
+/**
+ * fcoe_ctlr_vn_start() - Start in VN2VN mode
+ * @fip: The FCoE controller
+ *
+ * Called with fcoe_ctlr lock held.
+ */
+static void fcoe_ctlr_vn_start(struct fcoe_ctlr *fip)
+{
+ fip->probe_tries = 0;
+ prandom32_seed(&fip->rnd_state, fip->lp->wwpn);
+ fcoe_ctlr_vn_restart(fip);
+}
+
+/**
+ * fcoe_ctlr_vn_parse - parse probe request or response
+ * @fip: The FCoE controller
+ * @skb: incoming packet
+ * @rdata: buffer for resulting parsed VN entry plus fcoe_rport
+ *
+ * Returns non-zero error number on error.
+ * Does not consume the packet.
+ */
+static int fcoe_ctlr_vn_parse(struct fcoe_ctlr *fip,
+ struct sk_buff *skb,
+ struct fc_rport_priv *rdata)
+{
+ struct fip_header *fiph;
+ struct fip_desc *desc = NULL;
+ struct fip_mac_desc *macd = NULL;
+ struct fip_wwn_desc *wwn = NULL;
+ struct fip_vn_desc *vn = NULL;
+ struct fip_size_desc *size = NULL;
+ struct fcoe_rport *frport;
+ size_t rlen;
+ size_t dlen;
+ u32 desc_mask = 0;
+ u32 dtype;
+ u8 sub;
+
+ memset(rdata, 0, sizeof(*rdata) + sizeof(*frport));
+ frport = fcoe_ctlr_rport(rdata);
+
+ fiph = (struct fip_header *)skb->data;
+ frport->flags = ntohs(fiph->fip_flags);
+
+ sub = fiph->fip_subcode;
+ switch (sub) {
+ case FIP_SC_VN_PROBE_REQ:
+ case FIP_SC_VN_PROBE_REP:
+ case FIP_SC_VN_BEACON:
+ desc_mask = BIT(FIP_DT_MAC) | BIT(FIP_DT_NAME) |
+ BIT(FIP_DT_VN_ID);
+ break;
+ case FIP_SC_VN_CLAIM_NOTIFY:
+ case FIP_SC_VN_CLAIM_REP:
+ desc_mask = BIT(FIP_DT_MAC) | BIT(FIP_DT_NAME) |
+ BIT(FIP_DT_VN_ID) | BIT(FIP_DT_FC4F) |
+ BIT(FIP_DT_FCOE_SIZE);
+ break;
+ default:
+ LIBFCOE_FIP_DBG(fip, "vn_parse unknown subcode %u\n", sub);
+ return -EINVAL;
+ }
+
+ rlen = ntohs(fiph->fip_dl_len) * 4;
+ if (rlen + sizeof(*fiph) > skb->len)
+ return -EINVAL;
+
+ desc = (struct fip_desc *)(fiph + 1);
+ while (rlen > 0) {
+ dlen = desc->fip_dlen * FIP_BPW;
+ if (dlen < sizeof(*desc) || dlen > rlen)
+ return -EINVAL;
+
+ dtype = desc->fip_dtype;
+ if (dtype < 32) {
+ if (!(desc_mask & BIT(dtype))) {
+ LIBFCOE_FIP_DBG(fip,
+ "unexpected or duplicated desc "
+ "desc type %u in "
+ "FIP VN2VN subtype %u\n",
+ dtype, sub);
+ return -EINVAL;
+ }
+ desc_mask &= ~BIT(dtype);
+ }
+
+ switch (dtype) {
+ case FIP_DT_MAC:
+ if (dlen != sizeof(struct fip_mac_desc))
+ goto len_err;
+ macd = (struct fip_mac_desc *)desc;
+ if (!is_valid_ether_addr(macd->fd_mac)) {
+ LIBFCOE_FIP_DBG(fip,
+ "Invalid MAC addr %pM in FIP VN2VN\n",
+ macd->fd_mac);
+ return -EINVAL;
+ }
+ memcpy(frport->enode_mac, macd->fd_mac, ETH_ALEN);
+ break;
+ case FIP_DT_NAME:
+ if (dlen != sizeof(struct fip_wwn_desc))
+ goto len_err;
+ wwn = (struct fip_wwn_desc *)desc;
+ rdata->ids.node_name = get_unaligned_be64(&wwn->fd_wwn);
+ break;
+ case FIP_DT_VN_ID:
+ if (dlen != sizeof(struct fip_vn_desc))
+ goto len_err;
+ vn = (struct fip_vn_desc *)desc;
+ memcpy(frport->vn_mac, vn->fd_mac, ETH_ALEN);
+ rdata->ids.port_id = ntoh24(vn->fd_fc_id);
+ rdata->ids.port_name = get_unaligned_be64(&vn->fd_wwpn);
+ break;
+ case FIP_DT_FC4F:
+ if (dlen != sizeof(struct fip_fc4_feat))
+ goto len_err;
+ break;
+ case FIP_DT_FCOE_SIZE:
+ if (dlen != sizeof(struct fip_size_desc))
+ goto len_err;
+ size = (struct fip_size_desc *)desc;
+ frport->fcoe_len = ntohs(size->fd_size);
+ break;
+ default:
+ LIBFCOE_FIP_DBG(fip, "unexpected descriptor type %x "
+ "in FIP probe\n", dtype);
+ /* standard says ignore unknown descriptors >= 128 */
+ if (dtype < FIP_DT_VENDOR_BASE)
+ return -EINVAL;
+ break;
+ }
+ desc = (struct fip_desc *)((char *)desc + dlen);
+ rlen -= dlen;
+ }
+ return 0;
+
+len_err:
+ LIBFCOE_FIP_DBG(fip, "FIP length error in descriptor type %x len %zu\n",
+ dtype, dlen);
+ return -EINVAL;
+}
+
+/**
+ * fcoe_ctlr_vn_send_claim() - send multicast FIP VN2VN Claim Notification.
+ * @fip: The FCoE controller
+ *
+ * Called with ctlr_mutex held.
+ */
+static void fcoe_ctlr_vn_send_claim(struct fcoe_ctlr *fip)
+{
+ fcoe_ctlr_vn_send(fip, FIP_SC_VN_CLAIM_NOTIFY, fcoe_all_vn2vn, 0);
+ fip->sol_time = jiffies;
+}
+
+/**
+ * fcoe_ctlr_vn_probe_req() - handle incoming VN2VN probe request.
+ * @fip: The FCoE controller
+ * @rdata: parsed remote port with frport from the probe request
+ *
+ * Called with ctlr_mutex held.
+ */
+static void fcoe_ctlr_vn_probe_req(struct fcoe_ctlr *fip,
+ struct fc_rport_priv *rdata)
+{
+ struct fcoe_rport *frport = fcoe_ctlr_rport(rdata);
+
+ if (rdata->ids.port_id != fip->port_id)
+ return;
+
+ switch (fip->state) {
+ case FIP_ST_VNMP_CLAIM:
+ case FIP_ST_VNMP_UP:
+ fcoe_ctlr_vn_send(fip, FIP_SC_VN_PROBE_REP,
+ frport->enode_mac, 0);
+ break;
+ case FIP_ST_VNMP_PROBE1:
+ case FIP_ST_VNMP_PROBE2:
+ /*
+ * Decide whether to reply to the Probe.
+ * Our selected address is never a "recorded" one, so
+ * only reply if our WWPN is greater and the
+ * Probe's REC bit is not set.
+ * If we don't reply, we will change our address.
+ */
+ if (fip->lp->wwpn > rdata->ids.port_name &&
+ !(frport->flags & FIP_FL_REC_OR_P2P)) {
+ fcoe_ctlr_vn_send(fip, FIP_SC_VN_PROBE_REP,
+ frport->enode_mac, 0);
+ break;
+ }
+ /* fall through */
+ case FIP_ST_VNMP_START:
+ fcoe_ctlr_vn_restart(fip);
+ break;
+ default:
+ break;
+ }
+}
+
+/**
+ * fcoe_ctlr_vn_probe_reply() - handle incoming VN2VN probe reply.
+ * @fip: The FCoE controller
+ * @rdata: parsed remote port with frport from the probe request
+ *
+ * Called with ctlr_mutex held.
+ */
+static void fcoe_ctlr_vn_probe_reply(struct fcoe_ctlr *fip,
+ struct fc_rport_priv *rdata)
+{
+ if (rdata->ids.port_id != fip->port_id)
+ return;
+ switch (fip->state) {
+ case FIP_ST_VNMP_START:
+ case FIP_ST_VNMP_PROBE1:
+ case FIP_ST_VNMP_PROBE2:
+ case FIP_ST_VNMP_CLAIM:
+ fcoe_ctlr_vn_restart(fip);
+ break;
+ case FIP_ST_VNMP_UP:
+ fcoe_ctlr_vn_send_claim(fip);
+ break;
+ default:
+ break;
+ }
+}
+
+/**
+ * fcoe_ctlr_vn_add() - Add a VN2VN entry to the list, based on a claim reply.
+ * @fip: The FCoE controller
+ * @new: newly-parsed remote port with frport as a template for new rdata
+ *
+ * Called with ctlr_mutex held.
+ */
+static void fcoe_ctlr_vn_add(struct fcoe_ctlr *fip, struct fc_rport_priv *new)
+{
+ struct fc_lport *lport = fip->lp;
+ struct fc_rport_priv *rdata;
+ struct fc_rport_identifiers *ids;
+ struct fcoe_rport *frport;
+ u32 port_id;
+
+ port_id = new->ids.port_id;
+ if (port_id == fip->port_id)
+ return;
+
+ mutex_lock(&lport->disc.disc_mutex);
+ rdata = lport->tt.rport_create(lport, port_id);
+ if (!rdata) {
+ mutex_unlock(&lport->disc.disc_mutex);
+ return;
+ }
+
+ rdata->ops = &fcoe_ctlr_vn_rport_ops;
+ rdata->disc_id = lport->disc.disc_id;
+
+ ids = &rdata->ids;
+ if ((ids->port_name != -1 && ids->port_name != new->ids.port_name) ||
+ (ids->node_name != -1 && ids->node_name != new->ids.node_name))
+ lport->tt.rport_logoff(rdata);
+ ids->port_name = new->ids.port_name;
+ ids->node_name = new->ids.node_name;
+ mutex_unlock(&lport->disc.disc_mutex);
+
+ frport = fcoe_ctlr_rport(rdata);
+ LIBFCOE_FIP_DBG(fip, "vn_add rport %6.6x %s\n",
+ port_id, frport->fcoe_len ? "old" : "new");
+ *frport = *fcoe_ctlr_rport(new);
+ frport->time = 0;
+}
+
+/**
+ * fcoe_ctlr_vn_lookup() - Find VN remote port's MAC address
+ * @fip: The FCoE controller
+ * @port_id: The port_id of the remote VN_node
+ * @mac: buffer which will hold the VN_NODE destination MAC address, if found.
+ *
+ * Returns non-zero error if no remote port found.
+ */
+static int fcoe_ctlr_vn_lookup(struct fcoe_ctlr *fip, u32 port_id, u8 *mac)
+{
+ struct fc_lport *lport = fip->lp;
+ struct fc_rport_priv *rdata;
+ struct fcoe_rport *frport;
+ int ret = -1;
+
+ rcu_read_lock();
+ rdata = lport->tt.rport_lookup(lport, port_id);
+ if (rdata) {
+ frport = fcoe_ctlr_rport(rdata);
+ memcpy(mac, frport->enode_mac, ETH_ALEN);
+ ret = 0;
+ }
+ rcu_read_unlock();
+ return ret;
+}
+
+/**
+ * fcoe_ctlr_vn_claim_notify() - handle received FIP VN2VN Claim Notification
+ * @fip: The FCoE controller
+ * @new: newly-parsed remote port with frport as a template for new rdata
+ *
+ * Called with ctlr_mutex held.
+ */
+static void fcoe_ctlr_vn_claim_notify(struct fcoe_ctlr *fip,
+ struct fc_rport_priv *new)
+{
+ struct fcoe_rport *frport = fcoe_ctlr_rport(new);
+
+ if (frport->flags & FIP_FL_REC_OR_P2P) {
+ fcoe_ctlr_vn_send(fip, FIP_SC_VN_PROBE_REQ, fcoe_all_vn2vn, 0);
+ return;
+ }
+ switch (fip->state) {
+ case FIP_ST_VNMP_START:
+ case FIP_ST_VNMP_PROBE1:
+ case FIP_ST_VNMP_PROBE2:
+ if (new->ids.port_id == fip->port_id)
+ fcoe_ctlr_vn_restart(fip);
+ break;
+ case FIP_ST_VNMP_CLAIM:
+ case FIP_ST_VNMP_UP:
+ if (new->ids.port_id == fip->port_id) {
+ if (new->ids.port_name > fip->lp->wwpn) {
+ fcoe_ctlr_vn_restart(fip);
+ break;
+ }
+ fcoe_ctlr_vn_send_claim(fip);
+ break;
+ }
+ fcoe_ctlr_vn_send(fip, FIP_SC_VN_CLAIM_REP, frport->enode_mac,
+ min((u32)frport->fcoe_len,
+ fcoe_ctlr_fcoe_size(fip)));
+ fcoe_ctlr_vn_add(fip, new);
+ break;
+ default:
+ break;
+ }
+}
+
+/**
+ * fcoe_ctlr_vn_claim_resp() - handle received Claim Response
+ * @fip: The FCoE controller that received the frame
+ * @new: newly-parsed remote port with frport from the Claim Response
+ *
+ * Called with ctlr_mutex held.
+ */
+static void fcoe_ctlr_vn_claim_resp(struct fcoe_ctlr *fip,
+ struct fc_rport_priv *new)
+{
+ LIBFCOE_FIP_DBG(fip, "claim resp from from rport %x - state %s\n",
+ new->ids.port_id, fcoe_ctlr_state(fip->state));
+ if (fip->state == FIP_ST_VNMP_UP || fip->state == FIP_ST_VNMP_CLAIM)
+ fcoe_ctlr_vn_add(fip, new);
+}
+
+/**
+ * fcoe_ctlr_vn_beacon() - handle received beacon.
+ * @fip: The FCoE controller that received the frame
+ * @new: newly-parsed remote port with frport from the Beacon
+ *
+ * Called with ctlr_mutex held.
+ */
+static void fcoe_ctlr_vn_beacon(struct fcoe_ctlr *fip,
+ struct fc_rport_priv *new)
+{
+ struct fc_lport *lport = fip->lp;
+ struct fc_rport_priv *rdata;
+ struct fcoe_rport *frport;
+
+ frport = fcoe_ctlr_rport(new);
+ if (frport->flags & FIP_FL_REC_OR_P2P) {
+ fcoe_ctlr_vn_send(fip, FIP_SC_VN_PROBE_REQ, fcoe_all_vn2vn, 0);
+ return;
+ }
+ mutex_lock(&lport->disc.disc_mutex);
+ rdata = lport->tt.rport_lookup(lport, new->ids.port_id);
+ if (rdata)
+ kref_get(&rdata->kref);
+ mutex_unlock(&lport->disc.disc_mutex);
+ if (rdata) {
+ if (rdata->ids.node_name == new->ids.node_name &&
+ rdata->ids.port_name == new->ids.port_name) {
+ frport = fcoe_ctlr_rport(rdata);
+ if (!frport->time && fip->state == FIP_ST_VNMP_UP)
+ lport->tt.rport_login(rdata);
+ frport->time = jiffies;
+ }
+ kref_put(&rdata->kref, lport->tt.rport_destroy);
+ return;
+ }
+ if (fip->state != FIP_ST_VNMP_UP)
+ return;
+
+ /*
+ * Beacon from a new neighbor.
+ * Send a claim notify if one hasn't been sent recently.
+ * Don't add the neighbor yet.
+ */
+ LIBFCOE_FIP_DBG(fip, "beacon from new rport %x. sending claim notify\n",
+ new->ids.port_id);
+ if (time_after(jiffies,
+ fip->sol_time + msecs_to_jiffies(FIP_VN_ANN_WAIT)))
+ fcoe_ctlr_vn_send_claim(fip);
+}
+
+/**
+ * fcoe_ctlr_vn_age() - Check for VN_ports without recent beacons
+ * @fip: The FCoE controller
+ *
+ * Called with ctlr_mutex held.
+ * Called only in state FIP_ST_VNMP_UP.
+ * Returns the soonest time for next age-out or a time far in the future.
+ */
+static unsigned long fcoe_ctlr_vn_age(struct fcoe_ctlr *fip)
+{
+ struct fc_lport *lport = fip->lp;
+ struct fc_rport_priv *rdata;
+ struct fcoe_rport *frport;
+ unsigned long next_time;
+ unsigned long deadline;
+
+ next_time = jiffies + msecs_to_jiffies(FIP_VN_BEACON_INT * 10);
+ mutex_lock(&lport->disc.disc_mutex);
+ list_for_each_entry_rcu(rdata, &lport->disc.rports, peers) {
+ frport = fcoe_ctlr_rport(rdata);
+ if (!frport->time)
+ continue;
+ deadline = frport->time +
+ msecs_to_jiffies(FIP_VN_BEACON_INT * 25 / 10);
+ if (time_after_eq(jiffies, deadline)) {
+ frport->time = 0;
+ LIBFCOE_FIP_DBG(fip,
+ "port %16.16llx fc_id %6.6x beacon expired\n",
+ rdata->ids.port_name, rdata->ids.port_id);
+ lport->tt.rport_logoff(rdata);
+ } else if (time_before(deadline, next_time))
+ next_time = deadline;
+ }
+ mutex_unlock(&lport->disc.disc_mutex);
+ return next_time;
+}
+
+/**
+ * fcoe_ctlr_vn_recv() - Receive a FIP frame
+ * @fip: The FCoE controller that received the frame
+ * @skb: The received FIP frame
+ *
+ * Returns non-zero if the frame is dropped.
+ * Always consumes the frame.
+ */
+static int fcoe_ctlr_vn_recv(struct fcoe_ctlr *fip, struct sk_buff *skb)
+{
+ struct fip_header *fiph;
+ enum fip_vn2vn_subcode sub;
+ union {
+ struct fc_rport_priv rdata;
+ struct fcoe_rport frport;
+ } buf;
+ int rc;
+
+ fiph = (struct fip_header *)skb->data;
+ sub = fiph->fip_subcode;
+
+ rc = fcoe_ctlr_vn_parse(fip, skb, &buf.rdata);
+ if (rc) {
+ LIBFCOE_FIP_DBG(fip, "vn_recv vn_parse error %d\n", rc);
+ goto drop;
+ }
+
+ mutex_lock(&fip->ctlr_mutex);
+ switch (sub) {
+ case FIP_SC_VN_PROBE_REQ:
+ fcoe_ctlr_vn_probe_req(fip, &buf.rdata);
+ break;
+ case FIP_SC_VN_PROBE_REP:
+ fcoe_ctlr_vn_probe_reply(fip, &buf.rdata);
+ break;
+ case FIP_SC_VN_CLAIM_NOTIFY:
+ fcoe_ctlr_vn_claim_notify(fip, &buf.rdata);
+ break;
+ case FIP_SC_VN_CLAIM_REP:
+ fcoe_ctlr_vn_claim_resp(fip, &buf.rdata);
+ break;
+ case FIP_SC_VN_BEACON:
+ fcoe_ctlr_vn_beacon(fip, &buf.rdata);
+ break;
+ default:
+ LIBFCOE_FIP_DBG(fip, "vn_recv unknown subcode %d\n", sub);
+ rc = -1;
+ break;
+ }
+ mutex_unlock(&fip->ctlr_mutex);
+drop:
+ kfree_skb(skb);
+ return rc;
+}
+
+/**
+ * fcoe_ctlr_disc_recv - discovery receive handler for VN2VN mode.
+ * @lport: The local port
+ * @fp: The received frame
+ *
+ * This should never be called since we don't see RSCNs or other
+ * fabric-generated ELSes.
+ */
+static void fcoe_ctlr_disc_recv(struct fc_lport *lport, struct fc_frame *fp)
+{
+ struct fc_seq_els_data rjt_data;
+
+ rjt_data.reason = ELS_RJT_UNSUP;
+ rjt_data.explan = ELS_EXPL_NONE;
+ lport->tt.seq_els_rsp_send(fp, ELS_LS_RJT, &rjt_data);
+ fc_frame_free(fp);
+}
+
+/**
+ * fcoe_ctlr_disc_recv - start discovery for VN2VN mode.
+ * @fip: The FCoE controller
+ *
+ * This sets a flag indicating that remote ports should be created
+ * and started for the peers we discover. We use the disc_callback
+ * pointer as that flag. Peers already discovered are created here.
+ *
+ * The lport lock is held during this call. The callback must be done
+ * later, without holding either the lport or discovery locks.
+ * The fcoe_ctlr lock may also be held during this call.
+ */
+static void fcoe_ctlr_disc_start(void (*callback)(struct fc_lport *,
+ enum fc_disc_event),
+ struct fc_lport *lport)
+{
+ struct fc_disc *disc = &lport->disc;
+ struct fcoe_ctlr *fip = disc->priv;
+
+ mutex_lock(&disc->disc_mutex);
+ disc->disc_callback = callback;
+ disc->disc_id = (disc->disc_id + 2) | 1;
+ disc->pending = 1;
+ schedule_work(&fip->timer_work);
+ mutex_unlock(&disc->disc_mutex);
+}
+
+/**
+ * fcoe_ctlr_vn_disc() - report FIP VN_port discovery results after claim state.
+ * @fip: The FCoE controller
+ *
+ * Starts the FLOGI and PLOGI login process to each discovered rport for which
+ * we've received at least one beacon.
+ * Performs the discovery complete callback.
+ */
+static void fcoe_ctlr_vn_disc(struct fcoe_ctlr *fip)
+{
+ struct fc_lport *lport = fip->lp;
+ struct fc_disc *disc = &lport->disc;
+ struct fc_rport_priv *rdata;
+ struct fcoe_rport *frport;
+ void (*callback)(struct fc_lport *, enum fc_disc_event);
+
+ mutex_lock(&disc->disc_mutex);
+ callback = disc->pending ? disc->disc_callback : NULL;
+ disc->pending = 0;
+ list_for_each_entry_rcu(rdata, &disc->rports, peers) {
+ frport = fcoe_ctlr_rport(rdata);
+ if (frport->time)
+ lport->tt.rport_login(rdata);
+ }
+ mutex_unlock(&disc->disc_mutex);
+ if (callback)
+ callback(lport, DISC_EV_SUCCESS);
+}
+
+/**
+ * fcoe_ctlr_vn_timeout - timer work function for VN2VN mode.
+ * @fip: The FCoE controller
+ */
+static void fcoe_ctlr_vn_timeout(struct fcoe_ctlr *fip)
+{
+ unsigned long next_time;
+ u8 mac[ETH_ALEN];
+ u32 new_port_id = 0;
+
+ mutex_lock(&fip->ctlr_mutex);
+ switch (fip->state) {
+ case FIP_ST_VNMP_START:
+ fcoe_ctlr_set_state(fip, FIP_ST_VNMP_PROBE1);
+ fcoe_ctlr_vn_send(fip, FIP_SC_VN_PROBE_REQ, fcoe_all_vn2vn, 0);
+ next_time = jiffies + msecs_to_jiffies(FIP_VN_PROBE_WAIT);
+ break;
+ case FIP_ST_VNMP_PROBE1:
+ fcoe_ctlr_set_state(fip, FIP_ST_VNMP_PROBE2);
+ fcoe_ctlr_vn_send(fip, FIP_SC_VN_PROBE_REQ, fcoe_all_vn2vn, 0);
+ next_time = jiffies + msecs_to_jiffies(FIP_VN_ANN_WAIT);
+ break;
+ case FIP_ST_VNMP_PROBE2:
+ fcoe_ctlr_set_state(fip, FIP_ST_VNMP_CLAIM);
+ new_port_id = fip->port_id;
+ hton24(mac, FIP_VN_FC_MAP);
+ hton24(mac + 3, new_port_id);
+ fcoe_ctlr_map_dest(fip);
+ fip->update_mac(fip->lp, mac);
+ fcoe_ctlr_vn_send_claim(fip);
+ next_time = jiffies + msecs_to_jiffies(FIP_VN_ANN_WAIT);
+ break;
+ case FIP_ST_VNMP_CLAIM:
+ /*
+ * This may be invoked either by starting discovery so don't
+ * go to the next state unless it's been long enough.
+ */
+ next_time = fip->sol_time + msecs_to_jiffies(FIP_VN_ANN_WAIT);
+ if (time_after_eq(jiffies, next_time)) {
+ fcoe_ctlr_set_state(fip, FIP_ST_VNMP_UP);
+ fcoe_ctlr_vn_send(fip, FIP_SC_VN_BEACON,
+ fcoe_all_vn2vn, 0);
+ next_time = jiffies + msecs_to_jiffies(FIP_VN_ANN_WAIT);
+ fip->port_ka_time = next_time;
+ }
+ fcoe_ctlr_vn_disc(fip);
+ break;
+ case FIP_ST_VNMP_UP:
+ next_time = fcoe_ctlr_vn_age(fip);
+ if (time_after_eq(jiffies, fip->port_ka_time)) {
+ fcoe_ctlr_vn_send(fip, FIP_SC_VN_BEACON,
+ fcoe_all_vn2vn, 0);
+ fip->port_ka_time = jiffies +
+ msecs_to_jiffies(FIP_VN_BEACON_INT +
+ (random32() % FIP_VN_BEACON_FUZZ));
+ }
+ if (time_before(fip->port_ka_time, next_time))
+ next_time = fip->port_ka_time;
+ break;
+ case FIP_ST_LINK_WAIT:
+ goto unlock;
+ default:
+ WARN(1, "unexpected state %d", fip->state);
+ goto unlock;
+ }
+ mod_timer(&fip->timer, next_time);
+unlock:
+ mutex_unlock(&fip->ctlr_mutex);
+
+ /* If port ID is new, notify local port after dropping ctlr_mutex */
+ if (new_port_id)
+ fc_lport_set_local_id(fip->lp, new_port_id);
+}
+
+/**
* fcoe_libfc_config() - Sets up libfc related properties for local port
* @lp: The local port to configure libfc for
+ * @fip: The FCoE controller in use by the local port
* @tt: The libfc function template
+ * @init_fcp: If non-zero, the FCP portion of libfc should be initialized
*
* Returns : 0 for success
*/
-int fcoe_libfc_config(struct fc_lport *lport,
- struct libfc_function_template *tt)
+int fcoe_libfc_config(struct fc_lport *lport, struct fcoe_ctlr *fip,
+ const struct libfc_function_template *tt, int init_fcp)
{
/* Set the function pointers set by the LLDD */
memcpy(&lport->tt, tt, sizeof(*tt));
- if (fc_fcp_init(lport))
+ if (init_fcp && fc_fcp_init(lport))
return -ENOMEM;
fc_exch_init(lport);
fc_elsct_init(lport);
fc_lport_init(lport);
+ if (fip->mode == FIP_MODE_VN2VN)
+ lport->rport_priv_size = sizeof(struct fcoe_rport);
fc_rport_init(lport);
- fc_disc_init(lport);
-
+ if (fip->mode == FIP_MODE_VN2VN) {
+ lport->point_to_multipoint = 1;
+ lport->tt.disc_recv_req = fcoe_ctlr_disc_recv;
+ lport->tt.disc_start = fcoe_ctlr_disc_start;
+ lport->tt.disc_stop = fcoe_ctlr_disc_stop;
+ lport->tt.disc_stop_final = fcoe_ctlr_disc_stop_final;
+ mutex_init(&lport->disc.disc_mutex);
+ INIT_LIST_HEAD(&lport->disc.rports);
+ lport->disc.priv = fip;
+ } else {
+ fc_disc_init(lport);
+ }
return 0;
}
EXPORT_SYMBOL_GPL(fcoe_libfc_config);
-
diff --git a/drivers/scsi/fnic/fnic_main.c b/drivers/scsi/fnic/fnic_main.c
index 265e73d9cd6..9eb7a9ebcca 100644
--- a/drivers/scsi/fnic/fnic_main.c
+++ b/drivers/scsi/fnic/fnic_main.c
@@ -617,7 +617,6 @@ static int __devinit fnic_probe(struct pci_dev *pdev,
fnic->ctlr.send = fnic_eth_send;
fnic->ctlr.update_mac = fnic_update_mac;
fnic->ctlr.get_src_addr = fnic_get_mac;
- fcoe_ctlr_init(&fnic->ctlr);
if (fnic->config.flags & VFCF_FIP_CAPABLE) {
shost_printk(KERN_INFO, fnic->lport->host,
"firmware supports FIP\n");
@@ -625,10 +624,11 @@ static int __devinit fnic_probe(struct pci_dev *pdev,
vnic_dev_packet_filter(fnic->vdev, 1, 1, 0, 0, 0);
vnic_dev_add_addr(fnic->vdev, FIP_ALL_ENODE_MACS);
vnic_dev_add_addr(fnic->vdev, fnic->ctlr.ctl_src_addr);
+ fcoe_ctlr_init(&fnic->ctlr, FIP_MODE_AUTO);
} else {
shost_printk(KERN_INFO, fnic->lport->host,
"firmware uses non-FIP mode\n");
- fnic->ctlr.mode = FIP_ST_NON_FIP;
+ fcoe_ctlr_init(&fnic->ctlr, FIP_MODE_NON_FIP);
}
fnic->state = FNIC_IN_FC_MODE;
@@ -673,7 +673,6 @@ static int __devinit fnic_probe(struct pci_dev *pdev,
/* Start local port initiatialization */
lp->link_up = 0;
- lp->tt = fnic_transport_template;
lp->max_retry_count = fnic->config.flogi_retries;
lp->max_rport_retry_count = fnic->config.plogi_retries;
@@ -689,11 +688,7 @@ static int __devinit fnic_probe(struct pci_dev *pdev,
fc_set_wwnn(lp, fnic->config.node_wwn);
fc_set_wwpn(lp, fnic->config.port_wwn);
- fc_lport_init(lp);
- fc_exch_init(lp);
- fc_elsct_init(lp);
- fc_rport_init(lp);
- fc_disc_init(lp);
+ fcoe_libfc_config(lp, &fnic->ctlr, &fnic_transport_template, 0);
if (!fc_exch_mgr_alloc(lp, FC_CLASS_3, FCPIO_HOST_EXCH_RANGE_START,
FCPIO_HOST_EXCH_RANGE_END, NULL)) {
diff --git a/drivers/scsi/fnic/fnic_scsi.c b/drivers/scsi/fnic/fnic_scsi.c
index 3cc47c6e1ad..198cbab3e89 100644
--- a/drivers/scsi/fnic/fnic_scsi.c
+++ b/drivers/scsi/fnic/fnic_scsi.c
@@ -1246,11 +1246,10 @@ int fnic_abort_cmd(struct scsi_cmnd *sc)
lp = shost_priv(sc->device->host);
fnic = lport_priv(lp);
- FNIC_SCSI_DBG(KERN_DEBUG,
- fnic->lport->host,
- "Abort Cmd called FCID 0x%x, LUN 0x%x TAG %d\n",
- (starget_to_rport(scsi_target(sc->device)))->port_id,
- sc->device->lun, sc->request->tag);
+ rport = starget_to_rport(scsi_target(sc->device));
+ FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host,
+ "Abort Cmd called FCID 0x%x, LUN 0x%x TAG %d\n",
+ rport->port_id, sc->device->lun, sc->request->tag);
if (lp->state != LPORT_ST_READY || !(lp->link_up)) {
ret = FAILED;
@@ -1299,7 +1298,6 @@ int fnic_abort_cmd(struct scsi_cmnd *sc)
* port is up, then send abts to the remote port to terminate
* the IO. Else, just locally terminate the IO in the firmware
*/
- rport = starget_to_rport(scsi_target(sc->device));
if (fc_remote_port_chkready(rport) == 0)
task_req = FCPIO_ITMF_ABT_TASK;
else
@@ -1418,7 +1416,6 @@ static int fnic_clean_pending_aborts(struct fnic *fnic,
unsigned long flags;
int ret = 0;
struct scsi_cmnd *sc;
- struct fc_rport *rport;
struct scsi_lun fc_lun;
struct scsi_device *lun_dev = lr_sc->device;
DECLARE_COMPLETION_ONSTACK(tm_done);
@@ -1458,7 +1455,6 @@ static int fnic_clean_pending_aborts(struct fnic *fnic,
/* Now queue the abort command to firmware */
int_to_scsilun(sc->device->lun, &fc_lun);
- rport = starget_to_rport(scsi_target(sc->device));
if (fnic_queue_abort_io_req(fnic, tag,
FCPIO_ITMF_ABT_TASK_TERM,
@@ -1528,18 +1524,16 @@ int fnic_device_reset(struct scsi_cmnd *sc)
lp = shost_priv(sc->device->host);
fnic = lport_priv(lp);
- FNIC_SCSI_DBG(KERN_DEBUG,
- fnic->lport->host,
- "Device reset called FCID 0x%x, LUN 0x%x\n",
- (starget_to_rport(scsi_target(sc->device)))->port_id,
- sc->device->lun);
+ rport = starget_to_rport(scsi_target(sc->device));
+ FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host,
+ "Device reset called FCID 0x%x, LUN 0x%x\n",
+ rport->port_id, sc->device->lun);
if (lp->state != LPORT_ST_READY || !(lp->link_up))
goto fnic_device_reset_end;
/* Check if remote port up */
- rport = starget_to_rport(scsi_target(sc->device));
if (fc_remote_port_chkready(rport))
goto fnic_device_reset_end;
diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c
index 6660fa92ffa..8a8f803439e 100644
--- a/drivers/scsi/hosts.c
+++ b/drivers/scsi/hosts.c
@@ -32,6 +32,7 @@
#include <linux/completion.h>
#include <linux/transport_class.h>
#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
#include <scsi/scsi_device.h>
#include <scsi/scsi_host.h>
@@ -156,6 +157,7 @@ EXPORT_SYMBOL(scsi_host_set_state);
void scsi_remove_host(struct Scsi_Host *shost)
{
unsigned long flags;
+
mutex_lock(&shost->scan_mutex);
spin_lock_irqsave(shost->host_lock, flags);
if (scsi_host_set_state(shost, SHOST_CANCEL))
@@ -165,6 +167,8 @@ void scsi_remove_host(struct Scsi_Host *shost)
return;
}
spin_unlock_irqrestore(shost->host_lock, flags);
+
+ scsi_autopm_get_host(shost);
scsi_forget_host(shost);
mutex_unlock(&shost->scan_mutex);
scsi_proc_host_rm(shost);
@@ -216,12 +220,14 @@ int scsi_add_host_with_dma(struct Scsi_Host *shost, struct device *dev,
shost->shost_gendev.parent = dev ? dev : &platform_bus;
shost->dma_dev = dma_dev;
- device_enable_async_suspend(&shost->shost_gendev);
-
error = device_add(&shost->shost_gendev);
if (error)
goto out;
+ pm_runtime_set_active(&shost->shost_gendev);
+ pm_runtime_enable(&shost->shost_gendev);
+ device_enable_async_suspend(&shost->shost_gendev);
+
scsi_host_set_state(shost, SHOST_RUNNING);
get_device(shost->shost_gendev.parent);
@@ -325,7 +331,6 @@ struct Scsi_Host *scsi_host_alloc(struct scsi_host_template *sht, int privsize)
{
struct Scsi_Host *shost;
gfp_t gfp_mask = GFP_KERNEL;
- int rval;
if (sht->unchecked_isa_dma && privsize)
gfp_mask |= __GFP_DMA;
@@ -420,7 +425,8 @@ struct Scsi_Host *scsi_host_alloc(struct scsi_host_template *sht, int privsize)
shost->ehandler = kthread_run(scsi_error_handler, shost,
"scsi_eh_%d", shost->host_no);
if (IS_ERR(shost->ehandler)) {
- rval = PTR_ERR(shost->ehandler);
+ printk(KERN_WARNING "scsi%d: error handler thread failed to spawn, error = %ld\n",
+ shost->host_no, PTR_ERR(shost->ehandler));
goto fail_kfree;
}
diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c
index c016426b31b..4f5551b5fe5 100644
--- a/drivers/scsi/hpsa.c
+++ b/drivers/scsi/hpsa.c
@@ -86,10 +86,17 @@ static const struct pci_device_id hpsa_pci_device_id[] = {
{PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSE, 0x103C, 0x324a},
{PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSE, 0x103C, 0x324b},
{PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSE, 0x103C, 0x3233},
+ {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSE, 0x103C, 0x3250},
+ {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSE, 0x103C, 0x3251},
+ {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSE, 0x103C, 0x3252},
+ {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSE, 0x103C, 0x3253},
+ {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSE, 0x103C, 0x3254},
#define PCI_DEVICE_ID_HP_CISSF 0x333f
{PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSF, 0x103C, 0x333F},
{PCI_VENDOR_ID_HP, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
PCI_CLASS_STORAGE_RAID << 8, 0xffff << 8, 0},
+ {PCI_VENDOR_ID_COMPAQ, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
+ PCI_CLASS_STORAGE_RAID << 8, 0xffff << 8, 0},
{0,}
};
@@ -109,12 +116,18 @@ static struct board_type products[] = {
{0x324b103C, "Smart Array P711m", &SA5_access},
{0x3233103C, "StorageWorks P1210m", &SA5_access},
{0x333F103C, "StorageWorks P1210m", &SA5_access},
+ {0x3250103C, "Smart Array", &SA5_access},
+ {0x3250113C, "Smart Array", &SA5_access},
+ {0x3250123C, "Smart Array", &SA5_access},
+ {0x3250133C, "Smart Array", &SA5_access},
+ {0x3250143C, "Smart Array", &SA5_access},
{0xFFFF103C, "Unknown Smart Array", &SA5_access},
};
static int number_of_controllers;
-static irqreturn_t do_hpsa_intr(int irq, void *dev_id);
+static irqreturn_t do_hpsa_intr_intx(int irq, void *dev_id);
+static irqreturn_t do_hpsa_intr_msi(int irq, void *dev_id);
static int hpsa_ioctl(struct scsi_device *dev, int cmd, void *arg);
static void start_io(struct ctlr_info *h);
@@ -148,6 +161,8 @@ static ssize_t lunid_show(struct device *dev,
struct device_attribute *attr, char *buf);
static ssize_t unique_id_show(struct device *dev,
struct device_attribute *attr, char *buf);
+static ssize_t host_show_firmware_revision(struct device *dev,
+ struct device_attribute *attr, char *buf);
static void hpsa_update_scsi_devices(struct ctlr_info *h, int hostno);
static ssize_t host_store_rescan(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count);
@@ -158,13 +173,21 @@ static void check_ioctl_unit_attention(struct ctlr_info *h,
/* performant mode helper functions */
static void calc_bucket_map(int *bucket, int num_buckets,
int nsgs, int *bucket_map);
-static void hpsa_put_ctlr_into_performant_mode(struct ctlr_info *h);
+static __devinit void hpsa_put_ctlr_into_performant_mode(struct ctlr_info *h);
static inline u32 next_command(struct ctlr_info *h);
+static int __devinit hpsa_find_cfg_addrs(struct pci_dev *pdev,
+ void __iomem *vaddr, u32 *cfg_base_addr, u64 *cfg_base_addr_index,
+ u64 *cfg_offset);
+static int __devinit hpsa_pci_find_memory_BAR(struct pci_dev *pdev,
+ unsigned long *memory_bar);
+static int __devinit hpsa_lookup_board_id(struct pci_dev *pdev, u32 *board_id);
static DEVICE_ATTR(raid_level, S_IRUGO, raid_level_show, NULL);
static DEVICE_ATTR(lunid, S_IRUGO, lunid_show, NULL);
static DEVICE_ATTR(unique_id, S_IRUGO, unique_id_show, NULL);
static DEVICE_ATTR(rescan, S_IWUSR, NULL, host_store_rescan);
+static DEVICE_ATTR(firmware_revision, S_IRUGO,
+ host_show_firmware_revision, NULL);
static struct device_attribute *hpsa_sdev_attrs[] = {
&dev_attr_raid_level,
@@ -175,6 +198,7 @@ static struct device_attribute *hpsa_sdev_attrs[] = {
static struct device_attribute *hpsa_shost_attrs[] = {
&dev_attr_rescan,
+ &dev_attr_firmware_revision,
NULL,
};
@@ -260,6 +284,21 @@ static ssize_t host_store_rescan(struct device *dev,
return count;
}
+static ssize_t host_show_firmware_revision(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct ctlr_info *h;
+ struct Scsi_Host *shost = class_to_shost(dev);
+ unsigned char *fwrev;
+
+ h = shost_to_hba(shost);
+ if (!h->hba_inquiry_data)
+ return 0;
+ fwrev = &h->hba_inquiry_data[32];
+ return snprintf(buf, 20, "%c%c%c%c\n",
+ fwrev[0], fwrev[1], fwrev[2], fwrev[3]);
+}
+
/* Enqueuing and dequeuing functions for cmdlists. */
static inline void addQ(struct hlist_head *list, struct CommandList *c)
{
@@ -1440,12 +1479,6 @@ static int hpsa_update_device_info(struct ctlr_info *h,
goto bail_out;
}
- /* As a side effect, record the firmware version number
- * if we happen to be talking to the RAID controller.
- */
- if (is_hba_lunid(scsi3addr))
- memcpy(h->firm_ver, &inq_buff[32], 4);
-
this_device->devtype = (inq_buff[0] & 0x1f);
memcpy(this_device->scsi3addr, scsi3addr, 8);
memcpy(this_device->vendor, &inq_buff[8],
@@ -2826,9 +2859,8 @@ static inline bool interrupt_pending(struct ctlr_info *h)
static inline long interrupt_not_for_us(struct ctlr_info *h)
{
- return !(h->msi_vector || h->msix_vector) &&
- ((h->access.intr_pending(h) == 0) ||
- (h->interrupts_enabled == 0));
+ return (h->access.intr_pending(h) == 0) ||
+ (h->interrupts_enabled == 0);
}
static inline int bad_tag(struct ctlr_info *h, u32 tag_index,
@@ -2902,7 +2934,7 @@ static inline u32 process_nonindexed_cmd(struct ctlr_info *h,
return next_command(h);
}
-static irqreturn_t do_hpsa_intr(int irq, void *dev_id)
+static irqreturn_t do_hpsa_intr_intx(int irq, void *dev_id)
{
struct ctlr_info *h = dev_id;
unsigned long flags;
@@ -2911,6 +2943,26 @@ static irqreturn_t do_hpsa_intr(int irq, void *dev_id)
if (interrupt_not_for_us(h))
return IRQ_NONE;
spin_lock_irqsave(&h->lock, flags);
+ while (interrupt_pending(h)) {
+ raw_tag = get_next_completion(h);
+ while (raw_tag != FIFO_EMPTY) {
+ if (hpsa_tag_contains_index(raw_tag))
+ raw_tag = process_indexed_cmd(h, raw_tag);
+ else
+ raw_tag = process_nonindexed_cmd(h, raw_tag);
+ }
+ }
+ spin_unlock_irqrestore(&h->lock, flags);
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t do_hpsa_intr_msi(int irq, void *dev_id)
+{
+ struct ctlr_info *h = dev_id;
+ unsigned long flags;
+ u32 raw_tag;
+
+ spin_lock_irqsave(&h->lock, flags);
raw_tag = get_next_completion(h);
while (raw_tag != FIFO_EMPTY) {
if (hpsa_tag_contains_index(raw_tag))
@@ -3052,17 +3104,75 @@ static __devinit int hpsa_reset_msi(struct pci_dev *pdev)
return 0;
}
-/* This does a hard reset of the controller using PCI power management
- * states.
- */
-static __devinit int hpsa_hard_reset_controller(struct pci_dev *pdev)
+static int hpsa_controller_hard_reset(struct pci_dev *pdev,
+ void * __iomem vaddr, bool use_doorbell)
{
- u16 pmcsr, saved_config_space[32];
- int i, pos;
+ u16 pmcsr;
+ int pos;
- dev_info(&pdev->dev, "using PCI PM to reset controller\n");
+ if (use_doorbell) {
+ /* For everything after the P600, the PCI power state method
+ * of resetting the controller doesn't work, so we have this
+ * other way using the doorbell register.
+ */
+ dev_info(&pdev->dev, "using doorbell to reset controller\n");
+ writel(DOORBELL_CTLR_RESET, vaddr + SA5_DOORBELL);
+ msleep(1000);
+ } else { /* Try to do it the PCI power state way */
+
+ /* Quoting from the Open CISS Specification: "The Power
+ * Management Control/Status Register (CSR) controls the power
+ * state of the device. The normal operating state is D0,
+ * CSR=00h. The software off state is D3, CSR=03h. To reset
+ * the controller, place the interface device in D3 then to D0,
+ * this causes a secondary PCI reset which will reset the
+ * controller." */
+
+ pos = pci_find_capability(pdev, PCI_CAP_ID_PM);
+ if (pos == 0) {
+ dev_err(&pdev->dev,
+ "hpsa_reset_controller: "
+ "PCI PM not supported\n");
+ return -ENODEV;
+ }
+ dev_info(&pdev->dev, "using PCI PM to reset controller\n");
+ /* enter the D3hot power management state */
+ pci_read_config_word(pdev, pos + PCI_PM_CTRL, &pmcsr);
+ pmcsr &= ~PCI_PM_CTRL_STATE_MASK;
+ pmcsr |= PCI_D3hot;
+ pci_write_config_word(pdev, pos + PCI_PM_CTRL, pmcsr);
- /* This is very nearly the same thing as
+ msleep(500);
+
+ /* enter the D0 power management state */
+ pmcsr &= ~PCI_PM_CTRL_STATE_MASK;
+ pmcsr |= PCI_D0;
+ pci_write_config_word(pdev, pos + PCI_PM_CTRL, pmcsr);
+
+ msleep(500);
+ }
+ return 0;
+}
+
+/* This does a hard reset of the controller using PCI power management
+ * states or the using the doorbell register.
+ */
+static __devinit int hpsa_kdump_hard_reset_controller(struct pci_dev *pdev)
+{
+ u16 saved_config_space[32];
+ u64 cfg_offset;
+ u32 cfg_base_addr;
+ u64 cfg_base_addr_index;
+ void __iomem *vaddr;
+ unsigned long paddr;
+ u32 misc_fw_support, active_transport;
+ int rc, i;
+ struct CfgTable __iomem *cfgtable;
+ bool use_doorbell;
+ u32 board_id;
+
+ /* For controllers as old as the P600, this is very nearly
+ * the same thing as
*
* pci_save_state(pci_dev);
* pci_set_power_state(pci_dev, PCI_D3hot);
@@ -3076,41 +3186,54 @@ static __devinit int hpsa_hard_reset_controller(struct pci_dev *pdev)
* violate the ordering requirements for restoring the
* configuration space from the CCISS document (see the
* comment below). So we roll our own ....
+ *
+ * For controllers newer than the P600, the pci power state
+ * method of resetting doesn't work so we have another way
+ * using the doorbell register.
*/
+ /* Exclude 640x boards. These are two pci devices in one slot
+ * which share a battery backed cache module. One controls the
+ * cache, the other accesses the cache through the one that controls
+ * it. If we reset the one controlling the cache, the other will
+ * likely not be happy. Just forbid resetting this conjoined mess.
+ * The 640x isn't really supported by hpsa anyway.
+ */
+ hpsa_lookup_board_id(pdev, &board_id);
+ if (board_id == 0x409C0E11 || board_id == 0x409D0E11)
+ return -ENOTSUPP;
+
for (i = 0; i < 32; i++)
pci_read_config_word(pdev, 2*i, &saved_config_space[i]);
- pos = pci_find_capability(pdev, PCI_CAP_ID_PM);
- if (pos == 0) {
- dev_err(&pdev->dev,
- "hpsa_reset_controller: PCI PM not supported\n");
- return -ENODEV;
- }
-
- /* Quoting from the Open CISS Specification: "The Power
- * Management Control/Status Register (CSR) controls the power
- * state of the device. The normal operating state is D0,
- * CSR=00h. The software off state is D3, CSR=03h. To reset
- * the controller, place the interface device in D3 then to
- * D0, this causes a secondary PCI reset which will reset the
- * controller."
- */
- /* enter the D3hot power management state */
- pci_read_config_word(pdev, pos + PCI_PM_CTRL, &pmcsr);
- pmcsr &= ~PCI_PM_CTRL_STATE_MASK;
- pmcsr |= PCI_D3hot;
- pci_write_config_word(pdev, pos + PCI_PM_CTRL, pmcsr);
+ /* find the first memory BAR, so we can find the cfg table */
+ rc = hpsa_pci_find_memory_BAR(pdev, &paddr);
+ if (rc)
+ return rc;
+ vaddr = remap_pci_mem(paddr, 0x250);
+ if (!vaddr)
+ return -ENOMEM;
- msleep(500);
+ /* find cfgtable in order to check if reset via doorbell is supported */
+ rc = hpsa_find_cfg_addrs(pdev, vaddr, &cfg_base_addr,
+ &cfg_base_addr_index, &cfg_offset);
+ if (rc)
+ goto unmap_vaddr;
+ cfgtable = remap_pci_mem(pci_resource_start(pdev,
+ cfg_base_addr_index) + cfg_offset, sizeof(*cfgtable));
+ if (!cfgtable) {
+ rc = -ENOMEM;
+ goto unmap_vaddr;
+ }
- /* enter the D0 power management state */
- pmcsr &= ~PCI_PM_CTRL_STATE_MASK;
- pmcsr |= PCI_D0;
- pci_write_config_word(pdev, pos + PCI_PM_CTRL, pmcsr);
+ /* If reset via doorbell register is supported, use that. */
+ misc_fw_support = readl(&cfgtable->misc_fw_support);
+ use_doorbell = misc_fw_support & MISC_FW_DOORBELL_RESET;
- msleep(500);
+ rc = hpsa_controller_hard_reset(pdev, vaddr, use_doorbell);
+ if (rc)
+ goto unmap_cfgtable;
/* Restore the PCI configuration space. The Open CISS
* Specification says, "Restore the PCI Configuration
@@ -3127,7 +3250,29 @@ static __devinit int hpsa_hard_reset_controller(struct pci_dev *pdev)
wmb();
pci_write_config_word(pdev, 4, saved_config_space[2]);
- return 0;
+ /* Some devices (notably the HP Smart Array 5i Controller)
+ need a little pause here */
+ msleep(HPSA_POST_RESET_PAUSE_MSECS);
+
+ /* Controller should be in simple mode at this point. If it's not,
+ * It means we're on one of those controllers which doesn't support
+ * the doorbell reset method and on which the PCI power management reset
+ * method doesn't work (P800, for example.)
+ * In those cases, pretend the reset worked and hope for the best.
+ */
+ active_transport = readl(&cfgtable->TransportActive);
+ if (active_transport & PERFORMANT_MODE) {
+ dev_warn(&pdev->dev, "Unable to successfully reset controller,"
+ " proceeding anyway.\n");
+ rc = -ENOTSUPP;
+ }
+
+unmap_cfgtable:
+ iounmap(cfgtable);
+
+unmap_vaddr:
+ iounmap(vaddr);
+ return rc;
}
/*
@@ -3135,9 +3280,9 @@ static __devinit int hpsa_hard_reset_controller(struct pci_dev *pdev)
* the io functions.
* This is for debug only.
*/
-#ifdef HPSA_DEBUG
static void print_cfg_table(struct device *dev, struct CfgTable *tb)
{
+#ifdef HPSA_DEBUG
int i;
char temp_name[17];
@@ -3167,8 +3312,8 @@ static void print_cfg_table(struct device *dev, struct CfgTable *tb)
dev_info(dev, " Server Name = %s\n", temp_name);
dev_info(dev, " Heartbeat Counter = 0x%x\n\n\n",
readl(&(tb->HeartBeat)));
-}
#endif /* HPSA_DEBUG */
+}
static int find_PCI_BAR_index(struct pci_dev *pdev, unsigned long pci_bar_addr)
{
@@ -3209,8 +3354,7 @@ static int find_PCI_BAR_index(struct pci_dev *pdev, unsigned long pci_bar_addr)
* controllers that are capable. If not, we use IO-APIC mode.
*/
-static void __devinit hpsa_interrupt_mode(struct ctlr_info *h,
- struct pci_dev *pdev, u32 board_id)
+static void __devinit hpsa_interrupt_mode(struct ctlr_info *h)
{
#ifdef CONFIG_PCI_MSI
int err;
@@ -3219,13 +3363,12 @@ static void __devinit hpsa_interrupt_mode(struct ctlr_info *h,
};
/* Some boards advertise MSI but don't really support it */
- if ((board_id == 0x40700E11) ||
- (board_id == 0x40800E11) ||
- (board_id == 0x40820E11) || (board_id == 0x40830E11))
+ if ((h->board_id == 0x40700E11) || (h->board_id == 0x40800E11) ||
+ (h->board_id == 0x40820E11) || (h->board_id == 0x40830E11))
goto default_int_mode;
- if (pci_find_capability(pdev, PCI_CAP_ID_MSIX)) {
- dev_info(&pdev->dev, "MSIX\n");
- err = pci_enable_msix(pdev, hpsa_msix_entries, 4);
+ if (pci_find_capability(h->pdev, PCI_CAP_ID_MSIX)) {
+ dev_info(&h->pdev->dev, "MSIX\n");
+ err = pci_enable_msix(h->pdev, hpsa_msix_entries, 4);
if (!err) {
h->intr[0] = hpsa_msix_entries[0].vector;
h->intr[1] = hpsa_msix_entries[1].vector;
@@ -3235,144 +3378,158 @@ static void __devinit hpsa_interrupt_mode(struct ctlr_info *h,
return;
}
if (err > 0) {
- dev_warn(&pdev->dev, "only %d MSI-X vectors "
+ dev_warn(&h->pdev->dev, "only %d MSI-X vectors "
"available\n", err);
goto default_int_mode;
} else {
- dev_warn(&pdev->dev, "MSI-X init failed %d\n",
+ dev_warn(&h->pdev->dev, "MSI-X init failed %d\n",
err);
goto default_int_mode;
}
}
- if (pci_find_capability(pdev, PCI_CAP_ID_MSI)) {
- dev_info(&pdev->dev, "MSI\n");
- if (!pci_enable_msi(pdev))
+ if (pci_find_capability(h->pdev, PCI_CAP_ID_MSI)) {
+ dev_info(&h->pdev->dev, "MSI\n");
+ if (!pci_enable_msi(h->pdev))
h->msi_vector = 1;
else
- dev_warn(&pdev->dev, "MSI init failed\n");
+ dev_warn(&h->pdev->dev, "MSI init failed\n");
}
default_int_mode:
#endif /* CONFIG_PCI_MSI */
/* if we get here we're going to use the default interrupt mode */
- h->intr[PERF_MODE_INT] = pdev->irq;
+ h->intr[PERF_MODE_INT] = h->pdev->irq;
}
-static int __devinit hpsa_pci_init(struct ctlr_info *h, struct pci_dev *pdev)
+static int __devinit hpsa_lookup_board_id(struct pci_dev *pdev, u32 *board_id)
{
- ushort subsystem_vendor_id, subsystem_device_id, command;
- u32 board_id, scratchpad = 0;
- u64 cfg_offset;
- u32 cfg_base_addr;
- u64 cfg_base_addr_index;
- u32 trans_offset;
- int i, prod_index, err;
+ int i;
+ u32 subsystem_vendor_id, subsystem_device_id;
subsystem_vendor_id = pdev->subsystem_vendor;
subsystem_device_id = pdev->subsystem_device;
- board_id = (((u32) (subsystem_device_id << 16) & 0xffff0000) |
- subsystem_vendor_id);
+ *board_id = ((subsystem_device_id << 16) & 0xffff0000) |
+ subsystem_vendor_id;
for (i = 0; i < ARRAY_SIZE(products); i++)
- if (board_id == products[i].board_id)
- break;
-
- prod_index = i;
-
- if (prod_index == ARRAY_SIZE(products)) {
- prod_index--;
- if (subsystem_vendor_id != PCI_VENDOR_ID_HP ||
- !hpsa_allow_any) {
- dev_warn(&pdev->dev, "unrecognized board ID:"
- " 0x%08lx, ignoring.\n",
- (unsigned long) board_id);
+ if (*board_id == products[i].board_id)
+ return i;
+
+ if ((subsystem_vendor_id != PCI_VENDOR_ID_HP &&
+ subsystem_vendor_id != PCI_VENDOR_ID_COMPAQ) ||
+ !hpsa_allow_any) {
+ dev_warn(&pdev->dev, "unrecognized board ID: "
+ "0x%08x, ignoring.\n", *board_id);
return -ENODEV;
- }
- }
- /* check to see if controller has been disabled
- * BEFORE trying to enable it
- */
- (void)pci_read_config_word(pdev, PCI_COMMAND, &command);
- if (!(command & 0x02)) {
- dev_warn(&pdev->dev, "controller appears to be disabled\n");
- return -ENODEV;
- }
-
- err = pci_enable_device(pdev);
- if (err) {
- dev_warn(&pdev->dev, "unable to enable PCI device\n");
- return err;
}
+ return ARRAY_SIZE(products) - 1; /* generic unknown smart array */
+}
- err = pci_request_regions(pdev, "hpsa");
- if (err) {
- dev_err(&pdev->dev, "cannot obtain PCI resources, aborting\n");
- return err;
- }
+static inline bool hpsa_board_disabled(struct pci_dev *pdev)
+{
+ u16 command;
- /* If the kernel supports MSI/MSI-X we will try to enable that,
- * else we use the IO-APIC interrupt assigned to us by system ROM.
- */
- hpsa_interrupt_mode(h, pdev, board_id);
+ (void) pci_read_config_word(pdev, PCI_COMMAND, &command);
+ return ((command & PCI_COMMAND_MEMORY) == 0);
+}
- /* find the memory BAR */
- for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) {
- if (pci_resource_flags(pdev, i) & IORESOURCE_MEM)
- break;
- }
- if (i == DEVICE_COUNT_RESOURCE) {
- dev_warn(&pdev->dev, "no memory BAR found\n");
- err = -ENODEV;
- goto err_out_free_res;
- }
+static int __devinit hpsa_pci_find_memory_BAR(struct pci_dev *pdev,
+ unsigned long *memory_bar)
+{
+ int i;
- h->paddr = pci_resource_start(pdev, i); /* addressing mode bits
- * already removed
- */
+ for (i = 0; i < DEVICE_COUNT_RESOURCE; i++)
+ if (pci_resource_flags(pdev, i) & IORESOURCE_MEM) {
+ /* addressing mode bits already removed */
+ *memory_bar = pci_resource_start(pdev, i);
+ dev_dbg(&pdev->dev, "memory BAR = %lx\n",
+ *memory_bar);
+ return 0;
+ }
+ dev_warn(&pdev->dev, "no memory BAR found\n");
+ return -ENODEV;
+}
- h->vaddr = remap_pci_mem(h->paddr, 0x250);
+static int __devinit hpsa_wait_for_board_ready(struct ctlr_info *h)
+{
+ int i;
+ u32 scratchpad;
- /* Wait for the board to become ready. */
for (i = 0; i < HPSA_BOARD_READY_ITERATIONS; i++) {
scratchpad = readl(h->vaddr + SA5_SCRATCHPAD_OFFSET);
if (scratchpad == HPSA_FIRMWARE_READY)
- break;
+ return 0;
msleep(HPSA_BOARD_READY_POLL_INTERVAL_MSECS);
}
- if (scratchpad != HPSA_FIRMWARE_READY) {
- dev_warn(&pdev->dev, "board not ready, timed out.\n");
- err = -ENODEV;
- goto err_out_free_res;
- }
+ dev_warn(&h->pdev->dev, "board not ready, timed out.\n");
+ return -ENODEV;
+}
- /* get the address index number */
- cfg_base_addr = readl(h->vaddr + SA5_CTCFG_OFFSET);
- cfg_base_addr &= (u32) 0x0000ffff;
- cfg_base_addr_index = find_PCI_BAR_index(pdev, cfg_base_addr);
- if (cfg_base_addr_index == -1) {
+static int __devinit hpsa_find_cfg_addrs(struct pci_dev *pdev,
+ void __iomem *vaddr, u32 *cfg_base_addr, u64 *cfg_base_addr_index,
+ u64 *cfg_offset)
+{
+ *cfg_base_addr = readl(vaddr + SA5_CTCFG_OFFSET);
+ *cfg_offset = readl(vaddr + SA5_CTMEM_OFFSET);
+ *cfg_base_addr &= (u32) 0x0000ffff;
+ *cfg_base_addr_index = find_PCI_BAR_index(pdev, *cfg_base_addr);
+ if (*cfg_base_addr_index == -1) {
dev_warn(&pdev->dev, "cannot find cfg_base_addr_index\n");
- err = -ENODEV;
- goto err_out_free_res;
+ return -ENODEV;
}
+ return 0;
+}
- cfg_offset = readl(h->vaddr + SA5_CTMEM_OFFSET);
- h->cfgtable = remap_pci_mem(pci_resource_start(pdev,
- cfg_base_addr_index) + cfg_offset,
- sizeof(h->cfgtable));
+static int __devinit hpsa_find_cfgtables(struct ctlr_info *h)
+{
+ u64 cfg_offset;
+ u32 cfg_base_addr;
+ u64 cfg_base_addr_index;
+ u32 trans_offset;
+ int rc;
+
+ rc = hpsa_find_cfg_addrs(h->pdev, h->vaddr, &cfg_base_addr,
+ &cfg_base_addr_index, &cfg_offset);
+ if (rc)
+ return rc;
+ h->cfgtable = remap_pci_mem(pci_resource_start(h->pdev,
+ cfg_base_addr_index) + cfg_offset, sizeof(*h->cfgtable));
+ if (!h->cfgtable)
+ return -ENOMEM;
/* Find performant mode table. */
- trans_offset = readl(&(h->cfgtable->TransMethodOffset));
- h->transtable = remap_pci_mem(pci_resource_start(pdev,
+ trans_offset = readl(&h->cfgtable->TransMethodOffset);
+ h->transtable = remap_pci_mem(pci_resource_start(h->pdev,
cfg_base_addr_index)+cfg_offset+trans_offset,
sizeof(*h->transtable));
+ if (!h->transtable)
+ return -ENOMEM;
+ return 0;
+}
- h->board_id = board_id;
+static void __devinit hpsa_get_max_perf_mode_cmds(struct ctlr_info *h)
+{
h->max_commands = readl(&(h->cfgtable->MaxPerformantModeCommands));
- h->maxsgentries = readl(&(h->cfgtable->MaxScatterGatherElements));
+ if (h->max_commands < 16) {
+ dev_warn(&h->pdev->dev, "Controller reports "
+ "max supported commands of %d, an obvious lie. "
+ "Using 16. Ensure that firmware is up to date.\n",
+ h->max_commands);
+ h->max_commands = 16;
+ }
+}
+/* Interrogate the hardware for some limits:
+ * max commands, max SG elements without chaining, and with chaining,
+ * SG chain block size, etc.
+ */
+static void __devinit hpsa_find_board_params(struct ctlr_info *h)
+{
+ hpsa_get_max_perf_mode_cmds(h);
+ h->nr_cmds = h->max_commands - 4; /* Allow room for some ioctls */
+ h->maxsgentries = readl(&(h->cfgtable->MaxScatterGatherElements));
/*
* Limit in-command s/g elements to 32 save dma'able memory.
* Howvever spec says if 0, use 31
*/
-
h->max_cmd_sg_entries = 31;
if (h->maxsgentries > 512) {
h->max_cmd_sg_entries = 32;
@@ -3382,45 +3539,49 @@ static int __devinit hpsa_pci_init(struct ctlr_info *h, struct pci_dev *pdev)
h->maxsgentries = 31; /* default to traditional values */
h->chainsize = 0;
}
+}
- h->product_name = products[prod_index].product_name;
- h->access = *(products[prod_index].access);
- /* Allow room for some ioctls */
- h->nr_cmds = h->max_commands - 4;
-
+static inline bool hpsa_CISS_signature_present(struct ctlr_info *h)
+{
if ((readb(&h->cfgtable->Signature[0]) != 'C') ||
(readb(&h->cfgtable->Signature[1]) != 'I') ||
(readb(&h->cfgtable->Signature[2]) != 'S') ||
(readb(&h->cfgtable->Signature[3]) != 'S')) {
- dev_warn(&pdev->dev, "not a valid CISS config table\n");
- err = -ENODEV;
- goto err_out_free_res;
+ dev_warn(&h->pdev->dev, "not a valid CISS config table\n");
+ return false;
}
+ return true;
+}
+
+/* Need to enable prefetch in the SCSI core for 6400 in x86 */
+static inline void hpsa_enable_scsi_prefetch(struct ctlr_info *h)
+{
#ifdef CONFIG_X86
- {
- /* Need to enable prefetch in the SCSI core for 6400 in x86 */
- u32 prefetch;
- prefetch = readl(&(h->cfgtable->SCSI_Prefetch));
- prefetch |= 0x100;
- writel(prefetch, &(h->cfgtable->SCSI_Prefetch));
- }
+ u32 prefetch;
+
+ prefetch = readl(&(h->cfgtable->SCSI_Prefetch));
+ prefetch |= 0x100;
+ writel(prefetch, &(h->cfgtable->SCSI_Prefetch));
#endif
+}
- /* Disabling DMA prefetch for the P600
- * An ASIC bug may result in a prefetch beyond
- * physical memory.
- */
- if (board_id == 0x3225103C) {
- u32 dma_prefetch;
- dma_prefetch = readl(h->vaddr + I2O_DMA1_CFG);
- dma_prefetch |= 0x8000;
- writel(dma_prefetch, h->vaddr + I2O_DMA1_CFG);
- }
+/* Disable DMA prefetch for the P600. Otherwise an ASIC bug may result
+ * in a prefetch beyond physical memory.
+ */
+static inline void hpsa_p600_dma_prefetch_quirk(struct ctlr_info *h)
+{
+ u32 dma_prefetch;
- h->max_commands = readl(&(h->cfgtable->CmdsOutMax));
- /* Update the field, and then ring the doorbell */
- writel(CFGTBL_Trans_Simple, &(h->cfgtable->HostWrite.TransportRequest));
- writel(CFGTBL_ChangeReq, h->vaddr + SA5_DOORBELL);
+ if (h->board_id != 0x3225103C)
+ return;
+ dma_prefetch = readl(h->vaddr + I2O_DMA1_CFG);
+ dma_prefetch |= 0x8000;
+ writel(dma_prefetch, h->vaddr + I2O_DMA1_CFG);
+}
+
+static void __devinit hpsa_wait_for_mode_change_ack(struct ctlr_info *h)
+{
+ int i;
/* under certain very rare conditions, this can take awhile.
* (e.g.: hot replace a failed 144GB drive in a RAID 5 set right
@@ -3432,24 +3593,96 @@ static int __devinit hpsa_pci_init(struct ctlr_info *h, struct pci_dev *pdev)
/* delay and try again */
msleep(10);
}
+}
-#ifdef HPSA_DEBUG
- print_cfg_table(&pdev->dev, h->cfgtable);
-#endif /* HPSA_DEBUG */
+static int __devinit hpsa_enter_simple_mode(struct ctlr_info *h)
+{
+ u32 trans_support;
+ trans_support = readl(&(h->cfgtable->TransportSupport));
+ if (!(trans_support & SIMPLE_MODE))
+ return -ENOTSUPP;
+
+ h->max_commands = readl(&(h->cfgtable->CmdsOutMax));
+ /* Update the field, and then ring the doorbell */
+ writel(CFGTBL_Trans_Simple, &(h->cfgtable->HostWrite.TransportRequest));
+ writel(CFGTBL_ChangeReq, h->vaddr + SA5_DOORBELL);
+ hpsa_wait_for_mode_change_ack(h);
+ print_cfg_table(&h->pdev->dev, h->cfgtable);
if (!(readl(&(h->cfgtable->TransportActive)) & CFGTBL_Trans_Simple)) {
- dev_warn(&pdev->dev, "unable to get board into simple mode\n");
+ dev_warn(&h->pdev->dev,
+ "unable to get board into simple mode\n");
+ return -ENODEV;
+ }
+ return 0;
+}
+
+static int __devinit hpsa_pci_init(struct ctlr_info *h)
+{
+ int prod_index, err;
+
+ prod_index = hpsa_lookup_board_id(h->pdev, &h->board_id);
+ if (prod_index < 0)
+ return -ENODEV;
+ h->product_name = products[prod_index].product_name;
+ h->access = *(products[prod_index].access);
+
+ if (hpsa_board_disabled(h->pdev)) {
+ dev_warn(&h->pdev->dev, "controller appears to be disabled\n");
+ return -ENODEV;
+ }
+ err = pci_enable_device(h->pdev);
+ if (err) {
+ dev_warn(&h->pdev->dev, "unable to enable PCI device\n");
+ return err;
+ }
+
+ err = pci_request_regions(h->pdev, "hpsa");
+ if (err) {
+ dev_err(&h->pdev->dev,
+ "cannot obtain PCI resources, aborting\n");
+ return err;
+ }
+ hpsa_interrupt_mode(h);
+ err = hpsa_pci_find_memory_BAR(h->pdev, &h->paddr);
+ if (err)
+ goto err_out_free_res;
+ h->vaddr = remap_pci_mem(h->paddr, 0x250);
+ if (!h->vaddr) {
+ err = -ENOMEM;
+ goto err_out_free_res;
+ }
+ err = hpsa_wait_for_board_ready(h);
+ if (err)
+ goto err_out_free_res;
+ err = hpsa_find_cfgtables(h);
+ if (err)
+ goto err_out_free_res;
+ hpsa_find_board_params(h);
+
+ if (!hpsa_CISS_signature_present(h)) {
err = -ENODEV;
goto err_out_free_res;
}
+ hpsa_enable_scsi_prefetch(h);
+ hpsa_p600_dma_prefetch_quirk(h);
+ err = hpsa_enter_simple_mode(h);
+ if (err)
+ goto err_out_free_res;
return 0;
err_out_free_res:
+ if (h->transtable)
+ iounmap(h->transtable);
+ if (h->cfgtable)
+ iounmap(h->cfgtable);
+ if (h->vaddr)
+ iounmap(h->vaddr);
/*
* Deliberately omit pci_disable_device(): it does something nasty to
* Smart Array controllers that pci_enable_device does not undo
*/
- pci_release_regions(pdev);
+ pci_release_regions(h->pdev);
return err;
}
@@ -3469,33 +3702,51 @@ static void __devinit hpsa_hba_inquiry(struct ctlr_info *h)
}
}
+static __devinit int hpsa_init_reset_devices(struct pci_dev *pdev)
+{
+ int rc, i;
+
+ if (!reset_devices)
+ return 0;
+
+ /* Reset the controller with a PCI power-cycle or via doorbell */
+ rc = hpsa_kdump_hard_reset_controller(pdev);
+
+ /* -ENOTSUPP here means we cannot reset the controller
+ * but it's already (and still) up and running in
+ * "performant mode". Or, it might be 640x, which can't reset
+ * due to concerns about shared bbwc between 6402/6404 pair.
+ */
+ if (rc == -ENOTSUPP)
+ return 0; /* just try to do the kdump anyhow. */
+ if (rc)
+ return -ENODEV;
+ if (hpsa_reset_msi(pdev))
+ return -ENODEV;
+
+ /* Now try to get the controller to respond to a no-op */
+ for (i = 0; i < HPSA_POST_RESET_NOOP_RETRIES; i++) {
+ if (hpsa_noop(pdev) == 0)
+ break;
+ else
+ dev_warn(&pdev->dev, "no-op failed%s\n",
+ (i < 11 ? "; re-trying" : ""));
+ }
+ return 0;
+}
+
static int __devinit hpsa_init_one(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
- int i, rc;
- int dac;
+ int dac, rc;
struct ctlr_info *h;
if (number_of_controllers == 0)
printk(KERN_INFO DRIVER_NAME "\n");
- if (reset_devices) {
- /* Reset the controller with a PCI power-cycle */
- if (hpsa_hard_reset_controller(pdev) || hpsa_reset_msi(pdev))
- return -ENODEV;
- /* Some devices (notably the HP Smart Array 5i Controller)
- need a little pause here */
- msleep(HPSA_POST_RESET_PAUSE_MSECS);
-
- /* Now try to get the controller to respond to a no-op */
- for (i = 0; i < HPSA_POST_RESET_NOOP_RETRIES; i++) {
- if (hpsa_noop(pdev) == 0)
- break;
- else
- dev_warn(&pdev->dev, "no-op failed%s\n",
- (i < 11 ? "; re-trying" : ""));
- }
- }
+ rc = hpsa_init_reset_devices(pdev);
+ if (rc)
+ return rc;
/* Command structures must be aligned on a 32-byte boundary because
* the 5 lower bits of the address are used by the hardware. and by
@@ -3507,17 +3758,17 @@ static int __devinit hpsa_init_one(struct pci_dev *pdev,
if (!h)
return -ENOMEM;
+ h->pdev = pdev;
h->busy_initializing = 1;
INIT_HLIST_HEAD(&h->cmpQ);
INIT_HLIST_HEAD(&h->reqQ);
- rc = hpsa_pci_init(h, pdev);
+ rc = hpsa_pci_init(h);
if (rc != 0)
goto clean1;
sprintf(h->devname, "hpsa%d", number_of_controllers);
h->ctlr = number_of_controllers;
number_of_controllers++;
- h->pdev = pdev;
/* configure PCI DMA stuff */
rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(64));
@@ -3535,8 +3786,13 @@ static int __devinit hpsa_init_one(struct pci_dev *pdev,
/* make sure the board interrupts are off */
h->access.set_intr_mask(h, HPSA_INTR_OFF);
- rc = request_irq(h->intr[PERF_MODE_INT], do_hpsa_intr,
- IRQF_DISABLED, h->devname, h);
+
+ if (h->msix_vector || h->msi_vector)
+ rc = request_irq(h->intr[PERF_MODE_INT], do_hpsa_intr_msi,
+ IRQF_DISABLED, h->devname, h);
+ else
+ rc = request_irq(h->intr[PERF_MODE_INT], do_hpsa_intr_intx,
+ IRQF_DISABLED, h->devname, h);
if (rc) {
dev_err(&pdev->dev, "unable to get irq %d for %s\n",
h->intr[PERF_MODE_INT], h->devname);
@@ -3663,6 +3919,8 @@ static void __devexit hpsa_remove_one(struct pci_dev *pdev)
hpsa_unregister_scsi(h); /* unhook from SCSI subsystem */
hpsa_shutdown(pdev);
iounmap(h->vaddr);
+ iounmap(h->transtable);
+ iounmap(h->cfgtable);
hpsa_free_sg_chain_blocks(h);
pci_free_consistent(h->pdev,
h->nr_cmds * sizeof(struct CommandList),
@@ -3742,38 +4000,35 @@ static void calc_bucket_map(int bucket[], int num_buckets,
}
}
-static void hpsa_put_ctlr_into_performant_mode(struct ctlr_info *h)
+static __devinit void hpsa_enter_performant_mode(struct ctlr_info *h)
{
- u32 trans_support;
- u64 trans_offset;
+ int i;
+ unsigned long register_value;
+
+ /* This is a bit complicated. There are 8 registers on
+ * the controller which we write to to tell it 8 different
+ * sizes of commands which there may be. It's a way of
+ * reducing the DMA done to fetch each command. Encoded into
+ * each command's tag are 3 bits which communicate to the controller
+ * which of the eight sizes that command fits within. The size of
+ * each command depends on how many scatter gather entries there are.
+ * Each SG entry requires 16 bytes. The eight registers are programmed
+ * with the number of 16-byte blocks a command of that size requires.
+ * The smallest command possible requires 5 such 16 byte blocks.
+ * the largest command possible requires MAXSGENTRIES + 4 16-byte
+ * blocks. Note, this only extends to the SG entries contained
+ * within the command block, and does not extend to chained blocks
+ * of SG elements. bft[] contains the eight values we write to
+ * the registers. They are not evenly distributed, but have more
+ * sizes for small commands, and fewer sizes for larger commands.
+ */
+ int bft[8] = {5, 6, 8, 10, 12, 20, 28, MAXSGENTRIES + 4};
+ BUILD_BUG_ON(28 > MAXSGENTRIES + 4);
/* 5 = 1 s/g entry or 4k
* 6 = 2 s/g entry or 8k
* 8 = 4 s/g entry or 16k
* 10 = 6 s/g entry or 24k
*/
- int bft[8] = {5, 6, 8, 10, 12, 20, 28, 35}; /* for scatter/gathers */
- int i = 0;
- int l = 0;
- unsigned long register_value;
-
- trans_support = readl(&(h->cfgtable->TransportSupport));
- if (!(trans_support & PERFORMANT_MODE))
- return;
-
- h->max_commands = readl(&(h->cfgtable->MaxPerformantModeCommands));
- h->max_sg_entries = 32;
- /* Performant mode ring buffer and supporting data structures */
- h->reply_pool_size = h->max_commands * sizeof(u64);
- h->reply_pool = pci_alloc_consistent(h->pdev, h->reply_pool_size,
- &(h->reply_pool_dhandle));
-
- /* Need a block fetch table for performant mode */
- h->blockFetchTable = kmalloc(((h->max_sg_entries+1) *
- sizeof(u32)), GFP_KERNEL);
-
- if ((h->reply_pool == NULL)
- || (h->blockFetchTable == NULL))
- goto clean_up;
h->reply_pool_wraparound = 1; /* spec: init to 1 */
@@ -3781,7 +4036,6 @@ static void hpsa_put_ctlr_into_performant_mode(struct ctlr_info *h)
memset(h->reply_pool, 0, h->reply_pool_size);
h->reply_pool_head = h->reply_pool;
- trans_offset = readl(&(h->cfgtable->TransMethodOffset));
bft[7] = h->max_sg_entries + 4;
calc_bucket_map(bft, ARRAY_SIZE(bft), 32, h->blockFetchTable);
for (i = 0; i < 8; i++)
@@ -3797,23 +4051,39 @@ static void hpsa_put_ctlr_into_performant_mode(struct ctlr_info *h)
writel(CFGTBL_Trans_Performant,
&(h->cfgtable->HostWrite.TransportRequest));
writel(CFGTBL_ChangeReq, h->vaddr + SA5_DOORBELL);
- /* under certain very rare conditions, this can take awhile.
- * (e.g.: hot replace a failed 144GB drive in a RAID 5 set right
- * as we enter this code.) */
- for (l = 0; l < MAX_CONFIG_WAIT; l++) {
- register_value = readl(h->vaddr + SA5_DOORBELL);
- if (!(register_value & CFGTBL_ChangeReq))
- break;
- /* delay and try again */
- set_current_state(TASK_INTERRUPTIBLE);
- schedule_timeout(10);
- }
+ hpsa_wait_for_mode_change_ack(h);
register_value = readl(&(h->cfgtable->TransportActive));
if (!(register_value & CFGTBL_Trans_Performant)) {
dev_warn(&h->pdev->dev, "unable to get board into"
" performant mode\n");
return;
}
+}
+
+static __devinit void hpsa_put_ctlr_into_performant_mode(struct ctlr_info *h)
+{
+ u32 trans_support;
+
+ trans_support = readl(&(h->cfgtable->TransportSupport));
+ if (!(trans_support & PERFORMANT_MODE))
+ return;
+
+ hpsa_get_max_perf_mode_cmds(h);
+ h->max_sg_entries = 32;
+ /* Performant mode ring buffer and supporting data structures */
+ h->reply_pool_size = h->max_commands * sizeof(u64);
+ h->reply_pool = pci_alloc_consistent(h->pdev, h->reply_pool_size,
+ &(h->reply_pool_dhandle));
+
+ /* Need a block fetch table for performant mode */
+ h->blockFetchTable = kmalloc(((h->max_sg_entries+1) *
+ sizeof(u32)), GFP_KERNEL);
+
+ if ((h->reply_pool == NULL)
+ || (h->blockFetchTable == NULL))
+ goto clean_up;
+
+ hpsa_enter_performant_mode(h);
/* Change the access methods to the performant access methods */
h->access = SA5_performant_access;
diff --git a/drivers/scsi/hpsa.h b/drivers/scsi/hpsa.h
index 1bb5233b09a..a203ef65cb5 100644
--- a/drivers/scsi/hpsa.h
+++ b/drivers/scsi/hpsa.h
@@ -53,7 +53,6 @@ struct ctlr_info {
int ctlr;
char devname[8];
char *product_name;
- char firm_ver[4]; /* Firmware version */
struct pci_dev *pdev;
u32 board_id;
void __iomem *vaddr;
diff --git a/drivers/scsi/hpsa_cmd.h b/drivers/scsi/hpsa_cmd.h
index 78de9b6d1e0..f5c4c3cc053 100644
--- a/drivers/scsi/hpsa_cmd.h
+++ b/drivers/scsi/hpsa_cmd.h
@@ -100,6 +100,7 @@
/* Configuration Table */
#define CFGTBL_ChangeReq 0x00000001l
#define CFGTBL_AccCmds 0x00000001l
+#define DOORBELL_CTLR_RESET 0x00000004l
#define CFGTBL_Trans_Simple 0x00000002l
#define CFGTBL_Trans_Performant 0x00000004l
@@ -339,6 +340,9 @@ struct CfgTable {
u32 MaxPhysicalDevices;
u32 MaxPhysicalDrivesPerLogicalUnit;
u32 MaxPerformantModeCommands;
+ u8 reserved[0x78 - 0x58];
+ u32 misc_fw_support; /* offset 0x78 */
+#define MISC_FW_DOORBELL_RESET (0x02)
};
#define NUM_BLOCKFETCH_ENTRIES 8
diff --git a/drivers/scsi/hptiop.c b/drivers/scsi/hptiop.c
index 645f7cdf21a..0729f150b33 100644
--- a/drivers/scsi/hptiop.c
+++ b/drivers/scsi/hptiop.c
@@ -1157,7 +1157,7 @@ free_pci_regions:
disable_pci_device:
pci_disable_device(pcidev);
- dprintk("scsi%d: hptiop_probe fail\n", host->host_no);
+ dprintk("scsi%d: hptiop_probe fail\n", host ? host->host_no : 0);
return -ENODEV;
}
diff --git a/drivers/scsi/ibmvscsi/ibmvfc.c b/drivers/scsi/ibmvscsi/ibmvfc.c
index fef49521cbc..bd96cecaa61 100644
--- a/drivers/scsi/ibmvscsi/ibmvfc.c
+++ b/drivers/scsi/ibmvscsi/ibmvfc.c
@@ -504,12 +504,23 @@ static void ibmvfc_set_host_action(struct ibmvfc_host *vhost,
if (vhost->action == IBMVFC_HOST_ACTION_ALLOC_TGTS)
vhost->action = action;
break;
- case IBMVFC_HOST_ACTION_LOGO:
case IBMVFC_HOST_ACTION_INIT:
case IBMVFC_HOST_ACTION_TGT_DEL:
+ switch (vhost->action) {
+ case IBMVFC_HOST_ACTION_RESET:
+ case IBMVFC_HOST_ACTION_REENABLE:
+ break;
+ default:
+ vhost->action = action;
+ break;
+ };
+ break;
+ case IBMVFC_HOST_ACTION_LOGO:
case IBMVFC_HOST_ACTION_QUERY_TGTS:
case IBMVFC_HOST_ACTION_TGT_DEL_FAILED:
case IBMVFC_HOST_ACTION_NONE:
+ case IBMVFC_HOST_ACTION_RESET:
+ case IBMVFC_HOST_ACTION_REENABLE:
default:
vhost->action = action;
break;
@@ -641,7 +652,7 @@ static int ibmvfc_send_crq_init_complete(struct ibmvfc_host *vhost)
**/
static void ibmvfc_release_crq_queue(struct ibmvfc_host *vhost)
{
- long rc;
+ long rc = 0;
struct vio_dev *vdev = to_vio_dev(vhost->dev);
struct ibmvfc_crq_queue *crq = &vhost->crq;
@@ -649,6 +660,8 @@ static void ibmvfc_release_crq_queue(struct ibmvfc_host *vhost)
free_irq(vdev->irq, vhost);
tasklet_kill(&vhost->tasklet);
do {
+ if (rc)
+ msleep(100);
rc = plpar_hcall_norets(H_FREE_CRQ, vdev->unit_address);
} while (rc == H_BUSY || H_IS_LONG_BUSY(rc));
@@ -667,11 +680,13 @@ static void ibmvfc_release_crq_queue(struct ibmvfc_host *vhost)
**/
static int ibmvfc_reenable_crq_queue(struct ibmvfc_host *vhost)
{
- int rc;
+ int rc = 0;
struct vio_dev *vdev = to_vio_dev(vhost->dev);
/* Re-enable the CRQ */
do {
+ if (rc)
+ msleep(100);
rc = plpar_hcall_norets(H_ENABLE_CRQ, vdev->unit_address);
} while (rc == H_IN_PROGRESS || rc == H_BUSY || H_IS_LONG_BUSY(rc));
@@ -690,15 +705,19 @@ static int ibmvfc_reenable_crq_queue(struct ibmvfc_host *vhost)
**/
static int ibmvfc_reset_crq(struct ibmvfc_host *vhost)
{
- int rc;
+ int rc = 0;
+ unsigned long flags;
struct vio_dev *vdev = to_vio_dev(vhost->dev);
struct ibmvfc_crq_queue *crq = &vhost->crq;
/* Close the CRQ */
do {
+ if (rc)
+ msleep(100);
rc = plpar_hcall_norets(H_FREE_CRQ, vdev->unit_address);
} while (rc == H_BUSY || H_IS_LONG_BUSY(rc));
+ spin_lock_irqsave(vhost->host->host_lock, flags);
vhost->state = IBMVFC_NO_CRQ;
vhost->logged_in = 0;
ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_NONE);
@@ -716,6 +735,7 @@ static int ibmvfc_reset_crq(struct ibmvfc_host *vhost)
dev_warn(vhost->dev, "Partner adapter not ready\n");
else if (rc != 0)
dev_warn(vhost->dev, "Couldn't register crq (rc=%d)\n", rc);
+ spin_unlock_irqrestore(vhost->host->host_lock, flags);
return rc;
}
@@ -821,17 +841,9 @@ static void ibmvfc_purge_requests(struct ibmvfc_host *vhost, int error_code)
**/
static void ibmvfc_hard_reset_host(struct ibmvfc_host *vhost)
{
- int rc;
-
- scsi_block_requests(vhost->host);
ibmvfc_purge_requests(vhost, DID_ERROR);
- if ((rc = ibmvfc_reset_crq(vhost)) ||
- (rc = ibmvfc_send_crq_init(vhost)) ||
- (rc = vio_enable_interrupts(to_vio_dev(vhost->dev)))) {
- dev_err(vhost->dev, "Error after reset rc=%d\n", rc);
- ibmvfc_link_down(vhost, IBMVFC_LINK_DEAD);
- } else
- ibmvfc_link_down(vhost, IBMVFC_LINK_DOWN);
+ ibmvfc_link_down(vhost, IBMVFC_LINK_DOWN);
+ ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_RESET);
}
/**
@@ -2299,6 +2311,7 @@ static int ibmvfc_eh_abort_handler(struct scsi_cmnd *cmd)
int rc = FAILED;
ENTER;
+ fc_block_scsi_eh(cmd);
ibmvfc_wait_while_resetting(vhost);
cancel_rc = ibmvfc_cancel_all(sdev, IBMVFC_TMF_ABORT_TASK_SET);
abort_rc = ibmvfc_abort_task_set(sdev);
@@ -2325,6 +2338,7 @@ static int ibmvfc_eh_device_reset_handler(struct scsi_cmnd *cmd)
int rc = FAILED;
ENTER;
+ fc_block_scsi_eh(cmd);
ibmvfc_wait_while_resetting(vhost);
cancel_rc = ibmvfc_cancel_all(sdev, IBMVFC_TMF_LUN_RESET);
reset_rc = ibmvfc_reset_device(sdev, IBMVFC_LUN_RESET, "LUN");
@@ -2389,6 +2403,7 @@ static int ibmvfc_eh_target_reset_handler(struct scsi_cmnd *cmd)
unsigned long cancel_rc = 0;
ENTER;
+ fc_block_scsi_eh(cmd);
ibmvfc_wait_while_resetting(vhost);
starget_for_each_device(starget, &cancel_rc, ibmvfc_dev_cancel_all_reset);
reset_rc = ibmvfc_reset_device(sdev, IBMVFC_TARGET_RESET, "target");
@@ -2410,6 +2425,7 @@ static int ibmvfc_eh_host_reset_handler(struct scsi_cmnd *cmd)
int rc;
struct ibmvfc_host *vhost = shost_priv(cmd->device->host);
+ fc_block_scsi_eh(cmd);
dev_err(vhost->dev, "Resetting connection due to error recovery\n");
rc = ibmvfc_issue_fc_host_lip(vhost->host);
return rc ? FAILED : SUCCESS;
@@ -2606,22 +2622,13 @@ static void ibmvfc_handle_crq(struct ibmvfc_crq *crq, struct ibmvfc_host *vhost)
dev_info(vhost->dev, "Re-enabling adapter\n");
vhost->client_migrated = 1;
ibmvfc_purge_requests(vhost, DID_REQUEUE);
- if ((rc = ibmvfc_reenable_crq_queue(vhost)) ||
- (rc = ibmvfc_send_crq_init(vhost))) {
- ibmvfc_link_down(vhost, IBMVFC_LINK_DEAD);
- dev_err(vhost->dev, "Error after enable (rc=%ld)\n", rc);
- } else
- ibmvfc_link_down(vhost, IBMVFC_LINK_DOWN);
+ ibmvfc_link_down(vhost, IBMVFC_LINK_DOWN);
+ ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_REENABLE);
} else {
dev_err(vhost->dev, "Virtual adapter failed (rc=%d)\n", crq->format);
-
ibmvfc_purge_requests(vhost, DID_ERROR);
- if ((rc = ibmvfc_reset_crq(vhost)) ||
- (rc = ibmvfc_send_crq_init(vhost))) {
- ibmvfc_link_down(vhost, IBMVFC_LINK_DEAD);
- dev_err(vhost->dev, "Error after reset (rc=%ld)\n", rc);
- } else
- ibmvfc_link_down(vhost, IBMVFC_LINK_DOWN);
+ ibmvfc_link_down(vhost, IBMVFC_LINK_DOWN);
+ ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_RESET);
}
return;
case IBMVFC_CRQ_CMD_RSP:
@@ -4123,6 +4130,8 @@ static int __ibmvfc_work_to_do(struct ibmvfc_host *vhost)
case IBMVFC_HOST_ACTION_TGT_DEL:
case IBMVFC_HOST_ACTION_TGT_DEL_FAILED:
case IBMVFC_HOST_ACTION_QUERY:
+ case IBMVFC_HOST_ACTION_RESET:
+ case IBMVFC_HOST_ACTION_REENABLE:
default:
break;
};
@@ -4220,6 +4229,7 @@ static void ibmvfc_do_work(struct ibmvfc_host *vhost)
struct ibmvfc_target *tgt;
unsigned long flags;
struct fc_rport *rport;
+ int rc;
ibmvfc_log_ae(vhost, vhost->events_to_log);
spin_lock_irqsave(vhost->host->host_lock, flags);
@@ -4229,6 +4239,27 @@ static void ibmvfc_do_work(struct ibmvfc_host *vhost)
case IBMVFC_HOST_ACTION_LOGO_WAIT:
case IBMVFC_HOST_ACTION_INIT_WAIT:
break;
+ case IBMVFC_HOST_ACTION_RESET:
+ vhost->action = IBMVFC_HOST_ACTION_TGT_DEL;
+ spin_unlock_irqrestore(vhost->host->host_lock, flags);
+ rc = ibmvfc_reset_crq(vhost);
+ spin_lock_irqsave(vhost->host->host_lock, flags);
+ if (rc || (rc = ibmvfc_send_crq_init(vhost)) ||
+ (rc = vio_enable_interrupts(to_vio_dev(vhost->dev)))) {
+ ibmvfc_link_down(vhost, IBMVFC_LINK_DEAD);
+ dev_err(vhost->dev, "Error after reset (rc=%d)\n", rc);
+ }
+ break;
+ case IBMVFC_HOST_ACTION_REENABLE:
+ vhost->action = IBMVFC_HOST_ACTION_TGT_DEL;
+ spin_unlock_irqrestore(vhost->host->host_lock, flags);
+ rc = ibmvfc_reenable_crq_queue(vhost);
+ spin_lock_irqsave(vhost->host->host_lock, flags);
+ if (rc || (rc = ibmvfc_send_crq_init(vhost))) {
+ ibmvfc_link_down(vhost, IBMVFC_LINK_DEAD);
+ dev_err(vhost->dev, "Error after enable (rc=%d)\n", rc);
+ }
+ break;
case IBMVFC_HOST_ACTION_LOGO:
vhost->job_step(vhost);
break;
diff --git a/drivers/scsi/ibmvscsi/ibmvfc.h b/drivers/scsi/ibmvscsi/ibmvfc.h
index 7e9742764e4..d7e8dcd9065 100644
--- a/drivers/scsi/ibmvscsi/ibmvfc.h
+++ b/drivers/scsi/ibmvscsi/ibmvfc.h
@@ -29,8 +29,8 @@
#include "viosrp.h"
#define IBMVFC_NAME "ibmvfc"
-#define IBMVFC_DRIVER_VERSION "1.0.7"
-#define IBMVFC_DRIVER_DATE "(October 16, 2009)"
+#define IBMVFC_DRIVER_VERSION "1.0.8"
+#define IBMVFC_DRIVER_DATE "(June 17, 2010)"
#define IBMVFC_DEFAULT_TIMEOUT 60
#define IBMVFC_ADISC_CANCEL_TIMEOUT 45
@@ -649,6 +649,8 @@ struct ibmvfc_event_pool {
enum ibmvfc_host_action {
IBMVFC_HOST_ACTION_NONE = 0,
+ IBMVFC_HOST_ACTION_RESET,
+ IBMVFC_HOST_ACTION_REENABLE,
IBMVFC_HOST_ACTION_LOGO,
IBMVFC_HOST_ACTION_LOGO_WAIT,
IBMVFC_HOST_ACTION_INIT,
diff --git a/drivers/scsi/ibmvscsi/ibmvscsi.c b/drivers/scsi/ibmvscsi/ibmvscsi.c
index aad35cc41e4..67f78a470f5 100644
--- a/drivers/scsi/ibmvscsi/ibmvscsi.c
+++ b/drivers/scsi/ibmvscsi/ibmvscsi.c
@@ -73,6 +73,7 @@
#include <linux/slab.h>
#include <linux/of.h>
#include <linux/pm.h>
+#include <linux/kthread.h>
#include <asm/firmware.h>
#include <asm/vio.h>
#include <scsi/scsi.h>
@@ -101,7 +102,7 @@ static int client_reserve = 1;
static struct scsi_transport_template *ibmvscsi_transport_template;
-#define IBMVSCSI_VERSION "1.5.8"
+#define IBMVSCSI_VERSION "1.5.9"
static struct ibmvscsi_ops *ibmvscsi_ops;
@@ -473,23 +474,26 @@ static int map_data_for_srp_cmd(struct scsi_cmnd *cmd,
*/
static void purge_requests(struct ibmvscsi_host_data *hostdata, int error_code)
{
- struct srp_event_struct *tmp_evt, *pos;
+ struct srp_event_struct *evt;
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);
+ while (!list_empty(&hostdata->sent)) {
+ evt = list_first_entry(&hostdata->sent, struct srp_event_struct, list);
+ list_del(&evt->list);
+ del_timer(&evt->timer);
+
+ spin_unlock_irqrestore(hostdata->host->host_lock, flags);
+ if (evt->cmnd) {
+ evt->cmnd->result = (error_code << 16);
+ unmap_cmd_data(&evt->iu.srp.cmd, evt,
+ evt->hostdata->dev);
+ if (evt->cmnd_done)
+ evt->cmnd_done(evt->cmnd);
+ } else if (evt->done)
+ evt->done(evt);
+ free_event_struct(&evt->hostdata->pool, evt);
+ spin_lock_irqsave(hostdata->host->host_lock, flags);
}
spin_unlock_irqrestore(hostdata->host->host_lock, flags);
}
@@ -504,14 +508,8 @@ static void ibmvscsi_reset_host(struct ibmvscsi_host_data *hostdata)
atomic_set(&hostdata->request_limit, 0);
purge_requests(hostdata, DID_ERROR);
- if ((ibmvscsi_ops->reset_crq_queue(&hostdata->queue, hostdata)) ||
- (ibmvscsi_ops->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);
+ hostdata->reset_crq = 1;
+ wake_up(&hostdata->work_wait_q);
}
/**
@@ -550,6 +548,7 @@ static int ibmvscsi_send_srp_event(struct srp_event_struct *evt_struct,
u64 *crq_as_u64 = (u64 *) &evt_struct->crq;
int request_status = 0;
int rc;
+ int srp_req = 0;
/* If we have exhausted our request limit, just fail this request,
* unless it is for a reset or abort.
@@ -558,6 +557,7 @@ static int ibmvscsi_send_srp_event(struct srp_event_struct *evt_struct,
* can handle more requests (can_queue) when we actually can't
*/
if (evt_struct->crq.format == VIOSRP_SRP_FORMAT) {
+ srp_req = 1;
request_status =
atomic_dec_if_positive(&hostdata->request_limit);
/* If request limit was -1 when we started, it is now even
@@ -632,7 +632,8 @@ static int ibmvscsi_send_srp_event(struct srp_event_struct *evt_struct,
goto send_busy;
}
dev_err(hostdata->dev, "send error %d\n", rc);
- atomic_inc(&hostdata->request_limit);
+ if (srp_req)
+ atomic_inc(&hostdata->request_limit);
goto send_error;
}
@@ -642,7 +643,7 @@ static int ibmvscsi_send_srp_event(struct srp_event_struct *evt_struct,
unmap_cmd_data(&evt_struct->iu.srp.cmd, evt_struct, hostdata->dev);
free_event_struct(&hostdata->pool, evt_struct);
- if (request_status != -1)
+ if (srp_req && request_status != -1)
atomic_inc(&hostdata->request_limit);
return SCSI_MLQUEUE_HOST_BUSY;
@@ -1462,30 +1463,14 @@ void ibmvscsi_handle_crq(struct viosrp_crq *crq,
/* We need to re-setup the interpartition connection */
dev_info(hostdata->dev, "Re-enabling adapter!\n");
hostdata->client_migrated = 1;
+ hostdata->reenable_crq = 1;
purge_requests(hostdata, DID_REQUEUE);
- if ((ibmvscsi_ops->reenable_crq_queue(&hostdata->queue,
- hostdata)) ||
- (ibmvscsi_ops->send_crq(hostdata,
- 0xC001000000000000LL, 0))) {
- atomic_set(&hostdata->request_limit,
- -1);
- dev_err(hostdata->dev, "error after enable\n");
- }
+ wake_up(&hostdata->work_wait_q);
} else {
dev_err(hostdata->dev, "Virtual adapter failed rc %d!\n",
crq->format);
-
- purge_requests(hostdata, DID_ERROR);
- if ((ibmvscsi_ops->reset_crq_queue(&hostdata->queue,
- hostdata)) ||
- (ibmvscsi_ops->send_crq(hostdata,
- 0xC001000000000000LL, 0))) {
- atomic_set(&hostdata->request_limit,
- -1);
- dev_err(hostdata->dev, "error after reset\n");
- }
+ ibmvscsi_reset_host(hostdata);
}
- scsi_unblock_requests(hostdata->host);
return;
case 0x80: /* real payload */
break;
@@ -1850,6 +1835,75 @@ static unsigned long ibmvscsi_get_desired_dma(struct vio_dev *vdev)
return desired_io;
}
+static void ibmvscsi_do_work(struct ibmvscsi_host_data *hostdata)
+{
+ int rc;
+ char *action = "reset";
+
+ if (hostdata->reset_crq) {
+ smp_rmb();
+ hostdata->reset_crq = 0;
+
+ rc = ibmvscsi_ops->reset_crq_queue(&hostdata->queue, hostdata);
+ if (!rc)
+ rc = ibmvscsi_ops->send_crq(hostdata, 0xC001000000000000LL, 0);
+ if (!rc)
+ rc = vio_enable_interrupts(to_vio_dev(hostdata->dev));
+ } else if (hostdata->reenable_crq) {
+ smp_rmb();
+ action = "enable";
+ rc = ibmvscsi_ops->reenable_crq_queue(&hostdata->queue, hostdata);
+ hostdata->reenable_crq = 0;
+ if (!rc)
+ rc = ibmvscsi_ops->send_crq(hostdata, 0xC001000000000000LL, 0);
+ } else
+ return;
+
+ if (rc) {
+ atomic_set(&hostdata->request_limit, -1);
+ dev_err(hostdata->dev, "error after %s\n", action);
+ }
+
+ scsi_unblock_requests(hostdata->host);
+}
+
+static int ibmvscsi_work_to_do(struct ibmvscsi_host_data *hostdata)
+{
+ if (kthread_should_stop())
+ return 1;
+ else if (hostdata->reset_crq) {
+ smp_rmb();
+ return 1;
+ } else if (hostdata->reenable_crq) {
+ smp_rmb();
+ return 1;
+ }
+
+ return 0;
+}
+
+static int ibmvscsi_work(void *data)
+{
+ struct ibmvscsi_host_data *hostdata = data;
+ int rc;
+
+ set_user_nice(current, -20);
+
+ while (1) {
+ rc = wait_event_interruptible(hostdata->work_wait_q,
+ ibmvscsi_work_to_do(hostdata));
+
+ BUG_ON(rc);
+
+ if (kthread_should_stop())
+ break;
+
+ ibmvscsi_do_work(hostdata);
+ }
+
+ return 0;
+}
+
/**
* Called by bus code for each adapter
*/
@@ -1875,6 +1929,7 @@ static int ibmvscsi_probe(struct vio_dev *vdev, const struct vio_device_id *id)
hostdata = shost_priv(host);
memset(hostdata, 0x00, sizeof(*hostdata));
INIT_LIST_HEAD(&hostdata->sent);
+ init_waitqueue_head(&hostdata->work_wait_q);
hostdata->host = host;
hostdata->dev = dev;
atomic_set(&hostdata->request_limit, -1);
@@ -1885,10 +1940,19 @@ static int ibmvscsi_probe(struct vio_dev *vdev, const struct vio_device_id *id)
goto persist_bufs_failed;
}
+ hostdata->work_thread = kthread_run(ibmvscsi_work, hostdata, "%s_%d",
+ "ibmvscsi", host->host_no);
+
+ if (IS_ERR(hostdata->work_thread)) {
+ dev_err(&vdev->dev, "couldn't initialize kthread. rc=%ld\n",
+ PTR_ERR(hostdata->work_thread));
+ goto init_crq_failed;
+ }
+
rc = ibmvscsi_ops->init_crq_queue(&hostdata->queue, hostdata, max_events);
if (rc != 0 && rc != H_RESOURCE) {
dev_err(&vdev->dev, "couldn't initialize crq. rc=%d\n", rc);
- goto init_crq_failed;
+ goto kill_kthread;
}
if (initialize_event_pool(&hostdata->pool, max_events, hostdata) != 0) {
dev_err(&vdev->dev, "couldn't initialize event pool\n");
@@ -1944,6 +2008,8 @@ static int ibmvscsi_probe(struct vio_dev *vdev, const struct vio_device_id *id)
release_event_pool(&hostdata->pool, hostdata);
init_pool_failed:
ibmvscsi_ops->release_crq_queue(&hostdata->queue, hostdata, max_events);
+ kill_kthread:
+ kthread_stop(hostdata->work_thread);
init_crq_failed:
unmap_persist_bufs(hostdata);
persist_bufs_failed:
@@ -1960,6 +2026,7 @@ static int ibmvscsi_remove(struct vio_dev *vdev)
ibmvscsi_ops->release_crq_queue(&hostdata->queue, hostdata,
max_events);
+ kthread_stop(hostdata->work_thread);
srp_remove_host(hostdata->host);
scsi_remove_host(hostdata->host);
scsi_host_put(hostdata->host);
diff --git a/drivers/scsi/ibmvscsi/ibmvscsi.h b/drivers/scsi/ibmvscsi/ibmvscsi.h
index 9cb7c6a773e..02197a2b22b 100644
--- a/drivers/scsi/ibmvscsi/ibmvscsi.h
+++ b/drivers/scsi/ibmvscsi/ibmvscsi.h
@@ -91,12 +91,16 @@ struct event_pool {
struct ibmvscsi_host_data {
atomic_t request_limit;
int client_migrated;
+ int reset_crq;
+ int reenable_crq;
struct device *dev;
struct event_pool pool;
struct crq_queue queue;
struct tasklet_struct srp_task;
struct list_head sent;
struct Scsi_Host *host;
+ struct task_struct *work_thread;
+ wait_queue_head_t work_wait_q;
struct mad_adapter_info_data madapter_info;
struct capabilities caps;
dma_addr_t caps_addr;
diff --git a/drivers/scsi/ibmvscsi/ibmvstgt.c b/drivers/scsi/ibmvscsi/ibmvstgt.c
index e2056d517e9..2256babe047 100644
--- a/drivers/scsi/ibmvscsi/ibmvstgt.c
+++ b/drivers/scsi/ibmvscsi/ibmvstgt.c
@@ -956,7 +956,7 @@ static struct srp_function_template ibmvstgt_transport_functions = {
.it_nexus_response = ibmvstgt_it_nexus_response,
};
-static int ibmvstgt_init(void)
+static int __init ibmvstgt_init(void)
{
int err = -ENOMEM;
@@ -987,7 +987,7 @@ release_transport:
return err;
}
-static void ibmvstgt_exit(void)
+static void __exit ibmvstgt_exit(void)
{
printk("Unregister IBM virtual SCSI driver\n");
diff --git a/drivers/scsi/ibmvscsi/rpa_vscsi.c b/drivers/scsi/ibmvscsi/rpa_vscsi.c
index 989b9a8ba72..f48ae0190d9 100644
--- a/drivers/scsi/ibmvscsi/rpa_vscsi.c
+++ b/drivers/scsi/ibmvscsi/rpa_vscsi.c
@@ -31,6 +31,7 @@
#include <asm/prom.h>
#include <asm/iommu.h>
#include <asm/hvcall.h>
+#include <linux/delay.h>
#include <linux/dma-mapping.h>
#include <linux/gfp.h>
#include <linux/interrupt.h>
@@ -71,11 +72,13 @@ static void rpavscsi_release_crq_queue(struct crq_queue *queue,
struct ibmvscsi_host_data *hostdata,
int max_requests)
{
- long rc;
+ long rc = 0;
struct vio_dev *vdev = to_vio_dev(hostdata->dev);
free_irq(vdev->irq, (void *)hostdata);
tasklet_kill(&hostdata->srp_task);
do {
+ if (rc)
+ msleep(100);
rc = plpar_hcall_norets(H_FREE_CRQ, vdev->unit_address);
} while ((rc == H_BUSY) || (H_IS_LONG_BUSY(rc)));
dma_unmap_single(hostdata->dev,
@@ -200,11 +203,13 @@ static void set_adapter_info(struct ibmvscsi_host_data *hostdata)
static int rpavscsi_reset_crq_queue(struct crq_queue *queue,
struct ibmvscsi_host_data *hostdata)
{
- int rc;
+ int rc = 0;
struct vio_dev *vdev = to_vio_dev(hostdata->dev);
/* Close the CRQ */
do {
+ if (rc)
+ msleep(100);
rc = plpar_hcall_norets(H_FREE_CRQ, vdev->unit_address);
} while ((rc == H_BUSY) || (H_IS_LONG_BUSY(rc)));
@@ -301,7 +306,10 @@ static int rpavscsi_init_crq_queue(struct crq_queue *queue,
req_irq_failed:
tasklet_kill(&hostdata->srp_task);
+ rc = 0;
do {
+ if (rc)
+ msleep(100);
rc = plpar_hcall_norets(H_FREE_CRQ, vdev->unit_address);
} while ((rc == H_BUSY) || (H_IS_LONG_BUSY(rc)));
reg_crq_failed:
@@ -323,11 +331,13 @@ static int rpavscsi_init_crq_queue(struct crq_queue *queue,
static int rpavscsi_reenable_crq_queue(struct crq_queue *queue,
struct ibmvscsi_host_data *hostdata)
{
- int rc;
+ int rc = 0;
struct vio_dev *vdev = to_vio_dev(hostdata->dev);
/* Re-enable the CRQ */
do {
+ if (rc)
+ msleep(100);
rc = plpar_hcall_norets(H_ENABLE_CRQ, vdev->unit_address);
} while ((rc == H_IN_PROGRESS) || (rc == H_BUSY) || (H_IS_LONG_BUSY(rc)));
diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c
index f820cffb7f0..52568588039 100644
--- a/drivers/scsi/ipr.c
+++ b/drivers/scsi/ipr.c
@@ -167,21 +167,22 @@ static const struct ipr_chip_cfg_t ipr_chip_cfg[] = {
.clr_uproc_interrupt_reg32 = 0x0002C,
.init_feedback_reg = 0x0005C,
.dump_addr_reg = 0x00064,
- .dump_data_reg = 0x00068
+ .dump_data_reg = 0x00068,
+ .endian_swap_reg = 0x00084
}
},
};
static const struct ipr_chip_t ipr_chip[] = {
- { PCI_VENDOR_ID_MYLEX, PCI_DEVICE_ID_IBM_GEMSTONE, IPR_USE_LSI, IPR_SIS32, &ipr_chip_cfg[0] },
- { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CITRINE, IPR_USE_LSI, IPR_SIS32, &ipr_chip_cfg[0] },
- { PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_OBSIDIAN, IPR_USE_LSI, IPR_SIS32, &ipr_chip_cfg[0] },
- { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN, IPR_USE_LSI, IPR_SIS32, &ipr_chip_cfg[0] },
- { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN_E, IPR_USE_MSI, IPR_SIS32, &ipr_chip_cfg[0] },
- { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_SNIPE, IPR_USE_LSI, IPR_SIS32, &ipr_chip_cfg[1] },
- { PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_SCAMP, IPR_USE_LSI, IPR_SIS32, &ipr_chip_cfg[1] },
- { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CROC_FPGA_E2, IPR_USE_MSI, IPR_SIS64, &ipr_chip_cfg[2] },
- { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CROC_ASIC_E2, IPR_USE_MSI, IPR_SIS64, &ipr_chip_cfg[2] }
+ { PCI_VENDOR_ID_MYLEX, PCI_DEVICE_ID_IBM_GEMSTONE, IPR_USE_LSI, IPR_SIS32, IPR_PCI_CFG, &ipr_chip_cfg[0] },
+ { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CITRINE, IPR_USE_LSI, IPR_SIS32, IPR_PCI_CFG, &ipr_chip_cfg[0] },
+ { PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_OBSIDIAN, IPR_USE_LSI, IPR_SIS32, IPR_PCI_CFG, &ipr_chip_cfg[0] },
+ { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN, IPR_USE_LSI, IPR_SIS32, IPR_PCI_CFG, &ipr_chip_cfg[0] },
+ { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN_E, IPR_USE_MSI, IPR_SIS32, IPR_PCI_CFG, &ipr_chip_cfg[0] },
+ { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_SNIPE, IPR_USE_LSI, IPR_SIS32, IPR_PCI_CFG, &ipr_chip_cfg[1] },
+ { PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_SCAMP, IPR_USE_LSI, IPR_SIS32, IPR_PCI_CFG, &ipr_chip_cfg[1] },
+ { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CROC_FPGA_E2, IPR_USE_MSI, IPR_SIS64, IPR_MMIO, &ipr_chip_cfg[2] },
+ { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CROC_ASIC_E2, IPR_USE_MSI, IPR_SIS64, IPR_MMIO, &ipr_chip_cfg[2] }
};
static int ipr_max_bus_speeds [] = {
@@ -1167,7 +1168,7 @@ static void ipr_update_res_entry(struct ipr_resource_entry *res,
if (res->ioa_cfg->sis64) {
res->flags = cfgtew->u.cfgte64->flags;
res->res_flags = cfgtew->u.cfgte64->res_flags;
- res->type = cfgtew->u.cfgte64->res_type & 0x0f;
+ res->type = cfgtew->u.cfgte64->res_type;
memcpy(&res->std_inq_data, &cfgtew->u.cfgte64->std_inq_data,
sizeof(struct ipr_std_inq_data));
@@ -3761,6 +3762,36 @@ static struct device_attribute ipr_update_fw_attr = {
.store = ipr_store_update_fw
};
+/**
+ * ipr_show_fw_type - Show the adapter's firmware type.
+ * @dev: class device struct
+ * @buf: buffer
+ *
+ * Return value:
+ * number of bytes printed to buffer
+ **/
+static ssize_t ipr_show_fw_type(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct Scsi_Host *shost = class_to_shost(dev);
+ struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *)shost->hostdata;
+ unsigned long lock_flags = 0;
+ int len;
+
+ spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
+ len = snprintf(buf, PAGE_SIZE, "%d\n", ioa_cfg->sis64);
+ spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
+ return len;
+}
+
+static struct device_attribute ipr_ioa_fw_type_attr = {
+ .attr = {
+ .name = "fw_type",
+ .mode = S_IRUGO,
+ },
+ .show = ipr_show_fw_type
+};
+
static struct device_attribute *ipr_ioa_attrs[] = {
&ipr_fw_version_attr,
&ipr_log_level_attr,
@@ -3768,6 +3799,7 @@ static struct device_attribute *ipr_ioa_attrs[] = {
&ipr_ioa_state_attr,
&ipr_ioa_reset_attr,
&ipr_update_fw_attr,
+ &ipr_ioa_fw_type_attr,
NULL,
};
@@ -4121,14 +4153,49 @@ static ssize_t ipr_show_resource_path(struct device *dev, struct device_attribut
static struct device_attribute ipr_resource_path_attr = {
.attr = {
.name = "resource_path",
- .mode = S_IRUSR,
+ .mode = S_IRUGO,
},
.show = ipr_show_resource_path
};
+/**
+ * ipr_show_resource_type - Show the resource type for this device.
+ * @dev: device struct
+ * @buf: buffer
+ *
+ * Return value:
+ * number of bytes printed to buffer
+ **/
+static ssize_t ipr_show_resource_type(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct scsi_device *sdev = to_scsi_device(dev);
+ struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *)sdev->host->hostdata;
+ struct ipr_resource_entry *res;
+ unsigned long lock_flags = 0;
+ ssize_t len = -ENXIO;
+
+ spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
+ res = (struct ipr_resource_entry *)sdev->hostdata;
+
+ if (res)
+ len = snprintf(buf, PAGE_SIZE, "%x\n", res->type);
+
+ spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
+ return len;
+}
+
+static struct device_attribute ipr_resource_type_attr = {
+ .attr = {
+ .name = "resource_type",
+ .mode = S_IRUGO,
+ },
+ .show = ipr_show_resource_type
+};
+
static struct device_attribute *ipr_dev_attrs[] = {
&ipr_adapter_handle_attr,
&ipr_resource_path_attr,
+ &ipr_resource_type_attr,
NULL,
};
@@ -4352,8 +4419,6 @@ static int ipr_slave_configure(struct scsi_device *sdev)
IPR_VSET_RW_TIMEOUT);
blk_queue_max_hw_sectors(sdev->request_queue, IPR_VSET_MAX_SECTORS);
}
- if (ipr_is_vset_device(res) || ipr_is_scsi_disk(res))
- sdev->allow_restart = 1;
if (ipr_is_gata(res) && res->sata_port)
ap = res->sata_port->ap;
spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
@@ -6770,7 +6835,8 @@ static int ipr_init_res_table(struct ipr_cmnd *ipr_cmd)
list_move_tail(&res->queue, &ioa_cfg->used_res_q);
ipr_init_res_entry(res, &cfgtew);
res->add_to_ml = 1;
- }
+ } else if (res->sdev && (ipr_is_vset_device(res) || ipr_is_scsi_disk(res)))
+ res->sdev->allow_restart = 1;
if (found)
ipr_update_res_entry(res, &cfgtew);
@@ -7169,12 +7235,15 @@ static int ipr_reset_next_stage(struct ipr_cmnd *ipr_cmd)
stage_time = ioa_cfg->transop_timeout;
ipr_cmd->job_step = ipr_ioafp_identify_hrrq;
} else if (stage == IPR_IPL_INIT_STAGE_TRANSOP) {
- ipr_cmd->job_step = ipr_ioafp_identify_hrrq;
- maskval = IPR_PCII_IPL_STAGE_CHANGE;
- maskval = (maskval << 32) | IPR_PCII_IOA_TRANS_TO_OPER;
- writeq(maskval, ioa_cfg->regs.set_interrupt_mask_reg);
- int_reg = readl(ioa_cfg->regs.sense_interrupt_mask_reg);
- return IPR_RC_JOB_CONTINUE;
+ int_reg = readl(ioa_cfg->regs.sense_interrupt_reg32);
+ if (int_reg & IPR_PCII_IOA_TRANS_TO_OPER) {
+ ipr_cmd->job_step = ipr_ioafp_identify_hrrq;
+ maskval = IPR_PCII_IPL_STAGE_CHANGE;
+ maskval = (maskval << 32) | IPR_PCII_IOA_TRANS_TO_OPER;
+ writeq(maskval, ioa_cfg->regs.set_interrupt_mask_reg);
+ int_reg = readl(ioa_cfg->regs.sense_interrupt_mask_reg);
+ return IPR_RC_JOB_CONTINUE;
+ }
}
ipr_cmd->timer.data = (unsigned long) ipr_cmd;
@@ -7208,6 +7277,12 @@ static int ipr_reset_enable_ioa(struct ipr_cmnd *ipr_cmd)
ipr_init_ioa_mem(ioa_cfg);
ioa_cfg->allow_interrupts = 1;
+ if (ioa_cfg->sis64) {
+ /* Set the adapter to the correct endian mode. */
+ writel(IPR_ENDIAN_SWAP_KEY, ioa_cfg->regs.endian_swap_reg);
+ int_reg = readl(ioa_cfg->regs.endian_swap_reg);
+ }
+
int_reg = readl(ioa_cfg->regs.sense_interrupt_reg32);
if (int_reg & IPR_PCII_IOA_TRANS_TO_OPER) {
@@ -7365,6 +7440,7 @@ static void ipr_get_unit_check_buffer(struct ipr_ioa_cfg *ioa_cfg)
static int ipr_reset_restore_cfg_space(struct ipr_cmnd *ipr_cmd)
{
struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg;
+ volatile u32 int_reg;
int rc;
ENTER;
@@ -7383,6 +7459,12 @@ static int ipr_reset_restore_cfg_space(struct ipr_cmnd *ipr_cmd)
ipr_fail_all_ops(ioa_cfg);
+ if (ioa_cfg->sis64) {
+ /* Set the adapter to the correct endian mode. */
+ writel(IPR_ENDIAN_SWAP_KEY, ioa_cfg->regs.endian_swap_reg);
+ int_reg = readl(ioa_cfg->regs.endian_swap_reg);
+ }
+
if (ioa_cfg->ioa_unit_checked) {
ioa_cfg->ioa_unit_checked = 0;
ipr_get_unit_check_buffer(ioa_cfg);
@@ -7438,20 +7520,25 @@ static int ipr_reset_bist_done(struct ipr_cmnd *ipr_cmd)
static int ipr_reset_start_bist(struct ipr_cmnd *ipr_cmd)
{
struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg;
- int rc;
+ int rc = PCIBIOS_SUCCESSFUL;
ENTER;
pci_block_user_cfg_access(ioa_cfg->pdev);
- rc = pci_write_config_byte(ioa_cfg->pdev, PCI_BIST, PCI_BIST_START);
- if (rc != PCIBIOS_SUCCESSFUL) {
- pci_unblock_user_cfg_access(ipr_cmd->ioa_cfg->pdev);
- ipr_cmd->s.ioasa.hdr.ioasc = cpu_to_be32(IPR_IOASC_PCI_ACCESS_ERROR);
- rc = IPR_RC_JOB_CONTINUE;
- } else {
+ if (ioa_cfg->ipr_chip->bist_method == IPR_MMIO)
+ writel(IPR_UPROCI_SIS64_START_BIST,
+ ioa_cfg->regs.set_uproc_interrupt_reg32);
+ else
+ rc = pci_write_config_byte(ioa_cfg->pdev, PCI_BIST, PCI_BIST_START);
+
+ if (rc == PCIBIOS_SUCCESSFUL) {
ipr_cmd->job_step = ipr_reset_bist_done;
ipr_reset_start_timer(ipr_cmd, IPR_WAIT_FOR_BIST_TIMEOUT);
rc = IPR_RC_JOB_RETURN;
+ } else {
+ pci_unblock_user_cfg_access(ipr_cmd->ioa_cfg->pdev);
+ ipr_cmd->s.ioasa.hdr.ioasc = cpu_to_be32(IPR_IOASC_PCI_ACCESS_ERROR);
+ rc = IPR_RC_JOB_CONTINUE;
}
LEAVE;
@@ -7547,7 +7634,7 @@ static int ipr_reset_wait_to_start_bist(struct ipr_cmnd *ipr_cmd)
}
/**
- * ipr_reset_alert_part2 - Alert the adapter of a pending reset
+ * ipr_reset_alert - Alert the adapter of a pending reset
* @ipr_cmd: ipr command struct
*
* Description: This function alerts the adapter that it will be reset.
@@ -8318,6 +8405,7 @@ static void __devinit ipr_init_ioa_cfg(struct ipr_ioa_cfg *ioa_cfg,
t->init_feedback_reg = base + p->init_feedback_reg;
t->dump_addr_reg = base + p->dump_addr_reg;
t->dump_data_reg = base + p->dump_data_reg;
+ t->endian_swap_reg = base + p->endian_swap_reg;
}
}
@@ -8873,6 +8961,8 @@ static struct pci_device_id ipr_pci_table[] __devinitdata = {
{ PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN_E,
PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_57B3, 0, 0, 0 },
{ PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN_E,
+ PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_57CC, 0, 0, 0 },
+ { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN_E,
PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_57B7, 0, 0,
IPR_USE_LONG_TRANSOP_TIMEOUT | IPR_USE_PCI_WARM_RESET },
{ PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_SNIPE,
diff --git a/drivers/scsi/ipr.h b/drivers/scsi/ipr.h
index b965f3587c9..4d31625ab9c 100644
--- a/drivers/scsi/ipr.h
+++ b/drivers/scsi/ipr.h
@@ -62,12 +62,12 @@
#define IPR_SUBS_DEV_ID_2780 0x0264
#define IPR_SUBS_DEV_ID_5702 0x0266
#define IPR_SUBS_DEV_ID_5703 0x0278
-#define IPR_SUBS_DEV_ID_572E 0x028D
-#define IPR_SUBS_DEV_ID_573E 0x02D3
-#define IPR_SUBS_DEV_ID_573D 0x02D4
+#define IPR_SUBS_DEV_ID_572E 0x028D
+#define IPR_SUBS_DEV_ID_573E 0x02D3
+#define IPR_SUBS_DEV_ID_573D 0x02D4
#define IPR_SUBS_DEV_ID_571A 0x02C0
#define IPR_SUBS_DEV_ID_571B 0x02BE
-#define IPR_SUBS_DEV_ID_571E 0x02BF
+#define IPR_SUBS_DEV_ID_571E 0x02BF
#define IPR_SUBS_DEV_ID_571F 0x02D5
#define IPR_SUBS_DEV_ID_572A 0x02C1
#define IPR_SUBS_DEV_ID_572B 0x02C2
@@ -82,6 +82,7 @@
#define IPR_SUBS_DEV_ID_57B4 0x033B
#define IPR_SUBS_DEV_ID_57B2 0x035F
#define IPR_SUBS_DEV_ID_57C6 0x0357
+#define IPR_SUBS_DEV_ID_57CC 0x035C
#define IPR_SUBS_DEV_ID_57B5 0x033C
#define IPR_SUBS_DEV_ID_57CE 0x035E
@@ -272,6 +273,7 @@ IPR_PCII_NO_HOST_RRQ | IPR_PCII_IOARRIN_LOST | IPR_PCII_MMIO_ERROR)
#define IPR_UPROCI_RESET_ALERT (0x80000000 >> 7)
#define IPR_UPROCI_IO_DEBUG_ALERT (0x80000000 >> 9)
+#define IPR_UPROCI_SIS64_START_BIST (0x80000000 >> 23)
#define IPR_LDUMP_MAX_LONG_ACK_DELAY_IN_USEC 200000 /* 200 ms */
#define IPR_LDUMP_MAX_SHORT_ACK_DELAY_IN_USEC 200000 /* 200 ms */
@@ -996,7 +998,7 @@ struct ipr_hostrcb64_fabric_desc {
__be16 length;
u8 descriptor_id;
- u8 reserved;
+ u8 reserved[2];
u8 path_state;
u8 reserved2[2];
@@ -1054,7 +1056,7 @@ struct ipr_hostrcb64_error {
__be64 fd_lun;
u8 fd_res_path[8];
__be64 time_stamp;
- u8 reserved[2];
+ u8 reserved[16];
union {
struct ipr_hostrcb_type_ff_error type_ff_error;
struct ipr_hostrcb_type_12_error type_12_error;
@@ -1254,6 +1256,9 @@ struct ipr_interrupt_offsets {
unsigned long dump_addr_reg;
unsigned long dump_data_reg;
+
+#define IPR_ENDIAN_SWAP_KEY 0x00080800
+ unsigned long endian_swap_reg;
};
struct ipr_interrupts {
@@ -1279,6 +1284,8 @@ struct ipr_interrupts {
void __iomem *dump_addr_reg;
void __iomem *dump_data_reg;
+
+ void __iomem *endian_swap_reg;
};
struct ipr_chip_cfg_t {
@@ -1296,6 +1303,9 @@ struct ipr_chip_t {
u16 sis_type;
#define IPR_SIS32 0x00
#define IPR_SIS64 0x01
+ u16 bist_method;
+#define IPR_PCI_CFG 0x00
+#define IPR_MMIO 0x01
const struct ipr_chip_cfg_t *cfg;
};
@@ -1855,4 +1865,12 @@ static inline int ipr_sdt_is_fmt2(u32 sdt_word)
return 0;
}
+#ifndef writeq
+static inline void writeq(u64 val, void __iomem *addr)
+{
+ writel(((u32) (val >> 32)), addr);
+ writel(((u32) (val)), (addr + 4));
+}
#endif
+
+#endif /* _IPR_H */
diff --git a/drivers/scsi/libfc/fc_disc.c b/drivers/scsi/libfc/fc_disc.c
index c7985da8809..32f67c4b03f 100644
--- a/drivers/scsi/libfc/fc_disc.c
+++ b/drivers/scsi/libfc/fc_disc.c
@@ -63,27 +63,25 @@ static void fc_disc_restart(struct fc_disc *);
void fc_disc_stop_rports(struct fc_disc *disc)
{
struct fc_lport *lport;
- struct fc_rport_priv *rdata, *next;
+ struct fc_rport_priv *rdata;
- lport = disc->lport;
+ lport = fc_disc_lport(disc);
mutex_lock(&disc->disc_mutex);
- list_for_each_entry_safe(rdata, next, &disc->rports, peers)
+ list_for_each_entry_rcu(rdata, &disc->rports, peers)
lport->tt.rport_logoff(rdata);
mutex_unlock(&disc->disc_mutex);
}
/**
* fc_disc_recv_rscn_req() - Handle Registered State Change Notification (RSCN)
- * @sp: The sequence of the RSCN exchange
+ * @disc: The discovery object to which the RSCN applies
* @fp: The RSCN frame
- * @lport: The local port that the request will be sent on
*
* Locking Note: This function expects that the disc_mutex is locked
* before it is called.
*/
-static void fc_disc_recv_rscn_req(struct fc_seq *sp, struct fc_frame *fp,
- struct fc_disc *disc)
+static void fc_disc_recv_rscn_req(struct fc_disc *disc, struct fc_frame *fp)
{
struct fc_lport *lport;
struct fc_els_rscn *rp;
@@ -96,7 +94,7 @@ static void fc_disc_recv_rscn_req(struct fc_seq *sp, struct fc_frame *fp,
LIST_HEAD(disc_ports);
struct fc_disc_port *dp, *next;
- lport = disc->lport;
+ lport = fc_disc_lport(disc);
FC_DISC_DBG(disc, "Received an RSCN event\n");
@@ -151,7 +149,7 @@ static void fc_disc_recv_rscn_req(struct fc_seq *sp, struct fc_frame *fp,
break;
}
}
- lport->tt.seq_els_rsp_send(sp, ELS_LS_ACC, NULL);
+ lport->tt.seq_els_rsp_send(fp, ELS_LS_ACC, NULL);
/*
* If not doing a complete rediscovery, do GPN_ID on
@@ -177,25 +175,22 @@ static void fc_disc_recv_rscn_req(struct fc_seq *sp, struct fc_frame *fp,
return;
reject:
FC_DISC_DBG(disc, "Received a bad RSCN frame\n");
- rjt_data.fp = NULL;
rjt_data.reason = ELS_RJT_LOGIC;
rjt_data.explan = ELS_EXPL_NONE;
- lport->tt.seq_els_rsp_send(sp, ELS_LS_RJT, &rjt_data);
+ lport->tt.seq_els_rsp_send(fp, ELS_LS_RJT, &rjt_data);
fc_frame_free(fp);
}
/**
* fc_disc_recv_req() - Handle incoming requests
- * @sp: The sequence of the request exchange
- * @fp: The request frame
* @lport: The local port receiving the request
+ * @fp: The request frame
*
* Locking Note: This function is called from the EM and will lock
* the disc_mutex before calling the handler for the
* request.
*/
-static void fc_disc_recv_req(struct fc_seq *sp, struct fc_frame *fp,
- struct fc_lport *lport)
+static void fc_disc_recv_req(struct fc_lport *lport, struct fc_frame *fp)
{
u8 op;
struct fc_disc *disc = &lport->disc;
@@ -204,7 +199,7 @@ static void fc_disc_recv_req(struct fc_seq *sp, struct fc_frame *fp,
switch (op) {
case ELS_RSCN:
mutex_lock(&disc->disc_mutex);
- fc_disc_recv_rscn_req(sp, fp, disc);
+ fc_disc_recv_rscn_req(disc, fp);
mutex_unlock(&disc->disc_mutex);
break;
default:
@@ -275,7 +270,7 @@ static void fc_disc_start(void (*disc_callback)(struct fc_lport *,
*/
static void fc_disc_done(struct fc_disc *disc, enum fc_disc_event event)
{
- struct fc_lport *lport = disc->lport;
+ struct fc_lport *lport = fc_disc_lport(disc);
struct fc_rport_priv *rdata;
FC_DISC_DBG(disc, "Discovery complete\n");
@@ -292,7 +287,7 @@ static void fc_disc_done(struct fc_disc *disc, enum fc_disc_event event)
* Skip ports which were never discovered. These are the dNS port
* and ports which were created by PLOGI.
*/
- list_for_each_entry(rdata, &disc->rports, peers) {
+ list_for_each_entry_rcu(rdata, &disc->rports, peers) {
if (!rdata->disc_id)
continue;
if (rdata->disc_id == disc->disc_id)
@@ -313,7 +308,7 @@ static void fc_disc_done(struct fc_disc *disc, enum fc_disc_event event)
*/
static void fc_disc_error(struct fc_disc *disc, struct fc_frame *fp)
{
- struct fc_lport *lport = disc->lport;
+ struct fc_lport *lport = fc_disc_lport(disc);
unsigned long delay = 0;
FC_DISC_DBG(disc, "Error %ld, retries %d/%d\n",
@@ -353,7 +348,7 @@ static void fc_disc_error(struct fc_disc *disc, struct fc_frame *fp)
static void fc_disc_gpn_ft_req(struct fc_disc *disc)
{
struct fc_frame *fp;
- struct fc_lport *lport = disc->lport;
+ struct fc_lport *lport = fc_disc_lport(disc);
WARN_ON(!fc_lport_test_ready(lport));
@@ -396,7 +391,7 @@ static int fc_disc_gpn_ft_parse(struct fc_disc *disc, void *buf, size_t len)
struct fc_rport_identifiers ids;
struct fc_rport_priv *rdata;
- lport = disc->lport;
+ lport = fc_disc_lport(disc);
disc->seq_count++;
/*
@@ -733,7 +728,7 @@ int fc_disc_init(struct fc_lport *lport)
mutex_init(&disc->disc_mutex);
INIT_LIST_HEAD(&disc->rports);
- disc->lport = lport;
+ disc->priv = lport;
return 0;
}
diff --git a/drivers/scsi/libfc/fc_elsct.c b/drivers/scsi/libfc/fc_elsct.c
index e9412b710fa..9b25969e2ad 100644
--- a/drivers/scsi/libfc/fc_elsct.c
+++ b/drivers/scsi/libfc/fc_elsct.c
@@ -64,7 +64,7 @@ struct fc_seq *fc_elsct_send(struct fc_lport *lport, u32 did,
}
fc_fill_fc_hdr(fp, r_ctl, did, lport->port_id, fh_type,
- FC_FC_FIRST_SEQ | FC_FC_END_SEQ | FC_FC_SEQ_INIT, 0);
+ FC_FCTL_REQ, 0);
return lport->tt.exch_seq_send(lport, fp, resp, NULL, arg, timer_msec);
}
diff --git a/drivers/scsi/libfc/fc_exch.c b/drivers/scsi/libfc/fc_exch.c
index 104e0fba7c4..ec2a1aec235 100644
--- a/drivers/scsi/libfc/fc_exch.c
+++ b/drivers/scsi/libfc/fc_exch.c
@@ -129,11 +129,11 @@ struct fc_exch_mgr_anchor {
};
static void fc_exch_rrq(struct fc_exch *);
-static void fc_seq_ls_acc(struct fc_seq *);
-static void fc_seq_ls_rjt(struct fc_seq *, enum fc_els_rjt_reason,
+static void fc_seq_ls_acc(struct fc_frame *);
+static void fc_seq_ls_rjt(struct fc_frame *, enum fc_els_rjt_reason,
enum fc_els_rjt_explan);
-static void fc_exch_els_rec(struct fc_seq *, struct fc_frame *);
-static void fc_exch_els_rrq(struct fc_seq *, struct fc_frame *);
+static void fc_exch_els_rec(struct fc_frame *);
+static void fc_exch_els_rrq(struct fc_frame *);
/*
* Internal implementation notes.
@@ -219,8 +219,6 @@ static void fc_exch_els_rrq(struct fc_seq *, struct fc_frame *);
*/
static char *fc_exch_rctl_names[] = FC_RCTL_NAMES_INIT;
-#define FC_TABLE_SIZE(x) (sizeof(x) / sizeof(x[0]))
-
/**
* fc_exch_name_lookup() - Lookup name by opcode
* @op: Opcode to be looked up
@@ -249,7 +247,7 @@ static inline const char *fc_exch_name_lookup(unsigned int op, char **table,
static const char *fc_exch_rctl_name(unsigned int op)
{
return fc_exch_name_lookup(op, fc_exch_rctl_names,
- FC_TABLE_SIZE(fc_exch_rctl_names));
+ ARRAY_SIZE(fc_exch_rctl_names));
}
/**
@@ -464,6 +462,7 @@ static int fc_seq_send(struct fc_lport *lport, struct fc_seq *sp,
f_ctl = ntoh24(fh->fh_f_ctl);
fc_exch_setup_hdr(ep, fp, f_ctl);
+ fr_encaps(fp) = ep->encaps;
/*
* update sequence count if this frame is carrying
@@ -1002,28 +1001,30 @@ static void fc_exch_set_addr(struct fc_exch *ep,
/**
* fc_seq_els_rsp_send() - Send an ELS response using infomation from
* the existing sequence/exchange.
- * @sp: The sequence/exchange to get information from
+ * @fp: The received frame
* @els_cmd: The ELS command to be sent
* @els_data: The ELS data to be sent
+ *
+ * The received frame is not freed.
*/
-static void fc_seq_els_rsp_send(struct fc_seq *sp, enum fc_els_cmd els_cmd,
+static void fc_seq_els_rsp_send(struct fc_frame *fp, enum fc_els_cmd els_cmd,
struct fc_seq_els_data *els_data)
{
switch (els_cmd) {
case ELS_LS_RJT:
- fc_seq_ls_rjt(sp, els_data->reason, els_data->explan);
+ fc_seq_ls_rjt(fp, els_data->reason, els_data->explan);
break;
case ELS_LS_ACC:
- fc_seq_ls_acc(sp);
+ fc_seq_ls_acc(fp);
break;
case ELS_RRQ:
- fc_exch_els_rrq(sp, els_data->fp);
+ fc_exch_els_rrq(fp);
break;
case ELS_REC:
- fc_exch_els_rec(sp, els_data->fp);
+ fc_exch_els_rec(fp);
break;
default:
- FC_EXCH_DBG(fc_seq_exch(sp), "Invalid ELS CMD:%x\n", els_cmd);
+ FC_LPORT_DBG(fr_dev(fp), "Invalid ELS CMD:%x\n", els_cmd);
}
}
@@ -1230,11 +1231,35 @@ free:
}
/**
- * fc_exch_recv_req() - Handler for an incoming request where is other
- * end is originating the sequence
+ * fc_seq_assign() - Assign exchange and sequence for incoming request
+ * @lport: The local port that received the request
+ * @fp: The request frame
+ *
+ * On success, the sequence pointer will be returned and also in fr_seq(@fp).
+ */
+static struct fc_seq *fc_seq_assign(struct fc_lport *lport, struct fc_frame *fp)
+{
+ struct fc_exch_mgr_anchor *ema;
+
+ WARN_ON(lport != fr_dev(fp));
+ WARN_ON(fr_seq(fp));
+ fr_seq(fp) = NULL;
+
+ list_for_each_entry(ema, &lport->ema_list, ema_list)
+ if ((!ema->match || ema->match(fp)) &&
+ fc_seq_lookup_recip(lport, ema->mp, fp) != FC_RJT_NONE)
+ break;
+ return fr_seq(fp);
+}
+
+/**
+ * fc_exch_recv_req() - Handler for an incoming request
* @lport: The local port that received the request
* @mp: The EM that the exchange is on
* @fp: The request frame
+ *
+ * This is used when the other end is originating the exchange
+ * and the sequence.
*/
static void fc_exch_recv_req(struct fc_lport *lport, struct fc_exch_mgr *mp,
struct fc_frame *fp)
@@ -1252,13 +1277,23 @@ static void fc_exch_recv_req(struct fc_lport *lport, struct fc_exch_mgr *mp,
fc_frame_free(fp);
return;
}
+ fr_dev(fp) = lport;
+
+ BUG_ON(fr_seq(fp)); /* XXX remove later */
+
+ /*
+ * If the RX_ID is 0xffff, don't allocate an exchange.
+ * The upper-level protocol may request one later, if needed.
+ */
+ if (fh->fh_rx_id == htons(FC_XID_UNKNOWN))
+ return lport->tt.lport_recv(lport, fp);
- fr_seq(fp) = NULL;
reject = fc_seq_lookup_recip(lport, mp, fp);
if (reject == FC_RJT_NONE) {
sp = fr_seq(fp); /* sequence will be held */
ep = fc_seq_exch(sp);
fc_seq_send_ack(sp, fp);
+ ep->encaps = fr_encaps(fp);
/*
* Call the receive function.
@@ -1274,7 +1309,7 @@ static void fc_exch_recv_req(struct fc_lport *lport, struct fc_exch_mgr *mp,
if (ep->resp)
ep->resp(sp, fp, ep->arg);
else
- lport->tt.lport_recv(lport, sp, fp);
+ lport->tt.lport_recv(lport, fp);
fc_exch_release(ep); /* release from lookup */
} else {
FC_LPORT_DBG(lport, "exch/seq lookup failed: reject %x\n",
@@ -1542,53 +1577,55 @@ static void fc_exch_recv_bls(struct fc_exch_mgr *mp, struct fc_frame *fp)
/**
* fc_seq_ls_acc() - Accept sequence with LS_ACC
- * @req_sp: The request sequence
+ * @rx_fp: The received frame, not freed here.
*
* If this fails due to allocation or transmit congestion, assume the
* originator will repeat the sequence.
*/
-static void fc_seq_ls_acc(struct fc_seq *req_sp)
+static void fc_seq_ls_acc(struct fc_frame *rx_fp)
{
- struct fc_seq *sp;
+ struct fc_lport *lport;
struct fc_els_ls_acc *acc;
struct fc_frame *fp;
- sp = fc_seq_start_next(req_sp);
- fp = fc_frame_alloc(fc_seq_exch(sp)->lp, sizeof(*acc));
- if (fp) {
- acc = fc_frame_payload_get(fp, sizeof(*acc));
- memset(acc, 0, sizeof(*acc));
- acc->la_cmd = ELS_LS_ACC;
- fc_seq_send_last(sp, fp, FC_RCTL_ELS_REP, FC_TYPE_ELS);
- }
+ lport = fr_dev(rx_fp);
+ fp = fc_frame_alloc(lport, sizeof(*acc));
+ if (!fp)
+ return;
+ acc = fc_frame_payload_get(fp, sizeof(*acc));
+ memset(acc, 0, sizeof(*acc));
+ acc->la_cmd = ELS_LS_ACC;
+ fc_fill_reply_hdr(fp, rx_fp, FC_RCTL_ELS_REP, 0);
+ lport->tt.frame_send(lport, fp);
}
/**
* fc_seq_ls_rjt() - Reject a sequence with ELS LS_RJT
- * @req_sp: The request sequence
+ * @rx_fp: The received frame, not freed here.
* @reason: The reason the sequence is being rejected
- * @explan: The explaination for the rejection
+ * @explan: The explanation for the rejection
*
* If this fails due to allocation or transmit congestion, assume the
* originator will repeat the sequence.
*/
-static void fc_seq_ls_rjt(struct fc_seq *req_sp, enum fc_els_rjt_reason reason,
+static void fc_seq_ls_rjt(struct fc_frame *rx_fp, enum fc_els_rjt_reason reason,
enum fc_els_rjt_explan explan)
{
- struct fc_seq *sp;
+ struct fc_lport *lport;
struct fc_els_ls_rjt *rjt;
struct fc_frame *fp;
- sp = fc_seq_start_next(req_sp);
- fp = fc_frame_alloc(fc_seq_exch(sp)->lp, sizeof(*rjt));
- if (fp) {
- rjt = fc_frame_payload_get(fp, sizeof(*rjt));
- memset(rjt, 0, sizeof(*rjt));
- rjt->er_cmd = ELS_LS_RJT;
- rjt->er_reason = reason;
- rjt->er_explan = explan;
- fc_seq_send_last(sp, fp, FC_RCTL_ELS_REP, FC_TYPE_ELS);
- }
+ lport = fr_dev(rx_fp);
+ fp = fc_frame_alloc(lport, sizeof(*rjt));
+ if (!fp)
+ return;
+ rjt = fc_frame_payload_get(fp, sizeof(*rjt));
+ memset(rjt, 0, sizeof(*rjt));
+ rjt->er_cmd = ELS_LS_RJT;
+ rjt->er_reason = reason;
+ rjt->er_explan = explan;
+ fc_fill_reply_hdr(fp, rx_fp, FC_RCTL_ELS_REP, 0);
+ lport->tt.frame_send(lport, fp);
}
/**
@@ -1691,17 +1728,33 @@ void fc_exch_mgr_reset(struct fc_lport *lport, u32 sid, u32 did)
EXPORT_SYMBOL(fc_exch_mgr_reset);
/**
+ * fc_exch_lookup() - find an exchange
+ * @lport: The local port
+ * @xid: The exchange ID
+ *
+ * Returns exchange pointer with hold for caller, or NULL if not found.
+ */
+static struct fc_exch *fc_exch_lookup(struct fc_lport *lport, u32 xid)
+{
+ struct fc_exch_mgr_anchor *ema;
+
+ list_for_each_entry(ema, &lport->ema_list, ema_list)
+ if (ema->mp->min_xid <= xid && xid <= ema->mp->max_xid)
+ return fc_exch_find(ema->mp, xid);
+ return NULL;
+}
+
+/**
* fc_exch_els_rec() - Handler for ELS REC (Read Exchange Concise) requests
- * @sp: The sequence the REC is on
- * @rfp: The REC frame
+ * @rfp: The REC frame, not freed here.
*
* Note that the requesting port may be different than the S_ID in the request.
*/
-static void fc_exch_els_rec(struct fc_seq *sp, struct fc_frame *rfp)
+static void fc_exch_els_rec(struct fc_frame *rfp)
{
+ struct fc_lport *lport;
struct fc_frame *fp;
struct fc_exch *ep;
- struct fc_exch_mgr *em;
struct fc_els_rec *rp;
struct fc_els_rec_acc *acc;
enum fc_els_rjt_reason reason = ELS_RJT_LOGIC;
@@ -1710,6 +1763,7 @@ static void fc_exch_els_rec(struct fc_seq *sp, struct fc_frame *rfp)
u16 rxid;
u16 oxid;
+ lport = fr_dev(rfp);
rp = fc_frame_payload_get(rfp, sizeof(*rp));
explan = ELS_EXPL_INV_LEN;
if (!rp)
@@ -1718,35 +1772,19 @@ static void fc_exch_els_rec(struct fc_seq *sp, struct fc_frame *rfp)
rxid = ntohs(rp->rec_rx_id);
oxid = ntohs(rp->rec_ox_id);
- /*
- * Currently it's hard to find the local S_ID from the exchange
- * manager. This will eventually be fixed, but for now it's easier
- * to lookup the subject exchange twice, once as if we were
- * the initiator, and then again if we weren't.
- */
- em = fc_seq_exch(sp)->em;
- ep = fc_exch_find(em, oxid);
+ ep = fc_exch_lookup(lport,
+ sid == fc_host_port_id(lport->host) ? oxid : rxid);
explan = ELS_EXPL_OXID_RXID;
- if (ep && ep->oid == sid) {
- if (ep->rxid != FC_XID_UNKNOWN &&
- rxid != FC_XID_UNKNOWN &&
- ep->rxid != rxid)
- goto rel;
- } else {
- if (ep)
- fc_exch_release(ep);
- ep = NULL;
- if (rxid != FC_XID_UNKNOWN)
- ep = fc_exch_find(em, rxid);
- if (!ep)
- goto reject;
- }
-
- fp = fc_frame_alloc(fc_seq_exch(sp)->lp, sizeof(*acc));
- if (!fp) {
- fc_exch_done(sp);
+ if (!ep)
+ goto reject;
+ if (ep->oid != sid || oxid != ep->oxid)
+ goto rel;
+ if (rxid != FC_XID_UNKNOWN && rxid != ep->rxid)
+ goto rel;
+ fp = fc_frame_alloc(lport, sizeof(*acc));
+ if (!fp)
goto out;
- }
+
acc = fc_frame_payload_get(fp, sizeof(*acc));
memset(acc, 0, sizeof(*acc));
acc->reca_cmd = ELS_LS_ACC;
@@ -1761,18 +1799,16 @@ static void fc_exch_els_rec(struct fc_seq *sp, struct fc_frame *rfp)
acc->reca_e_stat = htonl(ep->esb_stat & (ESB_ST_RESP |
ESB_ST_SEQ_INIT |
ESB_ST_COMPLETE));
- sp = fc_seq_start_next(sp);
- fc_seq_send_last(sp, fp, FC_RCTL_ELS_REP, FC_TYPE_ELS);
+ fc_fill_reply_hdr(fp, rfp, FC_RCTL_ELS_REP, 0);
+ lport->tt.frame_send(lport, fp);
out:
fc_exch_release(ep);
- fc_frame_free(rfp);
return;
rel:
fc_exch_release(ep);
reject:
- fc_seq_ls_rjt(sp, reason, explan);
- fc_frame_free(rfp);
+ fc_seq_ls_rjt(rfp, reason, explan);
}
/**
@@ -1947,20 +1983,20 @@ retry:
spin_unlock_bh(&ep->ex_lock);
}
-
/**
* fc_exch_els_rrq() - Handler for ELS RRQ (Reset Recovery Qualifier) requests
- * @sp: The sequence that the RRQ is on
- * @fp: The RRQ frame
+ * @fp: The RRQ frame, not freed here.
*/
-static void fc_exch_els_rrq(struct fc_seq *sp, struct fc_frame *fp)
+static void fc_exch_els_rrq(struct fc_frame *fp)
{
+ struct fc_lport *lport;
struct fc_exch *ep = NULL; /* request or subject exchange */
struct fc_els_rrq *rp;
u32 sid;
u16 xid;
enum fc_els_rjt_explan explan;
+ lport = fr_dev(fp);
rp = fc_frame_payload_get(fp, sizeof(*rp));
explan = ELS_EXPL_INV_LEN;
if (!rp)
@@ -1969,11 +2005,10 @@ static void fc_exch_els_rrq(struct fc_seq *sp, struct fc_frame *fp)
/*
* lookup subject exchange.
*/
- ep = fc_seq_exch(sp);
sid = ntoh24(rp->rrq_s_id); /* subject source */
- xid = ep->did == sid ? ntohs(rp->rrq_ox_id) : ntohs(rp->rrq_rx_id);
- ep = fc_exch_find(ep->em, xid);
-
+ xid = fc_host_port_id(lport->host) == sid ?
+ ntohs(rp->rrq_ox_id) : ntohs(rp->rrq_rx_id);
+ ep = fc_exch_lookup(lport, xid);
explan = ELS_EXPL_OXID_RXID;
if (!ep)
goto reject;
@@ -2004,15 +2039,14 @@ static void fc_exch_els_rrq(struct fc_seq *sp, struct fc_frame *fp)
/*
* Send LS_ACC.
*/
- fc_seq_ls_acc(sp);
+ fc_seq_ls_acc(fp);
goto out;
unlock_reject:
spin_unlock_bh(&ep->ex_lock);
reject:
- fc_seq_ls_rjt(sp, ELS_RJT_LOGIC, explan);
+ fc_seq_ls_rjt(fp, ELS_RJT_LOGIC, explan);
out:
- fc_frame_free(fp);
if (ep)
fc_exch_release(ep); /* drop hold from fc_exch_find */
}
@@ -2243,7 +2277,7 @@ void fc_exch_recv(struct fc_lport *lport, struct fc_frame *fp)
fc_exch_recv_seq_resp(ema->mp, fp);
else if (f_ctl & FC_FC_SEQ_CTX)
fc_exch_recv_resp(ema->mp, fp);
- else
+ else /* no EX_CTX and no SEQ_CTX */
fc_exch_recv_req(lport, ema->mp, fp);
break;
default:
@@ -2281,6 +2315,9 @@ int fc_exch_init(struct fc_lport *lport)
if (!lport->tt.seq_exch_abort)
lport->tt.seq_exch_abort = fc_seq_exch_abort;
+ if (!lport->tt.seq_assign)
+ lport->tt.seq_assign = fc_seq_assign;
+
return 0;
}
EXPORT_SYMBOL(fc_exch_init);
diff --git a/drivers/scsi/libfc/fc_fcp.c b/drivers/scsi/libfc/fc_fcp.c
index ec1f66c4a9d..eac4d09314e 100644
--- a/drivers/scsi/libfc/fc_fcp.c
+++ b/drivers/scsi/libfc/fc_fcp.c
@@ -580,10 +580,8 @@ static int fc_fcp_send_data(struct fc_fcp_pkt *fsp, struct fc_seq *seq,
fsp, seq_blen, lport->lso_max, t_blen);
}
- WARN_ON(t_blen < FC_MIN_MAX_PAYLOAD);
if (t_blen > 512)
t_blen &= ~(512 - 1); /* round down to block size */
- WARN_ON(t_blen < FC_MIN_MAX_PAYLOAD); /* won't go below 256 */
sc = fsp->cmd;
remaining = seq_blen;
@@ -745,7 +743,7 @@ static void fc_fcp_recv(struct fc_seq *seq, struct fc_frame *fp, void *arg)
fh = fc_frame_header_get(fp);
r_ctl = fh->fh_r_ctl;
- if (!(lport->state & LPORT_ST_READY))
+ if (lport->state != LPORT_ST_READY)
goto out;
if (fc_fcp_lock_pkt(fsp))
goto out;
@@ -1110,7 +1108,7 @@ static int fc_fcp_cmd_send(struct fc_lport *lport, struct fc_fcp_pkt *fsp,
fc_fill_fc_hdr(fp, FC_RCTL_DD_UNSOL_CMD, rport->port_id,
rpriv->local_port->port_id, FC_TYPE_FCP,
- FC_FC_FIRST_SEQ | FC_FC_END_SEQ | FC_FC_SEQ_INIT, 0);
+ FC_FCTL_REQ, 0);
seq = lport->tt.exch_seq_send(lport, fp, resp, fc_fcp_pkt_destroy,
fsp, 0);
@@ -1383,7 +1381,7 @@ static void fc_fcp_rec(struct fc_fcp_pkt *fsp)
fr_seq(fp) = fsp->seq_ptr;
fc_fill_fc_hdr(fp, FC_RCTL_ELS_REQ, rport->port_id,
rpriv->local_port->port_id, FC_TYPE_ELS,
- FC_FC_FIRST_SEQ | FC_FC_END_SEQ | FC_FC_SEQ_INIT, 0);
+ FC_FCTL_REQ, 0);
if (lport->tt.elsct_send(lport, rport->port_id, fp, ELS_REC,
fc_fcp_rec_resp, fsp,
jiffies_to_msecs(FC_SCSI_REC_TOV))) {
@@ -1641,7 +1639,7 @@ static void fc_fcp_srr(struct fc_fcp_pkt *fsp, enum fc_rctl r_ctl, u32 offset)
fc_fill_fc_hdr(fp, FC_RCTL_ELS4_REQ, rport->port_id,
rpriv->local_port->port_id, FC_TYPE_FCP,
- FC_FC_FIRST_SEQ | FC_FC_END_SEQ | FC_FC_SEQ_INIT, 0);
+ FC_FCTL_REQ, 0);
seq = lport->tt.exch_seq_send(lport, fp, fc_fcp_srr_resp, NULL,
fsp, jiffies_to_msecs(FC_SCSI_REC_TOV));
@@ -1973,6 +1971,11 @@ static void fc_io_compl(struct fc_fcp_pkt *fsp)
break;
}
+ if (lport->state != LPORT_ST_READY && fsp->status_code != FC_COMPLETE) {
+ sc_cmd->result = (DID_REQUEUE << 16);
+ FC_FCP_DBG(fsp, "Returning DID_REQUEUE to scsi-ml\n");
+ }
+
spin_lock_irqsave(&si->scsi_queue_lock, flags);
list_del(&fsp->list);
spin_unlock_irqrestore(&si->scsi_queue_lock, flags);
diff --git a/drivers/scsi/libfc/fc_libfc.c b/drivers/scsi/libfc/fc_libfc.c
index 39f4b6ab04b..6a48c28e442 100644
--- a/drivers/scsi/libfc/fc_libfc.c
+++ b/drivers/scsi/libfc/fc_libfc.c
@@ -23,6 +23,7 @@
#include <linux/crc32.h>
#include <scsi/libfc.h>
+#include <scsi/fc_encode.h>
#include "fc_libfc.h"
@@ -132,3 +133,80 @@ u32 fc_copy_buffer_to_sglist(void *buf, size_t len,
}
return copy_len;
}
+
+/**
+ * fc_fill_hdr() - fill FC header fields based on request
+ * @fp: reply frame containing header to be filled in
+ * @in_fp: request frame containing header to use in filling in reply
+ * @r_ctl: R_CTL value for header
+ * @f_ctl: F_CTL value for header, with 0 pad
+ * @seq_cnt: sequence count for the header, ignored if frame has a sequence
+ * @parm_offset: parameter / offset value
+ */
+void fc_fill_hdr(struct fc_frame *fp, const struct fc_frame *in_fp,
+ enum fc_rctl r_ctl, u32 f_ctl, u16 seq_cnt, u32 parm_offset)
+{
+ struct fc_frame_header *fh;
+ struct fc_frame_header *in_fh;
+ struct fc_seq *sp;
+ u32 fill;
+
+ fh = __fc_frame_header_get(fp);
+ in_fh = __fc_frame_header_get(in_fp);
+
+ if (f_ctl & FC_FC_END_SEQ) {
+ fill = -fr_len(fp) & 3;
+ if (fill) {
+ /* TODO, this may be a problem with fragmented skb */
+ memset(skb_put(fp_skb(fp), fill), 0, fill);
+ f_ctl |= fill;
+ }
+ fr_eof(fp) = FC_EOF_T;
+ } else {
+ WARN_ON(fr_len(fp) % 4 != 0); /* no pad to non last frame */
+ fr_eof(fp) = FC_EOF_N;
+ }
+
+ fh->fh_r_ctl = r_ctl;
+ memcpy(fh->fh_d_id, in_fh->fh_s_id, sizeof(fh->fh_d_id));
+ memcpy(fh->fh_s_id, in_fh->fh_d_id, sizeof(fh->fh_s_id));
+ fh->fh_type = in_fh->fh_type;
+ hton24(fh->fh_f_ctl, f_ctl);
+ fh->fh_ox_id = in_fh->fh_ox_id;
+ fh->fh_rx_id = in_fh->fh_rx_id;
+ fh->fh_cs_ctl = 0;
+ fh->fh_df_ctl = 0;
+ fh->fh_parm_offset = htonl(parm_offset);
+
+ sp = fr_seq(in_fp);
+ if (sp) {
+ fr_seq(fp) = sp;
+ fh->fh_seq_id = sp->id;
+ seq_cnt = sp->cnt;
+ } else {
+ fh->fh_seq_id = 0;
+ }
+ fh->fh_seq_cnt = ntohs(seq_cnt);
+ fr_sof(fp) = seq_cnt ? FC_SOF_N3 : FC_SOF_I3;
+ fr_encaps(fp) = fr_encaps(in_fp);
+}
+EXPORT_SYMBOL(fc_fill_hdr);
+
+/**
+ * fc_fill_reply_hdr() - fill FC reply header fields based on request
+ * @fp: reply frame containing header to be filled in
+ * @in_fp: request frame containing header to use in filling in reply
+ * @r_ctl: R_CTL value for reply
+ * @parm_offset: parameter / offset value
+ */
+void fc_fill_reply_hdr(struct fc_frame *fp, const struct fc_frame *in_fp,
+ enum fc_rctl r_ctl, u32 parm_offset)
+{
+ struct fc_seq *sp;
+
+ sp = fr_seq(in_fp);
+ if (sp)
+ fr_seq(fp) = fr_dev(in_fp)->tt.seq_start_next(sp);
+ fc_fill_hdr(fp, in_fp, r_ctl, FC_FCTL_RESP, 0, parm_offset);
+}
+EXPORT_SYMBOL(fc_fill_reply_hdr);
diff --git a/drivers/scsi/libfc/fc_libfc.h b/drivers/scsi/libfc/fc_libfc.h
index f5c0ca4b6ef..16d2162dda1 100644
--- a/drivers/scsi/libfc/fc_libfc.h
+++ b/drivers/scsi/libfc/fc_libfc.h
@@ -52,7 +52,7 @@ extern unsigned int fc_debug_logging;
#define FC_DISC_DBG(disc, fmt, args...) \
FC_CHECK_LOGGING(FC_DISC_LOGGING, \
printk(KERN_INFO "host%u: disc: " fmt, \
- (disc)->lport->host->host_no, \
+ fc_disc_lport(disc)->host->host_no, \
##args))
#define FC_RPORT_ID_DBG(lport, port_id, fmt, args...) \
diff --git a/drivers/scsi/libfc/fc_lport.c b/drivers/scsi/libfc/fc_lport.c
index 79c9e3ccd34..d9b6e11b0e8 100644
--- a/drivers/scsi/libfc/fc_lport.c
+++ b/drivers/scsi/libfc/fc_lport.c
@@ -32,11 +32,11 @@
* invalid SID. We also need to ensure that states don't change unexpectedly
* while processing another state.
*
- * HEIRARCHY
+ * HIERARCHY
*
- * The following heirarchy defines the locking rules. A greater lock
+ * The following hierarchy defines the locking rules. A greater lock
* may be held before acquiring a lesser lock, but a lesser lock should never
- * be held while attempting to acquire a greater lock. Here is the heirarchy-
+ * be held while attempting to acquire a greater lock. Here is the hierarchy-
*
* lport > disc, lport > rport, disc > rport
*
@@ -375,41 +375,36 @@ static void fc_lport_add_fc4_type(struct fc_lport *lport, enum fc_fh_type type)
/**
* fc_lport_recv_rlir_req() - Handle received Registered Link Incident Report.
- * @sp: The sequence in the RLIR exchange
- * @fp: The RLIR request frame
* @lport: Fibre Channel local port recieving the RLIR
+ * @fp: The RLIR request frame
*
* Locking Note: The lport lock is expected to be held before calling
* this function.
*/
-static void fc_lport_recv_rlir_req(struct fc_seq *sp, struct fc_frame *fp,
- struct fc_lport *lport)
+static void fc_lport_recv_rlir_req(struct fc_lport *lport, struct fc_frame *fp)
{
FC_LPORT_DBG(lport, "Received RLIR request while in state %s\n",
fc_lport_state(lport));
- lport->tt.seq_els_rsp_send(sp, ELS_LS_ACC, NULL);
+ lport->tt.seq_els_rsp_send(fp, ELS_LS_ACC, NULL);
fc_frame_free(fp);
}
/**
* fc_lport_recv_echo_req() - Handle received ECHO request
- * @sp: The sequence in the ECHO exchange
- * @fp: ECHO request frame
* @lport: The local port recieving the ECHO
+ * @fp: ECHO request frame
*
* Locking Note: The lport lock is expected to be held before calling
* this function.
*/
-static void fc_lport_recv_echo_req(struct fc_seq *sp, struct fc_frame *in_fp,
- struct fc_lport *lport)
+static void fc_lport_recv_echo_req(struct fc_lport *lport,
+ struct fc_frame *in_fp)
{
struct fc_frame *fp;
- struct fc_exch *ep = fc_seq_exch(sp);
unsigned int len;
void *pp;
void *dp;
- u32 f_ctl;
FC_LPORT_DBG(lport, "Received ECHO request while in state %s\n",
fc_lport_state(lport));
@@ -425,29 +420,24 @@ static void fc_lport_recv_echo_req(struct fc_seq *sp, struct fc_frame *in_fp,
dp = fc_frame_payload_get(fp, len);
memcpy(dp, pp, len);
*((__be32 *)dp) = htonl(ELS_LS_ACC << 24);
- sp = lport->tt.seq_start_next(sp);
- f_ctl = FC_FC_EX_CTX | FC_FC_LAST_SEQ | FC_FC_END_SEQ;
- fc_fill_fc_hdr(fp, FC_RCTL_ELS_REP, ep->did, ep->sid,
- FC_TYPE_ELS, f_ctl, 0);
- lport->tt.seq_send(lport, sp, fp);
+ fc_fill_reply_hdr(fp, in_fp, FC_RCTL_ELS_REP, 0);
+ lport->tt.frame_send(lport, fp);
}
fc_frame_free(in_fp);
}
/**
* fc_lport_recv_rnid_req() - Handle received Request Node ID data request
- * @sp: The sequence in the RNID exchange
- * @fp: The RNID request frame
* @lport: The local port recieving the RNID
+ * @fp: The RNID request frame
*
* Locking Note: The lport lock is expected to be held before calling
* this function.
*/
-static void fc_lport_recv_rnid_req(struct fc_seq *sp, struct fc_frame *in_fp,
- struct fc_lport *lport)
+static void fc_lport_recv_rnid_req(struct fc_lport *lport,
+ struct fc_frame *in_fp)
{
struct fc_frame *fp;
- struct fc_exch *ep = fc_seq_exch(sp);
struct fc_els_rnid *req;
struct {
struct fc_els_rnid_resp rnid;
@@ -457,17 +447,15 @@ static void fc_lport_recv_rnid_req(struct fc_seq *sp, struct fc_frame *in_fp,
struct fc_seq_els_data rjt_data;
u8 fmt;
size_t len;
- u32 f_ctl;
FC_LPORT_DBG(lport, "Received RNID request while in state %s\n",
fc_lport_state(lport));
req = fc_frame_payload_get(in_fp, sizeof(*req));
if (!req) {
- rjt_data.fp = NULL;
rjt_data.reason = ELS_RJT_LOGIC;
rjt_data.explan = ELS_EXPL_NONE;
- lport->tt.seq_els_rsp_send(sp, ELS_LS_RJT, &rjt_data);
+ lport->tt.seq_els_rsp_send(in_fp, ELS_LS_RJT, &rjt_data);
} else {
fmt = req->rnid_fmt;
len = sizeof(*rp);
@@ -490,12 +478,8 @@ static void fc_lport_recv_rnid_req(struct fc_seq *sp, struct fc_frame *in_fp,
memcpy(&rp->gen, &lport->rnid_gen,
sizeof(rp->gen));
}
- sp = lport->tt.seq_start_next(sp);
- f_ctl = FC_FC_EX_CTX | FC_FC_LAST_SEQ;
- f_ctl |= FC_FC_END_SEQ | FC_FC_SEQ_INIT;
- fc_fill_fc_hdr(fp, FC_RCTL_ELS_REP, ep->did, ep->sid,
- FC_TYPE_ELS, f_ctl, 0);
- lport->tt.seq_send(lport, sp, fp);
+ fc_fill_reply_hdr(fp, in_fp, FC_RCTL_ELS_REP, 0);
+ lport->tt.frame_send(lport, fp);
}
}
fc_frame_free(in_fp);
@@ -503,17 +487,15 @@ static void fc_lport_recv_rnid_req(struct fc_seq *sp, struct fc_frame *in_fp,
/**
* fc_lport_recv_logo_req() - Handle received fabric LOGO request
- * @sp: The sequence in the LOGO exchange
- * @fp: The LOGO request frame
* @lport: The local port recieving the LOGO
+ * @fp: The LOGO request frame
*
* Locking Note: The lport lock is exected to be held before calling
* this function.
*/
-static void fc_lport_recv_logo_req(struct fc_seq *sp, struct fc_frame *fp,
- struct fc_lport *lport)
+static void fc_lport_recv_logo_req(struct fc_lport *lport, struct fc_frame *fp)
{
- lport->tt.seq_els_rsp_send(sp, ELS_LS_ACC, NULL);
+ lport->tt.seq_els_rsp_send(fp, ELS_LS_ACC, NULL);
fc_lport_enter_reset(lport);
fc_frame_free(fp);
}
@@ -755,10 +737,37 @@ static void fc_lport_set_port_id(struct fc_lport *lport, u32 port_id,
}
/**
+ * fc_lport_set_port_id() - set the local port Port ID for point-to-multipoint
+ * @lport: The local port which will have its Port ID set.
+ * @port_id: The new port ID.
+ *
+ * Called by the lower-level driver when transport sets the local port_id.
+ * This is used in VN_port to VN_port mode for FCoE, and causes FLOGI and
+ * discovery to be skipped.
+ */
+void fc_lport_set_local_id(struct fc_lport *lport, u32 port_id)
+{
+ mutex_lock(&lport->lp_mutex);
+
+ fc_lport_set_port_id(lport, port_id, NULL);
+
+ switch (lport->state) {
+ case LPORT_ST_RESET:
+ case LPORT_ST_FLOGI:
+ if (port_id)
+ fc_lport_enter_ready(lport);
+ break;
+ default:
+ break;
+ }
+ mutex_unlock(&lport->lp_mutex);
+}
+EXPORT_SYMBOL(fc_lport_set_local_id);
+
+/**
* fc_lport_recv_flogi_req() - Receive a FLOGI request
- * @sp_in: The sequence the FLOGI is on
- * @rx_fp: The FLOGI frame
* @lport: The local port that recieved the request
+ * @rx_fp: The FLOGI frame
*
* A received FLOGI request indicates a point-to-point connection.
* Accept it with the common service parameters indicating our N port.
@@ -767,26 +776,21 @@ static void fc_lport_set_port_id(struct fc_lport *lport, u32 port_id,
* Locking Note: The lport lock is expected to be held before calling
* this function.
*/
-static void fc_lport_recv_flogi_req(struct fc_seq *sp_in,
- struct fc_frame *rx_fp,
- struct fc_lport *lport)
+static void fc_lport_recv_flogi_req(struct fc_lport *lport,
+ struct fc_frame *rx_fp)
{
struct fc_frame *fp;
struct fc_frame_header *fh;
- struct fc_seq *sp;
- struct fc_exch *ep;
struct fc_els_flogi *flp;
struct fc_els_flogi *new_flp;
u64 remote_wwpn;
u32 remote_fid;
u32 local_fid;
- u32 f_ctl;
FC_LPORT_DBG(lport, "Received FLOGI request while in state %s\n",
fc_lport_state(lport));
- fh = fc_frame_header_get(rx_fp);
- remote_fid = ntoh24(fh->fh_s_id);
+ remote_fid = fc_frame_sid(rx_fp);
flp = fc_frame_payload_get(rx_fp, sizeof(*flp));
if (!flp)
goto out;
@@ -817,7 +821,6 @@ static void fc_lport_recv_flogi_req(struct fc_seq *sp_in,
fp = fc_frame_alloc(lport, sizeof(*flp));
if (fp) {
- sp = lport->tt.seq_start_next(fr_seq(rx_fp));
new_flp = fc_frame_payload_get(fp, sizeof(*flp));
fc_lport_flogi_fill(lport, new_flp, ELS_FLOGI);
new_flp->fl_cmd = (u8) ELS_LS_ACC;
@@ -826,27 +829,24 @@ static void fc_lport_recv_flogi_req(struct fc_seq *sp_in,
* Send the response. If this fails, the originator should
* repeat the sequence.
*/
- f_ctl = FC_FC_EX_CTX | FC_FC_LAST_SEQ | FC_FC_END_SEQ;
- ep = fc_seq_exch(sp);
- fc_fill_fc_hdr(fp, FC_RCTL_ELS_REP, remote_fid, local_fid,
- FC_TYPE_ELS, f_ctl, 0);
- lport->tt.seq_send(lport, sp, fp);
+ fc_fill_reply_hdr(fp, rx_fp, FC_RCTL_ELS_REP, 0);
+ fh = fc_frame_header_get(fp);
+ hton24(fh->fh_s_id, local_fid);
+ hton24(fh->fh_d_id, remote_fid);
+ lport->tt.frame_send(lport, fp);
} else {
fc_lport_error(lport, fp);
}
fc_lport_ptp_setup(lport, remote_fid, remote_wwpn,
get_unaligned_be64(&flp->fl_wwnn));
-
out:
- sp = fr_seq(rx_fp);
fc_frame_free(rx_fp);
}
/**
* fc_lport_recv_req() - The generic lport request handler
* @lport: The local port that received the request
- * @sp: The sequence the request is on
* @fp: The request frame
*
* This function will see if the lport handles the request or
@@ -855,11 +855,10 @@ out:
* Locking Note: This function should not be called with the lport
* lock held becuase it will grab the lock.
*/
-static void fc_lport_recv_req(struct fc_lport *lport, struct fc_seq *sp,
- struct fc_frame *fp)
+static void fc_lport_recv_req(struct fc_lport *lport, struct fc_frame *fp)
{
struct fc_frame_header *fh = fc_frame_header_get(fp);
- void (*recv) (struct fc_seq *, struct fc_frame *, struct fc_lport *);
+ void (*recv)(struct fc_lport *, struct fc_frame *);
mutex_lock(&lport->lp_mutex);
@@ -878,11 +877,11 @@ static void fc_lport_recv_req(struct fc_lport *lport, struct fc_seq *sp,
recv = lport->tt.rport_recv_req;
switch (fc_frame_payload_op(fp)) {
case ELS_FLOGI:
- recv = fc_lport_recv_flogi_req;
+ if (!lport->point_to_multipoint)
+ recv = fc_lport_recv_flogi_req;
break;
case ELS_LOGO:
- fh = fc_frame_header_get(fp);
- if (ntoh24(fh->fh_s_id) == FC_FID_FLOGI)
+ if (fc_frame_sid(fp) == FC_FID_FLOGI)
recv = fc_lport_recv_logo_req;
break;
case ELS_RSCN:
@@ -899,19 +898,13 @@ static void fc_lport_recv_req(struct fc_lport *lport, struct fc_seq *sp,
break;
}
- recv(sp, fp, lport);
+ recv(lport, fp);
} else {
FC_LPORT_DBG(lport, "dropping invalid frame (eof %x)\n",
fr_eof(fp));
fc_frame_free(fp);
}
mutex_unlock(&lport->lp_mutex);
-
- /*
- * The common exch_done for all request may not be good
- * if any request requires longer hold on exhange. XXX
- */
- lport->tt.exch_done(sp);
}
/**
@@ -954,7 +947,7 @@ static void fc_lport_reset_locked(struct fc_lport *lport)
lport->tt.exch_mgr_reset(lport, 0, 0);
fc_host_fabric_name(lport->host) = 0;
- if (lport->port_id)
+ if (lport->port_id && (!lport->point_to_multipoint || !lport->link_up))
fc_lport_set_port_id(lport, 0, NULL);
}
@@ -1019,38 +1012,24 @@ static void fc_lport_error(struct fc_lport *lport, struct fc_frame *fp)
PTR_ERR(fp), fc_lport_state(lport),
lport->retry_count);
- if (!fp || PTR_ERR(fp) == -FC_EX_TIMEOUT) {
- /*
- * Memory allocation failure, or the exchange timed out.
- * Retry after delay
- */
- if (lport->retry_count < lport->max_retry_count) {
- lport->retry_count++;
- if (!fp)
- delay = msecs_to_jiffies(500);
- else
- delay = msecs_to_jiffies(lport->e_d_tov);
-
- schedule_delayed_work(&lport->retry_work, delay);
- } else {
- switch (lport->state) {
- case LPORT_ST_DISABLED:
- case LPORT_ST_READY:
- case LPORT_ST_RESET:
- case LPORT_ST_RNN_ID:
- case LPORT_ST_RSNN_NN:
- case LPORT_ST_RSPN_ID:
- case LPORT_ST_RFT_ID:
- case LPORT_ST_RFF_ID:
- case LPORT_ST_SCR:
- case LPORT_ST_DNS:
- case LPORT_ST_FLOGI:
- case LPORT_ST_LOGO:
- fc_lport_enter_reset(lport);
- break;
- }
- }
- }
+ if (PTR_ERR(fp) == -FC_EX_CLOSED)
+ return;
+
+ /*
+ * Memory allocation failure, or the exchange timed out
+ * or we received LS_RJT.
+ * Retry after delay
+ */
+ if (lport->retry_count < lport->max_retry_count) {
+ lport->retry_count++;
+ if (!fp)
+ delay = msecs_to_jiffies(500);
+ else
+ delay = msecs_to_jiffies(lport->e_d_tov);
+
+ schedule_delayed_work(&lport->retry_work, delay);
+ } else
+ fc_lport_enter_reset(lport);
}
/**
@@ -1440,7 +1419,6 @@ void fc_lport_flogi_resp(struct fc_seq *sp, struct fc_frame *fp,
void *lp_arg)
{
struct fc_lport *lport = lp_arg;
- struct fc_frame_header *fh;
struct fc_els_flogi *flp;
u32 did;
u16 csp_flags;
@@ -1468,9 +1446,14 @@ void fc_lport_flogi_resp(struct fc_seq *sp, struct fc_frame *fp,
goto err;
}
- fh = fc_frame_header_get(fp);
- did = ntoh24(fh->fh_d_id);
- if (fc_frame_payload_op(fp) == ELS_LS_ACC && did != 0) {
+ did = fc_frame_did(fp);
+
+ if (!did) {
+ FC_LPORT_DBG(lport, "Bad FLOGI response\n");
+ goto out;
+ }
+
+ if (fc_frame_payload_op(fp) == ELS_LS_ACC) {
flp = fc_frame_payload_get(fp, sizeof(*flp));
if (flp) {
mfs = ntohs(flp->fl_csp.sp_bb_data) &
@@ -1495,7 +1478,7 @@ void fc_lport_flogi_resp(struct fc_seq *sp, struct fc_frame *fp,
"Port (%6.6x) entered "
"point-to-point mode\n",
lport->host->host_no, did);
- fc_lport_ptp_setup(lport, ntoh24(fh->fh_s_id),
+ fc_lport_ptp_setup(lport, fc_frame_sid(fp),
get_unaligned_be64(
&flp->fl_wwpn),
get_unaligned_be64(
@@ -1509,9 +1492,8 @@ void fc_lport_flogi_resp(struct fc_seq *sp, struct fc_frame *fp,
fc_lport_enter_dns(lport);
}
}
- } else {
- FC_LPORT_DBG(lport, "Bad FLOGI response\n");
- }
+ } else
+ fc_lport_error(lport, fp);
out:
fc_frame_free(fp);
@@ -1536,6 +1518,12 @@ void fc_lport_enter_flogi(struct fc_lport *lport)
fc_lport_state_enter(lport, LPORT_ST_FLOGI);
+ if (lport->point_to_multipoint) {
+ if (lport->port_id)
+ fc_lport_enter_ready(lport);
+ return;
+ }
+
fp = fc_frame_alloc(lport, sizeof(struct fc_els_flogi));
if (!fp)
return fc_lport_error(lport, fp);
@@ -1701,8 +1689,7 @@ static int fc_lport_els_request(struct fc_bsg_job *job,
hton24(fh->fh_d_id, did);
hton24(fh->fh_s_id, lport->port_id);
fh->fh_type = FC_TYPE_ELS;
- hton24(fh->fh_f_ctl, FC_FC_FIRST_SEQ |
- FC_FC_END_SEQ | FC_FC_SEQ_INIT);
+ hton24(fh->fh_f_ctl, FC_FCTL_REQ);
fh->fh_cs_ctl = 0;
fh->fh_df_ctl = 0;
fh->fh_parm_offset = 0;
@@ -1761,8 +1748,7 @@ static int fc_lport_ct_request(struct fc_bsg_job *job,
hton24(fh->fh_d_id, did);
hton24(fh->fh_s_id, lport->port_id);
fh->fh_type = FC_TYPE_CT;
- hton24(fh->fh_f_ctl, FC_FC_FIRST_SEQ |
- FC_FC_END_SEQ | FC_FC_SEQ_INIT);
+ hton24(fh->fh_f_ctl, FC_FCTL_REQ);
fh->fh_cs_ctl = 0;
fh->fh_df_ctl = 0;
fh->fh_parm_offset = 0;
diff --git a/drivers/scsi/libfc/fc_rport.c b/drivers/scsi/libfc/fc_rport.c
index 39e440f0f54..b9f2286fe0c 100644
--- a/drivers/scsi/libfc/fc_rport.c
+++ b/drivers/scsi/libfc/fc_rport.c
@@ -34,7 +34,7 @@
* The rport should never hold the rport mutex and then attempt to acquire
* either the lport or disc mutexes. The rport's mutex is considered lesser
* than both the lport's mutex and the disc mutex. Refer to fc_lport.c for
- * more comments on the heirarchy.
+ * more comments on the hierarchy.
*
* The locking strategy is similar to the lport's strategy. The lock protects
* the rport's states and is held and released by the entry points to the rport
@@ -60,6 +60,7 @@
struct workqueue_struct *rport_event_queue;
+static void fc_rport_enter_flogi(struct fc_rport_priv *);
static void fc_rport_enter_plogi(struct fc_rport_priv *);
static void fc_rport_enter_prli(struct fc_rport_priv *);
static void fc_rport_enter_rtv(struct fc_rport_priv *);
@@ -67,14 +68,10 @@ static void fc_rport_enter_ready(struct fc_rport_priv *);
static void fc_rport_enter_logo(struct fc_rport_priv *);
static void fc_rport_enter_adisc(struct fc_rport_priv *);
-static void fc_rport_recv_plogi_req(struct fc_lport *,
- struct fc_seq *, struct fc_frame *);
-static void fc_rport_recv_prli_req(struct fc_rport_priv *,
- struct fc_seq *, struct fc_frame *);
-static void fc_rport_recv_prlo_req(struct fc_rport_priv *,
- struct fc_seq *, struct fc_frame *);
-static void fc_rport_recv_logo_req(struct fc_lport *,
- struct fc_seq *, struct fc_frame *);
+static void fc_rport_recv_plogi_req(struct fc_lport *, struct fc_frame *);
+static void fc_rport_recv_prli_req(struct fc_rport_priv *, struct fc_frame *);
+static void fc_rport_recv_prlo_req(struct fc_rport_priv *, struct fc_frame *);
+static void fc_rport_recv_logo_req(struct fc_lport *, struct fc_frame *);
static void fc_rport_timeout(struct work_struct *);
static void fc_rport_error(struct fc_rport_priv *, struct fc_frame *);
static void fc_rport_error_retry(struct fc_rport_priv *, struct fc_frame *);
@@ -82,27 +79,29 @@ static void fc_rport_work(struct work_struct *);
static const char *fc_rport_state_names[] = {
[RPORT_ST_INIT] = "Init",
+ [RPORT_ST_FLOGI] = "FLOGI",
+ [RPORT_ST_PLOGI_WAIT] = "PLOGI_WAIT",
[RPORT_ST_PLOGI] = "PLOGI",
[RPORT_ST_PRLI] = "PRLI",
[RPORT_ST_RTV] = "RTV",
[RPORT_ST_READY] = "Ready",
- [RPORT_ST_LOGO] = "LOGO",
[RPORT_ST_ADISC] = "ADISC",
[RPORT_ST_DELETE] = "Delete",
- [RPORT_ST_RESTART] = "Restart",
};
/**
* fc_rport_lookup() - Lookup a remote port by port_id
* @lport: The local port to lookup the remote port on
* @port_id: The remote port ID to look up
+ *
+ * The caller must hold either disc_mutex or rcu_read_lock().
*/
static struct fc_rport_priv *fc_rport_lookup(const struct fc_lport *lport,
u32 port_id)
{
struct fc_rport_priv *rdata;
- list_for_each_entry(rdata, &lport->disc.rports, peers)
+ list_for_each_entry_rcu(rdata, &lport->disc.rports, peers)
if (rdata->ids.port_id == port_id)
return rdata;
return NULL;
@@ -126,7 +125,7 @@ static struct fc_rport_priv *fc_rport_create(struct fc_lport *lport,
if (rdata)
return rdata;
- rdata = kzalloc(sizeof(*rdata), GFP_KERNEL);
+ rdata = kzalloc(sizeof(*rdata) + lport->rport_priv_size, GFP_KERNEL);
if (!rdata)
return NULL;
@@ -147,11 +146,23 @@ static struct fc_rport_priv *fc_rport_create(struct fc_lport *lport,
INIT_DELAYED_WORK(&rdata->retry_work, fc_rport_timeout);
INIT_WORK(&rdata->event_work, fc_rport_work);
if (port_id != FC_FID_DIR_SERV)
- list_add(&rdata->peers, &lport->disc.rports);
+ list_add_rcu(&rdata->peers, &lport->disc.rports);
return rdata;
}
/**
+ * fc_rport_free_rcu() - Free a remote port
+ * @rcu: The rcu_head structure inside the remote port
+ */
+static void fc_rport_free_rcu(struct rcu_head *rcu)
+{
+ struct fc_rport_priv *rdata;
+
+ rdata = container_of(rcu, struct fc_rport_priv, rcu);
+ kfree(rdata);
+}
+
+/**
* fc_rport_destroy() - Free a remote port after last reference is released
* @kref: The remote port's kref
*/
@@ -160,7 +171,7 @@ static void fc_rport_destroy(struct kref *kref)
struct fc_rport_priv *rdata;
rdata = container_of(kref, struct fc_rport_priv, kref);
- kfree(rdata);
+ call_rcu(&rdata->rcu, fc_rport_free_rcu);
}
/**
@@ -194,7 +205,7 @@ EXPORT_SYMBOL(fc_set_rport_loss_tmo);
/**
* fc_plogi_get_maxframe() - Get the maximum payload from the common service
* parameters in a FLOGI frame
- * @flp: The FLOGI payload
+ * @flp: The FLOGI or PLOGI payload
* @maxval: The maximum frame size upper limit; this may be less than what
* is in the service parameters
*/
@@ -246,7 +257,6 @@ static void fc_rport_work(struct work_struct *work)
struct fc_rport_operations *rport_ops;
struct fc_rport_identifiers ids;
struct fc_rport *rport;
- int restart = 0;
mutex_lock(&rdata->rp_mutex);
event = rdata->event;
@@ -259,6 +269,7 @@ static void fc_rport_work(struct work_struct *work)
case RPORT_EV_READY:
ids = rdata->ids;
rdata->event = RPORT_EV_NONE;
+ rdata->major_retries = 0;
kref_get(&rdata->kref);
mutex_unlock(&rdata->rp_mutex);
@@ -298,24 +309,6 @@ static void fc_rport_work(struct work_struct *work)
port_id = rdata->ids.port_id;
mutex_unlock(&rdata->rp_mutex);
- if (port_id != FC_FID_DIR_SERV) {
- /*
- * We must drop rp_mutex before taking disc_mutex.
- * Re-evaluate state to allow for restart.
- * A transition to RESTART state must only happen
- * while disc_mutex is held and rdata is on the list.
- */
- mutex_lock(&lport->disc.disc_mutex);
- mutex_lock(&rdata->rp_mutex);
- if (rdata->rp_state == RPORT_ST_RESTART)
- restart = 1;
- else
- list_del(&rdata->peers);
- rdata->event = RPORT_EV_NONE;
- mutex_unlock(&rdata->rp_mutex);
- mutex_unlock(&lport->disc.disc_mutex);
- }
-
if (rport_ops && rport_ops->event_callback) {
FC_RPORT_DBG(rdata, "callback ev %d\n", event);
rport_ops->event_callback(lport, rdata, event);
@@ -336,13 +329,37 @@ static void fc_rport_work(struct work_struct *work)
mutex_unlock(&rdata->rp_mutex);
fc_remote_port_delete(rport);
}
- if (restart) {
- mutex_lock(&rdata->rp_mutex);
- FC_RPORT_DBG(rdata, "work restart\n");
- fc_rport_enter_plogi(rdata);
+
+ mutex_lock(&lport->disc.disc_mutex);
+ mutex_lock(&rdata->rp_mutex);
+ if (rdata->rp_state == RPORT_ST_DELETE) {
+ if (port_id == FC_FID_DIR_SERV) {
+ rdata->event = RPORT_EV_NONE;
+ mutex_unlock(&rdata->rp_mutex);
+ } else if ((rdata->flags & FC_RP_STARTED) &&
+ rdata->major_retries <
+ lport->max_rport_retry_count) {
+ rdata->major_retries++;
+ rdata->event = RPORT_EV_NONE;
+ FC_RPORT_DBG(rdata, "work restart\n");
+ fc_rport_enter_flogi(rdata);
+ mutex_unlock(&rdata->rp_mutex);
+ } else {
+ FC_RPORT_DBG(rdata, "work delete\n");
+ list_del_rcu(&rdata->peers);
+ mutex_unlock(&rdata->rp_mutex);
+ kref_put(&rdata->kref, lport->tt.rport_destroy);
+ }
+ } else {
+ /*
+ * Re-open for events. Reissue READY event if ready.
+ */
+ rdata->event = RPORT_EV_NONE;
+ if (rdata->rp_state == RPORT_ST_READY)
+ fc_rport_enter_ready(rdata);
mutex_unlock(&rdata->rp_mutex);
- } else
- kref_put(&rdata->kref, lport->tt.rport_destroy);
+ }
+ mutex_unlock(&lport->disc.disc_mutex);
break;
default:
@@ -367,20 +384,18 @@ int fc_rport_login(struct fc_rport_priv *rdata)
{
mutex_lock(&rdata->rp_mutex);
+ rdata->flags |= FC_RP_STARTED;
switch (rdata->rp_state) {
case RPORT_ST_READY:
FC_RPORT_DBG(rdata, "ADISC port\n");
fc_rport_enter_adisc(rdata);
break;
- case RPORT_ST_RESTART:
- break;
case RPORT_ST_DELETE:
FC_RPORT_DBG(rdata, "Restart deleted port\n");
- fc_rport_state_enter(rdata, RPORT_ST_RESTART);
break;
default:
FC_RPORT_DBG(rdata, "Login to port\n");
- fc_rport_enter_plogi(rdata);
+ fc_rport_enter_flogi(rdata);
break;
}
mutex_unlock(&rdata->rp_mutex);
@@ -431,15 +446,12 @@ int fc_rport_logoff(struct fc_rport_priv *rdata)
FC_RPORT_DBG(rdata, "Remove port\n");
+ rdata->flags &= ~FC_RP_STARTED;
if (rdata->rp_state == RPORT_ST_DELETE) {
FC_RPORT_DBG(rdata, "Port in Delete state, not removing\n");
goto out;
}
-
- if (rdata->rp_state == RPORT_ST_RESTART)
- FC_RPORT_DBG(rdata, "Port in Restart state, deleting\n");
- else
- fc_rport_enter_logo(rdata);
+ fc_rport_enter_logo(rdata);
/*
* Change the state to Delete so that we discard
@@ -485,6 +497,9 @@ static void fc_rport_timeout(struct work_struct *work)
mutex_lock(&rdata->rp_mutex);
switch (rdata->rp_state) {
+ case RPORT_ST_FLOGI:
+ fc_rport_enter_flogi(rdata);
+ break;
case RPORT_ST_PLOGI:
fc_rport_enter_plogi(rdata);
break;
@@ -494,16 +509,13 @@ static void fc_rport_timeout(struct work_struct *work)
case RPORT_ST_RTV:
fc_rport_enter_rtv(rdata);
break;
- case RPORT_ST_LOGO:
- fc_rport_enter_logo(rdata);
- break;
case RPORT_ST_ADISC:
fc_rport_enter_adisc(rdata);
break;
+ case RPORT_ST_PLOGI_WAIT:
case RPORT_ST_READY:
case RPORT_ST_INIT:
case RPORT_ST_DELETE:
- case RPORT_ST_RESTART:
break;
}
@@ -525,8 +537,9 @@ static void fc_rport_error(struct fc_rport_priv *rdata, struct fc_frame *fp)
fc_rport_state(rdata), rdata->retries);
switch (rdata->rp_state) {
+ case RPORT_ST_FLOGI:
case RPORT_ST_PLOGI:
- case RPORT_ST_LOGO:
+ rdata->flags &= ~FC_RP_STARTED;
fc_rport_enter_delete(rdata, RPORT_EV_FAILED);
break;
case RPORT_ST_RTV:
@@ -536,8 +549,8 @@ static void fc_rport_error(struct fc_rport_priv *rdata, struct fc_frame *fp)
case RPORT_ST_ADISC:
fc_rport_enter_logo(rdata);
break;
+ case RPORT_ST_PLOGI_WAIT:
case RPORT_ST_DELETE:
- case RPORT_ST_RESTART:
case RPORT_ST_READY:
case RPORT_ST_INIT:
break;
@@ -579,7 +592,250 @@ static void fc_rport_error_retry(struct fc_rport_priv *rdata,
}
/**
- * fc_rport_plogi_recv_resp() - Handler for ELS PLOGI responses
+ * fc_rport_login_complete() - Handle parameters and completion of p-mp login.
+ * @rdata: The remote port which we logged into or which logged into us.
+ * @fp: The FLOGI or PLOGI request or response frame
+ *
+ * Returns non-zero error if a problem is detected with the frame.
+ * Does not free the frame.
+ *
+ * This is only used in point-to-multipoint mode for FIP currently.
+ */
+static int fc_rport_login_complete(struct fc_rport_priv *rdata,
+ struct fc_frame *fp)
+{
+ struct fc_lport *lport = rdata->local_port;
+ struct fc_els_flogi *flogi;
+ unsigned int e_d_tov;
+ u16 csp_flags;
+
+ flogi = fc_frame_payload_get(fp, sizeof(*flogi));
+ if (!flogi)
+ return -EINVAL;
+
+ csp_flags = ntohs(flogi->fl_csp.sp_features);
+
+ if (fc_frame_payload_op(fp) == ELS_FLOGI) {
+ if (csp_flags & FC_SP_FT_FPORT) {
+ FC_RPORT_DBG(rdata, "Fabric bit set in FLOGI\n");
+ return -EINVAL;
+ }
+ } else {
+
+ /*
+ * E_D_TOV is not valid on an incoming FLOGI request.
+ */
+ e_d_tov = ntohl(flogi->fl_csp.sp_e_d_tov);
+ if (csp_flags & FC_SP_FT_EDTR)
+ e_d_tov /= 1000000;
+ if (e_d_tov > rdata->e_d_tov)
+ rdata->e_d_tov = e_d_tov;
+ }
+ rdata->maxframe_size = fc_plogi_get_maxframe(flogi, lport->mfs);
+ return 0;
+}
+
+/**
+ * fc_rport_flogi_resp() - Handle response to FLOGI request for p-mp mode
+ * @sp: The sequence that the FLOGI was on
+ * @fp: The FLOGI response frame
+ * @rp_arg: The remote port that received the FLOGI response
+ */
+void fc_rport_flogi_resp(struct fc_seq *sp, struct fc_frame *fp,
+ void *rp_arg)
+{
+ struct fc_rport_priv *rdata = rp_arg;
+ struct fc_lport *lport = rdata->local_port;
+ struct fc_els_flogi *flogi;
+ unsigned int r_a_tov;
+
+ FC_RPORT_DBG(rdata, "Received a FLOGI %s\n", fc_els_resp_type(fp));
+
+ if (fp == ERR_PTR(-FC_EX_CLOSED))
+ return;
+
+ mutex_lock(&rdata->rp_mutex);
+
+ if (rdata->rp_state != RPORT_ST_FLOGI) {
+ FC_RPORT_DBG(rdata, "Received a FLOGI response, but in state "
+ "%s\n", fc_rport_state(rdata));
+ if (IS_ERR(fp))
+ goto err;
+ goto out;
+ }
+
+ if (IS_ERR(fp)) {
+ fc_rport_error(rdata, fp);
+ goto err;
+ }
+
+ if (fc_frame_payload_op(fp) != ELS_LS_ACC)
+ goto bad;
+ if (fc_rport_login_complete(rdata, fp))
+ goto bad;
+
+ flogi = fc_frame_payload_get(fp, sizeof(*flogi));
+ if (!flogi)
+ goto bad;
+ r_a_tov = ntohl(flogi->fl_csp.sp_r_a_tov);
+ if (r_a_tov > rdata->r_a_tov)
+ rdata->r_a_tov = r_a_tov;
+
+ if (rdata->ids.port_name < lport->wwpn)
+ fc_rport_enter_plogi(rdata);
+ else
+ fc_rport_state_enter(rdata, RPORT_ST_PLOGI_WAIT);
+out:
+ fc_frame_free(fp);
+err:
+ mutex_unlock(&rdata->rp_mutex);
+ kref_put(&rdata->kref, rdata->local_port->tt.rport_destroy);
+ return;
+bad:
+ FC_RPORT_DBG(rdata, "Bad FLOGI response\n");
+ fc_rport_error_retry(rdata, fp);
+ goto out;
+}
+
+/**
+ * fc_rport_enter_flogi() - Send a FLOGI request to the remote port for p-mp
+ * @rdata: The remote port to send a FLOGI to
+ *
+ * Locking Note: The rport lock is expected to be held before calling
+ * this routine.
+ */
+static void fc_rport_enter_flogi(struct fc_rport_priv *rdata)
+{
+ struct fc_lport *lport = rdata->local_port;
+ struct fc_frame *fp;
+
+ if (!lport->point_to_multipoint)
+ return fc_rport_enter_plogi(rdata);
+
+ FC_RPORT_DBG(rdata, "Entered FLOGI state from %s state\n",
+ fc_rport_state(rdata));
+
+ fc_rport_state_enter(rdata, RPORT_ST_FLOGI);
+
+ fp = fc_frame_alloc(lport, sizeof(struct fc_els_flogi));
+ if (!fp)
+ return fc_rport_error_retry(rdata, fp);
+
+ if (!lport->tt.elsct_send(lport, rdata->ids.port_id, fp, ELS_FLOGI,
+ fc_rport_flogi_resp, rdata,
+ 2 * lport->r_a_tov))
+ fc_rport_error_retry(rdata, NULL);
+ else
+ kref_get(&rdata->kref);
+}
+
+/**
+ * fc_rport_recv_flogi_req() - Handle Fabric Login (FLOGI) request in p-mp mode
+ * @lport: The local port that received the PLOGI request
+ * @rx_fp: The PLOGI request frame
+ */
+static void fc_rport_recv_flogi_req(struct fc_lport *lport,
+ struct fc_frame *rx_fp)
+{
+ struct fc_disc *disc;
+ struct fc_els_flogi *flp;
+ struct fc_rport_priv *rdata;
+ struct fc_frame *fp = rx_fp;
+ struct fc_seq_els_data rjt_data;
+ u32 sid;
+
+ sid = fc_frame_sid(fp);
+
+ FC_RPORT_ID_DBG(lport, sid, "Received FLOGI request\n");
+
+ disc = &lport->disc;
+ mutex_lock(&disc->disc_mutex);
+
+ if (!lport->point_to_multipoint) {
+ rjt_data.reason = ELS_RJT_UNSUP;
+ rjt_data.explan = ELS_EXPL_NONE;
+ goto reject;
+ }
+
+ flp = fc_frame_payload_get(fp, sizeof(*flp));
+ if (!flp) {
+ rjt_data.reason = ELS_RJT_LOGIC;
+ rjt_data.explan = ELS_EXPL_INV_LEN;
+ goto reject;
+ }
+
+ rdata = lport->tt.rport_lookup(lport, sid);
+ if (!rdata) {
+ rjt_data.reason = ELS_RJT_FIP;
+ rjt_data.explan = ELS_EXPL_NOT_NEIGHBOR;
+ goto reject;
+ }
+ mutex_lock(&rdata->rp_mutex);
+
+ FC_RPORT_DBG(rdata, "Received FLOGI in %s state\n",
+ fc_rport_state(rdata));
+
+ switch (rdata->rp_state) {
+ case RPORT_ST_INIT:
+ case RPORT_ST_DELETE:
+ mutex_unlock(&rdata->rp_mutex);
+ rjt_data.reason = ELS_RJT_FIP;
+ rjt_data.explan = ELS_EXPL_NOT_NEIGHBOR;
+ goto reject;
+ case RPORT_ST_FLOGI:
+ case RPORT_ST_PLOGI_WAIT:
+ case RPORT_ST_PLOGI:
+ break;
+ case RPORT_ST_PRLI:
+ case RPORT_ST_RTV:
+ case RPORT_ST_READY:
+ case RPORT_ST_ADISC:
+ /*
+ * Set the remote port to be deleted and to then restart.
+ * This queues work to be sure exchanges are reset.
+ */
+ fc_rport_enter_delete(rdata, RPORT_EV_LOGO);
+ mutex_unlock(&rdata->rp_mutex);
+ rjt_data.reason = ELS_RJT_BUSY;
+ rjt_data.explan = ELS_EXPL_NONE;
+ goto reject;
+ }
+ if (fc_rport_login_complete(rdata, fp)) {
+ mutex_unlock(&rdata->rp_mutex);
+ rjt_data.reason = ELS_RJT_LOGIC;
+ rjt_data.explan = ELS_EXPL_NONE;
+ goto reject;
+ }
+
+ fp = fc_frame_alloc(lport, sizeof(*flp));
+ if (!fp)
+ goto out;
+
+ fc_flogi_fill(lport, fp);
+ flp = fc_frame_payload_get(fp, sizeof(*flp));
+ flp->fl_cmd = ELS_LS_ACC;
+
+ fc_fill_reply_hdr(fp, rx_fp, FC_RCTL_ELS_REP, 0);
+ lport->tt.frame_send(lport, fp);
+
+ if (rdata->ids.port_name < lport->wwpn)
+ fc_rport_enter_plogi(rdata);
+ else
+ fc_rport_state_enter(rdata, RPORT_ST_PLOGI_WAIT);
+out:
+ mutex_unlock(&rdata->rp_mutex);
+ mutex_unlock(&disc->disc_mutex);
+ fc_frame_free(rx_fp);
+ return;
+
+reject:
+ mutex_unlock(&disc->disc_mutex);
+ lport->tt.seq_els_rsp_send(rx_fp, ELS_LS_RJT, &rjt_data);
+ fc_frame_free(rx_fp);
+}
+
+/**
+ * fc_rport_plogi_resp() - Handler for ELS PLOGI responses
* @sp: The sequence the PLOGI is on
* @fp: The PLOGI response frame
* @rdata_arg: The remote port that sent the PLOGI response
@@ -594,7 +850,6 @@ static void fc_rport_plogi_resp(struct fc_seq *sp, struct fc_frame *fp,
struct fc_rport_priv *rdata = rdata_arg;
struct fc_lport *lport = rdata->local_port;
struct fc_els_flogi *plp = NULL;
- unsigned int tov;
u16 csp_seq;
u16 cssp_seq;
u8 op;
@@ -622,11 +877,8 @@ static void fc_rport_plogi_resp(struct fc_seq *sp, struct fc_frame *fp,
rdata->ids.port_name = get_unaligned_be64(&plp->fl_wwpn);
rdata->ids.node_name = get_unaligned_be64(&plp->fl_wwnn);
- tov = ntohl(plp->fl_csp.sp_e_d_tov);
- if (ntohs(plp->fl_csp.sp_features) & FC_SP_FT_EDTR)
- tov /= 1000000;
- if (tov > rdata->e_d_tov)
- rdata->e_d_tov = tov;
+ if (lport->point_to_multipoint)
+ fc_rport_login_complete(rdata, fp);
csp_seq = ntohs(plp->fl_csp.sp_tot_seq);
cssp_seq = ntohs(plp->fl_cssp[3 - 1].cp_con_seq);
if (cssp_seq < csp_seq)
@@ -664,6 +916,7 @@ static void fc_rport_enter_plogi(struct fc_rport_priv *rdata)
rdata->maxframe_size = FC_MIN_MAX_PAYLOAD;
fp = fc_frame_alloc(lport, sizeof(struct fc_els_flogi));
if (!fp) {
+ FC_RPORT_DBG(rdata, "%s frame alloc failed\n", __func__);
fc_rport_error_retry(rdata, fp);
return;
}
@@ -698,6 +951,7 @@ static void fc_rport_prli_resp(struct fc_seq *sp, struct fc_frame *fp,
u32 roles = FC_RPORT_ROLE_UNKNOWN;
u32 fcp_parm = 0;
u8 op;
+ u8 resp_code = 0;
mutex_lock(&rdata->rp_mutex);
@@ -722,11 +976,25 @@ static void fc_rport_prli_resp(struct fc_seq *sp, struct fc_frame *fp,
op = fc_frame_payload_op(fp);
if (op == ELS_LS_ACC) {
pp = fc_frame_payload_get(fp, sizeof(*pp));
- if (pp && pp->prli.prli_spp_len >= sizeof(pp->spp)) {
- fcp_parm = ntohl(pp->spp.spp_params);
- if (fcp_parm & FCP_SPPF_RETRY)
- rdata->flags |= FC_RP_FLAGS_RETRY;
+ if (!pp)
+ goto out;
+
+ resp_code = (pp->spp.spp_flags & FC_SPP_RESP_MASK);
+ FC_RPORT_DBG(rdata, "PRLI spp_flags = 0x%x\n",
+ pp->spp.spp_flags);
+ if (resp_code != FC_SPP_RESP_ACK) {
+ if (resp_code == FC_SPP_RESP_CONF)
+ fc_rport_error(rdata, fp);
+ else
+ fc_rport_error_retry(rdata, fp);
+ goto out;
}
+ if (pp->prli.prli_spp_len < sizeof(pp->spp))
+ goto out;
+
+ fcp_parm = ntohl(pp->spp.spp_params);
+ if (fcp_parm & FCP_SPPF_RETRY)
+ rdata->flags |= FC_RP_FLAGS_RETRY;
rdata->supported_classes = FC_COS_CLASS3;
if (fcp_parm & FCP_SPPF_INIT_FCN)
@@ -739,55 +1007,9 @@ static void fc_rport_prli_resp(struct fc_seq *sp, struct fc_frame *fp,
} else {
FC_RPORT_DBG(rdata, "Bad ELS response for PRLI command\n");
- fc_rport_enter_delete(rdata, RPORT_EV_FAILED);
- }
-
-out:
- fc_frame_free(fp);
-err:
- mutex_unlock(&rdata->rp_mutex);
- kref_put(&rdata->kref, rdata->local_port->tt.rport_destroy);
-}
-
-/**
- * fc_rport_logo_resp() - Handler for logout (LOGO) responses
- * @sp: The sequence the LOGO was on
- * @fp: The LOGO response frame
- * @rdata_arg: The remote port that sent the LOGO response
- *
- * Locking Note: This function will be called without the rport lock
- * held, but it will lock, call an _enter_* function or fc_rport_error
- * and then unlock the rport.
- */
-static void fc_rport_logo_resp(struct fc_seq *sp, struct fc_frame *fp,
- void *rdata_arg)
-{
- struct fc_rport_priv *rdata = rdata_arg;
- u8 op;
-
- mutex_lock(&rdata->rp_mutex);
-
- FC_RPORT_DBG(rdata, "Received a LOGO %s\n", fc_els_resp_type(fp));
-
- if (rdata->rp_state != RPORT_ST_LOGO) {
- FC_RPORT_DBG(rdata, "Received a LOGO response, but in state "
- "%s\n", fc_rport_state(rdata));
- if (IS_ERR(fp))
- goto err;
- goto out;
- }
-
- if (IS_ERR(fp)) {
fc_rport_error_retry(rdata, fp);
- goto err;
}
- op = fc_frame_payload_op(fp);
- if (op != ELS_LS_ACC)
- FC_RPORT_DBG(rdata, "Bad ELS response op %x for LOGO command\n",
- op);
- fc_rport_enter_delete(rdata, RPORT_EV_LOGO);
-
out:
fc_frame_free(fp);
err:
@@ -937,6 +1159,24 @@ static void fc_rport_enter_rtv(struct fc_rport_priv *rdata)
}
/**
+ * fc_rport_logo_resp() - Handler for logout (LOGO) responses
+ * @sp: The sequence the LOGO was on
+ * @fp: The LOGO response frame
+ * @lport_arg: The local port
+ */
+static void fc_rport_logo_resp(struct fc_seq *sp, struct fc_frame *fp,
+ void *lport_arg)
+{
+ struct fc_lport *lport = lport_arg;
+
+ FC_RPORT_ID_DBG(lport, fc_seq_exch(sp)->did,
+ "Received a LOGO %s\n", fc_els_resp_type(fp));
+ if (IS_ERR(fp))
+ return;
+ fc_frame_free(fp);
+}
+
+/**
* fc_rport_enter_logo() - Send a logout (LOGO) request
* @rdata: The remote port to send the LOGO request to
*
@@ -948,23 +1188,14 @@ static void fc_rport_enter_logo(struct fc_rport_priv *rdata)
struct fc_lport *lport = rdata->local_port;
struct fc_frame *fp;
- FC_RPORT_DBG(rdata, "Port entered LOGO state from %s state\n",
+ FC_RPORT_DBG(rdata, "Port sending LOGO from %s state\n",
fc_rport_state(rdata));
- fc_rport_state_enter(rdata, RPORT_ST_LOGO);
-
fp = fc_frame_alloc(lport, sizeof(struct fc_els_logo));
- if (!fp) {
- fc_rport_error_retry(rdata, fp);
+ if (!fp)
return;
- }
-
- if (!lport->tt.elsct_send(lport, rdata->ids.port_id, fp, ELS_LOGO,
- fc_rport_logo_resp, rdata,
- 2 * lport->r_a_tov))
- fc_rport_error_retry(rdata, NULL);
- else
- kref_get(&rdata->kref);
+ (void)lport->tt.elsct_send(lport, rdata->ids.port_id, fp, ELS_LOGO,
+ fc_rport_logo_resp, lport, 0);
}
/**
@@ -1013,7 +1244,7 @@ static void fc_rport_adisc_resp(struct fc_seq *sp, struct fc_frame *fp,
get_unaligned_be64(&adisc->adisc_wwpn) != rdata->ids.port_name ||
get_unaligned_be64(&adisc->adisc_wwnn) != rdata->ids.node_name) {
FC_RPORT_DBG(rdata, "ADISC error or mismatch\n");
- fc_rport_enter_plogi(rdata);
+ fc_rport_enter_flogi(rdata);
} else {
FC_RPORT_DBG(rdata, "ADISC OK\n");
fc_rport_enter_ready(rdata);
@@ -1058,29 +1289,25 @@ static void fc_rport_enter_adisc(struct fc_rport_priv *rdata)
/**
* fc_rport_recv_adisc_req() - Handler for Address Discovery (ADISC) requests
* @rdata: The remote port that sent the ADISC request
- * @sp: The sequence the ADISC request was on
* @in_fp: The ADISC request frame
*
* Locking Note: Called with the lport and rport locks held.
*/
static void fc_rport_recv_adisc_req(struct fc_rport_priv *rdata,
- struct fc_seq *sp, struct fc_frame *in_fp)
+ struct fc_frame *in_fp)
{
struct fc_lport *lport = rdata->local_port;
struct fc_frame *fp;
- struct fc_exch *ep = fc_seq_exch(sp);
struct fc_els_adisc *adisc;
struct fc_seq_els_data rjt_data;
- u32 f_ctl;
FC_RPORT_DBG(rdata, "Received ADISC request\n");
adisc = fc_frame_payload_get(in_fp, sizeof(*adisc));
if (!adisc) {
- rjt_data.fp = NULL;
rjt_data.reason = ELS_RJT_PROT;
rjt_data.explan = ELS_EXPL_INV_LEN;
- lport->tt.seq_els_rsp_send(sp, ELS_LS_RJT, &rjt_data);
+ lport->tt.seq_els_rsp_send(in_fp, ELS_LS_RJT, &rjt_data);
goto drop;
}
@@ -1090,11 +1317,8 @@ static void fc_rport_recv_adisc_req(struct fc_rport_priv *rdata,
fc_adisc_fill(lport, fp);
adisc = fc_frame_payload_get(fp, sizeof(*adisc));
adisc->adisc_cmd = ELS_LS_ACC;
- sp = lport->tt.seq_start_next(sp);
- f_ctl = FC_FC_EX_CTX | FC_FC_LAST_SEQ | FC_FC_END_SEQ | FC_FC_SEQ_INIT;
- fc_fill_fc_hdr(fp, FC_RCTL_ELS_REP, ep->did, ep->sid,
- FC_TYPE_ELS, f_ctl, 0);
- lport->tt.seq_send(lport, sp, fp);
+ fc_fill_reply_hdr(fp, in_fp, FC_RCTL_ELS_REP, 0);
+ lport->tt.frame_send(lport, fp);
drop:
fc_frame_free(in_fp);
}
@@ -1102,25 +1326,22 @@ drop:
/**
* fc_rport_recv_rls_req() - Handle received Read Link Status request
* @rdata: The remote port that sent the RLS request
- * @sp: The sequence that the RLS was on
* @rx_fp: The PRLI request frame
*
* Locking Note: The rport lock is expected to be held before calling
* this function.
*/
static void fc_rport_recv_rls_req(struct fc_rport_priv *rdata,
- struct fc_seq *sp, struct fc_frame *rx_fp)
+ struct fc_frame *rx_fp)
{
struct fc_lport *lport = rdata->local_port;
struct fc_frame *fp;
- struct fc_exch *ep = fc_seq_exch(sp);
struct fc_els_rls *rls;
struct fc_els_rls_resp *rsp;
struct fc_els_lesb *lesb;
struct fc_seq_els_data rjt_data;
struct fc_host_statistics *hst;
- u32 f_ctl;
FC_RPORT_DBG(rdata, "Received RLS request while in state %s\n",
fc_rport_state(rdata));
@@ -1157,16 +1378,12 @@ static void fc_rport_recv_rls_req(struct fc_rport_priv *rdata,
lesb->lesb_inv_crc = htonl(hst->invalid_crc_count);
}
- sp = lport->tt.seq_start_next(sp);
- f_ctl = FC_FC_EX_CTX | FC_FC_LAST_SEQ | FC_FC_END_SEQ;
- fc_fill_fc_hdr(fp, FC_RCTL_ELS_REP, ep->did, ep->sid,
- FC_TYPE_ELS, f_ctl, 0);
- lport->tt.seq_send(lport, sp, fp);
+ fc_fill_reply_hdr(fp, rx_fp, FC_RCTL_ELS_REP, 0);
+ lport->tt.frame_send(lport, fp);
goto out;
out_rjt:
- rjt_data.fp = NULL;
- lport->tt.seq_els_rsp_send(sp, ELS_LS_RJT, &rjt_data);
+ lport->tt.seq_els_rsp_send(rx_fp, ELS_LS_RJT, &rjt_data);
out:
fc_frame_free(rx_fp);
}
@@ -1174,7 +1391,6 @@ out:
/**
* fc_rport_recv_els_req() - Handler for validated ELS requests
* @lport: The local port that received the ELS request
- * @sp: The sequence that the ELS request was on
* @fp: The ELS request frame
*
* Handle incoming ELS requests that require port login.
@@ -1182,21 +1398,13 @@ out:
*
* Locking Note: Called with the lport lock held.
*/
-static void fc_rport_recv_els_req(struct fc_lport *lport,
- struct fc_seq *sp, struct fc_frame *fp)
+static void fc_rport_recv_els_req(struct fc_lport *lport, struct fc_frame *fp)
{
struct fc_rport_priv *rdata;
- struct fc_frame_header *fh;
struct fc_seq_els_data els_data;
- els_data.fp = NULL;
- els_data.reason = ELS_RJT_UNAB;
- els_data.explan = ELS_EXPL_PLOGI_REQD;
-
- fh = fc_frame_header_get(fp);
-
mutex_lock(&lport->disc.disc_mutex);
- rdata = lport->tt.rport_lookup(lport, ntoh24(fh->fh_s_id));
+ rdata = lport->tt.rport_lookup(lport, fc_frame_sid(fp));
if (!rdata) {
mutex_unlock(&lport->disc.disc_mutex);
goto reject;
@@ -1217,24 +1425,24 @@ static void fc_rport_recv_els_req(struct fc_lport *lport,
switch (fc_frame_payload_op(fp)) {
case ELS_PRLI:
- fc_rport_recv_prli_req(rdata, sp, fp);
+ fc_rport_recv_prli_req(rdata, fp);
break;
case ELS_PRLO:
- fc_rport_recv_prlo_req(rdata, sp, fp);
+ fc_rport_recv_prlo_req(rdata, fp);
break;
case ELS_ADISC:
- fc_rport_recv_adisc_req(rdata, sp, fp);
+ fc_rport_recv_adisc_req(rdata, fp);
break;
case ELS_RRQ:
- els_data.fp = fp;
- lport->tt.seq_els_rsp_send(sp, ELS_RRQ, &els_data);
+ lport->tt.seq_els_rsp_send(fp, ELS_RRQ, NULL);
+ fc_frame_free(fp);
break;
case ELS_REC:
- els_data.fp = fp;
- lport->tt.seq_els_rsp_send(sp, ELS_REC, &els_data);
+ lport->tt.seq_els_rsp_send(fp, ELS_REC, NULL);
+ fc_frame_free(fp);
break;
case ELS_RLS:
- fc_rport_recv_rls_req(rdata, sp, fp);
+ fc_rport_recv_rls_req(rdata, fp);
break;
default:
fc_frame_free(fp); /* can't happen */
@@ -1245,35 +1453,38 @@ static void fc_rport_recv_els_req(struct fc_lport *lport,
return;
reject:
- lport->tt.seq_els_rsp_send(sp, ELS_LS_RJT, &els_data);
+ els_data.reason = ELS_RJT_UNAB;
+ els_data.explan = ELS_EXPL_PLOGI_REQD;
+ lport->tt.seq_els_rsp_send(fp, ELS_LS_RJT, &els_data);
fc_frame_free(fp);
}
/**
* fc_rport_recv_req() - Handler for requests
- * @sp: The sequence the request was on
- * @fp: The request frame
* @lport: The local port that received the request
+ * @fp: The request frame
*
* Locking Note: Called with the lport lock held.
*/
-void fc_rport_recv_req(struct fc_seq *sp, struct fc_frame *fp,
- struct fc_lport *lport)
+void fc_rport_recv_req(struct fc_lport *lport, struct fc_frame *fp)
{
struct fc_seq_els_data els_data;
/*
- * Handle PLOGI and LOGO requests separately, since they
+ * Handle FLOGI, PLOGI and LOGO requests separately, since they
* don't require prior login.
* Check for unsupported opcodes first and reject them.
* For some ops, it would be incorrect to reject with "PLOGI required".
*/
switch (fc_frame_payload_op(fp)) {
+ case ELS_FLOGI:
+ fc_rport_recv_flogi_req(lport, fp);
+ break;
case ELS_PLOGI:
- fc_rport_recv_plogi_req(lport, sp, fp);
+ fc_rport_recv_plogi_req(lport, fp);
break;
case ELS_LOGO:
- fc_rport_recv_logo_req(lport, sp, fp);
+ fc_rport_recv_logo_req(lport, fp);
break;
case ELS_PRLI:
case ELS_PRLO:
@@ -1281,14 +1492,13 @@ void fc_rport_recv_req(struct fc_seq *sp, struct fc_frame *fp,
case ELS_RRQ:
case ELS_REC:
case ELS_RLS:
- fc_rport_recv_els_req(lport, sp, fp);
+ fc_rport_recv_els_req(lport, fp);
break;
default:
- fc_frame_free(fp);
- els_data.fp = NULL;
els_data.reason = ELS_RJT_UNSUP;
els_data.explan = ELS_EXPL_NONE;
- lport->tt.seq_els_rsp_send(sp, ELS_LS_RJT, &els_data);
+ lport->tt.seq_els_rsp_send(fp, ELS_LS_RJT, &els_data);
+ fc_frame_free(fp);
break;
}
}
@@ -1296,26 +1506,21 @@ void fc_rport_recv_req(struct fc_seq *sp, struct fc_frame *fp,
/**
* fc_rport_recv_plogi_req() - Handler for Port Login (PLOGI) requests
* @lport: The local port that received the PLOGI request
- * @sp: The sequence that the PLOGI request was on
* @rx_fp: The PLOGI request frame
*
* Locking Note: The rport lock is held before calling this function.
*/
static void fc_rport_recv_plogi_req(struct fc_lport *lport,
- struct fc_seq *sp, struct fc_frame *rx_fp)
+ struct fc_frame *rx_fp)
{
struct fc_disc *disc;
struct fc_rport_priv *rdata;
struct fc_frame *fp = rx_fp;
- struct fc_exch *ep;
- struct fc_frame_header *fh;
struct fc_els_flogi *pl;
struct fc_seq_els_data rjt_data;
- u32 sid, f_ctl;
+ u32 sid;
- rjt_data.fp = NULL;
- fh = fc_frame_header_get(fp);
- sid = ntoh24(fh->fh_s_id);
+ sid = fc_frame_sid(fp);
FC_RPORT_ID_DBG(lport, sid, "Received PLOGI request\n");
@@ -1358,6 +1563,9 @@ static void fc_rport_recv_plogi_req(struct fc_lport *lport,
case RPORT_ST_INIT:
FC_RPORT_DBG(rdata, "Received PLOGI in INIT state\n");
break;
+ case RPORT_ST_PLOGI_WAIT:
+ FC_RPORT_DBG(rdata, "Received PLOGI in PLOGI_WAIT state\n");
+ break;
case RPORT_ST_PLOGI:
FC_RPORT_DBG(rdata, "Received PLOGI in PLOGI state\n");
if (rdata->ids.port_name < lport->wwpn) {
@@ -1375,9 +1583,8 @@ static void fc_rport_recv_plogi_req(struct fc_lport *lport,
"- ignored for now\n", rdata->rp_state);
/* XXX TBD - should reset */
break;
+ case RPORT_ST_FLOGI:
case RPORT_ST_DELETE:
- case RPORT_ST_LOGO:
- case RPORT_ST_RESTART:
FC_RPORT_DBG(rdata, "Received PLOGI in state %s - send busy\n",
fc_rport_state(rdata));
mutex_unlock(&rdata->rp_mutex);
@@ -1390,50 +1597,41 @@ static void fc_rport_recv_plogi_req(struct fc_lport *lport,
* Get session payload size from incoming PLOGI.
*/
rdata->maxframe_size = fc_plogi_get_maxframe(pl, lport->mfs);
- fc_frame_free(rx_fp);
/*
* Send LS_ACC. If this fails, the originator should retry.
*/
- sp = lport->tt.seq_start_next(sp);
- if (!sp)
- goto out;
fp = fc_frame_alloc(lport, sizeof(*pl));
if (!fp)
goto out;
fc_plogi_fill(lport, fp, ELS_LS_ACC);
- f_ctl = FC_FC_EX_CTX | FC_FC_LAST_SEQ | FC_FC_END_SEQ | FC_FC_SEQ_INIT;
- ep = fc_seq_exch(sp);
- fc_fill_fc_hdr(fp, FC_RCTL_ELS_REP, ep->did, ep->sid,
- FC_TYPE_ELS, f_ctl, 0);
- lport->tt.seq_send(lport, sp, fp);
+ fc_fill_reply_hdr(fp, rx_fp, FC_RCTL_ELS_REP, 0);
+ lport->tt.frame_send(lport, fp);
fc_rport_enter_prli(rdata);
out:
mutex_unlock(&rdata->rp_mutex);
+ fc_frame_free(rx_fp);
return;
reject:
- lport->tt.seq_els_rsp_send(sp, ELS_LS_RJT, &rjt_data);
+ lport->tt.seq_els_rsp_send(fp, ELS_LS_RJT, &rjt_data);
fc_frame_free(fp);
}
/**
* fc_rport_recv_prli_req() - Handler for process login (PRLI) requests
* @rdata: The remote port that sent the PRLI request
- * @sp: The sequence that the PRLI was on
* @rx_fp: The PRLI request frame
*
* Locking Note: The rport lock is exected to be held before calling
* this function.
*/
static void fc_rport_recv_prli_req(struct fc_rport_priv *rdata,
- struct fc_seq *sp, struct fc_frame *rx_fp)
+ struct fc_frame *rx_fp)
{
struct fc_lport *lport = rdata->local_port;
- struct fc_exch *ep;
struct fc_frame *fp;
- struct fc_frame_header *fh;
struct {
struct fc_els_prli prli;
struct fc_els_spp spp;
@@ -1444,17 +1642,13 @@ static void fc_rport_recv_prli_req(struct fc_rport_priv *rdata,
unsigned int plen;
enum fc_els_spp_resp resp;
struct fc_seq_els_data rjt_data;
- u32 f_ctl;
u32 fcp_parm;
u32 roles = FC_RPORT_ROLE_UNKNOWN;
- rjt_data.fp = NULL;
- fh = fc_frame_header_get(rx_fp);
-
FC_RPORT_DBG(rdata, "Received PRLI request while in state %s\n",
fc_rport_state(rdata));
- len = fr_len(rx_fp) - sizeof(*fh);
+ len = fr_len(rx_fp) - sizeof(struct fc_frame_header);
pp = fc_frame_payload_get(rx_fp, sizeof(*pp));
if (!pp)
goto reject_len;
@@ -1475,8 +1669,6 @@ static void fc_rport_recv_prli_req(struct fc_rport_priv *rdata,
rjt_data.explan = ELS_EXPL_INSUF_RES;
goto reject;
}
- sp = lport->tt.seq_start_next(sp);
- WARN_ON(!sp);
pp = fc_frame_payload_get(fp, len);
WARN_ON(!pp);
memset(pp, 0, len);
@@ -1529,12 +1721,8 @@ static void fc_rport_recv_prli_req(struct fc_rport_priv *rdata,
/*
* Send LS_ACC. If this fails, the originator should retry.
*/
- f_ctl = FC_FC_EX_CTX | FC_FC_LAST_SEQ;
- f_ctl |= FC_FC_END_SEQ | FC_FC_SEQ_INIT;
- ep = fc_seq_exch(sp);
- fc_fill_fc_hdr(fp, FC_RCTL_ELS_REP, ep->did, ep->sid,
- FC_TYPE_ELS, f_ctl, 0);
- lport->tt.seq_send(lport, sp, fp);
+ fc_fill_reply_hdr(fp, rx_fp, FC_RCTL_ELS_REP, 0);
+ lport->tt.frame_send(lport, fp);
switch (rdata->rp_state) {
case RPORT_ST_PRLI:
@@ -1549,7 +1737,7 @@ reject_len:
rjt_data.reason = ELS_RJT_PROT;
rjt_data.explan = ELS_EXPL_INV_LEN;
reject:
- lport->tt.seq_els_rsp_send(sp, ELS_LS_RJT, &rjt_data);
+ lport->tt.seq_els_rsp_send(rx_fp, ELS_LS_RJT, &rjt_data);
drop:
fc_frame_free(rx_fp);
}
@@ -1557,54 +1745,90 @@ drop:
/**
* fc_rport_recv_prlo_req() - Handler for process logout (PRLO) requests
* @rdata: The remote port that sent the PRLO request
- * @sp: The sequence that the PRLO was on
- * @fp: The PRLO request frame
+ * @rx_fp: The PRLO request frame
*
* Locking Note: The rport lock is exected to be held before calling
* this function.
*/
static void fc_rport_recv_prlo_req(struct fc_rport_priv *rdata,
- struct fc_seq *sp,
- struct fc_frame *fp)
+ struct fc_frame *rx_fp)
{
struct fc_lport *lport = rdata->local_port;
-
- struct fc_frame_header *fh;
+ struct fc_frame *fp;
+ struct {
+ struct fc_els_prlo prlo;
+ struct fc_els_spp spp;
+ } *pp;
+ struct fc_els_spp *rspp; /* request service param page */
+ struct fc_els_spp *spp; /* response spp */
+ unsigned int len;
+ unsigned int plen;
struct fc_seq_els_data rjt_data;
- fh = fc_frame_header_get(fp);
-
FC_RPORT_DBG(rdata, "Received PRLO request while in state %s\n",
fc_rport_state(rdata));
- rjt_data.fp = NULL;
- rjt_data.reason = ELS_RJT_UNAB;
- rjt_data.explan = ELS_EXPL_NONE;
- lport->tt.seq_els_rsp_send(sp, ELS_LS_RJT, &rjt_data);
- fc_frame_free(fp);
+ len = fr_len(rx_fp) - sizeof(struct fc_frame_header);
+ pp = fc_frame_payload_get(rx_fp, sizeof(*pp));
+ if (!pp)
+ goto reject_len;
+ plen = ntohs(pp->prlo.prlo_len);
+ if (plen != 20)
+ goto reject_len;
+ if (plen < len)
+ len = plen;
+
+ rspp = &pp->spp;
+
+ fp = fc_frame_alloc(lport, len);
+ if (!fp) {
+ rjt_data.reason = ELS_RJT_UNAB;
+ rjt_data.explan = ELS_EXPL_INSUF_RES;
+ goto reject;
+ }
+
+ pp = fc_frame_payload_get(fp, len);
+ WARN_ON(!pp);
+ memset(pp, 0, len);
+ pp->prlo.prlo_cmd = ELS_LS_ACC;
+ pp->prlo.prlo_obs = 0x10;
+ pp->prlo.prlo_len = htons(len);
+ spp = &pp->spp;
+ spp->spp_type = rspp->spp_type;
+ spp->spp_type_ext = rspp->spp_type_ext;
+ spp->spp_flags = FC_SPP_RESP_ACK;
+
+ fc_rport_enter_delete(rdata, RPORT_EV_LOGO);
+
+ fc_fill_reply_hdr(fp, rx_fp, FC_RCTL_ELS_REP, 0);
+ lport->tt.frame_send(lport, fp);
+ goto drop;
+
+reject_len:
+ rjt_data.reason = ELS_RJT_PROT;
+ rjt_data.explan = ELS_EXPL_INV_LEN;
+reject:
+ lport->tt.seq_els_rsp_send(rx_fp, ELS_LS_RJT, &rjt_data);
+drop:
+ fc_frame_free(rx_fp);
}
/**
* fc_rport_recv_logo_req() - Handler for logout (LOGO) requests
* @lport: The local port that received the LOGO request
- * @sp: The sequence that the LOGO request was on
* @fp: The LOGO request frame
*
* Locking Note: The rport lock is exected to be held before calling
* this function.
*/
-static void fc_rport_recv_logo_req(struct fc_lport *lport,
- struct fc_seq *sp,
- struct fc_frame *fp)
+static void fc_rport_recv_logo_req(struct fc_lport *lport, struct fc_frame *fp)
{
- struct fc_frame_header *fh;
struct fc_rport_priv *rdata;
u32 sid;
- lport->tt.seq_els_rsp_send(sp, ELS_LS_ACC, NULL);
+ lport->tt.seq_els_rsp_send(fp, ELS_LS_ACC, NULL);
- fh = fc_frame_header_get(fp);
- sid = ntoh24(fh->fh_s_id);
+ sid = fc_frame_sid(fp);
mutex_lock(&lport->disc.disc_mutex);
rdata = lport->tt.rport_lookup(lport, sid);
@@ -1614,13 +1838,6 @@ static void fc_rport_recv_logo_req(struct fc_lport *lport,
fc_rport_state(rdata));
fc_rport_enter_delete(rdata, RPORT_EV_LOGO);
-
- /*
- * If the remote port was created due to discovery, set state
- * to log back in. It may have seen a stale RSCN about us.
- */
- if (rdata->disc_id)
- fc_rport_state_enter(rdata, RPORT_ST_RESTART);
mutex_unlock(&rdata->rp_mutex);
} else
FC_RPORT_ID_DBG(lport, sid,
diff --git a/drivers/scsi/libsas/sas_ata.c b/drivers/scsi/libsas/sas_ata.c
index 8c496b56556..042153cbbde 100644
--- a/drivers/scsi/libsas/sas_ata.c
+++ b/drivers/scsi/libsas/sas_ata.c
@@ -71,7 +71,7 @@ static enum ata_completion_errors sas_to_ata_err(struct task_status_struct *ts)
case SAS_SG_ERR:
return AC_ERR_INVALID;
- case SAM_CHECK_COND:
+ case SAM_STAT_CHECK_CONDITION:
case SAS_OPEN_TO:
case SAS_OPEN_REJECT:
SAS_DPRINTK("%s: Saw error %d. What to do?\n",
@@ -107,7 +107,7 @@ static void sas_ata_task_done(struct sas_task *task)
sas_ha = dev->port->ha;
spin_lock_irqsave(dev->sata_dev.ap->lock, flags);
- if (stat->stat == SAS_PROTO_RESPONSE || stat->stat == SAM_GOOD) {
+ if (stat->stat == SAS_PROTO_RESPONSE || stat->stat == SAM_STAT_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;
@@ -511,12 +511,12 @@ static int sas_execute_task(struct sas_task *task, void *buffer, int size,
goto ex_err;
}
}
- if (task->task_status.stat == SAM_BUSY ||
- task->task_status.stat == SAM_TASK_SET_FULL ||
+ if (task->task_status.stat == SAM_STAT_BUSY ||
+ task->task_status.stat == SAM_STAT_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) {
+ } else if (task->task_status.stat == SAM_STAT_CHECK_CONDITION) {
struct scsi_sense_hdr shdr;
if (!scsi_normalize_sense(ts->buf, ts->buf_valid_size,
@@ -549,7 +549,7 @@ static int sas_execute_task(struct sas_task *task, void *buffer, int size,
shdr.asc, shdr.ascq);
}
} else if (task->task_status.resp != SAS_TASK_COMPLETE ||
- task->task_status.stat != SAM_GOOD) {
+ task->task_status.stat != SAM_STAT_GOOD) {
SAS_DPRINTK("task finished with resp:0x%x, "
"stat:0x%x\n",
task->task_status.resp,
diff --git a/drivers/scsi/libsas/sas_expander.c b/drivers/scsi/libsas/sas_expander.c
index c65af02dcfe..83dd5070a15 100644
--- a/drivers/scsi/libsas/sas_expander.c
+++ b/drivers/scsi/libsas/sas_expander.c
@@ -107,7 +107,7 @@ static int smp_execute_task(struct domain_device *dev, void *req, int req_size,
}
}
if (task->task_status.resp == SAS_TASK_COMPLETE &&
- task->task_status.stat == SAM_GOOD) {
+ task->task_status.stat == SAM_STAT_GOOD) {
res = 0;
break;
} if (task->task_status.resp == SAS_TASK_COMPLETE &&
diff --git a/drivers/scsi/libsas/sas_scsi_host.c b/drivers/scsi/libsas/sas_scsi_host.c
index a7890c6d878..f0cfba9a1fc 100644
--- a/drivers/scsi/libsas/sas_scsi_host.c
+++ b/drivers/scsi/libsas/sas_scsi_host.c
@@ -113,10 +113,10 @@ static void sas_scsi_task_done(struct sas_task *task)
case SAS_ABORTED_TASK:
hs = DID_ABORT;
break;
- case SAM_CHECK_COND:
+ case SAM_STAT_CHECK_CONDITION:
memcpy(sc->sense_buffer, ts->buf,
min(SCSI_SENSE_BUFFERSIZE, ts->buf_valid_size));
- stat = SAM_CHECK_COND;
+ stat = SAM_STAT_CHECK_CONDITION;
break;
default:
stat = ts->stat;
diff --git a/drivers/scsi/libsas/sas_task.c b/drivers/scsi/libsas/sas_task.c
index 594524d5bfa..b13a3346894 100644
--- a/drivers/scsi/libsas/sas_task.c
+++ b/drivers/scsi/libsas/sas_task.c
@@ -15,13 +15,13 @@ void sas_ssp_task_response(struct device *dev, struct sas_task *task,
else if (iu->datapres == 1)
tstat->stat = iu->resp_data[3];
else if (iu->datapres == 2) {
- tstat->stat = SAM_CHECK_COND;
+ tstat->stat = SAM_STAT_CHECK_CONDITION;
tstat->buf_valid_size =
min_t(int, SAS_STATUS_BUF_SIZE,
be32_to_cpu(iu->sense_data_len));
memcpy(tstat->buf, iu->sense_data, tstat->buf_valid_size);
- if (iu->status != SAM_CHECK_COND)
+ if (iu->status != SAM_STAT_CHECK_CONDITION)
dev_printk(KERN_WARNING, dev,
"dev %llx sent sense data, but "
"stat(%x) is not CHECK CONDITION\n",
@@ -30,7 +30,7 @@ void sas_ssp_task_response(struct device *dev, struct sas_task *task,
}
else
/* when datapres contains corrupt/unknown value... */
- tstat->stat = SAM_CHECK_COND;
+ tstat->stat = SAM_STAT_CHECK_CONDITION;
}
EXPORT_SYMBOL_GPL(sas_ssp_task_response);
diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h
index e35a4c71eb9..3482d5a5aed 100644
--- a/drivers/scsi/lpfc/lpfc.h
+++ b/drivers/scsi/lpfc/lpfc.h
@@ -20,7 +20,6 @@
*******************************************************************/
#include <scsi/scsi_host.h>
-
struct lpfc_sli2_slim;
#define LPFC_PCI_DEV_LP 0x1
@@ -49,7 +48,7 @@ struct lpfc_sli2_slim;
#define LPFC_TGTQ_INTERVAL 40000 /* Min amount of time between tgt
queue depth change in millisecs */
#define LPFC_TGTQ_RAMPUP_PCENT 5 /* Target queue rampup in percentage */
-#define LPFC_MIN_TGT_QDEPTH 100
+#define LPFC_MIN_TGT_QDEPTH 10
#define LPFC_MAX_TGT_QDEPTH 0xFFFF
#define LPFC_MAX_BUCKET_COUNT 20 /* Maximum no. of buckets for stat data
@@ -376,6 +375,7 @@ struct lpfc_vport {
#define WORKER_FABRIC_BLOCK_TMO 0x400 /* hba: fabric block timeout */
#define WORKER_RAMP_DOWN_QUEUE 0x800 /* hba: Decrease Q depth */
#define WORKER_RAMP_UP_QUEUE 0x1000 /* hba: Increase Q depth */
+#define WORKER_SERVICE_TXQ 0x2000 /* hba: IOCBs on the txq */
struct timer_list fc_fdmitmo;
struct timer_list els_tmofunc;
@@ -400,6 +400,7 @@ struct lpfc_vport {
uint32_t cfg_max_luns;
uint32_t cfg_enable_da_id;
uint32_t cfg_max_scsicmpl_time;
+ uint32_t cfg_tgt_queue_depth;
uint32_t dev_loss_tmo_changed;
@@ -510,9 +511,9 @@ struct lpfc_hba {
void (*lpfc_stop_port)
(struct lpfc_hba *);
int (*lpfc_hba_init_link)
- (struct lpfc_hba *);
+ (struct lpfc_hba *, uint32_t);
int (*lpfc_hba_down_link)
- (struct lpfc_hba *);
+ (struct lpfc_hba *, uint32_t);
/* SLI4 specific HBA data structure */
struct lpfc_sli4_hba sli4_hba;
@@ -525,7 +526,6 @@ struct lpfc_hba {
#define LPFC_SLI3_NPIV_ENABLED 0x02
#define LPFC_SLI3_VPORT_TEARDOWN 0x04
#define LPFC_SLI3_CRP_ENABLED 0x08
-#define LPFC_SLI3_INB_ENABLED 0x10
#define LPFC_SLI3_BG_ENABLED 0x20
#define LPFC_SLI3_DSS_ENABLED 0x40
uint32_t iocb_cmd_size;
@@ -557,9 +557,6 @@ struct lpfc_hba {
MAILBOX_t *mbox;
uint32_t *mbox_ext;
- uint32_t *inb_ha_copy;
- uint32_t *inb_counter;
- uint32_t inb_last_counter;
uint32_t ha_copy;
struct _PCB *pcb;
struct _IOCB *IOCBs;
@@ -628,6 +625,7 @@ struct lpfc_hba {
uint32_t cfg_hostmem_hgp;
uint32_t cfg_log_verbose;
uint32_t cfg_aer_support;
+ uint32_t cfg_iocb_cnt;
uint32_t cfg_suppress_link_up;
#define LPFC_INITIALIZE_LINK 0 /* do normal init_link mbox */
#define LPFC_DELAY_INIT_LINK 1 /* layered driver hold off */
@@ -816,6 +814,9 @@ struct lpfc_hba {
uint8_t menlo_flag; /* menlo generic flags */
#define HBA_MENLO_SUPPORT 0x1 /* HBA supports menlo commands */
+ uint32_t iocb_cnt;
+ uint32_t iocb_max;
+ atomic_t sdev_cnt;
};
static inline struct Scsi_Host *
diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c
index bf33b315f93..162704cf6a9 100644
--- a/drivers/scsi/lpfc/lpfc_attr.c
+++ b/drivers/scsi/lpfc/lpfc_attr.c
@@ -506,10 +506,10 @@ lpfc_link_state_store(struct device *dev, struct device_attribute *attr,
if ((strncmp(buf, "up", sizeof("up") - 1) == 0) &&
(phba->link_state == LPFC_LINK_DOWN))
- status = phba->lpfc_hba_init_link(phba);
+ status = phba->lpfc_hba_init_link(phba, MBX_NOWAIT);
else if ((strncmp(buf, "down", sizeof("down") - 1) == 0) &&
(phba->link_state >= LPFC_LINK_UP))
- status = phba->lpfc_hba_down_link(phba);
+ status = phba->lpfc_hba_down_link(phba, MBX_NOWAIT);
if (status == 0)
return strlen(buf);
@@ -864,7 +864,6 @@ lpfc_get_hba_info(struct lpfc_hba *phba,
uint32_t *mrpi, uint32_t *arpi,
uint32_t *mvpi, uint32_t *avpi)
{
- struct lpfc_sli *psli = &phba->sli;
struct lpfc_mbx_read_config *rd_config;
LPFC_MBOXQ_t *pmboxq;
MAILBOX_t *pmb;
@@ -893,8 +892,7 @@ lpfc_get_hba_info(struct lpfc_hba *phba,
pmb->mbxOwner = OWN_HOST;
pmboxq->context1 = NULL;
- if ((phba->pport->fc_flag & FC_OFFLINE_MODE) ||
- (!(psli->sli_flag & LPFC_SLI_ACTIVE)))
+ if (phba->pport->fc_flag & FC_OFFLINE_MODE)
rc = MBX_NOT_FINISHED;
else
rc = lpfc_sli_issue_mbox_wait(phba, pmboxq, phba->fc_ratov * 2);
@@ -1949,6 +1947,59 @@ static DEVICE_ATTR(lpfc_enable_npiv, S_IRUGO, lpfc_enable_npiv_show, NULL);
LPFC_ATTR_R(suppress_link_up, LPFC_INITIALIZE_LINK, LPFC_INITIALIZE_LINK,
LPFC_DELAY_INIT_LINK_INDEFINITELY,
"Suppress Link Up at initialization");
+/*
+# lpfc_cnt: Number of IOCBs allocated for ELS, CT, and ABTS
+# 1 - (1024)
+# 2 - (2048)
+# 3 - (3072)
+# 4 - (4096)
+# 5 - (5120)
+*/
+static ssize_t
+lpfc_iocb_hw_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct Scsi_Host *shost = class_to_shost(dev);
+ struct lpfc_hba *phba = ((struct lpfc_vport *) shost->hostdata)->phba;
+
+ return snprintf(buf, PAGE_SIZE, "%d\n", phba->iocb_max);
+}
+
+static DEVICE_ATTR(iocb_hw, S_IRUGO,
+ lpfc_iocb_hw_show, NULL);
+static ssize_t
+lpfc_txq_hw_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct Scsi_Host *shost = class_to_shost(dev);
+ struct lpfc_hba *phba = ((struct lpfc_vport *) shost->hostdata)->phba;
+
+ return snprintf(buf, PAGE_SIZE, "%d\n",
+ phba->sli.ring[LPFC_ELS_RING].txq_max);
+}
+
+static DEVICE_ATTR(txq_hw, S_IRUGO,
+ lpfc_txq_hw_show, NULL);
+static ssize_t
+lpfc_txcmplq_hw_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct Scsi_Host *shost = class_to_shost(dev);
+ struct lpfc_hba *phba = ((struct lpfc_vport *) shost->hostdata)->phba;
+
+ return snprintf(buf, PAGE_SIZE, "%d\n",
+ phba->sli.ring[LPFC_ELS_RING].txcmplq_max);
+}
+
+static DEVICE_ATTR(txcmplq_hw, S_IRUGO,
+ lpfc_txcmplq_hw_show, NULL);
+
+int lpfc_iocb_cnt = 2;
+module_param(lpfc_iocb_cnt, int, 1);
+MODULE_PARM_DESC(lpfc_iocb_cnt,
+ "Number of IOCBs alloc for ELS, CT, and ABTS: 1k to 5k IOCBs");
+lpfc_param_show(iocb_cnt);
+lpfc_param_init(iocb_cnt, 2, 1, 5);
+static DEVICE_ATTR(lpfc_iocb_cnt, S_IRUGO,
+ lpfc_iocb_cnt_show, NULL);
/*
# lpfc_nodev_tmo: If set, it will hold all I/O errors on devices that disappear
@@ -2157,6 +2208,13 @@ LPFC_VPORT_ATTR_R(lun_queue_depth, 30, 1, 128,
"Max number of FCP commands we can queue to a specific LUN");
/*
+# tgt_queue_depth: This parameter is used to limit the number of outstanding
+# commands per target port. Value range is [10,65535]. Default value is 65535.
+*/
+LPFC_VPORT_ATTR_R(tgt_queue_depth, 65535, 10, 65535,
+ "Max number of FCP commands we can queue to a specific target port");
+
+/*
# hba_queue_depth: This parameter is used to limit the number of outstanding
# commands per lpfc HBA. Value range is [32,8192]. If this parameter
# value is greater than the maximum number of exchanges supported by the HBA,
@@ -2720,7 +2778,6 @@ static struct bin_attribute sysfs_drvr_stat_data_attr = {
.attr = {
.name = "lpfc_drvr_stat_data",
.mode = S_IRUSR,
- .owner = THIS_MODULE,
},
.size = LPFC_MAX_TARGET * MAX_STAT_DATA_SIZE_PER_TARGET,
.read = sysfs_drvr_stat_data_read,
@@ -2890,9 +2947,6 @@ lpfc_aer_support_store(struct device *dev, struct device_attribute *attr,
struct lpfc_hba *phba = vport->phba;
int val = 0, rc = -EINVAL;
- /* AER not supported on OC devices yet */
- if (phba->pci_dev_grp == LPFC_PCI_DEV_OC)
- return -EPERM;
if (!isdigit(buf[0]))
return -EINVAL;
if (sscanf(buf, "%i", &val) != 1)
@@ -2965,12 +3019,6 @@ lpfc_param_show(aer_support)
static int
lpfc_aer_support_init(struct lpfc_hba *phba, int val)
{
- /* AER not supported on OC devices yet */
- if (phba->pci_dev_grp == LPFC_PCI_DEV_OC) {
- phba->cfg_aer_support = 0;
- return -EPERM;
- }
-
if (val == 0 || val == 1) {
phba->cfg_aer_support = val;
return 0;
@@ -3015,9 +3063,6 @@ lpfc_aer_cleanup_state(struct device *dev, struct device_attribute *attr,
struct lpfc_hba *phba = vport->phba;
int val, rc = -1;
- /* AER not supported on OC devices yet */
- if (phba->pci_dev_grp == LPFC_PCI_DEV_OC)
- return -EPERM;
if (!isdigit(buf[0]))
return -EINVAL;
if (sscanf(buf, "%i", &val) != 1)
@@ -3083,7 +3128,7 @@ lpfc_max_scsicmpl_time_set(struct lpfc_vport *vport, int val)
continue;
if (ndlp->nlp_state == NLP_STE_UNUSED_NODE)
continue;
- ndlp->cmd_qdepth = LPFC_MAX_TGT_QDEPTH;
+ ndlp->cmd_qdepth = vport->cfg_tgt_queue_depth;
}
spin_unlock_irq(shost->host_lock);
return 0;
@@ -3287,6 +3332,7 @@ struct device_attribute *lpfc_hba_attrs[] = {
&dev_attr_lpfc_temp_sensor,
&dev_attr_lpfc_log_verbose,
&dev_attr_lpfc_lun_queue_depth,
+ &dev_attr_lpfc_tgt_queue_depth,
&dev_attr_lpfc_hba_queue_depth,
&dev_attr_lpfc_peer_port_login,
&dev_attr_lpfc_nodev_tmo,
@@ -3334,6 +3380,10 @@ struct device_attribute *lpfc_hba_attrs[] = {
&dev_attr_lpfc_aer_support,
&dev_attr_lpfc_aer_state_cleanup,
&dev_attr_lpfc_suppress_link_up,
+ &dev_attr_lpfc_iocb_cnt,
+ &dev_attr_iocb_hw,
+ &dev_attr_txq_hw,
+ &dev_attr_txcmplq_hw,
NULL,
};
@@ -3344,6 +3394,7 @@ struct device_attribute *lpfc_vport_attrs[] = {
&dev_attr_lpfc_drvr_version,
&dev_attr_lpfc_log_verbose,
&dev_attr_lpfc_lun_queue_depth,
+ &dev_attr_lpfc_tgt_queue_depth,
&dev_attr_lpfc_nodev_tmo,
&dev_attr_lpfc_devloss_tmo,
&dev_attr_lpfc_hba_queue_depth,
@@ -4042,8 +4093,7 @@ lpfc_get_stats(struct Scsi_Host *shost)
pmboxq->context1 = NULL;
pmboxq->vport = vport;
- if ((vport->fc_flag & FC_OFFLINE_MODE) ||
- (!(psli->sli_flag & LPFC_SLI_ACTIVE)))
+ if (vport->fc_flag & FC_OFFLINE_MODE)
rc = lpfc_sli_issue_mbox(phba, pmboxq, MBX_POLL);
else
rc = lpfc_sli_issue_mbox_wait(phba, pmboxq, phba->fc_ratov * 2);
@@ -4067,8 +4117,7 @@ lpfc_get_stats(struct Scsi_Host *shost)
pmboxq->context1 = NULL;
pmboxq->vport = vport;
- if ((vport->fc_flag & FC_OFFLINE_MODE) ||
- (!(psli->sli_flag & LPFC_SLI_ACTIVE)))
+ if (vport->fc_flag & FC_OFFLINE_MODE)
rc = lpfc_sli_issue_mbox(phba, pmboxq, MBX_POLL);
else
rc = lpfc_sli_issue_mbox_wait(phba, pmboxq, phba->fc_ratov * 2);
@@ -4521,6 +4570,7 @@ lpfc_get_cfgparam(struct lpfc_hba *phba)
lpfc_hba_log_verbose_init(phba, lpfc_log_verbose);
lpfc_aer_support_init(phba, lpfc_aer_support);
lpfc_suppress_link_up_init(phba, lpfc_suppress_link_up);
+ lpfc_iocb_cnt_init(phba, lpfc_iocb_cnt);
return;
}
@@ -4533,6 +4583,7 @@ lpfc_get_vport_cfgparam(struct lpfc_vport *vport)
{
lpfc_log_verbose_init(vport, lpfc_log_verbose);
lpfc_lun_queue_depth_init(vport, lpfc_lun_queue_depth);
+ lpfc_tgt_queue_depth_init(vport, lpfc_tgt_queue_depth);
lpfc_devloss_tmo_init(vport, lpfc_devloss_tmo);
lpfc_nodev_tmo_init(vport, lpfc_nodev_tmo);
lpfc_peer_port_login_init(vport, lpfc_peer_port_login);
diff --git a/drivers/scsi/lpfc/lpfc_bsg.c b/drivers/scsi/lpfc/lpfc_bsg.c
index dcf088262b2..d521569e662 100644
--- a/drivers/scsi/lpfc/lpfc_bsg.c
+++ b/drivers/scsi/lpfc/lpfc_bsg.c
@@ -377,6 +377,11 @@ lpfc_bsg_send_mgmt_cmd(struct fc_bsg_job *job)
if (rc == IOCB_SUCCESS)
return 0; /* done for now */
+ else if (rc == IOCB_BUSY)
+ rc = EAGAIN;
+ else
+ rc = EIO;
+
/* iocb failed so cleanup */
pci_unmap_sg(phba->pcidev, job->request_payload.sg_list,
@@ -625,6 +630,10 @@ lpfc_bsg_rport_els(struct fc_bsg_job *job)
lpfc_nlp_put(ndlp);
if (rc == IOCB_SUCCESS)
return 0; /* done for now */
+ else if (rc == IOCB_BUSY)
+ rc = EAGAIN;
+ else
+ rc = EIO;
pci_unmap_sg(phba->pcidev, job->request_payload.sg_list,
job->request_payload.sg_cnt, DMA_TO_DEVICE);
@@ -953,10 +962,22 @@ lpfc_bsg_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
if (phba->sli_rev == LPFC_SLI_REV4) {
evt_dat->immed_dat = phba->ctx_idx;
phba->ctx_idx = (phba->ctx_idx + 1) % 64;
+ /* Provide warning for over-run of the ct_ctx array */
+ if (phba->ct_ctx[evt_dat->immed_dat].flags &
+ UNSOL_VALID)
+ lpfc_printf_log(phba, KERN_WARNING, LOG_ELS,
+ "2717 CT context array entry "
+ "[%d] over-run: oxid:x%x, "
+ "sid:x%x\n", phba->ctx_idx,
+ phba->ct_ctx[
+ evt_dat->immed_dat].oxid,
+ phba->ct_ctx[
+ evt_dat->immed_dat].SID);
phba->ct_ctx[evt_dat->immed_dat].oxid =
piocbq->iocb.ulpContext;
phba->ct_ctx[evt_dat->immed_dat].SID =
piocbq->iocb.un.rcvels.remoteID;
+ phba->ct_ctx[evt_dat->immed_dat].flags = UNSOL_VALID;
} else
evt_dat->immed_dat = piocbq->iocb.ulpContext;
@@ -1314,6 +1335,21 @@ lpfc_issue_ct_rsp(struct lpfc_hba *phba, struct fc_bsg_job *job, uint32_t tag,
rc = IOCB_ERROR;
goto issue_ct_rsp_exit;
}
+
+ /* Check if the ndlp is active */
+ if (!ndlp || !NLP_CHK_NODE_ACT(ndlp)) {
+ rc = -IOCB_ERROR;
+ goto issue_ct_rsp_exit;
+ }
+
+ /* get a refernece count so the ndlp doesn't go away while
+ * we respond
+ */
+ if (!lpfc_nlp_get(ndlp)) {
+ rc = -IOCB_ERROR;
+ goto issue_ct_rsp_exit;
+ }
+
icmd->un.ulpWord[3] = ndlp->nlp_rpi;
/* The exchange is done, mark the entry as invalid */
phba->ct_ctx[tag].flags &= ~UNSOL_VALID;
diff --git a/drivers/scsi/lpfc/lpfc_crtn.h b/drivers/scsi/lpfc/lpfc_crtn.h
index fbc9baeb604..03f4ddc1857 100644
--- a/drivers/scsi/lpfc/lpfc_crtn.h
+++ b/drivers/scsi/lpfc/lpfc_crtn.h
@@ -41,6 +41,7 @@ void lpfc_read_config(struct lpfc_hba *, LPFC_MBOXQ_t *);
void lpfc_read_lnk_stat(struct lpfc_hba *, LPFC_MBOXQ_t *);
int lpfc_reg_rpi(struct lpfc_hba *, uint16_t, uint32_t, uint8_t *,
LPFC_MBOXQ_t *, uint32_t);
+void lpfc_set_var(struct lpfc_hba *, LPFC_MBOXQ_t *, uint32_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_vport *, LPFC_MBOXQ_t *);
@@ -190,6 +191,7 @@ irqreturn_t lpfc_sli4_sp_intr_handler(int, void *);
irqreturn_t lpfc_sli4_fp_intr_handler(int, void *);
void lpfc_read_rev(struct lpfc_hba *, LPFC_MBOXQ_t *);
+void lpfc_sli4_swap_str(struct lpfc_hba *, LPFC_MBOXQ_t *);
void lpfc_config_ring(struct lpfc_hba *, int, LPFC_MBOXQ_t *);
void lpfc_config_port(struct lpfc_hba *, LPFC_MBOXQ_t *);
void lpfc_kill_board(struct lpfc_hba *, LPFC_MBOXQ_t *);
@@ -402,3 +404,12 @@ int lpfc_bsg_request(struct fc_bsg_job *);
int lpfc_bsg_timeout(struct fc_bsg_job *);
int lpfc_bsg_ct_unsol_event(struct lpfc_hba *, struct lpfc_sli_ring *,
struct lpfc_iocbq *);
+void __lpfc_sli_ringtx_put(struct lpfc_hba *, struct lpfc_sli_ring *,
+ struct lpfc_iocbq *);
+struct lpfc_iocbq *lpfc_sli_ringtx_get(struct lpfc_hba *,
+ struct lpfc_sli_ring *);
+int __lpfc_sli_issue_iocb(struct lpfc_hba *, uint32_t,
+ struct lpfc_iocbq *, uint32_t);
+uint32_t lpfc_drain_txq(struct lpfc_hba *);
+
+
diff --git a/drivers/scsi/lpfc/lpfc_disc.h b/drivers/scsi/lpfc/lpfc_disc.h
index 36257a68550..7cae69de36f 100644
--- a/drivers/scsi/lpfc/lpfc_disc.h
+++ b/drivers/scsi/lpfc/lpfc_disc.h
@@ -114,6 +114,8 @@ struct lpfc_nodelist {
};
/* Defines for nlp_flag (uint32) */
+#define NLP_IGNR_REG_CMPL 0x00000001 /* Rcvd rscn before we cmpl reg login */
+#define NLP_REG_LOGIN_SEND 0x00000002 /* sent reglogin to adapter */
#define NLP_PLOGI_SND 0x00000020 /* sent PLOGI request for this entry */
#define NLP_PRLI_SND 0x00000040 /* sent PRLI request for this entry */
#define NLP_ADISC_SND 0x00000080 /* sent ADISC request for this entry */
diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c
index c4c7f0ad746..afbed6bc31f 100644
--- a/drivers/scsi/lpfc/lpfc_els.c
+++ b/drivers/scsi/lpfc/lpfc_els.c
@@ -796,7 +796,9 @@ lpfc_cmpl_els_flogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
* due to new FCF discovery
*/
if ((phba->hba_flag & HBA_FIP_SUPPORT) &&
- (phba->fcf.fcf_flag & FCF_DISCOVERY)) {
+ (phba->fcf.fcf_flag & FCF_DISCOVERY) &&
+ (irsp->ulpStatus != IOSTAT_LOCAL_REJECT) &&
+ (irsp->un.ulpWord[4] != IOERR_SLI_ABORTED)) {
lpfc_printf_log(phba, KERN_WARNING, LOG_FIP | LOG_ELS,
"2611 FLOGI failed on registered "
"FCF record fcf_index:%d, trying "
@@ -811,18 +813,21 @@ lpfc_cmpl_els_flogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
*/
lpfc_printf_log(phba, KERN_WARNING,
LOG_FIP | LOG_ELS,
- "2760 FLOGI exhausted FCF "
- "round robin failover list, "
- "retry FLOGI on the current "
- "registered FCF index:%d\n",
+ "2760 Completed one round "
+ "of FLOGI FCF round robin "
+ "failover list, retry FLOGI "
+ "on currently registered "
+ "FCF index:%d\n",
phba->fcf.current_rec.fcf_indx);
- spin_lock_irq(&phba->hbalock);
- phba->fcf.fcf_flag &= ~FCF_DISCOVERY;
- spin_unlock_irq(&phba->hbalock);
} else {
+ lpfc_printf_log(phba, KERN_INFO,
+ LOG_FIP | LOG_ELS,
+ "2794 FLOGI FCF round robin "
+ "failover to FCF index x%x\n",
+ fcf_index);
rc = lpfc_sli4_fcf_rr_read_fcf_rec(phba,
fcf_index);
- if (rc) {
+ if (rc)
lpfc_printf_log(phba, KERN_WARNING,
LOG_FIP | LOG_ELS,
"2761 FLOGI round "
@@ -831,10 +836,7 @@ lpfc_cmpl_els_flogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
"rc:x%x, fcf_index:"
"%d\n", rc,
phba->fcf.current_rec.fcf_indx);
- spin_lock_irq(&phba->hbalock);
- phba->fcf.fcf_flag &= ~FCF_DISCOVERY;
- spin_unlock_irq(&phba->hbalock);
- } else
+ else
goto out;
}
}
@@ -890,9 +892,39 @@ lpfc_cmpl_els_flogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
*/
if (sp->cmn.fPort)
rc = lpfc_cmpl_els_flogi_fabric(vport, ndlp, sp, irsp);
- else
+ else if (!(phba->hba_flag & HBA_FCOE_SUPPORT))
rc = lpfc_cmpl_els_flogi_nport(vport, ndlp, sp);
-
+ else {
+ lpfc_printf_vlog(vport, KERN_ERR,
+ LOG_FIP | LOG_ELS,
+ "2831 FLOGI response with cleared Fabric "
+ "bit fcf_index 0x%x "
+ "Switch Name %02x%02x%02x%02x%02x%02x%02x%02x "
+ "Fabric Name "
+ "%02x%02x%02x%02x%02x%02x%02x%02x\n",
+ phba->fcf.current_rec.fcf_indx,
+ phba->fcf.current_rec.switch_name[0],
+ phba->fcf.current_rec.switch_name[1],
+ phba->fcf.current_rec.switch_name[2],
+ phba->fcf.current_rec.switch_name[3],
+ phba->fcf.current_rec.switch_name[4],
+ phba->fcf.current_rec.switch_name[5],
+ phba->fcf.current_rec.switch_name[6],
+ phba->fcf.current_rec.switch_name[7],
+ phba->fcf.current_rec.fabric_name[0],
+ phba->fcf.current_rec.fabric_name[1],
+ phba->fcf.current_rec.fabric_name[2],
+ phba->fcf.current_rec.fabric_name[3],
+ phba->fcf.current_rec.fabric_name[4],
+ phba->fcf.current_rec.fabric_name[5],
+ phba->fcf.current_rec.fabric_name[6],
+ phba->fcf.current_rec.fabric_name[7]);
+ lpfc_nlp_put(ndlp);
+ spin_lock_irq(&phba->hbalock);
+ phba->fcf.fcf_flag &= ~FCF_DISCOVERY;
+ spin_unlock_irq(&phba->hbalock);
+ goto out;
+ }
if (!rc) {
/* Mark the FCF discovery process done */
if (phba->hba_flag & HBA_FIP_SUPPORT)
@@ -1472,8 +1504,12 @@ lpfc_cmpl_els_plogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
}
goto out;
}
- /* PLOGI failed */
- lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
+ /* PLOGI failed Don't print the vport to vport rjts */
+ if (irsp->ulpStatus != IOSTAT_LS_RJT ||
+ (((irsp->un.ulpWord[4]) >> 16 != LSRJT_INVALID_CMD) &&
+ ((irsp->un.ulpWord[4]) >> 16 != LSRJT_UNABLE_TPC)) ||
+ (phba)->pport->cfg_log_verbose & LOG_ELS)
+ lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
"2753 PLOGI failure DID:%06X Status:x%x/x%x\n",
ndlp->nlp_DID, irsp->ulpStatus,
irsp->un.ulpWord[4]);
@@ -2740,6 +2776,15 @@ lpfc_els_retry(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
retry = 1;
break;
}
+ if (stat.un.b.lsRjtRsnCodeExp ==
+ LSEXP_CANT_GIVE_DATA) {
+ if (cmd == ELS_CMD_PLOGI) {
+ delay = 1000;
+ maxretry = 48;
+ }
+ retry = 1;
+ break;
+ }
if (cmd == ELS_CMD_PLOGI) {
delay = 1000;
maxretry = lpfc_max_els_tries + 1;
@@ -5135,6 +5180,7 @@ lpfc_els_timeout(unsigned long ptr)
return;
}
+
/**
* lpfc_els_timeout_handler - Process an els timeout event
* @vport: pointer to a virtual N_Port data structure.
@@ -5155,13 +5201,19 @@ lpfc_els_timeout_handler(struct lpfc_vport *vport)
uint32_t els_command = 0;
uint32_t timeout;
uint32_t remote_ID = 0xffffffff;
+ LIST_HEAD(txcmplq_completions);
+ LIST_HEAD(abort_list);
+
- spin_lock_irq(&phba->hbalock);
timeout = (uint32_t)(phba->fc_ratov << 1);
pring = &phba->sli.ring[LPFC_ELS_RING];
- list_for_each_entry_safe(piocb, tmp_iocb, &pring->txcmplq, list) {
+ spin_lock_irq(&phba->hbalock);
+ list_splice_init(&pring->txcmplq, &txcmplq_completions);
+ spin_unlock_irq(&phba->hbalock);
+
+ list_for_each_entry_safe(piocb, tmp_iocb, &txcmplq_completions, list) {
cmd = &piocb->iocb;
if ((piocb->iocb_flag & LPFC_IO_LIBDFC) != 0 ||
@@ -5198,13 +5250,22 @@ lpfc_els_timeout_handler(struct lpfc_vport *vport)
if (ndlp && NLP_CHK_NODE_ACT(ndlp))
remote_ID = ndlp->nlp_DID;
}
+ list_add_tail(&piocb->dlist, &abort_list);
+ }
+ spin_lock_irq(&phba->hbalock);
+ list_splice(&txcmplq_completions, &pring->txcmplq);
+ spin_unlock_irq(&phba->hbalock);
+
+ list_for_each_entry_safe(piocb, tmp_iocb, &abort_list, dlist) {
lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
- "0127 ELS timeout Data: x%x x%x x%x "
- "x%x\n", els_command,
- remote_ID, cmd->ulpCommand, cmd->ulpIoTag);
+ "0127 ELS timeout Data: x%x x%x x%x "
+ "x%x\n", els_command,
+ remote_ID, cmd->ulpCommand, cmd->ulpIoTag);
+ spin_lock_irq(&phba->hbalock);
+ list_del_init(&piocb->dlist);
lpfc_sli_issue_abort_iotag(phba, pring, piocb);
+ spin_unlock_irq(&phba->hbalock);
}
- spin_unlock_irq(&phba->hbalock);
if (phba->sli.ring[LPFC_ELS_RING].txcmplq_cnt)
mod_timer(&vport->els_tmofunc, jiffies + HZ * timeout);
@@ -6901,6 +6962,7 @@ lpfc_sli4_els_xri_aborted(struct lpfc_hba *phba,
uint16_t xri = bf_get(lpfc_wcqe_xa_xri, axri);
struct lpfc_sglq *sglq_entry = NULL, *sglq_next = NULL;
unsigned long iflag = 0;
+ struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_ELS_RING];
spin_lock_irqsave(&phba->hbalock, iflag);
spin_lock(&phba->sli4_hba.abts_sgl_list_lock);
@@ -6913,6 +6975,10 @@ lpfc_sli4_els_xri_aborted(struct lpfc_hba *phba,
sglq_entry->state = SGL_FREED;
spin_unlock(&phba->sli4_hba.abts_sgl_list_lock);
spin_unlock_irqrestore(&phba->hbalock, iflag);
+
+ /* Check if TXQ queue needs to be serviced */
+ if (pring->txq_cnt)
+ lpfc_worker_wake_up(phba);
return;
}
}
diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c
index 1f87b4fb8b5..0639c994349 100644
--- a/drivers/scsi/lpfc/lpfc_hbadisc.c
+++ b/drivers/scsi/lpfc/lpfc_hbadisc.c
@@ -275,7 +275,9 @@ lpfc_dev_loss_tmo_handler(struct lpfc_nodelist *ndlp)
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))
+ (ndlp->nlp_state != NLP_STE_UNMAPPED_NODE) &&
+ (ndlp->nlp_state != NLP_STE_REG_LOGIN_ISSUE) &&
+ (ndlp->nlp_state != NLP_STE_PRLI_ISSUE))
lpfc_disc_state_machine(vport, ndlp, NULL, NLP_EVT_DEVICE_RM);
lpfc_unregister_unused_fcf(phba);
@@ -586,6 +588,8 @@ lpfc_work_done(struct lpfc_hba *phba)
(status &
HA_RXMASK));
}
+ if (pring->txq_cnt)
+ lpfc_drain_txq(phba);
/*
* Turn on Ring interrupts
*/
@@ -1297,7 +1301,7 @@ lpfc_register_fcf(struct lpfc_hba *phba)
* used for this FCF when the function returns.
* If the FCF record need to be used with a particular vlan id, the vlan is
* set in the vlan_id on return of the function. If not VLAN tagging need to
- * be used with the FCF vlan_id will be set to 0xFFFF;
+ * be used with the FCF vlan_id will be set to LPFC_FCOE_NULL_VID;
**/
static int
lpfc_match_fcf_conn_list(struct lpfc_hba *phba,
@@ -1333,7 +1337,7 @@ lpfc_match_fcf_conn_list(struct lpfc_hba *phba,
if (phba->valid_vlan)
*vlan_id = phba->vlan_id;
else
- *vlan_id = 0xFFFF;
+ *vlan_id = LPFC_FCOE_NULL_VID;
return 1;
}
@@ -1357,7 +1361,7 @@ lpfc_match_fcf_conn_list(struct lpfc_hba *phba,
if (fcf_vlan_id)
*vlan_id = fcf_vlan_id;
else
- *vlan_id = 0xFFFF;
+ *vlan_id = LPFC_FCOE_NULL_VID;
return 1;
}
@@ -1466,7 +1470,7 @@ lpfc_match_fcf_conn_list(struct lpfc_hba *phba,
else if (fcf_vlan_id)
*vlan_id = fcf_vlan_id;
else
- *vlan_id = 0xFFFF;
+ *vlan_id = LPFC_FCOE_NULL_VID;
return 1;
}
@@ -1518,6 +1522,9 @@ lpfc_check_pending_fcoe_event(struct lpfc_hba *phba, uint8_t unreg_fcf)
* Do not continue FCF discovery and clear FCF_DISC_INPROGRESS
* flag
*/
+ lpfc_printf_log(phba, KERN_INFO, LOG_FIP | LOG_DISCOVERY,
+ "2833 Stop FCF discovery process due to link "
+ "state change (x%x)\n", phba->link_state);
spin_lock_irq(&phba->hbalock);
phba->hba_flag &= ~FCF_DISC_INPROGRESS;
phba->fcf.fcf_flag &= ~(FCF_REDISC_FOV | FCF_DISCOVERY);
@@ -1565,7 +1572,7 @@ lpfc_sli4_new_fcf_random_select(struct lpfc_hba *phba, uint32_t fcf_cnt)
}
/**
- * lpfc_mbx_cmpl_read_fcf_record - Completion handler for read_fcf mbox.
+ * lpfc_sli4_fcf_rec_mbox_parse - Parse read_fcf mbox command.
* @phba: pointer to lpfc hba data structure.
* @mboxq: pointer to mailbox object.
* @next_fcf_index: pointer to holder of next fcf index.
@@ -1693,6 +1700,37 @@ lpfc_sli4_log_fcf_record_info(struct lpfc_hba *phba,
}
/**
+ lpfc_sli4_fcf_record_match - testing new FCF record for matching existing FCF
+ * @phba: pointer to lpfc hba data structure.
+ * @fcf_rec: pointer to an existing FCF record.
+ * @new_fcf_record: pointer to a new FCF record.
+ * @new_vlan_id: vlan id from the new FCF record.
+ *
+ * This function performs matching test of a new FCF record against an existing
+ * FCF record. If the new_vlan_id passed in is LPFC_FCOE_IGNORE_VID, vlan id
+ * will not be used as part of the FCF record matching criteria.
+ *
+ * Returns true if all the fields matching, otherwise returns false.
+ */
+static bool
+lpfc_sli4_fcf_record_match(struct lpfc_hba *phba,
+ struct lpfc_fcf_rec *fcf_rec,
+ struct fcf_record *new_fcf_record,
+ uint16_t new_vlan_id)
+{
+ if (new_vlan_id != LPFC_FCOE_IGNORE_VID)
+ if (!lpfc_vlan_id_match(fcf_rec->vlan_id, new_vlan_id))
+ return false;
+ if (!lpfc_mac_addr_match(fcf_rec->mac_addr, new_fcf_record))
+ return false;
+ if (!lpfc_sw_name_match(fcf_rec->switch_name, new_fcf_record))
+ return false;
+ if (!lpfc_fab_name_match(fcf_rec->fabric_name, new_fcf_record))
+ return false;
+ return true;
+}
+
+/**
* lpfc_mbx_cmpl_fcf_scan_read_fcf_rec - fcf scan read_fcf mbox cmpl handler.
* @phba: pointer to lpfc hba data structure.
* @mboxq: pointer to mailbox object.
@@ -1755,7 +1793,7 @@ lpfc_mbx_cmpl_fcf_scan_read_fcf_rec(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
*/
if (!rc) {
lpfc_printf_log(phba, KERN_WARNING, LOG_FIP,
- "2781 FCF record fcf_index:x%x failed FCF "
+ "2781 FCF record (x%x) failed FCF "
"connection list check, fcf_avail:x%x, "
"fcf_valid:x%x\n",
bf_get(lpfc_fcf_record_fcf_index,
@@ -1764,6 +1802,32 @@ lpfc_mbx_cmpl_fcf_scan_read_fcf_rec(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
new_fcf_record),
bf_get(lpfc_fcf_record_fcf_valid,
new_fcf_record));
+ if ((phba->fcf.fcf_flag & FCF_IN_USE) &&
+ lpfc_sli4_fcf_record_match(phba, &phba->fcf.current_rec,
+ new_fcf_record, LPFC_FCOE_IGNORE_VID)) {
+ /*
+ * In case the current in-use FCF record becomes
+ * invalid/unavailable during FCF discovery that
+ * was not triggered by fast FCF failover process,
+ * treat it as fast FCF failover.
+ */
+ if (!(phba->fcf.fcf_flag & FCF_REDISC_PEND) &&
+ !(phba->fcf.fcf_flag & FCF_REDISC_FOV)) {
+ lpfc_printf_log(phba, KERN_WARNING, LOG_FIP,
+ "2835 Invalid in-use FCF "
+ "record (x%x) reported, "
+ "entering fast FCF failover "
+ "mode scanning.\n",
+ phba->fcf.current_rec.fcf_indx);
+ spin_lock_irq(&phba->hbalock);
+ phba->fcf.fcf_flag |= FCF_REDISC_FOV;
+ spin_unlock_irq(&phba->hbalock);
+ lpfc_sli4_mbox_cmd_free(phba, mboxq);
+ lpfc_sli4_fcf_scan_read_fcf_rec(phba,
+ LPFC_FCOE_FCF_GET_FIRST);
+ return;
+ }
+ }
goto read_next_fcf;
} else {
fcf_index = bf_get(lpfc_fcf_record_fcf_index, new_fcf_record);
@@ -1780,14 +1844,8 @@ lpfc_mbx_cmpl_fcf_scan_read_fcf_rec(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
*/
spin_lock_irq(&phba->hbalock);
if (phba->fcf.fcf_flag & FCF_IN_USE) {
- if (lpfc_fab_name_match(phba->fcf.current_rec.fabric_name,
- new_fcf_record) &&
- lpfc_sw_name_match(phba->fcf.current_rec.switch_name,
- new_fcf_record) &&
- lpfc_mac_addr_match(phba->fcf.current_rec.mac_addr,
- new_fcf_record) &&
- lpfc_vlan_id_match(phba->fcf.current_rec.vlan_id,
- vlan_id)) {
+ if (lpfc_sli4_fcf_record_match(phba, &phba->fcf.current_rec,
+ new_fcf_record, vlan_id)) {
phba->fcf.fcf_flag |= FCF_AVAILABLE;
if (phba->fcf.fcf_flag & FCF_REDISC_PEND)
/* Stop FCF redisc wait timer if pending */
@@ -1797,6 +1855,13 @@ lpfc_mbx_cmpl_fcf_scan_read_fcf_rec(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
phba->fcf.fcf_flag &= ~(FCF_REDISC_FOV |
FCF_DISCOVERY);
spin_unlock_irq(&phba->hbalock);
+ lpfc_printf_log(phba, KERN_INFO, LOG_FIP,
+ "2836 The new FCF record (x%x) "
+ "matches the in-use FCF record "
+ "(x%x)\n",
+ phba->fcf.current_rec.fcf_indx,
+ bf_get(lpfc_fcf_record_fcf_index,
+ new_fcf_record));
goto out;
}
/*
@@ -1828,6 +1893,12 @@ lpfc_mbx_cmpl_fcf_scan_read_fcf_rec(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
*/
if (boot_flag && !(fcf_rec->flag & BOOT_ENABLE)) {
/* Choose this FCF record */
+ lpfc_printf_log(phba, KERN_INFO, LOG_FIP,
+ "2837 Update current FCF record "
+ "(x%x) with new FCF record (x%x)\n",
+ fcf_rec->fcf_indx,
+ bf_get(lpfc_fcf_record_fcf_index,
+ new_fcf_record));
__lpfc_update_fcf_record(phba, fcf_rec, new_fcf_record,
addr_mode, vlan_id, BOOT_ENABLE);
spin_unlock_irq(&phba->hbalock);
@@ -1848,6 +1919,12 @@ lpfc_mbx_cmpl_fcf_scan_read_fcf_rec(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
*/
if (new_fcf_record->fip_priority < fcf_rec->priority) {
/* Choose the new FCF record with lower priority */
+ lpfc_printf_log(phba, KERN_INFO, LOG_FIP,
+ "2838 Update current FCF record "
+ "(x%x) with new FCF record (x%x)\n",
+ fcf_rec->fcf_indx,
+ bf_get(lpfc_fcf_record_fcf_index,
+ new_fcf_record));
__lpfc_update_fcf_record(phba, fcf_rec, new_fcf_record,
addr_mode, vlan_id, 0);
/* Reset running random FCF selection count */
@@ -1857,11 +1934,18 @@ lpfc_mbx_cmpl_fcf_scan_read_fcf_rec(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
phba->fcf.eligible_fcf_cnt++;
select_new_fcf = lpfc_sli4_new_fcf_random_select(phba,
phba->fcf.eligible_fcf_cnt);
- if (select_new_fcf)
+ if (select_new_fcf) {
+ lpfc_printf_log(phba, KERN_INFO, LOG_FIP,
+ "2839 Update current FCF record "
+ "(x%x) with new FCF record (x%x)\n",
+ fcf_rec->fcf_indx,
+ bf_get(lpfc_fcf_record_fcf_index,
+ new_fcf_record));
/* Choose the new FCF by random selection */
__lpfc_update_fcf_record(phba, fcf_rec,
new_fcf_record,
addr_mode, vlan_id, 0);
+ }
}
spin_unlock_irq(&phba->hbalock);
goto read_next_fcf;
@@ -1871,6 +1955,11 @@ lpfc_mbx_cmpl_fcf_scan_read_fcf_rec(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
* initial best-fit FCF.
*/
if (fcf_rec) {
+ lpfc_printf_log(phba, KERN_INFO, LOG_FIP,
+ "2840 Update current FCF record "
+ "with initial FCF record (x%x)\n",
+ bf_get(lpfc_fcf_record_fcf_index,
+ new_fcf_record));
__lpfc_update_fcf_record(phba, fcf_rec, new_fcf_record,
addr_mode, vlan_id, (boot_flag ?
BOOT_ENABLE : 0));
@@ -1928,12 +2017,23 @@ read_next_fcf:
lpfc_unregister_fcf(phba);
/* Replace in-use record with the new record */
+ lpfc_printf_log(phba, KERN_INFO, LOG_FIP,
+ "2842 Replace the current in-use "
+ "FCF record (x%x) with failover FCF "
+ "record (x%x)\n",
+ phba->fcf.current_rec.fcf_indx,
+ phba->fcf.failover_rec.fcf_indx);
memcpy(&phba->fcf.current_rec,
&phba->fcf.failover_rec,
sizeof(struct lpfc_fcf_rec));
- /* mark the FCF fast failover completed */
+ /*
+ * Mark the fast FCF failover rediscovery completed
+ * and the start of the first round of the roundrobin
+ * FCF failover.
+ */
spin_lock_irq(&phba->hbalock);
- phba->fcf.fcf_flag &= ~FCF_REDISC_FOV;
+ phba->fcf.fcf_flag &=
+ ~(FCF_REDISC_FOV | FCF_REDISC_RRU);
spin_unlock_irq(&phba->hbalock);
/*
* Set up the initial registered FCF index for FLOGI
@@ -1951,15 +2051,42 @@ read_next_fcf:
if ((phba->fcf.fcf_flag & FCF_REDISC_EVT) ||
(phba->fcf.fcf_flag & FCF_REDISC_PEND))
return;
+
+ if (phba->fcf.fcf_flag & FCF_IN_USE) {
+ /*
+ * In case the current in-use FCF record no
+ * longer existed during FCF discovery that
+ * was not triggered by fast FCF failover
+ * process, treat it as fast FCF failover.
+ */
+ lpfc_printf_log(phba, KERN_INFO, LOG_FIP,
+ "2841 In-use FCF record (x%x) "
+ "not reported, entering fast "
+ "FCF failover mode scanning.\n",
+ phba->fcf.current_rec.fcf_indx);
+ spin_lock_irq(&phba->hbalock);
+ phba->fcf.fcf_flag |= FCF_REDISC_FOV;
+ spin_unlock_irq(&phba->hbalock);
+ lpfc_sli4_mbox_cmd_free(phba, mboxq);
+ lpfc_sli4_fcf_scan_read_fcf_rec(phba,
+ LPFC_FCOE_FCF_GET_FIRST);
+ return;
+ }
+
/*
* Otherwise, initial scan or post linkdown rescan,
* register with the best FCF record found so far
* through the FCF scanning process.
*/
- /* mark the initial FCF discovery completed */
+ /*
+ * Mark the initial FCF discovery completed and
+ * the start of the first round of the roundrobin
+ * FCF failover.
+ */
spin_lock_irq(&phba->hbalock);
- phba->fcf.fcf_flag &= ~FCF_INIT_DISC;
+ phba->fcf.fcf_flag &=
+ ~(FCF_INIT_DISC | FCF_REDISC_RRU);
spin_unlock_irq(&phba->hbalock);
/*
* Set up the initial registered FCF index for FLOGI
@@ -2033,6 +2160,11 @@ lpfc_mbx_cmpl_fcf_rr_read_fcf_rec(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
next_fcf_index);
/* Upload new FCF record to the failover FCF record */
+ lpfc_printf_log(phba, KERN_INFO, LOG_FIP,
+ "2834 Update the current FCF record (x%x) "
+ "with the next FCF record (x%x)\n",
+ phba->fcf.failover_rec.fcf_indx,
+ bf_get(lpfc_fcf_record_fcf_index, new_fcf_record));
spin_lock_irq(&phba->hbalock);
__lpfc_update_fcf_record(phba, &phba->fcf.failover_rec,
new_fcf_record, addr_mode, vlan_id,
@@ -2050,7 +2182,7 @@ lpfc_mbx_cmpl_fcf_rr_read_fcf_rec(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
lpfc_printf_log(phba, KERN_INFO, LOG_FIP,
"2783 FLOGI round robin FCF failover from FCF "
- "(index:x%x) to FCF (index:x%x).\n",
+ "(x%x) to FCF (x%x).\n",
current_fcf_index,
bf_get(lpfc_fcf_record_fcf_index, new_fcf_record));
@@ -2084,7 +2216,7 @@ lpfc_mbx_cmpl_read_fcf_rec(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
goto out;
/* If FCF discovery period is over, no need to proceed */
- if (phba->fcf.fcf_flag & FCF_DISCOVERY)
+ if (!(phba->fcf.fcf_flag & FCF_DISCOVERY))
goto out;
/* Parse the FCF record from the non-embedded mailbox command */
@@ -2715,11 +2847,35 @@ lpfc_mbx_cmpl_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
struct lpfc_vport *vport = pmb->vport;
struct lpfc_dmabuf *mp = (struct lpfc_dmabuf *) (pmb->context1);
struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *) pmb->context2;
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
pmb->context1 = NULL;
- /* Good status, call state machine */
- lpfc_disc_state_machine(vport, ndlp, pmb, NLP_EVT_CMPL_REG_LOGIN);
+ if (ndlp->nlp_flag & NLP_REG_LOGIN_SEND)
+ ndlp->nlp_flag &= ~NLP_REG_LOGIN_SEND;
+
+ if (ndlp->nlp_flag & NLP_IGNR_REG_CMPL ||
+ ndlp->nlp_state != NLP_STE_REG_LOGIN_ISSUE) {
+ /* We rcvd a rscn after issuing this
+ * mbox reg login, we may have cycled
+ * back through the state and be
+ * back at reg login state so this
+ * mbox needs to be ignored becase
+ * there is another reg login in
+ * proccess.
+ */
+ spin_lock_irq(shost->host_lock);
+ ndlp->nlp_flag &= ~NLP_IGNR_REG_CMPL;
+ spin_unlock_irq(shost->host_lock);
+ if (phba->sli_rev == LPFC_SLI_REV4)
+ lpfc_sli4_free_rpi(phba,
+ pmb->u.mb.un.varRegLogin.rpi);
+
+ } else
+ /* Good status, call state machine */
+ 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);
@@ -3427,7 +3583,7 @@ lpfc_initialize_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
kref_init(&ndlp->kref);
NLP_INT_NODE_ACT(ndlp);
atomic_set(&ndlp->cmd_pending, 0);
- ndlp->cmd_qdepth = LPFC_MAX_TGT_QDEPTH;
+ ndlp->cmd_qdepth = vport->cfg_tgt_queue_depth;
}
struct lpfc_nodelist *
@@ -3700,6 +3856,7 @@ lpfc_unreg_rpi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
mempool_free(mbox, phba->mbox_mem_pool);
}
lpfc_no_rpi(phba, ndlp);
+
ndlp->nlp_rpi = 0;
ndlp->nlp_flag &= ~NLP_RPI_VALID;
ndlp->nlp_flag &= ~NLP_NPR_ADISC;
@@ -3842,6 +3999,9 @@ lpfc_cleanup_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
kfree(mp);
}
list_del(&mb->list);
+ if (phba->sli_rev == LPFC_SLI_REV4)
+ lpfc_sli4_free_rpi(phba,
+ mb->u.mb.un.varRegLogin.rpi);
mempool_free(mb, phba->mbox_mem_pool);
/* We shall not invoke the lpfc_nlp_put to decrement
* the ndlp reference count as we are in the process
@@ -3883,6 +4043,7 @@ lpfc_nlp_remove(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
lpfc_cancel_retry_delay_tmo(vport, ndlp);
if ((ndlp->nlp_flag & NLP_DEFER_RM) &&
+ !(ndlp->nlp_flag & NLP_REG_LOGIN_SEND) &&
!(ndlp->nlp_flag & NLP_RPI_VALID)) {
/* For this case we need to cleanup the default rpi
* allocated by the firmware.
@@ -5180,13 +5341,16 @@ void
lpfc_unregister_unused_fcf(struct lpfc_hba *phba)
{
/*
- * If HBA is not running in FIP mode or if HBA does not support
- * FCoE or if FCF is not registered, do nothing.
+ * If HBA is not running in FIP mode, if HBA does not support
+ * FCoE, if FCF discovery is ongoing, or if FCF has not been
+ * registered, do nothing.
*/
spin_lock_irq(&phba->hbalock);
if (!(phba->hba_flag & HBA_FCOE_SUPPORT) ||
!(phba->fcf.fcf_flag & FCF_REGISTERED) ||
- !(phba->hba_flag & HBA_FIP_SUPPORT)) {
+ !(phba->hba_flag & HBA_FIP_SUPPORT) ||
+ (phba->fcf.fcf_flag & FCF_DISCOVERY) ||
+ (phba->pport->port_state == LPFC_FLOGI)) {
spin_unlock_irq(&phba->hbalock);
return;
}
diff --git a/drivers/scsi/lpfc/lpfc_hw.h b/drivers/scsi/lpfc/lpfc_hw.h
index e654d01dad2..f5dbf2be3ea 100644
--- a/drivers/scsi/lpfc/lpfc_hw.h
+++ b/drivers/scsi/lpfc/lpfc_hw.h
@@ -1170,6 +1170,7 @@ typedef struct {
#define PCI_DEVICE_ID_TIGERSHARK 0x0704
#define PCI_DEVICE_ID_TOMCAT 0x0714
#define PCI_DEVICE_ID_FALCON 0xf180
+#define PCI_DEVICE_ID_BALIUS 0xe131
#define JEDEC_ID_ADDRESS 0x0080001c
#define FIREFLY_JEDEC_ID 0x1ACC
@@ -3014,18 +3015,10 @@ struct sli3_pgp {
uint32_t hbq_get[16];
};
-struct sli3_inb_pgp {
- uint32_t ha_copy;
- uint32_t counter;
- struct lpfc_pgp port[MAX_RINGS];
- uint32_t hbq_get[16];
-};
-
union sli_var {
struct sli2_desc s2;
struct sli3_desc s3;
struct sli3_pgp s3_pgp;
- struct sli3_inb_pgp s3_inb_pgp;
};
typedef struct {
@@ -3132,6 +3125,14 @@ typedef struct {
#define IOERR_BUFFER_SHORTAGE 0x28
#define IOERR_DEFAULT 0x29
#define IOERR_CNT 0x2A
+#define IOERR_SLER_FAILURE 0x46
+#define IOERR_SLER_CMD_RCV_FAILURE 0x47
+#define IOERR_SLER_REC_RJT_ERR 0x48
+#define IOERR_SLER_REC_SRR_RETRY_ERR 0x49
+#define IOERR_SLER_SRR_RJT_ERR 0x4A
+#define IOERR_SLER_RRQ_RJT_ERR 0x4C
+#define IOERR_SLER_RRQ_RETRY_ERR 0x4D
+#define IOERR_SLER_ABTS_ERR 0x4E
#define IOERR_DRVR_MASK 0x100
#define IOERR_SLI_DOWN 0x101 /* ulpStatus - Driver defined */
diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c
index cd9697edf86..2786ee3b605 100644
--- a/drivers/scsi/lpfc/lpfc_init.c
+++ b/drivers/scsi/lpfc/lpfc_init.c
@@ -621,6 +621,7 @@ lpfc_config_port_post(struct lpfc_hba *phba)
/**
* lpfc_hba_init_link - Initialize the FC link
* @phba: pointer to lpfc hba data structure.
+ * @flag: mailbox command issue mode - either MBX_POLL or MBX_NOWAIT
*
* This routine will issue the INIT_LINK mailbox command call.
* It is available to other drivers through the lpfc_hba data
@@ -632,7 +633,7 @@ lpfc_config_port_post(struct lpfc_hba *phba)
* Any other value - error
**/
int
-lpfc_hba_init_link(struct lpfc_hba *phba)
+lpfc_hba_init_link(struct lpfc_hba *phba, uint32_t flag)
{
struct lpfc_vport *vport = phba->pport;
LPFC_MBOXQ_t *pmb;
@@ -651,7 +652,7 @@ lpfc_hba_init_link(struct lpfc_hba *phba)
phba->cfg_link_speed);
pmb->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
lpfc_set_loopback_flag(phba);
- rc = lpfc_sli_issue_mbox(phba, pmb, MBX_NOWAIT);
+ rc = lpfc_sli_issue_mbox(phba, pmb, flag);
if (rc != MBX_SUCCESS) {
lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
"0498 Adapter failed to init, mbxCmd x%x "
@@ -664,17 +665,21 @@ lpfc_hba_init_link(struct lpfc_hba *phba)
writel(0xffffffff, phba->HAregaddr);
readl(phba->HAregaddr); /* flush */
phba->link_state = LPFC_HBA_ERROR;
- if (rc != MBX_BUSY)
+ if (rc != MBX_BUSY || flag == MBX_POLL)
mempool_free(pmb, phba->mbox_mem_pool);
return -EIO;
}
phba->cfg_suppress_link_up = LPFC_INITIALIZE_LINK;
+ if (flag == MBX_POLL)
+ mempool_free(pmb, phba->mbox_mem_pool);
return 0;
}
/**
* lpfc_hba_down_link - this routine downs the FC link
+ * @phba: pointer to lpfc hba data structure.
+ * @flag: mailbox command issue mode - either MBX_POLL or MBX_NOWAIT
*
* This routine will issue the DOWN_LINK mailbox command call.
* It is available to other drivers through the lpfc_hba data
@@ -685,7 +690,7 @@ lpfc_hba_init_link(struct lpfc_hba *phba)
* Any other value - error
**/
int
-lpfc_hba_down_link(struct lpfc_hba *phba)
+lpfc_hba_down_link(struct lpfc_hba *phba, uint32_t flag)
{
LPFC_MBOXQ_t *pmb;
int rc;
@@ -701,7 +706,7 @@ lpfc_hba_down_link(struct lpfc_hba *phba)
"0491 Adapter Link is disabled.\n");
lpfc_down_link(phba, pmb);
pmb->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
- rc = lpfc_sli_issue_mbox(phba, pmb, MBX_NOWAIT);
+ rc = lpfc_sli_issue_mbox(phba, pmb, flag);
if ((rc != MBX_SUCCESS) && (rc != MBX_BUSY)) {
lpfc_printf_log(phba,
KERN_ERR, LOG_INIT,
@@ -711,6 +716,9 @@ lpfc_hba_down_link(struct lpfc_hba *phba)
mempool_free(pmb, phba->mbox_mem_pool);
return -EIO;
}
+ if (flag == MBX_POLL)
+ mempool_free(pmb, phba->mbox_mem_pool);
+
return 0;
}
@@ -1818,6 +1826,10 @@ lpfc_get_hba_model_desc(struct lpfc_hba *phba, uint8_t *mdp, uint8_t *descp)
m = (typeof(m)){"LPSe12002-ML1-E", "PCIe",
"EmulexSecure Fibre"};
break;
+ case PCI_DEVICE_ID_BALIUS:
+ m = (typeof(m)){"LPVe12002", "PCIe Shared I/O",
+ "Fibre Channel Adapter"};
+ break;
default:
m = (typeof(m)){"Unknown", "", ""};
break;
@@ -2279,10 +2291,32 @@ static void
lpfc_block_mgmt_io(struct lpfc_hba * phba)
{
unsigned long iflag;
+ uint8_t actcmd = MBX_HEARTBEAT;
+ unsigned long timeout;
+
spin_lock_irqsave(&phba->hbalock, iflag);
phba->sli.sli_flag |= LPFC_BLOCK_MGMT_IO;
+ if (phba->sli.mbox_active)
+ actcmd = phba->sli.mbox_active->u.mb.mbxCommand;
spin_unlock_irqrestore(&phba->hbalock, iflag);
+ /* Determine how long we might wait for the active mailbox
+ * command to be gracefully completed by firmware.
+ */
+ timeout = msecs_to_jiffies(lpfc_mbox_tmo_val(phba, actcmd) * 1000) +
+ jiffies;
+ /* Wait for the outstnading mailbox command to complete */
+ while (phba->sli.mbox_active) {
+ /* Check active mailbox complete status every 2ms */
+ msleep(2);
+ if (time_after(jiffies, timeout)) {
+ lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+ "2813 Mgmt IO is Blocked %x "
+ "- mbox cmd %x still active\n",
+ phba->sli.sli_flag, actcmd);
+ break;
+ }
+ }
}
/**
@@ -3323,22 +3357,14 @@ lpfc_sli4_async_fcoe_evt(struct lpfc_hba *phba,
"evt_tag:x%x, fcf_index:x%x\n",
acqe_fcoe->event_tag,
acqe_fcoe->index);
+ /* If the FCF discovery is in progress, do nothing. */
spin_lock_irq(&phba->hbalock);
- if ((phba->fcf.fcf_flag & FCF_SCAN_DONE) ||
- (phba->hba_flag & FCF_DISC_INPROGRESS)) {
- /*
- * If the current FCF is in discovered state or
- * FCF discovery is in progress, do nothing.
- */
+ if (phba->hba_flag & FCF_DISC_INPROGRESS) {
spin_unlock_irq(&phba->hbalock);
break;
}
-
+ /* If fast FCF failover rescan event is pending, do nothing */
if (phba->fcf.fcf_flag & FCF_REDISC_EVT) {
- /*
- * If fast FCF failover rescan event is pending,
- * do nothing.
- */
spin_unlock_irq(&phba->hbalock);
break;
}
@@ -3359,7 +3385,13 @@ lpfc_sli4_async_fcoe_evt(struct lpfc_hba *phba,
acqe_fcoe->index);
rc = lpfc_sli4_read_fcf_rec(phba, acqe_fcoe->index);
}
-
+ /* If the FCF has been in discovered state, do nothing. */
+ spin_lock_irq(&phba->hbalock);
+ if (phba->fcf.fcf_flag & FCF_SCAN_DONE) {
+ spin_unlock_irq(&phba->hbalock);
+ break;
+ }
+ spin_unlock_irq(&phba->hbalock);
/* Otherwise, scan the entire FCF table and re-discover SAN */
lpfc_printf_log(phba, KERN_INFO, LOG_FIP | LOG_DISCOVERY,
"2770 Start FCF table scan due to new FCF "
@@ -4885,6 +4917,7 @@ lpfc_create_shost(struct lpfc_hba *phba)
phba->fc_altov = FF_DEF_ALTOV;
phba->fc_arbtov = FF_DEF_ARBTOV;
+ atomic_set(&phba->sdev_cnt, 0);
vport = lpfc_create_port(phba, phba->brd_no, &phba->pcidev->dev);
if (!vport)
return -ENODEV;
@@ -5533,9 +5566,12 @@ lpfc_sli4_read_config(struct lpfc_hba *phba)
mempool_free(pmb, phba->mbox_mem_pool);
/* Reset the DFT_HBA_Q_DEPTH to the max xri */
- if (phba->cfg_hba_queue_depth > (phba->sli4_hba.max_cfg_param.max_xri))
+ if (phba->cfg_hba_queue_depth >
+ (phba->sli4_hba.max_cfg_param.max_xri -
+ lpfc_sli4_get_els_iocb_cnt(phba)))
phba->cfg_hba_queue_depth =
- phba->sli4_hba.max_cfg_param.max_xri;
+ phba->sli4_hba.max_cfg_param.max_xri -
+ lpfc_sli4_get_els_iocb_cnt(phba);
return rc;
}
@@ -6993,22 +7029,28 @@ lpfc_sli_disable_intr(struct lpfc_hba *phba)
static int
lpfc_sli4_enable_msix(struct lpfc_hba *phba)
{
- int rc, index;
+ int vectors, rc, index;
/* Set up MSI-X multi-message vectors */
for (index = 0; index < phba->sli4_hba.cfg_eqn; index++)
phba->sli4_hba.msix_entries[index].entry = index;
/* Configure MSI-X capability structure */
+ vectors = phba->sli4_hba.cfg_eqn;
+enable_msix_vectors:
rc = pci_enable_msix(phba->pcidev, phba->sli4_hba.msix_entries,
- phba->sli4_hba.cfg_eqn);
- if (rc) {
+ vectors);
+ if (rc > 1) {
+ vectors = rc;
+ goto enable_msix_vectors;
+ } else if (rc) {
lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
"0484 PCI enable MSI-X failed (%d)\n", rc);
goto msi_fail_out;
}
+
/* Log MSI-X vector assignment */
- for (index = 0; index < phba->sli4_hba.cfg_eqn; index++)
+ for (index = 0; index < vectors; index++)
lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
"0489 MSI-X entry[%d]: vector=x%x "
"message=%d\n", index,
@@ -7030,7 +7072,7 @@ lpfc_sli4_enable_msix(struct lpfc_hba *phba)
}
/* The rest of the vector(s) are associated to fast-path handler(s) */
- for (index = 1; index < phba->sli4_hba.cfg_eqn; index++) {
+ for (index = 1; index < vectors; index++) {
phba->sli4_hba.fcp_eq_hdl[index - 1].idx = index - 1;
phba->sli4_hba.fcp_eq_hdl[index - 1].phba = phba;
rc = request_irq(phba->sli4_hba.msix_entries[index].vector,
@@ -7044,6 +7086,7 @@ lpfc_sli4_enable_msix(struct lpfc_hba *phba)
goto cfg_fail_out;
}
}
+ phba->sli4_hba.msix_vec_nr = vectors;
return rc;
@@ -7077,9 +7120,10 @@ lpfc_sli4_disable_msix(struct lpfc_hba *phba)
/* Free up MSI-X multi-message vectors */
free_irq(phba->sli4_hba.msix_entries[0].vector, phba);
- for (index = 1; index < phba->sli4_hba.cfg_eqn; index++)
+ for (index = 1; index < phba->sli4_hba.msix_vec_nr; index++)
free_irq(phba->sli4_hba.msix_entries[index].vector,
&phba->sli4_hba.fcp_eq_hdl[index - 1]);
+
/* Disable MSI-X */
pci_disable_msix(phba->pcidev);
@@ -7121,6 +7165,7 @@ lpfc_sli4_enable_msi(struct lpfc_hba *phba)
pci_disable_msi(phba->pcidev);
lpfc_printf_log(phba, KERN_WARNING, LOG_INIT,
"0490 MSI request_irq failed (%d)\n", rc);
+ return rc;
}
for (index = 0; index < phba->cfg_fcp_eq_count; index++) {
@@ -7128,7 +7173,7 @@ lpfc_sli4_enable_msi(struct lpfc_hba *phba)
phba->sli4_hba.fcp_eq_hdl[index].phba = phba;
}
- return rc;
+ return 0;
}
/**
@@ -7839,6 +7884,9 @@ lpfc_sli_prep_dev_for_reset(struct lpfc_hba *phba)
lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
"2710 PCI channel disable preparing for reset\n");
+ /* Block any management I/Os to the device */
+ lpfc_block_mgmt_io(phba);
+
/* Block all SCSI devices' I/Os on the host */
lpfc_scsi_dev_block(phba);
@@ -7848,6 +7896,7 @@ lpfc_sli_prep_dev_for_reset(struct lpfc_hba *phba)
/* Disable interrupt and pci device */
lpfc_sli_disable_intr(phba);
pci_disable_device(phba->pcidev);
+
/* Flush all driver's outstanding SCSI I/Os as we are to reset */
lpfc_sli_flush_fcp_rings(phba);
}
@@ -7861,7 +7910,7 @@ lpfc_sli_prep_dev_for_reset(struct lpfc_hba *phba)
* pending I/Os.
**/
static void
-lpfc_prep_dev_for_perm_failure(struct lpfc_hba *phba)
+lpfc_sli_prep_dev_for_perm_failure(struct lpfc_hba *phba)
{
lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
"2711 PCI channel permanent disable for failure\n");
@@ -7910,7 +7959,7 @@ lpfc_io_error_detected_s3(struct pci_dev *pdev, pci_channel_state_t state)
return PCI_ERS_RESULT_NEED_RESET;
case pci_channel_io_perm_failure:
/* Permanent failure, prepare for device down */
- lpfc_prep_dev_for_perm_failure(phba);
+ lpfc_sli_prep_dev_for_perm_failure(phba);
return PCI_ERS_RESULT_DISCONNECT;
default:
/* Unknown state, prepare and request slot reset */
@@ -7979,7 +8028,8 @@ lpfc_io_slot_reset_s3(struct pci_dev *pdev)
} else
phba->intr_mode = intr_mode;
- /* Take device offline; this will perform cleanup */
+ /* Take device offline, it will perform cleanup */
+ lpfc_offline_prep(phba);
lpfc_offline(phba);
lpfc_sli_brdrestart(phba);
@@ -8110,8 +8160,12 @@ lpfc_pci_probe_one_s4(struct pci_dev *pdev, const struct pci_device_id *pid)
}
/* Initialize and populate the iocb list per host */
- error = lpfc_init_iocb_list(phba,
- phba->sli4_hba.max_cfg_param.max_xri);
+
+ lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
+ "2821 initialize iocb list %d.\n",
+ phba->cfg_iocb_cnt*1024);
+ error = lpfc_init_iocb_list(phba, phba->cfg_iocb_cnt*1024);
+
if (error) {
lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
"1413 Failed to initialize iocb list.\n");
@@ -8160,6 +8214,8 @@ lpfc_pci_probe_one_s4(struct pci_dev *pdev, const struct pci_device_id *pid)
/* Default to single FCP EQ for non-MSI-X */
if (phba->intr_type != MSIX)
phba->cfg_fcp_eq_count = 1;
+ else if (phba->sli4_hba.msix_vec_nr < phba->cfg_fcp_eq_count)
+ phba->cfg_fcp_eq_count = phba->sli4_hba.msix_vec_nr - 1;
/* Set up SLI-4 HBA */
if (lpfc_sli4_hba_setup(phba)) {
lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
@@ -8321,7 +8377,7 @@ lpfc_pci_suspend_one_s4(struct pci_dev *pdev, pm_message_t msg)
struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba;
lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
- "0298 PCI device Power Management suspend.\n");
+ "2843 PCI device Power Management suspend.\n");
/* Bring down the device */
lpfc_offline_prep(phba);
@@ -8412,6 +8468,84 @@ lpfc_pci_resume_one_s4(struct pci_dev *pdev)
}
/**
+ * lpfc_sli4_prep_dev_for_recover - Prepare SLI4 device for pci slot recover
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine is called to prepare the SLI4 device for PCI slot recover. It
+ * aborts all the outstanding SCSI I/Os to the pci device.
+ **/
+static void
+lpfc_sli4_prep_dev_for_recover(struct lpfc_hba *phba)
+{
+ struct lpfc_sli *psli = &phba->sli;
+ struct lpfc_sli_ring *pring;
+
+ lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+ "2828 PCI channel I/O abort preparing for recovery\n");
+ /*
+ * There may be errored I/Os through HBA, abort all I/Os on txcmplq
+ * and let the SCSI mid-layer to retry them to recover.
+ */
+ pring = &psli->ring[psli->fcp_ring];
+ lpfc_sli_abort_iocb_ring(phba, pring);
+}
+
+/**
+ * lpfc_sli4_prep_dev_for_reset - Prepare SLI4 device for pci slot reset
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine is called to prepare the SLI4 device for PCI slot reset. It
+ * disables the device interrupt and pci device, and aborts the internal FCP
+ * pending I/Os.
+ **/
+static void
+lpfc_sli4_prep_dev_for_reset(struct lpfc_hba *phba)
+{
+ lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+ "2826 PCI channel disable preparing for reset\n");
+
+ /* Block any management I/Os to the device */
+ lpfc_block_mgmt_io(phba);
+
+ /* Block all SCSI devices' I/Os on the host */
+ lpfc_scsi_dev_block(phba);
+
+ /* stop all timers */
+ lpfc_stop_hba_timers(phba);
+
+ /* Disable interrupt and pci device */
+ lpfc_sli4_disable_intr(phba);
+ pci_disable_device(phba->pcidev);
+
+ /* Flush all driver's outstanding SCSI I/Os as we are to reset */
+ lpfc_sli_flush_fcp_rings(phba);
+}
+
+/**
+ * lpfc_sli4_prep_dev_for_perm_failure - Prepare SLI4 dev for pci slot disable
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine is called to prepare the SLI4 device for PCI slot permanently
+ * disabling. It blocks the SCSI transport layer traffic and flushes the FCP
+ * pending I/Os.
+ **/
+static void
+lpfc_sli4_prep_dev_for_perm_failure(struct lpfc_hba *phba)
+{
+ lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+ "2827 PCI channel permanent disable for failure\n");
+
+ /* Block all SCSI devices' I/Os on the host */
+ lpfc_scsi_dev_block(phba);
+
+ /* stop all timers */
+ lpfc_stop_hba_timers(phba);
+
+ /* Clean up all driver's outstanding SCSI I/Os */
+ lpfc_sli_flush_fcp_rings(phba);
+}
+
+/**
* lpfc_io_error_detected_s4 - Method for handling PCI I/O error to SLI-4 device
* @pdev: pointer to PCI device.
* @state: the current PCI connection state.
@@ -8430,7 +8564,29 @@ lpfc_pci_resume_one_s4(struct pci_dev *pdev)
static pci_ers_result_t
lpfc_io_error_detected_s4(struct pci_dev *pdev, pci_channel_state_t state)
{
- return PCI_ERS_RESULT_NEED_RESET;
+ struct Scsi_Host *shost = pci_get_drvdata(pdev);
+ struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba;
+
+ switch (state) {
+ case pci_channel_io_normal:
+ /* Non-fatal error, prepare for recovery */
+ lpfc_sli4_prep_dev_for_recover(phba);
+ return PCI_ERS_RESULT_CAN_RECOVER;
+ case pci_channel_io_frozen:
+ /* Fatal error, prepare for slot reset */
+ lpfc_sli4_prep_dev_for_reset(phba);
+ return PCI_ERS_RESULT_NEED_RESET;
+ case pci_channel_io_perm_failure:
+ /* Permanent failure, prepare for device down */
+ lpfc_sli4_prep_dev_for_perm_failure(phba);
+ return PCI_ERS_RESULT_DISCONNECT;
+ default:
+ /* Unknown state, prepare and request slot reset */
+ lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+ "2825 Unknown PCI error state: x%x\n", state);
+ lpfc_sli4_prep_dev_for_reset(phba);
+ return PCI_ERS_RESULT_NEED_RESET;
+ }
}
/**
@@ -8454,6 +8610,39 @@ lpfc_io_error_detected_s4(struct pci_dev *pdev, pci_channel_state_t state)
static pci_ers_result_t
lpfc_io_slot_reset_s4(struct pci_dev *pdev)
{
+ struct Scsi_Host *shost = pci_get_drvdata(pdev);
+ struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba;
+ struct lpfc_sli *psli = &phba->sli;
+ uint32_t intr_mode;
+
+ dev_printk(KERN_INFO, &pdev->dev, "recovering from a slot reset.\n");
+ if (pci_enable_device_mem(pdev)) {
+ printk(KERN_ERR "lpfc: Cannot re-enable "
+ "PCI device after reset.\n");
+ return PCI_ERS_RESULT_DISCONNECT;
+ }
+
+ pci_restore_state(pdev);
+ if (pdev->is_busmaster)
+ pci_set_master(pdev);
+
+ spin_lock_irq(&phba->hbalock);
+ psli->sli_flag &= ~LPFC_SLI_ACTIVE;
+ spin_unlock_irq(&phba->hbalock);
+
+ /* Configure and enable interrupt */
+ intr_mode = lpfc_sli4_enable_intr(phba, phba->intr_mode);
+ if (intr_mode == LPFC_INTR_ERROR) {
+ lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+ "2824 Cannot re-enable interrupt after "
+ "slot reset.\n");
+ return PCI_ERS_RESULT_DISCONNECT;
+ } else
+ phba->intr_mode = intr_mode;
+
+ /* Log the current active interrupt mode */
+ lpfc_log_intr_mode(phba, phba->intr_mode);
+
return PCI_ERS_RESULT_RECOVERED;
}
@@ -8470,7 +8659,27 @@ lpfc_io_slot_reset_s4(struct pci_dev *pdev)
static void
lpfc_io_resume_s4(struct pci_dev *pdev)
{
- return;
+ struct Scsi_Host *shost = pci_get_drvdata(pdev);
+ struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba;
+
+ /*
+ * In case of slot reset, as function reset is performed through
+ * mailbox command which needs DMA to be enabled, this operation
+ * has to be moved to the io resume phase. Taking device offline
+ * will perform the necessary cleanup.
+ */
+ if (!(phba->sli.sli_flag & LPFC_SLI_ACTIVE)) {
+ /* Perform device reset */
+ lpfc_offline_prep(phba);
+ lpfc_offline(phba);
+ lpfc_sli_brdrestart(phba);
+ /* Bring the device back online */
+ lpfc_online(phba);
+ }
+
+ /* Clean up Advanced Error Reporting (AER) if needed */
+ if (phba->hba_flag & HBA_AER_ENABLED)
+ pci_cleanup_aer_uncorrect_error_status(pdev);
}
/**
@@ -8802,6 +9011,8 @@ static struct pci_device_id lpfc_id_table[] = {
PCI_ANY_ID, PCI_ANY_ID, },
{PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_FALCON,
PCI_ANY_ID, PCI_ANY_ID, },
+ {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_BALIUS,
+ PCI_ANY_ID, PCI_ANY_ID, },
{ 0 }
};
diff --git a/drivers/scsi/lpfc/lpfc_mbox.c b/drivers/scsi/lpfc/lpfc_mbox.c
index e84dc33ca20..9c2c7c7140c 100644
--- a/drivers/scsi/lpfc/lpfc_mbox.c
+++ b/drivers/scsi/lpfc/lpfc_mbox.c
@@ -955,6 +955,26 @@ lpfc_read_rev(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
return;
}
+void
+lpfc_sli4_swap_str(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
+{
+ MAILBOX_t *mb = &pmb->u.mb;
+ struct lpfc_mqe *mqe;
+
+ switch (mb->mbxCommand) {
+ case MBX_READ_REV:
+ mqe = &pmb->u.mqe;
+ lpfc_sli_pcimem_bcopy(mqe->un.read_rev.fw_name,
+ mqe->un.read_rev.fw_name, 16);
+ lpfc_sli_pcimem_bcopy(mqe->un.read_rev.ulp_fw_name,
+ mqe->un.read_rev.ulp_fw_name, 16);
+ break;
+ default:
+ break;
+ }
+ return;
+}
+
/**
* lpfc_build_hbq_profile2 - Set up the HBQ Selection Profile 2
* @hbqmb: pointer to the HBQ configuration data structure in mailbox command.
@@ -1199,7 +1219,6 @@ lpfc_config_port(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
mb->un.varCfgPort.cdss = 1; /* Configure Security */
mb->un.varCfgPort.cerbm = 1; /* Request HBQs */
mb->un.varCfgPort.ccrp = 1; /* Command Ring Polling */
- mb->un.varCfgPort.cinb = 1; /* Interrupt Notification Block */
mb->un.varCfgPort.max_hbq = lpfc_sli_hbq_count();
if (phba->max_vpi && phba->cfg_enable_npiv &&
phba->vpd.sli3Feat.cmv) {
@@ -2026,7 +2045,7 @@ lpfc_reg_fcfi(struct lpfc_hba *phba, struct lpfcMboxq *mbox)
phba->fcf.current_rec.fcf_indx);
/* reg_fcf addr mode is bit wise inverted value of fcf addr_mode */
bf_set(lpfc_reg_fcfi_mam, reg_fcfi, (~phba->fcf.addr_mode) & 0x3);
- if (phba->fcf.current_rec.vlan_id != 0xFFFF) {
+ if (phba->fcf.current_rec.vlan_id != LPFC_FCOE_NULL_VID) {
bf_set(lpfc_reg_fcfi_vv, reg_fcfi, 1);
bf_set(lpfc_reg_fcfi_vlan_tag, reg_fcfi,
phba->fcf.current_rec.vlan_id);
diff --git a/drivers/scsi/lpfc/lpfc_nportdisc.c b/drivers/scsi/lpfc/lpfc_nportdisc.c
index b90820a699f..bccc9c66fa3 100644
--- a/drivers/scsi/lpfc/lpfc_nportdisc.c
+++ b/drivers/scsi/lpfc/lpfc_nportdisc.c
@@ -190,6 +190,7 @@ lpfc_check_elscmpl_iocb(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
}
+
/*
* Free resources / clean up outstanding I/Os
* associated with a LPFC_NODELIST entry. This
@@ -199,13 +200,15 @@ int
lpfc_els_abort(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp)
{
LIST_HEAD(completions);
+ LIST_HEAD(txcmplq_completions);
+ LIST_HEAD(abort_list);
struct lpfc_sli *psli = &phba->sli;
struct lpfc_sli_ring *pring = &psli->ring[LPFC_ELS_RING];
struct lpfc_iocbq *iocb, *next_iocb;
/* Abort outstanding I/O on NPort <nlp_DID> */
lpfc_printf_vlog(ndlp->vport, KERN_INFO, LOG_DISCOVERY,
- "0205 Abort outstanding I/O on NPort x%x "
+ "2819 Abort outstanding I/O on NPort x%x "
"Data: x%x x%x x%x\n",
ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state,
ndlp->nlp_rpi);
@@ -224,14 +227,25 @@ 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) {
+ list_splice_init(&pring->txcmplq, &txcmplq_completions);
+ spin_unlock_irq(&phba->hbalock);
+
+ list_for_each_entry_safe(iocb, next_iocb, &txcmplq_completions, list) {
/* 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);
- }
+ if (lpfc_check_sli_ndlp(phba, pring, iocb, ndlp))
+ list_add_tail(&iocb->dlist, &abort_list);
}
+ spin_lock_irq(&phba->hbalock);
+ list_splice(&txcmplq_completions, &pring->txcmplq);
spin_unlock_irq(&phba->hbalock);
+ list_for_each_entry_safe(iocb, next_iocb, &abort_list, dlist) {
+ spin_lock_irq(&phba->hbalock);
+ list_del_init(&iocb->dlist);
+ lpfc_sli_issue_abort_iotag(phba, pring, iocb);
+ spin_unlock_irq(&phba->hbalock);
+ }
+
/* Cancel all the IOCBs from the completions list */
lpfc_sli_cancel_iocbs(phba, &completions, IOSTAT_LOCAL_REJECT,
IOERR_SLI_ABORTED);
@@ -626,7 +640,8 @@ lpfc_disc_set_adisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
if (!(vport->fc_flag & FC_PT2PT)) {
/* Check config parameter use-adisc or FCP-2 */
if ((vport->cfg_use_adisc && (vport->fc_flag & FC_RSCN_MODE)) ||
- ndlp->nlp_fcp_info & NLP_FCP_2_DEVICE) {
+ ((ndlp->nlp_fcp_info & NLP_FCP_2_DEVICE) &&
+ (ndlp->nlp_type & NLP_FCP_TARGET))) {
spin_lock_irq(shost->host_lock);
ndlp->nlp_flag |= NLP_NPR_ADISC;
spin_unlock_irq(shost->host_lock);
@@ -962,6 +977,7 @@ lpfc_cmpl_plogi_plogi_issue(struct lpfc_vport *vport,
mbox->mbox_cmpl = lpfc_mbx_cmpl_fdmi_reg_login;
break;
default:
+ ndlp->nlp_flag |= NLP_REG_LOGIN_SEND;
mbox->mbox_cmpl = lpfc_mbx_cmpl_reg_login;
}
mbox->context2 = lpfc_nlp_get(ndlp);
@@ -972,6 +988,8 @@ lpfc_cmpl_plogi_plogi_issue(struct lpfc_vport *vport,
NLP_STE_REG_LOGIN_ISSUE);
return ndlp->nlp_state;
}
+ if (ndlp->nlp_flag & NLP_REG_LOGIN_SEND)
+ ndlp->nlp_flag &= ~NLP_REG_LOGIN_SEND;
/* decrement node reference count to the failed mbox
* command
*/
@@ -1458,6 +1476,7 @@ lpfc_device_recov_reglogin_issue(struct lpfc_vport *vport,
ndlp->nlp_prev_state = NLP_STE_REG_LOGIN_ISSUE;
lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
spin_lock_irq(shost->host_lock);
+ ndlp->nlp_flag |= NLP_IGNR_REG_CMPL;
ndlp->nlp_flag &= ~(NLP_NODEV_REMOVE | NLP_NPR_2B_DISC);
spin_unlock_irq(shost->host_lock);
lpfc_disc_set_adisc(vport, ndlp);
diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c
index f4a3b2e79ee..c818a725596 100644
--- a/drivers/scsi/lpfc/lpfc_scsi.c
+++ b/drivers/scsi/lpfc/lpfc_scsi.c
@@ -623,6 +623,7 @@ lpfc_sli4_fcp_xri_aborted(struct lpfc_hba *phba,
unsigned long iflag = 0;
struct lpfc_iocbq *iocbq;
int i;
+ struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_ELS_RING];
spin_lock_irqsave(&phba->hbalock, iflag);
spin_lock(&phba->sli4_hba.abts_scsi_buf_list_lock);
@@ -651,6 +652,8 @@ lpfc_sli4_fcp_xri_aborted(struct lpfc_hba *phba,
psb = container_of(iocbq, struct lpfc_scsi_buf, cur_iocbq);
psb->exch_busy = 0;
spin_unlock_irqrestore(&phba->hbalock, iflag);
+ if (pring->txq_cnt)
+ lpfc_worker_wake_up(phba);
return;
}
@@ -747,7 +750,6 @@ lpfc_new_scsi_buf_s4(struct lpfc_vport *vport, int num_to_alloc)
int status = 0, index;
int bcnt;
int non_sequential_xri = 0;
- int rc = 0;
LIST_HEAD(sblist);
for (bcnt = 0; bcnt < num_to_alloc; bcnt++) {
@@ -774,6 +776,8 @@ lpfc_new_scsi_buf_s4(struct lpfc_vport *vport, int num_to_alloc)
/* Allocate iotag for psb->cur_iocbq. */
iotag = lpfc_sli_next_iotag(phba, &psb->cur_iocbq);
if (iotag == 0) {
+ pci_pool_free(phba->lpfc_scsi_dma_buf_pool,
+ psb->data, psb->dma_handle);
kfree(psb);
break;
}
@@ -858,7 +862,6 @@ lpfc_new_scsi_buf_s4(struct lpfc_vport *vport, int num_to_alloc)
if (status) {
/* Put this back on the abort scsi list */
psb->exch_busy = 1;
- rc++;
} else {
psb->exch_busy = 0;
psb->status = IOSTAT_SUCCESS;
@@ -877,7 +880,6 @@ lpfc_new_scsi_buf_s4(struct lpfc_vport *vport, int num_to_alloc)
if (status) {
/* Put this back on the abort scsi list */
psb->exch_busy = 1;
- rc++;
} else {
psb->exch_busy = 0;
psb->status = IOSTAT_SUCCESS;
@@ -887,7 +889,7 @@ lpfc_new_scsi_buf_s4(struct lpfc_vport *vport, int num_to_alloc)
}
}
- return bcnt + non_sequential_xri - rc;
+ return bcnt + non_sequential_xri;
}
/**
@@ -1323,6 +1325,10 @@ lpfc_bg_setup_bpl(struct lpfc_hba *phba, struct scsi_cmnd *sc,
bf_set(pde5_type, pde5, LPFC_PDE5_DESCRIPTOR);
pde5->reftag = reftag;
+ /* Endian convertion if necessary for PDE5 */
+ pde5->word0 = cpu_to_le32(pde5->word0);
+ pde5->reftag = cpu_to_le32(pde5->reftag);
+
/* advance bpl and increment bde count */
num_bde++;
bpl++;
@@ -1341,6 +1347,11 @@ lpfc_bg_setup_bpl(struct lpfc_hba *phba, struct scsi_cmnd *sc,
bf_set(pde6_ai, pde6, 1);
bf_set(pde6_apptagval, pde6, apptagval);
+ /* Endian convertion if necessary for PDE6 */
+ pde6->word0 = cpu_to_le32(pde6->word0);
+ pde6->word1 = cpu_to_le32(pde6->word1);
+ pde6->word2 = cpu_to_le32(pde6->word2);
+
/* advance bpl and increment bde count */
num_bde++;
bpl++;
@@ -1448,6 +1459,10 @@ lpfc_bg_setup_bpl_prot(struct lpfc_hba *phba, struct scsi_cmnd *sc,
bf_set(pde5_type, pde5, LPFC_PDE5_DESCRIPTOR);
pde5->reftag = reftag;
+ /* Endian convertion if necessary for PDE5 */
+ pde5->word0 = cpu_to_le32(pde5->word0);
+ pde5->reftag = cpu_to_le32(pde5->reftag);
+
/* advance bpl and increment bde count */
num_bde++;
bpl++;
@@ -1464,6 +1479,11 @@ lpfc_bg_setup_bpl_prot(struct lpfc_hba *phba, struct scsi_cmnd *sc,
bf_set(pde6_ai, pde6, 1);
bf_set(pde6_apptagval, pde6, apptagval);
+ /* Endian convertion if necessary for PDE6 */
+ pde6->word0 = cpu_to_le32(pde6->word0);
+ pde6->word1 = cpu_to_le32(pde6->word1);
+ pde6->word2 = cpu_to_le32(pde6->word2);
+
/* advance bpl and increment bde count */
num_bde++;
bpl++;
@@ -1475,7 +1495,6 @@ lpfc_bg_setup_bpl_prot(struct lpfc_hba *phba, struct scsi_cmnd *sc,
prot_bde->addrLow = le32_to_cpu(putPaddrHigh(protphysaddr));
protgroup_len = sg_dma_len(sgpe);
-
/* must be integer multiple of the DIF block length */
BUG_ON(protgroup_len % 8);
@@ -2293,15 +2312,21 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn,
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;
+ struct scsi_cmnd *cmd;
int result;
struct scsi_device *tmp_sdev;
int depth;
unsigned long flags;
struct lpfc_fast_path_event *fast_path_evt;
- struct Scsi_Host *shost = cmd->device->host;
+ struct Scsi_Host *shost;
uint32_t queue_depth, scsi_id;
+ /* Sanity check on return of outstanding command */
+ if (!(lpfc_cmd->pCmd))
+ return;
+ cmd = lpfc_cmd->pCmd;
+ shost = cmd->device->host;
+
lpfc_cmd->result = pIocbOut->iocb.un.ulpWord[4];
lpfc_cmd->status = pIocbOut->iocb.ulpStatus;
/* pick up SLI4 exhange busy status from HBA */
@@ -2363,7 +2388,8 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn,
case IOSTAT_LOCAL_REJECT:
if (lpfc_cmd->result == IOERR_INVALID_RPI ||
lpfc_cmd->result == IOERR_NO_RESOURCES ||
- lpfc_cmd->result == IOERR_ABORT_REQUESTED) {
+ lpfc_cmd->result == IOERR_ABORT_REQUESTED ||
+ lpfc_cmd->result == IOERR_SLER_CMD_RCV_FAILURE) {
cmd->result = ScsiResult(DID_REQUEUE, 0);
break;
}
@@ -2432,14 +2458,16 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn,
}
spin_unlock_irqrestore(shost->host_lock, flags);
} else if (pnode && NLP_CHK_NODE_ACT(pnode)) {
- if ((pnode->cmd_qdepth < LPFC_MAX_TGT_QDEPTH) &&
+ if ((pnode->cmd_qdepth < vport->cfg_tgt_queue_depth) &&
time_after(jiffies, pnode->last_change_time +
msecs_to_jiffies(LPFC_TGTQ_INTERVAL))) {
spin_lock_irqsave(shost->host_lock, flags);
- pnode->cmd_qdepth += pnode->cmd_qdepth *
- LPFC_TGTQ_RAMPUP_PCENT / 100;
- if (pnode->cmd_qdepth > LPFC_MAX_TGT_QDEPTH)
- pnode->cmd_qdepth = LPFC_MAX_TGT_QDEPTH;
+ depth = pnode->cmd_qdepth * LPFC_TGTQ_RAMPUP_PCENT
+ / 100;
+ depth = depth ? depth : 1;
+ pnode->cmd_qdepth += depth;
+ if (pnode->cmd_qdepth > vport->cfg_tgt_queue_depth)
+ pnode->cmd_qdepth = vport->cfg_tgt_queue_depth;
pnode->last_change_time = jiffies;
spin_unlock_irqrestore(shost->host_lock, flags);
}
@@ -2894,8 +2922,7 @@ lpfc_queuecommand(struct scsi_cmnd *cmnd, void (*done) (struct scsi_cmnd *))
cmnd->result = ScsiResult(DID_TRANSPORT_DISRUPTED, 0);
goto out_fail_command;
}
- if (vport->cfg_max_scsicmpl_time &&
- (atomic_read(&ndlp->cmd_pending) >= ndlp->cmd_qdepth))
+ if (atomic_read(&ndlp->cmd_pending) >= ndlp->cmd_qdepth)
goto out_host_busy;
lpfc_cmd = lpfc_get_scsi_buf(phba);
@@ -3041,7 +3068,9 @@ lpfc_abort_handler(struct scsi_cmnd *cmnd)
int ret = SUCCESS;
DECLARE_WAIT_QUEUE_HEAD_ONSTACK(waitq);
- fc_block_scsi_eh(cmnd);
+ ret = fc_block_scsi_eh(cmnd);
+ if (ret)
+ return ret;
lpfc_cmd = (struct lpfc_scsi_buf *)cmnd->host_scribble;
BUG_ON(!lpfc_cmd);
@@ -3225,7 +3254,9 @@ lpfc_send_taskmgmt(struct lpfc_vport *vport, struct lpfc_rport_data *rdata,
lpfc_taskmgmt_name(task_mgmt_cmd),
tgt_id, lun_id, iocbqrsp->iocb.ulpStatus,
iocbqrsp->iocb.un.ulpWord[4]);
- } else
+ } else if (status == IOCB_BUSY)
+ ret = FAILED;
+ else
ret = SUCCESS;
lpfc_sli_release_iocbq(phba, iocbqrsp);
@@ -3357,7 +3388,9 @@ lpfc_device_reset_handler(struct scsi_cmnd *cmnd)
return FAILED;
}
pnode = rdata->pnode;
- fc_block_scsi_eh(cmnd);
+ status = fc_block_scsi_eh(cmnd);
+ if (status)
+ return status;
status = lpfc_chk_tgt_mapped(vport, cmnd);
if (status == FAILED) {
@@ -3422,7 +3455,9 @@ lpfc_target_reset_handler(struct scsi_cmnd *cmnd)
return FAILED;
}
pnode = rdata->pnode;
- fc_block_scsi_eh(cmnd);
+ status = fc_block_scsi_eh(cmnd);
+ if (status)
+ return status;
status = lpfc_chk_tgt_mapped(vport, cmnd);
if (status == FAILED) {
@@ -3488,7 +3523,9 @@ lpfc_bus_reset_handler(struct scsi_cmnd *cmnd)
fc_host_post_vendor_event(shost, fc_get_event_number(),
sizeof(scsi_event), (char *)&scsi_event, LPFC_NL_VENDOR_ID);
- fc_block_scsi_eh(cmnd);
+ ret = fc_block_scsi_eh(cmnd);
+ if (ret)
+ return ret;
/*
* Since the driver manages a single bus device, reset all
@@ -3561,11 +3598,13 @@ lpfc_slave_alloc(struct scsi_device *sdev)
uint32_t total = 0;
uint32_t num_to_alloc = 0;
int num_allocated = 0;
+ uint32_t sdev_cnt;
if (!rport || fc_remote_port_chkready(rport))
return -ENXIO;
sdev->hostdata = rport->dd_data;
+ sdev_cnt = atomic_inc_return(&phba->sdev_cnt);
/*
* Populate the cmds_per_lun count scsi_bufs into this host's globally
@@ -3577,6 +3616,10 @@ lpfc_slave_alloc(struct scsi_device *sdev)
total = phba->total_scsi_bufs;
num_to_alloc = vport->cfg_lun_queue_depth + 2;
+ /* If allocated buffers are enough do nothing */
+ if ((sdev_cnt * (vport->cfg_lun_queue_depth + 2)) < total)
+ return 0;
+
/* Allow some exchanges to be available always to complete discovery */
if (total >= phba->cfg_hba_queue_depth - LPFC_DISC_IOCB_BUFF_COUNT ) {
lpfc_printf_vlog(vport, KERN_WARNING, LOG_FCP,
@@ -3658,6 +3701,9 @@ lpfc_slave_configure(struct scsi_device *sdev)
static void
lpfc_slave_destroy(struct scsi_device *sdev)
{
+ struct lpfc_vport *vport = (struct lpfc_vport *) sdev->host->hostdata;
+ struct lpfc_hba *phba = vport->phba;
+ atomic_dec(&phba->sdev_cnt);
sdev->hostdata = NULL;
return;
}
diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c
index 7a61455140b..e758eae0d0f 100644
--- a/drivers/scsi/lpfc/lpfc_sli.c
+++ b/drivers/scsi/lpfc/lpfc_sli.c
@@ -455,6 +455,11 @@ __lpfc_sli_get_iocbq(struct lpfc_hba *phba)
struct lpfc_iocbq * iocbq = NULL;
list_remove_head(lpfc_iocb_list, iocbq, struct lpfc_iocbq, list);
+
+ if (iocbq)
+ phba->iocb_cnt++;
+ if (phba->iocb_cnt > phba->iocb_max)
+ phba->iocb_max = phba->iocb_cnt;
return iocbq;
}
@@ -575,7 +580,8 @@ __lpfc_sli_release_iocbq_s4(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq)
{
struct lpfc_sglq *sglq;
size_t start_clean = offsetof(struct lpfc_iocbq, iocb);
- unsigned long iflag;
+ unsigned long iflag = 0;
+ struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_ELS_RING];
if (iocbq->sli4_xritag == NO_XRI)
sglq = NULL;
@@ -593,6 +599,10 @@ __lpfc_sli_release_iocbq_s4(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq)
} else {
sglq->state = SGL_FREED;
list_add(&sglq->list, &phba->sli4_hba.lpfc_sgl_list);
+
+ /* Check if TXQ queue needs to be serviced */
+ if (pring->txq_cnt)
+ lpfc_worker_wake_up(phba);
}
}
@@ -605,6 +615,7 @@ __lpfc_sli_release_iocbq_s4(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq)
list_add_tail(&iocbq->list, &phba->lpfc_iocb_list);
}
+
/**
* __lpfc_sli_release_iocbq_s3 - Release iocb to the iocb pool
* @phba: Pointer to HBA context object.
@@ -642,6 +653,7 @@ static void
__lpfc_sli_release_iocbq(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq)
{
phba->__lpfc_sli_release_iocbq(phba, iocbq);
+ phba->iocb_cnt--;
}
/**
@@ -872,7 +884,11 @@ lpfc_sli_ringtxcmpl_put(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
struct lpfc_iocbq *piocb)
{
list_add_tail(&piocb->list, &pring->txcmplq);
+ piocb->iocb_flag |= LPFC_IO_ON_Q;
pring->txcmplq_cnt++;
+ if (pring->txcmplq_cnt > pring->txcmplq_max)
+ pring->txcmplq_max = pring->txcmplq_cnt;
+
if ((unlikely(pring->ringno == LPFC_ELS_RING)) &&
(piocb->iocb.ulpCommand != CMD_ABORT_XRI_CN) &&
(piocb->iocb.ulpCommand != CMD_CLOSE_XRI_CN)) {
@@ -897,7 +913,7 @@ lpfc_sli_ringtxcmpl_put(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
* the txq, the function returns first iocb in the list after
* removing the iocb from the list, else it returns NULL.
**/
-static struct lpfc_iocbq *
+struct lpfc_iocbq *
lpfc_sli_ringtx_get(struct lpfc_hba *phba, struct lpfc_sli_ring *pring)
{
struct lpfc_iocbq *cmd_iocb;
@@ -2150,7 +2166,10 @@ 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_init(&cmd_iocb->list);
- pring->txcmplq_cnt--;
+ if (cmd_iocb->iocb_flag & LPFC_IO_ON_Q) {
+ pring->txcmplq_cnt--;
+ cmd_iocb->iocb_flag &= ~LPFC_IO_ON_Q;
+ }
return cmd_iocb;
}
@@ -2183,7 +2202,10 @@ lpfc_sli_iocbq_lookup_by_tag(struct lpfc_hba *phba,
if (iotag != 0 && iotag <= phba->sli.last_iotag) {
cmd_iocb = phba->sli.iocbq_lookup[iotag];
list_del_init(&cmd_iocb->list);
- pring->txcmplq_cnt--;
+ if (cmd_iocb->iocb_flag & LPFC_IO_ON_Q) {
+ cmd_iocb->iocb_flag &= ~LPFC_IO_ON_Q;
+ pring->txcmplq_cnt--;
+ }
return cmd_iocb;
}
@@ -3564,13 +3586,16 @@ static int
lpfc_sli_brdrestart_s4(struct lpfc_hba *phba)
{
struct lpfc_sli *psli = &phba->sli;
-
+ uint32_t hba_aer_enabled;
/* Restart HBA */
lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
"0296 Restart HBA Data: x%x x%x\n",
phba->pport->port_state, psli->sli_flag);
+ /* Take PCIe device Advanced Error Reporting (AER) state */
+ hba_aer_enabled = phba->hba_flag & HBA_AER_ENABLED;
+
lpfc_sli4_brdreset(phba);
spin_lock_irq(&phba->hbalock);
@@ -3582,6 +3607,10 @@ lpfc_sli_brdrestart_s4(struct lpfc_hba *phba)
memset(&psli->lnk_stat_offsets, 0, sizeof(psli->lnk_stat_offsets));
psli->stats_start = get_seconds();
+ /* Reset HBA AER if it was enabled, note hba_flag was reset above */
+ if (hba_aer_enabled)
+ pci_disable_pcie_error_reporting(phba->pcidev);
+
lpfc_hba_down_post(phba);
return 0;
@@ -3794,7 +3823,7 @@ lpfc_sli_hbq_setup(struct lpfc_hba *phba)
phba->link_state = LPFC_HBA_ERROR;
mempool_free(pmb, phba->mbox_mem_pool);
- return ENXIO;
+ return -ENXIO;
}
}
phba->hbq_count = hbq_count;
@@ -3885,7 +3914,6 @@ lpfc_sli_config_port(struct lpfc_hba *phba, int sli_mode)
phba->sli3_options &= ~(LPFC_SLI3_NPIV_ENABLED |
LPFC_SLI3_HBQ_ENABLED |
LPFC_SLI3_CRP_ENABLED |
- LPFC_SLI3_INB_ENABLED |
LPFC_SLI3_BG_ENABLED);
if (rc != MBX_SUCCESS) {
lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
@@ -3927,20 +3955,9 @@ lpfc_sli_config_port(struct lpfc_hba *phba, int sli_mode)
phba->sli3_options |= LPFC_SLI3_HBQ_ENABLED;
if (pmb->u.mb.un.varCfgPort.gcrp)
phba->sli3_options |= LPFC_SLI3_CRP_ENABLED;
- if (pmb->u.mb.un.varCfgPort.ginb) {
- phba->sli3_options |= LPFC_SLI3_INB_ENABLED;
- phba->hbq_get = phba->mbox->us.s3_inb_pgp.hbq_get;
- phba->port_gp = phba->mbox->us.s3_inb_pgp.port;
- phba->inb_ha_copy = &phba->mbox->us.s3_inb_pgp.ha_copy;
- phba->inb_counter = &phba->mbox->us.s3_inb_pgp.counter;
- phba->inb_last_counter =
- phba->mbox->us.s3_inb_pgp.counter;
- } else {
- phba->hbq_get = phba->mbox->us.s3_pgp.hbq_get;
- phba->port_gp = phba->mbox->us.s3_pgp.port;
- phba->inb_ha_copy = NULL;
- phba->inb_counter = NULL;
- }
+
+ phba->hbq_get = phba->mbox->us.s3_pgp.hbq_get;
+ phba->port_gp = phba->mbox->us.s3_pgp.port;
if (phba->cfg_enable_bg) {
if (pmb->u.mb.un.varCfgPort.gbg)
@@ -3953,8 +3970,6 @@ lpfc_sli_config_port(struct lpfc_hba *phba, int sli_mode)
} else {
phba->hbq_get = NULL;
phba->port_gp = phba->mbox->us.s2.port;
- phba->inb_ha_copy = NULL;
- phba->inb_counter = NULL;
phba->max_vpi = 0;
}
do_prep_failed:
@@ -4214,7 +4229,8 @@ lpfc_sli4_read_rev(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq,
if (mqe->un.read_rev.avail_vpd_len < *vpd_size)
*vpd_size = mqe->un.read_rev.avail_vpd_len;
- lpfc_sli_pcimem_bcopy(dmabuf->virt, vpd, *vpd_size);
+ memcpy(vpd, dmabuf->virt, *vpd_size);
+
dma_free_coherent(&phba->pcidev->dev, dma_size,
dmabuf->virt, dmabuf->phys);
kfree(dmabuf);
@@ -4539,6 +4555,24 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba)
/* Start error attention (ERATT) polling timer */
mod_timer(&phba->eratt_poll, jiffies + HZ * LPFC_ERATT_POLL_INTERVAL);
+ /* Enable PCIe device Advanced Error Reporting (AER) if configured */
+ if (phba->cfg_aer_support == 1 && !(phba->hba_flag & HBA_AER_ENABLED)) {
+ rc = pci_enable_pcie_error_reporting(phba->pcidev);
+ if (!rc) {
+ lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
+ "2829 This device supports "
+ "Advanced Error Reporting (AER)\n");
+ spin_lock_irq(&phba->hbalock);
+ phba->hba_flag |= HBA_AER_ENABLED;
+ spin_unlock_irq(&phba->hbalock);
+ } else {
+ lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
+ "2830 This device does not support "
+ "Advanced Error Reporting (AER)\n");
+ phba->cfg_aer_support = 0;
+ }
+ }
+
/*
* The port is ready, set the host's link state to LINK_DOWN
* in preparation for link interrupts.
@@ -5265,7 +5299,8 @@ lpfc_sli4_post_sync_mbox(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
if (mcqe_status != MB_CQE_STATUS_SUCCESS) {
bf_set(lpfc_mqe_status, mb, LPFC_MBX_ERROR_RANGE | mcqe_status);
rc = MBXERR_ERROR;
- }
+ } else
+ lpfc_sli4_swap_str(phba, mboxq);
lpfc_printf_log(phba, KERN_INFO, LOG_MBOX | LOG_SLI,
"(%d):0356 Mailbox cmd x%x (x%x) Status x%x "
@@ -5592,7 +5627,7 @@ lpfc_mbox_api_table_setup(struct lpfc_hba *phba, uint8_t dev_grp)
* iocb to the txq when SLI layer cannot submit the command iocb
* to the ring.
**/
-static void
+void
__lpfc_sli_ringtx_put(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
struct lpfc_iocbq *piocb)
{
@@ -6209,7 +6244,6 @@ __lpfc_sli_issue_iocb_s4(struct lpfc_hba *phba, uint32_t ring_number,
struct lpfc_iocbq *piocb, uint32_t flag)
{
struct lpfc_sglq *sglq;
- uint16_t xritag;
union lpfc_wqe wqe;
struct lpfc_sli_ring *pring = &phba->sli.ring[ring_number];
@@ -6218,10 +6252,26 @@ __lpfc_sli_issue_iocb_s4(struct lpfc_hba *phba, uint32_t ring_number,
piocb->iocb.ulpCommand == CMD_CLOSE_XRI_CN)
sglq = NULL;
else {
+ if (pring->txq_cnt) {
+ if (!(flag & SLI_IOCB_RET_IOCB)) {
+ __lpfc_sli_ringtx_put(phba,
+ pring, piocb);
+ return IOCB_SUCCESS;
+ } else {
+ return IOCB_BUSY;
+ }
+ } else {
sglq = __lpfc_sli_get_sglq(phba);
- if (!sglq)
- return IOCB_ERROR;
- piocb->sli4_xritag = sglq->sli4_xritag;
+ if (!sglq) {
+ if (!(flag & SLI_IOCB_RET_IOCB)) {
+ __lpfc_sli_ringtx_put(phba,
+ pring,
+ piocb);
+ return IOCB_SUCCESS;
+ } else
+ return IOCB_BUSY;
+ }
+ }
}
} else if (piocb->iocb_flag & LPFC_IO_FCP) {
sglq = NULL; /* These IO's already have an XRI and
@@ -6237,8 +6287,9 @@ __lpfc_sli_issue_iocb_s4(struct lpfc_hba *phba, uint32_t ring_number,
}
if (sglq) {
- xritag = lpfc_sli4_bpl2sgl(phba, piocb, sglq);
- if (xritag != sglq->sli4_xritag)
+ piocb->sli4_xritag = sglq->sli4_xritag;
+
+ if (NO_XRI == lpfc_sli4_bpl2sgl(phba, piocb, sglq))
return IOCB_ERROR;
}
@@ -6278,7 +6329,7 @@ __lpfc_sli_issue_iocb_s4(struct lpfc_hba *phba, uint32_t ring_number,
* IOCB_SUCCESS - Success
* IOCB_BUSY - Busy
**/
-static inline int
+int
__lpfc_sli_issue_iocb(struct lpfc_hba *phba, uint32_t ring_number,
struct lpfc_iocbq *piocb, uint32_t flag)
{
@@ -7095,13 +7146,6 @@ lpfc_sli_abort_els_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
*/
abort_iocb = phba->sli.iocbq_lookup[abort_context];
- lpfc_printf_log(phba, KERN_INFO, LOG_ELS | LOG_SLI,
- "0327 Cannot abort els iocb %p "
- "with tag %x context %x, abort status %x, "
- "abort code %x\n",
- abort_iocb, abort_iotag, abort_context,
- irsp->ulpStatus, irsp->un.ulpWord[4]);
-
/*
* If the iocb is not found in Firmware queue the iocb
* might have completed already. Do not free it again.
@@ -7120,6 +7164,13 @@ lpfc_sli_abort_els_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
if (abort_iocb && phba->sli_rev == LPFC_SLI_REV4)
abort_context = abort_iocb->iocb.ulpContext;
}
+
+ lpfc_printf_log(phba, KERN_WARNING, LOG_ELS | LOG_SLI,
+ "0327 Cannot abort els iocb %p "
+ "with tag %x context %x, abort status %x, "
+ "abort code %x\n",
+ 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.
@@ -7137,7 +7188,10 @@ lpfc_sli_abort_els_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
* following abort XRI from the HBA.
*/
list_del_init(&abort_iocb->list);
- pring->txcmplq_cnt--;
+ if (abort_iocb->iocb_flag & LPFC_IO_ON_Q) {
+ abort_iocb->iocb_flag &= ~LPFC_IO_ON_Q;
+ pring->txcmplq_cnt--;
+ }
/* Firmware could still be in progress of DMAing
* payload, so don't free data buffer till after
@@ -7269,8 +7323,9 @@ lpfc_sli_issue_abort_iotag(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
lpfc_printf_vlog(vport, KERN_INFO, LOG_SLI,
"0339 Abort xri x%x, original iotag x%x, "
"abort cmd iotag x%x\n",
+ iabt->un.acxri.abortIoTag,
iabt->un.acxri.abortContextTag,
- iabt->un.acxri.abortIoTag, abtsiocbp->iotag);
+ abtsiocbp->iotag);
retval = __lpfc_sli_issue_iocb(phba, pring->ringno, abtsiocbp, 0);
if (retval)
@@ -7600,7 +7655,7 @@ lpfc_sli_issue_iocb_wait(struct lpfc_hba *phba,
long timeleft, timeout_req = 0;
int retval = IOCB_SUCCESS;
uint32_t creg_val;
-
+ struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_ELS_RING];
/*
* If the caller has provided a response iocbq buffer, then context2
* is NULL or its an error.
@@ -7622,7 +7677,8 @@ lpfc_sli_issue_iocb_wait(struct lpfc_hba *phba,
readl(phba->HCregaddr); /* flush */
}
- retval = lpfc_sli_issue_iocb(phba, ring_number, piocb, 0);
+ retval = lpfc_sli_issue_iocb(phba, ring_number, piocb,
+ SLI_IOCB_RET_IOCB);
if (retval == IOCB_SUCCESS) {
timeout_req = timeout * HZ;
timeleft = wait_event_timeout(done_q,
@@ -7644,6 +7700,11 @@ lpfc_sli_issue_iocb_wait(struct lpfc_hba *phba,
timeout, (timeleft / jiffies));
retval = IOCB_TIMEDOUT;
}
+ } else if (retval == IOCB_BUSY) {
+ lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
+ "2818 Max IOCBs %d txq cnt %d txcmplq cnt %d\n",
+ phba->iocb_cnt, pring->txq_cnt, pring->txcmplq_cnt);
+ return retval;
} else {
lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
"0332 IOCB wait issue failed, Data x%x\n",
@@ -7724,9 +7785,10 @@ lpfc_sli_issue_mbox_wait(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq,
* if LPFC_MBX_WAKE flag is set the mailbox is completed
* else do not free the resources.
*/
- if (pmboxq->mbox_flag & LPFC_MBX_WAKE)
+ if (pmboxq->mbox_flag & LPFC_MBX_WAKE) {
retval = MBX_SUCCESS;
- else {
+ lpfc_sli4_swap_str(phba, pmboxq);
+ } else {
retval = MBX_TIMEOUT;
pmboxq->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
}
@@ -8789,12 +8851,17 @@ lpfc_sli4_sp_handle_els_wcqe(struct lpfc_hba *phba,
{
struct lpfc_iocbq *irspiocbq;
unsigned long iflags;
+ struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_FCP_RING];
/* Get an irspiocbq for later ELS response processing use */
irspiocbq = lpfc_sli_get_iocbq(phba);
if (!irspiocbq) {
lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
- "0387 Failed to allocate an iocbq\n");
+ "0387 NO IOCBQ data: txq_cnt=%d iocb_cnt=%d "
+ "fcp_txcmplq_cnt=%d, els_txcmplq_cnt=%d\n",
+ pring->txq_cnt, phba->iocb_cnt,
+ phba->sli.ring[LPFC_FCP_RING].txcmplq_cnt,
+ phba->sli.ring[LPFC_ELS_RING].txcmplq_cnt);
return false;
}
@@ -9043,9 +9110,10 @@ lpfc_sli4_sp_handle_eqe(struct lpfc_hba *phba, struct lpfc_eqe *eqe)
}
}
if (unlikely(!cq)) {
- lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
- "0365 Slow-path CQ identifier (%d) does "
- "not exist\n", cqid);
+ if (phba->sli.sli_flag & LPFC_SLI_ACTIVE)
+ lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+ "0365 Slow-path CQ identifier "
+ "(%d) does not exist\n", cqid);
return;
}
@@ -9208,6 +9276,7 @@ lpfc_sli4_fp_handle_wcqe(struct lpfc_hba *phba, struct lpfc_queue *cq,
{
struct lpfc_wcqe_release wcqe;
bool workposted = false;
+ unsigned long iflag;
/* Copy the work queue CQE and convert endian order if needed */
lpfc_sli_pcimem_bcopy(cqe, &wcqe, sizeof(struct lpfc_cqe));
@@ -9216,6 +9285,9 @@ lpfc_sli4_fp_handle_wcqe(struct lpfc_hba *phba, struct lpfc_queue *cq,
switch (bf_get(lpfc_wcqe_c_code, &wcqe)) {
case CQE_CODE_COMPL_WQE:
/* Process the WQ complete event */
+ spin_lock_irqsave(&phba->hbalock, iflag);
+ phba->last_completion_time = jiffies;
+ spin_unlock_irqrestore(&phba->hbalock, iflag);
lpfc_sli4_fp_handle_fcp_wcqe(phba,
(struct lpfc_wcqe_complete *)&wcqe);
break;
@@ -9271,9 +9343,10 @@ lpfc_sli4_fp_handle_eqe(struct lpfc_hba *phba, struct lpfc_eqe *eqe,
cq = phba->sli4_hba.fcp_cq[fcp_cqidx];
if (unlikely(!cq)) {
- lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
- "0367 Fast-path completion queue does not "
- "exist\n");
+ if (phba->sli.sli_flag & LPFC_SLI_ACTIVE)
+ lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+ "0367 Fast-path completion queue "
+ "does not exist\n");
return;
}
@@ -11898,12 +11971,26 @@ lpfc_sli4_alloc_rpi(struct lpfc_hba *phba)
* available rpis maintained by the driver.
**/
void
+__lpfc_sli4_free_rpi(struct lpfc_hba *phba, int rpi)
+{
+ if (test_and_clear_bit(rpi, phba->sli4_hba.rpi_bmask)) {
+ phba->sli4_hba.rpi_count--;
+ phba->sli4_hba.max_cfg_param.rpi_used--;
+ }
+}
+
+/**
+ * lpfc_sli4_free_rpi - Release an rpi for reuse.
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine is invoked to release an rpi to the pool of
+ * available rpis maintained by the driver.
+ **/
+void
lpfc_sli4_free_rpi(struct lpfc_hba *phba, int rpi)
{
spin_lock_irq(&phba->hbalock);
- clear_bit(rpi, phba->sli4_hba.rpi_bmask);
- phba->sli4_hba.rpi_count--;
- phba->sli4_hba.max_cfg_param.rpi_used--;
+ __lpfc_sli4_free_rpi(phba, rpi);
spin_unlock_irq(&phba->hbalock);
}
@@ -12318,18 +12405,47 @@ lpfc_sli4_fcf_rr_next_index_get(struct lpfc_hba *phba)
{
uint16_t next_fcf_index;
- /* Search from the currently registered FCF index */
+ /* Search start from next bit of currently registered FCF index */
+ next_fcf_index = (phba->fcf.current_rec.fcf_indx + 1) %
+ LPFC_SLI4_FCF_TBL_INDX_MAX;
next_fcf_index = find_next_bit(phba->fcf.fcf_rr_bmask,
LPFC_SLI4_FCF_TBL_INDX_MAX,
- phba->fcf.current_rec.fcf_indx);
+ next_fcf_index);
+
/* Wrap around condition on phba->fcf.fcf_rr_bmask */
if (next_fcf_index >= LPFC_SLI4_FCF_TBL_INDX_MAX)
next_fcf_index = find_next_bit(phba->fcf.fcf_rr_bmask,
LPFC_SLI4_FCF_TBL_INDX_MAX, 0);
- /* Round robin failover stop condition */
- if (next_fcf_index == phba->fcf.fcf_rr_init_indx)
+
+ /* Check roundrobin failover list empty condition */
+ if (next_fcf_index >= LPFC_SLI4_FCF_TBL_INDX_MAX) {
+ lpfc_printf_log(phba, KERN_WARNING, LOG_FIP,
+ "2844 No roundrobin failover FCF available\n");
return LPFC_FCOE_FCF_NEXT_NONE;
+ }
+
+ /* Check roundrobin failover index bmask stop condition */
+ if (next_fcf_index == phba->fcf.fcf_rr_init_indx) {
+ if (!(phba->fcf.fcf_flag & FCF_REDISC_RRU)) {
+ lpfc_printf_log(phba, KERN_WARNING, LOG_FIP,
+ "2847 Round robin failover FCF index "
+ "search hit stop condition:x%x\n",
+ next_fcf_index);
+ return LPFC_FCOE_FCF_NEXT_NONE;
+ }
+ /* The roundrobin failover index bmask updated, start over */
+ lpfc_printf_log(phba, KERN_INFO, LOG_FIP,
+ "2848 Round robin failover FCF index bmask "
+ "updated, start over\n");
+ spin_lock_irq(&phba->hbalock);
+ phba->fcf.fcf_flag &= ~FCF_REDISC_RRU;
+ spin_unlock_irq(&phba->hbalock);
+ return phba->fcf.fcf_rr_init_indx;
+ }
+ lpfc_printf_log(phba, KERN_INFO, LOG_FIP,
+ "2845 Get next round robin failover "
+ "FCF index x%x\n", next_fcf_index);
return next_fcf_index;
}
@@ -12359,11 +12475,20 @@ lpfc_sli4_fcf_rr_index_set(struct lpfc_hba *phba, uint16_t fcf_index)
/* Set the eligible FCF record index bmask */
set_bit(fcf_index, phba->fcf.fcf_rr_bmask);
+ /* Set the roundrobin index bmask updated */
+ spin_lock_irq(&phba->hbalock);
+ phba->fcf.fcf_flag |= FCF_REDISC_RRU;
+ spin_unlock_irq(&phba->hbalock);
+
+ lpfc_printf_log(phba, KERN_INFO, LOG_FIP,
+ "2790 Set FCF index x%x to round robin failover "
+ "bmask\n", fcf_index);
+
return 0;
}
/**
- * lpfc_sli4_fcf_rr_index_set - Clear bmask from eligible fcf record index
+ * lpfc_sli4_fcf_rr_index_clear - Clear bmask from eligible fcf record index
* @phba: pointer to lpfc hba data structure.
*
* This routine clears the FCF record index from the eligible bmask for
@@ -12384,6 +12509,10 @@ lpfc_sli4_fcf_rr_index_clear(struct lpfc_hba *phba, uint16_t fcf_index)
}
/* Clear the eligible FCF record index bmask */
clear_bit(fcf_index, phba->fcf.fcf_rr_bmask);
+
+ lpfc_printf_log(phba, KERN_INFO, LOG_FIP,
+ "2791 Clear FCF index x%x from round robin failover "
+ "bmask\n", fcf_index);
}
/**
@@ -12446,7 +12575,7 @@ lpfc_mbx_cmpl_redisc_fcf_table(struct lpfc_hba *phba, LPFC_MBOXQ_t *mbox)
}
/**
- * lpfc_sli4_redisc_all_fcf - Request to rediscover entire FCF table by port.
+ * lpfc_sli4_redisc_fcf_table - Request to rediscover entire FCF table by port.
* @phba: pointer to lpfc hba data structure.
*
* This routine is invoked to request for rediscovery of the entire FCF table
@@ -12662,6 +12791,7 @@ lpfc_cleanup_pending_mbox(struct lpfc_vport *vport)
LPFC_MBOXQ_t *mb, *nextmb;
struct lpfc_dmabuf *mp;
struct lpfc_nodelist *ndlp;
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
spin_lock_irq(&phba->hbalock);
list_for_each_entry_safe(mb, nextmb, &phba->sli.mboxq, list) {
@@ -12673,6 +12803,9 @@ lpfc_cleanup_pending_mbox(struct lpfc_vport *vport)
continue;
if (mb->u.mb.mbxCommand == MBX_REG_LOGIN64) {
+ if (phba->sli_rev == LPFC_SLI_REV4)
+ __lpfc_sli4_free_rpi(phba,
+ mb->u.mb.un.varRegLogin.rpi);
mp = (struct lpfc_dmabuf *) (mb->context1);
if (mp) {
__lpfc_mbuf_free(phba, mp->virt, mp->phys);
@@ -12680,6 +12813,9 @@ lpfc_cleanup_pending_mbox(struct lpfc_vport *vport)
}
ndlp = (struct lpfc_nodelist *) mb->context2;
if (ndlp) {
+ spin_lock_irq(shost->host_lock);
+ ndlp->nlp_flag &= ~NLP_IGNR_REG_CMPL;
+ spin_unlock_irq(shost->host_lock);
lpfc_nlp_put(ndlp);
mb->context2 = NULL;
}
@@ -12695,6 +12831,9 @@ lpfc_cleanup_pending_mbox(struct lpfc_vport *vport)
if (mb->u.mb.mbxCommand == MBX_REG_LOGIN64) {
ndlp = (struct lpfc_nodelist *) mb->context2;
if (ndlp) {
+ spin_lock_irq(shost->host_lock);
+ ndlp->nlp_flag &= ~NLP_IGNR_REG_CMPL;
+ spin_unlock_irq(shost->host_lock);
lpfc_nlp_put(ndlp);
mb->context2 = NULL;
}
@@ -12705,3 +12844,85 @@ lpfc_cleanup_pending_mbox(struct lpfc_vport *vport)
spin_unlock_irq(&phba->hbalock);
}
+/**
+ * lpfc_drain_txq - Drain the txq
+ * @phba: Pointer to HBA context object.
+ *
+ * This function attempt to submit IOCBs on the txq
+ * to the adapter. For SLI4 adapters, the txq contains
+ * ELS IOCBs that have been deferred because the there
+ * are no SGLs. This congestion can occur with large
+ * vport counts during node discovery.
+ **/
+
+uint32_t
+lpfc_drain_txq(struct lpfc_hba *phba)
+{
+ LIST_HEAD(completions);
+ struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_ELS_RING];
+ struct lpfc_iocbq *piocbq = 0;
+ unsigned long iflags = 0;
+ char *fail_msg = NULL;
+ struct lpfc_sglq *sglq;
+ union lpfc_wqe wqe;
+
+ spin_lock_irqsave(&phba->hbalock, iflags);
+ if (pring->txq_cnt > pring->txq_max)
+ pring->txq_max = pring->txq_cnt;
+
+ spin_unlock_irqrestore(&phba->hbalock, iflags);
+
+ while (pring->txq_cnt) {
+ spin_lock_irqsave(&phba->hbalock, iflags);
+
+ sglq = __lpfc_sli_get_sglq(phba);
+ if (!sglq) {
+ spin_unlock_irqrestore(&phba->hbalock, iflags);
+ break;
+ } else {
+ piocbq = lpfc_sli_ringtx_get(phba, pring);
+ if (!piocbq) {
+ /* The txq_cnt out of sync. This should
+ * never happen
+ */
+ sglq = __lpfc_clear_active_sglq(phba,
+ sglq->sli4_xritag);
+ spin_unlock_irqrestore(&phba->hbalock, iflags);
+ lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+ "2823 txq empty and txq_cnt is %d\n ",
+ pring->txq_cnt);
+ break;
+ }
+ }
+
+ /* The xri and iocb resources secured,
+ * attempt to issue request
+ */
+ piocbq->sli4_xritag = sglq->sli4_xritag;
+ if (NO_XRI == lpfc_sli4_bpl2sgl(phba, piocbq, sglq))
+ fail_msg = "to convert bpl to sgl";
+ else if (lpfc_sli4_iocb2wqe(phba, piocbq, &wqe))
+ fail_msg = "to convert iocb to wqe";
+ else if (lpfc_sli4_wq_put(phba->sli4_hba.els_wq, &wqe))
+ fail_msg = " - Wq is full";
+ else
+ lpfc_sli_ringtxcmpl_put(phba, pring, piocbq);
+
+ if (fail_msg) {
+ /* Failed means we can't issue and need to cancel */
+ lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+ "2822 IOCB failed %s iotag 0x%x "
+ "xri 0x%x\n",
+ fail_msg,
+ piocbq->iotag, piocbq->sli4_xritag);
+ list_add_tail(&piocbq->list, &completions);
+ }
+ spin_unlock_irqrestore(&phba->hbalock, iflags);
+ }
+
+ /* Cancel all the IOCBs that cannot be issued */
+ lpfc_sli_cancel_iocbs(phba, &completions, IOSTAT_LOCAL_REJECT,
+ IOERR_SLI_ABORTED);
+
+ return pring->txq_cnt;
+}
diff --git a/drivers/scsi/lpfc/lpfc_sli.h b/drivers/scsi/lpfc/lpfc_sli.h
index e3792151ca0..cd56d6cce6c 100644
--- a/drivers/scsi/lpfc/lpfc_sli.h
+++ b/drivers/scsi/lpfc/lpfc_sli.h
@@ -48,6 +48,7 @@ struct lpfc_iocbq {
/* lpfc_iocbqs are used in double linked lists */
struct list_head list;
struct list_head clist;
+ struct list_head dlist;
uint16_t iotag; /* pre-assigned IO tag */
uint16_t sli4_xritag; /* pre-assigned XRI, (OXID) tag. */
struct lpfc_cq_event cq_event;
@@ -64,6 +65,7 @@ struct lpfc_iocbq {
#define LPFC_EXCHANGE_BUSY 0x40 /* SLI4 hba reported XB in response */
#define LPFC_USE_FCPWQIDX 0x80 /* Submit to specified FCPWQ index */
#define DSS_SECURITY_OP 0x100 /* security IO */
+#define LPFC_IO_ON_Q 0x200 /* The IO is still on the TXCMPLQ */
#define LPFC_FIP_ELS_ID_MASK 0xc000 /* ELS_ID range 0-3, non-shifted mask */
#define LPFC_FIP_ELS_ID_SHIFT 14
diff --git a/drivers/scsi/lpfc/lpfc_sli4.h b/drivers/scsi/lpfc/lpfc_sli4.h
index 58bb4c81b54..a3b24d99a2a 100644
--- a/drivers/scsi/lpfc/lpfc_sli4.h
+++ b/drivers/scsi/lpfc/lpfc_sli4.h
@@ -51,6 +51,9 @@
#define LPFC_FCOE_FCF_GET_FIRST 0xFFFF
#define LPFC_FCOE_FCF_NEXT_NONE 0xFFFF
+#define LPFC_FCOE_NULL_VID 0xFFF
+#define LPFC_FCOE_IGNORE_VID 0xFFFF
+
/* First 3 bytes of default FCF MAC is specified by FC_MAP */
#define LPFC_FCOE_FCF_MAC3 0xFF
#define LPFC_FCOE_FCF_MAC4 0xFF
@@ -58,7 +61,7 @@
#define LPFC_FCOE_FCF_MAP0 0x0E
#define LPFC_FCOE_FCF_MAP1 0xFC
#define LPFC_FCOE_FCF_MAP2 0x00
-#define LPFC_FCOE_MAX_RCV_SIZE 0x5AC
+#define LPFC_FCOE_MAX_RCV_SIZE 0x800
#define LPFC_FCOE_FKA_ADV_PER 0
#define LPFC_FCOE_FIP_PRIORITY 0x80
@@ -160,6 +163,7 @@ struct lpfc_fcf {
#define FCF_REDISC_PEND 0x80 /* FCF rediscovery pending */
#define FCF_REDISC_EVT 0x100 /* FCF rediscovery event to worker thread */
#define FCF_REDISC_FOV 0x200 /* Post FCF rediscovery fast failover */
+#define FCF_REDISC_RRU 0x400 /* Roundrobin bitmap updated */
uint32_t addr_mode;
uint16_t fcf_rr_init_indx;
uint32_t eligible_fcf_cnt;
@@ -382,6 +386,7 @@ struct lpfc_sli4_hba {
struct lpfc_pc_sli4_params pc_sli4_params;
struct msix_entry *msix_entries;
uint32_t cfg_eqn;
+ uint32_t msix_vec_nr;
struct lpfc_fcp_eq_hdl *fcp_eq_hdl; /* FCP per-WQ handle */
/* Pointers to the constructed SLI4 queues */
struct lpfc_queue **fp_eq; /* Fast-path event queue */
@@ -524,6 +529,7 @@ int lpfc_sli4_post_all_rpi_hdrs(struct lpfc_hba *);
struct lpfc_rpi_hdr *lpfc_sli4_create_rpi_hdr(struct lpfc_hba *);
void lpfc_sli4_remove_rpi_hdrs(struct lpfc_hba *);
int lpfc_sli4_alloc_rpi(struct lpfc_hba *);
+void __lpfc_sli4_free_rpi(struct lpfc_hba *, int);
void lpfc_sli4_free_rpi(struct lpfc_hba *, int);
void lpfc_sli4_remove_rpis(struct lpfc_hba *);
void lpfc_sli4_async_event_proc(struct lpfc_hba *);
diff --git a/drivers/scsi/lpfc/lpfc_version.h b/drivers/scsi/lpfc/lpfc_version.h
index 5294c3a515a..d28830af71d 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.3.12"
+#define LPFC_DRIVER_VERSION "8.3.15"
#define LPFC_DRIVER_NAME "lpfc"
#define LPFC_SP_DRIVER_HANDLER_NAME "lpfc:sp"
#define LPFC_FP_DRIVER_HANDLER_NAME "lpfc:fp"
diff --git a/drivers/scsi/lpfc/lpfc_vport.c b/drivers/scsi/lpfc/lpfc_vport.c
index ab91359bde2..1655507a682 100644
--- a/drivers/scsi/lpfc/lpfc_vport.c
+++ b/drivers/scsi/lpfc/lpfc_vport.c
@@ -782,7 +782,7 @@ lpfc_destroy_vport_work_array(struct lpfc_hba *phba, struct lpfc_vport **vports)
int i;
if (vports == NULL)
return;
- for (i = 0; vports[i] != NULL && i <= phba->max_vports; i++)
+ for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++)
scsi_host_put(lpfc_shost_from_vport(vports[i]));
kfree(vports);
}
diff --git a/drivers/scsi/mpt2sas/mpi/mpi2.h b/drivers/scsi/mpt2sas/mpi/mpi2.h
index dada0a13223..4b1c2f0350f 100644
--- a/drivers/scsi/mpt2sas/mpi/mpi2.h
+++ b/drivers/scsi/mpt2sas/mpi/mpi2.h
@@ -8,7 +8,7 @@
* scatter/gather formats.
* Creation Date: June 21, 2006
*
- * mpi2.h Version: 02.00.14
+ * mpi2.h Version: 02.00.15
*
* Version History
* ---------------
@@ -57,6 +57,10 @@
* Added MSI-x index mask and shift for Reply Post Host
* Index register.
* Added function code for Host Based Discovery Action.
+ * 02-10-10 02.00.15 Bumped MPI2_HEADER_VERSION_UNIT.
+ * Added define for MPI2_FUNCTION_PWR_MGMT_CONTROL.
+ * Added defines for product-specific range of message
+ * function codes, 0xF0 to 0xFF.
* --------------------------------------------------------------------------
*/
@@ -82,7 +86,7 @@
#define MPI2_VERSION_02_00 (0x0200)
/* versioning for this MPI header set */
-#define MPI2_HEADER_VERSION_UNIT (0x0E)
+#define MPI2_HEADER_VERSION_UNIT (0x0F)
#define MPI2_HEADER_VERSION_DEV (0x00)
#define MPI2_HEADER_VERSION_UNIT_MASK (0xFF00)
#define MPI2_HEADER_VERSION_UNIT_SHIFT (8)
@@ -473,8 +477,6 @@ typedef union _MPI2_REPLY_DESCRIPTORS_UNION
/*****************************************************************************
*
* Message Functions
-* 0x80 -> 0x8F reserved for private message use per product
-*
*
*****************************************************************************/
@@ -506,6 +508,13 @@ typedef union _MPI2_REPLY_DESCRIPTORS_UNION
#define MPI2_FUNCTION_RAID_ACCELERATOR (0x2C) /* RAID Accelerator*/
/* Host Based Discovery Action */
#define MPI2_FUNCTION_HOST_BASED_DISCOVERY_ACTION (0x2F)
+/* Power Management Control */
+#define MPI2_FUNCTION_PWR_MGMT_CONTROL (0x30)
+/* beginning of product-specific range */
+#define MPI2_FUNCTION_MIN_PRODUCT_SPECIFIC (0xF0)
+/* end of product-specific range */
+#define MPI2_FUNCTION_MAX_PRODUCT_SPECIFIC (0xFF)
+
diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h b/drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h
index d4e9d6f8452..e3728d736d8 100644
--- a/drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h
+++ b/drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h
@@ -6,7 +6,7 @@
* Title: MPI Configuration messages and pages
* Creation Date: November 10, 2006
*
- * mpi2_cnfg.h Version: 02.00.13
+ * mpi2_cnfg.h Version: 02.00.14
*
* Version History
* ---------------
@@ -109,6 +109,18 @@
* Added Ethernet configuration pages.
* 10-28-09 02.00.13 Added MPI2_IOUNITPAGE1_ENABLE_HOST_BASED_DISCOVERY.
* Added SAS PHY Page 4 structure and defines.
+ * 02-10-10 02.00.14 Modified the comments for the configuration page
+ * structures that contain an array of data. The host
+ * should use the "count" field in the page data (e.g. the
+ * NumPhys field) to determine the number of valid elements
+ * in the array.
+ * Added/modified some MPI2_MFGPAGE_DEVID_SAS defines.
+ * Added PowerManagementCapabilities to IO Unit Page 7.
+ * Added PortWidthModGroup field to
+ * MPI2_SAS_IO_UNIT5_PHY_PM_SETTINGS.
+ * Added MPI2_CONFIG_PAGE_SASIOUNIT_6 and related defines.
+ * Added MPI2_CONFIG_PAGE_SASIOUNIT_7 and related defines.
+ * Added MPI2_CONFIG_PAGE_SASIOUNIT_8 and related defines.
* --------------------------------------------------------------------------
*/
@@ -373,8 +385,9 @@ typedef struct _MPI2_CONFIG_REPLY
#define MPI2_MFGPAGE_DEVID_SAS2208_4 (0x0083)
#define MPI2_MFGPAGE_DEVID_SAS2208_5 (0x0084)
#define MPI2_MFGPAGE_DEVID_SAS2208_6 (0x0085)
-#define MPI2_MFGPAGE_DEVID_SAS2208_7 (0x0086)
-#define MPI2_MFGPAGE_DEVID_SAS2208_8 (0x0087)
+#define MPI2_MFGPAGE_DEVID_SAS2308_1 (0x0086)
+#define MPI2_MFGPAGE_DEVID_SAS2308_2 (0x0087)
+#define MPI2_MFGPAGE_DEVID_SAS2308_3 (0x006E)
/* Manufacturing Page 0 */
@@ -540,7 +553,7 @@ typedef struct _MPI2_CONFIG_PAGE_MAN_4
/*
* Host code (drivers, BIOS, utilities, etc.) should leave this define set to
- * one and check Header.PageLength or NumPhys at runtime.
+ * one and check the value returned for NumPhys at runtime.
*/
#ifndef MPI2_MAN_PAGE_5_PHY_ENTRIES
#define MPI2_MAN_PAGE_5_PHY_ENTRIES (1)
@@ -618,7 +631,7 @@ typedef struct _MPI2_MANPAGE7_CONNECTOR_INFO
/*
* Host code (drivers, BIOS, utilities, etc.) should leave this define set to
- * one and check NumPhys at runtime.
+ * one and check the value returned for NumPhys at runtime.
*/
#ifndef MPI2_MANPAGE7_CONNECTOR_INFO_MAX
#define MPI2_MANPAGE7_CONNECTOR_INFO_MAX (1)
@@ -731,7 +744,7 @@ typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_1
/*
* Host code (drivers, BIOS, utilities, etc.) should leave this define set to
- * one and check Header.PageLength at runtime.
+ * one and check the value returned for GPIOCount at runtime.
*/
#ifndef MPI2_IO_UNIT_PAGE_3_GPIO_VAL_MAX
#define MPI2_IO_UNIT_PAGE_3_GPIO_VAL_MAX (1)
@@ -760,7 +773,7 @@ typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_3
/*
* Upper layer code (drivers, utilities, etc.) should leave this define set to
- * one and check Header.PageLength or NumDmaEngines at runtime.
+ * one and check the value returned for NumDmaEngines at runtime.
*/
#ifndef MPI2_IOUNITPAGE5_DMAENGINE_ENTRIES
#define MPI2_IOUNITPAGE5_DMAENGINE_ENTRIES (1)
@@ -823,7 +836,7 @@ typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_7 {
U8 PCIeWidth; /* 0x06 */
U8 PCIeSpeed; /* 0x07 */
U32 ProcessorState; /* 0x08 */
- U32 Reserved2; /* 0x0C */
+ U32 PowerManagementCapabilities; /* 0x0C */
U16 IOCTemperature; /* 0x10 */
U8 IOCTemperatureUnits; /* 0x12 */
U8 IOCSpeed; /* 0x13 */
@@ -831,7 +844,7 @@ typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_7 {
} MPI2_CONFIG_PAGE_IO_UNIT_7, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_IO_UNIT_7,
Mpi2IOUnitPage7_t, MPI2_POINTER pMpi2IOUnitPage7_t;
-#define MPI2_IOUNITPAGE7_PAGEVERSION (0x00)
+#define MPI2_IOUNITPAGE7_PAGEVERSION (0x01)
/* defines for IO Unit Page 7 PCIeWidth field */
#define MPI2_IOUNITPAGE7_PCIE_WIDTH_X1 (0x01)
@@ -852,6 +865,14 @@ typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_7 {
#define MPI2_IOUNITPAGE7_PSTATE_DISABLED (0x01)
#define MPI2_IOUNITPAGE7_PSTATE_ENABLED (0x02)
+/* defines for IO Unit Page 7 PowerManagementCapabilities field */
+#define MPI2_IOUNITPAGE7_PMCAP_12_5_PCT_IOCSPEED (0x00000400)
+#define MPI2_IOUNITPAGE7_PMCAP_25_0_PCT_IOCSPEED (0x00000200)
+#define MPI2_IOUNITPAGE7_PMCAP_50_0_PCT_IOCSPEED (0x00000100)
+#define MPI2_IOUNITPAGE7_PMCAP_PCIE_WIDTH_CHANGE (0x00000008)
+#define MPI2_IOUNITPAGE7_PMCAP_PCIE_SPEED_CHANGE (0x00000004)
+
+
/* defines for IO Unit Page 7 IOCTemperatureUnits field */
#define MPI2_IOUNITPAGE7_IOC_TEMP_NOT_PRESENT (0x00)
#define MPI2_IOUNITPAGE7_IOC_TEMP_FAHRENHEIT (0x01)
@@ -1195,7 +1216,7 @@ typedef struct _MPI2_CONFIG_PAGE_BIOS_3
/*
* Host code (drivers, BIOS, utilities, etc.) should leave this define set to
- * one and check Header.PageLength or NumPhys at runtime.
+ * one and check the value returned for NumPhys at runtime.
*/
#ifndef MPI2_BIOS_PAGE_4_PHY_ENTRIES
#define MPI2_BIOS_PAGE_4_PHY_ENTRIES (1)
@@ -1269,7 +1290,7 @@ typedef struct _MPI2_RAIDVOL0_SETTINGS
/*
* Host code (drivers, BIOS, utilities, etc.) should leave this define set to
- * one and check Header.PageLength at runtime.
+ * one and check the value returned for NumPhysDisks at runtime.
*/
#ifndef MPI2_RAID_VOL_PAGE_0_PHYSDISK_MAX
#define MPI2_RAID_VOL_PAGE_0_PHYSDISK_MAX (1)
@@ -1471,7 +1492,7 @@ typedef struct _MPI2_CONFIG_PAGE_RD_PDISK_0
/*
* Host code (drivers, BIOS, utilities, etc.) should leave this define set to
- * one and check Header.PageLength or NumPhysDiskPaths at runtime.
+ * one and check the value returned for NumPhysDiskPaths at runtime.
*/
#ifndef MPI2_RAID_PHYS_DISK1_PATH_MAX
#define MPI2_RAID_PHYS_DISK1_PATH_MAX (1)
@@ -1633,7 +1654,7 @@ typedef struct _MPI2_SAS_IO_UNIT0_PHY_DATA
/*
* Host code (drivers, BIOS, utilities, etc.) should leave this define set to
- * one and check Header.ExtPageLength or NumPhys at runtime.
+ * one and check the value returned for NumPhys at runtime.
*/
#ifndef MPI2_SAS_IOUNIT0_PHY_MAX
#define MPI2_SAS_IOUNIT0_PHY_MAX (1)
@@ -1704,7 +1725,7 @@ typedef struct _MPI2_SAS_IO_UNIT1_PHY_DATA
/*
* Host code (drivers, BIOS, utilities, etc.) should leave this define set to
- * one and check Header.ExtPageLength or NumPhys at runtime.
+ * one and check the value returned for NumPhys at runtime.
*/
#ifndef MPI2_SAS_IOUNIT1_PHY_MAX
#define MPI2_SAS_IOUNIT1_PHY_MAX (1)
@@ -1795,7 +1816,7 @@ typedef struct _MPI2_SAS_IOUNIT4_SPINUP_GROUP
/*
* Host code (drivers, BIOS, utilities, etc.) should leave this define set to
- * four and check Header.ExtPageLength or NumPhys at runtime.
+ * one and check the value returned for NumPhys at runtime.
*/
#ifndef MPI2_SAS_IOUNIT4_PHY_MAX
#define MPI2_SAS_IOUNIT4_PHY_MAX (4)
@@ -1833,7 +1854,7 @@ typedef struct _MPI2_CONFIG_PAGE_SASIOUNIT_4
typedef struct _MPI2_SAS_IO_UNIT5_PHY_PM_SETTINGS {
U8 ControlFlags; /* 0x00 */
- U8 Reserved1; /* 0x01 */
+ U8 PortWidthModGroup; /* 0x01 */
U16 InactivityTimerExponent; /* 0x02 */
U8 SATAPartialTimeout; /* 0x04 */
U8 Reserved2; /* 0x05 */
@@ -1853,6 +1874,9 @@ typedef struct _MPI2_SAS_IO_UNIT5_PHY_PM_SETTINGS {
#define MPI2_SASIOUNIT5_CONTROL_SATA_SLUMBER_ENABLE (0x02)
#define MPI2_SASIOUNIT5_CONTROL_SATA_PARTIAL_ENABLE (0x01)
+/* defines for PortWidthModeGroup field */
+#define MPI2_SASIOUNIT5_PWMG_DISABLE (0xFF)
+
/* defines for InactivityTimerExponent field */
#define MPI2_SASIOUNIT5_ITE_MASK_SAS_SLUMBER (0x7000)
#define MPI2_SASIOUNIT5_ITE_SHIFT_SAS_SLUMBER (12)
@@ -1874,7 +1898,7 @@ typedef struct _MPI2_SAS_IO_UNIT5_PHY_PM_SETTINGS {
/*
* Host code (drivers, BIOS, utilities, etc.) should leave this define set to
- * one and check Header.ExtPageLength or NumPhys at runtime.
+ * one and check the value returned for NumPhys at runtime.
*/
#ifndef MPI2_SAS_IOUNIT5_PHY_MAX
#define MPI2_SAS_IOUNIT5_PHY_MAX (1)
@@ -1892,7 +1916,132 @@ typedef struct _MPI2_CONFIG_PAGE_SASIOUNIT_5 {
MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SASIOUNIT_5,
Mpi2SasIOUnitPage5_t, MPI2_POINTER pMpi2SasIOUnitPage5_t;
-#define MPI2_SASIOUNITPAGE5_PAGEVERSION (0x00)
+#define MPI2_SASIOUNITPAGE5_PAGEVERSION (0x01)
+
+
+/* SAS IO Unit Page 6 */
+
+typedef struct _MPI2_SAS_IO_UNIT6_PORT_WIDTH_MOD_GROUP_STATUS {
+ U8 CurrentStatus; /* 0x00 */
+ U8 CurrentModulation; /* 0x01 */
+ U8 CurrentUtilization; /* 0x02 */
+ U8 Reserved1; /* 0x03 */
+ U32 Reserved2; /* 0x04 */
+} MPI2_SAS_IO_UNIT6_PORT_WIDTH_MOD_GROUP_STATUS,
+ MPI2_POINTER PTR_MPI2_SAS_IO_UNIT6_PORT_WIDTH_MOD_GROUP_STATUS,
+ Mpi2SasIOUnit6PortWidthModGroupStatus_t,
+ MPI2_POINTER pMpi2SasIOUnit6PortWidthModGroupStatus_t;
+
+/* defines for CurrentStatus field */
+#define MPI2_SASIOUNIT6_STATUS_UNAVAILABLE (0x00)
+#define MPI2_SASIOUNIT6_STATUS_UNCONFIGURED (0x01)
+#define MPI2_SASIOUNIT6_STATUS_INVALID_CONFIG (0x02)
+#define MPI2_SASIOUNIT6_STATUS_LINK_DOWN (0x03)
+#define MPI2_SASIOUNIT6_STATUS_OBSERVATION_ONLY (0x04)
+#define MPI2_SASIOUNIT6_STATUS_INACTIVE (0x05)
+#define MPI2_SASIOUNIT6_STATUS_ACTIVE_IOUNIT (0x06)
+#define MPI2_SASIOUNIT6_STATUS_ACTIVE_HOST (0x07)
+
+/* defines for CurrentModulation field */
+#define MPI2_SASIOUNIT6_MODULATION_25_PERCENT (0x00)
+#define MPI2_SASIOUNIT6_MODULATION_50_PERCENT (0x01)
+#define MPI2_SASIOUNIT6_MODULATION_75_PERCENT (0x02)
+#define MPI2_SASIOUNIT6_MODULATION_100_PERCENT (0x03)
+
+/*
+ * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
+ * one and check the value returned for NumGroups at runtime.
+ */
+#ifndef MPI2_SAS_IOUNIT6_GROUP_MAX
+#define MPI2_SAS_IOUNIT6_GROUP_MAX (1)
+#endif
+
+typedef struct _MPI2_CONFIG_PAGE_SASIOUNIT_6 {
+ MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */
+ U32 Reserved1; /* 0x08 */
+ U32 Reserved2; /* 0x0C */
+ U8 NumGroups; /* 0x10 */
+ U8 Reserved3; /* 0x11 */
+ U16 Reserved4; /* 0x12 */
+ MPI2_SAS_IO_UNIT6_PORT_WIDTH_MOD_GROUP_STATUS
+ PortWidthModulationGroupStatus[MPI2_SAS_IOUNIT6_GROUP_MAX]; /* 0x14 */
+} MPI2_CONFIG_PAGE_SASIOUNIT_6,
+ MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SASIOUNIT_6,
+ Mpi2SasIOUnitPage6_t, MPI2_POINTER pMpi2SasIOUnitPage6_t;
+
+#define MPI2_SASIOUNITPAGE6_PAGEVERSION (0x00)
+
+
+/* SAS IO Unit Page 7 */
+
+typedef struct _MPI2_SAS_IO_UNIT7_PORT_WIDTH_MOD_GROUP_SETTINGS {
+ U8 Flags; /* 0x00 */
+ U8 Reserved1; /* 0x01 */
+ U16 Reserved2; /* 0x02 */
+ U8 Threshold75Pct; /* 0x04 */
+ U8 Threshold50Pct; /* 0x05 */
+ U8 Threshold25Pct; /* 0x06 */
+ U8 Reserved3; /* 0x07 */
+} MPI2_SAS_IO_UNIT7_PORT_WIDTH_MOD_GROUP_SETTINGS,
+ MPI2_POINTER PTR_MPI2_SAS_IO_UNIT7_PORT_WIDTH_MOD_GROUP_SETTINGS,
+ Mpi2SasIOUnit7PortWidthModGroupSettings_t,
+ MPI2_POINTER pMpi2SasIOUnit7PortWidthModGroupSettings_t;
+
+/* defines for Flags field */
+#define MPI2_SASIOUNIT7_FLAGS_ENABLE_PORT_WIDTH_MODULATION (0x01)
+
+
+/*
+ * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
+ * one and check the value returned for NumGroups at runtime.
+ */
+#ifndef MPI2_SAS_IOUNIT7_GROUP_MAX
+#define MPI2_SAS_IOUNIT7_GROUP_MAX (1)
+#endif
+
+typedef struct _MPI2_CONFIG_PAGE_SASIOUNIT_7 {
+ MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */
+ U8 SamplingInterval; /* 0x08 */
+ U8 WindowLength; /* 0x09 */
+ U16 Reserved1; /* 0x0A */
+ U32 Reserved2; /* 0x0C */
+ U32 Reserved3; /* 0x10 */
+ U8 NumGroups; /* 0x14 */
+ U8 Reserved4; /* 0x15 */
+ U16 Reserved5; /* 0x16 */
+ MPI2_SAS_IO_UNIT7_PORT_WIDTH_MOD_GROUP_SETTINGS
+ PortWidthModulationGroupSettings[MPI2_SAS_IOUNIT7_GROUP_MAX]; /* 0x18 */
+} MPI2_CONFIG_PAGE_SASIOUNIT_7,
+ MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SASIOUNIT_7,
+ Mpi2SasIOUnitPage7_t, MPI2_POINTER pMpi2SasIOUnitPage7_t;
+
+#define MPI2_SASIOUNITPAGE7_PAGEVERSION (0x00)
+
+
+/* SAS IO Unit Page 8 */
+
+typedef struct _MPI2_CONFIG_PAGE_SASIOUNIT_8 {
+ MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */
+ U32 Reserved1; /* 0x08 */
+ U32 PowerManagementCapabilities;/* 0x0C */
+ U32 Reserved2; /* 0x10 */
+} MPI2_CONFIG_PAGE_SASIOUNIT_8,
+ MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SASIOUNIT_8,
+ Mpi2SasIOUnitPage8_t, MPI2_POINTER pMpi2SasIOUnitPage8_t;
+
+#define MPI2_SASIOUNITPAGE8_PAGEVERSION (0x00)
+
+/* defines for PowerManagementCapabilities field */
+#define MPI2_SASIOUNIT8_PM_HOST_PORT_WIDTH_MOD (0x000001000)
+#define MPI2_SASIOUNIT8_PM_HOST_SAS_SLUMBER_MODE (0x000000800)
+#define MPI2_SASIOUNIT8_PM_HOST_SAS_PARTIAL_MODE (0x000000400)
+#define MPI2_SASIOUNIT8_PM_HOST_SATA_SLUMBER_MODE (0x000000200)
+#define MPI2_SASIOUNIT8_PM_HOST_SATA_PARTIAL_MODE (0x000000100)
+#define MPI2_SASIOUNIT8_PM_IOUNIT_PORT_WIDTH_MOD (0x000000010)
+#define MPI2_SASIOUNIT8_PM_IOUNIT_SAS_SLUMBER_MODE (0x000000008)
+#define MPI2_SASIOUNIT8_PM_IOUNIT_SAS_PARTIAL_MODE (0x000000004)
+#define MPI2_SASIOUNIT8_PM_IOUNIT_SATA_SLUMBER_MODE (0x000000002)
+#define MPI2_SASIOUNIT8_PM_IOUNIT_SATA_PARTIAL_MODE (0x000000001)
@@ -2182,7 +2331,7 @@ typedef struct _MPI2_SASPHY2_PHY_EVENT {
/*
* Host code (drivers, BIOS, utilities, etc.) should leave this define set to
- * one and check Header.ExtPageLength or NumPhyEvents at runtime.
+ * one and check the value returned for NumPhyEvents at runtime.
*/
#ifndef MPI2_SASPHY2_PHY_EVENT_MAX
#define MPI2_SASPHY2_PHY_EVENT_MAX (1)
@@ -2274,7 +2423,7 @@ typedef struct _MPI2_SASPHY3_PHY_EVENT_CONFIG {
/*
* Host code (drivers, BIOS, utilities, etc.) should leave this define set to
- * one and check Header.ExtPageLength or NumPhyEvents at runtime.
+ * one and check the value returned for NumPhyEvents at runtime.
*/
#ifndef MPI2_SASPHY3_PHY_EVENT_MAX
#define MPI2_SASPHY3_PHY_EVENT_MAX (1)
@@ -2385,7 +2534,7 @@ typedef struct _MPI2_CONFIG_PAGE_SAS_ENCLOSURE_0
/*
* Host code (drivers, BIOS, utilities, etc.) should leave this define set to
- * one and check Header.ExtPageLength or NumPhys at runtime.
+ * one and check the value returned for NumLogEntries at runtime.
*/
#ifndef MPI2_LOG_0_NUM_LOG_ENTRIES
#define MPI2_LOG_0_NUM_LOG_ENTRIES (1)
@@ -2435,7 +2584,7 @@ typedef struct _MPI2_CONFIG_PAGE_LOG_0
/*
* Host code (drivers, BIOS, utilities, etc.) should leave this define set to
- * one and check Header.ExtPageLength or NumPhys at runtime.
+ * one and check the value returned for NumElements at runtime.
*/
#ifndef MPI2_RAIDCONFIG0_MAX_ELEMENTS
#define MPI2_RAIDCONFIG0_MAX_ELEMENTS (1)
diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_init.h b/drivers/scsi/mpt2sas/mpi/mpi2_init.h
index 220bf65a921..c4c99dfcb82 100644
--- a/drivers/scsi/mpt2sas/mpi/mpi2_init.h
+++ b/drivers/scsi/mpt2sas/mpi/mpi2_init.h
@@ -6,7 +6,7 @@
* Title: MPI SCSI initiator mode messages and structures
* Creation Date: June 23, 2006
*
- * mpi2_init.h Version: 02.00.08
+ * mpi2_init.h Version: 02.00.09
*
* Version History
* ---------------
@@ -31,6 +31,7 @@
* both SCSI IO Error Reply and SCSI Task Management Reply.
* Added ResponseInfo field to MPI2_SCSI_TASK_MANAGE_REPLY.
* Added MPI2_SCSITASKMGMT_RSP_TM_OVERLAPPED_TAG define.
+ * 02-10-10 02.00.09 Removed unused structure that had "#if 0" around it.
* --------------------------------------------------------------------------
*/
@@ -57,20 +58,6 @@ typedef struct
} MPI2_SCSI_IO_CDB_EEDP32, MPI2_POINTER PTR_MPI2_SCSI_IO_CDB_EEDP32,
Mpi2ScsiIoCdbEedp32_t, MPI2_POINTER pMpi2ScsiIoCdbEedp32_t;
-/* TBD: I don't think this is needed for MPI2/Gen2 */
-#if 0
-typedef struct
-{
- U8 CDB[16]; /* 0x00 */
- U32 DataLength; /* 0x10 */
- U32 PrimaryReferenceTag; /* 0x14 */
- U16 PrimaryApplicationTag; /* 0x18 */
- U16 PrimaryApplicationTagMask; /* 0x1A */
- U32 TransferLength; /* 0x1C */
-} MPI2_SCSI_IO32_CDB_EEDP16, MPI2_POINTER PTR_MPI2_SCSI_IO32_CDB_EEDP16,
- Mpi2ScsiIo32CdbEedp16_t, MPI2_POINTER pMpi2ScsiIo32CdbEedp16_t;
-#endif
-
typedef union
{
U8 CDB32[32];
diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_ioc.h b/drivers/scsi/mpt2sas/mpi/mpi2_ioc.h
index f18f114922b..495bedc4d1f 100644
--- a/drivers/scsi/mpt2sas/mpi/mpi2_ioc.h
+++ b/drivers/scsi/mpt2sas/mpi/mpi2_ioc.h
@@ -6,7 +6,7 @@
* Title: MPI IOC, Port, Event, FW Download, and FW Upload messages
* Creation Date: October 11, 2006
*
- * mpi2_ioc.h Version: 02.00.13
+ * mpi2_ioc.h Version: 02.00.14
*
* Version History
* ---------------
@@ -98,6 +98,9 @@
* (MPI2_FW_HEADER_PID_).
* Modified values for SAS ProductID Family
* (MPI2_FW_HEADER_PID_FAMILY_).
+ * 02-10-10 02.00.14 Added SAS Quiesce Event structure and defines.
+ * Added PowerManagementControl Request structures and
+ * defines.
* --------------------------------------------------------------------------
*/
@@ -469,6 +472,7 @@ typedef struct _MPI2_EVENT_NOTIFICATION_REPLY
#define MPI2_EVENT_SAS_PHY_COUNTER (0x0022)
#define MPI2_EVENT_GPIO_INTERRUPT (0x0023)
#define MPI2_EVENT_HOST_BASED_DISCOVERY_PHY (0x0024)
+#define MPI2_EVENT_SAS_QUIESCE (0x0025)
/* Log Entry Added Event data */
@@ -895,6 +899,22 @@ typedef struct _MPI2_EVENT_DATA_SAS_PHY_COUNTER {
* */
+/* SAS Quiesce Event data */
+
+typedef struct _MPI2_EVENT_DATA_SAS_QUIESCE {
+ U8 ReasonCode; /* 0x00 */
+ U8 Reserved1; /* 0x01 */
+ U16 Reserved2; /* 0x02 */
+ U32 Reserved3; /* 0x04 */
+} MPI2_EVENT_DATA_SAS_QUIESCE,
+ MPI2_POINTER PTR_MPI2_EVENT_DATA_SAS_QUIESCE,
+ Mpi2EventDataSasQuiesce_t, MPI2_POINTER pMpi2EventDataSasQuiesce_t;
+
+/* SAS Quiesce Event data ReasonCode values */
+#define MPI2_EVENT_SAS_QUIESCE_RC_STARTED (0x01)
+#define MPI2_EVENT_SAS_QUIESCE_RC_COMPLETED (0x02)
+
+
/* Host Based Discovery Phy Event data */
typedef struct _MPI2_EVENT_HBD_PHY_SAS {
@@ -1006,6 +1026,7 @@ typedef struct _MPI2_FW_DOWNLOAD_REQUEST
#define MPI2_FW_DOWNLOAD_ITYPE_CONFIG_1 (0x07)
#define MPI2_FW_DOWNLOAD_ITYPE_CONFIG_2 (0x08)
#define MPI2_FW_DOWNLOAD_ITYPE_MEGARAID (0x09)
+#define MPI2_FW_DOWNLOAD_ITYPE_COMPLETE (0x0A)
#define MPI2_FW_DOWNLOAD_ITYPE_COMMON_BOOT_BLOCK (0x0B)
/* FWDownload TransactionContext Element */
@@ -1183,7 +1204,6 @@ typedef struct _MPI2_FW_IMAGE_HEADER
#define MPI2_FW_HEADER_PID_PROD_MASK (0x0F00)
#define MPI2_FW_HEADER_PID_PROD_A (0x0000)
-#define MPI2_FW_HEADER_PID_PROD_MASK (0x0F00)
#define MPI2_FW_HEADER_PID_PROD_TARGET_INITIATOR_SCSI (0x0200)
#define MPI2_FW_HEADER_PID_PROD_IR_SCSI (0x0700)
@@ -1407,5 +1427,100 @@ typedef struct _MPI2_INIT_IMAGE_FOOTER
#define MPI2_INIT_IMAGE_RESETVECTOR_OFFSET (0x14)
+/****************************************************************************
+* PowerManagementControl message
+****************************************************************************/
+
+/* PowerManagementControl Request message */
+typedef struct _MPI2_PWR_MGMT_CONTROL_REQUEST {
+ U8 Feature; /* 0x00 */
+ U8 Reserved1; /* 0x01 */
+ U8 ChainOffset; /* 0x02 */
+ U8 Function; /* 0x03 */
+ U16 Reserved2; /* 0x04 */
+ U8 Reserved3; /* 0x06 */
+ U8 MsgFlags; /* 0x07 */
+ U8 VP_ID; /* 0x08 */
+ U8 VF_ID; /* 0x09 */
+ U16 Reserved4; /* 0x0A */
+ U8 Parameter1; /* 0x0C */
+ U8 Parameter2; /* 0x0D */
+ U8 Parameter3; /* 0x0E */
+ U8 Parameter4; /* 0x0F */
+ U32 Reserved5; /* 0x10 */
+ U32 Reserved6; /* 0x14 */
+} MPI2_PWR_MGMT_CONTROL_REQUEST, MPI2_POINTER PTR_MPI2_PWR_MGMT_CONTROL_REQUEST,
+ Mpi2PwrMgmtControlRequest_t, MPI2_POINTER pMpi2PwrMgmtControlRequest_t;
+
+/* defines for the Feature field */
+#define MPI2_PM_CONTROL_FEATURE_DA_PHY_POWER_COND (0x01)
+#define MPI2_PM_CONTROL_FEATURE_PORT_WIDTH_MODULATION (0x02)
+#define MPI2_PM_CONTROL_FEATURE_PCIE_LINK (0x03)
+#define MPI2_PM_CONTROL_FEATURE_IOC_SPEED (0x04)
+#define MPI2_PM_CONTROL_FEATURE_MIN_PRODUCT_SPECIFIC (0x80)
+#define MPI2_PM_CONTROL_FEATURE_MAX_PRODUCT_SPECIFIC (0xFF)
+
+/* parameter usage for the MPI2_PM_CONTROL_FEATURE_DA_PHY_POWER_COND Feature */
+/* Parameter1 contains a PHY number */
+/* Parameter2 indicates power condition action using these defines */
+#define MPI2_PM_CONTROL_PARAM2_PARTIAL (0x01)
+#define MPI2_PM_CONTROL_PARAM2_SLUMBER (0x02)
+#define MPI2_PM_CONTROL_PARAM2_EXIT_PWR_MGMT (0x03)
+/* Parameter3 and Parameter4 are reserved */
+
+/* parameter usage for the MPI2_PM_CONTROL_FEATURE_PORT_WIDTH_MODULATION
+ * Feature */
+/* Parameter1 contains SAS port width modulation group number */
+/* Parameter2 indicates IOC action using these defines */
+#define MPI2_PM_CONTROL_PARAM2_REQUEST_OWNERSHIP (0x01)
+#define MPI2_PM_CONTROL_PARAM2_CHANGE_MODULATION (0x02)
+#define MPI2_PM_CONTROL_PARAM2_RELINQUISH_OWNERSHIP (0x03)
+/* Parameter3 indicates desired modulation level using these defines */
+#define MPI2_PM_CONTROL_PARAM3_25_PERCENT (0x00)
+#define MPI2_PM_CONTROL_PARAM3_50_PERCENT (0x01)
+#define MPI2_PM_CONTROL_PARAM3_75_PERCENT (0x02)
+#define MPI2_PM_CONTROL_PARAM3_100_PERCENT (0x03)
+/* Parameter4 is reserved */
+
+/* parameter usage for the MPI2_PM_CONTROL_FEATURE_PCIE_LINK Feature */
+/* Parameter1 indicates desired PCIe link speed using these defines */
+#define MPI2_PM_CONTROL_PARAM1_PCIE_2_5_GBPS (0x00)
+#define MPI2_PM_CONTROL_PARAM1_PCIE_5_0_GBPS (0x01)
+#define MPI2_PM_CONTROL_PARAM1_PCIE_8_0_GBPS (0x02)
+/* Parameter2 indicates desired PCIe link width using these defines */
+#define MPI2_PM_CONTROL_PARAM2_WIDTH_X1 (0x01)
+#define MPI2_PM_CONTROL_PARAM2_WIDTH_X2 (0x02)
+#define MPI2_PM_CONTROL_PARAM2_WIDTH_X4 (0x04)
+#define MPI2_PM_CONTROL_PARAM2_WIDTH_X8 (0x08)
+/* Parameter3 and Parameter4 are reserved */
+
+/* parameter usage for the MPI2_PM_CONTROL_FEATURE_IOC_SPEED Feature */
+/* Parameter1 indicates desired IOC hardware clock speed using these defines */
+#define MPI2_PM_CONTROL_PARAM1_FULL_IOC_SPEED (0x01)
+#define MPI2_PM_CONTROL_PARAM1_HALF_IOC_SPEED (0x02)
+#define MPI2_PM_CONTROL_PARAM1_QUARTER_IOC_SPEED (0x04)
+#define MPI2_PM_CONTROL_PARAM1_EIGHTH_IOC_SPEED (0x08)
+/* Parameter2, Parameter3, and Parameter4 are reserved */
+
+
+/* PowerManagementControl Reply message */
+typedef struct _MPI2_PWR_MGMT_CONTROL_REPLY {
+ U8 Feature; /* 0x00 */
+ U8 Reserved1; /* 0x01 */
+ U8 MsgLength; /* 0x02 */
+ U8 Function; /* 0x03 */
+ U16 Reserved2; /* 0x04 */
+ U8 Reserved3; /* 0x06 */
+ U8 MsgFlags; /* 0x07 */
+ U8 VP_ID; /* 0x08 */
+ U8 VF_ID; /* 0x09 */
+ U16 Reserved4; /* 0x0A */
+ U16 Reserved5; /* 0x0C */
+ U16 IOCStatus; /* 0x0E */
+ U32 IOCLogInfo; /* 0x10 */
+} MPI2_PWR_MGMT_CONTROL_REPLY, MPI2_POINTER PTR_MPI2_PWR_MGMT_CONTROL_REPLY,
+ Mpi2PwrMgmtControlReply_t, MPI2_POINTER pMpi2PwrMgmtControlReply_t;
+
+
#endif
diff --git a/drivers/scsi/mpt2sas/mpt2sas_base.c b/drivers/scsi/mpt2sas/mpt2sas_base.c
index 0ec1ed389c2..57bcd5c9dcf 100644
--- a/drivers/scsi/mpt2sas/mpt2sas_base.c
+++ b/drivers/scsi/mpt2sas/mpt2sas_base.c
@@ -95,6 +95,10 @@ int mpt2sas_fwfault_debug;
MODULE_PARM_DESC(mpt2sas_fwfault_debug, " enable detection of firmware fault "
"and halt firmware - (default=0)");
+static int disable_discovery = -1;
+module_param(disable_discovery, int, 0);
+MODULE_PARM_DESC(disable_discovery, " disable discovery ");
+
/**
* _scsih_set_fwfault_debug - global setting of ioc->fwfault_debug.
*
@@ -1238,7 +1242,7 @@ mpt2sas_base_map_resources(struct MPT2SAS_ADAPTER *ioc)
u64 pio_chip = 0;
u64 chip_phys = 0;
- dinitprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n",
+ dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n",
ioc->name, __func__));
ioc->bars = pci_select_bars(pdev, IORESOURCE_MEM);
@@ -1307,6 +1311,9 @@ mpt2sas_base_map_resources(struct MPT2SAS_ADAPTER *ioc)
printk(MPT2SAS_INFO_FMT "ioport(0x%016llx), size(%d)\n",
ioc->name, (unsigned long long)pio_chip, pio_sz);
+ /* Save PCI configuration state for recovery from PCI AER/EEH errors */
+ pci_save_state(pdev);
+
return 0;
out_fail:
@@ -1861,7 +1868,7 @@ _base_static_config_pages(struct MPT2SAS_ADAPTER *ioc)
static void
_base_release_memory_pools(struct MPT2SAS_ADAPTER *ioc)
{
- dexitprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name,
+ dexitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
__func__));
if (ioc->request) {
@@ -1947,7 +1954,7 @@ _base_allocate_memory_pools(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
u32 retry_sz;
u16 max_request_credit;
- dinitprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name,
+ dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
__func__));
retry_sz = 0;
@@ -2374,7 +2381,7 @@ _base_wait_for_doorbell_int(struct MPT2SAS_ADAPTER *ioc, int timeout,
do {
int_status = readl(&ioc->chip->HostInterruptStatus);
if (int_status & MPI2_HIS_IOC2SYS_DB_STATUS) {
- dhsprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: "
+ dhsprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: "
"successfull count(%d), timeout(%d)\n", ioc->name,
__func__, count, timeout));
return 0;
@@ -2415,7 +2422,7 @@ _base_wait_for_doorbell_ack(struct MPT2SAS_ADAPTER *ioc, int timeout,
do {
int_status = readl(&ioc->chip->HostInterruptStatus);
if (!(int_status & MPI2_HIS_SYS2IOC_DB_STATUS)) {
- dhsprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: "
+ dhsprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: "
"successfull count(%d), timeout(%d)\n", ioc->name,
__func__, count, timeout));
return 0;
@@ -2463,7 +2470,7 @@ _base_wait_for_doorbell_not_used(struct MPT2SAS_ADAPTER *ioc, int timeout,
do {
doorbell_reg = readl(&ioc->chip->Doorbell);
if (!(doorbell_reg & MPI2_DOORBELL_USED)) {
- dhsprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: "
+ dhsprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: "
"successfull count(%d), timeout(%d)\n", ioc->name,
__func__, count, timeout));
return 0;
@@ -2637,9 +2644,9 @@ _base_handshake_req_reply_wait(struct MPT2SAS_ADAPTER *ioc, int request_bytes,
if (ioc->logging_level & MPT_DEBUG_INIT) {
mfp = (u32 *)reply;
- printk(KERN_DEBUG "\toffset:data\n");
+ printk(KERN_INFO "\toffset:data\n");
for (i = 0; i < reply_bytes/4; i++)
- printk(KERN_DEBUG "\t[0x%02x]:%08x\n", i*4,
+ printk(KERN_INFO "\t[0x%02x]:%08x\n", i*4,
le32_to_cpu(mfp[i]));
}
return 0;
@@ -2672,7 +2679,7 @@ mpt2sas_base_sas_iounit_control(struct MPT2SAS_ADAPTER *ioc,
void *request;
u16 wait_state_count;
- dinitprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name,
+ dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
__func__));
mutex_lock(&ioc->base_cmds.mutex);
@@ -2777,7 +2784,7 @@ mpt2sas_base_scsi_enclosure_processor(struct MPT2SAS_ADAPTER *ioc,
void *request;
u16 wait_state_count;
- dinitprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name,
+ dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
__func__));
mutex_lock(&ioc->base_cmds.mutex);
@@ -2865,7 +2872,7 @@ _base_get_port_facts(struct MPT2SAS_ADAPTER *ioc, int port, int sleep_flag)
Mpi2PortFactsReply_t mpi_reply, *pfacts;
int mpi_reply_sz, mpi_request_sz, r;
- dinitprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name,
+ dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
__func__));
mpi_reply_sz = sizeof(Mpi2PortFactsReply_t);
@@ -2907,7 +2914,7 @@ _base_get_ioc_facts(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
Mpi2IOCFactsReply_t mpi_reply, *facts;
int mpi_reply_sz, mpi_request_sz, r;
- dinitprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name,
+ dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
__func__));
mpi_reply_sz = sizeof(Mpi2IOCFactsReply_t);
@@ -2979,7 +2986,7 @@ _base_send_ioc_init(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
struct timeval current_time;
u16 ioc_status;
- dinitprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name,
+ dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
__func__));
memset(&mpi_request, 0, sizeof(Mpi2IOCInitRequest_t));
@@ -3040,9 +3047,9 @@ _base_send_ioc_init(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
int i;
mfp = (u32 *)&mpi_request;
- printk(KERN_DEBUG "\toffset:data\n");
+ printk(KERN_INFO "\toffset:data\n");
for (i = 0; i < sizeof(Mpi2IOCInitRequest_t)/4; i++)
- printk(KERN_DEBUG "\t[0x%02x]:%08x\n", i*4,
+ printk(KERN_INFO "\t[0x%02x]:%08x\n", i*4,
le32_to_cpu(mfp[i]));
}
@@ -3121,7 +3128,7 @@ _base_send_port_enable(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
r = -ETIME;
goto out;
} else
- dinitprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: complete\n",
+ dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: complete\n",
ioc->name, __func__));
ioc_state = _base_wait_on_iocstate(ioc, MPI2_IOC_STATE_OPERATIONAL,
@@ -3181,7 +3188,7 @@ _base_event_notification(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
int r = 0;
int i;
- dinitprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name,
+ dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
__func__));
if (ioc->base_cmds.status & MPT2_CMD_PENDING) {
@@ -3219,7 +3226,7 @@ _base_event_notification(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
else
r = -ETIME;
} else
- dinitprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: complete\n",
+ dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: complete\n",
ioc->name, __func__));
ioc->base_cmds.status = MPT2_CMD_NOT_USED;
return r;
@@ -3281,7 +3288,7 @@ _base_diag_reset(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
_base_save_msix_table(ioc);
- drsprintk(ioc, printk(MPT2SAS_DEBUG_FMT "clear interrupts\n",
+ drsprintk(ioc, printk(MPT2SAS_INFO_FMT "clear interrupts\n",
ioc->name));
count = 0;
@@ -3289,7 +3296,7 @@ _base_diag_reset(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
/* Write magic sequence to WriteSequence register
* Loop until in diagnostic mode
*/
- drsprintk(ioc, printk(MPT2SAS_DEBUG_FMT "write magic "
+ drsprintk(ioc, printk(MPT2SAS_INFO_FMT "write magic "
"sequence\n", ioc->name));
writel(MPI2_WRSEQ_FLUSH_KEY_VALUE, &ioc->chip->WriteSequence);
writel(MPI2_WRSEQ_1ST_KEY_VALUE, &ioc->chip->WriteSequence);
@@ -3309,7 +3316,7 @@ _base_diag_reset(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
goto out;
host_diagnostic = readl(&ioc->chip->HostDiagnostic);
- drsprintk(ioc, printk(MPT2SAS_DEBUG_FMT "wrote magic "
+ drsprintk(ioc, printk(MPT2SAS_INFO_FMT "wrote magic "
"sequence: count(%d), host_diagnostic(0x%08x)\n",
ioc->name, count, host_diagnostic));
@@ -3317,7 +3324,7 @@ _base_diag_reset(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
hcb_size = readl(&ioc->chip->HCBSize);
- drsprintk(ioc, printk(MPT2SAS_DEBUG_FMT "diag reset: issued\n",
+ drsprintk(ioc, printk(MPT2SAS_INFO_FMT "diag reset: issued\n",
ioc->name));
writel(host_diagnostic | MPI2_DIAG_RESET_ADAPTER,
&ioc->chip->HostDiagnostic);
@@ -3344,29 +3351,29 @@ _base_diag_reset(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
if (host_diagnostic & MPI2_DIAG_HCB_MODE) {
- drsprintk(ioc, printk(MPT2SAS_DEBUG_FMT "restart the adapter "
+ drsprintk(ioc, printk(MPT2SAS_INFO_FMT "restart the adapter "
"assuming the HCB Address points to good F/W\n",
ioc->name));
host_diagnostic &= ~MPI2_DIAG_BOOT_DEVICE_SELECT_MASK;
host_diagnostic |= MPI2_DIAG_BOOT_DEVICE_SELECT_HCDW;
writel(host_diagnostic, &ioc->chip->HostDiagnostic);
- drsprintk(ioc, printk(MPT2SAS_DEBUG_FMT
+ drsprintk(ioc, printk(MPT2SAS_INFO_FMT
"re-enable the HCDW\n", ioc->name));
writel(hcb_size | MPI2_HCB_SIZE_HCB_ENABLE,
&ioc->chip->HCBSize);
}
- drsprintk(ioc, printk(MPT2SAS_DEBUG_FMT "restart the adapter\n",
+ drsprintk(ioc, printk(MPT2SAS_INFO_FMT "restart the adapter\n",
ioc->name));
writel(host_diagnostic & ~MPI2_DIAG_HOLD_IOC_RESET,
&ioc->chip->HostDiagnostic);
- drsprintk(ioc, printk(MPT2SAS_DEBUG_FMT "disable writes to the "
+ drsprintk(ioc, printk(MPT2SAS_INFO_FMT "disable writes to the "
"diagnostic register\n", ioc->name));
writel(MPI2_WRSEQ_FLUSH_KEY_VALUE, &ioc->chip->WriteSequence);
- drsprintk(ioc, printk(MPT2SAS_DEBUG_FMT "Wait for FW to go to the "
+ drsprintk(ioc, printk(MPT2SAS_INFO_FMT "Wait for FW to go to the "
"READY state\n", ioc->name));
ioc_state = _base_wait_on_iocstate(ioc, MPI2_IOC_STATE_READY, 20,
sleep_flag);
@@ -3398,19 +3405,23 @@ _base_make_ioc_ready(struct MPT2SAS_ADAPTER *ioc, int sleep_flag,
enum reset_type type)
{
u32 ioc_state;
+ int rc;
- dinitprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name,
+ dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
__func__));
+ if (ioc->pci_error_recovery)
+ return 0;
+
ioc_state = mpt2sas_base_get_iocstate(ioc, 0);
- dhsprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: ioc_state(0x%08x)\n",
+ dhsprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: ioc_state(0x%08x)\n",
ioc->name, __func__, ioc_state));
if ((ioc_state & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_READY)
return 0;
if (ioc_state & MPI2_DOORBELL_USED) {
- dhsprintk(ioc, printk(MPT2SAS_DEBUG_FMT "unexpected doorbell "
+ dhsprintk(ioc, printk(MPT2SAS_INFO_FMT "unexpected doorbell "
"active!\n", ioc->name));
goto issue_diag_reset;
}
@@ -3426,11 +3437,15 @@ _base_make_ioc_ready(struct MPT2SAS_ADAPTER *ioc, int sleep_flag,
if ((ioc_state & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_OPERATIONAL)
if (!(_base_send_ioc_reset(ioc,
- MPI2_FUNCTION_IOC_MESSAGE_UNIT_RESET, 15, CAN_SLEEP)))
+ MPI2_FUNCTION_IOC_MESSAGE_UNIT_RESET, 15, CAN_SLEEP))) {
+ ioc->ioc_reset_count++;
return 0;
+ }
issue_diag_reset:
- return _base_diag_reset(ioc, CAN_SLEEP);
+ rc = _base_diag_reset(ioc, CAN_SLEEP);
+ ioc->ioc_reset_count++;
+ return rc;
}
/**
@@ -3449,7 +3464,7 @@ _base_make_ioc_operational(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
u16 smid;
struct _tr_list *delayed_tr, *delayed_tr_next;
- dinitprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name,
+ dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
__func__));
/* clean the delayed target reset list */
@@ -3459,6 +3474,12 @@ _base_make_ioc_operational(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
kfree(delayed_tr);
}
+ list_for_each_entry_safe(delayed_tr, delayed_tr_next,
+ &ioc->delayed_tr_volume_list, list) {
+ list_del(&delayed_tr->list);
+ kfree(delayed_tr);
+ }
+
/* initialize the scsi lookup free list */
spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
INIT_LIST_HEAD(&ioc->free_list);
@@ -3520,6 +3541,13 @@ _base_make_ioc_operational(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
if (sleep_flag == CAN_SLEEP)
_base_static_config_pages(ioc);
+ if (ioc->wait_for_port_enable_to_complete) {
+ if (diag_buffer_enable != 0)
+ mpt2sas_enable_diag_buffer(ioc, diag_buffer_enable);
+ if (disable_discovery > 0)
+ return r;
+ }
+
r = _base_send_port_enable(ioc, sleep_flag);
if (r)
return r;
@@ -3538,7 +3566,7 @@ mpt2sas_base_free_resources(struct MPT2SAS_ADAPTER *ioc)
{
struct pci_dev *pdev = ioc->pdev;
- dexitprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name,
+ dexitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
__func__));
_base_mask_interrupts(ioc);
@@ -3571,7 +3599,7 @@ mpt2sas_base_attach(struct MPT2SAS_ADAPTER *ioc)
{
int r, i;
- dinitprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name,
+ dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
__func__));
r = mpt2sas_base_map_resources(ioc);
@@ -3606,6 +3634,17 @@ mpt2sas_base_attach(struct MPT2SAS_ADAPTER *ioc)
init_waitqueue_head(&ioc->reset_wq);
+ /* allocate memory pd handle bitmask list */
+ ioc->pd_handles_sz = (ioc->facts.MaxDevHandle / 8);
+ if (ioc->facts.MaxDevHandle % 8)
+ ioc->pd_handles_sz++;
+ ioc->pd_handles = kzalloc(ioc->pd_handles_sz,
+ GFP_KERNEL);
+ if (!ioc->pd_handles) {
+ r = -ENOMEM;
+ goto out_free_resources;
+ }
+
ioc->fwfault_debug = mpt2sas_fwfault_debug;
/* base internal command bits */
@@ -3635,11 +3674,20 @@ mpt2sas_base_attach(struct MPT2SAS_ADAPTER *ioc)
/* ctl module internal command bits */
ioc->ctl_cmds.reply = kzalloc(ioc->reply_sz, GFP_KERNEL);
+ ioc->ctl_cmds.sense = kzalloc(SCSI_SENSE_BUFFERSIZE, GFP_KERNEL);
ioc->ctl_cmds.status = MPT2_CMD_NOT_USED;
mutex_init(&ioc->ctl_cmds.mutex);
if (!ioc->base_cmds.reply || !ioc->transport_cmds.reply ||
!ioc->scsih_cmds.reply || !ioc->tm_cmds.reply ||
+ !ioc->config_cmds.reply || !ioc->ctl_cmds.reply ||
+ !ioc->ctl_cmds.sense) {
+ r = -ENOMEM;
+ goto out_free_resources;
+ }
+
+ if (!ioc->base_cmds.reply || !ioc->transport_cmds.reply ||
+ !ioc->scsih_cmds.reply || !ioc->tm_cmds.reply ||
!ioc->config_cmds.reply || !ioc->ctl_cmds.reply) {
r = -ENOMEM;
goto out_free_resources;
@@ -3667,8 +3715,6 @@ mpt2sas_base_attach(struct MPT2SAS_ADAPTER *ioc)
goto out_free_resources;
mpt2sas_base_start_watchdog(ioc);
- if (diag_buffer_enable != 0)
- mpt2sas_enable_diag_buffer(ioc, diag_buffer_enable);
return 0;
out_free_resources:
@@ -3677,12 +3723,14 @@ mpt2sas_base_attach(struct MPT2SAS_ADAPTER *ioc)
mpt2sas_base_free_resources(ioc);
_base_release_memory_pools(ioc);
pci_set_drvdata(ioc->pdev, NULL);
+ kfree(ioc->pd_handles);
kfree(ioc->tm_cmds.reply);
kfree(ioc->transport_cmds.reply);
kfree(ioc->scsih_cmds.reply);
kfree(ioc->config_cmds.reply);
kfree(ioc->base_cmds.reply);
kfree(ioc->ctl_cmds.reply);
+ kfree(ioc->ctl_cmds.sense);
kfree(ioc->pfacts);
ioc->ctl_cmds.reply = NULL;
ioc->base_cmds.reply = NULL;
@@ -3705,15 +3753,17 @@ void
mpt2sas_base_detach(struct MPT2SAS_ADAPTER *ioc)
{
- dexitprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name,
+ dexitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
__func__));
mpt2sas_base_stop_watchdog(ioc);
mpt2sas_base_free_resources(ioc);
_base_release_memory_pools(ioc);
pci_set_drvdata(ioc->pdev, NULL);
+ kfree(ioc->pd_handles);
kfree(ioc->pfacts);
kfree(ioc->ctl_cmds.reply);
+ kfree(ioc->ctl_cmds.sense);
kfree(ioc->base_cmds.reply);
kfree(ioc->tm_cmds.reply);
kfree(ioc->transport_cmds.reply);
@@ -3738,11 +3788,11 @@ _base_reset_handler(struct MPT2SAS_ADAPTER *ioc, int reset_phase)
{
switch (reset_phase) {
case MPT2_IOC_PRE_RESET:
- dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: "
+ dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: "
"MPT2_IOC_PRE_RESET\n", ioc->name, __func__));
break;
case MPT2_IOC_AFTER_RESET:
- dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: "
+ dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: "
"MPT2_IOC_AFTER_RESET\n", ioc->name, __func__));
if (ioc->transport_cmds.status & MPT2_CMD_PENDING) {
ioc->transport_cmds.status |= MPT2_CMD_RESET;
@@ -3762,7 +3812,7 @@ _base_reset_handler(struct MPT2SAS_ADAPTER *ioc, int reset_phase)
}
break;
case MPT2_IOC_DONE_RESET:
- dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: "
+ dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: "
"MPT2_IOC_DONE_RESET\n", ioc->name, __func__));
break;
}
@@ -3804,7 +3854,7 @@ _wait_for_commands_to_complete(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
return;
/* wait for pending commands to complete */
- wait_event_timeout(ioc->reset_wq, ioc->pending_io_count == 0, 3 * HZ);
+ wait_event_timeout(ioc->reset_wq, ioc->pending_io_count == 0, 10 * HZ);
}
/**
@@ -3822,19 +3872,37 @@ mpt2sas_base_hard_reset_handler(struct MPT2SAS_ADAPTER *ioc, int sleep_flag,
int r;
unsigned long flags;
- dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: enter\n", ioc->name,
+ dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: enter\n", ioc->name,
__func__));
+ if (ioc->pci_error_recovery) {
+ printk(MPT2SAS_ERR_FMT "%s: pci error recovery reset\n",
+ ioc->name, __func__);
+ r = 0;
+ goto out;
+ }
+
if (mpt2sas_fwfault_debug)
mpt2sas_halt_firmware(ioc);
- spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags);
- if (ioc->shost_recovery) {
- spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags);
- printk(MPT2SAS_ERR_FMT "%s: busy\n",
- ioc->name, __func__);
- return -EBUSY;
+ /* TODO - What we really should be doing is pulling
+ * out all the code associated with NO_SLEEP; its never used.
+ * That is legacy code from mpt fusion driver, ported over.
+ * I will leave this BUG_ON here for now till its been resolved.
+ */
+ BUG_ON(sleep_flag == NO_SLEEP);
+
+ /* wait for an active reset in progress to complete */
+ if (!mutex_trylock(&ioc->reset_in_progress_mutex)) {
+ do {
+ ssleep(1);
+ } while (ioc->shost_recovery == 1);
+ dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: exit\n", ioc->name,
+ __func__));
+ return ioc->ioc_reset_in_progress_status;
}
+
+ spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags);
ioc->shost_recovery = 1;
spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags);
@@ -3849,13 +3917,17 @@ mpt2sas_base_hard_reset_handler(struct MPT2SAS_ADAPTER *ioc, int sleep_flag,
if (!r)
_base_reset_handler(ioc, MPT2_IOC_DONE_RESET);
out:
- dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: %s\n",
+ dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: %s\n",
ioc->name, __func__, ((r == 0) ? "SUCCESS" : "FAILED")));
spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags);
+ ioc->ioc_reset_in_progress_status = r;
ioc->shost_recovery = 0;
complete(&ioc->shost_recovery_done);
spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags);
+ mutex_unlock(&ioc->reset_in_progress_mutex);
+ dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: exit\n", ioc->name,
+ __func__));
return r;
}
diff --git a/drivers/scsi/mpt2sas/mpt2sas_base.h b/drivers/scsi/mpt2sas/mpt2sas_base.h
index b4afe431ac1..0b15a8bdebf 100644
--- a/drivers/scsi/mpt2sas/mpt2sas_base.h
+++ b/drivers/scsi/mpt2sas/mpt2sas_base.h
@@ -69,11 +69,11 @@
#define MPT2SAS_DRIVER_NAME "mpt2sas"
#define MPT2SAS_AUTHOR "LSI Corporation <DL-MPTFusionLinux@lsi.com>"
#define MPT2SAS_DESCRIPTION "LSI MPT Fusion SAS 2.0 Device Driver"
-#define MPT2SAS_DRIVER_VERSION "05.100.00.02"
-#define MPT2SAS_MAJOR_VERSION 05
+#define MPT2SAS_DRIVER_VERSION "06.100.00.00"
+#define MPT2SAS_MAJOR_VERSION 06
#define MPT2SAS_MINOR_VERSION 100
#define MPT2SAS_BUILD_VERSION 00
-#define MPT2SAS_RELEASE_VERSION 02
+#define MPT2SAS_RELEASE_VERSION 00
/*
* Set MPT2SAS_SG_DEPTH value based on user input.
@@ -124,7 +124,6 @@
* logging format
*/
#define MPT2SAS_FMT "%s: "
-#define MPT2SAS_DEBUG_FMT KERN_DEBUG MPT2SAS_FMT
#define MPT2SAS_INFO_FMT KERN_INFO MPT2SAS_FMT
#define MPT2SAS_NOTE_FMT KERN_NOTICE MPT2SAS_FMT
#define MPT2SAS_WARN_FMT KERN_WARNING MPT2SAS_FMT
@@ -248,6 +247,7 @@ struct MPT2SAS_DEVICE {
* @mutex: mutex
* @done: completion
* @reply: reply message pointer
+ * @sense: sense data
* @status: MPT2_CMD_XXX status
* @smid: system message id
*/
@@ -255,6 +255,7 @@ struct _internal_cmd {
struct mutex mutex;
struct completion done;
void *reply;
+ void *sense;
u16 status;
u16 smid;
};
@@ -276,7 +277,7 @@ struct _internal_cmd {
* @id: target id
* @channel: target channel
* @slot: number number
- * @hidden_raid_component: set to 1 when this is a raid member
+ * @phy: phy identifier provided in sas device page 0
* @responding: used in _scsih_sas_device_mark_responding
*/
struct _sas_device {
@@ -294,7 +295,7 @@ struct _sas_device {
int id;
int channel;
u16 slot;
- u8 hidden_raid_component;
+ u8 phy;
u8 responding;
};
@@ -474,8 +475,9 @@ typedef void (*MPT_ADD_SGE)(void *paddr, u32 flags_length, dma_addr_t dma_addr);
* @shost_recovery: host reset in progress
* @ioc_reset_in_progress_lock:
* @ioc_link_reset_in_progress: phy/hard reset in progress
- * @ignore_loginfos: ignore loginfos during task managment
+ * @ignore_loginfos: ignore loginfos during task management
* @remove_host: flag for when driver unloads, to avoid sending dev resets
+ * @pci_error_recovery: flag to prevent ioc access until slot reset completes
* @wait_for_port_enable_to_complete:
* @msix_enable: flag indicating msix is enabled
* @msix_vector_count: number msix vectors
@@ -488,6 +490,8 @@ typedef void (*MPT_ADD_SGE)(void *paddr, u32 flags_length, dma_addr_t dma_addr);
* @ctl_cb_idx: clt internal commands
* @base_cb_idx: base internal commands
* @config_cb_idx: base internal commands
+ * @tm_tr_cb_idx : device removal target reset handshake
+ * @tm_tr_volume_cb_idx : volume removal target reset
* @base_cmds:
* @transport_cmds:
* @scsih_cmds:
@@ -516,6 +520,9 @@ typedef void (*MPT_ADD_SGE)(void *paddr, u32 flags_length, dma_addr_t dma_addr);
* @sas_device_lock:
* @io_missing_delay: time for IO completed by fw when PDR enabled
* @device_missing_delay: time for device missing by fw when PDR enabled
+ * @sas_id : used for setting volume target IDs
+ * @pd_handles : bitmask for PD handles
+ * @pd_handles_sz : size of pd_handle bitmask
* @config_page_sz: config page size
* @config_page: reserve memory for config page payload
* @config_page_dma:
@@ -568,6 +575,8 @@ typedef void (*MPT_ADD_SGE)(void *paddr, u32 flags_length, dma_addr_t dma_addr);
* @reply_post_free_dma:
* @reply_post_free_dma_pool:
* @reply_post_host_index: head index in the pool where FW completes IO
+ * @delayed_tr_list: target reset link list
+ * @delayed_tr_volume_list: volume target reset link list
*/
struct MPT2SAS_ADAPTER {
struct list_head list;
@@ -600,17 +609,23 @@ struct MPT2SAS_ADAPTER {
int aen_event_read_flag;
u8 broadcast_aen_busy;
u8 shost_recovery;
+
+ struct mutex reset_in_progress_mutex;
struct completion shost_recovery_done;
spinlock_t ioc_reset_in_progress_lock;
u8 ioc_link_reset_in_progress;
+ int ioc_reset_in_progress_status;
+
u8 ignore_loginfos;
u8 remove_host;
+ u8 pci_error_recovery;
u8 wait_for_port_enable_to_complete;
u8 msix_enable;
u16 msix_vector_count;
u32 *msix_table;
u32 *msix_table_backup;
+ u32 ioc_reset_count;
/* internal commands, callback index */
u8 scsi_io_cb_idx;
@@ -621,6 +636,7 @@ struct MPT2SAS_ADAPTER {
u8 base_cb_idx;
u8 config_cb_idx;
u8 tm_tr_cb_idx;
+ u8 tm_tr_volume_cb_idx;
u8 tm_sas_control_cb_idx;
struct _internal_cmd base_cmds;
struct _internal_cmd transport_cmds;
@@ -664,6 +680,9 @@ struct MPT2SAS_ADAPTER {
u16 device_missing_delay;
int sas_id;
+ void *pd_handles;
+ u16 pd_handles_sz;
+
/* config page */
u16 config_page_sz;
void *config_page;
@@ -735,6 +754,7 @@ struct MPT2SAS_ADAPTER {
u32 reply_post_host_index;
struct list_head delayed_tr_list;
+ struct list_head delayed_tr_volume_list;
/* diag buffer support */
u8 *diag_buffer[MPI2_DIAG_BUF_TYPE_COUNT];
@@ -745,6 +765,8 @@ struct MPT2SAS_ADAPTER {
Mpi2ManufacturingPage10_t manu_pg10;
u32 product_specific[MPI2_DIAG_BUF_TYPE_COUNT][23];
u32 diagnostic_flags[MPI2_DIAG_BUF_TYPE_COUNT];
+ u32 ring_buffer_offset;
+ u32 ring_buffer_sz;
};
typedef u8 (*MPT_CALLBACK)(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index,
diff --git a/drivers/scsi/mpt2sas/mpt2sas_config.c b/drivers/scsi/mpt2sas/mpt2sas_config.c
index c65442982d7..6afd67b324f 100644
--- a/drivers/scsi/mpt2sas/mpt2sas_config.c
+++ b/drivers/scsi/mpt2sas/mpt2sas_config.c
@@ -159,7 +159,7 @@ _config_display_some_debug(struct MPT2SAS_ADAPTER *ioc, u16 smid,
if (!desc)
return;
- printk(MPT2SAS_DEBUG_FMT "%s: %s(%d), action(%d), form(0x%08x), "
+ printk(MPT2SAS_INFO_FMT "%s: %s(%d), action(%d), form(0x%08x), "
"smid(%d)\n", ioc->name, calling_function_name, desc,
mpi_request->Header.PageNumber, mpi_request->Action,
le32_to_cpu(mpi_request->PageAddress), smid);
@@ -168,7 +168,7 @@ _config_display_some_debug(struct MPT2SAS_ADAPTER *ioc, u16 smid,
return;
if (mpi_reply->IOCStatus || mpi_reply->IOCLogInfo)
- printk(MPT2SAS_DEBUG_FMT
+ printk(MPT2SAS_INFO_FMT
"\tiocstatus(0x%04x), loginfo(0x%08x)\n",
ioc->name, le16_to_cpu(mpi_reply->IOCStatus),
le32_to_cpu(mpi_reply->IOCLogInfo));
@@ -401,7 +401,7 @@ _config_request(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigRequest_t
if (ioc->config_cmds.smid == smid)
mpt2sas_base_free_smid(ioc, smid);
if ((ioc->shost_recovery) || (ioc->config_cmds.status &
- MPT2_CMD_RESET))
+ MPT2_CMD_RESET) || ioc->pci_error_recovery)
goto retry_config;
issue_host_reset = 1;
r = -EFAULT;
diff --git a/drivers/scsi/mpt2sas/mpt2sas_ctl.c b/drivers/scsi/mpt2sas/mpt2sas_ctl.c
index d88e9756d8f..b774973f076 100644
--- a/drivers/scsi/mpt2sas/mpt2sas_ctl.c
+++ b/drivers/scsi/mpt2sas/mpt2sas_ctl.c
@@ -80,6 +80,32 @@ enum block_state {
BLOCKING,
};
+/**
+ * _ctl_sas_device_find_by_handle - sas device search
+ * @ioc: per adapter object
+ * @handle: sas device handle (assigned by firmware)
+ * Context: Calling function should acquire ioc->sas_device_lock
+ *
+ * This searches for sas_device based on sas_address, then return sas_device
+ * object.
+ */
+static struct _sas_device *
+_ctl_sas_device_find_by_handle(struct MPT2SAS_ADAPTER *ioc, u16 handle)
+{
+ struct _sas_device *sas_device, *r;
+
+ r = NULL;
+ list_for_each_entry(sas_device, &ioc->sas_device_list, list) {
+ if (sas_device->handle != handle)
+ continue;
+ r = sas_device;
+ goto out;
+ }
+
+ out:
+ return r;
+}
+
#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
/**
* _ctl_display_some_debug - debug routine
@@ -188,14 +214,14 @@ _ctl_display_some_debug(struct MPT2SAS_ADAPTER *ioc, u16 smid,
if (!desc)
return;
- printk(MPT2SAS_DEBUG_FMT "%s: %s, smid(%d)\n",
+ printk(MPT2SAS_INFO_FMT "%s: %s, smid(%d)\n",
ioc->name, calling_function_name, desc, smid);
if (!mpi_reply)
return;
if (mpi_reply->IOCStatus || mpi_reply->IOCLogInfo)
- printk(MPT2SAS_DEBUG_FMT
+ printk(MPT2SAS_INFO_FMT
"\tiocstatus(0x%04x), loginfo(0x%08x)\n",
ioc->name, le16_to_cpu(mpi_reply->IOCStatus),
le32_to_cpu(mpi_reply->IOCLogInfo));
@@ -205,8 +231,24 @@ _ctl_display_some_debug(struct MPT2SAS_ADAPTER *ioc, u16 smid,
MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH) {
Mpi2SCSIIOReply_t *scsi_reply =
(Mpi2SCSIIOReply_t *)mpi_reply;
+ struct _sas_device *sas_device = NULL;
+ unsigned long flags;
+
+ spin_lock_irqsave(&ioc->sas_device_lock, flags);
+ sas_device = _ctl_sas_device_find_by_handle(ioc,
+ le16_to_cpu(scsi_reply->DevHandle));
+ if (sas_device) {
+ printk(MPT2SAS_WARN_FMT "\tsas_address(0x%016llx), "
+ "phy(%d)\n", ioc->name, (unsigned long long)
+ sas_device->sas_address, sas_device->phy);
+ printk(MPT2SAS_WARN_FMT
+ "\tenclosure_logical_id(0x%016llx), slot(%d)\n",
+ ioc->name, sas_device->enclosure_logical_id,
+ sas_device->slot);
+ }
+ spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
if (scsi_reply->SCSIState || scsi_reply->SCSIStatus)
- printk(MPT2SAS_DEBUG_FMT
+ printk(MPT2SAS_INFO_FMT
"\tscsi_state(0x%02x), scsi_status"
"(0x%02x)\n", ioc->name,
scsi_reply->SCSIState,
@@ -233,6 +275,9 @@ mpt2sas_ctl_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index,
u32 reply)
{
MPI2DefaultReply_t *mpi_reply;
+ Mpi2SCSIIOReply_t *scsiio_reply;
+ const void *sense_data;
+ u32 sz;
if (ioc->ctl_cmds.status == MPT2_CMD_NOT_USED)
return 1;
@@ -243,6 +288,20 @@ mpt2sas_ctl_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index,
if (mpi_reply) {
memcpy(ioc->ctl_cmds.reply, mpi_reply, mpi_reply->MsgLength*4);
ioc->ctl_cmds.status |= MPT2_CMD_REPLY_VALID;
+ /* get sense data */
+ if (mpi_reply->Function == MPI2_FUNCTION_SCSI_IO_REQUEST ||
+ mpi_reply->Function ==
+ MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH) {
+ scsiio_reply = (Mpi2SCSIIOReply_t *)mpi_reply;
+ if (scsiio_reply->SCSIState &
+ MPI2_SCSI_STATE_AUTOSENSE_VALID) {
+ sz = min_t(u32, SCSI_SENSE_BUFFERSIZE,
+ le32_to_cpu(scsiio_reply->SenseCount));
+ sense_data = mpt2sas_base_get_sense_buffer(ioc,
+ smid);
+ memcpy(ioc->ctl_cmds.sense, sense_data, sz);
+ }
+ }
}
#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
_ctl_display_some_debug(ioc, smid, "ctl_done", mpi_reply);
@@ -392,7 +451,7 @@ mpt2sas_ctl_reset_handler(struct MPT2SAS_ADAPTER *ioc, int reset_phase)
switch (reset_phase) {
case MPT2_IOC_PRE_RESET:
- dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: "
+ dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: "
"MPT2_IOC_PRE_RESET\n", ioc->name, __func__));
for (i = 0; i < MPI2_DIAG_BUF_TYPE_COUNT; i++) {
if (!(ioc->diag_buffer_status[i] &
@@ -405,7 +464,7 @@ mpt2sas_ctl_reset_handler(struct MPT2SAS_ADAPTER *ioc, int reset_phase)
}
break;
case MPT2_IOC_AFTER_RESET:
- dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: "
+ dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: "
"MPT2_IOC_AFTER_RESET\n", ioc->name, __func__));
if (ioc->ctl_cmds.status & MPT2_CMD_PENDING) {
ioc->ctl_cmds.status |= MPT2_CMD_RESET;
@@ -414,7 +473,7 @@ mpt2sas_ctl_reset_handler(struct MPT2SAS_ADAPTER *ioc, int reset_phase)
}
break;
case MPT2_IOC_DONE_RESET:
- dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: "
+ dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: "
"MPT2_IOC_DONE_RESET\n", ioc->name, __func__));
for (i = 0; i < MPI2_DIAG_BUF_TYPE_COUNT; i++) {
@@ -531,7 +590,7 @@ _ctl_set_task_mid(struct MPT2SAS_ADAPTER *ioc, struct mpt2_ioctl_command *karg,
spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
if (!found) {
- dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: "
+ dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: "
"handle(0x%04x), lun(%d), no active mid!!\n", ioc->name,
desc, le16_to_cpu(tm_request->DevHandle), lun));
tm_reply = ioc->ctl_cmds.reply;
@@ -549,7 +608,7 @@ _ctl_set_task_mid(struct MPT2SAS_ADAPTER *ioc, struct mpt2_ioctl_command *karg,
return 1;
}
- dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: "
+ dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: "
"handle(0x%04x), lun(%d), task_mid(%d)\n", ioc->name,
desc, le16_to_cpu(tm_request->DevHandle), lun,
le16_to_cpu(tm_request->TaskMID)));
@@ -567,7 +626,7 @@ static long
_ctl_do_mpt_command(struct MPT2SAS_ADAPTER *ioc,
struct mpt2_ioctl_command karg, void __user *mf, enum block_state state)
{
- MPI2RequestHeader_t *mpi_request;
+ MPI2RequestHeader_t *mpi_request = NULL, *request;
MPI2DefaultReply_t *mpi_reply;
u32 ioc_state;
u16 ioc_status;
@@ -576,7 +635,6 @@ _ctl_do_mpt_command(struct MPT2SAS_ADAPTER *ioc,
u8 issue_reset;
u32 sz;
void *psge;
- void *priv_sense = NULL;
void *data_out = NULL;
dma_addr_t data_out_dma;
size_t data_out_sz = 0;
@@ -621,31 +679,50 @@ _ctl_do_mpt_command(struct MPT2SAS_ADAPTER *ioc,
printk(MPT2SAS_INFO_FMT "%s: ioc is operational\n",
ioc->name, __func__);
- smid = mpt2sas_base_get_smid_scsiio(ioc, ioc->ctl_cb_idx, NULL);
- if (!smid) {
- printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n",
- ioc->name, __func__);
- ret = -EAGAIN;
+ mpi_request = kzalloc(ioc->request_sz, GFP_KERNEL);
+ if (!mpi_request) {
+ printk(MPT2SAS_ERR_FMT "%s: failed obtaining a memory for "
+ "mpi_request\n", ioc->name, __func__);
+ ret = -ENOMEM;
goto out;
}
- ret = 0;
- ioc->ctl_cmds.status = MPT2_CMD_PENDING;
- memset(ioc->ctl_cmds.reply, 0, ioc->reply_sz);
- mpi_request = mpt2sas_base_get_msg_frame(ioc, smid);
- ioc->ctl_cmds.smid = smid;
- data_out_sz = karg.data_out_size;
- data_in_sz = karg.data_in_size;
-
/* copy in request message frame from user */
if (copy_from_user(mpi_request, mf, karg.data_sge_offset*4)) {
printk(KERN_ERR "failure at %s:%d/%s()!\n", __FILE__, __LINE__,
__func__);
ret = -EFAULT;
- mpt2sas_base_free_smid(ioc, smid);
goto out;
}
+ if (mpi_request->Function == MPI2_FUNCTION_SCSI_TASK_MGMT) {
+ smid = mpt2sas_base_get_smid_hpr(ioc, ioc->ctl_cb_idx);
+ if (!smid) {
+ printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n",
+ ioc->name, __func__);
+ ret = -EAGAIN;
+ goto out;
+ }
+ } else {
+
+ smid = mpt2sas_base_get_smid_scsiio(ioc, ioc->ctl_cb_idx, NULL);
+ if (!smid) {
+ printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n",
+ ioc->name, __func__);
+ ret = -EAGAIN;
+ goto out;
+ }
+ }
+
+ ret = 0;
+ ioc->ctl_cmds.status = MPT2_CMD_PENDING;
+ memset(ioc->ctl_cmds.reply, 0, ioc->reply_sz);
+ request = mpt2sas_base_get_msg_frame(ioc, smid);
+ memcpy(request, mpi_request, karg.data_sge_offset*4);
+ ioc->ctl_cmds.smid = smid;
+ data_out_sz = karg.data_out_size;
+ data_in_sz = karg.data_in_size;
+
if (mpi_request->Function == MPI2_FUNCTION_SCSI_IO_REQUEST ||
mpi_request->Function == MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH) {
if (!le16_to_cpu(mpi_request->FunctionDependent1) ||
@@ -691,7 +768,7 @@ _ctl_do_mpt_command(struct MPT2SAS_ADAPTER *ioc,
}
/* add scatter gather elements */
- psge = (void *)mpi_request + (karg.data_sge_offset*4);
+ psge = (void *)request + (karg.data_sge_offset*4);
if (!data_out_sz && !data_in_sz) {
mpt2sas_base_build_zero_len_sge(ioc, psge);
@@ -739,11 +816,11 @@ _ctl_do_mpt_command(struct MPT2SAS_ADAPTER *ioc,
case MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH:
{
Mpi2SCSIIORequest_t *scsiio_request =
- (Mpi2SCSIIORequest_t *)mpi_request;
+ (Mpi2SCSIIORequest_t *)request;
+ scsiio_request->SenseBufferLength = SCSI_SENSE_BUFFERSIZE;
scsiio_request->SenseBufferLowAddress =
mpt2sas_base_get_sense_buffer_dma(ioc, smid);
- priv_sense = mpt2sas_base_get_sense_buffer(ioc, smid);
- memset(priv_sense, 0, SCSI_SENSE_BUFFERSIZE);
+ memset(ioc->ctl_cmds.sense, 0, SCSI_SENSE_BUFFERSIZE);
if (mpi_request->Function == MPI2_FUNCTION_SCSI_IO_REQUEST)
mpt2sas_base_put_smid_scsi_io(ioc, smid,
le16_to_cpu(mpi_request->FunctionDependent1));
@@ -754,9 +831,9 @@ _ctl_do_mpt_command(struct MPT2SAS_ADAPTER *ioc,
case MPI2_FUNCTION_SCSI_TASK_MGMT:
{
Mpi2SCSITaskManagementRequest_t *tm_request =
- (Mpi2SCSITaskManagementRequest_t *)mpi_request;
+ (Mpi2SCSITaskManagementRequest_t *)request;
- dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "TASK_MGMT: "
+ dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "TASK_MGMT: "
"handle(0x%04x), task_type(0x%02x)\n", ioc->name,
le16_to_cpu(tm_request->DevHandle), tm_request->TaskType));
@@ -851,7 +928,7 @@ _ctl_do_mpt_command(struct MPT2SAS_ADAPTER *ioc,
Mpi2SCSITaskManagementReply_t *tm_reply =
(Mpi2SCSITaskManagementReply_t *)mpi_reply;
- printk(MPT2SAS_DEBUG_FMT "TASK_MGMT: "
+ printk(MPT2SAS_INFO_FMT "TASK_MGMT: "
"IOCStatus(0x%04x), IOCLogInfo(0x%08x), "
"TerminationCount(0x%08x)\n", ioc->name,
le16_to_cpu(tm_reply->IOCStatus),
@@ -887,7 +964,8 @@ _ctl_do_mpt_command(struct MPT2SAS_ADAPTER *ioc,
MPI2_FUNCTION_SCSI_IO_REQUEST || mpi_request->Function ==
MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH)) {
sz = min_t(u32, karg.max_sense_bytes, SCSI_SENSE_BUFFERSIZE);
- if (copy_to_user(karg.sense_data_ptr, priv_sense, sz)) {
+ if (copy_to_user(karg.sense_data_ptr,
+ ioc->ctl_cmds.sense, sz)) {
printk(KERN_ERR "failure at %s:%d/%s()!\n", __FILE__,
__LINE__, __func__);
ret = -ENODATA;
@@ -926,6 +1004,7 @@ _ctl_do_mpt_command(struct MPT2SAS_ADAPTER *ioc,
pci_free_consistent(ioc->pdev, data_out_sz, data_out,
data_out_dma);
+ kfree(mpi_request);
ioc->ctl_cmds.status = MPT2_CMD_NOT_USED;
mutex_unlock(&ioc->ctl_cmds.mutex);
return ret;
@@ -950,7 +1029,7 @@ _ctl_getiocinfo(void __user *arg)
if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || !ioc)
return -ENODEV;
- dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: enter\n", ioc->name,
+ dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: enter\n", ioc->name,
__func__));
memset(&karg, 0 , sizeof(karg));
@@ -998,7 +1077,7 @@ _ctl_eventquery(void __user *arg)
if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || !ioc)
return -ENODEV;
- dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: enter\n", ioc->name,
+ dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: enter\n", ioc->name,
__func__));
karg.event_entries = MPT2SAS_CTL_EVENT_LOG_SIZE;
@@ -1031,7 +1110,7 @@ _ctl_eventenable(void __user *arg)
if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || !ioc)
return -ENODEV;
- dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: enter\n", ioc->name,
+ dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: enter\n", ioc->name,
__func__));
if (ioc->event_log)
@@ -1073,7 +1152,7 @@ _ctl_eventreport(void __user *arg)
if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || !ioc)
return -ENODEV;
- dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: enter\n", ioc->name,
+ dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: enter\n", ioc->name,
__func__));
number_bytes = karg.hdr.max_data_size -
@@ -1118,7 +1197,7 @@ _ctl_do_reset(void __user *arg)
if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || !ioc)
return -ENODEV;
- dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: enter\n", ioc->name,
+ dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: enter\n", ioc->name,
__func__));
retval = mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP,
@@ -1219,7 +1298,7 @@ _ctl_btdh_mapping(void __user *arg)
if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || !ioc)
return -ENODEV;
- dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name,
+ dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
__func__));
rc = _ctl_btdh_search_sas_device(ioc, &karg);
@@ -1288,7 +1367,7 @@ _ctl_diag_register_2(struct MPT2SAS_ADAPTER *ioc,
u16 ioc_status;
u8 issue_reset = 0;
- dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name,
+ dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
__func__));
if (ioc->ctl_cmds.status != MPT2_CMD_NOT_USED) {
@@ -1376,7 +1455,7 @@ _ctl_diag_register_2(struct MPT2SAS_ADAPTER *ioc,
mpi_request->VF_ID = 0; /* TODO */
mpi_request->VP_ID = 0;
- dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: diag_buffer(0x%p), "
+ dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: diag_buffer(0x%p), "
"dma(0x%llx), sz(%d)\n", ioc->name, __func__, request_data,
(unsigned long long)request_data_dma,
le32_to_cpu(mpi_request->BufferLength)));
@@ -1414,10 +1493,10 @@ _ctl_diag_register_2(struct MPT2SAS_ADAPTER *ioc,
if (ioc_status == MPI2_IOCSTATUS_SUCCESS) {
ioc->diag_buffer_status[buffer_type] |=
MPT2_DIAG_BUFFER_IS_REGISTERED;
- dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: success\n",
+ dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: success\n",
ioc->name, __func__));
} else {
- printk(MPT2SAS_DEBUG_FMT "%s: ioc_status(0x%04x) "
+ printk(MPT2SAS_INFO_FMT "%s: ioc_status(0x%04x) "
"log_info(0x%08x)\n", ioc->name, __func__,
ioc_status, le32_to_cpu(mpi_reply->IOCLogInfo));
rc = -EFAULT;
@@ -1541,7 +1620,7 @@ _ctl_diag_unregister(void __user *arg)
if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || !ioc)
return -ENODEV;
- dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name,
+ dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
__func__));
buffer_type = karg.unique_id & 0x000000ff;
@@ -1611,7 +1690,7 @@ _ctl_diag_query(void __user *arg)
if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || !ioc)
return -ENODEV;
- dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name,
+ dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
__func__));
karg.application_flags = 0;
@@ -1689,7 +1768,7 @@ _ctl_send_release(struct MPT2SAS_ADAPTER *ioc, u8 buffer_type, u8 *issue_reset)
int rc;
unsigned long timeleft;
- dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name,
+ dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
__func__));
rc = 0;
@@ -1697,7 +1776,7 @@ _ctl_send_release(struct MPT2SAS_ADAPTER *ioc, u8 buffer_type, u8 *issue_reset)
ioc_state = mpt2sas_base_get_iocstate(ioc, 1);
if (ioc_state != MPI2_IOC_STATE_OPERATIONAL) {
- dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: "
+ dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: "
"skipping due to FAULT state\n", ioc->name,
__func__));
rc = -EAGAIN;
@@ -1759,10 +1838,10 @@ _ctl_send_release(struct MPT2SAS_ADAPTER *ioc, u8 buffer_type, u8 *issue_reset)
if (ioc_status == MPI2_IOCSTATUS_SUCCESS) {
ioc->diag_buffer_status[buffer_type] |=
MPT2_DIAG_BUFFER_IS_RELEASED;
- dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: success\n",
+ dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: success\n",
ioc->name, __func__));
} else {
- printk(MPT2SAS_DEBUG_FMT "%s: ioc_status(0x%04x) "
+ printk(MPT2SAS_INFO_FMT "%s: ioc_status(0x%04x) "
"log_info(0x%08x)\n", ioc->name, __func__,
ioc_status, le32_to_cpu(mpi_reply->IOCLogInfo));
rc = -EFAULT;
@@ -1800,7 +1879,7 @@ _ctl_diag_release(void __user *arg, enum block_state state)
if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || !ioc)
return -ENODEV;
- dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name,
+ dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
__func__));
buffer_type = karg.unique_id & 0x000000ff;
@@ -1896,7 +1975,7 @@ _ctl_diag_read_buffer(void __user *arg, enum block_state state)
if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || !ioc)
return -ENODEV;
- dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name,
+ dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
__func__));
buffer_type = karg.unique_id & 0x000000ff;
@@ -1927,7 +2006,7 @@ _ctl_diag_read_buffer(void __user *arg, enum block_state state)
}
diag_data = (void *)(request_data + karg.starting_offset);
- dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: diag_buffer(%p), "
+ dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: diag_buffer(%p), "
"offset(%d), sz(%d)\n", ioc->name, __func__,
diag_data, karg.starting_offset, karg.bytes_to_read));
@@ -1942,11 +2021,11 @@ _ctl_diag_read_buffer(void __user *arg, enum block_state state)
if ((karg.flags & MPT2_FLAGS_REREGISTER) == 0)
return 0;
- dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: Reregister "
+ dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: Reregister "
"buffer_type(0x%02x)\n", ioc->name, __func__, buffer_type));
if ((ioc->diag_buffer_status[buffer_type] &
MPT2_DIAG_BUFFER_IS_RELEASED) == 0) {
- dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: "
+ dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: "
"buffer_type(0x%02x) is still registered\n", ioc->name,
__func__, buffer_type));
return 0;
@@ -2020,10 +2099,10 @@ _ctl_diag_read_buffer(void __user *arg, enum block_state state)
if (ioc_status == MPI2_IOCSTATUS_SUCCESS) {
ioc->diag_buffer_status[buffer_type] |=
MPT2_DIAG_BUFFER_IS_REGISTERED;
- dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: success\n",
+ dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: success\n",
ioc->name, __func__));
} else {
- printk(MPT2SAS_DEBUG_FMT "%s: ioc_status(0x%04x) "
+ printk(MPT2SAS_INFO_FMT "%s: ioc_status(0x%04x) "
"log_info(0x%08x)\n", ioc->name, __func__,
ioc_status, le32_to_cpu(mpi_reply->IOCLogInfo));
rc = -EFAULT;
@@ -2077,7 +2156,7 @@ _ctl_ioctl_main(struct file *file, unsigned int cmd, void __user *arg)
!ioc)
return -ENODEV;
- if (ioc->shost_recovery)
+ if (ioc->shost_recovery || ioc->pci_error_recovery)
return -EAGAIN;
if (_IOC_SIZE(cmd) == sizeof(struct mpt2_ioctl_command)) {
@@ -2140,7 +2219,7 @@ _ctl_ioctl_main(struct file *file, unsigned int cmd, void __user *arg)
!ioc)
return -ENODEV;
- dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT
+ dctlprintk(ioc, printk(MPT2SAS_INFO_FMT
"unsupported ioctl opcode(0x%08x)\n", ioc->name, cmd));
break;
}
@@ -2196,7 +2275,7 @@ _ctl_compat_mpt_command(struct file *file, unsigned cmd, unsigned long arg)
if (_ctl_verify_adapter(karg32.hdr.ioc_number, &ioc) == -1 || !ioc)
return -ENODEV;
- if (ioc->shost_recovery)
+ if (ioc->shost_recovery || ioc->pci_error_recovery)
return -EAGAIN;
memset(&karg, 0, sizeof(struct mpt2_ioctl_command));
@@ -2581,6 +2660,218 @@ _ctl_fwfault_debug_store(struct device *cdev,
static DEVICE_ATTR(fwfault_debug, S_IRUGO | S_IWUSR,
_ctl_fwfault_debug_show, _ctl_fwfault_debug_store);
+
+/**
+ * _ctl_ioc_reset_count_show - ioc reset count
+ * @cdev - pointer to embedded class device
+ * @buf - the buffer returned
+ *
+ * This is firmware queue depth limit
+ *
+ * A sysfs 'read-only' shost attribute.
+ */
+static ssize_t
+_ctl_ioc_reset_count_show(struct device *cdev, struct device_attribute *attr,
+ char *buf)
+{
+ struct Scsi_Host *shost = class_to_shost(cdev);
+ struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
+
+ return snprintf(buf, PAGE_SIZE, "%08d\n", ioc->ioc_reset_count);
+}
+static DEVICE_ATTR(ioc_reset_count, S_IRUGO,
+ _ctl_ioc_reset_count_show, NULL);
+
+struct DIAG_BUFFER_START {
+ u32 Size;
+ u32 DiagVersion;
+ u8 BufferType;
+ u8 Reserved[3];
+ u32 Reserved1;
+ u32 Reserved2;
+ u32 Reserved3;
+};
+/**
+ * _ctl_host_trace_buffer_size_show - host buffer size (trace only)
+ * @cdev - pointer to embedded class device
+ * @buf - the buffer returned
+ *
+ * A sysfs 'read-only' shost attribute.
+ */
+static ssize_t
+_ctl_host_trace_buffer_size_show(struct device *cdev,
+ struct device_attribute *attr, char *buf)
+{
+ struct Scsi_Host *shost = class_to_shost(cdev);
+ struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
+ u32 size = 0;
+ struct DIAG_BUFFER_START *request_data;
+
+ if (!ioc->diag_buffer[MPI2_DIAG_BUF_TYPE_TRACE]) {
+ printk(MPT2SAS_ERR_FMT "%s: host_trace_buffer is not "
+ "registered\n", ioc->name, __func__);
+ return 0;
+ }
+
+ if ((ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] &
+ MPT2_DIAG_BUFFER_IS_REGISTERED) == 0) {
+ printk(MPT2SAS_ERR_FMT "%s: host_trace_buffer is not "
+ "registered\n", ioc->name, __func__);
+ return 0;
+ }
+
+ request_data = (struct DIAG_BUFFER_START *)
+ ioc->diag_buffer[MPI2_DIAG_BUF_TYPE_TRACE];
+ if ((le32_to_cpu(request_data->DiagVersion) == 0x00000000 ||
+ le32_to_cpu(request_data->DiagVersion) == 0x01000000) &&
+ le32_to_cpu(request_data->Reserved3) == 0x4742444c)
+ size = le32_to_cpu(request_data->Size);
+
+ ioc->ring_buffer_sz = size;
+ return snprintf(buf, PAGE_SIZE, "%d\n", size);
+}
+static DEVICE_ATTR(host_trace_buffer_size, S_IRUGO,
+ _ctl_host_trace_buffer_size_show, NULL);
+
+/**
+ * _ctl_host_trace_buffer_show - firmware ring buffer (trace only)
+ * @cdev - pointer to embedded class device
+ * @buf - the buffer returned
+ *
+ * A sysfs 'read/write' shost attribute.
+ *
+ * You will only be able to read 4k bytes of ring buffer at a time.
+ * In order to read beyond 4k bytes, you will have to write out the
+ * offset to the same attribute, it will move the pointer.
+ */
+static ssize_t
+_ctl_host_trace_buffer_show(struct device *cdev, struct device_attribute *attr,
+ char *buf)
+{
+ struct Scsi_Host *shost = class_to_shost(cdev);
+ struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
+ void *request_data;
+ u32 size;
+
+ if (!ioc->diag_buffer[MPI2_DIAG_BUF_TYPE_TRACE]) {
+ printk(MPT2SAS_ERR_FMT "%s: host_trace_buffer is not "
+ "registered\n", ioc->name, __func__);
+ return 0;
+ }
+
+ if ((ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] &
+ MPT2_DIAG_BUFFER_IS_REGISTERED) == 0) {
+ printk(MPT2SAS_ERR_FMT "%s: host_trace_buffer is not "
+ "registered\n", ioc->name, __func__);
+ return 0;
+ }
+
+ if (ioc->ring_buffer_offset > ioc->ring_buffer_sz)
+ return 0;
+
+ size = ioc->ring_buffer_sz - ioc->ring_buffer_offset;
+ size = (size > PAGE_SIZE) ? PAGE_SIZE : size;
+ request_data = ioc->diag_buffer[0] + ioc->ring_buffer_offset;
+ memcpy(buf, request_data, size);
+ return size;
+}
+
+static ssize_t
+_ctl_host_trace_buffer_store(struct device *cdev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct Scsi_Host *shost = class_to_shost(cdev);
+ struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
+ int val = 0;
+
+ if (sscanf(buf, "%d", &val) != 1)
+ return -EINVAL;
+
+ ioc->ring_buffer_offset = val;
+ return strlen(buf);
+}
+static DEVICE_ATTR(host_trace_buffer, S_IRUGO | S_IWUSR,
+ _ctl_host_trace_buffer_show, _ctl_host_trace_buffer_store);
+
+/*****************************************/
+
+/**
+ * _ctl_host_trace_buffer_enable_show - firmware ring buffer (trace only)
+ * @cdev - pointer to embedded class device
+ * @buf - the buffer returned
+ *
+ * A sysfs 'read/write' shost attribute.
+ *
+ * This is a mechnism to post/release host_trace_buffers
+ */
+static ssize_t
+_ctl_host_trace_buffer_enable_show(struct device *cdev,
+ struct device_attribute *attr, char *buf)
+{
+ struct Scsi_Host *shost = class_to_shost(cdev);
+ struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
+
+ if ((!ioc->diag_buffer[MPI2_DIAG_BUF_TYPE_TRACE]) ||
+ ((ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] &
+ MPT2_DIAG_BUFFER_IS_REGISTERED) == 0))
+ return snprintf(buf, PAGE_SIZE, "off\n");
+ else if ((ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] &
+ MPT2_DIAG_BUFFER_IS_RELEASED))
+ return snprintf(buf, PAGE_SIZE, "release\n");
+ else
+ return snprintf(buf, PAGE_SIZE, "post\n");
+}
+
+static ssize_t
+_ctl_host_trace_buffer_enable_store(struct device *cdev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct Scsi_Host *shost = class_to_shost(cdev);
+ struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
+ char str[10] = "";
+ struct mpt2_diag_register diag_register;
+ u8 issue_reset = 0;
+
+ if (sscanf(buf, "%s", str) != 1)
+ return -EINVAL;
+
+ if (!strcmp(str, "post")) {
+ /* exit out if host buffers are already posted */
+ if ((ioc->diag_buffer[MPI2_DIAG_BUF_TYPE_TRACE]) &&
+ (ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] &
+ MPT2_DIAG_BUFFER_IS_REGISTERED) &&
+ ((ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] &
+ MPT2_DIAG_BUFFER_IS_RELEASED) == 0))
+ goto out;
+ memset(&diag_register, 0, sizeof(struct mpt2_diag_register));
+ printk(MPT2SAS_INFO_FMT "posting host trace buffers\n",
+ ioc->name);
+ diag_register.buffer_type = MPI2_DIAG_BUF_TYPE_TRACE;
+ diag_register.requested_buffer_size = (1024 * 1024);
+ diag_register.unique_id = 0x7075900;
+ ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] = 0;
+ _ctl_diag_register_2(ioc, &diag_register);
+ } else if (!strcmp(str, "release")) {
+ /* exit out if host buffers are already released */
+ if (!ioc->diag_buffer[MPI2_DIAG_BUF_TYPE_TRACE])
+ goto out;
+ if ((ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] &
+ MPT2_DIAG_BUFFER_IS_REGISTERED) == 0)
+ goto out;
+ if ((ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] &
+ MPT2_DIAG_BUFFER_IS_RELEASED))
+ goto out;
+ printk(MPT2SAS_INFO_FMT "releasing host trace buffer\n",
+ ioc->name);
+ _ctl_send_release(ioc, MPI2_DIAG_BUF_TYPE_TRACE, &issue_reset);
+ }
+
+ out:
+ return strlen(buf);
+}
+static DEVICE_ATTR(host_trace_buffer_enable, S_IRUGO | S_IWUSR,
+ _ctl_host_trace_buffer_enable_show, _ctl_host_trace_buffer_enable_store);
+
struct device_attribute *mpt2sas_host_attrs[] = {
&dev_attr_version_fw,
&dev_attr_version_bios,
@@ -2597,6 +2888,10 @@ struct device_attribute *mpt2sas_host_attrs[] = {
&dev_attr_fwfault_debug,
&dev_attr_fw_queue_depth,
&dev_attr_host_sas_address,
+ &dev_attr_ioc_reset_count,
+ &dev_attr_host_trace_buffer_size,
+ &dev_attr_host_trace_buffer,
+ &dev_attr_host_trace_buffer_enable,
NULL,
};
diff --git a/drivers/scsi/mpt2sas/mpt2sas_scsih.c b/drivers/scsi/mpt2sas/mpt2sas_scsih.c
index c5ff26a2a51..16e99b68635 100644
--- a/drivers/scsi/mpt2sas/mpt2sas_scsih.c
+++ b/drivers/scsi/mpt2sas/mpt2sas_scsih.c
@@ -70,6 +70,8 @@ static void _scsih_expander_node_remove(struct MPT2SAS_ADAPTER *ioc,
struct _sas_node *sas_expander);
static void _firmware_event_work(struct work_struct *work);
+static u8 _scsih_check_for_pending_tm(struct MPT2SAS_ADAPTER *ioc, u16 smid);
+
/* global parameters */
LIST_HEAD(mpt2sas_ioc_list);
@@ -84,6 +86,7 @@ static u8 config_cb_idx = -1;
static int mpt_ids;
static u8 tm_tr_cb_idx = -1 ;
+static u8 tm_tr_volume_cb_idx = -1 ;
static u8 tm_sas_control_cb_idx = -1;
/* command line options */
@@ -223,9 +226,12 @@ static struct pci_device_id scsih_pci_table[] = {
PCI_ANY_ID, PCI_ANY_ID },
{ MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_6,
PCI_ANY_ID, PCI_ANY_ID },
- { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_7,
+ /* Mustang ~ 2308 */
+ { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2308_1,
+ PCI_ANY_ID, PCI_ANY_ID },
+ { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2308_2,
PCI_ANY_ID, PCI_ANY_ID },
- { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_8,
+ { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2308_3,
PCI_ANY_ID, PCI_ANY_ID },
{0} /* Terminating entry */
};
@@ -432,7 +438,7 @@ _scsih_determine_boot_device(struct MPT2SAS_ADAPTER *ioc,
(ioc->bios_pg2.ReqBootDeviceForm &
MPI2_BIOSPAGE2_FORM_MASK),
&ioc->bios_pg2.RequestedBootDevice)) {
- dinitprintk(ioc, printk(MPT2SAS_DEBUG_FMT
+ dinitprintk(ioc, printk(MPT2SAS_INFO_FMT
"%s: req_boot_device(0x%016llx)\n",
ioc->name, __func__,
(unsigned long long)sas_address));
@@ -447,7 +453,7 @@ _scsih_determine_boot_device(struct MPT2SAS_ADAPTER *ioc,
(ioc->bios_pg2.ReqAltBootDeviceForm &
MPI2_BIOSPAGE2_FORM_MASK),
&ioc->bios_pg2.RequestedAltBootDevice)) {
- dinitprintk(ioc, printk(MPT2SAS_DEBUG_FMT
+ dinitprintk(ioc, printk(MPT2SAS_INFO_FMT
"%s: req_alt_boot_device(0x%016llx)\n",
ioc->name, __func__,
(unsigned long long)sas_address));
@@ -462,7 +468,7 @@ _scsih_determine_boot_device(struct MPT2SAS_ADAPTER *ioc,
(ioc->bios_pg2.CurrentBootDeviceForm &
MPI2_BIOSPAGE2_FORM_MASK),
&ioc->bios_pg2.CurrentBootDevice)) {
- dinitprintk(ioc, printk(MPT2SAS_DEBUG_FMT
+ dinitprintk(ioc, printk(MPT2SAS_INFO_FMT
"%s: current_boot_device(0x%016llx)\n",
ioc->name, __func__,
(unsigned long long)sas_address));
@@ -563,7 +569,7 @@ _scsih_sas_device_add(struct MPT2SAS_ADAPTER *ioc,
{
unsigned long flags;
- dewtprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: handle"
+ dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: handle"
"(0x%04x), sas_addr(0x%016llx)\n", ioc->name, __func__,
sas_device->handle, (unsigned long long)sas_device->sas_address));
@@ -590,7 +596,7 @@ _scsih_sas_device_init_add(struct MPT2SAS_ADAPTER *ioc,
{
unsigned long flags;
- dewtprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: handle"
+ dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: handle"
"(0x%04x), sas_addr(0x%016llx)\n", ioc->name, __func__,
sas_device->handle, (unsigned long long)sas_device->sas_address));
@@ -692,7 +698,7 @@ _scsih_raid_device_add(struct MPT2SAS_ADAPTER *ioc,
{
unsigned long flags;
- dewtprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: handle"
+ dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: handle"
"(0x%04x), wwid(0x%016llx)\n", ioc->name, __func__,
raid_device->handle, (unsigned long long)raid_device->wwid));
@@ -1223,7 +1229,7 @@ _scsih_target_alloc(struct scsi_target *starget)
sas_device->starget = starget;
sas_device->id = starget->id;
sas_device->channel = starget->channel;
- if (sas_device->hidden_raid_component)
+ if (test_bit(sas_device->handle, ioc->pd_handles))
sas_target_priv_data->flags |=
MPT_TARGET_FLAGS_RAID_COMPONENT;
}
@@ -1746,9 +1752,10 @@ _scsih_slave_configure(struct scsi_device *sdev)
}
sdev_printk(KERN_INFO, sdev, "%s: handle(0x%04x), "
- "sas_addr(0x%016llx), device_name(0x%016llx)\n",
+ "sas_addr(0x%016llx), phy(%d), device_name(0x%016llx)\n",
ds, sas_device->handle,
(unsigned long long)sas_device->sas_address,
+ sas_device->phy,
(unsigned long long)sas_device->device_name);
sdev_printk(KERN_INFO, sdev, "%s: "
"enclosure_logical_id(0x%016llx), slot(%d)\n", ds,
@@ -1990,7 +1997,8 @@ mpt2sas_scsih_issue_tm(struct MPT2SAS_ADAPTER *ioc, u16 handle, uint channel,
goto err_out;
}
- if (ioc->shost_recovery || ioc->remove_host) {
+ if (ioc->shost_recovery || ioc->remove_host ||
+ ioc->pci_error_recovery) {
printk(MPT2SAS_INFO_FMT "%s: host reset in progress!\n",
__func__, ioc->name);
rc = FAILED;
@@ -1999,7 +2007,7 @@ mpt2sas_scsih_issue_tm(struct MPT2SAS_ADAPTER *ioc, u16 handle, uint channel,
ioc_state = mpt2sas_base_get_iocstate(ioc, 0);
if (ioc_state & MPI2_DOORBELL_USED) {
- dhsprintk(ioc, printk(MPT2SAS_DEBUG_FMT "unexpected doorbell "
+ dhsprintk(ioc, printk(MPT2SAS_INFO_FMT "unexpected doorbell "
"active!\n", ioc->name));
mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP,
FORCE_BIG_HAMMER);
@@ -2116,8 +2124,59 @@ mpt2sas_scsih_issue_tm(struct MPT2SAS_ADAPTER *ioc, u16 handle, uint channel,
}
/**
+ * _scsih_tm_display_info - displays info about the device
+ * @ioc: per adapter struct
+ * @scmd: pointer to scsi command object
+ *
+ * Called by task management callback handlers.
+ */
+static void
+_scsih_tm_display_info(struct MPT2SAS_ADAPTER *ioc, struct scsi_cmnd *scmd)
+{
+ struct scsi_target *starget = scmd->device->sdev_target;
+ struct MPT2SAS_TARGET *priv_target = starget->hostdata;
+ struct _sas_device *sas_device = NULL;
+ unsigned long flags;
+
+ if (!priv_target)
+ return;
+
+ scsi_print_command(scmd);
+ if (priv_target->flags & MPT_TARGET_FLAGS_VOLUME) {
+ starget_printk(KERN_INFO, starget, "volume handle(0x%04x), "
+ "volume wwid(0x%016llx)\n",
+ priv_target->handle,
+ (unsigned long long)priv_target->sas_address);
+ } else {
+ spin_lock_irqsave(&ioc->sas_device_lock, flags);
+ sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
+ priv_target->sas_address);
+ if (sas_device) {
+ if (priv_target->flags &
+ MPT_TARGET_FLAGS_RAID_COMPONENT) {
+ starget_printk(KERN_INFO, starget,
+ "volume handle(0x%04x), "
+ "volume wwid(0x%016llx)\n",
+ sas_device->volume_handle,
+ (unsigned long long)sas_device->volume_wwid);
+ }
+ starget_printk(KERN_INFO, starget,
+ "handle(0x%04x), sas_address(0x%016llx), phy(%d)\n",
+ sas_device->handle,
+ (unsigned long long)sas_device->sas_address,
+ sas_device->phy);
+ starget_printk(KERN_INFO, starget,
+ "enclosure_logical_id(0x%016llx), slot(%d)\n",
+ (unsigned long long)sas_device->enclosure_logical_id,
+ sas_device->slot);
+ }
+ spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
+ }
+}
+
+/**
* _scsih_abort - eh threads main abort routine
- * @sdev: scsi device struct
+ * @scmd: pointer to scsi command object
*
* Returns SUCCESS if command aborted else FAILED
*/
@@ -2130,14 +2189,14 @@ _scsih_abort(struct scsi_cmnd *scmd)
u16 handle;
int r;
- printk(MPT2SAS_INFO_FMT "attempting task abort! scmd(%p)\n",
- ioc->name, scmd);
- scsi_print_command(scmd);
+ sdev_printk(KERN_INFO, scmd->device, "attempting task abort! "
+ "scmd(%p)\n", scmd);
+ _scsih_tm_display_info(ioc, scmd);
sas_device_priv_data = scmd->device->hostdata;
if (!sas_device_priv_data || !sas_device_priv_data->sas_target) {
- printk(MPT2SAS_INFO_FMT "device been deleted! scmd(%p)\n",
- ioc->name, scmd);
+ sdev_printk(KERN_INFO, scmd->device, "device been deleted! "
+ "scmd(%p)\n", scmd);
scmd->result = DID_NO_CONNECT << 16;
scmd->scsi_done(scmd);
r = SUCCESS;
@@ -2169,14 +2228,14 @@ _scsih_abort(struct scsi_cmnd *scmd)
MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK, smid, 30, scmd);
out:
- printk(MPT2SAS_INFO_FMT "task abort: %s scmd(%p)\n",
- ioc->name, ((r == SUCCESS) ? "SUCCESS" : "FAILED"), scmd);
+ sdev_printk(KERN_INFO, scmd->device, "task abort: %s scmd(%p)\n",
+ ((r == SUCCESS) ? "SUCCESS" : "FAILED"), scmd);
return r;
}
/**
* _scsih_dev_reset - eh threads main device reset routine
- * @sdev: scsi device struct
+ * @scmd: pointer to scsi command object
*
* Returns SUCCESS if command aborted else FAILED
*/
@@ -2190,14 +2249,16 @@ _scsih_dev_reset(struct scsi_cmnd *scmd)
u16 handle;
int r;
- printk(MPT2SAS_INFO_FMT "attempting device reset! scmd(%p)\n",
- ioc->name, scmd);
- scsi_print_command(scmd);
+ struct scsi_target *starget = scmd->device->sdev_target;
+
+ starget_printk(KERN_INFO, starget, "attempting target reset! "
+ "scmd(%p)\n", scmd);
+ _scsih_tm_display_info(ioc, scmd);
sas_device_priv_data = scmd->device->hostdata;
if (!sas_device_priv_data || !sas_device_priv_data->sas_target) {
- printk(MPT2SAS_INFO_FMT "device been deleted! scmd(%p)\n",
- ioc->name, scmd);
+ starget_printk(KERN_INFO, starget, "target been deleted! "
+ "scmd(%p)\n", scmd);
scmd->result = DID_NO_CONNECT << 16;
scmd->scsi_done(scmd);
r = SUCCESS;
@@ -2228,14 +2289,14 @@ _scsih_dev_reset(struct scsi_cmnd *scmd)
MPI2_SCSITASKMGMT_TASKTYPE_LOGICAL_UNIT_RESET, 0, 30, scmd);
out:
- printk(MPT2SAS_INFO_FMT "device reset: %s scmd(%p)\n",
- ioc->name, ((r == SUCCESS) ? "SUCCESS" : "FAILED"), scmd);
+ sdev_printk(KERN_INFO, scmd->device, "device reset: %s scmd(%p)\n",
+ ((r == SUCCESS) ? "SUCCESS" : "FAILED"), scmd);
return r;
}
/**
* _scsih_target_reset - eh threads main target reset routine
- * @sdev: scsi device struct
+ * @scmd: pointer to scsi command object
*
* Returns SUCCESS if command aborted else FAILED
*/
@@ -2248,15 +2309,16 @@ _scsih_target_reset(struct scsi_cmnd *scmd)
unsigned long flags;
u16 handle;
int r;
+ struct scsi_target *starget = scmd->device->sdev_target;
- printk(MPT2SAS_INFO_FMT "attempting target reset! scmd(%p)\n",
- ioc->name, scmd);
- scsi_print_command(scmd);
+ starget_printk(KERN_INFO, starget, "attempting target reset! "
+ "scmd(%p)\n", scmd);
+ _scsih_tm_display_info(ioc, scmd);
sas_device_priv_data = scmd->device->hostdata;
if (!sas_device_priv_data || !sas_device_priv_data->sas_target) {
- printk(MPT2SAS_INFO_FMT "target been deleted! scmd(%p)\n",
- ioc->name, scmd);
+ starget_printk(KERN_INFO, starget, "target been deleted! "
+ "scmd(%p)\n", scmd);
scmd->result = DID_NO_CONNECT << 16;
scmd->scsi_done(scmd);
r = SUCCESS;
@@ -2287,14 +2349,14 @@ _scsih_target_reset(struct scsi_cmnd *scmd)
30, scmd);
out:
- printk(MPT2SAS_INFO_FMT "target reset: %s scmd(%p)\n",
- ioc->name, ((r == SUCCESS) ? "SUCCESS" : "FAILED"), scmd);
+ starget_printk(KERN_INFO, starget, "target reset: %s scmd(%p)\n",
+ ((r == SUCCESS) ? "SUCCESS" : "FAILED"), scmd);
return r;
}
/**
* _scsih_host_reset - eh threads main host reset routine
- * @sdev: scsi device struct
+ * @scmd: pointer to scsi command object
*
* Returns SUCCESS if command aborted else FAILED
*/
@@ -2579,20 +2641,31 @@ _scsih_tm_tr_send(struct MPT2SAS_ADAPTER *ioc, u16 handle)
Mpi2SCSITaskManagementRequest_t *mpi_request;
u16 smid;
struct _sas_device *sas_device;
+ struct MPT2SAS_TARGET *sas_target_priv_data;
unsigned long flags;
struct _tr_list *delayed_tr;
- if (ioc->shost_recovery || ioc->remove_host) {
+ if (ioc->shost_recovery || ioc->remove_host ||
+ ioc->pci_error_recovery) {
dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: host reset in "
"progress!\n", __func__, ioc->name));
return;
}
+ /* if PD, then return */
+ if (test_bit(handle, ioc->pd_handles))
+ return;
+
spin_lock_irqsave(&ioc->sas_device_lock, flags);
sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
- if (sas_device && sas_device->hidden_raid_component) {
- spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
- return;
+ if (sas_device && sas_device->starget &&
+ sas_device->starget->hostdata) {
+ sas_target_priv_data = sas_device->starget->hostdata;
+ sas_target_priv_data->deleted = 1;
+ dewtprintk(ioc, printk(MPT2SAS_INFO_FMT
+ "setting delete flag: handle(0x%04x), "
+ "sas_addr(0x%016llx)\n", ioc->name, handle,
+ (unsigned long long) sas_device->sas_address));
}
spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
@@ -2655,6 +2728,101 @@ _scsih_sas_control_complete(struct MPT2SAS_ADAPTER *ioc, u16 smid,
}
/**
+ * _scsih_tm_tr_volume_send - send target reset request for volumes
+ * @ioc: per adapter object
+ * @handle: device handle
+ * Context: interrupt time.
+ *
+ * This is designed to send muliple task management request at the same
+ * time to the fifo. If the fifo is full, we will append the request,
+ * and process it in a future completion.
+ */
+static void
+_scsih_tm_tr_volume_send(struct MPT2SAS_ADAPTER *ioc, u16 handle)
+{
+ Mpi2SCSITaskManagementRequest_t *mpi_request;
+ u16 smid;
+ struct _tr_list *delayed_tr;
+
+ if (ioc->shost_recovery || ioc->remove_host ||
+ ioc->pci_error_recovery) {
+ dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: host reset in "
+ "progress!\n", __func__, ioc->name));
+ return;
+ }
+
+ smid = mpt2sas_base_get_smid_hpr(ioc, ioc->tm_tr_volume_cb_idx);
+ if (!smid) {
+ delayed_tr = kzalloc(sizeof(*delayed_tr), GFP_ATOMIC);
+ if (!delayed_tr)
+ return;
+ INIT_LIST_HEAD(&delayed_tr->list);
+ delayed_tr->handle = handle;
+ list_add_tail(&delayed_tr->list, &ioc->delayed_tr_volume_list);
+ dewtprintk(ioc, printk(MPT2SAS_INFO_FMT
+ "DELAYED:tr:handle(0x%04x), (open)\n",
+ ioc->name, handle));
+ return;
+ }
+
+ dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "tr_send:handle(0x%04x), "
+ "(open), smid(%d), cb(%d)\n", ioc->name, handle, smid,
+ ioc->tm_tr_volume_cb_idx));
+ mpi_request = mpt2sas_base_get_msg_frame(ioc, smid);
+ memset(mpi_request, 0, sizeof(Mpi2SCSITaskManagementRequest_t));
+ mpi_request->Function = MPI2_FUNCTION_SCSI_TASK_MGMT;
+ mpi_request->DevHandle = cpu_to_le16(handle);
+ mpi_request->TaskType = MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET;
+ mpt2sas_base_put_smid_hi_priority(ioc, smid);
+}
+
+/**
+ * _scsih_tm_volume_tr_complete - target reset completion
+ * @ioc: per adapter object
+ * @smid: system request message index
+ * @msix_index: MSIX table index supplied by the OS
+ * @reply: reply message frame(lower 32bit addr)
+ * Context: interrupt time.
+ *
+ * Return 1 meaning mf should be freed from _base_interrupt
+ * 0 means the mf is freed from this function.
+ */
+static u8
+_scsih_tm_volume_tr_complete(struct MPT2SAS_ADAPTER *ioc, u16 smid,
+ u8 msix_index, u32 reply)
+{
+ u16 handle;
+ Mpi2SCSITaskManagementRequest_t *mpi_request_tm;
+ Mpi2SCSITaskManagementReply_t *mpi_reply =
+ mpt2sas_base_get_reply_virt_addr(ioc, reply);
+
+ if (ioc->shost_recovery || ioc->remove_host ||
+ ioc->pci_error_recovery) {
+ dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: host reset in "
+ "progress!\n", __func__, ioc->name));
+ return 1;
+ }
+
+ mpi_request_tm = mpt2sas_base_get_msg_frame(ioc, smid);
+ handle = le16_to_cpu(mpi_request_tm->DevHandle);
+ if (handle != le16_to_cpu(mpi_reply->DevHandle)) {
+ dewtprintk(ioc, printk("spurious interrupt: "
+ "handle(0x%04x:0x%04x), smid(%d)!!!\n", handle,
+ le16_to_cpu(mpi_reply->DevHandle), smid));
+ return 0;
+ }
+
+ dewtprintk(ioc, printk(MPT2SAS_INFO_FMT
+ "tr_complete:handle(0x%04x), (open) smid(%d), ioc_status(0x%04x), "
+ "loginfo(0x%08x), completed(%d)\n", ioc->name,
+ handle, smid, le16_to_cpu(mpi_reply->IOCStatus),
+ le32_to_cpu(mpi_reply->IOCLogInfo),
+ le32_to_cpu(mpi_reply->TerminationCount)));
+
+ return _scsih_check_for_pending_tm(ioc, smid);
+}
+
+/**
* _scsih_tm_tr_complete -
* @ioc: per adapter object
* @smid: system request message index
@@ -2680,9 +2848,9 @@ _scsih_tm_tr_complete(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index,
mpt2sas_base_get_reply_virt_addr(ioc, reply);
Mpi2SasIoUnitControlRequest_t *mpi_request;
u16 smid_sas_ctrl;
- struct _tr_list *delayed_tr;
- if (ioc->shost_recovery || ioc->remove_host) {
+ if (ioc->shost_recovery || ioc->remove_host ||
+ ioc->pci_error_recovery) {
dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: host reset in "
"progress!\n", __func__, ioc->name));
return 1;
@@ -2721,6 +2889,35 @@ _scsih_tm_tr_complete(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index,
mpi_request->DevHandle = mpi_request_tm->DevHandle;
mpt2sas_base_put_smid_default(ioc, smid_sas_ctrl);
+ return _scsih_check_for_pending_tm(ioc, smid);
+}
+
+/**
+ * _scsih_check_for_pending_tm - check for pending task management
+ * @ioc: per adapter object
+ * @smid: system request message index
+ *
+ * This will check delayed target reset list, and feed the
+ * next reqeust.
+ *
+ * Return 1 meaning mf should be freed from _base_interrupt
+ * 0 means the mf is freed from this function.
+ */
+static u8
+_scsih_check_for_pending_tm(struct MPT2SAS_ADAPTER *ioc, u16 smid)
+{
+ struct _tr_list *delayed_tr;
+
+ if (!list_empty(&ioc->delayed_tr_volume_list)) {
+ delayed_tr = list_entry(ioc->delayed_tr_volume_list.next,
+ struct _tr_list, list);
+ mpt2sas_base_free_smid(ioc, smid);
+ _scsih_tm_tr_volume_send(ioc, delayed_tr->handle);
+ list_del(&delayed_tr->list);
+ kfree(delayed_tr);
+ return 0;
+ }
+
if (!list_empty(&ioc->delayed_tr_list)) {
delayed_tr = list_entry(ioc->delayed_tr_list.next,
struct _tr_list, list);
@@ -2728,8 +2925,9 @@ _scsih_tm_tr_complete(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index,
_scsih_tm_tr_send(ioc, delayed_tr->handle);
list_del(&delayed_tr->list);
kfree(delayed_tr);
- return 0; /* tells base_interrupt not to free mf */
+ return 0;
}
+
return 1;
}
@@ -2803,7 +3001,7 @@ _scsih_check_topo_delete_events(struct MPT2SAS_ADAPTER *ioc,
MPI2_EVENT_SAS_TOPO_ES_RESPONDING) {
if (le16_to_cpu(local_event_data->ExpanderDevHandle) ==
expander_handle) {
- dewtprintk(ioc, printk(MPT2SAS_DEBUG_FMT
+ dewtprintk(ioc, printk(MPT2SAS_INFO_FMT
"setting ignoring flag\n", ioc->name));
fw_event->ignore = 1;
}
@@ -2813,6 +3011,165 @@ _scsih_check_topo_delete_events(struct MPT2SAS_ADAPTER *ioc,
}
/**
+ * _scsih_set_volume_delete_flag - setting volume delete flag
+ * @ioc: per adapter object
+ * @handle: device handle
+ *
+ * This
+ * Return nothing.
+ */
+static void
+_scsih_set_volume_delete_flag(struct MPT2SAS_ADAPTER *ioc, u16 handle)
+{
+ struct _raid_device *raid_device;
+ struct MPT2SAS_TARGET *sas_target_priv_data;
+ unsigned long flags;
+
+ spin_lock_irqsave(&ioc->raid_device_lock, flags);
+ raid_device = _scsih_raid_device_find_by_handle(ioc, handle);
+ if (raid_device && raid_device->starget &&
+ raid_device->starget->hostdata) {
+ sas_target_priv_data =
+ raid_device->starget->hostdata;
+ sas_target_priv_data->deleted = 1;
+ dewtprintk(ioc, printk(MPT2SAS_INFO_FMT
+ "setting delete flag: handle(0x%04x), "
+ "wwid(0x%016llx)\n", ioc->name, handle,
+ (unsigned long long) raid_device->wwid));
+ }
+ spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
+}
+
+/**
+ * _scsih_set_volume_handle_for_tr - set handle for target reset to volume
+ * @handle: input handle
+ * @a: handle for volume a
+ * @b: handle for volume b
+ *
+ * IR firmware only supports two raid volumes. The purpose of this
+ * routine is to set the volume handle in either a or b. When the given
+ * input handle is non-zero, or when a and b have not been set before.
+ */
+static void
+_scsih_set_volume_handle_for_tr(u16 handle, u16 *a, u16 *b)
+{
+ if (!handle || handle == *a || handle == *b)
+ return;
+ if (!*a)
+ *a = handle;
+ else if (!*b)
+ *b = handle;
+}
+
+/**
+ * _scsih_check_ir_config_unhide_events - check for UNHIDE events
+ * @ioc: per adapter object
+ * @event_data: the event data payload
+ * Context: interrupt time.
+ *
+ * This routine will send target reset to volume, followed by target
+ * resets to the PDs. This is called when a PD has been removed, or
+ * volume has been deleted or removed. When the target reset is sent
+ * to volume, the PD target resets need to be queued to start upon
+ * completion of the volume target reset.
+ *
+ * Return nothing.
+ */
+static void
+_scsih_check_ir_config_unhide_events(struct MPT2SAS_ADAPTER *ioc,
+ Mpi2EventDataIrConfigChangeList_t *event_data)
+{
+ Mpi2EventIrConfigElement_t *element;
+ int i;
+ u16 handle, volume_handle, a, b;
+ struct _tr_list *delayed_tr;
+
+ a = 0;
+ b = 0;
+
+ /* Volume Resets for Deleted or Removed */
+ element = (Mpi2EventIrConfigElement_t *)&event_data->ConfigElement[0];
+ for (i = 0; i < event_data->NumElements; i++, element++) {
+ if (element->ReasonCode ==
+ MPI2_EVENT_IR_CHANGE_RC_VOLUME_DELETED ||
+ element->ReasonCode ==
+ MPI2_EVENT_IR_CHANGE_RC_REMOVED) {
+ volume_handle = le16_to_cpu(element->VolDevHandle);
+ _scsih_set_volume_delete_flag(ioc, volume_handle);
+ _scsih_set_volume_handle_for_tr(volume_handle, &a, &b);
+ }
+ }
+
+ /* Volume Resets for UNHIDE events */
+ element = (Mpi2EventIrConfigElement_t *)&event_data->ConfigElement[0];
+ for (i = 0; i < event_data->NumElements; i++, element++) {
+ if (le32_to_cpu(event_data->Flags) &
+ MPI2_EVENT_IR_CHANGE_FLAGS_FOREIGN_CONFIG)
+ continue;
+ if (element->ReasonCode == MPI2_EVENT_IR_CHANGE_RC_UNHIDE) {
+ volume_handle = le16_to_cpu(element->VolDevHandle);
+ _scsih_set_volume_handle_for_tr(volume_handle, &a, &b);
+ }
+ }
+
+ if (a)
+ _scsih_tm_tr_volume_send(ioc, a);
+ if (b)
+ _scsih_tm_tr_volume_send(ioc, b);
+
+ /* PD target resets */
+ element = (Mpi2EventIrConfigElement_t *)&event_data->ConfigElement[0];
+ for (i = 0; i < event_data->NumElements; i++, element++) {
+ if (element->ReasonCode != MPI2_EVENT_IR_CHANGE_RC_UNHIDE)
+ continue;
+ handle = le16_to_cpu(element->PhysDiskDevHandle);
+ volume_handle = le16_to_cpu(element->VolDevHandle);
+ clear_bit(handle, ioc->pd_handles);
+ if (!volume_handle)
+ _scsih_tm_tr_send(ioc, handle);
+ else if (volume_handle == a || volume_handle == b) {
+ delayed_tr = kzalloc(sizeof(*delayed_tr), GFP_ATOMIC);
+ BUG_ON(!delayed_tr);
+ INIT_LIST_HEAD(&delayed_tr->list);
+ delayed_tr->handle = handle;
+ list_add_tail(&delayed_tr->list, &ioc->delayed_tr_list);
+ dewtprintk(ioc, printk(MPT2SAS_INFO_FMT
+ "DELAYED:tr:handle(0x%04x), (open)\n", ioc->name,
+ handle));
+ } else
+ _scsih_tm_tr_send(ioc, handle);
+ }
+}
+
+
+/**
+ * _scsih_check_volume_delete_events - set delete flag for volumes
+ * @ioc: per adapter object
+ * @event_data: the event data payload
+ * Context: interrupt time.
+ *
+ * This will handle the case when the cable connected to entire volume is
+ * pulled. We will take care of setting the deleted flag so normal IO will
+ * not be sent.
+ *
+ * Return nothing.
+ */
+static void
+_scsih_check_volume_delete_events(struct MPT2SAS_ADAPTER *ioc,
+ Mpi2EventDataIrVolume_t *event_data)
+{
+ u32 state;
+
+ if (event_data->ReasonCode != MPI2_EVENT_IR_VOLUME_RC_STATE_CHANGED)
+ return;
+ state = le32_to_cpu(event_data->NewValue);
+ if (state == MPI2_RAID_VOL_STATE_MISSING || state ==
+ MPI2_RAID_VOL_STATE_FAILED)
+ _scsih_set_volume_delete_flag(ioc,
+ le16_to_cpu(event_data->VolDevHandle));
+}
+
+/**
* _scsih_flush_running_cmds - completing outstanding commands.
* @ioc: per adapter object
*
@@ -2835,7 +3192,10 @@ _scsih_flush_running_cmds(struct MPT2SAS_ADAPTER *ioc)
count++;
mpt2sas_base_free_smid(ioc, smid);
scsi_dma_unmap(scmd);
- scmd->result = DID_RESET << 16;
+ if (ioc->pci_error_recovery)
+ scmd->result = DID_NO_CONNECT << 16;
+ else
+ scmd->result = DID_RESET << 16;
scmd->scsi_done(scmd);
}
dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "completing %d cmds\n",
@@ -2858,9 +3218,7 @@ _scsih_setup_eedp(struct scsi_cmnd *scmd, Mpi2SCSIIORequest_t *mpi_request)
unsigned char prot_op = scsi_get_prot_op(scmd);
unsigned char prot_type = scsi_get_prot_type(scmd);
- if (prot_type == SCSI_PROT_DIF_TYPE0 ||
- prot_type == SCSI_PROT_DIF_TYPE2 ||
- prot_op == SCSI_PROT_NORMAL)
+ if (prot_type == SCSI_PROT_DIF_TYPE0 || prot_op == SCSI_PROT_NORMAL)
return;
if (prot_op == SCSI_PROT_READ_STRIP)
@@ -2882,7 +3240,13 @@ _scsih_setup_eedp(struct scsi_cmnd *scmd, Mpi2SCSIIORequest_t *mpi_request)
MPI2_SCSIIO_EEDPFLAGS_CHECK_GUARD;
mpi_request->CDB.EEDP32.PrimaryReferenceTag =
cpu_to_be32(scsi_get_lba(scmd));
+ break;
+ case SCSI_PROT_DIF_TYPE2:
+
+ eedp_flags |= MPI2_SCSIIO_EEDPFLAGS_INC_PRI_REFTAG |
+ MPI2_SCSIIO_EEDPFLAGS_CHECK_REFTAG |
+ MPI2_SCSIIO_EEDPFLAGS_CHECK_GUARD;
break;
case SCSI_PROT_DIF_TYPE3:
@@ -2968,6 +3332,12 @@ _scsih_qcmd(struct scsi_cmnd *scmd, void (*done)(struct scsi_cmnd *))
return 0;
}
+ if (ioc->pci_error_recovery) {
+ scmd->result = DID_NO_CONNECT << 16;
+ scmd->scsi_done(scmd);
+ return 0;
+ }
+
sas_target_priv_data = sas_device_priv_data->sas_target;
/* invalid device handle */
if (sas_target_priv_data->handle == MPT2SAS_INVALID_DEVICE_HANDLE) {
@@ -2979,7 +3349,7 @@ _scsih_qcmd(struct scsi_cmnd *scmd, void (*done)(struct scsi_cmnd *))
/* host recovery or link resets sent via IOCTLs */
if (ioc->shost_recovery || ioc->ioc_link_reset_in_progress)
return SCSI_MLQUEUE_HOST_BUSY;
- /* device busy with task managment */
+ /* device busy with task management */
else if (sas_device_priv_data->block || sas_target_priv_data->tm_busy)
return SCSI_MLQUEUE_DEVICE_BUSY;
/* device has been deleted */
@@ -3013,7 +3383,7 @@ _scsih_qcmd(struct scsi_cmnd *scmd, void (*done)(struct scsi_cmnd *))
mpi_control |= MPI2_SCSIIO_CONTROL_SIMPLEQ;
/* Make sure Device is not raid volume */
if (!_scsih_is_raid(&scmd->device->sdev_gendev) &&
- sas_is_tlr_enabled(scmd->device))
+ sas_is_tlr_enabled(scmd->device) && scmd->cmd_len != 32)
mpi_control |= MPI2_SCSIIO_CONTROL_TLR_ON;
smid = mpt2sas_base_get_smid_scsiio(ioc, ioc->scsi_io_cb_idx, scmd);
@@ -3025,6 +3395,8 @@ _scsih_qcmd(struct scsi_cmnd *scmd, void (*done)(struct scsi_cmnd *))
mpi_request = mpt2sas_base_get_msg_frame(ioc, smid);
memset(mpi_request, 0, sizeof(Mpi2SCSIIORequest_t));
_scsih_setup_eedp(scmd, mpi_request);
+ if (scmd->cmd_len == 32)
+ mpi_control |= 4 << MPI2_SCSIIO_CONTROL_ADDCDBLEN_SHIFT;
mpi_request->Function = MPI2_FUNCTION_SCSI_IO_REQUEST;
if (sas_device_priv_data->sas_target->flags &
MPT_TARGET_FLAGS_RAID_COMPONENT)
@@ -3119,6 +3491,13 @@ _scsih_scsi_ioc_info(struct MPT2SAS_ADAPTER *ioc, struct scsi_cmnd *scmd,
char *desc_scsi_status = NULL;
char *desc_scsi_state = ioc->tmp_string;
u32 log_info = le32_to_cpu(mpi_reply->IOCLogInfo);
+ struct _sas_device *sas_device = NULL;
+ unsigned long flags;
+ struct scsi_target *starget = scmd->device->sdev_target;
+ struct MPT2SAS_TARGET *priv_target = starget->hostdata;
+
+ if (!priv_target)
+ return;
if (log_info == 0x31170000)
return;
@@ -3234,10 +3613,29 @@ _scsih_scsi_ioc_info(struct MPT2SAS_ADAPTER *ioc, struct scsi_cmnd *scmd,
strcat(desc_scsi_state, "autosense valid ");
scsi_print_command(scmd);
- printk(MPT2SAS_WARN_FMT "\tdev handle(0x%04x), "
- "ioc_status(%s)(0x%04x), smid(%d)\n", ioc->name,
- le16_to_cpu(mpi_reply->DevHandle), desc_ioc_state,
- ioc_status, smid);
+
+ if (priv_target->flags & MPT_TARGET_FLAGS_VOLUME) {
+ printk(MPT2SAS_WARN_FMT "\tvolume wwid(0x%016llx)\n", ioc->name,
+ (unsigned long long)priv_target->sas_address);
+ } else {
+ spin_lock_irqsave(&ioc->sas_device_lock, flags);
+ sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
+ priv_target->sas_address);
+ if (sas_device) {
+ printk(MPT2SAS_WARN_FMT "\tsas_address(0x%016llx), "
+ "phy(%d)\n", ioc->name, sas_device->sas_address,
+ sas_device->phy);
+ printk(MPT2SAS_WARN_FMT
+ "\tenclosure_logical_id(0x%016llx), slot(%d)\n",
+ ioc->name, sas_device->enclosure_logical_id,
+ sas_device->slot);
+ }
+ spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
+ }
+
+ printk(MPT2SAS_WARN_FMT "\thandle(0x%04x), ioc_status(%s)(0x%04x), "
+ "smid(%d)\n", ioc->name, le16_to_cpu(mpi_reply->DevHandle),
+ desc_ioc_state, ioc_status, smid);
printk(MPT2SAS_WARN_FMT "\trequest_len(%d), underflow(%d), "
"resid(%d)\n", ioc->name, scsi_bufflen(scmd), scmd->underflow,
scsi_get_resid(scmd));
@@ -3772,7 +4170,7 @@ _scsih_expander_add(struct MPT2SAS_ADAPTER *ioc, u16 handle)
if (!handle)
return -1;
- if (ioc->shost_recovery)
+ if (ioc->shost_recovery || ioc->pci_error_recovery)
return -1;
if ((mpt2sas_config_get_expander_pg0(ioc, &mpi_reply, &expander_pg0,
@@ -4178,7 +4576,7 @@ _scsih_add_device(struct MPT2SAS_ADAPTER *ioc, u16 handle, u8 phy_num, u8 is_pd)
le16_to_cpu(sas_device_pg0.Slot);
sas_device->device_info = device_info;
sas_device->sas_address = sas_address;
- sas_device->hidden_raid_component = is_pd;
+ sas_device->phy = sas_device_pg0.PhyNum;
/* get enclosure_logical_id */
if (sas_device->enclosure_handle && !(mpt2sas_config_get_enclosure_pg0(
@@ -4199,62 +4597,6 @@ _scsih_add_device(struct MPT2SAS_ADAPTER *ioc, u16 handle, u8 phy_num, u8 is_pd)
}
/**
- * _scsih_remove_pd_device - removing sas device pd object
- * @ioc: per adapter object
- * @sas_device_delete: the sas_device object
- *
- * For hidden raid components, we do driver-fw handshake from
- * hotplug work threads.
- * Return nothing.
- */
-static void
-_scsih_remove_pd_device(struct MPT2SAS_ADAPTER *ioc, struct _sas_device
- sas_device)
-{
- Mpi2SasIoUnitControlReply_t mpi_reply;
- Mpi2SasIoUnitControlRequest_t mpi_request;
- u16 vol_handle, handle;
-
- handle = sas_device.handle;
- dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: enter: handle(0x%04x),"
- " sas_addr(0x%016llx)\n", ioc->name, __func__, handle,
- (unsigned long long) sas_device.sas_address));
-
- vol_handle = sas_device.volume_handle;
- if (!vol_handle)
- return;
- dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "issue target reset: "
- "handle(0x%04x)\n", ioc->name, vol_handle));
- mpt2sas_scsih_issue_tm(ioc, vol_handle, 0, 0, 0,
- MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET, 0, 30, NULL);
- dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "issue target reset "
- "done: handle(0x%04x)\n", ioc->name, vol_handle));
- if (ioc->shost_recovery)
- return;
-
- /* SAS_IO_UNIT_CNTR - send REMOVE_DEVICE */
- dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "sas_iounit: handle"
- "(0x%04x)\n", ioc->name, handle));
- memset(&mpi_request, 0, sizeof(Mpi2SasIoUnitControlRequest_t));
- mpi_request.Function = MPI2_FUNCTION_SAS_IO_UNIT_CONTROL;
- mpi_request.Operation = MPI2_SAS_OP_REMOVE_DEVICE;
- mpi_request.DevHandle = cpu_to_le16(handle);
- if ((mpt2sas_base_sas_iounit_control(ioc, &mpi_reply,
- &mpi_request)) != 0)
- printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
-
- dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "sas_iounit: ioc_status"
- "(0x%04x), loginfo(0x%08x)\n", ioc->name,
- le16_to_cpu(mpi_reply.IOCStatus),
- le32_to_cpu(mpi_reply.IOCLogInfo)));
-
- dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: exit: handle(0x%04x),"
- " sas_addr(0x%016llx)\n", ioc->name, __func__, handle,
- (unsigned long long) sas_device.sas_address));
-}
-
-/**
* _scsih_remove_device - removing sas device object
* @ioc: per adapter object
* @sas_device_delete: the sas_device object
@@ -4284,9 +4626,6 @@ _scsih_remove_device(struct MPT2SAS_ADAPTER *ioc,
sas_target_priv_data->deleted = 1;
}
- if (sas_device_backup.hidden_raid_component)
- _scsih_remove_pd_device(ioc, sas_device_backup);
-
_scsih_ublock_io_device(ioc, sas_device_backup.handle);
mpt2sas_transport_port_remove(ioc, sas_device_backup.sas_address,
@@ -4338,9 +4677,9 @@ _scsih_sas_topology_change_event_debug(struct MPT2SAS_ADAPTER *ioc,
status_str = "unknown status";
break;
}
- printk(MPT2SAS_DEBUG_FMT "sas topology change: (%s)\n",
+ printk(MPT2SAS_INFO_FMT "sas topology change: (%s)\n",
ioc->name, status_str);
- printk(KERN_DEBUG "\thandle(0x%04x), enclosure_handle(0x%04x) "
+ printk(KERN_INFO "\thandle(0x%04x), enclosure_handle(0x%04x) "
"start_phy(%02d), count(%d)\n",
le16_to_cpu(event_data->ExpanderDevHandle),
le16_to_cpu(event_data->EnclosureHandle),
@@ -4374,7 +4713,7 @@ _scsih_sas_topology_change_event_debug(struct MPT2SAS_ADAPTER *ioc,
}
link_rate = event_data->PHY[i].LinkRate >> 4;
prev_link_rate = event_data->PHY[i].LinkRate & 0xF;
- printk(KERN_DEBUG "\tphy(%02d), attached_handle(0x%04x): %s:"
+ printk(KERN_INFO "\tphy(%02d), attached_handle(0x%04x): %s:"
" link rate: new(0x%02x), old(0x%02x)\n", phy_number,
handle, status_str, link_rate, prev_link_rate);
@@ -4409,7 +4748,7 @@ _scsih_sas_topology_change_event(struct MPT2SAS_ADAPTER *ioc,
_scsih_sas_topology_change_event_debug(ioc, event_data);
#endif
- if (ioc->shost_recovery || ioc->remove_host)
+ if (ioc->shost_recovery || ioc->remove_host || ioc->pci_error_recovery)
return;
if (!ioc->sas_hba.num_phys)
@@ -4418,7 +4757,7 @@ _scsih_sas_topology_change_event(struct MPT2SAS_ADAPTER *ioc,
_scsih_sas_host_refresh(ioc);
if (fw_event->ignore) {
- dewtprintk(ioc, printk(MPT2SAS_DEBUG_FMT "ignoring expander "
+ dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "ignoring expander "
"event\n", ioc->name));
return;
}
@@ -4444,11 +4783,12 @@ _scsih_sas_topology_change_event(struct MPT2SAS_ADAPTER *ioc,
/* handle siblings events */
for (i = 0; i < event_data->NumEntries; i++) {
if (fw_event->ignore) {
- dewtprintk(ioc, printk(MPT2SAS_DEBUG_FMT "ignoring "
+ dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "ignoring "
"expander event\n", ioc->name));
return;
}
- if (ioc->shost_recovery || ioc->remove_host)
+ if (ioc->shost_recovery || ioc->remove_host ||
+ ioc->pci_error_recovery)
return;
phy_number = event_data->StartPhyNum + i;
reason_code = event_data->PHY[i].PhyStatus &
@@ -4564,12 +4904,12 @@ _scsih_sas_device_status_change_event_debug(struct MPT2SAS_ADAPTER *ioc,
reason_str = "unknown reason";
break;
}
- printk(MPT2SAS_DEBUG_FMT "device status change: (%s)\n"
+ printk(MPT2SAS_INFO_FMT "device status change: (%s)\n"
"\thandle(0x%04x), sas address(0x%016llx)", ioc->name,
reason_str, le16_to_cpu(event_data->DevHandle),
(unsigned long long)le64_to_cpu(event_data->SASAddress));
if (event_data->ReasonCode == MPI2_EVENT_SAS_DEV_STAT_RC_SMART_DATA)
- printk(MPT2SAS_DEBUG_FMT ", ASC(0x%x), ASCQ(0x%x)\n", ioc->name,
+ printk(MPT2SAS_INFO_FMT ", ASC(0x%x), ASCQ(0x%x)\n", ioc->name,
event_data->ASC, event_data->ASCQ);
printk(KERN_INFO "\n");
}
@@ -4653,7 +4993,7 @@ _scsih_sas_enclosure_dev_status_change_event_debug(struct MPT2SAS_ADAPTER *ioc,
break;
}
- printk(MPT2SAS_DEBUG_FMT "enclosure status change: (%s)\n"
+ printk(MPT2SAS_INFO_FMT "enclosure status change: (%s)\n"
"\thandle(0x%04x), enclosure logical id(0x%016llx)"
" number slots(%d)\n", ioc->name, reason_str,
le16_to_cpu(event_data->EnclosureHandle),
@@ -4704,10 +5044,10 @@ _scsih_sas_broadcast_primative_event(struct MPT2SAS_ADAPTER *ioc,
Mpi2EventDataSasBroadcastPrimitive_t *event_data = fw_event->event_data;
#endif
u16 ioc_status;
- dewtprintk(ioc, printk(MPT2SAS_DEBUG_FMT "broadcast primative: "
+ dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "broadcast primative: "
"phy number(%d), width(%d)\n", ioc->name, event_data->PhyNum,
event_data->PortWidth));
- dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: enter\n", ioc->name,
+ dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: enter\n", ioc->name,
__func__));
termination_count = 0;
@@ -4751,7 +5091,7 @@ _scsih_sas_broadcast_primative_event(struct MPT2SAS_ADAPTER *ioc,
}
ioc->broadcast_aen_busy = 0;
- dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT
+ dtmprintk(ioc, printk(MPT2SAS_INFO_FMT
"%s - exit, query_count = %d termination_count = %d\n",
ioc->name, __func__, query_count, termination_count));
}
@@ -4772,7 +5112,7 @@ _scsih_sas_discovery_event(struct MPT2SAS_ADAPTER *ioc,
#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK) {
- printk(MPT2SAS_DEBUG_FMT "discovery event: (%s)", ioc->name,
+ printk(MPT2SAS_INFO_FMT "discovery event: (%s)", ioc->name,
(event_data->ReasonCode == MPI2_EVENT_SAS_DISC_RC_STARTED) ?
"start" : "stop");
if (event_data->DiscoveryStatus)
@@ -4883,17 +5223,15 @@ _scsih_sas_volume_add(struct MPT2SAS_ADAPTER *ioc,
/**
* _scsih_sas_volume_delete - delete volume
* @ioc: per adapter object
- * @element: IR config element data
+ * @handle: volume device handle
* Context: user.
*
* Return nothing.
*/
static void
-_scsih_sas_volume_delete(struct MPT2SAS_ADAPTER *ioc,
- Mpi2EventIrConfigElement_t *element)
+_scsih_sas_volume_delete(struct MPT2SAS_ADAPTER *ioc, u16 handle)
{
struct _raid_device *raid_device;
- u16 handle = le16_to_cpu(element->VolDevHandle);
unsigned long flags;
struct MPT2SAS_TARGET *sas_target_priv_data;
@@ -4907,6 +5245,9 @@ _scsih_sas_volume_delete(struct MPT2SAS_ADAPTER *ioc,
sas_target_priv_data->deleted = 1;
scsi_remove_target(&raid_device->starget->dev);
}
+ printk(MPT2SAS_INFO_FMT "removing handle(0x%04x), wwid"
+ "(0x%016llx)\n", ioc->name, raid_device->handle,
+ (unsigned long long) raid_device->wwid);
_scsih_raid_device_remove(ioc, raid_device);
}
@@ -4935,7 +5276,7 @@ _scsih_sas_pd_expose(struct MPT2SAS_ADAPTER *ioc,
/* exposing raid component */
sas_device->volume_handle = 0;
sas_device->volume_wwid = 0;
- sas_device->hidden_raid_component = 0;
+ clear_bit(handle, ioc->pd_handles);
_scsih_reprobe_target(sas_device->starget, 0);
}
@@ -4966,7 +5307,7 @@ _scsih_sas_pd_hide(struct MPT2SAS_ADAPTER *ioc,
&sas_device->volume_handle);
mpt2sas_config_get_volume_wwid(ioc, sas_device->volume_handle,
&sas_device->volume_wwid);
- sas_device->hidden_raid_component = 1;
+ set_bit(handle, ioc->pd_handles);
_scsih_reprobe_target(sas_device->starget, 1);
}
@@ -5015,13 +5356,13 @@ _scsih_sas_pd_add(struct MPT2SAS_ADAPTER *ioc,
u64 sas_address;
u16 parent_handle;
+ set_bit(handle, ioc->pd_handles);
+
spin_lock_irqsave(&ioc->sas_device_lock, flags);
sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
- if (sas_device) {
- sas_device->hidden_raid_component = 1;
+ if (sas_device)
return;
- }
if ((mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0,
MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, handle))) {
@@ -5066,7 +5407,7 @@ _scsih_sas_ir_config_change_event_debug(struct MPT2SAS_ADAPTER *ioc,
element = (Mpi2EventIrConfigElement_t *)&event_data->ConfigElement[0];
- printk(MPT2SAS_DEBUG_FMT "raid config change: (%s), elements(%d)\n",
+ printk(MPT2SAS_INFO_FMT "raid config change: (%s), elements(%d)\n",
ioc->name, (le32_to_cpu(event_data->Flags) &
MPI2_EVENT_IR_CHANGE_FLAGS_FOREIGN_CONFIG) ?
"foreign" : "native", event_data->NumElements);
@@ -5119,7 +5460,7 @@ _scsih_sas_ir_config_change_event_debug(struct MPT2SAS_ADAPTER *ioc,
element_str = "unknown element";
break;
}
- printk(KERN_DEBUG "\t(%s:%s), vol handle(0x%04x), "
+ printk(KERN_INFO "\t(%s:%s), vol handle(0x%04x), "
"pd handle(0x%04x), pd num(0x%02x)\n", element_str,
reason_str, le16_to_cpu(element->VolDevHandle),
le16_to_cpu(element->PhysDiskDevHandle),
@@ -5165,7 +5506,8 @@ _scsih_sas_ir_config_change_event(struct MPT2SAS_ADAPTER *ioc,
case MPI2_EVENT_IR_CHANGE_RC_VOLUME_DELETED:
case MPI2_EVENT_IR_CHANGE_RC_REMOVED:
if (!foreign_config)
- _scsih_sas_volume_delete(ioc, element);
+ _scsih_sas_volume_delete(ioc,
+ le16_to_cpu(element->VolDevHandle));
break;
case MPI2_EVENT_IR_CHANGE_RC_PD_CREATED:
_scsih_sas_pd_hide(ioc, element);
@@ -5201,7 +5543,6 @@ _scsih_sas_ir_volume_event(struct MPT2SAS_ADAPTER *ioc,
u16 handle;
u32 state;
int rc;
- struct MPT2SAS_TARGET *sas_target_priv_data;
Mpi2EventDataIrVolume_t *event_data = fw_event->event_data;
if (event_data->ReasonCode != MPI2_EVENT_IR_VOLUME_RC_STATE_CHANGED)
@@ -5209,30 +5550,24 @@ _scsih_sas_ir_volume_event(struct MPT2SAS_ADAPTER *ioc,
handle = le16_to_cpu(event_data->VolDevHandle);
state = le32_to_cpu(event_data->NewValue);
- dewtprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: handle(0x%04x), "
+ dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: handle(0x%04x), "
"old(0x%08x), new(0x%08x)\n", ioc->name, __func__, handle,
le32_to_cpu(event_data->PreviousValue), state));
- spin_lock_irqsave(&ioc->raid_device_lock, flags);
- raid_device = _scsih_raid_device_find_by_handle(ioc, handle);
- spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
-
switch (state) {
case MPI2_RAID_VOL_STATE_MISSING:
case MPI2_RAID_VOL_STATE_FAILED:
- if (!raid_device)
- break;
- if (raid_device->starget) {
- sas_target_priv_data = raid_device->starget->hostdata;
- sas_target_priv_data->deleted = 1;
- scsi_remove_target(&raid_device->starget->dev);
- }
- _scsih_raid_device_remove(ioc, raid_device);
+ _scsih_sas_volume_delete(ioc, handle);
break;
case MPI2_RAID_VOL_STATE_ONLINE:
case MPI2_RAID_VOL_STATE_DEGRADED:
case MPI2_RAID_VOL_STATE_OPTIMAL:
+
+ spin_lock_irqsave(&ioc->raid_device_lock, flags);
+ raid_device = _scsih_raid_device_find_by_handle(ioc, handle);
+ spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
+
if (raid_device)
break;
@@ -5297,23 +5632,25 @@ _scsih_sas_ir_physical_disk_event(struct MPT2SAS_ADAPTER *ioc,
handle = le16_to_cpu(event_data->PhysDiskDevHandle);
state = le32_to_cpu(event_data->NewValue);
- dewtprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: handle(0x%04x), "
+ dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: handle(0x%04x), "
"old(0x%08x), new(0x%08x)\n", ioc->name, __func__, handle,
le32_to_cpu(event_data->PreviousValue), state));
- spin_lock_irqsave(&ioc->sas_device_lock, flags);
- sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
- spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
-
switch (state) {
case MPI2_RAID_PD_STATE_ONLINE:
case MPI2_RAID_PD_STATE_DEGRADED:
case MPI2_RAID_PD_STATE_REBUILDING:
case MPI2_RAID_PD_STATE_OPTIMAL:
- if (sas_device) {
- sas_device->hidden_raid_component = 1;
+ case MPI2_RAID_PD_STATE_HOT_SPARE:
+
+ set_bit(handle, ioc->pd_handles);
+
+ spin_lock_irqsave(&ioc->sas_device_lock, flags);
+ sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
+ spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
+
+ if (sas_device)
return;
- }
if ((mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply,
&sas_device_pg0, MPI2_SAS_DEVICE_PGAD_FORM_HANDLE,
@@ -5343,7 +5680,6 @@ _scsih_sas_ir_physical_disk_event(struct MPT2SAS_ADAPTER *ioc,
case MPI2_RAID_PD_STATE_OFFLINE:
case MPI2_RAID_PD_STATE_NOT_CONFIGURED:
case MPI2_RAID_PD_STATE_NOT_COMPATIBLE:
- case MPI2_RAID_PD_STATE_HOT_SPARE:
default:
break;
}
@@ -5471,7 +5807,7 @@ _scsih_task_set_full(struct MPT2SAS_ADAPTER *ioc, struct fw_event_work
sas_address = sas_device->sas_address;
/* if hidden raid component, then change to volume characteristics */
- if (sas_device->hidden_raid_component && sas_device->volume_handle) {
+ if (test_bit(handle, ioc->pd_handles) && sas_device->volume_handle) {
spin_lock_irqsave(&ioc->raid_device_lock, flags);
raid_device = _scsih_raid_device_find_by_handle(
ioc, sas_device->volume_handle);
@@ -5485,7 +5821,7 @@ _scsih_task_set_full(struct MPT2SAS_ADAPTER *ioc, struct fw_event_work
}
if (ioc->logging_level & MPT_DEBUG_TASK_SET_FULL)
- starget_printk(KERN_DEBUG, sas_device->starget, "task set "
+ starget_printk(KERN_INFO, sas_device->starget, "task set "
"full: handle(0x%04x), sas_addr(0x%016llx), depth(%d)\n",
handle, (unsigned long long)sas_address, current_depth);
@@ -5696,9 +6032,12 @@ static void
_scsih_search_responding_raid_devices(struct MPT2SAS_ADAPTER *ioc)
{
Mpi2RaidVolPage1_t volume_pg1;
+ Mpi2RaidVolPage0_t volume_pg0;
+ Mpi2RaidPhysDiskPage0_t pd_pg0;
Mpi2ConfigReply_t mpi_reply;
u16 ioc_status;
u16 handle;
+ u8 phys_disk_num;
printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, __func__);
@@ -5713,8 +6052,32 @@ _scsih_search_responding_raid_devices(struct MPT2SAS_ADAPTER *ioc)
if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)
break;
handle = le16_to_cpu(volume_pg1.DevHandle);
- _scsih_mark_responding_raid_device(ioc,
- le64_to_cpu(volume_pg1.WWID), handle);
+
+ if (mpt2sas_config_get_raid_volume_pg0(ioc, &mpi_reply,
+ &volume_pg0, MPI2_RAID_VOLUME_PGAD_FORM_HANDLE, handle,
+ sizeof(Mpi2RaidVolPage0_t)))
+ continue;
+
+ if (volume_pg0.VolumeState == MPI2_RAID_VOL_STATE_OPTIMAL ||
+ volume_pg0.VolumeState == MPI2_RAID_VOL_STATE_ONLINE ||
+ volume_pg0.VolumeState == MPI2_RAID_VOL_STATE_DEGRADED)
+ _scsih_mark_responding_raid_device(ioc,
+ le64_to_cpu(volume_pg1.WWID), handle);
+ }
+
+ /* refresh the pd_handles */
+ phys_disk_num = 0xFF;
+ memset(ioc->pd_handles, 0, ioc->pd_handles_sz);
+ while (!(mpt2sas_config_get_phys_disk_pg0(ioc, &mpi_reply,
+ &pd_pg0, MPI2_PHYSDISK_PGAD_FORM_GET_NEXT_PHYSDISKNUM,
+ phys_disk_num))) {
+ ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
+ MPI2_IOCSTATUS_MASK;
+ if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)
+ break;
+ phys_disk_num = pd_pg0.PhysDiskNum;
+ handle = le16_to_cpu(pd_pg0.DevHandle);
+ set_bit(handle, ioc->pd_handles);
}
}
@@ -5876,11 +6239,11 @@ mpt2sas_scsih_reset_handler(struct MPT2SAS_ADAPTER *ioc, int reset_phase)
{
switch (reset_phase) {
case MPT2_IOC_PRE_RESET:
- dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: "
+ dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: "
"MPT2_IOC_PRE_RESET\n", ioc->name, __func__));
break;
case MPT2_IOC_AFTER_RESET:
- dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: "
+ dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: "
"MPT2_IOC_AFTER_RESET\n", ioc->name, __func__));
if (ioc->scsih_cmds.status & MPT2_CMD_PENDING) {
ioc->scsih_cmds.status |= MPT2_CMD_RESET;
@@ -5897,7 +6260,7 @@ mpt2sas_scsih_reset_handler(struct MPT2SAS_ADAPTER *ioc, int reset_phase)
_scsih_queue_rescan(ioc);
break;
case MPT2_IOC_DONE_RESET:
- dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: "
+ dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: "
"MPT2_IOC_DONE_RESET\n", ioc->name, __func__));
_scsih_sas_host_refresh(ioc);
_scsih_prep_device_scan(ioc);
@@ -5925,7 +6288,8 @@ _firmware_event_work(struct work_struct *work)
struct MPT2SAS_ADAPTER *ioc = fw_event->ioc;
/* the queue is being flushed so ignore this event */
- if (ioc->remove_host || fw_event->cancel_pending_work) {
+ if (ioc->remove_host || fw_event->cancel_pending_work ||
+ ioc->pci_error_recovery) {
_scsih_fw_event_free(ioc, fw_event);
return;
}
@@ -6007,7 +6371,7 @@ mpt2sas_scsih_event_callback(struct MPT2SAS_ADAPTER *ioc, u8 msix_index,
u16 sz;
/* events turned off due to host reset or driver unloading */
- if (ioc->remove_host)
+ if (ioc->remove_host || ioc->pci_error_recovery)
return 1;
mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply);
@@ -6034,14 +6398,21 @@ mpt2sas_scsih_event_callback(struct MPT2SAS_ADAPTER *ioc, u8 msix_index,
(Mpi2EventDataSasTopologyChangeList_t *)
mpi_reply->EventData);
break;
-
+ case MPI2_EVENT_IR_CONFIGURATION_CHANGE_LIST:
+ _scsih_check_ir_config_unhide_events(ioc,
+ (Mpi2EventDataIrConfigChangeList_t *)
+ mpi_reply->EventData);
+ break;
+ case MPI2_EVENT_IR_VOLUME:
+ _scsih_check_volume_delete_events(ioc,
+ (Mpi2EventDataIrVolume_t *)
+ mpi_reply->EventData);
+ break;
case MPI2_EVENT_SAS_DEVICE_STATUS_CHANGE:
case MPI2_EVENT_IR_OPERATION_STATUS:
case MPI2_EVENT_SAS_DISCOVERY:
case MPI2_EVENT_SAS_ENCL_DEVICE_STATUS_CHANGE:
- case MPI2_EVENT_IR_VOLUME:
case MPI2_EVENT_IR_PHYSICAL_DISK:
- case MPI2_EVENT_IR_CONFIGURATION_CHANGE_LIST:
case MPI2_EVENT_TASK_SET_FULL:
break;
@@ -6548,9 +6919,11 @@ _scsih_probe(struct pci_dev *pdev, const struct pci_device_id *id)
ioc->scsih_cb_idx = scsih_cb_idx;
ioc->config_cb_idx = config_cb_idx;
ioc->tm_tr_cb_idx = tm_tr_cb_idx;
+ ioc->tm_tr_volume_cb_idx = tm_tr_volume_cb_idx;
ioc->tm_sas_control_cb_idx = tm_sas_control_cb_idx;
ioc->logging_level = logging_level;
/* misc semaphores and spin locks */
+ mutex_init(&ioc->reset_in_progress_mutex);
spin_lock_init(&ioc->ioc_reset_in_progress_lock);
spin_lock_init(&ioc->scsi_lookup_lock);
spin_lock_init(&ioc->sas_device_lock);
@@ -6565,9 +6938,10 @@ _scsih_probe(struct pci_dev *pdev, const struct pci_device_id *id)
INIT_LIST_HEAD(&ioc->raid_device_list);
INIT_LIST_HEAD(&ioc->sas_hba.sas_port_list);
INIT_LIST_HEAD(&ioc->delayed_tr_list);
+ INIT_LIST_HEAD(&ioc->delayed_tr_volume_list);
/* init shost parameters */
- shost->max_cmd_len = 16;
+ shost->max_cmd_len = 32;
shost->max_lun = max_lun;
shost->transportt = mpt2sas_transport_template;
shost->unique_id = ioc->id;
@@ -6580,7 +6954,7 @@ _scsih_probe(struct pci_dev *pdev, const struct pci_device_id *id)
}
scsi_host_set_prot(shost, SHOST_DIF_TYPE1_PROTECTION
- | SHOST_DIF_TYPE3_PROTECTION);
+ | SHOST_DIF_TYPE2_PROTECTION | SHOST_DIF_TYPE3_PROTECTION);
scsi_host_set_guard(shost, SHOST_DIX_GUARD_CRC);
/* event thread */
@@ -6700,12 +7074,17 @@ _scsih_pci_error_detected(struct pci_dev *pdev, pci_channel_state_t state)
case pci_channel_io_normal:
return PCI_ERS_RESULT_CAN_RECOVER;
case pci_channel_io_frozen:
+ /* Fatal error, prepare for slot reset */
+ ioc->pci_error_recovery = 1;
scsi_block_requests(ioc->shost);
mpt2sas_base_stop_watchdog(ioc);
mpt2sas_base_free_resources(ioc);
return PCI_ERS_RESULT_NEED_RESET;
case pci_channel_io_perm_failure:
- _scsih_remove(pdev);
+ /* Permanent error, prepare for device removal */
+ ioc->pci_error_recovery = 1;
+ mpt2sas_base_stop_watchdog(ioc);
+ _scsih_flush_running_cmds(ioc);
return PCI_ERS_RESULT_DISCONNECT;
}
return PCI_ERS_RESULT_NEED_RESET;
@@ -6729,7 +7108,9 @@ _scsih_pci_slot_reset(struct pci_dev *pdev)
printk(MPT2SAS_INFO_FMT "PCI error: slot reset callback!!\n",
ioc->name);
+ ioc->pci_error_recovery = 0;
ioc->pdev = pdev;
+ pci_restore_state(pdev);
rc = mpt2sas_base_map_resources(ioc);
if (rc)
return PCI_ERS_RESULT_DISCONNECT;
@@ -6845,7 +7226,7 @@ _scsih_init(void)
/* queuecommand callback hander */
scsi_io_cb_idx = mpt2sas_base_register_callback_handler(_scsih_io_done);
- /* task managment callback handler */
+ /* task management callback handler */
tm_cb_idx = mpt2sas_base_register_callback_handler(_scsih_tm_done);
/* base internal commands callback handler */
@@ -6867,6 +7248,10 @@ _scsih_init(void)
tm_tr_cb_idx = mpt2sas_base_register_callback_handler(
_scsih_tm_tr_complete);
+
+ tm_tr_volume_cb_idx = mpt2sas_base_register_callback_handler(
+ _scsih_tm_volume_tr_complete);
+
tm_sas_control_cb_idx = mpt2sas_base_register_callback_handler(
_scsih_sas_control_complete);
@@ -6906,6 +7291,7 @@ _scsih_exit(void)
mpt2sas_base_release_callback_handler(ctl_cb_idx);
mpt2sas_base_release_callback_handler(tm_tr_cb_idx);
+ mpt2sas_base_release_callback_handler(tm_tr_volume_cb_idx);
mpt2sas_base_release_callback_handler(tm_sas_control_cb_idx);
/* raid transport support */
diff --git a/drivers/scsi/mpt2sas/mpt2sas_transport.c b/drivers/scsi/mpt2sas/mpt2sas_transport.c
index 2727c3b6510..b55c6dc0747 100644
--- a/drivers/scsi/mpt2sas/mpt2sas_transport.c
+++ b/drivers/scsi/mpt2sas/mpt2sas_transport.c
@@ -140,7 +140,7 @@ _transport_set_identify(struct MPT2SAS_ADAPTER *ioc, u16 handle,
u32 device_info;
u32 ioc_status;
- if (ioc->shost_recovery) {
+ if (ioc->shost_recovery || ioc->pci_error_recovery) {
printk(MPT2SAS_INFO_FMT "%s: host reset in progress!\n",
__func__, ioc->name);
return -EFAULT;
@@ -302,7 +302,7 @@ _transport_expander_report_manufacture(struct MPT2SAS_ADAPTER *ioc,
u64 *sas_address_le;
u16 wait_state_count;
- if (ioc->shost_recovery) {
+ if (ioc->shost_recovery || ioc->pci_error_recovery) {
printk(MPT2SAS_INFO_FMT "%s: host reset in progress!\n",
__func__, ioc->name);
return -EFAULT;
@@ -397,7 +397,7 @@ _transport_expander_report_manufacture(struct MPT2SAS_ADAPTER *ioc,
sizeof(struct rep_manu_reply), data_out_dma +
sizeof(struct rep_manu_request));
- dtransportprintk(ioc, printk(MPT2SAS_DEBUG_FMT "report_manufacture - "
+ dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT "report_manufacture - "
"send to sas_addr(0x%016llx)\n", ioc->name,
(unsigned long long)sas_address));
mpt2sas_base_put_smid_default(ioc, smid);
@@ -415,7 +415,7 @@ _transport_expander_report_manufacture(struct MPT2SAS_ADAPTER *ioc,
goto issue_host_reset;
}
- dtransportprintk(ioc, printk(MPT2SAS_DEBUG_FMT "report_manufacture - "
+ dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT "report_manufacture - "
"complete\n", ioc->name));
if (ioc->transport_cmds.status & MPT2_CMD_REPLY_VALID) {
@@ -423,7 +423,7 @@ _transport_expander_report_manufacture(struct MPT2SAS_ADAPTER *ioc,
mpi_reply = ioc->transport_cmds.reply;
- dtransportprintk(ioc, printk(MPT2SAS_DEBUG_FMT
+ dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT
"report_manufacture - reply data transfer size(%d)\n",
ioc->name, le16_to_cpu(mpi_reply->ResponseDataLength)));
@@ -449,7 +449,7 @@ _transport_expander_report_manufacture(struct MPT2SAS_ADAPTER *ioc,
manufacture_reply->component_revision_id;
}
} else
- dtransportprintk(ioc, printk(MPT2SAS_DEBUG_FMT
+ dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT
"report_manufacture - no reply\n", ioc->name));
issue_host_reset:
@@ -894,7 +894,7 @@ mpt2sas_transport_update_links(struct MPT2SAS_ADAPTER *ioc,
struct _sas_node *sas_node;
struct _sas_phy *mpt2sas_phy;
- if (ioc->shost_recovery)
+ if (ioc->shost_recovery || ioc->pci_error_recovery)
return;
spin_lock_irqsave(&ioc->sas_node_lock, flags);
@@ -940,22 +940,230 @@ rphy_to_ioc(struct sas_rphy *rphy)
return shost_priv(shost);
}
-static struct _sas_phy *
-_transport_find_local_phy(struct MPT2SAS_ADAPTER *ioc, struct sas_phy *phy)
+
+/* report phy error log structure */
+struct phy_error_log_request{
+ u8 smp_frame_type; /* 0x40 */
+ u8 function; /* 0x11 */
+ u8 allocated_response_length;
+ u8 request_length; /* 02 */
+ u8 reserved_1[5];
+ u8 phy_identifier;
+ u8 reserved_2[2];
+};
+
+/* report phy error log reply structure */
+struct phy_error_log_reply{
+ u8 smp_frame_type; /* 0x41 */
+ u8 function; /* 0x11 */
+ u8 function_result;
+ u8 response_length;
+ u16 expander_change_count;
+ u8 reserved_1[3];
+ u8 phy_identifier;
+ u8 reserved_2[2];
+ u32 invalid_dword;
+ u32 running_disparity_error;
+ u32 loss_of_dword_sync;
+ u32 phy_reset_problem;
+};
+
+/**
+ * _transport_get_expander_phy_error_log - return expander counters
+ * @ioc: per adapter object
+ * @phy: The sas phy object
+ *
+ * Returns 0 for success, non-zero for failure.
+ *
+ */
+static int
+_transport_get_expander_phy_error_log(struct MPT2SAS_ADAPTER *ioc,
+ struct sas_phy *phy)
{
- int i;
+ Mpi2SmpPassthroughRequest_t *mpi_request;
+ Mpi2SmpPassthroughReply_t *mpi_reply;
+ struct phy_error_log_request *phy_error_log_request;
+ struct phy_error_log_reply *phy_error_log_reply;
+ int rc;
+ u16 smid;
+ u32 ioc_state;
+ unsigned long timeleft;
+ void *psge;
+ u32 sgl_flags;
+ u8 issue_reset = 0;
+ void *data_out = NULL;
+ dma_addr_t data_out_dma;
+ u32 sz;
+ u64 *sas_address_le;
+ u16 wait_state_count;
- for (i = 0; i < ioc->sas_hba.num_phys; i++)
- if (ioc->sas_hba.phy[i].phy == phy)
- return(&ioc->sas_hba.phy[i]);
- return NULL;
+ if (ioc->shost_recovery || ioc->pci_error_recovery) {
+ printk(MPT2SAS_INFO_FMT "%s: host reset in progress!\n",
+ __func__, ioc->name);
+ return -EFAULT;
+ }
+
+ mutex_lock(&ioc->transport_cmds.mutex);
+
+ if (ioc->transport_cmds.status != MPT2_CMD_NOT_USED) {
+ printk(MPT2SAS_ERR_FMT "%s: transport_cmds in use\n",
+ ioc->name, __func__);
+ rc = -EAGAIN;
+ goto out;
+ }
+ ioc->transport_cmds.status = MPT2_CMD_PENDING;
+
+ wait_state_count = 0;
+ ioc_state = mpt2sas_base_get_iocstate(ioc, 1);
+ while (ioc_state != MPI2_IOC_STATE_OPERATIONAL) {
+ if (wait_state_count++ == 10) {
+ printk(MPT2SAS_ERR_FMT
+ "%s: failed due to ioc not operational\n",
+ ioc->name, __func__);
+ rc = -EFAULT;
+ goto out;
+ }
+ ssleep(1);
+ ioc_state = mpt2sas_base_get_iocstate(ioc, 1);
+ printk(MPT2SAS_INFO_FMT "%s: waiting for "
+ "operational state(count=%d)\n", ioc->name,
+ __func__, wait_state_count);
+ }
+ if (wait_state_count)
+ printk(MPT2SAS_INFO_FMT "%s: ioc is operational\n",
+ ioc->name, __func__);
+
+ smid = mpt2sas_base_get_smid(ioc, ioc->transport_cb_idx);
+ if (!smid) {
+ printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n",
+ ioc->name, __func__);
+ rc = -EAGAIN;
+ goto out;
+ }
+
+ mpi_request = mpt2sas_base_get_msg_frame(ioc, smid);
+ ioc->transport_cmds.smid = smid;
+
+ sz = sizeof(struct phy_error_log_request) +
+ sizeof(struct phy_error_log_reply);
+ data_out = pci_alloc_consistent(ioc->pdev, sz, &data_out_dma);
+ if (!data_out) {
+ printk(KERN_ERR "failure at %s:%d/%s()!\n", __FILE__,
+ __LINE__, __func__);
+ rc = -ENOMEM;
+ mpt2sas_base_free_smid(ioc, smid);
+ goto out;
+ }
+
+ rc = -EINVAL;
+ memset(data_out, 0, sz);
+ phy_error_log_request = data_out;
+ phy_error_log_request->smp_frame_type = 0x40;
+ phy_error_log_request->function = 0x11;
+ phy_error_log_request->request_length = 2;
+ phy_error_log_request->allocated_response_length = 0;
+ phy_error_log_request->phy_identifier = phy->number;
+
+ memset(mpi_request, 0, sizeof(Mpi2SmpPassthroughRequest_t));
+ mpi_request->Function = MPI2_FUNCTION_SMP_PASSTHROUGH;
+ mpi_request->PhysicalPort = 0xFF;
+ mpi_request->VF_ID = 0; /* TODO */
+ mpi_request->VP_ID = 0;
+ sas_address_le = (u64 *)&mpi_request->SASAddress;
+ *sas_address_le = cpu_to_le64(phy->identify.sas_address);
+ mpi_request->RequestDataLength =
+ cpu_to_le16(sizeof(struct phy_error_log_request));
+ psge = &mpi_request->SGL;
+
+ /* WRITE sgel first */
+ sgl_flags = (MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
+ MPI2_SGE_FLAGS_END_OF_BUFFER | MPI2_SGE_FLAGS_HOST_TO_IOC);
+ sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT;
+ ioc->base_add_sg_single(psge, sgl_flags |
+ sizeof(struct phy_error_log_request), data_out_dma);
+
+ /* incr sgel */
+ psge += ioc->sge_size;
+
+ /* READ sgel last */
+ sgl_flags = (MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
+ MPI2_SGE_FLAGS_LAST_ELEMENT | MPI2_SGE_FLAGS_END_OF_BUFFER |
+ MPI2_SGE_FLAGS_END_OF_LIST);
+ sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT;
+ ioc->base_add_sg_single(psge, sgl_flags |
+ sizeof(struct phy_error_log_reply), data_out_dma +
+ sizeof(struct phy_error_log_request));
+
+ dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT "phy_error_log - "
+ "send to sas_addr(0x%016llx), phy(%d)\n", ioc->name,
+ (unsigned long long)phy->identify.sas_address, phy->number));
+ mpt2sas_base_put_smid_default(ioc, smid);
+ init_completion(&ioc->transport_cmds.done);
+ timeleft = wait_for_completion_timeout(&ioc->transport_cmds.done,
+ 10*HZ);
+
+ if (!(ioc->transport_cmds.status & MPT2_CMD_COMPLETE)) {
+ printk(MPT2SAS_ERR_FMT "%s: timeout\n",
+ ioc->name, __func__);
+ _debug_dump_mf(mpi_request,
+ sizeof(Mpi2SmpPassthroughRequest_t)/4);
+ if (!(ioc->transport_cmds.status & MPT2_CMD_RESET))
+ issue_reset = 1;
+ goto issue_host_reset;
+ }
+
+ dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT "phy_error_log - "
+ "complete\n", ioc->name));
+
+ if (ioc->transport_cmds.status & MPT2_CMD_REPLY_VALID) {
+
+ mpi_reply = ioc->transport_cmds.reply;
+
+ dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT
+ "phy_error_log - reply data transfer size(%d)\n",
+ ioc->name, le16_to_cpu(mpi_reply->ResponseDataLength)));
+
+ if (le16_to_cpu(mpi_reply->ResponseDataLength) !=
+ sizeof(struct phy_error_log_reply))
+ goto out;
+
+ phy_error_log_reply = data_out +
+ sizeof(struct phy_error_log_request);
+
+ dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT
+ "phy_error_log - function_result(%d)\n",
+ ioc->name, phy_error_log_reply->function_result));
+
+ phy->invalid_dword_count =
+ be32_to_cpu(phy_error_log_reply->invalid_dword);
+ phy->running_disparity_error_count =
+ be32_to_cpu(phy_error_log_reply->running_disparity_error);
+ phy->loss_of_dword_sync_count =
+ be32_to_cpu(phy_error_log_reply->loss_of_dword_sync);
+ phy->phy_reset_problem_count =
+ be32_to_cpu(phy_error_log_reply->phy_reset_problem);
+ rc = 0;
+ } else
+ dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT
+ "phy_error_log - no reply\n", ioc->name));
+
+ issue_host_reset:
+ if (issue_reset)
+ mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP,
+ FORCE_BIG_HAMMER);
+ out:
+ ioc->transport_cmds.status = MPT2_CMD_NOT_USED;
+ if (data_out)
+ pci_free_consistent(ioc->pdev, sz, data_out, data_out_dma);
+
+ mutex_unlock(&ioc->transport_cmds.mutex);
+ return rc;
}
/**
- * _transport_get_linkerrors -
+ * _transport_get_linkerrors - return phy counters for both hba and expanders
* @phy: The sas phy object
*
- * Only support sas_host direct attached phys.
* Returns 0 for success, non-zero for failure.
*
*/
@@ -963,17 +1171,24 @@ static int
_transport_get_linkerrors(struct sas_phy *phy)
{
struct MPT2SAS_ADAPTER *ioc = phy_to_ioc(phy);
- struct _sas_phy *mpt2sas_phy;
+ unsigned long flags;
Mpi2ConfigReply_t mpi_reply;
Mpi2SasPhyPage1_t phy_pg1;
- mpt2sas_phy = _transport_find_local_phy(ioc, phy);
-
- if (!mpt2sas_phy) /* this phy not on sas_host */
+ spin_lock_irqsave(&ioc->sas_node_lock, flags);
+ if (_transport_sas_node_find_by_sas_address(ioc,
+ phy->identify.sas_address) == NULL) {
+ spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
return -EINVAL;
+ }
+ spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
+ if (phy->identify.sas_address != ioc->sas_hba.sas_address)
+ return _transport_get_expander_phy_error_log(ioc, phy);
+
+ /* get hba phy error logs */
if ((mpt2sas_config_get_phy_pg1(ioc, &mpi_reply, &phy_pg1,
- mpt2sas_phy->phy_id))) {
+ phy->number))) {
printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
ioc->name, __FILE__, __LINE__, __func__);
return -ENXIO;
@@ -982,8 +1197,7 @@ _transport_get_linkerrors(struct sas_phy *phy)
if (mpi_reply.IOCStatus || mpi_reply.IOCLogInfo)
printk(MPT2SAS_INFO_FMT "phy(%d), ioc_status"
"(0x%04x), loginfo(0x%08x)\n", ioc->name,
- mpt2sas_phy->phy_id,
- le16_to_cpu(mpi_reply.IOCStatus),
+ phy->number, le16_to_cpu(mpi_reply.IOCStatus),
le32_to_cpu(mpi_reply.IOCLogInfo));
phy->invalid_dword_count = le32_to_cpu(phy_pg1.InvalidDwordCount);
@@ -1007,18 +1221,18 @@ static int
_transport_get_enclosure_identifier(struct sas_rphy *rphy, u64 *identifier)
{
struct MPT2SAS_ADAPTER *ioc = rphy_to_ioc(rphy);
- struct _sas_node *sas_expander;
+ struct _sas_device *sas_device;
unsigned long flags;
- spin_lock_irqsave(&ioc->sas_node_lock, flags);
- sas_expander = mpt2sas_scsih_expander_find_by_sas_address(ioc,
+ spin_lock_irqsave(&ioc->sas_device_lock, flags);
+ sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
rphy->identify.sas_address);
- spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
+ spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
- if (!sas_expander)
+ if (!sas_device)
return -ENXIO;
- *identifier = sas_expander->enclosure_logical_id;
+ *identifier = sas_device->enclosure_logical_id;
return 0;
}
@@ -1046,32 +1260,260 @@ _transport_get_bay_identifier(struct sas_rphy *rphy)
return sas_device->slot;
}
+/* phy control request structure */
+struct phy_control_request{
+ u8 smp_frame_type; /* 0x40 */
+ u8 function; /* 0x91 */
+ u8 allocated_response_length;
+ u8 request_length; /* 0x09 */
+ u16 expander_change_count;
+ u8 reserved_1[3];
+ u8 phy_identifier;
+ u8 phy_operation;
+ u8 reserved_2[13];
+ u64 attached_device_name;
+ u8 programmed_min_physical_link_rate;
+ u8 programmed_max_physical_link_rate;
+ u8 reserved_3[6];
+};
+
+/* phy control reply structure */
+struct phy_control_reply{
+ u8 smp_frame_type; /* 0x41 */
+ u8 function; /* 0x11 */
+ u8 function_result;
+ u8 response_length;
+};
+
+#define SMP_PHY_CONTROL_LINK_RESET (0x01)
+#define SMP_PHY_CONTROL_HARD_RESET (0x02)
+#define SMP_PHY_CONTROL_DISABLE (0x03)
+
+/**
+ * _transport_expander_phy_control - expander phy control
+ * @ioc: per adapter object
+ * @phy: The sas phy object
+ *
+ * Returns 0 for success, non-zero for failure.
+ *
+ */
+static int
+_transport_expander_phy_control(struct MPT2SAS_ADAPTER *ioc,
+ struct sas_phy *phy, u8 phy_operation)
+{
+ Mpi2SmpPassthroughRequest_t *mpi_request;
+ Mpi2SmpPassthroughReply_t *mpi_reply;
+ struct phy_control_request *phy_control_request;
+ struct phy_control_reply *phy_control_reply;
+ int rc;
+ u16 smid;
+ u32 ioc_state;
+ unsigned long timeleft;
+ void *psge;
+ u32 sgl_flags;
+ u8 issue_reset = 0;
+ void *data_out = NULL;
+ dma_addr_t data_out_dma;
+ u32 sz;
+ u64 *sas_address_le;
+ u16 wait_state_count;
+
+ if (ioc->shost_recovery) {
+ printk(MPT2SAS_INFO_FMT "%s: host reset in progress!\n",
+ __func__, ioc->name);
+ return -EFAULT;
+ }
+
+ mutex_lock(&ioc->transport_cmds.mutex);
+
+ if (ioc->transport_cmds.status != MPT2_CMD_NOT_USED) {
+ printk(MPT2SAS_ERR_FMT "%s: transport_cmds in use\n",
+ ioc->name, __func__);
+ rc = -EAGAIN;
+ goto out;
+ }
+ ioc->transport_cmds.status = MPT2_CMD_PENDING;
+
+ wait_state_count = 0;
+ ioc_state = mpt2sas_base_get_iocstate(ioc, 1);
+ while (ioc_state != MPI2_IOC_STATE_OPERATIONAL) {
+ if (wait_state_count++ == 10) {
+ printk(MPT2SAS_ERR_FMT
+ "%s: failed due to ioc not operational\n",
+ ioc->name, __func__);
+ rc = -EFAULT;
+ goto out;
+ }
+ ssleep(1);
+ ioc_state = mpt2sas_base_get_iocstate(ioc, 1);
+ printk(MPT2SAS_INFO_FMT "%s: waiting for "
+ "operational state(count=%d)\n", ioc->name,
+ __func__, wait_state_count);
+ }
+ if (wait_state_count)
+ printk(MPT2SAS_INFO_FMT "%s: ioc is operational\n",
+ ioc->name, __func__);
+
+ smid = mpt2sas_base_get_smid(ioc, ioc->transport_cb_idx);
+ if (!smid) {
+ printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n",
+ ioc->name, __func__);
+ rc = -EAGAIN;
+ goto out;
+ }
+
+ mpi_request = mpt2sas_base_get_msg_frame(ioc, smid);
+ ioc->transport_cmds.smid = smid;
+
+ sz = sizeof(struct phy_control_request) +
+ sizeof(struct phy_control_reply);
+ data_out = pci_alloc_consistent(ioc->pdev, sz, &data_out_dma);
+ if (!data_out) {
+ printk(KERN_ERR "failure at %s:%d/%s()!\n", __FILE__,
+ __LINE__, __func__);
+ rc = -ENOMEM;
+ mpt2sas_base_free_smid(ioc, smid);
+ goto out;
+ }
+
+ rc = -EINVAL;
+ memset(data_out, 0, sz);
+ phy_control_request = data_out;
+ phy_control_request->smp_frame_type = 0x40;
+ phy_control_request->function = 0x91;
+ phy_control_request->request_length = 9;
+ phy_control_request->allocated_response_length = 0;
+ phy_control_request->phy_identifier = phy->number;
+ phy_control_request->phy_operation = phy_operation;
+ phy_control_request->programmed_min_physical_link_rate =
+ phy->minimum_linkrate << 4;
+ phy_control_request->programmed_max_physical_link_rate =
+ phy->maximum_linkrate << 4;
+
+ memset(mpi_request, 0, sizeof(Mpi2SmpPassthroughRequest_t));
+ mpi_request->Function = MPI2_FUNCTION_SMP_PASSTHROUGH;
+ mpi_request->PhysicalPort = 0xFF;
+ mpi_request->VF_ID = 0; /* TODO */
+ mpi_request->VP_ID = 0;
+ sas_address_le = (u64 *)&mpi_request->SASAddress;
+ *sas_address_le = cpu_to_le64(phy->identify.sas_address);
+ mpi_request->RequestDataLength =
+ cpu_to_le16(sizeof(struct phy_error_log_request));
+ psge = &mpi_request->SGL;
+
+ /* WRITE sgel first */
+ sgl_flags = (MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
+ MPI2_SGE_FLAGS_END_OF_BUFFER | MPI2_SGE_FLAGS_HOST_TO_IOC);
+ sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT;
+ ioc->base_add_sg_single(psge, sgl_flags |
+ sizeof(struct phy_control_request), data_out_dma);
+
+ /* incr sgel */
+ psge += ioc->sge_size;
+
+ /* READ sgel last */
+ sgl_flags = (MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
+ MPI2_SGE_FLAGS_LAST_ELEMENT | MPI2_SGE_FLAGS_END_OF_BUFFER |
+ MPI2_SGE_FLAGS_END_OF_LIST);
+ sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT;
+ ioc->base_add_sg_single(psge, sgl_flags |
+ sizeof(struct phy_control_reply), data_out_dma +
+ sizeof(struct phy_control_request));
+
+ dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT "phy_control - "
+ "send to sas_addr(0x%016llx), phy(%d), opcode(%d)\n", ioc->name,
+ (unsigned long long)phy->identify.sas_address, phy->number,
+ phy_operation));
+ mpt2sas_base_put_smid_default(ioc, smid);
+ init_completion(&ioc->transport_cmds.done);
+ timeleft = wait_for_completion_timeout(&ioc->transport_cmds.done,
+ 10*HZ);
+
+ if (!(ioc->transport_cmds.status & MPT2_CMD_COMPLETE)) {
+ printk(MPT2SAS_ERR_FMT "%s: timeout\n",
+ ioc->name, __func__);
+ _debug_dump_mf(mpi_request,
+ sizeof(Mpi2SmpPassthroughRequest_t)/4);
+ if (!(ioc->transport_cmds.status & MPT2_CMD_RESET))
+ issue_reset = 1;
+ goto issue_host_reset;
+ }
+
+ dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT "phy_control - "
+ "complete\n", ioc->name));
+
+ if (ioc->transport_cmds.status & MPT2_CMD_REPLY_VALID) {
+
+ mpi_reply = ioc->transport_cmds.reply;
+
+ dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT
+ "phy_control - reply data transfer size(%d)\n",
+ ioc->name, le16_to_cpu(mpi_reply->ResponseDataLength)));
+
+ if (le16_to_cpu(mpi_reply->ResponseDataLength) !=
+ sizeof(struct phy_control_reply))
+ goto out;
+
+ phy_control_reply = data_out +
+ sizeof(struct phy_control_request);
+
+ dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT
+ "phy_control - function_result(%d)\n",
+ ioc->name, phy_control_reply->function_result));
+
+ rc = 0;
+ } else
+ dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT
+ "phy_control - no reply\n", ioc->name));
+
+ issue_host_reset:
+ if (issue_reset)
+ mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP,
+ FORCE_BIG_HAMMER);
+ out:
+ ioc->transport_cmds.status = MPT2_CMD_NOT_USED;
+ if (data_out)
+ pci_free_consistent(ioc->pdev, sz, data_out, data_out_dma);
+
+ mutex_unlock(&ioc->transport_cmds.mutex);
+ return rc;
+}
+
/**
* _transport_phy_reset -
* @phy: The sas phy object
* @hard_reset:
*
- * Only support sas_host direct attached phys.
* Returns 0 for success, non-zero for failure.
*/
static int
_transport_phy_reset(struct sas_phy *phy, int hard_reset)
{
struct MPT2SAS_ADAPTER *ioc = phy_to_ioc(phy);
- struct _sas_phy *mpt2sas_phy;
Mpi2SasIoUnitControlReply_t mpi_reply;
Mpi2SasIoUnitControlRequest_t mpi_request;
+ unsigned long flags;
- mpt2sas_phy = _transport_find_local_phy(ioc, phy);
-
- if (!mpt2sas_phy) /* this phy not on sas_host */
+ spin_lock_irqsave(&ioc->sas_node_lock, flags);
+ if (_transport_sas_node_find_by_sas_address(ioc,
+ phy->identify.sas_address) == NULL) {
+ spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
return -EINVAL;
+ }
+ spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
+
+ /* handle expander phys */
+ if (phy->identify.sas_address != ioc->sas_hba.sas_address)
+ return _transport_expander_phy_control(ioc, phy,
+ (hard_reset == 1) ? SMP_PHY_CONTROL_HARD_RESET :
+ SMP_PHY_CONTROL_LINK_RESET);
+ /* handle hba phys */
memset(&mpi_request, 0, sizeof(Mpi2SasIoUnitControlReply_t));
mpi_request.Function = MPI2_FUNCTION_SAS_IO_UNIT_CONTROL;
mpi_request.Operation = hard_reset ?
MPI2_SAS_OP_PHY_HARD_RESET : MPI2_SAS_OP_PHY_LINK_RESET;
- mpi_request.PhyNum = mpt2sas_phy->phy_id;
+ mpi_request.PhyNum = phy->number;
if ((mpt2sas_base_sas_iounit_control(ioc, &mpi_reply, &mpi_request))) {
printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
@@ -1082,8 +1524,7 @@ _transport_phy_reset(struct sas_phy *phy, int hard_reset)
if (mpi_reply.IOCStatus || mpi_reply.IOCLogInfo)
printk(MPT2SAS_INFO_FMT "phy(%d), ioc_status"
"(0x%04x), loginfo(0x%08x)\n", ioc->name,
- mpt2sas_phy->phy_id,
- le16_to_cpu(mpi_reply.IOCStatus),
+ phy->number, le16_to_cpu(mpi_reply.IOCStatus),
le32_to_cpu(mpi_reply.IOCLogInfo));
return 0;
@@ -1101,17 +1542,28 @@ static int
_transport_phy_enable(struct sas_phy *phy, int enable)
{
struct MPT2SAS_ADAPTER *ioc = phy_to_ioc(phy);
- struct _sas_phy *mpt2sas_phy;
Mpi2SasIOUnitPage1_t *sas_iounit_pg1 = NULL;
Mpi2ConfigReply_t mpi_reply;
u16 ioc_status;
u16 sz;
int rc = 0;
+ unsigned long flags;
- mpt2sas_phy = _transport_find_local_phy(ioc, phy);
-
- if (!mpt2sas_phy) /* this phy not on sas_host */
+ spin_lock_irqsave(&ioc->sas_node_lock, flags);
+ if (_transport_sas_node_find_by_sas_address(ioc,
+ phy->identify.sas_address) == NULL) {
+ spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
return -EINVAL;
+ }
+ spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
+
+ /* handle expander phys */
+ if (phy->identify.sas_address != ioc->sas_hba.sas_address)
+ return _transport_expander_phy_control(ioc, phy,
+ (enable == 1) ? SMP_PHY_CONTROL_LINK_RESET :
+ SMP_PHY_CONTROL_DISABLE);
+
+ /* handle hba phys */
/* sas_iounit page 1 */
sz = offsetof(Mpi2SasIOUnitPage1_t, PhyData) + (ioc->sas_hba.num_phys *
@@ -1140,14 +1592,18 @@ _transport_phy_enable(struct sas_phy *phy, int enable)
}
if (enable)
- sas_iounit_pg1->PhyData[mpt2sas_phy->phy_id].PhyFlags
+ sas_iounit_pg1->PhyData[phy->number].PhyFlags
&= ~MPI2_SASIOUNIT1_PHYFLAGS_PHY_DISABLE;
else
- sas_iounit_pg1->PhyData[mpt2sas_phy->phy_id].PhyFlags
+ sas_iounit_pg1->PhyData[phy->number].PhyFlags
|= MPI2_SASIOUNIT1_PHYFLAGS_PHY_DISABLE;
mpt2sas_config_set_sas_iounit_pg1(ioc, &mpi_reply, sas_iounit_pg1, sz);
+ /* link reset */
+ if (enable)
+ _transport_phy_reset(phy, 0);
+
out:
kfree(sas_iounit_pg1);
return rc;
@@ -1165,7 +1621,6 @@ static int
_transport_phy_speed(struct sas_phy *phy, struct sas_phy_linkrates *rates)
{
struct MPT2SAS_ADAPTER *ioc = phy_to_ioc(phy);
- struct _sas_phy *mpt2sas_phy;
Mpi2SasIOUnitPage1_t *sas_iounit_pg1 = NULL;
Mpi2SasPhyPage0_t phy_pg0;
Mpi2ConfigReply_t mpi_reply;
@@ -1173,11 +1628,15 @@ _transport_phy_speed(struct sas_phy *phy, struct sas_phy_linkrates *rates)
u16 sz;
int i;
int rc = 0;
+ unsigned long flags;
- mpt2sas_phy = _transport_find_local_phy(ioc, phy);
-
- if (!mpt2sas_phy) /* this phy not on sas_host */
+ spin_lock_irqsave(&ioc->sas_node_lock, flags);
+ if (_transport_sas_node_find_by_sas_address(ioc,
+ phy->identify.sas_address) == NULL) {
+ spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
return -EINVAL;
+ }
+ spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
if (!rates->minimum_linkrate)
rates->minimum_linkrate = phy->minimum_linkrate;
@@ -1189,6 +1648,16 @@ _transport_phy_speed(struct sas_phy *phy, struct sas_phy_linkrates *rates)
else if (rates->maximum_linkrate > phy->maximum_linkrate_hw)
rates->maximum_linkrate = phy->maximum_linkrate_hw;
+ /* handle expander phys */
+ if (phy->identify.sas_address != ioc->sas_hba.sas_address) {
+ phy->minimum_linkrate = rates->minimum_linkrate;
+ phy->maximum_linkrate = rates->maximum_linkrate;
+ return _transport_expander_phy_control(ioc, phy,
+ SMP_PHY_CONTROL_LINK_RESET);
+ }
+
+ /* handle hba phys */
+
/* sas_iounit page 1 */
sz = offsetof(Mpi2SasIOUnitPage1_t, PhyData) + (ioc->sas_hba.num_phys *
sizeof(Mpi2SasIOUnit1PhyData_t));
@@ -1216,7 +1685,7 @@ _transport_phy_speed(struct sas_phy *phy, struct sas_phy_linkrates *rates)
}
for (i = 0; i < ioc->sas_hba.num_phys; i++) {
- if (mpt2sas_phy->phy_id != i) {
+ if (phy->number != i) {
sas_iounit_pg1->PhyData[i].MaxMinLinkRate =
(ioc->sas_hba.phy[i].phy->minimum_linkrate +
(ioc->sas_hba.phy[i].phy->maximum_linkrate << 4));
@@ -1240,7 +1709,7 @@ _transport_phy_speed(struct sas_phy *phy, struct sas_phy_linkrates *rates)
/* read phy page 0, then update the rates in the sas transport phy */
if (!mpt2sas_config_get_phy_pg0(ioc, &mpi_reply, &phy_pg0,
- mpt2sas_phy->phy_id)) {
+ phy->number)) {
phy->minimum_linkrate = _transport_convert_phy_link_rate(
phy_pg0.ProgrammedLinkRate & MPI2_SAS_PRATE_MIN_RATE_MASK);
phy->maximum_linkrate = _transport_convert_phy_link_rate(
@@ -1392,7 +1861,7 @@ _transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
ioc->base_add_sg_single(psge, sgl_flags | (blk_rq_bytes(rsp) + 4),
dma_addr_in);
- dtransportprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s - "
+ dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT "%s - "
"sending smp request\n", ioc->name, __func__));
mpt2sas_base_put_smid_default(ioc, smid);
@@ -1410,14 +1879,14 @@ _transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
goto issue_host_reset;
}
- dtransportprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s - "
+ dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT "%s - "
"complete\n", ioc->name, __func__));
if (ioc->transport_cmds.status & MPT2_CMD_REPLY_VALID) {
mpi_reply = ioc->transport_cmds.reply;
- dtransportprintk(ioc, printk(MPT2SAS_DEBUG_FMT
+ dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT
"%s - reply data transfer size(%d)\n",
ioc->name, __func__,
le16_to_cpu(mpi_reply->ResponseDataLength)));
@@ -1428,7 +1897,7 @@ _transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
rsp->resid_len -=
le16_to_cpu(mpi_reply->ResponseDataLength);
} else {
- dtransportprintk(ioc, printk(MPT2SAS_DEBUG_FMT
+ dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT
"%s - no reply\n", ioc->name, __func__));
rc = -ENXIO;
}
diff --git a/drivers/scsi/mvsas/mv_sas.c b/drivers/scsi/mvsas/mv_sas.c
index f5e32179190..adedaa916ec 100644
--- a/drivers/scsi/mvsas/mv_sas.c
+++ b/drivers/scsi/mvsas/mv_sas.c
@@ -1483,7 +1483,7 @@ static int mvs_exec_internal_tmf_task(struct domain_device *dev,
}
if (task->task_status.resp == SAS_TASK_COMPLETE &&
- task->task_status.stat == SAM_GOOD) {
+ task->task_status.stat == SAM_STAT_GOOD) {
res = TMF_RESP_FUNC_COMPLETE;
break;
}
@@ -1640,7 +1640,7 @@ int mvs_abort_task(struct sas_task *task)
struct mvs_tmf_task tmf_task;
struct domain_device *dev = task->dev;
struct mvs_device *mvi_dev = (struct mvs_device *)dev->lldd_dev;
- struct mvs_info *mvi = mvi_dev->mvi_info;
+ struct mvs_info *mvi;
int rc = TMF_RESP_FUNC_FAILED;
unsigned long flags;
u32 tag;
@@ -1650,6 +1650,8 @@ int mvs_abort_task(struct sas_task *task)
rc = TMF_RESP_FUNC_FAILED;
}
+ mvi = mvi_dev->mvi_info;
+
spin_lock_irqsave(&task->task_state_lock, flags);
if (task->task_state_flags & SAS_TASK_STATE_DONE) {
spin_unlock_irqrestore(&task->task_state_lock, flags);
@@ -1756,7 +1758,7 @@ static int mvs_sata_done(struct mvs_info *mvi, struct sas_task *task,
struct mvs_device *mvi_dev = task->dev->lldd_dev;
struct task_status_struct *tstat = &task->task_status;
struct ata_task_resp *resp = (struct ata_task_resp *)tstat->buf;
- int stat = SAM_GOOD;
+ int stat = SAM_STAT_GOOD;
resp->frame_len = sizeof(struct dev_to_host_fis);
@@ -1788,13 +1790,13 @@ static int mvs_slot_err(struct mvs_info *mvi, struct sas_task *task,
MVS_CHIP_DISP->command_active(mvi, slot_idx);
- stat = SAM_CHECK_COND;
+ stat = SAM_STAT_CHECK_CONDITION;
switch (task->task_proto) {
case SAS_PROTOCOL_SSP:
stat = SAS_ABORTED_TASK;
break;
case SAS_PROTOCOL_SMP:
- stat = SAM_CHECK_COND;
+ stat = SAM_STAT_CHECK_CONDITION;
break;
case SAS_PROTOCOL_SATA:
@@ -1879,7 +1881,7 @@ int mvs_slot_complete(struct mvs_info *mvi, u32 rx_desc, u32 flags)
case SAS_PROTOCOL_SSP:
/* hw says status == 0, datapres == 0 */
if (rx_desc & RXQ_GOOD) {
- tstat->stat = SAM_GOOD;
+ tstat->stat = SAM_STAT_GOOD;
tstat->resp = SAS_TASK_COMPLETE;
}
/* response frame present */
@@ -1888,12 +1890,12 @@ int mvs_slot_complete(struct mvs_info *mvi, u32 rx_desc, u32 flags)
sizeof(struct mvs_err_info);
sas_ssp_task_response(mvi->dev, task, iu);
} else
- tstat->stat = SAM_CHECK_COND;
+ tstat->stat = SAM_STAT_CHECK_CONDITION;
break;
case SAS_PROTOCOL_SMP: {
struct scatterlist *sg_resp = &task->smp_task.smp_resp;
- tstat->stat = SAM_GOOD;
+ tstat->stat = SAM_STAT_GOOD;
to = kmap_atomic(sg_page(sg_resp), KM_IRQ0);
memcpy(to + sg_resp->offset,
slot->response + sizeof(struct mvs_err_info),
@@ -1910,7 +1912,7 @@ int mvs_slot_complete(struct mvs_info *mvi, u32 rx_desc, u32 flags)
}
default:
- tstat->stat = SAM_CHECK_COND;
+ tstat->stat = SAM_STAT_CHECK_CONDITION;
break;
}
if (!slot->port->port_attached) {
diff --git a/drivers/scsi/pcmcia/aha152x_stub.c b/drivers/scsi/pcmcia/aha152x_stub.c
index 9d70aef9922..61f49bdcc0c 100644
--- a/drivers/scsi/pcmcia/aha152x_stub.c
+++ b/drivers/scsi/pcmcia/aha152x_stub.c
@@ -49,7 +49,6 @@
#include <scsi/scsi_host.h>
#include "aha152x.h"
-#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/cistpl.h>
#include <pcmcia/ds.h>
@@ -101,9 +100,8 @@ static int aha152x_probe(struct pcmcia_device *link)
info->p_dev = link;
link->priv = info;
- link->io.NumPorts1 = 0x20;
- link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
- link->io.IOAddrLines = 10;
+ link->resource[0]->end = 0x20;
+ link->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO;
link->conf.Attributes = CONF_ENABLE_IRQ;
link->conf.IntType = INT_MEMORY_AND_IO;
link->conf.Present = PRESENT_OPTION;
@@ -131,15 +129,16 @@ static int aha152x_config_check(struct pcmcia_device *p_dev,
unsigned int vcc,
void *priv_data)
{
+ p_dev->io_lines = 10;
/* For New Media T&J, look for a SCSI window */
if (cfg->io.win[0].len >= 0x20)
- p_dev->io.BasePort1 = cfg->io.win[0].base;
+ p_dev->resource[0]->start = cfg->io.win[0].base;
else if ((cfg->io.nwin > 1) &&
(cfg->io.win[1].len >= 0x20))
- p_dev->io.BasePort1 = cfg->io.win[1].base;
+ p_dev->resource[0]->start = cfg->io.win[1].base;
if ((cfg->io.nwin > 0) &&
- (p_dev->io.BasePort1 < 0xffff)) {
- if (!pcmcia_request_io(p_dev, &p_dev->io))
+ (p_dev->resource[0]->start < 0xffff)) {
+ if (!pcmcia_request_io(p_dev))
return 0;
}
return -EINVAL;
@@ -168,7 +167,7 @@ static int aha152x_config_cs(struct pcmcia_device *link)
/* Set configuration options for the aha152x driver */
memset(&s, 0, sizeof(s));
s.conf = "PCMCIA setup";
- s.io_port = link->io.BasePort1;
+ s.io_port = link->resource[0]->start;
s.irq = link->irq;
s.scsiid = host_id;
s.reconnect = reconnect;
diff --git a/drivers/scsi/pcmcia/fdomain_stub.c b/drivers/scsi/pcmcia/fdomain_stub.c
index 21b141151df..13dbe5c4849 100644
--- a/drivers/scsi/pcmcia/fdomain_stub.c
+++ b/drivers/scsi/pcmcia/fdomain_stub.c
@@ -46,7 +46,6 @@
#include <scsi/scsi_host.h>
#include "fdomain.h"
-#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/cistpl.h>
#include <pcmcia/ds.h>
@@ -84,9 +83,8 @@ static int fdomain_probe(struct pcmcia_device *link)
info->p_dev = link;
link->priv = info;
- link->io.NumPorts1 = 0x10;
- link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
- link->io.IOAddrLines = 10;
+ link->resource[0]->end = 0x10;
+ link->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO;
link->conf.Attributes = CONF_ENABLE_IRQ;
link->conf.IntType = INT_MEMORY_AND_IO;
link->conf.Present = PRESENT_OPTION;
@@ -113,8 +111,9 @@ static int fdomain_config_check(struct pcmcia_device *p_dev,
unsigned int vcc,
void *priv_data)
{
- p_dev->io.BasePort1 = cfg->io.win[0].base;
- return pcmcia_request_io(p_dev, &p_dev->io);
+ p_dev->io_lines = 10;
+ p_dev->resource[0]->start = cfg->io.win[0].base;
+ return pcmcia_request_io(p_dev);
}
@@ -138,10 +137,10 @@ static int fdomain_config(struct pcmcia_device *link)
goto failed;
/* A bad hack... */
- release_region(link->io.BasePort1, link->io.NumPorts1);
+ release_region(link->resource[0]->start, resource_size(link->resource[0]));
/* Set configuration options for the fdomain driver */
- sprintf(str, "%d,%d", link->io.BasePort1, link->irq);
+ sprintf(str, "%d,%d", (unsigned int) link->resource[0]->start, link->irq);
fdomain_setup(str);
host = __fdomain_16x0_detect(&fdomain_driver_template);
diff --git a/drivers/scsi/pcmcia/nsp_cs.c b/drivers/scsi/pcmcia/nsp_cs.c
index 0f0e112c3f8..dd9b40306f3 100644
--- a/drivers/scsi/pcmcia/nsp_cs.c
+++ b/drivers/scsi/pcmcia/nsp_cs.c
@@ -47,7 +47,6 @@
#include <scsi/scsi.h>
#include <scsi/scsi_ioctl.h>
-#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/cistpl.h>
#include <pcmcia/cisreg.h>
@@ -1559,9 +1558,8 @@ static int nsp_cs_probe(struct pcmcia_device *link)
nsp_dbg(NSP_DEBUG_INIT, "info=0x%p", info);
/* The io structure describes IO port mapping */
- link->io.NumPorts1 = 0x10;
- link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
- link->io.IOAddrLines = 10; /* not used */
+ link->resource[0]->end = 0x10;
+ link->resource[0]->flags = IO_DATA_PATH_WIDTH_AUTO;
/* General socket configuration */
link->conf.Attributes = CONF_ENABLE_IRQ;
@@ -1642,29 +1640,27 @@ static int nsp_cs_config_check(struct pcmcia_device *p_dev,
p_dev->conf.Attributes |= CONF_ENABLE_IRQ;
/* IO window settings */
- p_dev->io.NumPorts1 = p_dev->io.NumPorts2 = 0;
+ p_dev->resource[0]->end = p_dev->resource[1]->end = 0;
if ((cfg->io.nwin > 0) || (dflt->io.nwin > 0)) {
cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt->io;
- p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
- if (!(io->flags & CISTPL_IO_8BIT))
- p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_16;
- if (!(io->flags & CISTPL_IO_16BIT))
- p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
- p_dev->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK;
- p_dev->io.BasePort1 = io->win[0].base;
- p_dev->io.NumPorts1 = io->win[0].len;
+ p_dev->io_lines = io->flags & CISTPL_IO_LINES_MASK;
+ p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH;
+ p_dev->resource[0]->flags |=
+ pcmcia_io_cfg_data_width(io->flags);
+ p_dev->resource[0]->start = io->win[0].base;
+ p_dev->resource[0]->end = io->win[0].len;
if (io->nwin > 1) {
- p_dev->io.Attributes2 = p_dev->io.Attributes1;
- p_dev->io.BasePort2 = io->win[1].base;
- p_dev->io.NumPorts2 = io->win[1].len;
+ p_dev->resource[1]->flags =
+ p_dev->resource[0]->flags;
+ p_dev->resource[1]->start = io->win[1].base;
+ p_dev->resource[1]->end = io->win[1].len;
}
/* This reserves IO space but doesn't actually enable it */
- if (pcmcia_request_io(p_dev, &p_dev->io) != 0)
+ if (pcmcia_request_io(p_dev) != 0)
goto next_entry;
}
if ((cfg->mem.nwin > 0) || (dflt->mem.nwin > 0)) {
- memreq_t map;
cistpl_mem_t *mem =
(cfg->mem.nwin) ? &cfg->mem : &dflt->mem;
cfg_mem->req.Attributes = WIN_DATA_WIDTH_16|WIN_MEMORY_TYPE_CM;
@@ -1676,8 +1672,8 @@ static int nsp_cs_config_check(struct pcmcia_device *p_dev,
cfg_mem->req.AccessSpeed = 0;
if (pcmcia_request_window(p_dev, &cfg_mem->req, &p_dev->win) != 0)
goto next_entry;
- map.Page = 0; map.CardOffset = mem->win[0].card_addr;
- if (pcmcia_map_mem_page(p_dev, p_dev->win, &map) != 0)
+ if (pcmcia_map_mem_page(p_dev, p_dev->win,
+ mem->win[0].card_addr) != 0)
goto next_entry;
cfg_mem->data->MmioAddress = (unsigned long) ioremap_nocache(cfg_mem->req.Base, cfg_mem->req.Size);
@@ -1720,17 +1716,19 @@ static int nsp_cs_config(struct pcmcia_device *link)
goto cs_failed;
if (free_ports) {
- if (link->io.BasePort1) {
- release_region(link->io.BasePort1, link->io.NumPorts1);
+ if (link->resource[0]) {
+ release_region(link->resource[0]->start,
+ resource_size(link->resource[0]));
}
- if (link->io.BasePort2) {
- release_region(link->io.BasePort2, link->io.NumPorts2);
+ if (link->resource[1]) {
+ release_region(link->resource[1]->start,
+ resource_size(link->resource[1]));
}
}
/* Set port and IRQ */
- data->BaseAddress = link->io.BasePort1;
- data->NumAddress = link->io.NumPorts1;
+ data->BaseAddress = link->resource[0]->start;
+ data->NumAddress = resource_size(link->resource[0]);
data->IrqNumber = link->irq;
nsp_dbg(NSP_DEBUG_INIT, "I/O[0x%x+0x%x] IRQ %d",
@@ -1765,13 +1763,10 @@ static int nsp_cs_config(struct pcmcia_device *link)
if (link->conf.Attributes & CONF_ENABLE_IRQ) {
printk(", irq %d", link->irq);
}
- if (link->io.NumPorts1) {
- printk(", io 0x%04x-0x%04x", link->io.BasePort1,
- link->io.BasePort1+link->io.NumPorts1-1);
- }
- if (link->io.NumPorts2)
- printk(" & 0x%04x-0x%04x", link->io.BasePort2,
- link->io.BasePort2+link->io.NumPorts2-1);
+ if (link->resource[0])
+ printk(", io %pR", link->resource[0]);
+ if (link->resource[1])
+ printk(" & %pR", link->resource[1]);
if (link->win)
printk(", mem 0x%06lx-0x%06lx", cfg_mem->req.Base,
cfg_mem->req.Base+cfg_mem->req.Size-1);
diff --git a/drivers/scsi/pcmcia/qlogic_stub.c b/drivers/scsi/pcmcia/qlogic_stub.c
index f0fc6baed9f..eb775f1a523 100644
--- a/drivers/scsi/pcmcia/qlogic_stub.c
+++ b/drivers/scsi/pcmcia/qlogic_stub.c
@@ -48,7 +48,6 @@
#include <scsi/scsi_host.h>
#include "../qlogicfas408.h"
-#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/cistpl.h>
#include <pcmcia/ds.h>
@@ -157,9 +156,8 @@ static int qlogic_probe(struct pcmcia_device *link)
return -ENOMEM;
info->p_dev = link;
link->priv = info;
- link->io.NumPorts1 = 16;
- link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
- link->io.IOAddrLines = 10;
+ link->resource[0]->end = 16;
+ link->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO;
link->conf.Attributes = CONF_ENABLE_IRQ;
link->conf.IntType = INT_MEMORY_AND_IO;
link->conf.Present = PRESENT_OPTION;
@@ -186,13 +184,14 @@ static int qlogic_config_check(struct pcmcia_device *p_dev,
unsigned int vcc,
void *priv_data)
{
- p_dev->io.BasePort1 = cfg->io.win[0].base;
- p_dev->io.NumPorts1 = cfg->io.win[0].len;
+ p_dev->io_lines = 10;
+ p_dev->resource[0]->start = cfg->io.win[0].base;
+ p_dev->resource[0]->end = cfg->io.win[0].len;
- if (p_dev->io.BasePort1 == 0)
+ if (p_dev->resource[0]->start == 0)
return -ENODEV;
- return pcmcia_request_io(p_dev, &p_dev->io);
+ return pcmcia_request_io(p_dev);
}
static int qlogic_config(struct pcmcia_device * link)
@@ -216,18 +215,18 @@ static int qlogic_config(struct pcmcia_device * link)
if ((info->manf_id == MANFID_MACNICA) || (info->manf_id == MANFID_PIONEER) || (info->manf_id == 0x0098)) {
/* set ATAcmd */
- outb(0xb4, link->io.BasePort1 + 0xd);
- outb(0x24, link->io.BasePort1 + 0x9);
- outb(0x04, link->io.BasePort1 + 0xd);
+ outb(0xb4, link->resource[0]->start + 0xd);
+ outb(0x24, link->resource[0]->start + 0x9);
+ outb(0x04, link->resource[0]->start + 0xd);
}
/* The KXL-810AN has a bigger IO port window */
- if (link->io.NumPorts1 == 32)
+ if (resource_size(link->resource[0]) == 32)
host = qlogic_detect(&qlogicfas_driver_template, link,
- link->io.BasePort1 + 16, link->irq);
+ link->resource[0]->start + 16, link->irq);
else
host = qlogic_detect(&qlogicfas_driver_template, link,
- link->io.BasePort1, link->irq);
+ link->resource[0]->start, link->irq);
if (!host) {
printk(KERN_INFO "%s: no SCSI devices found\n", qlogic_name);
@@ -269,9 +268,9 @@ static int qlogic_resume(struct pcmcia_device *link)
if ((info->manf_id == MANFID_MACNICA) ||
(info->manf_id == MANFID_PIONEER) ||
(info->manf_id == 0x0098)) {
- outb(0x80, link->io.BasePort1 + 0xd);
- outb(0x24, link->io.BasePort1 + 0x9);
- outb(0x04, link->io.BasePort1 + 0xd);
+ outb(0x80, link->resource[0]->start + 0xd);
+ outb(0x24, link->resource[0]->start + 0x9);
+ outb(0x04, link->resource[0]->start + 0xd);
}
/* Ugggglllyyyy!!! */
qlogicfas408_bus_reset(NULL);
diff --git a/drivers/scsi/pcmcia/sym53c500_cs.c b/drivers/scsi/pcmcia/sym53c500_cs.c
index a5116417117..321e390c912 100644
--- a/drivers/scsi/pcmcia/sym53c500_cs.c
+++ b/drivers/scsi/pcmcia/sym53c500_cs.c
@@ -71,7 +71,6 @@
#include <scsi/scsi.h>
#include <scsi/scsi_host.h>
-#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/cistpl.h>
#include <pcmcia/ds.h>
@@ -691,13 +690,14 @@ static int SYM53C500_config_check(struct pcmcia_device *p_dev,
unsigned int vcc,
void *priv_data)
{
- p_dev->io.BasePort1 = cfg->io.win[0].base;
- p_dev->io.NumPorts1 = cfg->io.win[0].len;
+ p_dev->io_lines = 10;
+ p_dev->resource[0]->start = cfg->io.win[0].base;
+ p_dev->resource[0]->end = cfg->io.win[0].len;
- if (p_dev->io.BasePort1 == 0)
+ if (p_dev->resource[0]->start == 0)
return -ENODEV;
- return pcmcia_request_io(p_dev, &p_dev->io);
+ return pcmcia_request_io(p_dev);
}
static int
@@ -734,9 +734,9 @@ SYM53C500_config(struct pcmcia_device *link)
(info->manf_id == MANFID_PIONEER) ||
(info->manf_id == 0x0098)) {
/* set ATAcmd */
- outb(0xb4, link->io.BasePort1 + 0xd);
- outb(0x24, link->io.BasePort1 + 0x9);
- outb(0x04, link->io.BasePort1 + 0xd);
+ outb(0xb4, link->resource[0]->start + 0xd);
+ outb(0x24, link->resource[0]->start + 0x9);
+ outb(0x04, link->resource[0]->start + 0xd);
}
/*
@@ -749,7 +749,7 @@ SYM53C500_config(struct pcmcia_device *link)
* 0x130, 0x230, 0x280, 0x290,
* 0x320, 0x330, 0x340, 0x350
*/
- port_base = link->io.BasePort1;
+ port_base = link->resource[0]->start;
irq_level = link->irq;
DEB(printk("SYM53C500: port_base=0x%x, irq=%d, fast_pio=%d\n",
@@ -822,15 +822,15 @@ static int sym53c500_resume(struct pcmcia_device *link)
if ((info->manf_id == MANFID_MACNICA) ||
(info->manf_id == MANFID_PIONEER) ||
(info->manf_id == 0x0098)) {
- outb(0x80, link->io.BasePort1 + 0xd);
- outb(0x24, link->io.BasePort1 + 0x9);
- outb(0x04, link->io.BasePort1 + 0xd);
+ outb(0x80, link->resource[0]->start + 0xd);
+ outb(0x24, link->resource[0]->start + 0x9);
+ outb(0x04, link->resource[0]->start + 0xd);
}
/*
* If things don't work after a "resume",
* this is a good place to start looking.
*/
- SYM53C500_int_host_reset(link->io.BasePort1);
+ SYM53C500_int_host_reset(link->resource[0]->start);
return 0;
}
@@ -859,9 +859,8 @@ SYM53C500_probe(struct pcmcia_device *link)
return -ENOMEM;
info->p_dev = link;
link->priv = info;
- link->io.NumPorts1 = 16;
- link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
- link->io.IOAddrLines = 10;
+ link->resource[0]->end = 16;
+ link->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO;
link->conf.Attributes = CONF_ENABLE_IRQ;
link->conf.IntType = INT_MEMORY_AND_IO;
diff --git a/drivers/scsi/pm8001/pm8001_hwi.c b/drivers/scsi/pm8001/pm8001_hwi.c
index 5ff8261c5d6..58d1134935e 100644
--- a/drivers/scsi/pm8001/pm8001_hwi.c
+++ b/drivers/scsi/pm8001/pm8001_hwi.c
@@ -1082,7 +1082,7 @@ static void pm8001_hw_chip_rst(struct pm8001_hba_info *pm8001_ha)
}
/**
- * pm8001_chip_iounmap - which maped when initilized.
+ * pm8001_chip_iounmap - which maped when initialized.
* @pm8001_ha: our hba card information
*/
static void pm8001_chip_iounmap(struct pm8001_hba_info *pm8001_ha)
@@ -1480,7 +1480,7 @@ mpi_ssp_completion(struct pm8001_hba_info *pm8001_ha , void *piomb)
",param = %d \n", param));
if (param == 0) {
ts->resp = SAS_TASK_COMPLETE;
- ts->stat = SAM_GOOD;
+ ts->stat = SAM_STAT_GOOD;
} else {
ts->resp = SAS_TASK_COMPLETE;
ts->stat = SAS_PROTO_RESPONSE;
@@ -1909,7 +1909,7 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
PM8001_IO_DBG(pm8001_ha, pm8001_printk("IO_SUCCESS\n"));
if (param == 0) {
ts->resp = SAS_TASK_COMPLETE;
- ts->stat = SAM_GOOD;
+ ts->stat = SAM_STAT_GOOD;
} else {
u8 len;
ts->resp = SAS_TASK_COMPLETE;
@@ -2450,7 +2450,7 @@ mpi_smp_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
case IO_SUCCESS:
PM8001_IO_DBG(pm8001_ha, pm8001_printk("IO_SUCCESS\n"));
ts->resp = SAS_TASK_COMPLETE;
- ts->stat = SAM_GOOD;
+ ts->stat = SAM_STAT_GOOD;
if (pm8001_dev)
pm8001_dev->running_req--;
break;
@@ -2479,19 +2479,19 @@ mpi_smp_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
PM8001_IO_DBG(pm8001_ha,
pm8001_printk("IO_ERROR_HW_TIMEOUT\n"));
ts->resp = SAS_TASK_COMPLETE;
- ts->stat = SAM_BUSY;
+ ts->stat = SAM_STAT_BUSY;
break;
case IO_XFER_ERROR_BREAK:
PM8001_IO_DBG(pm8001_ha,
pm8001_printk("IO_XFER_ERROR_BREAK\n"));
ts->resp = SAS_TASK_COMPLETE;
- ts->stat = SAM_BUSY;
+ ts->stat = SAM_STAT_BUSY;
break;
case IO_XFER_ERROR_PHY_NOT_READY:
PM8001_IO_DBG(pm8001_ha,
pm8001_printk("IO_XFER_ERROR_PHY_NOT_READY\n"));
ts->resp = SAS_TASK_COMPLETE;
- ts->stat = SAM_BUSY;
+ ts->stat = SAM_STAT_BUSY;
break;
case IO_OPEN_CNX_ERROR_PROTOCOL_NOT_SUPPORTED:
PM8001_IO_DBG(pm8001_ha,
@@ -3260,7 +3260,7 @@ mpi_task_abort_resp(struct pm8001_hba_info *pm8001_ha, void *piomb)
case IO_SUCCESS:
PM8001_EH_DBG(pm8001_ha, pm8001_printk("IO_SUCCESS\n"));
ts->resp = SAS_TASK_COMPLETE;
- ts->stat = SAM_GOOD;
+ ts->stat = SAM_STAT_GOOD;
break;
case IO_NOT_VALID:
PM8001_EH_DBG(pm8001_ha, pm8001_printk("IO_NOT_VALID\n"));
@@ -4152,7 +4152,7 @@ static int pm8001_chip_abort_task(struct pm8001_hba_info *pm8001_ha,
}
/**
- * pm8001_chip_ssp_tm_req - built the task managment command.
+ * pm8001_chip_ssp_tm_req - built the task management command.
* @pm8001_ha: our hba card information.
* @ccb: the ccb information.
* @tmf: task management function.
diff --git a/drivers/scsi/pm8001/pm8001_sas.c b/drivers/scsi/pm8001/pm8001_sas.c
index cd02ceaf67f..6ae059ebb4b 100644
--- a/drivers/scsi/pm8001/pm8001_sas.c
+++ b/drivers/scsi/pm8001/pm8001_sas.c
@@ -763,7 +763,7 @@ static int pm8001_exec_internal_tmf_task(struct domain_device *dev,
}
if (task->task_status.resp == SAS_TASK_COMPLETE &&
- task->task_status.stat == SAM_GOOD) {
+ task->task_status.stat == SAM_STAT_GOOD) {
res = TMF_RESP_FUNC_COMPLETE;
break;
}
@@ -853,7 +853,7 @@ pm8001_exec_internal_task_abort(struct pm8001_hba_info *pm8001_ha,
}
if (task->task_status.resp == SAS_TASK_COMPLETE &&
- task->task_status.stat == SAM_GOOD) {
+ task->task_status.stat == SAM_STAT_GOOD) {
res = TMF_RESP_FUNC_COMPLETE;
break;
diff --git a/drivers/scsi/pmcraid.c b/drivers/scsi/pmcraid.c
index c44e4ab4e93..ecc45c8b4e6 100644
--- a/drivers/scsi/pmcraid.c
+++ b/drivers/scsi/pmcraid.c
@@ -113,6 +113,7 @@ static struct pmcraid_chip_details pmcraid_chip_cfg[] = {
.global_intr_mask = 0x00034,
.ioa_host_intr = 0x0009C,
.ioa_host_intr_clr = 0x000A0,
+ .ioa_host_msix_intr = 0x7FC40,
.ioa_host_mask = 0x7FC28,
.ioa_host_mask_clr = 0x7FC28,
.host_ioa_intr = 0x00020,
@@ -154,8 +155,12 @@ static int pmcraid_slave_alloc(struct scsi_device *scsi_dev)
u8 target, bus, lun;
unsigned long lock_flags;
int rc = -ENXIO;
+ u16 fw_version;
+
pinstance = shost_priv(scsi_dev->host);
+ fw_version = be16_to_cpu(pinstance->inq_data->fw_version);
+
/* Driver exposes VSET and GSCSI resources only; all other device types
* are not exposed. Resource list is synchronized using resource lock
* so any traversal or modifications to the list should be done inside
@@ -166,7 +171,11 @@ static int pmcraid_slave_alloc(struct scsi_device *scsi_dev)
/* do not expose VSETs with order-ids > MAX_VSET_TARGETS */
if (RES_IS_VSET(temp->cfg_entry)) {
- target = temp->cfg_entry.unique_flags1;
+ if (fw_version <= PMCRAID_FW_VERSION_1)
+ target = temp->cfg_entry.unique_flags1;
+ else
+ target = temp->cfg_entry.array_id & 0xFF;
+
if (target > PMCRAID_MAX_VSET_TARGETS)
continue;
bus = PMCRAID_VSET_BUS_ID;
@@ -283,7 +292,7 @@ static void pmcraid_slave_destroy(struct scsi_device *scsi_dev)
* @reason: calling context
*
* Return value
- * actual depth set
+ * actual depth set
*/
static int pmcraid_change_queue_depth(struct scsi_device *scsi_dev, int depth,
int reason)
@@ -305,7 +314,7 @@ static int pmcraid_change_queue_depth(struct scsi_device *scsi_dev, int depth,
* @tag: type of tags to use
*
* Return value:
- * actual queue type set
+ * actual queue type set
*/
static int pmcraid_change_queue_type(struct scsi_device *scsi_dev, int tag)
{
@@ -357,6 +366,7 @@ void pmcraid_init_cmdblk(struct pmcraid_cmd *cmd, int index)
* processed by IOA
*/
memset(&cmd->ioa_cb->ioarcb.cdb, 0, PMCRAID_MAX_CDB_LEN);
+ ioarcb->hrrq_id = 0;
ioarcb->request_flags0 = 0;
ioarcb->request_flags1 = 0;
ioarcb->cmd_timeout = 0;
@@ -368,13 +378,15 @@ void pmcraid_init_cmdblk(struct pmcraid_cmd *cmd, int index)
ioarcb->add_cmd_param_offset = 0;
cmd->ioa_cb->ioasa.ioasc = 0;
cmd->ioa_cb->ioasa.residual_data_length = 0;
- cmd->u.time_left = 0;
+ cmd->time_left = 0;
}
cmd->cmd_done = NULL;
cmd->scsi_cmd = NULL;
cmd->release = 0;
cmd->completion_req = 0;
+ cmd->sense_buffer = 0;
+ cmd->sense_buffer_dma = 0;
cmd->dma_handle = 0;
init_timer(&cmd->timer);
}
@@ -449,7 +461,9 @@ void pmcraid_return_cmd(struct pmcraid_cmd *cmd)
*/
static u32 pmcraid_read_interrupts(struct pmcraid_instance *pinstance)
{
- return ioread32(pinstance->int_regs.ioa_host_interrupt_reg);
+ return (pinstance->interrupt_mode) ?
+ ioread32(pinstance->int_regs.ioa_host_msix_interrupt_reg) :
+ ioread32(pinstance->int_regs.ioa_host_interrupt_reg);
}
/**
@@ -469,10 +483,15 @@ static void pmcraid_disable_interrupts(
u32 gmask = ioread32(pinstance->int_regs.global_interrupt_mask_reg);
u32 nmask = gmask | GLOBAL_INTERRUPT_MASK;
- iowrite32(nmask, pinstance->int_regs.global_interrupt_mask_reg);
iowrite32(intrs, pinstance->int_regs.ioa_host_interrupt_clr_reg);
- iowrite32(intrs, pinstance->int_regs.ioa_host_interrupt_mask_reg);
- ioread32(pinstance->int_regs.ioa_host_interrupt_mask_reg);
+ iowrite32(nmask, pinstance->int_regs.global_interrupt_mask_reg);
+ ioread32(pinstance->int_regs.global_interrupt_mask_reg);
+
+ if (!pinstance->interrupt_mode) {
+ iowrite32(intrs,
+ pinstance->int_regs.ioa_host_interrupt_mask_reg);
+ ioread32(pinstance->int_regs.ioa_host_interrupt_mask_reg);
+ }
}
/**
@@ -493,8 +512,12 @@ static void pmcraid_enable_interrupts(
u32 nmask = gmask & (~GLOBAL_INTERRUPT_MASK);
iowrite32(nmask, pinstance->int_regs.global_interrupt_mask_reg);
- iowrite32(~intrs, pinstance->int_regs.ioa_host_interrupt_mask_reg);
- ioread32(pinstance->int_regs.ioa_host_interrupt_mask_reg);
+
+ if (!pinstance->interrupt_mode) {
+ iowrite32(~intrs,
+ pinstance->int_regs.ioa_host_interrupt_mask_reg);
+ ioread32(pinstance->int_regs.ioa_host_interrupt_mask_reg);
+ }
pmcraid_info("enabled interrupts global mask = %x intr_mask = %x\n",
ioread32(pinstance->int_regs.global_interrupt_mask_reg),
@@ -502,6 +525,39 @@ static void pmcraid_enable_interrupts(
}
/**
+ * pmcraid_clr_trans_op - clear trans to op interrupt
+ *
+ * @pinstance: pointer to per adapter instance structure
+ *
+ * Return Value
+ * None
+ */
+static void pmcraid_clr_trans_op(
+ struct pmcraid_instance *pinstance
+)
+{
+ unsigned long lock_flags;
+
+ if (!pinstance->interrupt_mode) {
+ iowrite32(INTRS_TRANSITION_TO_OPERATIONAL,
+ pinstance->int_regs.ioa_host_interrupt_mask_reg);
+ ioread32(pinstance->int_regs.ioa_host_interrupt_mask_reg);
+ iowrite32(INTRS_TRANSITION_TO_OPERATIONAL,
+ pinstance->int_regs.ioa_host_interrupt_clr_reg);
+ ioread32(pinstance->int_regs.ioa_host_interrupt_clr_reg);
+ }
+
+ if (pinstance->reset_cmd != NULL) {
+ del_timer(&pinstance->reset_cmd->timer);
+ spin_lock_irqsave(
+ pinstance->host->host_lock, lock_flags);
+ pinstance->reset_cmd->cmd_done(pinstance->reset_cmd);
+ spin_unlock_irqrestore(
+ pinstance->host->host_lock, lock_flags);
+ }
+}
+
+/**
* pmcraid_reset_type - Determine the required reset type
* @pinstance: pointer to adapter instance structure
*
@@ -536,7 +592,7 @@ static void pmcraid_reset_type(struct pmcraid_instance *pinstance)
* pmcraid_bist_done - completion function for PCI BIST
* @cmd: pointer to reset command
* Return Value
- * none
+ * none
*/
static void pmcraid_ioa_reset(struct pmcraid_cmd *);
@@ -552,16 +608,16 @@ static void pmcraid_bist_done(struct pmcraid_cmd *cmd)
/* If PCI config space can't be accessed wait for another two secs */
if ((rc != PCIBIOS_SUCCESSFUL || (!(pci_reg & PCI_COMMAND_MEMORY))) &&
- cmd->u.time_left > 0) {
+ cmd->time_left > 0) {
pmcraid_info("BIST not complete, waiting another 2 secs\n");
- cmd->timer.expires = jiffies + cmd->u.time_left;
- cmd->u.time_left = 0;
+ cmd->timer.expires = jiffies + cmd->time_left;
+ cmd->time_left = 0;
cmd->timer.data = (unsigned long)cmd;
cmd->timer.function =
(void (*)(unsigned long))pmcraid_bist_done;
add_timer(&cmd->timer);
} else {
- cmd->u.time_left = 0;
+ cmd->time_left = 0;
pmcraid_info("BIST is complete, proceeding with reset\n");
spin_lock_irqsave(pinstance->host->host_lock, lock_flags);
pmcraid_ioa_reset(cmd);
@@ -585,10 +641,10 @@ static void pmcraid_start_bist(struct pmcraid_cmd *cmd)
pinstance->int_regs.host_ioa_interrupt_reg);
doorbells = ioread32(pinstance->int_regs.host_ioa_interrupt_reg);
intrs = ioread32(pinstance->int_regs.ioa_host_interrupt_reg);
- pmcraid_info("doorbells after start bist: %x intrs: %x \n",
+ pmcraid_info("doorbells after start bist: %x intrs: %x\n",
doorbells, intrs);
- cmd->u.time_left = msecs_to_jiffies(PMCRAID_BIST_TIMEOUT);
+ cmd->time_left = msecs_to_jiffies(PMCRAID_BIST_TIMEOUT);
cmd->timer.data = (unsigned long)cmd;
cmd->timer.expires = jiffies + msecs_to_jiffies(PMCRAID_BIST_TIMEOUT);
cmd->timer.function = (void (*)(unsigned long))pmcraid_bist_done;
@@ -612,7 +668,7 @@ static void pmcraid_reset_alert_done(struct pmcraid_cmd *cmd)
* some more time to wait, restart the timer
*/
if (((status & INTRS_CRITICAL_OP_IN_PROGRESS) == 0) ||
- cmd->u.time_left <= 0) {
+ cmd->time_left <= 0) {
pmcraid_info("critical op is reset proceeding with reset\n");
spin_lock_irqsave(pinstance->host->host_lock, lock_flags);
pmcraid_ioa_reset(cmd);
@@ -620,7 +676,7 @@ static void pmcraid_reset_alert_done(struct pmcraid_cmd *cmd)
} else {
pmcraid_info("critical op is not yet reset waiting again\n");
/* restart timer if some more time is available to wait */
- cmd->u.time_left -= PMCRAID_CHECK_FOR_RESET_TIMEOUT;
+ cmd->time_left -= PMCRAID_CHECK_FOR_RESET_TIMEOUT;
cmd->timer.data = (unsigned long)cmd;
cmd->timer.expires = jiffies + PMCRAID_CHECK_FOR_RESET_TIMEOUT;
cmd->timer.function =
@@ -638,6 +694,7 @@ static void pmcraid_reset_alert_done(struct pmcraid_cmd *cmd)
* successfully written to IOA. Returns non-zero in case pci_config_space
* is not accessible
*/
+static void pmcraid_notify_ioastate(struct pmcraid_instance *, u32);
static void pmcraid_reset_alert(struct pmcraid_cmd *cmd)
{
struct pmcraid_instance *pinstance = cmd->drv_inst;
@@ -658,7 +715,7 @@ static void pmcraid_reset_alert(struct pmcraid_cmd *cmd)
* OPERATION bit is reset. A timer is started to wait for this
* bit to be reset.
*/
- cmd->u.time_left = PMCRAID_RESET_TIMEOUT;
+ cmd->time_left = PMCRAID_RESET_TIMEOUT;
cmd->timer.data = (unsigned long)cmd;
cmd->timer.expires = jiffies + PMCRAID_CHECK_FOR_RESET_TIMEOUT;
cmd->timer.function =
@@ -693,7 +750,8 @@ static void pmcraid_timeout_handler(struct pmcraid_cmd *cmd)
unsigned long lock_flags;
dev_info(&pinstance->pdev->dev,
- "Adapter being reset due to command timeout.\n");
+ "Adapter being reset due to cmd(CDB[0] = %x) timeout\n",
+ cmd->ioa_cb->ioarcb.cdb[0]);
/* Command timeouts result in hard reset sequence. The command that got
* timed out may be the one used as part of reset sequence. In this
@@ -736,9 +794,14 @@ static void pmcraid_timeout_handler(struct pmcraid_cmd *cmd)
*/
if (cmd == pinstance->reset_cmd)
cmd->cmd_done = pmcraid_ioa_reset;
-
}
+ /* Notify apps of important IOA bringup/bringdown sequences */
+ if (pinstance->scn.ioa_state != PMC_DEVICE_EVENT_RESET_START &&
+ pinstance->scn.ioa_state != PMC_DEVICE_EVENT_SHUTDOWN_START)
+ pmcraid_notify_ioastate(pinstance,
+ PMC_DEVICE_EVENT_RESET_START);
+
pinstance->ioa_state = IOA_STATE_IN_RESET_ALERT;
scsi_block_requests(pinstance->host);
pmcraid_reset_alert(cmd);
@@ -866,7 +929,7 @@ static void _pmcraid_fire_command(struct pmcraid_cmd *cmd)
/* Add this command block to pending cmd pool. We do this prior to
* writting IOARCB to ioarrin because IOA might complete the command
* by the time we are about to add it to the list. Response handler
- * (isr/tasklet) looks for cmb block in the pending pending list.
+ * (isr/tasklet) looks for cmd block in the pending pending list.
*/
spin_lock_irqsave(&pinstance->pending_pool_lock, lock_flags);
list_add_tail(&cmd->free_list, &pinstance->pending_cmd_pool);
@@ -916,6 +979,23 @@ static void pmcraid_send_cmd(
}
/**
+ * pmcraid_ioa_shutdown_done - completion function for IOA shutdown command
+ * @cmd: pointer to the command block used for sending IOA shutdown command
+ *
+ * Return value
+ * None
+ */
+static void pmcraid_ioa_shutdown_done(struct pmcraid_cmd *cmd)
+{
+ struct pmcraid_instance *pinstance = cmd->drv_inst;
+ unsigned long lock_flags;
+
+ spin_lock_irqsave(pinstance->host->host_lock, lock_flags);
+ pmcraid_ioa_reset(cmd);
+ spin_unlock_irqrestore(pinstance->host->host_lock, lock_flags);
+}
+
+/**
* pmcraid_ioa_shutdown - sends SHUTDOWN command to ioa
*
* @cmd: pointer to the command block used as part of reset sequence
@@ -943,30 +1023,112 @@ static void pmcraid_ioa_shutdown(struct pmcraid_cmd *cmd)
pmcraid_info("firing normal shutdown command (%d) to IOA\n",
le32_to_cpu(cmd->ioa_cb->ioarcb.response_handle));
- pmcraid_send_cmd(cmd, pmcraid_ioa_reset,
+ pmcraid_notify_ioastate(cmd->drv_inst, PMC_DEVICE_EVENT_SHUTDOWN_START);
+
+ pmcraid_send_cmd(cmd, pmcraid_ioa_shutdown_done,
PMCRAID_SHUTDOWN_TIMEOUT,
pmcraid_timeout_handler);
}
/**
- * pmcraid_identify_hrrq - registers host rrq buffers with IOA
- * @cmd: pointer to command block to be used for identify hrrq
+ * pmcraid_get_fwversion_done - completion function for get_fwversion
+ *
+ * @cmd: pointer to command block used to send INQUIRY command
*
* Return Value
- * 0 in case of success, otherwise non-zero failure code
+ * none
*/
-
static void pmcraid_querycfg(struct pmcraid_cmd *);
+static void pmcraid_get_fwversion_done(struct pmcraid_cmd *cmd)
+{
+ struct pmcraid_instance *pinstance = cmd->drv_inst;
+ u32 ioasc = le32_to_cpu(cmd->ioa_cb->ioasa.ioasc);
+ unsigned long lock_flags;
+
+ /* configuration table entry size depends on firmware version. If fw
+ * version is not known, it is not possible to interpret IOA config
+ * table
+ */
+ if (ioasc) {
+ pmcraid_err("IOA Inquiry failed with %x\n", ioasc);
+ spin_lock_irqsave(pinstance->host->host_lock, lock_flags);
+ pinstance->ioa_state = IOA_STATE_IN_RESET_ALERT;
+ pmcraid_reset_alert(cmd);
+ spin_unlock_irqrestore(pinstance->host->host_lock, lock_flags);
+ } else {
+ pmcraid_querycfg(cmd);
+ }
+}
+
+/**
+ * pmcraid_get_fwversion - reads firmware version information
+ *
+ * @cmd: pointer to command block used to send INQUIRY command
+ *
+ * Return Value
+ * none
+ */
+static void pmcraid_get_fwversion(struct pmcraid_cmd *cmd)
+{
+ struct pmcraid_ioarcb *ioarcb = &cmd->ioa_cb->ioarcb;
+ struct pmcraid_ioadl_desc *ioadl = ioarcb->add_data.u.ioadl;
+ struct pmcraid_instance *pinstance = cmd->drv_inst;
+ u16 data_size = sizeof(struct pmcraid_inquiry_data);
+
+ pmcraid_reinit_cmdblk(cmd);
+ ioarcb->request_type = REQ_TYPE_SCSI;
+ ioarcb->resource_handle = cpu_to_le32(PMCRAID_IOA_RES_HANDLE);
+ ioarcb->cdb[0] = INQUIRY;
+ ioarcb->cdb[1] = 1;
+ ioarcb->cdb[2] = 0xD0;
+ ioarcb->cdb[3] = (data_size >> 8) & 0xFF;
+ ioarcb->cdb[4] = data_size & 0xFF;
+
+ /* Since entire inquiry data it can be part of IOARCB itself
+ */
+ ioarcb->ioadl_bus_addr = cpu_to_le64((cmd->ioa_cb_bus_addr) +
+ offsetof(struct pmcraid_ioarcb,
+ add_data.u.ioadl[0]));
+ ioarcb->ioadl_length = cpu_to_le32(sizeof(struct pmcraid_ioadl_desc));
+ ioarcb->ioarcb_bus_addr &= ~(0x1FULL);
+
+ ioarcb->request_flags0 |= NO_LINK_DESCS;
+ ioarcb->data_transfer_length = cpu_to_le32(data_size);
+ ioadl = &(ioarcb->add_data.u.ioadl[0]);
+ ioadl->flags = IOADL_FLAGS_LAST_DESC;
+ ioadl->address = cpu_to_le64(pinstance->inq_data_baddr);
+ ioadl->data_len = cpu_to_le32(data_size);
+
+ pmcraid_send_cmd(cmd, pmcraid_get_fwversion_done,
+ PMCRAID_INTERNAL_TIMEOUT, pmcraid_timeout_handler);
+}
+
+/**
+ * pmcraid_identify_hrrq - registers host rrq buffers with IOA
+ * @cmd: pointer to command block to be used for identify hrrq
+ *
+ * Return Value
+ * none
+ */
static void pmcraid_identify_hrrq(struct pmcraid_cmd *cmd)
{
struct pmcraid_instance *pinstance = cmd->drv_inst;
struct pmcraid_ioarcb *ioarcb = &cmd->ioa_cb->ioarcb;
- int index = 0;
+ int index = cmd->hrrq_index;
__be64 hrrq_addr = cpu_to_be64(pinstance->hrrq_start_bus_addr[index]);
u32 hrrq_size = cpu_to_be32(sizeof(u32) * PMCRAID_MAX_CMD);
+ void (*done_function)(struct pmcraid_cmd *);
pmcraid_reinit_cmdblk(cmd);
+ cmd->hrrq_index = index + 1;
+
+ if (cmd->hrrq_index < pinstance->num_hrrq) {
+ done_function = pmcraid_identify_hrrq;
+ } else {
+ cmd->hrrq_index = 0;
+ done_function = pmcraid_get_fwversion;
+ }
/* Initialize ioarcb */
ioarcb->request_type = REQ_TYPE_IOACMD;
@@ -980,8 +1142,8 @@ static void pmcraid_identify_hrrq(struct pmcraid_cmd *cmd)
/* IOA expects 64-bit pci address to be written in B.E format
* (i.e cdb[2]=MSByte..cdb[9]=LSB.
*/
- pmcraid_info("HRRQ_IDENTIFY with hrrq:ioarcb => %llx:%llx\n",
- hrrq_addr, ioarcb->ioarcb_bus_addr);
+ pmcraid_info("HRRQ_IDENTIFY with hrrq:ioarcb:index => %llx:%llx:%x\n",
+ hrrq_addr, ioarcb->ioarcb_bus_addr, index);
memcpy(&(ioarcb->cdb[2]), &hrrq_addr, sizeof(hrrq_addr));
memcpy(&(ioarcb->cdb[10]), &hrrq_size, sizeof(hrrq_size));
@@ -990,7 +1152,7 @@ static void pmcraid_identify_hrrq(struct pmcraid_cmd *cmd)
* Note that this gets called even during reset from SCSI mid-layer
* or tasklet
*/
- pmcraid_send_cmd(cmd, pmcraid_querycfg,
+ pmcraid_send_cmd(cmd, done_function,
PMCRAID_INTERNAL_TIMEOUT,
pmcraid_timeout_handler);
}
@@ -1047,7 +1209,7 @@ static struct pmcraid_cmd *pmcraid_init_hcam
}
if (type == PMCRAID_HCAM_CODE_CONFIG_CHANGE) {
- rcb_size = sizeof(struct pmcraid_hcam_ccn);
+ rcb_size = sizeof(struct pmcraid_hcam_ccn_ext);
cmd_done = pmcraid_process_ccn;
dma = pinstance->ccn.baddr + PMCRAID_AEN_HDR_SIZE;
hcam = &pinstance->ccn;
@@ -1094,7 +1256,7 @@ static struct pmcraid_cmd *pmcraid_init_hcam
* This function will send a Host Controlled Async command to IOA.
*
* Return value:
- * none
+ * none
*/
static void pmcraid_send_hcam(struct pmcraid_instance *pinstance, u8 type)
{
@@ -1202,18 +1364,25 @@ static void pmcraid_cancel_ldn(struct pmcraid_cmd *cmd)
/**
* pmcraid_expose_resource - check if the resource can be exposed to OS
*
+ * @fw_version: firmware version code
* @cfgte: pointer to configuration table entry of the resource
*
* Return value:
- * true if resource can be added to midlayer, false(0) otherwise
+ * true if resource can be added to midlayer, false(0) otherwise
*/
-static int pmcraid_expose_resource(struct pmcraid_config_table_entry *cfgte)
+static int pmcraid_expose_resource(u16 fw_version,
+ struct pmcraid_config_table_entry *cfgte)
{
int retval = 0;
- if (cfgte->resource_type == RES_TYPE_VSET)
- retval = ((cfgte->unique_flags1 & 0x80) == 0);
- else if (cfgte->resource_type == RES_TYPE_GSCSI)
+ if (cfgte->resource_type == RES_TYPE_VSET) {
+ if (fw_version <= PMCRAID_FW_VERSION_1)
+ retval = ((cfgte->unique_flags1 & 0x80) == 0);
+ else
+ retval = ((cfgte->unique_flags0 & 0x80) == 0 &&
+ (cfgte->unique_flags1 & 0x80) == 0);
+
+ } else if (cfgte->resource_type == RES_TYPE_GSCSI)
retval = (RES_BUS(cfgte->resource_address) !=
PMCRAID_VIRTUAL_ENCL_BUS_ID);
return retval;
@@ -1246,8 +1415,8 @@ static struct genl_family pmcraid_event_family = {
* pmcraid_netlink_init - registers pmcraid_event_family
*
* Return value:
- * 0 if the pmcraid_event_family is successfully registered
- * with netlink generic, non-zero otherwise
+ * 0 if the pmcraid_event_family is successfully registered
+ * with netlink generic, non-zero otherwise
*/
static int pmcraid_netlink_init(void)
{
@@ -1268,7 +1437,7 @@ static int pmcraid_netlink_init(void)
* pmcraid_netlink_release - unregisters pmcraid_event_family
*
* Return value:
- * none
+ * none
*/
static void pmcraid_netlink_release(void)
{
@@ -1283,31 +1452,30 @@ static void pmcraid_netlink_release(void)
* Return value:
* 0 if success, error value in case of any failure.
*/
-static int pmcraid_notify_aen(struct pmcraid_instance *pinstance, u8 type)
+static int pmcraid_notify_aen(
+ struct pmcraid_instance *pinstance,
+ struct pmcraid_aen_msg *aen_msg,
+ u32 data_size
+)
{
struct sk_buff *skb;
- struct pmcraid_aen_msg *aen_msg;
void *msg_header;
- int data_size, total_size;
+ u32 total_size, nla_genl_hdr_total_size;
int result;
-
- if (type == PMCRAID_HCAM_CODE_LOG_DATA) {
- aen_msg = pinstance->ldn.msg;
- data_size = pinstance->ldn.hcam->data_len;
- } else {
- aen_msg = pinstance->ccn.msg;
- data_size = pinstance->ccn.hcam->data_len;
- }
-
- data_size += sizeof(struct pmcraid_hcam_hdr);
aen_msg->hostno = (pinstance->host->unique_id << 16 |
MINOR(pinstance->cdev.dev));
aen_msg->length = data_size;
+
data_size += sizeof(*aen_msg);
total_size = nla_total_size(data_size);
- skb = genlmsg_new(total_size, GFP_ATOMIC);
+ /* Add GENL_HDR to total_size */
+ nla_genl_hdr_total_size =
+ (total_size + (GENL_HDRLEN +
+ ((struct genl_family *)&pmcraid_event_family)->hdrsize)
+ + NLMSG_HDRLEN);
+ skb = genlmsg_new(nla_genl_hdr_total_size, GFP_ATOMIC);
if (!skb) {
@@ -1329,7 +1497,7 @@ static int pmcraid_notify_aen(struct pmcraid_instance *pinstance, u8 type)
result = nla_put(skb, PMCRAID_AEN_ATTR_EVENT, data_size, aen_msg);
if (result) {
- pmcraid_err("failed to copy AEN attribute data \n");
+ pmcraid_err("failed to copy AEN attribute data\n");
nlmsg_free(skb);
return -EINVAL;
}
@@ -1350,13 +1518,57 @@ static int pmcraid_notify_aen(struct pmcraid_instance *pinstance, u8 type)
* value.
*/
if (result)
- pmcraid_info("failed to send %s event message %x!\n",
- type == PMCRAID_HCAM_CODE_LOG_DATA ? "LDN" : "CCN",
- result);
+ pmcraid_info("error (%x) sending aen event message\n", result);
return result;
}
/**
+ * pmcraid_notify_ccn - notifies about CCN event msg to user space
+ * @pinstance: pointer adapter instance structure
+ *
+ * Return value:
+ * 0 if success, error value in case of any failure
+ */
+static int pmcraid_notify_ccn(struct pmcraid_instance *pinstance)
+{
+ return pmcraid_notify_aen(pinstance,
+ pinstance->ccn.msg,
+ pinstance->ccn.hcam->data_len +
+ sizeof(struct pmcraid_hcam_hdr));
+}
+
+/**
+ * pmcraid_notify_ldn - notifies about CCN event msg to user space
+ * @pinstance: pointer adapter instance structure
+ *
+ * Return value:
+ * 0 if success, error value in case of any failure
+ */
+static int pmcraid_notify_ldn(struct pmcraid_instance *pinstance)
+{
+ return pmcraid_notify_aen(pinstance,
+ pinstance->ldn.msg,
+ pinstance->ldn.hcam->data_len +
+ sizeof(struct pmcraid_hcam_hdr));
+}
+
+/**
+ * pmcraid_notify_ioastate - sends IOA state event msg to user space
+ * @pinstance: pointer adapter instance structure
+ * @evt: controller state event to be sent
+ *
+ * Return value:
+ * 0 if success, error value in case of any failure
+ */
+static void pmcraid_notify_ioastate(struct pmcraid_instance *pinstance, u32 evt)
+{
+ pinstance->scn.ioa_state = evt;
+ pmcraid_notify_aen(pinstance,
+ &pinstance->scn.msg,
+ sizeof(u32));
+}
+
+/**
* pmcraid_handle_config_change - Handle a config change from the adapter
* @pinstance: pointer to per adapter instance structure
*
@@ -1375,10 +1587,12 @@ static void pmcraid_handle_config_change(struct pmcraid_instance *pinstance)
unsigned long host_lock_flags;
u32 new_entry = 1;
u32 hidden_entry = 0;
+ u16 fw_version;
int rc;
ccn_hcam = (struct pmcraid_hcam_ccn *)pinstance->ccn.hcam;
cfg_entry = &ccn_hcam->cfg_entry;
+ fw_version = be16_to_cpu(pinstance->inq_data->fw_version);
pmcraid_info
("CCN(%x): %x type: %x lost: %x flags: %x res: %x:%x:%x:%x\n",
@@ -1391,7 +1605,10 @@ static void pmcraid_handle_config_change(struct pmcraid_instance *pinstance)
RES_IS_VSET(*cfg_entry) ? PMCRAID_VSET_BUS_ID :
(RES_IS_GSCSI(*cfg_entry) ? PMCRAID_PHYS_BUS_ID :
RES_BUS(cfg_entry->resource_address)),
- RES_IS_VSET(*cfg_entry) ? cfg_entry->unique_flags1 :
+ RES_IS_VSET(*cfg_entry) ?
+ (fw_version <= PMCRAID_FW_VERSION_1 ?
+ cfg_entry->unique_flags1 :
+ cfg_entry->array_id & 0xFF) :
RES_TARGET(cfg_entry->resource_address),
RES_LUN(cfg_entry->resource_address));
@@ -1415,11 +1632,16 @@ static void pmcraid_handle_config_change(struct pmcraid_instance *pinstance)
*/
if (pinstance->ccn.hcam->notification_type ==
NOTIFICATION_TYPE_ENTRY_CHANGED &&
- cfg_entry->resource_type == RES_TYPE_VSET &&
- cfg_entry->unique_flags1 & 0x80) {
- hidden_entry = 1;
- } else if (!pmcraid_expose_resource(cfg_entry))
+ cfg_entry->resource_type == RES_TYPE_VSET) {
+
+ if (fw_version <= PMCRAID_FW_VERSION_1)
+ hidden_entry = (cfg_entry->unique_flags1 & 0x80) != 0;
+ else
+ hidden_entry = (cfg_entry->unique_flags1 & 0x80) != 0;
+
+ } else if (!pmcraid_expose_resource(fw_version, cfg_entry)) {
goto out_notify_apps;
+ }
spin_lock_irqsave(&pinstance->resource_lock, lock_flags);
list_for_each_entry(res, &pinstance->used_res_q, queue) {
@@ -1466,13 +1688,15 @@ static void pmcraid_handle_config_change(struct pmcraid_instance *pinstance)
list_add_tail(&res->queue, &pinstance->used_res_q);
}
- memcpy(&res->cfg_entry, cfg_entry,
- sizeof(struct pmcraid_config_table_entry));
+ memcpy(&res->cfg_entry, cfg_entry, pinstance->config_table_entry_size);
if (pinstance->ccn.hcam->notification_type ==
NOTIFICATION_TYPE_ENTRY_DELETED || hidden_entry) {
if (res->scsi_dev) {
- res->cfg_entry.unique_flags1 &= 0x7F;
+ if (fw_version <= PMCRAID_FW_VERSION_1)
+ res->cfg_entry.unique_flags1 &= 0x7F;
+ else
+ res->cfg_entry.array_id &= 0xFF;
res->change_detected = RES_CHANGE_DEL;
res->cfg_entry.resource_handle =
PMCRAID_INVALID_RES_HANDLE;
@@ -1491,7 +1715,7 @@ out_notify_apps:
/* Notify configuration changes to registered applications.*/
if (!pmcraid_disable_aen)
- pmcraid_notify_aen(pinstance, PMCRAID_HCAM_CODE_CONFIG_CHANGE);
+ pmcraid_notify_ccn(pinstance);
cmd = pmcraid_init_hcam(pinstance, PMCRAID_HCAM_CODE_CONFIG_CHANGE);
if (cmd)
@@ -1528,7 +1752,7 @@ void pmcraid_ioasc_logger(u32 ioasc, struct pmcraid_cmd *cmd)
return;
/* log the error string */
- pmcraid_err("cmd [%d] for resource %x failed with %x(%s)\n",
+ pmcraid_err("cmd [%x] for resource %x failed with %x(%s)\n",
cmd->ioa_cb->ioarcb.cdb[0],
cmd->ioa_cb->ioarcb.resource_handle,
le32_to_cpu(ioasc), error_info->error_string);
@@ -1663,7 +1887,7 @@ static void pmcraid_process_ldn(struct pmcraid_cmd *cmd)
}
/* send netlink message for HCAM notification if enabled */
if (!pmcraid_disable_aen)
- pmcraid_notify_aen(pinstance, PMCRAID_HCAM_CODE_LOG_DATA);
+ pmcraid_notify_ldn(pinstance);
cmd = pmcraid_init_hcam(pinstance, PMCRAID_HCAM_CODE_LOG_DATA);
if (cmd)
@@ -1701,10 +1925,13 @@ static void pmcraid_unregister_hcams(struct pmcraid_cmd *cmd)
atomic_set(&pinstance->ldn.ignore, 1);
/* If adapter reset was forced as part of runtime reset sequence,
- * start the reset sequence.
+ * start the reset sequence. Reset will be triggered even in case
+ * IOA unit_check.
*/
- if (pinstance->force_ioa_reset && !pinstance->ioa_bringdown) {
+ if ((pinstance->force_ioa_reset && !pinstance->ioa_bringdown) ||
+ pinstance->ioa_unit_check) {
pinstance->force_ioa_reset = 0;
+ pinstance->ioa_unit_check = 0;
pinstance->ioa_state = IOA_STATE_IN_RESET_ALERT;
pmcraid_reset_alert(cmd);
return;
@@ -1735,10 +1962,13 @@ static int pmcraid_reset_enable_ioa(struct pmcraid_instance *pinstance)
pmcraid_enable_interrupts(pinstance, PMCRAID_PCI_INTERRUPTS);
if (intrs & INTRS_TRANSITION_TO_OPERATIONAL) {
- iowrite32(INTRS_TRANSITION_TO_OPERATIONAL,
- pinstance->int_regs.ioa_host_interrupt_mask_reg);
- iowrite32(INTRS_TRANSITION_TO_OPERATIONAL,
- pinstance->int_regs.ioa_host_interrupt_clr_reg);
+ if (!pinstance->interrupt_mode) {
+ iowrite32(INTRS_TRANSITION_TO_OPERATIONAL,
+ pinstance->int_regs.
+ ioa_host_interrupt_mask_reg);
+ iowrite32(INTRS_TRANSITION_TO_OPERATIONAL,
+ pinstance->int_regs.ioa_host_interrupt_clr_reg);
+ }
return 1;
} else {
return 0;
@@ -1777,8 +2007,19 @@ static void pmcraid_soft_reset(struct pmcraid_cmd *cmd)
doorbell = DOORBELL_RUNTIME_RESET |
DOORBELL_ENABLE_DESTRUCTIVE_DIAGS;
+ /* Since we do RESET_ALERT and Start BIST we have to again write
+ * MSIX Doorbell to indicate the interrupt mode
+ */
+ if (pinstance->interrupt_mode) {
+ iowrite32(DOORBELL_INTR_MODE_MSIX,
+ pinstance->int_regs.host_ioa_interrupt_reg);
+ ioread32(pinstance->int_regs.host_ioa_interrupt_reg);
+ }
+
iowrite32(doorbell, pinstance->int_regs.host_ioa_interrupt_reg);
+ ioread32(pinstance->int_regs.host_ioa_interrupt_reg),
int_reg = ioread32(pinstance->int_regs.ioa_host_interrupt_reg);
+
pmcraid_info("Waiting for IOA to become operational %x:%x\n",
ioread32(pinstance->int_regs.host_ioa_interrupt_reg),
int_reg);
@@ -1854,7 +2095,8 @@ static void pmcraid_fail_outstanding_cmds(struct pmcraid_instance *pinstance)
} else if (cmd->cmd_done == pmcraid_internal_done ||
cmd->cmd_done == pmcraid_erp_done) {
cmd->cmd_done(cmd);
- } else if (cmd->cmd_done != pmcraid_ioa_reset) {
+ } else if (cmd->cmd_done != pmcraid_ioa_reset &&
+ cmd->cmd_done != pmcraid_ioa_shutdown_done) {
pmcraid_return_cmd(cmd);
}
@@ -1964,6 +2206,13 @@ static void pmcraid_ioa_reset(struct pmcraid_cmd *cmd)
pinstance->ioa_reset_attempts = 0;
pmcraid_err("IOA didn't respond marking it as dead\n");
pinstance->ioa_state = IOA_STATE_DEAD;
+
+ if (pinstance->ioa_bringdown)
+ pmcraid_notify_ioastate(pinstance,
+ PMC_DEVICE_EVENT_SHUTDOWN_FAILED);
+ else
+ pmcraid_notify_ioastate(pinstance,
+ PMC_DEVICE_EVENT_RESET_FAILED);
reset_complete = 1;
break;
}
@@ -1971,7 +2220,6 @@ static void pmcraid_ioa_reset(struct pmcraid_cmd *cmd)
/* Once either bist or pci reset is done, restore PCI config
* space. If this fails, proceed with hard reset again
*/
-
if (pci_restore_state(pinstance->pdev)) {
pmcraid_info("config-space error resetting again\n");
pinstance->ioa_state = IOA_STATE_IN_RESET_ALERT;
@@ -2002,6 +2250,8 @@ static void pmcraid_ioa_reset(struct pmcraid_cmd *cmd)
pinstance->ioa_shutdown_type = SHUTDOWN_NONE;
pinstance->ioa_bringdown = 0;
pinstance->ioa_state = IOA_STATE_UNKNOWN;
+ pmcraid_notify_ioastate(pinstance,
+ PMC_DEVICE_EVENT_SHUTDOWN_SUCCESS);
reset_complete = 1;
} else {
/* bring-up IOA, so proceed with soft reset
@@ -2051,6 +2301,8 @@ static void pmcraid_ioa_reset(struct pmcraid_cmd *cmd)
*/
if (pinstance->ioa_shutdown_type == SHUTDOWN_NONE &&
pinstance->force_ioa_reset == 0) {
+ pmcraid_notify_ioastate(pinstance,
+ PMC_DEVICE_EVENT_RESET_SUCCESS);
reset_complete = 1;
} else {
if (pinstance->ioa_shutdown_type != SHUTDOWN_NONE)
@@ -2116,6 +2368,8 @@ static void pmcraid_initiate_reset(struct pmcraid_instance *pinstance)
pinstance->ioa_shutdown_type = SHUTDOWN_NONE;
pinstance->reset_cmd = cmd;
pinstance->force_ioa_reset = 1;
+ pmcraid_notify_ioastate(pinstance,
+ PMC_DEVICE_EVENT_RESET_START);
pmcraid_ioa_reset(cmd);
}
}
@@ -2191,7 +2445,7 @@ static int pmcraid_reset_reload(
wait_event(pinstance->reset_wait_q,
!pinstance->ioa_reset_in_progress);
- pmcraid_info("reset_reload: reset is complete !! \n");
+ pmcraid_info("reset_reload: reset is complete !!\n");
scsi_unblock_requests(pinstance->host);
if (pinstance->ioa_state == target_state)
reset = 0;
@@ -2225,6 +2479,8 @@ static int pmcraid_reset_bringdown(struct pmcraid_instance *pinstance)
*/
static int pmcraid_reset_bringup(struct pmcraid_instance *pinstance)
{
+ pmcraid_notify_ioastate(pinstance, PMC_DEVICE_EVENT_RESET_START);
+
return pmcraid_reset_reload(pinstance,
SHUTDOWN_NONE,
IOA_STATE_OPERATIONAL);
@@ -2704,7 +2960,7 @@ static struct pmcraid_cmd *pmcraid_abort_cmd(struct pmcraid_cmd *cmd)
pmcraid_info("command (%d) CDB[0] = %x for %x\n",
le32_to_cpu(cancel_cmd->ioa_cb->ioarcb.response_handle) >> 2,
- cmd->ioa_cb->ioarcb.cdb[0],
+ cancel_cmd->ioa_cb->ioarcb.cdb[0],
le32_to_cpu(cancel_cmd->ioa_cb->ioarcb.resource_handle));
pmcraid_send_cmd(cancel_cmd,
@@ -2729,8 +2985,8 @@ static int pmcraid_abort_complete(struct pmcraid_cmd *cancel_cmd)
u32 ioasc;
wait_for_completion(&cancel_cmd->wait_for_completion);
- res = cancel_cmd->u.res;
- cancel_cmd->u.res = NULL;
+ res = cancel_cmd->res;
+ cancel_cmd->res = NULL;
ioasc = le32_to_cpu(cancel_cmd->ioa_cb->ioasa.ioasc);
/* If the abort task is not timed out we will get a Good completion
@@ -2823,7 +3079,7 @@ static int pmcraid_eh_abort_handler(struct scsi_cmnd *scsi_cmd)
host_lock_flags);
if (cancel_cmd) {
- cancel_cmd->u.res = cmd->scsi_cmd->device->hostdata;
+ cancel_cmd->res = cmd->scsi_cmd->device->hostdata;
rc = pmcraid_abort_complete(cancel_cmd);
}
@@ -2842,7 +3098,7 @@ static int pmcraid_eh_abort_handler(struct scsi_cmnd *scsi_cmd)
* takes care by locking/unlocking host_lock.
*
* Return value
- * SUCCESS or FAILED
+ * SUCCESS or FAILED
*/
static int pmcraid_eh_device_reset_handler(struct scsi_cmnd *scmd)
{
@@ -2879,7 +3135,7 @@ static int pmcraid_eh_target_reset_handler(struct scsi_cmnd *scmd)
* Initiates adapter reset to bring it up to operational state
*
* Return value
- * SUCCESS or FAILED
+ * SUCCESS or FAILED
*/
static int pmcraid_eh_host_reset_handler(struct scsi_cmnd *scmd)
{
@@ -2991,7 +3247,7 @@ pmcraid_init_ioadls(struct pmcraid_cmd *cmd, int sgcount)
* to firmware. This builds ioadl descriptors and sets up ioarcb fields.
*
* Return value:
- * 0 on success or -1 on failure
+ * 0 on success or -1 on failure
*/
static int pmcraid_build_ioadl(
struct pmcraid_instance *pinstance,
@@ -3049,7 +3305,7 @@ static int pmcraid_build_ioadl(
* Free a DMA'able memory previously allocated with pmcraid_alloc_sglist
*
* Return value:
- * none
+ * none
*/
static void pmcraid_free_sglist(struct pmcraid_sglist *sglist)
{
@@ -3070,7 +3326,7 @@ static void pmcraid_free_sglist(struct pmcraid_sglist *sglist)
* list.
*
* Return value
- * pointer to sglist / NULL on failure
+ * pointer to sglist / NULL on failure
*/
static struct pmcraid_sglist *pmcraid_alloc_sglist(int buflen)
{
@@ -3224,11 +3480,12 @@ static int pmcraid_queuecommand(
struct pmcraid_resource_entry *res;
struct pmcraid_ioarcb *ioarcb;
struct pmcraid_cmd *cmd;
+ u32 fw_version;
int rc = 0;
pinstance =
(struct pmcraid_instance *)scsi_cmd->device->host->hostdata;
-
+ fw_version = be16_to_cpu(pinstance->inq_data->fw_version);
scsi_cmd->scsi_done = done;
res = scsi_cmd->device->hostdata;
scsi_cmd->result = (DID_OK << 16);
@@ -3247,6 +3504,15 @@ static int pmcraid_queuecommand(
if (pinstance->ioa_reset_in_progress)
return SCSI_MLQUEUE_HOST_BUSY;
+ /* Firmware doesn't support SYNCHRONIZE_CACHE command (0x35), complete
+ * the command here itself with success return
+ */
+ if (scsi_cmd->cmnd[0] == SYNCHRONIZE_CACHE) {
+ pmcraid_info("SYNC_CACHE(0x35), completing in driver itself\n");
+ scsi_cmd->scsi_done(scsi_cmd);
+ return 0;
+ }
+
/* initialize the command and IOARCB to be sent to IOA */
cmd = pmcraid_get_free_cmd(pinstance);
@@ -3261,6 +3527,13 @@ static int pmcraid_queuecommand(
ioarcb->resource_handle = res->cfg_entry.resource_handle;
ioarcb->request_type = REQ_TYPE_SCSI;
+ /* set hrrq number where the IOA should respond to. Note that all cmds
+ * generated internally uses hrrq_id 0, exception to this is the cmd
+ * block of scsi_cmd which is re-used (e.g. cancel/abort), which uses
+ * hrrq_id assigned here in queuecommand
+ */
+ ioarcb->hrrq_id = atomic_add_return(1, &(pinstance->last_message_id)) %
+ pinstance->num_hrrq;
cmd->cmd_done = pmcraid_io_done;
if (RES_IS_GSCSI(res->cfg_entry) || RES_IS_VSET(res->cfg_entry)) {
@@ -3287,7 +3560,9 @@ static int pmcraid_queuecommand(
RES_IS_VSET(res->cfg_entry) ? PMCRAID_VSET_BUS_ID :
PMCRAID_PHYS_BUS_ID,
RES_IS_VSET(res->cfg_entry) ?
- res->cfg_entry.unique_flags1 :
+ (fw_version <= PMCRAID_FW_VERSION_1 ?
+ res->cfg_entry.unique_flags1 :
+ res->cfg_entry.array_id & 0xFF) :
RES_TARGET(res->cfg_entry.resource_address),
RES_LUN(res->cfg_entry.resource_address));
@@ -3324,8 +3599,7 @@ static int pmcraid_chr_open(struct inode *inode, struct file *filep)
*/
static int pmcraid_chr_release(struct inode *inode, struct file *filep)
{
- struct pmcraid_instance *pinstance =
- ((struct pmcraid_instance *)filep->private_data);
+ struct pmcraid_instance *pinstance = filep->private_data;
filep->private_data = NULL;
fasync_helper(-1, filep, 0, &pinstance->aen_queue);
@@ -3344,7 +3618,7 @@ static int pmcraid_chr_fasync(int fd, struct file *filep, int mode)
struct pmcraid_instance *pinstance;
int rc;
- pinstance = (struct pmcraid_instance *)filep->private_data;
+ pinstance = filep->private_data;
mutex_lock(&pinstance->aen_queue_lock);
rc = fasync_helper(fd, filep, mode, &pinstance->aen_queue);
mutex_unlock(&pinstance->aen_queue_lock);
@@ -3465,6 +3739,7 @@ static long pmcraid_ioctl_passthrough(
unsigned long request_buffer;
unsigned long request_offset;
unsigned long lock_flags;
+ u32 ioasc;
int request_size;
int buffer_size;
u8 access, direction;
@@ -3566,6 +3841,14 @@ static long pmcraid_ioctl_passthrough(
buffer->ioarcb.add_cmd_param_length);
}
+ /* set hrrq number where the IOA should respond to. Note that all cmds
+ * generated internally uses hrrq_id 0, exception to this is the cmd
+ * block of scsi_cmd which is re-used (e.g. cancel/abort), which uses
+ * hrrq_id assigned here in queuecommand
+ */
+ ioarcb->hrrq_id = atomic_add_return(1, &(pinstance->last_message_id)) %
+ pinstance->num_hrrq;
+
if (request_size) {
rc = pmcraid_build_passthrough_ioadls(cmd,
request_size,
@@ -3606,6 +3889,14 @@ static long pmcraid_ioctl_passthrough(
_pmcraid_fire_command(cmd);
spin_unlock_irqrestore(pinstance->host->host_lock, lock_flags);
+ /* NOTE ! Remove the below line once abort_task is implemented
+ * in firmware. This line disables ioctl command timeout handling logic
+ * similar to IO command timeout handling, making ioctl commands to wait
+ * until the command completion regardless of timeout value specified in
+ * ioarcb
+ */
+ buffer->ioarcb.cmd_timeout = 0;
+
/* If command timeout is specified put caller to wait till that time,
* otherwise it would be blocking wait. If command gets timed out, it
* will be aborted.
@@ -3620,25 +3911,47 @@ static long pmcraid_ioctl_passthrough(
le32_to_cpu(cmd->ioa_cb->ioarcb.response_handle >> 2),
cmd->ioa_cb->ioarcb.cdb[0]);
- rc = -ETIMEDOUT;
spin_lock_irqsave(pinstance->host->host_lock, lock_flags);
cancel_cmd = pmcraid_abort_cmd(cmd);
spin_unlock_irqrestore(pinstance->host->host_lock, lock_flags);
if (cancel_cmd) {
wait_for_completion(&cancel_cmd->wait_for_completion);
+ ioasc = cancel_cmd->ioa_cb->ioasa.ioasc;
pmcraid_return_cmd(cancel_cmd);
+
+ /* if abort task couldn't find the command i.e it got
+ * completed prior to aborting, return good completion.
+ * if command got aborted succesfully or there was IOA
+ * reset due to abort task itself getting timedout then
+ * return -ETIMEDOUT
+ */
+ if (ioasc == PMCRAID_IOASC_IOA_WAS_RESET ||
+ PMCRAID_IOASC_SENSE_KEY(ioasc) == 0x00) {
+ if (ioasc != PMCRAID_IOASC_GC_IOARCB_NOTFOUND)
+ rc = -ETIMEDOUT;
+ goto out_handle_response;
+ }
}
- goto out_free_sglist;
+ /* no command block for abort task or abort task failed to abort
+ * the IOARCB, then wait for 150 more seconds and initiate reset
+ * sequence after timeout
+ */
+ if (!wait_for_completion_timeout(
+ &cmd->wait_for_completion,
+ msecs_to_jiffies(150 * 1000))) {
+ pmcraid_reset_bringup(cmd->drv_inst);
+ rc = -ETIMEDOUT;
+ }
}
+out_handle_response:
/* If the command failed for any reason, copy entire IOASA buffer and
* return IOCTL success. If copying IOASA to user-buffer fails, return
* EFAULT
*/
- if (le32_to_cpu(cmd->ioa_cb->ioasa.ioasc)) {
-
+ if (PMCRAID_IOASC_SENSE_KEY(le32_to_cpu(cmd->ioa_cb->ioasa.ioasc))) {
void *ioasa =
(void *)(arg +
offsetof(struct pmcraid_passthrough_ioctl_buffer, ioasa));
@@ -3651,6 +3964,7 @@ static long pmcraid_ioctl_passthrough(
rc = -EFAULT;
}
}
+
/* If the data transfer was from device, copy the data onto user
* buffers
*/
@@ -3699,7 +4013,7 @@ static long pmcraid_ioctl_driver(
int rc = -ENOSYS;
if (!access_ok(VERIFY_READ, user_buffer, _IOC_SIZE(cmd))) {
- pmcraid_err("ioctl_driver: access fault in request buffer \n");
+ pmcraid_err("ioctl_driver: access fault in request buffer\n");
return -EFAULT;
}
@@ -3795,7 +4109,7 @@ static long pmcraid_chr_ioctl(
return retval;
}
- pinstance = (struct pmcraid_instance *)filep->private_data;
+ pinstance = filep->private_data;
if (!pinstance) {
pmcraid_info("adapter instance is not found\n");
@@ -4011,36 +4325,77 @@ static struct scsi_host_template pmcraid_host_template = {
.proc_name = PMCRAID_DRIVER_NAME
};
-/**
- * pmcraid_isr_common - Common interrupt handler routine
- *
- * @pinstance: pointer to adapter instance
- * @intrs: active interrupts (contents of ioa_host_interrupt register)
- * @hrrq_id: Host RRQ index
+/*
+ * pmcraid_isr_msix - implements MSI-X interrupt handling routine
+ * @irq: interrupt vector number
+ * @dev_id: pointer hrrq_vector
*
* Return Value
- * none
+ * IRQ_HANDLED if interrupt is handled or IRQ_NONE if ignored
*/
-static void pmcraid_isr_common(
- struct pmcraid_instance *pinstance,
- u32 intrs,
- int hrrq_id
-)
+
+static irqreturn_t pmcraid_isr_msix(int irq, void *dev_id)
{
- u32 intrs_clear =
- (intrs & INTRS_CRITICAL_OP_IN_PROGRESS) ? intrs
- : INTRS_HRRQ_VALID;
- iowrite32(intrs_clear,
- pinstance->int_regs.ioa_host_interrupt_clr_reg);
- intrs = ioread32(pinstance->int_regs.ioa_host_interrupt_reg);
+ struct pmcraid_isr_param *hrrq_vector;
+ struct pmcraid_instance *pinstance;
+ unsigned long lock_flags;
+ u32 intrs_val;
+ int hrrq_id;
+
+ hrrq_vector = (struct pmcraid_isr_param *)dev_id;
+ hrrq_id = hrrq_vector->hrrq_id;
+ pinstance = hrrq_vector->drv_inst;
+
+ if (!hrrq_id) {
+ /* Read the interrupt */
+ intrs_val = pmcraid_read_interrupts(pinstance);
+ if (intrs_val &&
+ ((ioread32(pinstance->int_regs.host_ioa_interrupt_reg)
+ & DOORBELL_INTR_MSIX_CLR) == 0)) {
+ /* Any error interrupts including unit_check,
+ * initiate IOA reset.In case of unit check indicate
+ * to reset_sequence that IOA unit checked and prepare
+ * for a dump during reset sequence
+ */
+ if (intrs_val & PMCRAID_ERROR_INTERRUPTS) {
+ if (intrs_val & INTRS_IOA_UNIT_CHECK)
+ pinstance->ioa_unit_check = 1;
+
+ pmcraid_err("ISR: error interrupts: %x \
+ initiating reset\n", intrs_val);
+ spin_lock_irqsave(pinstance->host->host_lock,
+ lock_flags);
+ pmcraid_initiate_reset(pinstance);
+ spin_unlock_irqrestore(
+ pinstance->host->host_lock,
+ lock_flags);
+ }
+ /* If interrupt was as part of the ioa initialization,
+ * clear it. Delete the timer and wakeup the
+ * reset engine to proceed with reset sequence
+ */
+ if (intrs_val & INTRS_TRANSITION_TO_OPERATIONAL)
+ pmcraid_clr_trans_op(pinstance);
+
+ /* Clear the interrupt register by writing
+ * to host to ioa doorbell. Once done
+ * FW will clear the interrupt.
+ */
+ iowrite32(DOORBELL_INTR_MSIX_CLR,
+ pinstance->int_regs.host_ioa_interrupt_reg);
+ ioread32(pinstance->int_regs.host_ioa_interrupt_reg);
+
- /* hrrq valid bit was set, schedule tasklet to handle the response */
- if (intrs_clear == INTRS_HRRQ_VALID)
- tasklet_schedule(&(pinstance->isr_tasklet[hrrq_id]));
+ }
+ }
+
+ tasklet_schedule(&(pinstance->isr_tasklet[hrrq_id]));
+
+ return IRQ_HANDLED;
}
/**
- * pmcraid_isr - implements interrupt handling routine
+ * pmcraid_isr - implements legacy interrupt handling routine
*
* @irq: interrupt vector number
* @dev_id: pointer hrrq_vector
@@ -4052,8 +4407,9 @@ static irqreturn_t pmcraid_isr(int irq, void *dev_id)
{
struct pmcraid_isr_param *hrrq_vector;
struct pmcraid_instance *pinstance;
- unsigned long lock_flags;
u32 intrs;
+ unsigned long lock_flags;
+ int hrrq_id = 0;
/* In case of legacy interrupt mode where interrupts are shared across
* isrs, it may be possible that the current interrupt is not from IOA
@@ -4062,21 +4418,13 @@ static irqreturn_t pmcraid_isr(int irq, void *dev_id)
printk(KERN_INFO "%s(): NULL host pointer\n", __func__);
return IRQ_NONE;
}
-
hrrq_vector = (struct pmcraid_isr_param *)dev_id;
pinstance = hrrq_vector->drv_inst;
- /* Acquire the lock (currently host_lock) while processing interrupts.
- * This interval is small as most of the response processing is done by
- * tasklet without the lock.
- */
- spin_lock_irqsave(pinstance->host->host_lock, lock_flags);
intrs = pmcraid_read_interrupts(pinstance);
- if (unlikely((intrs & PMCRAID_PCI_INTERRUPTS) == 0)) {
- spin_unlock_irqrestore(pinstance->host->host_lock, lock_flags);
+ if (unlikely((intrs & PMCRAID_PCI_INTERRUPTS) == 0))
return IRQ_NONE;
- }
/* Any error interrupts including unit_check, initiate IOA reset.
* In case of unit check indicate to reset_sequence that IOA unit
@@ -4091,13 +4439,28 @@ static irqreturn_t pmcraid_isr(int irq, void *dev_id)
pinstance->int_regs.ioa_host_interrupt_clr_reg);
pmcraid_err("ISR: error interrupts: %x initiating reset\n",
intrs);
- intrs = ioread32(pinstance->int_regs.ioa_host_interrupt_reg);
+ intrs = ioread32(
+ pinstance->int_regs.ioa_host_interrupt_clr_reg);
+ spin_lock_irqsave(pinstance->host->host_lock, lock_flags);
pmcraid_initiate_reset(pinstance);
+ spin_unlock_irqrestore(pinstance->host->host_lock, lock_flags);
} else {
- pmcraid_isr_common(pinstance, intrs, hrrq_vector->hrrq_id);
- }
+ /* If interrupt was as part of the ioa initialization,
+ * clear. Delete the timer and wakeup the
+ * reset engine to proceed with reset sequence
+ */
+ if (intrs & INTRS_TRANSITION_TO_OPERATIONAL) {
+ pmcraid_clr_trans_op(pinstance);
+ } else {
+ iowrite32(intrs,
+ pinstance->int_regs.ioa_host_interrupt_clr_reg);
+ ioread32(
+ pinstance->int_regs.ioa_host_interrupt_clr_reg);
- spin_unlock_irqrestore(pinstance->host->host_lock, lock_flags);
+ tasklet_schedule(
+ &(pinstance->isr_tasklet[hrrq_id]));
+ }
+ }
return IRQ_HANDLED;
}
@@ -4120,6 +4483,7 @@ static void pmcraid_worker_function(struct work_struct *workp)
struct scsi_device *sdev;
unsigned long lock_flags;
unsigned long host_lock_flags;
+ u16 fw_version;
u8 bus, target, lun;
pinstance = container_of(workp, struct pmcraid_instance, worker_q);
@@ -4127,6 +4491,8 @@ static void pmcraid_worker_function(struct work_struct *workp)
if (!atomic_read(&pinstance->expose_resources))
return;
+ fw_version = be16_to_cpu(pinstance->inq_data->fw_version);
+
spin_lock_irqsave(&pinstance->resource_lock, lock_flags);
list_for_each_entry_safe(res, temp, &pinstance->used_res_q, queue) {
@@ -4166,12 +4532,16 @@ static void pmcraid_worker_function(struct work_struct *workp)
if (res->change_detected == RES_CHANGE_ADD) {
- if (!pmcraid_expose_resource(&res->cfg_entry))
+ if (!pmcraid_expose_resource(fw_version,
+ &res->cfg_entry))
continue;
if (RES_IS_VSET(res->cfg_entry)) {
bus = PMCRAID_VSET_BUS_ID;
- target = res->cfg_entry.unique_flags1;
+ if (fw_version <= PMCRAID_FW_VERSION_1)
+ target = res->cfg_entry.unique_flags1;
+ else
+ target = res->cfg_entry.array_id & 0xFF;
lun = PMCRAID_VSET_LUN_ID;
} else {
bus = PMCRAID_PHYS_BUS_ID;
@@ -4201,7 +4571,7 @@ static void pmcraid_worker_function(struct work_struct *workp)
* Return Value
* None
*/
-void pmcraid_tasklet_function(unsigned long instance)
+static void pmcraid_tasklet_function(unsigned long instance)
{
struct pmcraid_isr_param *hrrq_vector;
struct pmcraid_instance *pinstance;
@@ -4210,35 +4580,12 @@ void pmcraid_tasklet_function(unsigned long instance)
unsigned long host_lock_flags;
spinlock_t *lockp; /* hrrq buffer lock */
int id;
- u32 intrs;
__le32 resp;
hrrq_vector = (struct pmcraid_isr_param *)instance;
pinstance = hrrq_vector->drv_inst;
id = hrrq_vector->hrrq_id;
lockp = &(pinstance->hrrq_lock[id]);
- intrs = pmcraid_read_interrupts(pinstance);
-
- /* If interrupts was as part of the ioa initialization, clear and mask
- * it. Delete the timer and wakeup the reset engine to proceed with
- * reset sequence
- */
- if (intrs & INTRS_TRANSITION_TO_OPERATIONAL) {
- iowrite32(INTRS_TRANSITION_TO_OPERATIONAL,
- pinstance->int_regs.ioa_host_interrupt_mask_reg);
- iowrite32(INTRS_TRANSITION_TO_OPERATIONAL,
- pinstance->int_regs.ioa_host_interrupt_clr_reg);
-
- if (pinstance->reset_cmd != NULL) {
- del_timer(&pinstance->reset_cmd->timer);
- spin_lock_irqsave(pinstance->host->host_lock,
- host_lock_flags);
- pinstance->reset_cmd->cmd_done(pinstance->reset_cmd);
- spin_unlock_irqrestore(pinstance->host->host_lock,
- host_lock_flags);
- }
- return;
- }
/* loop through each of the commands responded by IOA. Each HRRQ buf is
* protected by its own lock. Traversals must be done within this lock
@@ -4256,27 +4603,6 @@ void pmcraid_tasklet_function(unsigned long instance)
int cmd_index = resp >> 2;
struct pmcraid_cmd *cmd = NULL;
- if (cmd_index < PMCRAID_MAX_CMD) {
- cmd = pinstance->cmd_list[cmd_index];
- } else {
- /* In case of invalid response handle, initiate IOA
- * reset sequence.
- */
- spin_unlock_irqrestore(lockp, hrrq_lock_flags);
-
- pmcraid_err("Invalid response %d initiating reset\n",
- cmd_index);
-
- spin_lock_irqsave(pinstance->host->host_lock,
- host_lock_flags);
- pmcraid_initiate_reset(pinstance);
- spin_unlock_irqrestore(pinstance->host->host_lock,
- host_lock_flags);
-
- spin_lock_irqsave(lockp, hrrq_lock_flags);
- break;
- }
-
if (pinstance->hrrq_curr[id] < pinstance->hrrq_end[id]) {
pinstance->hrrq_curr[id]++;
} else {
@@ -4284,6 +4610,14 @@ void pmcraid_tasklet_function(unsigned long instance)
pinstance->host_toggle_bit[id] ^= 1u;
}
+ if (cmd_index >= PMCRAID_MAX_CMD) {
+ /* In case of invalid response handle, log message */
+ pmcraid_err("Invalid response handle %d\n", cmd_index);
+ resp = le32_to_cpu(*(pinstance->hrrq_curr[id]));
+ continue;
+ }
+
+ cmd = pinstance->cmd_list[cmd_index];
spin_unlock_irqrestore(lockp, hrrq_lock_flags);
spin_lock_irqsave(&pinstance->pending_pool_lock,
@@ -4324,7 +4658,16 @@ void pmcraid_tasklet_function(unsigned long instance)
static
void pmcraid_unregister_interrupt_handler(struct pmcraid_instance *pinstance)
{
- free_irq(pinstance->pdev->irq, &(pinstance->hrrq_vector[0]));
+ int i;
+
+ for (i = 0; i < pinstance->num_hrrq; i++)
+ free_irq(pinstance->hrrq_vector[i].vector,
+ &(pinstance->hrrq_vector[i]));
+
+ if (pinstance->interrupt_mode) {
+ pci_disable_msix(pinstance->pdev);
+ pinstance->interrupt_mode = 0;
+ }
}
/**
@@ -4337,14 +4680,70 @@ void pmcraid_unregister_interrupt_handler(struct pmcraid_instance *pinstance)
static int
pmcraid_register_interrupt_handler(struct pmcraid_instance *pinstance)
{
+ int rc;
struct pci_dev *pdev = pinstance->pdev;
+ if (pci_find_capability(pdev, PCI_CAP_ID_MSIX)) {
+ int num_hrrq = PMCRAID_NUM_MSIX_VECTORS;
+ struct msix_entry entries[PMCRAID_NUM_MSIX_VECTORS];
+ int i;
+ for (i = 0; i < PMCRAID_NUM_MSIX_VECTORS; i++)
+ entries[i].entry = i;
+
+ rc = pci_enable_msix(pdev, entries, num_hrrq);
+ if (rc < 0)
+ goto pmcraid_isr_legacy;
+
+ /* Check how many MSIX vectors are allocated and register
+ * msi-x handlers for each of them giving appropriate buffer
+ */
+ if (rc > 0) {
+ num_hrrq = rc;
+ if (pci_enable_msix(pdev, entries, num_hrrq))
+ goto pmcraid_isr_legacy;
+ }
+
+ for (i = 0; i < num_hrrq; i++) {
+ pinstance->hrrq_vector[i].hrrq_id = i;
+ pinstance->hrrq_vector[i].drv_inst = pinstance;
+ pinstance->hrrq_vector[i].vector = entries[i].vector;
+ rc = request_irq(pinstance->hrrq_vector[i].vector,
+ pmcraid_isr_msix, 0,
+ PMCRAID_DRIVER_NAME,
+ &(pinstance->hrrq_vector[i]));
+
+ if (rc) {
+ int j;
+ for (j = 0; j < i; j++)
+ free_irq(entries[j].vector,
+ &(pinstance->hrrq_vector[j]));
+ pci_disable_msix(pdev);
+ goto pmcraid_isr_legacy;
+ }
+ }
+
+ pinstance->num_hrrq = num_hrrq;
+ pinstance->interrupt_mode = 1;
+ iowrite32(DOORBELL_INTR_MODE_MSIX,
+ pinstance->int_regs.host_ioa_interrupt_reg);
+ ioread32(pinstance->int_regs.host_ioa_interrupt_reg);
+ goto pmcraid_isr_out;
+ }
+
+pmcraid_isr_legacy:
+ /* If MSI-X registration failed fallback to legacy mode, where
+ * only one hrrq entry will be used
+ */
pinstance->hrrq_vector[0].hrrq_id = 0;
pinstance->hrrq_vector[0].drv_inst = pinstance;
- pinstance->hrrq_vector[0].vector = 0;
+ pinstance->hrrq_vector[0].vector = pdev->irq;
pinstance->num_hrrq = 1;
- return request_irq(pdev->irq, pmcraid_isr, IRQF_SHARED,
- PMCRAID_DRIVER_NAME, &pinstance->hrrq_vector[0]);
+ rc = 0;
+
+ rc = request_irq(pdev->irq, pmcraid_isr, IRQF_SHARED,
+ PMCRAID_DRIVER_NAME, &pinstance->hrrq_vector[0]);
+pmcraid_isr_out:
+ return rc;
}
/**
@@ -4516,12 +4915,11 @@ pmcraid_release_host_rrqs(struct pmcraid_instance *pinstance, int maxindex)
static int __devinit
pmcraid_allocate_host_rrqs(struct pmcraid_instance *pinstance)
{
- int i;
- int buf_count = PMCRAID_MAX_CMD / pinstance->num_hrrq;
+ int i, buffer_size;
- for (i = 0; i < pinstance->num_hrrq; i++) {
- int buffer_size = HRRQ_ENTRY_SIZE * buf_count;
+ buffer_size = HRRQ_ENTRY_SIZE * PMCRAID_MAX_CMD;
+ for (i = 0; i < pinstance->num_hrrq; i++) {
pinstance->hrrq_start[i] =
pci_alloc_consistent(
pinstance->pdev,
@@ -4529,7 +4927,8 @@ pmcraid_allocate_host_rrqs(struct pmcraid_instance *pinstance)
&(pinstance->hrrq_start_bus_addr[i]));
if (pinstance->hrrq_start[i] == 0) {
- pmcraid_err("could not allocate host rrq: %d\n", i);
+ pmcraid_err("pci_alloc failed for hrrq vector : %d\n",
+ i);
pmcraid_release_host_rrqs(pinstance, i);
return -ENOMEM;
}
@@ -4537,7 +4936,7 @@ pmcraid_allocate_host_rrqs(struct pmcraid_instance *pinstance)
memset(pinstance->hrrq_start[i], 0, buffer_size);
pinstance->hrrq_curr[i] = pinstance->hrrq_start[i];
pinstance->hrrq_end[i] =
- pinstance->hrrq_start[i] + buf_count - 1;
+ pinstance->hrrq_start[i] + PMCRAID_MAX_CMD - 1;
pinstance->host_toggle_bit[i] = 1;
spin_lock_init(&pinstance->hrrq_lock[i]);
}
@@ -4557,7 +4956,7 @@ static void pmcraid_release_hcams(struct pmcraid_instance *pinstance)
if (pinstance->ccn.msg != NULL) {
pci_free_consistent(pinstance->pdev,
PMCRAID_AEN_HDR_SIZE +
- sizeof(struct pmcraid_hcam_ccn),
+ sizeof(struct pmcraid_hcam_ccn_ext),
pinstance->ccn.msg,
pinstance->ccn.baddr);
@@ -4591,7 +4990,7 @@ static int pmcraid_allocate_hcams(struct pmcraid_instance *pinstance)
pinstance->ccn.msg = pci_alloc_consistent(
pinstance->pdev,
PMCRAID_AEN_HDR_SIZE +
- sizeof(struct pmcraid_hcam_ccn),
+ sizeof(struct pmcraid_hcam_ccn_ext),
&(pinstance->ccn.baddr));
pinstance->ldn.msg = pci_alloc_consistent(
@@ -4724,6 +5123,32 @@ static void pmcraid_kill_tasklets(struct pmcraid_instance *pinstance)
}
/**
+ * pmcraid_release_buffers - release per-adapter buffers allocated
+ *
+ * @pinstance: pointer to adapter soft state
+ *
+ * Return Value
+ * none
+ */
+static void pmcraid_release_buffers(struct pmcraid_instance *pinstance)
+{
+ pmcraid_release_config_buffers(pinstance);
+ pmcraid_release_control_blocks(pinstance, PMCRAID_MAX_CMD);
+ pmcraid_release_cmd_blocks(pinstance, PMCRAID_MAX_CMD);
+ pmcraid_release_host_rrqs(pinstance, pinstance->num_hrrq);
+
+ if (pinstance->inq_data != NULL) {
+ pci_free_consistent(pinstance->pdev,
+ sizeof(struct pmcraid_inquiry_data),
+ pinstance->inq_data,
+ pinstance->inq_data_baddr);
+
+ pinstance->inq_data = NULL;
+ pinstance->inq_data_baddr = 0;
+ }
+}
+
+/**
* pmcraid_init_buffers - allocates memory and initializes various structures
* @pinstance: pointer to per adapter instance structure
*
@@ -4753,20 +5178,32 @@ static int __devinit pmcraid_init_buffers(struct pmcraid_instance *pinstance)
}
if (pmcraid_allocate_cmd_blocks(pinstance)) {
- pmcraid_err("couldn't allocate memory for cmd blocks \n");
+ pmcraid_err("couldn't allocate memory for cmd blocks\n");
pmcraid_release_config_buffers(pinstance);
pmcraid_release_host_rrqs(pinstance, pinstance->num_hrrq);
return -ENOMEM;
}
if (pmcraid_allocate_control_blocks(pinstance)) {
- pmcraid_err("couldn't allocate memory control blocks \n");
+ pmcraid_err("couldn't allocate memory control blocks\n");
pmcraid_release_config_buffers(pinstance);
pmcraid_release_cmd_blocks(pinstance, PMCRAID_MAX_CMD);
pmcraid_release_host_rrqs(pinstance, pinstance->num_hrrq);
return -ENOMEM;
}
+ /* allocate DMAable memory for page D0 INQUIRY buffer */
+ pinstance->inq_data = pci_alloc_consistent(
+ pinstance->pdev,
+ sizeof(struct pmcraid_inquiry_data),
+ &pinstance->inq_data_baddr);
+
+ if (pinstance->inq_data == NULL) {
+ pmcraid_err("couldn't allocate DMA memory for INQUIRY\n");
+ pmcraid_release_buffers(pinstance);
+ return -ENOMEM;
+ }
+
/* Initialize all the command blocks and add them to free pool. No
* need to lock (free_pool_lock) as this is done in initialization
* itself
@@ -4785,7 +5222,7 @@ static int __devinit pmcraid_init_buffers(struct pmcraid_instance *pinstance)
* pmcraid_reinit_buffers - resets various buffer pointers
* @pinstance: pointer to adapter instance
* Return value
- * none
+ * none
*/
static void pmcraid_reinit_buffers(struct pmcraid_instance *pinstance)
{
@@ -4836,6 +5273,8 @@ static int __devinit pmcraid_init_instance(
mapped_pci_addr + chip_cfg->ioa_host_intr;
pint_regs->ioa_host_interrupt_clr_reg =
mapped_pci_addr + chip_cfg->ioa_host_intr_clr;
+ pint_regs->ioa_host_msix_interrupt_reg =
+ mapped_pci_addr + chip_cfg->ioa_host_msix_intr;
pint_regs->host_ioa_interrupt_reg =
mapped_pci_addr + chip_cfg->host_ioa_intr;
pint_regs->host_ioa_interrupt_clr_reg =
@@ -4858,6 +5297,7 @@ static int __devinit pmcraid_init_instance(
init_waitqueue_head(&pinstance->reset_wait_q);
atomic_set(&pinstance->outstanding_cmds, 0);
+ atomic_set(&pinstance->last_message_id, 0);
atomic_set(&pinstance->expose_resources, 0);
INIT_LIST_HEAD(&pinstance->free_res_q);
@@ -4883,23 +5323,6 @@ static int __devinit pmcraid_init_instance(
}
/**
- * pmcraid_release_buffers - release per-adapter buffers allocated
- *
- * @pinstance: pointer to adapter soft state
- *
- * Return Value
- * none
- */
-static void pmcraid_release_buffers(struct pmcraid_instance *pinstance)
-{
- pmcraid_release_config_buffers(pinstance);
- pmcraid_release_control_blocks(pinstance, PMCRAID_MAX_CMD);
- pmcraid_release_cmd_blocks(pinstance, PMCRAID_MAX_CMD);
- pmcraid_release_host_rrqs(pinstance, pinstance->num_hrrq);
-
-}
-
-/**
* pmcraid_shutdown - shutdown adapter controller.
* @pdev: pci device struct
*
@@ -4958,7 +5381,7 @@ static int pmcraid_setup_chrdev(struct pmcraid_instance *pinstance)
pmcraid_release_minor(minor);
else
device_create(pmcraid_class, NULL, MKDEV(pmcraid_major, minor),
- NULL, "pmcsas%u", minor);
+ NULL, "%s%u", PMCRAID_DEVFILE, minor);
return error;
}
@@ -5050,7 +5473,6 @@ static int pmcraid_resume(struct pci_dev *pdev)
struct pmcraid_instance *pinstance = pci_get_drvdata(pdev);
struct Scsi_Host *host = pinstance->host;
int rc;
- int hrrqs;
pci_set_power_state(pdev, PCI_D0);
pci_enable_wake(pdev, PCI_D0, 0);
@@ -5077,8 +5499,8 @@ static int pmcraid_resume(struct pci_dev *pdev)
goto disable_device;
}
+ pmcraid_disable_interrupts(pinstance, ~0);
atomic_set(&pinstance->outstanding_cmds, 0);
- hrrqs = pinstance->num_hrrq;
rc = pmcraid_register_interrupt_handler(pinstance);
if (rc) {
@@ -5100,7 +5522,7 @@ static int pmcraid_resume(struct pci_dev *pdev)
* state.
*/
if (pmcraid_reset_bringup(pinstance)) {
- dev_err(&pdev->dev, "couldn't initialize IOA \n");
+ dev_err(&pdev->dev, "couldn't initialize IOA\n");
rc = -ENODEV;
goto release_tasklets;
}
@@ -5108,6 +5530,7 @@ static int pmcraid_resume(struct pci_dev *pdev)
return 0;
release_tasklets:
+ pmcraid_disable_interrupts(pinstance, ~0);
pmcraid_kill_tasklets(pinstance);
pmcraid_unregister_interrupt_handler(pinstance);
@@ -5129,7 +5552,7 @@ disable_device:
/**
* pmcraid_complete_ioa_reset - Called by either timer or tasklet during
- * completion of the ioa reset
+ * completion of the ioa reset
* @cmd: pointer to reset command block
*/
static void pmcraid_complete_ioa_reset(struct pmcraid_cmd *cmd)
@@ -5204,11 +5627,14 @@ static void pmcraid_init_res_table(struct pmcraid_cmd *cmd)
struct pmcraid_config_table_entry *cfgte;
unsigned long lock_flags;
int found, rc, i;
+ u16 fw_version;
LIST_HEAD(old_res);
if (pinstance->cfg_table->flags & MICROCODE_UPDATE_REQUIRED)
pmcraid_err("IOA requires microcode download\n");
+ fw_version = be16_to_cpu(pinstance->inq_data->fw_version);
+
/* resource list is protected by pinstance->resource_lock.
* init_res_table can be called from probe (user-thread) or runtime
* reset (timer/tasklet)
@@ -5219,9 +5645,14 @@ static void pmcraid_init_res_table(struct pmcraid_cmd *cmd)
list_move_tail(&res->queue, &old_res);
for (i = 0; i < pinstance->cfg_table->num_entries; i++) {
- cfgte = &pinstance->cfg_table->entries[i];
+ if (be16_to_cpu(pinstance->inq_data->fw_version) <=
+ PMCRAID_FW_VERSION_1)
+ cfgte = &pinstance->cfg_table->entries[i];
+ else
+ cfgte = (struct pmcraid_config_table_entry *)
+ &pinstance->cfg_table->entries_ext[i];
- if (!pmcraid_expose_resource(cfgte))
+ if (!pmcraid_expose_resource(fw_version, cfgte))
continue;
found = 0;
@@ -5263,10 +5694,12 @@ static void pmcraid_init_res_table(struct pmcraid_cmd *cmd)
*/
if (found) {
memcpy(&res->cfg_entry, cfgte,
- sizeof(struct pmcraid_config_table_entry));
+ pinstance->config_table_entry_size);
pmcraid_info("New res type:%x, vset:%x, addr:%x:\n",
res->cfg_entry.resource_type,
- res->cfg_entry.unique_flags1,
+ (fw_version <= PMCRAID_FW_VERSION_1 ?
+ res->cfg_entry.unique_flags1 :
+ res->cfg_entry.array_id & 0xFF),
le32_to_cpu(res->cfg_entry.resource_address));
}
}
@@ -5306,6 +5739,14 @@ static void pmcraid_querycfg(struct pmcraid_cmd *cmd)
struct pmcraid_instance *pinstance = cmd->drv_inst;
int cfg_table_size = cpu_to_be32(sizeof(struct pmcraid_config_table));
+ if (be16_to_cpu(pinstance->inq_data->fw_version) <=
+ PMCRAID_FW_VERSION_1)
+ pinstance->config_table_entry_size =
+ sizeof(struct pmcraid_config_table_entry);
+ else
+ pinstance->config_table_entry_size =
+ sizeof(struct pmcraid_config_table_entry_ext);
+
ioarcb->request_type = REQ_TYPE_IOACMD;
ioarcb->resource_handle = cpu_to_le32(PMCRAID_IOA_RES_HANDLE);
@@ -5338,7 +5779,7 @@ static void pmcraid_querycfg(struct pmcraid_cmd *cmd)
/**
- * pmcraid_probe - PCI probe entry pointer for PMC MaxRaid controller driver
+ * pmcraid_probe - PCI probe entry pointer for PMC MaxRAID controller driver
* @pdev: pointer to pci device structure
* @dev_id: pointer to device ids structure
*
@@ -5485,7 +5926,7 @@ static int __devinit pmcraid_probe(
*/
pmcraid_info("starting IOA initialization sequence\n");
if (pmcraid_reset_bringup(pinstance)) {
- dev_err(&pdev->dev, "couldn't initialize IOA \n");
+ dev_err(&pdev->dev, "couldn't initialize IOA\n");
rc = 1;
goto out_release_bufs;
}
diff --git a/drivers/scsi/pmcraid.h b/drivers/scsi/pmcraid.h
index b8ad07c3449..6cfa0145a1d 100644
--- a/drivers/scsi/pmcraid.h
+++ b/drivers/scsi/pmcraid.h
@@ -40,10 +40,12 @@
* Driver version: version string in major_version.minor_version.patch format
* Driver date : date information in "Mon dd yyyy" format
*/
-#define PMCRAID_DRIVER_NAME "PMC MaxRAID"
+#define PMCRAID_DRIVER_NAME "PMC MaxRAID"
#define PMCRAID_DEVFILE "pmcsas"
-#define PMCRAID_DRIVER_VERSION "1.0.2"
-#define PMCRAID_DRIVER_DATE __DATE__
+#define PMCRAID_DRIVER_VERSION "2.0.2"
+#define PMCRAID_DRIVER_DATE __DATE__
+
+#define PMCRAID_FW_VERSION_1 0x002
/* Maximum number of adapters supported by current version of the driver */
#define PMCRAID_MAX_ADAPTERS 1024
@@ -85,17 +87,17 @@
#define PMCRAID_IOARCB_ALIGNMENT 32
#define PMCRAID_IOADL_ALIGNMENT 16
#define PMCRAID_IOASA_ALIGNMENT 4
-#define PMCRAID_NUM_MSIX_VECTORS 1
+#define PMCRAID_NUM_MSIX_VECTORS 16
/* various other limits */
-#define PMCRAID_VENDOR_ID_LEN 8
-#define PMCRAID_PRODUCT_ID_LEN 16
-#define PMCRAID_SERIAL_NUM_LEN 8
-#define PMCRAID_LUN_LEN 8
-#define PMCRAID_MAX_CDB_LEN 16
-#define PMCRAID_DEVICE_ID_LEN 8
-#define PMCRAID_SENSE_DATA_LEN 256
-#define PMCRAID_ADD_CMD_PARAM_LEN 48
+#define PMCRAID_VENDOR_ID_LEN 8
+#define PMCRAID_PRODUCT_ID_LEN 16
+#define PMCRAID_SERIAL_NUM_LEN 8
+#define PMCRAID_LUN_LEN 8
+#define PMCRAID_MAX_CDB_LEN 16
+#define PMCRAID_DEVICE_ID_LEN 8
+#define PMCRAID_SENSE_DATA_LEN 256
+#define PMCRAID_ADD_CMD_PARAM_LEN 48
#define PMCRAID_MAX_BUS_TO_SCAN 1
#define PMCRAID_MAX_NUM_TARGETS_PER_BUS 256
@@ -116,17 +118,10 @@
#define PMCRAID_VSET_MAX_SECTORS 512
#define PMCRAID_MAX_CMD_PER_LUN 254
-/* Number of configuration table entries (resources) */
-#define PMCRAID_MAX_NUM_OF_VSETS 240
-
-/* Todo : Check max limit for Phase 1 */
-#define PMCRAID_MAX_NUM_OF_PHY_DEVS 256
-
-/* MAX_NUM_OF_DEVS includes 1 FP, 1 Dummy Enclosure device */
-#define PMCRAID_MAX_NUM_OF_DEVS \
- (PMCRAID_MAX_NUM_OF_VSETS + PMCRAID_MAX_NUM_OF_PHY_DEVS + 2)
-
-#define PMCRAID_MAX_RESOURCES PMCRAID_MAX_NUM_OF_DEVS
+/* Number of configuration table entries (resources), includes 1 FP,
+ * 1 Enclosure device
+ */
+#define PMCRAID_MAX_RESOURCES 256
/* Adapter Commands used by driver */
#define PMCRAID_QUERY_RESOURCE_STATE 0xC2
@@ -177,6 +172,7 @@
#define PMCRAID_IOASC_SENSE_STATUS(ioasc) ((ioasc) & 0x000000ff)
#define PMCRAID_IOASC_GOOD_COMPLETION 0x00000000
+#define PMCRAID_IOASC_GC_IOARCB_NOTFOUND 0x005A0000
#define PMCRAID_IOASC_NR_INIT_CMD_REQUIRED 0x02040200
#define PMCRAID_IOASC_NR_IOA_RESET_REQUIRED 0x02048000
#define PMCRAID_IOASC_NR_SYNC_REQUIRED 0x023F0000
@@ -187,12 +183,12 @@
#define PMCRAID_IOASC_HW_IOA_RESET_REQUIRED 0x04448600
#define PMCRAID_IOASC_IR_INVALID_RESOURCE_HANDLE 0x05250000
#define PMCRAID_IOASC_AC_TERMINATED_BY_HOST 0x0B5A0000
-#define PMCRAID_IOASC_UA_BUS_WAS_RESET 0x06290000
-#define PMCRAID_IOASC_UA_BUS_WAS_RESET_BY_OTHER 0x06298000
+#define PMCRAID_IOASC_UA_BUS_WAS_RESET 0x06290000
+#define PMCRAID_IOASC_UA_BUS_WAS_RESET_BY_OTHER 0x06298000
/* Driver defined IOASCs */
-#define PMCRAID_IOASC_IOA_WAS_RESET 0x10000001
-#define PMCRAID_IOASC_PCI_ACCESS_ERROR 0x10000002
+#define PMCRAID_IOASC_IOA_WAS_RESET 0x10000001
+#define PMCRAID_IOASC_PCI_ACCESS_ERROR 0x10000002
/* Various timeout values (in milliseconds) used. If any of these are chip
* specific, move them to pmcraid_chip_details structure.
@@ -336,6 +332,13 @@ struct pmcraid_config_table_entry {
__u8 lun[PMCRAID_LUN_LEN];
} __attribute__((packed, aligned(4)));
+/* extended configuration table sizes are of 64 bytes in size */
+#define PMCRAID_CFGTE_EXT_SIZE 32
+struct pmcraid_config_table_entry_ext {
+ struct pmcraid_config_table_entry cfgte;
+ __u8 cfgte_ext[PMCRAID_CFGTE_EXT_SIZE];
+};
+
/* resource types (config_table_entry.resource_type values) */
#define RES_TYPE_AF_DASD 0x00
#define RES_TYPE_GSCSI 0x01
@@ -376,7 +379,12 @@ struct pmcraid_config_table {
__u8 reserved1;
__u8 flags;
__u8 reserved2[11];
- struct pmcraid_config_table_entry entries[PMCRAID_MAX_RESOURCES];
+ union {
+ struct pmcraid_config_table_entry
+ entries[PMCRAID_MAX_RESOURCES];
+ struct pmcraid_config_table_entry_ext
+ entries_ext[PMCRAID_MAX_RESOURCES];
+ };
} __attribute__((packed, aligned(4)));
/* config_table.flags value */
@@ -385,7 +393,7 @@ struct pmcraid_config_table {
/*
* HCAM format
*/
-#define PMCRAID_HOSTRCB_LDNSIZE 4056
+#define PMCRAID_HOSTRCB_LDNSIZE 4056
/* Error log notification format */
struct pmcraid_hostrcb_error {
@@ -416,6 +424,15 @@ struct pmcraid_hcam_hdr {
struct pmcraid_hcam_ccn {
struct pmcraid_hcam_hdr header;
struct pmcraid_config_table_entry cfg_entry;
+ struct pmcraid_config_table_entry cfg_entry_old;
+} __attribute__((packed, aligned(4)));
+
+#define PMCRAID_CCN_EXT_SIZE 3944
+struct pmcraid_hcam_ccn_ext {
+ struct pmcraid_hcam_hdr header;
+ struct pmcraid_config_table_entry_ext cfg_entry;
+ struct pmcraid_config_table_entry_ext cfg_entry_old;
+ __u8 reserved[PMCRAID_CCN_EXT_SIZE];
} __attribute__((packed, aligned(4)));
struct pmcraid_hcam_ldn {
@@ -431,6 +448,8 @@ struct pmcraid_hcam_ldn {
#define NOTIFICATION_TYPE_ENTRY_CHANGED 0x0
#define NOTIFICATION_TYPE_ENTRY_NEW 0x1
#define NOTIFICATION_TYPE_ENTRY_DELETED 0x2
+#define NOTIFICATION_TYPE_STATE_CHANGE 0x3
+#define NOTIFICATION_TYPE_ENTRY_STATECHANGED 0x4
#define NOTIFICATION_TYPE_ERROR_LOG 0x10
#define NOTIFICATION_TYPE_INFORMATION_LOG 0x11
@@ -460,6 +479,7 @@ struct pmcraid_chip_details {
unsigned long mailbox;
unsigned long global_intr_mask;
unsigned long ioa_host_intr;
+ unsigned long ioa_host_msix_intr;
unsigned long ioa_host_intr_clr;
unsigned long ioa_host_mask;
unsigned long ioa_host_mask_clr;
@@ -482,6 +502,7 @@ struct pmcraid_chip_details {
#define INTRS_IOA_PROCESSOR_ERROR PMC_BIT32(29)
#define INTRS_HRRQ_VALID PMC_BIT32(30)
#define INTRS_OPERATIONAL_STATUS PMC_BIT32(0)
+#define INTRS_ALLOW_MSIX_VECTOR0 PMC_BIT32(31)
/* Host to IOA Doorbells */
#define DOORBELL_RUNTIME_RESET PMC_BIT32(1)
@@ -489,10 +510,12 @@ struct pmcraid_chip_details {
#define DOORBELL_IOA_DEBUG_ALERT PMC_BIT32(9)
#define DOORBELL_ENABLE_DESTRUCTIVE_DIAGS PMC_BIT32(8)
#define DOORBELL_IOA_START_BIST PMC_BIT32(23)
+#define DOORBELL_INTR_MODE_MSIX PMC_BIT32(25)
+#define DOORBELL_INTR_MSIX_CLR PMC_BIT32(26)
#define DOORBELL_RESET_IOA PMC_BIT32(31)
/* Global interrupt mask register value */
-#define GLOBAL_INTERRUPT_MASK 0x4ULL
+#define GLOBAL_INTERRUPT_MASK 0x5ULL
#define PMCRAID_ERROR_INTERRUPTS (INTRS_IOARCB_TRANSFER_FAILED | \
INTRS_IOA_UNIT_CHECK | \
@@ -503,8 +526,8 @@ struct pmcraid_chip_details {
#define PMCRAID_PCI_INTERRUPTS (PMCRAID_ERROR_INTERRUPTS | \
INTRS_HRRQ_VALID | \
- INTRS_CRITICAL_OP_IN_PROGRESS |\
- INTRS_TRANSITION_TO_OPERATIONAL)
+ INTRS_TRANSITION_TO_OPERATIONAL |\
+ INTRS_ALLOW_MSIX_VECTOR0)
/* control_block, associated with each of the commands contains IOARCB, IOADLs
* memory for IOASA. Additional 3 * 16 bytes are allocated in order to support
@@ -526,17 +549,24 @@ struct pmcraid_sglist {
struct scatterlist scatterlist[1];
};
+/* page D0 inquiry data of focal point resource */
+struct pmcraid_inquiry_data {
+ __u8 ph_dev_type;
+ __u8 page_code;
+ __u8 reserved1;
+ __u8 add_page_len;
+ __u8 length;
+ __u8 reserved2;
+ __le16 fw_version;
+ __u8 reserved3[16];
+};
+
/* pmcraid_cmd - LLD representation of SCSI command */
struct pmcraid_cmd {
/* Ptr and bus address of DMA.able control block for this command */
struct pmcraid_control_block *ioa_cb;
dma_addr_t ioa_cb_bus_addr;
-
- /* sense buffer for REQUEST SENSE command if firmware is not sending
- * auto sense data
- */
- dma_addr_t sense_buffer_dma;
dma_addr_t dma_handle;
u8 *sense_buffer;
@@ -556,11 +586,22 @@ struct pmcraid_cmd {
struct pmcraid_sglist *sglist; /* used for passthrough IOCTLs */
- /* scratch used during reset sequence */
+ /* scratch used */
union {
+ /* during reset sequence */
unsigned long time_left;
struct pmcraid_resource_entry *res;
- } u;
+ int hrrq_index;
+
+ /* used during IO command error handling. Sense buffer
+ * for REQUEST SENSE command if firmware is not sending
+ * auto sense data
+ */
+ struct {
+ u8 *sense_buffer;
+ dma_addr_t sense_buffer_dma;
+ };
+ };
};
/*
@@ -568,6 +609,7 @@ struct pmcraid_cmd {
*/
struct pmcraid_interrupts {
void __iomem *ioa_host_interrupt_reg;
+ void __iomem *ioa_host_msix_interrupt_reg;
void __iomem *ioa_host_interrupt_clr_reg;
void __iomem *ioa_host_interrupt_mask_reg;
void __iomem *ioa_host_interrupt_mask_clr_reg;
@@ -578,11 +620,12 @@ struct pmcraid_interrupts {
/* ISR parameters LLD allocates (one for each MSI-X if enabled) vectors */
struct pmcraid_isr_param {
- u8 hrrq_id; /* hrrq entry index */
- u16 vector; /* allocated msi-x vector */
struct pmcraid_instance *drv_inst;
+ u16 vector; /* allocated msi-x vector */
+ u8 hrrq_id; /* hrrq entry index */
};
+
/* AEN message header sent as part of event data to applications */
struct pmcraid_aen_msg {
u32 hostno;
@@ -591,6 +634,19 @@ struct pmcraid_aen_msg {
u8 data[0];
};
+/* Controller state event message type */
+struct pmcraid_state_msg {
+ struct pmcraid_aen_msg msg;
+ u32 ioa_state;
+};
+
+#define PMC_DEVICE_EVENT_RESET_START 0x11000000
+#define PMC_DEVICE_EVENT_RESET_SUCCESS 0x11000001
+#define PMC_DEVICE_EVENT_RESET_FAILED 0x11000002
+#define PMC_DEVICE_EVENT_SHUTDOWN_START 0x11000003
+#define PMC_DEVICE_EVENT_SHUTDOWN_SUCCESS 0x11000004
+#define PMC_DEVICE_EVENT_SHUTDOWN_FAILED 0x11000005
+
struct pmcraid_hostrcb {
struct pmcraid_instance *drv_inst;
struct pmcraid_aen_msg *msg;
@@ -628,6 +684,7 @@ struct pmcraid_instance {
/* HostRCBs needed for HCAM */
struct pmcraid_hostrcb ldn;
struct pmcraid_hostrcb ccn;
+ struct pmcraid_state_msg scn; /* controller state change msg */
/* Bus address of start of HRRQ */
@@ -645,12 +702,15 @@ struct pmcraid_instance {
/* Lock for HRRQ access */
spinlock_t hrrq_lock[PMCRAID_NUM_MSIX_VECTORS];
+ struct pmcraid_inquiry_data *inq_data;
+ dma_addr_t inq_data_baddr;
+
+ /* size of configuration table entry, varies based on the firmware */
+ u32 config_table_entry_size;
+
/* Expected toggle bit at host */
u8 host_toggle_bit[PMCRAID_NUM_MSIX_VECTORS];
- /* No of Reset IOA retries . IOA marked dead if threshold exceeds */
- u8 ioa_reset_attempts;
-#define PMCRAID_RESET_ATTEMPTS 3
/* Wait Q for threads to wait for Reset IOA completion */
wait_queue_head_t reset_wait_q;
@@ -664,14 +724,22 @@ struct pmcraid_instance {
struct Scsi_Host *host; /* mid layer interface structure handle */
struct pci_dev *pdev; /* PCI device structure handle */
+ /* No of Reset IOA retries . IOA marked dead if threshold exceeds */
+ u8 ioa_reset_attempts;
+#define PMCRAID_RESET_ATTEMPTS 3
+
u8 current_log_level; /* default level for logging IOASC errors */
u8 num_hrrq; /* Number of interrupt vectors allocated */
+ u8 interrupt_mode; /* current interrupt mode legacy or msix */
dev_t dev; /* Major-Minor numbers for Char device */
/* Used as ISR handler argument */
struct pmcraid_isr_param hrrq_vector[PMCRAID_NUM_MSIX_VECTORS];
+ /* Message id as filled in last fired IOARCB, used to identify HRRQ */
+ atomic_t last_message_id;
+
/* configuration table */
struct pmcraid_config_table *cfg_table;
dma_addr_t cfg_table_bus_addr;
@@ -686,8 +754,14 @@ struct pmcraid_instance {
struct list_head free_cmd_pool;
struct list_head pending_cmd_pool;
- spinlock_t free_pool_lock; /* free pool lock */
- spinlock_t pending_pool_lock; /* pending pool lock */
+ spinlock_t free_pool_lock; /* free pool lock */
+ spinlock_t pending_pool_lock; /* pending pool lock */
+
+ /* Tasklet to handle deferred processing */
+ struct tasklet_struct isr_tasklet[PMCRAID_NUM_MSIX_VECTORS];
+
+ /* Work-queue (Shared) for deferred reset processing */
+ struct work_struct worker_q;
/* No of IO commands pending with FW */
atomic_t outstanding_cmds;
@@ -695,11 +769,6 @@ struct pmcraid_instance {
/* should add/delete resources to mid-layer now ?*/
atomic_t expose_resources;
- /* Tasklet to handle deferred processing */
- struct tasklet_struct isr_tasklet[PMCRAID_NUM_MSIX_VECTORS];
-
- /* Work-queue (Shared) for deferred reset processing */
- struct work_struct worker_q;
u32 ioa_state:4; /* For IOA Reset sequence FSM */
@@ -728,7 +797,10 @@ struct pmcraid_instance {
/* LLD maintained resource entry structure */
struct pmcraid_resource_entry {
struct list_head queue; /* link to "to be exposed" resources */
- struct pmcraid_config_table_entry cfg_entry;
+ union {
+ struct pmcraid_config_table_entry cfg_entry;
+ struct pmcraid_config_table_entry_ext cfg_entry_ext;
+ };
struct scsi_device *scsi_dev; /* Link scsi_device structure */
atomic_t read_failures; /* count of failed READ commands */
atomic_t write_failures; /* count of failed WRITE commands */
@@ -771,73 +843,75 @@ struct pmcraid_ioasc_error {
* statically.
*/
static struct pmcraid_ioasc_error pmcraid_ioasc_error_table[] = {
- {0x01180600, IOASC_LOG_LEVEL_MUST,
+ {0x01180600, IOASC_LOG_LEVEL_HARD,
"Recovered Error, soft media error, sector reassignment suggested"},
- {0x015D0000, IOASC_LOG_LEVEL_MUST,
- "Recovered Error, failure prediction threshold exceeded"},
- {0x015D9200, IOASC_LOG_LEVEL_MUST,
- "Recovered Error, soft Cache Card Battery error threshold"},
- {0x015D9200, IOASC_LOG_LEVEL_MUST,
- "Recovered Error, soft Cache Card Battery error threshold"},
- {0x02048000, IOASC_LOG_LEVEL_MUST,
+ {0x015D0000, IOASC_LOG_LEVEL_HARD,
+ "Recovered Error, failure prediction thresold exceeded"},
+ {0x015D9200, IOASC_LOG_LEVEL_HARD,
+ "Recovered Error, soft Cache Card Battery error thresold"},
+ {0x015D9200, IOASC_LOG_LEVEL_HARD,
+ "Recovered Error, soft Cache Card Battery error thresold"},
+ {0x02048000, IOASC_LOG_LEVEL_HARD,
"Not Ready, IOA Reset Required"},
- {0x02408500, IOASC_LOG_LEVEL_MUST,
+ {0x02408500, IOASC_LOG_LEVEL_HARD,
"Not Ready, IOA microcode download required"},
- {0x03110B00, IOASC_LOG_LEVEL_MUST,
+ {0x03110B00, IOASC_LOG_LEVEL_HARD,
"Medium Error, data unreadable, reassignment suggested"},
{0x03110C00, IOASC_LOG_LEVEL_MUST,
"Medium Error, data unreadable do not reassign"},
- {0x03310000, IOASC_LOG_LEVEL_MUST,
+ {0x03310000, IOASC_LOG_LEVEL_HARD,
"Medium Error, media corrupted"},
- {0x04050000, IOASC_LOG_LEVEL_MUST,
+ {0x04050000, IOASC_LOG_LEVEL_HARD,
"Hardware Error, IOA can't communicate with device"},
{0x04080000, IOASC_LOG_LEVEL_MUST,
"Hardware Error, device bus error"},
- {0x04080000, IOASC_LOG_LEVEL_MUST,
+ {0x04088000, IOASC_LOG_LEVEL_MUST,
"Hardware Error, device bus is not functioning"},
- {0x04118000, IOASC_LOG_LEVEL_MUST,
+ {0x04118000, IOASC_LOG_LEVEL_HARD,
"Hardware Error, IOA reserved area data check"},
- {0x04118100, IOASC_LOG_LEVEL_MUST,
+ {0x04118100, IOASC_LOG_LEVEL_HARD,
"Hardware Error, IOA reserved area invalid data pattern"},
- {0x04118200, IOASC_LOG_LEVEL_MUST,
+ {0x04118200, IOASC_LOG_LEVEL_HARD,
"Hardware Error, IOA reserved area LRC error"},
- {0x04320000, IOASC_LOG_LEVEL_MUST,
+ {0x04320000, IOASC_LOG_LEVEL_HARD,
"Hardware Error, reassignment space exhausted"},
- {0x04330000, IOASC_LOG_LEVEL_MUST,
+ {0x04330000, IOASC_LOG_LEVEL_HARD,
"Hardware Error, data transfer underlength error"},
- {0x04330000, IOASC_LOG_LEVEL_MUST,
+ {0x04330000, IOASC_LOG_LEVEL_HARD,
"Hardware Error, data transfer overlength error"},
{0x04418000, IOASC_LOG_LEVEL_MUST,
"Hardware Error, PCI bus error"},
- {0x04440000, IOASC_LOG_LEVEL_MUST,
+ {0x04440000, IOASC_LOG_LEVEL_HARD,
"Hardware Error, device error"},
- {0x04448300, IOASC_LOG_LEVEL_MUST,
+ {0x04448200, IOASC_LOG_LEVEL_MUST,
+ "Hardware Error, IOA error"},
+ {0x04448300, IOASC_LOG_LEVEL_HARD,
"Hardware Error, undefined device response"},
- {0x04448400, IOASC_LOG_LEVEL_MUST,
+ {0x04448400, IOASC_LOG_LEVEL_HARD,
"Hardware Error, IOA microcode error"},
- {0x04448600, IOASC_LOG_LEVEL_MUST,
+ {0x04448600, IOASC_LOG_LEVEL_HARD,
"Hardware Error, IOA reset required"},
- {0x04449200, IOASC_LOG_LEVEL_MUST,
+ {0x04449200, IOASC_LOG_LEVEL_HARD,
"Hardware Error, hard Cache Fearuee Card Battery error"},
- {0x0444A000, IOASC_LOG_LEVEL_MUST,
+ {0x0444A000, IOASC_LOG_LEVEL_HARD,
"Hardware Error, failed device altered"},
- {0x0444A200, IOASC_LOG_LEVEL_MUST,
+ {0x0444A200, IOASC_LOG_LEVEL_HARD,
"Hardware Error, data check after reassignment"},
- {0x0444A300, IOASC_LOG_LEVEL_MUST,
+ {0x0444A300, IOASC_LOG_LEVEL_HARD,
"Hardware Error, LRC error after reassignment"},
- {0x044A0000, IOASC_LOG_LEVEL_MUST,
+ {0x044A0000, IOASC_LOG_LEVEL_HARD,
"Hardware Error, device bus error (msg/cmd phase)"},
- {0x04670400, IOASC_LOG_LEVEL_MUST,
+ {0x04670400, IOASC_LOG_LEVEL_HARD,
"Hardware Error, new device can't be used"},
- {0x04678000, IOASC_LOG_LEVEL_MUST,
+ {0x04678000, IOASC_LOG_LEVEL_HARD,
"Hardware Error, invalid multiadapter configuration"},
- {0x04678100, IOASC_LOG_LEVEL_MUST,
+ {0x04678100, IOASC_LOG_LEVEL_HARD,
"Hardware Error, incorrect connection between enclosures"},
- {0x04678200, IOASC_LOG_LEVEL_MUST,
+ {0x04678200, IOASC_LOG_LEVEL_HARD,
"Hardware Error, connections exceed IOA design limits"},
- {0x04678300, IOASC_LOG_LEVEL_MUST,
+ {0x04678300, IOASC_LOG_LEVEL_HARD,
"Hardware Error, incorrect multipath connection"},
- {0x04679000, IOASC_LOG_LEVEL_MUST,
+ {0x04679000, IOASC_LOG_LEVEL_HARD,
"Hardware Error, command to LUN failed"},
{0x064C8000, IOASC_LOG_LEVEL_HARD,
"Unit Attention, cache exists for missing/failed device"},
@@ -845,15 +919,15 @@ static struct pmcraid_ioasc_error pmcraid_ioasc_error_table[] = {
"Unit Attention, incompatible exposed mode device"},
{0x06670600, IOASC_LOG_LEVEL_HARD,
"Unit Attention, attachment of logical unit failed"},
- {0x06678000, IOASC_LOG_LEVEL_MUST,
+ {0x06678000, IOASC_LOG_LEVEL_HARD,
"Unit Attention, cables exceed connective design limit"},
- {0x06678300, IOASC_LOG_LEVEL_MUST,
+ {0x06678300, IOASC_LOG_LEVEL_HARD,
"Unit Attention, incomplete multipath connection between" \
"IOA and enclosure"},
- {0x06678400, IOASC_LOG_LEVEL_MUST,
+ {0x06678400, IOASC_LOG_LEVEL_HARD,
"Unit Attention, incomplete multipath connection between" \
"device and enclosure"},
- {0x06678500, IOASC_LOG_LEVEL_MUST,
+ {0x06678500, IOASC_LOG_LEVEL_HARD,
"Unit Attention, incomplete multipath connection between" \
"IOA and remote IOA"},
{0x06678600, IOASC_LOG_LEVEL_HARD,
@@ -863,11 +937,11 @@ static struct pmcraid_ioasc_error pmcraid_ioasc_error_table[] = {
"function"},
{0x06698200, IOASC_LOG_LEVEL_HARD,
"Unit Attention, corrupt array parity detected on device"},
- {0x066B0200, IOASC_LOG_LEVEL_MUST,
+ {0x066B0200, IOASC_LOG_LEVEL_HARD,
"Unit Attention, array exposed"},
{0x066B8200, IOASC_LOG_LEVEL_HARD,
"Unit Attention, exposed array is still protected"},
- {0x066B9200, IOASC_LOG_LEVEL_MUST,
+ {0x066B9200, IOASC_LOG_LEVEL_HARD,
"Unit Attention, Multipath redundancy level got worse"},
{0x07270000, IOASC_LOG_LEVEL_HARD,
"Data Protect, device is read/write protected by IOA"},
@@ -875,37 +949,37 @@ static struct pmcraid_ioasc_error pmcraid_ioasc_error_table[] = {
"Data Protect, IOA doesn't support device attribute"},
{0x07278100, IOASC_LOG_LEVEL_HARD,
"Data Protect, NVRAM mirroring prohibited"},
- {0x07278400, IOASC_LOG_LEVEL_MUST,
+ {0x07278400, IOASC_LOG_LEVEL_HARD,
"Data Protect, array is short 2 or more devices"},
- {0x07278600, IOASC_LOG_LEVEL_MUST,
+ {0x07278600, IOASC_LOG_LEVEL_HARD,
"Data Protect, exposed array is short a required device"},
- {0x07278700, IOASC_LOG_LEVEL_MUST,
+ {0x07278700, IOASC_LOG_LEVEL_HARD,
"Data Protect, array members not at required addresses"},
- {0x07278800, IOASC_LOG_LEVEL_MUST,
+ {0x07278800, IOASC_LOG_LEVEL_HARD,
"Data Protect, exposed mode device resource address conflict"},
- {0x07278900, IOASC_LOG_LEVEL_MUST,
+ {0x07278900, IOASC_LOG_LEVEL_HARD,
"Data Protect, incorrect resource address of exposed mode device"},
- {0x07278A00, IOASC_LOG_LEVEL_MUST,
+ {0x07278A00, IOASC_LOG_LEVEL_HARD,
"Data Protect, Array is missing a device and parity is out of sync"},
- {0x07278B00, IOASC_LOG_LEVEL_MUST,
+ {0x07278B00, IOASC_LOG_LEVEL_HARD,
"Data Protect, maximum number of arrays already exist"},
{0x07278C00, IOASC_LOG_LEVEL_HARD,
"Data Protect, cannot locate cache data for device"},
{0x07278D00, IOASC_LOG_LEVEL_HARD,
"Data Protect, cache data exits for a changed device"},
- {0x07279100, IOASC_LOG_LEVEL_MUST,
+ {0x07279100, IOASC_LOG_LEVEL_HARD,
"Data Protect, detection of a device requiring format"},
- {0x07279200, IOASC_LOG_LEVEL_MUST,
+ {0x07279200, IOASC_LOG_LEVEL_HARD,
"Data Protect, IOA exceeds maximum number of devices"},
- {0x07279600, IOASC_LOG_LEVEL_MUST,
+ {0x07279600, IOASC_LOG_LEVEL_HARD,
"Data Protect, missing array, volume set is not functional"},
- {0x07279700, IOASC_LOG_LEVEL_MUST,
+ {0x07279700, IOASC_LOG_LEVEL_HARD,
"Data Protect, single device for a volume set"},
- {0x07279800, IOASC_LOG_LEVEL_MUST,
+ {0x07279800, IOASC_LOG_LEVEL_HARD,
"Data Protect, missing multiple devices for a volume set"},
{0x07279900, IOASC_LOG_LEVEL_HARD,
"Data Protect, maximum number of volument sets already exists"},
- {0x07279A00, IOASC_LOG_LEVEL_MUST,
+ {0x07279A00, IOASC_LOG_LEVEL_HARD,
"Data Protect, other volume set problem"},
};
@@ -952,27 +1026,6 @@ struct pmcraid_ioctl_header {
#define PMCRAID_IOCTL_SIGNATURE "PMCRAID"
-
-/*
- * pmcraid_event_details - defines AEN details that apps can retrieve from LLD
- *
- * .rcb_ccn - complete RCB of CCN
- * .rcb_ldn - complete RCB of CCN
- */
-struct pmcraid_event_details {
- struct pmcraid_hcam_ccn rcb_ccn;
- struct pmcraid_hcam_ldn rcb_ldn;
-};
-
-/*
- * pmcraid_driver_ioctl_buffer - structure passed as argument to most of the
- * PMC driver handled ioctls.
- */
-struct pmcraid_driver_ioctl_buffer {
- struct pmcraid_ioctl_header ioctl_header;
- struct pmcraid_event_details event_details;
-};
-
/*
* pmcraid_passthrough_ioctl_buffer - structure given as argument to
* passthrough(or firmware handled) IOCTL commands. Note that ioarcb requires
diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c
index 1e4cafabba1..420238cc794 100644
--- a/drivers/scsi/qla2xxx/qla_attr.c
+++ b/drivers/scsi/qla2xxx/qla_attr.c
@@ -1,6 +1,6 @@
/*
* QLogic Fibre Channel HBA Driver
- * Copyright (c) 2003-2008 QLogic Corporation
+ * Copyright (c) 2003-2010 QLogic Corporation
*
* See LICENSE.qla2xxx for copyright and licensing details.
*/
@@ -1187,6 +1187,21 @@ qla2x00_optrom_fw_version_show(struct device *dev,
}
static ssize_t
+qla2x00_optrom_gold_fw_version_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
+ struct qla_hw_data *ha = vha->hw;
+
+ if (!IS_QLA81XX(ha))
+ return snprintf(buf, PAGE_SIZE, "\n");
+
+ return snprintf(buf, PAGE_SIZE, "%d.%02d.%02d (%d)\n",
+ ha->gold_fw_version[0], ha->gold_fw_version[1],
+ ha->gold_fw_version[2], ha->gold_fw_version[3]);
+}
+
+static ssize_t
qla2x00_total_isp_aborts_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
@@ -1208,7 +1223,7 @@ qla24xx_84xx_fw_version_show(struct device *dev,
if (!IS_QLA84XX(ha))
return snprintf(buf, PAGE_SIZE, "\n");
- if (ha->cs84xx && ha->cs84xx->op_fw_version == 0)
+ if (ha->cs84xx->op_fw_version == 0)
rval = qla84xx_verify_chip(vha, status);
if ((rval == QLA_SUCCESS) && (status[0] == 0))
@@ -1336,6 +1351,8 @@ static DEVICE_ATTR(optrom_fcode_version, S_IRUGO,
qla2x00_optrom_fcode_version_show, NULL);
static DEVICE_ATTR(optrom_fw_version, S_IRUGO, qla2x00_optrom_fw_version_show,
NULL);
+static DEVICE_ATTR(optrom_gold_fw_version, S_IRUGO,
+ qla2x00_optrom_gold_fw_version_show, NULL);
static DEVICE_ATTR(84xx_fw_version, S_IRUGO, qla24xx_84xx_fw_version_show,
NULL);
static DEVICE_ATTR(total_isp_aborts, S_IRUGO, qla2x00_total_isp_aborts_show,
@@ -1376,6 +1393,7 @@ struct device_attribute *qla2x00_host_attrs[] = {
&dev_attr_vn_port_mac_address,
&dev_attr_fabric_param,
&dev_attr_fw_state,
+ &dev_attr_optrom_gold_fw_version,
NULL,
};
@@ -1732,7 +1750,7 @@ qla24xx_vport_create(struct fc_vport *fc_vport, bool disable)
fc_vport_set_state(fc_vport, FC_VPORT_LINKDOWN);
}
- if (IS_QLA25XX(ha) && ql2xenabledif) {
+ if ((IS_QLA25XX(ha) || IS_QLA81XX(ha)) && ql2xenabledif) {
if (ha->fw_attributes & BIT_4) {
vha->flags.difdix_supported = 1;
DEBUG18(qla_printk(KERN_INFO, ha,
@@ -1740,8 +1758,10 @@ qla24xx_vport_create(struct fc_vport *fc_vport, bool disable)
" protection.\n"));
scsi_host_set_prot(vha->host,
SHOST_DIF_TYPE1_PROTECTION
+ | SHOST_DIF_TYPE2_PROTECTION
| SHOST_DIF_TYPE3_PROTECTION
| SHOST_DIX_TYPE1_PROTECTION
+ | SHOST_DIX_TYPE2_PROTECTION
| SHOST_DIX_TYPE3_PROTECTION);
scsi_host_set_guard(vha->host, SHOST_DIX_GUARD_CRC);
} else
@@ -1809,7 +1829,6 @@ static int
qla24xx_vport_delete(struct fc_vport *fc_vport)
{
scsi_qla_host_t *vha = fc_vport->dd_data;
- fc_port_t *fcport, *tfcport;
struct qla_hw_data *ha = vha->hw;
uint16_t id = vha->vp_idx;
@@ -1823,11 +1842,7 @@ qla24xx_vport_delete(struct fc_vport *fc_vport)
scsi_remove_host(vha->host);
- list_for_each_entry_safe(fcport, tfcport, &vha->vp_fcports, list) {
- list_del(&fcport->list);
- kfree(fcport);
- fcport = NULL;
- }
+ qla2x00_free_fcports(vha);
qla24xx_deallocate_vp_id(vha);
diff --git a/drivers/scsi/qla2xxx/qla_bsg.c b/drivers/scsi/qla2xxx/qla_bsg.c
index b905dfe5ea6..9067629817e 100644
--- a/drivers/scsi/qla2xxx/qla_bsg.c
+++ b/drivers/scsi/qla2xxx/qla_bsg.c
@@ -1,6 +1,6 @@
/*
* QLogic Fibre Channel HBA Driver
- * Copyright (c) 2003-2008 QLogic Corporation
+ * Copyright (c) 2003-2010 QLogic Corporation
*
* See LICENSE.qla2xxx for copyright and licensing details.
*/
@@ -41,13 +41,28 @@ qla24xx_fcp_prio_cfg_valid(struct qla_fcp_prio_cfg *pri_cfg, uint8_t flag)
int i, ret, num_valid;
uint8_t *bcode;
struct qla_fcp_prio_entry *pri_entry;
+ uint32_t *bcode_val_ptr, bcode_val;
ret = 1;
num_valid = 0;
bcode = (uint8_t *)pri_cfg;
+ bcode_val_ptr = (uint32_t *)pri_cfg;
+ bcode_val = (uint32_t)(*bcode_val_ptr);
- if (bcode[0x0] != 'H' || bcode[0x1] != 'Q' || bcode[0x2] != 'O' ||
- bcode[0x3] != 'S') {
+ if (bcode_val == 0xFFFFFFFF) {
+ /* No FCP Priority config data in flash */
+ DEBUG2(printk(KERN_INFO
+ "%s: No FCP priority config data.\n",
+ __func__));
+ return 0;
+ }
+
+ if (bcode[0] != 'H' || bcode[1] != 'Q' || bcode[2] != 'O' ||
+ bcode[3] != 'S') {
+ /* Invalid FCP priority data header*/
+ DEBUG2(printk(KERN_ERR
+ "%s: Invalid FCP Priority data header. bcode=0x%x\n",
+ __func__, bcode_val));
return 0;
}
if (flag != 1)
@@ -60,8 +75,18 @@ qla24xx_fcp_prio_cfg_valid(struct qla_fcp_prio_cfg *pri_cfg, uint8_t flag)
pri_entry++;
}
- if (num_valid == 0)
+ if (num_valid == 0) {
+ /* No valid FCP priority data entries */
+ DEBUG2(printk(KERN_ERR
+ "%s: No valid FCP Priority data entries.\n",
+ __func__));
ret = 0;
+ } else {
+ /* FCP priority data is valid */
+ DEBUG2(printk(KERN_INFO
+ "%s: Valid FCP priority data. num entries = %d\n",
+ __func__, num_valid));
+ }
return ret;
}
@@ -78,6 +103,11 @@ qla24xx_proc_fcp_prio_cfg_cmd(struct fc_bsg_job *bsg_job)
bsg_job->reply->reply_payload_rcv_len = 0;
+ if (!IS_QLA24XX_TYPE(ha) || !IS_QLA25XX(ha)) {
+ ret = -EINVAL;
+ goto exit_fcp_prio_cfg;
+ }
+
if (test_bit(ISP_ABORT_NEEDED, &vha->dpc_flags) ||
test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags) ||
test_bit(ISP_ABORT_RETRY, &vha->dpc_flags)) {
@@ -199,7 +229,7 @@ static int
qla2x00_process_els(struct fc_bsg_job *bsg_job)
{
struct fc_rport *rport;
- fc_port_t *fcport;
+ fc_port_t *fcport = NULL;
struct Scsi_Host *host;
scsi_qla_host_t *vha;
struct qla_hw_data *ha;
@@ -210,6 +240,29 @@ qla2x00_process_els(struct fc_bsg_job *bsg_job)
uint16_t nextlid = 0;
struct srb_ctx *els;
+ if (bsg_job->request->msgcode == FC_BSG_RPT_ELS) {
+ rport = bsg_job->rport;
+ fcport = *(fc_port_t **) rport->dd_data;
+ host = rport_to_shost(rport);
+ vha = shost_priv(host);
+ ha = vha->hw;
+ type = "FC_BSG_RPT_ELS";
+ } else {
+ host = bsg_job->shost;
+ vha = shost_priv(host);
+ ha = vha->hw;
+ type = "FC_BSG_HST_ELS_NOLOGIN";
+ }
+
+ /* pass through is supported only for ISP 4Gb or higher */
+ if (!IS_FWI2_CAPABLE(ha)) {
+ DEBUG2(qla_printk(KERN_INFO, ha,
+ "scsi(%ld):ELS passthru not supported for ISP23xx based "
+ "adapters\n", vha->host_no));
+ rval = -EPERM;
+ goto done;
+ }
+
/* Multiple SG's are not supported for ELS requests */
if (bsg_job->request_payload.sg_cnt > 1 ||
bsg_job->reply_payload.sg_cnt > 1) {
@@ -224,13 +277,6 @@ qla2x00_process_els(struct fc_bsg_job *bsg_job)
/* ELS request for rport */
if (bsg_job->request->msgcode == FC_BSG_RPT_ELS) {
- rport = bsg_job->rport;
- fcport = *(fc_port_t **) rport->dd_data;
- host = rport_to_shost(rport);
- vha = shost_priv(host);
- ha = vha->hw;
- type = "FC_BSG_RPT_ELS";
-
/* make sure the rport is logged in,
* if not perform fabric login
*/
@@ -242,11 +288,6 @@ qla2x00_process_els(struct fc_bsg_job *bsg_job)
goto done;
}
} else {
- host = bsg_job->shost;
- vha = shost_priv(host);
- ha = vha->hw;
- type = "FC_BSG_HST_ELS_NOLOGIN";
-
/* Allocate a dummy fcport structure, since functions
* preparing the IOCB and mailbox command retrieves port
* specific information from fcport structure. For Host based
@@ -366,15 +407,6 @@ qla2x00_process_ct(struct fc_bsg_job *bsg_job)
char *type = "FC_BSG_HST_CT";
struct srb_ctx *ct;
- /* pass through is supported only for ISP 4Gb or higher */
- if (!IS_FWI2_CAPABLE(ha)) {
- DEBUG2(qla_printk(KERN_INFO, ha,
- "scsi(%ld):Firmware is not capable to support FC "
- "CT pass thru\n", vha->host_no));
- rval = -EPERM;
- goto done;
- }
-
req_sg_cnt =
dma_map_sg(&ha->pdev->dev, bsg_job->request_payload.sg_list,
bsg_job->request_payload.sg_cnt, DMA_TO_DEVICE);
@@ -483,6 +515,98 @@ done:
return rval;
}
+/* Set the port configuration to enable the
+ * internal loopback on ISP81XX
+ */
+static inline int
+qla81xx_set_internal_loopback(scsi_qla_host_t *vha, uint16_t *config,
+ uint16_t *new_config)
+{
+ int ret = 0;
+ int rval = 0;
+ struct qla_hw_data *ha = vha->hw;
+
+ if (!IS_QLA81XX(ha))
+ goto done_set_internal;
+
+ new_config[0] = config[0] | (ENABLE_INTERNAL_LOOPBACK << 1);
+ memcpy(&new_config[1], &config[1], sizeof(uint16_t) * 3) ;
+
+ ha->notify_dcbx_comp = 1;
+ ret = qla81xx_set_port_config(vha, new_config);
+ if (ret != QLA_SUCCESS) {
+ DEBUG2(printk(KERN_ERR
+ "%s(%lu): Set port config failed\n",
+ __func__, vha->host_no));
+ ha->notify_dcbx_comp = 0;
+ rval = -EINVAL;
+ goto done_set_internal;
+ }
+
+ /* Wait for DCBX complete event */
+ if (!wait_for_completion_timeout(&ha->dcbx_comp, (20 * HZ))) {
+ DEBUG2(qla_printk(KERN_WARNING, ha,
+ "State change notificaition not received.\n"));
+ } else
+ DEBUG2(qla_printk(KERN_INFO, ha,
+ "State change RECEIVED\n"));
+
+ ha->notify_dcbx_comp = 0;
+
+done_set_internal:
+ return rval;
+}
+
+/* Set the port configuration to disable the
+ * internal loopback on ISP81XX
+ */
+static inline int
+qla81xx_reset_internal_loopback(scsi_qla_host_t *vha, uint16_t *config,
+ int wait)
+{
+ int ret = 0;
+ int rval = 0;
+ uint16_t new_config[4];
+ struct qla_hw_data *ha = vha->hw;
+
+ if (!IS_QLA81XX(ha))
+ goto done_reset_internal;
+
+ memset(new_config, 0 , sizeof(new_config));
+ if ((config[0] & INTERNAL_LOOPBACK_MASK) >> 1 ==
+ ENABLE_INTERNAL_LOOPBACK) {
+ new_config[0] = config[0] & ~INTERNAL_LOOPBACK_MASK;
+ memcpy(&new_config[1], &config[1], sizeof(uint16_t) * 3) ;
+
+ ha->notify_dcbx_comp = wait;
+ ret = qla81xx_set_port_config(vha, new_config);
+ if (ret != QLA_SUCCESS) {
+ DEBUG2(printk(KERN_ERR
+ "%s(%lu): Set port config failed\n",
+ __func__, vha->host_no));
+ ha->notify_dcbx_comp = 0;
+ rval = -EINVAL;
+ goto done_reset_internal;
+ }
+
+ /* Wait for DCBX complete event */
+ if (wait && !wait_for_completion_timeout(&ha->dcbx_comp,
+ (20 * HZ))) {
+ DEBUG2(qla_printk(KERN_WARNING, ha,
+ "State change notificaition not received.\n"));
+ ha->notify_dcbx_comp = 0;
+ rval = -EINVAL;
+ goto done_reset_internal;
+ } else
+ DEBUG2(qla_printk(KERN_INFO, ha,
+ "State change RECEIVED\n"));
+
+ ha->notify_dcbx_comp = 0;
+ }
+done_reset_internal:
+ return rval;
+}
+
static int
qla2x00_process_loopback(struct fc_bsg_job *bsg_job)
{
@@ -494,6 +618,7 @@ qla2x00_process_loopback(struct fc_bsg_job *bsg_job)
char *type;
struct msg_echo_lb elreq;
uint16_t response[MAILBOX_REGISTER_COUNT];
+ uint16_t config[4], new_config[4];
uint8_t *fw_sts_ptr;
uint8_t *req_data = NULL;
dma_addr_t req_data_dma;
@@ -568,29 +693,102 @@ qla2x00_process_loopback(struct fc_bsg_job *bsg_job)
elreq.options = bsg_job->request->rqst_data.h_vendor.vendor_cmd[1];
- if (ha->current_topology != ISP_CFG_F) {
- type = "FC_BSG_HST_VENDOR_LOOPBACK";
+ if ((ha->current_topology == ISP_CFG_F ||
+ (IS_QLA81XX(ha) &&
+ le32_to_cpu(*(uint32_t *)req_data) == ELS_OPCODE_BYTE
+ && req_data_len == MAX_ELS_FRAME_PAYLOAD)) &&
+ elreq.options == EXTERNAL_LOOPBACK) {
+ type = "FC_BSG_HST_VENDOR_ECHO_DIAG";
DEBUG2(qla_printk(KERN_INFO, ha,
- "scsi(%ld) bsg rqst type: %s\n",
- vha->host_no, type));
-
- command_sent = INT_DEF_LB_LOOPBACK_CMD;
- rval = qla2x00_loopback_test(vha, &elreq, response);
+ "scsi(%ld) bsg rqst type: %s\n", vha->host_no, type));
+ command_sent = INT_DEF_LB_ECHO_CMD;
+ rval = qla2x00_echo_test(vha, &elreq, response);
+ } else {
if (IS_QLA81XX(ha)) {
+ memset(config, 0, sizeof(config));
+ memset(new_config, 0, sizeof(new_config));
+ if (qla81xx_get_port_config(vha, config)) {
+ DEBUG2(printk(KERN_ERR
+ "%s(%lu): Get port config failed\n",
+ __func__, vha->host_no));
+ bsg_job->reply->reply_payload_rcv_len = 0;
+ bsg_job->reply->result = (DID_ERROR << 16);
+ rval = -EPERM;
+ goto done_free_dma_req;
+ }
+
+ if (elreq.options != EXTERNAL_LOOPBACK) {
+ DEBUG2(qla_printk(KERN_INFO, ha,
+ "Internal: current port config = %x\n",
+ config[0]));
+ if (qla81xx_set_internal_loopback(vha, config,
+ new_config)) {
+ bsg_job->reply->reply_payload_rcv_len =
+ 0;
+ bsg_job->reply->result =
+ (DID_ERROR << 16);
+ rval = -EPERM;
+ goto done_free_dma_req;
+ }
+ } else {
+ /* For external loopback to work
+ * ensure internal loopback is disabled
+ */
+ if (qla81xx_reset_internal_loopback(vha,
+ config, 1)) {
+ bsg_job->reply->reply_payload_rcv_len =
+ 0;
+ bsg_job->reply->result =
+ (DID_ERROR << 16);
+ rval = -EPERM;
+ goto done_free_dma_req;
+ }
+ }
+
+ type = "FC_BSG_HST_VENDOR_LOOPBACK";
+ DEBUG2(qla_printk(KERN_INFO, ha,
+ "scsi(%ld) bsg rqst type: %s\n",
+ vha->host_no, type));
+
+ command_sent = INT_DEF_LB_LOOPBACK_CMD;
+ rval = qla2x00_loopback_test(vha, &elreq, response);
+
+ if (new_config[1]) {
+ /* Revert back to original port config
+ * Also clear internal loopback
+ */
+ qla81xx_reset_internal_loopback(vha,
+ new_config, 0);
+ }
+
if (response[0] == MBS_COMMAND_ERROR &&
- response[1] == MBS_LB_RESET) {
+ response[1] == MBS_LB_RESET) {
DEBUG2(printk(KERN_ERR "%s(%ld): ABORTing "
- "ISP\n", __func__, vha->host_no));
+ "ISP\n", __func__, vha->host_no));
set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
qla2xxx_wake_dpc(vha);
+ qla2x00_wait_for_chip_reset(vha);
+ /* Also reset the MPI */
+ if (qla81xx_restart_mpi_firmware(vha) !=
+ QLA_SUCCESS) {
+ qla_printk(KERN_INFO, ha,
+ "MPI reset failed for host%ld.\n",
+ vha->host_no);
+ }
+
+ bsg_job->reply->reply_payload_rcv_len = 0;
+ bsg_job->reply->result = (DID_ERROR << 16);
+ rval = -EIO;
+ goto done_free_dma_req;
}
+ } else {
+ type = "FC_BSG_HST_VENDOR_LOOPBACK";
+ DEBUG2(qla_printk(KERN_INFO, ha,
+ "scsi(%ld) bsg rqst type: %s\n",
+ vha->host_no, type));
+ command_sent = INT_DEF_LB_LOOPBACK_CMD;
+ rval = qla2x00_loopback_test(vha, &elreq, response);
}
- } else {
- type = "FC_BSG_HST_VENDOR_ECHO_DIAG";
- DEBUG2(qla_printk(KERN_INFO, ha,
- "scsi(%ld) bsg rqst type: %s\n", vha->host_no, type));
- command_sent = INT_DEF_LB_ECHO_CMD;
- rval = qla2x00_echo_test(vha, &elreq, response);
}
if (rval) {
@@ -1056,6 +1254,20 @@ qla24xx_iidma(struct fc_bsg_job *bsg_job)
return -EINVAL;
}
+ if (fcport->loop_id == FC_NO_LOOP_ID) {
+ DEBUG2(printk(KERN_ERR "%s(%ld): Invalid port loop id, "
+ "loop_id = 0x%x\n",
+ __func__, vha->host_no, fcport->loop_id));
+ return -EINVAL;
+ }
+
+ if (fcport->flags & FCF_LOGIN_NEEDED) {
+ DEBUG2(printk(KERN_ERR "%s(%ld): Remote port not logged in, "
+ "flags = 0x%x\n",
+ __func__, vha->host_no, fcport->flags));
+ return -EINVAL;
+ }
+
if (port_param->mode)
rval = qla2x00_set_idma_speed(vha, fcport->loop_id,
port_param->speed, mb);
diff --git a/drivers/scsi/qla2xxx/qla_bsg.h b/drivers/scsi/qla2xxx/qla_bsg.h
index 76ed92dd2ef..cc7c52f87a1 100644
--- a/drivers/scsi/qla2xxx/qla_bsg.h
+++ b/drivers/scsi/qla2xxx/qla_bsg.h
@@ -1,6 +1,6 @@
/*
* QLogic Fibre Channel HBA Driver
- * Copyright (c) 2003-2008 QLogic Corporation
+ * Copyright (c) 2003-2010 QLogic Corporation
*
* See LICENSE.qla2xxx for copyright and licensing details.
*/
@@ -19,6 +19,13 @@
#define INT_DEF_LB_LOOPBACK_CMD 0
#define INT_DEF_LB_ECHO_CMD 1
+/* Loopback related definations */
+#define EXTERNAL_LOOPBACK 0xF2
+#define ENABLE_INTERNAL_LOOPBACK 0x02
+#define INTERNAL_LOOPBACK_MASK 0x000E
+#define MAX_ELS_FRAME_PAYLOAD 252
+#define ELS_OPCODE_BYTE 0x10
+
/* BSG Vendor specific definations */
#define A84_ISSUE_WRITE_TYPE_CMD 0
#define A84_ISSUE_READ_TYPE_CMD 1
diff --git a/drivers/scsi/qla2xxx/qla_dbg.c b/drivers/scsi/qla2xxx/qla_dbg.c
index 2afc8a362f2..09614114825 100644
--- a/drivers/scsi/qla2xxx/qla_dbg.c
+++ b/drivers/scsi/qla2xxx/qla_dbg.c
@@ -1,6 +1,6 @@
/*
* QLogic Fibre Channel HBA Driver
- * Copyright (c) 2003-2008 QLogic Corporation
+ * Copyright (c) 2003-2010 QLogic Corporation
*
* See LICENSE.qla2xxx for copyright and licensing details.
*/
diff --git a/drivers/scsi/qla2xxx/qla_dbg.h b/drivers/scsi/qla2xxx/qla_dbg.h
index 916c81f3f55..6cfc28a25eb 100644
--- a/drivers/scsi/qla2xxx/qla_dbg.h
+++ b/drivers/scsi/qla2xxx/qla_dbg.h
@@ -1,6 +1,6 @@
/*
* QLogic Fibre Channel HBA Driver
- * Copyright (c) 2003-2008 QLogic Corporation
+ * Copyright (c) 2003-2010 QLogic Corporation
*
* See LICENSE.qla2xxx for copyright and licensing details.
*/
diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h
index 83961090901..3a432ea0c7a 100644
--- a/drivers/scsi/qla2xxx/qla_def.h
+++ b/drivers/scsi/qla2xxx/qla_def.h
@@ -1,6 +1,6 @@
/*
* QLogic Fibre Channel HBA Driver
- * Copyright (c) 2003-2008 QLogic Corporation
+ * Copyright (c) 2003-2010 QLogic Corporation
*
* See LICENSE.qla2xxx for copyright and licensing details.
*/
@@ -202,6 +202,7 @@ struct sd_dif_tuple {
* SCSI Request Block
*/
typedef struct srb {
+ atomic_t ref_count;
struct fc_port *fcport;
uint32_t handle;
@@ -249,16 +250,6 @@ struct srb_iocb {
uint32_t lun;
uint32_t data;
} tmf;
- struct {
- /*
- * values for modif field below are as
- * defined in mrk_entry_24xx struct
- * for the modifier field in qla_fw.h.
- */
- uint8_t modif;
- uint16_t lun;
- uint32_t data;
- } marker;
} u;
struct timer_list timer;
@@ -276,7 +267,6 @@ struct srb_iocb {
#define SRB_CT_CMD 5
#define SRB_ADISC_CMD 6
#define SRB_TM_CMD 7
-#define SRB_MARKER_CMD 8
struct srb_ctx {
uint16_t type;
@@ -713,6 +703,8 @@ typedef struct {
#define MBC_SEND_RNFT_ELS 0x5e /* Send RNFT ELS request */
#define MBC_GET_LINK_PRIV_STATS 0x6d /* Get link & private data. */
#define MBC_SET_VENDOR_ID 0x76 /* Set Vendor ID. */
+#define MBC_SET_PORT_CONFIG 0x122 /* Set port configuration */
+#define MBC_GET_PORT_CONFIG 0x123 /* Get port configuration */
/* Firmware return data sizes */
#define FCAL_MAP_SIZE 128
@@ -1660,8 +1652,14 @@ typedef struct {
uint8_t port_name[WWN_SIZE];
uint8_t fabric_port_name[WWN_SIZE];
uint16_t fp_speed;
+ uint8_t fc4_type;
} sw_info_t;
+/* FCP-4 types */
+#define FC4_TYPE_FCP_SCSI 0x08
+#define FC4_TYPE_OTHER 0x0
+#define FC4_TYPE_UNKNOWN 0xff
+
/*
* Fibre channel port type.
*/
@@ -1705,6 +1703,7 @@ typedef struct fc_port {
u32 supported_classes;
uint16_t vp_idx;
+ uint8_t fc4_type;
} fc_port_t;
/*
@@ -1787,6 +1786,9 @@ typedef struct fc_port {
#define GPSC_REQ_SIZE (16 + 8)
#define GPSC_RSP_SIZE (16 + 2 + 2)
+#define GFF_ID_CMD 0x011F
+#define GFF_ID_REQ_SIZE (16 + 4)
+#define GFF_ID_RSP_SIZE (16 + 128)
/*
* HBA attribute types.
@@ -1988,6 +1990,11 @@ struct ct_sns_req {
struct {
uint8_t port_name[8];
} gpsc;
+
+ struct {
+ uint8_t reserved;
+ uint8_t port_name[3];
+ } gff_id;
} req;
};
@@ -2060,6 +2067,11 @@ struct ct_sns_rsp {
uint16_t speeds;
uint16_t speed;
} gpsc;
+
+#define GFF_FCP_SCSI_OFFSET 7
+ struct {
+ uint8_t fc4_features[128];
+ } gff_id;
} rsp;
};
@@ -2410,6 +2422,7 @@ struct qla_hw_data {
uint32_t cpu_affinity_enabled :1;
uint32_t disable_msix_handshake :1;
uint32_t fcp_prio_enabled :1;
+ uint32_t fw_hung :1;
} flags;
/* This spinlock is used to protect "io transactions", you must
@@ -2630,6 +2643,8 @@ struct qla_hw_data {
struct mutex vport_lock; /* Virtual port synchronization */
struct completion mbx_cmd_comp; /* Serialize mbx access */
struct completion mbx_intr_comp; /* Used for completion notification */
+ struct completion dcbx_comp; /* For set port config notification */
+ int notify_dcbx_comp;
/* Basic firmware related information. */
uint16_t fw_major_version;
@@ -2699,6 +2714,8 @@ struct qla_hw_data {
uint8_t fcode_revision[16];
uint32_t fw_revision[4];
+ uint32_t gold_fw_version[4];
+
/* Offsets for flash/nvram access (set to ~0 if not used). */
uint32_t flash_conf_off;
uint32_t flash_data_off;
@@ -2783,6 +2800,9 @@ struct qla_hw_data {
uint16_t gbl_dsd_avail;
struct list_head gbl_dsd_list;
#define NUM_DSD_CHAIN 4096
+
+ uint8_t fw_type;
+ __le32 file_prd_off; /* File firmware product offset */
};
/*
@@ -2961,9 +2981,15 @@ typedef struct scsi_qla_host {
#define QLA_DSDS_PER_IOCB 37
+#define CMD_SP(Cmnd) ((Cmnd)->SCp.ptr)
+
+enum nexus_wait_type {
+ WAIT_HOST = 0,
+ WAIT_TARGET,
+ WAIT_LUN,
+};
+
#include "qla_gbl.h"
#include "qla_dbg.h"
#include "qla_inline.h"
-
-#define CMD_SP(Cmnd) ((Cmnd)->SCp.ptr)
#endif
diff --git a/drivers/scsi/qla2xxx/qla_dfs.c b/drivers/scsi/qla2xxx/qla_dfs.c
index 3a9a6ca4226..6271353e8c5 100644
--- a/drivers/scsi/qla2xxx/qla_dfs.c
+++ b/drivers/scsi/qla2xxx/qla_dfs.c
@@ -1,6 +1,6 @@
/*
* QLogic Fibre Channel HBA Driver
- * Copyright (c) 2003-2008 QLogic Corporation
+ * Copyright (c) 2003-2010 QLogic Corporation
*
* See LICENSE.qla2xxx for copyright and licensing details.
*/
diff --git a/drivers/scsi/qla2xxx/qla_fw.h b/drivers/scsi/qla2xxx/qla_fw.h
index 93f83396014..631fefc8482 100644
--- a/drivers/scsi/qla2xxx/qla_fw.h
+++ b/drivers/scsi/qla2xxx/qla_fw.h
@@ -1,6 +1,6 @@
/*
* QLogic Fibre Channel HBA Driver
- * Copyright (c) 2003-2008 QLogic Corporation
+ * Copyright (c) 2003-2010 QLogic Corporation
*
* See LICENSE.qla2xxx for copyright and licensing details.
*/
diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h
index 8217c3bcbc2..1a1b281cea3 100644
--- a/drivers/scsi/qla2xxx/qla_gbl.h
+++ b/drivers/scsi/qla2xxx/qla_gbl.h
@@ -1,6 +1,6 @@
/*
* QLogic Fibre Channel HBA Driver
- * Copyright (c) 2003-2008 QLogic Corporation
+ * Copyright (c) 2003-2010 QLogic Corporation
*
* See LICENSE.qla2xxx for copyright and licensing details.
*/
@@ -59,7 +59,6 @@ extern int qla2x00_async_logout(struct scsi_qla_host *, fc_port_t *);
extern int qla2x00_async_adisc(struct scsi_qla_host *, fc_port_t *,
uint16_t *);
extern int qla2x00_async_tm_cmd(fc_port_t *, uint32_t, uint32_t, uint32_t);
-extern int qla2x00_async_marker(fc_port_t *, uint16_t, uint8_t);
extern void qla2x00_async_login_done(struct scsi_qla_host *, fc_port_t *,
uint16_t *);
extern void qla2x00_async_logout_done(struct scsi_qla_host *, fc_port_t *,
@@ -68,8 +67,7 @@ extern void qla2x00_async_adisc_done(struct scsi_qla_host *, fc_port_t *,
uint16_t *);
extern void qla2x00_async_tm_cmd_done(struct scsi_qla_host *, fc_port_t *,
struct srb_iocb *);
-extern void qla2x00_async_marker_done(struct scsi_qla_host *, fc_port_t *,
- struct srb_iocb *);
+extern void *qla2x00_alloc_iocbs(struct scsi_qla_host *, srb_t *);
extern fc_port_t *
qla2x00_alloc_fcport(scsi_qla_host_t *, gfp_t );
@@ -124,6 +122,7 @@ extern struct scsi_qla_host *qla2x00_create_host(struct scsi_host_template *,
extern void qla2x00_free_host(struct scsi_qla_host *);
extern void qla2x00_relogin(struct scsi_qla_host *);
extern void qla2x00_do_work(struct scsi_qla_host *);
+extern void qla2x00_free_fcports(struct scsi_qla_host *);
/*
* Global Functions in qla_mid.c source file.
@@ -176,10 +175,7 @@ extern int qla2x00_start_scsi(srb_t *sp);
extern int qla24xx_start_scsi(srb_t *sp);
int qla2x00_marker(struct scsi_qla_host *, struct req_que *, struct rsp_que *,
uint16_t, uint16_t, uint8_t);
-int __qla2x00_marker(struct scsi_qla_host *, struct req_que *, struct rsp_que *,
- uint16_t, uint16_t, uint8_t);
extern int qla2x00_start_sp(srb_t *);
-extern void qla2x00_ctx_sp_free(srb_t *);
extern uint16_t qla24xx_calc_iocbs(uint16_t);
extern void qla24xx_build_scsi_iocbs(srb_t *, struct cmd_type_7 *, uint16_t);
extern int qla24xx_dif_start_scsi(srb_t *);
@@ -293,7 +289,9 @@ extern int
qla24xx_abort_target(struct fc_port *, unsigned int, int);
extern int
qla24xx_lun_reset(struct fc_port *, unsigned int, int);
-
+extern int
+qla2x00_eh_wait_for_pending_commands(scsi_qla_host_t *, unsigned int,
+ unsigned int, enum nexus_wait_type);
extern int
qla2x00_system_error(scsi_qla_host_t *);
@@ -357,6 +355,11 @@ qla2x00_write_ram_word(scsi_qla_host_t *, uint32_t, uint32_t);
extern int qla2x00_get_data_rate(scsi_qla_host_t *);
extern int qla24xx_set_fcp_prio(scsi_qla_host_t *, uint16_t, uint16_t,
uint16_t *);
+extern int
+qla81xx_get_port_config(scsi_qla_host_t *, uint16_t *);
+
+extern int
+qla81xx_set_port_config(scsi_qla_host_t *, uint16_t *);
/*
* Global Function Prototypes in qla_isr.c source file.
@@ -438,6 +441,7 @@ extern int qla2x00_ga_nxt(scsi_qla_host_t *, fc_port_t *);
extern int qla2x00_gid_pt(scsi_qla_host_t *, sw_info_t *);
extern int qla2x00_gpn_id(scsi_qla_host_t *, sw_info_t *);
extern int qla2x00_gnn_id(scsi_qla_host_t *, sw_info_t *);
+extern void qla2x00_gff_id(scsi_qla_host_t *, sw_info_t *);
extern int qla2x00_rft_id(scsi_qla_host_t *);
extern int qla2x00_rff_id(scsi_qla_host_t *);
extern int qla2x00_rnn_id(scsi_qla_host_t *);
@@ -482,11 +486,8 @@ extern int qla25xx_create_req_que(struct qla_hw_data *, uint16_t, uint8_t,
uint16_t, int, uint8_t);
extern int qla25xx_create_rsp_que(struct qla_hw_data *, uint16_t, uint8_t,
uint16_t, int);
-extern int qla25xx_update_req_que(struct scsi_qla_host *, uint8_t, uint8_t);
extern void qla2x00_init_response_q_entries(struct rsp_que *);
extern int qla25xx_delete_req_que(struct scsi_qla_host *, struct req_que *);
-extern int qla25xx_delete_rsp_que(struct scsi_qla_host *, struct rsp_que *);
-extern int qla25xx_create_queues(struct scsi_qla_host *, uint8_t);
extern int qla25xx_delete_queues(struct scsi_qla_host *);
extern uint16_t qla24xx_rd_req_reg(struct qla_hw_data *, uint16_t);
extern uint16_t qla25xx_rd_req_reg(struct qla_hw_data *, uint16_t);
@@ -503,17 +504,12 @@ extern int qla82xx_pci_mem_read_2M(struct qla_hw_data *, u64, void *, int);
extern int qla82xx_pci_mem_write_2M(struct qla_hw_data *, u64, void *, int);
extern char *qla82xx_pci_info_str(struct scsi_qla_host *, char *);
extern int qla82xx_pci_region_offset(struct pci_dev *, int);
-extern int qla82xx_pci_region_len(struct pci_dev *, int);
extern int qla82xx_iospace_config(struct qla_hw_data *);
/* Initialization related functions */
extern void qla82xx_reset_chip(struct scsi_qla_host *);
extern void qla82xx_config_rings(struct scsi_qla_host *);
-extern int qla82xx_nvram_config(struct scsi_qla_host *);
extern int qla82xx_pinit_from_rom(scsi_qla_host_t *);
-extern int qla82xx_load_firmware(scsi_qla_host_t *);
-extern int qla82xx_reset_hw(scsi_qla_host_t *);
-extern int qla82xx_load_risc_blob(scsi_qla_host_t *, uint32_t *);
extern void qla82xx_watchdog(scsi_qla_host_t *);
/* Firmware and flash related functions */
@@ -569,7 +565,6 @@ extern int qla82xx_mbx_intr_enable(scsi_qla_host_t *);
extern int qla82xx_mbx_intr_disable(scsi_qla_host_t *);
extern void qla82xx_start_iocbs(srb_t *);
extern int qla82xx_fcoe_ctx_reset(scsi_qla_host_t *);
-extern void qla82xx_wait_for_pending_commands(scsi_qla_host_t *);
/* BSG related functions */
extern int qla24xx_bsg_request(struct fc_bsg_job *);
diff --git a/drivers/scsi/qla2xxx/qla_gs.c b/drivers/scsi/qla2xxx/qla_gs.c
index 872c55f049a..4c083928c2f 100644
--- a/drivers/scsi/qla2xxx/qla_gs.c
+++ b/drivers/scsi/qla2xxx/qla_gs.c
@@ -1,6 +1,6 @@
/*
* QLogic Fibre Channel HBA Driver
- * Copyright (c) 2003-2008 QLogic Corporation
+ * Copyright (c) 2003-2010 QLogic Corporation
*
* See LICENSE.qla2xxx for copyright and licensing details.
*/
@@ -1913,3 +1913,75 @@ qla2x00_gpsc(scsi_qla_host_t *vha, sw_info_t *list)
return (rval);
}
+
+/**
+ * qla2x00_gff_id() - SNS Get FC-4 Features (GFF_ID) query.
+ *
+ * @ha: HA context
+ * @list: switch info entries to populate
+ *
+ */
+void
+qla2x00_gff_id(scsi_qla_host_t *vha, sw_info_t *list)
+{
+ int rval;
+ uint16_t i;
+
+ ms_iocb_entry_t *ms_pkt;
+ struct ct_sns_req *ct_req;
+ struct ct_sns_rsp *ct_rsp;
+ struct qla_hw_data *ha = vha->hw;
+ uint8_t fcp_scsi_features = 0;
+
+ for (i = 0; i < MAX_FIBRE_DEVICES; i++) {
+ /* Set default FC4 Type as UNKNOWN so the default is to
+ * Process this port */
+ list[i].fc4_type = FC4_TYPE_UNKNOWN;
+
+ /* Do not attempt GFF_ID if we are not FWI_2 capable */
+ if (!IS_FWI2_CAPABLE(ha))
+ continue;
+
+ /* Prepare common MS IOCB */
+ ms_pkt = ha->isp_ops->prep_ms_iocb(vha, GFF_ID_REQ_SIZE,
+ GFF_ID_RSP_SIZE);
+
+ /* Prepare CT request */
+ ct_req = qla2x00_prep_ct_req(&ha->ct_sns->p.req, GFF_ID_CMD,
+ GFF_ID_RSP_SIZE);
+ ct_rsp = &ha->ct_sns->p.rsp;
+
+ /* Prepare CT arguments -- port_id */
+ ct_req->req.port_id.port_id[0] = list[i].d_id.b.domain;
+ ct_req->req.port_id.port_id[1] = list[i].d_id.b.area;
+ ct_req->req.port_id.port_id[2] = list[i].d_id.b.al_pa;
+
+ /* Execute MS IOCB */
+ rval = qla2x00_issue_iocb(vha, ha->ms_iocb, ha->ms_iocb_dma,
+ sizeof(ms_iocb_entry_t));
+
+ if (rval != QLA_SUCCESS) {
+ DEBUG2_3(printk(KERN_INFO
+ "scsi(%ld): GFF_ID issue IOCB failed "
+ "(%d).\n", vha->host_no, rval));
+ } else if (qla2x00_chk_ms_status(vha, ms_pkt, ct_rsp,
+ "GPN_ID") != QLA_SUCCESS) {
+ DEBUG2_3(printk(KERN_INFO
+ "scsi(%ld): GFF_ID IOCB status had a "
+ "failure status code\n", vha->host_no));
+ } else {
+ fcp_scsi_features =
+ ct_rsp->rsp.gff_id.fc4_features[GFF_FCP_SCSI_OFFSET];
+ fcp_scsi_features &= 0x0f;
+
+ if (fcp_scsi_features)
+ list[i].fc4_type = FC4_TYPE_FCP_SCSI;
+ else
+ list[i].fc4_type = FC4_TYPE_OTHER;
+ }
+
+ /* Last device exit. */
+ if (list[i].d_id.b.rsvd_1 != 0)
+ break;
+ }
+}
diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c
index ab2cc71994c..d863ed2619b 100644
--- a/drivers/scsi/qla2xxx/qla_init.c
+++ b/drivers/scsi/qla2xxx/qla_init.c
@@ -1,6 +1,6 @@
/*
* QLogic Fibre Channel HBA Driver
- * Copyright (c) 2003-2008 QLogic Corporation
+ * Copyright (c) 2003-2010 QLogic Corporation
*
* See LICENSE.qla2xxx for copyright and licensing details.
*/
@@ -60,12 +60,11 @@ qla2x00_ctx_sp_timeout(unsigned long __data)
ctx = sp->ctx;
iocb = ctx->u.iocb_cmd;
iocb->timeout(sp);
- spin_unlock_irqrestore(&ha->hardware_lock, flags);
-
iocb->free(sp);
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
}
-void
+static void
qla2x00_ctx_sp_free(srb_t *sp)
{
struct srb_ctx *ctx = sp->ctx;
@@ -122,7 +121,23 @@ done:
/* Asynchronous Login/Logout Routines -------------------------------------- */
-#define ELS_TMO_2_RATOV(ha) ((ha)->r_a_tov / 10 * 2)
+static inline unsigned long
+qla2x00_get_async_timeout(struct scsi_qla_host *vha)
+{
+ unsigned long tmo;
+ struct qla_hw_data *ha = vha->hw;
+
+ /* Firmware should use switch negotiated r_a_tov for timeout. */
+ tmo = ha->r_a_tov / 10 * 2;
+ if (!IS_FWI2_CAPABLE(ha)) {
+ /*
+ * Except for earlier ISPs where the timeout is seeded from the
+ * initialization control block.
+ */
+ tmo = ha->login_timeout;
+ }
+ return tmo;
+}
static void
qla2x00_async_iocb_timeout(srb_t *sp)
@@ -131,12 +146,22 @@ qla2x00_async_iocb_timeout(srb_t *sp)
struct srb_ctx *ctx = sp->ctx;
DEBUG2(printk(KERN_WARNING
- "scsi(%ld:%x): Async-%s timeout.\n",
- fcport->vha->host_no, sp->handle, ctx->name));
+ "scsi(%ld:%x): Async-%s timeout - portid=%02x%02x%02x.\n",
+ fcport->vha->host_no, sp->handle,
+ ctx->name, fcport->d_id.b.domain,
+ fcport->d_id.b.area, fcport->d_id.b.al_pa));
fcport->flags &= ~FCF_ASYNC_SENT;
- if (ctx->type == SRB_LOGIN_CMD)
+ if (ctx->type == SRB_LOGIN_CMD) {
+ struct srb_iocb *lio = ctx->u.iocb_cmd;
qla2x00_post_async_logout_work(fcport->vha, fcport, NULL);
+ /* Retry as needed. */
+ lio->u.logio.data[0] = MBS_COMMAND_ERROR;
+ lio->u.logio.data[1] = lio->u.logio.flags & SRB_LOGIN_RETRIED ?
+ QLA_LOGIO_LOGIN_RETRIED : 0;
+ qla2x00_post_async_login_done_work(fcport->vha, fcport,
+ lio->u.logio.data);
+ }
}
static void
@@ -154,7 +179,6 @@ int
qla2x00_async_login(struct scsi_qla_host *vha, fc_port_t *fcport,
uint16_t *data)
{
- struct qla_hw_data *ha = vha->hw;
srb_t *sp;
struct srb_ctx *ctx;
struct srb_iocb *lio;
@@ -162,7 +186,7 @@ qla2x00_async_login(struct scsi_qla_host *vha, fc_port_t *fcport,
rval = QLA_FUNCTION_FAILED;
sp = qla2x00_get_ctx_sp(vha, fcport, sizeof(struct srb_ctx),
- ELS_TMO_2_RATOV(ha) + 2);
+ qla2x00_get_async_timeout(vha) + 2);
if (!sp)
goto done;
@@ -206,7 +230,6 @@ qla2x00_async_logout_ctx_done(srb_t *sp)
int
qla2x00_async_logout(struct scsi_qla_host *vha, fc_port_t *fcport)
{
- struct qla_hw_data *ha = vha->hw;
srb_t *sp;
struct srb_ctx *ctx;
struct srb_iocb *lio;
@@ -214,7 +237,7 @@ qla2x00_async_logout(struct scsi_qla_host *vha, fc_port_t *fcport)
rval = QLA_FUNCTION_FAILED;
sp = qla2x00_get_ctx_sp(vha, fcport, sizeof(struct srb_ctx),
- ELS_TMO_2_RATOV(ha) + 2);
+ qla2x00_get_async_timeout(vha) + 2);
if (!sp)
goto done;
@@ -255,7 +278,6 @@ int
qla2x00_async_adisc(struct scsi_qla_host *vha, fc_port_t *fcport,
uint16_t *data)
{
- struct qla_hw_data *ha = vha->hw;
srb_t *sp;
struct srb_ctx *ctx;
struct srb_iocb *lio;
@@ -263,7 +285,7 @@ qla2x00_async_adisc(struct scsi_qla_host *vha, fc_port_t *fcport,
rval = QLA_FUNCTION_FAILED;
sp = qla2x00_get_ctx_sp(vha, fcport, sizeof(struct srb_ctx),
- ELS_TMO_2_RATOV(ha) + 2);
+ qla2x00_get_async_timeout(vha) + 2);
if (!sp)
goto done;
@@ -307,7 +329,6 @@ qla2x00_async_tm_cmd(fc_port_t *fcport, uint32_t flags, uint32_t lun,
uint32_t tag)
{
struct scsi_qla_host *vha = fcport->vha;
- struct qla_hw_data *ha = vha->hw;
srb_t *sp;
struct srb_ctx *ctx;
struct srb_iocb *tcf;
@@ -315,7 +336,7 @@ qla2x00_async_tm_cmd(fc_port_t *fcport, uint32_t flags, uint32_t lun,
rval = QLA_FUNCTION_FAILED;
sp = qla2x00_get_ctx_sp(vha, fcport, sizeof(struct srb_ctx),
- ELS_TMO_2_RATOV(ha) + 2);
+ qla2x00_get_async_timeout(vha) + 2);
if (!sp)
goto done;
@@ -346,58 +367,6 @@ done:
return rval;
}
-static void
-qla2x00_async_marker_ctx_done(srb_t *sp)
-{
- struct srb_ctx *ctx = sp->ctx;
- struct srb_iocb *iocb = (struct srb_iocb *)ctx->u.iocb_cmd;
-
- qla2x00_async_marker_done(sp->fcport->vha, sp->fcport, iocb);
- iocb->free(sp);
-}
-
-int
-qla2x00_async_marker(fc_port_t *fcport, uint16_t lun, uint8_t modif)
-{
- struct scsi_qla_host *vha = fcport->vha;
- srb_t *sp;
- struct srb_ctx *ctx;
- struct srb_iocb *mrk;
- int rval;
-
- rval = QLA_FUNCTION_FAILED;
- sp = qla2x00_get_ctx_sp(vha, fcport, sizeof(struct srb_ctx), 0);
- if (!sp)
- goto done;
-
- ctx = sp->ctx;
- ctx->type = SRB_MARKER_CMD;
- ctx->name = "marker";
- mrk = ctx->u.iocb_cmd;
- mrk->u.marker.lun = lun;
- mrk->u.marker.modif = modif;
- mrk->timeout = qla2x00_async_iocb_timeout;
- mrk->done = qla2x00_async_marker_ctx_done;
-
- rval = qla2x00_start_sp(sp);
- if (rval != QLA_SUCCESS)
- goto done_free_sp;
-
- DEBUG2(printk(KERN_DEBUG
- "scsi(%ld:%x): Async-marker - loop-id=%x "
- "portid=%02x%02x%02x.\n",
- fcport->vha->host_no, sp->handle, fcport->loop_id,
- fcport->d_id.b.domain, fcport->d_id.b.area,
- fcport->d_id.b.al_pa));
-
- return rval;
-
-done_free_sp:
- mrk->free(sp);
-done:
- return rval;
-}
-
void
qla2x00_async_login_done(struct scsi_qla_host *vha, fc_port_t *fcport,
uint16_t *data)
@@ -418,10 +387,11 @@ qla2x00_async_login_done(struct scsi_qla_host *vha, fc_port_t *fcport,
if (data[1] & QLA_LOGIO_LOGIN_RETRIED)
set_bit(RELOGIN_NEEDED, &vha->dpc_flags);
else
- qla2x00_mark_device_lost(vha, fcport, 1, 0);
+ qla2x00_mark_device_lost(vha, fcport, 1, 1);
break;
case MBS_PORT_ID_USED:
fcport->loop_id = data[1];
+ qla2x00_post_async_logout_work(vha, fcport, NULL);
qla2x00_post_async_login_work(vha, fcport, NULL);
break;
case MBS_LOOP_ID_USED:
@@ -429,7 +399,7 @@ qla2x00_async_login_done(struct scsi_qla_host *vha, fc_port_t *fcport,
rval = qla2x00_find_new_loop_id(vha, fcport);
if (rval != QLA_SUCCESS) {
fcport->flags &= ~FCF_ASYNC_SENT;
- qla2x00_mark_device_lost(vha, fcport, 1, 0);
+ qla2x00_mark_device_lost(vha, fcport, 1, 1);
break;
}
qla2x00_post_async_login_work(vha, fcport, NULL);
@@ -461,7 +431,7 @@ qla2x00_async_adisc_done(struct scsi_qla_host *vha, fc_port_t *fcport,
if (data[1] & QLA_LOGIO_LOGIN_RETRIED)
set_bit(RELOGIN_NEEDED, &vha->dpc_flags);
else
- qla2x00_mark_device_lost(vha, fcport, 1, 0);
+ qla2x00_mark_device_lost(vha, fcport, 1, 1);
return;
}
@@ -478,7 +448,8 @@ qla2x00_async_tm_cmd_done(struct scsi_qla_host *vha, fc_port_t *fcport,
lun = (uint16_t)iocb->u.tmf.lun;
/* Issue Marker IOCB */
- rval = qla2x00_async_marker(fcport, lun,
+ rval = qla2x00_marker(vha, vha->hw->req_q_map[0],
+ vha->hw->rsp_q_map[0], fcport->loop_id, lun,
flags == TCF_LUN_RESET ? MK_SYNC_ID_LUN : MK_SYNC_ID);
if ((rval != QLA_SUCCESS) || iocb->u.tmf.data) {
@@ -490,24 +461,6 @@ qla2x00_async_tm_cmd_done(struct scsi_qla_host *vha, fc_port_t *fcport,
return;
}
-void
-qla2x00_async_marker_done(struct scsi_qla_host *vha, fc_port_t *fcport,
- struct srb_iocb *iocb)
-{
- /*
- * Currently we dont have any specific post response processing
- * for this IOCB. We'll just return success or failed
- * depending on whether the IOCB command succeeded or failed.
- */
- if (iocb->u.tmf.data) {
- DEBUG2_3_11(printk(KERN_WARNING
- "%s(%ld): Marker IOCB failed (%x).\n",
- __func__, vha->host_no, iocb->u.tmf.data));
- }
-
- return;
-}
-
/****************************************************************************/
/* QLogic ISP2x00 Hardware Support Functions. */
/****************************************************************************/
@@ -613,11 +566,8 @@ qla2x00_initialize_adapter(scsi_qla_host_t *vha)
}
}
- if (IS_QLA24XX_TYPE(ha) || IS_QLA25XX(ha)) {
- if (qla24xx_read_fcp_prio_cfg(vha))
- qla_printk(KERN_ERR, ha,
- "Unable to read FCP priority data.\n");
- }
+ if (IS_QLA24XX_TYPE(ha) || IS_QLA25XX(ha))
+ qla24xx_read_fcp_prio_cfg(vha);
return (rval);
}
@@ -1452,8 +1402,11 @@ qla2x00_setup_chip(scsi_qla_host_t *vha)
if (IS_QLA82XX(ha)) {
rval = ha->isp_ops->load_risc(vha, &srisc_address);
- if (rval == QLA_SUCCESS)
+ if (rval == QLA_SUCCESS) {
+ qla2x00_stop_firmware(vha);
goto enable_82xx_npiv;
+ } else
+ goto failed;
}
if (!IS_FWI2_CAPABLE(ha) && !IS_QLA2100(ha) && !IS_QLA2200(ha)) {
@@ -1960,7 +1913,8 @@ qla2x00_fw_ready(scsi_qla_host_t *vha)
}
} else {
/* Mailbox cmd failed. Timeout on min_wait. */
- if (time_after_eq(jiffies, mtime))
+ if (time_after_eq(jiffies, mtime) ||
+ (IS_QLA82XX(ha) && ha->flags.fw_hung))
break;
}
@@ -2396,7 +2350,7 @@ qla2x00_nvram_config(scsi_qla_host_t *vha)
ha->retry_count = nv->retry_count;
/* Set minimum login_timeout to 4 seconds. */
- if (nv->login_timeout < ql2xlogintimeout)
+ if (nv->login_timeout != ql2xlogintimeout)
nv->login_timeout = ql2xlogintimeout;
if (nv->login_timeout < 4)
nv->login_timeout = 4;
@@ -2639,7 +2593,8 @@ qla2x00_configure_loop(scsi_qla_host_t *vha)
set_bit(LOCAL_LOOP_UPDATE, &vha->dpc_flags);
if (test_bit(RSCN_UPDATE, &save_flags)) {
set_bit(RSCN_UPDATE, &vha->dpc_flags);
- vha->flags.rscn_queue_overflow = 1;
+ if (!IS_ALOGIO_CAPABLE(ha))
+ vha->flags.rscn_queue_overflow = 1;
}
}
@@ -3124,7 +3079,6 @@ qla2x00_configure_fabric(scsi_qla_host_t *vha)
return (rval);
}
-
/*
* qla2x00_find_all_fabric_devs
*
@@ -3177,6 +3131,10 @@ qla2x00_find_all_fabric_devs(scsi_qla_host_t *vha,
qla2x00_gfpn_id(vha, swl) == QLA_SUCCESS) {
qla2x00_gpsc(vha, swl);
}
+
+ /* If other queries succeeded probe for FC-4 type */
+ if (swl)
+ qla2x00_gff_id(vha, swl);
}
swl_idx = 0;
@@ -3197,8 +3155,9 @@ qla2x00_find_all_fabric_devs(scsi_qla_host_t *vha,
if (qla2x00_is_reserved_id(vha, loop_id))
continue;
- if (atomic_read(&vha->loop_down_timer) ||
- LOOP_TRANSITION(vha)) {
+ if (ha->current_topology == ISP_CFG_FL &&
+ (atomic_read(&vha->loop_down_timer) ||
+ LOOP_TRANSITION(vha))) {
atomic_set(&vha->loop_down_timer, 0);
set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags);
set_bit(LOCAL_LOOP_UPDATE, &vha->dpc_flags);
@@ -3217,6 +3176,7 @@ qla2x00_find_all_fabric_devs(scsi_qla_host_t *vha,
memcpy(new_fcport->fabric_port_name,
swl[swl_idx].fabric_port_name, WWN_SIZE);
new_fcport->fp_speed = swl[swl_idx].fp_speed;
+ new_fcport->fc4_type = swl[swl_idx].fc4_type;
if (swl[swl_idx].d_id.b.rsvd_1 != 0) {
last_dev = 1;
@@ -3278,6 +3238,11 @@ qla2x00_find_all_fabric_devs(scsi_qla_host_t *vha,
if ((new_fcport->d_id.b.domain & 0xf0) == 0xf0)
continue;
+ /* Bypass ports whose FCP-4 type is not FCP_SCSI */
+ if (new_fcport->fc4_type != FC4_TYPE_FCP_SCSI &&
+ new_fcport->fc4_type != FC4_TYPE_UNKNOWN)
+ continue;
+
/* Locate matching device in database. */
found = 0;
list_for_each_entry(fcport, &vha->vp_fcports, list) {
@@ -3868,8 +3833,13 @@ qla2x00_abort_isp_cleanup(scsi_qla_host_t *vha)
}
/* Make sure for ISP 82XX IO DMA is complete */
- if (IS_QLA82XX(ha))
- qla82xx_wait_for_pending_commands(vha);
+ if (IS_QLA82XX(ha)) {
+ if (qla2x00_eh_wait_for_pending_commands(vha, 0, 0,
+ WAIT_HOST) == QLA_SUCCESS) {
+ DEBUG2(qla_printk(KERN_INFO, ha,
+ "Done wait for pending commands\n"));
+ }
+ }
/* Requeue all commands in outstanding command list. */
qla2x00_abort_all_cmds(vha, DID_RESET << 16);
diff --git a/drivers/scsi/qla2xxx/qla_inline.h b/drivers/scsi/qla2xxx/qla_inline.h
index 84c2fea154d..48f97a92e33 100644
--- a/drivers/scsi/qla2xxx/qla_inline.h
+++ b/drivers/scsi/qla2xxx/qla_inline.h
@@ -1,6 +1,6 @@
/*
* QLogic Fibre Channel HBA Driver
- * Copyright (c) 2003-2008 QLogic Corporation
+ * Copyright (c) 2003-2010 QLogic Corporation
*
* See LICENSE.qla2xxx for copyright and licensing details.
*/
diff --git a/drivers/scsi/qla2xxx/qla_iocb.c b/drivers/scsi/qla2xxx/qla_iocb.c
index 8ef94536541..579f0285466 100644
--- a/drivers/scsi/qla2xxx/qla_iocb.c
+++ b/drivers/scsi/qla2xxx/qla_iocb.c
@@ -1,6 +1,6 @@
/*
* QLogic Fibre Channel HBA Driver
- * Copyright (c) 2003-2008 QLogic Corporation
+ * Copyright (c) 2003-2010 QLogic Corporation
*
* See LICENSE.qla2xxx for copyright and licensing details.
*/
@@ -11,8 +11,6 @@
#include <scsi/scsi_tcq.h>
-static request_t *qla2x00_req_pkt(struct scsi_qla_host *, struct req_que *,
- struct rsp_que *rsp);
static void qla2x00_isp_cmd(struct scsi_qla_host *, struct req_que *);
static void qla25xx_set_que(srb_t *, struct rsp_que **);
@@ -463,7 +461,7 @@ queuing_error:
*
* Returns non-zero if a failure occurred, else zero.
*/
-int
+static int
__qla2x00_marker(struct scsi_qla_host *vha, struct req_que *req,
struct rsp_que *rsp, uint16_t loop_id,
uint16_t lun, uint8_t type)
@@ -474,7 +472,7 @@ __qla2x00_marker(struct scsi_qla_host *vha, struct req_que *req,
scsi_qla_host_t *base_vha = pci_get_drvdata(ha->pdev);
mrk24 = NULL;
- mrk = (mrk_entry_t *)qla2x00_req_pkt(vha, req, rsp);
+ mrk = (mrk_entry_t *)qla2x00_alloc_iocbs(vha, 0);
if (mrk == NULL) {
DEBUG2_3(printk("%s(%ld): failed to allocate Marker IOCB.\n",
__func__, base_vha->host_no));
@@ -521,84 +519,6 @@ qla2x00_marker(struct scsi_qla_host *vha, struct req_que *req,
}
/**
- * qla2x00_req_pkt() - Retrieve a request packet from the request ring.
- * @ha: HA context
- *
- * Note: The caller must hold the hardware lock before calling this routine.
- *
- * Returns NULL if function failed, else, a pointer to the request packet.
- */
-static request_t *
-qla2x00_req_pkt(struct scsi_qla_host *vha, struct req_que *req,
- struct rsp_que *rsp)
-{
- struct qla_hw_data *ha = vha->hw;
- device_reg_t __iomem *reg = ISP_QUE_REG(ha, req->id);
- request_t *pkt = NULL;
- uint16_t cnt;
- uint32_t *dword_ptr;
- uint32_t timer;
- uint16_t req_cnt = 1;
-
- /* Wait 1 second for slot. */
- for (timer = HZ; timer; timer--) {
- if ((req_cnt + 2) >= req->cnt) {
- /* Calculate number of free request entries. */
- if (ha->mqenable)
- cnt = (uint16_t)
- RD_REG_DWORD(&reg->isp25mq.req_q_out);
- else {
- if (IS_QLA82XX(ha))
- cnt = (uint16_t)RD_REG_DWORD(
- &reg->isp82.req_q_out);
- else if (IS_FWI2_CAPABLE(ha))
- cnt = (uint16_t)RD_REG_DWORD(
- &reg->isp24.req_q_out);
- else
- cnt = qla2x00_debounce_register(
- ISP_REQ_Q_OUT(ha, &reg->isp));
- }
- if (req->ring_index < cnt)
- req->cnt = cnt - req->ring_index;
- else
- req->cnt = req->length -
- (req->ring_index - cnt);
- }
- /* If room for request in request ring. */
- if ((req_cnt + 2) < req->cnt) {
- req->cnt--;
- pkt = req->ring_ptr;
-
- /* Zero out packet. */
- dword_ptr = (uint32_t *)pkt;
- for (cnt = 0; cnt < REQUEST_ENTRY_SIZE / 4; cnt++)
- *dword_ptr++ = 0;
-
- /* Set entry count. */
- pkt->entry_count = 1;
-
- break;
- }
-
- /* Release ring specific lock */
- spin_unlock_irq(&ha->hardware_lock);
-
- udelay(2); /* 2 us */
-
- /* Check for pending interrupts. */
- /* During init we issue marker directly */
- if (!vha->marker_needed && !vha->flags.init_done)
- qla2x00_poll(rsp);
- spin_lock_irq(&ha->hardware_lock);
- }
- if (!pkt) {
- DEBUG2_3(printk("%s(): **** FAILED ****\n", __func__));
- }
-
- return (pkt);
-}
-
-/**
* qla2x00_isp_cmd() - Modify the request ring pointer.
* @ha: HA context
*
@@ -792,6 +712,25 @@ qla24xx_set_t10dif_tags(struct scsi_cmnd *cmd, struct fw_dif_context *pkt,
* match LBA in CDB + N
*/
case SCSI_PROT_DIF_TYPE2:
+ if (!ql2xenablehba_err_chk)
+ break;
+
+ if (scsi_prot_sg_count(cmd)) {
+ spt = page_address(sg_page(scsi_prot_sglist(cmd))) +
+ scsi_prot_sglist(cmd)[0].offset;
+ pkt->app_tag = swab32(spt->app_tag);
+ pkt->app_tag_mask[0] = 0xff;
+ pkt->app_tag_mask[1] = 0xff;
+ }
+
+ pkt->ref_tag = cpu_to_le32((uint32_t)
+ (0xffffffff & scsi_get_lba(cmd)));
+
+ /* enable ALL bytes of the ref tag */
+ pkt->ref_tag_mask[0] = 0xff;
+ pkt->ref_tag_mask[1] = 0xff;
+ pkt->ref_tag_mask[2] = 0xff;
+ pkt->ref_tag_mask[3] = 0xff;
break;
/* For Type 3 protection: 16 bit GUARD only */
@@ -1129,7 +1068,7 @@ qla24xx_build_scsi_crc_2_iocbs(srb_t *sp, struct cmd_type_crc_2 *cmd_pkt,
cmd_pkt->fcp_cmnd_dseg_address[1] = cpu_to_le32(
MSD(crc_ctx_dma + CRC_CONTEXT_FCPCMND_OFF));
fcp_cmnd->task_attribute = 0;
- fcp_cmnd->task_managment = 0;
+ fcp_cmnd->task_management = 0;
cmd_pkt->fcp_rsp_dseg_len = 0; /* Let response come in status iocb */
@@ -1142,7 +1081,7 @@ qla24xx_build_scsi_crc_2_iocbs(srb_t *sp, struct cmd_type_crc_2 *cmd_pkt,
total_bytes = data_bytes;
dif_bytes = 0;
blk_size = cmd->device->sector_size;
- if (scsi_get_prot_type(cmd) == SCSI_PROT_DIF_TYPE1) {
+ if (scsi_get_prot_op(cmd) != SCSI_PROT_NORMAL) {
dif_bytes = (data_bytes / blk_size) * 8;
total_bytes += dif_bytes;
}
@@ -1180,6 +1119,12 @@ qla24xx_build_scsi_crc_2_iocbs(srb_t *sp, struct cmd_type_crc_2 *cmd_pkt,
vha->host_no, dif_bytes, dif_bytes, total_bytes, total_bytes,
crc_ctx_pkt->blk_size, crc_ctx_pkt->blk_size));
+ if (!data_bytes || cmd->sc_data_direction == DMA_NONE) {
+ DEBUG18(printk(KERN_INFO "%s: Zero data bytes or DMA-NONE %d\n",
+ __func__, data_bytes));
+ cmd_pkt->byte_count = __constant_cpu_to_le32(0);
+ return QLA_SUCCESS;
+ }
/* Walks data segments */
cmd_pkt->control_flags |=
@@ -1390,9 +1335,11 @@ qla24xx_dif_start_scsi(srb_t *sp)
#define QDSS_GOT_Q_SPACE BIT_0
- /* Only process protection in this routine */
- if (scsi_get_prot_op(cmd) == SCSI_PROT_NORMAL)
- return qla24xx_start_scsi(sp);
+ /* Only process protection or >16 cdb in this routine */
+ if (scsi_get_prot_op(cmd) == SCSI_PROT_NORMAL) {
+ if (cmd->cmd_len <= 16)
+ return qla24xx_start_scsi(sp);
+ }
/* Setup device pointers. */
@@ -1559,11 +1506,9 @@ static void qla25xx_set_que(srb_t *sp, struct rsp_que **rsp)
}
/* Generic Control-SRB manipulation functions. */
-
-static void *
-qla2x00_alloc_iocbs(srb_t *sp)
+void *
+qla2x00_alloc_iocbs(scsi_qla_host_t *vha, srb_t *sp)
{
- scsi_qla_host_t *vha = sp->fcport->vha;
struct qla_hw_data *ha = vha->hw;
struct req_que *req = ha->req_q_map[0];
device_reg_t __iomem *reg = ISP_QUE_REG(ha, req->id);
@@ -1573,6 +1518,10 @@ qla2x00_alloc_iocbs(srb_t *sp)
pkt = NULL;
req_cnt = 1;
+ handle = 0;
+
+ if (!sp)
+ goto skip_cmd_array;
/* Check for room in outstanding command list. */
handle = req->current_outstanding_cmd;
@@ -1586,10 +1535,18 @@ qla2x00_alloc_iocbs(srb_t *sp)
if (index == MAX_OUTSTANDING_COMMANDS)
goto queuing_error;
+ /* Prep command array. */
+ req->current_outstanding_cmd = handle;
+ req->outstanding_cmds[handle] = sp;
+ sp->handle = handle;
+
+skip_cmd_array:
/* Check for room on request queue. */
if (req->cnt < req_cnt) {
if (ha->mqenable)
cnt = RD_REG_DWORD(&reg->isp25mq.req_q_out);
+ else if (IS_QLA82XX(ha))
+ cnt = RD_REG_DWORD(&reg->isp82.req_q_out);
else if (IS_FWI2_CAPABLE(ha))
cnt = RD_REG_DWORD(&reg->isp24.req_q_out);
else
@@ -1606,15 +1563,11 @@ qla2x00_alloc_iocbs(srb_t *sp)
goto queuing_error;
/* Prep packet */
- req->current_outstanding_cmd = handle;
- req->outstanding_cmds[handle] = sp;
req->cnt -= req_cnt;
-
pkt = req->ring_ptr;
memset(pkt, 0, REQUEST_ENTRY_SIZE);
pkt->entry_count = req_cnt;
pkt->handle = handle;
- sp->handle = handle;
queuing_error:
return pkt;
@@ -1683,7 +1636,7 @@ qla2x00_login_iocb(srb_t *sp, struct mbx_entry *mbx)
struct srb_iocb *lio = ctx->u.iocb_cmd;
uint16_t opts;
- mbx->entry_type = MBX_IOCB_TYPE;;
+ mbx->entry_type = MBX_IOCB_TYPE;
SET_TARGET_ID(ha, mbx->loop_id, sp->fcport->loop_id);
mbx->mb0 = cpu_to_le16(MBC_LOGIN_FABRIC_PORT);
opts = lio->u.logio.flags & SRB_LOGIN_COND_PLOGI ? BIT_0 : 0;
@@ -1718,7 +1671,7 @@ qla2x00_logout_iocb(srb_t *sp, struct mbx_entry *mbx)
{
struct qla_hw_data *ha = sp->fcport->vha->hw;
- mbx->entry_type = MBX_IOCB_TYPE;;
+ mbx->entry_type = MBX_IOCB_TYPE;
SET_TARGET_ID(ha, mbx->loop_id, sp->fcport->loop_id);
mbx->mb0 = cpu_to_le16(MBC_LOGOUT_FABRIC_PORT);
mbx->mb1 = HAS_EXTENDED_IDS(ha) ?
@@ -1795,31 +1748,6 @@ qla24xx_tm_iocb(srb_t *sp, struct tsk_mgmt_entry *tsk)
}
static void
-qla24xx_marker_iocb(srb_t *sp, struct mrk_entry_24xx *mrk)
-{
- uint16_t lun;
- uint8_t modif;
- struct fc_port *fcport = sp->fcport;
- scsi_qla_host_t *vha = fcport->vha;
- struct srb_ctx *ctx = sp->ctx;
- struct srb_iocb *iocb = ctx->u.iocb_cmd;
- struct req_que *req = vha->req;
-
- lun = iocb->u.marker.lun;
- modif = iocb->u.marker.modif;
- mrk->entry_type = MARKER_TYPE;
- mrk->modifier = modif;
- if (modif != MK_SYNC_ALL) {
- mrk->nport_handle = cpu_to_le16(fcport->loop_id);
- mrk->lun[1] = LSB(lun);
- mrk->lun[2] = MSB(lun);
- host_to_fcp_swap(mrk->lun, sizeof(mrk->lun));
- mrk->vp_index = vha->vp_idx;
- mrk->handle = MAKE_HANDLE(req->id, mrk->handle);
- }
-}
-
-static void
qla24xx_els_iocb(srb_t *sp, struct els_entry_24xx *els_iocb)
{
struct fc_bsg_job *bsg_job = ((struct srb_ctx *)sp->ctx)->u.bsg_job;
@@ -1864,6 +1792,82 @@ qla24xx_els_iocb(srb_t *sp, struct els_entry_24xx *els_iocb)
}
static void
+qla2x00_ct_iocb(srb_t *sp, ms_iocb_entry_t *ct_iocb)
+{
+ uint16_t avail_dsds;
+ uint32_t *cur_dsd;
+ struct scatterlist *sg;
+ int index;
+ uint16_t tot_dsds;
+ scsi_qla_host_t *vha = sp->fcport->vha;
+ struct qla_hw_data *ha = vha->hw;
+ struct fc_bsg_job *bsg_job = ((struct srb_ctx *)sp->ctx)->u.bsg_job;
+ int loop_iterartion = 0;
+ int cont_iocb_prsnt = 0;
+ int entry_count = 1;
+
+ memset(ct_iocb, 0, sizeof(ms_iocb_entry_t));
+ ct_iocb->entry_type = CT_IOCB_TYPE;
+ ct_iocb->entry_status = 0;
+ ct_iocb->handle1 = sp->handle;
+ SET_TARGET_ID(ha, ct_iocb->loop_id, sp->fcport->loop_id);
+ ct_iocb->status = __constant_cpu_to_le16(0);
+ ct_iocb->control_flags = __constant_cpu_to_le16(0);
+ ct_iocb->timeout = 0;
+ ct_iocb->cmd_dsd_count =
+ __constant_cpu_to_le16(bsg_job->request_payload.sg_cnt);
+ ct_iocb->total_dsd_count =
+ __constant_cpu_to_le16(bsg_job->request_payload.sg_cnt + 1);
+ ct_iocb->req_bytecount =
+ cpu_to_le32(bsg_job->request_payload.payload_len);
+ ct_iocb->rsp_bytecount =
+ cpu_to_le32(bsg_job->reply_payload.payload_len);
+
+ ct_iocb->dseg_req_address[0] = cpu_to_le32(LSD(sg_dma_address
+ (bsg_job->request_payload.sg_list)));
+ ct_iocb->dseg_req_address[1] = cpu_to_le32(MSD(sg_dma_address
+ (bsg_job->request_payload.sg_list)));
+ ct_iocb->dseg_req_length = ct_iocb->req_bytecount;
+
+ ct_iocb->dseg_rsp_address[0] = cpu_to_le32(LSD(sg_dma_address
+ (bsg_job->reply_payload.sg_list)));
+ ct_iocb->dseg_rsp_address[1] = cpu_to_le32(MSD(sg_dma_address
+ (bsg_job->reply_payload.sg_list)));
+ ct_iocb->dseg_rsp_length = ct_iocb->rsp_bytecount;
+
+ avail_dsds = 1;
+ cur_dsd = (uint32_t *)ct_iocb->dseg_rsp_address;
+ index = 0;
+ tot_dsds = bsg_job->reply_payload.sg_cnt;
+
+ for_each_sg(bsg_job->reply_payload.sg_list, sg, tot_dsds, index) {
+ 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 Cont.
+ * Type 1 IOCB.
+ */
+ cont_pkt = qla2x00_prep_cont_type1_iocb(vha);
+ cur_dsd = (uint32_t *) cont_pkt->dseg_0_address;
+ avail_dsds = 5;
+ cont_iocb_prsnt = 1;
+ entry_count++;
+ }
+
+ 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));
+ loop_iterartion++;
+ avail_dsds--;
+ }
+ ct_iocb->entry_count = entry_count;
+}
+
+static void
qla24xx_ct_iocb(srb_t *sp, struct ct_entry_24xx *ct_iocb)
{
uint16_t avail_dsds;
@@ -1945,7 +1949,7 @@ qla2x00_start_sp(srb_t *sp)
rval = QLA_FUNCTION_FAILED;
spin_lock_irqsave(&ha->hardware_lock, flags);
- pkt = qla2x00_alloc_iocbs(sp);
+ pkt = qla2x00_alloc_iocbs(sp->fcport->vha, sp);
if (!pkt)
goto done;
@@ -1966,7 +1970,9 @@ qla2x00_start_sp(srb_t *sp)
qla24xx_els_iocb(sp, pkt);
break;
case SRB_CT_CMD:
- qla24xx_ct_iocb(sp, pkt);
+ IS_FWI2_CAPABLE(ha) ?
+ qla24xx_ct_iocb(sp, pkt) :
+ qla2x00_ct_iocb(sp, pkt);
break;
case SRB_ADISC_CMD:
IS_FWI2_CAPABLE(ha) ?
@@ -1976,9 +1982,6 @@ qla2x00_start_sp(srb_t *sp)
case SRB_TM_CMD:
qla24xx_tm_iocb(sp, pkt);
break;
- case SRB_MARKER_CMD:
- qla24xx_marker_iocb(sp, pkt);
- break;
default:
break;
}
diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c
index be3d8bed2ec..6982ba70e12 100644
--- a/drivers/scsi/qla2xxx/qla_isr.c
+++ b/drivers/scsi/qla2xxx/qla_isr.c
@@ -1,6 +1,6 @@
/*
* QLogic Fibre Channel HBA Driver
- * Copyright (c) 2003-2008 QLogic Corporation
+ * Copyright (c) 2003-2010 QLogic Corporation
*
* See LICENSE.qla2xxx for copyright and licensing details.
*/
@@ -545,10 +545,13 @@ skip_rio:
if (IS_QLA2100(ha))
break;
- if (IS_QLA8XXX_TYPE(ha))
+ if (IS_QLA8XXX_TYPE(ha)) {
DEBUG2(printk("scsi(%ld): DCBX Completed -- %04x %04x "
"%04x\n", vha->host_no, mb[1], mb[2], mb[3]));
- else
+ if (ha->notify_dcbx_comp)
+ complete(&ha->dcbx_comp);
+
+ } else
DEBUG2(printk("scsi(%ld): Asynchronous P2P MODE "
"received.\n", vha->host_no));
@@ -918,12 +921,15 @@ qla2x00_mbx_iocb_entry(scsi_qla_host_t *vha, struct req_que *req,
QLA_LOGIO_LOGIN_RETRIED : 0;
if (mbx->entry_status) {
DEBUG2(printk(KERN_WARNING
- "scsi(%ld:%x): Async-%s error entry - entry-status=%x "
- "status=%x state-flag=%x status-flags=%x.\n",
+ "scsi(%ld:%x): Async-%s error entry - portid=%02x%02x%02x "
+ "entry-status=%x status=%x state-flag=%x "
+ "status-flags=%x.\n",
fcport->vha->host_no, sp->handle, type,
- mbx->entry_status, le16_to_cpu(mbx->status),
- le16_to_cpu(mbx->state_flags),
+ fcport->d_id.b.domain, fcport->d_id.b.area,
+ fcport->d_id.b.al_pa, mbx->entry_status,
+ le16_to_cpu(mbx->status), le16_to_cpu(mbx->state_flags),
le16_to_cpu(mbx->status_flags)));
+
DEBUG2(qla2x00_dump_buffer((uint8_t *)mbx, sizeof(*mbx)));
goto logio_done;
@@ -935,16 +941,18 @@ qla2x00_mbx_iocb_entry(scsi_qla_host_t *vha, struct req_que *req,
status = 0;
if (!status && le16_to_cpu(mbx->mb0) == MBS_COMMAND_COMPLETE) {
DEBUG2(printk(KERN_DEBUG
- "scsi(%ld:%x): Async-%s complete - mbx1=%x.\n",
+ "scsi(%ld:%x): Async-%s complete - portid=%02x%02x%02x "
+ "mbx1=%x.\n",
fcport->vha->host_no, sp->handle, type,
- le16_to_cpu(mbx->mb1)));
+ fcport->d_id.b.domain, fcport->d_id.b.area,
+ fcport->d_id.b.al_pa, le16_to_cpu(mbx->mb1)));
data[0] = MBS_COMMAND_COMPLETE;
if (ctx->type == SRB_LOGIN_CMD) {
fcport->port_type = FCT_TARGET;
if (le16_to_cpu(mbx->mb1) & BIT_0)
fcport->port_type = FCT_INITIATOR;
- if (le16_to_cpu(mbx->mb1) & BIT_1)
+ else if (le16_to_cpu(mbx->mb1) & BIT_1)
fcport->flags |= FCF_FCP2_DEVICE;
}
goto logio_done;
@@ -963,9 +971,10 @@ qla2x00_mbx_iocb_entry(scsi_qla_host_t *vha, struct req_que *req,
}
DEBUG2(printk(KERN_WARNING
- "scsi(%ld:%x): Async-%s failed - status=%x mb0=%x mb1=%x mb2=%x "
- "mb6=%x mb7=%x.\n",
- fcport->vha->host_no, sp->handle, type, status,
+ "scsi(%ld:%x): Async-%s failed - portid=%02x%02x%02x status=%x "
+ "mb0=%x mb1=%x mb2=%x mb6=%x mb7=%x.\n",
+ fcport->vha->host_no, sp->handle, type, fcport->d_id.b.domain,
+ fcport->d_id.b.area, fcport->d_id.b.al_pa, status,
le16_to_cpu(mbx->mb0), le16_to_cpu(mbx->mb1),
le16_to_cpu(mbx->mb2), le16_to_cpu(mbx->mb6),
le16_to_cpu(mbx->mb7)));
@@ -975,6 +984,86 @@ logio_done:
}
static void
+qla2x00_ct_entry(scsi_qla_host_t *vha, struct req_que *req,
+ sts_entry_t *pkt, int iocb_type)
+{
+ const char func[] = "CT_IOCB";
+ const char *type;
+ struct qla_hw_data *ha = vha->hw;
+ srb_t *sp;
+ struct srb_ctx *sp_bsg;
+ struct fc_bsg_job *bsg_job;
+ uint16_t comp_status;
+
+ sp = qla2x00_get_sp_from_handle(vha, func, req, pkt);
+ if (!sp)
+ return;
+
+ sp_bsg = sp->ctx;
+ bsg_job = sp_bsg->u.bsg_job;
+
+ type = NULL;
+ switch (sp_bsg->type) {
+ case SRB_CT_CMD:
+ type = "ct pass-through";
+ break;
+ default:
+ qla_printk(KERN_WARNING, ha,
+ "%s: Unrecognized SRB: (%p) type=%d.\n", func, sp,
+ sp_bsg->type);
+ return;
+ }
+
+ comp_status = le16_to_cpu(pkt->comp_status);
+
+ /* return FC_CTELS_STATUS_OK and leave the decoding of the ELS/CT
+ * fc payload to the caller
+ */
+ bsg_job->reply->reply_data.ctels_reply.status = FC_CTELS_STATUS_OK;
+ bsg_job->reply_len = sizeof(struct fc_bsg_reply);
+
+ if (comp_status != CS_COMPLETE) {
+ if (comp_status == CS_DATA_UNDERRUN) {
+ bsg_job->reply->result = DID_OK << 16;
+ bsg_job->reply->reply_payload_rcv_len =
+ le16_to_cpu(((sts_entry_t *)pkt)->rsp_info_len);
+
+ DEBUG2(qla_printk(KERN_WARNING, ha,
+ "scsi(%ld): CT pass-through-%s error "
+ "comp_status-status=0x%x total_byte = 0x%x.\n",
+ vha->host_no, type, comp_status,
+ bsg_job->reply->reply_payload_rcv_len));
+ } else {
+ DEBUG2(qla_printk(KERN_WARNING, ha,
+ "scsi(%ld): CT pass-through-%s error "
+ "comp_status-status=0x%x.\n",
+ vha->host_no, type, comp_status));
+ bsg_job->reply->result = DID_ERROR << 16;
+ bsg_job->reply->reply_payload_rcv_len = 0;
+ }
+ DEBUG2(qla2x00_dump_buffer((uint8_t *)pkt, sizeof(*pkt)));
+ } else {
+ bsg_job->reply->result = DID_OK << 16;;
+ bsg_job->reply->reply_payload_rcv_len =
+ bsg_job->reply_payload.payload_len;
+ bsg_job->reply_len = 0;
+ }
+
+ dma_unmap_sg(&ha->pdev->dev, bsg_job->request_payload.sg_list,
+ bsg_job->request_payload.sg_cnt, DMA_TO_DEVICE);
+
+ dma_unmap_sg(&ha->pdev->dev, bsg_job->reply_payload.sg_list,
+ bsg_job->reply_payload.sg_cnt, DMA_FROM_DEVICE);
+
+ if (sp_bsg->type == SRB_ELS_CMD_HST || sp_bsg->type == SRB_CT_CMD)
+ kfree(sp->fcport);
+
+ kfree(sp->ctx);
+ mempool_free(sp, ha->srb_mempool);
+ bsg_job->job_done(bsg_job);
+}
+
+static void
qla24xx_els_ct_entry(scsi_qla_host_t *vha, struct req_que *req,
struct sts_entry_24xx *pkt, int iocb_type)
{
@@ -1096,9 +1185,11 @@ qla24xx_logio_entry(scsi_qla_host_t *vha, struct req_que *req,
QLA_LOGIO_LOGIN_RETRIED : 0;
if (logio->entry_status) {
DEBUG2(printk(KERN_WARNING
- "scsi(%ld:%x): Async-%s error entry - entry-status=%x.\n",
+ "scsi(%ld:%x): Async-%s error entry - "
+ "portid=%02x%02x%02x entry-status=%x.\n",
fcport->vha->host_no, sp->handle, type,
- logio->entry_status));
+ fcport->d_id.b.domain, fcport->d_id.b.area,
+ fcport->d_id.b.al_pa, logio->entry_status));
DEBUG2(qla2x00_dump_buffer((uint8_t *)logio, sizeof(*logio)));
goto logio_done;
@@ -1106,8 +1197,11 @@ qla24xx_logio_entry(scsi_qla_host_t *vha, struct req_que *req,
if (le16_to_cpu(logio->comp_status) == CS_COMPLETE) {
DEBUG2(printk(KERN_DEBUG
- "scsi(%ld:%x): Async-%s complete - iop0=%x.\n",
+ "scsi(%ld:%x): Async-%s complete - portid=%02x%02x%02x "
+ "iop0=%x.\n",
fcport->vha->host_no, sp->handle, type,
+ fcport->d_id.b.domain, fcport->d_id.b.area,
+ fcport->d_id.b.al_pa,
le32_to_cpu(logio->io_parameter[0])));
data[0] = MBS_COMMAND_COMPLETE;
@@ -1119,9 +1213,9 @@ qla24xx_logio_entry(scsi_qla_host_t *vha, struct req_que *req,
fcport->port_type = FCT_TARGET;
if (iop[0] & BIT_8)
fcport->flags |= FCF_FCP2_DEVICE;
- }
- if (iop[0] & BIT_5)
+ } else if (iop[0] & BIT_5)
fcport->port_type = FCT_INITIATOR;
+
if (logio->io_parameter[7] || logio->io_parameter[8])
fcport->supported_classes |= FC_COS_CLASS2;
if (logio->io_parameter[9] || logio->io_parameter[10])
@@ -1152,8 +1246,10 @@ qla24xx_logio_entry(scsi_qla_host_t *vha, struct req_que *req,
}
DEBUG2(printk(KERN_WARNING
- "scsi(%ld:%x): Async-%s failed - comp=%x iop0=%x iop1=%x.\n",
- fcport->vha->host_no, sp->handle, type,
+ "scsi(%ld:%x): Async-%s failed - portid=%02x%02x%02x comp=%x "
+ "iop0=%x iop1=%x.\n",
+ fcport->vha->host_no, sp->handle, type, fcport->d_id.b.domain,
+ fcport->d_id.b.area, fcport->d_id.b.al_pa,
le16_to_cpu(logio->comp_status),
le32_to_cpu(logio->io_parameter[0]),
le32_to_cpu(logio->io_parameter[1])));
@@ -1222,39 +1318,6 @@ qla24xx_tm_iocb_entry(scsi_qla_host_t *vha, struct req_que *req,
iocb->done(sp);
}
-static void
-qla24xx_marker_iocb_entry(scsi_qla_host_t *vha, struct req_que *req,
- struct mrk_entry_24xx *mrk)
-{
- const char func[] = "MRK-IOCB";
- const char *type;
- fc_port_t *fcport;
- srb_t *sp;
- struct srb_iocb *iocb;
- struct srb_ctx *ctx;
- struct sts_entry_24xx *sts = (struct sts_entry_24xx *)mrk;
-
- sp = qla2x00_get_sp_from_handle(vha, func, req, mrk);
- if (!sp)
- return;
-
- ctx = sp->ctx;
- iocb = ctx->u.iocb_cmd;
- type = ctx->name;
- fcport = sp->fcport;
-
- if (sts->entry_status) {
- iocb->u.marker.data = 1;
- DEBUG2(printk(KERN_WARNING
- "scsi(%ld:%x): Async-%s error entry - entry-status=%x.\n",
- fcport->vha->host_no, sp->handle, type,
- sts->entry_status));
- DEBUG2(qla2x00_dump_buffer((uint8_t *)mrk, sizeof(*sts)));
- }
-
- iocb->done(sp);
-}
-
/**
* qla2x00_process_response_queue() - Process response queue entries.
* @ha: SCSI driver HA context
@@ -1320,6 +1383,9 @@ qla2x00_process_response_queue(struct rsp_que *rsp)
qla2x00_mbx_iocb_entry(vha, rsp->req,
(struct mbx_entry *)pkt);
break;
+ case CT_IOCB_TYPE:
+ qla2x00_ct_entry(vha, rsp->req, pkt, CT_IOCB_TYPE);
+ break;
default:
/* Type Not Supported. */
DEBUG4(printk(KERN_WARNING
@@ -1337,8 +1403,9 @@ qla2x00_process_response_queue(struct rsp_que *rsp)
}
static inline void
-qla2x00_handle_sense(srb_t *sp, uint8_t *sense_data, uint32_t sense_len,
- struct rsp_que *rsp)
+
+qla2x00_handle_sense(srb_t *sp, uint8_t *sense_data, uint32_t par_sense_len,
+ uint32_t sense_len, struct rsp_que *rsp)
{
struct scsi_cmnd *cp = sp->cmd;
@@ -1347,8 +1414,8 @@ qla2x00_handle_sense(srb_t *sp, uint8_t *sense_data, uint32_t sense_len,
sp->request_sense_length = sense_len;
sp->request_sense_ptr = cp->sense_buffer;
- if (sp->request_sense_length > 32)
- sense_len = 32;
+ if (sp->request_sense_length > par_sense_len)
+ sense_len = par_sense_len;
memcpy(cp->sense_buffer, sense_data, sense_len);
@@ -1455,7 +1522,8 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt)
uint16_t ox_id;
uint8_t lscsi_status;
int32_t resid;
- uint32_t sense_len, rsp_info_len, resid_len, fw_resid_len;
+ uint32_t sense_len, par_sense_len, rsp_info_len, resid_len,
+ fw_resid_len;
uint8_t *rsp_info, *sense_data;
struct qla_hw_data *ha = vha->hw;
uint32_t handle;
@@ -1513,7 +1581,8 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt)
fcport = sp->fcport;
ox_id = 0;
- sense_len = rsp_info_len = resid_len = fw_resid_len = 0;
+ sense_len = par_sense_len = rsp_info_len = resid_len =
+ fw_resid_len = 0;
if (IS_FWI2_CAPABLE(ha)) {
if (scsi_status & SS_SENSE_LEN_VALID)
sense_len = le32_to_cpu(sts24->sense_len);
@@ -1527,6 +1596,7 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt)
sense_data = sts24->data;
host_to_fcp_swap(sts24->data, sizeof(sts24->data));
ox_id = le16_to_cpu(sts24->ox_id);
+ par_sense_len = sizeof(sts24->data);
} else {
if (scsi_status & SS_SENSE_LEN_VALID)
sense_len = le16_to_cpu(sts->req_sense_length);
@@ -1535,13 +1605,16 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt)
resid_len = le32_to_cpu(sts->residual_length);
rsp_info = sts->rsp_info;
sense_data = sts->req_sense_data;
+ par_sense_len = sizeof(sts->req_sense_data);
}
/* Check for any FCP transport errors. */
if (scsi_status & SS_RESPONSE_INFO_LEN_VALID) {
/* Sense data lies beyond any FCP RESPONSE data. */
- if (IS_FWI2_CAPABLE(ha))
+ if (IS_FWI2_CAPABLE(ha)) {
sense_data += rsp_info_len;
+ par_sense_len -= rsp_info_len;
+ }
if (rsp_info_len > 3 && rsp_info[3]) {
DEBUG2(qla_printk(KERN_INFO, ha,
"scsi(%ld:%d:%d): FCP I/O protocol failure "
@@ -1601,7 +1674,8 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt)
if (!(scsi_status & SS_SENSE_LEN_VALID))
break;
- qla2x00_handle_sense(sp, sense_data, sense_len, rsp);
+ qla2x00_handle_sense(sp, sense_data, par_sense_len, sense_len,
+ rsp);
break;
case CS_DATA_UNDERRUN:
@@ -1665,7 +1739,8 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt)
if (!(scsi_status & SS_SENSE_LEN_VALID))
break;
- qla2x00_handle_sense(sp, sense_data, sense_len, rsp);
+ qla2x00_handle_sense(sp, sense_data, par_sense_len,
+ sense_len, rsp);
}
break;
@@ -1700,6 +1775,9 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt)
break;
case CS_RESET:
+ cp->result = DID_TRANSPORT_DISRUPTED << 16;
+ break;
+
case CS_ABORTED:
cp->result = DID_RESET << 16;
break;
@@ -1926,10 +2004,6 @@ void qla24xx_process_response_queue(struct scsi_qla_host *vha,
qla24xx_tm_iocb_entry(vha, rsp->req,
(struct tsk_mgmt_entry *)pkt);
break;
- case MARKER_TYPE:
- qla24xx_marker_iocb_entry(vha, rsp->req,
- (struct mrk_entry_24xx *)pkt);
- break;
case CT_IOCB_TYPE:
qla24xx_els_ct_entry(vha, rsp->req, pkt, CT_IOCB_TYPE);
clear_bit(MBX_INTERRUPT, &vha->hw->mbx_cmd_flags);
diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c
index f3650d0434c..6009b0c6948 100644
--- a/drivers/scsi/qla2xxx/qla_mbx.c
+++ b/drivers/scsi/qla2xxx/qla_mbx.c
@@ -1,6 +1,6 @@
/*
* QLogic Fibre Channel HBA Driver
- * Copyright (c) 2003-2008 QLogic Corporation
+ * Copyright (c) 2003-2010 QLogic Corporation
*
* See LICENSE.qla2xxx for copyright and licensing details.
*/
@@ -37,7 +37,7 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp)
device_reg_t __iomem *reg;
uint8_t abort_active;
uint8_t io_lock_on;
- uint16_t command;
+ uint16_t command = 0;
uint16_t *iptr;
uint16_t __iomem *optr;
uint32_t cnt;
@@ -83,6 +83,13 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp)
return QLA_FUNCTION_TIMEOUT;
}
+ if (IS_QLA82XX(ha) && ha->flags.fw_hung) {
+ /* Setting Link-Down error */
+ mcp->mb[0] = MBS_LINK_DOWN_ERROR;
+ rval = QLA_FUNCTION_FAILED;
+ goto premature_exit;
+ }
+
ha->flags.mbox_busy = 1;
/* Save mailbox command for debug */
ha->mcp = mcp;
@@ -151,7 +158,8 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp)
DEBUG2_3_11(printk(KERN_INFO
"%s(%ld): Pending Mailbox timeout. "
"Exiting.\n", __func__, base_vha->host_no));
- return QLA_FUNCTION_TIMEOUT;
+ rval = QLA_FUNCTION_TIMEOUT;
+ goto premature_exit;
}
WRT_REG_DWORD(&reg->isp82.hint, HINT_MBX_INT_PENDING);
} else if (IS_FWI2_CAPABLE(ha))
@@ -176,7 +184,8 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp)
DEBUG2_3_11(printk(KERN_INFO
"%s(%ld): Pending Mailbox timeout. "
"Exiting.\n", __func__, base_vha->host_no));
- return QLA_FUNCTION_TIMEOUT;
+ rval = QLA_FUNCTION_TIMEOUT;
+ goto premature_exit;
}
WRT_REG_DWORD(&reg->isp82.hint, HINT_MBX_INT_PENDING);
} else if (IS_FWI2_CAPABLE(ha))
@@ -214,6 +223,15 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp)
ha->flags.mbox_int = 0;
clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags);
+ if (IS_QLA82XX(ha) && ha->flags.fw_hung) {
+ ha->flags.mbox_busy = 0;
+ /* Setting Link-Down error */
+ mcp->mb[0] = MBS_LINK_DOWN_ERROR;
+ ha->mcp = NULL;
+ rval = QLA_FUNCTION_FAILED;
+ goto premature_exit;
+ }
+
if (ha->mailbox_out[0] != MBS_COMMAND_COMPLETE)
rval = QLA_FUNCTION_FAILED;
@@ -279,35 +297,51 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp)
DEBUG2_3_11(printk("%s(%ld): timeout schedule "
"isp_abort_needed.\n", __func__,
base_vha->host_no));
- qla_printk(KERN_WARNING, ha,
- "Mailbox command timeout occurred. Scheduling ISP "
- "abort. eeh_busy: 0x%x\n", ha->flags.eeh_busy);
- set_bit(ISP_ABORT_NEEDED, &base_vha->dpc_flags);
- qla2xxx_wake_dpc(vha);
+
+ if (!test_bit(ISP_ABORT_NEEDED, &vha->dpc_flags) &&
+ !test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags) &&
+ !test_bit(ISP_ABORT_RETRY, &vha->dpc_flags)) {
+
+ qla_printk(KERN_WARNING, ha,
+ "Mailbox command timeout occured. "
+ "Scheduling ISP " "abort. eeh_busy: 0x%x\n",
+ ha->flags.eeh_busy);
+ set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
+ qla2xxx_wake_dpc(vha);
+ }
} else if (!abort_active) {
/* call abort directly since we are in the DPC thread */
DEBUG(printk("%s(%ld): timeout calling abort_isp\n",
__func__, base_vha->host_no));
DEBUG2_3_11(printk("%s(%ld): timeout calling "
"abort_isp\n", __func__, base_vha->host_no));
- qla_printk(KERN_WARNING, ha,
- "Mailbox command timeout occurred. Issuing ISP "
- "abort.\n");
-
- set_bit(ABORT_ISP_ACTIVE, &base_vha->dpc_flags);
- clear_bit(ISP_ABORT_NEEDED, &base_vha->dpc_flags);
- if (ha->isp_ops->abort_isp(base_vha)) {
- /* Failed. retry later. */
- set_bit(ISP_ABORT_NEEDED, &base_vha->dpc_flags);
+
+ if (!test_bit(ISP_ABORT_NEEDED, &vha->dpc_flags) &&
+ !test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags) &&
+ !test_bit(ISP_ABORT_RETRY, &vha->dpc_flags)) {
+
+ qla_printk(KERN_WARNING, ha,
+ "Mailbox command timeout occured. "
+ "Issuing ISP abort.\n");
+
+ set_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags);
+ clear_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
+ if (ha->isp_ops->abort_isp(vha)) {
+ /* Failed. retry later. */
+ set_bit(ISP_ABORT_NEEDED,
+ &vha->dpc_flags);
+ }
+ clear_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags);
+ DEBUG(printk("%s(%ld): finished abort_isp\n",
+ __func__, vha->host_no));
+ DEBUG2_3_11(printk(
+ "%s(%ld): finished abort_isp\n",
+ __func__, vha->host_no));
}
- clear_bit(ABORT_ISP_ACTIVE, &base_vha->dpc_flags);
- DEBUG(printk("%s(%ld): finished abort_isp\n", __func__,
- base_vha->host_no));
- DEBUG2_3_11(printk("%s(%ld): finished abort_isp\n",
- __func__, base_vha->host_no));
}
}
+premature_exit:
/* Allow next mbx cmd to come in. */
complete(&ha->mbx_cmd_comp);
@@ -866,8 +900,8 @@ qla2x00_abort_target(struct fc_port *fcport, unsigned int l, int tag)
l = l;
vha = fcport->vha;
- req = vha->hw->req_q_map[tag];
- rsp = vha->hw->rsp_q_map[tag];
+ req = vha->hw->req_q_map[0];
+ rsp = req->rsp;
mcp->mb[0] = MBC_ABORT_TARGET;
mcp->out_mb = MBX_9|MBX_2|MBX_1|MBX_0;
if (HAS_EXTENDED_IDS(vha->hw)) {
@@ -915,8 +949,8 @@ qla2x00_lun_reset(struct fc_port *fcport, unsigned int l, int tag)
DEBUG11(printk("%s(%ld): entered.\n", __func__, fcport->vha->host_no));
vha = fcport->vha;
- req = vha->hw->req_q_map[tag];
- rsp = vha->hw->rsp_q_map[tag];
+ req = vha->hw->req_q_map[0];
+ rsp = req->rsp;
mcp->mb[0] = MBC_LUN_RESET;
mcp->out_mb = MBX_9|MBX_3|MBX_2|MBX_1|MBX_0;
if (HAS_EXTENDED_IDS(vha->hw))
@@ -3950,6 +3984,72 @@ qla2x00_get_data_rate(scsi_qla_host_t *vha)
}
int
+qla81xx_get_port_config(scsi_qla_host_t *vha, uint16_t *mb)
+{
+ int rval;
+ mbx_cmd_t mc;
+ mbx_cmd_t *mcp = &mc;
+ struct qla_hw_data *ha = vha->hw;
+
+ DEBUG11(printk(KERN_INFO
+ "%s(%ld): entered.\n", __func__, vha->host_no));
+
+ if (!IS_QLA81XX(ha))
+ return QLA_FUNCTION_FAILED;
+ mcp->mb[0] = MBC_GET_PORT_CONFIG;
+ mcp->out_mb = MBX_0;
+ mcp->in_mb = MBX_4|MBX_3|MBX_2|MBX_1|MBX_0;
+ mcp->tov = MBX_TOV_SECONDS;
+ mcp->flags = 0;
+
+ rval = qla2x00_mailbox_command(vha, mcp);
+
+ if (rval != QLA_SUCCESS) {
+ DEBUG2_3_11(printk(KERN_WARNING
+ "%s(%ld): failed=%x (%x).\n", __func__,
+ vha->host_no, rval, mcp->mb[0]));
+ } else {
+ /* Copy all bits to preserve original value */
+ memcpy(mb, &mcp->mb[1], sizeof(uint16_t) * 4);
+
+ DEBUG11(printk(KERN_INFO
+ "%s(%ld): done.\n", __func__, vha->host_no));
+ }
+ return rval;
+}
+
+int
+qla81xx_set_port_config(scsi_qla_host_t *vha, uint16_t *mb)
+{
+ int rval;
+ mbx_cmd_t mc;
+ mbx_cmd_t *mcp = &mc;
+
+ DEBUG11(printk(KERN_INFO
+ "%s(%ld): entered.\n", __func__, vha->host_no));
+
+ mcp->mb[0] = MBC_SET_PORT_CONFIG;
+ /* Copy all bits to preserve original setting */
+ memcpy(&mcp->mb[1], mb, sizeof(uint16_t) * 4);
+ mcp->out_mb = MBX_4|MBX_3|MBX_2|MBX_1|MBX_0;
+ mcp->in_mb = MBX_0;
+ mcp->tov = MBX_TOV_SECONDS;
+ mcp->flags = 0;
+ rval = qla2x00_mailbox_command(vha, mcp);
+
+ if (rval != QLA_SUCCESS) {
+ DEBUG2_3_11(printk(KERN_WARNING
+ "%s(%ld): failed=%x (%x).\n", __func__,
+ vha->host_no, rval, mcp->mb[0]));
+ } else
+ DEBUG11(printk(KERN_INFO
+ "%s(%ld): done.\n", __func__, vha->host_no));
+
+ return rval;
+}
+
+
+int
qla24xx_set_fcp_prio(scsi_qla_host_t *vha, uint16_t loop_id, uint16_t priority,
uint16_t *mb)
{
@@ -4011,7 +4111,7 @@ qla82xx_mbx_intr_enable(scsi_qla_host_t *vha)
"%s(%ld): entered.\n", __func__, vha->host_no));
memset(mcp, 0, sizeof(mbx_cmd_t));
- mcp->mb[0] = MBC_TOGGLE_INTR;
+ mcp->mb[0] = MBC_TOGGLE_INTERRUPT;
mcp->mb[1] = 1;
mcp->out_mb = MBX_1|MBX_0;
@@ -4047,7 +4147,7 @@ qla82xx_mbx_intr_disable(scsi_qla_host_t *vha)
"%s(%ld): entered.\n", __func__, vha->host_no));
memset(mcp, 0, sizeof(mbx_cmd_t));
- mcp->mb[0] = MBC_TOGGLE_INTR;
+ mcp->mb[0] = MBC_TOGGLE_INTERRUPT;
mcp->mb[1] = 0;
mcp->out_mb = MBX_1|MBX_0;
diff --git a/drivers/scsi/qla2xxx/qla_mid.c b/drivers/scsi/qla2xxx/qla_mid.c
index 8220e7b9799..987c5b0ca78 100644
--- a/drivers/scsi/qla2xxx/qla_mid.c
+++ b/drivers/scsi/qla2xxx/qla_mid.c
@@ -1,6 +1,6 @@
/*
* QLogic Fibre Channel HBA Driver
- * Copyright (c) 2003-2008 QLogic Corporation
+ * Copyright (c) 2003-2010 QLogic Corporation
*
* See LICENSE.qla2xxx for copyright and licensing details.
*/
@@ -136,7 +136,8 @@ qla24xx_enable_vp(scsi_qla_host_t *vha)
/* Check if physical ha port is Up */
if (atomic_read(&base_vha->loop_state) == LOOP_DOWN ||
- atomic_read(&base_vha->loop_state) == LOOP_DEAD) {
+ atomic_read(&base_vha->loop_state) == LOOP_DEAD ||
+ !(ha->current_topology & ISP_CFG_F)) {
vha->vp_err_state = VP_ERR_PORTDWN;
fc_vport_set_state(vha->fc_vport, FC_VPORT_LINKDOWN);
goto enable_failed;
@@ -398,7 +399,10 @@ qla24xx_create_vhost(struct fc_vport *fc_vport)
host->can_queue = base_vha->req->length + 128;
host->this_id = 255;
host->cmd_per_lun = 3;
- host->max_cmd_len = MAX_CMDSZ;
+ if ((IS_QLA25XX(ha) || IS_QLA81XX(ha)) && ql2xenabledif)
+ host->max_cmd_len = 32;
+ else
+ host->max_cmd_len = MAX_CMDSZ;
host->max_channel = MAX_BUSES - 1;
host->max_lun = MAX_LUNS;
host->unique_id = host->host_no;
@@ -481,7 +485,7 @@ qla25xx_delete_req_que(struct scsi_qla_host *vha, struct req_que *req)
return ret;
}
-int
+static int
qla25xx_delete_rsp_que(struct scsi_qla_host *vha, struct rsp_que *rsp)
{
int ret = -1;
@@ -496,23 +500,6 @@ qla25xx_delete_rsp_que(struct scsi_qla_host *vha, struct rsp_que *rsp)
return ret;
}
-int qla25xx_update_req_que(struct scsi_qla_host *vha, uint8_t que, uint8_t qos)
-{
- int ret = 0;
- struct qla_hw_data *ha = vha->hw;
- struct req_que *req = ha->req_q_map[que];
-
- req->options |= BIT_3;
- req->qos = qos;
- ret = qla25xx_init_req_que(vha, req);
- if (ret != QLA_SUCCESS)
- DEBUG2_17(printk(KERN_WARNING "%s failed\n", __func__));
- /* restore options bit */
- req->options &= ~BIT_3;
- return ret;
-}
-
-
/* Delete all queues for a given vhost */
int
qla25xx_delete_queues(struct scsi_qla_host *vha)
@@ -739,35 +726,3 @@ que_failed:
failed:
return 0;
}
-
-int
-qla25xx_create_queues(struct scsi_qla_host *vha, uint8_t qos)
-{
- uint16_t options = 0;
- uint8_t ret = 0;
- struct qla_hw_data *ha = vha->hw;
- struct rsp_que *rsp;
-
- options |= BIT_1;
- ret = qla25xx_create_rsp_que(ha, options, vha->vp_idx, 0, -1);
- if (!ret) {
- qla_printk(KERN_WARNING, ha, "Response Que create failed\n");
- return ret;
- } else
- qla_printk(KERN_INFO, ha, "Response Que:%d created.\n", ret);
- rsp = ha->rsp_q_map[ret];
-
- options = 0;
- if (qos & BIT_7)
- options |= BIT_8;
- ret = qla25xx_create_req_que(ha, options, vha->vp_idx, 0, ret,
- qos & ~BIT_7);
- if (ret) {
- vha->req = ha->req_q_map[ret];
- qla_printk(KERN_INFO, ha, "Request Que:%d created.\n", ret);
- } else
- qla_printk(KERN_WARNING, ha, "Request Que create failed\n");
- rsp->req = ha->req_q_map[ret];
-
- return ret;
-}
diff --git a/drivers/scsi/qla2xxx/qla_nx.c b/drivers/scsi/qla2xxx/qla_nx.c
index ff562de0e8e..915b77a6e19 100644
--- a/drivers/scsi/qla2xxx/qla_nx.c
+++ b/drivers/scsi/qla2xxx/qla_nx.c
@@ -1,6 +1,6 @@
/*
* QLogic Fibre Channel HBA Driver
- * Copyright (c) 2003-2008 QLogic Corporation
+ * Copyright (c) 2003-2010 QLogic Corporation
*
* See LICENSE.qla2xxx for copyright and licensing details.
*/
@@ -19,6 +19,7 @@
#define QLA82XX_PCI_OCM0_2M (0xc0000)
#define VALID_OCM_ADDR(addr) (((addr) & 0x3f800) != 0x3f800)
#define GET_MEM_OFFS_2M(addr) (addr & MASK(18))
+#define BLOCK_PROTECT_BITS 0x0F
/* CRB window related */
#define CRB_BLK(off) ((off >> 20) & 0x3f)
@@ -796,179 +797,6 @@ qla82xx_pci_mem_write_direct(struct qla_hw_data *ha,
return ret;
}
-int
-qla82xx_wrmem(struct qla_hw_data *ha, u64 off, void *data, int size)
-{
- int i, j, ret = 0, loop, sz[2], off0;
- u32 temp;
- u64 off8, mem_crb, tmpw, word[2] = {0, 0};
-#define MAX_CTL_CHECK 1000
- /*
- * If not MN, go check for MS or invalid.
- */
- if (off >= QLA82XX_ADDR_QDR_NET && off <= QLA82XX_P3_ADDR_QDR_NET_MAX) {
- mem_crb = QLA82XX_CRB_QDR_NET;
- } else {
- mem_crb = QLA82XX_CRB_DDR_NET;
- if (qla82xx_pci_mem_bound_check(ha, off, size) == 0)
- return qla82xx_pci_mem_write_direct(ha, off,
- data, size);
- }
-
- off8 = off & 0xfffffff8;
- off0 = off & 0x7;
- sz[0] = (size < (8 - off0)) ? size : (8 - off0);
- sz[1] = size - sz[0];
- loop = ((off0 + size - 1) >> 3) + 1;
-
- if ((size != 8) || (off0 != 0)) {
- for (i = 0; i < loop; i++) {
- if (qla82xx_rdmem(ha, off8 + (i << 3), &word[i], 8))
- return -1;
- }
- }
-
- switch (size) {
- case 1:
- tmpw = *((u8 *)data);
- break;
- case 2:
- tmpw = *((u16 *)data);
- break;
- case 4:
- tmpw = *((u32 *)data);
- break;
- case 8:
- default:
- tmpw = *((u64 *)data);
- break;
- }
-
- word[0] &= ~((~(~0ULL << (sz[0] * 8))) << (off0 * 8));
- word[0] |= tmpw << (off0 * 8);
-
- if (loop == 2) {
- word[1] &= ~(~0ULL << (sz[1] * 8));
- word[1] |= tmpw >> (sz[0] * 8);
- }
-
- for (i = 0; i < loop; i++) {
- temp = off8 + (i << 3);
- qla82xx_wr_32(ha, mem_crb+MIU_TEST_AGT_ADDR_LO, temp);
- temp = 0;
- qla82xx_wr_32(ha, mem_crb+MIU_TEST_AGT_ADDR_HI, temp);
- temp = word[i] & 0xffffffff;
- qla82xx_wr_32(ha, mem_crb+MIU_TEST_AGT_WRDATA_LO, temp);
- temp = (word[i] >> 32) & 0xffffffff;
- qla82xx_wr_32(ha, mem_crb+MIU_TEST_AGT_WRDATA_HI, temp);
- temp = MIU_TA_CTL_ENABLE | MIU_TA_CTL_WRITE;
- qla82xx_wr_32(ha, mem_crb+MIU_TEST_AGT_CTRL, temp);
- temp = MIU_TA_CTL_START | MIU_TA_CTL_ENABLE | MIU_TA_CTL_WRITE;
- qla82xx_wr_32(ha, mem_crb+MIU_TEST_AGT_CTRL, temp);
-
- for (j = 0; j < MAX_CTL_CHECK; j++) {
- temp = qla82xx_rd_32(ha, mem_crb + MIU_TEST_AGT_CTRL);
- if ((temp & MIU_TA_CTL_BUSY) == 0)
- break;
- }
-
- if (j >= MAX_CTL_CHECK) {
- qla_printk(KERN_WARNING, ha,
- "%s: Fail to write through agent\n",
- QLA2XXX_DRIVER_NAME);
- ret = -1;
- break;
- }
- }
- return ret;
-}
-
-int
-qla82xx_rdmem(struct qla_hw_data *ha, u64 off, void *data, int size)
-{
- int i, j = 0, k, start, end, loop, sz[2], off0[2];
- u32 temp;
- u64 off8, val, mem_crb, word[2] = {0, 0};
-#define MAX_CTL_CHECK 1000
-
- /*
- * If not MN, go check for MS or invalid.
- */
- if (off >= QLA82XX_ADDR_QDR_NET && off <= QLA82XX_P3_ADDR_QDR_NET_MAX)
- mem_crb = QLA82XX_CRB_QDR_NET;
- else {
- mem_crb = QLA82XX_CRB_DDR_NET;
- if (qla82xx_pci_mem_bound_check(ha, off, size) == 0)
- return qla82xx_pci_mem_read_direct(ha, off,
- data, size);
- }
-
- off8 = off & 0xfffffff8;
- off0[0] = off & 0x7;
- off0[1] = 0;
- sz[0] = (size < (8 - off0[0])) ? size : (8 - off0[0]);
- sz[1] = size - sz[0];
- loop = ((off0[0] + size - 1) >> 3) + 1;
-
- for (i = 0; i < loop; i++) {
- temp = off8 + (i << 3);
- qla82xx_wr_32(ha, mem_crb + MIU_TEST_AGT_ADDR_LO, temp);
- temp = 0;
- qla82xx_wr_32(ha, mem_crb + MIU_TEST_AGT_ADDR_HI, temp);
- temp = MIU_TA_CTL_ENABLE;
- qla82xx_wr_32(ha, mem_crb + MIU_TEST_AGT_CTRL, temp);
- temp = MIU_TA_CTL_START | MIU_TA_CTL_ENABLE;
- qla82xx_wr_32(ha, mem_crb + MIU_TEST_AGT_CTRL, temp);
-
- for (j = 0; j < MAX_CTL_CHECK; j++) {
- temp = qla82xx_rd_32(ha, mem_crb + MIU_TEST_AGT_CTRL);
- if ((temp & MIU_TA_CTL_BUSY) == 0)
- break;
- }
-
- if (j >= MAX_CTL_CHECK) {
- qla_printk(KERN_INFO, ha,
- "%s: Fail to read through agent\n",
- QLA2XXX_DRIVER_NAME);
- break;
- }
-
- start = off0[i] >> 2;
- end = (off0[i] + sz[i] - 1) >> 2;
- for (k = start; k <= end; k++) {
- temp = qla82xx_rd_32(ha,
- mem_crb + MIU_TEST_AGT_RDDATA(k));
- word[i] |= ((u64)temp << (32 * k));
- }
- }
-
- if (j >= MAX_CTL_CHECK)
- return -1;
-
- if (sz[0] == 8) {
- val = word[0];
- } else {
- val = ((word[0] >> (off0[0] * 8)) & (~(~0ULL << (sz[0] * 8)))) |
- ((word[1] & (~(~0ULL << (sz[1] * 8)))) << (sz[0] * 8));
- }
-
- switch (size) {
- case 1:
- *(u8 *)data = val;
- break;
- case 2:
- *(u16 *)data = val;
- break;
- case 4:
- *(u32 *)data = val;
- break;
- case 8:
- *(u64 *)data = val;
- break;
- }
- return 0;
-}
-
#define MTU_FUDGE_FACTOR 100
unsigned long qla82xx_decode_crb_addr(unsigned long addr)
{
@@ -1346,11 +1174,6 @@ int qla82xx_pinit_from_rom(scsi_qla_host_t *vha)
continue;
}
- if (off == (QLA82XX_CRB_PEG_NET_1 + 0x18)) {
- if (!QLA82XX_IS_REVISION_P3PLUS(ha->chip_revision))
- buf[i].data = 0x1020;
- }
-
qla82xx_wr_32(ha, off, buf[i].data);
/* ISP requires much bigger delay to settle down,
@@ -1407,7 +1230,8 @@ qla82xx_fw_load_from_flash(struct qla_hw_data *ha)
{
int i;
long size = 0;
- long flashaddr = BOOTLD_START, memaddr = BOOTLD_START;
+ long flashaddr = ha->flt_region_bootload << 2;
+ long memaddr = BOOTLD_START;
u64 data;
u32 high, low;
size = (IMAGE_START - BOOTLD_START) / 8;
@@ -1427,12 +1251,8 @@ qla82xx_fw_load_from_flash(struct qla_hw_data *ha)
}
udelay(100);
read_lock(&ha->hw_lock);
- if (QLA82XX_IS_REVISION_P3PLUS(ha->chip_revision)) {
- qla82xx_wr_32(ha, QLA82XX_CRB_PEG_NET_0 + 0x18, 0x1020);
- qla82xx_wr_32(ha, QLA82XX_ROMUSB_GLB_SW_RESET, 0x80001e);
- } else {
- qla82xx_wr_32(ha, QLA82XX_ROMUSB_GLB_SW_RESET, 0x80001d);
- }
+ qla82xx_wr_32(ha, QLA82XX_CRB_PEG_NET_0 + 0x18, 0x1020);
+ qla82xx_wr_32(ha, QLA82XX_ROMUSB_GLB_SW_RESET, 0x80001e);
read_unlock(&ha->hw_lock);
return 0;
}
@@ -1459,17 +1279,10 @@ qla82xx_pci_mem_read_2M(struct qla_hw_data *ha,
off, data, size);
}
- if (QLA82XX_IS_REVISION_P3PLUS(ha->chip_revision)) {
- off8 = off & 0xfffffff0;
- off0[0] = off & 0xf;
- sz[0] = (size < (16 - off0[0])) ? size : (16 - off0[0]);
- shift_amount = 4;
- } else {
- off8 = off & 0xfffffff8;
- off0[0] = off & 0x7;
- sz[0] = (size < (8 - off0[0])) ? size : (8 - off0[0]);
- shift_amount = 4;
- }
+ off8 = off & 0xfffffff0;
+ off0[0] = off & 0xf;
+ sz[0] = (size < (16 - off0[0])) ? size : (16 - off0[0]);
+ shift_amount = 4;
loop = ((off0[0] + size - 1) >> shift_amount) + 1;
off0[1] = 0;
sz[1] = size - sz[0];
@@ -1549,7 +1362,7 @@ qla82xx_pci_mem_write_2M(struct qla_hw_data *ha,
u64 off, void *data, int size)
{
int i, j, ret = 0, loop, sz[2], off0;
- int scale, shift_amount, p3p, startword;
+ int scale, shift_amount, startword;
uint32_t temp;
uint64_t off8, mem_crb, tmpw, word[2] = {0, 0};
@@ -1569,28 +1382,16 @@ qla82xx_pci_mem_write_2M(struct qla_hw_data *ha,
sz[0] = (size < (8 - off0)) ? size : (8 - off0);
sz[1] = size - sz[0];
- if (QLA82XX_IS_REVISION_P3PLUS(ha->chip_revision)) {
- off8 = off & 0xfffffff0;
- loop = (((off & 0xf) + size - 1) >> 4) + 1;
- shift_amount = 4;
- scale = 2;
- p3p = 1;
- startword = (off & 0xf)/8;
- } else {
- off8 = off & 0xfffffff8;
- loop = ((off0 + size - 1) >> 3) + 1;
- shift_amount = 3;
- scale = 1;
- p3p = 0;
- startword = 0;
- }
-
- if (p3p || (size != 8) || (off0 != 0)) {
- for (i = 0; i < loop; i++) {
- if (qla82xx_pci_mem_read_2M(ha, off8 +
- (i << shift_amount), &word[i * scale], 8))
- return -1;
- }
+ off8 = off & 0xfffffff0;
+ loop = (((off & 0xf) + size - 1) >> 4) + 1;
+ shift_amount = 4;
+ scale = 2;
+ startword = (off & 0xf)/8;
+
+ for (i = 0; i < loop; i++) {
+ if (qla82xx_pci_mem_read_2M(ha, off8 +
+ (i << shift_amount), &word[i * scale], 8))
+ return -1;
}
switch (size) {
@@ -1609,26 +1410,16 @@ qla82xx_pci_mem_write_2M(struct qla_hw_data *ha,
break;
}
- if (QLA82XX_IS_REVISION_P3PLUS(ha->chip_revision)) {
- if (sz[0] == 8) {
- word[startword] = tmpw;
- } else {
- word[startword] &=
- ~((~(~0ULL << (sz[0] * 8))) << (off0 * 8));
- word[startword] |= tmpw << (off0 * 8);
- }
- if (sz[1] != 0) {
- word[startword+1] &= ~(~0ULL << (sz[1] * 8));
- word[startword+1] |= tmpw >> (sz[0] * 8);
- }
+ if (sz[0] == 8) {
+ word[startword] = tmpw;
} else {
- word[startword] &= ~((~(~0ULL << (sz[0] * 8))) << (off0 * 8));
+ word[startword] &=
+ ~((~(~0ULL << (sz[0] * 8))) << (off0 * 8));
word[startword] |= tmpw << (off0 * 8);
-
- if (loop == 2) {
- word[1] &= ~(~0ULL << (sz[1] * 8));
- word[1] |= tmpw >> (sz[0] * 8);
- }
+ }
+ if (sz[1] != 0) {
+ word[startword+1] &= ~(~0ULL << (sz[1] * 8));
+ word[startword+1] |= tmpw >> (sz[0] * 8);
}
/*
@@ -1645,14 +1436,12 @@ qla82xx_pci_mem_write_2M(struct qla_hw_data *ha,
qla82xx_wr_32(ha, mem_crb+MIU_TEST_AGT_WRDATA_LO, temp);
temp = (word[i * scale] >> 32) & 0xffffffff;
qla82xx_wr_32(ha, mem_crb+MIU_TEST_AGT_WRDATA_HI, temp);
- if (QLA82XX_IS_REVISION_P3PLUS(ha->chip_revision)) {
- temp = word[i*scale + 1] & 0xffffffff;
- qla82xx_wr_32(ha, mem_crb +
- MIU_TEST_AGT_WRDATA_UPPER_LO, temp);
- temp = (word[i*scale + 1] >> 32) & 0xffffffff;
- qla82xx_wr_32(ha, mem_crb +
- MIU_TEST_AGT_WRDATA_UPPER_HI, temp);
- }
+ temp = word[i*scale + 1] & 0xffffffff;
+ qla82xx_wr_32(ha, mem_crb +
+ MIU_TEST_AGT_WRDATA_UPPER_LO, temp);
+ temp = (word[i*scale + 1] >> 32) & 0xffffffff;
+ qla82xx_wr_32(ha, mem_crb +
+ MIU_TEST_AGT_WRDATA_UPPER_HI, temp);
temp = MIU_TA_CTL_ENABLE | MIU_TA_CTL_WRITE;
qla82xx_wr_32(ha, mem_crb + MIU_TEST_AGT_CTRL, temp);
@@ -1677,6 +1466,94 @@ qla82xx_pci_mem_write_2M(struct qla_hw_data *ha,
return ret;
}
+static struct qla82xx_uri_table_desc *
+qla82xx_get_table_desc(const u8 *unirom, int section)
+{
+ uint32_t i;
+ struct qla82xx_uri_table_desc *directory =
+ (struct qla82xx_uri_table_desc *)&unirom[0];
+ __le32 offset;
+ __le32 tab_type;
+ __le32 entries = cpu_to_le32(directory->num_entries);
+
+ for (i = 0; i < entries; i++) {
+ offset = cpu_to_le32(directory->findex) +
+ (i * cpu_to_le32(directory->entry_size));
+ tab_type = cpu_to_le32(*((u32 *)&unirom[offset] + 8));
+
+ if (tab_type == section)
+ return (struct qla82xx_uri_table_desc *)&unirom[offset];
+ }
+
+ return NULL;
+}
+
+static struct qla82xx_uri_data_desc *
+qla82xx_get_data_desc(struct qla_hw_data *ha,
+ u32 section, u32 idx_offset)
+{
+ const u8 *unirom = ha->hablob->fw->data;
+ int idx = cpu_to_le32(*((int *)&unirom[ha->file_prd_off] + idx_offset));
+ struct qla82xx_uri_table_desc *tab_desc = NULL;
+ __le32 offset;
+
+ tab_desc = qla82xx_get_table_desc(unirom, section);
+ if (!tab_desc)
+ return NULL;
+
+ offset = cpu_to_le32(tab_desc->findex) +
+ (cpu_to_le32(tab_desc->entry_size) * idx);
+
+ return (struct qla82xx_uri_data_desc *)&unirom[offset];
+}
+
+static u8 *
+qla82xx_get_bootld_offset(struct qla_hw_data *ha)
+{
+ u32 offset = BOOTLD_START;
+ struct qla82xx_uri_data_desc *uri_desc = NULL;
+
+ if (ha->fw_type == QLA82XX_UNIFIED_ROMIMAGE) {
+ uri_desc = qla82xx_get_data_desc(ha,
+ QLA82XX_URI_DIR_SECT_BOOTLD, QLA82XX_URI_BOOTLD_IDX_OFF);
+ if (uri_desc)
+ offset = cpu_to_le32(uri_desc->findex);
+ }
+
+ return (u8 *)&ha->hablob->fw->data[offset];
+}
+
+static __le32
+qla82xx_get_fw_size(struct qla_hw_data *ha)
+{
+ struct qla82xx_uri_data_desc *uri_desc = NULL;
+
+ if (ha->fw_type == QLA82XX_UNIFIED_ROMIMAGE) {
+ uri_desc = qla82xx_get_data_desc(ha, QLA82XX_URI_DIR_SECT_FW,
+ QLA82XX_URI_FIRMWARE_IDX_OFF);
+ if (uri_desc)
+ return cpu_to_le32(uri_desc->size);
+ }
+
+ return cpu_to_le32(*(u32 *)&ha->hablob->fw->data[FW_SIZE_OFFSET]);
+}
+
+static u8 *
+qla82xx_get_fw_offs(struct qla_hw_data *ha)
+{
+ u32 offset = IMAGE_START;
+ struct qla82xx_uri_data_desc *uri_desc = NULL;
+
+ if (ha->fw_type == QLA82XX_UNIFIED_ROMIMAGE) {
+ uri_desc = qla82xx_get_data_desc(ha, QLA82XX_URI_DIR_SECT_FW,
+ QLA82XX_URI_FIRMWARE_IDX_OFF);
+ if (uri_desc)
+ offset = cpu_to_le32(uri_desc->findex);
+ }
+
+ return (u8 *)&ha->hablob->fw->data[offset];
+}
+
/* PCI related functions */
char *
qla82xx_pci_info_str(struct scsi_qla_host *vha, char *str)
@@ -1714,22 +1591,6 @@ int qla82xx_pci_region_offset(struct pci_dev *pdev, int region)
return val;
}
-int qla82xx_pci_region_len(struct pci_dev *pdev, int region)
-{
- unsigned long val = 0;
- u32 control;
- switch (region) {
- case 0:
- pci_read_config_dword(pdev, QLA82XX_PCI_REG_MSIX_TBL, &control);
- val = control;
- break;
- case 1:
- val = pci_resource_len(pdev, 0) -
- qla82xx_pci_region_offset(pdev, 1);
- break;
- }
- return val;
-}
int
qla82xx_iospace_config(struct qla_hw_data *ha)
@@ -1851,12 +1712,6 @@ void qla82xx_config_rings(struct scsi_qla_host *vha)
icb->response_q_address[0] = cpu_to_le32(LSD(rsp->dma));
icb->response_q_address[1] = cpu_to_le32(MSD(rsp->dma));
- icb->version = 1;
- icb->frame_payload_size = 2112;
- icb->execution_throttle = 8;
- icb->exchange_count = 128;
- icb->login_retry_count = 8;
-
WRT_REG_DWORD((unsigned long __iomem *)&reg->req_q_out[0], 0);
WRT_REG_DWORD((unsigned long __iomem *)&reg->rsp_q_in[0], 0);
WRT_REG_DWORD((unsigned long __iomem *)&reg->rsp_q_out[0], 0);
@@ -1878,19 +1733,19 @@ int qla82xx_fw_load_from_blob(struct qla_hw_data *ha)
size = (IMAGE_START - BOOTLD_START) / 8;
- ptr64 = (u64 *)&ha->hablob->fw->data[BOOTLD_START];
+ ptr64 = (u64 *)qla82xx_get_bootld_offset(ha);
flashaddr = BOOTLD_START;
for (i = 0; i < size; i++) {
data = cpu_to_le64(ptr64[i]);
- qla82xx_pci_mem_write_2M(ha, flashaddr, &data, 8);
+ if (qla82xx_pci_mem_write_2M(ha, flashaddr, &data, 8))
+ return -EIO;
flashaddr += 8;
}
- size = *(u32 *)&ha->hablob->fw->data[FW_SIZE_OFFSET];
- size = (__force u32)cpu_to_le32(size) / 8;
- ptr64 = (u64 *)&ha->hablob->fw->data[IMAGE_START];
flashaddr = FLASH_ADDR_START;
+ size = (__force u32)qla82xx_get_fw_size(ha) / 8;
+ ptr64 = (u64 *)qla82xx_get_fw_offs(ha);
for (i = 0; i < size; i++) {
data = cpu_to_le64(ptr64[i]);
@@ -1899,19 +1754,85 @@ int qla82xx_fw_load_from_blob(struct qla_hw_data *ha)
return -EIO;
flashaddr += 8;
}
+ udelay(100);
/* Write a magic value to CAMRAM register
* at a specified offset to indicate
* that all data is written and
* ready for firmware to initialize.
*/
- qla82xx_wr_32(ha, QLA82XX_CAM_RAM(0x1fc), 0x12345678);
+ qla82xx_wr_32(ha, QLA82XX_CAM_RAM(0x1fc), QLA82XX_BDINFO_MAGIC);
- if (QLA82XX_IS_REVISION_P3PLUS(ha->chip_revision)) {
- qla82xx_wr_32(ha, QLA82XX_CRB_PEG_NET_0 + 0x18, 0x1020);
- qla82xx_wr_32(ha, QLA82XX_ROMUSB_GLB_SW_RESET, 0x80001e);
- } else
- qla82xx_wr_32(ha, QLA82XX_ROMUSB_GLB_SW_RESET, 0x80001d);
+ read_lock(&ha->hw_lock);
+ qla82xx_wr_32(ha, QLA82XX_CRB_PEG_NET_0 + 0x18, 0x1020);
+ qla82xx_wr_32(ha, QLA82XX_ROMUSB_GLB_SW_RESET, 0x80001e);
+ read_unlock(&ha->hw_lock);
+ return 0;
+}
+
+static int
+qla82xx_set_product_offset(struct qla_hw_data *ha)
+{
+ struct qla82xx_uri_table_desc *ptab_desc = NULL;
+ const uint8_t *unirom = ha->hablob->fw->data;
+ uint32_t i;
+ __le32 entries;
+ __le32 flags, file_chiprev, offset;
+ uint8_t chiprev = ha->chip_revision;
+ /* Hardcoding mn_present flag for P3P */
+ int mn_present = 0;
+ uint32_t flagbit;
+
+ ptab_desc = qla82xx_get_table_desc(unirom,
+ QLA82XX_URI_DIR_SECT_PRODUCT_TBL);
+ if (!ptab_desc)
+ return -1;
+
+ entries = cpu_to_le32(ptab_desc->num_entries);
+
+ for (i = 0; i < entries; i++) {
+ offset = cpu_to_le32(ptab_desc->findex) +
+ (i * cpu_to_le32(ptab_desc->entry_size));
+ flags = cpu_to_le32(*((int *)&unirom[offset] +
+ QLA82XX_URI_FLAGS_OFF));
+ file_chiprev = cpu_to_le32(*((int *)&unirom[offset] +
+ QLA82XX_URI_CHIP_REV_OFF));
+
+ flagbit = mn_present ? 1 : 2;
+
+ if ((chiprev == file_chiprev) && ((1ULL << flagbit) & flags)) {
+ ha->file_prd_off = offset;
+ return 0;
+ }
+ }
+ return -1;
+}
+
+int
+qla82xx_validate_firmware_blob(scsi_qla_host_t *vha, uint8_t fw_type)
+{
+ __le32 val;
+ uint32_t min_size;
+ struct qla_hw_data *ha = vha->hw;
+ const struct firmware *fw = ha->hablob->fw;
+
+ ha->fw_type = fw_type;
+
+ if (fw_type == QLA82XX_UNIFIED_ROMIMAGE) {
+ if (qla82xx_set_product_offset(ha))
+ return -EINVAL;
+
+ min_size = QLA82XX_URI_FW_MIN_SIZE;
+ } else {
+ val = cpu_to_le32(*(u32 *)&fw->data[QLA82XX_FW_MAGIC_OFFSET]);
+ if ((__force u32)val != QLA82XX_BDINFO_MAGIC)
+ return -EINVAL;
+
+ min_size = QLA82XX_FW_MIN_SIZE;
+ }
+
+ if (fw->size < min_size)
+ return -EINVAL;
return 0;
}
@@ -2097,8 +2018,6 @@ qla82xx_intr_handler(int irq, void *dev_id)
if (RD_REG_DWORD(&reg->host_int)) {
stat = RD_REG_DWORD(&reg->host_status);
- if ((stat & HSRX_RISC_INT) == 0)
- break;
switch (stat & 0xff) {
case 0x1:
@@ -2173,8 +2092,6 @@ qla82xx_msix_default(int irq, void *dev_id)
do {
if (RD_REG_DWORD(&reg->host_int)) {
stat = RD_REG_DWORD(&reg->host_status);
- if ((stat & HSRX_RISC_INT) == 0)
- break;
switch (stat & 0xff) {
case 0x1:
@@ -2424,12 +2341,6 @@ int qla82xx_load_fw(scsi_qla_host_t *vha)
struct fw_blob *blob;
struct qla_hw_data *ha = vha->hw;
- /* Put both the PEG CMD and RCV PEG to default state
- * of 0 before resetting the hardware
- */
- qla82xx_wr_32(ha, CRB_CMDPEG_STATE, 0);
- qla82xx_wr_32(ha, CRB_RCVPEG_STATE, 0);
-
if (qla82xx_pinit_from_rom(vha) != QLA_SUCCESS) {
qla_printk(KERN_ERR, ha,
"%s: Error during CRB Initialization\n", __func__);
@@ -2470,6 +2381,18 @@ try_blob_fw:
goto fw_load_failed;
}
+ /* Validating firmware blob */
+ if (qla82xx_validate_firmware_blob(vha,
+ QLA82XX_FLASH_ROMIMAGE)) {
+ /* Fallback to URI format */
+ if (qla82xx_validate_firmware_blob(vha,
+ QLA82XX_UNIFIED_ROMIMAGE)) {
+ qla_printk(KERN_ERR, ha,
+ "No valid firmware image found!!!");
+ return QLA_FUNCTION_FAILED;
+ }
+ }
+
if (qla82xx_fw_load_from_blob(ha) == QLA_SUCCESS) {
qla_printk(KERN_ERR, ha,
"%s: Firmware loaded successfully "
@@ -2498,6 +2421,12 @@ qla82xx_start_firmware(scsi_qla_host_t *vha)
/* scrub dma mask expansion register */
qla82xx_wr_32(ha, CRB_DMA_SHIFT, 0x55555555);
+ /* Put both the PEG CMD and RCV PEG to default state
+ * of 0 before resetting the hardware
+ */
+ qla82xx_wr_32(ha, CRB_CMDPEG_STATE, 0);
+ qla82xx_wr_32(ha, CRB_RCVPEG_STATE, 0);
+
/* Overwrite stale initialization register values */
qla82xx_wr_32(ha, QLA82XX_PEG_HALT_STATUS1, 0);
qla82xx_wr_32(ha, QLA82XX_PEG_HALT_STATUS2, 0);
@@ -2977,10 +2906,10 @@ qla82xx_unprotect_flash(struct qla_hw_data *ha)
if (ret < 0)
goto done_unprotect;
- val &= ~(0x7 << 2);
+ val &= ~(BLOCK_PROTECT_BITS << 2);
ret = qla82xx_write_status_reg(ha, val);
if (ret < 0) {
- val |= (0x7 << 2);
+ val |= (BLOCK_PROTECT_BITS << 2);
qla82xx_write_status_reg(ha, val);
}
@@ -3008,7 +2937,7 @@ qla82xx_protect_flash(struct qla_hw_data *ha)
if (ret < 0)
goto done_protect;
- val |= (0x7 << 2);
+ val |= (BLOCK_PROTECT_BITS << 2);
/* LOCK all sectors */
ret = qla82xx_write_status_reg(ha, val);
if (ret < 0)
@@ -3201,11 +3130,16 @@ qla82xx_start_iocbs(srb_t *sp)
dbval = 0x04 | (ha->portnum << 5);
dbval = dbval | (req->id << 8) | (req->ring_index << 16);
- WRT_REG_DWORD((unsigned long __iomem *)ha->nxdb_wr_ptr, dbval);
- wmb();
- while (RD_REG_DWORD(ha->nxdb_rd_ptr) != dbval) {
- WRT_REG_DWORD((unsigned long __iomem *)ha->nxdb_wr_ptr, dbval);
+ if (ql2xdbwr)
+ qla82xx_wr_32(ha, ha->nxdb_wr_ptr, dbval);
+ else {
+ WRT_REG_DWORD((unsigned long __iomem *)ha->nxdb_wr_ptr, dbval);
wmb();
+ while (RD_REG_DWORD(ha->nxdb_rd_ptr) != dbval) {
+ WRT_REG_DWORD((unsigned long __iomem *)ha->nxdb_wr_ptr,
+ dbval);
+ wmb();
+ }
}
}
@@ -3279,6 +3213,10 @@ qla82xx_dev_failed_handler(scsi_qla_host_t *vha)
/* Disable the board */
qla_printk(KERN_INFO, ha, "Disabling the board\n");
+ qla82xx_idc_lock(ha);
+ qla82xx_clear_drv_active(ha);
+ qla82xx_idc_unlock(ha);
+
/* Set DEV_FAILED flag to disable timer */
vha->device_flags |= DFLG_DEV_FAILED;
qla2x00_abort_all_cmds(vha, DID_NO_CONNECT << 16);
@@ -3369,6 +3307,14 @@ qla82xx_check_fw_alive(scsi_qla_host_t *vha)
set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
}
qla2xxx_wake_dpc(vha);
+ if (ha->flags.mbox_busy) {
+ ha->flags.fw_hung = 1;
+ ha->flags.mbox_int = 1;
+ DEBUG2(qla_printk(KERN_ERR, ha,
+ "Due to fw hung, doing premature "
+ "completion of mbx command\n"));
+ complete(&ha->mbx_intr_comp);
+ }
}
}
vha->fw_heartbeat_counter = fw_heartbeat_counter;
@@ -3472,6 +3418,14 @@ void qla82xx_watchdog(scsi_qla_host_t *vha)
"%s(): Adapter reset needed!\n", __func__);
set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
qla2xxx_wake_dpc(vha);
+ if (ha->flags.mbox_busy) {
+ ha->flags.fw_hung = 1;
+ ha->flags.mbox_int = 1;
+ DEBUG2(qla_printk(KERN_ERR, ha,
+ "Need reset, doing premature "
+ "completion of mbx command\n"));
+ complete(&ha->mbx_intr_comp);
+ }
} else {
qla82xx_check_fw_alive(vha);
}
@@ -3527,8 +3481,10 @@ qla82xx_abort_isp(scsi_qla_host_t *vha)
qla82xx_clear_rst_ready(ha);
qla82xx_idc_unlock(ha);
- if (rval == QLA_SUCCESS)
+ if (rval == QLA_SUCCESS) {
+ ha->flags.fw_hung = 0;
qla82xx_restart_isp(vha);
+ }
if (rval) {
vha->flags.online = 1;
diff --git a/drivers/scsi/qla2xxx/qla_nx.h b/drivers/scsi/qla2xxx/qla_nx.h
index f8f99a5ea53..15559cab39f 100644
--- a/drivers/scsi/qla2xxx/qla_nx.h
+++ b/drivers/scsi/qla2xxx/qla_nx.h
@@ -1,6 +1,6 @@
/*
* QLogic Fibre Channel HBA Driver
- * Copyright (c) 2003-2008 QLogic Corporation
+ * Copyright (c) 2003-2010 QLogic Corporation
*
* See LICENSE.qla2xxx for copyright and licensing details.
*/
@@ -538,11 +538,10 @@
/* Driver Coexistence Defines */
#define QLA82XX_CRB_DRV_ACTIVE (QLA82XX_CAM_RAM(0x138))
#define QLA82XX_CRB_DEV_STATE (QLA82XX_CAM_RAM(0x140))
-#define QLA82XX_CRB_DEV_PART_INFO (QLA82XX_CAM_RAM(0x14c))
-#define QLA82XX_CRB_DRV_IDC_VERSION (QLA82XX_CAM_RAM(0x174))
#define QLA82XX_CRB_DRV_STATE (QLA82XX_CAM_RAM(0x144))
#define QLA82XX_CRB_DRV_SCRATCH (QLA82XX_CAM_RAM(0x148))
#define QLA82XX_CRB_DEV_PART_INFO (QLA82XX_CAM_RAM(0x14c))
+#define QLA82XX_CRB_DRV_IDC_VERSION (QLA82XX_CAM_RAM(0x174))
/* Every driver should use these Device State */
#define QLA82XX_DEV_COLD 1
@@ -774,15 +773,49 @@ struct qla82xx_legacy_intr_set {
.pci_int_reg = ISR_MSI_INT_TRIGGER(7) }, \
}
+#define BRDCFG_START 0x4000
#define BOOTLD_START 0x10000
#define IMAGE_START 0x100000
#define FLASH_ADDR_START 0x43000
/* Magic number to let user know flash is programmed */
#define QLA82XX_BDINFO_MAGIC 0x12345678
+#define QLA82XX_FW_MAGIC_OFFSET (BRDCFG_START + 0x128)
#define FW_SIZE_OFFSET (0x3e840c)
+#define QLA82XX_FW_MIN_SIZE 0x3fffff
+
+/* UNIFIED ROMIMAGE START */
+#define QLA82XX_URI_FW_MIN_SIZE 0xc8000
+#define QLA82XX_URI_DIR_SECT_PRODUCT_TBL 0x0
+#define QLA82XX_URI_DIR_SECT_BOOTLD 0x6
+#define QLA82XX_URI_DIR_SECT_FW 0x7
+
+/* Offsets */
+#define QLA82XX_URI_CHIP_REV_OFF 10
+#define QLA82XX_URI_FLAGS_OFF 11
+#define QLA82XX_URI_BIOS_VERSION_OFF 12
+#define QLA82XX_URI_BOOTLD_IDX_OFF 27
+#define QLA82XX_URI_FIRMWARE_IDX_OFF 29
+
+struct qla82xx_uri_table_desc{
+ uint32_t findex;
+ uint32_t num_entries;
+ uint32_t entry_size;
+ uint32_t reserved[5];
+};
+
+struct qla82xx_uri_data_desc{
+ uint32_t findex;
+ uint32_t size;
+ uint32_t reserved[5];
+};
+
+/* UNIFIED ROMIMAGE END */
+
+#define QLA82XX_UNIFIED_ROMIMAGE 3
+#define QLA82XX_FLASH_ROMIMAGE 4
+#define QLA82XX_UNKNOWN_ROMIMAGE 0xff
-#define QLA82XX_IS_REVISION_P3PLUS(_rev_) ((_rev_) >= 0x50)
#define MIU_TEST_AGT_WRDATA_UPPER_LO (0x0b0)
#define MIU_TEST_AGT_WRDATA_UPPER_HI (0x0b4)
@@ -832,7 +865,7 @@ struct fcp_cmnd {
struct scsi_lun lun;
uint8_t crn;
uint8_t task_attribute;
- uint8_t task_managment;
+ uint8_t task_management;
uint8_t additional_cdb_len;
uint8_t cdb[260]; /* 256 for CDB len and 4 for FCP_DL */
};
@@ -853,7 +886,7 @@ struct ct6_dsd {
struct list_head dsd_list;
};
-#define MBC_TOGGLE_INTR 0x10
+#define MBC_TOGGLE_INTERRUPT 0x10
/* Flash offset */
#define FLT_REG_BOOTLOAD_82XX 0x72
diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c
index be1a8fcbb1f..ff2172da7c1 100644
--- a/drivers/scsi/qla2xxx/qla_os.c
+++ b/drivers/scsi/qla2xxx/qla_os.c
@@ -1,6 +1,6 @@
/*
* QLogic Fibre Channel HBA Driver
- * Copyright (c) 2003-2008 QLogic Corporation
+ * Copyright (c) 2003-2010 QLogic Corporation
*
* See LICENSE.qla2xxx for copyright and licensing details.
*/
@@ -140,7 +140,7 @@ MODULE_PARM_DESC(ql2xetsenable,
"Enables firmware ETS burst."
"Default is 0 - skip ETS enablement.");
-int ql2xdbwr;
+int ql2xdbwr = 1;
module_param(ql2xdbwr, int, S_IRUGO|S_IRUSR);
MODULE_PARM_DESC(ql2xdbwr,
"Option to specify scheme for request queue posting\n"
@@ -517,6 +517,7 @@ qla2x00_get_new_sp(scsi_qla_host_t *vha, fc_port_t *fcport,
if (!sp)
return sp;
+ atomic_set(&sp->ref_count, 1);
sp->fcport = fcport;
sp->cmd = cmd;
sp->flags = 0;
@@ -700,7 +701,7 @@ qla2x00_wait_for_hba_online(scsi_qla_host_t *vha)
* Success (Adapter is online/no flash ops) : 0
* Failed (Adapter is offline/disabled/flash ops in progress) : 1
*/
-int
+static int
qla2x00_wait_for_reset_ready(scsi_qla_host_t *vha)
{
int return_status;
@@ -797,6 +798,12 @@ qla2x00_wait_for_loop_ready(scsi_qla_host_t *vha)
return (return_status);
}
+static void
+sp_get(struct srb *sp)
+{
+ atomic_inc(&sp->ref_count);
+}
+
/**************************************************************************
* qla2xxx_eh_abort
*
@@ -825,6 +832,7 @@ qla2xxx_eh_abort(struct scsi_cmnd *cmd)
struct qla_hw_data *ha = vha->hw;
struct req_que *req = vha->req;
srb_t *spt;
+ int got_ref = 0;
fc_block_scsi_eh(cmd);
@@ -856,6 +864,10 @@ qla2xxx_eh_abort(struct scsi_cmnd *cmd)
DEBUG2(printk("%s(%ld): aborting sp %p from RISC."
" pid=%ld.\n", __func__, vha->host_no, sp, serial));
+ /* Get a reference to the sp and drop the lock.*/
+ sp_get(sp);
+ got_ref++;
+
spin_unlock_irqrestore(&ha->hardware_lock, flags);
if (ha->isp_ops->abort_command(sp)) {
DEBUG2(printk("%s(%ld): abort_command "
@@ -881,6 +893,9 @@ qla2xxx_eh_abort(struct scsi_cmnd *cmd)
}
}
+ if (got_ref)
+ qla2x00_sp_compl(ha, sp);
+
qla_printk(KERN_INFO, ha,
"scsi(%ld:%d:%d): Abort command issued -- %d %lx %x.\n",
vha->host_no, id, lun, wait, serial, ret);
@@ -888,24 +903,17 @@ qla2xxx_eh_abort(struct scsi_cmnd *cmd)
return ret;
}
-enum nexus_wait_type {
- WAIT_HOST = 0,
- WAIT_TARGET,
- WAIT_LUN,
-};
-
-static int
+int
qla2x00_eh_wait_for_pending_commands(scsi_qla_host_t *vha, unsigned int t,
- unsigned int l, srb_t *sp, enum nexus_wait_type type)
+ unsigned int l, enum nexus_wait_type type)
{
int cnt, match, status;
unsigned long flags;
struct qla_hw_data *ha = vha->hw;
struct req_que *req;
+ srb_t *sp;
status = QLA_SUCCESS;
- if (!sp)
- return status;
spin_lock_irqsave(&ha->hardware_lock, flags);
req = vha->req;
@@ -943,24 +951,6 @@ qla2x00_eh_wait_for_pending_commands(scsi_qla_host_t *vha, unsigned int t,
return status;
}
-void qla82xx_wait_for_pending_commands(scsi_qla_host_t *vha)
-{
- int cnt;
- srb_t *sp;
- struct req_que *req = vha->req;
-
- DEBUG2(qla_printk(KERN_INFO, vha->hw,
- "Waiting for pending commands\n"));
- for (cnt = 1; cnt < MAX_OUTSTANDING_COMMANDS; cnt++) {
- sp = req->outstanding_cmds[cnt];
- if (qla2x00_eh_wait_for_pending_commands(vha, 0, 0,
- sp, WAIT_HOST) == QLA_SUCCESS) {
- DEBUG2(qla_printk(KERN_INFO, vha->hw,
- "Done wait for pending commands\n"));
- }
- }
-}
-
static char *reset_errors[] = {
"HBA not online",
"HBA not ready",
@@ -996,7 +986,7 @@ __qla2xxx_eh_generic_reset(char *name, enum nexus_wait_type type,
goto eh_reset_failed;
err = 3;
if (qla2x00_eh_wait_for_pending_commands(vha, cmd->device->id,
- cmd->device->lun, (srb_t *) CMD_SP(cmd), type) != QLA_SUCCESS)
+ cmd->device->lun, type) != QLA_SUCCESS)
goto eh_reset_failed;
qla_printk(KERN_INFO, vha->hw, "scsi(%ld:%d:%d): %s RESET SUCCEEDED.\n",
@@ -1004,7 +994,7 @@ __qla2xxx_eh_generic_reset(char *name, enum nexus_wait_type type,
return SUCCESS;
- eh_reset_failed:
+eh_reset_failed:
qla_printk(KERN_INFO, vha->hw, "scsi(%ld:%d:%d): %s RESET FAILED: %s.\n"
, vha->host_no, cmd->device->id, cmd->device->lun, name,
reset_errors[err]);
@@ -1054,7 +1044,6 @@ qla2xxx_eh_bus_reset(struct scsi_cmnd *cmd)
int ret = FAILED;
unsigned int id, lun;
unsigned long serial;
- srb_t *sp = (srb_t *) CMD_SP(cmd);
fc_block_scsi_eh(cmd);
@@ -1081,7 +1070,7 @@ qla2xxx_eh_bus_reset(struct scsi_cmnd *cmd)
goto eh_bus_reset_done;
/* Flush outstanding commands. */
- if (qla2x00_eh_wait_for_pending_commands(vha, 0, 0, sp, WAIT_HOST) !=
+ if (qla2x00_eh_wait_for_pending_commands(vha, 0, 0, WAIT_HOST) !=
QLA_SUCCESS)
ret = FAILED;
@@ -1116,7 +1105,6 @@ qla2xxx_eh_host_reset(struct scsi_cmnd *cmd)
int ret = FAILED;
unsigned int id, lun;
unsigned long serial;
- srb_t *sp = (srb_t *) CMD_SP(cmd);
scsi_qla_host_t *base_vha = pci_get_drvdata(ha->pdev);
fc_block_scsi_eh(cmd);
@@ -1171,7 +1159,7 @@ qla2xxx_eh_host_reset(struct scsi_cmnd *cmd)
}
/* Waiting for command to be returned to OS.*/
- if (qla2x00_eh_wait_for_pending_commands(vha, 0, 0, sp, WAIT_HOST) ==
+ if (qla2x00_eh_wait_for_pending_commands(vha, 0, 0, WAIT_HOST) ==
QLA_SUCCESS)
ret = SUCCESS;
@@ -1662,7 +1650,7 @@ static struct isp_operations qla81xx_isp_ops = {
.read_optrom = qla25xx_read_optrom_data,
.write_optrom = qla24xx_write_optrom_data,
.get_flash_version = qla24xx_get_flash_version,
- .start_scsi = qla24xx_start_scsi,
+ .start_scsi = qla24xx_dif_start_scsi,
.abort_isp = qla2x00_abort_isp,
};
@@ -2113,6 +2101,7 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
init_completion(&ha->mbx_cmd_comp);
complete(&ha->mbx_cmd_comp);
init_completion(&ha->mbx_intr_comp);
+ init_completion(&ha->dcbx_comp);
set_bit(0, (unsigned long *) ha->vp_idx_map);
@@ -2158,7 +2147,10 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
host->this_id = 255;
host->cmd_per_lun = 3;
host->unique_id = host->host_no;
- host->max_cmd_len = MAX_CMDSZ;
+ if ((IS_QLA25XX(ha) || IS_QLA81XX(ha)) && ql2xenabledif)
+ host->max_cmd_len = 32;
+ else
+ host->max_cmd_len = MAX_CMDSZ;
host->max_channel = MAX_BUSES - 1;
host->max_lun = MAX_LUNS;
host->transportt = qla2xxx_transport_template;
@@ -2258,7 +2250,7 @@ skip_dpc:
DEBUG2(printk("DEBUG: detect hba %ld at address = %p\n",
base_vha->host_no, ha));
- if (IS_QLA25XX(ha) && ql2xenabledif) {
+ if ((IS_QLA25XX(ha) || IS_QLA81XX(ha)) && ql2xenabledif) {
if (ha->fw_attributes & BIT_4) {
base_vha->flags.difdix_supported = 1;
DEBUG18(qla_printk(KERN_INFO, ha,
@@ -2266,8 +2258,10 @@ skip_dpc:
" protection.\n"));
scsi_host_set_prot(host,
SHOST_DIF_TYPE1_PROTECTION
+ | SHOST_DIF_TYPE2_PROTECTION
| SHOST_DIF_TYPE3_PROTECTION
| SHOST_DIX_TYPE1_PROTECTION
+ | SHOST_DIX_TYPE2_PROTECTION
| SHOST_DIX_TYPE3_PROTECTION);
scsi_host_set_guard(host, SHOST_DIX_GUARD_CRC);
} else
@@ -2402,6 +2396,10 @@ qla2x00_remove_one(struct pci_dev *pdev)
scsi_host_put(base_vha->host);
if (IS_QLA82XX(ha)) {
+ qla82xx_idc_lock(ha);
+ qla82xx_clear_drv_active(ha);
+ qla82xx_idc_unlock(ha);
+
iounmap((device_reg_t __iomem *)ha->nx_pcibase);
if (!ql2xdbwr)
iounmap((device_reg_t __iomem *)ha->nxdb_wr_ptr);
@@ -2467,11 +2465,24 @@ qla2x00_free_device(scsi_qla_host_t *vha)
qla2x00_free_irqs(vha);
+ qla2x00_free_fcports(vha);
+
qla2x00_mem_free(ha);
qla2x00_free_queues(ha);
}
+void qla2x00_free_fcports(struct scsi_qla_host *vha)
+{
+ fc_port_t *fcport, *tfcport;
+
+ list_for_each_entry_safe(fcport, tfcport, &vha->vp_fcports, list) {
+ list_del(&fcport->list);
+ kfree(fcport);
+ fcport = NULL;
+ }
+}
+
static inline void
qla2x00_schedule_rport_del(struct scsi_qla_host *vha, fc_port_t *fcport,
int defer)
@@ -3463,8 +3474,8 @@ qla2x00_sp_free_dma(srb_t *sp)
CMD_SP(cmd) = NULL;
}
-void
-qla2x00_sp_compl(struct qla_hw_data *ha, srb_t *sp)
+static void
+qla2x00_sp_final_compl(struct qla_hw_data *ha, srb_t *sp)
{
struct scsi_cmnd *cmd = sp->cmd;
@@ -3485,6 +3496,20 @@ qla2x00_sp_compl(struct qla_hw_data *ha, srb_t *sp)
cmd->scsi_done(cmd);
}
+void
+qla2x00_sp_compl(struct qla_hw_data *ha, srb_t *sp)
+{
+ if (atomic_read(&sp->ref_count) == 0) {
+ DEBUG2(qla_printk(KERN_WARNING, ha,
+ "SP reference-count to ZERO -- sp=%p\n", sp));
+ DEBUG2(BUG());
+ return;
+ }
+ if (!atomic_dec_and_test(&sp->ref_count))
+ return;
+ qla2x00_sp_final_compl(ha, sp);
+}
+
/**************************************************************************
* qla2x00_timer
*
diff --git a/drivers/scsi/qla2xxx/qla_settings.h b/drivers/scsi/qla2xxx/qla_settings.h
index 2801c2664b4..f0b2b9986a5 100644
--- a/drivers/scsi/qla2xxx/qla_settings.h
+++ b/drivers/scsi/qla2xxx/qla_settings.h
@@ -1,6 +1,6 @@
/*
* QLogic Fibre Channel HBA Driver
- * Copyright (c) 2003-2008 QLogic Corporation
+ * Copyright (c) 2003-2010 QLogic Corporation
*
* See LICENSE.qla2xxx for copyright and licensing details.
*/
diff --git a/drivers/scsi/qla2xxx/qla_sup.c b/drivers/scsi/qla2xxx/qla_sup.c
index de92504d758..76de9574b38 100644
--- a/drivers/scsi/qla2xxx/qla_sup.c
+++ b/drivers/scsi/qla2xxx/qla_sup.c
@@ -1,6 +1,6 @@
/*
* QLogic Fibre Channel HBA Driver
- * Copyright (c) 2003-2008 QLogic Corporation
+ * Copyright (c) 2003-2010 QLogic Corporation
*
* See LICENSE.qla2xxx for copyright and licensing details.
*/
@@ -664,6 +664,11 @@ qla2xxx_get_flt_info(scsi_qla_host_t *vha, uint32_t flt_addr)
struct qla_hw_data *ha = vha->hw;
struct req_que *req = ha->req_q_map[0];
+ def = 0;
+ if (IS_QLA25XX(ha))
+ def = 1;
+ else if (IS_QLA81XX(ha))
+ def = 2;
ha->flt_region_flt = flt_addr;
wptr = (uint16_t *)req->ring;
flt = (struct qla_flt_header *)req->ring;
@@ -691,6 +696,10 @@ qla2xxx_get_flt_info(scsi_qla_host_t *vha, uint32_t flt_addr)
goto no_flash_data;
}
+ /* Assign FCP prio region since older FLT's may not have it */
+ ha->flt_region_fcp_prio = ha->flags.port0 ?
+ fcp_prio_cfg0[def] : fcp_prio_cfg1[def];
+
loc = locations[1];
cnt = le16_to_cpu(flt->length) / sizeof(struct qla_flt_region);
for ( ; cnt; cnt--, region++) {
@@ -773,13 +782,6 @@ qla2xxx_get_flt_info(scsi_qla_host_t *vha, uint32_t flt_addr)
no_flash_data:
/* Use hardcoded defaults. */
loc = locations[0];
- def = 0;
- if (IS_QLA24XX_TYPE(ha))
- def = 0;
- else if (IS_QLA25XX(ha))
- def = 1;
- else if (IS_QLA81XX(ha))
- def = 2;
ha->flt_region_fw = def_fw[def];
ha->flt_region_boot = def_boot[def];
ha->flt_region_vpd_nvram = def_vpd_nvram[def];
@@ -790,14 +792,13 @@ no_flash_data:
ha->flt_region_fdt = def_fdt[def];
ha->flt_region_npiv_conf = ha->flags.port0 ?
def_npiv_conf0[def] : def_npiv_conf1[def];
- ha->flt_region_fcp_prio = ha->flags.port0 ?
- fcp_prio_cfg0[def] : fcp_prio_cfg1[def];
done:
DEBUG2(qla_printk(KERN_DEBUG, ha, "FLT[%s]: boot=0x%x fw=0x%x "
"vpd_nvram=0x%x vpd=0x%x nvram=0x%x fdt=0x%x flt=0x%x "
- "npiv=0x%x.\n", loc, ha->flt_region_boot, ha->flt_region_fw,
- ha->flt_region_vpd_nvram, ha->flt_region_vpd, ha->flt_region_nvram,
- ha->flt_region_fdt, ha->flt_region_flt, ha->flt_region_npiv_conf));
+ "npiv=0x%x. fcp_prio_cfg=0x%x\n", loc, ha->flt_region_boot,
+ ha->flt_region_fw, ha->flt_region_vpd_nvram, ha->flt_region_vpd,
+ ha->flt_region_nvram, ha->flt_region_fdt, ha->flt_region_flt,
+ ha->flt_region_npiv_conf, ha->flt_region_fcp_prio));
}
static void
@@ -2758,6 +2759,28 @@ qla24xx_get_flash_version(scsi_qla_host_t *vha, void *mbuf)
ha->fw_revision[3] = dcode[3];
}
+ /* Check for golden firmware and get version if available */
+ if (!IS_QLA81XX(ha)) {
+ /* Golden firmware is not present in non 81XX adapters */
+ return ret;
+ }
+
+ memset(ha->gold_fw_version, 0, sizeof(ha->gold_fw_version));
+ dcode = mbuf;
+ ha->isp_ops->read_optrom(vha, (uint8_t *)dcode,
+ ha->flt_region_gold_fw << 2, 32);
+
+ if (dcode[4] == 0xFFFFFFFF && dcode[5] == 0xFFFFFFFF &&
+ dcode[6] == 0xFFFFFFFF && dcode[7] == 0xFFFFFFFF) {
+ DEBUG2(qla_printk(KERN_INFO, ha,
+ "%s(%ld): Unrecognized golden fw at 0x%x.\n",
+ __func__, vha->host_no, ha->flt_region_gold_fw * 4));
+ return ret;
+ }
+
+ for (i = 4; i < 8; i++)
+ ha->gold_fw_version[i-4] = be32_to_cpu(dcode[i]);
+
return ret;
}
diff --git a/drivers/scsi/qla2xxx/qla_version.h b/drivers/scsi/qla2xxx/qla_version.h
index 109068df933..e75ccb91317 100644
--- a/drivers/scsi/qla2xxx/qla_version.h
+++ b/drivers/scsi/qla2xxx/qla_version.h
@@ -1,15 +1,15 @@
/*
* QLogic Fibre Channel HBA Driver
- * Copyright (c) 2003-2008 QLogic Corporation
+ * Copyright (c) 2003-2010 QLogic Corporation
*
* See LICENSE.qla2xxx for copyright and licensing details.
*/
/*
* Driver version
*/
-#define QLA2XXX_VERSION "8.03.02-k2"
+#define QLA2XXX_VERSION "8.03.03-k0"
#define QLA_DRIVER_MAJOR_VER 8
#define QLA_DRIVER_MINOR_VER 3
-#define QLA_DRIVER_PATCH_VER 2
-#define QLA_DRIVER_BETA_VER 2
+#define QLA_DRIVER_PATCH_VER 3
+#define QLA_DRIVER_BETA_VER 0
diff --git a/drivers/scsi/qla4xxx/Kconfig b/drivers/scsi/qla4xxx/Kconfig
index 69cbff3f57c..2c33ce6eac1 100644
--- a/drivers/scsi/qla4xxx/Kconfig
+++ b/drivers/scsi/qla4xxx/Kconfig
@@ -1,7 +1,7 @@
config SCSI_QLA_ISCSI
- tristate "QLogic ISP4XXX host adapter family support"
- depends on PCI && SCSI && NET
+ tristate "QLogic ISP4XXX and ISP82XX host adapter family support"
+ depends on PCI && SCSI
select SCSI_ISCSI_ATTRS
---help---
- This driver supports the QLogic 40xx (ISP4XXX) iSCSI host
- adapter family.
+ This driver supports the QLogic 40xx (ISP4XXX) and 8022 (ISP82XX)
+ iSCSI host adapter family.
diff --git a/drivers/scsi/qla4xxx/Makefile b/drivers/scsi/qla4xxx/Makefile
index 86ea37baa0f..0339ff03a53 100644
--- a/drivers/scsi/qla4xxx/Makefile
+++ b/drivers/scsi/qla4xxx/Makefile
@@ -1,5 +1,5 @@
qla4xxx-y := ql4_os.o ql4_init.o ql4_mbx.o ql4_iocb.o ql4_isr.o \
- ql4_nvram.o ql4_dbg.o
+ ql4_nx.o ql4_nvram.o ql4_dbg.o
obj-$(CONFIG_SCSI_QLA_ISCSI) += qla4xxx.o
diff --git a/drivers/scsi/qla4xxx/ql4_def.h b/drivers/scsi/qla4xxx/ql4_def.h
index 428802616e3..a79da8dd206 100644
--- a/drivers/scsi/qla4xxx/ql4_def.h
+++ b/drivers/scsi/qla4xxx/ql4_def.h
@@ -33,6 +33,8 @@
#include <scsi/scsi_transport.h>
#include <scsi/scsi_transport_iscsi.h>
+#include "ql4_dbg.h"
+#include "ql4_nx.h"
#ifndef PCI_DEVICE_ID_QLOGIC_ISP4010
#define PCI_DEVICE_ID_QLOGIC_ISP4010 0x4010
@@ -46,6 +48,10 @@
#define PCI_DEVICE_ID_QLOGIC_ISP4032 0x4032
#endif
+#ifndef PCI_DEVICE_ID_QLOGIC_ISP8022
+#define PCI_DEVICE_ID_QLOGIC_ISP8022 0x8022
+#endif
+
#define QLA_SUCCESS 0
#define QLA_ERROR 1
@@ -85,15 +91,22 @@
#define BIT_30 0x40000000
#define BIT_31 0x80000000
+/**
+ * Macros to help code, maintain, etc.
+ **/
+#define ql4_printk(level, ha, format, arg...) \
+ dev_printk(level , &((ha)->pdev->dev) , format , ## arg)
+
+
/*
* Host adapter default definitions
***********************************/
#define MAX_HBAS 16
#define MAX_BUSES 1
-#define MAX_TARGETS (MAX_PRST_DEV_DB_ENTRIES + MAX_DEV_DB_ENTRIES)
+#define MAX_TARGETS MAX_DEV_DB_ENTRIES
#define MAX_LUNS 0xffff
#define MAX_AEN_ENTRIES 256 /* should be > EXT_DEF_MAX_AEN_QUEUE */
-#define MAX_DDB_ENTRIES (MAX_PRST_DEV_DB_ENTRIES + MAX_DEV_DB_ENTRIES)
+#define MAX_DDB_ENTRIES MAX_DEV_DB_ENTRIES
#define MAX_PDU_ENTRIES 32
#define INVALID_ENTRY 0xFFFF
#define MAX_CMDS_TO_RISC 1024
@@ -118,7 +131,7 @@
#define DRIVER_NAME "qla4xxx"
#define MAX_LINKED_CMDS_PER_LUN 3
-#define MAX_REQS_SERVICED_PER_INTR 16
+#define MAX_REQS_SERVICED_PER_INTR 1
#define ISCSI_IPADDR_SIZE 4 /* IP address size */
#define ISCSI_ALIAS_SIZE 32 /* ISCSI Alias name size */
@@ -134,7 +147,7 @@
#define SOFT_RESET_TOV 30
#define RESET_INTR_TOV 3
#define SEMAPHORE_TOV 10
-#define ADAPTER_INIT_TOV 120
+#define ADAPTER_INIT_TOV 30
#define ADAPTER_RESET_TOV 180
#define EXTEND_CMD_TOV 60
#define WAIT_CMD_TOV 30
@@ -184,8 +197,6 @@ struct srb {
uint16_t iocb_tov;
uint16_t iocb_cnt; /* Number of used iocbs */
uint16_t cc_stat;
- u_long r_start; /* Time we recieve a cmd from OS */
- u_long u_start; /* Time when we handed the cmd to F/W */
/* Used for extended sense / status continuation */
uint8_t *req_sense_ptr;
@@ -221,7 +232,6 @@ struct ddb_entry {
unsigned long dev_scan_wait_to_start_relogin;
unsigned long dev_scan_wait_to_complete_relogin;
- uint16_t os_target_id; /* Target ID */
uint16_t fw_ddb_index; /* DDB firmware index */
uint16_t options;
uint32_t fw_ddb_device_state; /* F/W Device State -- see ql4_fw.h */
@@ -285,6 +295,67 @@ struct ddb_entry {
#include "ql4_fw.h"
#include "ql4_nvram.h"
+struct ql82xx_hw_data {
+ /* Offsets for flash/nvram access (set to ~0 if not used). */
+ uint32_t flash_conf_off;
+ uint32_t flash_data_off;
+
+ uint32_t fdt_wrt_disable;
+ uint32_t fdt_erase_cmd;
+ uint32_t fdt_block_size;
+ uint32_t fdt_unprotect_sec_cmd;
+ uint32_t fdt_protect_sec_cmd;
+
+ uint32_t flt_region_flt;
+ uint32_t flt_region_fdt;
+ uint32_t flt_region_boot;
+ uint32_t flt_region_bootload;
+ uint32_t flt_region_fw;
+ uint32_t reserved;
+};
+
+struct qla4_8xxx_legacy_intr_set {
+ uint32_t int_vec_bit;
+ uint32_t tgt_status_reg;
+ uint32_t tgt_mask_reg;
+ uint32_t pci_int_reg;
+};
+
+/* MSI-X Support */
+
+#define QLA_MSIX_DEFAULT 0x00
+#define QLA_MSIX_RSP_Q 0x01
+
+#define QLA_MSIX_ENTRIES 2
+#define QLA_MIDX_DEFAULT 0
+#define QLA_MIDX_RSP_Q 1
+
+struct ql4_msix_entry {
+ int have_irq;
+ uint16_t msix_vector;
+ uint16_t msix_entry;
+};
+
+/*
+ * ISP Operations
+ */
+struct isp_operations {
+ int (*iospace_config) (struct scsi_qla_host *ha);
+ void (*pci_config) (struct scsi_qla_host *);
+ void (*disable_intrs) (struct scsi_qla_host *);
+ void (*enable_intrs) (struct scsi_qla_host *);
+ int (*start_firmware) (struct scsi_qla_host *);
+ irqreturn_t (*intr_handler) (int , void *);
+ void (*interrupt_service_routine) (struct scsi_qla_host *, uint32_t);
+ int (*reset_chip) (struct scsi_qla_host *);
+ int (*reset_firmware) (struct scsi_qla_host *);
+ void (*queue_iocb) (struct scsi_qla_host *);
+ void (*complete_iocb) (struct scsi_qla_host *);
+ uint16_t (*rd_shdw_req_q_out) (struct scsi_qla_host *);
+ uint16_t (*rd_shdw_rsp_q_in) (struct scsi_qla_host *);
+ int (*get_sys_info) (struct scsi_qla_host *);
+};
+
/*
* Linux Host Adapter structure
*/
@@ -296,28 +367,39 @@ struct scsi_qla_host {
#define AF_INIT_DONE 1 /* 0x00000002 */
#define AF_MBOX_COMMAND 2 /* 0x00000004 */
#define AF_MBOX_COMMAND_DONE 3 /* 0x00000008 */
+#define AF_DPC_SCHEDULED 5 /* 0x00000020 */
#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 */
+#define AF_HBA_GOING_AWAY 12 /* 0x00001000 */
+#define AF_INTx_ENABLED 15 /* 0x00008000 */
+#define AF_MSI_ENABLED 16 /* 0x00010000 */
+#define AF_MSIX_ENABLED 17 /* 0x00020000 */
+#define AF_MBOX_COMMAND_NOPOLL 18 /* 0x00040000 */
+
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_FW_CONTEXT 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_LINK_CHANGED 18 /* 0x00040000 */
+#define DPC_RESET_ACTIVE 20 /* 0x00040000 */
+#define DPC_HA_UNRECOVERABLE 21 /* 0x00080000 ISP-82xx only*/
+#define DPC_HA_NEED_QUIESCENT 22 /* 0x00100000 ISP-82xx only*/
+
struct Scsi_Host *host; /* pointer to host data */
uint32_t tot_ddbs;
- uint16_t iocb_cnt;
+ uint16_t iocb_cnt;
/* SRB cache. */
#define SRB_MIN_REQ 128
@@ -332,14 +414,13 @@ struct scsi_qla_host {
#define MIN_IOBASE_LEN 0x100
uint16_t req_q_count;
- uint8_t rsvd1[2];
unsigned long host_no;
/* NVRAM registers */
struct eeprom_data *nvram;
spinlock_t hardware_lock ____cacheline_aligned;
- uint32_t eeprom_cmd_data;
+ uint32_t eeprom_cmd_data;
/* Counters for general statistics */
uint64_t isr_count;
@@ -375,7 +456,6 @@ struct scsi_qla_host {
uint8_t alias[32];
uint8_t name_string[256];
uint8_t heartbeat_interval;
- uint8_t rsvd;
/* --- From FlashSysInfo --- */
uint8_t my_mac[MAC_ADDR_LEN];
@@ -469,6 +549,40 @@ struct scsi_qla_host {
struct in6_addr ipv6_addr0;
struct in6_addr ipv6_addr1;
struct in6_addr ipv6_default_router_addr;
+
+ /* qla82xx specific fields */
+ struct device_reg_82xx __iomem *qla4_8xxx_reg; /* Base I/O address */
+ unsigned long nx_pcibase; /* Base I/O address */
+ uint8_t *nx_db_rd_ptr; /* Doorbell read pointer */
+ unsigned long nx_db_wr_ptr; /* Door bell write pointer */
+ unsigned long first_page_group_start;
+ unsigned long first_page_group_end;
+
+ uint32_t crb_win;
+ uint32_t curr_window;
+ uint32_t ddr_mn_window;
+ unsigned long mn_win_crb;
+ unsigned long ms_win_crb;
+ int qdr_sn_window;
+ rwlock_t hw_lock;
+ uint16_t func_num;
+ int link_width;
+
+ struct qla4_8xxx_legacy_intr_set nx_legacy_intr;
+ u32 nx_crb_mask;
+
+ uint8_t revision_id;
+ uint32_t fw_heartbeat_counter;
+
+ struct isp_operations *isp_ops;
+ struct ql82xx_hw_data hw;
+
+ struct ql4_msix_entry msix_entries[QLA_MSIX_ENTRIES];
+
+ uint32_t nx_dev_init_timeout;
+ uint32_t nx_reset_timeout;
+
+ struct completion mbx_intr_comp;
};
static inline int is_ipv4_enabled(struct scsi_qla_host *ha)
@@ -496,6 +610,11 @@ static inline int is_qla4032(struct scsi_qla_host *ha)
return ha->pdev->device == PCI_DEVICE_ID_QLOGIC_ISP4032;
}
+static inline int is_qla8022(struct scsi_qla_host *ha)
+{
+ return ha->pdev->device == PCI_DEVICE_ID_QLOGIC_ISP8022;
+}
+
static inline int adapter_up(struct scsi_qla_host *ha)
{
return (test_bit(AF_ONLINE, &ha->flags) != 0) &&
diff --git a/drivers/scsi/qla4xxx/ql4_fw.h b/drivers/scsi/qla4xxx/ql4_fw.h
index 855226e0866..c94c9ddfb3a 100644
--- a/drivers/scsi/qla4xxx/ql4_fw.h
+++ b/drivers/scsi/qla4xxx/ql4_fw.h
@@ -11,7 +11,7 @@
#define MAX_PRST_DEV_DB_ENTRIES 64
#define MIN_DISC_DEV_DB_ENTRY MAX_PRST_DEV_DB_ENTRIES
-#define MAX_DEV_DB_ENTRIES 512
+#define MAX_DEV_DB_ENTRIES 512
/*************************************************************************
*
@@ -37,6 +37,33 @@ struct host_mem_cfg_regs {
__le32 rsrvd1[31]; /* 0x84-0xFF */
};
+/*
+ * ISP 82xx I/O Register Set structure definitions.
+ */
+struct device_reg_82xx {
+ __le32 req_q_out; /* 0x0000 (R): Request Queue out-Pointer. */
+ __le32 reserve1[63]; /* Request Queue out-Pointer. (64 * 4) */
+ __le32 rsp_q_in; /* 0x0100 (R/W): Response Queue In-Pointer. */
+ __le32 reserve2[63]; /* Response Queue In-Pointer. */
+ __le32 rsp_q_out; /* 0x0200 (R/W): Response Queue Out-Pointer. */
+ __le32 reserve3[63]; /* Response Queue Out-Pointer. */
+
+ __le32 mailbox_in[8]; /* 0x0300 (R/W): Mail box In registers */
+ __le32 reserve4[24];
+ __le32 hint; /* 0x0380 (R/W): Host interrupt register */
+#define HINT_MBX_INT_PENDING BIT_0
+ __le32 reserve5[31];
+ __le32 mailbox_out[8]; /* 0x0400 (R): Mail box Out registers */
+ __le32 reserve6[56];
+
+ __le32 host_status; /* Offset 0x500 (R): host status */
+#define HSRX_RISC_MB_INT BIT_0 /* RISC to Host Mailbox interrupt */
+#define HSRX_RISC_IOCB_INT BIT_1 /* RISC to Host IOCB interrupt */
+
+ __le32 host_int; /* Offset 0x0504 (R/W): Interrupt status. */
+#define ISRX_82XX_RISC_INT BIT_0 /* RISC interrupt. */
+};
+
/* remote register set (access via PCI memory read/write) */
struct isp_reg {
#define MBOX_REG_COUNT 8
@@ -206,6 +233,79 @@ union external_hw_config_reg {
uint32_t Asuint32_t;
};
+/* 82XX Support start */
+/* 82xx Default FLT Addresses */
+#define FA_FLASH_LAYOUT_ADDR_82 0xFC400
+#define FA_FLASH_DESCR_ADDR_82 0xFC000
+#define FA_BOOT_LOAD_ADDR_82 0x04000
+#define FA_BOOT_CODE_ADDR_82 0x20000
+#define FA_RISC_CODE_ADDR_82 0x40000
+#define FA_GOLD_RISC_CODE_ADDR_82 0x80000
+
+/* Flash Description Table */
+struct qla_fdt_layout {
+ uint8_t sig[4];
+ uint16_t version;
+ uint16_t len;
+ uint16_t checksum;
+ uint8_t unused1[2];
+ uint8_t model[16];
+ uint16_t man_id;
+ uint16_t id;
+ uint8_t flags;
+ uint8_t erase_cmd;
+ uint8_t alt_erase_cmd;
+ uint8_t wrt_enable_cmd;
+ uint8_t wrt_enable_bits;
+ uint8_t wrt_sts_reg_cmd;
+ uint8_t unprotect_sec_cmd;
+ uint8_t read_man_id_cmd;
+ uint32_t block_size;
+ uint32_t alt_block_size;
+ uint32_t flash_size;
+ uint32_t wrt_enable_data;
+ uint8_t read_id_addr_len;
+ uint8_t wrt_disable_bits;
+ uint8_t read_dev_id_len;
+ uint8_t chip_erase_cmd;
+ uint16_t read_timeout;
+ uint8_t protect_sec_cmd;
+ uint8_t unused2[65];
+};
+
+/* Flash Layout Table */
+
+struct qla_flt_location {
+ uint8_t sig[4];
+ uint16_t start_lo;
+ uint16_t start_hi;
+ uint8_t version;
+ uint8_t unused[5];
+ uint16_t checksum;
+};
+
+struct qla_flt_header {
+ uint16_t version;
+ uint16_t length;
+ uint16_t checksum;
+ uint16_t unused;
+};
+
+/* 82xx FLT Regions */
+#define FLT_REG_FDT 0x1a
+#define FLT_REG_FLT 0x1c
+#define FLT_REG_BOOTLOAD_82 0x72
+#define FLT_REG_FW_82 0x74
+#define FLT_REG_GOLD_FW_82 0x75
+#define FLT_REG_BOOT_CODE_82 0x78
+
+struct qla_flt_region {
+ uint32_t code;
+ uint32_t size;
+ uint32_t start;
+ uint32_t end;
+};
+
/*************************************************************************
*
* Mailbox Commands Structures and Definitions
@@ -215,6 +315,10 @@ union external_hw_config_reg {
/* Mailbox command definitions */
#define MBOX_CMD_ABOUT_FW 0x0009
#define MBOX_CMD_PING 0x000B
+#define MBOX_CMD_ENABLE_INTRS 0x0010
+#define INTR_DISABLE 0
+#define INTR_ENABLE 1
+#define MBOX_CMD_STOP_FW 0x0014
#define MBOX_CMD_ABORT_TASK 0x0015
#define MBOX_CMD_LUN_RESET 0x0016
#define MBOX_CMD_TARGET_WARM_RESET 0x0017
@@ -243,6 +347,7 @@ union external_hw_config_reg {
#define DDB_DS_LOGIN_IN_PROCESS 0x07
#define MBOX_CMD_GET_FW_STATE 0x0069
#define MBOX_CMD_GET_INIT_FW_CTRL_BLOCK_DEFAULTS 0x006A
+#define MBOX_CMD_GET_SYS_INFO 0x0078
#define MBOX_CMD_RESTORE_FACTORY_DEFAULTS 0x0087
#define MBOX_CMD_SET_ACB 0x0088
#define MBOX_CMD_GET_ACB 0x0089
@@ -318,6 +423,15 @@ union external_hw_config_reg {
#define MBOX_ASTS_IPSEC_SYSTEM_FATAL_ERROR 0x8022
#define MBOX_ASTS_SUBNET_STATE_CHANGE 0x8027
+/* ACB State Defines */
+#define ACB_STATE_UNCONFIGURED 0x00
+#define ACB_STATE_INVALID 0x01
+#define ACB_STATE_ACQUIRING 0x02
+#define ACB_STATE_TENTATIVE 0x03
+#define ACB_STATE_DEPRICATED 0x04
+#define ACB_STATE_VALID 0x05
+#define ACB_STATE_DISABLING 0x06
+
/*************************************************************************/
/* Host Adapter Initialization Control Block (from host) */
@@ -558,6 +672,20 @@ struct flash_sys_info {
uint32_t reserved1[39]; /* 170-1ff */
}; /* 200 */
+struct mbx_sys_info {
+ uint8_t board_id_str[16]; /* Keep board ID string first */
+ /* in this structure for GUI. */
+ uint16_t board_id; /* board ID code */
+ uint16_t phys_port_cnt; /* number of physical network ports */
+ uint16_t port_num; /* network port for this PCI function */
+ /* (port 0 is first port) */
+ uint8_t mac_addr[6]; /* MAC address for this PCI function */
+ uint32_t iscsi_pci_func_cnt; /* number of iSCSI PCI functions */
+ uint32_t pci_func; /* this PCI function */
+ unsigned char serial_number[16]; /* serial number string */
+ uint8_t reserved[16];
+};
+
struct crash_record {
uint16_t fw_major_version; /* 00 - 01 */
uint16_t fw_minor_version; /* 02 - 03 */
@@ -814,4 +942,13 @@ struct passthru_status {
uint8_t res4[16]; /* 30-3F */
};
+/*
+ * ISP queue - response queue entry definition.
+ */
+struct response {
+ uint8_t data[60];
+ uint32_t signature;
+#define RESPONSE_PROCESSED 0xDEADDEAD /* Signature */
+};
+
#endif /* _QLA4X_FW_H */
diff --git a/drivers/scsi/qla4xxx/ql4_glbl.h b/drivers/scsi/qla4xxx/ql4_glbl.h
index c4636f6cb3c..c9cd5d6db98 100644
--- a/drivers/scsi/qla4xxx/ql4_glbl.h
+++ b/drivers/scsi/qla4xxx/ql4_glbl.h
@@ -10,31 +10,32 @@
struct iscsi_cls_conn;
-void qla4xxx_hw_reset(struct scsi_qla_host *ha);
+int 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);
-int qla4xxx_initialize_adapter(struct scsi_qla_host * ha,
+int qla4xxx_send_command_to_isp(struct scsi_qla_host *ha, struct srb *srb);
+int qla4xxx_initialize_adapter(struct scsi_qla_host *ha,
uint8_t renew_ddb_list);
int qla4xxx_soft_reset(struct scsi_qla_host *ha);
irqreturn_t qla4xxx_intr_handler(int irq, void *dev_id);
-void qla4xxx_free_ddb_list(struct scsi_qla_host * ha);
-void qla4xxx_process_aen(struct scsi_qla_host * ha, uint8_t process_aen);
+void qla4xxx_free_ddb_list(struct scsi_qla_host *ha);
+void qla4xxx_free_ddb(struct scsi_qla_host *ha, struct ddb_entry *ddb_entry);
+void qla4xxx_process_aen(struct scsi_qla_host *ha, uint8_t process_aen);
-int qla4xxx_get_dhcp_ip_address(struct scsi_qla_host * ha);
-int qla4xxx_relogin_device(struct scsi_qla_host * ha,
- struct ddb_entry * ddb_entry);
+int qla4xxx_get_dhcp_ip_address(struct scsi_qla_host *ha);
+int qla4xxx_relogin_device(struct scsi_qla_host *ha,
+ struct ddb_entry *ddb_entry);
int qla4xxx_abort_task(struct scsi_qla_host *ha, struct srb *srb);
-int qla4xxx_reset_lun(struct scsi_qla_host * ha, struct ddb_entry * ddb_entry,
+int qla4xxx_reset_lun(struct scsi_qla_host *ha, struct ddb_entry *ddb_entry,
int lun);
-int qla4xxx_reset_target(struct scsi_qla_host * ha,
- struct ddb_entry * ddb_entry);
-int qla4xxx_get_flash(struct scsi_qla_host * ha, dma_addr_t dma_addr,
+int qla4xxx_reset_target(struct scsi_qla_host *ha,
+ struct ddb_entry *ddb_entry);
+int qla4xxx_get_flash(struct scsi_qla_host *ha, dma_addr_t dma_addr,
uint32_t offset, uint32_t len);
-int qla4xxx_get_firmware_status(struct scsi_qla_host * ha);
-int qla4xxx_get_firmware_state(struct scsi_qla_host * ha);
-int qla4xxx_initialize_fw_cb(struct scsi_qla_host * ha);
+int qla4xxx_get_firmware_status(struct scsi_qla_host *ha);
+int qla4xxx_get_firmware_state(struct scsi_qla_host *ha);
+int qla4xxx_initialize_fw_cb(struct scsi_qla_host *ha);
/* FIXME: Goodness! this really wants a small struct to hold the
* parameters. On x86 the args will get passed on the stack! */
@@ -54,20 +55,20 @@ int qla4xxx_set_ddb_entry(struct scsi_qla_host * ha, uint16_t fw_ddb_index,
void qla4xxx_mark_device_missing(struct scsi_qla_host *ha,
struct ddb_entry *ddb_entry);
-u16 rd_nvram_word(struct scsi_qla_host * ha, int offset);
-void qla4xxx_get_crash_record(struct scsi_qla_host * ha);
+u16 rd_nvram_word(struct scsi_qla_host *ha, int offset);
+void qla4xxx_get_crash_record(struct scsi_qla_host *ha);
struct ddb_entry *qla4xxx_alloc_sess(struct scsi_qla_host *ha);
int qla4xxx_add_sess(struct ddb_entry *);
void qla4xxx_destroy_sess(struct ddb_entry *ddb_entry);
-int qla4xxx_is_nvram_configuration_valid(struct scsi_qla_host * ha);
+int qla4xxx_is_nvram_configuration_valid(struct scsi_qla_host *ha);
int qla4xxx_get_fw_version(struct scsi_qla_host * ha);
-void qla4xxx_interrupt_service_routine(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);
+int qla4xxx_init_rings(struct scsi_qla_host *ha);
void qla4xxx_srb_compl(struct kref *ref);
-int qla4xxx_reinitialize_ddb_list(struct scsi_qla_host * ha);
+struct srb *qla4xxx_del_from_active_array(struct scsi_qla_host *ha,
+ uint32_t index);
+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, uint32_t conn_error);
void qla4xxx_dump_buffer(void *b, uint32_t size);
@@ -75,8 +76,65 @@ int qla4xxx_send_marker_iocb(struct scsi_qla_host *ha,
struct ddb_entry *ddb_entry, int lun, uint16_t mrkr_mod);
int qla4_is_relogin_allowed(struct scsi_qla_host *ha, uint32_t conn_err);
+int qla4xxx_mailbox_command(struct scsi_qla_host *ha, uint8_t inCount,
+ uint8_t outCount, uint32_t *mbx_cmd, uint32_t *mbx_sts);
+
+void qla4xxx_queue_iocb(struct scsi_qla_host *ha);
+void qla4xxx_complete_iocb(struct scsi_qla_host *ha);
+int qla4xxx_get_sys_info(struct scsi_qla_host *ha);
+int qla4xxx_iospace_config(struct scsi_qla_host *ha);
+void qla4xxx_pci_config(struct scsi_qla_host *ha);
+int qla4xxx_start_firmware(struct scsi_qla_host *ha);
+irqreturn_t qla4xxx_intr_handler(int irq, void *dev_id);
+uint16_t qla4xxx_rd_shdw_req_q_out(struct scsi_qla_host *ha);
+uint16_t qla4xxx_rd_shdw_rsp_q_in(struct scsi_qla_host *ha);
+int qla4xxx_request_irqs(struct scsi_qla_host *ha);
+void qla4xxx_free_irqs(struct scsi_qla_host *ha);
+void qla4xxx_process_response_queue(struct scsi_qla_host *ha);
+void qla4xxx_wake_dpc(struct scsi_qla_host *ha);
+void qla4xxx_get_conn_event_log(struct scsi_qla_host *ha);
+
+void qla4_8xxx_pci_config(struct scsi_qla_host *);
+int qla4_8xxx_iospace_config(struct scsi_qla_host *ha);
+int qla4_8xxx_load_risc(struct scsi_qla_host *);
+irqreturn_t qla4_8xxx_intr_handler(int irq, void *dev_id);
+void qla4_8xxx_queue_iocb(struct scsi_qla_host *ha);
+void qla4_8xxx_complete_iocb(struct scsi_qla_host *ha);
+
+int qla4_8xxx_crb_win_lock(struct scsi_qla_host *);
+void qla4_8xxx_crb_win_unlock(struct scsi_qla_host *);
+int qla4_8xxx_pci_get_crb_addr_2M(struct scsi_qla_host *, ulong *);
+void qla4_8xxx_wr_32(struct scsi_qla_host *, ulong, u32);
+int qla4_8xxx_rd_32(struct scsi_qla_host *, ulong);
+int qla4_8xxx_pci_mem_read_2M(struct scsi_qla_host *, u64, void *, int);
+int qla4_8xxx_pci_mem_write_2M(struct scsi_qla_host *ha, u64, void *, int);
+int qla4_8xxx_isp_reset(struct scsi_qla_host *ha);
+void qla4_8xxx_interrupt_service_routine(struct scsi_qla_host *ha,
+ uint32_t intr_status);
+uint16_t qla4_8xxx_rd_shdw_req_q_out(struct scsi_qla_host *ha);
+uint16_t qla4_8xxx_rd_shdw_rsp_q_in(struct scsi_qla_host *ha);
+int qla4_8xxx_get_sys_info(struct scsi_qla_host *ha);
+void qla4_8xxx_watchdog(struct scsi_qla_host *ha);
+int qla4_8xxx_stop_firmware(struct scsi_qla_host *ha);
+int qla4_8xxx_get_flash_info(struct scsi_qla_host *ha);
+void qla4_8xxx_enable_intrs(struct scsi_qla_host *ha);
+void qla4_8xxx_disable_intrs(struct scsi_qla_host *ha);
+int qla4_8xxx_enable_msix(struct scsi_qla_host *ha);
+void qla4_8xxx_disable_msix(struct scsi_qla_host *ha);
+irqreturn_t qla4_8xxx_msi_handler(int irq, void *dev_id);
+irqreturn_t qla4_8xxx_default_intr_handler(int irq, void *dev_id);
+irqreturn_t qla4_8xxx_msix_rsp_q(int irq, void *dev_id);
+void qla4xxx_mark_all_devices_missing(struct scsi_qla_host *ha);
+void qla4xxx_dead_adapter_cleanup(struct scsi_qla_host *ha);
+int qla4_8xxx_idc_lock(struct scsi_qla_host *ha);
+void qla4_8xxx_idc_unlock(struct scsi_qla_host *ha);
+int qla4_8xxx_device_state_handler(struct scsi_qla_host *ha);
+void qla4_8xxx_need_qsnt_handler(struct scsi_qla_host *ha);
+void qla4_8xxx_clear_drv_active(struct scsi_qla_host *ha);
+
extern int ql4xextended_error_logging;
extern int ql4xdiscoverywait;
extern int ql4xdontresethba;
-extern int ql4_mod_unload;
+extern int ql4xenablemsix;
+
#endif /* _QLA4x_GBL_H */
diff --git a/drivers/scsi/qla4xxx/ql4_init.c b/drivers/scsi/qla4xxx/ql4_init.c
index 5510df8a7fa..30073577c3a 100644
--- a/drivers/scsi/qla4xxx/ql4_init.c
+++ b/drivers/scsi/qla4xxx/ql4_init.c
@@ -11,8 +11,8 @@
#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);
+static struct ddb_entry *qla4xxx_alloc_ddb(struct scsi_qla_host *ha,
+ uint32_t fw_ddb_index);
static void ql4xxx_set_mac_number(struct scsi_qla_host *ha)
{
@@ -51,8 +51,8 @@ static void ql4xxx_set_mac_number(struct scsi_qla_host *ha)
* This routine deallocates and unlinks the specified ddb_entry from the
* adapter's
**/
-static void qla4xxx_free_ddb(struct scsi_qla_host *ha,
- struct ddb_entry *ddb_entry)
+void qla4xxx_free_ddb(struct scsi_qla_host *ha,
+ struct ddb_entry *ddb_entry)
{
/* Remove device entry from list */
list_del_init(&ddb_entry->list);
@@ -86,6 +86,25 @@ void qla4xxx_free_ddb_list(struct scsi_qla_host *ha)
}
/**
+ * qla4xxx_init_response_q_entries() - Initializes response queue entries.
+ * @ha: HA context
+ *
+ * Beginning of request ring has initialization control block already built
+ * by nvram config routine.
+ **/
+static void qla4xxx_init_response_q_entries(struct scsi_qla_host *ha)
+{
+ uint16_t cnt;
+ struct response *pkt;
+
+ pkt = (struct response *)ha->response_ptr;
+ for (cnt = 0; cnt < RESPONSE_QUEUE_DEPTH; cnt++) {
+ pkt->signature = RESPONSE_PROCESSED;
+ pkt++;
+ }
+}
+
+/**
* qla4xxx_init_rings - initialize hw queues
* @ha: pointer to host adapter structure.
*
@@ -109,19 +128,31 @@ int qla4xxx_init_rings(struct scsi_qla_host *ha)
ha->response_out = 0;
ha->response_ptr = &ha->response_ring[ha->response_out];
- /*
- * Initialize DMA Shadow registers. The firmware is really supposed to
- * take care of this, but on some uniprocessor systems, the shadow
- * registers aren't cleared-- causing the interrupt_handler to think
- * there are responses to be processed when there aren't.
- */
- ha->shadow_regs->req_q_out = __constant_cpu_to_le32(0);
- ha->shadow_regs->rsp_q_in = __constant_cpu_to_le32(0);
- wmb();
+ if (is_qla8022(ha)) {
+ writel(0,
+ (unsigned long __iomem *)&ha->qla4_8xxx_reg->req_q_out);
+ writel(0,
+ (unsigned long __iomem *)&ha->qla4_8xxx_reg->rsp_q_in);
+ writel(0,
+ (unsigned long __iomem *)&ha->qla4_8xxx_reg->rsp_q_out);
+ } else {
+ /*
+ * Initialize DMA Shadow registers. The firmware is really
+ * supposed to take care of this, but on some uniprocessor
+ * systems, the shadow registers aren't cleared-- causing
+ * the interrupt_handler to think there are responses to be
+ * processed when there aren't.
+ */
+ ha->shadow_regs->req_q_out = __constant_cpu_to_le32(0);
+ ha->shadow_regs->rsp_q_in = __constant_cpu_to_le32(0);
+ wmb();
- writel(0, &ha->reg->req_q_in);
- writel(0, &ha->reg->rsp_q_out);
- readl(&ha->reg->rsp_q_out);
+ writel(0, &ha->reg->req_q_in);
+ writel(0, &ha->reg->rsp_q_out);
+ readl(&ha->reg->rsp_q_out);
+ }
+
+ qla4xxx_init_response_q_entries(ha);
spin_unlock_irqrestore(&ha->hardware_lock, flags);
@@ -129,11 +160,11 @@ int qla4xxx_init_rings(struct scsi_qla_host *ha)
}
/**
- * qla4xxx_validate_mac_address - validate adapter MAC address(es)
+ * qla4xxx_get_sys_info - validate adapter MAC address(es)
* @ha: pointer to host adapter structure.
*
**/
-static int qla4xxx_validate_mac_address(struct scsi_qla_host *ha)
+int qla4xxx_get_sys_info(struct scsi_qla_host *ha)
{
struct flash_sys_info *sys_info;
dma_addr_t sys_info_dma;
@@ -145,7 +176,7 @@ static int qla4xxx_validate_mac_address(struct scsi_qla_host *ha)
DEBUG2(printk("scsi%ld: %s: Unable to allocate dma buffer.\n",
ha->host_no, __func__));
- goto exit_validate_mac_no_free;
+ goto exit_get_sys_info_no_free;
}
memset(sys_info, 0, sizeof(*sys_info));
@@ -155,7 +186,7 @@ static int qla4xxx_validate_mac_address(struct scsi_qla_host *ha)
DEBUG2(printk("scsi%ld: %s: get_flash FLASH_OFFSET_SYS_INFO "
"failed\n", ha->host_no, __func__));
- goto exit_validate_mac;
+ goto exit_get_sys_info;
}
/* Save M.A.C. address & serial_number */
@@ -168,11 +199,11 @@ static int qla4xxx_validate_mac_address(struct scsi_qla_host *ha)
status = QLA_SUCCESS;
- exit_validate_mac:
+exit_get_sys_info:
dma_free_coherent(&ha->pdev->dev, sizeof(*sys_info), sys_info,
sys_info_dma);
- exit_validate_mac_no_free:
+exit_get_sys_info_no_free:
return status;
}
@@ -183,7 +214,7 @@ static int qla4xxx_validate_mac_address(struct scsi_qla_host *ha)
**/
static int qla4xxx_init_local_data(struct scsi_qla_host *ha)
{
- /* Initilize aen queue */
+ /* Initialize aen queue */
ha->aen_q_count = MAX_AEN_ENTRIES;
return qla4xxx_get_firmware_status(ha);
@@ -266,7 +297,7 @@ static int qla4xxx_fw_ready(struct scsi_qla_host *ha)
uint32_t timeout_count;
int ready = 0;
- DEBUG2(dev_info(&ha->pdev->dev, "Waiting for Firmware Ready..\n"));
+ DEBUG2(ql4_printk(KERN_INFO, ha, "Waiting for Firmware Ready..\n"));
for (timeout_count = ADAPTER_INIT_TOV; timeout_count > 0;
timeout_count--) {
if (test_and_clear_bit(DPC_GET_DHCP_IP_ADDR, &ha->dpc_flags))
@@ -339,29 +370,29 @@ static int qla4xxx_fw_ready(struct scsi_qla_host *ha)
if (!qla4xxx_wait_for_ip_config(ha) ||
timeout_count == 1) {
- DEBUG2(dev_info(&ha->pdev->dev,
- "Firmware Ready..\n"));
+ DEBUG2(ql4_printk(KERN_INFO, ha,
+ "Firmware Ready..\n"));
/* The firmware is ready to process SCSI
commands. */
- DEBUG2(dev_info(&ha->pdev->dev,
+ DEBUG2(ql4_printk(KERN_INFO, ha,
"scsi%ld: %s: MEDIA TYPE"
" - %s\n", ha->host_no,
__func__, (ha->addl_fw_state &
FW_ADDSTATE_OPTICAL_MEDIA)
!= 0 ? "OPTICAL" : "COPPER"));
- DEBUG2(dev_info(&ha->pdev->dev,
+ DEBUG2(ql4_printk(KERN_INFO, ha,
"scsi%ld: %s: DHCPv4 STATE"
" Enabled %s\n", ha->host_no,
__func__, (ha->addl_fw_state &
FW_ADDSTATE_DHCPv4_ENABLED) != 0 ?
"YES" : "NO"));
- DEBUG2(dev_info(&ha->pdev->dev,
+ DEBUG2(ql4_printk(KERN_INFO, ha,
"scsi%ld: %s: LINK %s\n",
ha->host_no, __func__,
(ha->addl_fw_state &
FW_ADDSTATE_LINK_UP) != 0 ?
"UP" : "DOWN"));
- DEBUG2(dev_info(&ha->pdev->dev,
+ DEBUG2(ql4_printk(KERN_INFO, ha,
"scsi%ld: %s: iSNS Service "
"Started %s\n",
ha->host_no, __func__,
@@ -399,6 +430,7 @@ static int qla4xxx_fw_ready(struct scsi_qla_host *ha)
DEBUG2(printk("scsi%ld: %s: FW initialized, but "
"auto-discovery still in process\n",
ha->host_no, __func__));
+ ready = 1;
}
return ready;
@@ -413,7 +445,7 @@ static int qla4xxx_init_firmware(struct scsi_qla_host *ha)
{
int status = QLA_ERROR;
- dev_info(&ha->pdev->dev, "Initializing firmware..\n");
+ ql4_printk(KERN_INFO, ha, "Initializing firmware..\n");
if (qla4xxx_initialize_fw_cb(ha) == QLA_ERROR) {
DEBUG2(printk("scsi%ld: %s: Failed to initialize firmware "
"control block\n", ha->host_no, __func__));
@@ -443,17 +475,17 @@ static struct ddb_entry* qla4xxx_get_ddb_entry(struct scsi_qla_host *ha,
if (fw_ddb_entry == NULL) {
DEBUG2(printk("scsi%ld: %s: Unable to allocate dma buffer.\n",
ha->host_no, __func__));
- return NULL;
+ goto exit_get_ddb_entry_no_free;
}
if (qla4xxx_get_fwddb_entry(ha, fw_ddb_index, fw_ddb_entry,
fw_ddb_entry_dma, NULL, NULL,
&device_state, NULL, NULL, NULL) ==
- QLA_ERROR) {
+ QLA_ERROR) {
DEBUG2(printk("scsi%ld: %s: failed get_ddb_entry for "
"fw_ddb_index %d\n", ha->host_no, __func__,
fw_ddb_index));
- return NULL;
+ goto exit_get_ddb_entry;
}
/* Allocate DDB if not already allocated. */
@@ -471,6 +503,7 @@ static struct ddb_entry* qla4xxx_get_ddb_entry(struct scsi_qla_host *ha,
}
}
+ /* if not found allocate new ddb */
if (!found) {
DEBUG2(printk("scsi%ld: %s: ddb[%d] not found - allocating "
"new ddb\n", ha->host_no, __func__,
@@ -479,10 +512,11 @@ static struct ddb_entry* qla4xxx_get_ddb_entry(struct scsi_qla_host *ha,
ddb_entry = qla4xxx_alloc_ddb(ha, fw_ddb_index);
}
- /* if not found allocate new ddb */
+exit_get_ddb_entry:
dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry), fw_ddb_entry,
fw_ddb_entry_dma);
+exit_get_ddb_entry_no_free:
return ddb_entry;
}
@@ -510,7 +544,8 @@ static int qla4xxx_update_ddb_entry(struct scsi_qla_host *ha,
if (ddb_entry == NULL) {
DEBUG2(printk("scsi%ld: %s: ddb_entry is NULL\n", ha->host_no,
__func__));
- goto exit_update_ddb;
+
+ goto exit_update_ddb_no_free;
}
/* Make sure the dma buffer is valid */
@@ -521,7 +556,7 @@ static int qla4xxx_update_ddb_entry(struct scsi_qla_host *ha,
DEBUG2(printk("scsi%ld: %s: Unable to allocate dma buffer.\n",
ha->host_no, __func__));
- goto exit_update_ddb;
+ goto exit_update_ddb_no_free;
}
if (qla4xxx_get_fwddb_entry(ha, fw_ddb_index, fw_ddb_entry,
@@ -529,7 +564,7 @@ static int qla4xxx_update_ddb_entry(struct scsi_qla_host *ha,
&ddb_entry->fw_ddb_device_state, &conn_err,
&ddb_entry->tcp_source_port_num,
&ddb_entry->connection_id) ==
- QLA_ERROR) {
+ QLA_ERROR) {
DEBUG2(printk("scsi%ld: %s: failed get_ddb_entry for "
"fw_ddb_index %d\n", ha->host_no, __func__,
fw_ddb_index));
@@ -559,6 +594,9 @@ static int qla4xxx_update_ddb_entry(struct scsi_qla_host *ha,
memcpy(&ddb_entry->iscsi_name[0], &fw_ddb_entry->iscsi_name[0],
min(sizeof(ddb_entry->iscsi_name),
sizeof(fw_ddb_entry->iscsi_name)));
+ memcpy(&ddb_entry->iscsi_alias[0], &fw_ddb_entry->iscsi_alias[0],
+ min(sizeof(ddb_entry->iscsi_alias),
+ sizeof(fw_ddb_entry->iscsi_alias)));
memcpy(&ddb_entry->ip_addr[0], &fw_ddb_entry->ip_addr[0],
min(sizeof(ddb_entry->ip_addr), sizeof(fw_ddb_entry->ip_addr)));
@@ -580,21 +618,19 @@ static int qla4xxx_update_ddb_entry(struct scsi_qla_host *ha,
min(sizeof(ddb_entry->link_local_ipv6_addr),
sizeof(fw_ddb_entry->link_local_ipv6_addr)));
- DEBUG2(dev_info(&ha->pdev->dev, "%s: DDB[%d] osIdx = %d "
- "State %04x ConnErr %08x IP %pI6 "
+ DEBUG2(ql4_printk(KERN_INFO, ha, "%s: DDB[%d] State %04x"
+ " ConnErr %08x IP %pI6 "
":%04d \"%s\"\n",
__func__, fw_ddb_index,
- ddb_entry->os_target_id,
ddb_entry->fw_ddb_device_state,
conn_err, fw_ddb_entry->ip_addr,
le16_to_cpu(fw_ddb_entry->port),
fw_ddb_entry->iscsi_name));
} else
- DEBUG2(dev_info(&ha->pdev->dev, "%s: DDB[%d] osIdx = %d "
- "State %04x ConnErr %08x IP %pI4 "
+ DEBUG2(ql4_printk(KERN_INFO, ha, "%s: DDB[%d] State %04x"
+ " ConnErr %08x IP %pI4 "
":%04d \"%s\"\n",
__func__, fw_ddb_index,
- ddb_entry->os_target_id,
ddb_entry->fw_ddb_device_state,
conn_err, fw_ddb_entry->ip_addr,
le16_to_cpu(fw_ddb_entry->port),
@@ -604,6 +640,7 @@ exit_update_ddb:
dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry),
fw_ddb_entry, fw_ddb_entry_dma);
+exit_update_ddb_no_free:
return status;
}
@@ -660,18 +697,18 @@ int qla4_is_relogin_allowed(struct scsi_qla_host *ha, uint32_t conn_err)
err_code = ((conn_err & 0x00ff0000) >> 16);
login_rsp_sts_class = ((conn_err & 0x0000ff00) >> 8);
if (err_code == 0x1c || err_code == 0x06) {
- DEBUG2(dev_info(&ha->pdev->dev,
- ": conn_err=0x%08x, send target completed"
- " or access denied failure\n", conn_err));
+ DEBUG2(ql4_printk(KERN_INFO, ha,
+ ": conn_err=0x%08x, send target completed"
+ " or access denied failure\n", conn_err));
relogin = 0;
}
if ((err_code == 0x08) && (login_rsp_sts_class == 0x02)) {
/* Login Response PDU returned an error.
Login Response Status in Error Code Detail
indicates login should not be retried.*/
- DEBUG2(dev_info(&ha->pdev->dev,
- ": conn_err=0x%08x, do not retry relogin\n",
- conn_err));
+ DEBUG2(ql4_printk(KERN_INFO, ha,
+ ": conn_err=0x%08x, do not retry relogin\n",
+ conn_err));
relogin = 0;
}
@@ -688,7 +725,7 @@ int qla4_is_relogin_allowed(struct scsi_qla_host *ha, uint32_t conn_err)
**/
static int qla4xxx_build_ddb_list(struct scsi_qla_host *ha)
{
- int status = QLA_SUCCESS;
+ int status = QLA_ERROR;
uint32_t fw_ddb_index = 0;
uint32_t next_fw_ddb_index = 0;
uint32_t ddb_state;
@@ -702,12 +739,13 @@ static int qla4xxx_build_ddb_list(struct scsi_qla_host *ha)
fw_ddb_entry = dma_alloc_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry),
&fw_ddb_entry_dma, GFP_KERNEL);
if (fw_ddb_entry == NULL) {
- DEBUG2(dev_info(&ha->pdev->dev, "%s: DMA alloc failed\n",
+ DEBUG2(ql4_printk(KERN_INFO, ha, "%s: DMA alloc failed\n",
__func__));
- return QLA_ERROR;
+
+ goto exit_build_ddb_list_no_free;
}
- dev_info(&ha->pdev->dev, "Initializing DDBs ...\n");
+ ql4_printk(KERN_INFO, ha, "Initializing DDBs ...\n");
for (fw_ddb_index = 0; fw_ddb_index < MAX_DDB_ENTRIES;
fw_ddb_index = next_fw_ddb_index) {
/* First, let's see if a device exists here */
@@ -719,7 +757,7 @@ static int qla4xxx_build_ddb_list(struct scsi_qla_host *ha)
DEBUG2(printk("scsi%ld: %s: get_ddb_entry, "
"fw_ddb_index %d failed", ha->host_no,
__func__, fw_ddb_index));
- return QLA_ERROR;
+ goto exit_build_ddb_list;
}
DEBUG2(printk("scsi%ld: %s: Getting DDB[%d] ddbstate=0x%x, "
@@ -749,7 +787,7 @@ static int qla4xxx_build_ddb_list(struct scsi_qla_host *ha)
"get_ddb_entry %d failed\n",
ha->host_no,
__func__, fw_ddb_index));
- return QLA_ERROR;
+ goto exit_build_ddb_list;
}
}
}
@@ -769,7 +807,7 @@ static int qla4xxx_build_ddb_list(struct scsi_qla_host *ha)
DEBUG2(printk("scsi%ld: %s: Unable to allocate memory "
"for device at fw_ddb_index %d\n",
ha->host_no, __func__, fw_ddb_index));
- return QLA_ERROR;
+ goto exit_build_ddb_list;
}
/* Fill in the device structure */
if (qla4xxx_update_ddb_entry(ha, ddb_entry, fw_ddb_index) ==
@@ -777,11 +815,10 @@ static int qla4xxx_build_ddb_list(struct scsi_qla_host *ha)
ha->fw_ddb_index_map[fw_ddb_index] =
(struct ddb_entry *)INVALID_ENTRY;
-
DEBUG2(printk("scsi%ld: %s: update_ddb_entry failed "
"for fw_ddb_index %d.\n",
ha->host_no, __func__, fw_ddb_index));
- return QLA_ERROR;
+ goto exit_build_ddb_list;
}
next_one:
@@ -791,8 +828,14 @@ next_one:
break;
}
- dev_info(&ha->pdev->dev, "DDB list done..\n");
+ status = QLA_SUCCESS;
+ ql4_printk(KERN_INFO, ha, "DDB list done..\n");
+
+exit_build_ddb_list:
+ dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry), fw_ddb_entry,
+ fw_ddb_entry_dma);
+exit_build_ddb_list_no_free:
return status;
}
@@ -951,6 +994,9 @@ static int qla4xxx_initialize_ddb_list(struct scsi_qla_host *ha)
qla4xxx_flush_AENS(ha);
+ /* Wait for an AEN */
+ qla4xxx_devices_ready(ha);
+
/*
* First perform device discovery for active
* fw ddb indexes and build
@@ -959,9 +1005,6 @@ static int qla4xxx_initialize_ddb_list(struct scsi_qla_host *ha)
if ((status = qla4xxx_build_ddb_list(ha)) == QLA_ERROR)
return status;
- /* Wait for an AEN */
- qla4xxx_devices_ready(ha);
-
/*
* Targets can come online after the inital discovery, so processing
* the aens here will catch them.
@@ -973,7 +1016,7 @@ static int qla4xxx_initialize_ddb_list(struct scsi_qla_host *ha)
}
/**
- * qla4xxx_update_ddb_list - update the driver ddb list
+ * qla4xxx_reinitialize_ddb_list - update the driver ddb list
* @ha: pointer to host adapter structure.
*
* This routine obtains device information from the F/W database after
@@ -993,6 +1036,7 @@ int qla4xxx_reinitialize_ddb_list(struct scsi_qla_host *ha)
DEBUG2(printk ("scsi%ld: %s: ddb index [%d] marked "
"ONLINE\n", ha->host_no, __func__,
ddb_entry->fw_ddb_index));
+ iscsi_unblock_session(ddb_entry->sess);
} else if (atomic_read(&ddb_entry->state) == DDB_STATE_ONLINE)
qla4xxx_mark_device_missing(ha, ddb_entry);
}
@@ -1016,7 +1060,7 @@ int qla4xxx_relogin_device(struct scsi_qla_host *ha,
(uint16_t)RELOGIN_TOV);
atomic_set(&ddb_entry->relogin_timer, relogin_timer);
- DEBUG2(printk("scsi%ld: Relogin index [%d]. TOV=%d\n", ha->host_no,
+ DEBUG2(printk("scsi%ld: Relogin ddb [%d]. TOV=%d\n", ha->host_no,
ddb_entry->fw_ddb_index, relogin_timer));
qla4xxx_set_ddb_entry(ha, ddb_entry->fw_ddb_index, 0);
@@ -1039,17 +1083,17 @@ static int qla4xxx_config_nvram(struct scsi_qla_host *ha)
}
/* Get EEPRom Parameters from NVRAM and validate */
- dev_info(&ha->pdev->dev, "Configuring NVRAM ...\n");
+ ql4_printk(KERN_INFO, ha, "Configuring NVRAM ...\n");
if (qla4xxx_is_nvram_configuration_valid(ha) == QLA_SUCCESS) {
spin_lock_irqsave(&ha->hardware_lock, flags);
extHwConfig.Asuint32_t =
rd_nvram_word(ha, eeprom_ext_hw_conf_offset(ha));
spin_unlock_irqrestore(&ha->hardware_lock, flags);
} else {
- dev_warn(&ha->pdev->dev,
- "scsi%ld: %s: EEProm checksum invalid. "
- "Please update your EEPROM\n", ha->host_no,
- __func__);
+ ql4_printk(KERN_WARNING, ha,
+ "scsi%ld: %s: EEProm checksum invalid. "
+ "Please update your EEPROM\n", ha->host_no,
+ __func__);
/* Attempt to set defaults */
if (is_qla4010(ha))
@@ -1073,12 +1117,21 @@ static int qla4xxx_config_nvram(struct scsi_qla_host *ha)
return QLA_SUCCESS;
}
-static void qla4x00_pci_config(struct scsi_qla_host *ha)
+/**
+ * qla4_8xxx_pci_config() - Setup ISP82xx PCI configuration registers.
+ * @ha: HA context
+ */
+void qla4_8xxx_pci_config(struct scsi_qla_host *ha)
+{
+ pci_set_master(ha->pdev);
+}
+
+void qla4xxx_pci_config(struct scsi_qla_host *ha)
{
uint16_t w;
int status;
- dev_info(&ha->pdev->dev, "Configuring PCI space...\n");
+ ql4_printk(KERN_INFO, ha, "Configuring PCI space...\n");
pci_set_master(ha->pdev);
status = pci_set_mwi(ha->pdev);
@@ -1100,7 +1153,7 @@ static int qla4xxx_start_firmware_from_flash(struct scsi_qla_host *ha)
unsigned long flags;
uint32_t mbox_status;
- dev_info(&ha->pdev->dev, "Starting firmware ...\n");
+ ql4_printk(KERN_INFO, ha, "Starting firmware ...\n");
/*
* Start firmware from flash ROM
@@ -1204,7 +1257,7 @@ int ql4xxx_lock_drvr_wait(struct scsi_qla_host *a)
* This routine performs the necessary steps to start the firmware for
* the QLA4010 adapter.
**/
-static int qla4xxx_start_firmware(struct scsi_qla_host *ha)
+int qla4xxx_start_firmware(struct scsi_qla_host *ha)
{
unsigned long flags = 0;
uint32_t mbox_status;
@@ -1283,7 +1336,8 @@ static int qla4xxx_start_firmware(struct scsi_qla_host *ha)
if (soft_reset) {
DEBUG(printk("scsi%ld: %s: Issue Soft Reset\n", ha->host_no,
__func__));
- status = qla4xxx_soft_reset(ha);
+ status = qla4xxx_soft_reset(ha); /* NOTE: acquires drvr
+ * lock again, but ok */
if (status == QLA_ERROR) {
DEBUG(printk("scsi%d: %s: Soft Reset failed!\n",
ha->host_no, __func__));
@@ -1304,7 +1358,6 @@ static int qla4xxx_start_firmware(struct scsi_qla_host *ha)
ql4xxx_unlock_drvr(ha);
if (status == QLA_SUCCESS) {
- qla4xxx_get_fw_version(ha);
if (test_and_clear_bit(AF_GET_CRASH_RECORD, &ha->flags))
qla4xxx_get_crash_record(ha);
} else {
@@ -1331,18 +1384,21 @@ int qla4xxx_initialize_adapter(struct scsi_qla_host *ha,
int status = QLA_ERROR;
int8_t ip_address[IP_ADDR_LEN] = {0} ;
- clear_bit(AF_ONLINE, &ha->flags);
ha->eeprom_cmd_data = 0;
- qla4x00_pci_config(ha);
+ ql4_printk(KERN_INFO, ha, "Configuring PCI space...\n");
+ ha->isp_ops->pci_config(ha);
- qla4xxx_disable_intrs(ha);
+ ha->isp_ops->disable_intrs(ha);
/* Initialize the Host adapter request/response queues and firmware */
- if (qla4xxx_start_firmware(ha) == QLA_ERROR)
+ if (ha->isp_ops->start_firmware(ha) == QLA_ERROR)
goto exit_init_hba;
- if (qla4xxx_validate_mac_address(ha) == QLA_ERROR)
+ if (qla4xxx_get_fw_version(ha) == QLA_ERROR)
+ goto exit_init_hba;
+
+ if (ha->isp_ops->get_sys_info(ha) == QLA_ERROR)
goto exit_init_hba;
if (qla4xxx_init_local_data(ha) == QLA_ERROR)
@@ -1395,6 +1451,8 @@ int qla4xxx_initialize_adapter(struct scsi_qla_host *ha,
exit_init_online:
set_bit(AF_ONLINE, &ha->flags);
exit_init_hba:
+ DEBUG2(printk("scsi%ld: initialize adapter: %s\n", ha->host_no,
+ status == QLA_ERROR ? "FAILED" : "SUCCEDED"));
return status;
}
@@ -1487,7 +1545,10 @@ int qla4xxx_process_ddb_changed(struct scsi_qla_host *ha, uint32_t fw_ddb_index,
ddb_entry->fw_ddb_device_state, state, fw_ddb_index));
if (old_fw_ddb_device_state == state &&
state == DDB_DS_SESSION_ACTIVE) {
- /* Do nothing, state not changed. */
+ if (atomic_read(&ddb_entry->state) != DDB_STATE_ONLINE) {
+ atomic_set(&ddb_entry->state, DDB_STATE_ONLINE);
+ iscsi_unblock_session(ddb_entry->sess);
+ }
return QLA_SUCCESS;
}
@@ -1511,7 +1572,7 @@ int qla4xxx_process_ddb_changed(struct scsi_qla_host *ha, uint32_t fw_ddb_index,
} else {
/* Device went away, mark device missing */
if (atomic_read(&ddb_entry->state) == DDB_STATE_ONLINE) {
- DEBUG2(dev_info(&ha->pdev->dev, "%s mark missing "
+ DEBUG2(ql4_printk(KERN_INFO, ha, "%s mark missing "
"ddb_entry 0x%p sess 0x%p conn 0x%p\n",
__func__, ddb_entry,
ddb_entry->sess, ddb_entry->conn));
@@ -1543,9 +1604,20 @@ int qla4xxx_process_ddb_changed(struct scsi_qla_host *ha, uint32_t fw_ddb_index,
atomic_set(&ddb_entry->relogin_timer, 0);
atomic_set(&ddb_entry->retry_relogin_timer,
ddb_entry->default_time2wait + 4);
+ DEBUG(printk("scsi%ld: %s: ddb[%d] "
+ "initiate relogin after %d seconds\n",
+ ha->host_no, __func__,
+ ddb_entry->fw_ddb_index,
+ ddb_entry->default_time2wait + 4));
+ } else {
+ DEBUG(printk("scsi%ld: %s: ddb[%d] "
+ "relogin not initiated, state = %d, "
+ "ddb_entry->flags = 0x%lx\n",
+ ha->host_no, __func__,
+ ddb_entry->fw_ddb_index,
+ ddb_entry->fw_ddb_device_state,
+ ddb_entry->flags));
}
}
-
return QLA_SUCCESS;
}
-
diff --git a/drivers/scsi/qla4xxx/ql4_inline.h b/drivers/scsi/qla4xxx/ql4_inline.h
index 6375eb017dd..9471ac75500 100644
--- a/drivers/scsi/qla4xxx/ql4_inline.h
+++ b/drivers/scsi/qla4xxx/ql4_inline.h
@@ -29,7 +29,7 @@ qla4xxx_lookup_ddb_by_fw_index(struct scsi_qla_host *ha, uint32_t fw_ddb_index)
ddb_entry = ha->fw_ddb_index_map[fw_ddb_index];
}
- DEBUG3(printk("scsi%d: %s: index [%d], ddb_entry = %p\n",
+ DEBUG3(printk("scsi%d: %s: ddb [%d], ddb_entry = %p\n",
ha->host_no, __func__, fw_ddb_index, ddb_entry));
return ddb_entry;
diff --git a/drivers/scsi/qla4xxx/ql4_iocb.c b/drivers/scsi/qla4xxx/ql4_iocb.c
index e66f3f263f4..f89973deac5 100644
--- a/drivers/scsi/qla4xxx/ql4_iocb.c
+++ b/drivers/scsi/qla4xxx/ql4_iocb.c
@@ -108,8 +108,7 @@ int qla4xxx_send_marker_iocb(struct scsi_qla_host *ha,
wmb();
/* Tell ISP it's got a new I/O request */
- writel(ha->request_in, &ha->reg->req_q_in);
- readl(&ha->reg->req_q_in);
+ ha->isp_ops->queue_iocb(ha);
exit_send_marker:
spin_unlock_irqrestore(&ha->hardware_lock, flags);
@@ -194,6 +193,72 @@ static void qla4xxx_build_scsi_iocbs(struct srb *srb,
}
/**
+ * qla4_8xxx_queue_iocb - Tell ISP it's got new request(s)
+ * @ha: pointer to host adapter structure.
+ *
+ * This routine notifies the ISP that one or more new request
+ * queue entries have been placed on the request queue.
+ **/
+void qla4_8xxx_queue_iocb(struct scsi_qla_host *ha)
+{
+ uint32_t dbval = 0;
+ unsigned long wtime;
+
+ dbval = 0x14 | (ha->func_num << 5);
+ dbval = dbval | (0 << 8) | (ha->request_in << 16);
+ writel(dbval, (unsigned long __iomem *)ha->nx_db_wr_ptr);
+ wmb();
+
+ wtime = jiffies + (2 * HZ);
+ while (readl((void __iomem *)ha->nx_db_rd_ptr) != dbval &&
+ !time_after_eq(jiffies, wtime)) {
+ writel(dbval, (unsigned long __iomem *)ha->nx_db_wr_ptr);
+ wmb();
+ }
+}
+
+/**
+ * qla4_8xxx_complete_iocb - Tell ISP we're done with response(s)
+ * @ha: pointer to host adapter structure.
+ *
+ * This routine notifies the ISP that one or more response/completion
+ * queue entries have been processed by the driver.
+ * This also clears the interrupt.
+ **/
+void qla4_8xxx_complete_iocb(struct scsi_qla_host *ha)
+{
+ writel(ha->response_out, &ha->qla4_8xxx_reg->rsp_q_out);
+ readl(&ha->qla4_8xxx_reg->rsp_q_out);
+}
+
+/**
+ * qla4xxx_queue_iocb - Tell ISP it's got new request(s)
+ * @ha: pointer to host adapter structure.
+ *
+ * This routine is notifies the ISP that one or more new request
+ * queue entries have been placed on the request queue.
+ **/
+void qla4xxx_queue_iocb(struct scsi_qla_host *ha)
+{
+ writel(ha->request_in, &ha->reg->req_q_in);
+ readl(&ha->reg->req_q_in);
+}
+
+/**
+ * qla4xxx_complete_iocb - Tell ISP we're done with response(s)
+ * @ha: pointer to host adapter structure.
+ *
+ * This routine is notifies the ISP that one or more response/completion
+ * queue entries have been processed by the driver.
+ * This also clears the interrupt.
+ **/
+void qla4xxx_complete_iocb(struct scsi_qla_host *ha)
+{
+ writel(ha->response_out, &ha->reg->rsp_q_out);
+ readl(&ha->reg->rsp_q_out);
+}
+
+/**
* qla4xxx_send_command_to_isp - issues command to HBA
* @ha: pointer to host adapter structure.
* @srb: pointer to SCSI Request Block to be sent to ISP
@@ -310,9 +375,7 @@ int qla4xxx_send_command_to_isp(struct scsi_qla_host *ha, struct srb * srb)
srb->iocb_cnt = req_cnt;
ha->req_q_count -= req_cnt;
- /* Debug print statements */
- writel(ha->request_in, &ha->reg->req_q_in);
- readl(&ha->reg->req_q_in);
+ ha->isp_ops->queue_iocb(ha);
spin_unlock_irqrestore(&ha->hardware_lock, flags);
return QLA_SUCCESS;
diff --git a/drivers/scsi/qla4xxx/ql4_isr.c b/drivers/scsi/qla4xxx/ql4_isr.c
index 596c3031483..aa65697a86b 100644
--- a/drivers/scsi/qla4xxx/ql4_isr.c
+++ b/drivers/scsi/qla4xxx/ql4_isr.c
@@ -118,13 +118,12 @@ static void qla4xxx_status_entry(struct scsi_qla_host *ha,
srb = qla4xxx_del_from_active_array(ha, le32_to_cpu(sts_entry->handle));
if (!srb) {
- /* FIXMEdg: Don't we need to reset ISP in this case??? */
DEBUG2(printk(KERN_WARNING "scsi%ld: %s: Status Entry invalid "
"handle 0x%x, sp=%p. This cmd may have already "
"been completed.\n", ha->host_no, __func__,
le32_to_cpu(sts_entry->handle), srb));
- dev_warn(&ha->pdev->dev, "%s invalid status entry:"
- " handle=0x%0x\n", __func__, sts_entry->handle);
+ ql4_printk(KERN_WARNING, ha, "%s invalid status entry:"
+ " handle=0x%0x\n", __func__, sts_entry->handle);
set_bit(DPC_RESET_HA, &ha->dpc_flags);
return;
}
@@ -135,8 +134,8 @@ static void qla4xxx_status_entry(struct scsi_qla_host *ha,
"OS pkt->handle=%d srb=%p srb->state:%d\n",
ha->host_no, __func__, sts_entry->handle,
srb, srb->state));
- dev_warn(&ha->pdev->dev, "Command is NULL:"
- " already returned to OS (srb=%p)\n", srb);
+ ql4_printk(KERN_WARNING, ha, "Command is NULL:"
+ " already returned to OS (srb=%p)\n", srb);
return;
}
@@ -293,6 +292,10 @@ static void qla4xxx_status_entry(struct scsi_qla_host *ha,
case SCS_DEVICE_LOGGED_OUT:
case SCS_DEVICE_UNAVAILABLE:
+ DEBUG2(printk(KERN_INFO "scsi%ld:%d:%d:%d: SCS_DEVICE "
+ "state: 0x%x\n", ha->host_no,
+ cmd->device->channel, cmd->device->id,
+ cmd->device->lun, sts_entry->completionStatus));
/*
* Mark device missing so that we won't continue to
* send I/O to this device. We should get a ddb
@@ -339,16 +342,14 @@ status_entry_exit:
* This routine process response queue completions in interrupt context.
* Hardware_lock locked upon entry
**/
-static void qla4xxx_process_response_queue(struct scsi_qla_host * ha)
+void qla4xxx_process_response_queue(struct scsi_qla_host *ha)
{
uint32_t count = 0;
struct srb *srb = NULL;
struct status_entry *sts_entry;
/* Process all responses from response queue */
- while ((ha->response_in =
- (uint16_t)le32_to_cpu(ha->shadow_regs->rsp_q_in)) !=
- ha->response_out) {
+ while ((ha->response_ptr->signature != RESPONSE_PROCESSED)) {
sts_entry = (struct status_entry *) ha->response_ptr;
count++;
@@ -413,14 +414,14 @@ static void qla4xxx_process_response_queue(struct scsi_qla_host * ha)
sts_entry->hdr.entryType));
goto exit_prq_error;
}
+ ((struct response *)sts_entry)->signature = RESPONSE_PROCESSED;
+ wmb();
}
/*
- * Done with responses, update the ISP For QLA4010, this also clears
- * the interrupt.
+ * Tell ISP we're done with response(s). This also clears the interrupt.
*/
- writel(ha->response_out, &ha->reg->rsp_q_out);
- readl(&ha->reg->rsp_q_out);
+ ha->isp_ops->complete_iocb(ha);
return;
@@ -430,9 +431,7 @@ exit_prq_invalid_handle:
sts_entry->completionStatus));
exit_prq_error:
- writel(ha->response_out, &ha->reg->rsp_q_out);
- readl(&ha->reg->rsp_q_out);
-
+ ha->isp_ops->complete_iocb(ha);
set_bit(DPC_RESET_HA, &ha->dpc_flags);
}
@@ -448,7 +447,7 @@ static void qla4xxx_isr_decode_mailbox(struct scsi_qla_host * ha,
uint32_t mbox_status)
{
int i;
- uint32_t mbox_stat2, mbox_stat3;
+ uint32_t mbox_sts[MBOX_AEN_REG_COUNT];
if ((mbox_status == MBOX_STS_BUSY) ||
(mbox_status == MBOX_STS_INTERMEDIATE_COMPLETION) ||
@@ -460,27 +459,37 @@ static void qla4xxx_isr_decode_mailbox(struct scsi_qla_host * ha,
* Copy all mailbox registers to a temporary
* location and set mailbox command done flag
*/
- for (i = 1; i < ha->mbox_status_count; i++)
- ha->mbox_status[i] =
- readl(&ha->reg->mailbox[i]);
+ for (i = 0; i < ha->mbox_status_count; i++)
+ ha->mbox_status[i] = is_qla8022(ha)
+ ? readl(&ha->qla4_8xxx_reg->mailbox_out[i])
+ : readl(&ha->reg->mailbox[i]);
set_bit(AF_MBOX_COMMAND_DONE, &ha->flags);
+
+ if (test_bit(AF_MBOX_COMMAND_NOPOLL, &ha->flags))
+ complete(&ha->mbx_intr_comp);
}
} else if (mbox_status >> 12 == MBOX_ASYNC_EVENT_STATUS) {
+ for (i = 0; i < MBOX_AEN_REG_COUNT; i++)
+ mbox_sts[i] = is_qla8022(ha)
+ ? readl(&ha->qla4_8xxx_reg->mailbox_out[i])
+ : readl(&ha->reg->mailbox[i]);
+
/* 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]);
+ mbox_sts[i];
ha->aen_log.count++;
}
switch (mbox_status) {
case MBOX_ASTS_SYSTEM_ERROR:
/* Log Mailbox registers */
+ ql4_printk(KERN_INFO, ha, "%s: System Err\n", __func__);
if (ql4xdontresethba) {
- DEBUG2(printk("%s:Dont Reset HBA\n",
- __func__));
+ DEBUG2(printk("scsi%ld: %s:Don't Reset HBA\n",
+ ha->host_no, __func__));
} else {
set_bit(AF_GET_CRASH_RECORD, &ha->flags);
set_bit(DPC_RESET_HA, &ha->dpc_flags);
@@ -502,18 +511,15 @@ static void qla4xxx_isr_decode_mailbox(struct scsi_qla_host * ha,
if (test_bit(AF_INIT_DONE, &ha->flags))
set_bit(DPC_LINK_CHANGED, &ha->dpc_flags);
- DEBUG2(printk(KERN_INFO "scsi%ld: AEN %04x Adapter"
- " LINK UP\n", ha->host_no,
- mbox_status));
+ ql4_printk(KERN_INFO, ha, "%s: LINK UP\n", __func__);
break;
case MBOX_ASTS_LINK_DOWN:
clear_bit(AF_LINK_UP, &ha->flags);
- set_bit(DPC_LINK_CHANGED, &ha->dpc_flags);
+ if (test_bit(AF_INIT_DONE, &ha->flags))
+ set_bit(DPC_LINK_CHANGED, &ha->dpc_flags);
- DEBUG2(printk(KERN_INFO "scsi%ld: AEN %04x Adapter"
- " LINK DOWN\n", ha->host_no,
- mbox_status));
+ ql4_printk(KERN_INFO, ha, "%s: LINK DOWN\n", __func__);
break;
case MBOX_ASTS_HEARTBEAT:
@@ -539,12 +545,17 @@ static void qla4xxx_isr_decode_mailbox(struct scsi_qla_host * ha,
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))
+ printk("scsi%ld: AEN %04x, mbox_sts[2]=%04x, "
+ "mbox_sts[3]=%04x\n", ha->host_no, mbox_sts[0],
+ mbox_sts[2], mbox_sts[3]);
+
+ /* mbox_sts[2] = Old ACB state
+ * mbox_sts[3] = new ACB state */
+ if ((mbox_sts[3] == ACB_STATE_VALID) &&
+ (mbox_sts[2] == ACB_STATE_TENTATIVE))
set_bit(DPC_GET_DHCP_IP_ADDR, &ha->dpc_flags);
- else if ((mbox_stat3 == 2) && (mbox_stat2 == 5))
+ else if ((mbox_sts[3] == ACB_STATE_ACQUIRING) &&
+ (mbox_sts[2] == ACB_STATE_VALID))
set_bit(DPC_RESET_HA, &ha->dpc_flags);
break;
@@ -553,9 +564,8 @@ static void qla4xxx_isr_decode_mailbox(struct scsi_qla_host * ha,
/* No action */
DEBUG2(printk(KERN_INFO "scsi%ld: AEN %04x, "
"mbox_sts[1]=%04x, mbox_sts[2]=%04x\n",
- ha->host_no, mbox_status,
- readl(&ha->reg->mailbox[1]),
- readl(&ha->reg->mailbox[2])));
+ ha->host_no, mbox_sts[0],
+ mbox_sts[1], mbox_sts[2]));
break;
case MBOX_ASTS_SELF_TEST_FAILED:
@@ -563,10 +573,8 @@ static void qla4xxx_isr_decode_mailbox(struct scsi_qla_host * ha,
/* No action */
DEBUG2(printk("scsi%ld: AEN %04x, mbox_sts[1]=%04x, "
"mbox_sts[2]=%04x, mbox_sts[3]=%04x\n",
- ha->host_no, mbox_status,
- readl(&ha->reg->mailbox[1]),
- readl(&ha->reg->mailbox[2]),
- readl(&ha->reg->mailbox[3])));
+ ha->host_no, mbox_sts[0], mbox_sts[1],
+ mbox_sts[2], mbox_sts[3]));
break;
case MBOX_ASTS_DATABASE_CHANGED:
@@ -577,21 +585,17 @@ static void qla4xxx_isr_decode_mailbox(struct scsi_qla_host * ha,
/* decrement available counter */
ha->aen_q_count--;
- for (i = 1; i < MBOX_AEN_REG_COUNT; i++)
+ for (i = 0; i < MBOX_AEN_REG_COUNT; i++)
ha->aen_q[ha->aen_in].mbox_sts[i] =
- readl(&ha->reg->mailbox[i]);
-
- ha->aen_q[ha->aen_in].mbox_sts[0] = mbox_status;
+ mbox_sts[i];
/* print debug message */
DEBUG2(printk("scsi%ld: AEN[%d] %04x queued"
- " mb1:0x%x mb2:0x%x mb3:0x%x mb4:0x%x\n",
- ha->host_no, ha->aen_in,
- mbox_status,
- ha->aen_q[ha->aen_in].mbox_sts[1],
- 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]));
+ " mb1:0x%x mb2:0x%x mb3:0x%x mb4:0x%x\n",
+ ha->host_no, ha->aen_in, mbox_sts[0],
+ mbox_sts[1], mbox_sts[2], mbox_sts[3],
+ mbox_sts[4]));
+
/* advance pointer */
ha->aen_in++;
if (ha->aen_in == MAX_AEN_ENTRIES)
@@ -603,18 +607,16 @@ static void qla4xxx_isr_decode_mailbox(struct scsi_qla_host * ha,
DEBUG2(printk("scsi%ld: %s: aen %04x, queue "
"overflowed! AEN LOST!!\n",
ha->host_no, __func__,
- mbox_status));
+ mbox_sts[0]));
DEBUG2(printk("scsi%ld: DUMP AEN QUEUE\n",
ha->host_no));
for (i = 0; i < MAX_AEN_ENTRIES; i++) {
DEBUG2(printk("AEN[%d] %04x %04x %04x "
- "%04x\n", i,
- ha->aen_q[i].mbox_sts[0],
- ha->aen_q[i].mbox_sts[1],
- ha->aen_q[i].mbox_sts[2],
- ha->aen_q[i].mbox_sts[3]));
+ "%04x\n", i, mbox_sts[0],
+ mbox_sts[1], mbox_sts[2],
+ mbox_sts[3]));
}
}
break;
@@ -622,7 +624,7 @@ static void qla4xxx_isr_decode_mailbox(struct scsi_qla_host * ha,
default:
DEBUG2(printk(KERN_WARNING
"scsi%ld: AEN %04x UNKNOWN\n",
- ha->host_no, mbox_status));
+ ha->host_no, mbox_sts[0]));
break;
}
} else {
@@ -634,6 +636,30 @@ static void qla4xxx_isr_decode_mailbox(struct scsi_qla_host * ha,
}
/**
+ * qla4_8xxx_interrupt_service_routine - isr
+ * @ha: pointer to host adapter structure.
+ *
+ * This is the main interrupt service routine.
+ * hardware_lock locked upon entry. runs in interrupt context.
+ **/
+void qla4_8xxx_interrupt_service_routine(struct scsi_qla_host *ha,
+ uint32_t intr_status)
+{
+ /* Process response queue interrupt. */
+ if (intr_status & HSRX_RISC_IOCB_INT)
+ qla4xxx_process_response_queue(ha);
+
+ /* Process mailbox/asynch event interrupt.*/
+ if (intr_status & HSRX_RISC_MB_INT)
+ qla4xxx_isr_decode_mailbox(ha,
+ readl(&ha->qla4_8xxx_reg->mailbox_out[0]));
+
+ /* clear the interrupt */
+ writel(0, &ha->qla4_8xxx_reg->host_int);
+ readl(&ha->qla4_8xxx_reg->host_int);
+}
+
+/**
* qla4xxx_interrupt_service_routine - isr
* @ha: pointer to host adapter structure.
*
@@ -660,6 +686,28 @@ void qla4xxx_interrupt_service_routine(struct scsi_qla_host * ha,
}
/**
+ * qla4_8xxx_spurious_interrupt - processes spurious interrupt
+ * @ha: pointer to host adapter structure.
+ * @reqs_count: .
+ *
+ **/
+static void qla4_8xxx_spurious_interrupt(struct scsi_qla_host *ha,
+ uint8_t reqs_count)
+{
+ if (reqs_count)
+ return;
+
+ DEBUG2(ql4_printk(KERN_INFO, ha, "Spurious Interrupt\n"));
+ if (is_qla8022(ha)) {
+ writel(0, &ha->qla4_8xxx_reg->host_int);
+ if (test_bit(AF_INTx_ENABLED, &ha->flags))
+ qla4_8xxx_wr_32(ha, ha->nx_legacy_intr.tgt_mask_reg,
+ 0xfbff);
+ }
+ ha->spurious_int_count++;
+}
+
+/**
* qla4xxx_intr_handler - hardware interrupt handler.
* @irq: Unused
* @dev_id: Pointer to host adapter structure
@@ -689,15 +737,14 @@ irqreturn_t qla4xxx_intr_handler(int irq, void *dev_id)
/*
* Read interrupt status
*/
- if (le32_to_cpu(ha->shadow_regs->rsp_q_in) !=
+ if (ha->isp_ops->rd_shdw_rsp_q_in(ha) !=
ha->response_out)
intr_status = CSR_SCSI_COMPLETION_INTR;
else
intr_status = readl(&ha->reg->ctrl_status);
if ((intr_status &
- (CSR_SCSI_RESET_INTR|CSR_FATAL_ERROR|INTR_PENDING)) ==
- 0) {
+ (CSR_SCSI_RESET_INTR|CSR_FATAL_ERROR|INTR_PENDING)) == 0) {
if (reqs_count == 0)
ha->spurious_int_count++;
break;
@@ -739,22 +786,159 @@ irqreturn_t qla4xxx_intr_handler(int irq, void *dev_id)
&ha->reg->ctrl_status);
readl(&ha->reg->ctrl_status);
- if (!ql4_mod_unload)
+ if (!test_bit(AF_HBA_GOING_AWAY, &ha->flags))
set_bit(DPC_RESET_HA_INTR, &ha->dpc_flags);
break;
} else if (intr_status & INTR_PENDING) {
- qla4xxx_interrupt_service_routine(ha, intr_status);
+ ha->isp_ops->interrupt_service_routine(ha, intr_status);
ha->total_io_count++;
if (++reqs_count == MAX_REQS_SERVICED_PER_INTR)
break;
+ }
+ }
+
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
+
+ return IRQ_HANDLED;
+}
+
+/**
+ * qla4_8xxx_intr_handler - hardware interrupt handler.
+ * @irq: Unused
+ * @dev_id: Pointer to host adapter structure
+ **/
+irqreturn_t qla4_8xxx_intr_handler(int irq, void *dev_id)
+{
+ struct scsi_qla_host *ha = dev_id;
+ uint32_t intr_status;
+ uint32_t status;
+ unsigned long flags = 0;
+ uint8_t reqs_count = 0;
+
+ ha->isr_count++;
+ status = qla4_8xxx_rd_32(ha, ISR_INT_VECTOR);
+ if (!(status & ha->nx_legacy_intr.int_vec_bit))
+ return IRQ_NONE;
+
+ status = qla4_8xxx_rd_32(ha, ISR_INT_STATE_REG);
+ if (!ISR_IS_LEGACY_INTR_TRIGGERED(status)) {
+ DEBUG2(ql4_printk(KERN_INFO, ha,
+ "%s legacy Int not triggered\n", __func__));
+ return IRQ_NONE;
+ }
+
+ /* clear the interrupt */
+ qla4_8xxx_wr_32(ha, ha->nx_legacy_intr.tgt_status_reg, 0xffffffff);
+
+ /* read twice to ensure write is flushed */
+ qla4_8xxx_rd_32(ha, ISR_INT_VECTOR);
+ qla4_8xxx_rd_32(ha, ISR_INT_VECTOR);
+
+ spin_lock_irqsave(&ha->hardware_lock, flags);
+ while (1) {
+ if (!(readl(&ha->qla4_8xxx_reg->host_int) &
+ ISRX_82XX_RISC_INT)) {
+ qla4_8xxx_spurious_interrupt(ha, reqs_count);
+ break;
+ }
+ intr_status = readl(&ha->qla4_8xxx_reg->host_status);
+ if ((intr_status &
+ (HSRX_RISC_MB_INT | HSRX_RISC_IOCB_INT)) == 0) {
+ qla4_8xxx_spurious_interrupt(ha, reqs_count);
+ break;
+ }
+
+ ha->isp_ops->interrupt_service_routine(ha, intr_status);
+
+ /* Enable Interrupt */
+ qla4_8xxx_wr_32(ha, ha->nx_legacy_intr.tgt_mask_reg, 0xfbff);
- intr_status = 0;
+ if (++reqs_count == MAX_REQS_SERVICED_PER_INTR)
+ break;
+ }
+
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
+ return IRQ_HANDLED;
+}
+
+irqreturn_t
+qla4_8xxx_msi_handler(int irq, void *dev_id)
+{
+ struct scsi_qla_host *ha;
+
+ ha = (struct scsi_qla_host *) dev_id;
+ if (!ha) {
+ DEBUG2(printk(KERN_INFO
+ "qla4xxx: MSIX: Interrupt with NULL host ptr\n"));
+ return IRQ_NONE;
+ }
+
+ ha->isr_count++;
+ /* clear the interrupt */
+ qla4_8xxx_wr_32(ha, ha->nx_legacy_intr.tgt_status_reg, 0xffffffff);
+
+ /* read twice to ensure write is flushed */
+ qla4_8xxx_rd_32(ha, ISR_INT_VECTOR);
+ qla4_8xxx_rd_32(ha, ISR_INT_VECTOR);
+
+ return qla4_8xxx_default_intr_handler(irq, dev_id);
+}
+
+/**
+ * qla4_8xxx_default_intr_handler - hardware interrupt handler.
+ * @irq: Unused
+ * @dev_id: Pointer to host adapter structure
+ *
+ * This interrupt handler is called directly for MSI-X, and
+ * called indirectly for MSI.
+ **/
+irqreturn_t
+qla4_8xxx_default_intr_handler(int irq, void *dev_id)
+{
+ struct scsi_qla_host *ha = dev_id;
+ unsigned long flags;
+ uint32_t intr_status;
+ uint8_t reqs_count = 0;
+
+ spin_lock_irqsave(&ha->hardware_lock, flags);
+ while (1) {
+ if (!(readl(&ha->qla4_8xxx_reg->host_int) &
+ ISRX_82XX_RISC_INT)) {
+ qla4_8xxx_spurious_interrupt(ha, reqs_count);
+ break;
+ }
+
+ intr_status = readl(&ha->qla4_8xxx_reg->host_status);
+ if ((intr_status &
+ (HSRX_RISC_MB_INT | HSRX_RISC_IOCB_INT)) == 0) {
+ qla4_8xxx_spurious_interrupt(ha, reqs_count);
+ break;
}
+
+ ha->isp_ops->interrupt_service_routine(ha, intr_status);
+
+ if (++reqs_count == MAX_REQS_SERVICED_PER_INTR)
+ break;
}
+ ha->isr_count++;
spin_unlock_irqrestore(&ha->hardware_lock, flags);
+ return IRQ_HANDLED;
+}
+irqreturn_t
+qla4_8xxx_msix_rsp_q(int irq, void *dev_id)
+{
+ struct scsi_qla_host *ha = dev_id;
+ unsigned long flags;
+
+ spin_lock_irqsave(&ha->hardware_lock, flags);
+ qla4xxx_process_response_queue(ha);
+ writel(0, &ha->qla4_8xxx_reg->host_int);
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
+
+ ha->isr_count++;
return IRQ_HANDLED;
}
@@ -825,7 +1009,7 @@ void qla4xxx_process_aen(struct scsi_qla_host * ha, uint8_t process_aen)
((ddb_entry->default_time2wait +
4) * HZ);
- DEBUG2(printk("scsi%ld: ddb index [%d] initate"
+ DEBUG2(printk("scsi%ld: ddb [%d] initate"
" RELOGIN after %d seconds\n",
ha->host_no,
ddb_entry->fw_ddb_index,
@@ -847,3 +1031,81 @@ void qla4xxx_process_aen(struct scsi_qla_host * ha, uint8_t process_aen)
spin_unlock_irqrestore(&ha->hardware_lock, flags);
}
+int qla4xxx_request_irqs(struct scsi_qla_host *ha)
+{
+ int ret;
+
+ if (!is_qla8022(ha))
+ goto try_intx;
+
+ if (ql4xenablemsix == 2)
+ goto try_msi;
+
+ if (ql4xenablemsix == 0 || ql4xenablemsix != 1)
+ goto try_intx;
+
+ /* Trying MSI-X */
+ ret = qla4_8xxx_enable_msix(ha);
+ if (!ret) {
+ DEBUG2(ql4_printk(KERN_INFO, ha,
+ "MSI-X: Enabled (0x%X).\n", ha->revision_id));
+ goto irq_attached;
+ }
+
+ ql4_printk(KERN_WARNING, ha,
+ "MSI-X: Falling back-to MSI mode -- %d.\n", ret);
+
+try_msi:
+ /* Trying MSI */
+ ret = pci_enable_msi(ha->pdev);
+ if (!ret) {
+ ret = request_irq(ha->pdev->irq, qla4_8xxx_msi_handler,
+ IRQF_DISABLED|IRQF_SHARED, DRIVER_NAME, ha);
+ if (!ret) {
+ DEBUG2(ql4_printk(KERN_INFO, ha, "MSI: Enabled.\n"));
+ set_bit(AF_MSI_ENABLED, &ha->flags);
+ goto irq_attached;
+ } else {
+ ql4_printk(KERN_WARNING, ha,
+ "MSI: Failed to reserve interrupt %d "
+ "already in use.\n", ha->pdev->irq);
+ pci_disable_msi(ha->pdev);
+ }
+ }
+ ql4_printk(KERN_WARNING, ha,
+ "MSI: Falling back-to INTx mode -- %d.\n", ret);
+
+try_intx:
+ /* Trying INTx */
+ ret = request_irq(ha->pdev->irq, ha->isp_ops->intr_handler,
+ IRQF_DISABLED|IRQF_SHARED, DRIVER_NAME, ha);
+ if (!ret) {
+ DEBUG2(ql4_printk(KERN_INFO, ha, "INTx: Enabled.\n"));
+ set_bit(AF_INTx_ENABLED, &ha->flags);
+ goto irq_attached;
+
+ } else {
+ ql4_printk(KERN_WARNING, ha,
+ "INTx: Failed to reserve interrupt %d already in"
+ " use.\n", ha->pdev->irq);
+ return ret;
+ }
+
+irq_attached:
+ set_bit(AF_IRQ_ATTACHED, &ha->flags);
+ ha->host->irq = ha->pdev->irq;
+ ql4_printk(KERN_INFO, ha, "%s: irq %d attached\n",
+ __func__, ha->pdev->irq);
+ return ret;
+}
+
+void qla4xxx_free_irqs(struct scsi_qla_host *ha)
+{
+ if (test_bit(AF_MSIX_ENABLED, &ha->flags))
+ qla4_8xxx_disable_msix(ha);
+ else if (test_and_clear_bit(AF_MSI_ENABLED, &ha->flags)) {
+ free_irq(ha->pdev->irq, ha);
+ pci_disable_msi(ha->pdev);
+ } else if (test_and_clear_bit(AF_INTx_ENABLED, &ha->flags))
+ free_irq(ha->pdev->irq, ha);
+}
diff --git a/drivers/scsi/qla4xxx/ql4_mbx.c b/drivers/scsi/qla4xxx/ql4_mbx.c
index 75496fb0ae7..940ee561ee0 100644
--- a/drivers/scsi/qla4xxx/ql4_mbx.c
+++ b/drivers/scsi/qla4xxx/ql4_mbx.c
@@ -19,13 +19,13 @@
* @mbx_cmd: data pointer for mailbox in registers.
* @mbx_sts: data pointer for mailbox out registers.
*
- * This routine sssue mailbox commands and waits for completion.
+ * This routine isssue mailbox commands and waits for completion.
* If outCount is 0, this routine completes successfully WITHOUT waiting
* for the mailbox command to complete.
**/
-static int qla4xxx_mailbox_command(struct scsi_qla_host *ha, uint8_t inCount,
- uint8_t outCount, uint32_t *mbx_cmd,
- uint32_t *mbx_sts)
+int qla4xxx_mailbox_command(struct scsi_qla_host *ha, uint8_t inCount,
+ uint8_t outCount, uint32_t *mbx_cmd,
+ uint32_t *mbx_sts)
{
int status = QLA_ERROR;
uint8_t i;
@@ -59,32 +59,66 @@ static int qla4xxx_mailbox_command(struct scsi_qla_host *ha, uint8_t inCount,
}
/* To prevent overwriting mailbox registers for a command that has
- * not yet been serviced, check to see if a previously issued
- * mailbox command is interrupting.
+ * not yet been serviced, check to see if an active command
+ * (AEN, IOCB, etc.) is interrupting, then service it.
* -----------------------------------------------------------------
*/
spin_lock_irqsave(&ha->hardware_lock, flags);
- intr_status = readl(&ha->reg->ctrl_status);
- if (intr_status & CSR_SCSI_PROCESSOR_INTR) {
- /* Service existing interrupt */
- qla4xxx_interrupt_service_routine(ha, intr_status);
- clear_bit(AF_MBOX_COMMAND_DONE, &ha->flags);
+
+ if (is_qla8022(ha)) {
+ intr_status = readl(&ha->qla4_8xxx_reg->host_int);
+ if (intr_status & ISRX_82XX_RISC_INT) {
+ /* Service existing interrupt */
+ DEBUG2(printk("scsi%ld: %s: "
+ "servicing existing interrupt\n",
+ ha->host_no, __func__));
+ intr_status = readl(&ha->qla4_8xxx_reg->host_status);
+ ha->isp_ops->interrupt_service_routine(ha, intr_status);
+ clear_bit(AF_MBOX_COMMAND_DONE, &ha->flags);
+ if (test_bit(AF_INTERRUPTS_ON, &ha->flags) &&
+ test_bit(AF_INTx_ENABLED, &ha->flags))
+ qla4_8xxx_wr_32(ha,
+ ha->nx_legacy_intr.tgt_mask_reg,
+ 0xfbff);
+ }
+ } else {
+ intr_status = readl(&ha->reg->ctrl_status);
+ if (intr_status & CSR_SCSI_PROCESSOR_INTR) {
+ /* Service existing interrupt */
+ ha->isp_ops->interrupt_service_routine(ha, intr_status);
+ clear_bit(AF_MBOX_COMMAND_DONE, &ha->flags);
+ }
}
- /* Send the mailbox command to the firmware */
ha->mbox_status_count = outCount;
for (i = 0; i < outCount; i++)
ha->mbox_status[i] = 0;
- /* Load all mailbox registers, except mailbox 0. */
- for (i = 1; i < inCount; i++)
- writel(mbx_cmd[i], &ha->reg->mailbox[i]);
+ if (is_qla8022(ha)) {
+ /* Load all mailbox registers, except mailbox 0. */
+ DEBUG5(
+ printk("scsi%ld: %s: Cmd ", ha->host_no, __func__);
+ for (i = 0; i < inCount; i++)
+ printk("mb%d=%04x ", i, mbx_cmd[i]);
+ printk("\n"));
+
+ for (i = 1; i < inCount; i++)
+ writel(mbx_cmd[i], &ha->qla4_8xxx_reg->mailbox_in[i]);
+ writel(mbx_cmd[0], &ha->qla4_8xxx_reg->mailbox_in[0]);
+ readl(&ha->qla4_8xxx_reg->mailbox_in[0]);
+ writel(HINT_MBX_INT_PENDING, &ha->qla4_8xxx_reg->hint);
+ } else {
+ /* Load all mailbox registers, except mailbox 0. */
+ for (i = 1; i < inCount; i++)
+ writel(mbx_cmd[i], &ha->reg->mailbox[i]);
+
+ /* Wakeup firmware */
+ writel(mbx_cmd[0], &ha->reg->mailbox[0]);
+ readl(&ha->reg->mailbox[0]);
+ writel(set_rmask(CSR_INTR_RISC), &ha->reg->ctrl_status);
+ readl(&ha->reg->ctrl_status);
+ }
- /* Wakeup firmware */
- writel(mbx_cmd[0], &ha->reg->mailbox[0]);
- readl(&ha->reg->mailbox[0]);
- writel(set_rmask(CSR_INTR_RISC), &ha->reg->ctrl_status);
- readl(&ha->reg->ctrl_status);
spin_unlock_irqrestore(&ha->hardware_lock, flags);
/* Wait for completion */
@@ -98,26 +132,66 @@ static int qla4xxx_mailbox_command(struct scsi_qla_host *ha, uint8_t inCount,
status = QLA_SUCCESS;
goto mbox_exit;
}
- /* Wait for command to complete */
- wait_count = jiffies + MBOX_TOV * HZ;
- while (test_bit(AF_MBOX_COMMAND_DONE, &ha->flags) == 0) {
- if (time_after_eq(jiffies, wait_count))
- break;
- spin_lock_irqsave(&ha->hardware_lock, flags);
- intr_status = readl(&ha->reg->ctrl_status);
- if (intr_status & INTR_PENDING) {
+ /*
+ * Wait for completion: Poll or completion queue
+ */
+ if (test_bit(AF_IRQ_ATTACHED, &ha->flags) &&
+ test_bit(AF_INTERRUPTS_ON, &ha->flags) &&
+ test_bit(AF_ONLINE, &ha->flags) &&
+ !test_bit(AF_HBA_GOING_AWAY, &ha->flags)) {
+ /* Do not poll for completion. Use completion queue */
+ set_bit(AF_MBOX_COMMAND_NOPOLL, &ha->flags);
+ wait_for_completion_timeout(&ha->mbx_intr_comp, MBOX_TOV * HZ);
+ clear_bit(AF_MBOX_COMMAND_NOPOLL, &ha->flags);
+ } else {
+ /* Poll for command to complete */
+ wait_count = jiffies + MBOX_TOV * HZ;
+ while (test_bit(AF_MBOX_COMMAND_DONE, &ha->flags) == 0) {
+ if (time_after_eq(jiffies, wait_count))
+ break;
/*
* Service the interrupt.
* The ISR will save the mailbox status registers
* to a temporary storage location in the adapter
* structure.
*/
- ha->mbox_status_count = outCount;
- qla4xxx_interrupt_service_routine(ha, intr_status);
+
+ spin_lock_irqsave(&ha->hardware_lock, flags);
+ if (is_qla8022(ha)) {
+ intr_status =
+ readl(&ha->qla4_8xxx_reg->host_int);
+ if (intr_status & ISRX_82XX_RISC_INT) {
+ ha->mbox_status_count = outCount;
+ intr_status =
+ readl(&ha->qla4_8xxx_reg->host_status);
+ ha->isp_ops->interrupt_service_routine(
+ ha, intr_status);
+ if (test_bit(AF_INTERRUPTS_ON,
+ &ha->flags) &&
+ test_bit(AF_INTx_ENABLED,
+ &ha->flags))
+ qla4_8xxx_wr_32(ha,
+ ha->nx_legacy_intr.tgt_mask_reg,
+ 0xfbff);
+ }
+ } else {
+ intr_status = readl(&ha->reg->ctrl_status);
+ if (intr_status & INTR_PENDING) {
+ /*
+ * Service the interrupt.
+ * The ISR will save the mailbox status
+ * registers to a temporary storage
+ * location in the adapter structure.
+ */
+ ha->mbox_status_count = outCount;
+ ha->isp_ops->interrupt_service_routine(
+ ha, intr_status);
+ }
+ }
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
+ msleep(10);
}
- spin_unlock_irqrestore(&ha->hardware_lock, flags);
- msleep(10);
}
/* Check for mailbox timeout. */
@@ -172,7 +246,7 @@ mbox_exit:
return status;
}
-uint8_t
+static uint8_t
qla4xxx_set_ifcb(struct scsi_qla_host *ha, uint32_t *mbox_cmd,
uint32_t *mbox_sts, dma_addr_t init_fw_cb_dma)
{
@@ -196,7 +270,7 @@ qla4xxx_set_ifcb(struct scsi_qla_host *ha, uint32_t *mbox_cmd,
return QLA_SUCCESS;
}
-uint8_t
+static uint8_t
qla4xxx_get_ifcb(struct scsi_qla_host *ha, uint32_t *mbox_cmd,
uint32_t *mbox_sts, dma_addr_t init_fw_cb_dma)
{
@@ -218,7 +292,7 @@ qla4xxx_get_ifcb(struct scsi_qla_host *ha, uint32_t *mbox_cmd,
return QLA_SUCCESS;
}
-void
+static void
qla4xxx_update_local_ip(struct scsi_qla_host *ha,
struct addr_ctrl_blk *init_fw_cb)
{
@@ -256,7 +330,7 @@ qla4xxx_update_local_ip(struct scsi_qla_host *ha,
}
}
-uint8_t
+static uint8_t
qla4xxx_update_local_ifcb(struct scsi_qla_host *ha,
uint32_t *mbox_cmd,
uint32_t *mbox_sts,
@@ -317,7 +391,7 @@ int qla4xxx_initialize_fw_cb(struct scsi_qla_host * ha)
if (init_fw_cb == NULL) {
DEBUG2(printk("scsi%ld: %s: Unable to alloc init_cb\n",
ha->host_no, __func__));
- return 10;
+ goto exit_init_fw_cb_no_free;
}
memset(init_fw_cb, 0, sizeof(struct addr_ctrl_blk));
@@ -373,7 +447,7 @@ int qla4xxx_initialize_fw_cb(struct scsi_qla_host * ha)
exit_init_fw_cb:
dma_free_coherent(&ha->pdev->dev, sizeof(struct addr_ctrl_blk),
init_fw_cb, init_fw_cb_dma);
-
+exit_init_fw_cb_no_free:
return status;
}
@@ -394,7 +468,7 @@ int qla4xxx_get_dhcp_ip_address(struct scsi_qla_host * ha)
if (init_fw_cb == NULL) {
printk("scsi%ld: %s: Unable to alloc init_cb\n", ha->host_no,
__func__);
- return 10;
+ return QLA_ERROR;
}
/* Get Initialize Firmware Control Block. */
@@ -445,7 +519,7 @@ int qla4xxx_get_firmware_state(struct scsi_qla_host * ha)
DEBUG2(printk("scsi%ld: %s firmware_state=0x%x\n",
ha->host_no, __func__, ha->firmware_state);)
- return QLA_SUCCESS;
+ return QLA_SUCCESS;
}
/**
@@ -470,6 +544,10 @@ int qla4xxx_get_firmware_status(struct scsi_qla_host * ha)
mbox_sts[0]));
return QLA_ERROR;
}
+
+ ql4_printk(KERN_INFO, ha, "%ld firmare IOCBs available (%d).\n",
+ ha->host_no, mbox_cmd[2]);
+
return QLA_SUCCESS;
}
@@ -500,7 +578,7 @@ int qla4xxx_get_fwddb_entry(struct scsi_qla_host *ha,
/* Make sure the device index is valid */
if (fw_ddb_index >= MAX_DDB_ENTRIES) {
- DEBUG2(printk("scsi%ld: %s: index [%d] out of range.\n",
+ DEBUG2(printk("scsi%ld: %s: ddb [%d] out of range.\n",
ha->host_no, __func__, fw_ddb_index));
goto exit_get_fwddb;
}
@@ -521,7 +599,7 @@ int qla4xxx_get_fwddb_entry(struct scsi_qla_host *ha,
goto exit_get_fwddb;
}
if (fw_ddb_index != mbox_sts[1]) {
- DEBUG2(printk("scsi%ld: %s: index mismatch [%d] != [%d].\n",
+ DEBUG2(printk("scsi%ld: %s: ddb mismatch [%d] != [%d].\n",
ha->host_no, __func__, fw_ddb_index,
mbox_sts[1]));
goto exit_get_fwddb;
@@ -529,7 +607,7 @@ int qla4xxx_get_fwddb_entry(struct scsi_qla_host *ha,
if (fw_ddb_entry) {
options = le16_to_cpu(fw_ddb_entry->options);
if (options & DDB_OPT_IPV6_DEVICE) {
- dev_info(&ha->pdev->dev, "%s: DDB[%d] MB0 %04x Tot %d "
+ ql4_printk(KERN_INFO, ha, "%s: DDB[%d] MB0 %04x Tot %d "
"Next %d State %04x ConnErr %08x %pI6 "
":%04d \"%s\"\n", __func__, fw_ddb_index,
mbox_sts[0], mbox_sts[2], mbox_sts[3],
@@ -538,7 +616,7 @@ int qla4xxx_get_fwddb_entry(struct scsi_qla_host *ha,
le16_to_cpu(fw_ddb_entry->port),
fw_ddb_entry->iscsi_name);
} else {
- dev_info(&ha->pdev->dev, "%s: DDB[%d] MB0 %04x Tot %d "
+ ql4_printk(KERN_INFO, ha, "%s: DDB[%d] MB0 %04x Tot %d "
"Next %d State %04x ConnErr %08x %pI4 "
":%04d \"%s\"\n", __func__, fw_ddb_index,
mbox_sts[0], mbox_sts[2], mbox_sts[3],
@@ -590,6 +668,7 @@ int qla4xxx_set_ddb_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];
+ int status;
/* Do not wait for completion. The firmware will send us an
* ASTS_DATABASE_CHANGED (0x8014) to notify us of the login status.
@@ -603,7 +682,12 @@ int qla4xxx_set_ddb_entry(struct scsi_qla_host * ha, uint16_t fw_ddb_index,
mbox_cmd[3] = MSDW(fw_ddb_entry_dma);
mbox_cmd[4] = sizeof(struct dev_db_entry);
- return qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 1, &mbox_cmd[0], &mbox_sts[0]);
+ status = qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 5, &mbox_cmd[0],
+ &mbox_sts[0]);
+ DEBUG2(printk("scsi%ld: %s: status=%d mbx0=0x%x mbx4=0x%x\n",
+ ha->host_no, __func__, status, mbox_sts[0], mbox_sts[4]);)
+
+ return status;
}
/**
@@ -817,8 +901,8 @@ int qla4xxx_abort_task(struct scsi_qla_host *ha, struct srb *srb)
/**
* qla4xxx_reset_lun - issues LUN Reset
* @ha: Pointer to host adapter structure.
- * @db_entry: Pointer to device database entry
- * @un_entry: Pointer to lun entry structure
+ * @ddb_entry: Pointer to device database entry
+ * @lun: lun number
*
* This routine performs a LUN RESET on the specified target/lun.
* The caller must ensure that the ddb_entry and lun_entry pointers
@@ -832,7 +916,7 @@ int qla4xxx_reset_lun(struct scsi_qla_host * ha, struct ddb_entry * ddb_entry,
int status = QLA_SUCCESS;
DEBUG2(printk("scsi%ld:%d:%d: lun reset issued\n", ha->host_no,
- ddb_entry->os_target_id, lun));
+ ddb_entry->fw_ddb_index, lun));
/*
* Send lun reset command to ISP, so that the ISP will return all
@@ -872,7 +956,7 @@ int qla4xxx_reset_target(struct scsi_qla_host *ha,
int status = QLA_SUCCESS;
DEBUG2(printk("scsi%ld:%d: target reset issued\n", ha->host_no,
- ddb_entry->os_target_id));
+ ddb_entry->fw_ddb_index));
/*
* Send target reset command to ISP, so that the ISP will return all
@@ -1019,16 +1103,16 @@ int qla4xxx_send_tgts(struct scsi_qla_host *ha, char *ip, uint16_t port)
DEBUG2(printk("scsi%ld: %s: Unable to allocate dma buffer.\n",
ha->host_no, __func__));
ret_val = QLA_ERROR;
- goto qla4xxx_send_tgts_exit;
+ goto exit_send_tgts_no_free;
}
ret_val = qla4xxx_get_default_ddb(ha, fw_ddb_entry_dma);
if (ret_val != QLA_SUCCESS)
- goto qla4xxx_send_tgts_exit;
+ goto exit_send_tgts;
ret_val = qla4xxx_req_ddb_entry(ha, &ddb_index);
if (ret_val != QLA_SUCCESS)
- goto qla4xxx_send_tgts_exit;
+ goto exit_send_tgts;
memset(fw_ddb_entry->iscsi_alias, 0,
sizeof(fw_ddb_entry->iscsi_alias));
@@ -1050,9 +1134,10 @@ int qla4xxx_send_tgts(struct scsi_qla_host *ha, char *ip, uint16_t port)
ret_val = qla4xxx_set_ddb_entry(ha, ddb_index, fw_ddb_entry_dma);
-qla4xxx_send_tgts_exit:
+exit_send_tgts:
dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry),
fw_ddb_entry, fw_ddb_entry_dma);
+exit_send_tgts_no_free:
return ret_val;
}
diff --git a/drivers/scsi/qla4xxx/ql4_nvram.c b/drivers/scsi/qla4xxx/ql4_nvram.c
index 7fe0482ecf0..f0d0fbf88aa 100644
--- a/drivers/scsi/qla4xxx/ql4_nvram.c
+++ b/drivers/scsi/qla4xxx/ql4_nvram.c
@@ -149,7 +149,7 @@ static int eeprom_readword(int eepromAddr, u16 * value,
/* Hardware_lock must be set before calling */
u16 rd_nvram_word(struct scsi_qla_host * ha, int offset)
{
- u16 val;
+ u16 val = 0;
/* NOTE: NVRAM uses half-word addresses */
eeprom_readword(offset, &val, ha);
diff --git a/drivers/scsi/qla4xxx/ql4_nvram.h b/drivers/scsi/qla4xxx/ql4_nvram.h
index b47b4fc59d8..7a8fc66a760 100644
--- a/drivers/scsi/qla4xxx/ql4_nvram.h
+++ b/drivers/scsi/qla4xxx/ql4_nvram.h
@@ -8,9 +8,9 @@
#ifndef _QL4XNVRM_H_
#define _QL4XNVRM_H_
-/*
+/**
* AM29LV Flash definitions
- */
+ **/
#define FM93C56A_SIZE_8 0x100
#define FM93C56A_SIZE_16 0x80
#define FM93C66A_SIZE_8 0x200
@@ -19,7 +19,7 @@
#define FM93C56A_START 0x1
-// Commands
+/* Commands */
#define FM93C56A_READ 0x2
#define FM93C56A_WEN 0x0
#define FM93C56A_WRITE 0x1
@@ -62,9 +62,9 @@
#define AUBURN_EEPROM_CLK_RISE 0x1
#define AUBURN_EEPROM_CLK_FALL 0x0
-/* */
+/**/
/* EEPROM format */
-/* */
+/**/
struct bios_params {
uint16_t SpinUpDelay:1;
uint16_t BIOSDisable:1;
diff --git a/drivers/scsi/qla4xxx/ql4_nx.c b/drivers/scsi/qla4xxx/ql4_nx.c
new file mode 100644
index 00000000000..3e119ae7839
--- /dev/null
+++ b/drivers/scsi/qla4xxx/ql4_nx.c
@@ -0,0 +1,2321 @@
+/*
+ * QLogic iSCSI HBA Driver
+ * Copyright (c) 2003-2009 QLogic Corporation
+ *
+ * See LICENSE.qla4xxx for copyright and licensing details.
+ */
+#include <linux/delay.h>
+#include <linux/pci.h>
+#include "ql4_def.h"
+#include "ql4_glbl.h"
+
+#define MASK(n) DMA_BIT_MASK(n)
+#define MN_WIN(addr) (((addr & 0x1fc0000) >> 1) | ((addr >> 25) & 0x3ff))
+#define OCM_WIN(addr) (((addr & 0x1ff0000) >> 1) | ((addr >> 25) & 0x3ff))
+#define MS_WIN(addr) (addr & 0x0ffc0000)
+#define QLA82XX_PCI_MN_2M (0)
+#define QLA82XX_PCI_MS_2M (0x80000)
+#define QLA82XX_PCI_OCM0_2M (0xc0000)
+#define VALID_OCM_ADDR(addr) (((addr) & 0x3f800) != 0x3f800)
+#define GET_MEM_OFFS_2M(addr) (addr & MASK(18))
+
+/* CRB window related */
+#define CRB_BLK(off) ((off >> 20) & 0x3f)
+#define CRB_SUBBLK(off) ((off >> 16) & 0xf)
+#define CRB_WINDOW_2M (0x130060)
+#define CRB_HI(off) ((qla4_8xxx_crb_hub_agt[CRB_BLK(off)] << 20) | \
+ ((off) & 0xf0000))
+#define QLA82XX_PCI_CAMQM_2M_END (0x04800800UL)
+#define QLA82XX_PCI_CAMQM_2M_BASE (0x000ff800UL)
+#define CRB_INDIRECT_2M (0x1e0000UL)
+
+static inline void __iomem *
+qla4_8xxx_pci_base_offsetfset(struct scsi_qla_host *ha, unsigned long off)
+{
+ if ((off < ha->first_page_group_end) &&
+ (off >= ha->first_page_group_start))
+ return (void __iomem *)(ha->nx_pcibase + off);
+
+ return NULL;
+}
+
+#define MAX_CRB_XFORM 60
+static unsigned long crb_addr_xform[MAX_CRB_XFORM];
+static int qla4_8xxx_crb_table_initialized;
+
+#define qla4_8xxx_crb_addr_transform(name) \
+ (crb_addr_xform[QLA82XX_HW_PX_MAP_CRB_##name] = \
+ QLA82XX_HW_CRB_HUB_AGT_ADR_##name << 20)
+static void
+qla4_8xxx_crb_addr_transform_setup(void)
+{
+ qla4_8xxx_crb_addr_transform(XDMA);
+ qla4_8xxx_crb_addr_transform(TIMR);
+ qla4_8xxx_crb_addr_transform(SRE);
+ qla4_8xxx_crb_addr_transform(SQN3);
+ qla4_8xxx_crb_addr_transform(SQN2);
+ qla4_8xxx_crb_addr_transform(SQN1);
+ qla4_8xxx_crb_addr_transform(SQN0);
+ qla4_8xxx_crb_addr_transform(SQS3);
+ qla4_8xxx_crb_addr_transform(SQS2);
+ qla4_8xxx_crb_addr_transform(SQS1);
+ qla4_8xxx_crb_addr_transform(SQS0);
+ qla4_8xxx_crb_addr_transform(RPMX7);
+ qla4_8xxx_crb_addr_transform(RPMX6);
+ qla4_8xxx_crb_addr_transform(RPMX5);
+ qla4_8xxx_crb_addr_transform(RPMX4);
+ qla4_8xxx_crb_addr_transform(RPMX3);
+ qla4_8xxx_crb_addr_transform(RPMX2);
+ qla4_8xxx_crb_addr_transform(RPMX1);
+ qla4_8xxx_crb_addr_transform(RPMX0);
+ qla4_8xxx_crb_addr_transform(ROMUSB);
+ qla4_8xxx_crb_addr_transform(SN);
+ qla4_8xxx_crb_addr_transform(QMN);
+ qla4_8xxx_crb_addr_transform(QMS);
+ qla4_8xxx_crb_addr_transform(PGNI);
+ qla4_8xxx_crb_addr_transform(PGND);
+ qla4_8xxx_crb_addr_transform(PGN3);
+ qla4_8xxx_crb_addr_transform(PGN2);
+ qla4_8xxx_crb_addr_transform(PGN1);
+ qla4_8xxx_crb_addr_transform(PGN0);
+ qla4_8xxx_crb_addr_transform(PGSI);
+ qla4_8xxx_crb_addr_transform(PGSD);
+ qla4_8xxx_crb_addr_transform(PGS3);
+ qla4_8xxx_crb_addr_transform(PGS2);
+ qla4_8xxx_crb_addr_transform(PGS1);
+ qla4_8xxx_crb_addr_transform(PGS0);
+ qla4_8xxx_crb_addr_transform(PS);
+ qla4_8xxx_crb_addr_transform(PH);
+ qla4_8xxx_crb_addr_transform(NIU);
+ qla4_8xxx_crb_addr_transform(I2Q);
+ qla4_8xxx_crb_addr_transform(EG);
+ qla4_8xxx_crb_addr_transform(MN);
+ qla4_8xxx_crb_addr_transform(MS);
+ qla4_8xxx_crb_addr_transform(CAS2);
+ qla4_8xxx_crb_addr_transform(CAS1);
+ qla4_8xxx_crb_addr_transform(CAS0);
+ qla4_8xxx_crb_addr_transform(CAM);
+ qla4_8xxx_crb_addr_transform(C2C1);
+ qla4_8xxx_crb_addr_transform(C2C0);
+ qla4_8xxx_crb_addr_transform(SMB);
+ qla4_8xxx_crb_addr_transform(OCM0);
+ qla4_8xxx_crb_addr_transform(I2C0);
+
+ qla4_8xxx_crb_table_initialized = 1;
+}
+
+static struct crb_128M_2M_block_map crb_128M_2M_map[64] = {
+ {{{0, 0, 0, 0} } }, /* 0: PCI */
+ {{{1, 0x0100000, 0x0102000, 0x120000}, /* 1: PCIE */
+ {1, 0x0110000, 0x0120000, 0x130000},
+ {1, 0x0120000, 0x0122000, 0x124000},
+ {1, 0x0130000, 0x0132000, 0x126000},
+ {1, 0x0140000, 0x0142000, 0x128000},
+ {1, 0x0150000, 0x0152000, 0x12a000},
+ {1, 0x0160000, 0x0170000, 0x110000},
+ {1, 0x0170000, 0x0172000, 0x12e000},
+ {0, 0x0000000, 0x0000000, 0x000000},
+ {0, 0x0000000, 0x0000000, 0x000000},
+ {0, 0x0000000, 0x0000000, 0x000000},
+ {0, 0x0000000, 0x0000000, 0x000000},
+ {0, 0x0000000, 0x0000000, 0x000000},
+ {0, 0x0000000, 0x0000000, 0x000000},
+ {1, 0x01e0000, 0x01e0800, 0x122000},
+ {0, 0x0000000, 0x0000000, 0x000000} } },
+ {{{1, 0x0200000, 0x0210000, 0x180000} } },/* 2: MN */
+ {{{0, 0, 0, 0} } }, /* 3: */
+ {{{1, 0x0400000, 0x0401000, 0x169000} } },/* 4: P2NR1 */
+ {{{1, 0x0500000, 0x0510000, 0x140000} } },/* 5: SRE */
+ {{{1, 0x0600000, 0x0610000, 0x1c0000} } },/* 6: NIU */
+ {{{1, 0x0700000, 0x0704000, 0x1b8000} } },/* 7: QM */
+ {{{1, 0x0800000, 0x0802000, 0x170000}, /* 8: SQM0 */
+ {0, 0x0000000, 0x0000000, 0x000000},
+ {0, 0x0000000, 0x0000000, 0x000000},
+ {0, 0x0000000, 0x0000000, 0x000000},
+ {0, 0x0000000, 0x0000000, 0x000000},
+ {0, 0x0000000, 0x0000000, 0x000000},
+ {0, 0x0000000, 0x0000000, 0x000000},
+ {0, 0x0000000, 0x0000000, 0x000000},
+ {0, 0x0000000, 0x0000000, 0x000000},
+ {0, 0x0000000, 0x0000000, 0x000000},
+ {0, 0x0000000, 0x0000000, 0x000000},
+ {0, 0x0000000, 0x0000000, 0x000000},
+ {0, 0x0000000, 0x0000000, 0x000000},
+ {0, 0x0000000, 0x0000000, 0x000000},
+ {0, 0x0000000, 0x0000000, 0x000000},
+ {1, 0x08f0000, 0x08f2000, 0x172000} } },
+ {{{1, 0x0900000, 0x0902000, 0x174000}, /* 9: SQM1*/
+ {0, 0x0000000, 0x0000000, 0x000000},
+ {0, 0x0000000, 0x0000000, 0x000000},
+ {0, 0x0000000, 0x0000000, 0x000000},
+ {0, 0x0000000, 0x0000000, 0x000000},
+ {0, 0x0000000, 0x0000000, 0x000000},
+ {0, 0x0000000, 0x0000000, 0x000000},
+ {0, 0x0000000, 0x0000000, 0x000000},
+ {0, 0x0000000, 0x0000000, 0x000000},
+ {0, 0x0000000, 0x0000000, 0x000000},
+ {0, 0x0000000, 0x0000000, 0x000000},
+ {0, 0x0000000, 0x0000000, 0x000000},
+ {0, 0x0000000, 0x0000000, 0x000000},
+ {0, 0x0000000, 0x0000000, 0x000000},
+ {0, 0x0000000, 0x0000000, 0x000000},
+ {1, 0x09f0000, 0x09f2000, 0x176000} } },
+ {{{0, 0x0a00000, 0x0a02000, 0x178000}, /* 10: SQM2*/
+ {0, 0x0000000, 0x0000000, 0x000000},
+ {0, 0x0000000, 0x0000000, 0x000000},
+ {0, 0x0000000, 0x0000000, 0x000000},
+ {0, 0x0000000, 0x0000000, 0x000000},
+ {0, 0x0000000, 0x0000000, 0x000000},
+ {0, 0x0000000, 0x0000000, 0x000000},
+ {0, 0x0000000, 0x0000000, 0x000000},
+ {0, 0x0000000, 0x0000000, 0x000000},
+ {0, 0x0000000, 0x0000000, 0x000000},
+ {0, 0x0000000, 0x0000000, 0x000000},
+ {0, 0x0000000, 0x0000000, 0x000000},
+ {0, 0x0000000, 0x0000000, 0x000000},
+ {0, 0x0000000, 0x0000000, 0x000000},
+ {0, 0x0000000, 0x0000000, 0x000000},
+ {1, 0x0af0000, 0x0af2000, 0x17a000} } },
+ {{{0, 0x0b00000, 0x0b02000, 0x17c000}, /* 11: SQM3*/
+ {0, 0x0000000, 0x0000000, 0x000000},
+ {0, 0x0000000, 0x0000000, 0x000000},
+ {0, 0x0000000, 0x0000000, 0x000000},
+ {0, 0x0000000, 0x0000000, 0x000000},
+ {0, 0x0000000, 0x0000000, 0x000000},
+ {0, 0x0000000, 0x0000000, 0x000000},
+ {0, 0x0000000, 0x0000000, 0x000000},
+ {0, 0x0000000, 0x0000000, 0x000000},
+ {0, 0x0000000, 0x0000000, 0x000000},
+ {0, 0x0000000, 0x0000000, 0x000000},
+ {0, 0x0000000, 0x0000000, 0x000000},
+ {0, 0x0000000, 0x0000000, 0x000000},
+ {0, 0x0000000, 0x0000000, 0x000000},
+ {0, 0x0000000, 0x0000000, 0x000000},
+ {1, 0x0bf0000, 0x0bf2000, 0x17e000} } },
+ {{{1, 0x0c00000, 0x0c04000, 0x1d4000} } },/* 12: I2Q */
+ {{{1, 0x0d00000, 0x0d04000, 0x1a4000} } },/* 13: TMR */
+ {{{1, 0x0e00000, 0x0e04000, 0x1a0000} } },/* 14: ROMUSB */
+ {{{1, 0x0f00000, 0x0f01000, 0x164000} } },/* 15: PEG4 */
+ {{{0, 0x1000000, 0x1004000, 0x1a8000} } },/* 16: XDMA */
+ {{{1, 0x1100000, 0x1101000, 0x160000} } },/* 17: PEG0 */
+ {{{1, 0x1200000, 0x1201000, 0x161000} } },/* 18: PEG1 */
+ {{{1, 0x1300000, 0x1301000, 0x162000} } },/* 19: PEG2 */
+ {{{1, 0x1400000, 0x1401000, 0x163000} } },/* 20: PEG3 */
+ {{{1, 0x1500000, 0x1501000, 0x165000} } },/* 21: P2ND */
+ {{{1, 0x1600000, 0x1601000, 0x166000} } },/* 22: P2NI */
+ {{{0, 0, 0, 0} } }, /* 23: */
+ {{{0, 0, 0, 0} } }, /* 24: */
+ {{{0, 0, 0, 0} } }, /* 25: */
+ {{{0, 0, 0, 0} } }, /* 26: */
+ {{{0, 0, 0, 0} } }, /* 27: */
+ {{{0, 0, 0, 0} } }, /* 28: */
+ {{{1, 0x1d00000, 0x1d10000, 0x190000} } },/* 29: MS */
+ {{{1, 0x1e00000, 0x1e01000, 0x16a000} } },/* 30: P2NR2 */
+ {{{1, 0x1f00000, 0x1f10000, 0x150000} } },/* 31: EPG */
+ {{{0} } }, /* 32: PCI */
+ {{{1, 0x2100000, 0x2102000, 0x120000}, /* 33: PCIE */
+ {1, 0x2110000, 0x2120000, 0x130000},
+ {1, 0x2120000, 0x2122000, 0x124000},
+ {1, 0x2130000, 0x2132000, 0x126000},
+ {1, 0x2140000, 0x2142000, 0x128000},
+ {1, 0x2150000, 0x2152000, 0x12a000},
+ {1, 0x2160000, 0x2170000, 0x110000},
+ {1, 0x2170000, 0x2172000, 0x12e000},
+ {0, 0x0000000, 0x0000000, 0x000000},
+ {0, 0x0000000, 0x0000000, 0x000000},
+ {0, 0x0000000, 0x0000000, 0x000000},
+ {0, 0x0000000, 0x0000000, 0x000000},
+ {0, 0x0000000, 0x0000000, 0x000000},
+ {0, 0x0000000, 0x0000000, 0x000000},
+ {0, 0x0000000, 0x0000000, 0x000000},
+ {0, 0x0000000, 0x0000000, 0x000000} } },
+ {{{1, 0x2200000, 0x2204000, 0x1b0000} } },/* 34: CAM */
+ {{{0} } }, /* 35: */
+ {{{0} } }, /* 36: */
+ {{{0} } }, /* 37: */
+ {{{0} } }, /* 38: */
+ {{{0} } }, /* 39: */
+ {{{1, 0x2800000, 0x2804000, 0x1a4000} } },/* 40: TMR */
+ {{{1, 0x2900000, 0x2901000, 0x16b000} } },/* 41: P2NR3 */
+ {{{1, 0x2a00000, 0x2a00400, 0x1ac400} } },/* 42: RPMX1 */
+ {{{1, 0x2b00000, 0x2b00400, 0x1ac800} } },/* 43: RPMX2 */
+ {{{1, 0x2c00000, 0x2c00400, 0x1acc00} } },/* 44: RPMX3 */
+ {{{1, 0x2d00000, 0x2d00400, 0x1ad000} } },/* 45: RPMX4 */
+ {{{1, 0x2e00000, 0x2e00400, 0x1ad400} } },/* 46: RPMX5 */
+ {{{1, 0x2f00000, 0x2f00400, 0x1ad800} } },/* 47: RPMX6 */
+ {{{1, 0x3000000, 0x3000400, 0x1adc00} } },/* 48: RPMX7 */
+ {{{0, 0x3100000, 0x3104000, 0x1a8000} } },/* 49: XDMA */
+ {{{1, 0x3200000, 0x3204000, 0x1d4000} } },/* 50: I2Q */
+ {{{1, 0x3300000, 0x3304000, 0x1a0000} } },/* 51: ROMUSB */
+ {{{0} } }, /* 52: */
+ {{{1, 0x3500000, 0x3500400, 0x1ac000} } },/* 53: RPMX0 */
+ {{{1, 0x3600000, 0x3600400, 0x1ae000} } },/* 54: RPMX8 */
+ {{{1, 0x3700000, 0x3700400, 0x1ae400} } },/* 55: RPMX9 */
+ {{{1, 0x3800000, 0x3804000, 0x1d0000} } },/* 56: OCM0 */
+ {{{1, 0x3900000, 0x3904000, 0x1b4000} } },/* 57: CRYPTO */
+ {{{1, 0x3a00000, 0x3a04000, 0x1d8000} } },/* 58: SMB */
+ {{{0} } }, /* 59: I2C0 */
+ {{{0} } }, /* 60: I2C1 */
+ {{{1, 0x3d00000, 0x3d04000, 0x1dc000} } },/* 61: LPC */
+ {{{1, 0x3e00000, 0x3e01000, 0x167000} } },/* 62: P2NC */
+ {{{1, 0x3f00000, 0x3f01000, 0x168000} } } /* 63: P2NR0 */
+};
+
+/*
+ * top 12 bits of crb internal address (hub, agent)
+ */
+static unsigned qla4_8xxx_crb_hub_agt[64] = {
+ 0,
+ QLA82XX_HW_CRB_HUB_AGT_ADR_PS,
+ QLA82XX_HW_CRB_HUB_AGT_ADR_MN,
+ QLA82XX_HW_CRB_HUB_AGT_ADR_MS,
+ 0,
+ QLA82XX_HW_CRB_HUB_AGT_ADR_SRE,
+ QLA82XX_HW_CRB_HUB_AGT_ADR_NIU,
+ QLA82XX_HW_CRB_HUB_AGT_ADR_QMN,
+ QLA82XX_HW_CRB_HUB_AGT_ADR_SQN0,
+ QLA82XX_HW_CRB_HUB_AGT_ADR_SQN1,
+ QLA82XX_HW_CRB_HUB_AGT_ADR_SQN2,
+ QLA82XX_HW_CRB_HUB_AGT_ADR_SQN3,
+ QLA82XX_HW_CRB_HUB_AGT_ADR_I2Q,
+ QLA82XX_HW_CRB_HUB_AGT_ADR_TIMR,
+ QLA82XX_HW_CRB_HUB_AGT_ADR_ROMUSB,
+ QLA82XX_HW_CRB_HUB_AGT_ADR_PGN4,
+ QLA82XX_HW_CRB_HUB_AGT_ADR_XDMA,
+ QLA82XX_HW_CRB_HUB_AGT_ADR_PGN0,
+ QLA82XX_HW_CRB_HUB_AGT_ADR_PGN1,
+ QLA82XX_HW_CRB_HUB_AGT_ADR_PGN2,
+ QLA82XX_HW_CRB_HUB_AGT_ADR_PGN3,
+ QLA82XX_HW_CRB_HUB_AGT_ADR_PGND,
+ QLA82XX_HW_CRB_HUB_AGT_ADR_PGNI,
+ QLA82XX_HW_CRB_HUB_AGT_ADR_PGS0,
+ QLA82XX_HW_CRB_HUB_AGT_ADR_PGS1,
+ QLA82XX_HW_CRB_HUB_AGT_ADR_PGS2,
+ QLA82XX_HW_CRB_HUB_AGT_ADR_PGS3,
+ 0,
+ QLA82XX_HW_CRB_HUB_AGT_ADR_PGSI,
+ QLA82XX_HW_CRB_HUB_AGT_ADR_SN,
+ 0,
+ QLA82XX_HW_CRB_HUB_AGT_ADR_EG,
+ 0,
+ QLA82XX_HW_CRB_HUB_AGT_ADR_PS,
+ QLA82XX_HW_CRB_HUB_AGT_ADR_CAM,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ QLA82XX_HW_CRB_HUB_AGT_ADR_TIMR,
+ 0,
+ QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX1,
+ QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX2,
+ QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX3,
+ QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX4,
+ QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX5,
+ QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX6,
+ QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX7,
+ QLA82XX_HW_CRB_HUB_AGT_ADR_XDMA,
+ QLA82XX_HW_CRB_HUB_AGT_ADR_I2Q,
+ QLA82XX_HW_CRB_HUB_AGT_ADR_ROMUSB,
+ 0,
+ QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX0,
+ QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX8,
+ QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX9,
+ QLA82XX_HW_CRB_HUB_AGT_ADR_OCM0,
+ 0,
+ QLA82XX_HW_CRB_HUB_AGT_ADR_SMB,
+ QLA82XX_HW_CRB_HUB_AGT_ADR_I2C0,
+ QLA82XX_HW_CRB_HUB_AGT_ADR_I2C1,
+ 0,
+ QLA82XX_HW_CRB_HUB_AGT_ADR_PGNC,
+ 0,
+};
+
+/* Device states */
+static char *qdev_state[] = {
+ "Unknown",
+ "Cold",
+ "Initializing",
+ "Ready",
+ "Need Reset",
+ "Need Quiescent",
+ "Failed",
+ "Quiescent",
+};
+
+/*
+ * In: 'off' is offset from CRB space in 128M pci map
+ * Out: 'off' is 2M pci map addr
+ * side effect: lock crb window
+ */
+static void
+qla4_8xxx_pci_set_crbwindow_2M(struct scsi_qla_host *ha, ulong *off)
+{
+ u32 win_read;
+
+ ha->crb_win = CRB_HI(*off);
+ writel(ha->crb_win,
+ (void __iomem *)(CRB_WINDOW_2M + ha->nx_pcibase));
+
+ /* Read back value to make sure write has gone through before trying
+ * to use it. */
+ win_read = readl((void __iomem *)(CRB_WINDOW_2M + ha->nx_pcibase));
+ if (win_read != ha->crb_win) {
+ DEBUG2(ql4_printk(KERN_INFO, ha,
+ "%s: Written crbwin (0x%x) != Read crbwin (0x%x),"
+ " off=0x%lx\n", __func__, ha->crb_win, win_read, *off));
+ }
+ *off = (*off & MASK(16)) + CRB_INDIRECT_2M + ha->nx_pcibase;
+}
+
+void
+qla4_8xxx_wr_32(struct scsi_qla_host *ha, ulong off, u32 data)
+{
+ unsigned long flags = 0;
+ int rv;
+
+ rv = qla4_8xxx_pci_get_crb_addr_2M(ha, &off);
+
+ BUG_ON(rv == -1);
+
+ if (rv == 1) {
+ write_lock_irqsave(&ha->hw_lock, flags);
+ qla4_8xxx_crb_win_lock(ha);
+ qla4_8xxx_pci_set_crbwindow_2M(ha, &off);
+ }
+
+ writel(data, (void __iomem *)off);
+
+ if (rv == 1) {
+ qla4_8xxx_crb_win_unlock(ha);
+ write_unlock_irqrestore(&ha->hw_lock, flags);
+ }
+}
+
+int
+qla4_8xxx_rd_32(struct scsi_qla_host *ha, ulong off)
+{
+ unsigned long flags = 0;
+ int rv;
+ u32 data;
+
+ rv = qla4_8xxx_pci_get_crb_addr_2M(ha, &off);
+
+ BUG_ON(rv == -1);
+
+ if (rv == 1) {
+ write_lock_irqsave(&ha->hw_lock, flags);
+ qla4_8xxx_crb_win_lock(ha);
+ qla4_8xxx_pci_set_crbwindow_2M(ha, &off);
+ }
+ data = readl((void __iomem *)off);
+
+ if (rv == 1) {
+ qla4_8xxx_crb_win_unlock(ha);
+ write_unlock_irqrestore(&ha->hw_lock, flags);
+ }
+ return data;
+}
+
+#define CRB_WIN_LOCK_TIMEOUT 100000000
+
+int qla4_8xxx_crb_win_lock(struct scsi_qla_host *ha)
+{
+ int i;
+ int done = 0, timeout = 0;
+
+ while (!done) {
+ /* acquire semaphore3 from PCI HW block */
+ done = qla4_8xxx_rd_32(ha, QLA82XX_PCIE_REG(PCIE_SEM7_LOCK));
+ if (done == 1)
+ break;
+ if (timeout >= CRB_WIN_LOCK_TIMEOUT)
+ return -1;
+
+ timeout++;
+
+ /* Yield CPU */
+ if (!in_interrupt())
+ schedule();
+ else {
+ for (i = 0; i < 20; i++)
+ cpu_relax(); /*This a nop instr on i386*/
+ }
+ }
+ qla4_8xxx_wr_32(ha, QLA82XX_CRB_WIN_LOCK_ID, ha->func_num);
+ return 0;
+}
+
+void qla4_8xxx_crb_win_unlock(struct scsi_qla_host *ha)
+{
+ qla4_8xxx_rd_32(ha, QLA82XX_PCIE_REG(PCIE_SEM7_UNLOCK));
+}
+
+#define IDC_LOCK_TIMEOUT 100000000
+
+/**
+ * qla4_8xxx_idc_lock - hw_lock
+ * @ha: pointer to adapter structure
+ *
+ * General purpose lock used to synchronize access to
+ * CRB_DEV_STATE, CRB_DEV_REF_COUNT, etc.
+ **/
+int qla4_8xxx_idc_lock(struct scsi_qla_host *ha)
+{
+ int i;
+ int done = 0, timeout = 0;
+
+ while (!done) {
+ /* acquire semaphore5 from PCI HW block */
+ done = qla4_8xxx_rd_32(ha, QLA82XX_PCIE_REG(PCIE_SEM5_LOCK));
+ if (done == 1)
+ break;
+ if (timeout >= IDC_LOCK_TIMEOUT)
+ return -1;
+
+ timeout++;
+
+ /* Yield CPU */
+ if (!in_interrupt())
+ schedule();
+ else {
+ for (i = 0; i < 20; i++)
+ cpu_relax(); /*This a nop instr on i386*/
+ }
+ }
+ return 0;
+}
+
+void qla4_8xxx_idc_unlock(struct scsi_qla_host *ha)
+{
+ qla4_8xxx_rd_32(ha, QLA82XX_PCIE_REG(PCIE_SEM5_UNLOCK));
+}
+
+int
+qla4_8xxx_pci_get_crb_addr_2M(struct scsi_qla_host *ha, ulong *off)
+{
+ struct crb_128M_2M_sub_block_map *m;
+
+ if (*off >= QLA82XX_CRB_MAX)
+ return -1;
+
+ if (*off >= QLA82XX_PCI_CAMQM && (*off < QLA82XX_PCI_CAMQM_2M_END)) {
+ *off = (*off - QLA82XX_PCI_CAMQM) +
+ QLA82XX_PCI_CAMQM_2M_BASE + ha->nx_pcibase;
+ return 0;
+ }
+
+ if (*off < QLA82XX_PCI_CRBSPACE)
+ return -1;
+
+ *off -= QLA82XX_PCI_CRBSPACE;
+ /*
+ * Try direct map
+ */
+
+ m = &crb_128M_2M_map[CRB_BLK(*off)].sub_block[CRB_SUBBLK(*off)];
+
+ if (m->valid && (m->start_128M <= *off) && (m->end_128M > *off)) {
+ *off = *off + m->start_2M - m->start_128M + ha->nx_pcibase;
+ return 0;
+ }
+
+ /*
+ * Not in direct map, use crb window
+ */
+ return 1;
+}
+
+/* PCI Windowing for DDR regions. */
+#define QLA82XX_ADDR_IN_RANGE(addr, low, high) \
+ (((addr) <= (high)) && ((addr) >= (low)))
+
+/*
+* check memory access boundary.
+* used by test agent. support ddr access only for now
+*/
+static unsigned long
+qla4_8xxx_pci_mem_bound_check(struct scsi_qla_host *ha,
+ unsigned long long addr, int size)
+{
+ if (!QLA82XX_ADDR_IN_RANGE(addr, QLA82XX_ADDR_DDR_NET,
+ QLA82XX_ADDR_DDR_NET_MAX) ||
+ !QLA82XX_ADDR_IN_RANGE(addr + size - 1,
+ QLA82XX_ADDR_DDR_NET, QLA82XX_ADDR_DDR_NET_MAX) ||
+ ((size != 1) && (size != 2) && (size != 4) && (size != 8))) {
+ return 0;
+ }
+ return 1;
+}
+
+static int qla4_8xxx_pci_set_window_warning_count;
+
+static unsigned long
+qla4_8xxx_pci_set_window(struct scsi_qla_host *ha, unsigned long long addr)
+{
+ int window;
+ u32 win_read;
+
+ if (QLA82XX_ADDR_IN_RANGE(addr, QLA82XX_ADDR_DDR_NET,
+ QLA82XX_ADDR_DDR_NET_MAX)) {
+ /* DDR network side */
+ window = MN_WIN(addr);
+ ha->ddr_mn_window = window;
+ qla4_8xxx_wr_32(ha, ha->mn_win_crb |
+ QLA82XX_PCI_CRBSPACE, window);
+ win_read = qla4_8xxx_rd_32(ha, ha->mn_win_crb |
+ QLA82XX_PCI_CRBSPACE);
+ if ((win_read << 17) != window) {
+ ql4_printk(KERN_WARNING, ha,
+ "%s: Written MNwin (0x%x) != Read MNwin (0x%x)\n",
+ __func__, window, win_read);
+ }
+ addr = GET_MEM_OFFS_2M(addr) + QLA82XX_PCI_DDR_NET;
+ } else if (QLA82XX_ADDR_IN_RANGE(addr, QLA82XX_ADDR_OCM0,
+ QLA82XX_ADDR_OCM0_MAX)) {
+ unsigned int temp1;
+ /* if bits 19:18&17:11 are on */
+ if ((addr & 0x00ff800) == 0xff800) {
+ printk("%s: QM access not handled.\n", __func__);
+ addr = -1UL;
+ }
+
+ window = OCM_WIN(addr);
+ ha->ddr_mn_window = window;
+ qla4_8xxx_wr_32(ha, ha->mn_win_crb |
+ QLA82XX_PCI_CRBSPACE, window);
+ win_read = qla4_8xxx_rd_32(ha, ha->mn_win_crb |
+ QLA82XX_PCI_CRBSPACE);
+ temp1 = ((window & 0x1FF) << 7) |
+ ((window & 0x0FFFE0000) >> 17);
+ if (win_read != temp1) {
+ printk("%s: Written OCMwin (0x%x) != Read"
+ " OCMwin (0x%x)\n", __func__, temp1, win_read);
+ }
+ addr = GET_MEM_OFFS_2M(addr) + QLA82XX_PCI_OCM0_2M;
+
+ } else if (QLA82XX_ADDR_IN_RANGE(addr, QLA82XX_ADDR_QDR_NET,
+ QLA82XX_P3_ADDR_QDR_NET_MAX)) {
+ /* QDR network side */
+ window = MS_WIN(addr);
+ ha->qdr_sn_window = window;
+ qla4_8xxx_wr_32(ha, ha->ms_win_crb |
+ QLA82XX_PCI_CRBSPACE, window);
+ win_read = qla4_8xxx_rd_32(ha,
+ ha->ms_win_crb | QLA82XX_PCI_CRBSPACE);
+ if (win_read != window) {
+ printk("%s: Written MSwin (0x%x) != Read "
+ "MSwin (0x%x)\n", __func__, window, win_read);
+ }
+ addr = GET_MEM_OFFS_2M(addr) + QLA82XX_PCI_QDR_NET;
+
+ } else {
+ /*
+ * peg gdb frequently accesses memory that doesn't exist,
+ * this limits the chit chat so debugging isn't slowed down.
+ */
+ if ((qla4_8xxx_pci_set_window_warning_count++ < 8) ||
+ (qla4_8xxx_pci_set_window_warning_count%64 == 0)) {
+ printk("%s: Warning:%s Unknown address range!\n",
+ __func__, DRIVER_NAME);
+ }
+ addr = -1UL;
+ }
+ return addr;
+}
+
+/* check if address is in the same windows as the previous access */
+static int qla4_8xxx_pci_is_same_window(struct scsi_qla_host *ha,
+ unsigned long long addr)
+{
+ int window;
+ unsigned long long qdr_max;
+
+ qdr_max = QLA82XX_P3_ADDR_QDR_NET_MAX;
+
+ if (QLA82XX_ADDR_IN_RANGE(addr, QLA82XX_ADDR_DDR_NET,
+ QLA82XX_ADDR_DDR_NET_MAX)) {
+ /* DDR network side */
+ BUG(); /* MN access can not come here */
+ } else if (QLA82XX_ADDR_IN_RANGE(addr, QLA82XX_ADDR_OCM0,
+ QLA82XX_ADDR_OCM0_MAX)) {
+ return 1;
+ } else if (QLA82XX_ADDR_IN_RANGE(addr, QLA82XX_ADDR_OCM1,
+ QLA82XX_ADDR_OCM1_MAX)) {
+ return 1;
+ } else if (QLA82XX_ADDR_IN_RANGE(addr, QLA82XX_ADDR_QDR_NET,
+ qdr_max)) {
+ /* QDR network side */
+ window = ((addr - QLA82XX_ADDR_QDR_NET) >> 22) & 0x3f;
+ if (ha->qdr_sn_window == window)
+ return 1;
+ }
+
+ return 0;
+}
+
+static int qla4_8xxx_pci_mem_read_direct(struct scsi_qla_host *ha,
+ u64 off, void *data, int size)
+{
+ unsigned long flags;
+ void __iomem *addr;
+ int ret = 0;
+ u64 start;
+ void __iomem *mem_ptr = NULL;
+ unsigned long mem_base;
+ unsigned long mem_page;
+
+ write_lock_irqsave(&ha->hw_lock, flags);
+
+ /*
+ * If attempting to access unknown address or straddle hw windows,
+ * do not access.
+ */
+ start = qla4_8xxx_pci_set_window(ha, off);
+ if ((start == -1UL) ||
+ (qla4_8xxx_pci_is_same_window(ha, off + size - 1) == 0)) {
+ write_unlock_irqrestore(&ha->hw_lock, flags);
+ printk(KERN_ERR"%s out of bound pci memory access. "
+ "offset is 0x%llx\n", DRIVER_NAME, off);
+ return -1;
+ }
+
+ addr = qla4_8xxx_pci_base_offsetfset(ha, start);
+ if (!addr) {
+ write_unlock_irqrestore(&ha->hw_lock, flags);
+ mem_base = pci_resource_start(ha->pdev, 0);
+ mem_page = start & PAGE_MASK;
+ /* Map two pages whenever user tries to access addresses in two
+ consecutive pages.
+ */
+ if (mem_page != ((start + size - 1) & PAGE_MASK))
+ mem_ptr = ioremap(mem_base + mem_page, PAGE_SIZE * 2);
+ else
+ mem_ptr = ioremap(mem_base + mem_page, PAGE_SIZE);
+
+ if (mem_ptr == NULL) {
+ *(u8 *)data = 0;
+ return -1;
+ }
+ addr = mem_ptr;
+ addr += start & (PAGE_SIZE - 1);
+ write_lock_irqsave(&ha->hw_lock, flags);
+ }
+
+ switch (size) {
+ case 1:
+ *(u8 *)data = readb(addr);
+ break;
+ case 2:
+ *(u16 *)data = readw(addr);
+ break;
+ case 4:
+ *(u32 *)data = readl(addr);
+ break;
+ case 8:
+ *(u64 *)data = readq(addr);
+ break;
+ default:
+ ret = -1;
+ break;
+ }
+ write_unlock_irqrestore(&ha->hw_lock, flags);
+
+ if (mem_ptr)
+ iounmap(mem_ptr);
+ return ret;
+}
+
+static int
+qla4_8xxx_pci_mem_write_direct(struct scsi_qla_host *ha, u64 off,
+ void *data, int size)
+{
+ unsigned long flags;
+ void __iomem *addr;
+ int ret = 0;
+ u64 start;
+ void __iomem *mem_ptr = NULL;
+ unsigned long mem_base;
+ unsigned long mem_page;
+
+ write_lock_irqsave(&ha->hw_lock, flags);
+
+ /*
+ * If attempting to access unknown address or straddle hw windows,
+ * do not access.
+ */
+ start = qla4_8xxx_pci_set_window(ha, off);
+ if ((start == -1UL) ||
+ (qla4_8xxx_pci_is_same_window(ha, off + size - 1) == 0)) {
+ write_unlock_irqrestore(&ha->hw_lock, flags);
+ printk(KERN_ERR"%s out of bound pci memory access. "
+ "offset is 0x%llx\n", DRIVER_NAME, off);
+ return -1;
+ }
+
+ addr = qla4_8xxx_pci_base_offsetfset(ha, start);
+ if (!addr) {
+ write_unlock_irqrestore(&ha->hw_lock, flags);
+ mem_base = pci_resource_start(ha->pdev, 0);
+ mem_page = start & PAGE_MASK;
+ /* Map two pages whenever user tries to access addresses in two
+ consecutive pages.
+ */
+ if (mem_page != ((start + size - 1) & PAGE_MASK))
+ mem_ptr = ioremap(mem_base + mem_page, PAGE_SIZE*2);
+ else
+ mem_ptr = ioremap(mem_base + mem_page, PAGE_SIZE);
+ if (mem_ptr == NULL)
+ return -1;
+
+ addr = mem_ptr;
+ addr += start & (PAGE_SIZE - 1);
+ write_lock_irqsave(&ha->hw_lock, flags);
+ }
+
+ switch (size) {
+ case 1:
+ writeb(*(u8 *)data, addr);
+ break;
+ case 2:
+ writew(*(u16 *)data, addr);
+ break;
+ case 4:
+ writel(*(u32 *)data, addr);
+ break;
+ case 8:
+ writeq(*(u64 *)data, addr);
+ break;
+ default:
+ ret = -1;
+ break;
+ }
+ write_unlock_irqrestore(&ha->hw_lock, flags);
+ if (mem_ptr)
+ iounmap(mem_ptr);
+ return ret;
+}
+
+#define MTU_FUDGE_FACTOR 100
+
+static unsigned long
+qla4_8xxx_decode_crb_addr(unsigned long addr)
+{
+ int i;
+ unsigned long base_addr, offset, pci_base;
+
+ if (!qla4_8xxx_crb_table_initialized)
+ qla4_8xxx_crb_addr_transform_setup();
+
+ pci_base = ADDR_ERROR;
+ base_addr = addr & 0xfff00000;
+ offset = addr & 0x000fffff;
+
+ for (i = 0; i < MAX_CRB_XFORM; i++) {
+ if (crb_addr_xform[i] == base_addr) {
+ pci_base = i << 20;
+ break;
+ }
+ }
+ if (pci_base == ADDR_ERROR)
+ return pci_base;
+ else
+ return pci_base + offset;
+}
+
+static long rom_max_timeout = 100;
+static long qla4_8xxx_rom_lock_timeout = 100;
+
+static int
+qla4_8xxx_rom_lock(struct scsi_qla_host *ha)
+{
+ int i;
+ int done = 0, timeout = 0;
+
+ while (!done) {
+ /* acquire semaphore2 from PCI HW block */
+
+ done = qla4_8xxx_rd_32(ha, QLA82XX_PCIE_REG(PCIE_SEM2_LOCK));
+ if (done == 1)
+ break;
+ if (timeout >= qla4_8xxx_rom_lock_timeout)
+ return -1;
+
+ timeout++;
+
+ /* Yield CPU */
+ if (!in_interrupt())
+ schedule();
+ else {
+ for (i = 0; i < 20; i++)
+ cpu_relax(); /*This a nop instr on i386*/
+ }
+ }
+ qla4_8xxx_wr_32(ha, QLA82XX_ROM_LOCK_ID, ROM_LOCK_DRIVER);
+ return 0;
+}
+
+static void
+qla4_8xxx_rom_unlock(struct scsi_qla_host *ha)
+{
+ qla4_8xxx_rd_32(ha, QLA82XX_PCIE_REG(PCIE_SEM2_UNLOCK));
+}
+
+static int
+qla4_8xxx_wait_rom_done(struct scsi_qla_host *ha)
+{
+ long timeout = 0;
+ long done = 0 ;
+
+ while (done == 0) {
+ done = qla4_8xxx_rd_32(ha, QLA82XX_ROMUSB_GLB_STATUS);
+ done &= 2;
+ timeout++;
+ if (timeout >= rom_max_timeout) {
+ printk("%s: Timeout reached waiting for rom done",
+ DRIVER_NAME);
+ return -1;
+ }
+ }
+ return 0;
+}
+
+static int
+qla4_8xxx_do_rom_fast_read(struct scsi_qla_host *ha, int addr, int *valp)
+{
+ qla4_8xxx_wr_32(ha, QLA82XX_ROMUSB_ROM_ADDRESS, addr);
+ qla4_8xxx_wr_32(ha, QLA82XX_ROMUSB_ROM_DUMMY_BYTE_CNT, 0);
+ qla4_8xxx_wr_32(ha, QLA82XX_ROMUSB_ROM_ABYTE_CNT, 3);
+ qla4_8xxx_wr_32(ha, QLA82XX_ROMUSB_ROM_INSTR_OPCODE, 0xb);
+ if (qla4_8xxx_wait_rom_done(ha)) {
+ printk("%s: Error waiting for rom done\n", DRIVER_NAME);
+ return -1;
+ }
+ /* reset abyte_cnt and dummy_byte_cnt */
+ qla4_8xxx_wr_32(ha, QLA82XX_ROMUSB_ROM_DUMMY_BYTE_CNT, 0);
+ udelay(10);
+ qla4_8xxx_wr_32(ha, QLA82XX_ROMUSB_ROM_ABYTE_CNT, 0);
+
+ *valp = qla4_8xxx_rd_32(ha, QLA82XX_ROMUSB_ROM_RDATA);
+ return 0;
+}
+
+static int
+qla4_8xxx_rom_fast_read(struct scsi_qla_host *ha, int addr, int *valp)
+{
+ int ret, loops = 0;
+
+ while ((qla4_8xxx_rom_lock(ha) != 0) && (loops < 50000)) {
+ udelay(100);
+ loops++;
+ }
+ if (loops >= 50000) {
+ printk("%s: qla4_8xxx_rom_lock failed\n", DRIVER_NAME);
+ return -1;
+ }
+ ret = qla4_8xxx_do_rom_fast_read(ha, addr, valp);
+ qla4_8xxx_rom_unlock(ha);
+ return ret;
+}
+
+/**
+ * This routine does CRB initialize sequence
+ * to put the ISP into operational state
+ **/
+static int
+qla4_8xxx_pinit_from_rom(struct scsi_qla_host *ha, int verbose)
+{
+ int addr, val;
+ int i ;
+ struct crb_addr_pair *buf;
+ unsigned long off;
+ unsigned offset, n;
+
+ struct crb_addr_pair {
+ long addr;
+ long data;
+ };
+
+ /* Halt all the indiviual PEGs and other blocks of the ISP */
+ qla4_8xxx_rom_lock(ha);
+ if (test_bit(DPC_RESET_HA, &ha->dpc_flags))
+ /* don't reset CAM block on reset */
+ qla4_8xxx_wr_32(ha, QLA82XX_ROMUSB_GLB_SW_RESET, 0xfeffffff);
+ else
+ qla4_8xxx_wr_32(ha, QLA82XX_ROMUSB_GLB_SW_RESET, 0xffffffff);
+
+ qla4_8xxx_rom_unlock(ha);
+
+ /* Read the signature value from the flash.
+ * Offset 0: Contain signature (0xcafecafe)
+ * Offset 4: Offset and number of addr/value pairs
+ * that present in CRB initialize sequence
+ */
+ if (qla4_8xxx_rom_fast_read(ha, 0, &n) != 0 || n != 0xcafecafeUL ||
+ qla4_8xxx_rom_fast_read(ha, 4, &n) != 0) {
+ ql4_printk(KERN_WARNING, ha,
+ "[ERROR] Reading crb_init area: n: %08x\n", n);
+ return -1;
+ }
+
+ /* Offset in flash = lower 16 bits
+ * Number of enteries = upper 16 bits
+ */
+ offset = n & 0xffffU;
+ n = (n >> 16) & 0xffffU;
+
+ /* number of addr/value pair should not exceed 1024 enteries */
+ if (n >= 1024) {
+ ql4_printk(KERN_WARNING, ha,
+ "%s: %s:n=0x%x [ERROR] Card flash not initialized.\n",
+ DRIVER_NAME, __func__, n);
+ return -1;
+ }
+
+ ql4_printk(KERN_INFO, ha,
+ "%s: %d CRB init values found in ROM.\n", DRIVER_NAME, n);
+
+ buf = kmalloc(n * sizeof(struct crb_addr_pair), GFP_KERNEL);
+ if (buf == NULL) {
+ ql4_printk(KERN_WARNING, ha,
+ "%s: [ERROR] Unable to malloc memory.\n", DRIVER_NAME);
+ return -1;
+ }
+
+ for (i = 0; i < n; i++) {
+ if (qla4_8xxx_rom_fast_read(ha, 8*i + 4*offset, &val) != 0 ||
+ qla4_8xxx_rom_fast_read(ha, 8*i + 4*offset + 4, &addr) !=
+ 0) {
+ kfree(buf);
+ return -1;
+ }
+
+ buf[i].addr = addr;
+ buf[i].data = val;
+ }
+
+ for (i = 0; i < n; i++) {
+ /* Translate internal CRB initialization
+ * address to PCI bus address
+ */
+ off = qla4_8xxx_decode_crb_addr((unsigned long)buf[i].addr) +
+ QLA82XX_PCI_CRBSPACE;
+ /* Not all CRB addr/value pair to be written,
+ * some of them are skipped
+ */
+
+ /* skip if LS bit is set*/
+ if (off & 0x1) {
+ DEBUG2(ql4_printk(KERN_WARNING, ha,
+ "Skip CRB init replay for offset = 0x%lx\n", off));
+ continue;
+ }
+
+ /* skipping cold reboot MAGIC */
+ if (off == QLA82XX_CAM_RAM(0x1fc))
+ continue;
+
+ /* do not reset PCI */
+ if (off == (ROMUSB_GLB + 0xbc))
+ continue;
+
+ /* skip core clock, so that firmware can increase the clock */
+ if (off == (ROMUSB_GLB + 0xc8))
+ continue;
+
+ /* skip the function enable register */
+ if (off == QLA82XX_PCIE_REG(PCIE_SETUP_FUNCTION))
+ continue;
+
+ if (off == QLA82XX_PCIE_REG(PCIE_SETUP_FUNCTION2))
+ continue;
+
+ if ((off & 0x0ff00000) == QLA82XX_CRB_SMB)
+ continue;
+
+ if ((off & 0x0ff00000) == QLA82XX_CRB_DDR_NET)
+ continue;
+
+ if (off == ADDR_ERROR) {
+ ql4_printk(KERN_WARNING, ha,
+ "%s: [ERROR] Unknown addr: 0x%08lx\n",
+ DRIVER_NAME, buf[i].addr);
+ continue;
+ }
+
+ qla4_8xxx_wr_32(ha, off, buf[i].data);
+
+ /* ISP requires much bigger delay to settle down,
+ * else crb_window returns 0xffffffff
+ */
+ if (off == QLA82XX_ROMUSB_GLB_SW_RESET)
+ msleep(1000);
+
+ /* ISP requires millisec delay between
+ * successive CRB register updation
+ */
+ msleep(1);
+ }
+
+ kfree(buf);
+
+ /* Resetting the data and instruction cache */
+ qla4_8xxx_wr_32(ha, QLA82XX_CRB_PEG_NET_D+0xec, 0x1e);
+ qla4_8xxx_wr_32(ha, QLA82XX_CRB_PEG_NET_D+0x4c, 8);
+ qla4_8xxx_wr_32(ha, QLA82XX_CRB_PEG_NET_I+0x4c, 8);
+
+ /* Clear all protocol processing engines */
+ qla4_8xxx_wr_32(ha, QLA82XX_CRB_PEG_NET_0+0x8, 0);
+ qla4_8xxx_wr_32(ha, QLA82XX_CRB_PEG_NET_0+0xc, 0);
+ qla4_8xxx_wr_32(ha, QLA82XX_CRB_PEG_NET_1+0x8, 0);
+ qla4_8xxx_wr_32(ha, QLA82XX_CRB_PEG_NET_1+0xc, 0);
+ qla4_8xxx_wr_32(ha, QLA82XX_CRB_PEG_NET_2+0x8, 0);
+ qla4_8xxx_wr_32(ha, QLA82XX_CRB_PEG_NET_2+0xc, 0);
+ qla4_8xxx_wr_32(ha, QLA82XX_CRB_PEG_NET_3+0x8, 0);
+ qla4_8xxx_wr_32(ha, QLA82XX_CRB_PEG_NET_3+0xc, 0);
+
+ return 0;
+}
+
+static int qla4_8xxx_check_for_bad_spd(struct scsi_qla_host *ha)
+{
+ u32 val = 0;
+ val = qla4_8xxx_rd_32(ha, BOOT_LOADER_DIMM_STATUS) ;
+ val &= QLA82XX_BOOT_LOADER_MN_ISSUE;
+ if (val & QLA82XX_PEG_TUNE_MN_SPD_ZEROED) {
+ printk("Memory DIMM SPD not programmed. Assumed valid.\n");
+ return 1;
+ } else if (val) {
+ printk("Memory DIMM type incorrect. Info:%08X.\n", val);
+ return 2;
+ }
+ return 0;
+}
+
+static int
+qla4_8xxx_load_from_flash(struct scsi_qla_host *ha, uint32_t image_start)
+{
+ int i;
+ long size = 0;
+ long flashaddr, memaddr;
+ u64 data;
+ u32 high, low;
+
+ flashaddr = memaddr = ha->hw.flt_region_bootload;
+ size = (image_start - flashaddr)/8;
+
+ DEBUG2(printk("scsi%ld: %s: bootldr=0x%lx, fw_image=0x%x\n",
+ ha->host_no, __func__, flashaddr, image_start));
+
+ for (i = 0; i < size; i++) {
+ if ((qla4_8xxx_rom_fast_read(ha, flashaddr, (int *)&low)) ||
+ (qla4_8xxx_rom_fast_read(ha, flashaddr + 4,
+ (int *)&high))) {
+ return -1;
+ }
+ data = ((u64)high << 32) | low ;
+ qla4_8xxx_pci_mem_write_2M(ha, memaddr, &data, 8);
+ flashaddr += 8;
+ memaddr += 8;
+
+ if (i%0x1000 == 0)
+ msleep(1);
+
+ }
+
+ udelay(100);
+
+ read_lock(&ha->hw_lock);
+ qla4_8xxx_wr_32(ha, QLA82XX_CRB_PEG_NET_0 + 0x18, 0x1020);
+ qla4_8xxx_wr_32(ha, QLA82XX_ROMUSB_GLB_SW_RESET, 0x80001e);
+ read_unlock(&ha->hw_lock);
+
+ return 0;
+}
+
+static int qla4_8xxx_load_fw(struct scsi_qla_host *ha, uint32_t image_start)
+{
+ u32 rst;
+
+ qla4_8xxx_wr_32(ha, CRB_CMDPEG_STATE, 0);
+ if (qla4_8xxx_pinit_from_rom(ha, 0) != QLA_SUCCESS) {
+ printk(KERN_WARNING "%s: Error during CRB Initialization\n",
+ __func__);
+ return QLA_ERROR;
+ }
+
+ udelay(500);
+
+ /* at this point, QM is in reset. This could be a problem if there are
+ * incoming d* transition queue messages. QM/PCIE could wedge.
+ * To get around this, QM is brought out of reset.
+ */
+
+ rst = qla4_8xxx_rd_32(ha, QLA82XX_ROMUSB_GLB_SW_RESET);
+ /* unreset qm */
+ rst &= ~(1 << 28);
+ qla4_8xxx_wr_32(ha, QLA82XX_ROMUSB_GLB_SW_RESET, rst);
+
+ if (qla4_8xxx_load_from_flash(ha, image_start)) {
+ printk("%s: Error trying to load fw from flash!\n", __func__);
+ return QLA_ERROR;
+ }
+
+ return QLA_SUCCESS;
+}
+
+int
+qla4_8xxx_pci_mem_read_2M(struct scsi_qla_host *ha,
+ u64 off, void *data, int size)
+{
+ int i, j = 0, k, start, end, loop, sz[2], off0[2];
+ int shift_amount;
+ uint32_t temp;
+ uint64_t off8, val, mem_crb, word[2] = {0, 0};
+
+ /*
+ * If not MN, go check for MS or invalid.
+ */
+
+ if (off >= QLA82XX_ADDR_QDR_NET && off <= QLA82XX_P3_ADDR_QDR_NET_MAX)
+ mem_crb = QLA82XX_CRB_QDR_NET;
+ else {
+ mem_crb = QLA82XX_CRB_DDR_NET;
+ if (qla4_8xxx_pci_mem_bound_check(ha, off, size) == 0)
+ return qla4_8xxx_pci_mem_read_direct(ha,
+ off, data, size);
+ }
+
+
+ off8 = off & 0xfffffff0;
+ off0[0] = off & 0xf;
+ sz[0] = (size < (16 - off0[0])) ? size : (16 - off0[0]);
+ shift_amount = 4;
+
+ loop = ((off0[0] + size - 1) >> shift_amount) + 1;
+ off0[1] = 0;
+ sz[1] = size - sz[0];
+
+ for (i = 0; i < loop; i++) {
+ temp = off8 + (i << shift_amount);
+ qla4_8xxx_wr_32(ha, mem_crb + MIU_TEST_AGT_ADDR_LO, temp);
+ temp = 0;
+ qla4_8xxx_wr_32(ha, mem_crb + MIU_TEST_AGT_ADDR_HI, temp);
+ temp = MIU_TA_CTL_ENABLE;
+ qla4_8xxx_wr_32(ha, mem_crb + MIU_TEST_AGT_CTRL, temp);
+ temp = MIU_TA_CTL_START | MIU_TA_CTL_ENABLE;
+ qla4_8xxx_wr_32(ha, mem_crb + MIU_TEST_AGT_CTRL, temp);
+
+ for (j = 0; j < MAX_CTL_CHECK; j++) {
+ temp = qla4_8xxx_rd_32(ha, mem_crb + MIU_TEST_AGT_CTRL);
+ if ((temp & MIU_TA_CTL_BUSY) == 0)
+ break;
+ }
+
+ if (j >= MAX_CTL_CHECK) {
+ if (printk_ratelimit())
+ ql4_printk(KERN_ERR, ha,
+ "failed to read through agent\n");
+ break;
+ }
+
+ start = off0[i] >> 2;
+ end = (off0[i] + sz[i] - 1) >> 2;
+ for (k = start; k <= end; k++) {
+ temp = qla4_8xxx_rd_32(ha,
+ mem_crb + MIU_TEST_AGT_RDDATA(k));
+ word[i] |= ((uint64_t)temp << (32 * (k & 1)));
+ }
+ }
+
+ if (j >= MAX_CTL_CHECK)
+ return -1;
+
+ if ((off0[0] & 7) == 0) {
+ val = word[0];
+ } else {
+ val = ((word[0] >> (off0[0] * 8)) & (~(~0ULL << (sz[0] * 8)))) |
+ ((word[1] & (~(~0ULL << (sz[1] * 8)))) << (sz[0] * 8));
+ }
+
+ switch (size) {
+ case 1:
+ *(uint8_t *)data = val;
+ break;
+ case 2:
+ *(uint16_t *)data = val;
+ break;
+ case 4:
+ *(uint32_t *)data = val;
+ break;
+ case 8:
+ *(uint64_t *)data = val;
+ break;
+ }
+ return 0;
+}
+
+int
+qla4_8xxx_pci_mem_write_2M(struct scsi_qla_host *ha,
+ u64 off, void *data, int size)
+{
+ int i, j, ret = 0, loop, sz[2], off0;
+ int scale, shift_amount, startword;
+ uint32_t temp;
+ uint64_t off8, mem_crb, tmpw, word[2] = {0, 0};
+
+ /*
+ * If not MN, go check for MS or invalid.
+ */
+ if (off >= QLA82XX_ADDR_QDR_NET && off <= QLA82XX_P3_ADDR_QDR_NET_MAX)
+ mem_crb = QLA82XX_CRB_QDR_NET;
+ else {
+ mem_crb = QLA82XX_CRB_DDR_NET;
+ if (qla4_8xxx_pci_mem_bound_check(ha, off, size) == 0)
+ return qla4_8xxx_pci_mem_write_direct(ha,
+ off, data, size);
+ }
+
+ off0 = off & 0x7;
+ sz[0] = (size < (8 - off0)) ? size : (8 - off0);
+ sz[1] = size - sz[0];
+
+ off8 = off & 0xfffffff0;
+ loop = (((off & 0xf) + size - 1) >> 4) + 1;
+ shift_amount = 4;
+ scale = 2;
+ startword = (off & 0xf)/8;
+
+ for (i = 0; i < loop; i++) {
+ if (qla4_8xxx_pci_mem_read_2M(ha, off8 +
+ (i << shift_amount), &word[i * scale], 8))
+ return -1;
+ }
+
+ switch (size) {
+ case 1:
+ tmpw = *((uint8_t *)data);
+ break;
+ case 2:
+ tmpw = *((uint16_t *)data);
+ break;
+ case 4:
+ tmpw = *((uint32_t *)data);
+ break;
+ case 8:
+ default:
+ tmpw = *((uint64_t *)data);
+ break;
+ }
+
+ if (sz[0] == 8)
+ word[startword] = tmpw;
+ else {
+ word[startword] &=
+ ~((~(~0ULL << (sz[0] * 8))) << (off0 * 8));
+ word[startword] |= tmpw << (off0 * 8);
+ }
+
+ if (sz[1] != 0) {
+ word[startword+1] &= ~(~0ULL << (sz[1] * 8));
+ word[startword+1] |= tmpw >> (sz[0] * 8);
+ }
+
+ for (i = 0; i < loop; i++) {
+ temp = off8 + (i << shift_amount);
+ qla4_8xxx_wr_32(ha, mem_crb+MIU_TEST_AGT_ADDR_LO, temp);
+ temp = 0;
+ qla4_8xxx_wr_32(ha, mem_crb+MIU_TEST_AGT_ADDR_HI, temp);
+ temp = word[i * scale] & 0xffffffff;
+ qla4_8xxx_wr_32(ha, mem_crb+MIU_TEST_AGT_WRDATA_LO, temp);
+ temp = (word[i * scale] >> 32) & 0xffffffff;
+ qla4_8xxx_wr_32(ha, mem_crb+MIU_TEST_AGT_WRDATA_HI, temp);
+ temp = word[i*scale + 1] & 0xffffffff;
+ qla4_8xxx_wr_32(ha, mem_crb + MIU_TEST_AGT_WRDATA_UPPER_LO,
+ temp);
+ temp = (word[i*scale + 1] >> 32) & 0xffffffff;
+ qla4_8xxx_wr_32(ha, mem_crb + MIU_TEST_AGT_WRDATA_UPPER_HI,
+ temp);
+
+ temp = MIU_TA_CTL_ENABLE | MIU_TA_CTL_WRITE;
+ qla4_8xxx_wr_32(ha, mem_crb+MIU_TEST_AGT_CTRL, temp);
+ temp = MIU_TA_CTL_START | MIU_TA_CTL_ENABLE | MIU_TA_CTL_WRITE;
+ qla4_8xxx_wr_32(ha, mem_crb+MIU_TEST_AGT_CTRL, temp);
+
+ for (j = 0; j < MAX_CTL_CHECK; j++) {
+ temp = qla4_8xxx_rd_32(ha, mem_crb + MIU_TEST_AGT_CTRL);
+ if ((temp & MIU_TA_CTL_BUSY) == 0)
+ break;
+ }
+
+ if (j >= MAX_CTL_CHECK) {
+ if (printk_ratelimit())
+ ql4_printk(KERN_ERR, ha,
+ "failed to write through agent\n");
+ ret = -1;
+ break;
+ }
+ }
+
+ return ret;
+}
+
+static int qla4_8xxx_cmdpeg_ready(struct scsi_qla_host *ha, int pegtune_val)
+{
+ u32 val = 0;
+ int retries = 60;
+
+ if (!pegtune_val) {
+ do {
+ val = qla4_8xxx_rd_32(ha, CRB_CMDPEG_STATE);
+ if ((val == PHAN_INITIALIZE_COMPLETE) ||
+ (val == PHAN_INITIALIZE_ACK))
+ return 0;
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout(500);
+
+ } while (--retries);
+
+ qla4_8xxx_check_for_bad_spd(ha);
+
+ if (!retries) {
+ pegtune_val = qla4_8xxx_rd_32(ha,
+ QLA82XX_ROMUSB_GLB_PEGTUNE_DONE);
+ printk(KERN_WARNING "%s: init failed, "
+ "pegtune_val = %x\n", __func__, pegtune_val);
+ return -1;
+ }
+ }
+ return 0;
+}
+
+static int qla4_8xxx_rcvpeg_ready(struct scsi_qla_host *ha)
+{
+ uint32_t state = 0;
+ int loops = 0;
+
+ /* Window 1 call */
+ read_lock(&ha->hw_lock);
+ state = qla4_8xxx_rd_32(ha, CRB_RCVPEG_STATE);
+ read_unlock(&ha->hw_lock);
+
+ while ((state != PHAN_PEG_RCV_INITIALIZED) && (loops < 30000)) {
+ udelay(100);
+ /* Window 1 call */
+ read_lock(&ha->hw_lock);
+ state = qla4_8xxx_rd_32(ha, CRB_RCVPEG_STATE);
+ read_unlock(&ha->hw_lock);
+
+ loops++;
+ }
+
+ if (loops >= 30000) {
+ DEBUG2(ql4_printk(KERN_INFO, ha,
+ "Receive Peg initialization not complete: 0x%x.\n", state));
+ return QLA_ERROR;
+ }
+
+ return QLA_SUCCESS;
+}
+
+static inline void
+qla4_8xxx_set_drv_active(struct scsi_qla_host *ha)
+{
+ uint32_t drv_active;
+
+ drv_active = qla4_8xxx_rd_32(ha, QLA82XX_CRB_DRV_ACTIVE);
+ drv_active |= (1 << (ha->func_num * 4));
+ qla4_8xxx_wr_32(ha, QLA82XX_CRB_DRV_ACTIVE, drv_active);
+}
+
+void
+qla4_8xxx_clear_drv_active(struct scsi_qla_host *ha)
+{
+ uint32_t drv_active;
+
+ drv_active = qla4_8xxx_rd_32(ha, QLA82XX_CRB_DRV_ACTIVE);
+ drv_active &= ~(1 << (ha->func_num * 4));
+ qla4_8xxx_wr_32(ha, QLA82XX_CRB_DRV_ACTIVE, drv_active);
+}
+
+static inline int
+qla4_8xxx_need_reset(struct scsi_qla_host *ha)
+{
+ uint32_t drv_state;
+ int rval;
+
+ drv_state = qla4_8xxx_rd_32(ha, QLA82XX_CRB_DRV_STATE);
+ rval = drv_state & (1 << (ha->func_num * 4));
+ return rval;
+}
+
+static inline void
+qla4_8xxx_set_rst_ready(struct scsi_qla_host *ha)
+{
+ uint32_t drv_state;
+
+ drv_state = qla4_8xxx_rd_32(ha, QLA82XX_CRB_DRV_STATE);
+ drv_state |= (1 << (ha->func_num * 4));
+ qla4_8xxx_wr_32(ha, QLA82XX_CRB_DRV_STATE, drv_state);
+}
+
+static inline void
+qla4_8xxx_clear_rst_ready(struct scsi_qla_host *ha)
+{
+ uint32_t drv_state;
+
+ drv_state = qla4_8xxx_rd_32(ha, QLA82XX_CRB_DRV_STATE);
+ drv_state &= ~(1 << (ha->func_num * 4));
+ qla4_8xxx_wr_32(ha, QLA82XX_CRB_DRV_STATE, drv_state);
+}
+
+static inline void
+qla4_8xxx_set_qsnt_ready(struct scsi_qla_host *ha)
+{
+ uint32_t qsnt_state;
+
+ qsnt_state = qla4_8xxx_rd_32(ha, QLA82XX_CRB_DRV_STATE);
+ qsnt_state |= (2 << (ha->func_num * 4));
+ qla4_8xxx_wr_32(ha, QLA82XX_CRB_DRV_STATE, qsnt_state);
+}
+
+
+static int
+qla4_8xxx_start_firmware(struct scsi_qla_host *ha, uint32_t image_start)
+{
+ int pcie_cap;
+ uint16_t lnk;
+
+ /* scrub dma mask expansion register */
+ qla4_8xxx_wr_32(ha, CRB_DMA_SHIFT, 0x55555555);
+
+ /* Overwrite stale initialization register values */
+ qla4_8xxx_wr_32(ha, CRB_CMDPEG_STATE, 0);
+ qla4_8xxx_wr_32(ha, CRB_RCVPEG_STATE, 0);
+ qla4_8xxx_wr_32(ha, QLA82XX_PEG_HALT_STATUS1, 0);
+ qla4_8xxx_wr_32(ha, QLA82XX_PEG_HALT_STATUS2, 0);
+
+ if (qla4_8xxx_load_fw(ha, image_start) != QLA_SUCCESS) {
+ printk("%s: Error trying to start fw!\n", __func__);
+ return QLA_ERROR;
+ }
+
+ /* Handshake with the card before we register the devices. */
+ if (qla4_8xxx_cmdpeg_ready(ha, 0) != QLA_SUCCESS) {
+ printk("%s: Error during card handshake!\n", __func__);
+ return QLA_ERROR;
+ }
+
+ /* Negotiated Link width */
+ pcie_cap = pci_find_capability(ha->pdev, PCI_CAP_ID_EXP);
+ pci_read_config_word(ha->pdev, pcie_cap + PCI_EXP_LNKSTA, &lnk);
+ ha->link_width = (lnk >> 4) & 0x3f;
+
+ /* Synchronize with Receive peg */
+ return qla4_8xxx_rcvpeg_ready(ha);
+}
+
+static int
+qla4_8xxx_try_start_fw(struct scsi_qla_host *ha)
+{
+ int rval = QLA_ERROR;
+
+ /*
+ * FW Load priority:
+ * 1) Operational firmware residing in flash.
+ * 2) Fail
+ */
+
+ ql4_printk(KERN_INFO, ha,
+ "FW: Retrieving flash offsets from FLT/FDT ...\n");
+ rval = qla4_8xxx_get_flash_info(ha);
+ if (rval != QLA_SUCCESS)
+ return rval;
+
+ ql4_printk(KERN_INFO, ha,
+ "FW: Attempting to load firmware from flash...\n");
+ rval = qla4_8xxx_start_firmware(ha, ha->hw.flt_region_fw);
+ if (rval == QLA_SUCCESS)
+ return rval;
+
+ ql4_printk(KERN_ERR, ha, "FW: Load firmware from flash FAILED...\n");
+
+ return rval;
+}
+
+/**
+ * qla4_8xxx_device_bootstrap - Initialize device, set DEV_READY, start fw
+ * @ha: pointer to adapter structure
+ *
+ * Note: IDC lock must be held upon entry
+ **/
+static int
+qla4_8xxx_device_bootstrap(struct scsi_qla_host *ha)
+{
+ int rval, i, timeout;
+ uint32_t old_count, count;
+
+ if (qla4_8xxx_need_reset(ha))
+ goto dev_initialize;
+
+ old_count = qla4_8xxx_rd_32(ha, QLA82XX_PEG_ALIVE_COUNTER);
+
+ for (i = 0; i < 10; i++) {
+ timeout = msleep_interruptible(200);
+ if (timeout) {
+ qla4_8xxx_wr_32(ha, QLA82XX_CRB_DEV_STATE,
+ QLA82XX_DEV_FAILED);
+ return QLA_ERROR;
+ }
+
+ count = qla4_8xxx_rd_32(ha, QLA82XX_PEG_ALIVE_COUNTER);
+ if (count != old_count)
+ goto dev_ready;
+ }
+
+dev_initialize:
+ /* set to DEV_INITIALIZING */
+ ql4_printk(KERN_INFO, ha, "HW State: INITIALIZING\n");
+ qla4_8xxx_wr_32(ha, QLA82XX_CRB_DEV_STATE, QLA82XX_DEV_INITIALIZING);
+
+ /* Driver that sets device state to initializating sets IDC version */
+ qla4_8xxx_wr_32(ha, QLA82XX_CRB_DRV_IDC_VERSION, QLA82XX_IDC_VERSION);
+
+ qla4_8xxx_idc_unlock(ha);
+ rval = qla4_8xxx_try_start_fw(ha);
+ qla4_8xxx_idc_lock(ha);
+
+ if (rval != QLA_SUCCESS) {
+ ql4_printk(KERN_INFO, ha, "HW State: FAILED\n");
+ qla4_8xxx_clear_drv_active(ha);
+ qla4_8xxx_wr_32(ha, QLA82XX_CRB_DEV_STATE, QLA82XX_DEV_FAILED);
+ return rval;
+ }
+
+dev_ready:
+ ql4_printk(KERN_INFO, ha, "HW State: READY\n");
+ qla4_8xxx_wr_32(ha, QLA82XX_CRB_DEV_STATE, QLA82XX_DEV_READY);
+
+ return QLA_SUCCESS;
+}
+
+/**
+ * qla4_8xxx_need_reset_handler - Code to start reset sequence
+ * @ha: pointer to adapter structure
+ *
+ * Note: IDC lock must be held upon entry
+ **/
+static void
+qla4_8xxx_need_reset_handler(struct scsi_qla_host *ha)
+{
+ uint32_t dev_state, drv_state, drv_active;
+ unsigned long reset_timeout;
+
+ ql4_printk(KERN_INFO, ha,
+ "Performing ISP error recovery\n");
+
+ if (test_and_clear_bit(AF_ONLINE, &ha->flags)) {
+ qla4_8xxx_idc_unlock(ha);
+ ha->isp_ops->disable_intrs(ha);
+ qla4_8xxx_idc_lock(ha);
+ }
+
+ qla4_8xxx_set_rst_ready(ha);
+
+ /* wait for 10 seconds for reset ack from all functions */
+ reset_timeout = jiffies + (ha->nx_reset_timeout * HZ);
+
+ drv_state = qla4_8xxx_rd_32(ha, QLA82XX_CRB_DRV_STATE);
+ drv_active = qla4_8xxx_rd_32(ha, QLA82XX_CRB_DRV_ACTIVE);
+
+ ql4_printk(KERN_INFO, ha,
+ "%s(%ld): drv_state = 0x%x, drv_active = 0x%x\n",
+ __func__, ha->host_no, drv_state, drv_active);
+
+ while (drv_state != drv_active) {
+ if (time_after_eq(jiffies, reset_timeout)) {
+ printk("%s: RESET TIMEOUT!\n", DRIVER_NAME);
+ break;
+ }
+
+ qla4_8xxx_idc_unlock(ha);
+ msleep(1000);
+ qla4_8xxx_idc_lock(ha);
+
+ drv_state = qla4_8xxx_rd_32(ha, QLA82XX_CRB_DRV_STATE);
+ drv_active = qla4_8xxx_rd_32(ha, QLA82XX_CRB_DRV_ACTIVE);
+ }
+
+ dev_state = qla4_8xxx_rd_32(ha, QLA82XX_CRB_DEV_STATE);
+ ql4_printk(KERN_INFO, ha, "3:Device state is 0x%x = %s\n", dev_state,
+ dev_state < MAX_STATES ? qdev_state[dev_state] : "Unknown");
+
+ /* Force to DEV_COLD unless someone else is starting a reset */
+ if (dev_state != QLA82XX_DEV_INITIALIZING) {
+ ql4_printk(KERN_INFO, ha, "HW State: COLD/RE-INIT\n");
+ qla4_8xxx_wr_32(ha, QLA82XX_CRB_DEV_STATE, QLA82XX_DEV_COLD);
+ }
+}
+
+/**
+ * qla4_8xxx_need_qsnt_handler - Code to start qsnt
+ * @ha: pointer to adapter structure
+ **/
+void
+qla4_8xxx_need_qsnt_handler(struct scsi_qla_host *ha)
+{
+ qla4_8xxx_idc_lock(ha);
+ qla4_8xxx_set_qsnt_ready(ha);
+ qla4_8xxx_idc_unlock(ha);
+}
+
+/**
+ * qla4_8xxx_device_state_handler - Adapter state machine
+ * @ha: pointer to host adapter structure.
+ *
+ * Note: IDC lock must be UNLOCKED upon entry
+ **/
+int qla4_8xxx_device_state_handler(struct scsi_qla_host *ha)
+{
+ uint32_t dev_state;
+ int rval = QLA_SUCCESS;
+ unsigned long dev_init_timeout;
+
+ if (!test_bit(AF_INIT_DONE, &ha->flags))
+ qla4_8xxx_set_drv_active(ha);
+
+ dev_state = qla4_8xxx_rd_32(ha, QLA82XX_CRB_DEV_STATE);
+ ql4_printk(KERN_INFO, ha, "1:Device state is 0x%x = %s\n", dev_state,
+ dev_state < MAX_STATES ? qdev_state[dev_state] : "Unknown");
+
+ /* wait for 30 seconds for device to go ready */
+ dev_init_timeout = jiffies + (ha->nx_dev_init_timeout * HZ);
+
+ while (1) {
+ qla4_8xxx_idc_lock(ha);
+
+ if (time_after_eq(jiffies, dev_init_timeout)) {
+ ql4_printk(KERN_WARNING, ha, "Device init failed!\n");
+ qla4_8xxx_wr_32(ha, QLA82XX_CRB_DEV_STATE,
+ QLA82XX_DEV_FAILED);
+ }
+
+ dev_state = qla4_8xxx_rd_32(ha, QLA82XX_CRB_DEV_STATE);
+ ql4_printk(KERN_INFO, ha,
+ "2:Device state is 0x%x = %s\n", dev_state,
+ dev_state < MAX_STATES ? qdev_state[dev_state] : "Unknown");
+
+ /* NOTE: Make sure idc unlocked upon exit of switch statement */
+ switch (dev_state) {
+ case QLA82XX_DEV_READY:
+ qla4_8xxx_idc_unlock(ha);
+ goto exit;
+ case QLA82XX_DEV_COLD:
+ rval = qla4_8xxx_device_bootstrap(ha);
+ qla4_8xxx_idc_unlock(ha);
+ goto exit;
+ case QLA82XX_DEV_INITIALIZING:
+ qla4_8xxx_idc_unlock(ha);
+ msleep(1000);
+ break;
+ case QLA82XX_DEV_NEED_RESET:
+ if (!ql4xdontresethba) {
+ qla4_8xxx_need_reset_handler(ha);
+ /* Update timeout value after need
+ * reset handler */
+ dev_init_timeout = jiffies +
+ (ha->nx_dev_init_timeout * HZ);
+ }
+ qla4_8xxx_idc_unlock(ha);
+ break;
+ case QLA82XX_DEV_NEED_QUIESCENT:
+ qla4_8xxx_idc_unlock(ha);
+ /* idc locked/unlocked in handler */
+ qla4_8xxx_need_qsnt_handler(ha);
+ qla4_8xxx_idc_lock(ha);
+ /* fall thru needs idc_locked */
+ case QLA82XX_DEV_QUIESCENT:
+ qla4_8xxx_idc_unlock(ha);
+ msleep(1000);
+ break;
+ case QLA82XX_DEV_FAILED:
+ qla4_8xxx_idc_unlock(ha);
+ qla4xxx_dead_adapter_cleanup(ha);
+ rval = QLA_ERROR;
+ goto exit;
+ default:
+ qla4_8xxx_idc_unlock(ha);
+ qla4xxx_dead_adapter_cleanup(ha);
+ rval = QLA_ERROR;
+ goto exit;
+ }
+ }
+exit:
+ return rval;
+}
+
+int qla4_8xxx_load_risc(struct scsi_qla_host *ha)
+{
+ int retval;
+ retval = qla4_8xxx_device_state_handler(ha);
+
+ if (retval == QLA_SUCCESS &&
+ !test_bit(AF_INIT_DONE, &ha->flags)) {
+ retval = qla4xxx_request_irqs(ha);
+ if (retval != QLA_SUCCESS) {
+ ql4_printk(KERN_WARNING, ha,
+ "Failed to reserve interrupt %d already in use.\n",
+ ha->pdev->irq);
+ } else {
+ set_bit(AF_IRQ_ATTACHED, &ha->flags);
+ ha->host->irq = ha->pdev->irq;
+ ql4_printk(KERN_INFO, ha, "%s: irq %d attached\n",
+ __func__, ha->pdev->irq);
+ }
+ }
+ return retval;
+}
+
+/*****************************************************************************/
+/* Flash Manipulation Routines */
+/*****************************************************************************/
+
+#define OPTROM_BURST_SIZE 0x1000
+#define OPTROM_BURST_DWORDS (OPTROM_BURST_SIZE / 4)
+
+#define FARX_DATA_FLAG BIT_31
+#define FARX_ACCESS_FLASH_CONF 0x7FFD0000
+#define FARX_ACCESS_FLASH_DATA 0x7FF00000
+
+static inline uint32_t
+flash_conf_addr(struct ql82xx_hw_data *hw, uint32_t faddr)
+{
+ return hw->flash_conf_off | faddr;
+}
+
+static inline uint32_t
+flash_data_addr(struct ql82xx_hw_data *hw, uint32_t faddr)
+{
+ return hw->flash_data_off | faddr;
+}
+
+static uint32_t *
+qla4_8xxx_read_flash_data(struct scsi_qla_host *ha, uint32_t *dwptr,
+ uint32_t faddr, uint32_t length)
+{
+ uint32_t i;
+ uint32_t val;
+ int loops = 0;
+ while ((qla4_8xxx_rom_lock(ha) != 0) && (loops < 50000)) {
+ udelay(100);
+ cond_resched();
+ loops++;
+ }
+ if (loops >= 50000) {
+ ql4_printk(KERN_WARNING, ha, "ROM lock failed\n");
+ return dwptr;
+ }
+
+ /* Dword reads to flash. */
+ for (i = 0; i < length/4; i++, faddr += 4) {
+ if (qla4_8xxx_do_rom_fast_read(ha, faddr, &val)) {
+ ql4_printk(KERN_WARNING, ha,
+ "Do ROM fast read failed\n");
+ goto done_read;
+ }
+ dwptr[i] = __constant_cpu_to_le32(val);
+ }
+
+done_read:
+ qla4_8xxx_rom_unlock(ha);
+ return dwptr;
+}
+
+/**
+ * Address and length are byte address
+ **/
+static uint8_t *
+qla4_8xxx_read_optrom_data(struct scsi_qla_host *ha, uint8_t *buf,
+ uint32_t offset, uint32_t length)
+{
+ qla4_8xxx_read_flash_data(ha, (uint32_t *)buf, offset, length);
+ return buf;
+}
+
+static int
+qla4_8xxx_find_flt_start(struct scsi_qla_host *ha, uint32_t *start)
+{
+ const char *loc, *locations[] = { "DEF", "PCI" };
+
+ /*
+ * FLT-location structure resides after the last PCI region.
+ */
+
+ /* Begin with sane defaults. */
+ loc = locations[0];
+ *start = FA_FLASH_LAYOUT_ADDR_82;
+
+ DEBUG2(ql4_printk(KERN_INFO, ha, "FLTL[%s] = 0x%x.\n", loc, *start));
+ return QLA_SUCCESS;
+}
+
+static void
+qla4_8xxx_get_flt_info(struct scsi_qla_host *ha, uint32_t flt_addr)
+{
+ const char *loc, *locations[] = { "DEF", "FLT" };
+ uint16_t *wptr;
+ uint16_t cnt, chksum;
+ uint32_t start;
+ struct qla_flt_header *flt;
+ struct qla_flt_region *region;
+ struct ql82xx_hw_data *hw = &ha->hw;
+
+ hw->flt_region_flt = flt_addr;
+ wptr = (uint16_t *)ha->request_ring;
+ flt = (struct qla_flt_header *)ha->request_ring;
+ region = (struct qla_flt_region *)&flt[1];
+ qla4_8xxx_read_optrom_data(ha, (uint8_t *)ha->request_ring,
+ flt_addr << 2, OPTROM_BURST_SIZE);
+ if (*wptr == __constant_cpu_to_le16(0xffff))
+ goto no_flash_data;
+ if (flt->version != __constant_cpu_to_le16(1)) {
+ DEBUG2(ql4_printk(KERN_INFO, ha, "Unsupported FLT detected: "
+ "version=0x%x length=0x%x checksum=0x%x.\n",
+ le16_to_cpu(flt->version), le16_to_cpu(flt->length),
+ le16_to_cpu(flt->checksum)));
+ goto no_flash_data;
+ }
+
+ cnt = (sizeof(struct qla_flt_header) + le16_to_cpu(flt->length)) >> 1;
+ for (chksum = 0; cnt; cnt--)
+ chksum += le16_to_cpu(*wptr++);
+ if (chksum) {
+ DEBUG2(ql4_printk(KERN_INFO, ha, "Inconsistent FLT detected: "
+ "version=0x%x length=0x%x checksum=0x%x.\n",
+ le16_to_cpu(flt->version), le16_to_cpu(flt->length),
+ chksum));
+ goto no_flash_data;
+ }
+
+ loc = locations[1];
+ cnt = le16_to_cpu(flt->length) / sizeof(struct qla_flt_region);
+ for ( ; cnt; cnt--, region++) {
+ /* Store addresses as DWORD offsets. */
+ start = le32_to_cpu(region->start) >> 2;
+
+ DEBUG3(ql4_printk(KERN_DEBUG, ha, "FLT[%02x]: start=0x%x "
+ "end=0x%x size=0x%x.\n", le32_to_cpu(region->code), start,
+ le32_to_cpu(region->end) >> 2, le32_to_cpu(region->size)));
+
+ switch (le32_to_cpu(region->code) & 0xff) {
+ case FLT_REG_FDT:
+ hw->flt_region_fdt = start;
+ break;
+ case FLT_REG_BOOT_CODE_82:
+ hw->flt_region_boot = start;
+ break;
+ case FLT_REG_FW_82:
+ hw->flt_region_fw = start;
+ break;
+ case FLT_REG_BOOTLOAD_82:
+ hw->flt_region_bootload = start;
+ break;
+ }
+ }
+ goto done;
+
+no_flash_data:
+ /* Use hardcoded defaults. */
+ loc = locations[0];
+
+ hw->flt_region_fdt = FA_FLASH_DESCR_ADDR_82;
+ hw->flt_region_boot = FA_BOOT_CODE_ADDR_82;
+ hw->flt_region_bootload = FA_BOOT_LOAD_ADDR_82;
+ hw->flt_region_fw = FA_RISC_CODE_ADDR_82;
+done:
+ DEBUG2(ql4_printk(KERN_INFO, ha, "FLT[%s]: flt=0x%x fdt=0x%x "
+ "boot=0x%x bootload=0x%x fw=0x%x\n", loc, hw->flt_region_flt,
+ hw->flt_region_fdt, hw->flt_region_boot, hw->flt_region_bootload,
+ hw->flt_region_fw));
+}
+
+static void
+qla4_8xxx_get_fdt_info(struct scsi_qla_host *ha)
+{
+#define FLASH_BLK_SIZE_4K 0x1000
+#define FLASH_BLK_SIZE_32K 0x8000
+#define FLASH_BLK_SIZE_64K 0x10000
+ const char *loc, *locations[] = { "MID", "FDT" };
+ uint16_t cnt, chksum;
+ uint16_t *wptr;
+ struct qla_fdt_layout *fdt;
+ uint16_t mid, fid;
+ struct ql82xx_hw_data *hw = &ha->hw;
+
+ hw->flash_conf_off = FARX_ACCESS_FLASH_CONF;
+ hw->flash_data_off = FARX_ACCESS_FLASH_DATA;
+
+ wptr = (uint16_t *)ha->request_ring;
+ fdt = (struct qla_fdt_layout *)ha->request_ring;
+ qla4_8xxx_read_optrom_data(ha, (uint8_t *)ha->request_ring,
+ hw->flt_region_fdt << 2, OPTROM_BURST_SIZE);
+
+ if (*wptr == __constant_cpu_to_le16(0xffff))
+ goto no_flash_data;
+
+ if (fdt->sig[0] != 'Q' || fdt->sig[1] != 'L' || fdt->sig[2] != 'I' ||
+ fdt->sig[3] != 'D')
+ goto no_flash_data;
+
+ for (cnt = 0, chksum = 0; cnt < sizeof(struct qla_fdt_layout) >> 1;
+ cnt++)
+ chksum += le16_to_cpu(*wptr++);
+
+ if (chksum) {
+ DEBUG2(ql4_printk(KERN_INFO, ha, "Inconsistent FDT detected: "
+ "checksum=0x%x id=%c version=0x%x.\n", chksum, fdt->sig[0],
+ le16_to_cpu(fdt->version)));
+ goto no_flash_data;
+ }
+
+ loc = locations[1];
+ mid = le16_to_cpu(fdt->man_id);
+ fid = le16_to_cpu(fdt->id);
+ hw->fdt_wrt_disable = fdt->wrt_disable_bits;
+ hw->fdt_erase_cmd = flash_conf_addr(hw, 0x0300 | fdt->erase_cmd);
+ hw->fdt_block_size = le32_to_cpu(fdt->block_size);
+
+ if (fdt->unprotect_sec_cmd) {
+ hw->fdt_unprotect_sec_cmd = flash_conf_addr(hw, 0x0300 |
+ fdt->unprotect_sec_cmd);
+ hw->fdt_protect_sec_cmd = fdt->protect_sec_cmd ?
+ flash_conf_addr(hw, 0x0300 | fdt->protect_sec_cmd) :
+ flash_conf_addr(hw, 0x0336);
+ }
+ goto done;
+
+no_flash_data:
+ loc = locations[0];
+ hw->fdt_block_size = FLASH_BLK_SIZE_64K;
+done:
+ DEBUG2(ql4_printk(KERN_INFO, ha, "FDT[%s]: (0x%x/0x%x) erase=0x%x "
+ "pro=%x upro=%x wrtd=0x%x blk=0x%x.\n", loc, mid, fid,
+ hw->fdt_erase_cmd, hw->fdt_protect_sec_cmd,
+ hw->fdt_unprotect_sec_cmd, hw->fdt_wrt_disable,
+ hw->fdt_block_size));
+}
+
+static void
+qla4_8xxx_get_idc_param(struct scsi_qla_host *ha)
+{
+#define QLA82XX_IDC_PARAM_ADDR 0x003e885c
+ uint32_t *wptr;
+
+ if (!is_qla8022(ha))
+ return;
+ wptr = (uint32_t *)ha->request_ring;
+ qla4_8xxx_read_optrom_data(ha, (uint8_t *)ha->request_ring,
+ QLA82XX_IDC_PARAM_ADDR , 8);
+
+ if (*wptr == __constant_cpu_to_le32(0xffffffff)) {
+ ha->nx_dev_init_timeout = ROM_DEV_INIT_TIMEOUT;
+ ha->nx_reset_timeout = ROM_DRV_RESET_ACK_TIMEOUT;
+ } else {
+ ha->nx_dev_init_timeout = le32_to_cpu(*wptr++);
+ ha->nx_reset_timeout = le32_to_cpu(*wptr);
+ }
+
+ DEBUG2(ql4_printk(KERN_DEBUG, ha,
+ "ha->nx_dev_init_timeout = %d\n", ha->nx_dev_init_timeout));
+ DEBUG2(ql4_printk(KERN_DEBUG, ha,
+ "ha->nx_reset_timeout = %d\n", ha->nx_reset_timeout));
+ return;
+}
+
+int
+qla4_8xxx_get_flash_info(struct scsi_qla_host *ha)
+{
+ int ret;
+ uint32_t flt_addr;
+
+ ret = qla4_8xxx_find_flt_start(ha, &flt_addr);
+ if (ret != QLA_SUCCESS)
+ return ret;
+
+ qla4_8xxx_get_flt_info(ha, flt_addr);
+ qla4_8xxx_get_fdt_info(ha);
+ qla4_8xxx_get_idc_param(ha);
+
+ return QLA_SUCCESS;
+}
+
+/**
+ * qla4_8xxx_stop_firmware - stops firmware on specified adapter instance
+ * @ha: pointer to host adapter structure.
+ *
+ * Remarks:
+ * For iSCSI, throws away all I/O and AENs into bit bucket, so they will
+ * not be available after successful return. Driver must cleanup potential
+ * outstanding I/O's after calling this funcion.
+ **/
+int
+qla4_8xxx_stop_firmware(struct scsi_qla_host *ha)
+{
+ int status;
+ 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_STOP_FW;
+ status = qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 1,
+ &mbox_cmd[0], &mbox_sts[0]);
+
+ DEBUG2(printk("scsi%ld: %s: status = %d\n", ha->host_no,
+ __func__, status));
+ return status;
+}
+
+/**
+ * qla4_8xxx_isp_reset - Resets ISP and aborts all outstanding commands.
+ * @ha: pointer to host adapter structure.
+ **/
+int
+qla4_8xxx_isp_reset(struct scsi_qla_host *ha)
+{
+ int rval;
+ uint32_t dev_state;
+
+ qla4_8xxx_idc_lock(ha);
+ dev_state = qla4_8xxx_rd_32(ha, QLA82XX_CRB_DEV_STATE);
+
+ if (dev_state == QLA82XX_DEV_READY) {
+ ql4_printk(KERN_INFO, ha, "HW State: NEED RESET\n");
+ qla4_8xxx_wr_32(ha, QLA82XX_CRB_DEV_STATE,
+ QLA82XX_DEV_NEED_RESET);
+ } else
+ ql4_printk(KERN_INFO, ha, "HW State: DEVICE INITIALIZING\n");
+
+ qla4_8xxx_idc_unlock(ha);
+
+ rval = qla4_8xxx_device_state_handler(ha);
+
+ qla4_8xxx_idc_lock(ha);
+ qla4_8xxx_clear_rst_ready(ha);
+ qla4_8xxx_idc_unlock(ha);
+
+ return rval;
+}
+
+/**
+ * qla4_8xxx_get_sys_info - get adapter MAC address(es) and serial number
+ * @ha: pointer to host adapter structure.
+ *
+ **/
+int qla4_8xxx_get_sys_info(struct scsi_qla_host *ha)
+{
+ uint32_t mbox_cmd[MBOX_REG_COUNT];
+ uint32_t mbox_sts[MBOX_REG_COUNT];
+ struct mbx_sys_info *sys_info;
+ dma_addr_t sys_info_dma;
+ int status = QLA_ERROR;
+
+ sys_info = dma_alloc_coherent(&ha->pdev->dev, sizeof(*sys_info),
+ &sys_info_dma, GFP_KERNEL);
+ if (sys_info == NULL) {
+ DEBUG2(printk("scsi%ld: %s: Unable to allocate dma buffer.\n",
+ ha->host_no, __func__));
+ return status;
+ }
+
+ memset(sys_info, 0, sizeof(*sys_info));
+ memset(&mbox_cmd, 0, sizeof(mbox_cmd));
+ memset(&mbox_sts, 0, sizeof(mbox_sts));
+
+ mbox_cmd[0] = MBOX_CMD_GET_SYS_INFO;
+ mbox_cmd[1] = LSDW(sys_info_dma);
+ mbox_cmd[2] = MSDW(sys_info_dma);
+ mbox_cmd[4] = sizeof(*sys_info);
+
+ if (qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 6, &mbox_cmd[0],
+ &mbox_sts[0]) != QLA_SUCCESS) {
+ DEBUG2(printk("scsi%ld: %s: GET_SYS_INFO failed\n",
+ ha->host_no, __func__));
+ goto exit_validate_mac82;
+ }
+
+ if (mbox_sts[4] < sizeof(*sys_info)) {
+ DEBUG2(printk("scsi%ld: %s: GET_SYS_INFO data receive"
+ " error (%x)\n", ha->host_no, __func__, mbox_sts[4]));
+ goto exit_validate_mac82;
+
+ }
+
+ /* Save M.A.C. address & serial_number */
+ memcpy(ha->my_mac, &sys_info->mac_addr[0],
+ min(sizeof(ha->my_mac), sizeof(sys_info->mac_addr)));
+ memcpy(ha->serial_number, &sys_info->serial_number,
+ min(sizeof(ha->serial_number), sizeof(sys_info->serial_number)));
+
+ DEBUG2(printk("scsi%ld: %s: "
+ "mac %02x:%02x:%02x:%02x:%02x:%02x "
+ "serial %s\n", ha->host_no, __func__,
+ ha->my_mac[0], ha->my_mac[1], ha->my_mac[2],
+ ha->my_mac[3], ha->my_mac[4], ha->my_mac[5],
+ ha->serial_number));
+
+ status = QLA_SUCCESS;
+
+exit_validate_mac82:
+ dma_free_coherent(&ha->pdev->dev, sizeof(*sys_info), sys_info,
+ sys_info_dma);
+ return status;
+}
+
+/* Interrupt handling helpers. */
+
+static int
+qla4_8xxx_mbx_intr_enable(struct scsi_qla_host *ha)
+{
+ uint32_t mbox_cmd[MBOX_REG_COUNT];
+ uint32_t mbox_sts[MBOX_REG_COUNT];
+
+ DEBUG2(ql4_printk(KERN_INFO, ha, "%s\n", __func__));
+
+ memset(&mbox_cmd, 0, sizeof(mbox_cmd));
+ memset(&mbox_sts, 0, sizeof(mbox_sts));
+ mbox_cmd[0] = MBOX_CMD_ENABLE_INTRS;
+ mbox_cmd[1] = INTR_ENABLE;
+ if (qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 1, &mbox_cmd[0],
+ &mbox_sts[0]) != QLA_SUCCESS) {
+ DEBUG2(ql4_printk(KERN_INFO, ha,
+ "%s: MBOX_CMD_ENABLE_INTRS failed (0x%04x)\n",
+ __func__, mbox_sts[0]));
+ return QLA_ERROR;
+ }
+ return QLA_SUCCESS;
+}
+
+static int
+qla4_8xxx_mbx_intr_disable(struct scsi_qla_host *ha)
+{
+ uint32_t mbox_cmd[MBOX_REG_COUNT];
+ uint32_t mbox_sts[MBOX_REG_COUNT];
+
+ DEBUG2(ql4_printk(KERN_INFO, ha, "%s\n", __func__));
+
+ memset(&mbox_cmd, 0, sizeof(mbox_cmd));
+ memset(&mbox_sts, 0, sizeof(mbox_sts));
+ mbox_cmd[0] = MBOX_CMD_ENABLE_INTRS;
+ mbox_cmd[1] = INTR_DISABLE;
+ if (qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 1, &mbox_cmd[0],
+ &mbox_sts[0]) != QLA_SUCCESS) {
+ DEBUG2(ql4_printk(KERN_INFO, ha,
+ "%s: MBOX_CMD_ENABLE_INTRS failed (0x%04x)\n",
+ __func__, mbox_sts[0]));
+ return QLA_ERROR;
+ }
+
+ return QLA_SUCCESS;
+}
+
+void
+qla4_8xxx_enable_intrs(struct scsi_qla_host *ha)
+{
+ qla4_8xxx_mbx_intr_enable(ha);
+
+ spin_lock_irq(&ha->hardware_lock);
+ /* BIT 10 - reset */
+ qla4_8xxx_wr_32(ha, ha->nx_legacy_intr.tgt_mask_reg, 0xfbff);
+ spin_unlock_irq(&ha->hardware_lock);
+ set_bit(AF_INTERRUPTS_ON, &ha->flags);
+}
+
+void
+qla4_8xxx_disable_intrs(struct scsi_qla_host *ha)
+{
+ if (test_bit(AF_INTERRUPTS_ON, &ha->flags))
+ qla4_8xxx_mbx_intr_disable(ha);
+
+ spin_lock_irq(&ha->hardware_lock);
+ /* BIT 10 - set */
+ qla4_8xxx_wr_32(ha, ha->nx_legacy_intr.tgt_mask_reg, 0x0400);
+ spin_unlock_irq(&ha->hardware_lock);
+ clear_bit(AF_INTERRUPTS_ON, &ha->flags);
+}
+
+struct ql4_init_msix_entry {
+ uint16_t entry;
+ uint16_t index;
+ const char *name;
+ irq_handler_t handler;
+};
+
+static struct ql4_init_msix_entry qla4_8xxx_msix_entries[QLA_MSIX_ENTRIES] = {
+ { QLA_MSIX_DEFAULT, QLA_MIDX_DEFAULT,
+ "qla4xxx (default)",
+ (irq_handler_t)qla4_8xxx_default_intr_handler },
+ { QLA_MSIX_RSP_Q, QLA_MIDX_RSP_Q,
+ "qla4xxx (rsp_q)", (irq_handler_t)qla4_8xxx_msix_rsp_q },
+};
+
+void
+qla4_8xxx_disable_msix(struct scsi_qla_host *ha)
+{
+ int i;
+ struct ql4_msix_entry *qentry;
+
+ for (i = 0; i < QLA_MSIX_ENTRIES; i++) {
+ qentry = &ha->msix_entries[qla4_8xxx_msix_entries[i].index];
+ if (qentry->have_irq) {
+ free_irq(qentry->msix_vector, ha);
+ DEBUG2(ql4_printk(KERN_INFO, ha, "%s: %s\n",
+ __func__, qla4_8xxx_msix_entries[i].name));
+ }
+ }
+ pci_disable_msix(ha->pdev);
+ clear_bit(AF_MSIX_ENABLED, &ha->flags);
+}
+
+int
+qla4_8xxx_enable_msix(struct scsi_qla_host *ha)
+{
+ int i, ret;
+ struct msix_entry entries[QLA_MSIX_ENTRIES];
+ struct ql4_msix_entry *qentry;
+
+ for (i = 0; i < QLA_MSIX_ENTRIES; i++)
+ entries[i].entry = qla4_8xxx_msix_entries[i].entry;
+
+ ret = pci_enable_msix(ha->pdev, entries, ARRAY_SIZE(entries));
+ if (ret) {
+ ql4_printk(KERN_WARNING, ha,
+ "MSI-X: Failed to enable support -- %d/%d\n",
+ QLA_MSIX_ENTRIES, ret);
+ goto msix_out;
+ }
+ set_bit(AF_MSIX_ENABLED, &ha->flags);
+
+ for (i = 0; i < QLA_MSIX_ENTRIES; i++) {
+ qentry = &ha->msix_entries[qla4_8xxx_msix_entries[i].index];
+ qentry->msix_vector = entries[i].vector;
+ qentry->msix_entry = entries[i].entry;
+ qentry->have_irq = 0;
+ ret = request_irq(qentry->msix_vector,
+ qla4_8xxx_msix_entries[i].handler, 0,
+ qla4_8xxx_msix_entries[i].name, ha);
+ if (ret) {
+ ql4_printk(KERN_WARNING, ha,
+ "MSI-X: Unable to register handler -- %x/%d.\n",
+ qla4_8xxx_msix_entries[i].index, ret);
+ qla4_8xxx_disable_msix(ha);
+ goto msix_out;
+ }
+ qentry->have_irq = 1;
+ DEBUG2(ql4_printk(KERN_INFO, ha, "%s: %s\n",
+ __func__, qla4_8xxx_msix_entries[i].name));
+ }
+msix_out:
+ return ret;
+}
diff --git a/drivers/scsi/qla4xxx/ql4_nx.h b/drivers/scsi/qla4xxx/ql4_nx.h
new file mode 100644
index 00000000000..931ad3f1e91
--- /dev/null
+++ b/drivers/scsi/qla4xxx/ql4_nx.h
@@ -0,0 +1,779 @@
+/*
+ * QLogic Fibre Channel HBA Driver
+ * Copyright (c) 2003-2008 QLogic Corporation
+ *
+ * See LICENSE.qla2xxx for copyright and licensing details.
+ */
+#ifndef __QLA_NX_H
+#define __QLA_NX_H
+
+/*
+ * Following are the states of the Phantom. Phantom will set them and
+ * Host will read to check if the fields are correct.
+*/
+#define PHAN_INITIALIZE_FAILED 0xffff
+#define PHAN_INITIALIZE_COMPLETE 0xff01
+
+/* Host writes the following to notify that it has done the init-handshake */
+#define PHAN_INITIALIZE_ACK 0xf00f
+#define PHAN_PEG_RCV_INITIALIZED 0xff01
+
+/*CRB_RELATED*/
+#define QLA82XX_CRB_BASE QLA82XX_CAM_RAM(0x200)
+#define QLA82XX_REG(X) (QLA82XX_CRB_BASE+(X))
+
+#define CRB_CMDPEG_STATE QLA82XX_REG(0x50)
+#define CRB_RCVPEG_STATE QLA82XX_REG(0x13c)
+#define BOOT_LOADER_DIMM_STATUS QLA82XX_REG(0x54)
+#define CRB_DMA_SHIFT QLA82XX_REG(0xcc)
+
+#define QLA82XX_HW_H0_CH_HUB_ADR 0x05
+#define QLA82XX_HW_H1_CH_HUB_ADR 0x0E
+#define QLA82XX_HW_H2_CH_HUB_ADR 0x03
+#define QLA82XX_HW_H3_CH_HUB_ADR 0x01
+#define QLA82XX_HW_H4_CH_HUB_ADR 0x06
+#define QLA82XX_HW_H5_CH_HUB_ADR 0x07
+#define QLA82XX_HW_H6_CH_HUB_ADR 0x08
+
+/* Hub 0 */
+#define QLA82XX_HW_MN_CRB_AGT_ADR 0x15
+#define QLA82XX_HW_MS_CRB_AGT_ADR 0x25
+
+/* Hub 1 */
+#define QLA82XX_HW_PS_CRB_AGT_ADR 0x73
+#define QLA82XX_HW_QMS_CRB_AGT_ADR 0x00
+#define QLA82XX_HW_RPMX3_CRB_AGT_ADR 0x0b
+#define QLA82XX_HW_SQGS0_CRB_AGT_ADR 0x01
+#define QLA82XX_HW_SQGS1_CRB_AGT_ADR 0x02
+#define QLA82XX_HW_SQGS2_CRB_AGT_ADR 0x03
+#define QLA82XX_HW_SQGS3_CRB_AGT_ADR 0x04
+#define QLA82XX_HW_C2C0_CRB_AGT_ADR 0x58
+#define QLA82XX_HW_C2C1_CRB_AGT_ADR 0x59
+#define QLA82XX_HW_C2C2_CRB_AGT_ADR 0x5a
+#define QLA82XX_HW_RPMX2_CRB_AGT_ADR 0x0a
+#define QLA82XX_HW_RPMX4_CRB_AGT_ADR 0x0c
+#define QLA82XX_HW_RPMX7_CRB_AGT_ADR 0x0f
+#define QLA82XX_HW_RPMX9_CRB_AGT_ADR 0x12
+#define QLA82XX_HW_SMB_CRB_AGT_ADR 0x18
+
+/* Hub 2 */
+#define QLA82XX_HW_NIU_CRB_AGT_ADR 0x31
+#define QLA82XX_HW_I2C0_CRB_AGT_ADR 0x19
+#define QLA82XX_HW_I2C1_CRB_AGT_ADR 0x29
+
+#define QLA82XX_HW_SN_CRB_AGT_ADR 0x10
+#define QLA82XX_HW_I2Q_CRB_AGT_ADR 0x20
+#define QLA82XX_HW_LPC_CRB_AGT_ADR 0x22
+#define QLA82XX_HW_ROMUSB_CRB_AGT_ADR 0x21
+#define QLA82XX_HW_QM_CRB_AGT_ADR 0x66
+#define QLA82XX_HW_SQG0_CRB_AGT_ADR 0x60
+#define QLA82XX_HW_SQG1_CRB_AGT_ADR 0x61
+#define QLA82XX_HW_SQG2_CRB_AGT_ADR 0x62
+#define QLA82XX_HW_SQG3_CRB_AGT_ADR 0x63
+#define QLA82XX_HW_RPMX1_CRB_AGT_ADR 0x09
+#define QLA82XX_HW_RPMX5_CRB_AGT_ADR 0x0d
+#define QLA82XX_HW_RPMX6_CRB_AGT_ADR 0x0e
+#define QLA82XX_HW_RPMX8_CRB_AGT_ADR 0x11
+
+/* Hub 3 */
+#define QLA82XX_HW_PH_CRB_AGT_ADR 0x1A
+#define QLA82XX_HW_SRE_CRB_AGT_ADR 0x50
+#define QLA82XX_HW_EG_CRB_AGT_ADR 0x51
+#define QLA82XX_HW_RPMX0_CRB_AGT_ADR 0x08
+
+/* Hub 4 */
+#define QLA82XX_HW_PEGN0_CRB_AGT_ADR 0x40
+#define QLA82XX_HW_PEGN1_CRB_AGT_ADR 0x41
+#define QLA82XX_HW_PEGN2_CRB_AGT_ADR 0x42
+#define QLA82XX_HW_PEGN3_CRB_AGT_ADR 0x43
+#define QLA82XX_HW_PEGNI_CRB_AGT_ADR 0x44
+#define QLA82XX_HW_PEGND_CRB_AGT_ADR 0x45
+#define QLA82XX_HW_PEGNC_CRB_AGT_ADR 0x46
+#define QLA82XX_HW_PEGR0_CRB_AGT_ADR 0x47
+#define QLA82XX_HW_PEGR1_CRB_AGT_ADR 0x48
+#define QLA82XX_HW_PEGR2_CRB_AGT_ADR 0x49
+#define QLA82XX_HW_PEGR3_CRB_AGT_ADR 0x4a
+#define QLA82XX_HW_PEGN4_CRB_AGT_ADR 0x4b
+
+/* Hub 5 */
+#define QLA82XX_HW_PEGS0_CRB_AGT_ADR 0x40
+#define QLA82XX_HW_PEGS1_CRB_AGT_ADR 0x41
+#define QLA82XX_HW_PEGS2_CRB_AGT_ADR 0x42
+#define QLA82XX_HW_PEGS3_CRB_AGT_ADR 0x43
+
+#define QLA82XX_HW_PEGSI_CRB_AGT_ADR 0x44
+#define QLA82XX_HW_PEGSD_CRB_AGT_ADR 0x45
+#define QLA82XX_HW_PEGSC_CRB_AGT_ADR 0x46
+
+/* Hub 6 */
+#define QLA82XX_HW_CAS0_CRB_AGT_ADR 0x46
+#define QLA82XX_HW_CAS1_CRB_AGT_ADR 0x47
+#define QLA82XX_HW_CAS2_CRB_AGT_ADR 0x48
+#define QLA82XX_HW_CAS3_CRB_AGT_ADR 0x49
+#define QLA82XX_HW_NCM_CRB_AGT_ADR 0x16
+#define QLA82XX_HW_TMR_CRB_AGT_ADR 0x17
+#define QLA82XX_HW_XDMA_CRB_AGT_ADR 0x05
+#define QLA82XX_HW_OCM0_CRB_AGT_ADR 0x06
+#define QLA82XX_HW_OCM1_CRB_AGT_ADR 0x07
+
+/* This field defines PCI/X adr [25:20] of agents on the CRB */
+/* */
+#define QLA82XX_HW_PX_MAP_CRB_PH 0
+#define QLA82XX_HW_PX_MAP_CRB_PS 1
+#define QLA82XX_HW_PX_MAP_CRB_MN 2
+#define QLA82XX_HW_PX_MAP_CRB_MS 3
+#define QLA82XX_HW_PX_MAP_CRB_SRE 5
+#define QLA82XX_HW_PX_MAP_CRB_NIU 6
+#define QLA82XX_HW_PX_MAP_CRB_QMN 7
+#define QLA82XX_HW_PX_MAP_CRB_SQN0 8
+#define QLA82XX_HW_PX_MAP_CRB_SQN1 9
+#define QLA82XX_HW_PX_MAP_CRB_SQN2 10
+#define QLA82XX_HW_PX_MAP_CRB_SQN3 11
+#define QLA82XX_HW_PX_MAP_CRB_QMS 12
+#define QLA82XX_HW_PX_MAP_CRB_SQS0 13
+#define QLA82XX_HW_PX_MAP_CRB_SQS1 14
+#define QLA82XX_HW_PX_MAP_CRB_SQS2 15
+#define QLA82XX_HW_PX_MAP_CRB_SQS3 16
+#define QLA82XX_HW_PX_MAP_CRB_PGN0 17
+#define QLA82XX_HW_PX_MAP_CRB_PGN1 18
+#define QLA82XX_HW_PX_MAP_CRB_PGN2 19
+#define QLA82XX_HW_PX_MAP_CRB_PGN3 20
+#define QLA82XX_HW_PX_MAP_CRB_PGN4 QLA82XX_HW_PX_MAP_CRB_SQS2
+#define QLA82XX_HW_PX_MAP_CRB_PGND 21
+#define QLA82XX_HW_PX_MAP_CRB_PGNI 22
+#define QLA82XX_HW_PX_MAP_CRB_PGS0 23
+#define QLA82XX_HW_PX_MAP_CRB_PGS1 24
+#define QLA82XX_HW_PX_MAP_CRB_PGS2 25
+#define QLA82XX_HW_PX_MAP_CRB_PGS3 26
+#define QLA82XX_HW_PX_MAP_CRB_PGSD 27
+#define QLA82XX_HW_PX_MAP_CRB_PGSI 28
+#define QLA82XX_HW_PX_MAP_CRB_SN 29
+#define QLA82XX_HW_PX_MAP_CRB_EG 31
+#define QLA82XX_HW_PX_MAP_CRB_PH2 32
+#define QLA82XX_HW_PX_MAP_CRB_PS2 33
+#define QLA82XX_HW_PX_MAP_CRB_CAM 34
+#define QLA82XX_HW_PX_MAP_CRB_CAS0 35
+#define QLA82XX_HW_PX_MAP_CRB_CAS1 36
+#define QLA82XX_HW_PX_MAP_CRB_CAS2 37
+#define QLA82XX_HW_PX_MAP_CRB_C2C0 38
+#define QLA82XX_HW_PX_MAP_CRB_C2C1 39
+#define QLA82XX_HW_PX_MAP_CRB_TIMR 40
+#define QLA82XX_HW_PX_MAP_CRB_RPMX1 42
+#define QLA82XX_HW_PX_MAP_CRB_RPMX2 43
+#define QLA82XX_HW_PX_MAP_CRB_RPMX3 44
+#define QLA82XX_HW_PX_MAP_CRB_RPMX4 45
+#define QLA82XX_HW_PX_MAP_CRB_RPMX5 46
+#define QLA82XX_HW_PX_MAP_CRB_RPMX6 47
+#define QLA82XX_HW_PX_MAP_CRB_RPMX7 48
+#define QLA82XX_HW_PX_MAP_CRB_XDMA 49
+#define QLA82XX_HW_PX_MAP_CRB_I2Q 50
+#define QLA82XX_HW_PX_MAP_CRB_ROMUSB 51
+#define QLA82XX_HW_PX_MAP_CRB_CAS3 52
+#define QLA82XX_HW_PX_MAP_CRB_RPMX0 53
+#define QLA82XX_HW_PX_MAP_CRB_RPMX8 54
+#define QLA82XX_HW_PX_MAP_CRB_RPMX9 55
+#define QLA82XX_HW_PX_MAP_CRB_OCM0 56
+#define QLA82XX_HW_PX_MAP_CRB_OCM1 57
+#define QLA82XX_HW_PX_MAP_CRB_SMB 58
+#define QLA82XX_HW_PX_MAP_CRB_I2C0 59
+#define QLA82XX_HW_PX_MAP_CRB_I2C1 60
+#define QLA82XX_HW_PX_MAP_CRB_LPC 61
+#define QLA82XX_HW_PX_MAP_CRB_PGNC 62
+#define QLA82XX_HW_PX_MAP_CRB_PGR0 63
+#define QLA82XX_HW_PX_MAP_CRB_PGR1 4
+#define QLA82XX_HW_PX_MAP_CRB_PGR2 30
+#define QLA82XX_HW_PX_MAP_CRB_PGR3 41
+
+/* This field defines CRB adr [31:20] of the agents */
+/* */
+
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_MN ((QLA82XX_HW_H0_CH_HUB_ADR << 7) | \
+ QLA82XX_HW_MN_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_PH ((QLA82XX_HW_H0_CH_HUB_ADR << 7) | \
+ QLA82XX_HW_PH_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_MS ((QLA82XX_HW_H0_CH_HUB_ADR << 7) | \
+ QLA82XX_HW_MS_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_PS ((QLA82XX_HW_H1_CH_HUB_ADR << 7) | \
+ QLA82XX_HW_PS_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_SS ((QLA82XX_HW_H1_CH_HUB_ADR << 7) | \
+ QLA82XX_HW_SS_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX3 ((QLA82XX_HW_H1_CH_HUB_ADR << 7) | \
+ QLA82XX_HW_RPMX3_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_QMS ((QLA82XX_HW_H1_CH_HUB_ADR << 7) | \
+ QLA82XX_HW_QMS_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_SQS0 ((QLA82XX_HW_H1_CH_HUB_ADR << 7) | \
+ QLA82XX_HW_SQGS0_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_SQS1 ((QLA82XX_HW_H1_CH_HUB_ADR << 7) | \
+ QLA82XX_HW_SQGS1_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_SQS2 ((QLA82XX_HW_H1_CH_HUB_ADR << 7) | \
+ QLA82XX_HW_SQGS2_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_SQS3 ((QLA82XX_HW_H1_CH_HUB_ADR << 7) | \
+ QLA82XX_HW_SQGS3_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_C2C0 ((QLA82XX_HW_H1_CH_HUB_ADR << 7) | \
+ QLA82XX_HW_C2C0_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_C2C1 ((QLA82XX_HW_H1_CH_HUB_ADR << 7) | \
+ QLA82XX_HW_C2C1_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX2 ((QLA82XX_HW_H1_CH_HUB_ADR << 7) | \
+ QLA82XX_HW_RPMX2_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX4 ((QLA82XX_HW_H1_CH_HUB_ADR << 7) | \
+ QLA82XX_HW_RPMX4_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX7 ((QLA82XX_HW_H1_CH_HUB_ADR << 7) | \
+ QLA82XX_HW_RPMX7_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX9 ((QLA82XX_HW_H1_CH_HUB_ADR << 7) | \
+ QLA82XX_HW_RPMX9_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_SMB ((QLA82XX_HW_H1_CH_HUB_ADR << 7) | \
+ QLA82XX_HW_SMB_CRB_AGT_ADR)
+
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_NIU ((QLA82XX_HW_H2_CH_HUB_ADR << 7) | \
+ QLA82XX_HW_NIU_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_I2C0 ((QLA82XX_HW_H2_CH_HUB_ADR << 7) | \
+ QLA82XX_HW_I2C0_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_I2C1 ((QLA82XX_HW_H2_CH_HUB_ADR << 7) | \
+ QLA82XX_HW_I2C1_CRB_AGT_ADR)
+
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_SRE ((QLA82XX_HW_H3_CH_HUB_ADR << 7) | \
+ QLA82XX_HW_SRE_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_EG ((QLA82XX_HW_H3_CH_HUB_ADR << 7) | \
+ QLA82XX_HW_EG_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX0 ((QLA82XX_HW_H3_CH_HUB_ADR << 7) | \
+ QLA82XX_HW_RPMX0_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_QMN ((QLA82XX_HW_H3_CH_HUB_ADR << 7) | \
+ QLA82XX_HW_QM_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_SQN0 ((QLA82XX_HW_H3_CH_HUB_ADR << 7) | \
+ QLA82XX_HW_SQG0_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_SQN1 ((QLA82XX_HW_H3_CH_HUB_ADR << 7) | \
+ QLA82XX_HW_SQG1_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_SQN2 ((QLA82XX_HW_H3_CH_HUB_ADR << 7) | \
+ QLA82XX_HW_SQG2_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_SQN3 ((QLA82XX_HW_H3_CH_HUB_ADR << 7) | \
+ QLA82XX_HW_SQG3_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX1 ((QLA82XX_HW_H3_CH_HUB_ADR << 7) | \
+ QLA82XX_HW_RPMX1_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX5 ((QLA82XX_HW_H3_CH_HUB_ADR << 7) | \
+ QLA82XX_HW_RPMX5_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX6 ((QLA82XX_HW_H3_CH_HUB_ADR << 7) | \
+ QLA82XX_HW_RPMX6_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX8 ((QLA82XX_HW_H3_CH_HUB_ADR << 7) | \
+ QLA82XX_HW_RPMX8_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_CAS0 ((QLA82XX_HW_H3_CH_HUB_ADR << 7) | \
+ QLA82XX_HW_CAS0_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_CAS1 ((QLA82XX_HW_H3_CH_HUB_ADR << 7) | \
+ QLA82XX_HW_CAS1_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_CAS2 ((QLA82XX_HW_H3_CH_HUB_ADR << 7) | \
+ QLA82XX_HW_CAS2_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_CAS3 ((QLA82XX_HW_H3_CH_HUB_ADR << 7) | \
+ QLA82XX_HW_CAS3_CRB_AGT_ADR)
+
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_PGNI ((QLA82XX_HW_H4_CH_HUB_ADR << 7) | \
+ QLA82XX_HW_PEGNI_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_PGND ((QLA82XX_HW_H4_CH_HUB_ADR << 7) | \
+ QLA82XX_HW_PEGND_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_PGN0 ((QLA82XX_HW_H4_CH_HUB_ADR << 7) | \
+ QLA82XX_HW_PEGN0_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_PGN1 ((QLA82XX_HW_H4_CH_HUB_ADR << 7) | \
+ QLA82XX_HW_PEGN1_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_PGN2 ((QLA82XX_HW_H4_CH_HUB_ADR << 7) | \
+ QLA82XX_HW_PEGN2_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_PGN3 ((QLA82XX_HW_H4_CH_HUB_ADR << 7) | \
+ QLA82XX_HW_PEGN3_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_PGN4 ((QLA82XX_HW_H4_CH_HUB_ADR << 7) | \
+ QLA82XX_HW_PEGN4_CRB_AGT_ADR)
+
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_PGNC ((QLA82XX_HW_H4_CH_HUB_ADR << 7) | \
+ QLA82XX_HW_PEGNC_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_PGR0 ((QLA82XX_HW_H4_CH_HUB_ADR << 7) | \
+ QLA82XX_HW_PEGR0_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_PGR1 ((QLA82XX_HW_H4_CH_HUB_ADR << 7) | \
+ QLA82XX_HW_PEGR1_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_PGR2 ((QLA82XX_HW_H4_CH_HUB_ADR << 7) | \
+ QLA82XX_HW_PEGR2_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_PGR3 ((QLA82XX_HW_H4_CH_HUB_ADR << 7) | \
+ QLA82XX_HW_PEGR3_CRB_AGT_ADR)
+
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_PGSI ((QLA82XX_HW_H5_CH_HUB_ADR << 7) | \
+ QLA82XX_HW_PEGSI_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_PGSD ((QLA82XX_HW_H5_CH_HUB_ADR << 7) | \
+ QLA82XX_HW_PEGSD_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_PGS0 ((QLA82XX_HW_H5_CH_HUB_ADR << 7) | \
+ QLA82XX_HW_PEGS0_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_PGS1 ((QLA82XX_HW_H5_CH_HUB_ADR << 7) | \
+ QLA82XX_HW_PEGS1_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_PGS2 ((QLA82XX_HW_H5_CH_HUB_ADR << 7) | \
+ QLA82XX_HW_PEGS2_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_PGS3 ((QLA82XX_HW_H5_CH_HUB_ADR << 7) | \
+ QLA82XX_HW_PEGS3_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_PGSC ((QLA82XX_HW_H5_CH_HUB_ADR << 7) | \
+ QLA82XX_HW_PEGSC_CRB_AGT_ADR)
+
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_CAM ((QLA82XX_HW_H6_CH_HUB_ADR << 7) | \
+ QLA82XX_HW_NCM_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_TIMR ((QLA82XX_HW_H6_CH_HUB_ADR << 7) | \
+ QLA82XX_HW_TMR_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_XDMA ((QLA82XX_HW_H6_CH_HUB_ADR << 7) | \
+ QLA82XX_HW_XDMA_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_SN ((QLA82XX_HW_H6_CH_HUB_ADR << 7) | \
+ QLA82XX_HW_SN_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_I2Q ((QLA82XX_HW_H6_CH_HUB_ADR << 7) | \
+ QLA82XX_HW_I2Q_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_ROMUSB ((QLA82XX_HW_H6_CH_HUB_ADR << 7) | \
+ QLA82XX_HW_ROMUSB_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_OCM0 ((QLA82XX_HW_H6_CH_HUB_ADR << 7) | \
+ QLA82XX_HW_OCM0_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_OCM1 ((QLA82XX_HW_H6_CH_HUB_ADR << 7) | \
+ QLA82XX_HW_OCM1_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_LPC ((QLA82XX_HW_H6_CH_HUB_ADR << 7) | \
+ QLA82XX_HW_LPC_CRB_AGT_ADR)
+
+#define ROMUSB_GLB (QLA82XX_CRB_ROMUSB + 0x00000)
+#define QLA82XX_ROMUSB_GLB_PEGTUNE_DONE (ROMUSB_GLB + 0x005c)
+#define QLA82XX_ROMUSB_GLB_STATUS (ROMUSB_GLB + 0x0004)
+#define QLA82XX_ROMUSB_GLB_SW_RESET (ROMUSB_GLB + 0x0008)
+#define QLA82XX_ROMUSB_ROM_ADDRESS (ROMUSB_ROM + 0x0008)
+#define QLA82XX_ROMUSB_ROM_WDATA (ROMUSB_ROM + 0x000c)
+#define QLA82XX_ROMUSB_ROM_ABYTE_CNT (ROMUSB_ROM + 0x0010)
+#define QLA82XX_ROMUSB_ROM_DUMMY_BYTE_CNT (ROMUSB_ROM + 0x0014)
+#define QLA82XX_ROMUSB_ROM_RDATA (ROMUSB_ROM + 0x0018)
+
+#define ROMUSB_ROM (QLA82XX_CRB_ROMUSB + 0x10000)
+#define QLA82XX_ROMUSB_ROM_INSTR_OPCODE (ROMUSB_ROM + 0x0004)
+#define QLA82XX_ROMUSB_GLB_CAS_RST (ROMUSB_GLB + 0x0038)
+
+/* Lock IDs for ROM lock */
+#define ROM_LOCK_DRIVER 0x0d417340
+
+#define QLA82XX_PCI_CRB_WINDOWSIZE 0x00100000 /* all are 1MB windows */
+#define QLA82XX_PCI_CRB_WINDOW(A) (QLA82XX_PCI_CRBSPACE + \
+ (A)*QLA82XX_PCI_CRB_WINDOWSIZE)
+
+#define QLA82XX_CRB_C2C_0 \
+ QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_C2C0)
+#define QLA82XX_CRB_C2C_1 \
+ QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_C2C1)
+#define QLA82XX_CRB_C2C_2 \
+ QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_C2C2)
+#define QLA82XX_CRB_CAM \
+ QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_CAM)
+#define QLA82XX_CRB_CASPER \
+ QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_CAS)
+#define QLA82XX_CRB_CASPER_0 \
+ QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_CAS0)
+#define QLA82XX_CRB_CASPER_1 \
+ QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_CAS1)
+#define QLA82XX_CRB_CASPER_2 \
+ QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_CAS2)
+#define QLA82XX_CRB_DDR_MD \
+ QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_MS)
+#define QLA82XX_CRB_DDR_NET \
+ QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_MN)
+#define QLA82XX_CRB_EPG \
+ QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_EG)
+#define QLA82XX_CRB_I2Q \
+ QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_I2Q)
+#define QLA82XX_CRB_NIU \
+ QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_NIU)
+/* HACK upon HACK upon HACK (for PCIE builds) */
+#define QLA82XX_CRB_PCIX_HOST \
+ QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_PH)
+#define QLA82XX_CRB_PCIX_HOST2 \
+ QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_PH2)
+#define QLA82XX_CRB_PCIX_MD \
+ QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_PS)
+#define QLA82XX_CRB_PCIE QLA82XX_CRB_PCIX_MD
+/* window 1 pcie slot */
+#define QLA82XX_CRB_PCIE2 \
+ QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_PS2)
+
+#define QLA82XX_CRB_PEG_MD_0 \
+ QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_PGS0)
+#define QLA82XX_CRB_PEG_MD_1 \
+ QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_PGS1)
+#define QLA82XX_CRB_PEG_MD_2 \
+ QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_PGS2)
+#define QLA82XX_CRB_PEG_MD_3 \
+ QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_PGS3)
+#define QLA82XX_CRB_PEG_MD_3 \
+ QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_PGS3)
+#define QLA82XX_CRB_PEG_MD_D \
+ QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_PGSD)
+#define QLA82XX_CRB_PEG_MD_I \
+ QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_PGSI)
+#define QLA82XX_CRB_PEG_NET_0 \
+ QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_PGN0)
+#define QLA82XX_CRB_PEG_NET_1 \
+ QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_PGN1)
+#define QLA82XX_CRB_PEG_NET_2 \
+ QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_PGN2)
+#define QLA82XX_CRB_PEG_NET_3 \
+ QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_PGN3)
+#define QLA82XX_CRB_PEG_NET_4 \
+ QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_PGN4)
+#define QLA82XX_CRB_PEG_NET_D \
+ QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_PGND)
+#define QLA82XX_CRB_PEG_NET_I \
+ QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_PGNI)
+#define QLA82XX_CRB_PQM_MD \
+ QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_QMS)
+#define QLA82XX_CRB_PQM_NET \
+ QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_QMN)
+#define QLA82XX_CRB_QDR_MD \
+ QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_SS)
+#define QLA82XX_CRB_QDR_NET \
+ QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_SN)
+#define QLA82XX_CRB_ROMUSB \
+ QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_ROMUSB)
+#define QLA82XX_CRB_RPMX_0 \
+ QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_RPMX0)
+#define QLA82XX_CRB_RPMX_1 \
+ QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_RPMX1)
+#define QLA82XX_CRB_RPMX_2 \
+ QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_RPMX2)
+#define QLA82XX_CRB_RPMX_3 \
+ QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_RPMX3)
+#define QLA82XX_CRB_RPMX_4 \
+ QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_RPMX4)
+#define QLA82XX_CRB_RPMX_5 \
+ QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_RPMX5)
+#define QLA82XX_CRB_RPMX_6 \
+ QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_RPMX6)
+#define QLA82XX_CRB_RPMX_7 \
+ QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_RPMX7)
+#define QLA82XX_CRB_SQM_MD_0 \
+ QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_SQS0)
+#define QLA82XX_CRB_SQM_MD_1 \
+ QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_SQS1)
+#define QLA82XX_CRB_SQM_MD_2 \
+ QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_SQS2)
+#define QLA82XX_CRB_SQM_MD_3 \
+ QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_SQS3)
+#define QLA82XX_CRB_SQM_NET_0 \
+ QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_SQN0)
+#define QLA82XX_CRB_SQM_NET_1 \
+ QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_SQN1)
+#define QLA82XX_CRB_SQM_NET_2 \
+ QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_SQN2)
+#define QLA82XX_CRB_SQM_NET_3 \
+ QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_SQN3)
+#define QLA82XX_CRB_SRE \
+ QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_SRE)
+#define QLA82XX_CRB_TIMER \
+ QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_TIMR)
+#define QLA82XX_CRB_XDMA \
+ QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_XDMA)
+#define QLA82XX_CRB_I2C0 \
+ QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_I2C0)
+#define QLA82XX_CRB_I2C1 \
+ QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_I2C1)
+#define QLA82XX_CRB_OCM0 \
+ QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_OCM0)
+#define QLA82XX_CRB_SMB \
+ QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_SMB)
+
+#define QLA82XX_CRB_MAX QLA82XX_PCI_CRB_WINDOW(64)
+
+/*
+ * ====================== BASE ADDRESSES ON-CHIP ======================
+ * Base addresses of major components on-chip.
+ * ====================== BASE ADDRESSES ON-CHIP ======================
+ */
+#define QLA82XX_ADDR_DDR_NET (0x0000000000000000ULL)
+#define QLA82XX_ADDR_DDR_NET_MAX (0x000000000fffffffULL)
+
+/* Imbus address bit used to indicate a host address. This bit is
+ * eliminated by the pcie bar and bar select before presentation
+ * over pcie. */
+/* host memory via IMBUS */
+#define QLA82XX_P2_ADDR_PCIE (0x0000000800000000ULL)
+#define QLA82XX_P3_ADDR_PCIE (0x0000008000000000ULL)
+#define QLA82XX_ADDR_PCIE_MAX (0x0000000FFFFFFFFFULL)
+#define QLA82XX_ADDR_OCM0 (0x0000000200000000ULL)
+#define QLA82XX_ADDR_OCM0_MAX (0x00000002000fffffULL)
+#define QLA82XX_ADDR_OCM1 (0x0000000200400000ULL)
+#define QLA82XX_ADDR_OCM1_MAX (0x00000002004fffffULL)
+#define QLA82XX_ADDR_QDR_NET (0x0000000300000000ULL)
+
+#define QLA82XX_P2_ADDR_QDR_NET_MAX (0x00000003001fffffULL)
+#define QLA82XX_P3_ADDR_QDR_NET_MAX (0x0000000303ffffffULL)
+
+#define QLA82XX_PCI_CRBSPACE (unsigned long)0x06000000
+#define QLA82XX_PCI_DIRECT_CRB (unsigned long)0x04400000
+#define QLA82XX_PCI_CAMQM (unsigned long)0x04800000
+#define QLA82XX_PCI_CAMQM_MAX (unsigned long)0x04ffffff
+#define QLA82XX_PCI_DDR_NET (unsigned long)0x00000000
+#define QLA82XX_PCI_QDR_NET (unsigned long)0x04000000
+#define QLA82XX_PCI_QDR_NET_MAX (unsigned long)0x043fffff
+
+/*
+ * Register offsets for MN
+ */
+#define MIU_CONTROL (0x000)
+#define MIU_TAG (0x004)
+#define MIU_TEST_AGT_CTRL (0x090)
+#define MIU_TEST_AGT_ADDR_LO (0x094)
+#define MIU_TEST_AGT_ADDR_HI (0x098)
+#define MIU_TEST_AGT_WRDATA_LO (0x0a0)
+#define MIU_TEST_AGT_WRDATA_HI (0x0a4)
+#define MIU_TEST_AGT_WRDATA(i) (0x0a0+(4*(i)))
+#define MIU_TEST_AGT_RDDATA_LO (0x0a8)
+#define MIU_TEST_AGT_RDDATA_HI (0x0ac)
+#define MIU_TEST_AGT_RDDATA(i) (0x0a8+(4*(i)))
+#define MIU_TEST_AGT_ADDR_MASK 0xfffffff8
+#define MIU_TEST_AGT_UPPER_ADDR(off) (0)
+
+/* MIU_TEST_AGT_CTRL flags. work for SIU as well */
+#define MIU_TA_CTL_START 1
+#define MIU_TA_CTL_ENABLE 2
+#define MIU_TA_CTL_WRITE 4
+#define MIU_TA_CTL_BUSY 8
+
+/*CAM RAM */
+# define QLA82XX_CAM_RAM_BASE (QLA82XX_CRB_CAM + 0x02000)
+# define QLA82XX_CAM_RAM(reg) (QLA82XX_CAM_RAM_BASE + (reg))
+
+#define QLA82XX_PEG_TUNE_MN_SPD_ZEROED 0x80000000
+#define QLA82XX_BOOT_LOADER_MN_ISSUE 0xff00ffff
+#define QLA82XX_PORT_MODE_ADDR (QLA82XX_CAM_RAM(0x24))
+#define QLA82XX_PEG_HALT_STATUS1 (QLA82XX_CAM_RAM(0xa8))
+#define QLA82XX_PEG_HALT_STATUS2 (QLA82XX_CAM_RAM(0xac))
+#define QLA82XX_PEG_ALIVE_COUNTER (QLA82XX_CAM_RAM(0xb0))
+
+#define HALT_STATUS_UNRECOVERABLE 0x80000000
+#define HALT_STATUS_RECOVERABLE 0x40000000
+
+
+#define QLA82XX_ROM_LOCK_ID (QLA82XX_CAM_RAM(0x100))
+#define QLA82XX_CRB_WIN_LOCK_ID (QLA82XX_CAM_RAM(0x124))
+#define QLA82XX_FW_VERSION_MAJOR (QLA82XX_CAM_RAM(0x150))
+#define QLA82XX_FW_VERSION_MINOR (QLA82XX_CAM_RAM(0x154))
+#define QLA82XX_FW_VERSION_SUB (QLA82XX_CAM_RAM(0x158))
+#define QLA82XX_PCIE_REG(reg) (QLA82XX_CRB_PCIE + (reg))
+
+/* Driver Coexistence Defines */
+#define QLA82XX_CRB_DRV_ACTIVE (QLA82XX_CAM_RAM(0x138))
+#define QLA82XX_CRB_DEV_STATE (QLA82XX_CAM_RAM(0x140))
+#define QLA82XX_CRB_DEV_PART_INFO (QLA82XX_CAM_RAM(0x14c))
+#define QLA82XX_CRB_DRV_IDC_VERSION (QLA82XX_CAM_RAM(0x174))
+#define QLA82XX_CRB_DRV_STATE (QLA82XX_CAM_RAM(0x144))
+#define QLA82XX_CRB_DRV_SCRATCH (QLA82XX_CAM_RAM(0x148))
+#define QLA82XX_CRB_DEV_PART_INFO (QLA82XX_CAM_RAM(0x14c))
+
+/* Every driver should use these Device State */
+#define QLA82XX_DEV_COLD 1
+#define QLA82XX_DEV_INITIALIZING 2
+#define QLA82XX_DEV_READY 3
+#define QLA82XX_DEV_NEED_RESET 4
+#define QLA82XX_DEV_NEED_QUIESCENT 5
+#define QLA82XX_DEV_FAILED 6
+#define QLA82XX_DEV_QUIESCENT 7
+#define MAX_STATES 8 /* Increment if new state added */
+
+#define QLA82XX_IDC_VERSION 0x1
+#define ROM_DEV_INIT_TIMEOUT 30
+#define ROM_DRV_RESET_ACK_TIMEOUT 10
+
+#define PCIE_SETUP_FUNCTION (0x12040)
+#define PCIE_SETUP_FUNCTION2 (0x12048)
+
+#define QLA82XX_PCIX_PS_REG(reg) (QLA82XX_CRB_PCIX_MD + (reg))
+#define QLA82XX_PCIX_PS2_REG(reg) (QLA82XX_CRB_PCIE2 + (reg))
+
+#define PCIE_SEM2_LOCK (0x1c010) /* Flash lock */
+#define PCIE_SEM2_UNLOCK (0x1c014) /* Flash unlock */
+#define PCIE_SEM5_LOCK (0x1c028) /* Coexistence lock */
+#define PCIE_SEM5_UNLOCK (0x1c02c) /* Coexistence unlock */
+#define PCIE_SEM7_LOCK (0x1c038) /* crb win lock */
+#define PCIE_SEM7_UNLOCK (0x1c03c) /* crbwin unlock*/
+
+/*
+ * The PCI VendorID and DeviceID for our board.
+ */
+#define QLA82XX_MSIX_TBL_SPACE 8192
+#define QLA82XX_PCI_REG_MSIX_TBL 0x44
+#define QLA82XX_PCI_MSIX_CONTROL 0x40
+
+struct crb_128M_2M_sub_block_map {
+ unsigned valid;
+ unsigned start_128M;
+ unsigned end_128M;
+ unsigned start_2M;
+};
+
+struct crb_128M_2M_block_map {
+ struct crb_128M_2M_sub_block_map sub_block[16];
+};
+
+struct crb_addr_pair {
+ long addr;
+ long data;
+};
+
+#define ADDR_ERROR ((unsigned long) 0xffffffff)
+#define MAX_CTL_CHECK 1000
+
+/***************************************************************************
+ * PCI related defines.
+ **************************************************************************/
+
+/*
+ * Interrupt related defines.
+ */
+#define PCIX_TARGET_STATUS (0x10118)
+#define PCIX_TARGET_STATUS_F1 (0x10160)
+#define PCIX_TARGET_STATUS_F2 (0x10164)
+#define PCIX_TARGET_STATUS_F3 (0x10168)
+#define PCIX_TARGET_STATUS_F4 (0x10360)
+#define PCIX_TARGET_STATUS_F5 (0x10364)
+#define PCIX_TARGET_STATUS_F6 (0x10368)
+#define PCIX_TARGET_STATUS_F7 (0x1036c)
+
+#define PCIX_TARGET_MASK (0x10128)
+#define PCIX_TARGET_MASK_F1 (0x10170)
+#define PCIX_TARGET_MASK_F2 (0x10174)
+#define PCIX_TARGET_MASK_F3 (0x10178)
+#define PCIX_TARGET_MASK_F4 (0x10370)
+#define PCIX_TARGET_MASK_F5 (0x10374)
+#define PCIX_TARGET_MASK_F6 (0x10378)
+#define PCIX_TARGET_MASK_F7 (0x1037c)
+
+/*
+ * Message Signaled Interrupts
+ */
+#define PCIX_MSI_F0 (0x13000)
+#define PCIX_MSI_F1 (0x13004)
+#define PCIX_MSI_F2 (0x13008)
+#define PCIX_MSI_F3 (0x1300c)
+#define PCIX_MSI_F4 (0x13010)
+#define PCIX_MSI_F5 (0x13014)
+#define PCIX_MSI_F6 (0x13018)
+#define PCIX_MSI_F7 (0x1301c)
+#define PCIX_MSI_F(FUNC) (0x13000 + ((FUNC) * 4))
+
+/*
+ *
+ */
+#define PCIX_INT_VECTOR (0x10100)
+#define PCIX_INT_MASK (0x10104)
+
+/*
+ * Interrupt state machine and other bits.
+ */
+#define PCIE_MISCCFG_RC (0x1206c)
+
+
+#define ISR_INT_TARGET_STATUS \
+ (QLA82XX_PCIX_PS_REG(PCIX_TARGET_STATUS))
+#define ISR_INT_TARGET_STATUS_F1 \
+ (QLA82XX_PCIX_PS_REG(PCIX_TARGET_STATUS_F1))
+#define ISR_INT_TARGET_STATUS_F2 \
+ (QLA82XX_PCIX_PS_REG(PCIX_TARGET_STATUS_F2))
+#define ISR_INT_TARGET_STATUS_F3 \
+ (QLA82XX_PCIX_PS_REG(PCIX_TARGET_STATUS_F3))
+#define ISR_INT_TARGET_STATUS_F4 \
+ (QLA82XX_PCIX_PS_REG(PCIX_TARGET_STATUS_F4))
+#define ISR_INT_TARGET_STATUS_F5 \
+ (QLA82XX_PCIX_PS_REG(PCIX_TARGET_STATUS_F5))
+#define ISR_INT_TARGET_STATUS_F6 \
+ (QLA82XX_PCIX_PS_REG(PCIX_TARGET_STATUS_F6))
+#define ISR_INT_TARGET_STATUS_F7 \
+ (QLA82XX_PCIX_PS_REG(PCIX_TARGET_STATUS_F7))
+
+#define ISR_INT_TARGET_MASK \
+ (QLA82XX_PCIX_PS_REG(PCIX_TARGET_MASK))
+#define ISR_INT_TARGET_MASK_F1 \
+ (QLA82XX_PCIX_PS_REG(PCIX_TARGET_MASK_F1))
+#define ISR_INT_TARGET_MASK_F2 \
+ (QLA82XX_PCIX_PS_REG(PCIX_TARGET_MASK_F2))
+#define ISR_INT_TARGET_MASK_F3 \
+ (QLA82XX_PCIX_PS_REG(PCIX_TARGET_MASK_F3))
+#define ISR_INT_TARGET_MASK_F4 \
+ (QLA82XX_PCIX_PS_REG(PCIX_TARGET_MASK_F4))
+#define ISR_INT_TARGET_MASK_F5 \
+ (QLA82XX_PCIX_PS_REG(PCIX_TARGET_MASK_F5))
+#define ISR_INT_TARGET_MASK_F6 \
+ (QLA82XX_PCIX_PS_REG(PCIX_TARGET_MASK_F6))
+#define ISR_INT_TARGET_MASK_F7 \
+ (QLA82XX_PCIX_PS_REG(PCIX_TARGET_MASK_F7))
+
+#define ISR_INT_VECTOR (QLA82XX_PCIX_PS_REG(PCIX_INT_VECTOR))
+#define ISR_INT_MASK (QLA82XX_PCIX_PS_REG(PCIX_INT_MASK))
+#define ISR_INT_STATE_REG (QLA82XX_PCIX_PS_REG(PCIE_MISCCFG_RC))
+
+#define ISR_MSI_INT_TRIGGER(FUNC) (QLA82XX_PCIX_PS_REG(PCIX_MSI_F(FUNC)))
+
+
+#define ISR_IS_LEGACY_INTR_IDLE(VAL) (((VAL) & 0x300) == 0)
+#define ISR_IS_LEGACY_INTR_TRIGGERED(VAL) (((VAL) & 0x300) == 0x200)
+
+/*
+ * PCI Interrupt Vector Values.
+ */
+#define PCIX_INT_VECTOR_BIT_F0 0x0080
+#define PCIX_INT_VECTOR_BIT_F1 0x0100
+#define PCIX_INT_VECTOR_BIT_F2 0x0200
+#define PCIX_INT_VECTOR_BIT_F3 0x0400
+#define PCIX_INT_VECTOR_BIT_F4 0x0800
+#define PCIX_INT_VECTOR_BIT_F5 0x1000
+#define PCIX_INT_VECTOR_BIT_F6 0x2000
+#define PCIX_INT_VECTOR_BIT_F7 0x4000
+
+/* struct qla4_8xxx_legacy_intr_set defined in ql4_def.h */
+
+#define QLA82XX_LEGACY_INTR_CONFIG \
+{ \
+ { \
+ .int_vec_bit = PCIX_INT_VECTOR_BIT_F0, \
+ .tgt_status_reg = ISR_INT_TARGET_STATUS, \
+ .tgt_mask_reg = ISR_INT_TARGET_MASK, \
+ .pci_int_reg = ISR_MSI_INT_TRIGGER(0) }, \
+ \
+ { \
+ .int_vec_bit = PCIX_INT_VECTOR_BIT_F1, \
+ .tgt_status_reg = ISR_INT_TARGET_STATUS_F1, \
+ .tgt_mask_reg = ISR_INT_TARGET_MASK_F1, \
+ .pci_int_reg = ISR_MSI_INT_TRIGGER(1) }, \
+ \
+ { \
+ .int_vec_bit = PCIX_INT_VECTOR_BIT_F2, \
+ .tgt_status_reg = ISR_INT_TARGET_STATUS_F2, \
+ .tgt_mask_reg = ISR_INT_TARGET_MASK_F2, \
+ .pci_int_reg = ISR_MSI_INT_TRIGGER(2) }, \
+ \
+ { \
+ .int_vec_bit = PCIX_INT_VECTOR_BIT_F3, \
+ .tgt_status_reg = ISR_INT_TARGET_STATUS_F3, \
+ .tgt_mask_reg = ISR_INT_TARGET_MASK_F3, \
+ .pci_int_reg = ISR_MSI_INT_TRIGGER(3) }, \
+ \
+ { \
+ .int_vec_bit = PCIX_INT_VECTOR_BIT_F4, \
+ .tgt_status_reg = ISR_INT_TARGET_STATUS_F4, \
+ .tgt_mask_reg = ISR_INT_TARGET_MASK_F4, \
+ .pci_int_reg = ISR_MSI_INT_TRIGGER(4) }, \
+ \
+ { \
+ .int_vec_bit = PCIX_INT_VECTOR_BIT_F5, \
+ .tgt_status_reg = ISR_INT_TARGET_STATUS_F5, \
+ .tgt_mask_reg = ISR_INT_TARGET_MASK_F5, \
+ .pci_int_reg = ISR_MSI_INT_TRIGGER(5) }, \
+ \
+ { \
+ .int_vec_bit = PCIX_INT_VECTOR_BIT_F6, \
+ .tgt_status_reg = ISR_INT_TARGET_STATUS_F6, \
+ .tgt_mask_reg = ISR_INT_TARGET_MASK_F6, \
+ .pci_int_reg = ISR_MSI_INT_TRIGGER(6) }, \
+ \
+ { \
+ .int_vec_bit = PCIX_INT_VECTOR_BIT_F7, \
+ .tgt_status_reg = ISR_INT_TARGET_STATUS_F7, \
+ .tgt_mask_reg = ISR_INT_TARGET_MASK_F7, \
+ .pci_int_reg = ISR_MSI_INT_TRIGGER(7) }, \
+}
+
+/* Magic number to let user know flash is programmed */
+#define QLA82XX_BDINFO_MAGIC 0x12345678
+#define FW_SIZE_OFFSET (0x3e840c)
+
+/* QLA82XX additions */
+#define MIU_TEST_AGT_WRDATA_UPPER_LO (0x0b0)
+#define MIU_TEST_AGT_WRDATA_UPPER_HI (0x0b4)
+
+#endif
diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c
index 38b1d38afca..5529b2a3974 100644
--- a/drivers/scsi/qla4xxx/ql4_os.c
+++ b/drivers/scsi/qla4xxx/ql4_os.c
@@ -30,22 +30,29 @@ static struct kmem_cache *srb_cachep;
* Module parameter information and variables
*/
int ql4xdiscoverywait = 60;
-module_param(ql4xdiscoverywait, int, S_IRUGO | S_IRUSR);
+module_param(ql4xdiscoverywait, int, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(ql4xdiscoverywait, "Discovery wait time");
+
int ql4xdontresethba = 0;
-module_param(ql4xdontresethba, int, S_IRUGO | S_IRUSR);
+module_param(ql4xdontresethba, int, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(ql4xdontresethba,
- "Dont reset the HBA when the driver gets 0x8002 AEN "
- " default it will reset hba :0"
- " set to 1 to avoid resetting HBA");
+ "Don't reset the HBA for driver recovery \n"
+ " 0 - It will reset HBA (Default)\n"
+ " 1 - It will NOT reset HBA");
int ql4xextended_error_logging = 0; /* 0 = off, 1 = log errors */
-module_param(ql4xextended_error_logging, int, S_IRUGO | S_IRUSR);
+module_param(ql4xextended_error_logging, int, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(ql4xextended_error_logging,
"Option to enable extended error logging, "
"Default is 0 - no logging, 1 - debug logging");
-int ql4_mod_unload = 0;
+int ql4xenablemsix = 1;
+module_param(ql4xenablemsix, int, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(ql4xenablemsix,
+ "Set to enable MSI or MSI-X interrupt mechanism.\n"
+ " 0 = enable INTx interrupt mechanism.\n"
+ " 1 = enable MSI-X interrupt mechanism (Default).\n"
+ " 2 = enable MSI interrupt mechanism.");
#define QL4_DEF_QDEPTH 32
@@ -83,6 +90,9 @@ static int qla4xxx_slave_configure(struct scsi_device *device);
static void qla4xxx_slave_destroy(struct scsi_device *sdev);
static void qla4xxx_scan_start(struct Scsi_Host *shost);
+static struct qla4_8xxx_legacy_intr_set legacy_intr[] =
+ QLA82XX_LEGACY_INTR_CONFIG;
+
static struct scsi_host_template qla4xxx_driver_template = {
.module = THIS_MODULE,
.name = DRIVER_NAME,
@@ -116,7 +126,8 @@ static struct iscsi_transport qla4xxx_iscsi_transport = {
.caps = CAP_FW_DB | CAP_SENDTARGETS_OFFLOAD |
CAP_DATA_PATH_OFFLOAD,
.param_mask = ISCSI_CONN_PORT | ISCSI_CONN_ADDRESS |
- ISCSI_TARGET_NAME | ISCSI_TPGT,
+ ISCSI_TARGET_NAME | ISCSI_TPGT |
+ ISCSI_TARGET_ALIAS,
.host_param_mask = ISCSI_HOST_HWADDRESS |
ISCSI_HOST_IPADDRESS |
ISCSI_HOST_INITIATOR_NAME,
@@ -152,15 +163,12 @@ static void qla4xxx_recovery_timedout(struct iscsi_cls_session *session)
if (atomic_read(&ddb_entry->state) != DDB_STATE_ONLINE) {
atomic_set(&ddb_entry->state, DDB_STATE_DEAD);
- DEBUG2(printk("scsi%ld: %s: index [%d] port down retry count "
+ DEBUG2(printk("scsi%ld: %s: ddb [%d] port down retry count "
"of (%d) secs exhausted, marking device DEAD.\n",
ha->host_no, __func__, ddb_entry->fw_ddb_index,
ha->port_down_retry_count));
- DEBUG2(printk("scsi%ld: %s: scheduling dpc routine - dpc "
- "flags = 0x%lx\n",
- ha->host_no, __func__, ha->dpc_flags));
- queue_work(ha->dpc_thread, &ha->dpc_work);
+ qla4xxx_wake_dpc(ha);
}
}
@@ -203,6 +211,10 @@ static int qla4xxx_sess_get_param(struct iscsi_cls_session *sess,
case ISCSI_PARAM_TPGT:
len = sprintf(buf, "%u\n", ddb_entry->tpgt);
break;
+ case ISCSI_PARAM_TARGET_ALIAS:
+ len = snprintf(buf, PAGE_SIZE - 1, "%s\n",
+ ddb_entry->iscsi_alias);
+ break;
default:
return -ENOSYS;
}
@@ -362,19 +374,37 @@ static void qla4xxx_stop_timer(struct scsi_qla_host *ha)
* @ha: Pointer to host adapter structure.
* @ddb_entry: Pointer to device database entry
*
- * This routine marks a device missing and resets the relogin retry count.
+ * This routine marks a device missing and close connection.
**/
void qla4xxx_mark_device_missing(struct scsi_qla_host *ha,
struct ddb_entry *ddb_entry)
{
- atomic_set(&ddb_entry->state, DDB_STATE_MISSING);
- DEBUG3(printk("scsi%d:%d:%d: index [%d] marked MISSING\n",
- ha->host_no, ddb_entry->bus, ddb_entry->target,
- ddb_entry->fw_ddb_index));
+ if ((atomic_read(&ddb_entry->state) != DDB_STATE_DEAD)) {
+ atomic_set(&ddb_entry->state, DDB_STATE_MISSING);
+ DEBUG2(printk("scsi%ld: ddb [%d] marked MISSING\n",
+ ha->host_no, ddb_entry->fw_ddb_index));
+ } else
+ DEBUG2(printk("scsi%ld: ddb [%d] DEAD\n", ha->host_no,
+ ddb_entry->fw_ddb_index))
+
iscsi_block_session(ddb_entry->sess);
iscsi_conn_error_event(ddb_entry->conn, ISCSI_ERR_CONN_FAILED);
}
+/**
+ * qla4xxx_mark_all_devices_missing - mark all devices as missing.
+ * @ha: Pointer to host adapter structure.
+ *
+ * This routine marks a device missing and resets the relogin retry count.
+ **/
+void qla4xxx_mark_all_devices_missing(struct scsi_qla_host *ha)
+{
+ struct ddb_entry *ddb_entry, *ddbtemp;
+ list_for_each_entry_safe(ddb_entry, ddbtemp, &ha->ddb_list, list) {
+ qla4xxx_mark_device_missing(ha, ddb_entry);
+ }
+}
+
static struct srb* qla4xxx_get_new_srb(struct scsi_qla_host *ha,
struct ddb_entry *ddb_entry,
struct scsi_cmnd *cmd,
@@ -463,7 +493,13 @@ static int qla4xxx_queuecommand(struct scsi_cmnd *cmd,
return SCSI_MLQUEUE_TARGET_BUSY;
}
- if (test_bit(DPC_RESET_HA_INTR, &ha->dpc_flags))
+ if (test_bit(DPC_RESET_HA_INTR, &ha->dpc_flags) ||
+ test_bit(DPC_RESET_ACTIVE, &ha->dpc_flags) ||
+ test_bit(DPC_RESET_HA, &ha->dpc_flags) ||
+ test_bit(DPC_HA_UNRECOVERABLE, &ha->dpc_flags) ||
+ test_bit(DPC_HA_NEED_QUIESCENT, &ha->dpc_flags) ||
+ !test_bit(AF_ONLINE, &ha->flags) ||
+ test_bit(DPC_RESET_HA_FW_CONTEXT, &ha->dpc_flags))
goto qc_host_busy;
spin_unlock_irq(ha->host->host_lock);
@@ -524,7 +560,15 @@ static void qla4xxx_mem_free(struct scsi_qla_host *ha)
ha->srb_mempool = NULL;
/* release io space registers */
- if (ha->reg)
+ if (is_qla8022(ha)) {
+ if (ha->nx_pcibase)
+ iounmap(
+ (struct device_reg_82xx __iomem *)ha->nx_pcibase);
+
+ if (ha->nx_db_wr_ptr)
+ iounmap(
+ (struct device_reg_82xx __iomem *)ha->nx_db_wr_ptr);
+ } else if (ha->reg)
iounmap(ha->reg);
pci_release_regions(ha->pdev);
}
@@ -549,8 +593,8 @@ static int qla4xxx_mem_alloc(struct scsi_qla_host *ha)
ha->queues = dma_alloc_coherent(&ha->pdev->dev, ha->queues_len,
&ha->queues_dma, GFP_KERNEL);
if (ha->queues == NULL) {
- dev_warn(&ha->pdev->dev,
- "Memory Allocation failed - queues.\n");
+ ql4_printk(KERN_WARNING, ha,
+ "Memory Allocation failed - queues.\n");
goto mem_alloc_error_exit;
}
@@ -586,8 +630,8 @@ static int qla4xxx_mem_alloc(struct scsi_qla_host *ha)
ha->srb_mempool = mempool_create(SRB_MIN_REQ, mempool_alloc_slab,
mempool_free_slab, srb_cachep);
if (ha->srb_mempool == NULL) {
- dev_warn(&ha->pdev->dev,
- "Memory Allocation failed - SRB Pool.\n");
+ ql4_printk(KERN_WARNING, ha,
+ "Memory Allocation failed - SRB Pool.\n");
goto mem_alloc_error_exit;
}
@@ -600,6 +644,74 @@ mem_alloc_error_exit:
}
/**
+ * qla4_8xxx_check_fw_alive - Check firmware health
+ * @ha: Pointer to host adapter structure.
+ *
+ * Context: Interrupt
+ **/
+static void qla4_8xxx_check_fw_alive(struct scsi_qla_host *ha)
+{
+ uint32_t fw_heartbeat_counter, halt_status;
+
+ fw_heartbeat_counter = qla4_8xxx_rd_32(ha, QLA82XX_PEG_ALIVE_COUNTER);
+
+ if (ha->fw_heartbeat_counter == fw_heartbeat_counter) {
+ ha->seconds_since_last_heartbeat++;
+ /* FW not alive after 2 seconds */
+ if (ha->seconds_since_last_heartbeat == 2) {
+ ha->seconds_since_last_heartbeat = 0;
+ halt_status = qla4_8xxx_rd_32(ha,
+ QLA82XX_PEG_HALT_STATUS1);
+ /* Since we cannot change dev_state in interrupt
+ * context, set appropriate DPC flag then wakeup
+ * DPC */
+ if (halt_status & HALT_STATUS_UNRECOVERABLE)
+ set_bit(DPC_HA_UNRECOVERABLE, &ha->dpc_flags);
+ else {
+ printk("scsi%ld: %s: detect abort needed!\n",
+ ha->host_no, __func__);
+ set_bit(DPC_RESET_HA, &ha->dpc_flags);
+ }
+ qla4xxx_wake_dpc(ha);
+ }
+ }
+ ha->fw_heartbeat_counter = fw_heartbeat_counter;
+}
+
+/**
+ * qla4_8xxx_watchdog - Poll dev state
+ * @ha: Pointer to host adapter structure.
+ *
+ * Context: Interrupt
+ **/
+void qla4_8xxx_watchdog(struct scsi_qla_host *ha)
+{
+ uint32_t dev_state;
+
+ dev_state = qla4_8xxx_rd_32(ha, QLA82XX_CRB_DEV_STATE);
+
+ /* don't poll if reset is going on */
+ if (!test_bit(DPC_RESET_ACTIVE, &ha->dpc_flags)) {
+ if (dev_state == QLA82XX_DEV_NEED_RESET &&
+ !test_bit(DPC_RESET_HA, &ha->dpc_flags)) {
+ printk("scsi%ld: %s: HW State: NEED RESET!\n",
+ ha->host_no, __func__);
+ set_bit(DPC_RESET_HA, &ha->dpc_flags);
+ qla4xxx_wake_dpc(ha);
+ } else if (dev_state == QLA82XX_DEV_NEED_QUIESCENT &&
+ !test_bit(DPC_HA_NEED_QUIESCENT, &ha->dpc_flags)) {
+ printk("scsi%ld: %s: HW State: NEED QUIES!\n",
+ ha->host_no, __func__);
+ set_bit(DPC_HA_NEED_QUIESCENT, &ha->dpc_flags);
+ qla4xxx_wake_dpc(ha);
+ } else {
+ /* Check firmware health */
+ qla4_8xxx_check_fw_alive(ha);
+ }
+ }
+}
+
+/**
* qla4xxx_timer - checks every second for work to do.
* @ha: Pointer to host adapter structure.
**/
@@ -608,6 +720,16 @@ static void qla4xxx_timer(struct scsi_qla_host *ha)
struct ddb_entry *ddb_entry, *dtemp;
int start_dpc = 0;
+ if (test_bit(AF_HBA_GOING_AWAY, &ha->flags)) {
+ DEBUG2(ql4_printk(KERN_INFO, ha, "%s exited. HBA GOING AWAY\n",
+ __func__));
+ return;
+ }
+
+ if (is_qla8022(ha)) {
+ qla4_8xxx_watchdog(ha);
+ }
+
/* Search for relogin's to time-out and port down retry. */
list_for_each_entry_safe(ddb_entry, dtemp, &ha->ddb_list, list) {
/* Count down time between sending relogins */
@@ -624,7 +746,7 @@ static void qla4xxx_timer(struct scsi_qla_host *ha)
set_bit(DPC_RELOGIN_DEVICE,
&ha->dpc_flags);
set_bit(DF_RELOGIN, &ddb_entry->flags);
- DEBUG2(printk("scsi%ld: %s: index [%d]"
+ DEBUG2(printk("scsi%ld: %s: ddb [%d]"
" login device\n",
ha->host_no, __func__,
ddb_entry->fw_ddb_index));
@@ -647,7 +769,7 @@ static void qla4xxx_timer(struct scsi_qla_host *ha)
DDB_DS_SESSION_FAILED) {
/* Reset retry relogin timer */
atomic_inc(&ddb_entry->relogin_retry_count);
- DEBUG2(printk("scsi%ld: index[%d] relogin"
+ DEBUG2(printk("scsi%ld: ddb [%d] relogin"
" timed out-retrying"
" relogin (%d)\n",
ha->host_no,
@@ -656,7 +778,7 @@ static void qla4xxx_timer(struct scsi_qla_host *ha)
relogin_retry_count))
);
start_dpc++;
- DEBUG(printk("scsi%ld:%d:%d: index [%d] "
+ DEBUG(printk("scsi%ld:%d:%d: ddb [%d] "
"initate relogin after"
" %d seconds\n",
ha->host_no, ddb_entry->bus,
@@ -671,31 +793,35 @@ static void qla4xxx_timer(struct scsi_qla_host *ha)
}
}
- /* Check for heartbeat interval. */
- if (ha->firmware_options & FWOPT_HEARTBEAT_ENABLE &&
- ha->heartbeat_interval != 0) {
- ha->seconds_since_last_heartbeat++;
- if (ha->seconds_since_last_heartbeat >
- ha->heartbeat_interval + 2)
- set_bit(DPC_RESET_HA, &ha->dpc_flags);
+ if (!is_qla8022(ha)) {
+ /* Check for heartbeat interval. */
+ if (ha->firmware_options & FWOPT_HEARTBEAT_ENABLE &&
+ ha->heartbeat_interval != 0) {
+ ha->seconds_since_last_heartbeat++;
+ if (ha->seconds_since_last_heartbeat >
+ ha->heartbeat_interval + 2)
+ set_bit(DPC_RESET_HA, &ha->dpc_flags);
+ }
}
-
/* Wakeup the dpc routine for this adapter, if needed. */
if ((start_dpc ||
test_bit(DPC_RESET_HA, &ha->dpc_flags) ||
test_bit(DPC_RETRY_RESET_HA, &ha->dpc_flags) ||
test_bit(DPC_RELOGIN_DEVICE, &ha->dpc_flags) ||
- test_bit(DPC_RESET_HA_DESTROY_DDB_LIST, &ha->dpc_flags) ||
+ test_bit(DPC_RESET_HA_FW_CONTEXT, &ha->dpc_flags) ||
test_bit(DPC_RESET_HA_INTR, &ha->dpc_flags) ||
test_bit(DPC_GET_DHCP_IP_ADDR, &ha->dpc_flags) ||
test_bit(DPC_LINK_CHANGED, &ha->dpc_flags) ||
+ test_bit(DPC_HA_UNRECOVERABLE, &ha->dpc_flags) ||
+ test_bit(DPC_HA_NEED_QUIESCENT, &ha->dpc_flags) ||
test_bit(DPC_AEN, &ha->dpc_flags)) &&
+ !test_bit(AF_DPC_SCHEDULED, &ha->flags) &&
ha->dpc_thread) {
DEBUG2(printk("scsi%ld: %s: scheduling dpc routine"
" - dpc flags = 0x%lx\n",
ha->host_no, __func__, ha->dpc_flags));
- queue_work(ha->dpc_thread, &ha->dpc_work);
+ qla4xxx_wake_dpc(ha);
}
/* Reschedule timer thread to call us back in one second */
@@ -714,16 +840,15 @@ static void qla4xxx_timer(struct scsi_qla_host *ha)
static int qla4xxx_cmd_wait(struct scsi_qla_host *ha)
{
uint32_t index = 0;
- int stat = QLA_SUCCESS;
unsigned long flags;
struct scsi_cmnd *cmd;
- int wait_cnt = WAIT_CMD_TOV; /*
- * Initialized for 30 seconds as we
- * expect all commands to retuned
- * ASAP.
- */
- while (wait_cnt) {
+ unsigned long wtime = jiffies + (WAIT_CMD_TOV * HZ);
+
+ DEBUG2(ql4_printk(KERN_INFO, ha, "Wait up to %d seconds for cmds to "
+ "complete\n", WAIT_CMD_TOV));
+
+ while (!time_after_eq(jiffies, wtime)) {
spin_lock_irqsave(&ha->hardware_lock, flags);
/* Find a command that hasn't completed. */
for (index = 0; index < ha->host->can_queue; index++) {
@@ -734,31 +859,26 @@ static int qla4xxx_cmd_wait(struct scsi_qla_host *ha)
spin_unlock_irqrestore(&ha->hardware_lock, flags);
/* If No Commands are pending, wait is complete */
- if (index == ha->host->can_queue) {
- break;
- }
-
- /* If we timed out on waiting for commands to come back
- * return ERROR.
- */
- wait_cnt--;
- if (wait_cnt == 0)
- stat = QLA_ERROR;
- else {
- msleep(1000);
- }
- } /* End of While (wait_cnt) */
+ if (index == ha->host->can_queue)
+ return QLA_SUCCESS;
- return stat;
+ msleep(1000);
+ }
+ /* If we timed out on waiting for commands to come back
+ * return ERROR. */
+ return QLA_ERROR;
}
-void qla4xxx_hw_reset(struct scsi_qla_host *ha)
+int qla4xxx_hw_reset(struct scsi_qla_host *ha)
{
uint32_t ctrl_status;
unsigned long flags = 0;
DEBUG2(printk(KERN_ERR "scsi%ld: %s\n", ha->host_no, __func__));
+ if (ql4xxx_lock_drvr_wait(ha) != QLA_SUCCESS)
+ return QLA_ERROR;
+
spin_lock_irqsave(&ha->hardware_lock, flags);
/*
@@ -774,6 +894,7 @@ void qla4xxx_hw_reset(struct scsi_qla_host *ha)
readl(&ha->reg->ctrl_status);
spin_unlock_irqrestore(&ha->hardware_lock, flags);
+ return QLA_SUCCESS;
}
/**
@@ -872,15 +993,16 @@ int qla4xxx_soft_reset(struct scsi_qla_host *ha)
}
/**
- * qla4xxx_flush_active_srbs - returns all outstanding i/o requests to O.S.
+ * qla4xxx_abort_active_cmds - returns all outstanding i/o requests to O.S.
* @ha: Pointer to host adapter structure.
+ * @res: returned scsi status
*
* This routine is called just prior to a HARD RESET to return all
* outstanding commands back to the Operating System.
* Caller should make sure that the following locks are released
* before this calling routine: Hardware lock, and io_request_lock.
**/
-static void qla4xxx_flush_active_srbs(struct scsi_qla_host *ha)
+static void qla4xxx_abort_active_cmds(struct scsi_qla_host *ha, int res)
{
struct srb *srb;
int i;
@@ -890,74 +1012,116 @@ static void qla4xxx_flush_active_srbs(struct scsi_qla_host *ha)
for (i = 0; i < ha->host->can_queue; i++) {
srb = qla4xxx_del_from_active_array(ha, i);
if (srb != NULL) {
- srb->cmd->result = DID_RESET << 16;
+ srb->cmd->result = res;
kref_put(&srb->srb_ref, qla4xxx_srb_compl);
}
}
spin_unlock_irqrestore(&ha->hardware_lock, flags);
}
+void qla4xxx_dead_adapter_cleanup(struct scsi_qla_host *ha)
+{
+ clear_bit(AF_ONLINE, &ha->flags);
+
+ /* Disable the board */
+ ql4_printk(KERN_INFO, ha, "Disabling the board\n");
+ set_bit(AF_HBA_GOING_AWAY, &ha->flags);
+
+ qla4xxx_abort_active_cmds(ha, DID_NO_CONNECT << 16);
+ qla4xxx_mark_all_devices_missing(ha);
+ clear_bit(AF_INIT_DONE, &ha->flags);
+}
+
/**
* qla4xxx_recover_adapter - recovers adapter after a fatal error
* @ha: Pointer to host adapter structure.
- * @renew_ddb_list: Indicates what to do with the adapter's ddb list
- *
- * renew_ddb_list value can be 0=preserve ddb list, 1=destroy and rebuild
- * ddb list.
**/
-static int qla4xxx_recover_adapter(struct scsi_qla_host *ha,
- uint8_t renew_ddb_list)
+static int qla4xxx_recover_adapter(struct scsi_qla_host *ha)
{
- int status;
+ int status = QLA_ERROR;
+ uint8_t reset_chip = 0;
/* Stall incoming I/O until we are done */
+ scsi_block_requests(ha->host);
clear_bit(AF_ONLINE, &ha->flags);
- DEBUG2(printk("scsi%ld: %s calling qla4xxx_cmd_wait\n", ha->host_no,
- __func__));
+ DEBUG2(ql4_printk(KERN_INFO, ha, "%s: adapter OFFLINE\n", __func__));
- /* Wait for outstanding commands to complete.
- * Stalls the driver for max 30 secs
- */
- status = qla4xxx_cmd_wait(ha);
+ set_bit(DPC_RESET_ACTIVE, &ha->dpc_flags);
- qla4xxx_disable_intrs(ha);
+ if (test_bit(DPC_RESET_HA, &ha->dpc_flags))
+ reset_chip = 1;
- /* Flush any pending ddb changed AENs */
- qla4xxx_process_aen(ha, FLUSH_DDB_CHANGED_AENS);
+ /* For the DPC_RESET_HA_INTR case (ISP-4xxx specific)
+ * do not reset adapter, jump to initialize_adapter */
+ if (test_bit(DPC_RESET_HA_INTR, &ha->dpc_flags)) {
+ status = QLA_SUCCESS;
+ goto recover_ha_init_adapter;
+ }
- qla4xxx_flush_active_srbs(ha);
+ /* For the ISP-82xx adapter, issue a stop_firmware if invoked
+ * from eh_host_reset or ioctl module */
+ if (is_qla8022(ha) && !reset_chip &&
+ test_bit(DPC_RESET_HA_FW_CONTEXT, &ha->dpc_flags)) {
+
+ DEBUG2(ql4_printk(KERN_INFO, ha,
+ "scsi%ld: %s - Performing stop_firmware...\n",
+ ha->host_no, __func__));
+ status = ha->isp_ops->reset_firmware(ha);
+ if (status == QLA_SUCCESS) {
+ qla4xxx_cmd_wait(ha);
+ ha->isp_ops->disable_intrs(ha);
+ qla4xxx_process_aen(ha, FLUSH_DDB_CHANGED_AENS);
+ qla4xxx_abort_active_cmds(ha, DID_RESET << 16);
+ } else {
+ /* If the stop_firmware fails then
+ * reset the entire chip */
+ reset_chip = 1;
+ clear_bit(DPC_RESET_HA_FW_CONTEXT, &ha->dpc_flags);
+ set_bit(DPC_RESET_HA, &ha->dpc_flags);
+ }
+ }
- /* Reset the firmware. If successful, function
- * returns with ISP interrupts enabled.
- */
- DEBUG2(printk("scsi%ld: %s - Performing soft reset..\n",
- ha->host_no, __func__));
- if (ql4xxx_lock_drvr_wait(ha) == QLA_SUCCESS)
- status = qla4xxx_soft_reset(ha);
- else
- status = QLA_ERROR;
+ /* Issue full chip reset if recovering from a catastrophic error,
+ * or if stop_firmware fails for ISP-82xx.
+ * This is the default case for ISP-4xxx */
+ if (!is_qla8022(ha) || reset_chip) {
+ qla4xxx_cmd_wait(ha);
+ qla4xxx_process_aen(ha, FLUSH_DDB_CHANGED_AENS);
+ qla4xxx_abort_active_cmds(ha, DID_RESET << 16);
+ DEBUG2(ql4_printk(KERN_INFO, ha,
+ "scsi%ld: %s - Performing chip reset..\n",
+ ha->host_no, __func__));
+ status = ha->isp_ops->reset_chip(ha);
+ }
/* Flush any pending ddb changed AENs */
qla4xxx_process_aen(ha, FLUSH_DDB_CHANGED_AENS);
- /* Re-initialize firmware. If successful, function returns
- * with ISP interrupts enabled */
+recover_ha_init_adapter:
+ /* Upon successful firmware/chip reset, re-initialize the adapter */
if (status == QLA_SUCCESS) {
- DEBUG2(printk("scsi%ld: %s - Initializing adapter..\n",
- ha->host_no, __func__));
-
- /* If successful, AF_ONLINE flag set in
- * qla4xxx_initialize_adapter */
- status = qla4xxx_initialize_adapter(ha, renew_ddb_list);
+ /* For ISP-4xxx, force function 1 to always initialize
+ * before function 3 to prevent both funcions from
+ * stepping on top of the other */
+ if (!is_qla8022(ha) && (ha->mac_index == 3))
+ ssleep(6);
+
+ /* NOTE: AF_ONLINE flag set upon successful completion of
+ * qla4xxx_initialize_adapter */
+ status = qla4xxx_initialize_adapter(ha, PRESERVE_DDB_LIST);
}
- /* Failed adapter initialization?
- * Retry reset_ha only if invoked via DPC (DPC_RESET_HA) */
- if ((test_bit(AF_ONLINE, &ha->flags) == 0) &&
- (test_bit(DPC_RESET_HA, &ha->dpc_flags))) {
+ /* Retry failed adapter initialization, if necessary
+ * Do not retry initialize_adapter for RESET_HA_INTR (ISP-4xxx specific)
+ * case to prevent ping-pong resets between functions */
+ if (!test_bit(AF_ONLINE, &ha->flags) &&
+ !test_bit(DPC_RESET_HA_INTR, &ha->dpc_flags)) {
/* Adapter initialization failed, see if we can retry
- * resetting the ha */
+ * resetting the ha.
+ * Since we don't want to block the DPC for too long
+ * with multiple resets in the same thread,
+ * utilize DPC to retry */
if (!test_bit(DPC_RETRY_RESET_HA, &ha->dpc_flags)) {
ha->retry_reset_ha_cnt = MAX_RESET_HA_RETRIES;
DEBUG2(printk("scsi%ld: recover adapter - retrying "
@@ -982,29 +1146,43 @@ static int qla4xxx_recover_adapter(struct scsi_qla_host *ha,
DEBUG2(printk("scsi%ld: recover adapter "
"failed - board disabled\n",
ha->host_no));
- qla4xxx_flush_active_srbs(ha);
+ qla4xxx_dead_adapter_cleanup(ha);
clear_bit(DPC_RETRY_RESET_HA, &ha->dpc_flags);
clear_bit(DPC_RESET_HA, &ha->dpc_flags);
- clear_bit(DPC_RESET_HA_DESTROY_DDB_LIST,
+ clear_bit(DPC_RESET_HA_FW_CONTEXT,
&ha->dpc_flags);
status = QLA_ERROR;
}
}
} else {
clear_bit(DPC_RESET_HA, &ha->dpc_flags);
- clear_bit(DPC_RESET_HA_DESTROY_DDB_LIST, &ha->dpc_flags);
+ clear_bit(DPC_RESET_HA_FW_CONTEXT, &ha->dpc_flags);
clear_bit(DPC_RETRY_RESET_HA, &ha->dpc_flags);
}
ha->adapter_error_count++;
- if (status == QLA_SUCCESS)
- qla4xxx_enable_intrs(ha);
+ if (test_bit(AF_ONLINE, &ha->flags))
+ ha->isp_ops->enable_intrs(ha);
+
+ scsi_unblock_requests(ha->host);
+
+ clear_bit(DPC_RESET_ACTIVE, &ha->dpc_flags);
+ DEBUG2(printk("scsi%ld: recover adapter: %s\n", ha->host_no,
+ status == QLA_ERROR ? "FAILED" : "SUCCEDED"));
- DEBUG2(printk("scsi%ld: recover adapter .. DONE\n", ha->host_no));
return status;
}
+void qla4xxx_wake_dpc(struct scsi_qla_host *ha)
+{
+ if (ha->dpc_thread &&
+ !test_bit(AF_DPC_SCHEDULED, &ha->flags)) {
+ set_bit(AF_DPC_SCHEDULED, &ha->flags);
+ queue_work(ha->dpc_thread, &ha->dpc_work);
+ }
+}
+
/**
* qla4xxx_do_dpc - dpc routine
* @data: in our case pointer to adapter structure
@@ -1024,21 +1202,47 @@ static void qla4xxx_do_dpc(struct work_struct *work)
int status = QLA_ERROR;
DEBUG2(printk("scsi%ld: %s: DPC handler waking up."
- "flags = 0x%08lx, dpc_flags = 0x%08lx ctrl_stat = 0x%08x\n",
- ha->host_no, __func__, ha->flags, ha->dpc_flags,
- readw(&ha->reg->ctrl_status)));
+ "flags = 0x%08lx, dpc_flags = 0x%08lx\n",
+ ha->host_no, __func__, ha->flags, ha->dpc_flags))
/* Initialization not yet finished. Don't do anything yet. */
if (!test_bit(AF_INIT_DONE, &ha->flags))
return;
- if (adapter_up(ha) ||
- test_bit(DPC_RESET_HA, &ha->dpc_flags) ||
+ /* HBA is in the process of being permanently disabled.
+ * Don't process anything */
+ if (test_bit(AF_HBA_GOING_AWAY, &ha->flags))
+ return;
+
+ if (is_qla8022(ha)) {
+ if (test_bit(DPC_HA_UNRECOVERABLE, &ha->dpc_flags)) {
+ qla4_8xxx_idc_lock(ha);
+ qla4_8xxx_wr_32(ha, QLA82XX_CRB_DEV_STATE,
+ QLA82XX_DEV_FAILED);
+ qla4_8xxx_idc_unlock(ha);
+ ql4_printk(KERN_INFO, ha, "HW State: FAILED\n");
+ qla4_8xxx_device_state_handler(ha);
+ }
+ if (test_and_clear_bit(DPC_HA_NEED_QUIESCENT, &ha->dpc_flags)) {
+ qla4_8xxx_need_qsnt_handler(ha);
+ }
+ }
+
+ if (!test_bit(DPC_RESET_ACTIVE, &ha->dpc_flags) &&
+ (test_bit(DPC_RESET_HA, &ha->dpc_flags) ||
test_bit(DPC_RESET_HA_INTR, &ha->dpc_flags) ||
- test_bit(DPC_RESET_HA_DESTROY_DDB_LIST, &ha->dpc_flags)) {
- if (test_bit(DPC_RESET_HA_DESTROY_DDB_LIST, &ha->dpc_flags) ||
- test_bit(DPC_RESET_HA, &ha->dpc_flags))
- qla4xxx_recover_adapter(ha, PRESERVE_DDB_LIST);
+ test_bit(DPC_RESET_HA_FW_CONTEXT, &ha->dpc_flags))) {
+ if (ql4xdontresethba) {
+ DEBUG2(printk("scsi%ld: %s: Don't Reset HBA\n",
+ ha->host_no, __func__));
+ clear_bit(DPC_RESET_HA, &ha->dpc_flags);
+ clear_bit(DPC_RESET_HA_INTR, &ha->dpc_flags);
+ clear_bit(DPC_RESET_HA_FW_CONTEXT, &ha->dpc_flags);
+ goto dpc_post_reset_ha;
+ }
+ if (test_bit(DPC_RESET_HA_FW_CONTEXT, &ha->dpc_flags) ||
+ test_bit(DPC_RESET_HA, &ha->dpc_flags))
+ qla4xxx_recover_adapter(ha);
if (test_bit(DPC_RESET_HA_INTR, &ha->dpc_flags)) {
uint8_t wait_time = RESET_INTR_TOV;
@@ -1053,18 +1257,18 @@ static void qla4xxx_do_dpc(struct work_struct *work)
DEBUG2(printk("scsi%ld: %s: SR|FSR "
"bit not cleared-- resetting\n",
ha->host_no, __func__));
- qla4xxx_flush_active_srbs(ha);
+ qla4xxx_abort_active_cmds(ha, DID_RESET << 16);
if (ql4xxx_lock_drvr_wait(ha) == QLA_SUCCESS) {
qla4xxx_process_aen(ha, FLUSH_DDB_CHANGED_AENS);
- status = qla4xxx_initialize_adapter(ha,
- PRESERVE_DDB_LIST);
+ status = qla4xxx_recover_adapter(ha);
}
clear_bit(DPC_RESET_HA_INTR, &ha->dpc_flags);
if (status == QLA_SUCCESS)
- qla4xxx_enable_intrs(ha);
+ ha->isp_ops->enable_intrs(ha);
}
}
+dpc_post_reset_ha:
/* ---- process AEN? --- */
if (test_and_clear_bit(DPC_AEN, &ha->dpc_flags))
qla4xxx_process_aen(ha, PROCESS_ALL_AENS);
@@ -1102,13 +1306,11 @@ static void qla4xxx_do_dpc(struct work_struct *work)
DDB_DS_SESSION_ACTIVE) {
atomic_set(&ddb_entry->state,
DDB_STATE_ONLINE);
- dev_info(&ha->pdev->dev,
+ ql4_printk(KERN_INFO, ha,
"scsi%ld: %s: ddb[%d]"
- " os[%d] marked"
- " ONLINE\n",
+ " marked ONLINE\n",
ha->host_no, __func__,
- ddb_entry->fw_ddb_index,
- ddb_entry->os_target_id);
+ ddb_entry->fw_ddb_index);
iscsi_unblock_session(
ddb_entry->sess);
@@ -1144,6 +1346,7 @@ static void qla4xxx_do_dpc(struct work_struct *work)
}
}
}
+ clear_bit(AF_DPC_SCHEDULED, &ha->flags);
}
/**
@@ -1155,30 +1358,99 @@ static void qla4xxx_free_adapter(struct scsi_qla_host *ha)
if (test_bit(AF_INTERRUPTS_ON, &ha->flags)) {
/* Turn-off interrupts on the card. */
- qla4xxx_disable_intrs(ha);
+ ha->isp_ops->disable_intrs(ha);
}
+ /* Remove timer thread, if present */
+ if (ha->timer_active)
+ qla4xxx_stop_timer(ha);
+
/* Kill the kernel thread for this host */
if (ha->dpc_thread)
destroy_workqueue(ha->dpc_thread);
- /* Issue Soft Reset to put firmware in unknown state */
- if (ql4xxx_lock_drvr_wait(ha) == QLA_SUCCESS)
- qla4xxx_hw_reset(ha);
+ /* Put firmware in known state */
+ ha->isp_ops->reset_firmware(ha);
- /* Remove timer thread, if present */
- if (ha->timer_active)
- qla4xxx_stop_timer(ha);
+ if (is_qla8022(ha)) {
+ qla4_8xxx_idc_lock(ha);
+ qla4_8xxx_clear_drv_active(ha);
+ qla4_8xxx_idc_unlock(ha);
+ }
/* Detach interrupts */
if (test_and_clear_bit(AF_IRQ_ATTACHED, &ha->flags))
- free_irq(ha->pdev->irq, ha);
+ qla4xxx_free_irqs(ha);
/* free extra memory */
qla4xxx_mem_free(ha);
+}
+
+int qla4_8xxx_iospace_config(struct scsi_qla_host *ha)
+{
+ int status = 0;
+ uint8_t revision_id;
+ unsigned long mem_base, mem_len, db_base, db_len;
+ struct pci_dev *pdev = ha->pdev;
+
+ status = pci_request_regions(pdev, DRIVER_NAME);
+ if (status) {
+ printk(KERN_WARNING
+ "scsi(%ld) Failed to reserve PIO regions (%s) "
+ "status=%d\n", ha->host_no, pci_name(pdev), status);
+ goto iospace_error_exit;
+ }
+
+ pci_read_config_byte(pdev, PCI_REVISION_ID, &revision_id);
+ DEBUG2(printk(KERN_INFO "%s: revision-id=%d\n",
+ __func__, revision_id));
+ ha->revision_id = revision_id;
+
+ /* remap phys address */
+ mem_base = pci_resource_start(pdev, 0); /* 0 is for BAR 0 */
+ mem_len = pci_resource_len(pdev, 0);
+ DEBUG2(printk(KERN_INFO "%s: ioremap from %lx a size of %lx\n",
+ __func__, mem_base, mem_len));
+
+ /* mapping of pcibase pointer */
+ ha->nx_pcibase = (unsigned long)ioremap(mem_base, mem_len);
+ if (!ha->nx_pcibase) {
+ printk(KERN_ERR
+ "cannot remap MMIO (%s), aborting\n", pci_name(pdev));
+ pci_release_regions(ha->pdev);
+ goto iospace_error_exit;
+ }
- pci_disable_device(ha->pdev);
+ /* Mapping of IO base pointer, door bell read and write pointer */
+ /* mapping of IO base pointer */
+ ha->qla4_8xxx_reg =
+ (struct device_reg_82xx __iomem *)((uint8_t *)ha->nx_pcibase +
+ 0xbc000 + (ha->pdev->devfn << 11));
+
+ db_base = pci_resource_start(pdev, 4); /* doorbell is on bar 4 */
+ db_len = pci_resource_len(pdev, 4);
+
+ /* mapping of doorbell write pointer */
+ ha->nx_db_wr_ptr = (unsigned long)ioremap(db_base +
+ (ha->pdev->devfn << 12), 4);
+ if (!ha->nx_db_wr_ptr) {
+ printk(KERN_ERR
+ "cannot remap MMIO doorbell-write (%s), aborting\n",
+ pci_name(pdev));
+ goto iospace_error_exit;
+ }
+ /* mapping of doorbell read pointer */
+ ha->nx_db_rd_ptr = (uint8_t *) ha->nx_pcibase + (512 * 1024) +
+ (ha->pdev->devfn * 8);
+ if (!ha->nx_db_rd_ptr)
+ printk(KERN_ERR
+ "cannot remap MMIO doorbell-read (%s), aborting\n",
+ pci_name(pdev));
+ return 0;
+
+iospace_error_exit:
+ return -ENOMEM;
}
/***
@@ -1188,7 +1460,7 @@ static void qla4xxx_free_adapter(struct scsi_qla_host *ha)
* This routines maps HBA's registers from the pci address space
* into the kernel virtual address space for memory mapped i/o.
**/
-static int qla4xxx_iospace_config(struct scsi_qla_host *ha)
+int qla4xxx_iospace_config(struct scsi_qla_host *ha)
{
unsigned long pio, pio_len, pio_flags;
unsigned long mmio, mmio_len, mmio_flags;
@@ -1198,12 +1470,12 @@ static int qla4xxx_iospace_config(struct scsi_qla_host *ha)
pio_flags = pci_resource_flags(ha->pdev, 0);
if (pio_flags & IORESOURCE_IO) {
if (pio_len < MIN_IOBASE_LEN) {
- dev_warn(&ha->pdev->dev,
+ ql4_printk(KERN_WARNING, ha,
"Invalid PCI I/O region size\n");
pio = 0;
}
} else {
- dev_warn(&ha->pdev->dev, "region #0 not a PIO resource\n");
+ ql4_printk(KERN_WARNING, ha, "region #0 not a PIO resource\n");
pio = 0;
}
@@ -1213,20 +1485,21 @@ static int qla4xxx_iospace_config(struct scsi_qla_host *ha)
mmio_flags = pci_resource_flags(ha->pdev, 1);
if (!(mmio_flags & IORESOURCE_MEM)) {
- dev_err(&ha->pdev->dev,
- "region #0 not an MMIO resource, aborting\n");
+ ql4_printk(KERN_ERR, ha,
+ "region #0 not an MMIO resource, aborting\n");
goto iospace_error_exit;
}
+
if (mmio_len < MIN_IOBASE_LEN) {
- dev_err(&ha->pdev->dev,
- "Invalid PCI mem region size, aborting\n");
+ ql4_printk(KERN_ERR, ha,
+ "Invalid PCI mem region size, aborting\n");
goto iospace_error_exit;
}
if (pci_request_regions(ha->pdev, DRIVER_NAME)) {
- dev_warn(&ha->pdev->dev,
- "Failed to reserve PIO/MMIO regions\n");
+ ql4_printk(KERN_WARNING, ha,
+ "Failed to reserve PIO/MMIO regions\n");
goto iospace_error_exit;
}
@@ -1235,8 +1508,8 @@ static int qla4xxx_iospace_config(struct scsi_qla_host *ha)
ha->pio_length = pio_len;
ha->reg = ioremap(mmio, MIN_IOBASE_LEN);
if (!ha->reg) {
- dev_err(&ha->pdev->dev,
- "cannot remap MMIO, aborting\n");
+ ql4_printk(KERN_ERR, ha,
+ "cannot remap MMIO, aborting\n");
goto iospace_error_exit;
}
@@ -1247,6 +1520,60 @@ iospace_error_exit:
return -ENOMEM;
}
+static struct isp_operations qla4xxx_isp_ops = {
+ .iospace_config = qla4xxx_iospace_config,
+ .pci_config = qla4xxx_pci_config,
+ .disable_intrs = qla4xxx_disable_intrs,
+ .enable_intrs = qla4xxx_enable_intrs,
+ .start_firmware = qla4xxx_start_firmware,
+ .intr_handler = qla4xxx_intr_handler,
+ .interrupt_service_routine = qla4xxx_interrupt_service_routine,
+ .reset_chip = qla4xxx_soft_reset,
+ .reset_firmware = qla4xxx_hw_reset,
+ .queue_iocb = qla4xxx_queue_iocb,
+ .complete_iocb = qla4xxx_complete_iocb,
+ .rd_shdw_req_q_out = qla4xxx_rd_shdw_req_q_out,
+ .rd_shdw_rsp_q_in = qla4xxx_rd_shdw_rsp_q_in,
+ .get_sys_info = qla4xxx_get_sys_info,
+};
+
+static struct isp_operations qla4_8xxx_isp_ops = {
+ .iospace_config = qla4_8xxx_iospace_config,
+ .pci_config = qla4_8xxx_pci_config,
+ .disable_intrs = qla4_8xxx_disable_intrs,
+ .enable_intrs = qla4_8xxx_enable_intrs,
+ .start_firmware = qla4_8xxx_load_risc,
+ .intr_handler = qla4_8xxx_intr_handler,
+ .interrupt_service_routine = qla4_8xxx_interrupt_service_routine,
+ .reset_chip = qla4_8xxx_isp_reset,
+ .reset_firmware = qla4_8xxx_stop_firmware,
+ .queue_iocb = qla4_8xxx_queue_iocb,
+ .complete_iocb = qla4_8xxx_complete_iocb,
+ .rd_shdw_req_q_out = qla4_8xxx_rd_shdw_req_q_out,
+ .rd_shdw_rsp_q_in = qla4_8xxx_rd_shdw_rsp_q_in,
+ .get_sys_info = qla4_8xxx_get_sys_info,
+};
+
+uint16_t qla4xxx_rd_shdw_req_q_out(struct scsi_qla_host *ha)
+{
+ return (uint16_t)le32_to_cpu(ha->shadow_regs->req_q_out);
+}
+
+uint16_t qla4_8xxx_rd_shdw_req_q_out(struct scsi_qla_host *ha)
+{
+ return (uint16_t)le32_to_cpu(readl(&ha->qla4_8xxx_reg->req_q_out));
+}
+
+uint16_t qla4xxx_rd_shdw_rsp_q_in(struct scsi_qla_host *ha)
+{
+ return (uint16_t)le32_to_cpu(ha->shadow_regs->rsp_q_in);
+}
+
+uint16_t qla4_8xxx_rd_shdw_rsp_q_in(struct scsi_qla_host *ha)
+{
+ return (uint16_t)le32_to_cpu(readl(&ha->qla4_8xxx_reg->rsp_q_in));
+}
+
/**
* qla4xxx_probe_adapter - callback function to probe HBA
* @pdev: pointer to pci_dev structure
@@ -1264,6 +1591,7 @@ static int __devinit qla4xxx_probe_adapter(struct pci_dev *pdev,
struct scsi_qla_host *ha;
uint8_t init_retry_count = 0;
char buf[34];
+ struct qla4_8xxx_legacy_intr_set *nx_legacy_intr;
if (pci_enable_device(pdev))
return -1;
@@ -1284,12 +1612,30 @@ static int __devinit qla4xxx_probe_adapter(struct pci_dev *pdev,
ha->host = host;
ha->host_no = host->host_no;
+ /* Setup Runtime configurable options */
+ if (is_qla8022(ha)) {
+ ha->isp_ops = &qla4_8xxx_isp_ops;
+ rwlock_init(&ha->hw_lock);
+ ha->qdr_sn_window = -1;
+ ha->ddr_mn_window = -1;
+ ha->curr_window = 255;
+ ha->func_num = PCI_FUNC(ha->pdev->devfn);
+ nx_legacy_intr = &legacy_intr[ha->func_num];
+ ha->nx_legacy_intr.int_vec_bit = nx_legacy_intr->int_vec_bit;
+ ha->nx_legacy_intr.tgt_status_reg =
+ nx_legacy_intr->tgt_status_reg;
+ ha->nx_legacy_intr.tgt_mask_reg = nx_legacy_intr->tgt_mask_reg;
+ ha->nx_legacy_intr.pci_int_reg = nx_legacy_intr->pci_int_reg;
+ } else {
+ ha->isp_ops = &qla4xxx_isp_ops;
+ }
+
/* Configure PCI I/O space. */
- ret = qla4xxx_iospace_config(ha);
+ ret = ha->isp_ops->iospace_config(ha);
if (ret)
- goto probe_failed;
+ goto probe_failed_ioconfig;
- dev_info(&ha->pdev->dev, "Found an ISP%04x, irq %d, iobase 0x%p\n",
+ ql4_printk(KERN_INFO, ha, "Found an ISP%04x, irq %d, iobase 0x%p\n",
pdev->device, pdev->irq, ha->reg);
qla4xxx_config_dma_addressing(ha);
@@ -1299,32 +1645,41 @@ static int __devinit qla4xxx_probe_adapter(struct pci_dev *pdev,
INIT_LIST_HEAD(&ha->free_srb_q);
mutex_init(&ha->mbox_sem);
+ init_completion(&ha->mbx_intr_comp);
spin_lock_init(&ha->hardware_lock);
/* Allocate dma buffers */
if (qla4xxx_mem_alloc(ha)) {
- dev_warn(&ha->pdev->dev,
- "[ERROR] Failed to allocate memory for adapter\n");
+ ql4_printk(KERN_WARNING, ha,
+ "[ERROR] Failed to allocate memory for adapter\n");
ret = -ENOMEM;
goto probe_failed;
}
+ if (is_qla8022(ha))
+ (void) qla4_8xxx_get_flash_info(ha);
+
/*
* Initialize the Host adapter request/response queues and
* firmware
* NOTE: interrupts enabled upon successful completion
*/
status = qla4xxx_initialize_adapter(ha, REBUILD_DDB_LIST);
- while (status == QLA_ERROR && init_retry_count++ < MAX_INIT_RETRIES) {
+ while ((!test_bit(AF_ONLINE, &ha->flags)) &&
+ init_retry_count++ < MAX_INIT_RETRIES) {
DEBUG2(printk("scsi: %s: retrying adapter initialization "
"(%d)\n", __func__, init_retry_count));
- qla4xxx_soft_reset(ha);
+
+ if (ha->isp_ops->reset_chip(ha) == QLA_ERROR)
+ continue;
+
status = qla4xxx_initialize_adapter(ha, REBUILD_DDB_LIST);
}
- if (status == QLA_ERROR) {
- dev_warn(&ha->pdev->dev, "Failed to initialize adapter\n");
+
+ if (!test_bit(AF_ONLINE, &ha->flags)) {
+ ql4_printk(KERN_WARNING, ha, "Failed to initialize adapter\n");
ret = -ENODEV;
goto probe_failed;
@@ -1340,8 +1695,9 @@ static int __devinit qla4xxx_probe_adapter(struct pci_dev *pdev,
ret = scsi_init_shared_tag_map(host, MAX_SRBS);
if (ret) {
- dev_warn(&ha->pdev->dev, "scsi_init_shared_tag_map failed\n");
- goto probe_failed;
+ ql4_printk(KERN_WARNING, ha,
+ "scsi_init_shared_tag_map failed\n");
+ goto probe_failed;
}
/* Startup the kernel thread for this host adapter. */
@@ -1350,24 +1706,27 @@ static int __devinit qla4xxx_probe_adapter(struct pci_dev *pdev,
sprintf(buf, "qla4xxx_%lu_dpc", ha->host_no);
ha->dpc_thread = create_singlethread_workqueue(buf);
if (!ha->dpc_thread) {
- dev_warn(&ha->pdev->dev, "Unable to start DPC thread!\n");
+ ql4_printk(KERN_WARNING, ha, "Unable to start DPC thread!\n");
ret = -ENODEV;
goto probe_failed;
}
INIT_WORK(&ha->dpc_work, qla4xxx_do_dpc);
- ret = request_irq(pdev->irq, qla4xxx_intr_handler,
- IRQF_DISABLED | IRQF_SHARED, "qla4xxx", ha);
- if (ret) {
- dev_warn(&ha->pdev->dev, "Failed to reserve interrupt %d"
- " already in use.\n", pdev->irq);
- goto probe_failed;
+ /* For ISP-82XX, request_irqs is called in qla4_8xxx_load_risc
+ * (which is called indirectly by qla4xxx_initialize_adapter),
+ * so that irqs will be registered after crbinit but before
+ * mbx_intr_enable.
+ */
+ if (!is_qla8022(ha)) {
+ ret = qla4xxx_request_irqs(ha);
+ if (ret) {
+ ql4_printk(KERN_WARNING, ha, "Failed to reserve "
+ "interrupt %d already in use.\n", pdev->irq);
+ goto probe_failed;
+ }
}
- set_bit(AF_IRQ_ATTACHED, &ha->flags);
- host->irq = pdev->irq;
- DEBUG(printk("scsi%d: irq %d attached\n", ha->host_no, ha->pdev->irq));
- qla4xxx_enable_intrs(ha);
+ ha->isp_ops->enable_intrs(ha);
/* Start timer thread. */
qla4xxx_start_timer(ha, qla4xxx_timer, 1);
@@ -1391,6 +1750,8 @@ static int __devinit qla4xxx_probe_adapter(struct pci_dev *pdev,
probe_failed:
qla4xxx_free_adapter(ha);
+
+probe_failed_ioconfig:
scsi_host_put(ha->host);
probe_disable_device:
@@ -1409,10 +1770,7 @@ 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);
+ set_bit(AF_HBA_GOING_AWAY, &ha->flags);
/* remove devs from iscsi_sessions to scsi_devices */
qla4xxx_free_ddb_list(ha);
@@ -1423,6 +1781,7 @@ static void __devexit qla4xxx_remove_adapter(struct pci_dev *pdev)
scsi_host_put(ha->host);
+ pci_disable_device(pdev);
pci_set_drvdata(pdev, NULL);
}
@@ -1479,7 +1838,8 @@ static void qla4xxx_slave_destroy(struct scsi_device *sdev)
*
* This routine removes and returns the srb at the specified index
**/
-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)
{
struct srb *srb = NULL;
struct scsi_cmnd *cmd = NULL;
@@ -1605,7 +1965,7 @@ static int qla4xxx_eh_abort(struct scsi_cmnd *cmd)
int ret = SUCCESS;
int wait = 0;
- dev_info(&ha->pdev->dev,
+ ql4_printk(KERN_INFO, ha,
"scsi%ld:%d:%d: Abort command issued cmd=%p, pid=%ld\n",
ha->host_no, id, lun, cmd, serial);
@@ -1637,7 +1997,7 @@ static int qla4xxx_eh_abort(struct scsi_cmnd *cmd)
}
}
- dev_info(&ha->pdev->dev,
+ ql4_printk(KERN_INFO, ha,
"scsi%ld:%d:%d: Abort command - %s\n",
ha->host_no, id, lun, (ret == SUCCESS) ? "succeded" : "failed");
@@ -1660,7 +2020,12 @@ static int qla4xxx_eh_device_reset(struct scsi_cmnd *cmd)
if (!ddb_entry)
return ret;
- dev_info(&ha->pdev->dev,
+ ret = iscsi_block_scsi_eh(cmd);
+ if (ret)
+ return ret;
+ ret = FAILED;
+
+ ql4_printk(KERN_INFO, ha,
"scsi%ld:%d:%d:%d: DEVICE RESET ISSUED.\n", ha->host_no,
cmd->device->channel, cmd->device->id, cmd->device->lun);
@@ -1673,13 +2038,13 @@ static int qla4xxx_eh_device_reset(struct scsi_cmnd *cmd)
/* FIXME: wait for hba to go online */
stat = qla4xxx_reset_lun(ha, ddb_entry, cmd->device->lun);
if (stat != QLA_SUCCESS) {
- dev_info(&ha->pdev->dev, "DEVICE RESET FAILED. %d\n", stat);
+ ql4_printk(KERN_INFO, ha, "DEVICE RESET FAILED. %d\n", stat);
goto eh_dev_reset_done;
}
if (qla4xxx_eh_wait_for_commands(ha, scsi_target(cmd->device),
cmd->device)) {
- dev_info(&ha->pdev->dev,
+ ql4_printk(KERN_INFO, ha,
"DEVICE RESET FAILED - waiting for "
"commands.\n");
goto eh_dev_reset_done;
@@ -1690,7 +2055,7 @@ static int qla4xxx_eh_device_reset(struct scsi_cmnd *cmd)
MM_LUN_RESET) != QLA_SUCCESS)
goto eh_dev_reset_done;
- dev_info(&ha->pdev->dev,
+ ql4_printk(KERN_INFO, ha,
"scsi(%ld:%d:%d:%d): DEVICE RESET SUCCEEDED.\n",
ha->host_no, cmd->device->channel, cmd->device->id,
cmd->device->lun);
@@ -1712,11 +2077,15 @@ static int qla4xxx_eh_target_reset(struct scsi_cmnd *cmd)
{
struct scsi_qla_host *ha = to_qla_host(cmd->device->host);
struct ddb_entry *ddb_entry = cmd->device->hostdata;
- int stat;
+ int stat, ret;
if (!ddb_entry)
return FAILED;
+ ret = iscsi_block_scsi_eh(cmd);
+ if (ret)
+ return ret;
+
starget_printk(KERN_INFO, scsi_target(cmd->device),
"WARM TARGET RESET ISSUED.\n");
@@ -1769,7 +2138,13 @@ static int qla4xxx_eh_host_reset(struct scsi_cmnd *cmd)
ha = (struct scsi_qla_host *) cmd->device->host->hostdata;
- dev_info(&ha->pdev->dev,
+ if (ql4xdontresethba) {
+ DEBUG2(printk("scsi%ld: %s: Don't Reset HBA\n",
+ ha->host_no, __func__));
+ return FAILED;
+ }
+
+ ql4_printk(KERN_INFO, ha,
"scsi(%ld:%d:%d:%d): HOST RESET ISSUED.\n", ha->host_no,
cmd->device->channel, cmd->device->id, cmd->device->lun);
@@ -1781,20 +2156,22 @@ static int qla4xxx_eh_host_reset(struct scsi_cmnd *cmd)
return FAILED;
}
- /* make sure the dpc thread is stopped while we reset the hba */
- clear_bit(AF_ONLINE, &ha->flags);
- flush_workqueue(ha->dpc_thread);
+ if (!test_bit(DPC_RESET_HA, &ha->dpc_flags)) {
+ if (is_qla8022(ha))
+ set_bit(DPC_RESET_HA_FW_CONTEXT, &ha->dpc_flags);
+ else
+ set_bit(DPC_RESET_HA, &ha->dpc_flags);
+ }
- if (qla4xxx_recover_adapter(ha, PRESERVE_DDB_LIST) == QLA_SUCCESS)
+ if (qla4xxx_recover_adapter(ha) == QLA_SUCCESS)
return_status = SUCCESS;
- dev_info(&ha->pdev->dev, "HOST RESET %s.\n",
+ ql4_printk(KERN_INFO, ha, "HOST RESET %s.\n",
return_status == FAILED ? "FAILED" : "SUCCEDED");
return return_status;
}
-
static struct pci_device_id qla4xxx_pci_tbl[] = {
{
.vendor = PCI_VENDOR_ID_QLOGIC,
@@ -1814,6 +2191,12 @@ static struct pci_device_id qla4xxx_pci_tbl[] = {
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
},
+ {
+ .vendor = PCI_VENDOR_ID_QLOGIC,
+ .device = PCI_DEVICE_ID_QLOGIC_ISP8022,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ },
{0, 0},
};
MODULE_DEVICE_TABLE(pci, qla4xxx_pci_tbl);
@@ -1869,7 +2252,6 @@ no_srp_cache:
static void __exit qla4xxx_module_exit(void)
{
- ql4_mod_unload = 1;
pci_unregister_driver(&qla4xxx_pci_driver);
iscsi_unregister_transport(&qla4xxx_iscsi_transport);
kmem_cache_destroy(srb_cachep);
diff --git a/drivers/scsi/qla4xxx/ql4_version.h b/drivers/scsi/qla4xxx/ql4_version.h
index 28a6c494a2e..c905dbd7533 100644
--- a/drivers/scsi/qla4xxx/ql4_version.h
+++ b/drivers/scsi/qla4xxx/ql4_version.h
@@ -5,4 +5,4 @@
* See LICENSE.qla4xxx for copyright and licensing details.
*/
-#define QLA4XXX_DRIVER_VERSION "5.02.00-k1"
+#define QLA4XXX_DRIVER_VERSION "5.02.00-k2"
diff --git a/drivers/scsi/qlogicpti.c b/drivers/scsi/qlogicpti.c
index ca5c15c779c..53d7ed0dc16 100644
--- a/drivers/scsi/qlogicpti.c
+++ b/drivers/scsi/qlogicpti.c
@@ -729,7 +729,7 @@ static int __devinit qpti_register_irq(struct qlogicpti *qpti)
{
struct of_device *op = qpti->op;
- qpti->qhost->irq = qpti->irq = op->irqs[0];
+ qpti->qhost->irq = qpti->irq = op->archdata.irqs[0];
/* We used to try various overly-clever things to
* reduce the interrupt processing overhead on
@@ -1302,7 +1302,7 @@ static int __devinit qpti_sbus_probe(struct of_device *op, const struct of_devic
/* Sometimes Antares cards come up not completely
* setup, and we get a report of a zero IRQ.
*/
- if (op->irqs[0] == 0)
+ if (op->archdata.irqs[0] == 0)
return -ENODEV;
host = scsi_host_alloc(tpnt, sizeof(struct qlogicpti));
@@ -1467,12 +1467,12 @@ static struct of_platform_driver qpti_sbus_driver = {
static int __init qpti_init(void)
{
- return of_register_driver(&qpti_sbus_driver, &of_bus_type);
+ return of_register_platform_driver(&qpti_sbus_driver);
}
static void __exit qpti_exit(void)
{
- of_unregister_driver(&qpti_sbus_driver);
+ of_unregister_platform_driver(&qpti_sbus_driver);
}
MODULE_DESCRIPTION("QlogicISP SBUS driver");
diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c
index 136329b4027..b02bdc6c2cd 100644
--- a/drivers/scsi/scsi_debug.c
+++ b/drivers/scsi/scsi_debug.c
@@ -1991,7 +1991,8 @@ static void map_region(sector_t lba, unsigned int len)
block = lba + alignment;
rem = do_div(block, granularity);
- set_bit(block, map_storep);
+ if (block < map_size)
+ set_bit(block, map_storep);
lba += granularity - rem;
}
@@ -2011,7 +2012,8 @@ static void unmap_region(sector_t lba, unsigned int len)
block = lba + alignment;
rem = do_div(block, granularity);
- if (rem == 0 && lba + granularity <= end)
+ if (rem == 0 && lba + granularity <= end &&
+ block < map_size)
clear_bit(block, map_storep);
lba += granularity - rem;
diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c
index a5d630f5f51..2bf98469dc4 100644
--- a/drivers/scsi/scsi_error.c
+++ b/drivers/scsi/scsi_error.c
@@ -307,6 +307,19 @@ static int scsi_check_sense(struct scsi_cmnd *scmd)
(sshdr.asc == 0x04) && (sshdr.ascq == 0x02))
return FAILED;
+ if (sshdr.asc == 0x3f && sshdr.ascq == 0x0e)
+ scmd_printk(KERN_WARNING, scmd,
+ "Warning! Received an indication that the "
+ "LUN assignments on this target have "
+ "changed. The Linux SCSI layer does not "
+ "automatically remap LUN assignments.\n");
+ else if (sshdr.asc == 0x3f)
+ scmd_printk(KERN_WARNING, scmd,
+ "Warning! Received an indication that the "
+ "operating parameters on this target have "
+ "changed. The Linux SCSI layer does not "
+ "automatically adjust these parameters.\n");
+
if (blk_barrier_rq(scmd->request))
/*
* barrier requests should always retry on UA
@@ -1762,6 +1775,14 @@ int scsi_error_handler(void *data)
* what we need to do to get it up and online again (if we can).
* If we fail, we end up taking the thing offline.
*/
+ if (scsi_autopm_get_host(shost) != 0) {
+ SCSI_LOG_ERROR_RECOVERY(1,
+ printk(KERN_ERR "Error handler scsi_eh_%d "
+ "unable to autoresume\n",
+ shost->host_no));
+ continue;
+ }
+
if (shost->transportt->eh_strategy_handler)
shost->transportt->eh_strategy_handler(shost);
else
@@ -1775,6 +1796,7 @@ int scsi_error_handler(void *data)
* which are still online.
*/
scsi_restart_operations(shost);
+ scsi_autopm_put_host(shost);
set_current_state(TASK_INTERRUPTIBLE);
}
__set_current_state(TASK_RUNNING);
@@ -1872,12 +1894,16 @@ scsi_reset_provider_done_command(struct scsi_cmnd *scmd)
int
scsi_reset_provider(struct scsi_device *dev, int flag)
{
- struct scsi_cmnd *scmd = scsi_get_command(dev, GFP_KERNEL);
+ struct scsi_cmnd *scmd;
struct Scsi_Host *shost = dev->host;
struct request req;
unsigned long flags;
int rtn;
+ if (scsi_autopm_get_host(shost) < 0)
+ return FAILED;
+
+ scmd = scsi_get_command(dev, GFP_KERNEL);
blk_rq_init(NULL, &req);
scmd->request = &req;
@@ -1934,6 +1960,7 @@ scsi_reset_provider(struct scsi_device *dev, int flag)
scsi_run_host_queues(shost);
scsi_next_command(scmd);
+ scsi_autopm_put_host(shost);
return rtn;
}
EXPORT_SYMBOL(scsi_reset_provider);
diff --git a/drivers/scsi/scsi_pm.c b/drivers/scsi/scsi_pm.c
new file mode 100644
index 00000000000..d70e91ae60a
--- /dev/null
+++ b/drivers/scsi/scsi_pm.c
@@ -0,0 +1,206 @@
+/*
+ * scsi_pm.c Copyright (C) 2010 Alan Stern
+ *
+ * SCSI dynamic Power Management
+ * Initial version: Alan Stern <stern@rowland.harvard.edu>
+ */
+
+#include <linux/pm_runtime.h>
+
+#include <scsi/scsi.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_driver.h>
+#include <scsi/scsi_host.h>
+
+#include "scsi_priv.h"
+
+static int scsi_dev_type_suspend(struct device *dev, pm_message_t msg)
+{
+ struct device_driver *drv;
+ int err;
+
+ err = scsi_device_quiesce(to_scsi_device(dev));
+ if (err == 0) {
+ drv = dev->driver;
+ if (drv && drv->suspend)
+ err = drv->suspend(dev, msg);
+ }
+ dev_dbg(dev, "scsi suspend: %d\n", err);
+ return err;
+}
+
+static int scsi_dev_type_resume(struct device *dev)
+{
+ struct device_driver *drv;
+ int err = 0;
+
+ drv = dev->driver;
+ if (drv && drv->resume)
+ err = drv->resume(dev);
+ scsi_device_resume(to_scsi_device(dev));
+ dev_dbg(dev, "scsi resume: %d\n", err);
+ return err;
+}
+
+#ifdef CONFIG_PM_SLEEP
+
+static int scsi_bus_suspend_common(struct device *dev, pm_message_t msg)
+{
+ int err = 0;
+
+ if (scsi_is_sdev_device(dev))
+ err = scsi_dev_type_suspend(dev, msg);
+ return err;
+}
+
+static int scsi_bus_resume_common(struct device *dev)
+{
+ int err = 0;
+
+ if (scsi_is_sdev_device(dev))
+ err = scsi_dev_type_resume(dev);
+
+ if (err == 0) {
+ pm_runtime_disable(dev);
+ pm_runtime_set_active(dev);
+ pm_runtime_enable(dev);
+ }
+ return err;
+}
+
+static int scsi_bus_suspend(struct device *dev)
+{
+ return scsi_bus_suspend_common(dev, PMSG_SUSPEND);
+}
+
+static int scsi_bus_freeze(struct device *dev)
+{
+ return scsi_bus_suspend_common(dev, PMSG_FREEZE);
+}
+
+static int scsi_bus_poweroff(struct device *dev)
+{
+ return scsi_bus_suspend_common(dev, PMSG_HIBERNATE);
+}
+
+#else /* CONFIG_PM_SLEEP */
+
+#define scsi_bus_resume_common NULL
+#define scsi_bus_suspend NULL
+#define scsi_bus_freeze NULL
+#define scsi_bus_poweroff NULL
+
+#endif /* CONFIG_PM_SLEEP */
+
+#ifdef CONFIG_PM_RUNTIME
+
+static int scsi_runtime_suspend(struct device *dev)
+{
+ int err = 0;
+
+ dev_dbg(dev, "scsi_runtime_suspend\n");
+ if (scsi_is_sdev_device(dev)) {
+ err = scsi_dev_type_suspend(dev, PMSG_AUTO_SUSPEND);
+ if (err == -EAGAIN)
+ pm_schedule_suspend(dev, jiffies_to_msecs(
+ round_jiffies_up_relative(HZ/10)));
+ }
+
+ /* Insert hooks here for targets, hosts, and transport classes */
+
+ return err;
+}
+
+static int scsi_runtime_resume(struct device *dev)
+{
+ int err = 0;
+
+ dev_dbg(dev, "scsi_runtime_resume\n");
+ if (scsi_is_sdev_device(dev))
+ err = scsi_dev_type_resume(dev);
+
+ /* Insert hooks here for targets, hosts, and transport classes */
+
+ return err;
+}
+
+static int scsi_runtime_idle(struct device *dev)
+{
+ int err;
+
+ dev_dbg(dev, "scsi_runtime_idle\n");
+
+ /* Insert hooks here for targets, hosts, and transport classes */
+
+ if (scsi_is_sdev_device(dev))
+ err = pm_schedule_suspend(dev, 100);
+ else
+ err = pm_runtime_suspend(dev);
+ return err;
+}
+
+int scsi_autopm_get_device(struct scsi_device *sdev)
+{
+ int err;
+
+ err = pm_runtime_get_sync(&sdev->sdev_gendev);
+ if (err < 0)
+ pm_runtime_put_sync(&sdev->sdev_gendev);
+ else if (err > 0)
+ err = 0;
+ return err;
+}
+EXPORT_SYMBOL_GPL(scsi_autopm_get_device);
+
+void scsi_autopm_put_device(struct scsi_device *sdev)
+{
+ pm_runtime_put_sync(&sdev->sdev_gendev);
+}
+EXPORT_SYMBOL_GPL(scsi_autopm_put_device);
+
+void scsi_autopm_get_target(struct scsi_target *starget)
+{
+ pm_runtime_get_sync(&starget->dev);
+}
+
+void scsi_autopm_put_target(struct scsi_target *starget)
+{
+ pm_runtime_put_sync(&starget->dev);
+}
+
+int scsi_autopm_get_host(struct Scsi_Host *shost)
+{
+ int err;
+
+ err = pm_runtime_get_sync(&shost->shost_gendev);
+ if (err < 0)
+ pm_runtime_put_sync(&shost->shost_gendev);
+ else if (err > 0)
+ err = 0;
+ return err;
+}
+
+void scsi_autopm_put_host(struct Scsi_Host *shost)
+{
+ pm_runtime_put_sync(&shost->shost_gendev);
+}
+
+#else
+
+#define scsi_runtime_suspend NULL
+#define scsi_runtime_resume NULL
+#define scsi_runtime_idle NULL
+
+#endif /* CONFIG_PM_RUNTIME */
+
+const struct dev_pm_ops scsi_bus_pm_ops = {
+ .suspend = scsi_bus_suspend,
+ .resume = scsi_bus_resume_common,
+ .freeze = scsi_bus_freeze,
+ .thaw = scsi_bus_resume_common,
+ .poweroff = scsi_bus_poweroff,
+ .restore = scsi_bus_resume_common,
+ .runtime_suspend = scsi_runtime_suspend,
+ .runtime_resume = scsi_runtime_resume,
+ .runtime_idle = scsi_runtime_idle,
+};
diff --git a/drivers/scsi/scsi_priv.h b/drivers/scsi/scsi_priv.h
index 1fbf7c78bba..b4056d14f81 100644
--- a/drivers/scsi/scsi_priv.h
+++ b/drivers/scsi/scsi_priv.h
@@ -7,6 +7,7 @@ struct request_queue;
struct request;
struct scsi_cmnd;
struct scsi_device;
+struct scsi_target;
struct scsi_host_template;
struct Scsi_Host;
struct scsi_nl_hdr;
@@ -144,6 +145,22 @@ static inline void scsi_netlink_init(void) {}
static inline void scsi_netlink_exit(void) {}
#endif
+/* scsi_pm.c */
+#ifdef CONFIG_PM_OPS
+extern const struct dev_pm_ops scsi_bus_pm_ops;
+#endif
+#ifdef CONFIG_PM_RUNTIME
+extern void scsi_autopm_get_target(struct scsi_target *);
+extern void scsi_autopm_put_target(struct scsi_target *);
+extern int scsi_autopm_get_host(struct Scsi_Host *);
+extern void scsi_autopm_put_host(struct Scsi_Host *);
+#else
+static inline void scsi_autopm_get_target(struct scsi_target *t) {}
+static inline void scsi_autopm_put_target(struct scsi_target *t) {}
+static inline int scsi_autopm_get_host(struct Scsi_Host *h) { return 0; }
+static inline void scsi_autopm_put_host(struct Scsi_Host *h) {}
+#endif /* CONFIG_PM_RUNTIME */
+
/*
* internal scsi timeout functions: for use by mid-layer and transport
* classes.
diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c
index 1c027a97d8b..3d0a1e6e9c4 100644
--- a/drivers/scsi/scsi_scan.c
+++ b/drivers/scsi/scsi_scan.c
@@ -1513,14 +1513,18 @@ struct scsi_device *__scsi_add_device(struct Scsi_Host *shost, uint channel,
starget = scsi_alloc_target(parent, channel, id);
if (!starget)
return ERR_PTR(-ENOMEM);
+ scsi_autopm_get_target(starget);
mutex_lock(&shost->scan_mutex);
if (!shost->async_scan)
scsi_complete_async_scans();
- if (scsi_host_scan_allowed(shost))
+ if (scsi_host_scan_allowed(shost) && scsi_autopm_get_host(shost) == 0) {
scsi_probe_and_add_lun(starget, lun, NULL, &sdev, 1, hostdata);
+ scsi_autopm_put_host(shost);
+ }
mutex_unlock(&shost->scan_mutex);
+ scsi_autopm_put_target(starget);
scsi_target_reap(starget);
put_device(&starget->dev);
@@ -1574,6 +1578,7 @@ static void __scsi_scan_target(struct device *parent, unsigned int channel,
starget = scsi_alloc_target(parent, channel, id);
if (!starget)
return;
+ scsi_autopm_get_target(starget);
if (lun != SCAN_WILD_CARD) {
/*
@@ -1599,6 +1604,7 @@ static void __scsi_scan_target(struct device *parent, unsigned int channel,
}
out_reap:
+ scsi_autopm_put_target(starget);
/* now determine if the target has any children at all
* and if not, nuke it */
scsi_target_reap(starget);
@@ -1633,8 +1639,10 @@ void scsi_scan_target(struct device *parent, unsigned int channel,
if (!shost->async_scan)
scsi_complete_async_scans();
- if (scsi_host_scan_allowed(shost))
+ if (scsi_host_scan_allowed(shost) && scsi_autopm_get_host(shost) == 0) {
__scsi_scan_target(parent, channel, id, lun, rescan);
+ scsi_autopm_put_host(shost);
+ }
mutex_unlock(&shost->scan_mutex);
}
EXPORT_SYMBOL(scsi_scan_target);
@@ -1686,7 +1694,7 @@ int scsi_scan_host_selected(struct Scsi_Host *shost, unsigned int channel,
if (!shost->async_scan)
scsi_complete_async_scans();
- if (scsi_host_scan_allowed(shost)) {
+ if (scsi_host_scan_allowed(shost) && scsi_autopm_get_host(shost) == 0) {
if (channel == SCAN_WILD_CARD)
for (channel = 0; channel <= shost->max_channel;
channel++)
@@ -1694,6 +1702,7 @@ int scsi_scan_host_selected(struct Scsi_Host *shost, unsigned int channel,
rescan);
else
scsi_scan_channel(shost, channel, id, lun, rescan);
+ scsi_autopm_put_host(shost);
}
mutex_unlock(&shost->scan_mutex);
@@ -1831,8 +1840,11 @@ static void do_scsi_scan_host(struct Scsi_Host *shost)
static int do_scan_async(void *_data)
{
struct async_scan_data *data = _data;
- do_scsi_scan_host(data->shost);
+ struct Scsi_Host *shost = data->shost;
+
+ do_scsi_scan_host(shost);
scsi_finish_async_scan(data);
+ scsi_autopm_put_host(shost);
return 0;
}
@@ -1847,16 +1859,20 @@ void scsi_scan_host(struct Scsi_Host *shost)
if (strncmp(scsi_scan_type, "none", 4) == 0)
return;
+ if (scsi_autopm_get_host(shost) < 0)
+ return;
data = scsi_prep_async_scan(shost);
if (!data) {
do_scsi_scan_host(shost);
+ scsi_autopm_put_host(shost);
return;
}
p = kthread_run(do_scan_async, data, "scsi_scan_%d", shost->host_no);
if (IS_ERR(p))
do_scan_async(data);
+ /* scsi_autopm_put_host(shost) is called in do_scan_async() */
}
EXPORT_SYMBOL(scsi_scan_host);
diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c
index c23ab978c3b..c3f67373a4f 100644
--- a/drivers/scsi/scsi_sysfs.c
+++ b/drivers/scsi/scsi_sysfs.c
@@ -11,6 +11,7 @@
#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/device.h>
+#include <linux/pm_runtime.h>
#include <scsi/scsi.h>
#include <scsi/scsi_device.h>
@@ -376,57 +377,13 @@ static int scsi_bus_uevent(struct device *dev, struct kobj_uevent_env *env)
return 0;
}
-static int scsi_bus_suspend(struct device * dev, pm_message_t state)
-{
- struct device_driver *drv;
- struct scsi_device *sdev;
- int err;
-
- if (dev->type != &scsi_dev_type)
- return 0;
-
- drv = dev->driver;
- sdev = to_scsi_device(dev);
-
- err = scsi_device_quiesce(sdev);
- if (err)
- return err;
-
- if (drv && drv->suspend) {
- err = drv->suspend(dev, state);
- if (err)
- return err;
- }
-
- return 0;
-}
-
-static int scsi_bus_resume(struct device * dev)
-{
- struct device_driver *drv;
- struct scsi_device *sdev;
- int err = 0;
-
- if (dev->type != &scsi_dev_type)
- return 0;
-
- drv = dev->driver;
- sdev = to_scsi_device(dev);
-
- if (drv && drv->resume)
- err = drv->resume(dev);
-
- scsi_device_resume(sdev);
-
- return err;
-}
-
struct bus_type scsi_bus_type = {
.name = "scsi",
.match = scsi_bus_match,
.uevent = scsi_bus_uevent,
- .suspend = scsi_bus_suspend,
- .resume = scsi_bus_resume,
+#ifdef CONFIG_PM_OPS
+ .pm = &scsi_bus_pm_ops,
+#endif
};
EXPORT_SYMBOL_GPL(scsi_bus_type);
@@ -848,8 +805,6 @@ static int scsi_target_add(struct scsi_target *starget)
if (starget->state != STARGET_CREATED)
return 0;
- device_enable_async_suspend(&starget->dev);
-
error = device_add(&starget->dev);
if (error) {
dev_err(&starget->dev, "target device_add failed, error %d\n", error);
@@ -858,6 +813,10 @@ static int scsi_target_add(struct scsi_target *starget)
transport_add_device(&starget->dev);
starget->state = STARGET_RUNNING;
+ pm_runtime_set_active(&starget->dev);
+ pm_runtime_enable(&starget->dev);
+ device_enable_async_suspend(&starget->dev);
+
return 0;
}
@@ -887,7 +846,20 @@ int scsi_sysfs_add_sdev(struct scsi_device *sdev)
return error;
transport_configure_device(&starget->dev);
+
device_enable_async_suspend(&sdev->sdev_gendev);
+ scsi_autopm_get_target(starget);
+ pm_runtime_set_active(&sdev->sdev_gendev);
+ pm_runtime_forbid(&sdev->sdev_gendev);
+ pm_runtime_enable(&sdev->sdev_gendev);
+ scsi_autopm_put_target(starget);
+
+ /* The following call will keep sdev active indefinitely, until
+ * its driver does a corresponding scsi_autopm_pm_device(). Only
+ * drivers supporting autosuspend will do this.
+ */
+ scsi_autopm_get_device(sdev);
+
error = device_add(&sdev->sdev_gendev);
if (error) {
printk(KERN_INFO "error 1\n");
diff --git a/drivers/scsi/scsi_transport_fc.c b/drivers/scsi/scsi_transport_fc.c
index 06813789145..edb6b362a8f 100644
--- a/drivers/scsi/scsi_transport_fc.c
+++ b/drivers/scsi/scsi_transport_fc.c
@@ -965,7 +965,7 @@ static FC_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 heirarchy and do not allow the driver to get
+ * port is in the hierarchy 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.
*/
diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c
index 1e6d4793542..e84026def1f 100644
--- a/drivers/scsi/scsi_transport_iscsi.c
+++ b/drivers/scsi/scsi_transport_iscsi.c
@@ -30,8 +30,9 @@
#include <scsi/scsi_transport.h>
#include <scsi/scsi_transport_iscsi.h>
#include <scsi/iscsi_if.h>
+#include <scsi/scsi_cmnd.h>
-#define ISCSI_SESSION_ATTRS 22
+#define ISCSI_SESSION_ATTRS 23
#define ISCSI_CONN_ATTRS 13
#define ISCSI_HOST_ATTRS 4
@@ -534,6 +535,37 @@ static void iscsi_scan_session(struct work_struct *work)
atomic_dec(&ihost->nr_scans);
}
+/**
+ * iscsi_block_scsi_eh - block scsi eh until session state has transistioned
+ * cmd: scsi cmd passed to scsi eh handler
+ *
+ * If the session is down this function will wait for the recovery
+ * timer to fire or for the session to be logged back in. If the
+ * recovery timer fires then FAST_IO_FAIL is returned. The caller
+ * should pass this error value to the scsi eh.
+ */
+int iscsi_block_scsi_eh(struct scsi_cmnd *cmd)
+{
+ struct iscsi_cls_session *session =
+ starget_to_session(scsi_target(cmd->device));
+ unsigned long flags;
+ int ret = 0;
+
+ spin_lock_irqsave(&session->lock, flags);
+ while (session->state != ISCSI_SESSION_LOGGED_IN) {
+ if (session->state == ISCSI_SESSION_FREE) {
+ ret = FAST_IO_FAIL;
+ break;
+ }
+ spin_unlock_irqrestore(&session->lock, flags);
+ msleep(1000);
+ spin_lock_irqsave(&session->lock, flags);
+ }
+ spin_unlock_irqrestore(&session->lock, flags);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(iscsi_block_scsi_eh);
+
static void session_recovery_timedout(struct work_struct *work)
{
struct iscsi_cls_session *session =
@@ -1763,7 +1795,8 @@ iscsi_session_attr(abort_tmo, ISCSI_PARAM_ABORT_TMO, 0);
iscsi_session_attr(lu_reset_tmo, ISCSI_PARAM_LU_RESET_TMO, 0);
iscsi_session_attr(tgt_reset_tmo, ISCSI_PARAM_TGT_RESET_TMO, 0);
iscsi_session_attr(ifacename, ISCSI_PARAM_IFACE_NAME, 0);
-iscsi_session_attr(initiatorname, ISCSI_PARAM_INITIATOR_NAME, 0)
+iscsi_session_attr(initiatorname, ISCSI_PARAM_INITIATOR_NAME, 0);
+iscsi_session_attr(targetalias, ISCSI_PARAM_TARGET_ALIAS, 0);
static ssize_t
show_priv_session_state(struct device *dev, struct device_attribute *attr,
@@ -1782,14 +1815,42 @@ show_priv_session_##field(struct device *dev, \
{ \
struct iscsi_cls_session *session = \
iscsi_dev_to_session(dev->parent); \
+ if (session->field == -1) \
+ return sprintf(buf, "off\n"); \
return sprintf(buf, format"\n", session->field); \
}
-#define iscsi_priv_session_attr(field, format) \
+#define iscsi_priv_session_attr_store(field) \
+static ssize_t \
+store_priv_session_##field(struct device *dev, \
+ struct device_attribute *attr, \
+ const char *buf, size_t count) \
+{ \
+ int val; \
+ char *cp; \
+ struct iscsi_cls_session *session = \
+ iscsi_dev_to_session(dev->parent); \
+ if ((session->state == ISCSI_SESSION_FREE) || \
+ (session->state == ISCSI_SESSION_FAILED)) \
+ return -EBUSY; \
+ if (strncmp(buf, "off", 3) == 0) \
+ session->field = -1; \
+ else { \
+ val = simple_strtoul(buf, &cp, 0); \
+ if (*cp != '\0' && *cp != '\n') \
+ return -EINVAL; \
+ session->field = val; \
+ } \
+ return count; \
+}
+
+#define iscsi_priv_session_rw_attr(field, format) \
iscsi_priv_session_attr_show(field, format) \
-static ISCSI_CLASS_ATTR(priv_sess, field, S_IRUGO, show_priv_session_##field, \
- NULL)
-iscsi_priv_session_attr(recovery_tmo, "%d");
+ iscsi_priv_session_attr_store(field) \
+static ISCSI_CLASS_ATTR(priv_sess, field, S_IRUGO | S_IWUGO, \
+ show_priv_session_##field, \
+ store_priv_session_##field)
+iscsi_priv_session_rw_attr(recovery_tmo, "%d");
/*
* iSCSI host attrs
@@ -1820,6 +1881,11 @@ do { \
count++; \
} while (0)
+#define SETUP_PRIV_SESSION_RW_ATTR(field) \
+do { \
+ priv->session_attrs[count] = &dev_attr_priv_sess_##field; \
+ count++; \
+} while (0)
#define SETUP_SESSION_RD_ATTR(field, param_flag) \
do { \
@@ -2006,7 +2072,8 @@ iscsi_register_transport(struct iscsi_transport *tt)
SETUP_SESSION_RD_ATTR(tgt_reset_tmo,ISCSI_TGT_RESET_TMO);
SETUP_SESSION_RD_ATTR(ifacename, ISCSI_IFACE_NAME);
SETUP_SESSION_RD_ATTR(initiatorname, ISCSI_INITIATOR_NAME);
- SETUP_PRIV_SESSION_RD_ATTR(recovery_tmo);
+ SETUP_SESSION_RD_ATTR(targetalias, ISCSI_TARGET_ALIAS);
+ SETUP_PRIV_SESSION_RW_ATTR(recovery_tmo);
SETUP_PRIV_SESSION_RD_ATTR(state);
BUG_ON(count > ISCSI_SESSION_ATTRS);
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c
index 8802e48bc06..cc8a1d1d915 100644
--- a/drivers/scsi/sd.c
+++ b/drivers/scsi/sd.c
@@ -759,6 +759,10 @@ static int sd_open(struct block_device *bdev, fmode_t mode)
sdev = sdkp->device;
+ retval = scsi_autopm_get_device(sdev);
+ if (retval)
+ goto error_autopm;
+
/*
* If the device is in error recovery, wait until it is done.
* If the device is offline, then disallow any access to it.
@@ -803,6 +807,8 @@ static int sd_open(struct block_device *bdev, fmode_t mode)
return 0;
error_out:
+ scsi_autopm_put_device(sdev);
+error_autopm:
scsi_disk_put(sdkp);
return retval;
}
@@ -834,6 +840,8 @@ static int sd_release(struct gendisk *disk, fmode_t mode)
* XXX and what if there are packets in flight and this close()
* XXX is followed by a "rmmod sd_mod"?
*/
+
+ scsi_autopm_put_device(sdev);
scsi_disk_put(sdkp);
return 0;
}
@@ -2232,7 +2240,6 @@ static void sd_probe_async(void *data, async_cookie_t cookie)
if (sdp->removable)
gd->flags |= GENHD_FL_REMOVABLE;
- dev_set_drvdata(dev, sdkp);
add_disk(gd);
sd_dif_config_host(sdkp);
@@ -2240,6 +2247,7 @@ static void sd_probe_async(void *data, async_cookie_t cookie)
sd_printk(KERN_NOTICE, sdkp, "Attached SCSI %sdisk\n",
sdp->removable ? "removable " : "");
+ scsi_autopm_put_device(sdp);
put_device(&sdkp->dev);
}
@@ -2317,14 +2325,15 @@ static int sd_probe(struct device *dev)
}
device_initialize(&sdkp->dev);
- sdkp->dev.parent = &sdp->sdev_gendev;
+ sdkp->dev.parent = dev;
sdkp->dev.class = &sd_disk_class;
- dev_set_name(&sdkp->dev, dev_name(&sdp->sdev_gendev));
+ dev_set_name(&sdkp->dev, dev_name(dev));
if (device_add(&sdkp->dev))
goto out_free_index;
- get_device(&sdp->sdev_gendev);
+ get_device(dev);
+ dev_set_drvdata(dev, sdkp);
get_device(&sdkp->dev); /* prevent release before async_schedule */
async_schedule(sd_probe_async, sdkp);
@@ -2358,8 +2367,10 @@ static int sd_remove(struct device *dev)
{
struct scsi_disk *sdkp;
- async_synchronize_full();
sdkp = dev_get_drvdata(dev);
+ scsi_autopm_get_device(sdkp->device);
+
+ async_synchronize_full();
blk_queue_prep_rq(sdkp->device->request_queue, scsi_prep_fn);
device_del(&sdkp->dev);
del_gendisk(sdkp->disk);
diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c
index ef752b248c4..2968c6b83dd 100644
--- a/drivers/scsi/sg.c
+++ b/drivers/scsi/sg.c
@@ -245,6 +245,10 @@ sg_open(struct inode *inode, struct file *filp)
if (retval)
goto sg_put;
+ retval = scsi_autopm_get_device(sdp->device);
+ if (retval)
+ goto sdp_put;
+
if (!((flags & O_NONBLOCK) ||
scsi_block_when_processing_errors(sdp->device))) {
retval = -ENXIO;
@@ -302,8 +306,11 @@ sg_open(struct inode *inode, struct file *filp)
}
retval = 0;
error_out:
- if (retval)
+ if (retval) {
+ scsi_autopm_put_device(sdp->device);
+sdp_put:
scsi_device_put(sdp->device);
+ }
sg_put:
if (sdp)
sg_put_dev(sdp);
@@ -327,6 +334,7 @@ sg_release(struct inode *inode, struct file *filp)
sdp->exclude = 0;
wake_up_interruptible(&sdp->o_excl_wait);
+ scsi_autopm_put_device(sdp->device);
kref_put(&sfp->f_ref, sg_remove_sfp);
return 0;
}
@@ -729,6 +737,8 @@ sg_common_write(Sg_fd * sfp, Sg_request * srp,
return k; /* probably out of space --> ENOMEM */
}
if (sdp->detached) {
+ if (srp->bio)
+ blk_end_request_all(srp->rq, -EIO);
sg_finish_rem_req(srp);
return -ENODEV;
}
diff --git a/drivers/scsi/sun_esp.c b/drivers/scsi/sun_esp.c
index 386dd9d602b..89ba6fe02f8 100644
--- a/drivers/scsi/sun_esp.c
+++ b/drivers/scsi/sun_esp.c
@@ -116,7 +116,7 @@ static int __devinit esp_sbus_register_irq(struct esp *esp)
struct Scsi_Host *host = esp->host;
struct of_device *op = esp->dev;
- host->irq = op->irqs[0];
+ host->irq = op->archdata.irqs[0];
return request_irq(host->irq, scsi_esp_intr, IRQF_SHARED, "ESP", esp);
}
@@ -644,12 +644,12 @@ static struct of_platform_driver esp_sbus_driver = {
static int __init sunesp_init(void)
{
- return of_register_driver(&esp_sbus_driver, &of_bus_type);
+ return of_register_platform_driver(&esp_sbus_driver);
}
static void __exit sunesp_exit(void)
{
- of_unregister_driver(&esp_sbus_driver);
+ of_unregister_platform_driver(&esp_sbus_driver);
}
MODULE_DESCRIPTION("Sun ESP SCSI driver");
diff --git a/drivers/serial/68360serial.c b/drivers/serial/68360serial.c
index 24661cd5e4f..768612f8e41 100644
--- a/drivers/serial/68360serial.c
+++ b/drivers/serial/68360serial.c
@@ -2649,7 +2649,7 @@ static int __init rs_360_init(void)
sup->tfcr = SMC_EB;
/* Set this to 1 for now, so we get single
- * character interrupts. Using idle charater
+ * character interrupts. Using idle character
* time requires some additional tuning.
*/
sup->mrblr = 1;
@@ -2728,7 +2728,7 @@ static int __init rs_360_init(void)
up->tfcr = SMC_EB;
/* Set this to 1 for now, so we get single
- * character interrupts. Using idle charater
+ * character interrupts. Using idle character
* time requires some additional tuning.
*/
up->mrblr = 1;
@@ -2886,7 +2886,7 @@ int serial_console_setup( struct console *co, char *options)
sup->tfcr = SMC_EB;
/* Set this to 1 for now, so we get single
- * character interrupts. Using idle charater
+ * character interrupts. Using idle character
* time requires some additional tuning.
*/
sup->mrblr = 1;
diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c
index 891e1dd65f2..09ef57034c9 100644
--- a/drivers/serial/8250.c
+++ b/drivers/serial/8250.c
@@ -302,7 +302,7 @@ static const struct serial8250_config uart_config[] = {
},
};
-#if defined (CONFIG_SERIAL_8250_AU1X00)
+#if defined(CONFIG_MIPS_ALCHEMY)
/* Au1x00 UART hardware has a weird register layout */
static const u8 au_io_in_map[] = {
@@ -422,7 +422,6 @@ static unsigned int mem32_serial_in(struct uart_port *p, int offset)
return readl(p->membase + offset);
}
-#ifdef CONFIG_SERIAL_8250_AU1X00
static unsigned int au_serial_in(struct uart_port *p, int offset)
{
offset = map_8250_in_reg(p, offset) << p->regshift;
@@ -434,7 +433,6 @@ static void au_serial_out(struct uart_port *p, int offset, int value)
offset = map_8250_out_reg(p, offset) << p->regshift;
__raw_writel(value, p->membase + offset);
}
-#endif
static unsigned int tsi_serial_in(struct uart_port *p, int offset)
{
@@ -503,12 +501,11 @@ static void set_io_from_upio(struct uart_port *p)
p->serial_out = mem32_serial_out;
break;
-#ifdef CONFIG_SERIAL_8250_AU1X00
case UPIO_AU:
p->serial_in = au_serial_in;
p->serial_out = au_serial_out;
break;
-#endif
+
case UPIO_TSI:
p->serial_in = tsi_serial_in;
p->serial_out = tsi_serial_out;
@@ -535,9 +532,7 @@ serial_out_sync(struct uart_8250_port *up, int offset, int value)
switch (p->iotype) {
case UPIO_MEM:
case UPIO_MEM32:
-#ifdef CONFIG_SERIAL_8250_AU1X00
case UPIO_AU:
-#endif
case UPIO_DWAPB:
p->serial_out(p, offset, value);
p->serial_in(p, UART_LCR); /* safe, no side-effects */
@@ -573,7 +568,7 @@ static inline void _serial_dl_write(struct uart_8250_port *up, int value)
serial_outp(up, UART_DLM, value >> 8 & 0xff);
}
-#if defined(CONFIG_SERIAL_8250_AU1X00)
+#if defined(CONFIG_MIPS_ALCHEMY)
/* Au1x00 haven't got a standard divisor latch */
static int serial_dl_read(struct uart_8250_port *up)
{
@@ -2596,11 +2591,9 @@ static void serial8250_config_port(struct uart_port *port, int flags)
if (flags & UART_CONFIG_TYPE)
autoconfig(up, probeflags);
-#ifdef CONFIG_SERIAL_8250_AU1X00
/* if access method is AU, it is a 16550 with a quirk */
if (up->port.type == PORT_16550A && up->port.iotype == UPIO_AU)
up->bugs |= UART_BUG_NOMSR;
-#endif
if (up->port.type != PORT_UNKNOWN && flags & UART_CONFIG_IRQ)
autoconfig_irq(up);
diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig
index 8b23165bc5d..e437ce8c174 100644
--- a/drivers/serial/Kconfig
+++ b/drivers/serial/Kconfig
@@ -258,14 +258,6 @@ config SERIAL_8250_ACORN
system, say Y to this option. The driver can handle 1, 2, or 3 port
cards. If unsure, say N.
-config SERIAL_8250_AU1X00
- bool "Au1x00 serial port support"
- depends on SERIAL_8250 != n && SOC_AU1X00
- help
- If you have an Au1x00 SOC based board and want to use the serial port,
- say Y to this option. The driver can handle up to 4 serial ports,
- depending on the SOC. If unsure, say N.
-
config SERIAL_8250_RM9K
bool "Support for MIPS RM9xxx integrated serial port"
depends on SERIAL_8250 != n && SERIAL_RM9000
diff --git a/drivers/serial/cpm_uart/cpm_uart_core.c b/drivers/serial/cpm_uart/cpm_uart_core.c
index cd6cf575902..6016179db53 100644
--- a/drivers/serial/cpm_uart/cpm_uart_core.c
+++ b/drivers/serial/cpm_uart/cpm_uart_core.c
@@ -852,7 +852,7 @@ static void cpm_uart_init_smc(struct uart_cpm_port *pinfo)
*/
cpm_set_smc_fcr(up);
- /* Using idle charater time requires some additional tuning. */
+ /* Using idle character time requires some additional tuning. */
out_be16(&up->smc_mrblr, pinfo->rx_fifosize);
out_be16(&up->smc_maxidl, pinfo->rx_fifosize);
out_be16(&up->smc_brklen, 0);
diff --git a/drivers/serial/kgdboc.c b/drivers/serial/kgdboc.c
index a9a94ae7234..39f9a1adaa7 100644
--- a/drivers/serial/kgdboc.c
+++ b/drivers/serial/kgdboc.c
@@ -17,6 +17,7 @@
#include <linux/kdb.h>
#include <linux/tty.h>
#include <linux/console.h>
+#include <linux/vt_kern.h>
#define MAX_CONFIG_LEN 40
@@ -31,6 +32,7 @@ static struct kparam_string kps = {
.maxlen = MAX_CONFIG_LEN,
};
+static int kgdboc_use_kms; /* 1 if we use kernel mode switching */
static struct tty_driver *kgdb_tty_driver;
static int kgdb_tty_line;
@@ -104,6 +106,12 @@ static int configure_kgdboc(void)
kgdboc_io_ops.is_console = 0;
kgdb_tty_driver = NULL;
+ kgdboc_use_kms = 0;
+ if (strncmp(cptr, "kms,", 4) == 0) {
+ cptr += 4;
+ kgdboc_use_kms = 1;
+ }
+
if (kgdboc_register_kbd(&cptr))
goto do_register;
@@ -201,8 +209,14 @@ static int param_set_kgdboc_var(const char *kmessage, struct kernel_param *kp)
return configure_kgdboc();
}
+static int dbg_restore_graphics;
+
static void kgdboc_pre_exp_handler(void)
{
+ if (!dbg_restore_graphics && kgdboc_use_kms) {
+ dbg_restore_graphics = 1;
+ con_debug_enter(vc_cons[fg_console].d);
+ }
/* Increment the module count when the debugger is active */
if (!kgdb_connected)
try_module_get(THIS_MODULE);
@@ -213,6 +227,10 @@ static void kgdboc_post_exp_handler(void)
/* decrement the module count when the debugger detaches */
if (!kgdb_connected)
module_put(THIS_MODULE);
+ if (kgdboc_use_kms && dbg_restore_graphics) {
+ dbg_restore_graphics = 0;
+ con_debug_leave();
+ }
}
static struct kgdb_io kgdboc_io_ops = {
diff --git a/drivers/serial/mpc52xx_uart.c b/drivers/serial/mpc52xx_uart.c
index 84a35f69901..1a88b363005 100644
--- a/drivers/serial/mpc52xx_uart.c
+++ b/drivers/serial/mpc52xx_uart.c
@@ -113,7 +113,9 @@ struct psc_ops {
unsigned char (*read_char)(struct uart_port *port);
void (*cw_disable_ints)(struct uart_port *port);
void (*cw_restore_ints)(struct uart_port *port);
- unsigned long (*getuartclk)(void *p);
+ unsigned int (*set_baudrate)(struct uart_port *port,
+ struct ktermios *new,
+ struct ktermios *old);
int (*clock)(struct uart_port *port, int enable);
int (*fifoc_init)(void);
void (*fifoc_uninit)(void);
@@ -121,6 +123,16 @@ struct psc_ops {
irqreturn_t (*handle_irq)(struct uart_port *port);
};
+/* setting the prescaler and divisor reg is common for all chips */
+static inline void mpc52xx_set_divisor(struct mpc52xx_psc __iomem *psc,
+ u16 prescaler, unsigned int divisor)
+{
+ /* select prescaler */
+ out_be16(&psc->mpc52xx_psc_clock_select, prescaler);
+ out_8(&psc->ctur, divisor >> 8);
+ out_8(&psc->ctlr, divisor & 0xff);
+}
+
#ifdef CONFIG_PPC_MPC52xx
#define FIFO_52xx(port) ((struct mpc52xx_psc_fifo __iomem *)(PSC(port)+1))
static void mpc52xx_psc_fifo_init(struct uart_port *port)
@@ -128,9 +140,6 @@ static void mpc52xx_psc_fifo_init(struct uart_port *port)
struct mpc52xx_psc __iomem *psc = PSC(port);
struct mpc52xx_psc_fifo __iomem *fifo = FIFO_52xx(port);
- /* /32 prescaler */
- out_be16(&psc->mpc52xx_psc_clock_select, 0xdd00);
-
out_8(&fifo->rfcntl, 0x00);
out_be16(&fifo->rfalarm, 0x1ff);
out_8(&fifo->tfcntl, 0x07);
@@ -219,15 +228,47 @@ static void mpc52xx_psc_cw_restore_ints(struct uart_port *port)
out_be16(&PSC(port)->mpc52xx_psc_imr, port->read_status_mask);
}
-/* Search for bus-frequency property in this node or a parent */
-static unsigned long mpc52xx_getuartclk(void *p)
+static unsigned int mpc5200_psc_set_baudrate(struct uart_port *port,
+ struct ktermios *new,
+ struct ktermios *old)
{
- /*
- * 5200 UARTs have a / 32 prescaler
- * but the generic serial code assumes 16
- * so return ipb freq / 2
- */
- return mpc5xxx_get_bus_frequency(p) / 2;
+ unsigned int baud;
+ unsigned int divisor;
+
+ /* The 5200 has a fixed /32 prescaler, uartclk contains the ipb freq */
+ baud = uart_get_baud_rate(port, new, old,
+ port->uartclk / (32 * 0xffff) + 1,
+ port->uartclk / 32);
+ divisor = (port->uartclk + 16 * baud) / (32 * baud);
+
+ /* enable the /32 prescaler and set the divisor */
+ mpc52xx_set_divisor(PSC(port), 0xdd00, divisor);
+ return baud;
+}
+
+static unsigned int mpc5200b_psc_set_baudrate(struct uart_port *port,
+ struct ktermios *new,
+ struct ktermios *old)
+{
+ unsigned int baud;
+ unsigned int divisor;
+ u16 prescaler;
+
+ /* The 5200B has a selectable /4 or /32 prescaler, uartclk contains the
+ * ipb freq */
+ baud = uart_get_baud_rate(port, new, old,
+ port->uartclk / (32 * 0xffff) + 1,
+ port->uartclk / 4);
+ divisor = (port->uartclk + 2 * baud) / (4 * baud);
+
+ /* select the proper prescaler and set the divisor */
+ if (divisor > 0xffff) {
+ divisor = (divisor + 4) / 8;
+ prescaler = 0xdd00; /* /32 */
+ } else
+ prescaler = 0xff00; /* /4 */
+ mpc52xx_set_divisor(PSC(port), prescaler, divisor);
+ return baud;
}
static void mpc52xx_psc_get_irq(struct uart_port *port, struct device_node *np)
@@ -258,7 +299,28 @@ static struct psc_ops mpc52xx_psc_ops = {
.read_char = mpc52xx_psc_read_char,
.cw_disable_ints = mpc52xx_psc_cw_disable_ints,
.cw_restore_ints = mpc52xx_psc_cw_restore_ints,
- .getuartclk = mpc52xx_getuartclk,
+ .set_baudrate = mpc5200_psc_set_baudrate,
+ .get_irq = mpc52xx_psc_get_irq,
+ .handle_irq = mpc52xx_psc_handle_irq,
+};
+
+static struct psc_ops mpc5200b_psc_ops = {
+ .fifo_init = mpc52xx_psc_fifo_init,
+ .raw_rx_rdy = mpc52xx_psc_raw_rx_rdy,
+ .raw_tx_rdy = mpc52xx_psc_raw_tx_rdy,
+ .rx_rdy = mpc52xx_psc_rx_rdy,
+ .tx_rdy = mpc52xx_psc_tx_rdy,
+ .tx_empty = mpc52xx_psc_tx_empty,
+ .stop_rx = mpc52xx_psc_stop_rx,
+ .start_tx = mpc52xx_psc_start_tx,
+ .stop_tx = mpc52xx_psc_stop_tx,
+ .rx_clr_irq = mpc52xx_psc_rx_clr_irq,
+ .tx_clr_irq = mpc52xx_psc_tx_clr_irq,
+ .write_char = mpc52xx_psc_write_char,
+ .read_char = mpc52xx_psc_read_char,
+ .cw_disable_ints = mpc52xx_psc_cw_disable_ints,
+ .cw_restore_ints = mpc52xx_psc_cw_restore_ints,
+ .set_baudrate = mpc5200b_psc_set_baudrate,
.get_irq = mpc52xx_psc_get_irq,
.handle_irq = mpc52xx_psc_handle_irq,
};
@@ -392,9 +454,35 @@ static void mpc512x_psc_cw_restore_ints(struct uart_port *port)
out_be32(&FIFO_512x(port)->rximr, port->read_status_mask & 0x7f);
}
-static unsigned long mpc512x_getuartclk(void *p)
+static unsigned int mpc512x_psc_set_baudrate(struct uart_port *port,
+ struct ktermios *new,
+ struct ktermios *old)
{
- return mpc5xxx_get_bus_frequency(p);
+ unsigned int baud;
+ unsigned int divisor;
+
+ /*
+ * The "MPC5121e Microcontroller Reference Manual, Rev. 3" says on
+ * pg. 30-10 that the chip supports a /32 and a /10 prescaler.
+ * Furthermore, it states that "After reset, the prescaler by 10
+ * for the UART mode is selected", but the reset register value is
+ * 0x0000 which means a /32 prescaler. This is wrong.
+ *
+ * In reality using /32 prescaler doesn't work, as it is not supported!
+ * Use /16 or /10 prescaler, see "MPC5121e Hardware Design Guide",
+ * Chapter 4.1 PSC in UART Mode.
+ * Calculate with a /16 prescaler here.
+ */
+
+ /* uartclk contains the ips freq */
+ baud = uart_get_baud_rate(port, new, old,
+ port->uartclk / (16 * 0xffff) + 1,
+ port->uartclk / 16);
+ divisor = (port->uartclk + 8 * baud) / (16 * baud);
+
+ /* enable the /16 prescaler and set the divisor */
+ mpc52xx_set_divisor(PSC(port), 0xdd00, divisor);
+ return baud;
}
/* Init PSC FIFO Controller */
@@ -498,7 +586,7 @@ static struct psc_ops mpc512x_psc_ops = {
.read_char = mpc512x_psc_read_char,
.cw_disable_ints = mpc512x_psc_cw_disable_ints,
.cw_restore_ints = mpc512x_psc_cw_restore_ints,
- .getuartclk = mpc512x_getuartclk,
+ .set_baudrate = mpc512x_psc_set_baudrate,
.clock = mpc512x_psc_clock,
.fifoc_init = mpc512x_psc_fifoc_init,
.fifoc_uninit = mpc512x_psc_fifoc_uninit,
@@ -666,8 +754,8 @@ mpc52xx_uart_set_termios(struct uart_port *port, struct ktermios *new,
struct mpc52xx_psc __iomem *psc = PSC(port);
unsigned long flags;
unsigned char mr1, mr2;
- unsigned short ctr;
- unsigned int j, baud, quot;
+ unsigned int j;
+ unsigned int baud;
/* Prepare what we're gonna write */
mr1 = 0;
@@ -704,16 +792,9 @@ mpc52xx_uart_set_termios(struct uart_port *port, struct ktermios *new,
mr2 |= MPC52xx_PSC_MODE_TXCTS;
}
- baud = uart_get_baud_rate(port, new, old, 0, port->uartclk/16);
- quot = uart_get_divisor(port, baud);
- ctr = quot & 0xffff;
-
/* Get the lock */
spin_lock_irqsave(&port->lock, flags);
- /* Update the per-port timeout */
- uart_update_timeout(port, new->c_cflag, baud);
-
/* Do our best to flush TX & RX, so we don't lose anything */
/* But we don't wait indefinitely ! */
j = 5000000; /* Maximum wait */
@@ -737,8 +818,10 @@ mpc52xx_uart_set_termios(struct uart_port *port, struct ktermios *new,
out_8(&psc->command, MPC52xx_PSC_SEL_MODE_REG_1);
out_8(&psc->mode, mr1);
out_8(&psc->mode, mr2);
- out_8(&psc->ctur, ctr >> 8);
- out_8(&psc->ctlr, ctr & 0xff);
+ baud = psc_ops->set_baudrate(port, new, old);
+
+ /* Update the per-port timeout */
+ uart_update_timeout(port, new->c_cflag, baud);
if (UART_ENABLE_MS(port, new->c_cflag))
mpc52xx_uart_enable_ms(port);
@@ -1118,7 +1201,7 @@ mpc52xx_console_setup(struct console *co, char *options)
return ret;
}
- uartclk = psc_ops->getuartclk(np);
+ uartclk = mpc5xxx_get_bus_frequency(np);
if (uartclk == 0) {
pr_debug("Could not find uart clock frequency!\n");
return -EINVAL;
@@ -1201,6 +1284,7 @@ static struct uart_driver mpc52xx_uart_driver = {
static struct of_device_id mpc52xx_uart_of_match[] = {
#ifdef CONFIG_PPC_MPC52xx
+ { .compatible = "fsl,mpc5200b-psc-uart", .data = &mpc5200b_psc_ops, },
{ .compatible = "fsl,mpc5200-psc-uart", .data = &mpc52xx_psc_ops, },
/* binding used by old lite5200 device trees: */
{ .compatible = "mpc5200-psc-uart", .data = &mpc52xx_psc_ops, },
@@ -1233,7 +1317,10 @@ mpc52xx_uart_of_probe(struct of_device *op, const struct of_device_id *match)
pr_debug("Found %s assigned to ttyPSC%x\n",
mpc52xx_uart_nodes[idx]->full_name, idx);
- uartclk = psc_ops->getuartclk(op->dev.of_node);
+ /* set the uart clock to the input clock of the psc, the different
+ * prescalers are taken into account in the set_baudrate() methods
+ * of the respective chip */
+ uartclk = mpc5xxx_get_bus_frequency(op->dev.of_node);
if (uartclk == 0) {
dev_dbg(&op->dev, "Could not find uart clock frequency!\n");
return -EINVAL;
diff --git a/drivers/serial/nwpserial.c b/drivers/serial/nwpserial.c
index 3c02fa96f28..e65b0d9202a 100644
--- a/drivers/serial/nwpserial.c
+++ b/drivers/serial/nwpserial.c
@@ -81,7 +81,7 @@ nwpserial_console_write(struct console *co, const char *s, unsigned int count)
uart_console_write(&up->port, s, count, nwpserial_console_putchar);
- /* wait for transmitter to become emtpy */
+ /* wait for transmitter to become empty */
while ((dcr_read(up->dcr_host, UART_LSR) & UART_LSR_THRE) == 0)
cpu_relax();
diff --git a/drivers/serial/serial_cs.c b/drivers/serial/serial_cs.c
index ab17c08ddc0..141c69554bd 100644
--- a/drivers/serial/serial_cs.c
+++ b/drivers/serial/serial_cs.c
@@ -45,7 +45,6 @@
#include <asm/io.h>
#include <asm/system.h>
-#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/cistpl.h>
#include <pcmcia/ciscode.h>
@@ -115,16 +114,14 @@ static void quirk_setup_brainboxes_0104(struct pcmcia_device *link, struct uart_
static int quirk_post_ibm(struct pcmcia_device *link)
{
- conf_reg_t reg = { 0, CS_READ, 0x800, 0 };
+ u8 val;
int ret;
- ret = pcmcia_access_configuration_register(link, &reg);
+ ret = pcmcia_read_config_byte(link, 0x800, &val);
if (ret)
goto failed;
- reg.Action = CS_WRITE;
- reg.Value = reg.Value | 1;
- ret = pcmcia_access_configuration_register(link, &reg);
+ ret = pcmcia_write_config_byte(link, 0x800, val | 1);
if (ret)
goto failed;
return 0;
@@ -338,8 +335,8 @@ static int serial_probe(struct pcmcia_device *link)
info->p_dev = link;
link->priv = info;
- link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
- link->io.NumPorts1 = 8;
+ link->resource[0]->flags |= IO_DATA_PATH_WIDTH_8;
+ link->resource[0]->end = 8;
link->conf.Attributes = CONF_ENABLE_IRQ;
if (do_sound) {
link->conf.Attributes |= CONF_ENABLE_SPKR;
@@ -427,12 +424,13 @@ static int simple_config_check(struct pcmcia_device *p_dev,
p_dev->conf.Vpp =
cf->vpp1.param[CISTPL_POWER_VNOM] / 10000;
+ p_dev->io_lines = ((*try & 0x1) == 0) ?
+ 16 : cf->io.flags & CISTPL_IO_LINES_MASK;
+
if ((cf->io.nwin > 0) && (cf->io.win[0].len == size_table[(*try >> 1)])
&& (cf->io.win[0].base != 0)) {
- p_dev->io.BasePort1 = cf->io.win[0].base;
- p_dev->io.IOAddrLines = ((*try & 0x1) == 0) ?
- 16 : cf->io.flags & CISTPL_IO_LINES_MASK;
- if (!pcmcia_request_io(p_dev, &p_dev->io))
+ p_dev->resource[0]->start = cf->io.win[0].base;
+ if (!pcmcia_request_io(p_dev))
return 0;
}
return -EINVAL;
@@ -449,9 +447,9 @@ static int simple_config_check_notpicky(struct pcmcia_device *p_dev,
if ((cf->io.nwin > 0) && ((cf->io.flags & CISTPL_IO_LINES_MASK) <= 3)) {
for (j = 0; j < 5; j++) {
- p_dev->io.BasePort1 = base[j];
- p_dev->io.IOAddrLines = base[j] ? 16 : 3;
- if (!pcmcia_request_io(p_dev, &p_dev->io))
+ p_dev->resource[0]->start = base[j];
+ p_dev->io_lines = base[j] ? 16 : 3;
+ if (!pcmcia_request_io(p_dev))
return 0;
}
}
@@ -466,13 +464,13 @@ static int simple_config(struct pcmcia_device *link)
/* If the card is already configured, look up the port and irq */
if (link->function_config) {
unsigned int port = 0;
- if ((link->io.BasePort2 != 0) &&
- (link->io.NumPorts2 == 8)) {
- port = link->io.BasePort2;
+ if ((link->resource[1]->end != 0) &&
+ (resource_size(link->resource[1]) == 8)) {
+ port = link->resource[1]->end;
info->slave = 1;
} else if ((info->manfid == MANFID_OSITECH) &&
- (link->io.NumPorts1 == 0x40)) {
- port = link->io.BasePort1 + 0x28;
+ (resource_size(link->resource[0]) == 0x40)) {
+ port = link->resource[0]->start + 0x28;
info->slave = 1;
}
if (info->slave) {
@@ -510,7 +508,7 @@ found_port:
i = pcmcia_request_configuration(link, &link->conf);
if (i != 0)
return -1;
- return setup_serial(link, info, link->io.BasePort1, link->irq);
+ return setup_serial(link, info, link->resource[0]->start, link->irq);
}
static int multi_config_check(struct pcmcia_device *p_dev,
@@ -524,10 +522,10 @@ static int multi_config_check(struct pcmcia_device *p_dev,
/* The quad port cards have bad CIS's, so just look for a
window larger than 8 ports and assume it will be right */
if ((cf->io.nwin == 1) && (cf->io.win[0].len > 8)) {
- p_dev->io.BasePort1 = cf->io.win[0].base;
- p_dev->io.IOAddrLines = cf->io.flags & CISTPL_IO_LINES_MASK;
- if (!pcmcia_request_io(p_dev, &p_dev->io)) {
- *base2 = p_dev->io.BasePort1 + 8;
+ p_dev->resource[0]->start = cf->io.win[0].base;
+ p_dev->io_lines = cf->io.flags & CISTPL_IO_LINES_MASK;
+ if (!pcmcia_request_io(p_dev)) {
+ *base2 = p_dev->resource[0]->start + 8;
return 0;
}
}
@@ -543,11 +541,11 @@ static int multi_config_check_notpicky(struct pcmcia_device *p_dev,
int *base2 = priv_data;
if (cf->io.nwin == 2) {
- p_dev->io.BasePort1 = cf->io.win[0].base;
- p_dev->io.BasePort2 = cf->io.win[1].base;
- p_dev->io.IOAddrLines = cf->io.flags & CISTPL_IO_LINES_MASK;
- if (!pcmcia_request_io(p_dev, &p_dev->io)) {
- *base2 = p_dev->io.BasePort2;
+ p_dev->resource[0]->start = cf->io.win[0].base;
+ p_dev->resource[1]->start = cf->io.win[1].base;
+ p_dev->io_lines = cf->io.flags & CISTPL_IO_LINES_MASK;
+ if (!pcmcia_request_io(p_dev)) {
+ *base2 = p_dev->resource[1]->start;
return 0;
}
}
@@ -560,10 +558,10 @@ static int multi_config(struct pcmcia_device *link)
int i, base2 = 0;
/* First, look for a generic full-sized window */
- link->io.NumPorts1 = info->multi * 8;
+ link->resource[0]->end = info->multi * 8;
if (pcmcia_loop_config(link, multi_config_check, &base2)) {
/* If that didn't work, look for two windows */
- link->io.NumPorts1 = link->io.NumPorts2 = 8;
+ link->resource[0]->end = link->resource[1]->end = 8;
info->multi = 2;
if (pcmcia_loop_config(link, multi_config_check_notpicky,
&base2)) {
@@ -599,9 +597,9 @@ static int multi_config(struct pcmcia_device *link)
link->conf.ConfigIndex == 3) {
err = setup_serial(link, info, base2,
link->irq);
- base2 = link->io.BasePort1;
+ base2 = link->resource[0]->start;;
} else {
- err = setup_serial(link, info, link->io.BasePort1,
+ err = setup_serial(link, info, link->resource[0]->start,
link->irq);
}
info->c950ctrl = base2;
@@ -616,7 +614,7 @@ static int multi_config(struct pcmcia_device *link)
return 0;
}
- setup_serial(link, info, link->io.BasePort1, link->irq);
+ setup_serial(link, info, link->resource[0]->start, link->irq);
for (i = 0; i < info->multi - 1; i++)
setup_serial(link, info, base2 + (8 * i),
link->irq);
diff --git a/drivers/serial/sn_console.c b/drivers/serial/sn_console.c
index 9794e0cd3dc..7e5e5efea4e 100644
--- a/drivers/serial/sn_console.c
+++ b/drivers/serial/sn_console.c
@@ -470,7 +470,7 @@ sn_receive_chars(struct sn_cons_port *port, unsigned long flags)
}
if (port->sc_port.state) {
- /* The serial_core stuffs are initilized, use them */
+ /* The serial_core stuffs are initialized, use them */
tty = port->sc_port.state->port.tty;
}
else {
@@ -551,11 +551,11 @@ static void sn_transmit_chars(struct sn_cons_port *port, int raw)
BUG_ON(!port->sc_is_asynch);
if (port->sc_port.state) {
- /* We're initilized, using serial core infrastructure */
+ /* We're initialized, using serial core infrastructure */
xmit = &port->sc_port.state->xmit;
} else {
/* Probably sn_sal_switch_to_asynch has been run but serial core isn't
- * initilized yet. Just return. Writes are going through
+ * initialized yet. Just return. Writes are going through
* sn_sal_console_write (due to register_console) at this time.
*/
return;
diff --git a/drivers/serial/sunhv.c b/drivers/serial/sunhv.c
index 890f9174296..a779e22d213 100644
--- a/drivers/serial/sunhv.c
+++ b/drivers/serial/sunhv.c
@@ -525,7 +525,7 @@ static int __devinit hv_probe(struct of_device *op, const struct of_device_id *m
unsigned long minor;
int err;
- if (op->irqs[0] == 0xffffffff)
+ if (op->archdata.irqs[0] == 0xffffffff)
return -ENODEV;
port = kzalloc(sizeof(struct uart_port), GFP_KERNEL);
@@ -557,7 +557,7 @@ static int __devinit hv_probe(struct of_device *op, const struct of_device_id *m
port->membase = (unsigned char __iomem *) __pa(port);
- port->irq = op->irqs[0];
+ port->irq = op->archdata.irqs[0];
port->dev = &op->dev;
@@ -644,12 +644,12 @@ static int __init sunhv_init(void)
if (tlb_type != hypervisor)
return -ENODEV;
- return of_register_driver(&hv_driver, &of_bus_type);
+ return of_register_platform_driver(&hv_driver);
}
static void __exit sunhv_exit(void)
{
- of_unregister_driver(&hv_driver);
+ of_unregister_platform_driver(&hv_driver);
}
module_init(sunhv_init);
diff --git a/drivers/serial/sunsab.c b/drivers/serial/sunsab.c
index 5e81bc6b48b..9845fb1cfb1 100644
--- a/drivers/serial/sunsab.c
+++ b/drivers/serial/sunsab.c
@@ -969,7 +969,7 @@ static int __devinit sunsab_init_one(struct uart_sunsab_port *up,
return -ENOMEM;
up->regs = (union sab82532_async_regs __iomem *) up->port.membase;
- up->port.irq = op->irqs[0];
+ up->port.irq = op->archdata.irqs[0];
up->port.fifosize = SAB82532_XMIT_FIFO_SIZE;
up->port.iotype = UPIO_MEM;
@@ -1130,12 +1130,12 @@ static int __init sunsab_init(void)
}
}
- return of_register_driver(&sab_driver, &of_bus_type);
+ return of_register_platform_driver(&sab_driver);
}
static void __exit sunsab_exit(void)
{
- of_unregister_driver(&sab_driver);
+ of_unregister_platform_driver(&sab_driver);
if (sunsab_reg.nr) {
sunserial_unregister_minors(&sunsab_reg, sunsab_reg.nr);
}
diff --git a/drivers/serial/sunsu.c b/drivers/serial/sunsu.c
index ffbf4553f66..3cdf74822db 100644
--- a/drivers/serial/sunsu.c
+++ b/drivers/serial/sunsu.c
@@ -1443,7 +1443,7 @@ static int __devinit su_probe(struct of_device *op, const struct of_device_id *m
return -ENOMEM;
}
- up->port.irq = op->irqs[0];
+ up->port.irq = op->archdata.irqs[0];
up->port.dev = &op->dev;
@@ -1586,7 +1586,7 @@ static int __init sunsu_init(void)
return err;
}
- err = of_register_driver(&su_driver, &of_bus_type);
+ err = of_register_platform_driver(&su_driver);
if (err && num_uart)
sunserial_unregister_minors(&sunsu_reg, num_uart);
diff --git a/drivers/serial/sunzilog.c b/drivers/serial/sunzilog.c
index f9a24f4ebb3..d1e6bcb5954 100644
--- a/drivers/serial/sunzilog.c
+++ b/drivers/serial/sunzilog.c
@@ -1426,7 +1426,7 @@ static int __devinit zs_probe(struct of_device *op, const struct of_device_id *m
rp = sunzilog_chip_regs[inst];
if (zilog_irq == -1)
- zilog_irq = op->irqs[0];
+ zilog_irq = op->archdata.irqs[0];
up = &sunzilog_port_table[inst * 2];
@@ -1434,7 +1434,7 @@ static int __devinit zs_probe(struct of_device *op, const struct of_device_id *m
up[0].port.mapbase = op->resource[0].start + 0x00;
up[0].port.membase = (void __iomem *) &rp->channelA;
up[0].port.iotype = UPIO_MEM;
- up[0].port.irq = op->irqs[0];
+ up[0].port.irq = op->archdata.irqs[0];
up[0].port.uartclk = ZS_CLOCK;
up[0].port.fifosize = 1;
up[0].port.ops = &sunzilog_pops;
@@ -1451,7 +1451,7 @@ static int __devinit zs_probe(struct of_device *op, const struct of_device_id *m
up[1].port.mapbase = op->resource[0].start + 0x04;
up[1].port.membase = (void __iomem *) &rp->channelB;
up[1].port.iotype = UPIO_MEM;
- up[1].port.irq = op->irqs[0];
+ up[1].port.irq = op->archdata.irqs[0];
up[1].port.uartclk = ZS_CLOCK;
up[1].port.fifosize = 1;
up[1].port.ops = &sunzilog_pops;
@@ -1492,12 +1492,12 @@ static int __devinit zs_probe(struct of_device *op, const struct of_device_id *m
"is a %s\n",
dev_name(&op->dev),
(unsigned long long) up[0].port.mapbase,
- op->irqs[0], sunzilog_type(&up[0].port));
+ op->archdata.irqs[0], sunzilog_type(&up[0].port));
printk(KERN_INFO "%s: Mouse at MMIO 0x%llx (irq = %d) "
"is a %s\n",
dev_name(&op->dev),
(unsigned long long) up[1].port.mapbase,
- op->irqs[0], sunzilog_type(&up[1].port));
+ op->archdata.irqs[0], sunzilog_type(&up[1].port));
kbm_inst++;
}
@@ -1576,7 +1576,7 @@ static int __init sunzilog_init(void)
goto out_free_tables;
}
- err = of_register_driver(&zs_driver, &of_bus_type);
+ err = of_register_platform_driver(&zs_driver);
if (err)
goto out_unregister_uart;
@@ -1604,7 +1604,7 @@ out:
return err;
out_unregister_driver:
- of_unregister_driver(&zs_driver);
+ of_unregister_platform_driver(&zs_driver);
out_unregister_uart:
if (num_sunzilog) {
@@ -1619,7 +1619,7 @@ out_free_tables:
static void __exit sunzilog_exit(void)
{
- of_unregister_driver(&zs_driver);
+ of_unregister_platform_driver(&zs_driver);
if (zilog_irq != -1) {
struct uart_sunzilog_port *up = sunzilog_irq_chain;
diff --git a/drivers/serial/uartlite.c b/drivers/serial/uartlite.c
index 8acccd56437..caf085d3a76 100644
--- a/drivers/serial/uartlite.c
+++ b/drivers/serial/uartlite.c
@@ -21,6 +21,7 @@
#include <asm/io.h>
#if defined(CONFIG_OF) && (defined(CONFIG_PPC32) || defined(CONFIG_MICROBLAZE))
#include <linux/of.h>
+#include <linux/of_address.h>
#include <linux/of_device.h>
#include <linux/of_platform.h>
diff --git a/drivers/spi/mpc512x_psc_spi.c b/drivers/spi/mpc512x_psc_spi.c
index 2534b1ec3ed..10baac3f8ea 100644
--- a/drivers/spi/mpc512x_psc_spi.c
+++ b/drivers/spi/mpc512x_psc_spi.c
@@ -19,6 +19,7 @@
#include <linux/init.h>
#include <linux/errno.h>
#include <linux/interrupt.h>
+#include <linux/of_address.h>
#include <linux/of_platform.h>
#include <linux/workqueue.h>
#include <linux/completion.h>
@@ -440,6 +441,7 @@ static int __init mpc512x_psc_spi_do_probe(struct device *dev, u32 regaddr,
master->setup = mpc512x_psc_spi_setup;
master->transfer = mpc512x_psc_spi_transfer;
master->cleanup = mpc512x_psc_spi_cleanup;
+ master->dev.of_node = dev->of_node;
tempp = ioremap(regaddr, size);
if (!tempp) {
diff --git a/drivers/spi/mpc52xx_psc_spi.c b/drivers/spi/mpc52xx_psc_spi.c
index 7104cb739da..66d170147dc 100644
--- a/drivers/spi/mpc52xx_psc_spi.c
+++ b/drivers/spi/mpc52xx_psc_spi.c
@@ -16,8 +16,8 @@
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/interrupt.h>
+#include <linux/of_address.h>
#include <linux/of_platform.h>
-#include <linux/of_spi.h>
#include <linux/workqueue.h>
#include <linux/completion.h>
#include <linux/io.h>
@@ -398,6 +398,7 @@ static int __init mpc52xx_psc_spi_do_probe(struct device *dev, u32 regaddr,
master->setup = mpc52xx_psc_spi_setup;
master->transfer = mpc52xx_psc_spi_transfer;
master->cleanup = mpc52xx_psc_spi_cleanup;
+ master->dev.of_node = dev->of_node;
mps->psc = ioremap(regaddr, size);
if (!mps->psc) {
@@ -470,7 +471,6 @@ static int __init mpc52xx_psc_spi_of_probe(struct of_device *op,
const u32 *regaddr_p;
u64 regaddr64, size64;
s16 id = -1;
- int rc;
regaddr_p = of_get_address(op->dev.of_node, 0, &size64, NULL);
if (!regaddr_p) {
@@ -491,13 +491,8 @@ static int __init mpc52xx_psc_spi_of_probe(struct of_device *op,
id = *psc_nump + 1;
}
- rc = mpc52xx_psc_spi_do_probe(&op->dev, (u32)regaddr64, (u32)size64,
+ return mpc52xx_psc_spi_do_probe(&op->dev, (u32)regaddr64, (u32)size64,
irq_of_parse_and_map(op->dev.of_node, 0), id);
- if (rc == 0)
- of_register_spi_devices(dev_get_drvdata(&op->dev),
- op->dev.of_node);
-
- return rc;
}
static int __exit mpc52xx_psc_spi_of_remove(struct of_device *op)
diff --git a/drivers/spi/mpc52xx_spi.c b/drivers/spi/mpc52xx_spi.c
index b1a76bff775..56136ff00e0 100644
--- a/drivers/spi/mpc52xx_spi.c
+++ b/drivers/spi/mpc52xx_spi.c
@@ -18,7 +18,6 @@
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/spi/spi.h>
-#include <linux/of_spi.h>
#include <linux/io.h>
#include <linux/of_gpio.h>
#include <linux/slab.h>
@@ -439,6 +438,7 @@ static int __devinit mpc52xx_spi_probe(struct of_device *op,
master->setup = mpc52xx_spi_setup;
master->transfer = mpc52xx_spi_transfer;
master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST;
+ master->dev.of_node = op->dev.of_node;
dev_set_drvdata(&op->dev, master);
@@ -512,7 +512,6 @@ static int __devinit mpc52xx_spi_probe(struct of_device *op,
if (rc)
goto err_register;
- of_register_spi_devices(master, op->dev.of_node);
dev_info(&ms->master->dev, "registered MPC5200 SPI bus\n");
return rc;
diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
index b3a1f9259b6..1bb1b88780c 100644
--- a/drivers/spi/spi.c
+++ b/drivers/spi/spi.c
@@ -26,6 +26,7 @@
#include <linux/slab.h>
#include <linux/mod_devicetable.h>
#include <linux/spi/spi.h>
+#include <linux/of_spi.h>
/* SPI bustype and spi_master class are registered after board init code
@@ -540,6 +541,9 @@ int spi_register_master(struct spi_master *master)
/* populate children from any spi device tables */
scan_boardinfo(master);
status = 0;
+
+ /* Register devices from the device tree */
+ of_register_spi_devices(master);
done:
return status;
}
diff --git a/drivers/spi/spi_mpc8xxx.c b/drivers/spi/spi_mpc8xxx.c
index 97ab0a81338..aad9ae1b9c6 100644
--- a/drivers/spi/spi_mpc8xxx.c
+++ b/drivers/spi/spi_mpc8xxx.c
@@ -38,7 +38,6 @@
#include <linux/of_platform.h>
#include <linux/gpio.h>
#include <linux/of_gpio.h>
-#include <linux/of_spi.h>
#include <linux/slab.h>
#include <sysdev/fsl_soc.h>
@@ -1009,6 +1008,7 @@ mpc8xxx_spi_probe(struct device *dev, struct resource *mem, unsigned int irq)
master->setup = mpc8xxx_spi_setup;
master->transfer = mpc8xxx_spi_transfer;
master->cleanup = mpc8xxx_spi_cleanup;
+ master->dev.of_node = dev->of_node;
mpc8xxx_spi = spi_master_get_devdata(master);
mpc8xxx_spi->dev = dev;
@@ -1299,8 +1299,6 @@ static int __devinit of_mpc8xxx_spi_probe(struct of_device *ofdev,
goto err;
}
- of_register_spi_devices(master, np);
-
return 0;
err:
diff --git a/drivers/spi/spi_ppc4xx.c b/drivers/spi/spi_ppc4xx.c
index d53466a249d..0f5fa7e2a55 100644
--- a/drivers/spi/spi_ppc4xx.c
+++ b/drivers/spi/spi_ppc4xx.c
@@ -407,6 +407,7 @@ static int __init spi_ppc4xx_of_probe(struct of_device *op,
master = spi_alloc_master(dev, sizeof *hw);
if (master == NULL)
return -ENOMEM;
+ master->dev.of_node = np;
dev_set_drvdata(dev, master);
hw = spi_master_get_devdata(master);
hw->master = spi_master_get(master);
@@ -545,7 +546,6 @@ static int __init spi_ppc4xx_of_probe(struct of_device *op,
}
dev_info(dev, "driver initialized\n");
- of_register_spi_devices(master, np);
return 0;
diff --git a/drivers/spi/xilinx_spi.c b/drivers/spi/xilinx_spi.c
index 1b47363cb73..80f2db5bcfd 100644
--- a/drivers/spi/xilinx_spi.c
+++ b/drivers/spi/xilinx_spi.c
@@ -390,6 +390,9 @@ struct spi_master *xilinx_spi_init(struct device *dev, struct resource *mem,
master->bus_num = bus_num;
master->num_chipselect = pdata->num_chipselect;
+#ifdef CONFIG_OF
+ master->dev.of_node = dev->of_node;
+#endif
xspi->mem = *mem;
xspi->irq = irq;
diff --git a/drivers/spi/xilinx_spi_of.c b/drivers/spi/xilinx_spi_of.c
index 4654805b08d..f53d3f6b9f6 100644
--- a/drivers/spi/xilinx_spi_of.c
+++ b/drivers/spi/xilinx_spi_of.c
@@ -29,6 +29,7 @@
#include <linux/io.h>
#include <linux/slab.h>
+#include <linux/of_address.h>
#include <linux/of_platform.h>
#include <linux/of_device.h>
#include <linux/of_spi.h>
@@ -80,9 +81,6 @@ static int __devinit xilinx_spi_of_probe(struct of_device *ofdev,
dev_set_drvdata(&ofdev->dev, master);
- /* Add any subnodes on the SPI bus */
- of_register_spi_devices(master, ofdev->dev.of_node);
-
return 0;
}
diff --git a/drivers/ssb/driver_chipcommon.c b/drivers/ssb/driver_chipcommon.c
index 59ae76bace1..7c031fdc820 100644
--- a/drivers/ssb/driver_chipcommon.c
+++ b/drivers/ssb/driver_chipcommon.c
@@ -209,6 +209,24 @@ static void chipco_powercontrol_init(struct ssb_chipcommon *cc)
}
}
+/* http://bcm-v4.sipsolutions.net/802.11/PmuFastPwrupDelay */
+static u16 pmu_fast_powerup_delay(struct ssb_chipcommon *cc)
+{
+ struct ssb_bus *bus = cc->dev->bus;
+
+ switch (bus->chip_id) {
+ case 0x4312:
+ case 0x4322:
+ case 0x4328:
+ return 7000;
+ case 0x4325:
+ /* TODO: */
+ default:
+ return 15000;
+ }
+}
+
+/* http://bcm-v4.sipsolutions.net/802.11/ClkctlFastPwrupDelay */
static void calc_fast_powerup_delay(struct ssb_chipcommon *cc)
{
struct ssb_bus *bus = cc->dev->bus;
@@ -218,6 +236,12 @@ static void calc_fast_powerup_delay(struct ssb_chipcommon *cc)
if (bus->bustype != SSB_BUSTYPE_PCI)
return;
+
+ if (cc->capabilities & SSB_CHIPCO_CAP_PMU) {
+ cc->fast_pwrup_delay = pmu_fast_powerup_delay(cc);
+ return;
+ }
+
if (!(cc->capabilities & SSB_CHIPCO_CAP_PCTL))
return;
@@ -235,6 +259,7 @@ void ssb_chipcommon_init(struct ssb_chipcommon *cc)
return; /* We don't have a ChipCommon */
if (cc->dev->id.revision >= 11)
cc->status = chipco_read32(cc, SSB_CHIPCO_CHIPSTAT);
+ ssb_dprintk(KERN_INFO PFX "chipcommon status is 0x%x\n", cc->status);
ssb_pmu_init(cc);
chipco_powercontrol_init(cc);
ssb_chipco_set_clockmode(cc, SSB_CLKMODE_FAST);
diff --git a/drivers/ssb/driver_chipcommon_pmu.c b/drivers/ssb/driver_chipcommon_pmu.c
index 3d551245a4e..5732bb2c357 100644
--- a/drivers/ssb/driver_chipcommon_pmu.c
+++ b/drivers/ssb/driver_chipcommon_pmu.c
@@ -502,9 +502,9 @@ static void ssb_pmu_resources_init(struct ssb_chipcommon *cc)
chipco_write32(cc, SSB_CHIPCO_PMU_MAXRES_MSK, max_msk);
}
+/* http://bcm-v4.sipsolutions.net/802.11/SSB/PmuInit */
void ssb_pmu_init(struct ssb_chipcommon *cc)
{
- struct ssb_bus *bus = cc->dev->bus;
u32 pmucap;
if (!(cc->capabilities & SSB_CHIPCO_CAP_PMU))
@@ -516,15 +516,12 @@ void ssb_pmu_init(struct ssb_chipcommon *cc)
ssb_dprintk(KERN_DEBUG PFX "Found rev %u PMU (capabilities 0x%08X)\n",
cc->pmu.rev, pmucap);
- if (cc->pmu.rev >= 1) {
- if ((bus->chip_id == 0x4325) && (bus->chip_rev < 2)) {
- chipco_mask32(cc, SSB_CHIPCO_PMU_CTL,
- ~SSB_CHIPCO_PMU_CTL_NOILPONW);
- } else {
- chipco_set32(cc, SSB_CHIPCO_PMU_CTL,
- SSB_CHIPCO_PMU_CTL_NOILPONW);
- }
- }
+ if (cc->pmu.rev == 1)
+ chipco_mask32(cc, SSB_CHIPCO_PMU_CTL,
+ ~SSB_CHIPCO_PMU_CTL_NOILPONW);
+ else
+ chipco_set32(cc, SSB_CHIPCO_PMU_CTL,
+ SSB_CHIPCO_PMU_CTL_NOILPONW);
ssb_pmu_pll_init(cc);
ssb_pmu_resources_init(cc);
}
diff --git a/drivers/ssb/main.c b/drivers/ssb/main.c
index 51275aac5b3..7892ac16352 100644
--- a/drivers/ssb/main.c
+++ b/drivers/ssb/main.c
@@ -20,7 +20,6 @@
#include <linux/mmc/sdio_func.h>
#include <linux/slab.h>
-#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/cistpl.h>
#include <pcmcia/ds.h>
@@ -486,6 +485,7 @@ static int ssb_devices_register(struct ssb_bus *bus)
#ifdef CONFIG_SSB_PCIHOST
sdev->irq = bus->host_pci->irq;
dev->parent = &bus->host_pci->dev;
+ sdev->dma_dev = dev->parent;
#endif
break;
case SSB_BUSTYPE_PCMCIA:
@@ -501,6 +501,7 @@ static int ssb_devices_register(struct ssb_bus *bus)
break;
case SSB_BUSTYPE_SSB:
dev->dma_mask = &dev->coherent_dma_mask;
+ sdev->dma_dev = dev;
break;
}
@@ -1226,80 +1227,6 @@ u32 ssb_dma_translation(struct ssb_device *dev)
}
EXPORT_SYMBOL(ssb_dma_translation);
-int ssb_dma_set_mask(struct ssb_device *dev, u64 mask)
-{
-#ifdef CONFIG_SSB_PCIHOST
- int err;
-#endif
-
- switch (dev->bus->bustype) {
- case SSB_BUSTYPE_PCI:
-#ifdef CONFIG_SSB_PCIHOST
- err = pci_set_dma_mask(dev->bus->host_pci, mask);
- if (err)
- return err;
- err = pci_set_consistent_dma_mask(dev->bus->host_pci, mask);
- return err;
-#endif
- case SSB_BUSTYPE_SSB:
- return dma_set_mask(dev->dev, mask);
- default:
- __ssb_dma_not_implemented(dev);
- }
- return -ENOSYS;
-}
-EXPORT_SYMBOL(ssb_dma_set_mask);
-
-void * ssb_dma_alloc_consistent(struct ssb_device *dev, size_t size,
- dma_addr_t *dma_handle, gfp_t gfp_flags)
-{
- switch (dev->bus->bustype) {
- case SSB_BUSTYPE_PCI:
-#ifdef CONFIG_SSB_PCIHOST
- if (gfp_flags & GFP_DMA) {
- /* Workaround: The PCI API does not support passing
- * a GFP flag. */
- return dma_alloc_coherent(&dev->bus->host_pci->dev,
- size, dma_handle, gfp_flags);
- }
- return pci_alloc_consistent(dev->bus->host_pci, size, dma_handle);
-#endif
- case SSB_BUSTYPE_SSB:
- return dma_alloc_coherent(dev->dev, size, dma_handle, gfp_flags);
- default:
- __ssb_dma_not_implemented(dev);
- }
- return NULL;
-}
-EXPORT_SYMBOL(ssb_dma_alloc_consistent);
-
-void ssb_dma_free_consistent(struct ssb_device *dev, size_t size,
- void *vaddr, dma_addr_t dma_handle,
- gfp_t gfp_flags)
-{
- switch (dev->bus->bustype) {
- case SSB_BUSTYPE_PCI:
-#ifdef CONFIG_SSB_PCIHOST
- if (gfp_flags & GFP_DMA) {
- /* Workaround: The PCI API does not support passing
- * a GFP flag. */
- dma_free_coherent(&dev->bus->host_pci->dev,
- size, vaddr, dma_handle);
- return;
- }
- pci_free_consistent(dev->bus->host_pci, size,
- vaddr, dma_handle);
- return;
-#endif
- case SSB_BUSTYPE_SSB:
- dma_free_coherent(dev->dev, size, vaddr, dma_handle);
- return;
- default:
- __ssb_dma_not_implemented(dev);
- }
-}
-EXPORT_SYMBOL(ssb_dma_free_consistent);
-
int ssb_bus_may_powerdown(struct ssb_bus *bus)
{
struct ssb_chipcommon *cc;
diff --git a/drivers/ssb/pci.c b/drivers/ssb/pci.c
index 6dcda86be6e..6e88d2b603b 100644
--- a/drivers/ssb/pci.c
+++ b/drivers/ssb/pci.c
@@ -626,11 +626,22 @@ static int ssb_pci_sprom_get(struct ssb_bus *bus,
return -ENODEV;
}
if (bus->chipco.dev) { /* can be unavailible! */
- bus->sprom_offset = (bus->chipco.dev->id.revision < 31) ?
- SSB_SPROM_BASE1 : SSB_SPROM_BASE31;
+ /*
+ * get SPROM offset: SSB_SPROM_BASE1 except for
+ * chipcommon rev >= 31 or chip ID is 0x4312 and
+ * chipcommon status & 3 == 2
+ */
+ if (bus->chipco.dev->id.revision >= 31)
+ bus->sprom_offset = SSB_SPROM_BASE31;
+ else if (bus->chip_id == 0x4312 &&
+ (bus->chipco.status & 0x03) == 2)
+ bus->sprom_offset = SSB_SPROM_BASE31;
+ else
+ bus->sprom_offset = SSB_SPROM_BASE1;
} else {
bus->sprom_offset = SSB_SPROM_BASE1;
}
+ ssb_dprintk(KERN_INFO PFX "SPROM offset is 0x%x\n", bus->sprom_offset);
buf = kcalloc(SSB_SPROMSIZE_WORDS_R123, sizeof(u16), GFP_KERNEL);
if (!buf)
diff --git a/drivers/ssb/pcmcia.c b/drivers/ssb/pcmcia.c
index e72f4046a5e..526682d68de 100644
--- a/drivers/ssb/pcmcia.c
+++ b/drivers/ssb/pcmcia.c
@@ -13,7 +13,6 @@
#include <linux/io.h>
#include <linux/etherdevice.h>
-#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/cistpl.h>
#include <pcmcia/ciscode.h>
@@ -72,14 +71,9 @@
/* Write to a PCMCIA configuration register. */
static int ssb_pcmcia_cfg_write(struct ssb_bus *bus, u8 offset, u8 value)
{
- conf_reg_t reg;
int res;
- memset(&reg, 0, sizeof(reg));
- reg.Offset = offset;
- reg.Action = CS_WRITE;
- reg.Value = value;
- res = pcmcia_access_configuration_register(bus->host_pcmcia, &reg);
+ res = pcmcia_write_config_byte(bus->host_pcmcia, offset, value);
if (unlikely(res != 0))
return -EBUSY;
@@ -89,16 +83,11 @@ static int ssb_pcmcia_cfg_write(struct ssb_bus *bus, u8 offset, u8 value)
/* Read from a PCMCIA configuration register. */
static int ssb_pcmcia_cfg_read(struct ssb_bus *bus, u8 offset, u8 *value)
{
- conf_reg_t reg;
int res;
- memset(&reg, 0, sizeof(reg));
- reg.Offset = offset;
- reg.Action = CS_READ;
- res = pcmcia_access_configuration_register(bus->host_pcmcia, &reg);
+ res = pcmcia_read_config_byte(bus->host_pcmcia, offset, value);
if (unlikely(res != 0))
return -EBUSY;
- *value = reg.Value;
return 0;
}
diff --git a/drivers/ssb/scan.c b/drivers/ssb/scan.c
index 0d6c0280eb3..9738cad4ba1 100644
--- a/drivers/ssb/scan.c
+++ b/drivers/ssb/scan.c
@@ -17,7 +17,6 @@
#include <linux/pci.h>
#include <linux/io.h>
-#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/cistpl.h>
#include <pcmcia/ds.h>
diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig
index 984a7544071..4a7a7a7f11b 100644
--- a/drivers/staging/Kconfig
+++ b/drivers/staging/Kconfig
@@ -97,6 +97,8 @@ source "drivers/staging/octeon/Kconfig"
source "drivers/staging/serqt_usb2/Kconfig"
+source "drivers/staging/spectra/Kconfig"
+
source "drivers/staging/quatech_usb2/Kconfig"
source "drivers/staging/vt6655/Kconfig"
@@ -109,15 +111,13 @@ source "drivers/staging/hv/Kconfig"
source "drivers/staging/vme/Kconfig"
-source "drivers/staging/rar_register/Kconfig"
-
source "drivers/staging/memrar/Kconfig"
source "drivers/staging/sep/Kconfig"
source "drivers/staging/iio/Kconfig"
-source "drivers/staging/ramzswap/Kconfig"
+source "drivers/staging/zram/Kconfig"
source "drivers/staging/wlags49_h2/Kconfig"
@@ -129,8 +129,6 @@ source "drivers/staging/samsung-laptop/Kconfig"
source "drivers/staging/sm7xx/Kconfig"
-source "drivers/staging/dt3155/Kconfig"
-
source "drivers/staging/dt3155v4l/Kconfig"
source "drivers/staging/crystalhd/Kconfig"
@@ -147,5 +145,15 @@ source "drivers/staging/mrst-touchscreen/Kconfig"
source "drivers/staging/msm/Kconfig"
+source "drivers/staging/lirc/Kconfig"
+
+source "drivers/staging/easycap/Kconfig"
+
+source "drivers/staging/solo6x10/Kconfig"
+
+source "drivers/staging/tidspbridge/Kconfig"
+
+source "drivers/staging/quickstart/Kconfig"
+
endif # !STAGING_EXCLUDE_BUILD
endif # STAGING
diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile
index 9fa25133874..ca5c03eb3ce 100644
--- a/drivers/staging/Makefile
+++ b/drivers/staging/Makefile
@@ -8,6 +8,7 @@ obj-$(CONFIG_SLICOSS) += slicoss/
obj-$(CONFIG_VIDEO_GO7007) += go7007/
obj-$(CONFIG_VIDEO_CX25821) += cx25821/
obj-$(CONFIG_VIDEO_TM6000) += tm6000/
+obj-$(CONFIG_LIRC_STAGING) += lirc/
obj-$(CONFIG_USB_IP_COMMON) += usbip/
obj-$(CONFIG_W35UND) += winbond/
obj-$(CONFIG_PRISM2_USB) += wlan-ng/
@@ -22,6 +23,7 @@ obj-$(CONFIG_R8187SE) += rtl8187se/
obj-$(CONFIG_RTL8192SU) += rtl8192su/
obj-$(CONFIG_RTL8192U) += rtl8192u/
obj-$(CONFIG_RTL8192E) += rtl8192e/
+obj-$(CONFIG_SPECTRA) += spectra/
obj-$(CONFIG_TRANZPORT) += frontier/
obj-$(CONFIG_DREAM) += dream/
obj-$(CONFIG_POHMELFS) += pohmelfs/
@@ -35,17 +37,15 @@ obj-$(CONFIG_VT6656) += vt6656/
obj-$(CONFIG_FB_UDL) += udlfb/
obj-$(CONFIG_HYPERV) += hv/
obj-$(CONFIG_VME_BUS) += vme/
-obj-$(CONFIG_RAR_REGISTER) += rar_register/
obj-$(CONFIG_MRST_RAR_HANDLER) += memrar/
obj-$(CONFIG_DX_SEP) += sep/
obj-$(CONFIG_IIO) += iio/
-obj-$(CONFIG_RAMZSWAP) += ramzswap/
+obj-$(CONFIG_ZRAM) += zram/
obj-$(CONFIG_WLAGS49_H2) += wlags49_h2/
obj-$(CONFIG_WLAGS49_H25) += wlags49_h25/
obj-$(CONFIG_BATMAN_ADV) += batman-adv/
obj-$(CONFIG_SAMSUNG_LAPTOP) += samsung-laptop/
obj-$(CONFIG_FB_SM7XX) += sm7xx/
-obj-$(CONFIG_DT3155) += dt3155/
obj-$(CONFIG_VIDEO_DT3155) += dt3155v4l/
obj-$(CONFIG_CRYSTALHD) += crystalhd/
obj-$(CONFIG_CXT1E1) += cxt1e1/
@@ -54,3 +54,7 @@ obj-$(CONFIG_ADIS16255) += adis16255/
obj-$(CONFIG_FB_XGI) += xgifb/
obj-$(CONFIG_TOUCHSCREEN_MRSTOUCH) += mrst-touchscreen/
obj-$(CONFIG_MSM_STAGING) += msm/
+obj-$(CONFIG_EASYCAP) += easycap/
+obj-$(CONFIG_SOLO6X10) += solo6x10/
+obj-$(CONFIG_TIDSPBRIDGE) += tidspbridge/
+obj-$(CONFIG_ACPI_QUICKSTART) += quickstart/
diff --git a/drivers/staging/adis16255/adis16255.c b/drivers/staging/adis16255/adis16255.c
index 55d66e290f7..c3e6a4d5f33 100644
--- a/drivers/staging/adis16255/adis16255.c
+++ b/drivers/staging/adis16255/adis16255.c
@@ -303,7 +303,7 @@ static int spi_adis16255_bringup(struct spi_adis16255_data *spiadis)
if (status != 0)
goto err;
if (value != 0x0800) {
- dev_warn(&spiadis->spi->dev, "Scale factor is none default"
+ dev_warn(&spiadis->spi->dev, "Scale factor is none default "
"value (%.4x)\n", value);
}
@@ -338,7 +338,7 @@ static int spi_adis16255_bringup(struct spi_adis16255_data *spiadis)
status = -ENODEV;
goto err;
} else if (value & 0x3) {
- dev_warn(&spiadis->spi->dev, "Sensor voltage"
+ dev_warn(&spiadis->spi->dev, "Sensor voltage "
"out of range.\n");
status = -ENODEV;
goto err;
diff --git a/drivers/staging/batman-adv/CHANGELOG b/drivers/staging/batman-adv/CHANGELOG
index c8f9d9e06bb..86450b4f7d7 100644
--- a/drivers/staging/batman-adv/CHANGELOG
+++ b/drivers/staging/batman-adv/CHANGELOG
@@ -1,3 +1,15 @@
+batman-adv 2010.0.0:
+
+* support latest kernels (2.6.21 - 2.6.35)
+* further code refactoring and cleaning for coding style
+* move from procfs based configuration to sysfs
+* reorganized sequence number handling
+* limit queue lengths for batman and broadcast packets
+* many bugs (endless loop and rogue packets on shutdown, wrong tcpdump output,
+ missing frees in error situations, sleeps in atomic contexts) squashed
+
+ -- Fri, 18 Jun 2010 21:34:26 +0200
+
batman-adv 0.2.1:
* support latest kernels (2.6.20 - 2.6.33)
diff --git a/drivers/staging/batman-adv/Kconfig b/drivers/staging/batman-adv/Kconfig
index 1e7e0a8dbc8..8553f351745 100644
--- a/drivers/staging/batman-adv/Kconfig
+++ b/drivers/staging/batman-adv/Kconfig
@@ -4,7 +4,7 @@
config BATMAN_ADV
tristate "B.A.T.M.A.N. Advanced Meshing Protocol"
- depends on PROC_FS && NET
+ depends on NET
default n
---help---
diff --git a/drivers/staging/batman-adv/Makefile b/drivers/staging/batman-adv/Makefile
index f25068c0fae..e9817b5a614 100644
--- a/drivers/staging/batman-adv/Makefile
+++ b/drivers/staging/batman-adv/Makefile
@@ -18,5 +18,5 @@
# 02110-1301, USA
#
-obj-m += batman-adv.o
-batman-adv-objs := main.o send.o routing.o soft-interface.o device.o translation-table.o bitarray.o hash.o ring_buffer.o vis.o hard-interface.o aggregation.o originator.o bat_sysfs.o
+obj-$(CONFIG_BATMAN_ADV) += batman-adv.o
+batman-adv-objs := main.o bat_debugfs.o bat_sysfs.o send.o routing.o soft-interface.o icmp_socket.o translation-table.o bitarray.o hash.o ring_buffer.o vis.o hard-interface.o aggregation.o originator.o
diff --git a/drivers/staging/batman-adv/README b/drivers/staging/batman-adv/README
index 14244a2c4e4..7192b7fa218 100644
--- a/drivers/staging/batman-adv/README
+++ b/drivers/staging/batman-adv/README
@@ -1,4 +1,4 @@
-[state: 03-05-2010]
+[state: 12-06-2010]
BATMAN-ADV
----------
diff --git a/drivers/staging/batman-adv/TODO b/drivers/staging/batman-adv/TODO
index 518db7fd41b..9c5aea20be1 100644
--- a/drivers/staging/batman-adv/TODO
+++ b/drivers/staging/batman-adv/TODO
@@ -1,6 +1,9 @@
-Request a review.
-Process the comments from the review.
-Move into mainline proper.
+ * Use hweight* for hamming weight calculation
+ * Save/cache packets direktly as skb instead of using a normal memory region
+ and copying it in a skb using send_raw_packet and similar functions
+ * Request a new review
+ * Process the comments from the review
+ * Move into mainline proper
Please send all patches to:
Marek Lindner <lindner_marek@yahoo.de>
diff --git a/drivers/staging/batman-adv/aggregation.c b/drivers/staging/batman-adv/aggregation.c
index ce8b8a6e5ae..9862d16bbdc 100644
--- a/drivers/staging/batman-adv/aggregation.c
+++ b/drivers/staging/batman-adv/aggregation.c
@@ -106,11 +106,14 @@ static void new_aggregated_packet(unsigned char *packet_buff,
{
struct forw_packet *forw_packet_aggr;
unsigned long flags;
+ /* FIXME: each batman_if will be attached to a softif */
+ struct bat_priv *bat_priv = netdev_priv(soft_device);
/* own packet should always be scheduled */
if (!own_packet) {
if (!atomic_dec_not_zero(&batman_queue_left)) {
- bat_dbg(DBG_BATMAN, "batman packet queue full\n");
+ bat_dbg(DBG_BATMAN, bat_priv,
+ "batman packet queue full\n");
return;
}
}
@@ -252,9 +255,9 @@ void receive_aggr_bat_packet(struct ethhdr *ethhdr, unsigned char *packet_buff,
while (aggregated_packet(buff_pos, packet_len,
batman_packet->num_hna)) {
- /* network to host order for our 16bit seqno, and the
+ /* network to host order for our 32bit seqno, and the
orig_interval. */
- batman_packet->seqno = ntohs(batman_packet->seqno);
+ batman_packet->seqno = ntohl(batman_packet->seqno);
hna_buff = packet_buff + buff_pos + BAT_PACKET_LEN;
receive_bat_packet(ethhdr, batman_packet,
diff --git a/drivers/staging/batman-adv/aggregation.h b/drivers/staging/batman-adv/aggregation.h
index 84401ca24c3..71a91b3da91 100644
--- a/drivers/staging/batman-adv/aggregation.h
+++ b/drivers/staging/batman-adv/aggregation.h
@@ -19,6 +19,9 @@
*
*/
+#ifndef _NET_BATMAN_ADV_AGGREGATION_H_
+#define _NET_BATMAN_ADV_AGGREGATION_H_
+
#include "main.h"
/* is there another aggregated packet here? */
@@ -36,3 +39,5 @@ void add_bat_packet_to_list(struct bat_priv *bat_priv,
unsigned long send_time);
void receive_aggr_bat_packet(struct ethhdr *ethhdr, unsigned char *packet_buff,
int packet_len, struct batman_if *if_incoming);
+
+#endif /* _NET_BATMAN_ADV_AGGREGATION_H_ */
diff --git a/drivers/staging/batman-adv/bat_debugfs.c b/drivers/staging/batman-adv/bat_debugfs.c
new file mode 100644
index 00000000000..507da68054c
--- /dev/null
+++ b/drivers/staging/batman-adv/bat_debugfs.c
@@ -0,0 +1,341 @@
+/*
+ * Copyright (C) 2010 B.A.T.M.A.N. contributors:
+ *
+ * Marek Lindner
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ *
+ */
+
+#include "main.h"
+
+#include <linux/debugfs.h>
+
+#include "bat_debugfs.h"
+#include "translation-table.h"
+#include "originator.h"
+#include "hard-interface.h"
+#include "vis.h"
+#include "icmp_socket.h"
+
+static struct dentry *bat_debugfs;
+
+#ifdef CONFIG_BATMAN_ADV_DEBUG
+#define LOG_BUFF_MASK (log_buff_len-1)
+#define LOG_BUFF(idx) (debug_log->log_buff[(idx) & LOG_BUFF_MASK])
+
+static int log_buff_len = LOG_BUF_LEN;
+
+static void emit_log_char(struct debug_log *debug_log, char c)
+{
+ LOG_BUFF(debug_log->log_end) = c;
+ debug_log->log_end++;
+
+ if (debug_log->log_end - debug_log->log_start > log_buff_len)
+ debug_log->log_start = debug_log->log_end - log_buff_len;
+}
+
+static int fdebug_log(struct debug_log *debug_log, char *fmt, ...)
+{
+ int printed_len;
+ va_list args;
+ static char debug_log_buf[256];
+ char *p;
+ unsigned long flags;
+
+ if (!debug_log)
+ return 0;
+
+ spin_lock_irqsave(&debug_log->lock, flags);
+ va_start(args, fmt);
+ printed_len = vscnprintf(debug_log_buf, sizeof(debug_log_buf),
+ fmt, args);
+ va_end(args);
+
+ for (p = debug_log_buf; *p != 0; p++)
+ emit_log_char(debug_log, *p);
+
+ spin_unlock_irqrestore(&debug_log->lock, flags);
+
+ wake_up(&debug_log->queue_wait);
+
+ return 0;
+}
+
+int debug_log(struct bat_priv *bat_priv, char *fmt, ...)
+{
+ va_list args;
+ char tmp_log_buf[256];
+
+ va_start(args, fmt);
+ vscnprintf(tmp_log_buf, sizeof(tmp_log_buf), fmt, args);
+ fdebug_log(bat_priv->debug_log, "[%10u] %s",
+ (jiffies / HZ), tmp_log_buf);
+ va_end(args);
+
+ return 0;
+}
+
+static int log_open(struct inode *inode, struct file *file)
+{
+ file->private_data = inode->i_private;
+ inc_module_count();
+ return 0;
+}
+
+static int log_release(struct inode *inode, struct file *file)
+{
+ dec_module_count();
+ return 0;
+}
+
+static ssize_t log_read(struct file *file, char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ struct bat_priv *bat_priv = file->private_data;
+ struct debug_log *debug_log = bat_priv->debug_log;
+ int error, i = 0;
+ char c;
+ unsigned long flags;
+
+ if ((file->f_flags & O_NONBLOCK) &&
+ !(debug_log->log_end - debug_log->log_start))
+ return -EAGAIN;
+
+ if ((!buf) || (count < 0))
+ return -EINVAL;
+
+ if (count == 0)
+ return 0;
+
+ if (!access_ok(VERIFY_WRITE, buf, count))
+ return -EFAULT;
+
+ error = wait_event_interruptible(debug_log->queue_wait,
+ (debug_log->log_start - debug_log->log_end));
+
+ if (error)
+ return error;
+
+ spin_lock_irqsave(&debug_log->lock, flags);
+
+ while ((!error) && (i < count) &&
+ (debug_log->log_start != debug_log->log_end)) {
+ c = LOG_BUFF(debug_log->log_start);
+
+ debug_log->log_start++;
+
+ spin_unlock_irqrestore(&debug_log->lock, flags);
+
+ error = __put_user(c, buf);
+
+ spin_lock_irqsave(&debug_log->lock, flags);
+
+ buf++;
+ i++;
+
+ }
+
+ spin_unlock_irqrestore(&debug_log->lock, flags);
+
+ if (!error)
+ return i;
+
+ return error;
+}
+
+static unsigned int log_poll(struct file *file, poll_table *wait)
+{
+ struct bat_priv *bat_priv = file->private_data;
+ struct debug_log *debug_log = bat_priv->debug_log;
+
+ poll_wait(file, &debug_log->queue_wait, wait);
+
+ if (debug_log->log_end - debug_log->log_start)
+ return POLLIN | POLLRDNORM;
+
+ return 0;
+}
+
+static const struct file_operations log_fops = {
+ .open = log_open,
+ .release = log_release,
+ .read = log_read,
+ .poll = log_poll,
+};
+
+static int debug_log_setup(struct bat_priv *bat_priv)
+{
+ struct dentry *d;
+
+ if (!bat_priv->debug_dir)
+ goto err;
+
+ bat_priv->debug_log = kzalloc(sizeof(struct debug_log), GFP_ATOMIC);
+ if (!bat_priv->debug_log)
+ goto err;
+
+ spin_lock_init(&bat_priv->debug_log->lock);
+ init_waitqueue_head(&bat_priv->debug_log->queue_wait);
+
+ d = debugfs_create_file("log", S_IFREG | S_IRUSR,
+ bat_priv->debug_dir, bat_priv, &log_fops);
+ if (d)
+ goto err;
+
+ return 0;
+
+err:
+ return 1;
+}
+
+static void debug_log_cleanup(struct bat_priv *bat_priv)
+{
+ kfree(bat_priv->debug_log);
+ bat_priv->debug_log = NULL;
+}
+#else /* CONFIG_BATMAN_ADV_DEBUG */
+static int debug_log_setup(struct bat_priv *bat_priv)
+{
+ bat_priv->debug_log = NULL;
+ return 0;
+}
+
+static void debug_log_cleanup(struct bat_priv *bat_priv)
+{
+ return;
+}
+#endif
+
+static int originators_open(struct inode *inode, struct file *file)
+{
+ struct net_device *net_dev = (struct net_device *)inode->i_private;
+ return single_open(file, orig_seq_print_text, net_dev);
+}
+
+static int transtable_global_open(struct inode *inode, struct file *file)
+{
+ struct net_device *net_dev = (struct net_device *)inode->i_private;
+ return single_open(file, hna_global_seq_print_text, net_dev);
+}
+
+static int transtable_local_open(struct inode *inode, struct file *file)
+{
+ struct net_device *net_dev = (struct net_device *)inode->i_private;
+ return single_open(file, hna_local_seq_print_text, net_dev);
+}
+
+static int vis_data_open(struct inode *inode, struct file *file)
+{
+ struct net_device *net_dev = (struct net_device *)inode->i_private;
+ return single_open(file, vis_seq_print_text, net_dev);
+}
+
+struct bat_debuginfo {
+ struct attribute attr;
+ const struct file_operations fops;
+};
+
+#define BAT_DEBUGINFO(_name, _mode, _open) \
+struct bat_debuginfo bat_debuginfo_##_name = { \
+ .attr = { .name = __stringify(_name), \
+ .mode = _mode, }, \
+ .fops = { .owner = THIS_MODULE, \
+ .open = _open, \
+ .read = seq_read, \
+ .llseek = seq_lseek, \
+ .release = single_release, \
+ } \
+};
+
+static BAT_DEBUGINFO(originators, S_IRUGO, originators_open);
+static BAT_DEBUGINFO(transtable_global, S_IRUGO, transtable_global_open);
+static BAT_DEBUGINFO(transtable_local, S_IRUGO, transtable_local_open);
+static BAT_DEBUGINFO(vis_data, S_IRUGO, vis_data_open);
+
+static struct bat_debuginfo *mesh_debuginfos[] = {
+ &bat_debuginfo_originators,
+ &bat_debuginfo_transtable_global,
+ &bat_debuginfo_transtable_local,
+ &bat_debuginfo_vis_data,
+ NULL,
+};
+
+void debugfs_init(void)
+{
+ bat_debugfs = debugfs_create_dir(DEBUGFS_BAT_SUBDIR, NULL);
+ if (bat_debugfs == ERR_PTR(-ENODEV))
+ bat_debugfs = NULL;
+}
+
+void debugfs_destroy(void)
+{
+ if (bat_debugfs) {
+ debugfs_remove_recursive(bat_debugfs);
+ bat_debugfs = NULL;
+ }
+}
+
+int debugfs_add_meshif(struct net_device *dev)
+{
+ struct bat_priv *bat_priv = netdev_priv(dev);
+ struct bat_debuginfo **bat_debug;
+ struct dentry *file;
+
+ if (!bat_debugfs)
+ goto out;
+
+ bat_priv->debug_dir = debugfs_create_dir(dev->name, bat_debugfs);
+ if (!bat_priv->debug_dir)
+ goto out;
+
+ bat_socket_setup(bat_priv);
+ debug_log_setup(bat_priv);
+
+ for (bat_debug = mesh_debuginfos; *bat_debug; ++bat_debug) {
+ file = debugfs_create_file(((*bat_debug)->attr).name,
+ S_IFREG | ((*bat_debug)->attr).mode,
+ bat_priv->debug_dir,
+ dev, &(*bat_debug)->fops);
+ if (!file) {
+ bat_err(dev, "Can't add debugfs file: %s/%s\n",
+ dev->name, ((*bat_debug)->attr).name);
+ goto rem_attr;
+ }
+ }
+
+ return 0;
+rem_attr:
+ debugfs_remove_recursive(bat_priv->debug_dir);
+ bat_priv->debug_dir = NULL;
+out:
+#ifdef CONFIG_DEBUG_FS
+ return -ENOMEM;
+#else
+ return 0;
+#endif /* CONFIG_DEBUG_FS */
+}
+
+void debugfs_del_meshif(struct net_device *dev)
+{
+ struct bat_priv *bat_priv = netdev_priv(dev);
+
+ debug_log_cleanup(bat_priv);
+
+ if (bat_debugfs) {
+ debugfs_remove_recursive(bat_priv->debug_dir);
+ bat_priv->debug_dir = NULL;
+ }
+}
diff --git a/drivers/staging/batman-adv/bat_debugfs.h b/drivers/staging/batman-adv/bat_debugfs.h
new file mode 100644
index 00000000000..72df532b7d5
--- /dev/null
+++ b/drivers/staging/batman-adv/bat_debugfs.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2010 B.A.T.M.A.N. contributors:
+ *
+ * Marek Lindner
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ *
+ */
+
+
+#ifndef _NET_BATMAN_ADV_DEBUGFS_H_
+#define _NET_BATMAN_ADV_DEBUGFS_H_
+
+#define DEBUGFS_BAT_SUBDIR "batman_adv"
+
+void debugfs_init(void);
+void debugfs_destroy(void);
+int debugfs_add_meshif(struct net_device *dev);
+void debugfs_del_meshif(struct net_device *dev);
+
+#endif /* _NET_BATMAN_ADV_DEBUGFS_H_ */
diff --git a/drivers/staging/batman-adv/bat_sysfs.c b/drivers/staging/batman-adv/bat_sysfs.c
index 212bc21e6d6..b4a8d5eb64f 100644
--- a/drivers/staging/batman-adv/bat_sysfs.c
+++ b/drivers/staging/batman-adv/bat_sysfs.c
@@ -28,22 +28,6 @@
#define to_dev(obj) container_of(obj, struct device, kobj)
-struct bat_attribute {
- struct attribute attr;
- ssize_t (*show)(struct kobject *kobj, struct attribute *attr,
- char *buf);
- ssize_t (*store)(struct kobject *kobj, struct attribute *attr,
- char *buf, size_t count);
-};
-
-struct hardif_attribute {
- struct attribute attr;
- ssize_t (*show)(struct kobject *kobj, struct attribute *attr,
- char *buf);
- ssize_t (*store)(struct kobject *kobj, struct attribute *attr,
- char *buf, size_t count);
-};
-
#define BAT_ATTR(_name, _mode, _show, _store) \
struct bat_attribute bat_attr_##_name = { \
.attr = {.name = __stringify(_name), \
@@ -52,34 +36,18 @@ struct bat_attribute bat_attr_##_name = { \
.store = _store, \
};
-#define BAT_BIN_ATTR(_name, _mode, _read, _write) \
-struct bin_attribute bat_attr_##_name = { \
- .attr = { .name = __stringify(_name), \
- .mode = _mode, }, \
- .read = _read, \
- .write = _write, \
-};
-
-#define HARDIF_ATTR(_name, _mode, _show, _store) \
-struct hardif_attribute hardif_attr_##_name = { \
- .attr = {.name = __stringify(_name), \
- .mode = _mode }, \
- .show = _show, \
- .store = _store, \
-};
-
-static ssize_t show_aggr_ogm(struct kobject *kobj, struct attribute *attr,
+static ssize_t show_aggr_ogms(struct kobject *kobj, struct attribute *attr,
char *buff)
{
struct device *dev = to_dev(kobj->parent);
struct bat_priv *bat_priv = netdev_priv(to_net_dev(dev));
int aggr_status = atomic_read(&bat_priv->aggregation_enabled);
- return sprintf(buff, "status: %s\ncommands: enable, disable, 0, 1\n",
+ return sprintf(buff, "%s\n",
aggr_status == 0 ? "disabled" : "enabled");
}
-static ssize_t store_aggr_ogm(struct kobject *kobj, struct attribute *attr,
+static ssize_t store_aggr_ogms(struct kobject *kobj, struct attribute *attr,
char *buff, size_t count)
{
struct device *dev = to_dev(kobj->parent);
@@ -99,23 +67,73 @@ static ssize_t store_aggr_ogm(struct kobject *kobj, struct attribute *attr,
if (buff[count - 1] == '\n')
buff[count - 1] = '\0';
- printk(KERN_INFO "batman-adv:Invalid parameter for 'aggregate OGM' setting on mesh %s received: %s\n",
- net_dev->name, buff);
+ bat_info(net_dev,
+ "Invalid parameter for 'aggregate OGM' setting"
+ "received: %s\n", buff);
return -EINVAL;
}
if (atomic_read(&bat_priv->aggregation_enabled) == aggr_tmp)
return count;
- printk(KERN_INFO "batman-adv:Changing aggregation from: %s to: %s on mesh: %s\n",
- atomic_read(&bat_priv->aggregation_enabled) == 1 ?
- "enabled" : "disabled", aggr_tmp == 1 ? "enabled" : "disabled",
- net_dev->name);
+ bat_info(net_dev, "Changing aggregation from: %s to: %s\n",
+ atomic_read(&bat_priv->aggregation_enabled) == 1 ?
+ "enabled" : "disabled", aggr_tmp == 1 ? "enabled" :
+ "disabled");
atomic_set(&bat_priv->aggregation_enabled, (unsigned)aggr_tmp);
return count;
}
+static ssize_t show_bond(struct kobject *kobj, struct attribute *attr,
+ char *buff)
+{
+ struct device *dev = to_dev(kobj->parent);
+ struct bat_priv *bat_priv = netdev_priv(to_net_dev(dev));
+ int bond_status = atomic_read(&bat_priv->bonding_enabled);
+
+ return sprintf(buff, "%s\n",
+ bond_status == 0 ? "disabled" : "enabled");
+}
+
+static ssize_t store_bond(struct kobject *kobj, struct attribute *attr,
+ char *buff, size_t count)
+{
+ struct device *dev = to_dev(kobj->parent);
+ struct net_device *net_dev = to_net_dev(dev);
+ struct bat_priv *bat_priv = netdev_priv(net_dev);
+ int bonding_enabled_tmp = -1;
+
+ if (((count == 2) && (buff[0] == '1')) ||
+ (strncmp(buff, "enable", 6) == 0))
+ bonding_enabled_tmp = 1;
+
+ if (((count == 2) && (buff[0] == '0')) ||
+ (strncmp(buff, "disable", 7) == 0))
+ bonding_enabled_tmp = 0;
+
+ if (bonding_enabled_tmp < 0) {
+ if (buff[count - 1] == '\n')
+ buff[count - 1] = '\0';
+
+ bat_err(net_dev,
+ "Invalid parameter for 'bonding' setting received: "
+ "%s\n", buff);
+ return -EINVAL;
+ }
+
+ if (atomic_read(&bat_priv->bonding_enabled) == bonding_enabled_tmp)
+ return count;
+
+ bat_info(net_dev, "Changing bonding from: %s to: %s\n",
+ atomic_read(&bat_priv->bonding_enabled) == 1 ?
+ "enabled" : "disabled",
+ bonding_enabled_tmp == 1 ? "enabled" : "disabled");
+
+ atomic_set(&bat_priv->bonding_enabled, (unsigned)bonding_enabled_tmp);
+ return count;
+}
+
static ssize_t show_vis_mode(struct kobject *kobj, struct attribute *attr,
char *buff)
{
@@ -123,10 +141,9 @@ static ssize_t show_vis_mode(struct kobject *kobj, struct attribute *attr,
struct bat_priv *bat_priv = netdev_priv(to_net_dev(dev));
int vis_mode = atomic_read(&bat_priv->vis_mode);
- return sprintf(buff, "status: %s\ncommands: client, server, %d, %d\n",
+ return sprintf(buff, "%s\n",
vis_mode == VIS_TYPE_CLIENT_UPDATE ?
- "client" : "server",
- VIS_TYPE_SERVER_SYNC, VIS_TYPE_CLIENT_UPDATE);
+ "client" : "server");
}
static ssize_t store_vis_mode(struct kobject *kobj, struct attribute *attr,
@@ -141,7 +158,8 @@ static ssize_t store_vis_mode(struct kobject *kobj, struct attribute *attr,
ret = strict_strtoul(buff, 10, &val);
if (((count == 2) && (!ret) && (val == VIS_TYPE_CLIENT_UPDATE)) ||
- (strncmp(buff, "client", 6) == 0))
+ (strncmp(buff, "client", 6) == 0) ||
+ (strncmp(buff, "off", 3) == 0))
vis_mode_tmp = VIS_TYPE_CLIENT_UPDATE;
if (((count == 2) && (!ret) && (val == VIS_TYPE_SERVER_SYNC)) ||
@@ -152,18 +170,19 @@ static ssize_t store_vis_mode(struct kobject *kobj, struct attribute *attr,
if (buff[count - 1] == '\n')
buff[count - 1] = '\0';
- printk(KERN_INFO "batman-adv:Invalid parameter for 'vis mode' setting on mesh %s received: %s\n",
- net_dev->name, buff);
+ bat_info(net_dev,
+ "Invalid parameter for 'vis mode' setting received: "
+ "%s\n", buff);
return -EINVAL;
}
if (atomic_read(&bat_priv->vis_mode) == vis_mode_tmp)
return count;
- printk(KERN_INFO "batman-adv:Changing vis mode from: %s to: %s on mesh: %s\n",
- atomic_read(&bat_priv->vis_mode) == VIS_TYPE_CLIENT_UPDATE ?
- "client" : "server", vis_mode_tmp == VIS_TYPE_CLIENT_UPDATE ?
- "client" : "server", net_dev->name);
+ bat_info(net_dev, "Changing vis mode from: %s to: %s\n",
+ atomic_read(&bat_priv->vis_mode) == VIS_TYPE_CLIENT_UPDATE ?
+ "client" : "server", vis_mode_tmp == VIS_TYPE_CLIENT_UPDATE ?
+ "client" : "server");
atomic_set(&bat_priv->vis_mode, (unsigned)vis_mode_tmp);
return count;
@@ -175,7 +194,7 @@ static ssize_t show_orig_interval(struct kobject *kobj, struct attribute *attr,
struct device *dev = to_dev(kobj->parent);
struct bat_priv *bat_priv = netdev_priv(to_net_dev(dev));
- return sprintf(buff, "status: %i\n",
+ return sprintf(buff, "%i\n",
atomic_read(&bat_priv->orig_interval));
}
@@ -190,91 +209,87 @@ static ssize_t store_orig_interval(struct kobject *kobj, struct attribute *attr,
ret = strict_strtoul(buff, 10, &orig_interval_tmp);
if (ret) {
- printk(KERN_INFO "batman-adv:Invalid parameter for 'orig_interval' setting on mesh %s received: %s\n",
- net_dev->name, buff);
+ bat_info(net_dev, "Invalid parameter for 'orig_interval' "
+ "setting received: %s\n", buff);
return -EINVAL;
}
- if (orig_interval_tmp <= JITTER * 2) {
- printk(KERN_INFO "batman-adv:New originator interval too small: %li (min: %i)\n",
- orig_interval_tmp, JITTER * 2);
+ if (orig_interval_tmp < JITTER * 2) {
+ bat_info(net_dev, "New originator interval too small: %li "
+ "(min: %i)\n", orig_interval_tmp, JITTER * 2);
return -EINVAL;
}
if (atomic_read(&bat_priv->orig_interval) == orig_interval_tmp)
return count;
- printk(KERN_INFO "batman-adv:Changing originator interval from: %i to: %li on mesh: %s\n",
- atomic_read(&bat_priv->orig_interval),
- orig_interval_tmp, net_dev->name);
+ bat_info(net_dev, "Changing originator interval from: %i to: %li\n",
+ atomic_read(&bat_priv->orig_interval),
+ orig_interval_tmp);
atomic_set(&bat_priv->orig_interval, orig_interval_tmp);
return count;
}
-static BAT_ATTR(aggregate_ogm, S_IRUGO | S_IWUSR,
- show_aggr_ogm, store_aggr_ogm);
-static BAT_ATTR(vis_mode, S_IRUGO | S_IWUSR, show_vis_mode, store_vis_mode);
-static BAT_ATTR(orig_interval, S_IRUGO | S_IWUSR,
- show_orig_interval, store_orig_interval);
-
-static struct bat_attribute *mesh_attrs[] = {
- &bat_attr_aggregate_ogm,
- &bat_attr_vis_mode,
- &bat_attr_orig_interval,
- NULL,
-};
-
-static ssize_t transtable_local_read(struct file *filp, struct kobject *kobj,
- struct bin_attribute *bin_attr,
- char *buff, loff_t off, size_t count)
+#ifdef CONFIG_BATMAN_ADV_DEBUG
+static ssize_t show_log_level(struct kobject *kobj, struct attribute *attr,
+ char *buff)
{
struct device *dev = to_dev(kobj->parent);
- struct net_device *net_dev = to_net_dev(dev);
+ struct bat_priv *bat_priv = netdev_priv(to_net_dev(dev));
+ int log_level = atomic_read(&bat_priv->log_level);
- return hna_local_fill_buffer_text(net_dev, buff, count, off);
+ return sprintf(buff, "%d\n", log_level);
}
-static ssize_t transtable_global_read(struct file *filp, struct kobject *kobj,
- struct bin_attribute *bin_attr,
- char *buff, loff_t off, size_t count)
+static ssize_t store_log_level(struct kobject *kobj, struct attribute *attr,
+ char *buff, size_t count)
{
struct device *dev = to_dev(kobj->parent);
struct net_device *net_dev = to_net_dev(dev);
+ struct bat_priv *bat_priv = netdev_priv(net_dev);
+ unsigned long log_level_tmp;
+ int ret;
- return hna_global_fill_buffer_text(net_dev, buff, count, off);
-}
-
-static ssize_t originators_read(struct file *filp, struct kobject *kobj,
- struct bin_attribute *bin_attr,
- char *buff, loff_t off, size_t count)
-{
- struct device *dev = to_dev(kobj->parent);
- struct net_device *net_dev = to_net_dev(dev);
+ ret = strict_strtoul(buff, 10, &log_level_tmp);
+ if (ret) {
+ bat_info(net_dev, "Invalid parameter for 'log_level' "
+ "setting received: %s\n", buff);
+ return -EINVAL;
+ }
- return orig_fill_buffer_text(net_dev, buff, count, off);
-}
+ if (log_level_tmp > 3) {
+ bat_info(net_dev, "New log level too big: %li "
+ "(max: %i)\n", log_level_tmp, 3);
+ return -EINVAL;
+ }
-static ssize_t vis_data_read(struct file *filp, struct kobject *kobj,
- struct bin_attribute *bin_attr,
- char *buff, loff_t off, size_t count)
-{
- struct device *dev = to_dev(kobj->parent);
- struct net_device *net_dev = to_net_dev(dev);
+ if (atomic_read(&bat_priv->log_level) == log_level_tmp)
+ return count;
- return vis_fill_buffer_text(net_dev, buff, count, off);
+ atomic_set(&bat_priv->log_level, (unsigned)log_level_tmp);
+ return count;
}
+#endif
-static BAT_BIN_ATTR(transtable_local, S_IRUGO, transtable_local_read, NULL);
-static BAT_BIN_ATTR(transtable_global, S_IRUGO, transtable_global_read, NULL);
-static BAT_BIN_ATTR(originators, S_IRUGO, originators_read, NULL);
-static BAT_BIN_ATTR(vis_data, S_IRUGO, vis_data_read, NULL);
+static BAT_ATTR(aggregated_ogms, S_IRUGO | S_IWUSR,
+ show_aggr_ogms, store_aggr_ogms);
+static BAT_ATTR(bonding, S_IRUGO | S_IWUSR, show_bond, store_bond);
+static BAT_ATTR(vis_mode, S_IRUGO | S_IWUSR, show_vis_mode, store_vis_mode);
+static BAT_ATTR(orig_interval, S_IRUGO | S_IWUSR,
+ show_orig_interval, store_orig_interval);
+#ifdef CONFIG_BATMAN_ADV_DEBUG
+static BAT_ATTR(log_level, S_IRUGO | S_IWUSR, show_log_level, store_log_level);
+#endif
-static struct bin_attribute *mesh_bin_attrs[] = {
- &bat_attr_transtable_local,
- &bat_attr_transtable_global,
- &bat_attr_originators,
- &bat_attr_vis_data,
+static struct bat_attribute *mesh_attrs[] = {
+ &bat_attr_aggregated_ogms,
+ &bat_attr_bonding,
+ &bat_attr_vis_mode,
+ &bat_attr_orig_interval,
+#ifdef CONFIG_BATMAN_ADV_DEBUG
+ &bat_attr_log_level,
+#endif
NULL,
};
@@ -283,22 +298,24 @@ int sysfs_add_meshif(struct net_device *dev)
struct kobject *batif_kobject = &dev->dev.kobj;
struct bat_priv *bat_priv = netdev_priv(dev);
struct bat_attribute **bat_attr;
- struct bin_attribute **bin_attr;
int err;
/* FIXME: should be done in the general mesh setup
routine as soon as we have it */
atomic_set(&bat_priv->aggregation_enabled, 1);
+ atomic_set(&bat_priv->bonding_enabled, 0);
atomic_set(&bat_priv->vis_mode, VIS_TYPE_CLIENT_UPDATE);
atomic_set(&bat_priv->orig_interval, 1000);
+ atomic_set(&bat_priv->log_level, 0);
+
bat_priv->primary_if = NULL;
bat_priv->num_ifaces = 0;
bat_priv->mesh_obj = kobject_create_and_add(SYSFS_IF_MESH_SUBDIR,
batif_kobject);
if (!bat_priv->mesh_obj) {
- printk(KERN_ERR "batman-adv:Can't add sysfs directory: %s/%s\n",
- dev->name, SYSFS_IF_MESH_SUBDIR);
+ bat_err(dev, "Can't add sysfs directory: %s/%s\n", dev->name,
+ SYSFS_IF_MESH_SUBDIR);
goto out;
}
@@ -306,28 +323,15 @@ int sysfs_add_meshif(struct net_device *dev)
err = sysfs_create_file(bat_priv->mesh_obj,
&((*bat_attr)->attr));
if (err) {
- printk(KERN_ERR "batman-adv:Can't add sysfs file: %s/%s/%s\n",
- dev->name, SYSFS_IF_MESH_SUBDIR,
- ((*bat_attr)->attr).name);
+ bat_err(dev, "Can't add sysfs file: %s/%s/%s\n",
+ dev->name, SYSFS_IF_MESH_SUBDIR,
+ ((*bat_attr)->attr).name);
goto rem_attr;
}
}
- for (bin_attr = mesh_bin_attrs; *bin_attr; ++bin_attr) {
- err = sysfs_create_bin_file(bat_priv->mesh_obj, (*bin_attr));
- if (err) {
- printk(KERN_ERR "batman-adv:Can't add sysfs file: %s/%s/%s\n",
- dev->name, SYSFS_IF_MESH_SUBDIR,
- ((*bin_attr)->attr).name);
- goto rem_bin_attr;
- }
- }
-
return 0;
-rem_bin_attr:
- for (bin_attr = mesh_bin_attrs; *bin_attr; ++bin_attr)
- sysfs_remove_bin_file(bat_priv->mesh_obj, (*bin_attr));
rem_attr:
for (bat_attr = mesh_attrs; *bat_attr; ++bat_attr)
sysfs_remove_file(bat_priv->mesh_obj, &((*bat_attr)->attr));
@@ -342,10 +346,6 @@ void sysfs_del_meshif(struct net_device *dev)
{
struct bat_priv *bat_priv = netdev_priv(dev);
struct bat_attribute **bat_attr;
- struct bin_attribute **bin_attr;
-
- for (bin_attr = mesh_bin_attrs; *bin_attr; ++bin_attr)
- sysfs_remove_bin_file(bat_priv->mesh_obj, (*bin_attr));
for (bat_attr = mesh_attrs; *bat_attr; ++bat_attr)
sysfs_remove_file(bat_priv->mesh_obj, &((*bat_attr)->attr));
@@ -364,7 +364,7 @@ static ssize_t show_mesh_iface(struct kobject *kobj, struct attribute *attr,
if (!batman_if)
return 0;
- return sprintf(buff, "status: %s\ncommands: none, bat0\n",
+ return sprintf(buff, "%s\n",
batman_if->if_status == IF_NOT_IN_USE ?
"none" : "bat0");
}
@@ -390,8 +390,8 @@ static ssize_t store_mesh_iface(struct kobject *kobj, struct attribute *attr,
if (buff[count - 1] == '\n')
buff[count - 1] = '\0';
- printk(KERN_ERR "batman-adv:Invalid parameter for 'mesh_iface' setting received: %s\n",
- buff);
+ pr_err("Invalid parameter for 'mesh_iface' setting received: "
+ "%s\n", buff);
return -EINVAL;
}
@@ -433,37 +433,37 @@ static ssize_t show_iface_status(struct kobject *kobj, struct attribute *attr,
}
}
-static HARDIF_ATTR(mesh_iface, S_IRUGO | S_IWUSR,
- show_mesh_iface, store_mesh_iface);
-static HARDIF_ATTR(iface_status, S_IRUGO, show_iface_status, NULL);
+static BAT_ATTR(mesh_iface, S_IRUGO | S_IWUSR,
+ show_mesh_iface, store_mesh_iface);
+static BAT_ATTR(iface_status, S_IRUGO, show_iface_status, NULL);
-static struct hardif_attribute *batman_attrs[] = {
- &hardif_attr_mesh_iface,
- &hardif_attr_iface_status,
+static struct bat_attribute *batman_attrs[] = {
+ &bat_attr_mesh_iface,
+ &bat_attr_iface_status,
NULL,
};
int sysfs_add_hardif(struct kobject **hardif_obj, struct net_device *dev)
{
struct kobject *hardif_kobject = &dev->dev.kobj;
- struct hardif_attribute **hardif_attr;
+ struct bat_attribute **bat_attr;
int err;
*hardif_obj = kobject_create_and_add(SYSFS_IF_BAT_SUBDIR,
hardif_kobject);
if (!*hardif_obj) {
- printk(KERN_ERR "batman-adv:Can't add sysfs directory: %s/%s\n",
- dev->name, SYSFS_IF_BAT_SUBDIR);
+ bat_err(dev, "Can't add sysfs directory: %s/%s\n", dev->name,
+ SYSFS_IF_BAT_SUBDIR);
goto out;
}
- for (hardif_attr = batman_attrs; *hardif_attr; ++hardif_attr) {
- err = sysfs_create_file(*hardif_obj, &((*hardif_attr)->attr));
+ for (bat_attr = batman_attrs; *bat_attr; ++bat_attr) {
+ err = sysfs_create_file(*hardif_obj, &((*bat_attr)->attr));
if (err) {
- printk(KERN_ERR "batman-adv:Can't add sysfs file: %s/%s/%s\n",
- dev->name, SYSFS_IF_BAT_SUBDIR,
- ((*hardif_attr)->attr).name);
+ bat_err(dev, "Can't add sysfs file: %s/%s/%s\n",
+ dev->name, SYSFS_IF_BAT_SUBDIR,
+ ((*bat_attr)->attr).name);
goto rem_attr;
}
}
@@ -471,8 +471,8 @@ int sysfs_add_hardif(struct kobject **hardif_obj, struct net_device *dev)
return 0;
rem_attr:
- for (hardif_attr = batman_attrs; *hardif_attr; ++hardif_attr)
- sysfs_remove_file(*hardif_obj, &((*hardif_attr)->attr));
+ for (bat_attr = batman_attrs; *bat_attr; ++bat_attr)
+ sysfs_remove_file(*hardif_obj, &((*bat_attr)->attr));
out:
return -ENOMEM;
}
diff --git a/drivers/staging/batman-adv/bat_sysfs.h b/drivers/staging/batman-adv/bat_sysfs.h
index e1893411871..7f186c007b4 100644
--- a/drivers/staging/batman-adv/bat_sysfs.h
+++ b/drivers/staging/batman-adv/bat_sysfs.h
@@ -20,10 +20,23 @@
*/
+#ifndef _NET_BATMAN_ADV_SYSFS_H_
+#define _NET_BATMAN_ADV_SYSFS_H_
+
#define SYSFS_IF_MESH_SUBDIR "mesh"
#define SYSFS_IF_BAT_SUBDIR "batman_adv"
+struct bat_attribute {
+ struct attribute attr;
+ ssize_t (*show)(struct kobject *kobj, struct attribute *attr,
+ char *buf);
+ ssize_t (*store)(struct kobject *kobj, struct attribute *attr,
+ char *buf, size_t count);
+};
+
int sysfs_add_meshif(struct net_device *dev);
void sysfs_del_meshif(struct net_device *dev);
int sysfs_add_hardif(struct kobject **hardif_obj, struct net_device *dev);
void sysfs_del_hardif(struct kobject **hardif_obj);
+
+#endif /* _NET_BATMAN_ADV_SYSFS_H_ */
diff --git a/drivers/staging/batman-adv/bitarray.c b/drivers/staging/batman-adv/bitarray.c
index 2fef6e35f8c..dd4193c99d4 100644
--- a/drivers/staging/batman-adv/bitarray.c
+++ b/drivers/staging/batman-adv/bitarray.c
@@ -24,10 +24,10 @@
/* returns true if the corresponding bit in the given seq_bits indicates true
* and curr_seqno is within range of last_seqno */
-uint8_t get_bit_status(TYPE_OF_WORD *seq_bits, uint16_t last_seqno,
- uint16_t curr_seqno)
+uint8_t get_bit_status(TYPE_OF_WORD *seq_bits, uint32_t last_seqno,
+ uint32_t curr_seqno)
{
- int16_t diff, word_offset, word_num;
+ int32_t diff, word_offset, word_num;
diff = last_seqno - curr_seqno;
if (diff < 0 || diff >= TQ_LOCAL_WINDOW_SIZE) {
@@ -63,7 +63,7 @@ void bit_mark(TYPE_OF_WORD *seq_bits, int32_t n)
}
/* shift the packet array by n places. */
-void bit_shift(TYPE_OF_WORD *seq_bits, int32_t n)
+static void bit_shift(TYPE_OF_WORD *seq_bits, int32_t n)
{
int32_t word_offset, word_num;
int32_t i;
@@ -125,9 +125,12 @@ static void bit_reset_window(TYPE_OF_WORD *seq_bits)
* 1 if the window was moved (either new or very old)
* 0 if the window was not moved/shifted.
*/
-char bit_get_packet(TYPE_OF_WORD *seq_bits, int16_t seq_num_diff,
+char bit_get_packet(TYPE_OF_WORD *seq_bits, int32_t seq_num_diff,
int8_t set_mark)
{
+ /* FIXME: each orig_node->batman_if will be attached to a softif */
+ struct bat_priv *bat_priv = netdev_priv(soft_device);
+
/* sequence number is slightly older. We already got a sequence number
* higher than this one, so we just mark it. */
@@ -152,7 +155,7 @@ char bit_get_packet(TYPE_OF_WORD *seq_bits, int16_t seq_num_diff,
if ((seq_num_diff >= TQ_LOCAL_WINDOW_SIZE)
|| (seq_num_diff < EXPECTED_SEQNO_RANGE)) {
- bat_dbg(DBG_BATMAN,
+ bat_dbg(DBG_BATMAN, bat_priv,
"We missed a lot of packets (%i) !\n",
seq_num_diff - 1);
bit_reset_window(seq_bits);
@@ -169,7 +172,7 @@ char bit_get_packet(TYPE_OF_WORD *seq_bits, int16_t seq_num_diff,
if ((seq_num_diff <= -TQ_LOCAL_WINDOW_SIZE)
|| (seq_num_diff >= EXPECTED_SEQNO_RANGE)) {
- bat_dbg(DBG_BATMAN,
+ bat_dbg(DBG_BATMAN, bat_priv,
"Other host probably restarted!\n");
bit_reset_window(seq_bits);
diff --git a/drivers/staging/batman-adv/bitarray.h b/drivers/staging/batman-adv/bitarray.h
index 76ad24c9f3d..01897d6962d 100644
--- a/drivers/staging/batman-adv/bitarray.h
+++ b/drivers/staging/batman-adv/bitarray.h
@@ -19,6 +19,8 @@
*
*/
+#ifndef _NET_BATMAN_ADV_BITARRAY_H_
+#define _NET_BATMAN_ADV_BITARRAY_H_
/* you should choose something big, if you don't want to waste cpu */
#define TYPE_OF_WORD unsigned long
@@ -26,20 +28,19 @@
/* returns true if the corresponding bit in the given seq_bits indicates true
* and curr_seqno is within range of last_seqno */
-uint8_t get_bit_status(TYPE_OF_WORD *seq_bits, uint16_t last_seqno,
- uint16_t curr_seqno);
+uint8_t get_bit_status(TYPE_OF_WORD *seq_bits, uint32_t last_seqno,
+ uint32_t curr_seqno);
/* turn corresponding bit on, so we can remember that we got the packet */
void bit_mark(TYPE_OF_WORD *seq_bits, int32_t n);
-/* shift the packet array by n places. */
-void bit_shift(TYPE_OF_WORD *seq_bits, int32_t n);
-
/* receive and process one packet, returns 1 if received seq_num is considered
* new, 0 if old */
-char bit_get_packet(TYPE_OF_WORD *seq_bits, int16_t seq_num_diff,
+char bit_get_packet(TYPE_OF_WORD *seq_bits, int32_t seq_num_diff,
int8_t set_mark);
/* count the hamming weight, how many good packets did we receive? */
int bit_packet_count(TYPE_OF_WORD *seq_bits);
+
+#endif /* _NET_BATMAN_ADV_BITARRAY_H_ */
diff --git a/drivers/staging/batman-adv/device.c b/drivers/staging/batman-adv/device.c
deleted file mode 100644
index 32204b5572d..00000000000
--- a/drivers/staging/batman-adv/device.c
+++ /dev/null
@@ -1,354 +0,0 @@
-/*
- * Copyright (C) 2007-2010 B.A.T.M.A.N. contributors:
- *
- * Marek Lindner
- *
- * 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., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA
- *
- */
-
-#include <linux/device.h>
-#include <linux/slab.h>
-#include "main.h"
-#include "device.h"
-#include "send.h"
-#include "types.h"
-#include "hash.h"
-#include "hard-interface.h"
-
-static struct class *batman_class;
-
-static int Major; /* Major number assigned to our device driver */
-
-static const struct file_operations fops = {
- .open = bat_device_open,
- .release = bat_device_release,
- .read = bat_device_read,
- .write = bat_device_write,
- .poll = bat_device_poll,
-};
-
-static struct device_client *device_client_hash[256];
-
-void bat_device_init(void)
-{
- memset(device_client_hash, 0, sizeof(device_client_hash));
-}
-
-int bat_device_setup(void)
-{
- int tmp_major;
-
- if (Major)
- return 1;
-
- /* register our device - kernel assigns a free major number */
- tmp_major = register_chrdev(0, DRIVER_DEVICE, &fops);
- if (tmp_major < 0) {
- printk(KERN_ERR "batman-adv:"
- "Registering the character device failed with %d\n",
- tmp_major);
- return 0;
- }
-
- batman_class = class_create(THIS_MODULE, "batman-adv");
-
- if (IS_ERR(batman_class)) {
- printk(KERN_ERR "batman-adv:"
- "Could not register class 'batman-adv'\n");
- return 0;
- }
-
- device_create(batman_class, NULL, MKDEV(tmp_major, 0), NULL,
- "batman-adv");
-
- Major = tmp_major;
- return 1;
-}
-
-void bat_device_destroy(void)
-{
- if (!Major)
- return;
-
- device_destroy(batman_class, MKDEV(Major, 0));
- class_destroy(batman_class);
-
- /* Unregister the device */
- unregister_chrdev(Major, DRIVER_DEVICE);
-
- Major = 0;
-}
-
-int bat_device_open(struct inode *inode, struct file *file)
-{
- unsigned int i;
- struct device_client *device_client;
-
- device_client = kmalloc(sizeof(struct device_client), GFP_KERNEL);
-
- if (!device_client)
- return -ENOMEM;
-
- for (i = 0; i < ARRAY_SIZE(device_client_hash); i++) {
- if (!device_client_hash[i]) {
- device_client_hash[i] = device_client;
- break;
- }
- }
-
- if (i == ARRAY_SIZE(device_client_hash)) {
- printk(KERN_ERR "batman-adv:"
- "Error - can't add another packet client: "
- "maximum number of clients reached\n");
- kfree(device_client);
- return -EXFULL;
- }
-
- INIT_LIST_HEAD(&device_client->queue_list);
- device_client->queue_len = 0;
- device_client->index = i;
- spin_lock_init(&device_client->lock);
- init_waitqueue_head(&device_client->queue_wait);
-
- file->private_data = device_client;
-
- inc_module_count();
- return 0;
-}
-
-int bat_device_release(struct inode *inode, struct file *file)
-{
- struct device_client *device_client =
- (struct device_client *)file->private_data;
- struct device_packet *device_packet;
- struct list_head *list_pos, *list_pos_tmp;
- unsigned long flags;
-
- spin_lock_irqsave(&device_client->lock, flags);
-
- /* for all packets in the queue ... */
- list_for_each_safe(list_pos, list_pos_tmp, &device_client->queue_list) {
- device_packet = list_entry(list_pos,
- struct device_packet, list);
-
- list_del(list_pos);
- kfree(device_packet);
- }
-
- device_client_hash[device_client->index] = NULL;
- spin_unlock_irqrestore(&device_client->lock, flags);
-
- kfree(device_client);
- dec_module_count();
-
- return 0;
-}
-
-ssize_t bat_device_read(struct file *file, char __user *buf, size_t count,
- loff_t *ppos)
-{
- struct device_client *device_client =
- (struct device_client *)file->private_data;
- struct device_packet *device_packet;
- int error;
- unsigned long flags;
-
- if ((file->f_flags & O_NONBLOCK) && (device_client->queue_len == 0))
- return -EAGAIN;
-
- if ((!buf) || (count < sizeof(struct icmp_packet)))
- return -EINVAL;
-
- if (!access_ok(VERIFY_WRITE, buf, count))
- return -EFAULT;
-
- error = wait_event_interruptible(device_client->queue_wait,
- device_client->queue_len);
-
- if (error)
- return error;
-
- spin_lock_irqsave(&device_client->lock, flags);
-
- device_packet = list_first_entry(&device_client->queue_list,
- struct device_packet, list);
- list_del(&device_packet->list);
- device_client->queue_len--;
-
- spin_unlock_irqrestore(&device_client->lock, flags);
-
- error = __copy_to_user(buf, &device_packet->icmp_packet,
- sizeof(struct icmp_packet));
-
- kfree(device_packet);
-
- if (error)
- return -EFAULT;
-
- return sizeof(struct icmp_packet);
-}
-
-ssize_t bat_device_write(struct file *file, const char __user *buff,
- size_t len, loff_t *off)
-{
- struct device_client *device_client =
- (struct device_client *)file->private_data;
- struct icmp_packet icmp_packet;
- struct orig_node *orig_node;
- struct batman_if *batman_if;
- uint8_t dstaddr[ETH_ALEN];
- unsigned long flags;
-
- if (len < sizeof(struct icmp_packet)) {
- bat_dbg(DBG_BATMAN, "batman-adv:"
- "Error - can't send packet from char device: "
- "invalid packet size\n");
- return -EINVAL;
- }
-
- if (!access_ok(VERIFY_READ, buff, sizeof(struct icmp_packet)))
- return -EFAULT;
-
- if (__copy_from_user(&icmp_packet, buff, sizeof(icmp_packet)))
- return -EFAULT;
-
- if (icmp_packet.packet_type != BAT_ICMP) {
- bat_dbg(DBG_BATMAN, "batman-adv:"
- "Error - can't send packet from char device: "
- "got bogus packet type (expected: BAT_ICMP)\n");
- return -EINVAL;
- }
-
- if (icmp_packet.msg_type != ECHO_REQUEST) {
- bat_dbg(DBG_BATMAN, "batman-adv:"
- "Error - can't send packet from char device: "
- "got bogus message type (expected: ECHO_REQUEST)\n");
- return -EINVAL;
- }
-
- icmp_packet.uid = device_client->index;
-
- if (icmp_packet.version != COMPAT_VERSION) {
- icmp_packet.msg_type = PARAMETER_PROBLEM;
- icmp_packet.ttl = COMPAT_VERSION;
- bat_device_add_packet(device_client, &icmp_packet);
- goto out;
- }
-
- if (atomic_read(&module_state) != MODULE_ACTIVE)
- goto dst_unreach;
-
- spin_lock_irqsave(&orig_hash_lock, flags);
- orig_node = ((struct orig_node *)hash_find(orig_hash, icmp_packet.dst));
-
- if (!orig_node)
- goto unlock;
-
- if (!orig_node->router)
- goto unlock;
-
- batman_if = orig_node->router->if_incoming;
- memcpy(dstaddr, orig_node->router->addr, ETH_ALEN);
-
- spin_unlock_irqrestore(&orig_hash_lock, flags);
-
- if (!batman_if)
- goto dst_unreach;
-
- if (batman_if->if_status != IF_ACTIVE)
- goto dst_unreach;
-
- memcpy(icmp_packet.orig,
- batman_if->net_dev->dev_addr,
- ETH_ALEN);
-
- send_raw_packet((unsigned char *)&icmp_packet,
- sizeof(struct icmp_packet),
- batman_if, dstaddr);
-
- goto out;
-
-unlock:
- spin_unlock_irqrestore(&orig_hash_lock, flags);
-dst_unreach:
- icmp_packet.msg_type = DESTINATION_UNREACHABLE;
- bat_device_add_packet(device_client, &icmp_packet);
-out:
- return len;
-}
-
-unsigned int bat_device_poll(struct file *file, poll_table *wait)
-{
- struct device_client *device_client =
- (struct device_client *)file->private_data;
-
- poll_wait(file, &device_client->queue_wait, wait);
-
- if (device_client->queue_len > 0)
- return POLLIN | POLLRDNORM;
-
- return 0;
-}
-
-void bat_device_add_packet(struct device_client *device_client,
- struct icmp_packet *icmp_packet)
-{
- struct device_packet *device_packet;
- unsigned long flags;
-
- device_packet = kmalloc(sizeof(struct device_packet), GFP_ATOMIC);
-
- if (!device_packet)
- return;
-
- INIT_LIST_HEAD(&device_packet->list);
- memcpy(&device_packet->icmp_packet, icmp_packet,
- sizeof(struct icmp_packet));
-
- spin_lock_irqsave(&device_client->lock, flags);
-
- /* while waiting for the lock the device_client could have been
- * deleted */
- if (!device_client_hash[icmp_packet->uid]) {
- spin_unlock_irqrestore(&device_client->lock, flags);
- kfree(device_packet);
- return;
- }
-
- list_add_tail(&device_packet->list, &device_client->queue_list);
- device_client->queue_len++;
-
- if (device_client->queue_len > 100) {
- device_packet = list_first_entry(&device_client->queue_list,
- struct device_packet, list);
-
- list_del(&device_packet->list);
- kfree(device_packet);
- device_client->queue_len--;
- }
-
- spin_unlock_irqrestore(&device_client->lock, flags);
-
- wake_up(&device_client->queue_wait);
-}
-
-void bat_device_receive_packet(struct icmp_packet *icmp_packet)
-{
- struct device_client *hash = device_client_hash[icmp_packet->uid];
-
- if (hash)
- bat_device_add_packet(hash, icmp_packet);
-}
diff --git a/drivers/staging/batman-adv/hard-interface.c b/drivers/staging/batman-adv/hard-interface.c
index 7a582e80de1..92c216a5688 100644
--- a/drivers/staging/batman-adv/hard-interface.c
+++ b/drivers/staging/batman-adv/hard-interface.c
@@ -30,6 +30,7 @@
#include "hash.h"
#include <linux/if_arp.h>
+#include <linux/netfilter_bridge.h>
#define MIN(x, y) ((x) < (y) ? (x) : (y))
@@ -71,7 +72,7 @@ static int is_valid_iface(struct net_device *net_dev)
#endif
/* Device is being bridged */
- /* if (net_dev->br_port != NULL)
+ /* if (net_dev->priv_flags & IFF_BRIDGE_PORT)
return 0; */
return 1;
@@ -108,7 +109,7 @@ static void set_primary_if(struct bat_priv *bat_priv,
set_main_if_addr(batman_if->net_dev->dev_addr);
batman_packet = (struct batman_packet *)(batman_if->packet_buff);
- batman_packet->flags = 0;
+ batman_packet->flags = PRIMARIES_FIRST_HOP;
batman_packet->ttl = TTL;
/***
@@ -149,12 +150,10 @@ static void check_known_mac_addr(uint8_t *addr)
if (!compare_orig(batman_if->net_dev->dev_addr, addr))
continue;
- printk(KERN_WARNING "batman-adv:"
- "The newly added mac address (%pM) already exists on: %s\n",
- addr, batman_if->dev);
- printk(KERN_WARNING "batman-adv:"
- "It is strongly recommended to keep mac addresses unique"
- "to avoid problems!\n");
+ pr_warning("The newly added mac address (%pM) already exists "
+ "on: %s\n", addr, batman_if->dev);
+ pr_warning("It is strongly recommended to keep mac addresses "
+ "unique to avoid problems!\n");
}
rcu_read_unlock();
}
@@ -188,7 +187,8 @@ void update_min_mtu(void)
soft_device->mtu = min_mtu;
}
-static void hardif_activate_interface(struct bat_priv *bat_priv,
+static void hardif_activate_interface(struct net_device *net_dev,
+ struct bat_priv *bat_priv,
struct batman_if *batman_if)
{
if (batman_if->if_status != IF_INACTIVE)
@@ -206,8 +206,7 @@ static void hardif_activate_interface(struct bat_priv *bat_priv,
if (!bat_priv->primary_if)
set_primary_if(bat_priv, batman_if);
- printk(KERN_INFO "batman-adv:Interface activated: %s\n",
- batman_if->dev);
+ bat_info(net_dev, "Interface activated: %s\n", batman_if->dev);
if (atomic_read(&module_state) == MODULE_INACTIVE)
activate_module();
@@ -216,7 +215,8 @@ static void hardif_activate_interface(struct bat_priv *bat_priv,
return;
}
-static void hardif_deactivate_interface(struct batman_if *batman_if)
+static void hardif_deactivate_interface(struct net_device *net_dev,
+ struct batman_if *batman_if)
{
if ((batman_if->if_status != IF_ACTIVE) &&
(batman_if->if_status != IF_TO_BE_ACTIVATED))
@@ -226,8 +226,7 @@ static void hardif_deactivate_interface(struct batman_if *batman_if)
batman_if->if_status = IF_INACTIVE;
- printk(KERN_INFO "batman-adv:Interface deactivated: %s\n",
- batman_if->dev);
+ bat_info(net_dev, "Interface deactivated: %s\n", batman_if->dev);
update_min_mtu();
}
@@ -245,9 +244,8 @@ int hardif_enable_interface(struct batman_if *batman_if)
batman_if->packet_buff = kmalloc(batman_if->packet_len, GFP_ATOMIC);
if (!batman_if->packet_buff) {
- printk(KERN_ERR "batman-adv:"
- "Can't add interface packet (%s): out of memory\n",
- batman_if->dev);
+ bat_err(soft_device, "Can't add interface packet (%s): "
+ "out of memory\n", batman_if->dev);
goto err;
}
@@ -265,15 +263,14 @@ int hardif_enable_interface(struct batman_if *batman_if)
orig_hash_add_if(batman_if, bat_priv->num_ifaces);
atomic_set(&batman_if->seqno, 1);
- printk(KERN_INFO "batman-adv:Adding interface: %s\n", batman_if->dev);
+ bat_info(soft_device, "Adding interface: %s\n", batman_if->dev);
if (hardif_is_iface_up(batman_if))
- hardif_activate_interface(bat_priv, batman_if);
+ hardif_activate_interface(soft_device, bat_priv, batman_if);
else
- printk(KERN_ERR "batman-adv:"
- "Not using interface %s "
- "(retrying later): interface not active\n",
- batman_if->dev);
+ bat_err(soft_device, "Not using interface %s "
+ "(retrying later): interface not active\n",
+ batman_if->dev);
/* begin scheduling originator messages on that interface */
schedule_own_packet(batman_if);
@@ -291,12 +288,12 @@ void hardif_disable_interface(struct batman_if *batman_if)
struct bat_priv *bat_priv = netdev_priv(soft_device);
if (batman_if->if_status == IF_ACTIVE)
- hardif_deactivate_interface(batman_if);
+ hardif_deactivate_interface(soft_device, batman_if);
if (batman_if->if_status != IF_INACTIVE)
return;
- printk(KERN_INFO "batman-adv:Removing interface: %s\n", batman_if->dev);
+ bat_info(soft_device, "Removing interface: %s\n", batman_if->dev);
bat_priv->num_ifaces--;
orig_hash_del_if(batman_if, bat_priv->num_ifaces);
@@ -323,8 +320,7 @@ static struct batman_if *hardif_add_interface(struct net_device *net_dev)
batman_if = kmalloc(sizeof(struct batman_if), GFP_ATOMIC);
if (!batman_if) {
- printk(KERN_ERR "batman-adv:"
- "Can't add interface (%s): out of memory\n",
+ pr_err("Can't add interface (%s): out of memory\n",
net_dev->name);
goto out;
}
@@ -407,11 +403,11 @@ static int hard_if_event(struct notifier_block *this,
case NETDEV_REGISTER:
break;
case NETDEV_UP:
- hardif_activate_interface(bat_priv, batman_if);
+ hardif_activate_interface(soft_device, bat_priv, batman_if);
break;
case NETDEV_GOING_DOWN:
case NETDEV_DOWN:
- hardif_deactivate_interface(batman_if);
+ hardif_deactivate_interface(soft_device, batman_if);
break;
case NETDEV_UNREGISTER:
hardif_remove_interface(batman_if);
@@ -432,14 +428,22 @@ out:
return NOTIFY_DONE;
}
+static int batman_skb_recv_finish(struct sk_buff *skb)
+{
+ return NF_ACCEPT;
+}
+
/* receive a packet with the batman ethertype coming on a hard
* interface */
int batman_skb_recv(struct sk_buff *skb, struct net_device *dev,
struct packet_type *ptype, struct net_device *orig_dev)
{
+ /* FIXME: each orig_node->batman_if will be attached to a softif */
+ struct bat_priv *bat_priv = netdev_priv(soft_device);
struct batman_packet *batman_packet;
struct batman_if *batman_if;
struct net_device_stats *stats;
+ struct rtnl_link_stats64 temp;
int ret;
skb = skb_share_check(skb, GFP_ATOMIC);
@@ -451,6 +455,13 @@ int batman_skb_recv(struct sk_buff *skb, struct net_device *dev,
if (atomic_read(&module_state) != MODULE_ACTIVE)
goto err_free;
+ /* if netfilter/ebtables wants to block incoming batman
+ * packets then give them a chance to do so here */
+ ret = NF_HOOK(PF_BRIDGE, NF_BR_LOCAL_IN, skb, dev, NULL,
+ batman_skb_recv_finish);
+ if (ret != 1)
+ goto err_out;
+
/* packet should hold at least type and version */
if (unlikely(skb_headlen(skb) < 2))
goto err_free;
@@ -468,7 +479,7 @@ int batman_skb_recv(struct sk_buff *skb, struct net_device *dev,
if (batman_if->if_status != IF_ACTIVE)
goto err_free;
- stats = (struct net_device_stats *)dev_get_stats(skb->dev);
+ stats = (struct net_device_stats *)dev_get_stats(skb->dev, &temp);
if (stats) {
stats->rx_packets++;
stats->rx_bytes += skb->len;
@@ -477,7 +488,7 @@ int batman_skb_recv(struct sk_buff *skb, struct net_device *dev,
batman_packet = (struct batman_packet *)skb->data;
if (batman_packet->version != COMPAT_VERSION) {
- bat_dbg(DBG_BATMAN,
+ bat_dbg(DBG_BATMAN, bat_priv,
"Drop packet: incompatible batman version (%i)\n",
batman_packet->version);
goto err_free;
@@ -499,7 +510,7 @@ int batman_skb_recv(struct sk_buff *skb, struct net_device *dev,
/* unicast packet */
case BAT_UNICAST:
- ret = recv_unicast_packet(skb);
+ ret = recv_unicast_packet(skb, batman_if);
break;
/* broadcast packet */
@@ -530,7 +541,6 @@ err_out:
return NET_RX_DROP;
}
-
struct notifier_block hard_if_notifier = {
.notifier_call = hard_if_event,
};
diff --git a/drivers/staging/batman-adv/hard-interface.h b/drivers/staging/batman-adv/hard-interface.h
index 1e5fc3e720f..d5640b045cb 100644
--- a/drivers/staging/batman-adv/hard-interface.h
+++ b/drivers/staging/batman-adv/hard-interface.h
@@ -19,6 +19,9 @@
*
*/
+#ifndef _NET_BATMAN_ADV_HARD_INTERFACE_H_
+#define _NET_BATMAN_ADV_HARD_INTERFACE_H_
+
#define IF_NOT_IN_USE 0
#define IF_TO_BE_REMOVED 1
#define IF_INACTIVE 2
@@ -38,3 +41,5 @@ int batman_skb_recv(struct sk_buff *skb,
struct net_device *orig_dev);
int hardif_min_mtu(void);
void update_min_mtu(void);
+
+#endif /* _NET_BATMAN_ADV_HARD_INTERFACE_H_ */
diff --git a/drivers/staging/batman-adv/hash.c b/drivers/staging/batman-adv/hash.c
index d4a4adc5704..1286f8ff44f 100644
--- a/drivers/staging/batman-adv/hash.c
+++ b/drivers/staging/batman-adv/hash.c
@@ -23,7 +23,7 @@
#include "hash.h"
/* clears the hash */
-void hash_init(struct hashtable_t *hash)
+static void hash_init(struct hashtable_t *hash)
{
int i;
diff --git a/drivers/staging/batman-adv/hash.h b/drivers/staging/batman-adv/hash.h
index ea6d21e0125..c483e1129fc 100644
--- a/drivers/staging/batman-adv/hash.h
+++ b/drivers/staging/batman-adv/hash.h
@@ -19,8 +19,9 @@
*
*/
-#ifndef _BATMAN_HASH_H
-#define _BATMAN_HASH_H
+#ifndef _NET_BATMAN_ADV_HASH_H_
+#define _NET_BATMAN_ADV_HASH_H_
+
#define HASHIT(name) struct hash_it_t name = { \
.index = -1, .bucket = NULL, \
.prev_bucket = NULL, \
@@ -56,9 +57,6 @@ struct hashtable_t {
* argument and the size the second */
};
-/* clears the hash */
-void hash_init(struct hashtable_t *hash);
-
/* allocates and clears the hash */
struct hashtable_t *hash_new(int size, hashdata_compare_cb compare,
hashdata_choose_cb choose);
@@ -99,6 +97,4 @@ struct hashtable_t *hash_resize(struct hashtable_t *hash, int size);
struct hash_it_t *hash_iterate(struct hashtable_t *hash,
struct hash_it_t *iter_in);
-/* print the hash table for debugging */
-void hash_debug(struct hashtable_t *hash);
-#endif
+#endif /* _NET_BATMAN_ADV_HASH_H_ */
diff --git a/drivers/staging/batman-adv/icmp_socket.c b/drivers/staging/batman-adv/icmp_socket.c
new file mode 100644
index 00000000000..fc3d32c1272
--- /dev/null
+++ b/drivers/staging/batman-adv/icmp_socket.c
@@ -0,0 +1,334 @@
+/*
+ * Copyright (C) 2007-2010 B.A.T.M.A.N. contributors:
+ *
+ * Marek Lindner
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ *
+ */
+
+#include "main.h"
+#include <linux/debugfs.h>
+#include <linux/slab.h>
+#include "icmp_socket.h"
+#include "send.h"
+#include "types.h"
+#include "hash.h"
+#include "hard-interface.h"
+
+
+static struct socket_client *socket_client_hash[256];
+
+static void bat_socket_add_packet(struct socket_client *socket_client,
+ struct icmp_packet_rr *icmp_packet,
+ size_t icmp_len);
+
+void bat_socket_init(void)
+{
+ memset(socket_client_hash, 0, sizeof(socket_client_hash));
+}
+
+static int bat_socket_open(struct inode *inode, struct file *file)
+{
+ unsigned int i;
+ struct socket_client *socket_client;
+
+ socket_client = kmalloc(sizeof(struct socket_client), GFP_KERNEL);
+
+ if (!socket_client)
+ return -ENOMEM;
+
+ for (i = 0; i < ARRAY_SIZE(socket_client_hash); i++) {
+ if (!socket_client_hash[i]) {
+ socket_client_hash[i] = socket_client;
+ break;
+ }
+ }
+
+ if (i == ARRAY_SIZE(socket_client_hash)) {
+ pr_err("Error - can't add another packet client: "
+ "maximum number of clients reached\n");
+ kfree(socket_client);
+ return -EXFULL;
+ }
+
+ INIT_LIST_HEAD(&socket_client->queue_list);
+ socket_client->queue_len = 0;
+ socket_client->index = i;
+ spin_lock_init(&socket_client->lock);
+ init_waitqueue_head(&socket_client->queue_wait);
+
+ file->private_data = socket_client;
+
+ inc_module_count();
+ return 0;
+}
+
+static int bat_socket_release(struct inode *inode, struct file *file)
+{
+ struct socket_client *socket_client = file->private_data;
+ struct socket_packet *socket_packet;
+ struct list_head *list_pos, *list_pos_tmp;
+ unsigned long flags;
+
+ spin_lock_irqsave(&socket_client->lock, flags);
+
+ /* for all packets in the queue ... */
+ list_for_each_safe(list_pos, list_pos_tmp, &socket_client->queue_list) {
+ socket_packet = list_entry(list_pos,
+ struct socket_packet, list);
+
+ list_del(list_pos);
+ kfree(socket_packet);
+ }
+
+ socket_client_hash[socket_client->index] = NULL;
+ spin_unlock_irqrestore(&socket_client->lock, flags);
+
+ kfree(socket_client);
+ dec_module_count();
+
+ return 0;
+}
+
+static ssize_t bat_socket_read(struct file *file, char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ struct socket_client *socket_client = file->private_data;
+ struct socket_packet *socket_packet;
+ size_t packet_len;
+ int error;
+ unsigned long flags;
+
+ if ((file->f_flags & O_NONBLOCK) && (socket_client->queue_len == 0))
+ return -EAGAIN;
+
+ if ((!buf) || (count < sizeof(struct icmp_packet)))
+ return -EINVAL;
+
+ if (!access_ok(VERIFY_WRITE, buf, count))
+ return -EFAULT;
+
+ error = wait_event_interruptible(socket_client->queue_wait,
+ socket_client->queue_len);
+
+ if (error)
+ return error;
+
+ spin_lock_irqsave(&socket_client->lock, flags);
+
+ socket_packet = list_first_entry(&socket_client->queue_list,
+ struct socket_packet, list);
+ list_del(&socket_packet->list);
+ socket_client->queue_len--;
+
+ spin_unlock_irqrestore(&socket_client->lock, flags);
+
+ error = __copy_to_user(buf, &socket_packet->icmp_packet,
+ socket_packet->icmp_len);
+
+ packet_len = socket_packet->icmp_len;
+ kfree(socket_packet);
+
+ if (error)
+ return -EFAULT;
+
+ return packet_len;
+}
+
+static ssize_t bat_socket_write(struct file *file, const char __user *buff,
+ size_t len, loff_t *off)
+{
+ /* FIXME: each orig_node->batman_if will be attached to a softif */
+ struct bat_priv *bat_priv = netdev_priv(soft_device);
+ struct socket_client *socket_client = file->private_data;
+ struct icmp_packet_rr icmp_packet;
+ struct orig_node *orig_node;
+ struct batman_if *batman_if;
+ size_t packet_len = sizeof(struct icmp_packet);
+ uint8_t dstaddr[ETH_ALEN];
+ unsigned long flags;
+
+ if (len < sizeof(struct icmp_packet)) {
+ bat_dbg(DBG_BATMAN, bat_priv,
+ "Error - can't send packet from char device: "
+ "invalid packet size\n");
+ return -EINVAL;
+ }
+
+ if (len >= sizeof(struct icmp_packet_rr))
+ packet_len = sizeof(struct icmp_packet_rr);
+
+ if (!access_ok(VERIFY_READ, buff, packet_len))
+ return -EFAULT;
+
+ if (__copy_from_user(&icmp_packet, buff, packet_len))
+ return -EFAULT;
+
+ if (icmp_packet.packet_type != BAT_ICMP) {
+ bat_dbg(DBG_BATMAN, bat_priv,
+ "Error - can't send packet from char device: "
+ "got bogus packet type (expected: BAT_ICMP)\n");
+ return -EINVAL;
+ }
+
+ if (icmp_packet.msg_type != ECHO_REQUEST) {
+ bat_dbg(DBG_BATMAN, bat_priv,
+ "Error - can't send packet from char device: "
+ "got bogus message type (expected: ECHO_REQUEST)\n");
+ return -EINVAL;
+ }
+
+ icmp_packet.uid = socket_client->index;
+
+ if (icmp_packet.version != COMPAT_VERSION) {
+ icmp_packet.msg_type = PARAMETER_PROBLEM;
+ icmp_packet.ttl = COMPAT_VERSION;
+ bat_socket_add_packet(socket_client, &icmp_packet, packet_len);
+ goto out;
+ }
+
+ if (atomic_read(&module_state) != MODULE_ACTIVE)
+ goto dst_unreach;
+
+ spin_lock_irqsave(&orig_hash_lock, flags);
+ orig_node = ((struct orig_node *)hash_find(orig_hash, icmp_packet.dst));
+
+ if (!orig_node)
+ goto unlock;
+
+ if (!orig_node->router)
+ goto unlock;
+
+ batman_if = orig_node->router->if_incoming;
+ memcpy(dstaddr, orig_node->router->addr, ETH_ALEN);
+
+ spin_unlock_irqrestore(&orig_hash_lock, flags);
+
+ if (!batman_if)
+ goto dst_unreach;
+
+ if (batman_if->if_status != IF_ACTIVE)
+ goto dst_unreach;
+
+ memcpy(icmp_packet.orig, batman_if->net_dev->dev_addr, ETH_ALEN);
+
+ if (packet_len == sizeof(struct icmp_packet_rr))
+ memcpy(icmp_packet.rr, batman_if->net_dev->dev_addr, ETH_ALEN);
+
+ send_raw_packet((unsigned char *)&icmp_packet,
+ packet_len, batman_if, dstaddr);
+
+ goto out;
+
+unlock:
+ spin_unlock_irqrestore(&orig_hash_lock, flags);
+dst_unreach:
+ icmp_packet.msg_type = DESTINATION_UNREACHABLE;
+ bat_socket_add_packet(socket_client, &icmp_packet, packet_len);
+out:
+ return len;
+}
+
+static unsigned int bat_socket_poll(struct file *file, poll_table *wait)
+{
+ struct socket_client *socket_client = file->private_data;
+
+ poll_wait(file, &socket_client->queue_wait, wait);
+
+ if (socket_client->queue_len > 0)
+ return POLLIN | POLLRDNORM;
+
+ return 0;
+}
+
+static const struct file_operations fops = {
+ .owner = THIS_MODULE,
+ .open = bat_socket_open,
+ .release = bat_socket_release,
+ .read = bat_socket_read,
+ .write = bat_socket_write,
+ .poll = bat_socket_poll,
+};
+
+int bat_socket_setup(struct bat_priv *bat_priv)
+{
+ struct dentry *d;
+
+ if (!bat_priv->debug_dir)
+ goto err;
+
+ d = debugfs_create_file(ICMP_SOCKET, S_IFREG | S_IWUSR | S_IRUSR,
+ bat_priv->debug_dir, NULL, &fops);
+ if (d)
+ goto err;
+
+ return 0;
+
+err:
+ return 1;
+}
+
+static void bat_socket_add_packet(struct socket_client *socket_client,
+ struct icmp_packet_rr *icmp_packet,
+ size_t icmp_len)
+{
+ struct socket_packet *socket_packet;
+ unsigned long flags;
+
+ socket_packet = kmalloc(sizeof(struct socket_packet), GFP_ATOMIC);
+
+ if (!socket_packet)
+ return;
+
+ INIT_LIST_HEAD(&socket_packet->list);
+ memcpy(&socket_packet->icmp_packet, icmp_packet, icmp_len);
+ socket_packet->icmp_len = icmp_len;
+
+ spin_lock_irqsave(&socket_client->lock, flags);
+
+ /* while waiting for the lock the socket_client could have been
+ * deleted */
+ if (!socket_client_hash[icmp_packet->uid]) {
+ spin_unlock_irqrestore(&socket_client->lock, flags);
+ kfree(socket_packet);
+ return;
+ }
+
+ list_add_tail(&socket_packet->list, &socket_client->queue_list);
+ socket_client->queue_len++;
+
+ if (socket_client->queue_len > 100) {
+ socket_packet = list_first_entry(&socket_client->queue_list,
+ struct socket_packet, list);
+
+ list_del(&socket_packet->list);
+ kfree(socket_packet);
+ socket_client->queue_len--;
+ }
+
+ spin_unlock_irqrestore(&socket_client->lock, flags);
+
+ wake_up(&socket_client->queue_wait);
+}
+
+void bat_socket_receive_packet(struct icmp_packet_rr *icmp_packet,
+ size_t icmp_len)
+{
+ struct socket_client *hash = socket_client_hash[icmp_packet->uid];
+
+ if (hash)
+ bat_socket_add_packet(hash, icmp_packet, icmp_len);
+}
diff --git a/drivers/staging/batman-adv/device.h b/drivers/staging/batman-adv/icmp_socket.h
index eb14b371cea..bf9b348cde2 100644
--- a/drivers/staging/batman-adv/device.h
+++ b/drivers/staging/batman-adv/icmp_socket.h
@@ -19,18 +19,16 @@
*
*/
+#ifndef _NET_BATMAN_ADV_ICMP_SOCKET_H_
+#define _NET_BATMAN_ADV_ICMP_SOCKET_H_
+
#include "types.h"
-void bat_device_init(void);
-int bat_device_setup(void);
-void bat_device_destroy(void);
-int bat_device_open(struct inode *inode, struct file *file);
-int bat_device_release(struct inode *inode, struct file *file);
-ssize_t bat_device_read(struct file *file, char __user *buf, size_t count,
- loff_t *ppos);
-ssize_t bat_device_write(struct file *file, const char __user *buff,
- size_t len, loff_t *off);
-unsigned int bat_device_poll(struct file *file, poll_table *wait);
-void bat_device_add_packet(struct device_client *device_client,
- struct icmp_packet *icmp_packet);
-void bat_device_receive_packet(struct icmp_packet *icmp_packet);
+#define ICMP_SOCKET "socket"
+
+void bat_socket_init(void);
+int bat_socket_setup(struct bat_priv *bat_priv);
+void bat_socket_receive_packet(struct icmp_packet_rr *icmp_packet,
+ size_t icmp_len);
+
+#endif /* _NET_BATMAN_ADV_ICMP_SOCKET_H_ */
diff --git a/drivers/staging/batman-adv/main.c b/drivers/staging/batman-adv/main.c
index 74c70d589a9..2686019fe4e 100644
--- a/drivers/staging/batman-adv/main.c
+++ b/drivers/staging/batman-adv/main.c
@@ -21,11 +21,12 @@
#include "main.h"
#include "bat_sysfs.h"
+#include "bat_debugfs.h"
#include "routing.h"
#include "send.h"
#include "originator.h"
#include "soft-interface.h"
-#include "device.h"
+#include "icmp_socket.h"
#include "translation-table.h"
#include "hard-interface.h"
#include "types.h"
@@ -41,7 +42,6 @@ DEFINE_SPINLOCK(orig_hash_lock);
DEFINE_SPINLOCK(forw_bat_list_lock);
DEFINE_SPINLOCK(forw_bcast_list_lock);
-atomic_t vis_interval;
atomic_t bcast_queue_left;
atomic_t batman_queue_left;
@@ -49,7 +49,7 @@ int16_t num_hna;
struct net_device *soft_device;
-unsigned char broadcastAddr[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+unsigned char broadcast_addr[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
atomic_t module_state;
static struct packet_type batman_adv_packet_type __read_mostly = {
@@ -59,18 +59,7 @@ static struct packet_type batman_adv_packet_type __read_mostly = {
struct workqueue_struct *bat_event_workqueue;
-#ifdef CONFIG_BATMAN_ADV_DEBUG
-int debug;
-
-module_param(debug, int, 0644);
-
-int bat_debug_type(int type)
-{
- return debug & type;
-}
-#endif
-
-int init_module(void)
+static int __init batman_init(void)
{
int retval;
@@ -80,8 +69,6 @@ int init_module(void)
atomic_set(&module_state, MODULE_INACTIVE);
- atomic_set(&vis_interval, 1000);/* TODO: raise this later, this is only
- * for debugging now. */
atomic_set(&bcast_queue_left, BCAST_QUEUE_LEN);
atomic_set(&batman_queue_left, BATMAN_QUEUE_LEN);
@@ -92,23 +79,22 @@ int init_module(void)
if (!bat_event_workqueue)
return -ENOMEM;
- bat_device_init();
+ bat_socket_init();
+ debugfs_init();
/* initialize layer 2 interface */
soft_device = alloc_netdev(sizeof(struct bat_priv) , "bat%d",
interface_setup);
if (!soft_device) {
- printk(KERN_ERR "batman-adv:"
- "Unable to allocate the batman interface\n");
+ pr_err("Unable to allocate the batman interface\n");
goto end;
}
retval = register_netdev(soft_device);
if (retval < 0) {
- printk(KERN_ERR "batman-adv:"
- "Unable to register the batman interface: %i\n", retval);
+ pr_err("Unable to register the batman interface: %i\n", retval);
goto free_soft_device;
}
@@ -117,15 +103,22 @@ int init_module(void)
if (retval < 0)
goto unreg_soft_device;
+ retval = debugfs_add_meshif(soft_device);
+
+ if (retval < 0)
+ goto unreg_sysfs;
+
register_netdevice_notifier(&hard_if_notifier);
dev_add_pack(&batman_adv_packet_type);
- printk(KERN_INFO "batman-adv:"
- "B.A.T.M.A.N. advanced %s%s (compatibility version %i) loaded\n",
- SOURCE_VERSION, REVISION_VERSION_STR, COMPAT_VERSION);
+ pr_info("B.A.T.M.A.N. advanced %s%s (compatibility version %i) "
+ "loaded\n", SOURCE_VERSION, REVISION_VERSION_STR,
+ COMPAT_VERSION);
return 0;
+unreg_sysfs:
+ sysfs_del_meshif(soft_device);
unreg_soft_device:
unregister_netdev(soft_device);
soft_device = NULL;
@@ -138,14 +131,16 @@ end:
return -ENOMEM;
}
-void cleanup_module(void)
+static void __exit batman_exit(void)
{
deactivate_module();
+ debugfs_destroy();
unregister_netdevice_notifier(&hard_if_notifier);
hardif_remove_interfaces();
if (soft_device) {
+ debugfs_del_meshif(soft_device);
sysfs_del_meshif(soft_device);
unregister_netdev(soft_device);
soft_device = NULL;
@@ -157,7 +152,7 @@ void cleanup_module(void)
bat_event_workqueue = NULL;
}
-/* activates the module, creates bat device, starts timer ... */
+/* activates the module, starts timer ... */
void activate_module(void)
{
if (originator_init() < 1)
@@ -171,9 +166,6 @@ void activate_module(void)
hna_local_add(soft_device->dev_addr);
- if (bat_device_setup() < 1)
- goto end;
-
if (vis_init() < 1)
goto err;
@@ -182,8 +174,7 @@ void activate_module(void)
goto end;
err:
- printk(KERN_ERR "batman-adv:"
- "Unable to allocate memory for mesh information structures: "
+ pr_err("Unable to allocate memory for mesh information structures: "
"out of mem ?\n");
deactivate_module();
end:
@@ -208,7 +199,6 @@ void deactivate_module(void)
hna_global_free();
synchronize_net();
- bat_device_destroy();
synchronize_rcu();
atomic_set(&module_state, MODULE_INACTIVE);
@@ -226,8 +216,7 @@ void dec_module_count(void)
int addr_to_string(char *buff, uint8_t *addr)
{
- return sprintf(buff, MAC_FMT,
- addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);
+ return sprintf(buff, "%pM", addr);
}
/* returns 1 if they are the same originator */
@@ -284,6 +273,9 @@ int is_mcast(uint8_t *addr)
return *addr & 0x01;
}
+module_init(batman_init);
+module_exit(batman_exit);
+
MODULE_LICENSE("GPL");
MODULE_AUTHOR(DRIVER_AUTHOR);
diff --git a/drivers/staging/batman-adv/main.h b/drivers/staging/batman-adv/main.h
index 5f8343d360f..8513261b8a7 100644
--- a/drivers/staging/batman-adv/main.h
+++ b/drivers/staging/batman-adv/main.h
@@ -19,6 +19,9 @@
*
*/
+#ifndef _NET_BATMAN_ADV_MAIN_H_
+#define _NET_BATMAN_ADV_MAIN_H_
+
/* Kernel Programming */
#define LINUX
@@ -27,7 +30,7 @@
#define DRIVER_DESC "B.A.T.M.A.N. advanced"
#define DRIVER_DEVICE "batman-adv"
-#define SOURCE_VERSION "0.2.2-beta"
+#define SOURCE_VERSION "maint"
/* B.A.T.M.A.N. parameters */
@@ -36,10 +39,10 @@
#define JITTER 20
#define TTL 50 /* Time To Live of broadcast messages */
-#define PURGE_TIMEOUT 200000 /* purge originators after time in ms if no
+#define PURGE_TIMEOUT 200 /* purge originators after time in seconds if no
* valid packet comes in -> TODO: check
* influence on TQ_LOCAL_WINDOW_SIZE */
-#define LOCAL_HNA_TIMEOUT 3600000
+#define LOCAL_HNA_TIMEOUT 3600 /* in seconds */
#define TQ_LOCAL_WINDOW_SIZE 64 /* sliding packet range of received originator
* messages in squence numbers (should be a
@@ -57,44 +60,42 @@
#define LOG_BUF_LEN 8192 /* has to be a power of 2 */
#define ETH_STR_LEN 20
+#define VIS_INTERVAL 5000 /* 5 seconds */
+
+/* how much worse secondary interfaces may be to
+ * to be considered as bonding candidates */
+
+#define BONDING_TQ_THRESHOLD 50
+
#define MAX_AGGREGATION_BYTES 512 /* should not be bigger than 512 bytes or
* change the size of
* forw_packet->direct_link_flags */
#define MAX_AGGREGATION_MS 100
#define RESET_PROTECTION_MS 30000
-#define EXPECTED_SEQNO_RANGE 4096
+#define EXPECTED_SEQNO_RANGE 65536
/* don't reset again within 30 seconds */
#define MODULE_INACTIVE 0
#define MODULE_ACTIVE 1
#define MODULE_DEACTIVATING 2
-#define BCAST_QUEUE_LEN 256
+#define BCAST_QUEUE_LEN 256
#define BATMAN_QUEUE_LEN 256
/*
* Debug Messages
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt /* Append 'batman-adv: ' before
+ * kernel messages */
#define DBG_BATMAN 1 /* all messages related to routing / flooding /
* broadcasting / etc */
#define DBG_ROUTES 2 /* route or hna added / changed / deleted */
+#define DBG_ALL 3
-#ifdef CONFIG_BATMAN_ADV_DEBUG
-extern int debug;
+#define LOG_BUF_LEN 8192 /* has to be a power of 2 */
-extern int bat_debug_type(int type);
-#define bat_dbg(type, fmt, arg...) do { \
- if (bat_debug_type(type)) \
- printk(KERN_DEBUG "batman-adv:" fmt, ## arg); \
- } \
- while (0)
-#else /* !CONFIG_BATMAN_ADV_DEBUG */
-#define bat_dbg(type, fmt, arg...) do { \
- } \
- while (0)
-#endif
/*
* Vis
@@ -117,6 +118,7 @@ extern int bat_debug_type(int type);
#include <linux/slab.h>
#include <net/sock.h> /* struct sock */
#include <linux/jiffies.h>
+#include <linux/seq_file.h>
#include "types.h"
#ifndef REVISION_VERSION
@@ -134,14 +136,13 @@ extern spinlock_t orig_hash_lock;
extern spinlock_t forw_bat_list_lock;
extern spinlock_t forw_bcast_list_lock;
-extern atomic_t vis_interval;
extern atomic_t bcast_queue_left;
extern atomic_t batman_queue_left;
extern int16_t num_hna;
extern struct net_device *soft_device;
-extern unsigned char broadcastAddr[];
+extern unsigned char broadcast_addr[];
extern atomic_t module_state;
extern struct workqueue_struct *bat_event_workqueue;
@@ -155,3 +156,44 @@ int choose_orig(void *data, int32_t size);
int is_my_mac(uint8_t *addr);
int is_bcast(uint8_t *addr);
int is_mcast(uint8_t *addr);
+
+#ifdef CONFIG_BATMAN_ADV_DEBUG
+extern int debug_log(struct bat_priv *bat_priv, char *fmt, ...);
+
+#define bat_dbg(type, bat_priv, fmt, arg...) \
+ do { \
+ if (atomic_read(&bat_priv->log_level) & type) \
+ debug_log(bat_priv, fmt, ## arg); \
+ } \
+ while (0)
+#else /* !CONFIG_BATMAN_ADV_DEBUG */
+static inline void bat_dbg(char type __attribute__((unused)),
+ struct bat_priv *bat_priv __attribute__((unused)),
+ char *fmt __attribute__((unused)), ...)
+{
+}
+#endif
+
+#define bat_warning(net_dev, fmt, arg...) \
+ do { \
+ struct net_device *_netdev = (net_dev); \
+ struct bat_priv *_batpriv = netdev_priv(_netdev); \
+ bat_dbg(DBG_ALL, _batpriv, fmt, ## arg); \
+ pr_warning("%s: " fmt, _netdev->name, ## arg); \
+ } while (0)
+#define bat_info(net_dev, fmt, arg...) \
+ do { \
+ struct net_device *_netdev = (net_dev); \
+ struct bat_priv *_batpriv = netdev_priv(_netdev); \
+ bat_dbg(DBG_ALL, _batpriv, fmt, ## arg); \
+ pr_info("%s: " fmt, _netdev->name, ## arg); \
+ } while (0)
+#define bat_err(net_dev, fmt, arg...) \
+ do { \
+ struct net_device *_netdev = (net_dev); \
+ struct bat_priv *_batpriv = netdev_priv(_netdev); \
+ bat_dbg(DBG_ALL, _batpriv, fmt, ## arg); \
+ pr_err("%s: " fmt, _netdev->name, ## arg); \
+ } while (0)
+
+#endif /* _NET_BATMAN_ADV_MAIN_H_ */
diff --git a/drivers/staging/batman-adv/originator.c b/drivers/staging/batman-adv/originator.c
index 568aef8371b..28bb627ffa1 100644
--- a/drivers/staging/batman-adv/originator.c
+++ b/drivers/staging/batman-adv/originator.c
@@ -56,28 +56,16 @@ err:
return 0;
}
-void originator_free(void)
-{
- unsigned long flags;
-
- if (!orig_hash)
- return;
-
- cancel_delayed_work_sync(&purge_orig_wq);
-
- spin_lock_irqsave(&orig_hash_lock, flags);
- hash_delete(orig_hash, free_orig_node);
- orig_hash = NULL;
- spin_unlock_irqrestore(&orig_hash_lock, flags);
-}
-
struct neigh_node *
create_neighbor(struct orig_node *orig_node, struct orig_node *orig_neigh_node,
uint8_t *neigh, struct batman_if *if_incoming)
{
+ /* FIXME: each orig_node->batman_if will be attached to a softif */
+ struct bat_priv *bat_priv = netdev_priv(soft_device);
struct neigh_node *neigh_node;
- bat_dbg(DBG_BATMAN, "Creating new last-hop neighbor of originator\n");
+ bat_dbg(DBG_BATMAN, bat_priv,
+ "Creating new last-hop neighbor of originator\n");
neigh_node = kzalloc(sizeof(struct neigh_node), GFP_ATOMIC);
if (!neigh_node)
@@ -93,7 +81,7 @@ create_neighbor(struct orig_node *orig_node, struct orig_node *orig_neigh_node,
return neigh_node;
}
-void free_orig_node(void *data)
+static void free_orig_node(void *data)
{
struct list_head *list_pos, *list_pos_tmp;
struct neigh_node *neigh_node;
@@ -114,6 +102,21 @@ void free_orig_node(void *data)
kfree(orig_node);
}
+void originator_free(void)
+{
+ unsigned long flags;
+
+ if (!orig_hash)
+ return;
+
+ cancel_delayed_work_sync(&purge_orig_wq);
+
+ spin_lock_irqsave(&orig_hash_lock, flags);
+ hash_delete(orig_hash, free_orig_node);
+ orig_hash = NULL;
+ spin_unlock_irqrestore(&orig_hash_lock, flags);
+}
+
/* this function finds or creates an originator entry for the given
* address if it does not exits */
struct orig_node *get_orig_node(uint8_t *addr)
@@ -129,7 +132,8 @@ struct orig_node *get_orig_node(uint8_t *addr)
if (orig_node != NULL)
return orig_node;
- bat_dbg(DBG_BATMAN, "Creating new originator: %pM\n", addr);
+ bat_dbg(DBG_BATMAN, bat_priv,
+ "Creating new originator: %pM\n", addr);
orig_node = kzalloc(sizeof(struct orig_node), GFP_ATOMIC);
if (!orig_node)
@@ -163,8 +167,8 @@ struct orig_node *get_orig_node(uint8_t *addr)
swaphash = hash_resize(orig_hash, orig_hash->size * 2);
if (swaphash == NULL)
- printk(KERN_ERR
- "batman-adv:Couldn't resize orig hash table\n");
+ bat_err(soft_device,
+ "Couldn't resize orig hash table\n");
else
orig_hash = swaphash;
}
@@ -182,6 +186,8 @@ free_orig_node:
static bool purge_orig_neighbors(struct orig_node *orig_node,
struct neigh_node **best_neigh_node)
{
+ /* FIXME: each orig_node->batman_if will be attached to a softif */
+ struct bat_priv *bat_priv = netdev_priv(soft_device);
struct list_head *list_pos, *list_pos_tmp;
struct neigh_node *neigh_node;
bool neigh_purged = false;
@@ -193,20 +199,19 @@ static bool purge_orig_neighbors(struct orig_node *orig_node,
neigh_node = list_entry(list_pos, struct neigh_node, list);
if ((time_after(jiffies,
- (neigh_node->last_valid +
- ((PURGE_TIMEOUT * HZ) / 1000)))) ||
+ neigh_node->last_valid + PURGE_TIMEOUT * HZ)) ||
(neigh_node->if_incoming->if_status ==
IF_TO_BE_REMOVED)) {
if (neigh_node->if_incoming->if_status ==
IF_TO_BE_REMOVED)
- bat_dbg(DBG_BATMAN,
+ bat_dbg(DBG_BATMAN, bat_priv,
"neighbor purge: originator %pM, "
"neighbor: %pM, iface: %s\n",
orig_node->orig, neigh_node->addr,
neigh_node->if_incoming->dev);
else
- bat_dbg(DBG_BATMAN,
+ bat_dbg(DBG_BATMAN, bat_priv,
"neighbor timeout: originator %pM, "
"neighbor: %pM, last_valid: %lu\n",
orig_node->orig, neigh_node->addr,
@@ -226,21 +231,26 @@ static bool purge_orig_neighbors(struct orig_node *orig_node,
static bool purge_orig_node(struct orig_node *orig_node)
{
+ /* FIXME: each batman_if will be attached to a softif */
+ struct bat_priv *bat_priv = netdev_priv(soft_device);
struct neigh_node *best_neigh_node;
if (time_after(jiffies,
- (orig_node->last_valid +
- ((2 * PURGE_TIMEOUT * HZ) / 1000)))) {
+ orig_node->last_valid + 2 * PURGE_TIMEOUT * HZ)) {
- bat_dbg(DBG_BATMAN,
+ bat_dbg(DBG_BATMAN, bat_priv,
"Originator timeout: originator %pM, last_valid %lu\n",
orig_node->orig, (orig_node->last_valid / HZ));
return true;
} else {
- if (purge_orig_neighbors(orig_node, &best_neigh_node))
+ if (purge_orig_neighbors(orig_node, &best_neigh_node)) {
update_routes(orig_node, best_neigh_node,
orig_node->hna_buff,
orig_node->hna_buff_len);
+ /* update bonding candidates, we could have lost
+ * some candidates. */
+ update_bonding_candidates(bat_priv, orig_node);
+ }
}
return false;
@@ -271,49 +281,41 @@ void purge_orig(struct work_struct *work)
start_purge_timer();
}
-ssize_t orig_fill_buffer_text(struct net_device *net_dev, char *buff,
- size_t count, loff_t off)
+int orig_seq_print_text(struct seq_file *seq, void *offset)
{
HASHIT(hashit);
+ struct net_device *net_dev = (struct net_device *)seq->private;
struct bat_priv *bat_priv = netdev_priv(net_dev);
struct orig_node *orig_node;
struct neigh_node *neigh_node;
- size_t hdr_len, tmp_len;
- int batman_count = 0, bytes_written = 0;
+ int batman_count = 0;
+ int last_seen_secs;
+ int last_seen_msecs;
unsigned long flags;
char orig_str[ETH_STR_LEN], router_str[ETH_STR_LEN];
- if (!bat_priv->primary_if) {
- if (off == 0)
- return sprintf(buff,
- "BATMAN mesh %s disabled - "
+ if ((!bat_priv->primary_if) ||
+ (bat_priv->primary_if->if_status != IF_ACTIVE)) {
+ if (!bat_priv->primary_if)
+ return seq_printf(seq, "BATMAN mesh %s disabled - "
"please specify interfaces to enable it\n",
net_dev->name);
- return 0;
+ return seq_printf(seq, "BATMAN mesh %s "
+ "disabled - primary interface not active\n",
+ net_dev->name);
}
- if (bat_priv->primary_if->if_status != IF_ACTIVE && off == 0)
- return sprintf(buff,
- "BATMAN mesh %s "
- "disabled - primary interface not active\n",
- net_dev->name);
- else if (bat_priv->primary_if->if_status != IF_ACTIVE)
- return 0;
-
rcu_read_lock();
- hdr_len = sprintf(buff,
- " %-14s (%s/%i) %17s [%10s]: %20s "
- "... [B.A.T.M.A.N. adv %s%s, MainIF/MAC: %s/%s (%s)]\n",
- "Originator", "#", TQ_MAX_VALUE, "Nexthop", "outgoingIF",
- "Potential nexthops", SOURCE_VERSION, REVISION_VERSION_STR,
+ seq_printf(seq, "[B.A.T.M.A.N. adv %s%s, MainIF/MAC: %s/%s (%s)]\n",
+ SOURCE_VERSION, REVISION_VERSION_STR,
bat_priv->primary_if->dev, bat_priv->primary_if->addr_str,
net_dev->name);
+ seq_printf(seq, " %-15s %s (%s/%i) %17s [%10s]: %20s ...\n",
+ "Originator", "last-seen", "#", TQ_MAX_VALUE, "Nexthop",
+ "outgoingIF", "Potential nexthops");
rcu_read_unlock();
- if (off < hdr_len)
- bytes_written = hdr_len;
-
spin_lock_irqsave(&orig_hash_lock, flags);
while (hash_iterate(orig_hash, &hashit)) {
@@ -326,44 +328,34 @@ ssize_t orig_fill_buffer_text(struct net_device *net_dev, char *buff,
if (orig_node->router->tq_avg == 0)
continue;
- /* estimated line length */
- if (count < bytes_written + 200)
- break;
-
addr_to_string(orig_str, orig_node->orig);
addr_to_string(router_str, orig_node->router->addr);
+ last_seen_secs = jiffies_to_msecs(jiffies -
+ orig_node->last_valid) / 1000;
+ last_seen_msecs = jiffies_to_msecs(jiffies -
+ orig_node->last_valid) % 1000;
- tmp_len = sprintf(buff + bytes_written,
- "%-17s (%3i) %17s [%10s]:",
- orig_str, orig_node->router->tq_avg,
- router_str,
- orig_node->router->if_incoming->dev);
+ seq_printf(seq, "%-17s %4i.%03is (%3i) %17s [%10s]:",
+ orig_str, last_seen_secs, last_seen_msecs,
+ orig_node->router->tq_avg, router_str,
+ orig_node->router->if_incoming->dev);
list_for_each_entry(neigh_node, &orig_node->neigh_list, list) {
addr_to_string(orig_str, neigh_node->addr);
- tmp_len += sprintf(buff + bytes_written + tmp_len,
- " %17s (%3i)", orig_str,
+ seq_printf(seq, " %17s (%3i)", orig_str,
neigh_node->tq_avg);
}
- tmp_len += sprintf(buff + bytes_written + tmp_len, "\n");
-
+ seq_printf(seq, "\n");
batman_count++;
- hdr_len += tmp_len;
-
- if (off >= hdr_len)
- continue;
-
- bytes_written += tmp_len;
}
spin_unlock_irqrestore(&orig_hash_lock, flags);
- if ((batman_count == 0) && (off == 0))
- bytes_written += sprintf(buff + bytes_written,
- "No batman nodes in range ...\n");
+ if ((batman_count == 0))
+ seq_printf(seq, "No batman nodes in range ...\n");
- return bytes_written;
+ return 0;
}
static int orig_node_add_if(struct orig_node *orig_node, int max_if_num)
@@ -373,8 +365,7 @@ static int orig_node_add_if(struct orig_node *orig_node, int max_if_num)
data_ptr = kmalloc(max_if_num * sizeof(TYPE_OF_WORD) * NUM_WORDS,
GFP_ATOMIC);
if (!data_ptr) {
- printk(KERN_ERR
- "batman-adv:Can't resize orig: out of memory\n");
+ pr_err("Can't resize orig: out of memory\n");
return -1;
}
@@ -385,8 +376,7 @@ static int orig_node_add_if(struct orig_node *orig_node, int max_if_num)
data_ptr = kmalloc(max_if_num * sizeof(uint8_t), GFP_ATOMIC);
if (!data_ptr) {
- printk(KERN_ERR
- "batman-adv:Can't resize orig: out of memory\n");
+ pr_err("Can't resize orig: out of memory\n");
return -1;
}
@@ -435,8 +425,7 @@ static int orig_node_del_if(struct orig_node *orig_node,
chunk_size = sizeof(TYPE_OF_WORD) * NUM_WORDS;
data_ptr = kmalloc(max_if_num * chunk_size, GFP_ATOMIC);
if (!data_ptr) {
- printk(KERN_ERR
- "batman-adv:Can't resize orig: out of memory\n");
+ pr_err("Can't resize orig: out of memory\n");
return -1;
}
@@ -457,8 +446,7 @@ free_bcast_own:
data_ptr = kmalloc(max_if_num * sizeof(uint8_t), GFP_ATOMIC);
if (!data_ptr) {
- printk(KERN_ERR
- "batman-adv:Can't resize orig: out of memory\n");
+ pr_err("Can't resize orig: out of memory\n");
return -1;
}
diff --git a/drivers/staging/batman-adv/originator.h b/drivers/staging/batman-adv/originator.h
index afbc7c0e8aa..e88411d9db7 100644
--- a/drivers/staging/batman-adv/originator.h
+++ b/drivers/staging/batman-adv/originator.h
@@ -19,16 +19,18 @@
*
*/
+#ifndef _NET_BATMAN_ADV_ORIGINATOR_H_
+#define _NET_BATMAN_ADV_ORIGINATOR_H_
+
int originator_init(void);
-void free_orig_node(void *data);
void originator_free(void);
void purge_orig(struct work_struct *work);
-struct orig_node *orig_find(char *mac);
struct orig_node *get_orig_node(uint8_t *addr);
struct neigh_node *
create_neighbor(struct orig_node *orig_node, struct orig_node *orig_neigh_node,
uint8_t *neigh, struct batman_if *if_incoming);
-ssize_t orig_fill_buffer_text(struct net_device *net_dev, char *buff,
- size_t count, loff_t off);
+int orig_seq_print_text(struct seq_file *seq, void *offset);
int orig_hash_add_if(struct batman_if *batman_if, int max_if_num);
int orig_hash_del_if(struct batman_if *batman_if, int max_if_num);
+
+#endif /* _NET_BATMAN_ADV_ORIGINATOR_H_ */
diff --git a/drivers/staging/batman-adv/packet.h b/drivers/staging/batman-adv/packet.h
index 152f57b1c6c..abb5e460f23 100644
--- a/drivers/staging/batman-adv/packet.h
+++ b/drivers/staging/batman-adv/packet.h
@@ -19,6 +19,9 @@
*
*/
+#ifndef _NET_BATMAN_ADV_PACKET_H_
+#define _NET_BATMAN_ADV_PACKET_H_
+
#define ETH_P_BATMAN 0x4305 /* unofficial/not registered Ethertype */
#define BAT_PACKET 0x01
@@ -28,9 +31,10 @@
#define BAT_VIS 0x05
/* this file is included by batctl which needs these defines */
-#define COMPAT_VERSION 8
+#define COMPAT_VERSION 11
#define DIRECTLINK 0x40
#define VIS_SERVER 0x20
+#define PRIMARIES_FIRST_HOP 0x10
/* ICMP message types */
#define ECHO_REPLY 0
@@ -48,7 +52,7 @@ struct batman_packet {
uint8_t version; /* batman version field */
uint8_t flags; /* 0x40: DIRECTLINK flag, 0x20 VIS_SERVER flag... */
uint8_t tq;
- uint16_t seqno;
+ uint32_t seqno;
uint8_t orig[6];
uint8_t prev_sender[6];
uint8_t ttl;
@@ -68,6 +72,23 @@ struct icmp_packet {
uint8_t uid;
} __attribute__((packed));
+#define BAT_RR_LEN 16
+
+/* icmp_packet_rr must start with all fields from imcp_packet
+ as this is assumed by code that handles ICMP packets */
+struct icmp_packet_rr {
+ uint8_t packet_type;
+ uint8_t version; /* batman version field */
+ uint8_t msg_type; /* see ICMP message types above */
+ uint8_t ttl;
+ uint8_t dst[6];
+ uint8_t orig[6];
+ uint16_t seqno;
+ uint8_t uid;
+ uint8_t rr_cur;
+ uint8_t rr[BAT_RR_LEN][ETH_ALEN];
+} __attribute__((packed));
+
struct unicast_packet {
uint8_t packet_type;
uint8_t version; /* batman version field */
@@ -79,18 +100,21 @@ struct bcast_packet {
uint8_t packet_type;
uint8_t version; /* batman version field */
uint8_t orig[6];
- uint16_t seqno;
+ uint8_t ttl;
+ uint32_t seqno;
} __attribute__((packed));
struct vis_packet {
uint8_t packet_type;
uint8_t version; /* batman version field */
uint8_t vis_type; /* which type of vis-participant sent this? */
- uint8_t seqno; /* sequence number */
uint8_t entries; /* number of entries behind this struct */
+ uint32_t seqno; /* sequence number */
uint8_t ttl; /* TTL */
uint8_t vis_orig[6]; /* originator that informs about its
* neighbors */
uint8_t target_orig[6]; /* who should receive this packet */
uint8_t sender_orig[6]; /* who sent or rebroadcasted this packet */
} __attribute__((packed));
+
+#endif /* _NET_BATMAN_ADV_PACKET_H_ */
diff --git a/drivers/staging/batman-adv/ring_buffer.h b/drivers/staging/batman-adv/ring_buffer.h
index b8c9456558b..6b0cb9aaeba 100644
--- a/drivers/staging/batman-adv/ring_buffer.h
+++ b/drivers/staging/batman-adv/ring_buffer.h
@@ -19,5 +19,10 @@
*
*/
+#ifndef _NET_BATMAN_ADV_RING_BUFFER_H_
+#define _NET_BATMAN_ADV_RING_BUFFER_H_
+
void ring_buffer_set(uint8_t lq_recv[], uint8_t *lq_index, uint8_t value);
uint8_t ring_buffer_avg(uint8_t lq_recv[]);
+
+#endif /* _NET_BATMAN_ADV_RING_BUFFER_H_ */
diff --git a/drivers/staging/batman-adv/routing.c b/drivers/staging/batman-adv/routing.c
index 066dc8b3881..066cc9149bf 100644
--- a/drivers/staging/batman-adv/routing.c
+++ b/drivers/staging/batman-adv/routing.c
@@ -25,7 +25,7 @@
#include "hash.h"
#include "soft-interface.h"
#include "hard-interface.h"
-#include "device.h"
+#include "icmp_socket.h"
#include "translation-table.h"
#include "originator.h"
#include "types.h"
@@ -33,7 +33,7 @@
#include "vis.h"
#include "aggregation.h"
-DECLARE_WAIT_QUEUE_HEAD(thread_wait);
+static DECLARE_WAIT_QUEUE_HEAD(thread_wait);
void slide_own_bcast_window(struct batman_if *batman_if)
{
@@ -77,24 +77,27 @@ static void update_route(struct orig_node *orig_node,
struct neigh_node *neigh_node,
unsigned char *hna_buff, int hna_buff_len)
{
+ /* FIXME: each orig_node->batman_if will be attached to a softif */
+ struct bat_priv *bat_priv = netdev_priv(soft_device);
+
/* route deleted */
if ((orig_node->router != NULL) && (neigh_node == NULL)) {
- bat_dbg(DBG_ROUTES, "Deleting route towards: %pM\n",
+ bat_dbg(DBG_ROUTES, bat_priv, "Deleting route towards: %pM\n",
orig_node->orig);
hna_global_del_orig(orig_node, "originator timed out");
/* route added */
} else if ((orig_node->router == NULL) && (neigh_node != NULL)) {
- bat_dbg(DBG_ROUTES,
+ bat_dbg(DBG_ROUTES, bat_priv,
"Adding route towards: %pM (via %pM)\n",
orig_node->orig, neigh_node->addr);
hna_global_add_orig(orig_node, hna_buff, hna_buff_len);
/* route changed */
} else {
- bat_dbg(DBG_ROUTES,
+ bat_dbg(DBG_ROUTES, bat_priv,
"Changing route towards: %pM "
"(now via %pM - was via %pM)\n",
orig_node->orig, neigh_node->addr,
@@ -120,11 +123,13 @@ void update_routes(struct orig_node *orig_node,
update_HNA(orig_node, hna_buff, hna_buff_len);
}
-static int isBidirectionalNeigh(struct orig_node *orig_node,
+static int is_bidirectional_neigh(struct orig_node *orig_node,
struct orig_node *orig_neigh_node,
struct batman_packet *batman_packet,
struct batman_if *if_incoming)
{
+ /* FIXME: each orig_node->batman_if will be attached to a softif */
+ struct bat_priv *bat_priv = netdev_priv(soft_device);
struct neigh_node *neigh_node = NULL, *tmp_neigh_node = NULL;
unsigned char total_count;
@@ -211,7 +216,7 @@ static int isBidirectionalNeigh(struct orig_node *orig_node,
orig_neigh_node->tq_asym_penalty) /
(TQ_MAX_VALUE * TQ_MAX_VALUE));
- bat_dbg(DBG_BATMAN,
+ bat_dbg(DBG_BATMAN, bat_priv,
"bidirectional: "
"orig = %-15pM neigh = %-15pM => own_bcast = %2i, "
"real recv = %2i, local tq: %3i, asym_penalty: %3i, "
@@ -234,10 +239,12 @@ static void update_orig(struct orig_node *orig_node, struct ethhdr *ethhdr,
unsigned char *hna_buff, int hna_buff_len,
char is_duplicate)
{
+ /* FIXME: get bat_priv */
+ struct bat_priv *bat_priv = netdev_priv(soft_device);
struct neigh_node *neigh_node = NULL, *tmp_neigh_node = NULL;
int tmp_hna_buff_len;
- bat_dbg(DBG_BATMAN, "update_originator(): "
+ bat_dbg(DBG_BATMAN, bat_priv, "update_originator(): "
"Searching and updating originator entry of received packet\n");
list_for_each_entry(tmp_neigh_node, &orig_node->neigh_list, list) {
@@ -269,7 +276,7 @@ static void update_orig(struct orig_node *orig_node, struct ethhdr *ethhdr,
if (!neigh_node)
return;
} else
- bat_dbg(DBG_BATMAN,
+ bat_dbg(DBG_BATMAN, bat_priv,
"Updating existing last-hop neighbor of originator\n");
orig_node->flags = batman_packet->flags;
@@ -318,16 +325,19 @@ update_hna:
* 0 if the packet is to be accepted
* 1 if the packet is to be ignored.
*/
-static int window_protected(int16_t seq_num_diff,
+static int window_protected(int32_t seq_num_diff,
unsigned long *last_reset)
{
+ /* FIXME: each orig_node->batman_if will be attached to a softif */
+ struct bat_priv *bat_priv = netdev_priv(soft_device);
+
if ((seq_num_diff <= -TQ_LOCAL_WINDOW_SIZE)
|| (seq_num_diff >= EXPECTED_SEQNO_RANGE)) {
if (time_after(jiffies, *last_reset +
msecs_to_jiffies(RESET_PROTECTION_MS))) {
*last_reset = jiffies;
- bat_dbg(DBG_BATMAN,
+ bat_dbg(DBG_BATMAN, bat_priv,
"old packet received, start protection\n");
return 0;
@@ -349,10 +359,12 @@ static char count_real_packets(struct ethhdr *ethhdr,
struct batman_packet *batman_packet,
struct batman_if *if_incoming)
{
+ /* FIXME: each orig_node->batman_if will be attached to a softif */
+ struct bat_priv *bat_priv = netdev_priv(soft_device);
struct orig_node *orig_node;
struct neigh_node *tmp_neigh_node;
char is_duplicate = 0;
- int16_t seq_diff;
+ int32_t seq_diff;
int need_update = 0;
int set_mark;
@@ -387,7 +399,8 @@ static char count_real_packets(struct ethhdr *ethhdr,
}
if (need_update) {
- bat_dbg(DBG_BATMAN, "updating last_seqno: old %d, new %d\n",
+ bat_dbg(DBG_BATMAN, bat_priv,
+ "updating last_seqno: old %d, new %d\n",
orig_node->last_real_seqno, batman_packet->seqno);
orig_node->last_real_seqno = batman_packet->seqno;
}
@@ -395,18 +408,127 @@ static char count_real_packets(struct ethhdr *ethhdr,
return is_duplicate;
}
+/* copy primary address for bonding */
+static void mark_bonding_address(struct bat_priv *bat_priv,
+ struct orig_node *orig_node,
+ struct orig_node *orig_neigh_node,
+ struct batman_packet *batman_packet)
+
+{
+ if (batman_packet->flags & PRIMARIES_FIRST_HOP)
+ memcpy(orig_neigh_node->primary_addr,
+ orig_node->orig, ETH_ALEN);
+
+ return;
+}
+
+/* mark possible bond.candidates in the neighbor list */
+void update_bonding_candidates(struct bat_priv *bat_priv,
+ struct orig_node *orig_node)
+{
+ int candidates;
+ int interference_candidate;
+ int best_tq;
+ struct neigh_node *tmp_neigh_node, *tmp_neigh_node2;
+ struct neigh_node *first_candidate, *last_candidate;
+
+ /* update the candidates for this originator */
+ if (!orig_node->router) {
+ orig_node->bond.candidates = 0;
+ return;
+ }
+
+ best_tq = orig_node->router->tq_avg;
+
+ /* update bond.candidates */
+
+ candidates = 0;
+
+ /* mark other nodes which also received "PRIMARIES FIRST HOP" packets
+ * as "bonding partner" */
+
+ /* first, zero the list */
+ list_for_each_entry(tmp_neigh_node, &orig_node->neigh_list, list) {
+ tmp_neigh_node->next_bond_candidate = NULL;
+ }
+
+ first_candidate = NULL;
+ last_candidate = NULL;
+ list_for_each_entry(tmp_neigh_node, &orig_node->neigh_list, list) {
+
+ /* only consider if it has the same primary address ... */
+ if (memcmp(orig_node->orig,
+ tmp_neigh_node->orig_node->primary_addr,
+ ETH_ALEN) != 0)
+ continue;
+
+ /* ... and is good enough to be considered */
+ if (tmp_neigh_node->tq_avg < best_tq - BONDING_TQ_THRESHOLD)
+ continue;
+
+ /* check if we have another candidate with the same
+ * mac address or interface. If we do, we won't
+ * select this candidate because of possible interference. */
+
+ interference_candidate = 0;
+ list_for_each_entry(tmp_neigh_node2,
+ &orig_node->neigh_list, list) {
+
+ if (tmp_neigh_node2 == tmp_neigh_node)
+ continue;
+
+ /* we only care if the other candidate is even
+ * considered as candidate. */
+ if (tmp_neigh_node2->next_bond_candidate == NULL)
+ continue;
+
+
+ if ((tmp_neigh_node->if_incoming ==
+ tmp_neigh_node2->if_incoming)
+ || (memcmp(tmp_neigh_node->addr,
+ tmp_neigh_node2->addr, ETH_ALEN) == 0)) {
+
+ interference_candidate = 1;
+ break;
+ }
+ }
+ /* don't care further if it is an interference candidate */
+ if (interference_candidate)
+ continue;
+
+ if (first_candidate == NULL) {
+ first_candidate = tmp_neigh_node;
+ tmp_neigh_node->next_bond_candidate = first_candidate;
+ } else
+ tmp_neigh_node->next_bond_candidate = last_candidate;
+
+ last_candidate = tmp_neigh_node;
+
+ candidates++;
+ }
+
+ if (candidates > 0) {
+ first_candidate->next_bond_candidate = last_candidate;
+ orig_node->bond.selected = first_candidate;
+ }
+
+ orig_node->bond.candidates = candidates;
+}
+
void receive_bat_packet(struct ethhdr *ethhdr,
struct batman_packet *batman_packet,
unsigned char *hna_buff, int hna_buff_len,
struct batman_if *if_incoming)
{
+ /* FIXME: each orig_node->batman_if will be attached to a softif */
+ struct bat_priv *bat_priv = netdev_priv(soft_device);
struct batman_if *batman_if;
struct orig_node *orig_neigh_node, *orig_node;
char has_directlink_flag;
char is_my_addr = 0, is_my_orig = 0, is_my_oldorig = 0;
char is_broadcast = 0, is_bidirectional, is_single_hop_neigh;
char is_duplicate;
- unsigned short if_incoming_seqno;
+ uint32_t if_incoming_seqno;
/* Silently drop when the batman packet is actually not a
* correct packet.
@@ -431,7 +553,8 @@ void receive_bat_packet(struct ethhdr *ethhdr,
is_single_hop_neigh = (compare_orig(ethhdr->h_source,
batman_packet->orig) ? 1 : 0);
- bat_dbg(DBG_BATMAN, "Received BATMAN packet via NB: %pM, IF: %s [%s] "
+ bat_dbg(DBG_BATMAN, bat_priv,
+ "Received BATMAN packet via NB: %pM, IF: %s [%s] "
"(from OG: %pM, via prev OG: %pM, seqno %d, tq %d, "
"TTL %d, V %d, IDF %d)\n",
ethhdr->h_source, if_incoming->dev, if_incoming->addr_str,
@@ -455,19 +578,19 @@ void receive_bat_packet(struct ethhdr *ethhdr,
batman_if->net_dev->dev_addr))
is_my_oldorig = 1;
- if (compare_orig(ethhdr->h_source, broadcastAddr))
+ if (compare_orig(ethhdr->h_source, broadcast_addr))
is_broadcast = 1;
}
if (batman_packet->version != COMPAT_VERSION) {
- bat_dbg(DBG_BATMAN,
+ bat_dbg(DBG_BATMAN, bat_priv,
"Drop packet: incompatible batman version (%i)\n",
batman_packet->version);
return;
}
if (is_my_addr) {
- bat_dbg(DBG_BATMAN,
+ bat_dbg(DBG_BATMAN, bat_priv,
"Drop packet: received my own broadcast (sender: %pM"
")\n",
ethhdr->h_source);
@@ -475,7 +598,7 @@ void receive_bat_packet(struct ethhdr *ethhdr,
}
if (is_broadcast) {
- bat_dbg(DBG_BATMAN, "Drop packet: "
+ bat_dbg(DBG_BATMAN, bat_priv, "Drop packet: "
"ignoring all packets with broadcast source addr (sender: %pM"
")\n", ethhdr->h_source);
return;
@@ -505,13 +628,13 @@ void receive_bat_packet(struct ethhdr *ethhdr,
bit_packet_count(word);
}
- bat_dbg(DBG_BATMAN, "Drop packet: "
+ bat_dbg(DBG_BATMAN, bat_priv, "Drop packet: "
"originator packet from myself (via neighbor)\n");
return;
}
if (is_my_oldorig) {
- bat_dbg(DBG_BATMAN,
+ bat_dbg(DBG_BATMAN, bat_priv,
"Drop packet: ignoring all rebroadcast echos (sender: "
"%pM)\n", ethhdr->h_source);
return;
@@ -524,14 +647,14 @@ void receive_bat_packet(struct ethhdr *ethhdr,
is_duplicate = count_real_packets(ethhdr, batman_packet, if_incoming);
if (is_duplicate == -1) {
- bat_dbg(DBG_BATMAN,
+ bat_dbg(DBG_BATMAN, bat_priv,
"Drop packet: packet within seqno protection time "
"(sender: %pM)\n", ethhdr->h_source);
return;
}
if (batman_packet->tq == 0) {
- bat_dbg(DBG_BATMAN,
+ bat_dbg(DBG_BATMAN, bat_priv,
"Drop packet: originator packet with tq equal 0\n");
return;
}
@@ -544,7 +667,7 @@ void receive_bat_packet(struct ethhdr *ethhdr,
!(compare_orig(batman_packet->orig, batman_packet->prev_sender)) &&
(compare_orig(orig_node->router->addr,
orig_node->router->orig_node->router->addr))) {
- bat_dbg(DBG_BATMAN,
+ bat_dbg(DBG_BATMAN, bat_priv,
"Drop packet: ignoring all rebroadcast packets that "
"may make me loop (sender: %pM)\n", ethhdr->h_source);
return;
@@ -561,11 +684,12 @@ void receive_bat_packet(struct ethhdr *ethhdr,
* don't route towards it */
if (!is_single_hop_neigh &&
(orig_neigh_node->router == NULL)) {
- bat_dbg(DBG_BATMAN, "Drop packet: OGM via unknown neighbor!\n");
+ bat_dbg(DBG_BATMAN, bat_priv,
+ "Drop packet: OGM via unknown neighbor!\n");
return;
}
- is_bidirectional = isBidirectionalNeigh(orig_node, orig_neigh_node,
+ is_bidirectional = is_bidirectional_neigh(orig_node, orig_neigh_node,
batman_packet, if_incoming);
/* update ranking if it is not a duplicate or has the same
@@ -577,6 +701,10 @@ void receive_bat_packet(struct ethhdr *ethhdr,
update_orig(orig_node, ethhdr, batman_packet,
if_incoming, hna_buff, hna_buff_len, is_duplicate);
+ mark_bonding_address(bat_priv, orig_node,
+ orig_neigh_node, batman_packet);
+ update_bonding_candidates(bat_priv, orig_node);
+
/* is single hop (direct) neighbor */
if (is_single_hop_neigh) {
@@ -584,24 +712,25 @@ void receive_bat_packet(struct ethhdr *ethhdr,
schedule_forward_packet(orig_node, ethhdr, batman_packet,
1, hna_buff_len, if_incoming);
- bat_dbg(DBG_BATMAN, "Forwarding packet: "
+ bat_dbg(DBG_BATMAN, bat_priv, "Forwarding packet: "
"rebroadcast neighbor packet with direct link flag\n");
return;
}
/* multihop originator */
if (!is_bidirectional) {
- bat_dbg(DBG_BATMAN,
+ bat_dbg(DBG_BATMAN, bat_priv,
"Drop packet: not received via bidirectional link\n");
return;
}
if (is_duplicate) {
- bat_dbg(DBG_BATMAN, "Drop packet: duplicate packet received\n");
+ bat_dbg(DBG_BATMAN, bat_priv,
+ "Drop packet: duplicate packet received\n");
return;
}
- bat_dbg(DBG_BATMAN,
+ bat_dbg(DBG_BATMAN, bat_priv,
"Forwarding packet: rebroadcast originator packet\n");
schedule_forward_packet(orig_node, ethhdr, batman_packet,
0, hna_buff_len, if_incoming);
@@ -652,10 +781,10 @@ int recv_bat_packet(struct sk_buff *skb,
return NET_RX_SUCCESS;
}
-static int recv_my_icmp_packet(struct sk_buff *skb)
+static int recv_my_icmp_packet(struct sk_buff *skb, size_t icmp_len)
{
struct orig_node *orig_node;
- struct icmp_packet *icmp_packet;
+ struct icmp_packet_rr *icmp_packet;
struct ethhdr *ethhdr;
struct sk_buff *skb_old;
struct batman_if *batman_if;
@@ -663,12 +792,12 @@ static int recv_my_icmp_packet(struct sk_buff *skb)
unsigned long flags;
uint8_t dstaddr[ETH_ALEN];
- icmp_packet = (struct icmp_packet *)skb->data;
+ icmp_packet = (struct icmp_packet_rr *)skb->data;
ethhdr = (struct ethhdr *)skb_mac_header(skb);
/* add data to device queue */
if (icmp_packet->msg_type != ECHO_REQUEST) {
- bat_device_receive_packet(icmp_packet);
+ bat_socket_receive_packet(icmp_packet, icmp_len);
return NET_RX_DROP;
}
@@ -690,13 +819,12 @@ static int recv_my_icmp_packet(struct sk_buff *skb)
/* create a copy of the skb, if needed, to modify it. */
skb_old = NULL;
- if (!skb_clone_writable(skb, sizeof(struct icmp_packet))) {
+ if (!skb_clone_writable(skb, icmp_len)) {
skb_old = skb;
skb = skb_copy(skb, GFP_ATOMIC);
if (!skb)
return NET_RX_DROP;
-
- icmp_packet = (struct icmp_packet *)skb->data;
+ icmp_packet = (struct icmp_packet_rr *)skb->data;
ethhdr = (struct ethhdr *)skb_mac_header(skb);
kfree_skb(skb_old);
}
@@ -715,7 +843,7 @@ static int recv_my_icmp_packet(struct sk_buff *skb)
return ret;
}
-static int recv_icmp_ttl_exceeded(struct sk_buff *skb)
+static int recv_icmp_ttl_exceeded(struct sk_buff *skb, size_t icmp_len)
{
struct orig_node *orig_node;
struct icmp_packet *icmp_packet;
@@ -731,10 +859,9 @@ static int recv_icmp_ttl_exceeded(struct sk_buff *skb)
/* send TTL exceeded if packet is an echo request (traceroute) */
if (icmp_packet->msg_type != ECHO_REQUEST) {
- printk(KERN_WARNING "batman-adv:"
- "Warning - can't forward icmp packet from %pM to %pM: "
- "ttl exceeded\n",
- icmp_packet->orig, icmp_packet->dst);
+ pr_warning("Warning - can't forward icmp packet from %pM to "
+ "%pM: ttl exceeded\n", icmp_packet->orig,
+ icmp_packet->dst);
return NET_RX_DROP;
}
@@ -754,7 +881,7 @@ static int recv_icmp_ttl_exceeded(struct sk_buff *skb)
spin_unlock_irqrestore(&orig_hash_lock, flags);
/* create a copy of the skb, if needed, to modify it. */
- if (!skb_clone_writable(skb, sizeof(struct icmp_packet))) {
+ if (!skb_clone_writable(skb, icmp_len)) {
skb_old = skb;
skb = skb_copy(skb, GFP_ATOMIC);
if (!skb)
@@ -781,7 +908,7 @@ static int recv_icmp_ttl_exceeded(struct sk_buff *skb)
int recv_icmp_packet(struct sk_buff *skb)
{
- struct icmp_packet *icmp_packet;
+ struct icmp_packet_rr *icmp_packet;
struct ethhdr *ethhdr;
struct orig_node *orig_node;
struct sk_buff *skb_old;
@@ -791,6 +918,12 @@ int recv_icmp_packet(struct sk_buff *skb)
unsigned long flags;
uint8_t dstaddr[ETH_ALEN];
+ /**
+ * we truncate all incoming icmp packets if they don't match our size
+ */
+ if (skb_headlen(skb) >= sizeof(struct icmp_packet_rr))
+ hdr_size = sizeof(struct icmp_packet_rr);
+
/* drop packet if it has not necessary minimum size */
if (skb_headlen(skb) < hdr_size)
return NET_RX_DROP;
@@ -809,15 +942,23 @@ int recv_icmp_packet(struct sk_buff *skb)
if (!is_my_mac(ethhdr->h_dest))
return NET_RX_DROP;
- icmp_packet = (struct icmp_packet *)skb->data;
+ icmp_packet = (struct icmp_packet_rr *)skb->data;
+
+ /* add record route information if not full */
+ if ((hdr_size == sizeof(struct icmp_packet_rr)) &&
+ (icmp_packet->rr_cur < BAT_RR_LEN)) {
+ memcpy(&(icmp_packet->rr[icmp_packet->rr_cur]),
+ ethhdr->h_dest, ETH_ALEN);
+ icmp_packet->rr_cur++;
+ }
/* packet for me */
if (is_my_mac(icmp_packet->dst))
- return recv_my_icmp_packet(skb);
+ return recv_my_icmp_packet(skb, hdr_size);
/* TTL exceeded */
if (icmp_packet->ttl < 2)
- return recv_icmp_ttl_exceeded(skb);
+ return recv_icmp_ttl_exceeded(skb, hdr_size);
ret = NET_RX_DROP;
@@ -836,12 +977,12 @@ int recv_icmp_packet(struct sk_buff *skb)
spin_unlock_irqrestore(&orig_hash_lock, flags);
/* create a copy of the skb, if needed, to modify it. */
- if (!skb_clone_writable(skb, sizeof(struct icmp_packet))) {
+ if (!skb_clone_writable(skb, hdr_size)) {
skb_old = skb;
skb = skb_copy(skb, GFP_ATOMIC);
if (!skb)
return NET_RX_DROP;
- icmp_packet = (struct icmp_packet *)skb->data;
+ icmp_packet = (struct icmp_packet_rr *)skb->data;
ethhdr = (struct ethhdr *)skb_mac_header(skb);
kfree_skb(skb_old);
}
@@ -859,16 +1000,109 @@ int recv_icmp_packet(struct sk_buff *skb)
return ret;
}
-int recv_unicast_packet(struct sk_buff *skb)
+/* find a suitable router for this originator, and use
+ * bonding if possible. */
+struct neigh_node *find_router(struct orig_node *orig_node,
+ struct batman_if *recv_if)
+{
+ /* FIXME: each orig_node->batman_if will be attached to a softif */
+ struct bat_priv *bat_priv = netdev_priv(soft_device);
+ struct orig_node *primary_orig_node;
+ struct orig_node *router_orig;
+ struct neigh_node *router, *first_candidate, *best_router;
+ static uint8_t zero_mac[ETH_ALEN] = {0, 0, 0, 0, 0, 0};
+ int bonding_enabled;
+
+ if (!orig_node)
+ return NULL;
+
+ if (!orig_node->router)
+ return NULL;
+
+ /* without bonding, the first node should
+ * always choose the default router. */
+
+ bonding_enabled = atomic_read(&bat_priv->bonding_enabled);
+ if (!bonding_enabled && (recv_if == NULL))
+ return orig_node->router;
+
+ router_orig = orig_node->router->orig_node;
+
+ /* if we have something in the primary_addr, we can search
+ * for a potential bonding candidate. */
+ if (memcmp(router_orig->primary_addr, zero_mac, ETH_ALEN) == 0)
+ return orig_node->router;
+
+ /* find the orig_node which has the primary interface. might
+ * even be the same as our router_orig in many cases */
+
+ if (memcmp(router_orig->primary_addr,
+ router_orig->orig, ETH_ALEN) == 0) {
+ primary_orig_node = router_orig;
+ } else {
+ primary_orig_node = hash_find(orig_hash,
+ router_orig->primary_addr);
+ if (!primary_orig_node)
+ return orig_node->router;
+ }
+
+ /* with less than 2 candidates, we can't do any
+ * bonding and prefer the original router. */
+
+ if (primary_orig_node->bond.candidates < 2)
+ return orig_node->router;
+
+
+ /* all nodes between should choose a candidate which
+ * is is not on the interface where the packet came
+ * in. */
+ first_candidate = primary_orig_node->bond.selected;
+ router = first_candidate;
+
+ if (bonding_enabled) {
+ /* in the bonding case, send the packets in a round
+ * robin fashion over the remaining interfaces. */
+ do {
+ /* recv_if == NULL on the first node. */
+ if (router->if_incoming != recv_if)
+ break;
+
+ router = router->next_bond_candidate;
+ } while (router != first_candidate);
+
+ primary_orig_node->bond.selected = router->next_bond_candidate;
+
+ } else {
+ /* if bonding is disabled, use the best of the
+ * remaining candidates which are not using
+ * this interface. */
+ best_router = first_candidate;
+
+ do {
+ /* recv_if == NULL on the first node. */
+ if ((router->if_incoming != recv_if) &&
+ (router->tq_avg > best_router->tq_avg))
+ best_router = router;
+
+ router = router->next_bond_candidate;
+ } while (router != first_candidate);
+
+ router = best_router;
+ }
+
+ return router;
+}
+
+int recv_unicast_packet(struct sk_buff *skb, struct batman_if *recv_if)
{
struct unicast_packet *unicast_packet;
struct orig_node *orig_node;
+ struct neigh_node *router;
struct ethhdr *ethhdr;
struct batman_if *batman_if;
struct sk_buff *skb_old;
uint8_t dstaddr[ETH_ALEN];
int hdr_size = sizeof(struct unicast_packet);
- int ret;
unsigned long flags;
/* drop packet if it has not necessary minimum size */
@@ -899,49 +1133,50 @@ int recv_unicast_packet(struct sk_buff *skb)
/* TTL exceeded */
if (unicast_packet->ttl < 2) {
- printk(KERN_WARNING "batman-adv:Warning - "
- "can't forward unicast packet from %pM to %pM: "
- "ttl exceeded\n",
- ethhdr->h_source, unicast_packet->dest);
+ pr_warning("Warning - can't forward unicast packet from %pM to "
+ "%pM: ttl exceeded\n", ethhdr->h_source,
+ unicast_packet->dest);
return NET_RX_DROP;
}
- ret = NET_RX_DROP;
/* get routing information */
spin_lock_irqsave(&orig_hash_lock, flags);
orig_node = ((struct orig_node *)
hash_find(orig_hash, unicast_packet->dest));
- if ((orig_node != NULL) &&
- (orig_node->router != NULL)) {
+ router = find_router(orig_node, recv_if);
- /* don't lock while sending the packets ... we therefore
- * copy the required data before sending */
- batman_if = orig_node->router->if_incoming;
- memcpy(dstaddr, orig_node->router->addr, ETH_ALEN);
+ if (!router) {
spin_unlock_irqrestore(&orig_hash_lock, flags);
+ return NET_RX_DROP;
+ }
- /* create a copy of the skb, if needed, to modify it. */
- if (!skb_clone_writable(skb, sizeof(struct unicast_packet))) {
- skb_old = skb;
- skb = skb_copy(skb, GFP_ATOMIC);
- if (!skb)
- return NET_RX_DROP;
- unicast_packet = (struct unicast_packet *)skb->data;
- ethhdr = (struct ethhdr *)skb_mac_header(skb);
- kfree_skb(skb_old);
- }
- /* decrement ttl */
- unicast_packet->ttl--;
+ /* don't lock while sending the packets ... we therefore
+ * copy the required data before sending */
- /* route it */
- send_skb_packet(skb, batman_if, dstaddr);
- ret = NET_RX_SUCCESS;
+ batman_if = router->if_incoming;
+ memcpy(dstaddr, router->addr, ETH_ALEN);
- } else
- spin_unlock_irqrestore(&orig_hash_lock, flags);
+ spin_unlock_irqrestore(&orig_hash_lock, flags);
- return ret;
+ /* create a copy of the skb, if needed, to modify it. */
+ if (!skb_clone_writable(skb, sizeof(struct unicast_packet))) {
+ skb_old = skb;
+ skb = skb_copy(skb, GFP_ATOMIC);
+ if (!skb)
+ return NET_RX_DROP;
+ unicast_packet = (struct unicast_packet *) skb->data;
+ ethhdr = (struct ethhdr *)skb_mac_header(skb);
+ kfree_skb(skb_old);
+ }
+
+ /* decrement ttl */
+ unicast_packet->ttl--;
+
+ /* route it */
+ send_skb_packet(skb, batman_if, dstaddr);
+
+ return NET_RX_SUCCESS;
}
int recv_bcast_packet(struct sk_buff *skb)
@@ -950,7 +1185,7 @@ int recv_bcast_packet(struct sk_buff *skb)
struct bcast_packet *bcast_packet;
struct ethhdr *ethhdr;
int hdr_size = sizeof(struct bcast_packet);
- int16_t seq_diff;
+ int32_t seq_diff;
unsigned long flags;
/* drop packet if it has not necessary minimum size */
@@ -977,6 +1212,9 @@ int recv_bcast_packet(struct sk_buff *skb)
if (is_my_mac(bcast_packet->orig))
return NET_RX_DROP;
+ if (bcast_packet->ttl < 2)
+ return NET_RX_DROP;
+
spin_lock_irqsave(&orig_hash_lock, flags);
orig_node = ((struct orig_node *)
hash_find(orig_hash, bcast_packet->orig));
@@ -989,12 +1227,12 @@ int recv_bcast_packet(struct sk_buff *skb)
/* check whether the packet is a duplicate */
if (get_bit_status(orig_node->bcast_bits,
orig_node->last_bcast_seqno,
- ntohs(bcast_packet->seqno))) {
+ ntohl(bcast_packet->seqno))) {
spin_unlock_irqrestore(&orig_hash_lock, flags);
return NET_RX_DROP;
}
- seq_diff = ntohs(bcast_packet->seqno) - orig_node->last_bcast_seqno;
+ seq_diff = ntohl(bcast_packet->seqno) - orig_node->last_bcast_seqno;
/* check whether the packet is old and the host just restarted. */
if (window_protected(seq_diff, &orig_node->bcast_seqno_reset)) {
@@ -1005,7 +1243,7 @@ int recv_bcast_packet(struct sk_buff *skb)
/* mark broadcast in flood history, update window position
* if required. */
if (bit_get_packet(orig_node->bcast_bits, seq_diff, 1))
- orig_node->last_bcast_seqno = ntohs(bcast_packet->seqno);
+ orig_node->last_bcast_seqno = ntohl(bcast_packet->seqno);
spin_unlock_irqrestore(&orig_hash_lock, flags);
/* rebroadcast packet */
diff --git a/drivers/staging/batman-adv/routing.h b/drivers/staging/batman-adv/routing.h
index 8288decea37..3eac64e3cf9 100644
--- a/drivers/staging/batman-adv/routing.h
+++ b/drivers/staging/batman-adv/routing.h
@@ -19,9 +19,10 @@
*
*/
-#include "types.h"
+#ifndef _NET_BATMAN_ADV_ROUTING_H_
+#define _NET_BATMAN_ADV_ROUTING_H_
-extern wait_queue_head_t thread_wait;
+#include "types.h"
void slide_own_bcast_window(struct batman_if *batman_if);
void receive_bat_packet(struct ethhdr *ethhdr,
@@ -32,8 +33,14 @@ void update_routes(struct orig_node *orig_node,
struct neigh_node *neigh_node,
unsigned char *hna_buff, int hna_buff_len);
int recv_icmp_packet(struct sk_buff *skb);
-int recv_unicast_packet(struct sk_buff *skb);
+int recv_unicast_packet(struct sk_buff *skb, struct batman_if *recv_if);
int recv_bcast_packet(struct sk_buff *skb);
int recv_vis_packet(struct sk_buff *skb);
int recv_bat_packet(struct sk_buff *skb,
struct batman_if *batman_if);
+struct neigh_node *find_router(struct orig_node *orig_node,
+ struct batman_if *recv_if);
+void update_bonding_candidates(struct bat_priv *bat_priv,
+ struct orig_node *orig_node);
+
+#endif /* _NET_BATMAN_ADV_ROUTING_H_ */
diff --git a/drivers/staging/batman-adv/send.c b/drivers/staging/batman-adv/send.c
index ac69ed871a7..055edee7b4e 100644
--- a/drivers/staging/batman-adv/send.c
+++ b/drivers/staging/batman-adv/send.c
@@ -29,6 +29,10 @@
#include "vis.h"
#include "aggregation.h"
+#include <linux/netfilter_bridge.h>
+
+static void send_outstanding_bcast_packet(struct work_struct *work);
+
/* apply hop penalty for a normal link */
static uint8_t hop_penalty(const uint8_t tq)
{
@@ -38,15 +42,15 @@ static uint8_t hop_penalty(const uint8_t tq)
/* when do we schedule our own packet to be sent */
static unsigned long own_send_time(struct bat_priv *bat_priv)
{
- return jiffies +
- (((atomic_read(&bat_priv->orig_interval) - JITTER +
- (random32() % 2*JITTER)) * HZ) / 1000);
+ return jiffies + msecs_to_jiffies(
+ atomic_read(&bat_priv->orig_interval) -
+ JITTER + (random32() % 2*JITTER));
}
/* when do we schedule a forwarded packet to be sent */
static unsigned long forward_send_time(struct bat_priv *bat_priv)
{
- return jiffies + (((random32() % (JITTER/2)) * HZ) / 1000);
+ return jiffies + msecs_to_jiffies(random32() % (JITTER/2));
}
/* send out an already prepared packet to the given address via the
@@ -64,10 +68,8 @@ int send_skb_packet(struct sk_buff *skb,
goto send_skb_err;
if (!(batman_if->net_dev->flags & IFF_UP)) {
- printk(KERN_WARNING
- "batman-adv:Interface %s "
- "is not up - can't send packet via that interface!\n",
- batman_if->dev);
+ pr_warning("Interface %s is not up - can't send packet via "
+ "that interface!\n", batman_if->dev);
goto send_skb_err;
}
@@ -90,9 +92,12 @@ int send_skb_packet(struct sk_buff *skb,
/* dev_queue_xmit() returns a negative result on error. However on
* congestion and traffic shaping, it drops and returns NET_XMIT_DROP
- * (which is > 0). This will not be treated as an error. */
+ * (which is > 0). This will not be treated as an error.
+ * Also, if netfilter/ebtables wants to block outgoing batman
+ * packets then giving them a chance to do so here */
- return dev_queue_xmit(skb);
+ return NF_HOOK(PF_BRIDGE, NF_BR_LOCAL_OUT, skb, NULL, skb->dev,
+ dev_queue_xmit);
send_skb_err:
kfree_skb(skb);
return NET_XMIT_DROP;
@@ -119,6 +124,8 @@ void send_raw_packet(unsigned char *pack_buff, int pack_buff_len,
static void send_packet_to_if(struct forw_packet *forw_packet,
struct batman_if *batman_if)
{
+ /* FIXME: each batman_if will be attached to a softif */
+ struct bat_priv *bat_priv = netdev_priv(soft_device);
char *fwd_str;
uint8_t packet_num;
int16_t buff_pos;
@@ -148,11 +155,11 @@ static void send_packet_to_if(struct forw_packet *forw_packet,
fwd_str = (packet_num > 0 ? "Forwarding" : (forw_packet->own ?
"Sending own" :
"Forwarding"));
- bat_dbg(DBG_BATMAN,
+ bat_dbg(DBG_BATMAN, bat_priv,
"%s %spacket (originator %pM, seqno %d, TQ %d, TTL %d,"
" IDF %s) on interface %s [%s]\n",
fwd_str, (packet_num > 0 ? "aggregated " : ""),
- batman_packet->orig, ntohs(batman_packet->seqno),
+ batman_packet->orig, ntohl(batman_packet->seqno),
batman_packet->tq, batman_packet->ttl,
(batman_packet->flags & DIRECTLINK ?
"on" : "off"),
@@ -167,20 +174,22 @@ static void send_packet_to_if(struct forw_packet *forw_packet,
send_raw_packet(forw_packet->packet_buff,
forw_packet->packet_len,
- batman_if, broadcastAddr);
+ batman_if, broadcast_addr);
}
/* send a batman packet */
static void send_packet(struct forw_packet *forw_packet)
{
+ /* FIXME: each batman_if will be attached to a softif */
+ struct bat_priv *bat_priv = netdev_priv(soft_device);
struct batman_if *batman_if;
struct batman_packet *batman_packet =
(struct batman_packet *)(forw_packet->packet_buff);
unsigned char directlink = (batman_packet->flags & DIRECTLINK ? 1 : 0);
if (!forw_packet->if_incoming) {
- printk(KERN_ERR "batman-adv: Error - can't forward packet: "
- "incoming iface not specified\n");
+ pr_err("Error - can't forward packet: incoming iface not "
+ "specified\n");
return;
}
@@ -193,18 +202,18 @@ static void send_packet(struct forw_packet *forw_packet)
(forw_packet->own && (forw_packet->if_incoming->if_num > 0))) {
/* FIXME: what about aggregated packets ? */
- bat_dbg(DBG_BATMAN,
+ bat_dbg(DBG_BATMAN, bat_priv,
"%s packet (originator %pM, seqno %d, TTL %d) "
"on interface %s [%s]\n",
(forw_packet->own ? "Sending own" : "Forwarding"),
- batman_packet->orig, ntohs(batman_packet->seqno),
+ batman_packet->orig, ntohl(batman_packet->seqno),
batman_packet->ttl, forw_packet->if_incoming->dev,
forw_packet->if_incoming->addr_str);
send_raw_packet(forw_packet->packet_buff,
forw_packet->packet_len,
forw_packet->if_incoming,
- broadcastAddr);
+ broadcast_addr);
return;
}
@@ -276,14 +285,14 @@ void schedule_own_packet(struct batman_if *batman_if)
batman_packet = (struct batman_packet *)batman_if->packet_buff;
/* change sequence number to network order */
- batman_packet->seqno = htons((uint16_t)atomic_read(&batman_if->seqno));
+ batman_packet->seqno =
+ htonl((uint32_t)atomic_read(&batman_if->seqno));
if (vis_server == VIS_TYPE_SERVER_SYNC)
- batman_packet->flags = VIS_SERVER;
+ batman_packet->flags |= VIS_SERVER;
else
batman_packet->flags &= ~VIS_SERVER;
- /* could be read by receive_bat_packet() */
atomic_inc(&batman_if->seqno);
slide_own_bcast_window(batman_if);
@@ -306,7 +315,7 @@ void schedule_forward_packet(struct orig_node *orig_node,
unsigned long send_time;
if (batman_packet->ttl <= 1) {
- bat_dbg(DBG_BATMAN, "ttl exceeded\n");
+ bat_dbg(DBG_BATMAN, bat_priv, "ttl exceeded\n");
return;
}
@@ -335,13 +344,16 @@ void schedule_forward_packet(struct orig_node *orig_node,
/* apply hop penalty */
batman_packet->tq = hop_penalty(batman_packet->tq);
- bat_dbg(DBG_BATMAN, "Forwarding packet: tq_orig: %i, tq_avg: %i, "
+ bat_dbg(DBG_BATMAN, bat_priv,
+ "Forwarding packet: tq_orig: %i, tq_avg: %i, "
"tq_forw: %i, ttl_orig: %i, ttl_forw: %i\n",
in_tq, tq_avg, batman_packet->tq, in_ttl - 1,
batman_packet->ttl);
- batman_packet->seqno = htons(batman_packet->seqno);
+ batman_packet->seqno = htonl(batman_packet->seqno);
+ /* switch of primaries first hop flag when forwarding */
+ batman_packet->flags &= ~PRIMARIES_FIRST_HOP;
if (directlink)
batman_packet->flags |= DIRECTLINK;
else
@@ -392,9 +404,12 @@ static void _add_bcast_packet_to_list(struct forw_packet *forw_packet,
int add_bcast_packet_to_list(struct sk_buff *skb)
{
struct forw_packet *forw_packet;
+ struct bcast_packet *bcast_packet;
+ /* FIXME: each batman_if will be attached to a softif */
+ struct bat_priv *bat_priv = netdev_priv(soft_device);
if (!atomic_dec_not_zero(&bcast_queue_left)) {
- bat_dbg(DBG_BATMAN, "bcast packet queue full\n");
+ bat_dbg(DBG_BATMAN, bat_priv, "bcast packet queue full\n");
goto out;
}
@@ -407,6 +422,10 @@ int add_bcast_packet_to_list(struct sk_buff *skb)
if (!skb)
goto packet_free;
+ /* as we have a copy now, it is safe to decrease the TTL */
+ bcast_packet = (struct bcast_packet *)skb->data;
+ bcast_packet->ttl--;
+
skb_reset_mac_header(skb);
forw_packet->skb = skb;
@@ -426,7 +445,7 @@ out:
return NETDEV_TX_BUSY;
}
-void send_outstanding_bcast_packet(struct work_struct *work)
+static void send_outstanding_bcast_packet(struct work_struct *work)
{
struct batman_if *batman_if;
struct delayed_work *delayed_work =
@@ -450,7 +469,7 @@ void send_outstanding_bcast_packet(struct work_struct *work)
skb1 = skb_copy(forw_packet->skb, GFP_ATOMIC);
if (skb1)
send_skb_packet(skb1,
- batman_if, broadcastAddr);
+ batman_if, broadcast_addr);
}
rcu_read_unlock();
@@ -502,15 +521,19 @@ out:
void purge_outstanding_packets(struct batman_if *batman_if)
{
+ /* FIXME: each batman_if will be attached to a softif */
+ struct bat_priv *bat_priv = netdev_priv(soft_device);
struct forw_packet *forw_packet;
struct hlist_node *tmp_node, *safe_tmp_node;
unsigned long flags;
if (batman_if)
- bat_dbg(DBG_BATMAN, "purge_outstanding_packets(): %s\n",
+ bat_dbg(DBG_BATMAN, bat_priv,
+ "purge_outstanding_packets(): %s\n",
batman_if->dev);
else
- bat_dbg(DBG_BATMAN, "purge_outstanding_packets()\n");
+ bat_dbg(DBG_BATMAN, bat_priv,
+ "purge_outstanding_packets()\n");
/* free bcast list */
spin_lock_irqsave(&forw_bcast_list_lock, flags);
diff --git a/drivers/staging/batman-adv/send.h b/drivers/staging/batman-adv/send.h
index feaa2fc7f9a..b64c62783fe 100644
--- a/drivers/staging/batman-adv/send.h
+++ b/drivers/staging/batman-adv/send.h
@@ -19,9 +19,11 @@
*
*/
+#ifndef _NET_BATMAN_ADV_SEND_H_
+#define _NET_BATMAN_ADV_SEND_H_
+
#include "types.h"
-void send_own_packet_work(struct work_struct *work);
int send_skb_packet(struct sk_buff *skb,
struct batman_if *batman_if,
uint8_t *dst_addr);
@@ -34,6 +36,7 @@ void schedule_forward_packet(struct orig_node *orig_node,
uint8_t directlink, int hna_buff_len,
struct batman_if *if_outgoing);
int add_bcast_packet_to_list(struct sk_buff *skb);
-void send_outstanding_bcast_packet(struct work_struct *work);
void send_outstanding_bat_packet(struct work_struct *work);
void purge_outstanding_packets(struct batman_if *batman_if);
+
+#endif /* _NET_BATMAN_ADV_SEND_H_ */
diff --git a/drivers/staging/batman-adv/soft-interface.c b/drivers/staging/batman-adv/soft-interface.c
index 51c40b77c8d..2ea97de435c 100644
--- a/drivers/staging/batman-adv/soft-interface.c
+++ b/drivers/staging/batman-adv/soft-interface.c
@@ -22,6 +22,7 @@
#include "main.h"
#include "soft-interface.h"
#include "hard-interface.h"
+#include "routing.h"
#include "send.h"
#include "translation-table.h"
#include "types.h"
@@ -30,13 +31,12 @@
#include <linux/ethtool.h>
#include <linux/etherdevice.h>
-static uint16_t bcast_seqno = 1; /* give own bcast messages seq numbers to avoid
+static uint32_t bcast_seqno = 1; /* give own bcast messages seq numbers to avoid
* broadcast storms */
static int32_t skb_packets;
static int32_t skb_bad_packets;
-unsigned char mainIfAddr[ETH_ALEN];
-static unsigned char mainIfAddr_default[ETH_ALEN];
+unsigned char main_if_addr[ETH_ALEN];
static int bat_get_settings(struct net_device *dev, struct ethtool_cmd *cmd);
static void bat_get_drvinfo(struct net_device *dev,
struct ethtool_drvinfo *info);
@@ -58,12 +58,7 @@ static const struct ethtool_ops bat_ethtool_ops = {
void set_main_if_addr(uint8_t *addr)
{
- memcpy(mainIfAddr, addr, ETH_ALEN);
-}
-
-int main_if_was_up(void)
-{
- return (memcmp(mainIfAddr, mainIfAddr_default, ETH_ALEN) != 0 ? 1 : 0);
+ memcpy(main_if_addr, addr, ETH_ALEN);
}
int my_skb_push(struct sk_buff *skb, unsigned int len)
@@ -83,69 +78,25 @@ int my_skb_push(struct sk_buff *skb, unsigned int len)
return 0;
}
-#ifdef HAVE_NET_DEVICE_OPS
-static const struct net_device_ops bat_netdev_ops = {
- .ndo_open = interface_open,
- .ndo_stop = interface_release,
- .ndo_get_stats = interface_stats,
- .ndo_set_mac_address = interface_set_mac_addr,
- .ndo_change_mtu = interface_change_mtu,
- .ndo_start_xmit = interface_tx,
- .ndo_validate_addr = eth_validate_addr
-};
-#endif
-
-void interface_setup(struct net_device *dev)
-{
- struct bat_priv *priv = netdev_priv(dev);
- char dev_addr[ETH_ALEN];
-
- ether_setup(dev);
-
-#ifdef HAVE_NET_DEVICE_OPS
- dev->netdev_ops = &bat_netdev_ops;
-#else
- dev->open = interface_open;
- dev->stop = interface_release;
- dev->get_stats = interface_stats;
- dev->set_mac_address = interface_set_mac_addr;
- dev->change_mtu = interface_change_mtu;
- dev->hard_start_xmit = interface_tx;
-#endif
- dev->destructor = free_netdev;
-
- dev->mtu = hardif_min_mtu();
- dev->hard_header_len = BAT_HEADER_LEN; /* reserve more space in the
- * skbuff for our header */
-
- /* generate random address */
- random_ether_addr(dev_addr);
- memcpy(dev->dev_addr, dev_addr, ETH_ALEN);
-
- SET_ETHTOOL_OPS(dev, &bat_ethtool_ops);
-
- memset(priv, 0, sizeof(struct bat_priv));
-}
-
-int interface_open(struct net_device *dev)
+static int interface_open(struct net_device *dev)
{
netif_start_queue(dev);
return 0;
}
-int interface_release(struct net_device *dev)
+static int interface_release(struct net_device *dev)
{
netif_stop_queue(dev);
return 0;
}
-struct net_device_stats *interface_stats(struct net_device *dev)
+static struct net_device_stats *interface_stats(struct net_device *dev)
{
struct bat_priv *priv = netdev_priv(dev);
return &priv->stats;
}
-int interface_set_mac_addr(struct net_device *dev, void *p)
+static int interface_set_mac_addr(struct net_device *dev, void *p)
{
struct sockaddr *addr = p;
@@ -163,7 +114,7 @@ int interface_set_mac_addr(struct net_device *dev, void *p)
return 0;
}
-int interface_change_mtu(struct net_device *dev, int new_mtu)
+static int interface_change_mtu(struct net_device *dev, int new_mtu)
{
/* check ranges */
if ((new_mtu < 68) || (new_mtu > hardif_min_mtu()))
@@ -179,6 +130,7 @@ int interface_tx(struct sk_buff *skb, struct net_device *dev)
struct unicast_packet *unicast_packet;
struct bcast_packet *bcast_packet;
struct orig_node *orig_node;
+ struct neigh_node *router;
struct ethhdr *ethhdr = (struct ethhdr *)skb->data;
struct bat_priv *priv = netdev_priv(dev);
struct batman_if *batman_if;
@@ -205,16 +157,17 @@ int interface_tx(struct sk_buff *skb, struct net_device *dev)
bcast_packet = (struct bcast_packet *)skb->data;
bcast_packet->version = COMPAT_VERSION;
+ bcast_packet->ttl = TTL;
/* batman packet type: broadcast */
bcast_packet->packet_type = BAT_BCAST;
/* hw address of first interface is the orig mac because only
* this mac is known throughout the mesh */
- memcpy(bcast_packet->orig, mainIfAddr, ETH_ALEN);
+ memcpy(bcast_packet->orig, main_if_addr, ETH_ALEN);
/* set broadcast sequence number */
- bcast_packet->seqno = htons(bcast_seqno);
+ bcast_packet->seqno = htonl(bcast_seqno);
/* broadcast packet. on success, increase seqno. */
if (add_bcast_packet_to_list(skb) == NETDEV_TX_OK)
@@ -235,38 +188,36 @@ int interface_tx(struct sk_buff *skb, struct net_device *dev)
if (!orig_node)
orig_node = transtable_search(ethhdr->h_dest);
- if ((orig_node) &&
- (orig_node->router)) {
- struct neigh_node *router = orig_node->router;
+ router = find_router(orig_node, NULL);
- if (my_skb_push(skb, sizeof(struct unicast_packet)) < 0)
- goto unlock;
+ if (!router)
+ goto unlock;
- unicast_packet = (struct unicast_packet *)skb->data;
+ /* don't lock while sending the packets ... we therefore
+ * copy the required data before sending */
- unicast_packet->version = COMPAT_VERSION;
- /* batman packet type: unicast */
- unicast_packet->packet_type = BAT_UNICAST;
- /* set unicast ttl */
- unicast_packet->ttl = TTL;
- /* copy the destination for faster routing */
- memcpy(unicast_packet->dest, orig_node->orig, ETH_ALEN);
+ batman_if = router->if_incoming;
+ memcpy(dstaddr, router->addr, ETH_ALEN);
- /* net_dev won't be available when not active */
- if (router->if_incoming->if_status != IF_ACTIVE)
- goto unlock;
+ spin_unlock_irqrestore(&orig_hash_lock, flags);
- /* don't lock while sending the packets ... we therefore
- * copy the required data before sending */
+ if (batman_if->if_status != IF_ACTIVE)
+ goto dropped;
- batman_if = router->if_incoming;
- memcpy(dstaddr, router->addr, ETH_ALEN);
- spin_unlock_irqrestore(&orig_hash_lock, flags);
+ if (my_skb_push(skb, sizeof(struct unicast_packet)) < 0)
+ goto dropped;
- send_skb_packet(skb, batman_if, dstaddr);
- } else {
- goto unlock;
- }
+ unicast_packet = (struct unicast_packet *)skb->data;
+
+ unicast_packet->version = COMPAT_VERSION;
+ /* batman packet type: unicast */
+ unicast_packet->packet_type = BAT_UNICAST;
+ /* set unicast ttl */
+ unicast_packet->ttl = TTL;
+ /* copy the destination for faster routing */
+ memcpy(unicast_packet->dest, orig_node->orig, ETH_ALEN);
+
+ send_skb_packet(skb, batman_if, dstaddr);
}
priv->stats.tx_packets++;
@@ -315,6 +266,50 @@ void interface_rx(struct sk_buff *skb, int hdr_size)
netif_rx(skb);
}
+#ifdef HAVE_NET_DEVICE_OPS
+static const struct net_device_ops bat_netdev_ops = {
+ .ndo_open = interface_open,
+ .ndo_stop = interface_release,
+ .ndo_get_stats = interface_stats,
+ .ndo_set_mac_address = interface_set_mac_addr,
+ .ndo_change_mtu = interface_change_mtu,
+ .ndo_start_xmit = interface_tx,
+ .ndo_validate_addr = eth_validate_addr
+};
+#endif
+
+void interface_setup(struct net_device *dev)
+{
+ struct bat_priv *priv = netdev_priv(dev);
+ char dev_addr[ETH_ALEN];
+
+ ether_setup(dev);
+
+#ifdef HAVE_NET_DEVICE_OPS
+ dev->netdev_ops = &bat_netdev_ops;
+#else
+ dev->open = interface_open;
+ dev->stop = interface_release;
+ dev->get_stats = interface_stats;
+ dev->set_mac_address = interface_set_mac_addr;
+ dev->change_mtu = interface_change_mtu;
+ dev->hard_start_xmit = interface_tx;
+#endif
+ dev->destructor = free_netdev;
+
+ dev->mtu = hardif_min_mtu();
+ dev->hard_header_len = BAT_HEADER_LEN; /* reserve more space in the
+ * skbuff for our header */
+
+ /* generate random address */
+ random_ether_addr(dev_addr);
+ memcpy(dev->dev_addr, dev_addr, ETH_ALEN);
+
+ SET_ETHTOOL_OPS(dev, &bat_ethtool_ops);
+
+ memset(priv, 0, sizeof(struct bat_priv));
+}
+
/* ethtool */
static int bat_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
{
diff --git a/drivers/staging/batman-adv/soft-interface.h b/drivers/staging/batman-adv/soft-interface.h
index e7f59af7df3..63648543900 100644
--- a/drivers/staging/batman-adv/soft-interface.h
+++ b/drivers/staging/batman-adv/soft-interface.h
@@ -19,16 +19,15 @@
*
*/
+#ifndef _NET_BATMAN_ADV_SOFT_INTERFACE_H_
+#define _NET_BATMAN_ADV_SOFT_INTERFACE_H_
+
void set_main_if_addr(uint8_t *addr);
-int main_if_was_up(void);
void interface_setup(struct net_device *dev);
-int interface_open(struct net_device *dev);
-int interface_release(struct net_device *dev);
-struct net_device_stats *interface_stats(struct net_device *dev);
-int interface_set_mac_addr(struct net_device *dev, void *addr);
-int interface_change_mtu(struct net_device *dev, int new_mtu);
int interface_tx(struct sk_buff *skb, struct net_device *dev);
void interface_rx(struct sk_buff *skb, int hdr_size);
int my_skb_push(struct sk_buff *skb, unsigned int len);
-extern unsigned char mainIfAddr[];
+extern unsigned char main_if_addr[];
+
+#endif /* _NET_BATMAN_ADV_SOFT_INTERFACE_H_ */
diff --git a/drivers/staging/batman-adv/sysfs-class-net-batman-adv b/drivers/staging/batman-adv/sysfs-class-net-batman-adv
new file mode 100644
index 00000000000..38dd762def4
--- /dev/null
+++ b/drivers/staging/batman-adv/sysfs-class-net-batman-adv
@@ -0,0 +1,14 @@
+
+What: /sys/class/net/<iface>/batman-adv/mesh_iface
+Date: May 2010
+Contact: Marek Lindner <lindner_marek@yahoo.de>
+Description:
+ The /sys/class/net/<iface>/batman-adv/mesh_iface file
+ displays the batman mesh interface this <iface>
+ currently is associated with.
+
+What: /sys/class/net/<iface>/batman-adv/iface_status
+Date: May 2010
+Contact: Marek Lindner <lindner_marek@yahoo.de>
+Description:
+ Indicates the status of <iface> as it is seen by batman.
diff --git a/drivers/staging/batman-adv/sysfs-class-net-mesh b/drivers/staging/batman-adv/sysfs-class-net-mesh
new file mode 100644
index 00000000000..5aa1912e455
--- /dev/null
+++ b/drivers/staging/batman-adv/sysfs-class-net-mesh
@@ -0,0 +1,33 @@
+
+What: /sys/class/net/<mesh_iface>/mesh/aggregated_ogms
+Date: May 2010
+Contact: Marek Lindner <lindner_marek@yahoo.de>
+Description:
+ Indicates whether the batman protocol messages of the
+ mesh <mesh_iface> shall be aggregated or not.
+
+What: /sys/class/net/<mesh_iface>/mesh/bonding
+Date: June 2010
+Contact: Simon Wunderlich <siwu@hrz.tu-chemnitz.de>
+Description:
+ Indicates whether the data traffic going through the
+ mesh will be sent using multiple interfaces at the
+ same time (if available).
+
+What: /sys/class/net/<mesh_iface>/mesh/orig_interval
+Date: May 2010
+Contact: Marek Lindner <lindner_marek@yahoo.de>
+Description:
+ Defines the interval in milliseconds in which batman
+ sends its protocol messages.
+
+What: /sys/class/net/<mesh_iface>/mesh/vis_mode
+Date: May 2010
+Contact: Marek Lindner <lindner_marek@yahoo.de>
+Description:
+ Each batman node only maintains information about its
+ own local neighborhood, therefore generating graphs
+ showing the topology of the entire mesh is not easily
+ feasible without having a central instance to collect
+ the local topologies from all nodes. This file allows
+ to activate the collecting (server) mode.
diff --git a/drivers/staging/batman-adv/translation-table.c b/drivers/staging/batman-adv/translation-table.c
index e01ff2151f7..b233377d756 100644
--- a/drivers/staging/batman-adv/translation-table.c
+++ b/drivers/staging/batman-adv/translation-table.c
@@ -32,7 +32,10 @@ atomic_t hna_local_changed;
DEFINE_SPINLOCK(hna_local_hash_lock);
static DEFINE_SPINLOCK(hna_global_hash_lock);
+static void hna_local_purge(struct work_struct *work);
static DECLARE_DELAYED_WORK(hna_local_purge_wq, hna_local_purge);
+static void _hna_global_del_orig(struct hna_global_entry *hna_global_entry,
+ char *message);
static void hna_local_start_timer(void)
{
@@ -57,6 +60,8 @@ int hna_local_init(void)
void hna_local_add(uint8_t *addr)
{
+ /* FIXME: each orig_node->batman_if will be attached to a softif */
+ struct bat_priv *bat_priv = netdev_priv(soft_device);
struct hna_local_entry *hna_local_entry;
struct hna_global_entry *hna_global_entry;
struct hashtable_t *swaphash;
@@ -77,15 +82,15 @@ void hna_local_add(uint8_t *addr)
MAC-flooding. */
if ((num_hna + 1 > (ETH_DATA_LEN - BAT_PACKET_LEN) / ETH_ALEN) ||
(num_hna + 1 > 255)) {
- bat_dbg(DBG_ROUTES,
+ bat_dbg(DBG_ROUTES, bat_priv,
"Can't add new local hna entry (%pM): "
"number of local hna entries exceeds packet size\n",
addr);
return;
}
- bat_dbg(DBG_ROUTES, "Creating new local hna entry: %pM\n",
- addr);
+ bat_dbg(DBG_ROUTES, bat_priv,
+ "Creating new local hna entry: %pM\n", addr);
hna_local_entry = kmalloc(sizeof(struct hna_local_entry), GFP_ATOMIC);
if (!hna_local_entry)
@@ -111,8 +116,7 @@ void hna_local_add(uint8_t *addr)
hna_local_hash->size * 2);
if (swaphash == NULL)
- printk(KERN_ERR "batman-adv:"
- "Couldn't resize local hna hash table\n");
+ pr_err("Couldn't resize local hna hash table\n");
else
hna_local_hash = swaphash;
}
@@ -160,59 +164,54 @@ int hna_local_fill_buffer(unsigned char *buff, int buff_len)
return i;
}
-int hna_local_fill_buffer_text(struct net_device *net_dev, char *buff,
- size_t count, loff_t off)
+int hna_local_seq_print_text(struct seq_file *seq, void *offset)
{
+ struct net_device *net_dev = (struct net_device *)seq->private;
struct bat_priv *bat_priv = netdev_priv(net_dev);
struct hna_local_entry *hna_local_entry;
HASHIT(hashit);
- int bytes_written = 0;
+ HASHIT(hashit_count);
unsigned long flags;
- size_t hdr_len;
+ size_t buf_size, pos;
+ char *buff;
if (!bat_priv->primary_if) {
- if (off == 0)
- return sprintf(buff,
- "BATMAN mesh %s disabled - "
- "please specify interfaces to enable it\n",
- net_dev->name);
-
- return 0;
+ return seq_printf(seq, "BATMAN mesh %s disabled - "
+ "please specify interfaces to enable it\n",
+ net_dev->name);
}
- hdr_len = sprintf(buff,
- "Locally retrieved addresses (from %s) "
- "announced via HNA:\n",
- net_dev->name);
-
- if (off < hdr_len)
- bytes_written = hdr_len;
+ seq_printf(seq, "Locally retrieved addresses (from %s) "
+ "announced via HNA:\n",
+ net_dev->name);
spin_lock_irqsave(&hna_local_hash_lock, flags);
- while (hash_iterate(hna_local_hash, &hashit)) {
- hdr_len += 21;
-
- if (count < bytes_written + 22)
- break;
+ buf_size = 1;
+ /* Estimate length for: " * xx:xx:xx:xx:xx:xx\n" */
+ while (hash_iterate(hna_local_hash, &hashit_count))
+ buf_size += 21;
- if (off >= hdr_len)
- continue;
+ buff = kmalloc(buf_size, GFP_ATOMIC);
+ if (!buff) {
+ spin_unlock_irqrestore(&hna_local_hash_lock, flags);
+ return -ENOMEM;
+ }
+ buff[0] = '\0';
+ pos = 0;
+ while (hash_iterate(hna_local_hash, &hashit)) {
hna_local_entry = hashit.bucket->data;
- bytes_written += snprintf(buff + bytes_written, 22,
- " * " MAC_FMT "\n",
- hna_local_entry->addr[0],
- hna_local_entry->addr[1],
- hna_local_entry->addr[2],
- hna_local_entry->addr[3],
- hna_local_entry->addr[4],
- hna_local_entry->addr[5]);
+ pos += snprintf(buff + pos, 22, " * %pM\n",
+ hna_local_entry->addr);
}
spin_unlock_irqrestore(&hna_local_hash_lock, flags);
- return bytes_written;
+
+ seq_printf(seq, "%s", buff);
+ kfree(buff);
+ return 0;
}
static void _hna_local_del(void *data)
@@ -225,7 +224,9 @@ static void _hna_local_del(void *data)
static void hna_local_del(struct hna_local_entry *hna_local_entry,
char *message)
{
- bat_dbg(DBG_ROUTES, "Deleting local hna entry (%pM): %s\n",
+ /* FIXME: each orig_node->batman_if will be attached to a softif */
+ struct bat_priv *bat_priv = netdev_priv(soft_device);
+ bat_dbg(DBG_ROUTES, bat_priv, "Deleting local hna entry (%pM): %s\n",
hna_local_entry->addr, message);
hash_remove(hna_local_hash, hna_local_entry->addr);
@@ -247,7 +248,7 @@ void hna_local_remove(uint8_t *addr, char *message)
spin_unlock_irqrestore(&hna_local_hash_lock, flags);
}
-void hna_local_purge(struct work_struct *work)
+static void hna_local_purge(struct work_struct *work)
{
struct hna_local_entry *hna_local_entry;
HASHIT(hashit);
@@ -259,8 +260,7 @@ void hna_local_purge(struct work_struct *work)
while (hash_iterate(hna_local_hash, &hashit)) {
hna_local_entry = hashit.bucket->data;
- timeout = hna_local_entry->last_seen +
- ((LOCAL_HNA_TIMEOUT / 1000) * HZ);
+ timeout = hna_local_entry->last_seen + LOCAL_HNA_TIMEOUT * HZ;
if ((!hna_local_entry->never_purge) &&
time_after(jiffies, timeout))
hna_local_del(hna_local_entry, "address timed out");
@@ -296,6 +296,8 @@ int hna_global_init(void)
void hna_global_add_orig(struct orig_node *orig_node,
unsigned char *hna_buff, int hna_buff_len)
{
+ /* FIXME: each orig_node->batman_if will be attached to a softif */
+ struct bat_priv *bat_priv = netdev_priv(soft_device);
struct hna_global_entry *hna_global_entry;
struct hna_local_entry *hna_local_entry;
struct hashtable_t *swaphash;
@@ -322,7 +324,7 @@ void hna_global_add_orig(struct orig_node *orig_node,
memcpy(hna_global_entry->addr, hna_ptr, ETH_ALEN);
- bat_dbg(DBG_ROUTES,
+ bat_dbg(DBG_ROUTES, bat_priv,
"Creating new global hna entry: "
"%pM (via %pM)\n",
hna_global_entry->addr, orig_node->orig);
@@ -369,8 +371,7 @@ void hna_global_add_orig(struct orig_node *orig_node,
hna_global_hash->size * 2);
if (swaphash == NULL)
- printk(KERN_ERR "batman-adv:"
- "Couldn't resize global hna hash table\n");
+ pr_err("Couldn't resize global hna hash table\n");
else
hna_global_hash = swaphash;
}
@@ -378,71 +379,63 @@ void hna_global_add_orig(struct orig_node *orig_node,
spin_unlock_irqrestore(&hna_global_hash_lock, flags);
}
-int hna_global_fill_buffer_text(struct net_device *net_dev, char *buff,
- size_t count, loff_t off)
+int hna_global_seq_print_text(struct seq_file *seq, void *offset)
{
+ struct net_device *net_dev = (struct net_device *)seq->private;
struct bat_priv *bat_priv = netdev_priv(net_dev);
struct hna_global_entry *hna_global_entry;
HASHIT(hashit);
- int bytes_written = 0;
+ HASHIT(hashit_count);
unsigned long flags;
- size_t hdr_len;
+ size_t buf_size, pos;
+ char *buff;
if (!bat_priv->primary_if) {
- if (off == 0)
- return sprintf(buff,
- "BATMAN mesh %s disabled - "
- "please specify interfaces to enable it\n",
- net_dev->name);
-
- return 0;
+ return seq_printf(seq, "BATMAN mesh %s disabled - "
+ "please specify interfaces to enable it\n",
+ net_dev->name);
}
- hdr_len = sprintf(buff,
- "Globally announced HNAs received via the mesh %s "
- "(translation table):\n",
- net_dev->name);
-
- if (off < hdr_len)
- bytes_written = hdr_len;
+ seq_printf(seq, "Globally announced HNAs received via the mesh %s\n",
+ net_dev->name);
spin_lock_irqsave(&hna_global_hash_lock, flags);
- while (hash_iterate(hna_global_hash, &hashit)) {
- hdr_len += 43;
-
- if (count < bytes_written + 44)
- break;
+ buf_size = 1;
+ /* Estimate length for: " * xx:xx:xx:xx:xx:xx via xx:xx:xx:xx:xx:xx\n"*/
+ while (hash_iterate(hna_global_hash, &hashit_count))
+ buf_size += 43;
- if (off >= hdr_len)
- continue;
+ buff = kmalloc(buf_size, GFP_ATOMIC);
+ if (!buff) {
+ spin_unlock_irqrestore(&hna_global_hash_lock, flags);
+ return -ENOMEM;
+ }
+ buff[0] = '\0';
+ pos = 0;
+ while (hash_iterate(hna_global_hash, &hashit)) {
hna_global_entry = hashit.bucket->data;
- bytes_written += snprintf(buff + bytes_written, 44,
- " * " MAC_FMT " via " MAC_FMT "\n",
- hna_global_entry->addr[0],
- hna_global_entry->addr[1],
- hna_global_entry->addr[2],
- hna_global_entry->addr[3],
- hna_global_entry->addr[4],
- hna_global_entry->addr[5],
- hna_global_entry->orig_node->orig[0],
- hna_global_entry->orig_node->orig[1],
- hna_global_entry->orig_node->orig[2],
- hna_global_entry->orig_node->orig[3],
- hna_global_entry->orig_node->orig[4],
- hna_global_entry->orig_node->orig[5]);
+ pos += snprintf(buff + pos, 44,
+ " * %pM via %pM\n", hna_global_entry->addr,
+ hna_global_entry->orig_node->orig);
}
spin_unlock_irqrestore(&hna_global_hash_lock, flags);
- return bytes_written;
+
+ seq_printf(seq, "%s", buff);
+ kfree(buff);
+ return 0;
}
-void _hna_global_del_orig(struct hna_global_entry *hna_global_entry,
- char *message)
+static void _hna_global_del_orig(struct hna_global_entry *hna_global_entry,
+ char *message)
{
- bat_dbg(DBG_ROUTES, "Deleting global hna entry %pM (via %pM): %s\n",
+ /* FIXME: each orig_node->batman_if will be attached to a softif */
+ struct bat_priv *bat_priv = netdev_priv(soft_device);
+ bat_dbg(DBG_ROUTES, bat_priv,
+ "Deleting global hna entry %pM (via %pM): %s\n",
hna_global_entry->addr, hna_global_entry->orig_node->orig,
message);
diff --git a/drivers/staging/batman-adv/translation-table.h b/drivers/staging/batman-adv/translation-table.h
index 8f412fca87f..fa93e37d095 100644
--- a/drivers/staging/batman-adv/translation-table.h
+++ b/drivers/staging/batman-adv/translation-table.h
@@ -19,23 +19,21 @@
*
*/
+#ifndef _NET_BATMAN_ADV_TRANSLATION_TABLE_H_
+#define _NET_BATMAN_ADV_TRANSLATION_TABLE_H_
+
#include "types.h"
int hna_local_init(void);
void hna_local_add(uint8_t *addr);
void hna_local_remove(uint8_t *addr, char *message);
int hna_local_fill_buffer(unsigned char *buff, int buff_len);
-int hna_local_fill_buffer_text(struct net_device *net_dev, char *buff,
- size_t count, loff_t off);
-void hna_local_purge(struct work_struct *work);
+int hna_local_seq_print_text(struct seq_file *seq, void *offset);
void hna_local_free(void);
int hna_global_init(void);
void hna_global_add_orig(struct orig_node *orig_node, unsigned char *hna_buff,
int hna_buff_len);
-int hna_global_fill_buffer_text(struct net_device *net_dev, char *buff,
- size_t count, loff_t off);
-void _hna_global_del_orig(struct hna_global_entry *hna_global_entry,
- char *orig_str);
+int hna_global_seq_print_text(struct seq_file *seq, void *offset);
void hna_global_del_orig(struct orig_node *orig_node, char *message);
void hna_global_free(void);
struct orig_node *transtable_search(uint8_t *addr);
@@ -43,3 +41,5 @@ struct orig_node *transtable_search(uint8_t *addr);
extern spinlock_t hna_local_hash_lock;
extern struct hashtable_t *hna_local_hash;
extern atomic_t hna_local_changed;
+
+#endif /* _NET_BATMAN_ADV_TRANSLATION_TABLE_H_ */
diff --git a/drivers/staging/batman-adv/types.h b/drivers/staging/batman-adv/types.h
index 86007c7eb44..21d0717afb0 100644
--- a/drivers/staging/batman-adv/types.h
+++ b/drivers/staging/batman-adv/types.h
@@ -21,10 +21,8 @@
-
-
-#ifndef TYPES_H
-#define TYPES_H
+#ifndef _NET_BATMAN_ADV_TYPES_H_
+#define _NET_BATMAN_ADV_TYPES_H_
#include "packet.h"
#include "bitarray.h"
@@ -52,6 +50,7 @@ struct batman_if {
/**
* orig_node - structure for orig_list maintaining nodes of mesh
+ * @primary_addr: hosts primary interface address
* @last_valid: when last packet from this node was received
* @bcast_seqno_reset: time when the broadcast seqno window was reset
* @batman_seqno_reset: time when the batman seqno window was reset
@@ -59,9 +58,13 @@ struct batman_if {
* @last_real_seqno: last and best known squence number
* @last_ttl: ttl of last received packet
* @last_bcast_seqno: last broadcast sequence number received by this host
+ *
+ * @candidates: how many candidates are available
+ * @selected: next bonding candidate
*/
struct orig_node {
uint8_t orig[ETH_ALEN];
+ uint8_t primary_addr[ETH_ALEN];
struct neigh_node *router;
TYPE_OF_WORD *bcast_own;
uint8_t *bcast_own_sum;
@@ -72,12 +75,16 @@ struct orig_node {
unsigned long batman_seqno_reset;
uint8_t flags;
unsigned char *hna_buff;
- int16_t hna_buff_len;
- uint16_t last_real_seqno;
+ int16_t hna_buff_len;
+ uint32_t last_real_seqno;
uint8_t last_ttl;
TYPE_OF_WORD bcast_bits[NUM_WORDS];
- uint16_t last_bcast_seqno;
+ uint32_t last_bcast_seqno;
struct list_head neigh_list;
+ struct {
+ uint8_t candidates;
+ struct neigh_node *selected;
+ } bond;
};
/**
@@ -92,6 +99,7 @@ struct neigh_node {
uint8_t tq_index;
uint8_t tq_avg;
uint8_t last_ttl;
+ struct neigh_node *next_bond_candidate;
unsigned long last_valid;
TYPE_OF_WORD real_bits[NUM_WORDS];
struct orig_node *orig_node;
@@ -101,14 +109,18 @@ struct neigh_node {
struct bat_priv {
struct net_device_stats stats;
atomic_t aggregation_enabled;
+ atomic_t bonding_enabled;
atomic_t vis_mode;
atomic_t orig_interval;
+ atomic_t log_level;
char num_ifaces;
+ struct debug_log *debug_log;
struct batman_if *primary_if;
struct kobject *mesh_obj;
+ struct dentry *debug_dir;
};
-struct device_client {
+struct socket_client {
struct list_head queue_list;
unsigned int queue_len;
unsigned char index;
@@ -116,9 +128,10 @@ struct device_client {
wait_queue_head_t queue_wait;
};
-struct device_packet {
+struct socket_packet {
struct list_head list;
- struct icmp_packet icmp_packet;
+ size_t icmp_len;
+ struct icmp_packet_rr icmp_packet;
};
struct hna_local_entry {
@@ -159,4 +172,12 @@ struct if_list_entry {
struct hlist_node list;
};
-#endif
+struct debug_log {
+ char log_buff[LOG_BUF_LEN];
+ unsigned long log_start;
+ unsigned long log_end;
+ spinlock_t lock;
+ wait_queue_head_t queue_wait;
+};
+
+#endif /* _NET_BATMAN_ADV_TYPES_H_ */
diff --git a/drivers/staging/batman-adv/vis.c b/drivers/staging/batman-adv/vis.c
index 1d3d954847f..4b6a5045f05 100644
--- a/drivers/staging/batman-adv/vis.c
+++ b/drivers/staging/batman-adv/vis.c
@@ -43,8 +43,8 @@
_dummy > smallest_signed_int(_dummy); })
#define seq_after(x, y) seq_before(y, x)
-struct hashtable_t *vis_hash;
-DEFINE_SPINLOCK(vis_hash_lock);
+static struct hashtable_t *vis_hash;
+static DEFINE_SPINLOCK(vis_hash_lock);
static DEFINE_SPINLOCK(recv_list_lock);
static struct vis_info *my_vis_info;
static struct list_head send_list; /* always locked with vis_hash_lock */
@@ -115,7 +115,7 @@ static void vis_data_insert_interface(const uint8_t *interface,
}
/* its a new address, add it to the list */
- entry = kmalloc(sizeof(*entry), GFP_KERNEL);
+ entry = kmalloc(sizeof(*entry), GFP_ATOMIC);
if (!entry)
return;
memcpy(entry->addr, interface, ETH_ALEN);
@@ -142,12 +142,29 @@ static ssize_t vis_data_read_prim_sec(char *buff, struct hlist_head *if_list)
return len;
}
+static size_t vis_data_count_prim_sec(struct hlist_head *if_list)
+{
+ struct if_list_entry *entry;
+ struct hlist_node *pos;
+ size_t count = 0;
+
+ hlist_for_each_entry(entry, pos, if_list, list) {
+ if (entry->primary)
+ count += 9;
+ else
+ count += 23;
+ }
+
+ return count;
+}
+
/* read an entry */
static ssize_t vis_data_read_entry(char *buff, struct vis_info_entry *entry,
uint8_t *src, bool primary)
{
- char to[40];
+ char to[18];
+ /* maximal length: max(4+17+2, 3+17+1+3+2) == 26 */
addr_to_string(to, entry->dest);
if (primary && entry->quality == 0)
return sprintf(buff, "HNA %s, ", to);
@@ -157,38 +174,74 @@ static ssize_t vis_data_read_entry(char *buff, struct vis_info_entry *entry,
return 0;
}
-ssize_t vis_fill_buffer_text(struct net_device *net_dev, char *buff,
- size_t count, loff_t off)
+int vis_seq_print_text(struct seq_file *seq, void *offset)
{
HASHIT(hashit);
+ HASHIT(hashit_count);
struct vis_info *info;
struct vis_info_entry *entries;
+ struct net_device *net_dev = (struct net_device *)seq->private;
struct bat_priv *bat_priv = netdev_priv(net_dev);
HLIST_HEAD(vis_if_list);
struct if_list_entry *entry;
struct hlist_node *pos, *n;
- size_t hdr_len, tmp_len;
- int i, bytes_written = 0;
+ int i;
char tmp_addr_str[ETH_STR_LEN];
unsigned long flags;
int vis_server = atomic_read(&bat_priv->vis_mode);
+ size_t buff_pos, buf_size;
+ char *buff;
if ((!bat_priv->primary_if) ||
(vis_server == VIS_TYPE_CLIENT_UPDATE))
return 0;
- hdr_len = 0;
-
+ buf_size = 1;
+ /* Estimate length */
spin_lock_irqsave(&vis_hash_lock, flags);
+ while (hash_iterate(vis_hash, &hashit_count)) {
+ info = hashit_count.bucket->data;
+ entries = (struct vis_info_entry *)
+ ((char *)info + sizeof(struct vis_info));
+
+ for (i = 0; i < info->packet.entries; i++) {
+ if (entries[i].quality == 0)
+ continue;
+ vis_data_insert_interface(entries[i].src, &vis_if_list,
+ compare_orig(entries[i].src,
+ info->packet.vis_orig));
+ }
+
+ hlist_for_each_entry(entry, pos, &vis_if_list, list) {
+ buf_size += 18 + 26 * info->packet.entries;
+
+ /* add primary/secondary records */
+ if (compare_orig(entry->addr, info->packet.vis_orig))
+ buf_size +=
+ vis_data_count_prim_sec(&vis_if_list);
+
+ buf_size += 1;
+ }
+
+ hlist_for_each_entry_safe(entry, pos, n, &vis_if_list, list) {
+ hlist_del(&entry->list);
+ kfree(entry);
+ }
+ }
+
+ buff = kmalloc(buf_size, GFP_ATOMIC);
+ if (!buff) {
+ spin_unlock_irqrestore(&vis_hash_lock, flags);
+ return -ENOMEM;
+ }
+ buff[0] = '\0';
+ buff_pos = 0;
+
while (hash_iterate(vis_hash, &hashit)) {
info = hashit.bucket->data;
entries = (struct vis_info_entry *)
((char *)info + sizeof(struct vis_info));
- /* estimated line length */
- if (count < bytes_written + 200)
- break;
-
for (i = 0; i < info->packet.entries; i++) {
if (entries[i].quality == 0)
continue;
@@ -199,30 +252,22 @@ ssize_t vis_fill_buffer_text(struct net_device *net_dev, char *buff,
hlist_for_each_entry(entry, pos, &vis_if_list, list) {
addr_to_string(tmp_addr_str, entry->addr);
- tmp_len = sprintf(buff + bytes_written,
- "%s,", tmp_addr_str);
+ buff_pos += sprintf(buff + buff_pos, "%s,",
+ tmp_addr_str);
for (i = 0; i < info->packet.entries; i++)
- tmp_len += vis_data_read_entry(
- buff + bytes_written + tmp_len,
- &entries[i], entry->addr,
- entry->primary);
+ buff_pos += vis_data_read_entry(buff + buff_pos,
+ &entries[i],
+ entry->addr,
+ entry->primary);
/* add primary/secondary records */
if (compare_orig(entry->addr, info->packet.vis_orig))
- tmp_len += vis_data_read_prim_sec(
- buff + bytes_written + tmp_len,
- &vis_if_list);
-
- tmp_len += sprintf(buff + bytes_written + tmp_len,
- "\n");
-
- hdr_len += tmp_len;
+ buff_pos +=
+ vis_data_read_prim_sec(buff + buff_pos,
+ &vis_if_list);
- if (off >= hdr_len)
- continue;
-
- bytes_written += tmp_len;
+ buff_pos += sprintf(buff + buff_pos, "\n");
}
hlist_for_each_entry_safe(entry, pos, n, &vis_if_list, list) {
@@ -230,9 +275,13 @@ ssize_t vis_fill_buffer_text(struct net_device *net_dev, char *buff,
kfree(entry);
}
}
+
spin_unlock_irqrestore(&vis_hash_lock, flags);
- return bytes_written;
+ seq_printf(seq, "%s", buff);
+ kfree(buff);
+
+ return 0;
}
/* add the info packet to the send list, if it was not
@@ -308,7 +357,8 @@ static struct vis_info *add_packet(struct vis_packet *vis_packet,
old_info = hash_find(vis_hash, &search_elem);
if (old_info != NULL) {
- if (!seq_after(vis_packet->seqno, old_info->packet.seqno)) {
+ if (!seq_after(ntohl(vis_packet->seqno),
+ ntohl(old_info->packet.seqno))) {
if (old_info->packet.seqno == vis_packet->seqno) {
recv_list_add(&old_info->recv_list,
vis_packet->sender_orig);
@@ -340,7 +390,7 @@ static struct vis_info *add_packet(struct vis_packet *vis_packet,
/* Make it a broadcast packet, if required */
if (make_broadcast)
- memcpy(info->packet.target_orig, broadcastAddr, ETH_ALEN);
+ memcpy(info->packet.target_orig, broadcast_addr, ETH_ALEN);
/* repair if entries is longer than packet. */
if (info->packet.entries * sizeof(struct vis_info_entry) > vis_info_len)
@@ -474,9 +524,9 @@ static int generate_vis_packet(struct bat_priv *bat_priv)
info->packet.vis_type = atomic_read(&bat_priv->vis_mode);
spin_lock_irqsave(&orig_hash_lock, flags);
- memcpy(info->packet.target_orig, broadcastAddr, ETH_ALEN);
+ memcpy(info->packet.target_orig, broadcast_addr, ETH_ALEN);
info->packet.ttl = TTL;
- info->packet.seqno++;
+ info->packet.seqno = htonl(ntohl(info->packet.seqno) + 1);
info->packet.entries = 0;
if (info->packet.vis_type == VIS_TYPE_CLIENT_UPDATE) {
@@ -547,7 +597,7 @@ static void purge_vis_packets(void)
if (info == my_vis_info) /* never purge own data. */
continue;
if (time_after(jiffies,
- info->first_seen + (VIS_TIMEOUT*HZ)/1000)) {
+ info->first_seen + VIS_TIMEOUT * HZ)) {
hash_remove_bucket(vis_hash, &hashit);
send_list_del(info);
kref_put(&info->refcount, free_info);
@@ -591,7 +641,7 @@ static void broadcast_vis_packet(struct vis_info *info, int packet_length)
}
spin_unlock_irqrestore(&orig_hash_lock, flags);
- memcpy(info->packet.target_orig, broadcastAddr, ETH_ALEN);
+ memcpy(info->packet.target_orig, broadcast_addr, ETH_ALEN);
}
static void unicast_vis_packet(struct vis_info *info, int packet_length)
@@ -628,11 +678,11 @@ static void send_vis_packet(struct vis_info *info)
int packet_length;
if (info->packet.ttl < 2) {
- printk(KERN_WARNING "batman-adv: Error - can't send vis packet: ttl exceeded\n");
+ pr_warning("Error - can't send vis packet: ttl exceeded\n");
return;
}
- memcpy(info->packet.sender_orig, mainIfAddr, ETH_ALEN);
+ memcpy(info->packet.sender_orig, main_if_addr, ETH_ALEN);
info->packet.ttl--;
packet_length = sizeof(struct vis_packet) +
@@ -690,18 +740,18 @@ int vis_init(void)
vis_hash = hash_new(256, vis_info_cmp, vis_info_choose);
if (!vis_hash) {
- printk(KERN_ERR "batman-adv:Can't initialize vis_hash\n");
+ pr_err("Can't initialize vis_hash\n");
goto err;
}
my_vis_info = kmalloc(1000, GFP_ATOMIC);
if (!my_vis_info) {
- printk(KERN_ERR "batman-adv:Can't initialize vis packet\n");
+ pr_err("Can't initialize vis packet\n");
goto err;
}
/* prefill the vis info */
- my_vis_info->first_seen = jiffies - atomic_read(&vis_interval);
+ my_vis_info->first_seen = jiffies - msecs_to_jiffies(VIS_INTERVAL);
INIT_LIST_HEAD(&my_vis_info->recv_list);
INIT_LIST_HEAD(&my_vis_info->send_list);
kref_init(&my_vis_info->refcount);
@@ -713,12 +763,11 @@ int vis_init(void)
INIT_LIST_HEAD(&send_list);
- memcpy(my_vis_info->packet.vis_orig, mainIfAddr, ETH_ALEN);
- memcpy(my_vis_info->packet.sender_orig, mainIfAddr, ETH_ALEN);
+ memcpy(my_vis_info->packet.vis_orig, main_if_addr, ETH_ALEN);
+ memcpy(my_vis_info->packet.sender_orig, main_if_addr, ETH_ALEN);
if (hash_add(vis_hash, my_vis_info) < 0) {
- printk(KERN_ERR
- "batman-adv:Can't add own vis packet into hash\n");
+ pr_err("Can't add own vis packet into hash\n");
/* not in hash, need to remove it manually. */
kref_put(&my_vis_info->refcount, free_info);
goto err;
@@ -764,5 +813,5 @@ void vis_quit(void)
static void start_vis_timer(void)
{
queue_delayed_work(bat_event_workqueue, &vis_timer_wq,
- (atomic_read(&vis_interval) * HZ) / 1000);
+ (VIS_INTERVAL * HZ) / 1000);
}
diff --git a/drivers/staging/batman-adv/vis.h b/drivers/staging/batman-adv/vis.h
index 9c1fd771cba..bb13bf1a3f4 100644
--- a/drivers/staging/batman-adv/vis.h
+++ b/drivers/staging/batman-adv/vis.h
@@ -19,7 +19,10 @@
*
*/
-#define VIS_TIMEOUT 200000
+#ifndef _NET_BATMAN_ADV_VIS_H_
+#define _NET_BATMAN_ADV_VIS_H_
+
+#define VIS_TIMEOUT 200 /* timeout of vis packets in seconds */
struct vis_info {
unsigned long first_seen;
@@ -44,11 +47,7 @@ struct recvlist_node {
uint8_t mac[ETH_ALEN];
};
-extern struct hashtable_t *vis_hash;
-extern spinlock_t vis_hash_lock;
-
-ssize_t vis_fill_buffer_text(struct net_device *net_dev, char *buff,
- size_t count, loff_t off);
+int vis_seq_print_text(struct seq_file *seq, void *offset);
void receive_server_sync_packet(struct bat_priv *bat_priv,
struct vis_packet *vis_packet,
int vis_info_len);
@@ -57,3 +56,5 @@ void receive_client_update_packet(struct bat_priv *bat_priv,
int vis_info_len);
int vis_init(void);
void vis_quit(void);
+
+#endif /* _NET_BATMAN_ADV_VIS_H_ */
diff --git a/drivers/staging/comedi/TODO b/drivers/staging/comedi/TODO
index 15c9348fb93..b10f739b7e3 100644
--- a/drivers/staging/comedi/TODO
+++ b/drivers/staging/comedi/TODO
@@ -2,7 +2,6 @@ TODO:
- checkpatch.pl cleanups
- Lindent
- remove all wrappers
- - remove typedefs
- audit userspace interface
- reserve major number
- cleanup the individual comedi drivers as well
diff --git a/drivers/staging/comedi/comedi_fops.c b/drivers/staging/comedi/comedi_fops.c
index aeb2c00875c..14091313ceb 100644
--- a/drivers/staging/comedi/comedi_fops.c
+++ b/drivers/staging/comedi/comedi_fops.c
@@ -1845,8 +1845,15 @@ ok:
}
}
- if (dev->attached && dev->use_count == 0 && dev->open)
- dev->open(dev);
+ if (dev->attached && dev->use_count == 0 && dev->open) {
+ int rc = dev->open(dev);
+ if (rc < 0) {
+ module_put(dev->driver->module);
+ module_put(THIS_MODULE);
+ mutex_unlock(&dev->mutex);
+ return rc;
+ }
+ }
dev->use_count++;
diff --git a/drivers/staging/comedi/comedidev.h b/drivers/staging/comedi/comedidev.h
index 4eb2b77f56d..68aa9176d24 100644
--- a/drivers/staging/comedi/comedidev.h
+++ b/drivers/staging/comedi/comedidev.h
@@ -53,62 +53,6 @@
COMEDI_MINORVERSION, COMEDI_MICROVERSION)
#define COMEDI_RELEASE VERSION
-#define COMEDI_INITCLEANUP_NOMODULE(x) \
- static int __init x ## _init_module(void) \
- {return comedi_driver_register(&(x)); } \
- static void __exit x ## _cleanup_module(void) \
- {comedi_driver_unregister(&(x)); } \
- module_init(x ## _init_module); \
- module_exit(x ## _cleanup_module);
-
-#define COMEDI_MODULE_MACROS \
- MODULE_AUTHOR("Comedi http://www.comedi.org"); \
- MODULE_DESCRIPTION("Comedi low-level driver"); \
- MODULE_LICENSE("GPL");
-
-#define COMEDI_INITCLEANUP(x) \
- COMEDI_MODULE_MACROS \
- COMEDI_INITCLEANUP_NOMODULE(x)
-
-#define COMEDI_PCI_INITCLEANUP_NOMODULE(comedi_driver, pci_id_table) \
- static int __devinit comedi_driver ## _pci_probe(struct pci_dev *dev, \
- const struct pci_device_id *ent) \
- { \
- return comedi_pci_auto_config(dev, comedi_driver.driver_name); \
- } \
- static void __devexit comedi_driver ## _pci_remove(\
- struct pci_dev *dev) \
- { \
- comedi_pci_auto_unconfig(dev); \
- } \
- static struct pci_driver comedi_driver ## _pci_driver = \
- { \
- .id_table = pci_id_table, \
- .probe = &comedi_driver ## _pci_probe, \
- .remove = __devexit_p(&comedi_driver ## _pci_remove) \
- }; \
- static int __init comedi_driver ## _init_module(void) \
- { \
- int retval; \
- retval = comedi_driver_register(&comedi_driver); \
- if (retval < 0) \
- return retval; \
- comedi_driver ## _pci_driver.name = \
- (char *)comedi_driver.driver_name; \
- return pci_register_driver(&comedi_driver ## _pci_driver); \
- } \
- static void __exit comedi_driver ## _cleanup_module(void) \
- { \
- pci_unregister_driver(&comedi_driver ## _pci_driver); \
- comedi_driver_unregister(&comedi_driver); \
- } \
- module_init(comedi_driver ## _init_module); \
- module_exit(comedi_driver ## _cleanup_module);
-
-#define COMEDI_PCI_INITCLEANUP(comedi_driver, pci_id_table) \
- COMEDI_MODULE_MACROS \
- COMEDI_PCI_INITCLEANUP_NOMODULE(comedi_driver, pci_id_table)
-
#define PCI_VENDOR_ID_ADLINK 0x144a
#define PCI_VENDOR_ID_ICP 0x104c
#define PCI_VENDOR_ID_CONTEC 0x1221
@@ -285,7 +229,7 @@ struct comedi_device {
struct fasync_struct *async_queue;
- void (*open) (struct comedi_device *dev);
+ int (*open) (struct comedi_device *dev);
void (*close) (struct comedi_device *dev);
};
diff --git a/drivers/staging/comedi/drivers/8255.c b/drivers/staging/comedi/drivers/8255.c
index fe63830bd85..95049a8d3b3 100644
--- a/drivers/staging/comedi/drivers/8255.c
+++ b/drivers/staging/comedi/drivers/8255.c
@@ -117,7 +117,18 @@ static struct comedi_driver driver_8255 = {
.detach = dev_8255_detach,
};
-COMEDI_INITCLEANUP(driver_8255);
+static int __init driver_8255_init_module(void)
+{
+ return comedi_driver_register(&driver_8255);
+}
+
+static void __exit driver_8255_cleanup_module(void)
+{
+ comedi_driver_unregister(&driver_8255);
+}
+
+module_init(driver_8255_init_module);
+module_exit(driver_8255_cleanup_module);
static void do_config(struct comedi_device *dev, struct comedi_subdevice *s);
@@ -457,3 +468,7 @@ static int dev_8255_detach(struct comedi_device *dev)
return 0;
}
+
+MODULE_AUTHOR("Comedi http://www.comedi.org");
+MODULE_DESCRIPTION("Comedi low-level driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/acl7225b.c b/drivers/staging/comedi/drivers/acl7225b.c
index e20c3542c06..9def2250bb8 100644
--- a/drivers/staging/comedi/drivers/acl7225b.c
+++ b/drivers/staging/comedi/drivers/acl7225b.c
@@ -49,7 +49,18 @@ static struct comedi_driver driver_acl7225b = {
.offset = sizeof(struct boardtype),
};
-COMEDI_INITCLEANUP(driver_acl7225b);
+static int __init driver_acl7225b_init_module(void)
+{
+ return comedi_driver_register(&driver_acl7225b);
+}
+
+static void __exit driver_acl7225b_cleanup_module(void)
+{
+ comedi_driver_unregister(&driver_acl7225b);
+}
+
+module_init(driver_acl7225b_init_module);
+module_exit(driver_acl7225b_cleanup_module);
static int acl7225b_do_insn(struct comedi_device *dev,
struct comedi_subdevice *s,
@@ -150,3 +161,7 @@ static int acl7225b_detach(struct comedi_device *dev)
return 0;
}
+
+MODULE_AUTHOR("Comedi http://www.comedi.org");
+MODULE_DESCRIPTION("Comedi low-level driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/addi-data/addi_amcc_s5933.h b/drivers/staging/comedi/drivers/addi-data/addi_amcc_s5933.h
index c3284eb0f0a..8ed19bcbf35 100644
--- a/drivers/staging/comedi/drivers/addi-data/addi_amcc_s5933.h
+++ b/drivers/staging/comedi/drivers/addi-data/addi_amcc_s5933.h
@@ -247,16 +247,14 @@ int i_pci_card_data(struct pcilst_struct *amcc,
/* build list of amcc cards in this system */
void v_pci_card_list_init(unsigned short pci_vendor, char display)
{
- struct pci_dev *pcidev;
+ struct pci_dev *pcidev = NULL;
struct pcilst_struct *amcc, *last;
int i;
int i_Count = 0;
amcc_devices = NULL;
last = NULL;
- for (pcidev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, NULL);
- pcidev != NULL;
- pcidev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, pcidev)) {
+ for_each_pci_dev(pcidev) {
for (i_Count = 0; i_Count < 2; i_Count++) {
pci_vendor = i_ADDIDATADeviceID[i_Count];
if (pcidev->vendor == pci_vendor) {
diff --git a/drivers/staging/comedi/drivers/addi-data/addi_common.c b/drivers/staging/comedi/drivers/addi-data/addi_common.c
index b18e81d8cf8..5ed4b9451f2 100644
--- a/drivers/staging/comedi/drivers/addi-data/addi_common.c
+++ b/drivers/staging/comedi/drivers/addi-data/addi_common.c
@@ -2541,7 +2541,43 @@ static struct comedi_driver driver_addi = {
.offset = sizeof(struct addi_board),
};
-COMEDI_PCI_INITCLEANUP(driver_addi, addi_apci_tbl);
+static int __devinit driver_addi_pci_probe(struct pci_dev *dev,
+ const struct pci_device_id *ent)
+{
+ return comedi_pci_auto_config(dev, driver_addi.driver_name);
+}
+
+static void __devexit driver_addi_pci_remove(struct pci_dev *dev)
+{
+ comedi_pci_auto_unconfig(dev);
+}
+
+static struct pci_driver driver_addi_pci_driver = {
+ .id_table = addi_apci_tbl,
+ .probe = &driver_addi_pci_probe,
+ .remove = __devexit_p(&driver_addi_pci_remove)
+};
+
+static int __init driver_addi_init_module(void)
+{
+ int retval;
+
+ retval = comedi_driver_register(&driver_addi);
+ if (retval < 0)
+ return retval;
+
+ driver_addi_pci_driver.name = (char *)driver_addi.driver_name;
+ return pci_register_driver(&driver_addi_pci_driver);
+}
+
+static void __exit driver_addi_cleanup_module(void)
+{
+ pci_unregister_driver(&driver_addi_pci_driver);
+ comedi_driver_unregister(&driver_addi);
+}
+
+module_init(driver_addi_init_module);
+module_exit(driver_addi_cleanup_module);
/*
+----------------------------------------------------------------------------+
diff --git a/drivers/staging/comedi/drivers/addi-data/addi_eeprom.c b/drivers/staging/comedi/drivers/addi-data/addi_eeprom.c
index bea329f44d8..e0213a903af 100644
--- a/drivers/staging/comedi/drivers/addi-data/addi_eeprom.c
+++ b/drivers/staging/comedi/drivers/addi-data/addi_eeprom.c
@@ -101,10 +101,10 @@ struct str_TimerMainHeader {
};
-typedef struct {
+struct str_AnalogOutputHeader {
unsigned short w_Nchannel;
unsigned char b_Resolution;
-} str_AnalogOutputHeader;
+};
struct str_AnalogInputHeader {
unsigned short w_Nchannel;
@@ -136,7 +136,7 @@ int i_EepromReadTimerHeader(unsigned short w_PCIBoardEepromAddress,
int i_EepromReadAnlogOutputHeader(unsigned short w_PCIBoardEepromAddress,
char *pc_PCIChipInformation, unsigned short w_Address,
- str_AnalogOutputHeader *s_Header);
+ struct str_AnalogOutputHeader *s_Header);
int i_EepromReadAnlogInputHeader(unsigned short w_PCIBoardEepromAddress,
char *pc_PCIChipInformation, unsigned short w_Address,
@@ -635,7 +635,7 @@ void v_EepromSendCommand76(unsigned int dw_Address, unsigned int dw_EepromComman
| Input Parameters : unsigned int dw_Address : PCI eeprom base address |
-| unsigned short w_offset : Offset of the adress to read |
+| unsigned short w_offset : Offset of the address to read |
| unsigned short * pw_Value : PCI eeprom 16 bit read value. |
@@ -811,7 +811,7 @@ int i_EepromReadMainHeader(unsigned short w_PCIBoardEepromAddress,
struct str_DigitalInputHeader s_DigitalInputHeader;
struct str_DigitalOutputHeader s_DigitalOutputHeader;
/* struct str_TimerMainHeader s_TimerMainHeader,s_WatchdogMainHeader; */
- str_AnalogOutputHeader s_AnalogOutputHeader;
+ struct str_AnalogOutputHeader s_AnalogOutputHeader;
struct str_AnalogInputHeader s_AnalogInputHeader;
/* Read size */
@@ -1081,7 +1081,7 @@ int i_EepromReadTimerHeader(unsigned short w_PCIBoardEepromAddress,
int i_EepromReadAnlogOutputHeader(unsigned short w_PCIBoardEepromAddress,
char *pc_PCIChipInformation, unsigned short w_Address,
- str_AnalogOutputHeader *s_Header)
+ struct str_AnalogOutputHeader *s_Header)
{
unsigned short w_Temp;
/* No of channels for 1st hard component */
diff --git a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3120.c b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3120.c
index f93ddd4eb06..851f71bbf1b 100644
--- a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3120.c
+++ b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3120.c
@@ -1090,13 +1090,13 @@ int i_APCI3120_CyclicAnalogInput(int mode, struct comedi_device *dev,
* and put into into an array array used may be for differnet pages
*/
- /* DMA Start Adress Low */
+ /* DMA Start Address Low */
outw(APCI3120_ADD_ON_MWAR_LOW, devpriv->i_IobaseAddon + 0);
outw((devpriv->ul_DmaBufferHw[0] & 0xFFFF),
devpriv->i_IobaseAddon + 2);
/*************************/
- /* DMA Start Adress High */
+ /* DMA Start Address High */
/*************************/
outw(APCI3120_ADD_ON_MWAR_HIGH, devpriv->i_IobaseAddon + 0);
outw((devpriv->ul_DmaBufferHw[0] / 65536),
@@ -1733,11 +1733,11 @@ void v_APCI3120_InterruptDma(int irq, void *d)
var = devpriv->ul_DmaBufferHw[next_dma_buf];
high_word = var / 65536;
- /* DMA Start Adress Low */
+ /* DMA Start Address Low */
outw(APCI3120_ADD_ON_MWAR_LOW, devpriv->i_IobaseAddon + 0);
outw(low_word, devpriv->i_IobaseAddon + 2);
- /* DMA Start Adress High */
+ /* DMA Start Address High */
outw(APCI3120_ADD_ON_MWAR_HIGH, devpriv->i_IobaseAddon + 0);
outw(high_word, devpriv->i_IobaseAddon + 2);
diff --git a/drivers/staging/comedi/drivers/addi_apci_035.c b/drivers/staging/comedi/drivers/addi_apci_035.c
index 6dfcbe803f2..4c00df4bc15 100644
--- a/drivers/staging/comedi/drivers/addi_apci_035.c
+++ b/drivers/staging/comedi/drivers/addi_apci_035.c
@@ -5,3 +5,7 @@
#define ADDIDATA_DRIVER_NAME "addi_apci_035"
#include "addi-data/addi_common.c"
+
+MODULE_AUTHOR("Comedi http://www.comedi.org");
+MODULE_DESCRIPTION("Comedi low-level driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/addi_apci_1032.c b/drivers/staging/comedi/drivers/addi_apci_1032.c
index 4722ec834f7..7831ce33b02 100644
--- a/drivers/staging/comedi/drivers/addi_apci_1032.c
+++ b/drivers/staging/comedi/drivers/addi_apci_1032.c
@@ -3,3 +3,7 @@
#define ADDIDATA_DRIVER_NAME "addi_apci_1032"
#include "addi-data/addi_common.c"
+
+MODULE_AUTHOR("Comedi http://www.comedi.org");
+MODULE_DESCRIPTION("Comedi low-level driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/addi_apci_1500.c b/drivers/staging/comedi/drivers/addi_apci_1500.c
index db3dafdcf69..bfd84f66d9c 100644
--- a/drivers/staging/comedi/drivers/addi_apci_1500.c
+++ b/drivers/staging/comedi/drivers/addi_apci_1500.c
@@ -3,3 +3,7 @@
#define ADDIDATA_DRIVER_NAME "addi_apci_1500"
#include "addi-data/addi_common.c"
+
+MODULE_AUTHOR("Comedi http://www.comedi.org");
+MODULE_DESCRIPTION("Comedi low-level driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/addi_apci_1516.c b/drivers/staging/comedi/drivers/addi_apci_1516.c
index f591baff6a0..a12e2f42137 100644
--- a/drivers/staging/comedi/drivers/addi_apci_1516.c
+++ b/drivers/staging/comedi/drivers/addi_apci_1516.c
@@ -3,3 +3,7 @@
#define ADDIDATA_DRIVER_NAME "addi_apci_1516"
#include "addi-data/addi_common.c"
+
+MODULE_AUTHOR("Comedi http://www.comedi.org");
+MODULE_DESCRIPTION("Comedi low-level driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/addi_apci_1564.c b/drivers/staging/comedi/drivers/addi_apci_1564.c
index 6f5c923ac22..1b9d598fb6c 100644
--- a/drivers/staging/comedi/drivers/addi_apci_1564.c
+++ b/drivers/staging/comedi/drivers/addi_apci_1564.c
@@ -3,3 +3,7 @@
#define ADDIDATA_DRIVER_NAME "addi_apci_1564"
#include "addi-data/addi_common.c"
+
+MODULE_AUTHOR("Comedi http://www.comedi.org");
+MODULE_DESCRIPTION("Comedi low-level driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/addi_apci_16xx.c b/drivers/staging/comedi/drivers/addi_apci_16xx.c
index 1d926add9e6..d54218d59c5 100644
--- a/drivers/staging/comedi/drivers/addi_apci_16xx.c
+++ b/drivers/staging/comedi/drivers/addi_apci_16xx.c
@@ -3,3 +3,7 @@
#define ADDIDATA_DRIVER_NAME "addi_apci_16xx"
#include "addi-data/addi_common.c"
+
+MODULE_AUTHOR("Comedi http://www.comedi.org");
+MODULE_DESCRIPTION("Comedi low-level driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/addi_apci_2016.c b/drivers/staging/comedi/drivers/addi_apci_2016.c
index 7266e412f0a..fa50c7bb7ad 100644
--- a/drivers/staging/comedi/drivers/addi_apci_2016.c
+++ b/drivers/staging/comedi/drivers/addi_apci_2016.c
@@ -3,3 +3,7 @@
#define ADDIDATA_DRIVER_NAME "addi_apci_2016"
#include "addi-data/addi_common.c"
+
+MODULE_AUTHOR("Comedi http://www.comedi.org");
+MODULE_DESCRIPTION("Comedi low-level driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/addi_apci_2032.c b/drivers/staging/comedi/drivers/addi_apci_2032.c
index f67da94119e..073a8a56dbe 100644
--- a/drivers/staging/comedi/drivers/addi_apci_2032.c
+++ b/drivers/staging/comedi/drivers/addi_apci_2032.c
@@ -3,3 +3,7 @@
#define ADDIDATA_DRIVER_NAME "addi_apci_2032"
#include "addi-data/addi_common.c"
+
+MODULE_AUTHOR("Comedi http://www.comedi.org");
+MODULE_DESCRIPTION("Comedi low-level driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/addi_apci_2200.c b/drivers/staging/comedi/drivers/addi_apci_2200.c
index bc7f7d65350..adfbb5d410e 100644
--- a/drivers/staging/comedi/drivers/addi_apci_2200.c
+++ b/drivers/staging/comedi/drivers/addi_apci_2200.c
@@ -3,3 +3,7 @@
#define ADDIDATA_DRIVER_NAME "addi_apci_2200"
#include "addi-data/addi_common.c"
+
+MODULE_AUTHOR("Comedi http://www.comedi.org");
+MODULE_DESCRIPTION("Comedi low-level driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/addi_apci_3001.c b/drivers/staging/comedi/drivers/addi_apci_3001.c
index d86c4209cb9..00ac762965c 100644
--- a/drivers/staging/comedi/drivers/addi_apci_3001.c
+++ b/drivers/staging/comedi/drivers/addi_apci_3001.c
@@ -3,3 +3,7 @@
#define ADDIDATA_DRIVER_NAME "addi_apci_3001"
#include "addi-data/addi_common.c"
+
+MODULE_AUTHOR("Comedi http://www.comedi.org");
+MODULE_DESCRIPTION("Comedi low-level driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/addi_apci_3120.c b/drivers/staging/comedi/drivers/addi_apci_3120.c
index 0b22cf10415..c35515845cf 100644
--- a/drivers/staging/comedi/drivers/addi_apci_3120.c
+++ b/drivers/staging/comedi/drivers/addi_apci_3120.c
@@ -3,3 +3,7 @@
#define ADDIDATA_DRIVER_NAME "addi_apci_3120"
#include "addi-data/addi_common.c"
+
+MODULE_AUTHOR("Comedi http://www.comedi.org");
+MODULE_DESCRIPTION("Comedi low-level driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/addi_apci_3501.c b/drivers/staging/comedi/drivers/addi_apci_3501.c
index d8a01b154e3..dd2c1d3bc18 100644
--- a/drivers/staging/comedi/drivers/addi_apci_3501.c
+++ b/drivers/staging/comedi/drivers/addi_apci_3501.c
@@ -3,3 +3,7 @@
#define ADDIDATA_DRIVER_NAME "addi_apci_3501"
#include "addi-data/addi_common.c"
+
+MODULE_AUTHOR("Comedi http://www.comedi.org");
+MODULE_DESCRIPTION("Comedi low-level driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/addi_apci_3xxx.c b/drivers/staging/comedi/drivers/addi_apci_3xxx.c
index 942bc9e259a..03161c88eac 100644
--- a/drivers/staging/comedi/drivers/addi_apci_3xxx.c
+++ b/drivers/staging/comedi/drivers/addi_apci_3xxx.c
@@ -3,3 +3,7 @@
#define ADDIDATA_DRIVER_NAME "addi_apci_3xxx"
#include "addi-data/addi_common.c"
+
+MODULE_AUTHOR("Comedi http://www.comedi.org");
+MODULE_DESCRIPTION("Comedi low-level driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/adl_pci6208.c b/drivers/staging/comedi/drivers/adl_pci6208.c
index 712b9e0788b..073d0242c28 100644
--- a/drivers/staging/comedi/drivers/adl_pci6208.c
+++ b/drivers/staging/comedi/drivers/adl_pci6208.c
@@ -119,7 +119,43 @@ static struct comedi_driver driver_pci6208 = {
.detach = pci6208_detach,
};
-COMEDI_PCI_INITCLEANUP(driver_pci6208, pci6208_pci_table);
+static int __devinit driver_pci6208_pci_probe(struct pci_dev *dev,
+ const struct pci_device_id *ent)
+{
+ return comedi_pci_auto_config(dev, driver_pci6208.driver_name);
+}
+
+static void __devexit driver_pci6208_pci_remove(struct pci_dev *dev)
+{
+ comedi_pci_auto_unconfig(dev);
+}
+
+static struct pci_driver driver_pci6208_pci_driver = {
+ .id_table = pci6208_pci_table,
+ .probe = &driver_pci6208_pci_probe,
+ .remove = __devexit_p(&driver_pci6208_pci_remove)
+};
+
+static int __init driver_pci6208_init_module(void)
+{
+ int retval;
+
+ retval = comedi_driver_register(&driver_pci6208);
+ if (retval < 0)
+ return retval;
+
+ driver_pci6208_pci_driver.name = (char *)driver_pci6208.driver_name;
+ return pci_register_driver(&driver_pci6208_pci_driver);
+}
+
+static void __exit driver_pci6208_cleanup_module(void)
+{
+ pci_unregister_driver(&driver_pci6208_pci_driver);
+ comedi_driver_unregister(&driver_pci6208);
+}
+
+module_init(driver_pci6208_init_module);
+module_exit(driver_pci6208_cleanup_module);
static int pci6208_find_device(struct comedi_device *dev, int bus, int slot);
static int
@@ -315,12 +351,10 @@ static int pci6208_ao_rinsn(struct comedi_device *dev,
static int pci6208_find_device(struct comedi_device *dev, int bus, int slot)
{
- struct pci_dev *pci_dev;
+ struct pci_dev *pci_dev = NULL;
int i;
- for (pci_dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, NULL);
- pci_dev != NULL;
- pci_dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, pci_dev)) {
+ for_each_pci_dev(pci_dev) {
if (pci_dev->vendor == PCI_VENDOR_ID_ADLINK) {
for (i = 0; i < ARRAY_SIZE(pci6208_boards); i++) {
if (pci6208_boards[i].dev_id ==
@@ -408,3 +442,7 @@ pci6208_pci_setup(struct pci_dev *pci_dev, unsigned long *io_base_ptr,
return 0;
}
+
+MODULE_AUTHOR("Comedi http://www.comedi.org");
+MODULE_DESCRIPTION("Comedi low-level driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/adl_pci7230.c b/drivers/staging/comedi/drivers/adl_pci7230.c
index 24a82eb9d15..72a7258b5b9 100644
--- a/drivers/staging/comedi/drivers/adl_pci7230.c
+++ b/drivers/staging/comedi/drivers/adl_pci7230.c
@@ -90,7 +90,7 @@ static int adl_pci7230_do_insn_bits(struct comedi_device *dev,
static int adl_pci7230_attach(struct comedi_device *dev,
struct comedi_devconfig *it)
{
- struct pci_dev *pcidev;
+ struct pci_dev *pcidev = NULL;
struct comedi_subdevice *s;
int bus, slot;
@@ -106,10 +106,7 @@ static int adl_pci7230_attach(struct comedi_device *dev,
if (alloc_subdevices(dev, 2) < 0)
return -ENOMEM;
- for (pcidev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, NULL);
- pcidev != NULL;
- pcidev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, pcidev)) {
-
+ for_each_pci_dev(pcidev) {
if (pcidev->vendor == PCI_VENDOR_ID_ADLINK &&
pcidev->device == PCI_DEVICE_ID_PCI7230) {
if (bus || slot) {
@@ -203,4 +200,46 @@ static int adl_pci7230_di_insn_bits(struct comedi_device *dev,
return 2;
}
-COMEDI_PCI_INITCLEANUP(driver_adl_pci7230, adl_pci7230_pci_table);
+static int __devinit driver_adl_pci7230_pci_probe(struct pci_dev *dev,
+ const struct pci_device_id
+ *ent)
+{
+ return comedi_pci_auto_config(dev, driver_adl_pci7230.driver_name);
+}
+
+static void __devexit driver_adl_pci7230_pci_remove(struct pci_dev *dev)
+{
+ comedi_pci_auto_unconfig(dev);
+}
+
+static struct pci_driver driver_adl_pci7230_pci_driver = {
+ .id_table = adl_pci7230_pci_table,
+ .probe = &driver_adl_pci7230_pci_probe,
+ .remove = __devexit_p(&driver_adl_pci7230_pci_remove)
+};
+
+static int __init driver_adl_pci7230_init_module(void)
+{
+ int retval;
+
+ retval = comedi_driver_register(&driver_adl_pci7230);
+ if (retval < 0)
+ return retval;
+
+ driver_adl_pci7230_pci_driver.name =
+ (char *)driver_adl_pci7230.driver_name;
+ return pci_register_driver(&driver_adl_pci7230_pci_driver);
+}
+
+static void __exit driver_adl_pci7230_cleanup_module(void)
+{
+ pci_unregister_driver(&driver_adl_pci7230_pci_driver);
+ comedi_driver_unregister(&driver_adl_pci7230);
+}
+
+module_init(driver_adl_pci7230_init_module);
+module_exit(driver_adl_pci7230_cleanup_module);
+
+MODULE_AUTHOR("Comedi http://www.comedi.org");
+MODULE_DESCRIPTION("Comedi low-level driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/adl_pci7296.c b/drivers/staging/comedi/drivers/adl_pci7296.c
index 8602865ae6b..f28fe6bec05 100644
--- a/drivers/staging/comedi/drivers/adl_pci7296.c
+++ b/drivers/staging/comedi/drivers/adl_pci7296.c
@@ -77,7 +77,7 @@ static struct comedi_driver driver_adl_pci7296 = {
static int adl_pci7296_attach(struct comedi_device *dev,
struct comedi_devconfig *it)
{
- struct pci_dev *pcidev;
+ struct pci_dev *pcidev = NULL;
struct comedi_subdevice *s;
int bus, slot;
int ret;
@@ -94,10 +94,7 @@ static int adl_pci7296_attach(struct comedi_device *dev,
if (alloc_subdevices(dev, 4) < 0)
return -ENOMEM;
- for (pcidev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, NULL);
- pcidev != NULL;
- pcidev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, pcidev)) {
-
+ for_each_pci_dev(pcidev) {
if (pcidev->vendor == PCI_VENDOR_ID_ADLINK &&
pcidev->device == PCI_DEVICE_ID_PCI7296) {
if (bus || slot) {
@@ -177,4 +174,46 @@ static int adl_pci7296_detach(struct comedi_device *dev)
return 0;
}
-COMEDI_PCI_INITCLEANUP(driver_adl_pci7296, adl_pci7296_pci_table);
+static int __devinit driver_adl_pci7296_pci_probe(struct pci_dev *dev,
+ const struct pci_device_id
+ *ent)
+{
+ return comedi_pci_auto_config(dev, driver_adl_pci7296.driver_name);
+}
+
+static void __devexit driver_adl_pci7296_pci_remove(struct pci_dev *dev)
+{
+ comedi_pci_auto_unconfig(dev);
+}
+
+static struct pci_driver driver_adl_pci7296_pci_driver = {
+ .id_table = adl_pci7296_pci_table,
+ .probe = &driver_adl_pci7296_pci_probe,
+ .remove = __devexit_p(&driver_adl_pci7296_pci_remove)
+};
+
+static int __init driver_adl_pci7296_init_module(void)
+{
+ int retval;
+
+ retval = comedi_driver_register(&driver_adl_pci7296);
+ if (retval < 0)
+ return retval;
+
+ driver_adl_pci7296_pci_driver.name =
+ (char *)driver_adl_pci7296.driver_name;
+ return pci_register_driver(&driver_adl_pci7296_pci_driver);
+}
+
+static void __exit driver_adl_pci7296_cleanup_module(void)
+{
+ pci_unregister_driver(&driver_adl_pci7296_pci_driver);
+ comedi_driver_unregister(&driver_adl_pci7296);
+}
+
+module_init(driver_adl_pci7296_init_module);
+module_exit(driver_adl_pci7296_cleanup_module);
+
+MODULE_AUTHOR("Comedi http://www.comedi.org");
+MODULE_DESCRIPTION("Comedi low-level driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/adl_pci7432.c b/drivers/staging/comedi/drivers/adl_pci7432.c
index b5a9499e438..262da7b29b2 100644
--- a/drivers/staging/comedi/drivers/adl_pci7432.c
+++ b/drivers/staging/comedi/drivers/adl_pci7432.c
@@ -86,7 +86,7 @@ static int adl_pci7432_do_insn_bits(struct comedi_device *dev,
static int adl_pci7432_attach(struct comedi_device *dev,
struct comedi_devconfig *it)
{
- struct pci_dev *pcidev;
+ struct pci_dev *pcidev = NULL;
struct comedi_subdevice *s;
int bus, slot;
@@ -102,10 +102,7 @@ static int adl_pci7432_attach(struct comedi_device *dev,
if (alloc_subdevices(dev, 2) < 0)
return -ENOMEM;
- for (pcidev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, NULL);
- pcidev != NULL;
- pcidev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, pcidev)) {
-
+ for_each_pci_dev(pcidev) {
if (pcidev->vendor == PCI_VENDOR_ID_ADLINK &&
pcidev->device == PCI_DEVICE_ID_PCI7432) {
if (bus || slot) {
@@ -210,4 +207,46 @@ static int adl_pci7432_di_insn_bits(struct comedi_device *dev,
return 2;
}
-COMEDI_PCI_INITCLEANUP(driver_adl_pci7432, adl_pci7432_pci_table);
+static int __devinit driver_adl_pci7432_pci_probe(struct pci_dev *dev,
+ const struct pci_device_id
+ *ent)
+{
+ return comedi_pci_auto_config(dev, driver_adl_pci7432.driver_name);
+}
+
+static void __devexit driver_adl_pci7432_pci_remove(struct pci_dev *dev)
+{
+ comedi_pci_auto_unconfig(dev);
+}
+
+static struct pci_driver driver_adl_pci7432_pci_driver = {
+ .id_table = adl_pci7432_pci_table,
+ .probe = &driver_adl_pci7432_pci_probe,
+ .remove = __devexit_p(&driver_adl_pci7432_pci_remove)
+};
+
+static int __init driver_adl_pci7432_init_module(void)
+{
+ int retval;
+
+ retval = comedi_driver_register(&driver_adl_pci7432);
+ if (retval < 0)
+ return retval;
+
+ driver_adl_pci7432_pci_driver.name =
+ (char *)driver_adl_pci7432.driver_name;
+ return pci_register_driver(&driver_adl_pci7432_pci_driver);
+}
+
+static void __exit driver_adl_pci7432_cleanup_module(void)
+{
+ pci_unregister_driver(&driver_adl_pci7432_pci_driver);
+ comedi_driver_unregister(&driver_adl_pci7432);
+}
+
+module_init(driver_adl_pci7432_init_module);
+module_exit(driver_adl_pci7432_cleanup_module);
+
+MODULE_AUTHOR("Comedi http://www.comedi.org");
+MODULE_DESCRIPTION("Comedi low-level driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/adl_pci8164.c b/drivers/staging/comedi/drivers/adl_pci8164.c
index da256a1e0b4..767a594935c 100644
--- a/drivers/staging/comedi/drivers/adl_pci8164.c
+++ b/drivers/staging/comedi/drivers/adl_pci8164.c
@@ -125,7 +125,7 @@ static int adl_pci8164_insn_write_buf1(struct comedi_device *dev,
static int adl_pci8164_attach(struct comedi_device *dev,
struct comedi_devconfig *it)
{
- struct pci_dev *pcidev;
+ struct pci_dev *pcidev = NULL;
struct comedi_subdevice *s;
int bus, slot;
@@ -142,10 +142,7 @@ static int adl_pci8164_attach(struct comedi_device *dev,
if (alloc_subdevices(dev, 4) < 0)
return -ENOMEM;
- for (pcidev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, NULL);
- pcidev != NULL;
- pcidev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, pcidev)) {
-
+ for_each_pci_dev(pcidev) {
if (pcidev->vendor == PCI_VENDOR_ID_ADLINK &&
pcidev->device == PCI_DEVICE_ID_PCI8164) {
if (bus || slot) {
@@ -389,4 +386,46 @@ static int adl_pci8164_insn_write_buf1(struct comedi_device *dev,
return 2;
}
-COMEDI_PCI_INITCLEANUP(driver_adl_pci8164, adl_pci8164_pci_table);
+static int __devinit driver_adl_pci8164_pci_probe(struct pci_dev *dev,
+ const struct pci_device_id
+ *ent)
+{
+ return comedi_pci_auto_config(dev, driver_adl_pci8164.driver_name);
+}
+
+static void __devexit driver_adl_pci8164_pci_remove(struct pci_dev *dev)
+{
+ comedi_pci_auto_unconfig(dev);
+}
+
+static struct pci_driver driver_adl_pci8164_pci_driver = {
+ .id_table = adl_pci8164_pci_table,
+ .probe = &driver_adl_pci8164_pci_probe,
+ .remove = __devexit_p(&driver_adl_pci8164_pci_remove)
+};
+
+static int __init driver_adl_pci8164_init_module(void)
+{
+ int retval;
+
+ retval = comedi_driver_register(&driver_adl_pci8164);
+ if (retval < 0)
+ return retval;
+
+ driver_adl_pci8164_pci_driver.name =
+ (char *)driver_adl_pci8164.driver_name;
+ return pci_register_driver(&driver_adl_pci8164_pci_driver);
+}
+
+static void __exit driver_adl_pci8164_cleanup_module(void)
+{
+ pci_unregister_driver(&driver_adl_pci8164_pci_driver);
+ comedi_driver_unregister(&driver_adl_pci8164);
+}
+
+module_init(driver_adl_pci8164_init_module);
+module_exit(driver_adl_pci8164_cleanup_module);
+
+MODULE_AUTHOR("Comedi http://www.comedi.org");
+MODULE_DESCRIPTION("Comedi low-level driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/adl_pci9111.c b/drivers/staging/comedi/drivers/adl_pci9111.c
index 39d112b708e..b2a02b0f569 100644
--- a/drivers/staging/comedi/drivers/adl_pci9111.c
+++ b/drivers/staging/comedi/drivers/adl_pci9111.c
@@ -38,8 +38,8 @@ Supports:
- do_insn read/write
- ai_do_cmd mode with the following sources:
- - start_src TRIG_NOW
- - scan_begin_src TRIG_FOLLOW TRIG_TIMER TRIG_EXT
+ - start_src TRIG_NOW
+ - scan_begin_src TRIG_FOLLOW TRIG_TIMER TRIG_EXT
- convert_src TRIG_TIMER TRIG_EXT
- scan_end_src TRIG_COUNT
- stop_src TRIG_COUNT TRIG_NONE
@@ -68,8 +68,9 @@ CHANGELOG:
TODO:
- Really test implemented functionality.
- - Add support for the PCI-9111DG with a probe routine to identify the card type
- (perhaps with the help of the channel number readback of the A/D Data register).
+ - Add support for the PCI-9111DG with a probe routine to identify the card
+ type (perhaps with the help of the channel number readback of the A/D Data
+ register).
- Add external multiplexer support.
*/
@@ -83,12 +84,12 @@ TODO:
#include "comedi_pci.h"
#include "comedi_fc.h"
-#define PCI9111_DRIVER_NAME "adl_pci9111"
-#define PCI9111_HR_DEVICE_ID 0x9111
+#define PCI9111_DRIVER_NAME "adl_pci9111"
+#define PCI9111_HR_DEVICE_ID 0x9111
/* TODO: Add other pci9111 board id */
-#define PCI9111_IO_RANGE 0x0100
+#define PCI9111_IO_RANGE 0x0100
#define PCI9111_FIFO_HALF_SIZE 512
@@ -134,27 +135,29 @@ TODO:
/* IO address map */
-#define PCI9111_REGISTER_AD_FIFO_VALUE 0x00 /* AD Data stored in FIFO */
-#define PCI9111_REGISTER_DA_OUTPUT 0x00
-#define PCI9111_REGISTER_DIGITAL_IO 0x02
-#define PCI9111_REGISTER_EXTENDED_IO_PORTS 0x04
-#define PCI9111_REGISTER_AD_CHANNEL_CONTROL 0x06 /* Channel selection */
-#define PCI9111_REGISTER_AD_CHANNEL_READBACK 0x06
-#define PCI9111_REGISTER_INPUT_SIGNAL_RANGE 0x08
-#define PCI9111_REGISTER_RANGE_STATUS_READBACK 0x08
-#define PCI9111_REGISTER_TRIGGER_MODE_CONTROL 0x0A
-#define PCI9111_REGISTER_AD_MODE_INTERRUPT_READBACK 0x0A
-#define PCI9111_REGISTER_SOFTWARE_TRIGGER 0x0E
-#define PCI9111_REGISTER_INTERRUPT_CONTROL 0x0C
+#define PCI9111_REGISTER_AD_FIFO_VALUE 0x00 /* AD Data stored
+ in FIFO */
+#define PCI9111_REGISTER_DA_OUTPUT 0x00
+#define PCI9111_REGISTER_DIGITAL_IO 0x02
+#define PCI9111_REGISTER_EXTENDED_IO_PORTS 0x04
+#define PCI9111_REGISTER_AD_CHANNEL_CONTROL 0x06 /* Channel
+ selection */
+#define PCI9111_REGISTER_AD_CHANNEL_READBACK 0x06
+#define PCI9111_REGISTER_INPUT_SIGNAL_RANGE 0x08
+#define PCI9111_REGISTER_RANGE_STATUS_READBACK 0x08
+#define PCI9111_REGISTER_TRIGGER_MODE_CONTROL 0x0A
+#define PCI9111_REGISTER_AD_MODE_INTERRUPT_READBACK 0x0A
+#define PCI9111_REGISTER_SOFTWARE_TRIGGER 0x0E
+#define PCI9111_REGISTER_INTERRUPT_CONTROL 0x0C
#define PCI9111_REGISTER_8254_COUNTER_0 0x40
#define PCI9111_REGISTER_8254_COUNTER_1 0x42
-#define PCI9111_REGISTER_8254_COUNTER_2 0X44
+#define PCI9111_REGISTER_8254_COUNTER_2 0X44
#define PCI9111_REGISTER_8254_CONTROL 0x46
-#define PCI9111_REGISTER_INTERRUPT_CLEAR 0x48
+#define PCI9111_REGISTER_INTERRUPT_CLEAR 0x48
-#define PCI9111_TRIGGER_MASK 0x0F
-#define PCI9111_PTRG_OFF (0 << 3)
-#define PCI9111_PTRG_ON (1 << 3)
+#define PCI9111_TRIGGER_MASK 0x0F
+#define PCI9111_PTRG_OFF (0 << 3)
+#define PCI9111_PTRG_ON (1 << 3)
#define PCI9111_EITS_EXTERNAL (1 << 2)
#define PCI9111_EITS_INTERNAL (0 << 2)
#define PCI9111_TPST_SOFTWARE_TRIGGER (0 << 1)
@@ -164,9 +167,9 @@ TODO:
#define PCI9111_ISC0_SET_IRQ_ON_ENDING_OF_AD_CONVERSION (0 << 0)
#define PCI9111_ISC0_SET_IRQ_ON_FIFO_HALF_FULL (1 << 0)
-#define PCI9111_ISC1_SET_IRQ_ON_TIMER_TICK (0 << 1)
-#define PCI9111_ISC1_SET_IRQ_ON_EXT_TRG (1 << 1)
-#define PCI9111_FFEN_SET_FIFO_ENABLE (0 << 2)
+#define PCI9111_ISC1_SET_IRQ_ON_TIMER_TICK (0 << 1)
+#define PCI9111_ISC1_SET_IRQ_ON_EXT_TRG (1 << 1)
+#define PCI9111_FFEN_SET_FIFO_ENABLE (0 << 2)
#define PCI9111_FFEN_SET_FIFO_DISABLE (1 << 2)
#define PCI9111_CHANNEL_MASK 0x0F
@@ -177,7 +180,7 @@ TODO:
#define PCI9111_FIFO_FULL_MASK 0x40
#define PCI9111_AD_BUSY_MASK 0x80
-#define PCI9111_IO_BASE dev->iobase
+#define PCI9111_IO_BASE (dev->iobase)
/*
* Define inlined function
@@ -189,8 +192,9 @@ TODO:
#define pci9111_trigger_and_autoscan_set(flags) \
outb(flags, PCI9111_IO_BASE+PCI9111_REGISTER_TRIGGER_MODE_CONTROL)
-#define pci9111_interrupt_and_fifo_get() \
- ((inb(PCI9111_IO_BASE+PCI9111_REGISTER_AD_MODE_INTERRUPT_READBACK) >> 4) &0x03)
+#define pci9111_interrupt_and_fifo_get() \
+ ((inb(PCI9111_IO_BASE+PCI9111_REGISTER_AD_MODE_INTERRUPT_READBACK) >> 4) \
+ &0x03)
#define pci9111_interrupt_and_fifo_set(flags) \
outb(flags, PCI9111_IO_BASE+PCI9111_REGISTER_INTERRUPT_CONTROL)
@@ -201,45 +205,56 @@ TODO:
#define pci9111_software_trigger() \
outb(0, PCI9111_IO_BASE+PCI9111_REGISTER_SOFTWARE_TRIGGER)
-#define pci9111_fifo_reset() \
- outb(PCI9111_FFEN_SET_FIFO_ENABLE, PCI9111_IO_BASE+PCI9111_REGISTER_INTERRUPT_CONTROL); \
- outb(PCI9111_FFEN_SET_FIFO_DISABLE, PCI9111_IO_BASE+PCI9111_REGISTER_INTERRUPT_CONTROL); \
- outb(PCI9111_FFEN_SET_FIFO_ENABLE, PCI9111_IO_BASE+PCI9111_REGISTER_INTERRUPT_CONTROL)
+#define pci9111_fifo_reset() do { \
+ outb(PCI9111_FFEN_SET_FIFO_ENABLE, \
+ PCI9111_IO_BASE+PCI9111_REGISTER_INTERRUPT_CONTROL); \
+ outb(PCI9111_FFEN_SET_FIFO_DISABLE, \
+ PCI9111_IO_BASE+PCI9111_REGISTER_INTERRUPT_CONTROL); \
+ outb(PCI9111_FFEN_SET_FIFO_ENABLE, \
+ PCI9111_IO_BASE+PCI9111_REGISTER_INTERRUPT_CONTROL); \
+ } while (0)
#define pci9111_is_fifo_full() \
((inb(PCI9111_IO_BASE+PCI9111_REGISTER_RANGE_STATUS_READBACK)& \
- PCI9111_FIFO_FULL_MASK)==0)
+ PCI9111_FIFO_FULL_MASK) == 0)
#define pci9111_is_fifo_half_full() \
((inb(PCI9111_IO_BASE+PCI9111_REGISTER_RANGE_STATUS_READBACK)& \
- PCI9111_FIFO_HALF_FULL_MASK)==0)
+ PCI9111_FIFO_HALF_FULL_MASK) == 0)
#define pci9111_is_fifo_empty() \
((inb(PCI9111_IO_BASE+PCI9111_REGISTER_RANGE_STATUS_READBACK)& \
- PCI9111_FIFO_EMPTY_MASK)==0)
+ PCI9111_FIFO_EMPTY_MASK) == 0)
-#define pci9111_ai_channel_set(channel) \
- outb((channel)&PCI9111_CHANNEL_MASK, PCI9111_IO_BASE+PCI9111_REGISTER_AD_CHANNEL_CONTROL)
+#define pci9111_ai_channel_set(channel) \
+ outb((channel)&PCI9111_CHANNEL_MASK, \
+ PCI9111_IO_BASE+PCI9111_REGISTER_AD_CHANNEL_CONTROL)
-#define pci9111_ai_channel_get() \
- inb(PCI9111_IO_BASE+PCI9111_REGISTER_AD_CHANNEL_READBACK)&PCI9111_CHANNEL_MASK
+#define pci9111_ai_channel_get() \
+ (inb(PCI9111_IO_BASE+PCI9111_REGISTER_AD_CHANNEL_READBACK) \
+ &PCI9111_CHANNEL_MASK)
-#define pci9111_ai_range_set(range) \
- outb((range)&PCI9111_RANGE_MASK, PCI9111_IO_BASE+PCI9111_REGISTER_INPUT_SIGNAL_RANGE)
+#define pci9111_ai_range_set(range) \
+ outb((range)&PCI9111_RANGE_MASK, \
+ PCI9111_IO_BASE+PCI9111_REGISTER_INPUT_SIGNAL_RANGE)
-#define pci9111_ai_range_get() \
- inb(PCI9111_IO_BASE+PCI9111_REGISTER_RANGE_STATUS_READBACK)&PCI9111_RANGE_MASK
+#define pci9111_ai_range_get() \
+ (inb(PCI9111_IO_BASE+PCI9111_REGISTER_RANGE_STATUS_READBACK) \
+ &PCI9111_RANGE_MASK)
-#define pci9111_ai_get_data() \
- ((inw(PCI9111_IO_BASE+PCI9111_REGISTER_AD_FIFO_VALUE)>>4)&PCI9111_AI_RESOLUTION_MASK) \
- ^ PCI9111_AI_RESOLUTION_2_CMP_BIT
+#define pci9111_ai_get_data() \
+ (((inw(PCI9111_IO_BASE+PCI9111_REGISTER_AD_FIFO_VALUE)>>4) \
+ &PCI9111_AI_RESOLUTION_MASK) \
+ ^ PCI9111_AI_RESOLUTION_2_CMP_BIT)
-#define pci9111_hr_ai_get_data() \
- (inw(PCI9111_IO_BASE+PCI9111_REGISTER_AD_FIFO_VALUE) & PCI9111_HR_AI_RESOLUTION_MASK) \
- ^ PCI9111_HR_AI_RESOLUTION_2_CMP_BIT
+#define pci9111_hr_ai_get_data() \
+ ((inw(PCI9111_IO_BASE+PCI9111_REGISTER_AD_FIFO_VALUE) \
+ & PCI9111_HR_AI_RESOLUTION_MASK) \
+ ^ PCI9111_HR_AI_RESOLUTION_2_CMP_BIT)
-#define pci9111_ao_set_data(data) \
- outw(data&PCI9111_AO_RESOLUTION_MASK, PCI9111_IO_BASE+PCI9111_REGISTER_DA_OUTPUT)
+#define pci9111_ao_set_data(data) \
+ outw(data&PCI9111_AO_RESOLUTION_MASK, \
+ PCI9111_IO_BASE+PCI9111_REGISTER_DA_OUTPUT)
#define pci9111_di_get_bits() \
inw(PCI9111_IO_BASE+PCI9111_REGISTER_DIGITAL_IO)
@@ -284,12 +299,11 @@ static const struct comedi_lrange pci9111_hr_ai_range = {
};
static DEFINE_PCI_DEVICE_TABLE(pci9111_pci_table) = {
- {
- PCI_VENDOR_ID_ADLINK, PCI9111_HR_DEVICE_ID, PCI_ANY_ID,
- PCI_ANY_ID, 0, 0, 0},
- /* { PCI_VENDOR_ID_ADLINK, PCI9111_HG_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, */
- {
- 0}
+ { PCI_VENDOR_ID_ADLINK, PCI9111_HR_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID,
+ 0, 0, 0 },
+ /* { PCI_VENDOR_ID_ADLINK, PCI9111_HG_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID,
+ * 0, 0, 0 }, */
+ { 0 }
};
MODULE_DEVICE_TABLE(pci, pci9111_pci_table);
@@ -337,7 +351,43 @@ static struct comedi_driver pci9111_driver = {
.detach = pci9111_detach,
};
-COMEDI_PCI_INITCLEANUP(pci9111_driver, pci9111_pci_table);
+static int __devinit pci9111_driver_pci_probe(struct pci_dev *dev,
+ const struct pci_device_id *ent)
+{
+ return comedi_pci_auto_config(dev, pci9111_driver.driver_name);
+}
+
+static void __devexit pci9111_driver_pci_remove(struct pci_dev *dev)
+{
+ comedi_pci_auto_unconfig(dev);
+}
+
+static struct pci_driver pci9111_driver_pci_driver = {
+ .id_table = pci9111_pci_table,
+ .probe = &pci9111_driver_pci_probe,
+ .remove = __devexit_p(&pci9111_driver_pci_remove)
+};
+
+static int __init pci9111_driver_init_module(void)
+{
+ int retval;
+
+ retval = comedi_driver_register(&pci9111_driver);
+ if (retval < 0)
+ return retval;
+
+ pci9111_driver_pci_driver.name = (char *)pci9111_driver.driver_name;
+ return pci_register_driver(&pci9111_driver_pci_driver);
+}
+
+static void __exit pci9111_driver_cleanup_module(void)
+{
+ pci_unregister_driver(&pci9111_driver_pci_driver);
+ comedi_driver_unregister(&pci9111_driver);
+}
+
+module_init(pci9111_driver_init_module);
+module_exit(pci9111_driver_cleanup_module);
/* Private data structure */
@@ -345,7 +395,8 @@ struct pci9111_private_data {
struct pci_dev *pci_device;
unsigned long io_range; /* PCI6503 io range */
- unsigned long lcr_io_base; /* Local configuration register base address */
+ unsigned long lcr_io_base; /* Local configuration register base
+ * address */
unsigned long lcr_io_range;
int stop_counter;
@@ -358,7 +409,8 @@ struct pci9111_private_data {
int ao_readback; /* Last written analog output data */
- unsigned int timer_divisor_1; /* Divisor values for the 8254 timer pacer */
+ unsigned int timer_divisor_1; /* Divisor values for the 8254 timer
+ * pacer */
unsigned int timer_divisor_2;
int is_valid; /* Is device valid */
@@ -366,7 +418,7 @@ struct pci9111_private_data {
short ai_bounce_buffer[2 * PCI9111_FIFO_HALF_SIZE];
};
-#define dev_private ((struct pci9111_private_data *)dev->private)
+#define dev_private ((struct pci9111_private_data *)dev->private)
/* ------------------------------------------------------------------ */
/* PLX9050 SECTION */
@@ -548,10 +600,12 @@ static int pci9111_ai_cancel(struct comedi_device *dev,
/* Test analog input command */
-#define pci9111_check_trigger_src(src, flags) \
- tmp = src; \
- src &= flags; \
- if (!src || tmp != src) error++
+#define pci9111_check_trigger_src(src, flags) do { \
+ tmp = src; \
+ src &= flags; \
+ if (!src || tmp != src) \
+ error++; \
+ } while (false);
static int
pci9111_ai_do_cmd_test(struct comedi_device *dev,
@@ -575,7 +629,8 @@ pci9111_ai_do_cmd_test(struct comedi_device *dev,
if (error)
return 1;
- /* step 2 : make sure trigger sources are unique and mutually compatible */
+ /* step 2 : make sure trigger sources are unique and mutually
+ * compatible */
if (cmd->start_src != TRIG_NOW)
error++;
@@ -637,7 +692,8 @@ pci9111_ai_do_cmd_test(struct comedi_device *dev,
cmd->scan_begin_arg = board->ai_acquisition_period_min_ns;
error++;
}
- if ((cmd->scan_begin_src == TRIG_FOLLOW) && (cmd->scan_begin_arg != 0)) {
+ if ((cmd->scan_begin_src == TRIG_FOLLOW)
+ && (cmd->scan_begin_arg != 0)) {
cmd->scan_begin_arg = 0;
error++;
}
@@ -1216,7 +1272,7 @@ static int pci9111_attach(struct comedi_device *dev,
{
struct comedi_subdevice *subdevice;
unsigned long io_base, io_range, lcr_io_base, lcr_io_range;
- struct pci_dev *pci_device;
+ struct pci_dev *pci_device = NULL;
int error, i;
const struct pci9111_board *board;
@@ -1226,17 +1282,17 @@ static int pci9111_attach(struct comedi_device *dev,
printk("comedi%d: " PCI9111_DRIVER_NAME " driver\n", dev->minor);
- for (pci_device = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, NULL);
- pci_device != NULL;
- pci_device = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, pci_device)) {
+ for_each_pci_dev(pci_device) {
if (pci_device->vendor == PCI_VENDOR_ID_ADLINK) {
for (i = 0; i < pci9111_board_nbr; i++) {
if (pci9111_boards[i].device_id ==
pci_device->device) {
- /* was a particular bus/slot requested? */
+ /* was a particular bus/slot
+ * requested? */
if ((it->options[0] != 0)
|| (it->options[1] != 0)) {
- /* are we on the wrong bus/slot? */
+ /* are we on the wrong
+ * bus/slot? */
if (pci_device->bus->number !=
it->options[0]
||
@@ -1272,7 +1328,8 @@ found:
/* TODO: Warn about non-tested boards. */
- /* Read local configuration register base address [PCI_BASE_ADDRESS #1]. */
+ /* Read local configuration register base address
+ * [PCI_BASE_ADDRESS #1]. */
lcr_io_base = pci_resource_start(pci_device, 1);
lcr_io_range = pci_resource_len(pci_device, 1);
@@ -1399,3 +1456,7 @@ static int pci9111_detach(struct comedi_device *dev)
return 0;
}
+
+MODULE_AUTHOR("Comedi http://www.comedi.org");
+MODULE_DESCRIPTION("Comedi low-level driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/adl_pci9118.c b/drivers/staging/comedi/drivers/adl_pci9118.c
index ccef549778e..b0e39cb7477 100644
--- a/drivers/staging/comedi/drivers/adl_pci9118.c
+++ b/drivers/staging/comedi/drivers/adl_pci9118.c
@@ -289,7 +289,43 @@ static struct comedi_driver driver_pci9118 = {
.offset = sizeof(struct boardtype),
};
-COMEDI_PCI_INITCLEANUP(driver_pci9118, pci9118_pci_table);
+static int __devinit driver_pci9118_pci_probe(struct pci_dev *dev,
+ const struct pci_device_id *ent)
+{
+ return comedi_pci_auto_config(dev, driver_pci9118.driver_name);
+}
+
+static void __devexit driver_pci9118_pci_remove(struct pci_dev *dev)
+{
+ comedi_pci_auto_unconfig(dev);
+}
+
+static struct pci_driver driver_pci9118_pci_driver = {
+ .id_table = pci9118_pci_table,
+ .probe = &driver_pci9118_pci_probe,
+ .remove = __devexit_p(&driver_pci9118_pci_remove)
+};
+
+static int __init driver_pci9118_init_module(void)
+{
+ int retval;
+
+ retval = comedi_driver_register(&driver_pci9118);
+ if (retval < 0)
+ return retval;
+
+ driver_pci9118_pci_driver.name = (char *)driver_pci9118.driver_name;
+ return pci_register_driver(&driver_pci9118_pci_driver);
+}
+
+static void __exit driver_pci9118_cleanup_module(void)
+{
+ pci_unregister_driver(&driver_pci9118_pci_driver);
+ comedi_driver_unregister(&driver_pci9118);
+}
+
+module_init(driver_pci9118_init_module);
+module_exit(driver_pci9118_cleanup_module);
struct pci9118_private {
unsigned long iobase_a; /* base+size for AMCC chip */
@@ -2432,3 +2468,7 @@ static int pci9118_detach(struct comedi_device *dev)
/*
==============================================================================
*/
+
+MODULE_AUTHOR("Comedi http://www.comedi.org");
+MODULE_DESCRIPTION("Comedi low-level driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/adq12b.c b/drivers/staging/comedi/drivers/adq12b.c
index f3ba645bf63..4b470000b69 100644
--- a/drivers/staging/comedi/drivers/adq12b.c
+++ b/drivers/staging/comedi/drivers/adq12b.c
@@ -402,4 +402,19 @@ static int adq12b_do_insn_bits(struct comedi_device *dev,
* A convenient macro that defines init_module() and cleanup_module(),
* as necessary.
*/
-COMEDI_INITCLEANUP(driver_adq12b);
+static int __init driver_adq12b_init_module(void)
+{
+ return comedi_driver_register(&driver_adq12b);
+}
+
+static void __exit driver_adq12b_cleanup_module(void)
+{
+ comedi_driver_unregister(&driver_adq12b);
+}
+
+module_init(driver_adq12b_init_module);
+module_exit(driver_adq12b_cleanup_module);
+
+MODULE_AUTHOR("Comedi http://www.comedi.org");
+MODULE_DESCRIPTION("Comedi low-level driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/adv_pci1710.c b/drivers/staging/comedi/drivers/adv_pci1710.c
index 67c4f11a36a..bdd6954cad9 100644
--- a/drivers/staging/comedi/drivers/adv_pci1710.c
+++ b/drivers/staging/comedi/drivers/adv_pci1710.c
@@ -19,7 +19,7 @@
/*
Driver: adv_pci1710
Description: Advantech PCI-1710, PCI-1710HG, PCI-1711, PCI-1713,
- Advantech PCI-1720, PCI-1731
+ Advantech PCI-1720, PCI-1731
Author: Michal Dobes <dobes@tesnet.cz>
Devices: [Advantech] PCI-1710 (adv_pci1710), PCI-1710HG (pci1710hg),
PCI-1711 (adv_pci1710), PCI-1713, PCI-1720,
@@ -37,8 +37,8 @@ PCI driver.
Configuration options:
[0] - PCI bus of device (optional)
[1] - PCI slot of device (optional)
- If bus/slot is not specified, the first available PCI
- device will be used.
+ If bus/slot is not specified, the first available PCI
+ device will be used.
*/
#include <linux/interrupt.h>
@@ -50,7 +50,9 @@ Configuration options:
#include "8253.h"
#include "amcc_s5933.h"
-#define PCI171x_PARANOIDCHECK /* if defined, then is used code which control correct channel number on every 12 bit sample */
+#define PCI171x_PARANOIDCHECK /* if defined, then is used code which control
+ * correct channel number on every 12 bit
+ * sample */
#undef PCI171X_EXTDEBUG
@@ -70,8 +72,8 @@ Configuration options:
#define TYPE_PCI1713 2
#define TYPE_PCI1720 3
-#define IORANGE_171x 32
-#define IORANGE_1720 16
+#define IORANGE_171x 32
+#define IORANGE_1720 16
#define PCI171x_AD_DATA 0 /* R: A/D data */
#define PCI171x_SOFTTRG 0 /* W: soft trigger for A/D */
@@ -91,13 +93,15 @@ Configuration options:
#define PCI171x_CNT2 28 /* R/W: 8254 counter 2 */
#define PCI171x_CNTCTRL 30 /* W: 8254 counter control */
-/* upper bits from status register (PCI171x_STATUS) (lower is same woth control reg) */
+/* upper bits from status register (PCI171x_STATUS) (lower is same with control
+ * reg) */
#define Status_FE 0x0100 /* 1=FIFO is empty */
#define Status_FH 0x0200 /* 1=FIFO is half full */
#define Status_FF 0x0400 /* 1=FIFO is full, fatal error */
#define Status_IRQ 0x0800 /* 1=IRQ occured */
/* bits from control register (PCI171x_CONTROL) */
-#define Control_CNT0 0x0040 /* 1=CNT0 have external source, 0=have internal 100kHz source */
+#define Control_CNT0 0x0040 /* 1=CNT0 have external source,
+ * 0=have internal 100kHz source */
#define Control_ONEFH 0x0020 /* 1=IRQ on FIFO is half full, 0=every sample */
#define Control_IRQEN 0x0010 /* 1=enable IRQ */
#define Control_GATE 0x0008 /* 1=enable external trigger GATE (8254?) */
@@ -112,7 +116,8 @@ Configuration options:
#define Counter_RW0 0x0010 /* RW0/RW1 select read/write mode */
#define Counter_RW1 0x0020
#define Counter_SC0 0x0040 /* Select Counter. Only 00 or 11 may */
-#define Counter_SC1 0x0080 /* be used, 00 for CNT0, 11 for read-back command */
+#define Counter_SC1 0x0080 /* be used, 00 for CNT0,
+ * 11 for read-back command */
#define PCI1720_DA0 0 /* W: D/A register 0 */
#define PCI1720_DA1 2 /* W: D/A register 1 */
@@ -138,8 +143,8 @@ static const struct comedi_lrange range_pci1710_3 = { 9, {
}
};
-static const char range_codes_pci1710_3[] =
- { 0x00, 0x01, 0x02, 0x03, 0x04, 0x10, 0x11, 0x12, 0x13 };
+static const char range_codes_pci1710_3[] = { 0x00, 0x01, 0x02, 0x03, 0x04,
+ 0x10, 0x11, 0x12, 0x13 };
static const struct comedi_lrange range_pci1710hg = { 12, {
BIP_RANGE(5),
@@ -157,10 +162,9 @@ static const struct comedi_lrange range_pci1710hg = { 12, {
}
};
-static const char range_codes_pci1710hg[] =
- { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x10, 0x11, 0x12,
- 0x13
-};
+static const char range_codes_pci1710hg[] = { 0x00, 0x01, 0x02, 0x03, 0x04,
+ 0x05, 0x06, 0x07, 0x10, 0x11,
+ 0x12, 0x13 };
static const struct comedi_lrange range_pci17x1 = { 5, {
BIP_RANGE(10),
@@ -301,7 +305,8 @@ struct pci1710_private {
unsigned int ai_timer1; /* timers */
unsigned int ai_timer2;
short ao_data[4]; /* data output buffer */
- unsigned int cnt0_write_wait; /* after a write, wait for update of the internal state */
+ unsigned int cnt0_write_wait; /* after a write, wait for update of the
+ * internal state */
};
#define devpriv ((struct pci1710_private *)dev->private)
@@ -324,7 +329,9 @@ static int pci1710_reset(struct comedi_device *dev);
static int pci171x_ai_cancel(struct comedi_device *dev,
struct comedi_subdevice *s);
-static const unsigned int muxonechan[] = { 0x0000, 0x0101, 0x0202, 0x0303, 0x0404, 0x0505, 0x0606, 0x0707, /* used for gain list programming */
+/* used for gain list programming */
+static const unsigned int muxonechan[] = {
+ 0x0000, 0x0101, 0x0202, 0x0303, 0x0404, 0x0505, 0x0606, 0x0707,
0x0808, 0x0909, 0x0a0a, 0x0b0b, 0x0c0c, 0x0d0d, 0x0e0e, 0x0f0f,
0x1010, 0x1111, 0x1212, 0x1313, 0x1414, 0x1515, 0x1616, 0x1717,
0x1818, 0x1919, 0x1a1a, 0x1b1b, 0x1c1c, 0x1d1d, 0x1e1e, 0x1f1f
@@ -774,7 +781,8 @@ static void interrupt_pci1710_half_fifo(void *d)
}
if (!devpriv->neverending_ai)
- if (devpriv->ai_act_scan >= devpriv->ai_scans) { /* all data sampled */
+ if (devpriv->ai_act_scan >= devpriv->ai_scans) { /* all data
+ sampled */
pci171x_ai_cancel(dev, s);
s->async->events |= COMEDI_CB_EOA;
comedi_event(dev, s);
@@ -1559,7 +1567,8 @@ static int pci1710_attach(struct comedi_device *dev,
s->maxdata = 1;
s->len_chanlist = this_board->n_dochan;
s->range_table = &range_digital;
- s->io_bits = (1 << this_board->n_dochan) - 1; /* all bits output */
+ /* all bits output */
+ s->io_bits = (1 << this_board->n_dochan) - 1;
s->state = 0;
s->insn_bits = pci171x_insn_bits_do;
subdev++;
@@ -1609,7 +1618,47 @@ static int pci1710_detach(struct comedi_device *dev)
/*
==============================================================================
*/
-COMEDI_PCI_INITCLEANUP(driver_pci1710, pci1710_pci_table);
+static int __devinit driver_pci1710_pci_probe(struct pci_dev *dev,
+ const struct pci_device_id *ent)
+{
+ return comedi_pci_auto_config(dev, driver_pci1710.driver_name);
+}
+
+static void __devexit driver_pci1710_pci_remove(struct pci_dev *dev)
+{
+ comedi_pci_auto_unconfig(dev);
+}
+
+static struct pci_driver driver_pci1710_pci_driver = {
+ .id_table = pci1710_pci_table,
+ .probe = &driver_pci1710_pci_probe,
+ .remove = __devexit_p(&driver_pci1710_pci_remove)
+};
+
+static int __init driver_pci1710_init_module(void)
+{
+ int retval;
+
+ retval = comedi_driver_register(&driver_pci1710);
+ if (retval < 0)
+ return retval;
+
+ driver_pci1710_pci_driver.name = (char *)driver_pci1710.driver_name;
+ return pci_register_driver(&driver_pci1710_pci_driver);
+}
+
+static void __exit driver_pci1710_cleanup_module(void)
+{
+ pci_unregister_driver(&driver_pci1710_pci_driver);
+ comedi_driver_unregister(&driver_pci1710);
+}
+
+module_init(driver_pci1710_init_module);
+module_exit(driver_pci1710_cleanup_module);
/*
==============================================================================
*/
+
+MODULE_AUTHOR("Comedi http://www.comedi.org");
+MODULE_DESCRIPTION("Comedi low-level driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/adv_pci1723.c b/drivers/staging/comedi/drivers/adv_pci1723.c
index 9fe8fcc7f1d..b133bb84c4f 100644
--- a/drivers/staging/comedi/drivers/adv_pci1723.c
+++ b/drivers/staging/comedi/drivers/adv_pci1723.c
@@ -496,4 +496,44 @@ static int pci1723_detach(struct comedi_device *dev)
* A convenient macro that defines init_module() and cleanup_module(),
* as necessary.
*/
-COMEDI_PCI_INITCLEANUP(driver_pci1723, pci1723_pci_table);
+static int __devinit driver_pci1723_pci_probe(struct pci_dev *dev,
+ const struct pci_device_id *ent)
+{
+ return comedi_pci_auto_config(dev, driver_pci1723.driver_name);
+}
+
+static void __devexit driver_pci1723_pci_remove(struct pci_dev *dev)
+{
+ comedi_pci_auto_unconfig(dev);
+}
+
+static struct pci_driver driver_pci1723_pci_driver = {
+ .id_table = pci1723_pci_table,
+ .probe = &driver_pci1723_pci_probe,
+ .remove = __devexit_p(&driver_pci1723_pci_remove)
+};
+
+static int __init driver_pci1723_init_module(void)
+{
+ int retval;
+
+ retval = comedi_driver_register(&driver_pci1723);
+ if (retval < 0)
+ return retval;
+
+ driver_pci1723_pci_driver.name = (char *)driver_pci1723.driver_name;
+ return pci_register_driver(&driver_pci1723_pci_driver);
+}
+
+static void __exit driver_pci1723_cleanup_module(void)
+{
+ pci_unregister_driver(&driver_pci1723_pci_driver);
+ comedi_driver_unregister(&driver_pci1723);
+}
+
+module_init(driver_pci1723_init_module);
+module_exit(driver_pci1723_cleanup_module);
+
+MODULE_AUTHOR("Comedi http://www.comedi.org");
+MODULE_DESCRIPTION("Comedi low-level driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/adv_pci_dio.c b/drivers/staging/comedi/drivers/adv_pci_dio.c
index e424a0c7d34..d018bb4e289 100644
--- a/drivers/staging/comedi/drivers/adv_pci_dio.c
+++ b/drivers/staging/comedi/drivers/adv_pci_dio.c
@@ -8,8 +8,8 @@
/*
Driver: adv_pci_dio
Description: Advantech PCI-1730, PCI-1733, PCI-1734, PCI-1735U,
- PCI-1736UP, PCI-1750, PCI-1751, PCI-1752, PCI-1753/E,
- PCI-1754, PCI-1756, PCI-1762
+ PCI-1736UP, PCI-1750, PCI-1751, PCI-1752, PCI-1753/E,
+ PCI-1754, PCI-1756, PCI-1762
Author: Michal Dobes <dobes@tesnet.cz>
Devices: [Advantech] PCI-1730 (adv_pci_dio), PCI-1733,
PCI-1734, PCI-1735U, PCI-1736UP, PCI-1750,
@@ -24,8 +24,8 @@ This driver supports now only insn interface for DI/DO/DIO.
Configuration options:
[0] - PCI bus of device (optional)
[1] - PCI slot of device (optional)
- If bus/slot is not specified, the first available PCI
- device will be used.
+ If bus/slot is not specified, the first available PCI
+ device will be used.
*/
@@ -67,9 +67,12 @@ enum hw_io_access {
#define MAX_DI_SUBDEVS 2 /* max number of DI subdevices per card */
#define MAX_DO_SUBDEVS 2 /* max number of DO subdevices per card */
-#define MAX_DIO_SUBDEVG 2 /* max number of DIO subdevices group per card */
-#define MAX_8254_SUBDEVS 1 /* max number of 8254 counter subdevs per card */
- /* (could be more than one 8254 per subdevice) */
+#define MAX_DIO_SUBDEVG 2 /* max number of DIO subdevices group per
+ * card */
+#define MAX_8254_SUBDEVS 1 /* max number of 8254 counter subdevs per
+ * card */
+ /* (could be more than one 8254 per
+ * subdevice) */
#define SIZE_8254 4 /* 8254 IO space length */
#define SIZE_8255 4 /* 8255 IO space length */
@@ -84,7 +87,8 @@ enum hw_io_access {
#define PCI1730_DO 2 /* W: Digital output 0-15 */
#define PCI1733_IDI 0 /* R: Isolated digital input 0-31 */
#define PCI1730_3_INT_EN 0x08 /* R/W: enable/disable interrupts */
-#define PCI1730_3_INT_RF 0x0c /* R/W: set falling/raising edge for interrupts */
+#define PCI1730_3_INT_RF 0x0c /* R/W: set falling/raising edge for
+ * interrupts */
#define PCI1730_3_INT_CLR 0x10 /* R/W: clear interrupts */
#define PCI1734_IDO 0 /* W: Isolated digital output 0-31 */
#define PCI173x_BOARDID 4 /* R: Board I/D switch for 1730/3/4 */
@@ -99,7 +103,8 @@ enum hw_io_access {
#define PCI1736_IDI 0 /* R: Isolated digital input 0-15 */
#define PCI1736_IDO 0 /* W: Isolated digital output 0-15 */
#define PCI1736_3_INT_EN 0x08 /* R/W: enable/disable interrupts */
-#define PCI1736_3_INT_RF 0x0c /* R/W: set falling/raising edge for interrupts */
+#define PCI1736_3_INT_RF 0x0c /* R/W: set falling/raising edge for
+ * interrupts */
#define PCI1736_3_INT_CLR 0x10 /* R/W: clear interrupts */
#define PCI1736_BOARDID 4 /* R: Board I/D switch for 1736UP */
#define PCI1736_MAINREG 0 /* Normal register (2) doesn't work */
@@ -161,37 +166,66 @@ enum hw_io_access {
#define INTCSR3 0x3b
/* PCI-1760 mailbox commands */
-#define CMD_ClearIMB2 0x00 /* Clear IMB2 status and return actaul DI status in IMB3 */
+#define CMD_ClearIMB2 0x00 /* Clear IMB2 status and return actual
+ * DI status in IMB3 */
#define CMD_SetRelaysOutput 0x01 /* Set relay output from OMB0 */
#define CMD_GetRelaysStatus 0x02 /* Get relay status to IMB0 */
-#define CMD_ReadCurrentStatus 0x07 /* Read the current status of the register in OMB0, result in IMB0 */
-#define CMD_ReadFirmwareVersion 0x0e /* Read the firmware ver., result in IMB1.IMB0 */
-#define CMD_ReadHardwareVersion 0x0f /* Read the hardware ver., result in IMB1.IMB0 */
-#define CMD_EnableIDIFilters 0x20 /* Enable IDI filters based on bits in OMB0 */
-#define CMD_EnableIDIPatternMatch 0x21 /* Enable IDI pattern match based on bits in OMB0 */
-#define CMD_SetIDIPatternMatch 0x22 /* Enable IDI pattern match based on bits in OMB0 */
-#define CMD_EnableIDICounters 0x28 /* Enable IDI counters based on bits in OMB0 */
-#define CMD_ResetIDICounters 0x29 /* Reset IDI counters based on bits in OMB0 to its reset values */
-#define CMD_OverflowIDICounters 0x2a /* Enable IDI counters overflow interrupts based on bits in OMB0 */
-#define CMD_MatchIntIDICounters 0x2b /* Enable IDI counters match value interrupts based on bits in OMB0 */
-#define CMD_EdgeIDICounters 0x2c /* Set IDI up counters count edge (bit=0 - rising, =1 - falling) */
-#define CMD_GetIDICntCurValue 0x2f /* Read IDI{OMB0} up counter current value */
-#define CMD_SetIDI0CntResetValue 0x40 /* Set IDI0 Counter Reset Value 256*OMB1+OMB0 */
-#define CMD_SetIDI1CntResetValue 0x41 /* Set IDI1 Counter Reset Value 256*OMB1+OMB0 */
-#define CMD_SetIDI2CntResetValue 0x42 /* Set IDI2 Counter Reset Value 256*OMB1+OMB0 */
-#define CMD_SetIDI3CntResetValue 0x43 /* Set IDI3 Counter Reset Value 256*OMB1+OMB0 */
-#define CMD_SetIDI4CntResetValue 0x44 /* Set IDI4 Counter Reset Value 256*OMB1+OMB0 */
-#define CMD_SetIDI5CntResetValue 0x45 /* Set IDI5 Counter Reset Value 256*OMB1+OMB0 */
-#define CMD_SetIDI6CntResetValue 0x46 /* Set IDI6 Counter Reset Value 256*OMB1+OMB0 */
-#define CMD_SetIDI7CntResetValue 0x47 /* Set IDI7 Counter Reset Value 256*OMB1+OMB0 */
-#define CMD_SetIDI0CntMatchValue 0x48 /* Set IDI0 Counter Match Value 256*OMB1+OMB0 */
-#define CMD_SetIDI1CntMatchValue 0x49 /* Set IDI1 Counter Match Value 256*OMB1+OMB0 */
-#define CMD_SetIDI2CntMatchValue 0x4a /* Set IDI2 Counter Match Value 256*OMB1+OMB0 */
-#define CMD_SetIDI3CntMatchValue 0x4b /* Set IDI3 Counter Match Value 256*OMB1+OMB0 */
-#define CMD_SetIDI4CntMatchValue 0x4c /* Set IDI4 Counter Match Value 256*OMB1+OMB0 */
-#define CMD_SetIDI5CntMatchValue 0x4d /* Set IDI5 Counter Match Value 256*OMB1+OMB0 */
-#define CMD_SetIDI6CntMatchValue 0x4e /* Set IDI6 Counter Match Value 256*OMB1+OMB0 */
-#define CMD_SetIDI7CntMatchValue 0x4f /* Set IDI7 Counter Match Value 256*OMB1+OMB0 */
+#define CMD_ReadCurrentStatus 0x07 /* Read the current status of the
+ * register in OMB0, result in IMB0 */
+#define CMD_ReadFirmwareVersion 0x0e /* Read the firmware ver., result in
+ * IMB1.IMB0 */
+#define CMD_ReadHardwareVersion 0x0f /* Read the hardware ver., result in
+ * IMB1.IMB0 */
+#define CMD_EnableIDIFilters 0x20 /* Enable IDI filters based on bits in
+ * OMB0 */
+#define CMD_EnableIDIPatternMatch 0x21 /* Enable IDI pattern match based on
+ * bits in OMB0 */
+#define CMD_SetIDIPatternMatch 0x22 /* Enable IDI pattern match based on
+ * bits in OMB0 */
+#define CMD_EnableIDICounters 0x28 /* Enable IDI counters based on bits in
+ * OMB0 */
+#define CMD_ResetIDICounters 0x29 /* Reset IDI counters based on bits in
+ * OMB0 to its reset values */
+#define CMD_OverflowIDICounters 0x2a /* Enable IDI counters overflow
+ * interrupts based on bits in OMB0 */
+#define CMD_MatchIntIDICounters 0x2b /* Enable IDI counters match value
+ * interrupts based on bits in OMB0 */
+#define CMD_EdgeIDICounters 0x2c /* Set IDI up counters count edge (bit=0
+ * - rising, =1 - falling) */
+#define CMD_GetIDICntCurValue 0x2f /* Read IDI{OMB0} up counter current
+ * value */
+#define CMD_SetIDI0CntResetValue 0x40 /* Set IDI0 Counter Reset Value
+ * 256*OMB1+OMB0 */
+#define CMD_SetIDI1CntResetValue 0x41 /* Set IDI1 Counter Reset Value
+ * 256*OMB1+OMB0 */
+#define CMD_SetIDI2CntResetValue 0x42 /* Set IDI2 Counter Reset Value
+ * 256*OMB1+OMB0 */
+#define CMD_SetIDI3CntResetValue 0x43 /* Set IDI3 Counter Reset Value
+ * 256*OMB1+OMB0 */
+#define CMD_SetIDI4CntResetValue 0x44 /* Set IDI4 Counter Reset Value
+ * 256*OMB1+OMB0 */
+#define CMD_SetIDI5CntResetValue 0x45 /* Set IDI5 Counter Reset Value
+ * 256*OMB1+OMB0 */
+#define CMD_SetIDI6CntResetValue 0x46 /* Set IDI6 Counter Reset Value
+ * 256*OMB1+OMB0 */
+#define CMD_SetIDI7CntResetValue 0x47 /* Set IDI7 Counter Reset Value
+ * 256*OMB1+OMB0 */
+#define CMD_SetIDI0CntMatchValue 0x48 /* Set IDI0 Counter Match Value
+ * 256*OMB1+OMB0 */
+#define CMD_SetIDI1CntMatchValue 0x49 /* Set IDI1 Counter Match Value
+ * 256*OMB1+OMB0 */
+#define CMD_SetIDI2CntMatchValue 0x4a /* Set IDI2 Counter Match Value
+ * 256*OMB1+OMB0 */
+#define CMD_SetIDI3CntMatchValue 0x4b /* Set IDI3 Counter Match Value
+ * 256*OMB1+OMB0 */
+#define CMD_SetIDI4CntMatchValue 0x4c /* Set IDI4 Counter Match Value
+ * 256*OMB1+OMB0 */
+#define CMD_SetIDI5CntMatchValue 0x4d /* Set IDI5 Counter Match Value
+ * 256*OMB1+OMB0 */
+#define CMD_SetIDI6CntMatchValue 0x4e /* Set IDI6 Counter Match Value
+ * 256*OMB1+OMB0 */
+#define CMD_SetIDI7CntMatchValue 0x4f /* Set IDI7 Counter Match Value
+ * 256*OMB1+OMB0 */
#define OMBCMD_RETRY 0x03 /* 3 times try request before error */
@@ -244,115 +278,115 @@ MODULE_DEVICE_TABLE(pci, pci_dio_pci_table);
static const struct dio_boardtype boardtypes[] = {
{"pci1730", PCI_VENDOR_ID_ADVANTECH, 0x1730, PCIDIO_MAINREG,
TYPE_PCI1730,
- {{16, PCI1730_DI, 2, 0}, {16, PCI1730_IDI, 2, 0}},
- {{16, PCI1730_DO, 2, 0}, {16, PCI1730_IDO, 2, 0}},
- {{0, 0, 0, 0}, {0, 0, 0, 0}},
+ { {16, PCI1730_DI, 2, 0}, {16, PCI1730_IDI, 2, 0} },
+ { {16, PCI1730_DO, 2, 0}, {16, PCI1730_IDO, 2, 0} },
+ { {0, 0, 0, 0}, {0, 0, 0, 0} },
{4, PCI173x_BOARDID, 1, SDF_INTERNAL},
- {{0, 0, 0, 0}},
+ { {0, 0, 0, 0} },
IO_8b},
{"pci1733", PCI_VENDOR_ID_ADVANTECH, 0x1733, PCIDIO_MAINREG,
TYPE_PCI1733,
- {{0, 0, 0, 0}, {32, PCI1733_IDI, 4, 0}},
- {{0, 0, 0, 0}, {0, 0, 0, 0}},
- {{0, 0, 0, 0}, {0, 0, 0, 0}},
+ { {0, 0, 0, 0}, {32, PCI1733_IDI, 4, 0} },
+ { {0, 0, 0, 0}, {0, 0, 0, 0} },
+ { {0, 0, 0, 0}, {0, 0, 0, 0} },
{4, PCI173x_BOARDID, 1, SDF_INTERNAL},
- {{0, 0, 0, 0}},
+ { {0, 0, 0, 0} },
IO_8b},
{"pci1734", PCI_VENDOR_ID_ADVANTECH, 0x1734, PCIDIO_MAINREG,
TYPE_PCI1734,
- {{0, 0, 0, 0}, {0, 0, 0, 0}},
- {{0, 0, 0, 0}, {32, PCI1734_IDO, 4, 0}},
- {{0, 0, 0, 0}, {0, 0, 0, 0}},
+ { {0, 0, 0, 0}, {0, 0, 0, 0} },
+ { {0, 0, 0, 0}, {32, PCI1734_IDO, 4, 0} },
+ { {0, 0, 0, 0}, {0, 0, 0, 0} },
{4, PCI173x_BOARDID, 1, SDF_INTERNAL},
- {{0, 0, 0, 0}},
+ { {0, 0, 0, 0} },
IO_8b},
{"pci1735", PCI_VENDOR_ID_ADVANTECH, 0x1735, PCIDIO_MAINREG,
TYPE_PCI1735,
- {{32, PCI1735_DI, 4, 0}, {0, 0, 0, 0}},
- {{32, PCI1735_DO, 4, 0}, {0, 0, 0, 0}},
- {{0, 0, 0, 0}, {0, 0, 0, 0}},
+ { {32, PCI1735_DI, 4, 0}, {0, 0, 0, 0} },
+ { {32, PCI1735_DO, 4, 0}, {0, 0, 0, 0} },
+ { {0, 0, 0, 0}, {0, 0, 0, 0} },
{ 4, PCI1735_BOARDID, 1, SDF_INTERNAL},
- {{3, PCI1735_C8254, 1, 0}},
+ { {3, PCI1735_C8254, 1, 0} },
IO_8b},
{"pci1736", PCI_VENDOR_ID_ADVANTECH, 0x1736, PCI1736_MAINREG,
TYPE_PCI1736,
- {{0, 0, 0, 0}, {16, PCI1736_IDI, 2, 0}},
- {{0, 0, 0, 0}, {16, PCI1736_IDO, 2, 0}},
- {{0, 0, 0, 0}, {0, 0, 0, 0}},
+ { {0, 0, 0, 0}, {16, PCI1736_IDI, 2, 0} },
+ { {0, 0, 0, 0}, {16, PCI1736_IDO, 2, 0} },
+ { {0, 0, 0, 0}, {0, 0, 0, 0} },
{4, PCI1736_BOARDID, 1, SDF_INTERNAL},
- {{0, 0, 0, 0}},
+ { {0, 0, 0, 0} },
IO_8b},
{"pci1750", PCI_VENDOR_ID_ADVANTECH, 0x1750, PCIDIO_MAINREG,
TYPE_PCI1750,
- {{0, 0, 0, 0}, {16, PCI1750_IDI, 2, 0}},
- {{0, 0, 0, 0}, {16, PCI1750_IDO, 2, 0}},
- {{0, 0, 0, 0}, {0, 0, 0, 0}},
+ { {0, 0, 0, 0}, {16, PCI1750_IDI, 2, 0} },
+ { {0, 0, 0, 0}, {16, PCI1750_IDO, 2, 0} },
+ { {0, 0, 0, 0}, {0, 0, 0, 0} },
{0, 0, 0, 0},
- {{0, 0, 0, 0}},
+ { {0, 0, 0, 0} },
IO_8b},
{"pci1751", PCI_VENDOR_ID_ADVANTECH, 0x1751, PCIDIO_MAINREG,
TYPE_PCI1751,
- {{0, 0, 0, 0}, {0, 0, 0, 0}},
- {{0, 0, 0, 0}, {0, 0, 0, 0}},
- {{48, PCI1751_DIO, 2, 0}, {0, 0, 0, 0}},
+ { {0, 0, 0, 0}, {0, 0, 0, 0} },
+ { {0, 0, 0, 0}, {0, 0, 0, 0} },
+ { {48, PCI1751_DIO, 2, 0}, {0, 0, 0, 0} },
{0, 0, 0, 0},
- {{0, 0, 0, 0}},
+ { {0, 0, 0, 0} },
IO_8b},
{"pci1752", PCI_VENDOR_ID_ADVANTECH, 0x1752, PCIDIO_MAINREG,
TYPE_PCI1752,
- {{0, 0, 0, 0}, {0, 0, 0, 0}},
- {{32, PCI1752_IDO, 2, 0}, {32, PCI1752_IDO2, 2, 0}},
- {{0, 0, 0, 0}, {0, 0, 0, 0}},
+ { {0, 0, 0, 0}, {0, 0, 0, 0} },
+ { {32, PCI1752_IDO, 2, 0}, {32, PCI1752_IDO2, 2, 0} },
+ { {0, 0, 0, 0}, {0, 0, 0, 0} },
{4, PCI175x_BOARDID, 1, SDF_INTERNAL},
- {{0, 0, 0, 0}},
+ { {0, 0, 0, 0} },
IO_16b},
{"pci1753", PCI_VENDOR_ID_ADVANTECH, 0x1753, PCIDIO_MAINREG,
TYPE_PCI1753,
- {{0, 0, 0, 0}, {0, 0, 0, 0}},
- {{0, 0, 0, 0}, {0, 0, 0, 0}},
- {{96, PCI1753_DIO, 4, 0}, {0, 0, 0, 0}},
+ { {0, 0, 0, 0}, {0, 0, 0, 0} },
+ { {0, 0, 0, 0}, {0, 0, 0, 0} },
+ { {96, PCI1753_DIO, 4, 0}, {0, 0, 0, 0} },
{0, 0, 0, 0},
- {{0, 0, 0, 0}},
+ { {0, 0, 0, 0} },
IO_8b},
{"pci1753e", PCI_VENDOR_ID_ADVANTECH, 0x1753, PCIDIO_MAINREG,
TYPE_PCI1753E,
- {{0, 0, 0, 0}, {0, 0, 0, 0}},
- {{0, 0, 0, 0}, {0, 0, 0, 0}},
- {{96, PCI1753_DIO, 4, 0}, {96, PCI1753E_DIO, 4, 0}},
+ { {0, 0, 0, 0}, {0, 0, 0, 0} },
+ { {0, 0, 0, 0}, {0, 0, 0, 0} },
+ { {96, PCI1753_DIO, 4, 0}, {96, PCI1753E_DIO, 4, 0} },
{0, 0, 0, 0},
- {{0, 0, 0, 0}},
+ { {0, 0, 0, 0} },
IO_8b},
{"pci1754", PCI_VENDOR_ID_ADVANTECH, 0x1754, PCIDIO_MAINREG,
TYPE_PCI1754,
- {{32, PCI1754_IDI, 2, 0}, {32, PCI1754_IDI2, 2, 0}},
- {{0, 0, 0, 0}, {0, 0, 0, 0}},
- {{0, 0, 0, 0}, {0, 0, 0, 0}},
+ { {32, PCI1754_IDI, 2, 0}, {32, PCI1754_IDI2, 2, 0} },
+ { {0, 0, 0, 0}, {0, 0, 0, 0} },
+ { {0, 0, 0, 0}, {0, 0, 0, 0} },
{4, PCI175x_BOARDID, 1, SDF_INTERNAL},
- {{0, 0, 0, 0}},
+ { {0, 0, 0, 0} },
IO_16b},
{"pci1756", PCI_VENDOR_ID_ADVANTECH, 0x1756, PCIDIO_MAINREG,
TYPE_PCI1756,
- {{0, 0, 0, 0}, {32, PCI1756_IDI, 2, 0}},
- {{0, 0, 0, 0}, {32, PCI1756_IDO, 2, 0}},
- {{0, 0, 0, 0}, {0, 0, 0, 0}},
+ { {0, 0, 0, 0}, {32, PCI1756_IDI, 2, 0} },
+ { {0, 0, 0, 0}, {32, PCI1756_IDO, 2, 0} },
+ { {0, 0, 0, 0}, {0, 0, 0, 0} },
{4, PCI175x_BOARDID, 1, SDF_INTERNAL},
- {{0, 0, 0, 0}},
+ { {0, 0, 0, 0} },
IO_16b},
{"pci1760", PCI_VENDOR_ID_ADVANTECH, 0x1760, 0,
TYPE_PCI1760,
- {{0, 0, 0, 0}, {0, 0, 0, 0}}, /* This card have own setup work */
- {{0, 0, 0, 0}, {0, 0, 0, 0}},
- {{0, 0, 0, 0}, {0, 0, 0, 0}},
+ { {0, 0, 0, 0}, {0, 0, 0, 0} }, /* This card have own setup work */
+ { {0, 0, 0, 0}, {0, 0, 0, 0} },
+ { {0, 0, 0, 0}, {0, 0, 0, 0} },
{0, 0, 0, 0},
- {{0, 0, 0, 0}},
+ { {0, 0, 0, 0} },
IO_8b},
{"pci1762", PCI_VENDOR_ID_ADVANTECH, 0x1762, PCIDIO_MAINREG,
TYPE_PCI1762,
- {{0, 0, 0, 0}, {16, PCI1762_IDI, 1, 0}},
- {{0, 0, 0, 0}, {16, PCI1762_RO, 1, 0}},
- {{0, 0, 0, 0}, {0, 0, 0, 0}},
+ { {0, 0, 0, 0}, {16, PCI1762_IDI, 1, 0} },
+ { {0, 0, 0, 0}, {16, PCI1762_RO, 1, 0} },
+ { {0, 0, 0, 0}, {0, 0, 0, 0} },
{4, PCI1762_BOARDID, 1, SDF_INTERNAL},
- {{0, 0, 0, 0}},
+ { {0, 0, 0, 0} },
IO_16b}
};
@@ -372,13 +406,16 @@ struct pci_dio_private {
char valid; /* card is usable */
char GlobalIrqEnabled; /* 1= any IRQ source is enabled */
/* PCI-1760 specific data */
- unsigned char IDICntEnable; /* counter's counting enable status */
- unsigned char IDICntOverEnable; /* counter's overflow interrupts enable status */
- unsigned char IDICntMatchEnable; /* counter's match interrupts enable status */
- unsigned char IDICntEdge; /* counter's count edge value (bit=0 - rising, =1 - falling) */
+ unsigned char IDICntEnable; /* counter's counting enable status */
+ unsigned char IDICntOverEnable; /* counter's overflow interrupts enable
+ * status */
+ unsigned char IDICntMatchEnable; /* counter's match interrupts
+ * enable status */
+ unsigned char IDICntEdge; /* counter's count edge value
+ * (bit=0 - rising, =1 - falling) */
unsigned short CntResValue[8]; /* counters' reset value */
- unsigned short CntMatchValue[8]; /* counters' match interrupt value */
- unsigned char IDIFiltersEn; /* IDI's digital filters enable status */
+ unsigned short CntMatchValue[8]; /* counters' match interrupt value */
+ unsigned char IDIFiltersEn; /* IDI's digital filters enable status */
unsigned char IDIPatMatchEn; /* IDI's pattern match enable status */
unsigned char IDIPatMatchValue; /* IDI's pattern match value */
unsigned short IDIFiltrLow[8]; /* IDI's filter value low signal */
@@ -691,7 +728,8 @@ static int pci1760_insn_cnt_write(struct comedi_device *dev,
};
unsigned char imb[4];
- if (devpriv->CntResValue[chan] != (data[0] & 0xffff)) { /* Set reset value if different */
+ /* Set reset value if different */
+ if (devpriv->CntResValue[chan] != (data[0] & 0xffff)) {
ret = pci1760_mbxrequest(dev, omb, imb);
if (!ret)
return ret;
@@ -704,7 +742,8 @@ static int pci1760_insn_cnt_write(struct comedi_device *dev,
if (!ret)
return ret;
- if (!(bitmask & devpriv->IDICntEnable)) { /* start counter if it don't run */
+ /* start counter if it don't run */
+ if (!(bitmask & devpriv->IDICntEnable)) {
omb[0] = bitmask;
omb[2] = CMD_EnableIDICounters;
ret = pci1760_mbxrequest(dev, omb, imb);
@@ -740,12 +779,14 @@ static int pci1760_reset(struct comedi_device *dev)
devpriv->IDICntEnable = 0;
omb[0] = 0x00;
- omb[2] = CMD_OverflowIDICounters; /* disable counters overflow interrupts */
+ omb[2] = CMD_OverflowIDICounters; /* disable counters overflow
+ * interrupts */
pci1760_mbxrequest(dev, omb, imb);
devpriv->IDICntOverEnable = 0;
omb[0] = 0x00;
- omb[2] = CMD_MatchIntIDICounters; /* disable counters match value interrupts */
+ omb[2] = CMD_MatchIntIDICounters; /* disable counters match value
+ * interrupts */
pci1760_mbxrequest(dev, omb, imb);
devpriv->IDICntMatchEnable = 0;
@@ -766,7 +807,8 @@ static int pci1760_reset(struct comedi_device *dev)
}
omb[0] = 0xff;
- omb[2] = CMD_ResetIDICounters; /* reset IDI up counters to reset values */
+ omb[2] = CMD_ResetIDICounters; /* reset IDI up counters to reset
+ * values */
pci1760_mbxrequest(dev, omb, imb);
omb[0] = 0x00;
@@ -807,9 +849,12 @@ static int pci_dio_reset(struct comedi_device *dev)
outb(0, dev->iobase + PCI1730_IDO + 1);
/* NO break there! */
case TYPE_PCI1733:
- outb(0, dev->iobase + PCI1730_3_INT_EN); /* disable interrupts */
- outb(0x0f, dev->iobase + PCI1730_3_INT_CLR); /* clear interrupts */
- outb(0, dev->iobase + PCI1730_3_INT_RF); /* set rising edge trigger */
+ /* disable interrupts */
+ outb(0, dev->iobase + PCI1730_3_INT_EN);
+ /* clear interrupts */
+ outb(0x0f, dev->iobase + PCI1730_3_INT_CLR);
+ /* set rising edge trigger */
+ outb(0, dev->iobase + PCI1730_3_INT_RF);
break;
case TYPE_PCI1734:
outb(0, dev->iobase + PCI1734_IDO); /* clear outputs */
@@ -830,43 +875,53 @@ static int pci_dio_reset(struct comedi_device *dev)
case TYPE_PCI1736:
outb(0, dev->iobase + PCI1736_IDO);
outb(0, dev->iobase + PCI1736_IDO + 1);
- outb(0, dev->iobase + PCI1736_3_INT_EN); /* disable interrupts */
- outb(0x0f, dev->iobase + PCI1736_3_INT_CLR); /* clear interrupts */
- outb(0, dev->iobase + PCI1736_3_INT_RF); /* set rising edge trigger */
+ /* disable interrupts */
+ outb(0, dev->iobase + PCI1736_3_INT_EN);
+ /* clear interrupts */
+ outb(0x0f, dev->iobase + PCI1736_3_INT_CLR);
+ /* set rising edge trigger */
+ outb(0, dev->iobase + PCI1736_3_INT_RF);
break;
case TYPE_PCI1750:
case TYPE_PCI1751:
- outb(0x88, dev->iobase + PCI1750_ICR); /* disable & clear interrupts */
+ /* disable & clear interrupts */
+ outb(0x88, dev->iobase + PCI1750_ICR);
break;
case TYPE_PCI1752:
- outw(0, dev->iobase + PCI1752_6_CFC); /* disable channel freeze function */
+ outw(0, dev->iobase + PCI1752_6_CFC); /* disable channel freeze
+ * function */
outw(0, dev->iobase + PCI1752_IDO); /* clear outputs */
outw(0, dev->iobase + PCI1752_IDO + 2);
outw(0, dev->iobase + PCI1752_IDO2);
outw(0, dev->iobase + PCI1752_IDO2 + 2);
break;
case TYPE_PCI1753E:
- outb(0x88, dev->iobase + PCI1753E_ICR0); /* disable & clear interrupts */
+ outb(0x88, dev->iobase + PCI1753E_ICR0); /* disable & clear
+ * interrupts */
outb(0x80, dev->iobase + PCI1753E_ICR1);
outb(0x80, dev->iobase + PCI1753E_ICR2);
outb(0x80, dev->iobase + PCI1753E_ICR3);
/* NO break there! */
case TYPE_PCI1753:
- outb(0x88, dev->iobase + PCI1753_ICR0); /* disable & clear interrupts */
+ outb(0x88, dev->iobase + PCI1753_ICR0); /* disable & clear
+ * interrupts */
outb(0x80, dev->iobase + PCI1753_ICR1);
outb(0x80, dev->iobase + PCI1753_ICR2);
outb(0x80, dev->iobase + PCI1753_ICR3);
break;
case TYPE_PCI1754:
- outw(0x08, dev->iobase + PCI1754_6_ICR0); /* disable and clear interrupts */
+ outw(0x08, dev->iobase + PCI1754_6_ICR0); /* disable and clear
+ * interrupts */
outw(0x08, dev->iobase + PCI1754_6_ICR1);
outw(0x08, dev->iobase + PCI1754_ICR2);
outw(0x08, dev->iobase + PCI1754_ICR3);
break;
case TYPE_PCI1756:
- outw(0, dev->iobase + PCI1752_6_CFC); /* disable channel freeze function */
- outw(0x08, dev->iobase + PCI1754_6_ICR0); /* disable and clear interrupts */
+ outw(0, dev->iobase + PCI1752_6_CFC); /* disable channel freeze
+ * function */
+ outw(0x08, dev->iobase + PCI1754_6_ICR0); /* disable and clear
+ * interrupts */
outw(0x08, dev->iobase + PCI1754_6_ICR1);
outw(0, dev->iobase + PCI1756_IDO); /* clear outputs */
outw(0, dev->iobase + PCI1756_IDO + 2);
@@ -875,7 +930,8 @@ static int pci_dio_reset(struct comedi_device *dev)
pci1760_reset(dev);
break;
case TYPE_PCI1762:
- outw(0x0101, dev->iobase + PCI1762_ICR); /* disable & clear interrupts */
+ outw(0x0101, dev->iobase + PCI1762_ICR); /* disable & clear
+ * interrupts */
break;
}
@@ -996,7 +1052,7 @@ static int pci_dio_add_do(struct comedi_device *dev, struct comedi_subdevice *s,
==============================================================================
*/
static int pci_dio_add_8254(struct comedi_device *dev,
- struct comedi_subdevice * s,
+ struct comedi_subdevice *s,
const struct diosubd_data *d, int subdev)
{
s->type = COMEDI_SUBD_COUNTER;
@@ -1023,7 +1079,7 @@ static int CheckAndAllocCard(struct comedi_device *dev,
for (pr = pci_priv, prev = NULL; pr != NULL; prev = pr, pr = pr->next) {
if (pr->pcidev == pcidev)
- return 0; /* this card is used, look for another */
+ return 0; /* this card is used, look for another */
}
@@ -1048,7 +1104,7 @@ static int pci_dio_attach(struct comedi_device *dev,
struct comedi_subdevice *s;
int ret, subdev, n_subdevices, i, j;
unsigned long iobase;
- struct pci_dev *pcidev;
+ struct pci_dev *pcidev = NULL;
printk("comedi%d: adv_pci_dio: ", dev->minor);
@@ -1058,9 +1114,7 @@ static int pci_dio_attach(struct comedi_device *dev,
return -ENOMEM;
}
- for (pcidev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, NULL);
- pcidev != NULL;
- pcidev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, pcidev)) {
+ for_each_pci_dev(pcidev) {
/* loop through cards supported by this driver */
for (i = 0; i < n_boardtypes; ++i) {
if (boardtypes[i].vendor_id != pcidev->vendor)
@@ -1215,15 +1269,12 @@ static int pci_dio_detach(struct comedi_device *dev)
}
}
- if (this_board->boardid.chans) {
+ if (this_board->boardid.chans)
subdev++;
- }
- for (i = 0; i < MAX_8254_SUBDEVS; i++) {
- if (this_board->s8254[i].chans) {
+ for (i = 0; i < MAX_8254_SUBDEVS; i++)
+ if (this_board->s8254[i].chans)
subdev++;
- }
- }
for (i = 0; i < dev->n_subdevices; i++) {
s = dev->subdevices + i;
@@ -1253,7 +1304,47 @@ static int pci_dio_detach(struct comedi_device *dev)
/*
==============================================================================
*/
-COMEDI_PCI_INITCLEANUP(driver_pci_dio, pci_dio_pci_table);
+static int __devinit driver_pci_dio_pci_probe(struct pci_dev *dev,
+ const struct pci_device_id *ent)
+{
+ return comedi_pci_auto_config(dev, driver_pci_dio.driver_name);
+}
+
+static void __devexit driver_pci_dio_pci_remove(struct pci_dev *dev)
+{
+ comedi_pci_auto_unconfig(dev);
+}
+
+static struct pci_driver driver_pci_dio_pci_driver = {
+ .id_table = pci_dio_pci_table,
+ .probe = &driver_pci_dio_pci_probe,
+ .remove = __devexit_p(&driver_pci_dio_pci_remove)
+};
+
+static int __init driver_pci_dio_init_module(void)
+{
+ int retval;
+
+ retval = comedi_driver_register(&driver_pci_dio);
+ if (retval < 0)
+ return retval;
+
+ driver_pci_dio_pci_driver.name = (char *)driver_pci_dio.driver_name;
+ return pci_register_driver(&driver_pci_dio_pci_driver);
+}
+
+static void __exit driver_pci_dio_cleanup_module(void)
+{
+ pci_unregister_driver(&driver_pci_dio_pci_driver);
+ comedi_driver_unregister(&driver_pci_dio);
+}
+
+module_init(driver_pci_dio_init_module);
+module_exit(driver_pci_dio_cleanup_module);
/*
==============================================================================
*/
+
+MODULE_AUTHOR("Comedi http://www.comedi.org");
+MODULE_DESCRIPTION("Comedi low-level driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/aio_aio12_8.c b/drivers/staging/comedi/drivers/aio_aio12_8.c
index 7a1c636df5b..1728cc013d1 100644
--- a/drivers/staging/comedi/drivers/aio_aio12_8.c
+++ b/drivers/staging/comedi/drivers/aio_aio12_8.c
@@ -227,4 +227,19 @@ static struct comedi_driver driver_aio_aio12_8 = {
.offset = sizeof(struct aio12_8_boardtype),
};
-COMEDI_INITCLEANUP(driver_aio_aio12_8);
+static int __init driver_aio_aio12_8_init_module(void)
+{
+ return comedi_driver_register(&driver_aio_aio12_8);
+}
+
+static void __exit driver_aio_aio12_8_cleanup_module(void)
+{
+ comedi_driver_unregister(&driver_aio_aio12_8);
+}
+
+module_init(driver_aio_aio12_8_init_module);
+module_exit(driver_aio_aio12_8_cleanup_module);
+
+MODULE_AUTHOR("Comedi http://www.comedi.org");
+MODULE_DESCRIPTION("Comedi low-level driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/aio_iiro_16.c b/drivers/staging/comedi/drivers/aio_iiro_16.c
index 4baef9ff932..487599531fe 100644
--- a/drivers/staging/comedi/drivers/aio_iiro_16.c
+++ b/drivers/staging/comedi/drivers/aio_iiro_16.c
@@ -184,4 +184,19 @@ static int aio_iiro_16_dio_insn_bits_read(struct comedi_device *dev,
return 2;
}
-COMEDI_INITCLEANUP(driver_aio_iiro_16);
+static int __init driver_aio_iiro_16_init_module(void)
+{
+ return comedi_driver_register(&driver_aio_iiro_16);
+}
+
+static void __exit driver_aio_iiro_16_cleanup_module(void)
+{
+ comedi_driver_unregister(&driver_aio_iiro_16);
+}
+
+module_init(driver_aio_iiro_16_init_module);
+module_exit(driver_aio_iiro_16_cleanup_module);
+
+MODULE_AUTHOR("Comedi http://www.comedi.org");
+MODULE_DESCRIPTION("Comedi low-level driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/am9513.h b/drivers/staging/comedi/drivers/am9513.h
index 73367d6afff..0bb839e5149 100644
--- a/drivers/staging/comedi/drivers/am9513.h
+++ b/drivers/staging/comedi/drivers/am9513.h
@@ -47,32 +47,32 @@
#ifdef Am9513_8BITBUS
#define Am9513_write_register(reg, val) \
- do{ \
+ do { \
Am9513_output_control(reg); \
Am9513_output_data(val>>8); \
Am9513_output_data(val&0xff); \
- }while (0)
+ } while (0)
#define Am9513_read_register(reg, val) \
- do{ \
+ do { \
Am9513_output_control(reg); \
- val=Am9513_input_data()<<8; \
- val|=Am9513_input_data(); \
- }while (0)
+ val = Am9513_input_data()<<8; \
+ val |= Am9513_input_data(); \
+ } while (0)
#else /* Am9513_16BITBUS */
#define Am9513_write_register(reg, val) \
- do{ \
+ do { \
Am9513_output_control(reg); \
Am9513_output_data(val); \
- }while (0)
+ } while (0)
#define Am9513_read_register(reg, val) \
- do{ \
+ do { \
Am9513_output_control(reg); \
- val=Am9513_input_data(); \
- }while (0)
+ val = Am9513_input_data(); \
+ } while (0)
#endif
diff --git a/drivers/staging/comedi/drivers/amplc_dio200.c b/drivers/staging/comedi/drivers/amplc_dio200.c
index bf27617aa62..93bbe4ec318 100644
--- a/drivers/staging/comedi/drivers/amplc_dio200.c
+++ b/drivers/staging/comedi/drivers/amplc_dio200.c
@@ -494,9 +494,58 @@ static struct comedi_driver driver_amplc_dio200 = {
};
#ifdef CONFIG_COMEDI_PCI
-COMEDI_PCI_INITCLEANUP(driver_amplc_dio200, dio200_pci_table);
+static int __devinit driver_amplc_dio200_pci_probe(struct pci_dev *dev,
+ const struct pci_device_id
+ *ent)
+{
+ return comedi_pci_auto_config(dev, driver_amplc_dio200.driver_name);
+}
+
+static void __devexit driver_amplc_dio200_pci_remove(struct pci_dev *dev)
+{
+ comedi_pci_auto_unconfig(dev);
+}
+
+static struct pci_driver driver_amplc_dio200_pci_driver = {
+ .id_table = dio200_pci_table,
+ .probe = &driver_amplc_dio200_pci_probe,
+ .remove = __devexit_p(&driver_amplc_dio200_pci_remove)
+};
+
+static int __init driver_amplc_dio200_init_module(void)
+{
+ int retval;
+
+ retval = comedi_driver_register(&driver_amplc_dio200);
+ if (retval < 0)
+ return retval;
+
+ driver_amplc_dio200_pci_driver.name =
+ (char *)driver_amplc_dio200.driver_name;
+ return pci_register_driver(&driver_amplc_dio200_pci_driver);
+}
+
+static void __exit driver_amplc_dio200_cleanup_module(void)
+{
+ pci_unregister_driver(&driver_amplc_dio200_pci_driver);
+ comedi_driver_unregister(&driver_amplc_dio200);
+}
+
+module_init(driver_amplc_dio200_init_module);
+module_exit(driver_amplc_dio200_cleanup_module);
#else
-COMEDI_INITCLEANUP(driver_amplc_dio200);
+static int __init driver_amplc_dio200_init_module(void)
+{
+ return comedi_driver_register(&driver_amplc_dio200);
+}
+
+static void __exit driver_amplc_dio200_cleanup_module(void)
+{
+ comedi_driver_unregister(&driver_amplc_dio200);
+}
+
+module_init(driver_amplc_dio200_init_module);
+module_exit(driver_amplc_dio200_cleanup_module);
#endif
/*
@@ -1501,3 +1550,7 @@ static int dio200_detach(struct comedi_device *dev)
return 0;
}
+
+MODULE_AUTHOR("Comedi http://www.comedi.org");
+MODULE_DESCRIPTION("Comedi low-level driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/amplc_pc236.c b/drivers/staging/comedi/drivers/amplc_pc236.c
index a307d68d79c..48246cd50d4 100644
--- a/drivers/staging/comedi/drivers/amplc_pc236.c
+++ b/drivers/staging/comedi/drivers/amplc_pc236.c
@@ -182,9 +182,58 @@ static struct comedi_driver driver_amplc_pc236 = {
};
#ifdef CONFIG_COMEDI_PCI
-COMEDI_PCI_INITCLEANUP(driver_amplc_pc236, pc236_pci_table);
+static int __devinit driver_amplc_pc236_pci_probe(struct pci_dev *dev,
+ const struct pci_device_id
+ *ent)
+{
+ return comedi_pci_auto_config(dev, driver_amplc_pc236.driver_name);
+}
+
+static void __devexit driver_amplc_pc236_pci_remove(struct pci_dev *dev)
+{
+ comedi_pci_auto_unconfig(dev);
+}
+
+static struct pci_driver driver_amplc_pc236_pci_driver = {
+ .id_table = pc236_pci_table,
+ .probe = &driver_amplc_pc236_pci_probe,
+ .remove = __devexit_p(&driver_amplc_pc236_pci_remove)
+};
+
+static int __init driver_amplc_pc236_init_module(void)
+{
+ int retval;
+
+ retval = comedi_driver_register(&driver_amplc_pc236);
+ if (retval < 0)
+ return retval;
+
+ driver_amplc_pc236_pci_driver.name =
+ (char *)driver_amplc_pc236.driver_name;
+ return pci_register_driver(&driver_amplc_pc236_pci_driver);
+}
+
+static void __exit driver_amplc_pc236_cleanup_module(void)
+{
+ pci_unregister_driver(&driver_amplc_pc236_pci_driver);
+ comedi_driver_unregister(&driver_amplc_pc236);
+}
+
+module_init(driver_amplc_pc236_init_module);
+module_exit(driver_amplc_pc236_cleanup_module);
#else
-COMEDI_INITCLEANUP(driver_amplc_pc236);
+static int __init driver_amplc_pc236_init_module(void)
+{
+ return comedi_driver_register(&driver_amplc_pc236);
+}
+
+static void __exit driver_amplc_pc236_cleanup_module(void)
+{
+ comedi_driver_unregister(&driver_amplc_pc236);
+}
+
+module_init(driver_amplc_pc236_init_module);
+module_exit(driver_amplc_pc236_cleanup_module);
#endif
static int pc236_request_region(unsigned minor, unsigned long from,
@@ -664,3 +713,7 @@ static irqreturn_t pc236_interrupt(int irq, void *d)
}
return IRQ_RETVAL(handled);
}
+
+MODULE_AUTHOR("Comedi http://www.comedi.org");
+MODULE_DESCRIPTION("Comedi low-level driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/amplc_pc263.c b/drivers/staging/comedi/drivers/amplc_pc263.c
index 15808e95cea..8a338807909 100644
--- a/drivers/staging/comedi/drivers/amplc_pc263.c
+++ b/drivers/staging/comedi/drivers/amplc_pc263.c
@@ -432,7 +432,60 @@ static int pc263_dio_insn_config(struct comedi_device *dev,
* as necessary.
*/
#ifdef CONFIG_COMEDI_PCI
-COMEDI_PCI_INITCLEANUP(driver_amplc_pc263, pc263_pci_table);
+static int __devinit driver_amplc_pc263_pci_probe(struct pci_dev *dev,
+ const struct pci_device_id
+ *ent)
+{
+ return comedi_pci_auto_config(dev, driver_amplc_pc263.driver_name);
+}
+
+static void __devexit driver_amplc_pc263_pci_remove(struct pci_dev *dev)
+{
+ comedi_pci_auto_unconfig(dev);
+}
+
+static struct pci_driver driver_amplc_pc263_pci_driver = {
+ .id_table = pc263_pci_table,
+ .probe = &driver_amplc_pc263_pci_probe,
+ .remove = __devexit_p(&driver_amplc_pc263_pci_remove)
+};
+
+static int __init driver_amplc_pc263_init_module(void)
+{
+ int retval;
+
+ retval = comedi_driver_register(&driver_amplc_pc263);
+ if (retval < 0)
+ return retval;
+
+ driver_amplc_pc263_pci_driver.name =
+ (char *)driver_amplc_pc263.driver_name;
+ return pci_register_driver(&driver_amplc_pc263_pci_driver);
+}
+
+static void __exit driver_amplc_pc263_cleanup_module(void)
+{
+ pci_unregister_driver(&driver_amplc_pc263_pci_driver);
+ comedi_driver_unregister(&driver_amplc_pc263);
+}
+
+module_init(driver_amplc_pc263_init_module);
+module_exit(driver_amplc_pc263_cleanup_module);
#else
-COMEDI_INITCLEANUP(driver_amplc_pc263);
+static int __init driver_amplc_pc263_init_module(void)
+{
+ return comedi_driver_register(&driver_amplc_pc263);
+}
+
+static void __exit driver_amplc_pc263_cleanup_module(void)
+{
+ comedi_driver_unregister(&driver_amplc_pc263);
+}
+
+module_init(driver_amplc_pc263_init_module);
+module_exit(driver_amplc_pc263_cleanup_module);
#endif
+
+MODULE_AUTHOR("Comedi http://www.comedi.org");
+MODULE_DESCRIPTION("Comedi low-level driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/amplc_pci224.c b/drivers/staging/comedi/drivers/amplc_pci224.c
index c486a878e18..1b5ba1c2725 100644
--- a/drivers/staging/comedi/drivers/amplc_pci224.c
+++ b/drivers/staging/comedi/drivers/amplc_pci224.c
@@ -443,7 +443,45 @@ static struct comedi_driver driver_amplc_pci224 = {
.num_names = ARRAY_SIZE(pci224_boards),
};
-COMEDI_PCI_INITCLEANUP(driver_amplc_pci224, pci224_pci_table);
+static int __devinit driver_amplc_pci224_pci_probe(struct pci_dev *dev,
+ const struct pci_device_id
+ *ent)
+{
+ return comedi_pci_auto_config(dev, driver_amplc_pci224.driver_name);
+}
+
+static void __devexit driver_amplc_pci224_pci_remove(struct pci_dev *dev)
+{
+ comedi_pci_auto_unconfig(dev);
+}
+
+static struct pci_driver driver_amplc_pci224_pci_driver = {
+ .id_table = pci224_pci_table,
+ .probe = &driver_amplc_pci224_pci_probe,
+ .remove = __devexit_p(&driver_amplc_pci224_pci_remove)
+};
+
+static int __init driver_amplc_pci224_init_module(void)
+{
+ int retval;
+
+ retval = comedi_driver_register(&driver_amplc_pci224);
+ if (retval < 0)
+ return retval;
+
+ driver_amplc_pci224_pci_driver.name =
+ (char *)driver_amplc_pci224.driver_name;
+ return pci_register_driver(&driver_amplc_pci224_pci_driver);
+}
+
+static void __exit driver_amplc_pci224_cleanup_module(void)
+{
+ pci_unregister_driver(&driver_amplc_pci224_pci_driver);
+ comedi_driver_unregister(&driver_amplc_pci224);
+}
+
+module_init(driver_amplc_pci224_init_module);
+module_exit(driver_amplc_pci224_cleanup_module);
/*
* Called from the 'insn_write' function to perform a single write.
@@ -1557,3 +1595,7 @@ static int pci224_detach(struct comedi_device *dev)
return 0;
}
+
+MODULE_AUTHOR("Comedi http://www.comedi.org");
+MODULE_DESCRIPTION("Comedi low-level driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/amplc_pci230.c b/drivers/staging/comedi/drivers/amplc_pci230.c
index 7fffd967d47..5d064577b2f 100644
--- a/drivers/staging/comedi/drivers/amplc_pci230.c
+++ b/drivers/staging/comedi/drivers/amplc_pci230.c
@@ -617,7 +617,45 @@ static struct comedi_driver driver_amplc_pci230 = {
.num_names = ARRAY_SIZE(pci230_boards),
};
-COMEDI_PCI_INITCLEANUP(driver_amplc_pci230, pci230_pci_table);
+static int __devinit driver_amplc_pci230_pci_probe(struct pci_dev *dev,
+ const struct pci_device_id
+ *ent)
+{
+ return comedi_pci_auto_config(dev, driver_amplc_pci230.driver_name);
+}
+
+static void __devexit driver_amplc_pci230_pci_remove(struct pci_dev *dev)
+{
+ comedi_pci_auto_unconfig(dev);
+}
+
+static struct pci_driver driver_amplc_pci230_pci_driver = {
+ .id_table = pci230_pci_table,
+ .probe = &driver_amplc_pci230_pci_probe,
+ .remove = __devexit_p(&driver_amplc_pci230_pci_remove)
+};
+
+static int __init driver_amplc_pci230_init_module(void)
+{
+ int retval;
+
+ retval = comedi_driver_register(&driver_amplc_pci230);
+ if (retval < 0)
+ return retval;
+
+ driver_amplc_pci230_pci_driver.name =
+ (char *)driver_amplc_pci230.driver_name;
+ return pci_register_driver(&driver_amplc_pci230_pci_driver);
+}
+
+static void __exit driver_amplc_pci230_cleanup_module(void)
+{
+ pci_unregister_driver(&driver_amplc_pci230_pci_driver);
+ comedi_driver_unregister(&driver_amplc_pci230);
+}
+
+module_init(driver_amplc_pci230_init_module);
+module_exit(driver_amplc_pci230_cleanup_module);
static int pci230_ai_rinsn(struct comedi_device *dev,
struct comedi_subdevice *s, struct comedi_insn *insn,
@@ -726,7 +764,7 @@ static int pci230_attach(struct comedi_device *dev, struct comedi_devconfig *it)
struct comedi_subdevice *s;
unsigned long iobase1, iobase2;
/* PCI230's I/O spaces 1 and 2 respectively. */
- struct pci_dev *pci_dev;
+ struct pci_dev *pci_dev = NULL;
int i = 0, irq_hdl, rc;
printk("comedi%d: amplc_pci230: attach %s %d,%d\n", dev->minor,
@@ -742,9 +780,7 @@ static int pci230_attach(struct comedi_device *dev, struct comedi_devconfig *it)
spin_lock_init(&devpriv->ai_stop_spinlock);
spin_lock_init(&devpriv->ao_stop_spinlock);
/* Find card */
- for (pci_dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, NULL);
- pci_dev != NULL;
- pci_dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, pci_dev)) {
+ for_each_pci_dev(pci_dev) {
if (it->options[0] || it->options[1]) {
/* Match against bus/slot options. */
if (it->options[0] != pci_dev->bus->number ||
@@ -3014,3 +3050,7 @@ static int pci230_ai_cancel(struct comedi_device *dev,
pci230_ai_stop(dev, s);
return 0;
}
+
+MODULE_AUTHOR("Comedi http://www.comedi.org");
+MODULE_DESCRIPTION("Comedi low-level driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/c6xdigio.c b/drivers/staging/comedi/drivers/c6xdigio.c
index fb0d5fa7176..e0ac825ea58 100644
--- a/drivers/staging/comedi/drivers/c6xdigio.c
+++ b/drivers/staging/comedi/drivers/c6xdigio.c
@@ -517,4 +517,19 @@ static int c6xdigio_detach(struct comedi_device *dev)
return 0;
}
-COMEDI_INITCLEANUP(driver_c6xdigio);
+static int __init driver_c6xdigio_init_module(void)
+{
+ return comedi_driver_register(&driver_c6xdigio);
+}
+
+static void __exit driver_c6xdigio_cleanup_module(void)
+{
+ comedi_driver_unregister(&driver_c6xdigio);
+}
+
+module_init(driver_c6xdigio_init_module);
+module_exit(driver_c6xdigio_cleanup_module);
+
+MODULE_AUTHOR("Comedi http://www.comedi.org");
+MODULE_DESCRIPTION("Comedi low-level driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/cb_das16_cs.c b/drivers/staging/comedi/drivers/cb_das16_cs.c
index cfeb11f443e..f8ede1182cc 100644
--- a/drivers/staging/comedi/drivers/cb_das16_cs.c
+++ b/drivers/staging/comedi/drivers/cb_das16_cs.c
@@ -37,7 +37,6 @@ Status: experimental
#include <linux/delay.h>
#include <linux/pci.h>
-#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/cistpl.h>
#include <pcmcia/ds.h>
@@ -171,7 +170,7 @@ static int das16cs_attach(struct comedi_device *dev,
if (!link)
return -EIO;
- dev->iobase = link->io.BasePort1;
+ dev->iobase = link->resource[0]->start;;
printk("I/O base=0x%04lx ", dev->iobase);
printk("fingerprint:\n");
@@ -662,14 +661,6 @@ static void das16cs_pcmcia_detach(struct pcmcia_device *);
less on other parts of the kernel.
*/
-/*
- The dev_info variable is the "key" that is used to match up this
- device driver with appropriate cards, through the card configuration
- database.
-*/
-
-static dev_info_t dev_info = "cb_das16_cs";
-
struct local_info_t {
struct pcmcia_device *link;
int stop;
@@ -719,8 +710,7 @@ static void das16cs_pcmcia_detach(struct pcmcia_device *link)
((struct local_info_t *)link->priv)->stop = 1;
das16cs_pcmcia_release(link);
/* This points to the parent struct local_info_t struct */
- if (link->priv)
- kfree(link->priv);
+ kfree(link->priv);
} /* das16cs_pcmcia_detach */
@@ -737,24 +727,22 @@ static int das16cs_pcmcia_config_loop(struct pcmcia_device *p_dev,
p_dev->conf.Attributes |= CONF_ENABLE_IRQ;
/* IO window settings */
- p_dev->io.NumPorts1 = p_dev->io.NumPorts2 = 0;
+ p_dev->resource[0]->end = p_dev->resource[1]->end = 0;
if ((cfg->io.nwin > 0) || (dflt->io.nwin > 0)) {
cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt->io;
- p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
- if (!(io->flags & CISTPL_IO_8BIT))
- p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_16;
- if (!(io->flags & CISTPL_IO_16BIT))
- p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
- p_dev->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK;
- p_dev->io.BasePort1 = io->win[0].base;
- p_dev->io.NumPorts1 = io->win[0].len;
+ p_dev->io_lines = io->flags & CISTPL_IO_LINES_MASK;
+ p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH;
+ p_dev->resource[0]->flags |=
+ pcmcia_io_cfg_data_width(io->flags);
+ p_dev->resource[0]->start = io->win[0].base;
+ p_dev->resource[0]->end = io->win[0].len;
if (io->nwin > 1) {
- p_dev->io.Attributes2 = p_dev->io.Attributes1;
- p_dev->io.BasePort2 = io->win[1].base;
- p_dev->io.NumPorts2 = io->win[1].len;
+ p_dev->resource[1]->flags = p_dev->resource[0]->flags;
+ p_dev->resource[1]->start = io->win[1].base;
+ p_dev->resource[1]->end = io->win[1].len;
}
/* This reserves IO space but doesn't actually enable it */
- return pcmcia_request_io(p_dev, &p_dev->io);
+ return pcmcia_request_io(p_dev);
}
return 0;
@@ -788,12 +776,10 @@ static void das16cs_pcmcia_config(struct pcmcia_device *link)
dev_info(&link->dev, "index 0x%02x", link->conf.ConfigIndex);
if (link->conf.Attributes & CONF_ENABLE_IRQ)
printk(", irq %u", link->irq);
- if (link->io.NumPorts1)
- printk(", io 0x%04x-0x%04x", link->io.BasePort1,
- link->io.BasePort1 + link->io.NumPorts1 - 1);
- if (link->io.NumPorts2)
- printk(" & 0x%04x-0x%04x", link->io.BasePort2,
- link->io.BasePort2 + link->io.NumPorts2 - 1);
+ if (link->resource[0])
+ printk(", io %pR", link->resource[0]);
+ if (link->resource[1])
+ printk(", io %pR", link->resource[1]);
printk("\n");
return;
@@ -847,7 +833,7 @@ struct pcmcia_driver das16cs_driver = {
.id_table = das16cs_id_table,
.owner = THIS_MODULE,
.drv = {
- .name = dev_info,
+ .name = "cb_das16_cs",
},
};
@@ -881,5 +867,16 @@ void __exit cleanup_module(void)
}
#else
-COMEDI_INITCLEANUP(driver_das16cs);
+static int __init driver_das16cs_init_module(void)
+{
+ return comedi_driver_register(&driver_das16cs);
+}
+
+static void __exit driver_das16cs_cleanup_module(void)
+{
+ comedi_driver_unregister(&driver_das16cs);
+}
+
+module_init(driver_das16cs_init_module);
+module_exit(driver_das16cs_cleanup_module);
#endif /* CONFIG_PCMCIA */
diff --git a/drivers/staging/comedi/drivers/cb_pcidas.c b/drivers/staging/comedi/drivers/cb_pcidas.c
index 434591de37c..6530b6c9d98 100644
--- a/drivers/staging/comedi/drivers/cb_pcidas.c
+++ b/drivers/staging/comedi/drivers/cb_pcidas.c
@@ -533,7 +533,7 @@ static int cb_pcidas_attach(struct comedi_device *dev,
struct comedi_devconfig *it)
{
struct comedi_subdevice *s;
- struct pci_dev *pcidev;
+ struct pci_dev *pcidev = NULL;
int index;
int i;
@@ -550,9 +550,7 @@ static int cb_pcidas_attach(struct comedi_device *dev,
*/
printk("\n");
- for (pcidev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, NULL);
- pcidev != NULL;
- pcidev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, pcidev)) {
+ for_each_pci_dev(pcidev) {
/* is it not a computer boards card? */
if (pcidev->vendor != PCI_VENDOR_ID_CB)
continue;
@@ -1871,4 +1869,44 @@ static int nvram_read(struct comedi_device *dev, unsigned int address,
* A convenient macro that defines init_module() and cleanup_module(),
* as necessary.
*/
-COMEDI_PCI_INITCLEANUP(driver_cb_pcidas, cb_pcidas_pci_table);
+static int __devinit driver_cb_pcidas_pci_probe(struct pci_dev *dev,
+ const struct pci_device_id *ent)
+{
+ return comedi_pci_auto_config(dev, driver_cb_pcidas.driver_name);
+}
+
+static void __devexit driver_cb_pcidas_pci_remove(struct pci_dev *dev)
+{
+ comedi_pci_auto_unconfig(dev);
+}
+
+static struct pci_driver driver_cb_pcidas_pci_driver = {
+ .id_table = cb_pcidas_pci_table,
+ .probe = &driver_cb_pcidas_pci_probe,
+ .remove = __devexit_p(&driver_cb_pcidas_pci_remove)
+};
+
+static int __init driver_cb_pcidas_init_module(void)
+{
+ int retval;
+
+ retval = comedi_driver_register(&driver_cb_pcidas);
+ if (retval < 0)
+ return retval;
+
+ driver_cb_pcidas_pci_driver.name = (char *)driver_cb_pcidas.driver_name;
+ return pci_register_driver(&driver_cb_pcidas_pci_driver);
+}
+
+static void __exit driver_cb_pcidas_cleanup_module(void)
+{
+ pci_unregister_driver(&driver_cb_pcidas_pci_driver);
+ comedi_driver_unregister(&driver_cb_pcidas);
+}
+
+module_init(driver_cb_pcidas_init_module);
+module_exit(driver_cb_pcidas_cleanup_module);
+
+MODULE_AUTHOR("Comedi http://www.comedi.org");
+MODULE_DESCRIPTION("Comedi low-level driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/cb_pcidas64.c b/drivers/staging/comedi/drivers/cb_pcidas64.c
index 79aa286e9bb..53e7015869f 100644
--- a/drivers/staging/comedi/drivers/cb_pcidas64.c
+++ b/drivers/staging/comedi/drivers/cb_pcidas64.c
@@ -1237,7 +1237,43 @@ static unsigned int get_ao_divisor(unsigned int ns, unsigned int flags);
static void load_ao_dma(struct comedi_device *dev,
const struct comedi_cmd *cmd);
-COMEDI_PCI_INITCLEANUP(driver_cb_pcidas, pcidas64_pci_table);
+static int __devinit driver_cb_pcidas_pci_probe(struct pci_dev *dev,
+ const struct pci_device_id *ent)
+{
+ return comedi_pci_auto_config(dev, driver_cb_pcidas.driver_name);
+}
+
+static void __devexit driver_cb_pcidas_pci_remove(struct pci_dev *dev)
+{
+ comedi_pci_auto_unconfig(dev);
+}
+
+static struct pci_driver driver_cb_pcidas_pci_driver = {
+ .id_table = pcidas64_pci_table,
+ .probe = &driver_cb_pcidas_pci_probe,
+ .remove = __devexit_p(&driver_cb_pcidas_pci_remove)
+};
+
+static int __init driver_cb_pcidas_init_module(void)
+{
+ int retval;
+
+ retval = comedi_driver_register(&driver_cb_pcidas);
+ if (retval < 0)
+ return retval;
+
+ driver_cb_pcidas_pci_driver.name = (char *)driver_cb_pcidas.driver_name;
+ return pci_register_driver(&driver_cb_pcidas_pci_driver);
+}
+
+static void __exit driver_cb_pcidas_cleanup_module(void)
+{
+ pci_unregister_driver(&driver_cb_pcidas_pci_driver);
+ comedi_driver_unregister(&driver_cb_pcidas);
+}
+
+module_init(driver_cb_pcidas_init_module);
+module_exit(driver_cb_pcidas_cleanup_module);
static unsigned int ai_range_bits_6xxx(const struct comedi_device *dev,
unsigned int range_index)
@@ -1718,7 +1754,7 @@ static inline void warn_external_queue(struct comedi_device *dev)
*/
static int attach(struct comedi_device *dev, struct comedi_devconfig *it)
{
- struct pci_dev *pcidev;
+ struct pci_dev *pcidev = NULL;
int index;
uint32_t local_range, local_decode;
int retval;
@@ -1735,9 +1771,7 @@ static int attach(struct comedi_device *dev, struct comedi_devconfig *it)
* Probe the device to determine what device in the series it is.
*/
- for (pcidev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, NULL);
- pcidev != NULL;
- pcidev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, pcidev)) {
+ for_each_pci_dev(pcidev) {
/* is it not a computer boards card? */
if (pcidev->vendor != PCI_VENDOR_ID_COMPUTERBOARDS)
continue;
@@ -4303,3 +4337,7 @@ static void i2c_write(struct comedi_device *dev, unsigned int address,
}
i2c_stop(dev);
}
+
+MODULE_AUTHOR("Comedi http://www.comedi.org");
+MODULE_DESCRIPTION("Comedi low-level driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/cb_pcidda.c b/drivers/staging/comedi/drivers/cb_pcidda.c
index c374bee2506..2d35143b8e5 100644
--- a/drivers/staging/comedi/drivers/cb_pcidda.c
+++ b/drivers/staging/comedi/drivers/cb_pcidda.c
@@ -280,7 +280,7 @@ static int cb_pcidda_attach(struct comedi_device *dev,
struct comedi_devconfig *it)
{
struct comedi_subdevice *s;
- struct pci_dev *pcidev;
+ struct pci_dev *pcidev = NULL;
int index;
printk("comedi%d: cb_pcidda: ", dev->minor);
@@ -296,9 +296,7 @@ static int cb_pcidda_attach(struct comedi_device *dev,
*/
printk("\n");
- for (pcidev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, NULL);
- pcidev != NULL;
- pcidev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, pcidev)) {
+ for_each_pci_dev(pcidev) {
if (pcidev->vendor == PCI_VENDOR_ID_CB) {
if (it->options[0] || it->options[1]) {
if (pcidev->bus->number != it->options[0] ||
@@ -856,4 +854,44 @@ static void cb_pcidda_calibrate(struct comedi_device *dev, unsigned int channel,
* A convenient macro that defines init_module() and cleanup_module(),
* as necessary.
*/
-COMEDI_PCI_INITCLEANUP(driver_cb_pcidda, cb_pcidda_pci_table);
+static int __devinit driver_cb_pcidda_pci_probe(struct pci_dev *dev,
+ const struct pci_device_id *ent)
+{
+ return comedi_pci_auto_config(dev, driver_cb_pcidda.driver_name);
+}
+
+static void __devexit driver_cb_pcidda_pci_remove(struct pci_dev *dev)
+{
+ comedi_pci_auto_unconfig(dev);
+}
+
+static struct pci_driver driver_cb_pcidda_pci_driver = {
+ .id_table = cb_pcidda_pci_table,
+ .probe = &driver_cb_pcidda_pci_probe,
+ .remove = __devexit_p(&driver_cb_pcidda_pci_remove)
+};
+
+static int __init driver_cb_pcidda_init_module(void)
+{
+ int retval;
+
+ retval = comedi_driver_register(&driver_cb_pcidda);
+ if (retval < 0)
+ return retval;
+
+ driver_cb_pcidda_pci_driver.name = (char *)driver_cb_pcidda.driver_name;
+ return pci_register_driver(&driver_cb_pcidda_pci_driver);
+}
+
+static void __exit driver_cb_pcidda_cleanup_module(void)
+{
+ pci_unregister_driver(&driver_cb_pcidda_pci_driver);
+ comedi_driver_unregister(&driver_cb_pcidda);
+}
+
+module_init(driver_cb_pcidda_init_module);
+module_exit(driver_cb_pcidda_cleanup_module);
+
+MODULE_AUTHOR("Comedi http://www.comedi.org");
+MODULE_DESCRIPTION("Comedi low-level driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/cb_pcidio.c b/drivers/staging/comedi/drivers/cb_pcidio.c
index 38ccd105fa3..c1693c91a6d 100644
--- a/drivers/staging/comedi/drivers/cb_pcidio.c
+++ b/drivers/staging/comedi/drivers/cb_pcidio.c
@@ -202,9 +202,7 @@ static int pcidio_attach(struct comedi_device *dev, struct comedi_devconfig *it)
* Probe the device to determine what device in the series it is.
*/
- for (pcidev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, NULL);
- pcidev != NULL;
- pcidev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, pcidev)) {
+ for_each_pci_dev(pcidev) {
/* is it not a computer boards card? */
if (pcidev->vendor != PCI_VENDOR_ID_CB)
continue;
@@ -300,4 +298,44 @@ static int pcidio_detach(struct comedi_device *dev)
* A convenient macro that defines init_module() and cleanup_module(),
* as necessary.
*/
-COMEDI_PCI_INITCLEANUP(driver_cb_pcidio, pcidio_pci_table);
+static int __devinit driver_cb_pcidio_pci_probe(struct pci_dev *dev,
+ const struct pci_device_id *ent)
+{
+ return comedi_pci_auto_config(dev, driver_cb_pcidio.driver_name);
+}
+
+static void __devexit driver_cb_pcidio_pci_remove(struct pci_dev *dev)
+{
+ comedi_pci_auto_unconfig(dev);
+}
+
+static struct pci_driver driver_cb_pcidio_pci_driver = {
+ .id_table = pcidio_pci_table,
+ .probe = &driver_cb_pcidio_pci_probe,
+ .remove = __devexit_p(&driver_cb_pcidio_pci_remove)
+};
+
+static int __init driver_cb_pcidio_init_module(void)
+{
+ int retval;
+
+ retval = comedi_driver_register(&driver_cb_pcidio);
+ if (retval < 0)
+ return retval;
+
+ driver_cb_pcidio_pci_driver.name = (char *)driver_cb_pcidio.driver_name;
+ return pci_register_driver(&driver_cb_pcidio_pci_driver);
+}
+
+static void __exit driver_cb_pcidio_cleanup_module(void)
+{
+ pci_unregister_driver(&driver_cb_pcidio_pci_driver);
+ comedi_driver_unregister(&driver_cb_pcidio);
+}
+
+module_init(driver_cb_pcidio_init_module);
+module_exit(driver_cb_pcidio_cleanup_module);
+
+MODULE_AUTHOR("Comedi http://www.comedi.org");
+MODULE_DESCRIPTION("Comedi low-level driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/cb_pcimdas.c b/drivers/staging/comedi/drivers/cb_pcimdas.c
index 49dccbbd713..ced346a7cae 100644
--- a/drivers/staging/comedi/drivers/cb_pcimdas.c
+++ b/drivers/staging/comedi/drivers/cb_pcimdas.c
@@ -210,7 +210,7 @@ static int cb_pcimdas_attach(struct comedi_device *dev,
struct comedi_devconfig *it)
{
struct comedi_subdevice *s;
- struct pci_dev *pcidev;
+ struct pci_dev *pcidev = NULL;
int index;
/* int i; */
@@ -227,9 +227,7 @@ static int cb_pcimdas_attach(struct comedi_device *dev,
*/
printk("\n");
- for (pcidev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, NULL);
- pcidev != NULL;
- pcidev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, pcidev)) {
+ for_each_pci_dev(pcidev) {
/* is it not a computer boards card? */
if (pcidev->vendor != PCI_VENDOR_ID_COMPUTERBOARDS)
continue;
@@ -491,4 +489,46 @@ static int cb_pcimdas_ao_rinsn(struct comedi_device *dev,
* A convenient macro that defines init_module() and cleanup_module(),
* as necessary.
*/
-COMEDI_PCI_INITCLEANUP(driver_cb_pcimdas, cb_pcimdas_pci_table);
+static int __devinit driver_cb_pcimdas_pci_probe(struct pci_dev *dev,
+ const struct pci_device_id
+ *ent)
+{
+ return comedi_pci_auto_config(dev, driver_cb_pcimdas.driver_name);
+}
+
+static void __devexit driver_cb_pcimdas_pci_remove(struct pci_dev *dev)
+{
+ comedi_pci_auto_unconfig(dev);
+}
+
+static struct pci_driver driver_cb_pcimdas_pci_driver = {
+ .id_table = cb_pcimdas_pci_table,
+ .probe = &driver_cb_pcimdas_pci_probe,
+ .remove = __devexit_p(&driver_cb_pcimdas_pci_remove)
+};
+
+static int __init driver_cb_pcimdas_init_module(void)
+{
+ int retval;
+
+ retval = comedi_driver_register(&driver_cb_pcimdas);
+ if (retval < 0)
+ return retval;
+
+ driver_cb_pcimdas_pci_driver.name =
+ (char *)driver_cb_pcimdas.driver_name;
+ return pci_register_driver(&driver_cb_pcimdas_pci_driver);
+}
+
+static void __exit driver_cb_pcimdas_cleanup_module(void)
+{
+ pci_unregister_driver(&driver_cb_pcimdas_pci_driver);
+ comedi_driver_unregister(&driver_cb_pcimdas);
+}
+
+module_init(driver_cb_pcimdas_init_module);
+module_exit(driver_cb_pcimdas_cleanup_module);
+
+MODULE_AUTHOR("Comedi http://www.comedi.org");
+MODULE_DESCRIPTION("Comedi low-level driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/cb_pcimdda.c b/drivers/staging/comedi/drivers/cb_pcimdda.c
index f404ec7723e..8c981a89ab6 100644
--- a/drivers/staging/comedi/drivers/cb_pcimdda.c
+++ b/drivers/staging/comedi/drivers/cb_pcimdda.c
@@ -195,7 +195,45 @@ MODULE_DESCRIPTION("Comedi low-level driver for the Computerboards PCIM-DDA "
"series. Currently only supports PCIM-DDA06-16 (which "
"also happens to be the only board in this series. :) ) ");
MODULE_LICENSE("GPL");
-COMEDI_PCI_INITCLEANUP_NOMODULE(cb_pcimdda_driver, pci_table);
+static int __devinit cb_pcimdda_driver_pci_probe(struct pci_dev *dev,
+ const struct pci_device_id
+ *ent)
+{
+ return comedi_pci_auto_config(dev, cb_pcimdda_driver.driver_name);
+}
+
+static void __devexit cb_pcimdda_driver_pci_remove(struct pci_dev *dev)
+{
+ comedi_pci_auto_unconfig(dev);
+}
+
+static struct pci_driver cb_pcimdda_driver_pci_driver = {
+ .id_table = pci_table,
+ .probe = &cb_pcimdda_driver_pci_probe,
+ .remove = __devexit_p(&cb_pcimdda_driver_pci_remove)
+};
+
+static int __init cb_pcimdda_driver_init_module(void)
+{
+ int retval;
+
+ retval = comedi_driver_register(&cb_pcimdda_driver);
+ if (retval < 0)
+ return retval;
+
+ cb_pcimdda_driver_pci_driver.name =
+ (char *)cb_pcimdda_driver.driver_name;
+ return pci_register_driver(&cb_pcimdda_driver_pci_driver);
+}
+
+static void __exit cb_pcimdda_driver_cleanup_module(void)
+{
+ pci_unregister_driver(&cb_pcimdda_driver_pci_driver);
+ comedi_driver_unregister(&cb_pcimdda_driver);
+}
+
+module_init(cb_pcimdda_driver_init_module);
+module_exit(cb_pcimdda_driver_cleanup_module);
static int ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s,
struct comedi_insn *insn, unsigned int *data);
@@ -426,13 +464,11 @@ static int ao_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
*/
static int probe(struct comedi_device *dev, const struct comedi_devconfig *it)
{
- struct pci_dev *pcidev;
+ struct pci_dev *pcidev = NULL;
int index;
unsigned long registers;
- for (pcidev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, NULL);
- pcidev != NULL;
- pcidev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, pcidev)) {
+ for_each_pci_dev(pcidev) {
/* is it not a computer boards card? */
if (pcidev->vendor != PCI_VENDOR_ID_COMPUTERBOARDS)
continue;
diff --git a/drivers/staging/comedi/drivers/comedi_bond.c b/drivers/staging/comedi/drivers/comedi_bond.c
index 701622280ff..cfcbd9b8f39 100644
--- a/drivers/staging/comedi/drivers/comedi_bond.c
+++ b/drivers/staging/comedi/drivers/comedi_bond.c
@@ -50,43 +50,6 @@ Configuration Options:
within each minor will be concatenated together in the order given here.
*/
-/*
- * The previous block comment is used to automatically generate
- * documentation in Comedi and Comedilib. The fields:
- *
- * Driver: the name of the driver
- * Description: a short phrase describing the driver. Don't list boards.
- * Devices: a full list of the boards that attempt to be supported by
- * the driver. Format is "(manufacturer) board name [comedi name]",
- * where comedi_name is the name that is used to configure the board.
- * See the comment near board_name: in the struct comedi_driver structure
- * below. If (manufacturer) or [comedi name] is missing, the previous
- * value is used.
- * Author: you
- * Updated: date when the _documentation_ was last updated. Use 'date -R'
- * to get a value for this.
- * Status: a one-word description of the status. Valid values are:
- * works - driver works correctly on most boards supported, and
- * passes comedi_test.
- * unknown - unknown. Usually put there by ds.
- * experimental - may not work in any particular release. Author
- * probably wants assistance testing it.
- * bitrotten - driver has not been update in a long time, probably
- * doesn't work, and probably is missing support for significant
- * Comedi interface features.
- * untested - author probably wrote it "blind", and is believed to
- * work, but no confirmation.
- *
- * These headers should be followed by a blank line, and any comments
- * you wish to say about the driver. The comment area is the place
- * to put any known bugs, limitations, unsupported features, supported
- * command triggers, whether or not commands are supported on particular
- * subdevices, etc.
- *
- * Somewhere in the comment should be information about configuration
- * options that are used with comedi_config.
- */
-
#include <linux/string.h>
#include <linux/slab.h>
#include "../comedi.h"
diff --git a/drivers/staging/comedi/drivers/comedi_parport.c b/drivers/staging/comedi/drivers/comedi_parport.c
index fcd7721c553..21d834dd92b 100644
--- a/drivers/staging/comedi/drivers/comedi_parport.c
+++ b/drivers/staging/comedi/drivers/comedi_parport.c
@@ -101,7 +101,18 @@ static struct comedi_driver driver_parport = {
.detach = parport_detach,
};
-COMEDI_INITCLEANUP(driver_parport);
+static int __init driver_parport_init_module(void)
+{
+ return comedi_driver_register(&driver_parport);
+}
+
+static void __exit driver_parport_cleanup_module(void)
+{
+ comedi_driver_unregister(&driver_parport);
+}
+
+module_init(driver_parport_init_module);
+module_exit(driver_parport_cleanup_module);
struct parport_private {
unsigned int a_data;
@@ -396,3 +407,7 @@ static int parport_detach(struct comedi_device *dev)
return 0;
}
+
+MODULE_AUTHOR("Comedi http://www.comedi.org");
+MODULE_DESCRIPTION("Comedi low-level driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/comedi_test.c b/drivers/staging/comedi/drivers/comedi_test.c
index ef83a1a445b..b220b305541 100644
--- a/drivers/staging/comedi/drivers/comedi_test.c
+++ b/drivers/staging/comedi/drivers/comedi_test.c
@@ -107,7 +107,18 @@ static struct comedi_driver driver_waveform = {
.num_names = ARRAY_SIZE(waveform_boards),
};
-COMEDI_INITCLEANUP(driver_waveform);
+static int __init driver_waveform_init_module(void)
+{
+ return comedi_driver_register(&driver_waveform);
+}
+
+static void __exit driver_waveform_cleanup_module(void)
+{
+ comedi_driver_unregister(&driver_waveform);
+}
+
+module_init(driver_waveform_init_module);
+module_exit(driver_waveform_cleanup_module);
static int waveform_ai_cmdtest(struct comedi_device *dev,
struct comedi_subdevice *s,
@@ -549,3 +560,7 @@ static int waveform_ao_insn_write(struct comedi_device *dev,
return insn->n;
}
+
+MODULE_AUTHOR("Comedi http://www.comedi.org");
+MODULE_DESCRIPTION("Comedi low-level driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/contec_pci_dio.c b/drivers/staging/comedi/drivers/contec_pci_dio.c
index 9511814e641..871f109bcfa 100644
--- a/drivers/staging/comedi/drivers/contec_pci_dio.c
+++ b/drivers/staging/comedi/drivers/contec_pci_dio.c
@@ -103,7 +103,7 @@ static int contec_ns_to_timer(unsigned int *ns, int round);
static int contec_attach(struct comedi_device *dev, struct comedi_devconfig *it)
{
- struct pci_dev *pcidev;
+ struct pci_dev *pcidev = NULL;
struct comedi_subdevice *s;
printk("comedi%d: contec: ", dev->minor);
@@ -116,10 +116,7 @@ static int contec_attach(struct comedi_device *dev, struct comedi_devconfig *it)
if (alloc_subdevices(dev, 2) < 0)
return -ENOMEM;
- for (pcidev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, NULL);
- pcidev != NULL;
- pcidev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, pcidev)) {
-
+ for_each_pci_dev(pcidev) {
if (pcidev->vendor == PCI_VENDOR_ID_CONTEC &&
pcidev->device == PCI_DEVICE_ID_PIO1616L) {
if (it->options[0] || it->options[1]) {
@@ -232,4 +229,44 @@ static int contec_di_insn_bits(struct comedi_device *dev,
return 2;
}
-COMEDI_PCI_INITCLEANUP(driver_contec, contec_pci_table);
+static int __devinit driver_contec_pci_probe(struct pci_dev *dev,
+ const struct pci_device_id *ent)
+{
+ return comedi_pci_auto_config(dev, driver_contec.driver_name);
+}
+
+static void __devexit driver_contec_pci_remove(struct pci_dev *dev)
+{
+ comedi_pci_auto_unconfig(dev);
+}
+
+static struct pci_driver driver_contec_pci_driver = {
+ .id_table = contec_pci_table,
+ .probe = &driver_contec_pci_probe,
+ .remove = __devexit_p(&driver_contec_pci_remove)
+};
+
+static int __init driver_contec_init_module(void)
+{
+ int retval;
+
+ retval = comedi_driver_register(&driver_contec);
+ if (retval < 0)
+ return retval;
+
+ driver_contec_pci_driver.name = (char *)driver_contec.driver_name;
+ return pci_register_driver(&driver_contec_pci_driver);
+}
+
+static void __exit driver_contec_cleanup_module(void)
+{
+ pci_unregister_driver(&driver_contec_pci_driver);
+ comedi_driver_unregister(&driver_contec);
+}
+
+module_init(driver_contec_init_module);
+module_exit(driver_contec_cleanup_module);
+
+MODULE_AUTHOR("Comedi http://www.comedi.org");
+MODULE_DESCRIPTION("Comedi low-level driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/daqboard2000.c b/drivers/staging/comedi/drivers/daqboard2000.c
index 078ec273b27..6af6c8323d5 100644
--- a/drivers/staging/comedi/drivers/daqboard2000.c
+++ b/drivers/staging/comedi/drivers/daqboard2000.c
@@ -887,4 +887,46 @@ static int daqboard2000_detach(struct comedi_device *dev)
return 0;
}
-COMEDI_PCI_INITCLEANUP(driver_daqboard2000, daqboard2000_pci_table);
+static int __devinit driver_daqboard2000_pci_probe(struct pci_dev *dev,
+ const struct pci_device_id
+ *ent)
+{
+ return comedi_pci_auto_config(dev, driver_daqboard2000.driver_name);
+}
+
+static void __devexit driver_daqboard2000_pci_remove(struct pci_dev *dev)
+{
+ comedi_pci_auto_unconfig(dev);
+}
+
+static struct pci_driver driver_daqboard2000_pci_driver = {
+ .id_table = daqboard2000_pci_table,
+ .probe = &driver_daqboard2000_pci_probe,
+ .remove = __devexit_p(&driver_daqboard2000_pci_remove)
+};
+
+static int __init driver_daqboard2000_init_module(void)
+{
+ int retval;
+
+ retval = comedi_driver_register(&driver_daqboard2000);
+ if (retval < 0)
+ return retval;
+
+ driver_daqboard2000_pci_driver.name =
+ (char *)driver_daqboard2000.driver_name;
+ return pci_register_driver(&driver_daqboard2000_pci_driver);
+}
+
+static void __exit driver_daqboard2000_cleanup_module(void)
+{
+ pci_unregister_driver(&driver_daqboard2000_pci_driver);
+ comedi_driver_unregister(&driver_daqboard2000);
+}
+
+module_init(driver_daqboard2000_init_module);
+module_exit(driver_daqboard2000_cleanup_module);
+
+MODULE_AUTHOR("Comedi http://www.comedi.org");
+MODULE_DESCRIPTION("Comedi low-level driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/das08.c b/drivers/staging/comedi/drivers/das08.c
index 9cb144f7e70..3141dc80fe7 100644
--- a/drivers/staging/comedi/drivers/das08.c
+++ b/drivers/staging/comedi/drivers/das08.c
@@ -29,11 +29,11 @@
* Description: DAS-08 compatible boards
* Author: Warren Jasper, ds, Frank Hess
* Devices: [Keithley Metrabyte] DAS08 (isa-das08),
- * [ComputerBoards] DAS08 (isa-das08), DAS08-PGM (das08-pgm),
- * DAS08-PGH (das08-pgh), DAS08-PGL (das08-pgl), DAS08-AOH (das08-aoh),
- * DAS08-AOL (das08-aol), DAS08-AOM (das08-aom), DAS08/JR-AO (das08/jr-ao),
- * DAS08/JR-16-AO (das08jr-16-ao), PCI-DAS08 (das08),
- * PC104-DAS08 (pc104-das08), DAS08/JR/16 (das08jr/16)
+ * [ComputerBoards] DAS08 (isa-das08), DAS08-PGM (das08-pgm),
+ * DAS08-PGH (das08-pgh), DAS08-PGL (das08-pgl), DAS08-AOH (das08-aoh),
+ * DAS08-AOL (das08-aol), DAS08-AOM (das08-aom), DAS08/JR-AO (das08/jr-ao),
+ * DAS08/JR-16-AO (das08jr-16-ao), PCI-DAS08 (das08),
+ * PC104-DAS08 (pc104-das08), DAS08/JR/16 (das08jr/16)
* Status: works
*
* This is a rewrite of the das08 and das08jr drivers.
@@ -980,7 +980,7 @@ static int das08_attach(struct comedi_device *dev, struct comedi_devconfig *it)
unsigned long iobase;
#ifdef CONFIG_COMEDI_PCI
unsigned long pci_iobase = 0;
- struct pci_dev *pdev;
+ struct pci_dev *pdev = NULL;
#endif
ret = alloc_private(dev, sizeof(struct das08_private_struct));
@@ -997,9 +997,7 @@ static int das08_attach(struct comedi_device *dev, struct comedi_devconfig *it)
}
printk("\n");
/* find card */
- for (pdev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, NULL);
- pdev != NULL;
- pdev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, pdev)) {
+ for_each_pci_dev(pdev) {
if (pdev->vendor == PCI_VENDOR_ID_COMPUTERBOARDS
&& pdev->device == PCI_DEVICE_ID_PCIDAS08) {
if (it->options[0] || it->options[1]) {
@@ -1082,11 +1080,62 @@ int das08_common_detach(struct comedi_device *dev)
EXPORT_SYMBOL_GPL(das08_common_detach);
#ifdef CONFIG_COMEDI_PCI
-COMEDI_PCI_INITCLEANUP(driver_das08, das08_pci_table);
+static int __devinit driver_das08_pci_probe(struct pci_dev *dev,
+ const struct pci_device_id *ent)
+{
+ return comedi_pci_auto_config(dev, driver_das08.driver_name);
+}
+
+static void __devexit driver_das08_pci_remove(struct pci_dev *dev)
+{
+ comedi_pci_auto_unconfig(dev);
+}
+
+static struct pci_driver driver_das08_pci_driver = {
+ .id_table = das08_pci_table,
+ .probe = &driver_das08_pci_probe,
+ .remove = __devexit_p(&driver_das08_pci_remove)
+};
+
+static int __init driver_das08_init_module(void)
+{
+ int retval;
+
+ retval = comedi_driver_register(&driver_das08);
+ if (retval < 0)
+ return retval;
+
+ driver_das08_pci_driver.name = (char *)driver_das08.driver_name;
+ return pci_register_driver(&driver_das08_pci_driver);
+}
+
+static void __exit driver_das08_cleanup_module(void)
+{
+ pci_unregister_driver(&driver_das08_pci_driver);
+ comedi_driver_unregister(&driver_das08);
+}
+
+module_init(driver_das08_init_module);
+module_exit(driver_das08_cleanup_module);
#else
-COMEDI_INITCLEANUP(driver_das08);
+static int __init driver_das08_init_module(void)
+{
+ return comedi_driver_register(&driver_das08);
+}
+
+static void __exit driver_das08_cleanup_module(void)
+{
+ comedi_driver_unregister(&driver_das08);
+}
+
+module_init(driver_das08_init_module);
+module_exit(driver_das08_cleanup_module);
#endif
#ifdef CONFIG_COMEDI_PCMCIA
EXPORT_SYMBOL_GPL(das08_cs_boards);
#endif
+
+MODULE_AUTHOR("Comedi http://www.comedi.org");
+MODULE_DESCRIPTION("Comedi low-level driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/das08_cs.c b/drivers/staging/comedi/drivers/das08_cs.c
index 8761a6d285d..c6aa52f8dce 100644
--- a/drivers/staging/comedi/drivers/das08_cs.c
+++ b/drivers/staging/comedi/drivers/das08_cs.c
@@ -48,7 +48,6 @@ Command support does not exist, but could be added for this board.
#include "das08.h"
/* pcmcia includes */
-#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/cistpl.h>
#include <pcmcia/ds.h>
@@ -89,7 +88,7 @@ static int das08_cs_attach(struct comedi_device *dev,
printk(" no pcmcia cards found\n");
return -EIO;
}
- iobase = link->io.BasePort1;
+ iobase = link->resource[0]->start;
} else {
printk(" bug! board does not have PCMCIA bustype\n");
return -EINVAL;
@@ -132,14 +131,6 @@ static void das08_pcmcia_detach(struct pcmcia_device *);
less on other parts of the kernel.
*/
-/*
- The dev_info variable is the "key" that is used to match up this
- device driver with appropriate cards, through the card configuration
- database.
-*/
-
-static const dev_info_t dev_info = "pcm-das08";
-
struct local_info_t {
struct pcmcia_device *link;
int stop;
@@ -206,8 +197,7 @@ static void das08_pcmcia_detach(struct pcmcia_device *link)
das08_pcmcia_release(link);
/* This points to the parent struct local_info_t struct */
- if (link->priv)
- kfree(link->priv);
+ kfree(link->priv);
} /* das08_pcmcia_detach */
@@ -225,24 +215,23 @@ static int das08_pcmcia_config_loop(struct pcmcia_device *p_dev,
p_dev->conf.Attributes |= CONF_ENABLE_IRQ;
/* IO window settings */
- p_dev->io.NumPorts1 = p_dev->io.NumPorts2 = 0;
+ p_dev->resource[0]->end = p_dev->resource[1]->end = 0;
if ((cfg->io.nwin > 0) || (dflt->io.nwin > 0)) {
cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt->io;
- p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
- if (!(io->flags & CISTPL_IO_8BIT))
- p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_16;
- if (!(io->flags & CISTPL_IO_16BIT))
- p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
+ p_dev->io_lines = io->flags & CISTPL_IO_LINES_MASK;
+ p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH;
+ p_dev->resource[0]->flags |=
+ pcmcia_io_cfg_data_width(io->flags);
p_dev->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK;
- p_dev->io.BasePort1 = io->win[0].base;
- p_dev->io.NumPorts1 = io->win[0].len;
+ p_dev->resource[0]->start = io->win[0].base;
+ p_dev->resource[0]->end = io->win[0].len;
if (io->nwin > 1) {
- p_dev->io.Attributes2 = p_dev->io.Attributes1;
- p_dev->io.BasePort2 = io->win[1].base;
- p_dev->io.NumPorts2 = io->win[1].len;
+ p_dev->resource[1]->flags = p_dev->resource[0]->flags;
+ p_dev->resource[1]->start = io->win[1].base;
+ p_dev->resource[1]->end = io->win[1].len;
}
/* This reserves IO space but doesn't actually enable it */
- return pcmcia_request_io(p_dev, &p_dev->io);
+ return pcmcia_request_io(p_dev);
}
return 0;
}
@@ -284,12 +273,10 @@ static void das08_pcmcia_config(struct pcmcia_device *link)
dev_info(&link->dev, "index 0x%02x", link->conf.ConfigIndex);
if (link->conf.Attributes & CONF_ENABLE_IRQ)
printk(", irq %u", link->irq);
- if (link->io.NumPorts1)
- printk(", io 0x%04x-0x%04x", link->io.BasePort1,
- link->io.BasePort1 + link->io.NumPorts1 - 1);
- if (link->io.NumPorts2)
- printk(" & 0x%04x-0x%04x", link->io.BasePort2,
- link->io.BasePort2 + link->io.NumPorts2 - 1);
+ if (link->resource[0])
+ printk(", io %pR", link->resource[0]);
+ if (link->resource[1])
+ printk(" & %pR", link->resource[1]);
printk("\n");
return;
@@ -363,7 +350,7 @@ struct pcmcia_driver das08_cs_driver = {
.id_table = das08_cs_id_table,
.owner = THIS_MODULE,
.drv = {
- .name = dev_info,
+ .name = "pcm-das08",
},
};
diff --git a/drivers/staging/comedi/drivers/das16.c b/drivers/staging/comedi/drivers/das16.c
index ccee4f1802d..0af1b465908 100644
--- a/drivers/staging/comedi/drivers/das16.c
+++ b/drivers/staging/comedi/drivers/das16.c
@@ -1717,7 +1717,18 @@ static int das16_detach(struct comedi_device *dev)
return 0;
}
-COMEDI_INITCLEANUP(driver_das16);
+static int __init driver_das16_init_module(void)
+{
+ return comedi_driver_register(&driver_das16);
+}
+
+static void __exit driver_das16_cleanup_module(void)
+{
+ comedi_driver_unregister(&driver_das16);
+}
+
+module_init(driver_das16_init_module);
+module_exit(driver_das16_cleanup_module);
/* utility function that suggests a dma transfer size in bytes */
static unsigned int das16_suggest_transfer_size(struct comedi_device *dev,
@@ -1776,3 +1787,7 @@ static void das16_ai_munge(struct comedi_device *dev,
}
}
+
+MODULE_AUTHOR("Comedi http://www.comedi.org");
+MODULE_DESCRIPTION("Comedi low-level driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/das16m1.c b/drivers/staging/comedi/drivers/das16m1.c
index c403d882743..a5ce3b2abe4 100644
--- a/drivers/staging/comedi/drivers/das16m1.c
+++ b/drivers/staging/comedi/drivers/das16m1.c
@@ -198,7 +198,18 @@ struct das16m1_private_struct {
#define devpriv ((struct das16m1_private_struct *)(dev->private))
#define thisboard ((const struct das16m1_board *)(dev->board_ptr))
-COMEDI_INITCLEANUP(driver_das16m1);
+static int __init driver_das16m1_init_module(void)
+{
+ return comedi_driver_register(&driver_das16m1);
+}
+
+static void __exit driver_das16m1_cleanup_module(void)
+{
+ comedi_driver_unregister(&driver_das16m1);
+}
+
+module_init(driver_das16m1_init_module);
+module_exit(driver_das16m1_cleanup_module);
static inline short munge_sample(short data)
{
@@ -777,3 +788,7 @@ static int das16m1_detach(struct comedi_device *dev)
return 0;
}
+
+MODULE_AUTHOR("Comedi http://www.comedi.org");
+MODULE_DESCRIPTION("Comedi low-level driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/das1800.c b/drivers/staging/comedi/drivers/das1800.c
index de5e82fec87..6ea93f9c0b4 100644
--- a/drivers/staging/comedi/drivers/das1800.c
+++ b/drivers/staging/comedi/drivers/das1800.c
@@ -531,7 +531,18 @@ static struct comedi_driver driver_das1800 = {
* A convenient macro that defines init_module() and cleanup_module(),
* as necessary.
*/
-COMEDI_INITCLEANUP(driver_das1800);
+static int __init driver_das1800_init_module(void)
+{
+ return comedi_driver_register(&driver_das1800);
+}
+
+static void __exit driver_das1800_cleanup_module(void)
+{
+ comedi_driver_unregister(&driver_das1800);
+}
+
+module_init(driver_das1800_init_module);
+module_exit(driver_das1800_cleanup_module);
static int das1800_init_dma(struct comedi_device *dev, unsigned int dma0,
unsigned int dma1)
@@ -1800,3 +1811,7 @@ static unsigned int suggest_transfer_size(struct comedi_cmd *cmd)
return size;
}
+
+MODULE_AUTHOR("Comedi http://www.comedi.org");
+MODULE_DESCRIPTION("Comedi low-level driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/das6402.c b/drivers/staging/comedi/drivers/das6402.c
index a404a183191..6328f5280b6 100644
--- a/drivers/staging/comedi/drivers/das6402.c
+++ b/drivers/staging/comedi/drivers/das6402.c
@@ -109,7 +109,18 @@ static struct comedi_driver driver_das6402 = {
.detach = das6402_detach,
};
-COMEDI_INITCLEANUP(driver_das6402);
+static int __init driver_das6402_init_module(void)
+{
+ return comedi_driver_register(&driver_das6402);
+}
+
+static void __exit driver_das6402_cleanup_module(void)
+{
+ comedi_driver_unregister(&driver_das6402);
+}
+
+module_init(driver_das6402_init_module);
+module_exit(driver_das6402_cleanup_module);
struct das6402_private {
int ai_bytes_to_read;
@@ -360,3 +371,7 @@ static int das6402_attach(struct comedi_device *dev,
return 0;
}
+
+MODULE_AUTHOR("Comedi http://www.comedi.org");
+MODULE_DESCRIPTION("Comedi low-level driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/das800.c b/drivers/staging/comedi/drivers/das800.c
index aadc4971c90..aecaedc5027 100644
--- a/drivers/staging/comedi/drivers/das800.c
+++ b/drivers/staging/comedi/drivers/das800.c
@@ -347,7 +347,18 @@ static int das800_probe(struct comedi_device *dev)
* A convenient macro that defines init_module() and cleanup_module(),
* as necessary.
*/
-COMEDI_INITCLEANUP(driver_das800);
+static int __init driver_das800_init_module(void)
+{
+ return comedi_driver_register(&driver_das800);
+}
+
+static void __exit driver_das800_cleanup_module(void)
+{
+ comedi_driver_unregister(&driver_das800);
+}
+
+module_init(driver_das800_init_module);
+module_exit(driver_das800_cleanup_module);
/* interrupt service routine */
static irqreturn_t das800_interrupt(int irq, void *d)
@@ -905,3 +916,7 @@ static int das800_set_frequency(struct comedi_device *dev)
return 0;
}
+
+MODULE_AUTHOR("Comedi http://www.comedi.org");
+MODULE_DESCRIPTION("Comedi low-level driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/dmm32at.c b/drivers/staging/comedi/drivers/dmm32at.c
index d5cbd515c37..693728e14bd 100644
--- a/drivers/staging/comedi/drivers/dmm32at.c
+++ b/drivers/staging/comedi/drivers/dmm32at.c
@@ -37,43 +37,6 @@ Configuration Options:
comedi_config /dev/comedi0 dmm32at baseaddr,irq
*/
-/*
- * The previous block comment is used to automatically generate
- * documentation in Comedi and Comedilib. The fields:
- *
- * Driver: the name of the driver
- * Description: a short phrase describing the driver. Don't list boards.
- * Devices: a full list of the boards that attempt to be supported by
- * the driver. Format is "(manufacturer) board name [comedi name]",
- * where comedi_name is the name that is used to configure the board.
- * See the comment near board_name: in the struct comedi_driver structure
- * below. If (manufacturer) or [comedi name] is missing, the previous
- * value is used.
- * Author: you
- * Updated: date when the _documentation_ was last updated. Use 'date -R'
- * to get a value for this.
- * Status: a one-word description of the status. Valid values are:
- * works - driver works correctly on most boards supported, and
- * passes comedi_test.
- * unknown - unknown. Usually put there by ds.
- * experimental - may not work in any particular release. Author
- * probably wants assistance testing it.
- * bitrotten - driver has not been update in a long time, probably
- * doesn't work, and probably is missing support for significant
- * Comedi interface features.
- * untested - author probably wrote it "blind", and is believed to
- * work, but no confirmation.
- *
- * These headers should be followed by a blank line, and any comments
- * you wish to say about the driver. The comment area is the place
- * to put any known bugs, limitations, unsupported features, supported
- * command triggers, whether or not commands are supported on particular
- * subdevices, etc.
- *
- * Somewhere in the comment should be information about configuration
- * options that are used with comedi_config.
- */
-
#include <linux/interrupt.h>
#include "../comedidev.h"
#include <linux/ioport.h>
@@ -336,12 +299,14 @@ static int dmm32at_attach(struct comedi_device *dev,
iobase = it->options[0];
irq = it->options[1];
- printk("comedi%d: dmm32at: attaching\n", dev->minor);
- printk("dmm32at: probing at address 0x%04lx, irq %u\n", iobase, irq);
+ printk(KERN_INFO "comedi%d: dmm32at: attaching\n", dev->minor);
+ printk(KERN_DEBUG "dmm32at: probing at address 0x%04lx, irq %u\n",
+ iobase, irq);
/* register address space */
if (!request_region(iobase, DMM32AT_MEMSIZE, thisboard->name)) {
- printk("I/O port conflict\n");
+ printk(KERN_ERR "comedi%d: dmm32at: I/O port conflict\n",
+ dev->minor);
return -EIO;
}
dev->iobase = iobase;
@@ -379,14 +344,15 @@ static int dmm32at_attach(struct comedi_device *dev,
intstat = dmm_inb(dev, DMM32AT_INTCLOCK);
airback = dmm_inb(dev, DMM32AT_AIRBACK);
- printk("dmm32at: lo=0x%02x hi=0x%02x fifostat=0x%02x\n",
+ printk(KERN_DEBUG "dmm32at: lo=0x%02x hi=0x%02x fifostat=0x%02x\n",
ailo, aihi, fifostat);
- printk("dmm32at: aistat=0x%02x intstat=0x%02x airback=0x%02x\n",
+ printk(KERN_DEBUG
+ "dmm32at: aistat=0x%02x intstat=0x%02x airback=0x%02x\n",
aistat, intstat, airback);
if ((ailo != 0x00) || (aihi != 0x1f) || (fifostat != 0x80) ||
(aistat != 0x60 || (intstat != 0x00) || airback != 0x0c)) {
- printk("dmmat32: board detection failed\n");
+ printk(KERN_ERR "dmmat32: board detection failed\n");
return -EIO;
}
@@ -394,7 +360,7 @@ static int dmm32at_attach(struct comedi_device *dev,
if (irq) {
ret = request_irq(irq, dmm32at_isr, 0, thisboard->name, dev);
if (ret < 0) {
- printk("irq conflict\n");
+ printk(KERN_ERR "dmm32at: irq conflict\n");
return ret;
}
dev->irq = irq;
@@ -478,7 +444,7 @@ static int dmm32at_attach(struct comedi_device *dev,
}
/* success */
- printk("comedi%d: dmm32at: attached\n", dev->minor);
+ printk(KERN_INFO "comedi%d: dmm32at: attached\n", dev->minor);
return 1;
@@ -494,7 +460,7 @@ static int dmm32at_attach(struct comedi_device *dev,
*/
static int dmm32at_detach(struct comedi_device *dev)
{
- printk("comedi%d: dmm32at: remove\n", dev->minor);
+ printk(KERN_INFO "comedi%d: dmm32at: remove\n", dev->minor);
if (dev->irq)
free_irq(dev->irq, dev);
if (dev->iobase)
@@ -542,7 +508,7 @@ static int dmm32at_ai_rinsn(struct comedi_device *dev,
break;
}
if (i == 40000) {
- printk("timeout\n");
+ printk(KERN_WARNING "dmm32at: timeout\n");
return -ETIMEDOUT;
}
@@ -557,7 +523,7 @@ static int dmm32at_ai_rinsn(struct comedi_device *dev,
break;
}
if (i == 40000) {
- printk("timeout\n");
+ printk(KERN_WARNING "dmm32at: timeout\n");
return -ETIMEDOUT;
}
@@ -627,7 +593,8 @@ static int dmm32at_ai_cmdtest(struct comedi_device *dev,
if (err)
return 1;
- /* step 2: make sure trigger sources are unique and mutually compatible */
+ /* step 2: make sure trigger sources are unique and mutually
+ * compatible */
/* note that mutual compatibility is not an issue here */
if (cmd->scan_begin_src != TRIG_TIMER &&
@@ -800,7 +767,8 @@ static int dmm32at_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
if (cmd->stop_src == TRIG_COUNT)
devpriv->ai_scans_left = cmd->stop_arg;
else { /* TRIG_NONE */
- devpriv->ai_scans_left = 0xffffffff; /* indicates TRIG_NONE to isr */
+ devpriv->ai_scans_left = 0xffffffff; /* indicates TRIG_NONE to
+ * isr */
}
/* wait for circuit to settle */
@@ -810,7 +778,7 @@ static int dmm32at_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
break;
}
if (i == 40000) {
- printk("timeout\n");
+ printk(KERN_WARNING "dmm32at: timeout\n");
return -ETIMEDOUT;
}
@@ -823,13 +791,13 @@ static int dmm32at_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
dmm_outb(dev, DMM32AT_CONV, 0xff);
}
-/* printk("dmmat32 in command\n"); */
+/* printk("dmmat32 in command\n"); */
-/* for(i=0;i<cmd->chanlist_len;i++) */
-/* comedi_buf_put(s->async,i*100); */
+/* for(i=0;i<cmd->chanlist_len;i++) */
+/* comedi_buf_put(s->async,i*100); */
-/* s->async->events |= COMEDI_CB_EOA; */
-/* comedi_event(dev, s); */
+/* s->async->events |= COMEDI_CB_EOA; */
+/* comedi_event(dev, s); */
return 0;
@@ -937,7 +905,7 @@ static int dmm32at_ao_winsn(struct comedi_device *dev,
break;
}
if (i == 40000) {
- printk("timeout\n");
+ printk(KERN_WARNING "dmm32at: timeout\n");
return -ETIMEDOUT;
}
/* dummy read to update trigger the output */
@@ -1095,4 +1063,19 @@ void dmm32at_setaitimer(struct comedi_device *dev, unsigned int nansec)
* A convenient macro that defines init_module() and cleanup_module(),
* as necessary.
*/
-COMEDI_INITCLEANUP(driver_dmm32at);
+static int __init driver_dmm32at_init_module(void)
+{
+ return comedi_driver_register(&driver_dmm32at);
+}
+
+static void __exit driver_dmm32at_cleanup_module(void)
+{
+ comedi_driver_unregister(&driver_dmm32at);
+}
+
+module_init(driver_dmm32at_init_module);
+module_exit(driver_dmm32at_cleanup_module);
+
+MODULE_AUTHOR("Comedi http://www.comedi.org");
+MODULE_DESCRIPTION("Comedi low-level driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/dt2801.c b/drivers/staging/comedi/drivers/dt2801.c
index 83fb6e56c3e..5cce1b5f448 100644
--- a/drivers/staging/comedi/drivers/dt2801.c
+++ b/drivers/staging/comedi/drivers/dt2801.c
@@ -98,7 +98,18 @@ static struct comedi_driver driver_dt2801 = {
.detach = dt2801_detach,
};
-COMEDI_INITCLEANUP(driver_dt2801);
+static int __init driver_dt2801_init_module(void)
+{
+ return comedi_driver_register(&driver_dt2801);
+}
+
+static void __exit driver_dt2801_cleanup_module(void)
+{
+ comedi_driver_unregister(&driver_dt2801);
+}
+
+module_init(driver_dt2801_init_module);
+module_exit(driver_dt2801_cleanup_module);
#if 0
/* ignore 'defined but not used' warning */
@@ -720,3 +731,7 @@ static int dt2801_dio_insn_config(struct comedi_device *dev,
return 1;
}
+
+MODULE_AUTHOR("Comedi http://www.comedi.org");
+MODULE_DESCRIPTION("Comedi low-level driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/dt2811.c b/drivers/staging/comedi/drivers/dt2811.c
index ea9bfb7fd88..a1664caa1d9 100644
--- a/drivers/staging/comedi/drivers/dt2811.c
+++ b/drivers/staging/comedi/drivers/dt2811.c
@@ -239,7 +239,18 @@ static struct comedi_driver driver_dt2811 = {
.offset = sizeof(struct dt2811_board),
};
-COMEDI_INITCLEANUP(driver_dt2811);
+static int __init driver_dt2811_init_module(void)
+{
+ return comedi_driver_register(&driver_dt2811);
+}
+
+static void __exit driver_dt2811_cleanup_module(void)
+{
+ comedi_driver_unregister(&driver_dt2811);
+}
+
+module_init(driver_dt2811_init_module);
+module_exit(driver_dt2811_cleanup_module);
static int dt2811_ai_insn(struct comedi_device *dev, struct comedi_subdevice *s,
struct comedi_insn *insn, unsigned int *data);
@@ -625,3 +636,7 @@ static int dt2811_do_insn_bits(struct comedi_device *dev,
return 2;
}
+
+MODULE_AUTHOR("Comedi http://www.comedi.org");
+MODULE_DESCRIPTION("Comedi low-level driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/dt2814.c b/drivers/staging/comedi/drivers/dt2814.c
index 16fde066d26..1c6248cf592 100644
--- a/drivers/staging/comedi/drivers/dt2814.c
+++ b/drivers/staging/comedi/drivers/dt2814.c
@@ -70,7 +70,18 @@ static struct comedi_driver driver_dt2814 = {
.detach = dt2814_detach,
};
-COMEDI_INITCLEANUP(driver_dt2814);
+static int __init driver_dt2814_init_module(void)
+{
+ return comedi_driver_register(&driver_dt2814);
+}
+
+static void __exit driver_dt2814_cleanup_module(void)
+{
+ comedi_driver_unregister(&driver_dt2814);
+}
+
+module_init(driver_dt2814_init_module);
+module_exit(driver_dt2814_cleanup_module);
static irqreturn_t dt2814_interrupt(int irq, void *dev);
@@ -387,3 +398,7 @@ static irqreturn_t dt2814_interrupt(int irq, void *d)
comedi_event(dev, s);
return IRQ_HANDLED;
}
+
+MODULE_AUTHOR("Comedi http://www.comedi.org");
+MODULE_DESCRIPTION("Comedi low-level driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/dt2815.c b/drivers/staging/comedi/drivers/dt2815.c
index d1a4f782243..4155da43fd5 100644
--- a/drivers/staging/comedi/drivers/dt2815.c
+++ b/drivers/staging/comedi/drivers/dt2815.c
@@ -82,7 +82,18 @@ static struct comedi_driver driver_dt2815 = {
.detach = dt2815_detach,
};
-COMEDI_INITCLEANUP(driver_dt2815);
+static int __init driver_dt2815_init_module(void)
+{
+ return comedi_driver_register(&driver_dt2815);
+}
+
+static void __exit driver_dt2815_cleanup_module(void)
+{
+ comedi_driver_unregister(&driver_dt2815);
+}
+
+module_init(driver_dt2815_init_module);
+module_exit(driver_dt2815_cleanup_module);
static void dt2815_free_resources(struct comedi_device *dev);
@@ -255,3 +266,7 @@ static int dt2815_detach(struct comedi_device *dev)
return 0;
}
+
+MODULE_AUTHOR("Comedi http://www.comedi.org");
+MODULE_DESCRIPTION("Comedi low-level driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/dt2817.c b/drivers/staging/comedi/drivers/dt2817.c
index 54e0dea0fc5..651fe050d02 100644
--- a/drivers/staging/comedi/drivers/dt2817.c
+++ b/drivers/staging/comedi/drivers/dt2817.c
@@ -57,7 +57,18 @@ static struct comedi_driver driver_dt2817 = {
.detach = dt2817_detach,
};
-COMEDI_INITCLEANUP(driver_dt2817);
+static int __init driver_dt2817_init_module(void)
+{
+ return comedi_driver_register(&driver_dt2817);
+}
+
+static void __exit driver_dt2817_cleanup_module(void)
+{
+ comedi_driver_unregister(&driver_dt2817);
+}
+
+module_init(driver_dt2817_init_module);
+module_exit(driver_dt2817_cleanup_module);
static int dt2817_dio_insn_config(struct comedi_device *dev,
struct comedi_subdevice *s,
@@ -180,3 +191,7 @@ static int dt2817_detach(struct comedi_device *dev)
return 0;
}
+
+MODULE_AUTHOR("Comedi http://www.comedi.org");
+MODULE_DESCRIPTION("Comedi low-level driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/dt282x.c b/drivers/staging/comedi/drivers/dt282x.c
index fd8728c8366..8cea9dca3d7 100644
--- a/drivers/staging/comedi/drivers/dt282x.c
+++ b/drivers/staging/comedi/drivers/dt282x.c
@@ -423,7 +423,18 @@ static struct comedi_driver driver_dt282x = {
.offset = sizeof(struct dt282x_board),
};
-COMEDI_INITCLEANUP(driver_dt282x);
+static int __init driver_dt282x_init_module(void)
+{
+ return comedi_driver_register(&driver_dt282x);
+}
+
+static void __exit driver_dt282x_cleanup_module(void)
+{
+ comedi_driver_unregister(&driver_dt282x);
+}
+
+module_init(driver_dt282x_init_module);
+module_exit(driver_dt282x_cleanup_module);
static void free_resources(struct comedi_device *dev);
static int prep_ai_dma(struct comedi_device *dev, int chan, int size);
@@ -1502,3 +1513,7 @@ static int dt282x_grab_dma(struct comedi_device *dev, int dma1, int dma2)
return 0;
}
+
+MODULE_AUTHOR("Comedi http://www.comedi.org");
+MODULE_DESCRIPTION("Comedi low-level driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/dt3000.c b/drivers/staging/comedi/drivers/dt3000.c
index ca687890fc1..656e7bbf2fc 100644
--- a/drivers/staging/comedi/drivers/dt3000.c
+++ b/drivers/staging/comedi/drivers/dt3000.c
@@ -287,7 +287,43 @@ static struct comedi_driver driver_dt3000 = {
.detach = dt3000_detach,
};
-COMEDI_PCI_INITCLEANUP(driver_dt3000, dt3k_pci_table);
+static int __devinit driver_dt3000_pci_probe(struct pci_dev *dev,
+ const struct pci_device_id *ent)
+{
+ return comedi_pci_auto_config(dev, driver_dt3000.driver_name);
+}
+
+static void __devexit driver_dt3000_pci_remove(struct pci_dev *dev)
+{
+ comedi_pci_auto_unconfig(dev);
+}
+
+static struct pci_driver driver_dt3000_pci_driver = {
+ .id_table = dt3k_pci_table,
+ .probe = &driver_dt3000_pci_probe,
+ .remove = __devexit_p(&driver_dt3000_pci_remove)
+};
+
+static int __init driver_dt3000_init_module(void)
+{
+ int retval;
+
+ retval = comedi_driver_register(&driver_dt3000);
+ if (retval < 0)
+ return retval;
+
+ driver_dt3000_pci_driver.name = (char *)driver_dt3000.driver_name;
+ return pci_register_driver(&driver_dt3000_pci_driver);
+}
+
+static void __exit driver_dt3000_cleanup_module(void)
+{
+ pci_unregister_driver(&driver_dt3000_pci_driver);
+ comedi_driver_unregister(&driver_dt3000);
+}
+
+module_init(driver_dt3000_init_module);
+module_exit(driver_dt3000_cleanup_module);
static void dt3k_ai_empty_fifo(struct comedi_device *dev,
struct comedi_subdevice *s);
@@ -991,3 +1027,7 @@ static struct pci_dev *dt_pci_find_device(struct pci_dev *from, int *board)
*board = -1;
return from;
}
+
+MODULE_AUTHOR("Comedi http://www.comedi.org");
+MODULE_DESCRIPTION("Comedi low-level driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/dt9812.c b/drivers/staging/comedi/drivers/dt9812.c
index 96caae36279..d01d2dc7911 100644
--- a/drivers/staging/comedi/drivers/dt9812.c
+++ b/drivers/staging/comedi/drivers/dt9812.c
@@ -890,8 +890,10 @@ static struct usb_driver dt9812_usb_driver = {
* Comedi functions
*/
-static void dt9812_comedi_open(struct comedi_device *dev)
+static int dt9812_comedi_open(struct comedi_device *dev)
{
+ int result = -ENODEV;
+
down(&devpriv->slot->mutex);
if (devpriv->slot->usb) {
/* We have an attached device, fill in current range info */
@@ -934,8 +936,10 @@ static void dt9812_comedi_open(struct comedi_device *dev)
}
break;
}
+ result = 0;
}
up(&devpriv->slot->mutex);
+ return result;
}
static int dt9812_di_rinsn(struct comedi_device *dev,
diff --git a/drivers/staging/comedi/drivers/fl512.c b/drivers/staging/comedi/drivers/fl512.c
index a10a2b070a2..7f49add60b2 100644
--- a/drivers/staging/comedi/drivers/fl512.c
+++ b/drivers/staging/comedi/drivers/fl512.c
@@ -52,7 +52,18 @@ static struct comedi_driver driver_fl512 = {
.detach = fl512_detach,
};
-COMEDI_INITCLEANUP(driver_fl512);
+static int __init driver_fl512_init_module(void)
+{
+ return comedi_driver_register(&driver_fl512);
+}
+
+static void __exit driver_fl512_cleanup_module(void)
+{
+ comedi_driver_unregister(&driver_fl512);
+}
+
+module_init(driver_fl512_init_module);
+module_exit(driver_fl512_cleanup_module);
static int fl512_ai_insn(struct comedi_device *dev,
struct comedi_subdevice *s, struct comedi_insn *insn,
@@ -205,3 +216,7 @@ static int fl512_detach(struct comedi_device *dev)
printk(KERN_INFO "comedi%d: fl512: dummy i detach\n", dev->minor);
return 0;
}
+
+MODULE_AUTHOR("Comedi http://www.comedi.org");
+MODULE_DESCRIPTION("Comedi low-level driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/gsc_hpdi.c b/drivers/staging/comedi/drivers/gsc_hpdi.c
index 51f12bf45cf..1661b57ca2a 100644
--- a/drivers/staging/comedi/drivers/gsc_hpdi.c
+++ b/drivers/staging/comedi/drivers/gsc_hpdi.c
@@ -311,17 +311,25 @@ struct hpdi_private {
void *plx9080_iobase;
void *hpdi_iobase;
uint32_t *dio_buffer[NUM_DMA_BUFFERS]; /* dma buffers */
- dma_addr_t dio_buffer_phys_addr[NUM_DMA_BUFFERS]; /* physical addresses of dma buffers */
- struct plx_dma_desc *dma_desc; /* array of dma descriptors read by plx9080, allocated to get proper alignment */
- dma_addr_t dma_desc_phys_addr; /* physical address of dma descriptor array */
+ /* physical addresses of dma buffers */
+ dma_addr_t dio_buffer_phys_addr[NUM_DMA_BUFFERS];
+ /* array of dma descriptors read by plx9080, allocated to get proper
+ * alignment */
+ struct plx_dma_desc *dma_desc;
+ /* physical address of dma descriptor array */
+ dma_addr_t dma_desc_phys_addr;
unsigned int num_dma_descriptors;
- uint32_t *desc_dio_buffer[NUM_DMA_DESCRIPTORS]; /* pointer to start of buffers indexed by descriptor */
- volatile unsigned int dma_desc_index; /* index of the dma descriptor that is currently being used */
+ /* pointer to start of buffers indexed by descriptor */
+ uint32_t *desc_dio_buffer[NUM_DMA_DESCRIPTORS];
+ /* index of the dma descriptor that is currently being used */
+ volatile unsigned int dma_desc_index;
unsigned int tx_fifo_size;
unsigned int rx_fifo_size;
volatile unsigned long dio_count;
- volatile uint32_t bits[24]; /* software copies of values written to hpdi registers */
- volatile unsigned int block_size; /* number of bytes at which to generate COMEDI_CB_BLOCK events */
+ /* software copies of values written to hpdi registers */
+ volatile uint32_t bits[24];
+ /* number of bytes at which to generate COMEDI_CB_BLOCK events */
+ volatile unsigned int block_size;
unsigned dio_config_output:1;
};
@@ -337,7 +345,43 @@ static struct comedi_driver driver_hpdi = {
.detach = hpdi_detach,
};
-COMEDI_PCI_INITCLEANUP(driver_hpdi, hpdi_pci_table);
+static int __devinit driver_hpdi_pci_probe(struct pci_dev *dev,
+ const struct pci_device_id *ent)
+{
+ return comedi_pci_auto_config(dev, driver_hpdi.driver_name);
+}
+
+static void __devexit driver_hpdi_pci_remove(struct pci_dev *dev)
+{
+ comedi_pci_auto_unconfig(dev);
+}
+
+static struct pci_driver driver_hpdi_pci_driver = {
+ .id_table = hpdi_pci_table,
+ .probe = &driver_hpdi_pci_probe,
+ .remove = __devexit_p(&driver_hpdi_pci_remove)
+};
+
+static int __init driver_hpdi_init_module(void)
+{
+ int retval;
+
+ retval = comedi_driver_register(&driver_hpdi);
+ if (retval < 0)
+ return retval;
+
+ driver_hpdi_pci_driver.name = (char *)driver_hpdi.driver_name;
+ return pci_register_driver(&driver_hpdi_pci_driver);
+}
+
+static void __exit driver_hpdi_cleanup_module(void)
+{
+ pci_unregister_driver(&driver_hpdi_pci_driver);
+ comedi_driver_unregister(&driver_hpdi);
+}
+
+module_init(driver_hpdi_init_module);
+module_exit(driver_hpdi_cleanup_module);
static int dio_config_insn(struct comedi_device *dev,
struct comedi_subdevice *s, struct comedi_insn *insn,
@@ -570,7 +614,8 @@ static int hpdi_attach(struct comedi_device *dev, struct comedi_devconfig *it)
return -ENOMEM;
pcidev = NULL;
- for (i = 0; i < ARRAY_SIZE(hpdi_boards) && dev->board_ptr == NULL; i++) {
+ for (i = 0; i < ARRAY_SIZE(hpdi_boards) &&
+ dev->board_ptr == NULL; i++) {
do {
pcidev = pci_get_subsys(PCI_VENDOR_ID_PLX,
hpdi_boards[i].device_id,
@@ -618,7 +663,7 @@ static int hpdi_attach(struct comedi_device *dev, struct comedi_devconfig *it)
/* remap, won't work with 2.0 kernels but who cares */
priv(dev)->plx9080_iobase = ioremap(priv(dev)->plx9080_phys_iobase,
pci_resource_len(pcidev,
- PLX9080_BADDRINDEX));
+ PLX9080_BADDRINDEX));
priv(dev)->hpdi_iobase =
ioremap(priv(dev)->hpdi_phys_iobase,
pci_resource_len(pcidev, HPDI_BADDRINDEX));
@@ -769,7 +814,8 @@ static int di_cmd_test(struct comedi_device *dev, struct comedi_subdevice *s,
if (err)
return 1;
- /* step 2: make sure trigger sources are unique and mutually compatible */
+ /* step 2: make sure trigger sources are unique and mutually
+ * compatible */
/* uniqueness check */
if (cmd->stop_src != TRIG_COUNT && cmd->stop_src != TRIG_NONE)
@@ -1066,3 +1112,7 @@ static int hpdi_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
return 0;
}
+
+MODULE_AUTHOR("Comedi http://www.comedi.org");
+MODULE_DESCRIPTION("Comedi low-level driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/icp_multi.c b/drivers/staging/comedi/drivers/icp_multi.c
index fa0e48173bd..809d17efd5b 100644
--- a/drivers/staging/comedi/drivers/icp_multi.c
+++ b/drivers/staging/comedi/drivers/icp_multi.c
@@ -185,7 +185,18 @@ board_name : &boardtypes[0].name,
offset : sizeof(struct boardtype),
};
-COMEDI_INITCLEANUP(driver_icp_multi);
+static int __init driver_icp_multi_init_module(void)
+{
+ return comedi_driver_register(&driver_icp_multi);
+}
+
+static void __exit driver_icp_multi_cleanup_module(void)
+{
+ comedi_driver_unregister(&driver_icp_multi);
+}
+
+module_init(driver_icp_multi_init_module);
+module_exit(driver_icp_multi_cleanup_module);
struct icp_multi_private {
struct pcilst_struct *card; /* pointer to card */
@@ -1125,3 +1136,7 @@ static int icp_multi_detach(struct comedi_device *dev)
return 0;
}
+
+MODULE_AUTHOR("Comedi http://www.comedi.org");
+MODULE_DESCRIPTION("Comedi low-level driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/icp_multi.h b/drivers/staging/comedi/drivers/icp_multi.h
index 2bb96b1d21e..68acefe1688 100644
--- a/drivers/staging/comedi/drivers/icp_multi.h
+++ b/drivers/staging/comedi/drivers/icp_multi.h
@@ -62,16 +62,14 @@ static int pci_card_data(struct pcilst_struct *amcc,
/* build list of Inova cards in this system */
static void pci_card_list_init(unsigned short pci_vendor, char display)
{
- struct pci_dev *pcidev;
+ struct pci_dev *pcidev = NULL;
struct pcilst_struct *inova, *last;
int i;
inova_devices = NULL;
last = NULL;
- for (pcidev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, NULL);
- pcidev != NULL;
- pcidev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, pcidev)) {
+ for_each_pci_dev(pcidev) {
if (pcidev->vendor == pci_vendor) {
inova = kzalloc(sizeof(*inova), GFP_KERNEL);
if (!inova) {
diff --git a/drivers/staging/comedi/drivers/ii_pci20kc.c b/drivers/staging/comedi/drivers/ii_pci20kc.c
index e26c1b88ebe..39a6a850d63 100644
--- a/drivers/staging/comedi/drivers/ii_pci20kc.c
+++ b/drivers/staging/comedi/drivers/ii_pci20kc.c
@@ -640,4 +640,19 @@ static unsigned int pci20xxx_di(struct comedi_device *dev,
}
#endif
-COMEDI_INITCLEANUP(driver_pci20xxx);
+static int __init driver_pci20xxx_init_module(void)
+{
+ return comedi_driver_register(&driver_pci20xxx);
+}
+
+static void __exit driver_pci20xxx_cleanup_module(void)
+{
+ comedi_driver_unregister(&driver_pci20xxx);
+}
+
+module_init(driver_pci20xxx_init_module);
+module_exit(driver_pci20xxx_cleanup_module);
+
+MODULE_AUTHOR("Comedi http://www.comedi.org");
+MODULE_DESCRIPTION("Comedi low-level driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/jr3_pci.c b/drivers/staging/comedi/drivers/jr3_pci.c
index d330b188684..8b383ee959b 100644
--- a/drivers/staging/comedi/drivers/jr3_pci.c
+++ b/drivers/staging/comedi/drivers/jr3_pci.c
@@ -48,6 +48,7 @@ Devices: [JR3] PCI force sensor board (jr3_pci)
#include <linux/jiffies.h>
#include <linux/slab.h>
#include <linux/timer.h>
+#include <linux/kernel.h>
#include "comedi_pci.h"
#include "jr3_pci.h"
@@ -123,12 +124,9 @@ struct jr3_pci_subdev_private {
};
/* Hotplug firmware loading stuff */
-
-typedef int comedi_firmware_callback(struct comedi_device *dev,
- const u8 * data, size_t size);
-
static int comedi_load_firmware(struct comedi_device *dev, char *name,
- comedi_firmware_callback cb)
+ int (*cb)(struct comedi_device *dev,
+ const u8 *data, size_t size))
{
int result = 0;
const struct firmware *fw;
@@ -373,7 +371,7 @@ static int jr3_pci_ai_insn_read(struct comedi_device *dev,
return result;
}
-static void jr3_pci_open(struct comedi_device *dev)
+static int jr3_pci_open(struct comedi_device *dev)
{
int i;
struct jr3_pci_dev_private *devpriv = dev->private;
@@ -388,6 +386,7 @@ static void jr3_pci_open(struct comedi_device *dev)
p->channel_no);
}
}
+ return 0;
}
int read_idm_word(const u8 * data, size_t size, int *pos, unsigned int *val)
@@ -399,14 +398,14 @@ int read_idm_word(const u8 * data, size_t size, int *pos, unsigned int *val)
}
/* Collect value */
*val = 0;
- for (; *pos < size && isxdigit(data[*pos]); (*pos)++) {
- char ch = tolower(data[*pos]);
- result = 1;
- if ('0' <= ch && ch <= '9') {
- *val = (*val << 4) + (ch - '0');
- } else if ('a' <= ch && ch <= 'f') {
- *val = (*val << 4) + (ch - 'a' + 10);
- }
+ for (; *pos < size; (*pos)++) {
+ int value;
+ value = hex_to_bin(data[*pos]);
+ if (value >= 0) {
+ result = 1;
+ *val = (*val << 4) + value;
+ } else
+ break;
}
}
return result;
@@ -986,4 +985,44 @@ static int jr3_pci_detach(struct comedi_device *dev)
return 0;
}
-COMEDI_PCI_INITCLEANUP(driver_jr3_pci, jr3_pci_pci_table);
+static int __devinit driver_jr3_pci_pci_probe(struct pci_dev *dev,
+ const struct pci_device_id *ent)
+{
+ return comedi_pci_auto_config(dev, driver_jr3_pci.driver_name);
+}
+
+static void __devexit driver_jr3_pci_pci_remove(struct pci_dev *dev)
+{
+ comedi_pci_auto_unconfig(dev);
+}
+
+static struct pci_driver driver_jr3_pci_pci_driver = {
+ .id_table = jr3_pci_pci_table,
+ .probe = &driver_jr3_pci_pci_probe,
+ .remove = __devexit_p(&driver_jr3_pci_pci_remove)
+};
+
+static int __init driver_jr3_pci_init_module(void)
+{
+ int retval;
+
+ retval = comedi_driver_register(&driver_jr3_pci);
+ if (retval < 0)
+ return retval;
+
+ driver_jr3_pci_pci_driver.name = (char *)driver_jr3_pci.driver_name;
+ return pci_register_driver(&driver_jr3_pci_pci_driver);
+}
+
+static void __exit driver_jr3_pci_cleanup_module(void)
+{
+ pci_unregister_driver(&driver_jr3_pci_pci_driver);
+ comedi_driver_unregister(&driver_jr3_pci);
+}
+
+module_init(driver_jr3_pci_init_module);
+module_exit(driver_jr3_pci_cleanup_module);
+
+MODULE_AUTHOR("Comedi http://www.comedi.org");
+MODULE_DESCRIPTION("Comedi low-level driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/ke_counter.c b/drivers/staging/comedi/drivers/ke_counter.c
index 73b0445e310..286093bca3f 100644
--- a/drivers/staging/comedi/drivers/ke_counter.c
+++ b/drivers/staging/comedi/drivers/ke_counter.c
@@ -96,7 +96,43 @@ static struct comedi_driver cnt_driver = {
.detach = cnt_detach,
};
-COMEDI_PCI_INITCLEANUP(cnt_driver, cnt_pci_table);
+static int __devinit cnt_driver_pci_probe(struct pci_dev *dev,
+ const struct pci_device_id *ent)
+{
+ return comedi_pci_auto_config(dev, cnt_driver.driver_name);
+}
+
+static void __devexit cnt_driver_pci_remove(struct pci_dev *dev)
+{
+ comedi_pci_auto_unconfig(dev);
+}
+
+static struct pci_driver cnt_driver_pci_driver = {
+ .id_table = cnt_pci_table,
+ .probe = &cnt_driver_pci_probe,
+ .remove = __devexit_p(&cnt_driver_pci_remove)
+};
+
+static int __init cnt_driver_init_module(void)
+{
+ int retval;
+
+ retval = comedi_driver_register(&cnt_driver);
+ if (retval < 0)
+ return retval;
+
+ cnt_driver_pci_driver.name = (char *)cnt_driver.driver_name;
+ return pci_register_driver(&cnt_driver_pci_driver);
+}
+
+static void __exit cnt_driver_cleanup_module(void)
+{
+ pci_unregister_driver(&cnt_driver_pci_driver);
+ comedi_driver_unregister(&cnt_driver);
+}
+
+module_init(cnt_driver_init_module);
+module_exit(cnt_driver_cleanup_module);
/*-- counter write ----------------------------------------------------------*/
@@ -152,7 +188,7 @@ static int cnt_rinsn(struct comedi_device *dev,
static int cnt_attach(struct comedi_device *dev, struct comedi_devconfig *it)
{
struct comedi_subdevice *subdevice;
- struct pci_dev *pci_device;
+ struct pci_dev *pci_device = NULL;
struct cnt_board_struct *board;
unsigned long io_base;
int error, i;
@@ -163,9 +199,7 @@ static int cnt_attach(struct comedi_device *dev, struct comedi_devconfig *it)
return error;
/* Probe the device to determine what device in the series it is. */
- for (pci_device = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, NULL);
- pci_device != NULL;
- pci_device = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, pci_device)) {
+ for_each_pci_dev(pci_device) {
if (pci_device->vendor == PCI_VENDOR_ID_KOLTER) {
for (i = 0; i < cnt_board_nbr; i++) {
if (cnt_boards[i].device_id ==
@@ -259,3 +293,7 @@ static int cnt_detach(struct comedi_device *dev)
dev->minor);
return 0;
}
+
+MODULE_AUTHOR("Comedi http://www.comedi.org");
+MODULE_DESCRIPTION("Comedi low-level driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/me4000.c b/drivers/staging/comedi/drivers/me4000.c
index 8b9fa0f9f1f..14713849564 100644
--- a/drivers/staging/comedi/drivers/me4000.c
+++ b/drivers/staging/comedi/drivers/me4000.c
@@ -91,22 +91,22 @@ static DEFINE_PCI_DEVICE_TABLE(me4000_pci_table) = {
MODULE_DEVICE_TABLE(pci, me4000_pci_table);
static const struct me4000_board me4000_boards[] = {
- {"ME-4650", 0x4650, {0, 0}, {16, 0, 0, 0}, {4}, {0}},
+ {"ME-4650", 0x4650, {0, 0}, {16, 0, 0, 0}, {4}, {0} },
- {"ME-4660", 0x4660, {0, 0}, {32, 0, 16, 0}, {4}, {3}},
- {"ME-4660i", 0x4661, {0, 0}, {32, 0, 16, 0}, {4}, {3}},
- {"ME-4660s", 0x4662, {0, 0}, {32, 8, 16, 0}, {4}, {3}},
- {"ME-4660is", 0x4663, {0, 0}, {32, 8, 16, 0}, {4}, {3}},
+ {"ME-4660", 0x4660, {0, 0}, {32, 0, 16, 0}, {4}, {3} },
+ {"ME-4660i", 0x4661, {0, 0}, {32, 0, 16, 0}, {4}, {3} },
+ {"ME-4660s", 0x4662, {0, 0}, {32, 8, 16, 0}, {4}, {3} },
+ {"ME-4660is", 0x4663, {0, 0}, {32, 8, 16, 0}, {4}, {3} },
- {"ME-4670", 0x4670, {4, 0}, {32, 0, 16, 1}, {4}, {3}},
- {"ME-4670i", 0x4671, {4, 0}, {32, 0, 16, 1}, {4}, {3}},
- {"ME-4670s", 0x4672, {4, 0}, {32, 8, 16, 1}, {4}, {3}},
- {"ME-4670is", 0x4673, {4, 0}, {32, 8, 16, 1}, {4}, {3}},
+ {"ME-4670", 0x4670, {4, 0}, {32, 0, 16, 1}, {4}, {3} },
+ {"ME-4670i", 0x4671, {4, 0}, {32, 0, 16, 1}, {4}, {3} },
+ {"ME-4670s", 0x4672, {4, 0}, {32, 8, 16, 1}, {4}, {3} },
+ {"ME-4670is", 0x4673, {4, 0}, {32, 8, 16, 1}, {4}, {3} },
- {"ME-4680", 0x4680, {4, 4}, {32, 0, 16, 1}, {4}, {3}},
- {"ME-4680i", 0x4681, {4, 4}, {32, 0, 16, 1}, {4}, {3}},
- {"ME-4680s", 0x4682, {4, 4}, {32, 8, 16, 1}, {4}, {3}},
- {"ME-4680is", 0x4683, {4, 4}, {32, 8, 16, 1}, {4}, {3}},
+ {"ME-4680", 0x4680, {4, 4}, {32, 0, 16, 1}, {4}, {3} },
+ {"ME-4680i", 0x4681, {4, 4}, {32, 0, 16, 1}, {4}, {3} },
+ {"ME-4680s", 0x4682, {4, 4}, {32, 8, 16, 1}, {4}, {3} },
+ {"ME-4680is", 0x4683, {4, 4}, {32, 8, 16, 1}, {4}, {3} },
{0},
};
@@ -120,10 +120,10 @@ static int me4000_attach(struct comedi_device *dev,
struct comedi_devconfig *it);
static int me4000_detach(struct comedi_device *dev);
static struct comedi_driver driver_me4000 = {
-driver_name:"me4000",
-module:THIS_MODULE,
-attach:me4000_attach,
-detach:me4000_detach,
+driver_name: "me4000",
+module : THIS_MODULE,
+attach : me4000_attach,
+detach : me4000_detach,
};
/*-----------------------------------------------------------------------------
@@ -302,8 +302,8 @@ static int me4000_attach(struct comedi_device *dev, struct comedi_devconfig *it)
if (request_irq(info->irq, me4000_ai_isr,
IRQF_SHARED, "ME-4000", dev)) {
printk
- ("comedi%d: me4000: me4000_attach(): Unable to allocate irq\n",
- dev->minor);
+ ("comedi%d: me4000: me4000_attach(): "
+ "Unable to allocate irq\n", dev->minor);
} else {
dev->read_subdev = s;
s->subdev_flags |= SDF_CMD_READ;
@@ -313,8 +313,8 @@ static int me4000_attach(struct comedi_device *dev, struct comedi_devconfig *it)
}
} else {
printk(KERN_WARNING
- "comedi%d: me4000: me4000_attach(): No interrupt available\n",
- dev->minor);
+ "comedi%d: me4000: me4000_attach(): "
+ "No interrupt available\n", dev->minor);
}
} else {
s->type = COMEDI_SUBD_UNUSED;
@@ -389,7 +389,7 @@ static int me4000_attach(struct comedi_device *dev, struct comedi_devconfig *it)
static int me4000_probe(struct comedi_device *dev, struct comedi_devconfig *it)
{
- struct pci_dev *pci_device;
+ struct pci_dev *pci_device = NULL;
int result, i;
struct me4000_board *board;
@@ -402,17 +402,21 @@ static int me4000_probe(struct comedi_device *dev, struct comedi_devconfig *it)
/*
* Probe the device to determine what device in the series it is.
*/
- for (pci_device = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, NULL);
- pci_device != NULL;
- pci_device = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, pci_device)) {
+ for_each_pci_dev(pci_device) {
if (pci_device->vendor == PCI_VENDOR_ID_MEILHAUS) {
for (i = 0; i < ME4000_BOARD_VERSIONS; i++) {
if (me4000_boards[i].device_id ==
pci_device->device) {
- /* Was a particular bus/slot requested? */
+ /*
+ * Was a particular
+ * bus/slot requested?
+ */
if ((it->options[0] != 0)
|| (it->options[1] != 0)) {
- /* Are we on the wrong bus/slot? */
+ /*
+ * Are we on the wrong
+ * bus/slot?
+ */
if (pci_device->bus->number !=
it->options[0]
||
@@ -433,14 +437,16 @@ static int me4000_probe(struct comedi_device *dev, struct comedi_devconfig *it)
}
printk(KERN_ERR
- "comedi%d: me4000: me4000_probe(): No supported board found (req. bus/slot : %d/%d)\n",
+ "comedi%d: me4000: me4000_probe(): "
+ "No supported board found (req. bus/slot : %d/%d)\n",
dev->minor, it->options[0], it->options[1]);
return -ENODEV;
found:
printk(KERN_INFO
- "comedi%d: me4000: me4000_probe(): Found %s at PCI bus %d, slot %d\n",
+ "comedi%d: me4000: me4000_probe(): "
+ "Found %s at PCI bus %d, slot %d\n",
dev->minor, me4000_boards[i].name, pci_device->bus->number,
PCI_SLOT(pci_device->devfn));
@@ -451,8 +457,8 @@ found:
result = comedi_pci_enable(pci_device, dev->board_name);
if (result) {
printk(KERN_ERR
- "comedi%d: me4000: me4000_probe(): Cannot enable PCI device and request I/O regions\n",
- dev->minor);
+ "comedi%d: me4000: me4000_probe(): Cannot enable PCI "
+ "device and request I/O regions\n", dev->minor);
return result;
}
@@ -460,16 +466,16 @@ found:
result = get_registers(dev, pci_device);
if (result) {
printk(KERN_ERR
- "comedi%d: me4000: me4000_probe(): Cannot get registers\n",
- dev->minor);
+ "comedi%d: me4000: me4000_probe(): "
+ "Cannot get registers\n", dev->minor);
return result;
}
/* Initialize board info */
result = init_board_info(dev, pci_device);
if (result) {
printk(KERN_ERR
- "comedi%d: me4000: me4000_probe(): Cannot init baord info\n",
- dev->minor);
+ "comedi%d: me4000: me4000_probe(): "
+ "Cannot init baord info\n", dev->minor);
return result;
}
@@ -477,8 +483,8 @@ found:
result = init_ao_context(dev);
if (result) {
printk(KERN_ERR
- "comedi%d: me4000: me4000_probe(): Cannot init ao context\n",
- dev->minor);
+ "comedi%d: me4000: me4000_probe(): "
+ "Cannot init ao context\n", dev->minor);
return result;
}
@@ -486,8 +492,8 @@ found:
result = init_ai_context(dev);
if (result) {
printk(KERN_ERR
- "comedi%d: me4000: me4000_probe(): Cannot init ai context\n",
- dev->minor);
+ "comedi%d: me4000: me4000_probe(): "
+ "Cannot init ai context\n", dev->minor);
return result;
}
@@ -495,8 +501,8 @@ found:
result = init_dio_context(dev);
if (result) {
printk(KERN_ERR
- "comedi%d: me4000: me4000_probe(): Cannot init dio context\n",
- dev->minor);
+ "comedi%d: me4000: me4000_probe(): "
+ "Cannot init dio context\n", dev->minor);
return result;
}
@@ -504,8 +510,8 @@ found:
result = init_cnt_context(dev);
if (result) {
printk(KERN_ERR
- "comedi%d: me4000: me4000_probe(): Cannot init cnt context\n",
- dev->minor);
+ "comedi%d: me4000: me4000_probe(): "
+ "Cannot init cnt context\n", dev->minor);
return result;
}
@@ -513,8 +519,8 @@ found:
result = xilinx_download(dev);
if (result) {
printk(KERN_ERR
- "comedi%d: me4000: me4000_probe(): Can't download firmware\n",
- dev->minor);
+ "comedi%d: me4000: me4000_probe(): "
+ "Can't download firmware\n", dev->minor);
return result;
}
@@ -535,24 +541,24 @@ static int get_registers(struct comedi_device *dev, struct pci_dev *pci_dev_p)
CALL_PDEBUG("In get_registers()\n");
- /*--------------------------- plx regbase ---------------------------------*/
+ /*--------------------------- plx regbase -------------------------------*/
info->plx_regbase = pci_resource_start(pci_dev_p, 1);
if (info->plx_regbase == 0) {
printk(KERN_ERR
- "comedi%d: me4000: get_registers(): PCI base address 1 is not available\n",
- dev->minor);
+ "comedi%d: me4000: get_registers(): "
+ "PCI base address 1 is not available\n", dev->minor);
return -ENODEV;
}
info->plx_regbase_size = pci_resource_len(pci_dev_p, 1);
- /*--------------------------- me4000 regbase ------------------------------*/
+ /*--------------------------- me4000 regbase ----------------------------*/
info->me4000_regbase = pci_resource_start(pci_dev_p, 2);
if (info->me4000_regbase == 0) {
printk(KERN_ERR
- "comedi%d: me4000: get_registers(): PCI base address 2 is not available\n",
- dev->minor);
+ "comedi%d: me4000: get_registers(): "
+ "PCI base address 2 is not available\n", dev->minor);
return -ENODEV;
}
info->me4000_regbase_size = pci_resource_len(pci_dev_p, 2);
@@ -562,19 +568,19 @@ static int get_registers(struct comedi_device *dev, struct pci_dev *pci_dev_p)
info->timer_regbase = pci_resource_start(pci_dev_p, 3);
if (info->timer_regbase == 0) {
printk(KERN_ERR
- "comedi%d: me4000: get_registers(): PCI base address 3 is not available\n",
- dev->minor);
+ "comedi%d: me4000: get_registers(): "
+ "PCI base address 3 is not available\n", dev->minor);
return -ENODEV;
}
info->timer_regbase_size = pci_resource_len(pci_dev_p, 3);
- /*--------------------------- program regbase ------------------------------*/
+ /*--------------------------- program regbase ----------------------------*/
info->program_regbase = pci_resource_start(pci_dev_p, 5);
if (info->program_regbase == 0) {
printk(KERN_ERR
- "comedi%d: me4000: get_registers(): PCI base address 5 is not available\n",
- dev->minor);
+ "comedi%d: me4000: get_registers(): "
+ "PCI base address 5 is not available\n", dev->minor);
return -ENODEV;
}
info->program_regbase_size = pci_resource_len(pci_dev_p, 5);
@@ -800,8 +806,8 @@ static int xilinx_download(struct comedi_device *dev)
udelay(20);
if (!(inl(info->plx_regbase + PLX_INTCSR) & 0x20)) {
printk(KERN_ERR
- "comedi%d: me4000: xilinx_download(): Can't init Xilinx\n",
- dev->minor);
+ "comedi%d: me4000: xilinx_download(): "
+ "Can't init Xilinx\n", dev->minor);
return -EIO;
}
@@ -810,8 +816,8 @@ static int xilinx_download(struct comedi_device *dev)
value &= ~0x100;
outl(value, info->plx_regbase + PLX_ICR);
if (FIRMWARE_NOT_AVAILABLE) {
- comedi_error(dev,
- "xilinx firmware unavailable due to licensing, aborting");
+ comedi_error(dev, "xilinx firmware unavailable "
+ "due to licensing, aborting");
return -EIO;
} else {
/* Download Xilinx firmware */
@@ -826,7 +832,8 @@ static int xilinx_download(struct comedi_device *dev)
/* Check if BUSY flag is low */
if (inl(info->plx_regbase + PLX_ICR) & 0x20) {
printk(KERN_ERR
- "comedi%d: me4000: xilinx_download(): Xilinx is still busy (idx = %d)\n",
+ "comedi%d: me4000: xilinx_download(): "
+ "Xilinx is still busy (idx = %d)\n",
dev->minor, idx);
return -EIO;
}
@@ -837,11 +844,11 @@ static int xilinx_download(struct comedi_device *dev)
if (inl(info->plx_regbase + PLX_ICR) & 0x4) {
} else {
printk(KERN_ERR
- "comedi%d: me4000: xilinx_download(): DONE flag is not set\n",
- dev->minor);
+ "comedi%d: me4000: xilinx_download(): "
+ "DONE flag is not set\n", dev->minor);
printk(KERN_ERR
- "comedi%d: me4000: xilinx_download(): Download not successful\n",
- dev->minor);
+ "comedi%d: me4000: xilinx_download(): "
+ "Download not successful\n", dev->minor);
return -EIO;
}
@@ -902,7 +909,10 @@ static int reset_board(struct comedi_device *dev)
me4000_outl(dev, ME4000_AO_DEMUX_ADJUST_VALUE,
info->me4000_regbase + ME4000_AO_DEMUX_ADJUST_REG);
- /* Set digital I/O direction for port 0 to output on isolated versions */
+ /*
+ * Set digital I/O direction for port 0
+ * to output on isolated versions
+ */
if (!(me4000_inl(dev, info->me4000_regbase + ME4000_DIO_DIR_REG) & 0x1)) {
me4000_outl(dev, 0x1,
info->me4000_regbase + ME4000_DIO_CTRL_REG);
@@ -950,8 +960,8 @@ static int me4000_ai_insn_read(struct comedi_device *dev,
return 0;
} else if (insn->n > 1) {
printk(KERN_ERR
- "comedi%d: me4000: me4000_ai_insn_read(): Invalid instruction length %d\n",
- dev->minor, insn->n);
+ "comedi%d: me4000: me4000_ai_insn_read(): "
+ "Invalid instruction length %d\n", dev->minor, insn->n);
return -EINVAL;
}
@@ -970,8 +980,8 @@ static int me4000_ai_insn_read(struct comedi_device *dev,
break;
default:
printk(KERN_ERR
- "comedi%d: me4000: me4000_ai_insn_read(): Invalid range specified\n",
- dev->minor);
+ "comedi%d: me4000: me4000_ai_insn_read(): "
+ "Invalid range specified\n", dev->minor);
return -EINVAL;
}
@@ -980,8 +990,8 @@ static int me4000_ai_insn_read(struct comedi_device *dev,
case AREF_COMMON:
if (chan >= thisboard->ai.count) {
printk(KERN_ERR
- "comedi%d: me4000: me4000_ai_insn_read(): Analog input is not available\n",
- dev->minor);
+ "comedi%d: me4000: me4000_ai_insn_read(): "
+ "Analog input is not available\n", dev->minor);
return -EINVAL;
}
entry |= ME4000_AI_LIST_INPUT_SINGLE_ENDED | chan;
@@ -990,23 +1000,24 @@ static int me4000_ai_insn_read(struct comedi_device *dev,
case AREF_DIFF:
if (rang == 0 || rang == 1) {
printk(KERN_ERR
- "comedi%d: me4000: me4000_ai_insn_read(): Range must be bipolar when aref = diff\n",
+ "comedi%d: me4000: me4000_ai_insn_read(): "
+ "Range must be bipolar when aref = diff\n",
dev->minor);
return -EINVAL;
}
if (chan >= thisboard->ai.diff_count) {
printk(KERN_ERR
- "comedi%d: me4000: me4000_ai_insn_read(): Analog input is not available\n",
- dev->minor);
+ "comedi%d: me4000: me4000_ai_insn_read(): "
+ "Analog input is not available\n", dev->minor);
return -EINVAL;
}
entry |= ME4000_AI_LIST_INPUT_DIFFERENTIAL | chan;
break;
default:
printk(KERN_ERR
- "comedi%d: me4000: me4000_ai_insn_read(): Invalid aref specified\n",
- dev->minor);
+ "comedi%d: me4000: me4000_ai_insn_read(): "
+ "Invalid aref specified\n", dev->minor);
return -EINVAL;
}
@@ -1045,8 +1056,8 @@ static int me4000_ai_insn_read(struct comedi_device *dev,
(me4000_inl(dev, info->ai_context.status_reg) &
ME4000_AI_STATUS_BIT_EF_DATA)) {
printk(KERN_ERR
- "comedi%d: me4000: me4000_ai_insn_read(): Value not available after wait\n",
- dev->minor);
+ "comedi%d: me4000: me4000_ai_insn_read(): "
+ "Value not available after wait\n", dev->minor);
return -EIO;
}
@@ -1086,24 +1097,24 @@ static int ai_check_chanlist(struct comedi_device *dev,
/* Check whether a channel list is available */
if (!cmd->chanlist_len) {
printk(KERN_ERR
- "comedi%d: me4000: ai_check_chanlist(): No channel list available\n",
- dev->minor);
+ "comedi%d: me4000: ai_check_chanlist(): "
+ "No channel list available\n", dev->minor);
return -EINVAL;
}
/* Check the channel list size */
if (cmd->chanlist_len > ME4000_AI_CHANNEL_LIST_COUNT) {
printk(KERN_ERR
- "comedi%d: me4000: ai_check_chanlist(): Channel list is to large\n",
- dev->minor);
+ "comedi%d: me4000: ai_check_chanlist(): "
+ "Channel list is to large\n", dev->minor);
return -EINVAL;
}
/* Check the pointer */
if (!cmd->chanlist) {
printk(KERN_ERR
- "comedi%d: me4000: ai_check_chanlist(): NULL pointer to channel list\n",
- dev->minor);
+ "comedi%d: me4000: ai_check_chanlist(): "
+ "NULL pointer to channel list\n", dev->minor);
return -EFAULT;
}
@@ -1112,7 +1123,8 @@ static int ai_check_chanlist(struct comedi_device *dev,
for (i = 0; i < cmd->chanlist_len; i++) {
if (CR_AREF(cmd->chanlist[i]) != aref) {
printk(KERN_ERR
- "comedi%d: me4000: ai_check_chanlist(): Mode is not equal for all entries\n",
+ "comedi%d: me4000: ai_check_chanlist(): "
+ "Mode is not equal for all entries\n",
dev->minor);
return -EINVAL;
}
@@ -1124,8 +1136,8 @@ static int ai_check_chanlist(struct comedi_device *dev,
if (CR_CHAN(cmd->chanlist[i]) >=
thisboard->ai.diff_count) {
printk(KERN_ERR
- "comedi%d: me4000: ai_check_chanlist(): Channel number to high\n",
- dev->minor);
+ "comedi%d: me4000: ai_check_chanlist():"
+ " Channel number to high\n", dev->minor);
return -EINVAL;
}
}
@@ -1133,8 +1145,8 @@ static int ai_check_chanlist(struct comedi_device *dev,
for (i = 0; i < cmd->chanlist_len; i++) {
if (CR_CHAN(cmd->chanlist[i]) >= thisboard->ai.count) {
printk(KERN_ERR
- "comedi%d: me4000: ai_check_chanlist(): Channel number to high\n",
- dev->minor);
+ "comedi%d: me4000: ai_check_chanlist(): "
+ "Channel number to high\n", dev->minor);
return -EINVAL;
}
}
@@ -1146,7 +1158,9 @@ static int ai_check_chanlist(struct comedi_device *dev,
if (CR_RANGE(cmd->chanlist[i]) != 1 &&
CR_RANGE(cmd->chanlist[i]) != 2) {
printk(KERN_ERR
- "comedi%d: me4000: ai_check_chanlist(): Bipolar is not selected in differential mode\n",
+ "comedi%d: me4000: ai_check_chanlist(): "
+ "Bipolar is not selected in "
+ "differential mode\n",
dev->minor);
return -EINVAL;
}
@@ -1330,21 +1344,19 @@ static int ai_write_chanlist(struct comedi_device *dev,
entry = chan;
- if (rang == 0) {
+ if (rang == 0)
entry |= ME4000_AI_LIST_RANGE_UNIPOLAR_2_5;
- } else if (rang == 1) {
+ else if (rang == 1)
entry |= ME4000_AI_LIST_RANGE_UNIPOLAR_10;
- } else if (rang == 2) {
+ else if (rang == 2)
entry |= ME4000_AI_LIST_RANGE_BIPOLAR_2_5;
- } else {
+ else
entry |= ME4000_AI_LIST_RANGE_BIPOLAR_10;
- }
- if (aref == SDF_DIFF) {
+ if (aref == SDF_DIFF)
entry |= ME4000_AI_LIST_INPUT_DIFFERENTIAL;
- } else {
+ else
entry |= ME4000_AI_LIST_INPUT_SINGLE_ENDED;
- }
me4000_outl(dev, entry, info->ai_context.channel_list_reg);
}
@@ -1454,8 +1466,8 @@ static int me4000_ai_do_cmd_test(struct comedi_device *dev,
break;
default:
printk(KERN_ERR
- "comedi%d: me4000: me4000_ai_do_cmd_test(): Invalid start source\n",
- dev->minor);
+ "comedi%d: me4000: me4000_ai_do_cmd_test(): "
+ "Invalid start source\n", dev->minor);
cmd->start_src = TRIG_NOW;
err++;
}
@@ -1470,8 +1482,8 @@ static int me4000_ai_do_cmd_test(struct comedi_device *dev,
break;
default:
printk(KERN_ERR
- "comedi%d: me4000: me4000_ai_do_cmd_test(): Invalid scan begin source\n",
- dev->minor);
+ "comedi%d: me4000: me4000_ai_do_cmd_test(): "
+ "Invalid scan begin source\n", dev->minor);
cmd->scan_begin_src = TRIG_FOLLOW;
err++;
}
@@ -1485,8 +1497,8 @@ static int me4000_ai_do_cmd_test(struct comedi_device *dev,
break;
default:
printk(KERN_ERR
- "comedi%d: me4000: me4000_ai_do_cmd_test(): Invalid convert source\n",
- dev->minor);
+ "comedi%d: me4000: me4000_ai_do_cmd_test(): "
+ "Invalid convert source\n", dev->minor);
cmd->convert_src = TRIG_TIMER;
err++;
}
@@ -1500,8 +1512,8 @@ static int me4000_ai_do_cmd_test(struct comedi_device *dev,
break;
default:
printk(KERN_ERR
- "comedi%d: me4000: me4000_ai_do_cmd_test(): Invalid scan end source\n",
- dev->minor);
+ "comedi%d: me4000: me4000_ai_do_cmd_test(): "
+ "Invalid scan end source\n", dev->minor);
cmd->scan_end_src = TRIG_NONE;
err++;
}
@@ -1515,8 +1527,8 @@ static int me4000_ai_do_cmd_test(struct comedi_device *dev,
break;
default:
printk(KERN_ERR
- "comedi%d: me4000: me4000_ai_do_cmd_test(): Invalid stop source\n",
- dev->minor);
+ "comedi%d: me4000: me4000_ai_do_cmd_test(): "
+ "Invalid stop source\n", dev->minor);
cmd->stop_src = TRIG_NONE;
err++;
}
@@ -1546,8 +1558,8 @@ static int me4000_ai_do_cmd_test(struct comedi_device *dev,
cmd->convert_src == TRIG_EXT) {
} else {
printk(KERN_ERR
- "comedi%d: me4000: me4000_ai_do_cmd_test(): Invalid start trigger combination\n",
- dev->minor);
+ "comedi%d: me4000: me4000_ai_do_cmd_test(): "
+ "Invalid start trigger combination\n", dev->minor);
cmd->start_src = TRIG_NOW;
cmd->scan_begin_src = TRIG_FOLLOW;
cmd->convert_src = TRIG_TIMER;
@@ -1563,8 +1575,8 @@ static int me4000_ai_do_cmd_test(struct comedi_device *dev,
cmd->scan_end_src == TRIG_COUNT) {
} else {
printk(KERN_ERR
- "comedi%d: me4000: me4000_ai_do_cmd_test(): Invalid stop trigger combination\n",
- dev->minor);
+ "comedi%d: me4000: me4000_ai_do_cmd_test(): "
+ "Invalid stop trigger combination\n", dev->minor);
cmd->stop_src = TRIG_NONE;
cmd->scan_end_src = TRIG_NONE;
err++;
@@ -1577,29 +1589,29 @@ static int me4000_ai_do_cmd_test(struct comedi_device *dev,
*/
if (cmd->chanlist_len < 1) {
printk(KERN_ERR
- "comedi%d: me4000: me4000_ai_do_cmd_test(): No channel list\n",
- dev->minor);
+ "comedi%d: me4000: me4000_ai_do_cmd_test(): "
+ "No channel list\n", dev->minor);
cmd->chanlist_len = 1;
err++;
}
if (init_ticks < 66) {
printk(KERN_ERR
- "comedi%d: me4000: me4000_ai_do_cmd_test(): Start arg to low\n",
- dev->minor);
+ "comedi%d: me4000: me4000_ai_do_cmd_test(): "
+ "Start arg to low\n", dev->minor);
cmd->start_arg = 2000;
err++;
}
if (scan_ticks && scan_ticks < 67) {
printk(KERN_ERR
- "comedi%d: me4000: me4000_ai_do_cmd_test(): Scan begin arg to low\n",
- dev->minor);
+ "comedi%d: me4000: me4000_ai_do_cmd_test(): "
+ "Scan begin arg to low\n", dev->minor);
cmd->scan_begin_arg = 2031;
err++;
}
if (chan_ticks < 66) {
printk(KERN_ERR
- "comedi%d: me4000: me4000_ai_do_cmd_test(): Convert arg to low\n",
- dev->minor);
+ "comedi%d: me4000: me4000_ai_do_cmd_test(): "
+ "Convert arg to low\n", dev->minor);
cmd->convert_arg = 2000;
err++;
}
@@ -1617,23 +1629,25 @@ static int me4000_ai_do_cmd_test(struct comedi_device *dev,
/* Check timer arguments */
if (init_ticks < ME4000_AI_MIN_TICKS) {
printk(KERN_ERR
- "comedi%d: me4000: me4000_ai_do_cmd_test(): Invalid start arg\n",
- dev->minor);
+ "comedi%d: me4000: me4000_ai_do_cmd_test(): "
+ "Invalid start arg\n", dev->minor);
cmd->start_arg = 2000; /* 66 ticks at least */
err++;
}
if (chan_ticks < ME4000_AI_MIN_TICKS) {
printk(KERN_ERR
- "comedi%d: me4000: me4000_ai_do_cmd_test(): Invalid convert arg\n",
- dev->minor);
+ "comedi%d: me4000: me4000_ai_do_cmd_test(): "
+ "Invalid convert arg\n", dev->minor);
cmd->convert_arg = 2000; /* 66 ticks at least */
err++;
}
if (scan_ticks <= cmd->chanlist_len * chan_ticks) {
printk(KERN_ERR
- "comedi%d: me4000: me4000_ai_do_cmd_test(): Invalid scan end arg\n",
- dev->minor);
- cmd->scan_end_arg = 2000 * cmd->chanlist_len + 31; /* At least one tick more */
+ "comedi%d: me4000: me4000_ai_do_cmd_test(): "
+ "Invalid scan end arg\n", dev->minor);
+
+ /* At least one tick more */
+ cmd->scan_end_arg = 2000 * cmd->chanlist_len + 31;
err++;
}
} else if (cmd->start_src == TRIG_NOW &&
@@ -1643,15 +1657,15 @@ static int me4000_ai_do_cmd_test(struct comedi_device *dev,
/* Check timer arguments */
if (init_ticks < ME4000_AI_MIN_TICKS) {
printk(KERN_ERR
- "comedi%d: me4000: me4000_ai_do_cmd_test(): Invalid start arg\n",
- dev->minor);
+ "comedi%d: me4000: me4000_ai_do_cmd_test(): "
+ "Invalid start arg\n", dev->minor);
cmd->start_arg = 2000; /* 66 ticks at least */
err++;
}
if (chan_ticks < ME4000_AI_MIN_TICKS) {
printk(KERN_ERR
- "comedi%d: me4000: me4000_ai_do_cmd_test(): Invalid convert arg\n",
- dev->minor);
+ "comedi%d: me4000: me4000_ai_do_cmd_test(): "
+ "Invalid convert arg\n", dev->minor);
cmd->convert_arg = 2000; /* 66 ticks at least */
err++;
}
@@ -1662,23 +1676,25 @@ static int me4000_ai_do_cmd_test(struct comedi_device *dev,
/* Check timer arguments */
if (init_ticks < ME4000_AI_MIN_TICKS) {
printk(KERN_ERR
- "comedi%d: me4000: me4000_ai_do_cmd_test(): Invalid start arg\n",
- dev->minor);
+ "comedi%d: me4000: me4000_ai_do_cmd_test(): "
+ "Invalid start arg\n", dev->minor);
cmd->start_arg = 2000; /* 66 ticks at least */
err++;
}
if (chan_ticks < ME4000_AI_MIN_TICKS) {
printk(KERN_ERR
- "comedi%d: me4000: me4000_ai_do_cmd_test(): Invalid convert arg\n",
- dev->minor);
+ "comedi%d: me4000: me4000_ai_do_cmd_test(): "
+ "Invalid convert arg\n", dev->minor);
cmd->convert_arg = 2000; /* 66 ticks at least */
err++;
}
if (scan_ticks <= cmd->chanlist_len * chan_ticks) {
printk(KERN_ERR
- "comedi%d: me4000: me4000_ai_do_cmd_test(): Invalid scan end arg\n",
- dev->minor);
- cmd->scan_end_arg = 2000 * cmd->chanlist_len + 31; /* At least one tick more */
+ "comedi%d: me4000: me4000_ai_do_cmd_test(): "
+ "Invalid scan end arg\n", dev->minor);
+
+ /* At least one tick more */
+ cmd->scan_end_arg = 2000 * cmd->chanlist_len + 31;
err++;
}
} else if (cmd->start_src == TRIG_EXT &&
@@ -1688,15 +1704,15 @@ static int me4000_ai_do_cmd_test(struct comedi_device *dev,
/* Check timer arguments */
if (init_ticks < ME4000_AI_MIN_TICKS) {
printk(KERN_ERR
- "comedi%d: me4000: me4000_ai_do_cmd_test(): Invalid start arg\n",
- dev->minor);
+ "comedi%d: me4000: me4000_ai_do_cmd_test(): "
+ "Invalid start arg\n", dev->minor);
cmd->start_arg = 2000; /* 66 ticks at least */
err++;
}
if (chan_ticks < ME4000_AI_MIN_TICKS) {
printk(KERN_ERR
- "comedi%d: me4000: me4000_ai_do_cmd_test(): Invalid convert arg\n",
- dev->minor);
+ "comedi%d: me4000: me4000_ai_do_cmd_test(): "
+ "Invalid convert arg\n", dev->minor);
cmd->convert_arg = 2000; /* 66 ticks at least */
err++;
}
@@ -1707,15 +1723,15 @@ static int me4000_ai_do_cmd_test(struct comedi_device *dev,
/* Check timer arguments */
if (init_ticks < ME4000_AI_MIN_TICKS) {
printk(KERN_ERR
- "comedi%d: me4000: me4000_ai_do_cmd_test(): Invalid start arg\n",
- dev->minor);
+ "comedi%d: me4000: me4000_ai_do_cmd_test(): "
+ "Invalid start arg\n", dev->minor);
cmd->start_arg = 2000; /* 66 ticks at least */
err++;
}
if (chan_ticks < ME4000_AI_MIN_TICKS) {
printk(KERN_ERR
- "comedi%d: me4000: me4000_ai_do_cmd_test(): Invalid convert arg\n",
- dev->minor);
+ "comedi%d: me4000: me4000_ai_do_cmd_test(): "
+ "Invalid convert arg\n", dev->minor);
cmd->convert_arg = 2000; /* 66 ticks at least */
err++;
}
@@ -1726,8 +1742,8 @@ static int me4000_ai_do_cmd_test(struct comedi_device *dev,
/* Check timer arguments */
if (init_ticks < ME4000_AI_MIN_TICKS) {
printk(KERN_ERR
- "comedi%d: me4000: me4000_ai_do_cmd_test(): Invalid start arg\n",
- dev->minor);
+ "comedi%d: me4000: me4000_ai_do_cmd_test(): "
+ "Invalid start arg\n", dev->minor);
cmd->start_arg = 2000; /* 66 ticks at least */
err++;
}
@@ -1735,8 +1751,8 @@ static int me4000_ai_do_cmd_test(struct comedi_device *dev,
if (cmd->stop_src == TRIG_COUNT) {
if (cmd->stop_arg == 0) {
printk(KERN_ERR
- "comedi%d: me4000: me4000_ai_do_cmd_test(): Invalid stop arg\n",
- dev->minor);
+ "comedi%d: me4000: me4000_ai_do_cmd_test(): "
+ "Invalid stop arg\n", dev->minor);
cmd->stop_arg = 1;
err++;
}
@@ -1744,8 +1760,8 @@ static int me4000_ai_do_cmd_test(struct comedi_device *dev,
if (cmd->scan_end_src == TRIG_COUNT) {
if (cmd->scan_end_arg == 0) {
printk(KERN_ERR
- "comedi%d: me4000: me4000_ai_do_cmd_test(): Invalid scan end arg\n",
- dev->minor);
+ "comedi%d: me4000: me4000_ai_do_cmd_test(): "
+ "Invalid scan end arg\n", dev->minor);
cmd->scan_end_arg = 1;
err++;
}
@@ -1786,8 +1802,8 @@ static irqreturn_t me4000_ai_isr(int irq, void *dev_id)
/* Check if irq number is right */
if (irq != ai_context->irq) {
printk(KERN_ERR
- "comedi%d: me4000: me4000_ai_isr(): Incorrect interrupt num: %d\n",
- dev->minor, irq);
+ "comedi%d: me4000: me4000_ai_isr(): "
+ "Incorrect interrupt num: %d\n", dev->minor, irq);
return IRQ_HANDLED;
}
@@ -1806,7 +1822,10 @@ static irqreturn_t me4000_ai_isr(int irq, void *dev_id)
ISR_PDEBUG("me4000_ai_isr(): Fifo full\n");
c = ME4000_AI_FIFO_COUNT;
- /* FIFO overflow, so stop conversion and disable all interrupts */
+ /*
+ * FIFO overflow, so stop conversion
+ * and disable all interrupts
+ */
tmp |= ME4000_AI_CTRL_BIT_IMMEDIATE_STOP;
tmp &= ~(ME4000_AI_CTRL_BIT_HF_IRQ |
ME4000_AI_CTRL_BIT_SC_IRQ);
@@ -1815,8 +1834,8 @@ static irqreturn_t me4000_ai_isr(int irq, void *dev_id)
s->async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA;
printk(KERN_ERR
- "comedi%d: me4000: me4000_ai_isr(): FIFO overflow\n",
- dev->minor);
+ "comedi%d: me4000: me4000_ai_isr(): "
+ "FIFO overflow\n", dev->minor);
} else if ((tmp & ME4000_AI_STATUS_BIT_FF_DATA)
&& !(tmp & ME4000_AI_STATUS_BIT_HF_DATA)
&& (tmp & ME4000_AI_STATUS_BIT_EF_DATA)) {
@@ -1827,11 +1846,14 @@ static irqreturn_t me4000_ai_isr(int irq, void *dev_id)
c = ME4000_AI_FIFO_COUNT / 2;
} else {
printk(KERN_ERR
- "comedi%d: me4000: me4000_ai_isr(): Can't determine state of fifo\n",
- dev->minor);
+ "comedi%d: me4000: me4000_ai_isr(): "
+ "Can't determine state of fifo\n", dev->minor);
c = 0;
- /* Undefined state, so stop conversion and disable all interrupts */
+ /*
+ * Undefined state, so stop conversion
+ * and disable all interrupts
+ */
tmp |= ME4000_AI_CTRL_BIT_IMMEDIATE_STOP;
tmp &= ~(ME4000_AI_CTRL_BIT_HF_IRQ |
ME4000_AI_CTRL_BIT_SC_IRQ);
@@ -1840,8 +1862,8 @@ static irqreturn_t me4000_ai_isr(int irq, void *dev_id)
s->async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA;
printk(KERN_ERR
- "comedi%d: me4000: me4000_ai_isr(): Undefined FIFO state\n",
- dev->minor);
+ "comedi%d: me4000: me4000_ai_isr(): "
+ "Undefined FIFO state\n", dev->minor);
}
ISR_PDEBUG("me4000_ai_isr(): Try to read %d values\n", c);
@@ -1852,7 +1874,10 @@ static irqreturn_t me4000_ai_isr(int irq, void *dev_id)
lval ^= 0x8000;
if (!comedi_buf_put(s->async, lval)) {
- /* Buffer overflow, so stop conversion and disable all interrupts */
+ /*
+ * Buffer overflow, so stop conversion
+ * and disable all interrupts
+ */
tmp |= ME4000_AI_CTRL_BIT_IMMEDIATE_STOP;
tmp &= ~(ME4000_AI_CTRL_BIT_HF_IRQ |
ME4000_AI_CTRL_BIT_SC_IRQ);
@@ -1861,8 +1886,8 @@ static irqreturn_t me4000_ai_isr(int irq, void *dev_id)
s->async->events |= COMEDI_CB_OVERFLOW;
printk(KERN_ERR
- "comedi%d: me4000: me4000_ai_isr(): Buffer overflow\n",
- dev->minor);
+ "comedi%d: me4000: me4000_ai_isr(): "
+ "Buffer overflow\n", dev->minor);
break;
}
@@ -1883,7 +1908,10 @@ static irqreturn_t me4000_ai_isr(int irq, void *dev_id)
s->async->events |= COMEDI_CB_BLOCK | COMEDI_CB_EOA;
- /* Acquisition is complete, so stop conversion and disable all interrupts */
+ /*
+ * Acquisition is complete, so stop
+ * conversion and disable all interrupts
+ */
tmp = me4000_inl(dev, ai_context->ctrl_reg);
tmp |= ME4000_AI_CTRL_BIT_IMMEDIATE_STOP;
tmp &= ~(ME4000_AI_CTRL_BIT_HF_IRQ | ME4000_AI_CTRL_BIT_SC_IRQ);
@@ -1897,8 +1925,8 @@ static irqreturn_t me4000_ai_isr(int irq, void *dev_id)
if (!comedi_buf_put(s->async, lval)) {
printk(KERN_ERR
- "comedi%d: me4000: me4000_ai_isr(): Buffer overflow\n",
- dev->minor);
+ "comedi%d: me4000: me4000_ai_isr(): "
+ "Buffer overflow\n", dev->minor);
s->async->events |= COMEDI_CB_OVERFLOW;
break;
}
@@ -1941,29 +1969,29 @@ static int me4000_ao_insn_write(struct comedi_device *dev,
return 0;
} else if (insn->n > 1) {
printk(KERN_ERR
- "comedi%d: me4000: me4000_ao_insn_write(): Invalid instruction length %d\n",
- dev->minor, insn->n);
+ "comedi%d: me4000: me4000_ao_insn_write(): "
+ "Invalid instruction length %d\n", dev->minor, insn->n);
return -EINVAL;
}
if (chan >= thisboard->ao.count) {
printk(KERN_ERR
- "comedi%d: me4000: me4000_ao_insn_write(): Invalid channel %d\n",
- dev->minor, insn->n);
+ "comedi%d: me4000: me4000_ao_insn_write(): "
+ "Invalid channel %d\n", dev->minor, insn->n);
return -EINVAL;
}
if (rang != 0) {
printk(KERN_ERR
- "comedi%d: me4000: me4000_ao_insn_write(): Invalid range %d\n",
- dev->minor, insn->n);
+ "comedi%d: me4000: me4000_ao_insn_write(): "
+ "Invalid range %d\n", dev->minor, insn->n);
return -EINVAL;
}
if (aref != AREF_GROUND && aref != AREF_COMMON) {
printk(KERN_ERR
- "comedi%d: me4000: me4000_ao_insn_write(): Invalid aref %d\n",
- dev->minor, insn->n);
+ "comedi%d: me4000: me4000_ao_insn_write(): "
+ "Invalid aref %d\n", dev->minor, insn->n);
return -EINVAL;
}
@@ -1994,8 +2022,8 @@ static int me4000_ao_insn_read(struct comedi_device *dev,
return 0;
} else if (insn->n > 1) {
printk
- ("comedi%d: me4000: me4000_ao_insn_read(): Invalid instruction length\n",
- dev->minor);
+ ("comedi%d: me4000: me4000_ao_insn_read(): "
+ "Invalid instruction length\n", dev->minor);
return -EINVAL;
}
@@ -2021,8 +2049,8 @@ static int me4000_dio_insn_bits(struct comedi_device *dev,
if (insn->n != 2) {
printk
- ("comedi%d: me4000: me4000_dio_insn_bits(): Invalid instruction length\n",
- dev->minor);
+ ("comedi%d: me4000: me4000_dio_insn_bits(): "
+ "Invalid instruction length\n", dev->minor);
return -EINVAL;
}
@@ -2095,8 +2123,9 @@ static int me4000_dio_insn_config(struct comedi_device *dev,
tmp |= ME4000_DIO_CTRL_BIT_MODE_0;
} else if (chan < 16) {
/*
- * Chech for optoisolated ME-4000 version. If one the first
- * port is a fixed output port and the second is a fixed input port.
+ * Chech for optoisolated ME-4000 version.
+ * If one the first port is a fixed output
+ * port and the second is a fixed input port.
*/
if (!me4000_inl(dev, info->dio_context.dir_reg))
return -ENODEV;
@@ -2121,8 +2150,9 @@ static int me4000_dio_insn_config(struct comedi_device *dev,
} else {
if (chan < 8) {
/*
- * Chech for optoisolated ME-4000 version. If one the first
- * port is a fixed output port and the second is a fixed input port.
+ * Chech for optoisolated ME-4000 version.
+ * If one the first port is a fixed output
+ * port and the second is a fixed input port.
*/
if (!me4000_inl(dev, info->dio_context.dir_reg))
return -ENODEV;
@@ -2257,7 +2287,8 @@ static int me4000_cnt_insn_config(struct comedi_device *dev,
case GPCT_RESET:
if (insn->n != 1) {
printk(KERN_ERR
- "comedi%d: me4000: me4000_cnt_insn_config(): Invalid instruction length%d\n",
+ "comedi%d: me4000: me4000_cnt_insn_config(): "
+ "Invalid instruction length%d\n",
dev->minor, insn->n);
return -EINVAL;
}
@@ -2269,7 +2300,8 @@ static int me4000_cnt_insn_config(struct comedi_device *dev,
case GPCT_SET_OPERATION:
if (insn->n != 2) {
printk(KERN_ERR
- "comedi%d: me4000: me4000_cnt_insn_config(): Invalid instruction length%d\n",
+ "comedi%d: me4000: me4000_cnt_insn_config(): "
+ "Invalid instruction length%d\n",
dev->minor, insn->n);
return -EINVAL;
}
@@ -2280,8 +2312,8 @@ static int me4000_cnt_insn_config(struct comedi_device *dev,
break;
default:
printk(KERN_ERR
- "comedi%d: me4000: me4000_cnt_insn_config(): Invalid instruction\n",
- dev->minor);
+ "comedi%d: me4000: me4000_cnt_insn_config(): "
+ "Invalid instruction\n", dev->minor);
return -EINVAL;
}
@@ -2302,7 +2334,8 @@ static int me4000_cnt_insn_read(struct comedi_device *dev,
if (insn->n > 1) {
printk(KERN_ERR
- "comedi%d: me4000: me4000_cnt_insn_read(): Invalid instruction length %d\n",
+ "comedi%d: me4000: me4000_cnt_insn_read(): "
+ "Invalid instruction length %d\n",
dev->minor, insn->n);
return -EINVAL;
}
@@ -2328,7 +2361,8 @@ static int me4000_cnt_insn_read(struct comedi_device *dev,
break;
default:
printk(KERN_ERR
- "comedi%d: me4000: me4000_cnt_insn_read(): Invalid channel %d\n",
+ "comedi%d: me4000: me4000_cnt_insn_read(): "
+ "Invalid channel %d\n",
dev->minor, insn->chanspec);
return -EINVAL;
}
@@ -2349,7 +2383,8 @@ static int me4000_cnt_insn_write(struct comedi_device *dev,
return 0;
} else if (insn->n > 1) {
printk(KERN_ERR
- "comedi%d: me4000: me4000_cnt_insn_write(): Invalid instruction length %d\n",
+ "comedi%d: me4000: me4000_cnt_insn_write(): "
+ "Invalid instruction length %d\n",
dev->minor, insn->n);
return -EINVAL;
}
@@ -2375,7 +2410,8 @@ static int me4000_cnt_insn_write(struct comedi_device *dev,
break;
default:
printk(KERN_ERR
- "comedi%d: me4000: me4000_cnt_insn_write(): Invalid channel %d\n",
+ "comedi%d: me4000: me4000_cnt_insn_write(): "
+ "Invalid channel %d\n",
dev->minor, insn->chanspec);
return -EINVAL;
}
@@ -2383,4 +2419,44 @@ static int me4000_cnt_insn_write(struct comedi_device *dev,
return 1;
}
-COMEDI_PCI_INITCLEANUP(driver_me4000, me4000_pci_table);
+static int __devinit driver_me4000_pci_probe(struct pci_dev *dev,
+ const struct pci_device_id *ent)
+{
+ return comedi_pci_auto_config(dev, driver_me4000.driver_name);
+}
+
+static void __devexit driver_me4000_pci_remove(struct pci_dev *dev)
+{
+ comedi_pci_auto_unconfig(dev);
+}
+
+static struct pci_driver driver_me4000_pci_driver = {
+ .id_table = me4000_pci_table,
+ .probe = &driver_me4000_pci_probe,
+ .remove = __devexit_p(&driver_me4000_pci_remove)
+};
+
+static int __init driver_me4000_init_module(void)
+{
+ int retval;
+
+ retval = comedi_driver_register(&driver_me4000);
+ if (retval < 0)
+ return retval;
+
+ driver_me4000_pci_driver.name = (char *)driver_me4000.driver_name;
+ return pci_register_driver(&driver_me4000_pci_driver);
+}
+
+static void __exit driver_me4000_cleanup_module(void)
+{
+ pci_unregister_driver(&driver_me4000_pci_driver);
+ comedi_driver_unregister(&driver_me4000);
+}
+
+module_init(driver_me4000_init_module);
+module_exit(driver_me4000_cleanup_module);
+
+MODULE_AUTHOR("Comedi http://www.comedi.org");
+MODULE_DESCRIPTION("Comedi low-level driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/me_daq.c b/drivers/staging/comedi/drivers/me_daq.c
index c8484aec657..cda4b224b30 100644
--- a/drivers/staging/comedi/drivers/me_daq.c
+++ b/drivers/staging/comedi/drivers/me_daq.c
@@ -257,7 +257,43 @@ static struct comedi_driver me_driver = {
.detach = me_detach,
};
-COMEDI_PCI_INITCLEANUP(me_driver, me_pci_table);
+static int __devinit me_driver_pci_probe(struct pci_dev *dev,
+ const struct pci_device_id *ent)
+{
+ return comedi_pci_auto_config(dev, me_driver.driver_name);
+}
+
+static void __devexit me_driver_pci_remove(struct pci_dev *dev)
+{
+ comedi_pci_auto_unconfig(dev);
+}
+
+static struct pci_driver me_driver_pci_driver = {
+ .id_table = me_pci_table,
+ .probe = &me_driver_pci_probe,
+ .remove = __devexit_p(&me_driver_pci_remove)
+};
+
+static int __init me_driver_init_module(void)
+{
+ int retval;
+
+ retval = comedi_driver_register(&me_driver);
+ if (retval < 0)
+ return retval;
+
+ me_driver_pci_driver.name = (char *)me_driver.driver_name;
+ return pci_register_driver(&me_driver_pci_driver);
+}
+
+static void __exit me_driver_cleanup_module(void)
+{
+ pci_unregister_driver(&me_driver_pci_driver);
+ comedi_driver_unregister(&me_driver);
+}
+
+module_init(me_driver_init_module);
+module_exit(me_driver_cleanup_module);
/* Private data structure */
struct me_private_data {
@@ -644,7 +680,7 @@ static int me_reset(struct comedi_device *dev)
*/
static int me_attach(struct comedi_device *dev, struct comedi_devconfig *it)
{
- struct pci_dev *pci_device;
+ struct pci_dev *pci_device = NULL;
struct comedi_subdevice *subdevice;
struct me_board *board;
resource_size_t plx_regbase_tmp;
@@ -661,9 +697,7 @@ static int me_attach(struct comedi_device *dev, struct comedi_devconfig *it)
return -ENOMEM;
/* Probe the device to determine what device in the series it is. */
- for (pci_device = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, NULL);
- pci_device != NULL;
- pci_device = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, pci_device)) {
+ for_each_pci_dev(pci_device) {
if (pci_device->vendor == PCI_VENDOR_ID_MEILHAUS) {
for (i = 0; i < me_board_nbr; i++) {
if (me_boards[i].device_id ==
@@ -857,3 +891,7 @@ static int me_detach(struct comedi_device *dev)
}
return 0;
}
+
+MODULE_AUTHOR("Comedi http://www.comedi.org");
+MODULE_DESCRIPTION("Comedi low-level driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/mite.c b/drivers/staging/comedi/drivers/mite.c
index 99d9985c5b3..cd25b241cc1 100644
--- a/drivers/staging/comedi/drivers/mite.c
+++ b/drivers/staging/comedi/drivers/mite.c
@@ -70,12 +70,10 @@ EXPORT_SYMBOL(mite_devices);
void mite_init(void)
{
- struct pci_dev *pcidev;
+ struct pci_dev *pcidev = NULL;
struct mite_struct *mite;
- for (pcidev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, NULL);
- pcidev != NULL;
- pcidev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, pcidev)) {
+ for_each_pci_dev(pcidev) {
if (pcidev->vendor == PCI_VENDOR_ID_NI) {
unsigned i;
@@ -829,3 +827,7 @@ void __exit cleanup_module(void)
mite_cleanup();
}
#endif
+
+MODULE_AUTHOR("Comedi http://www.comedi.org");
+MODULE_DESCRIPTION("Comedi low-level driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/mpc624.c b/drivers/staging/comedi/drivers/mpc624.c
index 9874ac3749c..a89eebd23f6 100644
--- a/drivers/staging/comedi/drivers/mpc624.c
+++ b/drivers/staging/comedi/drivers/mpc624.c
@@ -406,4 +406,19 @@ static int mpc624_ai_rinsn(struct comedi_device *dev,
return n;
}
-COMEDI_INITCLEANUP(driver_mpc624);
+static int __init driver_mpc624_init_module(void)
+{
+ return comedi_driver_register(&driver_mpc624);
+}
+
+static void __exit driver_mpc624_cleanup_module(void)
+{
+ comedi_driver_unregister(&driver_mpc624);
+}
+
+module_init(driver_mpc624_init_module);
+module_exit(driver_mpc624_cleanup_module);
+
+MODULE_AUTHOR("Comedi http://www.comedi.org");
+MODULE_DESCRIPTION("Comedi low-level driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/mpc8260cpm.c b/drivers/staging/comedi/drivers/mpc8260cpm.c
index 440a144a037..5f6816a3fe8 100644
--- a/drivers/staging/comedi/drivers/mpc8260cpm.c
+++ b/drivers/staging/comedi/drivers/mpc8260cpm.c
@@ -56,7 +56,18 @@ static struct comedi_driver driver_mpc8260cpm = {
.detach = mpc8260cpm_detach,
};
-COMEDI_INITCLEANUP(driver_mpc8260cpm);
+static int __init driver_mpc8260cpm_init_module(void)
+{
+ return comedi_driver_register(&driver_mpc8260cpm);
+}
+
+static void __exit driver_mpc8260cpm_cleanup_module(void)
+{
+ comedi_driver_unregister(&driver_mpc8260cpm);
+}
+
+module_init(driver_mpc8260cpm_init_module);
+module_exit(driver_mpc8260cpm_cleanup_module);
static int mpc8260cpm_dio_config(struct comedi_device *dev,
struct comedi_subdevice *s,
diff --git a/drivers/staging/comedi/drivers/multiq3.c b/drivers/staging/comedi/drivers/multiq3.c
index 6b22f0f8f06..dace902d3bc 100644
--- a/drivers/staging/comedi/drivers/multiq3.c
+++ b/drivers/staging/comedi/drivers/multiq3.c
@@ -93,7 +93,18 @@ static struct comedi_driver driver_multiq3 = {
.detach = multiq3_detach,
};
-COMEDI_INITCLEANUP(driver_multiq3);
+static int __init driver_multiq3_init_module(void)
+{
+ return comedi_driver_register(&driver_multiq3);
+}
+
+static void __exit driver_multiq3_cleanup_module(void)
+{
+ comedi_driver_unregister(&driver_multiq3);
+}
+
+module_init(driver_multiq3_init_module);
+module_exit(driver_multiq3_cleanup_module);
struct multiq3_private {
unsigned int ao_readback[2];
@@ -338,3 +349,7 @@ static int multiq3_detach(struct comedi_device *dev)
return 0;
}
+
+MODULE_AUTHOR("Comedi http://www.comedi.org");
+MODULE_DESCRIPTION("Comedi low-level driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/ni_6527.c b/drivers/staging/comedi/drivers/ni_6527.c
index 1fc76cc6a28..14e716e99a5 100644
--- a/drivers/staging/comedi/drivers/ni_6527.c
+++ b/drivers/staging/comedi/drivers/ni_6527.c
@@ -490,4 +490,40 @@ static int ni6527_find_device(struct comedi_device *dev, int bus, int slot)
return -EIO;
}
-COMEDI_PCI_INITCLEANUP(driver_ni6527, ni6527_pci_table);
+static int __devinit driver_ni6527_pci_probe(struct pci_dev *dev,
+ const struct pci_device_id *ent)
+{
+ return comedi_pci_auto_config(dev, driver_ni6527.driver_name);
+}
+
+static void __devexit driver_ni6527_pci_remove(struct pci_dev *dev)
+{
+ comedi_pci_auto_unconfig(dev);
+}
+
+static struct pci_driver driver_ni6527_pci_driver = {
+ .id_table = ni6527_pci_table,
+ .probe = &driver_ni6527_pci_probe,
+ .remove = __devexit_p(&driver_ni6527_pci_remove)
+};
+
+static int __init driver_ni6527_init_module(void)
+{
+ int retval;
+
+ retval = comedi_driver_register(&driver_ni6527);
+ if (retval < 0)
+ return retval;
+
+ driver_ni6527_pci_driver.name = (char *)driver_ni6527.driver_name;
+ return pci_register_driver(&driver_ni6527_pci_driver);
+}
+
+static void __exit driver_ni6527_cleanup_module(void)
+{
+ pci_unregister_driver(&driver_ni6527_pci_driver);
+ comedi_driver_unregister(&driver_ni6527);
+}
+
+module_init(driver_ni6527_init_module);
+module_exit(driver_ni6527_cleanup_module);
diff --git a/drivers/staging/comedi/drivers/ni_65xx.c b/drivers/staging/comedi/drivers/ni_65xx.c
index d793f5a4ac9..8b8e2aaf77f 100644
--- a/drivers/staging/comedi/drivers/ni_65xx.c
+++ b/drivers/staging/comedi/drivers/ni_65xx.c
@@ -834,4 +834,40 @@ static int ni_65xx_find_device(struct comedi_device *dev, int bus, int slot)
return -EIO;
}
-COMEDI_PCI_INITCLEANUP(driver_ni_65xx, ni_65xx_pci_table);
+static int __devinit driver_ni_65xx_pci_probe(struct pci_dev *dev,
+ const struct pci_device_id *ent)
+{
+ return comedi_pci_auto_config(dev, driver_ni_65xx.driver_name);
+}
+
+static void __devexit driver_ni_65xx_pci_remove(struct pci_dev *dev)
+{
+ comedi_pci_auto_unconfig(dev);
+}
+
+static struct pci_driver driver_ni_65xx_pci_driver = {
+ .id_table = ni_65xx_pci_table,
+ .probe = &driver_ni_65xx_pci_probe,
+ .remove = __devexit_p(&driver_ni_65xx_pci_remove)
+};
+
+static int __init driver_ni_65xx_init_module(void)
+{
+ int retval;
+
+ retval = comedi_driver_register(&driver_ni_65xx);
+ if (retval < 0)
+ return retval;
+
+ driver_ni_65xx_pci_driver.name = (char *)driver_ni_65xx.driver_name;
+ return pci_register_driver(&driver_ni_65xx_pci_driver);
+}
+
+static void __exit driver_ni_65xx_cleanup_module(void)
+{
+ pci_unregister_driver(&driver_ni_65xx_pci_driver);
+ comedi_driver_unregister(&driver_ni_65xx);
+}
+
+module_init(driver_ni_65xx_init_module);
+module_exit(driver_ni_65xx_cleanup_module);
diff --git a/drivers/staging/comedi/drivers/ni_660x.c b/drivers/staging/comedi/drivers/ni_660x.c
index 6a6fae53ea0..6612b085c4e 100644
--- a/drivers/staging/comedi/drivers/ni_660x.c
+++ b/drivers/staging/comedi/drivers/ni_660x.c
@@ -382,7 +382,7 @@ enum global_interrupt_config_register_bits {
Global_Int_Enable_Bit = 0x80000000
};
-/* Offset of the GPCT chips from the base-adress of the card */
+/* Offset of the GPCT chips from the base-address of the card */
/* First chip is at base-address + 0x00, etc. */
static const unsigned GPCT_OFFSET[2] = { 0x0, 0x800 };
@@ -471,7 +471,43 @@ static struct comedi_driver driver_ni_660x = {
.detach = ni_660x_detach,
};
-COMEDI_PCI_INITCLEANUP(driver_ni_660x, ni_660x_pci_table);
+static int __devinit driver_ni_660x_pci_probe(struct pci_dev *dev,
+ const struct pci_device_id *ent)
+{
+ return comedi_pci_auto_config(dev, driver_ni_660x.driver_name);
+}
+
+static void __devexit driver_ni_660x_pci_remove(struct pci_dev *dev)
+{
+ comedi_pci_auto_unconfig(dev);
+}
+
+static struct pci_driver driver_ni_660x_pci_driver = {
+ .id_table = ni_660x_pci_table,
+ .probe = &driver_ni_660x_pci_probe,
+ .remove = __devexit_p(&driver_ni_660x_pci_remove)
+};
+
+static int __init driver_ni_660x_init_module(void)
+{
+ int retval;
+
+ retval = comedi_driver_register(&driver_ni_660x);
+ if (retval < 0)
+ return retval;
+
+ driver_ni_660x_pci_driver.name = (char *)driver_ni_660x.driver_name;
+ return pci_register_driver(&driver_ni_660x_pci_driver);
+}
+
+static void __exit driver_ni_660x_cleanup_module(void)
+{
+ pci_unregister_driver(&driver_ni_660x_pci_driver);
+ comedi_driver_unregister(&driver_ni_660x);
+}
+
+module_init(driver_ni_660x_init_module);
+module_exit(driver_ni_660x_cleanup_module);
static int ni_660x_find_device(struct comedi_device *dev, int bus, int slot);
static int ni_660x_set_pfi_routing(struct comedi_device *dev, unsigned chan,
diff --git a/drivers/staging/comedi/drivers/ni_670x.c b/drivers/staging/comedi/drivers/ni_670x.c
index 44ae8368454..e9f034efdc6 100644
--- a/drivers/staging/comedi/drivers/ni_670x.c
+++ b/drivers/staging/comedi/drivers/ni_670x.c
@@ -120,7 +120,43 @@ static struct comedi_driver driver_ni_670x = {
.detach = ni_670x_detach,
};
-COMEDI_PCI_INITCLEANUP(driver_ni_670x, ni_670x_pci_table);
+static int __devinit driver_ni_670x_pci_probe(struct pci_dev *dev,
+ const struct pci_device_id *ent)
+{
+ return comedi_pci_auto_config(dev, driver_ni_670x.driver_name);
+}
+
+static void __devexit driver_ni_670x_pci_remove(struct pci_dev *dev)
+{
+ comedi_pci_auto_unconfig(dev);
+}
+
+static struct pci_driver driver_ni_670x_pci_driver = {
+ .id_table = ni_670x_pci_table,
+ .probe = &driver_ni_670x_pci_probe,
+ .remove = __devexit_p(&driver_ni_670x_pci_remove)
+};
+
+static int __init driver_ni_670x_init_module(void)
+{
+ int retval;
+
+ retval = comedi_driver_register(&driver_ni_670x);
+ if (retval < 0)
+ return retval;
+
+ driver_ni_670x_pci_driver.name = (char *)driver_ni_670x.driver_name;
+ return pci_register_driver(&driver_ni_670x_pci_driver);
+}
+
+static void __exit driver_ni_670x_cleanup_module(void)
+{
+ pci_unregister_driver(&driver_ni_670x_pci_driver);
+ comedi_driver_unregister(&driver_ni_670x);
+}
+
+module_init(driver_ni_670x_init_module);
+module_exit(driver_ni_670x_cleanup_module);
static struct comedi_lrange range_0_20mA = { 1, {RANGE_mA(0, 20)} };
diff --git a/drivers/staging/comedi/drivers/ni_at_a2150.c b/drivers/staging/comedi/drivers/ni_at_a2150.c
index 9bff34cf06d..e46d62b75fc 100644
--- a/drivers/staging/comedi/drivers/ni_at_a2150.c
+++ b/drivers/staging/comedi/drivers/ni_at_a2150.c
@@ -197,7 +197,18 @@ static int a2150_set_chanlist(struct comedi_device *dev,
* A convenient macro that defines init_module() and cleanup_module(),
* as necessary.
*/
-COMEDI_INITCLEANUP(driver_a2150);
+static int __init driver_a2150_init_module(void)
+{
+ return comedi_driver_register(&driver_a2150);
+}
+
+static void __exit driver_a2150_cleanup_module(void)
+{
+ comedi_driver_unregister(&driver_a2150);
+}
+
+module_init(driver_a2150_init_module);
+module_exit(driver_a2150_cleanup_module);
#ifdef A2150_DEBUG
@@ -910,3 +921,7 @@ static int a2150_set_chanlist(struct comedi_device *dev,
return 0;
}
+
+MODULE_AUTHOR("Comedi http://www.comedi.org");
+MODULE_DESCRIPTION("Comedi low-level driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/ni_at_ao.c b/drivers/staging/comedi/drivers/ni_at_ao.c
index ce60224bb7b..138dcc2275a 100644
--- a/drivers/staging/comedi/drivers/ni_at_ao.c
+++ b/drivers/staging/comedi/drivers/ni_at_ao.c
@@ -194,7 +194,18 @@ static struct comedi_driver driver_atao = {
.num_names = ARRAY_SIZE(atao_boards),
};
-COMEDI_INITCLEANUP(driver_atao);
+static int __init driver_atao_init_module(void)
+{
+ return comedi_driver_register(&driver_atao);
+}
+
+static void __exit driver_atao_cleanup_module(void)
+{
+ comedi_driver_unregister(&driver_atao);
+}
+
+module_init(driver_atao_init_module);
+module_exit(driver_atao_cleanup_module);
static void atao_reset(struct comedi_device *dev);
@@ -459,3 +470,7 @@ static int atao_calib_insn_write(struct comedi_device *dev,
return insn->n;
}
+
+MODULE_AUTHOR("Comedi http://www.comedi.org");
+MODULE_DESCRIPTION("Comedi low-level driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/ni_atmio.c b/drivers/staging/comedi/drivers/ni_atmio.c
index 003d00b595b..3330b3d53e8 100644
--- a/drivers/staging/comedi/drivers/ni_atmio.c
+++ b/drivers/staging/comedi/drivers/ni_atmio.c
@@ -349,7 +349,18 @@ static struct comedi_driver driver_atmio = {
.detach = ni_atmio_detach,
};
-COMEDI_INITCLEANUP(driver_atmio);
+static int __init driver_atmio_init_module(void)
+{
+ return comedi_driver_register(&driver_atmio);
+}
+
+static void __exit driver_atmio_cleanup_module(void)
+{
+ comedi_driver_unregister(&driver_atmio);
+}
+
+module_init(driver_atmio_init_module);
+module_exit(driver_atmio_cleanup_module);
#include "ni_mio_common.c"
diff --git a/drivers/staging/comedi/drivers/ni_atmio16d.c b/drivers/staging/comedi/drivers/ni_atmio16d.c
index cf4f241f210..285b933551a 100644
--- a/drivers/staging/comedi/drivers/ni_atmio16d.c
+++ b/drivers/staging/comedi/drivers/ni_atmio16d.c
@@ -151,7 +151,18 @@ static struct comedi_driver driver_atmio16d = {
.offset = sizeof(struct atmio16_board_t),
};
-COMEDI_INITCLEANUP(driver_atmio16d);
+static int __init driver_atmio16d_init_module(void)
+{
+ return comedi_driver_register(&driver_atmio16d);
+}
+
+static void __exit driver_atmio16d_cleanup_module(void)
+{
+ comedi_driver_unregister(&driver_atmio16d);
+}
+
+module_init(driver_atmio16d_init_module);
+module_exit(driver_atmio16d_cleanup_module);
/* range structs */
static const struct comedi_lrange range_atmio16d_ai_10_bipolar = { 4, {
@@ -887,3 +898,7 @@ static int atmio16d_detach(struct comedi_device *dev)
return 0;
}
+
+MODULE_AUTHOR("Comedi http://www.comedi.org");
+MODULE_DESCRIPTION("Comedi low-level driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/ni_daq_700.c b/drivers/staging/comedi/drivers/ni_daq_700.c
index 6ec77bf88c6..cc15666e5cc 100644
--- a/drivers/staging/comedi/drivers/ni_daq_700.c
+++ b/drivers/staging/comedi/drivers/ni_daq_700.c
@@ -47,7 +47,6 @@ IRQ is assigned but not used.
#include <linux/ioport.h>
-#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/cistpl.h>
#include <pcmcia/cisreg.h>
@@ -377,7 +376,7 @@ static int dio700_attach(struct comedi_device *dev, struct comedi_devconfig *it)
link = pcmcia_cur_dev; /* XXX hack */
if (!link)
return -EIO;
- iobase = link->io.BasePort1;
+ iobase = link->resource[0]->start;
#ifdef incomplete
irq = link->irq;
#endif
@@ -459,14 +458,6 @@ static void dio700_cs_detach(struct pcmcia_device *);
less on other parts of the kernel.
*/
-/*
- The dev_info variable is the "key" that is used to match up this
- device driver with appropriate cards, through the card configuration
- database.
-*/
-
-static const dev_info_t dev_info = "ni_daq_700";
-
struct local_info_t {
struct pcmcia_device *link;
int stop;
@@ -537,8 +528,7 @@ static void dio700_cs_detach(struct pcmcia_device *link)
dio700_release(link);
/* This points to the parent struct local_info_t struct */
- if (link->priv)
- kfree(link->priv);
+ kfree(link->priv);
} /* dio700_cs_detach */
@@ -556,9 +546,6 @@ static int dio700_pcmcia_config_loop(struct pcmcia_device *p_dev,
unsigned int vcc,
void *priv_data)
{
- win_req_t *req = priv_data;
- memreq_t map;
-
if (cfg->index == 0)
return -ENODEV;
@@ -572,44 +559,25 @@ static int dio700_pcmcia_config_loop(struct pcmcia_device *p_dev,
p_dev->conf.Attributes |= CONF_ENABLE_IRQ;
/* IO window settings */
- p_dev->io.NumPorts1 = p_dev->io.NumPorts2 = 0;
+ p_dev->resource[0]->end = p_dev->resource[1]->end = 0;
if ((cfg->io.nwin > 0) || (dflt->io.nwin > 0)) {
cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt->io;
- p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
- if (!(io->flags & CISTPL_IO_8BIT))
- p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_16;
- if (!(io->flags & CISTPL_IO_16BIT))
- p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
- p_dev->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK;
- p_dev->io.BasePort1 = io->win[0].base;
- p_dev->io.NumPorts1 = io->win[0].len;
+ p_dev->io_lines = io->flags & CISTPL_IO_LINES_MASK;
+ p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH;
+ p_dev->resource[0]->flags |=
+ pcmcia_io_cfg_data_width(io->flags);
+ p_dev->resource[0]->start = io->win[0].base;
+ p_dev->resource[0]->end = io->win[0].len;
if (io->nwin > 1) {
- p_dev->io.Attributes2 = p_dev->io.Attributes1;
- p_dev->io.BasePort2 = io->win[1].base;
- p_dev->io.NumPorts2 = io->win[1].len;
+ p_dev->resource[1]->flags = p_dev->resource[0]->flags;
+ p_dev->resource[1]->start = io->win[1].base;
+ p_dev->resource[1]->end = io->win[1].len;
}
/* This reserves IO space but doesn't actually enable it */
- if (pcmcia_request_io(p_dev, &p_dev->io) != 0)
+ if (pcmcia_request_io(p_dev) != 0)
return -ENODEV;
}
- if ((cfg->mem.nwin > 0) || (dflt->mem.nwin > 0)) {
- cistpl_mem_t *mem =
- (cfg->mem.nwin) ? &cfg->mem : &dflt->mem;
- req->Attributes = WIN_DATA_WIDTH_16 | WIN_MEMORY_TYPE_CM;
- req->Attributes |= WIN_ENABLE;
- req->Base = mem->win[0].host_addr;
- req->Size = mem->win[0].len;
- if (req->Size < 0x1000)
- req->Size = 0x1000;
- req->AccessSpeed = 0;
- if (pcmcia_request_window(p_dev, req, &p_dev->win))
- return -ENODEV;
- map.Page = 0;
- map.CardOffset = mem->win[0].card_addr;
- if (pcmcia_map_mem_page(p_dev, p_dev->win, &map))
- return -ENODEV;
- }
/* If we got this far, we're cool! */
return 0;
}
@@ -623,7 +591,7 @@ static void dio700_config(struct pcmcia_device *link)
dev_dbg(&link->dev, "dio700_config\n");
- ret = pcmcia_loop_config(link, dio700_pcmcia_config_loop, &req);
+ ret = pcmcia_loop_config(link, dio700_pcmcia_config_loop, NULL);
if (ret) {
dev_warn(&link->dev, "no configuration found\n");
goto failed;
@@ -645,15 +613,10 @@ static void dio700_config(struct pcmcia_device *link)
dev_info(&link->dev, "index 0x%02x", link->conf.ConfigIndex);
if (link->conf.Attributes & CONF_ENABLE_IRQ)
printk(", irq %d", link->irq);
- if (link->io.NumPorts1)
- printk(", io 0x%04x-0x%04x", link->io.BasePort1,
- link->io.BasePort1 + link->io.NumPorts1 - 1);
- if (link->io.NumPorts2)
- printk(" & 0x%04x-0x%04x", link->io.BasePort2,
- link->io.BasePort2 + link->io.NumPorts2 - 1);
- if (link->win)
- printk(", mem 0x%06lx-0x%06lx", req.Base,
- req.Base + req.Size - 1);
+ if (link->resource[0])
+ printk(", io %pR", link->resource[0]);
+ if (link->resource[1])
+ printk(" & %pR", link->resource[1]);
printk("\n");
return;
@@ -723,7 +686,7 @@ struct pcmcia_driver dio700_cs_driver = {
.id_table = dio700_cs_ids,
.owner = THIS_MODULE,
.drv = {
- .name = dev_info,
+ .name = "ni_daq_700",
},
};
diff --git a/drivers/staging/comedi/drivers/ni_daq_dio24.c b/drivers/staging/comedi/drivers/ni_daq_dio24.c
index e4865b1c231..773ae2044e0 100644
--- a/drivers/staging/comedi/drivers/ni_daq_dio24.c
+++ b/drivers/staging/comedi/drivers/ni_daq_dio24.c
@@ -48,7 +48,6 @@ the PCMCIA interface.
#include "8255.h"
-#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/cistpl.h>
#include <pcmcia/cisreg.h>
@@ -129,7 +128,7 @@ static int dio24_attach(struct comedi_device *dev, struct comedi_devconfig *it)
link = pcmcia_cur_dev; /* XXX hack */
if (!link)
return -EIO;
- iobase = link->io.BasePort1;
+ iobase = link->resource[0]->start;
#ifdef incomplete
irq = link->irq;
#endif
@@ -211,14 +210,6 @@ static void dio24_cs_detach(struct pcmcia_device *);
less on other parts of the kernel.
*/
-/*
- The dev_info variable is the "key" that is used to match up this
- device driver with appropriate cards, through the card configuration
- database.
-*/
-
-static const dev_info_t dev_info = "ni_daq_dio24";
-
struct local_info_t {
struct pcmcia_device *link;
int stop;
@@ -289,8 +280,7 @@ static void dio24_cs_detach(struct pcmcia_device *link)
dio24_release(link);
/* This points to the parent local_info_t struct */
- if (link->priv)
- kfree(link->priv);
+ kfree(link->priv);
} /* dio24_cs_detach */
@@ -308,9 +298,6 @@ static int dio24_pcmcia_config_loop(struct pcmcia_device *p_dev,
unsigned int vcc,
void *priv_data)
{
- win_req_t *req = priv_data;
- memreq_t map;
-
if (cfg->index == 0)
return -ENODEV;
@@ -324,44 +311,25 @@ static int dio24_pcmcia_config_loop(struct pcmcia_device *p_dev,
p_dev->conf.Attributes |= CONF_ENABLE_IRQ;
/* IO window settings */
- p_dev->io.NumPorts1 = p_dev->io.NumPorts2 = 0;
+ p_dev->resource[0]->end = p_dev->resource[1]->end = 0;
if ((cfg->io.nwin > 0) || (dflt->io.nwin > 0)) {
cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt->io;
- p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
- if (!(io->flags & CISTPL_IO_8BIT))
- p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_16;
- if (!(io->flags & CISTPL_IO_16BIT))
- p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
- p_dev->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK;
- p_dev->io.BasePort1 = io->win[0].base;
- p_dev->io.NumPorts1 = io->win[0].len;
+ p_dev->io_lines = io->flags & CISTPL_IO_LINES_MASK;
+ p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH;
+ p_dev->resource[0]->flags |=
+ pcmcia_io_cfg_data_width(io->flags);
+ p_dev->resource[0]->start = io->win[0].base;
+ p_dev->resource[0]->end = io->win[0].len;
if (io->nwin > 1) {
- p_dev->io.Attributes2 = p_dev->io.Attributes1;
- p_dev->io.BasePort2 = io->win[1].base;
- p_dev->io.NumPorts2 = io->win[1].len;
+ p_dev->resource[1]->flags = p_dev->resource[0]->flags;
+ p_dev->resource[1]->start = io->win[1].base;
+ p_dev->resource[1]->end = io->win[1].len;
}
/* This reserves IO space but doesn't actually enable it */
- if (pcmcia_request_io(p_dev, &p_dev->io) != 0)
+ if (pcmcia_request_io(p_dev) != 0)
return -ENODEV;
}
- if ((cfg->mem.nwin > 0) || (dflt->mem.nwin > 0)) {
- cistpl_mem_t *mem =
- (cfg->mem.nwin) ? &cfg->mem : &dflt->mem;
- req->Attributes = WIN_DATA_WIDTH_16 | WIN_MEMORY_TYPE_CM;
- req->Attributes |= WIN_ENABLE;
- req->Base = mem->win[0].host_addr;
- req->Size = mem->win[0].len;
- if (req->Size < 0x1000)
- req->Size = 0x1000;
- req->AccessSpeed = 0;
- if (pcmcia_request_window(p_dev, req, &p_dev->win))
- return -ENODEV;
- map.Page = 0;
- map.CardOffset = mem->win[0].card_addr;
- if (pcmcia_map_mem_page(p_dev, p_dev->win, &map))
- return -ENODEV;
- }
/* If we got this far, we're cool! */
return 0;
}
@@ -369,13 +337,12 @@ static int dio24_pcmcia_config_loop(struct pcmcia_device *p_dev,
static void dio24_config(struct pcmcia_device *link)
{
int ret;
- win_req_t req;
printk(KERN_INFO "ni_daq_dio24: HOLA SOY YO! - config\n");
dev_dbg(&link->dev, "dio24_config\n");
- ret = pcmcia_loop_config(link, dio24_pcmcia_config_loop, &req);
+ ret = pcmcia_loop_config(link, dio24_pcmcia_config_loop, NULL);
if (ret) {
dev_warn(&link->dev, "no configuration found\n");
goto failed;
@@ -397,15 +364,10 @@ static void dio24_config(struct pcmcia_device *link)
dev_info(&link->dev, "index 0x%02x", link->conf.ConfigIndex);
if (link->conf.Attributes & CONF_ENABLE_IRQ)
printk(", irq %d", link->irq);
- if (link->io.NumPorts1)
- printk(", io 0x%04x-0x%04x", link->io.BasePort1,
- link->io.BasePort1 + link->io.NumPorts1 - 1);
- if (link->io.NumPorts2)
- printk(" & 0x%04x-0x%04x", link->io.BasePort2,
- link->io.BasePort2 + link->io.NumPorts2 - 1);
- if (link->win)
- printk(", mem 0x%06lx-0x%06lx", req.Base,
- req.Base + req.Size - 1);
+ if (link->resource[0])
+ printk(" & %pR", link->resource[0]);
+ if (link->resource[1])
+ printk(" & %pR", link->resource[1]);
printk("\n");
return;
@@ -474,7 +436,7 @@ struct pcmcia_driver dio24_cs_driver = {
.id_table = dio24_cs_ids,
.owner = THIS_MODULE,
.drv = {
- .name = dev_info,
+ .name = "ni_daq_dio24",
},
};
diff --git a/drivers/staging/comedi/drivers/ni_labpc.c b/drivers/staging/comedi/drivers/ni_labpc.c
index 67c8a538802..3acf7e62bec 100644
--- a/drivers/staging/comedi/drivers/ni_labpc.c
+++ b/drivers/staging/comedi/drivers/ni_labpc.c
@@ -526,7 +526,8 @@ int labpc_common_attach(struct comedi_device *dev, unsigned long iobase,
unsigned long dma_flags, isr_flags;
short lsb, msb;
- printk("comedi%d: ni_labpc: %s, io 0x%lx", dev->minor, thisboard->name,
+ printk(KERN_ERR "comedi%d: ni_labpc: %s, io 0x%lx", dev->minor,
+ thisboard->name,
iobase);
if (irq)
printk(", irq %u", irq);
@@ -543,7 +544,7 @@ int labpc_common_attach(struct comedi_device *dev, unsigned long iobase,
/* check if io addresses are available */
if (!request_region(iobase, LABPC_SIZE,
driver_labpc.driver_name)) {
- printk("I/O port conflict\n");
+ printk(KERN_ERR "I/O port conflict\n");
return -EIO;
}
}
@@ -575,7 +576,7 @@ int labpc_common_attach(struct comedi_device *dev, unsigned long iobase,
isr_flags |= IRQF_SHARED;
if (request_irq(irq, labpc_interrupt, isr_flags,
driver_labpc.driver_name, dev)) {
- printk("unable to allocate irq %u\n", irq);
+ printk(KERN_ERR "unable to allocate irq %u\n", irq);
return -EINVAL;
}
}
@@ -583,18 +584,18 @@ int labpc_common_attach(struct comedi_device *dev, unsigned long iobase,
/* grab dma channel */
if (dma_chan > 3) {
- printk(" invalid dma channel %u\n", dma_chan);
+ printk(KERN_ERR " invalid dma channel %u\n", dma_chan);
return -EINVAL;
} else if (dma_chan) {
/* allocate dma buffer */
devpriv->dma_buffer =
kmalloc(dma_buffer_size, GFP_KERNEL | GFP_DMA);
if (devpriv->dma_buffer == NULL) {
- printk(" failed to allocate dma buffer\n");
+ printk(KERN_ERR " failed to allocate dma buffer\n");
return -ENOMEM;
}
if (request_dma(dma_chan, driver_labpc.driver_name)) {
- printk(" failed to allocate dma channel %u\n",
+ printk(KERN_ERR " failed to allocate dma channel %u\n",
dma_chan);
return -EINVAL;
}
@@ -690,7 +691,7 @@ int labpc_common_attach(struct comedi_device *dev, unsigned long iobase,
for (i = 0; i < EEPROM_SIZE; i++)
devpriv->eeprom_data[i] = labpc_eeprom_read(dev, i);
#ifdef LABPC_DEBUG
- printk(" eeprom:");
+ printk(KERN_ERR " eeprom:");
for (i = 0; i < EEPROM_SIZE; i++)
printk(" %i:0x%x ", i, devpriv->eeprom_data[i]);
printk("\n");
@@ -732,7 +733,8 @@ static int labpc_attach(struct comedi_device *dev, struct comedi_devconfig *it)
iobase = (unsigned long)devpriv->mite->daq_io_addr;
irq = mite_irq(devpriv->mite);
#else
- printk(" this driver has not been built with PCI support.\n");
+ printk(KERN_ERR " this driver has not been built with PCI "
+ "support.\n");
return -EINVAL;
#endif
break;
@@ -742,7 +744,7 @@ static int labpc_attach(struct comedi_device *dev, struct comedi_devconfig *it)
return -EINVAL;
break;
default:
- printk("bug! couldn't determine board type\n");
+ printk(KERN_ERR "bug! couldn't determine board type\n");
return -EINVAL;
break;
}
@@ -776,7 +778,7 @@ static int labpc_find_device(struct comedi_device *dev, int bus, int slot)
}
}
}
- printk("no device found\n");
+ printk(KERN_ERR "no device found\n");
mite_list_devices();
return -EIO;
}
@@ -784,7 +786,7 @@ static int labpc_find_device(struct comedi_device *dev, int bus, int slot)
int labpc_common_detach(struct comedi_device *dev)
{
- printk("comedi%d: ni_labpc: detach\n", dev->minor);
+ printk(KERN_ERR "comedi%d: ni_labpc: detach\n", dev->minor);
if (dev->subdevices)
subdev_8255_cleanup(dev, dev->subdevices + 2);
@@ -846,7 +848,7 @@ static enum scan_mode labpc_ai_scan_mode(const struct comedi_cmd *cmd)
if (CR_CHAN(cmd->chanlist[0]) > CR_CHAN(cmd->chanlist[1]))
return MODE_MULT_CHAN_DOWN;
- printk("ni_labpc: bug! this should never happen\n");
+ printk(KERN_ERR "ni_labpc: bug! this should never happen\n");
return 0;
}
@@ -902,7 +904,7 @@ static int labpc_ai_chanlist_invalid(const struct comedi_device *dev,
}
break;
default:
- printk("ni_labpc: bug! in chanlist check\n");
+ printk(KERN_ERR "ni_labpc: bug! in chanlist check\n");
return 1;
break;
}
@@ -1096,7 +1098,10 @@ static int labpc_ai_cmdtest(struct comedi_device *dev,
err++;
}
break;
- /* TRIG_EXT doesn't care since it doesn't trigger off a numbered channel */
+ /*
+ * TRIG_EXT doesn't care since it doesn't
+ * trigger off a numbered channel
+ */
default:
break;
}
@@ -1154,25 +1159,35 @@ static int labpc_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
/* setup hardware conversion counter */
if (cmd->stop_src == TRIG_EXT) {
- /* load counter a1 with count of 3 (pc+ manual says this is minimum allowed) using mode 0 */
+ /*
+ * load counter a1 with count of 3
+ * (pc+ manual says this is minimum allowed) using mode 0
+ */
ret = labpc_counter_load(dev, dev->iobase + COUNTER_A_BASE_REG,
1, 3, 0);
if (ret < 0) {
comedi_error(dev, "error loading counter a1");
return -1;
}
- } else /* otherwise, just put a1 in mode 0 with no count to set its output low */
+ } else /*
+ * otherwise, just put a1 in mode 0
+ * with no count to set its output low
+ */
devpriv->write_byte(INIT_A1_BITS,
dev->iobase + COUNTER_A_CONTROL_REG);
/* figure out what method we will use to transfer data */
if (devpriv->dma_chan && /* need a dma channel allocated */
- /* dma unsafe at RT priority, and too much setup time for TRIG_WAKE_EOS for */
+ /*
+ * dma unsafe at RT priority,
+ * and too much setup time for TRIG_WAKE_EOS for
+ */
(cmd->flags & (TRIG_WAKE_EOS | TRIG_RT)) == 0 &&
/* only available on the isa boards */
thisboard->bustype == isa_bustype) {
xfer = isa_dma_transfer;
- } else if (thisboard->register_layout == labpc_1200_layout && /* pc-plus has no fifo-half full interrupt */
+ /* pc-plus has no fifo-half full interrupt */
+ } else if (thisboard->register_layout == labpc_1200_layout &&
/* wake-end-of-scan should interrupt on fifo not empty */
(cmd->flags & TRIG_WAKE_EOS) == 0 &&
/* make sure we are taking more than just a few points */
@@ -1619,7 +1634,10 @@ static int labpc_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
devpriv->command4_bits |= ADC_DIFF_BIT;
devpriv->write_byte(devpriv->command4_bits, dev->iobase + COMMAND4_REG);
- /* initialize pacer counter output to make sure it doesn't cause any problems */
+ /*
+ * initialize pacer counter output to make sure it doesn't
+ * cause any problems
+ */
devpriv->write_byte(INIT_A0_BITS, dev->iobase + COUNTER_A_CONTROL_REG);
labpc_clear_adc_fifo(dev);
@@ -1844,7 +1862,10 @@ static void labpc_adc_timing(struct comedi_device *dev, struct comedi_cmd *cmd)
unsigned int scan_period;
scan_period = labpc_ai_scan_period(cmd);
- /* calculate cascaded counter values that give desired scan timing */
+ /*
+ * calculate cascaded counter values
+ * that give desired scan timing
+ */
i8253_cascade_ns_to_timer_2div(LABPC_TIMER_BASE,
&(devpriv->divisor_b1),
&(devpriv->divisor_b0),
@@ -1855,7 +1876,10 @@ static void labpc_adc_timing(struct comedi_device *dev, struct comedi_cmd *cmd)
unsigned int convert_period;
convert_period = labpc_ai_convert_period(cmd);
- /* calculate cascaded counter values that give desired conversion timing */
+ /*
+ * calculate cascaded counter values
+ * that give desired conversion timing
+ */
i8253_cascade_ns_to_timer_2div(LABPC_TIMER_BASE,
&(devpriv->divisor_a0),
&(devpriv->divisor_b0),
@@ -2076,9 +2100,56 @@ static void write_caldac(struct comedi_device *dev, unsigned int channel,
}
#ifdef CONFIG_COMEDI_PCI
-COMEDI_PCI_INITCLEANUP(driver_labpc, labpc_pci_table);
+static int __devinit driver_labpc_pci_probe(struct pci_dev *dev,
+ const struct pci_device_id *ent)
+{
+ return comedi_pci_auto_config(dev, driver_labpc.driver_name);
+}
+
+static void __devexit driver_labpc_pci_remove(struct pci_dev *dev)
+{
+ comedi_pci_auto_unconfig(dev);
+}
+
+static struct pci_driver driver_labpc_pci_driver = {
+ .id_table = labpc_pci_table,
+ .probe = &driver_labpc_pci_probe,
+ .remove = __devexit_p(&driver_labpc_pci_remove)
+};
+
+static int __init driver_labpc_init_module(void)
+{
+ int retval;
+
+ retval = comedi_driver_register(&driver_labpc);
+ if (retval < 0)
+ return retval;
+
+ driver_labpc_pci_driver.name = (char *)driver_labpc.driver_name;
+ return pci_register_driver(&driver_labpc_pci_driver);
+}
+
+static void __exit driver_labpc_cleanup_module(void)
+{
+ pci_unregister_driver(&driver_labpc_pci_driver);
+ comedi_driver_unregister(&driver_labpc);
+}
+
+module_init(driver_labpc_init_module);
+module_exit(driver_labpc_cleanup_module);
#else
-COMEDI_INITCLEANUP(driver_labpc);
+static int __init driver_labpc_init_module(void)
+{
+ return comedi_driver_register(&driver_labpc);
+}
+
+static void __exit driver_labpc_cleanup_module(void)
+{
+ comedi_driver_unregister(&driver_labpc);
+}
+
+module_init(driver_labpc_init_module);
+module_exit(driver_labpc_cleanup_module);
#endif
EXPORT_SYMBOL_GPL(labpc_common_attach);
@@ -2086,3 +2157,7 @@ EXPORT_SYMBOL_GPL(labpc_common_detach);
EXPORT_SYMBOL_GPL(range_labpc_1200_ai);
EXPORT_SYMBOL_GPL(labpc_1200_ai_gain_bits);
EXPORT_SYMBOL_GPL(labpc_1200_is_unipolar);
+
+MODULE_AUTHOR("Comedi http://www.comedi.org");
+MODULE_DESCRIPTION("Comedi low-level driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/ni_labpc_cs.c b/drivers/staging/comedi/drivers/ni_labpc_cs.c
index 163245ebb31..68c4ecbd93a 100644
--- a/drivers/staging/comedi/drivers/ni_labpc_cs.c
+++ b/drivers/staging/comedi/drivers/ni_labpc_cs.c
@@ -71,7 +71,6 @@ NI manuals:
#include "comedi_fc.h"
#include "ni_labpc.h"
-#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/cistpl.h>
#include <pcmcia/cisreg.h>
@@ -143,7 +142,7 @@ static int labpc_attach(struct comedi_device *dev, struct comedi_devconfig *it)
link = pcmcia_cur_dev; /* XXX hack */
if (!link)
return -EIO;
- iobase = link->io.BasePort1;
+ iobase = link->resource[0]->start;
irq = link->irq;
break;
default:
@@ -189,14 +188,6 @@ static void labpc_cs_detach(struct pcmcia_device *);
less on other parts of the kernel.
*/
-/*
- The dev_info variable is the "key" that is used to match up this
- device driver with appropriate cards, through the card configuration
- database.
-*/
-
-static const dev_info_t dev_info = "daqcard-1200";
-
struct local_info_t {
struct pcmcia_device *link;
int stop;
@@ -286,9 +277,6 @@ static int labpc_pcmcia_config_loop(struct pcmcia_device *p_dev,
unsigned int vcc,
void *priv_data)
{
- win_req_t *req = priv_data;
- memreq_t map;
-
if (cfg->index == 0)
return -ENODEV;
@@ -302,44 +290,25 @@ static int labpc_pcmcia_config_loop(struct pcmcia_device *p_dev,
p_dev->conf.Attributes |= CONF_ENABLE_IRQ | CONF_ENABLE_PULSE_IRQ;
/* IO window settings */
- p_dev->io.NumPorts1 = p_dev->io.NumPorts2 = 0;
+ p_dev->resource[0]->end = p_dev->resource[1]->end = 0;
if ((cfg->io.nwin > 0) || (dflt->io.nwin > 0)) {
cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt->io;
- p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
- if (!(io->flags & CISTPL_IO_8BIT))
- p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_16;
- if (!(io->flags & CISTPL_IO_16BIT))
- p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
- p_dev->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK;
- p_dev->io.BasePort1 = io->win[0].base;
- p_dev->io.NumPorts1 = io->win[0].len;
+ p_dev->io_lines = io->flags & CISTPL_IO_LINES_MASK;
+ p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH;
+ p_dev->resource[0]->flags |=
+ pcmcia_io_cfg_data_width(io->flags);
+ p_dev->resource[0]->start = io->win[0].base;
+ p_dev->resource[0]->end = io->win[0].len;
if (io->nwin > 1) {
- p_dev->io.Attributes2 = p_dev->io.Attributes1;
- p_dev->io.BasePort2 = io->win[1].base;
- p_dev->io.NumPorts2 = io->win[1].len;
+ p_dev->resource[1]->flags = p_dev->resource[0]->flags;
+ p_dev->resource[1]->start = io->win[1].base;
+ p_dev->resource[1]->end = io->win[1].len;
}
/* This reserves IO space but doesn't actually enable it */
- if (pcmcia_request_io(p_dev, &p_dev->io) != 0)
+ if (pcmcia_request_io(p_dev) != 0)
return -ENODEV;
}
- if ((cfg->mem.nwin > 0) || (dflt->mem.nwin > 0)) {
- cistpl_mem_t *mem =
- (cfg->mem.nwin) ? &cfg->mem : &dflt->mem;
- req->Attributes = WIN_DATA_WIDTH_16 | WIN_MEMORY_TYPE_CM;
- req->Attributes |= WIN_ENABLE;
- req->Base = mem->win[0].host_addr;
- req->Size = mem->win[0].len;
- if (req->Size < 0x1000)
- req->Size = 0x1000;
- req->AccessSpeed = 0;
- if (pcmcia_request_window(p_dev, req, &p_dev->win))
- return -ENODEV;
- map.Page = 0;
- map.CardOffset = mem->win[0].card_addr;
- if (pcmcia_map_mem_page(p_dev, p_dev->win, &map))
- return -ENODEV;
- }
/* If we got this far, we're cool! */
return 0;
}
@@ -348,11 +317,10 @@ static int labpc_pcmcia_config_loop(struct pcmcia_device *p_dev,
static void labpc_config(struct pcmcia_device *link)
{
int ret;
- win_req_t req;
dev_dbg(&link->dev, "labpc_config\n");
- ret = pcmcia_loop_config(link, labpc_pcmcia_config_loop, &req);
+ ret = pcmcia_loop_config(link, labpc_pcmcia_config_loop, NULL);
if (ret) {
dev_warn(&link->dev, "no configuration found\n");
goto failed;
@@ -374,15 +342,10 @@ static void labpc_config(struct pcmcia_device *link)
dev_info(&link->dev, "index 0x%02x", link->conf.ConfigIndex);
if (link->conf.Attributes & CONF_ENABLE_IRQ)
printk(", irq %d", link->irq);
- if (link->io.NumPorts1)
- printk(", io 0x%04x-0x%04x", link->io.BasePort1,
- link->io.BasePort1 + link->io.NumPorts1 - 1);
- if (link->io.NumPorts2)
- printk(" & 0x%04x-0x%04x", link->io.BasePort2,
- link->io.BasePort2 + link->io.NumPorts2 - 1);
- if (link->win)
- printk(", mem 0x%06lx-0x%06lx", req.Base,
- req.Base + req.Size - 1);
+ if (link->resource[0])
+ printk(" & %pR", link->resource[0]);
+ if (link->resource[1])
+ printk(" & %pR", link->resource[1]);
printk("\n");
return;
@@ -449,7 +412,7 @@ struct pcmcia_driver labpc_cs_driver = {
.id_table = labpc_cs_ids,
.owner = THIS_MODULE,
.drv = {
- .name = dev_info,
+ .name = "daqcard-1200",
},
};
diff --git a/drivers/staging/comedi/drivers/ni_mio_cs.c b/drivers/staging/comedi/drivers/ni_mio_cs.c
index 3a46f0c0bff..1f2426352eb 100644
--- a/drivers/staging/comedi/drivers/ni_mio_cs.c
+++ b/drivers/staging/comedi/drivers/ni_mio_cs.c
@@ -48,7 +48,6 @@ See the notes in the ni_atmio.o driver.
#include "ni_stc.h"
#include "8255.h"
-#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/cistpl.h>
#include <pcmcia/ds.h>
@@ -261,12 +260,11 @@ static void cs_release(struct pcmcia_device *link);
static void cs_detach(struct pcmcia_device *);
static struct pcmcia_device *cur_dev = NULL;
-static const dev_info_t dev_info = "ni_mio_cs";
static int cs_attach(struct pcmcia_device *link)
{
- link->io.Attributes1 = IO_DATA_PATH_WIDTH_16;
- link->io.NumPorts1 = 16;
+ link->resource[0]->flags |= IO_DATA_PATH_WIDTH_16;
+ link->resource[0]->end = 16;
link->conf.Attributes = CONF_ENABLE_IRQ;
link->conf.IntType = INT_MEMORY_AND_IO;
@@ -311,13 +309,12 @@ static int mio_pcmcia_config_loop(struct pcmcia_device *p_dev,
{
int base, ret;
- p_dev->io.NumPorts1 = cfg->io.win[0].len;
- p_dev->io.IOAddrLines = cfg->io.flags & CISTPL_IO_LINES_MASK;
- p_dev->io.NumPorts2 = 0;
+ p_dev->resource[0]->end = cfg->io.win[0].len;
+ p_dev->io_lines = cfg->io.flags & CISTPL_IO_LINES_MASK;
for (base = 0x000; base < 0x400; base += 0x20) {
- p_dev->io.BasePort1 = base;
- ret = pcmcia_request_io(p_dev, &p_dev->io);
+ p_dev->resource[0]->start = base;
+ ret = pcmcia_request_io(p_dev);
if (!ret)
return 0;
}
@@ -356,7 +353,7 @@ static int mio_cs_attach(struct comedi_device *dev, struct comedi_devconfig *it)
return -EIO;
dev->driver = &driver_ni_mio_cs;
- dev->iobase = link->io.BasePort1;
+ dev->iobase = link->resource[0]->start;
irq = link->irq;
@@ -450,7 +447,7 @@ struct pcmcia_driver ni_mio_cs_driver = {
.id_table = ni_mio_cs_ids,
.owner = THIS_MODULE,
.drv = {
- .name = dev_info,
+ .name = "ni_mio_cs",
},
};
diff --git a/drivers/staging/comedi/drivers/ni_pcidio.c b/drivers/staging/comedi/drivers/ni_pcidio.c
index b126638d33b..84a15c34e48 100644
--- a/drivers/staging/comedi/drivers/ni_pcidio.c
+++ b/drivers/staging/comedi/drivers/ni_pcidio.c
@@ -1317,4 +1317,40 @@ static int nidio_find_device(struct comedi_device *dev, int bus, int slot)
return -EIO;
}
-COMEDI_PCI_INITCLEANUP(driver_pcidio, ni_pcidio_pci_table);
+static int __devinit driver_pcidio_pci_probe(struct pci_dev *dev,
+ const struct pci_device_id *ent)
+{
+ return comedi_pci_auto_config(dev, driver_pcidio.driver_name);
+}
+
+static void __devexit driver_pcidio_pci_remove(struct pci_dev *dev)
+{
+ comedi_pci_auto_unconfig(dev);
+}
+
+static struct pci_driver driver_pcidio_pci_driver = {
+ .id_table = ni_pcidio_pci_table,
+ .probe = &driver_pcidio_pci_probe,
+ .remove = __devexit_p(&driver_pcidio_pci_remove)
+};
+
+static int __init driver_pcidio_init_module(void)
+{
+ int retval;
+
+ retval = comedi_driver_register(&driver_pcidio);
+ if (retval < 0)
+ return retval;
+
+ driver_pcidio_pci_driver.name = (char *)driver_pcidio.driver_name;
+ return pci_register_driver(&driver_pcidio_pci_driver);
+}
+
+static void __exit driver_pcidio_cleanup_module(void)
+{
+ pci_unregister_driver(&driver_pcidio_pci_driver);
+ comedi_driver_unregister(&driver_pcidio);
+}
+
+module_init(driver_pcidio_init_module);
+module_exit(driver_pcidio_cleanup_module);
diff --git a/drivers/staging/comedi/drivers/ni_pcimio.c b/drivers/staging/comedi/drivers/ni_pcimio.c
index 577fda84190..23a38124728 100644
--- a/drivers/staging/comedi/drivers/ni_pcimio.c
+++ b/drivers/staging/comedi/drivers/ni_pcimio.c
@@ -1239,7 +1239,43 @@ static struct comedi_driver driver_pcimio = {
.detach = pcimio_detach,
};
-COMEDI_PCI_INITCLEANUP(driver_pcimio, ni_pci_table)
+static int __devinit driver_pcimio_pci_probe(struct pci_dev *dev,
+ const struct pci_device_id *ent)
+{
+ return comedi_pci_auto_config(dev, driver_pcimio.driver_name);
+}
+
+static void __devexit driver_pcimio_pci_remove(struct pci_dev *dev)
+{
+ comedi_pci_auto_unconfig(dev);
+}
+
+static struct pci_driver driver_pcimio_pci_driver = {
+ .id_table = ni_pci_table,
+ .probe = &driver_pcimio_pci_probe,
+ .remove = __devexit_p(&driver_pcimio_pci_remove)
+};
+
+static int __init driver_pcimio_init_module(void)
+{
+ int retval;
+
+ retval = comedi_driver_register(&driver_pcimio);
+ if (retval < 0)
+ return retval;
+
+ driver_pcimio_pci_driver.name = (char *)driver_pcimio.driver_name;
+ return pci_register_driver(&driver_pcimio_pci_driver);
+}
+
+static void __exit driver_pcimio_cleanup_module(void)
+{
+ pci_unregister_driver(&driver_pcimio_pci_driver);
+ comedi_driver_unregister(&driver_pcimio);
+}
+
+module_init(driver_pcimio_init_module);
+module_exit(driver_pcimio_cleanup_module);
struct ni_private {
NI_PRIVATE_COMMON};
diff --git a/drivers/staging/comedi/drivers/ni_tio.c b/drivers/staging/comedi/drivers/ni_tio.c
index 13e5b264ff0..a9bb6b13dfc 100644
--- a/drivers/staging/comedi/drivers/ni_tio.c
+++ b/drivers/staging/comedi/drivers/ni_tio.c
@@ -302,7 +302,7 @@ struct ni_gpct_device *ni_gpct_device_construct(struct comedi_device *dev,
ni_gpct_register
reg),
unsigned (*read_register)
- (struct ni_gpct * counter,
+ (struct ni_gpct *counter,
enum ni_gpct_register reg),
enum ni_gpct_variant variant,
unsigned num_counters)
@@ -332,6 +332,7 @@ struct ni_gpct_device *ni_gpct_device_construct(struct comedi_device *dev,
counter_dev->num_counters = num_counters;
return counter_dev;
}
+EXPORT_SYMBOL_GPL(ni_gpct_device_construct);
void ni_gpct_device_destroy(struct ni_gpct_device *counter_dev)
{
@@ -340,6 +341,7 @@ void ni_gpct_device_destroy(struct ni_gpct_device *counter_dev)
kfree(counter_dev->counters);
kfree(counter_dev);
}
+EXPORT_SYMBOL_GPL(ni_gpct_device_destroy);
static int ni_tio_second_gate_registers_present(const struct ni_gpct_device
*counter_dev)
@@ -418,6 +420,7 @@ void ni_tio_init_counter(struct ni_gpct *counter)
NITIO_Gi_Interrupt_Enable_Reg(counter->counter_index),
~0, 0x0);
}
+EXPORT_SYMBOL_GPL(ni_tio_init_counter);
static unsigned int ni_tio_counter_status(struct ni_gpct *counter)
{
@@ -446,9 +449,7 @@ static void ni_tio_set_sync_mode(struct ni_gpct *counter, int force_alt_sync)
if (ni_tio_counting_mode_registers_present(counter_dev) == 0)
return;
- switch (ni_tio_get_soft_copy(counter,
- counting_mode_reg) & Gi_Counting_Mode_Mask)
- {
+ switch (ni_tio_get_soft_copy(counter, counting_mode_reg) & Gi_Counting_Mode_Mask) {
case Gi_Counting_Mode_QuadratureX1_Bits:
case Gi_Counting_Mode_QuadratureX2_Bits:
case Gi_Counting_Mode_QuadratureX4_Bits:
@@ -513,9 +514,8 @@ static int ni_tio_set_counter_mode(struct ni_gpct *counter, unsigned mode)
counting_mode_bits |=
((mode >> NI_GPCT_INDEX_PHASE_BITSHIFT) <<
Gi_Index_Phase_Bitshift) & Gi_Index_Phase_Mask;
- if (mode & NI_GPCT_INDEX_ENABLE_BIT) {
+ if (mode & NI_GPCT_INDEX_ENABLE_BIT)
counting_mode_bits |= Gi_Index_Mode_Bit;
- }
ni_tio_set_bits(counter,
NITIO_Gi_Counting_Mode_Reg(counter->
counter_index),
@@ -529,12 +529,10 @@ static int ni_tio_set_counter_mode(struct ni_gpct *counter, unsigned mode)
(mode >> NI_GPCT_COUNTING_DIRECTION_SHIFT) <<
Gi_Up_Down_Shift);
- if (mode & NI_GPCT_OR_GATE_BIT) {
+ if (mode & NI_GPCT_OR_GATE_BIT)
input_select_bits |= Gi_Or_Gate_Bit;
- }
- if (mode & NI_GPCT_INVERT_OUTPUT_BIT) {
+ if (mode & NI_GPCT_INVERT_OUTPUT_BIT)
input_select_bits |= Gi_Output_Polarity_Bit;
- }
ni_tio_set_bits(counter,
NITIO_Gi_Input_Select_Reg(counter->counter_index),
Gi_Gate_Select_Load_Source_Bit | Gi_Or_Gate_Bit |
@@ -600,6 +598,7 @@ int ni_tio_arm(struct ni_gpct *counter, int arm, unsigned start_trigger)
0, 0, command_transient_bits);
return 0;
}
+EXPORT_SYMBOL_GPL(ni_tio_arm);
static unsigned ni_660x_source_select_bits(unsigned int clock_source)
{
@@ -706,7 +705,7 @@ static unsigned ni_m_series_source_select_bits(unsigned int clock_source)
}
if (i <= ni_m_series_max_pfi_channel)
break;
- printk("invalid clock source 0x%lx\n",
+ printk(KERN_ERR "invalid clock source 0x%lx\n",
(unsigned long)clock_source);
BUG();
ni_m_series_clock = 0;
@@ -1026,14 +1025,12 @@ static void ni_tio_set_first_gate_modifiers(struct ni_gpct *counter,
const unsigned mode_mask = Gi_Gate_Polarity_Bit | Gi_Gating_Mode_Mask;
unsigned mode_values = 0;
- if (gate_source & CR_INVERT) {
+ if (gate_source & CR_INVERT)
mode_values |= Gi_Gate_Polarity_Bit;
- }
- if (gate_source & CR_EDGE) {
+ if (gate_source & CR_EDGE)
mode_values |= Gi_Rising_Edge_Gating_Bits;
- } else {
+ else
mode_values |= Gi_Level_Gating_Bits;
- }
ni_tio_set_bits(counter, NITIO_Gi_Mode_Reg(counter->counter_index),
mode_mask, mode_values);
}
@@ -1290,6 +1287,7 @@ int ni_tio_set_gate_src(struct ni_gpct *counter, unsigned gate_index,
}
return 0;
}
+EXPORT_SYMBOL_GPL(ni_tio_set_gate_src);
static int ni_tio_set_other_src(struct ni_gpct *counter, unsigned index,
unsigned int source)
@@ -1531,12 +1529,10 @@ static int ni_tio_get_gate_src(struct ni_gpct *counter, unsigned gate_index,
BUG();
break;
}
- if (mode_bits & Gi_Gate_Polarity_Bit) {
+ if (mode_bits & Gi_Gate_Polarity_Bit)
*gate_source |= CR_INVERT;
- }
- if ((mode_bits & Gi_Gating_Mode_Mask) != Gi_Level_Gating_Bits) {
+ if ((mode_bits & Gi_Gating_Mode_Mask) != Gi_Level_Gating_Bits)
*gate_source |= CR_EDGE;
- }
break;
case 1:
if ((mode_bits & Gi_Gating_Mode_Mask) == Gi_Gating_Disabled_Bits
@@ -1572,9 +1568,8 @@ static int ni_tio_get_gate_src(struct ni_gpct *counter, unsigned gate_index,
*gate_source |= CR_INVERT;
}
/* second gate can't have edge/level mode set independently */
- if ((mode_bits & Gi_Gating_Mode_Mask) != Gi_Level_Gating_Bits) {
+ if ((mode_bits & Gi_Gating_Mode_Mask) != Gi_Level_Gating_Bits)
*gate_source |= CR_EDGE;
- }
break;
default:
return -EINVAL;
@@ -1627,6 +1622,7 @@ int ni_tio_insn_config(struct ni_gpct *counter,
}
return -EINVAL;
}
+EXPORT_SYMBOL_GPL(ni_tio_insn_config);
int ni_tio_rinsn(struct ni_gpct *counter, struct comedi_insn *insn,
unsigned int *data)
@@ -1681,6 +1677,7 @@ int ni_tio_rinsn(struct ni_gpct *counter, struct comedi_insn *insn,
};
return 0;
}
+EXPORT_SYMBOL_GPL(ni_tio_rinsn);
static unsigned ni_tio_next_load_register(struct ni_gpct *counter)
{
@@ -1688,11 +1685,10 @@ static unsigned ni_tio_next_load_register(struct ni_gpct *counter)
NITIO_Gxx_Status_Reg(counter->
counter_index));
- if (bits & Gi_Next_Load_Source_Bit(counter->counter_index)) {
+ if (bits & Gi_Next_Load_Source_Bit(counter->counter_index))
return NITIO_Gi_LoadB_Reg(counter->counter_index);
- } else {
+ else
return NITIO_Gi_LoadA_Reg(counter->counter_index);
- }
}
int ni_tio_winsn(struct ni_gpct *counter, struct comedi_insn *insn,
@@ -1735,12 +1731,4 @@ int ni_tio_winsn(struct ni_gpct *counter, struct comedi_insn *insn,
}
return 0;
}
-
-EXPORT_SYMBOL_GPL(ni_tio_rinsn);
EXPORT_SYMBOL_GPL(ni_tio_winsn);
-EXPORT_SYMBOL_GPL(ni_tio_insn_config);
-EXPORT_SYMBOL_GPL(ni_tio_init_counter);
-EXPORT_SYMBOL_GPL(ni_tio_arm);
-EXPORT_SYMBOL_GPL(ni_tio_set_gate_src);
-EXPORT_SYMBOL_GPL(ni_gpct_device_construct);
-EXPORT_SYMBOL_GPL(ni_gpct_device_destroy);
diff --git a/drivers/staging/comedi/drivers/pcl711.c b/drivers/staging/comedi/drivers/pcl711.c
index a499f7070f7..b44386a6b63 100644
--- a/drivers/staging/comedi/drivers/pcl711.c
+++ b/drivers/staging/comedi/drivers/pcl711.c
@@ -171,7 +171,18 @@ static struct comedi_driver driver_pcl711 = {
.offset = sizeof(struct pcl711_board),
};
-COMEDI_INITCLEANUP(driver_pcl711);
+static int __init driver_pcl711_init_module(void)
+{
+ return comedi_driver_register(&driver_pcl711);
+}
+
+static void __exit driver_pcl711_cleanup_module(void)
+{
+ comedi_driver_unregister(&driver_pcl711);
+}
+
+module_init(driver_pcl711_init_module);
+module_exit(driver_pcl711_cleanup_module);
struct pcl711_private {
@@ -270,7 +281,7 @@ static int pcl711_ai_insn(struct comedi_device *dev, struct comedi_subdevice *s,
goto ok;
udelay(1);
}
- printk("comedi%d: pcl711: A/D timeout\n", dev->minor);
+ printk(KERN_ERR "comedi%d: pcl711: A/D timeout\n", dev->minor);
return -ETIME;
ok:
@@ -505,7 +516,7 @@ static int pcl711_do_insn_bits(struct comedi_device *dev,
/* Free any resources that we have claimed */
static int pcl711_detach(struct comedi_device *dev)
{
- printk("comedi%d: pcl711: remove\n", dev->minor);
+ printk(KERN_INFO "comedi%d: pcl711: remove\n", dev->minor);
if (dev->irq)
free_irq(dev->irq, dev);
@@ -527,7 +538,7 @@ static int pcl711_attach(struct comedi_device *dev, struct comedi_devconfig *it)
/* claim our I/O space */
iobase = it->options[0];
- printk("comedi%d: pcl711: 0x%04lx ", dev->minor, iobase);
+ printk(KERN_INFO "comedi%d: pcl711: 0x%04lx ", dev->minor, iobase);
if (!request_region(iobase, PCL711_SIZE, "pcl711")) {
printk("I/O port conflict\n");
return -EIO;
@@ -542,15 +553,15 @@ static int pcl711_attach(struct comedi_device *dev, struct comedi_devconfig *it)
/* grab our IRQ */
irq = it->options[1];
if (irq > this_board->maxirq) {
- printk("irq out of range\n");
+ printk(KERN_ERR "irq out of range\n");
return -EINVAL;
}
if (irq) {
if (request_irq(irq, pcl711_interrupt, 0, "pcl711", dev)) {
- printk("unable to allocate irq %u\n", irq);
+ printk(KERN_ERR "unable to allocate irq %u\n", irq);
return -EINVAL;
} else {
- printk("( irq = %u )\n", irq);
+ printk(KERN_INFO "( irq = %u )\n", irq);
}
}
dev->irq = irq;
@@ -624,7 +635,11 @@ static int pcl711_attach(struct comedi_device *dev, struct comedi_devconfig *it)
outb(0, dev->iobase + PCL711_DA1_LO);
outb(0, dev->iobase + PCL711_DA1_HI);
- printk("\n");
+ printk(KERN_INFO "\n");
return 0;
}
+
+MODULE_AUTHOR("Comedi http://www.comedi.org");
+MODULE_DESCRIPTION("Comedi low-level driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/pcl724.c b/drivers/staging/comedi/drivers/pcl724.c
index 0f103c32806..396a058bb67 100644
--- a/drivers/staging/comedi/drivers/pcl724.c
+++ b/drivers/staging/comedi/drivers/pcl724.c
@@ -93,7 +93,18 @@ static struct comedi_driver driver_pcl724 = {
.offset = sizeof(struct pcl724_board),
};
-COMEDI_INITCLEANUP(driver_pcl724);
+static int __init driver_pcl724_init_module(void)
+{
+ return comedi_driver_register(&driver_pcl724);
+}
+
+static void __exit driver_pcl724_cleanup_module(void)
+{
+ comedi_driver_unregister(&driver_pcl724);
+}
+
+module_init(driver_pcl724_init_module);
+module_exit(driver_pcl724_cleanup_module);
static int subdev_8255_cb(int dir, int port, int data, unsigned long arg)
{
@@ -221,3 +232,7 @@ static int pcl724_detach(struct comedi_device *dev)
return 0;
}
+
+MODULE_AUTHOR("Comedi http://www.comedi.org");
+MODULE_DESCRIPTION("Comedi low-level driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/pcl725.c b/drivers/staging/comedi/drivers/pcl725.c
index 60261f4ba5b..24b223ca439 100644
--- a/drivers/staging/comedi/drivers/pcl725.c
+++ b/drivers/staging/comedi/drivers/pcl725.c
@@ -30,7 +30,18 @@ static struct comedi_driver driver_pcl725 = {
.detach = pcl725_detach,
};
-COMEDI_INITCLEANUP(driver_pcl725);
+static int __init driver_pcl725_init_module(void)
+{
+ return comedi_driver_register(&driver_pcl725);
+}
+
+static void __exit driver_pcl725_cleanup_module(void)
+{
+ comedi_driver_unregister(&driver_pcl725);
+}
+
+module_init(driver_pcl725_init_module);
+module_exit(driver_pcl725_cleanup_module);
static int pcl725_do_insn(struct comedi_device *dev, struct comedi_subdevice *s,
struct comedi_insn *insn, unsigned int *data)
@@ -110,3 +121,7 @@ static int pcl725_detach(struct comedi_device *dev)
return 0;
}
+
+MODULE_AUTHOR("Comedi http://www.comedi.org");
+MODULE_DESCRIPTION("Comedi low-level driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/pcl726.c b/drivers/staging/comedi/drivers/pcl726.c
index 6a1a9790a90..897cd808eeb 100644
--- a/drivers/staging/comedi/drivers/pcl726.c
+++ b/drivers/staging/comedi/drivers/pcl726.c
@@ -162,7 +162,18 @@ static struct comedi_driver driver_pcl726 = {
.offset = sizeof(struct pcl726_board),
};
-COMEDI_INITCLEANUP(driver_pcl726);
+static int __init driver_pcl726_init_module(void)
+{
+ return comedi_driver_register(&driver_pcl726);
+}
+
+static void __exit driver_pcl726_cleanup_module(void)
+{
+ comedi_driver_unregister(&driver_pcl726);
+}
+
+module_init(driver_pcl726_init_module);
+module_exit(driver_pcl726_cleanup_module);
struct pcl726_private {
@@ -381,3 +392,7 @@ static int pcl726_detach(struct comedi_device *dev)
return 0;
}
+
+MODULE_AUTHOR("Comedi http://www.comedi.org");
+MODULE_DESCRIPTION("Comedi low-level driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/pcl730.c b/drivers/staging/comedi/drivers/pcl730.c
index e5e7bed21de..c9682d614e0 100644
--- a/drivers/staging/comedi/drivers/pcl730.c
+++ b/drivers/staging/comedi/drivers/pcl730.c
@@ -55,7 +55,18 @@ static struct comedi_driver driver_pcl730 = {
.offset = sizeof(struct pcl730_board),
};
-COMEDI_INITCLEANUP(driver_pcl730);
+static int __init driver_pcl730_init_module(void)
+{
+ return comedi_driver_register(&driver_pcl730);
+}
+
+static void __exit driver_pcl730_cleanup_module(void)
+{
+ comedi_driver_unregister(&driver_pcl730);
+}
+
+module_init(driver_pcl730_init_module);
+module_exit(driver_pcl730_cleanup_module);
static int pcl730_do_insn(struct comedi_device *dev, struct comedi_subdevice *s,
struct comedi_insn *insn, unsigned int *data)
@@ -166,3 +177,7 @@ static int pcl730_detach(struct comedi_device *dev)
return 0;
}
+
+MODULE_AUTHOR("Comedi http://www.comedi.org");
+MODULE_DESCRIPTION("Comedi low-level driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/pcl812.c b/drivers/staging/comedi/drivers/pcl812.c
index 1ddc19c705a..c6dce4a1425 100644
--- a/drivers/staging/comedi/drivers/pcl812.c
+++ b/drivers/staging/comedi/drivers/pcl812.c
@@ -15,97 +15,98 @@
* card: A-823PGH, A-823PGL, A-826PG
* driver: a823pgh, a823pgl, a826pg
*/
+
/*
-Driver: pcl812
-Description: Advantech PCL-812/PG, PCL-813/B,
- ADLink ACL-8112DG/HG/PG, ACL-8113, ACL-8216,
- ICP DAS A-821PGH/PGL/PGL-NDA, A-822PGH/PGL, A-823PGH/PGL, A-826PG,
- ICP DAS ISO-813
-Author: Michal Dobes <dobes@tesnet.cz>
-Devices: [Advantech] PCL-812 (pcl812), PCL-812PG (pcl812pg),
- PCL-813 (pcl813), PCL-813B (pcl813b), [ADLink] ACL-8112DG (acl8112dg),
- ACL-8112HG (acl8112hg), ACL-8113 (acl-8113), ACL-8216 (acl8216),
- [ICP] ISO-813 (iso813), A-821PGH (a821pgh), A-821PGL (a821pgl),
- A-821PGL-NDA (a821pclnda), A-822PGH (a822pgh), A-822PGL (a822pgl),
- A-823PGH (a823pgh), A-823PGL (a823pgl), A-826PG (a826pg)
-Updated: Mon, 06 Aug 2007 12:03:15 +0100
-Status: works (I hope. My board fire up under my hands
- and I cann't test all features.)
-
-This driver supports insn and cmd interfaces. Some boards support only insn
-becouse their hardware don't allow more (PCL-813/B, ACL-8113, ISO-813).
-Data transfer over DMA is supported only when you measure only one
-channel, this is too hardware limitation of these boards.
-
-Options for PCL-812:
- [0] - IO Base
- [1] - IRQ (0=disable, 2, 3, 4, 5, 6, 7; 10, 11, 12, 14, 15)
- [2] - DMA (0=disable, 1, 3)
- [3] - 0=trigger source is internal 8253 with 2MHz clock
- 1=trigger source is external
- [4] - 0=A/D input range is +/-10V
- 1=A/D input range is +/-5V
- 2=A/D input range is +/-2.5V
- 3=A/D input range is +/-1.25V
- 4=A/D input range is +/-0.625V
- 5=A/D input range is +/-0.3125V
- [5] - 0=D/A outputs 0-5V (internal reference -5V)
- 1=D/A outputs 0-10V (internal reference -10V)
- 2=D/A outputs unknown (external reference)
-
-Options for PCL-812PG, ACL-8112PG:
- [0] - IO Base
- [1] - IRQ (0=disable, 2, 3, 4, 5, 6, 7; 10, 11, 12, 14, 15)
- [2] - DMA (0=disable, 1, 3)
- [3] - 0=trigger source is internal 8253 with 2MHz clock
- 1=trigger source is external
- [4] - 0=A/D have max +/-5V input
- 1=A/D have max +/-10V input
- [5] - 0=D/A outputs 0-5V (internal reference -5V)
- 1=D/A outputs 0-10V (internal reference -10V)
- 2=D/A outputs unknown (external reference)
-
-Options for ACL-8112DG/HG, A-822PGL/PGH, A-823PGL/PGH, ACL-8216, A-826PG:
- [0] - IO Base
- [1] - IRQ (0=disable, 2, 3, 4, 5, 6, 7; 10, 11, 12, 14, 15)
- [2] - DMA (0=disable, 1, 3)
- [3] - 0=trigger source is internal 8253 with 2MHz clock
- 1=trigger source is external
- [4] - 0=A/D channels are S.E.
- 1=A/D channels are DIFF
- [5] - 0=D/A outputs 0-5V (internal reference -5V)
- 1=D/A outputs 0-10V (internal reference -10V)
- 2=D/A outputs unknown (external reference)
-
-Options for A-821PGL/PGH:
- [0] - IO Base
- [1] - IRQ (0=disable, 2, 3, 4, 5, 6, 7)
- [2] - 0=A/D channels are S.E.
- 1=A/D channels are DIFF
- [3] - 0=D/A output 0-5V (internal reference -5V)
- 1=D/A output 0-10V (internal reference -10V)
-
-Options for A-821PGL-NDA:
- [0] - IO Base
- [1] - IRQ (0=disable, 2, 3, 4, 5, 6, 7)
- [2] - 0=A/D channels are S.E.
- 1=A/D channels are DIFF
-
-Options for PCL-813:
- [0] - IO Base
-
-Options for PCL-813B:
- [0] - IO Base
- [1] - 0= bipolar inputs
- 1= unipolar inputs
-
-Options for ACL-8113, ISO-813:
- [0] - IO Base
- [1] - 0= 10V bipolar inputs
- 1= 10V unipolar inputs
- 2= 20V bipolar inputs
- 3= 20V unipolar inputs
-*/
+ * Driver: pcl812
+ * Description: Advantech PCL-812/PG, PCL-813/B,
+ * ADLink ACL-8112DG/HG/PG, ACL-8113, ACL-8216,
+ * ICP DAS A-821PGH/PGL/PGL-NDA, A-822PGH/PGL, A-823PGH/PGL, A-826PG,
+ * ICP DAS ISO-813
+ * Author: Michal Dobes <dobes@tesnet.cz>
+ * Devices: [Advantech] PCL-812 (pcl812), PCL-812PG (pcl812pg),
+ * PCL-813 (pcl813), PCL-813B (pcl813b), [ADLink] ACL-8112DG (acl8112dg),
+ * ACL-8112HG (acl8112hg), ACL-8113 (acl-8113), ACL-8216 (acl8216),
+ * [ICP] ISO-813 (iso813), A-821PGH (a821pgh), A-821PGL (a821pgl),
+ * A-821PGL-NDA (a821pclnda), A-822PGH (a822pgh), A-822PGL (a822pgl),
+ * A-823PGH (a823pgh), A-823PGL (a823pgl), A-826PG (a826pg)
+ * Updated: Mon, 06 Aug 2007 12:03:15 +0100
+ * Status: works (I hope. My board fire up under my hands
+ * and I cann't test all features.)
+ *
+ * This driver supports insn and cmd interfaces. Some boards support only insn
+ * becouse their hardware don't allow more (PCL-813/B, ACL-8113, ISO-813).
+ * Data transfer over DMA is supported only when you measure only one
+ * channel, this is too hardware limitation of these boards.
+ *
+ * Options for PCL-812:
+ * [0] - IO Base
+ * [1] - IRQ (0=disable, 2, 3, 4, 5, 6, 7; 10, 11, 12, 14, 15)
+ * [2] - DMA (0=disable, 1, 3)
+ * [3] - 0=trigger source is internal 8253 with 2MHz clock
+ * 1=trigger source is external
+ * [4] - 0=A/D input range is +/-10V
+ * 1=A/D input range is +/-5V
+ * 2=A/D input range is +/-2.5V
+ * 3=A/D input range is +/-1.25V
+ * 4=A/D input range is +/-0.625V
+ * 5=A/D input range is +/-0.3125V
+ * [5] - 0=D/A outputs 0-5V (internal reference -5V)
+ * 1=D/A outputs 0-10V (internal reference -10V)
+ * 2=D/A outputs unknown (external reference)
+ *
+ * Options for PCL-812PG, ACL-8112PG:
+ * [0] - IO Base
+ * [1] - IRQ (0=disable, 2, 3, 4, 5, 6, 7; 10, 11, 12, 14, 15)
+ * [2] - DMA (0=disable, 1, 3)
+ * [3] - 0=trigger source is internal 8253 with 2MHz clock
+ * 1=trigger source is external
+ * [4] - 0=A/D have max +/-5V input
+ * 1=A/D have max +/-10V input
+ * [5] - 0=D/A outputs 0-5V (internal reference -5V)
+ * 1=D/A outputs 0-10V (internal reference -10V)
+ * 2=D/A outputs unknown (external reference)
+ *
+ * Options for ACL-8112DG/HG, A-822PGL/PGH, A-823PGL/PGH, ACL-8216, A-826PG:
+ * [0] - IO Base
+ * [1] - IRQ (0=disable, 2, 3, 4, 5, 6, 7; 10, 11, 12, 14, 15)
+ * [2] - DMA (0=disable, 1, 3)
+ * [3] - 0=trigger source is internal 8253 with 2MHz clock
+ * 1=trigger source is external
+ * [4] - 0=A/D channels are S.E.
+ * 1=A/D channels are DIFF
+ * [5] - 0=D/A outputs 0-5V (internal reference -5V)
+ * 1=D/A outputs 0-10V (internal reference -10V)
+ * 2=D/A outputs unknown (external reference)
+ *
+ * Options for A-821PGL/PGH:
+ * [0] - IO Base
+ * [1] - IRQ (0=disable, 2, 3, 4, 5, 6, 7)
+ * [2] - 0=A/D channels are S.E.
+ * 1=A/D channels are DIFF
+ * [3] - 0=D/A output 0-5V (internal reference -5V)
+ * 1=D/A output 0-10V (internal reference -10V)
+ *
+ * Options for A-821PGL-NDA:
+ * [0] - IO Base
+ * [1] - IRQ (0=disable, 2, 3, 4, 5, 6, 7)
+ * [2] - 0=A/D channels are S.E.
+ * 1=A/D channels are DIFF
+ *
+ * Options for PCL-813:
+ * [0] - IO Base
+ *
+ * Options for PCL-813B:
+ * [0] - IO Base
+ * [1] - 0= bipolar inputs
+ * 1= unipolar inputs
+ *
+ * Options for ACL-8113, ISO-813:
+ * [0] - IO Base
+ * [1] - 0= 10V bipolar inputs
+ * 1= 10V unipolar inputs
+ * 2= 20V bipolar inputs
+ * 3= 20V unipolar inputs
+ */
#include <linux/interrupt.h>
#include <linux/gfp.h>
@@ -117,49 +118,50 @@ Options for ACL-8113, ISO-813:
#include "8253.h"
-#undef PCL812_EXTDEBUG /* if this is defined then a lot of messages is printed */
+/* if this is defined then a lot of messages is printed */
+#undef PCL812_EXTDEBUG
/* hardware types of the cards */
-#define boardPCL812PG 0 /* and ACL-8112PG */
-#define boardPCL813B 1
-#define boardPCL812 2
-#define boardPCL813 3
-#define boardISO813 5
-#define boardACL8113 6
-#define boardACL8112 7 /* ACL-8112DG/HG, A-822PGL/PGH, A-823PGL/PGH */
-#define boardACL8216 8 /* and ICP DAS A-826PG */
-#define boardA821 9 /* PGH, PGL, PGL/NDA versions */
-
-#define PCLx1x_IORANGE 16
-
-#define PCL812_CTR0 0
-#define PCL812_CTR1 1
-#define PCL812_CTR2 2
-#define PCL812_CTRCTL 3
-#define PCL812_AD_LO 4
-#define PCL812_DA1_LO 4
-#define PCL812_AD_HI 5
-#define PCL812_DA1_HI 5
-#define PCL812_DA2_LO 6
-#define PCL812_DI_LO 6
-#define PCL812_DA2_HI 7
-#define PCL812_DI_HI 7
-#define PCL812_CLRINT 8
-#define PCL812_GAIN 9
-#define PCL812_MUX 10
-#define PCL812_MODE 11
-#define PCL812_CNTENABLE 10
-#define PCL812_SOFTTRIG 12
-#define PCL812_DO_LO 13
-#define PCL812_DO_HI 14
-
-#define PCL812_DRDY 0x10 /* =0 data ready */
-
-#define ACL8216_STATUS 8 /* 5. bit signalize data ready */
-
-#define ACL8216_DRDY 0x20 /* =0 data ready */
-
-#define MAX_CHANLIST_LEN 256 /* length of scan list */
+#define boardPCL812PG 0 /* and ACL-8112PG */
+#define boardPCL813B 1
+#define boardPCL812 2
+#define boardPCL813 3
+#define boardISO813 5
+#define boardACL8113 6
+#define boardACL8112 7 /* ACL-8112DG/HG, A-822PGL/PGH, A-823PGL/PGH */
+#define boardACL8216 8 /* and ICP DAS A-826PG */
+#define boardA821 9 /* PGH, PGL, PGL/NDA versions */
+
+#define PCLx1x_IORANGE 16
+
+#define PCL812_CTR0 0
+#define PCL812_CTR1 1
+#define PCL812_CTR2 2
+#define PCL812_CTRCTL 3
+#define PCL812_AD_LO 4
+#define PCL812_DA1_LO 4
+#define PCL812_AD_HI 5
+#define PCL812_DA1_HI 5
+#define PCL812_DA2_LO 6
+#define PCL812_DI_LO 6
+#define PCL812_DA2_HI 7
+#define PCL812_DI_HI 7
+#define PCL812_CLRINT 8
+#define PCL812_GAIN 9
+#define PCL812_MUX 10
+#define PCL812_MODE 11
+#define PCL812_CNTENABLE 10
+#define PCL812_SOFTTRIG 12
+#define PCL812_DO_LO 13
+#define PCL812_DO_HI 14
+
+#define PCL812_DRDY 0x10 /* =0 data ready */
+
+#define ACL8216_STATUS 8 /* 5. bit signalize data ready */
+
+#define ACL8216_DRDY 0x20 /* =0 data ready */
+
+#define MAX_CHANLIST_LEN 256 /* length of scan list */
static const struct comedi_lrange range_pcl812pg_ai = { 5, {
BIP_RANGE(5),
@@ -407,7 +409,18 @@ static struct comedi_driver driver_pcl812 = {
.offset = sizeof(struct pcl812_board),
};
-COMEDI_INITCLEANUP(driver_pcl812);
+static int __init driver_pcl812_init_module(void)
+{
+ return comedi_driver_register(&driver_pcl812);
+}
+
+static void __exit driver_pcl812_cleanup_module(void)
+{
+ comedi_driver_unregister(&driver_pcl812);
+}
+
+module_init(driver_pcl812_init_module);
+module_exit(driver_pcl812_cleanup_module);
struct pcl812_private {
@@ -466,10 +479,13 @@ static int pcl812_ai_insn_read(struct comedi_device *dev,
int n;
int timeout, hi;
- outb(devpriv->mode_reg_int | 1, dev->iobase + PCL812_MODE); /* select software trigger */
- setup_range_channel(dev, s, insn->chanspec, 1); /* select channel and renge */
+ /* select software trigger */
+ outb(devpriv->mode_reg_int | 1, dev->iobase + PCL812_MODE);
+ /* select channel and renge */
+ setup_range_channel(dev, s, insn->chanspec, 1);
for (n = 0; n < insn->n; n++) {
- outb(255, dev->iobase + PCL812_SOFTTRIG); /* start conversion */
+ /* start conversion */
+ outb(255, dev->iobase + PCL812_SOFTTRIG);
udelay(5);
timeout = 50; /* wait max 50us, it must finish under 33us */
while (timeout--) {
@@ -501,10 +517,13 @@ static int acl8216_ai_insn_read(struct comedi_device *dev,
int n;
int timeout;
- outb(1, dev->iobase + PCL812_MODE); /* select software trigger */
- setup_range_channel(dev, s, insn->chanspec, 1); /* select channel and renge */
+ /* select software trigger */
+ outb(1, dev->iobase + PCL812_MODE);
+ /* select channel and renge */
+ setup_range_channel(dev, s, insn->chanspec, 1);
for (n = 0; n < insn->n; n++) {
- outb(255, dev->iobase + PCL812_SOFTTRIG); /* start conversion */
+ /* start conversion */
+ outb(255, dev->iobase + PCL812_SOFTTRIG);
udelay(5);
timeout = 50; /* wait max 50us, it must finish under 33us */
while (timeout--) {
@@ -558,9 +577,8 @@ static int pcl812_ao_insn_read(struct comedi_device *dev,
int chan = CR_CHAN(insn->chanspec);
int i;
- for (i = 0; i < insn->n; i++) {
+ for (i = 0; i < insn->n; i++)
data[i] = devpriv->ao_readback[chan];
- }
return i;
}
@@ -608,14 +626,15 @@ static int pcl812_do_insn_bits(struct comedi_device *dev,
*/
static void pcl812_cmdtest_out(int e, struct comedi_cmd *cmd)
{
- printk("pcl812 e=%d startsrc=%x scansrc=%x convsrc=%x\n", e,
+ printk(KERN_INFO "pcl812 e=%d startsrc=%x scansrc=%x convsrc=%x\n", e,
cmd->start_src, cmd->scan_begin_src, cmd->convert_src);
- printk("pcl812 e=%d startarg=%d scanarg=%d convarg=%d\n", e,
+ printk(KERN_INFO "pcl812 e=%d startarg=%d scanarg=%d convarg=%d\n", e,
cmd->start_arg, cmd->scan_begin_arg, cmd->convert_arg);
- printk("pcl812 e=%d stopsrc=%x scanend=%x\n", e, cmd->stop_src,
- cmd->scan_end_src);
- printk("pcl812 e=%d stoparg=%d scanendarg=%d chanlistlen=%d\n", e,
- cmd->stop_arg, cmd->scan_end_arg, cmd->chanlist_len);
+ printk(KERN_INFO "pcl812 e=%d stopsrc=%x scanend=%x\n", e,
+ cmd->stop_src, cmd->scan_end_src);
+ printk(KERN_INFO "pcl812 e=%d stoparg=%d scanendarg=%d "
+ "chanlistlen=%d\n", e, cmd->stop_arg, cmd->scan_end_arg,
+ cmd->chanlist_len);
}
#endif
@@ -645,11 +664,11 @@ static int pcl812_ai_cmdtest(struct comedi_device *dev,
err++;
tmp = cmd->convert_src;
- if (devpriv->use_ext_trg) {
+ if (devpriv->use_ext_trg)
cmd->convert_src &= TRIG_EXT;
- } else {
+ else
cmd->convert_src &= TRIG_TIMER;
- }
+
if (!cmd->convert_src || tmp != cmd->convert_src)
err++;
@@ -673,7 +692,10 @@ static int pcl812_ai_cmdtest(struct comedi_device *dev,
return 1;
}
- /* step 2: make sure trigger sources are unique and mutually compatible */
+ /*
+ * step 2: make sure trigger sources are
+ * unique and mutually compatible
+ */
if (cmd->start_src != TRIG_NOW) {
cmd->start_src = TRIG_NOW;
@@ -807,7 +829,7 @@ static int pcl812_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
struct comedi_cmd *cmd = &s->async->cmd;
#ifdef PCL812_EXTDEBUG
- printk("pcl812 EDBG: BGN: pcl812_ai_cmd(...)\n");
+ printk(KERN_DEBUG "pcl812 EDBG: BGN: pcl812_ai_cmd(...)\n");
#endif
if (cmd->start_src != TRIG_NOW)
@@ -842,13 +864,15 @@ static int pcl812_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
devpriv->ai_n_chan = cmd->chanlist_len;
memcpy(devpriv->ai_chanlist, cmd->chanlist,
sizeof(unsigned int) * cmd->scan_end_arg);
- setup_range_channel(dev, s, devpriv->ai_chanlist[0], 1); /* select first channel and range */
+ /* select first channel and range */
+ setup_range_channel(dev, s, devpriv->ai_chanlist[0], 1);
if (devpriv->dma) { /* check if we can use DMA transfer */
devpriv->ai_dma = 1;
for (i = 1; i < devpriv->ai_n_chan; i++)
if (devpriv->ai_chanlist[0] != devpriv->ai_chanlist[i]) {
- devpriv->ai_dma = 0; /* we cann't use DMA :-( */
+ /* we cann't use DMA :-( */
+ devpriv->ai_dma = 0;
break;
}
} else
@@ -869,14 +893,18 @@ static int pcl812_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
devpriv->ai_poll_ptr = 0;
s->async->cur_chan = 0;
- if ((devpriv->ai_flags & TRIG_WAKE_EOS)) { /* don't we want wake up every scan? */
+ /* don't we want wake up every scan? */
+ if ((devpriv->ai_flags & TRIG_WAKE_EOS)) {
devpriv->ai_eos = 1;
+
+ /* DMA is useless for this situation */
if (devpriv->ai_n_chan == 1)
- devpriv->ai_dma = 0; /* DMA is useless for this situation */
+ devpriv->ai_dma = 0;
}
if (devpriv->ai_dma) {
- if (devpriv->ai_eos) { /* we use EOS, so adapt DMA buffer to one scan */
+ /* we use EOS, so adapt DMA buffer to one scan */
+ if (devpriv->ai_eos) {
devpriv->dmabytestomove[0] =
devpriv->ai_n_chan * sizeof(short);
devpriv->dmabytestomove[1] =
@@ -894,9 +922,17 @@ static int pcl812_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
if (devpriv->ai_neverending) {
devpriv->dma_runs_to_end = 1;
} else {
- bytes = devpriv->ai_n_chan * devpriv->ai_scans * sizeof(short); /* how many samples we must transfer? */
- devpriv->dma_runs_to_end = bytes / devpriv->dmabytestomove[0]; /* how many DMA pages we must fill */
- devpriv->last_dma_run = bytes % devpriv->dmabytestomove[0]; /* on last dma transfer must be moved */
+ /* how many samples we must transfer? */
+ bytes = devpriv->ai_n_chan *
+ devpriv->ai_scans * sizeof(short);
+
+ /* how many DMA pages we must fill */
+ devpriv->dma_runs_to_end =
+ bytes / devpriv->dmabytestomove[0];
+
+ /* on last dma transfer must be moved */
+ devpriv->last_dma_run =
+ bytes % devpriv->dmabytestomove[0];
if (devpriv->dma_runs_to_end == 0)
devpriv->dmabytestomove[0] =
devpriv->last_dma_run;
@@ -934,14 +970,13 @@ static int pcl812_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
break;
}
- if (devpriv->ai_dma) {
- outb(devpriv->mode_reg_int | 2, dev->iobase + PCL812_MODE); /* let's go! */
- } else {
- outb(devpriv->mode_reg_int | 6, dev->iobase + PCL812_MODE); /* let's go! */
- }
+ if (devpriv->ai_dma) /* let's go! */
+ outb(devpriv->mode_reg_int | 2, dev->iobase + PCL812_MODE);
+ else /* let's go! */
+ outb(devpriv->mode_reg_int | 6, dev->iobase + PCL812_MODE);
#ifdef PCL812_EXTDEBUG
- printk("pcl812 EDBG: END: pcl812_ai_cmd(...)\n");
+ printk(KERN_DEBUG "pcl812 EDBG: END: pcl812_ai_cmd(...)\n");
#endif
return 0;
@@ -983,7 +1018,8 @@ static irqreturn_t interrupt_pcl812_ai_int(int irq, void *d)
if (err) {
printk
- ("comedi%d: pcl812: (%s at 0x%lx) A/D cmd IRQ without DRDY!\n",
+ ("comedi%d: pcl812: (%s at 0x%lx) "
+ "A/D cmd IRQ without DRDY!\n",
dev->minor, dev->board_name, dev->iobase);
pcl812_ai_cancel(dev, s);
s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
@@ -1009,7 +1045,8 @@ static irqreturn_t interrupt_pcl812_ai_int(int irq, void *d)
if (next_chan == 0) { /* one scan done */
devpriv->ai_act_scan++;
if (!(devpriv->ai_neverending))
- if (devpriv->ai_act_scan >= devpriv->ai_scans) { /* all data sampled */
+ /* all data sampled */
+ if (devpriv->ai_act_scan >= devpriv->ai_scans) {
pcl812_ai_cancel(dev, s);
s->async->events |= COMEDI_CB_EOA;
}
@@ -1030,14 +1067,16 @@ static void transfer_from_dma_buf(struct comedi_device *dev,
s->async->events = 0;
for (i = len; i; i--) {
- comedi_buf_put(s->async, ptr[bufptr++]); /* get one sample */
+ /* get one sample */
+ comedi_buf_put(s->async, ptr[bufptr++]);
s->async->cur_chan++;
if (s->async->cur_chan >= devpriv->ai_n_chan) {
s->async->cur_chan = 0;
devpriv->ai_act_scan++;
if (!devpriv->ai_neverending)
- if (devpriv->ai_act_scan >= devpriv->ai_scans) { /* all data sampled */
+ /* all data sampled */
+ if (devpriv->ai_act_scan >= devpriv->ai_scans) {
pcl812_ai_cancel(dev, s);
s->async->events |= COMEDI_CB_EOA;
break;
@@ -1060,7 +1099,7 @@ static irqreturn_t interrupt_pcl812_ai_dma(int irq, void *d)
short *ptr;
#ifdef PCL812_EXTDEBUG
- printk("pcl812 EDBG: BGN: interrupt_pcl812_ai_dma(...)\n");
+ printk(KERN_DEBUG "pcl812 EDBG: BGN: interrupt_pcl812_ai_dma(...)\n");
#endif
ptr = (short *)devpriv->dmabuf[devpriv->next_dma_buf];
len = (devpriv->dmabytestomove[devpriv->next_dma_buf] >> 1) -
@@ -1095,7 +1134,7 @@ static irqreturn_t interrupt_pcl812_ai_dma(int irq, void *d)
transfer_from_dma_buf(dev, s, ptr, bufptr, len);
#ifdef PCL812_EXTDEBUG
- printk("pcl812 EDBG: END: interrupt_pcl812_ai_dma(...)\n");
+ printk(KERN_DEBUG "pcl812 EDBG: END: interrupt_pcl812_ai_dma(...)\n");
#endif
return IRQ_HANDLED;
}
@@ -1111,11 +1150,10 @@ static irqreturn_t interrupt_pcl812(int irq, void *d)
comedi_error(dev, "spurious interrupt");
return IRQ_HANDLED;
}
- if (devpriv->ai_dma) {
+ if (devpriv->ai_dma)
return interrupt_pcl812_ai_dma(irq, d);
- } else {
+ else
return interrupt_pcl812_ai_int(irq, d);
- };
}
/*
@@ -1132,7 +1170,8 @@ static int pcl812_ai_poll(struct comedi_device *dev, struct comedi_subdevice *s)
spin_lock_irqsave(&dev->spinlock, flags);
for (i = 0; i < 10; i++) {
- top1 = get_dma_residue(devpriv->ai_dma); /* where is now DMA */
+ /* where is now DMA */
+ top1 = get_dma_residue(devpriv->ai_dma);
top2 = get_dma_residue(devpriv->ai_dma);
if (top1 == top2)
break;
@@ -1142,8 +1181,8 @@ static int pcl812_ai_poll(struct comedi_device *dev, struct comedi_subdevice *s)
spin_unlock_irqrestore(&dev->spinlock, flags);
return 0;
}
-
- top1 = devpriv->dmabytestomove[1 - devpriv->next_dma_buf] - top1; /* where is now DMA in buffer */
+ /* where is now DMA in buffer */
+ top1 = devpriv->dmabytestomove[1 - devpriv->next_dma_buf] - top1;
top1 >>= 1; /* sample position */
top2 = top1 - devpriv->ai_poll_ptr;
if (top2 < 1) { /* no new samples */
@@ -1171,7 +1210,9 @@ static void setup_range_channel(struct comedi_device *dev,
unsigned int rangechan, char wait)
{
unsigned char chan_reg = CR_CHAN(rangechan); /* normal board */
- unsigned char gain_reg = CR_RANGE(rangechan) + devpriv->range_correction; /* gain index */
+ /* gain index */
+ unsigned char gain_reg = CR_RANGE(rangechan) +
+ devpriv->range_correction;
if ((chan_reg == devpriv->old_chan_reg)
&& (gain_reg == devpriv->old_gain_reg))
@@ -1184,20 +1225,25 @@ static void setup_range_channel(struct comedi_device *dev,
if (devpriv->use_diff) {
chan_reg = chan_reg | 0x30; /* DIFF inputs */
} else {
- if (chan_reg & 0x80) {
- chan_reg = chan_reg | 0x20; /* SE inputs 8-15 */
- } else {
- chan_reg = chan_reg | 0x10; /* SE inputs 0-7 */
- }
+ if (chan_reg & 0x80)
+ /* SE inputs 8-15 */
+ chan_reg = chan_reg | 0x20;
+ else
+ /* SE inputs 0-7 */
+ chan_reg = chan_reg | 0x10;
}
}
outb(chan_reg, dev->iobase + PCL812_MUX); /* select channel */
outb(gain_reg, dev->iobase + PCL812_GAIN); /* select gain */
- if (wait) {
- udelay(devpriv->max_812_ai_mode0_rangewait); /* XXX this depends on selected range and can be very long for some high gain ranges! */
- }
+
+ if (wait)
+ /*
+ * XXX this depends on selected range and can be very long for
+ * some high gain ranges!
+ */
+ udelay(devpriv->max_812_ai_mode0_rangewait);
}
/*
@@ -1207,8 +1253,8 @@ static void start_pacer(struct comedi_device *dev, int mode,
unsigned int divisor1, unsigned int divisor2)
{
#ifdef PCL812_EXTDEBUG
- printk("pcl812 EDBG: BGN: start_pacer(%d,%u,%u)\n", mode, divisor1,
- divisor2);
+ printk(KERN_DEBUG "pcl812 EDBG: BGN: start_pacer(%d,%u,%u)\n", mode,
+ divisor1, divisor2);
#endif
outb(0xb4, dev->iobase + PCL812_CTRCTL);
outb(0x74, dev->iobase + PCL812_CTRCTL);
@@ -1221,7 +1267,7 @@ static void start_pacer(struct comedi_device *dev, int mode,
outb((divisor1 >> 8) & 0xff, dev->iobase + PCL812_CTR1);
}
#ifdef PCL812_EXTDEBUG
- printk("pcl812 EDBG: END: start_pacer(...)\n");
+ printk(KERN_DEBUG "pcl812 EDBG: END: start_pacer(...)\n");
#endif
}
@@ -1252,16 +1298,17 @@ static int pcl812_ai_cancel(struct comedi_device *dev,
struct comedi_subdevice *s)
{
#ifdef PCL812_EXTDEBUG
- printk("pcl812 EDBG: BGN: pcl812_ai_cancel(...)\n");
+ printk(KERN_DEBUG "pcl812 EDBG: BGN: pcl812_ai_cancel(...)\n");
#endif
if (devpriv->ai_dma)
disable_dma(devpriv->dma);
outb(0, dev->iobase + PCL812_CLRINT); /* clear INT request */
- outb(devpriv->mode_reg_int | 0, dev->iobase + PCL812_MODE); /* Stop A/D */
+ /* Stop A/D */
+ outb(devpriv->mode_reg_int | 0, dev->iobase + PCL812_MODE);
start_pacer(dev, -1, 0, 0); /* stop 8254 */
outb(0, dev->iobase + PCL812_CLRINT); /* clear INT request */
#ifdef PCL812_EXTDEBUG
- printk("pcl812 EDBG: END: pcl812_ai_cancel(...)\n");
+ printk(KERN_DEBUG "pcl812 EDBG: END: pcl812_ai_cancel(...)\n");
#endif
return 0;
}
@@ -1272,7 +1319,7 @@ static int pcl812_ai_cancel(struct comedi_device *dev,
static void pcl812_reset(struct comedi_device *dev)
{
#ifdef PCL812_EXTDEBUG
- printk("pcl812 EDBG: BGN: pcl812_reset(...)\n");
+ printk(KERN_DEBUG "pcl812 EDBG: BGN: pcl812_reset(...)\n");
#endif
outb(0, dev->iobase + PCL812_MUX);
outb(0 + devpriv->range_correction, dev->iobase + PCL812_GAIN);
@@ -1304,7 +1351,7 @@ static void pcl812_reset(struct comedi_device *dev)
}
udelay(5);
#ifdef PCL812_EXTDEBUG
- printk("pcl812 EDBG: END: pcl812_reset(...)\n");
+ printk(KERN_DEBUG "pcl812 EDBG: END: pcl812_reset(...)\n");
#endif
}
@@ -1322,8 +1369,8 @@ static int pcl812_attach(struct comedi_device *dev, struct comedi_devconfig *it)
int n_subdevices;
iobase = it->options[0];
- printk("comedi%d: pcl812: board=%s, ioport=0x%03lx", dev->minor,
- this_board->name, iobase);
+ printk(KERN_INFO "comedi%d: pcl812: board=%s, ioport=0x%03lx",
+ dev->minor, this_board->name, iobase);
if (!request_region(iobase, this_board->io_range, "pcl812")) {
printk("I/O port conflict\n");
@@ -1345,18 +1392,18 @@ static int pcl812_attach(struct comedi_device *dev, struct comedi_devconfig *it)
if (irq) { /* we want to use IRQ */
if (((1 << irq) & this_board->IRQbits) == 0) {
printk
- (", IRQ %u is out of allowed range, DISABLING IT",
- irq);
+ (", IRQ %u is out of allowed range, "
+ "DISABLING IT", irq);
irq = 0; /* Bad IRQ */
} else {
if (request_irq
(irq, interrupt_pcl812, 0, "pcl812", dev)) {
printk
- (", unable to allocate IRQ %u, DISABLING IT",
- irq);
+ (", unable to allocate IRQ %u, "
+ "DISABLING IT", irq);
irq = 0; /* Can't use IRQ */
} else {
- printk(", irq=%u", irq);
+ printk(KERN_INFO ", irq=%u", irq);
}
}
}
@@ -1376,16 +1423,20 @@ static int pcl812_attach(struct comedi_device *dev, struct comedi_devconfig *it)
}
ret = request_dma(dma, "pcl812");
if (ret) {
- printk(", unable to allocate DMA %u, FAIL!\n", dma);
+ printk(KERN_ERR ", unable to allocate DMA %u, FAIL!\n",
+ dma);
return -EBUSY; /* DMA isn't free */
}
devpriv->dma = dma;
- printk(", dma=%u", dma);
+ printk(KERN_INFO ", dma=%u", dma);
pages = 1; /* we want 8KB */
devpriv->dmabuf[0] = __get_dma_pages(GFP_KERNEL, pages);
if (!devpriv->dmabuf[0]) {
printk(", unable to allocate DMA buffer, FAIL!\n");
- /* maybe experiment with try_to_free_pages() will help .... */
+ /*
+ * maybe experiment with try_to_free_pages()
+ * will help ....
+ */
free_resources(dev);
return -EBUSY; /* no buffer :-( */
}
@@ -1394,7 +1445,7 @@ static int pcl812_attach(struct comedi_device *dev, struct comedi_devconfig *it)
devpriv->hwdmasize[0] = PAGE_SIZE * (1 << pages);
devpriv->dmabuf[1] = __get_dma_pages(GFP_KERNEL, pages);
if (!devpriv->dmabuf[1]) {
- printk(", unable to allocate DMA buffer, FAIL!\n");
+ printk(KERN_ERR ", unable to allocate DMA buffer, FAIL!\n");
free_resources(dev);
return -EBUSY;
}
@@ -1457,11 +1508,11 @@ no_dma:
s->maxdata = this_board->ai_maxdata;
s->len_chanlist = MAX_CHANLIST_LEN;
s->range_table = this_board->rangelist_ai;
- if (this_board->board_type == boardACL8216) {
+ if (this_board->board_type == boardACL8216)
s->insn_read = acl8216_ai_insn_read;
- } else {
+ else
s->insn_read = pcl812_ai_insn_read;
- }
+
devpriv->use_MPC = this_board->haveMPC508;
s->cancel = pcl812_ai_cancel;
if (dev->irq) {
@@ -1500,8 +1551,8 @@ no_dma:
s->range_table = &range_bipolar10;
break;
printk
- (", incorrect range number %d, changing to 0 (+/-10V)",
- it->options[4]);
+ (", incorrect range number %d, changing "
+ "to 0 (+/-10V)", it->options[4]);
break;
}
break;
@@ -1530,8 +1581,8 @@ no_dma:
s->range_table = &range_iso813_1_ai;
break;
printk
- (", incorrect range number %d, changing to 0 ",
- it->options[1]);
+ (", incorrect range number %d, "
+ "changing to 0 ", it->options[1]);
break;
}
break;
@@ -1555,8 +1606,8 @@ no_dma:
s->range_table = &range_acl8113_1_ai;
break;
printk
- (", incorrect range number %d, changing to 0 ",
- it->options[1]);
+ (", incorrect range number %d, "
+ "changing to 0 ", it->options[1]);
break;
}
break;
@@ -1627,7 +1678,8 @@ no_dma:
case boardACL8112:
devpriv->max_812_ai_mode0_rangewait = 1;
if (it->options[3] > 0)
- devpriv->use_ext_trg = 1; /* we use external trigger */
+ /* we use external trigger */
+ devpriv->use_ext_trg = 1;
case boardA821:
devpriv->max_812_ai_mode0_rangewait = 1;
devpriv->mode_reg_int = (irq << 4) & 0xf0;
@@ -1636,11 +1688,12 @@ no_dma:
case boardPCL813:
case boardISO813:
case boardACL8113:
- devpriv->max_812_ai_mode0_rangewait = 5; /* maybe there must by greatest timeout */
+ /* maybe there must by greatest timeout */
+ devpriv->max_812_ai_mode0_rangewait = 5;
break;
}
- printk("\n");
+ printk(KERN_INFO "\n");
devpriv->valid = 1;
pcl812_reset(dev);
@@ -1655,8 +1708,12 @@ static int pcl812_detach(struct comedi_device *dev)
{
#ifdef PCL812_EXTDEBUG
- printk("comedi%d: pcl812: remove\n", dev->minor);
+ printk(KERN_DEBUG "comedi%d: pcl812: remove\n", dev->minor);
#endif
free_resources(dev);
return 0;
}
+
+MODULE_AUTHOR("Comedi http://www.comedi.org");
+MODULE_DESCRIPTION("Comedi low-level driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/pcl816.c b/drivers/staging/comedi/drivers/pcl816.c
index 71c2a3aa379..3d0f018faa6 100644
--- a/drivers/staging/comedi/drivers/pcl816.c
+++ b/drivers/staging/comedi/drivers/pcl816.c
@@ -2,7 +2,7 @@
comedi/drivers/pcl816.c
Author: Juan Grigera <juan@grigera.com.ar>
- based on pcl818 by Michal Dobes <dobes@tesnet.cz> and bits of pcl812
+ based on pcl818 by Michal Dobes <dobes@tesnet.cz> and bits of pcl812
hardware driver for Advantech cards:
card: PCL-816, PCL814B
@@ -28,7 +28,7 @@ Configuration Options:
[1] - IRQ (0=disable, 2, 3, 4, 5, 6, 7)
[2] - DMA (0=disable, 1, 3)
[3] - 0, 10=10MHz clock for 8254
- 1= 1MHz clock for 8254
+ 1= 1MHz clock for 8254
*/
@@ -85,7 +85,7 @@ Configuration Options:
#define INT_TYPE_AI3_DMA_RTC 10
/* RTC stuff... */
-#define RTC_IRQ 8
+#define RTC_IRQ 8
#define RTC_IO_EXTENT 0x10
#endif
@@ -168,7 +168,18 @@ static struct comedi_driver driver_pcl816 = {
.offset = sizeof(struct pcl816_board),
};
-COMEDI_INITCLEANUP(driver_pcl816);
+static int __init driver_pcl816_init_module(void)
+{
+ return comedi_driver_register(&driver_pcl816);
+}
+
+static void __exit driver_pcl816_cleanup_module(void)
+{
+ comedi_driver_unregister(&driver_pcl816);
+}
+
+module_init(driver_pcl816_init_module);
+module_exit(driver_pcl816_cleanup_module);
struct pcl816_private {
@@ -253,7 +264,8 @@ static int pcl816_ai_insn_read(struct comedi_device *dev,
/* Set the input channel */
outb(CR_CHAN(insn->chanspec) & 0xf, dev->iobase + PCL816_MUX);
- outb(CR_RANGE(insn->chanspec), dev->iobase + PCL816_RANGE); /* select gain */
+ /* select gain */
+ outb(CR_RANGE(insn->chanspec), dev->iobase + PCL816_RANGE);
for (n = 0; n < insn->n; n++) {
@@ -268,8 +280,8 @@ static int pcl816_ai_insn_read(struct comedi_device *dev,
((inb(dev->iobase +
PCL816_AD_HI) << 8) |
(inb(dev->iobase + PCL816_AD_LO)));
-
- outb(0, dev->iobase + PCL816_CLRINT); /* clear INT (conversion end) flag */
+ /* clear INT (conversion end) flag */
+ outb(0, dev->iobase + PCL816_CLRINT);
break;
}
udelay(1);
@@ -278,7 +290,8 @@ static int pcl816_ai_insn_read(struct comedi_device *dev,
if (!timeout) {
comedi_error(dev, "A/D insn timeout\n");
data[0] = 0;
- outb(0, dev->iobase + PCL816_CLRINT); /* clear INT (conversion end) flag */
+ /* clear INT (conversion end) flag */
+ outb(0, dev->iobase + PCL816_CLRINT);
return -EIO;
}
@@ -332,7 +345,8 @@ static irqreturn_t interrupt_pcl816_ai_mode13_int(int irq, void *d)
}
if (!devpriv->ai_neverending)
- if (devpriv->ai_act_scan >= devpriv->ai_scans) { /* all data sampled */
+ /* all data sampled */
+ if (devpriv->ai_act_scan >= devpriv->ai_scans) {
/* all data sampled */
pcl816_ai_cancel(dev, s);
s->async->events |= COMEDI_CB_EOA;
@@ -369,7 +383,8 @@ static void transfer_from_dma_buf(struct comedi_device *dev,
}
if (!devpriv->ai_neverending)
- if (devpriv->ai_act_scan >= devpriv->ai_scans) { /* all data sampled */
+ /* all data sampled */
+ if (devpriv->ai_act_scan >= devpriv->ai_scans) {
pcl816_ai_cancel(dev, s);
s->async->events |= COMEDI_CB_EOA;
s->async->events |= COMEDI_CB_BLOCK;
@@ -391,7 +406,8 @@ static irqreturn_t interrupt_pcl816_ai_mode13_dma(int irq, void *d)
disable_dma(devpriv->dma);
this_dma_buf = devpriv->next_dma_buf;
- if ((devpriv->dma_runs_to_end > -1) || devpriv->ai_neverending) { /* switch dma bufs */
+ /* switch dma bufs */
+ if ((devpriv->dma_runs_to_end > -1) || devpriv->ai_neverending) {
devpriv->next_dma_buf = 1 - devpriv->next_dma_buf;
set_dma_mode(devpriv->dma, DMA_MODE_READ);
@@ -467,14 +483,14 @@ static irqreturn_t interrupt_pcl816(int irq, void *d)
*/
static void pcl816_cmdtest_out(int e, struct comedi_cmd *cmd)
{
- printk("pcl816 e=%d startsrc=%x scansrc=%x convsrc=%x\n", e,
+ printk(KERN_INFO "pcl816 e=%d startsrc=%x scansrc=%x convsrc=%x\n", e,
cmd->start_src, cmd->scan_begin_src, cmd->convert_src);
- printk("pcl816 e=%d startarg=%d scanarg=%d convarg=%d\n", e,
+ printk(KERN_INFO "pcl816 e=%d startarg=%d scanarg=%d convarg=%d\n", e,
cmd->start_arg, cmd->scan_begin_arg, cmd->convert_arg);
- printk("pcl816 e=%d stopsrc=%x scanend=%x\n", e, cmd->stop_src,
- cmd->scan_end_src);
- printk("pcl816 e=%d stoparg=%d scanendarg=%d chanlistlen=%d\n", e,
- cmd->stop_arg, cmd->scan_end_arg, cmd->chanlist_len);
+ printk(KERN_INFO "pcl816 e=%d stopsrc=%x scanend=%x\n", e,
+ cmd->stop_src, cmd->scan_end_src);
+ printk(KERN_INFO "pcl816 e=%d stoparg=%d scanendarg=%d chanlistlen=%d\n",
+ e, cmd->stop_arg, cmd->scan_end_arg, cmd->chanlist_len);
}
/*
@@ -486,8 +502,9 @@ static int pcl816_ai_cmdtest(struct comedi_device *dev,
int err = 0;
int tmp, divisor1 = 0, divisor2 = 0;
- DEBUG(printk("pcl816 pcl812_ai_cmdtest\n"); pcl816_cmdtest_out(-1, cmd);
- );
+ DEBUG(printk(KERN_INFO "pcl816 pcl812_ai_cmdtest\n");
+ pcl816_cmdtest_out(-1, cmd);
+ );
/* step 1: make sure trigger sources are trivially valid */
tmp = cmd->start_src;
@@ -515,11 +532,14 @@ static int pcl816_ai_cmdtest(struct comedi_device *dev,
if (!cmd->stop_src || tmp != cmd->stop_src)
err++;
- if (err) {
+ if (err)
return 1;
- }
- /* step 2: make sure trigger sources are unique and mutually compatible */
+
+ /*
+ * step 2: make sure trigger sources
+ * are unique and mutually compatible
+ */
if (cmd->start_src != TRIG_NOW) {
cmd->start_src = TRIG_NOW;
@@ -544,9 +564,9 @@ static int pcl816_ai_cmdtest(struct comedi_device *dev,
if (cmd->stop_src != TRIG_NONE && cmd->stop_src != TRIG_COUNT)
err++;
- if (err) {
+ if (err)
return 2;
- }
+
/* step 3: make sure arguments are trivially compatible */
if (cmd->start_arg != 0) {
@@ -586,9 +606,9 @@ static int pcl816_ai_cmdtest(struct comedi_device *dev,
}
}
- if (err) {
+ if (err)
return 3;
- }
+
/* step 4: fix up any arguments */
if (cmd->convert_src == TRIG_TIMER) {
@@ -603,9 +623,9 @@ static int pcl816_ai_cmdtest(struct comedi_device *dev,
err++;
}
- if (err) {
+ if (err)
return 4;
- }
+
/* step 5: complain about special chanlist considerations */
@@ -643,7 +663,9 @@ static int pcl816_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
i8253_cascade_ns_to_timer(this_board->i8254_osc_base, &divisor1,
&divisor2, &cmd->convert_arg,
cmd->flags & TRIG_ROUND_MASK);
- if (divisor1 == 1) { /* PCL816 crash if any divisor is set to 1 */
+
+ /* PCL816 crash if any divisor is set to 1 */
+ if (divisor1 == 1) {
divisor1 = 2;
divisor2 /= 2;
}
@@ -676,8 +698,10 @@ static int pcl816_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
devpriv->ai_neverending = 1;
}
- if ((cmd->flags & TRIG_WAKE_EOS)) { /* don't we want wake up every scan? */
- printk("pl816: You wankt WAKE_EOS but I dont want handle it");
+ /* don't we want wake up every scan? */
+ if ((cmd->flags & TRIG_WAKE_EOS)) {
+ printk(KERN_INFO
+ "pl816: You wankt WAKE_EOS but I dont want handle it");
/* devpriv->ai_eos=1; */
/* if (devpriv->ai_n_chan==1) */
/* devpriv->dma=0; // DMA is useless for this situation */
@@ -686,9 +710,17 @@ static int pcl816_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
if (devpriv->dma) {
bytes = devpriv->hwdmasize[0];
if (!devpriv->ai_neverending) {
- bytes = s->async->cmd.chanlist_len * s->async->cmd.chanlist_len * sizeof(short); /* how many */
- devpriv->dma_runs_to_end = bytes / devpriv->hwdmasize[0]; /* how many DMA pages we must fill */
- devpriv->last_dma_run = bytes % devpriv->hwdmasize[0]; /* on last dma transfer must be moved */
+ /* how many */
+ bytes = s->async->cmd.chanlist_len *
+ s->async->cmd.chanlist_len *
+ sizeof(short);
+
+ /* how many DMA pages we must fill */
+ devpriv->dma_runs_to_end = bytes /
+ devpriv->hwdmasize[0];
+
+ /* on last dma transfer must be moved */
+ devpriv->last_dma_run = bytes % devpriv->hwdmasize[0];
devpriv->dma_runs_to_end--;
if (devpriv->dma_runs_to_end >= 0)
bytes = devpriv->hwdmasize[0];
@@ -711,14 +743,22 @@ static int pcl816_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
switch (cmd->convert_src) {
case TRIG_TIMER:
devpriv->int816_mode = INT_TYPE_AI1_DMA;
- outb(0x32, dev->iobase + PCL816_CONTROL); /* Pacer+IRQ+DMA */
- outb(dmairq, dev->iobase + PCL816_STATUS); /* write irq and DMA to card */
+
+ /* Pacer+IRQ+DMA */
+ outb(0x32, dev->iobase + PCL816_CONTROL);
+
+ /* write irq and DMA to card */
+ outb(dmairq, dev->iobase + PCL816_STATUS);
break;
default:
devpriv->int816_mode = INT_TYPE_AI3_DMA;
- outb(0x34, dev->iobase + PCL816_CONTROL); /* Ext trig+IRQ+DMA */
- outb(dmairq, dev->iobase + PCL816_STATUS); /* write irq to card */
+
+ /* Ext trig+IRQ+DMA */
+ outb(0x34, dev->iobase + PCL816_CONTROL);
+
+ /* write irq to card */
+ outb(dmairq, dev->iobase + PCL816_STATUS);
break;
}
@@ -747,7 +787,8 @@ static int pcl816_ai_poll(struct comedi_device *dev, struct comedi_subdevice *s)
return 0;
}
- top1 = devpriv->hwdmasize[0] - top1; /* where is now DMA in buffer */
+ /* where is now DMA in buffer */
+ top1 = devpriv->hwdmasize[0] - top1;
top1 >>= 1; /* sample position */
top2 = top1 - devpriv->ai_poll_ptr;
if (top2 < 1) { /* no new samples */
@@ -787,16 +828,23 @@ static int pcl816_ai_cancel(struct comedi_device *dev,
disable_dma(devpriv->dma);
case INT_TYPE_AI1_INT:
case INT_TYPE_AI3_INT:
- outb(inb(dev->iobase + PCL816_CONTROL) & 0x73, dev->iobase + PCL816_CONTROL); /* Stop A/D */
+ outb(inb(dev->iobase + PCL816_CONTROL) & 0x73,
+ dev->iobase + PCL816_CONTROL); /* Stop A/D */
udelay(1);
outb(0, dev->iobase + PCL816_CONTROL); /* Stop A/D */
- outb(0xb0, dev->iobase + PCL816_CTRCTL); /* Stop pacer */
+
+ /* Stop pacer */
+ outb(0xb0, dev->iobase + PCL816_CTRCTL);
outb(0x70, dev->iobase + PCL816_CTRCTL);
outb(0, dev->iobase + PCL816_AD_LO);
inb(dev->iobase + PCL816_AD_LO);
inb(dev->iobase + PCL816_AD_HI);
- outb(0, dev->iobase + PCL816_CLRINT); /* clear INT request */
- outb(0, dev->iobase + PCL816_CONTROL); /* Stop A/D */
+
+ /* clear INT request */
+ outb(0, dev->iobase + PCL816_CLRINT);
+
+ /* Stop A/D */
+ outb(0, dev->iobase + PCL816_CONTROL);
devpriv->irq_blocked = 0;
devpriv->irq_was_now_closed = devpriv->int816_mode;
devpriv->int816_mode = 0;
@@ -866,8 +914,11 @@ start_pacer(struct comedi_device *dev, int mode, unsigned int divisor1,
outb(0xff, dev->iobase + PCL816_CTR0);
outb(0x00, dev->iobase + PCL816_CTR0);
udelay(1);
- outb(0xb4, dev->iobase + PCL816_CTRCTL); /* set counter 2 as mode 3 */
- outb(0x74, dev->iobase + PCL816_CTRCTL); /* set counter 1 as mode 3 */
+
+ /* set counter 2 as mode 3 */
+ outb(0xb4, dev->iobase + PCL816_CTRCTL);
+ /* set counter 1 as mode 3 */
+ outb(0x74, dev->iobase + PCL816_CTRCTL);
udelay(1);
if (mode == 1) {
@@ -903,41 +954,51 @@ check_channel_list(struct comedi_device *dev,
}
if (chanlen > 1) {
- chansegment[0] = chanlist[0]; /* first channel is everytime ok */
+ /* first channel is everytime ok */
+ chansegment[0] = chanlist[0];
for (i = 1, seglen = 1; i < chanlen; i++, seglen++) {
/* build part of chanlist */
- DEBUG(printk("%d. %d %d\n", i, CR_CHAN(chanlist[i]),
+ DEBUG(printk(KERN_INFO "%d. %d %d\n", i,
+ CR_CHAN(chanlist[i]),
CR_RANGE(chanlist[i]));)
+
+ /* we detect loop, this must by finish */
if (chanlist[0] == chanlist[i])
- break; /* we detect loop, this must by finish */
+ break;
nowmustbechan =
(CR_CHAN(chansegment[i - 1]) + 1) % chanlen;
if (nowmustbechan != CR_CHAN(chanlist[i])) {
/* channel list isn't continous :-( */
- printk
- ("comedi%d: pcl816: channel list must be continous! chanlist[%i]=%d but must be %d or %d!\n",
- dev->minor, i, CR_CHAN(chanlist[i]),
- nowmustbechan, CR_CHAN(chanlist[0]));
+ printk(KERN_WARNING
+ "comedi%d: pcl816: channel list must "
+ "be continous! chanlist[%i]=%d but "
+ "must be %d or %d!\n", dev->minor,
+ i, CR_CHAN(chanlist[i]), nowmustbechan,
+ CR_CHAN(chanlist[0]));
return 0;
}
- chansegment[i] = chanlist[i]; /* well, this is next correct channel in list */
+ /* well, this is next correct channel in list */
+ chansegment[i] = chanlist[i];
}
- for (i = 0, segpos = 0; i < chanlen; i++) { /* check whole chanlist */
+ /* check whole chanlist */
+ for (i = 0, segpos = 0; i < chanlen; i++) {
DEBUG(printk("%d %d=%d %d\n",
CR_CHAN(chansegment[i % seglen]),
CR_RANGE(chansegment[i % seglen]),
CR_CHAN(chanlist[i]),
CR_RANGE(chanlist[i]));)
if (chanlist[i] != chansegment[i % seglen]) {
- printk
- ("comedi%d: pcl816: bad channel or range number! chanlist[%i]=%d,%d,%d and not %d,%d,%d!\n",
- dev->minor, i, CR_CHAN(chansegment[i]),
- CR_RANGE(chansegment[i]),
- CR_AREF(chansegment[i]),
- CR_CHAN(chanlist[i % seglen]),
- CR_RANGE(chanlist[i % seglen]),
- CR_AREF(chansegment[i % seglen]));
+ printk(KERN_WARNING
+ "comedi%d: pcl816: bad channel or range"
+ " number! chanlist[%i]=%d,%d,%d and not"
+ " %d,%d,%d!\n", dev->minor, i,
+ CR_CHAN(chansegment[i]),
+ CR_RANGE(chansegment[i]),
+ CR_AREF(chansegment[i]),
+ CR_CHAN(chanlist[i % seglen]),
+ CR_RANGE(chanlist[i % seglen]),
+ CR_AREF(chansegment[i % seglen]));
return 0; /* chan/gain list is strange */
}
}
@@ -965,12 +1026,15 @@ setup_channel_list(struct comedi_device *dev,
for (i = 0; i < seglen; i++) { /* store range list to card */
devpriv->ai_act_chanlist[i] = CR_CHAN(chanlist[i]);
outb(CR_CHAN(chanlist[0]) & 0xf, dev->iobase + PCL816_MUX);
- outb(CR_RANGE(chanlist[0]), dev->iobase + PCL816_RANGE); /* select gain */
+ /* select gain */
+ outb(CR_RANGE(chanlist[0]), dev->iobase + PCL816_RANGE);
}
udelay(1);
-
- outb(devpriv->ai_act_chanlist[0] | (devpriv->ai_act_chanlist[seglen - 1] << 4), dev->iobase + PCL816_MUX); /* select channel interval to scan */
+ /* select channel interval to scan */
+ outb(devpriv->ai_act_chanlist[0] |
+ (devpriv->ai_act_chanlist[seglen - 1] << 4),
+ dev->iobase + PCL816_MUX);
}
#ifdef unused
@@ -998,11 +1062,11 @@ static int set_rtc_irq_bit(unsigned char bit)
save_flags(flags);
cli();
val = CMOS_READ(RTC_CONTROL);
- if (bit) {
+ if (bit)
val |= RTC_PIE;
- } else {
+ else
val &= ~RTC_PIE;
- }
+
CMOS_WRITE(val, RTC_CONTROL);
CMOS_READ(RTC_INTR_FLAGS);
restore_flags(flags);
@@ -1072,7 +1136,7 @@ static int pcl816_attach(struct comedi_device *dev, struct comedi_devconfig *it)
dev->iobase = iobase;
if (pcl816_check(iobase)) {
- printk(", I cann't detect board. FAIL!\n");
+ printk(KERN_ERR ", I cann't detect board. FAIL!\n");
return -EIO;
}
@@ -1090,30 +1154,29 @@ static int pcl816_attach(struct comedi_device *dev, struct comedi_devconfig *it)
if (irq) { /* we want to use IRQ */
if (((1 << irq) & this_board->IRQbits) == 0) {
printk
- (", IRQ %u is out of allowed range, DISABLING IT",
- irq);
+ (", IRQ %u is out of allowed range, "
+ "DISABLING IT", irq);
irq = 0; /* Bad IRQ */
} else {
if (request_irq
(irq, interrupt_pcl816, 0, "pcl816", dev)) {
printk
- (", unable to allocate IRQ %u, DISABLING IT",
- irq);
+ (", unable to allocate IRQ %u, "
+ "DISABLING IT", irq);
irq = 0; /* Can't use IRQ */
} else {
- printk(", irq=%u", irq);
+ printk(KERN_INFO ", irq=%u", irq);
}
}
}
}
dev->irq = irq;
- if (irq) {
+ if (irq) /* 1=we have allocated irq */
devpriv->irq_free = 1;
- } /* 1=we have allocated irq */
- else {
+ else
devpriv->irq_free = 0;
- }
+
devpriv->irq_blocked = 0; /* number of subdevice which use IRQ */
devpriv->int816_mode = 0; /* mode of irq */
@@ -1170,18 +1233,22 @@ no_rtc:
}
ret = request_dma(dma, "pcl816");
if (ret) {
- printk(", unable to allocate DMA %u, FAIL!\n", dma);
+ printk(KERN_ERR
+ ", unable to allocate DMA %u, FAIL!\n", dma);
return -EBUSY; /* DMA isn't free */
}
devpriv->dma = dma;
- printk(", dma=%u", dma);
+ printk(KERN_INFO ", dma=%u", dma);
pages = 2; /* we need 16KB */
devpriv->dmabuf[0] = __get_dma_pages(GFP_KERNEL, pages);
if (!devpriv->dmabuf[0]) {
printk(", unable to allocate DMA buffer, FAIL!\n");
- /* maybe experiment with try_to_free_pages() will help .... */
+ /*
+ * maybe experiment with try_to_free_pages()
+ * will help ....
+ */
return -EBUSY; /* no buffer :-( */
}
devpriv->dmapages[0] = pages;
@@ -1192,8 +1259,9 @@ no_rtc:
if (devpriv->dma_rtc == 0) { /* we must do duble buff :-( */
devpriv->dmabuf[1] = __get_dma_pages(GFP_KERNEL, pages);
if (!devpriv->dmabuf[1]) {
- printk
- (", unable to allocate DMA buffer, FAIL!\n");
+ printk(KERN_ERR
+ ", unable to allocate DMA buffer, "
+ "FAIL!\n");
return -EBUSY;
}
devpriv->dmapages[1] = pages;
@@ -1277,7 +1345,7 @@ case COMEDI_SUBD_DO:
*/
static int pcl816_detach(struct comedi_device *dev)
{
- DEBUG(printk("comedi%d: pcl816: remove\n", dev->minor);)
+ DEBUG(printk(KERN_INFO "comedi%d: pcl816: remove\n", dev->minor);)
free_resources(dev);
#ifdef unused
if (devpriv->dma_rtc)
@@ -1285,3 +1353,7 @@ static int pcl816_detach(struct comedi_device *dev)
#endif
return 0;
}
+
+MODULE_AUTHOR("Comedi http://www.comedi.org");
+MODULE_DESCRIPTION("Comedi low-level driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/pcl818.c b/drivers/staging/comedi/drivers/pcl818.c
index 9d6aa393ef1..d2bd6f82b83 100644
--- a/drivers/staging/comedi/drivers/pcl818.c
+++ b/drivers/staging/comedi/drivers/pcl818.c
@@ -313,7 +313,18 @@ static struct comedi_driver driver_pcl818 = {
.offset = sizeof(struct pcl818_board),
};
-COMEDI_INITCLEANUP(driver_pcl818);
+static int __init driver_pcl818_init_module(void)
+{
+ return comedi_driver_register(&driver_pcl818);
+}
+
+static void __exit driver_pcl818_cleanup_module(void)
+{
+ comedi_driver_unregister(&driver_pcl818);
+}
+
+module_init(driver_pcl818_init_module);
+module_exit(driver_pcl818_cleanup_module);
struct pcl818_private {
@@ -2036,3 +2047,7 @@ static int pcl818_detach(struct comedi_device *dev)
free_resources(dev);
return 0;
}
+
+MODULE_AUTHOR("Comedi http://www.comedi.org");
+MODULE_DESCRIPTION("Comedi low-level driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/pcm3724.c b/drivers/staging/comedi/drivers/pcm3724.c
index ed610307923..7fb3c27e597 100644
--- a/drivers/staging/comedi/drivers/pcm3724.c
+++ b/drivers/staging/comedi/drivers/pcm3724.c
@@ -97,7 +97,18 @@ static struct comedi_driver driver_pcm3724 = {
.offset = sizeof(struct pcm3724_board),
};
-COMEDI_INITCLEANUP(driver_pcm3724);
+static int __init driver_pcm3724_init_module(void)
+{
+ return comedi_driver_register(&driver_pcm3724);
+}
+
+static void __exit driver_pcm3724_cleanup_module(void)
+{
+ comedi_driver_unregister(&driver_pcm3724);
+}
+
+module_init(driver_pcm3724_init_module);
+module_exit(driver_pcm3724_cleanup_module);
/* (setq c-basic-offset 8) */
@@ -184,7 +195,7 @@ static void enable_chan(struct comedi_device *dev, struct comedi_subdevice *s,
struct priv_pcm3724 *priv;
gatecfg = 0;
- priv = (struct priv_pcm3724 *)(dev->private);
+ priv = dev->private;
mask = 1 << CR_CHAN(chanspec);
if (s == dev->subdevices) /* subdev 0 */
@@ -307,3 +318,7 @@ static int pcm3724_detach(struct comedi_device *dev)
return 0;
}
+
+MODULE_AUTHOR("Comedi http://www.comedi.org");
+MODULE_DESCRIPTION("Comedi low-level driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/pcm3730.c b/drivers/staging/comedi/drivers/pcm3730.c
index 22b7aae63ad..bada6b236ff 100644
--- a/drivers/staging/comedi/drivers/pcm3730.c
+++ b/drivers/staging/comedi/drivers/pcm3730.c
@@ -38,7 +38,18 @@ static struct comedi_driver driver_pcm3730 = {
.detach = pcm3730_detach,
};
-COMEDI_INITCLEANUP(driver_pcm3730);
+static int __init driver_pcm3730_init_module(void)
+{
+ return comedi_driver_register(&driver_pcm3730);
+}
+
+static void __exit driver_pcm3730_cleanup_module(void)
+{
+ comedi_driver_unregister(&driver_pcm3730);
+}
+
+module_init(driver_pcm3730_init_module);
+module_exit(driver_pcm3730_cleanup_module);
static int pcm3730_do_insn_bits(struct comedi_device *dev,
struct comedi_subdevice *s,
@@ -154,3 +165,7 @@ static int pcm3730_detach(struct comedi_device *dev)
return 0;
}
+
+MODULE_AUTHOR("Comedi http://www.comedi.org");
+MODULE_DESCRIPTION("Comedi low-level driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/pcm_common.c b/drivers/staging/comedi/drivers/pcm_common.c
index 52c2a669821..474af7bc6c8 100644
--- a/drivers/staging/comedi/drivers/pcm_common.c
+++ b/drivers/staging/comedi/drivers/pcm_common.c
@@ -109,3 +109,7 @@ int comedi_pcm_cmdtest(struct comedi_device *dev,
return 0;
}
EXPORT_SYMBOL(comedi_pcm_cmdtest);
+
+MODULE_AUTHOR("Comedi http://www.comedi.org");
+MODULE_DESCRIPTION("Comedi low-level driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/pcmad.c b/drivers/staging/comedi/drivers/pcmad.c
index fab8092bd7a..23b3d777340 100644
--- a/drivers/staging/comedi/drivers/pcmad.c
+++ b/drivers/staging/comedi/drivers/pcmad.c
@@ -89,7 +89,18 @@ static struct comedi_driver driver_pcmad = {
.offset = sizeof(pcmad_boards[0]),
};
-COMEDI_INITCLEANUP(driver_pcmad);
+static int __init driver_pcmad_init_module(void)
+{
+ return comedi_driver_register(&driver_pcmad);
+}
+
+static void __exit driver_pcmad_cleanup_module(void)
+{
+ comedi_driver_unregister(&driver_pcmad);
+}
+
+module_init(driver_pcmad_init_module);
+module_exit(driver_pcmad_cleanup_module);
#define TIMEOUT 100
@@ -176,3 +187,7 @@ static int pcmad_detach(struct comedi_device *dev)
return 0;
}
+
+MODULE_AUTHOR("Comedi http://www.comedi.org");
+MODULE_DESCRIPTION("Comedi low-level driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/pcmda12.c b/drivers/staging/comedi/drivers/pcmda12.c
index 7133eb0352b..0e9ffa28d74 100644
--- a/drivers/staging/comedi/drivers/pcmda12.c
+++ b/drivers/staging/comedi/drivers/pcmda12.c
@@ -157,7 +157,8 @@ static int pcmda12_attach(struct comedi_device *dev,
unsigned long iobase;
iobase = it->options[0];
- printk("comedi%d: %s: io: %lx %s ", dev->minor, driver.driver_name,
+ printk(KERN_INFO
+ "comedi%d: %s: io: %lx %s ", dev->minor, driver.driver_name,
iobase, it->options[1] ? "simultaneous xfer mode enabled" : "");
if (!request_region(iobase, IOSIZE, driver.driver_name)) {
@@ -177,7 +178,7 @@ static int pcmda12_attach(struct comedi_device *dev,
* convenient macro defined in comedidev.h.
*/
if (alloc_private(dev, sizeof(struct pcmda12_private)) < 0) {
- printk("cannot allocate private data structure\n");
+ printk(KERN_ERR "cannot allocate private data structure\n");
return -ENOMEM;
}
@@ -191,7 +192,7 @@ static int pcmda12_attach(struct comedi_device *dev,
* 96-channel version of the board.
*/
if (alloc_subdevices(dev, 1) < 0) {
- printk("cannot allocate subdevice data structures\n");
+ printk(KERN_ERR "cannot allocate subdevice data structures\n");
return -ENOMEM;
}
@@ -207,7 +208,7 @@ static int pcmda12_attach(struct comedi_device *dev,
zero_chans(dev); /* clear out all the registers, basically */
- printk("attached\n");
+ printk(KERN_INFO "attached\n");
return 1;
}
@@ -222,7 +223,8 @@ static int pcmda12_attach(struct comedi_device *dev,
*/
static int pcmda12_detach(struct comedi_device *dev)
{
- printk("comedi%d: %s: remove\n", dev->minor, driver.driver_name);
+ printk(KERN_INFO
+ "comedi%d: %s: remove\n", dev->minor, driver.driver_name);
if (dev->iobase)
release_region(dev->iobase, IOSIZE);
return 0;
@@ -303,4 +305,19 @@ static int ao_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
* A convenient macro that defines init_module() and cleanup_module(),
* as necessary.
*/
-COMEDI_INITCLEANUP(driver);
+static int __init driver_init_module(void)
+{
+ return comedi_driver_register(&driver);
+}
+
+static void __exit driver_cleanup_module(void)
+{
+ comedi_driver_unregister(&driver);
+}
+
+module_init(driver_init_module);
+module_exit(driver_cleanup_module);
+
+MODULE_AUTHOR("Comedi http://www.comedi.org");
+MODULE_DESCRIPTION("Comedi low-level driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/pcmmio.c b/drivers/staging/comedi/drivers/pcmmio.c
index 025a52e8981..5c832d7ed45 100644
--- a/drivers/staging/comedi/drivers/pcmmio.c
+++ b/drivers/staging/comedi/drivers/pcmmio.c
@@ -145,10 +145,6 @@ Configuration Options:
#define PAGE_ENAB 2
#define PAGE_INT_ID 3
-typedef int (*comedi_insn_fn_t) (struct comedi_device *,
- struct comedi_subdevice *,
- struct comedi_insn *, unsigned int *);
-
static int ai_rinsn(struct comedi_device *, struct comedi_subdevice *,
struct comedi_insn *, unsigned int *);
static int ao_rinsn(struct comedi_device *, struct comedi_subdevice *,
@@ -171,7 +167,18 @@ struct pcmmio_board {
const int n_ai_chans;
const int n_ao_chans;
const struct comedi_lrange *ai_range_table, *ao_range_table;
- comedi_insn_fn_t ai_rinsn, ao_rinsn, ao_winsn;
+ int (*ai_rinsn) (struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data);
+ int (*ao_rinsn) (struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data);
+ int (*ao_winsn) (struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data);
};
static const struct comedi_lrange ranges_ai = {
@@ -1333,4 +1340,19 @@ static int ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s,
* A convenient macro that defines init_module() and cleanup_module(),
* as necessary.
*/
-COMEDI_INITCLEANUP(driver);
+static int __init driver_init_module(void)
+{
+ return comedi_driver_register(&driver);
+}
+
+static void __exit driver_cleanup_module(void)
+{
+ comedi_driver_unregister(&driver);
+}
+
+module_init(driver_init_module);
+module_exit(driver_cleanup_module);
+
+MODULE_AUTHOR("Comedi http://www.comedi.org");
+MODULE_DESCRIPTION("Comedi low-level driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/pcmuio.c b/drivers/staging/comedi/drivers/pcmuio.c
index 5af4c8448a3..7a9287433b2 100644
--- a/drivers/staging/comedi/drivers/pcmuio.c
+++ b/drivers/staging/comedi/drivers/pcmuio.c
@@ -1018,4 +1018,19 @@ pcmuio_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s,
* A convenient macro that defines init_module() and cleanup_module(),
* as necessary.
*/
-COMEDI_INITCLEANUP(driver);
+static int __init driver_init_module(void)
+{
+ return comedi_driver_register(&driver);
+}
+
+static void __exit driver_cleanup_module(void)
+{
+ comedi_driver_unregister(&driver);
+}
+
+module_init(driver_init_module);
+module_exit(driver_cleanup_module);
+
+MODULE_AUTHOR("Comedi http://www.comedi.org");
+MODULE_DESCRIPTION("Comedi low-level driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/poc.c b/drivers/staging/comedi/drivers/poc.c
index 1ebc356ce40..831a576c24a 100644
--- a/drivers/staging/comedi/drivers/poc.c
+++ b/drivers/staging/comedi/drivers/poc.c
@@ -248,4 +248,19 @@ static int pcl734_insn_bits(struct comedi_device *dev,
return 2;
}
-COMEDI_INITCLEANUP(driver_poc);
+static int __init driver_poc_init_module(void)
+{
+ return comedi_driver_register(&driver_poc);
+}
+
+static void __exit driver_poc_cleanup_module(void)
+{
+ comedi_driver_unregister(&driver_poc);
+}
+
+module_init(driver_poc_init_module);
+module_exit(driver_poc_cleanup_module);
+
+MODULE_AUTHOR("Comedi http://www.comedi.org");
+MODULE_DESCRIPTION("Comedi low-level driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/quatech_daqp_cs.c b/drivers/staging/comedi/drivers/quatech_daqp_cs.c
index a91db6c4202..bf489d7f499 100644
--- a/drivers/staging/comedi/drivers/quatech_daqp_cs.c
+++ b/drivers/staging/comedi/drivers/quatech_daqp_cs.c
@@ -14,7 +14,7 @@
Documentation for the DAQP PCMCIA cards can be found on Quatech's site:
- ftp://ftp.quatech.com/Manuals/daqp-208.pdf
+ ftp://ftp.quatech.com/Manuals/daqp-208.pdf
This manual is for both the DAQP-208 and the DAQP-308.
@@ -50,7 +50,6 @@ Devices: [Quatech] DAQP-208 (daqp), DAQP-308
#include "../comedidev.h"
#include <linux/semaphore.h>
-#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/cistpl.h>
#include <pcmcia/cisreg.h>
@@ -195,7 +194,7 @@ static struct comedi_driver driver_daqp = {
static void daqp_dump(struct comedi_device *dev)
{
- printk("DAQP: status %02x; aux status %02x\n",
+ printk(KERN_INFO "DAQP: status %02x; aux status %02x\n",
inb(dev->iobase + DAQP_STATUS), inb(dev->iobase + DAQP_AUX));
}
@@ -207,9 +206,9 @@ static void hex_dump(char *str, void *ptr, int len)
printk(str);
for (i = 0; i < len; i++) {
- if (i % 16 == 0) {
- printk("\n0x%08x:", (unsigned int)cptr);
- }
+ if (i % 16 == 0)
+ printk("\n%p:", cptr);
+
printk(" %02x", *(cptr++));
}
printk("\n");
@@ -223,9 +222,9 @@ static int daqp_ai_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
{
struct local_info_t *local = (struct local_info_t *)s->private;
- if (local->stop) {
+ if (local->stop)
return -EIO;
- }
+
outb(DAQP_COMMAND_STOP, dev->iobase + DAQP_COMMAND);
@@ -355,9 +354,9 @@ static int daqp_ai_insn_read(struct comedi_device *dev,
int v;
int counter = 10000;
- if (local->stop) {
+ if (local->stop)
return -EIO;
- }
+
/* Stop any running conversion */
daqp_ai_cancel(dev, s);
@@ -372,9 +371,9 @@ static int daqp_ai_insn_read(struct comedi_device *dev,
v = DAQP_SCANLIST_CHANNEL(CR_CHAN(insn->chanspec))
| DAQP_SCANLIST_GAIN(CR_RANGE(insn->chanspec));
- if (CR_AREF(insn->chanspec) == AREF_DIFF) {
+ if (CR_AREF(insn->chanspec) == AREF_DIFF)
v |= DAQP_SCANLIST_DIFFERENTIAL;
- }
+
v |= DAQP_SCANLIST_START;
@@ -488,7 +487,10 @@ static int daqp_ai_cmdtest(struct comedi_device *dev,
if (err)
return 1;
- /* step 2: make sure trigger sources are unique and mutually compatible */
+ /*
+ * step 2: make sure trigger sources
+ * are unique and mutually compatible
+ */
/* note that mutual compatibility is not an issue here */
if (cmd->scan_begin_src != TRIG_TIMER &&
@@ -588,9 +590,9 @@ static int daqp_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
int i;
int v;
- if (local->stop) {
+ if (local->stop)
return -EIO;
- }
+
/* Stop any running conversion */
daqp_ai_cancel(dev, s);
@@ -640,13 +642,11 @@ static int daqp_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
v = DAQP_SCANLIST_CHANNEL(CR_CHAN(chanspec))
| DAQP_SCANLIST_GAIN(CR_RANGE(chanspec));
- if (CR_AREF(chanspec) == AREF_DIFF) {
+ if (CR_AREF(chanspec) == AREF_DIFF)
v |= DAQP_SCANLIST_DIFFERENTIAL;
- }
- if (i == 0 || scanlist_start_on_every_entry) {
+ if (i == 0 || scanlist_start_on_every_entry)
v |= DAQP_SCANLIST_START;
- }
outb(v & 0xff, dev->iobase + DAQP_SCANLIST);
outb(v >> 8, dev->iobase + DAQP_SCANLIST);
@@ -760,7 +760,8 @@ static int daqp_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
while (--counter
&& (inb(dev->iobase + DAQP_STATUS) & DAQP_STATUS_EVENTS)) ;
if (!counter) {
- printk("daqp: couldn't clear interrupts in status register\n");
+ printk(KERN_ERR
+ "daqp: couldn't clear interrupts in status register\n");
return -1;
}
@@ -785,9 +786,8 @@ static int daqp_ao_insn_write(struct comedi_device *dev,
int d;
unsigned int chan;
- if (local->stop) {
+ if (local->stop)
return -EIO;
- }
chan = CR_CHAN(insn->chanspec);
d = data[0];
@@ -811,9 +811,8 @@ static int daqp_di_insn_read(struct comedi_device *dev,
{
struct local_info_t *local = (struct local_info_t *)s->private;
- if (local->stop) {
+ if (local->stop)
return -EIO;
- }
data[0] = inb(dev->iobase + DAQP_DIGITAL_IO);
@@ -828,9 +827,8 @@ static int daqp_do_insn_write(struct comedi_device *dev,
{
struct local_info_t *local = (struct local_info_t *)s->private;
- if (local->stop) {
+ if (local->stop)
return -EIO;
- }
outw(data[0] & 0xf, dev->iobase + DAQP_DIGITAL_IO);
@@ -872,13 +870,13 @@ static int daqp_attach(struct comedi_device *dev, struct comedi_devconfig *it)
}
}
- dev->iobase = local->link->io.BasePort1;
+ dev->iobase = local->link->resource[0]->start;
ret = alloc_subdevices(dev, 4);
if (ret < 0)
return ret;
- printk("comedi%d: attaching daqp%d (io 0x%04lx)\n",
+ printk(KERN_INFO "comedi%d: attaching daqp%d (io 0x%04lx)\n",
dev->minor, it->options[0], dev->iobase);
s = dev->subdevices + 0;
@@ -931,7 +929,7 @@ static int daqp_attach(struct comedi_device *dev, struct comedi_devconfig *it)
static int daqp_detach(struct comedi_device *dev)
{
- printk("comedi%d: detaching daqp\n", dev->minor);
+ printk(KERN_INFO "comedi%d: detaching daqp\n", dev->minor);
return 0;
}
@@ -996,14 +994,6 @@ static int daqp_cs_resume(struct pcmcia_device *p_dev);
static int daqp_cs_attach(struct pcmcia_device *);
static void daqp_cs_detach(struct pcmcia_device *);
-/*
- The dev_info variable is the "key" that is used to match up this
- device driver with appropriate cards, through the card configuration
- database.
-*/
-
-static const dev_info_t dev_info = "quatech_daqp_cs";
-
/*======================================================================
daqp_cs_attach() creates an "instance" of the driver, allocating
@@ -1076,8 +1066,7 @@ static void daqp_cs_detach(struct pcmcia_device *link)
/* Unlink device structure, and free it */
dev_table[dev->table_index] = NULL;
- if (dev)
- kfree(dev);
+ kfree(dev);
} /* daqp_cs_detach */
@@ -1103,26 +1092,24 @@ static int daqp_pcmcia_config_loop(struct pcmcia_device *p_dev,
p_dev->conf.Attributes |= CONF_ENABLE_IRQ;
/* IO window settings */
- p_dev->io.NumPorts1 = p_dev->io.NumPorts2 = 0;
+ p_dev->resource[0]->end = p_dev->resource[1]->end = 0;
if ((cfg->io.nwin > 0) || (dflt->io.nwin > 0)) {
cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt->io;
- p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
- if (!(io->flags & CISTPL_IO_8BIT))
- p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_16;
- if (!(io->flags & CISTPL_IO_16BIT))
- p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
- p_dev->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK;
- p_dev->io.BasePort1 = io->win[0].base;
- p_dev->io.NumPorts1 = io->win[0].len;
+ p_dev->io_lines = io->flags & CISTPL_IO_LINES_MASK;
+ p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH;
+ p_dev->resource[0]->flags |=
+ pcmcia_io_cfg_data_width(io->flags);
+ p_dev->resource[0]->start = io->win[0].base;
+ p_dev->resource[0]->end = io->win[0].len;
if (io->nwin > 1) {
- p_dev->io.Attributes2 = p_dev->io.Attributes1;
- p_dev->io.BasePort2 = io->win[1].base;
- p_dev->io.NumPorts2 = io->win[1].len;
+ p_dev->resource[1]->flags = p_dev->resource[0]->flags;
+ p_dev->resource[1]->start = io->win[1].base;
+ p_dev->resource[1]->end = io->win[1].len;
}
}
/* This reserves IO space but doesn't actually enable it */
- return pcmcia_request_io(p_dev, &p_dev->io);
+ return pcmcia_request_io(p_dev);
}
static void daqp_cs_config(struct pcmcia_device *link)
@@ -1154,12 +1141,10 @@ static void daqp_cs_config(struct pcmcia_device *link)
dev_info(&link->dev, "index 0x%02x", link->conf.ConfigIndex);
if (link->conf.Attributes & CONF_ENABLE_IRQ)
printk(", irq %u", link->irq);
- if (link->io.NumPorts1)
- printk(", io 0x%04x-0x%04x", link->io.BasePort1,
- link->io.BasePort1 + link->io.NumPorts1 - 1);
- if (link->io.NumPorts2)
- printk(" & 0x%04x-0x%04x", link->io.BasePort2,
- link->io.BasePort2 + link->io.NumPorts2 - 1);
+ if (link->resource[0])
+ printk(" & %pR", link->resource[0]);
+ if (link->resource[1])
+ printk(" & %pR", link->resource[1]);
printk("\n");
return;
@@ -1228,7 +1213,7 @@ static struct pcmcia_driver daqp_cs_driver = {
.id_table = daqp_cs_id_table,
.owner = THIS_MODULE,
.drv = {
- .name = dev_info,
+ .name = "quatech_daqp_cs",
},
};
diff --git a/drivers/staging/comedi/drivers/rtd520.c b/drivers/staging/comedi/drivers/rtd520.c
index 8626658e778..0367d2b9e2f 100644
--- a/drivers/staging/comedi/drivers/rtd520.c
+++ b/drivers/staging/comedi/drivers/rtd520.c
@@ -2356,4 +2356,44 @@ static int rtd_dio_insn_config(struct comedi_device *dev,
* A convenient macro that defines init_module() and cleanup_module(),
* as necessary.
*/
-COMEDI_PCI_INITCLEANUP(rtd520Driver, rtd520_pci_table);
+static int __devinit rtd520Driver_pci_probe(struct pci_dev *dev,
+ const struct pci_device_id *ent)
+{
+ return comedi_pci_auto_config(dev, rtd520Driver.driver_name);
+}
+
+static void __devexit rtd520Driver_pci_remove(struct pci_dev *dev)
+{
+ comedi_pci_auto_unconfig(dev);
+}
+
+static struct pci_driver rtd520Driver_pci_driver = {
+ .id_table = rtd520_pci_table,
+ .probe = &rtd520Driver_pci_probe,
+ .remove = __devexit_p(&rtd520Driver_pci_remove)
+};
+
+static int __init rtd520Driver_init_module(void)
+{
+ int retval;
+
+ retval = comedi_driver_register(&rtd520Driver);
+ if (retval < 0)
+ return retval;
+
+ rtd520Driver_pci_driver.name = (char *)rtd520Driver.driver_name;
+ return pci_register_driver(&rtd520Driver_pci_driver);
+}
+
+static void __exit rtd520Driver_cleanup_module(void)
+{
+ pci_unregister_driver(&rtd520Driver_pci_driver);
+ comedi_driver_unregister(&rtd520Driver);
+}
+
+module_init(rtd520Driver_init_module);
+module_exit(rtd520Driver_cleanup_module);
+
+MODULE_AUTHOR("Comedi http://www.comedi.org");
+MODULE_DESCRIPTION("Comedi low-level driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/rti800.c b/drivers/staging/comedi/drivers/rti800.c
index 028ed6f89c4..72042b81831 100644
--- a/drivers/staging/comedi/drivers/rti800.c
+++ b/drivers/staging/comedi/drivers/rti800.c
@@ -158,7 +158,18 @@ static struct comedi_driver driver_rti800 = {
.offset = sizeof(struct rti800_board),
};
-COMEDI_INITCLEANUP(driver_rti800);
+static int __init driver_rti800_init_module(void)
+{
+ return comedi_driver_register(&driver_rti800);
+}
+
+static void __exit driver_rti800_cleanup_module(void)
+{
+ comedi_driver_unregister(&driver_rti800);
+}
+
+module_init(driver_rti800_init_module);
+module_exit(driver_rti800_cleanup_module);
static irqreturn_t rti800_interrupt(int irq, void *dev);
@@ -475,3 +486,7 @@ static int rti800_detach(struct comedi_device *dev)
return 0;
}
+
+MODULE_AUTHOR("Comedi http://www.comedi.org");
+MODULE_DESCRIPTION("Comedi low-level driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/rti802.c b/drivers/staging/comedi/drivers/rti802.c
index 2157edcf799..f59cb11590f 100644
--- a/drivers/staging/comedi/drivers/rti802.c
+++ b/drivers/staging/comedi/drivers/rti802.c
@@ -57,7 +57,18 @@ static struct comedi_driver driver_rti802 = {
.detach = rti802_detach,
};
-COMEDI_INITCLEANUP(driver_rti802);
+static int __init driver_rti802_init_module(void)
+{
+ return comedi_driver_register(&driver_rti802);
+}
+
+static void __exit driver_rti802_cleanup_module(void)
+{
+ comedi_driver_unregister(&driver_rti802);
+}
+
+module_init(driver_rti802_init_module);
+module_exit(driver_rti802_cleanup_module);
struct rti802_private {
enum {
@@ -150,3 +161,7 @@ static int rti802_detach(struct comedi_device *dev)
return 0;
}
+
+MODULE_AUTHOR("Comedi http://www.comedi.org");
+MODULE_DESCRIPTION("Comedi low-level driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/s526.c b/drivers/staging/comedi/drivers/s526.c
index 07c21e686f2..3607aaee4af 100644
--- a/drivers/staging/comedi/drivers/s526.c
+++ b/drivers/staging/comedi/drivers/s526.c
@@ -1002,4 +1002,19 @@ static int s526_dio_insn_config(struct comedi_device *dev,
* A convenient macro that defines init_module() and cleanup_module(),
* as necessary.
*/
-COMEDI_INITCLEANUP(driver_s526);
+static int __init driver_s526_init_module(void)
+{
+ return comedi_driver_register(&driver_s526);
+}
+
+static void __exit driver_s526_cleanup_module(void)
+{
+ comedi_driver_unregister(&driver_s526);
+}
+
+module_init(driver_s526_init_module);
+module_exit(driver_s526_cleanup_module);
+
+MODULE_AUTHOR("Comedi http://www.comedi.org");
+MODULE_DESCRIPTION("Comedi low-level driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/s626.c b/drivers/staging/comedi/drivers/s626.c
index a3cc93362ec..d5ba3ab357a 100644
--- a/drivers/staging/comedi/drivers/s626.c
+++ b/drivers/staging/comedi/drivers/s626.c
@@ -60,10 +60,10 @@ INSN_CONFIG instructions:
insn.insn=INSN_CONFIG; //configuration instruction
insn.n=1; //number of operation (must be 1)
insn.data=&initialvalue; //initial value loaded into encoder
- //during configuration
+ //during configuration
insn.subdev=5; //encoder subdevice
insn.chanspec=CR_PACK(encoder_channel,0,AREF_OTHER); //encoder_channel
- //to configure
+ //to configure
comedi_do_insn(cf,&insn); //executing configuration
*/
@@ -224,7 +224,43 @@ static struct dio_private *dio_private_word[]={
#define devpriv ((struct s626_private *)dev->private)
#define diopriv ((struct dio_private *)s->private)
-COMEDI_PCI_INITCLEANUP_NOMODULE(driver_s626, s626_pci_table);
+static int __devinit driver_s626_pci_probe(struct pci_dev *dev,
+ const struct pci_device_id *ent)
+{
+ return comedi_pci_auto_config(dev, driver_s626.driver_name);
+}
+
+static void __devexit driver_s626_pci_remove(struct pci_dev *dev)
+{
+ comedi_pci_auto_unconfig(dev);
+}
+
+static struct pci_driver driver_s626_pci_driver = {
+ .id_table = s626_pci_table,
+ .probe = &driver_s626_pci_probe,
+ .remove = __devexit_p(&driver_s626_pci_remove)
+};
+
+static int __init driver_s626_init_module(void)
+{
+ int retval;
+
+ retval = comedi_driver_register(&driver_s626);
+ if (retval < 0)
+ return retval;
+
+ driver_s626_pci_driver.name = (char *)driver_s626.driver_name;
+ return pci_register_driver(&driver_s626_pci_driver);
+}
+
+static void __exit driver_s626_cleanup_module(void)
+{
+ pci_unregister_driver(&driver_s626_pci_driver);
+ comedi_driver_unregister(&driver_s626);
+}
+
+module_init(driver_s626_init_module);
+module_exit(driver_s626_cleanup_module);
/* ioctl routines */
static int s626_ai_insn_config(struct comedi_device *dev,
@@ -263,7 +299,7 @@ static int s626_enc_insn_write(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_insn *insn, unsigned int *data);
static int s626_ns_to_timer(int *nanosec, int round_mode);
-static int s626_ai_load_polllist(uint8_t * ppl, struct comedi_cmd *cmd);
+static int s626_ai_load_polllist(uint8_t *ppl, struct comedi_cmd *cmd);
static int s626_ai_inttrig(struct comedi_device *dev,
struct comedi_subdevice *s, unsigned int trignum);
static irqreturn_t s626_irq_handler(int irq, void *d);
@@ -294,16 +330,16 @@ static void CloseDMAB(struct comedi_device *dev, struct bufferDMA *pdma,
/* COUNTER OBJECT ------------------------------------------------ */
struct enc_private {
/* Pointers to functions that differ for A and B counters: */
- uint16_t(*GetEnable) (struct comedi_device * dev, struct enc_private *); /* Return clock enable. */
- uint16_t(*GetIntSrc) (struct comedi_device * dev, struct enc_private *); /* Return interrupt source. */
- uint16_t(*GetLoadTrig) (struct comedi_device * dev, struct enc_private *); /* Return preload trigger source. */
- uint16_t(*GetMode) (struct comedi_device * dev, struct enc_private *); /* Return standardized operating mode. */
- void (*PulseIndex) (struct comedi_device * dev, struct enc_private *); /* Generate soft index strobe. */
- void (*SetEnable) (struct comedi_device * dev, struct enc_private *, uint16_t enab); /* Program clock enable. */
- void (*SetIntSrc) (struct comedi_device * dev, struct enc_private *, uint16_t IntSource); /* Program interrupt source. */
- void (*SetLoadTrig) (struct comedi_device * dev, struct enc_private *, uint16_t Trig); /* Program preload trigger source. */
- void (*SetMode) (struct comedi_device * dev, struct enc_private *, uint16_t Setup, uint16_t DisableIntSrc); /* Program standardized operating mode. */
- void (*ResetCapFlags) (struct comedi_device * dev, struct enc_private *); /* Reset event capture flags. */
+ uint16_t(*GetEnable) (struct comedi_device *dev, struct enc_private *); /* Return clock enable. */
+ uint16_t(*GetIntSrc) (struct comedi_device *dev, struct enc_private *); /* Return interrupt source. */
+ uint16_t(*GetLoadTrig) (struct comedi_device *dev, struct enc_private *); /* Return preload trigger source. */
+ uint16_t(*GetMode) (struct comedi_device *dev, struct enc_private *); /* Return standardized operating mode. */
+ void (*PulseIndex) (struct comedi_device *dev, struct enc_private *); /* Generate soft index strobe. */
+ void (*SetEnable) (struct comedi_device *dev, struct enc_private *, uint16_t enab); /* Program clock enable. */
+ void (*SetIntSrc) (struct comedi_device *dev, struct enc_private *, uint16_t IntSource); /* Program interrupt source. */
+ void (*SetLoadTrig) (struct comedi_device *dev, struct enc_private *, uint16_t Trig); /* Program preload trigger source. */
+ void (*SetMode) (struct comedi_device *dev, struct enc_private *, uint16_t Setup, uint16_t DisableIntSrc); /* Program standardized operating mode. */
+ void (*ResetCapFlags) (struct comedi_device *dev, struct enc_private *); /* Reset event capture flags. */
uint16_t MyCRA; /* Address of CRA register. */
uint16_t MyCRB; /* Address of CRB register. */
@@ -543,13 +579,13 @@ static int s626_attach(struct comedi_device *dev, struct comedi_devconfig *it)
devpriv->pdev = pdev;
if (pdev == NULL) {
- printk("s626_attach: Board not present!!!\n");
+ printk(KERN_ERR "s626_attach: Board not present!!!\n");
return -ENODEV;
}
result = comedi_pci_enable(pdev, "s626");
if (result < 0) {
- printk("s626_attach: comedi_pci_enable fails\n");
+ printk(KERN_ERR "s626_attach: comedi_pci_enable fails\n");
return -ENODEV;
}
devpriv->got_regions = 1;
@@ -558,7 +594,7 @@ static int s626_attach(struct comedi_device *dev, struct comedi_devconfig *it)
devpriv->base_addr = ioremap(resourceStart, SIZEOF_ADDRESS_SPACE);
if (devpriv->base_addr == NULL) {
- printk("s626_attach: IOREMAP failed\n");
+ printk(KERN_ERR "s626_attach: IOREMAP failed\n");
return -ENODEV;
}
@@ -579,7 +615,7 @@ static int s626_attach(struct comedi_device *dev, struct comedi_devconfig *it)
pci_alloc_consistent(devpriv->pdev, DMABUF_SIZE, &appdma);
if (devpriv->ANABuf.LogicalBase == NULL) {
- printk("s626_attach: DMA Memory mapping error\n");
+ printk(KERN_ERR "s626_attach: DMA Memory mapping error\n");
return -ENOMEM;
}
@@ -596,7 +632,7 @@ static int s626_attach(struct comedi_device *dev, struct comedi_devconfig *it)
pci_alloc_consistent(devpriv->pdev, DMABUF_SIZE, &appdma);
if (devpriv->RPSBuf.LogicalBase == NULL) {
- printk("s626_attach: DMA Memory mapping error\n");
+ printk(KERN_ERR "s626_attach: DMA Memory mapping error\n");
return -ENOMEM;
}
@@ -622,18 +658,18 @@ static int s626_attach(struct comedi_device *dev, struct comedi_devconfig *it)
/* set up interrupt handler */
if (dev->irq == 0) {
- printk(" unknown irq (bad)\n");
+ printk(KERN_ERR " unknown irq (bad)\n");
} else {
ret = request_irq(dev->irq, s626_irq_handler, IRQF_SHARED,
"s626", dev);
if (ret < 0) {
- printk(" irq not available\n");
+ printk(KERN_ERR " irq not available\n");
dev->irq = 0;
}
}
- DEBUG("s626_attach: -- it opts %d,%d -- \n",
+ DEBUG("s626_attach: -- it opts %d,%d --\n",
it->options[0], it->options[1]);
s = dev->subdevices + 0;
@@ -779,7 +815,8 @@ static int s626_attach(struct comedi_device *dev, struct comedi_devconfig *it)
/* Write I2C control: abort any I2C activity. */
MC_ENABLE(P_MC2, MC2_UPLD_IIC);
/* Invoke command upload */
- while ((RR7146(P_MC2) & MC2_UPLD_IIC) == 0) ;
+ while ((RR7146(P_MC2) & MC2_UPLD_IIC) == 0)
+ ;
/* and wait for upload to complete. */
/* Per SAA7146 data sheet, write to STATUS reg twice to
@@ -788,7 +825,8 @@ static int s626_attach(struct comedi_device *dev, struct comedi_devconfig *it)
WR7146(P_I2CSTAT, I2C_CLKSEL);
/* Write I2C control: reset error flags. */
MC_ENABLE(P_MC2, MC2_UPLD_IIC); /* Invoke command upload */
- while (!MC_TEST(P_MC2, MC2_UPLD_IIC)) ;
+ while (!MC_TEST(P_MC2, MC2_UPLD_IIC))
+ ;
/* and wait for upload to complete. */
}
@@ -828,14 +866,14 @@ static int s626_attach(struct comedi_device *dev, struct comedi_devconfig *it)
* not start up in a defined state after a PCI reset.
*/
-/* PollList = EOPL; // Create a simple polling */
-/* // list for analog input */
-/* // channel 0. */
+/* PollList = EOPL; // Create a simple polling */
+/* // list for analog input */
+/* // channel 0. */
/* ResetADC( dev, &PollList ); */
/* s626_ai_rinsn(dev,dev->subdevices,NULL,data); //( &AdcData ); // */
-/* //Get initial ADC */
-/* //value. */
+/* //Get initial ADC */
+/* //value. */
/* StartVal = data[0]; */
@@ -848,10 +886,10 @@ static int s626_attach(struct comedi_device *dev, struct comedi_devconfig *it)
/* for ( index = 0; index < 500; index++ ) */
/* { */
-/* s626_ai_rinsn(dev,dev->subdevices,NULL,data); */
-/* AdcData = data[0]; //ReadADC( &AdcData ); */
-/* if ( AdcData != StartVal ) */
-/* break; */
+/* s626_ai_rinsn(dev,dev->subdevices,NULL,data); */
+/* AdcData = data[0]; //ReadADC( &AdcData ); */
+/* if ( AdcData != StartVal ) */
+/* break; */
/* } */
/* end initADC */
@@ -1513,7 +1551,7 @@ void ResetADC(struct comedi_device *dev, uint8_t * ppl)
break; /* Exit poll list processing loop. */
}
}
- DEBUG("ResetADC: ADC items %d \n", devpriv->AdcItems);
+ DEBUG("ResetADC: ADC items %d\n", devpriv->AdcItems);
/* VERSION 2.01 CHANGE: DELAY CHANGED FROM 250NS to 2US. Allow the
* ADC to stabilize for 2 microseconds before starting the final
@@ -1574,7 +1612,7 @@ static int s626_ai_insn_config(struct comedi_device *dev,
/* register uint8_t i; */
/* register int32_t *readaddr; */
-/* DEBUG("as626_ai_rinsn: ai_rinsn enter \n"); */
+/* DEBUG("as626_ai_rinsn: ai_rinsn enter\n"); */
/* Trigger ADC scan loop start by setting RPS Signal 0. */
/* MC_ENABLE( P_MC2, MC2_ADC_RPS ); */
@@ -1591,11 +1629,11 @@ static int s626_ai_insn_config(struct comedi_device *dev,
/* Convert ADC data to 16-bit integer values and copy to application buffer. */
/* for ( i = 0; i < devpriv->AdcItems; i++ ) { */
/* *data = s626_ai_reg_to_uint( *readaddr++ ); */
-/* DEBUG("s626_ai_rinsn: data %d \n",*data); */
+/* DEBUG("s626_ai_rinsn: data %d\n",*data); */
/* data++; */
/* } */
-/* DEBUG("s626_ai_rinsn: ai_rinsn escape \n"); */
+/* DEBUG("s626_ai_rinsn: ai_rinsn escape\n"); */
/* return i; */
/* } */
@@ -1651,7 +1689,8 @@ static int s626_ai_insn_read(struct comedi_device *dev,
/* shift into FB BUFFER 1 register. */
/* Wait for ADC done. */
- while (!(RR7146(P_PSR) & PSR_GPIO2)) ;
+ while (!(RR7146(P_PSR) & PSR_GPIO2))
+ ;
/* Fetch ADC data. */
if (n != 0)
@@ -1683,7 +1722,8 @@ static int s626_ai_insn_read(struct comedi_device *dev,
/* Wait for the data to arrive in FB BUFFER 1 register. */
/* Wait for ADC done. */
- while (!(RR7146(P_PSR) & PSR_GPIO2)) ;
+ while (!(RR7146(P_PSR) & PSR_GPIO2))
+ ;
/* Fetch ADC data from audio interface's input shift register. */
@@ -1696,7 +1736,7 @@ static int s626_ai_insn_read(struct comedi_device *dev,
return n;
}
-static int s626_ai_load_polllist(uint8_t * ppl, struct comedi_cmd *cmd)
+static int s626_ai_load_polllist(uint8_t *ppl, struct comedi_cmd *cmd)
{
int n;
@@ -1743,7 +1783,7 @@ static int s626_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
DEBUG("s626_ai_cmd: entering command function\n");
if (devpriv->ai_cmd_running) {
- printk("s626_ai_cmd: Another ai_cmd is running %d\n",
+ printk(KERN_ERR "s626_ai_cmd: Another ai_cmd is running %d\n",
dev->minor);
return -EBUSY;
}
@@ -2147,7 +2187,7 @@ static void s626_dio_init(struct comedi_device *dev)
DEBIwrite(dev, diopriv->WRDOut, 0); /* Program all outputs */
/* to inactive state. */
}
- DEBUG("s626_dio_init: DIO initialized \n");
+ DEBUG("s626_dio_init: DIO initialized\n");
}
/* DIO devices are slightly special. Although it is possible to
@@ -2346,7 +2386,7 @@ static int s626_enc_insn_read(struct comedi_device *dev,
int n;
struct enc_private *k = &encpriv[CR_CHAN(insn->chanspec)];
- DEBUG("s626_enc_insn_read: encoder read channel %d \n",
+ DEBUG("s626_enc_insn_read: encoder read channel %d\n",
CR_CHAN(insn->chanspec));
for (n = 0; n < insn->n; n++)
@@ -2364,7 +2404,7 @@ static int s626_enc_insn_write(struct comedi_device *dev,
struct enc_private *k = &encpriv[CR_CHAN(insn->chanspec)];
- DEBUG("s626_enc_insn_write: encoder write channel %d \n",
+ DEBUG("s626_enc_insn_write: encoder write channel %d\n",
CR_CHAN(insn->chanspec));
/* Set the preload register */
@@ -2425,8 +2465,7 @@ static void s626_timer_load(struct comedi_device *dev, struct enc_private *k,
static uint8_t trimchan[] = { 10, 9, 8, 3, 2, 7, 6, 1, 0, 5, 4 };
/* TrimDac LogicalChan-to-EepromAdrs mapping table. */
-static uint8_t trimadrs[] =
- { 0x40, 0x41, 0x42, 0x50, 0x51, 0x52, 0x53, 0x60, 0x61, 0x62, 0x63 };
+static uint8_t trimadrs[] = { 0x40, 0x41, 0x42, 0x50, 0x51, 0x52, 0x53, 0x60, 0x61, 0x62, 0x63 };
static void LoadTrimDACs(struct comedi_device *dev)
{
@@ -2524,10 +2563,12 @@ static uint32_t I2Chandshake(struct comedi_device *dev, uint32_t val)
/* upload confirmation. */
MC_ENABLE(P_MC2, MC2_UPLD_IIC);
- while (!MC_TEST(P_MC2, MC2_UPLD_IIC)) ;
+ while (!MC_TEST(P_MC2, MC2_UPLD_IIC))
+ ;
/* Wait until I2C bus transfer is finished or an error occurs. */
- while ((RR7146(P_I2CCTRL) & (I2C_BUSY | I2C_ERR)) == I2C_BUSY) ;
+ while ((RR7146(P_I2CCTRL) & (I2C_BUSY | I2C_ERR)) == I2C_BUSY)
+ ;
/* Return non-zero if I2C error occured. */
return RR7146(P_I2CCTRL) & I2C_ERR;
@@ -2641,7 +2682,8 @@ static void SendDAC(struct comedi_device *dev, uint32_t val)
* Done by polling the DMAC enable flag; this flag is automatically
* cleared when the transfer has finished.
*/
- while ((RR7146(P_MC1) & MC1_A2OUT) != 0) ;
+ while ((RR7146(P_MC1) & MC1_A2OUT) != 0)
+ ;
/* START THE OUTPUT STREAM TO THE TARGET DAC -------------------- */
@@ -2658,7 +2700,8 @@ static void SendDAC(struct comedi_device *dev, uint32_t val)
* finished transferring the DAC's data DWORD from the output FIFO
* to the output buffer register.
*/
- while ((RR7146(P_SSR) & SSR_AF2_OUT) == 0) ;
+ while ((RR7146(P_SSR) & SSR_AF2_OUT) == 0)
+ ;
/* Set up to trap execution at slot 0 when the TSL sequencer cycles
* back to slot 0 after executing the EOS in slot 5. Also,
@@ -2694,7 +2737,8 @@ static void SendDAC(struct comedi_device *dev, uint32_t val)
* from 0xFF to 0x00, which slot 0 causes to happen by shifting
* out/in on SD2 the 0x00 that is always referenced by slot 5.
*/
- while ((RR7146(P_FB_BUFFER2) & 0xFF000000) != 0) ;
+ while ((RR7146(P_FB_BUFFER2) & 0xFF000000) != 0)
+ ;
}
/* Either (1) we were too late setting the slot 0 trap; the TSL
* sequencer restarted slot 0 before we could set the EOS trap flag,
@@ -2710,7 +2754,8 @@ static void SendDAC(struct comedi_device *dev, uint32_t val)
* the next DAC write. This is detected when FB_BUFFER2 MSB changes
* from 0x00 to 0xFF.
*/
- while ((RR7146(P_FB_BUFFER2) & 0xFF000000) == 0) ;
+ while ((RR7146(P_FB_BUFFER2) & 0xFF000000) == 0)
+ ;
}
static void WriteMISC2(struct comedi_device *dev, uint16_t NewImage)
@@ -2749,10 +2794,12 @@ static void DEBItransfer(struct comedi_device *dev)
/* Wait for completion of upload from shadow RAM to DEBI control */
/* register. */
- while (!MC_TEST(P_MC2, MC2_UPLD_DEBI)) ;
+ while (!MC_TEST(P_MC2, MC2_UPLD_DEBI))
+ ;
/* Wait until DEBI transfer is done. */
- while (RR7146(P_PSR) & PSR_DEBI_S) ;
+ while (RR7146(P_PSR) & PSR_DEBI_S)
+ ;
}
/* Write a value to a gate array register. */
@@ -3099,18 +3146,18 @@ static uint16_t GetEnable_B(struct comedi_device *dev, struct enc_private *k)
static void SetLatchSource(struct comedi_device *dev, struct enc_private *k,
uint16_t value)
{
- DEBUG("SetLatchSource: SetLatchSource enter 3550 \n");
+ DEBUG("SetLatchSource: SetLatchSource enter 3550\n");
DEBIreplace(dev, k->MyCRB,
(uint16_t) (~(CRBMSK_INTCTRL | CRBMSK_LATCHSRC)),
(uint16_t) (value << CRBBIT_LATCHSRC));
- DEBUG("SetLatchSource: SetLatchSource exit \n");
+ DEBUG("SetLatchSource: SetLatchSource exit\n");
}
/*
* static uint16_t GetLatchSource(struct comedi_device *dev, struct enc_private *k )
* {
- * return ( DEBIread( dev, k->MyCRB) >> CRBBIT_LATCHSRC ) & 3;
+ * return ( DEBIread( dev, k->MyCRB) >> CRBBIT_LATCHSRC ) & 3;
* }
*/
@@ -3317,6 +3364,6 @@ static void CountersInit(struct comedi_device *dev)
k->ResetCapFlags(dev, k);
k->SetEnable(dev, k, CLKENAB_ALWAYS);
}
- DEBUG("CountersInit: counters initialized \n");
+ DEBUG("CountersInit: counters initialized\n");
}
diff --git a/drivers/staging/comedi/drivers/s626.h b/drivers/staging/comedi/drivers/s626.h
index d02742a9529..2d1afecbbb6 100644
--- a/drivers/staging/comedi/drivers/s626.h
+++ b/drivers/staging/comedi/drivers/s626.h
@@ -720,15 +720,6 @@
#define STDMSK_CLKMULT ((uint16_t)(3 << STDBIT_CLKMULT))
#define STDMSK_CLKENAB ((uint16_t)(1 << STDBIT_CLKENAB))
-/* typedef struct indexCounter */
-/* { */
-/* unsigned int ao; */
-/* unsigned int ai; */
-/* unsigned int digout; */
-/* unsigned int digin; */
-/* unsigned int enc; */
-/* }CallCounter; */
-
struct bufferDMA {
dma_addr_t PhysicalBase;
void *LogicalBase;
diff --git a/drivers/staging/comedi/drivers/serial2002.c b/drivers/staging/comedi/drivers/serial2002.c
index 0792617ebc3..c9be9e05f02 100644
--- a/drivers/staging/comedi/drivers/serial2002.c
+++ b/drivers/staging/comedi/drivers/serial2002.c
@@ -393,15 +393,16 @@ static void serial_write(struct file *f, struct serial_data data)
}
}
-static void serial_2002_open(struct comedi_device *dev)
+static int serial_2002_open(struct comedi_device *dev)
{
+ int result;
char port[20];
sprintf(port, "/dev/ttyS%d", devpriv->port);
devpriv->tty = filp_open(port, O_RDWR, 0);
if (IS_ERR(devpriv->tty)) {
- printk("serial_2002: file open error = %ld\n",
- PTR_ERR(devpriv->tty));
+ result = (int)PTR_ERR(devpriv->tty);
+ printk("serial_2002: file open error = %d\n", result);
} else {
struct config_t {
@@ -411,29 +412,25 @@ static void serial_2002_open(struct comedi_device *dev)
int max;
};
- struct config_t dig_in_config[32];
- struct config_t dig_out_config[32];
- struct config_t chan_in_config[32];
- struct config_t chan_out_config[32];
+ struct config_t *dig_in_config;
+ struct config_t *dig_out_config;
+ struct config_t *chan_in_config;
+ struct config_t *chan_out_config;
int i;
- for (i = 0; i < 32; i++) {
- dig_in_config[i].kind = 0;
- dig_in_config[i].bits = 0;
- dig_in_config[i].min = 0;
- dig_in_config[i].max = 0;
- dig_out_config[i].kind = 0;
- dig_out_config[i].bits = 0;
- dig_out_config[i].min = 0;
- dig_out_config[i].max = 0;
- chan_in_config[i].kind = 0;
- chan_in_config[i].bits = 0;
- chan_in_config[i].min = 0;
- chan_in_config[i].max = 0;
- chan_out_config[i].kind = 0;
- chan_out_config[i].bits = 0;
- chan_out_config[i].min = 0;
- chan_out_config[i].max = 0;
+ result = 0;
+ dig_in_config = kcalloc(32, sizeof(struct config_t),
+ GFP_KERNEL);
+ dig_out_config = kcalloc(32, sizeof(struct config_t),
+ GFP_KERNEL);
+ chan_in_config = kcalloc(32, sizeof(struct config_t),
+ GFP_KERNEL);
+ chan_out_config = kcalloc(32, sizeof(struct config_t),
+ GFP_KERNEL);
+ if (!dig_in_config || !dig_out_config
+ || !chan_in_config || !chan_out_config) {
+ result = -ENOMEM;
+ goto err_alloc_configs;
}
tty_setspeed(devpriv->tty, devpriv->speed);
@@ -447,7 +444,7 @@ static void serial_2002_open(struct comedi_device *dev)
break;
} else {
int command, channel, kind;
- struct config_t *cur_config = 0;
+ struct config_t *cur_config = NULL;
channel = data.value & 0x1f;
kind = (data.value >> 5) & 0x7;
@@ -574,8 +571,8 @@ static void serial_2002_open(struct comedi_device *dev)
for (i = 0; i <= 4; i++) {
/* Fill in subdev data */
struct config_t *c;
- unsigned char *mapping = 0;
- struct serial2002_range_table_t *range = 0;
+ unsigned char *mapping = NULL;
+ struct serial2002_range_table_t *range = NULL;
int kind = 0;
switch (i) {
@@ -613,7 +610,7 @@ static void serial_2002_open(struct comedi_device *dev)
}
break;
default:{
- c = 0;
+ c = NULL;
}
break;
}
@@ -632,22 +629,23 @@ static void serial_2002_open(struct comedi_device *dev)
s = &dev->subdevices[i];
s->n_chan = chan;
s->maxdata = 0;
- if (s->maxdata_list) {
- kfree(s->maxdata_list);
- }
+ kfree(s->maxdata_list);
s->maxdata_list = maxdata_list =
kmalloc(sizeof(unsigned int) * s->n_chan,
GFP_KERNEL);
- if (s->range_table_list) {
- kfree(s->range_table_list);
- }
+ if (!s->maxdata_list)
+ break; /* error handled below */
+ kfree(s->range_table_list);
+ s->range_table = NULL;
+ s->range_table_list = NULL;
if (range) {
- s->range_table = 0;
s->range_table_list = range_table_list =
kmalloc(sizeof
(struct
serial2002_range_table_t) *
s->n_chan, GFP_KERNEL);
+ if (!s->range_table_list)
+ break; /* err handled below */
}
for (chan = 0, j = 0; j < 32; j++) {
if (c[j].kind == kind) {
@@ -673,7 +671,35 @@ static void serial_2002_open(struct comedi_device *dev)
}
}
}
+ if (i <= 4) {
+ /* Failed to allocate maxdata_list or range_table_list
+ * for a subdevice that needed it. */
+ result = -ENOMEM;
+ for (i = 0; i <= 4; i++) {
+ struct comedi_subdevice *s;
+
+ s = &dev->subdevices[i];
+ kfree(s->maxdata_list);
+ s->maxdata_list = NULL;
+ kfree(s->range_table_list);
+ s->range_table_list = NULL;
+ }
+ }
+
+err_alloc_configs:
+ kfree(dig_in_config);
+ kfree(dig_out_config);
+ kfree(chan_in_config);
+ kfree(chan_out_config);
+
+ if (result) {
+ if (devpriv->tty) {
+ filp_close(devpriv->tty, 0);
+ devpriv->tty = NULL;
+ }
+ }
}
+ return result;
}
static void serial_2002_close(struct comedi_device *dev)
@@ -879,7 +905,7 @@ static int serial2002_detach(struct comedi_device *dev)
int i;
printk("comedi%d: serial2002: remove\n", dev->minor);
- for (i = 0; i < 4; i++) {
+ for (i = 0; i < 5; i++) {
s = &dev->subdevices[i];
if (s->maxdata_list) {
kfree(s->maxdata_list);
@@ -891,4 +917,19 @@ static int serial2002_detach(struct comedi_device *dev)
return 0;
}
-COMEDI_INITCLEANUP(driver_serial2002);
+static int __init driver_serial2002_init_module(void)
+{
+ return comedi_driver_register(&driver_serial2002);
+}
+
+static void __exit driver_serial2002_cleanup_module(void)
+{
+ comedi_driver_unregister(&driver_serial2002);
+}
+
+module_init(driver_serial2002_init_module);
+module_exit(driver_serial2002_cleanup_module);
+
+MODULE_AUTHOR("Comedi http://www.comedi.org");
+MODULE_DESCRIPTION("Comedi low-level driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/skel.c b/drivers/staging/comedi/drivers/skel.c
index 490753b3d90..0b9ecb19511 100644
--- a/drivers/staging/comedi/drivers/skel.c
+++ b/drivers/staging/comedi/drivers/skel.c
@@ -39,28 +39,28 @@ Configuration Options:
* The previous block comment is used to automatically generate
* documentation in Comedi and Comedilib. The fields:
*
- * Driver: the name of the driver
- * Description: a short phrase describing the driver. Don't list boards.
- * Devices: a full list of the boards that attempt to be supported by
- * the driver. Format is "(manufacturer) board name [comedi name]",
- * where comedi_name is the name that is used to configure the board.
- * See the comment near board_name: in the struct comedi_driver structure
- * below. If (manufacturer) or [comedi name] is missing, the previous
- * value is used.
- * Author: you
- * Updated: date when the _documentation_ was last updated. Use 'date -R'
- * to get a value for this.
- * Status: a one-word description of the status. Valid values are:
- * works - driver works correctly on most boards supported, and
- * passes comedi_test.
- * unknown - unknown. Usually put there by ds.
- * experimental - may not work in any particular release. Author
- * probably wants assistance testing it.
- * bitrotten - driver has not been update in a long time, probably
- * doesn't work, and probably is missing support for significant
- * Comedi interface features.
- * untested - author probably wrote it "blind", and is believed to
- * work, but no confirmation.
+ * Driver: the name of the driver
+ * Description: a short phrase describing the driver. Don't list boards.
+ * Devices: a full list of the boards that attempt to be supported by
+ * the driver. Format is "(manufacturer) board name [comedi name]",
+ * where comedi_name is the name that is used to configure the board.
+ * See the comment near board_name: in the struct comedi_driver structure
+ * below. If (manufacturer) or [comedi name] is missing, the previous
+ * value is used.
+ * Author: you
+ * Updated: date when the _documentation_ was last updated. Use 'date -R'
+ * to get a value for this.
+ * Status: a one-word description of the status. Valid values are:
+ * works - driver works correctly on most boards supported, and
+ * passes comedi_test.
+ * unknown - unknown. Usually put there by ds.
+ * experimental - may not work in any particular release. Author
+ * probably wants assistance testing it.
+ * bitrotten - driver has not been update in a long time, probably
+ * doesn't work, and probably is missing support for significant
+ * Comedi interface features.
+ * untested - author probably wrote it "blind", and is believed to
+ * work, but no confirmation.
*
* These headers should be followed by a blank line, and any comments
* you wish to say about the driver. The comment area is the place
@@ -620,12 +620,59 @@ static int skel_dio_insn_config(struct comedi_device *dev,
return insn->n;
}
-/*
- * A convenient macro that defines init_module() and cleanup_module(),
- * as necessary.
- */
-COMEDI_INITCLEANUP(driver_skel);
-/* If you are writing a PCI driver you should use COMEDI_PCI_INITCLEANUP
- * instead.
- */
-/* COMEDI_PCI_INITCLEANUP(driver_skel, skel_pci_table) */
+#ifdef CONFIG_COMEDI_PCI
+static int __devinit driver_skel_pci_probe(struct pci_dev *dev,
+ const struct pci_device_id *ent)
+{
+ return comedi_pci_auto_config(dev, driver_skel.driver_name);
+}
+
+static void __devexit driver_skel_pci_remove(struct pci_dev *dev)
+{
+ comedi_pci_auto_unconfig(dev);
+}
+
+static struct pci_driver driver_skel_pci_driver = {
+ .id_table = skel_pci_table,
+ .probe = &driver_skel_pci_probe,
+ .remove = __devexit_p(&driver_skel_pci_remove)
+};
+
+static int __init driver_skel_init_module(void)
+{
+ int retval;
+
+ retval = comedi_driver_register(&driver_skel);
+ if (retval < 0)
+ return retval;
+
+ driver_skel_pci_driver.name = (char *)driver_skel.driver_name;
+ return pci_register_driver(&driver_skel_pci_driver);
+}
+
+static void __exit driver_skel_cleanup_module(void)
+{
+ pci_unregister_driver(&driver_skel_pci_driver);
+ comedi_driver_unregister(&driver_skel);
+}
+
+module_init(driver_skel_init_module);
+module_exit(driver_skel_cleanup_module);
+#else
+static int __init driver_skel_init_module(void)
+{
+ return comedi_driver_register(&driver_skel);
+}
+
+static void __exit driver_skel_cleanup_module(void)
+{
+ comedi_driver_unregister(&driver_skel);
+}
+
+module_init(driver_skel_init_module);
+module_exit(driver_skel_cleanup_module);
+#endif
+
+MODULE_AUTHOR("Comedi http://www.comedi.org");
+MODULE_DESCRIPTION("Comedi low-level driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/ssv_dnp.c b/drivers/staging/comedi/drivers/ssv_dnp.c
index 18b0a83c4bb..526de2efa12 100644
--- a/drivers/staging/comedi/drivers/ssv_dnp.c
+++ b/drivers/staging/comedi/drivers/ssv_dnp.c
@@ -102,7 +102,18 @@ static struct comedi_driver driver_dnp = {
.num_names = ARRAY_SIZE(dnp_boards),
};
-COMEDI_INITCLEANUP(driver_dnp);
+static int __init driver_dnp_init_module(void)
+{
+ return comedi_driver_register(&driver_dnp);
+}
+
+static void __exit driver_dnp_cleanup_module(void)
+{
+ comedi_driver_unregister(&driver_dnp);
+}
+
+module_init(driver_dnp_init_module);
+module_exit(driver_dnp_cleanup_module);
static int dnp_dio_insn_bits(struct comedi_device *dev,
struct comedi_subdevice *s,
@@ -314,3 +325,7 @@ static int dnp_dio_insn_config(struct comedi_device *dev,
return 1;
}
+
+MODULE_AUTHOR("Comedi http://www.comedi.org");
+MODULE_DESCRIPTION("Comedi low-level driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/unioxx5.c b/drivers/staging/comedi/drivers/unioxx5.c
index 16d4c9f6916..598884ec3ed 100644
--- a/drivers/staging/comedi/drivers/unioxx5.c
+++ b/drivers/staging/comedi/drivers/unioxx5.c
@@ -114,7 +114,18 @@ static struct comedi_driver unioxx5_driver = {
.detach = unioxx5_detach
};
-COMEDI_INITCLEANUP(unioxx5_driver);
+static int __init unioxx5_driver_init_module(void)
+{
+ return comedi_driver_register(&unioxx5_driver);
+}
+
+static void __exit unioxx5_driver_cleanup_module(void)
+{
+ comedi_driver_unregister(&unioxx5_driver);
+}
+
+module_init(unioxx5_driver_init_module);
+module_exit(unioxx5_driver_cleanup_module);
static int unioxx5_attach(struct comedi_device *dev,
struct comedi_devconfig *it)
@@ -302,7 +313,8 @@ static int __unioxx5_subdev_init(struct comedi_subdevice *subdev,
__unioxx5_analog_config(usp, i * 2);
outb(i + 1, subdev_iobase + 5); /* sends channel number to card */
outb('H', subdev_iobase + 6); /* requests EEPROM world */
- while (!(inb(subdev_iobase + 0) & TxBE)) ; /* waits while writting will be allowed */
+ while (!(inb(subdev_iobase + 0) & TxBE))
+ ; /* waits while writting will be allowed */
outb(0, subdev_iobase + 6);
/* waits while reading of two bytes will be allowed */
@@ -437,7 +449,8 @@ static int __unioxx5_analog_write(struct unioxx5_subd_priv *usp,
/* sending for bytes to module(one byte per cycle iteration) */
for (i = 0; i < 4; i++) {
- while (!((inb(usp->usp_iobase + 0)) & TxBE)) ; /* waits while writting will be allowed */
+ while (!((inb(usp->usp_iobase + 0)) & TxBE))
+ ; /* waits while writting will be allowed */
outb(usp->usp_extra_data[module][i], usp->usp_iobase + 6);
}
@@ -467,7 +480,8 @@ static int __unioxx5_analog_read(struct unioxx5_subd_priv *usp,
control = inb(usp->usp_iobase); /* get control register byte */
/* waits while reading four bytes will be allowed */
- while (!((control = inb(usp->usp_iobase + 0)) & Rx4CA)) ;
+ while (!((control = inb(usp->usp_iobase + 0)) & Rx4CA))
+ ;
/* if four bytes readding error occurs - return 0(false) */
if ((control & Rx4CA_ERR_MASK)) {
@@ -526,3 +540,7 @@ static int __unioxx5_define_chan_offset(int chan_num)
return (chan_num >> 3) + 1;
}
+
+MODULE_AUTHOR("Comedi http://www.comedi.org");
+MODULE_DESCRIPTION("Comedi low-level driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/usbdux.c b/drivers/staging/comedi/drivers/usbdux.c
index 27b4cb2e2ec..4b320b1ff82 100644
--- a/drivers/staging/comedi/drivers/usbdux.c
+++ b/drivers/staging/comedi/drivers/usbdux.c
@@ -111,7 +111,7 @@ sampling rate. If you sample two channels you get 4kHz and so on.
#define VENDOR_DIR_IN 0xC0
#define VENDOR_DIR_OUT 0x40
-/* internal adresses of the 8051 processor */
+/* internal addresses of the 8051 processor */
#define USBDUXSUB_CPUCS 0xE600
/*
@@ -2085,7 +2085,7 @@ static int usbdux_pwm_start(struct comedi_device *dev,
if (ret < 0)
return ret;
- /* initalise the buffer */
+ /* initialise the buffer */
for (i = 0; i < this_usbduxsub->sizePwmBuf; i++)
((char *)(this_usbduxsub->urbPwm->transfer_buffer))[i] = 0;
diff --git a/drivers/staging/comedi/drivers/usbduxfast.c b/drivers/staging/comedi/drivers/usbduxfast.c
index 29c3c016b93..0a164a9a66c 100644
--- a/drivers/staging/comedi/drivers/usbduxfast.c
+++ b/drivers/staging/comedi/drivers/usbduxfast.c
@@ -67,7 +67,7 @@
#define VENDOR_DIR_OUT 0x40
/*
- * internal adresses of the 8051 processor
+ * internal addresses of the 8051 processor
*/
#define USBDUXFASTSUB_CPUCS 0xE600
diff --git a/drivers/staging/comedi/kcomedilib/kcomedilib_main.c b/drivers/staging/comedi/kcomedilib/kcomedilib_main.c
index 863aae40ede..0252b440885 100644
--- a/drivers/staging/comedi/kcomedilib/kcomedilib_main.c
+++ b/drivers/staging/comedi/kcomedilib/kcomedilib_main.c
@@ -93,7 +93,7 @@ static int comedi_do_insn(struct comedi_device *dev, struct comedi_insn *insn)
s = dev->subdevices + insn->subdev;
if (s->type == COMEDI_SUBD_UNUSED) {
- printk("%d not useable subdevice\n", insn->subdev);
+ printk(KERN_ERR "%d not useable subdevice\n", insn->subdev);
ret = -EIO;
goto error;
}
@@ -102,7 +102,7 @@ static int comedi_do_insn(struct comedi_device *dev, struct comedi_insn *insn)
ret = comedi_check_chanlist(s, 1, &insn->chanspec);
if (ret < 0) {
- printk("bad chanspec\n");
+ printk(KERN_ERR "bad chanspec\n");
ret = -EINVAL;
goto error;
}
diff --git a/drivers/staging/crystalhd/crystalhd_lnx.c b/drivers/staging/crystalhd/crystalhd_lnx.c
index a4ec891328c..fbb80f09a3d 100644
--- a/drivers/staging/crystalhd/crystalhd_lnx.c
+++ b/drivers/staging/crystalhd/crystalhd_lnx.c
@@ -15,11 +15,12 @@
along with this driver. If not, see <http://www.gnu.org/licenses/>.
***************************************************************************/
-#include <linux/smp_lock.h>
+#include <linux/mutex.h>
#include <linux/slab.h>
#include "crystalhd_lnx.h"
+static DEFINE_MUTEX(chd_dec_mutex);
static struct class *crystalhd_class;
static struct crystalhd_adp *g_adp_info;
@@ -152,10 +153,8 @@ static int chd_dec_fetch_cdata(struct crystalhd_adp *adp, struct crystalhd_ioctl
if (rc) {
BCMLOG_ERR("failed to pull add_cdata sz:%x ua_off:%x\n",
io->add_cdata_sz, (unsigned int)ua_off);
- if (io->add_cdata) {
- kfree(io->add_cdata);
- io->add_cdata = NULL;
- }
+ kfree(io->add_cdata);
+ io->add_cdata = NULL;
return -ENODATA;
}
@@ -273,22 +272,22 @@ static long chd_dec_ioctl(struct file *fd, unsigned int cmd, unsigned long ua)
return -EINVAL;
}
- uc = (struct crystalhd_user *)fd->private_data;
+ uc = fd->private_data;
if (!uc) {
BCMLOG_ERR("Failed to get uc\n");
return -ENODATA;
}
- lock_kernel();
+ mutex_lock(&chd_dec_mutex);
cproc = crystalhd_get_cmd_proc(&adp->cmds, cmd, uc);
if (!cproc) {
BCMLOG_ERR("Unhandled command: %d\n", cmd);
- unlock_kernel();
+ mutex_unlock(&chd_dec_mutex);
return -EINVAL;
}
ret = chd_dec_api_cmd(adp, ua, uc->uid, cmd, cproc);
- unlock_kernel();
+ mutex_unlock(&chd_dec_mutex);
return ret;
}
@@ -334,7 +333,7 @@ static int chd_dec_close(struct inode *in, struct file *fd)
return -EINVAL;
}
- uc = (struct crystalhd_user *)fd->private_data;
+ uc = fd->private_data;
if (!uc) {
BCMLOG_ERR("Failed to get uc\n");
return -ENODATA;
@@ -435,8 +434,7 @@ static void __devexit chd_dec_release_chdev(struct crystalhd_adp *adp)
/* Clear iodata pool.. */
do {
temp = chd_dec_alloc_iodata(adp, 0);
- if (temp)
- kfree(temp);
+ kfree(temp);
} while (temp);
crystalhd_delete_elem_pool(adp);
diff --git a/drivers/staging/cx25821/Makefile b/drivers/staging/cx25821/Makefile
index 10f87f05d8e..d0eb16eac09 100644
--- a/drivers/staging/cx25821/Makefile
+++ b/drivers/staging/cx25821/Makefile
@@ -1,9 +1,8 @@
-cx25821-objs := cx25821-core.o cx25821-cards.o cx25821-i2c.o cx25821-gpio.o \
- cx25821-medusa-video.o cx25821-video.o cx25821-video0.o cx25821-video1.o \
- cx25821-video2.o cx25821-video3.o cx25821-video4.o cx25821-video5.o \
- cx25821-video6.o cx25821-video7.o cx25821-vidups9.o cx25821-vidups10.o \
- cx25821-audups11.o cx25821-video-upstream.o cx25821-video-upstream-ch2.o \
- cx25821-audio-upstream.o cx25821-videoioctl.o
+cx25821-objs := cx25821-core.o cx25821-cards.o cx25821-i2c.o \
+ cx25821-gpio.o cx25821-medusa-video.o \
+ cx25821-video.o cx25821-video-upstream.o \
+ cx25821-video-upstream-ch2.o \
+ cx25821-audio-upstream.o
obj-$(CONFIG_VIDEO_CX25821) += cx25821.o
obj-$(CONFIG_VIDEO_CX25821_ALSA) += cx25821-alsa.o
diff --git a/drivers/staging/cx25821/cx25821-alsa.c b/drivers/staging/cx25821/cx25821-alsa.c
index 1798975a69b..bbe36437ac1 100644
--- a/drivers/staging/cx25821/cx25821-alsa.c
+++ b/drivers/staging/cx25821/cx25821-alsa.c
@@ -55,6 +55,12 @@
static struct snd_card *snd_cx25821_cards[SNDRV_CARDS];
static int devno;
+struct cx25821_audio_buffer {
+ unsigned int bpl;
+ struct btcx_riscmem risc;
+ struct videobuf_dmabuf dma;
+};
+
struct cx25821_audio_dev {
struct cx25821_dev *dev;
struct cx25821_dmaqueue q;
@@ -77,7 +83,7 @@ struct cx25821_audio_dev {
struct videobuf_dmabuf *dma_risc;
- struct cx25821_buffer *buf;
+ struct cx25821_audio_buffer *buf;
struct snd_pcm_substream *substream;
};
@@ -136,7 +142,7 @@ MODULE_PARM_DESC(debug, "enable debug messages");
static int _cx25821_start_audio_dma(struct cx25821_audio_dev *chip)
{
- struct cx25821_buffer *buf = chip->buf;
+ struct cx25821_audio_buffer *buf = chip->buf;
struct cx25821_dev *dev = chip->dev;
struct sram_channel *audio_ch =
&cx25821_sram_channels[AUDIO_SRAM_CHANNEL];
@@ -331,7 +337,7 @@ static int dsp_buffer_free(struct cx25821_audio_dev *chip)
BUG_ON(!chip->dma_size);
dprintk(2, "Freeing buffer\n");
- videobuf_sg_dma_unmap(&chip->pci->dev, chip->dma_risc);
+ videobuf_dma_unmap(&chip->pci->dev, chip->dma_risc);
videobuf_dma_free(chip->dma_risc);
btcx_riscmem_free(chip->pci, &chip->buf->risc);
kfree(chip->buf);
@@ -432,7 +438,7 @@ static int snd_cx25821_hw_params(struct snd_pcm_substream *substream,
struct cx25821_audio_dev *chip = snd_pcm_substream_chip(substream);
struct videobuf_dmabuf *dma;
- struct cx25821_buffer *buf;
+ struct cx25821_audio_buffer *buf;
int ret;
if (substream->runtime->dma_area) {
@@ -447,36 +453,31 @@ static int snd_cx25821_hw_params(struct snd_pcm_substream *substream,
BUG_ON(!chip->dma_size);
BUG_ON(chip->num_periods & (chip->num_periods - 1));
- buf = videobuf_sg_alloc(sizeof(*buf));
+ buf = kzalloc(sizeof(*buf), GFP_KERNEL);
if (NULL == buf)
return -ENOMEM;
if (chip->period_size > AUDIO_LINE_SIZE)
chip->period_size = AUDIO_LINE_SIZE;
- buf->vb.memory = V4L2_MEMORY_MMAP;
- buf->vb.field = V4L2_FIELD_NONE;
- buf->vb.width = chip->period_size;
buf->bpl = chip->period_size;
- buf->vb.height = chip->num_periods;
- buf->vb.size = chip->dma_size;
- dma = videobuf_to_dma(&buf->vb);
+ dma = &buf->dma;
videobuf_dma_init(dma);
-
ret = videobuf_dma_init_kernel(dma, PCI_DMA_FROMDEVICE,
- (PAGE_ALIGN(buf->vb.size) >>
+ (PAGE_ALIGN(chip->dma_size) >>
PAGE_SHIFT));
if (ret < 0)
goto error;
- ret = videobuf_sg_dma_map(&chip->pci->dev, dma);
+ ret = videobuf_dma_map(&chip->pci->dev, dma);
if (ret < 0)
goto error;
ret =
cx25821_risc_databuffer_audio(chip->pci, &buf->risc, dma->sglist,
- buf->vb.width, buf->vb.height, 1);
+ chip->period_size, chip->num_periods,
+ 1);
if (ret < 0) {
printk(KERN_INFO
"DEBUG: ERROR after cx25821_risc_databuffer_audio()\n");
@@ -488,12 +489,10 @@ static int snd_cx25821_hw_params(struct snd_pcm_substream *substream,
buf->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
buf->risc.jmp[2] = cpu_to_le32(0); /* bits 63-32 */
- buf->vb.state = VIDEOBUF_PREPARED;
-
chip->buf = buf;
chip->dma_risc = dma;
- substream->runtime->dma_area = chip->dma_risc->vmalloc;
+ substream->runtime->dma_area = chip->dma_risc->vaddr;
substream->runtime->dma_bytes = chip->dma_size;
substream->runtime->dma_addr = 0;
@@ -699,7 +698,7 @@ static int cx25821_audio_initdev(struct cx25821_dev *dev)
/* Card "creation" */
card->private_free = snd_cx25821_dev_free;
- chip = (struct cx25821_audio_dev *) card->private_data;
+ chip = card->private_data;
spin_lock_init(&chip->reg_lock);
chip->dev = dev;
diff --git a/drivers/staging/cx25821/cx25821-audio-upstream.c b/drivers/staging/cx25821/cx25821-audio-upstream.c
index eb39d13f7d7..cdff49f409f 100644
--- a/drivers/staging/cx25821/cx25821-audio-upstream.c
+++ b/drivers/staging/cx25821/cx25821-audio-upstream.c
@@ -106,7 +106,7 @@ static __le32 *cx25821_risc_field_upstream_audio(struct cx25821_dev *dev,
{
unsigned int line;
struct sram_channel *sram_ch =
- &dev->sram_channels[dev->_audio_upstream_channel_select];
+ dev->channels[dev->_audio_upstream_channel_select].sram_channels;
int offset = 0;
/* scan lines */
@@ -217,7 +217,7 @@ void cx25821_free_memory_audio(struct cx25821_dev *dev)
void cx25821_stop_upstream_audio(struct cx25821_dev *dev)
{
struct sram_channel *sram_ch =
- &dev->sram_channels[AUDIO_UPSTREAM_SRAM_CHANNEL_B];
+ dev->channels[AUDIO_UPSTREAM_SRAM_CHANNEL_B].sram_channels;
u32 tmp = 0;
if (!dev->_audio_is_running) {
@@ -287,14 +287,14 @@ int cx25821_get_audio_data(struct cx25821_dev *dev,
return PTR_ERR(myfile);
} else {
if (!(myfile->f_op)) {
- printk("%s: File has no file operations registered!\n",
+ printk(KERN_ERR "%s: File has no file operations registered!\n",
__func__);
filp_close(myfile, NULL);
return -EIO;
}
if (!myfile->f_op->read) {
- printk("%s: File has no READ operations registered!\n",
+ printk(KERN_ERR "%s: File has no READ operations registered!\n",
__func__);
filp_close(myfile, NULL);
return -EIO;
@@ -353,8 +353,9 @@ static void cx25821_audioups_handler(struct work_struct *work)
}
cx25821_get_audio_data(dev,
- &dev->sram_channels[dev->
- _audio_upstream_channel_select]);
+ dev->channels[dev->
+ _audio_upstream_channel_select].
+ sram_channels);
}
int cx25821_openfile_audio(struct cx25821_dev *dev,
@@ -378,14 +379,14 @@ int cx25821_openfile_audio(struct cx25821_dev *dev,
return PTR_ERR(myfile);
} else {
if (!(myfile->f_op)) {
- printk("%s: File has no file operations registered!\n",
+ printk(KERN_ERR "%s: File has no file operations registered!\n",
__func__);
filp_close(myfile, NULL);
return -EIO;
}
if (!myfile->f_op->read) {
- printk("%s: File has no READ operations registered!\n",
+ printk(KERN_ERR "%s: File has no READ operations registered!\n",
__func__);
filp_close(myfile, NULL);
return -EIO;
@@ -505,7 +506,7 @@ int cx25821_audio_upstream_irq(struct cx25821_dev *dev, int chan_num,
{
int i = 0;
u32 int_msk_tmp;
- struct sram_channel *channel = &dev->sram_channels[chan_num];
+ struct sram_channel *channel = dev->channels[chan_num].sram_channels;
dma_addr_t risc_phys_jump_addr;
__le32 *rp;
@@ -569,15 +570,15 @@ int cx25821_audio_upstream_irq(struct cx25821_dev *dev, int chan_num,
spin_unlock(&dev->slock);
} else {
if (status & FLD_AUD_SRC_OF)
- printk("%s: Audio Received Overflow Error Interrupt!\n",
+ printk(KERN_WARNING "%s: Audio Received Overflow Error Interrupt!\n",
__func__);
if (status & FLD_AUD_SRC_SYNC)
- printk("%s: Audio Received Sync Error Interrupt!\n",
+ printk(KERN_WARNING "%s: Audio Received Sync Error Interrupt!\n",
__func__);
if (status & FLD_AUD_SRC_OPC_ERR)
- printk("%s: Audio Received OpCode Error Interrupt!\n",
+ printk(KERN_WARNING "%s: Audio Received OpCode Error Interrupt!\n",
__func__);
/* Read and write back the interrupt status register to clear
@@ -586,7 +587,7 @@ int cx25821_audio_upstream_irq(struct cx25821_dev *dev, int chan_num,
}
if (dev->_audiofile_status == END_OF_FILE) {
- printk("cx25821: EOF Channel Audio Framecount = %d\n",
+ printk(KERN_WARNING "cx25821: EOF Channel Audio Framecount = %d\n",
dev->_audioframe_count);
return -1;
}
@@ -607,7 +608,8 @@ static irqreturn_t cx25821_upstream_irq_audio(int irq, void *dev_id)
if (!dev)
return -1;
- sram_ch = &dev->sram_channels[dev->_audio_upstream_channel_select];
+ sram_ch = dev->channels[dev->_audio_upstream_channel_select].
+ sram_channels;
msk_stat = cx_read(sram_ch->int_mstat);
audio_status = cx_read(sram_ch->int_stat);
@@ -644,8 +646,8 @@ static void cx25821_wait_fifo_enable(struct cx25821_dev *dev,
/* 10 millisecond timeout */
if (count++ > 1000) {
- printk
- ("cx25821 ERROR: %s() fifo is NOT turned on. Timeout!\n",
+ printk(KERN_ERR
+ "cx25821 ERROR: %s() fifo is NOT turned on. Timeout!\n",
__func__);
return;
}
@@ -726,12 +728,12 @@ int cx25821_audio_upstream_init(struct cx25821_dev *dev, int channel_select)
int str_length = 0;
if (dev->_audio_is_running) {
- printk("Audio Channel is still running so return!\n");
+ printk(KERN_WARNING "Audio Channel is still running so return!\n");
return 0;
}
dev->_audio_upstream_channel_select = channel_select;
- sram_ch = &dev->sram_channels[channel_select];
+ sram_ch = dev->channels[channel_select].sram_channels;
/* Work queue */
INIT_WORK(&dev->_audio_work_entry, cx25821_audioups_handler);
diff --git a/drivers/staging/cx25821/cx25821-audio.h b/drivers/staging/cx25821/cx25821-audio.h
index 503f42f036a..434b2a312a8 100644
--- a/drivers/staging/cx25821/cx25821-audio.h
+++ b/drivers/staging/cx25821/cx25821-audio.h
@@ -27,24 +27,25 @@
#define LINES_PER_BUFFER 15
#define AUDIO_LINE_SIZE 128
-//Number of buffer programs to use at once.
+/* Number of buffer programs to use at once. */
#define NUMBER_OF_PROGRAMS 8
-//Max size of the RISC program for a buffer. - worst case is 2 writes per line
-// Space is also added for the 4 no-op instructions added on the end.
-
+/*
+ Max size of the RISC program for a buffer. - worst case is 2 writes per line
+ Space is also added for the 4 no-op instructions added on the end.
+*/
#ifndef USE_RISC_NOOP
#define MAX_BUFFER_PROGRAM_SIZE \
(2*LINES_PER_BUFFER*RISC_WRITE_INSTRUCTION_SIZE + RISC_WRITECR_INSTRUCTION_SIZE*4)
#endif
-// MAE 12 July 2005 Try to use NOOP RISC instruction instead
+/* MAE 12 July 2005 Try to use NOOP RISC instruction instead */
#ifdef USE_RISC_NOOP
#define MAX_BUFFER_PROGRAM_SIZE \
(2*LINES_PER_BUFFER*RISC_WRITE_INSTRUCTION_SIZE + RISC_NOOP_INSTRUCTION_SIZE*4)
#endif
-//Sizes of various instructions in bytes. Used when adding instructions.
+/* Sizes of various instructions in bytes. Used when adding instructions. */
#define RISC_WRITE_INSTRUCTION_SIZE 12
#define RISC_JUMP_INSTRUCTION_SIZE 12
#define RISC_SKIP_INSTRUCTION_SIZE 4
diff --git a/drivers/staging/cx25821/cx25821-audups11.c b/drivers/staging/cx25821/cx25821-audups11.c
deleted file mode 100644
index e49ead982f3..00000000000
--- a/drivers/staging/cx25821/cx25821-audups11.c
+++ /dev/null
@@ -1,420 +0,0 @@
-/*
- * Driver for the Conexant CX25821 PCIe bridge
- *
- * Copyright (C) 2009 Conexant Systems Inc.
- * Authors <shu.lin@conexant.com>, <hiep.huynh@conexant.com>
- * Based on Steven Toth <stoth@linuxtv.org> cx23885 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 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 "cx25821-video.h"
-
-static void buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
-{
- struct cx25821_buffer *buf =
- container_of(vb, struct cx25821_buffer, vb);
- struct cx25821_buffer *prev;
- struct cx25821_fh *fh = vq->priv_data;
- struct cx25821_dev *dev = fh->dev;
- struct cx25821_dmaqueue *q = &dev->vidq[SRAM_CH11];
-
- /* add jump to stopper */
- buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC);
- buf->risc.jmp[1] = cpu_to_le32(q->stopper.dma);
- buf->risc.jmp[2] = cpu_to_le32(0); /* bits 63-32 */
-
- dprintk(2, "jmp to stopper (0x%x)\n", buf->risc.jmp[1]);
-
- if (!list_empty(&q->queued)) {
- list_add_tail(&buf->vb.queue, &q->queued);
- buf->vb.state = VIDEOBUF_QUEUED;
- dprintk(2, "[%p/%d] buffer_queue - append to queued\n", buf,
- buf->vb.i);
-
- } else if (list_empty(&q->active)) {
- list_add_tail(&buf->vb.queue, &q->active);
- cx25821_start_video_dma(dev, q, buf,
- &dev->sram_channels[SRAM_CH11]);
- buf->vb.state = VIDEOBUF_ACTIVE;
- buf->count = q->count++;
- mod_timer(&q->timeout, jiffies + BUFFER_TIMEOUT);
- dprintk(2,
- "[%p/%d] buffer_queue - first active, buf cnt = %d, q->count = %d\n",
- buf, buf->vb.i, buf->count, q->count);
- } else {
- prev =
- list_entry(q->active.prev, struct cx25821_buffer, vb.queue);
- if (prev->vb.width == buf->vb.width
- && prev->vb.height == buf->vb.height
- && prev->fmt == buf->fmt) {
- list_add_tail(&buf->vb.queue, &q->active);
- buf->vb.state = VIDEOBUF_ACTIVE;
- buf->count = q->count++;
- prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
-
- /* 64 bit bits 63-32 */
- prev->risc.jmp[2] = cpu_to_le32(0);
- dprintk(2,
- "[%p/%d] buffer_queue - append to active, buf->count=%d\n",
- buf, buf->vb.i, buf->count);
-
- } else {
- list_add_tail(&buf->vb.queue, &q->queued);
- buf->vb.state = VIDEOBUF_QUEUED;
- dprintk(2, "[%p/%d] buffer_queue - first queued\n", buf,
- buf->vb.i);
- }
- }
-
- if (list_empty(&q->active)) {
- dprintk(2, "active queue empty!\n");
- }
-}
-
-static struct videobuf_queue_ops cx25821_video_qops = {
- .buf_setup = cx25821_buffer_setup,
- .buf_prepare = cx25821_buffer_prepare,
- .buf_queue = buffer_queue,
- .buf_release = cx25821_buffer_release,
-};
-
-static int video_open(struct file *file)
-{
- struct video_device *vdev = video_devdata(file);
- struct cx25821_dev *dev = video_drvdata(file);
- struct cx25821_fh *fh;
- enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-
- printk("open dev=%s type=%s\n", video_device_node_name(vdev),
- v4l2_type_names[type]);
-
- /* allocate + initialize per filehandle data */
- fh = kzalloc(sizeof(*fh), GFP_KERNEL);
- if (NULL == fh)
- return -ENOMEM;
-
- lock_kernel();
-
- file->private_data = fh;
- fh->dev = dev;
- fh->type = type;
- fh->width = 720;
-
- if (dev->tvnorm & V4L2_STD_PAL_BG || dev->tvnorm & V4L2_STD_PAL_DK)
- fh->height = 576;
- else
- fh->height = 480;
-
- dev->channel_opened = 10;
- fh->fmt = format_by_fourcc(V4L2_PIX_FMT_YUYV);
-
- v4l2_prio_open(&dev->prio, &fh->prio);
-
- videobuf_queue_sg_init(&fh->vidq, &cx25821_video_qops,
- &dev->pci->dev, &dev->slock,
- V4L2_BUF_TYPE_VIDEO_CAPTURE,
- V4L2_FIELD_INTERLACED,
- sizeof(struct cx25821_buffer), fh);
-
- dprintk(1, "post videobuf_queue_init()\n");
- unlock_kernel();
-
- return 0;
-}
-
-static ssize_t video_read(struct file *file, char __user * data, size_t count,
- loff_t * ppos)
-{
- struct cx25821_fh *fh = file->private_data;
-
- switch (fh->type) {
- case V4L2_BUF_TYPE_VIDEO_CAPTURE:
- if (cx25821_res_locked(fh->dev, RESOURCE_VIDEO11))
- return -EBUSY;
-
- return videobuf_read_one(&fh->vidq, data, count, ppos,
- file->f_flags & O_NONBLOCK);
-
- default:
- BUG();
- return 0;
- }
-}
-
-static unsigned int video_poll(struct file *file,
- struct poll_table_struct *wait)
-{
- struct cx25821_fh *fh = file->private_data;
- struct cx25821_buffer *buf;
-
- if (cx25821_res_check(fh, RESOURCE_VIDEO11)) {
- /* streaming capture */
- if (list_empty(&fh->vidq.stream))
- return POLLERR;
- buf = list_entry(fh->vidq.stream.next,
- struct cx25821_buffer, vb.stream);
- } else {
- /* read() capture */
- buf = (struct cx25821_buffer *)fh->vidq.read_buf;
- if (NULL == buf)
- return POLLERR;
- }
-
- poll_wait(file, &buf->vb.done, wait);
- if (buf->vb.state == VIDEOBUF_DONE || buf->vb.state == VIDEOBUF_ERROR)
- return POLLIN | POLLRDNORM;
- return 0;
-}
-
-static int video_release(struct file *file)
-{
- struct cx25821_fh *fh = file->private_data;
- struct cx25821_dev *dev = fh->dev;
-
- //stop the risc engine and fifo
- //cx_write(channel11->dma_ctl, 0);
-
- /* stop video capture */
- if (cx25821_res_check(fh, RESOURCE_VIDEO11)) {
- videobuf_queue_cancel(&fh->vidq);
- cx25821_res_free(dev, fh, RESOURCE_VIDEO11);
- }
-
- if (fh->vidq.read_buf) {
- cx25821_buffer_release(&fh->vidq, fh->vidq.read_buf);
- kfree(fh->vidq.read_buf);
- }
-
- videobuf_mmap_free(&fh->vidq);
-
- v4l2_prio_close(&dev->prio, fh->prio);
-
- file->private_data = NULL;
- kfree(fh);
-
- return 0;
-}
-
-static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
-{
- struct cx25821_fh *fh = priv;
- struct cx25821_dev *dev = fh->dev;
-
- if (unlikely(fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)) {
- return -EINVAL;
- }
-
- if (unlikely(i != fh->type)) {
- return -EINVAL;
- }
-
- if (unlikely(!cx25821_res_get(dev, fh, cx25821_get_resource(fh, RESOURCE_VIDEO11)))) {
- return -EBUSY;
- }
-
- return videobuf_streamon(get_queue(fh));
-}
-
-static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
-{
- struct cx25821_fh *fh = priv;
- struct cx25821_dev *dev = fh->dev;
- int err, res;
-
- if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
- if (i != fh->type)
- return -EINVAL;
-
- res = cx25821_get_resource(fh, RESOURCE_VIDEO11);
- err = videobuf_streamoff(get_queue(fh));
- if (err < 0)
- return err;
- cx25821_res_free(dev, fh, res);
- return 0;
-}
-
-static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
- struct v4l2_format *f)
-{
- struct cx25821_fh *fh = priv;
- struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
- int err;
-
- if (fh) {
- err = v4l2_prio_check(&dev->prio, fh->prio);
- if (0 != err)
- return err;
- }
-
- dprintk(2, "%s()\n", __func__);
- err = cx25821_vidioc_try_fmt_vid_cap(file, priv, f);
-
- if (0 != err)
- return err;
- fh->fmt = format_by_fourcc(f->fmt.pix.pixelformat);
- fh->width = f->fmt.pix.width;
- fh->height = f->fmt.pix.height;
- fh->vidq.field = f->fmt.pix.field;
- dprintk(2, "%s() width=%d height=%d field=%d\n", __func__, fh->width,
- fh->height, fh->vidq.field);
- cx25821_call_all(dev, video, s_fmt, f);
- return 0;
-}
-
-static long video_ioctl_upstream11(struct file *file, unsigned int cmd,
- unsigned long arg)
-{
- struct cx25821_fh *fh = file->private_data;
- struct cx25821_dev *dev = fh->dev;
- int command = 0;
- struct upstream_user_struct *data_from_user;
-
- data_from_user = (struct upstream_user_struct *)arg;
-
- if (!data_from_user) {
- printk
- ("cx25821 in %s(): Upstream data is INVALID. Returning.\n",
- __func__);
- return 0;
- }
-
- command = data_from_user->command;
-
- if (command != UPSTREAM_START_AUDIO && command != UPSTREAM_STOP_AUDIO) {
- return 0;
- }
-
- dev->input_filename = data_from_user->input_filename;
- dev->input_audiofilename = data_from_user->input_filename;
- dev->vid_stdname = data_from_user->vid_stdname;
- dev->pixel_format = data_from_user->pixel_format;
- dev->channel_select = data_from_user->channel_select;
- dev->command = data_from_user->command;
-
- switch (command) {
- case UPSTREAM_START_AUDIO:
- cx25821_start_upstream_audio(dev, data_from_user);
- break;
-
- case UPSTREAM_STOP_AUDIO:
- cx25821_stop_upstream_audio(dev);
- break;
- }
-
- return 0;
-}
-
-static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p)
-{
- struct cx25821_fh *fh = priv;
- return videobuf_dqbuf(get_queue(fh), p, file->f_flags & O_NONBLOCK);
-}
-
-static int vidioc_log_status(struct file *file, void *priv)
-{
- struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
- char name[32 + 2];
-
- snprintf(name, sizeof(name), "%s/2", dev->name);
- printk(KERN_INFO "%s/2: ============ START LOG STATUS ============\n",
- dev->name);
- cx25821_call_all(dev, core, log_status);
- printk(KERN_INFO "%s/2: ============= END LOG STATUS =============\n",
- dev->name);
- return 0;
-}
-
-static int vidioc_s_ctrl(struct file *file, void *priv,
- struct v4l2_control *ctl)
-{
- struct cx25821_fh *fh = priv;
- struct cx25821_dev *dev;
- int err;
-
- if (fh) {
- dev = fh->dev;
- err = v4l2_prio_check(&dev->prio, fh->prio);
- if (0 != err)
- return err;
- }
- return 0;
-}
-
-// exported stuff
-static const struct v4l2_file_operations video_fops = {
- .owner = THIS_MODULE,
- .open = video_open,
- .release = video_release,
- .read = video_read,
- .poll = video_poll,
- .mmap = cx25821_video_mmap,
- .ioctl = video_ioctl_upstream11,
-};
-
-static const struct v4l2_ioctl_ops video_ioctl_ops = {
- .vidioc_querycap = cx25821_vidioc_querycap,
- .vidioc_enum_fmt_vid_cap = cx25821_vidioc_enum_fmt_vid_cap,
- .vidioc_g_fmt_vid_cap = cx25821_vidioc_g_fmt_vid_cap,
- .vidioc_try_fmt_vid_cap = cx25821_vidioc_try_fmt_vid_cap,
- .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
- .vidioc_reqbufs = cx25821_vidioc_reqbufs,
- .vidioc_querybuf = cx25821_vidioc_querybuf,
- .vidioc_qbuf = cx25821_vidioc_qbuf,
- .vidioc_dqbuf = vidioc_dqbuf,
-#ifdef TUNER_FLAG
- .vidioc_s_std = cx25821_vidioc_s_std,
- .vidioc_querystd = cx25821_vidioc_querystd,
-#endif
- .vidioc_cropcap = cx25821_vidioc_cropcap,
- .vidioc_s_crop = cx25821_vidioc_s_crop,
- .vidioc_g_crop = cx25821_vidioc_g_crop,
- .vidioc_enum_input = cx25821_vidioc_enum_input,
- .vidioc_g_input = cx25821_vidioc_g_input,
- .vidioc_s_input = cx25821_vidioc_s_input,
- .vidioc_g_ctrl = cx25821_vidioc_g_ctrl,
- .vidioc_s_ctrl = vidioc_s_ctrl,
- .vidioc_queryctrl = cx25821_vidioc_queryctrl,
- .vidioc_streamon = vidioc_streamon,
- .vidioc_streamoff = vidioc_streamoff,
- .vidioc_log_status = vidioc_log_status,
- .vidioc_g_priority = cx25821_vidioc_g_priority,
- .vidioc_s_priority = cx25821_vidioc_s_priority,
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
- .vidiocgmbuf = cx25821_vidiocgmbuf,
-#endif
-#ifdef TUNER_FLAG
- .vidioc_g_tuner = cx25821_vidioc_g_tuner,
- .vidioc_s_tuner = cx25821_vidioc_s_tuner,
- .vidioc_g_frequency = cx25821_vidioc_g_frequency,
- .vidioc_s_frequency = cx25821_vidioc_s_frequency,
-#endif
-#ifdef CONFIG_VIDEO_ADV_DEBUG
- .vidioc_g_register = cx25821_vidioc_g_register,
- .vidioc_s_register = cx25821_vidioc_s_register,
-#endif
-};
-
-struct video_device cx25821_video_template11 = {
- .name = "cx25821-audioupstream",
- .fops = &video_fops,
- .ioctl_ops = &video_ioctl_ops,
- .tvnorms = CX25821_NORMS,
- .current_norm = V4L2_STD_NTSC_M,
-};
diff --git a/drivers/staging/cx25821/cx25821-core.c b/drivers/staging/cx25821/cx25821-core.c
index d90abb383fc..c487c19256b 100644
--- a/drivers/staging/cx25821/cx25821-core.c
+++ b/drivers/staging/cx25821/cx25821-core.c
@@ -781,14 +781,14 @@ static void cx25821_shutdown(struct cx25821_dev *dev)
/* Disable Video A/B activity */
for (i = 0; i < VID_CHANNEL_NUM; i++) {
- cx_write(dev->sram_channels[i].dma_ctl, 0);
- cx_write(dev->sram_channels[i].int_msk, 0);
+ cx_write(dev->channels[i].sram_channels->dma_ctl, 0);
+ cx_write(dev->channels[i].sram_channels->int_msk, 0);
}
for (i = VID_UPSTREAM_SRAM_CHANNEL_I; i <= VID_UPSTREAM_SRAM_CHANNEL_J;
i++) {
- cx_write(dev->sram_channels[i].dma_ctl, 0);
- cx_write(dev->sram_channels[i].int_msk, 0);
+ cx_write(dev->channels[i].sram_channels->dma_ctl, 0);
+ cx_write(dev->channels[i].sram_channels->int_msk, 0);
}
/* Disable Audio activity */
@@ -805,12 +805,10 @@ static void cx25821_shutdown(struct cx25821_dev *dev)
void cx25821_set_pixel_format(struct cx25821_dev *dev, int channel_select,
u32 format)
{
- struct sram_channel *ch;
-
if (channel_select <= 7 && channel_select >= 0) {
- ch = &cx25821_sram_channels[channel_select];
- cx_write(ch->pix_frmt, format);
- dev->pixel_formats[channel_select] = format;
+ cx_write(dev->channels[channel_select].
+ sram_channels->pix_frmt, format);
+ dev->channels[channel_select].pixel_formats = format;
}
}
@@ -831,7 +829,7 @@ static void cx25821_initialize(struct cx25821_dev *dev)
cx_write(PCI_INT_STAT, 0xffffffff);
for (i = 0; i < VID_CHANNEL_NUM; i++)
- cx_write(dev->sram_channels[i].int_stat, 0xffffffff);
+ cx_write(dev->channels[i].sram_channels->int_stat, 0xffffffff);
cx_write(AUD_A_INT_STAT, 0xffffffff);
cx_write(AUD_B_INT_STAT, 0xffffffff);
@@ -845,21 +843,22 @@ static void cx25821_initialize(struct cx25821_dev *dev)
mdelay(100);
for (i = 0; i < VID_CHANNEL_NUM; i++) {
- cx25821_set_vip_mode(dev, &dev->sram_channels[i]);
- cx25821_sram_channel_setup(dev, &dev->sram_channels[i], 1440,
- 0);
- dev->pixel_formats[i] = PIXEL_FRMT_422;
- dev->use_cif_resolution[i] = FALSE;
+ cx25821_set_vip_mode(dev, dev->channels[i].sram_channels);
+ cx25821_sram_channel_setup(dev, dev->channels[i].sram_channels,
+ 1440, 0);
+ dev->channels[i].pixel_formats = PIXEL_FRMT_422;
+ dev->channels[i].use_cif_resolution = FALSE;
}
/* Probably only affect Downstream */
for (i = VID_UPSTREAM_SRAM_CHANNEL_I; i <= VID_UPSTREAM_SRAM_CHANNEL_J;
i++) {
- cx25821_set_vip_mode(dev, &dev->sram_channels[i]);
+ cx25821_set_vip_mode(dev, dev->channels[i].sram_channels);
}
- cx25821_sram_channel_setup_audio(dev, &dev->sram_channels[SRAM_CH08],
- 128, 0);
+ cx25821_sram_channel_setup_audio(dev,
+ dev->channels[SRAM_CH08].sram_channels,
+ 128, 0);
cx25821_gpio_init(dev);
}
@@ -902,21 +901,6 @@ static int cx25821_dev_setup(struct cx25821_dev *dev)
{
int io_size = 0, i;
- struct video_device *video_template[] = {
- &cx25821_video_template0,
- &cx25821_video_template1,
- &cx25821_video_template2,
- &cx25821_video_template3,
- &cx25821_video_template4,
- &cx25821_video_template5,
- &cx25821_video_template6,
- &cx25821_video_template7,
- &cx25821_video_template9,
- &cx25821_video_template10,
- &cx25821_video_template11,
- &cx25821_videoioctl_template,
- };
-
printk(KERN_INFO "\n***********************************\n");
printk(KERN_INFO "cx25821 set up\n");
printk(KERN_INFO "***********************************\n\n");
@@ -947,7 +931,8 @@ static int cx25821_dev_setup(struct cx25821_dev *dev)
/* Apply a sensible clock frequency for the PCIe bridge */
dev->clk_freq = 28000000;
- dev->sram_channels = cx25821_sram_channels;
+ for (i = 0; i < MAX_VID_CHANNEL_NUM; i++)
+ dev->channels[i].sram_channels = &cx25821_sram_channels[i];
if (dev->nr > 1)
CX25821_INFO("dev->nr > 1!");
@@ -970,7 +955,6 @@ static int cx25821_dev_setup(struct cx25821_dev *dev)
dev->i2c_bus[0].reg_wdata = I2C1_WDATA;
dev->i2c_bus[0].i2c_period = (0x07 << 24); /* 1.95MHz */
-
if (cx25821_get_resources(dev) < 0) {
printk(KERN_ERR "%s No more PCIe resources for "
"subsystem: %04x:%04x\n",
@@ -1018,37 +1002,24 @@ static int cx25821_dev_setup(struct cx25821_dev *dev)
dev->i2c_bus[0].i2c_rc);
cx25821_card_setup(dev);
- medusa_video_init(dev);
- for (i = 0; i < VID_CHANNEL_NUM; i++) {
- if (cx25821_video_register(dev, i, video_template[i]) < 0) {
- printk(KERN_ERR
- "%s() Failed to register analog video adapters on VID channel %d\n",
- __func__, i);
- }
- }
+ if (medusa_video_init(dev) < 0)
+ CX25821_ERR("%s() Failed to initialize medusa!\n"
+ , __func__);
- for (i = VID_UPSTREAM_SRAM_CHANNEL_I;
- i <= AUDIO_UPSTREAM_SRAM_CHANNEL_B; i++) {
- /* Since we don't have template8 for Audio Downstream */
- if (cx25821_video_register(dev, i, video_template[i - 1]) < 0) {
- printk(KERN_ERR
- "%s() Failed to register analog video adapters for Upstream channel %d.\n",
- __func__, i);
- }
- }
+ cx25821_video_register(dev);
/* register IOCTL device */
dev->ioctl_dev =
- cx25821_vdev_init(dev, dev->pci, video_template[VIDEO_IOCTL_CH],
+ cx25821_vdev_init(dev, dev->pci, &cx25821_videoioctl_template,
"video");
if (video_register_device
(dev->ioctl_dev, VFL_TYPE_GRABBER, VIDEO_IOCTL_CH) < 0) {
cx25821_videoioctl_unregister(dev);
printk(KERN_ERR
- "%s() Failed to register video adapter for IOCTL so releasing.\n",
- __func__);
+ "%s() Failed to register video adapter for IOCTL, so \
+ unregistering videoioctl device.\n", __func__);
}
cx25821_dev_checkrevision(dev);
@@ -1349,7 +1320,7 @@ void cx25821_free_buffer(struct videobuf_queue *q, struct cx25821_buffer *buf)
BUG_ON(in_interrupt());
videobuf_waiton(&buf->vb, 0, 0);
- videobuf_dma_unmap(q, dma);
+ videobuf_dma_unmap(q->dev, dma);
videobuf_dma_free(dma);
btcx_riscmem_free(to_pci_dev(q->dev), &buf->risc);
buf->vb.state = VIDEOBUF_NEEDS_INIT;
@@ -1371,7 +1342,8 @@ static irqreturn_t cx25821_irq(int irq, void *dev_id)
for (i = 0; i < VID_CHANNEL_NUM; i++) {
if (pci_status & mask[i]) {
- vid_status = cx_read(dev->sram_channels[i].int_stat);
+ vid_status = cx_read(dev->channels[i].
+ sram_channels->int_stat);
if (vid_status)
handled +=
diff --git a/drivers/staging/cx25821/cx25821-i2c.c b/drivers/staging/cx25821/cx25821-i2c.c
index 08f45b52df6..e43572e61ec 100644
--- a/drivers/staging/cx25821/cx25821-i2c.c
+++ b/drivers/staging/cx25821/cx25821-i2c.c
@@ -282,6 +282,9 @@ static u32 cx25821_functionality(struct i2c_adapter *adap)
static struct i2c_algorithm cx25821_i2c_algo_template = {
.master_xfer = i2c_xfer,
.functionality = cx25821_functionality,
+#ifdef NEED_ALGO_CONTROL
+ .algo_control = dummy_algo_control,
+#endif
};
static struct i2c_adapter cx25821_i2c_adap_template = {
diff --git a/drivers/staging/cx25821/cx25821-medusa-defines.h b/drivers/staging/cx25821/cx25821-medusa-defines.h
index b0d216ba7f8..60d197f5755 100644
--- a/drivers/staging/cx25821/cx25821-medusa-defines.h
+++ b/drivers/staging/cx25821/cx25821-medusa-defines.h
@@ -23,7 +23,7 @@
#ifndef _MEDUSA_DEF_H_
#define _MEDUSA_DEF_H_
-// Video deocder that we supported
+/* Video deocder that we supported */
#define VDEC_A 0
#define VDEC_B 1
#define VDEC_C 2
@@ -33,19 +33,10 @@
#define VDEC_G 6
#define VDEC_H 7
-//#define AUTO_SWITCH_BIT[] = { 8, 9, 10, 11, 12, 13, 14, 15 };
-
-// The following bit position enables automatic source switching for decoder A-H.
-// Display index per camera.
-//#define VDEC_INDEX[] = {0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7};
-
-// Select input bit to video decoder A-H.
-//#define CH_SRC_SEL_BIT[] = {24, 25, 26, 27, 28, 29, 30, 31};
-
-// end of display sequence
+/* end of display sequence */
#define END_OF_SEQ 0xF;
-// registry string size
+/* registry string size */
#define MAX_REGISTRY_SZ 40;
#endif
diff --git a/drivers/staging/cx25821/cx25821-medusa-reg.h b/drivers/staging/cx25821/cx25821-medusa-reg.h
index 12c90f831b2..f7f33b3e705 100644
--- a/drivers/staging/cx25821/cx25821-medusa-reg.h
+++ b/drivers/staging/cx25821/cx25821-medusa-reg.h
@@ -23,11 +23,11 @@
#ifndef __MEDUSA_REGISTERS__
#define __MEDUSA_REGISTERS__
-// Serial Slave Registers
+/* Serial Slave Registers */
#define HOST_REGISTER1 0x0000
#define HOST_REGISTER2 0x0001
-// Chip Configuration Registers
+/* Chip Configuration Registers */
#define CHIP_CTRL 0x0100
#define AFE_AB_CTRL 0x0104
#define AFE_CD_CTRL 0x0108
@@ -92,7 +92,7 @@
#define ABIST_CLAMP_E 0x01F4
#define ABIST_CLAMP_F 0x01F8
-// Digital Video Encoder A Registers
+/* Digital Video Encoder A Registers */
#define DENC_A_REG_1 0x0200
#define DENC_A_REG_2 0x0204
#define DENC_A_REG_3 0x0208
@@ -102,7 +102,7 @@
#define DENC_A_REG_7 0x0218
#define DENC_A_REG_8 0x021C
-// Digital Video Encoder B Registers
+/* Digital Video Encoder B Registers */
#define DENC_B_REG_1 0x0300
#define DENC_B_REG_2 0x0304
#define DENC_B_REG_3 0x0308
@@ -112,7 +112,7 @@
#define DENC_B_REG_7 0x0318
#define DENC_B_REG_8 0x031C
-// Video Decoder A Registers
+/* Video Decoder A Registers */
#define MODE_CTRL 0x1000
#define OUT_CTRL1 0x1004
#define OUT_CTRL_NS 0x1008
@@ -153,7 +153,7 @@
#define VERSION 0x11F8
#define SOFT_RST_CTRL 0x11FC
-// Video Decoder B Registers
+/* Video Decoder B Registers */
#define VDEC_B_MODE_CTRL 0x1200
#define VDEC_B_OUT_CTRL1 0x1204
#define VDEC_B_OUT_CTRL_NS 0x1208
@@ -194,7 +194,7 @@
#define VDEC_B_VERSION 0x13F8
#define VDEC_B_SOFT_RST_CTRL 0x13FC
-// Video Decoder C Registers
+/* Video Decoder C Registers */
#define VDEC_C_MODE_CTRL 0x1400
#define VDEC_C_OUT_CTRL1 0x1404
#define VDEC_C_OUT_CTRL_NS 0x1408
@@ -235,7 +235,7 @@
#define VDEC_C_VERSION 0x15F8
#define VDEC_C_SOFT_RST_CTRL 0x15FC
-// Video Decoder D Registers
+/* Video Decoder D Registers */
#define VDEC_D_MODE_CTRL 0x1600
#define VDEC_D_OUT_CTRL1 0x1604
#define VDEC_D_OUT_CTRL_NS 0x1608
@@ -276,7 +276,7 @@
#define VDEC_D_VERSION 0x17F8
#define VDEC_D_SOFT_RST_CTRL 0x17FC
-// Video Decoder E Registers
+/* Video Decoder E Registers */
#define VDEC_E_MODE_CTRL 0x1800
#define VDEC_E_OUT_CTRL1 0x1804
#define VDEC_E_OUT_CTRL_NS 0x1808
@@ -317,7 +317,7 @@
#define VDEC_E_VERSION 0x19F8
#define VDEC_E_SOFT_RST_CTRL 0x19FC
-// Video Decoder F Registers
+/* Video Decoder F Registers */
#define VDEC_F_MODE_CTRL 0x1A00
#define VDEC_F_OUT_CTRL1 0x1A04
#define VDEC_F_OUT_CTRL_NS 0x1A08
@@ -358,7 +358,7 @@
#define VDEC_F_VERSION 0x1BF8
#define VDEC_F_SOFT_RST_CTRL 0x1BFC
-// Video Decoder G Registers
+/* Video Decoder G Registers */
#define VDEC_G_MODE_CTRL 0x1C00
#define VDEC_G_OUT_CTRL1 0x1C04
#define VDEC_G_OUT_CTRL_NS 0x1C08
@@ -399,7 +399,7 @@
#define VDEC_G_VERSION 0x1DF8
#define VDEC_G_SOFT_RST_CTRL 0x1DFC
-// Video Decoder H Registers
+/* Video Decoder H Registers */
#define VDEC_H_MODE_CTRL 0x1E00
#define VDEC_H_OUT_CTRL1 0x1E04
#define VDEC_H_OUT_CTRL_NS 0x1E08
@@ -440,14 +440,14 @@
#define VDEC_H_VERSION 0x1FF8
#define VDEC_H_SOFT_RST_CTRL 0x1FFC
-//*****************************************************************************
-// LUMA_CTRL register fields
+/*****************************************************************************/
+/* LUMA_CTRL register fields */
#define VDEC_A_BRITE_CTRL 0x1014
#define VDEC_A_CNTRST_CTRL 0x1015
#define VDEC_A_PEAK_SEL 0x1016
-//*****************************************************************************
-// CHROMA_CTRL register fields
+/*****************************************************************************/
+/* CHROMA_CTRL register fields */
#define VDEC_A_USAT_CTRL 0x1018
#define VDEC_A_VSAT_CTRL 0x1019
#define VDEC_A_HUE_CTRL 0x101A
diff --git a/drivers/staging/cx25821/cx25821-medusa-video.c b/drivers/staging/cx25821/cx25821-medusa-video.c
index 34616dc507f..ef9f2b82a86 100644
--- a/drivers/staging/cx25821/cx25821-medusa-video.c
+++ b/drivers/staging/cx25821/cx25821-medusa-video.c
@@ -778,9 +778,9 @@ int medusa_set_saturation(struct cx25821_dev *dev, int saturation, int decoder)
int medusa_video_init(struct cx25821_dev *dev)
{
- u32 value, tmp = 0;
- int ret_val;
- int i;
+ u32 value = 0, tmp = 0;
+ int ret_val = 0;
+ int i = 0;
mutex_lock(&dev->lock);
@@ -790,6 +790,7 @@ int medusa_video_init(struct cx25821_dev *dev)
value = cx25821_i2c_read(&dev->i2c_bus[0], MON_A_CTRL, &tmp);
value &= 0xFFFFF0FF;
ret_val = cx25821_i2c_write(&dev->i2c_bus[0], MON_A_CTRL, value);
+
if (ret_val < 0)
goto error;
@@ -797,6 +798,7 @@ int medusa_video_init(struct cx25821_dev *dev)
value = cx25821_i2c_read(&dev->i2c_bus[0], MON_A_CTRL, &tmp);
value &= 0xFFFFFFDF;
ret_val = cx25821_i2c_write(&dev->i2c_bus[0], MON_A_CTRL, value);
+
if (ret_val < 0)
goto error;
@@ -812,6 +814,7 @@ int medusa_video_init(struct cx25821_dev *dev)
value &= 0xFF70FF70;
value |= 0x00090008; /* set en_active */
ret_val = cx25821_i2c_write(&dev->i2c_bus[0], DENC_AB_CTRL, value);
+
if (ret_val < 0)
goto error;
@@ -826,8 +829,10 @@ int medusa_video_init(struct cx25821_dev *dev)
/* select AFE clock to output mode */
value = cx25821_i2c_read(&dev->i2c_bus[0], AFE_AB_DIAG_CTRL, &tmp);
value &= 0x83FFFFFF;
- ret_val = cx25821_i2c_write(&dev->i2c_bus[0], AFE_AB_DIAG_CTRL,
- value | 0x10000000);
+ ret_val =
+ cx25821_i2c_write(&dev->i2c_bus[0], AFE_AB_DIAG_CTRL,
+ value | 0x10000000);
+
if (ret_val < 0)
goto error;
@@ -849,12 +854,15 @@ int medusa_video_init(struct cx25821_dev *dev)
value |= 7;
ret_val = cx25821_i2c_write(&dev->i2c_bus[0], PIN_OE_CTRL, value);
+
if (ret_val < 0)
goto error;
+
mutex_unlock(&dev->lock);
ret_val = medusa_set_videostandard(dev);
+
return ret_val;
error:
diff --git a/drivers/staging/cx25821/cx25821-medusa-video.h b/drivers/staging/cx25821/cx25821-medusa-video.h
index 2fab4b2f251..6175e096185 100644
--- a/drivers/staging/cx25821/cx25821-medusa-video.h
+++ b/drivers/staging/cx25821/cx25821-medusa-video.h
@@ -25,7 +25,7 @@
#include "cx25821-medusa-defines.h"
-// Color control constants
+/* Color control constants */
#define VIDEO_PROCAMP_MIN 0
#define VIDEO_PROCAMP_MAX 10000
#define UNSIGNED_BYTE_MIN 0
@@ -33,7 +33,7 @@
#define SIGNED_BYTE_MIN -128
#define SIGNED_BYTE_MAX 127
-// Default video color settings
+/* Default video color settings */
#define SHARPNESS_DEFAULT 50
#define SATURATION_DEFAULT 5000
#define BRIGHTNESS_DEFAULT 6200
diff --git a/drivers/staging/cx25821/cx25821-reg.h b/drivers/staging/cx25821/cx25821-reg.h
index 7241e7ee3fd..cfe0f32db37 100644
--- a/drivers/staging/cx25821/cx25821-reg.h
+++ b/drivers/staging/cx25821/cx25821-reg.h
@@ -48,24 +48,24 @@
#define RISC_SYNC_EVEN_VBI 0x00000207
#define RISC_NOOP 0xF0000000
-//*****************************************************************************
-// ASB SRAM
-//*****************************************************************************
-#define TX_SRAM 0x000000 // Transmit SRAM
-
-//*****************************************************************************
-#define RX_RAM 0x010000 // Receive SRAM
-
-//*****************************************************************************
-// Application Layer (AL)
-//*****************************************************************************
-#define DEV_CNTRL2 0x040000 // Device control
+/*****************************************************************************
+* ASB SRAM
+ *****************************************************************************/
+#define TX_SRAM 0x000000 /* Transmit SRAM */
+
+/*****************************************************************************/
+#define RX_RAM 0x010000 /* Receive SRAM */
+
+/*****************************************************************************
+* Application Layer (AL)
+ *****************************************************************************/
+#define DEV_CNTRL2 0x040000 /* Device control */
#define FLD_RUN_RISC 0x00000020
-//*****************************************************************************
-#define PCI_INT_MSK 0x040010 // PCI interrupt mask
-#define PCI_INT_STAT 0x040014 // PCI interrupt status
-#define PCI_INT_MSTAT 0x040018 // PCI interrupt masked status
+/* ***************************************************************************** */
+#define PCI_INT_MSK 0x040010 /* PCI interrupt mask */
+#define PCI_INT_STAT 0x040014 /* PCI interrupt status */
+#define PCI_INT_MSTAT 0x040018 /* PCI interrupt masked status */
#define FLD_HAMMERHEAD_INT (1 << 27)
#define FLD_UART_INT (1 << 26)
#define FLD_IRQN_INT (1 << 25)
@@ -93,65 +93,65 @@
#define FLD_VID_B_INT (1 << 1)
#define FLD_VID_A_INT (1 << 0)
-//*****************************************************************************
-#define VID_A_INT_MSK 0x040020 // Video A interrupt mask
-#define VID_A_INT_STAT 0x040024 // Video A interrupt status
-#define VID_A_INT_MSTAT 0x040028 // Video A interrupt masked status
-#define VID_A_INT_SSTAT 0x04002C // Video A interrupt set status
-
-//*****************************************************************************
-#define VID_B_INT_MSK 0x040030 // Video B interrupt mask
-#define VID_B_INT_STAT 0x040034 // Video B interrupt status
-#define VID_B_INT_MSTAT 0x040038 // Video B interrupt masked status
-#define VID_B_INT_SSTAT 0x04003C // Video B interrupt set status
-
-//*****************************************************************************
-#define VID_C_INT_MSK 0x040040 // Video C interrupt mask
-#define VID_C_INT_STAT 0x040044 // Video C interrupt status
-#define VID_C_INT_MSTAT 0x040048 // Video C interrupt masked status
-#define VID_C_INT_SSTAT 0x04004C // Video C interrupt set status
-
-//*****************************************************************************
-#define VID_D_INT_MSK 0x040050 // Video D interrupt mask
-#define VID_D_INT_STAT 0x040054 // Video D interrupt status
-#define VID_D_INT_MSTAT 0x040058 // Video D interrupt masked status
-#define VID_D_INT_SSTAT 0x04005C // Video D interrupt set status
-
-//*****************************************************************************
-#define VID_E_INT_MSK 0x040060 // Video E interrupt mask
-#define VID_E_INT_STAT 0x040064 // Video E interrupt status
-#define VID_E_INT_MSTAT 0x040068 // Video E interrupt masked status
-#define VID_E_INT_SSTAT 0x04006C // Video E interrupt set status
-
-//*****************************************************************************
-#define VID_F_INT_MSK 0x040070 // Video F interrupt mask
-#define VID_F_INT_STAT 0x040074 // Video F interrupt status
-#define VID_F_INT_MSTAT 0x040078 // Video F interrupt masked status
-#define VID_F_INT_SSTAT 0x04007C // Video F interrupt set status
-
-//*****************************************************************************
-#define VID_G_INT_MSK 0x040080 // Video G interrupt mask
-#define VID_G_INT_STAT 0x040084 // Video G interrupt status
-#define VID_G_INT_MSTAT 0x040088 // Video G interrupt masked status
-#define VID_G_INT_SSTAT 0x04008C // Video G interrupt set status
-
-//*****************************************************************************
-#define VID_H_INT_MSK 0x040090 // Video H interrupt mask
-#define VID_H_INT_STAT 0x040094 // Video H interrupt status
-#define VID_H_INT_MSTAT 0x040098 // Video H interrupt masked status
-#define VID_H_INT_SSTAT 0x04009C // Video H interrupt set status
-
-//*****************************************************************************
-#define VID_I_INT_MSK 0x0400A0 // Video I interrupt mask
-#define VID_I_INT_STAT 0x0400A4 // Video I interrupt status
-#define VID_I_INT_MSTAT 0x0400A8 // Video I interrupt masked status
-#define VID_I_INT_SSTAT 0x0400AC // Video I interrupt set status
-
-//*****************************************************************************
-#define VID_J_INT_MSK 0x0400B0 // Video J interrupt mask
-#define VID_J_INT_STAT 0x0400B4 // Video J interrupt status
-#define VID_J_INT_MSTAT 0x0400B8 // Video J interrupt masked status
-#define VID_J_INT_SSTAT 0x0400BC // Video J interrupt set status
+/* ***************************************************************************** */
+#define VID_A_INT_MSK 0x040020 /* Video A interrupt mask */
+#define VID_A_INT_STAT 0x040024 /* Video A interrupt status */
+#define VID_A_INT_MSTAT 0x040028 /* Video A interrupt masked status */
+#define VID_A_INT_SSTAT 0x04002C /* Video A interrupt set status */
+
+/* ***************************************************************************** */
+#define VID_B_INT_MSK 0x040030 /* Video B interrupt mask */
+#define VID_B_INT_STAT 0x040034 /* Video B interrupt status */
+#define VID_B_INT_MSTAT 0x040038 /* Video B interrupt masked status */
+#define VID_B_INT_SSTAT 0x04003C /* Video B interrupt set status */
+
+/* ***************************************************************************** */
+#define VID_C_INT_MSK 0x040040 /* Video C interrupt mask */
+#define VID_C_INT_STAT 0x040044 /* Video C interrupt status */
+#define VID_C_INT_MSTAT 0x040048 /* Video C interrupt masked status */
+#define VID_C_INT_SSTAT 0x04004C /* Video C interrupt set status */
+
+/* ***************************************************************************** */
+#define VID_D_INT_MSK 0x040050 /* Video D interrupt mask */
+#define VID_D_INT_STAT 0x040054 /* Video D interrupt status */
+#define VID_D_INT_MSTAT 0x040058 /* Video D interrupt masked status */
+#define VID_D_INT_SSTAT 0x04005C /* Video D interrupt set status */
+
+/* ***************************************************************************** */
+#define VID_E_INT_MSK 0x040060 /* Video E interrupt mask */
+#define VID_E_INT_STAT 0x040064 /* Video E interrupt status */
+#define VID_E_INT_MSTAT 0x040068 /* Video E interrupt masked status */
+#define VID_E_INT_SSTAT 0x04006C /* Video E interrupt set status */
+
+/* ***************************************************************************** */
+#define VID_F_INT_MSK 0x040070 /* Video F interrupt mask */
+#define VID_F_INT_STAT 0x040074 /* Video F interrupt status */
+#define VID_F_INT_MSTAT 0x040078 /* Video F interrupt masked status */
+#define VID_F_INT_SSTAT 0x04007C /* Video F interrupt set status */
+
+/* ***************************************************************************** */
+#define VID_G_INT_MSK 0x040080 /* Video G interrupt mask */
+#define VID_G_INT_STAT 0x040084 /* Video G interrupt status */
+#define VID_G_INT_MSTAT 0x040088 /* Video G interrupt masked status */
+#define VID_G_INT_SSTAT 0x04008C /* Video G interrupt set status */
+
+/* ***************************************************************************** */
+#define VID_H_INT_MSK 0x040090 /* Video H interrupt mask */
+#define VID_H_INT_STAT 0x040094 /* Video H interrupt status */
+#define VID_H_INT_MSTAT 0x040098 /* Video H interrupt masked status */
+#define VID_H_INT_SSTAT 0x04009C /* Video H interrupt set status */
+
+/* ***************************************************************************** */
+#define VID_I_INT_MSK 0x0400A0 /* Video I interrupt mask */
+#define VID_I_INT_STAT 0x0400A4 /* Video I interrupt status */
+#define VID_I_INT_MSTAT 0x0400A8 /* Video I interrupt masked status */
+#define VID_I_INT_SSTAT 0x0400AC /* Video I interrupt set status */
+
+/* ***************************************************************************** */
+#define VID_J_INT_MSK 0x0400B0 /* Video J interrupt mask */
+#define VID_J_INT_STAT 0x0400B4 /* Video J interrupt status */
+#define VID_J_INT_MSTAT 0x0400B8 /* Video J interrupt masked status */
+#define VID_J_INT_SSTAT 0x0400BC /* Video J interrupt set status */
#define FLD_VID_SRC_OPC_ERR 0x00020000
#define FLD_VID_DST_OPC_ERR 0x00010000
@@ -166,35 +166,35 @@
#define FLD_VID_SRC_ERRORS FLD_VID_SRC_OPC_ERR | FLD_VID_SRC_SYNC | FLD_VID_SRC_UF
#define FLD_VID_DST_ERRORS FLD_VID_DST_OPC_ERR | FLD_VID_DST_SYNC | FLD_VID_DST_OF
-//*****************************************************************************
-#define AUD_A_INT_MSK 0x0400C0 // Audio Int interrupt mask
-#define AUD_A_INT_STAT 0x0400C4 // Audio Int interrupt status
-#define AUD_A_INT_MSTAT 0x0400C8 // Audio Int interrupt masked status
-#define AUD_A_INT_SSTAT 0x0400CC // Audio Int interrupt set status
-
-//*****************************************************************************
-#define AUD_B_INT_MSK 0x0400D0 // Audio Int interrupt mask
-#define AUD_B_INT_STAT 0x0400D4 // Audio Int interrupt status
-#define AUD_B_INT_MSTAT 0x0400D8 // Audio Int interrupt masked status
-#define AUD_B_INT_SSTAT 0x0400DC // Audio Int interrupt set status
-
-//*****************************************************************************
-#define AUD_C_INT_MSK 0x0400E0 // Audio Int interrupt mask
-#define AUD_C_INT_STAT 0x0400E4 // Audio Int interrupt status
-#define AUD_C_INT_MSTAT 0x0400E8 // Audio Int interrupt masked status
-#define AUD_C_INT_SSTAT 0x0400EC // Audio Int interrupt set status
-
-//*****************************************************************************
-#define AUD_D_INT_MSK 0x0400F0 // Audio Int interrupt mask
-#define AUD_D_INT_STAT 0x0400F4 // Audio Int interrupt status
-#define AUD_D_INT_MSTAT 0x0400F8 // Audio Int interrupt masked status
-#define AUD_D_INT_SSTAT 0x0400FC // Audio Int interrupt set status
-
-//*****************************************************************************
-#define AUD_E_INT_MSK 0x040100 // Audio Int interrupt mask
-#define AUD_E_INT_STAT 0x040104 // Audio Int interrupt status
-#define AUD_E_INT_MSTAT 0x040108 // Audio Int interrupt masked status
-#define AUD_E_INT_SSTAT 0x04010C // Audio Int interrupt set status
+/* ***************************************************************************** */
+#define AUD_A_INT_MSK 0x0400C0 /* Audio Int interrupt mask */
+#define AUD_A_INT_STAT 0x0400C4 /* Audio Int interrupt status */
+#define AUD_A_INT_MSTAT 0x0400C8 /* Audio Int interrupt masked status */
+#define AUD_A_INT_SSTAT 0x0400CC /* Audio Int interrupt set status */
+
+/* ***************************************************************************** */
+#define AUD_B_INT_MSK 0x0400D0 /* Audio Int interrupt mask */
+#define AUD_B_INT_STAT 0x0400D4 /* Audio Int interrupt status */
+#define AUD_B_INT_MSTAT 0x0400D8 /* Audio Int interrupt masked status */
+#define AUD_B_INT_SSTAT 0x0400DC /* Audio Int interrupt set status */
+
+/* ***************************************************************************** */
+#define AUD_C_INT_MSK 0x0400E0 /* Audio Int interrupt mask */
+#define AUD_C_INT_STAT 0x0400E4 /* Audio Int interrupt status */
+#define AUD_C_INT_MSTAT 0x0400E8 /* Audio Int interrupt masked status */
+#define AUD_C_INT_SSTAT 0x0400EC /* Audio Int interrupt set status */
+
+/* ***************************************************************************** */
+#define AUD_D_INT_MSK 0x0400F0 /* Audio Int interrupt mask */
+#define AUD_D_INT_STAT 0x0400F4 /* Audio Int interrupt status */
+#define AUD_D_INT_MSTAT 0x0400F8 /* Audio Int interrupt masked status */
+#define AUD_D_INT_SSTAT 0x0400FC /* Audio Int interrupt set status */
+
+/* ***************************************************************************** */
+#define AUD_E_INT_MSK 0x040100 /* Audio Int interrupt mask */
+#define AUD_E_INT_STAT 0x040104 /* Audio Int interrupt status */
+#define AUD_E_INT_MSTAT 0x040108 /* Audio Int interrupt masked status */
+#define AUD_E_INT_SSTAT 0x04010C /* Audio Int interrupt set status */
#define FLD_AUD_SRC_OPC_ERR 0x00020000
#define FLD_AUD_DST_OPC_ERR 0x00010000
@@ -207,17 +207,17 @@
#define FLD_AUD_SRC_RISCI1 0x00000002
#define FLD_AUD_DST_RISCI1 0x00000001
-//*****************************************************************************
-#define MBIF_A_INT_MSK 0x040110 // MBIF Int interrupt mask
-#define MBIF_A_INT_STAT 0x040114 // MBIF Int interrupt status
-#define MBIF_A_INT_MSTAT 0x040118 // MBIF Int interrupt masked status
-#define MBIF_A_INT_SSTAT 0x04011C // MBIF Int interrupt set status
+/* ***************************************************************************** */
+#define MBIF_A_INT_MSK 0x040110 /* MBIF Int interrupt mask */
+#define MBIF_A_INT_STAT 0x040114 /* MBIF Int interrupt status */
+#define MBIF_A_INT_MSTAT 0x040118 /* MBIF Int interrupt masked status */
+#define MBIF_A_INT_SSTAT 0x04011C /* MBIF Int interrupt set status */
-//*****************************************************************************
-#define MBIF_B_INT_MSK 0x040120 // MBIF Int interrupt mask
-#define MBIF_B_INT_STAT 0x040124 // MBIF Int interrupt status
-#define MBIF_B_INT_MSTAT 0x040128 // MBIF Int interrupt masked status
-#define MBIF_B_INT_SSTAT 0x04012C // MBIF Int interrupt set status
+/* ***************************************************************************** */
+#define MBIF_B_INT_MSK 0x040120 /* MBIF Int interrupt mask */
+#define MBIF_B_INT_STAT 0x040124 /* MBIF Int interrupt status */
+#define MBIF_B_INT_MSTAT 0x040128 /* MBIF Int interrupt masked status */
+#define MBIF_B_INT_SSTAT 0x04012C /* MBIF Int interrupt set status */
#define FLD_MBIF_DST_OPC_ERR 0x00010000
#define FLD_MBIF_DST_SYNC 0x00001000
@@ -225,35 +225,35 @@
#define FLD_MBIF_DST_RISCI2 0x00000010
#define FLD_MBIF_DST_RISCI1 0x00000001
-//*****************************************************************************
-#define AUD_EXT_INT_MSK 0x040060 // Audio Ext interrupt mask
-#define AUD_EXT_INT_STAT 0x040064 // Audio Ext interrupt status
-#define AUD_EXT_INT_MSTAT 0x040068 // Audio Ext interrupt masked status
-#define AUD_EXT_INT_SSTAT 0x04006C // Audio Ext interrupt set status
+/* ***************************************************************************** */
+#define AUD_EXT_INT_MSK 0x040060 /* Audio Ext interrupt mask */
+#define AUD_EXT_INT_STAT 0x040064 /* Audio Ext interrupt status */
+#define AUD_EXT_INT_MSTAT 0x040068 /* Audio Ext interrupt masked status */
+#define AUD_EXT_INT_SSTAT 0x04006C /* Audio Ext interrupt set status */
#define FLD_AUD_EXT_OPC_ERR 0x00010000
#define FLD_AUD_EXT_SYNC 0x00001000
#define FLD_AUD_EXT_OF 0x00000100
#define FLD_AUD_EXT_RISCI2 0x00000010
#define FLD_AUD_EXT_RISCI1 0x00000001
-//*****************************************************************************
-#define GPIO_LO 0x110010 // Lower of GPIO pins [31:0]
-#define GPIO_HI 0x110014 // Upper WORD of GPIO pins [47:31]
+/* ***************************************************************************** */
+#define GPIO_LO 0x110010 /* Lower of GPIO pins [31:0] */
+#define GPIO_HI 0x110014 /* Upper WORD of GPIO pins [47:31] */
-#define GPIO_LO_OE 0x110018 // Lower of GPIO output enable [31:0]
-#define GPIO_HI_OE 0x11001C // Upper word of GPIO output enable [47:32]
+#define GPIO_LO_OE 0x110018 /* Lower of GPIO output enable [31:0] */
+#define GPIO_HI_OE 0x11001C /* Upper word of GPIO output enable [47:32] */
-#define GPIO_LO_INT_MSK 0x11003C // GPIO interrupt mask
-#define GPIO_LO_INT_STAT 0x110044 // GPIO interrupt status
-#define GPIO_LO_INT_MSTAT 0x11004C // GPIO interrupt masked status
-#define GPIO_LO_ISM_SNS 0x110054 // GPIO interrupt sensitivity
-#define GPIO_LO_ISM_POL 0x11005C // GPIO interrupt polarity
+#define GPIO_LO_INT_MSK 0x11003C /* GPIO interrupt mask */
+#define GPIO_LO_INT_STAT 0x110044 /* GPIO interrupt status */
+#define GPIO_LO_INT_MSTAT 0x11004C /* GPIO interrupt masked status */
+#define GPIO_LO_ISM_SNS 0x110054 /* GPIO interrupt sensitivity */
+#define GPIO_LO_ISM_POL 0x11005C /* GPIO interrupt polarity */
-#define GPIO_HI_INT_MSK 0x110040 // GPIO interrupt mask
-#define GPIO_HI_INT_STAT 0x110048 // GPIO interrupt status
-#define GPIO_HI_INT_MSTAT 0x110050 // GPIO interrupt masked status
-#define GPIO_HI_ISM_SNS 0x110058 // GPIO interrupt sensitivity
-#define GPIO_HI_ISM_POL 0x110060 // GPIO interrupt polarity
+#define GPIO_HI_INT_MSK 0x110040 /* GPIO interrupt mask */
+#define GPIO_HI_INT_STAT 0x110048 /* GPIO interrupt status */
+#define GPIO_HI_INT_MSTAT 0x110050 /* GPIO interrupt masked status */
+#define GPIO_HI_ISM_SNS 0x110058 /* GPIO interrupt sensitivity */
+#define GPIO_HI_ISM_POL 0x110060 /* GPIO interrupt polarity */
#define FLD_GPIO43_INT (1 << 11)
#define FLD_GPIO42_INT (1 << 10)
@@ -271,236 +271,236 @@
#define FLD_GPIO1_INT (1 << 1)
#define FLD_GPIO0_INT (1 << 0)
-//*****************************************************************************
-#define TC_REQ 0x040090 // Rider PCI Express traFFic class request
+/* ***************************************************************************** */
+#define TC_REQ 0x040090 /* Rider PCI Express traFFic class request */
-//*****************************************************************************
-#define TC_REQ_SET 0x040094 // Rider PCI Express traFFic class request set
+/* ***************************************************************************** */
+#define TC_REQ_SET 0x040094 /* Rider PCI Express traFFic class request set */
-//*****************************************************************************
-// Rider
-//*****************************************************************************
+/* ***************************************************************************** */
+/* Rider */
+/* ***************************************************************************** */
-// PCI Compatible Header
-//*****************************************************************************
+/* PCI Compatible Header */
+/* ***************************************************************************** */
#define RDR_CFG0 0x050000
#define RDR_VENDOR_DEVICE_ID_CFG 0x050000
-//*****************************************************************************
+/* ***************************************************************************** */
#define RDR_CFG1 0x050004
-//*****************************************************************************
+/* ***************************************************************************** */
#define RDR_CFG2 0x050008
-//*****************************************************************************
+/* ***************************************************************************** */
#define RDR_CFG3 0x05000C
-//*****************************************************************************
+/* ***************************************************************************** */
#define RDR_CFG4 0x050010
-//*****************************************************************************
+/* ***************************************************************************** */
#define RDR_CFG5 0x050014
-//*****************************************************************************
+/* ***************************************************************************** */
#define RDR_CFG6 0x050018
-//*****************************************************************************
+/* ***************************************************************************** */
#define RDR_CFG7 0x05001C
-//*****************************************************************************
+/* ***************************************************************************** */
#define RDR_CFG8 0x050020
-//*****************************************************************************
+/* ***************************************************************************** */
#define RDR_CFG9 0x050024
-//*****************************************************************************
+/* ***************************************************************************** */
#define RDR_CFGA 0x050028
-//*****************************************************************************
+/* ***************************************************************************** */
#define RDR_CFGB 0x05002C
#define RDR_SUSSYSTEM_ID_CFG 0x05002C
-//*****************************************************************************
+/* ***************************************************************************** */
#define RDR_CFGC 0x050030
-//*****************************************************************************
+/* ***************************************************************************** */
#define RDR_CFGD 0x050034
-//*****************************************************************************
+/* ***************************************************************************** */
#define RDR_CFGE 0x050038
-//*****************************************************************************
+/* ***************************************************************************** */
#define RDR_CFGF 0x05003C
-//*****************************************************************************
-// PCI-Express Capabilities
-//*****************************************************************************
+/* ***************************************************************************** */
+/* PCI-Express Capabilities */
+/* ***************************************************************************** */
#define RDR_PECAP 0x050040
-//*****************************************************************************
+/* ***************************************************************************** */
#define RDR_PEDEVCAP 0x050044
-//*****************************************************************************
+/* ***************************************************************************** */
#define RDR_PEDEVSC 0x050048
-//*****************************************************************************
+/* ***************************************************************************** */
#define RDR_PELINKCAP 0x05004C
-//*****************************************************************************
+/* ***************************************************************************** */
#define RDR_PELINKSC 0x050050
-//*****************************************************************************
+/* ***************************************************************************** */
#define RDR_PMICAP 0x050080
-//*****************************************************************************
+/* ***************************************************************************** */
#define RDR_PMCSR 0x050084
-//*****************************************************************************
+/* ***************************************************************************** */
#define RDR_VPDCAP 0x050090
-//*****************************************************************************
+/* ***************************************************************************** */
#define RDR_VPDDATA 0x050094
-//*****************************************************************************
+/* ***************************************************************************** */
#define RDR_MSICAP 0x0500A0
-//*****************************************************************************
+/* ***************************************************************************** */
#define RDR_MSIARL 0x0500A4
-//*****************************************************************************
+/* ***************************************************************************** */
#define RDR_MSIARU 0x0500A8
-//*****************************************************************************
+/* ***************************************************************************** */
#define RDR_MSIDATA 0x0500AC
-//*****************************************************************************
-// PCI Express Extended Capabilities
-//*****************************************************************************
+/* ***************************************************************************** */
+/* PCI Express Extended Capabilities */
+/* ***************************************************************************** */
#define RDR_AERXCAP 0x050100
-//*****************************************************************************
+/* ***************************************************************************** */
#define RDR_AERUESTA 0x050104
-//*****************************************************************************
+/* ***************************************************************************** */
#define RDR_AERUEMSK 0x050108
-//*****************************************************************************
+/* ***************************************************************************** */
#define RDR_AERUESEV 0x05010C
-//*****************************************************************************
+/* ***************************************************************************** */
#define RDR_AERCESTA 0x050110
-//*****************************************************************************
+/* ***************************************************************************** */
#define RDR_AERCEMSK 0x050114
-//*****************************************************************************
+/* ***************************************************************************** */
#define RDR_AERCC 0x050118
-//*****************************************************************************
+/* ***************************************************************************** */
#define RDR_AERHL0 0x05011C
-//*****************************************************************************
+/* ***************************************************************************** */
#define RDR_AERHL1 0x050120
-//*****************************************************************************
+/* ***************************************************************************** */
#define RDR_AERHL2 0x050124
-//*****************************************************************************
+/* ***************************************************************************** */
#define RDR_AERHL3 0x050128
-//*****************************************************************************
+/* ***************************************************************************** */
#define RDR_VCXCAP 0x050200
-//*****************************************************************************
+/* ***************************************************************************** */
#define RDR_VCCAP1 0x050204
-//*****************************************************************************
+/* ***************************************************************************** */
#define RDR_VCCAP2 0x050208
-//*****************************************************************************
+/* ***************************************************************************** */
#define RDR_VCSC 0x05020C
-//*****************************************************************************
+/* ***************************************************************************** */
#define RDR_VCR0_CAP 0x050210
-//*****************************************************************************
+/* ***************************************************************************** */
#define RDR_VCR0_CTRL 0x050214
-//*****************************************************************************
+/* ***************************************************************************** */
#define RDR_VCR0_STAT 0x050218
-//*****************************************************************************
+/* ***************************************************************************** */
#define RDR_VCR1_CAP 0x05021C
-//*****************************************************************************
+/* ***************************************************************************** */
#define RDR_VCR1_CTRL 0x050220
-//*****************************************************************************
+/* ***************************************************************************** */
#define RDR_VCR1_STAT 0x050224
-//*****************************************************************************
+/* ***************************************************************************** */
#define RDR_VCR2_CAP 0x050228
-//*****************************************************************************
+/* ***************************************************************************** */
#define RDR_VCR2_CTRL 0x05022C
-//*****************************************************************************
+/* ***************************************************************************** */
#define RDR_VCR2_STAT 0x050230
-//*****************************************************************************
+/* ***************************************************************************** */
#define RDR_VCR3_CAP 0x050234
-//*****************************************************************************
+/* ***************************************************************************** */
#define RDR_VCR3_CTRL 0x050238
-//*****************************************************************************
+/* ***************************************************************************** */
#define RDR_VCR3_STAT 0x05023C
-//*****************************************************************************
+/* ***************************************************************************** */
#define RDR_VCARB0 0x050240
-//*****************************************************************************
+/* ***************************************************************************** */
#define RDR_VCARB1 0x050244
-//*****************************************************************************
+/* ***************************************************************************** */
#define RDR_VCARB2 0x050248
-//*****************************************************************************
+/* ***************************************************************************** */
#define RDR_VCARB3 0x05024C
-//*****************************************************************************
+/* ***************************************************************************** */
#define RDR_VCARB4 0x050250
-//*****************************************************************************
+/* ***************************************************************************** */
#define RDR_VCARB5 0x050254
-//*****************************************************************************
+/* ***************************************************************************** */
#define RDR_VCARB6 0x050258
-//*****************************************************************************
+/* ***************************************************************************** */
#define RDR_VCARB7 0x05025C
-//*****************************************************************************
+/* ***************************************************************************** */
#define RDR_RDRSTAT0 0x050300
-//*****************************************************************************
+/* ***************************************************************************** */
#define RDR_RDRSTAT1 0x050304
-//*****************************************************************************
+/* ***************************************************************************** */
#define RDR_RDRCTL0 0x050308
-//*****************************************************************************
+/* ***************************************************************************** */
#define RDR_RDRCTL1 0x05030C
-//*****************************************************************************
-// Transaction Layer Registers
-//*****************************************************************************
+/* ***************************************************************************** */
+/* Transaction Layer Registers */
+/* ***************************************************************************** */
#define RDR_TLSTAT0 0x050310
-//*****************************************************************************
+/* ***************************************************************************** */
#define RDR_TLSTAT1 0x050314
-//*****************************************************************************
+/* ***************************************************************************** */
#define RDR_TLCTL0 0x050318
#define FLD_CFG_UR_CPL_MODE 0x00000040
#define FLD_CFG_CORR_ERR_QUITE 0x00000020
@@ -510,569 +510,569 @@
#define FLD_CFG_RELAX_ORDER_MSK 0x00000002
#define FLD_CFG_TAG_ORDER_EN 0x00000001
-//*****************************************************************************
+/* ***************************************************************************** */
#define RDR_TLCTL1 0x05031C
-//*****************************************************************************
+/* ***************************************************************************** */
#define RDR_REQRCAL 0x050320
-//*****************************************************************************
+/* ***************************************************************************** */
#define RDR_REQRCAU 0x050324
-//*****************************************************************************
+/* ***************************************************************************** */
#define RDR_REQEPA 0x050328
-//*****************************************************************************
+/* ***************************************************************************** */
#define RDR_REQCTRL 0x05032C
-//*****************************************************************************
+/* ***************************************************************************** */
#define RDR_REQSTAT 0x050330
-//*****************************************************************************
+/* ***************************************************************************** */
#define RDR_TL_TEST 0x050334
-//*****************************************************************************
+/* ***************************************************************************** */
#define RDR_VCR01_CTL 0x050348
-//*****************************************************************************
+/* ***************************************************************************** */
#define RDR_VCR23_CTL 0x05034C
-//*****************************************************************************
+/* ***************************************************************************** */
#define RDR_RX_VCR0_FC 0x050350
-//*****************************************************************************
+/* ***************************************************************************** */
#define RDR_RX_VCR1_FC 0x050354
-//*****************************************************************************
+/* ***************************************************************************** */
#define RDR_RX_VCR2_FC 0x050358
-//*****************************************************************************
+/* ***************************************************************************** */
#define RDR_RX_VCR3_FC 0x05035C
-//*****************************************************************************
-// Data Link Layer Registers
-//*****************************************************************************
+/* ***************************************************************************** */
+/* Data Link Layer Registers */
+/* ***************************************************************************** */
#define RDR_DLLSTAT 0x050360
-//*****************************************************************************
+/* ***************************************************************************** */
#define RDR_DLLCTRL 0x050364
-//*****************************************************************************
+/* ***************************************************************************** */
#define RDR_REPLAYTO 0x050368
-//*****************************************************************************
+/* ***************************************************************************** */
#define RDR_ACKLATTO 0x05036C
-//*****************************************************************************
-// MAC Layer Registers
-//*****************************************************************************
+/* ***************************************************************************** */
+/* MAC Layer Registers */
+/* ***************************************************************************** */
#define RDR_MACSTAT0 0x050380
-//*****************************************************************************
+/* ***************************************************************************** */
#define RDR_MACSTAT1 0x050384
-//*****************************************************************************
+/* ***************************************************************************** */
#define RDR_MACCTRL0 0x050388
-//*****************************************************************************
+/* ***************************************************************************** */
#define RDR_MACCTRL1 0x05038C
-//*****************************************************************************
+/* ***************************************************************************** */
#define RDR_MACCTRL2 0x050390
-//*****************************************************************************
+/* ***************************************************************************** */
#define RDR_MAC_LB_DATA 0x050394
-//*****************************************************************************
+/* ***************************************************************************** */
#define RDR_L0S_EXIT_LAT 0x050398
-//*****************************************************************************
-// DMAC
-//*****************************************************************************
-#define DMA1_PTR1 0x100000 // DMA Current Ptr : Ch#1
+/* ***************************************************************************** */
+/* DMAC */
+/* ***************************************************************************** */
+#define DMA1_PTR1 0x100000 /* DMA Current Ptr : Ch#1 */
-//*****************************************************************************
-#define DMA2_PTR1 0x100004 // DMA Current Ptr : Ch#2
+/* ***************************************************************************** */
+#define DMA2_PTR1 0x100004 /* DMA Current Ptr : Ch#2 */
-//*****************************************************************************
-#define DMA3_PTR1 0x100008 // DMA Current Ptr : Ch#3
+/* ***************************************************************************** */
+#define DMA3_PTR1 0x100008 /* DMA Current Ptr : Ch#3 */
-//*****************************************************************************
-#define DMA4_PTR1 0x10000C // DMA Current Ptr : Ch#4
+/* ***************************************************************************** */
+#define DMA4_PTR1 0x10000C /* DMA Current Ptr : Ch#4 */
-//*****************************************************************************
-#define DMA5_PTR1 0x100010 // DMA Current Ptr : Ch#5
+/* ***************************************************************************** */
+#define DMA5_PTR1 0x100010 /* DMA Current Ptr : Ch#5 */
-//*****************************************************************************
-#define DMA6_PTR1 0x100014 // DMA Current Ptr : Ch#6
+/* ***************************************************************************** */
+#define DMA6_PTR1 0x100014 /* DMA Current Ptr : Ch#6 */
-//*****************************************************************************
-#define DMA7_PTR1 0x100018 // DMA Current Ptr : Ch#7
+/* ***************************************************************************** */
+#define DMA7_PTR1 0x100018 /* DMA Current Ptr : Ch#7 */
-//*****************************************************************************
-#define DMA8_PTR1 0x10001C // DMA Current Ptr : Ch#8
+/* ***************************************************************************** */
+#define DMA8_PTR1 0x10001C /* DMA Current Ptr : Ch#8 */
-//*****************************************************************************
-#define DMA9_PTR1 0x100020 // DMA Current Ptr : Ch#9
+/* ***************************************************************************** */
+#define DMA9_PTR1 0x100020 /* DMA Current Ptr : Ch#9 */
-//*****************************************************************************
-#define DMA10_PTR1 0x100024 // DMA Current Ptr : Ch#10
+/* ***************************************************************************** */
+#define DMA10_PTR1 0x100024 /* DMA Current Ptr : Ch#10 */
-//*****************************************************************************
-#define DMA11_PTR1 0x100028 // DMA Current Ptr : Ch#11
+/* ***************************************************************************** */
+#define DMA11_PTR1 0x100028 /* DMA Current Ptr : Ch#11 */
-//*****************************************************************************
-#define DMA12_PTR1 0x10002C // DMA Current Ptr : Ch#12
+/* ***************************************************************************** */
+#define DMA12_PTR1 0x10002C /* DMA Current Ptr : Ch#12 */
-//*****************************************************************************
-#define DMA13_PTR1 0x100030 // DMA Current Ptr : Ch#13
+/* ***************************************************************************** */
+#define DMA13_PTR1 0x100030 /* DMA Current Ptr : Ch#13 */
-//*****************************************************************************
-#define DMA14_PTR1 0x100034 // DMA Current Ptr : Ch#14
+/* ***************************************************************************** */
+#define DMA14_PTR1 0x100034 /* DMA Current Ptr : Ch#14 */
-//*****************************************************************************
-#define DMA15_PTR1 0x100038 // DMA Current Ptr : Ch#15
+/* ***************************************************************************** */
+#define DMA15_PTR1 0x100038 /* DMA Current Ptr : Ch#15 */
-//*****************************************************************************
-#define DMA16_PTR1 0x10003C // DMA Current Ptr : Ch#16
+/* ***************************************************************************** */
+#define DMA16_PTR1 0x10003C /* DMA Current Ptr : Ch#16 */
-//*****************************************************************************
-#define DMA17_PTR1 0x100040 // DMA Current Ptr : Ch#17
+/* ***************************************************************************** */
+#define DMA17_PTR1 0x100040 /* DMA Current Ptr : Ch#17 */
-//*****************************************************************************
-#define DMA18_PTR1 0x100044 // DMA Current Ptr : Ch#18
+/* ***************************************************************************** */
+#define DMA18_PTR1 0x100044 /* DMA Current Ptr : Ch#18 */
-//*****************************************************************************
-#define DMA19_PTR1 0x100048 // DMA Current Ptr : Ch#19
+/* ***************************************************************************** */
+#define DMA19_PTR1 0x100048 /* DMA Current Ptr : Ch#19 */
-//*****************************************************************************
-#define DMA20_PTR1 0x10004C // DMA Current Ptr : Ch#20
+/* ***************************************************************************** */
+#define DMA20_PTR1 0x10004C /* DMA Current Ptr : Ch#20 */
-//*****************************************************************************
-#define DMA21_PTR1 0x100050 // DMA Current Ptr : Ch#21
+/* ***************************************************************************** */
+#define DMA21_PTR1 0x100050 /* DMA Current Ptr : Ch#21 */
-//*****************************************************************************
-#define DMA22_PTR1 0x100054 // DMA Current Ptr : Ch#22
+/* ***************************************************************************** */
+#define DMA22_PTR1 0x100054 /* DMA Current Ptr : Ch#22 */
-//*****************************************************************************
-#define DMA23_PTR1 0x100058 // DMA Current Ptr : Ch#23
+/* ***************************************************************************** */
+#define DMA23_PTR1 0x100058 /* DMA Current Ptr : Ch#23 */
-//*****************************************************************************
-#define DMA24_PTR1 0x10005C // DMA Current Ptr : Ch#24
+/* ***************************************************************************** */
+#define DMA24_PTR1 0x10005C /* DMA Current Ptr : Ch#24 */
-//*****************************************************************************
-#define DMA25_PTR1 0x100060 // DMA Current Ptr : Ch#25
+/* ***************************************************************************** */
+#define DMA25_PTR1 0x100060 /* DMA Current Ptr : Ch#25 */
-//*****************************************************************************
-#define DMA26_PTR1 0x100064 // DMA Current Ptr : Ch#26
+/* ***************************************************************************** */
+#define DMA26_PTR1 0x100064 /* DMA Current Ptr : Ch#26 */
-//*****************************************************************************
-#define DMA1_PTR2 0x100080 // DMA Tab Ptr : Ch#1
+/* ***************************************************************************** */
+#define DMA1_PTR2 0x100080 /* DMA Tab Ptr : Ch#1 */
-//*****************************************************************************
-#define DMA2_PTR2 0x100084 // DMA Tab Ptr : Ch#2
+/* ***************************************************************************** */
+#define DMA2_PTR2 0x100084 /* DMA Tab Ptr : Ch#2 */
-//*****************************************************************************
-#define DMA3_PTR2 0x100088 // DMA Tab Ptr : Ch#3
+/* ***************************************************************************** */
+#define DMA3_PTR2 0x100088 /* DMA Tab Ptr : Ch#3 */
-//*****************************************************************************
-#define DMA4_PTR2 0x10008C // DMA Tab Ptr : Ch#4
+/* ***************************************************************************** */
+#define DMA4_PTR2 0x10008C /* DMA Tab Ptr : Ch#4 */
-//*****************************************************************************
-#define DMA5_PTR2 0x100090 // DMA Tab Ptr : Ch#5
+/* ***************************************************************************** */
+#define DMA5_PTR2 0x100090 /* DMA Tab Ptr : Ch#5 */
-//*****************************************************************************
-#define DMA6_PTR2 0x100094 // DMA Tab Ptr : Ch#6
+/* ***************************************************************************** */
+#define DMA6_PTR2 0x100094 /* DMA Tab Ptr : Ch#6 */
-//*****************************************************************************
-#define DMA7_PTR2 0x100098 // DMA Tab Ptr : Ch#7
+/* ***************************************************************************** */
+#define DMA7_PTR2 0x100098 /* DMA Tab Ptr : Ch#7 */
-//*****************************************************************************
-#define DMA8_PTR2 0x10009C // DMA Tab Ptr : Ch#8
+/* ***************************************************************************** */
+#define DMA8_PTR2 0x10009C /* DMA Tab Ptr : Ch#8 */
-//*****************************************************************************
-#define DMA9_PTR2 0x1000A0 // DMA Tab Ptr : Ch#9
+/* ***************************************************************************** */
+#define DMA9_PTR2 0x1000A0 /* DMA Tab Ptr : Ch#9 */
-//*****************************************************************************
-#define DMA10_PTR2 0x1000A4 // DMA Tab Ptr : Ch#10
+/* ***************************************************************************** */
+#define DMA10_PTR2 0x1000A4 /* DMA Tab Ptr : Ch#10 */
-//*****************************************************************************
-#define DMA11_PTR2 0x1000A8 // DMA Tab Ptr : Ch#11
+/* ***************************************************************************** */
+#define DMA11_PTR2 0x1000A8 /* DMA Tab Ptr : Ch#11 */
-//*****************************************************************************
-#define DMA12_PTR2 0x1000AC // DMA Tab Ptr : Ch#12
+/* ***************************************************************************** */
+#define DMA12_PTR2 0x1000AC /* DMA Tab Ptr : Ch#12 */
-//*****************************************************************************
-#define DMA13_PTR2 0x1000B0 // DMA Tab Ptr : Ch#13
+/* ***************************************************************************** */
+#define DMA13_PTR2 0x1000B0 /* DMA Tab Ptr : Ch#13 */
-//*****************************************************************************
-#define DMA14_PTR2 0x1000B4 // DMA Tab Ptr : Ch#14
+/* ***************************************************************************** */
+#define DMA14_PTR2 0x1000B4 /* DMA Tab Ptr : Ch#14 */
-//*****************************************************************************
-#define DMA15_PTR2 0x1000B8 // DMA Tab Ptr : Ch#15
+/* ***************************************************************************** */
+#define DMA15_PTR2 0x1000B8 /* DMA Tab Ptr : Ch#15 */
-//*****************************************************************************
-#define DMA16_PTR2 0x1000BC // DMA Tab Ptr : Ch#16
+/* ***************************************************************************** */
+#define DMA16_PTR2 0x1000BC /* DMA Tab Ptr : Ch#16 */
-//*****************************************************************************
-#define DMA17_PTR2 0x1000C0 // DMA Tab Ptr : Ch#17
+/* ***************************************************************************** */
+#define DMA17_PTR2 0x1000C0 /* DMA Tab Ptr : Ch#17 */
-//*****************************************************************************
-#define DMA18_PTR2 0x1000C4 // DMA Tab Ptr : Ch#18
+/* ***************************************************************************** */
+#define DMA18_PTR2 0x1000C4 /* DMA Tab Ptr : Ch#18 */
-//*****************************************************************************
-#define DMA19_PTR2 0x1000C8 // DMA Tab Ptr : Ch#19
+/* ***************************************************************************** */
+#define DMA19_PTR2 0x1000C8 /* DMA Tab Ptr : Ch#19 */
-//*****************************************************************************
-#define DMA20_PTR2 0x1000CC // DMA Tab Ptr : Ch#20
+/* ***************************************************************************** */
+#define DMA20_PTR2 0x1000CC /* DMA Tab Ptr : Ch#20 */
-//*****************************************************************************
-#define DMA21_PTR2 0x1000D0 // DMA Tab Ptr : Ch#21
+/* ***************************************************************************** */
+#define DMA21_PTR2 0x1000D0 /* DMA Tab Ptr : Ch#21 */
-//*****************************************************************************
-#define DMA22_PTR2 0x1000D4 // DMA Tab Ptr : Ch#22
+/* ***************************************************************************** */
+#define DMA22_PTR2 0x1000D4 /* DMA Tab Ptr : Ch#22 */
-//*****************************************************************************
-#define DMA23_PTR2 0x1000D8 // DMA Tab Ptr : Ch#23
+/* ***************************************************************************** */
+#define DMA23_PTR2 0x1000D8 /* DMA Tab Ptr : Ch#23 */
-//*****************************************************************************
-#define DMA24_PTR2 0x1000DC // DMA Tab Ptr : Ch#24
+/* ***************************************************************************** */
+#define DMA24_PTR2 0x1000DC /* DMA Tab Ptr : Ch#24 */
-//*****************************************************************************
-#define DMA25_PTR2 0x1000E0 // DMA Tab Ptr : Ch#25
+/* ***************************************************************************** */
+#define DMA25_PTR2 0x1000E0 /* DMA Tab Ptr : Ch#25 */
-//*****************************************************************************
-#define DMA26_PTR2 0x1000E4 // DMA Tab Ptr : Ch#26
+/* ***************************************************************************** */
+#define DMA26_PTR2 0x1000E4 /* DMA Tab Ptr : Ch#26 */
-//*****************************************************************************
-#define DMA1_CNT1 0x100100 // DMA BuFFer Size : Ch#1
+/* ***************************************************************************** */
+#define DMA1_CNT1 0x100100 /* DMA BuFFer Size : Ch#1 */
-//*****************************************************************************
-#define DMA2_CNT1 0x100104 // DMA BuFFer Size : Ch#2
+/* ***************************************************************************** */
+#define DMA2_CNT1 0x100104 /* DMA BuFFer Size : Ch#2 */
-//*****************************************************************************
-#define DMA3_CNT1 0x100108 // DMA BuFFer Size : Ch#3
+/* ***************************************************************************** */
+#define DMA3_CNT1 0x100108 /* DMA BuFFer Size : Ch#3 */
-//*****************************************************************************
-#define DMA4_CNT1 0x10010C // DMA BuFFer Size : Ch#4
+/* ***************************************************************************** */
+#define DMA4_CNT1 0x10010C /* DMA BuFFer Size : Ch#4 */
-//*****************************************************************************
-#define DMA5_CNT1 0x100110 // DMA BuFFer Size : Ch#5
+/* ***************************************************************************** */
+#define DMA5_CNT1 0x100110 /* DMA BuFFer Size : Ch#5 */
-//*****************************************************************************
-#define DMA6_CNT1 0x100114 // DMA BuFFer Size : Ch#6
+/* ***************************************************************************** */
+#define DMA6_CNT1 0x100114 /* DMA BuFFer Size : Ch#6 */
-//*****************************************************************************
-#define DMA7_CNT1 0x100118 // DMA BuFFer Size : Ch#7
+/* ***************************************************************************** */
+#define DMA7_CNT1 0x100118 /* DMA BuFFer Size : Ch#7 */
-//*****************************************************************************
-#define DMA8_CNT1 0x10011C // DMA BuFFer Size : Ch#8
+/* ***************************************************************************** */
+#define DMA8_CNT1 0x10011C /* DMA BuFFer Size : Ch#8 */
-//*****************************************************************************
-#define DMA9_CNT1 0x100120 // DMA BuFFer Size : Ch#9
+/* ***************************************************************************** */
+#define DMA9_CNT1 0x100120 /* DMA BuFFer Size : Ch#9 */
-//*****************************************************************************
-#define DMA10_CNT1 0x100124 // DMA BuFFer Size : Ch#10
+/* ***************************************************************************** */
+#define DMA10_CNT1 0x100124 /* DMA BuFFer Size : Ch#10 */
-//*****************************************************************************
-#define DMA11_CNT1 0x100128 // DMA BuFFer Size : Ch#11
+/* ***************************************************************************** */
+#define DMA11_CNT1 0x100128 /* DMA BuFFer Size : Ch#11 */
-//*****************************************************************************
-#define DMA12_CNT1 0x10012C // DMA BuFFer Size : Ch#12
+/* ***************************************************************************** */
+#define DMA12_CNT1 0x10012C /* DMA BuFFer Size : Ch#12 */
-//*****************************************************************************
-#define DMA13_CNT1 0x100130 // DMA BuFFer Size : Ch#13
+/* ***************************************************************************** */
+#define DMA13_CNT1 0x100130 /* DMA BuFFer Size : Ch#13 */
-//*****************************************************************************
-#define DMA14_CNT1 0x100134 // DMA BuFFer Size : Ch#14
+/* ***************************************************************************** */
+#define DMA14_CNT1 0x100134 /* DMA BuFFer Size : Ch#14 */
-//*****************************************************************************
-#define DMA15_CNT1 0x100138 // DMA BuFFer Size : Ch#15
+/* ***************************************************************************** */
+#define DMA15_CNT1 0x100138 /* DMA BuFFer Size : Ch#15 */
-//*****************************************************************************
-#define DMA16_CNT1 0x10013C // DMA BuFFer Size : Ch#16
+/* ***************************************************************************** */
+#define DMA16_CNT1 0x10013C /* DMA BuFFer Size : Ch#16 */
-//*****************************************************************************
-#define DMA17_CNT1 0x100140 // DMA BuFFer Size : Ch#17
+/* ***************************************************************************** */
+#define DMA17_CNT1 0x100140 /* DMA BuFFer Size : Ch#17 */
-//*****************************************************************************
-#define DMA18_CNT1 0x100144 // DMA BuFFer Size : Ch#18
+/* ***************************************************************************** */
+#define DMA18_CNT1 0x100144 /* DMA BuFFer Size : Ch#18 */
-//*****************************************************************************
-#define DMA19_CNT1 0x100148 // DMA BuFFer Size : Ch#19
+/* ***************************************************************************** */
+#define DMA19_CNT1 0x100148 /* DMA BuFFer Size : Ch#19 */
-//*****************************************************************************
-#define DMA20_CNT1 0x10014C // DMA BuFFer Size : Ch#20
+/* ***************************************************************************** */
+#define DMA20_CNT1 0x10014C /* DMA BuFFer Size : Ch#20 */
-//*****************************************************************************
-#define DMA21_CNT1 0x100150 // DMA BuFFer Size : Ch#21
+/* ***************************************************************************** */
+#define DMA21_CNT1 0x100150 /* DMA BuFFer Size : Ch#21 */
-//*****************************************************************************
-#define DMA22_CNT1 0x100154 // DMA BuFFer Size : Ch#22
+/* ***************************************************************************** */
+#define DMA22_CNT1 0x100154 /* DMA BuFFer Size : Ch#22 */
-//*****************************************************************************
-#define DMA23_CNT1 0x100158 // DMA BuFFer Size : Ch#23
+/* ***************************************************************************** */
+#define DMA23_CNT1 0x100158 /* DMA BuFFer Size : Ch#23 */
-//*****************************************************************************
-#define DMA24_CNT1 0x10015C // DMA BuFFer Size : Ch#24
+/* ***************************************************************************** */
+#define DMA24_CNT1 0x10015C /* DMA BuFFer Size : Ch#24 */
-//*****************************************************************************
-#define DMA25_CNT1 0x100160 // DMA BuFFer Size : Ch#25
+/* ***************************************************************************** */
+#define DMA25_CNT1 0x100160 /* DMA BuFFer Size : Ch#25 */
-//*****************************************************************************
-#define DMA26_CNT1 0x100164 // DMA BuFFer Size : Ch#26
+/* ***************************************************************************** */
+#define DMA26_CNT1 0x100164 /* DMA BuFFer Size : Ch#26 */
-//*****************************************************************************
-#define DMA1_CNT2 0x100180 // DMA Table Size : Ch#1
+/* ***************************************************************************** */
+#define DMA1_CNT2 0x100180 /* DMA Table Size : Ch#1 */
-//*****************************************************************************
-#define DMA2_CNT2 0x100184 // DMA Table Size : Ch#2
+/* ***************************************************************************** */
+#define DMA2_CNT2 0x100184 /* DMA Table Size : Ch#2 */
-//*****************************************************************************
-#define DMA3_CNT2 0x100188 // DMA Table Size : Ch#3
+/* ***************************************************************************** */
+#define DMA3_CNT2 0x100188 /* DMA Table Size : Ch#3 */
-//*****************************************************************************
-#define DMA4_CNT2 0x10018C // DMA Table Size : Ch#4
+/* ***************************************************************************** */
+#define DMA4_CNT2 0x10018C /* DMA Table Size : Ch#4 */
-//*****************************************************************************
-#define DMA5_CNT2 0x100190 // DMA Table Size : Ch#5
+/* ***************************************************************************** */
+#define DMA5_CNT2 0x100190 /* DMA Table Size : Ch#5 */
-//*****************************************************************************
-#define DMA6_CNT2 0x100194 // DMA Table Size : Ch#6
+/* ***************************************************************************** */
+#define DMA6_CNT2 0x100194 /* DMA Table Size : Ch#6 */
-//*****************************************************************************
-#define DMA7_CNT2 0x100198 // DMA Table Size : Ch#7
+/* ***************************************************************************** */
+#define DMA7_CNT2 0x100198 /* DMA Table Size : Ch#7 */
-//*****************************************************************************
-#define DMA8_CNT2 0x10019C // DMA Table Size : Ch#8
+/* ***************************************************************************** */
+#define DMA8_CNT2 0x10019C /* DMA Table Size : Ch#8 */
-//*****************************************************************************
-#define DMA9_CNT2 0x1001A0 // DMA Table Size : Ch#9
+/* ***************************************************************************** */
+#define DMA9_CNT2 0x1001A0 /* DMA Table Size : Ch#9 */
-//*****************************************************************************
-#define DMA10_CNT2 0x1001A4 // DMA Table Size : Ch#10
+/* ***************************************************************************** */
+#define DMA10_CNT2 0x1001A4 /* DMA Table Size : Ch#10 */
-//*****************************************************************************
-#define DMA11_CNT2 0x1001A8 // DMA Table Size : Ch#11
+/* ***************************************************************************** */
+#define DMA11_CNT2 0x1001A8 /* DMA Table Size : Ch#11 */
-//*****************************************************************************
-#define DMA12_CNT2 0x1001AC // DMA Table Size : Ch#12
+/* ***************************************************************************** */
+#define DMA12_CNT2 0x1001AC /* DMA Table Size : Ch#12 */
-//*****************************************************************************
-#define DMA13_CNT2 0x1001B0 // DMA Table Size : Ch#13
+/* ***************************************************************************** */
+#define DMA13_CNT2 0x1001B0 /* DMA Table Size : Ch#13 */
-//*****************************************************************************
-#define DMA14_CNT2 0x1001B4 // DMA Table Size : Ch#14
+/* ***************************************************************************** */
+#define DMA14_CNT2 0x1001B4 /* DMA Table Size : Ch#14 */
-//*****************************************************************************
-#define DMA15_CNT2 0x1001B8 // DMA Table Size : Ch#15
+/* ***************************************************************************** */
+#define DMA15_CNT2 0x1001B8 /* DMA Table Size : Ch#15 */
-//*****************************************************************************
-#define DMA16_CNT2 0x1001BC // DMA Table Size : Ch#16
+/* ***************************************************************************** */
+#define DMA16_CNT2 0x1001BC /* DMA Table Size : Ch#16 */
-//*****************************************************************************
-#define DMA17_CNT2 0x1001C0 // DMA Table Size : Ch#17
+/* ***************************************************************************** */
+#define DMA17_CNT2 0x1001C0 /* DMA Table Size : Ch#17 */
-//*****************************************************************************
-#define DMA18_CNT2 0x1001C4 // DMA Table Size : Ch#18
+/* ***************************************************************************** */
+#define DMA18_CNT2 0x1001C4 /* DMA Table Size : Ch#18 */
-//*****************************************************************************
-#define DMA19_CNT2 0x1001C8 // DMA Table Size : Ch#19
+/* ***************************************************************************** */
+#define DMA19_CNT2 0x1001C8 /* DMA Table Size : Ch#19 */
-//*****************************************************************************
-#define DMA20_CNT2 0x1001CC // DMA Table Size : Ch#20
+/* ***************************************************************************** */
+#define DMA20_CNT2 0x1001CC /* DMA Table Size : Ch#20 */
-//*****************************************************************************
-#define DMA21_CNT2 0x1001D0 // DMA Table Size : Ch#21
+/* ***************************************************************************** */
+#define DMA21_CNT2 0x1001D0 /* DMA Table Size : Ch#21 */
-//*****************************************************************************
-#define DMA22_CNT2 0x1001D4 // DMA Table Size : Ch#22
+/* ***************************************************************************** */
+#define DMA22_CNT2 0x1001D4 /* DMA Table Size : Ch#22 */
-//*****************************************************************************
-#define DMA23_CNT2 0x1001D8 // DMA Table Size : Ch#23
+/* ***************************************************************************** */
+#define DMA23_CNT2 0x1001D8 /* DMA Table Size : Ch#23 */
-//*****************************************************************************
-#define DMA24_CNT2 0x1001DC // DMA Table Size : Ch#24
+/* ***************************************************************************** */
+#define DMA24_CNT2 0x1001DC /* DMA Table Size : Ch#24 */
-//*****************************************************************************
-#define DMA25_CNT2 0x1001E0 // DMA Table Size : Ch#25
+/* ***************************************************************************** */
+#define DMA25_CNT2 0x1001E0 /* DMA Table Size : Ch#25 */
-//*****************************************************************************
-#define DMA26_CNT2 0x1001E4 // DMA Table Size : Ch#26
+/* ***************************************************************************** */
+#define DMA26_CNT2 0x1001E4 /* DMA Table Size : Ch#26 */
-//*****************************************************************************
- // ITG
-//*****************************************************************************
-#define TM_CNT_LDW 0x110000 // Timer : Counter low
+/* ***************************************************************************** */
+ /* ITG */
+/* ***************************************************************************** */
+#define TM_CNT_LDW 0x110000 /* Timer : Counter low */
-//*****************************************************************************
-#define TM_CNT_UW 0x110004 // Timer : Counter high word
+/* ***************************************************************************** */
+#define TM_CNT_UW 0x110004 /* Timer : Counter high word */
-//*****************************************************************************
-#define TM_LMT_LDW 0x110008 // Timer : Limit low
+/* ***************************************************************************** */
+#define TM_LMT_LDW 0x110008 /* Timer : Limit low */
-//*****************************************************************************
-#define TM_LMT_UW 0x11000C // Timer : Limit high word
+/* ***************************************************************************** */
+#define TM_LMT_UW 0x11000C /* Timer : Limit high word */
-//*****************************************************************************
-#define GP0_IO 0x110010 // GPIO output enables data I/O
-#define FLD_GP_OE 0x00FF0000 // GPIO: GP_OE output enable
-#define FLD_GP_IN 0x0000FF00 // GPIO: GP_IN status
-#define FLD_GP_OUT 0x000000FF // GPIO: GP_OUT control
+/* ***************************************************************************** */
+#define GP0_IO 0x110010 /* GPIO output enables data I/O */
+#define FLD_GP_OE 0x00FF0000 /* GPIO: GP_OE output enable */
+#define FLD_GP_IN 0x0000FF00 /* GPIO: GP_IN status */
+#define FLD_GP_OUT 0x000000FF /* GPIO: GP_OUT control */
-//*****************************************************************************
-#define GPIO_ISM 0x110014 // GPIO interrupt sensitivity mode
+/* ***************************************************************************** */
+#define GPIO_ISM 0x110014 /* GPIO interrupt sensitivity mode */
#define FLD_GP_ISM_SNS 0x00000070
#define FLD_GP_ISM_POL 0x00000007
-//*****************************************************************************
-#define SOFT_RESET 0x11001C // Output system reset reg
+/* ***************************************************************************** */
+#define SOFT_RESET 0x11001C /* Output system reset reg */
#define FLD_PECOS_SOFT_RESET 0x00000001
-//*****************************************************************************
-#define MC416_RWD 0x110020 // MC416 GPIO[18:3] pin
-#define MC416_OEN 0x110024 // Output enable of GPIO[18:3]
+/* ***************************************************************************** */
+#define MC416_RWD 0x110020 /* MC416 GPIO[18:3] pin */
+#define MC416_OEN 0x110024 /* Output enable of GPIO[18:3] */
#define MC416_CTL 0x110028
-//*****************************************************************************
-#define ALT_PIN_OUT_SEL 0x11002C // Alternate GPIO output select
+/* ***************************************************************************** */
+#define ALT_PIN_OUT_SEL 0x11002C /* Alternate GPIO output select */
#define FLD_ALT_GPIO_OUT_SEL 0xF0000000
-// 0 Disabled <-- default
-// 1 GPIO[0]
-// 2 GPIO[10]
-// 3 VIP_656_DATA_VAL
-// 4 VIP_656_DATA[0]
-// 5 VIP_656_CLK
-// 6 VIP_656_DATA_EXT[1]
-// 7 VIP_656_DATA_EXT[0]
-// 8 ATT_IF
+/* 0 Disabled <-- default */
+/* 1 GPIO[0] */
+/* 2 GPIO[10] */
+/* 3 VIP_656_DATA_VAL */
+/* 4 VIP_656_DATA[0] */
+/* 5 VIP_656_CLK */
+/* 6 VIP_656_DATA_EXT[1] */
+/* 7 VIP_656_DATA_EXT[0] */
+/* 8 ATT_IF */
#define FLD_AUX_PLL_CLK_ALT_SEL 0x0F000000
-// 0 AUX_PLL_CLK<-- default
-// 1 GPIO[2]
-// 2 GPIO[10]
-// 3 VIP_656_DATA_VAL
-// 4 VIP_656_DATA[0]
-// 5 VIP_656_CLK
-// 6 VIP_656_DATA_EXT[1]
-// 7 VIP_656_DATA_EXT[0]
+/* 0 AUX_PLL_CLK<-- default */
+/* 1 GPIO[2] */
+/* 2 GPIO[10] */
+/* 3 VIP_656_DATA_VAL */
+/* 4 VIP_656_DATA[0] */
+/* 5 VIP_656_CLK */
+/* 6 VIP_656_DATA_EXT[1] */
+/* 7 VIP_656_DATA_EXT[0] */
#define FLD_IR_TX_ALT_SEL 0x00F00000
-// 0 IR_TX <-- default
-// 1 GPIO[1]
-// 2 GPIO[10]
-// 3 VIP_656_DATA_VAL
-// 4 VIP_656_DATA[0]
-// 5 VIP_656_CLK
-// 6 VIP_656_DATA_EXT[1]
-// 7 VIP_656_DATA_EXT[0]
+/* 0 IR_TX <-- default */
+/* 1 GPIO[1] */
+/* 2 GPIO[10] */
+/* 3 VIP_656_DATA_VAL */
+/* 4 VIP_656_DATA[0] */
+/* 5 VIP_656_CLK */
+/* 6 VIP_656_DATA_EXT[1] */
+/* 7 VIP_656_DATA_EXT[0] */
#define FLD_IR_RX_ALT_SEL 0x000F0000
-// 0 IR_RX <-- default
-// 1 GPIO[0]
-// 2 GPIO[10]
-// 3 VIP_656_DATA_VAL
-// 4 VIP_656_DATA[0]
-// 5 VIP_656_CLK
-// 6 VIP_656_DATA_EXT[1]
-// 7 VIP_656_DATA_EXT[0]
+/* 0 IR_RX <-- default */
+/* 1 GPIO[0] */
+/* 2 GPIO[10] */
+/* 3 VIP_656_DATA_VAL */
+/* 4 VIP_656_DATA[0] */
+/* 5 VIP_656_CLK */
+/* 6 VIP_656_DATA_EXT[1] */
+/* 7 VIP_656_DATA_EXT[0] */
#define FLD_GPIO10_ALT_SEL 0x0000F000
-// 0 GPIO[10] <-- default
-// 1 GPIO[0]
-// 2 GPIO[10]
-// 3 VIP_656_DATA_VAL
-// 4 VIP_656_DATA[0]
-// 5 VIP_656_CLK
-// 6 VIP_656_DATA_EXT[1]
-// 7 VIP_656_DATA_EXT[0]
+/* 0 GPIO[10] <-- default */
+/* 1 GPIO[0] */
+/* 2 GPIO[10] */
+/* 3 VIP_656_DATA_VAL */
+/* 4 VIP_656_DATA[0] */
+/* 5 VIP_656_CLK */
+/* 6 VIP_656_DATA_EXT[1] */
+/* 7 VIP_656_DATA_EXT[0] */
#define FLD_GPIO2_ALT_SEL 0x00000F00
-// 0 GPIO[2] <-- default
-// 1 GPIO[1]
-// 2 GPIO[10]
-// 3 VIP_656_DATA_VAL
-// 4 VIP_656_DATA[0]
-// 5 VIP_656_CLK
-// 6 VIP_656_DATA_EXT[1]
-// 7 VIP_656_DATA_EXT[0]
+/* 0 GPIO[2] <-- default */
+/* 1 GPIO[1] */
+/* 2 GPIO[10] */
+/* 3 VIP_656_DATA_VAL */
+/* 4 VIP_656_DATA[0] */
+/* 5 VIP_656_CLK */
+/* 6 VIP_656_DATA_EXT[1] */
+/* 7 VIP_656_DATA_EXT[0] */
#define FLD_GPIO1_ALT_SEL 0x000000F0
-// 0 GPIO[1] <-- default
-// 1 GPIO[0]
-// 2 GPIO[10]
-// 3 VIP_656_DATA_VAL
-// 4 VIP_656_DATA[0]
-// 5 VIP_656_CLK
-// 6 VIP_656_DATA_EXT[1]
-// 7 VIP_656_DATA_EXT[0]
+/* 0 GPIO[1] <-- default */
+/* 1 GPIO[0] */
+/* 2 GPIO[10] */
+/* 3 VIP_656_DATA_VAL */
+/* 4 VIP_656_DATA[0] */
+/* 5 VIP_656_CLK */
+/* 6 VIP_656_DATA_EXT[1] */
+/* 7 VIP_656_DATA_EXT[0] */
#define FLD_GPIO0_ALT_SEL 0x0000000F
-// 0 GPIO[0] <-- default
-// 1 GPIO[1]
-// 2 GPIO[10]
-// 3 VIP_656_DATA_VAL
-// 4 VIP_656_DATA[0]
-// 5 VIP_656_CLK
-// 6 VIP_656_DATA_EXT[1]
-// 7 VIP_656_DATA_EXT[0]
+/* 0 GPIO[0] <-- default */
+/* 1 GPIO[1] */
+/* 2 GPIO[10] */
+/* 3 VIP_656_DATA_VAL */
+/* 4 VIP_656_DATA[0] */
+/* 5 VIP_656_CLK */
+/* 6 VIP_656_DATA_EXT[1] */
+/* 7 VIP_656_DATA_EXT[0] */
-#define ALT_PIN_IN_SEL 0x110030 // Alternate GPIO input select
+#define ALT_PIN_IN_SEL 0x110030 /* Alternate GPIO input select */
#define FLD_GPIO10_ALT_IN_SEL 0x0000F000
-// 0 GPIO[10] <-- default
-// 1 IR_RX
-// 2 IR_TX
-// 3 AUX_PLL_CLK
-// 4 IF_ATT_SEL
-// 5 GPIO[0]
-// 6 GPIO[1]
-// 7 GPIO[2]
+/* 0 GPIO[10] <-- default */
+/* 1 IR_RX */
+/* 2 IR_TX */
+/* 3 AUX_PLL_CLK */
+/* 4 IF_ATT_SEL */
+/* 5 GPIO[0] */
+/* 6 GPIO[1] */
+/* 7 GPIO[2] */
#define FLD_GPIO2_ALT_IN_SEL 0x00000F00
-// 0 GPIO[2] <-- default
-// 1 IR_RX
-// 2 IR_TX
-// 3 AUX_PLL_CLK
-// 4 IF_ATT_SEL
+/* 0 GPIO[2] <-- default */
+/* 1 IR_RX */
+/* 2 IR_TX */
+/* 3 AUX_PLL_CLK */
+/* 4 IF_ATT_SEL */
#define FLD_GPIO1_ALT_IN_SEL 0x000000F0
-// 0 GPIO[1] <-- default
-// 1 IR_RX
-// 2 IR_TX
-// 3 AUX_PLL_CLK
-// 4 IF_ATT_SEL
+/* 0 GPIO[1] <-- default */
+/* 1 IR_RX */
+/* 2 IR_TX */
+/* 3 AUX_PLL_CLK */
+/* 4 IF_ATT_SEL */
#define FLD_GPIO0_ALT_IN_SEL 0x0000000F
-// 0 GPIO[0] <-- default
-// 1 IR_RX
-// 2 IR_TX
-// 3 AUX_PLL_CLK
-// 4 IF_ATT_SEL
+/* 0 GPIO[0] <-- default */
+/* 1 IR_RX */
+/* 2 IR_TX */
+/* 3 AUX_PLL_CLK */
+/* 4 IF_ATT_SEL */
-//*****************************************************************************
-#define TEST_BUS_CTL1 0x110040 // Test bus control register #1
+/* ***************************************************************************** */
+#define TEST_BUS_CTL1 0x110040 /* Test bus control register #1 */
-//*****************************************************************************
-#define TEST_BUS_CTL2 0x110044 // Test bus control register #2
+/* ***************************************************************************** */
+#define TEST_BUS_CTL2 0x110044 /* Test bus control register #2 */
-//*****************************************************************************
-#define CLK_DELAY 0x110048 // Clock delay
-#define FLD_MOE_CLK_DIS 0x80000000 // Disable MoE clock
+/* ***************************************************************************** */
+#define CLK_DELAY 0x110048 /* Clock delay */
+#define FLD_MOE_CLK_DIS 0x80000000 /* Disable MoE clock */
-//*****************************************************************************
-#define PAD_CTRL 0x110068 // Pad drive strength control
+/* ***************************************************************************** */
+#define PAD_CTRL 0x110068 /* Pad drive strength control */
-//*****************************************************************************
-#define MBIST_CTRL 0x110050 // SRAM memory built-in self test control
+/* ***************************************************************************** */
+#define MBIST_CTRL 0x110050 /* SRAM memory built-in self test control */
-//*****************************************************************************
-#define MBIST_STAT 0x110054 // SRAM memory built-in self test status
+/* ***************************************************************************** */
+#define MBIST_STAT 0x110054 /* SRAM memory built-in self test status */
-//*****************************************************************************
-// PLL registers
-//*****************************************************************************
+/* ***************************************************************************** */
+/* PLL registers */
+/* ***************************************************************************** */
#define PLL_A_INT_FRAC 0x110088
#define PLL_A_POST_STAT_BIST 0x11008C
#define PLL_B_INT_FRAC 0x110090
@@ -1090,260 +1090,260 @@
#define VID_CH_MODE_SEL 0x110078
#define VID_CH_CLK_SEL 0x11007C
-//*****************************************************************************
-#define VBI_A_DMA 0x130008 // VBI A DMA data port
+/* ***************************************************************************** */
+#define VBI_A_DMA 0x130008 /* VBI A DMA data port */
-//*****************************************************************************
-#define VID_A_VIP_CTL 0x130080 // Video A VIP format control
+/* ***************************************************************************** */
+#define VID_A_VIP_CTL 0x130080 /* Video A VIP format control */
#define FLD_VIP_MODE 0x00000001
-//*****************************************************************************
-#define VID_A_PIXEL_FRMT 0x130084 // Video A pixel format
+/* ***************************************************************************** */
+#define VID_A_PIXEL_FRMT 0x130084 /* Video A pixel format */
#define FLD_VID_A_GAMMA_DIS 0x00000008
#define FLD_VID_A_FORMAT 0x00000007
#define FLD_VID_A_GAMMA_FACTOR 0x00000010
-//*****************************************************************************
-#define VID_A_VBI_CTL 0x130088 // Video A VBI miscellaneous control
+/* ***************************************************************************** */
+#define VID_A_VBI_CTL 0x130088 /* Video A VBI miscellaneous control */
#define FLD_VID_A_VIP_EXT 0x00000003
-//*****************************************************************************
-#define VID_B_DMA 0x130100 // Video B DMA data port
+/* ***************************************************************************** */
+#define VID_B_DMA 0x130100 /* Video B DMA data port */
-//*****************************************************************************
-#define VBI_B_DMA 0x130108 // VBI B DMA data port
+/* ***************************************************************************** */
+#define VBI_B_DMA 0x130108 /* VBI B DMA data port */
-//*****************************************************************************
-#define VID_B_SRC_SEL 0x130144 // Video B source select
+/* ***************************************************************************** */
+#define VID_B_SRC_SEL 0x130144 /* Video B source select */
#define FLD_VID_B_SRC_SEL 0x00000000
-//*****************************************************************************
-#define VID_B_LNGTH 0x130150 // Video B line length
+/* ***************************************************************************** */
+#define VID_B_LNGTH 0x130150 /* Video B line length */
#define FLD_VID_B_LN_LNGTH 0x00000FFF
-//*****************************************************************************
-#define VID_B_VIP_CTL 0x130180 // Video B VIP format control
+/* ***************************************************************************** */
+#define VID_B_VIP_CTL 0x130180 /* Video B VIP format control */
-//*****************************************************************************
-#define VID_B_PIXEL_FRMT 0x130184 // Video B pixel format
+/* ***************************************************************************** */
+#define VID_B_PIXEL_FRMT 0x130184 /* Video B pixel format */
#define FLD_VID_B_GAMMA_DIS 0x00000008
#define FLD_VID_B_FORMAT 0x00000007
#define FLD_VID_B_GAMMA_FACTOR 0x00000010
-//*****************************************************************************
-#define VID_C_DMA 0x130200 // Video C DMA data port
+/* ***************************************************************************** */
+#define VID_C_DMA 0x130200 /* Video C DMA data port */
-//*****************************************************************************
-#define VID_C_LNGTH 0x130250 // Video C line length
+/* ***************************************************************************** */
+#define VID_C_LNGTH 0x130250 /* Video C line length */
#define FLD_VID_C_LN_LNGTH 0x00000FFF
-//*****************************************************************************
-// Video Destination Channels
-//*****************************************************************************
-
-#define VID_DST_A_GPCNT 0x130020 // Video A general purpose counter
-#define VID_DST_B_GPCNT 0x130120 // Video B general purpose counter
-#define VID_DST_C_GPCNT 0x130220 // Video C general purpose counter
-#define VID_DST_D_GPCNT 0x130320 // Video D general purpose counter
-#define VID_DST_E_GPCNT 0x130420 // Video E general purpose counter
-#define VID_DST_F_GPCNT 0x130520 // Video F general purpose counter
-#define VID_DST_G_GPCNT 0x130620 // Video G general purpose counter
-#define VID_DST_H_GPCNT 0x130720 // Video H general purpose counter
-
-//*****************************************************************************
-
-#define VID_DST_A_GPCNT_CTL 0x130030 // Video A general purpose control
-#define VID_DST_B_GPCNT_CTL 0x130130 // Video B general purpose control
-#define VID_DST_C_GPCNT_CTL 0x130230 // Video C general purpose control
-#define VID_DST_D_GPCNT_CTL 0x130330 // Video D general purpose control
-#define VID_DST_E_GPCNT_CTL 0x130430 // Video E general purpose control
-#define VID_DST_F_GPCNT_CTL 0x130530 // Video F general purpose control
-#define VID_DST_G_GPCNT_CTL 0x130630 // Video G general purpose control
-#define VID_DST_H_GPCNT_CTL 0x130730 // Video H general purpose control
-
-//*****************************************************************************
-
-#define VID_DST_A_DMA_CTL 0x130040 // Video A DMA control
-#define VID_DST_B_DMA_CTL 0x130140 // Video B DMA control
-#define VID_DST_C_DMA_CTL 0x130240 // Video C DMA control
-#define VID_DST_D_DMA_CTL 0x130340 // Video D DMA control
-#define VID_DST_E_DMA_CTL 0x130440 // Video E DMA control
-#define VID_DST_F_DMA_CTL 0x130540 // Video F DMA control
-#define VID_DST_G_DMA_CTL 0x130640 // Video G DMA control
-#define VID_DST_H_DMA_CTL 0x130740 // Video H DMA control
+/* ***************************************************************************** */
+/* Video Destination Channels */
+/* ***************************************************************************** */
+
+#define VID_DST_A_GPCNT 0x130020 /* Video A general purpose counter */
+#define VID_DST_B_GPCNT 0x130120 /* Video B general purpose counter */
+#define VID_DST_C_GPCNT 0x130220 /* Video C general purpose counter */
+#define VID_DST_D_GPCNT 0x130320 /* Video D general purpose counter */
+#define VID_DST_E_GPCNT 0x130420 /* Video E general purpose counter */
+#define VID_DST_F_GPCNT 0x130520 /* Video F general purpose counter */
+#define VID_DST_G_GPCNT 0x130620 /* Video G general purpose counter */
+#define VID_DST_H_GPCNT 0x130720 /* Video H general purpose counter */
+
+/* ***************************************************************************** */
+
+#define VID_DST_A_GPCNT_CTL 0x130030 /* Video A general purpose control */
+#define VID_DST_B_GPCNT_CTL 0x130130 /* Video B general purpose control */
+#define VID_DST_C_GPCNT_CTL 0x130230 /* Video C general purpose control */
+#define VID_DST_D_GPCNT_CTL 0x130330 /* Video D general purpose control */
+#define VID_DST_E_GPCNT_CTL 0x130430 /* Video E general purpose control */
+#define VID_DST_F_GPCNT_CTL 0x130530 /* Video F general purpose control */
+#define VID_DST_G_GPCNT_CTL 0x130630 /* Video G general purpose control */
+#define VID_DST_H_GPCNT_CTL 0x130730 /* Video H general purpose control */
+
+/* ***************************************************************************** */
+
+#define VID_DST_A_DMA_CTL 0x130040 /* Video A DMA control */
+#define VID_DST_B_DMA_CTL 0x130140 /* Video B DMA control */
+#define VID_DST_C_DMA_CTL 0x130240 /* Video C DMA control */
+#define VID_DST_D_DMA_CTL 0x130340 /* Video D DMA control */
+#define VID_DST_E_DMA_CTL 0x130440 /* Video E DMA control */
+#define VID_DST_F_DMA_CTL 0x130540 /* Video F DMA control */
+#define VID_DST_G_DMA_CTL 0x130640 /* Video G DMA control */
+#define VID_DST_H_DMA_CTL 0x130740 /* Video H DMA control */
#define FLD_VID_RISC_EN 0x00000010
#define FLD_VID_FIFO_EN 0x00000001
-//*****************************************************************************
-
-#define VID_DST_A_VIP_CTL 0x130080 // Video A VIP control
-#define VID_DST_B_VIP_CTL 0x130180 // Video B VIP control
-#define VID_DST_C_VIP_CTL 0x130280 // Video C VIP control
-#define VID_DST_D_VIP_CTL 0x130380 // Video D VIP control
-#define VID_DST_E_VIP_CTL 0x130480 // Video E VIP control
-#define VID_DST_F_VIP_CTL 0x130580 // Video F VIP control
-#define VID_DST_G_VIP_CTL 0x130680 // Video G VIP control
-#define VID_DST_H_VIP_CTL 0x130780 // Video H VIP control
-
-//*****************************************************************************
-
-#define VID_DST_A_PIX_FRMT 0x130084 // Video A Pixel format
-#define VID_DST_B_PIX_FRMT 0x130184 // Video B Pixel format
-#define VID_DST_C_PIX_FRMT 0x130284 // Video C Pixel format
-#define VID_DST_D_PIX_FRMT 0x130384 // Video D Pixel format
-#define VID_DST_E_PIX_FRMT 0x130484 // Video E Pixel format
-#define VID_DST_F_PIX_FRMT 0x130584 // Video F Pixel format
-#define VID_DST_G_PIX_FRMT 0x130684 // Video G Pixel format
-#define VID_DST_H_PIX_FRMT 0x130784 // Video H Pixel format
-
-//*****************************************************************************
-// Video Source Channels
-//*****************************************************************************
-
-#define VID_SRC_A_GPCNT_CTL 0x130804 // Video A general purpose control
-#define VID_SRC_B_GPCNT_CTL 0x130904 // Video B general purpose control
-#define VID_SRC_C_GPCNT_CTL 0x130A04 // Video C general purpose control
-#define VID_SRC_D_GPCNT_CTL 0x130B04 // Video D general purpose control
-#define VID_SRC_E_GPCNT_CTL 0x130C04 // Video E general purpose control
-#define VID_SRC_F_GPCNT_CTL 0x130D04 // Video F general purpose control
-#define VID_SRC_I_GPCNT_CTL 0x130E04 // Video I general purpose control
-#define VID_SRC_J_GPCNT_CTL 0x130F04 // Video J general purpose control
-
-//*****************************************************************************
-
-#define VID_SRC_A_GPCNT 0x130808 // Video A general purpose counter
-#define VID_SRC_B_GPCNT 0x130908 // Video B general purpose counter
-#define VID_SRC_C_GPCNT 0x130A08 // Video C general purpose counter
-#define VID_SRC_D_GPCNT 0x130B08 // Video D general purpose counter
-#define VID_SRC_E_GPCNT 0x130C08 // Video E general purpose counter
-#define VID_SRC_F_GPCNT 0x130D08 // Video F general purpose counter
-#define VID_SRC_I_GPCNT 0x130E08 // Video I general purpose counter
-#define VID_SRC_J_GPCNT 0x130F08 // Video J general purpose counter
-
-//*****************************************************************************
-
-#define VID_SRC_A_DMA_CTL 0x13080C // Video A DMA control
-#define VID_SRC_B_DMA_CTL 0x13090C // Video B DMA control
-#define VID_SRC_C_DMA_CTL 0x130A0C // Video C DMA control
-#define VID_SRC_D_DMA_CTL 0x130B0C // Video D DMA control
-#define VID_SRC_E_DMA_CTL 0x130C0C // Video E DMA control
-#define VID_SRC_F_DMA_CTL 0x130D0C // Video F DMA control
-#define VID_SRC_I_DMA_CTL 0x130E0C // Video I DMA control
-#define VID_SRC_J_DMA_CTL 0x130F0C // Video J DMA control
+/* ***************************************************************************** */
+
+#define VID_DST_A_VIP_CTL 0x130080 /* Video A VIP control */
+#define VID_DST_B_VIP_CTL 0x130180 /* Video B VIP control */
+#define VID_DST_C_VIP_CTL 0x130280 /* Video C VIP control */
+#define VID_DST_D_VIP_CTL 0x130380 /* Video D VIP control */
+#define VID_DST_E_VIP_CTL 0x130480 /* Video E VIP control */
+#define VID_DST_F_VIP_CTL 0x130580 /* Video F VIP control */
+#define VID_DST_G_VIP_CTL 0x130680 /* Video G VIP control */
+#define VID_DST_H_VIP_CTL 0x130780 /* Video H VIP control */
+
+/* ***************************************************************************** */
+
+#define VID_DST_A_PIX_FRMT 0x130084 /* Video A Pixel format */
+#define VID_DST_B_PIX_FRMT 0x130184 /* Video B Pixel format */
+#define VID_DST_C_PIX_FRMT 0x130284 /* Video C Pixel format */
+#define VID_DST_D_PIX_FRMT 0x130384 /* Video D Pixel format */
+#define VID_DST_E_PIX_FRMT 0x130484 /* Video E Pixel format */
+#define VID_DST_F_PIX_FRMT 0x130584 /* Video F Pixel format */
+#define VID_DST_G_PIX_FRMT 0x130684 /* Video G Pixel format */
+#define VID_DST_H_PIX_FRMT 0x130784 /* Video H Pixel format */
+
+/* ***************************************************************************** */
+/* Video Source Channels */
+/* ***************************************************************************** */
+
+#define VID_SRC_A_GPCNT_CTL 0x130804 /* Video A general purpose control */
+#define VID_SRC_B_GPCNT_CTL 0x130904 /* Video B general purpose control */
+#define VID_SRC_C_GPCNT_CTL 0x130A04 /* Video C general purpose control */
+#define VID_SRC_D_GPCNT_CTL 0x130B04 /* Video D general purpose control */
+#define VID_SRC_E_GPCNT_CTL 0x130C04 /* Video E general purpose control */
+#define VID_SRC_F_GPCNT_CTL 0x130D04 /* Video F general purpose control */
+#define VID_SRC_I_GPCNT_CTL 0x130E04 /* Video I general purpose control */
+#define VID_SRC_J_GPCNT_CTL 0x130F04 /* Video J general purpose control */
+
+/* ***************************************************************************** */
+
+#define VID_SRC_A_GPCNT 0x130808 /* Video A general purpose counter */
+#define VID_SRC_B_GPCNT 0x130908 /* Video B general purpose counter */
+#define VID_SRC_C_GPCNT 0x130A08 /* Video C general purpose counter */
+#define VID_SRC_D_GPCNT 0x130B08 /* Video D general purpose counter */
+#define VID_SRC_E_GPCNT 0x130C08 /* Video E general purpose counter */
+#define VID_SRC_F_GPCNT 0x130D08 /* Video F general purpose counter */
+#define VID_SRC_I_GPCNT 0x130E08 /* Video I general purpose counter */
+#define VID_SRC_J_GPCNT 0x130F08 /* Video J general purpose counter */
+
+/* ***************************************************************************** */
+
+#define VID_SRC_A_DMA_CTL 0x13080C /* Video A DMA control */
+#define VID_SRC_B_DMA_CTL 0x13090C /* Video B DMA control */
+#define VID_SRC_C_DMA_CTL 0x130A0C /* Video C DMA control */
+#define VID_SRC_D_DMA_CTL 0x130B0C /* Video D DMA control */
+#define VID_SRC_E_DMA_CTL 0x130C0C /* Video E DMA control */
+#define VID_SRC_F_DMA_CTL 0x130D0C /* Video F DMA control */
+#define VID_SRC_I_DMA_CTL 0x130E0C /* Video I DMA control */
+#define VID_SRC_J_DMA_CTL 0x130F0C /* Video J DMA control */
#define FLD_APB_RISC_EN 0x00000010
#define FLD_APB_FIFO_EN 0x00000001
-//*****************************************************************************
-
-#define VID_SRC_A_FMT_CTL 0x130810 // Video A format control
-#define VID_SRC_B_FMT_CTL 0x130910 // Video B format control
-#define VID_SRC_C_FMT_CTL 0x130A10 // Video C format control
-#define VID_SRC_D_FMT_CTL 0x130B10 // Video D format control
-#define VID_SRC_E_FMT_CTL 0x130C10 // Video E format control
-#define VID_SRC_F_FMT_CTL 0x130D10 // Video F format control
-#define VID_SRC_I_FMT_CTL 0x130E10 // Video I format control
-#define VID_SRC_J_FMT_CTL 0x130F10 // Video J format control
-
-//*****************************************************************************
-
-#define VID_SRC_A_ACTIVE_CTL1 0x130814 // Video A active control 1
-#define VID_SRC_B_ACTIVE_CTL1 0x130914 // Video B active control 1
-#define VID_SRC_C_ACTIVE_CTL1 0x130A14 // Video C active control 1
-#define VID_SRC_D_ACTIVE_CTL1 0x130B14 // Video D active control 1
-#define VID_SRC_E_ACTIVE_CTL1 0x130C14 // Video E active control 1
-#define VID_SRC_F_ACTIVE_CTL1 0x130D14 // Video F active control 1
-#define VID_SRC_I_ACTIVE_CTL1 0x130E14 // Video I active control 1
-#define VID_SRC_J_ACTIVE_CTL1 0x130F14 // Video J active control 1
-
-//*****************************************************************************
-
-#define VID_SRC_A_ACTIVE_CTL2 0x130818 // Video A active control 2
-#define VID_SRC_B_ACTIVE_CTL2 0x130918 // Video B active control 2
-#define VID_SRC_C_ACTIVE_CTL2 0x130A18 // Video C active control 2
-#define VID_SRC_D_ACTIVE_CTL2 0x130B18 // Video D active control 2
-#define VID_SRC_E_ACTIVE_CTL2 0x130C18 // Video E active control 2
-#define VID_SRC_F_ACTIVE_CTL2 0x130D18 // Video F active control 2
-#define VID_SRC_I_ACTIVE_CTL2 0x130E18 // Video I active control 2
-#define VID_SRC_J_ACTIVE_CTL2 0x130F18 // Video J active control 2
-
-//*****************************************************************************
-
-#define VID_SRC_A_CDT_SZ 0x13081C // Video A CDT size
-#define VID_SRC_B_CDT_SZ 0x13091C // Video B CDT size
-#define VID_SRC_C_CDT_SZ 0x130A1C // Video C CDT size
-#define VID_SRC_D_CDT_SZ 0x130B1C // Video D CDT size
-#define VID_SRC_E_CDT_SZ 0x130C1C // Video E CDT size
-#define VID_SRC_F_CDT_SZ 0x130D1C // Video F CDT size
-#define VID_SRC_I_CDT_SZ 0x130E1C // Video I CDT size
-#define VID_SRC_J_CDT_SZ 0x130F1C // Video J CDT size
-
-//*****************************************************************************
-// Audio I/F
-//*****************************************************************************
-#define AUD_DST_A_DMA 0x140000 // Audio Int A DMA data port
-#define AUD_SRC_A_DMA 0x140008 // Audio Int A DMA data port
-
-#define AUD_A_GPCNT 0x140010 // Audio Int A gp counter
+/* ***************************************************************************** */
+
+#define VID_SRC_A_FMT_CTL 0x130810 /* Video A format control */
+#define VID_SRC_B_FMT_CTL 0x130910 /* Video B format control */
+#define VID_SRC_C_FMT_CTL 0x130A10 /* Video C format control */
+#define VID_SRC_D_FMT_CTL 0x130B10 /* Video D format control */
+#define VID_SRC_E_FMT_CTL 0x130C10 /* Video E format control */
+#define VID_SRC_F_FMT_CTL 0x130D10 /* Video F format control */
+#define VID_SRC_I_FMT_CTL 0x130E10 /* Video I format control */
+#define VID_SRC_J_FMT_CTL 0x130F10 /* Video J format control */
+
+/* ***************************************************************************** */
+
+#define VID_SRC_A_ACTIVE_CTL1 0x130814 /* Video A active control 1 */
+#define VID_SRC_B_ACTIVE_CTL1 0x130914 /* Video B active control 1 */
+#define VID_SRC_C_ACTIVE_CTL1 0x130A14 /* Video C active control 1 */
+#define VID_SRC_D_ACTIVE_CTL1 0x130B14 /* Video D active control 1 */
+#define VID_SRC_E_ACTIVE_CTL1 0x130C14 /* Video E active control 1 */
+#define VID_SRC_F_ACTIVE_CTL1 0x130D14 /* Video F active control 1 */
+#define VID_SRC_I_ACTIVE_CTL1 0x130E14 /* Video I active control 1 */
+#define VID_SRC_J_ACTIVE_CTL1 0x130F14 /* Video J active control 1 */
+
+/* ***************************************************************************** */
+
+#define VID_SRC_A_ACTIVE_CTL2 0x130818 /* Video A active control 2 */
+#define VID_SRC_B_ACTIVE_CTL2 0x130918 /* Video B active control 2 */
+#define VID_SRC_C_ACTIVE_CTL2 0x130A18 /* Video C active control 2 */
+#define VID_SRC_D_ACTIVE_CTL2 0x130B18 /* Video D active control 2 */
+#define VID_SRC_E_ACTIVE_CTL2 0x130C18 /* Video E active control 2 */
+#define VID_SRC_F_ACTIVE_CTL2 0x130D18 /* Video F active control 2 */
+#define VID_SRC_I_ACTIVE_CTL2 0x130E18 /* Video I active control 2 */
+#define VID_SRC_J_ACTIVE_CTL2 0x130F18 /* Video J active control 2 */
+
+/* ***************************************************************************** */
+
+#define VID_SRC_A_CDT_SZ 0x13081C /* Video A CDT size */
+#define VID_SRC_B_CDT_SZ 0x13091C /* Video B CDT size */
+#define VID_SRC_C_CDT_SZ 0x130A1C /* Video C CDT size */
+#define VID_SRC_D_CDT_SZ 0x130B1C /* Video D CDT size */
+#define VID_SRC_E_CDT_SZ 0x130C1C /* Video E CDT size */
+#define VID_SRC_F_CDT_SZ 0x130D1C /* Video F CDT size */
+#define VID_SRC_I_CDT_SZ 0x130E1C /* Video I CDT size */
+#define VID_SRC_J_CDT_SZ 0x130F1C /* Video J CDT size */
+
+/* ***************************************************************************** */
+/* Audio I/F */
+/* ***************************************************************************** */
+#define AUD_DST_A_DMA 0x140000 /* Audio Int A DMA data port */
+#define AUD_SRC_A_DMA 0x140008 /* Audio Int A DMA data port */
+
+#define AUD_A_GPCNT 0x140010 /* Audio Int A gp counter */
#define FLD_AUD_A_GP_CNT 0x0000FFFF
-#define AUD_A_GPCNT_CTL 0x140014 // Audio Int A gp control
+#define AUD_A_GPCNT_CTL 0x140014 /* Audio Int A gp control */
-#define AUD_A_LNGTH 0x140018 // Audio Int A line length
+#define AUD_A_LNGTH 0x140018 /* Audio Int A line length */
-#define AUD_A_CFG 0x14001C // Audio Int A configuration
+#define AUD_A_CFG 0x14001C /* Audio Int A configuration */
-//*****************************************************************************
-#define AUD_DST_B_DMA 0x140100 // Audio Int B DMA data port
-#define AUD_SRC_B_DMA 0x140108 // Audio Int B DMA data port
+/* ***************************************************************************** */
+#define AUD_DST_B_DMA 0x140100 /* Audio Int B DMA data port */
+#define AUD_SRC_B_DMA 0x140108 /* Audio Int B DMA data port */
-#define AUD_B_GPCNT 0x140110 // Audio Int B gp counter
+#define AUD_B_GPCNT 0x140110 /* Audio Int B gp counter */
#define FLD_AUD_B_GP_CNT 0x0000FFFF
-#define AUD_B_GPCNT_CTL 0x140114 // Audio Int B gp control
+#define AUD_B_GPCNT_CTL 0x140114 /* Audio Int B gp control */
-#define AUD_B_LNGTH 0x140118 // Audio Int B line length
+#define AUD_B_LNGTH 0x140118 /* Audio Int B line length */
-#define AUD_B_CFG 0x14011C // Audio Int B configuration
+#define AUD_B_CFG 0x14011C /* Audio Int B configuration */
-//*****************************************************************************
-#define AUD_DST_C_DMA 0x140200 // Audio Int C DMA data port
-#define AUD_SRC_C_DMA 0x140208 // Audio Int C DMA data port
+/* ***************************************************************************** */
+#define AUD_DST_C_DMA 0x140200 /* Audio Int C DMA data port */
+#define AUD_SRC_C_DMA 0x140208 /* Audio Int C DMA data port */
-#define AUD_C_GPCNT 0x140210 // Audio Int C gp counter
+#define AUD_C_GPCNT 0x140210 /* Audio Int C gp counter */
#define FLD_AUD_C_GP_CNT 0x0000FFFF
-#define AUD_C_GPCNT_CTL 0x140214 // Audio Int C gp control
+#define AUD_C_GPCNT_CTL 0x140214 /* Audio Int C gp control */
-#define AUD_C_LNGTH 0x140218 // Audio Int C line length
+#define AUD_C_LNGTH 0x140218 /* Audio Int C line length */
-#define AUD_C_CFG 0x14021C // Audio Int C configuration
+#define AUD_C_CFG 0x14021C /* Audio Int C configuration */
-//*****************************************************************************
-#define AUD_DST_D_DMA 0x140300 // Audio Int D DMA data port
-#define AUD_SRC_D_DMA 0x140308 // Audio Int D DMA data port
+/* ***************************************************************************** */
+#define AUD_DST_D_DMA 0x140300 /* Audio Int D DMA data port */
+#define AUD_SRC_D_DMA 0x140308 /* Audio Int D DMA data port */
-#define AUD_D_GPCNT 0x140310 // Audio Int D gp counter
+#define AUD_D_GPCNT 0x140310 /* Audio Int D gp counter */
#define FLD_AUD_D_GP_CNT 0x0000FFFF
-#define AUD_D_GPCNT_CTL 0x140314 // Audio Int D gp control
+#define AUD_D_GPCNT_CTL 0x140314 /* Audio Int D gp control */
-#define AUD_D_LNGTH 0x140318 // Audio Int D line length
+#define AUD_D_LNGTH 0x140318 /* Audio Int D line length */
-#define AUD_D_CFG 0x14031C // Audio Int D configuration
+#define AUD_D_CFG 0x14031C /* Audio Int D configuration */
-//*****************************************************************************
-#define AUD_SRC_E_DMA 0x140400 // Audio Int E DMA data port
+/* ***************************************************************************** */
+#define AUD_SRC_E_DMA 0x140400 /* Audio Int E DMA data port */
-#define AUD_E_GPCNT 0x140410 // Audio Int E gp counter
+#define AUD_E_GPCNT 0x140410 /* Audio Int E gp counter */
#define FLD_AUD_E_GP_CNT 0x0000FFFF
-#define AUD_E_GPCNT_CTL 0x140414 // Audio Int E gp control
+#define AUD_E_GPCNT_CTL 0x140414 /* Audio Int E gp control */
-#define AUD_E_CFG 0x14041C // Audio Int E configuration
+#define AUD_E_CFG 0x14041C /* Audio Int E configuration */
-//*****************************************************************************
+/* ***************************************************************************** */
#define FLD_AUD_DST_LN_LNGTH 0x00000FFF
@@ -1361,8 +1361,8 @@
#define FLD_AUD_SRC_ENABLE 0x00010000
-//*****************************************************************************
-#define AUD_INT_DMA_CTL 0x140500 // Audio Int DMA control
+/* ***************************************************************************** */
+#define AUD_INT_DMA_CTL 0x140500 /* Audio Int DMA control */
#define FLD_AUD_SRC_E_RISC_EN 0x00008000
#define FLD_AUD_SRC_C_RISC_EN 0x00004000
@@ -1384,15 +1384,15 @@
#define FLD_AUD_DST_B_FIFO_EN 0x00000002
#define FLD_AUD_DST_A_FIFO_EN 0x00000001
-//*****************************************************************************
-//
-// Mobilygen Interface Registers
-//
-//*****************************************************************************
-// Mobilygen Interface A
-//*****************************************************************************
-#define MB_IF_A_DMA 0x150000 // MBIF A DMA data port
-#define MB_IF_A_GPCN 0x150008 // MBIF A GP counter
+/* ***************************************************************************** */
+/* */
+/* Mobilygen Interface Registers */
+/* */
+/* ***************************************************************************** */
+/* Mobilygen Interface A */
+/* ***************************************************************************** */
+#define MB_IF_A_DMA 0x150000 /* MBIF A DMA data port */
+#define MB_IF_A_GPCN 0x150008 /* MBIF A GP counter */
#define MB_IF_A_GPCN_CTRL 0x15000C
#define MB_IF_A_DMA_CTRL 0x150010
#define MB_IF_A_LENGTH 0x150014
@@ -1415,11 +1415,11 @@
#define MB_IF_A_DATA_STRUCT_D 0x150058
#define MB_IF_A_DATA_STRUCT_E 0x15005C
#define MB_IF_A_DATA_STRUCT_F 0x150060
-//*****************************************************************************
-// Mobilygen Interface B
-//*****************************************************************************
-#define MB_IF_B_DMA 0x160000 // MBIF A DMA data port
-#define MB_IF_B_GPCN 0x160008 // MBIF A GP counter
+/* ***************************************************************************** */
+/* Mobilygen Interface B */
+/* ***************************************************************************** */
+#define MB_IF_B_DMA 0x160000 /* MBIF A DMA data port */
+#define MB_IF_B_GPCN 0x160008 /* MBIF A GP counter */
#define MB_IF_B_GPCN_CTRL 0x16000C
#define MB_IF_B_DMA_CTRL 0x160010
#define MB_IF_B_LENGTH 0x160014
@@ -1443,14 +1443,14 @@
#define MB_IF_B_DATA_STRUCT_E 0x16005C
#define MB_IF_B_DATA_STRUCT_F 0x160060
-// MB_DMA_CTRL
+/* MB_DMA_CTRL */
#define FLD_MB_IF_RISC_EN 0x00000010
#define FLD_MB_IF_FIFO_EN 0x00000001
-// MB_LENGTH
+/* MB_LENGTH */
#define FLD_MB_IF_LN_LNGTH 0x00000FFF
-// MB_HCMD register
+/* MB_HCMD register */
#define FLD_MB_HCMD_H_GO 0x80000000
#define FLD_MB_HCMD_H_BUSY 0x40000000
#define FLD_MB_HCMD_H_DMA_HOLD 0x10000000
@@ -1461,118 +1461,118 @@
#define FLD_MB_HCMD_H_ADDR 0x00FF0000
#define FLD_MB_HCMD_H_DATA 0x0000FFFF
-//*****************************************************************************
-// I2C #1
-//*****************************************************************************
-#define I2C1_ADDR 0x180000 // I2C #1 address
-#define FLD_I2C_DADDR 0xfe000000 // RW [31:25] I2C Device Address
- // RO [24] reserved
-//*****************************************************************************
-#define FLD_I2C_SADDR 0x00FFFFFF // RW [23:0] I2C Sub-address
-
-//*****************************************************************************
-#define I2C1_WDATA 0x180004 // I2C #1 write data
-#define FLD_I2C_WDATA 0xFFFFFFFF // RW [31:0]
-
-//*****************************************************************************
-#define I2C1_CTRL 0x180008 // I2C #1 control
-#define FLD_I2C_PERIOD 0xFF000000 // RW [31:24]
-#define FLD_I2C_SCL_IN 0x00200000 // RW [21]
-#define FLD_I2C_SDA_IN 0x00100000 // RW [20]
- // RO [19:18] reserved
-#define FLD_I2C_SCL_OUT 0x00020000 // RW [17]
-#define FLD_I2C_SDA_OUT 0x00010000 // RW [16]
- // RO [15] reserved
-#define FLD_I2C_DATA_LEN 0x00007000 // RW [14:12]
-#define FLD_I2C_SADDR_INC 0x00000800 // RW [11]
- // RO [10:9] reserved
-#define FLD_I2C_SADDR_LEN 0x00000300 // RW [9:8]
- // RO [7:6] reserved
-#define FLD_I2C_SOFT 0x00000020 // RW [5]
-#define FLD_I2C_NOSTOP 0x00000010 // RW [4]
-#define FLD_I2C_EXTEND 0x00000008 // RW [3]
-#define FLD_I2C_SYNC 0x00000004 // RW [2]
-#define FLD_I2C_READ_SA 0x00000002 // RW [1]
-#define FLD_I2C_READ_WRN 0x00000001 // RW [0]
-
-//*****************************************************************************
-#define I2C1_RDATA 0x18000C // I2C #1 read data
-#define FLD_I2C_RDATA 0xFFFFFFFF // RO [31:0]
-
-//*****************************************************************************
-#define I2C1_STAT 0x180010 // I2C #1 status
-#define FLD_I2C_XFER_IN_PROG 0x00000002 // RO [1]
-#define FLD_I2C_RACK 0x00000001 // RO [0]
-
-//*****************************************************************************
-// I2C #2
-//*****************************************************************************
-#define I2C2_ADDR 0x190000 // I2C #2 address
-
-//*****************************************************************************
-#define I2C2_WDATA 0x190004 // I2C #2 write data
-
-//*****************************************************************************
-#define I2C2_CTRL 0x190008 // I2C #2 control
-
-//*****************************************************************************
-#define I2C2_RDATA 0x19000C // I2C #2 read data
-
-//*****************************************************************************
-#define I2C2_STAT 0x190010 // I2C #2 status
-
-//*****************************************************************************
-// I2C #3
-//*****************************************************************************
-#define I2C3_ADDR 0x1A0000 // I2C #3 address
-
-//*****************************************************************************
-#define I2C3_WDATA 0x1A0004 // I2C #3 write data
-
-//*****************************************************************************
-#define I2C3_CTRL 0x1A0008 // I2C #3 control
-
-//*****************************************************************************
-#define I2C3_RDATA 0x1A000C // I2C #3 read data
-
-//*****************************************************************************
-#define I2C3_STAT 0x1A0010 // I2C #3 status
-
-//*****************************************************************************
-// UART
-//*****************************************************************************
-#define UART_CTL 0x1B0000 // UART Control Register
-#define FLD_LOOP_BACK_EN (1 << 7) // RW field - default 0
-#define FLD_RX_TRG_SZ (3 << 2) // RW field - default 0
-#define FLD_RX_EN (1 << 1) // RW field - default 0
-#define FLD_TX_EN (1 << 0) // RW field - default 0
-
-//*****************************************************************************
-#define UART_BRD 0x1B0004 // UART Baud Rate Divisor
-#define FLD_BRD 0x0000FFFF // RW field - default 0x197
-
-//*****************************************************************************
-#define UART_DBUF 0x1B0008 // UART Tx/Rx Data BuFFer
-#define FLD_DB 0xFFFFFFFF // RW field - default 0
-
-//*****************************************************************************
-#define UART_ISR 0x1B000C // UART Interrupt Status
-#define FLD_RXD_TIMEOUT_EN (1 << 7) // RW field - default 0
-#define FLD_FRM_ERR_EN (1 << 6) // RW field - default 0
-#define FLD_RXD_RDY_EN (1 << 5) // RW field - default 0
-#define FLD_TXD_EMPTY_EN (1 << 4) // RW field - default 0
-#define FLD_RXD_OVERFLOW (1 << 3) // RW field - default 0
-#define FLD_FRM_ERR (1 << 2) // RW field - default 0
-#define FLD_RXD_RDY (1 << 1) // RW field - default 0
-#define FLD_TXD_EMPTY (1 << 0) // RW field - default 0
-
-//*****************************************************************************
-#define UART_CNT 0x1B0010 // UART Tx/Rx FIFO Byte Count
-#define FLD_TXD_CNT (0x1F << 8) // RW field - default 0
-#define FLD_RXD_CNT (0x1F << 0) // RW field - default 0
-
-//*****************************************************************************
-// Motion Detection
+/* ***************************************************************************** */
+/* I2C #1 */
+/* ***************************************************************************** */
+#define I2C1_ADDR 0x180000 /* I2C #1 address */
+#define FLD_I2C_DADDR 0xfe000000 /* RW [31:25] I2C Device Address */
+ /* RO [24] reserved */
+/* ***************************************************************************** */
+#define FLD_I2C_SADDR 0x00FFFFFF /* RW [23:0] I2C Sub-address */
+
+/* ***************************************************************************** */
+#define I2C1_WDATA 0x180004 /* I2C #1 write data */
+#define FLD_I2C_WDATA 0xFFFFFFFF /* RW [31:0] */
+
+/* ***************************************************************************** */
+#define I2C1_CTRL 0x180008 /* I2C #1 control */
+#define FLD_I2C_PERIOD 0xFF000000 /* RW [31:24] */
+#define FLD_I2C_SCL_IN 0x00200000 /* RW [21] */
+#define FLD_I2C_SDA_IN 0x00100000 /* RW [20] */
+ /* RO [19:18] reserved */
+#define FLD_I2C_SCL_OUT 0x00020000 /* RW [17] */
+#define FLD_I2C_SDA_OUT 0x00010000 /* RW [16] */
+ /* RO [15] reserved */
+#define FLD_I2C_DATA_LEN 0x00007000 /* RW [14:12] */
+#define FLD_I2C_SADDR_INC 0x00000800 /* RW [11] */
+ /* RO [10:9] reserved */
+#define FLD_I2C_SADDR_LEN 0x00000300 /* RW [9:8] */
+ /* RO [7:6] reserved */
+#define FLD_I2C_SOFT 0x00000020 /* RW [5] */
+#define FLD_I2C_NOSTOP 0x00000010 /* RW [4] */
+#define FLD_I2C_EXTEND 0x00000008 /* RW [3] */
+#define FLD_I2C_SYNC 0x00000004 /* RW [2] */
+#define FLD_I2C_READ_SA 0x00000002 /* RW [1] */
+#define FLD_I2C_READ_WRN 0x00000001 /* RW [0] */
+
+/* ***************************************************************************** */
+#define I2C1_RDATA 0x18000C /* I2C #1 read data */
+#define FLD_I2C_RDATA 0xFFFFFFFF /* RO [31:0] */
+
+/* ***************************************************************************** */
+#define I2C1_STAT 0x180010 /* I2C #1 status */
+#define FLD_I2C_XFER_IN_PROG 0x00000002 /* RO [1] */
+#define FLD_I2C_RACK 0x00000001 /* RO [0] */
+
+/* ***************************************************************************** */
+/* I2C #2 */
+/* ***************************************************************************** */
+#define I2C2_ADDR 0x190000 /* I2C #2 address */
+
+/* ***************************************************************************** */
+#define I2C2_WDATA 0x190004 /* I2C #2 write data */
+
+/* ***************************************************************************** */
+#define I2C2_CTRL 0x190008 /* I2C #2 control */
+
+/* ***************************************************************************** */
+#define I2C2_RDATA 0x19000C /* I2C #2 read data */
+
+/* ***************************************************************************** */
+#define I2C2_STAT 0x190010 /* I2C #2 status */
+
+/* ***************************************************************************** */
+/* I2C #3 */
+/* ***************************************************************************** */
+#define I2C3_ADDR 0x1A0000 /* I2C #3 address */
+
+/* ***************************************************************************** */
+#define I2C3_WDATA 0x1A0004 /* I2C #3 write data */
+
+/* ***************************************************************************** */
+#define I2C3_CTRL 0x1A0008 /* I2C #3 control */
+
+/* ***************************************************************************** */
+#define I2C3_RDATA 0x1A000C /* I2C #3 read data */
+
+/* ***************************************************************************** */
+#define I2C3_STAT 0x1A0010 /* I2C #3 status */
+
+/* ***************************************************************************** */
+/* UART */
+/* ***************************************************************************** */
+#define UART_CTL 0x1B0000 /* UART Control Register */
+#define FLD_LOOP_BACK_EN (1 << 7) /* RW field - default 0 */
+#define FLD_RX_TRG_SZ (3 << 2) /* RW field - default 0 */
+#define FLD_RX_EN (1 << 1) /* RW field - default 0 */
+#define FLD_TX_EN (1 << 0) /* RW field - default 0 */
+
+/* ***************************************************************************** */
+#define UART_BRD 0x1B0004 /* UART Baud Rate Divisor */
+#define FLD_BRD 0x0000FFFF /* RW field - default 0x197 */
+
+/* ***************************************************************************** */
+#define UART_DBUF 0x1B0008 /* UART Tx/Rx Data BuFFer */
+#define FLD_DB 0xFFFFFFFF /* RW field - default 0 */
+
+/* ***************************************************************************** */
+#define UART_ISR 0x1B000C /* UART Interrupt Status */
+#define FLD_RXD_TIMEOUT_EN (1 << 7) /* RW field - default 0 */
+#define FLD_FRM_ERR_EN (1 << 6) /* RW field - default 0 */
+#define FLD_RXD_RDY_EN (1 << 5) /* RW field - default 0 */
+#define FLD_TXD_EMPTY_EN (1 << 4) /* RW field - default 0 */
+#define FLD_RXD_OVERFLOW (1 << 3) /* RW field - default 0 */
+#define FLD_FRM_ERR (1 << 2) /* RW field - default 0 */
+#define FLD_RXD_RDY (1 << 1) /* RW field - default 0 */
+#define FLD_TXD_EMPTY (1 << 0) /* RW field - default 0 */
+
+/* ***************************************************************************** */
+#define UART_CNT 0x1B0010 /* UART Tx/Rx FIFO Byte Count */
+#define FLD_TXD_CNT (0x1F << 8) /* RW field - default 0 */
+#define FLD_RXD_CNT (0x1F << 0) /* RW field - default 0 */
+
+/* ***************************************************************************** */
+/* Motion Detection */
#define MD_CH0_GRID_BLOCK_YCNT 0x170014
#define MD_CH1_GRID_BLOCK_YCNT 0x170094
#define MD_CH2_GRID_BLOCK_YCNT 0x170114
@@ -1589,4 +1589,4 @@
#define PIXEL_ENGINE_VIP1 0
#define PIXEL_ENGINE_VIP2 1
-#endif //Athena_REGISTERS
+#endif /* Athena_REGISTERS */
diff --git a/drivers/staging/cx25821/cx25821-sram.h b/drivers/staging/cx25821/cx25821-sram.h
index bd677ee2299..5f05d153bc4 100644
--- a/drivers/staging/cx25821/cx25821-sram.h
+++ b/drivers/staging/cx25821/cx25821-sram.h
@@ -23,34 +23,34 @@
#ifndef __ATHENA_SRAM_H__
#define __ATHENA_SRAM_H__
-//#define RX_SRAM_START_SIZE = 0; // Start of reserved SRAM
-#define VID_CMDS_SIZE 80 // Video CMDS size in bytes
-#define AUDIO_CMDS_SIZE 80 // AUDIO CMDS size in bytes
-#define MBIF_CMDS_SIZE 80 // MBIF CMDS size in bytes
+/* #define RX_SRAM_START_SIZE = 0; // Start of reserved SRAM */
+#define VID_CMDS_SIZE 80 /* Video CMDS size in bytes */
+#define AUDIO_CMDS_SIZE 80 /* AUDIO CMDS size in bytes */
+#define MBIF_CMDS_SIZE 80 /* MBIF CMDS size in bytes */
-//#define RX_SRAM_POOL_START_SIZE = 0; // Start of useable RX SRAM for buffers
-#define VID_IQ_SIZE 64 // VID instruction queue size in bytes
+/* #define RX_SRAM_POOL_START_SIZE = 0; // Start of useable RX SRAM for buffers */
+#define VID_IQ_SIZE 64 /* VID instruction queue size in bytes */
#define MBIF_IQ_SIZE 64
-#define AUDIO_IQ_SIZE 64 // AUD instruction queue size in bytes
+#define AUDIO_IQ_SIZE 64 /* AUD instruction queue size in bytes */
-#define VID_CDT_SIZE 64 // VID cluster descriptor table size in bytes
-#define MBIF_CDT_SIZE 64 // MBIF/HBI cluster descriptor table size in bytes
-#define AUDIO_CDT_SIZE 48 // AUD cluster descriptor table size in bytes
+#define VID_CDT_SIZE 64 /* VID cluster descriptor table size in bytes */
+#define MBIF_CDT_SIZE 64 /* MBIF/HBI cluster descriptor table size in bytes */
+#define AUDIO_CDT_SIZE 48 /* AUD cluster descriptor table size in bytes */
-//#define RX_SRAM_POOL_FREE_SIZE = 16; // Start of available RX SRAM
-//#define RX_SRAM_END_SIZE = 0; // End of RX SRAM
+/* #define RX_SRAM_POOL_FREE_SIZE = 16; // Start of available RX SRAM */
+/* #define RX_SRAM_END_SIZE = 0; // End of RX SRAM */
-//#define TX_SRAM_POOL_START_SIZE = 0; // Start of transmit pool SRAM
-//#define MSI_DATA_SIZE = 64; // Reserved (MSI Data, RISC working stora
+/* #define TX_SRAM_POOL_START_SIZE = 0; // Start of transmit pool SRAM */
+/* #define MSI_DATA_SIZE = 64; // Reserved (MSI Data, RISC working stora */
-#define VID_CLUSTER_SIZE 1440 // VID cluster data line
-#define AUDIO_CLUSTER_SIZE 128 // AUDIO cluster data line
-#define MBIF_CLUSTER_SIZE 1440 // MBIF/HBI cluster data line
+#define VID_CLUSTER_SIZE 1440 /* VID cluster data line */
+#define AUDIO_CLUSTER_SIZE 128 /* AUDIO cluster data line */
+#define MBIF_CLUSTER_SIZE 1440 /* MBIF/HBI cluster data line */
-//#define TX_SRAM_POOL_FREE_SIZE = 704; // Start of available TX SRAM
-//#define TX_SRAM_END_SIZE = 0; // End of TX SRAM
+/* #define TX_SRAM_POOL_FREE_SIZE = 704; // Start of available TX SRAM */
+/* #define TX_SRAM_END_SIZE = 0; // End of TX SRAM */
-// Receive SRAM
+/* Receive SRAM */
#define RX_SRAM_START 0x10000
#define VID_A_DOWN_CMDS 0x10000
#define VID_B_DOWN_CMDS 0x10050
@@ -78,9 +78,9 @@
#define AUD_E_UP_CMDS 0x10730
#define MBIF_A_DOWN_CMDS 0x10780
#define MBIF_B_DOWN_CMDS 0x107D0
-#define DMA_SCRATCH_PAD 0x10820 // Scratch pad area from 0x10820 to 0x10B40
+#define DMA_SCRATCH_PAD 0x10820 /* Scratch pad area from 0x10820 to 0x10B40 */
-//#define RX_SRAM_POOL_START = 0x105B0;
+/* #define RX_SRAM_POOL_START = 0x105B0; */
#define VID_A_IQ 0x11000
#define VID_B_IQ 0x11040
@@ -118,7 +118,7 @@
#define MBIF_A_CDT 0x10C00
#define MBIF_B_CDT 0x10CC0
-// Cluster Buffer for RX
+/* Cluster Buffer for RX */
#define VID_A_UP_CLUSTER_1 0x11400
#define VID_A_UP_CLUSTER_2 0x119A0
#define VID_A_UP_CLUSTER_3 0x11F40
@@ -178,9 +178,9 @@
#define RX_SRAM_POOL_FREE 0x1CE00
#define RX_SRAM_END 0x1D000
-// Free Receive SRAM 144 Bytes
+/* Free Receive SRAM 144 Bytes */
-// Transmit SRAM
+/* Transmit SRAM */
#define TX_SRAM_POOL_START 0x00000
#define VID_A_DOWN_CLUSTER_1 0x00040
diff --git a/drivers/staging/cx25821/cx25821-video-upstream-ch2.c b/drivers/staging/cx25821/cx25821-video-upstream-ch2.c
index 343df6619fe..d12dbb572e8 100644
--- a/drivers/staging/cx25821/cx25821-video-upstream-ch2.c
+++ b/drivers/staging/cx25821/cx25821-video-upstream-ch2.c
@@ -84,7 +84,7 @@ static __le32 *cx25821_risc_field_upstream_ch2(struct cx25821_dev *dev,
{
unsigned int line, i;
struct sram_channel *sram_ch =
- &dev->sram_channels[dev->_channel2_upstream_select];
+ dev->channels[dev->_channel2_upstream_select].sram_channels;
int dist_betwn_starts = bpl * 2;
/* sync instruction */
@@ -110,8 +110,11 @@ static __le32 *cx25821_risc_field_upstream_ch2(struct cx25821_dev *dev,
offset += dist_betwn_starts;
}
- // check if we need to enable the FIFO after the first 4 lines
- // For the upstream video channel, the risc engine will enable the FIFO.
+ /*
+ check if we need to enable the FIFO after the first 4 lines
+ For the upstream video channel, the risc engine will enable
+ the FIFO.
+ */
if (fifo_enable && line == 3) {
*(rp++) = RISC_WRITECR;
*(rp++) = sram_ch->dma_ctl;
@@ -130,7 +133,7 @@ int cx25821_risc_buffer_upstream_ch2(struct cx25821_dev *dev,
{
__le32 *rp;
int fifo_enable = 0;
- int singlefield_lines = lines >> 1; //get line count for single field
+ int singlefield_lines = lines >> 1; /*get line count for single field */
int odd_num_lines = singlefield_lines;
int frame = 0;
int frame_size = 0;
@@ -174,7 +177,7 @@ int cx25821_risc_buffer_upstream_ch2(struct cx25821_dev *dev,
fifo_enable = FIFO_DISABLE;
- //Even field
+ /* Even field */
rp = cx25821_risc_field_upstream_ch2(dev, rp,
dev->
_data_buf_phys_addr_ch2 +
@@ -192,7 +195,10 @@ int cx25821_risc_buffer_upstream_ch2(struct cx25821_dev *dev,
risc_phys_jump_addr = dev->_dma_phys_start_addr_ch2;
}
- // Loop to 2ndFrameRISC or to Start of Risc program & generate IRQ
+ /*
+ Loop to 2ndFrameRISC or to Start of
+ Risc program & generate IRQ
+ */
*(rp++) = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | risc_flag);
*(rp++) = cpu_to_le32(risc_phys_jump_addr);
*(rp++) = cpu_to_le32(0);
@@ -204,7 +210,7 @@ int cx25821_risc_buffer_upstream_ch2(struct cx25821_dev *dev,
void cx25821_stop_upstream_video_ch2(struct cx25821_dev *dev)
{
struct sram_channel *sram_ch =
- &dev->sram_channels[VID_UPSTREAM_SRAM_CHANNEL_J];
+ dev->channels[VID_UPSTREAM_SRAM_CHANNEL_J].sram_channels;
u32 tmp = 0;
if (!dev->_is_running_ch2) {
@@ -212,15 +218,15 @@ void cx25821_stop_upstream_video_ch2(struct cx25821_dev *dev)
("cx25821: No video file is currently running so return!\n");
return;
}
- //Disable RISC interrupts
+ /* Disable RISC interrupts */
tmp = cx_read(sram_ch->int_msk);
cx_write(sram_ch->int_msk, tmp & ~_intr_msk);
- //Turn OFF risc and fifo
+ /* Turn OFF risc and fifo */
tmp = cx_read(sram_ch->dma_ctl);
cx_write(sram_ch->dma_ctl, tmp & ~(FLD_VID_FIFO_EN | FLD_VID_RISC_EN));
- //Clear data buffer memory
+ /* Clear data buffer memory */
if (dev->_data_buf_virt_addr_ch2)
memset(dev->_data_buf_virt_addr_ch2, 0,
dev->_data_buf_size_ch2);
@@ -371,8 +377,8 @@ static void cx25821_vidups_handler_ch2(struct work_struct *work)
}
cx25821_get_frame_ch2(dev,
- &dev->sram_channels[dev->
- _channel2_upstream_select]);
+ dev->channels[dev->
+ _channel2_upstream_select].sram_channels);
}
int cx25821_openfile_ch2(struct cx25821_dev *dev, struct sram_channel *sram_ch)
@@ -488,7 +494,7 @@ static int cx25821_upstream_buffer_prepare_ch2(struct cx25821_dev *dev,
return -ENOMEM;
}
- //Iniitize at this address until n bytes to 0
+ /* Iniitize at this address until n bytes to 0 */
memset(dev->_dma_virt_addr_ch2, 0, dev->_risc_size_ch2);
if (dev->_data_buf_virt_addr_ch2 != NULL) {
@@ -496,7 +502,7 @@ static int cx25821_upstream_buffer_prepare_ch2(struct cx25821_dev *dev,
dev->_data_buf_virt_addr_ch2,
dev->_data_buf_phys_addr_ch2);
}
- //For Video Data buffer allocation
+ /* For Video Data buffer allocation */
dev->_data_buf_virt_addr_ch2 =
pci_alloc_consistent(dev->pci, dev->upstream_databuf_size_ch2,
&data_dma_addr);
@@ -509,14 +515,14 @@ static int cx25821_upstream_buffer_prepare_ch2(struct cx25821_dev *dev,
return -ENOMEM;
}
- //Initialize at this address until n bytes to 0
+ /* Initialize at this address until n bytes to 0 */
memset(dev->_data_buf_virt_addr_ch2, 0, dev->_data_buf_size_ch2);
ret = cx25821_openfile_ch2(dev, sram_ch);
if (ret < 0)
return ret;
- //Creating RISC programs
+ /* Creating RISC programs */
ret =
cx25821_risc_buffer_upstream_ch2(dev, dev->pci, 0, bpl,
dev->_lines_count_ch2);
@@ -536,7 +542,7 @@ int cx25821_video_upstream_irq_ch2(struct cx25821_dev *dev, int chan_num,
u32 status)
{
u32 int_msk_tmp;
- struct sram_channel *channel = &dev->sram_channels[chan_num];
+ struct sram_channel *channel = dev->channels[chan_num].sram_channels;
int singlefield_lines = NTSC_FIELD_HEIGHT;
int line_size_in_bytes = Y422_LINE_SZ;
int odd_risc_prog_size = 0;
@@ -544,10 +550,13 @@ int cx25821_video_upstream_irq_ch2(struct cx25821_dev *dev, int chan_num,
__le32 *rp;
if (status & FLD_VID_SRC_RISC1) {
- // We should only process one program per call
+ /* We should only process one program per call */
u32 prog_cnt = cx_read(channel->gpcnt);
- //Since we've identified our IRQ, clear our bits from the interrupt mask and interrupt status registers
+ /*
+ Since we've identified our IRQ, clear our bits from the
+ interrupt mask and interrupt status registers
+ */
int_msk_tmp = cx_read(channel->int_msk);
cx_write(channel->int_msk, int_msk_tmp & ~_intr_msk);
cx_write(channel->int_stat, _intr_msk);
@@ -588,7 +597,7 @@ int cx25821_video_upstream_irq_ch2(struct cx25821_dev *dev, int chan_num,
FIFO_DISABLE,
ODD_FIELD);
- // Jump to Even Risc program of 1st Frame
+ /* Jump to Even Risc program of 1st Frame */
*(rp++) = cpu_to_le32(RISC_JUMP);
*(rp++) = cpu_to_le32(risc_phys_jump_addr);
*(rp++) = cpu_to_le32(0);
@@ -603,7 +612,7 @@ int cx25821_video_upstream_irq_ch2(struct cx25821_dev *dev, int chan_num,
dev->_frame_count_ch2);
return -1;
}
- //ElSE, set the interrupt mask register, re-enable irq.
+ /* ElSE, set the interrupt mask register, re-enable irq. */
int_msk_tmp = cx_read(channel->int_msk);
cx_write(channel->int_msk, int_msk_tmp |= _intr_msk);
@@ -623,12 +632,12 @@ static irqreturn_t cx25821_upstream_irq_ch2(int irq, void *dev_id)
channel_num = VID_UPSTREAM_SRAM_CHANNEL_J;
- sram_ch = &dev->sram_channels[channel_num];
+ sram_ch = dev->channels[channel_num].sram_channels;
msk_stat = cx_read(sram_ch->int_mstat);
vid_status = cx_read(sram_ch->int_stat);
- // Only deal with our interrupt
+ /* Only deal with our interrupt */
if (vid_status) {
handled =
cx25821_video_upstream_irq_ch2(dev, channel_num,
@@ -658,7 +667,10 @@ static void cx25821_set_pixelengine_ch2(struct cx25821_dev *dev,
value |= dev->_isNTSC_ch2 ? 0 : 0x10;
cx_write(ch->vid_fmt_ctl, value);
- // set number of active pixels in each line. Default is 720 pixels in both NTSC and PAL format
+ /*
+ set number of active pixels in each line. Default is 720
+ pixels in both NTSC and PAL format
+ */
cx_write(ch->vid_active_ctl1, width);
num_lines = (height / 2) & 0x3FF;
@@ -670,7 +682,7 @@ static void cx25821_set_pixelengine_ch2(struct cx25821_dev *dev,
value = (num_lines << 16) | odd_num_lines;
- // set number of active lines in field 0 (top) and field 1 (bottom)
+ /* set number of active lines in field 0 (top) and field 1 (bottom) */
cx_write(ch->vid_active_ctl2, value);
cx_write(ch->vid_cdt_size, VID_CDT_SIZE >> 3);
@@ -682,21 +694,27 @@ int cx25821_start_video_dma_upstream_ch2(struct cx25821_dev *dev,
u32 tmp = 0;
int err = 0;
- // 656/VIP SRC Upstream Channel I & J and 7 - Host Bus Interface for channel A-C
+ /*
+ 656/VIP SRC Upstream Channel I & J and 7 - Host Bus Interface
+ for channel A-C
+ */
tmp = cx_read(VID_CH_MODE_SEL);
cx_write(VID_CH_MODE_SEL, tmp | 0x1B0001FF);
- // Set the physical start address of the RISC program in the initial program counter(IPC) member of the cmds.
+ /*
+ Set the physical start address of the RISC program in the initial
+ program counter(IPC) member of the cmds.
+ */
cx_write(sram_ch->cmds_start + 0, dev->_dma_phys_addr_ch2);
- cx_write(sram_ch->cmds_start + 4, 0); /* Risc IPC High 64 bits 63-32 */
+ cx_write(sram_ch->cmds_start + 4, 0); /* Risc IPC High 64 bits 63-32 */
/* reset counter */
cx_write(sram_ch->gpcnt_ctl, 3);
- // Clear our bits from the interrupt status register.
+ /* Clear our bits from the interrupt status register. */
cx_write(sram_ch->int_stat, _intr_msk);
- //Set the interrupt mask register, enable irq.
+ /* Set the interrupt mask register, enable irq. */
cx_set(PCI_INT_MSK, cx_read(PCI_INT_MSK) | (1 << sram_ch->irq_bit));
tmp = cx_read(sram_ch->int_msk);
cx_write(sram_ch->int_msk, tmp |= _intr_msk);
@@ -709,7 +727,7 @@ int cx25821_start_video_dma_upstream_ch2(struct cx25821_dev *dev,
dev->pci->irq);
goto fail_irq;
}
- // Start the DMA engine
+ /* Start the DMA engine */
tmp = cx_read(sram_ch->dma_ctl);
cx_set(sram_ch->dma_ctl, tmp | FLD_VID_RISC_EN);
@@ -740,7 +758,7 @@ int cx25821_vidupstream_init_ch2(struct cx25821_dev *dev, int channel_select,
}
dev->_channel2_upstream_select = channel_select;
- sram_ch = &dev->sram_channels[channel_select];
+ sram_ch = dev->channels[channel_select].sram_channels;
INIT_WORK(&dev->_irq_work_entry_ch2, cx25821_vidups_handler_ch2);
dev->_irq_queues_ch2 =
@@ -751,7 +769,10 @@ int cx25821_vidupstream_init_ch2(struct cx25821_dev *dev, int channel_select,
("cx25821: create_singlethread_workqueue() for Video FAILED!\n");
return -ENOMEM;
}
- // 656/VIP SRC Upstream Channel I & J and 7 - Host Bus Interface for channel A-C
+ /*
+ 656/VIP SRC Upstream Channel I & J and 7 -
+ Host Bus Interface for channel A-C
+ */
tmp = cx_read(VID_CH_MODE_SEL);
cx_write(VID_CH_MODE_SEL, tmp | 0x1B0001FF);
@@ -787,7 +808,7 @@ int cx25821_vidupstream_init_ch2(struct cx25821_dev *dev, int channel_select,
str_length + 1);
}
- //Default if filename is empty string
+ /* Default if filename is empty string */
if (strcmp(dev->input_filename_ch2, "") == 0) {
if (dev->_isNTSC_ch2) {
dev->_filename_ch2 =
@@ -812,7 +833,7 @@ int cx25821_vidupstream_init_ch2(struct cx25821_dev *dev, int channel_select,
dev->upstream_riscbuf_size_ch2 = risc_buffer_size * 2;
dev->upstream_databuf_size_ch2 = data_frame_size * 2;
- //Allocating buffers and prepare RISC program
+ /* Allocating buffers and prepare RISC program */
retval =
cx25821_upstream_buffer_prepare_ch2(dev, sram_ch,
dev->_line_size_ch2);
diff --git a/drivers/staging/cx25821/cx25821-video-upstream-ch2.h b/drivers/staging/cx25821/cx25821-video-upstream-ch2.h
index 73feea114c1..62340636c91 100644
--- a/drivers/staging/cx25821/cx25821-video-upstream-ch2.h
+++ b/drivers/staging/cx25821/cx25821-video-upstream-ch2.h
@@ -37,7 +37,7 @@
#define RESET_STATUS -1
#define NUM_NO_OPS 5
-// PAL and NTSC line sizes and number of lines.
+/* PAL and NTSC line sizes and number of lines. */
#define WIDTH_D1 720
#define NTSC_LINES_PER_FRAME 480
#define PAL_LINES_PER_FRAME 576
diff --git a/drivers/staging/cx25821/cx25821-video-upstream.c b/drivers/staging/cx25821/cx25821-video-upstream.c
index 7a3dad91eba..756a820a76c 100644
--- a/drivers/staging/cx25821/cx25821-video-upstream.c
+++ b/drivers/staging/cx25821/cx25821-video-upstream.c
@@ -134,7 +134,7 @@ static __le32 *cx25821_risc_field_upstream(struct cx25821_dev *dev, __le32 * rp,
{
unsigned int line, i;
struct sram_channel *sram_ch =
- &dev->sram_channels[dev->_channel_upstream_select];
+ dev->channels[dev->_channel_upstream_select].sram_channels;
int dist_betwn_starts = bpl * 2;
/* sync instruction */
@@ -253,7 +253,7 @@ int cx25821_risc_buffer_upstream(struct cx25821_dev *dev,
void cx25821_stop_upstream_video_ch1(struct cx25821_dev *dev)
{
struct sram_channel *sram_ch =
- &dev->sram_channels[VID_UPSTREAM_SRAM_CHANNEL_I];
+ dev->channels[VID_UPSTREAM_SRAM_CHANNEL_I].sram_channels;
u32 tmp = 0;
if (!dev->_is_running) {
@@ -346,20 +346,23 @@ int cx25821_get_frame(struct cx25821_dev *dev, struct sram_channel *sram_ch)
if (IS_ERR(myfile)) {
const int open_errno = -PTR_ERR(myfile);
- printk(KERN_ERR "%s(): ERROR opening file(%s) with errno = %d!\n",
- __func__, dev->_filename, open_errno);
+ printk(KERN_ERR
+ "%s(): ERROR opening file(%s) with errno = %d!\n",
+ __func__, dev->_filename, open_errno);
return PTR_ERR(myfile);
} else {
if (!(myfile->f_op)) {
- printk(KERN_ERR "%s: File has no file operations registered!",
- __func__);
+ printk(KERN_ERR
+ "%s: File has no file operations registered!",
+ __func__);
filp_close(myfile, NULL);
return -EIO;
}
if (!myfile->f_op->read) {
- printk(KERN_ERR "%s: File has no READ operations registered!",
- __func__);
+ printk(KERN_ERR
+ "%s: File has no READ operations registered!",
+ __func__);
filp_close(myfile, NULL);
return -EIO;
}
@@ -386,7 +389,8 @@ int cx25821_get_frame(struct cx25821_dev *dev, struct sram_channel *sram_ch)
if (vfs_read_retval < line_size) {
printk(KERN_INFO
- "Done: exit %s() since no more bytes to read from Video file.\n",
+ "Done: exit %s() since no more bytes to \
+ read from Video file.\n",
__func__);
break;
}
@@ -411,13 +415,15 @@ static void cx25821_vidups_handler(struct work_struct *work)
container_of(work, struct cx25821_dev, _irq_work_entry);
if (!dev) {
- printk(KERN_ERR "ERROR %s(): since container_of(work_struct) FAILED!\n",
- __func__);
+ printk(KERN_ERR
+ "ERROR %s(): since container_of(work_struct) FAILED!\n",
+ __func__);
return;
}
cx25821_get_frame(dev,
- &dev->sram_channels[dev->_channel_upstream_select]);
+ dev->channels[dev->_channel_upstream_select].
+ sram_channels);
}
int cx25821_openfile(struct cx25821_dev *dev, struct sram_channel *sram_ch)
@@ -437,20 +443,22 @@ int cx25821_openfile(struct cx25821_dev *dev, struct sram_channel *sram_ch)
if (IS_ERR(myfile)) {
const int open_errno = -PTR_ERR(myfile);
- printk(KERN_ERR "%s(): ERROR opening file(%s) with errno = %d!\n",
+ printk(KERN_ERR "%s(): ERROR opening file(%s) with errno = %d!\n",
__func__, dev->_filename, open_errno);
return PTR_ERR(myfile);
} else {
if (!(myfile->f_op)) {
- printk(KERN_ERR "%s: File has no file operations registered!",
- __func__);
+ printk(KERN_ERR
+ "%s: File has no file operations registered!",
+ __func__);
filp_close(myfile, NULL);
return -EIO;
}
if (!myfile->f_op->read) {
- printk
- (KERN_ERR "%s: File has no READ operations registered! Returning.",
+ printk(KERN_ERR
+ "%s: File has no READ operations registered! \
+ Returning.",
__func__);
filp_close(myfile, NULL);
return -EIO;
@@ -480,7 +488,8 @@ int cx25821_openfile(struct cx25821_dev *dev, struct sram_channel *sram_ch)
if (vfs_read_retval < line_size) {
printk(KERN_INFO
- "Done: exit %s() since no more bytes to read from Video file.\n",
+ "Done: exit %s() since no more \
+ bytes to read from Video file.\n",
__func__);
break;
}
@@ -526,7 +535,8 @@ int cx25821_upstream_buffer_prepare(struct cx25821_dev *dev,
if (!dev->_dma_virt_addr) {
printk
- (KERN_ERR "cx25821: FAILED to allocate memory for Risc buffer! Returning.\n");
+ (KERN_ERR "cx25821: FAILED to allocate memory for Risc \
+ buffer! Returning.\n");
return -ENOMEM;
}
@@ -547,7 +557,8 @@ int cx25821_upstream_buffer_prepare(struct cx25821_dev *dev,
if (!dev->_data_buf_virt_addr) {
printk
- (KERN_ERR "cx25821: FAILED to allocate memory for data buffer! Returning.\n");
+ (KERN_ERR "cx25821: FAILED to allocate memory for data \
+ buffer! Returning.\n");
return -ENOMEM;
}
@@ -578,7 +589,7 @@ int cx25821_video_upstream_irq(struct cx25821_dev *dev, int chan_num,
u32 status)
{
u32 int_msk_tmp;
- struct sram_channel *channel = &dev->sram_channels[chan_num];
+ struct sram_channel *channel = dev->channels[chan_num].sram_channels;
int singlefield_lines = NTSC_FIELD_HEIGHT;
int line_size_in_bytes = Y422_LINE_SZ;
int odd_risc_prog_size = 0;
@@ -642,16 +653,16 @@ int cx25821_video_upstream_irq(struct cx25821_dev *dev, int chan_num,
} else {
if (status & FLD_VID_SRC_UF)
printk
- (KERN_ERR "%s: Video Received Underflow Error Interrupt!\n",
- __func__);
+ (KERN_ERR "%s: Video Received Underflow Error \
+ Interrupt!\n", __func__);
if (status & FLD_VID_SRC_SYNC)
- printk(KERN_ERR "%s: Video Received Sync Error Interrupt!\n",
- __func__);
+ printk(KERN_ERR "%s: Video Received Sync Error \
+ Interrupt!\n", __func__);
if (status & FLD_VID_SRC_OPC_ERR)
- printk(KERN_ERR "%s: Video Received OpCode Error Interrupt!\n",
- __func__);
+ printk(KERN_ERR "%s: Video Received OpCode Error \
+ Interrupt!\n", __func__);
}
if (dev->_file_status == END_OF_FILE) {
@@ -679,7 +690,7 @@ static irqreturn_t cx25821_upstream_irq(int irq, void *dev_id)
channel_num = VID_UPSTREAM_SRAM_CHANNEL_I;
- sram_ch = &dev->sram_channels[channel_num];
+ sram_ch = dev->channels[channel_num].sram_channels;
msk_stat = cx_read(sram_ch->int_mstat);
vid_status = cx_read(sram_ch->int_stat);
@@ -800,14 +811,15 @@ int cx25821_vidupstream_init_ch1(struct cx25821_dev *dev, int channel_select,
}
dev->_channel_upstream_select = channel_select;
- sram_ch = &dev->sram_channels[channel_select];
+ sram_ch = dev->channels[channel_select].sram_channels;
INIT_WORK(&dev->_irq_work_entry, cx25821_vidups_handler);
dev->_irq_queues = create_singlethread_workqueue("cx25821_workqueue");
if (!dev->_irq_queues) {
printk
- (KERN_ERR "cx25821: create_singlethread_workqueue() for Video FAILED!\n");
+ (KERN_ERR "cx25821: create_singlethread_workqueue() for \
+ Video FAILED!\n");
return -ENOMEM;
}
/* 656/VIP SRC Upstream Channel I & J and 7 - Host Bus Interface for
diff --git a/drivers/staging/cx25821/cx25821-video-upstream.h b/drivers/staging/cx25821/cx25821-video-upstream.h
index cc9f9384251..10dee5c24a8 100644
--- a/drivers/staging/cx25821/cx25821-video-upstream.h
+++ b/drivers/staging/cx25821/cx25821-video-upstream.h
@@ -38,7 +38,7 @@
#define RESET_STATUS -1
#define NUM_NO_OPS 5
-// PAL and NTSC line sizes and number of lines.
+/* PAL and NTSC line sizes and number of lines. */
#define WIDTH_D1 720
#define NTSC_LINES_PER_FRAME 480
#define PAL_LINES_PER_FRAME 576
diff --git a/drivers/staging/cx25821/cx25821-video.c b/drivers/staging/cx25821/cx25821-video.c
index 791212c1a66..1d5e8796d38 100644
--- a/drivers/staging/cx25821/cx25821-video.c
+++ b/drivers/staging/cx25821/cx25821-video.c
@@ -4,6 +4,9 @@
* Copyright (C) 2009 Conexant Systems Inc.
* Authors <shu.lin@conexant.com>, <hiep.huynh@conexant.com>
* Based on Steven Toth <stoth@linuxtv.org> cx23885 driver
+ * Parts adapted/taken from Eduardo Moscoso Rubino
+ * Copyright (C) 2009 Eduardo Moscoso Rubino <moscoso@TopoLogica.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
@@ -24,7 +27,7 @@
#include "cx25821-video.h"
MODULE_DESCRIPTION("v4l2 driver module for cx25821 based TV cards");
-MODULE_AUTHOR("Steven Toth <stoth@linuxtv.org>");
+MODULE_AUTHOR("Hiep Huynh <hiep.huynh@conexant.com>");
MODULE_LICENSE("GPL");
static unsigned int video_nr[] = {[0 ... (CX25821_MAXBOARDS - 1)] = UNSET };
@@ -48,7 +51,10 @@ unsigned int vid_limit = 16;
module_param(vid_limit, int, 0644);
MODULE_PARM_DESC(vid_limit, "capture memory limit in megabytes");
-static void init_controls(struct cx25821_dev *dev, int chan_num);
+static void cx25821_init_controls(struct cx25821_dev *dev, int chan_num);
+
+static const struct v4l2_file_operations video_fops;
+static const struct v4l2_ioctl_ops video_ioctl_ops;
#define FORMAT_FLAGS_PACKED 0x01
@@ -211,7 +217,7 @@ static int cx25821_ctrl_query(struct v4l2_queryctrl *qctrl)
}
*/
-// resource management
+/* resource management */
int cx25821_res_get(struct cx25821_dev *dev, struct cx25821_fh *fh, unsigned int bit)
{
dprintk(1, "%s()\n", __func__);
@@ -221,14 +227,14 @@ int cx25821_res_get(struct cx25821_dev *dev, struct cx25821_fh *fh, unsigned int
/* is it free? */
mutex_lock(&dev->lock);
- if (dev->resources & bit) {
+ if (dev->channels[fh->channel_id].resources & bit) {
/* no, someone else uses it */
mutex_unlock(&dev->lock);
return 0;
}
/* it's free, grab it */
fh->resources |= bit;
- dev->resources |= bit;
+ dev->channels[fh->channel_id].resources |= bit;
dprintk(1, "res: get %d\n", bit);
mutex_unlock(&dev->lock);
return 1;
@@ -239,9 +245,9 @@ int cx25821_res_check(struct cx25821_fh *fh, unsigned int bit)
return fh->resources & bit;
}
-int cx25821_res_locked(struct cx25821_dev *dev, unsigned int bit)
+int cx25821_res_locked(struct cx25821_fh *fh, unsigned int bit)
{
- return dev->resources & bit;
+ return fh->dev->channels[fh->channel_id].resources & bit;
}
void cx25821_res_free(struct cx25821_dev *dev, struct cx25821_fh *fh, unsigned int bits)
@@ -251,7 +257,7 @@ void cx25821_res_free(struct cx25821_dev *dev, struct cx25821_fh *fh, unsigned i
mutex_lock(&dev->lock);
fh->resources &= ~bits;
- dev->resources &= ~bits;
+ dev->channels[fh->channel_id].resources &= ~bits;
dprintk(1, "res: put %d\n", bits);
mutex_unlock(&dev->lock);
}
@@ -358,11 +364,11 @@ void cx25821_vid_timeout(unsigned long data)
struct cx25821_data *timeout_data = (struct cx25821_data *)data;
struct cx25821_dev *dev = timeout_data->dev;
struct sram_channel *channel = timeout_data->channel;
- struct cx25821_dmaqueue *q = &dev->vidq[channel->i];
+ struct cx25821_dmaqueue *q = &dev->channels[channel->i].vidq;
struct cx25821_buffer *buf;
unsigned long flags;
- //cx25821_sram_channel_dump(dev, channel);
+ /* cx25821_sram_channel_dump(dev, channel); */
cx_clear(channel->dma_ctl, 0x11);
spin_lock_irqsave(&dev->slock, flags);
@@ -384,7 +390,7 @@ int cx25821_video_irq(struct cx25821_dev *dev, int chan_num, u32 status)
u32 count = 0;
int handled = 0;
u32 mask;
- struct sram_channel *channel = &dev->sram_channels[chan_num];
+ struct sram_channel *channel = dev->channels[chan_num].sram_channels;
mask = cx_read(channel->int_msk);
if (0 == (status & mask))
@@ -404,7 +410,8 @@ int cx25821_video_irq(struct cx25821_dev *dev, int chan_num, u32 status)
if (status & FLD_VID_DST_RISC1) {
spin_lock(&dev->slock);
count = cx_read(channel->gpcnt);
- cx25821_video_wakeup(dev, &dev->vidq[channel->i], count);
+ cx25821_video_wakeup(dev,
+ &dev->channels[channel->i].vidq, count);
spin_unlock(&dev->slock);
handled++;
}
@@ -413,8 +420,9 @@ int cx25821_video_irq(struct cx25821_dev *dev, int chan_num, u32 status)
if (status & 0x10) {
dprintk(2, "stopper video\n");
spin_lock(&dev->slock);
- cx25821_restart_video_queue(dev, &dev->vidq[channel->i],
- channel);
+ cx25821_restart_video_queue(dev,
+ &dev->channels[channel->i].vidq,
+ channel);
spin_unlock(&dev->slock);
handled++;
}
@@ -437,72 +445,95 @@ void cx25821_video_unregister(struct cx25821_dev *dev, int chan_num)
{
cx_clear(PCI_INT_MSK, 1);
- if (dev->video_dev[chan_num]) {
- if (video_is_registered(dev->video_dev[chan_num]))
- video_unregister_device(dev->video_dev[chan_num]);
+ if (dev->channels[chan_num].video_dev) {
+ if (video_is_registered(dev->channels[chan_num].video_dev))
+ video_unregister_device(
+ dev->channels[chan_num].video_dev);
else
- video_device_release(dev->video_dev[chan_num]);
+ video_device_release(
+ dev->channels[chan_num].video_dev);
- dev->video_dev[chan_num] = NULL;
+ dev->channels[chan_num].video_dev = NULL;
- btcx_riscmem_free(dev->pci, &dev->vidq[chan_num].stopper);
+ btcx_riscmem_free(dev->pci,
+ &dev->channels[chan_num].vidq.stopper);
printk(KERN_WARNING "device %d released!\n", chan_num);
}
}
-int cx25821_video_register(struct cx25821_dev *dev, int chan_num,
- struct video_device *video_template)
+int cx25821_video_register(struct cx25821_dev *dev)
{
int err;
+ int i;
+
+ struct video_device cx25821_video_device = {
+ .name = "cx25821-video",
+ .fops = &video_fops,
+ .minor = -1,
+ .ioctl_ops = &video_ioctl_ops,
+ .tvnorms = CX25821_NORMS,
+ .current_norm = V4L2_STD_NTSC_M,
+ };
spin_lock_init(&dev->slock);
- //printk(KERN_WARNING "Channel %d\n", chan_num);
+ for (i = 0; i < MAX_VID_CHANNEL_NUM - 1; ++i) {
+ cx25821_init_controls(dev, i);
-#ifdef TUNER_FLAG
- dev->tvnorm = video_template->current_norm;
-#endif
+ cx25821_risc_stopper(dev->pci,
+ &dev->channels[i].vidq.stopper,
+ dev->channels[i].sram_channels->dma_ctl,
+ 0x11, 0);
+
+ dev->channels[i].sram_channels = &cx25821_sram_channels[i];
+ dev->channels[i].video_dev = NULL;
+ dev->channels[i].resources = 0;
+
+ cx_write(dev->channels[i].sram_channels->int_stat,
+ 0xffffffff);
+
+ INIT_LIST_HEAD(&dev->channels[i].vidq.active);
+ INIT_LIST_HEAD(&dev->channels[i].vidq.queued);
+
+ dev->channels[i].timeout_data.dev = dev;
+ dev->channels[i].timeout_data.channel =
+ &cx25821_sram_channels[i];
+ dev->channels[i].vidq.timeout.function =
+ cx25821_vid_timeout;
+ dev->channels[i].vidq.timeout.data =
+ (unsigned long)&dev->channels[i].timeout_data;
+ init_timer(&dev->channels[i].vidq.timeout);
+
+ /* register v4l devices */
+ dev->channels[i].video_dev = cx25821_vdev_init(dev,
+ dev->pci, &cx25821_video_device, "video");
+
+ err = video_register_device(dev->channels[i].video_dev,
+ VFL_TYPE_GRABBER, video_nr[dev->nr]);
+
+ if (err < 0)
+ goto fail_unreg;
- /* init video dma queues */
- dev->timeout_data[chan_num].dev = dev;
- dev->timeout_data[chan_num].channel = &dev->sram_channels[chan_num];
- INIT_LIST_HEAD(&dev->vidq[chan_num].active);
- INIT_LIST_HEAD(&dev->vidq[chan_num].queued);
- dev->vidq[chan_num].timeout.function = cx25821_vid_timeout;
- dev->vidq[chan_num].timeout.data =
- (unsigned long)&dev->timeout_data[chan_num];
- init_timer(&dev->vidq[chan_num].timeout);
- cx25821_risc_stopper(dev->pci, &dev->vidq[chan_num].stopper,
- dev->sram_channels[chan_num].dma_ctl, 0x11, 0);
-
- /* register v4l devices */
- dev->video_dev[chan_num] =
- cx25821_vdev_init(dev, dev->pci, video_template, "video");
- err =
- video_register_device(dev->video_dev[chan_num], VFL_TYPE_GRABBER,
- video_nr[dev->nr]);
-
- if (err < 0) {
- goto fail_unreg;
}
- //set PCI interrupt
+
+ /* set PCI interrupt */
cx_set(PCI_INT_MSK, 0xff);
/* initial device configuration */
mutex_lock(&dev->lock);
#ifdef TUNER_FLAG
+ dev->tvnorm = cx25821_video_device.current_norm;
cx25821_set_tvnorm(dev, dev->tvnorm);
#endif
mutex_unlock(&dev->lock);
- init_controls(dev, chan_num);
- return 0;
+ return 0;
- fail_unreg:
- cx25821_video_unregister(dev, chan_num);
+fail_unreg:
+ cx25821_video_unregister(dev, i);
return err;
}
@@ -533,7 +564,7 @@ int cx25821_buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
u32 line0_offset, line1_offset;
struct videobuf_dmabuf *dma = videobuf_to_dma(&buf->vb);
int bpl_local = LINE_SIZE_D1;
- int channel_opened = 0;
+ int channel_opened = fh->channel_id;
BUG_ON(NULL == fh->fmt);
if (fh->width < 48 || fh->width > 720 ||
@@ -572,26 +603,29 @@ int cx25821_buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
channel_opened = (channel_opened < 0
|| channel_opened > 7) ? 7 : channel_opened;
- if (dev->pixel_formats[channel_opened] == PIXEL_FRMT_411)
+ if (dev->channels[channel_opened]
+ .pixel_formats == PIXEL_FRMT_411)
buf->bpl = (buf->fmt->depth * buf->vb.width) >> 3;
else
buf->bpl = (buf->fmt->depth >> 3) * (buf->vb.width);
- if (dev->pixel_formats[channel_opened] == PIXEL_FRMT_411) {
+ if (dev->channels[channel_opened]
+ .pixel_formats == PIXEL_FRMT_411) {
bpl_local = buf->bpl;
} else {
- bpl_local = buf->bpl; //Default
+ bpl_local = buf->bpl; /* Default */
if (channel_opened >= 0 && channel_opened <= 7) {
- if (dev->use_cif_resolution[channel_opened]) {
+ if (dev->channels[channel_opened]
+ .use_cif_resolution) {
if (dev->tvnorm & V4L2_STD_PAL_BG
|| dev->tvnorm & V4L2_STD_PAL_DK)
bpl_local = 352 << 1;
else
bpl_local =
- dev->
- cif_width[channel_opened] <<
- 1;
+ dev->channels[channel_opened].
+ cif_width <<
+ 1;
}
}
}
@@ -685,6 +719,383 @@ int cx25821_video_mmap(struct file *file, struct vm_area_struct *vma)
return videobuf_mmap_mapper(get_queue(fh), vma);
}
+
+static void buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
+{
+ struct cx25821_buffer *buf =
+ container_of(vb, struct cx25821_buffer, vb);
+ struct cx25821_buffer *prev;
+ struct cx25821_fh *fh = vq->priv_data;
+ struct cx25821_dev *dev = fh->dev;
+ struct cx25821_dmaqueue *q = &dev->channels[fh->channel_id].vidq;
+
+ /* add jump to stopper */
+ buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC);
+ buf->risc.jmp[1] = cpu_to_le32(q->stopper.dma);
+ buf->risc.jmp[2] = cpu_to_le32(0); /* bits 63-32 */
+
+ dprintk(2, "jmp to stopper (0x%x)\n", buf->risc.jmp[1]);
+
+ if (!list_empty(&q->queued)) {
+ list_add_tail(&buf->vb.queue, &q->queued);
+ buf->vb.state = VIDEOBUF_QUEUED;
+ dprintk(2, "[%p/%d] buffer_queue - append to queued\n", buf,
+ buf->vb.i);
+
+ } else if (list_empty(&q->active)) {
+ list_add_tail(&buf->vb.queue, &q->active);
+ cx25821_start_video_dma(dev, q, buf,
+ dev->channels[fh->channel_id].
+ sram_channels);
+ buf->vb.state = VIDEOBUF_ACTIVE;
+ buf->count = q->count++;
+ mod_timer(&q->timeout, jiffies + BUFFER_TIMEOUT);
+ dprintk(2,
+ "[%p/%d] buffer_queue - first active, buf cnt = %d, \
+ q->count = %d\n",
+ buf, buf->vb.i, buf->count, q->count);
+ } else {
+ prev =
+ list_entry(q->active.prev, struct cx25821_buffer, vb.queue);
+ if (prev->vb.width == buf->vb.width
+ && prev->vb.height == buf->vb.height
+ && prev->fmt == buf->fmt) {
+ list_add_tail(&buf->vb.queue, &q->active);
+ buf->vb.state = VIDEOBUF_ACTIVE;
+ buf->count = q->count++;
+ prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
+
+ /* 64 bit bits 63-32 */
+ prev->risc.jmp[2] = cpu_to_le32(0);
+ dprintk(2,
+ "[%p/%d] buffer_queue - append to active, \
+ buf->count=%d\n",
+ buf, buf->vb.i, buf->count);
+
+ } else {
+ list_add_tail(&buf->vb.queue, &q->queued);
+ buf->vb.state = VIDEOBUF_QUEUED;
+ dprintk(2, "[%p/%d] buffer_queue - first queued\n", buf,
+ buf->vb.i);
+ }
+ }
+
+ if (list_empty(&q->active))
+ dprintk(2, "active queue empty!\n");
+}
+
+static struct videobuf_queue_ops cx25821_video_qops = {
+ .buf_setup = cx25821_buffer_setup,
+ .buf_prepare = cx25821_buffer_prepare,
+ .buf_queue = buffer_queue,
+ .buf_release = cx25821_buffer_release,
+};
+
+static int video_open(struct file *file)
+{
+ struct video_device *vdev = video_devdata(file);
+ struct cx25821_dev *h, *dev = video_drvdata(file);
+ struct cx25821_fh *fh;
+ struct list_head *list;
+ int minor = video_devdata(file)->minor;
+ enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ u32 pix_format;
+ int ch_id = 0;
+ int i;
+
+ dprintk(1, "open dev=%s type=%s\n",
+ video_device_node_name(vdev),
+ v4l2_type_names[type]);
+
+ /* allocate + initialize per filehandle data */
+ fh = kzalloc(sizeof(*fh), GFP_KERNEL);
+ if (NULL == fh)
+ return -ENOMEM;
+
+ lock_kernel();
+
+ list_for_each(list, &cx25821_devlist)
+ {
+ h = list_entry(list, struct cx25821_dev, devlist);
+
+ for (i = 0; i < MAX_VID_CHANNEL_NUM; i++) {
+ if (h->channels[i].video_dev &&
+ h->channels[i].video_dev->minor == minor) {
+ dev = h;
+ ch_id = i;
+ type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ }
+ }
+ }
+
+ if (NULL == dev) {
+ unlock_kernel();
+ return -ENODEV;
+ }
+
+ file->private_data = fh;
+ fh->dev = dev;
+ fh->type = type;
+ fh->width = 720;
+ fh->channel_id = ch_id;
+
+ if (dev->tvnorm & V4L2_STD_PAL_BG || dev->tvnorm & V4L2_STD_PAL_DK)
+ fh->height = 576;
+ else
+ fh->height = 480;
+
+ dev->channel_opened = fh->channel_id;
+ pix_format =
+ (dev->channels[ch_id].pixel_formats ==
+ PIXEL_FRMT_411) ? V4L2_PIX_FMT_Y41P : V4L2_PIX_FMT_YUYV;
+ fh->fmt = format_by_fourcc(pix_format);
+
+ v4l2_prio_open(&dev->channels[ch_id].prio, &fh->prio);
+
+ videobuf_queue_sg_init(&fh->vidq, &cx25821_video_qops,
+ &dev->pci->dev, &dev->slock,
+ V4L2_BUF_TYPE_VIDEO_CAPTURE,
+ V4L2_FIELD_INTERLACED,
+ sizeof(struct cx25821_buffer), fh);
+
+ dprintk(1, "post videobuf_queue_init()\n");
+ unlock_kernel();
+
+ return 0;
+}
+
+static ssize_t video_read(struct file *file, char __user * data, size_t count,
+ loff_t *ppos)
+{
+ struct cx25821_fh *fh = file->private_data;
+
+ switch (fh->type) {
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+ if (cx25821_res_locked(fh, RESOURCE_VIDEO0))
+ return -EBUSY;
+
+ return videobuf_read_one(&fh->vidq, data, count, ppos,
+ file->f_flags & O_NONBLOCK);
+
+ default:
+ BUG();
+ return 0;
+ }
+}
+
+static unsigned int video_poll(struct file *file,
+ struct poll_table_struct *wait)
+{
+ struct cx25821_fh *fh = file->private_data;
+ struct cx25821_buffer *buf;
+
+ if (cx25821_res_check(fh, RESOURCE_VIDEO0)) {
+ /* streaming capture */
+ if (list_empty(&fh->vidq.stream))
+ return POLLERR;
+ buf = list_entry(fh->vidq.stream.next,
+ struct cx25821_buffer, vb.stream);
+ } else {
+ /* read() capture */
+ buf = (struct cx25821_buffer *)fh->vidq.read_buf;
+ if (NULL == buf)
+ return POLLERR;
+ }
+
+ poll_wait(file, &buf->vb.done, wait);
+ if (buf->vb.state == VIDEOBUF_DONE || buf->vb.state == VIDEOBUF_ERROR) {
+ if (buf->vb.state == VIDEOBUF_DONE) {
+ struct cx25821_dev *dev = fh->dev;
+
+ if (dev && dev->channels[fh->channel_id]
+ .use_cif_resolution) {
+ u8 cam_id = *((char *)buf->vb.baddr + 3);
+ memcpy((char *)buf->vb.baddr,
+ (char *)buf->vb.baddr + (fh->width * 2),
+ (fh->width * 2));
+ *((char *)buf->vb.baddr + 3) = cam_id;
+ }
+ }
+
+ return POLLIN | POLLRDNORM;
+ }
+
+ return 0;
+}
+
+static int video_release(struct file *file)
+{
+ struct cx25821_fh *fh = file->private_data;
+ struct cx25821_dev *dev = fh->dev;
+
+ /* stop the risc engine and fifo */
+ cx_write(channel0->dma_ctl, 0); /* FIFO and RISC disable */
+
+ /* stop video capture */
+ if (cx25821_res_check(fh, RESOURCE_VIDEO0)) {
+ videobuf_queue_cancel(&fh->vidq);
+ cx25821_res_free(dev, fh, RESOURCE_VIDEO0);
+ }
+
+ if (fh->vidq.read_buf) {
+ cx25821_buffer_release(&fh->vidq, fh->vidq.read_buf);
+ kfree(fh->vidq.read_buf);
+ }
+
+ videobuf_mmap_free(&fh->vidq);
+
+ v4l2_prio_close(&dev->channels[fh->channel_id].prio, fh->prio);
+ file->private_data = NULL;
+ kfree(fh);
+
+ return 0;
+}
+
+static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
+{
+ struct cx25821_fh *fh = priv;
+ struct cx25821_dev *dev = fh->dev;
+
+ if (unlikely(fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE))
+ return -EINVAL;
+
+ if (unlikely(i != fh->type))
+ return -EINVAL;
+
+ if (unlikely(!cx25821_res_get(dev, fh,
+ cx25821_get_resource(fh, RESOURCE_VIDEO0))))
+ return -EBUSY;
+
+ return videobuf_streamon(get_queue(fh));
+}
+
+static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
+{
+ struct cx25821_fh *fh = priv;
+ struct cx25821_dev *dev = fh->dev;
+ int err, res;
+
+ if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+ if (i != fh->type)
+ return -EINVAL;
+
+ res = cx25821_get_resource(fh, RESOURCE_VIDEO0);
+ err = videobuf_streamoff(get_queue(fh));
+ if (err < 0)
+ return err;
+ cx25821_res_free(dev, fh, res);
+ return 0;
+}
+
+static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct cx25821_fh *fh = priv;
+ struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
+ int err;
+ int pix_format = PIXEL_FRMT_422;
+
+ if (fh) {
+ err = v4l2_prio_check(&dev->channels[fh->channel_id]
+ .prio, fh->prio);
+ if (0 != err)
+ return err;
+ }
+
+ dprintk(2, "%s()\n", __func__);
+ err = cx25821_vidioc_try_fmt_vid_cap(file, priv, f);
+
+ if (0 != err)
+ return err;
+
+ fh->fmt = format_by_fourcc(f->fmt.pix.pixelformat);
+ fh->vidq.field = f->fmt.pix.field;
+
+ /* check if width and height is valid based on set standard */
+ if (cx25821_is_valid_width(f->fmt.pix.width, dev->tvnorm))
+ fh->width = f->fmt.pix.width;
+
+ if (cx25821_is_valid_height(f->fmt.pix.height, dev->tvnorm))
+ fh->height = f->fmt.pix.height;
+
+ if (f->fmt.pix.pixelformat == V4L2_PIX_FMT_Y41P)
+ pix_format = PIXEL_FRMT_411;
+ else if (f->fmt.pix.pixelformat == V4L2_PIX_FMT_YUYV)
+ pix_format = PIXEL_FRMT_422;
+ else
+ return -EINVAL;
+
+ cx25821_set_pixel_format(dev, SRAM_CH00, pix_format);
+
+ /* check if cif resolution */
+ if (fh->width == 320 || fh->width == 352)
+ dev->channels[fh->channel_id].use_cif_resolution = 1;
+ else
+ dev->channels[fh->channel_id].use_cif_resolution = 0;
+
+ dev->channels[fh->channel_id].cif_width = fh->width;
+ medusa_set_resolution(dev, fh->width, SRAM_CH00);
+
+ dprintk(2, "%s() width=%d height=%d field=%d\n", __func__, fh->width,
+ fh->height, fh->vidq.field);
+ cx25821_call_all(dev, video, s_fmt, f);
+
+ return 0;
+}
+
+static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p)
+{
+ int ret_val = 0;
+ struct cx25821_fh *fh = priv;
+ struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
+
+ ret_val = videobuf_dqbuf(get_queue(fh), p, file->f_flags & O_NONBLOCK);
+
+ p->sequence = dev->channels[fh->channel_id].vidq.count;
+
+ return ret_val;
+}
+
+static int vidioc_log_status(struct file *file, void *priv)
+{
+ struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
+ struct cx25821_fh *fh = priv;
+ char name[32 + 2];
+
+ struct sram_channel *sram_ch = dev->channels[fh->channel_id]
+ .sram_channels;
+ u32 tmp = 0;
+
+ snprintf(name, sizeof(name), "%s/2", dev->name);
+ printk(KERN_INFO "%s/2: ============ START LOG STATUS ============\n",
+ dev->name);
+ cx25821_call_all(dev, core, log_status);
+ tmp = cx_read(sram_ch->dma_ctl);
+ printk(KERN_INFO "Video input 0 is %s\n",
+ (tmp & 0x11) ? "streaming" : "stopped");
+ printk(KERN_INFO "%s/2: ============= END LOG STATUS =============\n",
+ dev->name);
+ return 0;
+}
+
+static int vidioc_s_ctrl(struct file *file, void *priv,
+ struct v4l2_control *ctl)
+{
+ struct cx25821_fh *fh = priv;
+ struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
+ int err;
+
+ if (fh) {
+ err = v4l2_prio_check(&dev->channels[fh->channel_id]
+ .prio, fh->prio);
+ if (0 != err)
+ return err;
+ }
+
+ return cx25821_set_control(dev, ctl, fh->channel_id);
+}
+
/* VIDEO IOCTLS */
int cx25821_vidioc_g_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f)
{
@@ -822,8 +1233,9 @@ int cx25821_vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *p)
int cx25821_vidioc_g_priority(struct file *file, void *f, enum v4l2_priority *p)
{
struct cx25821_dev *dev = ((struct cx25821_fh *)f)->dev;
+ struct cx25821_fh *fh = f;
- *p = v4l2_prio_max(&dev->prio);
+ *p = v4l2_prio_max(&dev->channels[fh->channel_id].prio);
return 0;
}
@@ -833,7 +1245,8 @@ int cx25821_vidioc_s_priority(struct file *file, void *f, enum v4l2_priority pri
struct cx25821_fh *fh = f;
struct cx25821_dev *dev = ((struct cx25821_fh *)f)->dev;
- return v4l2_prio_change(&dev->prio, &fh->prio, prio);
+ return v4l2_prio_change(&dev->channels[fh->channel_id]
+ .prio, &fh->prio, prio);
}
#ifdef TUNER_FLAG
@@ -846,7 +1259,8 @@ int cx25821_vidioc_s_std(struct file *file, void *priv, v4l2_std_id * tvnorms)
dprintk(1, "%s()\n", __func__);
if (fh) {
- err = v4l2_prio_check(&dev->prio, fh->prio);
+ err = v4l2_prio_check(&dev->channels[fh->channel_id]
+ .prio, fh->prio);
if (0 != err)
return err;
}
@@ -916,7 +1330,8 @@ int cx25821_vidioc_s_input(struct file *file, void *priv, unsigned int i)
dprintk(1, "%s(%d)\n", __func__, i);
if (fh) {
- err = v4l2_prio_check(&dev->prio, fh->prio);
+ err = v4l2_prio_check(&dev->channels[fh->channel_id]
+ .prio, fh->prio);
if (0 != err)
return err;
}
@@ -967,9 +1382,14 @@ int cx25821_vidioc_s_frequency(struct file *file, void *priv, struct v4l2_freque
int err;
if (fh) {
- err = v4l2_prio_check(&dev->prio, fh->prio);
+ dev = fh->dev;
+ err = v4l2_prio_check(&dev->channels[fh->channel_id]
+ .prio, fh->prio);
if (0 != err)
return err;
+ } else {
+ printk(KERN_ERR "Invalid fh pointer!\n");
+ return -EINVAL;
}
return cx25821_set_freq(dev, f);
@@ -1031,7 +1451,8 @@ int cx25821_vidioc_s_tuner(struct file *file, void *priv, struct v4l2_tuner *t)
int err;
if (fh) {
- err = v4l2_prio_check(&dev->prio, fh->prio);
+ err = v4l2_prio_check(&dev->channels[fh->channel_id]
+ .prio, fh->prio);
if (0 != err)
return err;
}
@@ -1046,7 +1467,7 @@ int cx25821_vidioc_s_tuner(struct file *file, void *priv, struct v4l2_tuner *t)
}
#endif
-// ******************************************************************************************
+/*****************************************************************************/
static const struct v4l2_queryctrl no_ctl = {
.name = "42",
.flags = V4L2_CTRL_FLAG_DISABLED,
@@ -1129,6 +1550,7 @@ static const struct v4l2_queryctrl *ctrl_by_id(unsigned int id)
int cx25821_vidioc_g_ctrl(struct file *file, void *priv, struct v4l2_control *ctl)
{
struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
+ struct cx25821_fh *fh = priv;
const struct v4l2_queryctrl *ctrl;
@@ -1138,16 +1560,16 @@ int cx25821_vidioc_g_ctrl(struct file *file, void *priv, struct v4l2_control *ct
return -EINVAL;
switch (ctl->id) {
case V4L2_CID_BRIGHTNESS:
- ctl->value = dev->ctl_bright;
+ ctl->value = dev->channels[fh->channel_id].ctl_bright;
break;
case V4L2_CID_HUE:
- ctl->value = dev->ctl_hue;
+ ctl->value = dev->channels[fh->channel_id].ctl_hue;
break;
case V4L2_CID_CONTRAST:
- ctl->value = dev->ctl_contrast;
+ ctl->value = dev->channels[fh->channel_id].ctl_contrast;
break;
case V4L2_CID_SATURATION:
- ctl->value = dev->ctl_saturation;
+ ctl->value = dev->channels[fh->channel_id].ctl_saturation;
break;
}
return 0;
@@ -1181,19 +1603,19 @@ int cx25821_set_control(struct cx25821_dev *dev,
switch (ctl->id) {
case V4L2_CID_BRIGHTNESS:
- dev->ctl_bright = ctl->value;
+ dev->channels[chan_num].ctl_bright = ctl->value;
medusa_set_brightness(dev, ctl->value, chan_num);
break;
case V4L2_CID_HUE:
- dev->ctl_hue = ctl->value;
+ dev->channels[chan_num].ctl_hue = ctl->value;
medusa_set_hue(dev, ctl->value, chan_num);
break;
case V4L2_CID_CONTRAST:
- dev->ctl_contrast = ctl->value;
+ dev->channels[chan_num].ctl_contrast = ctl->value;
medusa_set_contrast(dev, ctl->value, chan_num);
break;
case V4L2_CID_SATURATION:
- dev->ctl_saturation = ctl->value;
+ dev->channels[chan_num].ctl_saturation = ctl->value;
medusa_set_saturation(dev, ctl->value, chan_num);
break;
}
@@ -1203,7 +1625,7 @@ int cx25821_set_control(struct cx25821_dev *dev,
return err;
}
-static void init_controls(struct cx25821_dev *dev, int chan_num)
+static void cx25821_init_controls(struct cx25821_dev *dev, int chan_num)
{
struct v4l2_control ctrl;
int i;
@@ -1239,23 +1661,24 @@ int cx25821_vidioc_s_crop(struct file *file, void *priv, struct v4l2_crop *crop)
int err;
if (fh) {
- err = v4l2_prio_check(&dev->prio, fh->prio);
+ err = v4l2_prio_check(&dev->channels[fh->channel_id].
+ prio, fh->prio);
if (0 != err)
return err;
}
- // cx25821_vidioc_s_crop not supported
+ /* cx25821_vidioc_s_crop not supported */
return -EINVAL;
}
int cx25821_vidioc_g_crop(struct file *file, void *priv, struct v4l2_crop *crop)
{
- // cx25821_vidioc_g_crop not supported
+ /* cx25821_vidioc_g_crop not supported */
return -EINVAL;
}
int cx25821_vidioc_querystd(struct file *file, void *priv, v4l2_std_id * norm)
{
- // medusa does not support video standard sensing of current input
+ /* medusa does not support video standard sensing of current input */
*norm = CX25821_NORMS;
return 0;
@@ -1297,3 +1720,325 @@ int cx25821_is_valid_height(u32 height, v4l2_std_id tvnorm)
return 0;
}
+
+static long video_ioctl_upstream9(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ struct cx25821_fh *fh = file->private_data;
+ struct cx25821_dev *dev = fh->dev;
+ int command = 0;
+ struct upstream_user_struct *data_from_user;
+
+ data_from_user = (struct upstream_user_struct *)arg;
+
+ if (!data_from_user) {
+ printk
+ ("cx25821 in %s(): Upstream data is INVALID. Returning.\n",
+ __func__);
+ return 0;
+ }
+
+ command = data_from_user->command;
+
+ if (command != UPSTREAM_START_VIDEO &&
+ command != UPSTREAM_STOP_VIDEO)
+ return 0;
+
+ dev->input_filename = data_from_user->input_filename;
+ dev->input_audiofilename = data_from_user->input_filename;
+ dev->vid_stdname = data_from_user->vid_stdname;
+ dev->pixel_format = data_from_user->pixel_format;
+ dev->channel_select = data_from_user->channel_select;
+ dev->command = data_from_user->command;
+
+ switch (command) {
+ case UPSTREAM_START_VIDEO:
+ cx25821_start_upstream_video_ch1(dev, data_from_user);
+ break;
+
+ case UPSTREAM_STOP_VIDEO:
+ cx25821_stop_upstream_video_ch1(dev);
+ break;
+ }
+
+ return 0;
+}
+
+static long video_ioctl_upstream10(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ struct cx25821_fh *fh = file->private_data;
+ struct cx25821_dev *dev = fh->dev;
+ int command = 0;
+ struct upstream_user_struct *data_from_user;
+
+ data_from_user = (struct upstream_user_struct *)arg;
+
+ if (!data_from_user) {
+ printk
+ ("cx25821 in %s(): Upstream data is INVALID. Returning.\n",
+ __func__);
+ return 0;
+ }
+
+ command = data_from_user->command;
+
+ if (command != UPSTREAM_START_VIDEO &&
+ command != UPSTREAM_STOP_VIDEO)
+ return 0;
+
+ dev->input_filename_ch2 = data_from_user->input_filename;
+ dev->input_audiofilename = data_from_user->input_filename;
+ dev->vid_stdname_ch2 = data_from_user->vid_stdname;
+ dev->pixel_format_ch2 = data_from_user->pixel_format;
+ dev->channel_select_ch2 = data_from_user->channel_select;
+ dev->command_ch2 = data_from_user->command;
+
+ switch (command) {
+ case UPSTREAM_START_VIDEO:
+ cx25821_start_upstream_video_ch2(dev, data_from_user);
+ break;
+
+ case UPSTREAM_STOP_VIDEO:
+ cx25821_stop_upstream_video_ch2(dev);
+ break;
+ }
+
+ return 0;
+}
+
+static long video_ioctl_upstream11(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ struct cx25821_fh *fh = file->private_data;
+ struct cx25821_dev *dev = fh->dev;
+ int command = 0;
+ struct upstream_user_struct *data_from_user;
+
+ data_from_user = (struct upstream_user_struct *)arg;
+
+ if (!data_from_user) {
+ printk
+ ("cx25821 in %s(): Upstream data is INVALID. Returning.\n",
+ __func__);
+ return 0;
+ }
+
+ command = data_from_user->command;
+
+ if (command != UPSTREAM_START_AUDIO &&
+ command != UPSTREAM_STOP_AUDIO)
+ return 0;
+
+ dev->input_filename = data_from_user->input_filename;
+ dev->input_audiofilename = data_from_user->input_filename;
+ dev->vid_stdname = data_from_user->vid_stdname;
+ dev->pixel_format = data_from_user->pixel_format;
+ dev->channel_select = data_from_user->channel_select;
+ dev->command = data_from_user->command;
+
+ switch (command) {
+ case UPSTREAM_START_AUDIO:
+ cx25821_start_upstream_audio(dev, data_from_user);
+ break;
+
+ case UPSTREAM_STOP_AUDIO:
+ cx25821_stop_upstream_audio(dev);
+ break;
+ }
+
+ return 0;
+}
+
+static long video_ioctl_set(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ struct cx25821_fh *fh = file->private_data;
+ struct cx25821_dev *dev = fh->dev;
+ struct downstream_user_struct *data_from_user;
+ int command;
+ int width = 720;
+ int selected_channel = 0, pix_format = 0, i = 0;
+ int cif_enable = 0, cif_width = 0;
+ u32 value = 0;
+
+ data_from_user = (struct downstream_user_struct *)arg;
+
+ if (!data_from_user) {
+ printk(
+ "cx25821 in %s(): User data is INVALID. Returning.\n",
+ __func__);
+ return 0;
+ }
+
+ command = data_from_user->command;
+
+ if (command != SET_VIDEO_STD && command != SET_PIXEL_FORMAT
+ && command != ENABLE_CIF_RESOLUTION && command != REG_READ
+ && command != REG_WRITE && command != MEDUSA_READ
+ && command != MEDUSA_WRITE) {
+ return 0;
+ }
+
+ switch (command) {
+ case SET_VIDEO_STD:
+ dev->tvnorm =
+ !strcmp(data_from_user->vid_stdname,
+ "PAL") ? V4L2_STD_PAL_BG : V4L2_STD_NTSC_M;
+ medusa_set_videostandard(dev);
+ break;
+
+ case SET_PIXEL_FORMAT:
+ selected_channel = data_from_user->decoder_select;
+ pix_format = data_from_user->pixel_format;
+
+ if (!(selected_channel <= 7 && selected_channel >= 0)) {
+ selected_channel -= 4;
+ selected_channel = selected_channel % 8;
+ }
+
+ if (selected_channel >= 0)
+ cx25821_set_pixel_format(dev, selected_channel,
+ pix_format);
+
+ break;
+
+ case ENABLE_CIF_RESOLUTION:
+ selected_channel = data_from_user->decoder_select;
+ cif_enable = data_from_user->cif_resolution_enable;
+ cif_width = data_from_user->cif_width;
+
+ if (cif_enable) {
+ if (dev->tvnorm & V4L2_STD_PAL_BG
+ || dev->tvnorm & V4L2_STD_PAL_DK)
+ width = 352;
+ else
+ width = (cif_width == 320
+ || cif_width == 352) ? cif_width : 320;
+ }
+
+ if (!(selected_channel <= 7 && selected_channel >= 0)) {
+ selected_channel -= 4;
+ selected_channel = selected_channel % 8;
+ }
+
+ if (selected_channel <= 7 && selected_channel >= 0) {
+ dev->channels[selected_channel].
+ use_cif_resolution = cif_enable;
+ dev->channels[selected_channel].cif_width = width;
+ } else {
+ for (i = 0; i < VID_CHANNEL_NUM; i++) {
+ dev->channels[i].use_cif_resolution =
+ cif_enable;
+ dev->channels[i].cif_width = width;
+ }
+ }
+
+ medusa_set_resolution(dev, width, selected_channel);
+ break;
+ case REG_READ:
+ data_from_user->reg_data = cx_read(data_from_user->reg_address);
+ break;
+ case REG_WRITE:
+ cx_write(data_from_user->reg_address, data_from_user->reg_data);
+ break;
+ case MEDUSA_READ:
+ value =
+ cx25821_i2c_read(&dev->i2c_bus[0],
+ (u16) data_from_user->reg_address,
+ &data_from_user->reg_data);
+ break;
+ case MEDUSA_WRITE:
+ cx25821_i2c_write(&dev->i2c_bus[0],
+ (u16) data_from_user->reg_address,
+ data_from_user->reg_data);
+ break;
+ }
+
+ return 0;
+}
+
+static long cx25821_video_ioctl(struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ int ret = 0;
+
+ struct cx25821_fh *fh = file->private_data;
+
+ /* check to see if it's the video upstream */
+ if (fh->channel_id == SRAM_CH09) {
+ ret = video_ioctl_upstream9(file, cmd, arg);
+ return ret;
+ } else if (fh->channel_id == SRAM_CH10) {
+ ret = video_ioctl_upstream10(file, cmd, arg);
+ return ret;
+ } else if (fh->channel_id == SRAM_CH11) {
+ ret = video_ioctl_upstream11(file, cmd, arg);
+ ret = video_ioctl_set(file, cmd, arg);
+ return ret;
+ }
+
+ return video_ioctl2(file, cmd, arg);
+}
+
+/* exported stuff */
+static const struct v4l2_file_operations video_fops = {
+ .owner = THIS_MODULE,
+ .open = video_open,
+ .release = video_release,
+ .read = video_read,
+ .poll = video_poll,
+ .mmap = cx25821_video_mmap,
+ .ioctl = cx25821_video_ioctl,
+};
+
+static const struct v4l2_ioctl_ops video_ioctl_ops = {
+ .vidioc_querycap = cx25821_vidioc_querycap,
+ .vidioc_enum_fmt_vid_cap = cx25821_vidioc_enum_fmt_vid_cap,
+ .vidioc_g_fmt_vid_cap = cx25821_vidioc_g_fmt_vid_cap,
+ .vidioc_try_fmt_vid_cap = cx25821_vidioc_try_fmt_vid_cap,
+ .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
+ .vidioc_reqbufs = cx25821_vidioc_reqbufs,
+ .vidioc_querybuf = cx25821_vidioc_querybuf,
+ .vidioc_qbuf = cx25821_vidioc_qbuf,
+ .vidioc_dqbuf = vidioc_dqbuf,
+#ifdef TUNER_FLAG
+ .vidioc_s_std = cx25821_vidioc_s_std,
+ .vidioc_querystd = cx25821_vidioc_querystd,
+#endif
+ .vidioc_cropcap = cx25821_vidioc_cropcap,
+ .vidioc_s_crop = cx25821_vidioc_s_crop,
+ .vidioc_g_crop = cx25821_vidioc_g_crop,
+ .vidioc_enum_input = cx25821_vidioc_enum_input,
+ .vidioc_g_input = cx25821_vidioc_g_input,
+ .vidioc_s_input = cx25821_vidioc_s_input,
+ .vidioc_g_ctrl = cx25821_vidioc_g_ctrl,
+ .vidioc_s_ctrl = vidioc_s_ctrl,
+ .vidioc_queryctrl = cx25821_vidioc_queryctrl,
+ .vidioc_streamon = vidioc_streamon,
+ .vidioc_streamoff = vidioc_streamoff,
+ .vidioc_log_status = vidioc_log_status,
+ .vidioc_g_priority = cx25821_vidioc_g_priority,
+ .vidioc_s_priority = cx25821_vidioc_s_priority,
+#ifdef CONFIG_VIDEO_V4L1_COMPAT
+ .vidiocgmbuf = cx25821_vidiocgmbuf,
+#endif
+#ifdef TUNER_FLAG
+ .vidioc_g_tuner = cx25821_vidioc_g_tuner,
+ .vidioc_s_tuner = cx25821_vidioc_s_tuner,
+ .vidioc_g_frequency = cx25821_vidioc_g_frequency,
+ .vidioc_s_frequency = cx25821_vidioc_s_frequency,
+#endif
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+ .vidioc_g_register = cx25821_vidioc_g_register,
+ .vidioc_s_register = cx25821_vidioc_s_register,
+#endif
+};
+
+struct video_device cx25821_videoioctl_template = {
+ .name = "cx25821-videoioctl",
+ .fops = &video_fops,
+ .ioctl_ops = &video_ioctl_ops,
+ .tvnorms = CX25821_NORMS,
+ .current_norm = V4L2_STD_NTSC_M,
+};
diff --git a/drivers/staging/cx25821/cx25821-video.h b/drivers/staging/cx25821/cx25821-video.h
index 0bddc02be57..cc6034b1a95 100644
--- a/drivers/staging/cx25821/cx25821-video.h
+++ b/drivers/staging/cx25821/cx25821-video.h
@@ -54,7 +54,7 @@
printk(KERN_DEBUG "%s/0: " fmt, dev->name, ## arg);\
} while (0)
-//For IOCTL to identify running upstream
+/* For IOCTL to identify running upstream */
#define UPSTREAM_START_VIDEO 700
#define UPSTREAM_STOP_VIDEO 701
#define UPSTREAM_START_AUDIO 702
@@ -80,19 +80,8 @@ extern struct sram_channel *channel7;
extern struct sram_channel *channel9;
extern struct sram_channel *channel10;
extern struct sram_channel *channel11;
-extern struct video_device cx25821_video_template0;
-extern struct video_device cx25821_video_template1;
-extern struct video_device cx25821_video_template2;
-extern struct video_device cx25821_video_template3;
-extern struct video_device cx25821_video_template4;
-extern struct video_device cx25821_video_template5;
-extern struct video_device cx25821_video_template6;
-extern struct video_device cx25821_video_template7;
-extern struct video_device cx25821_video_template9;
-extern struct video_device cx25821_video_template10;
-extern struct video_device cx25821_video_template11;
extern struct video_device cx25821_videoioctl_template;
-//extern const u32 *ctrl_classes[];
+/* extern const u32 *ctrl_classes[]; */
extern unsigned int vid_limit;
@@ -113,7 +102,7 @@ extern int cx25821_set_tvnorm(struct cx25821_dev *dev, v4l2_std_id norm);
extern int cx25821_res_get(struct cx25821_dev *dev, struct cx25821_fh *fh,
unsigned int bit);
extern int cx25821_res_check(struct cx25821_fh *fh, unsigned int bit);
-extern int cx25821_res_locked(struct cx25821_dev *dev, unsigned int bit);
+extern int cx25821_res_locked(struct cx25821_fh *fh, unsigned int bit);
extern void cx25821_res_free(struct cx25821_dev *dev, struct cx25821_fh *fh,
unsigned int bits);
extern int cx25821_video_mux(struct cx25821_dev *dev, unsigned int input);
@@ -126,8 +115,7 @@ extern int cx25821_set_scale(struct cx25821_dev *dev, unsigned int width,
unsigned int height, enum v4l2_field field);
extern int cx25821_video_irq(struct cx25821_dev *dev, int chan_num, u32 status);
extern void cx25821_video_unregister(struct cx25821_dev *dev, int chan_num);
-extern int cx25821_video_register(struct cx25821_dev *dev, int chan_num,
- struct video_device *video_template);
+extern int cx25821_video_register(struct cx25821_dev *dev);
extern int cx25821_get_format_size(void);
extern int cx25821_buffer_setup(struct videobuf_queue *q, unsigned int *count,
diff --git a/drivers/staging/cx25821/cx25821-video0.c b/drivers/staging/cx25821/cx25821-video0.c
deleted file mode 100644
index 0be2cc15d85..00000000000
--- a/drivers/staging/cx25821/cx25821-video0.c
+++ /dev/null
@@ -1,434 +0,0 @@
-/*
- * Driver for the Conexant CX25821 PCIe bridge
- *
- * Copyright (C) 2009 Conexant Systems Inc.
- * Authors <shu.lin@conexant.com>, <hiep.huynh@conexant.com>
- * Based on Steven Toth <stoth@linuxtv.org> cx23885 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 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 "cx25821-video.h"
-
-static void buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
-{
- struct cx25821_buffer *buf =
- container_of(vb, struct cx25821_buffer, vb);
- struct cx25821_buffer *prev;
- struct cx25821_fh *fh = vq->priv_data;
- struct cx25821_dev *dev = fh->dev;
- struct cx25821_dmaqueue *q = &dev->vidq[SRAM_CH00];
-
- /* add jump to stopper */
- buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC);
- buf->risc.jmp[1] = cpu_to_le32(q->stopper.dma);
- buf->risc.jmp[2] = cpu_to_le32(0); /* bits 63-32 */
-
- dprintk(2, "jmp to stopper (0x%x)\n", buf->risc.jmp[1]);
-
- if (!list_empty(&q->queued)) {
- list_add_tail(&buf->vb.queue, &q->queued);
- buf->vb.state = VIDEOBUF_QUEUED;
- dprintk(2, "[%p/%d] buffer_queue - append to queued\n", buf,
- buf->vb.i);
-
- } else if (list_empty(&q->active)) {
- list_add_tail(&buf->vb.queue, &q->active);
- cx25821_start_video_dma(dev, q, buf,
- &dev->sram_channels[SRAM_CH00]);
- buf->vb.state = VIDEOBUF_ACTIVE;
- buf->count = q->count++;
- mod_timer(&q->timeout, jiffies + BUFFER_TIMEOUT);
- dprintk(2,
- "[%p/%d] buffer_queue - first active, buf cnt = %d, q->count = %d\n",
- buf, buf->vb.i, buf->count, q->count);
- } else {
- prev =
- list_entry(q->active.prev, struct cx25821_buffer, vb.queue);
- if (prev->vb.width == buf->vb.width
- && prev->vb.height == buf->vb.height
- && prev->fmt == buf->fmt) {
- list_add_tail(&buf->vb.queue, &q->active);
- buf->vb.state = VIDEOBUF_ACTIVE;
- buf->count = q->count++;
- prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
-
- /* 64 bit bits 63-32 */
- prev->risc.jmp[2] = cpu_to_le32(0);
- dprintk(2,
- "[%p/%d] buffer_queue - append to active, buf->count=%d\n",
- buf, buf->vb.i, buf->count);
-
- } else {
- list_add_tail(&buf->vb.queue, &q->queued);
- buf->vb.state = VIDEOBUF_QUEUED;
- dprintk(2, "[%p/%d] buffer_queue - first queued\n", buf,
- buf->vb.i);
- }
- }
-
- if (list_empty(&q->active)) {
- dprintk(2, "active queue empty!\n");
- }
-}
-
-static struct videobuf_queue_ops cx25821_video_qops = {
- .buf_setup = cx25821_buffer_setup,
- .buf_prepare = cx25821_buffer_prepare,
- .buf_queue = buffer_queue,
- .buf_release = cx25821_buffer_release,
-};
-
-static int video_open(struct file *file)
-{
- struct video_device *vdev = video_devdata(file);
- struct cx25821_dev *dev = video_drvdata(file);
- struct cx25821_fh *fh;
- enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- u32 pix_format;
-
- printk("open dev=%s type=%s\n", video_device_node_name(vdev),
- v4l2_type_names[type]);
-
- /* allocate + initialize per filehandle data */
- fh = kzalloc(sizeof(*fh), GFP_KERNEL);
- if (NULL == fh)
- return -ENOMEM;
-
- lock_kernel();
-
- file->private_data = fh;
- fh->dev = dev;
- fh->type = type;
- fh->width = 720;
-
- if (dev->tvnorm & V4L2_STD_PAL_BG || dev->tvnorm & V4L2_STD_PAL_DK)
- fh->height = 576;
- else
- fh->height = 480;
-
- dev->channel_opened = SRAM_CH00;
- pix_format =
- (dev->pixel_formats[dev->channel_opened] ==
- PIXEL_FRMT_411) ? V4L2_PIX_FMT_Y41P : V4L2_PIX_FMT_YUYV;
- fh->fmt = format_by_fourcc(pix_format);
-
- v4l2_prio_open(&dev->prio, &fh->prio);
-
- videobuf_queue_sg_init(&fh->vidq, &cx25821_video_qops,
- &dev->pci->dev, &dev->slock,
- V4L2_BUF_TYPE_VIDEO_CAPTURE,
- V4L2_FIELD_INTERLACED,
- sizeof(struct cx25821_buffer), fh);
-
- dprintk(1, "post videobuf_queue_init()\n");
- unlock_kernel();
-
- return 0;
-}
-
-static ssize_t video_read(struct file *file, char __user * data, size_t count,
- loff_t * ppos)
-{
- struct cx25821_fh *fh = file->private_data;
-
- switch (fh->type) {
- case V4L2_BUF_TYPE_VIDEO_CAPTURE:
- if (cx25821_res_locked(fh->dev, RESOURCE_VIDEO0))
- return -EBUSY;
-
- return videobuf_read_one(&fh->vidq, data, count, ppos,
- file->f_flags & O_NONBLOCK);
-
- default:
- BUG();
- return 0;
- }
-}
-
-static unsigned int video_poll(struct file *file,
- struct poll_table_struct *wait)
-{
- struct cx25821_fh *fh = file->private_data;
- struct cx25821_buffer *buf;
-
- if (cx25821_res_check(fh, RESOURCE_VIDEO0)) {
- /* streaming capture */
- if (list_empty(&fh->vidq.stream))
- return POLLERR;
- buf = list_entry(fh->vidq.stream.next,
- struct cx25821_buffer, vb.stream);
- } else {
- /* read() capture */
- buf = (struct cx25821_buffer *)fh->vidq.read_buf;
- if (NULL == buf)
- return POLLERR;
- }
-
- poll_wait(file, &buf->vb.done, wait);
- if (buf->vb.state == VIDEOBUF_DONE || buf->vb.state == VIDEOBUF_ERROR) {
- if (buf->vb.state == VIDEOBUF_DONE) {
- struct cx25821_dev *dev = fh->dev;
-
- if (dev && dev->use_cif_resolution[SRAM_CH00]) {
- u8 cam_id = *((char *)buf->vb.baddr + 3);
- memcpy((char *)buf->vb.baddr,
- (char *)buf->vb.baddr + (fh->width * 2),
- (fh->width * 2));
- *((char *)buf->vb.baddr + 3) = cam_id;
- }
- }
-
- return POLLIN | POLLRDNORM;
- }
-
- return 0;
-}
-
-static int video_release(struct file *file)
-{
- struct cx25821_fh *fh = file->private_data;
- struct cx25821_dev *dev = fh->dev;
-
- //stop the risc engine and fifo
- cx_write(channel0->dma_ctl, 0); /* FIFO and RISC disable */
-
- /* stop video capture */
- if (cx25821_res_check(fh, RESOURCE_VIDEO0)) {
- videobuf_queue_cancel(&fh->vidq);
- cx25821_res_free(dev, fh, RESOURCE_VIDEO0);
- }
-
- if (fh->vidq.read_buf) {
- cx25821_buffer_release(&fh->vidq, fh->vidq.read_buf);
- kfree(fh->vidq.read_buf);
- }
-
- videobuf_mmap_free(&fh->vidq);
-
- v4l2_prio_close(&dev->prio, fh->prio);
- file->private_data = NULL;
- kfree(fh);
-
- return 0;
-}
-
-static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
-{
- struct cx25821_fh *fh = priv;
- struct cx25821_dev *dev = fh->dev;
-
- if (unlikely(fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)) {
- return -EINVAL;
- }
-
- if (unlikely(i != fh->type)) {
- return -EINVAL;
- }
-
- if (unlikely(!cx25821_res_get(dev, fh, cx25821_get_resource(fh, RESOURCE_VIDEO0)))) {
- return -EBUSY;
- }
-
- return videobuf_streamon(get_queue(fh));
-}
-
-static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
-{
- struct cx25821_fh *fh = priv;
- struct cx25821_dev *dev = fh->dev;
- int err, res;
-
- if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
- if (i != fh->type)
- return -EINVAL;
-
- res = cx25821_get_resource(fh, RESOURCE_VIDEO0);
- err = videobuf_streamoff(get_queue(fh));
- if (err < 0)
- return err;
- cx25821_res_free(dev, fh, res);
- return 0;
-}
-
-static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
- struct v4l2_format *f)
-{
- struct cx25821_fh *fh = priv;
- struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
- int err;
- int pix_format = PIXEL_FRMT_422;
-
- if (fh) {
- err = v4l2_prio_check(&dev->prio, fh->prio);
- if (0 != err)
- return err;
- }
-
- dprintk(2, "%s()\n", __func__);
- err = cx25821_vidioc_try_fmt_vid_cap(file, priv, f);
-
- if (0 != err)
- return err;
-
- fh->fmt = format_by_fourcc(f->fmt.pix.pixelformat);
- fh->vidq.field = f->fmt.pix.field;
-
- // check if width and height is valid based on set standard
- if (cx25821_is_valid_width(f->fmt.pix.width, dev->tvnorm)) {
- fh->width = f->fmt.pix.width;
- }
-
- if (cx25821_is_valid_height(f->fmt.pix.height, dev->tvnorm)) {
- fh->height = f->fmt.pix.height;
- }
-
- if (f->fmt.pix.pixelformat == V4L2_PIX_FMT_Y41P)
- pix_format = PIXEL_FRMT_411;
- else if (f->fmt.pix.pixelformat == V4L2_PIX_FMT_YUYV)
- pix_format = PIXEL_FRMT_422;
- else
- return -EINVAL;
-
- cx25821_set_pixel_format(dev, SRAM_CH00, pix_format);
-
- // check if cif resolution
- if (fh->width == 320 || fh->width == 352) {
- dev->use_cif_resolution[SRAM_CH00] = 1;
- } else {
- dev->use_cif_resolution[SRAM_CH00] = 0;
- }
- dev->cif_width[SRAM_CH00] = fh->width;
- medusa_set_resolution(dev, fh->width, SRAM_CH00);
-
- dprintk(2, "%s() width=%d height=%d field=%d\n", __func__, fh->width,
- fh->height, fh->vidq.field);
- cx25821_call_all(dev, video, s_fmt, f);
-
- return 0;
-}
-
-static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p)
-{
- int ret_val = 0;
- struct cx25821_fh *fh = priv;
- struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
-
- ret_val = videobuf_dqbuf(get_queue(fh), p, file->f_flags & O_NONBLOCK);
-
- p->sequence = dev->vidq[SRAM_CH00].count;
-
- return ret_val;
-}
-
-static int vidioc_log_status(struct file *file, void *priv)
-{
- struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
- char name[32 + 2];
-
- struct sram_channel *sram_ch = &dev->sram_channels[SRAM_CH00];
- u32 tmp = 0;
-
- snprintf(name, sizeof(name), "%s/2", dev->name);
- printk(KERN_INFO "%s/2: ============ START LOG STATUS ============\n",
- dev->name);
- cx25821_call_all(dev, core, log_status);
- tmp = cx_read(sram_ch->dma_ctl);
- printk(KERN_INFO "Video input 0 is %s\n",
- (tmp & 0x11) ? "streaming" : "stopped");
- printk(KERN_INFO "%s/2: ============= END LOG STATUS =============\n",
- dev->name);
- return 0;
-}
-
-static int vidioc_s_ctrl(struct file *file, void *priv,
- struct v4l2_control *ctl)
-{
- struct cx25821_fh *fh = priv;
- struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
- int err;
-
- if (fh) {
- err = v4l2_prio_check(&dev->prio, fh->prio);
- if (0 != err)
- return err;
- }
-
- return cx25821_set_control(dev, ctl, SRAM_CH00);
-}
-
-// exported stuff
-static const struct v4l2_file_operations video_fops = {
- .owner = THIS_MODULE,
- .open = video_open,
- .release = video_release,
- .read = video_read,
- .poll = video_poll,
- .mmap = cx25821_video_mmap,
- .ioctl = video_ioctl2,
-};
-
-static const struct v4l2_ioctl_ops video_ioctl_ops = {
- .vidioc_querycap = cx25821_vidioc_querycap,
- .vidioc_enum_fmt_vid_cap = cx25821_vidioc_enum_fmt_vid_cap,
- .vidioc_g_fmt_vid_cap = cx25821_vidioc_g_fmt_vid_cap,
- .vidioc_try_fmt_vid_cap = cx25821_vidioc_try_fmt_vid_cap,
- .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
- .vidioc_reqbufs = cx25821_vidioc_reqbufs,
- .vidioc_querybuf = cx25821_vidioc_querybuf,
- .vidioc_qbuf = cx25821_vidioc_qbuf,
- .vidioc_dqbuf = vidioc_dqbuf,
-#ifdef TUNER_FLAG
- .vidioc_s_std = cx25821_vidioc_s_std,
- .vidioc_querystd = cx25821_vidioc_querystd,
-#endif
- .vidioc_cropcap = cx25821_vidioc_cropcap,
- .vidioc_s_crop = cx25821_vidioc_s_crop,
- .vidioc_g_crop = cx25821_vidioc_g_crop,
- .vidioc_enum_input = cx25821_vidioc_enum_input,
- .vidioc_g_input = cx25821_vidioc_g_input,
- .vidioc_s_input = cx25821_vidioc_s_input,
- .vidioc_g_ctrl = cx25821_vidioc_g_ctrl,
- .vidioc_s_ctrl = vidioc_s_ctrl,
- .vidioc_queryctrl = cx25821_vidioc_queryctrl,
- .vidioc_streamon = vidioc_streamon,
- .vidioc_streamoff = vidioc_streamoff,
- .vidioc_log_status = vidioc_log_status,
- .vidioc_g_priority = cx25821_vidioc_g_priority,
- .vidioc_s_priority = cx25821_vidioc_s_priority,
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
- .vidiocgmbuf = cx25821_vidiocgmbuf,
-#endif
-#ifdef TUNER_FLAG
- .vidioc_g_tuner = cx25821_vidioc_g_tuner,
- .vidioc_s_tuner = cx25821_vidioc_s_tuner,
- .vidioc_g_frequency = cx25821_vidioc_g_frequency,
- .vidioc_s_frequency = cx25821_vidioc_s_frequency,
-#endif
-#ifdef CONFIG_VIDEO_ADV_DEBUG
- .vidioc_g_register = cx25821_vidioc_g_register,
- .vidioc_s_register = cx25821_vidioc_s_register,
-#endif
-};
-
-struct video_device cx25821_video_template0 = {
- .name = "cx25821-video",
- .fops = &video_fops,
- .ioctl_ops = &video_ioctl_ops,
- .tvnorms = CX25821_NORMS,
- .current_norm = V4L2_STD_NTSC_M,
-};
diff --git a/drivers/staging/cx25821/cx25821-video1.c b/drivers/staging/cx25821/cx25821-video1.c
deleted file mode 100644
index b0bae627bfb..00000000000
--- a/drivers/staging/cx25821/cx25821-video1.c
+++ /dev/null
@@ -1,434 +0,0 @@
-/*
- * Driver for the Conexant CX25821 PCIe bridge
- *
- * Copyright (C) 2009 Conexant Systems Inc.
- * Authors <shu.lin@conexant.com>, <hiep.huynh@conexant.com>
- * Based on Steven Toth <stoth@linuxtv.org> cx23885 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 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 "cx25821-video.h"
-
-static void buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
-{
- struct cx25821_buffer *buf =
- container_of(vb, struct cx25821_buffer, vb);
- struct cx25821_buffer *prev;
- struct cx25821_fh *fh = vq->priv_data;
- struct cx25821_dev *dev = fh->dev;
- struct cx25821_dmaqueue *q = &dev->vidq[SRAM_CH01];
-
- /* add jump to stopper */
- buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC);
- buf->risc.jmp[1] = cpu_to_le32(q->stopper.dma);
- buf->risc.jmp[2] = cpu_to_le32(0); /* bits 63-32 */
-
- dprintk(2, "jmp to stopper (0x%x)\n", buf->risc.jmp[1]);
-
- if (!list_empty(&q->queued)) {
- list_add_tail(&buf->vb.queue, &q->queued);
- buf->vb.state = VIDEOBUF_QUEUED;
- dprintk(2, "[%p/%d] buffer_queue - append to queued\n", buf,
- buf->vb.i);
-
- } else if (list_empty(&q->active)) {
- list_add_tail(&buf->vb.queue, &q->active);
- cx25821_start_video_dma(dev, q, buf,
- &dev->sram_channels[SRAM_CH01]);
- buf->vb.state = VIDEOBUF_ACTIVE;
- buf->count = q->count++;
- mod_timer(&q->timeout, jiffies + BUFFER_TIMEOUT);
- dprintk(2,
- "[%p/%d] buffer_queue - first active, buf cnt = %d, q->count = %d\n",
- buf, buf->vb.i, buf->count, q->count);
- } else {
- prev =
- list_entry(q->active.prev, struct cx25821_buffer, vb.queue);
- if (prev->vb.width == buf->vb.width
- && prev->vb.height == buf->vb.height
- && prev->fmt == buf->fmt) {
- list_add_tail(&buf->vb.queue, &q->active);
- buf->vb.state = VIDEOBUF_ACTIVE;
- buf->count = q->count++;
- prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
-
- /* 64 bit bits 63-32 */
- prev->risc.jmp[2] = cpu_to_le32(0);
- dprintk(2,
- "[%p/%d] buffer_queue - append to active, buf->count=%d\n",
- buf, buf->vb.i, buf->count);
-
- } else {
- list_add_tail(&buf->vb.queue, &q->queued);
- buf->vb.state = VIDEOBUF_QUEUED;
- dprintk(2, "[%p/%d] buffer_queue - first queued\n", buf,
- buf->vb.i);
- }
- }
-
- if (list_empty(&q->active)) {
- dprintk(2, "active queue empty!\n");
- }
-}
-
-static struct videobuf_queue_ops cx25821_video_qops = {
- .buf_setup = cx25821_buffer_setup,
- .buf_prepare = cx25821_buffer_prepare,
- .buf_queue = buffer_queue,
- .buf_release = cx25821_buffer_release,
-};
-
-static int video_open(struct file *file)
-{
- struct video_device *vdev = video_devdata(file);
- struct cx25821_dev *dev = video_drvdata(file);
- struct cx25821_fh *fh;
- enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- u32 pix_format;
-
- printk("open dev=%s type=%s\n", video_device_node_name(vdev),
- v4l2_type_names[type]);
-
- /* allocate + initialize per filehandle data */
- fh = kzalloc(sizeof(*fh), GFP_KERNEL);
- if (NULL == fh)
- return -ENOMEM;
-
- lock_kernel();
-
- file->private_data = fh;
- fh->dev = dev;
- fh->type = type;
- fh->width = 720;
-
- if (dev->tvnorm & V4L2_STD_PAL_BG || dev->tvnorm & V4L2_STD_PAL_DK)
- fh->height = 576;
- else
- fh->height = 480;
-
- dev->channel_opened = SRAM_CH01;
- pix_format =
- (dev->pixel_formats[dev->channel_opened] ==
- PIXEL_FRMT_411) ? V4L2_PIX_FMT_Y41P : V4L2_PIX_FMT_YUYV;
- fh->fmt = format_by_fourcc(pix_format);
-
- v4l2_prio_open(&dev->prio, &fh->prio);
-
- videobuf_queue_sg_init(&fh->vidq, &cx25821_video_qops,
- &dev->pci->dev, &dev->slock,
- V4L2_BUF_TYPE_VIDEO_CAPTURE,
- V4L2_FIELD_INTERLACED,
- sizeof(struct cx25821_buffer), fh);
-
- dprintk(1, "post videobuf_queue_init()\n");
- unlock_kernel();
-
- return 0;
-}
-
-static ssize_t video_read(struct file *file, char __user * data, size_t count,
- loff_t * ppos)
-{
- struct cx25821_fh *fh = file->private_data;
-
- switch (fh->type) {
- case V4L2_BUF_TYPE_VIDEO_CAPTURE:
- if (cx25821_res_locked(fh->dev, RESOURCE_VIDEO1))
- return -EBUSY;
-
- return videobuf_read_one(&fh->vidq, data, count, ppos,
- file->f_flags & O_NONBLOCK);
-
- default:
- BUG();
- return 0;
- }
-}
-
-static unsigned int video_poll(struct file *file,
- struct poll_table_struct *wait)
-{
- struct cx25821_fh *fh = file->private_data;
- struct cx25821_buffer *buf;
-
- if (cx25821_res_check(fh, RESOURCE_VIDEO1)) {
- /* streaming capture */
- if (list_empty(&fh->vidq.stream))
- return POLLERR;
- buf = list_entry(fh->vidq.stream.next,
- struct cx25821_buffer, vb.stream);
- } else {
- /* read() capture */
- buf = (struct cx25821_buffer *)fh->vidq.read_buf;
- if (NULL == buf)
- return POLLERR;
- }
-
- poll_wait(file, &buf->vb.done, wait);
- if (buf->vb.state == VIDEOBUF_DONE || buf->vb.state == VIDEOBUF_ERROR) {
- if (buf->vb.state == VIDEOBUF_DONE) {
- struct cx25821_dev *dev = fh->dev;
-
- if (dev && dev->use_cif_resolution[SRAM_CH01]) {
- u8 cam_id = *((char *)buf->vb.baddr + 3);
- memcpy((char *)buf->vb.baddr,
- (char *)buf->vb.baddr + (fh->width * 2),
- (fh->width * 2));
- *((char *)buf->vb.baddr + 3) = cam_id;
- }
- }
-
- return POLLIN | POLLRDNORM;
- }
-
- return 0;
-}
-
-static int video_release(struct file *file)
-{
- struct cx25821_fh *fh = file->private_data;
- struct cx25821_dev *dev = fh->dev;
-
- //stop the risc engine and fifo
- cx_write(channel1->dma_ctl, 0); /* FIFO and RISC disable */
-
- /* stop video capture */
- if (cx25821_res_check(fh, RESOURCE_VIDEO1)) {
- videobuf_queue_cancel(&fh->vidq);
- cx25821_res_free(dev, fh, RESOURCE_VIDEO1);
- }
-
- if (fh->vidq.read_buf) {
- cx25821_buffer_release(&fh->vidq, fh->vidq.read_buf);
- kfree(fh->vidq.read_buf);
- }
-
- videobuf_mmap_free(&fh->vidq);
-
- v4l2_prio_close(&dev->prio, fh->prio);
- file->private_data = NULL;
- kfree(fh);
-
- return 0;
-}
-
-static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
-{
- struct cx25821_fh *fh = priv;
- struct cx25821_dev *dev = fh->dev;
-
- if (unlikely(fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)) {
- return -EINVAL;
- }
-
- if (unlikely(i != fh->type)) {
- return -EINVAL;
- }
-
- if (unlikely(!cx25821_res_get(dev, fh, cx25821_get_resource(fh, RESOURCE_VIDEO1)))) {
- return -EBUSY;
- }
-
- return videobuf_streamon(get_queue(fh));
-}
-
-static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
-{
- struct cx25821_fh *fh = priv;
- struct cx25821_dev *dev = fh->dev;
- int err, res;
-
- if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
- if (i != fh->type)
- return -EINVAL;
-
- res = cx25821_get_resource(fh, RESOURCE_VIDEO1);
- err = videobuf_streamoff(get_queue(fh));
- if (err < 0)
- return err;
- cx25821_res_free(dev, fh, res);
- return 0;
-}
-
-static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
- struct v4l2_format *f)
-{
- struct cx25821_fh *fh = priv;
- struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
- int err;
- int pix_format = 0;
-
- if (fh) {
- err = v4l2_prio_check(&dev->prio, fh->prio);
- if (0 != err)
- return err;
- }
-
- dprintk(2, "%s()\n", __func__);
- err = cx25821_vidioc_try_fmt_vid_cap(file, priv, f);
-
- if (0 != err)
- return err;
-
- fh->fmt = format_by_fourcc(f->fmt.pix.pixelformat);
- fh->vidq.field = f->fmt.pix.field;
-
- // check if width and height is valid based on set standard
- if (cx25821_is_valid_width(f->fmt.pix.width, dev->tvnorm)) {
- fh->width = f->fmt.pix.width;
- }
-
- if (cx25821_is_valid_height(f->fmt.pix.height, dev->tvnorm)) {
- fh->height = f->fmt.pix.height;
- }
-
- if (f->fmt.pix.pixelformat == V4L2_PIX_FMT_Y41P)
- pix_format = PIXEL_FRMT_411;
- else if (f->fmt.pix.pixelformat == V4L2_PIX_FMT_YUYV)
- pix_format = PIXEL_FRMT_422;
- else
- return -EINVAL;
-
- cx25821_set_pixel_format(dev, SRAM_CH01, pix_format);
-
- // check if cif resolution
- if (fh->width == 320 || fh->width == 352) {
- dev->use_cif_resolution[SRAM_CH01] = 1;
- } else {
- dev->use_cif_resolution[SRAM_CH01] = 0;
- }
- dev->cif_width[SRAM_CH01] = fh->width;
- medusa_set_resolution(dev, fh->width, SRAM_CH01);
-
- dprintk(2, "%s() width=%d height=%d field=%d\n", __func__, fh->width,
- fh->height, fh->vidq.field);
- cx25821_call_all(dev, video, s_fmt, f);
-
- return 0;
-}
-
-static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p)
-{
- int ret_val = 0;
- struct cx25821_fh *fh = priv;
- struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
-
- ret_val = videobuf_dqbuf(get_queue(fh), p, file->f_flags & O_NONBLOCK);
-
- p->sequence = dev->vidq[SRAM_CH01].count;
-
- return ret_val;
-}
-
-static int vidioc_log_status(struct file *file, void *priv)
-{
- struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
- char name[32 + 2];
-
- struct sram_channel *sram_ch = &dev->sram_channels[SRAM_CH01];
- u32 tmp = 0;
-
- snprintf(name, sizeof(name), "%s/2", dev->name);
- printk(KERN_INFO "%s/2: ============ START LOG STATUS ============\n",
- dev->name);
- cx25821_call_all(dev, core, log_status);
- tmp = cx_read(sram_ch->dma_ctl);
- printk(KERN_INFO "Video input 1 is %s\n",
- (tmp & 0x11) ? "streaming" : "stopped");
- printk(KERN_INFO "%s/2: ============= END LOG STATUS =============\n",
- dev->name);
- return 0;
-}
-
-static int vidioc_s_ctrl(struct file *file, void *priv,
- struct v4l2_control *ctl)
-{
- struct cx25821_fh *fh = priv;
- struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
- int err;
-
- if (fh) {
- err = v4l2_prio_check(&dev->prio, fh->prio);
- if (0 != err)
- return err;
- }
-
- return cx25821_set_control(dev, ctl, SRAM_CH01);
-}
-
-//exported stuff
-static const struct v4l2_file_operations video_fops = {
- .owner = THIS_MODULE,
- .open = video_open,
- .release = video_release,
- .read = video_read,
- .poll = video_poll,
- .mmap = cx25821_video_mmap,
- .ioctl = video_ioctl2,
-};
-
-static const struct v4l2_ioctl_ops video_ioctl_ops = {
- .vidioc_querycap = cx25821_vidioc_querycap,
- .vidioc_enum_fmt_vid_cap = cx25821_vidioc_enum_fmt_vid_cap,
- .vidioc_g_fmt_vid_cap = cx25821_vidioc_g_fmt_vid_cap,
- .vidioc_try_fmt_vid_cap = cx25821_vidioc_try_fmt_vid_cap,
- .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
- .vidioc_reqbufs = cx25821_vidioc_reqbufs,
- .vidioc_querybuf = cx25821_vidioc_querybuf,
- .vidioc_qbuf = cx25821_vidioc_qbuf,
- .vidioc_dqbuf = vidioc_dqbuf,
-#ifdef TUNER_FLAG
- .vidioc_s_std = cx25821_vidioc_s_std,
- .vidioc_querystd = cx25821_vidioc_querystd,
-#endif
- .vidioc_cropcap = cx25821_vidioc_cropcap,
- .vidioc_s_crop = cx25821_vidioc_s_crop,
- .vidioc_g_crop = cx25821_vidioc_g_crop,
- .vidioc_enum_input = cx25821_vidioc_enum_input,
- .vidioc_g_input = cx25821_vidioc_g_input,
- .vidioc_s_input = cx25821_vidioc_s_input,
- .vidioc_g_ctrl = cx25821_vidioc_g_ctrl,
- .vidioc_s_ctrl = vidioc_s_ctrl,
- .vidioc_queryctrl = cx25821_vidioc_queryctrl,
- .vidioc_streamon = vidioc_streamon,
- .vidioc_streamoff = vidioc_streamoff,
- .vidioc_log_status = vidioc_log_status,
- .vidioc_g_priority = cx25821_vidioc_g_priority,
- .vidioc_s_priority = cx25821_vidioc_s_priority,
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
- .vidiocgmbuf = cx25821_vidiocgmbuf,
-#endif
-#ifdef TUNER_FLAG
- .vidioc_g_tuner = cx25821_vidioc_g_tuner,
- .vidioc_s_tuner = cx25821_vidioc_s_tuner,
- .vidioc_g_frequency = cx25821_vidioc_g_frequency,
- .vidioc_s_frequency = cx25821_vidioc_s_frequency,
-#endif
-#ifdef CONFIG_VIDEO_ADV_DEBUG
- .vidioc_g_register = cx25821_vidioc_g_register,
- .vidioc_s_register = cx25821_vidioc_s_register,
-#endif
-};
-
-struct video_device cx25821_video_template1 = {
- .name = "cx25821-video",
- .fops = &video_fops,
- .ioctl_ops = &video_ioctl_ops,
- .tvnorms = CX25821_NORMS,
- .current_norm = V4L2_STD_NTSC_M,
-};
diff --git a/drivers/staging/cx25821/cx25821-video2.c b/drivers/staging/cx25821/cx25821-video2.c
deleted file mode 100644
index 400cdb80674..00000000000
--- a/drivers/staging/cx25821/cx25821-video2.c
+++ /dev/null
@@ -1,436 +0,0 @@
-/*
- * Driver for the Conexant CX25821 PCIe bridge
- *
- * Copyright (C) 2009 Conexant Systems Inc.
- * Authors <shu.lin@conexant.com>, <hiep.huynh@conexant.com>
- * Based on Steven Toth <stoth@linuxtv.org> cx23885 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 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 "cx25821-video.h"
-
-static void buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
-{
- struct cx25821_buffer *buf =
- container_of(vb, struct cx25821_buffer, vb);
- struct cx25821_buffer *prev;
- struct cx25821_fh *fh = vq->priv_data;
- struct cx25821_dev *dev = fh->dev;
- struct cx25821_dmaqueue *q = &dev->vidq[SRAM_CH02];
-
- /* add jump to stopper */
- buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC);
- buf->risc.jmp[1] = cpu_to_le32(q->stopper.dma);
- buf->risc.jmp[2] = cpu_to_le32(0); /* bits 63-32 */
-
- dprintk(2, "jmp to stopper (0x%x)\n", buf->risc.jmp[1]);
-
- if (!list_empty(&q->queued)) {
- list_add_tail(&buf->vb.queue, &q->queued);
- buf->vb.state = VIDEOBUF_QUEUED;
- dprintk(2, "[%p/%d] buffer_queue - append to queued\n", buf,
- buf->vb.i);
-
- } else if (list_empty(&q->active)) {
- list_add_tail(&buf->vb.queue, &q->active);
- cx25821_start_video_dma(dev, q, buf,
- &dev->sram_channels[SRAM_CH02]);
- buf->vb.state = VIDEOBUF_ACTIVE;
- buf->count = q->count++;
- mod_timer(&q->timeout, jiffies + BUFFER_TIMEOUT);
- dprintk(2,
- "[%p/%d] buffer_queue - first active, buf cnt = %d, q->count = %d\n",
- buf, buf->vb.i, buf->count, q->count);
- } else {
- prev =
- list_entry(q->active.prev, struct cx25821_buffer, vb.queue);
- if (prev->vb.width == buf->vb.width
- && prev->vb.height == buf->vb.height
- && prev->fmt == buf->fmt) {
- list_add_tail(&buf->vb.queue, &q->active);
- buf->vb.state = VIDEOBUF_ACTIVE;
- buf->count = q->count++;
- prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
-
- /* 64 bit bits 63-32 */
- prev->risc.jmp[2] = cpu_to_le32(0);
- dprintk(2,
- "[%p/%d] buffer_queue - append to active, buf->count=%d\n",
- buf, buf->vb.i, buf->count);
-
- } else {
- list_add_tail(&buf->vb.queue, &q->queued);
- buf->vb.state = VIDEOBUF_QUEUED;
- dprintk(2, "[%p/%d] buffer_queue - first queued\n", buf,
- buf->vb.i);
- }
- }
-
- if (list_empty(&q->active)) {
- dprintk(2, "active queue empty!\n");
- }
-}
-
-static struct videobuf_queue_ops cx25821_video_qops = {
- .buf_setup = cx25821_buffer_setup,
- .buf_prepare = cx25821_buffer_prepare,
- .buf_queue = buffer_queue,
- .buf_release = cx25821_buffer_release,
-};
-
-static int video_open(struct file *file)
-{
- struct video_device *vdev = video_devdata(file);
- struct cx25821_dev *dev = video_drvdata(file);
- struct cx25821_fh *fh;
- enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- u32 pix_format;
-
- printk("open dev=%s type=%s\n", video_device_node_name(vdev),
- v4l2_type_names[type]);
-
- /* allocate + initialize per filehandle data */
- fh = kzalloc(sizeof(*fh), GFP_KERNEL);
- if (NULL == fh)
- return -ENOMEM;
-
- lock_kernel();
-
- file->private_data = fh;
- fh->dev = dev;
- fh->type = type;
- fh->width = 720;
-
- if (dev->tvnorm & V4L2_STD_PAL_BG || dev->tvnorm & V4L2_STD_PAL_DK)
- fh->height = 576;
- else
- fh->height = 480;
-
- dev->channel_opened = SRAM_CH02;
- pix_format =
- (dev->pixel_formats[dev->channel_opened] ==
- PIXEL_FRMT_411) ? V4L2_PIX_FMT_Y41P : V4L2_PIX_FMT_YUYV;
- fh->fmt = format_by_fourcc(pix_format);
-
- v4l2_prio_open(&dev->prio, &fh->prio);
-
- videobuf_queue_sg_init(&fh->vidq, &cx25821_video_qops,
- &dev->pci->dev, &dev->slock,
- V4L2_BUF_TYPE_VIDEO_CAPTURE,
- V4L2_FIELD_INTERLACED,
- sizeof(struct cx25821_buffer), fh);
-
- dprintk(1, "post videobuf_queue_init()\n");
- unlock_kernel();
-
- return 0;
-}
-
-static ssize_t video_read(struct file *file, char __user * data, size_t count,
- loff_t * ppos)
-{
- struct cx25821_fh *fh = file->private_data;
-
- switch (fh->type) {
- case V4L2_BUF_TYPE_VIDEO_CAPTURE:
- if (cx25821_res_locked(fh->dev, RESOURCE_VIDEO2))
- return -EBUSY;
-
- return videobuf_read_one(&fh->vidq, data, count, ppos,
- file->f_flags & O_NONBLOCK);
-
- default:
- BUG();
- return 0;
- }
-}
-
-static unsigned int video_poll(struct file *file,
- struct poll_table_struct *wait)
-{
- struct cx25821_fh *fh = file->private_data;
- struct cx25821_buffer *buf;
-
- if (cx25821_res_check(fh, RESOURCE_VIDEO2)) {
- /* streaming capture */
- if (list_empty(&fh->vidq.stream))
- return POLLERR;
- buf = list_entry(fh->vidq.stream.next,
- struct cx25821_buffer, vb.stream);
- } else {
- /* read() capture */
- buf = (struct cx25821_buffer *)fh->vidq.read_buf;
- if (NULL == buf)
- return POLLERR;
- }
-
- poll_wait(file, &buf->vb.done, wait);
- if (buf->vb.state == VIDEOBUF_DONE || buf->vb.state == VIDEOBUF_ERROR) {
- if (buf->vb.state == VIDEOBUF_DONE) {
- struct cx25821_dev *dev = fh->dev;
-
- if (dev && dev->use_cif_resolution[SRAM_CH02]) {
- u8 cam_id = *((char *)buf->vb.baddr + 3);
- memcpy((char *)buf->vb.baddr,
- (char *)buf->vb.baddr + (fh->width * 2),
- (fh->width * 2));
- *((char *)buf->vb.baddr + 3) = cam_id;
- }
- }
-
- return POLLIN | POLLRDNORM;
- }
-
- return 0;
-}
-
-static int video_release(struct file *file)
-{
- struct cx25821_fh *fh = file->private_data;
- struct cx25821_dev *dev = fh->dev;
-
- //stop the risc engine and fifo
- cx_write(channel2->dma_ctl, 0); /* FIFO and RISC disable */
-
- /* stop video capture */
- if (cx25821_res_check(fh, RESOURCE_VIDEO2)) {
- videobuf_queue_cancel(&fh->vidq);
- cx25821_res_free(dev, fh, RESOURCE_VIDEO2);
- }
-
- if (fh->vidq.read_buf) {
- cx25821_buffer_release(&fh->vidq, fh->vidq.read_buf);
- kfree(fh->vidq.read_buf);
- }
-
- videobuf_mmap_free(&fh->vidq);
-
- v4l2_prio_close(&dev->prio, fh->prio);
- file->private_data = NULL;
- kfree(fh);
-
- return 0;
-}
-
-static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
-{
- struct cx25821_fh *fh = priv;
- struct cx25821_dev *dev = fh->dev;
-
- if (unlikely(fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)) {
- return -EINVAL;
- }
-
- if (unlikely(i != fh->type)) {
- return -EINVAL;
- }
-
- if (unlikely(!cx25821_res_get(dev, fh, cx25821_get_resource(fh, RESOURCE_VIDEO2)))) {
- return -EBUSY;
- }
-
- return videobuf_streamon(get_queue(fh));
-}
-
-static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
-{
- struct cx25821_fh *fh = priv;
- struct cx25821_dev *dev = fh->dev;
- int err, res;
-
- if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
- if (i != fh->type)
- return -EINVAL;
-
- res = cx25821_get_resource(fh, RESOURCE_VIDEO2);
- err = videobuf_streamoff(get_queue(fh));
- if (err < 0)
- return err;
- cx25821_res_free(dev, fh, res);
- return 0;
-}
-
-static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
- struct v4l2_format *f)
-{
- struct cx25821_fh *fh = priv;
- struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
- int err;
- int pix_format = 0;
-
- if (fh) {
- err = v4l2_prio_check(&dev->prio, fh->prio);
- if (0 != err)
- return err;
- }
-
- dprintk(2, "%s()\n", __func__);
- err = cx25821_vidioc_try_fmt_vid_cap(file, priv, f);
-
- if (0 != err)
- return err;
-
- fh->fmt = format_by_fourcc(f->fmt.pix.pixelformat);
- fh->vidq.field = f->fmt.pix.field;
-
- // check if width and height is valid based on set standard
- if (cx25821_is_valid_width(f->fmt.pix.width, dev->tvnorm)) {
- fh->width = f->fmt.pix.width;
- }
-
- if (cx25821_is_valid_height(f->fmt.pix.height, dev->tvnorm)) {
- fh->height = f->fmt.pix.height;
- }
-
- if (f->fmt.pix.pixelformat == V4L2_PIX_FMT_Y41P)
- pix_format = PIXEL_FRMT_411;
- else if (f->fmt.pix.pixelformat == V4L2_PIX_FMT_YUYV)
- pix_format = PIXEL_FRMT_422;
- else
- return -EINVAL;
-
- cx25821_set_pixel_format(dev, SRAM_CH02, pix_format);
-
- // check if cif resolution
- if (fh->width == 320 || fh->width == 352) {
- dev->use_cif_resolution[SRAM_CH02] = 1;
- } else {
- dev->use_cif_resolution[SRAM_CH02] = 0;
- }
- dev->cif_width[SRAM_CH02] = fh->width;
- medusa_set_resolution(dev, fh->width, SRAM_CH02);
-
- dprintk(2, "%s() width=%d height=%d field=%d\n", __func__, fh->width,
- fh->height, fh->vidq.field);
- cx25821_call_all(dev, video, s_fmt, f);
-
- return 0;
-}
-
-static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p)
-{
- int ret_val = 0;
- struct cx25821_fh *fh = priv;
- struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
-
- ret_val = videobuf_dqbuf(get_queue(fh), p, file->f_flags & O_NONBLOCK);
-
- p->sequence = dev->vidq[SRAM_CH02].count;
-
- return ret_val;
-}
-
-static int vidioc_log_status(struct file *file, void *priv)
-{
- struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
- char name[32 + 2];
-
- struct sram_channel *sram_ch = &dev->sram_channels[SRAM_CH02];
- u32 tmp = 0;
-
- snprintf(name, sizeof(name), "%s/2", dev->name);
- printk(KERN_INFO "%s/2: ============ START LOG STATUS ============\n",
- dev->name);
-
- cx25821_call_all(dev, core, log_status);
-
- tmp = cx_read(sram_ch->dma_ctl);
- printk(KERN_INFO "Video input 2 is %s\n",
- (tmp & 0x11) ? "streaming" : "stopped");
- printk(KERN_INFO "%s/2: ============= END LOG STATUS =============\n",
- dev->name);
- return 0;
-}
-
-static int vidioc_s_ctrl(struct file *file, void *priv,
- struct v4l2_control *ctl)
-{
- struct cx25821_fh *fh = priv;
- struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
- int err;
-
- if (fh) {
- err = v4l2_prio_check(&dev->prio, fh->prio);
- if (0 != err)
- return err;
- }
-
- return cx25821_set_control(dev, ctl, SRAM_CH02);
-}
-
-// exported stuff
-static const struct v4l2_file_operations video_fops = {
- .owner = THIS_MODULE,
- .open = video_open,
- .release = video_release,
- .read = video_read,
- .poll = video_poll,
- .mmap = cx25821_video_mmap,
- .ioctl = video_ioctl2,
-};
-
-static const struct v4l2_ioctl_ops video_ioctl_ops = {
- .vidioc_querycap = cx25821_vidioc_querycap,
- .vidioc_enum_fmt_vid_cap = cx25821_vidioc_enum_fmt_vid_cap,
- .vidioc_g_fmt_vid_cap = cx25821_vidioc_g_fmt_vid_cap,
- .vidioc_try_fmt_vid_cap = cx25821_vidioc_try_fmt_vid_cap,
- .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
- .vidioc_reqbufs = cx25821_vidioc_reqbufs,
- .vidioc_querybuf = cx25821_vidioc_querybuf,
- .vidioc_qbuf = cx25821_vidioc_qbuf,
- .vidioc_dqbuf = vidioc_dqbuf,
-#ifdef TUNER_FLAG
- .vidioc_s_std = cx25821_vidioc_s_std,
- .vidioc_querystd = cx25821_vidioc_querystd,
-#endif
- .vidioc_cropcap = cx25821_vidioc_cropcap,
- .vidioc_s_crop = cx25821_vidioc_s_crop,
- .vidioc_g_crop = cx25821_vidioc_g_crop,
- .vidioc_enum_input = cx25821_vidioc_enum_input,
- .vidioc_g_input = cx25821_vidioc_g_input,
- .vidioc_s_input = cx25821_vidioc_s_input,
- .vidioc_g_ctrl = cx25821_vidioc_g_ctrl,
- .vidioc_s_ctrl = vidioc_s_ctrl,
- .vidioc_queryctrl = cx25821_vidioc_queryctrl,
- .vidioc_streamon = vidioc_streamon,
- .vidioc_streamoff = vidioc_streamoff,
- .vidioc_log_status = vidioc_log_status,
- .vidioc_g_priority = cx25821_vidioc_g_priority,
- .vidioc_s_priority = cx25821_vidioc_s_priority,
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
- .vidiocgmbuf = cx25821_vidiocgmbuf,
-#endif
-#ifdef TUNER_FLAG
- .vidioc_g_tuner = cx25821_vidioc_g_tuner,
- .vidioc_s_tuner = cx25821_vidioc_s_tuner,
- .vidioc_g_frequency = cx25821_vidioc_g_frequency,
- .vidioc_s_frequency = cx25821_vidioc_s_frequency,
-#endif
-#ifdef CONFIG_VIDEO_ADV_DEBUG
- .vidioc_g_register = cx25821_vidioc_g_register,
- .vidioc_s_register = cx25821_vidioc_s_register,
-#endif
-};
-
-struct video_device cx25821_video_template2 = {
- .name = "cx25821-video",
- .fops = &video_fops,
- .ioctl_ops = &video_ioctl_ops,
- .tvnorms = CX25821_NORMS,
- .current_norm = V4L2_STD_NTSC_M,
-};
diff --git a/drivers/staging/cx25821/cx25821-video3.c b/drivers/staging/cx25821/cx25821-video3.c
deleted file mode 100644
index 3b216ed0906..00000000000
--- a/drivers/staging/cx25821/cx25821-video3.c
+++ /dev/null
@@ -1,435 +0,0 @@
-/*
- * Driver for the Conexant CX25821 PCIe bridge
- *
- * Copyright (C) 2009 Conexant Systems Inc.
- * Authors <shu.lin@conexant.com>, <hiep.huynh@conexant.com>
- * Based on Steven Toth <stoth@linuxtv.org> cx23885 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 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 "cx25821-video.h"
-
-static void buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
-{
- struct cx25821_buffer *buf =
- container_of(vb, struct cx25821_buffer, vb);
- struct cx25821_buffer *prev;
- struct cx25821_fh *fh = vq->priv_data;
- struct cx25821_dev *dev = fh->dev;
- struct cx25821_dmaqueue *q = &dev->vidq[SRAM_CH03];
-
- /* add jump to stopper */
- buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC);
- buf->risc.jmp[1] = cpu_to_le32(q->stopper.dma);
- buf->risc.jmp[2] = cpu_to_le32(0); /* bits 63-32 */
-
- dprintk(2, "jmp to stopper (0x%x)\n", buf->risc.jmp[1]);
-
- if (!list_empty(&q->queued)) {
- list_add_tail(&buf->vb.queue, &q->queued);
- buf->vb.state = VIDEOBUF_QUEUED;
- dprintk(2, "[%p/%d] buffer_queue - append to queued\n", buf,
- buf->vb.i);
-
- } else if (list_empty(&q->active)) {
- list_add_tail(&buf->vb.queue, &q->active);
- cx25821_start_video_dma(dev, q, buf,
- &dev->sram_channels[SRAM_CH03]);
- buf->vb.state = VIDEOBUF_ACTIVE;
- buf->count = q->count++;
- mod_timer(&q->timeout, jiffies + BUFFER_TIMEOUT);
- dprintk(2,
- "[%p/%d] buffer_queue - first active, buf cnt = %d, q->count = %d\n",
- buf, buf->vb.i, buf->count, q->count);
- } else {
- prev =
- list_entry(q->active.prev, struct cx25821_buffer, vb.queue);
- if (prev->vb.width == buf->vb.width
- && prev->vb.height == buf->vb.height
- && prev->fmt == buf->fmt) {
- list_add_tail(&buf->vb.queue, &q->active);
- buf->vb.state = VIDEOBUF_ACTIVE;
- buf->count = q->count++;
- prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
-
- /* 64 bit bits 63-32 */
- prev->risc.jmp[2] = cpu_to_le32(0);
- dprintk(2,
- "[%p/%d] buffer_queue - append to active, buf->count=%d\n",
- buf, buf->vb.i, buf->count);
-
- } else {
- list_add_tail(&buf->vb.queue, &q->queued);
- buf->vb.state = VIDEOBUF_QUEUED;
- dprintk(2, "[%p/%d] buffer_queue - first queued\n", buf,
- buf->vb.i);
- }
- }
-
- if (list_empty(&q->active)) {
- dprintk(2, "active queue empty!\n");
- }
-}
-
-static struct videobuf_queue_ops cx25821_video_qops = {
- .buf_setup = cx25821_buffer_setup,
- .buf_prepare = cx25821_buffer_prepare,
- .buf_queue = buffer_queue,
- .buf_release = cx25821_buffer_release,
-};
-
-static int video_open(struct file *file)
-{
- struct video_device *vdev = video_devdata(file);
- struct cx25821_dev *dev = video_drvdata(file);
- struct cx25821_fh *fh;
- enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- u32 pix_format;
-
- printk("open dev=%s type=%s\n", video_device_node_name(vdev),
- v4l2_type_names[type]);
-
- /* allocate + initialize per filehandle data */
- fh = kzalloc(sizeof(*fh), GFP_KERNEL);
- if (NULL == fh)
- return -ENOMEM;
-
- lock_kernel();
-
- file->private_data = fh;
- fh->dev = dev;
- fh->type = type;
- fh->width = 720;
-
- if (dev->tvnorm & V4L2_STD_PAL_BG || dev->tvnorm & V4L2_STD_PAL_DK)
- fh->height = 576;
- else
- fh->height = 480;
-
- dev->channel_opened = SRAM_CH03;
- pix_format =
- (dev->pixel_formats[dev->channel_opened] ==
- PIXEL_FRMT_411) ? V4L2_PIX_FMT_Y41P : V4L2_PIX_FMT_YUYV;
- fh->fmt = format_by_fourcc(pix_format);
-
- v4l2_prio_open(&dev->prio, &fh->prio);
-
- videobuf_queue_sg_init(&fh->vidq, &cx25821_video_qops,
- &dev->pci->dev, &dev->slock,
- V4L2_BUF_TYPE_VIDEO_CAPTURE,
- V4L2_FIELD_INTERLACED,
- sizeof(struct cx25821_buffer), fh);
-
- dprintk(1, "post videobuf_queue_init()\n");
- unlock_kernel();
-
- return 0;
-}
-
-static ssize_t video_read(struct file *file, char __user * data, size_t count,
- loff_t * ppos)
-{
- struct cx25821_fh *fh = file->private_data;
-
- switch (fh->type) {
- case V4L2_BUF_TYPE_VIDEO_CAPTURE:
- if (cx25821_res_locked(fh->dev, RESOURCE_VIDEO3))
- return -EBUSY;
-
- return videobuf_read_one(&fh->vidq, data, count, ppos,
- file->f_flags & O_NONBLOCK);
-
- default:
- BUG();
- return 0;
- }
-}
-
-static unsigned int video_poll(struct file *file,
- struct poll_table_struct *wait)
-{
- struct cx25821_fh *fh = file->private_data;
- struct cx25821_buffer *buf;
-
- if (cx25821_res_check(fh, RESOURCE_VIDEO3)) {
- /* streaming capture */
- if (list_empty(&fh->vidq.stream))
- return POLLERR;
- buf = list_entry(fh->vidq.stream.next,
- struct cx25821_buffer, vb.stream);
- } else {
- /* read() capture */
- buf = (struct cx25821_buffer *)fh->vidq.read_buf;
- if (NULL == buf)
- return POLLERR;
- }
-
- poll_wait(file, &buf->vb.done, wait);
- if (buf->vb.state == VIDEOBUF_DONE || buf->vb.state == VIDEOBUF_ERROR) {
- if (buf->vb.state == VIDEOBUF_DONE) {
- struct cx25821_dev *dev = fh->dev;
-
- if (dev && dev->use_cif_resolution[SRAM_CH03]) {
- u8 cam_id = *((char *)buf->vb.baddr + 3);
- memcpy((char *)buf->vb.baddr,
- (char *)buf->vb.baddr + (fh->width * 2),
- (fh->width * 2));
- *((char *)buf->vb.baddr + 3) = cam_id;
- }
- }
-
- return POLLIN | POLLRDNORM;
- }
-
- return 0;
-}
-
-static int video_release(struct file *file)
-{
- struct cx25821_fh *fh = file->private_data;
- struct cx25821_dev *dev = fh->dev;
-
- //stop the risc engine and fifo
- cx_write(channel3->dma_ctl, 0); /* FIFO and RISC disable */
-
- /* stop video capture */
- if (cx25821_res_check(fh, RESOURCE_VIDEO3)) {
- videobuf_queue_cancel(&fh->vidq);
- cx25821_res_free(dev, fh, RESOURCE_VIDEO3);
- }
-
- if (fh->vidq.read_buf) {
- cx25821_buffer_release(&fh->vidq, fh->vidq.read_buf);
- kfree(fh->vidq.read_buf);
- }
-
- videobuf_mmap_free(&fh->vidq);
-
- v4l2_prio_close(&dev->prio, fh->prio);
- file->private_data = NULL;
- kfree(fh);
-
- return 0;
-}
-
-static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
-{
- struct cx25821_fh *fh = priv;
- struct cx25821_dev *dev = fh->dev;
-
- if (unlikely(fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)) {
- return -EINVAL;
- }
-
- if (unlikely(i != fh->type)) {
- return -EINVAL;
- }
-
- if (unlikely(!cx25821_res_get(dev, fh, cx25821_get_resource(fh, RESOURCE_VIDEO3)))) {
- return -EBUSY;
- }
-
- return videobuf_streamon(get_queue(fh));
-}
-
-static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
-{
- struct cx25821_fh *fh = priv;
- struct cx25821_dev *dev = fh->dev;
- int err, res;
-
- if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
- if (i != fh->type)
- return -EINVAL;
-
- res = cx25821_get_resource(fh, RESOURCE_VIDEO3);
- err = videobuf_streamoff(get_queue(fh));
- if (err < 0)
- return err;
- cx25821_res_free(dev, fh, res);
- return 0;
-}
-
-static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
- struct v4l2_format *f)
-{
- struct cx25821_fh *fh = priv;
- struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
- int err;
- int pix_format = 0;
-
- if (fh) {
- err = v4l2_prio_check(&dev->prio, fh->prio);
- if (0 != err)
- return err;
- }
-
- dprintk(2, "%s()\n", __func__);
- err = cx25821_vidioc_try_fmt_vid_cap(file, priv, f);
-
- if (0 != err)
- return err;
-
- fh->fmt = format_by_fourcc(f->fmt.pix.pixelformat);
- fh->vidq.field = f->fmt.pix.field;
-
- // check if width and height is valid based on set standard
- if (cx25821_is_valid_width(f->fmt.pix.width, dev->tvnorm)) {
- fh->width = f->fmt.pix.width;
- }
-
- if (cx25821_is_valid_height(f->fmt.pix.height, dev->tvnorm)) {
- fh->height = f->fmt.pix.height;
- }
-
- if (f->fmt.pix.pixelformat == V4L2_PIX_FMT_Y41P)
- pix_format = PIXEL_FRMT_411;
- else if (f->fmt.pix.pixelformat == V4L2_PIX_FMT_YUYV)
- pix_format = PIXEL_FRMT_422;
- else
- return -EINVAL;
-
- cx25821_set_pixel_format(dev, SRAM_CH03, pix_format);
-
- // check if cif resolution
- if (fh->width == 320 || fh->width == 352) {
- dev->use_cif_resolution[SRAM_CH03] = 1;
- } else {
- dev->use_cif_resolution[SRAM_CH03] = 0;
- }
- dev->cif_width[SRAM_CH03] = fh->width;
- medusa_set_resolution(dev, fh->width, SRAM_CH03);
-
- dprintk(2, "%s() width=%d height=%d field=%d\n", __func__, fh->width,
- fh->height, fh->vidq.field);
- cx25821_call_all(dev, video, s_fmt, f);
-
- return 0;
-}
-
-static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p)
-{
- int ret_val = 0;
- struct cx25821_fh *fh = priv;
- struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
-
- ret_val = videobuf_dqbuf(get_queue(fh), p, file->f_flags & O_NONBLOCK);
-
- p->sequence = dev->vidq[SRAM_CH03].count;
-
- return ret_val;
-}
-
-static int vidioc_log_status(struct file *file, void *priv)
-{
- struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
- char name[32 + 2];
-
- struct sram_channel *sram_ch = &dev->sram_channels[SRAM_CH03];
- u32 tmp = 0;
-
- snprintf(name, sizeof(name), "%s/2", dev->name);
- printk(KERN_INFO "%s/2: ============ START LOG STATUS ============\n",
- dev->name);
- cx25821_call_all(dev, core, log_status);
-
- tmp = cx_read(sram_ch->dma_ctl);
- printk(KERN_INFO "Video input 3 is %s\n",
- (tmp & 0x11) ? "streaming" : "stopped");
- printk(KERN_INFO "%s/2: ============= END LOG STATUS =============\n",
- dev->name);
- return 0;
-}
-
-static int vidioc_s_ctrl(struct file *file, void *priv,
- struct v4l2_control *ctl)
-{
- struct cx25821_fh *fh = priv;
- struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
- int err;
-
- if (fh) {
- err = v4l2_prio_check(&dev->prio, fh->prio);
- if (0 != err)
- return err;
- }
-
- return cx25821_set_control(dev, ctl, SRAM_CH03);
-}
-
-// exported stuff
-static const struct v4l2_file_operations video_fops = {
- .owner = THIS_MODULE,
- .open = video_open,
- .release = video_release,
- .read = video_read,
- .poll = video_poll,
- .mmap = cx25821_video_mmap,
- .ioctl = video_ioctl2,
-};
-
-static const struct v4l2_ioctl_ops video_ioctl_ops = {
- .vidioc_querycap = cx25821_vidioc_querycap,
- .vidioc_enum_fmt_vid_cap = cx25821_vidioc_enum_fmt_vid_cap,
- .vidioc_g_fmt_vid_cap = cx25821_vidioc_g_fmt_vid_cap,
- .vidioc_try_fmt_vid_cap = cx25821_vidioc_try_fmt_vid_cap,
- .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
- .vidioc_reqbufs = cx25821_vidioc_reqbufs,
- .vidioc_querybuf = cx25821_vidioc_querybuf,
- .vidioc_qbuf = cx25821_vidioc_qbuf,
- .vidioc_dqbuf = vidioc_dqbuf,
-#ifdef TUNER_FLAG
- .vidioc_s_std = cx25821_vidioc_s_std,
- .vidioc_querystd = cx25821_vidioc_querystd,
-#endif
- .vidioc_cropcap = cx25821_vidioc_cropcap,
- .vidioc_s_crop = cx25821_vidioc_s_crop,
- .vidioc_g_crop = cx25821_vidioc_g_crop,
- .vidioc_enum_input = cx25821_vidioc_enum_input,
- .vidioc_g_input = cx25821_vidioc_g_input,
- .vidioc_s_input = cx25821_vidioc_s_input,
- .vidioc_g_ctrl = cx25821_vidioc_g_ctrl,
- .vidioc_s_ctrl = vidioc_s_ctrl,
- .vidioc_queryctrl = cx25821_vidioc_queryctrl,
- .vidioc_streamon = vidioc_streamon,
- .vidioc_streamoff = vidioc_streamoff,
- .vidioc_log_status = vidioc_log_status,
- .vidioc_g_priority = cx25821_vidioc_g_priority,
- .vidioc_s_priority = cx25821_vidioc_s_priority,
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
- .vidiocgmbuf = cx25821_vidiocgmbuf,
-#endif
-#ifdef TUNER_FLAG
- .vidioc_g_tuner = cx25821_vidioc_g_tuner,
- .vidioc_s_tuner = cx25821_vidioc_s_tuner,
- .vidioc_g_frequency = cx25821_vidioc_g_frequency,
- .vidioc_s_frequency = cx25821_vidioc_s_frequency,
-#endif
-#ifdef CONFIG_VIDEO_ADV_DEBUG
- .vidioc_g_register = cx25821_vidioc_g_register,
- .vidioc_s_register = cx25821_vidioc_s_register,
-#endif
-};
-
-struct video_device cx25821_video_template3 = {
- .name = "cx25821-video",
- .fops = &video_fops,
- .ioctl_ops = &video_ioctl_ops,
- .tvnorms = CX25821_NORMS,
- .current_norm = V4L2_STD_NTSC_M,
-};
diff --git a/drivers/staging/cx25821/cx25821-video4.c b/drivers/staging/cx25821/cx25821-video4.c
deleted file mode 100644
index f7b08c51868..00000000000
--- a/drivers/staging/cx25821/cx25821-video4.c
+++ /dev/null
@@ -1,434 +0,0 @@
-/*
- * Driver for the Conexant CX25821 PCIe bridge
- *
- * Copyright (C) 2009 Conexant Systems Inc.
- * Authors <shu.lin@conexant.com>, <hiep.huynh@conexant.com>
- * Based on Steven Toth <stoth@linuxtv.org> cx23885 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 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 "cx25821-video.h"
-
-static void buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
-{
- struct cx25821_buffer *buf =
- container_of(vb, struct cx25821_buffer, vb);
- struct cx25821_buffer *prev;
- struct cx25821_fh *fh = vq->priv_data;
- struct cx25821_dev *dev = fh->dev;
- struct cx25821_dmaqueue *q = &dev->vidq[SRAM_CH04];
-
- /* add jump to stopper */
- buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC);
- buf->risc.jmp[1] = cpu_to_le32(q->stopper.dma);
- buf->risc.jmp[2] = cpu_to_le32(0); /* bits 63-32 */
-
- dprintk(2, "jmp to stopper (0x%x)\n", buf->risc.jmp[1]);
-
- if (!list_empty(&q->queued)) {
- list_add_tail(&buf->vb.queue, &q->queued);
- buf->vb.state = VIDEOBUF_QUEUED;
- dprintk(2, "[%p/%d] buffer_queue - append to queued\n", buf,
- buf->vb.i);
-
- } else if (list_empty(&q->active)) {
- list_add_tail(&buf->vb.queue, &q->active);
- cx25821_start_video_dma(dev, q, buf,
- &dev->sram_channels[SRAM_CH04]);
- buf->vb.state = VIDEOBUF_ACTIVE;
- buf->count = q->count++;
- mod_timer(&q->timeout, jiffies + BUFFER_TIMEOUT);
- dprintk(2,
- "[%p/%d] buffer_queue - first active, buf cnt = %d, q->count = %d\n",
- buf, buf->vb.i, buf->count, q->count);
- } else {
- prev =
- list_entry(q->active.prev, struct cx25821_buffer, vb.queue);
- if (prev->vb.width == buf->vb.width
- && prev->vb.height == buf->vb.height
- && prev->fmt == buf->fmt) {
- list_add_tail(&buf->vb.queue, &q->active);
- buf->vb.state = VIDEOBUF_ACTIVE;
- buf->count = q->count++;
- prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
-
- /* 64 bit bits 63-32 */
- prev->risc.jmp[2] = cpu_to_le32(0);
- dprintk(2,
- "[%p/%d] buffer_queue - append to active, buf->count=%d\n",
- buf, buf->vb.i, buf->count);
-
- } else {
- list_add_tail(&buf->vb.queue, &q->queued);
- buf->vb.state = VIDEOBUF_QUEUED;
- dprintk(2, "[%p/%d] buffer_queue - first queued\n", buf,
- buf->vb.i);
- }
- }
-
- if (list_empty(&q->active)) {
- dprintk(2, "active queue empty!\n");
- }
-}
-
-static struct videobuf_queue_ops cx25821_video_qops = {
- .buf_setup = cx25821_buffer_setup,
- .buf_prepare = cx25821_buffer_prepare,
- .buf_queue = buffer_queue,
- .buf_release = cx25821_buffer_release,
-};
-
-static int video_open(struct file *file)
-{
- struct video_device *vdev = video_devdata(file);
- struct cx25821_dev *dev = video_drvdata(file);
- struct cx25821_fh *fh;
- enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- u32 pix_format;
-
- printk("open dev=%s type=%s\n", video_device_node_name(vdev),
- v4l2_type_names[type]);
-
- /* allocate + initialize per filehandle data */
- fh = kzalloc(sizeof(*fh), GFP_KERNEL);
- if (NULL == fh)
- return -ENOMEM;
-
- lock_kernel();
-
- file->private_data = fh;
- fh->dev = dev;
- fh->type = type;
- fh->width = 720;
-
- if (dev->tvnorm & V4L2_STD_PAL_BG || dev->tvnorm & V4L2_STD_PAL_DK)
- fh->height = 576;
- else
- fh->height = 480;
-
- dev->channel_opened = SRAM_CH04;
- pix_format =
- (dev->pixel_formats[dev->channel_opened] ==
- PIXEL_FRMT_411) ? V4L2_PIX_FMT_Y41P : V4L2_PIX_FMT_YUYV;
- fh->fmt = format_by_fourcc(pix_format);
-
- v4l2_prio_open(&dev->prio, &fh->prio);
- videobuf_queue_sg_init(&fh->vidq, &cx25821_video_qops,
- &dev->pci->dev, &dev->slock,
- V4L2_BUF_TYPE_VIDEO_CAPTURE,
- V4L2_FIELD_INTERLACED,
- sizeof(struct cx25821_buffer), fh);
-
- dprintk(1, "post videobuf_queue_init()\n");
- unlock_kernel();
-
- return 0;
-}
-
-static ssize_t video_read(struct file *file, char __user * data, size_t count,
- loff_t * ppos)
-{
- struct cx25821_fh *fh = file->private_data;
-
- switch (fh->type) {
- case V4L2_BUF_TYPE_VIDEO_CAPTURE:
- if (cx25821_res_locked(fh->dev, RESOURCE_VIDEO4))
- return -EBUSY;
-
- return videobuf_read_one(&fh->vidq, data, count, ppos,
- file->f_flags & O_NONBLOCK);
-
- default:
- BUG();
- return 0;
- }
-}
-
-static unsigned int video_poll(struct file *file,
- struct poll_table_struct *wait)
-{
- struct cx25821_fh *fh = file->private_data;
- struct cx25821_buffer *buf;
-
- if (cx25821_res_check(fh, RESOURCE_VIDEO4)) {
- /* streaming capture */
- if (list_empty(&fh->vidq.stream))
- return POLLERR;
- buf = list_entry(fh->vidq.stream.next,
- struct cx25821_buffer, vb.stream);
- } else {
- /* read() capture */
- buf = (struct cx25821_buffer *)fh->vidq.read_buf;
- if (NULL == buf)
- return POLLERR;
- }
-
- poll_wait(file, &buf->vb.done, wait);
- if (buf->vb.state == VIDEOBUF_DONE || buf->vb.state == VIDEOBUF_ERROR) {
- if (buf->vb.state == VIDEOBUF_DONE) {
- struct cx25821_dev *dev = fh->dev;
-
- if (dev && dev->use_cif_resolution[SRAM_CH04]) {
- u8 cam_id = *((char *)buf->vb.baddr + 3);
- memcpy((char *)buf->vb.baddr,
- (char *)buf->vb.baddr + (fh->width * 2),
- (fh->width * 2));
- *((char *)buf->vb.baddr + 3) = cam_id;
- }
- }
-
- return POLLIN | POLLRDNORM;
- }
-
- return 0;
-}
-
-static int video_release(struct file *file)
-{
- struct cx25821_fh *fh = file->private_data;
- struct cx25821_dev *dev = fh->dev;
-
- //stop the risc engine and fifo
- cx_write(channel4->dma_ctl, 0); /* FIFO and RISC disable */
-
- /* stop video capture */
- if (cx25821_res_check(fh, RESOURCE_VIDEO4)) {
- videobuf_queue_cancel(&fh->vidq);
- cx25821_res_free(dev, fh, RESOURCE_VIDEO4);
- }
-
- if (fh->vidq.read_buf) {
- cx25821_buffer_release(&fh->vidq, fh->vidq.read_buf);
- kfree(fh->vidq.read_buf);
- }
-
- videobuf_mmap_free(&fh->vidq);
-
- v4l2_prio_close(&dev->prio, fh->prio);
- file->private_data = NULL;
- kfree(fh);
-
- return 0;
-}
-
-static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
-{
- struct cx25821_fh *fh = priv;
- struct cx25821_dev *dev = fh->dev;
-
- if (unlikely(fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)) {
- return -EINVAL;
- }
-
- if (unlikely(i != fh->type)) {
- return -EINVAL;
- }
-
- if (unlikely(!cx25821_res_get(dev, fh, cx25821_get_resource(fh, RESOURCE_VIDEO4)))) {
- return -EBUSY;
- }
-
- return videobuf_streamon(get_queue(fh));
-}
-
-static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
-{
- struct cx25821_fh *fh = priv;
- struct cx25821_dev *dev = fh->dev;
- int err, res;
-
- if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
- if (i != fh->type)
- return -EINVAL;
-
- res = cx25821_get_resource(fh, RESOURCE_VIDEO4);
- err = videobuf_streamoff(get_queue(fh));
- if (err < 0)
- return err;
- cx25821_res_free(dev, fh, res);
- return 0;
-}
-
-static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
- struct v4l2_format *f)
-{
- struct cx25821_fh *fh = priv;
- struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
- int err;
- int pix_format = 0;
-
- // check priority
- if (fh) {
- err = v4l2_prio_check(&dev->prio, fh->prio);
- if (0 != err)
- return err;
- }
- dprintk(2, "%s()\n", __func__);
- err = cx25821_vidioc_try_fmt_vid_cap(file, priv, f);
-
- if (0 != err)
- return err;
-
- fh->fmt = format_by_fourcc(f->fmt.pix.pixelformat);
- fh->vidq.field = f->fmt.pix.field;
-
- // check if width and height is valid based on set standard
- if (cx25821_is_valid_width(f->fmt.pix.width, dev->tvnorm)) {
- fh->width = f->fmt.pix.width;
- }
-
- if (cx25821_is_valid_height(f->fmt.pix.height, dev->tvnorm)) {
- fh->height = f->fmt.pix.height;
- }
-
- if (f->fmt.pix.pixelformat == V4L2_PIX_FMT_Y41P)
- pix_format = PIXEL_FRMT_411;
- else if (f->fmt.pix.pixelformat == V4L2_PIX_FMT_YUYV)
- pix_format = PIXEL_FRMT_422;
- else
- return -EINVAL;
-
- cx25821_set_pixel_format(dev, SRAM_CH04, pix_format);
-
- // check if cif resolution
- if (fh->width == 320 || fh->width == 352) {
- dev->use_cif_resolution[SRAM_CH04] = 1;
- } else {
- dev->use_cif_resolution[SRAM_CH04] = 0;
- }
- dev->cif_width[SRAM_CH04] = fh->width;
- medusa_set_resolution(dev, fh->width, SRAM_CH04);
-
- dprintk(2, "%s() width=%d height=%d field=%d\n", __func__, fh->width,
- fh->height, fh->vidq.field);
- cx25821_call_all(dev, video, s_fmt, f);
-
- return 0;
-}
-
-static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p)
-{
- int ret_val = 0;
- struct cx25821_fh *fh = priv;
- struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
-
- ret_val = videobuf_dqbuf(get_queue(fh), p, file->f_flags & O_NONBLOCK);
-
- p->sequence = dev->vidq[SRAM_CH04].count;
-
- return ret_val;
-}
-
-static int vidioc_log_status(struct file *file, void *priv)
-{
- struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
- char name[32 + 2];
-
- struct sram_channel *sram_ch = &dev->sram_channels[SRAM_CH04];
- u32 tmp = 0;
-
- snprintf(name, sizeof(name), "%s/2", dev->name);
- printk(KERN_INFO "%s/2: ============ START LOG STATUS ============\n",
- dev->name);
- cx25821_call_all(dev, core, log_status);
-
- tmp = cx_read(sram_ch->dma_ctl);
- printk(KERN_INFO "Video input 4 is %s\n",
- (tmp & 0x11) ? "streaming" : "stopped");
- printk(KERN_INFO "%s/2: ============= END LOG STATUS =============\n",
- dev->name);
- return 0;
-}
-
-static int vidioc_s_ctrl(struct file *file, void *priv,
- struct v4l2_control *ctl)
-{
- struct cx25821_fh *fh = priv;
- struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
- int err;
-
- if (fh) {
- err = v4l2_prio_check(&dev->prio, fh->prio);
- if (0 != err)
- return err;
- }
-
- return cx25821_set_control(dev, ctl, SRAM_CH04);
-}
-
-// exported stuff
-static const struct v4l2_file_operations video_fops = {
- .owner = THIS_MODULE,
- .open = video_open,
- .release = video_release,
- .read = video_read,
- .poll = video_poll,
- .mmap = cx25821_video_mmap,
- .ioctl = video_ioctl2,
-};
-
-static const struct v4l2_ioctl_ops video_ioctl_ops = {
- .vidioc_querycap = cx25821_vidioc_querycap,
- .vidioc_enum_fmt_vid_cap = cx25821_vidioc_enum_fmt_vid_cap,
- .vidioc_g_fmt_vid_cap = cx25821_vidioc_g_fmt_vid_cap,
- .vidioc_try_fmt_vid_cap = cx25821_vidioc_try_fmt_vid_cap,
- .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
- .vidioc_reqbufs = cx25821_vidioc_reqbufs,
- .vidioc_querybuf = cx25821_vidioc_querybuf,
- .vidioc_qbuf = cx25821_vidioc_qbuf,
- .vidioc_dqbuf = vidioc_dqbuf,
-#ifdef TUNER_FLAG
- .vidioc_s_std = cx25821_vidioc_s_std,
- .vidioc_querystd = cx25821_vidioc_querystd,
-#endif
- .vidioc_cropcap = cx25821_vidioc_cropcap,
- .vidioc_s_crop = cx25821_vidioc_s_crop,
- .vidioc_g_crop = cx25821_vidioc_g_crop,
- .vidioc_enum_input = cx25821_vidioc_enum_input,
- .vidioc_g_input = cx25821_vidioc_g_input,
- .vidioc_s_input = cx25821_vidioc_s_input,
- .vidioc_g_ctrl = cx25821_vidioc_g_ctrl,
- .vidioc_s_ctrl = vidioc_s_ctrl,
- .vidioc_queryctrl = cx25821_vidioc_queryctrl,
- .vidioc_streamon = vidioc_streamon,
- .vidioc_streamoff = vidioc_streamoff,
- .vidioc_log_status = vidioc_log_status,
- .vidioc_g_priority = cx25821_vidioc_g_priority,
- .vidioc_s_priority = cx25821_vidioc_s_priority,
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
- .vidiocgmbuf = cx25821_vidiocgmbuf,
-#endif
-#ifdef TUNER_FLAG
- .vidioc_g_tuner = cx25821_vidioc_g_tuner,
- .vidioc_s_tuner = cx25821_vidioc_s_tuner,
- .vidioc_g_frequency = cx25821_vidioc_g_frequency,
- .vidioc_s_frequency = cx25821_vidioc_s_frequency,
-#endif
-#ifdef CONFIG_VIDEO_ADV_DEBUG
- .vidioc_g_register = cx25821_vidioc_g_register,
- .vidioc_s_register = cx25821_vidioc_s_register,
-#endif
-};
-
-struct video_device cx25821_video_template4 = {
- .name = "cx25821-video",
- .fops = &video_fops,
- .ioctl_ops = &video_ioctl_ops,
- .tvnorms = CX25821_NORMS,
- .current_norm = V4L2_STD_NTSC_M,
-};
diff --git a/drivers/staging/cx25821/cx25821-video5.c b/drivers/staging/cx25821/cx25821-video5.c
deleted file mode 100644
index 59370337b07..00000000000
--- a/drivers/staging/cx25821/cx25821-video5.c
+++ /dev/null
@@ -1,434 +0,0 @@
-/*
- * Driver for the Conexant CX25821 PCIe bridge
- *
- * Copyright (C) 2009 Conexant Systems Inc.
- * Authors <shu.lin@conexant.com>, <hiep.huynh@conexant.com>
- * Based on Steven Toth <stoth@linuxtv.org> cx23885 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 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 "cx25821-video.h"
-
-static void buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
-{
- struct cx25821_buffer *buf =
- container_of(vb, struct cx25821_buffer, vb);
- struct cx25821_buffer *prev;
- struct cx25821_fh *fh = vq->priv_data;
- struct cx25821_dev *dev = fh->dev;
- struct cx25821_dmaqueue *q = &dev->vidq[SRAM_CH05];
-
- /* add jump to stopper */
- buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC);
- buf->risc.jmp[1] = cpu_to_le32(q->stopper.dma);
- buf->risc.jmp[2] = cpu_to_le32(0); /* bits 63-32 */
-
- dprintk(2, "jmp to stopper (0x%x)\n", buf->risc.jmp[1]);
-
- if (!list_empty(&q->queued)) {
- list_add_tail(&buf->vb.queue, &q->queued);
- buf->vb.state = VIDEOBUF_QUEUED;
- dprintk(2, "[%p/%d] buffer_queue - append to queued\n", buf,
- buf->vb.i);
-
- } else if (list_empty(&q->active)) {
- list_add_tail(&buf->vb.queue, &q->active);
- cx25821_start_video_dma(dev, q, buf,
- &dev->sram_channels[SRAM_CH05]);
- buf->vb.state = VIDEOBUF_ACTIVE;
- buf->count = q->count++;
- mod_timer(&q->timeout, jiffies + BUFFER_TIMEOUT);
- dprintk(2,
- "[%p/%d] buffer_queue - first active, buf cnt = %d, q->count = %d\n",
- buf, buf->vb.i, buf->count, q->count);
- } else {
- prev =
- list_entry(q->active.prev, struct cx25821_buffer, vb.queue);
- if (prev->vb.width == buf->vb.width
- && prev->vb.height == buf->vb.height
- && prev->fmt == buf->fmt) {
- list_add_tail(&buf->vb.queue, &q->active);
- buf->vb.state = VIDEOBUF_ACTIVE;
- buf->count = q->count++;
- prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
-
- /* 64 bit bits 63-32 */
- prev->risc.jmp[2] = cpu_to_le32(0);
- dprintk(2,
- "[%p/%d] buffer_queue - append to active, buf->count=%d\n",
- buf, buf->vb.i, buf->count);
-
- } else {
- list_add_tail(&buf->vb.queue, &q->queued);
- buf->vb.state = VIDEOBUF_QUEUED;
- dprintk(2, "[%p/%d] buffer_queue - first queued\n", buf,
- buf->vb.i);
- }
- }
-
- if (list_empty(&q->active)) {
- dprintk(2, "active queue empty!\n");
- }
-}
-
-static struct videobuf_queue_ops cx25821_video_qops = {
- .buf_setup = cx25821_buffer_setup,
- .buf_prepare = cx25821_buffer_prepare,
- .buf_queue = buffer_queue,
- .buf_release = cx25821_buffer_release,
-};
-
-static int video_open(struct file *file)
-{
- struct video_device *vdev = video_devdata(file);
- struct cx25821_dev *dev = video_drvdata(file);
- struct cx25821_fh *fh;
- enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- u32 pix_format;
-
- printk("open dev=%s type=%s\n", video_device_node_name(vdev),
- v4l2_type_names[type]);
-
- /* allocate + initialize per filehandle data */
- fh = kzalloc(sizeof(*fh), GFP_KERNEL);
- if (NULL == fh)
- return -ENOMEM;
-
- lock_kernel();
-
- file->private_data = fh;
- fh->dev = dev;
- fh->type = type;
- fh->width = 720;
-
- if (dev->tvnorm & V4L2_STD_PAL_BG || dev->tvnorm & V4L2_STD_PAL_DK)
- fh->height = 576;
- else
- fh->height = 480;
-
- dev->channel_opened = SRAM_CH05;
- pix_format =
- (dev->pixel_formats[dev->channel_opened] ==
- PIXEL_FRMT_411) ? V4L2_PIX_FMT_Y41P : V4L2_PIX_FMT_YUYV;
- fh->fmt = format_by_fourcc(pix_format);
-
- v4l2_prio_open(&dev->prio, &fh->prio);
-
- videobuf_queue_sg_init(&fh->vidq, &cx25821_video_qops,
- &dev->pci->dev, &dev->slock,
- V4L2_BUF_TYPE_VIDEO_CAPTURE,
- V4L2_FIELD_INTERLACED,
- sizeof(struct cx25821_buffer), fh);
-
- dprintk(1, "post videobuf_queue_init()\n");
- unlock_kernel();
-
- return 0;
-}
-
-static ssize_t video_read(struct file *file, char __user * data, size_t count,
- loff_t * ppos)
-{
- struct cx25821_fh *fh = file->private_data;
-
- switch (fh->type) {
- case V4L2_BUF_TYPE_VIDEO_CAPTURE:
- if (cx25821_res_locked(fh->dev, RESOURCE_VIDEO5))
- return -EBUSY;
-
- return videobuf_read_one(&fh->vidq, data, count, ppos,
- file->f_flags & O_NONBLOCK);
-
- default:
- BUG();
- return 0;
- }
-}
-
-static unsigned int video_poll(struct file *file,
- struct poll_table_struct *wait)
-{
- struct cx25821_fh *fh = file->private_data;
- struct cx25821_buffer *buf;
-
- if (cx25821_res_check(fh, RESOURCE_VIDEO5)) {
- /* streaming capture */
- if (list_empty(&fh->vidq.stream))
- return POLLERR;
- buf = list_entry(fh->vidq.stream.next,
- struct cx25821_buffer, vb.stream);
- } else {
- /* read() capture */
- buf = (struct cx25821_buffer *)fh->vidq.read_buf;
- if (NULL == buf)
- return POLLERR;
- }
-
- poll_wait(file, &buf->vb.done, wait);
- if (buf->vb.state == VIDEOBUF_DONE || buf->vb.state == VIDEOBUF_ERROR) {
- if (buf->vb.state == VIDEOBUF_DONE) {
- struct cx25821_dev *dev = fh->dev;
-
- if (dev && dev->use_cif_resolution[SRAM_CH05]) {
- u8 cam_id = *((char *)buf->vb.baddr + 3);
- memcpy((char *)buf->vb.baddr,
- (char *)buf->vb.baddr + (fh->width * 2),
- (fh->width * 2));
- *((char *)buf->vb.baddr + 3) = cam_id;
- }
- }
-
- return POLLIN | POLLRDNORM;
- }
-
- return 0;
-}
-
-static int video_release(struct file *file)
-{
- struct cx25821_fh *fh = file->private_data;
- struct cx25821_dev *dev = fh->dev;
-
- //stop the risc engine and fifo
- cx_write(channel5->dma_ctl, 0); /* FIFO and RISC disable */
-
- /* stop video capture */
- if (cx25821_res_check(fh, RESOURCE_VIDEO5)) {
- videobuf_queue_cancel(&fh->vidq);
- cx25821_res_free(dev, fh, RESOURCE_VIDEO5);
- }
-
- if (fh->vidq.read_buf) {
- cx25821_buffer_release(&fh->vidq, fh->vidq.read_buf);
- kfree(fh->vidq.read_buf);
- }
-
- videobuf_mmap_free(&fh->vidq);
-
- v4l2_prio_close(&dev->prio, fh->prio);
- file->private_data = NULL;
- kfree(fh);
-
- return 0;
-}
-
-static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
-{
- struct cx25821_fh *fh = priv;
- struct cx25821_dev *dev = fh->dev;
-
- if (unlikely(fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)) {
- return -EINVAL;
- }
-
- if (unlikely(i != fh->type)) {
- return -EINVAL;
- }
-
- if (unlikely(!cx25821_res_get(dev, fh, cx25821_get_resource(fh, RESOURCE_VIDEO5)))) {
- return -EBUSY;
- }
-
- return videobuf_streamon(get_queue(fh));
-}
-
-static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
-{
- struct cx25821_fh *fh = priv;
- struct cx25821_dev *dev = fh->dev;
- int err, res;
-
- if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
- if (i != fh->type)
- return -EINVAL;
-
- res = cx25821_get_resource(fh, RESOURCE_VIDEO5);
- err = videobuf_streamoff(get_queue(fh));
- if (err < 0)
- return err;
- cx25821_res_free(dev, fh, res);
- return 0;
-}
-
-static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
- struct v4l2_format *f)
-{
- struct cx25821_fh *fh = priv;
- struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
- int err;
- int pix_format = 0;
-
- if (fh) {
- err = v4l2_prio_check(&dev->prio, fh->prio);
- if (0 != err)
- return err;
- }
-
- dprintk(2, "%s()\n", __func__);
- err = cx25821_vidioc_try_fmt_vid_cap(file, priv, f);
-
- if (0 != err)
- return err;
-
- fh->fmt = format_by_fourcc(f->fmt.pix.pixelformat);
- fh->vidq.field = f->fmt.pix.field;
-
- // check if width and height is valid based on set standard
- if (cx25821_is_valid_width(f->fmt.pix.width, dev->tvnorm)) {
- fh->width = f->fmt.pix.width;
- }
-
- if (cx25821_is_valid_height(f->fmt.pix.height, dev->tvnorm)) {
- fh->height = f->fmt.pix.height;
- }
-
- if (f->fmt.pix.pixelformat == V4L2_PIX_FMT_Y41P)
- pix_format = PIXEL_FRMT_411;
- else if (f->fmt.pix.pixelformat == V4L2_PIX_FMT_YUYV)
- pix_format = PIXEL_FRMT_422;
- else
- return -EINVAL;
-
- cx25821_set_pixel_format(dev, SRAM_CH05, pix_format);
-
- // check if cif resolution
- if (fh->width == 320 || fh->width == 352) {
- dev->use_cif_resolution[SRAM_CH05] = 1;
- } else {
- dev->use_cif_resolution[SRAM_CH05] = 0;
- }
- dev->cif_width[SRAM_CH05] = fh->width;
- medusa_set_resolution(dev, fh->width, SRAM_CH05);
-
- dprintk(2, "%s() width=%d height=%d field=%d\n", __func__, fh->width,
- fh->height, fh->vidq.field);
- cx25821_call_all(dev, video, s_fmt, f);
-
- return 0;
-}
-
-static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p)
-{
- int ret_val = 0;
- struct cx25821_fh *fh = priv;
- struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
-
- ret_val = videobuf_dqbuf(get_queue(fh), p, file->f_flags & O_NONBLOCK);
-
- p->sequence = dev->vidq[SRAM_CH05].count;
-
- return ret_val;
-}
-static int vidioc_log_status(struct file *file, void *priv)
-{
- struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
- char name[32 + 2];
-
- struct sram_channel *sram_ch = &dev->sram_channels[SRAM_CH05];
- u32 tmp = 0;
-
- snprintf(name, sizeof(name), "%s/2", dev->name);
- printk(KERN_INFO "%s/2: ============ START LOG STATUS ============\n",
- dev->name);
- cx25821_call_all(dev, core, log_status);
-
- tmp = cx_read(sram_ch->dma_ctl);
- printk(KERN_INFO "Video input 5 is %s\n",
- (tmp & 0x11) ? "streaming" : "stopped");
- printk(KERN_INFO "%s/2: ============= END LOG STATUS =============\n",
- dev->name);
- return 0;
-}
-
-static int vidioc_s_ctrl(struct file *file, void *priv,
- struct v4l2_control *ctl)
-{
- struct cx25821_fh *fh = priv;
- struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
- int err;
-
- if (fh) {
- err = v4l2_prio_check(&dev->prio, fh->prio);
- if (0 != err)
- return err;
- }
-
- return cx25821_set_control(dev, ctl, SRAM_CH05);
-}
-
-// exported stuff
-static const struct v4l2_file_operations video_fops = {
- .owner = THIS_MODULE,
- .open = video_open,
- .release = video_release,
- .read = video_read,
- .poll = video_poll,
- .mmap = cx25821_video_mmap,
- .ioctl = video_ioctl2,
-};
-
-static const struct v4l2_ioctl_ops video_ioctl_ops = {
- .vidioc_querycap = cx25821_vidioc_querycap,
- .vidioc_enum_fmt_vid_cap = cx25821_vidioc_enum_fmt_vid_cap,
- .vidioc_g_fmt_vid_cap = cx25821_vidioc_g_fmt_vid_cap,
- .vidioc_try_fmt_vid_cap = cx25821_vidioc_try_fmt_vid_cap,
- .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
- .vidioc_reqbufs = cx25821_vidioc_reqbufs,
- .vidioc_querybuf = cx25821_vidioc_querybuf,
- .vidioc_qbuf = cx25821_vidioc_qbuf,
- .vidioc_dqbuf = vidioc_dqbuf,
-#ifdef TUNER_FLAG
- .vidioc_s_std = cx25821_vidioc_s_std,
- .vidioc_querystd = cx25821_vidioc_querystd,
-#endif
- .vidioc_cropcap = cx25821_vidioc_cropcap,
- .vidioc_s_crop = cx25821_vidioc_s_crop,
- .vidioc_g_crop = cx25821_vidioc_g_crop,
- .vidioc_enum_input = cx25821_vidioc_enum_input,
- .vidioc_g_input = cx25821_vidioc_g_input,
- .vidioc_s_input = cx25821_vidioc_s_input,
- .vidioc_g_ctrl = cx25821_vidioc_g_ctrl,
- .vidioc_s_ctrl = vidioc_s_ctrl,
- .vidioc_queryctrl = cx25821_vidioc_queryctrl,
- .vidioc_streamon = vidioc_streamon,
- .vidioc_streamoff = vidioc_streamoff,
- .vidioc_log_status = vidioc_log_status,
- .vidioc_g_priority = cx25821_vidioc_g_priority,
- .vidioc_s_priority = cx25821_vidioc_s_priority,
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
- .vidiocgmbuf = cx25821_vidiocgmbuf,
-#endif
-#ifdef TUNER_FLAG
- .vidioc_g_tuner = cx25821_vidioc_g_tuner,
- .vidioc_s_tuner = cx25821_vidioc_s_tuner,
- .vidioc_g_frequency = cx25821_vidioc_g_frequency,
- .vidioc_s_frequency = cx25821_vidioc_s_frequency,
-#endif
-#ifdef CONFIG_VIDEO_ADV_DEBUG
- .vidioc_g_register = cx25821_vidioc_g_register,
- .vidioc_s_register = cx25821_vidioc_s_register,
-#endif
-};
-
-struct video_device cx25821_video_template5 = {
- .name = "cx25821-video",
- .fops = &video_fops,
- .ioctl_ops = &video_ioctl_ops,
- .tvnorms = CX25821_NORMS,
- .current_norm = V4L2_STD_NTSC_M,
-};
diff --git a/drivers/staging/cx25821/cx25821-video6.c b/drivers/staging/cx25821/cx25821-video6.c
deleted file mode 100644
index 4db2eb83d35..00000000000
--- a/drivers/staging/cx25821/cx25821-video6.c
+++ /dev/null
@@ -1,434 +0,0 @@
-/*
- * Driver for the Conexant CX25821 PCIe bridge
- *
- * Copyright (C) 2009 Conexant Systems Inc.
- * Authors <shu.lin@conexant.com>, <hiep.huynh@conexant.com>
- * Based on Steven Toth <stoth@linuxtv.org> cx23885 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 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 "cx25821-video.h"
-
-static void buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
-{
- struct cx25821_buffer *buf =
- container_of(vb, struct cx25821_buffer, vb);
- struct cx25821_buffer *prev;
- struct cx25821_fh *fh = vq->priv_data;
- struct cx25821_dev *dev = fh->dev;
- struct cx25821_dmaqueue *q = &dev->vidq[SRAM_CH06];
-
- /* add jump to stopper */
- buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC);
- buf->risc.jmp[1] = cpu_to_le32(q->stopper.dma);
- buf->risc.jmp[2] = cpu_to_le32(0); /* bits 63-32 */
-
- dprintk(2, "jmp to stopper (0x%x)\n", buf->risc.jmp[1]);
-
- if (!list_empty(&q->queued)) {
- list_add_tail(&buf->vb.queue, &q->queued);
- buf->vb.state = VIDEOBUF_QUEUED;
- dprintk(2, "[%p/%d] buffer_queue - append to queued\n", buf,
- buf->vb.i);
-
- } else if (list_empty(&q->active)) {
- list_add_tail(&buf->vb.queue, &q->active);
- cx25821_start_video_dma(dev, q, buf,
- &dev->sram_channels[SRAM_CH06]);
- buf->vb.state = VIDEOBUF_ACTIVE;
- buf->count = q->count++;
- mod_timer(&q->timeout, jiffies + BUFFER_TIMEOUT);
- dprintk(2,
- "[%p/%d] buffer_queue - first active, buf cnt = %d, q->count = %d\n",
- buf, buf->vb.i, buf->count, q->count);
- } else {
- prev =
- list_entry(q->active.prev, struct cx25821_buffer, vb.queue);
- if (prev->vb.width == buf->vb.width
- && prev->vb.height == buf->vb.height
- && prev->fmt == buf->fmt) {
- list_add_tail(&buf->vb.queue, &q->active);
- buf->vb.state = VIDEOBUF_ACTIVE;
- buf->count = q->count++;
- prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
-
- /* 64 bit bits 63-32 */
- prev->risc.jmp[2] = cpu_to_le32(0);
- dprintk(2,
- "[%p/%d] buffer_queue - append to active, buf->count=%d\n",
- buf, buf->vb.i, buf->count);
-
- } else {
- list_add_tail(&buf->vb.queue, &q->queued);
- buf->vb.state = VIDEOBUF_QUEUED;
- dprintk(2, "[%p/%d] buffer_queue - first queued\n", buf,
- buf->vb.i);
- }
- }
-
- if (list_empty(&q->active)) {
- dprintk(2, "active queue empty!\n");
- }
-}
-
-static struct videobuf_queue_ops cx25821_video_qops = {
- .buf_setup = cx25821_buffer_setup,
- .buf_prepare = cx25821_buffer_prepare,
- .buf_queue = buffer_queue,
- .buf_release = cx25821_buffer_release,
-};
-
-static int video_open(struct file *file)
-{
- struct video_device *vdev = video_devdata(file);
- struct cx25821_dev *dev = video_drvdata(file);
- struct cx25821_fh *fh;
- enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- u32 pix_format;
-
- printk("open dev=%s type=%s\n", video_device_node_name(vdev),
- v4l2_type_names[type]);
-
- /* allocate + initialize per filehandle data */
- fh = kzalloc(sizeof(*fh), GFP_KERNEL);
- if (NULL == fh)
- return -ENOMEM;
-
- lock_kernel();
-
- file->private_data = fh;
- fh->dev = dev;
- fh->type = type;
- fh->width = 720;
-
- if (dev->tvnorm & V4L2_STD_PAL_BG || dev->tvnorm & V4L2_STD_PAL_DK)
- fh->height = 576;
- else
- fh->height = 480;
-
- dev->channel_opened = SRAM_CH06;
- pix_format =
- (dev->pixel_formats[dev->channel_opened] ==
- PIXEL_FRMT_411) ? V4L2_PIX_FMT_Y41P : V4L2_PIX_FMT_YUYV;
- fh->fmt = format_by_fourcc(pix_format);
-
- v4l2_prio_open(&dev->prio, &fh->prio);
-
- videobuf_queue_sg_init(&fh->vidq, &cx25821_video_qops,
- &dev->pci->dev, &dev->slock,
- V4L2_BUF_TYPE_VIDEO_CAPTURE,
- V4L2_FIELD_INTERLACED,
- sizeof(struct cx25821_buffer), fh);
-
- dprintk(1, "post videobuf_queue_init()\n");
- unlock_kernel();
-
- return 0;
-}
-
-static ssize_t video_read(struct file *file, char __user * data, size_t count,
- loff_t * ppos)
-{
- struct cx25821_fh *fh = file->private_data;
-
- switch (fh->type) {
- case V4L2_BUF_TYPE_VIDEO_CAPTURE:
- if (cx25821_res_locked(fh->dev, RESOURCE_VIDEO6))
- return -EBUSY;
-
- return videobuf_read_one(&fh->vidq, data, count, ppos,
- file->f_flags & O_NONBLOCK);
-
- default:
- BUG();
- return 0;
- }
-}
-
-static unsigned int video_poll(struct file *file,
- struct poll_table_struct *wait)
-{
- struct cx25821_fh *fh = file->private_data;
- struct cx25821_buffer *buf;
-
- if (cx25821_res_check(fh, RESOURCE_VIDEO6)) {
- /* streaming capture */
- if (list_empty(&fh->vidq.stream))
- return POLLERR;
- buf = list_entry(fh->vidq.stream.next,
- struct cx25821_buffer, vb.stream);
- } else {
- /* read() capture */
- buf = (struct cx25821_buffer *)fh->vidq.read_buf;
- if (NULL == buf)
- return POLLERR;
- }
-
- poll_wait(file, &buf->vb.done, wait);
- if (buf->vb.state == VIDEOBUF_DONE || buf->vb.state == VIDEOBUF_ERROR) {
- if (buf->vb.state == VIDEOBUF_DONE) {
- struct cx25821_dev *dev = fh->dev;
-
- if (dev && dev->use_cif_resolution[SRAM_CH06]) {
- u8 cam_id = *((char *)buf->vb.baddr + 3);
- memcpy((char *)buf->vb.baddr,
- (char *)buf->vb.baddr + (fh->width * 2),
- (fh->width * 2));
- *((char *)buf->vb.baddr + 3) = cam_id;
- }
- }
-
- return POLLIN | POLLRDNORM;
- }
-
- return 0;
-}
-
-static int video_release(struct file *file)
-{
- struct cx25821_fh *fh = file->private_data;
- struct cx25821_dev *dev = fh->dev;
-
- //stop the risc engine and fifo
- cx_write(channel6->dma_ctl, 0); /* FIFO and RISC disable */
-
- /* stop video capture */
- if (cx25821_res_check(fh, RESOURCE_VIDEO6)) {
- videobuf_queue_cancel(&fh->vidq);
- cx25821_res_free(dev, fh, RESOURCE_VIDEO6);
- }
- if (fh->vidq.read_buf) {
- cx25821_buffer_release(&fh->vidq, fh->vidq.read_buf);
- kfree(fh->vidq.read_buf);
- }
-
- videobuf_mmap_free(&fh->vidq);
-
- v4l2_prio_close(&dev->prio, fh->prio);
- file->private_data = NULL;
- kfree(fh);
-
- return 0;
-}
-
-static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
-{
- struct cx25821_fh *fh = priv;
- struct cx25821_dev *dev = fh->dev;
-
- if (unlikely(fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)) {
- return -EINVAL;
- }
-
- if (unlikely(i != fh->type)) {
- return -EINVAL;
- }
-
- if (unlikely(!cx25821_res_get(dev, fh, cx25821_get_resource(fh, RESOURCE_VIDEO6)))) {
- return -EBUSY;
- }
-
- return videobuf_streamon(get_queue(fh));
-}
-
-static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
-{
- struct cx25821_fh *fh = priv;
- struct cx25821_dev *dev = fh->dev;
- int err, res;
-
- if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
- if (i != fh->type)
- return -EINVAL;
-
- res = cx25821_get_resource(fh, RESOURCE_VIDEO6);
- err = videobuf_streamoff(get_queue(fh));
- if (err < 0)
- return err;
- cx25821_res_free(dev, fh, res);
- return 0;
-}
-
-static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
- struct v4l2_format *f)
-{
- struct cx25821_fh *fh = priv;
- struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
- int err;
- int pix_format = 0;
-
- if (fh) {
- err = v4l2_prio_check(&dev->prio, fh->prio);
- if (0 != err)
- return err;
- }
-
- dprintk(2, "%s()\n", __func__);
- err = cx25821_vidioc_try_fmt_vid_cap(file, priv, f);
-
- if (0 != err)
- return err;
-
- fh->fmt = format_by_fourcc(f->fmt.pix.pixelformat);
- fh->vidq.field = f->fmt.pix.field;
-
- // check if width and height is valid based on set standard
- if (cx25821_is_valid_width(f->fmt.pix.width, dev->tvnorm)) {
- fh->width = f->fmt.pix.width;
- }
-
- if (cx25821_is_valid_height(f->fmt.pix.height, dev->tvnorm)) {
- fh->height = f->fmt.pix.height;
- }
-
- if (f->fmt.pix.pixelformat == V4L2_PIX_FMT_Y41P)
- pix_format = PIXEL_FRMT_411;
- else if (f->fmt.pix.pixelformat == V4L2_PIX_FMT_YUYV)
- pix_format = PIXEL_FRMT_422;
- else
- return -EINVAL;
-
- cx25821_set_pixel_format(dev, SRAM_CH06, pix_format);
-
- // check if cif resolution
- if (fh->width == 320 || fh->width == 352) {
- dev->use_cif_resolution[SRAM_CH06] = 1;
- } else {
- dev->use_cif_resolution[SRAM_CH06] = 0;
- }
- dev->cif_width[SRAM_CH06] = fh->width;
- medusa_set_resolution(dev, fh->width, SRAM_CH06);
-
- dprintk(2, "%s() width=%d height=%d field=%d\n", __func__, fh->width,
- fh->height, fh->vidq.field);
- cx25821_call_all(dev, video, s_fmt, f);
-
- return 0;
-}
-
-static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p)
-{
- int ret_val = 0;
- struct cx25821_fh *fh = priv;
- struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
-
- ret_val = videobuf_dqbuf(get_queue(fh), p, file->f_flags & O_NONBLOCK);
-
- p->sequence = dev->vidq[SRAM_CH06].count;
-
- return ret_val;
-}
-
-static int vidioc_log_status(struct file *file, void *priv)
-{
- struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
- char name[32 + 2];
-
- struct sram_channel *sram_ch = &dev->sram_channels[SRAM_CH06];
- u32 tmp = 0;
-
- snprintf(name, sizeof(name), "%s/2", dev->name);
- printk(KERN_INFO "%s/2: ============ START LOG STATUS ============\n",
- dev->name);
- cx25821_call_all(dev, core, log_status);
-
- tmp = cx_read(sram_ch->dma_ctl);
- printk(KERN_INFO "Video input 6 is %s\n",
- (tmp & 0x11) ? "streaming" : "stopped");
- printk(KERN_INFO "%s/2: ============= END LOG STATUS =============\n",
- dev->name);
- return 0;
-}
-
-static int vidioc_s_ctrl(struct file *file, void *priv,
- struct v4l2_control *ctl)
-{
- struct cx25821_fh *fh = priv;
- struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
- int err;
-
- if (fh) {
- err = v4l2_prio_check(&dev->prio, fh->prio);
- if (0 != err)
- return err;
- }
-
- return cx25821_set_control(dev, ctl, SRAM_CH06);
-}
-
-// exported stuff
-static const struct v4l2_file_operations video_fops = {
- .owner = THIS_MODULE,
- .open = video_open,
- .release = video_release,
- .read = video_read,
- .poll = video_poll,
- .mmap = cx25821_video_mmap,
- .ioctl = video_ioctl2,
-};
-
-static const struct v4l2_ioctl_ops video_ioctl_ops = {
- .vidioc_querycap = cx25821_vidioc_querycap,
- .vidioc_enum_fmt_vid_cap = cx25821_vidioc_enum_fmt_vid_cap,
- .vidioc_g_fmt_vid_cap = cx25821_vidioc_g_fmt_vid_cap,
- .vidioc_try_fmt_vid_cap = cx25821_vidioc_try_fmt_vid_cap,
- .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
- .vidioc_reqbufs = cx25821_vidioc_reqbufs,
- .vidioc_querybuf = cx25821_vidioc_querybuf,
- .vidioc_qbuf = cx25821_vidioc_qbuf,
- .vidioc_dqbuf = vidioc_dqbuf,
-#ifdef TUNER_FLAG
- .vidioc_s_std = cx25821_vidioc_s_std,
- .vidioc_querystd = cx25821_vidioc_querystd,
-#endif
- .vidioc_cropcap = cx25821_vidioc_cropcap,
- .vidioc_s_crop = cx25821_vidioc_s_crop,
- .vidioc_g_crop = cx25821_vidioc_g_crop,
- .vidioc_enum_input = cx25821_vidioc_enum_input,
- .vidioc_g_input = cx25821_vidioc_g_input,
- .vidioc_s_input = cx25821_vidioc_s_input,
- .vidioc_g_ctrl = cx25821_vidioc_g_ctrl,
- .vidioc_s_ctrl = vidioc_s_ctrl,
- .vidioc_queryctrl = cx25821_vidioc_queryctrl,
- .vidioc_streamon = vidioc_streamon,
- .vidioc_streamoff = vidioc_streamoff,
- .vidioc_log_status = vidioc_log_status,
- .vidioc_g_priority = cx25821_vidioc_g_priority,
- .vidioc_s_priority = cx25821_vidioc_s_priority,
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
- .vidiocgmbuf = cx25821_vidiocgmbuf,
-#endif
-#ifdef TUNER_FLAG
- .vidioc_g_tuner = cx25821_vidioc_g_tuner,
- .vidioc_s_tuner = cx25821_vidioc_s_tuner,
- .vidioc_g_frequency = cx25821_vidioc_g_frequency,
- .vidioc_s_frequency = cx25821_vidioc_s_frequency,
-#endif
-#ifdef CONFIG_VIDEO_ADV_DEBUG
- .vidioc_g_register = cx25821_vidioc_g_register,
- .vidioc_s_register = cx25821_vidioc_s_register,
-#endif
-};
-
-struct video_device cx25821_video_template6 = {
- .name = "cx25821-video",
- .fops = &video_fops,
- .ioctl_ops = &video_ioctl_ops,
- .tvnorms = CX25821_NORMS,
- .current_norm = V4L2_STD_NTSC_M,
-};
diff --git a/drivers/staging/cx25821/cx25821-video7.c b/drivers/staging/cx25821/cx25821-video7.c
deleted file mode 100644
index 5e4a769bada..00000000000
--- a/drivers/staging/cx25821/cx25821-video7.c
+++ /dev/null
@@ -1,433 +0,0 @@
-/*
- * Driver for the Conexant CX25821 PCIe bridge
- *
- * Copyright (C) 2009 Conexant Systems Inc.
- * Authors <shu.lin@conexant.com>, <hiep.huynh@conexant.com>
- * Based on Steven Toth <stoth@linuxtv.org> cx23885 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 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 "cx25821-video.h"
-
-static void buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
-{
- struct cx25821_buffer *buf =
- container_of(vb, struct cx25821_buffer, vb);
- struct cx25821_buffer *prev;
- struct cx25821_fh *fh = vq->priv_data;
- struct cx25821_dev *dev = fh->dev;
- struct cx25821_dmaqueue *q = &dev->vidq[SRAM_CH07];
-
- /* add jump to stopper */
- buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC);
- buf->risc.jmp[1] = cpu_to_le32(q->stopper.dma);
- buf->risc.jmp[2] = cpu_to_le32(0); /* bits 63-32 */
-
- dprintk(2, "jmp to stopper (0x%x)\n", buf->risc.jmp[1]);
- if (!list_empty(&q->queued)) {
- list_add_tail(&buf->vb.queue, &q->queued);
- buf->vb.state = VIDEOBUF_QUEUED;
- dprintk(2, "[%p/%d] buffer_queue - append to queued\n", buf,
- buf->vb.i);
-
- } else if (list_empty(&q->active)) {
- list_add_tail(&buf->vb.queue, &q->active);
- cx25821_start_video_dma(dev, q, buf,
- &dev->sram_channels[SRAM_CH07]);
- buf->vb.state = VIDEOBUF_ACTIVE;
- buf->count = q->count++;
- mod_timer(&q->timeout, jiffies + BUFFER_TIMEOUT);
- dprintk(2,
- "[%p/%d] buffer_queue - first active, buf cnt = %d, q->count = %d\n",
- buf, buf->vb.i, buf->count, q->count);
- } else {
- prev =
- list_entry(q->active.prev, struct cx25821_buffer, vb.queue);
- if (prev->vb.width == buf->vb.width
- && prev->vb.height == buf->vb.height
- && prev->fmt == buf->fmt) {
- list_add_tail(&buf->vb.queue, &q->active);
- buf->vb.state = VIDEOBUF_ACTIVE;
- buf->count = q->count++;
- prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
-
- /* 64 bit bits 63-32 */
- prev->risc.jmp[2] = cpu_to_le32(0);
- dprintk(2,
- "[%p/%d] buffer_queue - append to active, buf->count=%d\n",
- buf, buf->vb.i, buf->count);
-
- } else {
- list_add_tail(&buf->vb.queue, &q->queued);
- buf->vb.state = VIDEOBUF_QUEUED;
- dprintk(2, "[%p/%d] buffer_queue - first queued\n", buf,
- buf->vb.i);
- }
- }
-
- if (list_empty(&q->active)) {
- dprintk(2, "active queue empty!\n");
- }
-}
-
-static struct videobuf_queue_ops cx25821_video_qops = {
- .buf_setup = cx25821_buffer_setup,
- .buf_prepare = cx25821_buffer_prepare,
- .buf_queue = buffer_queue,
- .buf_release = cx25821_buffer_release,
-};
-
-static int video_open(struct file *file)
-{
- struct video_device *vdev = video_devdata(file);
- struct cx25821_dev *dev = video_drvdata(file);
- struct cx25821_fh *fh;
- enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- u32 pix_format;
-
- printk("open dev=%s type=%s\n", video_device_node_name(vdev),
- v4l2_type_names[type]);
-
- /* allocate + initialize per filehandle data */
- fh = kzalloc(sizeof(*fh), GFP_KERNEL);
- if (NULL == fh)
- return -ENOMEM;
-
- lock_kernel();
-
- file->private_data = fh;
- fh->dev = dev;
- fh->type = type;
- fh->width = 720;
-
- if (dev->tvnorm & V4L2_STD_PAL_BG || dev->tvnorm & V4L2_STD_PAL_DK)
- fh->height = 576;
- else
- fh->height = 480;
-
- dev->channel_opened = SRAM_CH07;
- pix_format =
- (dev->pixel_formats[dev->channel_opened] ==
- PIXEL_FRMT_411) ? V4L2_PIX_FMT_Y41P : V4L2_PIX_FMT_YUYV;
- fh->fmt = format_by_fourcc(pix_format);
-
- v4l2_prio_open(&dev->prio, &fh->prio);
-
- videobuf_queue_sg_init(&fh->vidq, &cx25821_video_qops,
- &dev->pci->dev, &dev->slock,
- V4L2_BUF_TYPE_VIDEO_CAPTURE,
- V4L2_FIELD_INTERLACED,
- sizeof(struct cx25821_buffer), fh);
-
- dprintk(1, "post videobuf_queue_init()\n");
- unlock_kernel();
-
- return 0;
-}
-
-static ssize_t video_read(struct file *file, char __user * data, size_t count,
- loff_t * ppos)
-{
- struct cx25821_fh *fh = file->private_data;
-
- switch (fh->type) {
- case V4L2_BUF_TYPE_VIDEO_CAPTURE:
- if (cx25821_res_locked(fh->dev, RESOURCE_VIDEO7))
- return -EBUSY;
-
- return videobuf_read_one(&fh->vidq, data, count, ppos,
- file->f_flags & O_NONBLOCK);
-
- default:
- BUG();
- return 0;
- }
-}
-
-static unsigned int video_poll(struct file *file,
- struct poll_table_struct *wait)
-{
- struct cx25821_fh *fh = file->private_data;
- struct cx25821_buffer *buf;
-
- if (cx25821_res_check(fh, RESOURCE_VIDEO7)) {
- /* streaming capture */
- if (list_empty(&fh->vidq.stream))
- return POLLERR;
- buf = list_entry(fh->vidq.stream.next,
- struct cx25821_buffer, vb.stream);
- } else {
- /* read() capture */
- buf = (struct cx25821_buffer *)fh->vidq.read_buf;
- if (NULL == buf)
- return POLLERR;
- }
-
- poll_wait(file, &buf->vb.done, wait);
- if (buf->vb.state == VIDEOBUF_DONE || buf->vb.state == VIDEOBUF_ERROR) {
- if (buf->vb.state == VIDEOBUF_DONE) {
- struct cx25821_dev *dev = fh->dev;
-
- if (dev && dev->use_cif_resolution[SRAM_CH07]) {
- u8 cam_id = *((char *)buf->vb.baddr + 3);
- memcpy((char *)buf->vb.baddr,
- (char *)buf->vb.baddr + (fh->width * 2),
- (fh->width * 2));
- *((char *)buf->vb.baddr + 3) = cam_id;
- }
- }
-
- return POLLIN | POLLRDNORM;
- }
-
- return 0;
-}
-
-static int video_release(struct file *file)
-{
- struct cx25821_fh *fh = file->private_data;
- struct cx25821_dev *dev = fh->dev;
-
- //stop the risc engine and fifo
- cx_write(channel7->dma_ctl, 0); /* FIFO and RISC disable */
-
- /* stop video capture */
- if (cx25821_res_check(fh, RESOURCE_VIDEO7)) {
- videobuf_queue_cancel(&fh->vidq);
- cx25821_res_free(dev, fh, RESOURCE_VIDEO7);
- }
-
- if (fh->vidq.read_buf) {
- cx25821_buffer_release(&fh->vidq, fh->vidq.read_buf);
- kfree(fh->vidq.read_buf);
- }
-
- videobuf_mmap_free(&fh->vidq);
-
- v4l2_prio_close(&dev->prio, fh->prio);
- file->private_data = NULL;
- kfree(fh);
-
- return 0;
-}
-
-static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
-{
- struct cx25821_fh *fh = priv;
- struct cx25821_dev *dev = fh->dev;
-
- if (unlikely(fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)) {
- return -EINVAL;
- }
-
- if (unlikely(i != fh->type)) {
- return -EINVAL;
- }
-
- if (unlikely(!cx25821_res_get(dev, fh, cx25821_get_resource(fh, RESOURCE_VIDEO7)))) {
- return -EBUSY;
- }
-
- return videobuf_streamon(get_queue(fh));
-}
-
-static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
-{
- struct cx25821_fh *fh = priv;
- struct cx25821_dev *dev = fh->dev;
- int err, res;
-
- if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
- if (i != fh->type)
- return -EINVAL;
-
- res = cx25821_get_resource(fh, RESOURCE_VIDEO7);
- err = videobuf_streamoff(get_queue(fh));
- if (err < 0)
- return err;
- cx25821_res_free(dev, fh, res);
- return 0;
-}
-
-static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
- struct v4l2_format *f)
-{
- struct cx25821_fh *fh = priv;
- struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
- int err;
- int pix_format = 0;
-
- if (fh) {
- err = v4l2_prio_check(&dev->prio, fh->prio);
- if (0 != err)
- return err;
- }
-
- dprintk(2, "%s()\n", __func__);
- err = cx25821_vidioc_try_fmt_vid_cap(file, priv, f);
-
- if (0 != err)
- return err;
-
- fh->fmt = format_by_fourcc(f->fmt.pix.pixelformat);
- fh->vidq.field = f->fmt.pix.field;
-
- // check if width and height is valid based on set standard
- if (cx25821_is_valid_width(f->fmt.pix.width, dev->tvnorm)) {
- fh->width = f->fmt.pix.width;
- }
-
- if (cx25821_is_valid_height(f->fmt.pix.height, dev->tvnorm)) {
- fh->height = f->fmt.pix.height;
- }
-
- if (f->fmt.pix.pixelformat == V4L2_PIX_FMT_Y41P)
- pix_format = PIXEL_FRMT_411;
- else if (f->fmt.pix.pixelformat == V4L2_PIX_FMT_YUYV)
- pix_format = PIXEL_FRMT_422;
- else
- return -EINVAL;
-
- cx25821_set_pixel_format(dev, SRAM_CH07, pix_format);
-
- // check if cif resolution
- if (fh->width == 320 || fh->width == 352) {
- dev->use_cif_resolution[SRAM_CH07] = 1;
- } else {
- dev->use_cif_resolution[SRAM_CH07] = 0;
- }
- dev->cif_width[SRAM_CH07] = fh->width;
- medusa_set_resolution(dev, fh->width, SRAM_CH07);
-
- dprintk(2, "%s() width=%d height=%d field=%d\n", __func__, fh->width,
- fh->height, fh->vidq.field);
- cx25821_call_all(dev, video, s_fmt, f);
-
- return 0;
-}
-
-static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p)
-{
- int ret_val = 0;
- struct cx25821_fh *fh = priv;
- struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
-
- ret_val = videobuf_dqbuf(get_queue(fh), p, file->f_flags & O_NONBLOCK);
-
- p->sequence = dev->vidq[SRAM_CH07].count;
-
- return ret_val;
-}
-static int vidioc_log_status(struct file *file, void *priv)
-{
- struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
- char name[32 + 2];
-
- struct sram_channel *sram_ch = &dev->sram_channels[SRAM_CH07];
- u32 tmp = 0;
-
- snprintf(name, sizeof(name), "%s/2", dev->name);
- printk(KERN_INFO "%s/2: ============ START LOG STATUS ============\n",
- dev->name);
- cx25821_call_all(dev, core, log_status);
-
- tmp = cx_read(sram_ch->dma_ctl);
- printk(KERN_INFO "Video input 7 is %s\n",
- (tmp & 0x11) ? "streaming" : "stopped");
- printk(KERN_INFO "%s/2: ============= END LOG STATUS =============\n",
- dev->name);
- return 0;
-}
-
-static int vidioc_s_ctrl(struct file *file, void *priv,
- struct v4l2_control *ctl)
-{
- struct cx25821_fh *fh = priv;
- struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
- int err;
-
- if (fh) {
- err = v4l2_prio_check(&dev->prio, fh->prio);
- if (0 != err)
- return err;
- }
-
- return cx25821_set_control(dev, ctl, SRAM_CH07);
-}
-
-// exported stuff
-static const struct v4l2_file_operations video_fops = {
- .owner = THIS_MODULE,
- .open = video_open,
- .release = video_release,
- .read = video_read,
- .poll = video_poll,
- .mmap = cx25821_video_mmap,
- .ioctl = video_ioctl2,
-};
-
-static const struct v4l2_ioctl_ops video_ioctl_ops = {
- .vidioc_querycap = cx25821_vidioc_querycap,
- .vidioc_enum_fmt_vid_cap = cx25821_vidioc_enum_fmt_vid_cap,
- .vidioc_g_fmt_vid_cap = cx25821_vidioc_g_fmt_vid_cap,
- .vidioc_try_fmt_vid_cap = cx25821_vidioc_try_fmt_vid_cap,
- .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
- .vidioc_reqbufs = cx25821_vidioc_reqbufs,
- .vidioc_querybuf = cx25821_vidioc_querybuf,
- .vidioc_qbuf = cx25821_vidioc_qbuf,
- .vidioc_dqbuf = vidioc_dqbuf,
-#ifdef TUNER_FLAG
- .vidioc_s_std = cx25821_vidioc_s_std,
- .vidioc_querystd = cx25821_vidioc_querystd,
-#endif
- .vidioc_cropcap = cx25821_vidioc_cropcap,
- .vidioc_s_crop = cx25821_vidioc_s_crop,
- .vidioc_g_crop = cx25821_vidioc_g_crop,
- .vidioc_enum_input = cx25821_vidioc_enum_input,
- .vidioc_g_input = cx25821_vidioc_g_input,
- .vidioc_s_input = cx25821_vidioc_s_input,
- .vidioc_g_ctrl = cx25821_vidioc_g_ctrl,
- .vidioc_s_ctrl = vidioc_s_ctrl,
- .vidioc_queryctrl = cx25821_vidioc_queryctrl,
- .vidioc_streamon = vidioc_streamon,
- .vidioc_streamoff = vidioc_streamoff,
- .vidioc_log_status = vidioc_log_status,
- .vidioc_g_priority = cx25821_vidioc_g_priority,
- .vidioc_s_priority = cx25821_vidioc_s_priority,
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
- .vidiocgmbuf = cx25821_vidiocgmbuf,
-#endif
-#ifdef TUNER_FLAG
- .vidioc_g_tuner = cx25821_vidioc_g_tuner,
- .vidioc_s_tuner = cx25821_vidioc_s_tuner,
- .vidioc_g_frequency = cx25821_vidioc_g_frequency,
- .vidioc_s_frequency = cx25821_vidioc_s_frequency,
-#endif
-#ifdef CONFIG_VIDEO_ADV_DEBUG
- .vidioc_g_register = cx25821_vidioc_g_register,
- .vidioc_s_register = cx25821_vidioc_s_register,
-#endif
-};
-
-struct video_device cx25821_video_template7 = {
- .name = "cx25821-video",
- .fops = &video_fops,
- .ioctl_ops = &video_ioctl_ops,
- .tvnorms = CX25821_NORMS,
- .current_norm = V4L2_STD_NTSC_M,
-};
diff --git a/drivers/staging/cx25821/cx25821-videoioctl.c b/drivers/staging/cx25821/cx25821-videoioctl.c
deleted file mode 100644
index d16807d88be..00000000000
--- a/drivers/staging/cx25821/cx25821-videoioctl.c
+++ /dev/null
@@ -1,480 +0,0 @@
-/*
- * Driver for the Conexant CX25821 PCIe bridge
- *
- * Copyright (C) 2009 Conexant Systems Inc.
- * Authors <shu.lin@conexant.com>, <hiep.huynh@conexant.com>
- * Based on Steven Toth <stoth@linuxtv.org> cx23885 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 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 "cx25821-video.h"
-
-static void buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
-{
- struct cx25821_buffer *buf =
- container_of(vb, struct cx25821_buffer, vb);
- struct cx25821_buffer *prev;
- struct cx25821_fh *fh = vq->priv_data;
- struct cx25821_dev *dev = fh->dev;
- struct cx25821_dmaqueue *q = &dev->vidq[VIDEO_IOCTL_CH];
-
- /* add jump to stopper */
- buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC);
- buf->risc.jmp[1] = cpu_to_le32(q->stopper.dma);
- buf->risc.jmp[2] = cpu_to_le32(0); /* bits 63-32 */
-
- dprintk(2, "jmp to stopper (0x%x)\n", buf->risc.jmp[1]);
-
- if (!list_empty(&q->queued)) {
- list_add_tail(&buf->vb.queue, &q->queued);
- buf->vb.state = VIDEOBUF_QUEUED;
- dprintk(2, "[%p/%d] buffer_queue - append to queued\n", buf,
- buf->vb.i);
-
- } else if (list_empty(&q->active)) {
- list_add_tail(&buf->vb.queue, &q->active);
- cx25821_start_video_dma(dev, q, buf,
- &dev->sram_channels[VIDEO_IOCTL_CH]);
- buf->vb.state = VIDEOBUF_ACTIVE;
- buf->count = q->count++;
- mod_timer(&q->timeout, jiffies + BUFFER_TIMEOUT);
- dprintk(2,
- "[%p/%d] buffer_queue - first active, buf cnt = %d, q->count = %d\n",
- buf, buf->vb.i, buf->count, q->count);
- } else {
- prev =
- list_entry(q->active.prev, struct cx25821_buffer, vb.queue);
- if (prev->vb.width == buf->vb.width
- && prev->vb.height == buf->vb.height
- && prev->fmt == buf->fmt) {
- list_add_tail(&buf->vb.queue, &q->active);
- buf->vb.state = VIDEOBUF_ACTIVE;
- buf->count = q->count++;
- prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
-
- /* 64 bit bits 63-32 */
- prev->risc.jmp[2] = cpu_to_le32(0);
- dprintk(2,
- "[%p/%d] buffer_queue - append to active, buf->count=%d\n",
- buf, buf->vb.i, buf->count);
-
- } else {
- list_add_tail(&buf->vb.queue, &q->queued);
- buf->vb.state = VIDEOBUF_QUEUED;
- dprintk(2, "[%p/%d] buffer_queue - first queued\n", buf,
- buf->vb.i);
- }
- }
-
- if (list_empty(&q->active)) {
- dprintk(2, "active queue empty!\n");
- }
-}
-
-static struct videobuf_queue_ops cx25821_video_qops = {
- .buf_setup = cx25821_buffer_setup,
- .buf_prepare = cx25821_buffer_prepare,
- .buf_queue = buffer_queue,
- .buf_release = cx25821_buffer_release,
-};
-
-static int video_open(struct file *file)
-{
- struct video_device *vdev = video_devdata(file);
- struct cx25821_dev *dev = video_drvdata(file);
- struct cx25821_fh *fh;
- enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- u32 pix_format;
-
- printk("open dev=%s type=%s\n", video_device_node_name(vdev),
- v4l2_type_names[type]);
-
- /* allocate + initialize per filehandle data */
- fh = kzalloc(sizeof(*fh), GFP_KERNEL);
- if (NULL == fh)
- return -ENOMEM;
-
- lock_kernel();
-
- file->private_data = fh;
- fh->dev = dev;
- fh->type = type;
- fh->width = 720;
-
- if (dev->tvnorm & V4L2_STD_PAL_BG || dev->tvnorm & V4L2_STD_PAL_DK)
- fh->height = 576;
- else
- fh->height = 480;
-
- dev->channel_opened = VIDEO_IOCTL_CH;
- pix_format = V4L2_PIX_FMT_YUYV;
- fh->fmt = format_by_fourcc(pix_format);
-
- v4l2_prio_open(&dev->prio, &fh->prio);
-
- videobuf_queue_sg_init(&fh->vidq, &cx25821_video_qops,
- &dev->pci->dev, &dev->slock,
- V4L2_BUF_TYPE_VIDEO_CAPTURE,
- V4L2_FIELD_INTERLACED,
- sizeof(struct cx25821_buffer), fh);
-
- dprintk(1, "post videobuf_queue_init()\n");
- unlock_kernel();
-
- return 0;
-}
-
-static ssize_t video_read(struct file *file, char __user * data, size_t count,
- loff_t * ppos)
-{
- struct cx25821_fh *fh = file->private_data;
-
- switch (fh->type) {
- case V4L2_BUF_TYPE_VIDEO_CAPTURE:
- if (cx25821_res_locked(fh->dev, RESOURCE_VIDEO_IOCTL))
- return -EBUSY;
-
- return videobuf_read_one(&fh->vidq, data, count, ppos,
- file->f_flags & O_NONBLOCK);
-
- default:
- BUG();
- return 0;
- }
-}
-
-static unsigned int video_poll(struct file *file,
- struct poll_table_struct *wait)
-{
- struct cx25821_fh *fh = file->private_data;
- struct cx25821_buffer *buf;
-
- if (cx25821_res_check(fh, RESOURCE_VIDEO_IOCTL)) {
- /* streaming capture */
- if (list_empty(&fh->vidq.stream))
- return POLLERR;
- buf = list_entry(fh->vidq.stream.next,
- struct cx25821_buffer, vb.stream);
- } else {
- /* read() capture */
- buf = (struct cx25821_buffer *)fh->vidq.read_buf;
- if (NULL == buf)
- return POLLERR;
- }
-
- poll_wait(file, &buf->vb.done, wait);
- if (buf->vb.state == VIDEOBUF_DONE || buf->vb.state == VIDEOBUF_ERROR)
- return POLLIN | POLLRDNORM;
-
- return 0;
-}
-
-static int video_release(struct file *file)
-{
- struct cx25821_fh *fh = file->private_data;
- struct cx25821_dev *dev = fh->dev;
-
- /* stop video capture */
- if (cx25821_res_check(fh, RESOURCE_VIDEO_IOCTL)) {
- videobuf_queue_cancel(&fh->vidq);
- cx25821_res_free(dev, fh, RESOURCE_VIDEO_IOCTL);
- }
-
- if (fh->vidq.read_buf) {
- cx25821_buffer_release(&fh->vidq, fh->vidq.read_buf);
- kfree(fh->vidq.read_buf);
- }
-
- videobuf_mmap_free(&fh->vidq);
-
- v4l2_prio_close(&dev->prio, fh->prio);
-
- file->private_data = NULL;
- kfree(fh);
-
- return 0;
-}
-
-static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
-{
- struct cx25821_fh *fh = priv;
- struct cx25821_dev *dev = fh->dev;
-
- if (unlikely(fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)) {
- return -EINVAL;
- }
-
- if (unlikely(i != fh->type)) {
- return -EINVAL;
- }
-
- if (unlikely(!cx25821_res_get(dev, fh, cx25821_get_resource(fh, RESOURCE_VIDEO_IOCTL)))) {
- return -EBUSY;
- }
-
- return videobuf_streamon(get_queue(fh));
-}
-
-static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
-{
- struct cx25821_fh *fh = priv;
- struct cx25821_dev *dev = fh->dev;
- int err, res;
-
- if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
- if (i != fh->type)
- return -EINVAL;
-
- res = cx25821_get_resource(fh, RESOURCE_VIDEO_IOCTL);
- err = videobuf_streamoff(get_queue(fh));
- if (err < 0)
- return err;
- cx25821_res_free(dev, fh, res);
- return 0;
-}
-
-static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
- struct v4l2_format *f)
-{
- struct cx25821_fh *fh = priv;
- struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
- int err;
-
- if (fh) {
- err = v4l2_prio_check(&dev->prio, fh->prio);
- if (0 != err)
- return err;
- }
-
- dprintk(2, "%s()\n", __func__);
- err = cx25821_vidioc_try_fmt_vid_cap(file, priv, f);
-
- if (0 != err)
- return err;
- fh->fmt = format_by_fourcc(f->fmt.pix.pixelformat);
- fh->width = f->fmt.pix.width;
- fh->height = f->fmt.pix.height;
- fh->vidq.field = f->fmt.pix.field;
- dprintk(2, "%s() width=%d height=%d field=%d\n", __func__, fh->width,
- fh->height, fh->vidq.field);
- cx25821_call_all(dev, video, s_fmt, f);
- return 0;
-}
-
-static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p)
-{
- struct cx25821_fh *fh = priv;
- return videobuf_dqbuf(get_queue(fh), p, file->f_flags & O_NONBLOCK);
-}
-
-static long video_ioctl_set(struct file *file, unsigned int cmd,
- unsigned long arg)
-{
- struct cx25821_fh *fh = file->private_data;
- struct cx25821_dev *dev = fh->dev;
- struct downstream_user_struct *data_from_user;
- int command;
- int width = 720;
- int selected_channel = 0, pix_format = 0, i = 0;
- int cif_enable = 0, cif_width = 0;
- u32 value = 0;
-
- data_from_user = (struct downstream_user_struct *)arg;
-
- if (!data_from_user) {
- printk("cx25821 in %s(): User data is INVALID. Returning.\n",
- __func__);
- return 0;
- }
-
- command = data_from_user->command;
-
- if (command != SET_VIDEO_STD && command != SET_PIXEL_FORMAT
- && command != ENABLE_CIF_RESOLUTION && command != REG_READ
- && command != REG_WRITE && command != MEDUSA_READ
- && command != MEDUSA_WRITE) {
- return 0;
- }
-
- switch (command) {
- case SET_VIDEO_STD:
- dev->tvnorm =
- !strcmp(data_from_user->vid_stdname,
- "PAL") ? V4L2_STD_PAL_BG : V4L2_STD_NTSC_M;
- medusa_set_videostandard(dev);
- break;
-
- case SET_PIXEL_FORMAT:
- selected_channel = data_from_user->decoder_select;
- pix_format = data_from_user->pixel_format;
-
- if (!(selected_channel <= 7 && selected_channel >= 0)) {
- selected_channel -= 4;
- selected_channel = selected_channel % 8;
- }
-
- if (selected_channel >= 0)
- cx25821_set_pixel_format(dev, selected_channel,
- pix_format);
-
- break;
-
- case ENABLE_CIF_RESOLUTION:
- selected_channel = data_from_user->decoder_select;
- cif_enable = data_from_user->cif_resolution_enable;
- cif_width = data_from_user->cif_width;
-
- if (cif_enable) {
- if (dev->tvnorm & V4L2_STD_PAL_BG
- || dev->tvnorm & V4L2_STD_PAL_DK)
- width = 352;
- else
- width = (cif_width == 320
- || cif_width == 352) ? cif_width : 320;
- }
-
- if (!(selected_channel <= 7 && selected_channel >= 0)) {
- selected_channel -= 4;
- selected_channel = selected_channel % 8;
- }
-
- if (selected_channel <= 7 && selected_channel >= 0) {
- dev->use_cif_resolution[selected_channel] = cif_enable;
- dev->cif_width[selected_channel] = width;
- } else {
- for (i = 0; i < VID_CHANNEL_NUM; i++) {
- dev->use_cif_resolution[i] = cif_enable;
- dev->cif_width[i] = width;
- }
- }
-
- medusa_set_resolution(dev, width, selected_channel);
- break;
- case REG_READ:
- data_from_user->reg_data = cx_read(data_from_user->reg_address);
- break;
- case REG_WRITE:
- cx_write(data_from_user->reg_address, data_from_user->reg_data);
- break;
- case MEDUSA_READ:
- value =
- cx25821_i2c_read(&dev->i2c_bus[0],
- (u16) data_from_user->reg_address,
- &data_from_user->reg_data);
- break;
- case MEDUSA_WRITE:
- cx25821_i2c_write(&dev->i2c_bus[0],
- (u16) data_from_user->reg_address,
- data_from_user->reg_data);
- break;
- }
-
- return 0;
-}
-
-static int vidioc_log_status(struct file *file, void *priv)
-{
- struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
- char name[32 + 2];
-
- snprintf(name, sizeof(name), "%s/2", dev->name);
- printk(KERN_INFO "%s/2: ============ START LOG STATUS ============\n",
- dev->name);
- cx25821_call_all(dev, core, log_status);
- printk(KERN_INFO "%s/2: ============= END LOG STATUS =============\n",
- dev->name);
- return 0;
-}
-
-static int vidioc_s_ctrl(struct file *file, void *priv,
- struct v4l2_control *ctl)
-{
- struct cx25821_fh *fh = priv;
- struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
- int err;
-
- if (fh) {
- err = v4l2_prio_check(&dev->prio, fh->prio);
- if (0 != err)
- return err;
- }
-
- return 0;
-}
-
-// exported stuff
-static const struct v4l2_file_operations video_fops = {
- .owner = THIS_MODULE,
- .open = video_open,
- .release = video_release,
- .read = video_read,
- .poll = video_poll,
- .mmap = cx25821_video_mmap,
- .ioctl = video_ioctl_set,
-};
-
-static const struct v4l2_ioctl_ops video_ioctl_ops = {
- .vidioc_querycap = cx25821_vidioc_querycap,
- .vidioc_enum_fmt_vid_cap = cx25821_vidioc_enum_fmt_vid_cap,
- .vidioc_g_fmt_vid_cap = cx25821_vidioc_g_fmt_vid_cap,
- .vidioc_try_fmt_vid_cap = cx25821_vidioc_try_fmt_vid_cap,
- .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
- .vidioc_reqbufs = cx25821_vidioc_reqbufs,
- .vidioc_querybuf = cx25821_vidioc_querybuf,
- .vidioc_qbuf = cx25821_vidioc_qbuf,
- .vidioc_dqbuf = vidioc_dqbuf,
-#ifdef TUNER_FLAG
- .vidioc_s_std = cx25821_vidioc_s_std,
- .vidioc_querystd = cx25821_vidioc_querystd,
-#endif
- .vidioc_cropcap = cx25821_vidioc_cropcap,
- .vidioc_s_crop = cx25821_vidioc_s_crop,
- .vidioc_g_crop = cx25821_vidioc_g_crop,
- .vidioc_enum_input = cx25821_vidioc_enum_input,
- .vidioc_g_input = cx25821_vidioc_g_input,
- .vidioc_s_input = cx25821_vidioc_s_input,
- .vidioc_g_ctrl = cx25821_vidioc_g_ctrl,
- .vidioc_s_ctrl = vidioc_s_ctrl,
- .vidioc_queryctrl = cx25821_vidioc_queryctrl,
- .vidioc_streamon = vidioc_streamon,
- .vidioc_streamoff = vidioc_streamoff,
- .vidioc_log_status = vidioc_log_status,
- .vidioc_g_priority = cx25821_vidioc_g_priority,
- .vidioc_s_priority = cx25821_vidioc_s_priority,
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
- .vidiocgmbuf = cx25821_vidiocgmbuf,
-#endif
-#ifdef TUNER_FLAG
- .vidioc_g_tuner = cx25821_vidioc_g_tuner,
- .vidioc_s_tuner = cx25821_vidioc_s_tuner,
- .vidioc_g_frequency = cx25821_vidioc_g_frequency,
- .vidioc_s_frequency = cx25821_vidioc_s_frequency,
-#endif
-#ifdef CONFIG_VIDEO_ADV_DEBUG
- .vidioc_g_register = cx25821_vidioc_g_register,
- .vidioc_s_register = cx25821_vidioc_s_register,
-#endif
-};
-
-struct video_device cx25821_videoioctl_template = {
- .name = "cx25821-videoioctl",
- .fops = &video_fops,
- .ioctl_ops = &video_ioctl_ops,
- .tvnorms = CX25821_NORMS,
- .current_norm = V4L2_STD_NTSC_M,
-};
diff --git a/drivers/staging/cx25821/cx25821-vidups10.c b/drivers/staging/cx25821/cx25821-vidups10.c
deleted file mode 100644
index c746a17ccbd..00000000000
--- a/drivers/staging/cx25821/cx25821-vidups10.c
+++ /dev/null
@@ -1,418 +0,0 @@
-/*
- * Driver for the Conexant CX25821 PCIe bridge
- *
- * Copyright (C) 2009 Conexant Systems Inc.
- * Authors <shu.lin@conexant.com>, <hiep.huynh@conexant.com>
- * Based on Steven Toth <stoth@linuxtv.org> cx23885 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 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 "cx25821-video.h"
-
-static void buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
-{
- struct cx25821_buffer *buf =
- container_of(vb, struct cx25821_buffer, vb);
- struct cx25821_buffer *prev;
- struct cx25821_fh *fh = vq->priv_data;
- struct cx25821_dev *dev = fh->dev;
- struct cx25821_dmaqueue *q = &dev->vidq[SRAM_CH10];
-
- /* add jump to stopper */
- buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC);
- buf->risc.jmp[1] = cpu_to_le32(q->stopper.dma);
- buf->risc.jmp[2] = cpu_to_le32(0); /* bits 63-32 */
-
- dprintk(2, "jmp to stopper (0x%x)\n", buf->risc.jmp[1]);
-
- if (!list_empty(&q->queued)) {
- list_add_tail(&buf->vb.queue, &q->queued);
- buf->vb.state = VIDEOBUF_QUEUED;
- dprintk(2, "[%p/%d] buffer_queue - append to queued\n", buf,
- buf->vb.i);
-
- } else if (list_empty(&q->active)) {
- list_add_tail(&buf->vb.queue, &q->active);
- cx25821_start_video_dma(dev, q, buf,
- &dev->sram_channels[SRAM_CH10]);
- buf->vb.state = VIDEOBUF_ACTIVE;
- buf->count = q->count++;
- mod_timer(&q->timeout, jiffies + BUFFER_TIMEOUT);
- dprintk(2,
- "[%p/%d] buffer_queue - first active, buf cnt = %d, q->count = %d\n",
- buf, buf->vb.i, buf->count, q->count);
- } else {
- prev =
- list_entry(q->active.prev, struct cx25821_buffer, vb.queue);
- if (prev->vb.width == buf->vb.width
- && prev->vb.height == buf->vb.height
- && prev->fmt == buf->fmt) {
- list_add_tail(&buf->vb.queue, &q->active);
- buf->vb.state = VIDEOBUF_ACTIVE;
- buf->count = q->count++;
- prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
-
- /* 64 bit bits 63-32 */
- prev->risc.jmp[2] = cpu_to_le32(0);
- dprintk(2,
- "[%p/%d] buffer_queue - append to active, buf->count=%d\n",
- buf, buf->vb.i, buf->count);
-
- } else {
- list_add_tail(&buf->vb.queue, &q->queued);
- buf->vb.state = VIDEOBUF_QUEUED;
- dprintk(2, "[%p/%d] buffer_queue - first queued\n", buf,
- buf->vb.i);
- }
- }
-
- if (list_empty(&q->active)) {
- dprintk(2, "active queue empty!\n");
- }
-}
-
-static struct videobuf_queue_ops cx25821_video_qops = {
- .buf_setup = cx25821_buffer_setup,
- .buf_prepare = cx25821_buffer_prepare,
- .buf_queue = buffer_queue,
- .buf_release = cx25821_buffer_release,
-};
-
-static int video_open(struct file *file)
-{
- struct video_device *vdev = video_devdata(file);
- struct cx25821_dev *dev = video_drvdata(file);
- struct cx25821_fh *fh;
- enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-
- printk("open dev=%s type=%s\n", video_device_node_name(vdev),
- v4l2_type_names[type]);
-
- /* allocate + initialize per filehandle data */
- fh = kzalloc(sizeof(*fh), GFP_KERNEL);
- if (NULL == fh)
- return -ENOMEM;
-
- lock_kernel();
-
- file->private_data = fh;
- fh->dev = dev;
- fh->type = type;
- fh->width = 720;
-
- if (dev->tvnorm & V4L2_STD_PAL_BG || dev->tvnorm & V4L2_STD_PAL_DK)
- fh->height = 576;
- else
- fh->height = 480;
-
- dev->channel_opened = 9;
- fh->fmt = format_by_fourcc(V4L2_PIX_FMT_YUYV);
-
- v4l2_prio_open(&dev->prio, &fh->prio);
-
- videobuf_queue_sg_init(&fh->vidq, &cx25821_video_qops,
- &dev->pci->dev, &dev->slock,
- V4L2_BUF_TYPE_VIDEO_CAPTURE,
- V4L2_FIELD_INTERLACED,
- sizeof(struct cx25821_buffer), fh);
-
- dprintk(1, "post videobuf_queue_init()\n");
- unlock_kernel();
-
- return 0;
-}
-
-static ssize_t video_read(struct file *file, char __user * data, size_t count,
- loff_t * ppos)
-{
- struct cx25821_fh *fh = file->private_data;
-
- switch (fh->type) {
- case V4L2_BUF_TYPE_VIDEO_CAPTURE:
- if (cx25821_res_locked(fh->dev, RESOURCE_VIDEO10))
- return -EBUSY;
-
- return videobuf_read_one(&fh->vidq, data, count, ppos,
- file->f_flags & O_NONBLOCK);
-
- default:
- BUG();
- return 0;
- }
-}
-
-static unsigned int video_poll(struct file *file,
- struct poll_table_struct *wait)
-{
- struct cx25821_fh *fh = file->private_data;
- struct cx25821_buffer *buf;
-
- if (cx25821_res_check(fh, RESOURCE_VIDEO10)) {
- /* streaming capture */
- if (list_empty(&fh->vidq.stream))
- return POLLERR;
- buf = list_entry(fh->vidq.stream.next,
- struct cx25821_buffer, vb.stream);
- } else {
- /* read() capture */
- buf = (struct cx25821_buffer *)fh->vidq.read_buf;
- if (NULL == buf)
- return POLLERR;
- }
-
- poll_wait(file, &buf->vb.done, wait);
- if (buf->vb.state == VIDEOBUF_DONE || buf->vb.state == VIDEOBUF_ERROR)
- return POLLIN | POLLRDNORM;
- return 0;
-}
-
-static int video_release(struct file *file)
-{
- struct cx25821_fh *fh = file->private_data;
- struct cx25821_dev *dev = fh->dev;
-
- //stop the risc engine and fifo
- //cx_write(channel10->dma_ctl, 0);
-
- /* stop video capture */
- if (cx25821_res_check(fh, RESOURCE_VIDEO10)) {
- videobuf_queue_cancel(&fh->vidq);
- cx25821_res_free(dev, fh, RESOURCE_VIDEO10);
- }
-
- if (fh->vidq.read_buf) {
- cx25821_buffer_release(&fh->vidq, fh->vidq.read_buf);
- kfree(fh->vidq.read_buf);
- }
-
- videobuf_mmap_free(&fh->vidq);
-
- v4l2_prio_close(&dev->prio, fh->prio);
-
- file->private_data = NULL;
- kfree(fh);
-
- return 0;
-}
-
-static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
-{
- struct cx25821_fh *fh = priv;
- struct cx25821_dev *dev = fh->dev;
-
- if (unlikely(fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)) {
- return -EINVAL;
- }
-
- if (unlikely(i != fh->type)) {
- return -EINVAL;
- }
-
- if (unlikely(!cx25821_res_get(dev, fh, cx25821_get_resource(fh, RESOURCE_VIDEO10)))) {
- return -EBUSY;
- }
-
- return videobuf_streamon(get_queue(fh));
-}
-
-static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
-{
- struct cx25821_fh *fh = priv;
- struct cx25821_dev *dev = fh->dev;
- int err, res;
-
- if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
- if (i != fh->type)
- return -EINVAL;
-
- res = cx25821_get_resource(fh, RESOURCE_VIDEO10);
- err = videobuf_streamoff(get_queue(fh));
- if (err < 0)
- return err;
- cx25821_res_free(dev, fh, res);
- return 0;
-}
-
-static long video_ioctl_upstream10(struct file *file, unsigned int cmd,
- unsigned long arg)
-{
- struct cx25821_fh *fh = file->private_data;
- struct cx25821_dev *dev = fh->dev;
- int command = 0;
- struct upstream_user_struct *data_from_user;
-
- data_from_user = (struct upstream_user_struct *)arg;
-
- if (!data_from_user) {
- printk
- ("cx25821 in %s(): Upstream data is INVALID. Returning.\n",
- __func__);
- return 0;
- }
-
- command = data_from_user->command;
-
- if (command != UPSTREAM_START_VIDEO && command != UPSTREAM_STOP_VIDEO) {
- return 0;
- }
-
- dev->input_filename_ch2 = data_from_user->input_filename;
- dev->input_audiofilename = data_from_user->input_filename;
- dev->vid_stdname_ch2 = data_from_user->vid_stdname;
- dev->pixel_format_ch2 = data_from_user->pixel_format;
- dev->channel_select_ch2 = data_from_user->channel_select;
- dev->command_ch2 = data_from_user->command;
-
- switch (command) {
- case UPSTREAM_START_VIDEO:
- cx25821_start_upstream_video_ch2(dev, data_from_user);
- break;
-
- case UPSTREAM_STOP_VIDEO:
- cx25821_stop_upstream_video_ch2(dev);
- break;
- }
-
- return 0;
-}
-
-static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
- struct v4l2_format *f)
-{
- struct cx25821_fh *fh = priv;
- struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
- int err;
-
- if (fh) {
- err = v4l2_prio_check(&dev->prio, fh->prio);
- if (0 != err)
- return err;
- }
-
- dprintk(2, "%s()\n", __func__);
- err = cx25821_vidioc_try_fmt_vid_cap(file, priv, f);
-
- if (0 != err)
- return err;
- fh->fmt = format_by_fourcc(f->fmt.pix.pixelformat);
- fh->width = f->fmt.pix.width;
- fh->height = f->fmt.pix.height;
- fh->vidq.field = f->fmt.pix.field;
- dprintk(2, "%s() width=%d height=%d field=%d\n", __func__, fh->width,
- fh->height, fh->vidq.field);
- cx25821_call_all(dev, video, s_fmt, f);
- return 0;
-}
-
-static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p)
-{
- struct cx25821_fh *fh = priv;
- return videobuf_dqbuf(get_queue(fh), p, file->f_flags & O_NONBLOCK);
-}
-
-static int vidioc_log_status(struct file *file, void *priv)
-{
- struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
- char name[32 + 2];
-
- snprintf(name, sizeof(name), "%s/2", dev->name);
- printk(KERN_INFO "%s/2: ============ START LOG STATUS ============\n",
- dev->name);
- cx25821_call_all(dev, core, log_status);
- printk(KERN_INFO "%s/2: ============= END LOG STATUS =============\n",
- dev->name);
- return 0;
-}
-
-static int vidioc_s_ctrl(struct file *file, void *priv,
- struct v4l2_control *ctl)
-{
- struct cx25821_fh *fh = priv;
- struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
- int err;
-
- if (fh) {
- err = v4l2_prio_check(&dev->prio, fh->prio);
- if (0 != err)
- return err;
- }
-
- return 0;
-}
-
-//exported stuff
-static const struct v4l2_file_operations video_fops = {
- .owner = THIS_MODULE,
- .open = video_open,
- .release = video_release,
- .read = video_read,
- .poll = video_poll,
- .mmap = cx25821_video_mmap,
- .ioctl = video_ioctl_upstream10,
-};
-
-static const struct v4l2_ioctl_ops video_ioctl_ops = {
- .vidioc_querycap = cx25821_vidioc_querycap,
- .vidioc_enum_fmt_vid_cap = cx25821_vidioc_enum_fmt_vid_cap,
- .vidioc_g_fmt_vid_cap = cx25821_vidioc_g_fmt_vid_cap,
- .vidioc_try_fmt_vid_cap = cx25821_vidioc_try_fmt_vid_cap,
- .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
- .vidioc_reqbufs = cx25821_vidioc_reqbufs,
- .vidioc_querybuf = cx25821_vidioc_querybuf,
- .vidioc_qbuf = cx25821_vidioc_qbuf,
- .vidioc_dqbuf = vidioc_dqbuf,
-#ifdef TUNER_FLAG
- .vidioc_s_std = cx25821_vidioc_s_std,
- .vidioc_querystd = cx25821_vidioc_querystd,
-#endif
- .vidioc_cropcap = cx25821_vidioc_cropcap,
- .vidioc_s_crop = cx25821_vidioc_s_crop,
- .vidioc_g_crop = cx25821_vidioc_g_crop,
- .vidioc_enum_input = cx25821_vidioc_enum_input,
- .vidioc_g_input = cx25821_vidioc_g_input,
- .vidioc_s_input = cx25821_vidioc_s_input,
- .vidioc_g_ctrl = cx25821_vidioc_g_ctrl,
- .vidioc_s_ctrl = vidioc_s_ctrl,
- .vidioc_queryctrl = cx25821_vidioc_queryctrl,
- .vidioc_streamon = vidioc_streamon,
- .vidioc_streamoff = vidioc_streamoff,
- .vidioc_log_status = vidioc_log_status,
- .vidioc_g_priority = cx25821_vidioc_g_priority,
- .vidioc_s_priority = cx25821_vidioc_s_priority,
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
- .vidiocgmbuf = cx25821_vidiocgmbuf,
-#endif
-#ifdef TUNER_FLAG
- .vidioc_g_tuner = cx25821_vidioc_g_tuner,
- .vidioc_s_tuner = cx25821_vidioc_s_tuner,
- .vidioc_g_frequency = cx25821_vidioc_g_frequency,
- .vidioc_s_frequency = cx25821_vidioc_s_frequency,
-#endif
-#ifdef CONFIG_VIDEO_ADV_DEBUG
- .vidioc_g_register = cx25821_vidioc_g_register,
- .vidioc_s_register = cx25821_vidioc_s_register,
-#endif
-};
-
-struct video_device cx25821_video_template10 = {
- .name = "cx25821-upstream10",
- .fops = &video_fops,
- .ioctl_ops = &video_ioctl_ops,
- .tvnorms = CX25821_NORMS,
- .current_norm = V4L2_STD_NTSC_M,
-};
diff --git a/drivers/staging/cx25821/cx25821-vidups9.c b/drivers/staging/cx25821/cx25821-vidups9.c
deleted file mode 100644
index 466e0f34ae3..00000000000
--- a/drivers/staging/cx25821/cx25821-vidups9.c
+++ /dev/null
@@ -1,416 +0,0 @@
-/*
- * Driver for the Conexant CX25821 PCIe bridge
- *
- * Copyright (C) 2009 Conexant Systems Inc.
- * Authors <shu.lin@conexant.com>, <hiep.huynh@conexant.com>
- * Based on Steven Toth <stoth@linuxtv.org> cx23885 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 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 "cx25821-video.h"
-
-static void buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
-{
- struct cx25821_buffer *buf =
- container_of(vb, struct cx25821_buffer, vb);
- struct cx25821_buffer *prev;
- struct cx25821_fh *fh = vq->priv_data;
- struct cx25821_dev *dev = fh->dev;
- struct cx25821_dmaqueue *q = &dev->vidq[SRAM_CH09];
-
- /* add jump to stopper */
- buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC);
- buf->risc.jmp[1] = cpu_to_le32(q->stopper.dma);
- buf->risc.jmp[2] = cpu_to_le32(0); /* bits 63-32 */
-
- dprintk(2, "jmp to stopper (0x%x)\n", buf->risc.jmp[1]);
-
- if (!list_empty(&q->queued)) {
- list_add_tail(&buf->vb.queue, &q->queued);
- buf->vb.state = VIDEOBUF_QUEUED;
- dprintk(2, "[%p/%d] buffer_queue - append to queued\n", buf,
- buf->vb.i);
-
- } else if (list_empty(&q->active)) {
- list_add_tail(&buf->vb.queue, &q->active);
- cx25821_start_video_dma(dev, q, buf,
- &dev->sram_channels[SRAM_CH09]);
- buf->vb.state = VIDEOBUF_ACTIVE;
- buf->count = q->count++;
- mod_timer(&q->timeout, jiffies + BUFFER_TIMEOUT);
- dprintk(2,
- "[%p/%d] buffer_queue - first active, buf cnt = %d, q->count = %d\n",
- buf, buf->vb.i, buf->count, q->count);
- } else {
- prev =
- list_entry(q->active.prev, struct cx25821_buffer, vb.queue);
- if (prev->vb.width == buf->vb.width
- && prev->vb.height == buf->vb.height
- && prev->fmt == buf->fmt) {
- list_add_tail(&buf->vb.queue, &q->active);
- buf->vb.state = VIDEOBUF_ACTIVE;
- buf->count = q->count++;
- prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
-
- /* 64 bit bits 63-32 */
- prev->risc.jmp[2] = cpu_to_le32(0);
- dprintk(2,
- "[%p/%d] buffer_queue - append to active, buf->count=%d\n",
- buf, buf->vb.i, buf->count);
-
- } else {
- list_add_tail(&buf->vb.queue, &q->queued);
- buf->vb.state = VIDEOBUF_QUEUED;
- dprintk(2, "[%p/%d] buffer_queue - first queued\n", buf,
- buf->vb.i);
- }
- }
-
- if (list_empty(&q->active)) {
- dprintk(2, "active queue empty!\n");
- }
-}
-
-static struct videobuf_queue_ops cx25821_video_qops = {
- .buf_setup = cx25821_buffer_setup,
- .buf_prepare = cx25821_buffer_prepare,
- .buf_queue = buffer_queue,
- .buf_release = cx25821_buffer_release,
-};
-
-static int video_open(struct file *file)
-{
- struct video_device *vdev = video_devdata(file);
- struct cx25821_dev *dev = video_drvdata(file);
- struct cx25821_fh *fh;
- enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-
- printk("open dev=%s type=%s\n", video_device_node_name(vdev),
- v4l2_type_names[type]);
-
- /* allocate + initialize per filehandle data */
- fh = kzalloc(sizeof(*fh), GFP_KERNEL);
- if (NULL == fh)
- return -ENOMEM;
-
- lock_kernel();
-
- file->private_data = fh;
- fh->dev = dev;
- fh->type = type;
- fh->width = 720;
-
- if (dev->tvnorm & V4L2_STD_PAL_BG || dev->tvnorm & V4L2_STD_PAL_DK)
- fh->height = 576;
- else
- fh->height = 480;
-
- dev->channel_opened = 8;
- fh->fmt = format_by_fourcc(V4L2_PIX_FMT_YUYV);
-
- v4l2_prio_open(&dev->prio, &fh->prio);
-
- videobuf_queue_sg_init(&fh->vidq, &cx25821_video_qops,
- &dev->pci->dev, &dev->slock,
- V4L2_BUF_TYPE_VIDEO_CAPTURE,
- V4L2_FIELD_INTERLACED,
- sizeof(struct cx25821_buffer), fh);
-
- dprintk(1, "post videobuf_queue_init()\n");
- unlock_kernel();
-
- return 0;
-}
-
-static ssize_t video_read(struct file *file, char __user * data, size_t count,
- loff_t * ppos)
-{
- struct cx25821_fh *fh = file->private_data;
-
- switch (fh->type) {
- case V4L2_BUF_TYPE_VIDEO_CAPTURE:
- if (cx25821_res_locked(fh->dev, RESOURCE_VIDEO9))
- return -EBUSY;
-
- return videobuf_read_one(&fh->vidq, data, count, ppos,
- file->f_flags & O_NONBLOCK);
-
- default:
- BUG();
- return 0;
- }
-}
-
-static unsigned int video_poll(struct file *file,
- struct poll_table_struct *wait)
-{
- struct cx25821_fh *fh = file->private_data;
- struct cx25821_buffer *buf;
-
- if (cx25821_res_check(fh, RESOURCE_VIDEO9)) {
- /* streaming capture */
- if (list_empty(&fh->vidq.stream))
- return POLLERR;
- buf = list_entry(fh->vidq.stream.next,
- struct cx25821_buffer, vb.stream);
- } else {
- /* read() capture */
- buf = (struct cx25821_buffer *)fh->vidq.read_buf;
- if (NULL == buf)
- return POLLERR;
- }
-
- poll_wait(file, &buf->vb.done, wait);
- if (buf->vb.state == VIDEOBUF_DONE || buf->vb.state == VIDEOBUF_ERROR)
- return POLLIN | POLLRDNORM;
- return 0;
-}
-
-static int video_release(struct file *file)
-{
- struct cx25821_fh *fh = file->private_data;
- struct cx25821_dev *dev = fh->dev;
-
- //stop the risc engine and fifo
- //cx_write(channel9->dma_ctl, 0);
-
- /* stop video capture */
- if (cx25821_res_check(fh, RESOURCE_VIDEO9)) {
- videobuf_queue_cancel(&fh->vidq);
- cx25821_res_free(dev, fh, RESOURCE_VIDEO9);
- }
-
- if (fh->vidq.read_buf) {
- cx25821_buffer_release(&fh->vidq, fh->vidq.read_buf);
- kfree(fh->vidq.read_buf);
- }
-
- videobuf_mmap_free(&fh->vidq);
-
- v4l2_prio_close(&dev->prio, fh->prio);
-
- file->private_data = NULL;
- kfree(fh);
-
- return 0;
-}
-
-static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
-{
- struct cx25821_fh *fh = priv;
- struct cx25821_dev *dev = fh->dev;
-
- if (unlikely(fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)) {
- return -EINVAL;
- }
-
- if (unlikely(i != fh->type)) {
- return -EINVAL;
- }
-
- if (unlikely(!cx25821_res_get(dev, fh, cx25821_get_resource(fh, RESOURCE_VIDEO9)))) {
- return -EBUSY;
- }
-
- return videobuf_streamon(get_queue(fh));
-}
-
-static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
-{
- struct cx25821_fh *fh = priv;
- struct cx25821_dev *dev = fh->dev;
- int err, res;
-
- if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
- if (i != fh->type)
- return -EINVAL;
-
- res = cx25821_get_resource(fh, RESOURCE_VIDEO9);
- err = videobuf_streamoff(get_queue(fh));
- if (err < 0)
- return err;
- cx25821_res_free(dev, fh, res);
- return 0;
-}
-
-static long video_ioctl_upstream9(struct file *file, unsigned int cmd,
- unsigned long arg)
-{
- struct cx25821_fh *fh = file->private_data;
- struct cx25821_dev *dev = fh->dev;
- int command = 0;
- struct upstream_user_struct *data_from_user;
-
- data_from_user = (struct upstream_user_struct *)arg;
-
- if (!data_from_user) {
- printk
- ("cx25821 in %s(): Upstream data is INVALID. Returning.\n",
- __func__);
- return 0;
- }
-
- command = data_from_user->command;
-
- if (command != UPSTREAM_START_VIDEO && command != UPSTREAM_STOP_VIDEO) {
- return 0;
- }
-
- dev->input_filename = data_from_user->input_filename;
- dev->input_audiofilename = data_from_user->input_filename;
- dev->vid_stdname = data_from_user->vid_stdname;
- dev->pixel_format = data_from_user->pixel_format;
- dev->channel_select = data_from_user->channel_select;
- dev->command = data_from_user->command;
-
- switch (command) {
- case UPSTREAM_START_VIDEO:
- cx25821_start_upstream_video_ch1(dev, data_from_user);
- break;
-
- case UPSTREAM_STOP_VIDEO:
- cx25821_stop_upstream_video_ch1(dev);
- break;
- }
-
- return 0;
-}
-
-static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
- struct v4l2_format *f)
-{
- struct cx25821_fh *fh = priv;
- struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
- int err;
-
- if (fh) {
- err = v4l2_prio_check(&dev->prio, fh->prio);
- if (0 != err)
- return err;
- }
-
- dprintk(2, "%s()\n", __func__);
- err = cx25821_vidioc_try_fmt_vid_cap(file, priv, f);
-
- if (0 != err)
- return err;
- fh->fmt = format_by_fourcc(f->fmt.pix.pixelformat);
- fh->width = f->fmt.pix.width;
- fh->height = f->fmt.pix.height;
- fh->vidq.field = f->fmt.pix.field;
- dprintk(2, "%s() width=%d height=%d field=%d\n", __func__, fh->width,
- fh->height, fh->vidq.field);
- cx25821_call_all(dev, video, s_fmt, f);
- return 0;
-}
-
-static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p)
-{
- struct cx25821_fh *fh = priv;
- return videobuf_dqbuf(get_queue(fh), p, file->f_flags & O_NONBLOCK);
-}
-static int vidioc_log_status(struct file *file, void *priv)
-{
- struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
- char name[32 + 2];
-
- snprintf(name, sizeof(name), "%s/2", dev->name);
- printk(KERN_INFO "%s/2: ============ START LOG STATUS ============\n",
- dev->name);
- cx25821_call_all(dev, core, log_status);
- printk(KERN_INFO "%s/2: ============= END LOG STATUS =============\n",
- dev->name);
- return 0;
-}
-
-static int vidioc_s_ctrl(struct file *file, void *priv,
- struct v4l2_control *ctl)
-{
- struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
- struct cx25821_fh *fh = priv;
- int err;
- if (fh) {
- err = v4l2_prio_check(&dev->prio, fh->prio);
- if (0 != err)
- return err;
- }
-
- return 0;
-}
-
-// exported stuff
-static const struct v4l2_file_operations video_fops = {
- .owner = THIS_MODULE,
- .open = video_open,
- .release = video_release,
- .read = video_read,
- .poll = video_poll,
- .mmap = cx25821_video_mmap,
- .ioctl = video_ioctl_upstream9,
-};
-
-static const struct v4l2_ioctl_ops video_ioctl_ops = {
- .vidioc_querycap = cx25821_vidioc_querycap,
- .vidioc_enum_fmt_vid_cap = cx25821_vidioc_enum_fmt_vid_cap,
- .vidioc_g_fmt_vid_cap = cx25821_vidioc_g_fmt_vid_cap,
- .vidioc_try_fmt_vid_cap = cx25821_vidioc_try_fmt_vid_cap,
- .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
- .vidioc_reqbufs = cx25821_vidioc_reqbufs,
- .vidioc_querybuf = cx25821_vidioc_querybuf,
- .vidioc_qbuf = cx25821_vidioc_qbuf,
- .vidioc_dqbuf = vidioc_dqbuf,
-#ifdef TUNER_FLAG
- .vidioc_s_std = cx25821_vidioc_s_std,
- .vidioc_querystd = cx25821_vidioc_querystd,
-#endif
- .vidioc_cropcap = cx25821_vidioc_cropcap,
- .vidioc_s_crop = cx25821_vidioc_s_crop,
- .vidioc_g_crop = cx25821_vidioc_g_crop,
- .vidioc_enum_input = cx25821_vidioc_enum_input,
- .vidioc_g_input = cx25821_vidioc_g_input,
- .vidioc_s_input = cx25821_vidioc_s_input,
- .vidioc_g_ctrl = cx25821_vidioc_g_ctrl,
- .vidioc_s_ctrl = vidioc_s_ctrl,
- .vidioc_queryctrl = cx25821_vidioc_queryctrl,
- .vidioc_streamon = vidioc_streamon,
- .vidioc_streamoff = vidioc_streamoff,
- .vidioc_log_status = vidioc_log_status,
- .vidioc_g_priority = cx25821_vidioc_g_priority,
- .vidioc_s_priority = cx25821_vidioc_s_priority,
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
- .vidiocgmbuf = cx25821_vidiocgmbuf,
-#endif
-#ifdef TUNER_FLAG
- .vidioc_g_tuner = cx25821_vidioc_g_tuner,
- .vidioc_s_tuner = cx25821_vidioc_s_tuner,
- .vidioc_g_frequency = cx25821_vidioc_g_frequency,
- .vidioc_s_frequency = cx25821_vidioc_s_frequency,
-#endif
-#ifdef CONFIG_VIDEO_ADV_DEBUG
- .vidioc_g_register = cx25821_vidioc_g_register,
- .vidioc_s_register = cx25821_vidioc_s_register,
-#endif
-};
-
-struct video_device cx25821_video_template9 = {
- .name = "cx25821-upstream9",
- .fops = &video_fops,
- .ioctl_ops = &video_ioctl_ops,
- .tvnorms = CX25821_NORMS,
- .current_norm = V4L2_STD_NTSC_M,
-};
diff --git a/drivers/staging/cx25821/cx25821.h b/drivers/staging/cx25821/cx25821.h
index cf2286d83b6..1b628f61578 100644
--- a/drivers/staging/cx25821/cx25821.h
+++ b/drivers/staging/cx25821/cx25821.h
@@ -61,7 +61,7 @@
#define FALSE 0
#define LINE_SIZE_D1 1440
-// Number of decoders and encoders
+/* Number of decoders and encoders */
#define MAX_DECODERS 8
#define MAX_ENCODERS 2
#define QUAD_DECODERS 4
@@ -139,6 +139,7 @@ struct cx25821_fh {
/* video capture */
struct cx25821_fmt *fmt;
unsigned int width, height;
+ int channel_id;
/* vbi capture */
struct videobuf_queue vidq;
@@ -236,13 +237,34 @@ struct cx25821_data {
struct sram_channel *channel;
};
+struct cx25821_channel {
+ struct v4l2_prio_state prio;
+
+ int ctl_bright;
+ int ctl_contrast;
+ int ctl_hue;
+ int ctl_saturation;
+
+ struct cx25821_data timeout_data;
+
+ struct video_device *video_dev;
+ struct cx25821_dmaqueue vidq;
+
+ struct sram_channel *sram_channels;
+
+ struct mutex lock;
+ int resources;
+
+ int pixel_formats;
+ int use_cif_resolution;
+ int cif_width;
+};
+
struct cx25821_dev {
struct list_head devlist;
atomic_t refcount;
struct v4l2_device v4l2_dev;
- struct v4l2_prio_state prio;
-
/* pci stuff */
struct pci_dev *pci;
unsigned char pci_rev, pci_lat;
@@ -261,13 +283,12 @@ struct cx25821_dev {
int nr;
struct mutex lock;
+ struct cx25821_channel channels[MAX_VID_CHANNEL_NUM];
+
/* board details */
unsigned int board;
char name[32];
- /* sram configuration */
- struct sram_channel *sram_channels;
-
/* Analog video */
u32 resources;
unsigned int input;
@@ -282,13 +303,6 @@ struct cx25821_dev {
unsigned char videc_addr;
unsigned short _max_num_decoders;
- int ctl_bright;
- int ctl_contrast;
- int ctl_hue;
- int ctl_saturation;
-
- struct cx25821_data timeout_data[MAX_VID_CHANNEL_NUM];
-
/* Analog Audio Upstream */
int _audio_is_running;
int _audiopixel_format;
@@ -297,7 +311,7 @@ struct cx25821_dev {
int _audio_lines_count;
int _audioframe_count;
int _audio_upstream_channel_select;
- int _last_index_irq; //The last interrupt index processed.
+ int _last_index_irq; /* The last interrupt index processed. */
__le32 *_risc_audio_jmp_addr;
__le32 *_risc_virt_start_addr;
@@ -313,12 +327,10 @@ struct cx25821_dev {
/* V4l */
u32 freq;
- struct video_device *video_dev[MAX_VID_CHANNEL_NUM];
struct video_device *vbi_dev;
struct video_device *radio_dev;
struct video_device *ioctl_dev;
- struct cx25821_dmaqueue vidq[MAX_VID_CHANNEL_NUM];
spinlock_t slock;
/* Video Upstream */
@@ -401,9 +413,6 @@ struct cx25821_dev {
int pixel_format;
int channel_select;
int command;
- int pixel_formats[VID_CHANNEL_NUM];
- int use_cif_resolution[VID_CHANNEL_NUM];
- int cif_width[VID_CHANNEL_NUM];
int channel_opened;
};
@@ -482,7 +491,7 @@ struct sram_channel {
u32 fld_aud_fifo_en;
u32 fld_aud_risc_en;
- //For Upstream Video
+ /* For Upstream Video */
u32 vid_fmt_ctl;
u32 vid_active_ctl1;
u32 vid_active_ctl2;
diff --git a/drivers/staging/cxt1e1/functions.c b/drivers/staging/cxt1e1/functions.c
index 86b49809026..23ea101d7a8 100644
--- a/drivers/staging/cxt1e1/functions.c
+++ b/drivers/staging/cxt1e1/functions.c
@@ -122,19 +122,7 @@ watchdog_func (unsigned long arg)
pr_warning("%s: drvr not available (%x)\n", __func__, drvr_state);
return;
}
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
- /* Initialize the tq entry only the first time */
- if (wd->init_tq)
- {
- wd->init_tq = 0;
- wd->tq.routine = wd->func;
- wd->tq.sync = 0;
- wd->tq.data = wd->softc;
- }
- schedule_task (&wd->tq);
-#else
schedule_work (&wd->work);
-#endif
mod_timer (&wd->h, jiffies + wd->ticks);
}
diff --git a/drivers/staging/cxt1e1/hwprobe.c b/drivers/staging/cxt1e1/hwprobe.c
index 4c8610293fc..89200e7af26 100644
--- a/drivers/staging/cxt1e1/hwprobe.c
+++ b/drivers/staging/cxt1e1/hwprobe.c
@@ -305,15 +305,9 @@ c4hw_attach_all (void)
error_flag = 0;
prep_hdw_info ();
/*** scan PCI bus for all possible boards */
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
while ((pdev = pci_get_device (PCI_VENDOR_ID_CONEXANT,
- PCI_DEVICE_ID_CN8474,
- pdev)))
-#else
- while ((pdev = pci_find_device (PCI_VENDOR_ID_CONEXANT,
PCI_DEVICE_ID_CN8474,
pdev)))
-#endif
{
if (c4_hdw_init (pdev, found))
found++;
diff --git a/drivers/staging/cxt1e1/linux.c b/drivers/staging/cxt1e1/linux.c
index 134e7568024..eb0f4bdf627 100644
--- a/drivers/staging/cxt1e1/linux.c
+++ b/drivers/staging/cxt1e1/linux.c
@@ -142,10 +142,6 @@ getuserbychan (int channum)
}
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-#define DEV_TO_PRIV(dev) ( * (struct c4_priv **) ((hdlc_device*)(dev)+1))
-#else
-
char *
get_hdlc_name (hdlc_device * hdlc)
{
@@ -154,7 +150,6 @@ get_hdlc_name (hdlc_device * hdlc)
return dev->name;
}
-#endif
static status_t
@@ -167,7 +162,6 @@ mkret (int bsd)
}
/***************************************************************************/
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,41)
#include <linux/workqueue.h>
/***
@@ -259,7 +253,6 @@ c4_wq_port_cleanup (mpi_t * pi)
pi->wq_port = 0;
}
}
-#endif
/***************************************************************************/
@@ -291,48 +284,6 @@ void_open (struct net_device * ndev)
}
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-#if !defined(GENERIC_HDLC_VERSION) || (GENERIC_HDLC_VERSION < 4)
-
-/** Linux 2.4.18-19 **/
-STATIC int
-chan_open (hdlc_device * hdlc)
-{
- status_t ret;
-
- if ((ret = c4_chan_up (DEV_TO_PRIV (hdlc)->ci, DEV_TO_PRIV (hdlc)->channum)))
- return -ret;
- MOD_INC_USE_COUNT;
- netif_start_queue (hdlc_to_dev (hdlc));
- return 0; /* no error = success */
-}
-
-#else
-
-/** Linux 2.4.20 and higher **/
-STATIC int
-chan_open (struct net_device * ndev)
-{
- hdlc_device *hdlc = dev_to_hdlc (ndev);
- status_t ret;
-
- hdlc->proto = IF_PROTO_HDLC;
- if ((ret = hdlc_open (hdlc)))
- {
- pr_info("hdlc_open failure, err %d.\n", ret);
- return ret;
- }
- if ((ret = c4_chan_up (DEV_TO_PRIV (hdlc)->ci, DEV_TO_PRIV (hdlc)->channum)))
- return -ret;
- MOD_INC_USE_COUNT;
- netif_start_queue (hdlc_to_dev (hdlc));
- return 0; /* no error = success */
-}
-#endif
-
-#else
-
-/** Linux 2.6 **/
STATIC int
chan_open (struct net_device * ndev)
{
@@ -351,39 +302,8 @@ chan_open (struct net_device * ndev)
netif_start_queue (ndev);
return 0; /* no error = success */
}
-#endif
-
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-#if !defined(GENERIC_HDLC_VERSION) || (GENERIC_HDLC_VERSION < 4)
-
-/** Linux 2.4.18-19 **/
-STATIC void
-chan_close (hdlc_device * hdlc)
-{
- netif_stop_queue (hdlc_to_dev (hdlc));
- musycc_chan_down ((ci_t *) 0, DEV_TO_PRIV (hdlc)->channum);
- MOD_DEC_USE_COUNT;
-}
-#else
-
-/** Linux 2.4.20 and higher **/
-STATIC int
-chan_close (struct net_device * ndev)
-{
- hdlc_device *hdlc = dev_to_hdlc (ndev);
-
- netif_stop_queue (hdlc_to_dev (hdlc));
- musycc_chan_down ((ci_t *) 0, DEV_TO_PRIV (hdlc)->channum);
- hdlc_close (hdlc);
- MOD_DEC_USE_COUNT;
- return 0;
-}
-#endif
-#else
-/** Linux 2.6 **/
STATIC int
chan_close (struct net_device * ndev)
{
@@ -396,37 +316,8 @@ chan_close (struct net_device * ndev)
module_put (THIS_MODULE);
return 0;
}
-#endif
-
-
-#if !defined(GENERIC_HDLC_VERSION) || (GENERIC_HDLC_VERSION < 4)
-
-/** Linux 2.4.18-19 **/
-STATIC int
-chan_ioctl (hdlc_device * hdlc, struct ifreq * ifr, int cmd)
-{
- if (cmd == HDLCSCLOCK)
- {
- ifr->ifr_ifru.ifru_ivalue = LINE_DEFAULT;
- return 0;
- }
- return -EINVAL;
-}
-#endif
-#if !defined(GENERIC_HDLC_VERSION) || (GENERIC_HDLC_VERSION < 4)
-STATIC int
-chan_dev_ioctl (struct net_device * hdlc, struct ifreq * ifr, int cmd)
-{
- if (cmd == HDLCSCLOCK)
- {
- ifr->ifr_ifru.ifru_ivalue = LINE_DEFAULT;
- return 0;
- }
- return -EINVAL;
-}
-#else
STATIC int
chan_dev_ioctl (struct net_device * dev, struct ifreq * ifr, int cmd)
{
@@ -435,16 +326,11 @@ chan_dev_ioctl (struct net_device * dev, struct ifreq * ifr, int cmd)
STATIC int
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-chan_attach_noop (hdlc_device * hdlc, unsigned short foo_1, unsigned short foo_2)
-#else
chan_attach_noop (struct net_device * ndev, unsigned short foo_1, unsigned short foo_2)
-#endif
{
return 0; /* our driver has nothing to do here, show's
* over, go home */
}
-#endif
STATIC struct net_device_stats *
@@ -455,16 +341,12 @@ chan_get_stats (struct net_device * ndev)
struct sbecom_chan_stats *stats;
int channum;
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
- channum = DEV_TO_PRIV (ndev)->channum;
-#else
{
struct c4_priv *priv;
priv = (struct c4_priv *) dev_to_hdlc (ndev)->priv;
channum = priv->channum;
}
-#endif
ch = c4_find_chan (channum);
if (ch == NULL)
@@ -511,34 +393,19 @@ get_ci_by_dev (struct net_device * ndev)
}
-#if !defined(GENERIC_HDLC_VERSION) || (GENERIC_HDLC_VERSION < 4)
-STATIC int
-c4_linux_xmit (hdlc_device * hdlc, struct sk_buff * skb)
-{
- int rval;
-
- rval = musycc_start_xmit (DEV_TO_PRIV (hdlc)->ci, DEV_TO_PRIV (hdlc)->channum, skb);
- return -rval;
-}
-#else /* new */
STATIC int
c4_linux_xmit (struct sk_buff * skb, struct net_device * ndev)
{
const struct c4_priv *priv;
int rval;
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
- priv = DEV_TO_PRIV (ndev);
-#else
hdlc_device *hdlc = dev_to_hdlc (ndev);
priv = hdlc->priv;
-#endif
rval = musycc_start_xmit (priv->ci, priv->channum, skb);
return -rval;
}
-#endif /* GENERIC_HDLC_VERSION */
static const struct net_device_ops chan_ops = {
.ndo_open = chan_open,
@@ -823,18 +690,10 @@ do_create_chan (struct net_device * ndev, void *data)
ret = mkret (c4_new_chan (ci, cp.port, cp.channum, dev));
if (ret)
{
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
- rtnl_unlock (); /* needed due to Ioctl calling sequence */
- V7 (unregister_hdlc_device) (dev_to_hdlc (dev));
- rtnl_lock (); /* needed due to Ioctl calling sequence */
- OS_kfree (DEV_TO_PRIV (dev));
- OS_kfree (dev);
-#else
rtnl_unlock (); /* needed due to Ioctl calling sequence */
unregister_hdlc_device (dev);
rtnl_lock (); /* needed due to Ioctl calling sequence */
free_netdev (dev);
-#endif
}
return ret;
}
@@ -883,11 +742,7 @@ do_deluser (struct net_device * ndev, int lockit)
const struct c4_priv *priv;
int channum;
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
- priv = DEV_TO_PRIV (ndev);
-#else
priv = (struct c4_priv *) dev_to_hdlc (ndev)->priv;
-#endif
ci = priv->ci;
channum = priv->channum;
@@ -897,22 +752,12 @@ do_deluser (struct net_device * ndev, int lockit)
ch->user = 0; /* will be freed, below */
}
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
- if (lockit)
- rtnl_unlock (); /* needed if Ioctl calling sequence */
- V7 (unregister_hdlc_device) (dev_to_hdlc (ndev));
- if (lockit)
- rtnl_lock (); /* needed if Ioctl calling sequence */
- OS_kfree (DEV_TO_PRIV (ndev));
- OS_kfree (ndev);
-#else
if (lockit)
rtnl_unlock (); /* needed if Ioctl calling sequence */
unregister_hdlc_device (ndev);
if (lockit)
rtnl_lock (); /* needed if Ioctl calling sequence */
free_netdev (ndev);
-#endif
return 0;
}
@@ -1339,14 +1184,6 @@ c4_mod_remove (void)
module_init (c4_mod_init);
module_exit (c4_mod_remove);
-#ifndef SBE_INCLUDE_SYMBOLS
-#ifndef CONFIG_SBE_WANC24_NCOMM
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-EXPORT_NO_SYMBOLS;
-#endif
-#endif
-#endif
-
MODULE_AUTHOR ("SBE Technical Services <support@sbei.com>");
MODULE_DESCRIPTION ("wanPCI-CxT1E1 Generic HDLC WAN Driver module");
#ifdef MODULE_LICENSE
diff --git a/drivers/staging/cxt1e1/musycc.c b/drivers/staging/cxt1e1/musycc.c
index d3f5a5b52dc..12c76a553e0 100644
--- a/drivers/staging/cxt1e1/musycc.c
+++ b/drivers/staging/cxt1e1/musycc.c
@@ -405,7 +405,6 @@ musycc_update_tx_thp (mch_t * ch)
}
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,41)
/*
* This is the workq task executed by the OS when our queue_work() is
* scheduled and run. It can fire off either RX or TX ACTIVATION depending
@@ -515,7 +514,6 @@ musycc_wq_chan_restart (void *arg) /* channel private structure */
#endif
}
}
-#endif
/*
@@ -531,7 +529,6 @@ musycc_chan_restart (mch_t * ch)
ch->channum, ch->txd_irq_srv, ch->txd_irq_srv->status);
#endif
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,41)
/* 2.6 - find next unprocessed message, then set TX thp to it */
#ifdef RLD_RESTART_DEBUG
pr_info(">> musycc_chan_restart: scheduling Chan %x workQ @ %p\n", ch->channum, &ch->ch_work);
@@ -539,51 +536,9 @@ musycc_chan_restart (mch_t * ch)
c4_wk_chan_restart (ch); /* work queue mechanism fires off: Ref:
* musycc_wq_chan_restart () */
-#else
-
-
- /* 2.4 - find next unprocessed message, then set TX thp to it */
-#ifdef RLD_RESTART_DEBUG
- pr_info(">> musycc_chan_restart: scheduling Chan %x start_tx %x\n", ch->channum, ch->ch_start_tx);
-#endif
- /* restart transmission from background loop */
- ch->up->up->wd_notify = WD_NOTIFY_1TX;
-#endif
}
-#if 0
-void
-musycc_cleanup (ci_t * ci)
-{
- mpi_t *pi;
- int i, j;
-
- /* free up driver resources */
- ci->state = C_INIT; /* mark as hardware not available */
-
- for (i = 0; i < ci->max_ports; i++)
- {
- pi = &ci->port[i];
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,41)
- c4_wq_port_cleanup (pi);
-#endif
- for (j = 0; j < MUSYCC_NCHANS; j++)
- {
- if (pi->chan[j])
- OS_kfree (pi->chan[j]); /* free mch_t struct */
- }
- OS_kfree (pi->regram_saved);
- }
-#if 0
- /* obsolete - watchdog is now static w/in ci_t */
- OS_free_watchdog (ci->wd);
-#endif
- OS_kfree (ci->iqd_p_saved);
- OS_kfree (ci);
-}
-#endif
-
void
rld_put_led (mpi_t * pi, u_int32_t ledval)
{
@@ -2008,37 +1963,13 @@ musycc_start_xmit (ci_t * ci, int channum, void *mem_token)
atomic_add (len, &ci->tx_pending);
ch->s.tx_packets++;
ch->s.tx_bytes += len;
-#if 0
- spin_unlock_irqrestore (&ch->ch_txlock, flags); /* allow pending
- * interrupt to sneak
- * thru */
-#endif
-
/*
* If an ONR was seen, then channel requires poking to restart
* transmission.
*/
if (ch->ch_start_tx)
{
-#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,41)
- SD_SEM_TAKE (&ci->sem_wdbusy, "_wd_"); /* only 1 thru here, per
- * board */
- if ((ch->ch_start_tx == CH_START_TX_ONR) && (ch->p.chan_mode == CFG_CH_PROTO_TRANS))
- {
- /* ONR restart transmission from background loop */
- ci->wd_notify = WD_NOTIFY_ONR; /* enabled global watchdog
- * scan-thru */
- } else
- {
- /* start first transmission from background loop */
- ci->wd_notify = WD_NOTIFY_1TX; /* enabled global watchdog
- * scan-thru */
- }
musycc_chan_restart (ch);
- SD_SEM_GIVE (&ci->sem_wdbusy);
-#else
- musycc_chan_restart (ch);
-#endif
}
#ifdef SBE_WAN256T3_ENABLE
wan256t3_led (ci, LED_TX, LEDV_G);
@@ -2047,139 +1978,4 @@ musycc_start_xmit (ci_t * ci, int channum, void *mem_token)
}
-#if 0
-int
-musycc_set_chan (ci_t * ci, int channum, struct sbecom_chan_param * p)
-{
- mch_t *ch;
- int rok = 0;
- int n = 0;
-
- if (channum < 0 || channum >= (MUSYCC_NPORTS * MUSYCC_NCHANS)) /* sanity chk param */
- return ECHRNG;
- if (!(ch = sd_find_chan (ci, channum)))
- return ENOENT;
- if (ch->channum != p->channum)
- return EINVAL;
- if (sd_line_is_ok (ch->user))
- {
- rok = 1;
- sd_line_is_down (ch->user);
- }
- if (ch->state == UP && /* bring down in current configuration */
- (ch->p.status != p->status ||
- ch->p.chan_mode != p->chan_mode ||
- ch->p.intr_mask != p->intr_mask ||
- ch->txd_free < ch->txd_num))
- {
- if ((n = musycc_chan_down (ci, channum)))
- return n;
- if (ch->p.mode_56k != p->mode_56k)
- {
- ch->p = *p; /* copy in new parameters */
- musycc_update_timeslots (&ci->port[ch->channum / MUSYCC_NCHANS]);
- } else
- ch->p = *p; /* copy in new parameters */
- if ((n = musycc_chan_up (ci, channum)))
- return n;
- sd_enable_xmit (ch->user); /* re-enable to catch flow controlled
- * channel */
- } else
- {
- if (ch->p.mode_56k != p->mode_56k)
- {
- ch->p = *p; /* copy in new parameters */
- musycc_update_timeslots (&ci->port[ch->channum / MUSYCC_NCHANS]);
- } else
- ch->p = *p; /* copy in new parameters */
- }
-
- if (rok)
- sd_line_is_up (ch->user);
- return 0;
-}
-#endif
-
-
-int
-musycc_get_chan (ci_t * ci, int channum, struct sbecom_chan_param * p)
-{
- mch_t *ch;
-
-#if 0
- if (channum < 0 || channum >= (MUSYCC_NPORTS * MUSYCC_NCHANS)) /* sanity chk param */
- return ECHRNG;
-#endif
- if (!(ch = sd_find_chan (ci, channum)))
- return ENOENT;
- *p = ch->p;
- return 0;
-}
-
-
-int
-musycc_get_chan_stats (ci_t * ci, int channum, struct sbecom_chan_stats * p)
-{
- mch_t *ch;
-
- if (channum < 0 || channum >= (MUSYCC_NPORTS * MUSYCC_NCHANS)) /* sanity chk param */
- return ECHRNG;
- if (!(ch = sd_find_chan (ci, channum)))
- return ENOENT;
- *p = ch->s;
- p->tx_pending = atomic_read (&ch->tx_pending);
- return 0;
-}
-
-
-
-#ifdef SBE_WAN256T3_ENABLE
-int
-musycc_chan_down (ci_t * ci, int channum)
-{
- mch_t *ch;
- mpi_t *pi;
- int i, gchan;
-
- if (!(ch = sd_find_chan (ci, channum)))
- return EINVAL;
- pi = ch->up;
- gchan = ch->gchan;
-
- /* Deactivate the channel */
- musycc_serv_req (pi, SR_CHANNEL_DEACTIVATE | SR_RX_DIRECTION | gchan);
- ch->ch_start_rx = 0;
- musycc_serv_req (pi, SR_CHANNEL_DEACTIVATE | SR_TX_DIRECTION | gchan);
- ch->ch_start_tx = 0;
-
- if (ch->state == DOWN)
- return 0;
- ch->state = DOWN;
-
- pi->regram->thp[gchan] = 0;
- pi->regram->tmp[gchan] = 0;
- pi->regram->rhp[gchan] = 0;
- pi->regram->rmp[gchan] = 0;
- FLUSH_MEM_WRITE ();
- for (i = 0; i < ch->txd_num; i++)
- {
- if (ch->mdt[i].mem_token != 0)
- OS_mem_token_free (ch->mdt[i].mem_token);
- }
-
- for (i = 0; i < ch->rxd_num; i++)
- {
- if (ch->mdr[i].mem_token != 0)
- OS_mem_token_free (ch->mdr[i].mem_token);
- }
-
- OS_kfree (ch->mdt);
- ch->mdt = 0;
- OS_kfree (ch->mdr);
- ch->mdr = 0;
-
- return 0;
-}
-#endif
-
/*** End-of-File ***/
diff --git a/drivers/staging/cxt1e1/pmc93x6_eeprom.c b/drivers/staging/cxt1e1/pmc93x6_eeprom.c
index 1c8dfb80e7d..62b12fb45fc 100644
--- a/drivers/staging/cxt1e1/pmc93x6_eeprom.c
+++ b/drivers/staging/cxt1e1/pmc93x6_eeprom.c
@@ -500,11 +500,7 @@ pmc_init_seeprom (u_int32_t addr, u_int32_t serialNum)
time_t createTime;
int i;
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
- createTime = CURRENT_TIME;
-#else
createTime = get_seconds ();
-#endif
/* use template data */
for (i = 0; i < sizeof (FLD_TYPE2); ++i)
diff --git a/drivers/staging/cxt1e1/pmcc4.h b/drivers/staging/cxt1e1/pmcc4.h
index 26c1f0ea72e..ef6ac7fe7dd 100644
--- a/drivers/staging/cxt1e1/pmcc4.h
+++ b/drivers/staging/cxt1e1/pmcc4.h
@@ -117,12 +117,8 @@ extern "C"
#include "pmcc4_private.h"
-#if !(LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
char *get_hdlc_name (hdlc_device *);
-#endif
-
-
/*
* external interface
*/
diff --git a/drivers/staging/cxt1e1/pmcc4_drv.c b/drivers/staging/cxt1e1/pmcc4_drv.c
index 333cf2687dd..9f730e68526 100644
--- a/drivers/staging/cxt1e1/pmcc4_drv.c
+++ b/drivers/staging/cxt1e1/pmcc4_drv.c
@@ -119,12 +119,10 @@ char OSSIid_pmcc4_drvc[] =
#define KERN_WARN KERN_WARNING
/* forward references */
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,41)
status_t c4_wk_chan_init (mpi_t *, mch_t *);
void c4_wq_port_cleanup (mpi_t *);
status_t c4_wq_port_init (mpi_t *);
-#endif
int c4_loop_port (ci_t *, int, u_int8_t);
status_t c4_set_port (ci_t *, int);
status_t musycc_chan_down (ci_t *, int);
@@ -533,145 +531,15 @@ checkPorts (ci_t * ci)
STATIC void
c4_watchdog (ci_t * ci)
{
-#if 0
- //unsigned long flags;
-#endif
-
if (drvr_state != SBE_DRVR_AVAILABLE)
{
if (log_level >= LOG_MONITOR)
pr_info("drvr not available (%x)\n", drvr_state);
return;
}
-#if 0
- SD_SEM_TAKE (&ci->sem_wdbusy, "_wd_"); /* only 1 thru here, per
- * board */
-#endif
-
ci->wdcount++;
checkPorts (ci);
-#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,41)
- if (ci->wd_notify)
- { /* is there a state change to search for */
- int port, gchan;
-
- ci->wd_notify = 0; /* reset notification */
- for (gchan = 0; gchan < MUSYCC_NCHANS; gchan++)
- {
- for (port = 0; port < ci->max_port; port++)
- {
- mch_t *ch = ci->port[port].chan[gchan];
-
- if (!ch || ci->state != C_RUNNING) /* state changed while
- * acquiring semaphore */
- break;
- if (ch->state == UP)/* channel must be set up */
- {
-#if 0
-#ifdef RLD_TRANS_DEBUG
- if (1 || log_level >= LOG_MONITOR)
-#else
- if (log_level >= LOG_MONITOR)
-#endif
- pr_info("%s: watchdog reviving Port %d Channel %d [%d] sts %x/%x, start_TX %x free %x start_RX %x\n",
- ci->devname, ch->channum, port, gchan, ch->channum,
- ch->p.status, ch->status,
- ch->ch_start_tx, ch->txd_free, ch->ch_start_rx);
-#endif
-
- /**********************************/
- /** check for RX restart request **/
- /**********************************/
-
- if (ch->ch_start_rx &&
- (ch->status & RX_ENABLED)) /* requires start on
- * enabled RX */
- {
- ch->ch_start_rx = 0; /* we are restarting RX... */
-#ifdef RLD_TRANS_DEBUG
- pr_info("++ c4_watchdog() CHAN RX ACTIVATE: chan %d\n",
- ch->channum);
-#endif
-#ifdef RLD_RXACT_DEBUG
- {
- struct mdesc *md;
- static int hereb4 = 7;
-
- if (hereb4)
- {
- hereb4--;
- md = &ch->mdr[ch->rxix_irq_srv];
- pr_info("++ c4_watchdog[%d] CHAN RX ACTIVATE: rxix_irq_srv %d, md %p sts %x, rxpkt %lu\n",
- ch->channum, ch->rxix_irq_srv, md, le32_to_cpu (md->status), ch->s.rx_packets);
- musycc_dump_rxbuffer_ring (ch, 1); /* RLD DEBUG */
- }
- }
-#endif
- musycc_serv_req (ch->up, SR_CHANNEL_ACTIVATE | SR_RX_DIRECTION | gchan);
- }
- /**********************************/
- /** check for TX restart request **/
- /**********************************/
-
- if (ch->ch_start_tx &&
- (ch->status & TX_ENABLED)) /* requires start on
- * enabled TX */
- {
- struct mdesc *md;
-
- /*
- * find next unprocessed message, then set TX thp to
- * it
- */
- musycc_update_tx_thp (ch);
-
-#if 0
- spin_lock_irqsave (&ch->ch_txlock, flags);
-#endif
- md = ch->txd_irq_srv;
- if (!md)
- {
- pr_info("-- c4_watchdog[%d]: WARNING, starting NULL md\n",
- ch->channum);
- pr_info("-- chan %d txd_irq_srv %p sts %x usr_add %p sts %x, txpkt %lu\n",
- ch->channum, ch->txd_irq_srv, le32_to_cpu ((struct mdesc *) (ch->txd_irq_srv)->status),
- ch->txd_usr_add, le32_to_cpu ((struct mdesc *) (ch->txd_usr_add)->status),
- ch->s.tx_packets);
-#if 0
- spin_unlock_irqrestore (&ch->ch_txlock, flags);
-#endif
- } else if (md->data && ((le32_to_cpu (md->status)) & MUSYCC_TX_OWNED))
- {
-#ifdef RLD_TRANS_DEBUG
- pr_info("++ c4_watchdog[%d] CHAN TX ACTIVATE: start_tx %x\n",
- ch->channum, ch->ch_start_tx);
-#endif
- ch->ch_start_tx = 0; /* we are restarting
- * TX... */
-#if 0
- spin_unlock_irqrestore (&ch->ch_txlock, flags); /* allow interrupts for
- * service request */
-#endif
- musycc_serv_req (ch->up, SR_CHANNEL_ACTIVATE | SR_TX_DIRECTION | gchan);
-#ifdef RLD_TRANS_DEBUG
- if (1 || log_level >= LOG_MONITOR)
-#else
- if (log_level >= LOG_MONITOR)
-#endif
- pr_info("++ SACK[P%d/C%d] ack'd, continuing...\n",
- ch->up->portnum, ch->channum);
- }
- }
- }
- }
- }
- }
-#else
ci->wd_notify = 0;
-#endif
-#if 0
- SD_SEM_GIVE (&ci->sem_wdbusy);/* release per-board hold */
-#endif
}
@@ -690,9 +558,7 @@ c4_cleanup (void)
for (portnum = 0; portnum < ci->max_port; portnum++)
{
pi = &ci->port[portnum];
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,41)
c4_wq_port_cleanup (pi);
-#endif
for (j = 0; j < MUSYCC_NCHANS; j++)
{
if (pi->chan[j])
@@ -700,10 +566,6 @@ c4_cleanup (void)
}
OS_kfree (pi->regram_saved);
}
-#if 0
- /* obsolete - watchdog is now static w/in ci_t */
- OS_free_watchdog (ci->wd);
-#endif
OS_kfree (ci->iqd_p_saved);
OS_kfree (ci);
ci = next; /* cleanup next board, if any */
@@ -1145,7 +1007,6 @@ c4_set_port (ci_t * ci, int portnum)
return EBUSY; /* group needs initialization only for
* first channel of a group */
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,41)
{
status_t ret;
@@ -1153,7 +1014,6 @@ c4_set_port (ci_t * ci, int portnum)
* workqueue_struct */
return (ret);
}
-#endif
init_comet (ci, pi->cometbase, pp->port_mode, 1 /* clockmaster == true */ , pp->portP);
clck = pci_read_32 ((u_int32_t *) &ci->cpldbase->mclk) & PMCC4_CPLD_MCLK_MASK;
@@ -1269,14 +1129,12 @@ c4_new_chan (ci_t * ci, int portnum, int channum, void *user)
spin_lock_init (&ch->ch_rxlock);
spin_lock_init (&ch->ch_txlock);
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,41)
{
status_t ret;
if ((ret = c4_wk_chan_init (pi, ch)))
return ret;
}
-#endif
/* save off interface assignments which bound a board */
if (ci->first_if == 0) /* first channel registered is assumed to
@@ -1705,31 +1563,23 @@ sbecom_get_brdinfo (ci_t * ci, struct sbe_brd_info * bip, u_int8_t *bsn)
if (ci->first_if)
{
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
- np = (char *) hdlc_to_name (ci->first_if);
-#else
{
struct net_device *dev;
dev = (struct net_device *) ci->first_if;
np = (char *) dev->name;
}
-#endif
strncpy (bip->first_iname, np, CHNM_STRLEN - 1);
} else
strcpy (bip->first_iname, "<NULL>");
if (ci->last_if)
{
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
- np = (char *) hdlc_to_name (ci->last_if);
-#else
{
struct net_device *dev;
dev = (struct net_device *) ci->last_if;
np = (char *) dev->name;
}
-#endif
strncpy (bip->last_iname, np, CHNM_STRLEN - 1);
} else
strcpy (bip->last_iname, "<NULL>");
@@ -1763,11 +1613,7 @@ c4_get_iidinfo (ci_t * ci, struct sbe_iid_info * iip)
if (!(dev = getuserbychan (iip->channum)))
return ENOENT;
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
- np = (char *) hdlc_to_name (dev_to_hdlc (dev));
-#else
np = dev->name;
-#endif
strncpy (iip->iname, np, CHNM_STRLEN - 1);
return 0;
}
@@ -1826,11 +1672,7 @@ c4_ebus_intr_th_handler (void *devp)
pci_write_32 ((u_int32_t *) &ci->reg->glcd, GCD_MAGIC | MUSYCC_GCD_INTB_DISABLE);
#endif
-#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,4,20)
- return;
-#else
return IRQ_RETVAL (handled);
-#endif
}
diff --git a/drivers/staging/cxt1e1/sbecom_inline_linux.h b/drivers/staging/cxt1e1/sbecom_inline_linux.h
index c65172db2ad..5a72cb5cff4 100644
--- a/drivers/staging/cxt1e1/sbecom_inline_linux.h
+++ b/drivers/staging/cxt1e1/sbecom_inline_linux.h
@@ -48,9 +48,6 @@
#else
#include <linux/types.h>
#include <linux/version.h>
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18)
-#include <linux/config.h>
-#endif
#if defined(CONFIG_SMP) && ! defined(__SMP__)
#define __SMP__
#endif
@@ -60,12 +57,8 @@
#ifdef MODULE
#ifdef MODVERSIONS
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-#include <linux/modversions.h>
-#else
#include <config/modversions.h>
#endif
-#endif
#include <linux/module.h>
#endif
#endif
@@ -260,11 +253,7 @@ OS_sem_free (void *sem)
struct watchdog
{
struct timer_list h;
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
- struct tq_struct tq;
-#else
struct work_struct work;
-#endif
void *softc;
void (*func) (void *softc);
int ticks;
diff --git a/drivers/staging/dream/camera/msm_vfe8x.c b/drivers/staging/dream/camera/msm_vfe8x.c
index e61fdba6283..d87d56f914d 100644
--- a/drivers/staging/dream/camera/msm_vfe8x.c
+++ b/drivers/staging/dream/camera/msm_vfe8x.c
@@ -644,17 +644,10 @@ static int vfe_config(struct msm_vfe_cfg_cmd *cmd, void *data)
if (!axid)
return -EFAULT;
- axio =
- kmalloc(sizeof(struct vfe_cmd_axi_output_config),
- GFP_ATOMIC);
- if (!axio)
- return -ENOMEM;
-
- if (copy_from_user(axio, (void __user *)(vfecmd.value),
- sizeof(struct vfe_cmd_axi_output_config))) {
- kfree(axio);
- return -EFAULT;
- }
+ axio = memdup_user((void __user *)(vfecmd.value),
+ sizeof(struct vfe_cmd_axi_output_config));
+ if (IS_ERR(axio))
+ return PTR_ERR(axio);
vfe_config_axi(OUTPUT_1, axid, axio);
vfe_axi_output_config(axio);
@@ -669,17 +662,10 @@ static int vfe_config(struct msm_vfe_cfg_cmd *cmd, void *data)
if (!axid)
return -EFAULT;
- axio =
- kmalloc(sizeof(struct vfe_cmd_axi_output_config),
- GFP_ATOMIC);
- if (!axio)
- return -ENOMEM;
-
- if (copy_from_user(axio, (void __user *)(vfecmd.value),
- sizeof(struct vfe_cmd_axi_output_config))) {
- kfree(axio);
- return -EFAULT;
- }
+ axio = memdup_user((void __user *)(vfecmd.value),
+ sizeof(struct vfe_cmd_axi_output_config));
+ if (IS_ERR(axio))
+ return PTR_ERR(axio);
vfe_config_axi(OUTPUT_2, axid, axio);
@@ -694,17 +680,10 @@ static int vfe_config(struct msm_vfe_cfg_cmd *cmd, void *data)
if (!axid)
return -EFAULT;
- axio =
- kmalloc(sizeof(struct vfe_cmd_axi_output_config),
- GFP_ATOMIC);
- if (!axio)
- return -ENOMEM;
-
- if (copy_from_user(axio, (void __user *)(vfecmd.value),
- sizeof(struct vfe_cmd_axi_output_config))) {
- kfree(axio);
- return -EFAULT;
- }
+ axio = memdup_user((void __user *)(vfecmd.value),
+ sizeof(struct vfe_cmd_axi_output_config));
+ if (IS_ERR(axio))
+ return PTR_ERR(axio);
vfe_config_axi(OUTPUT_1_AND_2,
axid, axio);
diff --git a/drivers/staging/dream/pmem.c b/drivers/staging/dream/pmem.c
index 6387365a833..7d6bbadd7fc 100644
--- a/drivers/staging/dream/pmem.c
+++ b/drivers/staging/dream/pmem.c
@@ -24,8 +24,8 @@
#include <linux/mempolicy.h>
#include <linux/sched.h>
#include <linux/slab.h>
-#include <asm/io.h>
-#include <asm/uaccess.h>
+#include <linux/io.h>
+#include <linux/uaccess.h>
#include <asm/cacheflush.h>
#define PMEM_MAX_DEVICES 10
@@ -175,7 +175,7 @@ static int pmem_mmap(struct file *, struct vm_area_struct *);
static int pmem_open(struct inode *, struct file *);
static long pmem_ioctl(struct file *, unsigned int, unsigned long);
-struct file_operations pmem_fops = {
+const struct file_operations pmem_fops = {
.release = pmem_release,
.mmap = pmem_mmap,
.open = pmem_open,
@@ -209,7 +209,7 @@ static int has_allocation(struct file *file)
if (unlikely(!file->private_data))
return 0;
- data = (struct pmem_data *)file->private_data;
+ data = file->private_data;
if (unlikely(data->index < 0))
return 0;
return 1;
@@ -223,7 +223,7 @@ static int is_master_owner(struct file *file)
if (!is_pmem_file(file) || !has_allocation(file))
return 0;
- data = (struct pmem_data *)file->private_data;
+ data = file->private_data;
if (PMEM_FLAGS_MASTERMAP & data->flags)
return 1;
master_file = fget_light(data->master_fd, &put_needed);
@@ -268,7 +268,7 @@ static void pmem_revoke(struct file *file, struct pmem_data *data);
static int pmem_release(struct inode *inode, struct file *file)
{
- struct pmem_data *data = (struct pmem_data *)file->private_data;
+ struct pmem_data *data = file->private_data;
struct pmem_region_node *region_node;
struct list_head *elt, *elt2;
int id = get_id(file), ret = 0;
@@ -399,8 +399,8 @@ static int pmem_allocate(int id, unsigned long len)
DLOG("order %lx\n", order);
/* look through the bitmap:
- * if you find a free slot of the correct order use it
- * otherwise, use the best fit (smallest with size > order) slot
+ * if you find a free slot of the correct order use it
+ * otherwise, use the best fit (smallest with size > order) slot
*/
while (curr < end) {
if (PMEM_IS_FREE(id, curr)) {
@@ -426,8 +426,8 @@ static int pmem_allocate(int id, unsigned long len)
}
/* now partition the best fit:
- * split the slot into 2 buddies of order - 1
- * repeat until the slot is of the correct order
+ * split the slot into 2 buddies of order - 1
+ * repeat until the slot is of the correct order
*/
while (PMEM_ORDER(id, best_fit) > (unsigned char)order) {
int buddy;
@@ -591,7 +591,7 @@ static int pmem_mmap(struct file *file, struct vm_area_struct *vma)
return -EINVAL;
}
- data = (struct pmem_data *)file->private_data;
+ data = file->private_data;
down_write(&data->sem);
/* check this file isn't already mmaped, for submaps check this file
* has never been mmaped */
@@ -690,7 +690,7 @@ int get_pmem_user_addr(struct file *file, unsigned long *start,
#endif
return -1;
}
- data = (struct pmem_data *)file->private_data;
+ data = file->private_data;
down_read(&data->sem);
if (data->vma) {
*start = data->vma->vm_start;
@@ -712,7 +712,7 @@ int get_pmem_addr(struct file *file, unsigned long *start,
if (!is_pmem_file(file) || !has_allocation(file))
return -1;
- data = (struct pmem_data *)file->private_data;
+ data = file->private_data;
if (data->index == -1) {
#if PMEM_DEBUG
printk(KERN_INFO "pmem: requested pmem data from file with no "
@@ -766,7 +766,7 @@ void put_pmem_file(struct file *file)
if (!is_pmem_file(file))
return;
id = get_id(file);
- data = (struct pmem_data *)file->private_data;
+ data = file->private_data;
#if PMEM_DEBUG
down_write(&data->sem);
if (data->ref == 0) {
@@ -793,7 +793,7 @@ void flush_pmem_file(struct file *file, unsigned long offset, unsigned long len)
return;
id = get_id(file);
- data = (struct pmem_data *)file->private_data;
+ data = file->private_data;
if (!pmem[id].cached)
return;
@@ -822,7 +822,7 @@ end:
static int pmem_connect(unsigned long connect, struct file *file)
{
- struct pmem_data *data = (struct pmem_data *)file->private_data;
+ struct pmem_data *data = file->private_data;
struct pmem_data *src_data;
struct file *src_file;
int ret = 0, put_needed;
@@ -842,7 +842,7 @@ static int pmem_connect(unsigned long connect, struct file *file)
ret = -EINVAL;
goto err_bad_file;
}
- src_data = (struct pmem_data *)src_file->private_data;
+ src_data = src_file->private_data;
if (has_allocation(file) && (data->index != src_data->index)) {
printk(KERN_INFO "pmem: file is already mapped but doesn't "
@@ -929,7 +929,7 @@ int pmem_remap(struct pmem_region *region, struct file *file,
struct mm_struct *mm = NULL;
struct list_head *elt, *elt2;
int id = get_id(file);
- struct pmem_data *data = (struct pmem_data *)file->private_data;
+ struct pmem_data *data = file->private_data;
/* pmem region must be aligned on a page boundry */
if (unlikely(!PMEM_IS_PAGE_ALIGNED(region->offset) ||
@@ -1053,7 +1053,7 @@ static void pmem_revoke(struct file *file, struct pmem_data *data)
static void pmem_get_size(struct pmem_region *region, struct file *file)
{
- struct pmem_data *data = (struct pmem_data *)file->private_data;
+ struct pmem_data *data = file->private_data;
int id = get_id(file);
if (!has_allocation(file)) {
@@ -1082,7 +1082,7 @@ static long pmem_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
region.offset = 0;
region.len = 0;
} else {
- data = (struct pmem_data *)file->private_data;
+ data = file->private_data;
region.offset = pmem_start_addr(id, data);
region.len = pmem_len(id, data);
}
@@ -1099,7 +1099,7 @@ static long pmem_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
if (copy_from_user(&region, (void __user *)arg,
sizeof(struct pmem_region)))
return -EFAULT;
- data = (struct pmem_data *)file->private_data;
+ data = file->private_data;
return pmem_remap(&region, file, PMEM_MAP);
}
break;
@@ -1109,7 +1109,7 @@ static long pmem_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
if (copy_from_user(&region, (void __user *)arg,
sizeof(struct pmem_region)))
return -EFAULT;
- data = (struct pmem_data *)file->private_data;
+ data = file->private_data;
return pmem_remap(&region, file, PMEM_UNMAP);
break;
}
@@ -1139,7 +1139,7 @@ static long pmem_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
if (has_allocation(file))
return -EINVAL;
- data = (struct pmem_data *)file->private_data;
+ data = file->private_data;
data->index = pmem_allocate(id, arg);
break;
}
diff --git a/drivers/staging/dt3155/Kconfig b/drivers/staging/dt3155/Kconfig
deleted file mode 100644
index 4a3293c721b..00000000000
--- a/drivers/staging/dt3155/Kconfig
+++ /dev/null
@@ -1,4 +0,0 @@
-config DT3155
- tristate "DT3155 Digitizer support"
- depends on PCI
-
diff --git a/drivers/staging/dt3155/Makefile b/drivers/staging/dt3155/Makefile
deleted file mode 100644
index 136f21fdbbe..00000000000
--- a/drivers/staging/dt3155/Makefile
+++ /dev/null
@@ -1,6 +0,0 @@
-obj-$(CONFIG_DT3155) += dt3155.o
-dt3155-objs := \
- dt3155_drv.o \
- dt3155_isr.o \
- dt3155_io.o \
- allocator.o
diff --git a/drivers/staging/dt3155/TODO b/drivers/staging/dt3155/TODO
deleted file mode 100644
index 3baa3b6294c..00000000000
--- a/drivers/staging/dt3155/TODO
+++ /dev/null
@@ -1,10 +0,0 @@
-TODO:
- - fix checkpatch.pl issues
- - remove old kernel support, it is not needed
- - convert to proper PCI device API
- - fix sparse warnings
- - audit for correct subsystem interaction
- - review review review!
-
-Please send patches to Greg Kroah-Hartman <greg@kroah.com>
-and Scott Smedley <ss@aao.gov.au>
diff --git a/drivers/staging/dt3155/allocator.README b/drivers/staging/dt3155/allocator.README
deleted file mode 100644
index 05700b6c926..00000000000
--- a/drivers/staging/dt3155/allocator.README
+++ /dev/null
@@ -1,98 +0,0 @@
-
-The allocator shown here exploits high memory. This document explains
-how a user can deal with drivers uses this allocator and how a
-programmer can link in the module.
-
-The module is being used by my pxc and pxdrv device drivers (as well as
-other ones), available from ftp.systemy.it/pub/develop and
-ftp.linux.it/pub/People/Rubini
-
- User's manual
- =============
-
-
-One of the most compelling problems with any DMA-capable device is the
-allocation of a suitable memory buffer. The "allocator" module tries
-to deal with the problem in a clean way. The module is able to use
-high memory (above the one used in normal operation) for DMA
-allocation.
-
-To prevent the kernel for using high memory, so that it remains
-available for DMA, you should pass a command line argument to the
-kernel. Command line arguments can be passed to Lilo, to Loadlin or
-to whichever loader you are using (unless it's very poor in design).
-For Lilo, either use "append=" in /etc/lilo.conf or add commandline
-arguments to the interactive prompt. For example, I have a 32MB box
-and reserve two megs for DMA:
-
-In lilo.conf:
- image = /zImage
- label = linux
- append = "mem=30M"
-
-Or, interactively:
- LILO: linux mem=30M
-
-Once the kernel is booted with the right command-line argument, any
-driver linked with the allocator module will be able to get
-DMA-capable memory without much trouble (unless the various drivers
-need more memory than available).
-
-The module implements an alloc/free mechanism, so that it can serve
-multiple drivers at the same time. Note however that the allocator
-uses all of high memory and assumes to be the only piece of software
-using such memory.
-
-
- Programmer's manual
- ===================
-
-The allocator, as released, is designed to be linked to a device
-driver. In this case, the driver must call allocator_init() before
-using the allocator and must call allocator_cleanup() before
-unloading. This is usually done from within init_module() and
-cleanup_module(). If the allocator is linked to a driver, it won't be
-possible for several drivers to allocate high DMA memory, as explained
-above.
-
-It is possible, on the other hand, to compile the module as a standalone
-module, so that several modules can rely on the allocator for they DMA
-buffers. To compile the allocator as a standalone module, do the
-following in this directory (or provide a suitable Makefile, or edit
-the source code):
-
- make allocator.o CC="gcc -Dallocator_init=init_module -Dallocator_cleanup=cleanup_module -include /usr/include/linux/module.h"
-
-The previous commandline tells to include <linux/module.h> in the
-first place, and to rename the init and cleanup function to the ones
-needed for module loading and unloading. Drivers using a standalone
-allocator won't need to call allocator_init() nor allocator_cleanup().
-
-The allocator exports the following functions (declared in allocator.h):
-
- unsigned long allocator_allocate_dma (unsigned long kilobytes,
- int priority);
-
- This function returns a physical address, over high_memory,
- which corresponds to an area of at least "kilobytes" kilobytes.
- The area will be owned by the module calling the function.
- The returned address can be passed to device boards, to instruct
- their DMA controllers, via phys_to_bus(). The address can be used
- by C code after vremap()/ioremap(). The "priority" argument should
- be GFP_KERNEL or GFP_ATOMIC, according to the context of the
- caller; it is used to call kmalloc(), as the allocator must keep
- track of any region it gives away. In case of error the function
- returns 0, and the caller is expected to issue a -ENOMEM error.
-
-
- void allocator_free_dma (unsigned long address);
-
- This function is the reverse of the previous one. If a driver
- doesn't free the DMA memory it allocated, the allocator will
- consider such memory as busy. Note, however, that
- allocator_cleanup() calls kfree() on every region it reclaimed,
- so that a driver with the allocator linked in can avoid calling
- allocator_free_dma() at unload time.
-
-
-
diff --git a/drivers/staging/dt3155/allocator.c b/drivers/staging/dt3155/allocator.c
deleted file mode 100644
index d33947b0378..00000000000
--- a/drivers/staging/dt3155/allocator.c
+++ /dev/null
@@ -1,294 +0,0 @@
-/*
- * allocator.c -- allocate after high_memory, if available
- *
- * NOTE: this is different from my previous allocator, the one that
- * assembles pages, which revealed itself both slow and unreliable.
- *
- * Copyright (C) 1998 rubini@linux.it (Alessandro Rubini)
- *
- * This program is free software; you can redistribute it and/or modify
- * 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.
- *
-
--- Changes --
-
- Date Programmer Description of changes made
- -------------------------------------------------------------------
- 02-Aug-2002 NJC allocator now steps in 1MB increments, rather
- than doubling its size each time.
- Also, allocator_init(u32 *) now returns
- (in the first arg) the size of the free
- space. This is no longer consistent with
- using the allocator as a module, and some changes
- may be necessary for that purpose. This was
- designed to work with the DT3155 driver, in
- stand alone mode only!!!
- 26-Oct-2009 SS Port to 2.6.30 kernel.
- */
-
-
-#ifndef __KERNEL__
-# define __KERNEL__
-#endif
-#ifndef MODULE
-# define MODULE
-#endif
-
-
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/fs.h>
-#include <linux/proc_fs.h>
-#include <linux/errno.h>
-#include <linux/types.h>
-#include <linux/mm.h> /* PAGE_ALIGN() */
-#include <linux/io.h>
-#include <linux/slab.h>
-
-#include <asm/page.h>
-
-#include "allocator.h"
-
-/*#define ALL_DEBUG*/
-#define ALL_MSG "allocator: "
-
-#undef PDEBUG /* undef it, just in case */
-#ifdef ALL_DEBUG
-# define __static
-# define DUMP_LIST() dump_list()
-# ifdef __KERNEL__
- /* This one if debugging is on, and kernel space */
-# define PDEBUG(fmt, args...) printk(KERN_DEBUG ALL_MSG fmt, ## args)
-# else
- /* This one for user space */
-# define PDEBUG(fmt, args...) fprintf(stderr, fmt, ## args)
-# endif
-#else
-# define PDEBUG(fmt, args...) /* not debugging: nothing */
-# define DUMP_LIST()
-# define __static static
-#endif
-
-#undef PDEBUGG
-#define PDEBUGG(fmt, args...)
-/*#define PDEBUGG(fmt, args...) printk( KERN_DEBUG ALL_MSG fmt, ## args)*/
-
-
-static int allocator_himem = 1; /* 0 = probe, pos. = megs, neg. = disable */
-static int allocator_step = 1; /* This is the step size in MB */
-static int allocator_probe = 1; /* This is a flag -- 1=probe, 0=don't probe */
-
-static unsigned long allocator_buffer; /* physical address */
-static unsigned long allocator_buffer_size; /* kilobytes */
-
-/*
- * The allocator keeps a list of DMA areas, so multiple devices
- * can coexist. The list is kept sorted by address
- */
-
-struct allocator_struct {
- unsigned long address;
- unsigned long size;
- struct allocator_struct *next;
-};
-
-static struct allocator_struct *allocator_list;
-
-#ifdef ALL_DEBUG
-static int dump_list(void)
-{
- struct allocator_struct *ptr;
-
- PDEBUG("Current list:\n");
- for (ptr = allocator_list; ptr; ptr = ptr->next)
- PDEBUG("0x%08lx (size %likB)\n", ptr->address, ptr->size>>10);
- return 0;
-}
-#endif
-
-/* ========================================================================
- * This function is the actual allocator.
- *
- * If space is available in high memory (as detected at load time), that
- * one is returned. The return value is a physical address (i.e., it can
- * be used straight ahead for DMA, but needs remapping for program use).
- */
-
-unsigned long allocator_allocate_dma(unsigned long kilobytes, gfp_t flags)
-{
- struct allocator_struct *ptr = allocator_list, *newptr;
- unsigned long bytes = kilobytes << 10;
-
- /* check if high memory is available */
- if (!allocator_buffer)
- return 0;
-
- /* Round it to a multiple of the pagesize */
- bytes = PAGE_ALIGN(bytes);
- PDEBUG("request for %li bytes\n", bytes);
-
- while (ptr && ptr->next) {
- if (ptr->next->address - (ptr->address + ptr->size) >= bytes)
- break; /* enough space */
- ptr = ptr->next;
- }
- if (!ptr->next) {
- DUMP_LIST();
- PDEBUG("alloc failed\n");
- return 0; /* end of list */
- }
- newptr = kmalloc(sizeof(struct allocator_struct), flags);
- if (!newptr)
- return 0;
-
- /* ok, now stick it after ptr */
- newptr->address = ptr->address + ptr->size;
- newptr->size = bytes;
- newptr->next = ptr->next;
- ptr->next = newptr;
-
- DUMP_LIST();
- PDEBUG("returning 0x%08lx\n", newptr->address);
- return newptr->address;
-}
-
-int allocator_free_dma(unsigned long address)
-{
- struct allocator_struct *ptr = allocator_list, *prev;
-
- while (ptr && ptr->next) {
- if (ptr->next->address == address)
- break;
- ptr = ptr->next;
- }
- /* the one being freed is ptr->next */
- prev = ptr; ptr = ptr->next;
-
- if (!ptr) {
- pr_err(ALL_MSG "free_dma but add. not allocated\n");
- return -EINVAL;
- }
- PDEBUGG("freeing: %08lx (%li) next %08lx\n", ptr->address, ptr->size,
- ptr->next->address);
- prev->next = ptr->next;
- kfree(ptr);
-
- /* dump_list(); */
- return 0;
-}
-
-/* ========================================================================
- * Init and cleanup
- *
- * On cleanup everything is released. If the list is not empty, that a
- * problem of our clients
- */
-int allocator_init(u32 *allocator_max)
-{
- /* check how much free memory is there */
- void *remapped;
- unsigned long max;
- unsigned long trial_size = allocator_himem<<20;
- unsigned long last_trial = 0;
- unsigned long step = allocator_step<<20;
- unsigned long i = 0;
- struct allocator_struct *head, *tail;
- char test_string[] = "0123456789abcde"; /* 16 bytes */
-
- PDEBUGG("himem = %i\n", allocator_himem);
- if (allocator_himem < 0) /* don't even try */
- return -EINVAL;
-
- if (!trial_size)
- trial_size = 1<<20; /* not specified: try one meg */
-
- while (1) {
- remapped = ioremap(__pa(high_memory), trial_size);
- if (!remapped) {
- PDEBUGG("%li megs failed!\n", trial_size>>20);
- break;
- }
- PDEBUGG("Trying %li megs (at %p, %p)\n", trial_size>>20,
- (void *)__pa(high_memory), remapped);
- for (i = last_trial; i < trial_size; i += 16) {
- strcpy((char *)(remapped)+i, test_string);
- if (strcmp((char *)(remapped)+i, test_string))
- break;
- }
- iounmap((void *)remapped);
- schedule();
- last_trial = trial_size;
- if (i == trial_size)
- trial_size += step; /* increment, if all went well */
- else {
- PDEBUGG("%li megs copy test failed!\n", trial_size>>20);
- break;
- }
- if (!allocator_probe)
- break;
- }
- PDEBUG("%li megs (%li k, %li b)\n", i>>20, i>>10, i);
- allocator_buffer_size = i>>10; /* kilobytes */
- allocator_buffer = __pa(high_memory);
- if (!allocator_buffer_size) {
- printk(KERN_WARNING ALL_MSG "no free high memory to use\n");
- return -ENOMEM;
- }
-
- /*
- * to simplify things, always have two cells in the list:
- * the first and the last. This avoids some conditionals and
- * extra code when allocating and deallocating: we only play
- * in the middle of the list
- */
- head = kmalloc(sizeof(struct allocator_struct), GFP_KERNEL);
- if (!head)
- return -ENOMEM;
- tail = kmalloc(sizeof(struct allocator_struct), GFP_KERNEL);
- if (!tail) {
- kfree(head);
- return -ENOMEM;
- }
-
- max = allocator_buffer_size<<10;
-
- head->size = tail->size = 0;
- head->address = allocator_buffer;
- tail->address = allocator_buffer + max;
- head->next = tail;
- tail->next = NULL;
- allocator_list = head;
-
- /* Back to the user code, in KB */
- *allocator_max = allocator_buffer_size;
-
- return 0; /* ok, ready */
-}
-
-void allocator_cleanup(void)
-{
- struct allocator_struct *ptr, *next;
-
- for (ptr = allocator_list; ptr; ptr = next) {
- next = ptr->next;
- PDEBUG("freeing list: 0x%08lx\n", ptr->address);
- kfree(ptr);
- }
-
- allocator_buffer = 0;
- allocator_buffer_size = 0;
- allocator_list = NULL;
-}
-
-
diff --git a/drivers/staging/dt3155/allocator.h b/drivers/staging/dt3155/allocator.h
deleted file mode 100644
index 425b70fcd50..00000000000
--- a/drivers/staging/dt3155/allocator.h
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * allocator.h -- prototypes for allocating high memory
- *
- * NOTE: this is different from my previous allocator, the one that
- * assembles pages, which revealed itself both slow and unreliable.
- *
- * Copyright (C) 1998 rubini@linux.it (Alessandro Rubini)
- *
- * This program is free software; you can redistribute it and/or modify
- * 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.
- *
- */
-
-int allocator_free_dma(unsigned long address);
-unsigned long allocator_allocate_dma(unsigned long kilobytes, gfp_t flags);
-int allocator_init(u32 *);
-void allocator_cleanup(void);
diff --git a/drivers/staging/dt3155/dt3155.h b/drivers/staging/dt3155/dt3155.h
deleted file mode 100644
index 793e2fcf446..00000000000
--- a/drivers/staging/dt3155/dt3155.h
+++ /dev/null
@@ -1,161 +0,0 @@
-/*
-
-Copyright 1996,2002,2005 Gregory D. Hager, Alfred A. Rizzi, Noah J. Cowan,
- Jason Lapenta, Scott Smedley
-
-This file is part of the DT3155 Device Driver.
-
-The DT3155 Device Driver is free software; you can redistribute it
-and/or modify 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 DT3155 Device Driver 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 the DT3155 Device Driver; if not, write to the Free
-Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
-MA 02111-1307 USA
-
--- Changes --
-
- Date Programmer Description of changes made
- -------------------------------------------------------------------
- 03-Jul-2000 JML n/a
- 10-Oct-2001 SS port to 2.4 kernel.
- 24-Jul-2002 SS remove unused code & added GPL licence.
- 05-Aug-2005 SS port to 2.6 kernel; make CCIR mode default.
-
-*/
-
-#ifndef _DT3155_INC
-#define _DT3155_INC
-
-#include <linux/types.h>
-#include <linux/time.h> /* struct timeval */
-
-
-/* Uncomment this for 50Hz CCIR */
-#define CCIR 1
-
-/* Can be 1 or 2 */
-#define MAXBOARDS 1
-
-#define BOARD_MAX_BUFFS 3
-#define MAXBUFFERS (BOARD_MAX_BUFFS*MAXBOARDS)
-
-#define PCI_PAGE_SIZE (1 << 12)
-
-#ifdef CCIR
-#define DT3155_MAX_ROWS 576
-#define DT3155_MAX_COLS 768
-#define FORMAT50HZ 1
-#else
-#define DT3155_MAX_ROWS 480
-#define DT3155_MAX_COLS 640
-#define FORMAT50HZ 0
-#endif
-
-/* Configuration structure */
-struct dt3155_config {
- u32 acq_mode;
- u32 cols, rows;
- u32 continuous;
-};
-
-
-/* hold data for each frame */
-struct frame_info {
- u32 addr; /* address of the buffer with the frame */
- u32 tag; /* unique number for the frame */
- struct timeval time; /* time that capture took place */
-};
-
-/*
- * Structure for interrupt and buffer handling.
- * This is the setup for 1 card
- */
-struct dt3155_fbuffer {
- int nbuffers;
-
- struct frame_info frame_info[BOARD_MAX_BUFFS];
-
- int empty_buffers[BOARD_MAX_BUFFS]; /* indexes empty frames */
- int empty_len; /* Number of empty buffers */
- /* Zero means empty */
-
- int active_buf; /* Where data is currently dma'ing */
- int locked_buf; /* Buffers used by user */
-
- int ready_que[BOARD_MAX_BUFFS];
- u32 ready_head; /* The most recent buffer located here */
- u32 ready_len; /* The number of ready buffers */
-
- int even_happened;
- int even_stopped;
-
- int stop_acquire; /* Flag to stop interrupts */
- u32 frame_count; /* Counter for frames acquired by this card */
-};
-
-
-
-#define DT3155_MODE_FRAME 1
-#define DT3155_MODE_FIELD 2
-
-#define DT3155_SNAP 1
-#define DT3155_ACQ 2
-
-/* There is one status structure for each card. */
-struct dt3155_status {
- int fixed_mode; /* if 1, we are in fixed frame mode */
- u32 reg_addr; /* Register address for a single card */
- u32 mem_addr; /* Buffer start addr for this card */
- u32 mem_size; /* This is the amount of mem available */
- u32 irq; /* this card's irq */
- struct dt3155_config config; /* configuration struct */
- struct dt3155_fbuffer fbuffer; /* frame buffer state struct */
- u32 state; /* this card's state */
- u32 device_installed; /* Flag if installed. 1=installed */
-};
-
-/* Reference to global status structure */
-extern struct dt3155_status dt3155_status[MAXBOARDS];
-
-#define DT3155_STATE_IDLE 0x00
-#define DT3155_STATE_FRAME 0x01
-#define DT3155_STATE_FLD 0x02
-#define DT3155_STATE_STOP 0x100
-#define DT3155_STATE_ERROR 0x200
-#define DT3155_STATE_MODE 0x0ff
-
-#define DT3155_IOC_MAGIC '!'
-
-#define DT3155_SET_CONFIG _IOW(DT3155_IOC_MAGIC, 1, struct dt3155_config)
-#define DT3155_GET_CONFIG _IOR(DT3155_IOC_MAGIC, 2, struct dt3155_status)
-#define DT3155_STOP _IO(DT3155_IOC_MAGIC, 3)
-#define DT3155_START _IO(DT3155_IOC_MAGIC, 4)
-#define DT3155_FLUSH _IO(DT3155_IOC_MAGIC, 5)
-#define DT3155_IOC_MAXNR 5
-
-/* Error codes */
-
-#define DT_ERR_NO_BUFFERS 0x10000 /* not used but it might be one day */
-#define DT_ERR_CORRUPT 0x20000
-#define DT_ERR_OVERRUN 0x30000
-#define DT_ERR_I2C_TIMEOUT 0x40000
-#define DT_ERR_MASK 0xff0000/* not used but it might be one day */
-
-/* User code will probably want to declare one of these for each card */
-struct dt3155_read {
- u32 offset;
- u32 frame_seq;
- u32 state;
-
- struct frame_info frame_info;
-};
-
-#endif /* _DT3155_inc */
diff --git a/drivers/staging/dt3155/dt3155.sysvinit b/drivers/staging/dt3155/dt3155.sysvinit
deleted file mode 100644
index 92ec0939cb7..00000000000
--- a/drivers/staging/dt3155/dt3155.sysvinit
+++ /dev/null
@@ -1,60 +0,0 @@
-#! /bin/sh
-#
-# Module load/unload script for use with SysV-style /etc/init.d/ systems.
-# On a Debian system, copy this to /etc/init.d/dt3155 and then run
-# /usr/sbin/update-rc.d dt3155 defaults 55
-# to create the appropriate /etc/rc?.d/[SK]55dt3155 start/stop links.
-# (The "55" is arbitrary but is what I use to load this rather late.)
-#
-# Andy Dougherty Feb 22 2000 doughera@lafayette.edu
-# Dept. of Physics
-# Lafayette College, Easton PA 18042
-#
-
-PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
-
-# Edit to point to your local copy.
-FILE=/usr/local/lib/modules/dt3155/dt3155.o
-NAME="dt3155"
-DESC="dt3155 Frame Grabber module"
-DEV="dt3155"
-
-if test ! -f $FILE; then
- echo "Unable to locate $FILE"
- exit 0
-fi
-
-set -e
-
-case "$1" in
- start)
- echo -n "Loading $DESC "
- if /sbin/insmod -v -f $FILE; then
- major=`grep $DEV /proc/devices | awk "{print \\$1}"`
- rm -f /dev/dt3155?
- mknod /dev/dt3155a c $major 0
- mknod /dev/dt3155b c $major 1
- chmod go+rw /dev/dt3155?
- echo
- else
- echo "$FILE not loaded."
- fi
- ;;
- stop)
- echo -n "Unloading $DESC: "
- if /sbin/rmmod $NAME ; then
- echo
- else
- echo "$DEV not removed"
- exit 0
- fi
- rm -f /dev/dt3155?
- ;;
- *)
- echo "Usage: /etc/init.d/$NAME {start|stop}"
- exit 1
- ;;
-esac
-
-exit 0
-
diff --git a/drivers/staging/dt3155/dt3155_drv.c b/drivers/staging/dt3155/dt3155_drv.c
deleted file mode 100644
index 40ef97f3feb..00000000000
--- a/drivers/staging/dt3155/dt3155_drv.c
+++ /dev/null
@@ -1,1099 +0,0 @@
-/*
-
-Copyright 1996,2002,2005 Gregory D. Hager, Alfred A. Rizzi, Noah J. Cowan,
- Jason Lapenta, Scott Smedley, Greg Sharp
-
-This file is part of the DT3155 Device Driver.
-
-The DT3155 Device Driver is free software; you can redistribute it
-and/or modify 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 DT3155 Device Driver 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 the DT3155 Device Driver; if not, write to the Free
-Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
-MA 02111-1307 USA
-
--- Changes --
-
- Date Programmer Description of changes made
- -------------------------------------------------------------------
- 03-Jul-2000 JML n/a
- 10-Oct-2001 SS port to 2.4 kernel
- 02-Apr-2002 SS Mods to use allocator as a standalone module;
- Merged John Roll's changes (john@cfa.harvard.edu)
- to make work with multiple boards.
- 02-Jul-2002 SS Merged James Rose's chages (rosejr@purdue.edu) to:
- * fix successive interrupt-driven captures
- * add select/poll support.
- 10-Jul-2002 GCS Add error check when ndevices > MAXBOARDS.
- 02-Aug-2002 GCS Fix field mode so that odd (lower) field is stored
- in lower half of buffer.
- 05-Aug-2005 SS port to 2.6 kernel.
- 26-Oct-2009 SS port to 2.6.30 kernel.
-
--- Notes --
-
-** appended "mem=124" in lilo.conf to allow for 4megs free on my 128meg system.
- * using allocator.c and allocator.h from o'reilly book (alessandro rubini)
- ftp://ftp.systemy.it/pub/develop (see README.allocator)
-
- + might want to get rid of MAXboards for allocating initial buffer.
- confusing and not necessary
-
- + in cleanup_module the MOD_IN_USE looks like it is check after it should
-
- * GFP_DMA should not be set with a PCI system (pg 291)
-
- - NJC why are only two buffers allowed? (see isr, approx line 358)
-
-*/
-
-extern void printques(int);
-
-#include <linux/module.h>
-#include <linux/interrupt.h>
-#include <linux/pci.h>
-#include <linux/types.h>
-#include <linux/poll.h>
-#include <linux/sched.h>
-#include <linux/smp_lock.h>
-
-#include <asm/io.h>
-#include <asm/uaccess.h>
-
-#include "dt3155.h"
-#include "dt3155_drv.h"
-#include "dt3155_isr.h"
-#include "dt3155_io.h"
-#include "allocator.h"
-
-
-MODULE_LICENSE("GPL");
-
-/* Error variable. Zero means no error. */
-int dt3155_errno = 0;
-
-#ifndef PCI_DEVICE_ID_INTEL_7116
-#define PCI_DEVICE_ID_INTEL_7116 0x1223
-#endif
-
-#define DT3155_VENDORID PCI_VENDOR_ID_INTEL
-#define DT3155_DEVICEID PCI_DEVICE_ID_INTEL_7116
-#define MAXPCI 16
-
-#ifdef DT_DEBUG
-#define DT_3155_DEBUG_MSG(x,y) printk(x,y)
-#else
-#define DT_3155_DEBUG_MSG(x,y)
-#endif
-
-/* wait queue for interrupts */
-wait_queue_head_t dt3155_read_wait_queue[MAXBOARDS];
-
-#define DT_3155_SUCCESS 0
-#define DT_3155_FAILURE -EIO
-
-/* set to dynamicaly allocate, but it is tunable: */
-/* insmod DT_3155 dt3155 dt3155_major=XX */
-int dt3155_major = 0;
-
-/* The minor numbers are 0 and 1 ... they are not tunable.
- * They are used as the indices for the structure vectors,
- * and register address vectors
- */
-
-/* Global structures and variables */
-
-/* Status of each device */
-struct dt3155_status dt3155_status[MAXBOARDS];
-
-/* kernel logical address of the board */
-u8 *dt3155_lbase[MAXBOARDS] = { NULL
-#if MAXBOARDS == 2
- , NULL
-#endif
-};
-/* DT3155 registers */
-u8 *dt3155_bbase = NULL; /* kernel logical address of the *
- * buffer region */
-u32 dt3155_dev_open[MAXBOARDS] = {0
-#if MAXBOARDS == 2
- , 0
-#endif
-};
-
-u32 ndevices = 0;
-u32 unique_tag = 0;;
-
-
-/*
- * Stops interrupt generation right away and resets the status
- * to idle. I don't know why this works and the other way doesn't.
- * (James Rose)
- */
-static void quick_stop (int minor)
-{
- // TODO: scott was here
-#if 1
- ReadMReg((dt3155_lbase[minor] + INT_CSR), int_csr_r.reg);
- /* disable interrupts */
- int_csr_r.fld.FLD_END_EVE_EN = 0;
- int_csr_r.fld.FLD_END_ODD_EN = 0;
- WriteMReg((dt3155_lbase[minor] + INT_CSR), int_csr_r.reg);
-
- dt3155_status[minor].state &= ~(DT3155_STATE_STOP|0xff);
- /* mark the system stopped: */
- dt3155_status[minor].state |= DT3155_STATE_IDLE;
- dt3155_fbuffer[minor]->stop_acquire = 0;
- dt3155_fbuffer[minor]->even_stopped = 0;
-#else
- dt3155_status[minor].state |= DT3155_STATE_STOP;
- dt3155_status[minor].fbuffer.stop_acquire = 1;
-#endif
-
-}
-
-
-/*****************************************************
- * dt3155_isr() Interrupt service routien
- *
- * - looks like this isr supports IRQ sharing (or could) JML
- * - Assumes irq's are disabled, via SA_INTERRUPT flag
- * being set in request_irq() call from init_module()
- *****************************************************/
-static void dt3155_isr(int irq, void *dev_id, struct pt_regs *regs)
-{
- int minor = -1;
- int index;
- unsigned long flags;
- u32 buffer_addr;
-
- /* find out who issued the interrupt */
- for (index = 0; index < ndevices; index++) {
- if(dev_id == (void*) &dt3155_status[index])
- {
- minor = index;
- break;
- }
- }
-
- /* hopefully we should not get here */
- if (minor < 0 || minor >= MAXBOARDS) {
- printk(KERN_ERR "dt3155_isr called with invalid dev_id\n");
- return;
- }
-
- /* Check for corruption and set a flag if so */
- ReadMReg((dt3155_lbase[minor] + CSR1), csr1_r.reg);
-
- if ((csr1_r.fld.FLD_CRPT_EVE) || (csr1_r.fld.FLD_CRPT_ODD))
- {
- /* TODO: this should probably stop acquisition */
- /* and set some flags so that dt3155_read */
- /* returns an error next time it is called */
- dt3155_errno = DT_ERR_CORRUPT;
- printk("dt3155: corrupt field\n");
- return;
- }
-
- ReadMReg((dt3155_lbase[minor] + INT_CSR), int_csr_r.reg);
-
- /* Handle the even field ... */
- if (int_csr_r.fld.FLD_END_EVE)
- {
- if ((dt3155_status[minor].state & DT3155_STATE_MODE) ==
- DT3155_STATE_FLD)
- {
- dt3155_fbuffer[minor]->frame_count++;
- }
-
- ReadI2C(dt3155_lbase[minor], EVEN_CSR, &i2c_even_csr.reg);
-
- /* Clear the interrupt? */
- int_csr_r.fld.FLD_END_EVE = 1;
-
- /* disable the interrupt if last field */
- if (dt3155_fbuffer[minor]->stop_acquire)
- {
- printk("dt3155: even stopped.\n");
- dt3155_fbuffer[minor]->even_stopped = 1;
- if (i2c_even_csr.fld.SNGL_EVE)
- {
- int_csr_r.fld.FLD_END_EVE_EN = 0;
- }
- else
- {
- i2c_even_csr.fld.SNGL_EVE = 1;
- }
- }
-
- WriteMReg((dt3155_lbase[minor] + INT_CSR), int_csr_r.reg);
-
- /* Set up next DMA if we are doing FIELDS */
- if ((dt3155_status[minor].state & DT3155_STATE_MODE) ==
- DT3155_STATE_FLD)
- {
- /* GCS (Aug 2, 2002) -- In field mode, dma the odd field
- into the lower half of the buffer */
- const u32 stride = dt3155_status[minor].config.cols;
- buffer_addr = dt3155_fbuffer[minor]->
- frame_info[dt3155_fbuffer[minor]->active_buf].addr
- + (DT3155_MAX_ROWS / 2) * stride;
- local_save_flags(flags);
- local_irq_disable();
- wake_up_interruptible(&dt3155_read_wait_queue[minor]);
-
- /* Set up the DMA address for the next field */
- local_irq_restore(flags);
- WriteMReg((dt3155_lbase[minor] + ODD_DMA_START), buffer_addr);
- }
-
- /* Check for errors. */
- i2c_even_csr.fld.DONE_EVE = 1;
- if (i2c_even_csr.fld.ERROR_EVE)
- dt3155_errno = DT_ERR_OVERRUN;
-
- WriteI2C(dt3155_lbase[minor], EVEN_CSR, i2c_even_csr.reg);
-
- /* Note that we actually saw an even field meaning */
- /* that subsequent odd field complete the frame */
- dt3155_fbuffer[minor]->even_happened = 1;
-
- /* recording the time that the even field finished, this should be */
- /* about time in the middle of the frame */
- do_gettimeofday(&(dt3155_fbuffer[minor]->
- frame_info[dt3155_fbuffer[minor]->
- active_buf].time));
- return;
- }
-
- /* ... now handle the odd field */
- if (int_csr_r.fld.FLD_END_ODD)
- {
- ReadI2C(dt3155_lbase[minor], ODD_CSR, &i2c_odd_csr.reg);
-
- /* Clear the interrupt? */
- int_csr_r.fld.FLD_END_ODD = 1;
-
- if (dt3155_fbuffer[minor]->even_happened ||
- (dt3155_status[minor].state & DT3155_STATE_MODE) ==
- DT3155_STATE_FLD)
- {
- dt3155_fbuffer[minor]->frame_count++;
- }
-
- if (dt3155_fbuffer[minor]->stop_acquire &&
- dt3155_fbuffer[minor]->even_stopped)
- {
- printk(KERN_DEBUG "dt3155: stopping odd..\n");
- if (i2c_odd_csr.fld.SNGL_ODD)
- {
- /* disable interrupts */
- int_csr_r.fld.FLD_END_ODD_EN = 0;
- dt3155_status[minor].state &= ~(DT3155_STATE_STOP|0xff);
-
- /* mark the system stopped: */
- dt3155_status[minor].state |= DT3155_STATE_IDLE;
- dt3155_fbuffer[minor]->stop_acquire = 0;
- dt3155_fbuffer[minor]->even_stopped = 0;
-
- printk(KERN_DEBUG "dt3155: state is now %x\n",
- dt3155_status[minor].state);
- }
- else
- {
- i2c_odd_csr.fld.SNGL_ODD = 1;
- }
- }
-
- WriteMReg((dt3155_lbase[minor] + INT_CSR), int_csr_r.reg);
-
- /* if the odd field has been acquired, then */
- /* change the next dma location for both fields */
- /* and wake up the process if sleeping */
- if (dt3155_fbuffer[minor]->even_happened ||
- (dt3155_status[minor].state & DT3155_STATE_MODE) ==
- DT3155_STATE_FLD)
- {
-
- local_save_flags(flags);
- local_irq_disable();
-
-#ifdef DEBUG_QUES_B
- printques(minor);
-#endif
- if (dt3155_fbuffer[minor]->nbuffers > 2)
- {
- if (!are_empty_buffers(minor))
- {
- /* The number of active + locked buffers is
- * at most 2, and since there are none empty, there
- * must be at least nbuffers-2 ready buffers.
- * This is where we 'drop frames', oldest first. */
- push_empty(pop_ready(minor), minor);
- }
-
- /* The ready_que can't be full, since we know
- * there is one active buffer right now, so it's safe
- * to push the active buf on the ready_que. */
- push_ready(minor, dt3155_fbuffer[minor]->active_buf);
- /* There's at least 1 empty -- make it active */
- dt3155_fbuffer[minor]->active_buf = pop_empty(minor);
- dt3155_fbuffer[minor]->
- frame_info[dt3155_fbuffer[minor]->
- active_buf].tag = ++unique_tag;
- }
- else /* nbuffers == 2, special case */
- { /* There is 1 active buffer.
- * If there is a locked buffer, keep the active buffer
- * the same -- that means we drop a frame.
- */
- if (dt3155_fbuffer[minor]->locked_buf < 0)
- {
- push_ready(minor,
- dt3155_fbuffer[minor]->active_buf);
- if (are_empty_buffers(minor))
- {
- dt3155_fbuffer[minor]->active_buf =
- pop_empty(minor);
- }
- else
- { /* no empty or locked buffers, so use a readybuf */
- dt3155_fbuffer[minor]->active_buf =
- pop_ready(minor);
- }
- }
- }
-
-#ifdef DEBUG_QUES_B
- printques(minor);
-#endif
-
- dt3155_fbuffer[minor]->even_happened = 0;
-
- wake_up_interruptible(&dt3155_read_wait_queue[minor]);
-
- local_irq_restore(flags);
- }
-
-
- /* Set up the DMA address for the next frame/field */
- buffer_addr = dt3155_fbuffer[minor]->
- frame_info[dt3155_fbuffer[minor]->active_buf].addr;
- if ((dt3155_status[minor].state & DT3155_STATE_MODE) ==
- DT3155_STATE_FLD)
- {
- WriteMReg((dt3155_lbase[minor] + EVEN_DMA_START), buffer_addr);
- }
- else
- {
- WriteMReg((dt3155_lbase[minor] + EVEN_DMA_START), buffer_addr);
-
- WriteMReg((dt3155_lbase[minor] + ODD_DMA_START), buffer_addr
- + dt3155_status[minor].config.cols);
- }
-
- /* Do error checking */
- i2c_odd_csr.fld.DONE_ODD = 1;
- if (i2c_odd_csr.fld.ERROR_ODD)
- dt3155_errno = DT_ERR_OVERRUN;
-
- WriteI2C(dt3155_lbase[minor], ODD_CSR, i2c_odd_csr.reg);
-
- return;
- }
- /* If we get here, the Odd Field wasn't it either... */
- printk("neither even nor odd. shared perhaps?\n");
-}
-
-/*****************************************************
- * init_isr(int minor)
- * turns on interupt generation for the card
- * designated by "minor".
- * It is called *only* from inside ioctl().
- *****************************************************/
-static void dt3155_init_isr(int minor)
-{
- const u32 stride = dt3155_status[minor].config.cols;
-
- switch (dt3155_status[minor].state & DT3155_STATE_MODE)
- {
- case DT3155_STATE_FLD:
- {
- even_dma_start_r = dt3155_status[minor].
- fbuffer.frame_info[dt3155_status[minor].fbuffer.active_buf].addr;
- even_dma_stride_r = 0;
- odd_dma_stride_r = 0;
-
- WriteMReg((dt3155_lbase[minor] + EVEN_DMA_START),
- even_dma_start_r);
- WriteMReg((dt3155_lbase[minor] + EVEN_DMA_STRIDE),
- even_dma_stride_r);
- WriteMReg((dt3155_lbase[minor] + ODD_DMA_STRIDE),
- odd_dma_stride_r);
- break;
- }
-
- case DT3155_STATE_FRAME:
- default:
- {
- even_dma_start_r = dt3155_status[minor].
- fbuffer.frame_info[dt3155_status[minor].fbuffer.active_buf].addr;
- odd_dma_start_r = even_dma_start_r + stride;
- even_dma_stride_r = stride;
- odd_dma_stride_r = stride;
-
- WriteMReg((dt3155_lbase[minor] + EVEN_DMA_START),
- even_dma_start_r);
- WriteMReg((dt3155_lbase[minor] + ODD_DMA_START),
- odd_dma_start_r);
- WriteMReg((dt3155_lbase[minor] + EVEN_DMA_STRIDE),
- even_dma_stride_r);
- WriteMReg((dt3155_lbase[minor] + ODD_DMA_STRIDE),
- odd_dma_stride_r);
- break;
- }
- }
-
- /* 50/60 Hz should be set before this point but let's make sure it is */
- /* right anyway */
-
- ReadI2C(dt3155_lbase[minor], CSR2, &i2c_csr2.reg);
- i2c_csr2.fld.HZ50 = FORMAT50HZ;
- WriteI2C(dt3155_lbase[minor], CSR2, i2c_csr2.reg);
-
- /* enable busmaster chip, clear flags */
-
- /*
- * TODO:
- * shouldn't we be concered with continuous values of
- * DT3155_SNAP & DT3155_ACQ here? (SS)
- */
-
- csr1_r.reg = 0;
- csr1_r.fld.CAP_CONT_EVE = 1; /* use continuous capture bits to */
- csr1_r.fld.CAP_CONT_ODD = 1; /* enable */
- csr1_r.fld.FLD_DN_EVE = 1; /* writing a 1 clears flags */
- csr1_r.fld.FLD_DN_ODD = 1;
- csr1_r.fld.SRST = 1; /* reset - must be 1 */
- csr1_r.fld.FIFO_EN = 1; /* fifo control - must be 1 */
- csr1_r.fld.FLD_CRPT_EVE = 1; /* writing a 1 clears flags */
- csr1_r.fld.FLD_CRPT_ODD = 1;
-
- WriteMReg((dt3155_lbase[minor] + CSR1),csr1_r.reg);
-
- /* Enable interrupts at the end of each field */
-
- int_csr_r.reg = 0;
- int_csr_r.fld.FLD_END_EVE_EN = 1;
- int_csr_r.fld.FLD_END_ODD_EN = 1;
- int_csr_r.fld.FLD_START_EN = 0;
-
- WriteMReg((dt3155_lbase[minor] + INT_CSR), int_csr_r.reg);
-
- /* start internal BUSY bits */
-
- ReadI2C(dt3155_lbase[minor], CSR2, &i2c_csr2.reg);
- i2c_csr2.fld.BUSY_ODD = 1;
- i2c_csr2.fld.BUSY_EVE = 1;
- WriteI2C(dt3155_lbase[minor], CSR2, i2c_csr2.reg);
-
- /* Now its up to the interrupt routine!! */
-
- return;
-}
-
-
-/*****************************************************
- * ioctl()
- *
- *****************************************************/
-static int dt3155_ioctl(struct inode *inode,
- struct file *file,
- unsigned int cmd,
- unsigned long arg)
-{
- int minor = MINOR(inode->i_rdev); /* What device are we ioctl()'ing? */
-
- if (minor >= MAXBOARDS || minor < 0)
- return -ENODEV;
-
- /* make sure it is valid command */
- if (_IOC_NR(cmd) > DT3155_IOC_MAXNR)
- {
- printk("DT3155: invalid IOCTL(0x%x)\n",cmd);
- printk("DT3155: Valid commands (0x%x), (0x%x), (0x%x), (0x%x), (0x%x)\n",
- (unsigned int)DT3155_GET_CONFIG,
- (unsigned int)DT3155_SET_CONFIG,
- (unsigned int)DT3155_START,
- (unsigned int)DT3155_STOP,
- (unsigned int)DT3155_FLUSH);
- return -EINVAL;
- }
-
- switch (cmd)
- {
- case DT3155_SET_CONFIG:
- {
- if (dt3155_status[minor].state != DT3155_STATE_IDLE)
- return -EBUSY;
-
- {
- struct dt3155_config tmp;
- if (copy_from_user((void *)&tmp, (void *) arg, sizeof(tmp)))
- return -EFAULT;
- /* check for valid settings */
- if (tmp.rows > DT3155_MAX_ROWS ||
- tmp.cols > DT3155_MAX_COLS ||
- (tmp.acq_mode != DT3155_MODE_FRAME &&
- tmp.acq_mode != DT3155_MODE_FIELD) ||
- (tmp.continuous != DT3155_SNAP &&
- tmp.continuous != DT3155_ACQ))
- {
- return -EINVAL;
- }
- dt3155_status[minor].config = tmp;
- }
- return 0;
- }
- case DT3155_GET_CONFIG:
- {
- if (copy_to_user((void *) arg, (void *) &dt3155_status[minor],
- sizeof(struct dt3155_status)))
- return -EFAULT;
- return 0;
- }
- case DT3155_FLUSH: /* Flushes the buffers -- ensures fresh data */
- {
- if (dt3155_status[minor].state != DT3155_STATE_IDLE)
- return -EBUSY;
- return dt3155_flush(minor);
- }
- case DT3155_STOP:
- {
- if (dt3155_status[minor].state & DT3155_STATE_STOP ||
- dt3155_status[minor].fbuffer.stop_acquire)
- return -EBUSY;
-
- if (dt3155_status[minor].state == DT3155_STATE_IDLE)
- return 0;
-
- quick_stop(minor);
- if (copy_to_user((void *) arg, (void *) &dt3155_status[minor],
- sizeof(struct dt3155_status)))
- return -EFAULT;
- return 0;
- }
- case DT3155_START:
- {
- if (dt3155_status[minor].state != DT3155_STATE_IDLE)
- return -EBUSY;
-
- dt3155_status[minor].fbuffer.stop_acquire = 0;
- dt3155_status[minor].fbuffer.frame_count = 0;
-
- /* Set the MODE in the status -- we default to FRAME */
- if (dt3155_status[minor].config.acq_mode == DT3155_MODE_FIELD)
- {
- dt3155_status[minor].state = DT3155_STATE_FLD;
- }
- else
- {
- dt3155_status[minor].state = DT3155_STATE_FRAME;
- }
-
- dt3155_init_isr(minor);
- if (copy_to_user((void *) arg, (void *) &dt3155_status[minor],
- sizeof(struct dt3155_status)))
- return -EFAULT;
- return 0;
- }
- default:
- {
- printk("DT3155: invalid IOCTL(0x%x)\n",cmd);
- printk("DT3155: Valid commands (0x%x), (0x%x), (0x%x), (0x%x), (0x%x)\n",
- (unsigned int)DT3155_GET_CONFIG,
- (unsigned int)DT3155_SET_CONFIG,
- DT3155_START, DT3155_STOP, DT3155_FLUSH);
- return -ENOSYS;
- }
- }
- return -ENOSYS;
-}
-
-/*****************************************************
- * mmap()
- *
- * only allow the user to mmap the registers and buffer
- * It is quite possible that this is broken, since the
- * addition of of the capacity for two cards!!!!!!!!
- * It *looks* like it should work but since I'm not
- * sure how to use it, I'm not actually sure. (NJC? ditto by SS)
- *****************************************************/
-static int dt3155_mmap (struct file * file, struct vm_area_struct * vma)
-{
- /* which device are we mmapping? */
- int minor = MINOR(file->f_dentry->d_inode->i_rdev);
- unsigned long offset;
- offset = vma->vm_pgoff << PAGE_SHIFT;
-
- if (offset >= __pa(high_memory) || (file->f_flags & O_SYNC))
- vma->vm_flags |= VM_IO;
-
- /* Don't try to swap out physical pages.. */
- vma->vm_flags |= VM_RESERVED;
-
- /* they are mapping the registers or the buffer */
- if ((offset == dt3155_status[minor].reg_addr &&
- vma->vm_end - vma->vm_start == PCI_PAGE_SIZE) ||
- (offset == dt3155_status[minor].mem_addr &&
- vma->vm_end - vma->vm_start == dt3155_status[minor].mem_size))
- {
- if (remap_pfn_range(vma,
- vma->vm_start,
- offset >> PAGE_SHIFT,
- vma->vm_end - vma->vm_start,
- vma->vm_page_prot)) {
- printk("DT3155: remap_page_range() failed.\n");
- return -EAGAIN;
- }
- }
- else
- {
- printk("DT3155: dt3155_mmap() bad call.\n");
- return -ENXIO;
- }
-
- return 0;
-}
-
-
-/*****************************************************
- * open()
- *
- * Our special open code.
- * MOD_INC_USE_COUNT make sure that the driver memory is not freed
- * while the device is in use.
- *****************************************************/
-static int dt3155_open(struct inode* inode, struct file* filep)
-{
- int minor = MINOR(inode->i_rdev); /* what device are we opening? */
- if (dt3155_dev_open[minor]) {
- printk ("DT3155: Already opened by another process.\n");
- return -EBUSY;
- }
-
- if (dt3155_status[minor].device_installed==0)
- {
- printk("DT3155 Open Error: No such device dt3155 minor number %d\n",
- minor);
- return -EIO;
- }
-
- if (dt3155_status[minor].state != DT3155_STATE_IDLE) {
- printk ("DT3155: Not in idle state (state = %x)\n",
- dt3155_status[minor].state);
- return -EBUSY;
- }
-
- printk("DT3155: Device opened.\n");
-
- dt3155_dev_open[minor] = 1 ;
-
- dt3155_flush(minor);
-
- /* Disable ALL interrupts */
- int_csr_r.reg = 0;
- WriteMReg((dt3155_lbase[minor] + INT_CSR), int_csr_r.reg);
-
- init_waitqueue_head(&(dt3155_read_wait_queue[minor]));
-
- return 0;
-}
-
-
-/*****************************************************
- * close()
- *
- * Now decrement the use count.
- *
- *****************************************************/
-static int dt3155_close(struct inode *inode, struct file *filep)
-{
- int minor;
-
- minor = MINOR(inode->i_rdev); /* which device are we closing */
- if (!dt3155_dev_open[minor])
- {
- printk("DT3155: attempt to CLOSE a not OPEN device\n");
- }
- else
- {
- dt3155_dev_open[minor] = 0;
-
- if (dt3155_status[minor].state != DT3155_STATE_IDLE)
- {
- quick_stop(minor);
- }
- }
- return 0;
-}
-
-/*****************************************************
- * read()
- *
- *****************************************************/
-static ssize_t dt3155_read(struct file *filep, char __user *buf,
- size_t count, loff_t *ppos)
-{
- /* which device are we reading from? */
- int minor = MINOR(filep->f_dentry->d_inode->i_rdev);
- u32 offset;
- int frame_index;
- struct frame_info *frame_info;
-
- /* TODO: this should check the error flag and */
- /* return an error on hardware failures */
- if (count != sizeof(struct dt3155_read))
- {
- printk("DT3155 ERROR (NJC): count is not right\n");
- return -EINVAL;
- }
-
-
- /* Hack here -- I'm going to allow reading even when idle.
- * this is so that the frames can be read after STOP has
- * been called. Leaving it here, commented out, as a reminder
- * for a short while to make sure there are no problems.
- * Note that if the driver is not opened in non_blocking mode,
- * and the device is idle, then it could sit here forever! */
-
- /* if (dt3155_status[minor].state == DT3155_STATE_IDLE)*/
- /* return -EBUSY;*/
-
- /* non-blocking reads should return if no data */
- if (filep->f_flags & O_NDELAY)
- {
- if ((frame_index = dt3155_get_ready_buffer(minor)) < 0) {
- /*printk("dt3155: no buffers available (?)\n");*/
- /* printques(minor); */
- return -EAGAIN;
- }
- }
- else
- {
- /*
- * sleep till data arrives , or we get interrupted.
- * Note that wait_event_interruptible() does not actually
- * sleep/wait if it's condition evaluates to true upon entry.
- */
- wait_event_interruptible(dt3155_read_wait_queue[minor],
- (frame_index = dt3155_get_ready_buffer(minor))
- >= 0);
-
- if (frame_index < 0)
- {
- printk ("DT3155: read: interrupted\n");
- quick_stop (minor);
- printques(minor);
- return -EINTR;
- }
- }
-
- frame_info = &dt3155_status[minor].fbuffer.frame_info[frame_index];
-
- /* make this an offset */
- offset = frame_info->addr - dt3155_status[minor].mem_addr;
-
- put_user(offset, (unsigned int *) buf);
- buf += sizeof(u32);
- put_user(dt3155_status[minor].fbuffer.frame_count, (unsigned int *) buf);
- buf += sizeof(u32);
- put_user(dt3155_status[minor].state, (unsigned int *) buf);
- buf += sizeof(u32);
- if (copy_to_user(buf, frame_info, sizeof(*frame_info)))
- return -EFAULT;
-
- return sizeof(struct dt3155_read);
-}
-
-static unsigned int dt3155_poll (struct file * filp, poll_table *wait)
-{
- int minor = MINOR(filp->f_dentry->d_inode->i_rdev);
-
- if (!is_ready_buf_empty(minor))
- return POLLIN | POLLRDNORM;
-
- poll_wait (filp, &dt3155_read_wait_queue[minor], wait);
-
- return 0;
-}
-
-static long
-dt3155_unlocked_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
-{
- int ret;
-
- lock_kernel();
- ret = dt3155_ioctl(file->f_path.dentry->d_inode, file, cmd, arg);
- unlock_kernel();
-
- return ret;
-}
-
-/*****************************************************
- * file operations supported by DT3155 driver
- * needed by init_module
- * register_chrdev
- *****************************************************/
-static struct file_operations dt3155_fops = {
- .read = dt3155_read,
- .unlocked_ioctl = dt3155_unlocked_ioctl,
- .mmap = dt3155_mmap,
- .poll = dt3155_poll,
- .open = dt3155_open,
- .release = dt3155_close
-};
-
-
-/*****************************************************
- * find_PCI();
- *
- * PCI has been totally reworked in 2.1..
- *****************************************************/
-static int find_PCI (void)
-{
- struct pci_dev *pci_dev = NULL;
- int error, pci_index = 0;
- unsigned short rev_device;
- unsigned long base;
- unsigned char irq;
-
- while ((pci_dev = pci_get_device
- (DT3155_VENDORID, DT3155_DEVICEID, pci_dev)) != NULL)
- {
- pci_index ++;
-
- /* Is it really there? */
- if ((error =
- pci_read_config_word(pci_dev, PCI_CLASS_DEVICE, &rev_device)))
- continue;
-
- /* Found a board */
- DT_3155_DEBUG_MSG("DT3155: Device number %d \n", pci_index);
-
- /* Make sure the driver was compiled with enough buffers to handle
- this many boards */
- if (pci_index > MAXBOARDS) {
- printk("DT3155: ERROR - found %d devices, but driver only configured "
- "for %d devices\n"
- "DT3155: Please change MAXBOARDS in dt3155.h\n",
- pci_index, MAXBOARDS);
- goto err;
- }
-
- /* Now, just go out and make sure that this/these device(s) is/are
- actually mapped into the kernel address space */
- if ((error = pci_read_config_dword(pci_dev, PCI_BASE_ADDRESS_0,
- (u32 *) &base)))
- {
- printk("DT3155: Was not able to find device \n");
- goto err;
- }
-
- DT_3155_DEBUG_MSG("DT3155: Base address 0 for device is %lx \n", base);
- dt3155_status[pci_index-1].reg_addr = base;
-
- /* Remap the base address to a logical address through which we
- * can access it. */
- dt3155_lbase[pci_index - 1] = ioremap(base,PCI_PAGE_SIZE);
- dt3155_status[pci_index - 1].reg_addr = base;
- DT_3155_DEBUG_MSG("DT3155: New logical address is %p \n",
- dt3155_lbase[pci_index-1]);
- if (!dt3155_lbase[pci_index-1])
- {
- printk("DT3155: Unable to remap control registers\n");
- goto err;
- }
-
- if ((error = pci_read_config_byte(pci_dev, PCI_INTERRUPT_LINE, &irq)))
- {
- printk("DT3155: Was not able to find device \n");
- goto err;
- }
-
- DT_3155_DEBUG_MSG("DT3155: IRQ is %d \n",irq);
- dt3155_status[pci_index-1].irq = irq;
- /* Set flag: kth device found! */
- dt3155_status[pci_index-1].device_installed = 1;
- printk("DT3155: Installing device %d w/irq %d and address %p\n",
- pci_index,
- dt3155_status[pci_index-1].irq,
- dt3155_lbase[pci_index-1]);
-
- }
- ndevices = pci_index;
-
- return DT_3155_SUCCESS;
-
-err:
- pci_dev_put(pci_dev);
- return DT_3155_FAILURE;
-}
-
-u32 allocatorAddr = 0;
-
-/*****************************************************
- * init_module()
- *****************************************************/
-int init_module(void)
-{
- int index;
- int rcode = 0;
- char *devname[MAXBOARDS];
-
- devname[0] = "dt3155a";
-#if MAXBOARDS == 2
- devname[1] = "dt3155b";
-#endif
-
- printk("DT3155: Loading module...\n");
-
- /* Register the device driver */
- rcode = register_chrdev(dt3155_major, "dt3155", &dt3155_fops);
- if(rcode < 0)
- {
- printk(KERN_INFO "DT3155: register_chrdev failed \n");
- return rcode;
- }
-
- if(dt3155_major == 0)
- dt3155_major = rcode; /* dynamic */
-
-
- /* init the status variables. */
- /* DMA memory is taken care of in setup_buffers() */
- for (index = 0; index < MAXBOARDS; index++)
- {
- dt3155_status[index].config.acq_mode = DT3155_MODE_FRAME;
- dt3155_status[index].config.continuous = DT3155_ACQ;
- dt3155_status[index].config.cols = DT3155_MAX_COLS;
- dt3155_status[index].config.rows = DT3155_MAX_ROWS;
- dt3155_status[index].state = DT3155_STATE_IDLE;
-
- /* find_PCI() will check if devices are installed; */
- /* first assume they're not: */
- dt3155_status[index].mem_addr = 0;
- dt3155_status[index].mem_size = 0;
- dt3155_status[index].state = DT3155_STATE_IDLE;
- dt3155_status[index].device_installed = 0;
- }
-
- /* Now let's find the hardware. find_PCI() will set ndevices to the
- * number of cards found in this machine. */
- {
- if ((rcode = find_PCI()) != DT_3155_SUCCESS)
- {
- printk("DT3155 error: find_PCI() failed to find dt3155 board(s)\n");
- unregister_chrdev(dt3155_major, "dt3155");
- return rcode;
- }
- }
-
- /* Ok, time to setup the frame buffers */
- if((rcode = dt3155_setup_buffers(&allocatorAddr)) < 0)
- {
- printk("DT3155: Error: setting up buffer not large enough.");
- unregister_chrdev(dt3155_major, "dt3155");
- return rcode;
- }
-
- /* If we are this far, then there is enough RAM */
- /* for the buffers: Print the configuration. */
- for( index = 0; index < ndevices; index++)
- {
- printk("DT3155: Device = %d; acq_mode = %d; "
- "continuous = %d; cols = %d; rows = %d;\n",
- index ,
- dt3155_status[index].config.acq_mode,
- dt3155_status[index].config.continuous,
- dt3155_status[index].config.cols,
- dt3155_status[index].config.rows);
- printk("DT3155: m_addr = 0x%x; m_size = %ld; "
- "state = %d; device_installed = %d\n",
- dt3155_status[index].mem_addr,
- (long int)dt3155_status[index].mem_size,
- dt3155_status[index].state,
- dt3155_status[index].device_installed);
- }
-
- /* Disable ALL interrupts */
- int_csr_r.reg = 0;
- for( index = 0; index < ndevices; index++)
- {
- WriteMReg((dt3155_lbase[index] + INT_CSR), int_csr_r.reg);
- if(dt3155_status[index].device_installed)
- {
- /*
- * This driver *looks* like it can handle sharing interrupts,
- * but I can't actually test myself. I've had reports that it
- * DOES work so I'll enable it for now. This comment will remain
- * as a reminder in case any problems arise. (SS)
- */
- /* in older kernels flags are: SA_SHIRQ | SA_INTERRUPT */
- rcode = request_irq(dt3155_status[index].irq, (void *)dt3155_isr,
- IRQF_SHARED | IRQF_DISABLED, devname[index],
- (void*) &dt3155_status[index]);
- if(rcode < 0)
- {
- printk("DT3155: minor %d request_irq failed for IRQ %d\n",
- index, dt3155_status[index].irq);
- unregister_chrdev(dt3155_major, "dt3155");
- return rcode;
- }
- }
- }
-
- printk("DT3155: finished loading\n");
-
- return 0;
-}
-
-/*****************************************************
- * cleanup_module(void)
- *
- *****************************************************/
-void cleanup_module(void)
-{
- int index;
-
- printk("DT3155: cleanup_module called\n");
-
- /* removed DMA allocated with the allocator */
-#ifdef STANDALONE_ALLOCATOR
- if (allocatorAddr != 0)
- allocator_free_dma(allocatorAddr);
-#else
- allocator_cleanup();
-#endif
-
- unregister_chrdev(dt3155_major, "dt3155");
-
- for(index = 0; index < ndevices; index++)
- {
- if(dt3155_status[index].device_installed == 1)
- {
- printk("DT3155: Freeing irq %d for device %d\n",
- dt3155_status[index].irq, index);
- free_irq(dt3155_status[index].irq, (void*)&dt3155_status[index]);
- }
- }
-}
-
diff --git a/drivers/staging/dt3155/dt3155_drv.h b/drivers/staging/dt3155/dt3155_drv.h
deleted file mode 100644
index 95e68c3388a..00000000000
--- a/drivers/staging/dt3155/dt3155_drv.h
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
-
-Copyright 1996,2002 Gregory D. Hager, Alfred A. Rizzi, Noah J. Cowan,
- Scott Smedley
-
-This file is part of the DT3155 Device Driver.
-
-The DT3155 Device Driver is free software; you can redistribute it
-and/or modify 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 DT3155 Device Driver 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 the DT3155 Device Driver; if not, write to the Free
-Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
-MA 02111-1307 USA
-*/
-
-#ifndef DT3155_DRV_INC
-#define DT3155_DRV_INC
-
-/* kernel logical address of the frame grabbers */
-extern u8 *dt3155_lbase[MAXBOARDS];
-
-/* kernel logical address of ram buffer */
-extern u8 *dt3155_bbase;
-
-#ifdef __KERNEL__
-#include <linux/wait.h>
-
-/* wait queue for reads */
-extern wait_queue_head_t dt3155_read_wait_queue[MAXBOARDS];
-#endif
-
-/* number of devices */
-extern u32 ndevices;
-
-extern int dt3155_errno;
-
-#endif
diff --git a/drivers/staging/dt3155/dt3155_io.c b/drivers/staging/dt3155/dt3155_io.c
deleted file mode 100644
index 7792e712d16..00000000000
--- a/drivers/staging/dt3155/dt3155_io.c
+++ /dev/null
@@ -1,165 +0,0 @@
-/*
- * Copyright 1996,2002,2005 Gregory D. Hager, Alfred A. Rizzi, Noah J. Cowan,
- * Jason Lapenta, Scott Smedley
- *
- * This file is part of the DT3155 Device Driver.
- *
- * The DT3155 Device Driver is free software; you can redistribute it and/or
- * modify 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 DT3155 Device Driver 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 file provides some basic register io routines. It is modified from
- * demo code provided by Data Translations.
- */
-
-#include <linux/delay.h>
-#include "dt3155.h"
-#include "dt3155_io.h"
-#include "dt3155_drv.h"
-
-
-/****** local copies of board's 32 bit registers ******/
-u32 even_dma_start_r; /* bit 0 should always be 0 */
-u32 odd_dma_start_r; /* .. */
-u32 even_dma_stride_r; /* bits 0&1 should always be 0 */
-u32 odd_dma_stride_r; /* .. */
-u32 even_pixel_fmt_r;
-u32 odd_pixel_fmt_r;
-
-FIFO_TRIGGER_R fifo_trigger_r;
-XFER_MODE_R xfer_mode_r;
-CSR1_R csr1_r;
-RETRY_WAIT_CNT_R retry_wait_cnt_r;
-INT_CSR_R int_csr_r;
-
-u32 even_fld_mask_r;
-u32 odd_fld_mask_r;
-
-MASK_LENGTH_R mask_length_r;
-FIFO_FLAG_CNT_R fifo_flag_cnt_r;
-IIC_CLK_DUR_R iic_clk_dur_r;
-IIC_CSR1_R iic_csr1_r;
-IIC_CSR2_R iic_csr2_r;
-DMA_UPPER_LMT_R even_dma_upper_lmt_r;
-DMA_UPPER_LMT_R odd_dma_upper_lmt_r;
-
-
-
-/******** local copies of board's 8 bit I2C registers ******/
-I2C_CSR2 i2c_csr2;
-I2C_EVEN_CSR i2c_even_csr;
-I2C_ODD_CSR i2c_odd_csr;
-I2C_CONFIG i2c_config;
-u8 i2c_dt_id;
-u8 i2c_x_clip_start;
-u8 i2c_y_clip_start;
-u8 i2c_x_clip_end;
-u8 i2c_y_clip_end;
-u8 i2c_ad_addr;
-u8 i2c_ad_lut;
-I2C_AD_CMD i2c_ad_cmd;
-u8 i2c_dig_out;
-u8 i2c_pm_lut_addr;
-u8 i2c_pm_lut_data;
-
-/*
- * wait_ibsyclr()
- *
- * This function handles read/write timing and r/w timeout error
- */
-static int wait_ibsyclr(u8 *lpReg)
-{
- /* wait 100 microseconds */
- udelay(100L);
- /* __delay(loops_per_sec/10000); */
-
- ReadMReg(lpReg + IIC_CSR2, iic_csr2_r.reg);
- if (iic_csr2_r.fld.NEW_CYCLE) {
- /* if NEW_CYCLE didn't clear */
- /* TIMEOUT ERROR */
- dt3155_errno = DT_ERR_I2C_TIMEOUT;
- return -ETIMEDOUT;
- }
-
- return 0; /* no error */
-}
-
-/*
- * WriteI2C()
- *
- * This function handles writing to 8-bit DT3155 registers
- *
- * 1st parameter is pointer to 32-bit register base address
- * 2nd parameter is reg. index;
- * 3rd is value to be written
- */
-int WriteI2C(u8 *lpReg, u_short wIregIndex, u8 byVal)
-{
- /* read 32 bit IIC_CSR2 register data into union */
-
- ReadMReg((lpReg + IIC_CSR2), iic_csr2_r.reg);
-
- /* for write operation */
- iic_csr2_r.fld.DIR_RD = 0;
- /* I2C address of I2C register: */
- iic_csr2_r.fld.DIR_ADDR = wIregIndex;
- /* 8 bit data to be written to I2C reg */
- iic_csr2_r.fld.DIR_WR_DATA = byVal;
- /* will start a direct I2C cycle: */
- iic_csr2_r.fld.NEW_CYCLE = 1;
-
- /* xfer union data into 32 bit IIC_CSR2 register */
- WriteMReg((lpReg + IIC_CSR2), iic_csr2_r.reg);
-
- /* wait for IIC cycle to finish */
- return wait_ibsyclr(lpReg);
-}
-
-/*
- * ReadI2C()
- *
- * This function handles reading from 8-bit DT3155 registers
- *
- * 1st parameter is pointer to 32-bit register base address
- * 2nd parameter is reg. index;
- * 3rd is adrs of value to be read
- */
-int ReadI2C(u8 *lpReg, u_short wIregIndex, u8 *byVal)
-{
- int writestat; /* status for return */
-
- /* read 32 bit IIC_CSR2 register data into union */
- ReadMReg((lpReg + IIC_CSR2), iic_csr2_r.reg);
-
- /* for read operation */
- iic_csr2_r.fld.DIR_RD = 1;
-
- /* I2C address of I2C register: */
- iic_csr2_r.fld.DIR_ADDR = wIregIndex;
-
- /* will start a direct I2C cycle: */
- iic_csr2_r.fld.NEW_CYCLE = 1;
-
- /* xfer union's data into 32 bit IIC_CSR2 register */
- WriteMReg((lpReg + IIC_CSR2), iic_csr2_r.reg);
-
- /* wait for IIC cycle to finish */
- writestat = wait_ibsyclr(lpReg);
-
- /* Next 2 commands read 32 bit IIC_CSR1 register's data into union */
- /* first read data is in IIC_CSR1 */
- ReadMReg((lpReg + IIC_CSR1), iic_csr1_r.reg);
-
- /* now get data u8 out of register */
- *byVal = (u8) iic_csr1_r.fld.RD_DATA;
-
- return writestat;
-}
diff --git a/drivers/staging/dt3155/dt3155_io.h b/drivers/staging/dt3155/dt3155_io.h
deleted file mode 100644
index d1a25100169..00000000000
--- a/drivers/staging/dt3155/dt3155_io.h
+++ /dev/null
@@ -1,358 +0,0 @@
-/*
-
-Copyright 1996,2002 Gregory D. Hager, Alfred A. Rizzi, Noah J. Cowan,
- Jason Lapenta, Scott Smedley
-
-This file is part of the DT3155 Device Driver.
-
-The DT3155 Device Driver is free software; you can redistribute it
-and/or modify 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 DT3155 Device Driver 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 the DT3155 Device Driver; if not, write to the Free
-Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
-MA 02111-1307 USA
-
-
--- Changes --
-
- Date Programmer Description of changes made
- -------------------------------------------------------------------
- 24-Jul-2002 SS GPL licence.
-
-*/
-
-/* This code is a modified version of examples provided by Data Translations.*/
-
-#ifndef DT3155_IO_INC
-#define DT3155_IO_INC
-
-/* macros to access registers */
-
-#define WriteMReg(Address, Data) (*((u32 *)(Address)) = Data)
-#define ReadMReg(Address, Data) (Data = *((u32 *)(Address)))
-
-/***************** 32 bit register globals **************/
-
-/* offsets for 32-bit memory mapped registers */
-
-#define EVEN_DMA_START 0x000
-#define ODD_DMA_START 0x00C
-#define EVEN_DMA_STRIDE 0x018
-#define ODD_DMA_STRIDE 0x024
-#define EVEN_PIXEL_FMT 0x030
-#define ODD_PIXEL_FMT 0x034
-#define FIFO_TRIGGER 0x038
-#define XFER_MODE 0x03C
-#define CSR1 0x040
-#define RETRY_WAIT_CNT 0x044
-#define INT_CSR 0x048
-#define EVEN_FLD_MASK 0x04C
-#define ODD_FLD_MASK 0x050
-#define MASK_LENGTH 0x054
-#define FIFO_FLAG_CNT 0x058
-#define IIC_CLK_DUR 0x05C
-#define IIC_CSR1 0x060
-#define IIC_CSR2 0x064
-#define EVEN_DMA_UPPR_LMT 0x08C
-#define ODD_DMA_UPPR_LMT 0x090
-
-#define CLK_DUR_VAL 0x01010101
-
-
-
-/******** Assignments and Typedefs for 32 bit Memory Mapped Registers ********/
-
-typedef union fifo_trigger_tag {
- u32 reg;
- struct {
- u32 PACKED:6;
- u32 :9;
- u32 PLANER:7;
- u32 :9;
- } fld;
-} FIFO_TRIGGER_R;
-
-typedef union xfer_mode_tag {
- u32 reg;
- struct {
- u32 :2;
- u32 FIELD_TOGGLE:1;
- u32 :5;
- u32 :2;
- u32 :22;
- } fld;
-} XFER_MODE_R;
-
-typedef union csr1_tag {
- u32 reg;
- struct {
- u32 CAP_CONT_EVE:1;
- u32 CAP_CONT_ODD:1;
- u32 CAP_SNGL_EVE:1;
- u32 CAP_SNGL_ODD:1;
- u32 FLD_DN_EVE :1;
- u32 FLD_DN_ODD :1;
- u32 SRST :1;
- u32 FIFO_EN :1;
- u32 FLD_CRPT_EVE:1;
- u32 FLD_CRPT_ODD:1;
- u32 ADDR_ERR_EVE:1;
- u32 ADDR_ERR_ODD:1;
- u32 CRPT_DIS :1;
- u32 RANGE_EN :1;
- u32 :16;
- } fld;
-} CSR1_R;
-
-typedef union retry_wait_cnt_tag {
- u32 reg;
- struct {
- u32 RTRY_WAIT_CNT:8;
- u32 :24;
- } fld;
-} RETRY_WAIT_CNT_R;
-
-typedef union int_csr_tag {
- u32 reg;
- struct {
- u32 FLD_END_EVE :1;
- u32 FLD_END_ODD :1;
- u32 FLD_START :1;
- u32 :5;
- u32 FLD_END_EVE_EN:1;
- u32 FLD_END_ODD_EN:1;
- u32 FLD_START_EN :1;
- u32 :21;
- } fld;
-} INT_CSR_R;
-
-typedef union mask_length_tag {
- u32 reg;
- struct {
- u32 MASK_LEN_EVE:5;
- u32 :11;
- u32 MASK_LEN_ODD:5;
- u32 :11;
- } fld;
-} MASK_LENGTH_R;
-
-typedef union fifo_flag_cnt_tag {
- u32 reg;
- struct {
- u32 AF_COUNT:7;
- u32 :9;
- u32 AE_COUNT:7;
- u32 :9;
- } fld;
-} FIFO_FLAG_CNT_R;
-
-typedef union iic_clk_dur {
- u32 reg;
- struct {
- u32 PHASE_1:8;
- u32 PHASE_2:8;
- u32 PHASE_3:8;
- u32 PHASE_4:8;
- } fld;
-} IIC_CLK_DUR_R;
-
-typedef union iic_csr1_tag {
- u32 reg;
- struct {
- u32 AUTO_EN :1;
- u32 BYPASS :1;
- u32 SDA_OUT :1;
- u32 SCL_OUT :1;
- u32 :4;
- u32 AUTO_ABORT :1;
- u32 DIRECT_ABORT:1;
- u32 SDA_IN :1;
- u32 SCL_IN :1;
- u32 :4;
- u32 AUTO_ADDR :8;
- u32 RD_DATA :8;
- } fld;
-} IIC_CSR1_R;
-
-/**********************************
- * iic_csr2_tag
- */
-typedef union iic_csr2_tag {
- u32 reg;
- struct {
- u32 DIR_WR_DATA :8;
- u32 DIR_SUB_ADDR:8;
- u32 DIR_RD :1;
- u32 DIR_ADDR :7;
- u32 NEW_CYCLE :1;
- u32 :7;
- } fld;
-} IIC_CSR2_R;
-
-/* use for both EVEN and ODD DMA UPPER LIMITS */
-
-/*
- * dma_upper_lmt_tag
- */
-typedef union dma_upper_lmt_tag {
- u32 reg;
- struct {
- u32 DMA_UPPER_LMT_VAL:24;
- u32 :8;
- } fld;
-} DMA_UPPER_LMT_R;
-
-
-/*
- * Global declarations of local copies of boards' 32 bit registers
- */
-extern u32 even_dma_start_r; /* bit 0 should always be 0 */
-extern u32 odd_dma_start_r; /* .. */
-extern u32 even_dma_stride_r; /* bits 0&1 should always be 0 */
-extern u32 odd_dma_stride_r; /* .. */
-extern u32 even_pixel_fmt_r;
-extern u32 odd_pixel_fmt_r;
-
-extern FIFO_TRIGGER_R fifo_trigger_r;
-extern XFER_MODE_R xfer_mode_r;
-extern CSR1_R csr1_r;
-extern RETRY_WAIT_CNT_R retry_wait_cnt_r;
-extern INT_CSR_R int_csr_r;
-
-extern u32 even_fld_mask_r;
-extern u32 odd_fld_mask_r;
-
-extern MASK_LENGTH_R mask_length_r;
-extern FIFO_FLAG_CNT_R fifo_flag_cnt_r;
-extern IIC_CLK_DUR_R iic_clk_dur_r;
-extern IIC_CSR1_R iic_csr1_r;
-extern IIC_CSR2_R iic_csr2_r;
-extern DMA_UPPER_LMT_R even_dma_upper_lmt_r;
-extern DMA_UPPER_LMT_R odd_dma_upper_lmt_r;
-
-
-
-/***************** 8 bit I2C register globals ***********/
-#define CSR2 0x010 /* indices of 8-bit I2C mapped reg's*/
-#define EVEN_CSR 0x011
-#define ODD_CSR 0x012
-#define CONFIG 0x013
-#define DT_ID 0x01F
-#define X_CLIP_START 0x020
-#define Y_CLIP_START 0x022
-#define X_CLIP_END 0x024
-#define Y_CLIP_END 0x026
-#define AD_ADDR 0x030
-#define AD_LUT 0x031
-#define AD_CMD 0x032
-#define DIG_OUT 0x040
-#define PM_LUT_ADDR 0x050
-#define PM_LUT_DATA 0x051
-
-
-/******** Assignments and Typedefs for 8 bit I2C Registers********************/
-
-typedef union i2c_csr2_tag {
- u8 reg;
- struct {
- u8 CHROM_FIL:1;
- u8 SYNC_SNTL:1;
- u8 HZ50:1;
- u8 SYNC_PRESENT:1;
- u8 BUSY_EVE:1;
- u8 BUSY_ODD:1;
- u8 DISP_PASS:1;
- } fld;
-} I2C_CSR2;
-
-typedef union i2c_even_csr_tag {
- u8 reg;
- struct {
- u8 DONE_EVE :1;
- u8 SNGL_EVE :1;
- u8 ERROR_EVE:1;
- u8 :5;
- } fld;
-} I2C_EVEN_CSR;
-
-typedef union i2c_odd_csr_tag {
- u8 reg;
- struct {
- u8 DONE_ODD:1;
- u8 SNGL_ODD:1;
- u8 ERROR_ODD:1;
- u8 :5;
- } fld;
-} I2C_ODD_CSR;
-
-typedef union i2c_config_tag {
- u8 reg;
- struct {
- u8 ACQ_MODE:2;
- u8 EXT_TRIG_EN:1;
- u8 EXT_TRIG_POL:1;
- u8 H_SCALE:1;
- u8 CLIP:1;
- u8 PM_LUT_SEL:1;
- u8 PM_LUT_PGM:1;
- } fld;
-} I2C_CONFIG;
-
-
-typedef union i2c_ad_cmd_tag {
- /* bits can have 3 different meanings depending on value of AD_ADDR */
- u8 reg;
- /* Bt252 Command Register if AD_ADDR = 00h */
- struct {
- u8 :2;
- u8 SYNC_LVL_SEL:2;
- u8 SYNC_CNL_SEL:2;
- u8 DIGITIZE_CNL_SEL1:2;
- } bt252_command;
-
- /* Bt252 IOUT0 register if AD_ADDR = 01h */
- struct {
- u8 IOUT_DATA:8;
- } bt252_iout0;
-
- /* BT252 IOUT1 register if AD_ADDR = 02h */
- struct {
- u8 IOUT_DATA:8;
- } bt252_iout1;
-} I2C_AD_CMD;
-
-
-/***** Global declarations of local copies of boards' 8 bit I2C registers ***/
-
-extern I2C_CSR2 i2c_csr2;
-extern I2C_EVEN_CSR i2c_even_csr;
-extern I2C_ODD_CSR i2c_odd_csr;
-extern I2C_CONFIG i2c_config;
-extern u8 i2c_dt_id;
-extern u8 i2c_x_clip_start;
-extern u8 i2c_y_clip_start;
-extern u8 i2c_x_clip_end;
-extern u8 i2c_y_clip_end;
-extern u8 i2c_ad_addr;
-extern u8 i2c_ad_lut;
-extern I2C_AD_CMD i2c_ad_cmd;
-extern u8 i2c_dig_out;
-extern u8 i2c_pm_lut_addr;
-extern u8 i2c_pm_lut_data;
-
-/* Functions for Global use */
-
-/* access 8-bit IIC registers */
-
-extern int ReadI2C(u8 *lpReg, u_short wIregIndex, u8 *byVal);
-extern int WriteI2C(u8 *lpReg, u_short wIregIndex, u8 byVal);
-
-#endif
diff --git a/drivers/staging/dt3155/dt3155_isr.c b/drivers/staging/dt3155/dt3155_isr.c
deleted file mode 100644
index 33ddc9c057f..00000000000
--- a/drivers/staging/dt3155/dt3155_isr.c
+++ /dev/null
@@ -1,509 +0,0 @@
-/*
-
-Copyright 1996,2002,2005 Gregory D. Hager, Alfred A. Rizzi, Noah J. Cowan,
- Jason Lapenta, Scott Smedley, Greg Sharp
-
-This file is part of the DT3155 Device Driver.
-
-The DT3155 Device Driver is free software; you can redistribute it
-and/or modify 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 DT3155 Device Driver 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 the DT3155 Device Driver; if not, write to the Free
-Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
-MA 02111-1307 USA
-
- File: dt3155_isr.c
-Purpose: Buffer management routines, and other routines for the ISR
- (the actual isr is in dt3155_drv.c)
-
--- Changes --
-
- Date Programmer Description of changes made
- -------------------------------------------------------------------
- 03-Jul-2000 JML n/a
- 02-Apr-2002 SS Mods to make work with separate allocator
- module; Merged John Roll's mods to make work with
- multiple boards.
- 10-Jul-2002 GCS Complete rewrite of setup_buffers to disallow
- buffers which span a 4MB boundary.
- 24-Jul-2002 SS GPL licence.
- 30-Jul-2002 NJC Added support for buffer loop.
- 31-Jul-2002 NJC Complete rewrite of buffer management
- 02-Aug-2002 NJC Including slab.h instead of malloc.h (no warning).
- Also, allocator_init() now returns allocator_max
- so cleaned up allocate_buffers() accordingly.
- 08-Aug-2005 SS port to 2.6 kernel.
-
-*/
-
-#include <asm/system.h>
-#include <linux/gfp.h>
-#include <linux/sched.h>
-#include <linux/types.h>
-
-#include "dt3155.h"
-#include "dt3155_drv.h"
-#include "dt3155_io.h"
-#include "dt3155_isr.h"
-#include "allocator.h"
-
-#define FOUR_MB (0x0400000) /* Can't DMA accross a 4MB boundary!*/
-#define UPPER_10_BITS (0x3FF<<22) /* Can't DMA accross a 4MB boundary!*/
-
-
-/* Pointer into global structure for handling buffers */
-struct dt3155_fbuffer *dt3155_fbuffer[MAXBOARDS] = {NULL
-#if MAXBOARDS == 2
- , NULL
-#endif
-};
-
-/******************************************************************************
- * Simple array based que struct
- *
- * Some handy functions using the buffering structure.
- *****************************************************************************/
-
-
-/***************************
- * are_empty_buffers
- * m is minor # of device
- ***************************/
-bool are_empty_buffers(int m)
-{
- return dt3155_fbuffer[m]->empty_len;
-}
-
-/**************************
- * push_empty
- * m is minor # of device
- *
- * This is slightly confusing. The number empty_len is the literal #
- * of empty buffers. After calling, empty_len-1 is the index into the
- * empty buffer stack. So, if empty_len == 1, there is one empty buffer,
- * given by dt3155_fbuffer[m]->empty_buffers[0].
- * empty_buffers should never fill up, though this is not checked.
- **************************/
-void push_empty(int index, int m)
-{
- dt3155_fbuffer[m]->empty_buffers[dt3155_fbuffer[m]->empty_len] = index;
- dt3155_fbuffer[m]->empty_len++;
-}
-
-/**************************
- * pop_empty(m)
- * m is minor # of device
- **************************/
-int pop_empty(int m)
-{
- dt3155_fbuffer[m]->empty_len--;
- return dt3155_fbuffer[m]->empty_buffers[dt3155_fbuffer[m]->empty_len];
-}
-
-/*************************
- * is_ready_buf_empty(m)
- * m is minor # of device
- *************************/
-bool is_ready_buf_empty(int m)
-{
- return ((dt3155_fbuffer[m]->ready_len) == 0);
-}
-
-/*************************
- * is_ready_buf_full(m)
- * m is minor # of device
- * this should *never* be true if there are any active, locked or empty
- * buffers, since it corresponds to nbuffers ready buffers!!
- * 7/31/02: total rewrite. --NJC
- *************************/
-bool is_ready_buf_full(int m)
-{
- return dt3155_fbuffer[m]->ready_len == dt3155_fbuffer[m]->nbuffers;
-}
-
-/*****************************************************
- * push_ready(m, buffer)
- * m is minor # of device
- *
- *****************************************************/
-void push_ready(int m, int index)
-{
- int head = dt3155_fbuffer[m]->ready_head;
-
- dt3155_fbuffer[m]->ready_que[head] = index;
- dt3155_fbuffer[m]->ready_head = ((head + 1) %
- (dt3155_fbuffer[m]->nbuffers));
- dt3155_fbuffer[m]->ready_len++;
-
-}
-
-/*****************************************************
- * get_tail()
- * m is minor # of device
- *
- * Simply comptutes the tail given the head and the length.
- *****************************************************/
-static int get_tail(int m)
-{
- return (dt3155_fbuffer[m]->ready_head -
- dt3155_fbuffer[m]->ready_len +
- dt3155_fbuffer[m]->nbuffers)%
- (dt3155_fbuffer[m]->nbuffers);
-}
-
-
-
-/*****************************************************
- * pop_ready()
- * m is minor # of device
- *
- * This assumes that there is a ready buffer ready... should
- * be checked (e.g. with is_ready_buf_empty() prior to call.
- *****************************************************/
-int pop_ready(int m)
-{
- int tail;
- tail = get_tail(m);
- dt3155_fbuffer[m]->ready_len--;
- return dt3155_fbuffer[m]->ready_que[tail];
-}
-
-
-/*****************************************************
- * printques
- * m is minor # of device
- *****************************************************/
-void printques(int m)
-{
- int head = dt3155_fbuffer[m]->ready_head;
- int tail;
- int num = dt3155_fbuffer[m]->nbuffers;
- int frame_index;
- int index;
-
- tail = get_tail(m);
-
- printk("\n R:");
- for (index = tail; index != head; index++, index = index % (num)) {
- frame_index = dt3155_fbuffer[m]->ready_que[index];
- printk(" %d ", frame_index);
- }
-
- printk("\n E:");
- for (index = 0; index < dt3155_fbuffer[m]->empty_len; index++) {
- frame_index = dt3155_fbuffer[m]->empty_buffers[index];
- printk(" %d ", frame_index);
- }
-
- frame_index = dt3155_fbuffer[m]->active_buf;
- printk("\n A: %d", frame_index);
-
- frame_index = dt3155_fbuffer[m]->locked_buf;
- printk("\n L: %d\n", frame_index);
-
-}
-
-/*****************************************************
- * adjust_4MB
- *
- * If a buffer intersects the 4MB boundary, push
- * the start address up to the beginning of the
- * next 4MB chunk (assuming bufsize < 4MB).
- *****************************************************/
-u32 adjust_4MB(u32 buf_addr, u32 bufsize)
-{
- if (((buf_addr+bufsize) & UPPER_10_BITS) != (buf_addr & UPPER_10_BITS))
- return (buf_addr+bufsize) & UPPER_10_BITS;
- else
- return buf_addr;
-}
-
-
-/*****************************************************
- * allocate_buffers
- *
- * Try to allocate enough memory for all requested
- * buffers. If there is not enough free space
- * try for less memory.
- *****************************************************/
-void allocate_buffers(u32 *buf_addr, u32* total_size_kbs,
- u32 bufsize)
-{
- /* Compute the minimum amount of memory guaranteed to hold all
- MAXBUFFERS such that no buffer crosses the 4MB boundary.
- Store this value in the variable "full_size" */
-
- u32 allocator_max;
- u32 bufs_per_chunk = (FOUR_MB / bufsize);
- u32 filled_chunks = (MAXBUFFERS-1) / bufs_per_chunk;
- u32 leftover_bufs = MAXBUFFERS - filled_chunks * bufs_per_chunk;
-
- u32 full_size = bufsize /* possibly unusable part of 1st chunk */
- + filled_chunks * FOUR_MB /* max # of completely filled 4mb chunks */
- + leftover_bufs * bufsize; /* these buffs will be in a partly filled
- chunk at beginning or end */
-
- u32 full_size_kbs = 1 + (full_size-1) / 1024;
- u32 min_size_kbs = 2*ndevices*bufsize / 1024;
- u32 size_kbs;
-
- /* Now, try to allocate full_size. If this fails, keep trying for
- less & less memory until it succeeds. */
-#ifndef STANDALONE_ALLOCATOR
- /* initialize the allocator */
- allocator_init(&allocator_max);
-#endif
- size_kbs = full_size_kbs;
- *buf_addr = 0;
- printk("DT3155: We would like to get: %d KB\n", full_size_kbs);
- printk("DT3155: ...but need at least: %d KB\n", min_size_kbs);
- printk("DT3155: ...the allocator has: %d KB\n", allocator_max);
- size_kbs = (full_size_kbs <= allocator_max ? full_size_kbs : allocator_max);
- if (size_kbs > min_size_kbs) {
- if ((*buf_addr = allocator_allocate_dma(size_kbs, GFP_KERNEL)) != 0) {
- printk("DT3155: Managed to allocate: %d KB\n", size_kbs);
- *total_size_kbs = size_kbs;
- return;
- }
- }
- /* If we got here, the allocation failed */
- printk("DT3155: Allocator failed!\n");
- *buf_addr = 0;
- *total_size_kbs = 0;
- return;
-
-}
-
-
-/*****************************************************
- * dt3155_setup_buffers
- *
- * setup_buffers just puts the buffering system into
- * a consistent state before the start of interrupts
- *
- * JML : it looks like all the buffers need to be
- * continuous. So I'm going to try and allocate one
- * continuous buffer.
- *
- * GCS : Fix DMA problems when buffer spans
- * 4MB boundary. Also, add error checking. This
- * function will return -ENOMEM when not enough memory.
- *****************************************************/
-u32 dt3155_setup_buffers(u32 *allocatorAddr)
-
-{
- u32 index;
- u32 rambuff_addr; /* start of allocation */
- u32 rambuff_size; /* total size allocated to driver */
- u32 rambuff_acm; /* accumlator, keep track of how much
- is left after being split up*/
- u32 rambuff_end; /* end of rambuff */
- u32 numbufs; /* number of useful buffers allocated (per device) */
- u32 bufsize = DT3155_MAX_ROWS * DT3155_MAX_COLS;
- int m; /* minor # of device, looped for all devs */
-
- /* zero the fbuffer status and address structure */
- for (m = 0; m < ndevices; m++) {
- dt3155_fbuffer[m] = &(dt3155_status[m].fbuffer);
-
- /* Make sure the buffering variables are consistent */
- {
- u8 *ptr = (u8 *) dt3155_fbuffer[m];
- for (index = 0; index < sizeof(struct dt3155_fbuffer); index++)
- *(ptr++) = 0;
- }
- }
-
- /* allocate a large contiguous chunk of RAM */
- allocate_buffers(&rambuff_addr, &rambuff_size, bufsize);
- printk("DT3155: mem info\n");
- printk(" - rambuf_addr = 0x%x\n", rambuff_addr);
- printk(" - length (kb) = %u\n", rambuff_size);
- if (rambuff_addr == 0) {
- printk(KERN_INFO
- "DT3155: Error setup_buffers() allocator dma failed\n");
- return -ENOMEM;
- }
- *allocatorAddr = rambuff_addr;
- rambuff_end = rambuff_addr + 1024 * rambuff_size;
-
- /* after allocation, we need to count how many useful buffers there
- are so we can give an equal number to each device */
- rambuff_acm = rambuff_addr;
- for (index = 0; index < MAXBUFFERS; index++) {
- rambuff_acm = adjust_4MB(rambuff_acm, bufsize);/*avoid spanning 4MB bdry*/
- if (rambuff_acm + bufsize > rambuff_end)
- break;
- rambuff_acm += bufsize;
- }
- /* Following line is OK, will waste buffers if index
- * not evenly divisible by ndevices -NJC*/
- numbufs = index / ndevices;
- printk(" - numbufs = %u\n", numbufs);
- if (numbufs < 2) {
- printk(KERN_INFO
- "DT3155: Error setup_buffers() couldn't allocate 2 bufs/board\n");
- return -ENOMEM;
- }
-
- /* now that we have board memory we spit it up */
- /* between the boards and the buffers */
- rambuff_acm = rambuff_addr;
- for (m = 0; m < ndevices; m++) {
- rambuff_acm = adjust_4MB(rambuff_acm, bufsize);
-
- /* Save the start of this boards buffer space (for mmap). */
- dt3155_status[m].mem_addr = rambuff_acm;
-
- for (index = 0; index < numbufs; index++) {
- rambuff_acm = adjust_4MB(rambuff_acm, bufsize);
- if (rambuff_acm + bufsize > rambuff_end) {
- /* Should never happen */
- printk("DT3155 PROGRAM ERROR (GCS)\n"
- "Error distributing allocated buffers\n");
- return -ENOMEM;
- }
-
- dt3155_fbuffer[m]->frame_info[index].addr = rambuff_acm;
- push_empty(index, m);
- /* printk(" - Buffer : %lx\n",
- * dt3155_fbuffer[m]->frame_info[index].addr);
- */
- dt3155_fbuffer[m]->nbuffers += 1;
- rambuff_acm += bufsize;
- }
-
- /* Make sure there is an active buffer there. */
- dt3155_fbuffer[m]->active_buf = pop_empty(m);
- dt3155_fbuffer[m]->even_happened = 0;
- dt3155_fbuffer[m]->even_stopped = 0;
-
- /* make sure there is no locked_buf JML 2/28/00 */
- dt3155_fbuffer[m]->locked_buf = -1;
-
- dt3155_status[m].mem_size =
- rambuff_acm - dt3155_status[m].mem_addr;
-
- /* setup the ready queue */
- dt3155_fbuffer[m]->ready_head = 0;
- dt3155_fbuffer[m]->ready_len = 0;
- printk("Available buffers for device %d: %d\n",
- m, dt3155_fbuffer[m]->nbuffers);
- }
-
- return 1;
-}
-
-/*****************************************************
- * internal_release_locked_buffer
- *
- * The internal function for releasing a locked buffer.
- * It assumes interrupts are turned off.
- *
- * m is minor number of device
- *****************************************************/
-static void internal_release_locked_buffer(int m)
-{
- /* Pointer into global structure for handling buffers */
- if (dt3155_fbuffer[m]->locked_buf >= 0) {
- push_empty(dt3155_fbuffer[m]->locked_buf, m);
- dt3155_fbuffer[m]->locked_buf = -1;
- }
-}
-
-
-/*****************************************************
- * dt3155_release_locked_buffer()
- * m is minor # of device
- *
- * The user function of the above.
- *
- *****************************************************/
-void dt3155_release_locked_buffer(int m)
-{
- unsigned long int flags;
- local_save_flags(flags);
- local_irq_disable();
- internal_release_locked_buffer(m);
- local_irq_restore(flags);
-}
-
-
-/*****************************************************
- * dt3155_flush()
- * m is minor # of device
- *
- *****************************************************/
-int dt3155_flush(int m)
-{
- int index;
- unsigned long int flags;
- local_save_flags(flags);
- local_irq_disable();
-
- internal_release_locked_buffer(m);
- dt3155_fbuffer[m]->empty_len = 0;
-
- for (index = 0; index < dt3155_fbuffer[m]->nbuffers; index++)
- push_empty(index, m);
-
- /* Make sure there is an active buffer there. */
- dt3155_fbuffer[m]->active_buf = pop_empty(m);
-
- dt3155_fbuffer[m]->even_happened = 0;
- dt3155_fbuffer[m]->even_stopped = 0;
-
- /* setup the ready queue */
- dt3155_fbuffer[m]->ready_head = 0;
- dt3155_fbuffer[m]->ready_len = 0;
-
- local_irq_restore(flags);
-
- return 0;
-}
-
-/*****************************************************
- * dt3155_get_ready_buffer()
- * m is minor # of device
- *
- * get_ready_buffer will grab the next chunk of data
- * if it is already there, otherwise it returns 0.
- * If the user has a buffer locked it will unlock
- * that buffer before returning the new one.
- *****************************************************/
-int dt3155_get_ready_buffer(int m)
-{
- int frame_index;
- unsigned long int flags;
- local_save_flags(flags);
- local_irq_disable();
-
-#ifdef DEBUG_QUES_A
- printques(m);
-#endif
-
- internal_release_locked_buffer(m);
-
- if (is_ready_buf_empty(m))
- frame_index = -1;
- else {
- frame_index = pop_ready(m);
- dt3155_fbuffer[m]->locked_buf = frame_index;
- }
-
-#ifdef DEBUG_QUES_B
- printques(m);
-#endif
-
- local_irq_restore(flags);
-
- return frame_index;
-}
diff --git a/drivers/staging/dt3155/dt3155_isr.h b/drivers/staging/dt3155/dt3155_isr.h
deleted file mode 100644
index 7d474cf743d..00000000000
--- a/drivers/staging/dt3155/dt3155_isr.h
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
-
-Copyright 1996,2002 Gregory D. Hager, Alfred A. Rizzi, Noah J. Cowan,
- Jason Lapenta, Scott Smedley
-
-This file is part of the DT3155 Device Driver.
-
-The DT3155 Device Driver is free software; you can redistribute it
-and/or modify 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 DT3155 Device Driver 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 the DT3155 Device Driver; if not, write to the Free
-Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
-MA 02111-1307 USA
-
-
--- Changes --
-
- Date Programmer Description of changes made
- -------------------------------------------------------------------
- 03-Jul-2000 JML n/a
- 24-Jul-2002 SS GPL licence.
- 26-Oct-2009 SS Porting to 2.6.30 kernel.
-
--- notes --
-
-*/
-
-#ifndef DT3155_ISR_H
-#define DT3155_ISR_H
-
-extern struct dt3155_fbuffer *dt3155_fbuffer[MAXBOARDS];
-
-/* User functions for buffering */
-/* Initialize the buffering system. This should */
-/* be called prior to enabling interrupts */
-
-u32 dt3155_setup_buffers(u32 *allocatorAddr);
-
-/* Get the next frame of data if it is ready. Returns */
-/* zero if no data is ready. If there is data but */
-/* the user has a locked buffer, it will unlock that */
-/* buffer and return it to the free list. */
-
-int dt3155_get_ready_buffer(int minor);
-
-/* Return a locked buffer to the free list */
-
-void dt3155_release_locked_buffer(int minor);
-
-/* Flush the buffer system */
-int dt3155_flush(int minor);
-
-/**********************************
- * Simple array based que struct
- **********************************/
-
-bool are_empty_buffers(int minor);
-void push_empty(int index, int minor);
-
-int pop_empty(int minor);
-
-bool is_ready_buf_empty(int minor);
-bool is_ready_buf_full(int minor);
-
-void push_ready(int minor, int index);
-int pop_ready(int minor);
-
-
-#endif
diff --git a/drivers/staging/dt3155v4l/dt3155v4l.c b/drivers/staging/dt3155v4l/dt3155v4l.c
index 6dc3af62284..fd48b38e797 100644
--- a/drivers/staging/dt3155v4l/dt3155v4l.c
+++ b/drivers/staging/dt3155v4l/dt3155v4l.c
@@ -1008,6 +1008,8 @@ struct dma_coherent_mem {
static int __devinit
dt3155_alloc_coherent(struct device *dev, size_t size, int flags)
{
+ struct dma_coherent_mem *mem;
+ dma_addr_t dev_base;
int pages = size >> PAGE_SHIFT;
int bitmap_size = BITS_TO_LONGS(pages) * sizeof(long);
@@ -1018,25 +1020,28 @@ dt3155_alloc_coherent(struct device *dev, size_t size, int flags)
if (dev->dma_mem)
goto out;
- dev->dma_mem = kzalloc(sizeof(struct dma_coherent_mem), GFP_KERNEL);
- if (!dev->dma_mem)
+ mem = kzalloc(sizeof(*mem), GFP_KERNEL);
+ if (!mem)
goto out;
- dev->dma_mem->bitmap = kzalloc(bitmap_size, GFP_KERNEL);
- if (!dev->dma_mem->bitmap)
+ mem->virt_base = dma_alloc_coherent(dev, size, &dev_base,
+ DT3155_COH_FLAGS);
+ if (!mem->virt_base)
+ goto err_alloc_coherent;
+ mem->bitmap = kzalloc(bitmap_size, GFP_KERNEL);
+ if (!mem->bitmap)
goto err_bitmap;
- dev->dma_mem->virt_base = dma_alloc_coherent(dev, size,
- &dev->dma_mem->device_base, DT3155_COH_FLAGS);
- if (!dev->dma_mem->virt_base)
- goto err_coherent;
- dev->dma_mem->size = pages;
- dev->dma_mem->flags = flags;
+ /* coherent_dma_mask is already set to 32 bits */
+ mem->device_base = dev_base;
+ mem->size = pages;
+ mem->flags = flags;
+ dev->dma_mem = mem;
return DMA_MEMORY_MAP;
-err_coherent:
- kfree(dev->dma_mem->bitmap);
err_bitmap:
- kfree(dev->dma_mem);
+ dma_free_coherent(dev, size, mem->virt_base, dev_base);
+err_alloc_coherent:
+ kfree(mem);
out:
return 0;
}
diff --git a/drivers/staging/easycap/Kconfig b/drivers/staging/easycap/Kconfig
new file mode 100644
index 00000000000..bd96f39f273
--- /dev/null
+++ b/drivers/staging/easycap/Kconfig
@@ -0,0 +1,17 @@
+config EASYCAP
+ tristate "EasyCAP USB ID 05e1:0408 support"
+ depends on USB && VIDEO_DEV
+
+ ---help---
+ This is an integrated audio/video driver for EasyCAP cards with
+ USB ID 05e1:0408. It supports two hardware variants:
+
+ * EasyCAP USB 2.0 Video Adapter with Audio, Model DC60,
+ having input cables labelled CVBS, S-VIDEO, AUDIO(L), AUDIO(R)
+
+ * EasyCAP002 4-Channel USB 2.0 DVR, having input cables labelled
+ 1, 2, 3, 4 and an unlabelled input cable for a microphone.
+
+ To compile this driver as a module, choose M here: the
+ module will be called easycap
+
diff --git a/drivers/staging/easycap/Makefile b/drivers/staging/easycap/Makefile
new file mode 100644
index 00000000000..d93bd6b70a4
--- /dev/null
+++ b/drivers/staging/easycap/Makefile
@@ -0,0 +1,13 @@
+
+obj-$(CONFIG_EASYCAP) += easycap.o
+
+easycap-objs := easycap_main.o easycap_low.o easycap_sound.o
+easycap-objs += easycap_ioctl.o easycap_settings.o
+easycap-objs += easycap_testcard.o
+
+EXTRA_CFLAGS += -Wall
+# Impose all or none of the following:
+EXTRA_CFLAGS += -DEASYCAP_IS_VIDEODEV_CLIENT
+EXTRA_CFLAGS += -DEASYCAP_NEEDS_V4L2_DEVICE_H
+EXTRA_CFLAGS += -DEASYCAP_NEEDS_V4L2_FOPS
+
diff --git a/drivers/staging/easycap/README b/drivers/staging/easycap/README
new file mode 100644
index 00000000000..3775481f05e
--- /dev/null
+++ b/drivers/staging/easycap/README
@@ -0,0 +1,130 @@
+
+ ***********************************************************
+ * EasyCAP USB 2.0 Video Adapter with Audio, Model DC60 *
+ * and *
+ * EasyCAP002 4-Channel USB 2.0 DVR *
+ ***********************************************************
+ Mike Thomas <rmthomas@sciolus.org>
+
+
+
+SUPPORTED HARDWARE
+------------------
+
+This driver is intended for use with hardware having USB ID 05e1:0408.
+Two kinds of EasyCAP have this USB ID, namely:
+
+ * EasyCAP USB 2.0 Video Adapter with Audio, Model DC60,
+ having input cables labelled CVBS, S-VIDEO, AUDIO(L), AUDIO(R)
+
+ * EasyCAP002 4-Channel USB 2.0 DVR, having input cables labelled
+ 1, 2, 3, 4 and an unlabelled input cable for a microphone.
+
+
+BUILD OPTIONS AND DEPENDENCIES
+------------------------------
+
+If the parameter EASYCAP_IS_VIDEODEV_CLIENT is undefined during compilation
+the built module is entirely independent of the videodev module, and when
+the EasyCAP is physically plugged into a USB port the special files
+/dev/easycap0 and /dev/easysnd1 are created as video and sound sources
+respectively.
+
+If the parameter EASYCAP_IS_VIDEODEV_CLIENT is defined during compilation
+the built easycap module is configured to register with the videodev module,
+in which case the special files created when the EasyCAP is plugged in are
+/dev/video0 and /dev/easysnd0. Use of the easycap module as a client of
+the videodev module has received very little testing as of June 2010.
+
+
+KNOWN BUILD PROBLEMS
+--------------------
+
+(1) Recent gcc versions may generate the message:
+
+ warning: the frame size of .... bytes is larger than 1024 bytes
+
+This warning can be suppressed by specifying in the Makefile:
+
+ EXTRA_CFLAGS += -Wframe-larger-than=8192
+
+but it would be preferable to remove the cause of the warning.
+
+
+KNOWN RUNTIME ISSUES
+--------------------
+
+(1) Randomly (maybe 5 to 10% of occasions) the driver fails to produce any
+output at start-up. Closing mplayer (or whatever the user program is) and
+restarting it restores normal performance without any other remedial action
+being necessary. The reason for this is not known.
+
+(2) Intentionally, this driver will not stream material which is unambiguously
+identified by the hardware as copy-protected. The video output will freeze
+within about a minute when this situation arises.
+
+(3) The controls for luminance, contrast, saturation, hue and volume may not
+always work properly.
+
+(4) Reduced-resolution S-Video seems to suffer from moire artefacts. No
+attempt has yet been made to rememdy this.
+
+
+SUPPORTED TV STANDARDS AND RESOLUTIONS
+--------------------------------------
+
+The following TV standards are natively supported by the hardware and are
+usable as (for example) the "norm=" parameter in the mplayer command:
+
+ PAL_BGHIN, NTSC_N_443,
+ PAL_Nc, NTSC_N,
+ SECAM, NTSC_M, NTSC_M_JP,
+ PAL_60, NTSC_443,
+ PAL_M.
+
+The available picture sizes are:
+
+ at 25 frames per second: 720x576, 704x576, 640x480, 360x288, 320x240;
+ at 30 frames per second: 720x480, 640x480, 360x240, 320x240;
+
+
+WHAT'S TESTED AND WHAT'S NOT
+----------------------------
+
+This driver is known to work with mplayer, mencoder, tvtime and sufficiently
+recent versions of vlc. An interface to ffmpeg is implemented, but serious
+audio-video synchronization problems remain.
+
+The driver is designed to support all the TV standards accepted by the
+hardware, but as yet it has actually been tested on only a few of these.
+
+I have been unable to test and calibrate the S-video input myself because I
+do not possess any equipment with S-video output.
+
+This driver does not understand the V4L1 IOCTL commands, so programs such
+as camorama are not compatible. There are reports that the driver does
+work with sufficiently recent (V4L2) versions of zoneminder, but I have not
+attempted to confirm this myself.
+
+
+UDEV RULES
+----------
+
+In order that the special files /dev/easycap0 and /dev/easysnd1 are created
+with conveniently relaxed permissions when the EasyCAP is plugged in, a file
+is preferably to be provided in directory /etc/udev/rules.d with content:
+
+ACTION!="add|change", GOTO="easycap_rules_end"
+ATTRS{idVendor}=="05e1", ATTRS{idProduct}=="0408", \
+ MODE="0666", OWNER="root", GROUP="root"
+LABEL="easycap_rules_end"
+
+
+ACKNOWLEGEMENTS AND REFERENCES
+------------------------------
+This driver makes use of information contained in the Syntek Semicon DC-1125
+Driver, presently maintained at http://sourceforge.net/projects/syntekdriver/
+by Nicolas Vivien. Particularly useful has been a patch to the latter driver
+provided by Ivor Hewitt in January 2009. The NTSC implementation is taken
+from the work of Ben Trask.
+
diff --git a/drivers/staging/easycap/easycap.h b/drivers/staging/easycap/easycap.h
new file mode 100644
index 00000000000..ad836d2d26f
--- /dev/null
+++ b/drivers/staging/easycap/easycap.h
@@ -0,0 +1,642 @@
+/*****************************************************************************
+* *
+* easycap.h *
+* *
+*****************************************************************************/
+/*
+ *
+ * Copyright (C) 2010 R.M. Thomas <rmthomas@sciolus.org>
+ *
+ *
+ * This is free software; you can redistribute it and/or modify
+ * 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 software 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 software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+*/
+/*****************************************************************************/
+/*---------------------------------------------------------------------------*/
+/*
+ * THE FOLLOWING PARAMETERS ARE UNDEFINED:
+ *
+ * EASYCAP_DEBUG
+ * EASYCAP_IS_VIDEODEV_CLIENT
+ * EASYCAP_NEEDS_USBVIDEO_H
+ * EASYCAP_NEEDS_V4L2_DEVICE_H
+ * EASYCAP_NEEDS_V4L2_FOPS
+ *
+ * IF REQUIRED THEY MUST BE EXTERNALLY DEFINED, FOR EXAMPLE AS COMPILER
+ * OPTIONS.
+ */
+/*---------------------------------------------------------------------------*/
+
+#if (!defined(EASYCAP_H))
+#define EASYCAP_H
+
+#if defined(EASYCAP_DEBUG)
+#if (9 < EASYCAP_DEBUG)
+#error Debug levels 0 to 9 are okay.\
+ To achieve higher levels, remove this trap manually from easycap.h
+#endif
+#endif /*EASYCAP_DEBUG*/
+/*---------------------------------------------------------------------------*/
+/*
+ * THESE ARE FOR MAINTENANCE ONLY - NORMALLY UNDEFINED:
+ */
+/*---------------------------------------------------------------------------*/
+#undef PREFER_NTSC
+#undef EASYCAP_TESTCARD
+#undef EASYCAP_TESTTONE
+#undef LOCKFRAME
+#undef NOREADBACK
+#undef AUDIOTIME
+/*---------------------------------------------------------------------------*/
+/*
+ *
+ * DEFINE BRIDGER TO ACTIVATE THE ROUTINE FOR BRIDGING VIDEOTAPE DROPOUTS.
+ *
+ * *** UNDER DEVELOPMENT/TESTING - NOT READY YET!***
+ *
+ */
+/*---------------------------------------------------------------------------*/
+#undef BRIDGER
+/*---------------------------------------------------------------------------*/
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/kref.h>
+#include <linux/smp_lock.h>
+#include <linux/usb.h>
+#include <linux/uaccess.h>
+
+#include <linux/i2c.h>
+#include <linux/version.h>
+#include <linux/workqueue.h>
+#include <linux/poll.h>
+#include <linux/mm.h>
+#include <linux/fs.h>
+#include <linux/delay.h>
+#include <linux/types.h>
+
+/*vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/
+#if defined(EASYCAP_IS_VIDEODEV_CLIENT)
+#if (!defined(__OLD_VIDIOC_))
+#define __OLD_VIDIOC_
+#endif /* !defined(__OLD_VIDIOC_) */
+
+#include <media/v4l2-dev.h>
+
+#if defined(EASYCAP_NEEDS_V4L2_DEVICE_H)
+#include <media/v4l2-device.h>
+#endif /*EASYCAP_NEEDS_V4L2_DEVICE_H*/
+#endif /*EASYCAP_IS_VIDEODEV_CLIENT*/
+/*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
+
+#if (!defined(__OLD_VIDIOC_))
+#define __OLD_VIDIOC_
+#endif /* !defined(__OLD_VIDIOC_) */
+#include <linux/videodev2.h>
+
+#include <linux/soundcard.h>
+
+#if defined(EASYCAP_NEEDS_USBVIDEO_H)
+#include <config/video/usbvideo.h>
+#endif /*EASYCAP_NEEDS_USBVIDEO_H*/
+
+#if (!defined(PAGE_SIZE))
+#error "PAGE_SIZE not defined"
+#endif
+
+#define STRINGIZE_AGAIN(x) #x
+#define STRINGIZE(x) STRINGIZE_AGAIN(x)
+
+/*---------------------------------------------------------------------------*/
+/* VENDOR, PRODUCT: Syntek Semiconductor Co., Ltd
+ *
+ * EITHER EasyCAP USB 2.0 Video Adapter with Audio, Model No. DC60
+ * with input cabling: AUDIO(L), AUDIO(R), CVBS, S-VIDEO.
+ *
+ * OR EasyCAP 4CHANNEL USB 2.0 DVR, Model No. EasyCAP002
+ * with input cabling: MICROPHONE, CVBS1, CVBS2, CVBS3, CVBS4.
+ */
+/*---------------------------------------------------------------------------*/
+#define USB_EASYCAP_VENDOR_ID 0x05e1
+#define USB_EASYCAP_PRODUCT_ID 0x0408
+
+#define EASYCAP_DRIVER_VERSION "0.8.21"
+#define EASYCAP_DRIVER_DESCRIPTION "easycapdc60"
+
+#define USB_SKEL_MINOR_BASE 192
+#define VIDEO_DEVICE_MANY 8
+
+/*---------------------------------------------------------------------------*/
+/*
+ * DEFAULT LUMINANCE, CONTRAST, SATURATION AND HUE
+ */
+/*---------------------------------------------------------------------------*/
+#define SAA_0A_DEFAULT 0x7F
+#define SAA_0B_DEFAULT 0x3F
+#define SAA_0C_DEFAULT 0x2F
+#define SAA_0D_DEFAULT 0x00
+/*---------------------------------------------------------------------------*/
+/*
+ * VIDEO STREAMING PARAMETERS:
+ * USB 2.0 PROVIDES FOR HIGH-BANDWIDTH ENDPOINTS WITH AN UPPER LIMIT
+ * OF 3072 BYTES PER MICROFRAME for wMaxPacketSize.
+ */
+/*---------------------------------------------------------------------------*/
+#define VIDEO_ISOC_BUFFER_MANY 16
+#define VIDEO_ISOC_ORDER 3
+#define VIDEO_ISOC_FRAMESPERDESC ((unsigned int) 1 << VIDEO_ISOC_ORDER)
+#define USB_2_0_MAXPACKETSIZE 3072
+#if (USB_2_0_MAXPACKETSIZE > PAGE_SIZE)
+#error video_isoc_buffer[.] will not be big enough
+#endif
+/*---------------------------------------------------------------------------*/
+/*
+ * VIDEO BUFFERS
+ */
+/*---------------------------------------------------------------------------*/
+#define FIELD_BUFFER_SIZE (203 * PAGE_SIZE)
+#define FRAME_BUFFER_SIZE (405 * PAGE_SIZE)
+#define FIELD_BUFFER_MANY 4
+#define FRAME_BUFFER_MANY 6
+/*---------------------------------------------------------------------------*/
+/*
+ * AUDIO STREAMING PARAMETERS
+ */
+/*---------------------------------------------------------------------------*/
+#define AUDIO_ISOC_BUFFER_MANY 16
+#define AUDIO_ISOC_ORDER 3
+#define AUDIO_ISOC_BUFFER_SIZE (PAGE_SIZE << AUDIO_ISOC_ORDER)
+/*---------------------------------------------------------------------------*/
+/*
+ * AUDIO BUFFERS
+ */
+/*---------------------------------------------------------------------------*/
+#define AUDIO_FRAGMENT_MANY 32
+/*---------------------------------------------------------------------------*/
+/*
+ * IT IS ESSENTIAL THAT EVEN-NUMBERED STANDARDS ARE 25 FRAMES PER SECOND,
+ * ODD-NUMBERED STANDARDS ARE 30 FRAMES PER SECOND.
+ * THE NUMBERING OF STANDARDS MUST NOT BE CHANGED WITHOUT DUE CARE. NOT
+ * ONLY MUST THE PARAMETER
+ * STANDARD_MANY
+ * BE CHANGED TO CORRESPOND TO THE NEW NUMBER OF STANDARDS, BUT ALSO THE
+ * NUMBERING MUST REMAIN AN UNBROKEN ASCENDING SEQUENCE: DUMMY STANDARDS
+ * MAY NEED TO BE ADDED. APPROPRIATE CHANGES WILL ALWAYS BE REQUIRED IN
+ * ROUTINE fillin_formats() AND POSSIBLY ELSEWHERE. BEWARE.
+ */
+/*---------------------------------------------------------------------------*/
+#define PAL_BGHIN 0
+#define PAL_Nc 2
+#define SECAM 4
+#define NTSC_N 6
+#define NTSC_N_443 8
+#define NTSC_M 1
+#define NTSC_443 3
+#define NTSC_M_JP 5
+#define PAL_60 7
+#define PAL_M 9
+#define STANDARD_MANY 10
+/*---------------------------------------------------------------------------*/
+/*
+ * ENUMS
+ */
+/*---------------------------------------------------------------------------*/
+enum {
+AT_720x576,
+AT_704x576,
+AT_640x480,
+AT_720x480,
+AT_360x288,
+AT_320x240,
+AT_360x240,
+RESOLUTION_MANY
+};
+enum {
+FMT_UYVY,
+FMT_YUY2,
+FMT_RGB24,
+FMT_RGB32,
+FMT_BGR24,
+FMT_BGR32,
+PIXELFORMAT_MANY
+};
+enum {
+FIELD_NONE,
+FIELD_INTERLACED,
+FIELD_ALTERNATE,
+INTERLACE_MANY
+};
+#define SETTINGS_MANY (STANDARD_MANY * \
+ RESOLUTION_MANY * \
+ 2 * \
+ PIXELFORMAT_MANY * \
+ INTERLACE_MANY)
+/*---------------------------------------------------------------------------*/
+/*
+ * STRUCTURE DEFINITIONS
+ */
+/*---------------------------------------------------------------------------*/
+struct data_buffer {
+struct list_head list_head;
+void *pgo;
+void *pto;
+__u16 kount;
+};
+/*---------------------------------------------------------------------------*/
+struct data_urb {
+struct list_head list_head;
+struct urb *purb;
+int isbuf;
+int length;
+};
+/*---------------------------------------------------------------------------*/
+struct easycap_standard {
+__u16 mask;
+struct v4l2_standard v4l2_standard;
+};
+struct easycap_format {
+__u16 mask;
+char name[128];
+struct v4l2_format v4l2_format;
+};
+/*---------------------------------------------------------------------------*/
+/*
+ * easycap.ilk == 0 => CVBS+S-VIDEO HARDWARE, AUDIO wMaxPacketSize=256
+ * easycap.ilk == 2 => CVBS+S-VIDEO HARDWARE, AUDIO wMaxPacketSize=9
+ * easycap.ilk == 3 => FOUR-CVBS HARDWARE, AUDIO wMaxPacketSize=9
+ */
+/*---------------------------------------------------------------------------*/
+struct easycap {
+unsigned int audio_pages_per_fragment;
+unsigned int audio_bytes_per_fragment;
+unsigned int audio_buffer_page_many;
+
+#define UPSAMPLE
+#if defined(UPSAMPLE)
+__s16 oldaudio;
+#endif /*UPSAMPLE*/
+
+struct easycap_format easycap_format[1 + SETTINGS_MANY];
+
+int ilk;
+bool microphone;
+
+/*vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/
+#if defined(EASYCAP_IS_VIDEODEV_CLIENT)
+struct video_device *pvideo_device;
+#endif /*EASYCAP_IS_VIDEODEV_CLIENT*/
+/*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
+
+struct usb_device *pusb_device;
+struct usb_interface *pusb_interface;
+
+struct kref kref;
+
+struct mutex mutex_mmap_video[FRAME_BUFFER_MANY];
+struct mutex mutex_timeval0;
+struct mutex mutex_timeval1;
+
+int queued[FRAME_BUFFER_MANY];
+int done[FRAME_BUFFER_MANY];
+
+wait_queue_head_t wq_video;
+wait_queue_head_t wq_audio;
+
+int input;
+int polled;
+int standard_offset;
+int format_offset;
+
+int fps;
+int usec;
+int tolerate;
+int merit[180];
+
+struct timeval timeval0;
+struct timeval timeval1;
+struct timeval timeval2;
+struct timeval timeval7;
+long long int dnbydt;
+
+int video_interface;
+int video_altsetting_on;
+int video_altsetting_off;
+int video_endpointnumber;
+int video_isoc_maxframesize;
+int video_isoc_buffer_size;
+int video_isoc_framesperdesc;
+
+int video_isoc_streaming;
+int video_isoc_sequence;
+int video_idle;
+int video_eof;
+int video_junk;
+
+int fudge;
+
+struct data_buffer video_isoc_buffer[VIDEO_ISOC_BUFFER_MANY];
+struct data_buffer \
+ field_buffer[FIELD_BUFFER_MANY][(FIELD_BUFFER_SIZE/PAGE_SIZE)];
+struct data_buffer \
+ frame_buffer[FRAME_BUFFER_MANY][(FRAME_BUFFER_SIZE/PAGE_SIZE)];
+
+struct list_head urb_video_head;
+struct list_head *purb_video_head;
+
+int vma_many;
+
+/*---------------------------------------------------------------------------*/
+/*
+ * BUFFER INDICATORS
+ */
+/*---------------------------------------------------------------------------*/
+int field_fill; /* Field buffer being filled by easycap_complete(). */
+ /* Bumped only by easycap_complete(). */
+int field_page; /* Page of field buffer page being filled by */
+ /* easycap_complete(). */
+int field_read; /* Field buffer to be read by field2frame(). */
+ /* Bumped only by easycap_complete(). */
+int frame_fill; /* Frame buffer being filled by field2frame(). */
+ /* Bumped only by easycap_dqbuf() when */
+ /* field2frame() has created a complete frame. */
+int frame_read; /* Frame buffer offered to user by DQBUF. */
+ /* Set only by easycap_dqbuf() to trail frame_fill.*/
+int frame_lock; /* Flag set to 1 by DQBUF and cleared by QBUF */
+/*---------------------------------------------------------------------------*/
+/*
+ * IMAGE PROPERTIES
+ */
+/*---------------------------------------------------------------------------*/
+__u32 pixelformat;
+__u32 field;
+int width;
+int height;
+int bytesperpixel;
+bool byteswaporder;
+bool decimatepixel;
+bool offerfields;
+int frame_buffer_used;
+int frame_buffer_many;
+int videofieldamount;
+
+int brightness;
+int contrast;
+int saturation;
+int hue;
+
+int allocation_video_urb;
+int allocation_video_page;
+int allocation_video_struct;
+int registered_video;
+/*---------------------------------------------------------------------------*/
+/*
+ * SOUND PROPERTIES
+ */
+/*---------------------------------------------------------------------------*/
+int audio_interface;
+int audio_altsetting_on;
+int audio_altsetting_off;
+int audio_endpointnumber;
+int audio_isoc_maxframesize;
+int audio_isoc_buffer_size;
+int audio_isoc_framesperdesc;
+
+int audio_isoc_streaming;
+int audio_idle;
+int audio_eof;
+int volume;
+int mute;
+
+struct data_buffer audio_isoc_buffer[AUDIO_ISOC_BUFFER_MANY];
+
+struct list_head urb_audio_head;
+struct list_head *purb_audio_head;
+/*---------------------------------------------------------------------------*/
+/*
+ * BUFFER INDICATORS
+ */
+/*---------------------------------------------------------------------------*/
+int audio_fill; /* Audio buffer being filled by easysnd_complete(). */
+ /* Bumped only by easysnd_complete(). */
+int audio_read; /* Audio buffer page being read by easysnd_read(). */
+ /* Set by easysnd_read() to trail audio_fill by */
+ /* one fragment. */
+/*---------------------------------------------------------------------------*/
+/*
+ * SOUND PROPERTIES
+ */
+/*---------------------------------------------------------------------------*/
+
+int audio_buffer_many;
+
+int allocation_audio_urb;
+int allocation_audio_page;
+int allocation_audio_struct;
+int registered_audio;
+
+long long int audio_sample;
+long long int audio_niveau;
+long long int audio_square;
+
+struct data_buffer audio_buffer[];
+};
+/*---------------------------------------------------------------------------*/
+/*
+ * VIDEO FUNCTION PROTOTYPES
+ */
+/*---------------------------------------------------------------------------*/
+void easycap_complete(struct urb *);
+int easycap_open(struct inode *, struct file *);
+int easycap_release(struct inode *, struct file *);
+int easycap_ioctl(struct inode *, struct file *, \
+ unsigned int, unsigned long);
+
+/*vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/
+#if defined(EASYCAP_IS_VIDEODEV_CLIENT)
+int easycap_open_noinode(struct file *);
+int easycap_release_noinode(struct file *);
+long easycap_ioctl_noinode(struct file *, \
+ unsigned int, unsigned long);
+int videodev_release(struct video_device *);
+#endif /*EASYCAP_IS_VIDEODEV_CLIENT*/
+/*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
+
+unsigned int easycap_poll(struct file *, poll_table *);
+int easycap_mmap(struct file *, struct vm_area_struct *);
+int easycap_usb_probe(struct usb_interface *, \
+ const struct usb_device_id *);
+void easycap_usb_disconnect(struct usb_interface *);
+void easycap_delete(struct kref *);
+
+void easycap_vma_open(struct vm_area_struct *);
+void easycap_vma_close(struct vm_area_struct *);
+int easycap_vma_fault(struct vm_area_struct *, struct vm_fault *);
+int easycap_dqbuf(struct easycap *, int);
+int submit_video_urbs(struct easycap *);
+int kill_video_urbs(struct easycap *);
+int field2frame(struct easycap *);
+int redaub(struct easycap *, void *, void *, \
+ int, int, __u8, __u8, bool);
+void debrief(struct easycap *);
+void sayreadonly(struct easycap *);
+void easycap_testcard(struct easycap *, int);
+int explain_ioctl(__u32);
+int explain_cid(__u32);
+int fillin_formats(void);
+int adjust_standard(struct easycap *, v4l2_std_id);
+int adjust_format(struct easycap *, __u32, __u32, __u32, \
+ int, bool);
+int adjust_brightness(struct easycap *, int);
+int adjust_contrast(struct easycap *, int);
+int adjust_saturation(struct easycap *, int);
+int adjust_hue(struct easycap *, int);
+int adjust_volume(struct easycap *, int);
+/*---------------------------------------------------------------------------*/
+/*
+ * AUDIO FUNCTION PROTOTYPES
+ */
+/*---------------------------------------------------------------------------*/
+void easysnd_complete(struct urb *);
+ssize_t easysnd_read(struct file *, char __user *, size_t, loff_t *);
+int easysnd_open(struct inode *, struct file *);
+int easysnd_release(struct inode *, struct file *);
+int easysnd_ioctl(struct inode *, struct file *, \
+ unsigned int, unsigned long);
+unsigned int easysnd_poll(struct file *, poll_table *);
+void easysnd_delete(struct kref *);
+int submit_audio_urbs(struct easycap *);
+int kill_audio_urbs(struct easycap *);
+void easysnd_testtone(struct easycap *, int);
+int audio_setup(struct easycap *);
+/*---------------------------------------------------------------------------*/
+/*
+ * LOW-LEVEL FUNCTION PROTOTYPES
+ */
+/*---------------------------------------------------------------------------*/
+int audio_gainget(struct usb_device *);
+int audio_gainset(struct usb_device *, __s8);
+
+int set_interface(struct usb_device *, __u16);
+int wakeup_device(struct usb_device *);
+int confirm_resolution(struct usb_device *);
+int confirm_stream(struct usb_device *);
+
+int setup_stk(struct usb_device *);
+int setup_saa(struct usb_device *);
+int setup_vt(struct usb_device *);
+int check_stk(struct usb_device *);
+int check_saa(struct usb_device *);
+int ready_saa(struct usb_device *);
+int merit_saa(struct usb_device *);
+int check_vt(struct usb_device *);
+int select_input(struct usb_device *, int, int);
+int set_resolution(struct usb_device *, \
+ __u16, __u16, __u16, __u16);
+
+int read_saa(struct usb_device *, __u16);
+int read_stk(struct usb_device *, __u32);
+int write_saa(struct usb_device *, __u16, __u16);
+int wait_i2c(struct usb_device *);
+int write_000(struct usb_device *, __u16, __u16);
+int start_100(struct usb_device *);
+int stop_100(struct usb_device *);
+int write_300(struct usb_device *);
+int read_vt(struct usb_device *, __u16);
+int write_vt(struct usb_device *, __u16, __u16);
+
+int set2to78(struct usb_device *);
+int set2to93(struct usb_device *);
+
+int regset(struct usb_device *, __u16, __u16);
+int regget(struct usb_device *, __u16, void *);
+/*---------------------------------------------------------------------------*/
+struct signed_div_result {
+long long int quotient;
+unsigned long long int remainder;
+} signed_div(long long int, long long int);
+/*---------------------------------------------------------------------------*/
+/*
+ * MACROS
+ */
+/*---------------------------------------------------------------------------*/
+#define GET(X, Y, Z) do { \
+ int rc; \
+ *(Z) = (__u16)0; \
+ rc = regget(X, Y, Z); \
+ if (0 > rc) { \
+ JOT(8, ":-(%i\n", __LINE__); return(rc); \
+ } \
+} while (0)
+
+#define SET(X, Y, Z) do { \
+ int rc; \
+ rc = regset(X, Y, Z); \
+ if (0 > rc) { \
+ JOT(8, ":-(%i\n", __LINE__); return(rc); \
+ } \
+} while (0)
+/*---------------------------------------------------------------------------*/
+
+#define SAY(format, args...) do { \
+ printk(KERN_DEBUG "easycap: %s: " format, __func__, ##args); \
+} while (0)
+
+
+#if defined(EASYCAP_DEBUG)
+#define JOT(n, format, args...) do { \
+ if (n <= easycap_debug) { \
+ printk(KERN_DEBUG "easycap: %s: " format, __func__, ##args); \
+ } \
+} while (0)
+#else
+#define JOT(n, format, args...) do {} while (0)
+#endif /*EASYCAP_DEBUG*/
+
+#define POUT JOT(8, ":-(in file %s line %4i\n", __FILE__, __LINE__)
+
+#define MICROSECONDS(X, Y) \
+ ((1000000*((long long int)(X.tv_sec - Y.tv_sec))) + \
+ (long long int)(X.tv_usec - Y.tv_usec))
+
+/*---------------------------------------------------------------------------*/
+/*
+ * (unsigned char *)P pointer to next byte pair
+ * (long int *)X pointer to accumulating count
+ * (long int *)Y pointer to accumulating sum
+ * (long long int *)Z pointer to accumulating sum of squares
+ */
+/*---------------------------------------------------------------------------*/
+#define SUMMER(P, X, Y, Z) do { \
+ unsigned char *p; \
+ unsigned int u0, u1, u2; \
+ long int s; \
+ p = (unsigned char *)(P); \
+ u0 = (unsigned int) (*p); \
+ u1 = (unsigned int) (*(p + 1)); \
+ u2 = (unsigned int) ((u1 << 8) | u0); \
+ if (0x8000 & u2) \
+ s = -(long int)(0x7FFF & (~u2)); \
+ else \
+ s = (long int)(0x7FFF & u2); \
+ *((X)) += (long int) 1; \
+ *((Y)) += (long int) s; \
+ *((Z)) += ((long long int)(s) * (long long int)(s)); \
+} while (0)
+/*---------------------------------------------------------------------------*/
+
+#endif /*EASYCAP_H*/
diff --git a/drivers/staging/easycap/easycap_debug.h b/drivers/staging/easycap/easycap_debug.h
new file mode 100644
index 00000000000..1d10d7ea7d6
--- /dev/null
+++ b/drivers/staging/easycap/easycap_debug.h
@@ -0,0 +1,27 @@
+/*****************************************************************************
+* *
+* easycap_debug.h *
+* *
+*****************************************************************************/
+/*
+ *
+ * Copyright (C) 2010 R.M. Thomas <rmthomas@sciolus.org>
+ *
+ *
+ * This is free software; you can redistribute it and/or modify
+ * 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 software 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 software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+*/
+/*****************************************************************************/
+extern int easycap_debug;
diff --git a/drivers/staging/easycap/easycap_ioctl.c b/drivers/staging/easycap/easycap_ioctl.c
new file mode 100644
index 00000000000..276b63dfe27
--- /dev/null
+++ b/drivers/staging/easycap/easycap_ioctl.c
@@ -0,0 +1,2687 @@
+/******************************************************************************
+* *
+* easycap_ioctl.c *
+* *
+******************************************************************************/
+/*
+ *
+ * Copyright (C) 2010 R.M. Thomas <rmthomas@sciolus.org>
+ *
+ *
+ * This is free software; you can redistribute it and/or modify
+ * 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 software 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 software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+*/
+/*****************************************************************************/
+
+#include "easycap.h"
+#include "easycap_debug.h"
+#include "easycap_standard.h"
+#include "easycap_ioctl.h"
+
+/*--------------------------------------------------------------------------*/
+/*
+ * UNLESS THERE IS A PREMATURE ERROR RETURN THIS ROUTINE UPDATES THE
+ * FOLLOWING:
+ * peasycap->standard_offset
+ * peasycap->fps
+ * peasycap->usec
+ * peasycap->tolerate
+ */
+/*---------------------------------------------------------------------------*/
+int adjust_standard(struct easycap *peasycap, v4l2_std_id std_id)
+{
+struct easycap_standard const *peasycap_standard;
+__u16 reg, set;
+int ir, rc, need;
+unsigned int itwas, isnow;
+
+if ((struct usb_device *)NULL == peasycap->pusb_device) {
+ SAY("ERROR: peasycap->pusb_device is NULL\n");
+ return -EFAULT;
+}
+peasycap_standard = &easycap_standard[0];
+while (0xFFFF != peasycap_standard->mask) {
+ if (std_id & peasycap_standard->v4l2_standard.id)
+ break;
+ peasycap_standard++;
+}
+if (0xFFFF == peasycap_standard->mask) {
+ SAY("ERROR: 0x%08X=std_id: standard not found\n", \
+ (unsigned int)std_id);
+ return -EINVAL;
+}
+SAY("user requests standard: %s\n", \
+ &(peasycap_standard->v4l2_standard.name[0]));
+if (peasycap->standard_offset == \
+ (int)(peasycap_standard - &easycap_standard[0])) {
+ SAY("requested standard already in effect\n");
+ return 0;
+}
+peasycap->standard_offset = (int)(peasycap_standard - &easycap_standard[0]);
+peasycap->fps = peasycap_standard->v4l2_standard.frameperiod.denominator / \
+ peasycap_standard->v4l2_standard.frameperiod.numerator;
+if (!peasycap->fps) {
+ SAY("MISTAKE: frames-per-second is zero\n");
+ return -EFAULT;
+}
+JOT(8, "%i frames-per-second\n", peasycap->fps);
+peasycap->usec = 1000000 / (2 * peasycap->fps);
+peasycap->tolerate = 1000 * (25 / peasycap->fps);
+
+kill_video_urbs(peasycap);
+
+/*--------------------------------------------------------------------------*/
+/*
+ * SAA7113H DATASHEET PAGE 44, TABLE 42
+ */
+/*--------------------------------------------------------------------------*/
+need = 0; itwas = 0; reg = 0x00; set = 0x00;
+switch (peasycap_standard->mask & 0x000F) {
+case NTSC_M_JP: {
+ reg = 0x0A; set = 0x95;
+ ir = read_saa(peasycap->pusb_device, reg);
+ if (0 > ir)
+ SAY("ERROR: cannot read SAA register 0x%02X\n", reg);
+ else
+ itwas = (unsigned int)ir;
+
+
+ set2to78(peasycap->pusb_device);
+
+
+ rc = write_saa(peasycap->pusb_device, reg, set);
+ if (0 != rc)
+ SAY("ERROR: failed to set SAA register " \
+ "0x%02X to 0x%02X for JP standard\n", reg, set);
+ else {
+ isnow = (unsigned int)read_saa(peasycap->pusb_device, reg);
+ if (0 > ir)
+ JOT(8, "SAA register 0x%02X changed " \
+ "to 0x%02X\n", reg, isnow);
+ else
+ JOT(8, "SAA register 0x%02X changed " \
+ "from 0x%02X to 0x%02X\n", reg, itwas, isnow);
+
+ set2to78(peasycap->pusb_device);
+
+ }
+
+ reg = 0x0B; set = 0x48;
+ ir = read_saa(peasycap->pusb_device, reg);
+ if (0 > ir)
+ SAY("ERROR: cannot read SAA register 0x%02X\n", reg);
+ else
+ itwas = (unsigned int)ir;
+
+ set2to78(peasycap->pusb_device);
+
+ rc = write_saa(peasycap->pusb_device, reg, set);
+ if (0 != rc)
+ SAY("ERROR: failed to set SAA register 0x%02X to 0x%02X " \
+ "for JP standard\n", reg, set);
+ else {
+ isnow = (unsigned int)read_saa(peasycap->pusb_device, reg);
+ if (0 > ir)
+ JOT(8, "SAA register 0x%02X changed " \
+ "to 0x%02X\n", reg, isnow);
+ else
+ JOT(8, "SAA register 0x%02X changed " \
+ "from 0x%02X to 0x%02X\n", reg, itwas, isnow);
+
+ set2to78(peasycap->pusb_device);
+
+ }
+/*--------------------------------------------------------------------------*/
+/*
+ * NOTE: NO break HERE: RUN ON TO NEXT CASE
+ */
+/*--------------------------------------------------------------------------*/
+}
+case NTSC_M:
+case PAL_BGHIN: {
+ reg = 0x0E; set = 0x01; need = 1; break;
+}
+case NTSC_N_443:
+case PAL_60: {
+ reg = 0x0E; set = 0x11; need = 1; break;
+}
+case NTSC_443:
+case PAL_Nc: {
+ reg = 0x0E; set = 0x21; need = 1; break;
+}
+case NTSC_N:
+case PAL_M: {
+ reg = 0x0E; set = 0x31; need = 1; break;
+}
+case SECAM: {
+ reg = 0x0E; set = 0x51; need = 1; break;
+}
+default:
+ break;
+}
+/*--------------------------------------------------------------------------*/
+if (need) {
+ ir = read_saa(peasycap->pusb_device, reg);
+ if (0 > ir)
+ SAY("ERROR: failed to read SAA register 0x%02X\n", reg);
+ else
+ itwas = (unsigned int)ir;
+
+ set2to78(peasycap->pusb_device);
+
+ rc = write_saa(peasycap->pusb_device, reg, set);
+ if (0 != write_saa(peasycap->pusb_device, reg, set)) {
+ SAY("ERROR: failed to set SAA register " \
+ "0x%02X to 0x%02X for table 42\n", reg, set);
+ } else {
+ isnow = (unsigned int)read_saa(peasycap->pusb_device, reg);
+ if (0 > ir)
+ JOT(8, "SAA register 0x%02X changed " \
+ "to 0x%02X\n", reg, isnow);
+ else
+ JOT(8, "SAA register 0x%02X changed " \
+ "from 0x%02X to 0x%02X\n", reg, itwas, isnow);
+ }
+}
+/*--------------------------------------------------------------------------*/
+/*
+ * SAA7113H DATASHEET PAGE 41
+ */
+/*--------------------------------------------------------------------------*/
+reg = 0x08;
+ir = read_saa(peasycap->pusb_device, reg);
+if (0 > ir)
+ SAY("ERROR: failed to read SAA register 0x%02X " \
+ "so cannot reset\n", reg);
+else {
+ itwas = (unsigned int)ir;
+ if (peasycap_standard->mask & 0x0001)
+ set = itwas | 0x40 ;
+ else
+ set = itwas & ~0x40 ;
+
+set2to78(peasycap->pusb_device);
+
+rc = write_saa(peasycap->pusb_device, reg, set);
+if (0 != rc)
+ SAY("ERROR: failed to set SAA register 0x%02X to 0x%02X\n", reg, set);
+else {
+ isnow = (unsigned int)read_saa(peasycap->pusb_device, reg);
+ if (0 > ir)
+ JOT(8, "SAA register 0x%02X changed to 0x%02X\n", reg, isnow);
+ else
+ JOT(8, "SAA register 0x%02X changed " \
+ "from 0x%02X to 0x%02X\n", reg, itwas, isnow);
+ }
+}
+/*--------------------------------------------------------------------------*/
+/*
+ * SAA7113H DATASHEET PAGE 51, TABLE 57
+ */
+/*---------------------------------------------------------------------------*/
+reg = 0x40;
+ir = read_saa(peasycap->pusb_device, reg);
+if (0 > ir)
+ SAY("ERROR: failed to read SAA register 0x%02X " \
+ "so cannot reset\n", reg);
+else {
+ itwas = (unsigned int)ir;
+ if (peasycap_standard->mask & 0x0001)
+ set = itwas | 0x80 ;
+ else
+ set = itwas & ~0x80 ;
+
+set2to78(peasycap->pusb_device);
+
+rc = write_saa(peasycap->pusb_device, reg, set);
+if (0 != rc)
+ SAY("ERROR: failed to set SAA register 0x%02X to 0x%02X\n", reg, set);
+else {
+ isnow = (unsigned int)read_saa(peasycap->pusb_device, reg);
+ if (0 > ir)
+ JOT(8, "SAA register 0x%02X changed to 0x%02X\n", reg, isnow);
+ else
+ JOT(8, "SAA register 0x%02X changed " \
+ "from 0x%02X to 0x%02X\n", reg, itwas, isnow);
+ }
+}
+/*--------------------------------------------------------------------------*/
+/*
+ * SAA7113H DATASHEET PAGE 53, TABLE 66
+ */
+/*--------------------------------------------------------------------------*/
+reg = 0x5A;
+ir = read_saa(peasycap->pusb_device, reg);
+if (0 > ir)
+ SAY("ERROR: failed to read SAA register 0x%02X but continuing\n", reg);
+ itwas = (unsigned int)ir;
+ if (peasycap_standard->mask & 0x0001)
+ set = 0x0A ;
+ else
+ set = 0x07 ;
+
+ set2to78(peasycap->pusb_device);
+
+ if (0 != write_saa(peasycap->pusb_device, reg, set))
+ SAY("ERROR: failed to set SAA register 0x%02X to 0x%02X\n", \
+ reg, set);
+ else {
+ isnow = (unsigned int)read_saa(peasycap->pusb_device, reg);
+ if (0 > ir)
+ JOT(8, "SAA register 0x%02X changed "
+ "to 0x%02X\n", reg, isnow);
+ else
+ JOT(8, "SAA register 0x%02X changed "
+ "from 0x%02X to 0x%02X\n", reg, itwas, isnow);
+ }
+ if (0 != check_saa(peasycap->pusb_device))
+ SAY("ERROR: check_saa() failed\n");
+return 0;
+}
+/*****************************************************************************/
+/*--------------------------------------------------------------------------*/
+/*
+ * THE ALGORITHM FOR RESPONDING TO THE VIDIO_S_FMT IOCTL DEPENDS ON THE
+ * CURRENT VALUE OF peasycap->standard_offset.
+ * PROVIDED THE ARGUMENT try IS false AND THERE IS NO PREMATURE ERROR RETURN
+ * THIS ROUTINE UPDATES THE FOLLOWING:
+ * peasycap->format_offset
+ * peasycap->pixelformat
+ * peasycap->field
+ * peasycap->height
+ * peasycap->width
+ * peasycap->bytesperpixel
+ * peasycap->byteswaporder
+ * peasycap->decimatepixel
+ * peasycap->frame_buffer_used
+ * peasycap->videofieldamount
+ * peasycap->offerfields
+ *
+ * IF SUCCESSFUL THE FUNCTION RETURNS THE OFFSET IN easycap_format[]
+ * IDENTIFYING THE FORMAT WHICH IS TO RETURNED TO THE USER.
+ * ERRORS RETURN A NEGATIVE NUMBER.
+ */
+/*--------------------------------------------------------------------------*/
+int adjust_format(struct easycap *peasycap, \
+ __u32 width, __u32 height, __u32 pixelformat, int field, bool try)
+{
+struct easycap_format *peasycap_format, *peasycap_best_format;
+__u16 mask;
+struct usb_device *p;
+int miss, multiplier, best;
+char bf[5], *pc;
+__u32 uc;
+
+if ((struct easycap *)NULL == peasycap) {
+ SAY("ERROR: peasycap is NULL\n");
+ return -EFAULT;
+}
+p = peasycap->pusb_device;
+if ((struct usb_device *)NULL == p) {
+ SAY("ERROR: peaycap->pusb_device is NULL\n");
+ return -EFAULT;
+}
+pc = &bf[0];
+uc = pixelformat; memcpy((void *)pc, (void *)(&uc), 4); bf[4] = 0;
+mask = easycap_standard[peasycap->standard_offset].mask;
+SAY("sought: %ix%i,%s(0x%08X),%i=field,0x%02X=std mask\n", \
+ width, height, pc, pixelformat, field, mask);
+if (V4L2_FIELD_ANY == field) {
+ field = V4L2_FIELD_INTERLACED;
+ SAY("prefer: V4L2_FIELD_INTERLACED=field, was V4L2_FIELD_ANY\n");
+}
+peasycap_best_format = (struct easycap_format *)NULL;
+peasycap_format = &easycap_format[0];
+while (0 != peasycap_format->v4l2_format.fmt.pix.width) {
+ JOT(16, ".> %i %i 0x%08X %ix%i\n", \
+ peasycap_format->mask & 0x01,
+ peasycap_format->v4l2_format.fmt.pix.field,
+ peasycap_format->v4l2_format.fmt.pix.pixelformat,
+ peasycap_format->v4l2_format.fmt.pix.width,
+ peasycap_format->v4l2_format.fmt.pix.height);
+
+ if (((peasycap_format->mask & 0x0F) == (mask & 0x0F)) && \
+ (peasycap_format->v4l2_format.fmt.pix.field == field) && \
+ (peasycap_format->v4l2_format.fmt.pix.pixelformat == \
+ pixelformat) && \
+ (peasycap_format->v4l2_format.fmt.pix.width == width) && \
+ (peasycap_format->v4l2_format.fmt.pix.height == height)) {
+ peasycap_best_format = peasycap_format;
+ break;
+ }
+ peasycap_format++;
+}
+if (0 == peasycap_format->v4l2_format.fmt.pix.width) {
+ SAY("cannot do: %ix%i with standard mask 0x%02X\n", \
+ width, height, mask);
+ peasycap_format = &easycap_format[0]; best = -1;
+ while (0 != peasycap_format->v4l2_format.fmt.pix.width) {
+ if (((peasycap_format->mask & 0x0F) == (mask & 0x0F)) && \
+ (peasycap_format->v4l2_format.fmt.pix\
+ .field == field) && \
+ (peasycap_format->v4l2_format.fmt.pix\
+ .pixelformat == pixelformat)) {
+ miss = abs(peasycap_format->\
+ v4l2_format.fmt.pix.width - width);
+ if ((best > miss) || (best < 0)) {
+ best = miss;
+ peasycap_best_format = peasycap_format;
+ if (!miss)
+ break;
+ }
+ }
+ peasycap_format++;
+ }
+ if (-1 == best) {
+ SAY("cannot do %ix... with standard mask 0x%02X\n", \
+ width, mask);
+ SAY("cannot do ...x%i with standard mask 0x%02X\n", \
+ height, mask);
+ SAY(" %ix%i unmatched\n", width, height);
+ return peasycap->format_offset;
+ }
+}
+if ((struct easycap_format *)NULL == peasycap_best_format) {
+ SAY("MISTAKE: peasycap_best_format is NULL");
+ return -EINVAL;
+}
+peasycap_format = peasycap_best_format;
+
+/*...........................................................................*/
+if (true == try)
+ return (int)(peasycap_best_format - &easycap_format[0]);
+/*...........................................................................*/
+
+if (false != try) {
+ SAY("MISTAKE: true==try where is should be false\n");
+ return -EINVAL;
+}
+SAY("actioning: %ix%i %s\n", \
+ peasycap_format->v4l2_format.fmt.pix.width, \
+ peasycap_format->v4l2_format.fmt.pix.height,
+ &peasycap_format->name[0]);
+peasycap->height = peasycap_format->v4l2_format.fmt.pix.height;
+peasycap->width = peasycap_format->v4l2_format.fmt.pix.width;
+peasycap->pixelformat = peasycap_format->v4l2_format.fmt.pix.pixelformat;
+peasycap->field = peasycap_format->v4l2_format.fmt.pix.field;
+peasycap->format_offset = (int)(peasycap_format - &easycap_format[0]);
+peasycap->bytesperpixel = (0x00F0 & peasycap_format->mask) >> 4 ;
+if (0x0100 & peasycap_format->mask)
+ peasycap->byteswaporder = true;
+else
+ peasycap->byteswaporder = false;
+if (0x0800 & peasycap_format->mask)
+ peasycap->decimatepixel = true;
+else
+ peasycap->decimatepixel = false;
+if (0x1000 & peasycap_format->mask)
+ peasycap->offerfields = true;
+else
+ peasycap->offerfields = false;
+if (true == peasycap->decimatepixel)
+ multiplier = 2;
+else
+ multiplier = 1;
+peasycap->videofieldamount = multiplier * peasycap->width * \
+ multiplier * peasycap->height;
+peasycap->frame_buffer_used = peasycap->bytesperpixel * \
+ peasycap->width * peasycap->height;
+
+if (true == peasycap->offerfields) {
+ SAY("WARNING: %i=peasycap->field is untested: " \
+ "please report problems\n", peasycap->field);
+
+
+/*
+ * FIXME ---- THIS IS UNTESTED, MAY BE (AND PROBABLY IS) INCORRECT:
+ *
+ * peasycap->frame_buffer_used = peasycap->frame_buffer_used / 2;
+ *
+ * SO DO NOT RISK IT YET.
+ *
+ */
+
+
+
+}
+
+kill_video_urbs(peasycap);
+
+/*---------------------------------------------------------------------------*/
+/*
+ * PAL
+ */
+/*---------------------------------------------------------------------------*/
+if (0 == (0x01 & peasycap_format->mask)) {
+ if (((720 == peasycap_format->v4l2_format.fmt.pix.width) && \
+ (576 == \
+ peasycap_format->v4l2_format.fmt.pix.height)) || \
+ ((360 == \
+ peasycap_format->v4l2_format.fmt.pix.width) && \
+ (288 == \
+ peasycap_format->v4l2_format.fmt.pix.height))) {
+ if (0 != set_resolution(p, 0x0000, 0x0001, 0x05A0, 0x0121)) {
+ SAY("ERROR: set_resolution() failed\n");
+ return -EINVAL;
+ }
+ } else if ((704 == peasycap_format->v4l2_format.fmt.pix.width) && \
+ (576 == peasycap_format->v4l2_format.fmt.pix.height)) {
+ if (0 != set_resolution(p, 0x0004, 0x0001, 0x0584, 0x0121)) {
+ SAY("ERROR: set_resolution() failed\n");
+ return -EINVAL;
+ }
+ } else if (((640 == peasycap_format->v4l2_format.fmt.pix.width) && \
+ (480 == \
+ peasycap_format->v4l2_format.fmt.pix.height)) || \
+ ((320 == \
+ peasycap_format->v4l2_format.fmt.pix.width) && \
+ (240 == \
+ peasycap_format->v4l2_format.fmt.pix.height))) {
+ if (0 != set_resolution(p, 0x0014, 0x0020, 0x0514, 0x0110)) {
+ SAY("ERROR: set_resolution() failed\n");
+ return -EINVAL;
+ }
+ } else {
+ SAY("MISTAKE: bad format, cannot set resolution\n");
+ return -EINVAL;
+ }
+/*---------------------------------------------------------------------------*/
+/*
+ * NTSC
+ */
+/*---------------------------------------------------------------------------*/
+} else {
+ if (((720 == peasycap_format->v4l2_format.fmt.pix.width) && \
+ (480 == \
+ peasycap_format->v4l2_format.fmt.pix.height)) || \
+ ((360 == \
+ peasycap_format->v4l2_format.fmt.pix.width) && \
+ (240 == \
+ peasycap_format->v4l2_format.fmt.pix.height))) {
+ if (0 != set_resolution(p, 0x0000, 0x0003, 0x05A0, 0x00F3)) {
+ SAY("ERROR: set_resolution() failed\n");
+ return -EINVAL;
+ }
+ } else if (((640 == peasycap_format->v4l2_format.fmt.pix.width) && \
+ (480 == \
+ peasycap_format->v4l2_format.fmt.pix.height)) || \
+ ((320 == \
+ peasycap_format->v4l2_format.fmt.pix.width) && \
+ (240 == \
+ peasycap_format->v4l2_format.fmt.pix.height))) {
+ if (0 != set_resolution(p, 0x0014, 0x0003, 0x0514, 0x00F3)) {
+ SAY("ERROR: set_resolution() failed\n");
+ return -EINVAL;
+ }
+ } else {
+ SAY("MISTAKE: bad format, cannot set resolution\n");
+ return -EINVAL;
+ }
+}
+/*---------------------------------------------------------------------------*/
+
+check_stk(peasycap->pusb_device);
+
+return (int)(peasycap_best_format - &easycap_format[0]);
+}
+/*****************************************************************************/
+int adjust_brightness(struct easycap *peasycap, int value)
+{
+unsigned int mood;
+int i1;
+
+if ((struct usb_device *)NULL == peasycap->pusb_device) {
+ SAY("ERROR: peasycap->pusb_device is NULL\n");
+ return -EFAULT;
+}
+i1 = 0;
+while (0xFFFFFFFF != easycap_control[i1].id) {
+ if (V4L2_CID_BRIGHTNESS == easycap_control[i1].id) {
+ if ((easycap_control[i1].minimum > value) || \
+ (easycap_control[i1].maximum < value))
+ value = easycap_control[i1].default_value;
+ peasycap->brightness = value;
+ mood = 0x00FF & (unsigned int)peasycap->brightness;
+
+ set2to78(peasycap->pusb_device);
+
+ if (!write_saa(peasycap->pusb_device, 0x0A, mood)) {
+ SAY("adjusting brightness to 0x%02X\n", mood);
+ return 0;
+ } else {
+ SAY("WARNING: failed to adjust brightness " \
+ "to 0x%02X\n", mood);
+ return -ENOENT;
+ }
+
+ set2to78(peasycap->pusb_device);
+
+ break;
+ }
+ i1++;
+}
+SAY("WARNING: failed to adjust brightness: control not found\n");
+return -ENOENT;
+}
+/*****************************************************************************/
+int adjust_contrast(struct easycap *peasycap, int value)
+{
+unsigned int mood;
+int i1;
+
+if ((struct usb_device *)NULL == peasycap->pusb_device) {
+ SAY("ERROR: peasycap->pusb_device is NULL\n");
+ return -EFAULT;
+}
+i1 = 0;
+while (0xFFFFFFFF != easycap_control[i1].id) {
+ if (V4L2_CID_CONTRAST == easycap_control[i1].id) {
+ if ((easycap_control[i1].minimum > value) || \
+ (easycap_control[i1].maximum < value))
+ value = easycap_control[i1].default_value;
+ peasycap->contrast = value;
+ mood = 0x00FF & (unsigned int) (peasycap->contrast - 128);
+
+ set2to78(peasycap->pusb_device);
+
+ if (!write_saa(peasycap->pusb_device, 0x0B, mood)) {
+ SAY("adjusting contrast to 0x%02X\n", mood);
+ return 0;
+ } else {
+ SAY("WARNING: failed to adjust contrast to " \
+ "0x%02X\n", mood);
+ return -ENOENT;
+ }
+
+ set2to78(peasycap->pusb_device);
+
+ break;
+ }
+ i1++;
+}
+SAY("WARNING: failed to adjust contrast: control not found\n");
+return -ENOENT;
+}
+/*****************************************************************************/
+int adjust_saturation(struct easycap *peasycap, int value)
+{
+unsigned int mood;
+int i1;
+
+if ((struct usb_device *)NULL == peasycap->pusb_device) {
+ SAY("ERROR: peasycap->pusb_device is NULL\n");
+ return -EFAULT;
+}
+i1 = 0;
+while (0xFFFFFFFF != easycap_control[i1].id) {
+ if (V4L2_CID_SATURATION == easycap_control[i1].id) {
+ if ((easycap_control[i1].minimum > value) || \
+ (easycap_control[i1].maximum < value))
+ value = easycap_control[i1].default_value;
+ peasycap->saturation = value;
+ mood = 0x00FF & (unsigned int) (peasycap->saturation - 128);
+
+ set2to78(peasycap->pusb_device);
+
+ if (!write_saa(peasycap->pusb_device, 0x0C, mood)) {
+ SAY("adjusting saturation to 0x%02X\n", mood);
+ return 0;
+ } else {
+ SAY("WARNING: failed to adjust saturation to " \
+ "0x%02X\n", mood);
+ return -ENOENT;
+ }
+ break;
+
+ set2to78(peasycap->pusb_device);
+
+ }
+ i1++;
+}
+SAY("WARNING: failed to adjust saturation: control not found\n");
+return -ENOENT;
+}
+/*****************************************************************************/
+int adjust_hue(struct easycap *peasycap, int value)
+{
+unsigned int mood;
+int i1, i2;
+
+if ((struct usb_device *)NULL == peasycap->pusb_device) {
+ SAY("ERROR: peasycap->pusb_device is NULL\n");
+ return -EFAULT;
+}
+i1 = 0;
+while (0xFFFFFFFF != easycap_control[i1].id) {
+ if (V4L2_CID_HUE == easycap_control[i1].id) {
+ if ((easycap_control[i1].minimum > value) || \
+ (easycap_control[i1].maximum < value))
+ value = easycap_control[i1].default_value;
+ peasycap->hue = value;
+ i2 = peasycap->hue - 128;
+ mood = 0x00FF & ((int) i2);
+
+ set2to78(peasycap->pusb_device);
+
+ if (!write_saa(peasycap->pusb_device, 0x0D, mood)) {
+ SAY("adjusting hue to 0x%02X\n", mood);
+ return 0;
+ } else {
+ SAY("WARNING: failed to adjust hue to 0x%02X\n", mood);
+ return -ENOENT;
+ }
+
+ set2to78(peasycap->pusb_device);
+
+ break;
+ }
+ i1++;
+}
+SAY("WARNING: failed to adjust hue: control not found\n");
+return -ENOENT;
+}
+/*****************************************************************************/
+int adjust_volume(struct easycap *peasycap, int value)
+{
+__s8 mood;
+int i1;
+
+if ((struct usb_device *)NULL == peasycap->pusb_device) {
+ SAY("ERROR: peasycap->pusb_device is NULL\n");
+ return -EFAULT;
+}
+i1 = 0;
+while (0xFFFFFFFF != easycap_control[i1].id) {
+ if (V4L2_CID_AUDIO_VOLUME == easycap_control[i1].id) {
+ if ((easycap_control[i1].minimum > value) || \
+ (easycap_control[i1].maximum < value))
+ value = easycap_control[i1].default_value;
+ peasycap->volume = value;
+ mood = (16 > peasycap->volume) ? 16 : \
+ ((31 < peasycap->volume) ? 31 : \
+ (__s8) peasycap->volume);
+ if (!audio_gainset(peasycap->pusb_device, mood)) {
+ SAY("adjusting volume to 0x%01X\n", mood);
+ return 0;
+ } else {
+ SAY("WARNING: failed to adjust volume to " \
+ "0x%1X\n", mood);
+ return -ENOENT;
+ }
+ break;
+ }
+i1++;
+}
+SAY("WARNING: failed to adjust volume: control not found\n");
+return -ENOENT;
+}
+/*****************************************************************************/
+/*---------------------------------------------------------------------------*/
+/*
+ * AN ALTERNATIVE METHOD OF MUTING MIGHT SEEM TO BE:
+ * usb_set_interface(peasycap->pusb_device, \
+ * peasycap->audio_interface, \
+ * peasycap->audio_altsetting_off);
+ * HOWEVER, AFTER THIS COMMAND IS ISSUED ALL SUBSEQUENT URBS RECEIVE STATUS
+ * -ESHUTDOWN. THE HANDLER ROUTINE easysnd_complete() DECLINES TO RESUBMIT
+ * THE URB AND THE PIPELINE COLLAPSES IRRETRIEVABLY. BEWARE.
+ */
+/*---------------------------------------------------------------------------*/
+int adjust_mute(struct easycap *peasycap, int value)
+{
+int i1;
+
+if ((struct usb_device *)NULL == peasycap->pusb_device) {
+ SAY("ERROR: peasycap->pusb_device is NULL\n");
+ return -EFAULT;
+}
+i1 = 0;
+while (0xFFFFFFFF != easycap_control[i1].id) {
+ if (V4L2_CID_AUDIO_MUTE == easycap_control[i1].id) {
+ peasycap->mute = value;
+ switch (peasycap->mute) {
+ case 1: {
+ peasycap->audio_idle = 1;
+ peasycap->timeval0.tv_sec = 0;
+ SAY("adjusting mute: %i=peasycap->audio_idle\n", \
+ peasycap->audio_idle);
+ return 0;
+ }
+ default: {
+ peasycap->audio_idle = 0;
+ SAY("adjusting mute: %i=peasycap->audio_idle\n", \
+ peasycap->audio_idle);
+ return 0;
+ }
+ }
+ break;
+ }
+ i1++;
+}
+SAY("WARNING: failed to adjust mute: control not found\n");
+return -ENOENT;
+}
+/****************************************************************************/
+/*vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/
+#if defined(EASYCAP_IS_VIDEODEV_CLIENT)
+long
+easycap_ioctl_noinode(struct file *file, unsigned int cmd, unsigned long arg)\
+ {
+ return easycap_ioctl((struct inode *)NULL, file, cmd, arg);
+}
+#endif /*EASYCAP_IS_VIDEODEV_CLIENT*/
+/*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
+/*--------------------------------------------------------------------------*/
+int easycap_ioctl(struct inode *inode, struct file *file, \
+ unsigned int cmd, unsigned long arg)
+{
+static struct easycap *peasycap;
+static struct usb_device *p;
+static __u32 isequence;
+
+peasycap = file->private_data;
+if (NULL == peasycap) {
+ SAY("ERROR: peasycap is NULL\n");
+ return -1;
+}
+p = peasycap->pusb_device;
+if ((struct usb_device *)NULL == p) {
+ SAY("ERROR: peasycap->pusb_device is NULL\n");
+ return -EFAULT;
+}
+/*---------------------------------------------------------------------------*/
+/*
+ * MOST OF THE VARIABLES DECLARED static IN THE case{} BLOCKS BELOW ARE SO
+ * DECLARED SIMPLY TO AVOID A COMPILER WARNING OF THE KIND:
+ * easycap_ioctl.c: warning:
+ * the frame size of ... bytes is larger than 1024 bytes
+ */
+/*---------------------------------------------------------------------------*/
+switch (cmd) {
+case VIDIOC_QUERYCAP: {
+ static struct v4l2_capability v4l2_capability;
+ static char version[16], *p1, *p2;
+ static int i, rc, k[3];
+ static long lng;
+
+ JOT(8, "VIDIOC_QUERYCAP\n");
+
+ if (16 <= strlen(EASYCAP_DRIVER_VERSION)) {
+ SAY("ERROR: bad driver version string\n"); return -EINVAL;
+ }
+ strcpy(&version[0], EASYCAP_DRIVER_VERSION);
+ for (i = 0; i < 3; i++)
+ k[i] = 0;
+ p2 = &version[0]; i = 0;
+ while (*p2) {
+ p1 = p2;
+ while (*p2 && ('.' != *p2))
+ p2++;
+ if (*p2)
+ *p2++ = 0;
+ if (3 > i) {
+ rc = (int) strict_strtol(p1, 10, &lng);
+ if (0 != rc) {
+ SAY("ERROR: %i=strict_strtol(%s,.,,)\n", \
+ rc, p1);
+ return -EINVAL;
+ }
+ k[i] = (int)lng;
+ }
+ i++;
+ }
+
+ memset(&v4l2_capability, 0, sizeof(struct v4l2_capability));
+ strlcpy(&v4l2_capability.driver[0], "easycap", \
+ sizeof(v4l2_capability.driver));
+
+ v4l2_capability.capabilities = \
+ V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING | \
+ V4L2_CAP_AUDIO | V4L2_CAP_READWRITE;
+
+ v4l2_capability.version = KERNEL_VERSION(k[0], k[1], k[2]);
+ JOT(8, "v4l2_capability.version=(%i,%i,%i)\n", k[0], k[1], k[2]);
+
+ strlcpy(&v4l2_capability.card[0], "EasyCAP DC60", \
+ sizeof(v4l2_capability.card));
+
+ if (usb_make_path(peasycap->pusb_device, &v4l2_capability.bus_info[0],\
+ sizeof(v4l2_capability.bus_info)) < 0) {
+ strlcpy(&v4l2_capability.bus_info[0], "EasyCAP bus_info", \
+ sizeof(v4l2_capability.bus_info));
+ JOT(8, "%s=v4l2_capability.bus_info\n", \
+ &v4l2_capability.bus_info[0]);
+ }
+ if (0 != copy_to_user((void __user *)arg, &v4l2_capability, \
+ sizeof(struct v4l2_capability))) {
+ POUT;
+ return -EFAULT;
+ }
+ break;
+}
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+case VIDIOC_ENUMINPUT: {
+ static struct v4l2_input v4l2_input;
+ static __u32 index;
+
+ JOT(8, "VIDIOC_ENUMINPUT\n");
+
+ if (0 != copy_from_user(&v4l2_input, (void __user *)arg, \
+ sizeof(struct v4l2_input))) {
+ POUT;
+ return -EFAULT;
+ }
+
+ index = v4l2_input.index;
+ memset(&v4l2_input, 0, sizeof(struct v4l2_input));
+
+ switch (index) {
+ case 0: {
+ v4l2_input.index = index;
+ strcpy(&v4l2_input.name[0], "CVBS0");
+ v4l2_input.type = V4L2_INPUT_TYPE_CAMERA;
+ v4l2_input.audioset = 0x01;
+ v4l2_input.tuner = 0;
+ v4l2_input.std = V4L2_STD_PAL | V4L2_STD_SECAM | \
+ V4L2_STD_NTSC ;
+ v4l2_input.status = 0;
+ JOT(8, "%i=index: %s\n", index, &v4l2_input.name[0]);
+ break;
+ }
+ case 1: {
+ v4l2_input.index = index;
+ strcpy(&v4l2_input.name[0], "CVBS1");
+ v4l2_input.type = V4L2_INPUT_TYPE_CAMERA;
+ v4l2_input.audioset = 0x01;
+ v4l2_input.tuner = 0;
+ v4l2_input.std = V4L2_STD_PAL | V4L2_STD_SECAM | \
+ V4L2_STD_NTSC ;
+ v4l2_input.status = 0;
+ JOT(8, "%i=index: %s\n", index, &v4l2_input.name[0]);
+ break;
+ }
+ case 2: {
+ v4l2_input.index = index;
+ strcpy(&v4l2_input.name[0], "CVBS2");
+ v4l2_input.type = V4L2_INPUT_TYPE_CAMERA;
+ v4l2_input.audioset = 0x01;
+ v4l2_input.tuner = 0;
+ v4l2_input.std = V4L2_STD_PAL | V4L2_STD_SECAM | \
+ V4L2_STD_NTSC ;
+ v4l2_input.status = 0;
+ JOT(8, "%i=index: %s\n", index, &v4l2_input.name[0]);
+ break;
+ }
+ case 3: {
+ v4l2_input.index = index;
+ strcpy(&v4l2_input.name[0], "CVBS3");
+ v4l2_input.type = V4L2_INPUT_TYPE_CAMERA;
+ v4l2_input.audioset = 0x01;
+ v4l2_input.tuner = 0;
+ v4l2_input.std = V4L2_STD_PAL | V4L2_STD_SECAM | \
+ V4L2_STD_NTSC ;
+ v4l2_input.status = 0;
+ JOT(8, "%i=index: %s\n", index, &v4l2_input.name[0]);
+ break;
+ }
+ case 4: {
+ v4l2_input.index = index;
+ strcpy(&v4l2_input.name[0], "CVBS4");
+ v4l2_input.type = V4L2_INPUT_TYPE_CAMERA;
+ v4l2_input.audioset = 0x01;
+ v4l2_input.tuner = 0;
+ v4l2_input.std = V4L2_STD_PAL | V4L2_STD_SECAM | \
+ V4L2_STD_NTSC ;
+ v4l2_input.status = 0;
+ JOT(8, "%i=index: %s\n", index, &v4l2_input.name[0]);
+ break;
+ }
+ case 5: {
+ v4l2_input.index = index;
+ strcpy(&v4l2_input.name[0], "S-VIDEO");
+ v4l2_input.type = V4L2_INPUT_TYPE_CAMERA;
+ v4l2_input.audioset = 0x01;
+ v4l2_input.tuner = 0;
+ v4l2_input.std = V4L2_STD_PAL | V4L2_STD_SECAM | \
+ V4L2_STD_NTSC ;
+ v4l2_input.status = 0;
+ JOT(8, "%i=index: %s\n", index, &v4l2_input.name[0]);
+ break;
+ }
+ default: {
+ JOT(8, "%i=index: exhausts inputs\n", index);
+ return -EINVAL;
+ }
+ }
+
+ if (0 != copy_to_user((void __user *)arg, &v4l2_input, \
+ sizeof(struct v4l2_input))) {
+ POUT;
+ return -EFAULT;
+ }
+ break;
+}
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+case VIDIOC_G_INPUT: {
+ static __u32 index;
+
+ JOT(8, "VIDIOC_G_INPUT\n");
+ index = (__u32)peasycap->input;
+ JOT(8, "user is told: %i\n", index);
+ if (0 != copy_to_user((void __user *)arg, &index, sizeof(__u32))) {
+ POUT;
+ return -EFAULT;
+ }
+ break;
+}
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+case VIDIOC_S_INPUT:
+ {
+ static __u32 index;
+
+ JOT(8, "VIDIOC_S_INPUT\n");
+
+ if (0 != copy_from_user(&index, (void __user *)arg, sizeof(__u32))) {
+ POUT;
+ return -EFAULT;
+ }
+
+ JOT(8, "user requests input %i\n", index);
+
+ if ((int)index == peasycap->input) {
+ SAY("requested input already in effect\n");
+ break;
+ }
+
+ if ((0 > index) || (5 < index)) {
+ JOT(8, "ERROR: bad requested input: %i\n", index);
+ return -EINVAL;
+ }
+ peasycap->input = (int)index;
+
+ select_input(peasycap->pusb_device, peasycap->input, 9);
+
+ break;
+}
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+case VIDIOC_ENUMAUDIO: {
+ JOT(8, "VIDIOC_ENUMAUDIO\n");
+ return -EINVAL;
+}
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+case VIDIOC_ENUMAUDOUT: {
+ static struct v4l2_audioout v4l2_audioout;
+
+ JOT(8, "VIDIOC_ENUMAUDOUT\n");
+
+ if (0 != copy_from_user(&v4l2_audioout, (void __user *)arg, \
+ sizeof(struct v4l2_audioout))) {
+ POUT;
+ return -EFAULT;
+ }
+
+ if (0 != v4l2_audioout.index)
+ return -EINVAL;
+ memset(&v4l2_audioout, 0, sizeof(struct v4l2_audioout));
+ v4l2_audioout.index = 0;
+ strcpy(&v4l2_audioout.name[0], "Soundtrack");
+
+ if (0 != copy_to_user((void __user *)arg, &v4l2_audioout, \
+ sizeof(struct v4l2_audioout))) {
+ POUT;
+ return -EFAULT;
+ }
+ break;
+}
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+case VIDIOC_QUERYCTRL: {
+ static int i1;
+ static struct v4l2_queryctrl v4l2_queryctrl;
+
+ JOT(8, "VIDIOC_QUERYCTRL\n");
+
+ if (0 != copy_from_user(&v4l2_queryctrl, (void __user *)arg, \
+ sizeof(struct v4l2_queryctrl))) {
+ POUT;
+ return -EFAULT;
+ }
+
+ i1 = 0;
+ while (0xFFFFFFFF != easycap_control[i1].id) {
+ if (easycap_control[i1].id == v4l2_queryctrl.id) {
+ JOT(8, "VIDIOC_QUERYCTRL %s=easycap_control[%i]" \
+ ".name\n", &easycap_control[i1].name[0], i1);
+ memcpy(&v4l2_queryctrl, &easycap_control[i1], \
+ sizeof(struct v4l2_queryctrl));
+ break;
+ }
+ i1++;
+ }
+ if (0xFFFFFFFF == easycap_control[i1].id) {
+ JOT(8, "%i=index: exhausts controls\n", i1);
+ return -EINVAL;
+ }
+ if (0 != copy_to_user((void __user *)arg, &v4l2_queryctrl, \
+ sizeof(struct v4l2_queryctrl))) {
+ POUT;
+ return -EFAULT;
+ }
+ break;
+}
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+case VIDIOC_QUERYMENU: {
+ JOT(8, "VIDIOC_QUERYMENU unsupported\n");
+ return -EINVAL;
+ break;
+}
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+case VIDIOC_G_CTRL: {
+ static struct v4l2_control v4l2_control;
+
+ JOT(8, "VIDIOC_G_CTRL\n");
+
+ if (0 != copy_from_user(&v4l2_control, (void __user *)arg, \
+ sizeof(struct v4l2_control))) {
+ POUT;
+ return -EFAULT;
+ }
+
+ switch (v4l2_control.id) {
+ case V4L2_CID_BRIGHTNESS: {
+ v4l2_control.value = peasycap->brightness;
+ JOT(8, "user enquires brightness: %i\n", v4l2_control.value);
+ break;
+ }
+ case V4L2_CID_CONTRAST: {
+ v4l2_control.value = peasycap->contrast;
+ JOT(8, "user enquires contrast: %i\n", v4l2_control.value);
+ break;
+ }
+ case V4L2_CID_SATURATION: {
+ v4l2_control.value = peasycap->saturation;
+ JOT(8, "user enquires saturation: %i\n", v4l2_control.value);
+ break;
+ }
+ case V4L2_CID_HUE: {
+ v4l2_control.value = peasycap->hue;
+ JOT(8, "user enquires hue: %i\n", v4l2_control.value);
+ break;
+ }
+ case V4L2_CID_AUDIO_VOLUME: {
+ v4l2_control.value = peasycap->volume;
+ JOT(8, "user enquires volume: %i\n", v4l2_control.value);
+ break;
+ }
+ case V4L2_CID_AUDIO_MUTE: {
+ if (1 == peasycap->mute)
+ v4l2_control.value = true;
+ else
+ v4l2_control.value = false;
+ JOT(8, "user enquires mute: %i\n", v4l2_control.value);
+ break;
+ }
+ default: {
+ SAY("ERROR: unknown V4L2 control: 0x%08X=id\n", \
+ v4l2_control.id);
+ explain_cid(v4l2_control.id);
+ return -EINVAL;
+ }
+ }
+ if (0 != copy_to_user((void __user *)arg, &v4l2_control, \
+ sizeof(struct v4l2_control))) {
+ POUT;
+ return -EFAULT;
+ }
+ break;
+}
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+#if defined(VIDIOC_S_CTRL_OLD)
+case VIDIOC_S_CTRL_OLD: {
+ JOT(8, "VIDIOC_S_CTRL_OLD required at least for xawtv\n");
+}
+#endif /*VIDIOC_S_CTRL_OLD*/
+case VIDIOC_S_CTRL:
+ {
+ static struct v4l2_control v4l2_control;
+
+ JOT(8, "VIDIOC_S_CTRL\n");
+
+ if (0 != copy_from_user(&v4l2_control, (void __user *)arg, \
+ sizeof(struct v4l2_control))) {
+ POUT;
+ return -EFAULT;
+ }
+
+ switch (v4l2_control.id) {
+ case V4L2_CID_BRIGHTNESS: {
+ JOT(8, "user requests brightness %i\n", v4l2_control.value);
+ if (0 != adjust_brightness(peasycap, v4l2_control.value))
+ ;
+ break;
+ }
+ case V4L2_CID_CONTRAST: {
+ JOT(8, "user requests contrast %i\n", v4l2_control.value);
+ if (0 != adjust_contrast(peasycap, v4l2_control.value))
+ ;
+ break;
+ }
+ case V4L2_CID_SATURATION: {
+ JOT(8, "user requests saturation %i\n", v4l2_control.value);
+ if (0 != adjust_saturation(peasycap, v4l2_control.value))
+ ;
+ break;
+ }
+ case V4L2_CID_HUE: {
+ JOT(8, "user requests hue %i\n", v4l2_control.value);
+ if (0 != adjust_hue(peasycap, v4l2_control.value))
+ ;
+ break;
+ }
+ case V4L2_CID_AUDIO_VOLUME: {
+ JOT(8, "user requests volume %i\n", v4l2_control.value);
+ if (0 != adjust_volume(peasycap, v4l2_control.value))
+ ;
+ break;
+ }
+ case V4L2_CID_AUDIO_MUTE: {
+ int mute;
+
+ JOT(8, "user requests mute %i\n", v4l2_control.value);
+ if (true == v4l2_control.value)
+ mute = 1;
+ else
+ mute = 0;
+
+ if (0 != adjust_mute(peasycap, mute))
+ SAY("WARNING: failed to adjust mute to %i\n", mute);
+ break;
+ }
+ default: {
+ SAY("ERROR: unknown V4L2 control: 0x%08X=id\n", \
+ v4l2_control.id);
+ explain_cid(v4l2_control.id);
+ return -EINVAL;
+ }
+ }
+ break;
+}
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+case VIDIOC_S_EXT_CTRLS: {
+ JOT(8, "VIDIOC_S_EXT_CTRLS unsupported\n");
+ return -EINVAL;
+}
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+case VIDIOC_ENUM_FMT: {
+ static __u32 index;
+ static struct v4l2_fmtdesc v4l2_fmtdesc;
+
+ JOT(8, "VIDIOC_ENUM_FMT\n");
+
+ if (0 != copy_from_user(&v4l2_fmtdesc, (void __user *)arg, \
+ sizeof(struct v4l2_fmtdesc))) {
+ POUT;
+ return -EFAULT;
+ }
+
+ index = v4l2_fmtdesc.index;
+ memset(&v4l2_fmtdesc, 0, sizeof(struct v4l2_fmtdesc));
+
+ v4l2_fmtdesc.index = index;
+ v4l2_fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+ switch (index) {
+ case 0: {
+ v4l2_fmtdesc.flags = 0;
+ strcpy(&v4l2_fmtdesc.description[0], "uyvy");
+ v4l2_fmtdesc.pixelformat = V4L2_PIX_FMT_UYVY;
+ JOT(8, "%i=index: %s\n", index, &v4l2_fmtdesc.description[0]);
+ break;
+ }
+ case 1: {
+ v4l2_fmtdesc.flags = 0;
+ strcpy(&v4l2_fmtdesc.description[0], "yuy2");
+ v4l2_fmtdesc.pixelformat = V4L2_PIX_FMT_YUYV;
+ JOT(8, "%i=index: %s\n", index, &v4l2_fmtdesc.description[0]);
+ break;
+ }
+ case 2: {
+ v4l2_fmtdesc.flags = 0;
+ strcpy(&v4l2_fmtdesc.description[0], "rgb24");
+ v4l2_fmtdesc.pixelformat = V4L2_PIX_FMT_RGB24;
+ JOT(8, "%i=index: %s\n", index, &v4l2_fmtdesc.description[0]);
+ break;
+ }
+ case 3: {
+ v4l2_fmtdesc.flags = 0;
+ strcpy(&v4l2_fmtdesc.description[0], "rgb32");
+ v4l2_fmtdesc.pixelformat = V4L2_PIX_FMT_RGB32;
+ JOT(8, "%i=index: %s\n", index, &v4l2_fmtdesc.description[0]);
+ break;
+ }
+ case 4: {
+ v4l2_fmtdesc.flags = 0;
+ strcpy(&v4l2_fmtdesc.description[0], "bgr24");
+ v4l2_fmtdesc.pixelformat = V4L2_PIX_FMT_BGR24;
+ JOT(8, "%i=index: %s\n", index, &v4l2_fmtdesc.description[0]);
+ break;
+ }
+ case 5: {
+ v4l2_fmtdesc.flags = 0;
+ strcpy(&v4l2_fmtdesc.description[0], "bgr32");
+ v4l2_fmtdesc.pixelformat = V4L2_PIX_FMT_BGR32;
+ JOT(8, "%i=index: %s\n", index, &v4l2_fmtdesc.description[0]);
+ break;
+ }
+ default: {
+ JOT(8, "%i=index: exhausts formats\n", index);
+ return -EINVAL;
+ }
+ }
+ if (0 != copy_to_user((void __user *)arg, &v4l2_fmtdesc, \
+ sizeof(struct v4l2_fmtdesc))) {
+ POUT;
+ return -EFAULT;
+ }
+ break;
+}
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+case VIDIOC_ENUM_FRAMESIZES: {
+ JOT(8, "VIDIOC_ENUM_FRAMESIZES unsupported\n");
+ return -EINVAL;
+}
+case VIDIOC_ENUM_FRAMEINTERVALS: {
+ JOT(8, "VIDIOC_ENUM_FRAME_INTERVALS unsupported\n");
+ return -EINVAL;
+}
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+case VIDIOC_G_FMT: {
+ static struct v4l2_format v4l2_format;
+ static struct v4l2_pix_format v4l2_pix_format;
+
+ JOT(8, "VIDIOC_G_FMT\n");
+
+ if (0 != copy_from_user(&v4l2_format, (void __user *)arg, \
+ sizeof(struct v4l2_format))) {
+ POUT;
+ return -EFAULT;
+ }
+
+ if (v4l2_format.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+ POUT;
+ return -EINVAL;
+ }
+
+ memset(&v4l2_pix_format, 0, sizeof(struct v4l2_pix_format));
+ v4l2_format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ memcpy(&(v4l2_format.fmt.pix), \
+ &(easycap_format[peasycap->format_offset]\
+ .v4l2_format.fmt.pix), sizeof(v4l2_pix_format));
+ JOT(8, "user is told: %s\n", \
+ &easycap_format[peasycap->format_offset].name[0]);
+
+ if (0 != copy_to_user((void __user *)arg, &v4l2_format, \
+ sizeof(struct v4l2_format))) {
+ POUT;
+ return -EFAULT;
+ }
+ break;
+}
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+case VIDIOC_TRY_FMT:
+case VIDIOC_S_FMT: {
+ static struct v4l2_format v4l2_format;
+ static struct v4l2_pix_format v4l2_pix_format;
+ static bool try;
+ static int best_format;
+
+ if (VIDIOC_TRY_FMT == cmd) {
+ JOT(8, "VIDIOC_TRY_FMT\n");
+ try = true;
+ } else {
+ JOT(8, "VIDIOC_S_FMT\n");
+ try = false;
+ }
+
+ if (0 != copy_from_user(&v4l2_format, (void __user *)arg, \
+ sizeof(struct v4l2_format))) {
+ POUT;
+ return -EFAULT;
+ }
+
+ best_format = adjust_format(peasycap, \
+ v4l2_format.fmt.pix.width, \
+ v4l2_format.fmt.pix.height, \
+ v4l2_format.fmt.pix.pixelformat, \
+ v4l2_format.fmt.pix.field, \
+ try);
+ if (0 > best_format) {
+ JOT(8, "WARNING: adjust_format() returned %i\n", best_format);
+ return -ENOENT;
+ }
+/*...........................................................................*/
+ memset(&v4l2_pix_format, 0, sizeof(struct v4l2_pix_format));
+ v4l2_format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+ memcpy(&(v4l2_format.fmt.pix), &(easycap_format[best_format]\
+ .v4l2_format.fmt.pix), sizeof(v4l2_pix_format));
+ JOT(8, "user is told: %s\n", &easycap_format[best_format].name[0]);
+
+ if (0 != copy_to_user((void __user *)arg, &v4l2_format, \
+ sizeof(struct v4l2_format))) {
+ POUT;
+ return -EFAULT;
+ }
+ break;
+}
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+case VIDIOC_CROPCAP: {
+ static struct v4l2_cropcap v4l2_cropcap;
+
+ JOT(8, "VIDIOC_CROPCAP\n");
+
+ if (0 != copy_from_user(&v4l2_cropcap, (void __user *)arg, \
+ sizeof(struct v4l2_cropcap))) {
+ POUT;
+ return -EFAULT;
+ }
+
+ if (v4l2_cropcap.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ JOT(8, "v4l2_cropcap.type != V4L2_BUF_TYPE_VIDEO_CAPTURE\n");
+
+ memset(&v4l2_cropcap, 0, sizeof(struct v4l2_cropcap));
+ v4l2_cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ v4l2_cropcap.bounds.left = 0;
+ v4l2_cropcap.bounds.top = 0;
+ v4l2_cropcap.bounds.width = peasycap->width;
+ v4l2_cropcap.bounds.height = peasycap->height;
+ v4l2_cropcap.defrect.left = 0;
+ v4l2_cropcap.defrect.top = 0;
+ v4l2_cropcap.defrect.width = peasycap->width;
+ v4l2_cropcap.defrect.height = peasycap->height;
+ v4l2_cropcap.pixelaspect.numerator = 1;
+ v4l2_cropcap.pixelaspect.denominator = 1;
+
+ JOT(8, "user is told: %ix%i\n", peasycap->width, peasycap->height);
+
+ if (0 != copy_to_user((void __user *)arg, &v4l2_cropcap, \
+ sizeof(struct v4l2_cropcap))) {
+ POUT;
+ return -EFAULT;
+ }
+ break;
+}
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+case VIDIOC_G_CROP:
+case VIDIOC_S_CROP: {
+ JOT(8, "VIDIOC_G_CROP|VIDIOC_S_CROP unsupported\n");
+ return -EINVAL;
+}
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+case VIDIOC_QUERYSTD: {
+ JOT(8, "VIDIOC_QUERYSTD: " \
+ "EasyCAP is incapable of detecting standard\n");
+ return -EINVAL;
+ break;
+}
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+/*---------------------------------------------------------------------------*/
+/*
+ * THE MANIPULATIONS INVOLVING last0,last1,last2,last3 CONSTITUTE A WORKAROUND
+ * FOR WHAT APPEARS TO BE A BUG IN 64-BIT mplayer.
+ * NOT NEEDED, BUT HOPEFULLY HARMLESS, FOR 32-BIT mplayer.
+ */
+/*---------------------------------------------------------------------------*/
+case VIDIOC_ENUMSTD: {
+ static int last0 = -1, last1 = -1, last2 = -1, last3 = -1;
+ static struct v4l2_standard v4l2_standard;
+ static __u32 index;
+ static struct easycap_standard const *peasycap_standard;
+
+ JOT(8, "VIDIOC_ENUMSTD\n");
+
+ if (0 != copy_from_user(&v4l2_standard, (void __user *)arg, \
+ sizeof(struct v4l2_standard))) {
+ POUT;
+ return -EFAULT;
+ }
+ index = v4l2_standard.index;
+
+ last3 = last2; last2 = last1; last1 = last0; last0 = index;
+ if ((index == last3) && (index == last2) && \
+ (index == last1) && (index == last0)) {
+ index++;
+ last3 = last2; last2 = last1; last1 = last0; last0 = index;
+ }
+
+ memset(&v4l2_standard, 0, sizeof(struct v4l2_standard));
+
+ peasycap_standard = &easycap_standard[0];
+ while (0xFFFF != peasycap_standard->mask) {
+ if ((int)(peasycap_standard - &easycap_standard[0]) == index)
+ break;
+ peasycap_standard++;
+ }
+ if (0xFFFF == peasycap_standard->mask) {
+ JOT(8, "%i=index: exhausts standards\n", index);
+ return -EINVAL;
+ }
+ JOT(8, "%i=index: %s\n", index, \
+ &(peasycap_standard->v4l2_standard.name[0]));
+ memcpy(&v4l2_standard, &(peasycap_standard->v4l2_standard), \
+ sizeof(struct v4l2_standard));
+
+ v4l2_standard.index = index;
+
+ if (0 != copy_to_user((void __user *)arg, &v4l2_standard, \
+ sizeof(struct v4l2_standard))) {
+ POUT;
+ return -EFAULT;
+ }
+ break;
+}
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+case VIDIOC_G_STD: {
+ static v4l2_std_id std_id;
+ static struct easycap_standard const *peasycap_standard;
+
+ JOT(8, "VIDIOC_G_STD\n");
+
+ if (0 != copy_from_user(&std_id, (void __user *)arg, \
+ sizeof(v4l2_std_id))) {
+ POUT;
+ return -EFAULT;
+ }
+
+ peasycap_standard = &easycap_standard[peasycap->standard_offset];
+ std_id = peasycap_standard->v4l2_standard.id;
+
+ JOT(8, "user is told: %s\n", \
+ &peasycap_standard->v4l2_standard.name[0]);
+
+ if (0 != copy_to_user((void __user *)arg, &std_id, \
+ sizeof(v4l2_std_id))) {
+ POUT;
+ return -EFAULT;
+ }
+ break;
+}
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+case VIDIOC_S_STD: {
+ static v4l2_std_id std_id;
+ static int rc;
+
+ JOT(8, "VIDIOC_S_STD\n");
+
+ if (0 != copy_from_user(&std_id, (void __user *)arg, \
+ sizeof(v4l2_std_id))) {
+ POUT;
+ return -EFAULT;
+ }
+
+ rc = adjust_standard(peasycap, std_id);
+ if (0 > rc) {
+ JOT(8, "WARNING: adjust_standard() returned %i\n", rc);
+ return -ENOENT;
+ }
+ break;
+}
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+case VIDIOC_REQBUFS: {
+ static int nbuffers;
+ static struct v4l2_requestbuffers v4l2_requestbuffers;
+
+ JOT(8, "VIDIOC_REQBUFS\n");
+
+ if (0 != copy_from_user(&v4l2_requestbuffers, (void __user *)arg, \
+ sizeof(struct v4l2_requestbuffers))) {
+ POUT;
+ return -EFAULT;
+ }
+
+ if (v4l2_requestbuffers.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+ if (v4l2_requestbuffers.memory != V4L2_MEMORY_MMAP) {
+ POUT;
+ return -EINVAL;
+ }
+ nbuffers = v4l2_requestbuffers.count;
+ JOT(8, " User requests %i buffers ...\n", nbuffers);
+ if (nbuffers < 2)
+ nbuffers = 2;
+ if (nbuffers > FRAME_BUFFER_MANY)
+ nbuffers = FRAME_BUFFER_MANY;
+ if (v4l2_requestbuffers.count == nbuffers) {
+ JOT(8, " ... agree to %i buffers\n", \
+ nbuffers);
+ } else {
+ JOT(8, " ... insist on %i buffers\n", \
+ nbuffers);
+ v4l2_requestbuffers.count = nbuffers;
+ }
+ peasycap->frame_buffer_many = nbuffers;
+
+ if (0 != copy_to_user((void __user *)arg, &v4l2_requestbuffers, \
+ sizeof(struct v4l2_requestbuffers))) {
+ POUT;
+ return -EFAULT;
+ }
+ break;
+}
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+case VIDIOC_QUERYBUF: {
+ static __u32 index;
+ static struct v4l2_buffer v4l2_buffer;
+
+ JOT(8, "VIDIOC_QUERYBUF\n");
+
+ if (peasycap->video_eof) {
+ JOT(8, "returning -1 because %i=video_eof\n", \
+ peasycap->video_eof);
+ return -1;
+ }
+
+ if (0 != copy_from_user(&v4l2_buffer, (void __user *)arg, \
+ sizeof(struct v4l2_buffer))) {
+ POUT;
+ return -EFAULT;
+ }
+
+ if (v4l2_buffer.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+ index = v4l2_buffer.index;
+ if (index < 0 || index >= peasycap->frame_buffer_many)
+ return -EINVAL;
+ memset(&v4l2_buffer, 0, sizeof(struct v4l2_buffer));
+ v4l2_buffer.index = index;
+ v4l2_buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ v4l2_buffer.bytesused = peasycap->frame_buffer_used;
+ v4l2_buffer.flags = V4L2_BUF_FLAG_MAPPED | \
+ peasycap->done[index] | \
+ peasycap->queued[index];
+ v4l2_buffer.field = peasycap->field;
+ v4l2_buffer.memory = V4L2_MEMORY_MMAP;
+ v4l2_buffer.m.offset = index * FRAME_BUFFER_SIZE;
+ v4l2_buffer.length = FRAME_BUFFER_SIZE;
+
+ JOT(16, " %10i=index\n", v4l2_buffer.index);
+ JOT(16, " 0x%08X=type\n", v4l2_buffer.type);
+ JOT(16, " %10i=bytesused\n", v4l2_buffer.bytesused);
+ JOT(16, " 0x%08X=flags\n", v4l2_buffer.flags);
+ JOT(16, " %10i=field\n", v4l2_buffer.field);
+ JOT(16, " %10li=timestamp.tv_usec\n", \
+ (long)v4l2_buffer.timestamp.tv_usec);
+ JOT(16, " %10i=sequence\n", v4l2_buffer.sequence);
+ JOT(16, " 0x%08X=memory\n", v4l2_buffer.memory);
+ JOT(16, " %10i=m.offset\n", v4l2_buffer.m.offset);
+ JOT(16, " %10i=length\n", v4l2_buffer.length);
+
+ if (0 != copy_to_user((void __user *)arg, &v4l2_buffer, \
+ sizeof(struct v4l2_buffer))) {
+ POUT;
+ return -EFAULT;
+ }
+ break;
+}
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+case VIDIOC_QBUF: {
+ static struct v4l2_buffer v4l2_buffer;
+
+ JOT(8, "VIDIOC_QBUF\n");
+
+ if (0 != copy_from_user(&v4l2_buffer, (void __user *)arg, \
+ sizeof(struct v4l2_buffer))) {
+ POUT;
+ return -EFAULT;
+ }
+
+ if (v4l2_buffer.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+ if (v4l2_buffer.memory != V4L2_MEMORY_MMAP)
+ return -EINVAL;
+ if (v4l2_buffer.index < 0 || \
+ (v4l2_buffer.index >= peasycap->frame_buffer_many))
+ return -EINVAL;
+ v4l2_buffer.flags = V4L2_BUF_FLAG_MAPPED | V4L2_BUF_FLAG_QUEUED;
+
+ peasycap->done[v4l2_buffer.index] = 0;
+ peasycap->queued[v4l2_buffer.index] = V4L2_BUF_FLAG_QUEUED;
+
+ if (0 != copy_to_user((void __user *)arg, &v4l2_buffer, \
+ sizeof(struct v4l2_buffer))) {
+ POUT;
+ return -EFAULT;
+ }
+
+ JOT(8, "..... user queueing frame buffer %i\n", \
+ (int)v4l2_buffer.index);
+
+ peasycap->frame_lock = 0;
+
+ break;
+}
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+case VIDIOC_DQBUF:
+ {
+#if defined(AUDIOTIME)
+ static struct signed_div_result sdr;
+ static long long int above, below, dnbydt, fudge, sll;
+ static unsigned long long int ull;
+ static struct timeval timeval0;
+ struct timeval timeval1;
+#endif /*AUDIOTIME*/
+ static struct timeval timeval, timeval2;
+ static int i, j;
+ static struct v4l2_buffer v4l2_buffer;
+
+ JOT(8, "VIDIOC_DQBUF\n");
+
+ if ((peasycap->video_idle) || (peasycap->video_eof)) {
+ JOT(8, "returning -EIO because " \
+ "%i=video_idle %i=video_eof\n", \
+ peasycap->video_idle, peasycap->video_eof);
+ return -EIO;
+ }
+
+ if (0 != copy_from_user(&v4l2_buffer, (void __user *)arg, \
+ sizeof(struct v4l2_buffer))) {
+ POUT;
+ return -EFAULT;
+ }
+
+ if (v4l2_buffer.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ if (!peasycap->video_isoc_streaming) {
+ JOT(16, "returning -EIO because video urbs not streaming\n");
+ return -EIO;
+ }
+/*---------------------------------------------------------------------------*/
+/*
+ * IF THE USER HAS PREVIOUSLY CALLED easycap_poll(), AS DETERMINED BY FINDING
+ * THE FLAG peasycap->polled SET, THERE MUST BE NO FURTHER WAIT HERE. IN THIS
+ * CASE, JUST CHOOSE THE FRAME INDICATED BY peasycap->frame_read
+ */
+/*---------------------------------------------------------------------------*/
+
+ if (!peasycap->polled) {
+ if (-EIO == easycap_dqbuf(peasycap, 0))
+ return -EIO;
+ } else {
+ if (peasycap->video_eof)
+ return -EIO;
+ }
+ if (V4L2_BUF_FLAG_DONE != peasycap->done[peasycap->frame_read]) {
+ SAY("ERROR: V4L2_BUF_FLAG_DONE != 0x%08X\n", \
+ peasycap->done[peasycap->frame_read]);
+ }
+ peasycap->polled = 0;
+
+ if (!(isequence % 10)) {
+ for (i = 0; i < 179; i++)
+ peasycap->merit[i] = peasycap->merit[i+1];
+ peasycap->merit[179] = merit_saa(peasycap->pusb_device);
+ j = 0;
+ for (i = 0; i < 180; i++)
+ j += peasycap->merit[i];
+ if (90 < j) {
+ SAY("easycap driver shutting down " \
+ "on condition blue\n");
+ peasycap->video_eof = 1; peasycap->audio_eof = 1;
+ }
+ }
+
+ v4l2_buffer.index = peasycap->frame_read;
+ v4l2_buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ v4l2_buffer.bytesused = peasycap->frame_buffer_used;
+ v4l2_buffer.flags = V4L2_BUF_FLAG_MAPPED | V4L2_BUF_FLAG_DONE;
+ v4l2_buffer.field = peasycap->field;
+ if (V4L2_FIELD_ALTERNATE == v4l2_buffer.field)
+ v4l2_buffer.field = \
+ 0x000F & (peasycap->\
+ frame_buffer[peasycap->frame_read][0].kount);
+ do_gettimeofday(&timeval);
+ timeval2 = timeval;
+
+#if defined(AUDIOTIME)
+ if (!peasycap->timeval0.tv_sec) {
+ timeval0 = timeval;
+ timeval1 = timeval;
+ timeval2 = timeval;
+ dnbydt = 192000;
+
+ if (mutex_lock_interruptible(&(peasycap->mutex_timeval0)))
+ return -ERESTARTSYS;
+ peasycap->timeval0 = timeval0;
+ mutex_unlock(&(peasycap->mutex_timeval0));
+ } else {
+ if (mutex_lock_interruptible(&(peasycap->mutex_timeval1)))
+ return -ERESTARTSYS;
+ dnbydt = peasycap->dnbydt;
+ timeval1 = peasycap->timeval1;
+ mutex_unlock(&(peasycap->mutex_timeval1));
+ above = dnbydt * MICROSECONDS(timeval, timeval1);
+ below = 192000;
+ sdr = signed_div(above, below);
+
+ above = sdr.quotient + timeval1.tv_usec - 350000;
+
+ below = 1000000;
+ sdr = signed_div(above, below);
+ timeval2.tv_usec = sdr.remainder;
+ timeval2.tv_sec = timeval1.tv_sec + sdr.quotient;
+ }
+ if (!(isequence % 500)) {
+ fudge = ((long long int)(1000000)) * \
+ ((long long int)(timeval.tv_sec - \
+ timeval2.tv_sec)) + \
+ (long long int)(timeval.tv_usec - \
+ timeval2.tv_usec);
+ sdr = signed_div(fudge, 1000);
+ sll = sdr.quotient;
+ ull = sdr.remainder;
+
+ SAY("%5lli.%-3lli=ms timestamp fudge\n", sll, ull);
+ }
+#endif /*AUDIOTIME*/
+
+ v4l2_buffer.timestamp = timeval2;
+ v4l2_buffer.sequence = isequence++;
+ v4l2_buffer.memory = V4L2_MEMORY_MMAP;
+ v4l2_buffer.m.offset = v4l2_buffer.index * FRAME_BUFFER_SIZE;
+ v4l2_buffer.length = FRAME_BUFFER_SIZE;
+
+ JOT(16, " %10i=index\n", v4l2_buffer.index);
+ JOT(16, " 0x%08X=type\n", v4l2_buffer.type);
+ JOT(16, " %10i=bytesused\n", v4l2_buffer.bytesused);
+ JOT(16, " 0x%08X=flags\n", v4l2_buffer.flags);
+ JOT(16, " %10i=field\n", v4l2_buffer.field);
+ JOT(16, " %10li=timestamp.tv_usec\n", \
+ (long)v4l2_buffer.timestamp.tv_usec);
+ JOT(16, " %10i=sequence\n", v4l2_buffer.sequence);
+ JOT(16, " 0x%08X=memory\n", v4l2_buffer.memory);
+ JOT(16, " %10i=m.offset\n", v4l2_buffer.m.offset);
+ JOT(16, " %10i=length\n", v4l2_buffer.length);
+
+ if (0 != copy_to_user((void __user *)arg, &v4l2_buffer, \
+ sizeof(struct v4l2_buffer))) {
+ POUT;
+ return -EFAULT;
+ }
+
+ JOT(8, "..... user is offered frame buffer %i\n", \
+ peasycap->frame_read);
+ peasycap->frame_lock = 1;
+ if (peasycap->frame_read == peasycap->frame_fill) {
+ if (peasycap->frame_lock) {
+ JOT(8, "ERROR: filling frame buffer " \
+ "while offered to user\n");
+ }
+ }
+ break;
+}
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+/*---------------------------------------------------------------------------*/
+/*
+ * AUDIO URBS HAVE ALREADY BEEN SUBMITTED WHEN THIS COMMAND IS RECEIVED;
+ * VIDEO URBS HAVE NOT.
+ */
+/*---------------------------------------------------------------------------*/
+case VIDIOC_STREAMON: {
+ static int i;
+
+ JOT(8, "VIDIOC_STREAMON\n");
+
+ isequence = 0;
+ for (i = 0; i < 180; i++)
+ peasycap->merit[i] = 0;
+ if ((struct usb_device *)NULL == peasycap->pusb_device) {
+ SAY("ERROR: peasycap->pusb_device is NULL\n");
+ return -EFAULT;
+ }
+ submit_video_urbs(peasycap);
+ peasycap->video_idle = 0;
+ peasycap->audio_idle = 0;
+ peasycap->video_eof = 0;
+ peasycap->audio_eof = 0;
+ break;
+}
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+case VIDIOC_STREAMOFF: {
+ JOT(8, "VIDIOC_STREAMOFF\n");
+
+ if ((struct usb_device *)NULL == peasycap->pusb_device) {
+ SAY("ERROR: peasycap->pusb_device is NULL\n");
+ return -EFAULT;
+ }
+
+ peasycap->video_idle = 1;
+ peasycap->audio_idle = 1; peasycap->timeval0.tv_sec = 0;
+/*---------------------------------------------------------------------------*/
+/*
+ * IF THE WAIT QUEUES ARE NOT CLEARED IN RESPONSE TO THE STREAMOFF COMMAND
+ * THE USERSPACE PROGRAM, E.G. mplayer, MAY HANG ON EXIT. BEWARE.
+ */
+/*---------------------------------------------------------------------------*/
+ JOT(8, "calling wake_up on wq_video and wq_audio\n");
+ wake_up_interruptible(&(peasycap->wq_video));
+ wake_up_interruptible(&(peasycap->wq_audio));
+/*---------------------------------------------------------------------------*/
+ break;
+}
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+case VIDIOC_G_PARM: {
+ static struct v4l2_streamparm v4l2_streamparm;
+
+ JOT(8, "VIDIOC_G_PARM\n");
+
+ if (0 != copy_from_user(&v4l2_streamparm, (void __user *)arg, \
+ sizeof(struct v4l2_streamparm))) {
+ POUT;
+ return -EFAULT;
+ }
+
+ if (v4l2_streamparm.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+ POUT;
+ return -EINVAL;
+ }
+ v4l2_streamparm.parm.capture.capability = 0;
+ v4l2_streamparm.parm.capture.capturemode = 0;
+ v4l2_streamparm.parm.capture.timeperframe.numerator = 1;
+ v4l2_streamparm.parm.capture.timeperframe.denominator = 30;
+ v4l2_streamparm.parm.capture.readbuffers = peasycap->frame_buffer_many;
+ v4l2_streamparm.parm.capture.extendedmode = 0;
+ if (0 != copy_to_user((void __user *)arg, &v4l2_streamparm, \
+ sizeof(struct v4l2_streamparm))) {
+ POUT;
+ return -EFAULT;
+ }
+ break;
+}
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+case VIDIOC_S_PARM: {
+ JOT(8, "VIDIOC_S_PARM unsupported\n");
+ return -EINVAL;
+}
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+case VIDIOC_G_AUDIO: {
+ JOT(8, "VIDIOC_G_AUDIO unsupported\n");
+ return -EINVAL;
+}
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+case VIDIOC_S_AUDIO: {
+ JOT(8, "VIDIOC_S_AUDIO unsupported\n");
+ return -EINVAL;
+}
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+case VIDIOC_S_TUNER: {
+ JOT(8, "VIDIOC_S_TUNER unsupported\n");
+ return -EINVAL;
+}
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+case VIDIOC_G_FBUF:
+case VIDIOC_S_FBUF:
+case VIDIOC_OVERLAY: {
+ JOT(8, "VIDIOC_G_FBUF|VIDIOC_S_FBUF|VIDIOC_OVERLAY unsupported\n");
+ return -EINVAL;
+}
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+case VIDIOC_G_TUNER: {
+ JOT(8, "VIDIOC_G_TUNER unsupported\n");
+ return -EINVAL;
+}
+case VIDIOC_G_FREQUENCY:
+case VIDIOC_S_FREQUENCY: {
+ JOT(8, "VIDIOC_G_FREQUENCY|VIDIOC_S_FREQUENCY unsupported\n");
+ return -EINVAL;
+}
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+default: {
+ JOT(8, "ERROR: unrecognized V4L2 IOCTL command: 0x%08X\n", cmd);
+ explain_ioctl(cmd);
+ POUT;
+ return -ENOIOCTLCMD;
+}
+}
+return 0;
+}
+/****************************************************************************/
+/*vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/
+#if defined(EASYCAP_IS_VIDEODEV_CLIENT)
+long
+easysnd_ioctl_noinode(struct file *file, unsigned int cmd, unsigned long arg)
+{
+ return easysnd_ioctl((struct inode *)NULL, file, cmd, arg);
+}
+#endif /*EASYCAP_IS_VIDEODEV_CLIENT*/
+/*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
+/*--------------------------------------------------------------------------*/
+int easysnd_ioctl(struct inode *inode, struct file *file, \
+ unsigned int cmd, unsigned long arg)
+{
+struct easycap *peasycap;
+struct usb_device *p;
+
+peasycap = file->private_data;
+if (NULL == peasycap) {
+ SAY("ERROR: peasycap is NULL.\n");
+ return -1;
+}
+p = peasycap->pusb_device;
+/*---------------------------------------------------------------------------*/
+switch (cmd) {
+case SNDCTL_DSP_GETCAPS: {
+ int caps;
+ JOT(8, "SNDCTL_DSP_GETCAPS\n");
+
+#if defined(UPSAMPLE)
+ if (true == peasycap->microphone)
+ caps = 0x04400000;
+ else
+ caps = 0x04400000;
+#else
+ if (true == peasycap->microphone)
+ caps = 0x02400000;
+ else
+ caps = 0x04400000;
+#endif /*UPSAMPLE*/
+
+ if (0 != copy_to_user((void __user *)arg, &caps, sizeof(int)))
+ return -EFAULT;
+ break;
+}
+case SNDCTL_DSP_GETFMTS: {
+ int incoming;
+ JOT(8, "SNDCTL_DSP_GETFMTS\n");
+
+#if defined(UPSAMPLE)
+ if (true == peasycap->microphone)
+ incoming = AFMT_S16_LE;
+ else
+ incoming = AFMT_S16_LE;
+#else
+ if (true == peasycap->microphone)
+ incoming = AFMT_S16_LE;
+ else
+ incoming = AFMT_S16_LE;
+#endif /*UPSAMPLE*/
+
+ if (0 != copy_to_user((void __user *)arg, &incoming, sizeof(int)))
+ return -EFAULT;
+ break;
+}
+case SNDCTL_DSP_SETFMT: {
+ int incoming, outgoing;
+ JOT(8, "SNDCTL_DSP_SETFMT\n");
+ if (0 != copy_from_user(&incoming, (void __user *)arg, sizeof(int)))
+ return -EFAULT;
+ JOT(8, "........... %i=incoming\n", incoming);
+
+#if defined(UPSAMPLE)
+ if (true == peasycap->microphone)
+ outgoing = AFMT_S16_LE;
+ else
+ outgoing = AFMT_S16_LE;
+#else
+ if (true == peasycap->microphone)
+ outgoing = AFMT_S16_LE;
+ else
+ outgoing = AFMT_S16_LE;
+#endif /*UPSAMPLE*/
+
+ if (incoming != outgoing) {
+ JOT(8, "........... %i=outgoing\n", outgoing);
+ JOT(8, " cf. %i=AFMT_S16_LE\n", AFMT_S16_LE);
+ JOT(8, " cf. %i=AFMT_U8\n", AFMT_U8);
+ if (0 != copy_to_user((void __user *)arg, &outgoing, \
+ sizeof(int)))
+ return -EFAULT;
+ return -EINVAL ;
+ }
+ break;
+}
+case SNDCTL_DSP_STEREO: {
+ int incoming;
+ JOT(8, "SNDCTL_DSP_STEREO\n");
+ if (0 != copy_from_user(&incoming, (void __user *)arg, sizeof(int)))
+ return -EFAULT;
+ JOT(8, "........... %i=incoming\n", incoming);
+
+#if defined(UPSAMPLE)
+ if (true == peasycap->microphone)
+ incoming = 1;
+ else
+ incoming = 1;
+#else
+ if (true == peasycap->microphone)
+ incoming = 0;
+ else
+ incoming = 1;
+#endif /*UPSAMPLE*/
+
+ if (0 != copy_to_user((void __user *)arg, &incoming, sizeof(int)))
+ return -EFAULT;
+ break;
+}
+case SNDCTL_DSP_SPEED: {
+ int incoming;
+ JOT(8, "SNDCTL_DSP_SPEED\n");
+ if (0 != copy_from_user(&incoming, (void __user *)arg, sizeof(int)))
+ return -EFAULT;
+ JOT(8, "........... %i=incoming\n", incoming);
+
+#if defined(UPSAMPLE)
+ if (true == peasycap->microphone)
+ incoming = 32000;
+ else
+ incoming = 48000;
+#else
+ if (true == peasycap->microphone)
+ incoming = 8000;
+ else
+ incoming = 48000;
+#endif /*UPSAMPLE*/
+
+ if (0 != copy_to_user((void __user *)arg, &incoming, sizeof(int)))
+ return -EFAULT;
+ break;
+}
+case SNDCTL_DSP_GETTRIGGER: {
+ int incoming;
+ JOT(8, "SNDCTL_DSP_GETTRIGGER\n");
+ if (0 != copy_from_user(&incoming, (void __user *)arg, sizeof(int)))
+ return -EFAULT;
+ JOT(8, "........... %i=incoming\n", incoming);
+
+ incoming = PCM_ENABLE_INPUT;
+ if (0 != copy_to_user((void __user *)arg, &incoming, sizeof(int)))
+ return -EFAULT;
+ break;
+}
+case SNDCTL_DSP_SETTRIGGER: {
+ int incoming;
+ JOT(8, "SNDCTL_DSP_SETTRIGGER\n");
+ if (0 != copy_from_user(&incoming, (void __user *)arg, sizeof(int)))
+ return -EFAULT;
+ JOT(8, "........... %i=incoming\n", incoming);
+ JOT(8, "........... cf 0x%x=PCM_ENABLE_INPUT " \
+ "0x%x=PCM_ENABLE_OUTPUT\n", \
+ PCM_ENABLE_INPUT, PCM_ENABLE_OUTPUT);
+ ;
+ ;
+ ;
+ ;
+ break;
+}
+case SNDCTL_DSP_GETBLKSIZE: {
+ int incoming;
+ JOT(8, "SNDCTL_DSP_GETBLKSIZE\n");
+ if (0 != copy_from_user(&incoming, (void __user *)arg, sizeof(int)))
+ return -EFAULT;
+ JOT(8, "........... %i=incoming\n", incoming);
+ incoming = peasycap->audio_bytes_per_fragment;
+ if (0 != copy_to_user((void __user *)arg, &incoming, sizeof(int)))
+ return -EFAULT;
+ break;
+}
+case SNDCTL_DSP_GETISPACE: {
+ struct audio_buf_info audio_buf_info;
+
+ JOT(8, "SNDCTL_DSP_GETISPACE\n");
+
+ audio_buf_info.bytes = peasycap->audio_bytes_per_fragment;
+ audio_buf_info.fragments = 1;
+ audio_buf_info.fragsize = 0;
+ audio_buf_info.fragstotal = 0;
+
+ if (0 != copy_to_user((void __user *)arg, &audio_buf_info, \
+ sizeof(int)))
+ return -EFAULT;
+ break;
+}
+default: {
+ JOT(8, "ERROR: unrecognized DSP IOCTL command: 0x%08X\n", cmd);
+ POUT;
+ return -ENOIOCTLCMD;
+}
+}
+return 0;
+}
+/*****************************************************************************/
+int explain_ioctl(__u32 wot)
+{
+int k;
+/*---------------------------------------------------------------------------*/
+/*
+ * THE DATA FOR THE ARRAY mess BELOW WERE CONSTRUCTED BY RUNNING THE FOLLOWING
+ * SHELL SCRIPT:
+ * #
+ * cat /usr/src/linux-headers-`uname -r`/include/linux/videodev2.h | \
+ * grep "^#define VIDIOC_" - | grep -v "_OLD" - | \
+ * sed -e "s,_IO.*$,,;p" | sed -e "N;s,\n,, " | \
+ * sed -e "s/^#define / {/;s/#define /, \"/;s/$/\"},/" | \
+ * sed -e "s, ,,g;s, ,,g" >ioctl.tmp
+ * echo "{0xFFFFFFFF,\"\"}" >>ioctl.tmp
+ * exit 0
+ * #
+ * AND REINSTATING THE EXCISED "_OLD" CASES WERE LATER MANUALLY.
+ *
+ * THE DATA FOR THE ARRAY mess1 BELOW WERE CONSTRUCTED BY RUNNING THE FOLLOWING
+ * SHELL SCRIPT:
+ * cat /usr/src/linux-headers-`uname -r`/include/linux/videodev.h | \
+ * grep "^#define VIDIOC" - | grep -v "_OLD" - | \
+ * sed -e "s,_IO.*$,,;p" | sed -e "N;s,\n,, " | \
+ * sed -e "s/^#define / {/;s/#define /, \"/;s/$/\"},/" | \
+ * sed -e "s, ,,g;s, ,,g" >ioctl.tmp
+ * echo "{0xFFFFFFFF,\"\"}" >>ioctl.tmp
+ * exit 0
+ * #
+ */
+/*---------------------------------------------------------------------------*/
+static struct mess {
+ __u32 command;
+ char name[64];
+} mess[] = {
+#if defined(VIDIOC_QUERYCAP)
+{VIDIOC_QUERYCAP, "VIDIOC_QUERYCAP"},
+#endif
+#if defined(VIDIOC_RESERVED)
+{VIDIOC_RESERVED, "VIDIOC_RESERVED"},
+#endif
+#if defined(VIDIOC_ENUM_FMT)
+{VIDIOC_ENUM_FMT, "VIDIOC_ENUM_FMT"},
+#endif
+#if defined(VIDIOC_G_FMT)
+{VIDIOC_G_FMT, "VIDIOC_G_FMT"},
+#endif
+#if defined(VIDIOC_S_FMT)
+{VIDIOC_S_FMT, "VIDIOC_S_FMT"},
+#endif
+#if defined(VIDIOC_REQBUFS)
+{VIDIOC_REQBUFS, "VIDIOC_REQBUFS"},
+#endif
+#if defined(VIDIOC_QUERYBUF)
+{VIDIOC_QUERYBUF, "VIDIOC_QUERYBUF"},
+#endif
+#if defined(VIDIOC_G_FBUF)
+{VIDIOC_G_FBUF, "VIDIOC_G_FBUF"},
+#endif
+#if defined(VIDIOC_S_FBUF)
+{VIDIOC_S_FBUF, "VIDIOC_S_FBUF"},
+#endif
+#if defined(VIDIOC_OVERLAY)
+{VIDIOC_OVERLAY, "VIDIOC_OVERLAY"},
+#endif
+#if defined(VIDIOC_QBUF)
+{VIDIOC_QBUF, "VIDIOC_QBUF"},
+#endif
+#if defined(VIDIOC_DQBUF)
+{VIDIOC_DQBUF, "VIDIOC_DQBUF"},
+#endif
+#if defined(VIDIOC_STREAMON)
+{VIDIOC_STREAMON, "VIDIOC_STREAMON"},
+#endif
+#if defined(VIDIOC_STREAMOFF)
+{VIDIOC_STREAMOFF, "VIDIOC_STREAMOFF"},
+#endif
+#if defined(VIDIOC_G_PARM)
+{VIDIOC_G_PARM, "VIDIOC_G_PARM"},
+#endif
+#if defined(VIDIOC_S_PARM)
+{VIDIOC_S_PARM, "VIDIOC_S_PARM"},
+#endif
+#if defined(VIDIOC_G_STD)
+{VIDIOC_G_STD, "VIDIOC_G_STD"},
+#endif
+#if defined(VIDIOC_S_STD)
+{VIDIOC_S_STD, "VIDIOC_S_STD"},
+#endif
+#if defined(VIDIOC_ENUMSTD)
+{VIDIOC_ENUMSTD, "VIDIOC_ENUMSTD"},
+#endif
+#if defined(VIDIOC_ENUMINPUT)
+{VIDIOC_ENUMINPUT, "VIDIOC_ENUMINPUT"},
+#endif
+#if defined(VIDIOC_G_CTRL)
+{VIDIOC_G_CTRL, "VIDIOC_G_CTRL"},
+#endif
+#if defined(VIDIOC_S_CTRL)
+{VIDIOC_S_CTRL, "VIDIOC_S_CTRL"},
+#endif
+#if defined(VIDIOC_G_TUNER)
+{VIDIOC_G_TUNER, "VIDIOC_G_TUNER"},
+#endif
+#if defined(VIDIOC_S_TUNER)
+{VIDIOC_S_TUNER, "VIDIOC_S_TUNER"},
+#endif
+#if defined(VIDIOC_G_AUDIO)
+{VIDIOC_G_AUDIO, "VIDIOC_G_AUDIO"},
+#endif
+#if defined(VIDIOC_S_AUDIO)
+{VIDIOC_S_AUDIO, "VIDIOC_S_AUDIO"},
+#endif
+#if defined(VIDIOC_QUERYCTRL)
+{VIDIOC_QUERYCTRL, "VIDIOC_QUERYCTRL"},
+#endif
+#if defined(VIDIOC_QUERYMENU)
+{VIDIOC_QUERYMENU, "VIDIOC_QUERYMENU"},
+#endif
+#if defined(VIDIOC_G_INPUT)
+{VIDIOC_G_INPUT, "VIDIOC_G_INPUT"},
+#endif
+#if defined(VIDIOC_S_INPUT)
+{VIDIOC_S_INPUT, "VIDIOC_S_INPUT"},
+#endif
+#if defined(VIDIOC_G_OUTPUT)
+{VIDIOC_G_OUTPUT, "VIDIOC_G_OUTPUT"},
+#endif
+#if defined(VIDIOC_S_OUTPUT)
+{VIDIOC_S_OUTPUT, "VIDIOC_S_OUTPUT"},
+#endif
+#if defined(VIDIOC_ENUMOUTPUT)
+{VIDIOC_ENUMOUTPUT, "VIDIOC_ENUMOUTPUT"},
+#endif
+#if defined(VIDIOC_G_AUDOUT)
+{VIDIOC_G_AUDOUT, "VIDIOC_G_AUDOUT"},
+#endif
+#if defined(VIDIOC_S_AUDOUT)
+{VIDIOC_S_AUDOUT, "VIDIOC_S_AUDOUT"},
+#endif
+#if defined(VIDIOC_G_MODULATOR)
+{VIDIOC_G_MODULATOR, "VIDIOC_G_MODULATOR"},
+#endif
+#if defined(VIDIOC_S_MODULATOR)
+{VIDIOC_S_MODULATOR, "VIDIOC_S_MODULATOR"},
+#endif
+#if defined(VIDIOC_G_FREQUENCY)
+{VIDIOC_G_FREQUENCY, "VIDIOC_G_FREQUENCY"},
+#endif
+#if defined(VIDIOC_S_FREQUENCY)
+{VIDIOC_S_FREQUENCY, "VIDIOC_S_FREQUENCY"},
+#endif
+#if defined(VIDIOC_CROPCAP)
+{VIDIOC_CROPCAP, "VIDIOC_CROPCAP"},
+#endif
+#if defined(VIDIOC_G_CROP)
+{VIDIOC_G_CROP, "VIDIOC_G_CROP"},
+#endif
+#if defined(VIDIOC_S_CROP)
+{VIDIOC_S_CROP, "VIDIOC_S_CROP"},
+#endif
+#if defined(VIDIOC_G_JPEGCOMP)
+{VIDIOC_G_JPEGCOMP, "VIDIOC_G_JPEGCOMP"},
+#endif
+#if defined(VIDIOC_S_JPEGCOMP)
+{VIDIOC_S_JPEGCOMP, "VIDIOC_S_JPEGCOMP"},
+#endif
+#if defined(VIDIOC_QUERYSTD)
+{VIDIOC_QUERYSTD, "VIDIOC_QUERYSTD"},
+#endif
+#if defined(VIDIOC_TRY_FMT)
+{VIDIOC_TRY_FMT, "VIDIOC_TRY_FMT"},
+#endif
+#if defined(VIDIOC_ENUMAUDIO)
+{VIDIOC_ENUMAUDIO, "VIDIOC_ENUMAUDIO"},
+#endif
+#if defined(VIDIOC_ENUMAUDOUT)
+{VIDIOC_ENUMAUDOUT, "VIDIOC_ENUMAUDOUT"},
+#endif
+#if defined(VIDIOC_G_PRIORITY)
+{VIDIOC_G_PRIORITY, "VIDIOC_G_PRIORITY"},
+#endif
+#if defined(VIDIOC_S_PRIORITY)
+{VIDIOC_S_PRIORITY, "VIDIOC_S_PRIORITY"},
+#endif
+#if defined(VIDIOC_G_SLICED_VBI_CAP)
+{VIDIOC_G_SLICED_VBI_CAP, "VIDIOC_G_SLICED_VBI_CAP"},
+#endif
+#if defined(VIDIOC_LOG_STATUS)
+{VIDIOC_LOG_STATUS, "VIDIOC_LOG_STATUS"},
+#endif
+#if defined(VIDIOC_G_EXT_CTRLS)
+{VIDIOC_G_EXT_CTRLS, "VIDIOC_G_EXT_CTRLS"},
+#endif
+#if defined(VIDIOC_S_EXT_CTRLS)
+{VIDIOC_S_EXT_CTRLS, "VIDIOC_S_EXT_CTRLS"},
+#endif
+#if defined(VIDIOC_TRY_EXT_CTRLS)
+{VIDIOC_TRY_EXT_CTRLS, "VIDIOC_TRY_EXT_CTRLS"},
+#endif
+#if defined(VIDIOC_ENUM_FRAMESIZES)
+{VIDIOC_ENUM_FRAMESIZES, "VIDIOC_ENUM_FRAMESIZES"},
+#endif
+#if defined(VIDIOC_ENUM_FRAMEINTERVALS)
+{VIDIOC_ENUM_FRAMEINTERVALS, "VIDIOC_ENUM_FRAMEINTERVALS"},
+#endif
+#if defined(VIDIOC_G_ENC_INDEX)
+{VIDIOC_G_ENC_INDEX, "VIDIOC_G_ENC_INDEX"},
+#endif
+#if defined(VIDIOC_ENCODER_CMD)
+{VIDIOC_ENCODER_CMD, "VIDIOC_ENCODER_CMD"},
+#endif
+#if defined(VIDIOC_TRY_ENCODER_CMD)
+{VIDIOC_TRY_ENCODER_CMD, "VIDIOC_TRY_ENCODER_CMD"},
+#endif
+#if defined(VIDIOC_G_CHIP_IDENT)
+{VIDIOC_G_CHIP_IDENT, "VIDIOC_G_CHIP_IDENT"},
+#endif
+
+#if defined(VIDIOC_OVERLAY_OLD)
+{VIDIOC_OVERLAY_OLD, "VIDIOC_OVERLAY_OLD"},
+#endif
+#if defined(VIDIOC_S_PARM_OLD)
+{VIDIOC_S_PARM_OLD, "VIDIOC_S_PARM_OLD"},
+#endif
+#if defined(VIDIOC_S_CTRL_OLD)
+{VIDIOC_S_CTRL_OLD, "VIDIOC_S_CTRL_OLD"},
+#endif
+#if defined(VIDIOC_G_AUDIO_OLD)
+{VIDIOC_G_AUDIO_OLD, "VIDIOC_G_AUDIO_OLD"},
+#endif
+#if defined(VIDIOC_G_AUDOUT_OLD)
+{VIDIOC_G_AUDOUT_OLD, "VIDIOC_G_AUDOUT_OLD"},
+#endif
+#if defined(VIDIOC_CROPCAP_OLD)
+{VIDIOC_CROPCAP_OLD, "VIDIOC_CROPCAP_OLD"},
+#endif
+{0xFFFFFFFF, ""}
+};
+
+static struct mess mess1[] = \
+{
+#if defined(VIDIOCGCAP)
+{VIDIOCGCAP, "VIDIOCGCAP"},
+#endif
+#if defined(VIDIOCGCHAN)
+{VIDIOCGCHAN, "VIDIOCGCHAN"},
+#endif
+#if defined(VIDIOCSCHAN)
+{VIDIOCSCHAN, "VIDIOCSCHAN"},
+#endif
+#if defined(VIDIOCGTUNER)
+{VIDIOCGTUNER, "VIDIOCGTUNER"},
+#endif
+#if defined(VIDIOCSTUNER)
+{VIDIOCSTUNER, "VIDIOCSTUNER"},
+#endif
+#if defined(VIDIOCGPICT)
+{VIDIOCGPICT, "VIDIOCGPICT"},
+#endif
+#if defined(VIDIOCSPICT)
+{VIDIOCSPICT, "VIDIOCSPICT"},
+#endif
+#if defined(VIDIOCCAPTURE)
+{VIDIOCCAPTURE, "VIDIOCCAPTURE"},
+#endif
+#if defined(VIDIOCGWIN)
+{VIDIOCGWIN, "VIDIOCGWIN"},
+#endif
+#if defined(VIDIOCSWIN)
+{VIDIOCSWIN, "VIDIOCSWIN"},
+#endif
+#if defined(VIDIOCGFBUF)
+{VIDIOCGFBUF, "VIDIOCGFBUF"},
+#endif
+#if defined(VIDIOCSFBUF)
+{VIDIOCSFBUF, "VIDIOCSFBUF"},
+#endif
+#if defined(VIDIOCKEY)
+{VIDIOCKEY, "VIDIOCKEY"},
+#endif
+#if defined(VIDIOCGFREQ)
+{VIDIOCGFREQ, "VIDIOCGFREQ"},
+#endif
+#if defined(VIDIOCSFREQ)
+{VIDIOCSFREQ, "VIDIOCSFREQ"},
+#endif
+#if defined(VIDIOCGAUDIO)
+{VIDIOCGAUDIO, "VIDIOCGAUDIO"},
+#endif
+#if defined(VIDIOCSAUDIO)
+{VIDIOCSAUDIO, "VIDIOCSAUDIO"},
+#endif
+#if defined(VIDIOCSYNC)
+{VIDIOCSYNC, "VIDIOCSYNC"},
+#endif
+#if defined(VIDIOCMCAPTURE)
+{VIDIOCMCAPTURE, "VIDIOCMCAPTURE"},
+#endif
+#if defined(VIDIOCGMBUF)
+{VIDIOCGMBUF, "VIDIOCGMBUF"},
+#endif
+#if defined(VIDIOCGUNIT)
+{VIDIOCGUNIT, "VIDIOCGUNIT"},
+#endif
+#if defined(VIDIOCGCAPTURE)
+{VIDIOCGCAPTURE, "VIDIOCGCAPTURE"},
+#endif
+#if defined(VIDIOCSCAPTURE)
+{VIDIOCSCAPTURE, "VIDIOCSCAPTURE"},
+#endif
+#if defined(VIDIOCSPLAYMODE)
+{VIDIOCSPLAYMODE, "VIDIOCSPLAYMODE"},
+#endif
+#if defined(VIDIOCSWRITEMODE)
+{VIDIOCSWRITEMODE, "VIDIOCSWRITEMODE"},
+#endif
+#if defined(VIDIOCGPLAYINFO)
+{VIDIOCGPLAYINFO, "VIDIOCGPLAYINFO"},
+#endif
+#if defined(VIDIOCSMICROCODE)
+{VIDIOCSMICROCODE, "VIDIOCSMICROCODE"},
+#endif
+{0xFFFFFFFF, ""}
+};
+
+k = 0;
+while (mess[k].name[0]) {
+ if (wot == mess[k].command) {
+ JOT(8, "ioctl 0x%08X is %s\n", \
+ mess[k].command, &mess[k].name[0]);
+ return 0;
+ }
+ k++;
+}
+JOT(8, "ioctl 0x%08X is not in videodev2.h\n", wot);
+
+k = 0;
+while (mess1[k].name[0]) {
+ if (wot == mess1[k].command) {
+ JOT(8, "ioctl 0x%08X is %s (V4L1)\n", \
+ mess1[k].command, &mess1[k].name[0]);
+ return 0;
+ }
+ k++;
+}
+JOT(8, "ioctl 0x%08X is not in videodev.h\n", wot);
+return -1;
+}
+/*****************************************************************************/
+int explain_cid(__u32 wot)
+{
+int k;
+/*---------------------------------------------------------------------------*/
+/*
+ * THE DATA FOR THE ARRAY mess BELOW WERE CONSTRUCTED BY RUNNING THE FOLLOWING
+ * SHELL SCRIPT:
+ * #
+ * cat /usr/src/linux-headers-`uname -r`/include/linux/videodev2.h | \
+ * grep "^#define V4L2_CID_" | \
+ * sed -e "s,(.*$,,;p" | sed -e "N;s,\n,, " | \
+ * sed -e "s/^#define / {/;s/#define /, \"/;s/$/\"},/" | \
+ * sed -e "s, ,,g;s, ,,g" | grep -v "_BASE" | grep -v "MPEG" >cid.tmp
+ * echo "{0xFFFFFFFF,\"\"}" >>cid.tmp
+ * exit 0
+ * #
+ */
+/*---------------------------------------------------------------------------*/
+static struct mess
+{
+__u32 command;
+char name[64];
+} mess[] = {
+#if defined(V4L2_CID_USER_CLASS)
+{V4L2_CID_USER_CLASS, "V4L2_CID_USER_CLASS"},
+#endif
+#if defined(V4L2_CID_BRIGHTNESS)
+{V4L2_CID_BRIGHTNESS, "V4L2_CID_BRIGHTNESS"},
+#endif
+#if defined(V4L2_CID_CONTRAST)
+{V4L2_CID_CONTRAST, "V4L2_CID_CONTRAST"},
+#endif
+#if defined(V4L2_CID_SATURATION)
+{V4L2_CID_SATURATION, "V4L2_CID_SATURATION"},
+#endif
+#if defined(V4L2_CID_HUE)
+{V4L2_CID_HUE, "V4L2_CID_HUE"},
+#endif
+#if defined(V4L2_CID_AUDIO_VOLUME)
+{V4L2_CID_AUDIO_VOLUME, "V4L2_CID_AUDIO_VOLUME"},
+#endif
+#if defined(V4L2_CID_AUDIO_BALANCE)
+{V4L2_CID_AUDIO_BALANCE, "V4L2_CID_AUDIO_BALANCE"},
+#endif
+#if defined(V4L2_CID_AUDIO_BASS)
+{V4L2_CID_AUDIO_BASS, "V4L2_CID_AUDIO_BASS"},
+#endif
+#if defined(V4L2_CID_AUDIO_TREBLE)
+{V4L2_CID_AUDIO_TREBLE, "V4L2_CID_AUDIO_TREBLE"},
+#endif
+#if defined(V4L2_CID_AUDIO_MUTE)
+{V4L2_CID_AUDIO_MUTE, "V4L2_CID_AUDIO_MUTE"},
+#endif
+#if defined(V4L2_CID_AUDIO_LOUDNESS)
+{V4L2_CID_AUDIO_LOUDNESS, "V4L2_CID_AUDIO_LOUDNESS"},
+#endif
+#if defined(V4L2_CID_BLACK_LEVEL)
+{V4L2_CID_BLACK_LEVEL, "V4L2_CID_BLACK_LEVEL"},
+#endif
+#if defined(V4L2_CID_AUTO_WHITE_BALANCE)
+{V4L2_CID_AUTO_WHITE_BALANCE, "V4L2_CID_AUTO_WHITE_BALANCE"},
+#endif
+#if defined(V4L2_CID_DO_WHITE_BALANCE)
+{V4L2_CID_DO_WHITE_BALANCE, "V4L2_CID_DO_WHITE_BALANCE"},
+#endif
+#if defined(V4L2_CID_RED_BALANCE)
+{V4L2_CID_RED_BALANCE, "V4L2_CID_RED_BALANCE"},
+#endif
+#if defined(V4L2_CID_BLUE_BALANCE)
+{V4L2_CID_BLUE_BALANCE, "V4L2_CID_BLUE_BALANCE"},
+#endif
+#if defined(V4L2_CID_GAMMA)
+{V4L2_CID_GAMMA, "V4L2_CID_GAMMA"},
+#endif
+#if defined(V4L2_CID_WHITENESS)
+{V4L2_CID_WHITENESS, "V4L2_CID_WHITENESS"},
+#endif
+#if defined(V4L2_CID_EXPOSURE)
+{V4L2_CID_EXPOSURE, "V4L2_CID_EXPOSURE"},
+#endif
+#if defined(V4L2_CID_AUTOGAIN)
+{V4L2_CID_AUTOGAIN, "V4L2_CID_AUTOGAIN"},
+#endif
+#if defined(V4L2_CID_GAIN)
+{V4L2_CID_GAIN, "V4L2_CID_GAIN"},
+#endif
+#if defined(V4L2_CID_HFLIP)
+{V4L2_CID_HFLIP, "V4L2_CID_HFLIP"},
+#endif
+#if defined(V4L2_CID_VFLIP)
+{V4L2_CID_VFLIP, "V4L2_CID_VFLIP"},
+#endif
+#if defined(V4L2_CID_HCENTER)
+{V4L2_CID_HCENTER, "V4L2_CID_HCENTER"},
+#endif
+#if defined(V4L2_CID_VCENTER)
+{V4L2_CID_VCENTER, "V4L2_CID_VCENTER"},
+#endif
+#if defined(V4L2_CID_POWER_LINE_FREQUENCY)
+{V4L2_CID_POWER_LINE_FREQUENCY, "V4L2_CID_POWER_LINE_FREQUENCY"},
+#endif
+#if defined(V4L2_CID_HUE_AUTO)
+{V4L2_CID_HUE_AUTO, "V4L2_CID_HUE_AUTO"},
+#endif
+#if defined(V4L2_CID_WHITE_BALANCE_TEMPERATURE)
+{V4L2_CID_WHITE_BALANCE_TEMPERATURE, "V4L2_CID_WHITE_BALANCE_TEMPERATURE"},
+#endif
+#if defined(V4L2_CID_SHARPNESS)
+{V4L2_CID_SHARPNESS, "V4L2_CID_SHARPNESS"},
+#endif
+#if defined(V4L2_CID_BACKLIGHT_COMPENSATION)
+{V4L2_CID_BACKLIGHT_COMPENSATION, "V4L2_CID_BACKLIGHT_COMPENSATION"},
+#endif
+#if defined(V4L2_CID_CHROMA_AGC)
+{V4L2_CID_CHROMA_AGC, "V4L2_CID_CHROMA_AGC"},
+#endif
+#if defined(V4L2_CID_COLOR_KILLER)
+{V4L2_CID_COLOR_KILLER, "V4L2_CID_COLOR_KILLER"},
+#endif
+#if defined(V4L2_CID_LASTP1)
+{V4L2_CID_LASTP1, "V4L2_CID_LASTP1"},
+#endif
+#if defined(V4L2_CID_CAMERA_CLASS)
+{V4L2_CID_CAMERA_CLASS, "V4L2_CID_CAMERA_CLASS"},
+#endif
+#if defined(V4L2_CID_EXPOSURE_AUTO)
+{V4L2_CID_EXPOSURE_AUTO, "V4L2_CID_EXPOSURE_AUTO"},
+#endif
+#if defined(V4L2_CID_EXPOSURE_ABSOLUTE)
+{V4L2_CID_EXPOSURE_ABSOLUTE, "V4L2_CID_EXPOSURE_ABSOLUTE"},
+#endif
+#if defined(V4L2_CID_EXPOSURE_AUTO_PRIORITY)
+{V4L2_CID_EXPOSURE_AUTO_PRIORITY, "V4L2_CID_EXPOSURE_AUTO_PRIORITY"},
+#endif
+#if defined(V4L2_CID_PAN_RELATIVE)
+{V4L2_CID_PAN_RELATIVE, "V4L2_CID_PAN_RELATIVE"},
+#endif
+#if defined(V4L2_CID_TILT_RELATIVE)
+{V4L2_CID_TILT_RELATIVE, "V4L2_CID_TILT_RELATIVE"},
+#endif
+#if defined(V4L2_CID_PAN_RESET)
+{V4L2_CID_PAN_RESET, "V4L2_CID_PAN_RESET"},
+#endif
+#if defined(V4L2_CID_TILT_RESET)
+{V4L2_CID_TILT_RESET, "V4L2_CID_TILT_RESET"},
+#endif
+#if defined(V4L2_CID_PAN_ABSOLUTE)
+{V4L2_CID_PAN_ABSOLUTE, "V4L2_CID_PAN_ABSOLUTE"},
+#endif
+#if defined(V4L2_CID_TILT_ABSOLUTE)
+{V4L2_CID_TILT_ABSOLUTE, "V4L2_CID_TILT_ABSOLUTE"},
+#endif
+#if defined(V4L2_CID_FOCUS_ABSOLUTE)
+{V4L2_CID_FOCUS_ABSOLUTE, "V4L2_CID_FOCUS_ABSOLUTE"},
+#endif
+#if defined(V4L2_CID_FOCUS_RELATIVE)
+{V4L2_CID_FOCUS_RELATIVE, "V4L2_CID_FOCUS_RELATIVE"},
+#endif
+#if defined(V4L2_CID_FOCUS_AUTO)
+{V4L2_CID_FOCUS_AUTO, "V4L2_CID_FOCUS_AUTO"},
+#endif
+{0xFFFFFFFF, ""}
+};
+
+k = 0;
+while (mess[k].name[0]) {
+ if (wot == mess[k].command) {
+ JOT(8, "ioctl 0x%08X is %s\n", \
+ mess[k].command, &mess[k].name[0]);
+ return 0;
+ }
+ k++;
+}
+JOT(8, "cid 0x%08X is not in videodev2.h\n", wot);
+return -1;
+}
+/*****************************************************************************/
diff --git a/drivers/staging/easycap/easycap_ioctl.h b/drivers/staging/easycap/easycap_ioctl.h
new file mode 100644
index 00000000000..210cd627235
--- /dev/null
+++ b/drivers/staging/easycap/easycap_ioctl.h
@@ -0,0 +1,28 @@
+/*****************************************************************************
+* *
+* easycap_ioctl.h *
+* *
+*****************************************************************************/
+/*
+ *
+ * Copyright (C) 2010 R.M. Thomas <rmthomas@sciolus.org>
+ *
+ *
+ * This is free software; you can redistribute it and/or modify
+ * 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 software 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 software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+*/
+/*****************************************************************************/
+extern struct easycap_format easycap_format[];
+extern struct v4l2_queryctrl easycap_control[];
diff --git a/drivers/staging/easycap/easycap_low.c b/drivers/staging/easycap/easycap_low.c
new file mode 100644
index 00000000000..ad1fc4cc471
--- /dev/null
+++ b/drivers/staging/easycap/easycap_low.c
@@ -0,0 +1,1041 @@
+/*****************************************************************************
+* *
+* *
+* easycap_low.c *
+* *
+* *
+*****************************************************************************/
+/*
+ *
+ * Copyright (C) 2010 R.M. Thomas <rmthomas@sciolus.org>
+ *
+ *
+ * This is free software; you can redistribute it and/or modify
+ * 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 software 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 software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+*/
+/*****************************************************************************/
+/*
+ * ACKNOWLEGEMENTS AND REFERENCES
+ * ------------------------------
+ * This driver makes use of register information contained in the Syntek
+ * Semicon DC-1125 driver hosted at
+ * http://sourceforge.net/projects/syntekdriver/.
+ * Particularly useful has been a patch to the latter driver provided by
+ * Ivor Hewitt in January 2009. The NTSC implementation is taken from the
+ * work of Ben Trask.
+*/
+/****************************************************************************/
+
+#include "easycap_debug.h"
+#include "easycap.h"
+
+/*--------------------------------------------------------------------------*/
+const struct stk1160config { int reg; int set; } stk1160config[256] = {
+ {0x000, 0x0098},
+ {0x002, 0x0093},
+
+ {0x001, 0x0003},
+ {0x003, 0x0080},
+ {0x00D, 0x0000},
+ {0x00F, 0x0002},
+ {0x018, 0x0010},
+ {0x019, 0x0000},
+ {0x01A, 0x0014},
+ {0x01B, 0x000E},
+ {0x01C, 0x0046},
+
+ {0x100, 0x0033},
+ {0x103, 0x0000},
+ {0x104, 0x0000},
+ {0x105, 0x0000},
+ {0x106, 0x0000},
+
+#if defined(PREFER_NTSC)
+
+#undef OLDMARGIN
+#if defined(OLDMARGIN)
+ {0x110, 0x0008},
+#else
+ {0x110, 0x0014},
+#endif /*OLDMARGIN*/
+
+ {0x111, 0x0000},
+ {0x112, 0x0003},
+ {0x113, 0x0000},
+
+#if defined(OLDMARGIN)
+ {0x114, 0x0508},
+#else
+ {0x114, 0x0514},
+#endif /*OLDMARGIN*/
+
+ {0x115, 0x0005},
+ {0x116, 0x00F3},
+ {0x117, 0x0000},
+
+#else /* ! PREFER_NTSC*/
+
+#if defined(OLDMARGIN)
+ {0x110, 0x0008},
+#else
+ {0x110, 0x0014},
+#endif /*OLDMARGIN*/
+
+ {0x111, 0x0000},
+ {0x112, 0x0020},
+ {0x113, 0x0000},
+
+#if defined(OLDMARGIN)
+ {0x114, 0x0508},
+#else
+ {0x114, 0x0514},
+#endif /*OLDMARGIN*/
+
+ {0x115, 0x0005},
+ {0x116, 0x0110},
+ {0x117, 0x0001},
+
+#endif /* ! PREFER_NTSC*/
+
+ {0x202, 0x000F},
+ {0x203, 0x004A},
+ {0x2FF, 0x0000},
+/*---------------------------------------------------------------------------*/
+ {0xFFF, 0xFFFF}
+ };
+/*--------------------------------------------------------------------------*/
+const struct saa7113config { int reg; int set; } saa7113config[256] = {
+ {0x01, 0x08},
+ {0x02, 0x80},
+ {0x03, 0x33},
+ {0x04, 0x00},
+ {0x05, 0x00},
+ {0x06, 0xE9},
+ {0x07, 0x0D},
+#if defined(PREFER_NTSC)
+ {0x08, 0x78},
+#else
+ {0x08, 0x38},
+#endif /* ! PREFER_NTSC*/
+ {0x09, 0x00},
+ {0x0A, SAA_0A_DEFAULT},
+ {0x0B, SAA_0B_DEFAULT},
+ {0x0C, SAA_0C_DEFAULT},
+ {0x0D, SAA_0D_DEFAULT},
+ {0x0E, 0x01},
+ {0x0F, 0x36},
+ {0x10, 0x00},
+ {0x11, 0x0C},
+ {0x12, 0xE7},
+ {0x13, 0x00},
+ {0x15, 0x00},
+ {0x16, 0x00},
+#if defined(PREFER_NTSC)
+ {0x40, 0x82},
+#else
+ {0x40, 0x02},
+#endif /* ! PREFER_NTSC*/
+ {0x41, 0xFF},
+ {0x42, 0xFF},
+ {0x43, 0xFF},
+ {0x44, 0xFF},
+ {0x45, 0xFF},
+ {0x46, 0xFF},
+ {0x47, 0xFF},
+ {0x48, 0xFF},
+ {0x49, 0xFF},
+ {0x4A, 0xFF},
+ {0x4B, 0xFF},
+ {0x4C, 0xFF},
+ {0x4D, 0xFF},
+ {0x4E, 0xFF},
+ {0x4F, 0xFF},
+ {0x50, 0xFF},
+ {0x51, 0xFF},
+ {0x52, 0xFF},
+ {0x53, 0xFF},
+ {0x54, 0xFF},
+ {0x55, 0xFF},
+ {0x56, 0xFF},
+ {0x57, 0xFF},
+ {0x58, 0x40},
+ {0x59, 0x54},
+#if defined(PREFER_NTSC)
+ {0x5A, 0x0A},
+#else
+ {0x5A, 0x07},
+#endif /* ! PREFER_NTSC*/
+ {0x5B, 0x83},
+ {0xFF, 0xFF}
+ };
+/*--------------------------------------------------------------------------*/
+
+/****************************************************************************/
+int
+confirm_resolution(struct usb_device *p)
+{
+__u8 get0, get1, get2, get3, get4, get5, get6, get7;
+GET(p, 0x0110, &get0);
+GET(p, 0x0111, &get1);
+GET(p, 0x0112, &get2);
+GET(p, 0x0113, &get3);
+GET(p, 0x0114, &get4);
+GET(p, 0x0115, &get5);
+GET(p, 0x0116, &get6);
+GET(p, 0x0117, &get7);
+JOT(8, "0x%03X, 0x%03X, " \
+ "0x%03X, 0x%03X, " \
+ "0x%03X, 0x%03X, " \
+ "0x%03X, 0x%03X\n", \
+ get0, get1, get2, get3, get4, get5, get6, get7);
+JOT(8, "....cf PAL_720x526: " \
+ "0x%03X, 0x%03X, " \
+ "0x%03X, 0x%03X, " \
+ "0x%03X, 0x%03X, " \
+ "0x%03X, 0x%03X\n", \
+ 0x000, 0x000, 0x001, 0x000, 0x5A0, 0x005, 0x121, 0x001);
+JOT(8, "....cf PAL_704x526: " \
+ "0x%03X, 0x%03X, " \
+ "0x%03X, 0x%03X, " \
+ "0x%03X, 0x%03X, " \
+ "0x%03X, 0x%03X\n", \
+ 0x004, 0x000, 0x001, 0x000, 0x584, 0x005, 0x121, 0x001);
+JOT(8, "....cf VGA_640x480: " \
+ "0x%03X, 0x%03X, " \
+ "0x%03X, 0x%03X, " \
+ "0x%03X, 0x%03X, " \
+ "0x%03X, 0x%03X\n", \
+ 0x008, 0x000, 0x020, 0x000, 0x508, 0x005, 0x110, 0x001);
+return 0;
+}
+/****************************************************************************/
+int
+confirm_stream(struct usb_device *p)
+{
+__u16 get2;
+__u8 igot;
+
+GET(p, 0x0100, &igot); get2 = 0x80 & igot;
+if (0x80 == get2)
+ JOT(8, "confirm_stream: OK\n");
+else
+ JOT(8, "confirm_stream: STUCK\n");
+return 0;
+}
+/****************************************************************************/
+int
+setup_stk(struct usb_device *p)
+{
+int i0;
+
+i0 = 0;
+while (0xFFF != stk1160config[i0].reg) {
+ SET(p, stk1160config[i0].reg, stk1160config[i0].set);
+ i0++;
+ }
+
+write_300(p);
+
+return 0;
+}
+/****************************************************************************/
+int
+setup_saa(struct usb_device *p)
+{
+int i0, ir;
+
+
+set2to78(p);
+
+
+i0 = 0;
+while (0xFF != saa7113config[i0].reg) {
+ ir = write_saa(p, saa7113config[i0].reg, saa7113config[i0].set);
+ i0++;
+ }
+return 0;
+}
+/****************************************************************************/
+int
+write_000(struct usb_device *p, __u16 set2, __u16 set0)
+{
+__u8 igot0, igot2;
+
+GET(p, 0x0002, &igot2);
+GET(p, 0x0000, &igot0);
+SET(p, 0x0002, set2);
+SET(p, 0x0000, set0);
+return 0;
+}
+/****************************************************************************/
+int
+write_saa(struct usb_device *p, __u16 reg0, __u16 set0)
+{
+SET(p, 0x200, 0x00);
+SET(p, 0x204, reg0);
+SET(p, 0x205, set0);
+SET(p, 0x200, 0x01);
+return wait_i2c(p);
+}
+/****************************************************************************/
+/*--------------------------------------------------------------------------*/
+/*
+ * REGISTER 500: SETTING VALUE TO 0x008B READS FROM VT1612A (?)
+ * REGISTER 500: SETTING VALUE TO 0x008C WRITES TO VT1612A
+ * REGISTER 502: LEAST SIGNIFICANT BYTE OF VALUE TO SET
+ * REGISTER 503: MOST SIGNIFICANT BYTE OF VALUE TO SET
+ * REGISTER 504: TARGET ADDRESS ON VT1612A
+ */
+/*--------------------------------------------------------------------------*/
+int
+write_vt(struct usb_device *p, __u16 reg0, __u16 set0)
+{
+__u8 igot;
+__u16 got502, got503;
+__u16 set502, set503;
+
+SET(p, 0x0504, reg0);
+SET(p, 0x0500, 0x008B);
+
+GET(p, 0x0502, &igot); got502 = (0xFF & igot);
+GET(p, 0x0503, &igot); got503 = (0xFF & igot);
+
+JOT(16, "write_vt(., 0x%04X, 0x%04X): was 0x%04X\n", \
+ reg0, set0, ((got503 << 8) | got502));
+
+set502 = (0x00FF & set0);
+set503 = ((0xFF00 & set0) >> 8);
+
+SET(p, 0x0504, reg0);
+SET(p, 0x0502, set502);
+SET(p, 0x0503, set503);
+SET(p, 0x0500, 0x008C);
+
+return 0;
+}
+/****************************************************************************/
+/*--------------------------------------------------------------------------*/
+/*
+ * REGISTER 500: SETTING VALUE TO 0x008B READS FROM VT1612A (?)
+ * REGISTER 500: SETTING VALUE TO 0x008C WRITES TO VT1612A
+ * REGISTER 502: LEAST SIGNIFICANT BYTE OF VALUE TO GET
+ * REGISTER 503: MOST SIGNIFICANT BYTE OF VALUE TO GET
+ * REGISTER 504: TARGET ADDRESS ON VT1612A
+ */
+/*--------------------------------------------------------------------------*/
+int
+read_vt(struct usb_device *p, __u16 reg0)
+{
+__u8 igot;
+__u16 got502, got503;
+
+SET(p, 0x0504, reg0);
+SET(p, 0x0500, 0x008B);
+
+GET(p, 0x0502, &igot); got502 = (0xFF & igot);
+GET(p, 0x0503, &igot); got503 = (0xFF & igot);
+
+JOT(16, "read_vt(., 0x%04X): has 0x%04X\n", reg0, ((got503 << 8) | got502));
+
+return (got503 << 8) | got502;
+}
+/****************************************************************************/
+/*--------------------------------------------------------------------------*/
+/*
+ * THESE APPEAR TO HAVE NO EFFECT ON EITHER VIDEO OR AUDIO.
+ */
+/*--------------------------------------------------------------------------*/
+int
+write_300(struct usb_device *p)
+{
+SET(p, 0x300, 0x0012);
+SET(p, 0x350, 0x002D);
+SET(p, 0x351, 0x0001);
+SET(p, 0x352, 0x0000);
+SET(p, 0x353, 0x0000);
+SET(p, 0x300, 0x0080);
+return 0;
+}
+/****************************************************************************/
+/*--------------------------------------------------------------------------*/
+/*
+ * NOTE: THE FOLLOWING IS NOT CHECKED:
+ * REGISTER 0x0F, WHICH IS INVOLVED IN CHROMINANCE AUTOMATIC GAIN CONTROL.
+ */
+/*--------------------------------------------------------------------------*/
+int
+check_saa(struct usb_device *p)
+{
+int i0, ir, rc;
+i0 = 0;
+
+rc = 0;
+while (0xFF != saa7113config[i0].reg) {
+ if (0x0F == saa7113config[i0].reg) {
+ i0++; continue;
+ }
+
+ ir = read_saa(p, saa7113config[i0].reg);
+ if (ir != saa7113config[i0].set) {
+ SAY("SAA register 0x%02X has 0x%02X, expected 0x%02X\n", \
+ saa7113config[i0].reg, ir, saa7113config[i0].set);
+ rc--;
+ }
+ i0++;
+}
+if (-8 > rc)
+ return rc;
+else
+ return 0;
+}
+/****************************************************************************/
+int
+merit_saa(struct usb_device *p)
+{
+int rc;
+
+rc = read_saa(p, 0x1F);
+if ((0 > rc) || (0x02 & rc))
+ return 1 ;
+else
+ return 0;
+}
+/****************************************************************************/
+int
+ready_saa(struct usb_device *p)
+{
+int j, rc;
+static int max = 10;
+
+j = 0;
+while (max > j) {
+ rc = read_saa(p, 0x1F);
+ if (0 <= rc) {
+ if ((1 == (0x01 & rc))&&(0 == (0x40 & rc)))
+ break;
+ }
+ msleep(100); j++;
+}
+if (max == j)
+ return -1;
+else {
+ if (0x20 & rc)
+ JOT(8, "hardware detects 60 Hz\n");
+ else
+ JOT(8, "hardware detects 50 Hz\n");
+ if (0x80 & rc)
+ JOT(8, "hardware detects interlacing\n");
+ else
+ JOT(8, "hardware detects no interlacing\n");
+}
+return 0;
+}
+/****************************************************************************/
+/*--------------------------------------------------------------------------*/
+/*
+ * NOTE: THE FOLLOWING ARE NOT CHECKED:
+ * REGISTERS 0x000, 0x002: FUNCTIONALITY IS NOT KNOWN
+ * REGISTER 0x100: ACCEPT ALSO (0x80 | stk1160config[.].set)
+ */
+/*--------------------------------------------------------------------------*/
+int
+check_stk(struct usb_device *p)
+{
+int i0, ir;
+i0 = 0;
+while (0xFFF != stk1160config[i0].reg) {
+ if (0x000 == stk1160config[i0].reg) {
+ i0++; continue;
+ }
+ if (0x002 == stk1160config[i0].reg) {
+ i0++; continue;
+ }
+
+ ir = read_stk(p, stk1160config[i0].reg);
+
+ if (0x100 == stk1160config[i0].reg) {
+ if ((ir != (0xFF & stk1160config[i0].set)) && \
+ (ir != (0x80 | (0xFF & stk1160config[i0].set))) && \
+ (0xFFFF != stk1160config[i0].set)) {
+ SAY("STK register 0x%03X has 0x%02X, " \
+ "expected 0x%02X\n", \
+ stk1160config[i0].reg, ir, \
+ stk1160config[i0].set);
+ }
+ i0++; continue;
+ }
+
+ if ((ir != (0xFF & stk1160config[i0].set)) && \
+ (0xFFFF != stk1160config[i0].set)) {
+ SAY("STK register 0x%03X has 0x%02X, " \
+ "expected 0x%02X\n", \
+ stk1160config[i0].reg, ir, \
+ stk1160config[i0].set);
+ }
+ i0++;
+ }
+return 0;
+}
+/****************************************************************************/
+int
+read_saa(struct usb_device *p, __u16 reg0)
+{
+__u8 igot;
+
+SET(p, 0x208, reg0);
+SET(p, 0x200, 0x20);
+if (0 != wait_i2c(p))
+ return -1;
+igot = 0;
+GET(p, 0x0209, &igot);
+return igot;
+}
+/****************************************************************************/
+int
+read_stk(struct usb_device *p, __u32 reg0)
+{
+__u8 igot;
+
+igot = 0;
+GET(p, reg0, &igot);
+return igot;
+}
+/*****************************************************************************/
+/*---------------------------------------------------------------------------*/
+/*
+ * HARDWARE USERSPACE INPUT NUMBER PHYSICAL INPUT DRIVER input VALUE
+ *
+ * CVBS+S-VIDEO 0 or 1 CVBS 1
+ * FOUR-CVBS 0 or 1 CVBS1 1
+ * FOUR-CVBS 2 CVBS2 2
+ * FOUR-CVBS 3 CVBS3 3
+ * FOUR-CVBS 4 CVBS4 4
+ * CVBS+S-VIDEO 5 S-VIDEO 5
+ *
+ * WHEN 5==input THE ARGUMENT mode MUST ALSO BE SUPPLIED:
+ *
+ * mode 7 => GAIN TO BE SET EXPLICITLY USING REGISTER 0x05 (UNTESTED)
+ * mode 9 => USE AUTOMATIC GAIN CONTROL (DEFAULT)
+ *
+*/
+/*---------------------------------------------------------------------------*/
+int
+select_input(struct usb_device *p, int input, int mode)
+{
+
+stop_100(p);
+
+msleep(20);
+switch (input) {
+case 0:
+case 1: {
+ SET(p, 0x0000, 0x0098); break;
+}
+case 2: {
+ SET(p, 0x0000, 0x0090); break;
+}
+case 3: {
+ SET(p, 0x0000, 0x0088); break;
+}
+case 4: {
+ SET(p, 0x0000, 0x0080); break;
+}
+case 5: {
+ if (9 != mode)
+ mode = 7;
+ switch (mode) {
+ case 7:
+ {
+ if (0 != write_saa(p, 0x02, 0x87)) {
+ SAY("ERROR: failed to set SAA " \
+ "register 0x02 for input " \
+ "%i\n", input);
+ }
+ if (0 != write_saa(p, 0x05, 0xFF)) {
+ SAY("ERROR: failed to set SAA " \
+ "register 0x05 for input " \
+ "%i\n", input);
+ }
+ break;
+ }
+ case 9:
+ {
+ if (0 != write_saa(p, 0x02, 0x89)) {
+ SAY("ERROR: failed to set SAA " \
+ "register 0x02 for input " \
+ "%i\n", input);
+ }
+ if (0 != write_saa(p, 0x05, 0x00)) {
+ SAY("ERROR: failed to set SAA " \
+ "register 0x05 for input " \
+ "%i\n", input);
+ }
+ break;
+ }
+ default:
+ {
+ SAY("MISTAKE: bad mode: %i\n", mode);
+ return -1;
+ }
+ }
+ if (0 != write_saa(p, 0x04, 0x00)) {
+ SAY("ERROR: failed to set SAA register 0x04 " \
+ "for input %i\n", input);
+ }
+ if (0 != write_saa(p, 0x09, 0x80)) {
+ SAY("ERROR: failed to set SAA register 0x09 " \
+ "for input %i\n", input);
+ }
+ break;
+}
+default:
+ {
+ SAY("ERROR: bad input: %i\n", input);
+ return -1;
+}
+}
+msleep(20);
+SET(p, 0x0002, 0x0093);
+msleep(20);
+
+start_100(p);
+
+return 0;
+}
+/****************************************************************************/
+int
+set_resolution(struct usb_device *p, \
+ __u16 set0, __u16 set1, __u16 set2, __u16 set3)
+{
+__u16 u0x0111, u0x0113, u0x0115, u0x0117;
+
+u0x0111 = ((0xFF00 & set0) >> 8);
+u0x0113 = ((0xFF00 & set1) >> 8);
+u0x0115 = ((0xFF00 & set2) >> 8);
+u0x0117 = ((0xFF00 & set3) >> 8);
+
+SET(p, 0x0110, (0x00FF & set0));
+SET(p, 0x0111, u0x0111);
+SET(p, 0x0112, (0x00FF & set1));
+SET(p, 0x0113, u0x0113);
+SET(p, 0x0114, (0x00FF & set2));
+SET(p, 0x0115, u0x0115);
+SET(p, 0x0116, (0x00FF & set3));
+SET(p, 0x0117, u0x0117);
+
+return 0;
+}
+/****************************************************************************/
+int
+start_100(struct usb_device *p)
+{
+__u16 get0;
+__u8 igot;
+
+GET(p, 0x0100, &igot); get0 = igot;
+msleep(0x1f4);
+SET(p, 0x0100, (0x80 | get0));
+msleep(0x1f4);
+return 0;
+}
+/****************************************************************************/
+int
+stop_100(struct usb_device *p)
+{
+__u16 get0;
+__u8 igot;
+
+GET(p, 0x0100, &igot); get0 = igot;
+msleep(0x1f4);
+SET(p, 0x0100, (0x7F & get0));
+msleep(0x1f4);
+return 0;
+}
+/****************************************************************************/
+/*--------------------------------------------------------------------------*/
+/*
+ * FUNCTION wait_i2c() RETURNS 0 ON SUCCESS
+*/
+/*--------------------------------------------------------------------------*/
+int
+wait_i2c(struct usb_device *p)
+{
+__u16 get0;
+__u8 igot;
+const int max = 4;
+int k;
+
+for (k = 0; k < max; k++) {
+ GET(p, 0x0201, &igot); get0 = igot;
+ switch (get0) {
+ case 0x04:
+ case 0x01: {
+ return 0;
+ }
+ case 0x00: {
+ msleep(10);
+ continue;
+ }
+ default: {
+ return get0 - 1;
+ }
+ }
+}
+return -1;
+}
+/****************************************************************************/
+int
+regset(struct usb_device *pusb_device, __u16 index, __u16 value)
+{
+__u16 igot;
+int rc0, rc1;
+
+if (!pusb_device)
+ return -EFAULT;
+
+rc1 = 0; igot = 0;
+rc0 = usb_control_msg(pusb_device, usb_sndctrlpipe(pusb_device, 0), \
+ (__u8)0x01, \
+ (__u8)(USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE), \
+ (__u16)value, \
+ (__u16)index, \
+ (void *)NULL, \
+ (__u16)0, \
+ (int)500);
+
+#if defined(NOREADBACK)
+#
+#else
+rc1 = usb_control_msg(pusb_device, usb_rcvctrlpipe(pusb_device, 0), \
+ (__u8)0x00, \
+ (__u8)(USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE), \
+ (__u16)0x00, \
+ (__u16)index, \
+ (void *)&igot, \
+ (__u16)sizeof(__u16), \
+ (int)50000);
+igot = 0xFF & igot;
+switch (index) {
+case 0x000:
+case 0x500:
+case 0x502:
+case 0x503:
+case 0x504:
+case 0x506:
+case 0x507: {
+ break;
+}
+case 0x204:
+case 0x205:
+case 0x350:
+case 0x351: {
+ if (0 != igot) {
+ JOT(8, "unexpected 0x%02X for STK register 0x%03X\n", \
+ igot, index);
+ }
+break;
+}
+case 0x114:
+case 0x116: {
+ if ((0xFF & value) != igot) {
+ JOT(8, "unexpected 0x%02X != 0x%02X " \
+ "for STK register 0x%03X\n", \
+ igot, value, index);
+ }
+break;
+}
+case 0x200: {
+ if (0 == igot)
+ break;
+}
+default: {
+ if (value != igot) {
+ JOT(8, "unexpected 0x%02X != 0x%02X " \
+ "for STK register 0x%03X\n", \
+ igot, value, index);
+ }
+break;
+}
+}
+#endif /* ! NOREADBACK*/
+
+return (0 > rc0) ? rc0 : rc1;
+}
+/*****************************************************************************/
+int
+regget(struct usb_device *pusb_device, __u16 index, void *pvoid)
+{
+int ir;
+
+if (!pusb_device)
+ return -EFAULT;
+
+ir = usb_control_msg(pusb_device, usb_rcvctrlpipe(pusb_device, 0), \
+ (__u8)0x00, \
+ (__u8)(USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE), \
+ (__u16)0x00, \
+ (__u16)index, \
+ (void *)pvoid, \
+ sizeof(__u8), \
+ (int)50000);
+return 0xFF & ir;
+}
+/*****************************************************************************/
+int
+wakeup_device(struct usb_device *pusb_device)
+{
+return usb_control_msg(pusb_device, usb_sndctrlpipe(pusb_device, 0), \
+ (__u8)USB_REQ_SET_FEATURE, \
+ (__u8)(USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE), \
+ USB_DEVICE_REMOTE_WAKEUP, \
+ (__u16)0, \
+ (void *) NULL, \
+ (__u16)0, \
+ (int)50000);
+}
+/*****************************************************************************/
+/*---------------------------------------------------------------------------*/
+/*
+ * IMPORTANT:
+ * THE MESSAGE OF TYPE (USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE)
+ * CAUSES MUTING IF THE VALUE 0x0100 IS SENT.
+ * TO ENABLE AUDIO THE VALUE 0x0200 MUST BE SENT.
+ */
+/*---------------------------------------------------------------------------*/
+int
+audio_setup(struct easycap *peasycap)
+{
+struct usb_device *pusb_device;
+static __u8 request = 0x01;
+static __u8 requesttype = \
+ (__u8)(USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE);
+
+static __u16 value_unmute = 0x0200;
+static __u16 index = 0x0301;
+
+static unsigned char buffer[1];
+static __u16 length = 1;
+int rc, id1, id2;
+
+if (NULL == peasycap)
+ return -EFAULT;
+
+pusb_device = peasycap->pusb_device;
+if (NULL == pusb_device)
+ return -EFAULT;
+
+JOT(8, "%02X %02X %02X %02X %02X %02X %02X %02X\n", \
+ requesttype, request, \
+ (0x00FF & value_unmute), \
+ (0xFF00 & value_unmute) >> 8, \
+ (0x00FF & index), \
+ (0xFF00 & index) >> 8, \
+ (0x00FF & length), \
+ (0xFF00 & length) >> 8);
+
+buffer[0] = 0x01;
+
+rc = usb_control_msg(pusb_device, usb_sndctrlpipe(pusb_device, 0), \
+ (__u8)request, \
+ (__u8)requesttype, \
+ (__u16)value_unmute, \
+ (__u16)index, \
+ (void *)&buffer[0], \
+ (__u16)length, \
+ (int)50000);
+
+JOT(8, "0x%02X=buffer\n", *((__u8 *) &buffer[0]));
+if (rc != (int)length)
+ SAY("ERROR: usb_control_msg returned %i\n", rc);
+
+/*--------------------------------------------------------------------------*/
+/*
+ * REGISTER 500: SETTING VALUE TO 0x0094 RESETS AUDIO CONFIGURATION ???
+ * REGISTER 506: ANALOGUE AUDIO ATTENTUATOR ???
+ * FOR THE CVBS+S-VIDEO HARDWARE:
+ * SETTING VALUE TO 0x0000 GIVES QUIET SOUND.
+ * THE UPPER BYTE SEEMS TO HAVE NO EFFECT.
+ * FOR THE FOUR-CVBS HARDWARE:
+ * SETTING VALUE TO 0x0000 SEEMS TO HAVE NO EFFECT.
+ * REGISTER 507: ANALOGUE AUDIO PREAMPLIFIER ON/OFF ???
+ * FOR THE CVBS-S-VIDEO HARDWARE:
+ * SETTING VALUE TO 0x0001 GIVES VERY LOUD, DISTORTED SOUND.
+ * THE UPPER BYTE SEEMS TO HAVE NO EFFECT.
+ */
+/*--------------------------------------------------------------------------*/
+
+SET(pusb_device, 0x0500, 0x0094);
+
+SET(pusb_device, 0x0500, 0x008C);
+
+SET(pusb_device, 0x0506, 0x0001);
+SET(pusb_device, 0x0507, 0x0000);
+
+id1 = read_vt(pusb_device, 0x007C);
+id2 = read_vt(pusb_device, 0x007E);
+SAY("0x%04X:0x%04X is audio vendor id\n", id1, id2);
+
+/*---------------------------------------------------------------------------*/
+/*
+* SELECT AUDIO SOURCE "LINE IN" AND SET DEFAULT GAIN TO 0 dB.
+*
+* THESE COMMANDS SEEM TO BE ACCEPTED (THOUGH POSSIBLY IGNORED) EVEN WHEN
+* THERE IS NO SEPARATE AUDIO CHIP PRESENT.
+*/
+/*---------------------------------------------------------------------------*/
+
+write_vt(pusb_device, 0x0002, 0x8000);
+write_vt(pusb_device, 0x001C, 0x8000);
+
+write_vt(pusb_device, 0x000E, 0x0000);
+write_vt(pusb_device, 0x0010, 0x0000);
+write_vt(pusb_device, 0x0012, 0x8000);
+write_vt(pusb_device, 0x0016, 0x0000);
+
+write_vt(pusb_device, 0x001A, 0x0404);
+write_vt(pusb_device, 0x0002, 0x0000);
+write_vt(pusb_device, 0x001C, 0x0000);
+
+check_vt(pusb_device);
+
+return 0;
+}
+/*****************************************************************************/
+int
+check_vt(struct usb_device *pusb_device)
+{
+int igot;
+
+igot = read_vt(pusb_device, 0x0002);
+if (0 > igot)
+ SAY("ERROR: failed to read VT1612A register 0x02\n");
+if (0x8000 & igot)
+ SAY("register 0x%02X muted\n", 0x02);
+
+igot = read_vt(pusb_device, 0x000E);
+if (0 > igot)
+ SAY("ERROR: failed to read VT1612A register 0x0E\n");
+if (0x8000 & igot)
+ SAY("register 0x%02X muted\n", 0x0E);
+
+igot = read_vt(pusb_device, 0x0010);
+if (0 > igot)
+ SAY("ERROR: failed to read VT1612A register 0x10\n");
+if (0x8000 & igot)
+ SAY("register 0x%02X muted\n", 0x10);
+
+igot = read_vt(pusb_device, 0x0012);
+if (0 > igot)
+ SAY("ERROR: failed to read VT1612A register 0x12\n");
+if (0x8000 & igot)
+ SAY("register 0x%02X muted\n", 0x12);
+
+igot = read_vt(pusb_device, 0x0016);
+if (0 > igot)
+ SAY("ERROR: failed to read VT1612A register 0x16\n");
+if (0x8000 & igot)
+ SAY("register 0x%02X muted\n", 0x16);
+
+igot = read_vt(pusb_device, 0x001A);
+if (0 > igot)
+ SAY("ERROR: failed to read VT1612A register 0x1A\n");
+if (0x8000 & igot)
+ SAY("register 0x%02X muted\n", 0x1A);
+
+igot = read_vt(pusb_device, 0x001C);
+if (0 > igot)
+ SAY("ERROR: failed to read VT1612A register 0x1C\n");
+if (0x8000 & igot)
+ SAY("register 0x%02X muted\n", 0x1C);
+
+return 0;
+}
+/*****************************************************************************/
+/*---------------------------------------------------------------------------*/
+/*
+ * NOTE: THIS DOES INCREASE THE VOLUME DRAMATICALLY:
+ * audio_gainset(pusb_device, 0x000F);
+ *
+ * IF 16<loud<31 VT1621A REGISTER 0x1C IS SET FOR POSITIVE GAIN.
+ * IF loud<=16 VT1621A REGISTER 0x1C IS SET FOR ZERO GAIN.
+ * THERE IS NEVER ANY (ADDITIONAL) ATTENUATION.
+ */
+/*---------------------------------------------------------------------------*/
+int
+audio_gainset(struct usb_device *pusb_device, __s8 loud)
+{
+int igot;
+__u8 u8;
+__u16 mute;
+
+if (16 > loud)
+ loud = 16;
+u8 = 0x000F & (__u8)(loud - 16);
+
+write_vt(pusb_device, 0x0002, 0x8000);
+
+igot = read_vt(pusb_device, 0x001C);
+if (0 > igot) {
+ SAY("ERROR: failed to read VT1612A register 0x1C\n");
+ mute = 0x0000;
+} else
+ mute = 0x8000 & ((unsigned int)igot);
+
+JOT(8, "0x%04X=(mute|u8|(u8<<8))\n", mute | u8 | (u8 << 8));
+
+write_vt(pusb_device, 0x001C, 0x8000);
+write_vt(pusb_device, 0x001C, (mute | u8 | (u8 << 8)));
+write_vt(pusb_device, 0x0002, 0x0000);
+
+return 0;
+}
+/*****************************************************************************/
+int
+audio_gainget(struct usb_device *pusb_device)
+{
+int igot;
+
+igot = read_vt(pusb_device, 0x001C);
+if (0 > igot)
+ SAY("ERROR: failed to read VT1612A register 0x1C\n");
+return igot;
+}
+/*****************************************************************************/
+int
+set2to78(struct usb_device *p)
+{
+int ir;
+
+msleep(20);
+ir = regset(p, 0x0002, 0x0078);
+if (0 > ir)
+ SAY("ERROR: failed to set register 0x0002 to 0x0078\n");
+msleep(20);
+return ir;
+}
+/*****************************************************************************/
+int
+set2to93(struct usb_device *p)
+{
+int ir;
+
+msleep(20);
+ir = regset(p, 0x0002, 0x0093);
+if (0 > ir)
+ SAY("ERROR: failed to set register 0x0002 to 0x0078\n");
+msleep(20);
+return ir;
+}
+/*****************************************************************************/
diff --git a/drivers/staging/easycap/easycap_main.c b/drivers/staging/easycap/easycap_main.c
new file mode 100644
index 00000000000..09c194ce10a
--- /dev/null
+++ b/drivers/staging/easycap/easycap_main.c
@@ -0,0 +1,4354 @@
+/******************************************************************************
+* *
+* easycap_main.c *
+* *
+* Video driver for EasyCAP USB2.0 Video Capture Device DC60 *
+* *
+* *
+******************************************************************************/
+/*
+ *
+ * Copyright (C) 2010 R.M. Thomas <rmthomas@sciolus.org>
+ *
+ *
+ * This is free software; you can redistribute it and/or modify
+ * 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 software 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 software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+*/
+/*****************************************************************************/
+
+#include "easycap.h"
+#include "easycap_standard.h"
+
+int easycap_debug;
+module_param(easycap_debug, int, S_IRUGO | S_IWUSR);
+
+/*---------------------------------------------------------------------------*/
+/*
+ * PARAMETERS APPLICABLE TO ENTIRE DRIVER, I.E. BOTH VIDEO AND AUDIO
+ */
+/*---------------------------------------------------------------------------*/
+struct usb_device_id easycap_usb_device_id_table[] = {
+{ USB_DEVICE(USB_EASYCAP_VENDOR_ID, USB_EASYCAP_PRODUCT_ID) },
+{ }
+};
+MODULE_DEVICE_TABLE(usb, easycap_usb_device_id_table);
+struct usb_driver easycap_usb_driver = {
+.name = "easycap",
+.id_table = easycap_usb_device_id_table,
+.probe = easycap_usb_probe,
+.disconnect = easycap_usb_disconnect,
+};
+/*---------------------------------------------------------------------------*/
+/*
+ * PARAMETERS USED WHEN REGISTERING THE VIDEO INTERFACE
+ *
+ * NOTE: SOME KERNELS IGNORE usb_class_driver.minor_base, AS MENTIONED BY
+ * CORBET ET AL. "LINUX DEVICE DRIVERS", 3rd EDITION, PAGE 253.
+ * THIS IS THE CASE FOR OpenSUSE.
+ */
+/*---------------------------------------------------------------------------*/
+const struct file_operations easycap_fops = {
+.owner = THIS_MODULE,
+.open = easycap_open,
+.release = easycap_release,
+.ioctl = easycap_ioctl,
+.poll = easycap_poll,
+.mmap = easycap_mmap,
+.llseek = no_llseek,
+};
+struct vm_operations_struct easycap_vm_ops = {
+.open = easycap_vma_open,
+.close = easycap_vma_close,
+.fault = easycap_vma_fault,
+};
+struct usb_class_driver easycap_class = {
+.name = "usb/easycap%d",
+.fops = &easycap_fops,
+.minor_base = USB_SKEL_MINOR_BASE,
+};
+
+/*vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/
+#if defined(EASYCAP_IS_VIDEODEV_CLIENT)
+#if defined(EASYCAP_NEEDS_V4L2_FOPS)
+const struct v4l2_file_operations v4l2_fops = {
+.owner = THIS_MODULE,
+.open = easycap_open_noinode,
+.release = easycap_release_noinode,
+.ioctl = easycap_ioctl_noinode,
+.poll = easycap_poll,
+.mmap = easycap_mmap,
+};
+#endif /*EASYCAP_NEEDS_V4L2_FOPS*/
+int video_device_many /*=0*/;
+struct video_device *pvideo_array[VIDEO_DEVICE_MANY], *pvideo_device;
+#endif /*EASYCAP_IS_VIDEODEV_CLIENT*/
+/*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
+
+/*--------------------------------------------------------------------------*/
+/*
+ * PARAMETERS USED WHEN REGISTERING THE AUDIO INTERFACE
+ */
+/*--------------------------------------------------------------------------*/
+const struct file_operations easysnd_fops = {
+.owner = THIS_MODULE,
+.open = easysnd_open,
+.release = easysnd_release,
+.ioctl = easysnd_ioctl,
+.read = easysnd_read,
+.llseek = no_llseek,
+};
+struct usb_class_driver easysnd_class = {
+.name = "usb/easysnd%d",
+.fops = &easysnd_fops,
+.minor_base = USB_SKEL_MINOR_BASE,
+};
+/****************************************************************************/
+/*--------------------------------------------------------------------------*/
+/*
+ * IT IS NOT APPROPRIATE FOR easycap_open() TO SUBMIT THE VIDEO URBS HERE,
+ * BECAUSE THERE WILL ALWAYS BE SUBSEQUENT NEGOTIATION OF TV STANDARD AND
+ * FORMAT BY IOCTL AND IT IS INADVISABLE TO HAVE THE URBS RUNNING WHILE
+ * REGISTERS OF THE SA7113H ARE BEING MANIPULATED.
+ *
+ * THE SUBMISSION OF VIDEO URBS IS THEREFORE DELAYED UNTIL THE IOCTL COMMAND
+ * STREAMON IS RECEIVED.
+ */
+/*--------------------------------------------------------------------------*/
+/*vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/
+#if defined(EASYCAP_IS_VIDEODEV_CLIENT)
+int
+easycap_open_noinode(struct file *file)
+{
+return easycap_open((struct inode *)NULL, file);
+}
+#endif /*EASYCAP_IS_VIDEODEV_CLIENT*/
+/*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
+int
+easycap_open(struct inode *inode, struct file *file)
+{
+#if (!defined(EASYCAP_IS_VIDEODEV_CLIENT))
+struct usb_interface *pusb_interface;
+#endif /*EASYCAP_IS_VIDEODEV_CLIENT*/
+struct usb_device *p;
+struct easycap *peasycap;
+int i, k, m, rc;
+
+JOT(4, "\n");
+SAY("==========OPEN=========\n");
+
+peasycap = (struct easycap *)NULL;
+#if (!defined(EASYCAP_IS_VIDEODEV_CLIENT))
+if ((struct inode *)NULL == inode) {
+ SAY("ERROR: inode is NULL.\n");
+ return -EFAULT;
+}
+pusb_interface = usb_find_interface(&easycap_usb_driver, iminor(inode));
+if (!pusb_interface) {
+ SAY("ERROR: pusb_interface is NULL.\n");
+ return -EFAULT;
+}
+peasycap = usb_get_intfdata(pusb_interface);
+/*vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/
+#else
+for (i = 0; i < video_device_many; i++) {
+ pvideo_device = pvideo_array[i];
+ if ((struct video_device *)NULL != pvideo_device) {
+ peasycap = (struct easycap *)video_get_drvdata(pvideo_device);
+ break;
+ }
+}
+/*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
+#endif /*EASYCAP_IS_VIDEODEV_CLIENT*/
+if ((struct easycap *)NULL == peasycap) {
+ SAY("MISTAKE: peasycap is NULL\n");
+ return -EFAULT;
+}
+file->private_data = peasycap;
+/*---------------------------------------------------------------------------*/
+/*
+ * INITIALIZATION
+ */
+/*---------------------------------------------------------------------------*/
+JOT(4, "starting initialization\n");
+
+for (k = 0; k < FRAME_BUFFER_MANY; k++) {
+ for (m = 0; m < FRAME_BUFFER_SIZE/PAGE_SIZE; m++)
+ memset(peasycap->frame_buffer[k][m].pgo, 0, PAGE_SIZE);
+}
+p = peasycap->pusb_device;
+if ((struct usb_device *)NULL == p) {
+ SAY("ERROR: peasycap->pusb_device is NULL\n");
+ return -EFAULT;
+} else {
+ JOT(16, "0x%08lX=peasycap->pusb_device\n", \
+ (long int)peasycap->pusb_device);
+}
+rc = wakeup_device(peasycap->pusb_device);
+if (0 == rc)
+ JOT(8, "wakeup_device() OK\n");
+else {
+ SAY("ERROR: wakeup_device() returned %i\n", rc);
+ return -EFAULT;
+}
+rc = setup_stk(p); peasycap->input = 0;
+if (0 == rc)
+ JOT(8, "setup_stk() OK\n");
+else {
+ SAY("ERROR: setup_stk() returned %i\n", rc);
+ return -EFAULT;
+}
+rc = setup_saa(p);
+if (0 == rc)
+ JOT(8, "setup_saa() OK\n");
+else {
+ SAY("ERROR: setup_saa() returned %i\n", rc);
+ return -EFAULT;
+}
+rc = check_saa(p);
+if (0 == rc)
+ JOT(8, "check_saa() OK\n");
+else if (-8 < rc)
+ SAY("check_saa() returned %i\n", rc);
+else {
+ SAY("ERROR: check_saa() returned %i\n", rc);
+ return -EFAULT;
+}
+peasycap->standard_offset = -1;
+/*---------------------------------------------------------------------------*/
+#if defined(PREFER_NTSC)
+
+rc = adjust_standard(peasycap, V4L2_STD_NTSC_M);
+if (0 == rc)
+ JOT(8, "adjust_standard(.,NTSC_M) OK\n");
+else {
+ SAY("ERROR: adjust_standard(.,NTSC_M) returned %i\n", rc);
+ return -EFAULT;
+}
+rc = adjust_format(peasycap, 640, 480, V4L2_PIX_FMT_UYVY, V4L2_FIELD_NONE, \
+ false);
+if (0 <= rc)
+ JOT(8, "adjust_format(.,640,480,UYVY) OK\n");
+else {
+ SAY("ERROR: adjust_format(.,640,480,UYVY) returned %i\n", rc);
+ return -EFAULT;
+}
+
+#else
+
+rc = adjust_standard(peasycap, \
+ (V4L2_STD_PAL_B | V4L2_STD_PAL_G | V4L2_STD_PAL_H | \
+ V4L2_STD_PAL_I | V4L2_STD_PAL_N));
+if (0 == rc)
+ JOT(8, "adjust_standard(.,PAL_BGHIN) OK\n");
+else {
+ SAY("ERROR: adjust_standard(.,PAL_BGHIN) returned %i\n", rc);
+ return -EFAULT;
+}
+rc = adjust_format(peasycap, 640, 480, V4L2_PIX_FMT_UYVY, V4L2_FIELD_NONE, \
+ false);
+if (0 <= rc)
+ JOT(8, "adjust_format(.,640,480,uyvy,false) OK\n");
+else {
+ SAY("ERROR: adjust_format(.,640,480,uyvy,false) returned %i\n", rc);
+ return -EFAULT;
+}
+
+#endif /* !PREFER_NTSC*/
+/*---------------------------------------------------------------------------*/
+rc = adjust_brightness(peasycap, -8192);
+if (0 != rc) {
+ SAY("ERROR: adjust_brightness(default) returned %i\n", rc);
+ return -EFAULT;
+}
+rc = adjust_contrast(peasycap, -8192);
+if (0 != rc) {
+ SAY("ERROR: adjust_contrast(default) returned %i\n", rc);
+ return -EFAULT;
+}
+rc = adjust_saturation(peasycap, -8192);
+if (0 != rc) {
+ SAY("ERROR: adjust_saturation(default) returned %i\n", rc);
+ return -EFAULT;
+}
+rc = adjust_hue(peasycap, -8192);
+if (0 != rc) {
+ SAY("ERROR: adjust_hue(default) returned %i\n", rc);
+ return -EFAULT;
+}
+/*---------------------------------------------------------------------------*/
+rc = usb_set_interface(peasycap->pusb_device, peasycap->video_interface, \
+ peasycap->video_altsetting_on);
+if (0 == rc)
+ JOT(8, "usb_set_interface(.,%i,%i) OK\n", peasycap->video_interface, \
+ peasycap->video_altsetting_on);
+else {
+ SAY("ERROR: usb_set_interface() returned %i\n", rc);
+ return -EFAULT;
+}
+rc = start_100(p);
+if (0 == rc)
+ JOT(8, "start_100() OK\n");
+else {
+ SAY("ERROR: start_100() returned %i\n", rc);
+ return -EFAULT;
+}
+peasycap->video_isoc_sequence = VIDEO_ISOC_BUFFER_MANY - 1;
+peasycap->video_idle = 0;
+peasycap->video_junk = 0;
+for (i = 0; i < 180; i++)
+ peasycap->merit[i] = 0;
+peasycap->video_eof = 0;
+peasycap->audio_eof = 0;
+
+do_gettimeofday(&peasycap->timeval7);
+
+peasycap->fudge = 0;
+
+JOT(4, "finished initialization\n");
+return 0;
+}
+/*****************************************************************************/
+int
+submit_video_urbs(struct easycap *peasycap)
+{
+struct data_urb *pdata_urb;
+struct urb *purb;
+struct list_head *plist_head;
+int j, isbad, m, rc;
+int isbuf;
+
+if ((struct list_head *)NULL == peasycap->purb_video_head) {
+ SAY("ERROR: peasycap->urb_video_head uninitialized\n");
+ return -EFAULT;
+}
+if ((struct usb_device *)NULL == peasycap->pusb_device) {
+ SAY("ERROR: peasycap->pusb_device is NULL\n");
+ return -EFAULT;
+}
+if (!peasycap->video_isoc_streaming) {
+
+
+
+
+
+
+
+
+ JOT(4, "submission of all video urbs\n");
+ if (0 != ready_saa(peasycap->pusb_device)) {
+ SAY("ERROR: not ready to capture after waiting " \
+ "one second\n");
+ SAY("..... continuing anyway\n");
+ }
+ isbad = 0; m = 0;
+ list_for_each(plist_head, (peasycap->purb_video_head)) {
+ pdata_urb = list_entry(plist_head, struct data_urb, list_head);
+ if (NULL != pdata_urb) {
+ purb = pdata_urb->purb;
+ if (NULL != purb) {
+ isbuf = pdata_urb->isbuf;
+ purb->interval = 1;
+ purb->dev = peasycap->pusb_device;
+ purb->pipe = \
+ usb_rcvisocpipe(peasycap->pusb_device,\
+ peasycap->video_endpointnumber);
+ purb->transfer_flags = URB_ISO_ASAP;
+ purb->transfer_buffer = \
+ peasycap->video_isoc_buffer[isbuf].pgo;
+ purb->transfer_buffer_length = \
+ peasycap->video_isoc_buffer_size;
+ purb->complete = easycap_complete;
+ purb->context = peasycap;
+ purb->start_frame = 0;
+ purb->number_of_packets = \
+ peasycap->video_isoc_framesperdesc;
+
+ for (j = 0; j < peasycap->\
+ video_isoc_framesperdesc; j++) {
+ purb->iso_frame_desc[j].\
+ offset = j * \
+ peasycap->\
+ video_isoc_maxframesize;
+ purb->iso_frame_desc[j].\
+ length = peasycap->\
+ video_isoc_maxframesize;
+ }
+
+ rc = usb_submit_urb(purb, GFP_KERNEL);
+ if (0 != rc) {
+ isbad++;
+ SAY("ERROR: usb_submit_urb() failed " \
+ "for urb with rc:\n");
+ switch (rc) {
+ case -ENOMEM: {
+ SAY("ENOMEM\n");
+ break;
+ }
+ case -ENODEV: {
+ SAY("ENODEV\n");
+ break;
+ }
+ case -ENXIO: {
+ SAY("ENXIO\n");
+ break;
+ }
+ case -EINVAL: {
+ SAY("EINVAL\n");
+ break;
+ }
+ case -EAGAIN: {
+ SAY("EAGAIN\n");
+ break;
+ }
+ case -EFBIG: {
+ SAY("EFBIG\n");
+ break;
+ }
+ case -EPIPE: {
+ SAY("EPIPE\n");
+ break;
+ }
+ case -EMSGSIZE: {
+ SAY("EMSGSIZE\n");
+ break;
+ }
+ default: {
+ SAY("unknown error code %i\n",\
+ rc);
+ break;
+ }
+ }
+ } else {
+ m++;
+ }
+ } else {
+ isbad++;
+ }
+ } else {
+ isbad++;
+ }
+ }
+ if (isbad) {
+ JOT(4, "attempting cleanup instead of submitting\n");
+ list_for_each(plist_head, (peasycap->purb_video_head)) {
+ pdata_urb = list_entry(plist_head, struct data_urb, \
+ list_head);
+ if (NULL != pdata_urb) {
+ purb = pdata_urb->purb;
+ if (NULL != purb)
+ usb_kill_urb(purb);
+ }
+ }
+ peasycap->video_isoc_streaming = 0;
+ } else {
+ peasycap->video_isoc_streaming = 1;
+ JOT(4, "submitted %i video urbs\n", m);
+ }
+
+
+
+
+
+
+} else {
+ JOT(4, "already streaming video urbs\n");
+}
+return 0;
+}
+/*****************************************************************************/
+int
+kill_video_urbs(struct easycap *peasycap)
+{
+int m;
+struct list_head *plist_head;
+struct data_urb *pdata_urb;
+
+if ((struct easycap *)NULL == peasycap) {
+ SAY("ERROR: peasycap is NULL\n");
+ return -EFAULT;
+}
+if (peasycap->video_isoc_streaming) {
+
+
+
+ if ((struct list_head *)NULL != peasycap->purb_video_head) {
+ peasycap->video_isoc_streaming = 0;
+ JOT(4, "killing video urbs\n");
+ m = 0;
+ list_for_each(plist_head, (peasycap->purb_video_head)) {
+ pdata_urb = list_entry(plist_head, struct data_urb, \
+ list_head);
+ if ((struct data_urb *)NULL != pdata_urb) {
+ if ((struct urb *)NULL != pdata_urb->purb) {
+ usb_kill_urb(pdata_urb->purb);
+ m++;
+ }
+ }
+ }
+ JOT(4, "%i video urbs killed\n", m);
+ } else {
+ SAY("ERROR: peasycap->purb_video_head is NULL\n");
+ return -EFAULT;
+ }
+} else {
+ JOT(8, "%i=video_isoc_streaming, no video urbs killed\n", \
+ peasycap->video_isoc_streaming);
+}
+return 0;
+}
+/****************************************************************************/
+/*vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/
+#if defined(EASYCAP_IS_VIDEODEV_CLIENT)
+int
+easycap_release_noinode(struct file *file)
+{
+return easycap_release((struct inode *)NULL, file);
+}
+#endif /*EASYCAP_IS_VIDEODEV_CLIENT*/
+/*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
+/*--------------------------------------------------------------------------*/
+int
+easycap_release(struct inode *inode, struct file *file)
+{
+#if (!defined(EASYCAP_IS_VIDEODEV_CLIENT))
+struct easycap *peasycap;
+
+JOT(4, "\n");
+
+peasycap = file->private_data;
+if (NULL == peasycap) {
+ SAY("ERROR: peasycap is NULL.\n");
+ SAY("ending unsuccessfully\n");
+ return -EFAULT;
+}
+if (0 != kill_video_urbs(peasycap)) {
+ SAY("ERROR: kill_video_urbs() failed\n");
+ return -EFAULT;
+}
+JOT(4, "ending successfully\n");
+/*vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/
+#else
+#
+/*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
+#endif /*EASYCAP_IS_VIDEODEV_CLIENT*/
+
+return 0;
+}
+/****************************************************************************/
+/*vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/
+#if defined(EASYCAP_IS_VIDEODEV_CLIENT)
+int
+videodev_release(struct video_device *pvd)
+{
+struct easycap *peasycap;
+int i, j, k;
+
+JOT(4, "\n");
+
+k = 0;
+for (i = 0; i < video_device_many; i++) {
+ pvideo_device = pvideo_array[i];
+ if ((struct video_device *)NULL != pvideo_device) {
+ if (pvd->minor == pvideo_device->minor) {
+ peasycap = (struct easycap *)\
+ video_get_drvdata(pvideo_device);
+ if ((struct easycap *)NULL == peasycap) {
+ SAY("ERROR: peasycap is NULL\n");
+ SAY("ending unsuccessfully\n");
+ return -EFAULT;
+ }
+ if (0 != kill_video_urbs(peasycap)) {
+ SAY("ERROR: kill_video_urbs() failed\n");
+ return -EFAULT;
+ }
+ JOT(4, "freeing video_device structure: " \
+ "/dev/video%i\n", i);
+ kfree((void *)pvideo_device);
+ for (j = i; j < (VIDEO_DEVICE_MANY - 1); j++)
+ pvideo_array[j] = pvideo_array[j + 1];
+ video_device_many--; k++;
+ break;
+ }
+ }
+}
+if (!k) {
+ SAY("ERROR: lost video_device structure for %i=minor\n", pvd->minor);
+ SAY("cannot free: may cause memory leak\n");
+ SAY("ending unsuccessfully\n");
+ return -EFAULT;
+}
+
+JOT(4, "ending successfully\n");
+return 0;
+}
+#endif /*EASYCAP_IS_VIDEODEV_CLIENT*/
+/*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
+/****************************************************************************/
+/*--------------------------------------------------------------------------*/
+/*
+ * THIS FUNCTION IS CALLED FROM WITHIN easycap_usb_disconnect().
+ * BY THIS STAGE THE DEVICE HAS ALREADY BEEN PHYSICALLY UNPLUGGED.
+ * peasycap->pusb_device IS NO LONGER VALID AND SHOULD HAVE BEEN SET TO NULL.
+ */
+/*---------------------------------------------------------------------------*/
+void
+easycap_delete(struct kref *pkref)
+{
+int k, m, lost;
+int allocation_video_urb, allocation_video_page, allocation_video_struct;
+int allocation_audio_urb, allocation_audio_page, allocation_audio_struct;
+int registered_video, registered_audio;
+struct easycap *peasycap;
+struct data_urb *pdata_urb;
+struct list_head *plist_head, *plist_next;
+
+JOT(4, "\n");
+
+peasycap = container_of(pkref, struct easycap, kref);
+if ((struct easycap *)NULL == peasycap) {
+ SAY("ERROR: peasycap is NULL: cannot perform deletions\n");
+ return;
+}
+/*---------------------------------------------------------------------------*/
+/*
+ * FREE VIDEO.
+ */
+/*---------------------------------------------------------------------------*/
+if ((struct list_head *)NULL != peasycap->purb_video_head) {
+ JOT(4, "freeing video urbs\n");
+ m = 0;
+ list_for_each(plist_head, (peasycap->purb_video_head)) {
+ pdata_urb = list_entry(plist_head, struct data_urb, list_head);
+ if (NULL == pdata_urb)
+ JOT(4, "ERROR: pdata_urb is NULL\n");
+ else {
+ if ((struct urb *)NULL != pdata_urb->purb) {
+ usb_free_urb(pdata_urb->purb);
+ pdata_urb->purb = (struct urb *)NULL;
+ peasycap->allocation_video_urb -= 1;
+ m++;
+ }
+ }
+ }
+
+ JOT(4, "%i video urbs freed\n", m);
+/*---------------------------------------------------------------------------*/
+ JOT(4, "freeing video data_urb structures.\n");
+ m = 0;
+ list_for_each_safe(plist_head, plist_next, peasycap->purb_video_head) {
+ pdata_urb = list_entry(plist_head, struct data_urb, list_head);
+ if ((struct data_urb *)NULL != pdata_urb) {
+ kfree(pdata_urb); pdata_urb = (struct data_urb *)NULL;
+ peasycap->allocation_video_struct -= \
+ sizeof(struct data_urb);
+ m++;
+ }
+ }
+ JOT(4, "%i video data_urb structures freed\n", m);
+ JOT(4, "setting peasycap->purb_video_head=NULL\n");
+ peasycap->purb_video_head = (struct list_head *)NULL;
+ } else {
+JOT(4, "peasycap->purb_video_head is NULL\n");
+}
+/*---------------------------------------------------------------------------*/
+JOT(4, "freeing video isoc buffers.\n");
+m = 0;
+for (k = 0; k < VIDEO_ISOC_BUFFER_MANY; k++) {
+ if ((void *)NULL != peasycap->video_isoc_buffer[k].pgo) {
+ free_pages((unsigned long)\
+ (peasycap->video_isoc_buffer[k].pgo), \
+ VIDEO_ISOC_ORDER);
+ peasycap->video_isoc_buffer[k].pgo = (void *)NULL;
+ peasycap->allocation_video_page -= \
+ ((unsigned int)(0x01 << VIDEO_ISOC_ORDER));
+ m++;
+ }
+}
+JOT(4, "isoc video buffers freed: %i pages\n", m * (0x01 << VIDEO_ISOC_ORDER));
+/*---------------------------------------------------------------------------*/
+JOT(4, "freeing video field buffers.\n");
+lost = 0;
+for (k = 0; k < FIELD_BUFFER_MANY; k++) {
+ for (m = 0; m < FIELD_BUFFER_SIZE/PAGE_SIZE; m++) {
+ if ((void *)NULL != peasycap->field_buffer[k][m].pgo) {
+ free_page((unsigned long)\
+ (peasycap->field_buffer[k][m].pgo));
+ peasycap->field_buffer[k][m].pgo = (void *)NULL;
+ peasycap->allocation_video_page -= 1;
+ lost++;
+ }
+ }
+}
+JOT(4, "video field buffers freed: %i pages\n", lost);
+/*---------------------------------------------------------------------------*/
+JOT(4, "freeing video frame buffers.\n");
+lost = 0;
+for (k = 0; k < FRAME_BUFFER_MANY; k++) {
+ for (m = 0; m < FRAME_BUFFER_SIZE/PAGE_SIZE; m++) {
+ if ((void *)NULL != peasycap->frame_buffer[k][m].pgo) {
+ free_page((unsigned long)\
+ (peasycap->frame_buffer[k][m].pgo));
+ peasycap->frame_buffer[k][m].pgo = (void *)NULL;
+ peasycap->allocation_video_page -= 1;
+ lost++;
+ }
+ }
+}
+JOT(4, "video frame buffers freed: %i pages\n", lost);
+/*---------------------------------------------------------------------------*/
+/*
+ * FREE AUDIO.
+ */
+/*---------------------------------------------------------------------------*/
+if ((struct list_head *)NULL != peasycap->purb_audio_head) {
+ JOT(4, "freeing audio urbs\n");
+ m = 0;
+ list_for_each(plist_head, (peasycap->purb_audio_head)) {
+ pdata_urb = list_entry(plist_head, struct data_urb, list_head);
+ if (NULL == pdata_urb)
+ JOT(4, "ERROR: pdata_urb is NULL\n");
+ else {
+ if ((struct urb *)NULL != pdata_urb->purb) {
+ usb_free_urb(pdata_urb->purb);
+ pdata_urb->purb = (struct urb *)NULL;
+ peasycap->allocation_audio_urb -= 1;
+ m++;
+ }
+ }
+ }
+ JOT(4, "%i audio urbs freed\n", m);
+/*---------------------------------------------------------------------------*/
+ JOT(4, "freeing audio data_urb structures.\n");
+ m = 0;
+ list_for_each_safe(plist_head, plist_next, peasycap->purb_audio_head) {
+ pdata_urb = list_entry(plist_head, struct data_urb, list_head);
+ if ((struct data_urb *)NULL != pdata_urb) {
+ kfree(pdata_urb); pdata_urb = (struct data_urb *)NULL;
+ peasycap->allocation_audio_struct -= \
+ sizeof(struct data_urb);
+ m++;
+ }
+ }
+JOT(4, "%i audio data_urb structures freed\n", m);
+JOT(4, "setting peasycap->purb_audio_head=NULL\n");
+peasycap->purb_audio_head = (struct list_head *)NULL;
+} else {
+JOT(4, "peasycap->purb_audio_head is NULL\n");
+}
+/*---------------------------------------------------------------------------*/
+JOT(4, "freeing audio isoc buffers.\n");
+m = 0;
+for (k = 0; k < AUDIO_ISOC_BUFFER_MANY; k++) {
+ if ((void *)NULL != peasycap->audio_isoc_buffer[k].pgo) {
+ free_pages((unsigned long)\
+ (peasycap->audio_isoc_buffer[k].pgo), \
+ AUDIO_ISOC_ORDER);
+ peasycap->audio_isoc_buffer[k].pgo = (void *)NULL;
+ peasycap->allocation_audio_page -= \
+ ((unsigned int)(0x01 << AUDIO_ISOC_ORDER));
+ m++;
+ }
+}
+JOT(4, "easysnd_delete(): isoc audio buffers freed: %i pages\n", \
+ m * (0x01 << AUDIO_ISOC_ORDER));
+/*---------------------------------------------------------------------------*/
+JOT(4, "freeing audio buffers.\n");
+lost = 0;
+for (k = 0; k < peasycap->audio_buffer_page_many; k++) {
+ if ((void *)NULL != peasycap->audio_buffer[k].pgo) {
+ free_page((unsigned long)(peasycap->audio_buffer[k].pgo));
+ peasycap->audio_buffer[k].pgo = (void *)NULL;
+ peasycap->allocation_audio_page -= 1;
+ lost++;
+ }
+}
+JOT(4, "easysnd_delete(): audio buffers freed: %i pages\n", lost);
+/*---------------------------------------------------------------------------*/
+JOT(4, "freeing easycap structure.\n");
+allocation_video_urb = peasycap->allocation_video_urb;
+allocation_video_page = peasycap->allocation_video_page;
+allocation_video_struct = peasycap->allocation_video_struct;
+registered_video = peasycap->registered_video;
+allocation_audio_urb = peasycap->allocation_audio_urb;
+allocation_audio_page = peasycap->allocation_audio_page;
+allocation_audio_struct = peasycap->allocation_audio_struct;
+registered_audio = peasycap->registered_audio;
+m = 0;
+if ((struct easycap *)NULL != peasycap) {
+ kfree(peasycap); peasycap = (struct easycap *)NULL;
+ allocation_video_struct -= sizeof(struct easycap);
+ m++;
+}
+JOT(4, "%i easycap structure freed\n", m);
+/*---------------------------------------------------------------------------*/
+
+SAY("%8i= video urbs after all deletions\n", allocation_video_urb);
+SAY("%8i= video pages after all deletions\n", allocation_video_page);
+SAY("%8i= video structs after all deletions\n", allocation_video_struct);
+SAY("%8i= video devices after all deletions\n", registered_video);
+SAY("%8i= audio urbs after all deletions\n", allocation_audio_urb);
+SAY("%8i= audio pages after all deletions\n", allocation_audio_page);
+SAY("%8i= audio structs after all deletions\n", allocation_audio_struct);
+SAY("%8i= audio devices after all deletions\n", registered_audio);
+
+JOT(4, "ending.\n");
+return;
+}
+/*****************************************************************************/
+unsigned int easycap_poll(struct file *file, poll_table *wait)
+{
+struct easycap *peasycap;
+
+JOT(8, "\n");
+
+if (NULL == ((poll_table *)wait))
+ JOT(8, "WARNING: poll table pointer is NULL ... continuing\n");
+if (NULL == ((struct file *)file)) {
+ SAY("ERROR: file pointer is NULL\n");
+ return -EFAULT;
+}
+peasycap = file->private_data;
+if (NULL == peasycap) {
+ SAY("ERROR: peasycap is NULL\n");
+ return -EFAULT;
+}
+peasycap->polled = 1;
+
+if (0 == easycap_dqbuf(peasycap, 0))
+ return POLLIN | POLLRDNORM;
+else
+ return POLLERR;
+
+}
+/*****************************************************************************/
+/*---------------------------------------------------------------------------*/
+/*
+ * IF mode IS NONZERO THIS ROUTINE RETURNS -EAGAIN RATHER THAN BLOCKING.
+ */
+/*---------------------------------------------------------------------------*/
+int
+easycap_dqbuf(struct easycap *peasycap, int mode)
+{
+int miss, rc;
+
+JOT(8, "\n");
+
+if (NULL == peasycap) {
+ SAY("ERROR: peasycap is NULL\n");
+ return -EFAULT;
+}
+/*---------------------------------------------------------------------------*/
+/*
+ * WAIT FOR FIELD 0
+ */
+/*---------------------------------------------------------------------------*/
+miss = 0;
+if (mutex_lock_interruptible(&(peasycap->mutex_mmap_video[0])))
+ return -ERESTARTSYS;
+while ((peasycap->field_read == peasycap->field_fill) || \
+ (0 != (0xFF00 & peasycap->field_buffer\
+ [peasycap->field_read][0].kount)) || \
+ (0 != (0x00FF & peasycap->field_buffer\
+ [peasycap->field_read][0].kount))) {
+ mutex_unlock(&(peasycap->mutex_mmap_video[0]));
+
+ if (mode)
+ return -EAGAIN;
+
+ JOT(8, "first wait on wq_video, " \
+ "%i=field_read %i=field_fill\n", \
+ peasycap->field_read, peasycap->field_fill);
+
+ msleep(1);
+ if (0 != (wait_event_interruptible(peasycap->wq_video, \
+ (peasycap->video_idle || peasycap->video_eof || \
+ ((peasycap->field_read != peasycap->field_fill) && \
+ (0 == (0xFF00 & peasycap->field_buffer\
+ [peasycap->field_read][0].kount)) && \
+ (0 == (0x00FF & peasycap->field_buffer\
+ [peasycap->field_read][0].kount))))))){
+ SAY("aborted by signal\n");
+ return -EIO;
+ }
+ if (peasycap->video_idle) {
+ JOT(8, "%i=peasycap->video_idle\n", peasycap->video_idle);
+ return -EIO;
+ }
+ if (peasycap->video_eof) {
+ JOT(8, "%i=peasycap->video_eof\n", peasycap->video_eof);
+ debrief(peasycap);
+ kill_video_urbs(peasycap);
+ return -EIO;
+ }
+miss++;
+if (mutex_lock_interruptible(&(peasycap->mutex_mmap_video[0])))
+ return -ERESTARTSYS;
+}
+mutex_unlock(&(peasycap->mutex_mmap_video[0]));
+JOT(8, "first awakening on wq_video after %i waits\n", miss);
+
+rc = field2frame(peasycap);
+if (0 != rc)
+ SAY("ERROR: field2frame() returned %i\n", rc);
+
+if (true == peasycap->offerfields) {
+ peasycap->frame_read = peasycap->frame_fill;
+ (peasycap->frame_fill)++;
+ if (peasycap->frame_buffer_many <= peasycap->frame_fill)
+ peasycap->frame_fill = 0;
+
+ if (0x01 & easycap_standard[peasycap->standard_offset].mask) {
+ peasycap->frame_buffer[peasycap->frame_read][0].kount = \
+ V4L2_FIELD_BOTTOM;
+ } else {
+ peasycap->frame_buffer[peasycap->frame_read][0].kount = \
+ V4L2_FIELD_TOP;
+ }
+JOT(8, "setting: %i=peasycap->frame_read\n", peasycap->frame_read);
+JOT(8, "bumped to: %i=peasycap->frame_fill\n", peasycap->frame_fill);
+}
+/*---------------------------------------------------------------------------*/
+/*
+ * WAIT FOR FIELD 1
+ */
+/*---------------------------------------------------------------------------*/
+miss = 0;
+if (mutex_lock_interruptible(&(peasycap->mutex_mmap_video[0])))
+ return -ERESTARTSYS;
+while ((peasycap->field_read == peasycap->field_fill) || \
+ (0 != (0xFF00 & peasycap->field_buffer\
+ [peasycap->field_read][0].kount)) || \
+ (0 == (0x00FF & peasycap->field_buffer\
+ [peasycap->field_read][0].kount))) {
+ mutex_unlock(&(peasycap->mutex_mmap_video[0]));
+
+ if (mode)
+ return -EAGAIN;
+
+ JOT(8, "second wait on wq_video, " \
+ "%i=field_read %i=field_fill\n", \
+ peasycap->field_read, peasycap->field_fill);
+ msleep(1);
+ if (0 != (wait_event_interruptible(peasycap->wq_video, \
+ (peasycap->video_idle || peasycap->video_eof || \
+ ((peasycap->field_read != peasycap->field_fill) && \
+ (0 == (0xFF00 & peasycap->field_buffer\
+ [peasycap->field_read][0].kount)) && \
+ (0 != (0x00FF & peasycap->field_buffer\
+ [peasycap->field_read][0].kount))))))){
+ SAY("aborted by signal\n");
+ return -EIO;
+ }
+ if (peasycap->video_idle) {
+ JOT(8, "%i=peasycap->video_idle\n", peasycap->video_idle);
+ return -EIO;
+ }
+ if (peasycap->video_eof) {
+ JOT(8, "%i=peasycap->video_eof\n", peasycap->video_eof);
+ debrief(peasycap);
+ kill_video_urbs(peasycap);
+ return -EIO;
+ }
+miss++;
+if (mutex_lock_interruptible(&(peasycap->mutex_mmap_video[0])))
+ return -ERESTARTSYS;
+}
+mutex_unlock(&(peasycap->mutex_mmap_video[0]));
+JOT(8, "second awakening on wq_video after %i waits\n", miss);
+
+rc = field2frame(peasycap);
+if (0 != rc)
+ SAY("ERROR: field2frame() returned %i\n", rc);
+
+peasycap->frame_read = peasycap->frame_fill;
+peasycap->queued[peasycap->frame_read] = 0;
+peasycap->done[peasycap->frame_read] = V4L2_BUF_FLAG_DONE;
+
+(peasycap->frame_fill)++;
+if (peasycap->frame_buffer_many <= peasycap->frame_fill)
+ peasycap->frame_fill = 0;
+
+if (0x01 & easycap_standard[peasycap->standard_offset].mask) {
+ peasycap->frame_buffer[peasycap->frame_read][0].kount = \
+ V4L2_FIELD_TOP;
+} else {
+ peasycap->frame_buffer[peasycap->frame_read][0].kount = \
+ V4L2_FIELD_BOTTOM;
+}
+
+JOT(8, "setting: %i=peasycap->frame_read\n", peasycap->frame_read);
+JOT(8, "bumped to: %i=peasycap->frame_fill\n", peasycap->frame_fill);
+
+return 0;
+}
+/*****************************************************************************/
+/*---------------------------------------------------------------------------*/
+/*
+ * BY DEFINITION, odd IS true FOR THE FIELD OCCUPYING LINES 1,3,5,...,479
+ * odd IS false FOR THE FIELD OCCUPYING LINES 0,2,4,...,478
+ *
+ * WHEN BOOLEAN PARAMETER decimatepixel IS true, ONLY THE FIELD FOR WHICH
+ * odd==false IS TRANSFERRED TO THE FRAME BUFFER.
+ *
+ * THE BOOLEAN PARAMETER offerfields IS true ONLY WHEN THE USER PROGRAM
+ * CHOOSES THE OPTION V4L2_FIELD_ALTERNATE. NO USERSPACE PROGRAM TESTED
+ * TO DATE HAS DONE THIS. BUGS ARE LIKELY.
+ */
+/*---------------------------------------------------------------------------*/
+int
+field2frame(struct easycap *peasycap)
+{
+static struct timeval timeval0;
+struct timeval timeval;
+long long int above, below;
+__u32 remainder;
+struct signed_div_result sdr;
+
+void *pex, *pad;
+int kex, kad, mex, mad, rex, rad, rad2;
+int c2, c3, w2, w3, cz, wz;
+int rc, bytesperpixel, multiplier, much, more, over, rump, caches;
+__u8 mask, margin;
+bool odd, isuy, decimatepixel, offerfields;
+
+JOT(8, "===== parity %i, field buffer %i --> frame buffer %i\n", \
+ peasycap->field_buffer[peasycap->field_read][0].kount,\
+ peasycap->field_read, peasycap->frame_fill);
+JOT(8, "===== %i=bytesperpixel\n", peasycap->bytesperpixel);
+if (true == peasycap->offerfields)
+ JOT(8, "===== offerfields\n");
+
+/*---------------------------------------------------------------------------*/
+/*
+ * REJECT OR CLEAN BAD FIELDS
+ */
+/*---------------------------------------------------------------------------*/
+if (peasycap->field_read == peasycap->field_fill) {
+ SAY("ERROR: on entry, still filling field buffer %i\n", \
+ peasycap->field_read);
+ return 0;
+}
+#if defined(EASYCAP_TESTCARD)
+easycap_testcard(peasycap, peasycap->field_read);
+#else
+if (0 != (0x0400 & peasycap->field_buffer[peasycap->field_read][0].kount))
+ easycap_testcard(peasycap, peasycap->field_read);
+#endif /*EASYCAP_TESTCARD*/
+/*---------------------------------------------------------------------------*/
+
+offerfields = peasycap->offerfields;
+bytesperpixel = peasycap->bytesperpixel;
+decimatepixel = peasycap->decimatepixel;
+
+if ((2 != bytesperpixel) && \
+ (3 != bytesperpixel) && \
+ (4 != bytesperpixel)) {
+ SAY("MISTAKE: %i=bytesperpixel\n", bytesperpixel);
+ return -EFAULT;
+}
+if (true == decimatepixel)
+ multiplier = 2;
+else
+ multiplier = 1;
+
+w2 = 2 * multiplier * (peasycap->width);
+w3 = bytesperpixel * \
+ multiplier * \
+ (peasycap->width);
+wz = multiplier * \
+ (peasycap->height) * \
+ multiplier * \
+ (peasycap->width);
+
+kex = peasycap->field_read; mex = 0;
+kad = peasycap->frame_fill; mad = 0;
+
+pex = peasycap->field_buffer[kex][0].pgo; rex = PAGE_SIZE;
+pad = peasycap->frame_buffer[kad][0].pgo; rad = PAGE_SIZE;
+if (peasycap->field_buffer[kex][0].kount)
+ odd = true;
+else
+ odd = false;
+
+if ((true == odd) && (false == offerfields) &&(false == decimatepixel)) {
+ JOT(8, " initial skipping %4i bytes p.%4i\n", \
+ w3/multiplier, mad);
+ pad += (w3 / multiplier); rad -= (w3 / multiplier);
+}
+isuy = true;
+mask = 0; rump = 0; caches = 0;
+
+cz = 0;
+while (cz < wz) {
+ /*-------------------------------------------------------------------*/
+ /*
+ ** PROCESS ONE LINE OF FRAME AT FULL RESOLUTION:
+ ** READ w2 BYTES FROM FIELD BUFFER,
+ ** WRITE w3 BYTES TO FRAME BUFFER
+ **/
+ /*-------------------------------------------------------------------*/
+ if (false == decimatepixel) {
+ over = w2;
+ do {
+ much = over; more = 0; margin = 0; mask = 0x00;
+ if (rex < much)
+ much = rex;
+ rump = 0;
+
+ if (much % 2) {
+ SAY("MISTAKE: much is odd\n");
+ return -EFAULT;
+ }
+
+ more = (bytesperpixel * \
+ much) / 2;
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+ if (1 < bytesperpixel) {
+ if ((rad * \
+ 2) < (much * \
+ bytesperpixel)) {
+ /*
+ ** INJUDICIOUS ALTERATION OF THIS
+ ** BLOCK WILL CAUSE BREAKAGE.
+ ** BEWARE.
+ **/
+ rad2 = rad + bytesperpixel - 1;
+ much = ((((2 * \
+ rad2)/bytesperpixel)/2) * 2);
+ rump = ((bytesperpixel * \
+ much) / 2) - rad;
+ more = rad;
+ }
+ mask = (__u8)rump;
+ margin = 0;
+ if (much == rex) {
+ mask |= 0x04;
+ if ((mex + 1) < FIELD_BUFFER_SIZE/ \
+ PAGE_SIZE) {
+ margin = *((__u8 *)(peasycap->\
+ field_buffer\
+ [kex][mex + 1].pgo));
+ } else
+ mask |= 0x08;
+ }
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+ } else {
+ SAY("MISTAKE: %i=bytesperpixel\n", \
+ bytesperpixel);
+ return -EFAULT;
+ }
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+ if (rump)
+ caches++;
+
+ rc = redaub(peasycap, pad, pex, much, more, \
+ mask, margin, isuy);
+ if (0 > rc) {
+ SAY("ERROR: redaub() failed\n");
+ return -EFAULT;
+ }
+ if (much % 4) {
+ if (isuy)
+ isuy = false;
+ else
+ isuy = true;
+ }
+ over -= much; cz += much;
+ pex += much; rex -= much;
+ if (!rex) {
+ mex++;
+ pex = peasycap->field_buffer[kex][mex].pgo;
+ rex = PAGE_SIZE;
+ }
+ pad += more;
+ rad -= more;
+ if (!rad) {
+ mad++;
+ pad = peasycap->frame_buffer[kad][mad].pgo;
+ rad = PAGE_SIZE;
+ if (rump) {
+ pad += rump;
+ rad -= rump;
+ }
+ }
+ } while (over);
+/*---------------------------------------------------------------------------*/
+/*
+ * SKIP w3 BYTES IN TARGET FRAME BUFFER,
+ * UNLESS IT IS THE LAST LINE OF AN ODD FRAME
+ */
+/*---------------------------------------------------------------------------*/
+ if (((false == odd) || (cz != wz))&&(false == offerfields)) {
+ over = w3;
+ do {
+ if (!rad) {
+ mad++;
+ pad = peasycap->frame_buffer\
+ [kad][mad].pgo;
+ rad = PAGE_SIZE;
+ }
+ more = over;
+ if (rad < more)
+ more = rad;
+ over -= more;
+ pad += more;
+ rad -= more;
+ } while (over);
+ }
+/*---------------------------------------------------------------------------*/
+/*
+ * PROCESS ONE LINE OF FRAME AT REDUCED RESOLUTION:
+ * ONLY IF false==odd,
+ * READ w2 BYTES FROM FIELD BUFFER,
+ * WRITE w3 / 2 BYTES TO FRAME BUFFER
+ */
+/*---------------------------------------------------------------------------*/
+ } else if (false == odd) {
+ over = w2;
+ do {
+ much = over; more = 0; margin = 0; mask = 0x00;
+ if (rex < much)
+ much = rex;
+ rump = 0;
+
+ if (much % 2) {
+ SAY("MISTAKE: much is odd\n");
+ return -EFAULT;
+ }
+
+ more = (bytesperpixel * \
+ much) / 4;
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+ if (1 < bytesperpixel) {
+ if ((rad * 4) < (much * \
+ bytesperpixel)) {
+ /*
+ ** INJUDICIOUS ALTERATION OF THIS
+ ** BLOCK WILL CAUSE BREAKAGE.
+ ** BEWARE.
+ **/
+ rad2 = rad + bytesperpixel - 1;
+ much = ((((2 * rad2)/bytesperpixel)/2)\
+ * 4);
+ rump = ((bytesperpixel * \
+ much) / 4) - rad;
+ more = rad;
+ }
+ mask = (__u8)rump;
+ margin = 0;
+ if (much == rex) {
+ mask |= 0x04;
+ if ((mex + 1) < FIELD_BUFFER_SIZE/ \
+ PAGE_SIZE) {
+ margin = *((__u8 *)(peasycap->\
+ field_buffer\
+ [kex][mex + 1].pgo));
+ }
+ else
+ mask |= 0x08;
+ }
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+ } else {
+ SAY("MISTAKE: %i=bytesperpixel\n", \
+ bytesperpixel);
+ return -EFAULT;
+ }
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+ if (rump)
+ caches++;
+
+ rc = redaub(peasycap, pad, pex, much, more, \
+ mask, margin, isuy);
+ if (0 > rc) {
+ SAY("ERROR: redaub() failed\n");
+ return -EFAULT;
+ }
+ over -= much; cz += much;
+ pex += much; rex -= much;
+ if (!rex) {
+ mex++;
+ pex = peasycap->field_buffer[kex][mex].pgo;
+ rex = PAGE_SIZE;
+ }
+ pad += more;
+ rad -= more;
+ if (!rad) {
+ mad++;
+ pad = peasycap->frame_buffer[kad][mad].pgo;
+ rad = PAGE_SIZE;
+ if (rump) {
+ pad += rump;
+ rad -= rump;
+ }
+ }
+ } while (over);
+/*---------------------------------------------------------------------------*/
+/*
+ * OTHERWISE JUST
+ * READ w2 BYTES FROM FIELD BUFFER AND DISCARD THEM
+ */
+/*---------------------------------------------------------------------------*/
+ } else {
+ over = w2;
+ do {
+ if (!rex) {
+ mex++;
+ pex = peasycap->field_buffer[kex][mex].pgo;
+ rex = PAGE_SIZE;
+ }
+ much = over;
+ if (rex < much)
+ much = rex;
+ over -= much;
+ cz += much;
+ pex += much;
+ rex -= much;
+ } while (over);
+ }
+}
+/*---------------------------------------------------------------------------*/
+/*
+ * SANITY CHECKS
+ */
+/*---------------------------------------------------------------------------*/
+c2 = (mex + 1)*PAGE_SIZE - rex;
+if (cz != c2)
+ SAY("ERROR: discrepancy %i in bytes read\n", c2 - cz);
+c3 = (mad + 1)*PAGE_SIZE - rad;
+
+if (false == decimatepixel) {
+ if (bytesperpixel * \
+ cz != c3) \
+ SAY("ERROR: discrepancy %i in bytes written\n", \
+ c3 - (bytesperpixel * \
+ cz));
+} else {
+ if (false == odd) {
+ if (bytesperpixel * \
+ cz != (4 * c3))
+ SAY("ERROR: discrepancy %i in bytes written\n", \
+ (2*c3)-(bytesperpixel * \
+ cz));
+ } else {
+ if (0 != c3)
+ SAY("ERROR: discrepancy %i " \
+ "in bytes written\n", c3);
+ }
+}
+if (rump)
+ SAY("ERROR: undischarged cache at end of line in frame buffer\n");
+
+JOT(8, "===== field2frame(): %i bytes --> %i bytes (incl skip)\n", c2, c3);
+JOT(8, "===== field2frame(): %i=mad %i=rad\n", mad, rad);
+
+if (true == odd)
+ JOT(8, "+++++ field2frame(): frame buffer %i is full\n", kad);
+
+if (peasycap->field_read == peasycap->field_fill)
+ SAY("WARNING: on exit, filling field buffer %i\n", \
+ peasycap->field_read);
+/*---------------------------------------------------------------------------*/
+/*
+ * CALCULATE VIDEO STREAMING RATE
+ */
+/*---------------------------------------------------------------------------*/
+do_gettimeofday(&timeval);
+if (timeval0.tv_sec) {
+ below = ((long long int)(1000000)) * \
+ ((long long int)(timeval.tv_sec - timeval0.tv_sec)) + \
+ (long long int)(timeval.tv_usec - timeval0.tv_usec);
+ above = (long long int)1000000;
+
+ sdr = signed_div(above, below);
+ above = sdr.quotient;
+ remainder = (__u32)sdr.remainder;
+
+ JOT(8, "video streaming at %3lli.%03i fields per second\n", above, \
+ (remainder/1000));
+}
+timeval0 = timeval;
+
+if (caches)
+ JOT(8, "%i=caches\n", caches);
+return 0;
+}
+/*****************************************************************************/
+struct signed_div_result
+signed_div(long long int above, long long int below)
+{
+struct signed_div_result sdr;
+
+if (((0 <= above) && (0 <= below)) || ((0 > above) && (0 > below))) {
+ sdr.remainder = (unsigned long long int) do_div(above, below);
+ sdr.quotient = (long long int) above;
+} else {
+ if (0 > above)
+ above = -above;
+ if (0 > below)
+ below = -below;
+ sdr.remainder = (unsigned long long int) do_div(above, below);
+ sdr.quotient = -((long long int) above);
+}
+return sdr;
+}
+/*****************************************************************************/
+/*---------------------------------------------------------------------------*/
+/*
+ * DECIMATION AND COLOURSPACE CONVERSION.
+ *
+ * THIS ROUTINE REQUIRES THAT ALL THE DATA TO BE READ RESIDES ON ONE PAGE
+ * AND THAT ALL THE DATA TO BE WRITTEN RESIDES ON ONE (DIFFERENT) PAGE.
+ * THE CALLING ROUTINE MUST ENSURE THAT THIS REQUIREMENT IS MET, AND MUST
+ * ALSO ENSURE THAT much IS EVEN.
+ *
+ * much BYTES ARE READ, AT LEAST (bytesperpixel * much)/2 BYTES ARE WRITTEN
+ * IF THERE IS NO DECIMATION, HALF THIS AMOUNT IF THERE IS DECIMATION.
+ *
+ * mask IS ZERO WHEN NO SPECIAL BEHAVIOUR REQUIRED. OTHERWISE IT IS SET THUS:
+ * 0x03 & mask = number of bytes to be written to cache instead of to
+ * frame buffer
+ * 0x04 & mask => use argument margin to set the chrominance for last pixel
+ * 0x08 & mask => do not set the chrominance for last pixel
+ *
+ * YUV to RGB CONVERSION IS (OR SHOULD BE) ITU-R BT 601.
+ *
+ * THERE IS A LOT OF CODE REPETITION IN THIS ROUTINE IN ORDER TO AVOID
+ * INEFFICIENT SWITCHING INSIDE INNER LOOPS. REARRANGING THE LOGIC TO
+ * REDUCE CODE LENGTH WILL GENERALLY IMPAIR RUNTIME PERFORMANCE. BEWARE.
+ */
+/*---------------------------------------------------------------------------*/
+int
+redaub(struct easycap *peasycap, void *pad, void *pex, int much, int more, \
+ __u8 mask, __u8 margin, bool isuy)
+{
+static __s32 ay[256], bu[256], rv[256], gu[256], gv[256];
+static __u8 cache[8], *pcache;
+__u8 r, g, b, y, u, v, c, *p2, *p3, *pz, *pr;
+int bytesperpixel;
+bool byteswaporder, decimatepixel, last;
+int j, rump;
+__s32 s32;
+
+if (much % 2) {
+ SAY("MISTAKE: much is odd\n");
+ return -EFAULT;
+}
+bytesperpixel = peasycap->bytesperpixel;
+byteswaporder = peasycap->byteswaporder;
+decimatepixel = peasycap->decimatepixel;
+
+/*---------------------------------------------------------------------------*/
+if (!bu[255]) {
+ for (j = 0; j < 112; j++) {
+ s32 = (0xFF00 & (453 * j)) >> 8;
+ bu[j + 128] = s32; bu[127 - j] = -s32;
+ s32 = (0xFF00 & (359 * j)) >> 8;
+ rv[j + 128] = s32; rv[127 - j] = -s32;
+ s32 = (0xFF00 & (88 * j)) >> 8;
+ gu[j + 128] = s32; gu[127 - j] = -s32;
+ s32 = (0xFF00 & (183 * j)) >> 8;
+ gv[j + 128] = s32; gv[127 - j] = -s32;
+ }
+ for (j = 0; j < 16; j++) {
+ bu[j] = bu[16]; rv[j] = rv[16];
+ gu[j] = gu[16]; gv[j] = gv[16];
+ }
+ for (j = 240; j < 256; j++) {
+ bu[j] = bu[239]; rv[j] = rv[239];
+ gu[j] = gu[239]; gv[j] = gv[239];
+ }
+ for (j = 16; j < 236; j++)
+ ay[j] = j;
+ for (j = 0; j < 16; j++)
+ ay[j] = ay[16];
+ for (j = 236; j < 256; j++)
+ ay[j] = ay[235];
+ JOT(8, "lookup tables are prepared\n");
+}
+if ((__u8 *)NULL == pcache)
+ pcache = &cache[0];
+/*---------------------------------------------------------------------------*/
+/*
+ * TRANSFER CONTENTS OF CACHE TO THE FRAME BUFFER
+ */
+/*---------------------------------------------------------------------------*/
+if (!pcache) {
+ SAY("MISTAKE: pcache is NULL\n");
+ return -EFAULT;
+}
+
+if (pcache != &cache[0])
+ JOT(16, "cache has %i bytes\n", (int)(pcache - &cache[0]));
+p2 = &cache[0];
+p3 = (__u8 *)pad - (int)(pcache - &cache[0]);
+while (p2 < pcache) {
+ *p3++ = *p2; p2++;
+}
+pcache = &cache[0];
+if (p3 != pad) {
+ SAY("MISTAKE: pointer misalignment\n");
+ return -EFAULT;
+}
+/*---------------------------------------------------------------------------*/
+rump = (int)(0x03 & mask);
+u = 0; v = 0;
+p2 = (__u8 *)pex; pz = p2 + much; pr = p3 + more; last = false;
+p2++;
+
+if (true == isuy)
+ u = *(p2 - 1);
+else
+ v = *(p2 - 1);
+
+if (rump)
+ JOT(16, "%4i=much %4i=more %i=rump\n", much, more, rump);
+
+/*---------------------------------------------------------------------------*/
+switch (bytesperpixel) {
+case 2: {
+ if (false == decimatepixel) {
+ memcpy(pad, pex, (size_t)much);
+ if (false == byteswaporder)
+ /*---------------------------------------------------*/
+ /*
+ ** UYVY
+ */
+ /*---------------------------------------------------*/
+ return 0;
+ else {
+ /*---------------------------------------------------*/
+ /*
+ ** YUYV
+ */
+ /*---------------------------------------------------*/
+ p3 = (__u8 *)pad; pz = p3 + much;
+ while (pz > p3) {
+ c = *p3;
+ *p3 = *(p3 + 1);
+ *(p3 + 1) = c;
+ p3 += 2;
+ }
+ return 0;
+ }
+ } else {
+ if (false == byteswaporder) {
+ /*---------------------------------------------------*/
+ /*
+ ** UYVY DECIMATED
+ */
+ /*---------------------------------------------------*/
+ p2 = (__u8 *)pex; p3 = (__u8 *)pad; pz = p2 + much;
+ while (pz > p2) {
+ *p3 = *p2;
+ *(p3 + 1) = *(p2 + 1);
+ *(p3 + 2) = *(p2 + 2);
+ *(p3 + 3) = *(p2 + 3);
+ p3 += 4; p2 += 8;
+ }
+ return 0;
+ } else {
+ /*---------------------------------------------------*/
+ /*
+ ** YUYV DECIMATED
+ **/
+ /*---------------------------------------------------*/
+ p2 = (__u8 *)pex; p3 = (__u8 *)pad; pz = p2 + much;
+ while (pz > p2) {
+ *p3 = *(p2 + 1);
+ *(p3 + 1) = *p2;
+ *(p3 + 2) = *(p2 + 3);
+ *(p3 + 3) = *(p2 + 2);
+ p3 += 4; p2 += 8;
+ }
+ return 0;
+ }
+ }
+ break;
+ }
+case 3:
+ {
+ if (false == decimatepixel) {
+ if (false == byteswaporder) {
+ /*---------------------------------------------------*/
+ /*
+ ** RGB
+ **/
+ /*---------------------------------------------------*/
+ while (pz > p2) {
+ if (pr <= (p3 + bytesperpixel))
+ last = true;
+ else
+ last = false;
+ y = *p2;
+ if ((true == last) && (0x0C & mask)) {
+ if (0x04 & mask) {
+ if (true == isuy)
+ v = margin;
+ else
+ u = margin;
+ } else
+ if (0x08 & mask)
+ ;
+ } else {
+ if (true == isuy)
+ v = *(p2 + 1);
+ else
+ u = *(p2 + 1);
+ }
+
+ s32 = ay[(int)y] + rv[(int)v];
+ r = (255 < s32) ? 255 : ((0 > s32) ? \
+ 0 : (__u8)s32);
+ s32 = ay[(int)y] - gu[(int)u] - gv[(int)v];
+ g = (255 < s32) ? 255 : ((0 > s32) ? \
+ 0 : (__u8)s32);
+ s32 = ay[(int)y] + bu[(int)u];
+ b = (255 < s32) ? 255 : ((0 > s32) ? \
+ 0 : (__u8)s32);
+
+ if ((true == last) && rump) {
+ pcache = &cache[0];
+ switch (bytesperpixel - rump) {
+ case 1: {
+ *p3 = r;
+ *pcache++ = g;
+ *pcache++ = b;
+ break;
+ }
+ case 2: {
+ *p3 = r;
+ *(p3 + 1) = g;
+ *pcache++ = b;
+ break;
+ }
+ default: {
+ SAY("MISTAKE: %i=rump\n", \
+ bytesperpixel - rump);
+ return -EFAULT;
+ }
+ }
+ } else {
+ *p3 = r;
+ *(p3 + 1) = g;
+ *(p3 + 2) = b;
+ }
+ p2 += 2;
+ if (true == isuy)
+ isuy = false;
+ else
+ isuy = true;
+ p3 += bytesperpixel;
+ }
+ return 0;
+ } else {
+ /*---------------------------------------------------*/
+ /*
+ ** BGR
+ */
+ /*---------------------------------------------------*/
+ while (pz > p2) {
+ if (pr <= (p3 + bytesperpixel))
+ last = true;
+ else
+ last = false;
+ y = *p2;
+ if ((true == last) && (0x0C & mask)) {
+ if (0x04 & mask) {
+ if (true == isuy)
+ v = margin;
+ else
+ u = margin;
+ }
+ else
+ if (0x08 & mask)
+ ;
+ } else {
+ if (true == isuy)
+ v = *(p2 + 1);
+ else
+ u = *(p2 + 1);
+ }
+
+ s32 = ay[(int)y] + rv[(int)v];
+ r = (255 < s32) ? 255 : ((0 > s32) ? \
+ 0 : (__u8)s32);
+ s32 = ay[(int)y] - gu[(int)u] - gv[(int)v];
+ g = (255 < s32) ? 255 : ((0 > s32) ? \
+ 0 : (__u8)s32);
+ s32 = ay[(int)y] + bu[(int)u];
+ b = (255 < s32) ? 255 : ((0 > s32) ? \
+ 0 : (__u8)s32);
+
+ if ((true == last) && rump) {
+ pcache = &cache[0];
+ switch (bytesperpixel - rump) {
+ case 1: {
+ *p3 = b;
+ *pcache++ = g;
+ *pcache++ = r;
+ break;
+ }
+ case 2: {
+ *p3 = b;
+ *(p3 + 1) = g;
+ *pcache++ = r;
+ break;
+ }
+ default: {
+ SAY("MISTAKE: %i=rump\n", \
+ bytesperpixel - rump);
+ return -EFAULT;
+ }
+ }
+ } else {
+ *p3 = b;
+ *(p3 + 1) = g;
+ *(p3 + 2) = r;
+ }
+ p2 += 2;
+ if (true == isuy)
+ isuy = false;
+ else
+ isuy = true;
+ p3 += bytesperpixel;
+ }
+ }
+ return 0;
+ } else {
+ if (false == byteswaporder) {
+ /*---------------------------------------------------*/
+ /*
+ ** RGB DECIMATED
+ */
+ /*---------------------------------------------------*/
+ while (pz > p2) {
+ if (pr <= (p3 + bytesperpixel))
+ last = true;
+ else
+ last = false;
+ y = *p2;
+ if ((true == last) && (0x0C & mask)) {
+ if (0x04 & mask) {
+ if (true == isuy)
+ v = margin;
+ else
+ u = margin;
+ } else
+ if (0x08 & mask)
+ ;
+ } else {
+ if (true == isuy)
+ v = *(p2 + 1);
+ else
+ u = *(p2 + 1);
+ }
+
+ if (true == isuy) {
+ s32 = ay[(int)y] + rv[(int)v];
+ r = (255 < s32) ? 255 : ((0 > s32) ? \
+ 0 : (__u8)s32);
+ s32 = ay[(int)y] - gu[(int)u] - \
+ gv[(int)v];
+ g = (255 < s32) ? 255 : ((0 > s32) ? \
+ 0 : (__u8)s32);
+ s32 = ay[(int)y] + bu[(int)u];
+ b = (255 < s32) ? 255 : ((0 > s32) ? \
+ 0 : (__u8)s32);
+
+ if ((true == last) && rump) {
+ pcache = &cache[0];
+ switch (bytesperpixel - rump) {
+ case 1: {
+ *p3 = r;
+ *pcache++ = g;
+ *pcache++ = b;
+ break;
+ }
+ case 2: {
+ *p3 = r;
+ *(p3 + 1) = g;
+ *pcache++ = b;
+ break;
+ }
+ default: {
+ SAY("MISTAKE: " \
+ "%i=rump\n", \
+ bytesperpixel - rump);
+ return -EFAULT;
+ }
+ }
+ } else {
+ *p3 = r;
+ *(p3 + 1) = g;
+ *(p3 + 2) = b;
+ }
+ isuy = false;
+ p3 += bytesperpixel;
+ } else {
+ isuy = true;
+ }
+ p2 += 2;
+ }
+ return 0;
+ } else {
+ /*---------------------------------------------------*/
+ /*
+ * BGR DECIMATED
+ */
+ /*---------------------------------------------------*/
+ while (pz > p2) {
+ if (pr <= (p3 + bytesperpixel))
+ last = true;
+ else
+ last = false;
+ y = *p2;
+ if ((true == last) && (0x0C & mask)) {
+ if (0x04 & mask) {
+ if (true == isuy)
+ v = margin;
+ else
+ u = margin;
+ } else
+ if (0x08 & mask)
+ ;
+ } else {
+ if (true == isuy)
+ v = *(p2 + 1);
+ else
+ u = *(p2 + 1);
+ }
+
+ if (true == isuy) {
+
+ s32 = ay[(int)y] + rv[(int)v];
+ r = (255 < s32) ? 255 : ((0 > s32) ? \
+ 0 : (__u8)s32);
+ s32 = ay[(int)y] - gu[(int)u] - \
+ gv[(int)v];
+ g = (255 < s32) ? 255 : ((0 > s32) ? \
+ 0 : (__u8)s32);
+ s32 = ay[(int)y] + bu[(int)u];
+ b = (255 < s32) ? 255 : ((0 > s32) ? \
+ 0 : (__u8)s32);
+
+ if ((true == last) && rump) {
+ pcache = &cache[0];
+ switch (bytesperpixel - rump) {
+ case 1: {
+ *p3 = b;
+ *pcache++ = g;
+ *pcache++ = r;
+ break;
+ }
+ case 2: {
+ *p3 = b;
+ *(p3 + 1) = g;
+ *pcache++ = r;
+ break;
+ }
+ default: {
+ SAY("MISTAKE: " \
+ "%i=rump\n", \
+ bytesperpixel - rump);
+ return -EFAULT;
+ }
+ }
+ } else {
+ *p3 = b;
+ *(p3 + 1) = g;
+ *(p3 + 2) = r;
+ }
+ isuy = false;
+ p3 += bytesperpixel;
+ }
+ else
+ isuy = true;
+ p2 += 2;
+ }
+ return 0;
+ }
+ }
+ break;
+ }
+case 4:
+ {
+ if (false == decimatepixel) {
+ if (false == byteswaporder) {
+ /*---------------------------------------------------*/
+ /*
+ ** RGBA
+ */
+ /*---------------------------------------------------*/
+ while (pz > p2) {
+ if (pr <= (p3 + bytesperpixel))
+ last = true;
+ else
+ last = false;
+ y = *p2;
+ if ((true == last) && (0x0C & mask)) {
+ if (0x04 & mask) {
+ if (true == isuy)
+ v = margin;
+ else
+ u = margin;
+ } else
+ if (0x08 & mask)
+ ;
+ } else {
+ if (true == isuy)
+ v = *(p2 + 1);
+ else
+ u = *(p2 + 1);
+ }
+
+ s32 = ay[(int)y] + rv[(int)v];
+ r = (255 < s32) ? 255 : ((0 > s32) ? \
+ 0 : (__u8)s32);
+ s32 = ay[(int)y] - gu[(int)u] - gv[(int)v];
+ g = (255 < s32) ? 255 : ((0 > s32) ? \
+ 0 : (__u8)s32);
+ s32 = ay[(int)y] + bu[(int)u];
+ b = (255 < s32) ? 255 : ((0 > s32) ? \
+ 0 : (__u8)s32);
+
+ if ((true == last) && rump) {
+ pcache = &cache[0];
+ switch (bytesperpixel - rump) {
+ case 1: {
+ *p3 = r;
+ *pcache++ = g;
+ *pcache++ = b;
+ *pcache++ = 0;
+ break;
+ }
+ case 2: {
+ *p3 = r;
+ *(p3 + 1) = g;
+ *pcache++ = b;
+ *pcache++ = 0;
+ break;
+ }
+ case 3: {
+ *p3 = r;
+ *(p3 + 1) = g;
+ *(p3 + 2) = b;
+ *pcache++ = 0;
+ break;
+ }
+ default: {
+ SAY("MISTAKE: %i=rump\n", \
+ bytesperpixel - rump);
+ return -EFAULT;
+ }
+ }
+ } else {
+ *p3 = r;
+ *(p3 + 1) = g;
+ *(p3 + 2) = b;
+ *(p3 + 3) = 0;
+ }
+ p2 += 2;
+ if (true == isuy)
+ isuy = false;
+ else
+ isuy = true;
+ p3 += bytesperpixel;
+ }
+ return 0;
+ } else {
+ /*---------------------------------------------------*/
+ /*
+ ** BGRA
+ */
+ /*---------------------------------------------------*/
+ while (pz > p2) {
+ if (pr <= (p3 + bytesperpixel))
+ last = true;
+ else
+ last = false;
+ y = *p2;
+ if ((true == last) && (0x0C & mask)) {
+ if (0x04 & mask) {
+ if (true == isuy)
+ v = margin;
+ else
+ u = margin;
+ } else
+ if (0x08 & mask)
+ ;
+ } else {
+ if (true == isuy)
+ v = *(p2 + 1);
+ else
+ u = *(p2 + 1);
+ }
+
+ s32 = ay[(int)y] + rv[(int)v];
+ r = (255 < s32) ? 255 : ((0 > s32) ? \
+ 0 : (__u8)s32);
+ s32 = ay[(int)y] - gu[(int)u] - gv[(int)v];
+ g = (255 < s32) ? 255 : ((0 > s32) ? \
+ 0 : (__u8)s32);
+ s32 = ay[(int)y] + bu[(int)u];
+ b = (255 < s32) ? 255 : ((0 > s32) ? \
+ 0 : (__u8)s32);
+
+ if ((true == last) && rump) {
+ pcache = &cache[0];
+ switch (bytesperpixel - rump) {
+ case 1: {
+ *p3 = b;
+ *pcache++ = g;
+ *pcache++ = r;
+ *pcache++ = 0;
+ break;
+ }
+ case 2: {
+ *p3 = b;
+ *(p3 + 1) = g;
+ *pcache++ = r;
+ *pcache++ = 0;
+ break;
+ }
+ case 3: {
+ *p3 = b;
+ *(p3 + 1) = g;
+ *(p3 + 2) = r;
+ *pcache++ = 0;
+ break;
+ }
+ default: {
+ SAY("MISTAKE: %i=rump\n", \
+ bytesperpixel - rump);
+ return -EFAULT;
+ }
+ }
+ } else {
+ *p3 = b;
+ *(p3 + 1) = g;
+ *(p3 + 2) = r;
+ *(p3 + 3) = 0;
+ }
+ p2 += 2;
+ if (true == isuy)
+ isuy = false;
+ else
+ isuy = true;
+ p3 += bytesperpixel;
+ }
+ }
+ return 0;
+ } else {
+ if (false == byteswaporder) {
+ /*---------------------------------------------------*/
+ /*
+ ** RGBA DECIMATED
+ */
+ /*---------------------------------------------------*/
+ while (pz > p2) {
+ if (pr <= (p3 + bytesperpixel))
+ last = true;
+ else
+ last = false;
+ y = *p2;
+ if ((true == last) && (0x0C & mask)) {
+ if (0x04 & mask) {
+ if (true == isuy)
+ v = margin;
+ else
+ u = margin;
+ } else
+ if (0x08 & mask)
+ ;
+ } else {
+ if (true == isuy)
+ v = *(p2 + 1);
+ else
+ u = *(p2 + 1);
+ }
+
+ if (true == isuy) {
+
+ s32 = ay[(int)y] + rv[(int)v];
+ r = (255 < s32) ? 255 : ((0 > s32) ? \
+ 0 : (__u8)s32);
+ s32 = ay[(int)y] - gu[(int)u] - \
+ gv[(int)v];
+ g = (255 < s32) ? 255 : ((0 > s32) ? \
+ 0 : (__u8)s32);
+ s32 = ay[(int)y] + bu[(int)u];
+ b = (255 < s32) ? 255 : ((0 > s32) ? \
+ 0 : (__u8)s32);
+
+ if ((true == last) && rump) {
+ pcache = &cache[0];
+ switch (bytesperpixel - rump) {
+ case 1: {
+ *p3 = r;
+ *pcache++ = g;
+ *pcache++ = b;
+ *pcache++ = 0;
+ break;
+ }
+ case 2: {
+ *p3 = r;
+ *(p3 + 1) = g;
+ *pcache++ = b;
+ *pcache++ = 0;
+ break;
+ }
+ case 3: {
+ *p3 = r;
+ *(p3 + 1) = g;
+ *(p3 + 2) = b;
+ *pcache++ = 0;
+ break;
+ }
+ default: {
+ SAY("MISTAKE: " \
+ "%i=rump\n", \
+ bytesperpixel - \
+ rump);
+ return -EFAULT;
+ }
+ }
+ } else {
+ *p3 = r;
+ *(p3 + 1) = g;
+ *(p3 + 2) = b;
+ *(p3 + 3) = 0;
+ }
+ isuy = false;
+ p3 += bytesperpixel;
+ } else
+ isuy = true;
+ p2 += 2;
+ }
+ return 0;
+ } else {
+ /*---------------------------------------------------*/
+ /*
+ ** BGRA DECIMATED
+ */
+ /*---------------------------------------------------*/
+ while (pz > p2) {
+ if (pr <= (p3 + bytesperpixel))
+ last = true;
+ else
+ last = false;
+ y = *p2;
+ if ((true == last) && (0x0C & mask)) {
+ if (0x04 & mask) {
+ if (true == isuy)
+ v = margin;
+ else
+ u = margin;
+ } else
+ if (0x08 & mask)
+ ;
+ } else {
+ if (true == isuy)
+ v = *(p2 + 1);
+ else
+ u = *(p2 + 1);
+ }
+
+ if (true == isuy) {
+ s32 = ay[(int)y] + rv[(int)v];
+ r = (255 < s32) ? 255 : ((0 > s32) ? \
+ 0 : (__u8)s32);
+ s32 = ay[(int)y] - gu[(int)u] - \
+ gv[(int)v];
+ g = (255 < s32) ? 255 : ((0 > s32) ? \
+ 0 : (__u8)s32);
+ s32 = ay[(int)y] + bu[(int)u];
+ b = (255 < s32) ? 255 : ((0 > s32) ? \
+ 0 : (__u8)s32);
+
+ if ((true == last) && rump) {
+ pcache = &cache[0];
+ switch (bytesperpixel - rump) {
+ case 1: {
+ *p3 = b;
+ *pcache++ = g;
+ *pcache++ = r;
+ *pcache++ = 0;
+ break;
+ }
+ case 2: {
+ *p3 = b;
+ *(p3 + 1) = g;
+ *pcache++ = r;
+ *pcache++ = 0;
+ break;
+ }
+ case 3: {
+ *p3 = b;
+ *(p3 + 1) = g;
+ *(p3 + 2) = r;
+ *pcache++ = 0;
+ break;
+ }
+ default: {
+ SAY("MISTAKE: " \
+ "%i=rump\n", \
+ bytesperpixel - rump);
+ return -EFAULT;
+ }
+ }
+ } else {
+ *p3 = b;
+ *(p3 + 1) = g;
+ *(p3 + 2) = r;
+ *(p3 + 3) = 0;
+ }
+ isuy = false;
+ p3 += bytesperpixel;
+ } else
+ isuy = true;
+ p2 += 2;
+ }
+ return 0;
+ }
+ }
+ break;
+ }
+default: {
+ SAY("MISTAKE: %i=bytesperpixel\n", bytesperpixel);
+ return -EFAULT;
+ }
+}
+return 0;
+}
+/*****************************************************************************/
+void
+debrief(struct easycap *peasycap)
+{
+if ((struct usb_device *)NULL != peasycap->pusb_device) {
+ check_stk(peasycap->pusb_device);
+ check_saa(peasycap->pusb_device);
+ sayreadonly(peasycap);
+ SAY("%i=peasycap->field_fill\n", peasycap->field_fill);
+ SAY("%i=peasycap->field_read\n", peasycap->field_read);
+ SAY("%i=peasycap->frame_fill\n", peasycap->frame_fill);
+ SAY("%i=peasycap->frame_read\n", peasycap->frame_read);
+}
+return;
+}
+/*****************************************************************************/
+void
+sayreadonly(struct easycap *peasycap)
+{
+static int done;
+int got00, got1F, got60, got61, got62;
+
+if ((!done) && ((struct usb_device *)NULL != peasycap->pusb_device)) {
+ done = 1;
+ got00 = read_saa(peasycap->pusb_device, 0x00);
+ got1F = read_saa(peasycap->pusb_device, 0x1F);
+ got60 = read_saa(peasycap->pusb_device, 0x60);
+ got61 = read_saa(peasycap->pusb_device, 0x61);
+ got62 = read_saa(peasycap->pusb_device, 0x62);
+ SAY("0x%02X=reg0x00 0x%02X=reg0x1F\n", got00, got1F);
+ SAY("0x%02X=reg0x60 0x%02X=reg0x61 0x%02X=reg0x62\n", \
+ got60, got61, got62);
+}
+return;
+}
+/*****************************************************************************/
+/*---------------------------------------------------------------------------*/
+/*
+ * SEE CORBET ET AL. "LINUX DEVICE DRIVERS", 3rd EDITION, PAGES 430-434
+ */
+/*---------------------------------------------------------------------------*/
+int easycap_mmap(struct file *file, struct vm_area_struct *pvma)
+{
+
+JOT(8, "\n");
+
+pvma->vm_ops = &easycap_vm_ops;
+pvma->vm_flags |= VM_RESERVED;
+if (NULL != file)
+ pvma->vm_private_data = file->private_data;
+easycap_vma_open(pvma);
+return 0;
+}
+/*****************************************************************************/
+void
+easycap_vma_open(struct vm_area_struct *pvma)
+{
+struct easycap *peasycap;
+
+peasycap = pvma->vm_private_data;
+if (NULL != peasycap)
+ peasycap->vma_many++;
+
+JOT(8, "%i=peasycap->vma_many\n", peasycap->vma_many);
+
+return;
+}
+/*****************************************************************************/
+void
+easycap_vma_close(struct vm_area_struct *pvma)
+{
+struct easycap *peasycap;
+
+peasycap = pvma->vm_private_data;
+if (NULL != peasycap) {
+ peasycap->vma_many--;
+ JOT(8, "%i=peasycap->vma_many\n", peasycap->vma_many);
+}
+return;
+}
+/*****************************************************************************/
+int
+easycap_vma_fault(struct vm_area_struct *pvma, struct vm_fault *pvmf)
+{
+int k, m, retcode;
+void *pbuf;
+struct page *page;
+struct easycap *peasycap;
+
+retcode = VM_FAULT_NOPAGE;
+pbuf = (void *)NULL;
+page = (struct page *)NULL;
+
+if (NULL == pvma) {
+ SAY("pvma is NULL\n");
+ return retcode;
+}
+if (NULL == pvmf) {
+ SAY("pvmf is NULL\n");
+ return retcode;
+}
+
+k = (pvmf->pgoff) / (FRAME_BUFFER_SIZE/PAGE_SIZE);
+m = (pvmf->pgoff) % (FRAME_BUFFER_SIZE/PAGE_SIZE);
+
+if (!m)
+ JOT(4, "%4i=k, %4i=m\n", k, m);
+else
+ JOT(16, "%4i=k, %4i=m\n", k, m);
+
+if ((0 > k) || (FRAME_BUFFER_MANY <= k)) {
+ SAY("ERROR: buffer index %i out of range\n", k);
+ return retcode;
+}
+if ((0 > m) || (FRAME_BUFFER_SIZE/PAGE_SIZE <= m)) {
+ SAY("ERROR: page number %i out of range\n", m);
+ return retcode;
+}
+peasycap = pvma->vm_private_data;
+if (NULL == peasycap) {
+ SAY("ERROR: peasycap is NULL\n");
+ return retcode;
+}
+mutex_lock(&(peasycap->mutex_mmap_video[0]));
+/*---------------------------------------------------------------------------*/
+pbuf = peasycap->frame_buffer[k][m].pgo;
+if (NULL == pbuf) {
+ SAY("ERROR: pbuf is NULL\n");
+ goto finish;
+}
+page = virt_to_page(pbuf);
+if (NULL == page) {
+ SAY("ERROR: page is NULL\n");
+ goto finish;
+}
+get_page(page);
+/*---------------------------------------------------------------------------*/
+finish:
+mutex_unlock(&(peasycap->mutex_mmap_video[0]));
+if (NULL == page) {
+ SAY("ERROR: page is NULL after get_page(page)\n");
+} else {
+ pvmf->page = page;
+ retcode = VM_FAULT_MINOR;
+}
+return retcode;
+}
+/*****************************************************************************/
+/*---------------------------------------------------------------------------*/
+/*
+ * ON COMPLETION OF A VIDEO URB ITS DATA IS COPIED TO THE FIELD BUFFERS
+ * PROVIDED peasycap->video_idle IS ZER0. REGARDLESS OF THIS BEING TRUE,
+ * IT IS RESUBMITTED PROVIDED peasycap->video_isoc_streaming IS NOT ZERO.
+ *
+ * THIS FUNCTION IS AN INTERRUPT SERVICE ROUTINE AND MUST NOT SLEEP.
+ *
+ * INFORMATION ABOUT THE VALIDITY OF THE CONTENTS OF THE FIELD BUFFER ARE
+ * STORED IN THE TWO-BYTE STATUS PARAMETER
+ * peasycap->field_buffer[peasycap->field_fill][0].kount
+ * NOTICE THAT THE INFORMATION IS STORED ONLY WITH PAGE 0 OF THE FIELD BUFFER.
+ *
+ * THE LOWER BYTE CONTAINS THE FIELD PARITY BYTE FURNISHED BY THE SAA7113H
+ * CHIP.
+ *
+ * THE UPPER BYTE IS ZERO IF NO PROBLEMS, OTHERWISE:
+ * 0 != (kount & 0x8000) => AT LEAST ONE URB COMPLETED WITH ERRORS
+ * 0 != (kount & 0x4000) => BUFFER HAS TOO MUCH DATA
+ * 0 != (kount & 0x2000) => BUFFER HAS NOT ENOUGH DATA
+ * 0 != (kount & 0x0400) => FIELD WAS SUBMITTED BY BRIDGER ROUTINE
+ * 0 != (kount & 0x0200) => FIELD BUFFER NOT YET CHECKED
+ * 0 != (kount & 0x0100) => BUFFER HAS TWO EXTRA BYTES - WHY?
+ */
+/*---------------------------------------------------------------------------*/
+void
+easycap_complete(struct urb *purb)
+{
+static int mt;
+struct easycap *peasycap;
+struct data_buffer *pfield_buffer;
+char errbuf[16];
+int i, more, much, leap, rc, last;
+int videofieldamount;
+unsigned int override;
+int framestatus, framelength, frameactual, frameoffset;
+__u8 *pu;
+#if defined(BRIDGER)
+struct timeval timeval;
+long long usec;
+#endif /*BRIDGER*/
+
+if (NULL == purb) {
+ SAY("ERROR: easycap_complete(): purb is NULL\n");
+ return;
+}
+peasycap = purb->context;
+if (NULL == peasycap) {
+ SAY("ERROR: easycap_complete(): peasycap is NULL\n");
+ return;
+}
+
+if (peasycap->video_eof)
+ return;
+
+for (i = 0; i < VIDEO_ISOC_BUFFER_MANY; i++)
+ if (purb->transfer_buffer == peasycap->video_isoc_buffer[i].pgo)
+ break;
+JOT(16, "%2i=urb\n", i);
+last = peasycap->video_isoc_sequence;
+if ((((VIDEO_ISOC_BUFFER_MANY - 1) == last) && \
+ (0 != i)) || \
+ (((VIDEO_ISOC_BUFFER_MANY - 1) != last) && \
+ ((last + 1) != i))) {
+ SAY("ERROR: out-of-order urbs %i,%i ... continuing\n", last, i);
+}
+peasycap->video_isoc_sequence = i;
+
+if (peasycap->video_idle) {
+ JOT(16, "%i=video_idle %i=video_isoc_streaming\n", \
+ peasycap->video_idle, peasycap->video_isoc_streaming);
+ if (peasycap->video_isoc_streaming) {
+ rc = usb_submit_urb(purb, GFP_ATOMIC);
+ if (0 != rc) {
+ SAY("ERROR: while %i=video_idle, " \
+ "usb_submit_urb() failed with rc:\n", \
+ peasycap->video_idle);
+ switch (rc) {
+ case -ENOMEM: {
+ SAY("ENOMEM\n");
+ break;
+ }
+ case -ENODEV: {
+ SAY("ENODEV\n");
+ break;
+ }
+ case -ENXIO: {
+ SAY("ENXIO\n");
+ break;
+ }
+ case -EINVAL: {
+ SAY("EINVAL\n");
+ break;
+ }
+ case -EAGAIN: {
+ SAY("EAGAIN\n");
+ break;
+ }
+ case -EFBIG: {
+ SAY("EFBIG\n");
+ break;
+ }
+ case -EPIPE: {
+ SAY("EPIPE\n");
+ break;
+ }
+ case -EMSGSIZE: {
+ SAY("EMSGSIZE\n");
+ break;
+ }
+ case -ENOSPC: {
+ SAY("ENOSPC\n");
+ break;
+ }
+ default: {
+ SAY("0x%08X\n", rc);
+ break;
+ }
+ }
+ }
+ }
+return;
+}
+override = 0;
+/*---------------------------------------------------------------------------*/
+if (FIELD_BUFFER_MANY <= peasycap->field_fill) {
+ SAY("ERROR: bad peasycap->field_fill\n");
+ return;
+}
+if (purb->status) {
+ if ((-ESHUTDOWN == purb->status) || (-ENOENT == purb->status)) {
+ JOT(8, "urb status -ESHUTDOWN or -ENOENT\n");
+ return;
+ }
+
+ (peasycap->field_buffer[peasycap->field_fill][0].kount) |= 0x8000 ;
+ SAY("ERROR: bad urb status:\n");
+ switch (purb->status) {
+ case -EINPROGRESS: {
+ SAY("-EINPROGRESS\n"); break;
+ }
+ case -ENOSR: {
+ SAY("-ENOSR\n"); break;
+ }
+ case -EPIPE: {
+ SAY("-EPIPE\n"); break;
+ }
+ case -EOVERFLOW: {
+ SAY("-EOVERFLOW\n"); break;
+ }
+ case -EPROTO: {
+ SAY("-EPROTO\n"); break;
+ }
+ case -EILSEQ: {
+ SAY("-EILSEQ\n"); break;
+ }
+ case -ETIMEDOUT: {
+ SAY("-ETIMEDOUT\n"); break;
+ }
+ case -EMSGSIZE: {
+ SAY("-EMSGSIZE\n"); break;
+ }
+ case -EOPNOTSUPP: {
+ SAY("-EOPNOTSUPP\n"); break;
+ }
+ case -EPFNOSUPPORT: {
+ SAY("-EPFNOSUPPORT\n"); break;
+ }
+ case -EAFNOSUPPORT: {
+ SAY("-EAFNOSUPPORT\n"); break;
+ }
+ case -EADDRINUSE: {
+ SAY("-EADDRINUSE\n"); break;
+ }
+ case -EADDRNOTAVAIL: {
+ SAY("-EADDRNOTAVAIL\n"); break;
+ }
+ case -ENOBUFS: {
+ SAY("-ENOBUFS\n"); break;
+ }
+ case -EISCONN: {
+ SAY("-EISCONN\n"); break;
+ }
+ case -ENOTCONN: {
+ SAY("-ENOTCONN\n"); break;
+ }
+ case -ESHUTDOWN: {
+ SAY("-ESHUTDOWN\n"); break;
+ }
+ case -ENOENT: {
+ SAY("-ENOENT\n"); break;
+ }
+ case -ECONNRESET: {
+ SAY("-ECONNRESET\n"); break;
+ }
+ case -ENOSPC: {
+ SAY("ENOSPC\n"); break;
+ }
+ default: {
+ SAY("unknown error code 0x%08X\n", purb->status); break;
+ }
+ }
+/*---------------------------------------------------------------------------*/
+} else {
+ for (i = 0; i < purb->number_of_packets; i++) {
+ if (0 != purb->iso_frame_desc[i].status) {
+ (peasycap->field_buffer\
+ [peasycap->field_fill][0].kount) |= 0x8000 ;
+ switch (purb->iso_frame_desc[i].status) {
+ case 0: {
+ strcpy(&errbuf[0], "OK"); break;
+ }
+ case -ENOENT: {
+ strcpy(&errbuf[0], "-ENOENT"); break;
+ }
+ case -EINPROGRESS: {
+ strcpy(&errbuf[0], "-EINPROGRESS"); break;
+ }
+ case -EPROTO: {
+ strcpy(&errbuf[0], "-EPROTO"); break;
+ }
+ case -EILSEQ: {
+ strcpy(&errbuf[0], "-EILSEQ"); break;
+ }
+ case -ETIME: {
+ strcpy(&errbuf[0], "-ETIME"); break;
+ }
+ case -ETIMEDOUT: {
+ strcpy(&errbuf[0], "-ETIMEDOUT"); break;
+ }
+ case -EPIPE: {
+ strcpy(&errbuf[0], "-EPIPE"); break;
+ }
+ case -ECOMM: {
+ strcpy(&errbuf[0], "-ECOMM"); break;
+ }
+ case -ENOSR: {
+ strcpy(&errbuf[0], "-ENOSR"); break;
+ }
+ case -EOVERFLOW: {
+ strcpy(&errbuf[0], "-EOVERFLOW"); break;
+ }
+ case -EREMOTEIO: {
+ strcpy(&errbuf[0], "-EREMOTEIO"); break;
+ }
+ case -ENODEV: {
+ strcpy(&errbuf[0], "-ENODEV"); break;
+ }
+ case -EXDEV: {
+ strcpy(&errbuf[0], "-EXDEV"); break;
+ }
+ case -EINVAL: {
+ strcpy(&errbuf[0], "-EINVAL"); break;
+ }
+ case -ECONNRESET: {
+ strcpy(&errbuf[0], "-ECONNRESET"); break;
+ }
+ case -ENOSPC: {
+ SAY("ENOSPC\n"); break;
+ }
+ case -ESHUTDOWN: {
+ strcpy(&errbuf[0], "-ESHUTDOWN"); break;
+ }
+ default: {
+ strcpy(&errbuf[0], "unknown error"); break;
+ }
+ }
+ }
+ framestatus = purb->iso_frame_desc[i].status;
+ framelength = purb->iso_frame_desc[i].length;
+ frameactual = purb->iso_frame_desc[i].actual_length;
+ frameoffset = purb->iso_frame_desc[i].offset;
+
+ JOT(16, "frame[%2i]:" \
+ "%4i=status " \
+ "%4i=actual " \
+ "%4i=length " \
+ "%5i=offset\n", \
+ i, framestatus, frameactual, framelength, frameoffset);
+ if (!purb->iso_frame_desc[i].status) {
+ more = purb->iso_frame_desc[i].actual_length;
+ pfield_buffer = &peasycap->field_buffer\
+ [peasycap->field_fill][peasycap->field_page];
+ videofieldamount = (peasycap->field_page * \
+ PAGE_SIZE) + \
+ (int)(pfield_buffer->pto - pfield_buffer->pgo);
+ if (4 == more)
+ mt++;
+ if (4 < more) {
+ if (mt) {
+ JOT(8, "%4i empty video urb frames\n", mt);
+ mt = 0;
+ }
+ if (FIELD_BUFFER_MANY <= peasycap->field_fill) {
+ SAY("ERROR: bad peasycap->field_fill\n");
+ return;
+ }
+ if (FIELD_BUFFER_SIZE/PAGE_SIZE <= \
+ peasycap->field_page) {
+ SAY("ERROR: bad peasycap->field_page\n");
+ return;
+ }
+ pfield_buffer = &peasycap->field_buffer\
+ [peasycap->field_fill][peasycap->field_page];
+ pu = (__u8 *)(purb->transfer_buffer + \
+ purb->iso_frame_desc[i].offset);
+ if (0x80 & *pu)
+ leap = 8;
+ else
+ leap = 4;
+/*--------------------------------------------------------------------------*/
+/*
+ * EIGHT-BYTE END-OF-VIDEOFIELD MARKER.
+ * NOTE: A SUCCESSION OF URB FRAMES FOLLOWING THIS ARE EMPTY,
+ * CORRESPONDING TO THE FIELD FLYBACK (VERTICAL BLANKING) PERIOD.
+ *
+ * PROVIDED THE FIELD BUFFER CONTAINS GOOD DATA AS INDICATED BY A ZERO UPPER
+ * BYTE OF
+ * peasycap->field_buffer[peasycap->field_fill][0].kount
+ * THE CONTENTS OF THE FIELD BUFFER ARE OFFERED TO dqbuf(), field_read IS
+ * UPDATED AND field_fill IS BUMPED. IF THE FIELD BUFFER CONTAINS BAD DATA
+ * NOTHING IS OFFERED TO dqbuf().
+ *
+ * THE DECISION ON WHETHER THE PARITY OF THE OFFERED FIELD BUFFER IS RIGHT
+ * RESTS WITH dqbuf().
+ */
+/*---------------------------------------------------------------------------*/
+ if ((8 == more) || override) {
+ if (videofieldamount > \
+ peasycap->videofieldamount) {
+ if (2 == videofieldamount - \
+ peasycap->\
+ videofieldamount)
+ (peasycap->field_buffer\
+ [peasycap->field_fill]\
+ [0].kount) |= 0x0100;
+ else
+ (peasycap->field_buffer\
+ [peasycap->field_fill]\
+ [0].kount) |= 0x4000;
+ } else if (videofieldamount < \
+ peasycap->\
+ videofieldamount) {
+ (peasycap->field_buffer\
+ [peasycap->field_fill]\
+ [0].kount) |= 0x2000;
+ }
+ if (!(0xFF00 & peasycap->field_buffer\
+ [peasycap->field_fill]\
+ [0].kount)) {
+ (peasycap->video_junk)--;
+ if (-16 > peasycap->video_junk)
+ peasycap->video_junk = -16;
+ peasycap->field_read = \
+ (peasycap->\
+ field_fill)++;
+
+ if (FIELD_BUFFER_MANY <= \
+ peasycap->field_fill)
+ peasycap->field_fill = 0;
+ peasycap->field_page = 0;
+ pfield_buffer = &peasycap->\
+ field_buffer\
+ [peasycap->field_fill]\
+ [peasycap->field_page];
+ pfield_buffer->pto = \
+ pfield_buffer->pgo;
+
+ JOT(8, "bumped to: %i=peasycap->" \
+ "field_fill %i=parity\n", \
+ peasycap->field_fill, \
+ 0x00FF & pfield_buffer->kount);
+ JOT(8, "field buffer %i has %i " \
+ "bytes fit to be read\n", \
+ peasycap->field_read, \
+ videofieldamount);
+ JOT(8, "wakeup call to wq_video, " \
+ "%i=field_read %i=field_fill "\
+ "%i=parity\n", \
+ peasycap->field_read, \
+ peasycap->field_fill, \
+ 0x00FF & peasycap->\
+ field_buffer[peasycap->\
+ field_read][0].kount);
+ wake_up_interruptible(&(peasycap->\
+ wq_video));
+ do_gettimeofday(&peasycap->timeval7);
+ } else {
+ peasycap->video_junk++;
+ JOT(8, "field buffer %i had %i " \
+ "bytes, now discarded\n", \
+ peasycap->field_fill, \
+ videofieldamount);
+
+ (peasycap->field_fill)++;
+
+ if (FIELD_BUFFER_MANY <= \
+ peasycap->field_fill)
+ peasycap->field_fill = 0;
+ peasycap->field_page = 0;
+ pfield_buffer = \
+ &peasycap->field_buffer\
+ [peasycap->field_fill]\
+ [peasycap->field_page];
+ pfield_buffer->pto = \
+ pfield_buffer->pgo;
+
+ JOT(8, "bumped to: %i=peasycap->" \
+ "field_fill %i=parity\n", \
+ peasycap->field_fill, \
+ 0x00FF & pfield_buffer->kount);
+ }
+ if (8 == more) {
+ JOT(8, "end-of-field: received " \
+ "parity byte 0x%02X\n", \
+ (0xFF & *pu));
+ if (0x40 & *pu)
+ pfield_buffer->kount = 0x0000;
+ else
+ pfield_buffer->kount = 0x0001;
+ JOT(8, "end-of-field: 0x%02X=kount\n",\
+ 0xFF & pfield_buffer->kount);
+ }
+ }
+/*---------------------------------------------------------------------------*/
+/*
+ * COPY more BYTES FROM ISOC BUFFER TO FIELD BUFFER
+ */
+/*---------------------------------------------------------------------------*/
+ pu += leap;
+ more -= leap;
+
+ if (FIELD_BUFFER_MANY <= peasycap->field_fill) {
+ SAY("ERROR: bad peasycap->field_fill\n");
+ return;
+ }
+ if (FIELD_BUFFER_SIZE/PAGE_SIZE <= \
+ peasycap->field_page) {
+ SAY("ERROR: bad peasycap->field_page\n");
+ return;
+ }
+ pfield_buffer = &peasycap->field_buffer\
+ [peasycap->field_fill][peasycap->field_page];
+ while (more) {
+ pfield_buffer = &peasycap->field_buffer\
+ [peasycap->field_fill]\
+ [peasycap->field_page];
+ if (PAGE_SIZE < (pfield_buffer->pto - \
+ pfield_buffer->pgo)) {
+ SAY("ERROR: bad pfield_buffer->pto\n");
+ return;
+ }
+ if (PAGE_SIZE == (pfield_buffer->pto - \
+ pfield_buffer->pgo)) {
+ (peasycap->field_page)++;
+ if (FIELD_BUFFER_SIZE/PAGE_SIZE <= \
+ peasycap->field_page) {
+ JOT(16, "wrapping peasycap->" \
+ "field_page\n");
+ peasycap->field_page = 0;
+ }
+ pfield_buffer = &peasycap->\
+ field_buffer\
+ [peasycap->field_fill]\
+ [peasycap->field_page];
+ pfield_buffer->pto = \
+ pfield_buffer->pgo;
+ }
+
+ much = PAGE_SIZE - (int)(pfield_buffer->pto - \
+ pfield_buffer->pgo);
+
+ if (much > more)
+ much = more;
+ memcpy(pfield_buffer->pto, pu, much);
+ pu += much;
+ (pfield_buffer->pto) += much;
+ more -= much;
+ }
+ }
+ }
+ }
+}
+/*---------------------------------------------------------------------------*/
+/*
+ *
+ *
+ * *** UNDER DEVELOPMENT/TESTING - NOT READY YET! ***
+ *
+ *
+ *
+ * VIDEOTAPES MAY HAVE BEEN MANUALLY PAUSED AND RESTARTED DURING RECORDING.
+ * THIS CAUSES LOSS OF SYNC, CONFUSING DOWNSTREAM USERSPACE PROGRAMS WHICH
+ * MAY INTERPRET THE INTERRUPTION AS A SYMPTOM OF LATENCY. TO OVERCOME THIS
+ * THE DRIVER BRIDGES THE HIATUS BY SENDING DUMMY VIDEO FRAMES AT ROUGHLY
+ * THE RIGHT TIME INTERVALS IN THE HOPE OF PERSUADING THE DOWNSTREAM USERSPACE
+ * PROGRAM TO RESUME NORMAL SERVICE WHEN THE INTERRUPTION IS OVER.
+ */
+/*---------------------------------------------------------------------------*/
+#if defined(BRIDGER)
+do_gettimeofday(&timeval);
+if (peasycap->timeval7.tv_sec) {
+ usec = 1000000*(timeval.tv_sec - peasycap->timeval7.tv_sec) + \
+ (timeval.tv_usec - peasycap->timeval7.tv_usec);
+ if (usec > (peasycap->usec + peasycap->tolerate)) {
+ JOT(8, "bridging hiatus\n");
+ peasycap->video_junk = 0;
+ peasycap->field_buffer[peasycap->field_fill][0].kount |= 0x0400;
+
+ peasycap->field_read = (peasycap->field_fill)++;
+
+ if (FIELD_BUFFER_MANY <= peasycap->field_fill) \
+ peasycap->field_fill = 0;
+ peasycap->field_page = 0;
+ pfield_buffer = &peasycap->field_buffer\
+ [peasycap->field_fill][peasycap->field_page];
+ pfield_buffer->pto = pfield_buffer->pgo;
+
+ JOT(8, "bumped to: %i=peasycap->field_fill %i=parity\n", \
+ peasycap->field_fill, 0x00FF & pfield_buffer->kount);
+ JOT(8, "field buffer %i has %i bytes to be overwritten\n", \
+ peasycap->field_read, videofieldamount);
+ JOT(8, "wakeup call to wq_video, " \
+ "%i=field_read %i=field_fill %i=parity\n", \
+ peasycap->field_read, peasycap->field_fill, \
+ 0x00FF & \
+ peasycap->field_buffer[peasycap->field_read][0].kount);
+ wake_up_interruptible(&(peasycap->wq_video));
+ do_gettimeofday(&peasycap->timeval7);
+ }
+}
+#endif /*BRIDGER*/
+/*---------------------------------------------------------------------------*/
+/*
+ * RESUBMIT THIS URB, UNLESS A SEVERE PERSISTENT ERROR CONDITION EXISTS.
+ *
+ * IF THE WAIT QUEUES ARE NOT CLEARED IN RESPONSE TO AN ERROR CONDITION
+ * THE USERSPACE PROGRAM, E.G. mplayer, MAY HANG ON EXIT. BEWARE.
+ */
+/*---------------------------------------------------------------------------*/
+if (VIDEO_ISOC_BUFFER_MANY <= peasycap->video_junk) {
+ SAY("easycap driver shutting down on condition green\n");
+ peasycap->video_eof = 1;
+ peasycap->audio_eof = 1;
+ peasycap->video_junk = -VIDEO_ISOC_BUFFER_MANY;
+ wake_up_interruptible(&(peasycap->wq_video));
+ wake_up_interruptible(&(peasycap->wq_audio));
+ return;
+}
+if (peasycap->video_isoc_streaming) {
+ rc = usb_submit_urb(purb, GFP_ATOMIC);
+ if (0 != rc) {
+ SAY("ERROR: while %i=video_idle, usb_submit_urb() failed " \
+ "with rc:\n", peasycap->video_idle);
+ switch (rc) {
+ case -ENOMEM: {
+ SAY("ENOMEM\n"); break;
+ }
+ case -ENODEV: {
+ SAY("ENODEV\n"); break;
+ }
+ case -ENXIO: {
+ SAY("ENXIO\n"); break;
+ }
+ case -EINVAL: {
+ SAY("EINVAL\n"); break;
+ }
+ case -EAGAIN: {
+ SAY("EAGAIN\n"); break;
+ }
+ case -EFBIG: {
+ SAY("EFBIG\n"); break;
+ }
+ case -EPIPE: {
+ SAY("EPIPE\n"); break;
+ }
+ case -EMSGSIZE: {
+ SAY("EMSGSIZE\n"); break;
+ }
+ case -ENOSPC: {
+ SAY("ENOSPC\n"); break;
+ }
+ default: {
+ SAY("0x%08X\n", rc); break;
+ }
+ }
+ }
+}
+return;
+}
+/*****************************************************************************/
+/*---------------------------------------------------------------------------*/
+/*
+ *
+ * FIXME
+ *
+ *
+ * THIS FUNCTION ASSUMES THAT, ON EACH AND EVERY OCCASION THAT THE DEVICE IS
+ * PHYSICALLY PLUGGED IN, INTERFACE 0 IS PROBED FIRST.
+ * IF THIS IS NOT TRUE, THERE IS THE POSSIBILITY OF AN Oops.
+ *
+ * THIS HAS NEVER BEEN A PROBLEM IN PRACTICE, BUT SOMETHING SEEMS WRONG HERE.
+ */
+/*---------------------------------------------------------------------------*/
+int
+easycap_usb_probe(struct usb_interface *pusb_interface, \
+ const struct usb_device_id *id)
+{
+struct usb_device *pusb_device, *pusb_device1;
+struct usb_host_interface *pusb_host_interface;
+struct usb_endpoint_descriptor *pepd;
+struct usb_interface_descriptor *pusb_interface_descriptor;
+struct usb_interface_assoc_descriptor *pusb_interface_assoc_descriptor;
+struct urb *purb;
+static struct easycap *peasycap /*=NULL*/;
+struct data_urb *pdata_urb;
+size_t wMaxPacketSize;
+int ISOCwMaxPacketSize;
+int BULKwMaxPacketSize;
+int INTwMaxPacketSize;
+int CTRLwMaxPacketSize;
+__u8 bEndpointAddress;
+__u8 ISOCbEndpointAddress;
+__u8 INTbEndpointAddress;
+int isin, i, j, k, m;
+__u8 bInterfaceNumber;
+__u8 bInterfaceClass;
+__u8 bInterfaceSubClass;
+void *pbuf;
+int okalt[8], isokalt;
+int okepn[8], isokepn;
+int okmps[8], isokmps;
+int maxpacketsize;
+int rc;
+
+JOT(4, "\n");
+
+if ((struct usb_interface *)NULL == pusb_interface) {
+ SAY("ERROR: pusb_interface is NULL\n");
+ return -EFAULT;
+}
+/*---------------------------------------------------------------------------*/
+/*
+ * GET POINTER TO STRUCTURE usb_device
+ */
+/*---------------------------------------------------------------------------*/
+pusb_device1 = container_of(pusb_interface->dev.parent, \
+ struct usb_device, dev);
+if ((struct usb_device *)NULL == pusb_device1) {
+ SAY("ERROR: pusb_device1 is NULL\n");
+ return -EFAULT;
+}
+pusb_device = usb_get_dev(pusb_device1);
+if ((struct usb_device *)NULL == pusb_device) {
+ SAY("ERROR: pusb_device is NULL\n");
+ return -EFAULT;
+}
+if ((unsigned long int)pusb_device1 != (unsigned long int)pusb_device) {
+ JOT(4, "ERROR: pusb_device1 != pusb_device\n");
+ return -EFAULT;
+}
+
+JOT(4, "bNumConfigurations=%i\n", pusb_device->descriptor.bNumConfigurations);
+
+/*---------------------------------------------------------------------------*/
+pusb_host_interface = pusb_interface->cur_altsetting;
+if (NULL == pusb_host_interface) {
+ SAY("ERROR: pusb_host_interface is NULL\n");
+ return -EFAULT;
+}
+pusb_interface_descriptor = &(pusb_host_interface->desc);
+if (NULL == pusb_interface_descriptor) {
+ SAY("ERROR: pusb_interface_descriptor is NULL\n");
+ return -EFAULT;
+}
+/*---------------------------------------------------------------------------*/
+/*
+ * GET PROPERTIES OF PROBED INTERFACE
+ */
+/*---------------------------------------------------------------------------*/
+bInterfaceNumber = pusb_interface_descriptor->bInterfaceNumber;
+bInterfaceClass = pusb_interface_descriptor->bInterfaceClass;
+bInterfaceSubClass = pusb_interface_descriptor->bInterfaceSubClass;
+
+JOT(4, "intf[%i]: pusb_interface->num_altsetting=%i\n", \
+ bInterfaceNumber, pusb_interface->num_altsetting);
+JOT(4, "intf[%i]: pusb_interface->cur_altsetting - " \
+ "pusb_interface->altsetting=%li\n", bInterfaceNumber, \
+ (long int)(pusb_interface->cur_altsetting - \
+ pusb_interface->altsetting));
+switch (bInterfaceClass) {
+case USB_CLASS_AUDIO: {
+ JOT(4, "intf[%i]: bInterfaceClass=0x%02X=USB_CLASS_AUDIO\n", \
+ bInterfaceNumber, bInterfaceClass); break;
+ }
+case USB_CLASS_VIDEO: {
+ JOT(4, "intf[%i]: bInterfaceClass=0x%02X=USB_CLASS_VIDEO\n", \
+ bInterfaceNumber, bInterfaceClass); break;
+ }
+case USB_CLASS_VENDOR_SPEC: {
+ JOT(4, "intf[%i]: bInterfaceClass=0x%02X=USB_CLASS_VENDOR_SPEC\n", \
+ bInterfaceNumber, bInterfaceClass); break;
+ }
+default:
+ break;
+}
+switch (bInterfaceSubClass) {
+case 0x01: {
+ JOT(4, "intf[%i]: bInterfaceSubClass=0x%02X=AUDIOCONTROL\n", \
+ bInterfaceNumber, bInterfaceSubClass); break;
+}
+case 0x02: {
+ JOT(4, "intf[%i]: bInterfaceSubClass=0x%02X=AUDIOSTREAMING\n", \
+ bInterfaceNumber, bInterfaceSubClass); break;
+}
+case 0x03: {
+ JOT(4, "intf[%i]: bInterfaceSubClass=0x%02X=MIDISTREAMING\n", \
+ bInterfaceNumber, bInterfaceSubClass); break;
+}
+default:
+ break;
+}
+/*---------------------------------------------------------------------------*/
+pusb_interface_assoc_descriptor = pusb_interface->intf_assoc;
+if (NULL != pusb_interface_assoc_descriptor) {
+ JOT(4, "intf[%i]: bFirstInterface=0x%02X bInterfaceCount=0x%02X\n", \
+ bInterfaceNumber, \
+ pusb_interface_assoc_descriptor->bFirstInterface, \
+ pusb_interface_assoc_descriptor->bInterfaceCount);
+} else {
+JOT(4, "intf[%i]: pusb_interface_assoc_descriptor is NULL\n", \
+ bInterfaceNumber);
+}
+/*---------------------------------------------------------------------------*/
+/*
+ * A NEW struct easycap IS ALWAYS ALLOCATED WHEN INTERFACE 0 IS PROBED.
+ * IT IS NOT POSSIBLE HERE TO FREE ANY EXISTING struct easycap. THIS
+ * SHOULD HAVE BEEN DONE BY easycap_delete() WHEN THE DEVICE WAS PHYSICALLY
+ * UNPLUGGED.
+ */
+/*---------------------------------------------------------------------------*/
+if (0 == bInterfaceNumber) {
+ peasycap = kzalloc(sizeof(struct easycap), GFP_KERNEL);
+ if (NULL == peasycap) {
+ SAY("ERROR: Could not allocate peasycap\n");
+ return -ENOMEM;
+ } else {
+ peasycap->allocation_video_struct = sizeof(struct easycap);
+ peasycap->allocation_video_page = 0;
+ peasycap->allocation_video_urb = 0;
+ peasycap->allocation_audio_struct = 0;
+ peasycap->allocation_audio_page = 0;
+ peasycap->allocation_audio_urb = 0;
+ }
+/*---------------------------------------------------------------------------*/
+/*
+ * INITIALIZE THE NEW easycap STRUCTURE.
+ * NO PARAMETERS ARE SPECIFIED HERE REQUIRING THE SETTING OF REGISTERS.
+ * THAT IS DONE FIRST BY easycap_open() AND LATER BY easycap_ioctl().
+ */
+/*---------------------------------------------------------------------------*/
+ peasycap->pusb_device = pusb_device;
+ peasycap->pusb_interface = pusb_interface;
+
+ kref_init(&peasycap->kref);
+ JOT(8, "intf[%i]: after kref_init(..._video) " \
+ "%i=peasycap->kref.refcount.counter\n", \
+ bInterfaceNumber, peasycap->kref.refcount.counter);
+
+ init_waitqueue_head(&(peasycap->wq_video));
+ init_waitqueue_head(&(peasycap->wq_audio));
+
+ mutex_init(&(peasycap->mutex_timeval0));
+ mutex_init(&(peasycap->mutex_timeval1));
+
+ for (k = 0; k < FRAME_BUFFER_MANY; k++)
+ mutex_init(&(peasycap->mutex_mmap_video[k]));
+
+ peasycap->ilk = 0;
+ peasycap->microphone = false;
+
+ peasycap->video_interface = -1;
+ peasycap->video_altsetting_on = -1;
+ peasycap->video_altsetting_off = -1;
+ peasycap->video_endpointnumber = -1;
+ peasycap->video_isoc_maxframesize = -1;
+ peasycap->video_isoc_buffer_size = -1;
+
+ peasycap->audio_interface = -1;
+ peasycap->audio_altsetting_on = -1;
+ peasycap->audio_altsetting_off = -1;
+ peasycap->audio_endpointnumber = -1;
+ peasycap->audio_isoc_maxframesize = -1;
+ peasycap->audio_isoc_buffer_size = -1;
+
+ peasycap->frame_buffer_many = FRAME_BUFFER_MANY;
+
+ if ((struct mutex *)NULL == &(peasycap->mutex_mmap_video[0])) {
+ SAY("ERROR: &(peasycap->mutex_mmap_video[%i]) is NULL\n", 0);
+ return -EFAULT;
+ }
+/*---------------------------------------------------------------------------*/
+/*
+ * DYNAMICALLY FILL IN THE AVAILABLE FORMATS.
+ */
+/*---------------------------------------------------------------------------*/
+ rc = fillin_formats();
+ if (0 > rc) {
+ SAY("ERROR: fillin_formats() returned %i\n", rc);
+ return -EFAULT;
+ }
+ JOT(4, "%i formats available\n", rc);
+ } else {
+/*---------------------------------------------------------------------------*/
+ if ((struct easycap *)NULL == peasycap) {
+ SAY("ERROR: peasycap is NULL " \
+ "when probing interface %i\n", \
+ bInterfaceNumber);
+ return -EFAULT;
+ }
+
+ JOT(8, "kref_get() with %i=peasycap->kref.refcount.counter\n", \
+ (int)peasycap->kref.refcount.counter);
+ kref_get(&peasycap->kref);
+}
+/*---------------------------------------------------------------------------*/
+if ((USB_CLASS_VIDEO == bInterfaceClass) || \
+ (USB_CLASS_VENDOR_SPEC == bInterfaceClass)) {
+ if (-1 == peasycap->video_interface) {
+ peasycap->video_interface = bInterfaceNumber;
+ JOT(4, "setting peasycap->video_interface=%i\n", \
+ peasycap->video_interface);
+ } else {
+ if (peasycap->video_interface != bInterfaceNumber) {
+ SAY("ERROR: attempting to reset " \
+ "peasycap->video_interface\n");
+ SAY("...... continuing with " \
+ "%i=peasycap->video_interface\n", \
+ peasycap->video_interface);
+ }
+ }
+} else if ((USB_CLASS_AUDIO == bInterfaceClass) && \
+ (0x02 == bInterfaceSubClass)) {
+ if (-1 == peasycap->audio_interface) {
+ peasycap->audio_interface = bInterfaceNumber;
+ JOT(4, "setting peasycap->audio_interface=%i\n", \
+ peasycap->audio_interface);
+ } else {
+ if (peasycap->audio_interface != bInterfaceNumber) {
+ SAY("ERROR: attempting to reset " \
+ "peasycap->audio_interface\n");
+ SAY("...... continuing with " \
+ "%i=peasycap->audio_interface\n", \
+ peasycap->audio_interface);
+ }
+ }
+}
+/*---------------------------------------------------------------------------*/
+/*
+ * INVESTIGATE ALL ALTSETTINGS.
+ * DONE IN DETAIL BECAUSE USB DEVICE 05e1:0408 HAS DISPARATE INCARNATIONS.
+ */
+/*---------------------------------------------------------------------------*/
+isokalt = 0;
+isokepn = 0;
+isokmps = 0;
+
+for (i = 0; i < pusb_interface->num_altsetting; i++) {
+ pusb_host_interface = &(pusb_interface->altsetting[i]);
+ if ((struct usb_host_interface *)NULL == pusb_host_interface) {
+ SAY("ERROR: pusb_host_interface is NULL\n");
+ return -EFAULT;
+ }
+ pusb_interface_descriptor = &(pusb_host_interface->desc);
+ if ((struct usb_interface_descriptor *)NULL == \
+ pusb_interface_descriptor) {
+ SAY("ERROR: pusb_interface_descriptor is NULL\n");
+ return -EFAULT;
+ }
+
+ JOT(4, "intf[%i]alt[%i]: desc.bDescriptorType=0x%02X\n", \
+ bInterfaceNumber, i, pusb_interface_descriptor->bDescriptorType);
+ JOT(4, "intf[%i]alt[%i]: desc.bInterfaceNumber=0x%02X\n", \
+ bInterfaceNumber, i, pusb_interface_descriptor->bInterfaceNumber);
+ JOT(4, "intf[%i]alt[%i]: desc.bAlternateSetting=0x%02X\n", \
+ bInterfaceNumber, i, pusb_interface_descriptor->bAlternateSetting);
+ JOT(4, "intf[%i]alt[%i]: desc.bNumEndpoints=0x%02X\n", \
+ bInterfaceNumber, i, pusb_interface_descriptor->bNumEndpoints);
+ JOT(4, "intf[%i]alt[%i]: desc.bInterfaceClass=0x%02X\n", \
+ bInterfaceNumber, i, pusb_interface_descriptor->bInterfaceClass);
+ JOT(4, "intf[%i]alt[%i]: desc.bInterfaceSubClass=0x%02X\n", \
+ bInterfaceNumber, i, pusb_interface_descriptor->bInterfaceSubClass);
+ JOT(4, "intf[%i]alt[%i]: desc.bInterfaceProtocol=0x%02X\n", \
+ bInterfaceNumber, i, pusb_interface_descriptor->bInterfaceProtocol);
+ JOT(4, "intf[%i]alt[%i]: desc.iInterface=0x%02X\n", \
+ bInterfaceNumber, i, pusb_interface_descriptor->iInterface);
+
+ ISOCwMaxPacketSize = -1;
+ BULKwMaxPacketSize = -1;
+ INTwMaxPacketSize = -1;
+ CTRLwMaxPacketSize = -1;
+ ISOCbEndpointAddress = 0;
+ INTbEndpointAddress = 0;
+
+ if (0 == pusb_interface_descriptor->bNumEndpoints)
+ JOT(4, "intf[%i]alt[%i] has no endpoints\n", \
+ bInterfaceNumber, i);
+/*---------------------------------------------------------------------------*/
+ for (j = 0; j < pusb_interface_descriptor->bNumEndpoints; j++) {
+ pepd = &(pusb_host_interface->endpoint[j].desc);
+ if ((struct usb_endpoint_descriptor *)NULL == pepd) {
+ SAY("ERROR: pepd is NULL.\n");
+ SAY("...... skipping\n");
+ continue;
+ }
+ wMaxPacketSize = le16_to_cpu(pepd->wMaxPacketSize);
+ bEndpointAddress = pepd->bEndpointAddress;
+
+ JOT(4, "intf[%i]alt[%i]end[%i]: bEndpointAddress=0x%X\n", \
+ bInterfaceNumber, i, j, \
+ pepd->bEndpointAddress);
+ JOT(4, "intf[%i]alt[%i]end[%i]: bmAttributes=0x%X\n", \
+ bInterfaceNumber, i, j, \
+ pepd->bmAttributes);
+ JOT(4, "intf[%i]alt[%i]end[%i]: wMaxPacketSize=%i\n", \
+ bInterfaceNumber, i, j, \
+ pepd->wMaxPacketSize);
+ JOT(4, "intf[%i]alt[%i]end[%i]: bInterval=%i\n",
+ bInterfaceNumber, i, j, \
+ pepd->bInterval);
+
+ if (pepd->bEndpointAddress & USB_DIR_IN) {
+ JOT(4, "intf[%i]alt[%i]end[%i] is an IN endpoint\n",\
+ bInterfaceNumber, i, j);
+ isin = 1;
+ } else {
+ JOT(4, "intf[%i]alt[%i]end[%i] is an OUT endpoint\n",\
+ bInterfaceNumber, i, j);
+ SAY("ERROR: OUT endpoint unexpected\n");
+ SAY("...... continuing\n");
+ isin = 0;
+ }
+ if ((pepd->bmAttributes & \
+ USB_ENDPOINT_XFERTYPE_MASK) == \
+ USB_ENDPOINT_XFER_ISOC) {
+ JOT(4, "intf[%i]alt[%i]end[%i] is an ISOC endpoint\n",\
+ bInterfaceNumber, i, j);
+ if (isin) {
+ switch (bInterfaceClass) {
+ case USB_CLASS_VIDEO:
+ case USB_CLASS_VENDOR_SPEC: {
+ if (!peasycap) {
+ SAY("MISTAKE: " \
+ "peasycap is NULL\n");
+ return -EFAULT;
+ }
+ if (pepd->wMaxPacketSize) {
+ if (8 > isokalt) {
+ okalt[isokalt] = i;
+ JOT(4,\
+ "%i=okalt[%i]\n", \
+ okalt[isokalt], \
+ isokalt);
+ isokalt++;
+ }
+ if (8 > isokepn) {
+ okepn[isokepn] = \
+ pepd->\
+ bEndpointAddress & \
+ 0x0F;
+ JOT(4,\
+ "%i=okepn[%i]\n", \
+ okepn[isokepn], \
+ isokepn);
+ isokepn++;
+ }
+ if (8 > isokmps) {
+ okmps[isokmps] = \
+ le16_to_cpu(pepd->\
+ wMaxPacketSize);
+ JOT(4,\
+ "%i=okmps[%i]\n", \
+ okmps[isokmps], \
+ isokmps);
+ isokmps++;
+ }
+ } else {
+ if (-1 == peasycap->\
+ video_altsetting_off) {
+ peasycap->\
+ video_altsetting_off =\
+ i;
+ JOT(4, "%i=video_" \
+ "altsetting_off " \
+ "<====\n", \
+ peasycap->\
+ video_altsetting_off);
+ } else {
+ SAY("ERROR: peasycap" \
+ "->video_altsetting_" \
+ "off already set\n");
+ SAY("...... " \
+ "continuing with " \
+ "%i=peasycap->video_" \
+ "altsetting_off\n", \
+ peasycap->\
+ video_altsetting_off);
+ }
+ }
+ break;
+ }
+ case USB_CLASS_AUDIO: {
+ if (0x02 != bInterfaceSubClass)
+ break;
+ if (!peasycap) {
+ SAY("MISTAKE: " \
+ "peasycap is NULL\n");
+ return -EFAULT;
+ }
+ if (pepd->wMaxPacketSize) {
+ if (8 > isokalt) {
+ okalt[isokalt] = i ;
+ JOT(4,\
+ "%i=okalt[%i]\n", \
+ okalt[isokalt], \
+ isokalt);
+ isokalt++;
+ }
+ if (8 > isokepn) {
+ okepn[isokepn] = \
+ pepd->\
+ bEndpointAddress & \
+ 0x0F;
+ JOT(4,\
+ "%i=okepn[%i]\n", \
+ okepn[isokepn], \
+ isokepn);
+ isokepn++;
+ }
+ if (8 > isokmps) {
+ okmps[isokmps] = \
+ le16_to_cpu(pepd->\
+ wMaxPacketSize);
+ JOT(4,\
+ "%i=okmps[%i]\n",\
+ okmps[isokmps], \
+ isokmps);
+ isokmps++;
+ }
+ } else {
+ if (-1 == peasycap->\
+ audio_altsetting_off) {
+ peasycap->\
+ audio_altsetting_off =\
+ i;
+ JOT(4, "%i=audio_" \
+ "altsetting_off " \
+ "<====\n", \
+ peasycap->\
+ audio_altsetting_off);
+ } else {
+ SAY("ERROR: peasycap" \
+ "->audio_altsetting_" \
+ "off already set\n");
+ SAY("...... " \
+ "continuing with " \
+ "%i=peasycap->\
+ audio_altsetting_" \
+ "off\n",
+ peasycap->\
+ audio_altsetting_off);
+ }
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ }
+ } else if ((pepd->bmAttributes & \
+ USB_ENDPOINT_XFERTYPE_MASK) ==\
+ USB_ENDPOINT_XFER_BULK) {
+ JOT(4, "intf[%i]alt[%i]end[%i] is a BULK endpoint\n",\
+ bInterfaceNumber, i, j);
+ } else if ((pepd->bmAttributes & \
+ USB_ENDPOINT_XFERTYPE_MASK) ==\
+ USB_ENDPOINT_XFER_INT) {
+ JOT(4, "intf[%i]alt[%i]end[%i] is an INT endpoint\n",\
+ bInterfaceNumber, i, j);
+ } else {
+ JOT(4, "intf[%i]alt[%i]end[%i] is a CTRL endpoint\n",\
+ bInterfaceNumber, i, j);
+ }
+ if (0 == pepd->wMaxPacketSize) {
+ JOT(4, "intf[%i]alt[%i]end[%i] " \
+ "has zero packet size\n", \
+ bInterfaceNumber, i, j);
+ }
+ }
+}
+/*---------------------------------------------------------------------------*/
+/*
+ * PERFORM INITIALIZATION OF THE PROBED INTERFACE
+ */
+/*---------------------------------------------------------------------------*/
+JOT(4, "initialization begins for interface %i\n", \
+ pusb_interface_descriptor->bInterfaceNumber);
+switch (bInterfaceNumber) {
+/*---------------------------------------------------------------------------*/
+/*
+ * INTERFACE 0 IS THE VIDEO INTERFACE
+ */
+/*---------------------------------------------------------------------------*/
+case 0: {
+ if (!peasycap) {
+ SAY("MISTAKE: peasycap is NULL\n");
+ return -EFAULT;
+ }
+ if (!isokalt) {
+ SAY("ERROR: no viable video_altsetting_on\n");
+ return -ENOENT;
+ } else {
+ peasycap->video_altsetting_on = okalt[isokalt - 1];
+ JOT(4, "%i=video_altsetting_on <====\n", \
+ peasycap->video_altsetting_on);
+ }
+ if (!isokepn) {
+ SAY("ERROR: no viable video_endpointnumber\n");
+ return -ENOENT;
+ } else {
+ peasycap->video_endpointnumber = okepn[isokepn - 1];
+ JOT(4, "%i=video_endpointnumber\n", \
+ peasycap->video_endpointnumber);
+ }
+ if (!isokmps) {
+ SAY("ERROR: no viable video_maxpacketsize\n");
+ return -ENOENT;
+/*---------------------------------------------------------------------------*/
+/*
+ * DECIDE THE VIDEO STREAMING PARAMETERS
+ */
+/*---------------------------------------------------------------------------*/
+ } else {
+ maxpacketsize = okmps[isokmps - 1] - 1024;
+ if (USB_2_0_MAXPACKETSIZE > maxpacketsize) {
+ peasycap->video_isoc_maxframesize = maxpacketsize;
+ } else {
+ peasycap->video_isoc_maxframesize = \
+ USB_2_0_MAXPACKETSIZE;
+ }
+ JOT(4, "%i=video_isoc_maxframesize\n", \
+ peasycap->video_isoc_maxframesize);
+ if (0 >= peasycap->video_isoc_maxframesize) {
+ SAY("ERROR: bad video_isoc_maxframesize\n");
+ return -ENOENT;
+ }
+ peasycap->video_isoc_framesperdesc = VIDEO_ISOC_FRAMESPERDESC;
+ JOT(4, "%i=video_isoc_framesperdesc\n", \
+ peasycap->video_isoc_framesperdesc);
+ if (0 >= peasycap->video_isoc_framesperdesc) {
+ SAY("ERROR: bad video_isoc_framesperdesc\n");
+ return -ENOENT;
+ }
+ peasycap->video_isoc_buffer_size = \
+ peasycap->video_isoc_maxframesize * \
+ peasycap->video_isoc_framesperdesc;
+ JOT(4, "%i=video_isoc_buffer_size\n", \
+ peasycap->video_isoc_buffer_size);
+ if ((PAGE_SIZE << VIDEO_ISOC_ORDER) < \
+ peasycap->video_isoc_buffer_size) {
+ SAY("MISTAKE: " \
+ "peasycap->video_isoc_buffer_size too big\n");
+ return -EFAULT;
+ }
+ }
+/*---------------------------------------------------------------------------*/
+ if (-1 == peasycap->video_interface) {
+ SAY("MISTAKE: video_interface is unset\n");
+ return -EFAULT;
+ }
+ if (-1 == peasycap->video_altsetting_on) {
+ SAY("MISTAKE: video_altsetting_on is unset\n");
+ return -EFAULT;
+ }
+ if (-1 == peasycap->video_altsetting_off) {
+ SAY("MISTAKE: video_interface_off is unset\n");
+ return -EFAULT;
+ }
+ if (-1 == peasycap->video_endpointnumber) {
+ SAY("MISTAKE: video_endpointnumber is unset\n");
+ return -EFAULT;
+ }
+ if (-1 == peasycap->video_isoc_maxframesize) {
+ SAY("MISTAKE: video_isoc_maxframesize is unset\n");
+ return -EFAULT;
+ }
+ if (-1 == peasycap->video_isoc_buffer_size) {
+ SAY("MISTAKE: video_isoc_buffer_size is unset\n");
+ return -EFAULT;
+ }
+/*---------------------------------------------------------------------------*/
+/*
+ * ALLOCATE MEMORY FOR VIDEO BUFFERS. LISTS MUST BE INITIALIZED FIRST.
+ */
+/*---------------------------------------------------------------------------*/
+ INIT_LIST_HEAD(&(peasycap->urb_video_head));
+ peasycap->purb_video_head = &(peasycap->urb_video_head);
+/*---------------------------------------------------------------------------*/
+ JOT(4, "allocating %i frame buffers of size %li\n", \
+ FRAME_BUFFER_MANY, (long int)FRAME_BUFFER_SIZE);
+ JOT(4, ".... each scattered over %li pages\n", \
+ FRAME_BUFFER_SIZE/PAGE_SIZE);
+
+ for (k = 0; k < FRAME_BUFFER_MANY; k++) {
+ for (m = 0; m < FRAME_BUFFER_SIZE/PAGE_SIZE; m++) {
+ if ((void *)NULL != peasycap->frame_buffer[k][m].pgo)
+ SAY("attempting to reallocate frame " \
+ " buffers\n");
+ else {
+ pbuf = (void *)__get_free_page(GFP_KERNEL);
+ if ((void *)NULL == pbuf) {
+ SAY("ERROR: Could not allocate frame "\
+ "buffer %i page %i\n", k, m);
+ return -ENOMEM;
+ } else
+ peasycap->allocation_video_page += 1;
+ peasycap->frame_buffer[k][m].pgo = pbuf;
+ }
+ peasycap->frame_buffer[k][m].pto = \
+ peasycap->frame_buffer[k][m].pgo;
+ }
+ }
+
+ peasycap->frame_fill = 0;
+ peasycap->frame_read = 0;
+ JOT(4, "allocation of frame buffers done: %i pages\n", k * \
+ m);
+/*---------------------------------------------------------------------------*/
+ JOT(4, "allocating %i field buffers of size %li\n", \
+ FIELD_BUFFER_MANY, (long int)FIELD_BUFFER_SIZE);
+ JOT(4, ".... each scattered over %li pages\n", \
+ FIELD_BUFFER_SIZE/PAGE_SIZE);
+
+ for (k = 0; k < FIELD_BUFFER_MANY; k++) {
+ for (m = 0; m < FIELD_BUFFER_SIZE/PAGE_SIZE; m++) {
+ if ((void *)NULL != peasycap->field_buffer[k][m].pgo) {
+ SAY("ERROR: attempting to reallocate " \
+ "field buffers\n");
+ } else {
+ pbuf = (void *) __get_free_page(GFP_KERNEL);
+ if ((void *)NULL == pbuf) {
+ SAY("ERROR: Could not allocate field" \
+ " buffer %i page %i\n", k, m);
+ return -ENOMEM;
+ }
+ else
+ peasycap->allocation_video_page += 1;
+ peasycap->field_buffer[k][m].pgo = pbuf;
+ }
+ peasycap->field_buffer[k][m].pto = \
+ peasycap->field_buffer[k][m].pgo;
+ }
+ peasycap->field_buffer[k][0].kount = 0x0200;
+ }
+ peasycap->field_fill = 0;
+ peasycap->field_page = 0;
+ peasycap->field_read = 0;
+ JOT(4, "allocation of field buffers done: %i pages\n", k * \
+ m);
+/*---------------------------------------------------------------------------*/
+ JOT(4, "allocating %i isoc video buffers of size %i\n", \
+ VIDEO_ISOC_BUFFER_MANY, \
+ peasycap->video_isoc_buffer_size);
+ JOT(4, ".... each occupying contiguous memory pages\n");
+
+ for (k = 0; k < VIDEO_ISOC_BUFFER_MANY; k++) {
+ pbuf = (void *)__get_free_pages(GFP_KERNEL, VIDEO_ISOC_ORDER);
+ if (NULL == pbuf) {
+ SAY("ERROR: Could not allocate isoc video buffer " \
+ "%i\n", k);
+ return -ENOMEM;
+ } else
+ peasycap->allocation_video_page += \
+ ((unsigned int)(0x01 << VIDEO_ISOC_ORDER));
+
+ peasycap->video_isoc_buffer[k].pgo = pbuf;
+ peasycap->video_isoc_buffer[k].pto = pbuf + \
+ peasycap->video_isoc_buffer_size;
+ peasycap->video_isoc_buffer[k].kount = k;
+ }
+ JOT(4, "allocation of isoc video buffers done: %i pages\n", \
+ k * (0x01 << VIDEO_ISOC_ORDER));
+/*---------------------------------------------------------------------------*/
+/*
+ * ALLOCATE AND INITIALIZE MULTIPLE struct urb ...
+ */
+/*---------------------------------------------------------------------------*/
+ JOT(4, "allocating %i struct urb.\n", VIDEO_ISOC_BUFFER_MANY);
+ JOT(4, "using %i=peasycap->video_isoc_framesperdesc\n", \
+ peasycap->video_isoc_framesperdesc);
+ JOT(4, "using %i=peasycap->video_isoc_maxframesize\n", \
+ peasycap->video_isoc_maxframesize);
+ JOT(4, "using %i=peasycap->video_isoc_buffer_sizen", \
+ peasycap->video_isoc_buffer_size);
+
+ for (k = 0; k < VIDEO_ISOC_BUFFER_MANY; k++) {
+ purb = usb_alloc_urb(peasycap->video_isoc_framesperdesc, \
+ GFP_KERNEL);
+ if (NULL == purb) {
+ SAY("ERROR: usb_alloc_urb returned NULL for buffer " \
+ "%i\n", k);
+ return -ENOMEM;
+ } else
+ peasycap->allocation_video_urb += 1;
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+ pdata_urb = kzalloc(sizeof(struct data_urb), GFP_KERNEL);
+ if (NULL == pdata_urb) {
+ SAY("ERROR: Could not allocate struct data_urb.\n");
+ return -ENOMEM;
+ } else
+ peasycap->allocation_video_struct += \
+ sizeof(struct data_urb);
+
+ pdata_urb->purb = purb;
+ pdata_urb->isbuf = k;
+ pdata_urb->length = 0;
+ list_add_tail(&(pdata_urb->list_head), \
+ peasycap->purb_video_head);
+/*---------------------------------------------------------------------------*/
+/*
+ * ... AND INITIALIZE THEM
+ */
+/*---------------------------------------------------------------------------*/
+ if (!k) {
+ JOT(4, "initializing video urbs thus:\n");
+ JOT(4, " purb->interval = 1;\n");
+ JOT(4, " purb->dev = peasycap->pusb_device;\n");
+ JOT(4, " purb->pipe = usb_rcvisocpipe" \
+ "(peasycap->pusb_device,%i);\n", \
+ peasycap->video_endpointnumber);
+ JOT(4, " purb->transfer_flags = URB_ISO_ASAP;\n");
+ JOT(4, " purb->transfer_buffer = peasycap->" \
+ "video_isoc_buffer[.].pgo;\n");
+ JOT(4, " purb->transfer_buffer_length = %i;\n", \
+ peasycap->video_isoc_buffer_size);
+ JOT(4, " purb->complete = easycap_complete;\n");
+ JOT(4, " purb->context = peasycap;\n");
+ JOT(4, " purb->start_frame = 0;\n");
+ JOT(4, " purb->number_of_packets = %i;\n", \
+ peasycap->video_isoc_framesperdesc);
+ JOT(4, " for (j = 0; j < %i; j++)\n", \
+ peasycap->video_isoc_framesperdesc);
+ JOT(4, " {\n");
+ JOT(4, " purb->iso_frame_desc[j].offset = j*%i;\n",\
+ peasycap->video_isoc_maxframesize);
+ JOT(4, " purb->iso_frame_desc[j].length = %i;\n", \
+ peasycap->video_isoc_maxframesize);
+ JOT(4, " }\n");
+ }
+
+ purb->interval = 1;
+ purb->dev = peasycap->pusb_device;
+ purb->pipe = usb_rcvisocpipe(peasycap->pusb_device, \
+ peasycap->video_endpointnumber);
+ purb->transfer_flags = URB_ISO_ASAP;
+ purb->transfer_buffer = peasycap->video_isoc_buffer[k].pgo;
+ purb->transfer_buffer_length = \
+ peasycap->video_isoc_buffer_size;
+ purb->complete = easycap_complete;
+ purb->context = peasycap;
+ purb->start_frame = 0;
+ purb->number_of_packets = peasycap->video_isoc_framesperdesc;
+ for (j = 0; j < peasycap->video_isoc_framesperdesc; j++) {
+ purb->iso_frame_desc[j].offset = j * \
+ peasycap->video_isoc_maxframesize;
+ purb->iso_frame_desc[j].length = \
+ peasycap->video_isoc_maxframesize;
+ }
+ }
+ JOT(4, "allocation of %i struct urb done.\n", k);
+/*--------------------------------------------------------------------------*/
+/*
+ * SAVE POINTER peasycap IN THIS INTERFACE.
+ */
+/*--------------------------------------------------------------------------*/
+ usb_set_intfdata(pusb_interface, peasycap);
+/*--------------------------------------------------------------------------*/
+/*
+ * THE VIDEO DEVICE CAN BE REGISTERED NOW, AS IT IS READY.
+ */
+/*--------------------------------------------------------------------------*/
+#if (!defined(EASYCAP_IS_VIDEODEV_CLIENT))
+ if (0 != (usb_register_dev(pusb_interface, &easycap_class))) {
+ err("Not able to get a minor for this device");
+ usb_set_intfdata(pusb_interface, NULL);
+ return -ENODEV;
+ } else
+ (peasycap->registered_video)++;
+ SAY("easycap attached to minor #%d\n", pusb_interface->minor);
+ break;
+/*vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/
+#else
+ pvideo_device = (struct video_device *)\
+ kzalloc(sizeof(struct video_device), GFP_KERNEL);
+ if ((struct video_device *)NULL == pvideo_device) {
+ SAY("ERROR: Could not allocate structure video_device\n");
+ return -ENOMEM;
+ }
+ if (VIDEO_DEVICE_MANY <= video_device_many) {
+ SAY("ERROR: Too many /dev/videos\n");
+ return -ENOMEM;
+ }
+ pvideo_array[video_device_many] = pvideo_device; video_device_many++;
+
+ strcpy(&pvideo_device->name[0], "easycapdc60");
+#if defined(EASYCAP_NEEDS_V4L2_FOPS)
+ pvideo_device->fops = &v4l2_fops;
+#else
+ pvideo_device->fops = &easycap_fops;
+#endif /*EASYCAP_NEEDS_V4L2_FOPS*/
+ pvideo_device->minor = -1;
+ pvideo_device->release = (void *)(&videodev_release);
+
+ video_set_drvdata(pvideo_device, (void *)peasycap);
+
+ rc = video_register_device(pvideo_device, VFL_TYPE_GRABBER, -1);
+ if (0 != rc) {
+ err("Not able to register with videodev");
+ videodev_release(pvideo_device);
+ return -ENODEV;
+ } else {
+ peasycap->pvideo_device = pvideo_device;
+ (peasycap->registered_video)++;
+ JOT(4, "registered with videodev: %i=minor\n", \
+ pvideo_device->minor);
+ }
+/*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
+#endif /*EASYCAP_IS_VIDEODEV_CLIENT*/
+ break;
+}
+/*--------------------------------------------------------------------------*/
+/*
+ * INTERFACE 1 IS THE AUDIO CONTROL INTERFACE
+ * INTERFACE 2 IS THE AUDIO STREAMING INTERFACE
+ */
+/*--------------------------------------------------------------------------*/
+case 1: {
+/*--------------------------------------------------------------------------*/
+/*
+ * SAVE POINTER peasycap IN INTERFACE 1
+ */
+/*--------------------------------------------------------------------------*/
+ usb_set_intfdata(pusb_interface, peasycap);
+ JOT(4, "no initialization required for interface %i\n", \
+ pusb_interface_descriptor->bInterfaceNumber);
+ break;
+}
+/*--------------------------------------------------------------------------*/
+case 2: {
+ if (!peasycap) {
+ SAY("MISTAKE: peasycap is NULL\n");
+ return -EFAULT;
+ }
+ if (!isokalt) {
+ SAY("ERROR: no viable audio_altsetting_on\n");
+ return -ENOENT;
+ } else {
+ peasycap->audio_altsetting_on = okalt[isokalt - 1];
+ JOT(4, "%i=audio_altsetting_on <====\n", \
+ peasycap->audio_altsetting_on);
+ }
+ if (!isokepn) {
+ SAY("ERROR: no viable audio_endpointnumber\n");
+ return -ENOENT;
+ } else {
+ peasycap->audio_endpointnumber = okepn[isokepn - 1];
+ JOT(4, "%i=audio_endpointnumber\n", \
+ peasycap->audio_endpointnumber);
+ }
+ if (!isokmps) {
+ SAY("ERROR: no viable audio_maxpacketsize\n");
+ return -ENOENT;
+ } else {
+ peasycap->audio_isoc_maxframesize = okmps[isokmps - 1];
+ JOT(4, "%i=audio_isoc_maxframesize\n", \
+ peasycap->audio_isoc_maxframesize);
+ if (0 >= peasycap->audio_isoc_maxframesize) {
+ SAY("ERROR: bad audio_isoc_maxframesize\n");
+ return -ENOENT;
+ }
+ if (9 == peasycap->audio_isoc_maxframesize) {
+ peasycap->ilk |= 0x02;
+ SAY("hardware is FOUR-CVBS\n");
+ peasycap->microphone = true;
+ peasycap->audio_pages_per_fragment = 4;
+ } else if (256 == peasycap->audio_isoc_maxframesize) {
+ peasycap->ilk &= ~0x02;
+ SAY("hardware is CVBS+S-VIDEO\n");
+ peasycap->microphone = false;
+ peasycap->audio_pages_per_fragment = 4;
+ } else {
+ SAY("hardware is unidentified:\n");
+ SAY("%i=audio_isoc_maxframesize\n", \
+ peasycap->audio_isoc_maxframesize);
+ return -ENOENT;
+ }
+
+ peasycap->audio_bytes_per_fragment = \
+ peasycap->audio_pages_per_fragment * \
+ PAGE_SIZE ;
+ peasycap->audio_buffer_page_many = (AUDIO_FRAGMENT_MANY * \
+ peasycap->audio_pages_per_fragment);
+
+ JOT(4, "%6i=AUDIO_FRAGMENT_MANY\n", AUDIO_FRAGMENT_MANY);
+ JOT(4, "%6i=audio_pages_per_fragment\n", \
+ peasycap->audio_pages_per_fragment);
+ JOT(4, "%6i=audio_bytes_per_fragment\n", \
+ peasycap->audio_bytes_per_fragment);
+ JOT(4, "%6i=audio_buffer_page_many\n", \
+ peasycap->audio_buffer_page_many);
+
+ peasycap->audio_isoc_framesperdesc = 128;
+
+ JOT(4, "%i=audio_isoc_framesperdesc\n", \
+ peasycap->audio_isoc_framesperdesc);
+ if (0 >= peasycap->audio_isoc_framesperdesc) {
+ SAY("ERROR: bad audio_isoc_framesperdesc\n");
+ return -ENOENT;
+ }
+
+ peasycap->audio_isoc_buffer_size = \
+ peasycap->audio_isoc_maxframesize * \
+ peasycap->audio_isoc_framesperdesc;
+ JOT(4, "%i=audio_isoc_buffer_size\n", \
+ peasycap->audio_isoc_buffer_size);
+ if (AUDIO_ISOC_BUFFER_SIZE < \
+ peasycap->audio_isoc_buffer_size) {
+ SAY("MISTAKE: audio_isoc_buffer_size bigger "
+ "than %li=AUDIO_ISOC_BUFFER_SIZE\n", \
+ AUDIO_ISOC_BUFFER_SIZE);
+ return -EFAULT;
+ }
+ }
+
+ if (-1 == peasycap->audio_interface) {
+ SAY("MISTAKE: audio_interface is unset\n");
+ return -EFAULT;
+ }
+ if (-1 == peasycap->audio_altsetting_on) {
+ SAY("MISTAKE: audio_altsetting_on is unset\n");
+ return -EFAULT;
+ }
+ if (-1 == peasycap->audio_altsetting_off) {
+ SAY("MISTAKE: audio_interface_off is unset\n");
+ return -EFAULT;
+ }
+ if (-1 == peasycap->audio_endpointnumber) {
+ SAY("MISTAKE: audio_endpointnumber is unset\n");
+ return -EFAULT;
+ }
+ if (-1 == peasycap->audio_isoc_maxframesize) {
+ SAY("MISTAKE: audio_isoc_maxframesize is unset\n");
+ return -EFAULT;
+ }
+ if (-1 == peasycap->audio_isoc_buffer_size) {
+ SAY("MISTAKE: audio_isoc_buffer_size is unset\n");
+ return -EFAULT;
+ }
+/*---------------------------------------------------------------------------*/
+/*
+ * ALLOCATE MEMORY FOR AUDIO BUFFERS. LISTS MUST BE INITIALIZED FIRST.
+ */
+/*---------------------------------------------------------------------------*/
+ INIT_LIST_HEAD(&(peasycap->urb_audio_head));
+ peasycap->purb_audio_head = &(peasycap->urb_audio_head);
+
+ JOT(4, "allocating an audio buffer\n");
+ JOT(4, ".... scattered over %i pages\n", \
+ peasycap->audio_buffer_page_many);
+
+ for (k = 0; k < peasycap->audio_buffer_page_many; k++) {
+ if ((void *)NULL != peasycap->audio_buffer[k].pgo) {
+ SAY("ERROR: attempting to reallocate audio buffers\n");
+ } else {
+ pbuf = (void *) __get_free_page(GFP_KERNEL);
+ if ((void *)NULL == pbuf) {
+ SAY("ERROR: Could not allocate audio " \
+ "buffer page %i\n", k);
+ return -ENOMEM;
+ } else
+ peasycap->allocation_audio_page += 1;
+
+ peasycap->audio_buffer[k].pgo = pbuf;
+ }
+ peasycap->audio_buffer[k].pto = peasycap->audio_buffer[k].pgo;
+ }
+
+ peasycap->audio_fill = 0;
+ peasycap->audio_read = 0;
+ JOT(4, "allocation of audio buffer done: %i pages\n", k);
+/*---------------------------------------------------------------------------*/
+ JOT(4, "allocating %i isoc audio buffers of size %i\n", \
+ AUDIO_ISOC_BUFFER_MANY, peasycap->audio_isoc_buffer_size);
+ JOT(4, ".... each occupying contiguous memory pages\n");
+
+ for (k = 0; k < AUDIO_ISOC_BUFFER_MANY; k++) {
+ pbuf = (void *)__get_free_pages(GFP_KERNEL, AUDIO_ISOC_ORDER);
+ if (NULL == pbuf) {
+ SAY("ERROR: Could not allocate isoc audio buffer " \
+ "%i\n", k);
+ return -ENOMEM;
+ } else
+ peasycap->allocation_audio_page += \
+ ((unsigned int)(0x01 << AUDIO_ISOC_ORDER));
+
+ peasycap->audio_isoc_buffer[k].pgo = pbuf;
+ peasycap->audio_isoc_buffer[k].pto = pbuf + \
+ peasycap->audio_isoc_buffer_size;
+ peasycap->audio_isoc_buffer[k].kount = k;
+ }
+ JOT(4, "allocation of isoc audio buffers done.\n");
+/*---------------------------------------------------------------------------*/
+/*
+ * ALLOCATE AND INITIALIZE MULTIPLE struct urb ...
+ */
+/*---------------------------------------------------------------------------*/
+ JOT(4, "allocating %i struct urb.\n", AUDIO_ISOC_BUFFER_MANY);
+ JOT(4, "using %i=peasycap->audio_isoc_framesperdesc\n", \
+ peasycap->audio_isoc_framesperdesc);
+ JOT(4, "using %i=peasycap->audio_isoc_maxframesize\n", \
+ peasycap->audio_isoc_maxframesize);
+ JOT(4, "using %i=peasycap->audio_isoc_buffer_size\n", \
+ peasycap->audio_isoc_buffer_size);
+
+ for (k = 0; k < AUDIO_ISOC_BUFFER_MANY; k++) {
+ purb = usb_alloc_urb(peasycap->audio_isoc_framesperdesc, \
+ GFP_KERNEL);
+ if (NULL == purb) {
+ SAY("ERROR: usb_alloc_urb returned NULL for buffer " \
+ "%i\n", k);
+ return -ENOMEM;
+ } else
+ peasycap->allocation_audio_urb += 1 ;
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+ pdata_urb = kzalloc(sizeof(struct data_urb), GFP_KERNEL);
+ if (NULL == pdata_urb) {
+ SAY("ERROR: Could not allocate struct data_urb.\n");
+ return -ENOMEM;
+ } else
+ peasycap->allocation_audio_struct += \
+ sizeof(struct data_urb);
+
+ pdata_urb->purb = purb;
+ pdata_urb->isbuf = k;
+ pdata_urb->length = 0;
+ list_add_tail(&(pdata_urb->list_head), \
+ peasycap->purb_audio_head);
+/*---------------------------------------------------------------------------*/
+/*
+ * ... AND INITIALIZE THEM
+ */
+/*---------------------------------------------------------------------------*/
+ if (!k) {
+ JOT(4, "initializing audio urbs thus:\n");
+ JOT(4, " purb->interval = 1;\n");
+ JOT(4, " purb->dev = peasycap->pusb_device;\n");
+ JOT(4, " purb->pipe = usb_rcvisocpipe(peasycap->" \
+ "pusb_device,%i);\n", \
+ peasycap->audio_endpointnumber);
+ JOT(4, " purb->transfer_flags = URB_ISO_ASAP;\n");
+ JOT(4, " purb->transfer_buffer = " \
+ "peasycap->audio_isoc_buffer[.].pgo;\n");
+ JOT(4, " purb->transfer_buffer_length = %i;\n", \
+ peasycap->audio_isoc_buffer_size);
+ JOT(4, " purb->complete = easysnd_complete;\n");
+ JOT(4, " purb->context = peasycap;\n");
+ JOT(4, " purb->start_frame = 0;\n");
+ JOT(4, " purb->number_of_packets = %i;\n", \
+ peasycap->audio_isoc_framesperdesc);
+ JOT(4, " for (j = 0; j < %i; j++)\n", \
+ peasycap->audio_isoc_framesperdesc);
+ JOT(4, " {\n");
+ JOT(4, " purb->iso_frame_desc[j].offset = j*%i;\n",\
+ peasycap->audio_isoc_maxframesize);
+ JOT(4, " purb->iso_frame_desc[j].length = %i;\n", \
+ peasycap->audio_isoc_maxframesize);
+ JOT(4, " }\n");
+ }
+
+ purb->interval = 1;
+ purb->dev = peasycap->pusb_device;
+ purb->pipe = usb_rcvisocpipe(peasycap->pusb_device, \
+ peasycap->audio_endpointnumber);
+ purb->transfer_flags = URB_ISO_ASAP;
+ purb->transfer_buffer = peasycap->audio_isoc_buffer[k].pgo;
+ purb->transfer_buffer_length = \
+ peasycap->audio_isoc_buffer_size;
+ purb->complete = easysnd_complete;
+ purb->context = peasycap;
+ purb->start_frame = 0;
+ purb->number_of_packets = peasycap->audio_isoc_framesperdesc;
+ for (j = 0; j < peasycap->audio_isoc_framesperdesc; j++) {
+ purb->iso_frame_desc[j].offset = j * \
+ peasycap->audio_isoc_maxframesize;
+ purb->iso_frame_desc[j].length = \
+ peasycap->audio_isoc_maxframesize;
+ }
+ }
+ JOT(4, "allocation of %i struct urb done.\n", k);
+/*---------------------------------------------------------------------------*/
+/*
+ * SAVE POINTER peasycap IN THIS INTERFACE.
+ */
+/*---------------------------------------------------------------------------*/
+ usb_set_intfdata(pusb_interface, peasycap);
+/*---------------------------------------------------------------------------*/
+/*
+ * THE AUDIO DEVICE CAN BE REGISTERED NOW, AS IT IS READY.
+ */
+/*---------------------------------------------------------------------------*/
+ rc = usb_register_dev(pusb_interface, &easysnd_class);
+ if (0 != rc) {
+ err("Not able to get a minor for this device.");
+ usb_set_intfdata(pusb_interface, NULL);
+ return -ENODEV;
+ } else
+ (peasycap->registered_audio)++;
+/*---------------------------------------------------------------------------*/
+/*
+ * LET THE USER KNOW WHAT NODE THE AUDIO DEVICE IS ATTACHED TO.
+ */
+/*---------------------------------------------------------------------------*/
+ SAY("easysnd attached to minor #%d\n", pusb_interface->minor);
+ break;
+}
+/*---------------------------------------------------------------------------*/
+/*
+ * INTERFACES OTHER THAN 0, 1 AND 2 ARE UNEXPECTED
+ */
+/*---------------------------------------------------------------------------*/
+default: {
+ JOT(4, "ERROR: unexpected interface %i\n", bInterfaceNumber);
+ return -EINVAL;
+}
+}
+JOT(4, "ends successfully for interface %i\n", \
+ pusb_interface_descriptor->bInterfaceNumber);
+return 0;
+}
+/*****************************************************************************/
+/*---------------------------------------------------------------------------*/
+/*
+ * WHEN THIS FUNCTION IS CALLED THE DEVICE HAS ALREADY BEEN PHYSICALLY
+ * UNPLUGGED.
+ * HENCE peasycap->pusb_device IS NO LONGER VALID AND MUST BE SET TO NULL.
+ */
+/*---------------------------------------------------------------------------*/
+void
+easycap_usb_disconnect(struct usb_interface *pusb_interface)
+{
+struct usb_host_interface *pusb_host_interface;
+struct usb_interface_descriptor *pusb_interface_descriptor;
+__u8 bInterfaceNumber;
+struct easycap *peasycap;
+
+struct list_head *plist_head;
+struct data_urb *pdata_urb;
+int minor, m;
+
+JOT(4, "\n");
+
+if ((struct usb_interface *)NULL == pusb_interface) {
+ JOT(4, "ERROR: pusb_interface is NULL\n");
+ return;
+}
+pusb_host_interface = pusb_interface->cur_altsetting;
+if ((struct usb_host_interface *)NULL == pusb_host_interface) {
+ JOT(4, "ERROR: pusb_host_interface is NULL\n");
+ return;
+}
+pusb_interface_descriptor = &(pusb_host_interface->desc);
+if ((struct usb_interface_descriptor *)NULL == pusb_interface_descriptor) {
+ JOT(4, "ERROR: pusb_interface_descriptor is NULL\n");
+ return;
+}
+bInterfaceNumber = pusb_interface_descriptor->bInterfaceNumber;
+minor = pusb_interface->minor;
+JOT(4, "intf[%i]: minor=%i\n", bInterfaceNumber, minor);
+
+peasycap = usb_get_intfdata(pusb_interface);
+if ((struct easycap *)NULL == peasycap)
+ SAY("ERROR: peasycap is NULL\n");
+else {
+ peasycap->pusb_device = (struct usb_device *)NULL;
+ switch (bInterfaceNumber) {
+/*---------------------------------------------------------------------------*/
+ case 0: {
+ if ((struct list_head *)NULL != peasycap->purb_video_head) {
+ JOT(4, "killing video urbs\n");
+ m = 0;
+ list_for_each(plist_head, (peasycap->purb_video_head))
+ {
+ pdata_urb = list_entry(plist_head, \
+ struct data_urb, list_head);
+ if ((struct data_urb *)NULL != pdata_urb) {
+ if ((struct urb *)NULL != \
+ pdata_urb->purb) {
+ usb_kill_urb(pdata_urb->purb);
+ m++;
+ }
+ }
+ }
+ JOT(4, "%i video urbs killed\n", m);
+ } else
+ SAY("ERROR: peasycap->purb_video_head is NULL\n");
+ break;
+ }
+/*---------------------------------------------------------------------------*/
+ case 2: {
+ if ((struct list_head *)NULL != peasycap->purb_audio_head) {
+ JOT(4, "killing audio urbs\n");
+ m = 0;
+ list_for_each(plist_head, \
+ (peasycap->purb_audio_head)) {
+ pdata_urb = list_entry(plist_head, \
+ struct data_urb, list_head);
+ if ((struct data_urb *)NULL != pdata_urb) {
+ if ((struct urb *)NULL != \
+ pdata_urb->purb) {
+ usb_kill_urb(pdata_urb->purb);
+ m++;
+ }
+ }
+ }
+ JOT(4, "%i audio urbs killed\n", m);
+ } else
+ SAY("ERROR: peasycap->purb_audio_head is NULL\n");
+ break;
+ }
+/*---------------------------------------------------------------------------*/
+ default:
+ break;
+ }
+}
+/*--------------------------------------------------------------------------*/
+/*
+ * DEREGISTER
+ */
+/*--------------------------------------------------------------------------*/
+switch (bInterfaceNumber) {
+case 0: {
+#if (!defined(EASYCAP_IS_VIDEODEV_CLIENT))
+ if ((struct easycap *)NULL == peasycap) {
+ SAY("ERROR: peasycap has become NULL\n");
+ } else {
+ lock_kernel();
+ usb_deregister_dev(pusb_interface, &easycap_class);
+ (peasycap->registered_video)--;
+
+ JOT(4, "intf[%i]: usb_deregister_dev()\n", bInterfaceNumber);
+ unlock_kernel();
+ SAY("easycap detached from minor #%d\n", minor);
+ }
+/*vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/
+#else
+ if ((struct easycap *)NULL == peasycap)
+ SAY("ERROR: peasycap has become NULL\n");
+ else {
+ lock_kernel();
+ video_unregister_device(peasycap->pvideo_device);
+ (peasycap->registered_video)--;
+ unlock_kernel();
+ JOT(4, "unregistered with videodev: %i=minor\n", \
+ pvideo_device->minor);
+ }
+/*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
+#endif /*EASYCAP_IS_VIDEODEV_CLIENT*/
+ break;
+}
+case 2: {
+ lock_kernel();
+
+ usb_deregister_dev(pusb_interface, &easysnd_class);
+ if ((struct easycap *)NULL != peasycap)
+ (peasycap->registered_audio)--;
+
+ JOT(4, "intf[%i]: usb_deregister_dev()\n", bInterfaceNumber);
+ unlock_kernel();
+
+ SAY("easysnd detached from minor #%d\n", minor);
+ break;
+}
+default:
+ break;
+}
+/*---------------------------------------------------------------------------*/
+/*
+ * CALL easycap_delete() IF NO REMAINING REFERENCES TO peasycap
+ */
+/*---------------------------------------------------------------------------*/
+if ((struct easycap *)NULL == peasycap) {
+ SAY("ERROR: peasycap has become NULL\n");
+ SAY("cannot call kref_put()\n");
+ SAY("ending unsuccessfully: may cause memory leak\n");
+ return;
+}
+if (!peasycap->kref.refcount.counter) {
+ SAY("ERROR: peasycap->kref.refcount.counter is zero " \
+ "so cannot call kref_put()\n");
+ SAY("ending unsuccessfully: may cause memory leak\n");
+ return;
+}
+JOT(4, "intf[%i]: kref_put() with %i=peasycap->kref.refcount.counter\n", \
+ bInterfaceNumber, (int)peasycap->kref.refcount.counter);
+kref_put(&peasycap->kref, easycap_delete);
+JOT(4, "intf[%i]: kref_put() done.\n", bInterfaceNumber);
+/*---------------------------------------------------------------------------*/
+
+JOT(4, "ends\n");
+return;
+}
+/*****************************************************************************/
+int __init
+easycap_module_init(void)
+{
+int result;
+
+SAY("========easycap=======\n");
+JOT(4, "begins. %i=debug\n", easycap_debug);
+SAY("version: " EASYCAP_DRIVER_VERSION "\n");
+/*---------------------------------------------------------------------------*/
+/*
+ * REGISTER THIS DRIVER WITH THE USB SUBSYTEM.
+ */
+/*---------------------------------------------------------------------------*/
+JOT(4, "registering driver easycap\n");
+
+result = usb_register(&easycap_usb_driver);
+if (0 != result)
+ SAY("ERROR: usb_register returned %i\n", result);
+
+JOT(4, "ends\n");
+return result;
+}
+/*****************************************************************************/
+void __exit
+easycap_module_exit(void)
+{
+JOT(4, "begins\n");
+
+/*---------------------------------------------------------------------------*/
+/*
+ * DEREGISTER THIS DRIVER WITH THE USB SUBSYTEM.
+ */
+/*---------------------------------------------------------------------------*/
+usb_deregister(&easycap_usb_driver);
+
+JOT(4, "ends\n");
+}
+/*****************************************************************************/
+
+module_init(easycap_module_init);
+module_exit(easycap_module_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("R.M. Thomas <rmthomas@sciolus.org>");
+MODULE_DESCRIPTION(EASYCAP_DRIVER_DESCRIPTION);
+MODULE_VERSION(EASYCAP_DRIVER_VERSION);
+#if defined(EASYCAP_DEBUG)
+MODULE_PARM_DESC(easycap_debug, "debug: 0 (default), 1, 2,...");
+#endif /*EASYCAP_DEBUG*/
+/*****************************************************************************/
diff --git a/drivers/staging/easycap/easycap_settings.c b/drivers/staging/easycap/easycap_settings.c
new file mode 100644
index 00000000000..38d94051241
--- /dev/null
+++ b/drivers/staging/easycap/easycap_settings.c
@@ -0,0 +1,489 @@
+/******************************************************************************
+* *
+* easycap_settings.c *
+* *
+******************************************************************************/
+/*
+ *
+ * Copyright (C) 2010 R.M. Thomas <rmthomas@sciolus.org>
+ *
+ *
+ * This is free software; you can redistribute it and/or modify
+ * 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 software 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 software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+*/
+/*****************************************************************************/
+
+#include "easycap.h"
+#include "easycap_debug.h"
+
+/*---------------------------------------------------------------------------*/
+/*
+ * THE LEAST SIGNIFICANT BIT OF easycap_standard.mask HAS MEANING:
+ * 0 => 25 fps
+ * 1 => 30 fps
+ */
+/*---------------------------------------------------------------------------*/
+const struct easycap_standard easycap_standard[] = {
+{
+.mask = 0x000F & PAL_BGHIN ,
+.v4l2_standard = {
+ .index = PAL_BGHIN,
+ .id = (V4L2_STD_PAL_B | V4L2_STD_PAL_G | V4L2_STD_PAL_H | \
+ V4L2_STD_PAL_I | V4L2_STD_PAL_N),
+ .name = "PAL_BGHIN",
+ .frameperiod = {1, 25},
+ .framelines = 625,
+ .reserved = {0, 0, 0, 0}
+ }
+},
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+{
+.mask = 0x000F & NTSC_N_443 ,
+.v4l2_standard = {
+ .index = NTSC_N_443,
+ .id = V4L2_STD_UNKNOWN,
+ .name = "NTSC_N_443",
+ .frameperiod = {1, 25},
+ .framelines = 480,
+ .reserved = {0, 0, 0, 0}
+}
+},
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+{
+.mask = 0x000F & PAL_Nc ,
+.v4l2_standard = {
+ .index = PAL_Nc,
+ .id = V4L2_STD_PAL_Nc,
+ .name = "PAL_Nc",
+ .frameperiod = {1, 25},
+ .framelines = 625,
+ .reserved = {0, 0, 0, 0}
+}
+},
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+{
+.mask = 0x000F & NTSC_N ,
+.v4l2_standard = {
+ .index = NTSC_N,
+ .id = V4L2_STD_UNKNOWN,
+ .name = "NTSC_N",
+ .frameperiod = {1, 25},
+ .framelines = 525,
+ .reserved = {0, 0, 0, 0}
+}
+},
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+{
+.mask = 0x000F & SECAM ,
+.v4l2_standard = {
+ .index = SECAM,
+ .id = V4L2_STD_SECAM,
+ .name = "SECAM",
+ .frameperiod = {1, 25},
+ .framelines = 625,
+ .reserved = {0, 0, 0, 0}
+}
+},
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+{
+.mask = 0x000F & NTSC_M ,
+.v4l2_standard = {
+ .index = NTSC_M,
+ .id = V4L2_STD_NTSC_M,
+ .name = "NTSC_M",
+ .frameperiod = {1, 30},
+ .framelines = 525,
+ .reserved = {0, 0, 0, 0}
+}
+},
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+{
+.mask = 0x000F & NTSC_M_JP ,
+.v4l2_standard = {
+ .index = NTSC_M_JP,
+ .id = V4L2_STD_NTSC_M_JP,
+ .name = "NTSC_M_JP",
+ .frameperiod = {1, 30},
+ .framelines = 525,
+ .reserved = {0, 0, 0, 0}
+}
+},
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+{
+.mask = 0x000F & PAL_60 ,
+.v4l2_standard = {
+ .index = PAL_60,
+ .id = V4L2_STD_PAL_60,
+ .name = "PAL_60",
+ .frameperiod = {1, 30},
+ .framelines = 525,
+ .reserved = {0, 0, 0, 0}
+}
+},
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+{
+.mask = 0x000F & NTSC_443 ,
+.v4l2_standard = {
+ .index = NTSC_443,
+ .id = V4L2_STD_NTSC_443,
+ .name = "NTSC_443",
+ .frameperiod = {1, 30},
+ .framelines = 525,
+ .reserved = {0, 0, 0, 0}
+}
+},
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+{
+.mask = 0x000F & PAL_M ,
+.v4l2_standard = {
+ .index = PAL_M,
+ .id = V4L2_STD_PAL_M,
+ .name = "PAL_M",
+ .frameperiod = {1, 30},
+ .framelines = 525,
+ .reserved = {0, 0, 0, 0}
+}
+},
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+{
+.mask = 0xFFFF
+}
+};
+/*---------------------------------------------------------------------------*/
+/*
+ * THE 16-BIT easycap_format.mask HAS MEANING:
+ * (least significant) BIT 0: 0 => PAL, 25 FPS; 1 => NTSC, 30 FPS
+ * BITS 1-3: RESERVED FOR DIFFERENTIATING STANDARDS
+ * BITS 4-7: NUMBER OF BYTES PER PIXEL
+ * BIT 8: 0 => NATIVE BYTE ORDER; 1 => SWAPPED
+ * BITS 9-10: RESERVED FOR OTHER BYTE PERMUTATIONS
+ * BIT 11: 0 => UNDECIMATED; 1 => DECIMATED
+ * BIT 12: 0 => OFFER FRAMES; 1 => OFFER FIELDS
+ * (most significant) BITS 13-15: RESERVED FOR OTHER FIELD ORDER OPTIONS
+ * IT FOLLOWS THAT:
+ * bytesperpixel IS ((0x00F0 & easycap_format.mask) >> 4)
+ * byteswaporder IS true IF (0 != (0x0100 & easycap_format.mask))
+ *
+ * decimatepixel IS true IF (0 != (0x0800 & easycap_format.mask))
+ *
+ * offerfields IS true IF (0 != (0x1000 & easycap_format.mask))
+ */
+/*---------------------------------------------------------------------------*/
+
+struct easycap_format easycap_format[1 + SETTINGS_MANY];
+
+int
+fillin_formats(void)
+{
+int i, j, k, m, n;
+__u32 width, height, pixelformat, bytesperline, sizeimage;
+__u32 field, colorspace;
+__u16 mask1, mask2, mask3, mask4;
+char name1[32], name2[32], name3[32], name4[32];
+
+for (i = 0, n = 0; i < STANDARD_MANY; i++) {
+ mask1 = 0x0000;
+ switch (i) {
+ case PAL_BGHIN: {
+ mask1 = PAL_BGHIN;
+ strcpy(&name1[0], "PAL_BGHIN");
+ colorspace = V4L2_COLORSPACE_470_SYSTEM_BG;
+ break;
+ }
+ case SECAM: {
+ mask1 = SECAM;
+ strcpy(&name1[0], "SECAM");
+ colorspace = V4L2_COLORSPACE_470_SYSTEM_BG;
+ break;
+ }
+ case PAL_Nc: {
+ mask1 = PAL_Nc;
+ strcpy(&name1[0], "PAL_Nc");
+ colorspace = V4L2_COLORSPACE_470_SYSTEM_BG;
+ break;
+ }
+ case PAL_60: {
+ mask1 = PAL_60;
+ strcpy(&name1[0], "PAL_60");
+ colorspace = V4L2_COLORSPACE_470_SYSTEM_BG;
+ break;
+ }
+ case PAL_M: {
+ mask1 = PAL_M;
+ strcpy(&name1[0], "PAL_M");
+ colorspace = V4L2_COLORSPACE_470_SYSTEM_BG;
+ break;
+ }
+ case NTSC_M: {
+ mask1 = NTSC_M;
+ strcpy(&name1[0], "NTSC_M");
+ colorspace = V4L2_COLORSPACE_470_SYSTEM_M;
+ break;
+ }
+ case NTSC_443: {
+ mask1 = NTSC_443;
+ strcpy(&name1[0], "NTSC_443");
+ colorspace = V4L2_COLORSPACE_470_SYSTEM_M;
+ break;
+ }
+ case NTSC_M_JP: {
+ mask1 = NTSC_M_JP;
+ strcpy(&name1[0], "NTSC_M_JP");
+ colorspace = V4L2_COLORSPACE_470_SYSTEM_M;
+ break;
+ }
+ case NTSC_N: {
+ mask1 = NTSC_M;
+ strcpy(&name1[0], "NTSC_N");
+ colorspace = V4L2_COLORSPACE_470_SYSTEM_M;
+ break;
+ }
+ case NTSC_N_443: {
+ mask1 = NTSC_N_443;
+ strcpy(&name1[0], "NTSC_N_443");
+ colorspace = V4L2_COLORSPACE_470_SYSTEM_M;
+ break;
+ }
+ default:
+ return -1;
+ }
+
+ for (j = 0; j < RESOLUTION_MANY; j++) {
+ mask2 = 0x0000;
+ switch (j) {
+ case AT_720x576: {
+ if (0x1 & mask1)
+ continue;
+ strcpy(&name2[0], "_AT_720x576");
+ width = 720; height = 576; break;
+ }
+ case AT_704x576: {
+ if (0x1 & mask1)
+ continue;
+ strcpy(&name2[0], "_AT_704x576");
+ width = 704; height = 576; break;
+ }
+ case AT_640x480: {
+ strcpy(&name2[0], "_AT_640x480");
+ width = 640; height = 480; break;
+ }
+ case AT_720x480: {
+ if (!(0x1 & mask1))
+ continue;
+ strcpy(&name2[0], "_AT_720x480");
+ width = 720; height = 480; break;
+ }
+ case AT_360x288: {
+ if (0x1 & mask1)
+ continue;
+ strcpy(&name2[0], "_AT_360x288");
+ width = 360; height = 288; mask2 = 0x0800; break;
+ }
+ case AT_320x240: {
+ strcpy(&name2[0], "_AT_320x240");
+ width = 320; height = 240; mask2 = 0x0800; break;
+ }
+ case AT_360x240: {
+ if (!(0x1 & mask1))
+ continue;
+ strcpy(&name2[0], "_AT_360x240");
+ width = 360; height = 240; mask2 = 0x0800; break;
+ }
+ default:
+ return -2;
+ }
+
+ for (k = 0; k < PIXELFORMAT_MANY; k++) {
+ mask3 = 0x0000;
+ switch (k) {
+ case FMT_UYVY: {
+ strcpy(&name3[0], "_" STRINGIZE(FMT_UYVY));
+ pixelformat = V4L2_PIX_FMT_UYVY;
+ mask3 |= (0x02 << 4);
+ break;
+ }
+ case FMT_YUY2: {
+ strcpy(&name3[0], "_" STRINGIZE(FMT_YUY2));
+ pixelformat = V4L2_PIX_FMT_YUYV;
+ mask3 |= (0x02 << 4);
+ mask3 |= 0x0100;
+ break;
+ }
+ case FMT_RGB24: {
+ strcpy(&name3[0], "_" STRINGIZE(FMT_RGB24));
+ pixelformat = V4L2_PIX_FMT_RGB24;
+ mask3 |= (0x03 << 4);
+ break;
+ }
+ case FMT_RGB32: {
+ strcpy(&name3[0], "_" STRINGIZE(FMT_RGB32));
+ pixelformat = V4L2_PIX_FMT_RGB32;
+ mask3 |= (0x04 << 4);
+ break;
+ }
+ case FMT_BGR24: {
+ strcpy(&name3[0], "_" STRINGIZE(FMT_BGR24));
+ pixelformat = V4L2_PIX_FMT_BGR24;
+ mask3 |= (0x03 << 4);
+ mask3 |= 0x0100;
+ break;
+ }
+ case FMT_BGR32: {
+ strcpy(&name3[0], "_" STRINGIZE(FMT_BGR32));
+ pixelformat = V4L2_PIX_FMT_BGR32;
+ mask3 |= (0x04 << 4);
+ mask3 |= 0x0100;
+ break;
+ }
+ default:
+ return -3;
+ }
+ bytesperline = width * ((mask3 & 0x00F0) >> 4);
+ sizeimage = bytesperline * height;
+
+ for (m = 0; m < INTERLACE_MANY; m++) {
+ mask4 = 0x0000;
+ switch (m) {
+ case FIELD_NONE: {
+ strcpy(&name4[0], "-n");
+ field = V4L2_FIELD_NONE;
+ break;
+ }
+ case FIELD_INTERLACED: {
+ strcpy(&name4[0], "-i");
+ field = V4L2_FIELD_INTERLACED;
+ break;
+ }
+ case FIELD_ALTERNATE: {
+ strcpy(&name4[0], "-a");
+ mask4 |= 0x1000;
+ field = V4L2_FIELD_ALTERNATE;
+ break;
+ }
+ default:
+ return -4;
+ }
+ if (SETTINGS_MANY <= n)
+ return -5;
+ strcpy(&easycap_format[n].name[0], &name1[0]);
+ strcat(&easycap_format[n].name[0], &name2[0]);
+ strcat(&easycap_format[n].name[0], &name3[0]);
+ strcat(&easycap_format[n].name[0], &name4[0]);
+ easycap_format[n].mask = \
+ mask1 | mask2 | mask3 | mask4;
+ easycap_format[n].v4l2_format\
+ .type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ easycap_format[n].v4l2_format\
+ .fmt.pix.width = width;
+ easycap_format[n].v4l2_format\
+ .fmt.pix.height = height;
+ easycap_format[n].v4l2_format\
+ .fmt.pix.pixelformat = pixelformat;
+ easycap_format[n].v4l2_format\
+ .fmt.pix.field = field;
+ easycap_format[n].v4l2_format\
+ .fmt.pix.bytesperline = bytesperline;
+ easycap_format[n].v4l2_format\
+ .fmt.pix.sizeimage = sizeimage;
+ easycap_format[n].v4l2_format\
+ .fmt.pix.colorspace = colorspace;
+ easycap_format[n].v4l2_format\
+ .fmt.pix.priv = 0;
+ n++;
+ }
+ }
+ }
+}
+if ((1 + SETTINGS_MANY) <= n)
+ return -6;
+easycap_format[n].mask = 0xFFFF;
+return n;
+}
+/*---------------------------------------------------------------------------*/
+struct v4l2_queryctrl easycap_control[] = \
+ {{
+.id = V4L2_CID_BRIGHTNESS,
+.type = V4L2_CTRL_TYPE_INTEGER,
+.name = "Brightness",
+.minimum = 0,
+.maximum = 255,
+.step = 1,
+.default_value = SAA_0A_DEFAULT,
+.flags = 0,
+.reserved = {0, 0}
+},
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+{
+.id = V4L2_CID_CONTRAST,
+.type = V4L2_CTRL_TYPE_INTEGER,
+.name = "Contrast",
+.minimum = 0,
+.maximum = 255,
+.step = 1,
+.default_value = SAA_0B_DEFAULT + 128,
+.flags = 0,
+.reserved = {0, 0}
+},
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+{
+.id = V4L2_CID_SATURATION,
+.type = V4L2_CTRL_TYPE_INTEGER,
+.name = "Saturation",
+.minimum = 0,
+.maximum = 255,
+.step = 1,
+.default_value = SAA_0C_DEFAULT + 128,
+.flags = 0,
+.reserved = {0, 0}
+},
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+{
+.id = V4L2_CID_HUE,
+.type = V4L2_CTRL_TYPE_INTEGER,
+.name = "Hue",
+.minimum = 0,
+.maximum = 255,
+.step = 1,
+.default_value = SAA_0D_DEFAULT + 128,
+.flags = 0,
+.reserved = {0, 0}
+},
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+{
+.id = V4L2_CID_AUDIO_VOLUME,
+.type = V4L2_CTRL_TYPE_INTEGER,
+.name = "Volume",
+.minimum = 0,
+.maximum = 31,
+.step = 1,
+.default_value = 16,
+.flags = 0,
+.reserved = {0, 0}
+},
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+{
+.id = V4L2_CID_AUDIO_MUTE,
+.type = V4L2_CTRL_TYPE_BOOLEAN,
+.name = "Mute",
+.default_value = true,
+.flags = 0,
+.reserved = {0, 0}
+},
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+{
+.id = 0xFFFFFFFF
+}
+ };
+/*****************************************************************************/
diff --git a/drivers/staging/easycap/easycap_sound.c b/drivers/staging/easycap/easycap_sound.c
new file mode 100644
index 00000000000..63562bda738
--- /dev/null
+++ b/drivers/staging/easycap/easycap_sound.c
@@ -0,0 +1,1046 @@
+/******************************************************************************
+* *
+* easycap_sound.c *
+* *
+* Audio driver for EasyCAP USB2.0 Video Capture Device DC60 *
+* *
+* *
+******************************************************************************/
+/*
+ *
+ * Copyright (C) 2010 R.M. Thomas <rmthomas@sciolus.org>
+ *
+ *
+ * This is free software; you can redistribute it and/or modify
+ * 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 software 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 software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+*/
+/*****************************************************************************/
+
+#include "easycap.h"
+#include "easycap_debug.h"
+#include "easycap_sound.h"
+
+/*****************************************************************************/
+/*---------------------------------------------------------------------------*/
+/*
+ * ON COMPLETION OF AN AUDIO URB ITS DATA IS COPIED TO THE AUDIO BUFFERS
+ * PROVIDED peasycap->audio_idle IS ZER0. REGARDLESS OF THIS BEING TRUE,
+ * IT IS RESUBMITTED PROVIDED peasycap->audio_isoc_streaming IS NOT ZERO.
+ */
+/*---------------------------------------------------------------------------*/
+void
+easysnd_complete(struct urb *purb)
+{
+static int mt;
+struct easycap *peasycap;
+struct data_buffer *paudio_buffer;
+char errbuf[16];
+__u8 *p1, *p2;
+__s16 s16;
+int i, j, more, much, leap, rc;
+#if defined(UPSAMPLE)
+int k;
+__s16 oldaudio, newaudio, delta;
+#endif /*UPSAMPLE*/
+
+JOT(16, "\n");
+
+if (NULL == purb) {
+ SAY("ERROR: purb is NULL\n");
+ return;
+}
+peasycap = purb->context;
+if (NULL == peasycap) {
+ SAY("ERROR: peasycap is NULL\n");
+ return;
+}
+much = 0;
+
+
+if (peasycap->audio_idle) {
+ JOT(16, "%i=audio_idle %i=audio_isoc_streaming\n", \
+ peasycap->audio_idle, peasycap->audio_isoc_streaming);
+ if (peasycap->audio_isoc_streaming) {
+ rc = usb_submit_urb(purb, GFP_ATOMIC);
+ if (0 != rc) {
+ SAY("ERROR: while %i=audio_idle, " \
+ "usb_submit_urb() failed with rc:\n", \
+ peasycap->audio_idle);
+ switch (rc) {
+ case -ENOMEM: {
+ SAY("ENOMEM\n"); break;
+ }
+ case -ENODEV: {
+ SAY("ENODEV\n"); break;
+ }
+ case -ENXIO: {
+ SAY("ENXIO\n"); break;
+ }
+ case -EINVAL: {
+ SAY("EINVAL\n"); break;
+ }
+ case -EAGAIN: {
+ SAY("EAGAIN\n"); break;
+ }
+ case -EFBIG: {
+ SAY("EFBIG\n"); break;
+ }
+ case -EPIPE: {
+ SAY("EPIPE\n"); break;
+ }
+ case -EMSGSIZE: {
+ SAY("EMSGSIZE\n"); break;
+ }
+ case -ENOSPC: {
+ SAY("ENOSPC\n"); break;
+ }
+ default: {
+ SAY("0x%08X\n", rc); break;
+ }
+ }
+ }
+ }
+return;
+}
+/*---------------------------------------------------------------------------*/
+if (purb->status) {
+ if (-ESHUTDOWN == purb->status) {
+ JOT(16, "immediate return because -ESHUTDOWN=purb->status\n");
+ return;
+ }
+ SAY("ERROR: non-zero urb status:\n");
+ switch (purb->status) {
+ case -EINPROGRESS: {
+ SAY("-EINPROGRESS\n"); break;
+ }
+ case -ENOSR: {
+ SAY("-ENOSR\n"); break;
+ }
+ case -EPIPE: {
+ SAY("-EPIPE\n"); break;
+ }
+ case -EOVERFLOW: {
+ SAY("-EOVERFLOW\n"); break;
+ }
+ case -EPROTO: {
+ SAY("-EPROTO\n"); break;
+ }
+ case -EILSEQ: {
+ SAY("-EILSEQ\n"); break;
+ }
+ case -ETIMEDOUT: {
+ SAY("-ETIMEDOUT\n"); break;
+ }
+ case -EMSGSIZE: {
+ SAY("-EMSGSIZE\n"); break;
+ }
+ case -EOPNOTSUPP: {
+ SAY("-EOPNOTSUPP\n"); break;
+ }
+ case -EPFNOSUPPORT: {
+ SAY("-EPFNOSUPPORT\n"); break;
+ }
+ case -EAFNOSUPPORT: {
+ SAY("-EAFNOSUPPORT\n"); break;
+ }
+ case -EADDRINUSE: {
+ SAY("-EADDRINUSE\n"); break;
+ }
+ case -EADDRNOTAVAIL: {
+ SAY("-EADDRNOTAVAIL\n"); break;
+ }
+ case -ENOBUFS: {
+ SAY("-ENOBUFS\n"); break;
+ }
+ case -EISCONN: {
+ SAY("-EISCONN\n"); break;
+ }
+ case -ENOTCONN: {
+ SAY("-ENOTCONN\n"); break;
+ }
+ case -ESHUTDOWN: {
+ SAY("-ESHUTDOWN\n"); break;
+ }
+ case -ENOENT: {
+ SAY("-ENOENT\n"); break;
+ }
+ case -ECONNRESET: {
+ SAY("-ECONNRESET\n"); break;
+ }
+ case -ENOSPC: {
+ SAY("ENOSPC\n"); break;
+ }
+ default: {
+ SAY("unknown error code 0x%08X\n", purb->status); break;
+ }
+ }
+/*---------------------------------------------------------------------------*/
+/*
+ * RESUBMIT THIS URB AFTER AN ERROR
+ *
+ * (THIS IS DUPLICATE CODE TO REDUCE INDENTATION OF THE NO-ERROR PATH)
+ */
+/*---------------------------------------------------------------------------*/
+ if (peasycap->audio_isoc_streaming) {
+ rc = usb_submit_urb(purb, GFP_ATOMIC);
+ if (0 != rc) {
+ SAY("ERROR: while %i=audio_idle, usb_submit_urb() "
+ "failed with rc:\n", peasycap->audio_idle);
+ switch (rc) {
+ case -ENOMEM: {
+ SAY("ENOMEM\n"); break;
+ }
+ case -ENODEV: {
+ SAY("ENODEV\n"); break;
+ }
+ case -ENXIO: {
+ SAY("ENXIO\n"); break;
+ }
+ case -EINVAL: {
+ SAY("EINVAL\n"); break;
+ }
+ case -EAGAIN: {
+ SAY("EAGAIN\n"); break;
+ }
+ case -EFBIG: {
+ SAY("EFBIG\n"); break;
+ }
+ case -EPIPE: {
+ SAY("EPIPE\n"); break;
+ }
+ case -EMSGSIZE: {
+ SAY("EMSGSIZE\n"); break;
+ }
+ default: {
+ SAY("0x%08X\n", rc); break;
+ }
+ }
+ }
+ }
+ return;
+}
+/*---------------------------------------------------------------------------*/
+/*
+ * PROCEED HERE WHEN NO ERROR
+ */
+/*---------------------------------------------------------------------------*/
+#if defined(UPSAMPLE)
+oldaudio = peasycap->oldaudio;
+#endif /*UPSAMPLE*/
+
+for (i = 0; i < purb->number_of_packets; i++) {
+ switch (purb->iso_frame_desc[i].status) {
+ case 0: {
+ strcpy(&errbuf[0], "OK"); break;
+ }
+ case -ENOENT: {
+ strcpy(&errbuf[0], "-ENOENT"); break;
+ }
+ case -EINPROGRESS: {
+ strcpy(&errbuf[0], "-EINPROGRESS"); break;
+ }
+ case -EPROTO: {
+ strcpy(&errbuf[0], "-EPROTO"); break;
+ }
+ case -EILSEQ: {
+ strcpy(&errbuf[0], "-EILSEQ"); break;
+ }
+ case -ETIME: {
+ strcpy(&errbuf[0], "-ETIME"); break;
+ }
+ case -ETIMEDOUT: {
+ strcpy(&errbuf[0], "-ETIMEDOUT"); break;
+ }
+ case -EPIPE: {
+ strcpy(&errbuf[0], "-EPIPE"); break;
+ }
+ case -ECOMM: {
+ strcpy(&errbuf[0], "-ECOMM"); break;
+ }
+ case -ENOSR: {
+ strcpy(&errbuf[0], "-ENOSR"); break;
+ }
+ case -EOVERFLOW: {
+ strcpy(&errbuf[0], "-EOVERFLOW"); break;
+ }
+ case -EREMOTEIO: {
+ strcpy(&errbuf[0], "-EREMOTEIO"); break;
+ }
+ case -ENODEV: {
+ strcpy(&errbuf[0], "-ENODEV"); break;
+ }
+ case -EXDEV: {
+ strcpy(&errbuf[0], "-EXDEV"); break;
+ }
+ case -EINVAL: {
+ strcpy(&errbuf[0], "-EINVAL"); break;
+ }
+ case -ECONNRESET: {
+ strcpy(&errbuf[0], "-ECONNRESET"); break;
+ }
+ case -ENOSPC: {
+ strcpy(&errbuf[0], "-ENOSPC"); break;
+ }
+ case -ESHUTDOWN: {
+ strcpy(&errbuf[0], "-ESHUTDOWN"); break;
+ }
+ default: {
+ strcpy(&errbuf[0], "UNKNOWN"); break;
+ }
+ }
+ if ((!purb->iso_frame_desc[i].status) && 0) {
+ JOT(16, "frame[%2i]: %i=status{=%16s} " \
+ "%5i=actual " \
+ "%5i=length " \
+ "%3i=offset\n", \
+ i, purb->iso_frame_desc[i].status, &errbuf[0],
+ purb->iso_frame_desc[i].actual_length,
+ purb->iso_frame_desc[i].length,
+ purb->iso_frame_desc[i].offset);
+ }
+ if (!purb->iso_frame_desc[i].status) {
+ more = purb->iso_frame_desc[i].actual_length;
+
+#if defined(TESTTONE)
+ if (!more)
+ more = purb->iso_frame_desc[i].length;
+#endif
+
+ if (!more)
+ mt++;
+ else {
+ if (mt) {
+ JOT(16, "%4i empty audio urb frames\n", mt);
+ mt = 0;
+ }
+
+ p1 = (__u8 *)(purb->transfer_buffer + \
+ purb->iso_frame_desc[i].offset);
+
+ leap = 0;
+ p1 += leap;
+ more -= leap;
+/*---------------------------------------------------------------------------*/
+/*
+ * COPY more BYTES FROM ISOC BUFFER TO AUDIO BUFFER,
+ * CONVERTING 8-BIT MONO TO 16-BIT SIGNED LITTLE-ENDIAN SAMPLES IF NECESSARY
+ */
+/*---------------------------------------------------------------------------*/
+ while (more) {
+ if (0 > more) {
+ SAY("easysnd_complete: MISTAKE: " \
+ "more is negative\n");
+ return;
+ }
+ if (peasycap->audio_buffer_page_many <= \
+ peasycap->audio_fill) {
+ SAY("ERROR: bad " \
+ "peasycap->audio_fill\n");
+ return;
+ }
+
+ paudio_buffer = &peasycap->audio_buffer\
+ [peasycap->audio_fill];
+ if (PAGE_SIZE < (paudio_buffer->pto - \
+ paudio_buffer->pgo)) {
+ SAY("ERROR: bad paudio_buffer->pto\n");
+ return;
+ }
+ if (PAGE_SIZE == (paudio_buffer->pto - \
+ paudio_buffer->pgo)) {
+
+#if defined(TESTTONE)
+ easysnd_testtone(peasycap, \
+ peasycap->audio_fill);
+#endif /*TESTTONE*/
+
+ paudio_buffer->pto = \
+ paudio_buffer->pgo;
+ (peasycap->audio_fill)++;
+ if (peasycap->\
+ audio_buffer_page_many <= \
+ peasycap->audio_fill)
+ peasycap->audio_fill = 0;
+
+ JOT(12, "bumped peasycap->" \
+ "audio_fill to %i\n", \
+ peasycap->audio_fill);
+
+ paudio_buffer = &peasycap->\
+ audio_buffer\
+ [peasycap->audio_fill];
+ paudio_buffer->pto = \
+ paudio_buffer->pgo;
+
+ if (!(peasycap->audio_fill % \
+ peasycap->\
+ audio_pages_per_fragment)) {
+ JOT(12, "wakeup call on wq_" \
+ "audio, %i=frag reading %i" \
+ "=fragment fill\n", \
+ (peasycap->audio_read / \
+ peasycap->\
+ audio_pages_per_fragment), \
+ (peasycap->audio_fill / \
+ peasycap->\
+ audio_pages_per_fragment));
+ wake_up_interruptible\
+ (&(peasycap->wq_audio));
+ }
+ }
+
+ much = PAGE_SIZE - (int)(paudio_buffer->pto -\
+ paudio_buffer->pgo);
+
+ if (false == peasycap->microphone) {
+ if (much > more)
+ much = more;
+
+ memcpy(paudio_buffer->pto, p1, much);
+ p1 += much;
+ more -= much;
+ } else {
+#if defined(UPSAMPLE)
+ if (much % 16)
+ JOT(8, "MISTAKE? much" \
+ " is not divisible by 16\n");
+ if (much > (16 * \
+ more))
+ much = 16 * \
+ more;
+ p2 = (__u8 *)paudio_buffer->pto;
+
+ for (j = 0; j < (much/16); j++) {
+ newaudio = ((int) *p1) - 128;
+ newaudio = 128 * \
+ newaudio;
+
+ delta = (newaudio - oldaudio) \
+ / 4;
+ s16 = oldaudio + delta;
+
+ for (k = 0; k < 4; k++) {
+ *p2 = (0x00FF & s16);
+ *(p2 + 1) = (0xFF00 & \
+ s16) >> 8;
+ p2 += 2;
+ *p2 = (0x00FF & s16);
+ *(p2 + 1) = (0xFF00 & \
+ s16) >> 8;
+ p2 += 2;
+
+ s16 += delta;
+ }
+ p1++;
+ more--;
+ oldaudio = s16;
+ }
+#else
+ if (much > (2 * more))
+ much = 2 * more;
+ p2 = (__u8 *)paudio_buffer->pto;
+
+ for (j = 0; j < (much / 2); j++) {
+ s16 = ((int) *p1) - 128;
+ s16 = 128 * \
+ s16;
+ *p2 = (0x00FF & s16);
+ *(p2 + 1) = (0xFF00 & s16) >> \
+ 8;
+ p1++; p2 += 2;
+ more--;
+ }
+#endif /*UPSAMPLE*/
+ }
+ (paudio_buffer->pto) += much;
+ }
+ }
+ } else {
+ JOT(12, "discarding audio samples because " \
+ "%i=purb->iso_frame_desc[i].status\n", \
+ purb->iso_frame_desc[i].status);
+ }
+
+#if defined(UPSAMPLE)
+peasycap->oldaudio = oldaudio;
+#endif /*UPSAMPLE*/
+
+}
+/*---------------------------------------------------------------------------*/
+/*
+ * RESUBMIT THIS URB AFTER NO ERROR
+ */
+/*---------------------------------------------------------------------------*/
+if (peasycap->audio_isoc_streaming) {
+ rc = usb_submit_urb(purb, GFP_ATOMIC);
+ if (0 != rc) {
+ SAY("ERROR: while %i=audio_idle, usb_submit_urb() failed " \
+ "with rc:\n", peasycap->audio_idle);
+ switch (rc) {
+ case -ENOMEM: {
+ SAY("ENOMEM\n"); break;
+ }
+ case -ENODEV: {
+ SAY("ENODEV\n"); break;
+ }
+ case -ENXIO: {
+ SAY("ENXIO\n"); break;
+ }
+ case -EINVAL: {
+ SAY("EINVAL\n"); break;
+ }
+ case -EAGAIN: {
+ SAY("EAGAIN\n"); break;
+ }
+ case -EFBIG: {
+ SAY("EFBIG\n"); break;
+ }
+ case -EPIPE: {
+ SAY("EPIPE\n"); break;
+ }
+ case -EMSGSIZE: {
+ SAY("EMSGSIZE\n"); break;
+ }
+ case -ENOSPC: {
+ SAY("ENOSPC\n"); break;
+ }
+ default: {
+ SAY("0x%08X\n", rc); break;
+ }
+ }
+ }
+}
+return;
+}
+/*****************************************************************************/
+/*---------------------------------------------------------------------------*/
+/*
+ * THE AUDIO URBS ARE SUBMITTED AT THIS EARLY STAGE SO THAT IT IS POSSIBLE TO
+ * STREAM FROM /dev/easysnd1 WITH SIMPLE PROGRAMS SUCH AS cat WHICH DO NOT
+ * HAVE AN IOCTL INTERFACE. THE VIDEO URBS, BY CONTRAST, MUST BE SUBMITTED
+ * MUCH LATER: SEE COMMENTS IN FILE easycap_main.c.
+ */
+/*---------------------------------------------------------------------------*/
+int
+easysnd_open(struct inode *inode, struct file *file)
+{
+struct usb_interface *pusb_interface;
+struct easycap *peasycap;
+int subminor, rc;
+
+JOT(4, "begins.\n");
+
+subminor = iminor(inode);
+
+pusb_interface = usb_find_interface(&easycap_usb_driver, subminor);
+if (NULL == pusb_interface) {
+ SAY("ERROR: pusb_interface is NULL\n");
+ SAY("ending unsuccessfully\n");
+ return -1;
+}
+peasycap = usb_get_intfdata(pusb_interface);
+if (NULL == peasycap) {
+ SAY("ERROR: peasycap is NULL\n");
+ SAY("ending unsuccessfully\n");
+ return -1;
+}
+
+file->private_data = peasycap;
+
+/*---------------------------------------------------------------------------*/
+/*
+ * INITIALIZATION.
+ */
+/*---------------------------------------------------------------------------*/
+JOT(4, "starting initialization\n");
+
+if ((struct usb_device *)NULL == peasycap->pusb_device) {
+ SAY("ERROR: peasycap->pusb_device is NULL\n");
+ return -EFAULT;
+} else {
+ JOT(16, "0x%08lX=peasycap->pusb_device\n", \
+ (long int)peasycap->pusb_device);
+}
+
+rc = audio_setup(peasycap);
+if (0 <= rc)
+ JOT(8, "audio_setup() returned %i\n", rc);
+else
+ JOT(8, "easysnd open(): ERROR: audio_setup() returned %i\n", rc);
+
+if ((struct usb_device *)NULL == peasycap->pusb_device) {
+ SAY("ERROR: peasycap->pusb_device has become NULL\n");
+ return -EFAULT;
+}
+rc = adjust_volume(peasycap, -8192);
+if (0 != rc) {
+ SAY("ERROR: adjust_volume(default) returned %i\n", rc);
+ return -EFAULT;
+}
+/*---------------------------------------------------------------------------*/
+if ((struct usb_device *)NULL == peasycap->pusb_device) {
+ SAY("ERROR: peasycap->pusb_device has become NULL\n");
+ return -EFAULT;
+}
+rc = usb_set_interface(peasycap->pusb_device, peasycap->audio_interface, \
+ peasycap->audio_altsetting_on);
+JOT(8, "usb_set_interface(.,%i,%i) returned %i\n", peasycap->audio_interface, \
+ peasycap->audio_altsetting_on, rc);
+
+if ((struct usb_device *)NULL == peasycap->pusb_device) {
+ SAY("ERROR: peasycap->pusb_device has become NULL\n");
+ return -EFAULT;
+}
+rc = wakeup_device(peasycap->pusb_device);
+if (0 == rc)
+ JOT(8, "wakeup_device() returned %i\n", rc);
+else
+ JOT(8, "easysnd open(): ERROR: wakeup_device() returned %i\n", rc);
+
+if ((struct usb_device *)NULL == peasycap->pusb_device) {
+ SAY("ERROR: peasycap->pusb_device has become NULL\n");
+ return -EFAULT;
+}
+submit_audio_urbs(peasycap);
+peasycap->audio_idle = 0;
+
+peasycap->timeval1.tv_sec = 0;
+peasycap->timeval1.tv_usec = 0;
+
+JOT(4, "finished initialization\n");
+return 0;
+}
+/*****************************************************************************/
+int
+easysnd_release(struct inode *inode, struct file *file)
+{
+struct easycap *peasycap;
+
+JOT(4, "begins\n");
+
+peasycap = file->private_data;
+if (NULL == peasycap) {
+ SAY("ERROR: peasycap is NULL.\n");
+ return -EFAULT;
+}
+if (0 != kill_audio_urbs(peasycap)) {
+ SAY("ERROR: kill_audio_urbs() failed\n");
+ return -EFAULT;
+}
+JOT(4, "ending successfully\n");
+return 0;
+}
+/*****************************************************************************/
+ssize_t
+easysnd_read(struct file *file, char __user *puserspacebuffer, \
+ size_t kount, loff_t *poff)
+{
+struct timeval timeval;
+static struct timeval timeval1;
+static long long int audio_bytes, above, below, mean;
+struct signed_div_result sdr;
+unsigned char *p0;
+long int kount1, more, rc, l0, lm;
+int fragment;
+struct easycap *peasycap;
+struct data_buffer *pdata_buffer;
+size_t szret;
+
+/*---------------------------------------------------------------------------*/
+/*
+ * DO A BLOCKING READ TO TRANSFER DATA TO USER SPACE.
+ *
+ ******************************************************************************
+ ***** N.B. IF THIS FUNCTION RETURNS 0, NOTHING IS SEEN IN USER SPACE. ******
+ ***** THIS CONDITION SIGNIFIES END-OF-FILE. ******
+ ******************************************************************************
+ */
+/*---------------------------------------------------------------------------*/
+
+JOT(8, "===== easysnd_read(): kount=%i, *poff=%i\n", (int)kount, (int)(*poff));
+
+peasycap = (struct easycap *)(file->private_data);
+if (NULL == peasycap) {
+ SAY("ERROR in easysnd_read(): peasycap is NULL\n");
+ return -EFAULT;
+}
+/*---------------------------------------------------------------------------*/
+if ((0 > peasycap->audio_read) || \
+ (peasycap->audio_buffer_page_many <= peasycap->audio_read)) {
+ SAY("ERROR: peasycap->audio_read out of range\n");
+ return -EFAULT;
+}
+pdata_buffer = &peasycap->audio_buffer[peasycap->audio_read];
+if ((struct data_buffer *)NULL == pdata_buffer) {
+ SAY("ERROR: pdata_buffer is NULL\n");
+ return -EFAULT;
+}
+JOT(12, "before wait, %i=frag read %i=frag fill\n", \
+ (peasycap->audio_read / peasycap->audio_pages_per_fragment), \
+ (peasycap->audio_fill / peasycap->audio_pages_per_fragment));
+fragment = (peasycap->audio_read / peasycap->audio_pages_per_fragment);
+while ((fragment == (peasycap->audio_fill / \
+ peasycap->audio_pages_per_fragment)) || \
+ (0 == (PAGE_SIZE - (pdata_buffer->pto - pdata_buffer->pgo)))) {
+ if (file->f_flags & O_NONBLOCK) {
+ JOT(16, "returning -EAGAIN as instructed\n");
+ return -EAGAIN;
+ }
+ rc = wait_event_interruptible(peasycap->wq_audio, \
+ (peasycap->audio_idle || peasycap->audio_eof || \
+ ((fragment != (peasycap->audio_fill / \
+ peasycap->audio_pages_per_fragment)) && \
+ (0 < (PAGE_SIZE - (pdata_buffer->pto - pdata_buffer->pgo))))));
+ if (0 != rc) {
+ SAY("aborted by signal\n");
+ return -ERESTARTSYS;
+ }
+ if (peasycap->audio_eof) {
+ JOT(8, "returning 0 because %i=audio_eof\n", \
+ peasycap->audio_eof);
+ kill_audio_urbs(peasycap);
+ msleep(500);
+ return 0;
+ }
+ if (peasycap->audio_idle) {
+ JOT(16, "returning 0 because %i=audio_idle\n", \
+ peasycap->audio_idle);
+ return 0;
+ }
+ if (!peasycap->audio_isoc_streaming) {
+ JOT(16, "returning 0 because audio urbs not streaming\n");
+ return 0;
+ }
+}
+JOT(12, "after wait, %i=frag read %i=frag fill\n", \
+ (peasycap->audio_read / peasycap->audio_pages_per_fragment), \
+ (peasycap->audio_fill / peasycap->audio_pages_per_fragment));
+szret = (size_t)0;
+while (fragment == (peasycap->audio_read / \
+ peasycap->audio_pages_per_fragment)) {
+ if (NULL == pdata_buffer->pgo) {
+ SAY("ERROR: pdata_buffer->pgo is NULL\n");
+ return -EFAULT;
+ }
+ if (NULL == pdata_buffer->pto) {
+ SAY("ERROR: pdata_buffer->pto is NULL\n");
+ return -EFAULT;
+ }
+ kount1 = PAGE_SIZE - (pdata_buffer->pto - pdata_buffer->pgo);
+ if (0 > kount1) {
+ SAY("easysnd_read: MISTAKE: kount1 is negative\n");
+ return -ERESTARTSYS;
+ }
+ if (!kount1) {
+ (peasycap->audio_read)++;
+ if (peasycap->audio_buffer_page_many <= peasycap->audio_read)
+ peasycap->audio_read = 0;
+ JOT(12, "bumped peasycap->audio_read to %i\n", \
+ peasycap->audio_read);
+
+ if (fragment != (peasycap->audio_read / \
+ peasycap->audio_pages_per_fragment))
+ break;
+
+ if ((0 > peasycap->audio_read) || \
+ (peasycap->audio_buffer_page_many <= \
+ peasycap->audio_read)) {
+ SAY("ERROR: peasycap->audio_read out of range\n");
+ return -EFAULT;
+ }
+ pdata_buffer = &peasycap->audio_buffer[peasycap->audio_read];
+ if ((struct data_buffer *)NULL == pdata_buffer) {
+ SAY("ERROR: pdata_buffer is NULL\n");
+ return -EFAULT;
+ }
+ if (NULL == pdata_buffer->pgo) {
+ SAY("ERROR: pdata_buffer->pgo is NULL\n");
+ return -EFAULT;
+ }
+ if (NULL == pdata_buffer->pto) {
+ SAY("ERROR: pdata_buffer->pto is NULL\n");
+ return -EFAULT;
+ }
+ kount1 = PAGE_SIZE - (pdata_buffer->pto - pdata_buffer->pgo);
+ }
+ JOT(12, "ready to send %li bytes\n", (long int) kount1);
+ JOT(12, "still to send %li bytes\n", (long int) kount);
+ more = kount1;
+ if (more > kount)
+ more = kount;
+ JOT(12, "agreed to send %li bytes from page %i\n", \
+ more, peasycap->audio_read);
+ if (!more)
+ break;
+
+/*---------------------------------------------------------------------------*/
+/*
+ * ACCUMULATE DYNAMIC-RANGE INFORMATION
+ */
+/*---------------------------------------------------------------------------*/
+ p0 = (unsigned char *)pdata_buffer->pgo; l0 = 0; lm = more/2;
+ while (l0 < lm) {
+ SUMMER(p0, &peasycap->audio_sample, &peasycap->audio_niveau, \
+ &peasycap->audio_square); l0++; p0 += 2;
+ }
+/*---------------------------------------------------------------------------*/
+ rc = copy_to_user(puserspacebuffer, pdata_buffer->pto, more);
+ if (0 != rc) {
+ SAY("ERROR: copy_to_user() returned %li\n", rc);
+ return -EFAULT;
+ }
+ *poff += (loff_t)more;
+ szret += (size_t)more;
+ pdata_buffer->pto += more;
+ puserspacebuffer += more;
+ kount -= (size_t)more;
+}
+JOT(12, "after read, %i=frag read %i=frag fill\n", \
+ (peasycap->audio_read / peasycap->audio_pages_per_fragment), \
+ (peasycap->audio_fill / peasycap->audio_pages_per_fragment));
+if (kount < 0) {
+ SAY("MISTAKE: %li=kount %li=szret\n", \
+ (long int)kount, (long int)szret);
+}
+/*---------------------------------------------------------------------------*/
+/*
+ * CALCULATE DYNAMIC RANGE FOR (VAPOURWARE) AUTOMATIC VOLUME CONTROL
+ */
+/*---------------------------------------------------------------------------*/
+if (peasycap->audio_sample) {
+ below = peasycap->audio_sample;
+ above = peasycap->audio_square;
+ sdr = signed_div(above, below);
+ above = sdr.quotient;
+ mean = peasycap->audio_niveau;
+ sdr = signed_div(mean, peasycap->audio_sample);
+
+ JOT(8, "%8lli=mean %8lli=meansquare after %lli samples, =>\n", \
+ sdr.quotient, above, peasycap->audio_sample);
+
+ sdr = signed_div(above, 32768);
+ JOT(8, "audio dynamic range is roughly %lli\n", sdr.quotient);
+}
+/*---------------------------------------------------------------------------*/
+/*
+ * UPDATE THE AUDIO CLOCK
+ */
+/*---------------------------------------------------------------------------*/
+do_gettimeofday(&timeval);
+if (!peasycap->timeval1.tv_sec) {
+ audio_bytes = 0;
+ timeval1 = timeval;
+
+ if (mutex_lock_interruptible(&(peasycap->mutex_timeval1)))
+ return -ERESTARTSYS;
+ peasycap->timeval1 = timeval1;
+ mutex_unlock(&(peasycap->mutex_timeval1));
+ sdr.quotient = 192000;
+} else {
+ audio_bytes += (long long int) szret;
+ below = ((long long int)(1000000)) * \
+ ((long long int)(timeval.tv_sec - timeval1.tv_sec)) + \
+ (long long int)(timeval.tv_usec - timeval1.tv_usec);
+ above = 1000000 * ((long long int) audio_bytes);
+
+ if (below)
+ sdr = signed_div(above, below);
+ else
+ sdr.quotient = 192000;
+}
+JOT(8, "audio streaming at %lli bytes/second\n", sdr.quotient);
+if (mutex_lock_interruptible(&(peasycap->mutex_timeval1)))
+ return -ERESTARTSYS;
+peasycap->dnbydt = sdr.quotient;
+mutex_unlock(&(peasycap->mutex_timeval1));
+
+JOT(8, "returning %li\n", (long int)szret);
+return szret;
+}
+/*****************************************************************************/
+/*---------------------------------------------------------------------------*/
+/*
+ * SUBMIT ALL AUDIO URBS.
+ */
+/*---------------------------------------------------------------------------*/
+int
+submit_audio_urbs(struct easycap *peasycap)
+{
+struct data_urb *pdata_urb;
+struct urb *purb;
+struct list_head *plist_head;
+int j, isbad, m, rc;
+int isbuf;
+
+if ((struct list_head *)NULL == peasycap->purb_audio_head) {
+ SAY("ERROR: peasycap->urb_audio_head uninitialized\n");
+ return -EFAULT;
+}
+if ((struct usb_device *)NULL == peasycap->pusb_device) {
+ SAY("ERROR: peasycap->pusb_device is NULL\n");
+ return -EFAULT;
+}
+if (!peasycap->audio_isoc_streaming) {
+ JOT(4, "initial submission of all audio urbs\n");
+ rc = usb_set_interface(peasycap->pusb_device,
+ peasycap->audio_interface, \
+ peasycap->audio_altsetting_on);
+ JOT(8, "usb_set_interface(.,%i,%i) returned %i\n", \
+ peasycap->audio_interface, \
+ peasycap->audio_altsetting_on, rc);
+
+ isbad = 0; m = 0;
+ list_for_each(plist_head, (peasycap->purb_audio_head)) {
+ pdata_urb = list_entry(plist_head, struct data_urb, list_head);
+ if (NULL != pdata_urb) {
+ purb = pdata_urb->purb;
+ if (NULL != purb) {
+ isbuf = pdata_urb->isbuf;
+
+ purb->interval = 1;
+ purb->dev = peasycap->pusb_device;
+ purb->pipe = \
+ usb_rcvisocpipe(peasycap->pusb_device,\
+ peasycap->audio_endpointnumber);
+ purb->transfer_flags = URB_ISO_ASAP;
+ purb->transfer_buffer = \
+ peasycap->audio_isoc_buffer[isbuf].pgo;
+ purb->transfer_buffer_length = \
+ peasycap->audio_isoc_buffer_size;
+ purb->complete = easysnd_complete;
+ purb->context = peasycap;
+ purb->start_frame = 0;
+ purb->number_of_packets = \
+ peasycap->audio_isoc_framesperdesc;
+ for (j = 0; j < peasycap->\
+ audio_isoc_framesperdesc; \
+ j++) {
+ purb->iso_frame_desc[j].offset = j * \
+ peasycap->\
+ audio_isoc_maxframesize;
+ purb->iso_frame_desc[j].length = \
+ peasycap->\
+ audio_isoc_maxframesize;
+ }
+
+ rc = usb_submit_urb(purb, GFP_KERNEL);
+ if (0 != rc) {
+ isbad++;
+ SAY("ERROR: usb_submit_urb() failed" \
+ " for urb with rc:\n");
+ switch (rc) {
+ case -ENOMEM: {
+ SAY("ENOMEM\n"); break;
+ }
+ case -ENODEV: {
+ SAY("ENODEV\n"); break;
+ }
+ case -ENXIO: {
+ SAY("ENXIO\n"); break;
+ }
+ case -EINVAL: {
+ SAY("EINVAL\n"); break;
+ }
+ case -EAGAIN: {
+ SAY("EAGAIN\n"); break;
+ }
+ case -EFBIG: {
+ SAY("EFBIG\n"); break;
+ }
+ case -EPIPE: {
+ SAY("EPIPE\n"); break;
+ }
+ case -EMSGSIZE: {
+ SAY("EMSGSIZE\n"); break;
+ }
+ case -ENOSPC: {
+ SAY("ENOSPC\n"); break;
+ }
+ default: {
+ SAY("unknown error code %i\n",\
+ rc); break;
+ }
+ }
+ } else {
+ m++;
+ }
+ } else {
+ isbad++;
+ }
+ } else {
+ isbad++;
+ }
+ }
+ if (isbad) {
+ JOT(4, "attempting cleanup instead of submitting\n");
+ list_for_each(plist_head, (peasycap->purb_audio_head)) {
+ pdata_urb = list_entry(plist_head, struct data_urb, \
+ list_head);
+ if (NULL != pdata_urb) {
+ purb = pdata_urb->purb;
+ if (NULL != purb)
+ usb_kill_urb(purb);
+ }
+ }
+ peasycap->audio_isoc_streaming = 0;
+ } else {
+ peasycap->audio_isoc_streaming = 1;
+ JOT(4, "submitted %i audio urbs\n", m);
+ }
+} else
+ JOT(4, "already streaming audio urbs\n");
+
+return 0;
+}
+/*****************************************************************************/
+/*---------------------------------------------------------------------------*/
+/*
+ * KILL ALL AUDIO URBS.
+ */
+/*---------------------------------------------------------------------------*/
+int
+kill_audio_urbs(struct easycap *peasycap)
+{
+int m;
+struct list_head *plist_head;
+struct data_urb *pdata_urb;
+
+if (peasycap->audio_isoc_streaming) {
+ if ((struct list_head *)NULL != peasycap->purb_audio_head) {
+ peasycap->audio_isoc_streaming = 0;
+ JOT(4, "killing audio urbs\n");
+ m = 0;
+ list_for_each(plist_head, (peasycap->purb_audio_head)) {
+ pdata_urb = list_entry(plist_head, struct data_urb,
+ list_head);
+ if ((struct data_urb *)NULL != pdata_urb) {
+ if ((struct urb *)NULL != pdata_urb->purb) {
+ usb_kill_urb(pdata_urb->purb);
+ m++;
+ }
+ }
+ }
+ JOT(4, "%i audio urbs killed\n", m);
+ } else {
+ SAY("ERROR: peasycap->purb_audio_head is NULL\n");
+ return -EFAULT;
+ }
+} else {
+ JOT(8, "%i=audio_isoc_streaming, no audio urbs killed\n", \
+ peasycap->audio_isoc_streaming);
+}
+return 0;
+}
+/*****************************************************************************/
diff --git a/drivers/staging/easycap/easycap_sound.h b/drivers/staging/easycap/easycap_sound.h
new file mode 100644
index 00000000000..49127396902
--- /dev/null
+++ b/drivers/staging/easycap/easycap_sound.h
@@ -0,0 +1,28 @@
+/*****************************************************************************
+* *
+* easycap_sound.h *
+* *
+*****************************************************************************/
+/*
+ *
+ * Copyright (C) 2010 R.M. Thomas <rmthomas@sciolus.org>
+ *
+ *
+ * This is free software; you can redistribute it and/or modify
+ * 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 software 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 software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+*/
+/*****************************************************************************/
+extern struct easycap *peasycap;
+extern struct usb_driver easycap_usb_driver;
diff --git a/drivers/staging/easycap/easycap_standard.h b/drivers/staging/easycap/easycap_standard.h
new file mode 100644
index 00000000000..cadc8d27a85
--- /dev/null
+++ b/drivers/staging/easycap/easycap_standard.h
@@ -0,0 +1,27 @@
+/*****************************************************************************
+* *
+* easycap_standard.h *
+* *
+*****************************************************************************/
+/*
+ *
+ * Copyright (C) 2010 R.M. Thomas <rmthomas@sciolus.org>
+ *
+ *
+ * This is free software; you can redistribute it and/or modify
+ * 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 software 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 software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+*/
+/*****************************************************************************/
+extern struct easycap_standard easycap_standard[];
diff --git a/drivers/staging/easycap/easycap_testcard.c b/drivers/staging/easycap/easycap_testcard.c
new file mode 100644
index 00000000000..3c2ce28fab9
--- /dev/null
+++ b/drivers/staging/easycap/easycap_testcard.c
@@ -0,0 +1,392 @@
+/******************************************************************************
+* *
+* easycap_testcard.c *
+* *
+******************************************************************************/
+/*
+ *
+ * Copyright (C) 2010 R.M. Thomas <rmthomas@sciolus.org>
+ *
+ *
+ * This is free software; you can redistribute it and/or modify
+ * 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 software 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 software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+*/
+/*****************************************************************************/
+
+#include "easycap.h"
+#include "easycap_debug.h"
+
+/*****************************************************************************/
+#define TESTCARD_BYTESPERLINE (2 * 1440)
+void
+easycap_testcard(struct easycap *peasycap, int field_fill)
+{
+int total;
+int y, u, v, r, g, b;
+unsigned char uyvy[4];
+
+int i1, line, k, m, n, more, much, barwidth;
+unsigned char bfbar[TESTCARD_BYTESPERLINE / 8], *p1, *p2;
+struct data_buffer *pfield_buffer;
+
+JOT(8, "%i=field_fill\n", field_fill);
+
+if ((TESTCARD_BYTESPERLINE / 2) < peasycap->width) {
+ SAY("ERROR: image is too wide\n");
+ return;
+}
+if (peasycap->width % 16) {
+ SAY("ERROR: indivisible image width\n");
+ return;
+}
+
+total = 0;
+barwidth = (2 * peasycap->width) / 8;
+
+k = field_fill;
+m = 0;
+n = 0;
+
+for (line = 0; line < (peasycap->height / 2); line++) {
+ for (i1 = 0; i1 < 8; i1++) {
+ r = (i1 * 256)/8;
+ g = (i1 * 256)/8;
+ b = (i1 * 256)/8;
+
+ y = 299*r/1000 + 587*g/1000 + 114*b/1000 ;
+ u = -147*r/1000 - 289*g/1000 + 436*b/1000 ; u = u + 128;
+ v = 615*r/1000 - 515*g/1000 - 100*b/1000 ; v = v + 128;
+
+ uyvy[0] = 0xFF & u ;
+ uyvy[1] = 0xFF & y ;
+ uyvy[2] = 0xFF & v ;
+ uyvy[3] = 0xFF & y ;
+
+ p1 = &bfbar[0];
+ while (p1 < &bfbar[barwidth]) {
+ *p1++ = uyvy[0] ;
+ *p1++ = uyvy[1] ;
+ *p1++ = uyvy[2] ;
+ *p1++ = uyvy[3] ;
+ total += 4;
+ }
+
+ p1 = &bfbar[0];
+ more = barwidth;
+
+ while (more) {
+ if ((FIELD_BUFFER_SIZE/PAGE_SIZE) <= m) {
+ SAY("ERROR: bad m reached\n");
+ return;
+ }
+ if (PAGE_SIZE < n) {
+ SAY("ERROR: bad n reached\n"); return;
+ }
+
+ if (0 > more) {
+ SAY("ERROR: internal fault\n");
+ return;
+ }
+
+ much = PAGE_SIZE - n;
+ if (much > more)
+ much = more;
+ pfield_buffer = &peasycap->field_buffer[k][m];
+ p2 = pfield_buffer->pgo + n;
+ memcpy(p2, p1, much);
+
+ p1 += much;
+ n += much;
+ more -= much;
+ if (PAGE_SIZE == n) {
+ m++;
+ n = 0;
+ }
+ }
+ }
+}
+
+JOT(8, "%i=total\n", total);
+if (total != peasycap->width * peasycap->height)
+ SAY("ERROR: wrong number of bytes written: %i\n", total);
+return;
+}
+/*****************************************************************************/
+#if defined(EASYCAP_TESTTONE)
+/*-----------------------------------------------------------------------------
+THE tones[] ARRAY BELOW IS THE OUTPUT OF THIS PROGRAM,
+COMPILED gcc -o prog -lm prog.c
+- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+#include <stdio.h>
+#include <math.h>
+
+int main(void);
+int
+main(void)
+{
+int i1, i2, last;
+double d1, d2;
+
+last = 1024 - 1;
+d1 = 10.0*3.14159265/1024.0;
+printf("int tones[2048] =\n{\n");
+for (i1 = 0; i1 <= last; i1++)
+ {
+ d2 = ((double)i1) * d1;
+ i2 = (int)(16384.0*sin(d2));
+
+ if (last != i1)
+ {
+ printf("%6i, ", i2); printf("%6i, ", i2);
+ if (!((i1 + 1)%5)) printf("\n");
+ }
+ else
+ {
+ printf("%6i, ", i2); printf("%6i\n};\n", i2);
+ }
+ }
+return(0);
+}
+-----------------------------------------------------------------------------*/
+int tones[2048] = {
+ 0, 0, 502, 502, 1004, 1004, 1505, 1505, 2005, 2005,
+ 2503, 2503, 2998, 2998, 3491, 3491, 3980, 3980, 4466, 4466,
+ 4948, 4948, 5424, 5424, 5896, 5896, 6362, 6362, 6822, 6822,
+ 7276, 7276, 7723, 7723, 8162, 8162, 8594, 8594, 9018, 9018,
+ 9434, 9434, 9840, 9840, 10237, 10237, 10625, 10625, 11002, 11002,
+ 11370, 11370, 11726, 11726, 12072, 12072, 12406, 12406, 12728, 12728,
+ 13038, 13038, 13337, 13337, 13622, 13622, 13895, 13895, 14155, 14155,
+ 14401, 14401, 14634, 14634, 14853, 14853, 15058, 15058, 15249, 15249,
+ 15426, 15426, 15588, 15588, 15735, 15735, 15868, 15868, 15985, 15985,
+ 16088, 16088, 16175, 16175, 16248, 16248, 16305, 16305, 16346, 16346,
+ 16372, 16372, 16383, 16383, 16379, 16379, 16359, 16359, 16323, 16323,
+ 16272, 16272, 16206, 16206, 16125, 16125, 16028, 16028, 15917, 15917,
+ 15790, 15790, 15649, 15649, 15492, 15492, 15322, 15322, 15136, 15136,
+ 14937, 14937, 14723, 14723, 14496, 14496, 14255, 14255, 14001, 14001,
+ 13733, 13733, 13452, 13452, 13159, 13159, 12854, 12854, 12536, 12536,
+ 12207, 12207, 11866, 11866, 11513, 11513, 11150, 11150, 10777, 10777,
+ 10393, 10393, 10000, 10000, 9597, 9597, 9185, 9185, 8765, 8765,
+ 8336, 8336, 7900, 7900, 7456, 7456, 7005, 7005, 6547, 6547,
+ 6083, 6083, 5614, 5614, 5139, 5139, 4659, 4659, 4175, 4175,
+ 3687, 3687, 3196, 3196, 2701, 2701, 2204, 2204, 1705, 1705,
+ 1205, 1205, 703, 703, 201, 201, -301, -301, -803, -803,
+ -1305, -1305, -1805, -1805, -2304, -2304, -2801, -2801, -3294, -3294,
+ -3785, -3785, -4272, -4272, -4756, -4756, -5234, -5234, -5708, -5708,
+ -6176, -6176, -6639, -6639, -7095, -7095, -7545, -7545, -7988, -7988,
+ -8423, -8423, -8850, -8850, -9268, -9268, -9679, -9679, -10079, -10079,
+-10471, -10471, -10853, -10853, -11224, -11224, -11585, -11585, -11935, -11935,
+-12273, -12273, -12600, -12600, -12916, -12916, -13219, -13219, -13510, -13510,
+-13788, -13788, -14053, -14053, -14304, -14304, -14543, -14543, -14767, -14767,
+-14978, -14978, -15175, -15175, -15357, -15357, -15525, -15525, -15678, -15678,
+-15817, -15817, -15940, -15940, -16049, -16049, -16142, -16142, -16221, -16221,
+-16284, -16284, -16331, -16331, -16364, -16364, -16381, -16381, -16382, -16382,
+-16368, -16368, -16339, -16339, -16294, -16294, -16234, -16234, -16159, -16159,
+-16069, -16069, -15963, -15963, -15842, -15842, -15707, -15707, -15557, -15557,
+-15392, -15392, -15212, -15212, -15018, -15018, -14810, -14810, -14589, -14589,
+-14353, -14353, -14104, -14104, -13842, -13842, -13566, -13566, -13278, -13278,
+-12977, -12977, -12665, -12665, -12340, -12340, -12003, -12003, -11656, -11656,
+-11297, -11297, -10928, -10928, -10548, -10548, -10159, -10159, -9759, -9759,
+ -9351, -9351, -8934, -8934, -8509, -8509, -8075, -8075, -7634, -7634,
+ -7186, -7186, -6731, -6731, -6269, -6269, -5802, -5802, -5329, -5329,
+ -4852, -4852, -4369, -4369, -3883, -3883, -3393, -3393, -2900, -2900,
+ -2404, -2404, -1905, -1905, -1405, -1405, -904, -904, -402, -402,
+ 100, 100, 603, 603, 1105, 1105, 1605, 1605, 2105, 2105,
+ 2602, 2602, 3097, 3097, 3589, 3589, 4078, 4078, 4563, 4563,
+ 5043, 5043, 5519, 5519, 5990, 5990, 6455, 6455, 6914, 6914,
+ 7366, 7366, 7811, 7811, 8249, 8249, 8680, 8680, 9102, 9102,
+ 9516, 9516, 9920, 9920, 10315, 10315, 10701, 10701, 11077, 11077,
+ 11442, 11442, 11796, 11796, 12139, 12139, 12471, 12471, 12791, 12791,
+ 13099, 13099, 13395, 13395, 13678, 13678, 13948, 13948, 14205, 14205,
+ 14449, 14449, 14679, 14679, 14895, 14895, 15098, 15098, 15286, 15286,
+ 15459, 15459, 15618, 15618, 15763, 15763, 15892, 15892, 16007, 16007,
+ 16107, 16107, 16191, 16191, 16260, 16260, 16314, 16314, 16353, 16353,
+ 16376, 16376, 16384, 16384, 16376, 16376, 16353, 16353, 16314, 16314,
+ 16260, 16260, 16191, 16191, 16107, 16107, 16007, 16007, 15892, 15892,
+ 15763, 15763, 15618, 15618, 15459, 15459, 15286, 15286, 15098, 15098,
+ 14895, 14895, 14679, 14679, 14449, 14449, 14205, 14205, 13948, 13948,
+ 13678, 13678, 13395, 13395, 13099, 13099, 12791, 12791, 12471, 12471,
+ 12139, 12139, 11796, 11796, 11442, 11442, 11077, 11077, 10701, 10701,
+ 10315, 10315, 9920, 9920, 9516, 9516, 9102, 9102, 8680, 8680,
+ 8249, 8249, 7811, 7811, 7366, 7366, 6914, 6914, 6455, 6455,
+ 5990, 5990, 5519, 5519, 5043, 5043, 4563, 4563, 4078, 4078,
+ 3589, 3589, 3097, 3097, 2602, 2602, 2105, 2105, 1605, 1605,
+ 1105, 1105, 603, 603, 100, 100, -402, -402, -904, -904,
+ -1405, -1405, -1905, -1905, -2404, -2404, -2900, -2900, -3393, -3393,
+ -3883, -3883, -4369, -4369, -4852, -4852, -5329, -5329, -5802, -5802,
+ -6269, -6269, -6731, -6731, -7186, -7186, -7634, -7634, -8075, -8075,
+ -8509, -8509, -8934, -8934, -9351, -9351, -9759, -9759, -10159, -10159,
+-10548, -10548, -10928, -10928, -11297, -11297, -11656, -11656, -12003, -12003,
+-12340, -12340, -12665, -12665, -12977, -12977, -13278, -13278, -13566, -13566,
+-13842, -13842, -14104, -14104, -14353, -14353, -14589, -14589, -14810, -14810,
+-15018, -15018, -15212, -15212, -15392, -15392, -15557, -15557, -15707, -15707,
+-15842, -15842, -15963, -15963, -16069, -16069, -16159, -16159, -16234, -16234,
+-16294, -16294, -16339, -16339, -16368, -16368, -16382, -16382, -16381, -16381,
+-16364, -16364, -16331, -16331, -16284, -16284, -16221, -16221, -16142, -16142,
+-16049, -16049, -15940, -15940, -15817, -15817, -15678, -15678, -15525, -15525,
+-15357, -15357, -15175, -15175, -14978, -14978, -14767, -14767, -14543, -14543,
+-14304, -14304, -14053, -14053, -13788, -13788, -13510, -13510, -13219, -13219,
+-12916, -12916, -12600, -12600, -12273, -12273, -11935, -11935, -11585, -11585,
+-11224, -11224, -10853, -10853, -10471, -10471, -10079, -10079, -9679, -9679,
+ -9268, -9268, -8850, -8850, -8423, -8423, -7988, -7988, -7545, -7545,
+ -7095, -7095, -6639, -6639, -6176, -6176, -5708, -5708, -5234, -5234,
+ -4756, -4756, -4272, -4272, -3785, -3785, -3294, -3294, -2801, -2801,
+ -2304, -2304, -1805, -1805, -1305, -1305, -803, -803, -301, -301,
+ 201, 201, 703, 703, 1205, 1205, 1705, 1705, 2204, 2204,
+ 2701, 2701, 3196, 3196, 3687, 3687, 4175, 4175, 4659, 4659,
+ 5139, 5139, 5614, 5614, 6083, 6083, 6547, 6547, 7005, 7005,
+ 7456, 7456, 7900, 7900, 8336, 8336, 8765, 8765, 9185, 9185,
+ 9597, 9597, 10000, 10000, 10393, 10393, 10777, 10777, 11150, 11150,
+ 11513, 11513, 11866, 11866, 12207, 12207, 12536, 12536, 12854, 12854,
+ 13159, 13159, 13452, 13452, 13733, 13733, 14001, 14001, 14255, 14255,
+ 14496, 14496, 14723, 14723, 14937, 14937, 15136, 15136, 15322, 15322,
+ 15492, 15492, 15649, 15649, 15790, 15790, 15917, 15917, 16028, 16028,
+ 16125, 16125, 16206, 16206, 16272, 16272, 16323, 16323, 16359, 16359,
+ 16379, 16379, 16383, 16383, 16372, 16372, 16346, 16346, 16305, 16305,
+ 16248, 16248, 16175, 16175, 16088, 16088, 15985, 15985, 15868, 15868,
+ 15735, 15735, 15588, 15588, 15426, 15426, 15249, 15249, 15058, 15058,
+ 14853, 14853, 14634, 14634, 14401, 14401, 14155, 14155, 13895, 13895,
+ 13622, 13622, 13337, 13337, 13038, 13038, 12728, 12728, 12406, 12406,
+ 12072, 12072, 11726, 11726, 11370, 11370, 11002, 11002, 10625, 10625,
+ 10237, 10237, 9840, 9840, 9434, 9434, 9018, 9018, 8594, 8594,
+ 8162, 8162, 7723, 7723, 7276, 7276, 6822, 6822, 6362, 6362,
+ 5896, 5896, 5424, 5424, 4948, 4948, 4466, 4466, 3980, 3980,
+ 3491, 3491, 2998, 2998, 2503, 2503, 2005, 2005, 1505, 1505,
+ 1004, 1004, 502, 502, 0, 0, -502, -502, -1004, -1004,
+ -1505, -1505, -2005, -2005, -2503, -2503, -2998, -2998, -3491, -3491,
+ -3980, -3980, -4466, -4466, -4948, -4948, -5424, -5424, -5896, -5896,
+ -6362, -6362, -6822, -6822, -7276, -7276, -7723, -7723, -8162, -8162,
+ -8594, -8594, -9018, -9018, -9434, -9434, -9840, -9840, -10237, -10237,
+-10625, -10625, -11002, -11002, -11370, -11370, -11726, -11726, -12072, -12072,
+-12406, -12406, -12728, -12728, -13038, -13038, -13337, -13337, -13622, -13622,
+-13895, -13895, -14155, -14155, -14401, -14401, -14634, -14634, -14853, -14853,
+-15058, -15058, -15249, -15249, -15426, -15426, -15588, -15588, -15735, -15735,
+-15868, -15868, -15985, -15985, -16088, -16088, -16175, -16175, -16248, -16248,
+-16305, -16305, -16346, -16346, -16372, -16372, -16383, -16383, -16379, -16379,
+-16359, -16359, -16323, -16323, -16272, -16272, -16206, -16206, -16125, -16125,
+-16028, -16028, -15917, -15917, -15790, -15790, -15649, -15649, -15492, -15492,
+-15322, -15322, -15136, -15136, -14937, -14937, -14723, -14723, -14496, -14496,
+-14255, -14255, -14001, -14001, -13733, -13733, -13452, -13452, -13159, -13159,
+-12854, -12854, -12536, -12536, -12207, -12207, -11866, -11866, -11513, -11513,
+-11150, -11150, -10777, -10777, -10393, -10393, -10000, -10000, -9597, -9597,
+ -9185, -9185, -8765, -8765, -8336, -8336, -7900, -7900, -7456, -7456,
+ -7005, -7005, -6547, -6547, -6083, -6083, -5614, -5614, -5139, -5139,
+ -4659, -4659, -4175, -4175, -3687, -3687, -3196, -3196, -2701, -2701,
+ -2204, -2204, -1705, -1705, -1205, -1205, -703, -703, -201, -201,
+ 301, 301, 803, 803, 1305, 1305, 1805, 1805, 2304, 2304,
+ 2801, 2801, 3294, 3294, 3785, 3785, 4272, 4272, 4756, 4756,
+ 5234, 5234, 5708, 5708, 6176, 6176, 6639, 6639, 7095, 7095,
+ 7545, 7545, 7988, 7988, 8423, 8423, 8850, 8850, 9268, 9268,
+ 9679, 9679, 10079, 10079, 10471, 10471, 10853, 10853, 11224, 11224,
+ 11585, 11585, 11935, 11935, 12273, 12273, 12600, 12600, 12916, 12916,
+ 13219, 13219, 13510, 13510, 13788, 13788, 14053, 14053, 14304, 14304,
+ 14543, 14543, 14767, 14767, 14978, 14978, 15175, 15175, 15357, 15357,
+ 15525, 15525, 15678, 15678, 15817, 15817, 15940, 15940, 16049, 16049,
+ 16142, 16142, 16221, 16221, 16284, 16284, 16331, 16331, 16364, 16364,
+ 16381, 16381, 16382, 16382, 16368, 16368, 16339, 16339, 16294, 16294,
+ 16234, 16234, 16159, 16159, 16069, 16069, 15963, 15963, 15842, 15842,
+ 15707, 15707, 15557, 15557, 15392, 15392, 15212, 15212, 15018, 15018,
+ 14810, 14810, 14589, 14589, 14353, 14353, 14104, 14104, 13842, 13842,
+ 13566, 13566, 13278, 13278, 12977, 12977, 12665, 12665, 12340, 12340,
+ 12003, 12003, 11656, 11656, 11297, 11297, 10928, 10928, 10548, 10548,
+ 10159, 10159, 9759, 9759, 9351, 9351, 8934, 8934, 8509, 8509,
+ 8075, 8075, 7634, 7634, 7186, 7186, 6731, 6731, 6269, 6269,
+ 5802, 5802, 5329, 5329, 4852, 4852, 4369, 4369, 3883, 3883,
+ 3393, 3393, 2900, 2900, 2404, 2404, 1905, 1905, 1405, 1405,
+ 904, 904, 402, 402, -100, -100, -603, -603, -1105, -1105,
+ -1605, -1605, -2105, -2105, -2602, -2602, -3097, -3097, -3589, -3589,
+ -4078, -4078, -4563, -4563, -5043, -5043, -5519, -5519, -5990, -5990,
+ -6455, -6455, -6914, -6914, -7366, -7366, -7811, -7811, -8249, -8249,
+ -8680, -8680, -9102, -9102, -9516, -9516, -9920, -9920, -10315, -10315,
+-10701, -10701, -11077, -11077, -11442, -11442, -11796, -11796, -12139, -12139,
+-12471, -12471, -12791, -12791, -13099, -13099, -13395, -13395, -13678, -13678,
+-13948, -13948, -14205, -14205, -14449, -14449, -14679, -14679, -14895, -14895,
+-15098, -15098, -15286, -15286, -15459, -15459, -15618, -15618, -15763, -15763,
+-15892, -15892, -16007, -16007, -16107, -16107, -16191, -16191, -16260, -16260,
+-16314, -16314, -16353, -16353, -16376, -16376, -16383, -16383, -16376, -16376,
+-16353, -16353, -16314, -16314, -16260, -16260, -16191, -16191, -16107, -16107,
+-16007, -16007, -15892, -15892, -15763, -15763, -15618, -15618, -15459, -15459,
+-15286, -15286, -15098, -15098, -14895, -14895, -14679, -14679, -14449, -14449,
+-14205, -14205, -13948, -13948, -13678, -13678, -13395, -13395, -13099, -13099,
+-12791, -12791, -12471, -12471, -12139, -12139, -11796, -11796, -11442, -11442,
+-11077, -11077, -10701, -10701, -10315, -10315, -9920, -9920, -9516, -9516,
+ -9102, -9102, -8680, -8680, -8249, -8249, -7811, -7811, -7366, -7366,
+ -6914, -6914, -6455, -6455, -5990, -5990, -5519, -5519, -5043, -5043,
+ -4563, -4563, -4078, -4078, -3589, -3589, -3097, -3097, -2602, -2602,
+ -2105, -2105, -1605, -1605, -1105, -1105, -603, -603, -100, -100,
+ 402, 402, 904, 904, 1405, 1405, 1905, 1905, 2404, 2404,
+ 2900, 2900, 3393, 3393, 3883, 3883, 4369, 4369, 4852, 4852,
+ 5329, 5329, 5802, 5802, 6269, 6269, 6731, 6731, 7186, 7186,
+ 7634, 7634, 8075, 8075, 8509, 8509, 8934, 8934, 9351, 9351,
+ 9759, 9759, 10159, 10159, 10548, 10548, 10928, 10928, 11297, 11297,
+ 11656, 11656, 12003, 12003, 12340, 12340, 12665, 12665, 12977, 12977,
+ 13278, 13278, 13566, 13566, 13842, 13842, 14104, 14104, 14353, 14353,
+ 14589, 14589, 14810, 14810, 15018, 15018, 15212, 15212, 15392, 15392,
+ 15557, 15557, 15707, 15707, 15842, 15842, 15963, 15963, 16069, 16069,
+ 16159, 16159, 16234, 16234, 16294, 16294, 16339, 16339, 16368, 16368,
+ 16382, 16382, 16381, 16381, 16364, 16364, 16331, 16331, 16284, 16284,
+ 16221, 16221, 16142, 16142, 16049, 16049, 15940, 15940, 15817, 15817,
+ 15678, 15678, 15525, 15525, 15357, 15357, 15175, 15175, 14978, 14978,
+ 14767, 14767, 14543, 14543, 14304, 14304, 14053, 14053, 13788, 13788,
+ 13510, 13510, 13219, 13219, 12916, 12916, 12600, 12600, 12273, 12273,
+ 11935, 11935, 11585, 11585, 11224, 11224, 10853, 10853, 10471, 10471,
+ 10079, 10079, 9679, 9679, 9268, 9268, 8850, 8850, 8423, 8423,
+ 7988, 7988, 7545, 7545, 7095, 7095, 6639, 6639, 6176, 6176,
+ 5708, 5708, 5234, 5234, 4756, 4756, 4272, 4272, 3785, 3785,
+ 3294, 3294, 2801, 2801, 2304, 2304, 1805, 1805, 1305, 1305,
+ 803, 803, 301, 301, -201, -201, -703, -703, -1205, -1205,
+ -1705, -1705, -2204, -2204, -2701, -2701, -3196, -3196, -3687, -3687,
+ -4175, -4175, -4659, -4659, -5139, -5139, -5614, -5614, -6083, -6083,
+ -6547, -6547, -7005, -7005, -7456, -7456, -7900, -7900, -8336, -8336,
+ -8765, -8765, -9185, -9185, -9597, -9597, -10000, -10000, -10393, -10393,
+-10777, -10777, -11150, -11150, -11513, -11513, -11866, -11866, -12207, -12207,
+-12536, -12536, -12854, -12854, -13159, -13159, -13452, -13452, -13733, -13733,
+-14001, -14001, -14255, -14255, -14496, -14496, -14723, -14723, -14937, -14937,
+-15136, -15136, -15322, -15322, -15492, -15492, -15649, -15649, -15790, -15790,
+-15917, -15917, -16028, -16028, -16125, -16125, -16206, -16206, -16272, -16272,
+-16323, -16323, -16359, -16359, -16379, -16379, -16383, -16383, -16372, -16372,
+-16346, -16346, -16305, -16305, -16248, -16248, -16175, -16175, -16088, -16088,
+-15985, -15985, -15868, -15868, -15735, -15735, -15588, -15588, -15426, -15426,
+-15249, -15249, -15058, -15058, -14853, -14853, -14634, -14634, -14401, -14401,
+-14155, -14155, -13895, -13895, -13622, -13622, -13337, -13337, -13038, -13038,
+-12728, -12728, -12406, -12406, -12072, -12072, -11726, -11726, -11370, -11370,
+-11002, -11002, -10625, -10625, -10237, -10237, -9840, -9840, -9434, -9434,
+ -9018, -9018, -8594, -8594, -8162, -8162, -7723, -7723, -7276, -7276,
+ -6822, -6822, -6362, -6362, -5896, -5896, -5424, -5424, -4948, -4948,
+ -4466, -4466, -3980, -3980, -3491, -3491, -2998, -2998, -2503, -2503,
+ -2005, -2005, -1505, -1505, -1004, -1004, -502, -502
+};
+/*****************************************************************************/
+void
+easysnd_testtone(struct easycap *peasycap, int audio_fill)
+{
+int i1;
+unsigned char *p2;
+struct data_buffer *paudio_buffer;
+
+JOT(8, "%i=audio_fill\n", audio_fill);
+
+paudio_buffer = &peasycap->audio_buffer[audio_fill];
+
+p2 = (unsigned char *)(paudio_buffer->pgo);
+for (i1 = 0; i1 < PAGE_SIZE; i1 += 4, p2 += 4) {
+ *p2 = (unsigned char) (0x00FF & tones[i1/2]);
+ *(p2 + 1) = (unsigned char)((0xFF00 & tones[i1/2]) >> 8);
+ *(p2 + 2) = (unsigned char) (0x00FF & tones[i1/2 + 1]);
+ *(p2 + 3) = (unsigned char)((0xFF00 & tones[i1/2 + 1]) >> 8);
+ }
+return;
+}
+#endif /*EASYCAP_TESTTONE*/
+/*****************************************************************************/
diff --git a/drivers/staging/et131x/et1310_phy.c b/drivers/staging/et131x/et1310_phy.c
index a6d9f29ff49..21c5eeec62d 100644
--- a/drivers/staging/et131x/et1310_phy.c
+++ b/drivers/staging/et131x/et1310_phy.c
@@ -760,7 +760,8 @@ void et131x_Mii_check(struct et131x_adapter *etdev,
if (etdev->linkspeed == TRUEPHY_SPEED_10MBPS) {
/* NOTE - Is there a way to query this without
* TruePHY?
- * && TRU_QueryCoreType(etdev->hTruePhy, 0) == EMI_TRUEPHY_A13O) {
+ * && TRU_QueryCoreType(etdev->hTruePhy, 0) ==
+ * EMI_TRUEPHY_A13O) {
*/
u16 Register18;
@@ -778,7 +779,7 @@ void et131x_Mii_check(struct et131x_adapter *etdev,
* in the LinkDetectionDPC).
*/
if (!(etdev->Flags & fMP_ADAPTER_LINK_DETECTION) ||
- (etdev->MediaState == NETIF_STATUS_MEDIA_DISCONNECT)) {
+ (etdev->MediaState == NETIF_STATUS_MEDIA_DISCONNECT)) {
spin_lock_irqsave(&etdev->Lock, flags);
etdev->MediaState =
NETIF_STATUS_MEDIA_DISCONNECT;
@@ -836,7 +837,8 @@ void et131x_Mii_check(struct et131x_adapter *etdev,
/*
* NOTE - Is there a way to query this without
* TruePHY?
- * && TRU_QueryCoreType(etdev->hTruePhy, 0)== EMI_TRUEPHY_A13O) {
+ * && TRU_QueryCoreType(etdev->hTruePhy, 0)==
+ * EMI_TRUEPHY_A13O) {
*/
u16 Register18;
diff --git a/drivers/staging/hv/Kconfig b/drivers/staging/hv/Kconfig
index 97480f5c659..7455c804962 100644
--- a/drivers/staging/hv/Kconfig
+++ b/drivers/staging/hv/Kconfig
@@ -17,7 +17,7 @@ config HYPERV_STORAGE
config HYPERV_BLOCK
tristate "Microsoft Hyper-V virtual block driver"
- depends on BLOCK && SCSI && LBDAF
+ depends on BLOCK && SCSI && (LBDAF || 64BIT)
default HYPERV
help
Select this option to enable the Hyper-V virtual block driver.
diff --git a/drivers/staging/hv/Makefile b/drivers/staging/hv/Makefile
index 1866f80a45d..b63515c20f5 100644
--- a/drivers/staging/hv/Makefile
+++ b/drivers/staging/hv/Makefile
@@ -1,4 +1,4 @@
-obj-$(CONFIG_HYPERV) += hv_vmbus.o
+obj-$(CONFIG_HYPERV) += hv_vmbus.o hv_timesource.o
obj-$(CONFIG_HYPERV_STORAGE) += hv_storvsc.o
obj-$(CONFIG_HYPERV_BLOCK) += hv_blkvsc.o
obj-$(CONFIG_HYPERV_NET) += hv_netvsc.o
diff --git a/drivers/staging/hv/blkvsc.c b/drivers/staging/hv/blkvsc.c
index 0daebc472e6..929238a6ce8 100644
--- a/drivers/staging/hv/blkvsc.c
+++ b/drivers/staging/hv/blkvsc.c
@@ -40,15 +40,11 @@ static int BlkVscOnDeviceAdd(struct hv_device *Device, void *AdditionalInfo)
struct storvsc_device_info *deviceInfo;
int ret = 0;
- DPRINT_ENTER(BLKVSC);
-
deviceInfo = (struct storvsc_device_info *)AdditionalInfo;
ret = StorVscOnDeviceAdd(Device, AdditionalInfo);
- if (ret != 0) {
- DPRINT_EXIT(BLKVSC);
+ if (ret != 0)
return ret;
- }
/*
* We need to use the device instance guid to set the path and target
@@ -63,8 +59,6 @@ static int BlkVscOnDeviceAdd(struct hv_device *Device, void *AdditionalInfo)
deviceInfo->TargetId = Device->deviceInstance.data[5] << 8 |
Device->deviceInstance.data[4];
- DPRINT_EXIT(BLKVSC);
-
return ret;
}
@@ -73,8 +67,6 @@ int BlkVscInitialize(struct hv_driver *Driver)
struct storvsc_driver_object *storDriver;
int ret = 0;
- DPRINT_ENTER(BLKVSC);
-
storDriver = (struct storvsc_driver_object *)Driver;
/* Make sure we are at least 2 pages since 1 page is used for control */
@@ -106,7 +98,5 @@ int BlkVscInitialize(struct hv_driver *Driver)
storDriver->Base.OnCleanup = StorVscOnCleanup;
storDriver->OnIORequest = StorVscOnIORequest;
- DPRINT_EXIT(BLKVSC);
-
return ret;
}
diff --git a/drivers/staging/hv/blkvsc_drv.c b/drivers/staging/hv/blkvsc_drv.c
index 61bd0be5fb1..f7ea2a3efed 100644
--- a/drivers/staging/hv/blkvsc_drv.c
+++ b/drivers/staging/hv/blkvsc_drv.c
@@ -175,8 +175,6 @@ static int blkvsc_drv_init(int (*drv_init)(struct hv_driver *drv))
struct driver_context *drv_ctx = &g_blkvsc_drv.drv_ctx;
int ret;
- DPRINT_ENTER(BLKVSC_DRV);
-
vmbus_get_interface(&storvsc_drv_obj->Base.VmbusChannelInterface);
storvsc_drv_obj->RingBufferSize = blkvsc_ringbuffer_size;
@@ -195,8 +193,6 @@ static int blkvsc_drv_init(int (*drv_init)(struct hv_driver *drv))
/* The driver belongs to vmbus */
ret = vmbus_child_driver_register(drv_ctx);
- DPRINT_EXIT(BLKVSC_DRV);
-
return ret;
}
@@ -214,8 +210,6 @@ static void blkvsc_drv_exit(void)
struct device *current_dev;
int ret;
- DPRINT_ENTER(BLKVSC_DRV);
-
while (1) {
current_dev = NULL;
@@ -241,8 +235,6 @@ static void blkvsc_drv_exit(void)
vmbus_child_driver_unregister(drv_ctx);
- DPRINT_EXIT(BLKVSC_DRV);
-
return;
}
@@ -268,8 +260,6 @@ static int blkvsc_probe(struct device *device)
static int ide0_registered;
static int ide1_registered;
- DPRINT_ENTER(BLKVSC_DRV);
-
DPRINT_DBG(BLKVSC_DRV, "blkvsc_probe - enter");
if (!storvsc_drv_obj->Base.OnDeviceAdd) {
@@ -413,8 +403,6 @@ Cleanup:
blkdev = NULL;
}
- DPRINT_EXIT(BLKVSC_DRV);
-
return ret;
}
@@ -751,14 +739,10 @@ static int blkvsc_remove(struct device *device)
unsigned long flags;
int ret;
- DPRINT_ENTER(BLKVSC_DRV);
-
DPRINT_DBG(BLKVSC_DRV, "blkvsc_remove()\n");
- if (!storvsc_drv_obj->Base.OnDeviceRemove) {
- DPRINT_EXIT(BLKVSC_DRV);
+ if (!storvsc_drv_obj->Base.OnDeviceRemove)
return -1;
- }
/*
* Call to the vsc driver to let it know that the device is being
@@ -802,8 +786,6 @@ static int blkvsc_remove(struct device *device)
kfree(blkdev);
- DPRINT_EXIT(BLKVSC_DRV);
-
return ret;
}
@@ -1492,22 +1474,16 @@ static int __init blkvsc_init(void)
BUILD_BUG_ON(sizeof(sector_t) != 8);
- DPRINT_ENTER(BLKVSC_DRV);
-
DPRINT_INFO(BLKVSC_DRV, "Blkvsc initializing....");
ret = blkvsc_drv_init(BlkVscInitialize);
- DPRINT_EXIT(BLKVSC_DRV);
-
return ret;
}
static void __exit blkvsc_exit(void)
{
- DPRINT_ENTER(BLKVSC_DRV);
blkvsc_drv_exit();
- DPRINT_ENTER(BLKVSC_DRV);
}
MODULE_LICENSE("GPL");
diff --git a/drivers/staging/hv/channel.c b/drivers/staging/hv/channel.c
index f047c5a7f64..fece30c303a 100644
--- a/drivers/staging/hv/channel.c
+++ b/drivers/staging/hv/channel.c
@@ -74,8 +74,6 @@ static void VmbusChannelSetEvent(struct vmbus_channel *Channel)
{
struct hv_monitor_page *monitorPage;
- DPRINT_ENTER(VMBUS);
-
if (Channel->OfferMsg.MonitorAllocated) {
/* Each u32 represents 32 channels */
set_bit(Channel->OfferMsg.ChildRelId & 31,
@@ -92,8 +90,6 @@ static void VmbusChannelSetEvent(struct vmbus_channel *Channel)
} else {
VmbusSetEvent(Channel->OfferMsg.ChildRelId);
}
-
- DPRINT_EXIT(VMBUS);
}
#if 0
@@ -101,8 +97,6 @@ static void VmbusChannelClearEvent(struct vmbus_channel *channel)
{
struct hv_monitor_page *monitorPage;
- DPRINT_ENTER(VMBUS);
-
if (Channel->OfferMsg.MonitorAllocated) {
/* Each u32 represents 32 channels */
clear_bit(Channel->OfferMsg.ChildRelId & 31,
@@ -117,8 +111,6 @@ static void VmbusChannelClearEvent(struct vmbus_channel *channel)
(unsigned long *)&monitorPage->TriggerGroup
[Channel->MonitorGroup].Pending);
}
-
- DPRINT_EXIT(VMBUS);
}
#endif
@@ -180,8 +172,6 @@ int VmbusChannelOpen(struct vmbus_channel *NewChannel, u32 SendRingBufferSize,
unsigned long flags;
int ret, err = 0;
- DPRINT_ENTER(VMBUS);
-
/* Aligned to page size */
/* ASSERT(!(SendRingBufferSize & (PAGE_SIZE - 1))); */
/* ASSERT(!(RecvRingBufferSize & (PAGE_SIZE - 1))); */
@@ -305,9 +295,6 @@ Cleanup:
kfree(openInfo->WaitEvent);
kfree(openInfo);
-
- DPRINT_EXIT(VMBUS);
-
return 0;
errorout:
@@ -465,6 +452,8 @@ static int VmbusChannelCreateGpadlHeader(void *Kbuffer, u32 Size,
sizeof(struct vmbus_channel_gpadl_header) +
sizeof(struct gpa_range) + pageCount * sizeof(u64);
msgHeader = kzalloc(msgSize, GFP_KERNEL);
+ if (msgHeader == NULL)
+ goto nomem;
msgHeader->MessageSize = msgSize;
gpaHeader = (struct vmbus_channel_gpadl_header *)msgHeader->Msg;
@@ -509,8 +498,6 @@ int VmbusChannelEstablishGpadl(struct vmbus_channel *Channel, void *Kbuffer,
unsigned long flags;
int ret = 0;
- DPRINT_ENTER(VMBUS);
-
nextGpadlHandle = atomic_read(&gVmbusConnection.NextGpadlHandle);
atomic_inc(&gVmbusConnection.NextGpadlHandle);
@@ -592,9 +579,6 @@ Cleanup:
kfree(msgInfo->WaitEvent);
kfree(msgInfo);
-
- DPRINT_EXIT(VMBUS);
-
return ret;
}
@@ -608,8 +592,6 @@ int VmbusChannelTeardownGpadl(struct vmbus_channel *Channel, u32 GpadlHandle)
unsigned long flags;
int ret;
- DPRINT_ENTER(VMBUS);
-
/* ASSERT(GpadlHandle != 0); */
info = kmalloc(sizeof(*info) +
@@ -650,9 +632,6 @@ int VmbusChannelTeardownGpadl(struct vmbus_channel *Channel, u32 GpadlHandle)
kfree(info->WaitEvent);
kfree(info);
-
- DPRINT_EXIT(VMBUS);
-
return ret;
}
@@ -666,8 +645,6 @@ void VmbusChannelClose(struct vmbus_channel *Channel)
unsigned long flags;
int ret;
- DPRINT_ENTER(VMBUS);
-
/* Stop callback and cancel the timer asap */
Channel->OnChannelCallback = NULL;
del_timer_sync(&Channel->poll_timer);
@@ -720,8 +697,6 @@ void VmbusChannelClose(struct vmbus_channel *Channel)
FreeVmbusChannel(Channel);
}
-
- DPRINT_EXIT(VMBUS);
}
/**
@@ -749,7 +724,6 @@ int VmbusChannelSendPacket(struct vmbus_channel *Channel, const void *Buffer,
u64 alignedData = 0;
int ret;
- DPRINT_ENTER(VMBUS);
DPRINT_DBG(VMBUS, "channel %p buffer %p len %d",
Channel, Buffer, BufferLen);
@@ -776,8 +750,6 @@ int VmbusChannelSendPacket(struct vmbus_channel *Channel, const void *Buffer,
if (ret == 0 && !GetRingBufferInterruptMask(&Channel->Outbound))
VmbusChannelSetEvent(Channel);
- DPRINT_EXIT(VMBUS);
-
return ret;
}
EXPORT_SYMBOL(VmbusChannelSendPacket);
@@ -800,8 +772,6 @@ int VmbusChannelSendPacketPageBuffer(struct vmbus_channel *Channel,
struct scatterlist bufferList[3];
u64 alignedData = 0;
- DPRINT_ENTER(VMBUS);
-
if (PageCount > MAX_PAGE_BUFFER_COUNT)
return -EINVAL;
@@ -844,8 +814,6 @@ int VmbusChannelSendPacketPageBuffer(struct vmbus_channel *Channel,
if (ret == 0 && !GetRingBufferInterruptMask(&Channel->Outbound))
VmbusChannelSetEvent(Channel);
- DPRINT_EXIT(VMBUS);
-
return ret;
}
@@ -867,8 +835,6 @@ int VmbusChannelSendPacketMultiPageBuffer(struct vmbus_channel *Channel,
u32 PfnCount = NUM_PAGES_SPANNED(MultiPageBuffer->Offset,
MultiPageBuffer->Length);
- DPRINT_ENTER(VMBUS);
-
DumpVmbusChannel(Channel);
DPRINT_DBG(VMBUS, "data buffer - offset %u len %u pfn count %u",
@@ -914,8 +880,6 @@ int VmbusChannelSendPacketMultiPageBuffer(struct vmbus_channel *Channel,
if (ret == 0 && !GetRingBufferInterruptMask(&Channel->Outbound))
VmbusChannelSetEvent(Channel);
- DPRINT_EXIT(VMBUS);
-
return ret;
}
@@ -942,8 +906,6 @@ int VmbusChannelRecvPacket(struct vmbus_channel *Channel, void *Buffer,
int ret;
unsigned long flags;
- DPRINT_ENTER(VMBUS);
-
*BufferActualLen = 0;
*RequestId = 0;
@@ -955,7 +917,6 @@ int VmbusChannelRecvPacket(struct vmbus_channel *Channel, void *Buffer,
spin_unlock_irqrestore(&Channel->inbound_lock, flags);
/* DPRINT_DBG(VMBUS, "nothing to read!!"); */
- DPRINT_EXIT(VMBUS);
return 0;
}
@@ -977,8 +938,6 @@ int VmbusChannelRecvPacket(struct vmbus_channel *Channel, void *Buffer,
DPRINT_ERR(VMBUS, "buffer too small - got %d needs %d",
BufferLen, userLen);
- DPRINT_EXIT(VMBUS);
-
return -1;
}
@@ -990,8 +949,6 @@ int VmbusChannelRecvPacket(struct vmbus_channel *Channel, void *Buffer,
spin_unlock_irqrestore(&Channel->inbound_lock, flags);
- DPRINT_EXIT(VMBUS);
-
return 0;
}
EXPORT_SYMBOL(VmbusChannelRecvPacket);
@@ -1009,8 +966,6 @@ int VmbusChannelRecvPacketRaw(struct vmbus_channel *Channel, void *Buffer,
int ret;
unsigned long flags;
- DPRINT_ENTER(VMBUS);
-
*BufferActualLen = 0;
*RequestId = 0;
@@ -1022,7 +977,6 @@ int VmbusChannelRecvPacketRaw(struct vmbus_channel *Channel, void *Buffer,
spin_unlock_irqrestore(&Channel->inbound_lock, flags);
/* DPRINT_DBG(VMBUS, "nothing to read!!"); */
- DPRINT_EXIT(VMBUS);
return 0;
}
@@ -1043,7 +997,6 @@ int VmbusChannelRecvPacketRaw(struct vmbus_channel *Channel, void *Buffer,
DPRINT_ERR(VMBUS, "buffer too small - needed %d bytes but "
"got space for only %d bytes", packetLen, BufferLen);
- DPRINT_EXIT(VMBUS);
return -2;
}
@@ -1053,9 +1006,6 @@ int VmbusChannelRecvPacketRaw(struct vmbus_channel *Channel, void *Buffer,
ret = RingBufferRead(&Channel->Inbound, Buffer, packetLen, 0);
spin_unlock_irqrestore(&Channel->inbound_lock, flags);
-
- DPRINT_EXIT(VMBUS);
-
return 0;
}
diff --git a/drivers/staging/hv/channel_mgmt.c b/drivers/staging/hv/channel_mgmt.c
index 12db555a3a5..6ccf505e802 100644
--- a/drivers/staging/hv/channel_mgmt.c
+++ b/drivers/staging/hv/channel_mgmt.c
@@ -267,15 +267,11 @@ static inline void ReleaseVmbusChannel(void *context)
{
struct vmbus_channel *channel = context;
- DPRINT_ENTER(VMBUS);
-
DPRINT_DBG(VMBUS, "releasing channel (%p)", channel);
destroy_workqueue(channel->ControlWQ);
DPRINT_DBG(VMBUS, "channel released (%p)", channel);
kfree(channel);
-
- DPRINT_EXIT(VMBUS);
}
/*
@@ -326,8 +322,6 @@ static void VmbusChannelProcessOffer(void *context)
int cnt;
unsigned long flags;
- DPRINT_ENTER(VMBUS);
-
/* Make sure this is a new offer */
spin_lock_irqsave(&gVmbusConnection.channel_lock, flags);
@@ -353,7 +347,6 @@ static void VmbusChannelProcessOffer(void *context)
DPRINT_DBG(VMBUS, "Ignoring duplicate offer for relid (%d)",
newChannel->OfferMsg.ChildRelId);
FreeVmbusChannel(newChannel);
- DPRINT_EXIT(VMBUS);
return;
}
@@ -410,7 +403,6 @@ static void VmbusChannelProcessOffer(void *context)
}
}
}
- DPRINT_EXIT(VMBUS);
}
/*
@@ -420,9 +412,7 @@ static void VmbusChannelProcessRescindOffer(void *context)
{
struct vmbus_channel *channel = context;
- DPRINT_ENTER(VMBUS);
VmbusChildDeviceRemove(channel->DeviceObject);
- DPRINT_EXIT(VMBUS);
}
/*
@@ -441,8 +431,6 @@ static void VmbusChannelOnOffer(struct vmbus_channel_message_header *hdr)
int i;
int fSupported = 0;
- DPRINT_ENTER(VMBUS);
-
offer = (struct vmbus_channel_offer_channel *)hdr;
for (i = 0; i < MAX_NUM_DEVICE_CLASSES_SUPPORTED; i++) {
if (memcmp(&offer->Offer.InterfaceType,
@@ -455,7 +443,6 @@ static void VmbusChannelOnOffer(struct vmbus_channel_message_header *hdr)
if (!fSupported) {
DPRINT_DBG(VMBUS, "Ignoring channel offer notification for "
"child relid %d", offer->ChildRelId);
- DPRINT_EXIT(VMBUS);
return;
}
@@ -504,8 +491,6 @@ static void VmbusChannelOnOffer(struct vmbus_channel_message_header *hdr)
/* TODO: Make sure the offer comes from our parent partition */
osd_schedule_callback(newChannel->ControlWQ, VmbusChannelProcessOffer,
newChannel);
-
- DPRINT_EXIT(VMBUS);
}
/*
@@ -518,8 +503,6 @@ static void VmbusChannelOnOfferRescind(struct vmbus_channel_message_header *hdr)
struct vmbus_channel_rescind_offer *rescind;
struct vmbus_channel *channel;
- DPRINT_ENTER(VMBUS);
-
rescind = (struct vmbus_channel_rescind_offer *)hdr;
channel = GetChannelFromRelId(rescind->ChildRelId);
if (channel == NULL) {
@@ -531,8 +514,6 @@ static void VmbusChannelOnOfferRescind(struct vmbus_channel_message_header *hdr)
osd_schedule_callback(channel->ControlWQ,
VmbusChannelProcessRescindOffer,
channel);
-
- DPRINT_EXIT(VMBUS);
}
/*
@@ -543,8 +524,6 @@ static void VmbusChannelOnOfferRescind(struct vmbus_channel_message_header *hdr)
static void VmbusChannelOnOffersDelivered(
struct vmbus_channel_message_header *hdr)
{
- DPRINT_ENTER(VMBUS);
- DPRINT_EXIT(VMBUS);
}
/*
@@ -563,8 +542,6 @@ static void VmbusChannelOnOpenResult(struct vmbus_channel_message_header *hdr)
struct vmbus_channel_open_channel *openMsg;
unsigned long flags;
- DPRINT_ENTER(VMBUS);
-
result = (struct vmbus_channel_open_result *)hdr;
DPRINT_DBG(VMBUS, "vmbus open result - %d", result->Status);
@@ -591,8 +568,6 @@ static void VmbusChannelOnOpenResult(struct vmbus_channel_message_header *hdr)
}
}
spin_unlock_irqrestore(&gVmbusConnection.channelmsg_lock, flags);
-
- DPRINT_EXIT(VMBUS);
}
/*
@@ -611,8 +586,6 @@ static void VmbusChannelOnGpadlCreated(struct vmbus_channel_message_header *hdr)
struct vmbus_channel_gpadl_header *gpadlHeader;
unsigned long flags;
- DPRINT_ENTER(VMBUS);
-
gpadlCreated = (struct vmbus_channel_gpadl_created *)hdr;
DPRINT_DBG(VMBUS, "vmbus gpadl created result - %d",
gpadlCreated->CreationStatus);
@@ -643,8 +616,6 @@ static void VmbusChannelOnGpadlCreated(struct vmbus_channel_message_header *hdr)
}
}
spin_unlock_irqrestore(&gVmbusConnection.channelmsg_lock, flags);
-
- DPRINT_EXIT(VMBUS);
}
/*
@@ -664,8 +635,6 @@ static void VmbusChannelOnGpadlTorndown(
struct vmbus_channel_gpadl_teardown *gpadlTeardown;
unsigned long flags;
- DPRINT_ENTER(VMBUS);
-
gpadlTorndown = (struct vmbus_channel_gpadl_torndown *)hdr;
/*
@@ -691,8 +660,6 @@ static void VmbusChannelOnGpadlTorndown(
}
}
spin_unlock_irqrestore(&gVmbusConnection.channelmsg_lock, flags);
-
- DPRINT_EXIT(VMBUS);
}
/*
@@ -712,8 +679,6 @@ static void VmbusChannelOnVersionResponse(
struct vmbus_channel_version_response *versionResponse;
unsigned long flags;
- DPRINT_ENTER(VMBUS);
-
versionResponse = (struct vmbus_channel_version_response *)hdr;
spin_lock_irqsave(&gVmbusConnection.channelmsg_lock, flags);
@@ -732,8 +697,6 @@ static void VmbusChannelOnVersionResponse(
}
}
spin_unlock_irqrestore(&gVmbusConnection.channelmsg_lock, flags);
-
- DPRINT_EXIT(VMBUS);
}
/* Channel message dispatch table */
@@ -769,8 +732,6 @@ void VmbusOnChannelMessage(void *Context)
struct vmbus_channel_message_header *hdr;
int size;
- DPRINT_ENTER(VMBUS);
-
hdr = (struct vmbus_channel_message_header *)msg->u.Payload;
size = msg->Header.PayloadSize;
@@ -794,7 +755,6 @@ void VmbusOnChannelMessage(void *Context)
/* Free the msg that was allocated in VmbusOnMsgDPC() */
kfree(msg);
- DPRINT_EXIT(VMBUS);
}
/*
@@ -806,8 +766,6 @@ int VmbusChannelRequestOffers(void)
struct vmbus_channel_msginfo *msgInfo;
int ret;
- DPRINT_ENTER(VMBUS);
-
msgInfo = kmalloc(sizeof(*msgInfo) +
sizeof(struct vmbus_channel_message_header),
GFP_KERNEL);
@@ -853,7 +811,6 @@ Cleanup:
kfree(msgInfo);
}
- DPRINT_EXIT(VMBUS);
return ret;
}
diff --git a/drivers/staging/hv/channel_mgmt.h b/drivers/staging/hv/channel_mgmt.h
index 5908b81d3e9..f969267895b 100644
--- a/drivers/staging/hv/channel_mgmt.h
+++ b/drivers/staging/hv/channel_mgmt.h
@@ -247,8 +247,8 @@ struct vmbus_channel {
/* Allocated memory for ring buffer */
void *RingBufferPages;
u32 RingBufferPageCount;
- RING_BUFFER_INFO Outbound; /* send to parent */
- RING_BUFFER_INFO Inbound; /* receive from parent */
+ struct hv_ring_buffer_info Outbound; /* send to parent */
+ struct hv_ring_buffer_info Inbound; /* receive from parent */
spinlock_t inbound_lock;
struct workqueue_struct *ControlWQ;
@@ -272,8 +272,8 @@ struct vmbus_channel_debug_info {
u32 ClientMonitorLatency;
u32 ClientMonitorConnectionId;
- RING_BUFFER_DEBUG_INFO Inbound;
- RING_BUFFER_DEBUG_INFO Outbound;
+ struct hv_ring_buffer_debug_info Inbound;
+ struct hv_ring_buffer_debug_info Outbound;
};
/*
diff --git a/drivers/staging/hv/connection.c b/drivers/staging/hv/connection.c
index e8824dadffc..1f4d6683aaa 100644
--- a/drivers/staging/hv/connection.c
+++ b/drivers/staging/hv/connection.c
@@ -44,8 +44,6 @@ int VmbusConnect(void)
struct vmbus_channel_initiate_contact *msg;
unsigned long flags;
- DPRINT_ENTER(VMBUS);
-
/* Make sure we are not connecting or connected */
if (gVmbusConnection.ConnectState != Disconnected)
return -1;
@@ -155,8 +153,6 @@ int VmbusConnect(void)
kfree(msgInfo->WaitEvent);
kfree(msgInfo);
- DPRINT_EXIT(VMBUS);
-
return 0;
Cleanup:
@@ -180,8 +176,6 @@ Cleanup:
kfree(msgInfo);
}
- DPRINT_EXIT(VMBUS);
-
return ret;
}
@@ -193,8 +187,6 @@ int VmbusDisconnect(void)
int ret = 0;
struct vmbus_channel_message_header *msg;
- DPRINT_ENTER(VMBUS);
-
/* Make sure we are connected */
if (gVmbusConnection.ConnectState != Connected)
return -1;
@@ -221,7 +213,6 @@ int VmbusDisconnect(void)
Cleanup:
kfree(msg);
- DPRINT_EXIT(VMBUS);
return ret;
}
@@ -285,8 +276,6 @@ void VmbusOnEvents(void)
int relid;
u32 *recvInterruptPage = gVmbusConnection.RecvInterruptPage;
- DPRINT_ENTER(VMBUS);
-
/* Check events */
if (recvInterruptPage) {
for (dword = 0; dword < maxdword; dword++) {
@@ -310,8 +299,6 @@ void VmbusOnEvents(void)
}
}
}
- DPRINT_EXIT(VMBUS);
-
return;
}
@@ -332,18 +319,10 @@ int VmbusPostMessage(void *buffer, size_t bufferLen)
*/
int VmbusSetEvent(u32 childRelId)
{
- int ret = 0;
-
- DPRINT_ENTER(VMBUS);
-
/* Each u32 represents 32 channels */
set_bit(childRelId & 31,
(unsigned long *)gVmbusConnection.SendInterruptPage +
(childRelId >> 5));
- ret = HvSignalEvent();
-
- DPRINT_EXIT(VMBUS);
-
- return ret;
+ return HvSignalEvent();
}
diff --git a/drivers/staging/hv/hv.c b/drivers/staging/hv/hv.c
index 6c77e64027f..86b1ddd9040 100644
--- a/drivers/staging/hv/hv.c
+++ b/drivers/staging/hv/hv.c
@@ -192,8 +192,6 @@ int HvInit(void)
union hv_x64_msr_hypercall_contents hypercallMsr;
void *virtAddr = NULL;
- DPRINT_ENTER(VMBUS);
-
memset(gHvContext.synICEventPage, 0, sizeof(void *) * MAX_NUM_CPUS);
memset(gHvContext.synICMessagePage, 0, sizeof(void *) * MAX_NUM_CPUS);
@@ -275,8 +273,6 @@ int HvInit(void)
gHvContext.SignalEventParam->FlagNumber = 0;
gHvContext.SignalEventParam->RsvdZ = 0;
- DPRINT_EXIT(VMBUS);
-
return ret;
Cleanup:
@@ -289,8 +285,6 @@ Cleanup:
vfree(virtAddr);
}
ret = -1;
- DPRINT_EXIT(VMBUS);
-
return ret;
}
@@ -303,8 +297,6 @@ void HvCleanup(void)
{
union hv_x64_msr_hypercall_contents hypercallMsr;
- DPRINT_ENTER(VMBUS);
-
kfree(gHvContext.SignalEventBuffer);
gHvContext.SignalEventBuffer = NULL;
gHvContext.SignalEventParam = NULL;
@@ -315,8 +307,6 @@ void HvCleanup(void)
vfree(gHvContext.HypercallPage);
gHvContext.HypercallPage = NULL;
}
-
- DPRINT_EXIT(VMBUS);
}
/*
@@ -392,12 +382,8 @@ void HvSynicInit(void *irqarg)
u32 irqVector = *((u32 *)(irqarg));
int cpu = smp_processor_id();
- DPRINT_ENTER(VMBUS);
-
- if (!gHvContext.HypercallPage) {
- DPRINT_EXIT(VMBUS);
+ if (!gHvContext.HypercallPage)
return;
- }
/* Check the version */
rdmsrl(HV_X64_MSR_SVERSION, version);
@@ -464,9 +450,6 @@ void HvSynicInit(void *irqarg)
wrmsrl(HV_X64_MSR_SCONTROL, sctrl.AsUINT64);
gHvContext.SynICInitialized = true;
-
- DPRINT_EXIT(VMBUS);
-
return;
Cleanup:
@@ -475,8 +458,6 @@ Cleanup:
if (gHvContext.synICMessagePage[cpu])
osd_PageFree(gHvContext.synICMessagePage[cpu], 1);
-
- DPRINT_EXIT(VMBUS);
return;
}
@@ -490,12 +471,8 @@ void HvSynicCleanup(void *arg)
union hv_synic_siefp siefp;
int cpu = smp_processor_id();
- DPRINT_ENTER(VMBUS);
-
- if (!gHvContext.SynICInitialized) {
- DPRINT_EXIT(VMBUS);
+ if (!gHvContext.SynICInitialized)
return;
- }
rdmsrl(HV_X64_MSR_SINT0 + VMBUS_MESSAGE_SINT, sharedSint.AsUINT64);
@@ -519,6 +496,4 @@ void HvSynicCleanup(void *arg)
osd_PageFree(gHvContext.synICMessagePage[cpu], 1);
osd_PageFree(gHvContext.synICEventPage[cpu], 1);
-
- DPRINT_EXIT(VMBUS);
}
diff --git a/drivers/staging/hv/hv_timesource.c b/drivers/staging/hv/hv_timesource.c
new file mode 100644
index 00000000000..a7ee533303b
--- /dev/null
+++ b/drivers/staging/hv/hv_timesource.c
@@ -0,0 +1,101 @@
+/*
+ * A clocksource for Linux running on HyperV.
+ *
+ *
+ * Copyright (C) 2010, Novell, Inc.
+ * Author : K. Y. Srinivasan <ksrinivasan@novell.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, 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <linux/version.h>
+#include <linux/clocksource.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/dmi.h>
+#include <asm/hyperv.h>
+#include <asm/mshyperv.h>
+#include <asm/hypervisor.h>
+
+#define HV_CLOCK_SHIFT 22
+
+static cycle_t read_hv_clock(struct clocksource *arg)
+{
+ cycle_t current_tick;
+ /*
+ * Read the partition counter to get the current tick count. This count
+ * is set to 0 when the partition is created and is incremented in
+ * 100 nanosecond units.
+ */
+ rdmsrl(HV_X64_MSR_TIME_REF_COUNT, current_tick);
+ return current_tick;
+}
+
+static struct clocksource hyperv_cs = {
+ .name = "hyperv_clocksource",
+ .rating = 400, /* use this when running on Hyperv*/
+ .read = read_hv_clock,
+ .mask = CLOCKSOURCE_MASK(64),
+ /*
+ * The time ref counter in HyperV is in 100ns units.
+ * The definition of mult is:
+ * mult/2^shift = ns/cyc = 100
+ * mult = (100 << shift)
+ */
+ .mult = (100 << HV_CLOCK_SHIFT),
+ .shift = HV_CLOCK_SHIFT,
+};
+
+static const struct dmi_system_id __initconst
+hv_timesource_dmi_table[] __maybe_unused = {
+ {
+ .ident = "Hyper-V",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Virtual Machine"),
+ DMI_MATCH(DMI_BOARD_NAME, "Virtual Machine"),
+ },
+ },
+ { },
+};
+MODULE_DEVICE_TABLE(dmi, hv_timesource_dmi_table);
+
+static const struct pci_device_id __initconst
+hv_timesource_pci_table[] __maybe_unused = {
+ { PCI_DEVICE(0x1414, 0x5353) }, /* VGA compatible controller */
+ { 0 }
+};
+MODULE_DEVICE_TABLE(pci, hv_timesource_pci_table);
+
+
+static int __init init_hv_clocksource(void)
+{
+ if ((x86_hyper != &x86_hyper_ms_hyperv) ||
+ !(ms_hyperv.features & HV_X64_MSR_TIME_REF_COUNT_AVAILABLE))
+ return -ENODEV;
+
+ if (!dmi_check_system(hv_timesource_dmi_table))
+ return -ENODEV;
+
+ printk(KERN_INFO "Registering HyperV clock source\n");
+ return clocksource_register(&hyperv_cs);
+}
+
+module_init(init_hv_clocksource);
+MODULE_DESCRIPTION("HyperV based clocksource");
+MODULE_AUTHOR("K. Y. Srinivasan <ksrinivasan@novell.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/hv/hv_utils.c b/drivers/staging/hv/hv_utils.c
index 2adc9b48ca9..6eb79febef9 100644
--- a/drivers/staging/hv/hv_utils.c
+++ b/drivers/staging/hv/hv_utils.c
@@ -52,8 +52,6 @@ static void shutdown_onchannelcallback(void *context)
struct icmsg_hdr *icmsghdrp;
struct icmsg_negotiate *negop = NULL;
- DPRINT_ENTER(VMBUS);
-
buflen = PAGE_SIZE;
buf = kmalloc(buflen, GFP_ATOMIC);
@@ -102,8 +100,6 @@ static void shutdown_onchannelcallback(void *context)
kfree(buf);
- DPRINT_EXIT(VMBUS);
-
if (execute_shutdown == true)
orderly_poweroff(false);
}
@@ -160,8 +156,6 @@ static void timesync_onchannelcallback(void *context)
struct icmsg_hdr *icmsghdrp;
struct ictimesync_data *timedatap;
- DPRINT_ENTER(VMBUS);
-
buflen = PAGE_SIZE;
buf = kmalloc(buflen, GFP_ATOMIC);
@@ -192,8 +186,6 @@ static void timesync_onchannelcallback(void *context)
}
kfree(buf);
-
- DPRINT_EXIT(VMBUS);
}
/*
@@ -210,8 +202,6 @@ static void heartbeat_onchannelcallback(void *context)
struct icmsg_hdr *icmsghdrp;
struct heartbeat_msg_data *heartbeat_msg;
- DPRINT_ENTER(VMBUS);
-
buflen = PAGE_SIZE;
buf = kmalloc(buflen, GFP_ATOMIC);
@@ -249,8 +239,6 @@ static void heartbeat_onchannelcallback(void *context)
}
kfree(buf);
-
- DPRINT_EXIT(VMBUS);
}
static const struct pci_device_id __initconst
diff --git a/drivers/staging/hv/logging.h b/drivers/staging/hv/logging.h
index ad4cfcfb7b1..20d4d12023d 100644
--- a/drivers/staging/hv/logging.h
+++ b/drivers/staging/hv/logging.h
@@ -92,21 +92,4 @@ extern unsigned int vmbus_loglevel;
__func__, ## args);\
} while (0)
-#ifdef DEBUG
-#define DPRINT_ENTER(mod) do {\
- if ((mod & (HIWORD(vmbus_loglevel))) && \
- (DEBUG_LVL_ENTEREXIT <= LOWORD(vmbus_loglevel))) \
- printk(KERN_DEBUG "["#mod"]: %s() enter\n", __func__);\
- } while (0)
-
-#define DPRINT_EXIT(mod) do {\
- if ((mod & (HIWORD(vmbus_loglevel))) && \
- (DEBUG_LVL_ENTEREXIT <= LOWORD(vmbus_loglevel))) \
- printk(KERN_DEBUG "["#mod"]: %s() exit\n", __func__);\
- } while (0)
-#else
-#define DPRINT_ENTER(mod)
-#define DPRINT_EXIT(mod)
-#endif
-
#endif /* _LOGGING_H_ */
diff --git a/drivers/staging/hv/netvsc.c b/drivers/staging/hv/netvsc.c
index ba15059c45b..1d2ebbe17e2 100644
--- a/drivers/staging/hv/netvsc.c
+++ b/drivers/staging/hv/netvsc.c
@@ -174,8 +174,6 @@ int NetVscInitialize(struct hv_driver *drv)
{
struct netvsc_driver *driver = (struct netvsc_driver *)drv;
- DPRINT_ENTER(NETVSC);
-
DPRINT_DBG(NETVSC, "sizeof(struct hv_netvsc_packet)=%zd, "
"sizeof(struct nvsp_message)=%zd, "
"sizeof(struct vmtransfer_page_packet_header)=%zd",
@@ -202,9 +200,6 @@ int NetVscInitialize(struct hv_driver *drv)
driver->OnSend = NetVscOnSend;
RndisFilterInit(driver);
-
- DPRINT_EXIT(NETVSC);
-
return 0;
}
@@ -214,13 +209,10 @@ static int NetVscInitializeReceiveBufferWithNetVsp(struct hv_device *Device)
struct netvsc_device *netDevice;
struct nvsp_message *initPacket;
- DPRINT_ENTER(NETVSC);
-
netDevice = GetOutboundNetDevice(Device);
if (!netDevice) {
DPRINT_ERR(NETVSC, "unable to get net device..."
"device being destroyed?");
- DPRINT_EXIT(NETVSC);
return -1;
}
/* ASSERT(netDevice->ReceiveBufferSize > 0); */
@@ -335,7 +327,6 @@ Cleanup:
Exit:
PutNetDevice(Device);
- DPRINT_EXIT(NETVSC);
return ret;
}
@@ -345,13 +336,10 @@ static int NetVscInitializeSendBufferWithNetVsp(struct hv_device *Device)
struct netvsc_device *netDevice;
struct nvsp_message *initPacket;
- DPRINT_ENTER(NETVSC);
-
netDevice = GetOutboundNetDevice(Device);
if (!netDevice) {
DPRINT_ERR(NETVSC, "unable to get net device..."
"device being destroyed?");
- DPRINT_EXIT(NETVSC);
return -1;
}
if (netDevice->SendBufferSize <= 0) {
@@ -434,7 +422,6 @@ Cleanup:
Exit:
PutNetDevice(Device);
- DPRINT_EXIT(NETVSC);
return ret;
}
@@ -443,8 +430,6 @@ static int NetVscDestroyReceiveBuffer(struct netvsc_device *NetDevice)
struct nvsp_message *revokePacket;
int ret = 0;
- DPRINT_ENTER(NETVSC);
-
/*
* If we got a section count, it means we received a
* SendReceiveBufferComplete msg (ie sent
@@ -475,7 +460,6 @@ static int NetVscDestroyReceiveBuffer(struct netvsc_device *NetDevice)
if (ret != 0) {
DPRINT_ERR(NETVSC, "unable to send revoke receive "
"buffer to netvsp");
- DPRINT_EXIT(NETVSC);
return -1;
}
}
@@ -492,7 +476,6 @@ static int NetVscDestroyReceiveBuffer(struct netvsc_device *NetDevice)
if (ret != 0) {
DPRINT_ERR(NETVSC,
"unable to teardown receive buffer's gpadl");
- DPRINT_EXIT(NETVSC);
return -1;
}
NetDevice->ReceiveBufferGpadlHandle = 0;
@@ -513,8 +496,6 @@ static int NetVscDestroyReceiveBuffer(struct netvsc_device *NetDevice)
NetDevice->ReceiveSections = NULL;
}
- DPRINT_EXIT(NETVSC);
-
return ret;
}
@@ -523,8 +504,6 @@ static int NetVscDestroySendBuffer(struct netvsc_device *NetDevice)
struct nvsp_message *revokePacket;
int ret = 0;
- DPRINT_ENTER(NETVSC);
-
/*
* If we got a section count, it means we received a
* SendReceiveBufferComplete msg (ie sent
@@ -554,7 +533,6 @@ static int NetVscDestroySendBuffer(struct netvsc_device *NetDevice)
if (ret != 0) {
DPRINT_ERR(NETVSC, "unable to send revoke send buffer "
"to netvsp");
- DPRINT_EXIT(NETVSC);
return -1;
}
}
@@ -572,7 +550,6 @@ static int NetVscDestroySendBuffer(struct netvsc_device *NetDevice)
if (ret != 0) {
DPRINT_ERR(NETVSC, "unable to teardown send buffer's "
"gpadl");
- DPRINT_EXIT(NETVSC);
return -1;
}
NetDevice->SendBufferGpadlHandle = 0;
@@ -587,8 +564,6 @@ static int NetVscDestroySendBuffer(struct netvsc_device *NetDevice)
NetDevice->SendBuffer = NULL;
}
- DPRINT_EXIT(NETVSC);
-
return ret;
}
@@ -600,13 +575,10 @@ static int NetVscConnectToVsp(struct hv_device *Device)
struct nvsp_message *initPacket;
int ndisVersion;
- DPRINT_ENTER(NETVSC);
-
netDevice = GetOutboundNetDevice(Device);
if (!netDevice) {
DPRINT_ERR(NETVSC, "unable to get net device..."
"device being destroyed?");
- DPRINT_EXIT(NETVSC);
return -1;
}
@@ -696,18 +668,13 @@ static int NetVscConnectToVsp(struct hv_device *Device)
Cleanup:
PutNetDevice(Device);
- DPRINT_EXIT(NETVSC);
return ret;
}
static void NetVscDisconnectFromVsp(struct netvsc_device *NetDevice)
{
- DPRINT_ENTER(NETVSC);
-
NetVscDestroyReceiveBuffer(NetDevice);
NetVscDestroySendBuffer(NetDevice);
-
- DPRINT_EXIT(NETVSC);
}
/*
@@ -722,8 +689,6 @@ static int NetVscOnDeviceAdd(struct hv_device *Device, void *AdditionalInfo)
struct netvsc_driver *netDriver =
(struct netvsc_driver *)Device->Driver;
- DPRINT_ENTER(NETVSC);
-
netDevice = AllocNetDevice(Device);
if (!netDevice) {
ret = -1;
@@ -787,7 +752,6 @@ static int NetVscOnDeviceAdd(struct hv_device *Device, void *AdditionalInfo)
DPRINT_INFO(NETVSC, "*** NetVSC channel handshake result - %d ***",
ret);
- DPRINT_EXIT(NETVSC);
return ret;
Close:
@@ -812,7 +776,6 @@ Cleanup:
FreeNetDevice(netDevice);
}
- DPRINT_EXIT(NETVSC);
return ret;
}
@@ -824,8 +787,6 @@ static int NetVscOnDeviceRemove(struct hv_device *Device)
struct netvsc_device *netDevice;
struct hv_netvsc_packet *netvscPacket, *pos;
- DPRINT_ENTER(NETVSC);
-
DPRINT_INFO(NETVSC, "Disabling outbound traffic on net device (%p)...",
Device->Extension);
@@ -868,8 +829,6 @@ static int NetVscOnDeviceRemove(struct hv_device *Device)
kfree(netDevice->ChannelInitEvent);
FreeNetDevice(netDevice);
-
- DPRINT_EXIT(NETVSC);
return 0;
}
@@ -878,8 +837,6 @@ static int NetVscOnDeviceRemove(struct hv_device *Device)
*/
static void NetVscOnCleanup(struct hv_driver *drv)
{
- DPRINT_ENTER(NETVSC);
- DPRINT_EXIT(NETVSC);
}
static void NetVscOnSendCompletion(struct hv_device *Device,
@@ -889,13 +846,10 @@ static void NetVscOnSendCompletion(struct hv_device *Device,
struct nvsp_message *nvspPacket;
struct hv_netvsc_packet *nvscPacket;
- DPRINT_ENTER(NETVSC);
-
netDevice = GetInboundNetDevice(Device);
if (!netDevice) {
DPRINT_ERR(NETVSC, "unable to get net device..."
"device being destroyed?");
- DPRINT_EXIT(NETVSC);
return;
}
@@ -929,7 +883,6 @@ static void NetVscOnSendCompletion(struct hv_device *Device,
}
PutNetDevice(Device);
- DPRINT_EXIT(NETVSC);
}
static int NetVscOnSend(struct hv_device *Device,
@@ -940,13 +893,10 @@ static int NetVscOnSend(struct hv_device *Device,
struct nvsp_message sendMessage;
- DPRINT_ENTER(NETVSC);
-
netDevice = GetOutboundNetDevice(Device);
if (!netDevice) {
DPRINT_ERR(NETVSC, "net device (%p) shutting down..."
"ignoring outbound packets", netDevice);
- DPRINT_EXIT(NETVSC);
return -2;
}
@@ -986,8 +936,6 @@ static int NetVscOnSend(struct hv_device *Device,
atomic_inc(&netDevice->NumOutstandingSends);
PutNetDevice(Device);
-
- DPRINT_EXIT(NETVSC);
return ret;
}
@@ -1007,13 +955,10 @@ static void NetVscOnReceive(struct hv_device *Device,
unsigned long flags;
LIST_HEAD(listHead);
- DPRINT_ENTER(NETVSC);
-
netDevice = GetInboundNetDevice(Device);
if (!netDevice) {
DPRINT_ERR(NETVSC, "unable to get net device..."
"device being destroyed?");
- DPRINT_EXIT(NETVSC);
return;
}
@@ -1189,7 +1134,6 @@ static void NetVscOnReceive(struct hv_device *Device,
/* ASSERT(list_empty(&listHead)); */
PutNetDevice(Device);
- DPRINT_EXIT(NETVSC);
}
static void NetVscSendReceiveCompletion(struct hv_device *Device,
@@ -1248,8 +1192,6 @@ static void NetVscOnReceiveCompletion(void *Context)
bool fSendReceiveComp = false;
unsigned long flags;
- DPRINT_ENTER(NETVSC);
-
/* ASSERT(packet->XferPagePacket); */
/*
@@ -1261,7 +1203,6 @@ static void NetVscOnReceiveCompletion(void *Context)
if (!netDevice) {
DPRINT_ERR(NETVSC, "unable to get net device..."
"device being destroyed?");
- DPRINT_EXIT(NETVSC);
return;
}
@@ -1292,7 +1233,6 @@ static void NetVscOnReceiveCompletion(void *Context)
NetVscSendReceiveCompletion(device, transactionId);
PutNetDevice(device);
- DPRINT_EXIT(NETVSC);
}
static void NetVscOnChannelCallback(void *Context)
@@ -1307,9 +1247,6 @@ static void NetVscOnChannelCallback(void *Context)
unsigned char *buffer;
int bufferlen = NETVSC_PACKET_SIZE;
-
- DPRINT_ENTER(NETVSC);
-
/* ASSERT(device); */
packet = kzalloc(NETVSC_PACKET_SIZE * sizeof(unsigned char),
@@ -1322,7 +1259,6 @@ static void NetVscOnChannelCallback(void *Context)
if (!netDevice) {
DPRINT_ERR(NETVSC, "net device (%p) shutting down..."
"ignoring inbound packets", netDevice);
- DPRINT_EXIT(NETVSC);
goto out;
}
@@ -1386,7 +1322,6 @@ static void NetVscOnChannelCallback(void *Context)
} while (1);
PutNetDevice(device);
- DPRINT_EXIT(NETVSC);
out:
kfree(buffer);
return;
diff --git a/drivers/staging/hv/netvsc_drv.c b/drivers/staging/hv/netvsc_drv.c
index 55b993298ff..56e11575c97 100644
--- a/drivers/staging/hv/netvsc_drv.c
+++ b/drivers/staging/hv/netvsc_drv.c
@@ -76,8 +76,6 @@ static int netvsc_open(struct net_device *net)
struct hv_device *device_obj = &net_device_ctx->device_ctx->device_obj;
int ret = 0;
- DPRINT_ENTER(NETVSC_DRV);
-
if (netif_carrier_ok(net)) {
/* Open up the device */
ret = RndisFilterOnOpen(device_obj);
@@ -92,7 +90,6 @@ static int netvsc_open(struct net_device *net)
DPRINT_ERR(NETVSC_DRV, "unable to open device...link is down.");
}
- DPRINT_EXIT(NETVSC_DRV);
return ret;
}
@@ -102,16 +99,12 @@ static int netvsc_close(struct net_device *net)
struct hv_device *device_obj = &net_device_ctx->device_ctx->device_obj;
int ret;
- DPRINT_ENTER(NETVSC_DRV);
-
netif_stop_queue(net);
ret = RndisFilterOnClose(device_obj);
if (ret != 0)
DPRINT_ERR(NETVSC_DRV, "unable to close device (ret %d).", ret);
- DPRINT_EXIT(NETVSC_DRV);
-
return ret;
}
@@ -121,8 +114,6 @@ static void netvsc_xmit_completion(void *context)
struct sk_buff *skb = (struct sk_buff *)
(unsigned long)packet->Completion.Send.SendCompletionTid;
- DPRINT_ENTER(NETVSC_DRV);
-
kfree(packet);
if (skb) {
@@ -135,8 +126,6 @@ static void netvsc_xmit_completion(void *context)
if ((net_device_ctx->avail += num_pages) >= PACKET_PAGES_HIWATER)
netif_wake_queue(net);
}
-
- DPRINT_EXIT(NETVSC_DRV);
}
static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net)
@@ -151,8 +140,6 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net)
int ret;
unsigned int i, num_pages;
- DPRINT_ENTER(NETVSC_DRV);
-
DPRINT_DBG(NETVSC_DRV, "xmit packet - len %d data_len %d",
skb->len, skb->data_len);
@@ -225,7 +212,6 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net)
netvsc_xmit_completion(packet);
}
- DPRINT_EXIT(NETVSC_DRV);
return NETDEV_TX_OK;
}
@@ -238,8 +224,6 @@ static void netvsc_linkstatus_callback(struct hv_device *device_obj,
struct vm_device *device_ctx = to_vm_device(device_obj);
struct net_device *net = dev_get_drvdata(&device_ctx->device);
- DPRINT_ENTER(NETVSC_DRV);
-
if (!net) {
DPRINT_ERR(NETVSC_DRV, "got link status but net device "
"not initialized yet");
@@ -253,7 +237,6 @@ static void netvsc_linkstatus_callback(struct hv_device *device_obj,
netif_carrier_off(net);
netif_stop_queue(net);
}
- DPRINT_EXIT(NETVSC_DRV);
}
/*
@@ -270,8 +253,6 @@ static int netvsc_recv_callback(struct hv_device *device_obj,
int i;
unsigned long flags;
- DPRINT_ENTER(NETVSC_DRV);
-
if (!net) {
DPRINT_ERR(NETVSC_DRV, "got receive callback but net device "
"not initialized yet");
@@ -323,8 +304,6 @@ static int netvsc_recv_callback(struct hv_device *device_obj,
DPRINT_DBG(NETVSC_DRV, "# of recvs %lu total size %lu",
net->stats.rx_packets, net->stats.rx_bytes);
- DPRINT_EXIT(NETVSC_DRV);
-
return 0;
}
@@ -364,8 +343,6 @@ static int netvsc_probe(struct device *device)
struct netvsc_device_info device_info;
int ret;
- DPRINT_ENTER(NETVSC_DRV);
-
if (!net_drv_obj->Base.OnDeviceAdd)
return -1;
@@ -422,7 +399,6 @@ static int netvsc_probe(struct device *device)
free_netdev(net);
}
- DPRINT_EXIT(NETVSC_DRV);
return ret;
}
@@ -438,18 +414,13 @@ static int netvsc_remove(struct device *device)
struct hv_device *device_obj = &device_ctx->device_obj;
int ret;
- DPRINT_ENTER(NETVSC_DRV);
-
if (net == NULL) {
DPRINT_INFO(NETVSC, "no net device to remove");
- DPRINT_EXIT(NETVSC_DRV);
return 0;
}
- if (!net_drv_obj->Base.OnDeviceRemove) {
- DPRINT_EXIT(NETVSC_DRV);
+ if (!net_drv_obj->Base.OnDeviceRemove)
return -1;
- }
/* Stop outbound asap */
netif_stop_queue(net);
@@ -468,7 +439,6 @@ static int netvsc_remove(struct device *device)
}
free_netdev(net);
- DPRINT_EXIT(NETVSC_DRV);
return ret;
}
@@ -488,8 +458,6 @@ static void netvsc_drv_exit(void)
struct device *current_dev;
int ret;
- DPRINT_ENTER(NETVSC_DRV);
-
while (1) {
current_dev = NULL;
@@ -515,8 +483,6 @@ static void netvsc_drv_exit(void)
vmbus_child_driver_unregister(drv_ctx);
- DPRINT_EXIT(NETVSC_DRV);
-
return;
}
@@ -526,8 +492,6 @@ static int netvsc_drv_init(int (*drv_init)(struct hv_driver *drv))
struct driver_context *drv_ctx = &g_netvsc_drv.drv_ctx;
int ret;
- DPRINT_ENTER(NETVSC_DRV);
-
vmbus_get_interface(&net_drv_obj->Base.VmbusChannelInterface);
net_drv_obj->RingBufferSize = ring_size * PAGE_SIZE;
@@ -547,8 +511,6 @@ static int netvsc_drv_init(int (*drv_init)(struct hv_driver *drv))
/* The driver belongs to vmbus */
ret = vmbus_child_driver_register(drv_ctx);
- DPRINT_EXIT(NETVSC_DRV);
-
return ret;
}
@@ -568,26 +530,17 @@ MODULE_DEVICE_TABLE(dmi, hv_netvsc_dmi_table);
static int __init netvsc_init(void)
{
- int ret;
-
- DPRINT_ENTER(NETVSC_DRV);
DPRINT_INFO(NETVSC_DRV, "Netvsc initializing....");
if (!dmi_check_system(hv_netvsc_dmi_table))
return -ENODEV;
- ret = netvsc_drv_init(NetVscInitialize);
-
- DPRINT_EXIT(NETVSC_DRV);
-
- return ret;
+ return netvsc_drv_init(NetVscInitialize);
}
static void __exit netvsc_exit(void)
{
- DPRINT_ENTER(NETVSC_DRV);
netvsc_drv_exit();
- DPRINT_EXIT(NETVSC_DRV);
}
static const struct pci_device_id __initconst
diff --git a/drivers/staging/hv/ring_buffer.c b/drivers/staging/hv/ring_buffer.c
index ae2a10e24d9..17bc7626f70 100644
--- a/drivers/staging/hv/ring_buffer.c
+++ b/drivers/staging/hv/ring_buffer.c
@@ -46,7 +46,7 @@ Description:
--*/
static inline void
-GetRingBufferAvailBytes(RING_BUFFER_INFO *rbi, u32 *read, u32 *write)
+GetRingBufferAvailBytes(struct hv_ring_buffer_info *rbi, u32 *read, u32 *write)
{
u32 read_loc, write_loc;
@@ -68,7 +68,7 @@ Description:
--*/
static inline u32
-GetNextWriteLocation(RING_BUFFER_INFO *RingInfo)
+GetNextWriteLocation(struct hv_ring_buffer_info *RingInfo)
{
u32 next = RingInfo->RingBuffer->WriteIndex;
@@ -87,7 +87,8 @@ Description:
--*/
static inline void
-SetNextWriteLocation(RING_BUFFER_INFO *RingInfo, u32 NextWriteLocation)
+SetNextWriteLocation(struct hv_ring_buffer_info *RingInfo,
+ u32 NextWriteLocation)
{
RingInfo->RingBuffer->WriteIndex = NextWriteLocation;
}
@@ -102,7 +103,7 @@ Description:
--*/
static inline u32
-GetNextReadLocation(RING_BUFFER_INFO *RingInfo)
+GetNextReadLocation(struct hv_ring_buffer_info *RingInfo)
{
u32 next = RingInfo->RingBuffer->ReadIndex;
@@ -122,7 +123,7 @@ Description:
--*/
static inline u32
-GetNextReadLocationWithOffset(RING_BUFFER_INFO *RingInfo, u32 Offset)
+GetNextReadLocationWithOffset(struct hv_ring_buffer_info *RingInfo, u32 Offset)
{
u32 next = RingInfo->RingBuffer->ReadIndex;
@@ -143,7 +144,7 @@ Description:
--*/
static inline void
-SetNextReadLocation(RING_BUFFER_INFO *RingInfo, u32 NextReadLocation)
+SetNextReadLocation(struct hv_ring_buffer_info *RingInfo, u32 NextReadLocation)
{
RingInfo->RingBuffer->ReadIndex = NextReadLocation;
}
@@ -159,7 +160,7 @@ Description:
--*/
static inline void *
-GetRingBuffer(RING_BUFFER_INFO *RingInfo)
+GetRingBuffer(struct hv_ring_buffer_info *RingInfo)
{
return (void *)RingInfo->RingBuffer->Buffer;
}
@@ -175,7 +176,7 @@ Description:
--*/
static inline u32
-GetRingBufferSize(RING_BUFFER_INFO *RingInfo)
+GetRingBufferSize(struct hv_ring_buffer_info *RingInfo)
{
return RingInfo->RingDataSize;
}
@@ -190,7 +191,7 @@ Description:
--*/
static inline u64
-GetRingBufferIndices(RING_BUFFER_INFO *RingInfo)
+GetRingBufferIndices(struct hv_ring_buffer_info *RingInfo)
{
return ((u64)RingInfo->RingBuffer->WriteIndex << 32)
|| RingInfo->RingBuffer->ReadIndex;
@@ -206,7 +207,7 @@ Description:
Dump out to console the ring buffer info
--*/
-void DumpRingInfo(RING_BUFFER_INFO *RingInfo, char *Prefix)
+void DumpRingInfo(struct hv_ring_buffer_info *RingInfo, char *Prefix)
{
u32 bytesAvailToWrite;
u32 bytesAvailToRead;
@@ -233,14 +234,14 @@ void DumpRingInfo(RING_BUFFER_INFO *RingInfo, char *Prefix)
static u32
CopyToRingBuffer(
- RING_BUFFER_INFO *RingInfo,
+ struct hv_ring_buffer_info *RingInfo,
u32 StartWriteOffset,
void *Src,
u32 SrcLen);
static u32
CopyFromRingBuffer(
- RING_BUFFER_INFO *RingInfo,
+ struct hv_ring_buffer_info *RingInfo,
void *Dest,
u32 DestLen,
u32 StartReadOffset);
@@ -256,8 +257,8 @@ Description:
Get various debug metrics for the specified ring buffer
--*/
-void RingBufferGetDebugInfo(RING_BUFFER_INFO *RingInfo,
- RING_BUFFER_DEBUG_INFO *DebugInfo)
+void RingBufferGetDebugInfo(struct hv_ring_buffer_info *RingInfo,
+ struct hv_ring_buffer_debug_info *debug_info)
{
u32 bytesAvailToWrite;
u32 bytesAvailToRead;
@@ -267,11 +268,11 @@ void RingBufferGetDebugInfo(RING_BUFFER_INFO *RingInfo,
&bytesAvailToRead,
&bytesAvailToWrite);
- DebugInfo->BytesAvailToRead = bytesAvailToRead;
- DebugInfo->BytesAvailToWrite = bytesAvailToWrite;
- DebugInfo->CurrentReadIndex = RingInfo->RingBuffer->ReadIndex;
- DebugInfo->CurrentWriteIndex = RingInfo->RingBuffer->WriteIndex;
- DebugInfo->CurrentInterruptMask = RingInfo->RingBuffer->InterruptMask;
+ debug_info->BytesAvailToRead = bytesAvailToRead;
+ debug_info->BytesAvailToWrite = bytesAvailToWrite;
+ debug_info->CurrentReadIndex = RingInfo->RingBuffer->ReadIndex;
+ debug_info->CurrentWriteIndex = RingInfo->RingBuffer->WriteIndex;
+ debug_info->CurrentInterruptMask = RingInfo->RingBuffer->InterruptMask;
}
}
@@ -285,7 +286,7 @@ Description:
Get the interrupt mask for the specified ring buffer
--*/
-u32 GetRingBufferInterruptMask(RING_BUFFER_INFO *rbi)
+u32 GetRingBufferInterruptMask(struct hv_ring_buffer_info *rbi)
{
return rbi->RingBuffer->InterruptMask;
}
@@ -299,18 +300,18 @@ Description:
Initialize the ring buffer
--*/
-int RingBufferInit(RING_BUFFER_INFO *RingInfo, void *Buffer, u32 BufferLen)
+int RingBufferInit(struct hv_ring_buffer_info *RingInfo, void *Buffer, u32 BufferLen)
{
- if (sizeof(RING_BUFFER) != PAGE_SIZE)
+ if (sizeof(struct hv_ring_buffer) != PAGE_SIZE)
return -EINVAL;
- memset(RingInfo, 0, sizeof(RING_BUFFER_INFO));
+ memset(RingInfo, 0, sizeof(struct hv_ring_buffer_info));
- RingInfo->RingBuffer = (RING_BUFFER *)Buffer;
+ RingInfo->RingBuffer = (struct hv_ring_buffer *)Buffer;
RingInfo->RingBuffer->ReadIndex = RingInfo->RingBuffer->WriteIndex = 0;
RingInfo->RingSize = BufferLen;
- RingInfo->RingDataSize = BufferLen - sizeof(RING_BUFFER);
+ RingInfo->RingDataSize = BufferLen - sizeof(struct hv_ring_buffer);
spin_lock_init(&RingInfo->ring_lock);
@@ -326,7 +327,7 @@ Description:
Cleanup the ring buffer
--*/
-void RingBufferCleanup(RING_BUFFER_INFO *RingInfo)
+void RingBufferCleanup(struct hv_ring_buffer_info *RingInfo)
{
}
@@ -339,7 +340,7 @@ Description:
Write to the ring buffer
--*/
-int RingBufferWrite(RING_BUFFER_INFO *OutRingInfo,
+int RingBufferWrite(struct hv_ring_buffer_info *OutRingInfo,
struct scatterlist *sglist, u32 sgcount)
{
int i = 0;
@@ -352,8 +353,6 @@ int RingBufferWrite(RING_BUFFER_INFO *OutRingInfo,
u64 prevIndices = 0;
unsigned long flags;
- DPRINT_ENTER(VMBUS);
-
for_each_sg(sglist, sg, sgcount, i)
{
totalBytesToWrite += sg->length;
@@ -382,9 +381,6 @@ int RingBufferWrite(RING_BUFFER_INFO *OutRingInfo,
byteAvailToWrite);
spin_unlock_irqrestore(&OutRingInfo->ring_lock, flags);
-
- DPRINT_EXIT(VMBUS);
-
return -1;
}
@@ -416,9 +412,6 @@ int RingBufferWrite(RING_BUFFER_INFO *OutRingInfo,
/* DumpRingInfo(OutRingInfo, "AFTER "); */
spin_unlock_irqrestore(&OutRingInfo->ring_lock, flags);
-
- DPRINT_EXIT(VMBUS);
-
return 0;
}
@@ -432,7 +425,7 @@ Description:
Read without advancing the read index
--*/
-int RingBufferPeek(RING_BUFFER_INFO *InRingInfo, void *Buffer, u32 BufferLen)
+int RingBufferPeek(struct hv_ring_buffer_info *InRingInfo, void *Buffer, u32 BufferLen)
{
u32 bytesAvailToWrite;
u32 bytesAvailToRead;
@@ -481,7 +474,7 @@ Description:
Read and advance the read index
--*/
-int RingBufferRead(RING_BUFFER_INFO *InRingInfo, void *Buffer,
+int RingBufferRead(struct hv_ring_buffer_info *InRingInfo, void *Buffer,
u32 BufferLen, u32 Offset)
{
u32 bytesAvailToWrite;
@@ -556,7 +549,7 @@ Description:
--*/
static u32
CopyToRingBuffer(
- RING_BUFFER_INFO *RingInfo,
+ struct hv_ring_buffer_info *RingInfo,
u32 StartWriteOffset,
void *Src,
u32 SrcLen)
@@ -594,7 +587,7 @@ Description:
--*/
static u32
CopyFromRingBuffer(
- RING_BUFFER_INFO *RingInfo,
+ struct hv_ring_buffer_info *RingInfo,
void *Dest,
u32 DestLen,
u32 StartReadOffset)
diff --git a/drivers/staging/hv/ring_buffer.h b/drivers/staging/hv/ring_buffer.h
index 6202157e145..a7f1717c6a5 100644
--- a/drivers/staging/hv/ring_buffer.h
+++ b/drivers/staging/hv/ring_buffer.h
@@ -27,7 +27,7 @@
#include <linux/scatterlist.h>
-typedef struct _RING_BUFFER {
+struct hv_ring_buffer {
/* Offset in bytes from the start of ring data below */
volatile u32 WriteIndex;
@@ -51,51 +51,52 @@ typedef struct _RING_BUFFER {
* !!! DO NOT place any fields below this !!!
*/
u8 Buffer[0];
-} __attribute__((packed)) RING_BUFFER;
+} __attribute__((packed));
-typedef struct _RING_BUFFER_INFO {
- RING_BUFFER *RingBuffer;
+struct hv_ring_buffer_info {
+ struct hv_ring_buffer *RingBuffer;
u32 RingSize; /* Include the shared header */
spinlock_t ring_lock;
u32 RingDataSize; /* < ringSize */
u32 RingDataStartOffset;
+};
-} RING_BUFFER_INFO;
-
-typedef struct _RING_BUFFER_DEBUG_INFO {
+struct hv_ring_buffer_debug_info {
u32 CurrentInterruptMask;
u32 CurrentReadIndex;
u32 CurrentWriteIndex;
u32 BytesAvailToRead;
u32 BytesAvailToWrite;
-} RING_BUFFER_DEBUG_INFO;
+};
/* Interface */
-int RingBufferInit(RING_BUFFER_INFO *RingInfo, void *Buffer, u32 BufferLen);
+int RingBufferInit(struct hv_ring_buffer_info *RingInfo, void *Buffer,
+ u32 BufferLen);
-void RingBufferCleanup(RING_BUFFER_INFO *RingInfo);
+void RingBufferCleanup(struct hv_ring_buffer_info *RingInfo);
-int RingBufferWrite(RING_BUFFER_INFO *RingInfo,
+int RingBufferWrite(struct hv_ring_buffer_info *RingInfo,
struct scatterlist *sglist,
u32 sgcount);
-int RingBufferPeek(RING_BUFFER_INFO *RingInfo, void *Buffer, u32 BufferLen);
+int RingBufferPeek(struct hv_ring_buffer_info *RingInfo, void *Buffer,
+ u32 BufferLen);
-int RingBufferRead(RING_BUFFER_INFO *RingInfo,
+int RingBufferRead(struct hv_ring_buffer_info *RingInfo,
void *Buffer,
u32 BufferLen,
u32 Offset);
-u32 GetRingBufferInterruptMask(RING_BUFFER_INFO *RingInfo);
+u32 GetRingBufferInterruptMask(struct hv_ring_buffer_info *RingInfo);
-void DumpRingInfo(RING_BUFFER_INFO *RingInfo, char *Prefix);
+void DumpRingInfo(struct hv_ring_buffer_info *RingInfo, char *Prefix);
-void RingBufferGetDebugInfo(RING_BUFFER_INFO *RingInfo,
- RING_BUFFER_DEBUG_INFO *DebugInfo);
+void RingBufferGetDebugInfo(struct hv_ring_buffer_info *RingInfo,
+ struct hv_ring_buffer_debug_info *debug_info);
#endif /* _RING_BUFFER_H_ */
diff --git a/drivers/staging/hv/rndis_filter.c b/drivers/staging/hv/rndis_filter.c
index 5edf0853c6a..fa2141f454f 100644
--- a/drivers/staging/hv/rndis_filter.c
+++ b/drivers/staging/hv/rndis_filter.c
@@ -244,8 +244,6 @@ static int RndisFilterSendRequest(struct rndis_device *Device,
int ret;
struct hv_netvsc_packet *packet;
- DPRINT_ENTER(NETVSC);
-
/* Setup the packet to send it */
packet = &Request->Packet;
@@ -265,7 +263,6 @@ static int RndisFilterSendRequest(struct rndis_device *Device,
packet->Completion.Send.SendCompletionTid = (unsigned long)Device;
ret = gRndisFilter.InnerDriver.OnSend(Device->NetDevice->Device, packet);
- DPRINT_EXIT(NETVSC);
return ret;
}
@@ -276,8 +273,6 @@ static void RndisFilterReceiveResponse(struct rndis_device *Device,
bool found = false;
unsigned long flags;
- DPRINT_ENTER(NETVSC);
-
spin_lock_irqsave(&Device->request_lock, flags);
list_for_each_entry(request, &Device->RequestList, ListEntry) {
/*
@@ -325,8 +320,6 @@ static void RndisFilterReceiveResponse(struct rndis_device *Device,
Response->Message.InitializeComplete.RequestId,
Response->NdisMessageType);
}
-
- DPRINT_EXIT(NETVSC);
}
static void RndisFilterReceiveIndicateStatus(struct rndis_device *Device,
@@ -353,8 +346,6 @@ static void RndisFilterReceiveData(struct rndis_device *Device,
struct rndis_packet *rndisPacket;
u32 dataOffset;
- DPRINT_ENTER(NETVSC);
-
/* empty ethernet frame ?? */
/* ASSERT(Packet->PageBuffers[0].Length > */
/* RNDIS_MESSAGE_SIZE(struct rndis_packet)); */
@@ -377,8 +368,6 @@ static void RndisFilterReceiveData(struct rndis_device *Device,
gRndisFilter.InnerDriver.OnReceiveCallback(Device->NetDevice->Device,
Packet);
-
- DPRINT_EXIT(NETVSC);
}
static int RndisFilterOnReceive(struct hv_device *Device,
@@ -389,8 +378,6 @@ static int RndisFilterOnReceive(struct hv_device *Device,
struct rndis_message rndisMessage;
struct rndis_message *rndisHeader;
- DPRINT_ENTER(NETVSC);
-
if (!netDevice)
return -EINVAL;
@@ -398,7 +385,6 @@ static int RndisFilterOnReceive(struct hv_device *Device,
if (!netDevice->Extension) {
DPRINT_ERR(NETVSC, "got rndis message but no rndis device..."
"dropping this message!");
- DPRINT_EXIT(NETVSC);
return -1;
}
@@ -406,7 +392,6 @@ static int RndisFilterOnReceive(struct hv_device *Device,
if (rndisDevice->State == RNDIS_DEV_UNINITIALIZED) {
DPRINT_ERR(NETVSC, "got rndis message but rndis device "
"uninitialized...dropping this message!");
- DPRINT_EXIT(NETVSC);
return -1;
}
@@ -431,7 +416,6 @@ static int RndisFilterOnReceive(struct hv_device *Device,
"bytes got %u)...dropping this message!",
rndisHeader->MessageLength,
Packet->TotalDataBufferLength);
- DPRINT_EXIT(NETVSC);
return -1;
}
#endif
@@ -479,7 +463,6 @@ static int RndisFilterOnReceive(struct hv_device *Device,
break;
}
- DPRINT_EXIT(NETVSC);
return 0;
}
@@ -492,8 +475,6 @@ static int RndisFilterQueryDevice(struct rndis_device *Device, u32 Oid,
struct rndis_query_complete *queryComplete;
int ret = 0;
- DPRINT_ENTER(NETVSC);
-
if (!Result)
return -EINVAL;
@@ -536,7 +517,6 @@ static int RndisFilterQueryDevice(struct rndis_device *Device, u32 Oid,
Cleanup:
if (request)
PutRndisRequest(Device, request);
- DPRINT_EXIT(NETVSC);
return ret;
}
@@ -568,8 +548,6 @@ static int RndisFilterSetPacketFilter(struct rndis_device *Device,
u32 status;
int ret;
- DPRINT_ENTER(NETVSC);
-
/* ASSERT(RNDIS_MESSAGE_SIZE(struct rndis_set_request) + sizeof(u32) <= */
/* sizeof(struct rndis_message)); */
@@ -614,15 +592,11 @@ Cleanup:
if (request)
PutRndisRequest(Device, request);
Exit:
- DPRINT_EXIT(NETVSC);
-
return ret;
}
int RndisFilterInit(struct netvsc_driver *Driver)
{
- DPRINT_ENTER(NETVSC);
-
DPRINT_DBG(NETVSC, "sizeof(struct rndis_filter_packet) == %zd",
sizeof(struct rndis_filter_packet));
@@ -658,8 +632,6 @@ int RndisFilterInit(struct netvsc_driver *Driver)
/* Driver->QueryLinkStatus = RndisFilterQueryDeviceLinkStatus; */
Driver->OnReceiveCallback = RndisFilterOnReceive;
- DPRINT_EXIT(NETVSC);
-
return 0;
}
@@ -671,8 +643,6 @@ static int RndisFilterInitDevice(struct rndis_device *Device)
u32 status;
int ret;
- DPRINT_ENTER(NETVSC);
-
request = GetRndisRequest(Device, REMOTE_NDIS_INITIALIZE_MSG,
RNDIS_MESSAGE_SIZE(struct rndis_initialize_request));
if (!request) {
@@ -710,7 +680,6 @@ static int RndisFilterInitDevice(struct rndis_device *Device)
Cleanup:
if (request)
PutRndisRequest(Device, request);
- DPRINT_EXIT(NETVSC);
return ret;
}
@@ -720,8 +689,6 @@ static void RndisFilterHaltDevice(struct rndis_device *Device)
struct rndis_request *request;
struct rndis_halt_request *halt;
- DPRINT_ENTER(NETVSC);
-
/* Attempt to do a rndis device halt */
request = GetRndisRequest(Device, REMOTE_NDIS_HALT_MSG,
RNDIS_MESSAGE_SIZE(struct rndis_halt_request));
@@ -740,7 +707,6 @@ static void RndisFilterHaltDevice(struct rndis_device *Device)
Cleanup:
if (request)
PutRndisRequest(Device, request);
- DPRINT_EXIT(NETVSC);
return;
}
@@ -748,8 +714,6 @@ static int RndisFilterOpenDevice(struct rndis_device *Device)
{
int ret;
- DPRINT_ENTER(NETVSC);
-
if (Device->State != RNDIS_DEV_INITIALIZED)
return 0;
@@ -760,7 +724,6 @@ static int RndisFilterOpenDevice(struct rndis_device *Device)
if (ret == 0)
Device->State = RNDIS_DEV_DATAINITIALIZED;
- DPRINT_EXIT(NETVSC);
return ret;
}
@@ -768,8 +731,6 @@ static int RndisFilterCloseDevice(struct rndis_device *Device)
{
int ret;
- DPRINT_ENTER(NETVSC);
-
if (Device->State != RNDIS_DEV_DATAINITIALIZED)
return 0;
@@ -777,8 +738,6 @@ static int RndisFilterCloseDevice(struct rndis_device *Device)
if (ret == 0)
Device->State = RNDIS_DEV_INITIALIZED;
- DPRINT_EXIT(NETVSC);
-
return ret;
}
@@ -790,13 +749,9 @@ static int RndisFilterOnDeviceAdd(struct hv_device *Device,
struct rndis_device *rndisDevice;
struct netvsc_device_info *deviceInfo = AdditionalInfo;
- DPRINT_ENTER(NETVSC);
-
rndisDevice = GetRndisDevice();
- if (!rndisDevice) {
- DPRINT_EXIT(NETVSC);
+ if (!rndisDevice)
return -1;
- }
DPRINT_DBG(NETVSC, "rndis device object allocated - %p", rndisDevice);
@@ -808,7 +763,6 @@ static int RndisFilterOnDeviceAdd(struct hv_device *Device,
ret = gRndisFilter.InnerDriver.Base.OnDeviceAdd(Device, AdditionalInfo);
if (ret != 0) {
kfree(rndisDevice);
- DPRINT_EXIT(NETVSC);
return ret;
}
@@ -849,8 +803,6 @@ static int RndisFilterOnDeviceAdd(struct hv_device *Device,
DPRINT_INFO(NETVSC, "Device 0x%p link state %s", rndisDevice,
((deviceInfo->LinkState) ? ("down") : ("up")));
- DPRINT_EXIT(NETVSC);
-
return ret;
}
@@ -859,8 +811,6 @@ static int RndisFilterOnDeviceRemove(struct hv_device *Device)
struct netvsc_device *netDevice = Device->Extension;
struct rndis_device *rndisDevice = netDevice->Extension;
- DPRINT_ENTER(NETVSC);
-
/* Halt and release the rndis device */
RndisFilterHaltDevice(rndisDevice);
@@ -870,50 +820,31 @@ static int RndisFilterOnDeviceRemove(struct hv_device *Device)
/* Pass control to inner driver to remove the device */
gRndisFilter.InnerDriver.Base.OnDeviceRemove(Device);
- DPRINT_EXIT(NETVSC);
-
return 0;
}
static void RndisFilterOnCleanup(struct hv_driver *Driver)
{
- DPRINT_ENTER(NETVSC);
-
- DPRINT_EXIT(NETVSC);
}
int RndisFilterOnOpen(struct hv_device *Device)
{
- int ret;
struct netvsc_device *netDevice = Device->Extension;
- DPRINT_ENTER(NETVSC);
-
if (!netDevice)
return -EINVAL;
- ret = RndisFilterOpenDevice(netDevice->Extension);
-
- DPRINT_EXIT(NETVSC);
-
- return ret;
+ return RndisFilterOpenDevice(netDevice->Extension);
}
int RndisFilterOnClose(struct hv_device *Device)
{
- int ret;
struct netvsc_device *netDevice = Device->Extension;
- DPRINT_ENTER(NETVSC);
-
if (!netDevice)
return -EINVAL;
- ret = RndisFilterCloseDevice(netDevice->Extension);
-
- DPRINT_EXIT(NETVSC);
-
- return ret;
+ return RndisFilterCloseDevice(netDevice->Extension);
}
static int RndisFilterOnSend(struct hv_device *Device,
@@ -925,8 +856,6 @@ static int RndisFilterOnSend(struct hv_device *Device,
struct rndis_packet *rndisPacket;
u32 rndisMessageSize;
- DPRINT_ENTER(NETVSC);
-
/* Add the rndis header */
filterPacket = (struct rndis_filter_packet *)Packet->Extension;
/* ASSERT(filterPacket); */
@@ -971,8 +900,6 @@ static int RndisFilterOnSend(struct hv_device *Device,
filterPacket->CompletionContext;
}
- DPRINT_EXIT(NETVSC);
-
return ret;
}
@@ -980,19 +907,12 @@ static void RndisFilterOnSendCompletion(void *Context)
{
struct rndis_filter_packet *filterPacket = Context;
- DPRINT_ENTER(NETVSC);
-
/* Pass it back to the original handler */
filterPacket->OnCompletion(filterPacket->CompletionContext);
-
- DPRINT_EXIT(NETVSC);
}
static void RndisFilterOnSendRequestCompletion(void *Context)
{
- DPRINT_ENTER(NETVSC);
-
/* Noop */
- DPRINT_EXIT(NETVSC);
}
diff --git a/drivers/staging/hv/storvsc.c b/drivers/staging/hv/storvsc.c
index 27a276e08ee..6bd2ff138d2 100644
--- a/drivers/staging/hv/storvsc.c
+++ b/drivers/staging/hv/storvsc.c
@@ -186,7 +186,6 @@ static int StorVscChannelInit(struct hv_device *Device)
if (!storDevice) {
DPRINT_ERR(STORVSC, "unable to get stor device..."
"device being destroyed?");
- DPRINT_EXIT(STORVSC);
return -1;
}
@@ -344,8 +343,6 @@ Cleanup:
request->WaitEvent = NULL;
nomem:
PutStorDevice(Device);
-
- DPRINT_EXIT(STORVSC);
return ret;
}
@@ -356,13 +353,10 @@ static void StorVscOnIOCompletion(struct hv_device *Device,
struct hv_storvsc_request *request;
struct storvsc_device *storDevice;
- DPRINT_ENTER(STORVSC);
-
storDevice = MustGetStorDevice(Device);
if (!storDevice) {
DPRINT_ERR(STORVSC, "unable to get stor device..."
"device being destroyed?");
- DPRINT_EXIT(STORVSC);
return;
}
@@ -414,8 +408,6 @@ static void StorVscOnIOCompletion(struct hv_device *Device,
atomic_dec(&storDevice->NumOutstandingRequests);
PutStorDevice(Device);
-
- DPRINT_EXIT(STORVSC);
}
static void StorVscOnReceive(struct hv_device *Device,
@@ -449,15 +441,12 @@ static void StorVscOnChannelCallback(void *context)
struct storvsc_request_extension *request;
int ret;
- DPRINT_ENTER(STORVSC);
-
/* ASSERT(device); */
storDevice = MustGetStorDevice(device);
if (!storDevice) {
DPRINT_ERR(STORVSC, "unable to get stor device..."
"device being destroyed?");
- DPRINT_EXIT(STORVSC);
return;
}
@@ -501,8 +490,6 @@ static void StorVscOnChannelCallback(void *context)
} while (1);
PutStorDevice(device);
-
- DPRINT_EXIT(STORVSC);
return;
}
@@ -547,8 +534,6 @@ static int StorVscOnDeviceAdd(struct hv_device *Device, void *AdditionalInfo)
struct storvsc_device_info *deviceInfo;
int ret = 0;
- DPRINT_ENTER(STORVSC);
-
deviceInfo = (struct storvsc_device_info *)AdditionalInfo;
storDevice = AllocStorDevice(Device);
if (!storDevice) {
@@ -584,8 +569,6 @@ static int StorVscOnDeviceAdd(struct hv_device *Device, void *AdditionalInfo)
storDevice->TargetId);
Cleanup:
- DPRINT_EXIT(STORVSC);
-
return ret;
}
@@ -596,8 +579,6 @@ static int StorVscOnDeviceRemove(struct hv_device *Device)
{
struct storvsc_device *storDevice;
- DPRINT_ENTER(STORVSC);
-
DPRINT_INFO(STORVSC, "disabling storage device (%p)...",
Device->Extension);
@@ -625,8 +606,6 @@ static int StorVscOnDeviceRemove(struct hv_device *Device)
Device->Driver->VmbusChannelInterface.Close(Device);
FreeStorDevice(storDevice);
-
- DPRINT_EXIT(STORVSC);
return 0;
}
@@ -637,15 +616,12 @@ int StorVscOnHostReset(struct hv_device *Device)
struct vstor_packet *vstorPacket;
int ret;
- DPRINT_ENTER(STORVSC);
-
DPRINT_INFO(STORVSC, "resetting host adapter...");
storDevice = GetStorDevice(Device);
if (!storDevice) {
DPRINT_ERR(STORVSC, "unable to get stor device..."
"device being destroyed?");
- DPRINT_EXIT(STORVSC);
return -1;
}
@@ -687,7 +663,6 @@ int StorVscOnHostReset(struct hv_device *Device)
Cleanup:
PutStorDevice(Device);
- DPRINT_EXIT(STORVSC);
return ret;
}
@@ -702,8 +677,6 @@ static int StorVscOnIORequest(struct hv_device *Device,
struct vstor_packet *vstorPacket;
int ret = 0;
- DPRINT_ENTER(STORVSC);
-
requestExtension =
(struct storvsc_request_extension *)Request->Extension;
vstorPacket = &requestExtension->VStorPacket;
@@ -720,7 +693,6 @@ static int StorVscOnIORequest(struct hv_device *Device,
if (!storDevice) {
DPRINT_ERR(STORVSC, "unable to get stor device..."
"device being destroyed?");
- DPRINT_EXIT(STORVSC);
return -2;
}
@@ -786,8 +758,6 @@ static int StorVscOnIORequest(struct hv_device *Device,
atomic_inc(&storDevice->NumOutstandingRequests);
PutStorDevice(Device);
-
- DPRINT_EXIT(STORVSC);
return ret;
}
@@ -796,8 +766,6 @@ static int StorVscOnIORequest(struct hv_device *Device,
*/
static void StorVscOnCleanup(struct hv_driver *Driver)
{
- DPRINT_ENTER(STORVSC);
- DPRINT_EXIT(STORVSC);
}
/*
@@ -807,8 +775,6 @@ int StorVscInitialize(struct hv_driver *Driver)
{
struct storvsc_driver_object *storDriver;
- DPRINT_ENTER(STORVSC);
-
storDriver = (struct storvsc_driver_object *)Driver;
DPRINT_DBG(STORVSC, "sizeof(STORVSC_REQUEST)=%zd "
@@ -852,7 +818,5 @@ int StorVscInitialize(struct hv_driver *Driver)
storDriver->OnIORequest = StorVscOnIORequest;
- DPRINT_EXIT(STORVSC);
-
return 0;
}
diff --git a/drivers/staging/hv/storvsc_drv.c b/drivers/staging/hv/storvsc_drv.c
index d22e35f598b..075b61bd492 100644
--- a/drivers/staging/hv/storvsc_drv.c
+++ b/drivers/staging/hv/storvsc_drv.c
@@ -141,8 +141,6 @@ static int storvsc_drv_init(int (*drv_init)(struct hv_driver *drv))
struct storvsc_driver_object *storvsc_drv_obj = &g_storvsc_drv.drv_obj;
struct driver_context *drv_ctx = &g_storvsc_drv.drv_ctx;
- DPRINT_ENTER(STORVSC_DRV);
-
vmbus_get_interface(&storvsc_drv_obj->Base.VmbusChannelInterface);
storvsc_drv_obj->RingBufferSize = storvsc_ringbuffer_size;
@@ -175,8 +173,6 @@ static int storvsc_drv_init(int (*drv_init)(struct hv_driver *drv))
/* The driver belongs to vmbus */
ret = vmbus_child_driver_register(drv_ctx);
- DPRINT_EXIT(STORVSC_DRV);
-
return ret;
}
@@ -194,8 +190,6 @@ static void storvsc_drv_exit(void)
struct device *current_dev = NULL;
int ret;
- DPRINT_ENTER(STORVSC_DRV);
-
while (1) {
current_dev = NULL;
@@ -219,9 +213,6 @@ static void storvsc_drv_exit(void)
storvsc_drv_obj->Base.OnCleanup(&storvsc_drv_obj->Base);
vmbus_child_driver_unregister(drv_ctx);
-
- DPRINT_EXIT(STORVSC_DRV);
-
return;
}
@@ -243,8 +234,6 @@ static int storvsc_probe(struct device *device)
struct host_device_context *host_device_ctx;
struct storvsc_device_info device_info;
- DPRINT_ENTER(STORVSC_DRV);
-
if (!storvsc_drv_obj->Base.OnDeviceAdd)
return -1;
@@ -271,8 +260,6 @@ static int storvsc_probe(struct device *device)
if (!host_device_ctx->request_pool) {
scsi_host_put(host);
- DPRINT_EXIT(STORVSC_DRV);
-
return -ENOMEM;
}
@@ -284,8 +271,6 @@ static int storvsc_probe(struct device *device)
DPRINT_ERR(STORVSC_DRV, "unable to add scsi vsc device");
kmem_cache_destroy(host_device_ctx->request_pool);
scsi_host_put(host);
- DPRINT_EXIT(STORVSC_DRV);
-
return -1;
}
@@ -309,15 +294,10 @@ static int storvsc_probe(struct device *device)
kmem_cache_destroy(host_device_ctx->request_pool);
scsi_host_put(host);
- DPRINT_EXIT(STORVSC_DRV);
-
return -1;
}
scsi_scan_host(host);
-
- DPRINT_EXIT(STORVSC_DRV);
-
return ret;
}
@@ -340,12 +320,8 @@ static int storvsc_remove(struct device *device)
(struct host_device_context *)host->hostdata;
- DPRINT_ENTER(STORVSC_DRV);
-
- if (!storvsc_drv_obj->Base.OnDeviceRemove) {
- DPRINT_EXIT(STORVSC_DRV);
+ if (!storvsc_drv_obj->Base.OnDeviceRemove)
return -1;
- }
/*
* Call to the vsc driver to let it know that the device is being
@@ -368,9 +344,6 @@ static int storvsc_remove(struct device *device)
DPRINT_INFO(STORVSC, "releasing host adapter (%p)...", host);
scsi_host_put(host);
-
- DPRINT_EXIT(STORVSC_DRV);
-
return ret;
}
@@ -393,8 +366,6 @@ static void storvsc_commmand_completion(struct hv_storvsc_request *request)
/* (unsigned long)cmd_request); */
/* ASSERT(scmnd->scsi_done); */
- DPRINT_ENTER(STORVSC_DRV);
-
if (cmd_request->bounce_sgl_count) {
/* using bounce buffer */
/* printk("copy_from_bounce_buffer\n"); */
@@ -427,8 +398,6 @@ static void storvsc_commmand_completion(struct hv_storvsc_request *request)
scsi_done_fn(scmnd);
kmem_cache_free(host_device_ctx->request_pool, cmd_request);
-
- DPRINT_EXIT(STORVSC_DRV);
}
static int do_bounce_buffer(struct scatterlist *sgl, unsigned int sg_count)
@@ -647,8 +616,6 @@ static int storvsc_queuecommand(struct scsi_cmnd *scmnd,
int i;
struct scatterlist *sgl;
- DPRINT_ENTER(STORVSC_DRV);
-
DPRINT_DBG(STORVSC_DRV, "scmnd %p dir %d, use_sg %d buf %p len %d "
"queue depth %d tagged %d", scmnd, scmnd->sc_data_direction,
scsi_sg_count(scmnd), scsi_sglist(scmnd),
@@ -812,8 +779,6 @@ retry_request:
ret = SCSI_MLQUEUE_DEVICE_BUSY;
}
- DPRINT_EXIT(STORVSC_DRV);
-
return ret;
}
@@ -873,23 +838,17 @@ static int storvsc_host_reset_handler(struct scsi_cmnd *scmnd)
(struct host_device_context *)scmnd->device->host->hostdata;
struct vm_device *device_ctx = host_device_ctx->device_ctx;
- DPRINT_ENTER(STORVSC_DRV);
-
DPRINT_INFO(STORVSC_DRV, "sdev (%p) dev obj (%p) - host resetting...",
scmnd->device, &device_ctx->device_obj);
/* Invokes the vsc to reset the host/bus */
ret = StorVscOnHostReset(&device_ctx->device_obj);
- if (ret != 0) {
- DPRINT_EXIT(STORVSC_DRV);
+ if (ret != 0)
return ret;
- }
DPRINT_INFO(STORVSC_DRV, "sdev (%p) dev obj (%p) - host reseted",
scmnd->device, &device_ctx->device_obj);
- DPRINT_EXIT(STORVSC_DRV);
-
return ret;
}
@@ -977,18 +936,14 @@ static int __init storvsc_init(void)
{
int ret;
- DPRINT_ENTER(STORVSC_DRV);
DPRINT_INFO(STORVSC_DRV, "Storvsc initializing....");
ret = storvsc_drv_init(StorVscInitialize);
- DPRINT_EXIT(STORVSC_DRV);
return ret;
}
static void __exit storvsc_exit(void)
{
- DPRINT_ENTER(STORVSC_DRV);
storvsc_drv_exit();
- DPRINT_ENTER(STORVSC_DRV);
}
MODULE_LICENSE("GPL");
diff --git a/drivers/staging/hv/vmbus.c b/drivers/staging/hv/vmbus.c
index 007543bdb41..ca1e18a6200 100644
--- a/drivers/staging/hv/vmbus.c
+++ b/drivers/staging/hv/vmbus.c
@@ -57,9 +57,7 @@ static struct hv_device *gDevice; /* vmbus root device */
*/
static void VmbusGetChannelOffers(void)
{
- DPRINT_ENTER(VMBUS);
VmbusChannelRequestOffers();
- DPRINT_EXIT(VMBUS);
}
/*
@@ -120,8 +118,6 @@ static int VmbusOnDeviceAdd(struct hv_device *dev, void *AdditionalInfo)
u32 *irqvector = AdditionalInfo;
int ret;
- DPRINT_ENTER(VMBUS);
-
gDevice = dev;
memcpy(&gDevice->deviceType, &gVmbusDeviceType, sizeof(struct hv_guid));
@@ -136,8 +132,6 @@ static int VmbusOnDeviceAdd(struct hv_device *dev, void *AdditionalInfo)
ret = VmbusConnect();
/* VmbusSendEvent(device->localPortId+1); */
- DPRINT_EXIT(VMBUS);
-
return ret;
}
@@ -148,12 +142,9 @@ static int VmbusOnDeviceRemove(struct hv_device *dev)
{
int ret = 0;
- DPRINT_ENTER(VMBUS);
VmbusChannelReleaseUnattachedChannels();
VmbusDisconnect();
on_each_cpu(HvSynicCleanup, NULL, 1);
- DPRINT_EXIT(VMBUS);
-
return ret;
}
@@ -164,9 +155,7 @@ static void VmbusOnCleanup(struct hv_driver *drv)
{
/* struct vmbus_driver *driver = (struct vmbus_driver *)drv; */
- DPRINT_ENTER(VMBUS);
HvCleanup();
- DPRINT_EXIT(VMBUS);
}
/*
@@ -239,8 +228,6 @@ static int VmbusOnISR(struct hv_driver *drv)
page_addr = gHvContext.synICMessagePage[cpu];
msg = (struct hv_message *)page_addr + VMBUS_MESSAGE_SINT;
- DPRINT_ENTER(VMBUS);
-
/* Check if there are actual msgs to be process */
if (msg->Header.MessageType != HvMessageTypeNone) {
DPRINT_DBG(VMBUS, "received msg type %d size %d",
@@ -259,7 +246,6 @@ static int VmbusOnISR(struct hv_driver *drv)
ret |= 0x2;
}
- DPRINT_EXIT(VMBUS);
return ret;
}
@@ -271,8 +257,6 @@ int VmbusInitialize(struct hv_driver *drv)
struct vmbus_driver *driver = (struct vmbus_driver *)drv;
int ret;
- DPRINT_ENTER(VMBUS);
-
DPRINT_INFO(VMBUS, "+++++++ HV Driver version = %s +++++++",
HV_DRV_VERSION);
DPRINT_INFO(VMBUS, "+++++++ Vmbus supported version = %d +++++++",
@@ -305,7 +289,5 @@ int VmbusInitialize(struct hv_driver *drv)
ret);
gDriver = drv;
- DPRINT_EXIT(VMBUS);
-
return ret;
}
diff --git a/drivers/staging/hv/vmbus_drv.c b/drivers/staging/hv/vmbus_drv.c
index 22c80ece638..092f02ed6be 100644
--- a/drivers/staging/hv/vmbus_drv.c
+++ b/drivers/staging/hv/vmbus_drv.c
@@ -254,8 +254,6 @@ static int vmbus_bus_init(int (*drv_init)(struct hv_driver *drv))
int ret;
unsigned int vector;
- DPRINT_ENTER(VMBUS_DRV);
-
/*
* Set this up to allow lower layer to callback to add/remove child
* devices on the bus
@@ -360,8 +358,6 @@ static int vmbus_bus_init(int (*drv_init)(struct hv_driver *drv))
wait_for_completion(&hv_channel_ready);
cleanup:
- DPRINT_EXIT(VMBUS_DRV);
-
return ret;
}
@@ -377,8 +373,6 @@ static void vmbus_bus_exit(void)
struct vm_device *dev_ctx = &g_vmbus_drv.device_ctx;
- DPRINT_ENTER(VMBUS_DRV);
-
/* Remove the root device */
if (vmbus_drv_obj->Base.OnDeviceRemove)
vmbus_drv_obj->Base.OnDeviceRemove(&dev_ctx->device_obj);
@@ -395,10 +389,6 @@ static void vmbus_bus_exit(void)
tasklet_kill(&vmbus_drv_ctx->msg_dpc);
tasklet_kill(&vmbus_drv_ctx->event_dpc);
-
- DPRINT_EXIT(VMBUS_DRV);
-
- return;
}
@@ -419,8 +409,6 @@ int vmbus_child_driver_register(struct driver_context *driver_ctx)
struct vmbus_driver *vmbus_drv_obj = &g_vmbus_drv.drv_obj;
int ret;
- DPRINT_ENTER(VMBUS_DRV);
-
DPRINT_INFO(VMBUS_DRV, "child driver (%p) registering - name %s",
driver_ctx, driver_ctx->driver.name);
@@ -431,8 +419,6 @@ int vmbus_child_driver_register(struct driver_context *driver_ctx)
vmbus_drv_obj->GetChannelOffers();
- DPRINT_EXIT(VMBUS_DRV);
-
return ret;
}
EXPORT_SYMBOL(vmbus_child_driver_register);
@@ -450,16 +436,12 @@ EXPORT_SYMBOL(vmbus_child_driver_register);
*/
void vmbus_child_driver_unregister(struct driver_context *driver_ctx)
{
- DPRINT_ENTER(VMBUS_DRV);
-
DPRINT_INFO(VMBUS_DRV, "child driver (%p) unregistering - name %s",
driver_ctx, driver_ctx->driver.name);
driver_unregister(&driver_ctx->driver);
driver_ctx->driver.bus = NULL;
-
- DPRINT_EXIT(VMBUS_DRV);
}
EXPORT_SYMBOL(vmbus_child_driver_unregister);
@@ -506,15 +488,11 @@ static struct hv_device *vmbus_child_device_create(struct hv_guid *type,
struct vm_device *child_device_ctx;
struct hv_device *child_device_obj;
- DPRINT_ENTER(VMBUS_DRV);
-
/* Allocate the new child device */
child_device_ctx = kzalloc(sizeof(struct vm_device), GFP_KERNEL);
if (!child_device_ctx) {
DPRINT_ERR(VMBUS_DRV,
"unable to allocate device_context for child device");
- DPRINT_EXIT(VMBUS_DRV);
-
return NULL;
}
@@ -546,8 +524,6 @@ static struct hv_device *vmbus_child_device_create(struct hv_guid *type,
memcpy(&child_device_ctx->class_id, type, sizeof(struct hv_guid));
memcpy(&child_device_ctx->device_id, instance, sizeof(struct hv_guid));
- DPRINT_EXIT(VMBUS_DRV);
-
return child_device_obj;
}
@@ -564,8 +540,6 @@ static int vmbus_child_device_register(struct hv_device *root_device_obj,
to_vm_device(child_device_obj);
static atomic_t device_num = ATOMIC_INIT(0);
- DPRINT_ENTER(VMBUS_DRV);
-
DPRINT_DBG(VMBUS_DRV, "child device (%p) registering",
child_device_ctx);
@@ -594,8 +568,6 @@ static int vmbus_child_device_register(struct hv_device *root_device_obj,
DPRINT_INFO(VMBUS_DRV, "child device (%p) registered",
&child_device_ctx->device);
- DPRINT_EXIT(VMBUS_DRV);
-
return ret;
}
@@ -607,8 +579,6 @@ static void vmbus_child_device_unregister(struct hv_device *device_obj)
{
struct vm_device *device_ctx = to_vm_device(device_obj);
- DPRINT_ENTER(VMBUS_DRV);
-
DPRINT_INFO(VMBUS_DRV, "unregistering child device (%p)",
&device_ctx->device);
@@ -620,8 +590,6 @@ static void vmbus_child_device_unregister(struct hv_device *device_obj)
DPRINT_INFO(VMBUS_DRV, "child device (%p) unregistered",
&device_ctx->device);
-
- DPRINT_EXIT(VMBUS_DRV);
}
/*
@@ -629,9 +597,6 @@ static void vmbus_child_device_unregister(struct hv_device *device_obj)
*/
static void vmbus_child_device_destroy(struct hv_device *device_obj)
{
- DPRINT_ENTER(VMBUS_DRV);
-
- DPRINT_EXIT(VMBUS_DRV);
}
/*
@@ -646,8 +611,6 @@ static int vmbus_uevent(struct device *device, struct kobj_uevent_env *env)
struct vm_device *device_ctx = device_to_vm_device(device);
int ret;
- DPRINT_ENTER(VMBUS_DRV);
-
DPRINT_INFO(VMBUS_DRV, "generating uevent - VMBUS_DEVICE_CLASS_GUID={"
"%02x%02x%02x%02x-%02x%02x-%02x%02x-"
"%02x%02x%02x%02x%02x%02x%02x%02x}",
@@ -708,8 +671,6 @@ static int vmbus_uevent(struct device *device, struct kobj_uevent_env *env)
if (ret)
return ret;
- DPRINT_EXIT(VMBUS_DRV);
-
return 0;
}
@@ -722,8 +683,6 @@ static int vmbus_match(struct device *device, struct device_driver *driver)
struct driver_context *driver_ctx = driver_to_driver_context(driver);
struct vm_device *device_ctx = device_to_vm_device(device);
- DPRINT_ENTER(VMBUS_DRV);
-
/* We found our driver ? */
if (memcmp(&device_ctx->class_id, &driver_ctx->class_id,
sizeof(struct hv_guid)) == 0) {
@@ -742,9 +701,6 @@ static int vmbus_match(struct device *device, struct device_driver *driver)
match = 1;
}
-
- DPRINT_EXIT(VMBUS_DRV);
-
return match;
}
@@ -759,8 +715,6 @@ static void vmbus_probe_failed_cb(struct work_struct *context)
{
struct vm_device *device_ctx = (struct vm_device *)context;
- DPRINT_ENTER(VMBUS_DRV);
-
/*
* Kick off the process of unregistering the device.
* This will call vmbus_remove() and eventually vmbus_device_release()
@@ -768,7 +722,6 @@ static void vmbus_probe_failed_cb(struct work_struct *context)
device_unregister(&device_ctx->device);
/* put_device(&device_ctx->device); */
- DPRINT_EXIT(VMBUS_DRV);
}
/*
@@ -782,8 +735,6 @@ static int vmbus_probe(struct device *child_device)
struct vm_device *device_ctx =
device_to_vm_device(child_device);
- DPRINT_ENTER(VMBUS_DRV);
-
/* Let the specific open-source driver handles the probe if it can */
if (driver_ctx->probe) {
ret = device_ctx->probe_error = driver_ctx->probe(child_device);
@@ -802,8 +753,6 @@ static int vmbus_probe(struct device *child_device)
child_device->driver->name);
ret = -1;
}
-
- DPRINT_EXIT(VMBUS_DRV);
return ret;
}
@@ -815,15 +764,12 @@ static int vmbus_remove(struct device *child_device)
int ret;
struct driver_context *driver_ctx;
- DPRINT_ENTER(VMBUS_DRV);
-
/* Special case root bus device */
if (child_device->parent == NULL) {
/*
* No-op since it is statically defined and handle in
* vmbus_bus_exit()
*/
- DPRINT_EXIT(VMBUS_DRV);
return 0;
}
@@ -844,8 +790,6 @@ static int vmbus_remove(struct device *child_device)
}
}
- DPRINT_EXIT(VMBUS_DRV);
-
return 0;
}
@@ -856,23 +800,18 @@ static void vmbus_shutdown(struct device *child_device)
{
struct driver_context *driver_ctx;
- DPRINT_ENTER(VMBUS_DRV);
-
/* Special case root bus device */
if (child_device->parent == NULL) {
/*
* No-op since it is statically defined and handle in
* vmbus_bus_exit()
*/
- DPRINT_EXIT(VMBUS_DRV);
return;
}
/* The device may not be attached yet */
- if (!child_device->driver) {
- DPRINT_EXIT(VMBUS_DRV);
+ if (!child_device->driver)
return;
- }
driver_ctx = driver_to_driver_context(child_device->driver);
@@ -880,8 +819,6 @@ static void vmbus_shutdown(struct device *child_device)
if (driver_ctx->shutdown)
driver_ctx->shutdown(child_device);
- DPRINT_EXIT(VMBUS_DRV);
-
return;
}
@@ -890,13 +827,11 @@ static void vmbus_shutdown(struct device *child_device)
*/
static void vmbus_bus_release(struct device *device)
{
- DPRINT_ENTER(VMBUS_DRV);
/* FIXME */
/* Empty release functions are a bug, or a major sign
* of a problem design, this MUST BE FIXED! */
dev_err(device, "%s needs to be fixed!\n", __func__);
WARN_ON(1);
- DPRINT_EXIT(VMBUS_DRV);
}
/*
@@ -906,15 +841,10 @@ static void vmbus_device_release(struct device *device)
{
struct vm_device *device_ctx = device_to_vm_device(device);
- DPRINT_ENTER(VMBUS_DRV);
-
/* vmbus_child_device_destroy(&device_ctx->device_obj); */
kfree(device_ctx);
/* !!DO NOT REFERENCE device_ctx anymore at this point!! */
- DPRINT_EXIT(VMBUS_DRV);
-
- return;
}
/*
@@ -924,14 +854,10 @@ static void vmbus_msg_dpc(unsigned long data)
{
struct vmbus_driver *vmbus_drv_obj = (struct vmbus_driver *)data;
- DPRINT_ENTER(VMBUS_DRV);
-
/* ASSERT(vmbus_drv_obj->OnMsgDpc != NULL); */
/* Call to bus driver to handle interrupt */
vmbus_drv_obj->OnMsgDpc(&vmbus_drv_obj->Base);
-
- DPRINT_EXIT(VMBUS_DRV);
}
/*
@@ -941,14 +867,10 @@ static void vmbus_event_dpc(unsigned long data)
{
struct vmbus_driver *vmbus_drv_obj = (struct vmbus_driver *)data;
- DPRINT_ENTER(VMBUS_DRV);
-
/* ASSERT(vmbus_drv_obj->OnEventDpc != NULL); */
/* Call to bus driver to handle interrupt */
vmbus_drv_obj->OnEventDpc(&vmbus_drv_obj->Base);
-
- DPRINT_EXIT(VMBUS_DRV);
}
static irqreturn_t vmbus_isr(int irq, void *dev_id)
@@ -956,8 +878,6 @@ static irqreturn_t vmbus_isr(int irq, void *dev_id)
struct vmbus_driver *vmbus_driver_obj = &g_vmbus_drv.drv_obj;
int ret;
- DPRINT_ENTER(VMBUS_DRV);
-
/* ASSERT(vmbus_driver_obj->OnIsr != NULL); */
/* Call to bus driver to handle interrupt */
@@ -971,10 +891,8 @@ static irqreturn_t vmbus_isr(int irq, void *dev_id)
if (test_bit(1, (unsigned long *)&ret))
tasklet_schedule(&g_vmbus_drv.event_dpc);
- DPRINT_EXIT(VMBUS_DRV);
return IRQ_HANDLED;
} else {
- DPRINT_EXIT(VMBUS_DRV);
return IRQ_NONE;
}
}
@@ -994,10 +912,6 @@ MODULE_DEVICE_TABLE(dmi, microsoft_hv_dmi_table);
static int __init vmbus_init(void)
{
- int ret = 0;
-
- DPRINT_ENTER(VMBUS_DRV);
-
DPRINT_INFO(VMBUS_DRV,
"Vmbus initializing.... current log level 0x%x (%x,%x)",
vmbus_loglevel, HIWORD(vmbus_loglevel), LOWORD(vmbus_loglevel));
@@ -1006,20 +920,13 @@ static int __init vmbus_init(void)
if (!dmi_check_system(microsoft_hv_dmi_table))
return -ENODEV;
- ret = vmbus_bus_init(VmbusInitialize);
-
- DPRINT_EXIT(VMBUS_DRV);
- return ret;
+ return vmbus_bus_init(VmbusInitialize);
}
static void __exit vmbus_exit(void)
{
- DPRINT_ENTER(VMBUS_DRV);
-
vmbus_bus_exit();
/* Todo: it is used for loglevel, to be ported to new kernel. */
- DPRINT_EXIT(VMBUS_DRV);
- return;
}
/*
@@ -1028,7 +935,7 @@ static void __exit vmbus_exit(void)
* installed and/or configured. We don't do anything else with the table, but
* it needs to be present.
*/
-const static struct pci_device_id microsoft_hv_pci_table[] = {
+static const struct pci_device_id microsoft_hv_pci_table[] = {
{ PCI_DEVICE(0x1414, 0x5353) }, /* VGA compatible controller */
{ 0 }
};
diff --git a/drivers/staging/iio/Documentation/overview.txt b/drivers/staging/iio/Documentation/overview.txt
index e39dfc1705a..cc6ecad4035 100644
--- a/drivers/staging/iio/Documentation/overview.txt
+++ b/drivers/staging/iio/Documentation/overview.txt
@@ -44,7 +44,7 @@ which the raw data it self may be read back.
applications it it useful to be able to capture data based on some
external signal (trigger). These triggers might be a data ready
signal, a gpio line connected to some external system or an on
-processor periodic interrupt. A single trigger many initialize data
+processor periodic interrupt. A single trigger may initialize data
capture or reading from a number of sensors. These triggers are
used in iio to fill software ring buffers acting in a very similar
fashion to the hardware buffers described above.
diff --git a/drivers/staging/iio/Kconfig b/drivers/staging/iio/Kconfig
index b0e62449c62..ed48815a916 100644
--- a/drivers/staging/iio/Kconfig
+++ b/drivers/staging/iio/Kconfig
@@ -21,6 +21,7 @@ config IIO_RING_BUFFER
if IIO_RING_BUFFER
config IIO_SW_RING
+ select IIO_TRIGGER
tristate "Industrial I/O lock free software ring"
help
Example software ring buffer implementation. The design aim
@@ -44,6 +45,7 @@ source "drivers/staging/iio/adc/Kconfig"
source "drivers/staging/iio/gyro/Kconfig"
source "drivers/staging/iio/imu/Kconfig"
source "drivers/staging/iio/light/Kconfig"
+source "drivers/staging/iio/magnetometer/Kconfig"
source "drivers/staging/iio/trigger/Kconfig"
diff --git a/drivers/staging/iio/Makefile b/drivers/staging/iio/Makefile
index 3502b39f084..e909674920f 100644
--- a/drivers/staging/iio/Makefile
+++ b/drivers/staging/iio/Makefile
@@ -14,5 +14,5 @@ obj-y += adc/
obj-y += gyro/
obj-y += imu/
obj-y += light/
-
-obj-y += trigger/ \ No newline at end of file
+obj-y += trigger/
+obj-y += magnetometer/
diff --git a/drivers/staging/iio/TODO b/drivers/staging/iio/TODO
index 15da0c2bb78..898cba1c939 100644
--- a/drivers/staging/iio/TODO
+++ b/drivers/staging/iio/TODO
@@ -66,4 +66,4 @@ Documentation
2) Some device require indvidual docs.
Contact: Jonathan Cameron <jic23@cam.ac.uk>.
-Mailing list: LKML.
+Mailing list: linux-iio@vger.kernel.org
diff --git a/drivers/staging/iio/accel/Kconfig b/drivers/staging/iio/accel/Kconfig
index b4e57d1bc87..5926c03be1a 100644
--- a/drivers/staging/iio/accel/Kconfig
+++ b/drivers/staging/iio/accel/Kconfig
@@ -4,29 +4,29 @@
comment "Accelerometers"
config ADIS16209
- tristate "Analog Devices ADIS16209 Dual-Axis Digital Inclinometer and Accelerometer"
- depends on SPI
- select IIO_TRIGGER if IIO_RING_BUFFER
- select IIO_SW_RING if IIO_RING_BUFFER
- help
- Say yes here to build support for Analog Devices adis16209 dual-axis digital inclinometer
- and accelerometer.
+ tristate "Analog Devices ADIS16209 Dual-Axis Digital Inclinometer and Accelerometer"
+ depends on SPI
+ select IIO_TRIGGER if IIO_RING_BUFFER
+ select IIO_SW_RING if IIO_RING_BUFFER
+ help
+ Say yes here to build support for Analog Devices adis16209 dual-axis digital inclinometer
+ and accelerometer.
config ADIS16220
- tristate "Analog Devices ADIS16220 Programmable Digital Vibration Sensor driver"
- depends on SPI
- help
- Say yes here to build support for Analog Devices adis16220 programmable
- digital vibration sensor.
+ tristate "Analog Devices ADIS16220 Programmable Digital Vibration Sensor"
+ depends on SPI
+ help
+ Say yes here to build support for Analog Devices adis16220 programmable
+ digital vibration sensor.
config ADIS16240
- tristate "Analog Devices ADIS16240 Programmable Impact Sensor and Recorder"
- depends on SPI
- select IIO_TRIGGER if IIO_RING_BUFFER
- select IIO_SW_RING if IIO_RING_BUFFER
- help
- Say yes here to build support for Analog Devices adis16240 programmable
- impact Sensor and recorder.
+ tristate "Analog Devices ADIS16240 Programmable Impact Sensor and Recorder"
+ depends on SPI
+ select IIO_TRIGGER if IIO_RING_BUFFER
+ select IIO_SW_RING if IIO_RING_BUFFER
+ help
+ Say yes here to build support for Analog Devices adis16240 programmable
+ impact Sensor and recorder.
config KXSD9
tristate "Kionix KXSD9 Accelerometer Driver"
@@ -46,9 +46,9 @@ config LIS3L02DQ
and an event interface via a character device.
config SCA3000
- depends on IIO_RING_BUFFER
- depends on SPI
- tristate "VTI SCA3000 series accelerometers"
- help
- Say yes here to build support for the VTI SCA3000 series of SPI
- accelerometers. These devices use a hardware ring buffer. \ No newline at end of file
+ depends on IIO_RING_BUFFER
+ depends on SPI
+ tristate "VTI SCA3000 series accelerometers"
+ help
+ Say yes here to build support for the VTI SCA3000 series of SPI
+ accelerometers. These devices use a hardware ring buffer.
diff --git a/drivers/staging/iio/accel/Makefile b/drivers/staging/iio/accel/Makefile
index c34b13634c2..ff84703a16f 100644
--- a/drivers/staging/iio/accel/Makefile
+++ b/drivers/staging/iio/accel/Makefile
@@ -1,6 +1,7 @@
#
# Makefile for industrial I/O accelerometer drivers
#
+
adis16209-y := adis16209_core.o
adis16209-$(CONFIG_IIO_RING_BUFFER) += adis16209_ring.o adis16209_trigger.o
obj-$(CONFIG_ADIS16209) += adis16209.o
@@ -19,4 +20,4 @@ lis3l02dq-$(CONFIG_IIO_RING_BUFFER) += lis3l02dq_ring.o
obj-$(CONFIG_LIS3L02DQ) += lis3l02dq.o
sca3000-y := sca3000_core.o sca3000_ring.o
-obj-$(CONFIG_SCA3000) += sca3000.o \ No newline at end of file
+obj-$(CONFIG_SCA3000) += sca3000.o
diff --git a/drivers/staging/iio/accel/adis16209.h b/drivers/staging/iio/accel/adis16209.h
index 877fd2a4838..4e97596620e 100644
--- a/drivers/staging/iio/accel/adis16209.h
+++ b/drivers/staging/iio/accel/adis16209.h
@@ -105,8 +105,6 @@
* struct adis16209_state - device instance specific data
* @us: actual spi_device
* @work_trigger_to_ring: bh for triggered event handling
- * @work_cont_thresh: CLEAN
- * @inter: used to check if new interrupt has been triggered
* @last_timestamp: passing timestamp from th to bh of interrupt handler
* @indio_dev: industrial I/O device structure
* @trig: data ready trigger registered with iio
@@ -117,7 +115,6 @@
struct adis16209_state {
struct spi_device *us;
struct work_struct work_trigger_to_ring;
- struct iio_work_cont work_cont_thresh;
s64 last_timestamp;
struct iio_dev *indio_dev;
struct iio_trigger *trig;
@@ -129,16 +126,15 @@ struct adis16209_state {
int adis16209_set_irq(struct device *dev, bool enable);
#ifdef CONFIG_IIO_RING_BUFFER
-enum adis16209_scan {
- ADIS16209_SCAN_SUPPLY,
- ADIS16209_SCAN_ACC_X,
- ADIS16209_SCAN_ACC_Y,
- ADIS16209_SCAN_AUX_ADC,
- ADIS16209_SCAN_TEMP,
- ADIS16209_SCAN_INCLI_X,
- ADIS16209_SCAN_INCLI_Y,
- ADIS16209_SCAN_ROT,
-};
+
+#define ADIS16209_SCAN_SUPPLY 0
+#define ADIS16209_SCAN_ACC_X 1
+#define ADIS16209_SCAN_ACC_Y 2
+#define ADIS16209_SCAN_AUX_ADC 3
+#define ADIS16209_SCAN_TEMP 4
+#define ADIS16209_SCAN_INCLI_X 5
+#define ADIS16209_SCAN_INCLI_Y 6
+#define ADIS16209_SCAN_ROT 7
void adis16209_remove_trigger(struct iio_dev *indio_dev);
int adis16209_probe_trigger(struct iio_dev *indio_dev);
@@ -150,8 +146,6 @@ ssize_t adis16209_read_data_from_ring(struct device *dev,
int adis16209_configure_ring(struct iio_dev *indio_dev);
void adis16209_unconfigure_ring(struct iio_dev *indio_dev);
-int adis16209_initialize_ring(struct iio_ring_buffer *ring);
-void adis16209_uninitialize_ring(struct iio_ring_buffer *ring);
#else /* CONFIG_IIO_RING_BUFFER */
static inline void adis16209_remove_trigger(struct iio_dev *indio_dev)
@@ -180,14 +174,5 @@ static inline void adis16209_unconfigure_ring(struct iio_dev *indio_dev)
{
}
-static inline int adis16209_initialize_ring(struct iio_ring_buffer *ring)
-{
- return 0;
-}
-
-static inline void adis16209_uninitialize_ring(struct iio_ring_buffer *ring)
-{
-}
-
#endif /* CONFIG_IIO_RING_BUFFER */
#endif /* SPI_ADIS16209_H_ */
diff --git a/drivers/staging/iio/accel/adis16209_core.c b/drivers/staging/iio/accel/adis16209_core.c
index ac375c50f56..6c6923f2eaa 100644
--- a/drivers/staging/iio/accel/adis16209_core.c
+++ b/drivers/staging/iio/accel/adis16209_core.c
@@ -14,12 +14,13 @@
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/spi/spi.h>
-
+#include <linux/slab.h>
#include <linux/sysfs.h>
#include <linux/list.h>
#include "../iio.h"
#include "../sysfs.h"
+#include "../ring_generic.h"
#include "accel.h"
#include "inclinometer.h"
#include "../gyro/gyro.h"
@@ -76,11 +77,13 @@ static int adis16209_spi_write_reg_16(struct device *dev,
.bits_per_word = 8,
.len = 2,
.cs_change = 1,
+ .delay_usecs = 30,
}, {
.tx_buf = st->tx + 2,
.bits_per_word = 8,
.len = 2,
.cs_change = 1,
+ .delay_usecs = 30,
},
};
@@ -120,13 +123,13 @@ static int adis16209_spi_read_reg_16(struct device *dev,
.bits_per_word = 8,
.len = 2,
.cs_change = 1,
- .delay_usecs = 20,
+ .delay_usecs = 30,
}, {
.rx_buf = st->rx,
.bits_per_word = 8,
.len = 2,
.cs_change = 1,
- .delay_usecs = 20,
+ .delay_usecs = 30,
},
};
@@ -518,7 +521,7 @@ static int __devinit adis16209_probe(struct spi_device *spi)
goto error_unreg_ring_funcs;
regdone = 1;
- ret = adis16209_initialize_ring(st->indio_dev->ring);
+ ret = iio_ring_buffer_register(st->indio_dev->ring, 0);
if (ret) {
printk(KERN_ERR "failed to initialize the ring\n");
goto error_unreg_ring_funcs;
@@ -550,7 +553,7 @@ error_unregister_line:
if (spi->irq)
iio_unregister_interrupt_line(st->indio_dev, 0);
error_uninitialize_ring:
- adis16209_uninitialize_ring(st->indio_dev->ring);
+ iio_ring_buffer_unregister(st->indio_dev->ring);
error_unreg_ring_funcs:
adis16209_unconfigure_ring(st->indio_dev);
error_free_dev:
@@ -579,7 +582,7 @@ static int adis16209_remove(struct spi_device *spi)
if (spi->irq)
iio_unregister_interrupt_line(indio_dev, 0);
- adis16209_uninitialize_ring(indio_dev->ring);
+ iio_ring_buffer_unregister(indio_dev->ring);
iio_device_unregister(indio_dev);
adis16209_unconfigure_ring(indio_dev);
kfree(st->tx);
diff --git a/drivers/staging/iio/accel/adis16209_ring.c b/drivers/staging/iio/accel/adis16209_ring.c
index 533e2857491..25fde659d09 100644
--- a/drivers/staging/iio/accel/adis16209_ring.c
+++ b/drivers/staging/iio/accel/adis16209_ring.c
@@ -6,6 +6,7 @@
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/spi/spi.h>
+#include <linux/slab.h>
#include <linux/sysfs.h>
#include <linux/list.h>
@@ -16,16 +17,6 @@
#include "../trigger.h"
#include "adis16209.h"
-/**
- * combine_8_to_16() utility function to munge to u8s into u16
- **/
-static inline u16 combine_8_to_16(u8 lower, u8 upper)
-{
- u16 _lower = lower;
- u16 _upper = upper;
- return _lower | (_upper << 8);
-}
-
static IIO_SCAN_EL_C(supply, ADIS16209_SCAN_SUPPLY, IIO_UNSIGNED(14),
ADIS16209_SUPPLY_OUT, NULL);
static IIO_SCAN_EL_C(accel_x, ADIS16209_SCAN_ACC_X, IIO_SIGNED(14),
@@ -67,10 +58,10 @@ static struct attribute_group adis16209_scan_el_group = {
* adis16209_poll_func_th() top half interrupt handler called by trigger
* @private_data: iio_dev
**/
-static void adis16209_poll_func_th(struct iio_dev *indio_dev)
+static void adis16209_poll_func_th(struct iio_dev *indio_dev, s64 time)
{
struct adis16209_state *st = iio_dev_get_devdata(indio_dev);
- st->last_timestamp = indio_dev->trig->timestamp;
+ st->last_timestamp = time;
schedule_work(&st->work_trigger_to_ring);
}
@@ -138,10 +129,9 @@ static void adis16209_trigger_bh_to_ring(struct work_struct *work_s)
if (st->indio_dev->scan_count)
if (adis16209_read_ring_data(&st->indio_dev->dev, st->rx) >= 0)
- for (; i < st->indio_dev->scan_count; i++) {
- data[i] = combine_8_to_16(st->rx[i*2+1],
- st->rx[i*2]);
- }
+ for (; i < st->indio_dev->scan_count; i++)
+ data[i] = be16_to_cpup(
+ (__be16 *)&(st->rx[i*2]));
/* Guaranteed to be aligned with 8 byte boundary */
if (st->indio_dev->scan_timestamp)
@@ -157,50 +147,6 @@ static void adis16209_trigger_bh_to_ring(struct work_struct *work_s)
return;
}
-/* in these circumstances is it better to go with unaligned packing and
- * deal with the cost?*/
-static int adis16209_data_rdy_ring_preenable(struct iio_dev *indio_dev)
-{
- size_t size;
- dev_dbg(&indio_dev->dev, "%s\n", __func__);
- /* Check if there are any scan elements enabled, if not fail*/
- if (!(indio_dev->scan_count || indio_dev->scan_timestamp))
- return -EINVAL;
-
- if (indio_dev->ring->access.set_bpd) {
- if (indio_dev->scan_timestamp)
- if (indio_dev->scan_count)
- /* Timestamp (aligned to s64) and data */
- size = (((indio_dev->scan_count * sizeof(s16))
- + sizeof(s64) - 1)
- & ~(sizeof(s64) - 1))
- + sizeof(s64);
- else /* Timestamp only */
- size = sizeof(s64);
- else /* Data only */
- size = indio_dev->scan_count*sizeof(s16);
- indio_dev->ring->access.set_bpd(indio_dev->ring, size);
- }
-
- return 0;
-}
-
-static int adis16209_data_rdy_ring_postenable(struct iio_dev *indio_dev)
-{
- return indio_dev->trig
- ? iio_trigger_attach_poll_func(indio_dev->trig,
- indio_dev->pollfunc)
- : 0;
-}
-
-static int adis16209_data_rdy_ring_predisable(struct iio_dev *indio_dev)
-{
- return indio_dev->trig
- ? iio_trigger_dettach_poll_func(indio_dev->trig,
- indio_dev->pollfunc)
- : 0;
-}
-
void adis16209_unconfigure_ring(struct iio_dev *indio_dev)
{
kfree(indio_dev->pollfunc);
@@ -235,18 +181,16 @@ int adis16209_configure_ring(struct iio_dev *indio_dev)
indio_dev->ring = ring;
/* Effectively select the ring buffer implementation */
iio_ring_sw_register_funcs(&ring->access);
- ring->preenable = &adis16209_data_rdy_ring_preenable;
- ring->postenable = &adis16209_data_rdy_ring_postenable;
- ring->predisable = &adis16209_data_rdy_ring_predisable;
+ ring->bpe = 2;
+ ring->preenable = &iio_sw_ring_preenable;
+ ring->postenable = &iio_triggered_ring_postenable;
+ ring->predisable = &iio_triggered_ring_predisable;
ring->owner = THIS_MODULE;
- indio_dev->pollfunc = kzalloc(sizeof(*indio_dev->pollfunc), GFP_KERNEL);
- if (indio_dev->pollfunc == NULL) {
- ret = -ENOMEM;
- goto error_iio_sw_rb_free;;
- }
- indio_dev->pollfunc->poll_func_main = &adis16209_poll_func_th;
- indio_dev->pollfunc->private_data = indio_dev;
+ ret = iio_alloc_pollfunc(indio_dev, NULL, &adis16209_poll_func_th);
+ if (ret)
+ goto error_iio_sw_rb_free;
+
indio_dev->modes |= INDIO_RING_TRIGGERED;
return 0;
@@ -254,13 +198,3 @@ error_iio_sw_rb_free:
iio_sw_rb_free(indio_dev->ring);
return ret;
}
-
-int adis16209_initialize_ring(struct iio_ring_buffer *ring)
-{
- return iio_ring_buffer_register(ring, 0);
-}
-
-void adis16209_uninitialize_ring(struct iio_ring_buffer *ring)
-{
- iio_ring_buffer_unregister(ring);
-}
diff --git a/drivers/staging/iio/accel/adis16209_trigger.c b/drivers/staging/iio/accel/adis16209_trigger.c
index 4a0507c9a13..1487effa2e3 100644
--- a/drivers/staging/iio/accel/adis16209_trigger.c
+++ b/drivers/staging/iio/accel/adis16209_trigger.c
@@ -23,8 +23,7 @@ static int adis16209_data_rdy_trig_poll(struct iio_dev *dev_info,
struct adis16209_state *st = iio_dev_get_devdata(dev_info);
struct iio_trigger *trig = st->trig;
- trig->timestamp = timestamp;
- iio_trigger_poll(trig);
+ iio_trigger_poll(trig, timestamp);
return IRQ_HANDLED;
}
@@ -83,14 +82,13 @@ int adis16209_probe_trigger(struct iio_dev *indio_dev)
struct adis16209_state *st = indio_dev->dev_data;
st->trig = iio_allocate_trigger();
- st->trig->name = kmalloc(IIO_TRIGGER_NAME_LENGTH, GFP_KERNEL);
+ st->trig->name = kasprintf(GFP_KERNEL,
+ "adis16209-dev%d",
+ indio_dev->id);
if (!st->trig->name) {
ret = -ENOMEM;
goto error_free_trig;
}
- snprintf((char *)st->trig->name,
- IIO_TRIGGER_NAME_LENGTH,
- "adis16209-dev%d", indio_dev->id);
st->trig->dev.parent = &st->us->dev;
st->trig->owner = THIS_MODULE;
st->trig->private_data = st;
diff --git a/drivers/staging/iio/accel/adis16220.h b/drivers/staging/iio/accel/adis16220.h
index 2abf4850b37..7013314a9d7 100644
--- a/drivers/staging/iio/accel/adis16220.h
+++ b/drivers/staging/iio/accel/adis16220.h
@@ -127,7 +127,6 @@
* struct adis16220_state - device instance specific data
* @us: actual spi_device
* @work_trigger_to_ring: bh for triggered event handling
- * @work_cont_thresh: CLEAN
* @inter: used to check if new interrupt has been triggered
* @last_timestamp: passing timestamp from th to bh of interrupt handler
* @indio_dev: industrial I/O device structure
diff --git a/drivers/staging/iio/accel/adis16220_core.c b/drivers/staging/iio/accel/adis16220_core.c
index 6de439fd167..bb7d76539cd 100644
--- a/drivers/staging/iio/accel/adis16220_core.c
+++ b/drivers/staging/iio/accel/adis16220_core.c
@@ -14,7 +14,7 @@
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/spi/spi.h>
-
+#include <linux/slab.h>
#include <linux/sysfs.h>
#include <linux/list.h>
@@ -72,13 +72,13 @@ static int adis16220_spi_write_reg_16(struct device *dev,
.bits_per_word = 8,
.len = 2,
.cs_change = 1,
- .delay_usecs = 25,
+ .delay_usecs = 35,
}, {
.tx_buf = st->tx + 2,
.bits_per_word = 8,
.len = 2,
.cs_change = 1,
- .delay_usecs = 25,
+ .delay_usecs = 35,
},
};
@@ -118,13 +118,13 @@ static int adis16220_spi_read_reg_16(struct device *dev,
.bits_per_word = 8,
.len = 2,
.cs_change = 1,
- .delay_usecs = 25,
+ .delay_usecs = 35,
}, {
.rx_buf = st->rx,
.bits_per_word = 8,
.len = 2,
.cs_change = 1,
- .delay_usecs = 25,
+ .delay_usecs = 35,
},
};
@@ -291,9 +291,9 @@ static int adis16220_check_status(struct device *dev)
if (status & ADIS16220_DIAG_STAT_FLASH_UPT)
dev_err(dev, "Flash update failed\n");
if (status & ADIS16220_DIAG_STAT_POWER_HIGH)
- dev_err(dev, "Power supply above 5.25V\n");
+ dev_err(dev, "Power supply above 3.625V\n");
if (status & ADIS16220_DIAG_STAT_POWER_LOW)
- dev_err(dev, "Power supply below 4.75V\n");
+ dev_err(dev, "Power supply below 3.15V\n");
error_ret:
return ret;
@@ -414,7 +414,7 @@ static ssize_t adis16220_capture_buffer_read(struct adis16220_state *st,
return count;
}
-static ssize_t adis16220_accel_bin_read(struct kobject *kobj,
+static ssize_t adis16220_accel_bin_read(struct file *filp, struct kobject *kobj,
struct bin_attribute *attr,
char *buf,
loff_t off,
@@ -438,7 +438,7 @@ static struct bin_attribute accel_bin = {
.size = ADIS16220_CAPTURE_SIZE,
};
-static ssize_t adis16220_adc1_bin_read(struct kobject *kobj,
+static ssize_t adis16220_adc1_bin_read(struct file *filp, struct kobject *kobj,
struct bin_attribute *attr,
char *buf, loff_t off,
size_t count)
@@ -461,7 +461,7 @@ static struct bin_attribute adc1_bin = {
.size = ADIS16220_CAPTURE_SIZE,
};
-static ssize_t adis16220_adc2_bin_read(struct kobject *kobj,
+static ssize_t adis16220_adc2_bin_read(struct file *filp, struct kobject *kobj,
struct bin_attribute *attr,
char *buf, loff_t off,
size_t count)
diff --git a/drivers/staging/iio/accel/adis16240.h b/drivers/staging/iio/accel/adis16240.h
index dcff43c7523..51a807dde27 100644
--- a/drivers/staging/iio/accel/adis16240.h
+++ b/drivers/staging/iio/accel/adis16240.h
@@ -127,7 +127,6 @@
* struct adis16240_state - device instance specific data
* @us: actual spi_device
* @work_trigger_to_ring: bh for triggered event handling
- * @work_cont_thresh: CLEAN
* @inter: used to check if new interrupt has been triggered
* @last_timestamp: passing timestamp from th to bh of interrupt handler
* @indio_dev: industrial I/O device structure
@@ -139,7 +138,6 @@
struct adis16240_state {
struct spi_device *us;
struct work_struct work_trigger_to_ring;
- struct iio_work_cont work_cont_thresh;
s64 last_timestamp;
struct iio_dev *indio_dev;
struct iio_trigger *trig;
@@ -155,14 +153,12 @@ int adis16240_set_irq(struct device *dev, bool enable);
* filling. This may change!
*/
-enum adis16240_scan {
- ADIS16240_SCAN_SUPPLY,
- ADIS16240_SCAN_ACC_X,
- ADIS16240_SCAN_ACC_Y,
- ADIS16240_SCAN_ACC_Z,
- ADIS16240_SCAN_AUX_ADC,
- ADIS16240_SCAN_TEMP,
-};
+#define ADIS16240_SCAN_SUPPLY 0
+#define ADIS16240_SCAN_ACC_X 1
+#define ADIS16240_SCAN_ACC_Y 2
+#define ADIS16240_SCAN_ACC_Z 3
+#define ADIS16240_SCAN_AUX_ADC 4
+#define ADIS16240_SCAN_TEMP 5
void adis16240_remove_trigger(struct iio_dev *indio_dev);
int adis16240_probe_trigger(struct iio_dev *indio_dev);
@@ -175,8 +171,6 @@ ssize_t adis16240_read_data_from_ring(struct device *dev,
int adis16240_configure_ring(struct iio_dev *indio_dev);
void adis16240_unconfigure_ring(struct iio_dev *indio_dev);
-int adis16240_initialize_ring(struct iio_ring_buffer *ring);
-void adis16240_uninitialize_ring(struct iio_ring_buffer *ring);
#else /* CONFIG_IIO_RING_BUFFER */
static inline void adis16240_remove_trigger(struct iio_dev *indio_dev)
@@ -205,14 +199,5 @@ static inline void adis16240_unconfigure_ring(struct iio_dev *indio_dev)
{
}
-static inline int adis16240_initialize_ring(struct iio_ring_buffer *ring)
-{
- return 0;
-}
-
-static inline void adis16240_uninitialize_ring(struct iio_ring_buffer *ring)
-{
-}
-
#endif /* CONFIG_IIO_RING_BUFFER */
#endif /* SPI_ADIS16240_H_ */
diff --git a/drivers/staging/iio/accel/adis16240_core.c b/drivers/staging/iio/accel/adis16240_core.c
index 54fd6d77412..3e9531dd000 100644
--- a/drivers/staging/iio/accel/adis16240_core.c
+++ b/drivers/staging/iio/accel/adis16240_core.c
@@ -14,12 +14,13 @@
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/spi/spi.h>
-
+#include <linux/slab.h>
#include <linux/sysfs.h>
#include <linux/list.h>
#include "../iio.h"
#include "../sysfs.h"
+#include "../ring_generic.h"
#include "accel.h"
#include "../adc/adc.h"
@@ -74,13 +75,13 @@ static int adis16240_spi_write_reg_16(struct device *dev,
.bits_per_word = 8,
.len = 2,
.cs_change = 1,
- .delay_usecs = 25,
+ .delay_usecs = 35,
}, {
.tx_buf = st->tx + 2,
.bits_per_word = 8,
.len = 2,
.cs_change = 1,
- .delay_usecs = 25,
+ .delay_usecs = 35,
},
};
@@ -120,13 +121,13 @@ static int adis16240_spi_read_reg_16(struct device *dev,
.bits_per_word = 8,
.len = 2,
.cs_change = 1,
- .delay_usecs = 25,
+ .delay_usecs = 35,
}, {
.rx_buf = st->rx,
.bits_per_word = 8,
.len = 2,
.cs_change = 1,
- .delay_usecs = 25,
+ .delay_usecs = 35,
},
};
@@ -502,7 +503,7 @@ static int __devinit adis16240_probe(struct spi_device *spi)
goto error_unreg_ring_funcs;
regdone = 1;
- ret = adis16240_initialize_ring(st->indio_dev->ring);
+ ret = iio_ring_buffer_register(st->indio_dev->ring, 0);
if (ret) {
printk(KERN_ERR "failed to initialize the ring\n");
goto error_unreg_ring_funcs;
@@ -534,7 +535,7 @@ error_unregister_line:
if (spi->irq)
iio_unregister_interrupt_line(st->indio_dev, 0);
error_uninitialize_ring:
- adis16240_uninitialize_ring(st->indio_dev->ring);
+ iio_ring_buffer_unregister(st->indio_dev->ring);
error_unreg_ring_funcs:
adis16240_unconfigure_ring(st->indio_dev);
error_free_dev:
@@ -563,7 +564,7 @@ static int adis16240_remove(struct spi_device *spi)
if (spi->irq)
iio_unregister_interrupt_line(indio_dev, 0);
- adis16240_uninitialize_ring(indio_dev->ring);
+ iio_ring_buffer_unregister(indio_dev->ring);
iio_device_unregister(indio_dev);
adis16240_unconfigure_ring(indio_dev);
kfree(st->tx);
diff --git a/drivers/staging/iio/accel/adis16240_ring.c b/drivers/staging/iio/accel/adis16240_ring.c
index 26b677bd84c..cd69a2e2bb9 100644
--- a/drivers/staging/iio/accel/adis16240_ring.c
+++ b/drivers/staging/iio/accel/adis16240_ring.c
@@ -6,6 +6,7 @@
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/spi/spi.h>
+#include <linux/slab.h>
#include <linux/sysfs.h>
#include <linux/list.h>
@@ -16,16 +17,6 @@
#include "../trigger.h"
#include "adis16240.h"
-/**
- * combine_8_to_16() utility function to munge to u8s into u16
- **/
-static inline u16 combine_8_to_16(u8 lower, u8 upper)
-{
- u16 _lower = lower;
- u16 _upper = upper;
- return _lower | (_upper << 8);
-}
-
static IIO_SCAN_EL_C(supply, ADIS16240_SCAN_SUPPLY, IIO_UNSIGNED(10),
ADIS16240_SUPPLY_OUT, NULL);
static IIO_SCAN_EL_C(accel_x, ADIS16240_SCAN_ACC_X, IIO_SIGNED(10),
@@ -61,10 +52,10 @@ static struct attribute_group adis16240_scan_el_group = {
* adis16240_poll_func_th() top half interrupt handler called by trigger
* @private_data: iio_dev
**/
-static void adis16240_poll_func_th(struct iio_dev *indio_dev)
+static void adis16240_poll_func_th(struct iio_dev *indio_dev, s64 time)
{
struct adis16240_state *st = iio_dev_get_devdata(indio_dev);
- st->last_timestamp = indio_dev->trig->timestamp;
+ st->last_timestamp = time;
schedule_work(&st->work_trigger_to_ring);
}
@@ -130,10 +121,9 @@ static void adis16240_trigger_bh_to_ring(struct work_struct *work_s)
if (st->indio_dev->scan_count)
if (adis16240_read_ring_data(&st->indio_dev->dev, st->rx) >= 0)
- for (; i < st->indio_dev->scan_count; i++) {
- data[i] = combine_8_to_16(st->rx[i*2+1],
- st->rx[i*2]);
- }
+ for (; i < st->indio_dev->scan_count; i++)
+ data[i] = be16_to_cpup(
+ (__be16 *)&(st->rx[i*2]));
/* Guaranteed to be aligned with 8 byte boundary */
if (st->indio_dev->scan_timestamp)
@@ -149,48 +139,6 @@ static void adis16240_trigger_bh_to_ring(struct work_struct *work_s)
return;
}
-static int adis16240_data_rdy_ring_preenable(struct iio_dev *indio_dev)
-{
- size_t size;
- dev_dbg(&indio_dev->dev, "%s\n", __func__);
- /* Check if there are any scan elements enabled, if not fail*/
- if (!(indio_dev->scan_count || indio_dev->scan_timestamp))
- return -EINVAL;
-
- if (indio_dev->ring->access.set_bpd) {
- if (indio_dev->scan_timestamp)
- if (indio_dev->scan_count)
- /* Timestamp (aligned sizeof(s64) and data */
- size = (((indio_dev->scan_count * sizeof(s16))
- + sizeof(s64) - 1)
- & ~(sizeof(s64) - 1))
- + sizeof(s64);
- else /* Timestamp only */
- size = sizeof(s64);
- else /* Data only */
- size = indio_dev->scan_count*sizeof(s16);
- indio_dev->ring->access.set_bpd(indio_dev->ring, size);
- }
-
- return 0;
-}
-
-static int adis16240_data_rdy_ring_postenable(struct iio_dev *indio_dev)
-{
- return indio_dev->trig
- ? iio_trigger_attach_poll_func(indio_dev->trig,
- indio_dev->pollfunc)
- : 0;
-}
-
-static int adis16240_data_rdy_ring_predisable(struct iio_dev *indio_dev)
-{
- return indio_dev->trig
- ? iio_trigger_dettach_poll_func(indio_dev->trig,
- indio_dev->pollfunc)
- : 0;
-}
-
void adis16240_unconfigure_ring(struct iio_dev *indio_dev)
{
kfree(indio_dev->pollfunc);
@@ -223,18 +171,16 @@ int adis16240_configure_ring(struct iio_dev *indio_dev)
indio_dev->ring = ring;
/* Effectively select the ring buffer implementation */
iio_ring_sw_register_funcs(&ring->access);
- ring->preenable = &adis16240_data_rdy_ring_preenable;
- ring->postenable = &adis16240_data_rdy_ring_postenable;
- ring->predisable = &adis16240_data_rdy_ring_predisable;
+ ring->bpe = 2;
+ ring->preenable = &iio_sw_ring_preenable;
+ ring->postenable = &iio_triggered_ring_postenable;
+ ring->predisable = &iio_triggered_ring_predisable;
ring->owner = THIS_MODULE;
- indio_dev->pollfunc = kzalloc(sizeof(*indio_dev->pollfunc), GFP_KERNEL);
- if (indio_dev->pollfunc == NULL) {
- ret = -ENOMEM;
- goto error_iio_sw_rb_free;;
- }
- indio_dev->pollfunc->poll_func_main = &adis16240_poll_func_th;
- indio_dev->pollfunc->private_data = indio_dev;
+ ret = iio_alloc_pollfunc(indio_dev, NULL, &adis16240_poll_func_th);
+ if (ret)
+ goto error_iio_sw_rb_free;
+
indio_dev->modes |= INDIO_RING_TRIGGERED;
return 0;
@@ -243,12 +189,3 @@ error_iio_sw_rb_free:
return ret;
}
-int adis16240_initialize_ring(struct iio_ring_buffer *ring)
-{
- return iio_ring_buffer_register(ring, 0);
-}
-
-void adis16240_uninitialize_ring(struct iio_ring_buffer *ring)
-{
- iio_ring_buffer_unregister(ring);
-}
diff --git a/drivers/staging/iio/accel/adis16240_trigger.c b/drivers/staging/iio/accel/adis16240_trigger.c
index df1312e17f4..2ba71fd73a4 100644
--- a/drivers/staging/iio/accel/adis16240_trigger.c
+++ b/drivers/staging/iio/accel/adis16240_trigger.c
@@ -23,8 +23,7 @@ static int adis16240_data_rdy_trig_poll(struct iio_dev *dev_info,
struct adis16240_state *st = iio_dev_get_devdata(dev_info);
struct iio_trigger *trig = st->trig;
- trig->timestamp = timestamp;
- iio_trigger_poll(trig);
+ iio_trigger_poll(trig, timestamp);
return IRQ_HANDLED;
}
@@ -83,14 +82,13 @@ int adis16240_probe_trigger(struct iio_dev *indio_dev)
struct adis16240_state *st = indio_dev->dev_data;
st->trig = iio_allocate_trigger();
- st->trig->name = kmalloc(IIO_TRIGGER_NAME_LENGTH, GFP_KERNEL);
+ st->trig->name = kasprintf(GFP_KERNEL,
+ "adis16240-dev%d",
+ indio_dev->id);
if (!st->trig->name) {
ret = -ENOMEM;
goto error_free_trig;
}
- snprintf((char *)st->trig->name,
- IIO_TRIGGER_NAME_LENGTH,
- "adis16240-dev%d", indio_dev->id);
st->trig->dev.parent = &st->us->dev;
st->trig->owner = THIS_MODULE;
st->trig->private_data = st;
diff --git a/drivers/staging/iio/accel/kxsd9.c b/drivers/staging/iio/accel/kxsd9.c
index ae7ffe114fc..79f57950ebe 100644
--- a/drivers/staging/iio/accel/kxsd9.c
+++ b/drivers/staging/iio/accel/kxsd9.c
@@ -16,17 +16,11 @@
* heavily optimized ring buffer access function.
*/
-#include <linux/interrupt.h>
-#include <linux/gpio.h>
-#include <linux/fs.h>
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/spi/spi.h>
#include <linux/sysfs.h>
-#include <linux/rtc.h>
-#include <linux/delay.h>
#include <linux/slab.h>
-#include <linux/string.h>
#include "../iio.h"
#include "../sysfs.h"
diff --git a/drivers/staging/iio/accel/lis3l02dq.h b/drivers/staging/iio/accel/lis3l02dq.h
index e76a97937a3..6e730553fca 100644
--- a/drivers/staging/iio/accel/lis3l02dq.h
+++ b/drivers/staging/iio/accel/lis3l02dq.h
@@ -148,30 +148,31 @@ Form of high byte dependant on justification set in ctrl reg */
#define LIS3L02DQ_MAX_RX 12
/**
* struct lis3l02dq_state - device instance specific data
+ * @helper: data and func pointer allowing generic functions
* @us: actual spi_device
- * @work_trigger_to_ring: bh for triggered event handling
- * @work_cont_thresh: CLEAN
+ * @work_thresh: bh for threshold events
+ * @thresh_timestamp: timestamp for threshold interrupts.
* @inter: used to check if new interrupt has been triggered
- * @last_timestamp: passing timestamp from th to bh of interrupt handler
- * @indio_dev: industrial I/O device structure
* @trig: data ready trigger registered with iio
* @tx: transmit buffer
* @rx: recieve buffer
* @buf_lock: mutex to protect tx and rx
**/
struct lis3l02dq_state {
+ struct iio_sw_ring_helper_state help;
struct spi_device *us;
- struct work_struct work_trigger_to_ring;
- struct iio_work_cont work_cont_thresh;
+ struct work_struct work_thresh;
+ s64 thresh_timestamp;
bool inter;
- s64 last_timestamp;
- struct iio_dev *indio_dev;
struct iio_trigger *trig;
u8 *tx;
u8 *rx;
struct mutex buf_lock;
};
+#define lis3l02dq_h_to_s(_h) \
+ container_of(_h, struct lis3l02dq_state, help)
+
int lis3l02dq_spi_read_reg_8(struct device *dev,
u8 reg_address,
u8 *val);
@@ -195,15 +196,15 @@ ssize_t lis3l02dq_read_accel_from_ring(struct device *dev,
int lis3l02dq_configure_ring(struct iio_dev *indio_dev);
void lis3l02dq_unconfigure_ring(struct iio_dev *indio_dev);
-int lis3l02dq_initialize_ring(struct iio_ring_buffer *ring);
-void lis3l02dq_uninitialize_ring(struct iio_ring_buffer *ring);
#else /* CONFIG_IIO_RING_BUFFER */
-static inline void lis3l02dq_remove_trigger(struct iio_dev *indio_dev) {};
+static inline void lis3l02dq_remove_trigger(struct iio_dev *indio_dev)
+{
+}
static inline int lis3l02dq_probe_trigger(struct iio_dev *indio_dev)
{
return 0;
-};
+}
static inline ssize_t
lis3l02dq_read_accel_from_ring(struct device *dev,
@@ -211,18 +212,14 @@ lis3l02dq_read_accel_from_ring(struct device *dev,
char *buf)
{
return 0;
-};
+}
static int lis3l02dq_configure_ring(struct iio_dev *indio_dev)
{
return 0;
-};
+}
static inline void lis3l02dq_unconfigure_ring(struct iio_dev *indio_dev)
-{};
-static inline int lis3l02dq_initialize_ring(struct iio_ring_buffer *ring)
{
- return 0;
-};
-static inline void lis3l02dq_uninitialize_ring(struct iio_ring_buffer *ring) {};
+}
#endif /* CONFIG_IIO_RING_BUFFER */
#endif /* SPI_LIS3L02DQ_H_ */
diff --git a/drivers/staging/iio/accel/lis3l02dq_core.c b/drivers/staging/iio/accel/lis3l02dq_core.c
index 6b5577d7d8d..0ee93373754 100644
--- a/drivers/staging/iio/accel/lis3l02dq_core.c
+++ b/drivers/staging/iio/accel/lis3l02dq_core.c
@@ -27,6 +27,9 @@
#include "../iio.h"
#include "../sysfs.h"
+#include "../ring_generic.h"
+#include "../ring_sw.h"
+
#include "accel.h"
#include "lis3l02dq.h"
@@ -47,7 +50,9 @@ int lis3l02dq_spi_read_reg_8(struct device *dev, u8 reg_address, u8 *val)
int ret;
struct spi_message msg;
struct iio_dev *indio_dev = dev_get_drvdata(dev);
- struct lis3l02dq_state *st = iio_dev_get_devdata(indio_dev);
+ struct iio_sw_ring_helper_state *h = iio_dev_get_devdata(indio_dev);
+ struct lis3l02dq_state *st = lis3l02dq_h_to_s(h);
+
struct spi_transfer xfer = {
.tx_buf = st->tx,
.rx_buf = st->rx,
@@ -82,7 +87,9 @@ int lis3l02dq_spi_write_reg_8(struct device *dev,
int ret;
struct spi_message msg;
struct iio_dev *indio_dev = dev_get_drvdata(dev);
- struct lis3l02dq_state *st = iio_dev_get_devdata(indio_dev);
+ struct iio_sw_ring_helper_state *h
+ = iio_dev_get_devdata(indio_dev);
+ struct lis3l02dq_state *st = lis3l02dq_h_to_s(h);
struct spi_transfer xfer = {
.tx_buf = st->tx,
.bits_per_word = 8,
@@ -96,7 +103,7 @@ int lis3l02dq_spi_write_reg_8(struct device *dev,
spi_message_init(&msg);
spi_message_add_tail(&xfer, &msg);
- ret = spi_sync(st->us, &msg);
+ ret = spi_sync(st->us, &msg);
mutex_unlock(&st->buf_lock);
return ret;
@@ -116,7 +123,9 @@ static int lis3l02dq_spi_write_reg_s16(struct device *dev,
int ret;
struct spi_message msg;
struct iio_dev *indio_dev = dev_get_drvdata(dev);
- struct lis3l02dq_state *st = iio_dev_get_devdata(indio_dev);
+ struct iio_sw_ring_helper_state *h
+ = iio_dev_get_devdata(indio_dev);
+ struct lis3l02dq_state *st = lis3l02dq_h_to_s(h);
struct spi_transfer xfers[] = { {
.tx_buf = st->tx,
.bits_per_word = 8,
@@ -158,7 +167,9 @@ static int lis3l02dq_spi_read_reg_s16(struct device *dev,
{
struct spi_message msg;
struct iio_dev *indio_dev = dev_get_drvdata(dev);
- struct lis3l02dq_state *st = iio_dev_get_devdata(indio_dev);
+ struct iio_sw_ring_helper_state *h
+ = iio_dev_get_devdata(indio_dev);
+ struct lis3l02dq_state *st = lis3l02dq_h_to_s(h);
int ret;
struct spi_transfer xfers[] = { {
.tx_buf = st->tx,
@@ -411,7 +422,7 @@ static int lis3l02dq_initial_setup(struct lis3l02dq_state *st)
val = LIS3L02DQ_DEFAULT_CTRL1;
/* Write suitable defaults to ctrl1 */
- ret = lis3l02dq_spi_write_reg_8(&st->indio_dev->dev,
+ ret = lis3l02dq_spi_write_reg_8(&st->help.indio_dev->dev,
LIS3L02DQ_REG_CTRL_1_ADDR,
&val);
if (ret) {
@@ -419,7 +430,7 @@ static int lis3l02dq_initial_setup(struct lis3l02dq_state *st)
goto err_ret;
}
/* Repeat as sometimes doesn't work first time?*/
- ret = lis3l02dq_spi_write_reg_8(&st->indio_dev->dev,
+ ret = lis3l02dq_spi_write_reg_8(&st->help.indio_dev->dev,
LIS3L02DQ_REG_CTRL_1_ADDR,
&val);
if (ret) {
@@ -429,17 +440,17 @@ static int lis3l02dq_initial_setup(struct lis3l02dq_state *st)
/* Read back to check this has worked acts as loose test of correct
* chip */
- ret = lis3l02dq_spi_read_reg_8(&st->indio_dev->dev,
+ ret = lis3l02dq_spi_read_reg_8(&st->help.indio_dev->dev,
LIS3L02DQ_REG_CTRL_1_ADDR,
&valtest);
if (ret || (valtest != val)) {
- dev_err(&st->indio_dev->dev, "device not playing ball");
+ dev_err(&st->help.indio_dev->dev, "device not playing ball");
ret = -EINVAL;
goto err_ret;
}
val = LIS3L02DQ_DEFAULT_CTRL2;
- ret = lis3l02dq_spi_write_reg_8(&st->indio_dev->dev,
+ ret = lis3l02dq_spi_write_reg_8(&st->help.indio_dev->dev,
LIS3L02DQ_REG_CTRL_2_ADDR,
&val);
if (ret) {
@@ -448,7 +459,7 @@ static int lis3l02dq_initial_setup(struct lis3l02dq_state *st)
}
val = LIS3L02DQ_REG_WAKE_UP_CFG_LATCH_SRC;
- ret = lis3l02dq_spi_write_reg_8(&st->indio_dev->dev,
+ ret = lis3l02dq_spi_write_reg_8(&st->help.indio_dev->dev,
LIS3L02DQ_REG_WAKE_UP_CFG_ADDR,
&val);
if (ret)
@@ -524,8 +535,7 @@ static ssize_t lis3l02dq_read_interrupt_config(struct device *dev,
LIS3L02DQ_REG_WAKE_UP_CFG_ADDR,
(u8 *)&val);
- return ret ? ret : sprintf(buf, "%d\n",
- (val & this_attr->mask) ? 1 : 0);;
+ return ret ? ret : sprintf(buf, "%d\n", !!(val & this_attr->mask));
}
static ssize_t lis3l02dq_write_interrupt_config(struct device *dev,
@@ -595,16 +605,18 @@ error_mutex_unlock:
}
-static int lis3l02dq_thresh_handler_th(struct iio_dev *dev_info,
+static int lis3l02dq_thresh_handler_th(struct iio_dev *indio_dev,
int index,
s64 timestamp,
int no_test)
{
- struct lis3l02dq_state *st = dev_info->dev_data;
+ struct iio_sw_ring_helper_state *h
+ = iio_dev_get_devdata(indio_dev);
+ struct lis3l02dq_state *st = lis3l02dq_h_to_s(h);
/* Stash the timestamp somewhere convenient for the bh */
- st->last_timestamp = timestamp;
- schedule_work(&st->work_cont_thresh.ws);
+ st->thresh_timestamp = timestamp;
+ schedule_work(&st->work_thresh);
return 0;
}
@@ -615,48 +627,49 @@ static int lis3l02dq_thresh_handler_th(struct iio_dev *dev_info,
*/
static void lis3l02dq_thresh_handler_bh_no_check(struct work_struct *work_s)
{
- struct iio_work_cont *wc
- = container_of(work_s, struct iio_work_cont, ws);
- struct lis3l02dq_state *st = wc->st;
+ struct lis3l02dq_state *st
+ = container_of(work_s,
+ struct lis3l02dq_state, work_thresh);
+
u8 t;
- lis3l02dq_spi_read_reg_8(&st->indio_dev->dev,
+ lis3l02dq_spi_read_reg_8(&st->help.indio_dev->dev,
LIS3L02DQ_REG_WAKE_UP_SRC_ADDR,
&t);
if (t & LIS3L02DQ_REG_WAKE_UP_SRC_INTERRUPT_Z_HIGH)
- iio_push_event(st->indio_dev, 0,
+ iio_push_event(st->help.indio_dev, 0,
IIO_EVENT_CODE_ACCEL_Z_HIGH,
- st->last_timestamp);
+ st->thresh_timestamp);
if (t & LIS3L02DQ_REG_WAKE_UP_SRC_INTERRUPT_Z_LOW)
- iio_push_event(st->indio_dev, 0,
+ iio_push_event(st->help.indio_dev, 0,
IIO_EVENT_CODE_ACCEL_Z_LOW,
- st->last_timestamp);
+ st->thresh_timestamp);
if (t & LIS3L02DQ_REG_WAKE_UP_SRC_INTERRUPT_Y_HIGH)
- iio_push_event(st->indio_dev, 0,
+ iio_push_event(st->help.indio_dev, 0,
IIO_EVENT_CODE_ACCEL_Y_HIGH,
- st->last_timestamp);
+ st->thresh_timestamp);
if (t & LIS3L02DQ_REG_WAKE_UP_SRC_INTERRUPT_Y_LOW)
- iio_push_event(st->indio_dev, 0,
+ iio_push_event(st->help.indio_dev, 0,
IIO_EVENT_CODE_ACCEL_Y_LOW,
- st->last_timestamp);
+ st->thresh_timestamp);
if (t & LIS3L02DQ_REG_WAKE_UP_SRC_INTERRUPT_X_HIGH)
- iio_push_event(st->indio_dev, 0,
+ iio_push_event(st->help.indio_dev, 0,
IIO_EVENT_CODE_ACCEL_X_HIGH,
- st->last_timestamp);
+ st->thresh_timestamp);
if (t & LIS3L02DQ_REG_WAKE_UP_SRC_INTERRUPT_X_LOW)
- iio_push_event(st->indio_dev, 0,
+ iio_push_event(st->help.indio_dev, 0,
IIO_EVENT_CODE_ACCEL_X_LOW,
- st->last_timestamp);
+ st->thresh_timestamp);
/* reenable the irq */
enable_irq(st->us->irq);
/* Ack and allow for new interrupts */
- lis3l02dq_spi_read_reg_8(&st->indio_dev->dev,
+ lis3l02dq_spi_read_reg_8(&st->help.indio_dev->dev,
LIS3L02DQ_REG_WAKE_UP_ACK_ADDR,
&t);
@@ -750,6 +763,7 @@ static int __devinit lis3l02dq_probe(struct spi_device *spi)
ret = -ENOMEM;
goto error_ret;
}
+ INIT_WORK(&st->work_thresh, lis3l02dq_thresh_handler_bh_no_check);
/* this is only used tor removal purposes */
spi_set_drvdata(spi, st);
@@ -767,56 +781,46 @@ static int __devinit lis3l02dq_probe(struct spi_device *spi)
st->us = spi;
mutex_init(&st->buf_lock);
/* setup the industrialio driver allocated elements */
- st->indio_dev = iio_allocate_device();
- if (st->indio_dev == NULL) {
+ st->help.indio_dev = iio_allocate_device();
+ if (st->help.indio_dev == NULL) {
ret = -ENOMEM;
goto error_free_tx;
}
- st->indio_dev->dev.parent = &spi->dev;
- st->indio_dev->num_interrupt_lines = 1;
- st->indio_dev->event_attrs = &lis3l02dq_event_attribute_group;
- st->indio_dev->attrs = &lis3l02dq_attribute_group;
- st->indio_dev->dev_data = (void *)(st);
- st->indio_dev->driver_module = THIS_MODULE;
- st->indio_dev->modes = INDIO_DIRECT_MODE;
+ st->help.indio_dev->dev.parent = &spi->dev;
+ st->help.indio_dev->num_interrupt_lines = 1;
+ st->help.indio_dev->event_attrs = &lis3l02dq_event_attribute_group;
+ st->help.indio_dev->attrs = &lis3l02dq_attribute_group;
+ st->help.indio_dev->dev_data = (void *)(&st->help);
+ st->help.indio_dev->driver_module = THIS_MODULE;
+ st->help.indio_dev->modes = INDIO_DIRECT_MODE;
- ret = lis3l02dq_configure_ring(st->indio_dev);
+ ret = lis3l02dq_configure_ring(st->help.indio_dev);
if (ret)
goto error_free_dev;
- ret = iio_device_register(st->indio_dev);
+ ret = iio_device_register(st->help.indio_dev);
if (ret)
goto error_unreg_ring_funcs;
regdone = 1;
- ret = lis3l02dq_initialize_ring(st->indio_dev->ring);
+ ret = iio_ring_buffer_register(st->help.indio_dev->ring, 0);
if (ret) {
printk(KERN_ERR "failed to initialize the ring\n");
goto error_unreg_ring_funcs;
}
if (spi->irq && gpio_is_valid(irq_to_gpio(spi->irq)) > 0) {
- /* This is a little unusual, in that the device seems
- to need a full read of the interrupt source reg before
- the interrupt will reset.
- Hence the two handlers are the same */
- iio_init_work_cont(&st->work_cont_thresh,
- lis3l02dq_thresh_handler_bh_no_check,
- lis3l02dq_thresh_handler_bh_no_check,
- LIS3L02DQ_REG_WAKE_UP_SRC_ADDR,
- 0,
- st);
st->inter = 0;
ret = iio_register_interrupt_line(spi->irq,
- st->indio_dev,
+ st->help.indio_dev,
0,
IRQF_TRIGGER_RISING,
"lis3l02dq");
if (ret)
goto error_uninitialize_ring;
- ret = lis3l02dq_probe_trigger(st->indio_dev);
+ ret = lis3l02dq_probe_trigger(st->help.indio_dev);
if (ret)
goto error_unregister_line;
}
@@ -828,20 +832,20 @@ static int __devinit lis3l02dq_probe(struct spi_device *spi)
return 0;
error_remove_trigger:
- if (st->indio_dev->modes & INDIO_RING_TRIGGERED)
- lis3l02dq_remove_trigger(st->indio_dev);
+ if (st->help.indio_dev->modes & INDIO_RING_TRIGGERED)
+ lis3l02dq_remove_trigger(st->help.indio_dev);
error_unregister_line:
- if (st->indio_dev->modes & INDIO_RING_TRIGGERED)
- iio_unregister_interrupt_line(st->indio_dev, 0);
+ if (st->help.indio_dev->modes & INDIO_RING_TRIGGERED)
+ iio_unregister_interrupt_line(st->help.indio_dev, 0);
error_uninitialize_ring:
- lis3l02dq_uninitialize_ring(st->indio_dev->ring);
+ iio_ring_buffer_unregister(st->help.indio_dev->ring);
error_unreg_ring_funcs:
- lis3l02dq_unconfigure_ring(st->indio_dev);
+ lis3l02dq_unconfigure_ring(st->help.indio_dev);
error_free_dev:
if (regdone)
- iio_device_unregister(st->indio_dev);
+ iio_device_unregister(st->help.indio_dev);
else
- iio_free_device(st->indio_dev);
+ iio_free_device(st->help.indio_dev);
error_free_tx:
kfree(st->tx);
error_free_rx:
@@ -856,7 +860,9 @@ error_ret:
static int lis3l02dq_stop_device(struct iio_dev *indio_dev)
{
int ret;
- struct lis3l02dq_state *st = indio_dev->dev_data;
+ struct iio_sw_ring_helper_state *h
+ = iio_dev_get_devdata(indio_dev);
+ struct lis3l02dq_state *st = lis3l02dq_h_to_s(h);
u8 val = 0;
mutex_lock(&indio_dev->mlock);
@@ -883,7 +889,7 @@ static int lis3l02dq_remove(struct spi_device *spi)
{
int ret;
struct lis3l02dq_state *st = spi_get_drvdata(spi);
- struct iio_dev *indio_dev = st->indio_dev;
+ struct iio_dev *indio_dev = st->help.indio_dev;
ret = lis3l02dq_stop_device(indio_dev);
if (ret)
@@ -895,7 +901,7 @@ static int lis3l02dq_remove(struct spi_device *spi)
if (spi->irq && gpio_is_valid(irq_to_gpio(spi->irq)) > 0)
iio_unregister_interrupt_line(indio_dev, 0);
- lis3l02dq_uninitialize_ring(indio_dev->ring);
+ iio_ring_buffer_unregister(indio_dev->ring);
lis3l02dq_unconfigure_ring(indio_dev);
iio_device_unregister(indio_dev);
kfree(st->tx);
diff --git a/drivers/staging/iio/accel/lis3l02dq_ring.c b/drivers/staging/iio/accel/lis3l02dq_ring.c
index e4e202e6cb3..a960a8ff3c4 100644
--- a/drivers/staging/iio/accel/lis3l02dq_ring.c
+++ b/drivers/staging/iio/accel/lis3l02dq_ring.c
@@ -103,13 +103,15 @@ static struct attribute_group lis3l02dq_scan_el_group = {
* lis3l02dq_poll_func_th() top half interrupt handler called by trigger
* @private_data: iio_dev
**/
-static void lis3l02dq_poll_func_th(struct iio_dev *indio_dev)
+static void lis3l02dq_poll_func_th(struct iio_dev *indio_dev, s64 time)
{
- struct lis3l02dq_state *st = iio_dev_get_devdata(indio_dev);
- st->last_timestamp = indio_dev->trig->timestamp;
- schedule_work(&st->work_trigger_to_ring);
- /* Indicate that this interrupt is being handled */
+ struct iio_sw_ring_helper_state *h
+ = iio_dev_get_devdata(indio_dev);
+ struct lis3l02dq_state *st = lis3l02dq_h_to_s(h);
+ /* in this case we need to slightly extend the helper function */
+ iio_sw_poll_func_th(indio_dev, time);
+ /* Indicate that this interrupt is being handled */
/* Technically this is trigger related, but without this
* handler running there is currently now way for the interrupt
* to clear.
@@ -120,16 +122,16 @@ static void lis3l02dq_poll_func_th(struct iio_dev *indio_dev)
/**
* lis3l02dq_data_rdy_trig_poll() the event handler for the data rdy trig
**/
-static int lis3l02dq_data_rdy_trig_poll(struct iio_dev *dev_info,
+static int lis3l02dq_data_rdy_trig_poll(struct iio_dev *indio_dev,
int index,
s64 timestamp,
int no_test)
{
- struct lis3l02dq_state *st = iio_dev_get_devdata(dev_info);
- struct iio_trigger *trig = st->trig;
+ struct iio_sw_ring_helper_state *h
+ = iio_dev_get_devdata(indio_dev);
+ struct lis3l02dq_state *st = lis3l02dq_h_to_s(h);
- trig->timestamp = timestamp;
- iio_trigger_poll(trig);
+ iio_trigger_poll(st->trig, timestamp);
return IRQ_HANDLED;
}
@@ -213,7 +215,7 @@ static int lis3l02dq_read_all(struct lis3l02dq_state *st, u8 *rx_array)
struct spi_message msg;
int ret, i, j = 0;
- xfers = kzalloc((st->indio_dev->scan_count) * 2
+ xfers = kzalloc((st->help.indio_dev->scan_count) * 2
* sizeof(*xfers), GFP_KERNEL);
if (!xfers)
return -ENOMEM;
@@ -221,7 +223,7 @@ static int lis3l02dq_read_all(struct lis3l02dq_state *st, u8 *rx_array)
mutex_lock(&st->buf_lock);
for (i = 0; i < ARRAY_SIZE(read_all_tx_array)/4; i++) {
- if (st->indio_dev->scan_mask & (1 << i)) {
+ if (st->help.indio_dev->scan_mask & (1 << i)) {
/* lower byte */
xfers[j].tx_buf = st->tx + 2*j;
st->tx[2*j] = read_all_tx_array[i*4];
@@ -249,7 +251,7 @@ static int lis3l02dq_read_all(struct lis3l02dq_state *st, u8 *rx_array)
* values in alternate bytes
*/
spi_message_init(&msg);
- for (j = 0; j < st->indio_dev->scan_count * 2; j++)
+ for (j = 0; j < st->help.indio_dev->scan_count * 2; j++)
spi_message_add_tail(&xfers[j], &msg);
ret = spi_sync(st->us, &msg);
@@ -259,102 +261,37 @@ static int lis3l02dq_read_all(struct lis3l02dq_state *st, u8 *rx_array)
return ret;
}
-
-/* Whilst this makes a lot of calls to iio_sw_ring functions - it is to device
- * specific to be rolled into the core.
- */
static void lis3l02dq_trigger_bh_to_ring(struct work_struct *work_s)
{
- struct lis3l02dq_state *st
- = container_of(work_s, struct lis3l02dq_state,
- work_trigger_to_ring);
-
- u8 *rx_array;
- int i = 0;
- u16 *data;
- size_t datasize = st->indio_dev
- ->ring->access.get_bpd(st->indio_dev->ring);
-
- data = kmalloc(datasize , GFP_KERNEL);
- if (data == NULL) {
- dev_err(&st->us->dev, "memory alloc failed in ring bh");
- return;
- }
- /* Due to interleaved nature of transmission this buffer must be
- * twice the number of bytes, or 4 times the number of channels
- */
- rx_array = kmalloc(4 * (st->indio_dev->scan_count), GFP_KERNEL);
- if (rx_array == NULL) {
- dev_err(&st->us->dev, "memory alloc failed in ring bh");
- kfree(data);
- return;
- }
+ struct iio_sw_ring_helper_state *h
+ = container_of(work_s, struct iio_sw_ring_helper_state,
+ work_trigger_to_ring);
+ struct lis3l02dq_state *st = lis3l02dq_h_to_s(h);
- /* whilst trigger specific, if this read does nto occur the data
- ready interrupt will not be cleared. Need to add a mechanism
- to provide a dummy read function if this is not triggering on
- the data ready function but something else is.
- */
st->inter = 0;
-
- if (st->indio_dev->scan_count)
- if (lis3l02dq_read_all(st, rx_array) >= 0)
- for (; i < st->indio_dev->scan_count; i++)
- data[i] = combine_8_to_16(rx_array[i*4+1],
- rx_array[i*4+3]);
- /* Guaranteed to be aligned with 8 byte boundary */
- if (st->indio_dev->scan_timestamp)
- *((s64 *)(data + ((i + 3)/4)*4)) = st->last_timestamp;
-
- st->indio_dev->ring->access.store_to(st->indio_dev->ring,
- (u8 *)data,
- st->last_timestamp);
-
- iio_trigger_notify_done(st->indio_dev->trig);
- kfree(rx_array);
- kfree(data);
-
- return;
-}
-/* in these circumstances is it better to go with unaligned packing and
- * deal with the cost?*/
-static int lis3l02dq_data_rdy_ring_preenable(struct iio_dev *indio_dev)
-{
- size_t size;
- /* Check if there are any scan elements enabled, if not fail*/
- if (!(indio_dev->scan_count || indio_dev->scan_timestamp))
- return -EINVAL;
-
- if (indio_dev->ring->access.set_bpd) {
- if (indio_dev->scan_timestamp)
- if (indio_dev->scan_count) /* Timestamp and data */
- size = 2*sizeof(s64);
- else /* Timestamp only */
- size = sizeof(s64);
- else /* Data only */
- size = indio_dev->scan_count*sizeof(s16);
- indio_dev->ring->access.set_bpd(indio_dev->ring, size);
- }
-
- return 0;
+ iio_sw_trigger_bh_to_ring(work_s);
}
-static int lis3l02dq_data_rdy_ring_postenable(struct iio_dev *indio_dev)
+static int lis3l02dq_get_ring_element(struct iio_sw_ring_helper_state *h,
+ u8 *buf)
{
- return indio_dev->trig
- ? iio_trigger_attach_poll_func(indio_dev->trig,
- indio_dev->pollfunc)
- : 0;
-}
+ int ret, i;
+ u8 *rx_array ;
+ s16 *data = (s16 *)buf;
-static int lis3l02dq_data_rdy_ring_predisable(struct iio_dev *indio_dev)
-{
- return indio_dev->trig
- ? iio_trigger_dettach_poll_func(indio_dev->trig,
- indio_dev->pollfunc)
- : 0;
-}
+ rx_array = kzalloc(4 * (h->indio_dev->scan_count), GFP_KERNEL);
+ if (rx_array == NULL)
+ return -ENOMEM;
+ ret = lis3l02dq_read_all(lis3l02dq_h_to_s(h), rx_array);
+ if (ret < 0)
+ return ret;
+ for (i = 0; i < h->indio_dev->scan_count; i++)
+ data[i] = combine_8_to_16(rx_array[i*4+1],
+ rx_array[i*4+3]);
+ kfree(rx_array);
+ return i*sizeof(data[0]);
+}
/* Caller responsible for locking as necessary. */
static int
@@ -427,7 +364,7 @@ static int lis3l02dq_data_rdy_trigger_set_state(struct iio_trigger *trig,
struct lis3l02dq_state *st = trig->private_data;
int ret = 0;
u8 t;
- __lis3l02dq_write_data_ready_config(&st->indio_dev->dev,
+ __lis3l02dq_write_data_ready_config(&st->help.indio_dev->dev,
&iio_event_data_rdy_trig,
state);
if (state == false) {
@@ -437,7 +374,7 @@ static int lis3l02dq_data_rdy_trigger_set_state(struct iio_trigger *trig,
/* Clear any outstanding ready events */
ret = lis3l02dq_read_all(st, NULL);
}
- lis3l02dq_spi_read_reg_8(&st->indio_dev->dev,
+ lis3l02dq_spi_read_reg_8(&st->help.indio_dev->dev,
LIS3L02DQ_REG_WAKE_UP_SRC_ADDR,
&t);
return ret;
@@ -495,14 +432,14 @@ int lis3l02dq_probe_trigger(struct iio_dev *indio_dev)
if (!state->trig)
return -ENOMEM;
- state->trig->name = kmalloc(IIO_TRIGGER_NAME_LENGTH, GFP_KERNEL);
+ state->trig->name = kasprintf(GFP_KERNEL,
+ "lis3l02dq-dev%d",
+ indio_dev->id);
if (!state->trig->name) {
ret = -ENOMEM;
goto error_free_trig;
}
- snprintf((char *)state->trig->name,
- IIO_TRIGGER_NAME_LENGTH,
- "lis3l02dq-dev%d", indio_dev->id);
+
state->trig->dev.parent = &state->us->dev;
state->trig->owner = THIS_MODULE;
state->trig->private_data = state;
@@ -540,12 +477,12 @@ void lis3l02dq_unconfigure_ring(struct iio_dev *indio_dev)
int lis3l02dq_configure_ring(struct iio_dev *indio_dev)
{
- int ret = 0;
- struct lis3l02dq_state *st = indio_dev->dev_data;
- struct iio_ring_buffer *ring;
- INIT_WORK(&st->work_trigger_to_ring, lis3l02dq_trigger_bh_to_ring);
- /* Set default scan mode */
+ int ret;
+ struct iio_sw_ring_helper_state *h = iio_dev_get_devdata(indio_dev);
+ INIT_WORK(&h->work_trigger_to_ring, lis3l02dq_trigger_bh_to_ring);
+ /* Set default scan mode */
+ h->get_ring_element = &lis3l02dq_get_ring_element;
iio_scan_mask_set(indio_dev, iio_scan_el_accel_x.number);
iio_scan_mask_set(indio_dev, iio_scan_el_accel_y.number);
iio_scan_mask_set(indio_dev, iio_scan_el_accel_z.number);
@@ -553,26 +490,21 @@ int lis3l02dq_configure_ring(struct iio_dev *indio_dev)
indio_dev->scan_el_attrs = &lis3l02dq_scan_el_group;
- ring = iio_sw_rb_allocate(indio_dev);
- if (!ring) {
- ret = -ENOMEM;
- return ret;
- }
- indio_dev->ring = ring;
+ indio_dev->ring = iio_sw_rb_allocate(indio_dev);
+ if (!indio_dev->ring)
+ return -ENOMEM;
+
/* Effectively select the ring buffer implementation */
- iio_ring_sw_register_funcs(&ring->access);
- ring->preenable = &lis3l02dq_data_rdy_ring_preenable;
- ring->postenable = &lis3l02dq_data_rdy_ring_postenable;
- ring->predisable = &lis3l02dq_data_rdy_ring_predisable;
- ring->owner = THIS_MODULE;
-
- indio_dev->pollfunc = kzalloc(sizeof(*indio_dev->pollfunc), GFP_KERNEL);
- if (indio_dev->pollfunc == NULL) {
- ret = -ENOMEM;
+ iio_ring_sw_register_funcs(&indio_dev->ring->access);
+ indio_dev->ring->bpe = 2;
+ indio_dev->ring->preenable = &iio_sw_ring_preenable;
+ indio_dev->ring->postenable = &iio_triggered_ring_postenable;
+ indio_dev->ring->predisable = &iio_triggered_ring_predisable;
+ indio_dev->ring->owner = THIS_MODULE;
+
+ ret = iio_alloc_pollfunc(indio_dev, NULL, &lis3l02dq_poll_func_th);
+ if (ret)
goto error_iio_sw_rb_free;;
- }
- indio_dev->pollfunc->poll_func_main = &lis3l02dq_poll_func_th;
- indio_dev->pollfunc->private_data = indio_dev;
indio_dev->modes |= INDIO_RING_TRIGGERED;
return 0;
@@ -580,23 +512,3 @@ error_iio_sw_rb_free:
iio_sw_rb_free(indio_dev->ring);
return ret;
}
-
-int lis3l02dq_initialize_ring(struct iio_ring_buffer *ring)
-{
- return iio_ring_buffer_register(ring, 0);
-}
-
-void lis3l02dq_uninitialize_ring(struct iio_ring_buffer *ring)
-{
- iio_ring_buffer_unregister(ring);
-}
-
-int lis3l02dq_set_ring_length(struct iio_dev *indio_dev, int length)
-{
- /* Set sensible defaults for the ring buffer */
- if (indio_dev->ring->access.set_length)
- return indio_dev->ring->access.set_length(indio_dev->ring, 500);
- return 0;
-}
-
-
diff --git a/drivers/staging/iio/accel/sca3000.h b/drivers/staging/iio/accel/sca3000.h
index e5321999b26..09d9470bb9a 100644
--- a/drivers/staging/iio/accel/sca3000.h
+++ b/drivers/staging/iio/accel/sca3000.h
@@ -242,7 +242,7 @@ static inline int sca3000_11bit_convert(uint8_t msb, uint8_t lsb)
val |= (val & (1 << 12)) ? 0xE000 : 0;
return val;
-};
+}
static inline int sca3000_13bit_convert(uint8_t msb, uint8_t lsb)
{
@@ -253,7 +253,7 @@ static inline int sca3000_13bit_convert(uint8_t msb, uint8_t lsb)
val |= (val & (1 << 12)) ? 0xE000 : 0;
return val;
-};
+}
#ifdef CONFIG_IIO_RING_BUFFER
@@ -286,15 +286,19 @@ void sca3000_unconfigure_ring(struct iio_dev *indio_dev);
void sca3000_ring_int_process(u8 val, struct iio_ring_buffer *ring);
#else
-static inline void sca3000_register_ring_funcs(struct iio_dev *indio_dev) {};
+static inline void sca3000_register_ring_funcs(struct iio_dev *indio_dev)
+{
+}
static inline
int sca3000_register_ring_access_and_init(struct iio_dev *indio_dev)
{
return 0;
-};
+}
-static inline void sca3000_ring_int_process(u8 val, void *ring) {};
+static inline void sca3000_ring_int_process(u8 val, void *ring)
+{
+}
#endif
diff --git a/drivers/staging/iio/accel/sca3000_core.c b/drivers/staging/iio/accel/sca3000_core.c
index d4f82c39f33..b78b6b66ffe 100644
--- a/drivers/staging/iio/accel/sca3000_core.c
+++ b/drivers/staging/iio/accel/sca3000_core.c
@@ -387,7 +387,7 @@ sca3000_show_available_measurement_modes(struct device *dev,
case SCA3000_OP_MODE_BYPASS:
len += sprintf(buf + len, ", 1 - bypass mode");
break;
- };
+ }
switch (st->info->option_mode_2) {
case SCA3000_OP_MODE_WIDE:
len += sprintf(buf + len, ", 2 - wide mode");
@@ -433,7 +433,7 @@ sca3000_show_measurement_mode(struct device *dev,
case SCA3000_OP_MODE_BYPASS:
len += sprintf(buf + len, "1 - bypass mode\n");
break;
- };
+ }
break;
case SCA3000_MEAS_MODE_OP_2:
switch (st->info->option_mode_2) {
@@ -442,7 +442,7 @@ sca3000_show_measurement_mode(struct device *dev,
break;
}
break;
- };
+ }
error_ret:
mutex_unlock(&st->lock);
@@ -559,7 +559,7 @@ static ssize_t sca3000_read_av_freq(struct device *dev,
st->info->option_mode_2_freq/2,
st->info->option_mode_2_freq/4);
break;
- };
+ }
kfree(rx);
return len;
error_ret:
@@ -590,7 +590,7 @@ static inline int __sca3000_get_base_freq(struct sca3000_state *st,
case SCA3000_MEAS_MODE_OP_2:
*base_freq = info->option_mode_2_freq;
break;
- };
+ }
kfree(rx);
error_ret:
return ret;
@@ -627,8 +627,8 @@ static ssize_t sca3000_read_frequency(struct device *dev,
case 0x02:
len = sprintf(buf, "%d\n", base_freq/4);
break;
- };
- kfree(rx);
+ }
+ kfree(rx);
return len;
error_ret_mut:
mutex_unlock(&st->lock);
diff --git a/drivers/staging/iio/adc/Makefile b/drivers/staging/iio/adc/Makefile
index 18c9376ecbb..688510fd8bb 100644
--- a/drivers/staging/iio/adc/Makefile
+++ b/drivers/staging/iio/adc/Makefile
@@ -1,4 +1,4 @@
-
+#
# Makefile for industrial I/O ADC drivers
#
diff --git a/drivers/staging/iio/adc/adc.h b/drivers/staging/iio/adc/adc.h
index 04eb16fd0a9..7841e6ad434 100644
--- a/drivers/staging/iio/adc/adc.h
+++ b/drivers/staging/iio/adc/adc.h
@@ -26,3 +26,6 @@
_show, \
NULL, \
_addr)
+
+#define IIO_EVENT_CODE_IN_HIGH_THRESH(a) (IIO_EVENT_CODE_ADC_BASE + a)
+#define IIO_EVENT_CODE_IN_LOW_THRESH(a) (IIO_EVENT_CODE_ADC_BASE + a + 32)
diff --git a/drivers/staging/iio/adc/max1363.h b/drivers/staging/iio/adc/max1363.h
index 72cf3670936..8f0fe1ced2c 100644
--- a/drivers/staging/iio/adc/max1363.h
+++ b/drivers/staging/iio/adc/max1363.h
@@ -32,14 +32,6 @@
/* Specific to the max1363 */
#define MAX1363_MON_RESET_CHAN(a) (1 << ((a) + 4))
-#define MAX1363_MON_CONV_RATE_133ksps 0
-#define MAX1363_MON_CONV_RATE_66_5ksps 0x02
-#define MAX1363_MON_CONV_RATE_33_3ksps 0x04
-#define MAX1363_MON_CONV_RATE_16_6ksps 0x06
-#define MAX1363_MON_CONV_RATE_8_3ksps 0x08
-#define MAX1363_MON_CONV_RATE_4_2ksps 0x0A
-#define MAX1363_MON_CONV_RATE_2_0ksps 0x0C
-#define MAX1363_MON_CONV_RATE_1_0ksps 0x0E
#define MAX1363_MON_INT_ENABLE 0x01
/* defined for readability reasons */
@@ -67,9 +59,8 @@
/**
* struct max1363_mode - scan mode information
- * @name: Name used to identify the scan mode.
* @conf: The corresponding value of the configuration register
- * @numvals: The number of values returned by a single scan
+ * @modemask: Bit mask corresponding to channels enabled in this mode
*/
struct max1363_mode {
int8_t conf;
@@ -122,15 +113,6 @@ struct max1363_mode {
.modemask = _mask \
}
-/* Not currently handled */
-#define MAX1363_MODE_MONITOR { \
- .name = "monitor", \
- .conf = MAX1363_CHANNEL_SEL(3) \
- | MAX1363_CONFIG_SCAN_MONITOR_MODE \
- | MAX1363_CONFIG_SE, \
- .numvals = 10, \
- }
-
/* This may seem an overly long winded way to do this, but at least it makes
* clear what all the various options actually do. Alternative suggestions
* that don't require user to have intimate knowledge of the chip welcomed.
@@ -147,7 +129,7 @@ enum max1363_channels {
max1363_in1min0, max1363_in3min2,
max1363_in5min4, max1363_in7min6,
max1363_in9min8, max1363_in11min10,
- };
+};
/* This must be maintained along side the max1363_mode_table in max1363_core */
enum max1363_modes {
@@ -179,7 +161,6 @@ enum max1363_modes {
* @default_mode: the scan mode in which the chip starts up
*/
struct max1363_chip_info {
- const char *name;
u8 num_inputs;
u8 bits;
u16 int_vref_mv;
@@ -191,7 +172,6 @@ struct max1363_chip_info {
struct attribute_group *scan_attrs;
};
-
/**
* struct max1363_state - driver instance specific data
* @indio_dev: the industrial I/O device
@@ -204,12 +184,20 @@ struct max1363_chip_info {
* @poll_work: bottom half of polling interrupt handler
* @protect_ring: used to ensure only one polling bh running at a time
* @reg: supply regulator
+ * @monitor_on: whether monitor mode is enabled
+ * @monitor_speed: parameter corresponding to device monitor speed setting
+ * @mask_high: bitmask for enabled high thresholds
+ * @mask_low: bitmask for enabled low thresholds
+ * @thresh_high: high threshold values
+ * @thresh_low: low threshold values
+ * @last_timestamp: timestamp of last event interrupt
+ * @thresh_work: bh work structure for event handling
*/
struct max1363_state {
struct iio_dev *indio_dev;
struct i2c_client *client;
- char setupbyte;
- char configbyte;
+ u8 setupbyte;
+ u8 configbyte;
const struct max1363_chip_info *chip_info;
const struct max1363_mode *current_mode;
u32 requestedmask;
@@ -217,6 +205,18 @@ struct max1363_state {
atomic_t protect_ring;
struct iio_trigger *trig;
struct regulator *reg;
+
+ /* Using monitor modes and buffer at the same time is
+ currently not supported */
+ bool monitor_on;
+ unsigned int monitor_speed:3;
+ u8 mask_high;
+ u8 mask_low;
+ /* 4x unipolar first then the fours bipolar ones */
+ s16 thresh_high[8];
+ s16 thresh_low[8];
+ s64 last_timestamp;
+ struct work_struct thresh_work;
};
const struct max1363_mode
@@ -230,32 +230,21 @@ int max1363_single_channel_from_ring(long mask, struct max1363_state *st);
int max1363_register_ring_funcs_and_init(struct iio_dev *indio_dev);
void max1363_ring_cleanup(struct iio_dev *indio_dev);
-int max1363_initialize_ring(struct iio_ring_buffer *ring);
-void max1363_uninitialize_ring(struct iio_ring_buffer *ring);
-
#else /* CONFIG_MAX1363_RING_BUFFER */
-static inline void max1363_uninitialize_ring(struct iio_ring_buffer *ring)
-{
-};
-
-static inline int max1363_initialize_ring(struct iio_ring_buffer *ring)
-{
- return 0;
-};
-
int max1363_single_channel_from_ring(long mask, struct max1363_state *st)
{
return -EINVAL;
-};
-
+}
static inline int
max1363_register_ring_funcs_and_init(struct iio_dev *indio_dev)
{
return 0;
-};
+}
-static inline void max1363_ring_cleanup(struct iio_dev *indio_dev) {};
+static inline void max1363_ring_cleanup(struct iio_dev *indio_dev)
+{
+}
#endif /* CONFIG_MAX1363_RING_BUFFER */
#endif /* _MAX1363_H_ */
diff --git a/drivers/staging/iio/adc/max1363_core.c b/drivers/staging/iio/adc/max1363_core.c
index 905f8560d31..6435e509dd5 100644
--- a/drivers/staging/iio/adc/max1363_core.c
+++ b/drivers/staging/iio/adc/max1363_core.c
@@ -18,21 +18,19 @@
*
* Not currently implemented.
*
- * - Monitor interrrupt generation.
* - Control of internal reference.
*/
#include <linux/interrupt.h>
-#include <linux/gpio.h>
#include <linux/workqueue.h>
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/sysfs.h>
#include <linux/list.h>
#include <linux/i2c.h>
-#include <linux/rtc.h>
#include <linux/regulator/consumer.h>
#include <linux/slab.h>
+#include <linux/err.h>
#include "../iio.h"
#include "../sysfs.h"
@@ -48,7 +46,7 @@
IIO_SCAN_EL_C(in##number, number, IIO_UNSIGNED(16), 0, NULL);
#define MAX1363_SCAN_EL_D(p, n, number) \
IIO_SCAN_NAMED_EL_C(in##p##m##in##n, in##p-in##n, \
- number, IIO_SIGNED(16), 0 , NULL);
+ number, IIO_SIGNED(16), 0, NULL);
static MAX1363_SCAN_EL(0);
static MAX1363_SCAN_EL(1);
@@ -148,7 +146,7 @@ const struct max1363_mode
mask))
return &max1363_mode_table[ci->mode_list[i]];
return NULL;
-};
+}
static ssize_t max1363_show_precision(struct device *dev,
struct device_attribute *attr,
@@ -167,7 +165,7 @@ static int max1363_write_basic_config(struct i2c_client *client,
unsigned char d2)
{
int ret;
- u8 *tx_buf = kmalloc(2 , GFP_KERNEL);
+ u8 *tx_buf = kmalloc(2, GFP_KERNEL);
if (!tx_buf)
return -ENOMEM;
@@ -206,6 +204,16 @@ static ssize_t max1363_read_single_channel(struct device *dev,
long mask;
mutex_lock(&dev_info->mlock);
+ /*
+ * If monitor mode is enabled, the method for reading a single
+ * channel will have to be rather different and has not yet
+ * been implemented.
+ */
+ if (st->monitor_on) {
+ ret = -EBUSY;
+ goto error_ret;
+ }
+
/* If ring buffer capture is occuring, query the buffer */
if (iio_ring_enabled(dev_info)) {
mask = max1363_mode_table[this_attr->address].modemask;
@@ -305,7 +313,7 @@ static ssize_t max1363_show_name(struct device *dev,
{
struct iio_dev *dev_info = dev_get_drvdata(dev);
struct max1363_state *st = iio_dev_get_devdata(dev_info);
- return sprintf(buf, "%s\n", st->chip_info->name);
+ return sprintf(buf, "%s\n", st->client->name);
}
static IIO_DEVICE_ATTR(name, S_IRUGO, max1363_show_name, NULL, 0);
@@ -552,8 +560,7 @@ enum { max1361,
/* max1363 and max1368 tested - rest from data sheet */
static const struct max1363_chip_info max1363_chip_info_tbl[] = {
- {
- .name = "max1361",
+ [max1361] = {
.num_inputs = 4,
.bits = 10,
.int_vref_mv = 2048,
@@ -563,8 +570,8 @@ static const struct max1363_chip_info max1363_chip_info_tbl[] = {
.default_mode = s0to3,
.dev_attrs = &max1363_dev_attr_group,
.scan_attrs = &max1363_scan_el_group,
- }, {
- .name = "max1362",
+ },
+ [max1362] = {
.num_inputs = 4,
.bits = 10,
.int_vref_mv = 4096,
@@ -574,8 +581,8 @@ static const struct max1363_chip_info max1363_chip_info_tbl[] = {
.default_mode = s0to3,
.dev_attrs = &max1363_dev_attr_group,
.scan_attrs = &max1363_scan_el_group,
- }, {
- .name = "max1363",
+ },
+ [max1363] = {
.num_inputs = 4,
.bits = 12,
.int_vref_mv = 2048,
@@ -585,8 +592,8 @@ static const struct max1363_chip_info max1363_chip_info_tbl[] = {
.default_mode = s0to3,
.dev_attrs = &max1363_dev_attr_group,
.scan_attrs = &max1363_scan_el_group,
- }, {
- .name = "max1364",
+ },
+ [max1364] = {
.num_inputs = 4,
.bits = 12,
.int_vref_mv = 4096,
@@ -596,8 +603,8 @@ static const struct max1363_chip_info max1363_chip_info_tbl[] = {
.default_mode = s0to3,
.dev_attrs = &max1363_dev_attr_group,
.scan_attrs = &max1363_scan_el_group,
- }, {
- .name = "max1036",
+ },
+ [max1036] = {
.num_inputs = 4,
.bits = 8,
.int_vref_mv = 4096,
@@ -606,8 +613,8 @@ static const struct max1363_chip_info max1363_chip_info_tbl[] = {
.default_mode = s0to3,
.dev_attrs = &max1363_dev_attr_group,
.scan_attrs = &max1363_scan_el_group,
- }, {
- .name = "max1037",
+ },
+ [max1037] = {
.num_inputs = 4,
.bits = 8,
.int_vref_mv = 2048,
@@ -616,8 +623,8 @@ static const struct max1363_chip_info max1363_chip_info_tbl[] = {
.default_mode = s0to3,
.dev_attrs = &max1363_dev_attr_group,
.scan_attrs = &max1363_scan_el_group,
- }, {
- .name = "max1038",
+ },
+ [max1038] = {
.num_inputs = 12,
.bits = 8,
.int_vref_mv = 4096,
@@ -626,8 +633,8 @@ static const struct max1363_chip_info max1363_chip_info_tbl[] = {
.default_mode = s0to11,
.dev_attrs = &max1238_dev_attr_group,
.scan_attrs = &max1238_scan_el_group,
- }, {
- .name = "max1039",
+ },
+ [max1039] = {
.num_inputs = 12,
.bits = 8,
.int_vref_mv = 2048,
@@ -636,8 +643,8 @@ static const struct max1363_chip_info max1363_chip_info_tbl[] = {
.default_mode = s0to11,
.dev_attrs = &max1238_dev_attr_group,
.scan_attrs = &max1238_scan_el_group,
- }, {
- .name = "max1136",
+ },
+ [max1136] = {
.num_inputs = 4,
.bits = 10,
.int_vref_mv = 4096,
@@ -646,8 +653,8 @@ static const struct max1363_chip_info max1363_chip_info_tbl[] = {
.default_mode = s0to3,
.dev_attrs = &max1363_dev_attr_group,
.scan_attrs = &max1363_scan_el_group,
- }, {
- .name = "max1137",
+ },
+ [max1137] = {
.num_inputs = 4,
.bits = 10,
.int_vref_mv = 2048,
@@ -656,8 +663,8 @@ static const struct max1363_chip_info max1363_chip_info_tbl[] = {
.default_mode = s0to3,
.dev_attrs = &max1363_dev_attr_group,
.scan_attrs = &max1363_scan_el_group,
- }, {
- .name = "max1138",
+ },
+ [max1138] = {
.num_inputs = 12,
.bits = 10,
.int_vref_mv = 4096,
@@ -666,8 +673,8 @@ static const struct max1363_chip_info max1363_chip_info_tbl[] = {
.default_mode = s0to11,
.dev_attrs = &max1238_dev_attr_group,
.scan_attrs = &max1238_scan_el_group,
- }, {
- .name = "max1139",
+ },
+ [max1139] = {
.num_inputs = 12,
.bits = 10,
.int_vref_mv = 2048,
@@ -676,8 +683,8 @@ static const struct max1363_chip_info max1363_chip_info_tbl[] = {
.default_mode = s0to11,
.dev_attrs = &max1238_dev_attr_group,
.scan_attrs = &max1238_scan_el_group,
- }, {
- .name = "max1236",
+ },
+ [max1236] = {
.num_inputs = 4,
.bits = 12,
.int_vref_mv = 4096,
@@ -686,8 +693,8 @@ static const struct max1363_chip_info max1363_chip_info_tbl[] = {
.default_mode = s0to3,
.dev_attrs = &max1363_dev_attr_group,
.scan_attrs = &max1363_scan_el_group,
- }, {
- .name = "max1237",
+ },
+ [max1237] = {
.num_inputs = 4,
.bits = 12,
.int_vref_mv = 2048,
@@ -696,8 +703,8 @@ static const struct max1363_chip_info max1363_chip_info_tbl[] = {
.default_mode = s0to3,
.dev_attrs = &max1363_dev_attr_group,
.scan_attrs = &max1363_scan_el_group,
- }, {
- .name = "max1238",
+ },
+ [max1238] = {
.num_inputs = 12,
.bits = 12,
.int_vref_mv = 4096,
@@ -706,8 +713,8 @@ static const struct max1363_chip_info max1363_chip_info_tbl[] = {
.default_mode = s0to11,
.dev_attrs = &max1238_dev_attr_group,
.scan_attrs = &max1238_scan_el_group,
- }, {
- .name = "max1239",
+ },
+ [max1239] = {
.num_inputs = 12,
.bits = 12,
.int_vref_mv = 2048,
@@ -716,8 +723,8 @@ static const struct max1363_chip_info max1363_chip_info_tbl[] = {
.default_mode = s0to11,
.dev_attrs = &max1238_dev_attr_group,
.scan_attrs = &max1238_scan_el_group,
- }, {
- .name = "max11600",
+ },
+ [max11600] = {
.num_inputs = 4,
.bits = 8,
.int_vref_mv = 4096,
@@ -726,8 +733,8 @@ static const struct max1363_chip_info max1363_chip_info_tbl[] = {
.default_mode = s0to3,
.dev_attrs = &max1363_dev_attr_group,
.scan_attrs = &max1363_scan_el_group,
- }, {
- .name = "max11601",
+ },
+ [max11601] = {
.num_inputs = 4,
.bits = 8,
.int_vref_mv = 2048,
@@ -736,8 +743,8 @@ static const struct max1363_chip_info max1363_chip_info_tbl[] = {
.default_mode = s0to3,
.dev_attrs = &max1363_dev_attr_group,
.scan_attrs = &max1363_scan_el_group,
- }, {
- .name = "max11602",
+ },
+ [max11602] = {
.num_inputs = 8,
.bits = 8,
.int_vref_mv = 4096,
@@ -746,8 +753,8 @@ static const struct max1363_chip_info max1363_chip_info_tbl[] = {
.default_mode = s0to7,
.dev_attrs = &max11608_dev_attr_group,
.scan_attrs = &max11608_scan_el_group,
- }, {
- .name = "max11603",
+ },
+ [max11603] = {
.num_inputs = 8,
.bits = 8,
.int_vref_mv = 2048,
@@ -756,8 +763,8 @@ static const struct max1363_chip_info max1363_chip_info_tbl[] = {
.default_mode = s0to7,
.dev_attrs = &max11608_dev_attr_group,
.scan_attrs = &max11608_scan_el_group,
- }, {
- .name = "max11604",
+ },
+ [max11604] = {
.num_inputs = 12,
.bits = 8,
.int_vref_mv = 4098,
@@ -766,8 +773,8 @@ static const struct max1363_chip_info max1363_chip_info_tbl[] = {
.default_mode = s0to11,
.dev_attrs = &max1238_dev_attr_group,
.scan_attrs = &max1238_scan_el_group,
- }, {
- .name = "max11605",
+ },
+ [max11605] = {
.num_inputs = 12,
.bits = 8,
.int_vref_mv = 2048,
@@ -776,8 +783,8 @@ static const struct max1363_chip_info max1363_chip_info_tbl[] = {
.default_mode = s0to11,
.dev_attrs = &max1238_dev_attr_group,
.scan_attrs = &max1238_scan_el_group,
- }, {
- .name = "max11606",
+ },
+ [max11606] = {
.num_inputs = 4,
.bits = 10,
.int_vref_mv = 4096,
@@ -786,8 +793,8 @@ static const struct max1363_chip_info max1363_chip_info_tbl[] = {
.default_mode = s0to3,
.dev_attrs = &max1363_dev_attr_group,
.scan_attrs = &max1363_scan_el_group,
- }, {
- .name = "max11607",
+ },
+ [max11607] = {
.num_inputs = 4,
.bits = 10,
.int_vref_mv = 2048,
@@ -796,8 +803,8 @@ static const struct max1363_chip_info max1363_chip_info_tbl[] = {
.default_mode = s0to3,
.dev_attrs = &max1363_dev_attr_group,
.scan_attrs = &max1363_scan_el_group,
- }, {
- .name = "max11608",
+ },
+ [max11608] = {
.num_inputs = 8,
.bits = 10,
.int_vref_mv = 4096,
@@ -806,8 +813,8 @@ static const struct max1363_chip_info max1363_chip_info_tbl[] = {
.default_mode = s0to7,
.dev_attrs = &max11608_dev_attr_group,
.scan_attrs = &max11608_scan_el_group,
- }, {
- .name = "max11609",
+ },
+ [max11609] = {
.num_inputs = 8,
.bits = 10,
.int_vref_mv = 2048,
@@ -816,8 +823,8 @@ static const struct max1363_chip_info max1363_chip_info_tbl[] = {
.default_mode = s0to7,
.dev_attrs = &max11608_dev_attr_group,
.scan_attrs = &max11608_scan_el_group,
- }, {
- .name = "max11610",
+ },
+ [max11610] = {
.num_inputs = 12,
.bits = 10,
.int_vref_mv = 4098,
@@ -826,8 +833,8 @@ static const struct max1363_chip_info max1363_chip_info_tbl[] = {
.default_mode = s0to11,
.dev_attrs = &max1238_dev_attr_group,
.scan_attrs = &max1238_scan_el_group,
- }, {
- .name = "max11611",
+ },
+ [max11611] = {
.num_inputs = 12,
.bits = 10,
.int_vref_mv = 2048,
@@ -836,8 +843,8 @@ static const struct max1363_chip_info max1363_chip_info_tbl[] = {
.default_mode = s0to11,
.dev_attrs = &max1238_dev_attr_group,
.scan_attrs = &max1238_scan_el_group,
- }, {
- .name = "max11612",
+ },
+ [max11612] = {
.num_inputs = 4,
.bits = 12,
.int_vref_mv = 4096,
@@ -846,8 +853,8 @@ static const struct max1363_chip_info max1363_chip_info_tbl[] = {
.default_mode = s0to3,
.dev_attrs = &max1363_dev_attr_group,
.scan_attrs = &max1363_scan_el_group,
- }, {
- .name = "max11613",
+ },
+ [max11613] = {
.num_inputs = 4,
.bits = 12,
.int_vref_mv = 2048,
@@ -856,8 +863,8 @@ static const struct max1363_chip_info max1363_chip_info_tbl[] = {
.default_mode = s0to3,
.dev_attrs = &max1363_dev_attr_group,
.scan_attrs = &max1363_scan_el_group,
- }, {
- .name = "max11614",
+ },
+ [max11614] = {
.num_inputs = 8,
.bits = 12,
.int_vref_mv = 4096,
@@ -866,8 +873,8 @@ static const struct max1363_chip_info max1363_chip_info_tbl[] = {
.default_mode = s0to7,
.dev_attrs = &max11608_dev_attr_group,
.scan_attrs = &max11608_scan_el_group,
- }, {
- .name = "max11615",
+ },
+ [max11615] = {
.num_inputs = 8,
.bits = 12,
.int_vref_mv = 2048,
@@ -876,8 +883,8 @@ static const struct max1363_chip_info max1363_chip_info_tbl[] = {
.default_mode = s0to7,
.dev_attrs = &max11608_dev_attr_group,
.scan_attrs = &max11608_scan_el_group,
- }, {
- .name = "max11616",
+ },
+ [max11616] = {
.num_inputs = 12,
.bits = 12,
.int_vref_mv = 4098,
@@ -886,8 +893,8 @@ static const struct max1363_chip_info max1363_chip_info_tbl[] = {
.default_mode = s0to11,
.dev_attrs = &max1238_dev_attr_group,
.scan_attrs = &max1238_scan_el_group,
- }, {
- .name = "max11617",
+ },
+ [max11617] = {
.num_inputs = 12,
.bits = 12,
.int_vref_mv = 2048,
@@ -899,6 +906,668 @@ static const struct max1363_chip_info max1363_chip_info_tbl[] = {
}
};
+static const int max1363_monitor_speeds[] = { 133000, 665000, 33300, 16600,
+ 8300, 4200, 2000, 1000 };
+
+static ssize_t max1363_monitor_show_freq(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct max1363_state *st = iio_dev_get_devdata(dev_info);
+ return sprintf(buf, "%d\n", max1363_monitor_speeds[st->monitor_speed]);
+}
+
+static ssize_t max1363_monitor_store_freq(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct max1363_state *st = iio_dev_get_devdata(dev_info);
+ int i, ret;
+ unsigned long val;
+ bool found = false;
+
+ ret = strict_strtoul(buf, 10, &val);
+ if (ret)
+ return -EINVAL;
+ for (i = 0; i < ARRAY_SIZE(max1363_monitor_speeds); i++)
+ if (val == max1363_monitor_speeds[i]) {
+ found = true;
+ break;
+ }
+ if (!found)
+ return -EINVAL;
+
+ mutex_lock(&dev_info->mlock);
+ st->monitor_speed = i;
+ mutex_unlock(&dev_info->mlock);
+
+ return 0;
+}
+
+static IIO_DEV_ATTR_SAMP_FREQ(S_IRUGO | S_IWUSR,
+ max1363_monitor_show_freq,
+ max1363_monitor_store_freq);
+
+static IIO_CONST_ATTR(sampling_frequency_available,
+ "133000 665000 33300 16600 8300 4200 2000 1000");
+
+static ssize_t max1363_show_thresh(struct device *dev,
+ struct device_attribute *attr,
+ char *buf,
+ bool high)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct max1363_state *st = iio_dev_get_devdata(dev_info);
+ struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
+
+ if (high)
+ return sprintf(buf, "%d\n",
+ st->thresh_high[this_attr->address]);
+ else
+ return sprintf(buf, "%d\n",
+ st->thresh_low[this_attr->address & 0x7]);
+}
+
+static ssize_t max1363_show_thresh_low(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return max1363_show_thresh(dev, attr, buf, false);
+}
+
+static ssize_t max1363_show_thresh_high(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return max1363_show_thresh(dev, attr, buf, true);
+}
+
+static ssize_t max1363_store_thresh_unsigned(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len,
+ bool high)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct max1363_state *st = iio_dev_get_devdata(dev_info);
+ struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
+ unsigned long val;
+ int ret;
+
+ ret = strict_strtoul(buf, 10, &val);
+ if (ret)
+ return -EINVAL;
+ switch (st->chip_info->bits) {
+ case 10:
+ if (val > 0x3FF)
+ return -EINVAL;
+ break;
+ case 12:
+ if (val > 0xFFF)
+ return -EINVAL;
+ break;
+ }
+
+ switch (high) {
+ case 1:
+ st->thresh_high[this_attr->address] = val;
+ break;
+ case 0:
+ st->thresh_low[this_attr->address & 0x7] = val;
+ break;
+ }
+
+ return len;
+}
+
+static ssize_t max1363_store_thresh_high_unsigned(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
+{
+ return max1363_store_thresh_unsigned(dev, attr, buf, len, true);
+}
+
+static ssize_t max1363_store_thresh_low_unsigned(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
+{
+ return max1363_store_thresh_unsigned(dev, attr, buf, len, false);
+}
+
+static ssize_t max1363_store_thresh_signed(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len,
+ bool high)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct max1363_state *st = iio_dev_get_devdata(dev_info);
+ struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
+ long val;
+ int ret;
+
+ ret = strict_strtol(buf, 10, &val);
+ if (ret)
+ return -EINVAL;
+ switch (st->chip_info->bits) {
+ case 10:
+ if (val < -512 || val > 511)
+ return -EINVAL;
+ break;
+ case 12:
+ if (val < -2048 || val > 2047)
+ return -EINVAL;
+ break;
+ }
+
+ switch (high) {
+ case 1:
+ st->thresh_high[this_attr->address] = val;
+ break;
+ case 0:
+ st->thresh_low[this_attr->address & 0x7] = val;
+ break;
+ }
+
+ return len;
+}
+
+static ssize_t max1363_store_thresh_high_signed(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
+{
+ return max1363_store_thresh_signed(dev, attr, buf, len, true);
+}
+
+static ssize_t max1363_store_thresh_low_signed(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
+{
+ return max1363_store_thresh_signed(dev, attr, buf, len, false);
+}
+
+static IIO_DEVICE_ATTR(in0_thresh_high_value, S_IRUGO | S_IWUSR,
+ max1363_show_thresh_high,
+ max1363_store_thresh_high_unsigned, 0);
+static IIO_DEVICE_ATTR(in0_thresh_low_value, S_IRUGO | S_IWUSR,
+ max1363_show_thresh_low,
+ max1363_store_thresh_low_unsigned, 0);
+static IIO_DEVICE_ATTR(in1_thresh_high_value, S_IRUGO | S_IWUSR,
+ max1363_show_thresh_high,
+ max1363_store_thresh_high_unsigned, 1);
+static IIO_DEVICE_ATTR(in1_thresh_low_value, S_IRUGO | S_IWUSR,
+ max1363_show_thresh_low,
+ max1363_store_thresh_low_unsigned, 1);
+static IIO_DEVICE_ATTR(in2_thresh_high_value, S_IRUGO | S_IWUSR,
+ max1363_show_thresh_high,
+ max1363_store_thresh_high_unsigned, 2);
+static IIO_DEVICE_ATTR(in2_thresh_low_value, S_IRUGO | S_IWUSR,
+ max1363_show_thresh_low,
+ max1363_store_thresh_low_unsigned, 2);
+static IIO_DEVICE_ATTR(in3_thresh_high_value, S_IRUGO | S_IWUSR,
+ max1363_show_thresh_high,
+ max1363_store_thresh_high_unsigned, 3);
+static IIO_DEVICE_ATTR(in3_thresh_low_value, S_IRUGO | S_IWUSR,
+ max1363_show_thresh_low,
+ max1363_store_thresh_low_unsigned, 3);
+
+static IIO_DEVICE_ATTR_NAMED(in0min1_thresh_high_value,
+ in0-in1_thresh_high_value,
+ S_IRUGO | S_IWUSR, max1363_show_thresh_high,
+ max1363_store_thresh_high_signed, 4);
+static IIO_DEVICE_ATTR_NAMED(in0min1_thresh_low_value,
+ in0-in1_thresh_low_value,
+ S_IRUGO | S_IWUSR, max1363_show_thresh_low,
+ max1363_store_thresh_low_signed, 4);
+static IIO_DEVICE_ATTR_NAMED(in2min3_thresh_high_value,
+ in2-in3_thresh_high_value,
+ S_IRUGO | S_IWUSR, max1363_show_thresh_high,
+ max1363_store_thresh_high_signed, 5);
+static IIO_DEVICE_ATTR_NAMED(in2min3_thresh_low_value,
+ in2-in3_thresh_low_value,
+ S_IRUGO | S_IWUSR, max1363_show_thresh_low,
+ max1363_store_thresh_low_signed, 5);
+static IIO_DEVICE_ATTR_NAMED(in1min0_thresh_high_value,
+ in1-in0_thresh_high_value,
+ S_IRUGO | S_IWUSR, max1363_show_thresh_high,
+ max1363_store_thresh_high_signed, 6);
+static IIO_DEVICE_ATTR_NAMED(in1min0_thresh_low_value,
+ in1-in0_thresh_low_value,
+ S_IRUGO | S_IWUSR, max1363_show_thresh_low,
+ max1363_store_thresh_low_signed, 6);
+static IIO_DEVICE_ATTR_NAMED(in3min2_thresh_high_value,
+ in3-in2_thresh_high_value,
+ S_IRUGO | S_IWUSR, max1363_show_thresh_high,
+ max1363_store_thresh_high_signed, 7);
+static IIO_DEVICE_ATTR_NAMED(in3min2_thresh_low_value,
+ in3-in2_thresh_low_value,
+ S_IRUGO | S_IWUSR, max1363_show_thresh_low,
+ max1363_store_thresh_low_signed, 7);
+
+static int max1363_int_th(struct iio_dev *dev_info,
+ int index,
+ s64 timestamp,
+ int not_test)
+{
+ struct max1363_state *st = dev_info->dev_data;
+
+ st->last_timestamp = timestamp;
+ schedule_work(&st->thresh_work);
+ return 0;
+}
+
+static void max1363_thresh_handler_bh(struct work_struct *work_s)
+{
+ struct max1363_state *st = container_of(work_s, struct max1363_state,
+ thresh_work);
+ u8 rx;
+ u8 tx[2] = { st->setupbyte,
+ MAX1363_MON_INT_ENABLE | (st->monitor_speed << 1) | 0xF0 };
+
+ i2c_master_recv(st->client, &rx, 1);
+ if (rx & (1 << 0))
+ iio_push_event(st->indio_dev, 0,
+ IIO_EVENT_CODE_IN_LOW_THRESH(3),
+ st->last_timestamp);
+ if (rx & (1 << 1))
+ iio_push_event(st->indio_dev, 0,
+ IIO_EVENT_CODE_IN_HIGH_THRESH(3),
+ st->last_timestamp);
+ if (rx & (1 << 2))
+ iio_push_event(st->indio_dev, 0,
+ IIO_EVENT_CODE_IN_LOW_THRESH(2),
+ st->last_timestamp);
+ if (rx & (1 << 3))
+ iio_push_event(st->indio_dev, 0,
+ IIO_EVENT_CODE_IN_HIGH_THRESH(2),
+ st->last_timestamp);
+ if (rx & (1 << 4))
+ iio_push_event(st->indio_dev, 0,
+ IIO_EVENT_CODE_IN_LOW_THRESH(1),
+ st->last_timestamp);
+ if (rx & (1 << 5))
+ iio_push_event(st->indio_dev, 0,
+ IIO_EVENT_CODE_IN_HIGH_THRESH(1),
+ st->last_timestamp);
+ if (rx & (1 << 6))
+ iio_push_event(st->indio_dev, 0,
+ IIO_EVENT_CODE_IN_LOW_THRESH(0),
+ st->last_timestamp);
+ if (rx & (1 << 7))
+ iio_push_event(st->indio_dev, 0,
+ IIO_EVENT_CODE_IN_HIGH_THRESH(0),
+ st->last_timestamp);
+ enable_irq(st->client->irq);
+ i2c_master_send(st->client, tx, 2);
+}
+
+static ssize_t max1363_read_interrupt_config(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct max1363_state *st = iio_dev_get_devdata(dev_info);
+ struct iio_event_attr *this_attr = to_iio_event_attr(attr);
+ int val;
+
+ mutex_lock(&dev_info->mlock);
+ if (this_attr->mask & 0x8)
+ val = (1 << (this_attr->mask & 0x7)) & st->mask_low;
+ else
+ val = (1 << this_attr->mask) & st->mask_high;
+ mutex_unlock(&dev_info->mlock);
+
+ return sprintf(buf, "%d\n", !!val);
+}
+
+static int max1363_monitor_mode_update(struct max1363_state *st, int enabled)
+{
+ u8 *tx_buf;
+ int ret, i = 3, j;
+ unsigned long numelements;
+ int len;
+ long modemask;
+
+ if (!enabled) {
+ /* transition to ring capture is not currently supported */
+ st->setupbyte &= ~MAX1363_SETUP_MONITOR_SETUP;
+ st->configbyte &= ~MAX1363_SCAN_MASK;
+ st->monitor_on = false;
+ return max1363_write_basic_config(st->client,
+ st->setupbyte,
+ st->configbyte);
+ }
+
+ /* Ensure we are in the relevant mode */
+ st->setupbyte |= MAX1363_SETUP_MONITOR_SETUP;
+ st->configbyte &= ~(MAX1363_CHANNEL_SEL_MASK
+ | MAX1363_SCAN_MASK
+ | MAX1363_SE_DE_MASK);
+ st->configbyte |= MAX1363_CONFIG_SCAN_MONITOR_MODE;
+ if ((st->mask_low | st->mask_high) & 0x0F) {
+ st->configbyte |= max1363_mode_table[s0to3].conf;
+ modemask = max1363_mode_table[s0to3].modemask;
+ } else if ((st->mask_low | st->mask_high) & 0x30) {
+ st->configbyte |= max1363_mode_table[d0m1to2m3].conf;
+ modemask = max1363_mode_table[d0m1to2m3].modemask;
+ } else {
+ st->configbyte |= max1363_mode_table[d1m0to3m2].conf;
+ modemask = max1363_mode_table[d1m0to3m2].modemask;
+ }
+ numelements = hweight_long(modemask);
+ len = 3 * numelements + 3;
+ tx_buf = kmalloc(len, GFP_KERNEL);
+ if (!tx_buf) {
+ ret = -ENOMEM;
+ goto error_ret;
+ }
+ tx_buf[0] = st->configbyte;
+ tx_buf[1] = st->setupbyte;
+ tx_buf[2] = (st->monitor_speed << 1);
+
+ /*
+ * So we need to do yet another bit of nefarious scan mode
+ * setup to match what we need.
+ */
+ for (j = 0; j < 8; j++)
+ if (modemask & (1 << j)) {
+ /* Establish the mode is in the scan */
+ if (st->mask_low & (1 << j)) {
+ tx_buf[i] = (st->thresh_low[j] >> 4) & 0xFF;
+ tx_buf[i + 1] = (st->thresh_low[j] << 4) & 0xF0;
+ } else if (j < 4) {
+ tx_buf[i] = 0;
+ tx_buf[i + 1] = 0;
+ } else {
+ tx_buf[i] = 0x80;
+ tx_buf[i + 1] = 0;
+ }
+ if (st->mask_high & (1 << j)) {
+ tx_buf[i + 1] |=
+ (st->thresh_high[j] >> 8) & 0x0F;
+ tx_buf[i + 2] = st->thresh_high[j] & 0xFF;
+ } else if (j < 4) {
+ tx_buf[i + 1] |= 0x0F;
+ tx_buf[i + 2] = 0xFF;
+ } else {
+ tx_buf[i + 1] |= 0x07;
+ tx_buf[i + 2] = 0xFF;
+ }
+ i += 3;
+ }
+
+
+ ret = i2c_master_send(st->client, tx_buf, len);
+ if (ret < 0)
+ goto error_ret;
+ if (ret != len) {
+ ret = -EIO;
+ goto error_ret;
+ }
+
+ /*
+ * Now that we hopefully have sensible thresholds in place it is
+ * time to turn the interrupts on.
+ * It is unclear from the data sheet if this should be necessary
+ * (i.e. whether monitor mode setup is atomic) but it appears to
+ * be in practice.
+ */
+ tx_buf[0] = st->setupbyte;
+ tx_buf[1] = MAX1363_MON_INT_ENABLE | (st->monitor_speed << 1) | 0xF0;
+ ret = i2c_master_send(st->client, tx_buf, 2);
+ if (ret < 0)
+ goto error_ret;
+ if (ret != 2) {
+ ret = -EIO;
+ goto error_ret;
+ }
+ ret = 0;
+ st->monitor_on = true;
+error_ret:
+
+ kfree(tx_buf);
+
+ return ret;
+}
+
+/*
+ * To keep this managable we always use one of 3 scan modes.
+ * Scan 0...3, 0-1,2-3 and 1-0,3-2
+ */
+static inline int __max1363_check_event_mask(int thismask, int checkmask)
+{
+ int ret = 0;
+ /* Is it unipolar */
+ if (thismask < 4) {
+ if (checkmask & ~0x0F) {
+ ret = -EBUSY;
+ goto error_ret;
+ }
+ } else if (thismask < 6) {
+ if (checkmask & ~0x30) {
+ ret = -EBUSY;
+ goto error_ret;
+ }
+ } else if (checkmask & ~0xC0)
+ ret = -EBUSY;
+error_ret:
+ return ret;
+}
+
+static ssize_t max1363_write_interrupt_config(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct max1363_state *st = iio_dev_get_devdata(dev_info);
+ struct iio_event_attr *this_attr = to_iio_event_attr(attr);
+ unsigned long val;
+ int ret;
+ u16 unifiedmask;
+ ret = strict_strtoul(buf, 10, &val);
+ if (ret)
+ return -EINVAL;
+ mutex_lock(&st->indio_dev->mlock);
+ unifiedmask = st->mask_low | st->mask_high;
+ if (this_attr->mask & 0x08) {
+ /* If we are disabling no need to test */
+ if (val == 0)
+ st->mask_low &= ~(1 << (this_attr->mask & 0x7));
+ else {
+ ret = __max1363_check_event_mask(this_attr->mask & 0x7,
+ unifiedmask);
+ if (ret)
+ goto error_ret;
+ st->mask_low |= (1 << (this_attr->mask & 0x7));
+ }
+ } else {
+ if (val == 0)
+ st->mask_high &= ~(1 << (this_attr->mask));
+ else {
+ ret = __max1363_check_event_mask(this_attr->mask,
+ unifiedmask);
+ if (ret)
+ goto error_ret;
+ st->mask_high |= (1 << this_attr->mask);
+ }
+ }
+ if (st->monitor_on && !st->mask_high && !st->mask_low)
+ iio_remove_event_from_list(this_attr->listel,
+ &dev_info->interrupts[0]->ev_list);
+ if (!st->monitor_on && val)
+ iio_add_event_to_list(this_attr->listel,
+ &dev_info->interrupts[0]->ev_list);
+
+ max1363_monitor_mode_update(st, !!(st->mask_high | st->mask_low));
+error_ret:
+ mutex_unlock(&st->indio_dev->mlock);
+
+ return len;
+}
+
+IIO_EVENT_SH(max1363_thresh, max1363_int_th);
+
+#define MAX1363_HIGH_THRESH(a) a
+#define MAX1363_LOW_THRESH(a) (a | 0x8)
+
+IIO_EVENT_ATTR_SH(in0_thresh_high_en,
+ iio_event_max1363_thresh,
+ max1363_read_interrupt_config,
+ max1363_write_interrupt_config,
+ MAX1363_HIGH_THRESH(0));
+
+IIO_EVENT_ATTR_SH(in0_thresh_low_en,
+ iio_event_max1363_thresh,
+ max1363_read_interrupt_config,
+ max1363_write_interrupt_config,
+ MAX1363_LOW_THRESH(0));
+
+IIO_EVENT_ATTR_SH(in1_thresh_high_en,
+ iio_event_max1363_thresh,
+ max1363_read_interrupt_config,
+ max1363_write_interrupt_config,
+ MAX1363_HIGH_THRESH(1));
+
+IIO_EVENT_ATTR_SH(in1_thresh_low_en,
+ iio_event_max1363_thresh,
+ max1363_read_interrupt_config,
+ max1363_write_interrupt_config,
+ MAX1363_LOW_THRESH(1));
+
+IIO_EVENT_ATTR_SH(in2_thresh_high_en,
+ iio_event_max1363_thresh,
+ max1363_read_interrupt_config,
+ max1363_write_interrupt_config,
+ MAX1363_HIGH_THRESH(2));
+
+IIO_EVENT_ATTR_SH(in2_thresh_low_en,
+ iio_event_max1363_thresh,
+ max1363_read_interrupt_config,
+ max1363_write_interrupt_config,
+ MAX1363_LOW_THRESH(2));
+
+IIO_EVENT_ATTR_SH(in3_thresh_high_en,
+ iio_event_max1363_thresh,
+ max1363_read_interrupt_config,
+ max1363_write_interrupt_config,
+ MAX1363_HIGH_THRESH(3));
+
+IIO_EVENT_ATTR_SH(in3_thresh_low_en,
+ iio_event_max1363_thresh,
+ max1363_read_interrupt_config,
+ max1363_write_interrupt_config,
+ MAX1363_LOW_THRESH(3));
+
+IIO_EVENT_ATTR_NAMED_SH(in0min1_thresh_high_en,
+ in0-in1_thresh_high_en,
+ iio_event_max1363_thresh,
+ max1363_read_interrupt_config,
+ max1363_write_interrupt_config,
+ MAX1363_HIGH_THRESH(4));
+
+IIO_EVENT_ATTR_NAMED_SH(in0min1_thresh_low_en,
+ in0-in1_thresh_low_en,
+ iio_event_max1363_thresh,
+ max1363_read_interrupt_config,
+ max1363_write_interrupt_config,
+ MAX1363_LOW_THRESH(4));
+
+IIO_EVENT_ATTR_NAMED_SH(in3min2_thresh_high_en,
+ in3-in2_thresh_high_en,
+ iio_event_max1363_thresh,
+ max1363_read_interrupt_config,
+ max1363_write_interrupt_config,
+ MAX1363_HIGH_THRESH(5));
+
+IIO_EVENT_ATTR_NAMED_SH(in3min2_thresh_low_en,
+ in3-in2_thresh_low_en,
+ iio_event_max1363_thresh,
+ max1363_read_interrupt_config,
+ max1363_write_interrupt_config,
+ MAX1363_LOW_THRESH(5));
+
+IIO_EVENT_ATTR_NAMED_SH(in1min0_thresh_high_en,
+ in1-in0_thresh_high_en,
+ iio_event_max1363_thresh,
+ max1363_read_interrupt_config,
+ max1363_write_interrupt_config,
+ MAX1363_HIGH_THRESH(6));
+
+IIO_EVENT_ATTR_NAMED_SH(in1min0_thresh_low_en,
+ in1-in0_thresh_low_en,
+ iio_event_max1363_thresh,
+ max1363_read_interrupt_config,
+ max1363_write_interrupt_config,
+ MAX1363_LOW_THRESH(6));
+
+IIO_EVENT_ATTR_NAMED_SH(in2min3_thresh_high_en,
+ in2-in3_thresh_high_en,
+ iio_event_max1363_thresh,
+ max1363_read_interrupt_config,
+ max1363_write_interrupt_config,
+ MAX1363_HIGH_THRESH(7));
+
+IIO_EVENT_ATTR_NAMED_SH(in2min3_thresh_low_en,
+ in2-in3_thresh_low_en,
+ iio_event_max1363_thresh,
+ max1363_read_interrupt_config,
+ max1363_write_interrupt_config,
+ MAX1363_LOW_THRESH(7));
+
+/*
+ * As with scan_elements, only certain sets of these can
+ * be combined.
+ */
+static struct attribute *max1363_event_attributes[] = {
+ &iio_dev_attr_in0_thresh_high_value.dev_attr.attr,
+ &iio_dev_attr_in0_thresh_low_value.dev_attr.attr,
+ &iio_dev_attr_in1_thresh_high_value.dev_attr.attr,
+ &iio_dev_attr_in1_thresh_low_value.dev_attr.attr,
+ &iio_dev_attr_in2_thresh_high_value.dev_attr.attr,
+ &iio_dev_attr_in2_thresh_low_value.dev_attr.attr,
+ &iio_dev_attr_in3_thresh_high_value.dev_attr.attr,
+ &iio_dev_attr_in3_thresh_low_value.dev_attr.attr,
+ &iio_dev_attr_in0min1_thresh_high_value.dev_attr.attr,
+ &iio_dev_attr_in0min1_thresh_low_value.dev_attr.attr,
+ &iio_dev_attr_in2min3_thresh_high_value.dev_attr.attr,
+ &iio_dev_attr_in2min3_thresh_low_value.dev_attr.attr,
+ &iio_dev_attr_in1min0_thresh_high_value.dev_attr.attr,
+ &iio_dev_attr_in1min0_thresh_low_value.dev_attr.attr,
+ &iio_dev_attr_in3min2_thresh_high_value.dev_attr.attr,
+ &iio_dev_attr_in3min2_thresh_low_value.dev_attr.attr,
+ &iio_dev_attr_sampling_frequency.dev_attr.attr,
+ &iio_const_attr_sampling_frequency_available.dev_attr.attr,
+ &iio_event_attr_in0_thresh_high_en.dev_attr.attr,
+ &iio_event_attr_in0_thresh_low_en.dev_attr.attr,
+ &iio_event_attr_in1_thresh_high_en.dev_attr.attr,
+ &iio_event_attr_in1_thresh_low_en.dev_attr.attr,
+ &iio_event_attr_in2_thresh_high_en.dev_attr.attr,
+ &iio_event_attr_in2_thresh_low_en.dev_attr.attr,
+ &iio_event_attr_in3_thresh_high_en.dev_attr.attr,
+ &iio_event_attr_in3_thresh_low_en.dev_attr.attr,
+ &iio_event_attr_in0min1_thresh_high_en.dev_attr.attr,
+ &iio_event_attr_in0min1_thresh_low_en.dev_attr.attr,
+ &iio_event_attr_in3min2_thresh_high_en.dev_attr.attr,
+ &iio_event_attr_in3min2_thresh_low_en.dev_attr.attr,
+ &iio_event_attr_in1min0_thresh_high_en.dev_attr.attr,
+ &iio_event_attr_in1min0_thresh_low_en.dev_attr.attr,
+ &iio_event_attr_in2min3_thresh_high_en.dev_attr.attr,
+ &iio_event_attr_in2min3_thresh_low_en.dev_attr.attr,
+ NULL,
+};
+
+static struct attribute_group max1363_event_attribute_group = {
+ .attrs = max1363_event_attributes,
+};
+
static int max1363_initial_setup(struct max1363_state *st)
{
st->setupbyte = MAX1363_SETUP_AIN3_IS_AIN3_REF_IS_VDD
@@ -930,19 +1599,7 @@ static int __devinit max1363_probe(struct i2c_client *client,
atomic_set(&st->protect_ring, 0);
- /* Find the chip model specific data */
- for (i = 0; i < ARRAY_SIZE(max1363_chip_info_tbl); i++)
- if (!strcmp(max1363_chip_info_tbl[i].name, id->name)) {
- st->chip_info = &max1363_chip_info_tbl[i];
- break;
- };
- /* Unsupported chip */
- if (!st->chip_info) {
- dev_err(&client->dev, "%s is not supported\n", id->name);
- ret = -ENODEV;
- goto error_free_st;
- }
-
+ st->chip_info = &max1363_chip_info_tbl[id->driver_data];
st->reg = regulator_get(&client->dev, "vcc");
if (!IS_ERR(st->reg)) {
ret = regulator_enable(st->reg);
@@ -978,6 +1635,11 @@ static int __devinit max1363_probe(struct i2c_client *client,
st->indio_dev->dev_data = (void *)(st);
st->indio_dev->driver_module = THIS_MODULE;
st->indio_dev->modes = INDIO_DIRECT_MODE;
+ if (st->chip_info->monitor_mode && client->irq) {
+ st->indio_dev->num_interrupt_lines = 1;
+ st->indio_dev->event_attrs
+ = &max1363_event_attribute_group;
+ }
ret = max1363_initial_setup(st);
if (ret)
@@ -991,10 +1653,25 @@ static int __devinit max1363_probe(struct i2c_client *client,
if (ret)
goto error_cleanup_ring;
regdone = 1;
- ret = max1363_initialize_ring(st->indio_dev->ring);
+ ret = iio_ring_buffer_register(st->indio_dev->ring, 0);
if (ret)
goto error_cleanup_ring;
+
+ if (st->chip_info->monitor_mode && client->irq) {
+ ret = iio_register_interrupt_line(client->irq,
+ st->indio_dev,
+ 0,
+ IRQF_TRIGGER_RISING,
+ client->name);
+ if (ret)
+ goto error_uninit_ring;
+
+ INIT_WORK(&st->thresh_work, max1363_thresh_handler_bh);
+ }
+
return 0;
+error_uninit_ring:
+ iio_ring_buffer_unregister(st->indio_dev->ring);
error_cleanup_ring:
max1363_ring_cleanup(st->indio_dev);
error_free_available_scan_masks:
@@ -1010,7 +1687,6 @@ error_disable_reg:
error_put_reg:
if (!IS_ERR(st->reg))
regulator_put(st->reg);
-error_free_st:
kfree(st);
error_ret:
@@ -1021,7 +1697,10 @@ static int max1363_remove(struct i2c_client *client)
{
struct max1363_state *st = i2c_get_clientdata(client);
struct iio_dev *indio_dev = st->indio_dev;
- max1363_uninitialize_ring(indio_dev->ring);
+
+ if (st->chip_info->monitor_mode && client->irq)
+ iio_unregister_interrupt_line(st->indio_dev, 0);
+ iio_ring_buffer_unregister(indio_dev->ring);
max1363_ring_cleanup(indio_dev);
kfree(st->indio_dev->available_scan_masks);
iio_device_unregister(indio_dev);
diff --git a/drivers/staging/iio/adc/max1363_ring.c b/drivers/staging/iio/adc/max1363_ring.c
index 56688dc9c92..786b17a0d6b 100644
--- a/drivers/staging/iio/adc/max1363_ring.c
+++ b/drivers/staging/iio/adc/max1363_ring.c
@@ -68,7 +68,7 @@ error_ret:
}
/**
- * max1363_ring_preenable() setup the parameters of the ring before enabling
+ * max1363_ring_preenable() - setup the parameters of the ring before enabling
*
* The complex nature of the setting of the nuber of bytes per datum is due
* to this driver currently ensuring that the timestamp is stored at an 8
@@ -105,44 +105,15 @@ static int max1363_ring_preenable(struct iio_dev *indio_dev)
return 0;
}
-/**
- * max1363_ring_postenable() typical ring post enable
- *
- * Only not moved into the core for the hardware ring buffer cases
- * that are more sophisticated.
- **/
-static int max1363_ring_postenable(struct iio_dev *indio_dev)
-{
- if (indio_dev->trig == NULL)
- return 0;
- return iio_trigger_attach_poll_func(indio_dev->trig,
- indio_dev->pollfunc);
-}
/**
- * max1363_ring_predisable() runs just prior to ring buffer being disabled
- *
- * Typical predisable function which ensures that no trigger events can
- * occur before we disable the ring buffer (and hence would have no idea
- * what to do with them)
- **/
-static int max1363_ring_predisable(struct iio_dev *indio_dev)
-{
- if (indio_dev->trig)
- return iio_trigger_dettach_poll_func(indio_dev->trig,
- indio_dev->pollfunc);
- else
- return 0;
-}
-
-/**
- * max1363_poll_func_th() th of trigger launched polling to ring buffer
+ * max1363_poll_func_th() - th of trigger launched polling to ring buffer
*
* As sampling only occurs on i2c comms occuring, leave timestamping until
* then. Some triggers will generate their own time stamp. Currently
* there is no way of notifying them when no one cares.
**/
-static void max1363_poll_func_th(struct iio_dev *indio_dev)
+static void max1363_poll_func_th(struct iio_dev *indio_dev, s64 time)
{
struct max1363_state *st = indio_dev->dev_data;
@@ -151,7 +122,7 @@ static void max1363_poll_func_th(struct iio_dev *indio_dev)
return;
}
/**
- * max1363_poll_bh_to_ring() bh of trigger launched polling to ring buffer
+ * max1363_poll_bh_to_ring() - bh of trigger launched polling to ring buffer
* @work_s: the work struct through which this was scheduled
*
* Currently there is no option in this driver to disable the saving of
@@ -223,19 +194,14 @@ int max1363_register_ring_funcs_and_init(struct iio_dev *indio_dev)
}
/* Effectively select the ring buffer implementation */
iio_ring_sw_register_funcs(&st->indio_dev->ring->access);
- indio_dev->pollfunc = kzalloc(sizeof(*indio_dev->pollfunc), GFP_KERNEL);
- if (indio_dev->pollfunc == NULL) {
- ret = -ENOMEM;
+ ret = iio_alloc_pollfunc(indio_dev, NULL, &max1363_poll_func_th);
+ if (ret)
goto error_deallocate_sw_rb;
- }
- /* Configure the polling function called on trigger interrupts */
- indio_dev->pollfunc->poll_func_main = &max1363_poll_func_th;
- indio_dev->pollfunc->private_data = indio_dev;
/* Ring buffer functions - here trigger setup related */
- indio_dev->ring->postenable = &max1363_ring_postenable;
+ indio_dev->ring->postenable = &iio_triggered_ring_postenable;
indio_dev->ring->preenable = &max1363_ring_preenable;
- indio_dev->ring->predisable = &max1363_ring_predisable;
+ indio_dev->ring->predisable = &iio_triggered_ring_predisable;
INIT_WORK(&st->poll_work, &max1363_poll_bh_to_ring);
/* Flag that polled ring buffering is possible */
@@ -258,13 +224,3 @@ void max1363_ring_cleanup(struct iio_dev *indio_dev)
kfree(indio_dev->pollfunc);
iio_sw_rb_free(indio_dev->ring);
}
-
-void max1363_uninitialize_ring(struct iio_ring_buffer *ring)
-{
- iio_ring_buffer_unregister(ring);
-};
-
-int max1363_initialize_ring(struct iio_ring_buffer *ring)
-{
- return iio_ring_buffer_register(ring, 0);
-};
diff --git a/drivers/staging/iio/chrdev.h b/drivers/staging/iio/chrdev.h
index 3f96f8696a4..fd23bd1ea7b 100644
--- a/drivers/staging/iio/chrdev.h
+++ b/drivers/staging/iio/chrdev.h
@@ -73,8 +73,6 @@ struct iio_shared_ev_pointer {
* @det_events: list of detected events
* @max_events: maximum number of events before new ones are dropped
* @current_events: number of events in detected list
- * @id: indentifier to allow the event interface to know which
- * physical line it corresponds to
* @attr: this chrdev's minor number sysfs attribute
* @owner: ensure the driver module owns the file, not iio
* @private: driver specific data
@@ -90,7 +88,6 @@ struct iio_event_interface {
struct iio_detected_event_list det_events;
int max_events;
int current_events;
- int id;
struct iio_chrdev_minor_attr attr;
struct module *owner;
void *private;
diff --git a/drivers/staging/iio/gyro/Makefile b/drivers/staging/iio/gyro/Makefile
index 6d2c547686c..b5f0dc01122 100644
--- a/drivers/staging/iio/gyro/Makefile
+++ b/drivers/staging/iio/gyro/Makefile
@@ -1,4 +1,4 @@
-
+#
# Makefile for digital gyroscope sensor drivers
#
diff --git a/drivers/staging/iio/gyro/adis16260.h b/drivers/staging/iio/gyro/adis16260.h
index f19efb4c91c..812440af57d 100644
--- a/drivers/staging/iio/gyro/adis16260.h
+++ b/drivers/staging/iio/gyro/adis16260.h
@@ -85,7 +85,6 @@
* struct adis16260_state - device instance specific data
* @us: actual spi_device
* @work_trigger_to_ring: bh for triggered event handling
- * @work_cont_thresh: CLEAN
* @inter: used to check if new interrupt has been triggered
* @last_timestamp: passing timestamp from th to bh of interrupt handler
* @indio_dev: industrial I/O device structure
@@ -97,7 +96,6 @@
struct adis16260_state {
struct spi_device *us;
struct work_struct work_trigger_to_ring;
- struct iio_work_cont work_cont_thresh;
s64 last_timestamp;
struct iio_dev *indio_dev;
struct iio_trigger *trig;
@@ -113,13 +111,11 @@ int adis16260_set_irq(struct device *dev, bool enable);
* filling. This may change!
*/
-enum adis16260_scan {
- ADIS16260_SCAN_SUPPLY,
- ADIS16260_SCAN_GYRO,
- ADIS16260_SCAN_AUX_ADC,
- ADIS16260_SCAN_TEMP,
- ADIS16260_SCAN_ANGL,
-};
+#define ADIS16260_SCAN_SUPPLY 0
+#define ADIS16260_SCAN_GYRO 1
+#define ADIS16260_SCAN_AUX_ADC 2
+#define ADIS16260_SCAN_TEMP 3
+#define ADIS16260_SCAN_ANGL 4
void adis16260_remove_trigger(struct iio_dev *indio_dev);
int adis16260_probe_trigger(struct iio_dev *indio_dev);
@@ -132,8 +128,6 @@ ssize_t adis16260_read_data_from_ring(struct device *dev,
int adis16260_configure_ring(struct iio_dev *indio_dev);
void adis16260_unconfigure_ring(struct iio_dev *indio_dev);
-int adis16260_initialize_ring(struct iio_ring_buffer *ring);
-void adis16260_uninitialize_ring(struct iio_ring_buffer *ring);
#else /* CONFIG_IIO_RING_BUFFER */
static inline void adis16260_remove_trigger(struct iio_dev *indio_dev)
@@ -162,14 +156,5 @@ static inline void adis16260_unconfigure_ring(struct iio_dev *indio_dev)
{
}
-static inline int adis16260_initialize_ring(struct iio_ring_buffer *ring)
-{
- return 0;
-}
-
-static inline void adis16260_uninitialize_ring(struct iio_ring_buffer *ring)
-{
-}
-
#endif /* CONFIG_IIO_RING_BUFFER */
#endif /* SPI_ADIS16260_H_ */
diff --git a/drivers/staging/iio/gyro/adis16260_core.c b/drivers/staging/iio/gyro/adis16260_core.c
index c93f4d580fc..134dfaae2f0 100644
--- a/drivers/staging/iio/gyro/adis16260_core.c
+++ b/drivers/staging/iio/gyro/adis16260_core.c
@@ -14,12 +14,13 @@
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/spi/spi.h>
-
+#include <linux/slab.h>
#include <linux/sysfs.h>
#include <linux/list.h>
#include "../iio.h"
#include "../sysfs.h"
+#include "../ring_generic.h"
#include "../adc/adc.h"
#include "gyro.h"
@@ -555,8 +556,7 @@ static int __devinit adis16260_probe(struct spi_device *spi)
if (ret)
goto error_unreg_ring_funcs;
regdone = 1;
-
- ret = adis16260_initialize_ring(st->indio_dev->ring);
+ ret = iio_ring_buffer_register(st->indio_dev->ring, 0);
if (ret) {
printk(KERN_ERR "failed to initialize the ring\n");
goto error_unreg_ring_funcs;
@@ -588,7 +588,7 @@ error_unregister_line:
if (spi->irq)
iio_unregister_interrupt_line(st->indio_dev, 0);
error_uninitialize_ring:
- adis16260_uninitialize_ring(st->indio_dev->ring);
+ iio_ring_buffer_unregister(st->indio_dev->ring);
error_unreg_ring_funcs:
adis16260_unconfigure_ring(st->indio_dev);
error_free_dev:
@@ -622,15 +622,13 @@ static int adis16260_remove(struct spi_device *spi)
if (spi->irq)
iio_unregister_interrupt_line(indio_dev, 0);
- adis16260_uninitialize_ring(indio_dev->ring);
+ iio_ring_buffer_unregister(st->indio_dev->ring);
iio_device_unregister(indio_dev);
adis16260_unconfigure_ring(indio_dev);
kfree(st->tx);
kfree(st->rx);
kfree(st);
- return 0;
-
err_ret:
return ret;
}
diff --git a/drivers/staging/iio/gyro/adis16260_ring.c b/drivers/staging/iio/gyro/adis16260_ring.c
index 4c4390ca6d7..9ef7f9080dc 100644
--- a/drivers/staging/iio/gyro/adis16260_ring.c
+++ b/drivers/staging/iio/gyro/adis16260_ring.c
@@ -6,6 +6,7 @@
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/spi/spi.h>
+#include <linux/slab.h>
#include <linux/sysfs.h>
#include <linux/list.h>
@@ -16,16 +17,6 @@
#include "../trigger.h"
#include "adis16260.h"
-/**
- * combine_8_to_16() utility function to munge to u8s into u16
- **/
-static inline u16 combine_8_to_16(u8 lower, u8 upper)
-{
- u16 _lower = lower;
- u16 _upper = upper;
- return _lower | (_upper << 8);
-}
-
static IIO_SCAN_EL_C(supply, ADIS16260_SCAN_SUPPLY, IIO_UNSIGNED(12),
ADIS16260_SUPPLY_OUT, NULL);
static IIO_SCAN_EL_C(gyro, ADIS16260_SCAN_GYRO, IIO_SIGNED(14),
@@ -58,10 +49,10 @@ static struct attribute_group adis16260_scan_el_group = {
* adis16260_poll_func_th() top half interrupt handler called by trigger
* @private_data: iio_dev
**/
-static void adis16260_poll_func_th(struct iio_dev *indio_dev)
+static void adis16260_poll_func_th(struct iio_dev *indio_dev, s64 time)
{
struct adis16260_state *st = iio_dev_get_devdata(indio_dev);
- st->last_timestamp = indio_dev->trig->timestamp;
+ st->last_timestamp = time;
schedule_work(&st->work_trigger_to_ring);
}
@@ -133,10 +124,9 @@ static void adis16260_trigger_bh_to_ring(struct work_struct *work_s)
if (st->indio_dev->scan_count)
if (adis16260_read_ring_data(&st->indio_dev->dev, st->rx) >= 0)
- for (; i < st->indio_dev->scan_count; i++) {
- data[i] = combine_8_to_16(st->rx[i*2+1],
- st->rx[i*2]);
- }
+ for (; i < st->indio_dev->scan_count; i++)
+ data[i] = be16_to_cpup(
+ (__be16 *)&(st->rx[i*2]));
/* Guaranteed to be aligned with 8 byte boundary */
if (st->indio_dev->scan_timestamp)
@@ -152,48 +142,6 @@ static void adis16260_trigger_bh_to_ring(struct work_struct *work_s)
return;
}
-static int adis16260_data_rdy_ring_preenable(struct iio_dev *indio_dev)
-{
- size_t size;
- dev_dbg(&indio_dev->dev, "%s\n", __func__);
- /* Check if there are any scan elements enabled, if not fail*/
- if (!(indio_dev->scan_count || indio_dev->scan_timestamp))
- return -EINVAL;
-
- if (indio_dev->ring->access.set_bpd) {
- if (indio_dev->scan_timestamp)
- if (indio_dev->scan_count)
- /* Timestamp (aligned s64) and data */
- size = (((indio_dev->scan_count * sizeof(s16))
- + sizeof(s64) - 1)
- & ~(sizeof(s64) - 1))
- + sizeof(s64);
- else /* Timestamp only */
- size = sizeof(s64);
- else /* Data only */
- size = indio_dev->scan_count*sizeof(s16);
- indio_dev->ring->access.set_bpd(indio_dev->ring, size);
- }
-
- return 0;
-}
-
-static int adis16260_data_rdy_ring_postenable(struct iio_dev *indio_dev)
-{
- return indio_dev->trig
- ? iio_trigger_attach_poll_func(indio_dev->trig,
- indio_dev->pollfunc)
- : 0;
-}
-
-static int adis16260_data_rdy_ring_predisable(struct iio_dev *indio_dev)
-{
- return indio_dev->trig
- ? iio_trigger_dettach_poll_func(indio_dev->trig,
- indio_dev->pollfunc)
- : 0;
-}
-
void adis16260_unconfigure_ring(struct iio_dev *indio_dev)
{
kfree(indio_dev->pollfunc);
@@ -225,18 +173,16 @@ int adis16260_configure_ring(struct iio_dev *indio_dev)
indio_dev->ring = ring;
/* Effectively select the ring buffer implementation */
iio_ring_sw_register_funcs(&ring->access);
- ring->preenable = &adis16260_data_rdy_ring_preenable;
- ring->postenable = &adis16260_data_rdy_ring_postenable;
- ring->predisable = &adis16260_data_rdy_ring_predisable;
+ ring->bpe = 2;
+ ring->preenable = &iio_sw_ring_preenable;
+ ring->postenable = &iio_triggered_ring_postenable;
+ ring->predisable = &iio_triggered_ring_predisable;
ring->owner = THIS_MODULE;
- indio_dev->pollfunc = kzalloc(sizeof(*indio_dev->pollfunc), GFP_KERNEL);
- if (indio_dev->pollfunc == NULL) {
- ret = -ENOMEM;
- goto error_iio_sw_rb_free;;
- }
- indio_dev->pollfunc->poll_func_main = &adis16260_poll_func_th;
- indio_dev->pollfunc->private_data = indio_dev;
+ ret = iio_alloc_pollfunc(indio_dev, NULL, &adis16260_poll_func_th);
+ if (ret)
+ goto error_iio_sw_rb_free;
+
indio_dev->modes |= INDIO_RING_TRIGGERED;
return 0;
@@ -244,13 +190,3 @@ error_iio_sw_rb_free:
iio_sw_rb_free(indio_dev->ring);
return ret;
}
-
-int adis16260_initialize_ring(struct iio_ring_buffer *ring)
-{
- return iio_ring_buffer_register(ring, 0);
-}
-
-void adis16260_uninitialize_ring(struct iio_ring_buffer *ring)
-{
- iio_ring_buffer_unregister(ring);
-}
diff --git a/drivers/staging/iio/gyro/adis16260_trigger.c b/drivers/staging/iio/gyro/adis16260_trigger.c
index b3c565942b8..de01537d257 100644
--- a/drivers/staging/iio/gyro/adis16260_trigger.c
+++ b/drivers/staging/iio/gyro/adis16260_trigger.c
@@ -23,8 +23,7 @@ static int adis16260_data_rdy_trig_poll(struct iio_dev *dev_info,
struct adis16260_state *st = iio_dev_get_devdata(dev_info);
struct iio_trigger *trig = st->trig;
- trig->timestamp = timestamp;
- iio_trigger_poll(trig);
+ iio_trigger_poll(trig, timestamp);
return IRQ_HANDLED;
}
@@ -83,14 +82,13 @@ int adis16260_probe_trigger(struct iio_dev *indio_dev)
struct adis16260_state *st = indio_dev->dev_data;
st->trig = iio_allocate_trigger();
- st->trig->name = kmalloc(IIO_TRIGGER_NAME_LENGTH, GFP_KERNEL);
+ st->trig->name = kasprintf(GFP_KERNEL,
+ "adis16260-dev%d",
+ indio_dev->id);
if (!st->trig->name) {
ret = -ENOMEM;
goto error_free_trig;
}
- snprintf((char *)st->trig->name,
- IIO_TRIGGER_NAME_LENGTH,
- "adis16260-dev%d", indio_dev->id);
st->trig->dev.parent = &st->us->dev;
st->trig->owner = THIS_MODULE;
st->trig->private_data = st;
diff --git a/drivers/staging/iio/iio.h b/drivers/staging/iio/iio.h
index fcee47cbe89..9d0ca128679 100644
--- a/drivers/staging/iio/iio.h
+++ b/drivers/staging/iio/iio.h
@@ -16,9 +16,7 @@
#include "chrdev.h"
/* IIO TODO LIST */
-/* Static device specific elements (conversion factors etc)
- * should be exported via sysfs
- *
+/*
* Provide means of adjusting timer accuracy.
* Currently assumes nano seconds.
*/
@@ -284,49 +282,6 @@ int iio_push_event(struct iio_dev *dev_info,
s64 timestamp);
/**
- * struct iio_work_cont - container for when singleton handler case matters
- * @ws: [DEVICE] work_struct when not only possible event
- * @ws_nocheck: [DEVICE] work_struct when only possible event
- * @address: [DEVICE] associated register address
- * @mask: [DEVICE] associated mask for identifying event source
- * @st: [DEVICE] device specific state information
- **/
-struct iio_work_cont {
- struct work_struct ws;
- struct work_struct ws_nocheck;
- int address;
- int mask;
- void *st;
-};
-
-#define to_iio_work_cont_check(_ws) \
- container_of(_ws, struct iio_work_cont, ws)
-
-#define to_iio_work_cont_no_check(_ws) \
- container_of(_ws, struct iio_work_cont, ws_nocheck)
-
-/**
- * iio_init_work_cont() - intiialize the elements of a work container
- * @cont: the work container
- * @_checkfunc: function called when there are multiple possible int sources
- * @_nocheckfunc: function for when there is only one int source
- * @_add: driver dependent, typically a register address
- * @_mask: driver dependent, typically a bit mask for a register
- * @_st: driver dependent, typically pointer to a device state structure
- **/
-static inline void
-iio_init_work_cont(struct iio_work_cont *cont,
- void (*_checkfunc)(struct work_struct *),
- void (*_nocheckfunc)(struct work_struct *),
- int _add, int _mask, void *_st)
-{
- INIT_WORK(&(cont)->ws, _checkfunc);
- INIT_WORK(&(cont)->ws_nocheck, _nocheckfunc);
- cont->address = _add;
- cont->mask = _mask;
- cont->st = _st;
-}
-/**
* __iio_push_event() - tries to add an event to the list associated with a chrdev
* @ev_int: the event interface to which we are pushing the event
* @ev_code: the outgoing event code
@@ -428,7 +383,9 @@ void iio_put(void);
**/
void iio_get(void);
-/* Ring buffer related */
+/**
+ * iio_device_get_chrdev_minor() - get an unused minor number
+ **/
int iio_device_get_chrdev_minor(void);
void iio_device_free_chrdev_minor(int val);
diff --git a/drivers/staging/iio/imu/Kconfig b/drivers/staging/iio/imu/Kconfig
index 6308d6faad5..31a6233a206 100644
--- a/drivers/staging/iio/imu/Kconfig
+++ b/drivers/staging/iio/imu/Kconfig
@@ -6,9 +6,8 @@ comment "Inertial measurement units"
config ADIS16300
tristate "Analog Devices ADIS16300 IMU SPI driver"
depends on SPI
- select IIO_SW_RING
- select IIO_RING_BUFFER
- select IIO_TRIGGER
+ select IIO_SW_RING if IIO_RING_BUFFER
+ select IIO_TRIGGER if IIO_RING_BUFFER
help
Say yes here to build support for Analog Devices adis16300 four degrees
of freedom inertial sensor.
@@ -24,10 +23,9 @@ config ADIS16350
config ADIS16400
tristate "Analog Devices ADIS16400/5 IMU SPI driver"
- depends on SPI
- select IIO_SW_RING
- select IIO_RING_BUFFER
- select IIO_TRIGGER
- help
- Say yes here to build support for Analog Devices adis16400/5 triaxial
- inertial sensor with Magnetometer. \ No newline at end of file
+ depends on SPI
+ select IIO_SW_RING if IIO_RING_BUFFER
+ select IIO_TRIGGER if IIO_RING_BUFFER
+ help
+ Say yes here to build support for Analog Devices adis16400/5 triaxial
+ inertial sensor with Magnetometer.
diff --git a/drivers/staging/iio/imu/Makefile b/drivers/staging/iio/imu/Makefile
index 31df7359e20..f3b450b6611 100644
--- a/drivers/staging/iio/imu/Makefile
+++ b/drivers/staging/iio/imu/Makefile
@@ -1,6 +1,7 @@
#
# Makefile for Inertial Measurement Units
#
+
adis16300-y := adis16300_core.o
adis16300-$(CONFIG_IIO_RING_BUFFER) += adis16300_ring.o adis16300_trigger.o
obj-$(CONFIG_ADIS16300) += adis16300.o
@@ -11,4 +12,4 @@ obj-$(CONFIG_ADIS16350) += adis16350.o
adis16400-y := adis16400_core.o
adis16400-$(CONFIG_IIO_RING_BUFFER) += adis16400_ring.o adis16400_trigger.o
-obj-$(CONFIG_ADIS16400) += adis16400.o \ No newline at end of file
+obj-$(CONFIG_ADIS16400) += adis16400.o
diff --git a/drivers/staging/iio/imu/adis16300.h b/drivers/staging/iio/imu/adis16300.h
index 1c7ea5c840e..1f25d68064a 100644
--- a/drivers/staging/iio/imu/adis16300.h
+++ b/drivers/staging/iio/imu/adis16300.h
@@ -94,7 +94,6 @@
* struct adis16300_state - device instance specific data
* @us: actual spi_device
* @work_trigger_to_ring: bh for triggered event handling
- * @work_cont_thresh: CLEAN
* @inter: used to check if new interrupt has been triggered
* @last_timestamp: passing timestamp from th to bh of interrupt handler
* @indio_dev: industrial I/O device structure
@@ -106,7 +105,6 @@
struct adis16300_state {
struct spi_device *us;
struct work_struct work_trigger_to_ring;
- struct iio_work_cont work_cont_thresh;
s64 last_timestamp;
struct iio_dev *indio_dev;
struct iio_trigger *trig;
@@ -115,30 +113,22 @@ struct adis16300_state {
struct mutex buf_lock;
};
-int adis16300_spi_read_burst(struct device *dev, u8 *rx);
-
int adis16300_set_irq(struct device *dev, bool enable);
-int adis16300_reset(struct device *dev);
-
-int adis16300_check_status(struct device *dev);
-
#ifdef CONFIG_IIO_RING_BUFFER
/* At the moment triggers are only used for ring buffer
* filling. This may change!
*/
-enum adis16300_scan {
- ADIS16300_SCAN_SUPPLY,
- ADIS16300_SCAN_GYRO_X,
- ADIS16300_SCAN_ACC_X,
- ADIS16300_SCAN_ACC_Y,
- ADIS16300_SCAN_ACC_Z,
- ADIS16300_SCAN_TEMP,
- ADIS16300_SCAN_ADC_0,
- ADIS16300_SCAN_INCLI_X,
- ADIS16300_SCAN_INCLI_Y,
-};
+#define ADIS16300_SCAN_SUPPLY 0
+#define ADIS16300_SCAN_GYRO_X 1
+#define ADIS16300_SCAN_ACC_X 2
+#define ADIS16300_SCAN_ACC_Y 3
+#define ADIS16300_SCAN_ACC_Z 4
+#define ADIS16300_SCAN_TEMP 5
+#define ADIS16300_SCAN_ADC_0 6
+#define ADIS16300_SCAN_INCLI_X 7
+#define ADIS16300_SCAN_INCLI_Y 8
void adis16300_remove_trigger(struct iio_dev *indio_dev);
int adis16300_probe_trigger(struct iio_dev *indio_dev);
diff --git a/drivers/staging/iio/imu/adis16300_core.c b/drivers/staging/iio/imu/adis16300_core.c
index 5a7e5ef9bc5..f1950d56cb1 100644
--- a/drivers/staging/iio/imu/adis16300_core.c
+++ b/drivers/staging/iio/imu/adis16300_core.c
@@ -14,12 +14,13 @@
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/spi/spi.h>
-
+#include <linux/slab.h>
#include <linux/sysfs.h>
#include <linux/list.h>
#include "../iio.h"
#include "../sysfs.h"
+#include "../ring_generic.h"
#include "../accel/accel.h"
#include "../accel/inclinometer.h"
#include "../gyro/gyro.h"
@@ -29,10 +30,7 @@
#define DRIVER_NAME "adis16300"
-/* At the moment the spi framework doesn't allow global setting of cs_change.
- * It's in the likely to be added comment at the top of spi.h.
- * This means that use cannot be made of spi_write etc.
- */
+static int adis16300_check_status(struct device *dev);
/**
* adis16300_spi_write_reg_8() - write single byte to a register
@@ -79,11 +77,13 @@ static int adis16300_spi_write_reg_16(struct device *dev,
.bits_per_word = 8,
.len = 2,
.cs_change = 1,
+ .delay_usecs = 75,
}, {
.tx_buf = st->tx + 2,
.bits_per_word = 8,
.len = 2,
.cs_change = 1,
+ .delay_usecs = 75,
},
};
@@ -122,12 +122,14 @@ static int adis16300_spi_read_reg_16(struct device *dev,
.tx_buf = st->tx,
.bits_per_word = 8,
.len = 2,
- .cs_change = 0,
+ .cs_change = 1,
+ .delay_usecs = 75,
}, {
.rx_buf = st->rx,
.bits_per_word = 8,
.len = 2,
- .cs_change = 0,
+ .cs_change = 1,
+ .delay_usecs = 75,
},
};
@@ -154,54 +156,6 @@ error_ret:
return ret;
}
-/**
- * adis16300_spi_read_burst() - read all data registers
- * @dev: device associated with child of actual device (iio_dev or iio_trig)
- * @rx: somewhere to pass back the value read (min size is 24 bytes)
- **/
-int adis16300_spi_read_burst(struct device *dev, u8 *rx)
-{
- struct spi_message msg;
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
- struct adis16300_state *st = iio_dev_get_devdata(indio_dev);
- u32 old_speed_hz = st->us->max_speed_hz;
- int ret;
-
- struct spi_transfer xfers[] = {
- {
- .tx_buf = st->tx,
- .bits_per_word = 8,
- .len = 2,
- .cs_change = 0,
- }, {
- .rx_buf = rx,
- .bits_per_word = 8,
- .len = 18,
- .cs_change = 0,
- },
- };
-
- mutex_lock(&st->buf_lock);
- st->tx[0] = ADIS16300_READ_REG(ADIS16300_GLOB_CMD);
- st->tx[1] = 0;
-
- spi_message_init(&msg);
- spi_message_add_tail(&xfers[0], &msg);
- spi_message_add_tail(&xfers[1], &msg);
-
- st->us->max_speed_hz = min(ADIS16300_SPI_BURST, old_speed_hz);
- spi_setup(st->us);
-
- ret = spi_sync(st->us, &msg);
- if (ret)
- dev_err(&st->us->dev, "problem when burst reading");
-
- st->us->max_speed_hz = old_speed_hz;
- spi_setup(st->us);
- mutex_unlock(&st->buf_lock);
- return ret;
-}
-
static ssize_t adis16300_spi_read_signed(struct device *dev,
struct device_attribute *attr,
char *buf,
@@ -240,6 +194,24 @@ static ssize_t adis16300_read_12bit_unsigned(struct device *dev,
return sprintf(buf, "%u\n", val & 0x0FFF);
}
+static ssize_t adis16300_read_14bit_unsigned(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ int ret;
+ u16 val = 0;
+ struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
+
+ ret = adis16300_spi_read_reg_16(dev, this_attr->address, &val);
+ if (ret)
+ return ret;
+
+ if (val & ADIS16300_ERROR_ACTIVE)
+ adis16300_check_status(dev);
+
+ return sprintf(buf, "%u\n", val & 0x3FFF);
+}
+
static ssize_t adis16300_read_14bit_signed(struct device *dev,
struct device_attribute *attr,
char *buf)
@@ -356,6 +328,18 @@ static ssize_t adis16300_write_frequency(struct device *dev,
return ret ? ret : len;
}
+static int adis16300_reset(struct device *dev)
+{
+ int ret;
+ ret = adis16300_spi_write_reg_8(dev,
+ ADIS16300_GLOB_CMD,
+ ADIS16300_GLOB_CMD_SW_RESET);
+ if (ret)
+ dev_err(dev, "problem resetting device");
+
+ return ret;
+}
+
static ssize_t adis16300_write_reset(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t len)
@@ -371,8 +355,6 @@ static ssize_t adis16300_write_reset(struct device *dev,
return -1;
}
-
-
int adis16300_set_irq(struct device *dev, bool enable)
{
int ret;
@@ -396,32 +378,37 @@ error_ret:
return ret;
}
-int adis16300_reset(struct device *dev)
+/* Power down the device */
+static int adis16300_stop_device(struct device *dev)
{
int ret;
- ret = adis16300_spi_write_reg_8(dev,
- ADIS16300_GLOB_CMD,
- ADIS16300_GLOB_CMD_SW_RESET);
+ u16 val = ADIS16300_SLP_CNT_POWER_OFF;
+
+ ret = adis16300_spi_write_reg_16(dev, ADIS16300_SLP_CNT, val);
if (ret)
- dev_err(dev, "problem resetting device");
+ dev_err(dev, "problem with turning device off: SLP_CNT");
return ret;
}
-/* Power down the device */
-static int adis16300_stop_device(struct device *dev)
+static int adis16300_self_test(struct device *dev)
{
int ret;
- u16 val = ADIS16300_SLP_CNT_POWER_OFF;
+ ret = adis16300_spi_write_reg_16(dev,
+ ADIS16300_MSC_CTRL,
+ ADIS16300_MSC_CTRL_MEM_TEST);
+ if (ret) {
+ dev_err(dev, "problem starting self test");
+ goto err_ret;
+ }
- ret = adis16300_spi_write_reg_16(dev, ADIS16300_SLP_CNT, val);
- if (ret)
- dev_err(dev, "problem with turning device off: SLP_CNT");
+ adis16300_check_status(dev);
+err_ret:
return ret;
}
-int adis16300_check_status(struct device *dev)
+static int adis16300_check_status(struct device *dev)
{
u16 status;
int ret;
@@ -483,6 +470,11 @@ static int adis16300_initial_setup(struct adis16300_state *st)
}
/* Do self test */
+ ret = adis16300_self_test(dev);
+ if (ret) {
+ dev_err(dev, "self test failure");
+ goto err_ret;
+ }
/* Read status register to check the result */
ret = adis16300_check_status(dev);
@@ -526,7 +518,7 @@ static IIO_DEV_ATTR_ACCEL_Z_OFFSET(S_IWUSR | S_IRUGO,
adis16300_write_16bit,
ADIS16300_ZACCL_OFF);
-static IIO_DEV_ATTR_IN_NAMED_RAW(supply, adis16300_read_14bit_signed,
+static IIO_DEV_ATTR_IN_NAMED_RAW(supply, adis16300_read_14bit_unsigned,
ADIS16300_SUPPLY_OUT);
static IIO_CONST_ATTR(in_supply_scale, "0.00242");
@@ -548,7 +540,7 @@ static IIO_DEV_ATTR_INCLI_Y(adis16300_read_13bit_signed,
ADIS16300_YINCLI_OUT);
static IIO_CONST_ATTR(incli_scale, "0.044 d");
-static IIO_DEV_ATTR_TEMP_RAW(adis16300_read_12bit_signed);
+static IIO_DEV_ATTR_TEMP_RAW(adis16300_read_12bit_unsigned);
static IIO_CONST_ATTR(temp_offset, "198.16 K");
static IIO_CONST_ATTR(temp_scale, "0.14 K");
@@ -653,21 +645,13 @@ static int __devinit adis16300_probe(struct spi_device *spi)
goto error_unreg_ring_funcs;
regdone = 1;
- ret = adis16300_initialize_ring(st->indio_dev->ring);
+ ret = iio_ring_buffer_register(st->indio_dev->ring, 0);
if (ret) {
printk(KERN_ERR "failed to initialize the ring\n");
goto error_unreg_ring_funcs;
}
- if (spi->irq && gpio_is_valid(irq_to_gpio(spi->irq)) > 0) {
-#if 0 /* fixme: here we should support */
- iio_init_work_cont(&st->work_cont_thresh,
- NULL,
- adis16300_thresh_handler_bh_no_check,
- 0,
- 0,
- st);
-#endif
+ if (spi->irq) {
ret = iio_register_interrupt_line(spi->irq,
st->indio_dev,
0,
@@ -688,13 +672,12 @@ static int __devinit adis16300_probe(struct spi_device *spi)
return 0;
error_remove_trigger:
- if (st->indio_dev->modes & INDIO_RING_TRIGGERED)
- adis16300_remove_trigger(st->indio_dev);
+ adis16300_remove_trigger(st->indio_dev);
error_unregister_line:
- if (st->indio_dev->modes & INDIO_RING_TRIGGERED)
+ if (spi->irq)
iio_unregister_interrupt_line(st->indio_dev, 0);
error_uninitialize_ring:
- adis16300_uninitialize_ring(st->indio_dev->ring);
+ iio_ring_buffer_unregister(st->indio_dev->ring);
error_unreg_ring_funcs:
adis16300_unconfigure_ring(st->indio_dev);
error_free_dev:
@@ -712,7 +695,6 @@ error_ret:
return ret;
}
-/* fixme, confirm ordering in this function */
static int adis16300_remove(struct spi_device *spi)
{
int ret;
@@ -726,12 +708,12 @@ static int adis16300_remove(struct spi_device *spi)
flush_scheduled_work();
adis16300_remove_trigger(indio_dev);
- if (spi->irq && gpio_is_valid(irq_to_gpio(spi->irq)) > 0)
+ if (spi->irq)
iio_unregister_interrupt_line(indio_dev, 0);
- adis16300_uninitialize_ring(indio_dev->ring);
- adis16300_unconfigure_ring(indio_dev);
+ iio_ring_buffer_unregister(indio_dev->ring);
iio_device_unregister(indio_dev);
+ adis16300_unconfigure_ring(indio_dev);
kfree(st->tx);
kfree(st->rx);
kfree(st);
diff --git a/drivers/staging/iio/imu/adis16300_ring.c b/drivers/staging/iio/imu/adis16300_ring.c
index 76cf8a6f3c3..fc93160acb2 100644
--- a/drivers/staging/iio/imu/adis16300_ring.c
+++ b/drivers/staging/iio/imu/adis16300_ring.c
@@ -6,6 +6,7 @@
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/spi/spi.h>
+#include <linux/slab.h>
#include <linux/sysfs.h>
#include <linux/list.h>
@@ -16,17 +17,7 @@
#include "../trigger.h"
#include "adis16300.h"
-/**
- * combine_8_to_16() utility function to munge to u8s into u16
- **/
-static inline u16 combine_8_to_16(u8 lower, u8 upper)
-{
- u16 _lower = lower;
- u16 _upper = upper;
- return _lower | (_upper << 8);
-}
-
-static IIO_SCAN_EL_C(supply, ADIS16300_SCAN_SUPPLY, IIO_SIGNED(14),
+static IIO_SCAN_EL_C(supply, ADIS16300_SCAN_SUPPLY, IIO_UNSIGNED(14),
ADIS16300_SUPPLY_OUT, NULL);
static IIO_SCAN_EL_C(gyro_x, ADIS16300_SCAN_GYRO_X, IIO_SIGNED(14),
@@ -39,9 +30,9 @@ static IIO_SCAN_EL_C(accel_y, ADIS16300_SCAN_ACC_Y, IIO_SIGNED(14),
static IIO_SCAN_EL_C(accel_z, ADIS16300_SCAN_ACC_Z, IIO_SIGNED(14),
ADIS16300_ZACCL_OUT, NULL);
-static IIO_SCAN_EL_C(temp, ADIS16300_SCAN_TEMP, IIO_SIGNED(12),
+static IIO_SCAN_EL_C(temp, ADIS16300_SCAN_TEMP, IIO_UNSIGNED(12),
ADIS16300_TEMP_OUT, NULL);
-static IIO_SCAN_EL_C(adc_0, ADIS16300_SCAN_ADC_0, IIO_SIGNED(12),
+static IIO_SCAN_EL_C(adc_0, ADIS16300_SCAN_ADC_0, IIO_UNSIGNED(12),
ADIS16300_AUX_ADC, NULL);
static IIO_SCAN_EL_C(incli_x, ADIS16300_SCAN_INCLI_X, IIO_SIGNED(12),
@@ -74,10 +65,10 @@ static struct attribute_group adis16300_scan_el_group = {
* adis16300_poll_func_th() top half interrupt handler called by trigger
* @private_data: iio_dev
**/
-static void adis16300_poll_func_th(struct iio_dev *indio_dev)
+static void adis16300_poll_func_th(struct iio_dev *indio_dev, s64 time)
{
struct adis16300_state *st = iio_dev_get_devdata(indio_dev);
- st->last_timestamp = indio_dev->trig->timestamp;
+ st->last_timestamp = time;
schedule_work(&st->work_trigger_to_ring);
/* Indicate that this interrupt is being handled */
@@ -87,6 +78,54 @@ static void adis16300_poll_func_th(struct iio_dev *indio_dev)
*/
}
+/**
+ * adis16300_spi_read_burst() - read all data registers
+ * @dev: device associated with child of actual device (iio_dev or iio_trig)
+ * @rx: somewhere to pass back the value read (min size is 24 bytes)
+ **/
+static int adis16300_spi_read_burst(struct device *dev, u8 *rx)
+{
+ struct spi_message msg;
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct adis16300_state *st = iio_dev_get_devdata(indio_dev);
+ u32 old_speed_hz = st->us->max_speed_hz;
+ int ret;
+
+ struct spi_transfer xfers[] = {
+ {
+ .tx_buf = st->tx,
+ .bits_per_word = 8,
+ .len = 2,
+ .cs_change = 0,
+ }, {
+ .rx_buf = rx,
+ .bits_per_word = 8,
+ .len = 18,
+ .cs_change = 0,
+ },
+ };
+
+ mutex_lock(&st->buf_lock);
+ st->tx[0] = ADIS16300_READ_REG(ADIS16300_GLOB_CMD);
+ st->tx[1] = 0;
+
+ spi_message_init(&msg);
+ spi_message_add_tail(&xfers[0], &msg);
+ spi_message_add_tail(&xfers[1], &msg);
+
+ st->us->max_speed_hz = ADIS16300_SPI_BURST;
+ spi_setup(st->us);
+
+ ret = spi_sync(st->us, &msg);
+ if (ret)
+ dev_err(&st->us->dev, "problem when burst reading");
+
+ st->us->max_speed_hz = old_speed_hz;
+ spi_setup(st->us);
+ mutex_unlock(&st->buf_lock);
+ return ret;
+}
+
/* Whilst this makes a lot of calls to iio_sw_ring functions - it is to device
* specific to be rolled into the core.
*/
@@ -109,10 +148,9 @@ static void adis16300_trigger_bh_to_ring(struct work_struct *work_s)
if (st->indio_dev->scan_count)
if (adis16300_spi_read_burst(&st->indio_dev->dev, st->rx) >= 0)
- for (; i < st->indio_dev->scan_count; i++) {
- data[i] = combine_8_to_16(st->rx[i*2+1],
- st->rx[i*2]);
- }
+ for (; i < st->indio_dev->scan_count; i++)
+ data[i] = be16_to_cpup(
+ (__be16 *)&(st->rx[i*2]));
/* Guaranteed to be aligned with 8 byte boundary */
if (st->indio_dev->scan_timestamp)
@@ -127,45 +165,6 @@ static void adis16300_trigger_bh_to_ring(struct work_struct *work_s)
return;
}
-/* in these circumstances is it better to go with unaligned packing and
- * deal with the cost?*/
-static int adis16300_data_rdy_ring_preenable(struct iio_dev *indio_dev)
-{
- size_t size;
- dev_dbg(&indio_dev->dev, "%s\n", __func__);
- /* Check if there are any scan elements enabled, if not fail*/
- if (!(indio_dev->scan_count || indio_dev->scan_timestamp))
- return -EINVAL;
-
- if (indio_dev->ring->access.set_bpd) {
- if (indio_dev->scan_timestamp)
- if (indio_dev->scan_count) /* Timestamp and data */
- size = 4*sizeof(s64);
- else /* Timestamp only */
- size = sizeof(s64);
- else /* Data only */
- size = indio_dev->scan_count*sizeof(s16);
- indio_dev->ring->access.set_bpd(indio_dev->ring, size);
- }
-
- return 0;
-}
-
-static int adis16300_data_rdy_ring_postenable(struct iio_dev *indio_dev)
-{
- return indio_dev->trig
- ? iio_trigger_attach_poll_func(indio_dev->trig,
- indio_dev->pollfunc)
- : 0;
-}
-
-static int adis16300_data_rdy_ring_predisable(struct iio_dev *indio_dev)
-{
- return indio_dev->trig
- ? iio_trigger_dettach_poll_func(indio_dev->trig,
- indio_dev->pollfunc)
- : 0;
-}
void adis16300_unconfigure_ring(struct iio_dev *indio_dev)
{
@@ -202,18 +201,16 @@ int adis16300_configure_ring(struct iio_dev *indio_dev)
indio_dev->ring = ring;
/* Effectively select the ring buffer implementation */
iio_ring_sw_register_funcs(&ring->access);
- ring->preenable = &adis16300_data_rdy_ring_preenable;
- ring->postenable = &adis16300_data_rdy_ring_postenable;
- ring->predisable = &adis16300_data_rdy_ring_predisable;
+ ring->bpe = 2;
+ ring->preenable = &iio_sw_ring_preenable;
+ ring->postenable = &iio_triggered_ring_postenable;
+ ring->predisable = &iio_triggered_ring_predisable;
ring->owner = THIS_MODULE;
- indio_dev->pollfunc = kzalloc(sizeof(*indio_dev->pollfunc), GFP_KERNEL);
- if (indio_dev->pollfunc == NULL) {
- ret = -ENOMEM;
- goto error_iio_sw_rb_free;;
- }
- indio_dev->pollfunc->poll_func_main = &adis16300_poll_func_th;
- indio_dev->pollfunc->private_data = indio_dev;
+ ret = iio_alloc_pollfunc(indio_dev, NULL, &adis16300_poll_func_th);
+ if (ret)
+ goto error_iio_sw_rb_free;
+
indio_dev->modes |= INDIO_RING_TRIGGERED;
return 0;
@@ -222,12 +219,3 @@ error_iio_sw_rb_free:
return ret;
}
-int adis16300_initialize_ring(struct iio_ring_buffer *ring)
-{
- return iio_ring_buffer_register(ring, 0);
-}
-
-void adis16300_uninitialize_ring(struct iio_ring_buffer *ring)
-{
- iio_ring_buffer_unregister(ring);
-}
diff --git a/drivers/staging/iio/imu/adis16300_trigger.c b/drivers/staging/iio/imu/adis16300_trigger.c
index 54edb20bf11..64036cd9910 100644
--- a/drivers/staging/iio/imu/adis16300_trigger.c
+++ b/drivers/staging/iio/imu/adis16300_trigger.c
@@ -23,8 +23,7 @@ static int adis16300_data_rdy_trig_poll(struct iio_dev *dev_info,
struct adis16300_state *st = iio_dev_get_devdata(dev_info);
struct iio_trigger *trig = st->trig;
- trig->timestamp = timestamp;
- iio_trigger_poll(trig);
+ iio_trigger_poll(trig, timestamp);
return IRQ_HANDLED;
}
@@ -86,14 +85,13 @@ int adis16300_probe_trigger(struct iio_dev *indio_dev)
struct adis16300_state *st = indio_dev->dev_data;
st->trig = iio_allocate_trigger();
- st->trig->name = kmalloc(IIO_TRIGGER_NAME_LENGTH, GFP_KERNEL);
+ st->trig->name = kasprintf(GFP_KERNEL,
+ "adis16300-dev%d",
+ indio_dev->id);
if (!st->trig->name) {
ret = -ENOMEM;
goto error_free_trig;
}
- snprintf((char *)st->trig->name,
- IIO_TRIGGER_NAME_LENGTH,
- "adis16300-dev%d", indio_dev->id);
st->trig->dev.parent = &st->us->dev;
st->trig->owner = THIS_MODULE;
st->trig->private_data = st;
diff --git a/drivers/staging/iio/imu/adis16350.h b/drivers/staging/iio/imu/adis16350.h
index 334b18ace38..b00001e3edd 100644
--- a/drivers/staging/iio/imu/adis16350.h
+++ b/drivers/staging/iio/imu/adis16350.h
@@ -100,7 +100,6 @@
* struct adis16350_state - device instance specific data
* @us: actual spi_device
* @work_trigger_to_ring: bh for triggered event handling
- * @work_cont_thresh: CLEAN
* @inter: used to check if new interrupt has been triggered
* @last_timestamp: passing timestamp from th to bh of interrupt handler
* @indio_dev: industrial I/O device structure
@@ -112,7 +111,6 @@
struct adis16350_state {
struct spi_device *us;
struct work_struct work_trigger_to_ring;
- struct iio_work_cont work_cont_data_rdy;
s64 last_timestamp;
struct iio_dev *indio_dev;
struct iio_trigger *trig;
@@ -125,19 +123,17 @@ int adis16350_set_irq(struct device *dev, bool enable);
#ifdef CONFIG_IIO_RING_BUFFER
-enum adis16350_scan {
- ADIS16350_SCAN_SUPPLY,
- ADIS16350_SCAN_GYRO_X,
- ADIS16350_SCAN_GYRO_Y,
- ADIS16350_SCAN_GYRO_Z,
- ADIS16350_SCAN_ACC_X,
- ADIS16350_SCAN_ACC_Y,
- ADIS16350_SCAN_ACC_Z,
- ADIS16350_SCAN_TEMP_X,
- ADIS16350_SCAN_TEMP_Y,
- ADIS16350_SCAN_TEMP_Z,
- ADIS16350_SCAN_ADC_0
-};
+#define ADIS16350_SCAN_SUPPLY 0
+#define ADIS16350_SCAN_GYRO_X 1
+#define ADIS16350_SCAN_GYRO_Y 2
+#define ADIS16350_SCAN_GYRO_Z 3
+#define ADIS16350_SCAN_ACC_X 4
+#define ADIS16350_SCAN_ACC_Y 5
+#define ADIS16350_SCAN_ACC_Z 6
+#define ADIS16350_SCAN_TEMP_X 7
+#define ADIS16350_SCAN_TEMP_Y 8
+#define ADIS16350_SCAN_TEMP_Z 9
+#define ADIS16350_SCAN_ADC_0 10
void adis16350_remove_trigger(struct iio_dev *indio_dev);
int adis16350_probe_trigger(struct iio_dev *indio_dev);
@@ -150,8 +146,6 @@ ssize_t adis16350_read_data_from_ring(struct device *dev,
int adis16350_configure_ring(struct iio_dev *indio_dev);
void adis16350_unconfigure_ring(struct iio_dev *indio_dev);
-int adis16350_initialize_ring(struct iio_ring_buffer *ring);
-void adis16350_uninitialize_ring(struct iio_ring_buffer *ring);
#else /* CONFIG_IIO_RING_BUFFER */
static inline void adis16350_remove_trigger(struct iio_dev *indio_dev)
@@ -171,7 +165,7 @@ adis16350_read_data_from_ring(struct device *dev,
return 0;
}
-static int adis16350_configure_ring(struct iio_dev *indio_dev)
+static inline int adis16350_configure_ring(struct iio_dev *indio_dev)
{
return 0;
}
@@ -179,15 +173,5 @@ static int adis16350_configure_ring(struct iio_dev *indio_dev)
static inline void adis16350_unconfigure_ring(struct iio_dev *indio_dev)
{
}
-
-static inline int adis16350_initialize_ring(struct iio_ring_buffer *ring)
-{
- return 0;
-}
-
-static inline void adis16350_uninitialize_ring(struct iio_ring_buffer *ring)
-{
-}
-
#endif /* CONFIG_IIO_RING_BUFFER */
#endif /* SPI_ADIS16350_H_ */
diff --git a/drivers/staging/iio/imu/adis16350_core.c b/drivers/staging/iio/imu/adis16350_core.c
index 0edde73ce5c..1575b7b5d44 100644
--- a/drivers/staging/iio/imu/adis16350_core.c
+++ b/drivers/staging/iio/imu/adis16350_core.c
@@ -14,12 +14,13 @@
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/spi/spi.h>
-
+#include <linux/slab.h>
#include <linux/sysfs.h>
#include <linux/list.h>
#include "../iio.h"
#include "../sysfs.h"
+#include "../ring_generic.h"
#include "../accel/accel.h"
#include "../adc/adc.h"
#include "../gyro/gyro.h"
@@ -75,13 +76,13 @@ static int adis16350_spi_write_reg_16(struct device *dev,
.bits_per_word = 8,
.len = 2,
.cs_change = 1,
- .delay_usecs = 25,
+ .delay_usecs = 35,
}, {
.tx_buf = st->tx + 2,
.bits_per_word = 8,
.len = 2,
.cs_change = 1,
- .delay_usecs = 25,
+ .delay_usecs = 35,
},
};
@@ -121,13 +122,13 @@ static int adis16350_spi_read_reg_16(struct device *dev,
.bits_per_word = 8,
.len = 2,
.cs_change = 1,
- .delay_usecs = 25,
+ .delay_usecs = 35,
}, {
.rx_buf = st->rx,
.bits_per_word = 8,
.len = 2,
.cs_change = 1,
- .delay_usecs = 25,
+ .delay_usecs = 35,
},
};
@@ -619,7 +620,7 @@ static int __devinit adis16350_probe(struct spi_device *spi)
goto error_unreg_ring_funcs;
regdone = 1;
- ret = adis16350_initialize_ring(st->indio_dev->ring);
+ ret = iio_ring_buffer_register(st->indio_dev->ring, 0);
if (ret) {
printk(KERN_ERR "failed to initialize the ring\n");
goto error_unreg_ring_funcs;
@@ -651,7 +652,7 @@ error_unregister_line:
if (spi->irq)
iio_unregister_interrupt_line(st->indio_dev, 0);
error_uninitialize_ring:
- adis16350_uninitialize_ring(st->indio_dev->ring);
+ iio_ring_buffer_unregister(st->indio_dev->ring);
error_unreg_ring_funcs:
adis16350_unconfigure_ring(st->indio_dev);
error_free_dev:
@@ -685,7 +686,7 @@ static int adis16350_remove(struct spi_device *spi)
if (spi->irq)
iio_unregister_interrupt_line(indio_dev, 0);
- adis16350_uninitialize_ring(indio_dev->ring);
+ iio_ring_buffer_unregister(indio_dev->ring);
iio_device_unregister(indio_dev);
adis16350_unconfigure_ring(indio_dev);
kfree(st->tx);
diff --git a/drivers/staging/iio/imu/adis16350_ring.c b/drivers/staging/iio/imu/adis16350_ring.c
index 5e9716ea7c7..e053e9aaa2e 100644
--- a/drivers/staging/iio/imu/adis16350_ring.c
+++ b/drivers/staging/iio/imu/adis16350_ring.c
@@ -6,6 +6,7 @@
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/spi/spi.h>
+#include <linux/slab.h>
#include <linux/sysfs.h>
#include <linux/list.h>
@@ -16,16 +17,6 @@
#include "../trigger.h"
#include "adis16350.h"
-/**
- * combine_8_to_16() utility function to munge to u8s into u16
- **/
-static inline u16 combine_8_to_16(u8 lower, u8 upper)
-{
- u16 _lower = lower;
- u16 _upper = upper;
- return _lower | (_upper << 8);
-}
-
static IIO_SCAN_EL_C(supply, ADIS16350_SCAN_SUPPLY, IIO_UNSIGNED(12),
ADIS16350_SUPPLY_OUT, NULL);
@@ -80,10 +71,10 @@ static struct attribute_group adis16350_scan_el_group = {
* adis16350_poll_func_th() top half interrupt handler called by trigger
* @private_data: iio_dev
**/
-static void adis16350_poll_func_th(struct iio_dev *indio_dev)
+static void adis16350_poll_func_th(struct iio_dev *indio_dev, s64 time)
{
struct adis16350_state *st = iio_dev_get_devdata(indio_dev);
- st->last_timestamp = indio_dev->trig->timestamp;
+ st->last_timestamp = time;
schedule_work(&st->work_trigger_to_ring);
}
@@ -157,10 +148,9 @@ static void adis16350_trigger_bh_to_ring(struct work_struct *work_s)
if (st->indio_dev->scan_count)
if (adis16350_spi_read_burst(&st->indio_dev->dev, st->rx) >= 0)
- for (; i < st->indio_dev->scan_count; i++) {
- data[i] = combine_8_to_16(st->rx[i*2+1],
- st->rx[i*2]);
- }
+ for (; i < st->indio_dev->scan_count; i++)
+ data[i] = be16_to_cpup(
+ (__be16 *)&(st->rx[i*2]));
/* Guaranteed to be aligned with 8 byte boundary */
if (st->indio_dev->scan_timestamp)
@@ -176,48 +166,6 @@ static void adis16350_trigger_bh_to_ring(struct work_struct *work_s)
return;
}
-static int adis16350_data_rdy_ring_preenable(struct iio_dev *indio_dev)
-{
- size_t size;
- dev_dbg(&indio_dev->dev, "%s\n", __func__);
- /* Check if there are any scan elements enabled, if not fail*/
- if (!(indio_dev->scan_count || indio_dev->scan_timestamp))
- return -EINVAL;
-
- if (indio_dev->ring->access.set_bpd) {
- if (indio_dev->scan_timestamp)
- if (indio_dev->scan_count)
- /* Timestamp (aligned sizeof(s64) and data */
- size = (((indio_dev->scan_count * sizeof(s16))
- + sizeof(s64) - 1)
- & ~(sizeof(s64) - 1))
- + sizeof(s64);
- else /* Timestamp only */
- size = sizeof(s64);
- else /* Data only */
- size = indio_dev->scan_count*sizeof(s16);
- indio_dev->ring->access.set_bpd(indio_dev->ring, size);
- }
-
- return 0;
-}
-
-static int adis16350_data_rdy_ring_postenable(struct iio_dev *indio_dev)
-{
- return indio_dev->trig
- ? iio_trigger_attach_poll_func(indio_dev->trig,
- indio_dev->pollfunc)
- : 0;
-}
-
-static int adis16350_data_rdy_ring_predisable(struct iio_dev *indio_dev)
-{
- return indio_dev->trig
- ? iio_trigger_dettach_poll_func(indio_dev->trig,
- indio_dev->pollfunc)
- : 0;
-}
-
void adis16350_unconfigure_ring(struct iio_dev *indio_dev)
{
kfree(indio_dev->pollfunc);
@@ -255,18 +203,16 @@ int adis16350_configure_ring(struct iio_dev *indio_dev)
indio_dev->ring = ring;
/* Effectively select the ring buffer implementation */
iio_ring_sw_register_funcs(&ring->access);
- ring->preenable = &adis16350_data_rdy_ring_preenable;
- ring->postenable = &adis16350_data_rdy_ring_postenable;
- ring->predisable = &adis16350_data_rdy_ring_predisable;
+ ring->bpe = 2;
+ ring->preenable = &iio_sw_ring_preenable;
+ ring->postenable = &iio_triggered_ring_postenable;
+ ring->predisable = &iio_triggered_ring_predisable;
ring->owner = THIS_MODULE;
- indio_dev->pollfunc = kzalloc(sizeof(*indio_dev->pollfunc), GFP_KERNEL);
- if (indio_dev->pollfunc == NULL) {
- ret = -ENOMEM;
- goto error_iio_sw_rb_free;;
- }
- indio_dev->pollfunc->poll_func_main = &adis16350_poll_func_th;
- indio_dev->pollfunc->private_data = indio_dev;
+ ret = iio_alloc_pollfunc(indio_dev, NULL, &adis16350_poll_func_th);
+ if (ret)
+ goto error_iio_sw_rb_free;
+
indio_dev->modes |= INDIO_RING_TRIGGERED;
return 0;
@@ -275,12 +221,3 @@ error_iio_sw_rb_free:
return ret;
}
-int adis16350_initialize_ring(struct iio_ring_buffer *ring)
-{
- return iio_ring_buffer_register(ring, 0);
-}
-
-void adis16350_uninitialize_ring(struct iio_ring_buffer *ring)
-{
- iio_ring_buffer_unregister(ring);
-}
diff --git a/drivers/staging/iio/imu/adis16350_trigger.c b/drivers/staging/iio/imu/adis16350_trigger.c
index 1ffa75d05fa..76edccc85b7 100644
--- a/drivers/staging/iio/imu/adis16350_trigger.c
+++ b/drivers/staging/iio/imu/adis16350_trigger.c
@@ -23,8 +23,7 @@ static int adis16350_data_rdy_trig_poll(struct iio_dev *dev_info,
struct adis16350_state *st = iio_dev_get_devdata(dev_info);
struct iio_trigger *trig = st->trig;
- trig->timestamp = timestamp;
- iio_trigger_poll(trig);
+ iio_trigger_poll(trig, timestamp);
return IRQ_HANDLED;
}
@@ -86,14 +85,13 @@ int adis16350_probe_trigger(struct iio_dev *indio_dev)
struct adis16350_state *st = indio_dev->dev_data;
st->trig = iio_allocate_trigger();
- st->trig->name = kmalloc(IIO_TRIGGER_NAME_LENGTH, GFP_KERNEL);
+ st->trig->name = kasprintf(GFP_KERNEL,
+ "adis16350-dev%d",
+ indio_dev->id);
if (!st->trig->name) {
ret = -ENOMEM;
goto error_free_trig;
}
- snprintf((char *)st->trig->name,
- IIO_TRIGGER_NAME_LENGTH,
- "adis16350-dev%d", indio_dev->id);
st->trig->dev.parent = &st->us->dev;
st->trig->owner = THIS_MODULE;
st->trig->private_data = st;
diff --git a/drivers/staging/iio/imu/adis16400.h b/drivers/staging/iio/imu/adis16400.h
index 5a69a7ab91c..6ff33e1ad8c 100644
--- a/drivers/staging/iio/imu/adis16400.h
+++ b/drivers/staging/iio/imu/adis16400.h
@@ -126,7 +126,6 @@
* struct adis16400_state - device instance specific data
* @us: actual spi_device
* @work_trigger_to_ring: bh for triggered event handling
- * @work_cont_thresh: CLEAN
* @inter: used to check if new interrupt has been triggered
* @last_timestamp: passing timestamp from th to bh of interrupt handler
* @indio_dev: industrial I/O device structure
@@ -138,7 +137,6 @@
struct adis16400_state {
struct spi_device *us;
struct work_struct work_trigger_to_ring;
- struct iio_work_cont work_cont_thresh;
s64 last_timestamp;
struct iio_dev *indio_dev;
struct iio_trigger *trig;
@@ -147,33 +145,25 @@ struct adis16400_state {
struct mutex buf_lock;
};
-int adis16400_spi_read_burst(struct device *dev, u8 *rx);
-
int adis16400_set_irq(struct device *dev, bool enable);
-int adis16400_reset(struct device *dev);
-
-int adis16400_check_status(struct device *dev);
-
#ifdef CONFIG_IIO_RING_BUFFER
/* At the moment triggers are only used for ring buffer
* filling. This may change!
*/
-enum adis16400_scan {
- ADIS16400_SCAN_SUPPLY,
- ADIS16400_SCAN_GYRO_X,
- ADIS16400_SCAN_GYRO_Y,
- ADIS16400_SCAN_GYRO_Z,
- ADIS16400_SCAN_ACC_X,
- ADIS16400_SCAN_ACC_Y,
- ADIS16400_SCAN_ACC_Z,
- ADIS16400_SCAN_MAGN_X,
- ADIS16400_SCAN_MAGN_Y,
- ADIS16400_SCAN_MAGN_Z,
- ADIS16400_SCAN_TEMP,
- ADIS16400_SCAN_ADC_0
-};
+#define ADIS16400_SCAN_SUPPLY 0
+#define ADIS16400_SCAN_GYRO_X 1
+#define ADIS16400_SCAN_GYRO_Y 2
+#define ADIS16400_SCAN_GYRO_Z 3
+#define ADIS16400_SCAN_ACC_X 4
+#define ADIS16400_SCAN_ACC_Y 5
+#define ADIS16400_SCAN_ACC_Z 6
+#define ADIS16400_SCAN_MAGN_X 7
+#define ADIS16400_SCAN_MAGN_Y 8
+#define ADIS16400_SCAN_MAGN_Z 9
+#define ADIS16400_SCAN_TEMP 10
+#define ADIS16400_SCAN_ADC_0 11
void adis16400_remove_trigger(struct iio_dev *indio_dev);
int adis16400_probe_trigger(struct iio_dev *indio_dev);
@@ -186,8 +176,6 @@ ssize_t adis16400_read_data_from_ring(struct device *dev,
int adis16400_configure_ring(struct iio_dev *indio_dev);
void adis16400_unconfigure_ring(struct iio_dev *indio_dev);
-int adis16400_initialize_ring(struct iio_ring_buffer *ring);
-void adis16400_uninitialize_ring(struct iio_ring_buffer *ring);
#else /* CONFIG_IIO_RING_BUFFER */
static inline void adis16400_remove_trigger(struct iio_dev *indio_dev)
@@ -216,14 +204,5 @@ static inline void adis16400_unconfigure_ring(struct iio_dev *indio_dev)
{
}
-static inline int adis16400_initialize_ring(struct iio_ring_buffer *ring)
-{
- return 0;
-}
-
-static inline void adis16400_uninitialize_ring(struct iio_ring_buffer *ring)
-{
-}
-
#endif /* CONFIG_IIO_RING_BUFFER */
#endif /* SPI_ADIS16400_H_ */
diff --git a/drivers/staging/iio/imu/adis16400_core.c b/drivers/staging/iio/imu/adis16400_core.c
index e69e2ce47da..6013fee218e 100644
--- a/drivers/staging/iio/imu/adis16400_core.c
+++ b/drivers/staging/iio/imu/adis16400_core.c
@@ -21,12 +21,13 @@
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/spi/spi.h>
-
+#include <linux/slab.h>
#include <linux/sysfs.h>
#include <linux/list.h>
#include "../iio.h"
#include "../sysfs.h"
+#include "../ring_generic.h"
#include "../accel/accel.h"
#include "../adc/adc.h"
#include "../gyro/gyro.h"
@@ -36,6 +37,8 @@
#define DRIVER_NAME "adis16400"
+static int adis16400_check_status(struct device *dev);
+
/* At the moment the spi framework doesn't allow global setting of cs_change.
* It's in the likely to be added comment at the top of spi.h.
* This means that use cannot be made of spi_write etc.
@@ -161,54 +164,6 @@ error_ret:
return ret;
}
-/**
- * adis16400_spi_read_burst() - read all data registers
- * @dev: device associated with child of actual device (iio_dev or iio_trig)
- * @rx: somewhere to pass back the value read (min size is 24 bytes)
- **/
-int adis16400_spi_read_burst(struct device *dev, u8 *rx)
-{
- struct spi_message msg;
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
- struct adis16400_state *st = iio_dev_get_devdata(indio_dev);
- u32 old_speed_hz = st->us->max_speed_hz;
- int ret;
-
- struct spi_transfer xfers[] = {
- {
- .tx_buf = st->tx,
- .bits_per_word = 8,
- .len = 2,
- .cs_change = 0,
- }, {
- .rx_buf = rx,
- .bits_per_word = 8,
- .len = 24,
- .cs_change = 1,
- },
- };
-
- mutex_lock(&st->buf_lock);
- st->tx[0] = ADIS16400_READ_REG(ADIS16400_GLOB_CMD);
- st->tx[1] = 0;
-
- spi_message_init(&msg);
- spi_message_add_tail(&xfers[0], &msg);
- spi_message_add_tail(&xfers[1], &msg);
-
- st->us->max_speed_hz = min(ADIS16400_SPI_BURST, old_speed_hz);
- spi_setup(st->us);
-
- ret = spi_sync(st->us, &msg);
- if (ret)
- dev_err(&st->us->dev, "problem when burst reading");
-
- st->us->max_speed_hz = old_speed_hz;
- spi_setup(st->us);
- mutex_unlock(&st->buf_lock);
- return ret;
-}
-
static ssize_t adis16400_spi_read_signed(struct device *dev,
struct device_attribute *attr,
char *buf,
@@ -277,7 +232,6 @@ static ssize_t adis16400_read_12bit_signed(struct device *dev,
return ret;
}
-
static ssize_t adis16400_write_16bit(struct device *dev,
struct device_attribute *attr,
const char *buf,
@@ -349,6 +303,18 @@ static ssize_t adis16400_write_frequency(struct device *dev,
return ret ? ret : len;
}
+static int adis16400_reset(struct device *dev)
+{
+ int ret;
+ ret = adis16400_spi_write_reg_8(dev,
+ ADIS16400_GLOB_CMD,
+ ADIS16400_GLOB_CMD_SW_RESET);
+ if (ret)
+ dev_err(dev, "problem resetting device");
+
+ return ret;
+}
+
static ssize_t adis16400_write_reset(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t len)
@@ -364,8 +330,6 @@ static ssize_t adis16400_write_reset(struct device *dev,
return -1;
}
-
-
int adis16400_set_irq(struct device *dev, bool enable)
{
int ret;
@@ -388,18 +352,6 @@ error_ret:
return ret;
}
-int adis16400_reset(struct device *dev)
-{
- int ret;
- ret = adis16400_spi_write_reg_8(dev,
- ADIS16400_GLOB_CMD,
- ADIS16400_GLOB_CMD_SW_RESET);
- if (ret)
- dev_err(dev, "problem resetting device");
-
- return ret;
-}
-
/* Power down the device */
static int adis16400_stop_device(struct device *dev)
{
@@ -430,7 +382,7 @@ err_ret:
return ret;
}
-int adis16400_check_status(struct device *dev)
+static int adis16400_check_status(struct device *dev)
{
u16 status;
int ret;
@@ -496,6 +448,11 @@ static int adis16400_initial_setup(struct adis16400_state *st)
}
/* Do self test */
+ ret = adis16400_self_test(dev);
+ if (ret) {
+ dev_err(dev, "self test failure");
+ goto err_ret;
+ }
/* Read status register to check the result */
ret = adis16400_check_status(dev);
@@ -685,21 +642,13 @@ static int __devinit adis16400_probe(struct spi_device *spi)
goto error_unreg_ring_funcs;
regdone = 1;
- ret = adis16400_initialize_ring(st->indio_dev->ring);
+ ret = iio_ring_buffer_register(st->indio_dev->ring, 0);
if (ret) {
printk(KERN_ERR "failed to initialize the ring\n");
goto error_unreg_ring_funcs;
}
if (spi->irq && gpio_is_valid(irq_to_gpio(spi->irq)) > 0) {
-#if 0 /* fixme: here we should support */
- iio_init_work_cont(&st->work_cont_thresh,
- NULL,
- adis16400_thresh_handler_bh_no_check,
- 0,
- 0,
- st);
-#endif
ret = iio_register_interrupt_line(spi->irq,
st->indio_dev,
0,
@@ -726,7 +675,7 @@ error_unregister_line:
if (st->indio_dev->modes & INDIO_RING_TRIGGERED)
iio_unregister_interrupt_line(st->indio_dev, 0);
error_uninitialize_ring:
- adis16400_uninitialize_ring(st->indio_dev->ring);
+ iio_ring_buffer_unregister(st->indio_dev->ring);
error_unreg_ring_funcs:
adis16400_unconfigure_ring(st->indio_dev);
error_free_dev:
@@ -761,7 +710,7 @@ static int adis16400_remove(struct spi_device *spi)
if (spi->irq && gpio_is_valid(irq_to_gpio(spi->irq)) > 0)
iio_unregister_interrupt_line(indio_dev, 0);
- adis16400_uninitialize_ring(indio_dev->ring);
+ iio_ring_buffer_unregister(st->indio_dev->ring);
adis16400_unconfigure_ring(indio_dev);
iio_device_unregister(indio_dev);
kfree(st->tx);
diff --git a/drivers/staging/iio/imu/adis16400_ring.c b/drivers/staging/iio/imu/adis16400_ring.c
index 5529b32bd2e..949db76283d 100644
--- a/drivers/staging/iio/imu/adis16400_ring.c
+++ b/drivers/staging/iio/imu/adis16400_ring.c
@@ -6,6 +6,7 @@
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/spi/spi.h>
+#include <linux/slab.h>
#include <linux/sysfs.h>
#include <linux/list.h>
@@ -16,16 +17,6 @@
#include "../trigger.h"
#include "adis16400.h"
-/**
- * combine_8_to_16() utility function to munge to u8s into u16
- **/
-static inline u16 combine_8_to_16(u8 lower, u8 upper)
-{
- u16 _lower = lower;
- u16 _upper = upper;
- return _lower | (_upper << 8);
-}
-
static IIO_SCAN_EL_C(supply, ADIS16400_SCAN_SUPPLY, IIO_SIGNED(14),
ADIS16400_SUPPLY_OUT, NULL);
@@ -83,10 +74,10 @@ static struct attribute_group adis16400_scan_el_group = {
* adis16400_poll_func_th() top half interrupt handler called by trigger
* @private_data: iio_dev
**/
-static void adis16400_poll_func_th(struct iio_dev *indio_dev)
+static void adis16400_poll_func_th(struct iio_dev *indio_dev, s64 time)
{
struct adis16400_state *st = iio_dev_get_devdata(indio_dev);
- st->last_timestamp = indio_dev->trig->timestamp;
+ st->last_timestamp = time;
schedule_work(&st->work_trigger_to_ring);
/* Indicate that this interrupt is being handled */
@@ -96,6 +87,54 @@ static void adis16400_poll_func_th(struct iio_dev *indio_dev)
*/
}
+/**
+ * adis16400_spi_read_burst() - read all data registers
+ * @dev: device associated with child of actual device (iio_dev or iio_trig)
+ * @rx: somewhere to pass back the value read (min size is 24 bytes)
+ **/
+static int adis16400_spi_read_burst(struct device *dev, u8 *rx)
+{
+ struct spi_message msg;
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct adis16400_state *st = iio_dev_get_devdata(indio_dev);
+ u32 old_speed_hz = st->us->max_speed_hz;
+ int ret;
+
+ struct spi_transfer xfers[] = {
+ {
+ .tx_buf = st->tx,
+ .bits_per_word = 8,
+ .len = 2,
+ .cs_change = 0,
+ }, {
+ .rx_buf = rx,
+ .bits_per_word = 8,
+ .len = 24,
+ .cs_change = 1,
+ },
+ };
+
+ mutex_lock(&st->buf_lock);
+ st->tx[0] = ADIS16400_READ_REG(ADIS16400_GLOB_CMD);
+ st->tx[1] = 0;
+
+ spi_message_init(&msg);
+ spi_message_add_tail(&xfers[0], &msg);
+ spi_message_add_tail(&xfers[1], &msg);
+
+ st->us->max_speed_hz = min(ADIS16400_SPI_BURST, old_speed_hz);
+ spi_setup(st->us);
+
+ ret = spi_sync(st->us, &msg);
+ if (ret)
+ dev_err(&st->us->dev, "problem when burst reading");
+
+ st->us->max_speed_hz = old_speed_hz;
+ spi_setup(st->us);
+ mutex_unlock(&st->buf_lock);
+ return ret;
+}
+
/* Whilst this makes a lot of calls to iio_sw_ring functions - it is to device
* specific to be rolled into the core.
*/
@@ -118,10 +157,9 @@ static void adis16400_trigger_bh_to_ring(struct work_struct *work_s)
if (st->indio_dev->scan_count)
if (adis16400_spi_read_burst(&st->indio_dev->dev, st->rx) >= 0)
- for (; i < st->indio_dev->scan_count; i++) {
- data[i] = combine_8_to_16(st->rx[i*2+1],
- st->rx[i*2]);
- }
+ for (; i < st->indio_dev->scan_count; i++)
+ data[i] = be16_to_cpup(
+ (__be16 *)&(st->rx[i*2]));
/* Guaranteed to be aligned with 8 byte boundary */
if (st->indio_dev->scan_timestamp)
@@ -136,45 +174,6 @@ static void adis16400_trigger_bh_to_ring(struct work_struct *work_s)
return;
}
-/* in these circumstances is it better to go with unaligned packing and
- * deal with the cost?*/
-static int adis16400_data_rdy_ring_preenable(struct iio_dev *indio_dev)
-{
- size_t size;
- dev_dbg(&indio_dev->dev, "%s\n", __func__);
- /* Check if there are any scan elements enabled, if not fail*/
- if (!(indio_dev->scan_count || indio_dev->scan_timestamp))
- return -EINVAL;
-
- if (indio_dev->ring->access.set_bpd) {
- if (indio_dev->scan_timestamp)
- if (indio_dev->scan_count) /* Timestamp and data */
- size = 6*sizeof(s64);
- else /* Timestamp only */
- size = sizeof(s64);
- else /* Data only */
- size = indio_dev->scan_count*sizeof(s16);
- indio_dev->ring->access.set_bpd(indio_dev->ring, size);
- }
-
- return 0;
-}
-
-static int adis16400_data_rdy_ring_postenable(struct iio_dev *indio_dev)
-{
- return indio_dev->trig
- ? iio_trigger_attach_poll_func(indio_dev->trig,
- indio_dev->pollfunc)
- : 0;
-}
-
-static int adis16400_data_rdy_ring_predisable(struct iio_dev *indio_dev)
-{
- return indio_dev->trig
- ? iio_trigger_dettach_poll_func(indio_dev->trig,
- indio_dev->pollfunc)
- : 0;
-}
void adis16400_unconfigure_ring(struct iio_dev *indio_dev)
{
@@ -214,18 +213,16 @@ int adis16400_configure_ring(struct iio_dev *indio_dev)
indio_dev->ring = ring;
/* Effectively select the ring buffer implementation */
iio_ring_sw_register_funcs(&ring->access);
- ring->preenable = &adis16400_data_rdy_ring_preenable;
- ring->postenable = &adis16400_data_rdy_ring_postenable;
- ring->predisable = &adis16400_data_rdy_ring_predisable;
+ ring->bpe = 2;
+ ring->preenable = &iio_sw_ring_preenable;
+ ring->postenable = &iio_triggered_ring_postenable;
+ ring->predisable = &iio_triggered_ring_predisable;
ring->owner = THIS_MODULE;
- indio_dev->pollfunc = kzalloc(sizeof(*indio_dev->pollfunc), GFP_KERNEL);
- if (indio_dev->pollfunc == NULL) {
- ret = -ENOMEM;
- goto error_iio_sw_rb_free;;
- }
- indio_dev->pollfunc->poll_func_main = &adis16400_poll_func_th;
- indio_dev->pollfunc->private_data = indio_dev;
+ ret = iio_alloc_pollfunc(indio_dev, NULL, &adis16400_poll_func_th);
+ if (ret)
+ goto error_iio_sw_rb_free;
+
indio_dev->modes |= INDIO_RING_TRIGGERED;
return 0;
@@ -233,13 +230,3 @@ error_iio_sw_rb_free:
iio_sw_rb_free(indio_dev->ring);
return ret;
}
-
-int adis16400_initialize_ring(struct iio_ring_buffer *ring)
-{
- return iio_ring_buffer_register(ring, 0);
-}
-
-void adis16400_uninitialize_ring(struct iio_ring_buffer *ring)
-{
- iio_ring_buffer_unregister(ring);
-}
diff --git a/drivers/staging/iio/imu/adis16400_trigger.c b/drivers/staging/iio/imu/adis16400_trigger.c
index 3b3250ac768..aafe6010f1b 100644
--- a/drivers/staging/iio/imu/adis16400_trigger.c
+++ b/drivers/staging/iio/imu/adis16400_trigger.c
@@ -23,8 +23,7 @@ static int adis16400_data_rdy_trig_poll(struct iio_dev *dev_info,
struct adis16400_state *st = iio_dev_get_devdata(dev_info);
struct iio_trigger *trig = st->trig;
- trig->timestamp = timestamp;
- iio_trigger_poll(trig);
+ iio_trigger_poll(trig, timestamp);
return IRQ_HANDLED;
}
@@ -86,14 +85,13 @@ int adis16400_probe_trigger(struct iio_dev *indio_dev)
struct adis16400_state *st = indio_dev->dev_data;
st->trig = iio_allocate_trigger();
- st->trig->name = kmalloc(IIO_TRIGGER_NAME_LENGTH, GFP_KERNEL);
+ st->trig->name = kasprintf(GFP_KERNEL,
+ "adis16400-dev%d",
+ indio_dev->id);
if (!st->trig->name) {
ret = -ENOMEM;
goto error_free_trig;
}
- snprintf((char *)st->trig->name,
- IIO_TRIGGER_NAME_LENGTH,
- "adis16400-dev%d", indio_dev->id);
st->trig->dev.parent = &st->us->dev;
st->trig->owner = THIS_MODULE;
st->trig->private_data = st;
diff --git a/drivers/staging/iio/industrialio-core.c b/drivers/staging/iio/industrialio-core.c
index 01030684ef2..dd4d87a8bca 100644
--- a/drivers/staging/iio/industrialio-core.c
+++ b/drivers/staging/iio/industrialio-core.c
@@ -30,9 +30,6 @@
/* IDR to assign each registered device a unique id*/
static DEFINE_IDR(iio_idr);
-
-/* IDR for general event identifiers */
-static DEFINE_IDR(iio_event_idr);
/* IDR to allocate character device minor numbers */
static DEFINE_IDR(iio_chrdev_idr);
/* Lock used to protect both of the above */
@@ -654,16 +651,11 @@ static int iio_device_register_eventset(struct iio_dev *dev_info)
for (i = 0; i < dev_info->num_interrupt_lines; i++) {
dev_info->event_interfaces[i].owner = dev_info->driver_module;
- ret = iio_get_new_idr_val(&iio_event_idr);
- if (ret < 0)
- goto error_free_setup_ev_ints;
- else
- dev_info->event_interfaces[i].id = ret;
snprintf(dev_info->event_interfaces[i]._name, 20,
"%s:event%d",
dev_name(&dev_info->dev),
- dev_info->event_interfaces[i].id);
+ i);
ret = iio_setup_ev_int(&dev_info->event_interfaces[i],
(const char *)(dev_info
@@ -674,8 +666,6 @@ static int iio_device_register_eventset(struct iio_dev *dev_info)
if (ret) {
dev_err(&dev_info->dev,
"Could not get chrdev interface\n");
- iio_free_idr_val(&iio_event_idr,
- dev_info->event_interfaces[i].id);
goto error_free_setup_ev_ints;
}
@@ -711,11 +701,8 @@ error_remove_sysfs_interfaces:
->event_interfaces[j].dev.kobj,
&dev_info->event_attrs[j]);
error_free_setup_ev_ints:
- for (j = 0; j < i; j++) {
- iio_free_idr_val(&iio_event_idr,
- dev_info->event_interfaces[j].id);
+ for (j = 0; j < i; j++)
iio_free_ev_int(&dev_info->event_interfaces[j]);
- }
kfree(dev_info->interrupts);
error_free_event_interfaces:
kfree(dev_info->event_interfaces);
@@ -735,11 +722,8 @@ static void iio_device_unregister_eventset(struct iio_dev *dev_info)
->event_interfaces[i].dev.kobj,
&dev_info->event_attrs[i]);
- for (i = 0; i < dev_info->num_interrupt_lines; i++) {
- iio_free_idr_val(&iio_event_idr,
- dev_info->event_interfaces[i].id);
+ for (i = 0; i < dev_info->num_interrupt_lines; i++)
iio_free_ev_int(&dev_info->event_interfaces[i]);
- }
kfree(dev_info->interrupts);
kfree(dev_info->event_interfaces);
}
diff --git a/drivers/staging/iio/industrialio-ring.c b/drivers/staging/iio/industrialio-ring.c
index ada159bbb1f..6ab578e4f5f 100644
--- a/drivers/staging/iio/industrialio-ring.c
+++ b/drivers/staging/iio/industrialio-ring.c
@@ -149,12 +149,10 @@ __iio_request_ring_buffer_event_chrdev(struct iio_ring_buffer *buf,
{
int ret;
- buf->ev_int.id = id;
-
snprintf(buf->ev_int._name, sizeof(buf->ev_int._name),
"%s:event%d",
dev_name(&buf->dev),
- buf->ev_int.id);
+ id);
ret = iio_setup_ev_int(&(buf->ev_int),
buf->ev_int._name,
owner,
diff --git a/drivers/staging/iio/industrialio-trigger.c b/drivers/staging/iio/industrialio-trigger.c
index 5682e61600f..57dd9232cf0 100644
--- a/drivers/staging/iio/industrialio-trigger.c
+++ b/drivers/staging/iio/industrialio-trigger.c
@@ -31,7 +31,6 @@
* Any other suggestions?
*/
-
static DEFINE_IDR(iio_trigger_idr);
static DEFINE_SPINLOCK(iio_trigger_idr_lock);
@@ -173,7 +172,7 @@ struct iio_trigger *iio_trigger_find_by_name(const char *name, size_t len)
}
EXPORT_SYMBOL(iio_trigger_find_by_name);
-void iio_trigger_poll(struct iio_trigger *trig)
+void iio_trigger_poll(struct iio_trigger *trig, s64 time)
{
struct iio_poll_func *pf_cursor;
@@ -185,7 +184,8 @@ void iio_trigger_poll(struct iio_trigger *trig)
}
list_for_each_entry(pf_cursor, &trig->pollfunc_list, list) {
if (pf_cursor->poll_func_main) {
- pf_cursor->poll_func_main(pf_cursor->private_data);
+ pf_cursor->poll_func_main(pf_cursor->private_data,
+ time);
trig->use_count++;
}
}
@@ -198,8 +198,7 @@ void iio_trigger_notify_done(struct iio_trigger *trig)
if (trig->use_count == 0 && trig->try_reenable)
if (trig->try_reenable(trig)) {
/* Missed and interrupt so launch new poll now */
- trig->timestamp = 0;
- iio_trigger_poll(trig);
+ iio_trigger_poll(trig, 0);
}
}
EXPORT_SYMBOL(iio_trigger_notify_done);
@@ -284,7 +283,7 @@ error_ret:
EXPORT_SYMBOL(iio_trigger_dettach_poll_func);
/**
- * iio_trigger_read_currrent() trigger consumer sysfs query which trigger
+ * iio_trigger_read_currrent() - trigger consumer sysfs query which trigger
*
* For trigger consumers the current_trigger interface allows the trigger
* used by the device to be queried.
@@ -296,10 +295,9 @@ static ssize_t iio_trigger_read_current(struct device *dev,
struct iio_dev *dev_info = dev_get_drvdata(dev);
int len = 0;
if (dev_info->trig)
- len = snprintf(buf,
- IIO_TRIGGER_NAME_LENGTH,
- "%s\n",
- dev_info->trig->name);
+ len = sprintf(buf,
+ "%s\n",
+ dev_info->trig->name);
return len;
}
@@ -324,8 +322,6 @@ static ssize_t iio_trigger_write_current(struct device *dev,
}
mutex_unlock(&dev_info->mlock);
- len = len < IIO_TRIGGER_NAME_LENGTH ? len : IIO_TRIGGER_NAME_LENGTH;
-
dev_info->trig = iio_trigger_find_by_name(buf, len);
if (oldtrig && dev_info->trig != oldtrig)
iio_put_trigger(oldtrig);
@@ -402,3 +398,34 @@ int iio_device_unregister_trigger_consumer(struct iio_dev *dev_info)
}
EXPORT_SYMBOL(iio_device_unregister_trigger_consumer);
+int iio_alloc_pollfunc(struct iio_dev *indio_dev,
+ void (*immediate)(struct iio_dev *indio_dev),
+ void (*main)(struct iio_dev *private_data, s64 time))
+{
+ indio_dev->pollfunc = kzalloc(sizeof(*indio_dev->pollfunc), GFP_KERNEL);
+ if (indio_dev->pollfunc == NULL)
+ return -ENOMEM;
+ indio_dev->pollfunc->poll_func_immediate = immediate;
+ indio_dev->pollfunc->poll_func_main = main;
+ indio_dev->pollfunc->private_data = indio_dev;
+ return 0;
+}
+EXPORT_SYMBOL(iio_alloc_pollfunc);
+
+int iio_triggered_ring_postenable(struct iio_dev *indio_dev)
+{
+ return indio_dev->trig
+ ? iio_trigger_attach_poll_func(indio_dev->trig,
+ indio_dev->pollfunc)
+ : 0;
+}
+EXPORT_SYMBOL(iio_triggered_ring_postenable);
+
+int iio_triggered_ring_predisable(struct iio_dev *indio_dev)
+{
+ return indio_dev->trig
+ ? iio_trigger_dettach_poll_func(indio_dev->trig,
+ indio_dev->pollfunc)
+ : 0;
+}
+EXPORT_SYMBOL(iio_triggered_ring_predisable);
diff --git a/drivers/staging/iio/light/Kconfig b/drivers/staging/iio/light/Kconfig
index 80cb6e590fb..3ddc478e618 100644
--- a/drivers/staging/iio/light/Kconfig
+++ b/drivers/staging/iio/light/Kconfig
@@ -12,4 +12,3 @@ config SENSORS_TSL2563
This driver can also be built as a module. If so, the module
will be called tsl2563.
-
diff --git a/drivers/staging/iio/light/light.h b/drivers/staging/iio/light/light.h
index f00f827689c..e4e1e2c4139 100644
--- a/drivers/staging/iio/light/light.h
+++ b/drivers/staging/iio/light/light.h
@@ -2,11 +2,6 @@
/* Light to digital sensor attributes */
-#define IIO_DEV_ATTR_LIGHT_INFRARED(_num, _show, _addr) \
- IIO_DEVICE_ATTR(light_infrared##_num, S_IRUGO, _show, NULL, _addr)
+#define IIO_EVENT_CODE_LIGHT_THRESH IIO_EVENT_CODE_LIGHT_BASE
-#define IIO_DEV_ATTR_LIGHT_BROAD(_num, _show, _addr) \
- IIO_DEVICE_ATTR(light_broadspectrum##_num, S_IRUGO, _show, NULL, _addr)
-#define IIO_DEV_ATTR_LIGHT_VISIBLE(_num, _show, _addr) \
- IIO_DEVICE_ATTR(light_visible##_num, S_IRUGO, _show, NULL, _addr)
diff --git a/drivers/staging/iio/light/tsl2563.c b/drivers/staging/iio/light/tsl2563.c
index e4b0a5ef1c1..98f8b78f5d8 100644
--- a/drivers/staging/iio/light/tsl2563.c
+++ b/drivers/staging/iio/light/tsl2563.c
@@ -27,6 +27,7 @@
#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/interrupt.h>
+#include <linux/irq.h>
#include <linux/sched.h>
#include <linux/mutex.h>
#include <linux/delay.h>
@@ -117,15 +118,17 @@ struct tsl2563_chip {
struct iio_dev *indio_dev;
struct delayed_work poweroff_work;
+ struct work_struct work_thresh;
+ s64 event_timestamp;
/* Remember state for suspend and resume functions */
pm_message_t state;
struct tsl2563_gainlevel_coeff *gainlevel;
- /* Thresholds are in lux */
u16 low_thres;
u16 high_thres;
u8 intr;
+ bool int_enabled;
/* Calibration coefficients */
u32 calib0;
@@ -189,17 +192,29 @@ static int tsl2563_get_power(struct tsl2563_chip *chip)
static int tsl2563_configure(struct tsl2563_chip *chip)
{
- struct i2c_client *client = chip->client;
int ret;
- ret = tsl2563_write(client, TSL2563_REG_TIMING,
+ ret = tsl2563_write(chip->client, TSL2563_REG_TIMING,
chip->gainlevel->gaintime);
if (ret)
- goto out;
-
- ret = tsl2563_write(client, TSL2563_REG_INT, chip->intr);
-
-out:
+ goto error_ret;
+ ret = tsl2563_write(chip->client, TSL2563_REG_HIGHLOW,
+ chip->high_thres & 0xFF);
+ if (ret)
+ goto error_ret;
+ ret = tsl2563_write(chip->client, TSL2563_REG_HIGHHIGH,
+ (chip->high_thres >> 8) & 0xFF);
+ if (ret)
+ goto error_ret;
+ ret = tsl2563_write(chip->client, TSL2563_REG_LOWLOW,
+ chip->low_thres & 0xFF);
+ if (ret)
+ goto error_ret;
+ ret = tsl2563_write(chip->client, TSL2563_REG_LOWHIGH,
+ (chip->low_thres >> 8) & 0xFF);
+/* Interrupt register is automatically written anyway if it is relevant
+ so is not here */
+error_ret:
return ret;
}
@@ -323,21 +338,23 @@ static int tsl2563_get_adc(struct tsl2563_chip *chip)
if (chip->state.event != PM_EVENT_ON)
goto out;
- cancel_delayed_work(&chip->poweroff_work);
-
- if (!tsl2563_get_power(chip)) {
- ret = tsl2563_set_power(chip, 1);
- if (ret)
- goto out;
- ret = tsl2563_configure(chip);
- if (ret)
- goto out;
- tsl2563_wait_adc(chip);
+ if (!chip->int_enabled) {
+ cancel_delayed_work(&chip->poweroff_work);
+
+ if (!tsl2563_get_power(chip)) {
+ ret = tsl2563_set_power(chip, 1);
+ if (ret)
+ goto out;
+ ret = tsl2563_configure(chip);
+ if (ret)
+ goto out;
+ tsl2563_wait_adc(chip);
+ }
}
while (retry) {
ret = tsl2563_read(client,
- TSL2563_REG_DATA0LOW | TSL2563_CLEARINT,
+ TSL2563_REG_DATA0LOW,
buf0, sizeof(buf0));
if (ret != sizeof(buf0))
goto out;
@@ -356,7 +373,8 @@ static int tsl2563_get_adc(struct tsl2563_chip *chip)
chip->data0 = normalize_adc(adc0, chip->gainlevel->gaintime);
chip->data1 = normalize_adc(adc1, chip->gainlevel->gaintime);
- schedule_delayed_work(&chip->poweroff_work, 5 * HZ);
+ if (!chip->int_enabled)
+ schedule_delayed_work(&chip->poweroff_work, 5 * HZ);
ret = 0;
out:
@@ -449,11 +467,12 @@ static unsigned int adc_to_lux(u32 adc0, u32 adc1)
/* Sysfs interface */
/*--------------------------------------------------------------*/
-static ssize_t tsl2563_adc0_show(struct device *dev,
+static ssize_t tsl2563_adc_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct tsl2563_chip *chip = indio_dev->dev_data;
+ struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
int ret;
mutex_lock(&chip->lock);
@@ -462,26 +481,14 @@ static ssize_t tsl2563_adc0_show(struct device *dev,
if (ret)
goto out;
- ret = snprintf(buf, PAGE_SIZE, "%d\n", chip->data0);
-out:
- mutex_unlock(&chip->lock);
- return ret;
-}
-
-static ssize_t tsl2563_adc1_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
- struct tsl2563_chip *chip = indio_dev->dev_data;
- int ret;
-
- mutex_lock(&chip->lock);
-
- ret = tsl2563_get_adc(chip);
- if (ret)
- goto out;
-
- ret = snprintf(buf, PAGE_SIZE, "%d\n", chip->data1);
+ switch (this_attr->address) {
+ case 0:
+ ret = snprintf(buf, PAGE_SIZE, "%d\n", chip->data0);
+ break;
+ case 1:
+ ret = snprintf(buf, PAGE_SIZE, "%d\n", chip->data1);
+ break;
+ }
out:
mutex_unlock(&chip->lock);
return ret;
@@ -527,37 +534,36 @@ static ssize_t format_calib(char *buf, int len, u32 calib)
return snprintf(buf, PAGE_SIZE, "%d\n", calib_to_sysfs(calib));
}
-static ssize_t tsl2563_calib0_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
- struct tsl2563_chip *chip = indio_dev->dev_data;
- int ret;
-
- mutex_lock(&chip->lock);
- ret = format_calib(buf, PAGE_SIZE, chip->calib0);
- mutex_unlock(&chip->lock);
- return ret;
-}
-
-static ssize_t tsl2563_calib1_show(struct device *dev,
- struct device_attribute *attr, char *buf)
+static ssize_t tsl2563_calib_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct tsl2563_chip *chip = indio_dev->dev_data;
+ struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
int ret;
mutex_lock(&chip->lock);
- ret = format_calib(buf, PAGE_SIZE, chip->calib1);
+ switch (this_attr->address) {
+ case 0:
+ ret = format_calib(buf, PAGE_SIZE, chip->calib0);
+ break;
+ case 1:
+ ret = format_calib(buf, PAGE_SIZE, chip->calib1);
+ break;
+ default:
+ ret = -ENODEV;
+ }
mutex_unlock(&chip->lock);
return ret;
}
-static int do_calib_store(struct device *dev, const char *buf, size_t len,
- int ch)
+static ssize_t tsl2563_calib_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t len)
{
struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct tsl2563_chip *chip = indio_dev->dev_data;
+ struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
int value;
u32 calib;
@@ -566,37 +572,27 @@ static int do_calib_store(struct device *dev, const char *buf, size_t len,
calib = calib_from_sysfs(value);
- if (ch)
- chip->calib1 = calib;
- else
+ switch (this_attr->address) {
+ case 0:
chip->calib0 = calib;
+ break;
+ case 1:
+ chip->calib1 = calib;
+ break;
+ }
return len;
}
-static ssize_t tsl2563_calib0_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t len)
-{
- return do_calib_store(dev, buf, len, 0);
-}
-
-static ssize_t tsl2563_calib1_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t len)
-{
- return do_calib_store(dev, buf, len, 1);
-}
-
-/* AmitXXXX: Convert to IIO_DEV_ATTR_LIGHT* as in tsl2561
- * once I understand what they mean */
-static DEVICE_ATTR(adc0, S_IRUGO, tsl2563_adc0_show, NULL);
-static DEVICE_ATTR(adc1, S_IRUGO, tsl2563_adc1_show, NULL);
+static IIO_DEVICE_ATTR(intensity_both_raw, S_IRUGO,
+ tsl2563_adc_show, NULL, 0);
+static IIO_DEVICE_ATTR(intensity_ir_raw, S_IRUGO,
+ tsl2563_adc_show, NULL, 1);
static DEVICE_ATTR(illuminance0_input, S_IRUGO, tsl2563_lux_show, NULL);
-static DEVICE_ATTR(calib0, S_IRUGO | S_IWUSR,
- tsl2563_calib0_show, tsl2563_calib0_store);
-static DEVICE_ATTR(calib1, S_IRUGO | S_IWUSR,
- tsl2563_calib1_show, tsl2563_calib1_store);
+static IIO_DEVICE_ATTR(intensity_both_calibgain, S_IRUGO | S_IWUSR,
+ tsl2563_calib_show, tsl2563_calib_store, 0);
+static IIO_DEVICE_ATTR(intensity_ir_calibgain, S_IRUGO | S_IWUSR,
+ tsl2563_calib_show, tsl2563_calib_store, 1);
static ssize_t tsl2563_show_name(struct device *dev,
struct device_attribute *attr,
@@ -610,11 +606,11 @@ static ssize_t tsl2563_show_name(struct device *dev,
static DEVICE_ATTR(name, S_IRUGO, tsl2563_show_name, NULL);
static struct attribute *tsl2563_attributes[] = {
- &dev_attr_adc0.attr,
- &dev_attr_adc1.attr,
+ &iio_dev_attr_intensity_both_raw.dev_attr.attr,
+ &iio_dev_attr_intensity_ir_raw.dev_attr.attr,
&dev_attr_illuminance0_input.attr,
- &dev_attr_calib0.attr,
- &dev_attr_calib1.attr,
+ &iio_dev_attr_intensity_both_calibgain.dev_attr.attr,
+ &iio_dev_attr_intensity_ir_calibgain.dev_attr.attr,
&dev_attr_name.attr,
NULL
};
@@ -623,6 +619,192 @@ static const struct attribute_group tsl2563_group = {
.attrs = tsl2563_attributes,
};
+static ssize_t tsl2563_read_thresh(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct tsl2563_chip *chip = indio_dev->dev_data;
+ struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
+ u16 val = 0;
+ switch (this_attr->address) {
+ case TSL2563_REG_HIGHLOW:
+ val = chip->high_thres;
+ break;
+ case TSL2563_REG_LOWLOW:
+ val = chip->low_thres;
+ break;
+ }
+ return snprintf(buf, PAGE_SIZE, "%d\n", val);
+}
+
+static ssize_t tsl2563_write_thresh(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
+{
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct tsl2563_chip *chip = indio_dev->dev_data;
+ struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
+ unsigned long val;
+ int ret;
+
+ ret = strict_strtoul(buf, 10, &val);
+ if (ret)
+ return ret;
+ mutex_lock(&chip->lock);
+ ret = tsl2563_write(chip->client, this_attr->address, val & 0xFF);
+ if (ret)
+ goto error_ret;
+ ret = tsl2563_write(chip->client, this_attr->address + 1,
+ (val >> 8) & 0xFF);
+ switch (this_attr->address) {
+ case TSL2563_REG_HIGHLOW:
+ chip->high_thres = val;
+ break;
+ case TSL2563_REG_LOWLOW:
+ chip->low_thres = val;
+ break;
+ }
+
+error_ret:
+ mutex_unlock(&chip->lock);
+
+ return ret < 0 ? ret : len;
+}
+
+static IIO_DEVICE_ATTR(intensity_both_thresh_high_value,
+ S_IRUGO | S_IWUSR,
+ tsl2563_read_thresh,
+ tsl2563_write_thresh,
+ TSL2563_REG_HIGHLOW);
+
+static IIO_DEVICE_ATTR(intensity_both_thresh_low_value,
+ S_IRUGO | S_IWUSR,
+ tsl2563_read_thresh,
+ tsl2563_write_thresh,
+ TSL2563_REG_LOWLOW);
+
+static int tsl2563_int_th(struct iio_dev *dev_info,
+ int index,
+ s64 timestamp,
+ int not_test)
+{
+ struct tsl2563_chip *chip = dev_info->dev_data;
+
+ chip->event_timestamp = timestamp;
+ schedule_work(&chip->work_thresh);
+
+ return 0;
+}
+
+static void tsl2563_int_bh(struct work_struct *work_s)
+{
+ struct tsl2563_chip *chip
+ = container_of(work_s,
+ struct tsl2563_chip, work_thresh);
+ u8 cmd = TSL2563_CMD | TSL2563_CLEARINT;
+
+ iio_push_event(chip->indio_dev, 0,
+ IIO_EVENT_CODE_LIGHT_BASE,
+ chip->event_timestamp);
+
+ /* reenable_irq */
+ enable_irq(chip->client->irq);
+ /* clear the interrupt and push the event */
+ i2c_master_send(chip->client, &cmd, sizeof(cmd));
+
+}
+
+static ssize_t tsl2563_write_interrupt_config(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
+{
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct tsl2563_chip *chip = indio_dev->dev_data;
+ struct iio_event_attr *this_attr = to_iio_event_attr(attr);
+ int input, ret = 0;
+
+ ret = sscanf(buf, "%d", &input);
+ if (ret != 1)
+ return -EINVAL;
+ mutex_lock(&chip->lock);
+ if (input && !(chip->intr & 0x30)) {
+ iio_add_event_to_list(this_attr->listel,
+ &indio_dev->interrupts[0]->ev_list);
+ chip->intr &= ~0x30;
+ chip->intr |= 0x10;
+ /* ensure the chip is actually on */
+ cancel_delayed_work(&chip->poweroff_work);
+ if (!tsl2563_get_power(chip)) {
+ ret = tsl2563_set_power(chip, 1);
+ if (ret)
+ goto out;
+ ret = tsl2563_configure(chip);
+ if (ret)
+ goto out;
+ }
+ ret = tsl2563_write(chip->client, TSL2563_REG_INT, chip->intr);
+ chip->int_enabled = true;
+ }
+
+ if (!input && (chip->intr & 0x30)) {
+ chip->intr |= ~0x30;
+ ret = tsl2563_write(chip->client, TSL2563_REG_INT, chip->intr);
+ iio_remove_event_from_list(this_attr->listel,
+ &indio_dev->interrupts[0]->ev_list);
+ chip->int_enabled = false;
+ /* now the interrupt is not enabled, we can go to sleep */
+ schedule_delayed_work(&chip->poweroff_work, 5 * HZ);
+ }
+out:
+ mutex_unlock(&chip->lock);
+
+ return (ret < 0) ? ret : len;
+}
+
+static ssize_t tsl2563_read_interrupt_config(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct tsl2563_chip *chip = indio_dev->dev_data;
+ int ret;
+ u8 rxbuf;
+ ssize_t len;
+
+ mutex_lock(&chip->lock);
+ ret = tsl2563_read(chip->client,
+ TSL2563_REG_INT,
+ &rxbuf,
+ sizeof(rxbuf));
+ mutex_unlock(&chip->lock);
+ if (ret < 0)
+ goto error_ret;
+ len = snprintf(buf, PAGE_SIZE, "%d\n", !!(rxbuf & 0x30));
+error_ret:
+
+ return (ret < 0) ? ret : len;
+}
+
+IIO_EVENT_ATTR(intensity_both_thresh_both_en,
+ tsl2563_read_interrupt_config,
+ tsl2563_write_interrupt_config,
+ 0,
+ tsl2563_int_th);
+
+static struct attribute *tsl2563_event_attributes[] = {
+ &iio_event_attr_intensity_both_thresh_both_en.dev_attr.attr,
+ &iio_dev_attr_intensity_both_thresh_high_value.dev_attr.attr,
+ &iio_dev_attr_intensity_both_thresh_low_value.dev_attr.attr,
+ NULL,
+};
+
+static struct attribute_group tsl2563_event_attribute_group = {
+ .attrs = tsl2563_event_attributes,
+};
+
/*--------------------------------------------------------------*/
/* Probe, Attach, Remove */
/*--------------------------------------------------------------*/
@@ -641,6 +823,7 @@ static int __devinit tsl2563_probe(struct i2c_client *client,
if (!chip)
return -ENOMEM;
+ INIT_WORK(&chip->work_thresh, tsl2563_int_bh);
i2c_set_clientdata(client, chip);
chip->client = client;
@@ -679,18 +862,36 @@ static int __devinit tsl2563_probe(struct i2c_client *client,
chip->indio_dev->dev_data = (void *)(chip);
chip->indio_dev->driver_module = THIS_MODULE;
chip->indio_dev->modes = INDIO_DIRECT_MODE;
+ if (client->irq) {
+ chip->indio_dev->num_interrupt_lines = 1;
+ chip->indio_dev->event_attrs
+ = &tsl2563_event_attribute_group;
+ }
ret = iio_device_register(chip->indio_dev);
if (ret)
goto fail1;
+ if (client->irq) {
+ ret = iio_register_interrupt_line(client->irq,
+ chip->indio_dev,
+ 0,
+ IRQF_TRIGGER_RISING,
+ client->name);
+ if (ret)
+ goto fail2;
+ }
err = tsl2563_configure(chip);
if (err)
- goto fail2;
+ goto fail3;
INIT_DELAYED_WORK(&chip->poweroff_work, tsl2563_poweroff_work);
+ /* The interrupt cannot yet be enabled so this is fine without lock */
schedule_delayed_work(&chip->poweroff_work, 5 * HZ);
return 0;
+fail3:
+ if (client->irq)
+ iio_unregister_interrupt_line(chip->indio_dev, 0);
fail2:
iio_device_unregister(chip->indio_dev);
fail1:
@@ -701,7 +902,15 @@ fail1:
static int tsl2563_remove(struct i2c_client *client)
{
struct tsl2563_chip *chip = i2c_get_clientdata(client);
-
+ if (!chip->int_enabled)
+ cancel_delayed_work(&chip->poweroff_work);
+ /* Ensure that interrupts are disabled - then flush any bottom halves */
+ chip->intr |= ~0x30;
+ tsl2563_write(chip->client, TSL2563_REG_INT, chip->intr);
+ flush_scheduled_work();
+ tsl2563_set_power(chip, 0);
+ if (client->irq)
+ iio_unregister_interrupt_line(chip->indio_dev, 0);
iio_device_unregister(chip->indio_dev);
kfree(chip);
diff --git a/drivers/staging/iio/magnetometer/Kconfig b/drivers/staging/iio/magnetometer/Kconfig
new file mode 100644
index 00000000000..d01445060f5
--- /dev/null
+++ b/drivers/staging/iio/magnetometer/Kconfig
@@ -0,0 +1,15 @@
+#
+# Magnetometer sensors
+#
+comment "Magnetometer sensors"
+
+config SENSORS_HMC5843
+ tristate "Honeywell HMC5843 3-Axis Magnetometer"
+ depends on I2C
+ help
+ Say Y here to add support for the Honeywell HMC 5843 3-Axis
+ Magnetometer (digital compass).
+
+ To compile this driver as a module, choose M here: the module
+ will be called hmc5843
+
diff --git a/drivers/staging/iio/magnetometer/Makefile b/drivers/staging/iio/magnetometer/Makefile
new file mode 100644
index 00000000000..f9bfb2e11d7
--- /dev/null
+++ b/drivers/staging/iio/magnetometer/Makefile
@@ -0,0 +1,5 @@
+#
+# Makefile for industrial I/O Magnetometer sensors
+#
+
+obj-$(CONFIG_SENSORS_HMC5843) += hmc5843.o
diff --git a/drivers/staging/iio/magnetometer/hmc5843.c b/drivers/staging/iio/magnetometer/hmc5843.c
new file mode 100644
index 00000000000..92f6c6fb90f
--- /dev/null
+++ b/drivers/staging/iio/magnetometer/hmc5843.c
@@ -0,0 +1,624 @@
+/* Copyright (C) 2010 Texas Instruments
+ Author: Shubhrajyoti Datta <shubhrajyoti@ti.com>
+ Acknowledgement: Jonathan Cameron <jic23@cam.ac.uk> for valuable inputs.
+
+ This program is free software; you can redistribute it and/or modify
+ 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/i2c.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include "../iio.h"
+#include "../sysfs.h"
+#include "magnet.h"
+
+#define HMC5843_I2C_ADDRESS 0x1E
+
+#define HMC5843_CONFIG_REG_A 0x00
+#define HMC5843_CONFIG_REG_B 0x01
+#define HMC5843_MODE_REG 0x02
+#define HMC5843_DATA_OUT_X_MSB_REG 0x03
+#define HMC5843_DATA_OUT_X_LSB_REG 0x04
+#define HMC5843_DATA_OUT_Y_MSB_REG 0x05
+#define HMC5843_DATA_OUT_Y_LSB_REG 0x06
+#define HMC5843_DATA_OUT_Z_MSB_REG 0x07
+#define HMC5843_DATA_OUT_Z_LSB_REG 0x08
+#define HMC5843_STATUS_REG 0x09
+#define HMC5843_ID_REG_A 0x0A
+#define HMC5843_ID_REG_B 0x0B
+#define HMC5843_ID_REG_C 0x0C
+
+#define HMC5843_ID_REG_LENGTH 0x03
+#define HMC5843_ID_STRING "H43"
+
+/*
+ * Range settings in (+-)Ga
+ * */
+#define RANGE_GAIN_OFFSET 0x05
+
+#define RANGE_0_7 0x00
+#define RANGE_1_0 0x01 /* default */
+#define RANGE_1_5 0x02
+#define RANGE_2_0 0x03
+#define RANGE_3_2 0x04
+#define RANGE_3_8 0x05
+#define RANGE_4_5 0x06
+#define RANGE_6_5 0x07 /* Not recommended */
+
+/*
+ * Device status
+ */
+#define DATA_READY 0x01
+#define DATA_OUTPUT_LOCK 0x02
+#define VOLTAGE_REGULATOR_ENABLED 0x04
+
+/*
+ * Mode register configuration
+ */
+#define MODE_CONVERSION_CONTINUOUS 0x00
+#define MODE_CONVERSION_SINGLE 0x01
+#define MODE_IDLE 0x02
+#define MODE_SLEEP 0x03
+
+/* Minimum Data Output Rate in 1/10 Hz */
+#define RATE_OFFSET 0x02
+#define RATE_BITMASK 0x1C
+#define RATE_5 0x00
+#define RATE_10 0x01
+#define RATE_20 0x02
+#define RATE_50 0x03
+#define RATE_100 0x04
+#define RATE_200 0x05
+#define RATE_500 0x06
+#define RATE_NOT_USED 0x07
+
+/*
+ * Device Configutration
+ */
+#define CONF_NORMAL 0x00
+#define CONF_POSITIVE_BIAS 0x01
+#define CONF_NEGATIVE_BIAS 0x02
+#define CONF_NOT_USED 0x03
+#define MEAS_CONF_MASK 0x03
+
+static const int regval_to_counts_per_mg[] = {
+ 1620,
+ 1300,
+ 970,
+ 780,
+ 530,
+ 460,
+ 390,
+ 280
+};
+static const int regval_to_input_field_mg[] = {
+ 700,
+ 1000,
+ 1500,
+ 2000,
+ 3200,
+ 3800,
+ 4500,
+ 6500
+};
+static const char *regval_to_samp_freq[] = {
+ "0.5",
+ "1",
+ "2",
+ "5",
+ "10",
+ "20",
+ "50",
+};
+
+/* Addresses to scan: 0x1E */
+static const unsigned short normal_i2c[] = { HMC5843_I2C_ADDRESS,
+ I2C_CLIENT_END };
+
+/* Each client has this additional data */
+struct hmc5843_data {
+ struct iio_dev *indio_dev;
+ struct mutex lock;
+ u8 rate;
+ u8 meas_conf;
+ u8 operating_mode;
+ u8 range;
+};
+
+static void hmc5843_init_client(struct i2c_client *client);
+
+static s32 hmc5843_configure(struct i2c_client *client,
+ u8 operating_mode)
+{
+ /* The lower two bits contain the current conversion mode */
+ return i2c_smbus_write_byte_data(client,
+ HMC5843_MODE_REG,
+ (operating_mode & 0x03));
+}
+
+/* Return the measurement value from the specified channel */
+static ssize_t hmc5843_read_measurement(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct i2c_client *client = to_i2c_client(indio_dev->dev.parent);
+ s16 coordinate_val;
+ struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
+ struct hmc5843_data *data = indio_dev->dev_data;
+ s32 result;
+
+ mutex_lock(&data->lock);
+
+ result = i2c_smbus_read_byte_data(client, HMC5843_STATUS_REG);
+ while (!(result & DATA_READY))
+ result = i2c_smbus_read_byte_data(client, HMC5843_STATUS_REG);
+
+ result = i2c_smbus_read_word_data(client, this_attr->address);
+ mutex_unlock(&data->lock);
+ if (result < 0)
+ return -EINVAL;
+
+ coordinate_val = (s16)swab16((u16)result);
+ return sprintf(buf, "%d\n", coordinate_val);
+}
+static IIO_DEV_ATTR_MAGN_X(hmc5843_read_measurement,
+ HMC5843_DATA_OUT_X_MSB_REG);
+static IIO_DEV_ATTR_MAGN_Y(hmc5843_read_measurement,
+ HMC5843_DATA_OUT_Y_MSB_REG);
+static IIO_DEV_ATTR_MAGN_Z(hmc5843_read_measurement,
+ HMC5843_DATA_OUT_Z_MSB_REG);
+
+/*
+ * From the datasheet
+ * 0 - Continuous-Conversion Mode: In continuous-conversion mode, the
+ * device continuously performs conversions an places the result in the
+ * data register.
+ *
+ * 1 - Single-Conversion Mode : device performs a single measurement,
+ * sets RDY high and returned to sleep mode
+ *
+ * 2 - Idle Mode : Device is placed in idle mode.
+ *
+ * 3 - Sleep Mode. Device is placed in sleep mode.
+ *
+ */
+static ssize_t hmc5843_show_operating_mode(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct hmc5843_data *data = indio_dev->dev_data;
+ return sprintf(buf, "%d\n", data->operating_mode);
+}
+
+static ssize_t hmc5843_set_operating_mode(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t count)
+{
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct i2c_client *client = to_i2c_client(indio_dev->dev.parent);
+ struct hmc5843_data *data = indio_dev->dev_data;
+ struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
+ unsigned long operating_mode = 0;
+ s32 status;
+ int error;
+ mutex_lock(&data->lock);
+ error = strict_strtoul(buf, 10, &operating_mode);
+ if (error)
+ return error;
+ dev_dbg(dev, "set Conversion mode to %lu\n", operating_mode);
+ if (operating_mode > MODE_SLEEP)
+ return -EINVAL;
+
+ status = i2c_smbus_write_byte_data(client, this_attr->address,
+ operating_mode);
+ if (status) {
+ count = -EINVAL;
+ goto exit;
+ }
+ data->operating_mode = operating_mode;
+
+exit:
+ mutex_unlock(&data->lock);
+ return count;
+}
+static IIO_DEVICE_ATTR(operating_mode,
+ S_IWUSR | S_IRUGO,
+ hmc5843_show_operating_mode,
+ hmc5843_set_operating_mode,
+ HMC5843_MODE_REG);
+
+/*
+ * API for setting the measurement configuration to
+ * Normal, Positive bias and Negative bias
+ * From the datasheet
+ *
+ * Normal measurement configuration (default): In normal measurement
+ * configuration the device follows normal measurement flow. Pins BP and BN
+ * are left floating and high impedance.
+ *
+ * Positive bias configuration: In positive bias configuration, a positive
+ * current is forced across the resistive load on pins BP and BN.
+ *
+ * Negative bias configuration. In negative bias configuration, a negative
+ * current is forced across the resistive load on pins BP and BN.
+ *
+ */
+static s32 hmc5843_set_meas_conf(struct i2c_client *client,
+ u8 meas_conf)
+{
+ struct hmc5843_data *data = i2c_get_clientdata(client);
+ u8 reg_val;
+ reg_val = (meas_conf & MEAS_CONF_MASK) | (data->rate << RATE_OFFSET);
+ return i2c_smbus_write_byte_data(client, HMC5843_CONFIG_REG_A, reg_val);
+}
+
+static ssize_t hmc5843_show_measurement_configuration(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct hmc5843_data *data = indio_dev->dev_data;
+ return sprintf(buf, "%d\n", data->meas_conf);
+}
+
+static ssize_t hmc5843_set_measurement_configuration(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t count)
+{
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct i2c_client *client = to_i2c_client(indio_dev->dev.parent);
+ struct hmc5843_data *data = i2c_get_clientdata(client);
+ unsigned long meas_conf = 0;
+ int error = strict_strtoul(buf, 10, &meas_conf);
+ if (error)
+ return error;
+ mutex_lock(&data->lock);
+
+ dev_dbg(dev, "set mode to %lu\n", meas_conf);
+ if (hmc5843_set_meas_conf(client, meas_conf)) {
+ count = -EINVAL;
+ goto exit;
+ }
+ data->meas_conf = meas_conf;
+
+exit:
+ mutex_unlock(&data->lock);
+ return count;
+}
+static IIO_DEVICE_ATTR(meas_conf,
+ S_IWUSR | S_IRUGO,
+ hmc5843_show_measurement_configuration,
+ hmc5843_set_measurement_configuration,
+ 0);
+
+/*
+ * From Datasheet
+ * The table shows the minimum data output
+ * Value | Minimum data output rate(Hz)
+ * 0 | 0.5
+ * 1 | 1
+ * 2 | 2
+ * 3 | 5
+ * 4 | 10 (default)
+ * 5 | 20
+ * 6 | 50
+ * 7 | Not used
+ */
+static IIO_CONST_ATTR_AVAIL_SAMP_FREQ("0.5 1 2 5 10 20 50");
+
+static s32 hmc5843_set_rate(struct i2c_client *client,
+ u8 rate)
+{
+ struct hmc5843_data *data = i2c_get_clientdata(client);
+ u8 reg_val;
+
+ reg_val = (data->meas_conf) | (rate << RATE_OFFSET);
+ if (rate >= RATE_NOT_USED) {
+ dev_err(&client->dev,
+ "This data output rate is not supported \n");
+ return -EINVAL;
+ }
+ return i2c_smbus_write_byte_data(client, HMC5843_CONFIG_REG_A, reg_val);
+}
+
+static ssize_t set_sampling_frequency(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct i2c_client *client = to_i2c_client(indio_dev->dev.parent);
+ struct hmc5843_data *data = indio_dev->dev_data;
+ unsigned long rate = 0;
+
+ if (strncmp(buf, "0.5" , 3) == 0)
+ rate = RATE_5;
+ else if (strncmp(buf, "1" , 1) == 0)
+ rate = RATE_10;
+ else if (strncmp(buf, "2", 1) == 0)
+ rate = RATE_20;
+ else if (strncmp(buf, "5", 1) == 0)
+ rate = RATE_50;
+ else if (strncmp(buf, "10", 2) == 0)
+ rate = RATE_100;
+ else if (strncmp(buf, "20" , 2) == 0)
+ rate = RATE_200;
+ else if (strncmp(buf, "50" , 2) == 0)
+ rate = RATE_500;
+ else
+ return -EINVAL;
+
+ mutex_lock(&data->lock);
+ dev_dbg(dev, "set rate to %lu\n", rate);
+ if (hmc5843_set_rate(client, rate)) {
+ count = -EINVAL;
+ goto exit;
+ }
+ data->rate = rate;
+
+exit:
+ mutex_unlock(&data->lock);
+ return count;
+}
+
+static ssize_t show_sampling_frequency(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct i2c_client *client = to_i2c_client(indio_dev->dev.parent);
+ struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
+ u32 rate;
+
+ rate = i2c_smbus_read_byte_data(client, this_attr->address);
+ if (rate < 0)
+ return -EINVAL;
+ rate = (rate & RATE_BITMASK) >> RATE_OFFSET;
+ return sprintf(buf, "%s\n", regval_to_samp_freq[rate]);
+}
+static IIO_DEVICE_ATTR(sampling_frequency,
+ S_IWUSR | S_IRUGO,
+ show_sampling_frequency,
+ set_sampling_frequency,
+ HMC5843_CONFIG_REG_A);
+
+/*
+ * From Datasheet
+ * Nominal gain settings
+ * Value | Sensor Input Field Range(Ga) | Gain(counts/ milli-gauss)
+ *0 |(+-)0.7 |1620
+ *1 |(+-)1.0 |1300
+ *2 |(+-)1.5 |970
+ *3 |(+-)2.0 |780
+ *4 |(+-)3.2 |530
+ *5 |(+-)3.8 |460
+ *6 |(+-)4.5 |390
+ *7 |(+-)6.5 |280
+ */
+static ssize_t show_range(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ u8 range;
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct hmc5843_data *data = indio_dev->dev_data;
+
+ range = data->range;
+ return sprintf(buf, "%d\n", regval_to_input_field_mg[range]);
+}
+
+static ssize_t set_range(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t count)
+{
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct i2c_client *client = to_i2c_client(indio_dev->dev.parent);
+ struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
+ struct hmc5843_data *data = indio_dev->dev_data;
+ unsigned long range = 0;
+ int error;
+ mutex_lock(&data->lock);
+ error = strict_strtoul(buf, 10, &range);
+ if (error)
+ return error;
+ dev_dbg(dev, "set range to %lu\n", range);
+
+ if (range > RANGE_6_5)
+ return -EINVAL;
+
+ data->range = range;
+ range = range << RANGE_GAIN_OFFSET;
+ if (i2c_smbus_write_byte_data(client, this_attr->address, range))
+ count = -EINVAL;
+
+ mutex_unlock(&data->lock);
+ return count;
+
+}
+static IIO_DEVICE_ATTR(magn_range,
+ S_IWUSR | S_IRUGO,
+ show_range,
+ set_range,
+ HMC5843_CONFIG_REG_B);
+
+static ssize_t show_gain(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct hmc5843_data *data = indio_dev->dev_data;
+ return sprintf(buf, "%d\n", regval_to_counts_per_mg[data->range]);
+}
+static IIO_DEVICE_ATTR(magn_gain,
+ S_IRUGO,
+ show_gain,
+ NULL , 0);
+
+static struct attribute *hmc5843_attributes[] = {
+ &iio_dev_attr_meas_conf.dev_attr.attr,
+ &iio_dev_attr_operating_mode.dev_attr.attr,
+ &iio_dev_attr_sampling_frequency.dev_attr.attr,
+ &iio_dev_attr_magn_range.dev_attr.attr,
+ &iio_dev_attr_magn_gain.dev_attr.attr,
+ &iio_dev_attr_magn_x_raw.dev_attr.attr,
+ &iio_dev_attr_magn_y_raw.dev_attr.attr,
+ &iio_dev_attr_magn_z_raw.dev_attr.attr,
+ &iio_const_attr_available_sampling_frequency.dev_attr.attr,
+ NULL
+};
+
+static const struct attribute_group hmc5843_group = {
+ .attrs = hmc5843_attributes,
+};
+
+static int hmc5843_detect(struct i2c_client *client,
+ struct i2c_board_info *info)
+{
+ unsigned char id_str[HMC5843_ID_REG_LENGTH];
+
+ if (client->addr != HMC5843_I2C_ADDRESS)
+ return -ENODEV;
+
+ if (i2c_smbus_read_i2c_block_data(client, HMC5843_ID_REG_A,
+ HMC5843_ID_REG_LENGTH, id_str)
+ != HMC5843_ID_REG_LENGTH)
+ return -ENODEV;
+
+ if (0 != strncmp(id_str, HMC5843_ID_STRING, HMC5843_ID_REG_LENGTH))
+ return -ENODEV;
+
+ return 0;
+}
+
+/* Called when we have found a new HMC5843. */
+static void hmc5843_init_client(struct i2c_client *client)
+{
+ struct hmc5843_data *data = i2c_get_clientdata(client);
+ hmc5843_set_meas_conf(client, data->meas_conf);
+ hmc5843_set_rate(client, data->rate);
+ hmc5843_configure(client, data->operating_mode);
+ i2c_smbus_write_byte_data(client, HMC5843_CONFIG_REG_B, data->range);
+ mutex_init(&data->lock);
+ pr_info("HMC5843 initialized\n");
+}
+
+static int hmc5843_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct hmc5843_data *data;
+ int err = 0;
+
+ data = kzalloc(sizeof(struct hmc5843_data), GFP_KERNEL);
+ if (!data) {
+ err = -ENOMEM;
+ goto exit;
+ }
+
+ /* default settings at probe */
+
+ data->meas_conf = CONF_NORMAL;
+ data->range = RANGE_1_0;
+ data->operating_mode = MODE_CONVERSION_CONTINUOUS;
+
+ i2c_set_clientdata(client, data);
+
+ /* Initialize the HMC5843 chip */
+ hmc5843_init_client(client);
+
+ data->indio_dev = iio_allocate_device();
+ if (!data->indio_dev) {
+ err = -ENOMEM;
+ goto exit_free1;
+ }
+ data->indio_dev->attrs = &hmc5843_group;
+ data->indio_dev->dev.parent = &client->dev;
+ data->indio_dev->dev_data = (void *)(data);
+ data->indio_dev->driver_module = THIS_MODULE;
+ data->indio_dev->modes = INDIO_DIRECT_MODE;
+ err = iio_device_register(data->indio_dev);
+ if (err)
+ goto exit_free2;
+ return 0;
+exit_free2:
+ iio_free_device(data->indio_dev);
+exit_free1:
+ kfree(data);
+exit:
+ return err;
+}
+
+static int hmc5843_remove(struct i2c_client *client)
+{
+ struct hmc5843_data *data = i2c_get_clientdata(client);
+ /* sleep mode to save power */
+ hmc5843_configure(client, MODE_SLEEP);
+ iio_device_unregister(data->indio_dev);
+ kfree(i2c_get_clientdata(client));
+ return 0;
+}
+
+static int hmc5843_suspend(struct i2c_client *client, pm_message_t mesg)
+{
+ hmc5843_configure(client, MODE_SLEEP);
+ return 0;
+}
+
+static int hmc5843_resume(struct i2c_client *client)
+{
+ struct hmc5843_data *data = i2c_get_clientdata(client);
+ hmc5843_configure(client, data->operating_mode);
+ return 0;
+}
+
+static const struct i2c_device_id hmc5843_id[] = {
+ { "hmc5843", 0 },
+ { }
+};
+
+static struct i2c_driver hmc5843_driver = {
+ .driver = {
+ .name = "hmc5843",
+ },
+ .id_table = hmc5843_id,
+ .probe = hmc5843_probe,
+ .remove = hmc5843_remove,
+ .detect = hmc5843_detect,
+ .address_list = normal_i2c,
+ .suspend = hmc5843_suspend,
+ .resume = hmc5843_resume,
+};
+
+static int __init hmc5843_init(void)
+{
+ return i2c_add_driver(&hmc5843_driver);
+}
+
+static void __exit hmc5843_exit(void)
+{
+ i2c_del_driver(&hmc5843_driver);
+}
+
+MODULE_AUTHOR("Shubhrajyoti Datta <shubhrajyoti@ti.com");
+MODULE_DESCRIPTION("HMC5843 driver");
+MODULE_LICENSE("GPL");
+
+module_init(hmc5843_init);
+module_exit(hmc5843_exit);
diff --git a/drivers/staging/iio/ring_generic.h b/drivers/staging/iio/ring_generic.h
index 0e443757b02..a872d3904a3 100644
--- a/drivers/staging/iio/ring_generic.h
+++ b/drivers/staging/iio/ring_generic.h
@@ -11,6 +11,8 @@
#define _IIO_RING_GENERIC_H_
#include "iio.h"
+#ifdef CONFIG_IIO_RING_BUFFER
+
struct iio_handler;
struct iio_ring_buffer;
struct iio_dev;
@@ -98,6 +100,7 @@ struct iio_ring_access_funcs {
* @access_id: device id number
* @length: [DEVICE] number of datums in ring
* @bpd: [DEVICE] size of individual datum including timestamp
+ * @bpe: [DEVICE] size of individual channel value
* @loopcount: [INTERN] number of times the ring has looped
* @access_handler: [INTERN] chrdev access handling
* @ev_int: [INTERN] chrdev interface for the event chrdev
@@ -119,6 +122,7 @@ struct iio_ring_buffer {
int access_id;
int length;
int bpd;
+ int bpe;
int loopcount;
struct iio_handler access_handler;
struct iio_event_interface ev_int;
@@ -213,7 +217,7 @@ ssize_t iio_scan_el_ts_show(struct device *dev, struct device_attribute *attr,
* @_label: indentification variable used by drivers. Often a reg address.
* @_controlfunc: function used to notify hardware of whether state changes
**/
-#define IIO_SCAN_EL_C(_name, _number, _bits, _label, _controlfunc) \
+#define __IIO_SCAN_EL_C(_name, _number, _bits, _label, _controlfunc) \
struct iio_scan_el iio_scan_el_##_name = { \
.dev_attr = __ATTR(_number##_##_name##_en, \
S_IRUGO | S_IWUSR, \
@@ -225,7 +229,10 @@ ssize_t iio_scan_el_ts_show(struct device *dev, struct device_attribute *attr,
.set_state = _controlfunc, \
}
-#define IIO_SCAN_NAMED_EL_C(_name, _string, _number, _bits, _label, _cf) \
+#define IIO_SCAN_EL_C(_name, _number, _bits, _label, _controlfunc) \
+ __IIO_SCAN_EL_C(_name, _number, _bits, _label, _controlfunc)
+
+#define __IIO_SCAN_NAMED_EL_C(_name, _string, _number, _bits, _label, _cf) \
struct iio_scan_el iio_scan_el_##_name = { \
.dev_attr = __ATTR(_number##_##_string##_en, \
S_IRUGO | S_IWUSR, \
@@ -236,7 +243,8 @@ ssize_t iio_scan_el_ts_show(struct device *dev, struct device_attribute *attr,
.label = _label, \
.set_state = _cf, \
}
-
+#define IIO_SCAN_NAMED_EL_C(_name, _string, _number, _bits, _label, _cf) \
+ __IIO_SCAN_NAMED_EL_C(_name, _string, _number, _bits, _label, _cf)
/**
* IIO_SCAN_EL_TIMESTAMP - declare a special scan element for timestamps
*
@@ -287,5 +295,14 @@ ssize_t iio_show_ring_enable(struct device *dev,
#define IIO_RING_ENABLE_ATTR DEVICE_ATTR(ring_enable, S_IRUGO | S_IWUSR, \
iio_show_ring_enable, \
iio_store_ring_enable)
+#else /* CONFIG_IIO_RING_BUFFER */
+static inline int iio_ring_buffer_register(struct iio_ring_buffer *ring, int id)
+{
+ return 0;
+};
+static inline void iio_ring_buffer_unregister(struct iio_ring_buffer *ring)
+{};
+
+#endif /* CONFIG_IIO_RING_BUFFER */
#endif /* _IIO_RING_GENERIC_H_ */
diff --git a/drivers/staging/iio/ring_sw.c b/drivers/staging/iio/ring_sw.c
index 294272d0619..e2f01c640ba 100644
--- a/drivers/staging/iio/ring_sw.c
+++ b/drivers/staging/iio/ring_sw.c
@@ -13,6 +13,7 @@
#include <linux/device.h>
#include <linux/workqueue.h>
#include "ring_sw.h"
+#include "trigger.h"
static inline int __iio_allocate_sw_ring_buffer(struct iio_sw_ring_buffer *ring,
int bytes_per_datum, int length)
@@ -431,5 +432,73 @@ void iio_sw_rb_free(struct iio_ring_buffer *r)
iio_put_ring_buffer(r);
}
EXPORT_SYMBOL(iio_sw_rb_free);
+
+int iio_sw_ring_preenable(struct iio_dev *indio_dev)
+{
+ size_t size;
+ dev_dbg(&indio_dev->dev, "%s\n", __func__);
+ /* Check if there are any scan elements enabled, if not fail*/
+ if (!(indio_dev->scan_count || indio_dev->scan_timestamp))
+ return -EINVAL;
+ if (indio_dev->scan_timestamp)
+ if (indio_dev->scan_count)
+ /* Timestamp (aligned to s64) and data */
+ size = (((indio_dev->scan_count * indio_dev->ring->bpe)
+ + sizeof(s64) - 1)
+ & ~(sizeof(s64) - 1))
+ + sizeof(s64);
+ else /* Timestamp only */
+ size = sizeof(s64);
+ else /* Data only */
+ size = indio_dev->scan_count * indio_dev->ring->bpe;
+ indio_dev->ring->access.set_bpd(indio_dev->ring, size);
+
+ return 0;
+}
+EXPORT_SYMBOL(iio_sw_ring_preenable);
+
+void iio_sw_trigger_bh_to_ring(struct work_struct *work_s)
+{
+ struct iio_sw_ring_helper_state *st
+ = container_of(work_s, struct iio_sw_ring_helper_state,
+ work_trigger_to_ring);
+ int len = 0;
+ size_t datasize = st->indio_dev
+ ->ring->access.get_bpd(st->indio_dev->ring);
+ char *data = kmalloc(datasize, GFP_KERNEL);
+
+ if (data == NULL) {
+ dev_err(st->indio_dev->dev.parent,
+ "memory alloc failed in ring bh");
+ return;
+ }
+
+ if (st->indio_dev->scan_count)
+ len = st->get_ring_element(st, data);
+
+ /* Guaranteed to be aligned with 8 byte boundary */
+ if (st->indio_dev->scan_timestamp)
+ *(s64 *)(((phys_addr_t)data + len
+ + sizeof(s64) - 1) & ~(sizeof(s64) - 1))
+ = st->last_timestamp;
+ st->indio_dev->ring->access.store_to(st->indio_dev->ring,
+ (u8 *)data,
+ st->last_timestamp);
+
+ iio_trigger_notify_done(st->indio_dev->trig);
+ kfree(data);
+
+ return;
+}
+EXPORT_SYMBOL(iio_sw_trigger_bh_to_ring);
+
+void iio_sw_poll_func_th(struct iio_dev *indio_dev, s64 time)
+{ struct iio_sw_ring_helper_state *h
+ = iio_dev_get_devdata(indio_dev);
+ h->last_timestamp = time;
+ schedule_work(&h->work_trigger_to_ring);
+}
+EXPORT_SYMBOL(iio_sw_poll_func_th);
+
MODULE_DESCRIPTION("Industrialio I/O software ring buffer");
MODULE_LICENSE("GPL");
diff --git a/drivers/staging/iio/ring_sw.h b/drivers/staging/iio/ring_sw.h
index fd677f00836..61f1ed65039 100644
--- a/drivers/staging/iio/ring_sw.h
+++ b/drivers/staging/iio/ring_sw.h
@@ -207,10 +207,21 @@ struct iio_sw_ring_buffer {
struct iio_ring_buffer *iio_sw_rb_allocate(struct iio_dev *indio_dev);
void iio_sw_rb_free(struct iio_ring_buffer *ring);
+int iio_sw_ring_preenable(struct iio_dev *indio_dev);
+struct iio_sw_ring_helper_state {
+ struct work_struct work_trigger_to_ring;
+ struct iio_dev *indio_dev;
+ int (*get_ring_element)(struct iio_sw_ring_helper_state *st, u8 *buf);
+ s64 last_timestamp;
+};
+
+void iio_sw_poll_func_th(struct iio_dev *indio_dev, s64 time);
+void iio_sw_trigger_bh_to_ring(struct work_struct *work_s);
#else /* CONFIG_IIO_RING_BUFFER*/
-static inline void iio_ring_sw_register_funcs(struct iio_ring_access_funcs *ra)
-{};
+struct iio_sw_ring_helper_state {
+ struct iio_dev *indio_dev;
+};
#endif /* !CONFIG_IIO_RING_BUFFER */
#endif /* _IIO_RING_SW_H_ */
diff --git a/drivers/staging/iio/sysfs.h b/drivers/staging/iio/sysfs.h
index afcf5ab85f4..60834162eb3 100644
--- a/drivers/staging/iio/sysfs.h
+++ b/drivers/staging/iio/sysfs.h
@@ -284,6 +284,14 @@ struct iio_const_attr {
.mask = _mask, \
.listel = &_ev_list };
+#define IIO_EVENT_ATTR_NAMED_SH(_vname, _name, _ev_list, _show, _store, _mask) \
+ static struct iio_event_attr \
+ iio_event_attr_##_vname \
+ = { .dev_attr = __ATTR(_name, S_IRUGO | S_IWUSR, \
+ _show, _store), \
+ .mask = _mask, \
+ .listel = &_ev_list };
+
/**
* IIO_EVENT_ATTR - non-shared event attribute
* @_name: event name
@@ -293,10 +301,7 @@ struct iio_const_attr {
* @_handler: handler function to be called
**/
#define IIO_EVENT_ATTR(_name, _show, _store, _mask, _handler) \
- static struct iio_event_handler_list \
- iio_event_##_name = { \
- .handler = _handler, \
- }; \
+ IIO_EVENT_SH(_name, _handler); \
static struct \
iio_event_attr \
iio_event_attr_##_name \
@@ -324,6 +329,7 @@ struct iio_const_attr {
#define IIO_EVENT_CODE_GYRO_BASE 400
#define IIO_EVENT_CODE_ADC_BASE 500
#define IIO_EVENT_CODE_MISC_BASE 600
+#define IIO_EVENT_CODE_LIGHT_BASE 700
#define IIO_EVENT_CODE_DEVICE_SPECIFIC 1000
diff --git a/drivers/staging/iio/trigger.h b/drivers/staging/iio/trigger.h
index 784e7b6fac1..4699586a593 100644
--- a/drivers/staging/iio/trigger.h
+++ b/drivers/staging/iio/trigger.h
@@ -8,10 +8,6 @@
*/
#ifndef _IIO_TRIGGER_H_
#define _IIO_TRIGGER_H_
-#define IIO_TRIGGER_NAME_LENGTH 20
-#define IIO_TRIGGER_ID_PREFIX "iio:trigger"
-#define IIO_TRIGGER_ID_FORMAT IIO_TRIGGER_ID_PREFIX "%d"
-
/**
* struct iio_trigger - industrial I/O trigger device
@@ -25,7 +21,6 @@
* @pollfunc_list_lock: [INTERN] protection of the polling function list
* @pollfunc_list: [INTERN] list of functions to run on trigger.
* @control_attrs: [DRIVER] sysfs attributes relevant to trigger type
- * @timestamp: [INTERN] timestamp usesd by some trigs (e.g. datardy)
* @owner: [DRIVER] used to monitor usage count of the trigger.
* @use_count: use count for the trigger
* @set_trigger_state: [DRIVER] switch on/off the trigger on demand
@@ -43,7 +38,6 @@ struct iio_trigger {
spinlock_t pollfunc_list_lock;
struct list_head pollfunc_list;
const struct attribute_group *control_attrs;
- s64 timestamp;
struct module *owner;
int use_count;
@@ -124,7 +118,7 @@ int iio_trigger_dettach_poll_func(struct iio_trigger *trig,
*
* Typically called in relevant hardware interrupt handler.
**/
-void iio_trigger_poll(struct iio_trigger *trig);
+void iio_trigger_poll(struct iio_trigger *trig, s64 time);
void iio_trigger_notify_done(struct iio_trigger *trig);
/**
@@ -148,13 +142,27 @@ struct iio_poll_func {
struct list_head list;
void *private_data;
void (*poll_func_immediate)(struct iio_dev *indio_dev);
- void (*poll_func_main)(struct iio_dev *private_data);
+ void (*poll_func_main)(struct iio_dev *private_data, s64 time);
};
+int iio_alloc_pollfunc(struct iio_dev *indio_dev,
+ void (*immediate)(struct iio_dev *indio_dev),
+ void (*main)(struct iio_dev *private_data, s64 time));
+
+/*
+ * Two functions for common case where all that happens is a pollfunc
+ * is attached and detached form a trigger
+ */
+int iio_triggered_ring_postenable(struct iio_dev *indio_dev);
+int iio_triggered_ring_predisable(struct iio_dev *indio_dev);
+
struct iio_trigger *iio_allocate_trigger(void);
void iio_free_trigger(struct iio_trigger *trig);
+struct iio_simple_trigger {
+ struct iio_trigger trig;
+};
#endif /* _IIO_TRIGGER_H_ */
diff --git a/drivers/staging/iio/trigger/Makefile b/drivers/staging/iio/trigger/Makefile
index e5f96d2fe64..10aeca5e347 100644
--- a/drivers/staging/iio/trigger/Makefile
+++ b/drivers/staging/iio/trigger/Makefile
@@ -1,5 +1,6 @@
#
# Makefile for triggers not associated with iio-devices
#
+
obj-$(CONFIG_IIO_PERIODIC_RTC_TRIGGER) += iio-trig-periodic-rtc.o
-obj-$(CONFIG_IIO_GPIO_TRIGGER) += iio-trig-gpio.o \ No newline at end of file
+obj-$(CONFIG_IIO_GPIO_TRIGGER) += iio-trig-gpio.o
diff --git a/drivers/staging/iio/trigger/iio-trig-gpio.c b/drivers/staging/iio/trigger/iio-trig-gpio.c
index 1da285d2863..f93cc916983 100644
--- a/drivers/staging/iio/trigger/iio-trig-gpio.c
+++ b/drivers/staging/iio/trigger/iio-trig-gpio.c
@@ -42,7 +42,8 @@ struct iio_gpio_trigger_info {
static irqreturn_t iio_gpio_trigger_poll(int irq, void *private)
{
- iio_trigger_poll(private);
+ /* Timestamp not currently provided */
+ iio_trigger_poll(private, 0);
return IRQ_HANDLED;
}
@@ -93,16 +94,11 @@ static int iio_gpio_trigger_probe(struct platform_device *pdev)
trig->private_data = trig_info;
trig_info->irq = irq;
trig->owner = THIS_MODULE;
- trig->name = kmalloc(IIO_TRIGGER_NAME_LENGTH,
- GFP_KERNEL);
- if (!trig->name) {
+ trig->name = kasprintf(GFP_KERNEL, "irqtrig%d", irq);
+ if (trig->name == NULL) {
ret = -ENOMEM;
goto error_free_trig_info;
}
- snprintf((char *)trig->name,
- IIO_TRIGGER_NAME_LENGTH,
- "irqtrig%d", irq);
-
ret = request_irq(irq, iio_gpio_trigger_poll,
irqflags, trig->name, trig);
if (ret) {
diff --git a/drivers/staging/iio/trigger/iio-trig-periodic-rtc.c b/drivers/staging/iio/trigger/iio-trig-periodic-rtc.c
index 4ee3ae1ef89..b0b52f84edf 100644
--- a/drivers/staging/iio/trigger/iio-trig-periodic-rtc.c
+++ b/drivers/staging/iio/trigger/iio-trig-periodic-rtc.c
@@ -25,7 +25,6 @@ static DEFINE_MUTEX(iio_prtc_trigger_list_lock);
struct iio_prtc_trigger_info {
struct rtc_device *rtc;
int frequency;
- char *name;
struct rtc_task task;
};
@@ -78,8 +77,7 @@ static ssize_t iio_trig_periodic_read_name(struct device *dev,
char *buf)
{
struct iio_trigger *trig = dev_get_drvdata(dev);
- struct iio_prtc_trigger_info *trig_info = trig->private_data;
- return sprintf(buf, "%s\n", trig_info->name);
+ return sprintf(buf, "%s\n", trig->name);
}
static DEVICE_ATTR(name, S_IRUGO,
@@ -100,7 +98,8 @@ static const struct attribute_group iio_trig_prtc_attr_group = {
static void iio_prtc_trigger_poll(void *private_data)
{
- iio_trigger_poll(private_data);
+ /* Timestamp is not provided currently */
+ iio_trigger_poll(private_data, 0);
}
static int iio_trig_periodic_rtc_probe(struct platform_device *dev)
@@ -129,16 +128,12 @@ static int iio_trig_periodic_rtc_probe(struct platform_device *dev)
trig->private_data = trig_info;
trig->owner = THIS_MODULE;
trig->set_trigger_state = &iio_trig_periodic_rtc_set_state;
- trig->name = kmalloc(IIO_TRIGGER_NAME_LENGTH, GFP_KERNEL);
+ trig->name = kasprintf(GFP_KERNEL, "periodic%s", pdata[i]);
if (trig->name == NULL) {
ret = -ENOMEM;
goto error_free_trig_info;
}
- snprintf((char *)trig->name,
- IIO_TRIGGER_NAME_LENGTH,
- "periodic%s",
- pdata[i]);
- trig_info->name = (char *)trig->name;
+
/* RTC access */
trig_info->rtc
= rtc_class_open(pdata[i]);
diff --git a/drivers/staging/line6/Kconfig b/drivers/staging/line6/Kconfig
index 7852d4a960c..bc1ffbed3c8 100644
--- a/drivers/staging/line6/Kconfig
+++ b/drivers/staging/line6/Kconfig
@@ -2,6 +2,7 @@ config LINE6_USB
tristate "Line6 USB support"
depends on USB && SND
select SND_RAWMIDI
+ select SND_PCM
help
This is a driver for the guitar amp, cab, and effects modeller
PODxt Pro by Line6 (and similar devices), supporting the
diff --git a/drivers/staging/line6/driver.c b/drivers/staging/line6/driver.c
index 1d5a4730276..27b986a50a0 100644
--- a/drivers/staging/line6/driver.c
+++ b/drivers/staging/line6/driver.c
@@ -679,8 +679,10 @@ static int line6_probe(struct usb_interface *interface, const struct usb_device_
usb_get_dev(usbdev);
/* we don't handle multiple configurations */
- if (usbdev->descriptor.bNumConfigurations != 1)
- return -ENODEV;
+ if (usbdev->descriptor.bNumConfigurations != 1) {
+ ret = -ENODEV;
+ goto err_put;
+ }
/* check vendor and product id */
for (devtype = ARRAY_SIZE(line6_id_table) - 1; devtype--;) {
@@ -692,16 +694,20 @@ static int line6_probe(struct usb_interface *interface, const struct usb_device_
break;
}
- if (devtype < 0)
- return -ENODEV;
+ if (devtype < 0) {
+ ret = -ENODEV;
+ goto err_put;
+ }
/* find free slot in device table: */
for (devnum = 0; devnum < LINE6_MAX_DEVICES; ++devnum)
if (line6_devices[devnum] == NULL)
break;
- if (devnum == LINE6_MAX_DEVICES)
- return -ENODEV;
+ if (devnum == LINE6_MAX_DEVICES) {
+ ret = -ENODEV;
+ goto err_put;
+ }
/* initialize device info: */
properties = &line6_properties_table[devtype];
@@ -762,13 +768,14 @@ static int line6_probe(struct usb_interface *interface, const struct usb_device_
default:
MISSING_CASE;
- return -ENODEV;
+ ret = -ENODEV;
+ goto err_put;
}
ret = usb_set_interface(usbdev, interface_number, alternate);
if (ret < 0) {
dev_err(&interface->dev, "set_interface failed\n");
- return ret;
+ goto err_put;
}
/* initialize device data based on product id: */
@@ -815,7 +822,8 @@ static int line6_probe(struct usb_interface *interface, const struct usb_device_
break;
default:
- return -ENODEV;
+ ret = -ENODEV;
+ goto err_put;
}
break;
@@ -827,19 +835,22 @@ static int line6_probe(struct usb_interface *interface, const struct usb_device_
default:
MISSING_CASE;
- return -ENODEV;
+ ret = -ENODEV;
+ goto err_put;
}
if (size == 0) {
dev_err(line6->ifcdev, "driver bug: interface data size not set\n");
- return -ENODEV;
+ ret = -ENODEV;
+ goto err_put;
}
line6 = kzalloc(size, GFP_KERNEL);
if (line6 == NULL) {
dev_err(&interface->dev, "Out of memory\n");
- return -ENOMEM;
+ ret = -ENODEV;
+ goto err_put;
}
/* store basic data: */
@@ -875,16 +886,16 @@ static int line6_probe(struct usb_interface *interface, const struct usb_device_
if (line6->buffer_listen == NULL) {
dev_err(&interface->dev, "Out of memory\n");
- line6_destruct(interface);
- return -ENOMEM;
+ ret = -ENOMEM;
+ goto err_destruct;
}
line6->buffer_message = kmalloc(LINE6_MESSAGE_MAXLEN, GFP_KERNEL);
if (line6->buffer_message == NULL) {
dev_err(&interface->dev, "Out of memory\n");
- line6_destruct(interface);
- return -ENOMEM;
+ ret = -ENOMEM;
+ goto err_destruct;
}
line6->urb_listen = usb_alloc_urb(0, GFP_KERNEL);
@@ -892,15 +903,15 @@ static int line6_probe(struct usb_interface *interface, const struct usb_device_
if (line6->urb_listen == NULL) {
dev_err(&interface->dev, "Out of memory\n");
line6_destruct(interface);
- return -ENOMEM;
+ ret = -ENOMEM;
+ goto err_destruct;
}
ret = line6_start_listen(line6);
if (ret < 0) {
dev_err(&interface->dev, "%s: usb_submit_urb failed\n",
__func__);
- line6_destruct(interface);
- return ret;
+ goto err_destruct;
}
}
@@ -952,22 +963,25 @@ static int line6_probe(struct usb_interface *interface, const struct usb_device_
ret = -ENODEV;
}
- if (ret < 0) {
- line6_destruct(interface);
- return ret;
- }
+ if (ret < 0)
+ goto err_destruct;
ret = sysfs_create_link(&interface->dev.kobj, &usbdev->dev.kobj,
"usb_device");
- if (ret < 0) {
- line6_destruct(interface);
- return ret;
- }
+ if (ret < 0)
+ goto err_destruct;
dev_info(&interface->dev, "Line6 %s now attached\n",
line6->properties->name);
line6_devices[devnum] = line6;
line6_list_devices();
+ return 0;
+
+err_destruct:
+ line6_destruct(interface);
+err_put:
+ usb_put_intf(interface);
+ usb_put_dev(usbdev);
return ret;
}
diff --git a/drivers/staging/lirc/Kconfig b/drivers/staging/lirc/Kconfig
new file mode 100644
index 00000000000..968c2adee06
--- /dev/null
+++ b/drivers/staging/lirc/Kconfig
@@ -0,0 +1,110 @@
+#
+# LIRC driver(s) configuration
+#
+menuconfig LIRC_STAGING
+ bool "Linux Infrared Remote Control IR receiver/transmitter drivers"
+ help
+ Say Y here, and all supported Linux Infrared Remote Control IR and
+ RF receiver and transmitter drivers will be displayed. When paired
+ with a remote control and the lirc daemon, the receiver drivers
+ allow control of your Linux system via remote control.
+
+if LIRC_STAGING
+
+config LIRC_BT829
+ tristate "BT829 based hardware"
+ depends on LIRC_STAGING
+ help
+ Driver for the IR interface on BT829-based hardware
+
+config LIRC_ENE0100
+ tristate "ENE KB3924/ENE0100 CIR Port Reciever"
+ depends on LIRC_STAGING
+ help
+ This is a driver for CIR port handled by ENE KB3924 embedded
+ controller found on some notebooks.
+ It appears on PNP list as ENE0100.
+
+config LIRC_I2C
+ tristate "I2C Based IR Receivers"
+ depends on LIRC_STAGING
+ help
+ Driver for I2C-based IR receivers, such as those commonly
+ found onboard Hauppauge PVR-150/250/350 video capture cards
+
+config LIRC_IGORPLUGUSB
+ tristate "Igor Cesko's USB IR Receiver"
+ depends on LIRC_STAGING && USB
+ help
+ Driver for Igor Cesko's USB IR Receiver
+
+config LIRC_IMON
+ tristate "Legacy SoundGraph iMON Receiver and Display"
+ depends on LIRC_STAGING
+ help
+ Driver for the original SoundGraph iMON IR Receiver and Display
+
+ Current generation iMON devices use the input layer imon driver.
+
+config LIRC_IT87
+ tristate "ITE IT87XX CIR Port Receiver"
+ depends on LIRC_STAGING
+ help
+ Driver for the ITE IT87xx IR Receiver
+
+config LIRC_ITE8709
+ tristate "ITE8709 CIR Port Receiver"
+ depends on LIRC_STAGING && PNP
+ help
+ Driver for the ITE8709 IR Receiver
+
+config LIRC_PARALLEL
+ tristate "Homebrew Parallel Port Receiver"
+ depends on LIRC_STAGING && !SMP
+ help
+ Driver for Homebrew Parallel Port Receivers
+
+config LIRC_SASEM
+ tristate "Sasem USB IR Remote"
+ depends on LIRC_STAGING
+ help
+ Driver for the Sasem OnAir Remocon-V or Dign HV5 HTPC IR/VFD Module
+
+config LIRC_SERIAL
+ tristate "Homebrew Serial Port Receiver"
+ depends on LIRC_STAGING
+ help
+ Driver for Homebrew Serial Port Receivers
+
+config LIRC_SERIAL_TRANSMITTER
+ bool "Serial Port Transmitter"
+ default y
+ depends on LIRC_SERIAL
+ help
+ Serial Port Transmitter support
+
+config LIRC_SIR
+ tristate "Built-in SIR IrDA port"
+ depends on LIRC_STAGING
+ help
+ Driver for the SIR IrDA port
+
+config LIRC_STREAMZAP
+ tristate "Streamzap PC Receiver"
+ depends on LIRC_STAGING
+ help
+ Driver for the Streamzap PC Receiver
+
+config LIRC_TTUSBIR
+ tristate "Technotrend USB IR Receiver"
+ depends on LIRC_STAGING && USB
+ help
+ Driver for the Technotrend USB IR Receiver
+
+config LIRC_ZILOG
+ tristate "Zilog/Hauppauge IR Transmitter"
+ depends on LIRC_STAGING
+ help
+ Driver for the Zilog/Hauppauge IR Transmitter, found on
+ PVR-150/500, HVR-1200/1250/1700/1800, HD-PVR and other cards
+endif
diff --git a/drivers/staging/lirc/Makefile b/drivers/staging/lirc/Makefile
new file mode 100644
index 00000000000..a019182a7a3
--- /dev/null
+++ b/drivers/staging/lirc/Makefile
@@ -0,0 +1,19 @@
+# Makefile for the lirc drivers.
+#
+
+# Each configuration option enables a list of files.
+
+obj-$(CONFIG_LIRC_BT829) += lirc_bt829.o
+obj-$(CONFIG_LIRC_ENE0100) += lirc_ene0100.o
+obj-$(CONFIG_LIRC_I2C) += lirc_i2c.o
+obj-$(CONFIG_LIRC_IGORPLUGUSB) += lirc_igorplugusb.o
+obj-$(CONFIG_LIRC_IMON) += lirc_imon.o
+obj-$(CONFIG_LIRC_IT87) += lirc_it87.o
+obj-$(CONFIG_LIRC_ITE8709) += lirc_ite8709.o
+obj-$(CONFIG_LIRC_PARALLEL) += lirc_parallel.o
+obj-$(CONFIG_LIRC_SASEM) += lirc_sasem.o
+obj-$(CONFIG_LIRC_SERIAL) += lirc_serial.o
+obj-$(CONFIG_LIRC_SIR) += lirc_sir.o
+obj-$(CONFIG_LIRC_STREAMZAP) += lirc_streamzap.o
+obj-$(CONFIG_LIRC_TTUSBIR) += lirc_ttusbir.o
+obj-$(CONFIG_LIRC_ZILOG) += lirc_zilog.o
diff --git a/drivers/staging/lirc/TODO b/drivers/staging/lirc/TODO
new file mode 100644
index 00000000000..b6cb593f55c
--- /dev/null
+++ b/drivers/staging/lirc/TODO
@@ -0,0 +1,8 @@
+- All drivers should either be ported to ir-core, or dropped entirely
+ (see drivers/media/IR/mceusb.c vs. lirc_mceusb.c in lirc cvs for an
+ example of a previously completed port).
+
+Please send patches to:
+Jarod Wilson <jarod@wilsonet.com>
+Greg Kroah-Hartman <greg@kroah.com>
+
diff --git a/drivers/staging/lirc/TODO.lirc_i2c b/drivers/staging/lirc/TODO.lirc_i2c
new file mode 100644
index 00000000000..1f0a6ff6543
--- /dev/null
+++ b/drivers/staging/lirc/TODO.lirc_i2c
@@ -0,0 +1,3 @@
+lirc_i2c provides support for some drivers that have already a RC
+driver under drivers/media/video. It should be integrated into those
+drivers, in special with drivers/media/video/ir-kbd-i2c.c.
diff --git a/drivers/staging/lirc/lirc_bt829.c b/drivers/staging/lirc/lirc_bt829.c
new file mode 100644
index 00000000000..33881025426
--- /dev/null
+++ b/drivers/staging/lirc/lirc_bt829.c
@@ -0,0 +1,383 @@
+/*
+ * Remote control driver for the TV-card based on bt829
+ *
+ * by Leonid Froenchenko <lfroen@galileo.co.il>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/threads.h>
+#include <linux/sched.h>
+#include <linux/ioport.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+
+#include <media/lirc_dev.h>
+
+static int poll_main(void);
+static int atir_init_start(void);
+
+static void write_index(unsigned char index, unsigned int value);
+static unsigned int read_index(unsigned char index);
+
+static void do_i2c_start(void);
+static void do_i2c_stop(void);
+
+static void seems_wr_byte(unsigned char al);
+static unsigned char seems_rd_byte(void);
+
+static unsigned int read_index(unsigned char al);
+static void write_index(unsigned char ah, unsigned int edx);
+
+static void cycle_delay(int cycle);
+
+static void do_set_bits(unsigned char bl);
+static unsigned char do_get_bits(void);
+
+#define DATA_PCI_OFF 0x7FFC00
+#define WAIT_CYCLE 20
+
+#define DRIVER_NAME "lirc_bt829"
+
+static int debug;
+#define dprintk(fmt, args...) \
+ do { \
+ if (debug) \
+ printk(KERN_DEBUG DRIVER_NAME ": "fmt, ## args); \
+ } while (0)
+
+static int atir_minor;
+static unsigned long pci_addr_phys;
+static unsigned char *pci_addr_lin;
+
+static struct lirc_driver atir_driver;
+
+static struct pci_dev *do_pci_probe(void)
+{
+ struct pci_dev *my_dev;
+ my_dev = pci_get_device(PCI_VENDOR_ID_ATI,
+ PCI_DEVICE_ID_ATI_264VT, NULL);
+ if (my_dev) {
+ printk(KERN_ERR DRIVER_NAME ": Using device: %s\n",
+ pci_name(my_dev));
+ pci_addr_phys = 0;
+ if (my_dev->resource[0].flags & IORESOURCE_MEM) {
+ pci_addr_phys = my_dev->resource[0].start;
+ printk(KERN_INFO DRIVER_NAME ": memory at 0x%08X\n",
+ (unsigned int)pci_addr_phys);
+ }
+ if (pci_addr_phys == 0) {
+ printk(KERN_ERR DRIVER_NAME ": no memory resource ?\n");
+ return NULL;
+ }
+ } else {
+ printk(KERN_ERR DRIVER_NAME ": pci_probe failed\n");
+ return NULL;
+ }
+ return my_dev;
+}
+
+static int atir_add_to_buf(void *data, struct lirc_buffer *buf)
+{
+ unsigned char key;
+ int status;
+ status = poll_main();
+ key = (status >> 8) & 0xFF;
+ if (status & 0xFF) {
+ dprintk("reading key %02X\n", key);
+ lirc_buffer_write(buf, &key);
+ return 0;
+ }
+ return -ENODATA;
+}
+
+static int atir_set_use_inc(void *data)
+{
+ dprintk("driver is opened\n");
+ return 0;
+}
+
+static void atir_set_use_dec(void *data)
+{
+ dprintk("driver is closed\n");
+}
+
+int init_module(void)
+{
+ struct pci_dev *pdev;
+
+ pdev = do_pci_probe();
+ if (pdev == NULL)
+ return 1;
+
+ if (!atir_init_start())
+ return 1;
+
+ strcpy(atir_driver.name, "ATIR");
+ atir_driver.minor = -1;
+ atir_driver.code_length = 8;
+ atir_driver.sample_rate = 10;
+ atir_driver.data = 0;
+ atir_driver.add_to_buf = atir_add_to_buf;
+ atir_driver.set_use_inc = atir_set_use_inc;
+ atir_driver.set_use_dec = atir_set_use_dec;
+ atir_driver.dev = &pdev->dev;
+ atir_driver.owner = THIS_MODULE;
+
+ atir_minor = lirc_register_driver(&atir_driver);
+ if (atir_minor < 0) {
+ printk(KERN_ERR DRIVER_NAME ": failed to register driver!\n");
+ return atir_minor;
+ }
+ dprintk("driver is registered on minor %d\n", atir_minor);
+
+ return 0;
+}
+
+
+void cleanup_module(void)
+{
+ lirc_unregister_driver(atir_minor);
+}
+
+
+static int atir_init_start(void)
+{
+ pci_addr_lin = ioremap(pci_addr_phys + DATA_PCI_OFF, 0x400);
+ if (pci_addr_lin == 0) {
+ printk(KERN_INFO DRIVER_NAME ": pci mem must be mapped\n");
+ return 0;
+ }
+ return 1;
+}
+
+static void cycle_delay(int cycle)
+{
+ udelay(WAIT_CYCLE*cycle);
+}
+
+
+static int poll_main()
+{
+ unsigned char status_high, status_low;
+
+ do_i2c_start();
+
+ seems_wr_byte(0xAA);
+ seems_wr_byte(0x01);
+
+ do_i2c_start();
+
+ seems_wr_byte(0xAB);
+
+ status_low = seems_rd_byte();
+ status_high = seems_rd_byte();
+
+ do_i2c_stop();
+
+ return (status_high << 8) | status_low;
+}
+
+static void do_i2c_start(void)
+{
+ do_set_bits(3);
+ cycle_delay(4);
+
+ do_set_bits(1);
+ cycle_delay(7);
+
+ do_set_bits(0);
+ cycle_delay(2);
+}
+
+static void do_i2c_stop(void)
+{
+ unsigned char bits;
+ bits = do_get_bits() & 0xFD;
+ do_set_bits(bits);
+ cycle_delay(1);
+
+ bits |= 1;
+ do_set_bits(bits);
+ cycle_delay(2);
+
+ bits |= 2;
+ do_set_bits(bits);
+ bits = 3;
+ do_set_bits(bits);
+ cycle_delay(2);
+}
+
+static void seems_wr_byte(unsigned char value)
+{
+ int i;
+ unsigned char reg;
+
+ reg = do_get_bits();
+ for (i = 0; i < 8; i++) {
+ if (value & 0x80)
+ reg |= 0x02;
+ else
+ reg &= 0xFD;
+
+ do_set_bits(reg);
+ cycle_delay(1);
+
+ reg |= 1;
+ do_set_bits(reg);
+ cycle_delay(1);
+
+ reg &= 0xFE;
+ do_set_bits(reg);
+ cycle_delay(1);
+ value <<= 1;
+ }
+ cycle_delay(2);
+
+ reg |= 2;
+ do_set_bits(reg);
+
+ reg |= 1;
+ do_set_bits(reg);
+
+ cycle_delay(1);
+ do_get_bits();
+
+ reg &= 0xFE;
+ do_set_bits(reg);
+ cycle_delay(3);
+}
+
+static unsigned char seems_rd_byte(void)
+{
+ int i;
+ int rd_byte;
+ unsigned char bits_2, bits_1;
+
+ bits_1 = do_get_bits() | 2;
+ do_set_bits(bits_1);
+
+ rd_byte = 0;
+ for (i = 0; i < 8; i++) {
+ bits_1 &= 0xFE;
+ do_set_bits(bits_1);
+ cycle_delay(2);
+
+ bits_1 |= 1;
+ do_set_bits(bits_1);
+ cycle_delay(1);
+
+ bits_2 = do_get_bits();
+ if (bits_2 & 2)
+ rd_byte |= 1;
+
+ rd_byte <<= 1;
+ }
+
+ bits_1 = 0;
+ if (bits_2 == 0)
+ bits_1 |= 2;
+
+ do_set_bits(bits_1);
+ cycle_delay(2);
+
+ bits_1 |= 1;
+ do_set_bits(bits_1);
+ cycle_delay(3);
+
+ bits_1 &= 0xFE;
+ do_set_bits(bits_1);
+ cycle_delay(2);
+
+ rd_byte >>= 1;
+ rd_byte &= 0xFF;
+ return rd_byte;
+}
+
+static void do_set_bits(unsigned char new_bits)
+{
+ int reg_val;
+ reg_val = read_index(0x34);
+ if (new_bits & 2) {
+ reg_val &= 0xFFFFFFDF;
+ reg_val |= 1;
+ } else {
+ reg_val &= 0xFFFFFFFE;
+ reg_val |= 0x20;
+ }
+ reg_val |= 0x10;
+ write_index(0x34, reg_val);
+
+ reg_val = read_index(0x31);
+ if (new_bits & 1)
+ reg_val |= 0x1000000;
+ else
+ reg_val &= 0xFEFFFFFF;
+
+ reg_val |= 0x8000000;
+ write_index(0x31, reg_val);
+}
+
+static unsigned char do_get_bits(void)
+{
+ unsigned char bits;
+ int reg_val;
+
+ reg_val = read_index(0x34);
+ reg_val |= 0x10;
+ reg_val &= 0xFFFFFFDF;
+ write_index(0x34, reg_val);
+
+ reg_val = read_index(0x34);
+ bits = 0;
+ if (reg_val & 8)
+ bits |= 2;
+ else
+ bits &= 0xFD;
+
+ reg_val = read_index(0x31);
+ if (reg_val & 0x1000000)
+ bits |= 1;
+ else
+ bits &= 0xFE;
+
+ return bits;
+}
+
+static unsigned int read_index(unsigned char index)
+{
+ unsigned char *addr;
+ unsigned int value;
+ /* addr = pci_addr_lin + DATA_PCI_OFF + ((index & 0xFF) << 2); */
+ addr = pci_addr_lin + ((index & 0xFF) << 2);
+ value = readl(addr);
+ return value;
+}
+
+static void write_index(unsigned char index, unsigned int reg_val)
+{
+ unsigned char *addr;
+ addr = pci_addr_lin + ((index & 0xFF) << 2);
+ writel(reg_val, addr);
+}
+
+MODULE_AUTHOR("Froenchenko Leonid");
+MODULE_DESCRIPTION("IR remote driver for bt829 based TV cards");
+MODULE_LICENSE("GPL");
+
+module_param(debug, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug, "Debug enabled or not");
diff --git a/drivers/staging/lirc/lirc_ene0100.c b/drivers/staging/lirc/lirc_ene0100.c
new file mode 100644
index 00000000000..a152c52b074
--- /dev/null
+++ b/drivers/staging/lirc/lirc_ene0100.c
@@ -0,0 +1,646 @@
+/*
+ * driver for ENE KB3926 B/C/D CIR (also known as ENE0100)
+ *
+ * Copyright (C) 2009 Maxim Levitsky <maximlevitsky@gmail.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/module.h>
+#include <linux/pnp.h>
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <linux/sched.h>
+#include "lirc_ene0100.h"
+
+static int sample_period = 75;
+static int enable_idle = 1;
+static int enable_learning;
+
+static void ene_set_idle(struct ene_device *dev, int idle);
+static void ene_set_inputs(struct ene_device *dev, int enable);
+
+/* read a hardware register */
+static u8 ene_hw_read_reg(struct ene_device *dev, u16 reg)
+{
+ outb(reg >> 8, dev->hw_io + ENE_ADDR_HI);
+ outb(reg & 0xFF, dev->hw_io + ENE_ADDR_LO);
+ return inb(dev->hw_io + ENE_IO);
+}
+
+/* write a hardware register */
+static void ene_hw_write_reg(struct ene_device *dev, u16 reg, u8 value)
+{
+ outb(reg >> 8, dev->hw_io + ENE_ADDR_HI);
+ outb(reg & 0xFF, dev->hw_io + ENE_ADDR_LO);
+ outb(value, dev->hw_io + ENE_IO);
+}
+
+/* change specific bits in hardware register */
+static void ene_hw_write_reg_mask(struct ene_device *dev,
+ u16 reg, u8 value, u8 mask)
+{
+ u8 regvalue;
+
+ outb(reg >> 8, dev->hw_io + ENE_ADDR_HI);
+ outb(reg & 0xFF, dev->hw_io + ENE_ADDR_LO);
+
+ regvalue = inb(dev->hw_io + ENE_IO) & ~mask;
+ regvalue |= (value & mask);
+ outb(regvalue, dev->hw_io + ENE_IO);
+}
+
+/* read irq status and ack it */
+static int ene_hw_irq_status(struct ene_device *dev, int *buffer_pointer)
+{
+ u8 irq_status;
+ u8 fw_flags1, fw_flags2;
+
+ fw_flags2 = ene_hw_read_reg(dev, ENE_FW2);
+
+ if (buffer_pointer)
+ *buffer_pointer = 4 * (fw_flags2 & ENE_FW2_BUF_HIGH);
+
+ if (dev->hw_revision < ENE_HW_C) {
+ irq_status = ene_hw_read_reg(dev, ENEB_IRQ_STATUS);
+
+ if (!(irq_status & ENEB_IRQ_STATUS_IR))
+ return 0;
+ ene_hw_write_reg(dev, ENEB_IRQ_STATUS,
+ irq_status & ~ENEB_IRQ_STATUS_IR);
+
+ /* rev B support only recieving */
+ return ENE_IRQ_RX;
+ }
+
+ irq_status = ene_hw_read_reg(dev, ENEC_IRQ);
+
+ if (!(irq_status & ENEC_IRQ_STATUS))
+ return 0;
+
+ /* original driver does that twice - a workaround ? */
+ ene_hw_write_reg(dev, ENEC_IRQ, irq_status & ~ENEC_IRQ_STATUS);
+ ene_hw_write_reg(dev, ENEC_IRQ, irq_status & ~ENEC_IRQ_STATUS);
+
+ /* clear unknown flag in F8F9 */
+ if (fw_flags2 & ENE_FW2_IRQ_CLR)
+ ene_hw_write_reg(dev, ENE_FW2, fw_flags2 & ~ENE_FW2_IRQ_CLR);
+
+ /* check if this is a TX interrupt */
+ fw_flags1 = ene_hw_read_reg(dev, ENE_FW1);
+
+ if (fw_flags1 & ENE_FW1_TXIRQ) {
+ ene_hw_write_reg(dev, ENE_FW1, fw_flags1 & ~ENE_FW1_TXIRQ);
+ return ENE_IRQ_TX;
+ } else
+ return ENE_IRQ_RX;
+}
+
+static int ene_hw_detect(struct ene_device *dev)
+{
+ u8 chip_major, chip_minor;
+ u8 hw_revision, old_ver;
+ u8 tmp;
+ u8 fw_capabilities;
+
+ tmp = ene_hw_read_reg(dev, ENE_HW_UNK);
+ ene_hw_write_reg(dev, ENE_HW_UNK, tmp & ~ENE_HW_UNK_CLR);
+
+ chip_major = ene_hw_read_reg(dev, ENE_HW_VER_MAJOR);
+ chip_minor = ene_hw_read_reg(dev, ENE_HW_VER_MINOR);
+
+ ene_hw_write_reg(dev, ENE_HW_UNK, tmp);
+ hw_revision = ene_hw_read_reg(dev, ENE_HW_VERSION);
+ old_ver = ene_hw_read_reg(dev, ENE_HW_VER_OLD);
+
+ if (hw_revision == 0xFF) {
+
+ ene_printk(KERN_WARNING, "device seems to be disabled\n");
+ ene_printk(KERN_WARNING,
+ "send a mail to lirc-list@lists.sourceforge.net\n");
+ ene_printk(KERN_WARNING, "please attach output of acpidump\n");
+
+ return -ENODEV;
+ }
+
+ if (chip_major == 0x33) {
+ ene_printk(KERN_WARNING, "chips 0x33xx aren't supported yet\n");
+ return -ENODEV;
+ }
+
+ if (chip_major == 0x39 && chip_minor == 0x26 && hw_revision == 0xC0) {
+ dev->hw_revision = ENE_HW_C;
+ ene_printk(KERN_WARNING,
+ "KB3926C detected, driver support is not complete!\n");
+
+ } else if (old_ver == 0x24 && hw_revision == 0xC0) {
+ dev->hw_revision = ENE_HW_B;
+ ene_printk(KERN_NOTICE, "KB3926B detected\n");
+ } else {
+ dev->hw_revision = ENE_HW_D;
+ ene_printk(KERN_WARNING,
+ "unknown ENE chip detected, assuming KB3926D\n");
+ ene_printk(KERN_WARNING, "driver support incomplete");
+
+ }
+
+ ene_printk(KERN_DEBUG, "chip is 0x%02x%02x - 0x%02x, 0x%02x\n",
+ chip_major, chip_minor, old_ver, hw_revision);
+
+
+ /* detect features hardware supports */
+
+ if (dev->hw_revision < ENE_HW_C)
+ return 0;
+
+ fw_capabilities = ene_hw_read_reg(dev, ENE_FW2);
+
+ dev->hw_gpio40_learning = fw_capabilities & ENE_FW2_GP40_AS_LEARN;
+ dev->hw_learning_and_tx_capable = fw_capabilities & ENE_FW2_LEARNING;
+
+ dev->hw_fan_as_normal_input = dev->hw_learning_and_tx_capable &&
+ fw_capabilities & ENE_FW2_FAN_AS_NRML_IN;
+
+ ene_printk(KERN_NOTICE, "hardware features:\n");
+ ene_printk(KERN_NOTICE,
+ "learning and tx %s, gpio40_learn %s, fan_in %s\n",
+ dev->hw_learning_and_tx_capable ? "on" : "off",
+ dev->hw_gpio40_learning ? "on" : "off",
+ dev->hw_fan_as_normal_input ? "on" : "off");
+
+ if (!dev->hw_learning_and_tx_capable && enable_learning)
+ enable_learning = 0;
+
+ if (dev->hw_learning_and_tx_capable) {
+ ene_printk(KERN_WARNING,
+ "Device supports transmitting, but the driver doesn't\n");
+ ene_printk(KERN_WARNING,
+ "due to lack of hardware to test against.\n");
+ ene_printk(KERN_WARNING,
+ "Send a mail to: lirc-list@lists.sourceforge.net\n");
+ }
+ return 0;
+}
+
+/* hardware initialization */
+static int ene_hw_init(void *data)
+{
+ u8 reg_value;
+ struct ene_device *dev = (struct ene_device *)data;
+ dev->in_use = 1;
+
+ if (dev->hw_revision < ENE_HW_C) {
+ ene_hw_write_reg(dev, ENEB_IRQ, dev->irq << 1);
+ ene_hw_write_reg(dev, ENEB_IRQ_UNK1, 0x01);
+ } else {
+ reg_value = ene_hw_read_reg(dev, ENEC_IRQ) & 0xF0;
+ reg_value |= ENEC_IRQ_UNK_EN;
+ reg_value &= ~ENEC_IRQ_STATUS;
+ reg_value |= (dev->irq & ENEC_IRQ_MASK);
+ ene_hw_write_reg(dev, ENEC_IRQ, reg_value);
+ ene_hw_write_reg(dev, ENE_TX_UNK1, 0x63);
+ }
+
+ ene_hw_write_reg(dev, ENE_CIR_CONF2, 0x00);
+ ene_set_inputs(dev, enable_learning);
+
+ /* set sampling period */
+ ene_hw_write_reg(dev, ENE_CIR_SAMPLE_PERIOD, sample_period);
+
+ /* ack any pending irqs - just in case */
+ ene_hw_irq_status(dev, NULL);
+
+ /* enter idle mode */
+ ene_set_idle(dev, 1);
+
+ /* enable firmware bits */
+ ene_hw_write_reg_mask(dev, ENE_FW1,
+ ENE_FW1_ENABLE | ENE_FW1_IRQ,
+ ENE_FW1_ENABLE | ENE_FW1_IRQ);
+ /* clear stats */
+ dev->sample = 0;
+ return 0;
+}
+
+/* this enables gpio40 signal, used if connected to wide band input*/
+static void ene_enable_gpio40(struct ene_device *dev, int enable)
+{
+ ene_hw_write_reg_mask(dev, ENE_CIR_CONF1, enable ?
+ 0 : ENE_CIR_CONF2_GPIO40DIS,
+ ENE_CIR_CONF2_GPIO40DIS);
+}
+
+/* this enables the classic sampler */
+static void ene_enable_normal_recieve(struct ene_device *dev, int enable)
+{
+ ene_hw_write_reg(dev, ENE_CIR_CONF1, enable ? ENE_CIR_CONF1_ADC_ON : 0);
+}
+
+/* this enables recieve via fan input */
+static void ene_enable_fan_recieve(struct ene_device *dev, int enable)
+{
+ if (!enable)
+ ene_hw_write_reg(dev, ENE_FAN_AS_IN1, 0);
+ else {
+ ene_hw_write_reg(dev, ENE_FAN_AS_IN1, ENE_FAN_AS_IN1_EN);
+ ene_hw_write_reg(dev, ENE_FAN_AS_IN2, ENE_FAN_AS_IN2_EN);
+ }
+ dev->fan_input_inuse = enable;
+}
+
+/* determine which input to use*/
+static void ene_set_inputs(struct ene_device *dev, int learning_enable)
+{
+ ene_enable_normal_recieve(dev, 1);
+
+ /* old hardware doesn't support learning mode for sure */
+ if (dev->hw_revision <= ENE_HW_B)
+ return;
+
+ /* reciever not learning capable, still set gpio40 correctly */
+ if (!dev->hw_learning_and_tx_capable) {
+ ene_enable_gpio40(dev, !dev->hw_gpio40_learning);
+ return;
+ }
+
+ /* enable learning mode */
+ if (learning_enable) {
+ ene_enable_gpio40(dev, dev->hw_gpio40_learning);
+
+ /* fan input is not used for learning */
+ if (dev->hw_fan_as_normal_input)
+ ene_enable_fan_recieve(dev, 0);
+
+ /* disable learning mode */
+ } else {
+ if (dev->hw_fan_as_normal_input) {
+ ene_enable_fan_recieve(dev, 1);
+ ene_enable_normal_recieve(dev, 0);
+ } else
+ ene_enable_gpio40(dev, !dev->hw_gpio40_learning);
+ }
+
+ /* set few additional settings for this mode */
+ ene_hw_write_reg_mask(dev, ENE_CIR_CONF1, learning_enable ?
+ ENE_CIR_CONF1_LEARN1 : 0, ENE_CIR_CONF1_LEARN1);
+
+ ene_hw_write_reg_mask(dev, ENE_CIR_CONF2, learning_enable ?
+ ENE_CIR_CONF2_LEARN2 : 0, ENE_CIR_CONF2_LEARN2);
+}
+
+/* deinitialization */
+static void ene_hw_deinit(void *data)
+{
+ struct ene_device *dev = (struct ene_device *)data;
+
+ /* disable samplers */
+ ene_enable_normal_recieve(dev, 0);
+
+ if (dev->hw_fan_as_normal_input)
+ ene_enable_fan_recieve(dev, 0);
+
+ /* disable hardware IRQ and firmware flag */
+ ene_hw_write_reg_mask(dev, ENE_FW1, 0, ENE_FW1_ENABLE | ENE_FW1_IRQ);
+
+ ene_set_idle(dev, 1);
+ dev->in_use = 0;
+}
+
+/* sends current sample to userspace */
+static void send_sample(struct ene_device *dev)
+{
+ int value = abs(dev->sample) & PULSE_MASK;
+
+ if (dev->sample > 0)
+ value |= PULSE_BIT;
+
+ if (!lirc_buffer_full(dev->lirc_driver->rbuf)) {
+ lirc_buffer_write(dev->lirc_driver->rbuf, (void *)&value);
+ wake_up(&dev->lirc_driver->rbuf->wait_poll);
+ }
+ dev->sample = 0;
+}
+
+/* this updates current sample */
+static void update_sample(struct ene_device *dev, int sample)
+{
+ if (!dev->sample)
+ dev->sample = sample;
+ else if (same_sign(dev->sample, sample))
+ dev->sample += sample;
+ else {
+ send_sample(dev);
+ dev->sample = sample;
+ }
+}
+
+/* enable or disable idle mode */
+static void ene_set_idle(struct ene_device *dev, int idle)
+{
+ struct timeval now;
+ int disable = idle && enable_idle && (dev->hw_revision < ENE_HW_C);
+
+ ene_hw_write_reg_mask(dev, ENE_CIR_SAMPLE_PERIOD,
+ disable ? 0 : ENE_CIR_SAMPLE_OVERFLOW,
+ ENE_CIR_SAMPLE_OVERFLOW);
+ dev->idle = idle;
+
+ /* remember when we have entered the idle mode */
+ if (idle) {
+ do_gettimeofday(&dev->gap_start);
+ return;
+ }
+
+ /* send the gap between keypresses now */
+ do_gettimeofday(&now);
+
+ if (now.tv_sec - dev->gap_start.tv_sec > 16)
+ dev->sample = space(PULSE_MASK);
+ else
+ dev->sample = dev->sample +
+ space(1000000ull * (now.tv_sec - dev->gap_start.tv_sec))
+ + space(now.tv_usec - dev->gap_start.tv_usec);
+
+ if (abs(dev->sample) > PULSE_MASK)
+ dev->sample = space(PULSE_MASK);
+ send_sample(dev);
+}
+
+/* interrupt handler */
+static irqreturn_t ene_hw_irq(int irq, void *data)
+{
+ u16 hw_value;
+ int i, hw_sample;
+ int space;
+ int buffer_pointer;
+ int irq_status;
+
+ struct ene_device *dev = (struct ene_device *)data;
+ irq_status = ene_hw_irq_status(dev, &buffer_pointer);
+
+ if (!irq_status)
+ return IRQ_NONE;
+
+ /* TODO: only RX for now */
+ if (irq_status == ENE_IRQ_TX)
+ return IRQ_HANDLED;
+
+ for (i = 0; i < ENE_SAMPLES_SIZE; i++) {
+
+ hw_value = ene_hw_read_reg(dev,
+ ENE_SAMPLE_BUFFER + buffer_pointer + i);
+
+ if (dev->fan_input_inuse) {
+ /* read high part of the sample */
+ hw_value |= ene_hw_read_reg(dev,
+ ENE_SAMPLE_BUFFER_FAN + buffer_pointer + i) << 8;
+
+ /* test for _space_ bit */
+ space = !(hw_value & ENE_FAN_SMPL_PULS_MSK);
+
+ /* clear space bit, and other unused bits */
+ hw_value &= ENE_FAN_VALUE_MASK;
+ hw_sample = hw_value * ENE_SAMPLE_PERIOD_FAN;
+
+ } else {
+ space = hw_value & ENE_SAMPLE_SPC_MASK;
+ hw_value &= ENE_SAMPLE_VALUE_MASK;
+ hw_sample = hw_value * sample_period;
+ }
+
+ /* no more data */
+ if (!(hw_value))
+ break;
+
+ if (space)
+ hw_sample *= -1;
+
+ /* overflow sample recieved, handle it */
+
+ if (!dev->fan_input_inuse && hw_value == ENE_SAMPLE_OVERFLOW) {
+
+ if (dev->idle)
+ continue;
+
+ if (dev->sample > 0 || abs(dev->sample) <= ENE_MAXGAP)
+ update_sample(dev, hw_sample);
+ else
+ ene_set_idle(dev, 1);
+
+ continue;
+ }
+
+ /* normal first sample recieved */
+ if (!dev->fan_input_inuse && dev->idle) {
+ ene_set_idle(dev, 0);
+
+ /* discard first recieved value, its random
+ since its the time signal was off before
+ first pulse if idle mode is enabled, HW
+ does that for us */
+
+ if (!enable_idle)
+ continue;
+ }
+ update_sample(dev, hw_sample);
+ send_sample(dev);
+ }
+ return IRQ_HANDLED;
+}
+
+static int ene_probe(struct pnp_dev *pnp_dev,
+ const struct pnp_device_id *dev_id)
+{
+ struct ene_device *dev;
+ struct lirc_driver *lirc_driver;
+ int error = -ENOMEM;
+
+ dev = kzalloc(sizeof(struct ene_device), GFP_KERNEL);
+
+ if (!dev)
+ goto err1;
+
+ dev->pnp_dev = pnp_dev;
+ pnp_set_drvdata(pnp_dev, dev);
+
+
+ /* prepare lirc interface */
+ error = -ENOMEM;
+ lirc_driver = kzalloc(sizeof(struct lirc_driver), GFP_KERNEL);
+
+ if (!lirc_driver)
+ goto err2;
+
+ dev->lirc_driver = lirc_driver;
+
+ strcpy(lirc_driver->name, ENE_DRIVER_NAME);
+ lirc_driver->minor = -1;
+ lirc_driver->code_length = sizeof(int) * 8;
+ lirc_driver->features = LIRC_CAN_REC_MODE2;
+ lirc_driver->data = dev;
+ lirc_driver->set_use_inc = ene_hw_init;
+ lirc_driver->set_use_dec = ene_hw_deinit;
+ lirc_driver->dev = &pnp_dev->dev;
+ lirc_driver->owner = THIS_MODULE;
+
+ lirc_driver->rbuf = kzalloc(sizeof(struct lirc_buffer), GFP_KERNEL);
+
+ if (!lirc_driver->rbuf)
+ goto err3;
+
+ if (lirc_buffer_init(lirc_driver->rbuf, sizeof(int), sizeof(int) * 256))
+ goto err4;
+
+ error = -ENODEV;
+ if (lirc_register_driver(lirc_driver))
+ goto err5;
+
+ /* validate resources */
+ if (!pnp_port_valid(pnp_dev, 0) ||
+ pnp_port_len(pnp_dev, 0) < ENE_MAX_IO)
+ goto err6;
+
+ if (!pnp_irq_valid(pnp_dev, 0))
+ goto err6;
+
+ dev->hw_io = pnp_port_start(pnp_dev, 0);
+ dev->irq = pnp_irq(pnp_dev, 0);
+
+ /* claim the resources */
+ error = -EBUSY;
+ if (!request_region(dev->hw_io, ENE_MAX_IO, ENE_DRIVER_NAME))
+ goto err6;
+
+ if (request_irq(dev->irq, ene_hw_irq,
+ IRQF_SHARED, ENE_DRIVER_NAME, (void *)dev))
+ goto err7;
+
+ /* detect hardware version and features */
+ error = ene_hw_detect(dev);
+ if (error)
+ goto err8;
+
+ ene_printk(KERN_NOTICE, "driver has been succesfully loaded\n");
+ return 0;
+
+err8:
+ free_irq(dev->irq, dev);
+err7:
+ release_region(dev->hw_io, ENE_MAX_IO);
+err6:
+ lirc_unregister_driver(lirc_driver->minor);
+err5:
+ lirc_buffer_free(lirc_driver->rbuf);
+err4:
+ kfree(lirc_driver->rbuf);
+err3:
+ kfree(lirc_driver);
+err2:
+ kfree(dev);
+err1:
+ return error;
+}
+
+static void ene_remove(struct pnp_dev *pnp_dev)
+{
+ struct ene_device *dev = pnp_get_drvdata(pnp_dev);
+ ene_hw_deinit(dev);
+ free_irq(dev->irq, dev);
+ release_region(dev->hw_io, ENE_MAX_IO);
+ lirc_unregister_driver(dev->lirc_driver->minor);
+ lirc_buffer_free(dev->lirc_driver->rbuf);
+ kfree(dev->lirc_driver);
+ kfree(dev);
+}
+
+#ifdef CONFIG_PM
+
+/* TODO: make 'wake on IR' configurable and add .shutdown */
+/* currently impossible due to lack of kernel support */
+
+static int ene_suspend(struct pnp_dev *pnp_dev, pm_message_t state)
+{
+ struct ene_device *dev = pnp_get_drvdata(pnp_dev);
+ ene_hw_write_reg_mask(dev, ENE_FW1, ENE_FW1_WAKE, ENE_FW1_WAKE);
+ return 0;
+}
+
+static int ene_resume(struct pnp_dev *pnp_dev)
+{
+ struct ene_device *dev = pnp_get_drvdata(pnp_dev);
+ if (dev->in_use)
+ ene_hw_init(dev);
+
+ ene_hw_write_reg_mask(dev, ENE_FW1, 0, ENE_FW1_WAKE);
+ return 0;
+}
+
+#endif
+
+static const struct pnp_device_id ene_ids[] = {
+ {.id = "ENE0100",},
+ {},
+};
+
+static struct pnp_driver ene_driver = {
+ .name = ENE_DRIVER_NAME,
+ .id_table = ene_ids,
+ .flags = PNP_DRIVER_RES_DO_NOT_CHANGE,
+
+ .probe = ene_probe,
+ .remove = __devexit_p(ene_remove),
+
+#ifdef CONFIG_PM
+ .suspend = ene_suspend,
+ .resume = ene_resume,
+#endif
+};
+
+static int __init ene_init(void)
+{
+ if (sample_period < 5) {
+ ene_printk(KERN_ERR, "sample period must be at\n");
+ ene_printk(KERN_ERR, "least 5 us, (at least 30 recommended)\n");
+ return -EINVAL;
+ }
+ return pnp_register_driver(&ene_driver);
+}
+
+static void ene_exit(void)
+{
+ pnp_unregister_driver(&ene_driver);
+}
+
+module_param(sample_period, int, S_IRUGO);
+MODULE_PARM_DESC(sample_period, "Hardware sample period (75 us default)");
+
+module_param(enable_idle, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(enable_idle,
+ "Enables turning off signal sampling after long inactivity time; "
+ "if disabled might help detecting input signal (default: enabled)");
+
+module_param(enable_learning, bool, S_IRUGO);
+MODULE_PARM_DESC(enable_learning, "Use wide band (learning) reciever");
+
+MODULE_DEVICE_TABLE(pnp, ene_ids);
+MODULE_DESCRIPTION
+ ("LIRC driver for KB3926B/KB3926C/KB3926D (aka ENE0100) CIR port");
+MODULE_AUTHOR("Maxim Levitsky");
+MODULE_LICENSE("GPL");
+
+module_init(ene_init);
+module_exit(ene_exit);
diff --git a/drivers/staging/lirc/lirc_ene0100.h b/drivers/staging/lirc/lirc_ene0100.h
new file mode 100644
index 00000000000..776b693bb30
--- /dev/null
+++ b/drivers/staging/lirc/lirc_ene0100.h
@@ -0,0 +1,169 @@
+/*
+ * driver for ENE KB3926 B/C/D CIR (also known as ENE0100)
+ *
+ * Copyright (C) 2009 Maxim Levitsky <maximlevitsky@gmail.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 <media/lirc.h>
+#include <media/lirc_dev.h>
+
+/* hardware address */
+#define ENE_STATUS 0 /* hardware status - unused */
+#define ENE_ADDR_HI 1 /* hi byte of register address */
+#define ENE_ADDR_LO 2 /* low byte of register address */
+#define ENE_IO 3 /* read/write window */
+#define ENE_MAX_IO 4
+
+/* 8 bytes of samples, divided in 2 halfs*/
+#define ENE_SAMPLE_BUFFER 0xF8F0 /* regular sample buffer */
+#define ENE_SAMPLE_SPC_MASK (1 << 7) /* sample is space */
+#define ENE_SAMPLE_VALUE_MASK 0x7F
+#define ENE_SAMPLE_OVERFLOW 0x7F
+#define ENE_SAMPLES_SIZE 4
+
+/* fan input sample buffer */
+#define ENE_SAMPLE_BUFFER_FAN 0xF8FB /* this buffer holds high byte of */
+ /* each sample of normal buffer */
+
+#define ENE_FAN_SMPL_PULS_MSK 0x8000 /* this bit of combined sample */
+ /* if set, says that sample is pulse */
+#define ENE_FAN_VALUE_MASK 0x0FFF /* mask for valid bits of the value */
+
+/* first firmware register */
+#define ENE_FW1 0xF8F8
+#define ENE_FW1_ENABLE (1 << 0) /* enable fw processing */
+#define ENE_FW1_TXIRQ (1 << 1) /* TX interrupt pending */
+#define ENE_FW1_WAKE (1 << 6) /* enable wake from S3 */
+#define ENE_FW1_IRQ (1 << 7) /* enable interrupt */
+
+/* second firmware register */
+#define ENE_FW2 0xF8F9
+#define ENE_FW2_BUF_HIGH (1 << 0) /* which half of the buffer to read */
+#define ENE_FW2_IRQ_CLR (1 << 2) /* clear this on IRQ */
+#define ENE_FW2_GP40_AS_LEARN (1 << 4) /* normal input is used as */
+ /* learning input */
+#define ENE_FW2_FAN_AS_NRML_IN (1 << 6) /* fan is used as normal input */
+#define ENE_FW2_LEARNING (1 << 7) /* hardware supports learning and TX */
+
+/* fan as input settings - only if learning capable */
+#define ENE_FAN_AS_IN1 0xFE30 /* fan init reg 1 */
+#define ENE_FAN_AS_IN1_EN 0xCD
+#define ENE_FAN_AS_IN2 0xFE31 /* fan init reg 2 */
+#define ENE_FAN_AS_IN2_EN 0x03
+#define ENE_SAMPLE_PERIOD_FAN 61 /* fan input has fixed sample period */
+
+/* IRQ registers block (for revision B) */
+#define ENEB_IRQ 0xFD09 /* IRQ number */
+#define ENEB_IRQ_UNK1 0xFD17 /* unknown setting = 1 */
+#define ENEB_IRQ_STATUS 0xFD80 /* irq status */
+#define ENEB_IRQ_STATUS_IR (1 << 5) /* IR irq */
+
+/* IRQ registers block (for revision C,D) */
+#define ENEC_IRQ 0xFE9B /* new irq settings register */
+#define ENEC_IRQ_MASK 0x0F /* irq number mask */
+#define ENEC_IRQ_UNK_EN (1 << 4) /* always enabled */
+#define ENEC_IRQ_STATUS (1 << 5) /* irq status and ACK */
+
+/* CIR block settings */
+#define ENE_CIR_CONF1 0xFEC0
+#define ENE_CIR_CONF1_ADC_ON 0x7 /* reciever on gpio40 enabled */
+#define ENE_CIR_CONF1_LEARN1 (1 << 3) /* enabled on learning mode */
+#define ENE_CIR_CONF1_TX_ON 0x30 /* enabled on transmit */
+#define ENE_CIR_CONF1_TX_CARR (1 << 7) /* send TX carrier or not */
+
+#define ENE_CIR_CONF2 0xFEC1 /* unknown setting = 0 */
+#define ENE_CIR_CONF2_LEARN2 (1 << 4) /* set on enable learning */
+#define ENE_CIR_CONF2_GPIO40DIS (1 << 5) /* disable normal input via gpio40 */
+
+#define ENE_CIR_SAMPLE_PERIOD 0xFEC8 /* sample period in us */
+#define ENE_CIR_SAMPLE_OVERFLOW (1 << 7) /* interrupt on overflows if set */
+
+
+/* transmitter - not implemented yet */
+/* KB3926C and higher */
+/* transmission is very similiar to recieving, a byte is written to */
+/* ENE_TX_INPUT, in same manner as it is read from sample buffer */
+/* sample period is fixed*/
+
+
+/* transmitter ports */
+#define ENE_TX_PORT1 0xFC01 /* this enables one or both */
+#define ENE_TX_PORT1_EN (1 << 5) /* TX ports */
+#define ENE_TX_PORT2 0xFC08
+#define ENE_TX_PORT2_EN (1 << 1)
+
+#define ENE_TX_INPUT 0xFEC9 /* next byte to transmit */
+#define ENE_TX_SPC_MASK (1 << 7) /* Transmitted sample is space */
+#define ENE_TX_UNK1 0xFECB /* set to 0x63 */
+#define ENE_TX_SMPL_PERIOD 50 /* transmit sample period */
+
+
+#define ENE_TX_CARRIER 0xFECE /* TX carrier * 2 (khz) */
+#define ENE_TX_CARRIER_UNKBIT 0x80 /* This bit set on transmit */
+#define ENE_TX_CARRIER_LOW 0xFECF /* TX carrier / 2 */
+
+/* Hardware versions */
+#define ENE_HW_VERSION 0xFF00 /* hardware revision */
+#define ENE_HW_UNK 0xFF1D
+#define ENE_HW_UNK_CLR (1 << 2)
+#define ENE_HW_VER_MAJOR 0xFF1E /* chip version */
+#define ENE_HW_VER_MINOR 0xFF1F
+#define ENE_HW_VER_OLD 0xFD00
+
+#define same_sign(a, b) ((((a) > 0) && (b) > 0) || ((a) < 0 && (b) < 0))
+
+#define ENE_DRIVER_NAME "enecir"
+#define ENE_MAXGAP 250000 /* this is amount of time we wait
+ before turning the sampler, chosen
+ arbitry */
+
+#define space(len) (-(len)) /* add a space */
+
+/* software defines */
+#define ENE_IRQ_RX 1
+#define ENE_IRQ_TX 2
+
+#define ENE_HW_B 1 /* 3926B */
+#define ENE_HW_C 2 /* 3926C */
+#define ENE_HW_D 3 /* 3926D */
+
+#define ene_printk(level, text, ...) \
+ printk(level ENE_DRIVER_NAME ": " text, ## __VA_ARGS__)
+
+struct ene_device {
+ struct pnp_dev *pnp_dev;
+ struct lirc_driver *lirc_driver;
+
+ /* hw settings */
+ unsigned long hw_io;
+ int irq;
+
+ int hw_revision; /* hardware revision */
+ int hw_learning_and_tx_capable; /* learning capable */
+ int hw_gpio40_learning; /* gpio40 is learning */
+ int hw_fan_as_normal_input; /* fan input is used as regular input */
+
+ /* device data */
+ int idle;
+ int fan_input_inuse;
+
+ int sample;
+ int in_use;
+
+ struct timeval gap_start;
+};
diff --git a/drivers/staging/lirc/lirc_i2c.c b/drivers/staging/lirc/lirc_i2c.c
new file mode 100644
index 00000000000..6df2c0e8d72
--- /dev/null
+++ b/drivers/staging/lirc/lirc_i2c.c
@@ -0,0 +1,536 @@
+/*
+ * lirc_i2c.c
+ *
+ * i2c IR driver for the onboard IR port on many TV tuner cards, including:
+ * -Flavors of the Hauppauge PVR-150/250/350
+ * -Hauppauge HVR-1300
+ * -PixelView (BT878P+W/FM)
+ * -KNC ONE TV Station/Anubis Typhoon TView Tuner
+ * -Asus TV-Box and Creative/VisionTek BreakOut-Box
+ * -Leadtek Winfast PVR2000
+ *
+ * Copyright (c) 2000 Gerd Knorr <kraxel@goldbach.in-berlin.de>
+ * modified for PixelView (BT878P+W/FM) by
+ * Michal Kochanowicz <mkochano@pld.org.pl>
+ * Christoph Bartelmus <lirc@bartelmus.de>
+ * modified for KNC ONE TV Station/Anubis Typhoon TView Tuner by
+ * Ulrich Mueller <ulrich.mueller42@web.de>
+ * modified for Asus TV-Box and Creative/VisionTek BreakOut-Box by
+ * Stefan Jahn <stefan@lkcc.org>
+ * modified for inclusion into kernel sources by
+ * Jerome Brock <jbrock@users.sourceforge.net>
+ * modified for Leadtek Winfast PVR2000 by
+ * Thomas Reitmayr (treitmayr@yahoo.com)
+ * modified for Hauppauge HVR-1300 by
+ * Jan Frey (jfrey@gmx.de)
+ *
+ * parts are cut&pasted from the old lirc_haup.c 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 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/version.h>
+#include <linux/module.h>
+#include <linux/kmod.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/i2c-algo-bit.h>
+
+#include <media/lirc_dev.h>
+
+struct IR {
+ struct lirc_driver l;
+ struct i2c_client c;
+ int nextkey;
+ unsigned char b[3];
+ unsigned char bits;
+ unsigned char flag;
+};
+
+#define DEVICE_NAME "lirc_i2c"
+
+/* module parameters */
+static int debug; /* debug output */
+static int minor = -1; /* minor number */
+
+#define dprintk(fmt, args...) \
+ do { \
+ if (debug) \
+ printk(KERN_DEBUG DEVICE_NAME ": " fmt, \
+ ## args); \
+ } while (0)
+
+static int reverse(int data, int bits)
+{
+ int i;
+ int c;
+
+ for (c = 0, i = 0; i < bits; i++)
+ c |= ((data & (1<<i)) ? 1 : 0) << (bits-1-i);
+
+ return c;
+}
+
+static int add_to_buf_adap(void *data, struct lirc_buffer *buf)
+{
+ struct IR *ir = data;
+ unsigned char keybuf[4];
+
+ keybuf[0] = 0x00;
+ i2c_master_send(&ir->c, keybuf, 1);
+ /* poll IR chip */
+ if (i2c_master_recv(&ir->c, keybuf, sizeof(keybuf)) != sizeof(keybuf)) {
+ dprintk("read error\n");
+ return -EIO;
+ }
+
+ dprintk("key (0x%02x%02x%02x%02x)\n",
+ keybuf[0], keybuf[1], keybuf[2], keybuf[3]);
+
+ /* key pressed ? */
+ if (keybuf[2] == 0xff)
+ return -ENODATA;
+
+ /* remove repeat bit */
+ keybuf[2] &= 0x7f;
+ keybuf[3] |= 0x80;
+
+ lirc_buffer_write(buf, keybuf);
+ return 0;
+}
+
+static int add_to_buf_pcf8574(void *data, struct lirc_buffer *buf)
+{
+ struct IR *ir = data;
+ int rc;
+ unsigned char all, mask;
+ unsigned char key;
+
+ /* compute all valid bits (key code + pressed/release flag) */
+ all = ir->bits | ir->flag;
+
+ /* save IR writable mask bits */
+ mask = i2c_smbus_read_byte(&ir->c) & ~all;
+
+ /* send bit mask */
+ rc = i2c_smbus_write_byte(&ir->c, (0xff & all) | mask);
+
+ /* receive scan code */
+ rc = i2c_smbus_read_byte(&ir->c);
+
+ if (rc == -1) {
+ dprintk("%s read error\n", ir->c.name);
+ return -EIO;
+ }
+
+ /* drop duplicate polls */
+ if (ir->b[0] == (rc & all))
+ return -ENODATA;
+
+ ir->b[0] = rc & all;
+
+ dprintk("%s key 0x%02X %s\n", ir->c.name, rc & ir->bits,
+ (rc & ir->flag) ? "released" : "pressed");
+
+ /* ignore released buttons */
+ if (rc & ir->flag)
+ return -ENODATA;
+
+ /* set valid key code */
+ key = rc & ir->bits;
+ lirc_buffer_write(buf, &key);
+ return 0;
+}
+
+/* common for Hauppauge IR receivers */
+static int add_to_buf_haup_common(void *data, struct lirc_buffer *buf,
+ unsigned char *keybuf, int size, int offset)
+{
+ struct IR *ir = data;
+ __u16 code;
+ unsigned char codes[2];
+ int ret;
+
+ /* poll IR chip */
+ ret = i2c_master_recv(&ir->c, keybuf, size);
+ if (ret == size) {
+ ir->b[0] = keybuf[offset];
+ ir->b[1] = keybuf[offset+1];
+ ir->b[2] = keybuf[offset+2];
+ if (ir->b[0] != 0x00 && ir->b[1] != 0x00)
+ dprintk("key (0x%02x/0x%02x)\n", ir->b[0], ir->b[1]);
+ } else {
+ dprintk("read error (ret=%d)\n", ret);
+ /* keep last successful read buffer */
+ }
+
+ /* key pressed ? */
+ if ((ir->b[0] & 0x80) == 0)
+ return -ENODATA;
+
+ /* look what we have */
+ code = (((__u16)ir->b[0]&0x7f)<<6) | (ir->b[1]>>2);
+
+ codes[0] = (code >> 8) & 0xff;
+ codes[1] = code & 0xff;
+
+ /* return it */
+ dprintk("sending code 0x%02x%02x to lirc\n", codes[0], codes[1]);
+ lirc_buffer_write(buf, codes);
+ return 0;
+}
+
+/* specific for the Hauppauge PVR150 IR receiver */
+static int add_to_buf_haup_pvr150(void *data, struct lirc_buffer *buf)
+{
+ unsigned char keybuf[6];
+ /* fetch 6 bytes, first relevant is at offset 3 */
+ return add_to_buf_haup_common(data, buf, keybuf, 6, 3);
+}
+
+/* used for all Hauppauge IR receivers but the PVR150 */
+static int add_to_buf_haup(void *data, struct lirc_buffer *buf)
+{
+ unsigned char keybuf[3];
+ /* fetch 3 bytes, first relevant is at offset 0 */
+ return add_to_buf_haup_common(data, buf, keybuf, 3, 0);
+}
+
+
+static int add_to_buf_pvr2000(void *data, struct lirc_buffer *buf)
+{
+ struct IR *ir = data;
+ unsigned char key;
+ s32 flags;
+ s32 code;
+
+ /* poll IR chip */
+ flags = i2c_smbus_read_byte_data(&ir->c, 0x10);
+ if (-1 == flags) {
+ dprintk("read error\n");
+ return -ENODATA;
+ }
+ /* key pressed ? */
+ if (0 == (flags & 0x80))
+ return -ENODATA;
+
+ /* read actual key code */
+ code = i2c_smbus_read_byte_data(&ir->c, 0x00);
+ if (-1 == code) {
+ dprintk("read error\n");
+ return -ENODATA;
+ }
+
+ key = code & 0xFF;
+
+ dprintk("IR Key/Flags: (0x%02x/0x%02x)\n", key, flags & 0xFF);
+
+ /* return it */
+ lirc_buffer_write(buf, &key);
+ return 0;
+}
+
+static int add_to_buf_pixelview(void *data, struct lirc_buffer *buf)
+{
+ struct IR *ir = data;
+ unsigned char key;
+
+ /* poll IR chip */
+ if (1 != i2c_master_recv(&ir->c, &key, 1)) {
+ dprintk("read error\n");
+ return -1;
+ }
+ dprintk("key %02x\n", key);
+
+ /* return it */
+ lirc_buffer_write(buf, &key);
+ return 0;
+}
+
+static int add_to_buf_pv951(void *data, struct lirc_buffer *buf)
+{
+ struct IR *ir = data;
+ unsigned char key;
+ unsigned char codes[4];
+
+ /* poll IR chip */
+ if (1 != i2c_master_recv(&ir->c, &key, 1)) {
+ dprintk("read error\n");
+ return -ENODATA;
+ }
+ /* ignore 0xaa */
+ if (key == 0xaa)
+ return -ENODATA;
+ dprintk("key %02x\n", key);
+
+ codes[0] = 0x61;
+ codes[1] = 0xD6;
+ codes[2] = reverse(key, 8);
+ codes[3] = (~codes[2])&0xff;
+
+ lirc_buffer_write(buf, codes);
+ return 0;
+}
+
+static int add_to_buf_knc1(void *data, struct lirc_buffer *buf)
+{
+ static unsigned char last_key = 0xFF;
+ struct IR *ir = data;
+ unsigned char key;
+
+ /* poll IR chip */
+ if (1 != i2c_master_recv(&ir->c, &key, 1)) {
+ dprintk("read error\n");
+ return -ENODATA;
+ }
+
+ /*
+ * it seems that 0xFE indicates that a button is still held
+ * down, while 0xFF indicates that no button is held
+ * down. 0xFE sequences are sometimes interrupted by 0xFF
+ */
+
+ dprintk("key %02x\n", key);
+
+ if (key == 0xFF)
+ return -ENODATA;
+
+ if (key == 0xFE)
+ key = last_key;
+
+ last_key = key;
+ lirc_buffer_write(buf, &key);
+
+ return 0;
+}
+
+static int set_use_inc(void *data)
+{
+ struct IR *ir = data;
+
+ dprintk("%s called\n", __func__);
+
+ /* lock bttv in memory while /dev/lirc is in use */
+ i2c_use_client(&ir->c);
+
+ return 0;
+}
+
+static void set_use_dec(void *data)
+{
+ struct IR *ir = data;
+
+ dprintk("%s called\n", __func__);
+
+ i2c_release_client(&ir->c);
+}
+
+static struct lirc_driver lirc_template = {
+ .name = "lirc_i2c",
+ .set_use_inc = set_use_inc,
+ .set_use_dec = set_use_dec,
+ .dev = NULL,
+ .owner = THIS_MODULE,
+};
+
+static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id);
+static int ir_remove(struct i2c_client *client);
+static int ir_command(struct i2c_client *client, unsigned int cmd, void *arg);
+
+static const struct i2c_device_id ir_receiver_id[] = {
+ /* Generic entry for any IR receiver */
+ { "ir_video", 0 },
+ /* IR device specific entries could be added here */
+ { }
+};
+
+static struct i2c_driver driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "i2c ir driver",
+ },
+ .probe = ir_probe,
+ .remove = ir_remove,
+ .id_table = ir_receiver_id,
+ .command = ir_command,
+};
+
+static void pcf_probe(struct i2c_client *client, struct IR *ir)
+{
+ int ret1, ret2, ret3, ret4;
+
+ ret1 = i2c_smbus_write_byte(client, 0xff);
+ ret2 = i2c_smbus_read_byte(client);
+ ret3 = i2c_smbus_write_byte(client, 0x00);
+ ret4 = i2c_smbus_read_byte(client);
+
+ /* in the Asus TV-Box: bit 1-0 */
+ if (((ret2 & 0x03) == 0x03) && ((ret4 & 0x03) == 0x00)) {
+ ir->bits = (unsigned char) ~0x07;
+ ir->flag = 0x04;
+ /* in the Creative/VisionTek BreakOut-Box: bit 7-6 */
+ } else if (((ret2 & 0xc0) == 0xc0) && ((ret4 & 0xc0) == 0x00)) {
+ ir->bits = (unsigned char) ~0xe0;
+ ir->flag = 0x20;
+ }
+
+ return;
+}
+
+static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id)
+{
+ struct IR *ir;
+ struct i2c_adapter *adap = client->adapter;
+ unsigned short addr = client->addr;
+ int retval;
+
+ ir = kzalloc(sizeof(struct IR), GFP_KERNEL);
+ if (!ir)
+ return -ENOMEM;
+ memcpy(&ir->l, &lirc_template, sizeof(struct lirc_driver));
+ memcpy(&ir->c, client, sizeof(struct i2c_client));
+
+ i2c_set_clientdata(client, ir);
+ ir->l.data = ir;
+ ir->l.minor = minor;
+ ir->l.sample_rate = 10;
+ ir->l.dev = &ir->c.dev;
+ ir->nextkey = -1;
+
+ switch (addr) {
+ case 0x64:
+ strlcpy(ir->c.name, "Pixelview IR", I2C_NAME_SIZE);
+ ir->l.code_length = 8;
+ ir->l.add_to_buf = add_to_buf_pixelview;
+ break;
+ case 0x4b:
+ strlcpy(ir->c.name, "PV951 IR", I2C_NAME_SIZE);
+ ir->l.code_length = 32;
+ ir->l.add_to_buf = add_to_buf_pv951;
+ break;
+ case 0x71:
+ if (adap->id == I2C_HW_B_CX2388x)
+ strlcpy(ir->c.name, "Hauppauge HVR1300", I2C_NAME_SIZE);
+ else /* bt8xx or cx2341x */
+ /*
+ * The PVR150 IR receiver uses the same protocol as
+ * other Hauppauge cards, but the data flow is
+ * different, so we need to deal with it by its own.
+ */
+ strlcpy(ir->c.name, "Hauppauge PVR150", I2C_NAME_SIZE);
+ ir->l.code_length = 13;
+ ir->l.add_to_buf = add_to_buf_haup_pvr150;
+ break;
+ case 0x6b:
+ strlcpy(ir->c.name, "Adaptec IR", I2C_NAME_SIZE);
+ ir->l.code_length = 32;
+ ir->l.add_to_buf = add_to_buf_adap;
+ break;
+ case 0x18:
+ case 0x1a:
+ if (adap->id == I2C_HW_B_CX2388x) {
+ strlcpy(ir->c.name, "Leadtek IR", I2C_NAME_SIZE);
+ ir->l.code_length = 8;
+ ir->l.add_to_buf = add_to_buf_pvr2000;
+ } else { /* bt8xx or cx2341x */
+ strlcpy(ir->c.name, "Hauppauge IR", I2C_NAME_SIZE);
+ ir->l.code_length = 13;
+ ir->l.add_to_buf = add_to_buf_haup;
+ }
+ break;
+ case 0x30:
+ strlcpy(ir->c.name, "KNC ONE IR", I2C_NAME_SIZE);
+ ir->l.code_length = 8;
+ ir->l.add_to_buf = add_to_buf_knc1;
+ break;
+ case 0x21:
+ case 0x23:
+ pcf_probe(client, ir);
+ strlcpy(ir->c.name, "TV-Box IR", I2C_NAME_SIZE);
+ ir->l.code_length = 8;
+ ir->l.add_to_buf = add_to_buf_pcf8574;
+ break;
+ default:
+ /* shouldn't happen */
+ printk("lirc_i2c: Huh? unknown i2c address (0x%02x)?\n", addr);
+ kfree(ir);
+ return -EINVAL;
+ }
+ printk(KERN_INFO "lirc_i2c: chip 0x%x found @ 0x%02x (%s)\n",
+ adap->id, addr, ir->c.name);
+
+ retval = lirc_register_driver(&ir->l);
+
+ if (retval < 0) {
+ printk(KERN_ERR "lirc_i2c: failed to register driver!\n");
+ kfree(ir);
+ return retval;
+ }
+
+ ir->l.minor = retval;
+
+ return 0;
+}
+
+static int ir_remove(struct i2c_client *client)
+{
+ struct IR *ir = i2c_get_clientdata(client);
+
+ /* unregister device */
+ lirc_unregister_driver(ir->l.minor);
+
+ /* free memory */
+ kfree(ir);
+ return 0;
+}
+
+static int ir_command(struct i2c_client *client, unsigned int cmd, void *arg)
+{
+ /* nothing */
+ return 0;
+}
+
+static int __init lirc_i2c_init(void)
+{
+ i2c_add_driver(&driver);
+ return 0;
+}
+
+static void __exit lirc_i2c_exit(void)
+{
+ i2c_del_driver(&driver);
+}
+
+MODULE_DESCRIPTION("Infrared receiver driver for Hauppauge and "
+ "Pixelview cards (i2c stack)");
+MODULE_AUTHOR("Gerd Knorr, Michal Kochanowicz, Christoph Bartelmus, "
+ "Ulrich Mueller, Stefan Jahn, Jerome Brock");
+MODULE_LICENSE("GPL");
+
+module_param(minor, int, S_IRUGO);
+MODULE_PARM_DESC(minor, "Preferred minor device number");
+
+module_param(debug, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug, "Enable debugging messages");
+
+module_init(lirc_i2c_init);
+module_exit(lirc_i2c_exit);
diff --git a/drivers/staging/lirc/lirc_igorplugusb.c b/drivers/staging/lirc/lirc_igorplugusb.c
new file mode 100644
index 00000000000..bce600ede26
--- /dev/null
+++ b/drivers/staging/lirc/lirc_igorplugusb.c
@@ -0,0 +1,555 @@
+/*
+ * lirc_igorplugusb - USB remote support for LIRC
+ *
+ * Supports the standard homebrew IgorPlugUSB receiver with Igor's firmware.
+ * See http://www.cesko.host.sk/IgorPlugUSB/IgorPlug-USB%20(AVR)_eng.htm
+ *
+ * The device can only record bursts of up to 36 pulses/spaces.
+ * Works fine with RC5. Longer commands lead to device buffer overrun.
+ * (Maybe a better firmware or a microcontroller with more ram can help?)
+ *
+ * Version 0.1 [beta status]
+ *
+ * Copyright (C) 2004 Jan M. Hochstein
+ * <hochstein@algo.informatik.tu-darmstadt.de>
+ *
+ * This driver was derived from:
+ * Paul Miller <pmiller9@users.sourceforge.net>
+ * "lirc_atiusb" module
+ * Vladimir Dergachev <volodya@minspring.com>'s 2002
+ * "USB ATI Remote support" (input device)
+ * Adrian Dewhurst <sailor-lk@sailorfrag.net>'s 2002
+ * "USB StreamZap remote driver" (LIRC)
+ * Artur Lipowski <alipowski@kki.net.pl>'s 2002
+ * "lirc_dev" and "lirc_gpio" LIRC modules
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * 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/kmod.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/usb.h>
+#include <linux/time.h>
+
+#include <media/lirc.h>
+#include <media/lirc_dev.h>
+
+
+/* module identification */
+#define DRIVER_VERSION "0.1"
+#define DRIVER_AUTHOR \
+ "Jan M. Hochstein <hochstein@algo.informatik.tu-darmstadt.de>"
+#define DRIVER_DESC "USB remote driver for LIRC"
+#define DRIVER_NAME "lirc_igorplugusb"
+
+/* debugging support */
+#ifdef CONFIG_USB_DEBUG
+static int debug = 1;
+#else
+static int debug;
+#endif
+
+#define dprintk(fmt, args...) \
+ do { \
+ if (debug) \
+ printk(KERN_DEBUG fmt, ## args); \
+ } while (0)
+
+/* One mode2 pulse/space has 4 bytes. */
+#define CODE_LENGTH sizeof(int)
+
+/* Igor's firmware cannot record bursts longer than 36. */
+#define DEVICE_BUFLEN 36
+
+/*
+ * Header at the beginning of the device's buffer:
+ * unsigned char data_length
+ * unsigned char data_start (!=0 means ring-buffer overrun)
+ * unsigned char counter (incremented by each burst)
+ */
+#define DEVICE_HEADERLEN 3
+
+/* This is for the gap */
+#define ADDITIONAL_LIRC_BYTES 2
+
+/* times to poll per second */
+#define SAMPLE_RATE 100
+static int sample_rate = SAMPLE_RATE;
+
+
+/**** Igor's USB Request Codes */
+
+#define SET_INFRABUFFER_EMPTY 1
+/**
+ * Params: none
+ * Answer: empty
+ */
+
+#define GET_INFRACODE 2
+/**
+ * Params:
+ * wValue: offset to begin reading infra buffer
+ *
+ * Answer: infra data
+ */
+
+#define SET_DATAPORT_DIRECTION 3
+/**
+ * Params:
+ * wValue: (byte) 1 bit for each data port pin (0=in, 1=out)
+ *
+ * Answer: empty
+ */
+
+#define GET_DATAPORT_DIRECTION 4
+/**
+ * Params: none
+ *
+ * Answer: (byte) 1 bit for each data port pin (0=in, 1=out)
+ */
+
+#define SET_OUT_DATAPORT 5
+/**
+ * Params:
+ * wValue: byte to write to output data port
+ *
+ * Answer: empty
+ */
+
+#define GET_OUT_DATAPORT 6
+/**
+ * Params: none
+ *
+ * Answer: least significant 3 bits read from output data port
+ */
+
+#define GET_IN_DATAPORT 7
+/**
+ * Params: none
+ *
+ * Answer: least significant 3 bits read from input data port
+ */
+
+#define READ_EEPROM 8
+/**
+ * Params:
+ * wValue: offset to begin reading EEPROM
+ *
+ * Answer: EEPROM bytes
+ */
+
+#define WRITE_EEPROM 9
+/**
+ * Params:
+ * wValue: offset to EEPROM byte
+ * wIndex: byte to write
+ *
+ * Answer: empty
+ */
+
+#define SEND_RS232 10
+/**
+ * Params:
+ * wValue: byte to send
+ *
+ * Answer: empty
+ */
+
+#define RECV_RS232 11
+/**
+ * Params: none
+ *
+ * Answer: byte received
+ */
+
+#define SET_RS232_BAUD 12
+/**
+ * Params:
+ * wValue: byte to write to UART bit rate register (UBRR)
+ *
+ * Answer: empty
+ */
+
+#define GET_RS232_BAUD 13
+/**
+ * Params: none
+ *
+ * Answer: byte read from UART bit rate register (UBRR)
+ */
+
+
+/* data structure for each usb remote */
+struct igorplug {
+
+ /* usb */
+ struct usb_device *usbdev;
+ struct urb *urb_in;
+ int devnum;
+
+ unsigned char *buf_in;
+ unsigned int len_in;
+ int in_space;
+ struct timeval last_time;
+
+ dma_addr_t dma_in;
+
+ /* lirc */
+ struct lirc_driver *d;
+
+ /* handle sending (init strings) */
+ int send_flags;
+ wait_queue_head_t wait_out;
+};
+
+static int unregister_from_lirc(struct igorplug *ir)
+{
+ struct lirc_driver *d = ir->d;
+ int devnum;
+
+ if (!ir->d)
+ return -EINVAL;
+
+ devnum = ir->devnum;
+ dprintk(DRIVER_NAME "[%d]: unregister from lirc called\n", devnum);
+
+ lirc_unregister_driver(d->minor);
+
+ printk(DRIVER_NAME "[%d]: usb remote disconnected\n", devnum);
+
+ kfree(d);
+ ir->d = NULL;
+ kfree(ir);
+ return 0;
+}
+
+static int set_use_inc(void *data)
+{
+ struct igorplug *ir = data;
+
+ if (!ir) {
+ printk(DRIVER_NAME "[?]: set_use_inc called with no context\n");
+ return -EIO;
+ }
+ dprintk(DRIVER_NAME "[%d]: set use inc\n", ir->devnum);
+
+ if (!ir->usbdev)
+ return -ENODEV;
+
+ return 0;
+}
+
+static void set_use_dec(void *data)
+{
+ struct igorplug *ir = data;
+
+ if (!ir) {
+ printk(DRIVER_NAME "[?]: set_use_dec called with no context\n");
+ return;
+ }
+ dprintk(DRIVER_NAME "[%d]: set use dec\n", ir->devnum);
+}
+
+
+/**
+ * Called in user context.
+ * return 0 if data was added to the buffer and
+ * -ENODATA if none was available. This should add some number of bits
+ * evenly divisible by code_length to the buffer
+ */
+static int usb_remote_poll(void *data, struct lirc_buffer *buf)
+{
+ int ret;
+ struct igorplug *ir = (struct igorplug *)data;
+
+ if (!ir->usbdev) /* Has the device been removed? */
+ return -ENODEV;
+
+ memset(ir->buf_in, 0, ir->len_in);
+
+ ret = usb_control_msg(
+ ir->usbdev, usb_rcvctrlpipe(ir->usbdev, 0),
+ GET_INFRACODE, USB_TYPE_VENDOR|USB_DIR_IN,
+ 0/* offset */, /*unused*/0,
+ ir->buf_in, ir->len_in,
+ /*timeout*/HZ * USB_CTRL_GET_TIMEOUT);
+ if (ret > 0) {
+ int i = DEVICE_HEADERLEN;
+ int code, timediff;
+ struct timeval now;
+
+ if (ret <= 1) /* ACK packet has 1 byte --> ignore */
+ return -ENODATA;
+
+ dprintk(DRIVER_NAME ": Got %d bytes. Header: %02x %02x %02x\n",
+ ret, ir->buf_in[0], ir->buf_in[1], ir->buf_in[2]);
+
+ if (ir->buf_in[2] != 0) {
+ printk(DRIVER_NAME "[%d]: Device buffer overrun.\n",
+ ir->devnum);
+ /* start at earliest byte */
+ i = DEVICE_HEADERLEN + ir->buf_in[2];
+ /* where are we now? space, gap or pulse? */
+ }
+
+ do_gettimeofday(&now);
+ timediff = now.tv_sec - ir->last_time.tv_sec;
+ if (timediff + 1 > PULSE_MASK / 1000000)
+ timediff = PULSE_MASK;
+ else {
+ timediff *= 1000000;
+ timediff += now.tv_usec - ir->last_time.tv_usec;
+ }
+ ir->last_time.tv_sec = now.tv_sec;
+ ir->last_time.tv_usec = now.tv_usec;
+
+ /* create leading gap */
+ code = timediff;
+ lirc_buffer_write(buf, (unsigned char *)&code);
+ ir->in_space = 1; /* next comes a pulse */
+
+ /* MODE2: pulse/space (PULSE_BIT) in 1us units */
+
+ while (i < ret) {
+ /* 1 Igor-tick = 85.333333 us */
+ code = (unsigned int)ir->buf_in[i] * 85
+ + (unsigned int)ir->buf_in[i] / 3;
+ if (ir->in_space)
+ code |= PULSE_BIT;
+ lirc_buffer_write(buf, (unsigned char *)&code);
+ /* 1 chunk = CODE_LENGTH bytes */
+ ir->in_space ^= 1;
+ ++i;
+ }
+
+ ret = usb_control_msg(
+ ir->usbdev, usb_rcvctrlpipe(ir->usbdev, 0),
+ SET_INFRABUFFER_EMPTY, USB_TYPE_VENDOR|USB_DIR_IN,
+ /*unused*/0, /*unused*/0,
+ /*dummy*/ir->buf_in, /*dummy*/ir->len_in,
+ /*timeout*/HZ * USB_CTRL_GET_TIMEOUT);
+ if (ret < 0)
+ printk(DRIVER_NAME "[%d]: SET_INFRABUFFER_EMPTY: "
+ "error %d\n", ir->devnum, ret);
+ return 0;
+ } else if (ret < 0)
+ printk(DRIVER_NAME "[%d]: GET_INFRACODE: error %d\n",
+ ir->devnum, ret);
+
+ return -ENODATA;
+}
+
+
+
+static int usb_remote_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+{
+ struct usb_device *dev = NULL;
+ struct usb_host_interface *idesc = NULL;
+ struct usb_host_endpoint *ep_ctl2;
+ struct igorplug *ir = NULL;
+ struct lirc_driver *driver = NULL;
+ int devnum, pipe, maxp;
+ int minor = 0;
+ char buf[63], name[128] = "";
+ int mem_failure = 0;
+ int ret;
+
+ dprintk(DRIVER_NAME ": usb probe called.\n");
+
+ dev = interface_to_usbdev(intf);
+
+ idesc = intf->cur_altsetting;
+
+ if (idesc->desc.bNumEndpoints != 1)
+ return -ENODEV;
+ ep_ctl2 = idesc->endpoint;
+ if (((ep_ctl2->desc.bEndpointAddress & USB_ENDPOINT_DIR_MASK)
+ != USB_DIR_IN)
+ || (ep_ctl2->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
+ != USB_ENDPOINT_XFER_CONTROL)
+ return -ENODEV;
+ pipe = usb_rcvctrlpipe(dev, ep_ctl2->desc.bEndpointAddress);
+ devnum = dev->devnum;
+ maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe));
+
+ dprintk(DRIVER_NAME "[%d]: bytes_in_key=%lu maxp=%d\n",
+ devnum, CODE_LENGTH, maxp);
+
+
+ mem_failure = 0;
+ ir = kzalloc(sizeof(struct igorplug), GFP_KERNEL);
+ if (!ir) {
+ mem_failure = 1;
+ goto mem_failure_switch;
+ }
+ driver = kzalloc(sizeof(struct lirc_driver), GFP_KERNEL);
+ if (!driver) {
+ mem_failure = 2;
+ goto mem_failure_switch;
+ }
+
+ ir->buf_in = usb_alloc_coherent(dev,
+ DEVICE_BUFLEN+DEVICE_HEADERLEN,
+ GFP_ATOMIC, &ir->dma_in);
+ if (!ir->buf_in) {
+ mem_failure = 3;
+ goto mem_failure_switch;
+ }
+
+ strcpy(driver->name, DRIVER_NAME " ");
+ driver->minor = -1;
+ driver->code_length = CODE_LENGTH * 8; /* in bits */
+ driver->features = LIRC_CAN_REC_MODE2;
+ driver->data = ir;
+ driver->chunk_size = CODE_LENGTH;
+ driver->buffer_size = DEVICE_BUFLEN + ADDITIONAL_LIRC_BYTES;
+ driver->set_use_inc = &set_use_inc;
+ driver->set_use_dec = &set_use_dec;
+ driver->sample_rate = sample_rate; /* per second */
+ driver->add_to_buf = &usb_remote_poll;
+ driver->dev = &intf->dev;
+ driver->owner = THIS_MODULE;
+
+ init_waitqueue_head(&ir->wait_out);
+
+ minor = lirc_register_driver(driver);
+ if (minor < 0)
+ mem_failure = 9;
+
+mem_failure_switch:
+
+ switch (mem_failure) {
+ case 9:
+ usb_free_coherent(dev, DEVICE_BUFLEN+DEVICE_HEADERLEN,
+ ir->buf_in, ir->dma_in);
+ case 3:
+ kfree(driver);
+ case 2:
+ kfree(ir);
+ case 1:
+ printk(DRIVER_NAME "[%d]: out of memory (code=%d)\n",
+ devnum, mem_failure);
+ return -ENOMEM;
+ }
+
+ driver->minor = minor;
+ ir->d = driver;
+ ir->devnum = devnum;
+ ir->usbdev = dev;
+ ir->len_in = DEVICE_BUFLEN+DEVICE_HEADERLEN;
+ ir->in_space = 1; /* First mode2 event is a space. */
+ do_gettimeofday(&ir->last_time);
+
+ if (dev->descriptor.iManufacturer
+ && usb_string(dev, dev->descriptor.iManufacturer,
+ buf, sizeof(buf)) > 0)
+ strlcpy(name, buf, sizeof(name));
+ if (dev->descriptor.iProduct
+ && usb_string(dev, dev->descriptor.iProduct, buf, sizeof(buf)) > 0)
+ snprintf(name + strlen(name), sizeof(name) - strlen(name),
+ " %s", buf);
+ printk(DRIVER_NAME "[%d]: %s on usb%d:%d\n", devnum, name,
+ dev->bus->busnum, devnum);
+
+ /* clear device buffer */
+ ret = usb_control_msg(ir->usbdev, usb_rcvctrlpipe(ir->usbdev, 0),
+ SET_INFRABUFFER_EMPTY, USB_TYPE_VENDOR|USB_DIR_IN,
+ /*unused*/0, /*unused*/0,
+ /*dummy*/ir->buf_in, /*dummy*/ir->len_in,
+ /*timeout*/HZ * USB_CTRL_GET_TIMEOUT);
+ if (ret < 0)
+ printk(DRIVER_NAME "[%d]: SET_INFRABUFFER_EMPTY: error %d\n",
+ devnum, ret);
+
+ usb_set_intfdata(intf, ir);
+ return 0;
+}
+
+
+static void usb_remote_disconnect(struct usb_interface *intf)
+{
+ struct usb_device *dev = interface_to_usbdev(intf);
+ struct igorplug *ir = usb_get_intfdata(intf);
+ usb_set_intfdata(intf, NULL);
+
+ if (!ir || !ir->d)
+ return;
+
+ ir->usbdev = NULL;
+ wake_up_all(&ir->wait_out);
+
+ usb_free_coherent(dev, ir->len_in, ir->buf_in, ir->dma_in);
+
+ unregister_from_lirc(ir);
+}
+
+static struct usb_device_id usb_remote_id_table[] = {
+ /* Igor Plug USB (Atmel's Manufact. ID) */
+ { USB_DEVICE(0x03eb, 0x0002) },
+
+ /* Terminating entry */
+ { }
+};
+
+static struct usb_driver usb_remote_driver = {
+ .name = DRIVER_NAME,
+ .probe = usb_remote_probe,
+ .disconnect = usb_remote_disconnect,
+ .id_table = usb_remote_id_table
+};
+
+static int __init usb_remote_init(void)
+{
+ int i;
+
+ printk(KERN_INFO "\n"
+ DRIVER_NAME ": " DRIVER_DESC " v" DRIVER_VERSION "\n");
+ printk(DRIVER_NAME ": " DRIVER_AUTHOR "\n");
+ dprintk(DRIVER_NAME ": debug mode enabled\n");
+
+ i = usb_register(&usb_remote_driver);
+ if (i < 0) {
+ printk(DRIVER_NAME ": usb register failed, result = %d\n", i);
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static void __exit usb_remote_exit(void)
+{
+ usb_deregister(&usb_remote_driver);
+}
+
+module_init(usb_remote_init);
+module_exit(usb_remote_exit);
+
+#include <linux/vermagic.h>
+MODULE_INFO(vermagic, VERMAGIC_STRING);
+
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(usb, usb_remote_id_table);
+
+module_param(sample_rate, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(sample_rate, "Sampling rate in Hz (default: 100)");
+
diff --git a/drivers/staging/lirc/lirc_imon.c b/drivers/staging/lirc/lirc_imon.c
new file mode 100644
index 00000000000..66493253042
--- /dev/null
+++ b/drivers/staging/lirc/lirc_imon.c
@@ -0,0 +1,1058 @@
+/*
+ * lirc_imon.c: LIRC/VFD/LCD driver for SoundGraph iMON IR/VFD/LCD
+ * including the iMON PAD model
+ *
+ * Copyright(C) 2004 Venky Raju(dev@venky.ws)
+ * Copyright(C) 2009 Jarod Wilson <jarod@wilsonet.com>
+ *
+ * lirc_imon is free software; you can redistribute it and/or modify
+ * 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/errno.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+#include <linux/usb.h>
+
+#include <media/lirc.h>
+#include <media/lirc_dev.h>
+
+
+#define MOD_AUTHOR "Venky Raju <dev@venky.ws>"
+#define MOD_DESC "Driver for SoundGraph iMON MultiMedia IR/Display"
+#define MOD_NAME "lirc_imon"
+#define MOD_VERSION "0.8"
+
+#define DISPLAY_MINOR_BASE 144
+#define DEVICE_NAME "lcd%d"
+
+#define BUF_CHUNK_SIZE 4
+#define BUF_SIZE 128
+
+#define BIT_DURATION 250 /* each bit received is 250us */
+
+/*** P R O T O T Y P E S ***/
+
+/* USB Callback prototypes */
+static int imon_probe(struct usb_interface *interface,
+ const struct usb_device_id *id);
+static void imon_disconnect(struct usb_interface *interface);
+static void usb_rx_callback(struct urb *urb);
+static void usb_tx_callback(struct urb *urb);
+
+/* suspend/resume support */
+static int imon_resume(struct usb_interface *intf);
+static int imon_suspend(struct usb_interface *intf, pm_message_t message);
+
+/* Display file_operations function prototypes */
+static int display_open(struct inode *inode, struct file *file);
+static int display_close(struct inode *inode, struct file *file);
+
+/* VFD write operation */
+static ssize_t vfd_write(struct file *file, const char *buf,
+ size_t n_bytes, loff_t *pos);
+
+/* LIRC driver function prototypes */
+static int ir_open(void *data);
+static void ir_close(void *data);
+
+/* Driver init/exit prototypes */
+static int __init imon_init(void);
+static void __exit imon_exit(void);
+
+/*** G L O B A L S ***/
+#define IMON_DATA_BUF_SZ 35
+
+struct imon_context {
+ struct usb_device *usbdev;
+ /* Newer devices have two interfaces */
+ int display; /* not all controllers do */
+ int display_isopen; /* display port has been opened */
+ int ir_isopen; /* IR port open */
+ int dev_present; /* USB device presence */
+ struct mutex ctx_lock; /* to lock this object */
+ wait_queue_head_t remove_ok; /* For unexpected USB disconnects */
+
+ int vfd_proto_6p; /* some VFD require a 6th packet */
+
+ struct lirc_driver *driver;
+ struct usb_endpoint_descriptor *rx_endpoint;
+ struct usb_endpoint_descriptor *tx_endpoint;
+ struct urb *rx_urb;
+ struct urb *tx_urb;
+ unsigned char usb_rx_buf[8];
+ unsigned char usb_tx_buf[8];
+
+ struct rx_data {
+ int count; /* length of 0 or 1 sequence */
+ int prev_bit; /* logic level of sequence */
+ int initial_space; /* initial space flag */
+ } rx;
+
+ struct tx_t {
+ unsigned char data_buf[IMON_DATA_BUF_SZ]; /* user data buffer */
+ struct completion finished; /* wait for write to finish */
+ atomic_t busy; /* write in progress */
+ int status; /* status of tx completion */
+ } tx;
+};
+
+static const struct file_operations display_fops = {
+ .owner = THIS_MODULE,
+ .open = &display_open,
+ .write = &vfd_write,
+ .release = &display_close
+};
+
+/*
+ * USB Device ID for iMON USB Control Boards
+ *
+ * The Windows drivers contain 6 different inf files, more or less one for
+ * each new device until the 0x0034-0x0046 devices, which all use the same
+ * driver. Some of the devices in the 34-46 range haven't been definitively
+ * identified yet. Early devices have either a TriGem Computer, Inc. or a
+ * Samsung vendor ID (0x0aa8 and 0x04e8 respectively), while all later
+ * devices use the SoundGraph vendor ID (0x15c2).
+ */
+static struct usb_device_id imon_usb_id_table[] = {
+ /* TriGem iMON (IR only) -- TG_iMON.inf */
+ { USB_DEVICE(0x0aa8, 0x8001) },
+
+ /* SoundGraph iMON (IR only) -- sg_imon.inf */
+ { USB_DEVICE(0x04e8, 0xff30) },
+
+ /* SoundGraph iMON VFD (IR & VFD) -- iMON_VFD.inf */
+ { USB_DEVICE(0x0aa8, 0xffda) },
+
+ /* SoundGraph iMON SS (IR & VFD) -- iMON_SS.inf */
+ { USB_DEVICE(0x15c2, 0xffda) },
+
+ {}
+};
+
+/* Some iMON VFD models requires a 6th packet for VFD writes */
+static struct usb_device_id vfd_proto_6p_list[] = {
+ { USB_DEVICE(0x15c2, 0xffda) },
+ {}
+};
+
+/* Some iMON devices have no lcd/vfd, don't set one up */
+static struct usb_device_id ir_only_list[] = {
+ { USB_DEVICE(0x0aa8, 0x8001) },
+ { USB_DEVICE(0x04e8, 0xff30) },
+ {}
+};
+
+/* USB Device data */
+static struct usb_driver imon_driver = {
+ .name = MOD_NAME,
+ .probe = imon_probe,
+ .disconnect = imon_disconnect,
+ .suspend = imon_suspend,
+ .resume = imon_resume,
+ .id_table = imon_usb_id_table,
+};
+
+static struct usb_class_driver imon_class = {
+ .name = DEVICE_NAME,
+ .fops = &display_fops,
+ .minor_base = DISPLAY_MINOR_BASE,
+};
+
+/* to prevent races between open() and disconnect(), probing, etc */
+static DEFINE_MUTEX(driver_lock);
+
+static int debug;
+
+/*** M O D U L E C O D E ***/
+
+MODULE_AUTHOR(MOD_AUTHOR);
+MODULE_DESCRIPTION(MOD_DESC);
+MODULE_VERSION(MOD_VERSION);
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(usb, imon_usb_id_table);
+module_param(debug, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug, "Debug messages: 0=no, 1=yes(default: no)");
+
+static void free_imon_context(struct imon_context *context)
+{
+ struct device *dev = context->driver->dev;
+ usb_free_urb(context->tx_urb);
+ usb_free_urb(context->rx_urb);
+ lirc_buffer_free(context->driver->rbuf);
+ kfree(context->driver->rbuf);
+ kfree(context->driver);
+ kfree(context);
+
+ dev_dbg(dev, "%s: iMON context freed\n", __func__);
+}
+
+static void deregister_from_lirc(struct imon_context *context)
+{
+ int retval;
+ int minor = context->driver->minor;
+
+ retval = lirc_unregister_driver(minor);
+ if (retval)
+ err("%s: unable to deregister from lirc(%d)",
+ __func__, retval);
+ else
+ printk(KERN_INFO MOD_NAME ": Deregistered iMON driver "
+ "(minor:%d)\n", minor);
+
+}
+
+/**
+ * Called when the Display device (e.g. /dev/lcd0)
+ * is opened by the application.
+ */
+static int display_open(struct inode *inode, struct file *file)
+{
+ struct usb_interface *interface;
+ struct imon_context *context = NULL;
+ int subminor;
+ int retval = 0;
+
+ /* prevent races with disconnect */
+ mutex_lock(&driver_lock);
+
+ subminor = iminor(inode);
+ interface = usb_find_interface(&imon_driver, subminor);
+ if (!interface) {
+ err("%s: could not find interface for minor %d",
+ __func__, subminor);
+ retval = -ENODEV;
+ goto exit;
+ }
+ context = usb_get_intfdata(interface);
+
+ if (!context) {
+ err("%s: no context found for minor %d",
+ __func__, subminor);
+ retval = -ENODEV;
+ goto exit;
+ }
+
+ mutex_lock(&context->ctx_lock);
+
+ if (!context->display) {
+ err("%s: display not supported by device", __func__);
+ retval = -ENODEV;
+ } else if (context->display_isopen) {
+ err("%s: display port is already open", __func__);
+ retval = -EBUSY;
+ } else {
+ context->display_isopen = 1;
+ file->private_data = context;
+ dev_info(context->driver->dev, "display port opened\n");
+ }
+
+ mutex_unlock(&context->ctx_lock);
+
+exit:
+ mutex_unlock(&driver_lock);
+ return retval;
+}
+
+/**
+ * Called when the display device (e.g. /dev/lcd0)
+ * is closed by the application.
+ */
+static int display_close(struct inode *inode, struct file *file)
+{
+ struct imon_context *context = NULL;
+ int retval = 0;
+
+ context = (struct imon_context *)file->private_data;
+
+ if (!context) {
+ err("%s: no context for device", __func__);
+ return -ENODEV;
+ }
+
+ mutex_lock(&context->ctx_lock);
+
+ if (!context->display) {
+ err("%s: display not supported by device", __func__);
+ retval = -ENODEV;
+ } else if (!context->display_isopen) {
+ err("%s: display is not open", __func__);
+ retval = -EIO;
+ } else {
+ context->display_isopen = 0;
+ dev_info(context->driver->dev, "display port closed\n");
+ if (!context->dev_present && !context->ir_isopen) {
+ /*
+ * Device disconnected before close and IR port is not
+ * open. If IR port is open, context will be deleted by
+ * ir_close.
+ */
+ mutex_unlock(&context->ctx_lock);
+ free_imon_context(context);
+ return retval;
+ }
+ }
+
+ mutex_unlock(&context->ctx_lock);
+ return retval;
+}
+
+/**
+ * Sends a packet to the device -- this function must be called
+ * with context->ctx_lock held.
+ */
+static int send_packet(struct imon_context *context)
+{
+ unsigned int pipe;
+ int interval = 0;
+ int retval = 0;
+ struct usb_ctrlrequest *control_req = NULL;
+
+ /* Check if we need to use control or interrupt urb */
+ pipe = usb_sndintpipe(context->usbdev,
+ context->tx_endpoint->bEndpointAddress);
+ interval = context->tx_endpoint->bInterval;
+
+ usb_fill_int_urb(context->tx_urb, context->usbdev, pipe,
+ context->usb_tx_buf,
+ sizeof(context->usb_tx_buf),
+ usb_tx_callback, context, interval);
+
+ context->tx_urb->actual_length = 0;
+
+ init_completion(&context->tx.finished);
+ atomic_set(&(context->tx.busy), 1);
+
+ retval = usb_submit_urb(context->tx_urb, GFP_KERNEL);
+ if (retval) {
+ atomic_set(&(context->tx.busy), 0);
+ err("%s: error submitting urb(%d)", __func__, retval);
+ } else {
+ /* Wait for transmission to complete (or abort) */
+ mutex_unlock(&context->ctx_lock);
+ retval = wait_for_completion_interruptible(
+ &context->tx.finished);
+ if (retval)
+ err("%s: task interrupted", __func__);
+ mutex_lock(&context->ctx_lock);
+
+ retval = context->tx.status;
+ if (retval)
+ err("%s: packet tx failed (%d)", __func__, retval);
+ }
+
+ kfree(control_req);
+
+ return retval;
+}
+
+/**
+ * Writes data to the VFD. The iMON VFD is 2x16 characters
+ * and requires data in 5 consecutive USB interrupt packets,
+ * each packet but the last carrying 7 bytes.
+ *
+ * I don't know if the VFD board supports features such as
+ * scrolling, clearing rows, blanking, etc. so at
+ * the caller must provide a full screen of data. If fewer
+ * than 32 bytes are provided spaces will be appended to
+ * generate a full screen.
+ */
+static ssize_t vfd_write(struct file *file, const char *buf,
+ size_t n_bytes, loff_t *pos)
+{
+ int i;
+ int offset;
+ int seq;
+ int retval = 0;
+ struct imon_context *context;
+ const unsigned char vfd_packet6[] = {
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF };
+ int *data_buf;
+
+ context = (struct imon_context *)file->private_data;
+ if (!context) {
+ err("%s: no context for device", __func__);
+ return -ENODEV;
+ }
+
+ mutex_lock(&context->ctx_lock);
+
+ if (!context->dev_present) {
+ err("%s: no iMON device present", __func__);
+ retval = -ENODEV;
+ goto exit;
+ }
+
+ if (n_bytes <= 0 || n_bytes > IMON_DATA_BUF_SZ - 3) {
+ err("%s: invalid payload size", __func__);
+ retval = -EINVAL;
+ goto exit;
+ }
+
+ data_buf = memdup_user(buf, n_bytes);
+ if (IS_ERR(data_buf)) {
+ retval = PTR_ERR(data_buf);
+ goto exit;
+ }
+
+ memcpy(context->tx.data_buf, data_buf, n_bytes);
+
+ /* Pad with spaces */
+ for (i = n_bytes; i < IMON_DATA_BUF_SZ - 3; ++i)
+ context->tx.data_buf[i] = ' ';
+
+ for (i = IMON_DATA_BUF_SZ - 3; i < IMON_DATA_BUF_SZ; ++i)
+ context->tx.data_buf[i] = 0xFF;
+
+ offset = 0;
+ seq = 0;
+
+ do {
+ memcpy(context->usb_tx_buf, context->tx.data_buf + offset, 7);
+ context->usb_tx_buf[7] = (unsigned char) seq;
+
+ retval = send_packet(context);
+ if (retval) {
+ err("%s: send packet failed for packet #%d",
+ __func__, seq/2);
+ goto exit;
+ } else {
+ seq += 2;
+ offset += 7;
+ }
+
+ } while (offset < IMON_DATA_BUF_SZ);
+
+ if (context->vfd_proto_6p) {
+ /* Send packet #6 */
+ memcpy(context->usb_tx_buf, &vfd_packet6, sizeof(vfd_packet6));
+ context->usb_tx_buf[7] = (unsigned char) seq;
+ retval = send_packet(context);
+ if (retval)
+ err("%s: send packet failed for packet #%d",
+ __func__, seq/2);
+ }
+
+exit:
+ mutex_unlock(&context->ctx_lock);
+
+ return (!retval) ? n_bytes : retval;
+}
+
+/**
+ * Callback function for USB core API: transmit data
+ */
+static void usb_tx_callback(struct urb *urb)
+{
+ struct imon_context *context;
+
+ if (!urb)
+ return;
+ context = (struct imon_context *)urb->context;
+ if (!context)
+ return;
+
+ context->tx.status = urb->status;
+
+ /* notify waiters that write has finished */
+ atomic_set(&context->tx.busy, 0);
+ complete(&context->tx.finished);
+
+ return;
+}
+
+/**
+ * Called by lirc_dev when the application opens /dev/lirc
+ */
+static int ir_open(void *data)
+{
+ int retval = 0;
+ struct imon_context *context;
+
+ /* prevent races with disconnect */
+ mutex_lock(&driver_lock);
+
+ context = (struct imon_context *)data;
+
+ /* initial IR protocol decode variables */
+ context->rx.count = 0;
+ context->rx.initial_space = 1;
+ context->rx.prev_bit = 0;
+
+ context->ir_isopen = 1;
+ dev_info(context->driver->dev, "IR port opened\n");
+
+ mutex_unlock(&driver_lock);
+ return retval;
+}
+
+/**
+ * Called by lirc_dev when the application closes /dev/lirc
+ */
+static void ir_close(void *data)
+{
+ struct imon_context *context;
+
+ context = (struct imon_context *)data;
+ if (!context) {
+ err("%s: no context for device", __func__);
+ return;
+ }
+
+ mutex_lock(&context->ctx_lock);
+
+ context->ir_isopen = 0;
+ dev_info(context->driver->dev, "IR port closed\n");
+
+ if (!context->dev_present) {
+ /*
+ * Device disconnected while IR port was still open. Driver
+ * was not deregistered at disconnect time, so do it now.
+ */
+ deregister_from_lirc(context);
+
+ if (!context->display_isopen) {
+ mutex_unlock(&context->ctx_lock);
+ free_imon_context(context);
+ return;
+ }
+ /*
+ * If display port is open, context will be deleted by
+ * display_close
+ */
+ }
+
+ mutex_unlock(&context->ctx_lock);
+ return;
+}
+
+/**
+ * Convert bit count to time duration (in us) and submit
+ * the value to lirc_dev.
+ */
+static void submit_data(struct imon_context *context)
+{
+ unsigned char buf[4];
+ int value = context->rx.count;
+ int i;
+
+ dev_dbg(context->driver->dev, "submitting data to LIRC\n");
+
+ value *= BIT_DURATION;
+ value &= PULSE_MASK;
+ if (context->rx.prev_bit)
+ value |= PULSE_BIT;
+
+ for (i = 0; i < 4; ++i)
+ buf[i] = value>>(i*8);
+
+ lirc_buffer_write(context->driver->rbuf, buf);
+ wake_up(&context->driver->rbuf->wait_poll);
+ return;
+}
+
+static inline int tv2int(const struct timeval *a, const struct timeval *b)
+{
+ int usecs = 0;
+ int sec = 0;
+
+ if (b->tv_usec > a->tv_usec) {
+ usecs = 1000000;
+ sec--;
+ }
+
+ usecs += a->tv_usec - b->tv_usec;
+
+ sec += a->tv_sec - b->tv_sec;
+ sec *= 1000;
+ usecs /= 1000;
+ sec += usecs;
+
+ if (sec < 0)
+ sec = 1000;
+
+ return sec;
+}
+
+/**
+ * Process the incoming packet
+ */
+static void imon_incoming_packet(struct imon_context *context,
+ struct urb *urb, int intf)
+{
+ int len = urb->actual_length;
+ unsigned char *buf = urb->transfer_buffer;
+ struct device *dev = context->driver->dev;
+ int octet, bit;
+ unsigned char mask;
+ int i, chunk_num;
+
+ /*
+ * just bail out if no listening IR client
+ */
+ if (!context->ir_isopen)
+ return;
+
+ if (len != 8) {
+ dev_warn(dev, "imon %s: invalid incoming packet "
+ "size (len = %d, intf%d)\n", __func__, len, intf);
+ return;
+ }
+
+ if (debug) {
+ printk(KERN_INFO "raw packet: ");
+ for (i = 0; i < len; ++i)
+ printk("%02x ", buf[i]);
+ printk("\n");
+ }
+
+ /*
+ * Translate received data to pulse and space lengths.
+ * Received data is active low, i.e. pulses are 0 and
+ * spaces are 1.
+ *
+ * My original algorithm was essentially similar to
+ * Changwoo Ryu's with the exception that he switched
+ * the incoming bits to active high and also fed an
+ * initial space to LIRC at the start of a new sequence
+ * if the previous bit was a pulse.
+ *
+ * I've decided to adopt his algorithm.
+ */
+
+ if (buf[7] == 1 && context->rx.initial_space) {
+ /* LIRC requires a leading space */
+ context->rx.prev_bit = 0;
+ context->rx.count = 4;
+ submit_data(context);
+ context->rx.count = 0;
+ }
+
+ for (octet = 0; octet < 5; ++octet) {
+ mask = 0x80;
+ for (bit = 0; bit < 8; ++bit) {
+ int curr_bit = !(buf[octet] & mask);
+ if (curr_bit != context->rx.prev_bit) {
+ if (context->rx.count) {
+ submit_data(context);
+ context->rx.count = 0;
+ }
+ context->rx.prev_bit = curr_bit;
+ }
+ ++context->rx.count;
+ mask >>= 1;
+ }
+ }
+
+ if (chunk_num == 10) {
+ if (context->rx.count) {
+ submit_data(context);
+ context->rx.count = 0;
+ }
+ context->rx.initial_space = context->rx.prev_bit;
+ }
+}
+
+/**
+ * Callback function for USB core API: receive data
+ */
+static void usb_rx_callback(struct urb *urb)
+{
+ struct imon_context *context;
+ unsigned char *buf;
+ int len;
+ int intfnum = 0;
+
+ if (!urb)
+ return;
+
+ context = (struct imon_context *)urb->context;
+ if (!context)
+ return;
+
+ buf = urb->transfer_buffer;
+ len = urb->actual_length;
+
+ switch (urb->status) {
+ case -ENOENT: /* usbcore unlink successful! */
+ return;
+
+ case 0:
+ imon_incoming_packet(context, urb, intfnum);
+ break;
+
+ default:
+ dev_warn(context->driver->dev, "imon %s: status(%d): ignored\n",
+ __func__, urb->status);
+ break;
+ }
+
+ usb_submit_urb(context->rx_urb, GFP_ATOMIC);
+
+ return;
+}
+
+/**
+ * Callback function for USB core API: Probe
+ */
+static int imon_probe(struct usb_interface *interface,
+ const struct usb_device_id *id)
+{
+ struct usb_device *usbdev = NULL;
+ struct usb_host_interface *iface_desc = NULL;
+ struct usb_endpoint_descriptor *rx_endpoint = NULL;
+ struct usb_endpoint_descriptor *tx_endpoint = NULL;
+ struct urb *rx_urb = NULL;
+ struct urb *tx_urb = NULL;
+ struct lirc_driver *driver = NULL;
+ struct lirc_buffer *rbuf = NULL;
+ struct device *dev = &interface->dev;
+ int ifnum;
+ int lirc_minor = 0;
+ int num_endpts;
+ int retval = 0;
+ int display_ep_found = 0;
+ int ir_ep_found = 0;
+ int alloc_status = 0;
+ int vfd_proto_6p = 0;
+ int code_length;
+ struct imon_context *context = NULL;
+ int i;
+ u16 vendor, product;
+
+ context = kzalloc(sizeof(struct imon_context), GFP_KERNEL);
+ if (!context) {
+ err("%s: kzalloc failed for context", __func__);
+ alloc_status = 1;
+ goto alloc_status_switch;
+ }
+
+ /*
+ * Try to auto-detect the type of display if the user hasn't set
+ * it by hand via the display_type modparam. Default is VFD.
+ */
+ if (usb_match_id(interface, ir_only_list))
+ context->display = 0;
+ else
+ context->display = 1;
+
+ code_length = BUF_CHUNK_SIZE * 8;
+
+ usbdev = usb_get_dev(interface_to_usbdev(interface));
+ iface_desc = interface->cur_altsetting;
+ num_endpts = iface_desc->desc.bNumEndpoints;
+ ifnum = iface_desc->desc.bInterfaceNumber;
+ vendor = le16_to_cpu(usbdev->descriptor.idVendor);
+ product = le16_to_cpu(usbdev->descriptor.idProduct);
+
+ dev_dbg(dev, "%s: found iMON device (%04x:%04x, intf%d)\n",
+ __func__, vendor, product, ifnum);
+
+ /* prevent races probing devices w/multiple interfaces */
+ mutex_lock(&driver_lock);
+
+ /*
+ * Scan the endpoint list and set:
+ * first input endpoint = IR endpoint
+ * first output endpoint = display endpoint
+ */
+ for (i = 0; i < num_endpts && !(ir_ep_found && display_ep_found); ++i) {
+ struct usb_endpoint_descriptor *ep;
+ int ep_dir;
+ int ep_type;
+ ep = &iface_desc->endpoint[i].desc;
+ ep_dir = ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK;
+ ep_type = ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK;
+
+ if (!ir_ep_found &&
+ ep_dir == USB_DIR_IN &&
+ ep_type == USB_ENDPOINT_XFER_INT) {
+
+ rx_endpoint = ep;
+ ir_ep_found = 1;
+ dev_dbg(dev, "%s: found IR endpoint\n", __func__);
+
+ } else if (!display_ep_found && ep_dir == USB_DIR_OUT &&
+ ep_type == USB_ENDPOINT_XFER_INT) {
+ tx_endpoint = ep;
+ display_ep_found = 1;
+ dev_dbg(dev, "%s: found display endpoint\n", __func__);
+ }
+ }
+
+ /*
+ * Some iMON receivers have no display. Unfortunately, it seems
+ * that SoundGraph recycles device IDs between devices both with
+ * and without... :\
+ */
+ if (context->display == 0) {
+ display_ep_found = 0;
+ dev_dbg(dev, "%s: device has no display\n", __func__);
+ }
+
+ /* Input endpoint is mandatory */
+ if (!ir_ep_found) {
+ err("%s: no valid input (IR) endpoint found.", __func__);
+ retval = -ENODEV;
+ alloc_status = 2;
+ goto alloc_status_switch;
+ }
+
+ /* Determine if display requires 6 packets */
+ if (display_ep_found) {
+ if (usb_match_id(interface, vfd_proto_6p_list))
+ vfd_proto_6p = 1;
+
+ dev_dbg(dev, "%s: vfd_proto_6p: %d\n",
+ __func__, vfd_proto_6p);
+ }
+
+ driver = kzalloc(sizeof(struct lirc_driver), GFP_KERNEL);
+ if (!driver) {
+ err("%s: kzalloc failed for lirc_driver", __func__);
+ alloc_status = 2;
+ goto alloc_status_switch;
+ }
+ rbuf = kmalloc(sizeof(struct lirc_buffer), GFP_KERNEL);
+ if (!rbuf) {
+ err("%s: kmalloc failed for lirc_buffer", __func__);
+ alloc_status = 3;
+ goto alloc_status_switch;
+ }
+ if (lirc_buffer_init(rbuf, BUF_CHUNK_SIZE, BUF_SIZE)) {
+ err("%s: lirc_buffer_init failed", __func__);
+ alloc_status = 4;
+ goto alloc_status_switch;
+ }
+ rx_urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!rx_urb) {
+ err("%s: usb_alloc_urb failed for IR urb", __func__);
+ alloc_status = 5;
+ goto alloc_status_switch;
+ }
+ tx_urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!tx_urb) {
+ err("%s: usb_alloc_urb failed for display urb",
+ __func__);
+ alloc_status = 6;
+ goto alloc_status_switch;
+ }
+
+ mutex_init(&context->ctx_lock);
+ context->vfd_proto_6p = vfd_proto_6p;
+
+ strcpy(driver->name, MOD_NAME);
+ driver->minor = -1;
+ driver->code_length = sizeof(int) * 8;
+ driver->sample_rate = 0;
+ driver->features = LIRC_CAN_REC_MODE2;
+ driver->data = context;
+ driver->rbuf = rbuf;
+ driver->set_use_inc = ir_open;
+ driver->set_use_dec = ir_close;
+ driver->dev = &interface->dev;
+ driver->owner = THIS_MODULE;
+
+ mutex_lock(&context->ctx_lock);
+
+ context->driver = driver;
+ /* start out in keyboard mode */
+
+ lirc_minor = lirc_register_driver(driver);
+ if (lirc_minor < 0) {
+ err("%s: lirc_register_driver failed", __func__);
+ alloc_status = 7;
+ goto alloc_status_switch;
+ } else
+ dev_info(dev, "Registered iMON driver "
+ "(lirc minor: %d)\n", lirc_minor);
+
+ /* Needed while unregistering! */
+ driver->minor = lirc_minor;
+
+ context->usbdev = usbdev;
+ context->dev_present = 1;
+ context->rx_endpoint = rx_endpoint;
+ context->rx_urb = rx_urb;
+
+ /*
+ * tx is used to send characters to lcd/vfd, associate RF
+ * remotes, set IR protocol, and maybe more...
+ */
+ context->tx_endpoint = tx_endpoint;
+ context->tx_urb = tx_urb;
+
+ if (display_ep_found)
+ context->display = 1;
+
+ usb_fill_int_urb(context->rx_urb, context->usbdev,
+ usb_rcvintpipe(context->usbdev,
+ context->rx_endpoint->bEndpointAddress),
+ context->usb_rx_buf, sizeof(context->usb_rx_buf),
+ usb_rx_callback, context,
+ context->rx_endpoint->bInterval);
+
+ retval = usb_submit_urb(context->rx_urb, GFP_KERNEL);
+
+ if (retval) {
+ err("%s: usb_submit_urb failed for intf0 (%d)",
+ __func__, retval);
+ mutex_unlock(&context->ctx_lock);
+ goto exit;
+ }
+
+ usb_set_intfdata(interface, context);
+
+ if (context->display && ifnum == 0) {
+ dev_dbg(dev, "%s: Registering iMON display with sysfs\n",
+ __func__);
+
+ if (usb_register_dev(interface, &imon_class)) {
+ /* Not a fatal error, so ignore */
+ dev_info(dev, "%s: could not get a minor number for "
+ "display\n", __func__);
+ }
+ }
+
+ dev_info(dev, "iMON device (%04x:%04x, intf%d) on "
+ "usb<%d:%d> initialized\n", vendor, product, ifnum,
+ usbdev->bus->busnum, usbdev->devnum);
+
+alloc_status_switch:
+ mutex_unlock(&context->ctx_lock);
+
+ switch (alloc_status) {
+ case 7:
+ usb_free_urb(tx_urb);
+ case 6:
+ usb_free_urb(rx_urb);
+ case 5:
+ if (rbuf)
+ lirc_buffer_free(rbuf);
+ case 4:
+ kfree(rbuf);
+ case 3:
+ kfree(driver);
+ case 2:
+ kfree(context);
+ context = NULL;
+ case 1:
+ if (retval != -ENODEV)
+ retval = -ENOMEM;
+ break;
+ case 0:
+ retval = 0;
+ }
+
+exit:
+ mutex_unlock(&driver_lock);
+
+ return retval;
+}
+
+/**
+ * Callback function for USB core API: disconnect
+ */
+static void imon_disconnect(struct usb_interface *interface)
+{
+ struct imon_context *context;
+ int ifnum;
+
+ /* prevent races with ir_open()/display_open() */
+ mutex_lock(&driver_lock);
+
+ context = usb_get_intfdata(interface);
+ ifnum = interface->cur_altsetting->desc.bInterfaceNumber;
+
+ mutex_lock(&context->ctx_lock);
+
+ usb_set_intfdata(interface, NULL);
+
+ /* Abort ongoing write */
+ if (atomic_read(&context->tx.busy)) {
+ usb_kill_urb(context->tx_urb);
+ complete_all(&context->tx.finished);
+ }
+
+ context->dev_present = 0;
+ usb_kill_urb(context->rx_urb);
+ if (context->display)
+ usb_deregister_dev(interface, &imon_class);
+
+ if (!context->ir_isopen && !context->dev_present) {
+ deregister_from_lirc(context);
+ mutex_unlock(&context->ctx_lock);
+ if (!context->display_isopen)
+ free_imon_context(context);
+ } else
+ mutex_unlock(&context->ctx_lock);
+
+ mutex_unlock(&driver_lock);
+
+ printk(KERN_INFO "%s: iMON device (intf%d) disconnected\n",
+ __func__, ifnum);
+}
+
+static int imon_suspend(struct usb_interface *intf, pm_message_t message)
+{
+ struct imon_context *context = usb_get_intfdata(intf);
+
+ usb_kill_urb(context->rx_urb);
+
+ return 0;
+}
+
+static int imon_resume(struct usb_interface *intf)
+{
+ int rc = 0;
+ struct imon_context *context = usb_get_intfdata(intf);
+
+ usb_fill_int_urb(context->rx_urb, context->usbdev,
+ usb_rcvintpipe(context->usbdev,
+ context->rx_endpoint->bEndpointAddress),
+ context->usb_rx_buf, sizeof(context->usb_rx_buf),
+ usb_rx_callback, context,
+ context->rx_endpoint->bInterval);
+
+ rc = usb_submit_urb(context->rx_urb, GFP_ATOMIC);
+
+ return rc;
+}
+
+static int __init imon_init(void)
+{
+ int rc;
+
+ printk(KERN_INFO MOD_NAME ": " MOD_DESC ", v" MOD_VERSION "\n");
+
+ rc = usb_register(&imon_driver);
+ if (rc) {
+ err("%s: usb register failed(%d)", __func__, rc);
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static void __exit imon_exit(void)
+{
+ usb_deregister(&imon_driver);
+ printk(KERN_INFO MOD_NAME ": module removed. Goodbye!\n");
+}
+
+module_init(imon_init);
+module_exit(imon_exit);
diff --git a/drivers/staging/lirc/lirc_it87.c b/drivers/staging/lirc/lirc_it87.c
new file mode 100644
index 00000000000..09f36961c6d
--- /dev/null
+++ b/drivers/staging/lirc/lirc_it87.c
@@ -0,0 +1,1019 @@
+/*
+ * LIRC driver for ITE IT8712/IT8705 CIR port
+ *
+ * Copyright (C) 2001 Hans-Gunter Lutke Uphues <hg_lu@web.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
+ *
+ * ITE IT8705 and IT8712(not tested) and IT8720 CIR-port support for lirc based
+ * via cut and paste from lirc_sir.c (C) 2000 Milan Pikula
+ *
+ * Attention: Sendmode only tested with debugging logs
+ *
+ * 2001/02/27 Christoph Bartelmus <lirc@bartelmus.de> :
+ * reimplemented read function
+ * 2005/06/05 Andrew Calkin implemented support for Asus Digimatrix,
+ * based on work of the following member of the Outertrack Digimatrix
+ * Forum: Art103 <r_tay@hotmail.com>
+ * 2009/12/24 James Edwards <jimbo-lirc@edwardsclan.net> implemeted support
+ * for ITE8704/ITE8718, on my machine, the DSDT reports 8704, but the
+ * chip identifies as 18.
+ */
+
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/signal.h>
+#include <linux/fs.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/kernel.h>
+#include <linux/time.h>
+#include <linux/string.h>
+#include <linux/types.h>
+#include <linux/wait.h>
+#include <linux/mm.h>
+#include <linux/delay.h>
+#include <linux/poll.h>
+#include <asm/system.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/fcntl.h>
+
+#include <linux/timer.h>
+#include <linux/pnp.h>
+
+#include <media/lirc.h>
+#include <media/lirc_dev.h>
+
+#include "lirc_it87.h"
+
+#ifdef LIRC_IT87_DIGIMATRIX
+static int digimatrix = 1;
+static int it87_freq = 36; /* kHz */
+static int irq = 9;
+#else
+static int digimatrix;
+static int it87_freq = 38; /* kHz */
+static int irq = IT87_CIR_DEFAULT_IRQ;
+#endif
+
+static unsigned long it87_bits_in_byte_out;
+static unsigned long it87_send_counter;
+static unsigned char it87_RXEN_mask = IT87_CIR_RCR_RXEN;
+
+#define RBUF_LEN 1024
+
+#define LIRC_DRIVER_NAME "lirc_it87"
+
+/* timeout for sequences in jiffies (=5/100s) */
+/* must be longer than TIME_CONST */
+#define IT87_TIMEOUT (HZ*5/100)
+
+/* module parameters */
+static int debug;
+#define dprintk(fmt, args...) \
+ do { \
+ if (debug) \
+ printk(KERN_DEBUG LIRC_DRIVER_NAME ": " \
+ fmt, ## args); \
+ } while (0)
+
+static int io = IT87_CIR_DEFAULT_IOBASE;
+/* receiver demodulator default: off */
+static int it87_enable_demodulator;
+
+static int timer_enabled;
+static DEFINE_SPINLOCK(timer_lock);
+static struct timer_list timerlist;
+/* time of last signal change detected */
+static struct timeval last_tv = {0, 0};
+/* time of last UART data ready interrupt */
+static struct timeval last_intr_tv = {0, 0};
+static int last_value;
+
+static DECLARE_WAIT_QUEUE_HEAD(lirc_read_queue);
+
+static DEFINE_SPINLOCK(hardware_lock);
+static DEFINE_SPINLOCK(dev_lock);
+
+static int rx_buf[RBUF_LEN];
+unsigned int rx_tail, rx_head;
+
+static struct pnp_driver it87_pnp_driver;
+
+/* SECTION: Prototypes */
+
+/* Communication with user-space */
+static int lirc_open(struct inode *inode, struct file *file);
+static int lirc_close(struct inode *inode, struct file *file);
+static unsigned int lirc_poll(struct file *file, poll_table *wait);
+static ssize_t lirc_read(struct file *file, char *buf,
+ size_t count, loff_t *ppos);
+static ssize_t lirc_write(struct file *file, const char *buf,
+ size_t n, loff_t *pos);
+static long lirc_ioctl(struct file *filep, unsigned int cmd, unsigned long arg);
+static void add_read_queue(int flag, unsigned long val);
+static int init_chrdev(void);
+static void drop_chrdev(void);
+/* Hardware */
+static irqreturn_t it87_interrupt(int irq, void *dev_id);
+static void send_space(unsigned long len);
+static void send_pulse(unsigned long len);
+static void init_send(void);
+static void terminate_send(unsigned long len);
+static int init_hardware(void);
+static void drop_hardware(void);
+/* Initialisation */
+static int init_port(void);
+static void drop_port(void);
+
+
+/* SECTION: Communication with user-space */
+
+static int lirc_open(struct inode *inode, struct file *file)
+{
+ spin_lock(&dev_lock);
+ if (module_refcount(THIS_MODULE)) {
+ spin_unlock(&dev_lock);
+ return -EBUSY;
+ }
+ spin_unlock(&dev_lock);
+ return 0;
+}
+
+
+static int lirc_close(struct inode *inode, struct file *file)
+{
+ return 0;
+}
+
+
+static unsigned int lirc_poll(struct file *file, poll_table *wait)
+{
+ poll_wait(file, &lirc_read_queue, wait);
+ if (rx_head != rx_tail)
+ return POLLIN | POLLRDNORM;
+ return 0;
+}
+
+
+static ssize_t lirc_read(struct file *file, char *buf,
+ size_t count, loff_t *ppos)
+{
+ int n = 0;
+ int retval = 0;
+
+ while (n < count) {
+ if (file->f_flags & O_NONBLOCK && rx_head == rx_tail) {
+ retval = -EAGAIN;
+ break;
+ }
+ retval = wait_event_interruptible(lirc_read_queue,
+ rx_head != rx_tail);
+ if (retval)
+ break;
+
+ if (copy_to_user((void *) buf + n, (void *) (rx_buf + rx_head),
+ sizeof(int))) {
+ retval = -EFAULT;
+ break;
+ }
+ rx_head = (rx_head + 1) & (RBUF_LEN - 1);
+ n += sizeof(int);
+ }
+ if (n)
+ return n;
+ return retval;
+}
+
+
+static ssize_t lirc_write(struct file *file, const char *buf,
+ size_t n, loff_t *pos)
+{
+ int i = 0;
+ int *tx_buf;
+
+ if (n % sizeof(int))
+ return -EINVAL;
+ tx_buf = memdup_user(buf, n);
+ if (IS_ERR(tx_buf))
+ return PTR_ERR(tx_buf);
+ n /= sizeof(int);
+ init_send();
+ while (1) {
+ if (i >= n)
+ break;
+ if (tx_buf[i])
+ send_pulse(tx_buf[i]);
+ i++;
+ if (i >= n)
+ break;
+ if (tx_buf[i])
+ send_space(tx_buf[i]);
+ i++;
+ }
+ terminate_send(tx_buf[i - 1]);
+ return n;
+}
+
+
+static long lirc_ioctl(struct file *filep, unsigned int cmd, unsigned long arg)
+{
+ int retval = 0;
+ unsigned long value = 0;
+ unsigned int ivalue;
+ unsigned long hw_flags;
+
+ if (cmd == LIRC_GET_FEATURES)
+ value = LIRC_CAN_SEND_PULSE |
+ LIRC_CAN_SET_SEND_CARRIER |
+ LIRC_CAN_REC_MODE2;
+ else if (cmd == LIRC_GET_SEND_MODE)
+ value = LIRC_MODE_PULSE;
+ else if (cmd == LIRC_GET_REC_MODE)
+ value = LIRC_MODE_MODE2;
+
+ switch (cmd) {
+ case LIRC_GET_FEATURES:
+ case LIRC_GET_SEND_MODE:
+ case LIRC_GET_REC_MODE:
+ retval = put_user(value, (unsigned long *) arg);
+ break;
+
+ case LIRC_SET_SEND_MODE:
+ case LIRC_SET_REC_MODE:
+ retval = get_user(value, (unsigned long *) arg);
+ break;
+
+ case LIRC_SET_SEND_CARRIER:
+ retval = get_user(ivalue, (unsigned int *) arg);
+ if (retval)
+ return retval;
+ ivalue /= 1000;
+ if (ivalue > IT87_CIR_FREQ_MAX ||
+ ivalue < IT87_CIR_FREQ_MIN)
+ return -EINVAL;
+
+ it87_freq = ivalue;
+
+ spin_lock_irqsave(&hardware_lock, hw_flags);
+ outb(((inb(io + IT87_CIR_TCR2) & IT87_CIR_TCR2_TXMPW) |
+ (it87_freq - IT87_CIR_FREQ_MIN) << 3),
+ io + IT87_CIR_TCR2);
+ spin_unlock_irqrestore(&hardware_lock, hw_flags);
+ dprintk("demodulation frequency: %d kHz\n", it87_freq);
+
+ break;
+
+ default:
+ retval = -EINVAL;
+ }
+
+ if (retval)
+ return retval;
+
+ if (cmd == LIRC_SET_REC_MODE) {
+ if (value != LIRC_MODE_MODE2)
+ retval = -ENOSYS;
+ } else if (cmd == LIRC_SET_SEND_MODE) {
+ if (value != LIRC_MODE_PULSE)
+ retval = -ENOSYS;
+ }
+ return retval;
+}
+
+static void add_read_queue(int flag, unsigned long val)
+{
+ unsigned int new_rx_tail;
+ int newval;
+
+ dprintk("add flag %d with val %lu\n", flag, val);
+
+ newval = val & PULSE_MASK;
+
+ /*
+ * statistically, pulses are ~TIME_CONST/2 too long. we could
+ * maybe make this more exact, but this is good enough
+ */
+ if (flag) {
+ /* pulse */
+ if (newval > TIME_CONST / 2)
+ newval -= TIME_CONST / 2;
+ else /* should not ever happen */
+ newval = 1;
+ newval |= PULSE_BIT;
+ } else
+ newval += TIME_CONST / 2;
+ new_rx_tail = (rx_tail + 1) & (RBUF_LEN - 1);
+ if (new_rx_tail == rx_head) {
+ dprintk("Buffer overrun.\n");
+ return;
+ }
+ rx_buf[rx_tail] = newval;
+ rx_tail = new_rx_tail;
+ wake_up_interruptible(&lirc_read_queue);
+}
+
+
+static const struct file_operations lirc_fops = {
+ .owner = THIS_MODULE,
+ .read = lirc_read,
+ .write = lirc_write,
+ .poll = lirc_poll,
+ .unlocked_ioctl = lirc_ioctl,
+ .open = lirc_open,
+ .release = lirc_close,
+};
+
+static int set_use_inc(void *data)
+{
+ return 0;
+}
+
+static void set_use_dec(void *data)
+{
+}
+
+static struct lirc_driver driver = {
+ .name = LIRC_DRIVER_NAME,
+ .minor = -1,
+ .code_length = 1,
+ .sample_rate = 0,
+ .data = NULL,
+ .add_to_buf = NULL,
+ .set_use_inc = set_use_inc,
+ .set_use_dec = set_use_dec,
+ .fops = &lirc_fops,
+ .dev = NULL,
+ .owner = THIS_MODULE,
+};
+
+
+#ifdef MODULE
+static int init_chrdev(void)
+{
+ driver.minor = lirc_register_driver(&driver);
+
+ if (driver.minor < 0) {
+ printk(KERN_ERR LIRC_DRIVER_NAME ": init_chrdev() failed.\n");
+ return -EIO;
+ }
+ return 0;
+}
+
+
+static void drop_chrdev(void)
+{
+ lirc_unregister_driver(driver.minor);
+}
+#endif
+
+
+/* SECTION: Hardware */
+static long delta(struct timeval *tv1, struct timeval *tv2)
+{
+ unsigned long deltv;
+
+ deltv = tv2->tv_sec - tv1->tv_sec;
+ if (deltv > 15)
+ deltv = 0xFFFFFF;
+ else
+ deltv = deltv*1000000 + tv2->tv_usec - tv1->tv_usec;
+ return deltv;
+}
+
+static void it87_timeout(unsigned long data)
+{
+ unsigned long flags;
+
+ /* avoid interference with interrupt */
+ spin_lock_irqsave(&timer_lock, flags);
+
+ if (digimatrix) {
+ /* We have timed out. Disable the RX mechanism. */
+
+ outb((inb(io + IT87_CIR_RCR) & ~IT87_CIR_RCR_RXEN) |
+ IT87_CIR_RCR_RXACT, io + IT87_CIR_RCR);
+ if (it87_RXEN_mask)
+ outb(inb(io + IT87_CIR_RCR) | IT87_CIR_RCR_RXEN,
+ io + IT87_CIR_RCR);
+ dprintk(" TIMEOUT\n");
+ timer_enabled = 0;
+
+ /* fifo clear */
+ outb(inb(io + IT87_CIR_TCR1) | IT87_CIR_TCR1_FIFOCLR,
+ io+IT87_CIR_TCR1);
+
+ } else {
+ /*
+ * if last received signal was a pulse, but receiving stopped
+ * within the 9 bit frame, we need to finish this pulse and
+ * simulate a signal change to from pulse to space. Otherwise
+ * upper layers will receive two sequences next time.
+ */
+
+ if (last_value) {
+ unsigned long pulse_end;
+
+ /* determine 'virtual' pulse end: */
+ pulse_end = delta(&last_tv, &last_intr_tv);
+ dprintk("timeout add %d for %lu usec\n",
+ last_value, pulse_end);
+ add_read_queue(last_value, pulse_end);
+ last_value = 0;
+ last_tv = last_intr_tv;
+ }
+ }
+ spin_unlock_irqrestore(&timer_lock, flags);
+}
+
+static irqreturn_t it87_interrupt(int irq, void *dev_id)
+{
+ unsigned char data;
+ struct timeval curr_tv;
+ static unsigned long deltv;
+ unsigned long deltintrtv;
+ unsigned long flags, hw_flags;
+ int iir, lsr;
+ int fifo = 0;
+ static char lastbit;
+ char bit;
+
+ /* Bit duration in microseconds */
+ const unsigned long bit_duration = 1000000ul /
+ (115200 / IT87_CIR_BAUDRATE_DIVISOR);
+
+
+ iir = inb(io + IT87_CIR_IIR);
+
+ switch (iir & IT87_CIR_IIR_IID) {
+ case 0x4:
+ case 0x6:
+ lsr = inb(io + IT87_CIR_RSR) & (IT87_CIR_RSR_RXFTO |
+ IT87_CIR_RSR_RXFBC);
+ fifo = lsr & IT87_CIR_RSR_RXFBC;
+ dprintk("iir: 0x%x fifo: 0x%x\n", iir, lsr);
+
+ /* avoid interference with timer */
+ spin_lock_irqsave(&timer_lock, flags);
+ spin_lock_irqsave(&hardware_lock, hw_flags);
+ if (digimatrix) {
+ static unsigned long acc_pulse;
+ static unsigned long acc_space;
+
+ do {
+ data = inb(io + IT87_CIR_DR);
+ data = ~data;
+ fifo--;
+ if (data != 0x00) {
+ if (timer_enabled)
+ del_timer(&timerlist);
+ /*
+ * start timer for end of
+ * sequence detection
+ */
+ timerlist.expires = jiffies +
+ IT87_TIMEOUT;
+ add_timer(&timerlist);
+ timer_enabled = 1;
+ }
+ /* Loop through */
+ for (bit = 0; bit < 8; ++bit) {
+ if ((data >> bit) & 1) {
+ ++acc_pulse;
+ if (lastbit == 0) {
+ add_read_queue(0,
+ acc_space *
+ bit_duration);
+ acc_space = 0;
+ }
+ } else {
+ ++acc_space;
+ if (lastbit == 1) {
+ add_read_queue(1,
+ acc_pulse *
+ bit_duration);
+ acc_pulse = 0;
+ }
+ }
+ lastbit = (data >> bit) & 1;
+ }
+
+ } while (fifo != 0);
+ } else { /* Normal Operation */
+ do {
+ del_timer(&timerlist);
+ data = inb(io + IT87_CIR_DR);
+
+ dprintk("data=%02x\n", data);
+ do_gettimeofday(&curr_tv);
+ deltv = delta(&last_tv, &curr_tv);
+ deltintrtv = delta(&last_intr_tv, &curr_tv);
+
+ dprintk("t %lu , d %d\n",
+ deltintrtv, (int)data);
+
+ /*
+ * if nothing came in last 2 cycles,
+ * it was gap
+ */
+ if (deltintrtv > TIME_CONST * 2) {
+ if (last_value) {
+ dprintk("GAP\n");
+
+ /* simulate signal change */
+ add_read_queue(last_value,
+ deltv -
+ deltintrtv);
+ last_value = 0;
+ last_tv.tv_sec =
+ last_intr_tv.tv_sec;
+ last_tv.tv_usec =
+ last_intr_tv.tv_usec;
+ deltv = deltintrtv;
+ }
+ }
+ data = 1;
+ if (data ^ last_value) {
+ /*
+ * deltintrtv > 2*TIME_CONST,
+ * remember ? the other case is
+ * timeout
+ */
+ add_read_queue(last_value,
+ deltv-TIME_CONST);
+ last_value = data;
+ last_tv = curr_tv;
+ if (last_tv.tv_usec >= TIME_CONST)
+ last_tv.tv_usec -= TIME_CONST;
+ else {
+ last_tv.tv_sec--;
+ last_tv.tv_usec += 1000000 -
+ TIME_CONST;
+ }
+ }
+ last_intr_tv = curr_tv;
+ if (data) {
+ /*
+ * start timer for end of
+ * sequence detection
+ */
+ timerlist.expires =
+ jiffies + IT87_TIMEOUT;
+ add_timer(&timerlist);
+ }
+ outb((inb(io + IT87_CIR_RCR) &
+ ~IT87_CIR_RCR_RXEN) |
+ IT87_CIR_RCR_RXACT,
+ io + IT87_CIR_RCR);
+ if (it87_RXEN_mask)
+ outb(inb(io + IT87_CIR_RCR) |
+ IT87_CIR_RCR_RXEN,
+ io + IT87_CIR_RCR);
+ fifo--;
+ } while (fifo != 0);
+ }
+ spin_unlock_irqrestore(&hardware_lock, hw_flags);
+ spin_unlock_irqrestore(&timer_lock, flags);
+
+ return IRQ_RETVAL(IRQ_HANDLED);
+
+ default:
+ /* not our irq */
+ dprintk("unknown IRQ (shouldn't happen) !!\n");
+ return IRQ_RETVAL(IRQ_NONE);
+ }
+}
+
+
+static void send_it87(unsigned long len, unsigned long stime,
+ unsigned char send_byte, unsigned int count_bits)
+{
+ long count = len / stime;
+ long time_left = 0;
+ static unsigned char byte_out;
+ unsigned long hw_flags;
+
+ dprintk("%s: len=%ld, sb=%d\n", __func__, len, send_byte);
+
+ time_left = (long)len - (long)count * (long)stime;
+ count += ((2 * time_left) / stime);
+ while (count) {
+ long i = 0;
+ for (i = 0; i < count_bits; i++) {
+ byte_out = (byte_out << 1) | (send_byte & 1);
+ it87_bits_in_byte_out++;
+ }
+ if (it87_bits_in_byte_out == 8) {
+ dprintk("out=0x%x, tsr_txfbc: 0x%x\n",
+ byte_out,
+ inb(io + IT87_CIR_TSR) &
+ IT87_CIR_TSR_TXFBC);
+
+ while ((inb(io + IT87_CIR_TSR) &
+ IT87_CIR_TSR_TXFBC) >= IT87_CIR_FIFO_SIZE)
+ ;
+
+ spin_lock_irqsave(&hardware_lock, hw_flags);
+ outb(byte_out, io + IT87_CIR_DR);
+ spin_unlock_irqrestore(&hardware_lock, hw_flags);
+
+ it87_bits_in_byte_out = 0;
+ it87_send_counter++;
+ byte_out = 0;
+ }
+ count--;
+ }
+}
+
+
+/*TODO: maybe exchange space and pulse because it8705 only modulates 0-bits */
+
+static void send_space(unsigned long len)
+{
+ send_it87(len, TIME_CONST, IT87_CIR_SPACE, IT87_CIR_BAUDRATE_DIVISOR);
+}
+
+static void send_pulse(unsigned long len)
+{
+ send_it87(len, TIME_CONST, IT87_CIR_PULSE, IT87_CIR_BAUDRATE_DIVISOR);
+}
+
+
+static void init_send()
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&hardware_lock, flags);
+ /* RXEN=0: receiver disable */
+ it87_RXEN_mask = 0;
+ outb(inb(io + IT87_CIR_RCR) & ~IT87_CIR_RCR_RXEN,
+ io + IT87_CIR_RCR);
+ spin_unlock_irqrestore(&hardware_lock, flags);
+ it87_bits_in_byte_out = 0;
+ it87_send_counter = 0;
+}
+
+
+static void terminate_send(unsigned long len)
+{
+ unsigned long flags;
+ unsigned long last = 0;
+
+ last = it87_send_counter;
+ /* make sure all necessary data has been sent */
+ while (last == it87_send_counter)
+ send_space(len);
+ /* wait until all data sent */
+ while ((inb(io + IT87_CIR_TSR) & IT87_CIR_TSR_TXFBC) != 0)
+ ;
+ /* then re-enable receiver */
+ spin_lock_irqsave(&hardware_lock, flags);
+ it87_RXEN_mask = IT87_CIR_RCR_RXEN;
+ outb(inb(io + IT87_CIR_RCR) | IT87_CIR_RCR_RXEN,
+ io + IT87_CIR_RCR);
+ spin_unlock_irqrestore(&hardware_lock, flags);
+}
+
+
+static int init_hardware(void)
+{
+ unsigned long flags;
+ unsigned char it87_rcr = 0;
+
+ spin_lock_irqsave(&hardware_lock, flags);
+ /* init cir-port */
+ /* enable r/w-access to Baudrate-Register */
+ outb(IT87_CIR_IER_BR, io + IT87_CIR_IER);
+ outb(IT87_CIR_BAUDRATE_DIVISOR % 0x100, io+IT87_CIR_BDLR);
+ outb(IT87_CIR_BAUDRATE_DIVISOR / 0x100, io+IT87_CIR_BDHR);
+ /* Baudrate Register off, define IRQs: Input only */
+ if (digimatrix) {
+ outb(IT87_CIR_IER_IEC | IT87_CIR_IER_RFOIE, io + IT87_CIR_IER);
+ /* RX: HCFS=0, RXDCR = 001b (33,75..38,25 kHz), RXEN=1 */
+ } else {
+ outb(IT87_CIR_IER_IEC | IT87_CIR_IER_RDAIE, io + IT87_CIR_IER);
+ /* RX: HCFS=0, RXDCR = 001b (35,6..40,3 kHz), RXEN=1 */
+ }
+ it87_rcr = (IT87_CIR_RCR_RXEN & it87_RXEN_mask) | 0x1;
+ if (it87_enable_demodulator)
+ it87_rcr |= IT87_CIR_RCR_RXEND;
+ outb(it87_rcr, io + IT87_CIR_RCR);
+ if (digimatrix) {
+ /* Set FIFO depth to 1 byte, and disable TX */
+ outb(inb(io + IT87_CIR_TCR1) | 0x00,
+ io + IT87_CIR_TCR1);
+
+ /*
+ * TX: it87_freq (36kHz), 'reserved' sensitivity
+ * setting (0x00)
+ */
+ outb(((it87_freq - IT87_CIR_FREQ_MIN) << 3) | 0x00,
+ io + IT87_CIR_TCR2);
+ } else {
+ /* TX: 38kHz, 13,3us (pulse-width) */
+ outb(((it87_freq - IT87_CIR_FREQ_MIN) << 3) | 0x06,
+ io + IT87_CIR_TCR2);
+ }
+ spin_unlock_irqrestore(&hardware_lock, flags);
+ return 0;
+}
+
+
+static void drop_hardware(void)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&hardware_lock, flags);
+ disable_irq(irq);
+ /* receiver disable */
+ it87_RXEN_mask = 0;
+ outb(0x1, io + IT87_CIR_RCR);
+ /* turn off irqs */
+ outb(0, io + IT87_CIR_IER);
+ /* fifo clear */
+ outb(IT87_CIR_TCR1_FIFOCLR, io+IT87_CIR_TCR1);
+ /* reset */
+ outb(IT87_CIR_IER_RESET, io+IT87_CIR_IER);
+ enable_irq(irq);
+ spin_unlock_irqrestore(&hardware_lock, flags);
+}
+
+
+static unsigned char it87_read(unsigned char port)
+{
+ outb(port, IT87_ADRPORT);
+ return inb(IT87_DATAPORT);
+}
+
+
+static void it87_write(unsigned char port, unsigned char data)
+{
+ outb(port, IT87_ADRPORT);
+ outb(data, IT87_DATAPORT);
+}
+
+
+/* SECTION: Initialisation */
+
+static int init_port(void)
+{
+ unsigned long hw_flags;
+ int retval = 0;
+
+ unsigned char init_bytes[4] = IT87_INIT;
+ unsigned char it87_chipid = 0;
+ unsigned char ldn = 0;
+ unsigned int it87_io = 0;
+ unsigned int it87_irq = 0;
+
+ /* Enter MB PnP Mode */
+ outb(init_bytes[0], IT87_ADRPORT);
+ outb(init_bytes[1], IT87_ADRPORT);
+ outb(init_bytes[2], IT87_ADRPORT);
+ outb(init_bytes[3], IT87_ADRPORT);
+
+ /* 8712 or 8705 ? */
+ it87_chipid = it87_read(IT87_CHIP_ID1);
+ if (it87_chipid != 0x87) {
+ retval = -ENXIO;
+ return retval;
+ }
+ it87_chipid = it87_read(IT87_CHIP_ID2);
+ if ((it87_chipid != 0x05) &&
+ (it87_chipid != 0x12) &&
+ (it87_chipid != 0x18) &&
+ (it87_chipid != 0x20)) {
+ printk(KERN_INFO LIRC_DRIVER_NAME
+ ": no IT8704/05/12/18/20 found (claimed IT87%02x), "
+ "exiting..\n", it87_chipid);
+ retval = -ENXIO;
+ return retval;
+ }
+ printk(KERN_INFO LIRC_DRIVER_NAME
+ ": found IT87%02x.\n",
+ it87_chipid);
+
+ /* get I/O-Port and IRQ */
+ if (it87_chipid == 0x12 || it87_chipid == 0x18)
+ ldn = IT8712_CIR_LDN;
+ else
+ ldn = IT8705_CIR_LDN;
+ it87_write(IT87_LDN, ldn);
+
+ it87_io = it87_read(IT87_CIR_BASE_MSB) * 256 +
+ it87_read(IT87_CIR_BASE_LSB);
+ if (it87_io == 0) {
+ if (io == 0)
+ io = IT87_CIR_DEFAULT_IOBASE;
+ printk(KERN_INFO LIRC_DRIVER_NAME
+ ": set default io 0x%x\n",
+ io);
+ it87_write(IT87_CIR_BASE_MSB, io / 0x100);
+ it87_write(IT87_CIR_BASE_LSB, io % 0x100);
+ } else
+ io = it87_io;
+
+ it87_irq = it87_read(IT87_CIR_IRQ);
+ if (digimatrix || it87_irq == 0) {
+ if (irq == 0)
+ irq = IT87_CIR_DEFAULT_IRQ;
+ printk(KERN_INFO LIRC_DRIVER_NAME
+ ": set default irq 0x%x\n",
+ irq);
+ it87_write(IT87_CIR_IRQ, irq);
+ } else
+ irq = it87_irq;
+
+ spin_lock_irqsave(&hardware_lock, hw_flags);
+ /* reset */
+ outb(IT87_CIR_IER_RESET, io+IT87_CIR_IER);
+ /* fifo clear */
+ outb(IT87_CIR_TCR1_FIFOCLR |
+ /* IT87_CIR_TCR1_ILE | */
+ IT87_CIR_TCR1_TXRLE |
+ IT87_CIR_TCR1_TXENDF, io+IT87_CIR_TCR1);
+ spin_unlock_irqrestore(&hardware_lock, hw_flags);
+
+ /* get I/O port access and IRQ line */
+ if (request_region(io, 8, LIRC_DRIVER_NAME) == NULL) {
+ printk(KERN_ERR LIRC_DRIVER_NAME
+ ": i/o port 0x%.4x already in use.\n", io);
+ /* Leaving MB PnP Mode */
+ it87_write(IT87_CFGCTRL, 0x2);
+ return -EBUSY;
+ }
+
+ /* activate CIR-Device */
+ it87_write(IT87_CIR_ACT, 0x1);
+
+ /* Leaving MB PnP Mode */
+ it87_write(IT87_CFGCTRL, 0x2);
+
+ retval = request_irq(irq, it87_interrupt, 0 /*IRQF_DISABLED*/,
+ LIRC_DRIVER_NAME, NULL);
+ if (retval < 0) {
+ printk(KERN_ERR LIRC_DRIVER_NAME
+ ": IRQ %d already in use.\n",
+ irq);
+ release_region(io, 8);
+ return retval;
+ }
+
+ printk(KERN_INFO LIRC_DRIVER_NAME
+ ": I/O port 0x%.4x, IRQ %d.\n", io, irq);
+
+ init_timer(&timerlist);
+ timerlist.function = it87_timeout;
+ timerlist.data = 0xabadcafe;
+
+ return 0;
+}
+
+
+static void drop_port(void)
+{
+#if 0
+ unsigned char init_bytes[4] = IT87_INIT;
+
+ /* Enter MB PnP Mode */
+ outb(init_bytes[0], IT87_ADRPORT);
+ outb(init_bytes[1], IT87_ADRPORT);
+ outb(init_bytes[2], IT87_ADRPORT);
+ outb(init_bytes[3], IT87_ADRPORT);
+
+ /* deactivate CIR-Device */
+ it87_write(IT87_CIR_ACT, 0x0);
+
+ /* Leaving MB PnP Mode */
+ it87_write(IT87_CFGCTRL, 0x2);
+#endif
+
+ del_timer_sync(&timerlist);
+ free_irq(irq, NULL);
+ release_region(io, 8);
+}
+
+
+static int init_lirc_it87(void)
+{
+ int retval;
+
+ init_waitqueue_head(&lirc_read_queue);
+ retval = init_port();
+ if (retval < 0)
+ return retval;
+ init_hardware();
+ printk(KERN_INFO LIRC_DRIVER_NAME ": Installed.\n");
+ return 0;
+}
+
+static int it87_probe(struct pnp_dev *pnp_dev,
+ const struct pnp_device_id *dev_id)
+{
+ int retval;
+
+ driver.dev = &pnp_dev->dev;
+
+ retval = init_chrdev();
+ if (retval < 0)
+ return retval;
+
+ retval = init_lirc_it87();
+ if (retval)
+ goto init_lirc_it87_failed;
+
+ return 0;
+
+init_lirc_it87_failed:
+ drop_chrdev();
+
+ return retval;
+}
+
+static int __init lirc_it87_init(void)
+{
+ return pnp_register_driver(&it87_pnp_driver);
+}
+
+
+static void __exit lirc_it87_exit(void)
+{
+ drop_hardware();
+ drop_chrdev();
+ drop_port();
+ pnp_unregister_driver(&it87_pnp_driver);
+ printk(KERN_INFO LIRC_DRIVER_NAME ": Uninstalled.\n");
+}
+
+/* SECTION: PNP for ITE8704/18 */
+
+static const struct pnp_device_id pnp_dev_table[] = {
+ {"ITE8704", 0},
+ {}
+};
+
+MODULE_DEVICE_TABLE(pnp, pnp_dev_table);
+
+static struct pnp_driver it87_pnp_driver = {
+ .name = LIRC_DRIVER_NAME,
+ .id_table = pnp_dev_table,
+ .probe = it87_probe,
+};
+
+module_init(lirc_it87_init);
+module_exit(lirc_it87_exit);
+
+MODULE_DESCRIPTION("LIRC driver for ITE IT8704/05/12/18/20 CIR port");
+MODULE_AUTHOR("Hans-Gunter Lutke Uphues");
+MODULE_LICENSE("GPL");
+
+module_param(io, int, S_IRUGO);
+MODULE_PARM_DESC(io, "I/O base address (default: 0x310)");
+
+module_param(irq, int, S_IRUGO);
+#ifdef LIRC_IT87_DIGIMATRIX
+MODULE_PARM_DESC(irq, "Interrupt (1,3-12) (default: 9)");
+#else
+MODULE_PARM_DESC(irq, "Interrupt (1,3-12) (default: 7)");
+#endif
+
+module_param(it87_enable_demodulator, bool, S_IRUGO);
+MODULE_PARM_DESC(it87_enable_demodulator,
+ "Receiver demodulator enable/disable (1/0), default: 0");
+
+module_param(debug, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug, "Enable debugging messages");
+
+module_param(digimatrix, bool, S_IRUGO | S_IWUSR);
+#ifdef LIRC_IT87_DIGIMATRIX
+MODULE_PARM_DESC(digimatrix,
+ "Asus Digimatrix it87 compat. enable/disable (1/0), default: 1");
+#else
+MODULE_PARM_DESC(digimatrix,
+ "Asus Digimatrix it87 compat. enable/disable (1/0), default: 0");
+#endif
+
+
+module_param(it87_freq, int, S_IRUGO);
+#ifdef LIRC_IT87_DIGIMATRIX
+MODULE_PARM_DESC(it87_freq,
+ "Carrier demodulator frequency (kHz), (default: 36)");
+#else
+MODULE_PARM_DESC(it87_freq,
+ "Carrier demodulator frequency (kHz), (default: 38)");
+#endif
diff --git a/drivers/staging/lirc/lirc_it87.h b/drivers/staging/lirc/lirc_it87.h
new file mode 100644
index 00000000000..cf021c893a3
--- /dev/null
+++ b/drivers/staging/lirc/lirc_it87.h
@@ -0,0 +1,116 @@
+/* lirc_it87.h */
+/* SECTION: Definitions */
+
+/********************************* ITE IT87xx ************************/
+
+/* based on the following documentation from ITE:
+ a) IT8712F Preliminary CIR Programming Guide V0.1
+ b) IT8705F Simple LPC I/O Preliminary Specification V0.3
+ c) IT8712F EC-LPC I/O Preliminary Specification V0.5
+*/
+
+/* IT8712/05 Ports: */
+#define IT87_ADRPORT 0x2e
+#define IT87_DATAPORT 0x2f
+#define IT87_INIT {0x87, 0x01, 0x55, 0x55}
+
+/* alternate Ports: */
+/*
+#define IT87_ADRPORT 0x4e
+#define IT87_DATAPORT 0x4f
+#define IT87_INIT {0x87, 0x01, 0x55, 0xaa}
+ */
+
+/* IT8712/05 Registers */
+#define IT87_CFGCTRL 0x2
+#define IT87_LDN 0x7
+#define IT87_CHIP_ID1 0x20
+#define IT87_CHIP_ID2 0x21
+#define IT87_CFG_VERSION 0x22
+#define IT87_SWSUSPEND 0x23
+
+#define IT8712_CIR_LDN 0xa
+#define IT8705_CIR_LDN 0x7
+
+/* CIR Configuration Registers: */
+#define IT87_CIR_ACT 0x30
+#define IT87_CIR_BASE_MSB 0x60
+#define IT87_CIR_BASE_LSB 0x61
+#define IT87_CIR_IRQ 0x70
+#define IT87_CIR_CONFIG 0xf0
+
+/* List of IT87_CIR registers: offset to BaseAddr */
+#define IT87_CIR_DR 0
+#define IT87_CIR_IER 1
+#define IT87_CIR_RCR 2
+#define IT87_CIR_TCR1 3
+#define IT87_CIR_TCR2 4
+#define IT87_CIR_TSR 5
+#define IT87_CIR_RSR 6
+#define IT87_CIR_BDLR 5
+#define IT87_CIR_BDHR 6
+#define IT87_CIR_IIR 7
+
+/* Bit Definition */
+/* IER: */
+#define IT87_CIR_IER_TM_EN 0x80
+#define IT87_CIR_IER_RESEVED 0x40
+#define IT87_CIR_IER_RESET 0x20
+#define IT87_CIR_IER_BR 0x10
+#define IT87_CIR_IER_IEC 0x8
+#define IT87_CIR_IER_RFOIE 0x4
+#define IT87_CIR_IER_RDAIE 0x2
+#define IT87_CIR_IER_TLDLIE 0x1
+
+/* RCR: */
+#define IT87_CIR_RCR_RDWOS 0x80
+#define IT87_CIR_RCR_HCFS 0x40
+#define IT87_CIR_RCR_RXEN 0x20
+#define IT87_CIR_RCR_RXEND 0x10
+#define IT87_CIR_RCR_RXACT 0x8
+#define IT87_CIR_RCR_RXDCR 0x7
+
+/* TCR1: */
+#define IT87_CIR_TCR1_FIFOCLR 0x80
+#define IT87_CIR_TCR1_ILE 0x40
+#define IT87_CIR_TCR1_FIFOTL 0x30
+#define IT87_CIR_TCR1_TXRLE 0x8
+#define IT87_CIR_TCR1_TXENDF 0x4
+#define IT87_CIR_TCR1_TXMPM 0x3
+
+/* TCR2: */
+#define IT87_CIR_TCR2_CFQ 0xf8
+#define IT87_CIR_TCR2_TXMPW 0x7
+
+/* TSR: */
+#define IT87_CIR_TSR_RESERVED 0xc0
+#define IT87_CIR_TSR_TXFBC 0x3f
+
+/* RSR: */
+#define IT87_CIR_RSR_RXFTO 0x80
+#define IT87_CIR_RSR_RESERVED 0x40
+#define IT87_CIR_RSR_RXFBC 0x3f
+
+/* IIR: */
+#define IT87_CIR_IIR_RESERVED 0xf8
+#define IT87_CIR_IIR_IID 0x6
+#define IT87_CIR_IIR_IIP 0x1
+
+/* TM: */
+#define IT87_CIR_TM_IL_SEL 0x80
+#define IT87_CIR_TM_RESERVED 0x40
+#define IT87_CIR_TM_TM_REG 0x3f
+
+#define IT87_CIR_FIFO_SIZE 32
+
+/* Baudratedivisor for IT87: power of 2: only 1,2,4 or 8) */
+#define IT87_CIR_BAUDRATE_DIVISOR 0x1
+#define IT87_CIR_DEFAULT_IOBASE 0x310
+#define IT87_CIR_DEFAULT_IRQ 0x7
+#define IT87_CIR_SPACE 0x00
+#define IT87_CIR_PULSE 0xff
+#define IT87_CIR_FREQ_MIN 27
+#define IT87_CIR_FREQ_MAX 58
+#define TIME_CONST (IT87_CIR_BAUDRATE_DIVISOR * 8000000ul / 115200ul)
+
+/********************************* ITE IT87xx ************************/
diff --git a/drivers/staging/lirc/lirc_ite8709.c b/drivers/staging/lirc/lirc_ite8709.c
new file mode 100644
index 00000000000..9352f45bbec
--- /dev/null
+++ b/drivers/staging/lirc/lirc_ite8709.c
@@ -0,0 +1,542 @@
+/*
+ * LIRC driver for ITE8709 CIR port
+ *
+ * Copyright (C) 2008 Grégory Lardière <spmf2004-lirc@yahoo.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/interrupt.h>
+#include <linux/sched.h>
+#include <linux/delay.h>
+#include <linux/pnp.h>
+#include <linux/io.h>
+
+#include <media/lirc.h>
+#include <media/lirc_dev.h>
+
+#define LIRC_DRIVER_NAME "lirc_ite8709"
+
+#define BUF_CHUNK_SIZE sizeof(int)
+#define BUF_SIZE (128*BUF_CHUNK_SIZE)
+
+/*
+ * The ITE8709 device seems to be the combination of IT8512 superIO chip and
+ * a specific firmware running on the IT8512's embedded micro-controller.
+ * In addition of the embedded micro-controller, the IT8512 chip contains a
+ * CIR module and several other modules. A few modules are directly accessible
+ * by the host CPU, but most of them are only accessible by the
+ * micro-controller. The CIR module is only accessible by the micro-controller.
+ * The battery-backed SRAM module is accessible by the host CPU and the
+ * micro-controller. So one of the MC's firmware role is to act as a bridge
+ * between the host CPU and the CIR module. The firmware implements a kind of
+ * communication protocol using the SRAM module as a shared memory. The IT8512
+ * specification is publicly available on ITE's web site, but the communication
+ * protocol is not, so it was reverse-engineered.
+ */
+
+/* ITE8709 Registers addresses and values (reverse-engineered) */
+#define ITE8709_MODE 0x1a
+#define ITE8709_REG_ADR 0x1b
+#define ITE8709_REG_VAL 0x1c
+#define ITE8709_IIR 0x1e /* Interrupt identification register */
+#define ITE8709_RFSR 0x1f /* Receiver FIFO status register */
+#define ITE8709_FIFO_START 0x20
+
+#define ITE8709_MODE_READY 0X00
+#define ITE8709_MODE_WRITE 0X01
+#define ITE8709_MODE_READ 0X02
+#define ITE8709_IIR_RDAI 0x02 /* Receiver data available interrupt */
+#define ITE8709_IIR_RFOI 0x04 /* Receiver FIFO overrun interrupt */
+#define ITE8709_RFSR_MASK 0x3f /* FIFO byte count mask */
+
+/*
+ * IT8512 CIR-module registers addresses and values
+ * (from IT8512 E/F specification v0.4.1)
+ */
+#define IT8512_REG_MSTCR 0x01 /* Master control register */
+#define IT8512_REG_IER 0x02 /* Interrupt enable register */
+#define IT8512_REG_CFR 0x04 /* Carrier frequency register */
+#define IT8512_REG_RCR 0x05 /* Receive control register */
+#define IT8512_REG_BDLR 0x08 /* Baud rate divisor low byte register */
+#define IT8512_REG_BDHR 0x09 /* Baud rate divisor high byte register */
+
+#define IT8512_MSTCR_RESET 0x01 /* Reset registers to default value */
+#define IT8512_MSTCR_FIFOCLR 0x02 /* Clear FIFO */
+#define IT8512_MSTCR_FIFOTL_7 0x04 /* FIFO threshold level : 7 */
+#define IT8512_MSTCR_FIFOTL_25 0x0c /* FIFO threshold level : 25 */
+#define IT8512_IER_RDAIE 0x02 /* Enable data interrupt request */
+#define IT8512_IER_RFOIE 0x04 /* Enable FIFO overrun interrupt req */
+#define IT8512_IER_IEC 0x80 /* Enable interrupt request */
+#define IT8512_CFR_CF_36KHZ 0x09 /* Carrier freq : low speed, 36kHz */
+#define IT8512_RCR_RXDCR_1 0x01 /* Demodulation carrier range : 1 */
+#define IT8512_RCR_RXACT 0x08 /* Receiver active */
+#define IT8512_RCR_RXEN 0x80 /* Receiver enable */
+#define IT8512_BDR_6 6 /* Baud rate divisor : 6 */
+
+/* Actual values used by this driver */
+#define CFG_FIFOTL IT8512_MSTCR_FIFOTL_25
+#define CFG_CR_FREQ IT8512_CFR_CF_36KHZ
+#define CFG_DCR IT8512_RCR_RXDCR_1
+#define CFG_BDR IT8512_BDR_6
+#define CFG_TIMEOUT 100000 /* Rearm interrupt when a space is > 100 ms */
+
+static int debug;
+
+struct ite8709_device {
+ int use_count;
+ int io;
+ int irq;
+ spinlock_t hardware_lock;
+ unsigned long long acc_pulse;
+ unsigned long long acc_space;
+ char lastbit;
+ struct timeval last_tv;
+ struct lirc_driver driver;
+ struct tasklet_struct tasklet;
+ char force_rearm;
+ char rearmed;
+ char device_busy;
+};
+
+#define dprintk(fmt, args...) \
+ do { \
+ if (debug) \
+ printk(KERN_DEBUG LIRC_DRIVER_NAME ": " \
+ fmt, ## args); \
+ } while (0)
+
+
+static unsigned char ite8709_read(struct ite8709_device *dev,
+ unsigned char port)
+{
+ outb(port, dev->io);
+ return inb(dev->io+1);
+}
+
+static void ite8709_write(struct ite8709_device *dev, unsigned char port,
+ unsigned char data)
+{
+ outb(port, dev->io);
+ outb(data, dev->io+1);
+}
+
+static void ite8709_wait_device(struct ite8709_device *dev)
+{
+ int i = 0;
+ /*
+ * loop until device tells it's ready to continue
+ * iterations count is usually ~750 but can sometimes achieve 13000
+ */
+ for (i = 0; i < 15000; i++) {
+ udelay(2);
+ if (ite8709_read(dev, ITE8709_MODE) == ITE8709_MODE_READY)
+ break;
+ }
+}
+
+static void ite8709_write_register(struct ite8709_device *dev,
+ unsigned char reg_adr, unsigned char reg_value)
+{
+ ite8709_wait_device(dev);
+
+ ite8709_write(dev, ITE8709_REG_VAL, reg_value);
+ ite8709_write(dev, ITE8709_REG_ADR, reg_adr);
+ ite8709_write(dev, ITE8709_MODE, ITE8709_MODE_WRITE);
+}
+
+static void ite8709_init_hardware(struct ite8709_device *dev)
+{
+ spin_lock_irq(&dev->hardware_lock);
+ dev->device_busy = 1;
+ spin_unlock_irq(&dev->hardware_lock);
+
+ ite8709_write_register(dev, IT8512_REG_BDHR, (CFG_BDR >> 8) & 0xff);
+ ite8709_write_register(dev, IT8512_REG_BDLR, CFG_BDR & 0xff);
+ ite8709_write_register(dev, IT8512_REG_CFR, CFG_CR_FREQ);
+ ite8709_write_register(dev, IT8512_REG_IER,
+ IT8512_IER_IEC | IT8512_IER_RFOIE | IT8512_IER_RDAIE);
+ ite8709_write_register(dev, IT8512_REG_RCR, CFG_DCR);
+ ite8709_write_register(dev, IT8512_REG_MSTCR,
+ CFG_FIFOTL | IT8512_MSTCR_FIFOCLR);
+ ite8709_write_register(dev, IT8512_REG_RCR,
+ IT8512_RCR_RXEN | IT8512_RCR_RXACT | CFG_DCR);
+
+ spin_lock_irq(&dev->hardware_lock);
+ dev->device_busy = 0;
+ spin_unlock_irq(&dev->hardware_lock);
+
+ tasklet_enable(&dev->tasklet);
+}
+
+static void ite8709_drop_hardware(struct ite8709_device *dev)
+{
+ tasklet_disable(&dev->tasklet);
+
+ spin_lock_irq(&dev->hardware_lock);
+ dev->device_busy = 1;
+ spin_unlock_irq(&dev->hardware_lock);
+
+ ite8709_write_register(dev, IT8512_REG_RCR, 0);
+ ite8709_write_register(dev, IT8512_REG_MSTCR,
+ IT8512_MSTCR_RESET | IT8512_MSTCR_FIFOCLR);
+
+ spin_lock_irq(&dev->hardware_lock);
+ dev->device_busy = 0;
+ spin_unlock_irq(&dev->hardware_lock);
+}
+
+static int ite8709_set_use_inc(void *data)
+{
+ struct ite8709_device *dev;
+ dev = data;
+ if (dev->use_count == 0)
+ ite8709_init_hardware(dev);
+ dev->use_count++;
+ return 0;
+}
+
+static void ite8709_set_use_dec(void *data)
+{
+ struct ite8709_device *dev;
+ dev = data;
+ dev->use_count--;
+ if (dev->use_count == 0)
+ ite8709_drop_hardware(dev);
+}
+
+static void ite8709_add_read_queue(struct ite8709_device *dev, int flag,
+ unsigned long long val)
+{
+ int value;
+
+ dprintk("add a %llu usec %s\n", val, flag ? "pulse" : "space");
+
+ value = (val > PULSE_MASK) ? PULSE_MASK : val;
+ if (flag)
+ value |= PULSE_BIT;
+
+ if (!lirc_buffer_full(dev->driver.rbuf)) {
+ lirc_buffer_write(dev->driver.rbuf, (void *) &value);
+ wake_up(&dev->driver.rbuf->wait_poll);
+ }
+}
+
+static irqreturn_t ite8709_interrupt(int irq, void *dev_id)
+{
+ unsigned char data;
+ int iir, rfsr, i;
+ int fifo = 0;
+ char bit;
+ struct timeval curr_tv;
+
+ /* Bit duration in microseconds */
+ const unsigned long bit_duration = 1000000ul / (115200 / CFG_BDR);
+
+ struct ite8709_device *dev;
+ dev = dev_id;
+
+ /*
+ * If device is busy, we simply discard data because we are in one of
+ * these two cases : shutting down or rearming the device, so this
+ * doesn't really matter and this avoids waiting too long in IRQ ctx
+ */
+ spin_lock(&dev->hardware_lock);
+ if (dev->device_busy) {
+ spin_unlock(&dev->hardware_lock);
+ return IRQ_RETVAL(IRQ_HANDLED);
+ }
+
+ iir = ite8709_read(dev, ITE8709_IIR);
+
+ switch (iir) {
+ case ITE8709_IIR_RFOI:
+ dprintk("fifo overrun, scheduling forced rearm just in case\n");
+ dev->force_rearm = 1;
+ tasklet_schedule(&dev->tasklet);
+ spin_unlock(&dev->hardware_lock);
+ return IRQ_RETVAL(IRQ_HANDLED);
+
+ case ITE8709_IIR_RDAI:
+ rfsr = ite8709_read(dev, ITE8709_RFSR);
+ fifo = rfsr & ITE8709_RFSR_MASK;
+ if (fifo > 32)
+ fifo = 32;
+ dprintk("iir: 0x%x rfsr: 0x%x fifo: %d\n", iir, rfsr, fifo);
+
+ if (dev->rearmed) {
+ do_gettimeofday(&curr_tv);
+ dev->acc_space += 1000000ull
+ * (curr_tv.tv_sec - dev->last_tv.tv_sec)
+ + (curr_tv.tv_usec - dev->last_tv.tv_usec);
+ dev->rearmed = 0;
+ }
+ for (i = 0; i < fifo; i++) {
+ data = ite8709_read(dev, i+ITE8709_FIFO_START);
+ data = ~data;
+ /* Loop through */
+ for (bit = 0; bit < 8; ++bit) {
+ if ((data >> bit) & 1) {
+ dev->acc_pulse += bit_duration;
+ if (dev->lastbit == 0) {
+ ite8709_add_read_queue(dev, 0,
+ dev->acc_space);
+ dev->acc_space = 0;
+ }
+ } else {
+ dev->acc_space += bit_duration;
+ if (dev->lastbit == 1) {
+ ite8709_add_read_queue(dev, 1,
+ dev->acc_pulse);
+ dev->acc_pulse = 0;
+ }
+ }
+ dev->lastbit = (data >> bit) & 1;
+ }
+ }
+ ite8709_write(dev, ITE8709_RFSR, 0);
+
+ if (dev->acc_space > CFG_TIMEOUT) {
+ dprintk("scheduling rearm IRQ\n");
+ do_gettimeofday(&dev->last_tv);
+ dev->force_rearm = 0;
+ tasklet_schedule(&dev->tasklet);
+ }
+
+ spin_unlock(&dev->hardware_lock);
+ return IRQ_RETVAL(IRQ_HANDLED);
+
+ default:
+ /* not our irq */
+ dprintk("unknown IRQ (shouldn't happen) !!\n");
+ spin_unlock(&dev->hardware_lock);
+ return IRQ_RETVAL(IRQ_NONE);
+ }
+}
+
+static void ite8709_rearm_irq(unsigned long data)
+{
+ struct ite8709_device *dev;
+ unsigned long flags;
+ dev = (struct ite8709_device *) data;
+
+ spin_lock_irqsave(&dev->hardware_lock, flags);
+ dev->device_busy = 1;
+ spin_unlock_irqrestore(&dev->hardware_lock, flags);
+
+ if (dev->force_rearm || dev->acc_space > CFG_TIMEOUT) {
+ dprintk("rearming IRQ\n");
+ ite8709_write_register(dev, IT8512_REG_RCR,
+ IT8512_RCR_RXACT | CFG_DCR);
+ ite8709_write_register(dev, IT8512_REG_MSTCR,
+ CFG_FIFOTL | IT8512_MSTCR_FIFOCLR);
+ ite8709_write_register(dev, IT8512_REG_RCR,
+ IT8512_RCR_RXEN | IT8512_RCR_RXACT | CFG_DCR);
+ if (!dev->force_rearm)
+ dev->rearmed = 1;
+ dev->force_rearm = 0;
+ }
+
+ spin_lock_irqsave(&dev->hardware_lock, flags);
+ dev->device_busy = 0;
+ spin_unlock_irqrestore(&dev->hardware_lock, flags);
+}
+
+static int ite8709_cleanup(struct ite8709_device *dev, int stage, int errno,
+ char *msg)
+{
+ if (msg != NULL)
+ printk(KERN_ERR LIRC_DRIVER_NAME ": %s\n", msg);
+
+ switch (stage) {
+ case 6:
+ if (dev->use_count > 0)
+ ite8709_drop_hardware(dev);
+ case 5:
+ free_irq(dev->irq, dev);
+ case 4:
+ release_region(dev->io, 2);
+ case 3:
+ lirc_unregister_driver(dev->driver.minor);
+ case 2:
+ lirc_buffer_free(dev->driver.rbuf);
+ kfree(dev->driver.rbuf);
+ case 1:
+ kfree(dev);
+ case 0:
+ ;
+ }
+
+ return errno;
+}
+
+static int __devinit ite8709_pnp_probe(struct pnp_dev *dev,
+ const struct pnp_device_id *dev_id)
+{
+ struct lirc_driver *driver;
+ struct ite8709_device *ite8709_dev;
+ int ret;
+
+ /* Check resources validity */
+ if (!pnp_irq_valid(dev, 0))
+ return ite8709_cleanup(NULL, 0, -ENODEV, "invalid IRQ");
+ if (!pnp_port_valid(dev, 2))
+ return ite8709_cleanup(NULL, 0, -ENODEV, "invalid IO port");
+
+ /* Allocate memory for device struct */
+ ite8709_dev = kzalloc(sizeof(struct ite8709_device), GFP_KERNEL);
+ if (ite8709_dev == NULL)
+ return ite8709_cleanup(NULL, 0, -ENOMEM, "kzalloc failed");
+ pnp_set_drvdata(dev, ite8709_dev);
+
+ /* Initialize device struct */
+ ite8709_dev->use_count = 0;
+ ite8709_dev->irq = pnp_irq(dev, 0);
+ ite8709_dev->io = pnp_port_start(dev, 2);
+ ite8709_dev->hardware_lock =
+ __SPIN_LOCK_UNLOCKED(ite8709_dev->hardware_lock);
+ ite8709_dev->acc_pulse = 0;
+ ite8709_dev->acc_space = 0;
+ ite8709_dev->lastbit = 0;
+ do_gettimeofday(&ite8709_dev->last_tv);
+ tasklet_init(&ite8709_dev->tasklet, ite8709_rearm_irq,
+ (long) ite8709_dev);
+ ite8709_dev->force_rearm = 0;
+ ite8709_dev->rearmed = 0;
+ ite8709_dev->device_busy = 0;
+
+ /* Initialize driver struct */
+ driver = &ite8709_dev->driver;
+ strcpy(driver->name, LIRC_DRIVER_NAME);
+ driver->minor = -1;
+ driver->code_length = sizeof(int) * 8;
+ driver->sample_rate = 0;
+ driver->features = LIRC_CAN_REC_MODE2;
+ driver->data = ite8709_dev;
+ driver->add_to_buf = NULL;
+ driver->set_use_inc = ite8709_set_use_inc;
+ driver->set_use_dec = ite8709_set_use_dec;
+ driver->dev = &dev->dev;
+ driver->owner = THIS_MODULE;
+
+ /* Initialize LIRC buffer */
+ driver->rbuf = kmalloc(sizeof(struct lirc_buffer), GFP_KERNEL);
+ if (!driver->rbuf)
+ return ite8709_cleanup(ite8709_dev, 1, -ENOMEM,
+ "can't allocate lirc_buffer");
+ if (lirc_buffer_init(driver->rbuf, BUF_CHUNK_SIZE, BUF_SIZE))
+ return ite8709_cleanup(ite8709_dev, 1, -ENOMEM,
+ "lirc_buffer_init() failed");
+
+ /* Register LIRC driver */
+ ret = lirc_register_driver(driver);
+ if (ret < 0)
+ return ite8709_cleanup(ite8709_dev, 2, ret,
+ "lirc_register_driver() failed");
+
+ /* Reserve I/O port access */
+ if (!request_region(ite8709_dev->io, 2, LIRC_DRIVER_NAME))
+ return ite8709_cleanup(ite8709_dev, 3, -EBUSY,
+ "i/o port already in use");
+
+ /* Reserve IRQ line */
+ ret = request_irq(ite8709_dev->irq, ite8709_interrupt, 0,
+ LIRC_DRIVER_NAME, ite8709_dev);
+ if (ret < 0)
+ return ite8709_cleanup(ite8709_dev, 4, ret,
+ "IRQ already in use");
+
+ /* Initialize hardware */
+ ite8709_drop_hardware(ite8709_dev); /* Shutdown hw until first use */
+
+ printk(KERN_INFO LIRC_DRIVER_NAME ": device found : irq=%d io=0x%x\n",
+ ite8709_dev->irq, ite8709_dev->io);
+
+ return 0;
+}
+
+static void __devexit ite8709_pnp_remove(struct pnp_dev *dev)
+{
+ struct ite8709_device *ite8709_dev;
+ ite8709_dev = pnp_get_drvdata(dev);
+
+ ite8709_cleanup(ite8709_dev, 6, 0, NULL);
+
+ printk(KERN_INFO LIRC_DRIVER_NAME ": device removed\n");
+}
+
+#ifdef CONFIG_PM
+static int ite8709_pnp_suspend(struct pnp_dev *dev, pm_message_t state)
+{
+ struct ite8709_device *ite8709_dev;
+ ite8709_dev = pnp_get_drvdata(dev);
+
+ if (ite8709_dev->use_count > 0)
+ ite8709_drop_hardware(ite8709_dev);
+
+ return 0;
+}
+
+static int ite8709_pnp_resume(struct pnp_dev *dev)
+{
+ struct ite8709_device *ite8709_dev;
+ ite8709_dev = pnp_get_drvdata(dev);
+
+ if (ite8709_dev->use_count > 0)
+ ite8709_init_hardware(ite8709_dev);
+
+ return 0;
+}
+#else
+#define ite8709_pnp_suspend NULL
+#define ite8709_pnp_resume NULL
+#endif
+
+static const struct pnp_device_id pnp_dev_table[] = {
+ {"ITE8709", 0},
+ {}
+};
+
+MODULE_DEVICE_TABLE(pnp, pnp_dev_table);
+
+static struct pnp_driver ite8709_pnp_driver = {
+ .name = LIRC_DRIVER_NAME,
+ .probe = ite8709_pnp_probe,
+ .remove = __devexit_p(ite8709_pnp_remove),
+ .suspend = ite8709_pnp_suspend,
+ .resume = ite8709_pnp_resume,
+ .id_table = pnp_dev_table,
+};
+
+static int __init ite8709_init_module(void)
+{
+ return pnp_register_driver(&ite8709_pnp_driver);
+}
+module_init(ite8709_init_module);
+
+static void __exit ite8709_cleanup_module(void)
+{
+ pnp_unregister_driver(&ite8709_pnp_driver);
+}
+module_exit(ite8709_cleanup_module);
+
+MODULE_DESCRIPTION("LIRC driver for ITE8709 CIR port");
+MODULE_AUTHOR("Grégory Lardière");
+MODULE_LICENSE("GPL");
+
+module_param(debug, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug, "Enable debugging messages");
diff --git a/drivers/staging/lirc/lirc_parallel.c b/drivers/staging/lirc/lirc_parallel.c
new file mode 100644
index 00000000000..a1ebd071640
--- /dev/null
+++ b/drivers/staging/lirc/lirc_parallel.c
@@ -0,0 +1,705 @@
+/*
+ * lirc_parallel.c
+ *
+ * lirc_parallel - device driver for infra-red signal receiving and
+ * transmitting unit built by the author
+ *
+ * Copyright (C) 1998 Christoph Bartelmus <lirc@bartelmus.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
+ *
+ */
+
+/*** Includes ***/
+
+#ifdef CONFIG_SMP
+#error "--- Sorry, this driver is not SMP safe. ---"
+#endif
+
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/signal.h>
+#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <linux/ioport.h>
+#include <linux/time.h>
+#include <linux/mm.h>
+#include <linux/delay.h>
+
+#include <linux/io.h>
+#include <linux/signal.h>
+#include <linux/irq.h>
+#include <linux/uaccess.h>
+#include <asm/div64.h>
+
+#include <linux/poll.h>
+#include <linux/parport.h>
+
+#include <media/lirc.h>
+#include <media/lirc_dev.h>
+
+#include "lirc_parallel.h"
+
+#define LIRC_DRIVER_NAME "lirc_parallel"
+
+#ifndef LIRC_IRQ
+#define LIRC_IRQ 7
+#endif
+#ifndef LIRC_PORT
+#define LIRC_PORT 0x378
+#endif
+#ifndef LIRC_TIMER
+#define LIRC_TIMER 65536
+#endif
+
+/*** Global Variables ***/
+
+static int debug;
+static int check_pselecd;
+
+unsigned int irq = LIRC_IRQ;
+unsigned int io = LIRC_PORT;
+#ifdef LIRC_TIMER
+unsigned int timer;
+unsigned int default_timer = LIRC_TIMER;
+#endif
+
+#define RBUF_SIZE (256) /* this must be a power of 2 larger than 1 */
+
+static int rbuf[RBUF_SIZE];
+
+DECLARE_WAIT_QUEUE_HEAD(lirc_wait);
+
+unsigned int rptr;
+unsigned int wptr;
+unsigned int lost_irqs;
+int is_open;
+
+struct parport *pport;
+struct pardevice *ppdevice;
+int is_claimed;
+
+unsigned int tx_mask = 1;
+
+/*** Internal Functions ***/
+
+static unsigned int in(int offset)
+{
+ switch (offset) {
+ case LIRC_LP_BASE:
+ return parport_read_data(pport);
+ case LIRC_LP_STATUS:
+ return parport_read_status(pport);
+ case LIRC_LP_CONTROL:
+ return parport_read_control(pport);
+ }
+ return 0; /* make compiler happy */
+}
+
+static void out(int offset, int value)
+{
+ switch (offset) {
+ case LIRC_LP_BASE:
+ parport_write_data(pport, value);
+ break;
+ case LIRC_LP_CONTROL:
+ parport_write_control(pport, value);
+ break;
+ case LIRC_LP_STATUS:
+ printk(KERN_INFO "%s: attempt to write to status register\n",
+ LIRC_DRIVER_NAME);
+ break;
+ }
+}
+
+static unsigned int lirc_get_timer(void)
+{
+ return in(LIRC_PORT_TIMER) & LIRC_PORT_TIMER_BIT;
+}
+
+static unsigned int lirc_get_signal(void)
+{
+ return in(LIRC_PORT_SIGNAL) & LIRC_PORT_SIGNAL_BIT;
+}
+
+static void lirc_on(void)
+{
+ out(LIRC_PORT_DATA, tx_mask);
+}
+
+static void lirc_off(void)
+{
+ out(LIRC_PORT_DATA, 0);
+}
+
+static unsigned int init_lirc_timer(void)
+{
+ struct timeval tv, now;
+ unsigned int level, newlevel, timeelapsed, newtimer;
+ int count = 0;
+
+ do_gettimeofday(&tv);
+ tv.tv_sec++; /* wait max. 1 sec. */
+ level = lirc_get_timer();
+ do {
+ newlevel = lirc_get_timer();
+ if (level == 0 && newlevel != 0)
+ count++;
+ level = newlevel;
+ do_gettimeofday(&now);
+ } while (count < 1000 && (now.tv_sec < tv.tv_sec
+ || (now.tv_sec == tv.tv_sec
+ && now.tv_usec < tv.tv_usec)));
+
+ timeelapsed = ((now.tv_sec + 1 - tv.tv_sec)*1000000
+ + (now.tv_usec - tv.tv_usec));
+ if (count >= 1000 && timeelapsed > 0) {
+ if (default_timer == 0) {
+ /* autodetect timer */
+ newtimer = (1000000*count)/timeelapsed;
+ printk(KERN_INFO "%s: %u Hz timer detected\n",
+ LIRC_DRIVER_NAME, newtimer);
+ return newtimer;
+ } else {
+ newtimer = (1000000*count)/timeelapsed;
+ if (abs(newtimer - default_timer) > default_timer/10) {
+ /* bad timer */
+ printk(KERN_NOTICE "%s: bad timer: %u Hz\n",
+ LIRC_DRIVER_NAME, newtimer);
+ printk(KERN_NOTICE "%s: using default timer: "
+ "%u Hz\n",
+ LIRC_DRIVER_NAME, default_timer);
+ return default_timer;
+ } else {
+ printk(KERN_INFO "%s: %u Hz timer detected\n",
+ LIRC_DRIVER_NAME, newtimer);
+ return newtimer; /* use detected value */
+ }
+ }
+ } else {
+ printk(KERN_NOTICE "%s: no timer detected\n", LIRC_DRIVER_NAME);
+ return 0;
+ }
+}
+
+static int lirc_claim(void)
+{
+ if (parport_claim(ppdevice) != 0) {
+ printk(KERN_WARNING "%s: could not claim port\n",
+ LIRC_DRIVER_NAME);
+ printk(KERN_WARNING "%s: waiting for port becoming available"
+ "\n", LIRC_DRIVER_NAME);
+ if (parport_claim_or_block(ppdevice) < 0) {
+ printk(KERN_NOTICE "%s: could not claim port, giving"
+ " up\n", LIRC_DRIVER_NAME);
+ return 0;
+ }
+ }
+ out(LIRC_LP_CONTROL, LP_PSELECP|LP_PINITP);
+ is_claimed = 1;
+ return 1;
+}
+
+/*** interrupt handler ***/
+
+static void rbuf_write(int signal)
+{
+ unsigned int nwptr;
+
+ nwptr = (wptr + 1) & (RBUF_SIZE - 1);
+ if (nwptr == rptr) {
+ /* no new signals will be accepted */
+ lost_irqs++;
+ printk(KERN_NOTICE "%s: buffer overrun\n", LIRC_DRIVER_NAME);
+ return;
+ }
+ rbuf[wptr] = signal;
+ wptr = nwptr;
+}
+
+static void irq_handler(void *blah)
+{
+ struct timeval tv;
+ static struct timeval lasttv;
+ static int init;
+ long signal;
+ int data;
+ unsigned int level, newlevel;
+ unsigned int timeout;
+
+ if (!module_refcount(THIS_MODULE))
+ return;
+
+ if (!is_claimed)
+ return;
+
+#if 0
+ /* disable interrupt */
+ disable_irq(irq);
+ out(LIRC_PORT_IRQ, in(LIRC_PORT_IRQ) & (~LP_PINTEN));
+#endif
+ if (check_pselecd && (in(1) & LP_PSELECD))
+ return;
+
+#ifdef LIRC_TIMER
+ if (init) {
+ do_gettimeofday(&tv);
+
+ signal = tv.tv_sec - lasttv.tv_sec;
+ if (signal > 15)
+ /* really long time */
+ data = PULSE_MASK;
+ else
+ data = (int) (signal*1000000 +
+ tv.tv_usec - lasttv.tv_usec +
+ LIRC_SFH506_DELAY);
+
+ rbuf_write(data); /* space */
+ } else {
+ if (timer == 0) {
+ /*
+ * wake up; we'll lose this signal, but it will be
+ * garbage if the device is turned on anyway
+ */
+ timer = init_lirc_timer();
+ /* enable_irq(irq); */
+ return;
+ }
+ init = 1;
+ }
+
+ timeout = timer/10; /* timeout after 1/10 sec. */
+ signal = 1;
+ level = lirc_get_timer();
+ do {
+ newlevel = lirc_get_timer();
+ if (level == 0 && newlevel != 0)
+ signal++;
+ level = newlevel;
+
+ /* giving up */
+ if (signal > timeout
+ || (check_pselecd && (in(1) & LP_PSELECD))) {
+ signal = 0;
+ printk(KERN_NOTICE "%s: timeout\n", LIRC_DRIVER_NAME);
+ break;
+ }
+ } while (lirc_get_signal());
+
+ if (signal != 0) {
+ /* ajust value to usecs */
+ unsigned long long helper;
+
+ helper = ((unsigned long long) signal)*1000000;
+ do_div(helper, timer);
+ signal = (long) helper;
+
+ if (signal > LIRC_SFH506_DELAY)
+ data = signal - LIRC_SFH506_DELAY;
+ else
+ data = 1;
+ rbuf_write(PULSE_BIT|data); /* pulse */
+ }
+ do_gettimeofday(&lasttv);
+#else
+ /* add your code here */
+#endif
+
+ wake_up_interruptible(&lirc_wait);
+
+ /* enable interrupt */
+ /*
+ enable_irq(irq);
+ out(LIRC_PORT_IRQ, in(LIRC_PORT_IRQ)|LP_PINTEN);
+ */
+}
+
+/*** file operations ***/
+
+static loff_t lirc_lseek(struct file *filep, loff_t offset, int orig)
+{
+ return -ESPIPE;
+}
+
+static ssize_t lirc_read(struct file *filep, char *buf, size_t n, loff_t *ppos)
+{
+ int result = 0;
+ int count = 0;
+ DECLARE_WAITQUEUE(wait, current);
+
+ if (n % sizeof(int))
+ return -EINVAL;
+
+ add_wait_queue(&lirc_wait, &wait);
+ set_current_state(TASK_INTERRUPTIBLE);
+ while (count < n) {
+ if (rptr != wptr) {
+ if (copy_to_user(buf+count, (char *) &rbuf[rptr],
+ sizeof(int))) {
+ result = -EFAULT;
+ break;
+ }
+ rptr = (rptr + 1) & (RBUF_SIZE - 1);
+ count += sizeof(int);
+ } else {
+ if (filep->f_flags & O_NONBLOCK) {
+ result = -EAGAIN;
+ break;
+ }
+ if (signal_pending(current)) {
+ result = -ERESTARTSYS;
+ break;
+ }
+ schedule();
+ set_current_state(TASK_INTERRUPTIBLE);
+ }
+ }
+ remove_wait_queue(&lirc_wait, &wait);
+ set_current_state(TASK_RUNNING);
+ return count ? count : result;
+}
+
+static ssize_t lirc_write(struct file *filep, const char *buf, size_t n,
+ loff_t *ppos)
+{
+ int count;
+ unsigned int i;
+ unsigned int level, newlevel;
+ unsigned long flags;
+ int counttimer;
+ int *wbuf;
+
+ if (!is_claimed)
+ return -EBUSY;
+
+ count = n / sizeof(int);
+
+ if (n % sizeof(int) || count % 2 == 0)
+ return -EINVAL;
+
+ wbuf = memdup_user(buf, n);
+ if (IS_ERR(wbuf))
+ return PTR_ERR(wbuf);
+
+#ifdef LIRC_TIMER
+ if (timer == 0) {
+ /* try again if device is ready */
+ timer = init_lirc_timer();
+ if (timer == 0)
+ return -EIO;
+ }
+
+ /* adjust values from usecs */
+ for (i = 0; i < count; i++) {
+ unsigned long long helper;
+
+ helper = ((unsigned long long) wbuf[i])*timer;
+ do_div(helper, 1000000);
+ wbuf[i] = (int) helper;
+ }
+
+ local_irq_save(flags);
+ i = 0;
+ while (i < count) {
+ level = lirc_get_timer();
+ counttimer = 0;
+ lirc_on();
+ do {
+ newlevel = lirc_get_timer();
+ if (level == 0 && newlevel != 0)
+ counttimer++;
+ level = newlevel;
+ if (check_pselecd && (in(1) & LP_PSELECD)) {
+ lirc_off();
+ local_irq_restore(flags);
+ return -EIO;
+ }
+ } while (counttimer < wbuf[i]);
+ i++;
+
+ lirc_off();
+ if (i == count)
+ break;
+ counttimer = 0;
+ do {
+ newlevel = lirc_get_timer();
+ if (level == 0 && newlevel != 0)
+ counttimer++;
+ level = newlevel;
+ if (check_pselecd && (in(1) & LP_PSELECD)) {
+ local_irq_restore(flags);
+ return -EIO;
+ }
+ } while (counttimer < wbuf[i]);
+ i++;
+ }
+ local_irq_restore(flags);
+#else
+ /* place code that handles write without external timer here */
+#endif
+ return n;
+}
+
+static unsigned int lirc_poll(struct file *file, poll_table *wait)
+{
+ poll_wait(file, &lirc_wait, wait);
+ if (rptr != wptr)
+ return POLLIN | POLLRDNORM;
+ return 0;
+}
+
+static long lirc_ioctl(struct file *filep, unsigned int cmd, unsigned long arg)
+{
+ int result;
+ unsigned long features = LIRC_CAN_SET_TRANSMITTER_MASK |
+ LIRC_CAN_SEND_PULSE | LIRC_CAN_REC_MODE2;
+ unsigned long mode;
+ unsigned int ivalue;
+
+ switch (cmd) {
+ case LIRC_GET_FEATURES:
+ result = put_user(features, (unsigned long *) arg);
+ if (result)
+ return result;
+ break;
+ case LIRC_GET_SEND_MODE:
+ result = put_user(LIRC_MODE_PULSE, (unsigned long *) arg);
+ if (result)
+ return result;
+ break;
+ case LIRC_GET_REC_MODE:
+ result = put_user(LIRC_MODE_MODE2, (unsigned long *) arg);
+ if (result)
+ return result;
+ break;
+ case LIRC_SET_SEND_MODE:
+ result = get_user(mode, (unsigned long *) arg);
+ if (result)
+ return result;
+ if (mode != LIRC_MODE_PULSE)
+ return -EINVAL;
+ break;
+ case LIRC_SET_REC_MODE:
+ result = get_user(mode, (unsigned long *) arg);
+ if (result)
+ return result;
+ if (mode != LIRC_MODE_MODE2)
+ return -ENOSYS;
+ break;
+ case LIRC_SET_TRANSMITTER_MASK:
+ result = get_user(ivalue, (unsigned int *) arg);
+ if (result)
+ return result;
+ if ((ivalue & LIRC_PARALLEL_TRANSMITTER_MASK) != ivalue)
+ return LIRC_PARALLEL_MAX_TRANSMITTERS;
+ tx_mask = ivalue;
+ break;
+ default:
+ return -ENOIOCTLCMD;
+ }
+ return 0;
+}
+
+static int lirc_open(struct inode *node, struct file *filep)
+{
+ if (module_refcount(THIS_MODULE) || !lirc_claim())
+ return -EBUSY;
+
+ parport_enable_irq(pport);
+
+ /* init read ptr */
+ rptr = 0;
+ wptr = 0;
+ lost_irqs = 0;
+
+ is_open = 1;
+ return 0;
+}
+
+static int lirc_close(struct inode *node, struct file *filep)
+{
+ if (is_claimed) {
+ is_claimed = 0;
+ parport_release(ppdevice);
+ }
+ is_open = 0;
+ return 0;
+}
+
+static const struct file_operations lirc_fops = {
+ .owner = THIS_MODULE,
+ .llseek = lirc_lseek,
+ .read = lirc_read,
+ .write = lirc_write,
+ .poll = lirc_poll,
+ .unlocked_ioctl = lirc_ioctl,
+ .open = lirc_open,
+ .release = lirc_close
+};
+
+static int set_use_inc(void *data)
+{
+ return 0;
+}
+
+static void set_use_dec(void *data)
+{
+}
+
+static struct lirc_driver driver = {
+ .name = LIRC_DRIVER_NAME,
+ .minor = -1,
+ .code_length = 1,
+ .sample_rate = 0,
+ .data = NULL,
+ .add_to_buf = NULL,
+ .set_use_inc = set_use_inc,
+ .set_use_dec = set_use_dec,
+ .fops = &lirc_fops,
+ .dev = NULL,
+ .owner = THIS_MODULE,
+};
+
+static int pf(void *handle);
+static void kf(void *handle);
+
+static struct timer_list poll_timer;
+static void poll_state(unsigned long ignored);
+
+static void poll_state(unsigned long ignored)
+{
+ printk(KERN_NOTICE "%s: time\n",
+ LIRC_DRIVER_NAME);
+ del_timer(&poll_timer);
+ if (is_claimed)
+ return;
+ kf(NULL);
+ if (!is_claimed) {
+ printk(KERN_NOTICE "%s: could not claim port, giving up\n",
+ LIRC_DRIVER_NAME);
+ init_timer(&poll_timer);
+ poll_timer.expires = jiffies + HZ;
+ poll_timer.data = (unsigned long)current;
+ poll_timer.function = poll_state;
+ add_timer(&poll_timer);
+ }
+}
+
+static int pf(void *handle)
+{
+ parport_disable_irq(pport);
+ is_claimed = 0;
+ return 0;
+}
+
+static void kf(void *handle)
+{
+ if (!is_open)
+ return;
+ if (!lirc_claim())
+ return;
+ parport_enable_irq(pport);
+ lirc_off();
+ /* this is a bit annoying when you actually print...*/
+ /*
+ printk(KERN_INFO "%s: reclaimed port\n", LIRC_DRIVER_NAME);
+ */
+}
+
+/*** module initialization and cleanup ***/
+
+static int __init lirc_parallel_init(void)
+{
+ pport = parport_find_base(io);
+ if (pport == NULL) {
+ printk(KERN_NOTICE "%s: no port at %x found\n",
+ LIRC_DRIVER_NAME, io);
+ return -ENXIO;
+ }
+ ppdevice = parport_register_device(pport, LIRC_DRIVER_NAME,
+ pf, kf, irq_handler, 0, NULL);
+ parport_put_port(pport);
+ if (ppdevice == NULL) {
+ printk(KERN_NOTICE "%s: parport_register_device() failed\n",
+ LIRC_DRIVER_NAME);
+ return -ENXIO;
+ }
+ if (parport_claim(ppdevice) != 0)
+ goto skip_init;
+ is_claimed = 1;
+ out(LIRC_LP_CONTROL, LP_PSELECP|LP_PINITP);
+
+#ifdef LIRC_TIMER
+ if (debug)
+ out(LIRC_PORT_DATA, tx_mask);
+
+ timer = init_lirc_timer();
+
+#if 0 /* continue even if device is offline */
+ if (timer == 0) {
+ is_claimed = 0;
+ parport_release(pport);
+ parport_unregister_device(ppdevice);
+ return -EIO;
+ }
+
+#endif
+ if (debug)
+ out(LIRC_PORT_DATA, 0);
+#endif
+
+ is_claimed = 0;
+ parport_release(ppdevice);
+ skip_init:
+ driver.minor = lirc_register_driver(&driver);
+ if (driver.minor < 0) {
+ printk(KERN_NOTICE "%s: register_chrdev() failed\n",
+ LIRC_DRIVER_NAME);
+ parport_unregister_device(ppdevice);
+ return -EIO;
+ }
+ printk(KERN_INFO "%s: installed using port 0x%04x irq %d\n",
+ LIRC_DRIVER_NAME, io, irq);
+ return 0;
+}
+
+static void __exit lirc_parallel_exit(void)
+{
+ parport_unregister_device(ppdevice);
+ lirc_unregister_driver(driver.minor);
+}
+
+module_init(lirc_parallel_init);
+module_exit(lirc_parallel_exit);
+
+MODULE_DESCRIPTION("Infrared receiver driver for parallel ports.");
+MODULE_AUTHOR("Christoph Bartelmus");
+MODULE_LICENSE("GPL");
+
+module_param(io, int, S_IRUGO);
+MODULE_PARM_DESC(io, "I/O address base (0x3bc, 0x378 or 0x278)");
+
+module_param(irq, int, S_IRUGO);
+MODULE_PARM_DESC(irq, "Interrupt (7 or 5)");
+
+module_param(tx_mask, int, S_IRUGO);
+MODULE_PARM_DESC(tx_maxk, "Transmitter mask (default: 0x01)");
+
+module_param(debug, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug, "Enable debugging messages");
+
+module_param(check_pselecd, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug, "Check for printer (default: 0)");
diff --git a/drivers/staging/lirc/lirc_parallel.h b/drivers/staging/lirc/lirc_parallel.h
new file mode 100644
index 00000000000..4bed6afe063
--- /dev/null
+++ b/drivers/staging/lirc/lirc_parallel.h
@@ -0,0 +1,26 @@
+/* lirc_parallel.h */
+
+#ifndef _LIRC_PARALLEL_H
+#define _LIRC_PARALLEL_H
+
+#include <linux/lp.h>
+
+#define LIRC_PORT_LEN 3
+
+#define LIRC_LP_BASE 0
+#define LIRC_LP_STATUS 1
+#define LIRC_LP_CONTROL 2
+
+#define LIRC_PORT_DATA LIRC_LP_BASE /* base */
+#define LIRC_PORT_TIMER LIRC_LP_STATUS /* status port */
+#define LIRC_PORT_TIMER_BIT LP_PBUSY /* busy signal */
+#define LIRC_PORT_SIGNAL LIRC_LP_STATUS /* status port */
+#define LIRC_PORT_SIGNAL_BIT LP_PACK /* ack signal */
+#define LIRC_PORT_IRQ LIRC_LP_CONTROL /* control port */
+
+#define LIRC_SFH506_DELAY 0 /* delay t_phl in usecs */
+
+#define LIRC_PARALLEL_MAX_TRANSMITTERS 8
+#define LIRC_PARALLEL_TRANSMITTER_MASK ((1<<LIRC_PARALLEL_MAX_TRANSMITTERS) - 1)
+
+#endif
diff --git a/drivers/staging/lirc/lirc_sasem.c b/drivers/staging/lirc/lirc_sasem.c
new file mode 100644
index 00000000000..73166c3f581
--- /dev/null
+++ b/drivers/staging/lirc/lirc_sasem.c
@@ -0,0 +1,933 @@
+/*
+ * lirc_sasem.c - USB remote support for LIRC
+ * Version 0.5
+ *
+ * Copyright (C) 2004-2005 Oliver Stabel <oliver.stabel@gmx.de>
+ * Tim Davies <tim@opensystems.net.au>
+ *
+ * This driver was derived from:
+ * Venky Raju <dev@venky.ws>
+ * "lirc_imon - "LIRC/VFD driver for Ahanix/Soundgraph IMON IR/VFD"
+ * Paul Miller <pmiller9@users.sourceforge.net>'s 2003-2004
+ * "lirc_atiusb - USB remote support for LIRC"
+ * Culver Consulting Services <henry@culcon.com>'s 2003
+ * "Sasem OnAir VFD/IR USB driver"
+ *
+ *
+ * NOTE - The LCDproc iMon driver should work with this module. More info at
+ * http://www.frogstorm.info/sasem
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * 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/errno.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+#include <linux/usb.h>
+
+#include <media/lirc.h>
+#include <media/lirc_dev.h>
+
+
+#define MOD_AUTHOR "Oliver Stabel <oliver.stabel@gmx.de>, " \
+ "Tim Davies <tim@opensystems.net.au>"
+#define MOD_DESC "USB Driver for Sasem Remote Controller V1.1"
+#define MOD_NAME "lirc_sasem"
+#define MOD_VERSION "0.5"
+
+#define VFD_MINOR_BASE 144 /* Same as LCD */
+#define DEVICE_NAME "lcd%d"
+
+#define BUF_CHUNK_SIZE 8
+#define BUF_SIZE 128
+
+#define IOCTL_LCD_CONTRAST 1
+
+/*** P R O T O T Y P E S ***/
+
+/* USB Callback prototypes */
+static int sasem_probe(struct usb_interface *interface,
+ const struct usb_device_id *id);
+static void sasem_disconnect(struct usb_interface *interface);
+static void usb_rx_callback(struct urb *urb);
+static void usb_tx_callback(struct urb *urb);
+
+/* VFD file_operations function prototypes */
+static int vfd_open(struct inode *inode, struct file *file);
+static long vfd_ioctl(struct file *file, unsigned cmd, unsigned long arg);
+static int vfd_close(struct inode *inode, struct file *file);
+static ssize_t vfd_write(struct file *file, const char *buf,
+ size_t n_bytes, loff_t *pos);
+
+/* LIRC driver function prototypes */
+static int ir_open(void *data);
+static void ir_close(void *data);
+
+/* Driver init/exit prototypes */
+static int __init sasem_init(void);
+static void __exit sasem_exit(void);
+
+/*** G L O B A L S ***/
+#define SASEM_DATA_BUF_SZ 32
+
+struct sasem_context {
+
+ struct usb_device *dev;
+ int vfd_isopen; /* VFD port has been opened */
+ unsigned int vfd_contrast; /* VFD contrast */
+ int ir_isopen; /* IR port has been opened */
+ int dev_present; /* USB device presence */
+ struct mutex ctx_lock; /* to lock this object */
+ wait_queue_head_t remove_ok; /* For unexpected USB disconnects */
+
+ struct lirc_driver *driver;
+ struct usb_endpoint_descriptor *rx_endpoint;
+ struct usb_endpoint_descriptor *tx_endpoint;
+ struct urb *rx_urb;
+ struct urb *tx_urb;
+ unsigned char usb_rx_buf[8];
+ unsigned char usb_tx_buf[8];
+
+ struct tx_t {
+ unsigned char data_buf[SASEM_DATA_BUF_SZ]; /* user data buffer */
+ struct completion finished; /* wait for write to finish */
+ atomic_t busy; /* write in progress */
+ int status; /* status of tx completion */
+ } tx;
+
+ /* for dealing with repeat codes (wish there was a toggle bit!) */
+ struct timeval presstime;
+ char lastcode[8];
+ int codesaved;
+};
+
+/* VFD file operations */
+static const struct file_operations vfd_fops = {
+ .owner = THIS_MODULE,
+ .open = &vfd_open,
+ .write = &vfd_write,
+ .unlocked_ioctl = &vfd_ioctl,
+ .release = &vfd_close,
+};
+
+/* USB Device ID for Sasem USB Control Board */
+static struct usb_device_id sasem_usb_id_table[] = {
+ /* Sasem USB Control Board */
+ { USB_DEVICE(0x11ba, 0x0101) },
+ /* Terminating entry */
+ {}
+};
+
+/* USB Device data */
+static struct usb_driver sasem_driver = {
+ .name = MOD_NAME,
+ .probe = sasem_probe,
+ .disconnect = sasem_disconnect,
+ .id_table = sasem_usb_id_table,
+};
+
+static struct usb_class_driver sasem_class = {
+ .name = DEVICE_NAME,
+ .fops = &vfd_fops,
+ .minor_base = VFD_MINOR_BASE,
+};
+
+/* to prevent races between open() and disconnect() */
+static DEFINE_MUTEX(disconnect_lock);
+
+static int debug;
+
+
+/*** M O D U L E C O D E ***/
+
+MODULE_AUTHOR(MOD_AUTHOR);
+MODULE_DESCRIPTION(MOD_DESC);
+MODULE_LICENSE("GPL");
+module_param(debug, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug, "Debug messages: 0=no, 1=yes (default: no)");
+
+static void delete_context(struct sasem_context *context)
+{
+ usb_free_urb(context->tx_urb); /* VFD */
+ usb_free_urb(context->rx_urb); /* IR */
+ lirc_buffer_free(context->driver->rbuf);
+ kfree(context->driver->rbuf);
+ kfree(context->driver);
+ kfree(context);
+
+ if (debug)
+ printk(KERN_INFO "%s: context deleted\n", __func__);
+}
+
+static void deregister_from_lirc(struct sasem_context *context)
+{
+ int retval;
+ int minor = context->driver->minor;
+
+ retval = lirc_unregister_driver(minor);
+ if (retval)
+ err("%s: unable to deregister from lirc (%d)",
+ __func__, retval);
+ else
+ printk(KERN_INFO "Deregistered Sasem driver (minor:%d)\n",
+ minor);
+
+}
+
+/**
+ * Called when the VFD device (e.g. /dev/usb/lcd)
+ * is opened by the application.
+ */
+static int vfd_open(struct inode *inode, struct file *file)
+{
+ struct usb_interface *interface;
+ struct sasem_context *context = NULL;
+ int subminor;
+ int retval = 0;
+
+ /* prevent races with disconnect */
+ mutex_lock(&disconnect_lock);
+
+ subminor = iminor(inode);
+ interface = usb_find_interface(&sasem_driver, subminor);
+ if (!interface) {
+ err("%s: could not find interface for minor %d",
+ __func__, subminor);
+ retval = -ENODEV;
+ goto exit;
+ }
+ context = usb_get_intfdata(interface);
+
+ if (!context) {
+ err("%s: no context found for minor %d",
+ __func__, subminor);
+ retval = -ENODEV;
+ goto exit;
+ }
+
+ mutex_lock(&context->ctx_lock);
+
+ if (context->vfd_isopen) {
+ err("%s: VFD port is already open", __func__);
+ retval = -EBUSY;
+ } else {
+ context->vfd_isopen = 1;
+ file->private_data = context;
+ printk(KERN_INFO "VFD port opened\n");
+ }
+
+ mutex_unlock(&context->ctx_lock);
+
+exit:
+ mutex_unlock(&disconnect_lock);
+ return retval;
+}
+
+/**
+ * Called when the VFD device (e.g. /dev/usb/lcd)
+ * is closed by the application.
+ */
+static long vfd_ioctl(struct file *file, unsigned cmd, unsigned long arg)
+{
+ struct sasem_context *context = NULL;
+
+ context = (struct sasem_context *) file->private_data;
+
+ if (!context) {
+ err("%s: no context for device", __func__);
+ return -ENODEV;
+ }
+
+ mutex_lock(&context->ctx_lock);
+
+ switch (cmd) {
+ case IOCTL_LCD_CONTRAST:
+ if (arg > 1000)
+ arg = 1000;
+ context->vfd_contrast = (unsigned int)arg;
+ break;
+ default:
+ printk(KERN_INFO "Unknown IOCTL command\n");
+ mutex_unlock(&context->ctx_lock);
+ return -ENOIOCTLCMD; /* not supported */
+ }
+
+ mutex_unlock(&context->ctx_lock);
+ return 0;
+}
+
+/**
+ * Called when the VFD device (e.g. /dev/usb/lcd)
+ * is closed by the application.
+ */
+static int vfd_close(struct inode *inode, struct file *file)
+{
+ struct sasem_context *context = NULL;
+ int retval = 0;
+
+ context = (struct sasem_context *) file->private_data;
+
+ if (!context) {
+ err("%s: no context for device", __func__);
+ return -ENODEV;
+ }
+
+ mutex_lock(&context->ctx_lock);
+
+ if (!context->vfd_isopen) {
+ err("%s: VFD is not open", __func__);
+ retval = -EIO;
+ } else {
+ context->vfd_isopen = 0;
+ printk(KERN_INFO "VFD port closed\n");
+ if (!context->dev_present && !context->ir_isopen) {
+
+ /* Device disconnected before close and IR port is
+ * not open. If IR port is open, context will be
+ * deleted by ir_close. */
+ mutex_unlock(&context->ctx_lock);
+ delete_context(context);
+ return retval;
+ }
+ }
+
+ mutex_unlock(&context->ctx_lock);
+ return retval;
+}
+
+/**
+ * Sends a packet to the VFD.
+ */
+static int send_packet(struct sasem_context *context)
+{
+ unsigned int pipe;
+ int interval = 0;
+ int retval = 0;
+
+ pipe = usb_sndintpipe(context->dev,
+ context->tx_endpoint->bEndpointAddress);
+ interval = context->tx_endpoint->bInterval;
+
+ usb_fill_int_urb(context->tx_urb, context->dev, pipe,
+ context->usb_tx_buf, sizeof(context->usb_tx_buf),
+ usb_tx_callback, context, interval);
+
+ context->tx_urb->actual_length = 0;
+
+ init_completion(&context->tx.finished);
+ atomic_set(&(context->tx.busy), 1);
+
+ retval = usb_submit_urb(context->tx_urb, GFP_KERNEL);
+ if (retval) {
+ atomic_set(&(context->tx.busy), 0);
+ err("%s: error submitting urb (%d)", __func__, retval);
+ } else {
+ /* Wait for transmission to complete (or abort) */
+ mutex_unlock(&context->ctx_lock);
+ wait_for_completion(&context->tx.finished);
+ mutex_lock(&context->ctx_lock);
+
+ retval = context->tx.status;
+ if (retval)
+ err("%s: packet tx failed (%d)", __func__, retval);
+ }
+
+ return retval;
+}
+
+/**
+ * Writes data to the VFD. The Sasem VFD is 2x16 characters
+ * and requires data in 9 consecutive USB interrupt packets,
+ * each packet carrying 8 bytes.
+ */
+static ssize_t vfd_write(struct file *file, const char *buf,
+ size_t n_bytes, loff_t *pos)
+{
+ int i;
+ int retval = 0;
+ struct sasem_context *context;
+ int *data_buf;
+
+ context = (struct sasem_context *) file->private_data;
+ if (!context) {
+ err("%s: no context for device", __func__);
+ return -ENODEV;
+ }
+
+ mutex_lock(&context->ctx_lock);
+
+ if (!context->dev_present) {
+ err("%s: no Sasem device present", __func__);
+ retval = -ENODEV;
+ goto exit;
+ }
+
+ if (n_bytes <= 0 || n_bytes > SASEM_DATA_BUF_SZ) {
+ err("%s: invalid payload size", __func__);
+ retval = -EINVAL;
+ goto exit;
+ }
+
+ data_buf = memdup_user(buf, n_bytes);
+ if (PTR_ERR(data_buf))
+ return PTR_ERR(data_buf);
+
+ memcpy(context->tx.data_buf, data_buf, n_bytes);
+
+ /* Pad with spaces */
+ for (i = n_bytes; i < SASEM_DATA_BUF_SZ; ++i)
+ context->tx.data_buf[i] = ' ';
+
+ /* Nine 8 byte packets to be sent */
+ /* NOTE: "\x07\x01\0\0\0\0\0\0" or "\x0c\0\0\0\0\0\0\0"
+ * will clear the VFD */
+ for (i = 0; i < 9; i++) {
+ switch (i) {
+ case 0:
+ memcpy(context->usb_tx_buf, "\x07\0\0\0\0\0\0\0", 8);
+ context->usb_tx_buf[1] = (context->vfd_contrast) ?
+ (0x2B - (context->vfd_contrast - 1) / 250)
+ : 0x2B;
+ break;
+ case 1:
+ memcpy(context->usb_tx_buf, "\x09\x01\0\0\0\0\0\0", 8);
+ break;
+ case 2:
+ memcpy(context->usb_tx_buf, "\x0b\x01\0\0\0\0\0\0", 8);
+ break;
+ case 3:
+ memcpy(context->usb_tx_buf, context->tx.data_buf, 8);
+ break;
+ case 4:
+ memcpy(context->usb_tx_buf,
+ context->tx.data_buf + 8, 8);
+ break;
+ case 5:
+ memcpy(context->usb_tx_buf, "\x09\x01\0\0\0\0\0\0", 8);
+ break;
+ case 6:
+ memcpy(context->usb_tx_buf, "\x0b\x02\0\0\0\0\0\0", 8);
+ break;
+ case 7:
+ memcpy(context->usb_tx_buf,
+ context->tx.data_buf + 16, 8);
+ break;
+ case 8:
+ memcpy(context->usb_tx_buf,
+ context->tx.data_buf + 24, 8);
+ break;
+ }
+ retval = send_packet(context);
+ if (retval) {
+
+ err("%s: send packet failed for packet #%d",
+ __func__, i);
+ goto exit;
+ }
+ }
+exit:
+
+ mutex_unlock(&context->ctx_lock);
+
+ return (!retval) ? n_bytes : retval;
+}
+
+/**
+ * Callback function for USB core API: transmit data
+ */
+static void usb_tx_callback(struct urb *urb)
+{
+ struct sasem_context *context;
+
+ if (!urb)
+ return;
+ context = (struct sasem_context *) urb->context;
+ if (!context)
+ return;
+
+ context->tx.status = urb->status;
+
+ /* notify waiters that write has finished */
+ atomic_set(&context->tx.busy, 0);
+ complete(&context->tx.finished);
+
+ return;
+}
+
+/**
+ * Called by lirc_dev when the application opens /dev/lirc
+ */
+static int ir_open(void *data)
+{
+ int retval = 0;
+ struct sasem_context *context;
+
+ /* prevent races with disconnect */
+ mutex_lock(&disconnect_lock);
+
+ context = (struct sasem_context *) data;
+
+ mutex_lock(&context->ctx_lock);
+
+ if (context->ir_isopen) {
+ err("%s: IR port is already open", __func__);
+ retval = -EBUSY;
+ goto exit;
+ }
+
+ usb_fill_int_urb(context->rx_urb, context->dev,
+ usb_rcvintpipe(context->dev,
+ context->rx_endpoint->bEndpointAddress),
+ context->usb_rx_buf, sizeof(context->usb_rx_buf),
+ usb_rx_callback, context, context->rx_endpoint->bInterval);
+
+ retval = usb_submit_urb(context->rx_urb, GFP_KERNEL);
+
+ if (retval)
+ err("%s: usb_submit_urb failed for ir_open (%d)",
+ __func__, retval);
+ else {
+ context->ir_isopen = 1;
+ printk(KERN_INFO "IR port opened\n");
+ }
+
+exit:
+ mutex_unlock(&context->ctx_lock);
+
+ mutex_unlock(&disconnect_lock);
+ return 0;
+}
+
+/**
+ * Called by lirc_dev when the application closes /dev/lirc
+ */
+static void ir_close(void *data)
+{
+ struct sasem_context *context;
+
+ context = (struct sasem_context *)data;
+ if (!context) {
+ err("%s: no context for device", __func__);
+ return;
+ }
+
+ mutex_lock(&context->ctx_lock);
+
+ usb_kill_urb(context->rx_urb);
+ context->ir_isopen = 0;
+ printk(KERN_INFO "IR port closed\n");
+
+ if (!context->dev_present) {
+
+ /*
+ * Device disconnected while IR port was
+ * still open. Driver was not deregistered
+ * at disconnect time, so do it now.
+ */
+ deregister_from_lirc(context);
+
+ if (!context->vfd_isopen) {
+
+ mutex_unlock(&context->ctx_lock);
+ delete_context(context);
+ return;
+ }
+ /* If VFD port is open, context will be deleted by vfd_close */
+ }
+
+ mutex_unlock(&context->ctx_lock);
+ return;
+}
+
+/**
+ * Process the incoming packet
+ */
+static void incoming_packet(struct sasem_context *context,
+ struct urb *urb)
+{
+ int len = urb->actual_length;
+ unsigned char *buf = urb->transfer_buffer;
+ long ms;
+ struct timeval tv;
+
+ if (len != 8) {
+ printk(KERN_WARNING "%s: invalid incoming packet size (%d)\n",
+ __func__, len);
+ return;
+ }
+
+#ifdef DEBUG
+ int i;
+ for (i = 0; i < 8; ++i)
+ printk(KERN_INFO "%02x ", buf[i]);
+ printk(KERN_INFO "\n");
+#endif
+
+ /*
+ * Lirc could deal with the repeat code, but we really need to block it
+ * if it arrives too late. Otherwise we could repeat the wrong code.
+ */
+
+ /* get the time since the last button press */
+ do_gettimeofday(&tv);
+ ms = (tv.tv_sec - context->presstime.tv_sec) * 1000 +
+ (tv.tv_usec - context->presstime.tv_usec) / 1000;
+
+ if (memcmp(buf, "\x08\0\0\0\0\0\0\0", 8) == 0) {
+ /*
+ * the repeat code is being sent, so we copy
+ * the old code to LIRC
+ */
+
+ /*
+ * NOTE: Only if the last code was less than 250ms ago
+ * - no one should be able to push another (undetected) button
+ * in that time and then get a false repeat of the previous
+ * press but it is long enough for a genuine repeat
+ */
+ if ((ms < 250) && (context->codesaved != 0)) {
+ memcpy(buf, &context->lastcode, 8);
+ context->presstime.tv_sec = tv.tv_sec;
+ context->presstime.tv_usec = tv.tv_usec;
+ }
+ } else {
+ /* save the current valid code for repeats */
+ memcpy(&context->lastcode, buf, 8);
+ /*
+ * set flag to signal a valid code was save;
+ * just for safety reasons
+ */
+ context->codesaved = 1;
+ context->presstime.tv_sec = tv.tv_sec;
+ context->presstime.tv_usec = tv.tv_usec;
+ }
+
+ lirc_buffer_write(context->driver->rbuf, buf);
+ wake_up(&context->driver->rbuf->wait_poll);
+}
+
+/**
+ * Callback function for USB core API: receive data
+ */
+static void usb_rx_callback(struct urb *urb)
+{
+ struct sasem_context *context;
+
+ if (!urb)
+ return;
+ context = (struct sasem_context *) urb->context;
+ if (!context)
+ return;
+
+ switch (urb->status) {
+
+ case -ENOENT: /* usbcore unlink successful! */
+ return;
+
+ case 0:
+ if (context->ir_isopen)
+ incoming_packet(context, urb);
+ break;
+
+ default:
+ printk(KERN_WARNING "%s: status (%d): ignored",
+ __func__, urb->status);
+ break;
+ }
+
+ usb_submit_urb(context->rx_urb, GFP_ATOMIC);
+ return;
+}
+
+
+
+/**
+ * Callback function for USB core API: Probe
+ */
+static int sasem_probe(struct usb_interface *interface,
+ const struct usb_device_id *id)
+{
+ struct usb_device *dev = NULL;
+ struct usb_host_interface *iface_desc = NULL;
+ struct usb_endpoint_descriptor *rx_endpoint = NULL;
+ struct usb_endpoint_descriptor *tx_endpoint = NULL;
+ struct urb *rx_urb = NULL;
+ struct urb *tx_urb = NULL;
+ struct lirc_driver *driver = NULL;
+ struct lirc_buffer *rbuf = NULL;
+ int lirc_minor = 0;
+ int num_endpoints;
+ int retval = 0;
+ int vfd_ep_found;
+ int ir_ep_found;
+ int alloc_status;
+ struct sasem_context *context = NULL;
+ int i;
+
+ printk(KERN_INFO "%s: found Sasem device\n", __func__);
+
+
+ dev = usb_get_dev(interface_to_usbdev(interface));
+ iface_desc = interface->cur_altsetting;
+ num_endpoints = iface_desc->desc.bNumEndpoints;
+
+ /*
+ * Scan the endpoint list and set:
+ * first input endpoint = IR endpoint
+ * first output endpoint = VFD endpoint
+ */
+
+ ir_ep_found = 0;
+ vfd_ep_found = 0;
+
+ for (i = 0; i < num_endpoints && !(ir_ep_found && vfd_ep_found); ++i) {
+
+ struct usb_endpoint_descriptor *ep;
+ int ep_dir;
+ int ep_type;
+ ep = &iface_desc->endpoint [i].desc;
+ ep_dir = ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK;
+ ep_type = ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK;
+
+ if (!ir_ep_found &&
+ ep_dir == USB_DIR_IN &&
+ ep_type == USB_ENDPOINT_XFER_INT) {
+
+ rx_endpoint = ep;
+ ir_ep_found = 1;
+ if (debug)
+ printk(KERN_INFO "%s: found IR endpoint\n",
+ __func__);
+
+ } else if (!vfd_ep_found &&
+ ep_dir == USB_DIR_OUT &&
+ ep_type == USB_ENDPOINT_XFER_INT) {
+
+ tx_endpoint = ep;
+ vfd_ep_found = 1;
+ if (debug)
+ printk(KERN_INFO "%s: found VFD endpoint\n",
+ __func__);
+ }
+ }
+
+ /* Input endpoint is mandatory */
+ if (!ir_ep_found) {
+
+ err("%s: no valid input (IR) endpoint found.", __func__);
+ retval = -ENODEV;
+ goto exit;
+ }
+
+ if (!vfd_ep_found)
+ printk(KERN_INFO "%s: no valid output (VFD) endpoint found.\n",
+ __func__);
+
+
+ /* Allocate memory */
+ alloc_status = 0;
+
+ context = kzalloc(sizeof(struct sasem_context), GFP_KERNEL);
+ if (!context) {
+ err("%s: kzalloc failed for context", __func__);
+ alloc_status = 1;
+ goto alloc_status_switch;
+ }
+ driver = kzalloc(sizeof(struct lirc_driver), GFP_KERNEL);
+ if (!driver) {
+ err("%s: kzalloc failed for lirc_driver", __func__);
+ alloc_status = 2;
+ goto alloc_status_switch;
+ }
+ rbuf = kmalloc(sizeof(struct lirc_buffer), GFP_KERNEL);
+ if (!rbuf) {
+ err("%s: kmalloc failed for lirc_buffer", __func__);
+ alloc_status = 3;
+ goto alloc_status_switch;
+ }
+ if (lirc_buffer_init(rbuf, BUF_CHUNK_SIZE, BUF_SIZE)) {
+ err("%s: lirc_buffer_init failed", __func__);
+ alloc_status = 4;
+ goto alloc_status_switch;
+ }
+ rx_urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!rx_urb) {
+ err("%s: usb_alloc_urb failed for IR urb", __func__);
+ alloc_status = 5;
+ goto alloc_status_switch;
+ }
+ if (vfd_ep_found) {
+ tx_urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!tx_urb) {
+ err("%s: usb_alloc_urb failed for VFD urb",
+ __func__);
+ alloc_status = 6;
+ goto alloc_status_switch;
+ }
+ }
+
+ mutex_init(&context->ctx_lock);
+
+ strcpy(driver->name, MOD_NAME);
+ driver->minor = -1;
+ driver->code_length = 64;
+ driver->sample_rate = 0;
+ driver->features = LIRC_CAN_REC_LIRCCODE;
+ driver->data = context;
+ driver->rbuf = rbuf;
+ driver->set_use_inc = ir_open;
+ driver->set_use_dec = ir_close;
+ driver->dev = &interface->dev;
+ driver->owner = THIS_MODULE;
+
+ mutex_lock(&context->ctx_lock);
+
+ lirc_minor = lirc_register_driver(driver);
+ if (lirc_minor < 0) {
+ err("%s: lirc_register_driver failed", __func__);
+ alloc_status = 7;
+ mutex_unlock(&context->ctx_lock);
+ } else
+ printk(KERN_INFO "%s: Registered Sasem driver (minor:%d)\n",
+ __func__, lirc_minor);
+
+alloc_status_switch:
+
+ switch (alloc_status) {
+
+ case 7:
+ if (vfd_ep_found)
+ usb_free_urb(tx_urb);
+ case 6:
+ usb_free_urb(rx_urb);
+ case 5:
+ lirc_buffer_free(rbuf);
+ case 4:
+ kfree(rbuf);
+ case 3:
+ kfree(driver);
+ case 2:
+ kfree(context);
+ context = NULL;
+ case 1:
+ retval = -ENOMEM;
+ goto exit;
+ }
+
+ /* Needed while unregistering! */
+ driver->minor = lirc_minor;
+
+ context->dev = dev;
+ context->dev_present = 1;
+ context->rx_endpoint = rx_endpoint;
+ context->rx_urb = rx_urb;
+ if (vfd_ep_found) {
+ context->tx_endpoint = tx_endpoint;
+ context->tx_urb = tx_urb;
+ context->vfd_contrast = 1000; /* range 0 - 1000 */
+ }
+ context->driver = driver;
+
+ usb_set_intfdata(interface, context);
+
+ if (vfd_ep_found) {
+
+ if (debug)
+ printk(KERN_INFO "Registering VFD with sysfs\n");
+ if (usb_register_dev(interface, &sasem_class))
+ /* Not a fatal error, so ignore */
+ printk(KERN_INFO "%s: could not get a minor number "
+ "for VFD\n", __func__);
+ }
+
+ printk(KERN_INFO "%s: Sasem device on usb<%d:%d> initialized\n",
+ __func__, dev->bus->busnum, dev->devnum);
+
+ mutex_unlock(&context->ctx_lock);
+exit:
+ return retval;
+}
+
+/**
+ * Callback function for USB core API: disonnect
+ */
+static void sasem_disconnect(struct usb_interface *interface)
+{
+ struct sasem_context *context;
+
+ /* prevent races with ir_open()/vfd_open() */
+ mutex_lock(&disconnect_lock);
+
+ context = usb_get_intfdata(interface);
+ mutex_lock(&context->ctx_lock);
+
+ printk(KERN_INFO "%s: Sasem device disconnected\n", __func__);
+
+ usb_set_intfdata(interface, NULL);
+ context->dev_present = 0;
+
+ /* Stop reception */
+ usb_kill_urb(context->rx_urb);
+
+ /* Abort ongoing write */
+ if (atomic_read(&context->tx.busy)) {
+
+ usb_kill_urb(context->tx_urb);
+ wait_for_completion(&context->tx.finished);
+ }
+
+ /* De-register from lirc_dev if IR port is not open */
+ if (!context->ir_isopen)
+ deregister_from_lirc(context);
+
+ usb_deregister_dev(interface, &sasem_class);
+
+ mutex_unlock(&context->ctx_lock);
+
+ if (!context->ir_isopen && !context->vfd_isopen)
+ delete_context(context);
+
+ mutex_unlock(&disconnect_lock);
+}
+
+static int __init sasem_init(void)
+{
+ int rc;
+
+ printk(KERN_INFO MOD_DESC ", v" MOD_VERSION "\n");
+ printk(KERN_INFO MOD_AUTHOR "\n");
+
+ rc = usb_register(&sasem_driver);
+ if (rc < 0) {
+ err("%s: usb register failed (%d)", __func__, rc);
+ return -ENODEV;
+ }
+ return 0;
+}
+
+static void __exit sasem_exit(void)
+{
+ usb_deregister(&sasem_driver);
+ printk(KERN_INFO "module removed. Goodbye!\n");
+}
+
+
+module_init(sasem_init);
+module_exit(sasem_exit);
diff --git a/drivers/staging/lirc/lirc_serial.c b/drivers/staging/lirc/lirc_serial.c
new file mode 100644
index 00000000000..9456f8e3f9e
--- /dev/null
+++ b/drivers/staging/lirc/lirc_serial.c
@@ -0,0 +1,1313 @@
+/*
+ * lirc_serial.c
+ *
+ * lirc_serial - Device driver that records pulse- and pause-lengths
+ * (space-lengths) between DDCD event on a serial port.
+ *
+ * Copyright (C) 1996,97 Ralph Metzler <rjkm@thp.uni-koeln.de>
+ * Copyright (C) 1998 Trent Piepho <xyzzy@u.washington.edu>
+ * Copyright (C) 1998 Ben Pfaff <blp@gnu.org>
+ * Copyright (C) 1999 Christoph Bartelmus <lirc@bartelmus.de>
+ * Copyright (C) 2007 Andrei Tanas <andrei@tanas.ca> (suspend/resume 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
+ *
+ */
+
+/*
+ * Steve's changes to improve transmission fidelity:
+ * - for systems with the rdtsc instruction and the clock counter, a
+ * send_pule that times the pulses directly using the counter.
+ * This means that the LIRC_SERIAL_TRANSMITTER_LATENCY fudge is
+ * not needed. Measurement shows very stable waveform, even where
+ * PCI activity slows the access to the UART, which trips up other
+ * versions.
+ * - For other system, non-integer-microsecond pulse/space lengths,
+ * done using fixed point binary. So, much more accurate carrier
+ * frequency.
+ * - fine tuned transmitter latency, taking advantage of fractional
+ * microseconds in previous change
+ * - Fixed bug in the way transmitter latency was accounted for by
+ * tuning the pulse lengths down - the send_pulse routine ignored
+ * this overhead as it timed the overall pulse length - so the
+ * pulse frequency was right but overall pulse length was too
+ * long. Fixed by accounting for latency on each pulse/space
+ * iteration.
+ *
+ * Steve Davies <steve@daviesfam.org> July 2001
+ */
+
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/fs.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/kernel.h>
+#include <linux/serial_reg.h>
+#include <linux/time.h>
+#include <linux/string.h>
+#include <linux/types.h>
+#include <linux/wait.h>
+#include <linux/mm.h>
+#include <linux/delay.h>
+#include <linux/poll.h>
+#include <linux/platform_device.h>
+
+#include <asm/system.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/fcntl.h>
+#include <linux/spinlock.h>
+
+#ifdef CONFIG_LIRC_SERIAL_NSLU2
+#include <asm/hardware.h>
+#endif
+/* From Intel IXP42X Developer's Manual (#252480-005): */
+/* ftp://download.intel.com/design/network/manuals/25248005.pdf */
+#define UART_IE_IXP42X_UUE 0x40 /* IXP42X UART Unit enable */
+#define UART_IE_IXP42X_RTOIE 0x10 /* IXP42X Receiver Data Timeout int.enable */
+
+#include <media/lirc.h>
+#include <media/lirc_dev.h>
+
+#define LIRC_DRIVER_NAME "lirc_serial"
+
+struct lirc_serial {
+ int signal_pin;
+ int signal_pin_change;
+ u8 on;
+ u8 off;
+ long (*send_pulse)(unsigned long length);
+ void (*send_space)(long length);
+ int features;
+ spinlock_t lock;
+};
+
+#define LIRC_HOMEBREW 0
+#define LIRC_IRDEO 1
+#define LIRC_IRDEO_REMOTE 2
+#define LIRC_ANIMAX 3
+#define LIRC_IGOR 4
+#define LIRC_NSLU2 5
+
+/*** module parameters ***/
+static int type;
+static int io;
+static int irq;
+static int iommap;
+static int ioshift;
+static int softcarrier = 1;
+static int share_irq;
+static int debug;
+static int sense = -1; /* -1 = auto, 0 = active high, 1 = active low */
+static int txsense; /* 0 = active high, 1 = active low */
+
+#define dprintk(fmt, args...) \
+ do { \
+ if (debug) \
+ printk(KERN_DEBUG LIRC_DRIVER_NAME ": " \
+ fmt, ## args); \
+ } while (0)
+
+/* forward declarations */
+static long send_pulse_irdeo(unsigned long length);
+static long send_pulse_homebrew(unsigned long length);
+static void send_space_irdeo(long length);
+static void send_space_homebrew(long length);
+
+static struct lirc_serial hardware[] = {
+ [LIRC_HOMEBREW] = {
+ .signal_pin = UART_MSR_DCD,
+ .signal_pin_change = UART_MSR_DDCD,
+ .on = (UART_MCR_RTS | UART_MCR_OUT2 | UART_MCR_DTR),
+ .off = (UART_MCR_RTS | UART_MCR_OUT2),
+ .send_pulse = send_pulse_homebrew,
+ .send_space = send_space_homebrew,
+#ifdef CONFIG_LIRC_SERIAL_TRANSMITTER
+ .features = (LIRC_CAN_SET_SEND_DUTY_CYCLE |
+ LIRC_CAN_SET_SEND_CARRIER |
+ LIRC_CAN_SEND_PULSE | LIRC_CAN_REC_MODE2)
+#else
+ .features = LIRC_CAN_REC_MODE2
+#endif
+ },
+
+ [LIRC_IRDEO] = {
+ .signal_pin = UART_MSR_DSR,
+ .signal_pin_change = UART_MSR_DDSR,
+ .on = UART_MCR_OUT2,
+ .off = (UART_MCR_RTS | UART_MCR_DTR | UART_MCR_OUT2),
+ .send_pulse = send_pulse_irdeo,
+ .send_space = send_space_irdeo,
+ .features = (LIRC_CAN_SET_SEND_DUTY_CYCLE |
+ LIRC_CAN_SEND_PULSE | LIRC_CAN_REC_MODE2)
+ },
+
+ [LIRC_IRDEO_REMOTE] = {
+ .signal_pin = UART_MSR_DSR,
+ .signal_pin_change = UART_MSR_DDSR,
+ .on = (UART_MCR_RTS | UART_MCR_DTR | UART_MCR_OUT2),
+ .off = (UART_MCR_RTS | UART_MCR_DTR | UART_MCR_OUT2),
+ .send_pulse = send_pulse_irdeo,
+ .send_space = send_space_irdeo,
+ .features = (LIRC_CAN_SET_SEND_DUTY_CYCLE |
+ LIRC_CAN_SEND_PULSE | LIRC_CAN_REC_MODE2)
+ },
+
+ [LIRC_ANIMAX] = {
+ .signal_pin = UART_MSR_DCD,
+ .signal_pin_change = UART_MSR_DDCD,
+ .on = 0,
+ .off = (UART_MCR_RTS | UART_MCR_DTR | UART_MCR_OUT2),
+ .send_pulse = NULL,
+ .send_space = NULL,
+ .features = LIRC_CAN_REC_MODE2
+ },
+
+ [LIRC_IGOR] = {
+ .signal_pin = UART_MSR_DSR,
+ .signal_pin_change = UART_MSR_DDSR,
+ .on = (UART_MCR_RTS | UART_MCR_OUT2 | UART_MCR_DTR),
+ .off = (UART_MCR_RTS | UART_MCR_OUT2),
+ .send_pulse = send_pulse_homebrew,
+ .send_space = send_space_homebrew,
+#ifdef CONFIG_LIRC_SERIAL_TRANSMITTER
+ .features = (LIRC_CAN_SET_SEND_DUTY_CYCLE |
+ LIRC_CAN_SET_SEND_CARRIER |
+ LIRC_CAN_SEND_PULSE | LIRC_CAN_REC_MODE2)
+#else
+ .features = LIRC_CAN_REC_MODE2
+#endif
+ },
+
+#ifdef CONFIG_LIRC_SERIAL_NSLU2
+ /*
+ * Modified Linksys Network Storage Link USB 2.0 (NSLU2):
+ * We receive on CTS of the 2nd serial port (R142,LHS), we
+ * transmit with a IR diode between GPIO[1] (green status LED),
+ * and ground (Matthias Goebl <matthias.goebl@goebl.net>).
+ * See also http://www.nslu2-linux.org for this device
+ */
+ [LIRC_NSLU2] = {
+ .signal_pin = UART_MSR_CTS,
+ .signal_pin_change = UART_MSR_DCTS,
+ .on = (UART_MCR_RTS | UART_MCR_OUT2 | UART_MCR_DTR),
+ .off = (UART_MCR_RTS | UART_MCR_OUT2),
+ .send_pulse = send_pulse_homebrew,
+ .send_space = send_space_homebrew,
+#ifdef CONFIG_LIRC_SERIAL_TRANSMITTER
+ .features = (LIRC_CAN_SET_SEND_DUTY_CYCLE |
+ LIRC_CAN_SET_SEND_CARRIER |
+ LIRC_CAN_SEND_PULSE | LIRC_CAN_REC_MODE2)
+#else
+ .features = LIRC_CAN_REC_MODE2
+#endif
+ },
+#endif
+
+};
+
+#define RS_ISR_PASS_LIMIT 256
+
+/*
+ * A long pulse code from a remote might take up to 300 bytes. The
+ * daemon should read the bytes as soon as they are generated, so take
+ * the number of keys you think you can push before the daemon runs
+ * and multiply by 300. The driver will warn you if you overrun this
+ * buffer. If you have a slow computer or non-busmastering IDE disks,
+ * maybe you will need to increase this.
+ */
+
+/* This MUST be a power of two! It has to be larger than 1 as well. */
+
+#define RBUF_LEN 256
+
+static struct timeval lasttv = {0, 0};
+
+static struct lirc_buffer rbuf;
+
+static unsigned int freq = 38000;
+static unsigned int duty_cycle = 50;
+
+/* Initialized in init_timing_params() */
+static unsigned long period;
+static unsigned long pulse_width;
+static unsigned long space_width;
+
+#if defined(__i386__)
+/*
+ * From:
+ * Linux I/O port programming mini-HOWTO
+ * Author: Riku Saikkonen <Riku.Saikkonen@hut.fi>
+ * v, 28 December 1997
+ *
+ * [...]
+ * Actually, a port I/O instruction on most ports in the 0-0x3ff range
+ * takes almost exactly 1 microsecond, so if you're, for example, using
+ * the parallel port directly, just do additional inb()s from that port
+ * to delay.
+ * [...]
+ */
+/* transmitter latency 1.5625us 0x1.90 - this figure arrived at from
+ * comment above plus trimming to match actual measured frequency.
+ * This will be sensitive to cpu speed, though hopefully most of the 1.5us
+ * is spent in the uart access. Still - for reference test machine was a
+ * 1.13GHz Athlon system - Steve
+ */
+
+/*
+ * changed from 400 to 450 as this works better on slower machines;
+ * faster machines will use the rdtsc code anyway
+ */
+#define LIRC_SERIAL_TRANSMITTER_LATENCY 450
+
+#else
+
+/* does anybody have information on other platforms ? */
+/* 256 = 1<<8 */
+#define LIRC_SERIAL_TRANSMITTER_LATENCY 256
+
+#endif /* __i386__ */
+/*
+ * FIXME: should we be using hrtimers instead of this
+ * LIRC_SERIAL_TRANSMITTER_LATENCY nonsense?
+ */
+
+/* fetch serial input packet (1 byte) from register offset */
+static u8 sinp(int offset)
+{
+ if (iommap != 0)
+ /* the register is memory-mapped */
+ offset <<= ioshift;
+
+ return inb(io + offset);
+}
+
+/* write serial output packet (1 byte) of value to register offset */
+static void soutp(int offset, u8 value)
+{
+ if (iommap != 0)
+ /* the register is memory-mapped */
+ offset <<= ioshift;
+
+ outb(value, io + offset);
+}
+
+static void on(void)
+{
+#ifdef CONFIG_LIRC_SERIAL_NSLU2
+ /*
+ * On NSLU2, we put the transmit diode between the output of the green
+ * status LED and ground
+ */
+ if (type == LIRC_NSLU2) {
+ gpio_line_set(NSLU2_LED_GRN, IXP4XX_GPIO_LOW);
+ return;
+ }
+#endif
+ if (txsense)
+ soutp(UART_MCR, hardware[type].off);
+ else
+ soutp(UART_MCR, hardware[type].on);
+}
+
+static void off(void)
+{
+#ifdef CONFIG_LIRC_SERIAL_NSLU2
+ if (type == LIRC_NSLU2) {
+ gpio_line_set(NSLU2_LED_GRN, IXP4XX_GPIO_HIGH);
+ return;
+ }
+#endif
+ if (txsense)
+ soutp(UART_MCR, hardware[type].on);
+ else
+ soutp(UART_MCR, hardware[type].off);
+}
+
+#ifndef MAX_UDELAY_MS
+#define MAX_UDELAY_US 5000
+#else
+#define MAX_UDELAY_US (MAX_UDELAY_MS*1000)
+#endif
+
+static void safe_udelay(unsigned long usecs)
+{
+ while (usecs > MAX_UDELAY_US) {
+ udelay(MAX_UDELAY_US);
+ usecs -= MAX_UDELAY_US;
+ }
+ udelay(usecs);
+}
+
+#ifdef USE_RDTSC
+/*
+ * This is an overflow/precision juggle, complicated in that we can't
+ * do long long divide in the kernel
+ */
+
+/*
+ * When we use the rdtsc instruction to measure clocks, we keep the
+ * pulse and space widths as clock cycles. As this is CPU speed
+ * dependent, the widths must be calculated in init_port and ioctl
+ * time
+ */
+
+/* So send_pulse can quickly convert microseconds to clocks */
+static unsigned long conv_us_to_clocks;
+
+static int init_timing_params(unsigned int new_duty_cycle,
+ unsigned int new_freq)
+{
+ unsigned long long loops_per_sec, work;
+
+ duty_cycle = new_duty_cycle;
+ freq = new_freq;
+
+ loops_per_sec = current_cpu_data.loops_per_jiffy;
+ loops_per_sec *= HZ;
+
+ /* How many clocks in a microsecond?, avoiding long long divide */
+ work = loops_per_sec;
+ work *= 4295; /* 4295 = 2^32 / 1e6 */
+ conv_us_to_clocks = (work >> 32);
+
+ /*
+ * Carrier period in clocks, approach good up to 32GHz clock,
+ * gets carrier frequency within 8Hz
+ */
+ period = loops_per_sec >> 3;
+ period /= (freq >> 3);
+
+ /* Derive pulse and space from the period */
+ pulse_width = period * duty_cycle / 100;
+ space_width = period - pulse_width;
+ dprintk("in init_timing_params, freq=%d, duty_cycle=%d, "
+ "clk/jiffy=%ld, pulse=%ld, space=%ld, "
+ "conv_us_to_clocks=%ld\n",
+ freq, duty_cycle, current_cpu_data.loops_per_jiffy,
+ pulse_width, space_width, conv_us_to_clocks);
+ return 0;
+}
+#else /* ! USE_RDTSC */
+static int init_timing_params(unsigned int new_duty_cycle,
+ unsigned int new_freq)
+{
+/*
+ * period, pulse/space width are kept with 8 binary places -
+ * IE multiplied by 256.
+ */
+ if (256 * 1000000L / new_freq * new_duty_cycle / 100 <=
+ LIRC_SERIAL_TRANSMITTER_LATENCY)
+ return -EINVAL;
+ if (256 * 1000000L / new_freq * (100 - new_duty_cycle) / 100 <=
+ LIRC_SERIAL_TRANSMITTER_LATENCY)
+ return -EINVAL;
+ duty_cycle = new_duty_cycle;
+ freq = new_freq;
+ period = 256 * 1000000L / freq;
+ pulse_width = period * duty_cycle / 100;
+ space_width = period - pulse_width;
+ dprintk("in init_timing_params, freq=%d pulse=%ld, "
+ "space=%ld\n", freq, pulse_width, space_width);
+ return 0;
+}
+#endif /* USE_RDTSC */
+
+
+/* return value: space length delta */
+
+static long send_pulse_irdeo(unsigned long length)
+{
+ long rawbits, ret;
+ int i;
+ unsigned char output;
+ unsigned char chunk, shifted;
+
+ /* how many bits have to be sent ? */
+ rawbits = length * 1152 / 10000;
+ if (duty_cycle > 50)
+ chunk = 3;
+ else
+ chunk = 1;
+ for (i = 0, output = 0x7f; rawbits > 0; rawbits -= 3) {
+ shifted = chunk << (i * 3);
+ shifted >>= 1;
+ output &= (~shifted);
+ i++;
+ if (i == 3) {
+ soutp(UART_TX, output);
+ while (!(sinp(UART_LSR) & UART_LSR_THRE))
+ ;
+ output = 0x7f;
+ i = 0;
+ }
+ }
+ if (i != 0) {
+ soutp(UART_TX, output);
+ while (!(sinp(UART_LSR) & UART_LSR_TEMT))
+ ;
+ }
+
+ if (i == 0)
+ ret = (-rawbits) * 10000 / 1152;
+ else
+ ret = (3 - i) * 3 * 10000 / 1152 + (-rawbits) * 10000 / 1152;
+
+ return ret;
+}
+
+#ifdef USE_RDTSC
+/* Version that uses Pentium rdtsc instruction to measure clocks */
+
+/*
+ * This version does sub-microsecond timing using rdtsc instruction,
+ * and does away with the fudged LIRC_SERIAL_TRANSMITTER_LATENCY
+ * Implicitly i586 architecture... - Steve
+ */
+
+static long send_pulse_homebrew_softcarrier(unsigned long length)
+{
+ int flag;
+ unsigned long target, start, now;
+
+ /* Get going quick as we can */
+ rdtscl(start);
+ on();
+ /* Convert length from microseconds to clocks */
+ length *= conv_us_to_clocks;
+ /* And loop till time is up - flipping at right intervals */
+ now = start;
+ target = pulse_width;
+ flag = 1;
+ /*
+ * FIXME: This looks like a hard busy wait, without even an occasional,
+ * polite, cpu_relax() call. There's got to be a better way?
+ *
+ * The i2c code has the result of a lot of bit-banging work, I wonder if
+ * there's something there which could be helpful here.
+ */
+ while ((now - start) < length) {
+ /* Delay till flip time */
+ do {
+ rdtscl(now);
+ } while ((now - start) < target);
+
+ /* flip */
+ if (flag) {
+ rdtscl(now);
+ off();
+ target += space_width;
+ } else {
+ rdtscl(now); on();
+ target += pulse_width;
+ }
+ flag = !flag;
+ }
+ rdtscl(now);
+ return ((now - start) - length) / conv_us_to_clocks;
+}
+#else /* ! USE_RDTSC */
+/* Version using udelay() */
+
+/*
+ * here we use fixed point arithmetic, with 8
+ * fractional bits. that gets us within 0.1% or so of the right average
+ * frequency, albeit with some jitter in pulse length - Steve
+ */
+
+/* To match 8 fractional bits used for pulse/space length */
+
+static long send_pulse_homebrew_softcarrier(unsigned long length)
+{
+ int flag;
+ unsigned long actual, target, d;
+ length <<= 8;
+
+ actual = 0; target = 0; flag = 0;
+ while (actual < length) {
+ if (flag) {
+ off();
+ target += space_width;
+ } else {
+ on();
+ target += pulse_width;
+ }
+ d = (target - actual -
+ LIRC_SERIAL_TRANSMITTER_LATENCY + 128) >> 8;
+ /*
+ * Note - we've checked in ioctl that the pulse/space
+ * widths are big enough so that d is > 0
+ */
+ udelay(d);
+ actual += (d << 8) + LIRC_SERIAL_TRANSMITTER_LATENCY;
+ flag = !flag;
+ }
+ return (actual-length) >> 8;
+}
+#endif /* USE_RDTSC */
+
+static long send_pulse_homebrew(unsigned long length)
+{
+ if (length <= 0)
+ return 0;
+
+ if (softcarrier)
+ return send_pulse_homebrew_softcarrier(length);
+ else {
+ on();
+ safe_udelay(length);
+ return 0;
+ }
+}
+
+static void send_space_irdeo(long length)
+{
+ if (length <= 0)
+ return;
+
+ safe_udelay(length);
+}
+
+static void send_space_homebrew(long length)
+{
+ off();
+ if (length <= 0)
+ return;
+ safe_udelay(length);
+}
+
+static void rbwrite(int l)
+{
+ if (lirc_buffer_full(&rbuf)) {
+ /* no new signals will be accepted */
+ dprintk("Buffer overrun\n");
+ return;
+ }
+ lirc_buffer_write(&rbuf, (void *)&l);
+}
+
+static void frbwrite(int l)
+{
+ /* simple noise filter */
+ static int pulse, space;
+ static unsigned int ptr;
+
+ if (ptr > 0 && (l & PULSE_BIT)) {
+ pulse += l & PULSE_MASK;
+ if (pulse > 250) {
+ rbwrite(space);
+ rbwrite(pulse | PULSE_BIT);
+ ptr = 0;
+ pulse = 0;
+ }
+ return;
+ }
+ if (!(l & PULSE_BIT)) {
+ if (ptr == 0) {
+ if (l > 20000) {
+ space = l;
+ ptr++;
+ return;
+ }
+ } else {
+ if (l > 20000) {
+ space += pulse;
+ if (space > PULSE_MASK)
+ space = PULSE_MASK;
+ space += l;
+ if (space > PULSE_MASK)
+ space = PULSE_MASK;
+ pulse = 0;
+ return;
+ }
+ rbwrite(space);
+ rbwrite(pulse | PULSE_BIT);
+ ptr = 0;
+ pulse = 0;
+ }
+ }
+ rbwrite(l);
+}
+
+static irqreturn_t irq_handler(int i, void *blah)
+{
+ struct timeval tv;
+ int counter, dcd;
+ u8 status;
+ long deltv;
+ int data;
+ static int last_dcd = -1;
+
+ if ((sinp(UART_IIR) & UART_IIR_NO_INT)) {
+ /* not our interrupt */
+ return IRQ_NONE;
+ }
+
+ counter = 0;
+ do {
+ counter++;
+ status = sinp(UART_MSR);
+ if (counter > RS_ISR_PASS_LIMIT) {
+ printk(KERN_WARNING LIRC_DRIVER_NAME ": AIEEEE: "
+ "We're caught!\n");
+ break;
+ }
+ if ((status & hardware[type].signal_pin_change)
+ && sense != -1) {
+ /* get current time */
+ do_gettimeofday(&tv);
+
+ /* New mode, written by Trent Piepho
+ <xyzzy@u.washington.edu>. */
+
+ /*
+ * The old format was not very portable.
+ * We now use an int to pass pulses
+ * and spaces to user space.
+ *
+ * If PULSE_BIT is set a pulse has been
+ * received, otherwise a space has been
+ * received. The driver needs to know if your
+ * receiver is active high or active low, or
+ * the space/pulse sense could be
+ * inverted. The bits denoted by PULSE_MASK are
+ * the length in microseconds. Lengths greater
+ * than or equal to 16 seconds are clamped to
+ * PULSE_MASK. All other bits are unused.
+ * This is a much simpler interface for user
+ * programs, as well as eliminating "out of
+ * phase" errors with space/pulse
+ * autodetection.
+ */
+
+ /* calc time since last interrupt in microseconds */
+ dcd = (status & hardware[type].signal_pin) ? 1 : 0;
+
+ if (dcd == last_dcd) {
+ printk(KERN_WARNING LIRC_DRIVER_NAME
+ ": ignoring spike: %d %d %lx %lx %lx %lx\n",
+ dcd, sense,
+ tv.tv_sec, lasttv.tv_sec,
+ tv.tv_usec, lasttv.tv_usec);
+ continue;
+ }
+
+ deltv = tv.tv_sec-lasttv.tv_sec;
+ if (tv.tv_sec < lasttv.tv_sec ||
+ (tv.tv_sec == lasttv.tv_sec &&
+ tv.tv_usec < lasttv.tv_usec)) {
+ printk(KERN_WARNING LIRC_DRIVER_NAME
+ ": AIEEEE: your clock just jumped "
+ "backwards\n");
+ printk(KERN_WARNING LIRC_DRIVER_NAME
+ ": %d %d %lx %lx %lx %lx\n",
+ dcd, sense,
+ tv.tv_sec, lasttv.tv_sec,
+ tv.tv_usec, lasttv.tv_usec);
+ data = PULSE_MASK;
+ } else if (deltv > 15) {
+ data = PULSE_MASK; /* really long time */
+ if (!(dcd^sense)) {
+ /* sanity check */
+ printk(KERN_WARNING LIRC_DRIVER_NAME
+ ": AIEEEE: "
+ "%d %d %lx %lx %lx %lx\n",
+ dcd, sense,
+ tv.tv_sec, lasttv.tv_sec,
+ tv.tv_usec, lasttv.tv_usec);
+ /*
+ * detecting pulse while this
+ * MUST be a space!
+ */
+ sense = sense ? 0 : 1;
+ }
+ } else
+ data = (int) (deltv*1000000 +
+ tv.tv_usec -
+ lasttv.tv_usec);
+ frbwrite(dcd^sense ? data : (data|PULSE_BIT));
+ lasttv = tv;
+ last_dcd = dcd;
+ wake_up_interruptible(&rbuf.wait_poll);
+ }
+ } while (!(sinp(UART_IIR) & UART_IIR_NO_INT)); /* still pending ? */
+ return IRQ_HANDLED;
+}
+
+
+static int hardware_init_port(void)
+{
+ u8 scratch, scratch2, scratch3;
+
+ /*
+ * This is a simple port existence test, borrowed from the autoconfig
+ * function in drivers/serial/8250.c
+ */
+ scratch = sinp(UART_IER);
+ soutp(UART_IER, 0);
+#ifdef __i386__
+ outb(0xff, 0x080);
+#endif
+ scratch2 = sinp(UART_IER) & 0x0f;
+ soutp(UART_IER, 0x0f);
+#ifdef __i386__
+ outb(0x00, 0x080);
+#endif
+ scratch3 = sinp(UART_IER) & 0x0f;
+ soutp(UART_IER, scratch);
+ if (scratch2 != 0 || scratch3 != 0x0f) {
+ /* we fail, there's nothing here */
+ printk(KERN_ERR LIRC_DRIVER_NAME ": port existence test "
+ "failed, cannot continue\n");
+ return -EINVAL;
+ }
+
+
+
+ /* Set DLAB 0. */
+ soutp(UART_LCR, sinp(UART_LCR) & (~UART_LCR_DLAB));
+
+ /* First of all, disable all interrupts */
+ soutp(UART_IER, sinp(UART_IER) &
+ (~(UART_IER_MSI|UART_IER_RLSI|UART_IER_THRI|UART_IER_RDI)));
+
+ /* Clear registers. */
+ sinp(UART_LSR);
+ sinp(UART_RX);
+ sinp(UART_IIR);
+ sinp(UART_MSR);
+
+#ifdef CONFIG_LIRC_SERIAL_NSLU2
+ if (type == LIRC_NSLU2) {
+ /* Setup NSLU2 UART */
+
+ /* Enable UART */
+ soutp(UART_IER, sinp(UART_IER) | UART_IE_IXP42X_UUE);
+ /* Disable Receiver data Time out interrupt */
+ soutp(UART_IER, sinp(UART_IER) & ~UART_IE_IXP42X_RTOIE);
+ /* set out2 = interrupt unmask; off() doesn't set MCR
+ on NSLU2 */
+ soutp(UART_MCR, UART_MCR_RTS|UART_MCR_OUT2);
+ }
+#endif
+
+ /* Set line for power source */
+ off();
+
+ /* Clear registers again to be sure. */
+ sinp(UART_LSR);
+ sinp(UART_RX);
+ sinp(UART_IIR);
+ sinp(UART_MSR);
+
+ switch (type) {
+ case LIRC_IRDEO:
+ case LIRC_IRDEO_REMOTE:
+ /* setup port to 7N1 @ 115200 Baud */
+ /* 7N1+start = 9 bits at 115200 ~ 3 bits at 38kHz */
+
+ /* Set DLAB 1. */
+ soutp(UART_LCR, sinp(UART_LCR) | UART_LCR_DLAB);
+ /* Set divisor to 1 => 115200 Baud */
+ soutp(UART_DLM, 0);
+ soutp(UART_DLL, 1);
+ /* Set DLAB 0 + 7N1 */
+ soutp(UART_LCR, UART_LCR_WLEN7);
+ /* THR interrupt already disabled at this point */
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static int init_port(void)
+{
+ int i, nlow, nhigh;
+
+ /* Reserve io region. */
+ /*
+ * Future MMAP-Developers: Attention!
+ * For memory mapped I/O you *might* need to use ioremap() first,
+ * for the NSLU2 it's done in boot code.
+ */
+ if (((iommap != 0)
+ && (request_mem_region(iommap, 8 << ioshift,
+ LIRC_DRIVER_NAME) == NULL))
+ || ((iommap == 0)
+ && (request_region(io, 8, LIRC_DRIVER_NAME) == NULL))) {
+ printk(KERN_ERR LIRC_DRIVER_NAME
+ ": port %04x already in use\n", io);
+ printk(KERN_WARNING LIRC_DRIVER_NAME
+ ": use 'setserial /dev/ttySX uart none'\n");
+ printk(KERN_WARNING LIRC_DRIVER_NAME
+ ": or compile the serial port driver as module and\n");
+ printk(KERN_WARNING LIRC_DRIVER_NAME
+ ": make sure this module is loaded first\n");
+ return -EBUSY;
+ }
+
+ if (hardware_init_port() < 0)
+ return -EINVAL;
+
+ /* Initialize pulse/space widths */
+ init_timing_params(duty_cycle, freq);
+
+ /* If pin is high, then this must be an active low receiver. */
+ if (sense == -1) {
+ /* wait 1/2 sec for the power supply */
+ msleep(500);
+
+ /*
+ * probe 9 times every 0.04s, collect "votes" for
+ * active high/low
+ */
+ nlow = 0;
+ nhigh = 0;
+ for (i = 0; i < 9; i++) {
+ if (sinp(UART_MSR) & hardware[type].signal_pin)
+ nlow++;
+ else
+ nhigh++;
+ msleep(40);
+ }
+ sense = (nlow >= nhigh ? 1 : 0);
+ printk(KERN_INFO LIRC_DRIVER_NAME ": auto-detected active "
+ "%s receiver\n", sense ? "low" : "high");
+ } else
+ printk(KERN_INFO LIRC_DRIVER_NAME ": Manually using active "
+ "%s receiver\n", sense ? "low" : "high");
+
+ return 0;
+}
+
+static int set_use_inc(void *data)
+{
+ int result;
+ unsigned long flags;
+
+ /* initialize timestamp */
+ do_gettimeofday(&lasttv);
+
+ result = request_irq(irq, irq_handler,
+ IRQF_DISABLED | (share_irq ? IRQF_SHARED : 0),
+ LIRC_DRIVER_NAME, (void *)&hardware);
+
+ switch (result) {
+ case -EBUSY:
+ printk(KERN_ERR LIRC_DRIVER_NAME ": IRQ %d busy\n", irq);
+ return -EBUSY;
+ case -EINVAL:
+ printk(KERN_ERR LIRC_DRIVER_NAME
+ ": Bad irq number or handler\n");
+ return -EINVAL;
+ default:
+ dprintk("Interrupt %d, port %04x obtained\n", irq, io);
+ break;
+ };
+
+ spin_lock_irqsave(&hardware[type].lock, flags);
+
+ /* Set DLAB 0. */
+ soutp(UART_LCR, sinp(UART_LCR) & (~UART_LCR_DLAB));
+
+ soutp(UART_IER, sinp(UART_IER)|UART_IER_MSI);
+
+ spin_unlock_irqrestore(&hardware[type].lock, flags);
+
+ return 0;
+}
+
+static void set_use_dec(void *data)
+{ unsigned long flags;
+
+ spin_lock_irqsave(&hardware[type].lock, flags);
+
+ /* Set DLAB 0. */
+ soutp(UART_LCR, sinp(UART_LCR) & (~UART_LCR_DLAB));
+
+ /* First of all, disable all interrupts */
+ soutp(UART_IER, sinp(UART_IER) &
+ (~(UART_IER_MSI|UART_IER_RLSI|UART_IER_THRI|UART_IER_RDI)));
+ spin_unlock_irqrestore(&hardware[type].lock, flags);
+
+ free_irq(irq, (void *)&hardware);
+
+ dprintk("freed IRQ %d\n", irq);
+}
+
+static ssize_t lirc_write(struct file *file, const char *buf,
+ size_t n, loff_t *ppos)
+{
+ int i, count;
+ unsigned long flags;
+ long delta = 0;
+ int *wbuf;
+
+ if (!(hardware[type].features & LIRC_CAN_SEND_PULSE))
+ return -EBADF;
+
+ count = n / sizeof(int);
+ if (n % sizeof(int) || count % 2 == 0)
+ return -EINVAL;
+ wbuf = memdup_user(buf, n);
+ if (PTR_ERR(wbuf))
+ return PTR_ERR(wbuf);
+ spin_lock_irqsave(&hardware[type].lock, flags);
+ if (type == LIRC_IRDEO) {
+ /* DTR, RTS down */
+ on();
+ }
+ for (i = 0; i < count; i++) {
+ if (i%2)
+ hardware[type].send_space(wbuf[i] - delta);
+ else
+ delta = hardware[type].send_pulse(wbuf[i]);
+ }
+ off();
+ spin_unlock_irqrestore(&hardware[type].lock, flags);
+ return n;
+}
+
+static long lirc_ioctl(struct file *filep, unsigned int cmd, unsigned long arg)
+{
+ int result;
+ unsigned long value;
+ unsigned int ivalue;
+
+ switch (cmd) {
+ case LIRC_GET_SEND_MODE:
+ if (!(hardware[type].features&LIRC_CAN_SEND_MASK))
+ return -ENOIOCTLCMD;
+
+ result = put_user(LIRC_SEND2MODE
+ (hardware[type].features&LIRC_CAN_SEND_MASK),
+ (unsigned long *) arg);
+ if (result)
+ return result;
+ break;
+
+ case LIRC_SET_SEND_MODE:
+ if (!(hardware[type].features&LIRC_CAN_SEND_MASK))
+ return -ENOIOCTLCMD;
+
+ result = get_user(value, (unsigned long *) arg);
+ if (result)
+ return result;
+ /* only LIRC_MODE_PULSE supported */
+ if (value != LIRC_MODE_PULSE)
+ return -ENOSYS;
+ break;
+
+ case LIRC_GET_LENGTH:
+ return -ENOSYS;
+ break;
+
+ case LIRC_SET_SEND_DUTY_CYCLE:
+ dprintk("SET_SEND_DUTY_CYCLE\n");
+ if (!(hardware[type].features&LIRC_CAN_SET_SEND_DUTY_CYCLE))
+ return -ENOIOCTLCMD;
+
+ result = get_user(ivalue, (unsigned int *) arg);
+ if (result)
+ return result;
+ if (ivalue <= 0 || ivalue > 100)
+ return -EINVAL;
+ return init_timing_params(ivalue, freq);
+ break;
+
+ case LIRC_SET_SEND_CARRIER:
+ dprintk("SET_SEND_CARRIER\n");
+ if (!(hardware[type].features&LIRC_CAN_SET_SEND_CARRIER))
+ return -ENOIOCTLCMD;
+
+ result = get_user(ivalue, (unsigned int *) arg);
+ if (result)
+ return result;
+ if (ivalue > 500000 || ivalue < 20000)
+ return -EINVAL;
+ return init_timing_params(duty_cycle, ivalue);
+ break;
+
+ default:
+ return lirc_dev_fop_ioctl(filep, cmd, arg);
+ }
+ return 0;
+}
+
+static const struct file_operations lirc_fops = {
+ .owner = THIS_MODULE,
+ .write = lirc_write,
+ .unlocked_ioctl = lirc_ioctl,
+ .read = lirc_dev_fop_read,
+ .poll = lirc_dev_fop_poll,
+ .open = lirc_dev_fop_open,
+ .release = lirc_dev_fop_close,
+};
+
+static struct lirc_driver driver = {
+ .name = LIRC_DRIVER_NAME,
+ .minor = -1,
+ .code_length = 1,
+ .sample_rate = 0,
+ .data = NULL,
+ .add_to_buf = NULL,
+ .rbuf = &rbuf,
+ .set_use_inc = set_use_inc,
+ .set_use_dec = set_use_dec,
+ .fops = &lirc_fops,
+ .dev = NULL,
+ .owner = THIS_MODULE,
+};
+
+static struct platform_device *lirc_serial_dev;
+
+static int __devinit lirc_serial_probe(struct platform_device *dev)
+{
+ return 0;
+}
+
+static int __devexit lirc_serial_remove(struct platform_device *dev)
+{
+ return 0;
+}
+
+static int lirc_serial_suspend(struct platform_device *dev,
+ pm_message_t state)
+{
+ /* Set DLAB 0. */
+ soutp(UART_LCR, sinp(UART_LCR) & (~UART_LCR_DLAB));
+
+ /* Disable all interrupts */
+ soutp(UART_IER, sinp(UART_IER) &
+ (~(UART_IER_MSI|UART_IER_RLSI|UART_IER_THRI|UART_IER_RDI)));
+
+ /* Clear registers. */
+ sinp(UART_LSR);
+ sinp(UART_RX);
+ sinp(UART_IIR);
+ sinp(UART_MSR);
+
+ return 0;
+}
+
+/* twisty maze... need a forward-declaration here... */
+static void lirc_serial_exit(void);
+
+static int lirc_serial_resume(struct platform_device *dev)
+{
+ unsigned long flags;
+
+ if (hardware_init_port() < 0) {
+ lirc_serial_exit();
+ return -EINVAL;
+ }
+
+ spin_lock_irqsave(&hardware[type].lock, flags);
+ /* Enable Interrupt */
+ do_gettimeofday(&lasttv);
+ soutp(UART_IER, sinp(UART_IER)|UART_IER_MSI);
+ off();
+
+ lirc_buffer_clear(&rbuf);
+
+ spin_unlock_irqrestore(&hardware[type].lock, flags);
+
+ return 0;
+}
+
+static struct platform_driver lirc_serial_driver = {
+ .probe = lirc_serial_probe,
+ .remove = __devexit_p(lirc_serial_remove),
+ .suspend = lirc_serial_suspend,
+ .resume = lirc_serial_resume,
+ .driver = {
+ .name = "lirc_serial",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init lirc_serial_init(void)
+{
+ int result;
+
+ /* Init read buffer. */
+ result = lirc_buffer_init(&rbuf, sizeof(int), RBUF_LEN);
+ if (result < 0)
+ return -ENOMEM;
+
+ result = platform_driver_register(&lirc_serial_driver);
+ if (result) {
+ printk("lirc register returned %d\n", result);
+ goto exit_buffer_free;
+ }
+
+ lirc_serial_dev = platform_device_alloc("lirc_serial", 0);
+ if (!lirc_serial_dev) {
+ result = -ENOMEM;
+ goto exit_driver_unregister;
+ }
+
+ result = platform_device_add(lirc_serial_dev);
+ if (result)
+ goto exit_device_put;
+
+ return 0;
+
+exit_device_put:
+ platform_device_put(lirc_serial_dev);
+exit_driver_unregister:
+ platform_driver_unregister(&lirc_serial_driver);
+exit_buffer_free:
+ lirc_buffer_free(&rbuf);
+ return result;
+}
+
+static void lirc_serial_exit(void)
+{
+ platform_device_unregister(lirc_serial_dev);
+ platform_driver_unregister(&lirc_serial_driver);
+ lirc_buffer_free(&rbuf);
+}
+
+static int __init lirc_serial_init_module(void)
+{
+ int result;
+
+ result = lirc_serial_init();
+ if (result)
+ return result;
+
+ switch (type) {
+ case LIRC_HOMEBREW:
+ case LIRC_IRDEO:
+ case LIRC_IRDEO_REMOTE:
+ case LIRC_ANIMAX:
+ case LIRC_IGOR:
+ /* if nothing specified, use ttyS0/com1 and irq 4 */
+ io = io ? io : 0x3f8;
+ irq = irq ? irq : 4;
+ break;
+#ifdef CONFIG_LIRC_SERIAL_NSLU2
+ case LIRC_NSLU2:
+ io = io ? io : IRQ_IXP4XX_UART2;
+ irq = irq ? irq : (IXP4XX_UART2_BASE_VIRT + REG_OFFSET);
+ iommap = iommap ? iommap : IXP4XX_UART2_BASE_PHYS;
+ ioshift = ioshift ? ioshift : 2;
+ break;
+#endif
+ default:
+ result = -EINVAL;
+ goto exit_serial_exit;
+ }
+ if (!softcarrier) {
+ switch (type) {
+ case LIRC_HOMEBREW:
+ case LIRC_IGOR:
+#ifdef CONFIG_LIRC_SERIAL_NSLU2
+ case LIRC_NSLU2:
+#endif
+ hardware[type].features &=
+ ~(LIRC_CAN_SET_SEND_DUTY_CYCLE|
+ LIRC_CAN_SET_SEND_CARRIER);
+ break;
+ }
+ }
+
+ result = init_port();
+ if (result < 0)
+ goto exit_serial_exit;
+ driver.features = hardware[type].features;
+ driver.dev = &lirc_serial_dev->dev;
+ driver.minor = lirc_register_driver(&driver);
+ if (driver.minor < 0) {
+ printk(KERN_ERR LIRC_DRIVER_NAME
+ ": register_chrdev failed!\n");
+ result = -EIO;
+ goto exit_release;
+ }
+ return 0;
+exit_release:
+ release_region(io, 8);
+exit_serial_exit:
+ lirc_serial_exit();
+ return result;
+}
+
+static void __exit lirc_serial_exit_module(void)
+{
+ lirc_serial_exit();
+ if (iommap != 0)
+ release_mem_region(iommap, 8 << ioshift);
+ else
+ release_region(io, 8);
+ lirc_unregister_driver(driver.minor);
+ dprintk("cleaned up module\n");
+}
+
+
+module_init(lirc_serial_init_module);
+module_exit(lirc_serial_exit_module);
+
+MODULE_DESCRIPTION("Infra-red receiver driver for serial ports.");
+MODULE_AUTHOR("Ralph Metzler, Trent Piepho, Ben Pfaff, "
+ "Christoph Bartelmus, Andrei Tanas");
+MODULE_LICENSE("GPL");
+
+module_param(type, int, S_IRUGO);
+MODULE_PARM_DESC(type, "Hardware type (0 = home-brew, 1 = IRdeo,"
+ " 2 = IRdeo Remote, 3 = AnimaX, 4 = IgorPlug,"
+ " 5 = NSLU2 RX:CTS2/TX:GreenLED)");
+
+module_param(io, int, S_IRUGO);
+MODULE_PARM_DESC(io, "I/O address base (0x3f8 or 0x2f8)");
+
+/* some architectures (e.g. intel xscale) have memory mapped registers */
+module_param(iommap, bool, S_IRUGO);
+MODULE_PARM_DESC(iommap, "physical base for memory mapped I/O"
+ " (0 = no memory mapped io)");
+
+/*
+ * some architectures (e.g. intel xscale) align the 8bit serial registers
+ * on 32bit word boundaries.
+ * See linux-kernel/serial/8250.c serial_in()/out()
+ */
+module_param(ioshift, int, S_IRUGO);
+MODULE_PARM_DESC(ioshift, "shift I/O register offset (0 = no shift)");
+
+module_param(irq, int, S_IRUGO);
+MODULE_PARM_DESC(irq, "Interrupt (4 or 3)");
+
+module_param(share_irq, bool, S_IRUGO);
+MODULE_PARM_DESC(share_irq, "Share interrupts (0 = off, 1 = on)");
+
+module_param(sense, bool, S_IRUGO);
+MODULE_PARM_DESC(sense, "Override autodetection of IR receiver circuit"
+ " (0 = active high, 1 = active low )");
+
+#ifdef CONFIG_LIRC_SERIAL_TRANSMITTER
+module_param(txsense, bool, S_IRUGO);
+MODULE_PARM_DESC(txsense, "Sense of transmitter circuit"
+ " (0 = active high, 1 = active low )");
+#endif
+
+module_param(softcarrier, bool, S_IRUGO);
+MODULE_PARM_DESC(softcarrier, "Software carrier (0 = off, 1 = on, default on)");
+
+module_param(debug, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug, "Enable debugging messages");
diff --git a/drivers/staging/lirc/lirc_sir.c b/drivers/staging/lirc/lirc_sir.c
new file mode 100644
index 00000000000..eb08fa7138b
--- /dev/null
+++ b/drivers/staging/lirc/lirc_sir.c
@@ -0,0 +1,1282 @@
+/*
+ * LIRC SIR driver, (C) 2000 Milan Pikula <www@fornax.sk>
+ *
+ * lirc_sir - Device driver for use with SIR (serial infra red)
+ * mode of IrDA on many notebooks.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * 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
+ *
+ *
+ * 2000/09/16 Frank Przybylski <mail@frankprzybylski.de> :
+ * added timeout and relaxed pulse detection, removed gap bug
+ *
+ * 2000/12/15 Christoph Bartelmus <lirc@bartelmus.de> :
+ * added support for Tekram Irmate 210 (sending does not work yet,
+ * kind of disappointing that nobody was able to implement that
+ * before),
+ * major clean-up
+ *
+ * 2001/02/27 Christoph Bartelmus <lirc@bartelmus.de> :
+ * added support for StrongARM SA1100 embedded microprocessor
+ * parts cut'n'pasted from sa1100_ir.c (C) 2000 Russell King
+ */
+
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/signal.h>
+#include <linux/fs.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/kernel.h>
+#include <linux/serial_reg.h>
+#include <linux/time.h>
+#include <linux/string.h>
+#include <linux/types.h>
+#include <linux/wait.h>
+#include <linux/mm.h>
+#include <linux/delay.h>
+#include <linux/poll.h>
+#include <asm/system.h>
+#include <linux/io.h>
+#include <asm/irq.h>
+#include <linux/fcntl.h>
+#ifdef LIRC_ON_SA1100
+#include <asm/hardware.h>
+#ifdef CONFIG_SA1100_COLLIE
+#include <asm/arch/tc35143.h>
+#include <asm/ucb1200.h>
+#endif
+#endif
+
+#include <linux/timer.h>
+
+#include <media/lirc.h>
+#include <media/lirc_dev.h>
+
+/* SECTION: Definitions */
+
+/*** Tekram dongle ***/
+#ifdef LIRC_SIR_TEKRAM
+/* stolen from kernel source */
+/* definitions for Tekram dongle */
+#define TEKRAM_115200 0x00
+#define TEKRAM_57600 0x01
+#define TEKRAM_38400 0x02
+#define TEKRAM_19200 0x03
+#define TEKRAM_9600 0x04
+#define TEKRAM_2400 0x08
+
+#define TEKRAM_PW 0x10 /* Pulse select bit */
+
+/* 10bit * 1s/115200bit in milliseconds = 87ms*/
+#define TIME_CONST (10000000ul/115200ul)
+
+#endif
+
+#ifdef LIRC_SIR_ACTISYS_ACT200L
+static void init_act200(void);
+#elif defined(LIRC_SIR_ACTISYS_ACT220L)
+static void init_act220(void);
+#endif
+
+/*** SA1100 ***/
+#ifdef LIRC_ON_SA1100
+struct sa1100_ser2_registers {
+ /* HSSP control register */
+ unsigned char hscr0;
+ /* UART registers */
+ unsigned char utcr0;
+ unsigned char utcr1;
+ unsigned char utcr2;
+ unsigned char utcr3;
+ unsigned char utcr4;
+ unsigned char utdr;
+ unsigned char utsr0;
+ unsigned char utsr1;
+} sr;
+
+static int irq = IRQ_Ser2ICP;
+
+#define LIRC_ON_SA1100_TRANSMITTER_LATENCY 0
+
+/* pulse/space ratio of 50/50 */
+static unsigned long pulse_width = (13-LIRC_ON_SA1100_TRANSMITTER_LATENCY);
+/* 1000000/freq-pulse_width */
+static unsigned long space_width = (13-LIRC_ON_SA1100_TRANSMITTER_LATENCY);
+static unsigned int freq = 38000; /* modulation frequency */
+static unsigned int duty_cycle = 50; /* duty cycle of 50% */
+
+#endif
+
+#define RBUF_LEN 1024
+#define WBUF_LEN 1024
+
+#define LIRC_DRIVER_NAME "lirc_sir"
+
+#define PULSE '['
+
+#ifndef LIRC_SIR_TEKRAM
+/* 9bit * 1s/115200bit in milli seconds = 78.125ms*/
+#define TIME_CONST (9000000ul/115200ul)
+#endif
+
+
+/* timeout for sequences in jiffies (=5/100s), must be longer than TIME_CONST */
+#define SIR_TIMEOUT (HZ*5/100)
+
+#ifndef LIRC_ON_SA1100
+#ifndef LIRC_IRQ
+#define LIRC_IRQ 4
+#endif
+#ifndef LIRC_PORT
+/* for external dongles, default to com1 */
+#if defined(LIRC_SIR_ACTISYS_ACT200L) || \
+ defined(LIRC_SIR_ACTISYS_ACT220L) || \
+ defined(LIRC_SIR_TEKRAM)
+#define LIRC_PORT 0x3f8
+#else
+/* onboard sir ports are typically com3 */
+#define LIRC_PORT 0x3e8
+#endif
+#endif
+
+static int io = LIRC_PORT;
+static int irq = LIRC_IRQ;
+static int threshold = 3;
+#endif
+
+static DEFINE_SPINLOCK(timer_lock);
+static struct timer_list timerlist;
+/* time of last signal change detected */
+static struct timeval last_tv = {0, 0};
+/* time of last UART data ready interrupt */
+static struct timeval last_intr_tv = {0, 0};
+static int last_value;
+
+static DECLARE_WAIT_QUEUE_HEAD(lirc_read_queue);
+
+static DEFINE_SPINLOCK(hardware_lock);
+
+static int rx_buf[RBUF_LEN];
+static unsigned int rx_tail, rx_head;
+
+static int debug;
+#define dprintk(fmt, args...) \
+ do { \
+ if (debug) \
+ printk(KERN_DEBUG LIRC_DRIVER_NAME ": " \
+ fmt, ## args); \
+ } while (0)
+
+/* SECTION: Prototypes */
+
+/* Communication with user-space */
+static unsigned int lirc_poll(struct file *file, poll_table *wait);
+static ssize_t lirc_read(struct file *file, char *buf, size_t count,
+ loff_t *ppos);
+static ssize_t lirc_write(struct file *file, const char *buf, size_t n,
+ loff_t *pos);
+static long lirc_ioctl(struct file *filep, unsigned int cmd, unsigned long arg);
+static void add_read_queue(int flag, unsigned long val);
+static int init_chrdev(void);
+static void drop_chrdev(void);
+/* Hardware */
+static irqreturn_t sir_interrupt(int irq, void *dev_id);
+static void send_space(unsigned long len);
+static void send_pulse(unsigned long len);
+static int init_hardware(void);
+static void drop_hardware(void);
+/* Initialisation */
+static int init_port(void);
+static void drop_port(void);
+
+#ifdef LIRC_ON_SA1100
+static void on(void)
+{
+ PPSR |= PPC_TXD2;
+}
+
+static void off(void)
+{
+ PPSR &= ~PPC_TXD2;
+}
+#else
+static inline unsigned int sinp(int offset)
+{
+ return inb(io + offset);
+}
+
+static inline void soutp(int offset, int value)
+{
+ outb(value, io + offset);
+}
+#endif
+
+#ifndef MAX_UDELAY_MS
+#define MAX_UDELAY_US 5000
+#else
+#define MAX_UDELAY_US (MAX_UDELAY_MS*1000)
+#endif
+
+static void safe_udelay(unsigned long usecs)
+{
+ while (usecs > MAX_UDELAY_US) {
+ udelay(MAX_UDELAY_US);
+ usecs -= MAX_UDELAY_US;
+ }
+ udelay(usecs);
+}
+
+/* SECTION: Communication with user-space */
+
+static unsigned int lirc_poll(struct file *file, poll_table *wait)
+{
+ poll_wait(file, &lirc_read_queue, wait);
+ if (rx_head != rx_tail)
+ return POLLIN | POLLRDNORM;
+ return 0;
+}
+
+static ssize_t lirc_read(struct file *file, char *buf, size_t count,
+ loff_t *ppos)
+{
+ int n = 0;
+ int retval = 0;
+ DECLARE_WAITQUEUE(wait, current);
+
+ if (count % sizeof(int))
+ return -EINVAL;
+
+ add_wait_queue(&lirc_read_queue, &wait);
+ set_current_state(TASK_INTERRUPTIBLE);
+ while (n < count) {
+ if (rx_head != rx_tail) {
+ if (copy_to_user((void *) buf + n,
+ (void *) (rx_buf + rx_head),
+ sizeof(int))) {
+ retval = -EFAULT;
+ break;
+ }
+ rx_head = (rx_head + 1) & (RBUF_LEN - 1);
+ n += sizeof(int);
+ } else {
+ if (file->f_flags & O_NONBLOCK) {
+ retval = -EAGAIN;
+ break;
+ }
+ if (signal_pending(current)) {
+ retval = -ERESTARTSYS;
+ break;
+ }
+ schedule();
+ set_current_state(TASK_INTERRUPTIBLE);
+ }
+ }
+ remove_wait_queue(&lirc_read_queue, &wait);
+ set_current_state(TASK_RUNNING);
+ return n ? n : retval;
+}
+static ssize_t lirc_write(struct file *file, const char *buf, size_t n,
+ loff_t *pos)
+{
+ unsigned long flags;
+ int i, count;
+ int *tx_buf;
+
+ count = n / sizeof(int);
+ if (n % sizeof(int) || count % 2 == 0)
+ return -EINVAL;
+ tx_buf = memdup_user(buf, n);
+ if (IS_ERR(tx_buf))
+ return PTR_ERR(tx_buf);
+ i = 0;
+#ifdef LIRC_ON_SA1100
+ /* disable receiver */
+ Ser2UTCR3 = 0;
+#endif
+ local_irq_save(flags);
+ while (1) {
+ if (i >= count)
+ break;
+ if (tx_buf[i])
+ send_pulse(tx_buf[i]);
+ i++;
+ if (i >= count)
+ break;
+ if (tx_buf[i])
+ send_space(tx_buf[i]);
+ i++;
+ }
+ local_irq_restore(flags);
+#ifdef LIRC_ON_SA1100
+ off();
+ udelay(1000); /* wait 1ms for IR diode to recover */
+ Ser2UTCR3 = 0;
+ /* clear status register to prevent unwanted interrupts */
+ Ser2UTSR0 &= (UTSR0_RID | UTSR0_RBB | UTSR0_REB);
+ /* enable receiver */
+ Ser2UTCR3 = UTCR3_RXE|UTCR3_RIE;
+#endif
+ return count;
+}
+
+static long lirc_ioctl(struct file *filep, unsigned int cmd, unsigned long arg)
+{
+ int retval = 0;
+ unsigned long value = 0;
+#ifdef LIRC_ON_SA1100
+ unsigned int ivalue;
+
+ if (cmd == LIRC_GET_FEATURES)
+ value = LIRC_CAN_SEND_PULSE |
+ LIRC_CAN_SET_SEND_DUTY_CYCLE |
+ LIRC_CAN_SET_SEND_CARRIER |
+ LIRC_CAN_REC_MODE2;
+ else if (cmd == LIRC_GET_SEND_MODE)
+ value = LIRC_MODE_PULSE;
+ else if (cmd == LIRC_GET_REC_MODE)
+ value = LIRC_MODE_MODE2;
+#else
+ if (cmd == LIRC_GET_FEATURES)
+ value = LIRC_CAN_SEND_PULSE | LIRC_CAN_REC_MODE2;
+ else if (cmd == LIRC_GET_SEND_MODE)
+ value = LIRC_MODE_PULSE;
+ else if (cmd == LIRC_GET_REC_MODE)
+ value = LIRC_MODE_MODE2;
+#endif
+
+ switch (cmd) {
+ case LIRC_GET_FEATURES:
+ case LIRC_GET_SEND_MODE:
+ case LIRC_GET_REC_MODE:
+ retval = put_user(value, (unsigned long *) arg);
+ break;
+
+ case LIRC_SET_SEND_MODE:
+ case LIRC_SET_REC_MODE:
+ retval = get_user(value, (unsigned long *) arg);
+ break;
+#ifdef LIRC_ON_SA1100
+ case LIRC_SET_SEND_DUTY_CYCLE:
+ retval = get_user(ivalue, (unsigned int *) arg);
+ if (retval)
+ return retval;
+ if (ivalue <= 0 || ivalue > 100)
+ return -EINVAL;
+ /* (ivalue/100)*(1000000/freq) */
+ duty_cycle = ivalue;
+ pulse_width = (unsigned long) duty_cycle*10000/freq;
+ space_width = (unsigned long) 1000000L/freq-pulse_width;
+ if (pulse_width >= LIRC_ON_SA1100_TRANSMITTER_LATENCY)
+ pulse_width -= LIRC_ON_SA1100_TRANSMITTER_LATENCY;
+ if (space_width >= LIRC_ON_SA1100_TRANSMITTER_LATENCY)
+ space_width -= LIRC_ON_SA1100_TRANSMITTER_LATENCY;
+ break;
+ case LIRC_SET_SEND_CARRIER:
+ retval = get_user(ivalue, (unsigned int *) arg);
+ if (retval)
+ return retval;
+ if (ivalue > 500000 || ivalue < 20000)
+ return -EINVAL;
+ freq = ivalue;
+ pulse_width = (unsigned long) duty_cycle*10000/freq;
+ space_width = (unsigned long) 1000000L/freq-pulse_width;
+ if (pulse_width >= LIRC_ON_SA1100_TRANSMITTER_LATENCY)
+ pulse_width -= LIRC_ON_SA1100_TRANSMITTER_LATENCY;
+ if (space_width >= LIRC_ON_SA1100_TRANSMITTER_LATENCY)
+ space_width -= LIRC_ON_SA1100_TRANSMITTER_LATENCY;
+ break;
+#endif
+ default:
+ retval = -ENOIOCTLCMD;
+
+ }
+
+ if (retval)
+ return retval;
+ if (cmd == LIRC_SET_REC_MODE) {
+ if (value != LIRC_MODE_MODE2)
+ retval = -ENOSYS;
+ } else if (cmd == LIRC_SET_SEND_MODE) {
+ if (value != LIRC_MODE_PULSE)
+ retval = -ENOSYS;
+ }
+
+ return retval;
+}
+
+static void add_read_queue(int flag, unsigned long val)
+{
+ unsigned int new_rx_tail;
+ int newval;
+
+ dprintk("add flag %d with val %lu\n", flag, val);
+
+ newval = val & PULSE_MASK;
+
+ /*
+ * statistically, pulses are ~TIME_CONST/2 too long. we could
+ * maybe make this more exact, but this is good enough
+ */
+ if (flag) {
+ /* pulse */
+ if (newval > TIME_CONST/2)
+ newval -= TIME_CONST/2;
+ else /* should not ever happen */
+ newval = 1;
+ newval |= PULSE_BIT;
+ } else {
+ newval += TIME_CONST/2;
+ }
+ new_rx_tail = (rx_tail + 1) & (RBUF_LEN - 1);
+ if (new_rx_tail == rx_head) {
+ dprintk("Buffer overrun.\n");
+ return;
+ }
+ rx_buf[rx_tail] = newval;
+ rx_tail = new_rx_tail;
+ wake_up_interruptible(&lirc_read_queue);
+}
+
+static const struct file_operations lirc_fops = {
+ .owner = THIS_MODULE,
+ .read = lirc_read,
+ .write = lirc_write,
+ .poll = lirc_poll,
+ .unlocked_ioctl = lirc_ioctl,
+ .open = lirc_dev_fop_open,
+ .release = lirc_dev_fop_close,
+};
+
+static int set_use_inc(void *data)
+{
+ return 0;
+}
+
+static void set_use_dec(void *data)
+{
+}
+
+static struct lirc_driver driver = {
+ .name = LIRC_DRIVER_NAME,
+ .minor = -1,
+ .code_length = 1,
+ .sample_rate = 0,
+ .data = NULL,
+ .add_to_buf = NULL,
+ .set_use_inc = set_use_inc,
+ .set_use_dec = set_use_dec,
+ .fops = &lirc_fops,
+ .dev = NULL,
+ .owner = THIS_MODULE,
+};
+
+
+static int init_chrdev(void)
+{
+ driver.minor = lirc_register_driver(&driver);
+ if (driver.minor < 0) {
+ printk(KERN_ERR LIRC_DRIVER_NAME ": init_chrdev() failed.\n");
+ return -EIO;
+ }
+ return 0;
+}
+
+static void drop_chrdev(void)
+{
+ lirc_unregister_driver(driver.minor);
+}
+
+/* SECTION: Hardware */
+static long delta(struct timeval *tv1, struct timeval *tv2)
+{
+ unsigned long deltv;
+
+ deltv = tv2->tv_sec - tv1->tv_sec;
+ if (deltv > 15)
+ deltv = 0xFFFFFF;
+ else
+ deltv = deltv*1000000 +
+ tv2->tv_usec -
+ tv1->tv_usec;
+ return deltv;
+}
+
+static void sir_timeout(unsigned long data)
+{
+ /*
+ * if last received signal was a pulse, but receiving stopped
+ * within the 9 bit frame, we need to finish this pulse and
+ * simulate a signal change to from pulse to space. Otherwise
+ * upper layers will receive two sequences next time.
+ */
+
+ unsigned long flags;
+ unsigned long pulse_end;
+
+ /* avoid interference with interrupt */
+ spin_lock_irqsave(&timer_lock, flags);
+ if (last_value) {
+#ifndef LIRC_ON_SA1100
+ /* clear unread bits in UART and restart */
+ outb(UART_FCR_CLEAR_RCVR, io + UART_FCR);
+#endif
+ /* determine 'virtual' pulse end: */
+ pulse_end = delta(&last_tv, &last_intr_tv);
+ dprintk("timeout add %d for %lu usec\n", last_value, pulse_end);
+ add_read_queue(last_value, pulse_end);
+ last_value = 0;
+ last_tv = last_intr_tv;
+ }
+ spin_unlock_irqrestore(&timer_lock, flags);
+}
+
+static irqreturn_t sir_interrupt(int irq, void *dev_id)
+{
+ unsigned char data;
+ struct timeval curr_tv;
+ static unsigned long deltv;
+#ifdef LIRC_ON_SA1100
+ int status;
+ static int n;
+
+ status = Ser2UTSR0;
+ /*
+ * Deal with any receive errors first. The bytes in error may be
+ * the only bytes in the receive FIFO, so we do this first.
+ */
+ while (status & UTSR0_EIF) {
+ int bstat;
+
+ if (debug) {
+ dprintk("EIF\n");
+ bstat = Ser2UTSR1;
+
+ if (bstat & UTSR1_FRE)
+ dprintk("frame error\n");
+ if (bstat & UTSR1_ROR)
+ dprintk("receive fifo overrun\n");
+ if (bstat & UTSR1_PRE)
+ dprintk("parity error\n");
+ }
+
+ bstat = Ser2UTDR;
+ n++;
+ status = Ser2UTSR0;
+ }
+
+ if (status & (UTSR0_RFS | UTSR0_RID)) {
+ do_gettimeofday(&curr_tv);
+ deltv = delta(&last_tv, &curr_tv);
+ do {
+ data = Ser2UTDR;
+ dprintk("%d data: %u\n", n, (unsigned int) data);
+ n++;
+ } while (status & UTSR0_RID && /* do not empty fifo in order to
+ * get UTSR0_RID in any case */
+ Ser2UTSR1 & UTSR1_RNE); /* data ready */
+
+ if (status&UTSR0_RID) {
+ add_read_queue(0 , deltv - n * TIME_CONST); /*space*/
+ add_read_queue(1, n * TIME_CONST); /*pulse*/
+ n = 0;
+ last_tv = curr_tv;
+ }
+ }
+
+ if (status & UTSR0_TFS)
+ printk(KERN_ERR "transmit fifo not full, shouldn't happen\n");
+
+ /* We must clear certain bits. */
+ status &= (UTSR0_RID | UTSR0_RBB | UTSR0_REB);
+ if (status)
+ Ser2UTSR0 = status;
+#else
+ unsigned long deltintrtv;
+ unsigned long flags;
+ int iir, lsr;
+
+ while ((iir = inb(io + UART_IIR) & UART_IIR_ID)) {
+ switch (iir&UART_IIR_ID) { /* FIXME toto treba preriedit */
+ case UART_IIR_MSI:
+ (void) inb(io + UART_MSR);
+ break;
+ case UART_IIR_RLSI:
+ (void) inb(io + UART_LSR);
+ break;
+ case UART_IIR_THRI:
+#if 0
+ if (lsr & UART_LSR_THRE) /* FIFO is empty */
+ outb(data, io + UART_TX)
+#endif
+ break;
+ case UART_IIR_RDI:
+ /* avoid interference with timer */
+ spin_lock_irqsave(&timer_lock, flags);
+ do {
+ del_timer(&timerlist);
+ data = inb(io + UART_RX);
+ do_gettimeofday(&curr_tv);
+ deltv = delta(&last_tv, &curr_tv);
+ deltintrtv = delta(&last_intr_tv, &curr_tv);
+ dprintk("t %lu, d %d\n", deltintrtv, (int)data);
+ /*
+ * if nothing came in last X cycles,
+ * it was gap
+ */
+ if (deltintrtv > TIME_CONST * threshold) {
+ if (last_value) {
+ dprintk("GAP\n");
+ /* simulate signal change */
+ add_read_queue(last_value,
+ deltv -
+ deltintrtv);
+ last_value = 0;
+ last_tv.tv_sec =
+ last_intr_tv.tv_sec;
+ last_tv.tv_usec =
+ last_intr_tv.tv_usec;
+ deltv = deltintrtv;
+ }
+ }
+ data = 1;
+ if (data ^ last_value) {
+ /*
+ * deltintrtv > 2*TIME_CONST, remember?
+ * the other case is timeout
+ */
+ add_read_queue(last_value,
+ deltv-TIME_CONST);
+ last_value = data;
+ last_tv = curr_tv;
+ if (last_tv.tv_usec >= TIME_CONST) {
+ last_tv.tv_usec -= TIME_CONST;
+ } else {
+ last_tv.tv_sec--;
+ last_tv.tv_usec += 1000000 -
+ TIME_CONST;
+ }
+ }
+ last_intr_tv = curr_tv;
+ if (data) {
+ /*
+ * start timer for end of
+ * sequence detection
+ */
+ timerlist.expires = jiffies +
+ SIR_TIMEOUT;
+ add_timer(&timerlist);
+ }
+
+ lsr = inb(io + UART_LSR);
+ } while (lsr & UART_LSR_DR); /* data ready */
+ spin_unlock_irqrestore(&timer_lock, flags);
+ break;
+ default:
+ break;
+ }
+ }
+#endif
+ return IRQ_RETVAL(IRQ_HANDLED);
+}
+
+#ifdef LIRC_ON_SA1100
+static void send_pulse(unsigned long length)
+{
+ unsigned long k, delay;
+ int flag;
+
+ if (length == 0)
+ return;
+ /*
+ * this won't give us the carrier frequency we really want
+ * due to integer arithmetic, but we can accept this inaccuracy
+ */
+
+ for (k = flag = 0; k < length; k += delay, flag = !flag) {
+ if (flag) {
+ off();
+ delay = space_width;
+ } else {
+ on();
+ delay = pulse_width;
+ }
+ safe_udelay(delay);
+ }
+ off();
+}
+
+static void send_space(unsigned long length)
+{
+ if (length == 0)
+ return;
+ off();
+ safe_udelay(length);
+}
+#else
+static void send_space(unsigned long len)
+{
+ safe_udelay(len);
+}
+
+static void send_pulse(unsigned long len)
+{
+ long bytes_out = len / TIME_CONST;
+ long time_left;
+
+ time_left = (long)len - (long)bytes_out * (long)TIME_CONST;
+ if (bytes_out == 0) {
+ bytes_out++;
+ time_left = 0;
+ }
+ while (bytes_out--) {
+ outb(PULSE, io + UART_TX);
+ /* FIXME treba seriozne cakanie z char/serial.c */
+ while (!(inb(io + UART_LSR) & UART_LSR_THRE))
+ ;
+ }
+#if 0
+ if (time_left > 0)
+ safe_udelay(time_left);
+#endif
+}
+#endif
+
+#ifdef CONFIG_SA1100_COLLIE
+static int sa1100_irda_set_power_collie(int state)
+{
+ if (state) {
+ /*
+ * 0 - off
+ * 1 - short range, lowest power
+ * 2 - medium range, medium power
+ * 3 - maximum range, high power
+ */
+ ucb1200_set_io_direction(TC35143_GPIO_IR_ON,
+ TC35143_IODIR_OUTPUT);
+ ucb1200_set_io(TC35143_GPIO_IR_ON, TC35143_IODAT_LOW);
+ udelay(100);
+ } else {
+ /* OFF */
+ ucb1200_set_io_direction(TC35143_GPIO_IR_ON,
+ TC35143_IODIR_OUTPUT);
+ ucb1200_set_io(TC35143_GPIO_IR_ON, TC35143_IODAT_HIGH);
+ }
+ return 0;
+}
+#endif
+
+static int init_hardware(void)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&hardware_lock, flags);
+ /* reset UART */
+#ifdef LIRC_ON_SA1100
+#ifdef CONFIG_SA1100_BITSY
+ if (machine_is_bitsy()) {
+ printk(KERN_INFO "Power on IR module\n");
+ set_bitsy_egpio(EGPIO_BITSY_IR_ON);
+ }
+#endif
+#ifdef CONFIG_SA1100_COLLIE
+ sa1100_irda_set_power_collie(3); /* power on */
+#endif
+ sr.hscr0 = Ser2HSCR0;
+
+ sr.utcr0 = Ser2UTCR0;
+ sr.utcr1 = Ser2UTCR1;
+ sr.utcr2 = Ser2UTCR2;
+ sr.utcr3 = Ser2UTCR3;
+ sr.utcr4 = Ser2UTCR4;
+
+ sr.utdr = Ser2UTDR;
+ sr.utsr0 = Ser2UTSR0;
+ sr.utsr1 = Ser2UTSR1;
+
+ /* configure GPIO */
+ /* output */
+ PPDR |= PPC_TXD2;
+ PSDR |= PPC_TXD2;
+ /* set output to 0 */
+ off();
+
+ /* Enable HP-SIR modulation, and ensure that the port is disabled. */
+ Ser2UTCR3 = 0;
+ Ser2HSCR0 = sr.hscr0 & (~HSCR0_HSSP);
+
+ /* clear status register to prevent unwanted interrupts */
+ Ser2UTSR0 &= (UTSR0_RID | UTSR0_RBB | UTSR0_REB);
+
+ /* 7N1 */
+ Ser2UTCR0 = UTCR0_1StpBit|UTCR0_7BitData;
+ /* 115200 */
+ Ser2UTCR1 = 0;
+ Ser2UTCR2 = 1;
+ /* use HPSIR, 1.6 usec pulses */
+ Ser2UTCR4 = UTCR4_HPSIR|UTCR4_Z1_6us;
+
+ /* enable receiver, receive fifo interrupt */
+ Ser2UTCR3 = UTCR3_RXE|UTCR3_RIE;
+
+ /* clear status register to prevent unwanted interrupts */
+ Ser2UTSR0 &= (UTSR0_RID | UTSR0_RBB | UTSR0_REB);
+
+#elif defined(LIRC_SIR_TEKRAM)
+ /* disable FIFO */
+ soutp(UART_FCR,
+ UART_FCR_CLEAR_RCVR|
+ UART_FCR_CLEAR_XMIT|
+ UART_FCR_TRIGGER_1);
+
+ /* Set DLAB 0. */
+ soutp(UART_LCR, sinp(UART_LCR) & (~UART_LCR_DLAB));
+
+ /* First of all, disable all interrupts */
+ soutp(UART_IER, sinp(UART_IER) &
+ (~(UART_IER_MSI|UART_IER_RLSI|UART_IER_THRI|UART_IER_RDI)));
+
+ /* Set DLAB 1. */
+ soutp(UART_LCR, sinp(UART_LCR) | UART_LCR_DLAB);
+
+ /* Set divisor to 12 => 9600 Baud */
+ soutp(UART_DLM, 0);
+ soutp(UART_DLL, 12);
+
+ /* Set DLAB 0. */
+ soutp(UART_LCR, sinp(UART_LCR) & (~UART_LCR_DLAB));
+
+ /* power supply */
+ soutp(UART_MCR, UART_MCR_RTS|UART_MCR_DTR|UART_MCR_OUT2);
+ safe_udelay(50*1000);
+
+ /* -DTR low -> reset PIC */
+ soutp(UART_MCR, UART_MCR_RTS|UART_MCR_OUT2);
+ udelay(1*1000);
+
+ soutp(UART_MCR, UART_MCR_RTS|UART_MCR_DTR|UART_MCR_OUT2);
+ udelay(100);
+
+
+ /* -RTS low -> send control byte */
+ soutp(UART_MCR, UART_MCR_DTR|UART_MCR_OUT2);
+ udelay(7);
+ soutp(UART_TX, TEKRAM_115200|TEKRAM_PW);
+
+ /* one byte takes ~1042 usec to transmit at 9600,8N1 */
+ udelay(1500);
+
+ /* back to normal operation */
+ soutp(UART_MCR, UART_MCR_RTS|UART_MCR_DTR|UART_MCR_OUT2);
+ udelay(50);
+
+ udelay(1500);
+
+ /* read previous control byte */
+ printk(KERN_INFO LIRC_DRIVER_NAME
+ ": 0x%02x\n", sinp(UART_RX));
+
+ /* Set DLAB 1. */
+ soutp(UART_LCR, sinp(UART_LCR) | UART_LCR_DLAB);
+
+ /* Set divisor to 1 => 115200 Baud */
+ soutp(UART_DLM, 0);
+ soutp(UART_DLL, 1);
+
+ /* Set DLAB 0, 8 Bit */
+ soutp(UART_LCR, UART_LCR_WLEN8);
+ /* enable interrupts */
+ soutp(UART_IER, sinp(UART_IER)|UART_IER_RDI);
+#else
+ outb(0, io + UART_MCR);
+ outb(0, io + UART_IER);
+ /* init UART */
+ /* set DLAB, speed = 115200 */
+ outb(UART_LCR_DLAB | UART_LCR_WLEN7, io + UART_LCR);
+ outb(1, io + UART_DLL); outb(0, io + UART_DLM);
+ /* 7N1+start = 9 bits at 115200 ~ 3 bits at 44000 */
+ outb(UART_LCR_WLEN7, io + UART_LCR);
+ /* FIFO operation */
+ outb(UART_FCR_ENABLE_FIFO, io + UART_FCR);
+ /* interrupts */
+ /* outb(UART_IER_RLSI|UART_IER_RDI|UART_IER_THRI, io + UART_IER); */
+ outb(UART_IER_RDI, io + UART_IER);
+ /* turn on UART */
+ outb(UART_MCR_DTR|UART_MCR_RTS|UART_MCR_OUT2, io + UART_MCR);
+#ifdef LIRC_SIR_ACTISYS_ACT200L
+ init_act200();
+#elif defined(LIRC_SIR_ACTISYS_ACT220L)
+ init_act220();
+#endif
+#endif
+ spin_unlock_irqrestore(&hardware_lock, flags);
+ return 0;
+}
+
+static void drop_hardware(void)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&hardware_lock, flags);
+
+#ifdef LIRC_ON_SA1100
+ Ser2UTCR3 = 0;
+
+ Ser2UTCR0 = sr.utcr0;
+ Ser2UTCR1 = sr.utcr1;
+ Ser2UTCR2 = sr.utcr2;
+ Ser2UTCR4 = sr.utcr4;
+ Ser2UTCR3 = sr.utcr3;
+
+ Ser2HSCR0 = sr.hscr0;
+#ifdef CONFIG_SA1100_BITSY
+ if (machine_is_bitsy())
+ clr_bitsy_egpio(EGPIO_BITSY_IR_ON);
+#endif
+#ifdef CONFIG_SA1100_COLLIE
+ sa1100_irda_set_power_collie(0); /* power off */
+#endif
+#else
+ /* turn off interrupts */
+ outb(0, io + UART_IER);
+#endif
+ spin_unlock_irqrestore(&hardware_lock, flags);
+}
+
+/* SECTION: Initialisation */
+
+static int init_port(void)
+{
+ int retval;
+
+ /* get I/O port access and IRQ line */
+#ifndef LIRC_ON_SA1100
+ if (request_region(io, 8, LIRC_DRIVER_NAME) == NULL) {
+ printk(KERN_ERR LIRC_DRIVER_NAME
+ ": i/o port 0x%.4x already in use.\n", io);
+ return -EBUSY;
+ }
+#endif
+ retval = request_irq(irq, sir_interrupt, IRQF_DISABLED,
+ LIRC_DRIVER_NAME, NULL);
+ if (retval < 0) {
+# ifndef LIRC_ON_SA1100
+ release_region(io, 8);
+# endif
+ printk(KERN_ERR LIRC_DRIVER_NAME
+ ": IRQ %d already in use.\n",
+ irq);
+ return retval;
+ }
+#ifndef LIRC_ON_SA1100
+ printk(KERN_INFO LIRC_DRIVER_NAME
+ ": I/O port 0x%.4x, IRQ %d.\n",
+ io, irq);
+#endif
+
+ init_timer(&timerlist);
+ timerlist.function = sir_timeout;
+ timerlist.data = 0xabadcafe;
+
+ return 0;
+}
+
+static void drop_port(void)
+{
+ free_irq(irq, NULL);
+ del_timer_sync(&timerlist);
+#ifndef LIRC_ON_SA1100
+ release_region(io, 8);
+#endif
+}
+
+#ifdef LIRC_SIR_ACTISYS_ACT200L
+/* Crystal/Cirrus CS8130 IR transceiver, used in Actisys Act200L dongle */
+/* some code borrowed from Linux IRDA driver */
+
+/* Register 0: Control register #1 */
+#define ACT200L_REG0 0x00
+#define ACT200L_TXEN 0x01 /* Enable transmitter */
+#define ACT200L_RXEN 0x02 /* Enable receiver */
+#define ACT200L_ECHO 0x08 /* Echo control chars */
+
+/* Register 1: Control register #2 */
+#define ACT200L_REG1 0x10
+#define ACT200L_LODB 0x01 /* Load new baud rate count value */
+#define ACT200L_WIDE 0x04 /* Expand the maximum allowable pulse */
+
+/* Register 3: Transmit mode register #2 */
+#define ACT200L_REG3 0x30
+#define ACT200L_B0 0x01 /* DataBits, 0=6, 1=7, 2=8, 3=9(8P) */
+#define ACT200L_B1 0x02 /* DataBits, 0=6, 1=7, 2=8, 3=9(8P) */
+#define ACT200L_CHSY 0x04 /* StartBit Synced 0=bittime, 1=startbit */
+
+/* Register 4: Output Power register */
+#define ACT200L_REG4 0x40
+#define ACT200L_OP0 0x01 /* Enable LED1C output */
+#define ACT200L_OP1 0x02 /* Enable LED2C output */
+#define ACT200L_BLKR 0x04
+
+/* Register 5: Receive Mode register */
+#define ACT200L_REG5 0x50
+#define ACT200L_RWIDL 0x01 /* fixed 1.6us pulse mode */
+ /*.. other various IRDA bit modes, and TV remote modes..*/
+
+/* Register 6: Receive Sensitivity register #1 */
+#define ACT200L_REG6 0x60
+#define ACT200L_RS0 0x01 /* receive threshold bit 0 */
+#define ACT200L_RS1 0x02 /* receive threshold bit 1 */
+
+/* Register 7: Receive Sensitivity register #2 */
+#define ACT200L_REG7 0x70
+#define ACT200L_ENPOS 0x04 /* Ignore the falling edge */
+
+/* Register 8,9: Baud Rate Divider register #1,#2 */
+#define ACT200L_REG8 0x80
+#define ACT200L_REG9 0x90
+
+#define ACT200L_2400 0x5f
+#define ACT200L_9600 0x17
+#define ACT200L_19200 0x0b
+#define ACT200L_38400 0x05
+#define ACT200L_57600 0x03
+#define ACT200L_115200 0x01
+
+/* Register 13: Control register #3 */
+#define ACT200L_REG13 0xd0
+#define ACT200L_SHDW 0x01 /* Enable access to shadow registers */
+
+/* Register 15: Status register */
+#define ACT200L_REG15 0xf0
+
+/* Register 21: Control register #4 */
+#define ACT200L_REG21 0x50
+#define ACT200L_EXCK 0x02 /* Disable clock output driver */
+#define ACT200L_OSCL 0x04 /* oscillator in low power, medium accuracy mode */
+
+static void init_act200(void)
+{
+ int i;
+ __u8 control[] = {
+ ACT200L_REG15,
+ ACT200L_REG13 | ACT200L_SHDW,
+ ACT200L_REG21 | ACT200L_EXCK | ACT200L_OSCL,
+ ACT200L_REG13,
+ ACT200L_REG7 | ACT200L_ENPOS,
+ ACT200L_REG6 | ACT200L_RS0 | ACT200L_RS1,
+ ACT200L_REG5 | ACT200L_RWIDL,
+ ACT200L_REG4 | ACT200L_OP0 | ACT200L_OP1 | ACT200L_BLKR,
+ ACT200L_REG3 | ACT200L_B0,
+ ACT200L_REG0 | ACT200L_TXEN | ACT200L_RXEN,
+ ACT200L_REG8 | (ACT200L_115200 & 0x0f),
+ ACT200L_REG9 | ((ACT200L_115200 >> 4) & 0x0f),
+ ACT200L_REG1 | ACT200L_LODB | ACT200L_WIDE
+ };
+
+ /* Set DLAB 1. */
+ soutp(UART_LCR, UART_LCR_DLAB | UART_LCR_WLEN8);
+
+ /* Set divisor to 12 => 9600 Baud */
+ soutp(UART_DLM, 0);
+ soutp(UART_DLL, 12);
+
+ /* Set DLAB 0. */
+ soutp(UART_LCR, UART_LCR_WLEN8);
+ /* Set divisor to 12 => 9600 Baud */
+
+ /* power supply */
+ soutp(UART_MCR, UART_MCR_RTS|UART_MCR_DTR|UART_MCR_OUT2);
+ for (i = 0; i < 50; i++)
+ safe_udelay(1000);
+
+ /* Reset the dongle : set RTS low for 25 ms */
+ soutp(UART_MCR, UART_MCR_DTR|UART_MCR_OUT2);
+ for (i = 0; i < 25; i++)
+ udelay(1000);
+
+ soutp(UART_MCR, UART_MCR_RTS|UART_MCR_DTR|UART_MCR_OUT2);
+ udelay(100);
+
+ /* Clear DTR and set RTS to enter command mode */
+ soutp(UART_MCR, UART_MCR_RTS|UART_MCR_OUT2);
+ udelay(7);
+
+ /* send out the control register settings for 115K 7N1 SIR operation */
+ for (i = 0; i < sizeof(control); i++) {
+ soutp(UART_TX, control[i]);
+ /* one byte takes ~1042 usec to transmit at 9600,8N1 */
+ udelay(1500);
+ }
+
+ /* back to normal operation */
+ soutp(UART_MCR, UART_MCR_RTS|UART_MCR_DTR|UART_MCR_OUT2);
+ udelay(50);
+
+ udelay(1500);
+ soutp(UART_LCR, sinp(UART_LCR) | UART_LCR_DLAB);
+
+ /* Set DLAB 1. */
+ soutp(UART_LCR, UART_LCR_DLAB | UART_LCR_WLEN7);
+
+ /* Set divisor to 1 => 115200 Baud */
+ soutp(UART_DLM, 0);
+ soutp(UART_DLL, 1);
+
+ /* Set DLAB 0. */
+ soutp(UART_LCR, sinp(UART_LCR) & (~UART_LCR_DLAB));
+
+ /* Set DLAB 0, 7 Bit */
+ soutp(UART_LCR, UART_LCR_WLEN7);
+
+ /* enable interrupts */
+ soutp(UART_IER, sinp(UART_IER)|UART_IER_RDI);
+}
+#endif
+
+#ifdef LIRC_SIR_ACTISYS_ACT220L
+/*
+ * Derived from linux IrDA driver (net/irda/actisys.c)
+ * Drop me a mail for any kind of comment: maxx@spaceboyz.net
+ */
+
+void init_act220(void)
+{
+ int i;
+
+ /* DLAB 1 */
+ soutp(UART_LCR, UART_LCR_DLAB|UART_LCR_WLEN7);
+
+ /* 9600 baud */
+ soutp(UART_DLM, 0);
+ soutp(UART_DLL, 12);
+
+ /* DLAB 0 */
+ soutp(UART_LCR, UART_LCR_WLEN7);
+
+ /* reset the dongle, set DTR low for 10us */
+ soutp(UART_MCR, UART_MCR_RTS|UART_MCR_OUT2);
+ udelay(10);
+
+ /* back to normal (still 9600) */
+ soutp(UART_MCR, UART_MCR_DTR|UART_MCR_RTS|UART_MCR_OUT2);
+
+ /*
+ * send RTS pulses until we reach 115200
+ * i hope this is really the same for act220l/act220l+
+ */
+ for (i = 0; i < 3; i++) {
+ udelay(10);
+ /* set RTS low for 10 us */
+ soutp(UART_MCR, UART_MCR_DTR|UART_MCR_OUT2);
+ udelay(10);
+ /* set RTS high for 10 us */
+ soutp(UART_MCR, UART_MCR_RTS|UART_MCR_DTR|UART_MCR_OUT2);
+ }
+
+ /* back to normal operation */
+ udelay(1500); /* better safe than sorry ;) */
+
+ /* Set DLAB 1. */
+ soutp(UART_LCR, UART_LCR_DLAB | UART_LCR_WLEN7);
+
+ /* Set divisor to 1 => 115200 Baud */
+ soutp(UART_DLM, 0);
+ soutp(UART_DLL, 1);
+
+ /* Set DLAB 0, 7 Bit */
+ /* The dongle doesn't seem to have any problems with operation at 7N1 */
+ soutp(UART_LCR, UART_LCR_WLEN7);
+
+ /* enable interrupts */
+ soutp(UART_IER, UART_IER_RDI);
+}
+#endif
+
+static int init_lirc_sir(void)
+{
+ int retval;
+
+ init_waitqueue_head(&lirc_read_queue);
+ retval = init_port();
+ if (retval < 0)
+ return retval;
+ init_hardware();
+ printk(KERN_INFO LIRC_DRIVER_NAME
+ ": Installed.\n");
+ return 0;
+}
+
+
+static int __init lirc_sir_init(void)
+{
+ int retval;
+
+ retval = init_chrdev();
+ if (retval < 0)
+ return retval;
+ retval = init_lirc_sir();
+ if (retval) {
+ drop_chrdev();
+ return retval;
+ }
+ return 0;
+}
+
+static void __exit lirc_sir_exit(void)
+{
+ drop_hardware();
+ drop_chrdev();
+ drop_port();
+ printk(KERN_INFO LIRC_DRIVER_NAME ": Uninstalled.\n");
+}
+
+module_init(lirc_sir_init);
+module_exit(lirc_sir_exit);
+
+#ifdef LIRC_SIR_TEKRAM
+MODULE_DESCRIPTION("Infrared receiver driver for Tekram Irmate 210");
+MODULE_AUTHOR("Christoph Bartelmus");
+#elif defined(LIRC_ON_SA1100)
+MODULE_DESCRIPTION("LIRC driver for StrongARM SA1100 embedded microprocessor");
+MODULE_AUTHOR("Christoph Bartelmus");
+#elif defined(LIRC_SIR_ACTISYS_ACT200L)
+MODULE_DESCRIPTION("LIRC driver for Actisys Act200L");
+MODULE_AUTHOR("Karl Bongers");
+#elif defined(LIRC_SIR_ACTISYS_ACT220L)
+MODULE_DESCRIPTION("LIRC driver for Actisys Act220L(+)");
+MODULE_AUTHOR("Jan Roemisch");
+#else
+MODULE_DESCRIPTION("Infrared receiver driver for SIR type serial ports");
+MODULE_AUTHOR("Milan Pikula");
+#endif
+MODULE_LICENSE("GPL");
+
+#ifdef LIRC_ON_SA1100
+module_param(irq, int, S_IRUGO);
+MODULE_PARM_DESC(irq, "Interrupt (16)");
+#else
+module_param(io, int, S_IRUGO);
+MODULE_PARM_DESC(io, "I/O address base (0x3f8 or 0x2f8)");
+
+module_param(irq, int, S_IRUGO);
+MODULE_PARM_DESC(irq, "Interrupt (4 or 3)");
+
+module_param(threshold, int, S_IRUGO);
+MODULE_PARM_DESC(threshold, "space detection threshold (3)");
+#endif
+
+module_param(debug, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug, "Enable debugging messages");
diff --git a/drivers/staging/lirc/lirc_streamzap.c b/drivers/staging/lirc/lirc_streamzap.c
new file mode 100644
index 00000000000..be09c103f0c
--- /dev/null
+++ b/drivers/staging/lirc/lirc_streamzap.c
@@ -0,0 +1,821 @@
+/*
+ * Streamzap Remote Control driver
+ *
+ * Copyright (c) 2005 Christoph Bartelmus <lirc@bartelmus.de>
+ *
+ * This driver was based on the work of Greg Wickham and Adrian
+ * Dewhurst. It was substantially rewritten to support correct signal
+ * gaps and now maintains a delay buffer, which is used to present
+ * consistent timing behaviour to user space applications. Without the
+ * delay buffer an ugly hack would be required in lircd, which can
+ * cause sluggish signal decoding in certain situations.
+ *
+ * This driver is based on the USB skeleton driver packaged with the
+ * kernel; copyright (C) 2001-2003 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, 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/errno.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/smp_lock.h>
+#include <linux/completion.h>
+#include <linux/uaccess.h>
+#include <linux/usb.h>
+
+#include <media/lirc.h>
+#include <media/lirc_dev.h>
+
+#define DRIVER_VERSION "1.28"
+#define DRIVER_NAME "lirc_streamzap"
+#define DRIVER_DESC "Streamzap Remote Control driver"
+
+static int debug;
+
+#define USB_STREAMZAP_VENDOR_ID 0x0e9c
+#define USB_STREAMZAP_PRODUCT_ID 0x0000
+
+/* Use our own dbg macro */
+#define dprintk(fmt, args...) \
+ do { \
+ if (debug) \
+ printk(KERN_DEBUG DRIVER_NAME "[%d]: " \
+ fmt "\n", ## args); \
+ } while (0)
+
+/* table of devices that work with this driver */
+static struct usb_device_id streamzap_table[] = {
+ /* Streamzap Remote Control */
+ { USB_DEVICE(USB_STREAMZAP_VENDOR_ID, USB_STREAMZAP_PRODUCT_ID) },
+ /* Terminating entry */
+ { }
+};
+
+MODULE_DEVICE_TABLE(usb, streamzap_table);
+
+#define STREAMZAP_PULSE_MASK 0xf0
+#define STREAMZAP_SPACE_MASK 0x0f
+#define STREAMZAP_TIMEOUT 0xff
+#define STREAMZAP_RESOLUTION 256
+
+/* number of samples buffered */
+#define STREAMZAP_BUF_LEN 128
+
+enum StreamzapDecoderState {
+ PulseSpace,
+ FullPulse,
+ FullSpace,
+ IgnorePulse
+};
+
+/* Structure to hold all of our device specific stuff
+ *
+ * some remarks regarding locking:
+ * theoretically this struct can be accessed from three threads:
+ *
+ * - from lirc_dev through set_use_inc/set_use_dec
+ *
+ * - from the USB layer throuh probe/disconnect/irq
+ *
+ * Careful placement of lirc_register_driver/lirc_unregister_driver
+ * calls will prevent conflicts. lirc_dev makes sure that
+ * set_use_inc/set_use_dec are not being executed and will not be
+ * called after lirc_unregister_driver returns.
+ *
+ * - by the timer callback
+ *
+ * The timer is only running when the device is connected and the
+ * LIRC device is open. Making sure the timer is deleted by
+ * set_use_dec will make conflicts impossible.
+ */
+struct usb_streamzap {
+
+ /* usb */
+ /* save off the usb device pointer */
+ struct usb_device *udev;
+ /* the interface for this device */
+ struct usb_interface *interface;
+
+ /* buffer & dma */
+ unsigned char *buf_in;
+ dma_addr_t dma_in;
+ unsigned int buf_in_len;
+
+ struct usb_endpoint_descriptor *endpoint;
+
+ /* IRQ */
+ struct urb *urb_in;
+
+ /* lirc */
+ struct lirc_driver *driver;
+ struct lirc_buffer *delay_buf;
+
+ /* timer used to support delay buffering */
+ struct timer_list delay_timer;
+ int timer_running;
+ spinlock_t timer_lock;
+
+ /* tracks whether we are currently receiving some signal */
+ int idle;
+ /* sum of signal lengths received since signal start */
+ unsigned long sum;
+ /* start time of signal; necessary for gap tracking */
+ struct timeval signal_last;
+ struct timeval signal_start;
+ enum StreamzapDecoderState decoder_state;
+ struct timer_list flush_timer;
+ int flush;
+ int in_use;
+ int timeout_enabled;
+};
+
+
+/* local function prototypes */
+static int streamzap_probe(struct usb_interface *interface,
+ const struct usb_device_id *id);
+static void streamzap_disconnect(struct usb_interface *interface);
+static void usb_streamzap_irq(struct urb *urb);
+static int streamzap_use_inc(void *data);
+static void streamzap_use_dec(void *data);
+static long streamzap_ioctl(struct file *filep, unsigned int cmd,
+ unsigned long arg);
+static int streamzap_suspend(struct usb_interface *intf, pm_message_t message);
+static int streamzap_resume(struct usb_interface *intf);
+
+/* usb specific object needed to register this driver with the usb subsystem */
+
+static struct usb_driver streamzap_driver = {
+ .name = DRIVER_NAME,
+ .probe = streamzap_probe,
+ .disconnect = streamzap_disconnect,
+ .suspend = streamzap_suspend,
+ .resume = streamzap_resume,
+ .id_table = streamzap_table,
+};
+
+static void stop_timer(struct usb_streamzap *sz)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&sz->timer_lock, flags);
+ if (sz->timer_running) {
+ sz->timer_running = 0;
+ spin_unlock_irqrestore(&sz->timer_lock, flags);
+ del_timer_sync(&sz->delay_timer);
+ } else {
+ spin_unlock_irqrestore(&sz->timer_lock, flags);
+ }
+}
+
+static void flush_timeout(unsigned long arg)
+{
+ struct usb_streamzap *sz = (struct usb_streamzap *) arg;
+
+ /* finally start accepting data */
+ sz->flush = 0;
+}
+static void delay_timeout(unsigned long arg)
+{
+ unsigned long flags;
+ /* deliver data every 10 ms */
+ static unsigned long timer_inc =
+ (10000/(1000000/HZ)) == 0 ? 1 : (10000/(1000000/HZ));
+ struct usb_streamzap *sz = (struct usb_streamzap *) arg;
+ int data;
+
+ spin_lock_irqsave(&sz->timer_lock, flags);
+
+ if (!lirc_buffer_empty(sz->delay_buf) &&
+ !lirc_buffer_full(sz->driver->rbuf)) {
+ lirc_buffer_read(sz->delay_buf, (unsigned char *) &data);
+ lirc_buffer_write(sz->driver->rbuf, (unsigned char *) &data);
+ }
+ if (!lirc_buffer_empty(sz->delay_buf)) {
+ while (lirc_buffer_available(sz->delay_buf) <
+ STREAMZAP_BUF_LEN / 2 &&
+ !lirc_buffer_full(sz->driver->rbuf)) {
+ lirc_buffer_read(sz->delay_buf,
+ (unsigned char *) &data);
+ lirc_buffer_write(sz->driver->rbuf,
+ (unsigned char *) &data);
+ }
+ if (sz->timer_running) {
+ sz->delay_timer.expires = jiffies + timer_inc;
+ add_timer(&sz->delay_timer);
+ }
+ } else {
+ sz->timer_running = 0;
+ }
+
+ if (!lirc_buffer_empty(sz->driver->rbuf))
+ wake_up(&sz->driver->rbuf->wait_poll);
+
+ spin_unlock_irqrestore(&sz->timer_lock, flags);
+}
+
+static void flush_delay_buffer(struct usb_streamzap *sz)
+{
+ int data;
+ int empty = 1;
+
+ while (!lirc_buffer_empty(sz->delay_buf)) {
+ empty = 0;
+ lirc_buffer_read(sz->delay_buf, (unsigned char *) &data);
+ if (!lirc_buffer_full(sz->driver->rbuf)) {
+ lirc_buffer_write(sz->driver->rbuf,
+ (unsigned char *) &data);
+ } else {
+ dprintk("buffer overflow", sz->driver->minor);
+ }
+ }
+ if (!empty)
+ wake_up(&sz->driver->rbuf->wait_poll);
+}
+
+static void push(struct usb_streamzap *sz, unsigned char *data)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&sz->timer_lock, flags);
+ if (lirc_buffer_full(sz->delay_buf)) {
+ int read_data;
+
+ lirc_buffer_read(sz->delay_buf,
+ (unsigned char *) &read_data);
+ if (!lirc_buffer_full(sz->driver->rbuf)) {
+ lirc_buffer_write(sz->driver->rbuf,
+ (unsigned char *) &read_data);
+ } else {
+ dprintk("buffer overflow", sz->driver->minor);
+ }
+ }
+
+ lirc_buffer_write(sz->delay_buf, data);
+
+ if (!sz->timer_running) {
+ sz->delay_timer.expires = jiffies + HZ/10;
+ add_timer(&sz->delay_timer);
+ sz->timer_running = 1;
+ }
+
+ spin_unlock_irqrestore(&sz->timer_lock, flags);
+}
+
+static void push_full_pulse(struct usb_streamzap *sz,
+ unsigned char value)
+{
+ int pulse;
+
+ if (sz->idle) {
+ long deltv;
+ int tmp;
+
+ sz->signal_last = sz->signal_start;
+ do_gettimeofday(&sz->signal_start);
+
+ deltv = sz->signal_start.tv_sec-sz->signal_last.tv_sec;
+ if (deltv > 15) {
+ /* really long time */
+ tmp = LIRC_SPACE(LIRC_VALUE_MASK);
+ } else {
+ tmp = (int) (deltv*1000000+
+ sz->signal_start.tv_usec -
+ sz->signal_last.tv_usec);
+ tmp -= sz->sum;
+ tmp = LIRC_SPACE(tmp);
+ }
+ dprintk("ls %u", sz->driver->minor, tmp);
+ push(sz, (char *)&tmp);
+
+ sz->idle = 0;
+ sz->sum = 0;
+ }
+
+ pulse = ((int) value) * STREAMZAP_RESOLUTION;
+ pulse += STREAMZAP_RESOLUTION / 2;
+ sz->sum += pulse;
+ pulse = LIRC_PULSE(pulse);
+
+ dprintk("p %u", sz->driver->minor, pulse & PULSE_MASK);
+ push(sz, (char *)&pulse);
+}
+
+static void push_half_pulse(struct usb_streamzap *sz,
+ unsigned char value)
+{
+ push_full_pulse(sz, (value & STREAMZAP_PULSE_MASK)>>4);
+}
+
+static void push_full_space(struct usb_streamzap *sz,
+ unsigned char value)
+{
+ int space;
+
+ space = ((int) value)*STREAMZAP_RESOLUTION;
+ space += STREAMZAP_RESOLUTION/2;
+ sz->sum += space;
+ space = LIRC_SPACE(space);
+ dprintk("s %u", sz->driver->minor, space);
+ push(sz, (char *)&space);
+}
+
+static void push_half_space(struct usb_streamzap *sz,
+ unsigned char value)
+{
+ push_full_space(sz, value & STREAMZAP_SPACE_MASK);
+}
+
+/**
+ * usb_streamzap_irq - IRQ handler
+ *
+ * This procedure is invoked on reception of data from
+ * the usb remote.
+ */
+static void usb_streamzap_irq(struct urb *urb)
+{
+ struct usb_streamzap *sz;
+ int len;
+ unsigned int i = 0;
+
+ if (!urb)
+ return;
+
+ sz = urb->context;
+ len = urb->actual_length;
+
+ switch (urb->status) {
+ case -ECONNRESET:
+ case -ENOENT:
+ case -ESHUTDOWN:
+ /*
+ * this urb is terminated, clean up.
+ * sz might already be invalid at this point
+ */
+ dprintk("urb status: %d", -1, urb->status);
+ return;
+ default:
+ break;
+ }
+
+ dprintk("received %d", sz->driver->minor, urb->actual_length);
+ if (!sz->flush) {
+ for (i = 0; i < urb->actual_length; i++) {
+ dprintk("%d: %x", sz->driver->minor,
+ i, (unsigned char) sz->buf_in[i]);
+ switch (sz->decoder_state) {
+ case PulseSpace:
+ if ((sz->buf_in[i]&STREAMZAP_PULSE_MASK) ==
+ STREAMZAP_PULSE_MASK) {
+ sz->decoder_state = FullPulse;
+ continue;
+ } else if ((sz->buf_in[i]&STREAMZAP_SPACE_MASK)
+ == STREAMZAP_SPACE_MASK) {
+ push_half_pulse(sz, sz->buf_in[i]);
+ sz->decoder_state = FullSpace;
+ continue;
+ } else {
+ push_half_pulse(sz, sz->buf_in[i]);
+ push_half_space(sz, sz->buf_in[i]);
+ }
+ break;
+ case FullPulse:
+ push_full_pulse(sz, sz->buf_in[i]);
+ sz->decoder_state = IgnorePulse;
+ break;
+ case FullSpace:
+ if (sz->buf_in[i] == STREAMZAP_TIMEOUT) {
+ sz->idle = 1;
+ stop_timer(sz);
+ if (sz->timeout_enabled) {
+ int timeout =
+ LIRC_TIMEOUT
+ (STREAMZAP_TIMEOUT *
+ STREAMZAP_RESOLUTION);
+ push(sz, (char *)&timeout);
+ }
+ flush_delay_buffer(sz);
+ } else
+ push_full_space(sz, sz->buf_in[i]);
+ sz->decoder_state = PulseSpace;
+ break;
+ case IgnorePulse:
+ if ((sz->buf_in[i]&STREAMZAP_SPACE_MASK) ==
+ STREAMZAP_SPACE_MASK) {
+ sz->decoder_state = FullSpace;
+ continue;
+ }
+ push_half_space(sz, sz->buf_in[i]);
+ sz->decoder_state = PulseSpace;
+ break;
+ }
+ }
+ }
+
+ usb_submit_urb(urb, GFP_ATOMIC);
+
+ return;
+}
+
+static const struct file_operations streamzap_fops = {
+ .owner = THIS_MODULE,
+ .unlocked_ioctl = streamzap_ioctl,
+ .read = lirc_dev_fop_read,
+ .write = lirc_dev_fop_write,
+ .poll = lirc_dev_fop_poll,
+ .open = lirc_dev_fop_open,
+ .release = lirc_dev_fop_close,
+};
+
+
+/**
+ * streamzap_probe
+ *
+ * Called by usb-core to associated with a candidate device
+ * On any failure the return value is the ERROR
+ * On success return 0
+ */
+static int streamzap_probe(struct usb_interface *interface,
+ const struct usb_device_id *id)
+{
+ struct usb_device *udev = interface_to_usbdev(interface);
+ struct usb_host_interface *iface_host;
+ struct usb_streamzap *sz;
+ struct lirc_driver *driver;
+ struct lirc_buffer *lirc_buf;
+ struct lirc_buffer *delay_buf;
+ char buf[63], name[128] = "";
+ int retval = -ENOMEM;
+ int minor = 0;
+
+ /* Allocate space for device driver specific data */
+ sz = kzalloc(sizeof(struct usb_streamzap), GFP_KERNEL);
+ if (sz == NULL)
+ return -ENOMEM;
+
+ sz->udev = udev;
+ sz->interface = interface;
+
+ /* Check to ensure endpoint information matches requirements */
+ iface_host = interface->cur_altsetting;
+
+ if (iface_host->desc.bNumEndpoints != 1) {
+ err("%s: Unexpected desc.bNumEndpoints (%d)", __func__,
+ iface_host->desc.bNumEndpoints);
+ retval = -ENODEV;
+ goto free_sz;
+ }
+
+ sz->endpoint = &(iface_host->endpoint[0].desc);
+ if ((sz->endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK)
+ != USB_DIR_IN) {
+ err("%s: endpoint doesn't match input device 02%02x",
+ __func__, sz->endpoint->bEndpointAddress);
+ retval = -ENODEV;
+ goto free_sz;
+ }
+
+ if ((sz->endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
+ != USB_ENDPOINT_XFER_INT) {
+ err("%s: endpoint attributes don't match xfer 02%02x",
+ __func__, sz->endpoint->bmAttributes);
+ retval = -ENODEV;
+ goto free_sz;
+ }
+
+ if (sz->endpoint->wMaxPacketSize == 0) {
+ err("%s: endpoint message size==0? ", __func__);
+ retval = -ENODEV;
+ goto free_sz;
+ }
+
+ /* Allocate the USB buffer and IRQ URB */
+
+ sz->buf_in_len = sz->endpoint->wMaxPacketSize;
+ sz->buf_in = usb_alloc_coherent(sz->udev, sz->buf_in_len,
+ GFP_ATOMIC, &sz->dma_in);
+ if (sz->buf_in == NULL)
+ goto free_sz;
+
+ sz->urb_in = usb_alloc_urb(0, GFP_KERNEL);
+ if (sz->urb_in == NULL)
+ goto free_sz;
+
+ /* Connect this device to the LIRC sub-system */
+ driver = kzalloc(sizeof(struct lirc_driver), GFP_KERNEL);
+ if (!driver)
+ goto free_sz;
+
+ lirc_buf = kmalloc(sizeof(struct lirc_buffer), GFP_KERNEL);
+ if (!lirc_buf)
+ goto free_driver;
+ if (lirc_buffer_init(lirc_buf, sizeof(int), STREAMZAP_BUF_LEN))
+ goto kfree_lirc_buf;
+
+ delay_buf = kmalloc(sizeof(struct lirc_buffer), GFP_KERNEL);
+ if (!delay_buf)
+ goto free_lirc_buf;
+ if (lirc_buffer_init(delay_buf, sizeof(int), STREAMZAP_BUF_LEN))
+ goto kfree_delay_buf;
+
+ sz->driver = driver;
+ strcpy(sz->driver->name, DRIVER_NAME);
+ sz->driver->minor = -1;
+ sz->driver->sample_rate = 0;
+ sz->driver->code_length = sizeof(int) * 8;
+ sz->driver->features = LIRC_CAN_REC_MODE2 |
+ LIRC_CAN_GET_REC_RESOLUTION |
+ LIRC_CAN_SET_REC_TIMEOUT;
+ sz->driver->data = sz;
+ sz->driver->min_timeout = STREAMZAP_TIMEOUT * STREAMZAP_RESOLUTION;
+ sz->driver->max_timeout = STREAMZAP_TIMEOUT * STREAMZAP_RESOLUTION;
+ sz->driver->rbuf = lirc_buf;
+ sz->delay_buf = delay_buf;
+ sz->driver->set_use_inc = &streamzap_use_inc;
+ sz->driver->set_use_dec = &streamzap_use_dec;
+ sz->driver->fops = &streamzap_fops;
+ sz->driver->dev = &interface->dev;
+ sz->driver->owner = THIS_MODULE;
+
+ sz->idle = 1;
+ sz->decoder_state = PulseSpace;
+ init_timer(&sz->delay_timer);
+ sz->delay_timer.function = delay_timeout;
+ sz->delay_timer.data = (unsigned long) sz;
+ sz->timer_running = 0;
+ spin_lock_init(&sz->timer_lock);
+
+ init_timer(&sz->flush_timer);
+ sz->flush_timer.function = flush_timeout;
+ sz->flush_timer.data = (unsigned long) sz;
+ /* Complete final initialisations */
+
+ usb_fill_int_urb(sz->urb_in, udev,
+ usb_rcvintpipe(udev, sz->endpoint->bEndpointAddress),
+ sz->buf_in, sz->buf_in_len, usb_streamzap_irq, sz,
+ sz->endpoint->bInterval);
+ sz->urb_in->transfer_dma = sz->dma_in;
+ sz->urb_in->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+
+ if (udev->descriptor.iManufacturer
+ && usb_string(udev, udev->descriptor.iManufacturer,
+ buf, sizeof(buf)) > 0)
+ strlcpy(name, buf, sizeof(name));
+
+ if (udev->descriptor.iProduct
+ && usb_string(udev, udev->descriptor.iProduct,
+ buf, sizeof(buf)) > 0)
+ snprintf(name + strlen(name), sizeof(name) - strlen(name),
+ " %s", buf);
+
+ minor = lirc_register_driver(driver);
+
+ if (minor < 0)
+ goto free_delay_buf;
+
+ sz->driver->minor = minor;
+
+ usb_set_intfdata(interface, sz);
+
+ printk(KERN_INFO DRIVER_NAME "[%d]: %s on usb%d:%d attached\n",
+ sz->driver->minor, name,
+ udev->bus->busnum, sz->udev->devnum);
+
+ return 0;
+
+free_delay_buf:
+ lirc_buffer_free(sz->delay_buf);
+kfree_delay_buf:
+ kfree(delay_buf);
+free_lirc_buf:
+ lirc_buffer_free(sz->driver->rbuf);
+kfree_lirc_buf:
+ kfree(lirc_buf);
+free_driver:
+ kfree(driver);
+free_sz:
+ if (retval == -ENOMEM)
+ err("Out of memory");
+
+ if (sz) {
+ usb_free_urb(sz->urb_in);
+ usb_free_coherent(udev, sz->buf_in_len, sz->buf_in, sz->dma_in);
+ kfree(sz);
+ }
+
+ return retval;
+}
+
+static int streamzap_use_inc(void *data)
+{
+ struct usb_streamzap *sz = data;
+
+ if (!sz) {
+ dprintk("%s called with no context", -1, __func__);
+ return -EINVAL;
+ }
+ dprintk("set use inc", sz->driver->minor);
+
+ lirc_buffer_clear(sz->driver->rbuf);
+ lirc_buffer_clear(sz->delay_buf);
+
+ sz->flush_timer.expires = jiffies + HZ;
+ sz->flush = 1;
+ add_timer(&sz->flush_timer);
+
+ sz->urb_in->dev = sz->udev;
+ if (usb_submit_urb(sz->urb_in, GFP_ATOMIC)) {
+ dprintk("open result = -EIO error submitting urb",
+ sz->driver->minor);
+ return -EIO;
+ }
+ sz->in_use++;
+
+ return 0;
+}
+
+static void streamzap_use_dec(void *data)
+{
+ struct usb_streamzap *sz = data;
+
+ if (!sz) {
+ dprintk("%s called with no context", -1, __func__);
+ return;
+ }
+ dprintk("set use dec", sz->driver->minor);
+
+ if (sz->flush) {
+ sz->flush = 0;
+ del_timer_sync(&sz->flush_timer);
+ }
+
+ usb_kill_urb(sz->urb_in);
+
+ stop_timer(sz);
+
+ sz->in_use--;
+}
+
+static long streamzap_ioctl(struct file *filep, unsigned int cmd,
+ unsigned long arg)
+{
+ int result = 0;
+ int val;
+ struct usb_streamzap *sz = lirc_get_pdata(filep);
+
+ switch (cmd) {
+ case LIRC_GET_REC_RESOLUTION:
+ result = put_user(STREAMZAP_RESOLUTION, (unsigned int *) arg);
+ break;
+ case LIRC_SET_REC_TIMEOUT:
+ result = get_user(val, (int *)arg);
+ if (result == 0) {
+ if (val == STREAMZAP_TIMEOUT * STREAMZAP_RESOLUTION)
+ sz->timeout_enabled = 1;
+ else if (val == 0)
+ sz->timeout_enabled = 0;
+ else
+ result = -EINVAL;
+ }
+ break;
+ default:
+ return lirc_dev_fop_ioctl(filep, cmd, arg);
+ }
+ return result;
+}
+
+/**
+ * streamzap_disconnect
+ *
+ * Called by the usb core when the device is removed from the system.
+ *
+ * This routine guarantees that the driver will not submit any more urbs
+ * by clearing dev->udev. It is also supposed to terminate any currently
+ * active urbs. Unfortunately, usb_bulk_msg(), used in streamzap_read(),
+ * does not provide any way to do this.
+ */
+static void streamzap_disconnect(struct usb_interface *interface)
+{
+ struct usb_streamzap *sz;
+ int errnum;
+ int minor;
+
+ sz = usb_get_intfdata(interface);
+
+ /* unregister from the LIRC sub-system */
+
+ errnum = lirc_unregister_driver(sz->driver->minor);
+ if (errnum != 0)
+ dprintk("error in lirc_unregister: (returned %d)",
+ sz->driver->minor, errnum);
+
+ lirc_buffer_free(sz->delay_buf);
+ lirc_buffer_free(sz->driver->rbuf);
+
+ /* unregister from the USB sub-system */
+
+ usb_free_urb(sz->urb_in);
+
+ usb_free_coherent(sz->udev, sz->buf_in_len, sz->buf_in, sz->dma_in);
+
+ minor = sz->driver->minor;
+ kfree(sz->driver->rbuf);
+ kfree(sz->driver);
+ kfree(sz->delay_buf);
+ kfree(sz);
+
+ printk(KERN_INFO DRIVER_NAME "[%d]: disconnected\n", minor);
+}
+
+static int streamzap_suspend(struct usb_interface *intf, pm_message_t message)
+{
+ struct usb_streamzap *sz = usb_get_intfdata(intf);
+
+ printk(KERN_INFO DRIVER_NAME "[%d]: suspend\n", sz->driver->minor);
+ if (sz->in_use) {
+ if (sz->flush) {
+ sz->flush = 0;
+ del_timer_sync(&sz->flush_timer);
+ }
+
+ stop_timer(sz);
+
+ usb_kill_urb(sz->urb_in);
+ }
+ return 0;
+}
+
+static int streamzap_resume(struct usb_interface *intf)
+{
+ struct usb_streamzap *sz = usb_get_intfdata(intf);
+
+ lirc_buffer_clear(sz->driver->rbuf);
+ lirc_buffer_clear(sz->delay_buf);
+
+ if (sz->in_use) {
+ sz->flush_timer.expires = jiffies + HZ;
+ sz->flush = 1;
+ add_timer(&sz->flush_timer);
+
+ sz->urb_in->dev = sz->udev;
+ if (usb_submit_urb(sz->urb_in, GFP_ATOMIC)) {
+ dprintk("open result = -EIO error submitting urb",
+ sz->driver->minor);
+ return -EIO;
+ }
+ }
+ return 0;
+}
+
+/**
+ * usb_streamzap_init
+ */
+static int __init usb_streamzap_init(void)
+{
+ int result;
+
+ /* register this driver with the USB subsystem */
+ result = usb_register(&streamzap_driver);
+
+ if (result) {
+ err("usb_register failed. Error number %d",
+ result);
+ return result;
+ }
+
+ printk(KERN_INFO DRIVER_NAME " " DRIVER_VERSION " registered\n");
+ return 0;
+}
+
+/**
+ * usb_streamzap_exit
+ */
+static void __exit usb_streamzap_exit(void)
+{
+ usb_deregister(&streamzap_driver);
+}
+
+
+module_init(usb_streamzap_init);
+module_exit(usb_streamzap_exit);
+
+MODULE_AUTHOR("Christoph Bartelmus, Greg Wickham, Adrian Dewhurst");
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
+
+module_param(debug, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug, "Enable debugging messages");
diff --git a/drivers/staging/lirc/lirc_ttusbir.c b/drivers/staging/lirc/lirc_ttusbir.c
new file mode 100644
index 00000000000..e345ab9a004
--- /dev/null
+++ b/drivers/staging/lirc/lirc_ttusbir.c
@@ -0,0 +1,396 @@
+/*
+ * lirc_ttusbir.c
+ *
+ * lirc_ttusbir - LIRC device driver for the TechnoTrend USB IR Receiver
+ *
+ * Copyright (C) 2007 Stefan Macher <st_maker-lirc@yahoo.de>
+ *
+ * This LIRC driver provides access to the TechnoTrend USB IR Receiver.
+ * The receiver delivers the IR signal as raw sampled true/false data in
+ * isochronous USB packets each of size 128 byte.
+ * Currently the driver reduces the sampling rate by factor of 8 as this
+ * is still more than enough to decode RC-5 - others should be analyzed.
+ * But the driver does not rely on RC-5 it should be able to decode every
+ * IR signal that is not too fast.
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * 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/version.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/usb.h>
+
+#include <media/lirc.h>
+#include <media/lirc_dev.h>
+
+MODULE_DESCRIPTION("TechnoTrend USB IR device driver for LIRC");
+MODULE_AUTHOR("Stefan Macher (st_maker-lirc@yahoo.de)");
+MODULE_LICENSE("GPL");
+
+/* #define DEBUG */
+#ifdef DEBUG
+#define DPRINTK printk
+#else
+#define DPRINTK(_x_, a...)
+#endif
+
+/* function declarations */
+static int probe(struct usb_interface *intf, const struct usb_device_id *id);
+static void disconnect(struct usb_interface *intf);
+static void urb_complete(struct urb *urb);
+static int set_use_inc(void *data);
+static void set_use_dec(void *data);
+
+static int num_urbs = 2;
+module_param(num_urbs, int, S_IRUGO);
+MODULE_PARM_DESC(num_urbs,
+ "Number of URBs in queue. Try to increase to 4 in case "
+ "of problems (default: 2; minimum: 2)");
+
+/* table of devices that work with this driver */
+static struct usb_device_id device_id_table[] = {
+ /* TechnoTrend USB IR Receiver */
+ { USB_DEVICE(0x0B48, 0x2003) },
+ /* Terminating entry */
+ { }
+};
+MODULE_DEVICE_TABLE(usb, device_id_table);
+
+/* USB driver definition */
+static struct usb_driver usb_driver = {
+ .name = "TTUSBIR",
+ .id_table = &(device_id_table[0]),
+ .probe = probe,
+ .disconnect = disconnect,
+};
+
+/* USB device definition */
+struct ttusbir_device {
+ struct usb_driver *usb_driver;
+ struct usb_device *udev;
+ struct usb_interface *interf;
+ struct usb_class_driver class_driver;
+ unsigned int ifnum; /* Interface number to use */
+ unsigned int alt_setting; /* alternate setting to use */
+ unsigned int endpoint; /* Endpoint to use */
+ struct urb **urb; /* num_urb URB pointers*/
+ char **buffer; /* 128 byte buffer for each URB */
+ struct lirc_buffer rbuf; /* Buffer towards LIRC */
+ struct lirc_driver driver;
+ int minor;
+ int last_pulse; /* remembers if last received byte was pulse or space */
+ int last_num; /* remembers how many last bytes appeared */
+ int opened;
+};
+
+/*** LIRC specific functions ***/
+static int set_use_inc(void *data)
+{
+ int i, retval;
+ struct ttusbir_device *ttusbir = data;
+
+ DPRINTK("Sending first URBs\n");
+ /* @TODO Do I need to check if I am already opened */
+ ttusbir->opened = 1;
+
+ for (i = 0; i < num_urbs; i++) {
+ retval = usb_submit_urb(ttusbir->urb[i], GFP_KERNEL);
+ if (retval) {
+ err("%s: usb_submit_urb failed on urb %d",
+ __func__, i);
+ return retval;
+ }
+ }
+ return 0;
+}
+
+static void set_use_dec(void *data)
+{
+ struct ttusbir_device *ttusbir = data;
+
+ DPRINTK("Device closed\n");
+
+ ttusbir->opened = 0;
+}
+
+/*** USB specific functions ***/
+
+/*
+ * This mapping table is used to do a very simple filtering of the
+ * input signal.
+ * For a value with at least 4 bits set it returns 0xFF otherwise
+ * 0x00. For faster IR signals this can not be used. But for RC-5 we
+ * still have about 14 samples per pulse/space, i.e. we sample with 14
+ * times higher frequency than the signal frequency
+ */
+const unsigned char map_table[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
+ 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
+ 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
+ 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF,
+ 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF,
+ 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
+ 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
+ 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF,
+ 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF,
+ 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
+ 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF,
+ 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF,
+ 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF,
+ 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
+};
+
+static void urb_complete(struct urb *urb)
+{
+ struct ttusbir_device *ttusbir;
+ unsigned char *buf;
+ int i;
+ int l;
+
+ ttusbir = urb->context;
+
+ if (!ttusbir->opened)
+ return;
+
+ buf = (unsigned char *)urb->transfer_buffer;
+
+ for (i = 0; i < 128; i++) {
+ /* Here we do the filtering and some kind of down sampling */
+ buf[i] = ~map_table[buf[i]];
+ if (ttusbir->last_pulse == buf[i]) {
+ if (ttusbir->last_num < PULSE_MASK/63)
+ ttusbir->last_num++;
+ /*
+ * else we are in a idle period and do not need to
+ * increment any longer
+ */
+ } else {
+ l = ttusbir->last_num * 62; /* about 62 = us/byte */
+ if (ttusbir->last_pulse) /* pulse or space? */
+ l |= PULSE_BIT;
+ if (!lirc_buffer_full(&ttusbir->rbuf)) {
+ lirc_buffer_write(&ttusbir->rbuf, (void *)&l);
+ wake_up_interruptible(&ttusbir->rbuf.wait_poll);
+ }
+ ttusbir->last_num = 0;
+ ttusbir->last_pulse = buf[i];
+ }
+ }
+ usb_submit_urb(urb, GFP_ATOMIC); /* keep data rolling :-) */
+}
+
+/*
+ * Called whenever the USB subsystem thinks we could be the right driver
+ * to handle this device
+ */
+static int probe(struct usb_interface *intf, const struct usb_device_id *id)
+{
+ int alt_set, endp;
+ int found = 0;
+ int i, j;
+ int struct_size;
+ struct usb_host_interface *host_interf;
+ struct usb_interface_descriptor *interf_desc;
+ struct usb_host_endpoint *host_endpoint;
+ struct ttusbir_device *ttusbir;
+
+ DPRINTK("Module ttusbir probe\n");
+
+ /* To reduce memory fragmentation we use only one allocation */
+ struct_size = sizeof(struct ttusbir_device) +
+ (sizeof(struct urb *) * num_urbs) +
+ (sizeof(char *) * num_urbs) +
+ (num_urbs * 128);
+ ttusbir = kzalloc(struct_size, GFP_KERNEL);
+ if (!ttusbir)
+ return -ENOMEM;
+
+ ttusbir->urb = (struct urb **)((char *)ttusbir +
+ sizeof(struct ttusbir_device));
+ ttusbir->buffer = (char **)((char *)ttusbir->urb +
+ (sizeof(struct urb *) * num_urbs));
+ for (i = 0; i < num_urbs; i++)
+ ttusbir->buffer[i] = (char *)ttusbir->buffer +
+ (sizeof(char *)*num_urbs) + (i * 128);
+
+ ttusbir->usb_driver = &usb_driver;
+ ttusbir->alt_setting = -1;
+ /* @TODO check if error can be returned */
+ ttusbir->udev = usb_get_dev(interface_to_usbdev(intf));
+ ttusbir->interf = intf;
+ ttusbir->last_pulse = 0x00;
+ ttusbir->last_num = 0;
+
+ /*
+ * Now look for interface setting we can handle
+ * We are searching for the alt setting where end point
+ * 0x82 has max packet size 16
+ */
+ for (alt_set = 0; alt_set < intf->num_altsetting && !found; alt_set++) {
+ host_interf = &intf->altsetting[alt_set];
+ interf_desc = &host_interf->desc;
+ for (endp = 0; endp < interf_desc->bNumEndpoints; endp++) {
+ host_endpoint = &host_interf->endpoint[endp];
+ if ((host_endpoint->desc.bEndpointAddress == 0x82) &&
+ (host_endpoint->desc.wMaxPacketSize == 0x10)) {
+ ttusbir->alt_setting = alt_set;
+ ttusbir->endpoint = endp;
+ found = 1;
+ break;
+ }
+ }
+ }
+ if (ttusbir->alt_setting != -1)
+ DPRINTK("alt setting: %d\n", ttusbir->alt_setting);
+ else {
+ err("Could not find alternate setting\n");
+ kfree(ttusbir);
+ return -EINVAL;
+ }
+
+ /* OK lets setup this interface setting */
+ usb_set_interface(ttusbir->udev, 0, ttusbir->alt_setting);
+
+ /* Store device info in interface structure */
+ usb_set_intfdata(intf, ttusbir);
+
+ /* Register as a LIRC driver */
+ if (lirc_buffer_init(&ttusbir->rbuf, sizeof(int), 256) < 0) {
+ err("Could not get memory for LIRC data buffer\n");
+ usb_set_intfdata(intf, NULL);
+ kfree(ttusbir);
+ return -ENOMEM;
+ }
+ strcpy(ttusbir->driver.name, "TTUSBIR");
+ ttusbir->driver.minor = -1;
+ ttusbir->driver.code_length = 1;
+ ttusbir->driver.sample_rate = 0;
+ ttusbir->driver.data = ttusbir;
+ ttusbir->driver.add_to_buf = NULL;
+ ttusbir->driver.rbuf = &ttusbir->rbuf;
+ ttusbir->driver.set_use_inc = set_use_inc;
+ ttusbir->driver.set_use_dec = set_use_dec;
+ ttusbir->driver.dev = &intf->dev;
+ ttusbir->driver.owner = THIS_MODULE;
+ ttusbir->driver.features = LIRC_CAN_REC_MODE2;
+ ttusbir->minor = lirc_register_driver(&ttusbir->driver);
+ if (ttusbir->minor < 0) {
+ err("Error registering as LIRC driver\n");
+ usb_set_intfdata(intf, NULL);
+ lirc_buffer_free(&ttusbir->rbuf);
+ kfree(ttusbir);
+ return -EIO;
+ }
+
+ /* Allocate and setup the URB that we will use to talk to the device */
+ for (i = 0; i < num_urbs; i++) {
+ ttusbir->urb[i] = usb_alloc_urb(8, GFP_KERNEL);
+ if (!ttusbir->urb[i]) {
+ err("Could not allocate memory for the URB\n");
+ for (j = i - 1; j >= 0; j--)
+ kfree(ttusbir->urb[j]);
+ lirc_buffer_free(&ttusbir->rbuf);
+ lirc_unregister_driver(ttusbir->minor);
+ kfree(ttusbir);
+ usb_set_intfdata(intf, NULL);
+ return -ENOMEM;
+ }
+ ttusbir->urb[i]->dev = ttusbir->udev;
+ ttusbir->urb[i]->context = ttusbir;
+ ttusbir->urb[i]->pipe = usb_rcvisocpipe(ttusbir->udev,
+ ttusbir->endpoint);
+ ttusbir->urb[i]->interval = 1;
+ ttusbir->urb[i]->transfer_flags = URB_ISO_ASAP;
+ ttusbir->urb[i]->transfer_buffer = &ttusbir->buffer[i][0];
+ ttusbir->urb[i]->complete = urb_complete;
+ ttusbir->urb[i]->number_of_packets = 8;
+ ttusbir->urb[i]->transfer_buffer_length = 128;
+ for (j = 0; j < 8; j++) {
+ ttusbir->urb[i]->iso_frame_desc[j].offset = j*16;
+ ttusbir->urb[i]->iso_frame_desc[j].length = 16;
+ }
+ }
+ return 0;
+}
+
+/**
+ * Called when the driver is unloaded or the device is unplugged
+ */
+static void disconnect(struct usb_interface *intf)
+{
+ int i;
+ struct ttusbir_device *ttusbir;
+
+ DPRINTK("Module ttusbir disconnect\n");
+
+ ttusbir = (struct ttusbir_device *) usb_get_intfdata(intf);
+ usb_set_intfdata(intf, NULL);
+ lirc_unregister_driver(ttusbir->minor);
+ DPRINTK("unregistered\n");
+
+ for (i = 0; i < num_urbs; i++) {
+ usb_kill_urb(ttusbir->urb[i]);
+ usb_free_urb(ttusbir->urb[i]);
+ }
+ DPRINTK("URBs killed\n");
+ lirc_buffer_free(&ttusbir->rbuf);
+ kfree(ttusbir);
+}
+
+static int ttusbir_init_module(void)
+{
+ int result;
+
+ DPRINTK(KERN_DEBUG "Module ttusbir init\n");
+
+ /* register this driver with the USB subsystem */
+ result = usb_register(&usb_driver);
+ if (result)
+ err("usb_register failed. Error number %d", result);
+ return result;
+}
+
+static void ttusbir_exit_module(void)
+{
+ printk(KERN_DEBUG "Module ttusbir exit\n");
+ usb_deregister(&usb_driver);
+}
+
+module_init(ttusbir_init_module);
+module_exit(ttusbir_exit_module);
diff --git a/drivers/staging/lirc/lirc_zilog.c b/drivers/staging/lirc/lirc_zilog.c
new file mode 100644
index 00000000000..100caab1045
--- /dev/null
+++ b/drivers/staging/lirc/lirc_zilog.c
@@ -0,0 +1,1387 @@
+/*
+ * i2c IR lirc driver for devices with zilog IR processors
+ *
+ * Copyright (c) 2000 Gerd Knorr <kraxel@goldbach.in-berlin.de>
+ * modified for PixelView (BT878P+W/FM) by
+ * Michal Kochanowicz <mkochano@pld.org.pl>
+ * Christoph Bartelmus <lirc@bartelmus.de>
+ * modified for KNC ONE TV Station/Anubis Typhoon TView Tuner by
+ * Ulrich Mueller <ulrich.mueller42@web.de>
+ * modified for Asus TV-Box and Creative/VisionTek BreakOut-Box by
+ * Stefan Jahn <stefan@lkcc.org>
+ * modified for inclusion into kernel sources by
+ * Jerome Brock <jbrock@users.sourceforge.net>
+ * modified for Leadtek Winfast PVR2000 by
+ * Thomas Reitmayr (treitmayr@yahoo.com)
+ * modified for Hauppauge PVR-150 IR TX device by
+ * Mark Weaver <mark@npsl.co.uk>
+ * changed name from lirc_pvr150 to lirc_zilog, works on more than pvr-150
+ * Jarod Wilson <jarod@redhat.com>
+ *
+ * parts are cut&pasted from the lirc_i2c.c 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 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/version.h>
+#include <linux/module.h>
+#include <linux/kmod.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/fs.h>
+#include <linux/poll.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/delay.h>
+#include <linux/completion.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/firmware.h>
+#include <linux/vmalloc.h>
+
+#include <linux/mutex.h>
+#include <linux/kthread.h>
+
+#include <media/lirc_dev.h>
+#include <media/lirc.h>
+
+struct IR {
+ struct lirc_driver l;
+
+ /* Device info */
+ struct mutex ir_lock;
+ int open;
+
+ /* RX device */
+ struct i2c_client c_rx;
+ int have_rx;
+
+ /* RX device buffer & lock */
+ struct lirc_buffer buf;
+ struct mutex buf_lock;
+
+ /* RX polling thread data */
+ struct completion *t_notify;
+ struct completion *t_notify2;
+ int shutdown;
+ struct task_struct *task;
+
+ /* RX read data */
+ unsigned char b[3];
+
+ /* TX device */
+ struct i2c_client c_tx;
+ int need_boot;
+ int have_tx;
+};
+
+/* Minor -> data mapping */
+static struct IR *ir_devices[MAX_IRCTL_DEVICES];
+
+/* Block size for IR transmitter */
+#define TX_BLOCK_SIZE 99
+
+/* Hauppauge IR transmitter data */
+struct tx_data_struct {
+ /* Boot block */
+ unsigned char *boot_data;
+
+ /* Start of binary data block */
+ unsigned char *datap;
+
+ /* End of binary data block */
+ unsigned char *endp;
+
+ /* Number of installed codesets */
+ unsigned int num_code_sets;
+
+ /* Pointers to codesets */
+ unsigned char **code_sets;
+
+ /* Global fixed data template */
+ int fixed[TX_BLOCK_SIZE];
+};
+
+static struct tx_data_struct *tx_data;
+static struct mutex tx_data_lock;
+
+#define zilog_notify(s, args...) printk(KERN_NOTICE KBUILD_MODNAME ": " s, \
+ ## args)
+#define zilog_error(s, args...) printk(KERN_ERR KBUILD_MODNAME ": " s, ## args)
+
+#define ZILOG_HAUPPAUGE_IR_RX_NAME "Zilog/Hauppauge IR RX"
+#define ZILOG_HAUPPAUGE_IR_TX_NAME "Zilog/Hauppauge IR TX"
+
+/* module parameters */
+static int debug; /* debug output */
+static int disable_rx; /* disable RX device */
+static int disable_tx; /* disable TX device */
+static int minor = -1; /* minor number */
+
+#define dprintk(fmt, args...) \
+ do { \
+ if (debug) \
+ printk(KERN_DEBUG KBUILD_MODNAME ": " fmt, \
+ ## args); \
+ } while (0)
+
+static int add_to_buf(struct IR *ir)
+{
+ __u16 code;
+ unsigned char codes[2];
+ unsigned char keybuf[6];
+ int got_data = 0;
+ int ret;
+ int failures = 0;
+ unsigned char sendbuf[1] = { 0 };
+
+ if (lirc_buffer_full(&ir->buf)) {
+ dprintk("buffer overflow\n");
+ return -EOVERFLOW;
+ }
+
+ /*
+ * service the device as long as it is returning
+ * data and we have space
+ */
+ do {
+ /*
+ * Lock i2c bus for the duration. RX/TX chips interfere so
+ * this is worth it
+ */
+ mutex_lock(&ir->ir_lock);
+
+ /*
+ * Send random "poll command" (?) Windows driver does this
+ * and it is a good point to detect chip failure.
+ */
+ ret = i2c_master_send(&ir->c_rx, sendbuf, 1);
+ if (ret != 1) {
+ zilog_error("i2c_master_send failed with %d\n", ret);
+ if (failures >= 3) {
+ mutex_unlock(&ir->ir_lock);
+ zilog_error("unable to read from the IR chip "
+ "after 3 resets, giving up\n");
+ return ret;
+ }
+
+ /* Looks like the chip crashed, reset it */
+ zilog_error("polling the IR receiver chip failed, "
+ "trying reset\n");
+
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout((100 * HZ + 999) / 1000);
+ ir->need_boot = 1;
+
+ ++failures;
+ mutex_unlock(&ir->ir_lock);
+ continue;
+ }
+
+ ret = i2c_master_recv(&ir->c_rx, keybuf, sizeof(keybuf));
+ mutex_unlock(&ir->ir_lock);
+ if (ret != sizeof(keybuf)) {
+ zilog_error("i2c_master_recv failed with %d -- "
+ "keeping last read buffer\n", ret);
+ } else {
+ ir->b[0] = keybuf[3];
+ ir->b[1] = keybuf[4];
+ ir->b[2] = keybuf[5];
+ dprintk("key (0x%02x/0x%02x)\n", ir->b[0], ir->b[1]);
+ }
+
+ /* key pressed ? */
+#ifdef I2C_HW_B_HDPVR
+ if (ir->c_rx.adapter->id == I2C_HW_B_HDPVR) {
+ if (got_data && (keybuf[0] == 0x80))
+ return 0;
+ else if (got_data && (keybuf[0] == 0x00))
+ return -ENODATA;
+ } else if ((ir->b[0] & 0x80) == 0)
+#else
+ if ((ir->b[0] & 0x80) == 0)
+#endif
+ return got_data ? 0 : -ENODATA;
+
+ /* look what we have */
+ code = (((__u16)ir->b[0] & 0x7f) << 6) | (ir->b[1] >> 2);
+
+ codes[0] = (code >> 8) & 0xff;
+ codes[1] = code & 0xff;
+
+ /* return it */
+ lirc_buffer_write(&ir->buf, codes);
+ ++got_data;
+ } while (!lirc_buffer_full(&ir->buf));
+
+ return 0;
+}
+
+/*
+ * Main function of the polling thread -- from lirc_dev.
+ * We don't fit the LIRC model at all anymore. This is horrible, but
+ * basically we have a single RX/TX device with a nasty failure mode
+ * that needs to be accounted for across the pair. lirc lets us provide
+ * fops, but prevents us from using the internal polling, etc. if we do
+ * so. Hence the replication. Might be neater to extend the LIRC model
+ * to account for this but I'd think it's a very special case of seriously
+ * messed up hardware.
+ */
+static int lirc_thread(void *arg)
+{
+ struct IR *ir = arg;
+
+ if (ir->t_notify != NULL)
+ complete(ir->t_notify);
+
+ dprintk("poll thread started\n");
+
+ do {
+ if (ir->open) {
+ set_current_state(TASK_INTERRUPTIBLE);
+
+ /*
+ * This is ~113*2 + 24 + jitter (2*repeat gap +
+ * code length). We use this interval as the chip
+ * resets every time you poll it (bad!). This is
+ * therefore just sufficient to catch all of the
+ * button presses. It makes the remote much more
+ * responsive. You can see the difference by
+ * running irw and holding down a button. With
+ * 100ms, the old polling interval, you'll notice
+ * breaks in the repeat sequence corresponding to
+ * lost keypresses.
+ */
+ schedule_timeout((260 * HZ) / 1000);
+ if (ir->shutdown)
+ break;
+ if (!add_to_buf(ir))
+ wake_up_interruptible(&ir->buf.wait_poll);
+ } else {
+ /* if device not opened so we can sleep half a second */
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule_timeout(HZ/2);
+ }
+ } while (!ir->shutdown);
+
+ if (ir->t_notify2 != NULL)
+ wait_for_completion(ir->t_notify2);
+
+ ir->task = NULL;
+ if (ir->t_notify != NULL)
+ complete(ir->t_notify);
+
+ dprintk("poll thread ended\n");
+ return 0;
+}
+
+static int set_use_inc(void *data)
+{
+ struct IR *ir = data;
+
+ if (ir->l.owner == NULL || try_module_get(ir->l.owner) == 0)
+ return -ENODEV;
+
+ /* lock bttv in memory while /dev/lirc is in use */
+ /*
+ * this is completely broken code. lirc_unregister_driver()
+ * must be possible even when the device is open
+ */
+ if (ir->c_rx.addr)
+ i2c_use_client(&ir->c_rx);
+ if (ir->c_tx.addr)
+ i2c_use_client(&ir->c_tx);
+
+ return 0;
+}
+
+static void set_use_dec(void *data)
+{
+ struct IR *ir = data;
+
+ if (ir->c_rx.addr)
+ i2c_release_client(&ir->c_rx);
+ if (ir->c_tx.addr)
+ i2c_release_client(&ir->c_tx);
+ if (ir->l.owner != NULL)
+ module_put(ir->l.owner);
+}
+
+/* safe read of a uint32 (always network byte order) */
+static int read_uint32(unsigned char **data,
+ unsigned char *endp, unsigned int *val)
+{
+ if (*data + 4 > endp)
+ return 0;
+ *val = ((*data)[0] << 24) | ((*data)[1] << 16) |
+ ((*data)[2] << 8) | (*data)[3];
+ *data += 4;
+ return 1;
+}
+
+/* safe read of a uint8 */
+static int read_uint8(unsigned char **data,
+ unsigned char *endp, unsigned char *val)
+{
+ if (*data + 1 > endp)
+ return 0;
+ *val = *((*data)++);
+ return 1;
+}
+
+/* safe skipping of N bytes */
+static int skip(unsigned char **data,
+ unsigned char *endp, unsigned int distance)
+{
+ if (*data + distance > endp)
+ return 0;
+ *data += distance;
+ return 1;
+}
+
+/* decompress key data into the given buffer */
+static int get_key_data(unsigned char *buf,
+ unsigned int codeset, unsigned int key)
+{
+ unsigned char *data, *endp, *diffs, *key_block;
+ unsigned char keys, ndiffs, id;
+ unsigned int base, lim, pos, i;
+
+ /* Binary search for the codeset */
+ for (base = 0, lim = tx_data->num_code_sets; lim; lim >>= 1) {
+ pos = base + (lim >> 1);
+ data = tx_data->code_sets[pos];
+
+ if (!read_uint32(&data, tx_data->endp, &i))
+ goto corrupt;
+
+ if (i == codeset)
+ break;
+ else if (codeset > i) {
+ base = pos + 1;
+ --lim;
+ }
+ }
+ /* Not found? */
+ if (!lim)
+ return -EPROTO;
+
+ /* Set end of data block */
+ endp = pos < tx_data->num_code_sets - 1 ?
+ tx_data->code_sets[pos + 1] : tx_data->endp;
+
+ /* Read the block header */
+ if (!read_uint8(&data, endp, &keys) ||
+ !read_uint8(&data, endp, &ndiffs) ||
+ ndiffs > TX_BLOCK_SIZE || keys == 0)
+ goto corrupt;
+
+ /* Save diffs & skip */
+ diffs = data;
+ if (!skip(&data, endp, ndiffs))
+ goto corrupt;
+
+ /* Read the id of the first key */
+ if (!read_uint8(&data, endp, &id))
+ goto corrupt;
+
+ /* Unpack the first key's data */
+ for (i = 0; i < TX_BLOCK_SIZE; ++i) {
+ if (tx_data->fixed[i] == -1) {
+ if (!read_uint8(&data, endp, &buf[i]))
+ goto corrupt;
+ } else {
+ buf[i] = (unsigned char)tx_data->fixed[i];
+ }
+ }
+
+ /* Early out key found/not found */
+ if (key == id)
+ return 0;
+ if (keys == 1)
+ return -EPROTO;
+
+ /* Sanity check */
+ key_block = data;
+ if (!skip(&data, endp, (keys - 1) * (ndiffs + 1)))
+ goto corrupt;
+
+ /* Binary search for the key */
+ for (base = 0, lim = keys - 1; lim; lim >>= 1) {
+ /* Seek to block */
+ unsigned char *key_data;
+ pos = base + (lim >> 1);
+ key_data = key_block + (ndiffs + 1) * pos;
+
+ if (*key_data == key) {
+ /* skip key id */
+ ++key_data;
+
+ /* found, so unpack the diffs */
+ for (i = 0; i < ndiffs; ++i) {
+ unsigned char val;
+ if (!read_uint8(&key_data, endp, &val) ||
+ diffs[i] >= TX_BLOCK_SIZE)
+ goto corrupt;
+ buf[diffs[i]] = val;
+ }
+
+ return 0;
+ } else if (key > *key_data) {
+ base = pos + 1;
+ --lim;
+ }
+ }
+ /* Key not found */
+ return -EPROTO;
+
+corrupt:
+ zilog_error("firmware is corrupt\n");
+ return -EFAULT;
+}
+
+/* send a block of data to the IR TX device */
+static int send_data_block(struct IR *ir, unsigned char *data_block)
+{
+ int i, j, ret;
+ unsigned char buf[5];
+
+ for (i = 0; i < TX_BLOCK_SIZE;) {
+ int tosend = TX_BLOCK_SIZE - i;
+ if (tosend > 4)
+ tosend = 4;
+ buf[0] = (unsigned char)(i + 1);
+ for (j = 0; j < tosend; ++j)
+ buf[1 + j] = data_block[i + j];
+ dprintk("%02x %02x %02x %02x %02x",
+ buf[0], buf[1], buf[2], buf[3], buf[4]);
+ ret = i2c_master_send(&ir->c_tx, buf, tosend + 1);
+ if (ret != tosend + 1) {
+ zilog_error("i2c_master_send failed with %d\n", ret);
+ return ret < 0 ? ret : -EFAULT;
+ }
+ i += tosend;
+ }
+ return 0;
+}
+
+/* send boot data to the IR TX device */
+static int send_boot_data(struct IR *ir)
+{
+ int ret;
+ unsigned char buf[4];
+
+ /* send the boot block */
+ ret = send_data_block(ir, tx_data->boot_data);
+ if (ret != 0)
+ return ret;
+
+ /* kick it off? */
+ buf[0] = 0x00;
+ buf[1] = 0x20;
+ ret = i2c_master_send(&ir->c_tx, buf, 2);
+ if (ret != 2) {
+ zilog_error("i2c_master_send failed with %d\n", ret);
+ return ret < 0 ? ret : -EFAULT;
+ }
+ ret = i2c_master_send(&ir->c_tx, buf, 1);
+ if (ret != 1) {
+ zilog_error("i2c_master_send failed with %d\n", ret);
+ return ret < 0 ? ret : -EFAULT;
+ }
+
+ /* Here comes the firmware version... (hopefully) */
+ ret = i2c_master_recv(&ir->c_tx, buf, 4);
+ if (ret != 4) {
+ zilog_error("i2c_master_recv failed with %d\n", ret);
+ return 0;
+ }
+ if (buf[0] != 0x80) {
+ zilog_error("unexpected IR TX response: %02x\n", buf[0]);
+ return 0;
+ }
+ zilog_notify("Zilog/Hauppauge IR blaster firmware version "
+ "%d.%d.%d loaded\n", buf[1], buf[2], buf[3]);
+
+ return 0;
+}
+
+/* unload "firmware", lock held */
+static void fw_unload_locked(void)
+{
+ if (tx_data) {
+ if (tx_data->code_sets)
+ vfree(tx_data->code_sets);
+
+ if (tx_data->datap)
+ vfree(tx_data->datap);
+
+ vfree(tx_data);
+ tx_data = NULL;
+ dprintk("successfully unloaded IR blaster firmware\n");
+ }
+}
+
+/* unload "firmware" for the IR TX device */
+static void fw_unload(void)
+{
+ mutex_lock(&tx_data_lock);
+ fw_unload_locked();
+ mutex_unlock(&tx_data_lock);
+}
+
+/* load "firmware" for the IR TX device */
+static int fw_load(struct IR *ir)
+{
+ int ret;
+ unsigned int i;
+ unsigned char *data, version, num_global_fixed;
+ const struct firmware *fw_entry;
+
+ /* Already loaded? */
+ mutex_lock(&tx_data_lock);
+ if (tx_data) {
+ ret = 0;
+ goto out;
+ }
+
+ /* Request codeset data file */
+ ret = request_firmware(&fw_entry, "haup-ir-blaster.bin", &ir->c_tx.dev);
+ if (ret != 0) {
+ zilog_error("firmware haup-ir-blaster.bin not available "
+ "(%d)\n", ret);
+ ret = ret < 0 ? ret : -EFAULT;
+ goto out;
+ }
+ dprintk("firmware of size %zu loaded\n", fw_entry->size);
+
+ /* Parse the file */
+ tx_data = vmalloc(sizeof(*tx_data));
+ if (tx_data == NULL) {
+ zilog_error("out of memory\n");
+ release_firmware(fw_entry);
+ ret = -ENOMEM;
+ goto out;
+ }
+ tx_data->code_sets = NULL;
+
+ /* Copy the data so hotplug doesn't get confused and timeout */
+ tx_data->datap = vmalloc(fw_entry->size);
+ if (tx_data->datap == NULL) {
+ zilog_error("out of memory\n");
+ release_firmware(fw_entry);
+ vfree(tx_data);
+ ret = -ENOMEM;
+ goto out;
+ }
+ memcpy(tx_data->datap, fw_entry->data, fw_entry->size);
+ tx_data->endp = tx_data->datap + fw_entry->size;
+ release_firmware(fw_entry); fw_entry = NULL;
+
+ /* Check version */
+ data = tx_data->datap;
+ if (!read_uint8(&data, tx_data->endp, &version))
+ goto corrupt;
+ if (version != 1) {
+ zilog_error("unsupported code set file version (%u, expected"
+ "1) -- please upgrade to a newer driver",
+ version);
+ fw_unload_locked();
+ ret = -EFAULT;
+ goto out;
+ }
+
+ /* Save boot block for later */
+ tx_data->boot_data = data;
+ if (!skip(&data, tx_data->endp, TX_BLOCK_SIZE))
+ goto corrupt;
+
+ if (!read_uint32(&data, tx_data->endp,
+ &tx_data->num_code_sets))
+ goto corrupt;
+
+ dprintk("%u IR blaster codesets loaded\n", tx_data->num_code_sets);
+
+ tx_data->code_sets = vmalloc(
+ tx_data->num_code_sets * sizeof(char *));
+ if (tx_data->code_sets == NULL) {
+ fw_unload_locked();
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ for (i = 0; i < TX_BLOCK_SIZE; ++i)
+ tx_data->fixed[i] = -1;
+
+ /* Read global fixed data template */
+ if (!read_uint8(&data, tx_data->endp, &num_global_fixed) ||
+ num_global_fixed > TX_BLOCK_SIZE)
+ goto corrupt;
+ for (i = 0; i < num_global_fixed; ++i) {
+ unsigned char pos, val;
+ if (!read_uint8(&data, tx_data->endp, &pos) ||
+ !read_uint8(&data, tx_data->endp, &val) ||
+ pos >= TX_BLOCK_SIZE)
+ goto corrupt;
+ tx_data->fixed[pos] = (int)val;
+ }
+
+ /* Filch out the position of each code set */
+ for (i = 0; i < tx_data->num_code_sets; ++i) {
+ unsigned int id;
+ unsigned char keys;
+ unsigned char ndiffs;
+
+ /* Save the codeset position */
+ tx_data->code_sets[i] = data;
+
+ /* Read header */
+ if (!read_uint32(&data, tx_data->endp, &id) ||
+ !read_uint8(&data, tx_data->endp, &keys) ||
+ !read_uint8(&data, tx_data->endp, &ndiffs) ||
+ ndiffs > TX_BLOCK_SIZE || keys == 0)
+ goto corrupt;
+
+ /* skip diff positions */
+ if (!skip(&data, tx_data->endp, ndiffs))
+ goto corrupt;
+
+ /*
+ * After the diffs we have the first key id + data -
+ * global fixed
+ */
+ if (!skip(&data, tx_data->endp,
+ 1 + TX_BLOCK_SIZE - num_global_fixed))
+ goto corrupt;
+
+ /* Then we have keys-1 blocks of key id+diffs */
+ if (!skip(&data, tx_data->endp,
+ (ndiffs + 1) * (keys - 1)))
+ goto corrupt;
+ }
+ ret = 0;
+ goto out;
+
+corrupt:
+ zilog_error("firmware is corrupt\n");
+ fw_unload_locked();
+ ret = -EFAULT;
+
+out:
+ mutex_unlock(&tx_data_lock);
+ return ret;
+}
+
+/* initialise the IR TX device */
+static int tx_init(struct IR *ir)
+{
+ int ret;
+
+ /* Load 'firmware' */
+ ret = fw_load(ir);
+ if (ret != 0)
+ return ret;
+
+ /* Send boot block */
+ ret = send_boot_data(ir);
+ if (ret != 0)
+ return ret;
+ ir->need_boot = 0;
+
+ /* Looks good */
+ return 0;
+}
+
+/* do nothing stub to make LIRC happy */
+static loff_t lseek(struct file *filep, loff_t offset, int orig)
+{
+ return -ESPIPE;
+}
+
+/* copied from lirc_dev */
+static ssize_t read(struct file *filep, char *outbuf, size_t n, loff_t *ppos)
+{
+ struct IR *ir = (struct IR *)filep->private_data;
+ unsigned char buf[ir->buf.chunk_size];
+ int ret = 0, written = 0;
+ DECLARE_WAITQUEUE(wait, current);
+
+ dprintk("read called\n");
+ if (ir->c_rx.addr == 0)
+ return -ENODEV;
+
+ if (mutex_lock_interruptible(&ir->buf_lock))
+ return -ERESTARTSYS;
+
+ if (n % ir->buf.chunk_size) {
+ dprintk("read result = -EINVAL\n");
+ mutex_unlock(&ir->buf_lock);
+ return -EINVAL;
+ }
+
+ /*
+ * we add ourselves to the task queue before buffer check
+ * to avoid losing scan code (in case when queue is awaken somewhere
+ * between while condition checking and scheduling)
+ */
+ add_wait_queue(&ir->buf.wait_poll, &wait);
+ set_current_state(TASK_INTERRUPTIBLE);
+
+ /*
+ * while we didn't provide 'length' bytes, device is opened in blocking
+ * mode and 'copy_to_user' is happy, wait for data.
+ */
+ while (written < n && ret == 0) {
+ if (lirc_buffer_empty(&ir->buf)) {
+ /*
+ * According to the read(2) man page, 'written' can be
+ * returned as less than 'n', instead of blocking
+ * again, returning -EWOULDBLOCK, or returning
+ * -ERESTARTSYS
+ */
+ if (written)
+ break;
+ if (filep->f_flags & O_NONBLOCK) {
+ ret = -EWOULDBLOCK;
+ break;
+ }
+ if (signal_pending(current)) {
+ ret = -ERESTARTSYS;
+ break;
+ }
+ schedule();
+ set_current_state(TASK_INTERRUPTIBLE);
+ } else {
+ lirc_buffer_read(&ir->buf, buf);
+ ret = copy_to_user((void *)outbuf+written, buf,
+ ir->buf.chunk_size);
+ written += ir->buf.chunk_size;
+ }
+ }
+
+ remove_wait_queue(&ir->buf.wait_poll, &wait);
+ set_current_state(TASK_RUNNING);
+ mutex_unlock(&ir->buf_lock);
+
+ dprintk("read result = %s (%d)\n",
+ ret ? "-EFAULT" : "OK", ret);
+
+ return ret ? ret : written;
+}
+
+/* send a keypress to the IR TX device */
+static int send_code(struct IR *ir, unsigned int code, unsigned int key)
+{
+ unsigned char data_block[TX_BLOCK_SIZE];
+ unsigned char buf[2];
+ int i, ret;
+
+ /* Get data for the codeset/key */
+ ret = get_key_data(data_block, code, key);
+
+ if (ret == -EPROTO) {
+ zilog_error("failed to get data for code %u, key %u -- check "
+ "lircd.conf entries\n", code, key);
+ return ret;
+ } else if (ret != 0)
+ return ret;
+
+ /* Send the data block */
+ ret = send_data_block(ir, data_block);
+ if (ret != 0)
+ return ret;
+
+ /* Send data block length? */
+ buf[0] = 0x00;
+ buf[1] = 0x40;
+ ret = i2c_master_send(&ir->c_tx, buf, 2);
+ if (ret != 2) {
+ zilog_error("i2c_master_send failed with %d\n", ret);
+ return ret < 0 ? ret : -EFAULT;
+ }
+ ret = i2c_master_send(&ir->c_tx, buf, 1);
+ if (ret != 1) {
+ zilog_error("i2c_master_send failed with %d\n", ret);
+ return ret < 0 ? ret : -EFAULT;
+ }
+
+ /* Send finished download? */
+ ret = i2c_master_recv(&ir->c_tx, buf, 1);
+ if (ret != 1) {
+ zilog_error("i2c_master_recv failed with %d\n", ret);
+ return ret < 0 ? ret : -EFAULT;
+ }
+ if (buf[0] != 0xA0) {
+ zilog_error("unexpected IR TX response #1: %02x\n",
+ buf[0]);
+ return -EFAULT;
+ }
+
+ /* Send prepare command? */
+ buf[0] = 0x00;
+ buf[1] = 0x80;
+ ret = i2c_master_send(&ir->c_tx, buf, 2);
+ if (ret != 2) {
+ zilog_error("i2c_master_send failed with %d\n", ret);
+ return ret < 0 ? ret : -EFAULT;
+ }
+
+#ifdef I2C_HW_B_HDPVR
+ /*
+ * The sleep bits aren't necessary on the HD PVR, and in fact, the
+ * last i2c_master_recv always fails with a -5, so for now, we're
+ * going to skip this whole mess and say we're done on the HD PVR
+ */
+ if (ir->c_rx.adapter->id == I2C_HW_B_HDPVR)
+ goto done;
+#endif
+
+ /*
+ * This bit NAKs until the device is ready, so we retry it
+ * sleeping a bit each time. This seems to be what the windows
+ * driver does, approximately.
+ * Try for up to 1s.
+ */
+ for (i = 0; i < 20; ++i) {
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout((50 * HZ + 999) / 1000);
+ ret = i2c_master_send(&ir->c_tx, buf, 1);
+ if (ret == 1)
+ break;
+ dprintk("NAK expected: i2c_master_send "
+ "failed with %d (try %d)\n", ret, i+1);
+ }
+ if (ret != 1) {
+ zilog_error("IR TX chip never got ready: last i2c_master_send "
+ "failed with %d\n", ret);
+ return ret < 0 ? ret : -EFAULT;
+ }
+
+ /* Seems to be an 'ok' response */
+ i = i2c_master_recv(&ir->c_tx, buf, 1);
+ if (i != 1) {
+ zilog_error("i2c_master_recv failed with %d\n", ret);
+ return -EFAULT;
+ }
+ if (buf[0] != 0x80) {
+ zilog_error("unexpected IR TX response #2: %02x\n", buf[0]);
+ return -EFAULT;
+ }
+
+done:
+ /* Oh good, it worked */
+ dprintk("sent code %u, key %u\n", code, key);
+ return 0;
+}
+
+/*
+ * Write a code to the device. We take in a 32-bit number (an int) and then
+ * decode this to a codeset/key index. The key data is then decompressed and
+ * sent to the device. We have a spin lock as per i2c documentation to prevent
+ * multiple concurrent sends which would probably cause the device to explode.
+ */
+static ssize_t write(struct file *filep, const char *buf, size_t n,
+ loff_t *ppos)
+{
+ struct IR *ir = (struct IR *)filep->private_data;
+ size_t i;
+ int failures = 0;
+
+ if (ir->c_tx.addr == 0)
+ return -ENODEV;
+
+ /* Validate user parameters */
+ if (n % sizeof(int))
+ return -EINVAL;
+
+ /* Lock i2c bus for the duration */
+ mutex_lock(&ir->ir_lock);
+
+ /* Send each keypress */
+ for (i = 0; i < n;) {
+ int ret = 0;
+ int command;
+
+ if (copy_from_user(&command, buf + i, sizeof(command))) {
+ mutex_unlock(&ir->ir_lock);
+ return -EFAULT;
+ }
+
+ /* Send boot data first if required */
+ if (ir->need_boot == 1) {
+ ret = send_boot_data(ir);
+ if (ret == 0)
+ ir->need_boot = 0;
+ }
+
+ /* Send the code */
+ if (ret == 0) {
+ ret = send_code(ir, (unsigned)command >> 16,
+ (unsigned)command & 0xFFFF);
+ if (ret == -EPROTO) {
+ mutex_unlock(&ir->ir_lock);
+ return ret;
+ }
+ }
+
+ /*
+ * Hmm, a failure. If we've had a few then give up, otherwise
+ * try a reset
+ */
+ if (ret != 0) {
+ /* Looks like the chip crashed, reset it */
+ zilog_error("sending to the IR transmitter chip "
+ "failed, trying reset\n");
+
+ if (failures >= 3) {
+ zilog_error("unable to send to the IR chip "
+ "after 3 resets, giving up\n");
+ mutex_unlock(&ir->ir_lock);
+ return ret;
+ }
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout((100 * HZ + 999) / 1000);
+ ir->need_boot = 1;
+ ++failures;
+ } else
+ i += sizeof(int);
+ }
+
+ /* Release i2c bus */
+ mutex_unlock(&ir->ir_lock);
+
+ /* All looks good */
+ return n;
+}
+
+/* copied from lirc_dev */
+static unsigned int poll(struct file *filep, poll_table *wait)
+{
+ struct IR *ir = (struct IR *)filep->private_data;
+ unsigned int ret;
+
+ dprintk("poll called\n");
+ if (ir->c_rx.addr == 0)
+ return -ENODEV;
+
+ mutex_lock(&ir->buf_lock);
+
+ poll_wait(filep, &ir->buf.wait_poll, wait);
+
+ dprintk("poll result = %s\n",
+ lirc_buffer_empty(&ir->buf) ? "0" : "POLLIN|POLLRDNORM");
+
+ ret = lirc_buffer_empty(&ir->buf) ? 0 : (POLLIN|POLLRDNORM);
+
+ mutex_unlock(&ir->buf_lock);
+ return ret;
+}
+
+static long ioctl(struct file *filep, unsigned int cmd, unsigned long arg)
+{
+ struct IR *ir = (struct IR *)filep->private_data;
+ int result;
+ unsigned long mode, features = 0;
+
+ if (ir->c_rx.addr != 0)
+ features |= LIRC_CAN_REC_LIRCCODE;
+ if (ir->c_tx.addr != 0)
+ features |= LIRC_CAN_SEND_PULSE;
+
+ switch (cmd) {
+ case LIRC_GET_LENGTH:
+ result = put_user((unsigned long)13,
+ (unsigned long *)arg);
+ break;
+ case LIRC_GET_FEATURES:
+ result = put_user(features, (unsigned long *) arg);
+ break;
+ case LIRC_GET_REC_MODE:
+ if (!(features&LIRC_CAN_REC_MASK))
+ return -ENOSYS;
+
+ result = put_user(LIRC_REC2MODE
+ (features&LIRC_CAN_REC_MASK),
+ (unsigned long *)arg);
+ break;
+ case LIRC_SET_REC_MODE:
+ if (!(features&LIRC_CAN_REC_MASK))
+ return -ENOSYS;
+
+ result = get_user(mode, (unsigned long *)arg);
+ if (!result && !(LIRC_MODE2REC(mode) & features))
+ result = -EINVAL;
+ break;
+ case LIRC_GET_SEND_MODE:
+ if (!(features&LIRC_CAN_SEND_MASK))
+ return -ENOSYS;
+
+ result = put_user(LIRC_MODE_PULSE, (unsigned long *) arg);
+ break;
+ case LIRC_SET_SEND_MODE:
+ if (!(features&LIRC_CAN_SEND_MASK))
+ return -ENOSYS;
+
+ result = get_user(mode, (unsigned long *) arg);
+ if (!result && mode != LIRC_MODE_PULSE)
+ return -EINVAL;
+ break;
+ default:
+ return -EINVAL;
+ }
+ return result;
+}
+
+/*
+ * Open the IR device. Get hold of our IR structure and
+ * stash it in private_data for the file
+ */
+static int open(struct inode *node, struct file *filep)
+{
+ struct IR *ir;
+ int ret;
+
+ /* find our IR struct */
+ unsigned minor = MINOR(node->i_rdev);
+ if (minor >= MAX_IRCTL_DEVICES) {
+ dprintk("minor %d: open result = -ENODEV\n",
+ minor);
+ return -ENODEV;
+ }
+ ir = ir_devices[minor];
+
+ /* increment in use count */
+ mutex_lock(&ir->ir_lock);
+ ++ir->open;
+ ret = set_use_inc(ir);
+ if (ret != 0) {
+ --ir->open;
+ mutex_unlock(&ir->ir_lock);
+ return ret;
+ }
+ mutex_unlock(&ir->ir_lock);
+
+ /* stash our IR struct */
+ filep->private_data = ir;
+
+ return 0;
+}
+
+/* Close the IR device */
+static int close(struct inode *node, struct file *filep)
+{
+ /* find our IR struct */
+ struct IR *ir = (struct IR *)filep->private_data;
+ if (ir == NULL) {
+ zilog_error("close: no private_data attached to the file!\n");
+ return -ENODEV;
+ }
+
+ /* decrement in use count */
+ mutex_lock(&ir->ir_lock);
+ --ir->open;
+ set_use_dec(ir);
+ mutex_unlock(&ir->ir_lock);
+
+ return 0;
+}
+
+static struct lirc_driver lirc_template = {
+ .name = "lirc_zilog",
+ .set_use_inc = set_use_inc,
+ .set_use_dec = set_use_dec,
+ .owner = THIS_MODULE
+};
+
+static int ir_remove(struct i2c_client *client);
+static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id);
+static int ir_command(struct i2c_client *client, unsigned int cmd, void *arg);
+
+static const struct i2c_device_id ir_transceiver_id[] = {
+ /* Generic entry for any IR transceiver */
+ { "ir_video", 0 },
+ /* IR device specific entries should be added here */
+ { "ir_tx_z8f0811_haup", 0 },
+ { "ir_rx_z8f0811_haup", 0 },
+ { }
+};
+
+static struct i2c_driver driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "Zilog/Hauppauge i2c IR",
+ },
+ .probe = ir_probe,
+ .remove = ir_remove,
+ .command = ir_command,
+ .id_table = ir_transceiver_id,
+};
+
+static const struct file_operations lirc_fops = {
+ .owner = THIS_MODULE,
+ .llseek = lseek,
+ .read = read,
+ .write = write,
+ .poll = poll,
+ .unlocked_ioctl = ioctl,
+ .open = open,
+ .release = close
+};
+
+static int ir_remove(struct i2c_client *client)
+{
+ struct IR *ir = i2c_get_clientdata(client);
+
+ mutex_lock(&ir->ir_lock);
+
+ if (ir->have_rx || ir->have_tx) {
+ DECLARE_COMPLETION(tn);
+ DECLARE_COMPLETION(tn2);
+
+ /* end up polling thread */
+ if (ir->task && !IS_ERR(ir->task)) {
+ ir->t_notify = &tn;
+ ir->t_notify2 = &tn2;
+ ir->shutdown = 1;
+ wake_up_process(ir->task);
+ complete(&tn2);
+ wait_for_completion(&tn);
+ ir->t_notify = NULL;
+ ir->t_notify2 = NULL;
+ }
+
+ } else {
+ mutex_unlock(&ir->ir_lock);
+ zilog_error("%s: detached from something we didn't "
+ "attach to\n", __func__);
+ return -ENODEV;
+ }
+
+ /* unregister lirc driver */
+ if (ir->l.minor >= 0 && ir->l.minor < MAX_IRCTL_DEVICES) {
+ lirc_unregister_driver(ir->l.minor);
+ ir_devices[ir->l.minor] = NULL;
+ }
+
+ /* free memory */
+ lirc_buffer_free(&ir->buf);
+ mutex_unlock(&ir->ir_lock);
+ kfree(ir);
+
+ return 0;
+}
+
+static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id)
+{
+ struct IR *ir = NULL;
+ struct i2c_adapter *adap = client->adapter;
+ char buf;
+ int ret;
+ int have_rx = 0, have_tx = 0;
+
+ dprintk("%s: adapter id=0x%x, client addr=0x%02x\n",
+ __func__, adap->id, client->addr);
+
+ /*
+ * The external IR receiver is at i2c address 0x71.
+ * The IR transmitter is at 0x70.
+ */
+ client->addr = 0x70;
+
+ if (!disable_tx) {
+ if (i2c_master_recv(client, &buf, 1) == 1)
+ have_tx = 1;
+ dprintk("probe 0x70 @ %s: %s\n",
+ adap->name, have_tx ? "success" : "failed");
+ }
+
+ if (!disable_rx) {
+ client->addr = 0x71;
+ if (i2c_master_recv(client, &buf, 1) == 1)
+ have_rx = 1;
+ dprintk("probe 0x71 @ %s: %s\n",
+ adap->name, have_rx ? "success" : "failed");
+ }
+
+ if (!(have_rx || have_tx)) {
+ zilog_error("%s: no devices found\n", adap->name);
+ goto out_nodev;
+ }
+
+ printk(KERN_INFO "lirc_zilog: chip found with %s\n",
+ have_rx && have_tx ? "RX and TX" :
+ have_rx ? "RX only" : "TX only");
+
+ ir = kzalloc(sizeof(struct IR), GFP_KERNEL);
+
+ if (!ir)
+ goto out_nomem;
+
+ ret = lirc_buffer_init(&ir->buf, 2, BUFLEN / 2);
+ if (ret)
+ goto out_nomem;
+
+ mutex_init(&ir->ir_lock);
+ mutex_init(&ir->buf_lock);
+ ir->need_boot = 1;
+
+ memcpy(&ir->l, &lirc_template, sizeof(struct lirc_driver));
+ ir->l.minor = -1;
+
+ /* I2C attach to device */
+ i2c_set_clientdata(client, ir);
+
+ /* initialise RX device */
+ if (have_rx) {
+ DECLARE_COMPLETION(tn);
+ memcpy(&ir->c_rx, client, sizeof(struct i2c_client));
+
+ ir->c_rx.addr = 0x71;
+ strlcpy(ir->c_rx.name, ZILOG_HAUPPAUGE_IR_RX_NAME,
+ I2C_NAME_SIZE);
+
+ /* try to fire up polling thread */
+ ir->t_notify = &tn;
+ ir->task = kthread_run(lirc_thread, ir, "lirc_zilog");
+ if (IS_ERR(ir->task)) {
+ ret = PTR_ERR(ir->task);
+ zilog_error("lirc_register_driver: cannot run "
+ "poll thread %d\n", ret);
+ goto err;
+ }
+ wait_for_completion(&tn);
+ ir->t_notify = NULL;
+ ir->have_rx = 1;
+ }
+
+ /* initialise TX device */
+ if (have_tx) {
+ memcpy(&ir->c_tx, client, sizeof(struct i2c_client));
+ ir->c_tx.addr = 0x70;
+ strlcpy(ir->c_tx.name, ZILOG_HAUPPAUGE_IR_TX_NAME,
+ I2C_NAME_SIZE);
+ ir->have_tx = 1;
+ }
+
+ /* set lirc_dev stuff */
+ ir->l.code_length = 13;
+ ir->l.rbuf = &ir->buf;
+ ir->l.fops = &lirc_fops;
+ ir->l.data = ir;
+ ir->l.minor = minor;
+ ir->l.dev = &adap->dev;
+ ir->l.sample_rate = 0;
+
+ /* register with lirc */
+ ir->l.minor = lirc_register_driver(&ir->l);
+ if (ir->l.minor < 0 || ir->l.minor >= MAX_IRCTL_DEVICES) {
+ zilog_error("ir_attach: \"minor\" must be between 0 and %d "
+ "(%d)!\n", MAX_IRCTL_DEVICES-1, ir->l.minor);
+ ret = -EBADRQC;
+ goto err;
+ }
+
+ /* store this for getting back in open() later on */
+ ir_devices[ir->l.minor] = ir;
+
+ /*
+ * if we have the tx device, load the 'firmware'. We do this
+ * after registering with lirc as otherwise hotplug seems to take
+ * 10s to create the lirc device.
+ */
+ if (have_tx) {
+ /* Special TX init */
+ ret = tx_init(ir);
+ if (ret != 0)
+ goto err;
+ }
+
+ return 0;
+
+err:
+ /* undo everything, hopefully... */
+ if (ir->c_rx.addr)
+ ir_remove(&ir->c_rx);
+ if (ir->c_tx.addr)
+ ir_remove(&ir->c_tx);
+ return ret;
+
+out_nodev:
+ zilog_error("no device found\n");
+ return -ENODEV;
+
+out_nomem:
+ zilog_error("memory allocation failure\n");
+ kfree(ir);
+ return -ENOMEM;
+}
+
+static int ir_command(struct i2c_client *client, unsigned int cmd, void *arg)
+{
+ /* nothing */
+ return 0;
+}
+
+static int __init zilog_init(void)
+{
+ int ret;
+
+ zilog_notify("Zilog/Hauppauge IR driver initializing\n");
+
+ mutex_init(&tx_data_lock);
+
+ request_module("firmware_class");
+
+ ret = i2c_add_driver(&driver);
+ if (ret)
+ zilog_error("initialization failed\n");
+ else
+ zilog_notify("initialization complete\n");
+
+ return ret;
+}
+
+static void __exit zilog_exit(void)
+{
+ i2c_del_driver(&driver);
+ /* if loaded */
+ fw_unload();
+ zilog_notify("Zilog/Hauppauge IR driver unloaded\n");
+}
+
+module_init(zilog_init);
+module_exit(zilog_exit);
+
+MODULE_DESCRIPTION("Zilog/Hauppauge infrared transmitter driver (i2c stack)");
+MODULE_AUTHOR("Gerd Knorr, Michal Kochanowicz, Christoph Bartelmus, "
+ "Ulrich Mueller, Stefan Jahn, Jerome Brock, Mark Weaver");
+MODULE_LICENSE("GPL");
+/* for compat with old name, which isn't all that accurate anymore */
+MODULE_ALIAS("lirc_pvr150");
+
+module_param(minor, int, 0444);
+MODULE_PARM_DESC(minor, "Preferred minor device number");
+
+module_param(debug, bool, 0644);
+MODULE_PARM_DESC(debug, "Enable debugging messages");
+
+module_param(disable_rx, bool, 0644);
+MODULE_PARM_DESC(disable_rx, "Disable the IR receiver device");
+
+module_param(disable_tx, bool, 0644);
+MODULE_PARM_DESC(disable_tx, "Disable the IR transmitter device");
diff --git a/drivers/staging/memrar/TODO b/drivers/staging/memrar/TODO
index 0087447d503..435e09ba44c 100644
--- a/drivers/staging/memrar/TODO
+++ b/drivers/staging/memrar/TODO
@@ -1,7 +1,7 @@
RAR Handler (memrar) Driver TODO Items
======================================
-Maintainer: Ossama Othman <ossama.othman@intel.com>
+Maintainer: Eugene Epshteyn <eugene.epshteyn@intel.com>
memrar.h
--------
diff --git a/drivers/staging/memrar/memrar-abi b/drivers/staging/memrar/memrar-abi
index 98a6bb158ba..c23fc996a43 100644
--- a/drivers/staging/memrar/memrar-abi
+++ b/drivers/staging/memrar/memrar-abi
@@ -1,7 +1,7 @@
What: /dev/memrar
Date: March 2010
-KernelVersion: Kernel version this feature first showed up in.
-Contact: Ossama Othman <ossama.othman@intel.com>
+KernelVersion: 2.6.34
+Contact: Eugene Epshteyn <eugene.epshteyn@intel.com>
Description: The Intel Moorestown Restricted Access Region (RAR)
Handler driver exposes an ioctl() based interface that
allows a user to reserve and release blocks of RAR
diff --git a/drivers/staging/memrar/memrar_handler.c b/drivers/staging/memrar/memrar_handler.c
index efa7fd62d39..a98b3f1f11e 100644
--- a/drivers/staging/memrar/memrar_handler.c
+++ b/drivers/staging/memrar/memrar_handler.c
@@ -47,8 +47,7 @@
#include <linux/mm.h>
#include <linux/ioport.h>
#include <linux/io.h>
-
-#include "../rar_register/rar_register.h"
+#include <linux/rar_register.h>
#include "memrar.h"
#include "memrar_allocator.h"
@@ -279,19 +278,10 @@ static int memrar_init_rar_resources(int rarnum, char const *devname)
BUG_ON(!memrar_is_valid_rar_type(rarnum));
BUG_ON(rar->allocated);
- mutex_init(&rar->lock);
-
- /*
- * Initialize the process table before we reach any
- * code that exit on failure since the finalization
- * code requires an initialized list.
- */
- INIT_LIST_HEAD(&rar->buffers.list);
-
if (rar_get_address(rarnum, &low, &high) != 0)
/* No RAR is available. */
return -ENODEV;
-
+
if (low == 0 || high == 0) {
rar->base = 0;
rar->length = 0;
@@ -311,7 +301,8 @@ static int memrar_init_rar_resources(int rarnum, char const *devname)
/* Claim RAR memory as our own. */
if (request_mem_region(low, rar->length, devname) == NULL) {
rar->length = 0;
- pr_err("%s: Unable to claim RAR[%d] memory.\n", devname, rarnum);
+ pr_err("%s: Unable to claim RAR[%d] memory.\n",
+ devname, rarnum);
pr_err("%s: RAR[%d] disabled.\n", devname, rarnum);
return -EBUSY;
}
@@ -347,7 +338,7 @@ static int memrar_init_rar_resources(int rarnum, char const *devname)
}
pr_info("%s: BRAR[%d] bus address range = [0x%lx, 0x%lx]\n",
- devname, rarnum, (unsigned long) low, (unsigned long) high);
+ devname, rarnum, (unsigned long) low, (unsigned long) high);
pr_info("%s: BRAR[%d] size = %zu KiB\n",
devname, rarnum, rar->allocator->capacity / 1024);
@@ -531,7 +522,7 @@ static long memrar_get_stat(struct RAR_stat *r)
{
struct memrar_allocator *allocator;
- if (!memrar_is_valid_rar_type(r->type))
+ if (!memrar_is_valid_rar_type(r->type))
return -EINVAL;
if (!memrars[r->type].allocated)
@@ -940,9 +931,28 @@ static int memrar_registration_callback(unsigned long rar)
static int __init memrar_init(void)
{
int err;
+ int i;
printk(banner);
+ /*
+ * Some delayed initialization is performed in this driver.
+ * Make sure resources that are used during driver clean-up
+ * (e.g. during driver's release() function) are fully
+ * initialized before first use. This is particularly
+ * important for the case when the delayed initialization
+ * isn't completed, leaving behind a partially initialized
+ * driver.
+ *
+ * Such a scenario can occur when RAR is not available on the
+ * platform, and the driver is release()d.
+ */
+ for (i = 0; i != ARRAY_SIZE(memrars); ++i) {
+ struct memrar_rar_info * const rar = &memrars[i];
+ mutex_init(&rar->lock);
+ INIT_LIST_HEAD(&rar->buffers.list);
+ }
+
err = misc_register(&memrar_miscdev);
if (err)
return err;
diff --git a/drivers/staging/msm/Kconfig b/drivers/staging/msm/Kconfig
index c57039f2060..c5309eec58f 100644
--- a/drivers/staging/msm/Kconfig
+++ b/drivers/staging/msm/Kconfig
@@ -46,21 +46,11 @@ config FB_MSM_LCDC_PRISM_WVGA
select FB_MSM_LCDC_PANEL
default n
-config FB_MSM_LCDC_ST1_WXGA
- bool
- select FB_MSM_LCDC_PANEL
- default n
-
config FB_MSM_LCDC_ST15_WXGA
bool
select FB_MSM_LCDC_PANEL
default n
-config FB_MSM_LCDC_WXGA
- bool
- select FB_MSM_LCDC_PANEL
- default n
-
choice
prompt "LCD Panel"
default FB_MSM_LCDC_ST15_PANEL
diff --git a/drivers/staging/msm/Makefile b/drivers/staging/msm/Makefile
index 98a0ce177cb..bb3606faf20 100644
--- a/drivers/staging/msm/Makefile
+++ b/drivers/staging/msm/Makefile
@@ -61,14 +61,12 @@ obj-y += mddi_prism.o
obj-y += mddi_toshiba.o
obj-y += mddi_toshiba_vga.o
obj-y += mddi_toshiba_wvga_pt.o
-obj-y += mddi_toshiba_wvga.o
obj-y += mddi_sharp.o
else
obj-$(CONFIG_FB_MSM_MDDI_PRISM_WVGA) += mddi_prism.o
obj-$(CONFIG_FB_MSM_MDDI_TOSHIBA_COMMON) += mddi_toshiba.o
obj-$(CONFIG_FB_MSM_MDDI_TOSHIBA_COMMON_VGA) += mddi_toshiba_vga.o
obj-$(CONFIG_FB_MSM_MDDI_TOSHIBA_WVGA_PORTRAIT) += mddi_toshiba_wvga_pt.o
-obj-$(CONFIG_FB_MSM_MDDI_TOSHIBA_WVGA) += mddi_toshiba_wvga.o
obj-$(CONFIG_FB_MSM_MDDI_SHARP_QVGA_128x128) += mddi_sharp.o
endif
@@ -76,11 +74,8 @@ obj-$(CONFIG_FB_MSM_LCDC_PANEL) += lcdc_panel.o
obj-$(CONFIG_FB_MSM_LCDC_PRISM_WVGA) += lcdc_prism.o
obj-$(CONFIG_FB_MSM_LCDC_EXTERNAL_WXGA) += lcdc_external.o
obj-$(CONFIG_FB_MSM_LCDC_GORDON_VGA) += lcdc_gordon.o
-obj-$(CONFIG_FB_MSM_LCDC_WXGA) += lcdc_wxga.o
obj-$(CONFIG_FB_MSM_LCDC_TOSHIBA_WVGA_PT) += lcdc_toshiba_wvga_pt.o
obj-$(CONFIG_FB_MSM_LCDC_SHARP_WVGA_PT) += lcdc_sharp_wvga_pt.o
-obj-$(CONFIG_FB_MSM_LCDC_GRAPEFRUIT_VGA) += lcdc_grapefruit.o
-obj-$(CONFIG_FB_MSM_LCDC_ST1_WXGA) += lcdc_st1_wxga.o
obj-$(CONFIG_FB_MSM_LCDC_ST15_WXGA) += lcdc_st15.o
obj-$(CONFIG_FB_MSM_HDMI_SII_EXTERNAL_720P) += hdmi_sii9022.o
diff --git a/drivers/staging/msm/lcdc_grapefruit.c b/drivers/staging/msm/lcdc_grapefruit.c
deleted file mode 100644
index 7284649ea0a..00000000000
--- a/drivers/staging/msm/lcdc_grapefruit.c
+++ /dev/null
@@ -1,60 +0,0 @@
-/* Copyright (c) 2009, Code Aurora Forum. 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 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA.
- */
-
-#include "msm_fb.h"
-
-#ifdef CONFIG_FB_MSM_TRY_MDDI_CATCH_LCDC_PRISM
-#include "mddihosti.h"
-#endif
-
-static int __init lcdc_grapefruit_init(void)
-{
- int ret;
- struct msm_panel_info pinfo;
-
-#ifdef CONFIG_FB_MSM_TRY_MDDI_CATCH_LCDC_PRISM
- if (msm_fb_detect_client("lcdc_grapefruit_vga"))
- return 0;
-#endif
-
- pinfo.xres = 1024;
- pinfo.yres = 600;
- pinfo.type = LCDC_PANEL;
- pinfo.pdest = DISPLAY_1;
- pinfo.wait_cycle = 0;
- pinfo.bpp = 18;
- pinfo.fb_num = 2;
- pinfo.clk_rate = 40000000;
-
- pinfo.lcdc.h_back_porch = 88;
- pinfo.lcdc.h_front_porch = 40;
- pinfo.lcdc.h_pulse_width = 128;
- pinfo.lcdc.v_back_porch = 23;
- pinfo.lcdc.v_front_porch = 1;
- pinfo.lcdc.v_pulse_width = 4;
- pinfo.lcdc.border_clr = 0; /* blk */
- pinfo.lcdc.underflow_clr = 0xff; /* blue */
- pinfo.lcdc.hsync_skew = 0;
-
- ret = lcdc_device_register(&pinfo);
- if (ret)
- printk(KERN_ERR "%s: failed to register device!\n", __func__);
-
- return ret;
-}
-
-module_init(lcdc_grapefruit_init);
diff --git a/drivers/staging/msm/lcdc_st1_wxga.c b/drivers/staging/msm/lcdc_st1_wxga.c
deleted file mode 100644
index 73760019cf2..00000000000
--- a/drivers/staging/msm/lcdc_st1_wxga.c
+++ /dev/null
@@ -1,54 +0,0 @@
-/* Copyright (c) 2009, Code Aurora Forum. 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 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA.
- */
-
-#include "msm_fb.h"
-
-static int __init lcdc_st1_wxga_init(void)
-{
- int ret;
- struct msm_panel_info pinfo;
-
- if (msm_fb_detect_client("lcdc_st1_wxga"))
- return 0;
-
- pinfo.xres = 1280;
- pinfo.yres = 720;
- pinfo.type = LCDC_PANEL;
- pinfo.pdest = DISPLAY_1;
- pinfo.wait_cycle = 0;
- pinfo.bpp = 18;
- pinfo.fb_num = 2;
- pinfo.clk_rate = 74250000;
-
- pinfo.lcdc.h_back_porch = 124;
- pinfo.lcdc.h_front_porch = 110;
- pinfo.lcdc.h_pulse_width = 136;
- pinfo.lcdc.v_back_porch = 19;
- pinfo.lcdc.v_front_porch = 5;
- pinfo.lcdc.v_pulse_width = 6;
- pinfo.lcdc.border_clr = 0; /* blk */
- pinfo.lcdc.underflow_clr = 0xff; /* blue */
- pinfo.lcdc.hsync_skew = 0;
-
- ret = lcdc_device_register(&pinfo);
- if (ret)
- printk(KERN_ERR "%s: failed to register device!\n", __func__);
-
- return ret;
-}
-
-module_init(lcdc_st1_wxga_init);
diff --git a/drivers/staging/msm/lcdc_wxga.c b/drivers/staging/msm/lcdc_wxga.c
deleted file mode 100644
index 202c92c0ef5..00000000000
--- a/drivers/staging/msm/lcdc_wxga.c
+++ /dev/null
@@ -1,56 +0,0 @@
-/* Copyright (c) 2009, Code Aurora Forum. 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 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA.
- */
-
-#include "msm_fb.h"
-
-static int __init lcdc_wxga_init(void)
-{
- int ret;
- struct msm_panel_info pinfo;
-
-#ifdef CONFIG_FB_MSM_MDDI_AUTO_DETECT
- if (msm_fb_detect_client("lcdc_wxga"))
- return 0;
-#endif
-
- pinfo.xres = 1280;
- pinfo.yres = 720;
- pinfo.type = LCDC_PANEL;
- pinfo.pdest = DISPLAY_1;
- pinfo.wait_cycle = 0;
- pinfo.bpp = 24;
- pinfo.fb_num = 2;
- pinfo.clk_rate = 74250000;
-
- pinfo.lcdc.h_back_porch = 124;
- pinfo.lcdc.h_front_porch = 110;
- pinfo.lcdc.h_pulse_width = 136;
- pinfo.lcdc.v_back_porch = 19;
- pinfo.lcdc.v_front_porch = 5;
- pinfo.lcdc.v_pulse_width = 6;
- pinfo.lcdc.border_clr = 0; /* blk */
- pinfo.lcdc.underflow_clr = 0xff; /* blue */
- pinfo.lcdc.hsync_skew = 0;
-
- ret = lcdc_device_register(&pinfo);
- if (ret)
- printk(KERN_ERR "%s: failed to register device!\n", __func__);
-
- return ret;
-}
-
-module_init(lcdc_wxga_init);
diff --git a/drivers/staging/msm/mddi_toshiba_wvga.c b/drivers/staging/msm/mddi_toshiba_wvga.c
deleted file mode 100644
index 557b0f08faf..00000000000
--- a/drivers/staging/msm/mddi_toshiba_wvga.c
+++ /dev/null
@@ -1,63 +0,0 @@
-/* Copyright (c) 2009, Code Aurora Forum. 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 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA.
- */
-
-#include "msm_fb.h"
-#include "mddihost.h"
-#include "mddi_toshiba.h"
-
-static int __init mddi_toshiba_wvga_init(void)
-{
- int ret;
- struct msm_panel_info pinfo;
-
-#ifdef CONFIG_FB_MSM_MDDI_AUTO_DETECT
- if (msm_fb_detect_client("mddi_toshiba_wvga"))
- return 0;
-#endif
-
- pinfo.xres = 800;
- pinfo.yres = 480;
- pinfo.pdest = DISPLAY_2;
- pinfo.type = MDDI_PANEL;
- pinfo.mddi.vdopkt = MDDI_DEFAULT_PRIM_PIX_ATTR;
- pinfo.wait_cycle = 0;
- pinfo.bpp = 18;
- pinfo.lcd.vsync_enable = TRUE;
- pinfo.lcd.refx100 = 6118;
- pinfo.lcd.v_back_porch = 6;
- pinfo.lcd.v_front_porch = 0;
- pinfo.lcd.v_pulse_width = 0;
- pinfo.lcd.hw_vsync_mode = FALSE;
- pinfo.lcd.vsync_notifier_period = (1 * HZ);
- pinfo.bl_max = 4;
- pinfo.bl_min = 1;
- pinfo.clk_rate = 192000000;
- pinfo.clk_min = 190000000;
- pinfo.clk_max = 200000000;
- pinfo.fb_num = 2;
-
- ret = mddi_toshiba_device_register(&pinfo, TOSHIBA_VGA_PRIM,
- LCD_TOSHIBA_2P4_WVGA);
- if (ret) {
- printk(KERN_ERR "%s: failed to register device!\n", __func__);
- return ret;
- }
-
- return ret;
-}
-
-module_init(mddi_toshiba_wvga_init);
diff --git a/drivers/staging/msm/mddihost.h b/drivers/staging/msm/mddihost.h
index 20b817841c4..c46f24aea25 100644
--- a/drivers/staging/msm/mddihost.h
+++ b/drivers/staging/msm/mddihost.h
@@ -44,8 +44,6 @@
#include <asm/system.h>
#include <asm/mach-types.h>
-#include <linux/types.h>
-#include <linux/dma-mapping.h>
#include "msm_fb_panel.h"
diff --git a/drivers/staging/msm/mdp4_debugfs.c b/drivers/staging/msm/mdp4_debugfs.c
index 844d46775ec..36954e89478 100644
--- a/drivers/staging/msm/mdp4_debugfs.c
+++ b/drivers/staging/msm/mdp4_debugfs.c
@@ -63,13 +63,6 @@ DEFINE_SIMPLE_ATTRIBUTE(
"%llx\n");
-static int mdp4_debugfs_open(struct inode *inode, struct file *file)
-{
- /* non-seekable */
- file->f_mode &= ~(FMODE_LSEEK | FMODE_PREAD | FMODE_PWRITE);
- return 0;
-}
-
static int mdp4_debugfs_release(struct inode *inode, struct file *file)
{
return 0;
@@ -144,10 +137,11 @@ static ssize_t mdp4_debugfs_read(
}
static const struct file_operations mdp4_debugfs_fops = {
- .open = mdp4_debugfs_open,
+ .open = nonseekable_open,
.release = mdp4_debugfs_release,
.read = mdp4_debugfs_read,
.write = mdp4_debugfs_write,
+ .llseek = no_llseek,
};
int mdp4_debugfs_init(void)
diff --git a/drivers/staging/msm/mdp4_overlay.c b/drivers/staging/msm/mdp4_overlay.c
index 304bb829763..de284c28faa 100644
--- a/drivers/staging/msm/mdp4_overlay.c
+++ b/drivers/staging/msm/mdp4_overlay.c
@@ -874,8 +874,8 @@ struct mdp4_overlay_pipe *mdp4_overlay_pipe_alloc(void)
if (pipe->pipe_ndx == 0) {
pipe->pipe_ndx = i + 1; /* start from 1 */
init_completion(&pipe->comp);
- printk(KERN_INFO "mdp4_overlay_pipe_alloc: pipe=%x ndx=%d\n",
- (int)pipe, pipe->pipe_ndx);
+ printk(KERN_INFO "mdp4_overlay_pipe_alloc: pipe=%p ndx=%d\n",
+ pipe, pipe->pipe_ndx);
return pipe;
}
pipe++;
@@ -887,8 +887,8 @@ struct mdp4_overlay_pipe *mdp4_overlay_pipe_alloc(void)
void mdp4_overlay_pipe_free(struct mdp4_overlay_pipe *pipe)
{
- printk(KERN_INFO "mdp4_overlay_pipe_free: pipe=%x ndx=%d\n",
- (int)pipe, pipe->pipe_ndx);
+ printk(KERN_INFO "mdp4_overlay_pipe_free: pipe=%p ndx=%d\n",
+ pipe, pipe->pipe_ndx);
memset(pipe, 0, sizeof(*pipe));
}
diff --git a/drivers/staging/msm/msm_fb_def.h b/drivers/staging/msm/msm_fb_def.h
index 6de44093742..c5f9e9e670f 100644
--- a/drivers/staging/msm/msm_fb_def.h
+++ b/drivers/staging/msm/msm_fb_def.h
@@ -50,15 +50,11 @@
#include <linux/debugfs.h>
#include <linux/console.h>
-#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/time.h>
-#include <linux/init.h>
#include <linux/interrupt.h>
-#include "linux/proc_fs.h"
#include <mach/hardware.h>
#include <linux/io.h>
-#include <linux/fb.h>
#include <asm/system.h>
#include <asm/mach-types.h>
#include <linux/platform_device.h>
diff --git a/drivers/staging/msm/staging-devices.c b/drivers/staging/msm/staging-devices.c
index 0f8ec3e2601..861f3307231 100644
--- a/drivers/staging/msm/staging-devices.c
+++ b/drivers/staging/msm/staging-devices.c
@@ -18,7 +18,6 @@
#include "msm_mdp.h"
#include "memory_ll.h"
//#include "android_pmem.h"
-#include <mach/board.h>
#ifdef CONFIG_MSM_SOC_REV_A
#define MSM_SMI_BASE 0xE0000000
@@ -115,17 +114,7 @@ static int msm_fb_detect_panel(const char *name)
} else if ((machine_is_qsd8x50_surf() || machine_is_qsd8x50a_surf())
&& !strcmp(name, "lcdc_external"))
ret = 0;
- else if (0 /*machine_is_qsd8x50_grapefruit() */) {
- if (!strcmp(name, "lcdc_grapefruit_vga"))
- ret = 0;
- else
- ret = -ENODEV;
- } else if (machine_is_qsd8x50_st1()) {
- if (!strcmp(name, "lcdc_st1_wxga"))
- ret = 0;
- else
- ret = -ENODEV;
- } else if (machine_is_qsd8x50a_st1_5()) {
+ else if (machine_is_qsd8x50a_st1_5()) {
if (!strcmp(name, "lcdc_st15") ||
!strcmp(name, "hdmi_sii9022"))
ret = 0;
diff --git a/drivers/staging/octeon/cvmx-cmd-queue.c b/drivers/staging/octeon/cvmx-cmd-queue.c
index 976227b0127..e9809d37516 100644
--- a/drivers/staging/octeon/cvmx-cmd-queue.c
+++ b/drivers/staging/octeon/cvmx-cmd-queue.c
@@ -140,21 +140,21 @@ cvmx_cmd_queue_result_t cvmx_cmd_queue_initialize(cvmx_cmd_queue_id_t queue_id,
if (qstate->base_ptr_div128) {
if (max_depth != (int)qstate->max_depth) {
cvmx_dprintf("ERROR: cvmx_cmd_queue_initialize: "
- "Queue already initalized with different "
+ "Queue already initialized with different "
"max_depth (%d).\n",
(int)qstate->max_depth);
return CVMX_CMD_QUEUE_INVALID_PARAM;
}
if (fpa_pool != qstate->fpa_pool) {
cvmx_dprintf("ERROR: cvmx_cmd_queue_initialize: "
- "Queue already initalized with different "
+ "Queue already initialized with different "
"FPA pool (%u).\n",
qstate->fpa_pool);
return CVMX_CMD_QUEUE_INVALID_PARAM;
}
if ((pool_size >> 3) - 1 != qstate->pool_size_m1) {
cvmx_dprintf("ERROR: cvmx_cmd_queue_initialize: "
- "Queue already initalized with different "
+ "Queue already initialized with different "
"FPA pool size (%u).\n",
(qstate->pool_size_m1 + 1) << 3);
return CVMX_CMD_QUEUE_INVALID_PARAM;
diff --git a/drivers/staging/octeon/cvmx-fau.h b/drivers/staging/octeon/cvmx-fau.h
index 29bdce66cdf..a6939fc8ba1 100644
--- a/drivers/staging/octeon/cvmx-fau.h
+++ b/drivers/staging/octeon/cvmx-fau.h
@@ -299,7 +299,7 @@ cvmx_fau_tagwait_fetch_and_add8(cvmx_fau_reg_8_t reg, int8_t value)
/**
* Builds I/O data for async operations
*
- * @scraddr: Scratch pad byte addres to write to. Must be 8 byte aligned
+ * @scraddr: Scratch pad byte address to write to. Must be 8 byte aligned
* @value: Signed value to add.
* Note: When performing 32 and 64 bit access, only the low
* 22 bits are available.
diff --git a/drivers/staging/octeon/ethernet-mdio.c b/drivers/staging/octeon/ethernet-mdio.c
index 7e0be8d00dc..10a82ef3021 100644
--- a/drivers/staging/octeon/ethernet-mdio.c
+++ b/drivers/staging/octeon/ethernet-mdio.c
@@ -113,7 +113,7 @@ int cvm_oct_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
if (!priv->phydev)
return -EINVAL;
- return phy_mii_ioctl(priv->phydev, if_mii(rq), cmd);
+ return phy_mii_ioctl(priv->phydev, rq, cmd);
}
static void cvm_oct_adjust_link(struct net_device *dev)
diff --git a/drivers/staging/octeon/ethernet-spi.c b/drivers/staging/octeon/ethernet-spi.c
index b58b8971f93..97082542188 100644
--- a/drivers/staging/octeon/ethernet-spi.c
+++ b/drivers/staging/octeon/ethernet-spi.c
@@ -294,6 +294,8 @@ int cvm_oct_spi_init(struct net_device *dev)
if (number_spi_ports == 0) {
r = request_irq(OCTEON_IRQ_RML, cvm_oct_spi_rml_interrupt,
IRQF_SHARED, "SPI", &number_spi_ports);
+ if (r)
+ return r;
}
number_spi_ports++;
diff --git a/drivers/staging/otus/80211core/ctxrx.c b/drivers/staging/otus/80211core/ctxrx.c
index a127196260e..135167d23d0 100644
--- a/drivers/staging/otus/80211core/ctxrx.c
+++ b/drivers/staging/otus/80211core/ctxrx.c
@@ -3117,7 +3117,7 @@ u16_t zfWlanRxFilter(zdev_t* dev, zbuf_t* buf)
index = (src[2]+up) & (ZM_FILTER_TABLE_ROW-1);
- /* TBD : filter frame with source address == own MAC adress */
+ /* TBD : filter frame with source address == own MAC address */
if ((wd->macAddr[0] == src[0]) && (wd->macAddr[1] == src[1])
&& (wd->macAddr[2] == src[2]))
{
diff --git a/drivers/staging/otus/TODO b/drivers/staging/otus/TODO
index 4caf026a491..6fea974fcc9 100644
--- a/drivers/staging/otus/TODO
+++ b/drivers/staging/otus/TODO
@@ -2,15 +2,7 @@ I'm hesitant to add a TODO file here, as the wireless developers would
really have people help them out on the "clean" ar9170 driver that can
be found at the linux-wireless developer site.
-But, if you wish to clean up this driver instead, here's a short list of
-things that need to be done to get it into a more mergable shape:
-
-TODO:
- - checkpatch.pl cleanups
- - sparse cleanups
- - port to in-kernel 80211 stack
- - review by the wireless developer community
-
-Please send any patches to Greg Kroah-Hartman <greg@kroah.com> and
-Luis Rodriguez <Luis.Rodriguez@Atheros.com> and the
-otus-devel@lists.madwifi-project.org mailing list.
+This driver is unmaintained and its only purpose is as a
+source of documentation for developers working on ar9170 and carl9170.
+Once carl9170 gets 11n support and merged upstream then this driver
+can be removed.
diff --git a/drivers/staging/otus/apdbg.c b/drivers/staging/otus/apdbg.c
index b59028e7e33..09415a6b93c 100644
--- a/drivers/staging/otus/apdbg.c
+++ b/drivers/staging/otus/apdbg.c
@@ -90,28 +90,6 @@ struct zdap_ioctl {
#endif
-static char hex(char v)
-{
- if (isdigit(v))
- return v - '0';
- else if (isxdigit(v))
- return tolower(v) - 'a' + 10;
- else
- return 0;
-}
-
-static unsigned char asctohex(char *str)
-{
- unsigned char value;
-
- value = hex(*str) & 0x0f;
- value = value << 4;
- str++;
- value |= hex(*str) & 0x0f;
-
- return value;
-}
-
char *prgname;
int set_ioctl(int sock, struct ifreq *req)
@@ -180,7 +158,7 @@ int main(int argc, char **argv)
if (argc < 3) {
fprintf(stderr, "%s: usage is \"%s <ifname> <operation>"
"[<address>] [<value>]\"\n", prgname, prgname);
- fprintf(stderr, "valid operation : read, write, mem, reg, \n");
+ fprintf(stderr, "valid operation : read, write, mem, reg,\n");
fprintf(stderr, " : txd, rxd, rmem, wmem\n");
fprintf(stderr, " : dmat, regt, test\n");
diff --git a/drivers/staging/otus/hal/hpani.c b/drivers/staging/otus/hal/hpani.c
index f53e483b394..9b9420c75d4 100644
--- a/drivers/staging/otus/hal/hpani.c
+++ b/drivers/staging/otus/hal/hpani.c
@@ -72,7 +72,6 @@ s32_t BEACON_RSSI(zdev_t *dev)
void zfHpAniAttach(zdev_t *dev)
{
-#define N(a) (sizeof(a) / sizeof(a[0]))
u32_t i;
struct zsHpPriv *HpPriv;
@@ -125,7 +124,6 @@ void zfHpAniAttach(zdev_t *dev)
HpPriv->stats.ast_nodestats.ns_avgbrssi = ZM_RSSI_DUMMY_MARKER;
HpPriv->stats.ast_nodestats.ns_avgrssi = ZM_RSSI_DUMMY_MARKER;
HpPriv->stats.ast_nodestats.ns_avgtxrssi = ZM_RSSI_DUMMY_MARKER;
-#undef N
}
/*
@@ -133,7 +131,6 @@ void zfHpAniAttach(zdev_t *dev)
*/
u8_t zfHpAniControl(zdev_t *dev, ZM_HAL_ANI_CMD cmd, int param)
{
-#define N(a) (sizeof(a)/sizeof(a[0]))
typedef s32_t TABLE[];
struct zsHpPriv *HpPriv;
struct zsAniState *aniState;
@@ -148,9 +145,9 @@ u8_t zfHpAniControl(zdev_t *dev, ZM_HAL_ANI_CMD cmd, int param)
{
u32_t level = param;
- if (level >= N(HpPriv->totalSizeDesired)) {
+ if (level >= ARRAY_SIZE(HpPriv->totalSizeDesired)) {
zm_debug_msg1("level out of range, desired level : ", level);
- zm_debug_msg1("max level : ", N(HpPriv->totalSizeDesired));
+ zm_debug_msg1("max level : ", ARRAY_SIZE(HpPriv->totalSizeDesired));
return FALSE;
}
@@ -260,10 +257,10 @@ u8_t zfHpAniControl(zdev_t *dev, ZM_HAL_ANI_CMD cmd, int param)
const TABLE firstep = { 0, 4, 8 };
u32_t level = param;
- if (level >= N(firstep))
+ if (level >= ARRAY_SIZE(firstep))
{
zm_debug_msg1("level out of range, desired level : ", level);
- zm_debug_msg1("max level : ", N(firstep));
+ zm_debug_msg1("max level : ", ARRAY_SIZE(firstep));
return FALSE;
}
zfDelayWriteInternalReg(dev, AR_PHY_FIND_SIG,
@@ -283,10 +280,10 @@ u8_t zfHpAniControl(zdev_t *dev, ZM_HAL_ANI_CMD cmd, int param)
const TABLE cycpwrThr1 = { 2, 4, 6, 8, 10, 12, 14, 16 };
u32_t level = param;
- if (level >= N(cycpwrThr1))
+ if (level >= ARRAY_SIZE(cycpwrThr1))
{
zm_debug_msg1("level out of range, desired level : ", level);
- zm_debug_msg1("max level : ", N(cycpwrThr1));
+ zm_debug_msg1("max level : ", ARRAY_SIZE(cycpwrThr1));
return FALSE;
}
zfDelayWriteInternalReg(dev, AR_PHY_TIMING5,
@@ -335,7 +332,6 @@ u8_t zfHpAniControl(zdev_t *dev, ZM_HAL_ANI_CMD cmd, int param)
return FALSE;
}
return TRUE;
-#undef N
}
void zfHpAniRestart(zdev_t* dev)
diff --git a/drivers/staging/otus/hal/hpmain.c b/drivers/staging/otus/hal/hpmain.c
index 5f412e02045..6d2d358d5ca 100644
--- a/drivers/staging/otus/hal/hpmain.c
+++ b/drivers/staging/otus/hal/hpmain.c
@@ -430,7 +430,7 @@ void zfInitPhy(zdev_t* dev, u32_t frequency, u8_t bw40)
* Register setting by mode
*/
- entries = sizeof(ar5416Modes) / sizeof(*ar5416Modes);
+ entries = ARRAY_SIZE(ar5416Modes);
zm_msg1_scan(ZM_LV_2, "Modes register setting entries=", entries);
for (i=0; i<entries; i++)
{
@@ -496,7 +496,7 @@ void zfInitPhy(zdev_t* dev, u32_t frequency, u8_t bw40)
/*
* Common Register setting
*/
- entries = sizeof(ar5416Common) / sizeof(*ar5416Common);
+ entries = ARRAY_SIZE(ar5416Common);
for (i=0; i<entries; i++)
{
reg_write(ar5416Common[i][0], ar5416Common[i][1]);
@@ -506,7 +506,7 @@ void zfInitPhy(zdev_t* dev, u32_t frequency, u8_t bw40)
/*
* RF Gain setting by freqIndex
*/
- entries = sizeof(ar5416BB_RfGain) / sizeof(*ar5416BB_RfGain);
+ entries = ARRAY_SIZE(ar5416BB_RfGain);
for (i=0; i<entries; i++)
{
reg_write(ar5416BB_RfGain[i][0], ar5416BB_RfGain[i][freqIndex]);
@@ -963,7 +963,6 @@ u32_t reverse_bits(u32_t chan_sel)
/* Bank 0 1 2 3 5 6 7 */
void zfSetRfRegs(zdev_t* dev, u32_t frequency)
{
- u16_t entries;
u16_t freqIndex = 0;
u16_t i;
@@ -984,33 +983,28 @@ void zfSetRfRegs(zdev_t* dev, u32_t frequency)
}
#if 1
- entries = sizeof(otusBank) / sizeof(*otusBank);
- for (i=0; i<entries; i++)
+ for (i=0; i<ARRAY_SIZE(otusBank); i++)
{
reg_write(otusBank[i][0], otusBank[i][freqIndex]);
}
#else
/* Bank0 */
- entries = sizeof(ar5416Bank0) / sizeof(*ar5416Bank0);
- for (i=0; i<entries; i++)
+ for (i=0; i<ARRAY_SIZE(ar5416Bank0); i++)
{
reg_write(ar5416Bank0[i][0], ar5416Bank0[i][1]);
}
/* Bank1 */
- entries = sizeof(ar5416Bank1) / sizeof(*ar5416Bank1);
- for (i=0; i<entries; i++)
+ for (i=0; i<ARRAY_SIZE(ar5416Bank1); i++)
{
reg_write(ar5416Bank1[i][0], ar5416Bank1[i][1]);
}
/* Bank2 */
- entries = sizeof(ar5416Bank2) / sizeof(*ar5416Bank2);
- for (i=0; i<entries; i++)
+ for (i=0; i<ARRAY_SIZE(ar5416Bank2); i++)
{
reg_write(ar5416Bank2[i][0], ar5416Bank2[i][1]);
}
/* Bank3 */
- entries = sizeof(ar5416Bank3) / sizeof(*ar5416Bank3);
- for (i=0; i<entries; i++)
+ for (i=0; i<ARRAY_SIZE(ar5416Bank3); i++)
{
reg_write(ar5416Bank3[i][0], ar5416Bank3[i][freqIndex]);
}
@@ -1018,14 +1012,12 @@ void zfSetRfRegs(zdev_t* dev, u32_t frequency)
reg_write (0x98b0, 0x00000013);
reg_write (0x98e4, 0x00000002);
/* Bank6 */
- entries = sizeof(ar5416Bank6) / sizeof(*ar5416Bank6);
- for (i=0; i<entries; i++)
+ for (i=0; i<ARRAY_SIZE(ar5416Bank6); i++)
{
reg_write(ar5416Bank6[i][0], ar5416Bank6[i][freqIndex]);
}
/* Bank7 */
- entries = sizeof(ar5416Bank7) / sizeof(*ar5416Bank7);
- for (i=0; i<entries; i++)
+ for (i=0; i<ARRAY_SIZE(ar5416Bank7); i++)
{
reg_write(ar5416Bank7[i][0], ar5416Bank7[i][1]);
}
diff --git a/drivers/staging/otus/hal/hpreg.c b/drivers/staging/otus/hal/hpreg.c
index da3b7743387..9b04653c1c5 100644
--- a/drivers/staging/otus/hal/hpreg.c
+++ b/drivers/staging/otus/hal/hpreg.c
@@ -29,9 +29,6 @@
#include "hpreg.h"
#include "hpusb.h"
-/* used throughout this file... */
-#define N(a) (sizeof(a) / sizeof(a[0]))
-
#define HAL_MODE_11A_TURBO HAL_MODE_108A
#define HAL_MODE_11G_TURBO HAL_MODE_108G
@@ -1557,7 +1554,7 @@ u8_t GetWmRD(u16_t regionCode, u16_t channelFlag, REG_DOMAIN *rd)
u64_t flags = NO_REQ;
REG_DMN_PAIR_MAPPING *regPair = NULL;
- for (i = 0, found = 0; (i < N(regDomainPairs)) && (!found); i++) {
+ for (i = 0, found = 0; (i < ARRAY_SIZE(regDomainPairs)) && (!found); i++) {
if (regDomainPairs[i].regDmnEnum == regionCode) {
regPair = &regDomainPairs[i];
found = 1;
@@ -1581,7 +1578,7 @@ u8_t GetWmRD(u16_t regionCode, u16_t channelFlag, REG_DOMAIN *rd)
* unitary reg domain of the pair
*/
- for (i = 0 ; i < N(regDomains) ; i++) {
+ for (i = 0 ; i < ARRAY_SIZE(regDomains) ; i++) {
if (regDomains[i].regDmnEnum == regDmn) {
if (rd != NULL) {
zfMemoryCopy((u8_t *)rd, (u8_t *)&regDomains[i],
@@ -1653,7 +1650,7 @@ void zfHpGetRegulationTable(zdev_t *dev, u16_t regionCode, u16_t c_lo, u16_t c_h
zmw_enter_critical_section(dev);
- for (cm = modes; cm < &modes[N(modes)]; cm++) {
+ for (cm = modes; cm < &modes[ARRAY_SIZE(modes)]; cm++) {
u16_t c;
u64_t *channelBM = NULL;
REG_DOMAIN *rd = NULL;
@@ -1846,7 +1843,7 @@ void zfHpGetRegulationTablefromCountry(zdev_t *dev, u16_t CountryCode)
zmw_declare_for_critical_section();
- for (i = 0; i < N(allCountries); i++) {
+ for (i = 0; i < ARRAY_SIZE(allCountries); i++) {
if (CountryCode == allCountries[i].countryCode) {
RegDomain = allCountries[i].regDmnEnum;
@@ -1881,7 +1878,7 @@ u8_t zfHpGetRegulationTablefromISO(zdev_t *dev, u8_t *countryInfo, u8_t length)
strLen = 3; */
}
/* zm_debug_msg_s("Desired iso name = ", isoName); */
- for (i = 0; i < N(allCountries); i++) {
+ for (i = 0; i < ARRAY_SIZE(allCountries); i++) {
/* zm_debug_msg_s("Current iso name = ", allCountries[i].isoName); */
if (zfMemoryIsEqual((u8_t *)allCountries[i].isoName, (u8_t *)&countryInfo[2], length-1)) {
/* DbgPrint("Set current iso name = %s\n", allCountries[i].isoName); */
@@ -1937,7 +1934,7 @@ const char *zfHpGetisoNamefromregionCode(zdev_t *dev, u16_t regionCode)
{
u16_t i;
- for (i = 0; i < N(allCountries); i++) {
+ for (i = 0; i < ARRAY_SIZE(allCountries); i++) {
if (allCountries[i].regDmnEnum == regionCode)
return allCountries[i].isoName;
}
@@ -1953,7 +1950,7 @@ u16_t zfHpGetRegionCodeFromIsoName(zdev_t *dev, u8_t *countryIsoName)
/* if no matching item, return default */
regionCode = DEF_REGDMN;
- for (i = 0; i < N(allCountries); i++) {
+ for (i = 0; i < ARRAY_SIZE(allCountries); i++) {
if (zfMemoryIsEqual((u8_t *)allCountries[i].isoName, countryIsoName, 2)) {
regionCode = allCountries[i].regDmnEnum;
break;
diff --git a/drivers/staging/otus/ioctl.c b/drivers/staging/otus/ioctl.c
index a48c8e4a9ea..dc3066d2884 100644
--- a/drivers/staging/otus/ioctl.c
+++ b/drivers/staging/otus/ioctl.c
@@ -63,8 +63,7 @@
extern u16_t zfLnxGetVapId(zdev_t *dev);
-static const u32_t channel_frequency_11A[] =
-{
+static const u32_t channel_frequency_11A[] = {
/* Even element for Channel Number, Odd for Frequency */
36, 5180,
40, 5200,
@@ -507,7 +506,7 @@ int usbdrvwext_giwname(struct net_device *dev,
{
/* struct usbdrv_private *macp = dev->ml_priv; */
- strcpy(wrq->name, "IEEE 802.11-MIMO");
+ strcpy(wrq->name, "IEEE 802.11abgn");
return 0;
}
@@ -1361,7 +1360,7 @@ int usbdrvwext_giwpower(struct net_device *dev,
}
/*int usbdrvwext_setparam(struct net_device *dev, struct iw_request_info *info,
-* void *w, char *extra)
+* void *w, char *extra)
*{
* struct ieee80211vap *vap = dev->ml_priv;
* struct ieee80211com *ic = vap->iv_ic;
@@ -2261,10 +2260,10 @@ int usbdrv_wpa_ioctl(struct net_device *dev, struct athr_wlan_param *zdparm)
printk(KERN_ERR "wd->ap.wpaLen : % d\n", len);
/* DUMP WPA IE */
- for(ii = 0; ii < len;) {
+ for (ii = 0; ii < len;) {
printk(KERN_ERR "0x%02x ", wpaie[ii]);
- if((++ii % 16) == 0)
+ if ((++ii % 16) == 0)
printk(KERN_ERR "\n");
}
printk(KERN_ERR "\n");
@@ -2309,11 +2308,10 @@ int usbdrv_cenc_ioctl(struct net_device *dev, struct zydas_cenc_param *zdparm)
/* Get the AP Id */
apId = zfLnxGetVapId(dev);
- if (apId == 0xffff) {
+ if (apId == 0xffff)
apId = 0;
- } else {
+ else
apId = apId + 1;
- }
switch (zdparm->cmd) {
case ZM_CMD_CENC_SETCENC:
@@ -2334,15 +2332,15 @@ int usbdrv_cenc_ioctl(struct net_device *dev, struct zydas_cenc_param *zdparm)
printk(KERN_ERR "Key Index : % d\n", zdparm->u.crypt.keyid);
printk(KERN_ERR "Encryption key = ");
- for (ii = 0; ii < 16; ii++) {
+ for (ii = 0; ii < 16; ii++)
printk(KERN_ERR "0x%02x ", zdparm->u.crypt.key[ii]);
- }
+
printk(KERN_ERR "\n");
printk(KERN_ERR "MIC key = ");
- for(ii = 16; ii < ZM_CENC_KEY_SIZE; ii++) {
+ for (ii = 16; ii < ZM_CENC_KEY_SIZE; ii++)
printk(KERN_ERR "0x%02x ", zdparm->u.crypt.key[ii]);
- }
+
printk(KERN_ERR "\n");
/* Set up key information */
@@ -2424,7 +2422,7 @@ int usbdrv_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
break;
case SIOCSIWRTS:
err = usbdrv_ioctl_setrts(dev, &wrq->u.rts);
- if (! err)
+ if (!err)
changed = 1;
break;
/* set_auth */
@@ -2582,8 +2580,7 @@ int usbdrv_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
ZM_AUTH_MODE_WPA);
} else if ((macp->supIe[17] == 0xf) &&
(macp->supIe[18] == 0xac) &&
- (macp->supIe[19] == 0x2))
- {
+ (macp->supIe[19] == 0x2)) {
printk(KERN_ERR
"wd->sta.authMode = ZM_AUTH_MODE_WPA2PSK\n");
/* wd->sta.authMode = ZM_AUTH_MODE_WPA2PSK; */
@@ -2592,8 +2589,7 @@ int usbdrv_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
ZM_AUTH_MODE_WPA2PSK);
} else if ((macp->supIe[17] == 0xf) &&
(macp->supIe[18] == 0xac) &&
- (macp->supIe[19] == 0x1))
- {
+ (macp->supIe[19] == 0x1)) {
printk(KERN_ERR
"wd->sta.authMode = ZM_AUTH_MODE_WPA2\n");
/* wd->sta.authMode = ZM_AUTH_MODE_WPA2; */
@@ -2618,7 +2614,7 @@ int usbdrv_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
zfiWlanSetWepStatus(dev, ZM_ENCRYPTION_AES);
}
}
- //WPA2 or WPA2PSK
+ /*WPA2 or WPA2PSK*/
if ((macp->supIe[17] == 0xf) ||
(macp->supIe[18] == 0xac)) {
if (macp->supIe[13] == 0x2) {
@@ -2656,7 +2652,7 @@ int usbdrv_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
printk(KERN_ERR
"****************ZD_PARAM_COUNTERMEASURES : ");
- if(arg) {
+ if (arg) {
/* mCounterMeasureState=1; */
printk(KERN_ERR "enable\n");
} else {
@@ -2667,20 +2663,18 @@ int usbdrv_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
if (op == ZD_PARAM_DROPUNENCRYPTED) {
printk(KERN_ERR "ZD_PARAM_DROPUNENCRYPTED : ");
- if(arg) {
+ if (arg)
printk(KERN_ERR "enable\n");
- } else {
+ else
printk(KERN_ERR "disable\n");
- }
}
if (op == ZD_PARAM_AUTH_ALGS) {
printk(KERN_ERR "ZD_PARAM_AUTH_ALGS : ");
- if (arg == 0) {
+ if (arg == 0)
printk(KERN_ERR "OPEN_SYSTEM\n");
- } else {
+ else
printk(KERN_ERR "SHARED_KEY\n");
- }
}
if (op == ZD_PARAM_WPS_FILTER) {
printk(KERN_ERR "ZD_PARAM_WPS_FILTER : ");
@@ -2705,11 +2699,10 @@ int usbdrv_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
/* Get the AP Id */
apId = zfLnxGetVapId(dev);
- if (apId == 0xffff) {
+ if (apId == 0xffff)
apId = 0;
- } else {
+ else
apId = apId + 1;
- }
if (copy_from_user(&req_wpaie, ifr->ifr_data,
sizeof(struct ieee80211req_wpaie))) {
@@ -2721,10 +2714,10 @@ int usbdrv_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
for (j = 0; j < IEEE80211_ADDR_LEN; j++) {
if (macp->stawpaie[i].wpa_macaddr[j] !=
req_wpaie.wpa_macaddr[j])
- break;
+ break;
}
if (j == 6)
- break;
+ break;
}
if (i < ZM_OAL_MAX_STA_SUPPORT) {
diff --git a/drivers/staging/otus/wrap_sec.c b/drivers/staging/otus/wrap_sec.c
index 0b238e9999b..1fba7a98d52 100644
--- a/drivers/staging/otus/wrap_sec.c
+++ b/drivers/staging/otus/wrap_sec.c
@@ -36,7 +36,7 @@ extern int zfLnxCencSendMsg(struct sock *netlink_sk, u_int8_t *msg, int len);
u16_t zfLnxCencAsocNotify(zdev_t *dev, u16_t *macAddr, u8_t *body,
u16_t bodySize, u16_t port)
{
- struct usbdrv_private *macp = (struct usbdrv_private *)dev->priv;
+ struct usbdrv_private *macp = dev->priv;
struct zydas_cenc_sta_info cenc_info;
/* struct sock *netlink_sk; */
u8_t ie_len;
diff --git a/drivers/staging/otus/wrap_usb.c b/drivers/staging/otus/wrap_usb.c
index 93459cadc47..9f04047bf5a 100644
--- a/drivers/staging/otus/wrap_usb.c
+++ b/drivers/staging/otus/wrap_usb.c
@@ -104,6 +104,11 @@ u32_t zfwUsbSubmitControl(zdev_t *dev, u8_t req, u16_t value, u16_t index,
if (size > 0) {
buf = kmalloc(size, GFP_KERNEL);
+ if (buf == NULL) {
+ pr_err("zfwUsbSubmitControl() failed, "
+ "kmalloc() returned NULL\n");
+ return 1;
+ }
memcpy(buf, (u8_t *)data, size);
} else
buf = NULL;
diff --git a/drivers/staging/otus/wwrap.c b/drivers/staging/otus/wwrap.c
index b02eb42cd79..fcd3da07155 100644
--- a/drivers/staging/otus/wwrap.c
+++ b/drivers/staging/otus/wwrap.c
@@ -29,24 +29,24 @@
#include <linux/slab.h>
#include <net/iw_handler.h>
-extern void zfiRecv80211(zdev_t* dev, zbuf_t* buf, struct zsAdditionInfo* addInfo);
-extern void zfCoreRecv(zdev_t* dev, zbuf_t* buf, struct zsAdditionInfo* addInfo);
-extern void zfIdlChkRsp(zdev_t* dev, u32_t* rsp, u16_t rspLen);
-extern void zfIdlRsp(zdev_t* dev, u32_t *rsp, u16_t rspLen);
+extern void zfiRecv80211(zdev_t *dev, zbuf_t *buf, struct zsAdditionInfo *addInfo);
+extern void zfCoreRecv(zdev_t *dev, zbuf_t *buf, struct zsAdditionInfo *addInfo);
+extern void zfIdlChkRsp(zdev_t *dev, u32_t *rsp, u16_t rspLen);
+extern void zfIdlRsp(zdev_t *dev, u32_t *rsp, u16_t rspLen);
-//extern struct zsWdsStruct wds[ZM_WDS_PORT_NUMBER];
+/*extern struct zsWdsStruct wds[ZM_WDS_PORT_NUMBER];*/
extern struct zsVapStruct vap[ZM_VAP_PORT_NUMBER];
-u32_t zfLnxUsbSubmitTxData(zdev_t* dev);
-u32_t zfLnxUsbIn(zdev_t* dev, urb_t *urb, zbuf_t *buf);
+u32_t zfLnxUsbSubmitTxData(zdev_t *dev);
+u32_t zfLnxUsbIn(zdev_t *dev, urb_t *urb, zbuf_t *buf);
u32_t zfLnxSubmitRegInUrb(zdev_t *dev);
u32_t zfLnxUsbSubmitBulkUrb(urb_t *urb, struct usb_device *usb, u16_t epnum, u16_t direction,
- void *transfer_buffer, int buffer_length, usb_complete_t complete, void *context);
+ void *transfer_buffer, int buffer_length, usb_complete_t complete, void *context);
u32_t zfLnxUsbSubmitIntUrb(urb_t *urb, struct usb_device *usb, u16_t epnum, u16_t direction,
- void *transfer_buffer, int buffer_length, usb_complete_t complete, void *context,
- u32_t interval);
+ void *transfer_buffer, int buffer_length, usb_complete_t complete, void *context,
+ u32_t interval);
u16_t zfLnxGetFreeTxUrb(zdev_t *dev)
{
@@ -56,22 +56,19 @@ u16_t zfLnxGetFreeTxUrb(zdev_t *dev)
spin_lock_irqsave(&macp->cs_lock, irqFlag);
- //idx = ((macp->TxUrbTail + 1) & (ZM_MAX_TX_URB_NUM - 1));
+ /*idx = ((macp->TxUrbTail + 1) & (ZM_MAX_TX_URB_NUM - 1));*/
- //if (idx != macp->TxUrbHead)
- if (macp->TxUrbCnt != 0)
- {
- idx = macp->TxUrbTail;
- macp->TxUrbTail = ((macp->TxUrbTail + 1) & (ZM_MAX_TX_URB_NUM - 1));
- macp->TxUrbCnt--;
- }
- else
- {
- //printk(KERN_ERR "macp->TxUrbCnt: %d\n", macp->TxUrbCnt);
- idx = 0xffff;
- }
+ /*if (idx != macp->TxUrbHead)*/
+ if (macp->TxUrbCnt != 0) {
+ idx = macp->TxUrbTail;
+ macp->TxUrbTail = ((macp->TxUrbTail + 1) & (ZM_MAX_TX_URB_NUM - 1));
+ macp->TxUrbCnt--;
+ } else {
+ /*printk(KERN_ERR "macp->TxUrbCnt: %d\n", macp->TxUrbCnt);*/
+ idx = 0xffff;
+ }
- spin_unlock_irqrestore(&macp->cs_lock, irqFlag);
+ spin_unlock_irqrestore(&macp->cs_lock, irqFlag);
return idx;
}
@@ -85,16 +82,13 @@ void zfLnxPutTxUrb(zdev_t *dev)
idx = ((macp->TxUrbHead + 1) & (ZM_MAX_TX_URB_NUM - 1));
- //if (idx != macp->TxUrbTail)
- if (macp->TxUrbCnt < ZM_MAX_TX_URB_NUM)
- {
- macp->TxUrbHead = idx;
- macp->TxUrbCnt++;
- }
- else
- {
- printk("UsbTxUrbQ inconsistent: TxUrbHead: %d, TxUrbTail: %d\n",
- macp->TxUrbHead, macp->TxUrbTail);
+ /*if (idx != macp->TxUrbTail)*/
+ if (macp->TxUrbCnt < ZM_MAX_TX_URB_NUM) {
+ macp->TxUrbHead = idx;
+ macp->TxUrbCnt++;
+ } else {
+ printk("UsbTxUrbQ inconsistent: TxUrbHead: %d, TxUrbTail: %d\n",
+ macp->TxUrbHead, macp->TxUrbTail);
}
spin_unlock_irqrestore(&macp->cs_lock, irqFlag);
@@ -125,24 +119,20 @@ UsbTxQ_t *zfLnxGetUsbTxBuffer(zdev_t *dev)
idx = ((macp->TxBufHead+1) & (ZM_MAX_TX_BUF_NUM - 1));
- //if (idx != macp->TxBufTail)
- if (macp->TxBufCnt > 0)
- {
- //printk("CWY - zfwGetUsbTxBuffer ,macp->TxBufCnt = %d\n", macp->TxBufCnt);
- TxQ = (UsbTxQ_t *)&(macp->UsbTxBufQ[macp->TxBufHead]);
- macp->TxBufHead = ((macp->TxBufHead+1) & (ZM_MAX_TX_BUF_NUM - 1));
- macp->TxBufCnt--;
- }
- else
- {
- if (macp->TxBufHead != macp->TxBufTail)
- {
- printk(KERN_ERR "zfwGetUsbTxBuf UsbTxBufQ inconsistent: TxBufHead: %d, TxBufTail: %d\n",
- macp->TxBufHead, macp->TxBufTail);
- }
-
- spin_unlock_irqrestore(&macp->cs_lock, irqFlag);
- return NULL;
+ /*if (idx != macp->TxBufTail)*/
+ if (macp->TxBufCnt > 0) {
+ /*printk("CWY - zfwGetUsbTxBuffer ,macp->TxBufCnt = %d\n", macp->TxBufCnt);*/
+ TxQ = (UsbTxQ_t *)&(macp->UsbTxBufQ[macp->TxBufHead]);
+ macp->TxBufHead = ((macp->TxBufHead+1) & (ZM_MAX_TX_BUF_NUM - 1));
+ macp->TxBufCnt--;
+ } else {
+ if (macp->TxBufHead != macp->TxBufTail) {
+ printk(KERN_ERR "zfwGetUsbTxBuf UsbTxBufQ inconsistent: TxBufHead: %d, TxBufTail: %d\n",
+ macp->TxBufHead, macp->TxBufTail);
+ }
+
+ spin_unlock_irqrestore(&macp->cs_lock, irqFlag);
+ return NULL;
}
spin_unlock_irqrestore(&macp->cs_lock, irqFlag);
@@ -150,8 +140,8 @@ UsbTxQ_t *zfLnxGetUsbTxBuffer(zdev_t *dev)
}
u16_t zfLnxPutUsbTxBuffer(zdev_t *dev, u8_t *hdr, u16_t hdrlen,
- u8_t *snap, u16_t snapLen, u8_t *tail, u16_t tailLen,
- zbuf_t *buf, u16_t offset)
+ u8_t *snap, u16_t snapLen, u8_t *tail, u16_t tailLen,
+ zbuf_t *buf, u16_t offset)
{
struct usbdrv_private *macp = dev->ml_priv;
u16_t idx;
@@ -163,32 +153,29 @@ u16_t zfLnxPutUsbTxBuffer(zdev_t *dev, u8_t *hdr, u16_t hdrlen,
idx = ((macp->TxBufTail+1) & (ZM_MAX_TX_BUF_NUM - 1));
/* For Tx debug */
- //zm_assert(macp->TxBufCnt >= 0); // deleted because of always true
-
- //if (idx != macp->TxBufHead)
- if (macp->TxBufCnt < ZM_MAX_TX_BUF_NUM)
- {
- //printk("CWY - zfwPutUsbTxBuffer ,macp->TxBufCnt = %d\n", macp->TxBufCnt);
- TxQ = (UsbTxQ_t *)&(macp->UsbTxBufQ[macp->TxBufTail]);
- memcpy(TxQ->hdr, hdr, hdrlen);
- TxQ->hdrlen = hdrlen;
- memcpy(TxQ->snap, snap, snapLen);
- TxQ->snapLen = snapLen;
- memcpy(TxQ->tail, tail, tailLen);
- TxQ->tailLen = tailLen;
- TxQ->buf = buf;
- TxQ->offset = offset;
-
- macp->TxBufTail = ((macp->TxBufTail+1) & (ZM_MAX_TX_BUF_NUM - 1));
- macp->TxBufCnt++;
- }
- else
- {
- printk(KERN_ERR "zfLnxPutUsbTxBuffer UsbTxBufQ inconsistent: TxBufHead: %d, TxBufTail: %d, TxBufCnt: %d\n",
- macp->TxBufHead, macp->TxBufTail, macp->TxBufCnt);
- spin_unlock_irqrestore(&macp->cs_lock, irqFlag);
- return 0xffff;
- }
+ /*zm_assert(macp->TxBufCnt >= 0); // deleted because of always true*/
+
+ /*if (idx != macp->TxBufHead)*/
+ if (macp->TxBufCnt < ZM_MAX_TX_BUF_NUM) {
+ /*printk("CWY - zfwPutUsbTxBuffer ,macp->TxBufCnt = %d\n", macp->TxBufCnt);*/
+ TxQ = (UsbTxQ_t *)&(macp->UsbTxBufQ[macp->TxBufTail]);
+ memcpy(TxQ->hdr, hdr, hdrlen);
+ TxQ->hdrlen = hdrlen;
+ memcpy(TxQ->snap, snap, snapLen);
+ TxQ->snapLen = snapLen;
+ memcpy(TxQ->tail, tail, tailLen);
+ TxQ->tailLen = tailLen;
+ TxQ->buf = buf;
+ TxQ->offset = offset;
+
+ macp->TxBufTail = ((macp->TxBufTail+1) & (ZM_MAX_TX_BUF_NUM - 1));
+ macp->TxBufCnt++;
+ } else {
+ printk(KERN_ERR "zfLnxPutUsbTxBuffer UsbTxBufQ inconsistent: TxBufHead: %d, TxBufTail: %d, TxBufCnt: %d\n",
+ macp->TxBufHead, macp->TxBufTail, macp->TxBufCnt);
+ spin_unlock_irqrestore(&macp->cs_lock, irqFlag);
+ return 0xffff;
+ }
spin_unlock_irqrestore(&macp->cs_lock, irqFlag);
return 0;
@@ -197,28 +184,25 @@ u16_t zfLnxPutUsbTxBuffer(zdev_t *dev, u8_t *hdr, u16_t hdrlen,
zbuf_t *zfLnxGetUsbRxBuffer(zdev_t *dev)
{
struct usbdrv_private *macp = dev->ml_priv;
- //u16_t idx;
+ /*u16_t idx;*/
zbuf_t *buf;
unsigned long irqFlag;
spin_lock_irqsave(&macp->cs_lock, irqFlag);
- //idx = ((macp->RxBufHead+1) & (ZM_MAX_RX_URB_NUM - 1));
-
- //if (idx != macp->RxBufTail)
- if (macp->RxBufCnt != 0)
- {
- buf = macp->UsbRxBufQ[macp->RxBufHead];
- macp->RxBufHead = ((macp->RxBufHead+1) & (ZM_MAX_RX_URB_NUM - 1));
- macp->RxBufCnt--;
- }
- else
- {
- printk("RxBufQ inconsistent: RxBufHead: %d, RxBufTail: %d\n",
- macp->RxBufHead, macp->RxBufTail);
- spin_unlock_irqrestore(&macp->cs_lock, irqFlag);
- return NULL;
- }
+ /*idx = ((macp->RxBufHead+1) & (ZM_MAX_RX_URB_NUM - 1));*/
+
+ /*if (idx != macp->RxBufTail)*/
+ if (macp->RxBufCnt != 0) {
+ buf = macp->UsbRxBufQ[macp->RxBufHead];
+ macp->RxBufHead = ((macp->RxBufHead+1) & (ZM_MAX_RX_URB_NUM - 1));
+ macp->RxBufCnt--;
+ } else {
+ printk("RxBufQ inconsistent: RxBufHead: %d, RxBufTail: %d\n",
+ macp->RxBufHead, macp->RxBufTail);
+ spin_unlock_irqrestore(&macp->cs_lock, irqFlag);
+ return NULL;
+ }
spin_unlock_irqrestore(&macp->cs_lock, irqFlag);
return buf;
@@ -234,61 +218,56 @@ u32_t zfLnxPutUsbRxBuffer(zdev_t *dev, zbuf_t *buf)
idx = ((macp->RxBufTail+1) & (ZM_MAX_RX_URB_NUM - 1));
- //if (idx != macp->RxBufHead)
- if (macp->RxBufCnt != ZM_MAX_RX_URB_NUM)
- {
- macp->UsbRxBufQ[macp->RxBufTail] = buf;
- macp->RxBufTail = idx;
- macp->RxBufCnt++;
- }
- else
- {
- printk("RxBufQ inconsistent: RxBufHead: %d, RxBufTail: %d\n",
- macp->RxBufHead, macp->RxBufTail);
- spin_unlock_irqrestore(&macp->cs_lock, irqFlag);
- return 0xffff;
- }
+ /*if (idx != macp->RxBufHead)*/
+ if (macp->RxBufCnt != ZM_MAX_RX_URB_NUM) {
+ macp->UsbRxBufQ[macp->RxBufTail] = buf;
+ macp->RxBufTail = idx;
+ macp->RxBufCnt++;
+ } else {
+ printk("RxBufQ inconsistent: RxBufHead: %d, RxBufTail: %d\n",
+ macp->RxBufHead, macp->RxBufTail);
+ spin_unlock_irqrestore(&macp->cs_lock, irqFlag);
+ return 0xffff;
+ }
- spin_unlock_irqrestore(&macp->cs_lock, irqFlag);
- return 0;
+ spin_unlock_irqrestore(&macp->cs_lock, irqFlag);
+ return 0;
}
void zfLnxUsbDataOut_callback(urb_t *urb)
{
- zdev_t* dev = urb->context;
- //UsbTxQ_t *TxData;
+ zdev_t *dev = urb->context;
+ /*UsbTxQ_t *TxData;*/
/* Give the urb back */
zfLnxPutTxUrb(dev);
/* Check whether there is any pending buffer needed */
/* to be sent */
- if (zfLnxCheckTxBufferCnt(dev) != 0)
- {
- //TxData = zfwGetUsbTxBuffer(dev);
-
- //if (TxData == NULL)
- //{
- // printk("Get a NULL buffer from zfwGetUsbTxBuffer\n");
- // return;
- //}
- //else
- //{
- zfLnxUsbSubmitTxData(dev);
- //}
+ if (zfLnxCheckTxBufferCnt(dev) != 0) {
+ /*TxData = zfwGetUsbTxBuffer(dev);
+ //if (TxData == NULL)
+ //{
+ // printk("Get a NULL buffer from zfwGetUsbTxBuffer\n");
+ // return;
+ //}
+ //else
+ //{
+ zfLnxUsbSubmitTxData(dev);
+ //}*/
}
}
void zfLnxUsbDataIn_callback(urb_t *urb)
{
- zdev_t* dev = urb->context;
+ zdev_t *dev = urb->context;
struct usbdrv_private *macp = dev->ml_priv;
zbuf_t *buf;
zbuf_t *new_buf;
int status;
#if ZM_USB_STREAM_MODE == 1
- static int remain_len = 0, check_pad = 0, check_len = 0;
+ static int remain_len, check_pad, check_len;
int index = 0;
int chk_idx;
u16_t pkt_len;
@@ -299,47 +278,45 @@ void zfLnxUsbDataIn_callback(urb_t *urb)
#endif
/* Check status for URB */
- if (urb->status != 0){
- printk("zfLnxUsbDataIn_callback() : status=0x%x\n", urb->status);
- if ((urb->status != -ENOENT) && (urb->status != -ECONNRESET)
- && (urb->status != -ESHUTDOWN))
- {
- if (urb->status == -EPIPE){
- //printk(KERN_ERR "nonzero read bulk status received: -EPIPE");
- status = -1;
- }
-
- if (urb->status == -EPROTO){
- //printk(KERN_ERR "nonzero read bulk status received: -EPROTO");
- status = -1;
- }
- }
-
- //printk(KERN_ERR "urb->status: 0x%08x\n", urb->status);
-
- /* Dequeue skb buffer */
- buf = zfLnxGetUsbRxBuffer(dev);
- dev_kfree_skb_any(buf);
- #if 0
- /* Enqueue skb buffer */
- zfLnxPutUsbRxBuffer(dev, buf);
-
- /* Submit a Rx urb */
- zfLnxUsbIn(dev, urb, buf);
- #endif
- return;
- }
+ if (urb->status != 0) {
+ printk("zfLnxUsbDataIn_callback() : status=0x%x\n", urb->status);
+ if ((urb->status != -ENOENT) && (urb->status != -ECONNRESET)
+ && (urb->status != -ESHUTDOWN)) {
+ if (urb->status == -EPIPE) {
+ /*printk(KERN_ERR "nonzero read bulk status received: -EPIPE");*/
+ status = -1;
+ }
+
+ if (urb->status == -EPROTO) {
+ /*printk(KERN_ERR "nonzero read bulk status received: -EPROTO");*/
+ status = -1;
+ }
+ }
+
+ /*printk(KERN_ERR "urb->status: 0x%08x\n", urb->status);*/
+
+ /* Dequeue skb buffer */
+ buf = zfLnxGetUsbRxBuffer(dev);
+ dev_kfree_skb_any(buf);
+ #if 0
+ /* Enqueue skb buffer */
+ zfLnxPutUsbRxBuffer(dev, buf);
- if (urb->actual_length == 0)
- {
- printk(KERN_ERR "Get an URB whose length is zero");
- status = -1;
+ /* Submit a Rx urb */
+ zfLnxUsbIn(dev, urb, buf);
+ #endif
+ return;
+ }
+
+ if (urb->actual_length == 0) {
+ printk(KERN_ERR "Get an URB whose length is zero");
+ status = -1;
}
/* Dequeue skb buffer */
buf = zfLnxGetUsbRxBuffer(dev);
- //zfwBufSetSize(dev, buf, urb->actual_length);
+ /*zfwBufSetSize(dev, buf, urb->actual_length);*/
#ifdef NET_SKBUFF_DATA_USES_OFFSET
buf->tail = 0;
buf->len = 0;
@@ -353,134 +330,122 @@ void zfLnxUsbDataIn_callback(urb_t *urb)
skb_put(buf, urb->actual_length);
#if ZM_USB_STREAM_MODE == 1
- if (remain_len != 0)
- {
- zbuf_t *remain_buf = macp->reamin_buf;
+ if (remain_len != 0) {
+ zbuf_t *remain_buf = macp->reamin_buf;
- index = remain_len;
- remain_len -= check_pad;
+ index = remain_len;
+ remain_len -= check_pad;
- /* Copy data */
- memcpy(&(remain_buf->data[check_len]), buf->data, remain_len);
- check_len += remain_len;
- remain_len = 0;
+ /* Copy data */
+ memcpy(&(remain_buf->data[check_len]), buf->data, remain_len);
+ check_len += remain_len;
+ remain_len = 0;
- rxBufPool[rxBufPoolIndex++] = remain_buf;
+ rxBufPool[rxBufPoolIndex++] = remain_buf;
}
- while(index < urb->actual_length)
- {
- pkt_len = buf->data[index] + (buf->data[index+1] << 8);
- pkt_tag = buf->data[index+2] + (buf->data[index+3] << 8);
-
- if (pkt_tag == 0x4e00)
- {
- int pad_len;
-
- //printk("Get a packet, index: %d, pkt_len: 0x%04x\n", index, pkt_len);
- #if 0
- /* Dump data */
- for (ii = index; ii < pkt_len+4;)
- {
- printk("%02x ", (buf->data[ii] & 0xff));
-
- if ((++ii % 16) == 0)
- printk("\n");
- }
-
- printk("\n");
- #endif
-
- pad_len = 4 - (pkt_len & 0x3);
-
- if(pad_len == 4)
- pad_len = 0;
-
- chk_idx = index;
- index = index + 4 + pkt_len + pad_len;
-
- if (index > ZM_MAX_RX_BUFFER_SIZE)
- {
- remain_len = index - ZM_MAX_RX_BUFFER_SIZE; // - pad_len;
- check_len = ZM_MAX_RX_BUFFER_SIZE - chk_idx - 4;
- check_pad = pad_len;
-
- /* Allocate a skb buffer */
- //new_buf = zfwBufAllocate(dev, ZM_MAX_RX_BUFFER_SIZE);
- new_buf = dev_alloc_skb(ZM_MAX_RX_BUFFER_SIZE);
-
- /* Set skb buffer length */
- #ifdef NET_SKBUFF_DATA_USES_OFFSET
- new_buf->tail = 0;
- new_buf->len = 0;
- #else
- new_buf->tail = new_buf->data;
- new_buf->len = 0;
- #endif
-
- skb_put(new_buf, pkt_len);
-
- /* Copy the buffer */
- memcpy(new_buf->data, &(buf->data[chk_idx+4]), check_len);
-
- /* Record the buffer pointer */
- macp->reamin_buf = new_buf;
- }
- else
- {
- #ifdef ZM_DONT_COPY_RX_BUFFER
- if (rxBufPoolIndex == 0)
- {
- new_buf = skb_clone(buf, GFP_ATOMIC);
-
- new_buf->data = &(buf->data[chk_idx+4]);
- new_buf->len = pkt_len;
- }
- else
- {
- #endif
- /* Allocate a skb buffer */
- new_buf = dev_alloc_skb(ZM_MAX_RX_BUFFER_SIZE);
-
- /* Set skb buffer length */
- #ifdef NET_SKBUFF_DATA_USES_OFFSET
- new_buf->tail = 0;
- new_buf->len = 0;
- #else
- new_buf->tail = new_buf->data;
- new_buf->len = 0;
- #endif
-
- skb_put(new_buf, pkt_len);
-
- /* Copy the buffer */
- memcpy(new_buf->data, &(buf->data[chk_idx+4]), pkt_len);
-
- #ifdef ZM_DONT_COPY_RX_BUFFER
- }
- #endif
- rxBufPool[rxBufPoolIndex++] = new_buf;
- }
- }
- else
- {
- printk(KERN_ERR "Can't find tag, pkt_len: 0x%04x, tag: 0x%04x\n", pkt_len, pkt_tag);
-
- /* Free buffer */
- dev_kfree_skb_any(buf);
-
- /* Allocate a skb buffer */
- new_buf = dev_alloc_skb(ZM_MAX_RX_BUFFER_SIZE);
-
- /* Enqueue skb buffer */
- zfLnxPutUsbRxBuffer(dev, new_buf);
-
- /* Submit a Rx urb */
- zfLnxUsbIn(dev, urb, new_buf);
-
- return;
- }
- }
+ while (index < urb->actual_length) {
+ pkt_len = buf->data[index] + (buf->data[index+1] << 8);
+ pkt_tag = buf->data[index+2] + (buf->data[index+3] << 8);
+
+ if (pkt_tag == 0x4e00) {
+ int pad_len;
+
+ /*printk("Get a packet, index: %d, pkt_len: 0x%04x\n", index, pkt_len);*/
+ #if 0
+ /* Dump data */
+ for (ii = index; ii < pkt_len+4;) {
+ printk("%02x ", (buf->data[ii] & 0xff));
+
+ if ((++ii % 16) == 0)
+ printk("\n");
+ }
+
+ printk("\n");
+ #endif
+
+ pad_len = 4 - (pkt_len & 0x3);
+
+ if (pad_len == 4)
+ pad_len = 0;
+
+ chk_idx = index;
+ index = index + 4 + pkt_len + pad_len;
+
+ if (index > ZM_MAX_RX_BUFFER_SIZE) {
+ remain_len = index - ZM_MAX_RX_BUFFER_SIZE; /* - pad_len;*/
+ check_len = ZM_MAX_RX_BUFFER_SIZE - chk_idx - 4;
+ check_pad = pad_len;
+
+ /* Allocate a skb buffer */
+ /*new_buf = zfwBufAllocate(dev, ZM_MAX_RX_BUFFER_SIZE);*/
+ new_buf = dev_alloc_skb(ZM_MAX_RX_BUFFER_SIZE);
+
+ /* Set skb buffer length */
+ #ifdef NET_SKBUFF_DATA_USES_OFFSET
+ new_buf->tail = 0;
+ new_buf->len = 0;
+ #else
+ new_buf->tail = new_buf->data;
+ new_buf->len = 0;
+ #endif
+
+ skb_put(new_buf, pkt_len);
+
+ /* Copy the buffer */
+ memcpy(new_buf->data, &(buf->data[chk_idx+4]), check_len);
+
+ /* Record the buffer pointer */
+ macp->reamin_buf = new_buf;
+ } else {
+ #ifdef ZM_DONT_COPY_RX_BUFFER
+ if (rxBufPoolIndex == 0) {
+ new_buf = skb_clone(buf, GFP_ATOMIC);
+
+ new_buf->data = &(buf->data[chk_idx+4]);
+ new_buf->len = pkt_len;
+ } else {
+ #endif
+ /* Allocate a skb buffer */
+ new_buf = dev_alloc_skb(ZM_MAX_RX_BUFFER_SIZE);
+
+ /* Set skb buffer length */
+ #ifdef NET_SKBUFF_DATA_USES_OFFSET
+ new_buf->tail = 0;
+ new_buf->len = 0;
+ #else
+ new_buf->tail = new_buf->data;
+ new_buf->len = 0;
+ #endif
+
+ skb_put(new_buf, pkt_len);
+
+ /* Copy the buffer */
+ memcpy(new_buf->data, &(buf->data[chk_idx+4]), pkt_len);
+
+ #ifdef ZM_DONT_COPY_RX_BUFFER
+ }
+ #endif
+ rxBufPool[rxBufPoolIndex++] = new_buf;
+ }
+ } else {
+ printk(KERN_ERR "Can't find tag, pkt_len: 0x%04x, tag: 0x%04x\n", pkt_len, pkt_tag);
+
+ /* Free buffer */
+ dev_kfree_skb_any(buf);
+
+ /* Allocate a skb buffer */
+ new_buf = dev_alloc_skb(ZM_MAX_RX_BUFFER_SIZE);
+
+ /* Enqueue skb buffer */
+ zfLnxPutUsbRxBuffer(dev, new_buf);
+
+ /* Submit a Rx urb */
+ zfLnxUsbIn(dev, urb, new_buf);
+
+ return;
+ }
+ }
/* Free buffer */
dev_kfree_skb_any(buf);
@@ -496,9 +461,8 @@ void zfLnxUsbDataIn_callback(urb_t *urb)
zfLnxUsbIn(dev, urb, new_buf);
#if ZM_USB_STREAM_MODE == 1
- for(ii = 0; ii < rxBufPoolIndex; ii++)
- {
- macp->usbCbFunctions.zfcbUsbRecv(dev, rxBufPool[ii]);
+ for (ii = 0; ii < rxBufPoolIndex; ii++) {
+ macp->usbCbFunctions.zfcbUsbRecv(dev, rxBufPool[ii]);
}
#else
/* pass data to upper layer */
@@ -508,51 +472,48 @@ void zfLnxUsbDataIn_callback(urb_t *urb)
void zfLnxUsbRegOut_callback(urb_t *urb)
{
- //dev_t* dev = urb->context;
+ /*dev_t* dev = urb->context;*/
- //printk(KERN_ERR "zfwUsbRegOut_callback\n");
+ /*printk(KERN_ERR "zfwUsbRegOut_callback\n");*/
}
void zfLnxUsbRegIn_callback(urb_t *urb)
{
- zdev_t* dev = urb->context;
+ zdev_t *dev = urb->context;
u32_t rsp[64/4];
int status;
struct usbdrv_private *macp = dev->ml_priv;
/* Check status for URB */
- if (urb->status != 0){
- printk("zfLnxUsbRegIn_callback() : status=0x%x\n", urb->status);
- if ((urb->status != -ENOENT) && (urb->status != -ECONNRESET)
- && (urb->status != -ESHUTDOWN))
- {
- if (urb->status == -EPIPE){
- //printk(KERN_ERR "nonzero read bulk status received: -EPIPE");
- status = -1;
- }
-
- if (urb->status == -EPROTO){
- //printk(KERN_ERR "nonzero read bulk status received: -EPROTO");
- status = -1;
- }
- }
-
- //printk(KERN_ERR "urb->status: 0x%08x\n", urb->status);
- return;
- }
+ if (urb->status != 0) {
+ printk("zfLnxUsbRegIn_callback() : status=0x%x\n", urb->status);
+ if ((urb->status != -ENOENT) && (urb->status != -ECONNRESET) && (urb->status != -ESHUTDOWN)) {
+ if (urb->status == -EPIPE) {
+ /*printk(KERN_ERR "nonzero read bulk status received: -EPIPE");*/
+ status = -1;
+ }
+
+ if (urb->status == -EPROTO) {
+ /*printk(KERN_ERR "nonzero read bulk status received: -EPROTO");*/
+ status = -1;
+ }
+ }
+
+ /*printk(KERN_ERR "urb->status: 0x%08x\n", urb->status);*/
+ return;
+ }
- if (urb->actual_length == 0)
- {
- printk(KERN_ERR "Get an URB whose length is zero");
- status = -1;
+ if (urb->actual_length == 0) {
+ printk(KERN_ERR "Get an URB whose length is zero");
+ status = -1;
}
/* Copy data into respone buffer */
memcpy(rsp, macp->regUsbReadBuf, urb->actual_length);
/* Notify to upper layer */
- //zfIdlChkRsp(dev, rsp, (u16_t)urb->actual_length);
- //zfiUsbRegIn(dev, rsp, (u16_t)urb->actual_length);
+ /*zfIdlChkRsp(dev, rsp, (u16_t)urb->actual_length);*/
+ /*zfiUsbRegIn(dev, rsp, (u16_t)urb->actual_length);*/
macp->usbCbFunctions.zfcbUsbRegIn(dev, rsp, (u16_t)urb->actual_length);
/* Issue another USB IN URB */
@@ -564,22 +525,22 @@ u32_t zfLnxSubmitRegInUrb(zdev_t *dev)
u32_t ret;
struct usbdrv_private *macp = dev->ml_priv;
- /* Submit a rx urb */
+ /* Submit a rx urb
//ret = zfLnxUsbSubmitBulkUrb(macp->RegInUrb, macp->udev,
// USB_REG_IN_PIPE, USB_DIR_IN, macp->regUsbReadBuf,
// ZM_USB_REG_MAX_BUF_SIZE, zfLnxUsbRegIn_callback, dev);
//CWYang(-)
//if (ret != 0)
- // printk("zfwUsbSubmitBulkUrb fail, status: 0x%08x\n", (int)ret);
+ // printk("zfwUsbSubmitBulkUrb fail, status: 0x%08x\n", (int)ret);*/
ret = zfLnxUsbSubmitIntUrb(macp->RegInUrb, macp->udev,
- USB_REG_IN_PIPE, USB_DIR_IN, macp->regUsbReadBuf,
- ZM_USB_REG_MAX_BUF_SIZE, zfLnxUsbRegIn_callback, dev, 1);
+ USB_REG_IN_PIPE, USB_DIR_IN, macp->regUsbReadBuf,
+ ZM_USB_REG_MAX_BUF_SIZE, zfLnxUsbRegIn_callback, dev, 1);
return ret;
}
-u32_t zfLnxUsbSubmitTxData(zdev_t* dev)
+u32_t zfLnxUsbSubmitTxData(zdev_t *dev)
{
u32_t i;
u32_t ret;
@@ -600,39 +561,33 @@ u32_t zfLnxUsbSubmitTxData(zdev_t* dev)
freeTxUrb = zfLnxGetFreeTxUrb(dev);
/* If there is no any free Tx Urb */
- if (freeTxUrb == 0xffff)
- {
- //printk(KERN_ERR "Can't get free Tx Urb\n");
- //printk("CWY - Can't get free Tx Urb\n");
- return 0xffff;
+ if (freeTxUrb == 0xffff) {
+ /*printk(KERN_ERR "Can't get free Tx Urb\n");
+ //printk("CWY - Can't get free Tx Urb\n");*/
+ return 0xffff;
}
#if ZM_USB_TX_STREAM_MODE == 1
usbTxAggCnt = zfLnxCheckTxBufferCnt(dev);
- if (usbTxAggCnt >= ZM_MAX_TX_AGGREGATE_NUM)
- {
- usbTxAggCnt = ZM_MAX_TX_AGGREGATE_NUM;
- }
- else
- {
- usbTxAggCnt = 1;
+ if (usbTxAggCnt >= ZM_MAX_TX_AGGREGATE_NUM) {
+ usbTxAggCnt = ZM_MAX_TX_AGGREGATE_NUM;
+ } else {
+ usbTxAggCnt = 1;
}
- //printk("usbTxAggCnt: %d\n", usbTxAggCnt);
+ /*printk("usbTxAggCnt: %d\n", usbTxAggCnt);*/
#endif
#if ZM_USB_TX_STREAM_MODE == 1
- for(ii = 0; ii < usbTxAggCnt; ii++)
- {
+ for (ii = 0; ii < usbTxAggCnt; ii++) {
#endif
/* Dequeue the packet from UsbTxBufQ */
TxData = zfLnxGetUsbTxBuffer(dev);
- if (TxData == NULL)
- {
- /* Give the urb back */
- zfLnxPutTxUrb(dev);
- return 0xffff;
+ if (TxData == NULL) {
+ /* Give the urb back */
+ zfLnxPutTxUrb(dev);
+ return 0xffff;
}
/* Point to the freeTxUrb buffer */
@@ -644,114 +599,103 @@ u32_t zfLnxUsbSubmitTxData(zdev_t* dev)
/* Add the packet length and tag information */
*pUsbTxHdr++ = TxData->hdrlen + TxData->snapLen +
- (TxData->buf->len - TxData->offset) + TxData->tailLen;
+ (TxData->buf->len - TxData->offset) + TxData->tailLen;
*pUsbTxHdr++ = 0x697e;
puTxBuf += 4;
-#endif // #ifdef ZM_USB_TX_STREAM_MODE
+#endif /* #ifdef ZM_USB_TX_STREAM_MODE*/
/* Copy WLAN header and packet buffer into USB buffer */
- for(i = 0; i < TxData->hdrlen; i++)
- {
- *puTxBuf++ = TxData->hdr[i];
+ for (i = 0; i < TxData->hdrlen; i++) {
+ *puTxBuf++ = TxData->hdr[i];
}
/* Copy SNAP header */
- for(i = 0; i < TxData->snapLen; i++)
- {
- *puTxBuf++ = TxData->snap[i];
+ for (i = 0; i < TxData->snapLen; i++) {
+ *puTxBuf++ = TxData->snap[i];
}
/* Copy packet buffer */
- for(i = 0; i < TxData->buf->len - TxData->offset; i++)
- {
- //*puTxBuf++ = zmw_rx_buf_readb(dev, TxData->buf, i);
- *puTxBuf++ = *(u8_t*)((u8_t*)TxData->buf->data+i+TxData->offset);
+ for (i = 0; i < TxData->buf->len - TxData->offset; i++) {
+ /*puTxBuf++ = zmw_rx_buf_readb(dev, TxData->buf, i);*/
+ *puTxBuf++ = *(u8_t *)((u8_t *)TxData->buf->data+i+TxData->offset);
}
/* Copy tail */
- for(i = 0; i < TxData->tailLen; i++)
- {
- *puTxBuf++ = TxData->tail[i];
+ for (i = 0; i < TxData->tailLen; i++) {
+ *puTxBuf++ = TxData->tail[i];
}
len = TxData->hdrlen+TxData->snapLen+TxData->buf->len+TxData->tailLen-TxData->offset;
#if 0
- if (TxData->hdrlen != 0)
- {
- puTxBuf = macp->txUsbBuf[freeTxUrb];
- for (i = 0; i < len; i++)
- {
- printk("%02x ", puTxBuf[i]);
- if (i % 16 == 15)
- printk("\n");
- }
- printk("\n");
- }
+ if (TxData->hdrlen != 0) {
+ puTxBuf = macp->txUsbBuf[freeTxUrb];
+ for (i = 0; i < len; i++) {
+ printk("%02x ", puTxBuf[i]);
+ if (i % 16 == 15)
+ printk("\n");
+ }
+ printk("\n");
+ }
#endif
#if 0
/* For debug purpose */
- if(TxData->hdr[9] & 0x40)
- {
- int i;
- u16_t ctrlLen = TxData->hdr[0] + (TxData->hdr[1] << 8);
-
- if (ctrlLen != len + 4)
- {
- /* Dump control setting */
- for(i = 0; i < 8; i++)
- {
- printk(KERN_ERR "0x%02x ", TxData->hdr[i]);
- }
- printk(KERN_ERR "\n");
-
- printk(KERN_ERR "ctrLen: %d, hdrLen: %d, snapLen: %d\n", ctrlLen, TxData->hdrlen, TxData->snapLen);
- printk(KERN_ERR "bufLen: %d, tailLen: %d, len: %d\n", TxData->buf->len, TxData->tailLen, len);
- }
+ if (TxData->hdr[9] & 0x40) {
+ int i;
+ u16_t ctrlLen = TxData->hdr[0] + (TxData->hdr[1] << 8);
+
+ if (ctrlLen != len + 4) {
+ /* Dump control setting */
+ for (i = 0; i < 8; i++) {
+ printk(KERN_ERR "0x%02x ", TxData->hdr[i]);
+ }
+ printk(KERN_ERR "\n");
+
+ printk(KERN_ERR "ctrLen: %d, hdrLen: %d, snapLen: %d\n", ctrlLen, TxData->hdrlen, TxData->snapLen);
+ printk(KERN_ERR "bufLen: %d, tailLen: %d, len: %d\n", TxData->buf->len, TxData->tailLen, len);
+ }
}
#endif
#if ZM_USB_TX_STREAM_MODE == 1
- // Add the Length and Tag
+ /* Add the Length and Tag*/
len += 4;
- //printk("%d packet, length: %d\n", ii+1, len);
+ /*printk("%d packet, length: %d\n", ii+1, len);*/
- if (ii < (ZM_MAX_TX_AGGREGATE_NUM-1))
- {
- /* Pad the buffer to firmware descriptor boundary */
- offset += (((len-1) / 4) + 1) * 4;
+ if (ii < (ZM_MAX_TX_AGGREGATE_NUM-1)) {
+ /* Pad the buffer to firmware descriptor boundary */
+ offset += (((len-1) / 4) + 1) * 4;
}
- if (ii == (ZM_MAX_TX_AGGREGATE_NUM-1))
- {
- len += offset;
+ if (ii == (ZM_MAX_TX_AGGREGATE_NUM-1)) {
+ len += offset;
}
TxQPool[ii] = TxData;
- //DbgPrint("%d packet, offset: %d\n", ii+1, pUsbTxTransfer->offset);
+ /*DbgPrint("%d packet, offset: %d\n", ii+1, pUsbTxTransfer->offset);*/
/* free packet */
- //zfBufFree(dev, txData->buf);
+ /*zfBufFree(dev, txData->buf);*/
}
#endif
- //printk("CWY - call zfwUsbSubmitBulkUrb(), len = 0x%d\n", len);
+ /*printk("CWY - call zfwUsbSubmitBulkUrb(), len = 0x%d\n", len);*/
/* Submit a tx urb */
ret = zfLnxUsbSubmitBulkUrb(macp->WlanTxDataUrb[freeTxUrb], macp->udev,
- USB_WLAN_TX_PIPE, USB_DIR_OUT, macp->txUsbBuf[freeTxUrb],
- len, zfLnxUsbDataOut_callback, dev);
- //CWYang(-)
+ USB_WLAN_TX_PIPE, USB_DIR_OUT, macp->txUsbBuf[freeTxUrb],
+ len, zfLnxUsbDataOut_callback, dev);
+ /*CWYang(-)
//if (ret != 0)
- // printk("zfwUsbSubmitBulkUrb fail, status: 0x%08x\n", (int)ret);
+ // printk("zfwUsbSubmitBulkUrb fail, status: 0x%08x\n", (int)ret);*/
/* free packet */
- //dev_kfree_skb_any(TxData->buf);
+ /*dev_kfree_skb_any(TxData->buf);*/
#if ZM_USB_TX_STREAM_MODE == 1
- for(ii = 0; ii < usbTxAggCnt; ii++)
- macp->usbCbFunctions.zfcbUsbOutComplete(dev, TxQPool[ii]->buf, 1, TxQPool[ii]->hdr);
+ for (ii = 0; ii < usbTxAggCnt; ii++)
+ macp->usbCbFunctions.zfcbUsbOutComplete(dev, TxQPool[ii]->buf, 1, TxQPool[ii]->hdr);
#else
macp->usbCbFunctions.zfcbUsbOutComplete(dev, TxData->buf, 1, TxData->hdr);
#endif
@@ -761,23 +705,23 @@ u32_t zfLnxUsbSubmitTxData(zdev_t* dev)
-u32_t zfLnxUsbIn(zdev_t* dev, urb_t *urb, zbuf_t *buf)
+u32_t zfLnxUsbIn(zdev_t *dev, urb_t *urb, zbuf_t *buf)
{
u32_t ret;
struct usbdrv_private *macp = dev->ml_priv;
/* Submit a rx urb */
ret = zfLnxUsbSubmitBulkUrb(urb, macp->udev, USB_WLAN_RX_PIPE,
- USB_DIR_IN, buf->data, ZM_MAX_RX_BUFFER_SIZE,
- zfLnxUsbDataIn_callback, dev);
- //CWYang(-)
+ USB_DIR_IN, buf->data, ZM_MAX_RX_BUFFER_SIZE,
+ zfLnxUsbDataIn_callback, dev);
+ /*CWYang(-)
//if (ret != 0)
- // printk("zfwUsbSubmitBulkUrb fail, status: 0x%08x\n", (int)ret);
+ // printk("zfwUsbSubmitBulkUrb fail, status: 0x%08x\n", (int)ret);*/
return ret;
}
-u32_t zfLnxUsbWriteReg(zdev_t* dev, u32_t* cmd, u16_t cmdLen)
+u32_t zfLnxUsbWriteReg(zdev_t *dev, u32_t *cmd, u16_t cmdLen)
{
struct usbdrv_private *macp = dev->ml_priv;
u32_t ret;
@@ -785,7 +729,7 @@ u32_t zfLnxUsbWriteReg(zdev_t* dev, u32_t* cmd, u16_t cmdLen)
#ifdef ZM_CONFIG_BIG_ENDIAN
int ii = 0;
- for(ii=0; ii<(cmdLen>>2); ii++)
+ for (ii = 0; ii < (cmdLen>>2); ii++)
cmd[ii] = cpu_to_le32(cmd[ii]);
#endif
@@ -794,39 +738,38 @@ u32_t zfLnxUsbWriteReg(zdev_t* dev, u32_t* cmd, u16_t cmdLen)
/* Issue an USB Out transfer */
/* Submit a tx urb */
ret = zfLnxUsbSubmitIntUrb(macp->RegOutUrb, macp->udev,
- USB_REG_OUT_PIPE, USB_DIR_OUT, macp->regUsbWriteBuf,
- cmdLen, zfLnxUsbRegOut_callback, dev, 1);
+ USB_REG_OUT_PIPE, USB_DIR_OUT, macp->regUsbWriteBuf,
+ cmdLen, zfLnxUsbRegOut_callback, dev, 1);
return ret;
}
-u32_t zfLnxUsbOut(zdev_t* dev, u8_t *hdr, u16_t hdrlen, u8_t *snap, u16_t snapLen,
- u8_t *tail, u16_t tailLen, zbuf_t *buf, u16_t offset)
+u32_t zfLnxUsbOut(zdev_t *dev, u8_t *hdr, u16_t hdrlen, u8_t *snap, u16_t snapLen,
+ u8_t *tail, u16_t tailLen, zbuf_t *buf, u16_t offset)
{
u32_t ret;
struct usbdrv_private *macp = dev->ml_priv;
/* Check length of tail buffer */
- //zm_assert((tailLen <= 16));
+ /*zm_assert((tailLen <= 16));*/
/* Enqueue the packet into UsbTxBufQ */
- if (zfLnxPutUsbTxBuffer(dev, hdr, hdrlen, snap, snapLen, tail, tailLen, buf, offset) == 0xffff)
- {
- /* free packet */
- //printk("CWY - zfwPutUsbTxBuffer Error, free packet\n");
- //dev_kfree_skb_any(buf);
- macp->usbCbFunctions.zfcbUsbOutComplete(dev, buf, 0, hdr);
- return 0xffff;
- }
+ if (zfLnxPutUsbTxBuffer(dev, hdr, hdrlen, snap, snapLen, tail, tailLen, buf, offset) == 0xffff) {
+ /* free packet */
+ /*printk("CWY - zfwPutUsbTxBuffer Error, free packet\n");
+ //dev_kfree_skb_any(buf);*/
+ macp->usbCbFunctions.zfcbUsbOutComplete(dev, buf, 0, hdr);
+ return 0xffff;
+ }
- //return 0;
- //printk("CWY - call zfwUsbSubmitTxData()\n");
+ /*return 0;
+ //printk("CWY - call zfwUsbSubmitTxData()\n");*/
ret = zfLnxUsbSubmitTxData(dev);
return ret;
}
-void zfLnxInitUsbTxQ(zdev_t* dev)
+void zfLnxInitUsbTxQ(zdev_t *dev)
{
struct usbdrv_private *macp = dev->ml_priv;
@@ -842,7 +785,7 @@ void zfLnxInitUsbTxQ(zdev_t* dev)
macp->TxUrbCnt = ZM_MAX_TX_URB_NUM;
}
-void zfLnxInitUsbRxQ(zdev_t* dev)
+void zfLnxInitUsbRxQ(zdev_t *dev)
{
u16_t i;
zbuf_t *buf;
@@ -853,76 +796,65 @@ void zfLnxInitUsbRxQ(zdev_t* dev)
macp->RxBufHead = 0;
- for (i = 0; i < ZM_MAX_RX_URB_NUM; i++)
- {
- //buf = zfwBufAllocate(dev, ZM_MAX_RX_BUFFER_SIZE);
- buf = dev_alloc_skb(ZM_MAX_RX_BUFFER_SIZE);
- macp->UsbRxBufQ[i] = buf;
- }
+ for (i = 0; i < ZM_MAX_RX_URB_NUM; i++) {
+ /*buf = zfwBufAllocate(dev, ZM_MAX_RX_BUFFER_SIZE);*/
+ buf = dev_alloc_skb(ZM_MAX_RX_BUFFER_SIZE);
+ macp->UsbRxBufQ[i] = buf;
+ }
- //macp->RxBufTail = ZM_MAX_RX_URB_NUM - 1;
+ /*macp->RxBufTail = ZM_MAX_RX_URB_NUM - 1;*/
macp->RxBufTail = 0;
/* Submit all Rx urbs */
- for (i = 0; i < ZM_MAX_RX_URB_NUM; i++)
- {
- zfLnxPutUsbRxBuffer(dev, macp->UsbRxBufQ[i]);
- zfLnxUsbIn(dev, macp->WlanRxDataUrb[i], macp->UsbRxBufQ[i]);
- }
+ for (i = 0; i < ZM_MAX_RX_URB_NUM; i++) {
+ zfLnxPutUsbRxBuffer(dev, macp->UsbRxBufQ[i]);
+ zfLnxUsbIn(dev, macp->WlanRxDataUrb[i], macp->UsbRxBufQ[i]);
+ }
}
u32_t zfLnxUsbSubmitBulkUrb(urb_t *urb, struct usb_device *usb, u16_t epnum, u16_t direction,
- void *transfer_buffer, int buffer_length, usb_complete_t complete, void *context)
+ void *transfer_buffer, int buffer_length, usb_complete_t complete, void *context)
{
u32_t ret;
- if(direction == USB_DIR_OUT)
- {
- usb_fill_bulk_urb(urb, usb, usb_sndbulkpipe(usb, epnum),
- transfer_buffer, buffer_length, complete, context);
+ if (direction == USB_DIR_OUT) {
+ usb_fill_bulk_urb(urb, usb, usb_sndbulkpipe(usb, epnum),
+ transfer_buffer, buffer_length, complete, context);
- urb->transfer_flags |= URB_ZERO_PACKET;
- }
- else
- {
- usb_fill_bulk_urb(urb, usb, usb_rcvbulkpipe(usb, epnum),
- transfer_buffer, buffer_length, complete, context);
+ urb->transfer_flags |= URB_ZERO_PACKET;
+ } else {
+ usb_fill_bulk_urb(urb, usb, usb_rcvbulkpipe(usb, epnum),
+ transfer_buffer, buffer_length, complete, context);
}
- if (epnum == 4)
- {
- if (urb->hcpriv)
- {
- //printk("CWY - urb->hcpriv set by unknown reason, reset it\n");
- //urb->hcpriv = 0;
- }
- }
+ if (epnum == 4) {
+ if (urb->hcpriv) {
+ /*printk("CWY - urb->hcpriv set by unknown reason, reset it\n");
+ //urb->hcpriv = 0;*/
+ }
+ }
ret = usb_submit_urb(urb, GFP_ATOMIC);
- if ((epnum == 4) & (ret != 0))
- {
- //printk("CWY - ret = %x\n", ret);
+ if ((epnum == 4) & (ret != 0)) {
+ /*printk("CWY - ret = %x\n", ret);*/
}
return ret;
}
u32_t zfLnxUsbSubmitIntUrb(urb_t *urb, struct usb_device *usb, u16_t epnum, u16_t direction,
- void *transfer_buffer, int buffer_length, usb_complete_t complete, void *context,
- u32_t interval)
+ void *transfer_buffer, int buffer_length, usb_complete_t complete, void *context,
+ u32_t interval)
{
u32_t ret;
- if(direction == USB_DIR_OUT)
- {
- usb_fill_int_urb(urb, usb, usb_sndbulkpipe(usb, epnum),
- transfer_buffer, buffer_length, complete, context, interval);
- }
- else
- {
- usb_fill_int_urb(urb, usb, usb_rcvbulkpipe(usb, epnum),
- transfer_buffer, buffer_length, complete, context, interval);
+ if (direction == USB_DIR_OUT) {
+ usb_fill_int_urb(urb, usb, usb_sndbulkpipe(usb, epnum),
+ transfer_buffer, buffer_length, complete, context, interval);
+ } else {
+ usb_fill_int_urb(urb, usb, usb_rcvbulkpipe(usb, epnum),
+ transfer_buffer, buffer_length, complete, context, interval);
}
ret = usb_submit_urb(urb, GFP_ATOMIC);
@@ -946,51 +878,48 @@ int zfLnxCencSendMsg(struct sock *netlink_sk, u_int8_t *msg, int len)
size = NLMSG_SPACE(len);
skb = alloc_skb(size, GFP_ATOMIC);
- if(skb == NULL)
- {
+ if (skb == NULL) {
printk("dev_alloc_skb failure \n");
goto out;
}
old_tail = skb->tail;
- /*ÌîдÊý¾Ý±¨Ïà¹ØÐÅÏ¢*/
+ /* */
nlh = NLMSG_PUT(skb, 0, 0, WAI_K_MSG, size-sizeof(*nlh));
pos = NLMSG_DATA(nlh);
- /*´«Êäµ½Óû§¿Õ¼äµÄÊý¾Ý*/
+ /* */
memcpy(pos, msg, len);
- /*¼ÆËã¾­¹ý×Ö½Ú¶ÔÆäºóµÄÊý¾Ýʵ¼Ê³¤¶È*/
+ /* */
nlh->nlmsg_len = skb->tail - old_tail;
NETLINK_CB(skb).dst_group = COMMTYPE_GROUP;
netlink_broadcast(netlink_sk, skb, 0, COMMTYPE_GROUP, GFP_ATOMIC);
ret = 0;
out:
return ret;
-nlmsg_failure: /*NLMSG_PUT ʧ°Ü£¬Ôò³·ÏúÌ×½Ó×Ö»º´æ*/
+nlmsg_failure: /* */
kfree_skb(skb);
goto out;
#undef COMMTYPE_GROUP
#undef WAI_K_MSG
}
-#endif //ZM_ENABLE_CENC
+#endif /*ZM_ENABLE_CENC*/
/* Simply return 0xffff if VAP function is not supported */
-u16_t zfLnxGetVapId(zdev_t* dev)
+u16_t zfLnxGetVapId(zdev_t *dev)
{
u16_t i;
- for (i=0; i<ZM_VAP_PORT_NUMBER; i++)
- {
- if (vap[i].dev == dev)
- {
- return i;
- }
- }
- return 0xffff;
+ for (i = 0; i < ZM_VAP_PORT_NUMBER; i++) {
+ if (vap[i].dev == dev) {
+ return i;
+ }
+ }
+ return 0xffff;
}
-u32_t zfwReadReg(zdev_t* dev, u32_t offset)
+u32_t zfwReadReg(zdev_t *dev, u32_t offset)
{
return 0;
}
@@ -1012,25 +941,23 @@ u32_t smp_kevent_Lock = 0;
void kevent(struct work_struct *work)
{
struct usbdrv_private *macp =
- container_of(work, struct usbdrv_private, kevent);
- zdev_t *dev = macp->device;
+ container_of(work, struct usbdrv_private, kevent);
+ zdev_t *dev = macp->device;
- if (test_and_set_bit(0, (void *)&smp_kevent_Lock))
- {
- //schedule_work(&macp->kevent);
- return;
+ if (test_and_set_bit(0, (void *)&smp_kevent_Lock)) {
+ /*schedule_work(&macp->kevent);*/
+ return;
}
down(&macp->ioctl_sem);
- if (test_and_clear_bit(KEVENT_WATCHDOG, &macp->kevent_flags))
- {
+ if (test_and_clear_bit(KEVENT_WATCHDOG, &macp->kevent_flags)) {
extern u16_t zfHpStartRecv(zdev_t *dev);
- //zfiHwWatchDogReinit(dev);
- printk(("\n ************ Hw watchDog occur!! ************** \n"));
- zfiWlanSuspend(dev);
- zfiWlanResume(dev,0);
- zfHpStartRecv(dev);
+ /*zfiHwWatchDogReinit(dev);*/
+ printk(("\n ************ Hw watchDog occur!! ************** \n"));
+ zfiWlanSuspend(dev);
+ zfiWlanResume(dev , 0);
+ zfHpStartRecv(dev);
}
clear_bit(0, (void *)&smp_kevent_Lock);
@@ -1083,41 +1010,38 @@ void zfLnxSignalThread(zdev_t *dev, int flag)
{
struct usbdrv_private *macp = dev->ml_priv;
- if (macp == NULL)
- {
- printk("macp is NULL\n");
- return;
+ if (macp == NULL) {
+ printk("macp is NULL\n");
+ return;
}
- if (0 && macp->kevent_ready != 1)
- {
- printk("Kevent not ready\n");
- return;
+ if (0 && macp->kevent_ready != 1) {
+ printk("Kevent not ready\n");
+ return;
}
set_bit(flag, &macp->kevent_flags);
- if (!schedule_work(&macp->kevent))
- {
- //Fails is Normal
- //printk(KERN_ERR "schedule_task failed, flag = %x\n", flag);
- }
+ if (!schedule_work(&macp->kevent)) {
+ /*Fails is Normal
+ //printk(KERN_ERR "schedule_task failed, flag = %x\n", flag);*/
+ }
}
/* Notify wrapper todo redownload firmware and reinit procedure when */
/* hardware watchdog occur : zfiHwWatchDogReinit() */
-void zfLnxWatchDogNotify(zdev_t* dev)
+void zfLnxWatchDogNotify(zdev_t *dev)
{
zfLnxSignalThread(dev, KEVENT_WATCHDOG);
}
/* Query Durantion of Active Scan */
-void zfwGetActiveScanDur(zdev_t* dev, u8_t* Dur)
+void zfwGetActiveScanDur(zdev_t *dev, u8_t *Dur)
{
- *Dur = 30; // default 30 ms
+ *Dur = 30; /* default 30 ms*/
}
-void zfwGetShowZeroLengthSSID(zdev_t* dev, u8_t* Dur)
+void zfwGetShowZeroLengthSSID(zdev_t *dev, u8_t *Dur)
{
*Dur = 0;
}
diff --git a/drivers/staging/otus/zdusb.c b/drivers/staging/otus/zdusb.c
index 2c799a25029..4014b747245 100644
--- a/drivers/staging/otus/zdusb.c
+++ b/drivers/staging/otus/zdusb.c
@@ -48,7 +48,7 @@ static const char driver_name[] = "Otus";
/* table of devices that work with this driver */
static const struct usb_device_id zd1221_ids[] = {
{ USB_DEVICE(VENDOR_ATHR, PRODUCT_AR9170) },
- { USB_DEVICE(VENDOR_DLINK, PRODUCT_DWA160A) },
+ { USB_DEVICE(VENDOR_DLINK, PRODUCT_DWA160A) },
{ USB_DEVICE(VENDOR_NETGEAR, PRODUCT_WNDA3100) },
{ USB_DEVICE(VENDOR_NETGEAR, PRODUCT_WN111v2) },
{ } /* Terminating entry */
@@ -60,9 +60,9 @@ extern u8_t zfLnxInitSetup(struct net_device *dev, struct usbdrv_private *macp);
extern int usbdrv_close(struct net_device *dev);
extern u8_t zfLnxClearStructs(struct net_device *dev);
extern int zfWdsClose(struct net_device *dev);
-extern int zfUnregisterWdsDev(struct net_device* parentDev, u16_t wdsId);
+extern int zfUnregisterWdsDev(struct net_device *parentDev, u16_t wdsId);
extern int zfLnxVapClose(struct net_device *dev);
-extern int zfLnxUnregisterVapDev(struct net_device* parentDev, u16_t vapId);
+extern int zfLnxUnregisterVapDev(struct net_device *parentDev, u16_t vapId);
/* WDS */
extern struct zsWdsStruct wds[ZM_WDS_PORT_NUMBER];
@@ -73,148 +73,135 @@ extern struct zsVapStruct vap[ZM_VAP_PORT_NUMBER];
static int zfLnxProbe(struct usb_interface *interface,
const struct usb_device_id *id)
{
- struct usb_device *dev = interface_to_usbdev(interface);
-
- struct net_device *net = NULL;
- struct usbdrv_private *macp = NULL;
- int vendor_id, product_id;
- int result = 0;
-
- usb_get_dev(dev);
-
- vendor_id = dev->descriptor.idVendor;
- product_id = dev->descriptor.idProduct;
-
-#ifdef HMAC_DEBUG
- printk(KERN_NOTICE "vendor_id = %04x\n", vendor_id);
- printk(KERN_NOTICE "product_id = %04x\n", product_id);
-
- if (dev->speed == USB_SPEED_HIGH)
- printk(KERN_NOTICE "USB 2.0 Host\n");
- else
- printk(KERN_NOTICE "USB 1.1 Host\n");
-#endif
-
- macp = kzalloc(sizeof(struct usbdrv_private), GFP_KERNEL);
- if (!macp)
- {
- printk(KERN_ERR "out of memory allocating device structure\n");
- result = -ENOMEM;
- goto fail;
- }
-
- net = alloc_etherdev(0);
-
- if (net == NULL)
- {
- printk(KERN_ERR "zfLnxProbe: Not able to alloc etherdev struct\n");
- result = -ENOMEM;
- goto fail1;
- }
-
- strcpy(net->name, "ath%d");
-
- net->ml_priv = macp; //kernel 2.6
- macp->udev = dev;
- macp->device = net;
-
- /* set up the endpoint information */
- /* check out the endpoints */
- macp->interface = interface;
-
- //init_waitqueue_head(&macp->regSet_wait);
- //init_waitqueue_head(&macp->iorwRsp_wait);
- //init_waitqueue_head(&macp->term_wait);
-
- if (!zfLnxAllocAllUrbs(macp))
- {
- result = -ENOMEM;
- goto fail2;
- }
-
- if (!zfLnxInitSetup(net, macp))
- {
- result = -EIO;
- goto fail3;
- }
- else
- {
- usb_set_intfdata(interface, macp);
- SET_NETDEV_DEV(net, &interface->dev);
-
- if (register_netdev(net) != 0)
- {
- usb_set_intfdata(interface, NULL);
- goto fail3;
- }
- }
-
- netif_carrier_off(net);
- goto done;
-
+ struct usb_device *dev = interface_to_usbdev(interface);
+
+ struct net_device *net = NULL;
+ struct usbdrv_private *macp = NULL;
+ int vendor_id, product_id;
+ int result = 0;
+
+ usb_get_dev(dev);
+
+ vendor_id = dev->descriptor.idVendor;
+ product_id = dev->descriptor.idProduct;
+
+ #ifdef HMAC_DEBUG
+ printk(KERN_NOTICE "vendor_id = %04x\n", vendor_id);
+ printk(KERN_NOTICE "product_id = %04x\n", product_id);
+
+ if (dev->speed == USB_SPEED_HIGH)
+ printk(KERN_NOTICE "USB 2.0 Host\n");
+ else
+ printk(KERN_NOTICE "USB 1.1 Host\n");
+ #endif
+
+ macp = kzalloc(sizeof(struct usbdrv_private), GFP_KERNEL);
+ if (!macp) {
+ printk(KERN_ERR "out of memory allocating device structure\n");
+ result = -ENOMEM;
+ goto fail;
+ }
+
+ net = alloc_etherdev(0);
+
+ if (net == NULL) {
+ printk(KERN_ERR "zfLnxProbe: Not able to alloc etherdev struct\n");
+ result = -ENOMEM;
+ goto fail1;
+ }
+
+ strcpy(net->name, "ath%d");
+
+ net->ml_priv = macp; /* kernel 2.6 */
+ macp->udev = dev;
+ macp->device = net;
+
+ /* set up the endpoint information */
+ /* check out the endpoints */
+ macp->interface = interface;
+
+ /* init_waitqueue_head(&macp->regSet_wait); */
+ /* init_waitqueue_head(&macp->iorwRsp_wait); */
+ /* init_waitqueue_head(&macp->term_wait); */
+
+ if (!zfLnxAllocAllUrbs(macp)) {
+ result = -ENOMEM;
+ goto fail2;
+ }
+
+ if (!zfLnxInitSetup(net, macp)) {
+ result = -EIO;
+ goto fail3;
+ } else {
+ usb_set_intfdata(interface, macp);
+ SET_NETDEV_DEV(net, &interface->dev);
+
+ if (register_netdev(net) != 0) {
+ usb_set_intfdata(interface, NULL);
+ goto fail3;
+ }
+ }
+
+ netif_carrier_off(net);
+ goto done;
fail3:
- zfLnxFreeAllUrbs(macp);
+ zfLnxFreeAllUrbs(macp);
fail2:
- free_netdev(net); //kernel 2.6
+ free_netdev(net); /* kernel 2.6 */
fail1:
- kfree(macp);
-
+ kfree(macp);
fail:
- usb_put_dev(dev);
- macp = NULL;
-
+ usb_put_dev(dev);
+ macp = NULL;
done:
- return result;
+ return result;
}
static void zfLnxDisconnect(struct usb_interface *interface)
{
- struct usbdrv_private *macp = (struct usbdrv_private *) usb_get_intfdata(interface);
-
- printk(KERN_DEBUG "zfLnxDisconnect\n");
-
- if (!macp)
- {
- printk(KERN_ERR "unregistering non-existant device\n");
- return;
- }
-
- if (macp->driver_isolated)
- {
- if (macp->device->flags & IFF_UP)
- usbdrv_close(macp->device);
- }
-
-#if 0
- /* Close WDS */
- //zfWdsClose(wds[0].dev);
- /* Unregister WDS */
- //zfUnregisterWdsDev(macp->device, 0);
-
- /* Close VAP */
- zfLnxVapClose(vap[0].dev);
- /* Unregister VAP */
- zfLnxUnregisterVapDev(macp->device, 0);
-#endif
+ struct usbdrv_private *macp = (struct usbdrv_private *) usb_get_intfdata(interface);
+
+ printk(KERN_DEBUG "zfLnxDisconnect\n");
+
+ if (!macp) {
+ printk(KERN_ERR "unregistering non-existant device\n");
+ return;
+ }
+
+ if (macp->driver_isolated)
+ if (macp->device->flags & IFF_UP)
+ usbdrv_close(macp->device);
+
+ #if 0
+ /* Close WDS */
+ /* zfWdsClose(wds[0].dev); */
+ /* Unregister WDS */
+ /* zfUnregisterWdsDev(macp->device, 0); */
+
+ /* Close VAP */
+ zfLnxVapClose(vap[0].dev);
+ /* Unregister VAP */
+ zfLnxUnregisterVapDev(macp->device, 0);
+ #endif
- zfLnxClearStructs(macp->device);
+ zfLnxClearStructs(macp->device);
- unregister_netdev(macp->device);
+ unregister_netdev(macp->device);
- usb_put_dev(interface_to_usbdev(interface));
+ usb_put_dev(interface_to_usbdev(interface));
- //printk(KERN_ERR "3. zfLnxUnlinkAllUrbs\n");
- //zfLnxUnlinkAllUrbs(macp);
+ /* printk(KERN_ERR "3. zfLnxUnlinkAllUrbs\n"); */
+ /* zfLnxUnlinkAllUrbs(macp); */
- /* Free network interface */
- free_netdev(macp->device);
+ /* Free network interface */
+ free_netdev(macp->device);
- zfLnxFreeAllUrbs(macp);
- //zfLnxClearStructs(macp->device);
- kfree(macp);
- macp = NULL;
+ zfLnxFreeAllUrbs(macp);
+ /* zfLnxClearStructs(macp->device); */
+ kfree(macp);
+ macp = NULL;
- usb_set_intfdata(interface, NULL);
+ usb_set_intfdata(interface, NULL);
}
static struct usb_driver zd1221_driver = {
@@ -226,13 +213,13 @@ static struct usb_driver zd1221_driver = {
int __init zfLnxIinit(void)
{
- printk(KERN_NOTICE "%s - version %s\n", DRIVER_NAME, VERSIONID);
- return usb_register(&zd1221_driver);
+ printk(KERN_NOTICE "%s - version %s\n", DRIVER_NAME, VERSIONID);
+ return usb_register(&zd1221_driver);
}
void __exit zfLnxExit(void)
{
- usb_deregister(&zd1221_driver);
+ usb_deregister(&zd1221_driver);
}
module_init(zfLnxIinit);
diff --git a/drivers/staging/panel/panel.c b/drivers/staging/panel/panel.c
index 9ca0e9e2a96..3221814a856 100644
--- a/drivers/staging/panel/panel.c
+++ b/drivers/staging/panel/panel.c
@@ -48,6 +48,7 @@
#include <linux/fcntl.h>
#include <linux/init.h>
#include <linux/delay.h>
+#include <linux/kernel.h>
#include <linux/ctype.h>
#include <linux/parport.h>
#include <linux/version.h>
@@ -68,11 +69,16 @@
#define LCD_MAXBYTES 256 /* max burst write */
#define KEYPAD_BUFFER 64
-#define INPUT_POLL_TIME (HZ/50) /* poll the keyboard this every second */
-#define KEYPAD_REP_START (10) /* a key starts to repeat after this times INPUT_POLL_TIME */
-#define KEYPAD_REP_DELAY (2) /* a key repeats this times INPUT_POLL_TIME */
-#define FLASH_LIGHT_TEMPO (200) /* keep the light on this times INPUT_POLL_TIME for each flash */
+/* poll the keyboard this every second */
+#define INPUT_POLL_TIME (HZ/50)
+/* a key starts to repeat after this times INPUT_POLL_TIME */
+#define KEYPAD_REP_START (10)
+/* a key repeats this times INPUT_POLL_TIME */
+#define KEYPAD_REP_DELAY (2)
+
+/* keep the light on this times INPUT_POLL_TIME for each flash */
+#define FLASH_LIGHT_TEMPO (200)
/* converts an r_str() input to an active high, bits string : 000BAOSE */
#define PNL_PINPUT(a) ((((unsigned char)(a)) ^ 0x7F) >> 3)
@@ -84,7 +90,8 @@
#define PNL_PERRORP 0x08 /* direct input, active low */
#define PNL_PBIDIR 0x20 /* bi-directional ports */
-#define PNL_PINTEN 0x10 /* high to read data in or-ed with data out */
+/* high to read data in or-ed with data out */
+#define PNL_PINTEN 0x10
#define PNL_PSELECP 0x08 /* inverted output, active low */
#define PNL_PINITP 0x04 /* direct output, active low */
#define PNL_PAUTOLF 0x02 /* inverted output, active low */
@@ -123,7 +130,7 @@
#define LCD_FLAG_N 0x0040 /* 2-rows mode */
#define LCD_FLAG_L 0x0080 /* backlight enabled */
-#define LCD_ESCAPE_LEN 24 /* 24 chars max for an LCD escape command */
+#define LCD_ESCAPE_LEN 24 /* max chars for LCD escape command */
#define LCD_ESCAPE_CHAR 27 /* use char 27 for escape command */
/* macros to simplify use of the parallel port */
@@ -134,8 +141,10 @@
#define w_dtr(x, y) do { parport_write_data((x)->port, (y)); } while (0)
/* this defines which bits are to be used and which ones to be ignored */
-static __u8 scan_mask_o; /* logical or of the output bits involved in the scan matrix */
-static __u8 scan_mask_i; /* logical or of the input bits involved in the scan matrix */
+/* logical or of the output bits involved in the scan matrix */
+static __u8 scan_mask_o;
+/* logical or of the input bits involved in the scan matrix */
+static __u8 scan_mask_i;
typedef __u64 pmask_t;
@@ -161,14 +170,14 @@ struct logical_input {
__u8 rise_timer, fall_timer, high_timer;
union {
- struct { /* this structure is valid when type == INPUT_TYPE_STD */
+ struct { /* valid when type == INPUT_TYPE_STD */
void (*press_fct) (int);
void (*release_fct) (int);
int press_data;
int release_data;
} std;
- struct { /* this structure is valid when type == INPUT_TYPE_KBD */
- /* strings can be full-length (ie. non null-terminated) */
+ struct { /* valid when type == INPUT_TYPE_KBD */
+ /* strings can be non null-terminated */
char press_str[sizeof(void *) + sizeof(int)];
char repeat_str[sizeof(void *) + sizeof(int)];
char release_str[sizeof(void *) + sizeof(int)];
@@ -188,11 +197,17 @@ LIST_HEAD(logical_inputs); /* list of all defined logical inputs */
* 0000000000000000000BAPSEBAPSEBAPSEBAPSEBAPSEBAPSEBAPSEBAPSEBAPSE
* <-----unused------><gnd><d07><d06><d05><d04><d03><d02><d01><d00>
*/
-static pmask_t phys_read; /* what has just been read from the I/O ports */
-static pmask_t phys_read_prev; /* previous phys_read */
-static pmask_t phys_curr; /* stabilized phys_read (phys_read|phys_read_prev) */
-static pmask_t phys_prev; /* previous phys_curr */
-static char inputs_stable; /* 0 means that at least one logical signal needs be computed */
+
+/* what has just been read from the I/O ports */
+static pmask_t phys_read;
+/* previous phys_read */
+static pmask_t phys_read_prev;
+/* stabilized phys_read (phys_read|phys_read_prev) */
+static pmask_t phys_curr;
+/* previous phys_curr */
+static pmask_t phys_prev;
+/* 0 means that at least one logical signal needs be computed */
+static char inputs_stable;
/* these variables are specific to the keypad */
static char keypad_buffer[KEYPAD_BUFFER];
@@ -202,11 +217,17 @@ static char keypressed;
static wait_queue_head_t keypad_read_wait;
/* lcd-specific variables */
-static unsigned long int lcd_flags; /* contains the LCD config state */
-static unsigned long int lcd_addr_x; /* contains the LCD X offset */
-static unsigned long int lcd_addr_y; /* contains the LCD Y offset */
-static char lcd_escape[LCD_ESCAPE_LEN + 1]; /* current escape sequence, 0 terminated */
-static int lcd_escape_len = -1; /* not in escape state. >=0 = escape cmd len */
+
+/* contains the LCD config state */
+static unsigned long int lcd_flags;
+/* contains the LCD X offset */
+static unsigned long int lcd_addr_x;
+/* contains the LCD Y offset */
+static unsigned long int lcd_addr_y;
+/* current escape sequence, 0 terminated */
+static char lcd_escape[LCD_ESCAPE_LEN + 1];
+/* not in escape state. >=0 = escape cmd len */
+static int lcd_escape_len = -1;
/*
* Bit masks to convert LCD signals to parallel port outputs.
@@ -436,11 +457,13 @@ MODULE_PARM_DESC(keypad_enabled, "Deprecated option, use keypad_type instead");
static int lcd_type = -1;
module_param(lcd_type, int, 0000);
MODULE_PARM_DESC(lcd_type,
- "LCD type: 0=none, 1=old //, 2=serial ks0074, 3=hantronix //, 4=nexcom //, 5=compiled-in");
+ "LCD type: 0=none, 1=old //, 2=serial ks0074, "
+ "3=hantronix //, 4=nexcom //, 5=compiled-in");
static int lcd_proto = -1;
module_param(lcd_proto, int, 0000);
-MODULE_PARM_DESC(lcd_proto, "LCD communication: 0=parallel (//), 1=serial,"
+MODULE_PARM_DESC(lcd_proto,
+ "LCD communication: 0=parallel (//), 1=serial,"
"2=TI LCD Interface");
static int lcd_charset = -1;
@@ -450,12 +473,14 @@ MODULE_PARM_DESC(lcd_charset, "LCD character set: 0=standard, 1=KS0074");
static int keypad_type = -1;
module_param(keypad_type, int, 0000);
MODULE_PARM_DESC(keypad_type,
- "Keypad type: 0=none, 1=old 6 keys, 2=new 6+1 keys, 3=nexcom 4 keys");
+ "Keypad type: 0=none, 1=old 6 keys, 2=new 6+1 keys, "
+ "3=nexcom 4 keys");
static int profile = DEFAULT_PROFILE;
module_param(profile, int, 0000);
MODULE_PARM_DESC(profile,
- "1=16x2 old kp; 2=serial 16x2, new kp; 3=16x2 hantronix; 4=16x2 nexcom; default=40x2, old kp");
+ "1=16x2 old kp; 2=serial 16x2, new kp; 3=16x2 hantronix; "
+ "4=16x2 nexcom; default=40x2, old kp");
/*
* These are the parallel port pins the LCD control signals are connected to.
@@ -469,32 +494,38 @@ MODULE_PARM_DESC(profile,
static int lcd_e_pin = PIN_NOT_SET;
module_param(lcd_e_pin, int, 0000);
MODULE_PARM_DESC(lcd_e_pin,
- "# of the // port pin connected to LCD 'E' signal, with polarity (-17..17)");
+ "# of the // port pin connected to LCD 'E' signal, "
+ "with polarity (-17..17)");
static int lcd_rs_pin = PIN_NOT_SET;
module_param(lcd_rs_pin, int, 0000);
MODULE_PARM_DESC(lcd_rs_pin,
- "# of the // port pin connected to LCD 'RS' signal, with polarity (-17..17)");
+ "# of the // port pin connected to LCD 'RS' signal, "
+ "with polarity (-17..17)");
static int lcd_rw_pin = PIN_NOT_SET;
module_param(lcd_rw_pin, int, 0000);
MODULE_PARM_DESC(lcd_rw_pin,
- "# of the // port pin connected to LCD 'RW' signal, with polarity (-17..17)");
+ "# of the // port pin connected to LCD 'RW' signal, "
+ "with polarity (-17..17)");
static int lcd_bl_pin = PIN_NOT_SET;
module_param(lcd_bl_pin, int, 0000);
MODULE_PARM_DESC(lcd_bl_pin,
- "# of the // port pin connected to LCD backlight, with polarity (-17..17)");
+ "# of the // port pin connected to LCD backlight, "
+ "with polarity (-17..17)");
static int lcd_da_pin = PIN_NOT_SET;
module_param(lcd_da_pin, int, 0000);
MODULE_PARM_DESC(lcd_da_pin,
- "# of the // port pin connected to serial LCD 'SDA' signal, with polarity (-17..17)");
+ "# of the // port pin connected to serial LCD 'SDA' "
+ "signal, with polarity (-17..17)");
static int lcd_cl_pin = PIN_NOT_SET;
module_param(lcd_cl_pin, int, 0000);
MODULE_PARM_DESC(lcd_cl_pin,
- "# of the // port pin connected to serial LCD 'SCL' signal, with polarity (-17..17)");
+ "# of the // port pin connected to serial LCD 'SCL' "
+ "signal, with polarity (-17..17)");
static unsigned char *lcd_char_conv;
@@ -572,12 +603,12 @@ static char (*keypad_profile)[4][9] = old_keypad_profile;
/* FIXME: this should be converted to a bit array containing signals states */
static struct {
- unsigned char e; /* parallel LCD E (data latch on falling edge) */
- unsigned char rs; /* parallel LCD RS (0 = cmd, 1 = data) */
- unsigned char rw; /* parallel LCD R/W (0 = W, 1 = R) */
- unsigned char bl; /* parallel LCD backlight (0 = off, 1 = on) */
- unsigned char cl; /* serial LCD clock (latch on rising edge) */
- unsigned char da; /* serial LCD data */
+ unsigned char e; /* parallel LCD E (data latch on falling edge) */
+ unsigned char rs; /* parallel LCD RS (0 = cmd, 1 = data) */
+ unsigned char rw; /* parallel LCD R/W (0 = W, 1 = R) */
+ unsigned char bl; /* parallel LCD backlight (0 = off, 1 = on) */
+ unsigned char cl; /* serial LCD clock (latch on rising edge) */
+ unsigned char da; /* serial LCD data */
} bits;
static void init_scan_timer(void);
@@ -666,7 +697,7 @@ void pin_to_bits(int pin, unsigned char *d_val, unsigned char *c_val)
c_bit = PNL_PAUTOLF;
inv = !inv;
break;
- case PIN_INITP: /* init, direct */
+ case PIN_INITP: /* init, direct */
c_bit = PNL_PINITP;
break;
case PIN_SELECP: /* select_in, inverted */
@@ -698,23 +729,23 @@ static void long_sleep(int ms)
}
}
-/* send a serial byte to the LCD panel. The caller is responsible for locking if needed. */
+/* send a serial byte to the LCD panel. The caller is responsible for locking
+ if needed. */
static void lcd_send_serial(int byte)
{
int bit;
/* the data bit is set on D0, and the clock on STROBE.
- * LCD reads D0 on STROBE's rising edge.
- */
+ * LCD reads D0 on STROBE's rising edge. */
for (bit = 0; bit < 8; bit++) {
bits.cl = BIT_CLR; /* CLK low */
panel_set_bits();
bits.da = byte & 1;
panel_set_bits();
- udelay(2); /* maintain the data during 2 us before CLK up */
+ udelay(2); /* maintain the data during 2 us before CLK up */
bits.cl = BIT_SET; /* CLK high */
panel_set_bits();
- udelay(1); /* maintain the strobe during 1 us */
+ udelay(1); /* maintain the strobe during 1 us */
byte >>= 1;
}
}
@@ -760,19 +791,19 @@ static void lcd_write_cmd_p8(int cmd)
spin_lock(&pprt_lock);
/* present the data to the data port */
w_dtr(pprt, cmd);
- udelay(20); /* maintain the data during 20 us before the strobe */
+ udelay(20); /* maintain the data during 20 us before the strobe */
bits.e = BIT_SET;
bits.rs = BIT_CLR;
bits.rw = BIT_CLR;
set_ctrl_bits();
- udelay(40); /* maintain the strobe during 40 us */
+ udelay(40); /* maintain the strobe during 40 us */
bits.e = BIT_CLR;
set_ctrl_bits();
- udelay(120); /* the shortest command takes at least 120 us */
+ udelay(120); /* the shortest command takes at least 120 us */
spin_unlock(&pprt_lock);
}
@@ -782,19 +813,19 @@ static void lcd_write_data_p8(int data)
spin_lock(&pprt_lock);
/* present the data to the data port */
w_dtr(pprt, data);
- udelay(20); /* maintain the data during 20 us before the strobe */
+ udelay(20); /* maintain the data during 20 us before the strobe */
bits.e = BIT_SET;
bits.rs = BIT_SET;
bits.rw = BIT_CLR;
set_ctrl_bits();
- udelay(40); /* maintain the strobe during 40 us */
+ udelay(40); /* maintain the strobe during 40 us */
bits.e = BIT_CLR;
set_ctrl_bits();
- udelay(45); /* the shortest data takes at least 45 us */
+ udelay(45); /* the shortest data takes at least 45 us */
spin_unlock(&pprt_lock);
}
@@ -822,7 +853,8 @@ static void lcd_gotoxy(void)
{
lcd_write_cmd(0x80 /* set DDRAM address */
| (lcd_addr_y ? lcd_hwidth : 0)
- /* we force the cursor to stay at the end of the line if it wants to go farther */
+ /* we force the cursor to stay at the end of the
+ line if it wants to go farther */
| ((lcd_addr_x < lcd_bwidth) ? lcd_addr_x &
(lcd_hwidth - 1) : lcd_bwidth - 1));
}
@@ -871,19 +903,23 @@ static void lcd_clear_fast_p8(void)
for (pos = 0; pos < lcd_height * lcd_hwidth; pos++) {
/* present the data to the data port */
w_dtr(pprt, ' ');
- udelay(20); /* maintain the data during 20 us before the strobe */
+
+ /* maintain the data during 20 us before the strobe */
+ udelay(20);
bits.e = BIT_SET;
bits.rs = BIT_SET;
bits.rw = BIT_CLR;
set_ctrl_bits();
- udelay(40); /* maintain the strobe during 40 us */
+ /* maintain the strobe during 40 us */
+ udelay(40);
bits.e = BIT_CLR;
set_ctrl_bits();
- udelay(45); /* the shortest data takes at least 45 us */
+ /* the shortest data takes at least 45 us */
+ udelay(45);
}
spin_unlock(&pprt_lock);
@@ -954,7 +990,8 @@ static void lcd_init_display(void)
long_sleep(10);
- lcd_write_cmd(0x06); /* entry mode set : increment, cursor shifting */
+ /* entry mode set : increment, cursor shifting */
+ lcd_write_cmd(0x06);
lcd_clear_display();
}
@@ -966,317 +1003,336 @@ static void lcd_init_display(void)
*
*/
+static inline int handle_lcd_special_code(void)
+{
+ /* LCD special codes */
+
+ int processed = 0;
+
+ char *esc = lcd_escape + 2;
+ int oldflags = lcd_flags;
+
+ /* check for display mode flags */
+ switch (*esc) {
+ case 'D': /* Display ON */
+ lcd_flags |= LCD_FLAG_D;
+ processed = 1;
+ break;
+ case 'd': /* Display OFF */
+ lcd_flags &= ~LCD_FLAG_D;
+ processed = 1;
+ break;
+ case 'C': /* Cursor ON */
+ lcd_flags |= LCD_FLAG_C;
+ processed = 1;
+ break;
+ case 'c': /* Cursor OFF */
+ lcd_flags &= ~LCD_FLAG_C;
+ processed = 1;
+ break;
+ case 'B': /* Blink ON */
+ lcd_flags |= LCD_FLAG_B;
+ processed = 1;
+ break;
+ case 'b': /* Blink OFF */
+ lcd_flags &= ~LCD_FLAG_B;
+ processed = 1;
+ break;
+ case '+': /* Back light ON */
+ lcd_flags |= LCD_FLAG_L;
+ processed = 1;
+ break;
+ case '-': /* Back light OFF */
+ lcd_flags &= ~LCD_FLAG_L;
+ processed = 1;
+ break;
+ case '*':
+ /* flash back light using the keypad timer */
+ if (scan_timer.function != NULL) {
+ if (light_tempo == 0 && ((lcd_flags & LCD_FLAG_L) == 0))
+ lcd_backlight(1);
+ light_tempo = FLASH_LIGHT_TEMPO;
+ }
+ processed = 1;
+ break;
+ case 'f': /* Small Font */
+ lcd_flags &= ~LCD_FLAG_F;
+ processed = 1;
+ break;
+ case 'F': /* Large Font */
+ lcd_flags |= LCD_FLAG_F;
+ processed = 1;
+ break;
+ case 'n': /* One Line */
+ lcd_flags &= ~LCD_FLAG_N;
+ processed = 1;
+ break;
+ case 'N': /* Two Lines */
+ lcd_flags |= LCD_FLAG_N;
+ break;
+ case 'l': /* Shift Cursor Left */
+ if (lcd_addr_x > 0) {
+ /* back one char if not at end of line */
+ if (lcd_addr_x < lcd_bwidth)
+ lcd_write_cmd(0x10);
+ lcd_addr_x--;
+ }
+ processed = 1;
+ break;
+ case 'r': /* shift cursor right */
+ if (lcd_addr_x < lcd_width) {
+ /* allow the cursor to pass the end of the line */
+ if (lcd_addr_x <
+ (lcd_bwidth - 1))
+ lcd_write_cmd(0x14);
+ lcd_addr_x++;
+ }
+ processed = 1;
+ break;
+ case 'L': /* shift display left */
+ lcd_left_shift++;
+ lcd_write_cmd(0x18);
+ processed = 1;
+ break;
+ case 'R': /* shift display right */
+ lcd_left_shift--;
+ lcd_write_cmd(0x1C);
+ processed = 1;
+ break;
+ case 'k': { /* kill end of line */
+ int x;
+ for (x = lcd_addr_x; x < lcd_bwidth; x++)
+ lcd_write_data(' ');
+
+ /* restore cursor position */
+ lcd_gotoxy();
+ processed = 1;
+ break;
+ }
+ case 'I': /* reinitialize display */
+ lcd_init_display();
+ lcd_left_shift = 0;
+ processed = 1;
+ break;
+ case 'G': {
+ /* Generator : LGcxxxxx...xx; must have <c> between '0'
+ * and '7', representing the numerical ASCII code of the
+ * redefined character, and <xx...xx> a sequence of 16
+ * hex digits representing 8 bytes for each character.
+ * Most LCDs will only use 5 lower bits of the 7 first
+ * bytes.
+ */
+
+ unsigned char cgbytes[8];
+ unsigned char cgaddr;
+ int cgoffset;
+ int shift;
+ char value;
+ int addr;
+
+ if (strchr(esc, ';') == NULL)
+ break;
+
+ esc++;
+
+ cgaddr = *(esc++) - '0';
+ if (cgaddr > 7) {
+ processed = 1;
+ break;
+ }
+
+ cgoffset = 0;
+ shift = 0;
+ value = 0;
+ while (*esc && cgoffset < 8) {
+ shift ^= 4;
+ if (*esc >= '0' && *esc <= '9')
+ value |= (*esc - '0') << shift;
+ else if (*esc >= 'A' && *esc <= 'Z')
+ value |= (*esc - 'A' + 10) << shift;
+ else if (*esc >= 'a' && *esc <= 'z')
+ value |= (*esc - 'a' + 10) << shift;
+ else {
+ esc++;
+ continue;
+ }
+
+ if (shift == 0) {
+ cgbytes[cgoffset++] = value;
+ value = 0;
+ }
+
+ esc++;
+ }
+
+ lcd_write_cmd(0x40 | (cgaddr * 8));
+ for (addr = 0; addr < cgoffset; addr++)
+ lcd_write_data(cgbytes[addr]);
+
+ /* ensures that we stop writing to CGRAM */
+ lcd_gotoxy();
+ processed = 1;
+ break;
+ }
+ case 'x': /* gotoxy : LxXXX[yYYY]; */
+ case 'y': /* gotoxy : LyYYY[xXXX]; */
+ if (strchr(esc, ';') == NULL)
+ break;
+
+ while (*esc) {
+ char *endp;
+
+ if (*esc == 'x') {
+ esc++;
+ lcd_addr_x = simple_strtoul(esc, &endp, 10);
+ esc = endp;
+ } else if (*esc == 'y') {
+ esc++;
+ lcd_addr_y = simple_strtoul(esc, &endp, 10);
+ esc = endp;
+ } else
+ break;
+ }
+
+ lcd_gotoxy();
+ processed = 1;
+ break;
+ }
+
+ /* Check wether one flag was changed */
+ if (oldflags != lcd_flags) {
+ /* check whether one of B,C,D flags were changed */
+ if ((oldflags ^ lcd_flags) &
+ (LCD_FLAG_B | LCD_FLAG_C | LCD_FLAG_D))
+ /* set display mode */
+ lcd_write_cmd(0x08
+ | ((lcd_flags & LCD_FLAG_D) ? 4 : 0)
+ | ((lcd_flags & LCD_FLAG_C) ? 2 : 0)
+ | ((lcd_flags & LCD_FLAG_B) ? 1 : 0));
+ /* check whether one of F,N flags was changed */
+ else if ((oldflags ^ lcd_flags) & (LCD_FLAG_F | LCD_FLAG_N))
+ lcd_write_cmd(0x30
+ | ((lcd_flags & LCD_FLAG_F) ? 4 : 0)
+ | ((lcd_flags & LCD_FLAG_N) ? 8 : 0));
+ /* check wether L flag was changed */
+ else if ((oldflags ^ lcd_flags) & (LCD_FLAG_L)) {
+ if (lcd_flags & (LCD_FLAG_L))
+ lcd_backlight(1);
+ else if (light_tempo == 0)
+ /* switch off the light only when the tempo
+ lighting is gone */
+ lcd_backlight(0);
+ }
+ }
+
+ return processed;
+}
+
static ssize_t lcd_write(struct file *file,
const char *buf, size_t count, loff_t *ppos)
{
-
const char *tmp = buf;
char c;
for (; count-- > 0; (ppos ? (*ppos)++ : 0), ++tmp) {
if (!in_interrupt() && (((count + 1) & 0x1f) == 0))
- schedule(); /* let's be a little nice with other processes that need some CPU */
+ /* let's be a little nice with other processes
+ that need some CPU */
+ schedule();
if (ppos == NULL && file == NULL)
- c = *tmp; /* let's not use get_user() from the kernel ! */
+ /* let's not use get_user() from the kernel ! */
+ c = *tmp;
else if (get_user(c, tmp))
return -EFAULT;
/* first, we'll test if we're in escape mode */
- if ((c != '\n') && lcd_escape_len >= 0) { /* yes, let's add this char to the buffer */
+ if ((c != '\n') && lcd_escape_len >= 0) {
+ /* yes, let's add this char to the buffer */
lcd_escape[lcd_escape_len++] = c;
lcd_escape[lcd_escape_len] = 0;
} else {
- lcd_escape_len = -1; /* aborts any previous escape sequence */
+ /* aborts any previous escape sequence */
+ lcd_escape_len = -1;
switch (c) {
- case LCD_ESCAPE_CHAR: /* start of an escape sequence */
+ case LCD_ESCAPE_CHAR:
+ /* start of an escape sequence */
lcd_escape_len = 0;
lcd_escape[lcd_escape_len] = 0;
break;
- case '\b': /* go back one char and clear it */
+ case '\b':
+ /* go back one char and clear it */
if (lcd_addr_x > 0) {
- if (lcd_addr_x < lcd_bwidth) /* check if we're not at the end of the line */
- lcd_write_cmd(0x10); /* back one char */
+ /* check if we're not at the
+ end of the line */
+ if (lcd_addr_x < lcd_bwidth)
+ /* back one char */
+ lcd_write_cmd(0x10);
lcd_addr_x--;
}
- lcd_write_data(' '); /* replace with a space */
- lcd_write_cmd(0x10); /* back one char again */
+ /* replace with a space */
+ lcd_write_data(' ');
+ /* back one char again */
+ lcd_write_cmd(0x10);
break;
- case '\014': /* quickly clear the display */
+ case '\014':
+ /* quickly clear the display */
lcd_clear_fast();
break;
- case '\n': /* flush the remainder of the current line and go to the
- beginning of the next line */
+ case '\n':
+ /* flush the remainder of the current line and
+ go to the beginning of the next line */
for (; lcd_addr_x < lcd_bwidth; lcd_addr_x++)
lcd_write_data(' ');
lcd_addr_x = 0;
lcd_addr_y = (lcd_addr_y + 1) % lcd_height;
lcd_gotoxy();
break;
- case '\r': /* go to the beginning of the same line */
+ case '\r':
+ /* go to the beginning of the same line */
lcd_addr_x = 0;
lcd_gotoxy();
break;
- case '\t': /* print a space instead of the tab */
+ case '\t':
+ /* print a space instead of the tab */
lcd_print(' ');
break;
- default: /* simply print this char */
+ default:
+ /* simply print this char */
lcd_print(c);
break;
}
}
/* now we'll see if we're in an escape mode and if the current
- escape sequence can be understood.
- */
- if (lcd_escape_len >= 2) { /* minimal length for an escape command */
- int processed = 0; /* 1 means the command has been processed */
+ escape sequence can be understood. */
+ if (lcd_escape_len >= 2) {
+ int processed = 0;
- if (!strcmp(lcd_escape, "[2J")) { /* Clear the display */
- lcd_clear_fast(); /* clear display */
+ if (!strcmp(lcd_escape, "[2J")) {
+ /* clear the display */
+ lcd_clear_fast();
processed = 1;
- } else if (!strcmp(lcd_escape, "[H")) { /* Cursor to home */
+ } else if (!strcmp(lcd_escape, "[H")) {
+ /* cursor to home */
lcd_addr_x = lcd_addr_y = 0;
lcd_gotoxy();
processed = 1;
}
/* codes starting with ^[[L */
else if ((lcd_escape_len >= 3) &&
- (lcd_escape[0] == '[') && (lcd_escape[1] == 'L')) { /* LCD special codes */
-
- char *esc = lcd_escape + 2;
- int oldflags = lcd_flags;
-
- /* check for display mode flags */
- switch (*esc) {
- case 'D': /* Display ON */
- lcd_flags |= LCD_FLAG_D;
- processed = 1;
- break;
- case 'd': /* Display OFF */
- lcd_flags &= ~LCD_FLAG_D;
- processed = 1;
- break;
- case 'C': /* Cursor ON */
- lcd_flags |= LCD_FLAG_C;
- processed = 1;
- break;
- case 'c': /* Cursor OFF */
- lcd_flags &= ~LCD_FLAG_C;
- processed = 1;
- break;
- case 'B': /* Blink ON */
- lcd_flags |= LCD_FLAG_B;
- processed = 1;
- break;
- case 'b': /* Blink OFF */
- lcd_flags &= ~LCD_FLAG_B;
- processed = 1;
- break;
- case '+': /* Back light ON */
- lcd_flags |= LCD_FLAG_L;
- processed = 1;
- break;
- case '-': /* Back light OFF */
- lcd_flags &= ~LCD_FLAG_L;
- processed = 1;
- break;
- case '*': /* flash back light using the keypad timer */
- if (scan_timer.function != NULL) {
- if (light_tempo == 0
- && ((lcd_flags & LCD_FLAG_L)
- == 0))
- lcd_backlight(1);
- light_tempo = FLASH_LIGHT_TEMPO;
- }
- processed = 1;
- break;
- case 'f': /* Small Font */
- lcd_flags &= ~LCD_FLAG_F;
- processed = 1;
- break;
- case 'F': /* Large Font */
- lcd_flags |= LCD_FLAG_F;
- processed = 1;
- break;
- case 'n': /* One Line */
- lcd_flags &= ~LCD_FLAG_N;
- processed = 1;
- break;
- case 'N': /* Two Lines */
- lcd_flags |= LCD_FLAG_N;
- break;
-
- case 'l': /* Shift Cursor Left */
- if (lcd_addr_x > 0) {
- if (lcd_addr_x < lcd_bwidth)
- lcd_write_cmd(0x10); /* back one char if not at end of line */
- lcd_addr_x--;
- }
- processed = 1;
- break;
-
- case 'r': /* shift cursor right */
- if (lcd_addr_x < lcd_width) {
- if (lcd_addr_x < (lcd_bwidth - 1))
- lcd_write_cmd(0x14); /* allow the cursor to pass the end of the line */
- lcd_addr_x++;
- }
- processed = 1;
- break;
-
- case 'L': /* shift display left */
- lcd_left_shift++;
- lcd_write_cmd(0x18);
- processed = 1;
- break;
-
- case 'R': /* shift display right */
- lcd_left_shift--;
- lcd_write_cmd(0x1C);
- processed = 1;
- break;
-
- case 'k':{ /* kill end of line */
- int x;
- for (x = lcd_addr_x; x < lcd_bwidth; x++)
- lcd_write_data(' ');
- lcd_gotoxy(); /* restore cursor position */
- processed = 1;
- break;
- }
- case 'I': /* reinitialize display */
- lcd_init_display();
- lcd_left_shift = 0;
- processed = 1;
- break;
-
- case 'G': /* Generator : LGcxxxxx...xx; */ {
- /* must have <c> between '0' and '7', representing the numerical
- * ASCII code of the redefined character, and <xx...xx> a sequence
- * of 16 hex digits representing 8 bytes for each character. Most
- * LCDs will only use 5 lower bits of the 7 first bytes.
- */
-
- unsigned char cgbytes[8];
- unsigned char cgaddr;
- int cgoffset;
- int shift;
- char value;
- int addr;
-
- if (strchr(esc, ';') == NULL)
- break;
-
- esc++;
-
- cgaddr = *(esc++) - '0';
- if (cgaddr > 7) {
- processed = 1;
- break;
- }
-
- cgoffset = 0;
- shift = 0;
- value = 0;
- while (*esc && cgoffset < 8) {
- shift ^= 4;
- if (*esc >= '0' && *esc <= '9')
- value |= (*esc - '0') << shift;
- else if (*esc >= 'A' && *esc <= 'Z')
- value |= (*esc - 'A' + 10) << shift;
- else if (*esc >= 'a' && *esc <= 'z')
- value |= (*esc - 'a' + 10) << shift;
- else {
- esc++;
- continue;
- }
-
- if (shift == 0) {
- cgbytes[cgoffset++] = value;
- value = 0;
- }
-
- esc++;
- }
-
- lcd_write_cmd(0x40 | (cgaddr * 8));
- for (addr = 0; addr < cgoffset; addr++)
- lcd_write_data(cgbytes[addr]);
-
- lcd_gotoxy(); /* ensures that we stop writing to CGRAM */
- processed = 1;
- break;
- }
- case 'x': /* gotoxy : LxXXX[yYYY]; */
- case 'y': /* gotoxy : LyYYY[xXXX]; */
- if (strchr(esc, ';') == NULL)
- break;
-
- while (*esc) {
- if (*esc == 'x') {
- esc++;
- lcd_addr_x = 0;
- while (isdigit(*esc)) {
- lcd_addr_x =
- lcd_addr_x *
- 10 + (*esc -
- '0');
- esc++;
- }
- } else if (*esc == 'y') {
- esc++;
- lcd_addr_y = 0;
- while (isdigit(*esc)) {
- lcd_addr_y =
- lcd_addr_y *
- 10 + (*esc -
- '0');
- esc++;
- }
- } else
- break;
- }
-
- lcd_gotoxy();
- processed = 1;
- break;
- } /* end of switch */
-
- /* Check wether one flag was changed */
- if (oldflags != lcd_flags) {
- /* check wether one of B,C,D flags was changed */
- if ((oldflags ^ lcd_flags) &
- (LCD_FLAG_B | LCD_FLAG_C | LCD_FLAG_D))
- /* set display mode */
- lcd_write_cmd(0x08 |
- ((lcd_flags & LCD_FLAG_D) ? 4 : 0) |
- ((lcd_flags & LCD_FLAG_C) ? 2 : 0) |
- ((lcd_flags & LCD_FLAG_B) ? 1 : 0));
- /* check wether one of F,N flags was changed */
- else if ((oldflags ^ lcd_flags) &
- (LCD_FLAG_F | LCD_FLAG_N))
- lcd_write_cmd(0x30 |
- ((lcd_flags & LCD_FLAG_F) ? 4 : 0) |
- ((lcd_flags & LCD_FLAG_N) ? 8 : 0));
- /* check wether L flag was changed */
- else if ((oldflags ^ lcd_flags) &
- (LCD_FLAG_L)) {
- if (lcd_flags & (LCD_FLAG_L))
- lcd_backlight(1);
- else if (light_tempo == 0) /* switch off the light only when the tempo lighting is gone */
- lcd_backlight(0);
- }
- }
+ (lcd_escape[0] == '[') &&
+ (lcd_escape[1] == 'L')) {
+ processed = handle_lcd_special_code();
}
/* LCD special escape codes */
- /* flush the escape sequence if it's been processed or if it is
- getting too long. */
+ /* flush the escape sequence if it's been processed
+ or if it is getting too long. */
if (processed || (lcd_escape_len >= LCD_ESCAPE_LEN))
lcd_escape_len = -1;
- } /* escape codes */
+ } /* escape codes */
}
return tmp - buf;
@@ -1295,7 +1351,7 @@ static int lcd_open(struct inode *inode, struct file *file)
lcd_must_clear = 0;
}
lcd_open_cnt++;
- return 0;
+ return nonseekable_open(inode, file);
}
static int lcd_release(struct inode *inode, struct file *file)
@@ -1304,10 +1360,11 @@ static int lcd_release(struct inode *inode, struct file *file)
return 0;
}
-static struct file_operations lcd_fops = {
+static const struct file_operations lcd_fops = {
.write = lcd_write,
.open = lcd_open,
.release = lcd_release,
+ .llseek = no_llseek,
};
static struct miscdevice lcd_dev = {
@@ -1327,7 +1384,8 @@ void panel_lcd_print(char *s)
void lcd_init(void)
{
switch (lcd_type) {
- case LCD_TYPE_OLD: /* parallel mode, 8 bits */
+ case LCD_TYPE_OLD:
+ /* parallel mode, 8 bits */
if (lcd_proto < 0)
lcd_proto = LCD_PROTO_PARALLEL;
if (lcd_charset < 0)
@@ -1346,7 +1404,8 @@ void lcd_init(void)
if (lcd_height < 0)
lcd_height = 2;
break;
- case LCD_TYPE_KS0074: /* serial mode, ks0074 */
+ case LCD_TYPE_KS0074:
+ /* serial mode, ks0074 */
if (lcd_proto < 0)
lcd_proto = LCD_PROTO_SERIAL;
if (lcd_charset < 0)
@@ -1367,7 +1426,8 @@ void lcd_init(void)
if (lcd_height < 0)
lcd_height = 2;
break;
- case LCD_TYPE_NEXCOM: /* parallel mode, 8 bits, generic */
+ case LCD_TYPE_NEXCOM:
+ /* parallel mode, 8 bits, generic */
if (lcd_proto < 0)
lcd_proto = LCD_PROTO_PARALLEL;
if (lcd_charset < 0)
@@ -1388,14 +1448,16 @@ void lcd_init(void)
if (lcd_height < 0)
lcd_height = 2;
break;
- case LCD_TYPE_CUSTOM: /* customer-defined */
+ case LCD_TYPE_CUSTOM:
+ /* customer-defined */
if (lcd_proto < 0)
lcd_proto = DEFAULT_LCD_PROTO;
if (lcd_charset < 0)
lcd_charset = DEFAULT_LCD_CHARSET;
/* default geometry will be set later */
break;
- case LCD_TYPE_HANTRONIX: /* parallel mode, 8 bits, hantronix-like */
+ case LCD_TYPE_HANTRONIX:
+ /* parallel mode, 8 bits, hantronix-like */
default:
if (lcd_proto < 0)
lcd_proto = LCD_PROTO_PARALLEL;
@@ -1496,8 +1558,7 @@ void lcd_init(void)
/* before this line, we must NOT send anything to the display.
* Since lcd_init_display() needs to write data, we have to
- * enable mark the LCD initialized just before.
- */
+ * enable mark the LCD initialized just before. */
lcd_initialized = 1;
lcd_init_display();
@@ -1511,7 +1572,8 @@ void lcd_init(void)
PANEL_VERSION);
#endif
lcd_addr_x = lcd_addr_y = 0;
- lcd_must_clear = 1; /* clear the display on the next device opening */
+ /* clear the display on the next device opening */
+ lcd_must_clear = 1;
lcd_gotoxy();
}
@@ -1535,7 +1597,8 @@ static ssize_t keypad_read(struct file *file,
return -EINTR;
}
- for (; count-- > 0 && (keypad_buflen > 0); ++i, ++tmp, --keypad_buflen) {
+ for (; count-- > 0 && (keypad_buflen > 0);
+ ++i, ++tmp, --keypad_buflen) {
put_user(keypad_buffer[keypad_start], tmp);
keypad_start = (keypad_start + 1) % KEYPAD_BUFFER;
}
@@ -1564,7 +1627,7 @@ static int keypad_release(struct inode *inode, struct file *file)
return 0;
}
-static struct file_operations keypad_fops = {
+static const struct file_operations keypad_fops = {
.read = keypad_read, /* read */
.open = keypad_open, /* open */
.release = keypad_release, /* close */
@@ -1591,14 +1654,15 @@ static void keypad_send_key(char *string, int max_len)
}
}
-/* this function scans all the bits involving at least one logical signal, and puts the
- * results in the bitfield "phys_read" (one bit per established contact), and sets
- * "phys_read_prev" to "phys_read".
+/* this function scans all the bits involving at least one logical signal,
+ * and puts the results in the bitfield "phys_read" (one bit per established
+ * contact), and sets "phys_read_prev" to "phys_read".
*
- * Note: to debounce input signals, we will only consider as switched a signal which is
- * stable across 2 measures. Signals which are different between two reads will be kept
- * as they previously were in their logical form (phys_prev). A signal which has just
- * switched will have a 1 in (phys_read ^ phys_read_prev).
+ * Note: to debounce input signals, we will only consider as switched a signal
+ * which is stable across 2 measures. Signals which are different between two
+ * reads will be kept as they previously were in their logical form (phys_prev).
+ * A signal which has just switched will have a 1 in
+ * (phys_read ^ phys_read_prev).
*/
static void phys_scan_contacts(void)
{
@@ -1611,21 +1675,30 @@ static void phys_scan_contacts(void)
phys_read_prev = phys_read;
phys_read = 0; /* flush all signals */
- oldval = r_dtr(pprt) | scan_mask_o; /* keep track of old value, with all outputs disabled */
- w_dtr(pprt, oldval & ~scan_mask_o); /* activate all keyboard outputs (active low) */
- bitmask = PNL_PINPUT(r_str(pprt)) & scan_mask_i; /* will have a 1 for each bit set to gnd */
- w_dtr(pprt, oldval); /* disable all matrix signals */
+ /* keep track of old value, with all outputs disabled */
+ oldval = r_dtr(pprt) | scan_mask_o;
+ /* activate all keyboard outputs (active low) */
+ w_dtr(pprt, oldval & ~scan_mask_o);
+
+ /* will have a 1 for each bit set to gnd */
+ bitmask = PNL_PINPUT(r_str(pprt)) & scan_mask_i;
+ /* disable all matrix signals */
+ w_dtr(pprt, oldval);
/* now that all outputs are cleared, the only active input bits are
* directly connected to the ground
*/
- gndmask = PNL_PINPUT(r_str(pprt)) & scan_mask_i; /* 1 for each grounded input */
- phys_read |= (pmask_t) gndmask << 40; /* grounded inputs are signals 40-44 */
+ /* 1 for each grounded input */
+ gndmask = PNL_PINPUT(r_str(pprt)) & scan_mask_i;
+
+ /* grounded inputs are signals 40-44 */
+ phys_read |= (pmask_t) gndmask << 40;
if (bitmask != gndmask) {
- /* since clearing the outputs changed some inputs, we know that some
- * input signals are currently tied to some outputs. So we'll scan them.
+ /* since clearing the outputs changed some inputs, we know
+ * that some input signals are currently tied to some outputs.
+ * So we'll scan them.
*/
for (bit = 0; bit < 8; bit++) {
bitval = 1 << bit;
@@ -1639,11 +1712,127 @@ static void phys_scan_contacts(void)
}
w_dtr(pprt, oldval); /* disable all outputs */
}
- /* this is easy: use old bits when they are flapping, use new ones when stable */
- phys_curr =
- (phys_prev & (phys_read ^ phys_read_prev)) | (phys_read &
- ~(phys_read ^
- phys_read_prev));
+ /* this is easy: use old bits when they are flapping,
+ * use new ones when stable */
+ phys_curr = (phys_prev & (phys_read ^ phys_read_prev)) |
+ (phys_read & ~(phys_read ^ phys_read_prev));
+}
+
+static inline int input_state_high(struct logical_input *input)
+{
+#if 0
+ /* FIXME:
+ * this is an invalid test. It tries to catch
+ * transitions from single-key to multiple-key, but
+ * doesn't take into account the contacts polarity.
+ * The only solution to the problem is to parse keys
+ * from the most complex to the simplest combinations,
+ * and mark them as 'caught' once a combination
+ * matches, then unmatch it for all other ones.
+ */
+
+ /* try to catch dangerous transitions cases :
+ * someone adds a bit, so this signal was a false
+ * positive resulting from a transition. We should
+ * invalidate the signal immediately and not call the
+ * release function.
+ * eg: 0 -(press A)-> A -(press B)-> AB : don't match A's release.
+ */
+ if (((phys_prev & input->mask) == input->value)
+ && ((phys_curr & input->mask) > input->value)) {
+ input->state = INPUT_ST_LOW; /* invalidate */
+ return 1;
+ }
+#endif
+
+ if ((phys_curr & input->mask) == input->value) {
+ if ((input->type == INPUT_TYPE_STD) &&
+ (input->high_timer == 0)) {
+ input->high_timer++;
+ if (input->u.std.press_fct != NULL)
+ input->u.std.press_fct(input->u.std.press_data);
+ } else if (input->type == INPUT_TYPE_KBD) {
+ /* will turn on the light */
+ keypressed = 1;
+
+ if (input->high_timer == 0) {
+ char *press_str = input->u.kbd.press_str;
+ if (press_str[0])
+ keypad_send_key(press_str,
+ sizeof(press_str));
+ }
+
+ if (input->u.kbd.repeat_str[0]) {
+ char *repeat_str = input->u.kbd.repeat_str;
+ if (input->high_timer >= KEYPAD_REP_START) {
+ input->high_timer -= KEYPAD_REP_DELAY;
+ keypad_send_key(repeat_str,
+ sizeof(repeat_str));
+ }
+ /* we will need to come back here soon */
+ inputs_stable = 0;
+ }
+
+ if (input->high_timer < 255)
+ input->high_timer++;
+ }
+ return 1;
+ } else {
+ /* else signal falling down. Let's fall through. */
+ input->state = INPUT_ST_FALLING;
+ input->fall_timer = 0;
+ }
+ return 0;
+}
+
+static inline void input_state_falling(struct logical_input *input)
+{
+#if 0
+ /* FIXME !!! same comment as in input_state_high */
+ if (((phys_prev & input->mask) == input->value)
+ && ((phys_curr & input->mask) > input->value)) {
+ input->state = INPUT_ST_LOW; /* invalidate */
+ return;
+ }
+#endif
+
+ if ((phys_curr & input->mask) == input->value) {
+ if (input->type == INPUT_TYPE_KBD) {
+ /* will turn on the light */
+ keypressed = 1;
+
+ if (input->u.kbd.repeat_str[0]) {
+ char *repeat_str = input->u.kbd.repeat_str;
+ if (input->high_timer >= KEYPAD_REP_START)
+ input->high_timer -= KEYPAD_REP_DELAY;
+ keypad_send_key(repeat_str,
+ sizeof(repeat_str));
+ /* we will need to come back here soon */
+ inputs_stable = 0;
+ }
+
+ if (input->high_timer < 255)
+ input->high_timer++;
+ }
+ input->state = INPUT_ST_HIGH;
+ } else if (input->fall_timer >= input->fall_time) {
+ /* call release event */
+ if (input->type == INPUT_TYPE_STD) {
+ void (*release_fct)(int) = input->u.std.release_fct;
+ if (release_fct != NULL)
+ release_fct(input->u.std.release_data);
+ } else if (input->type == INPUT_TYPE_KBD) {
+ char *release_str = input->u.kbd.release_str;
+ if (release_str[0])
+ keypad_send_key(release_str,
+ sizeof(release_str));
+ }
+
+ input->state = INPUT_ST_LOW;
+ } else {
+ input->fall_timer++;
+ inputs_stable = 0;
+ }
}
static void panel_process_inputs(void)
@@ -1666,10 +1855,12 @@ static void panel_process_inputs(void)
case INPUT_ST_LOW:
if ((phys_curr & input->mask) != input->value)
break;
- /* if all needed ones were already set previously, this means that
- * this logical signal has been activated by the releasing of
- * another combined signal, so we don't want to match.
- * eg: AB -(release B)-> A -(release A)-> 0 : don't match A.
+ /* if all needed ones were already set previously,
+ * this means that this logical signal has been
+ * activated by the releasing of another combined
+ * signal, so we don't want to match.
+ * eg: AB -(release B)-> A -(release A)-> 0 :
+ * don't match A.
*/
if ((phys_prev & input->mask) == input->value)
break;
@@ -1690,122 +1881,11 @@ static void panel_process_inputs(void)
input->state = INPUT_ST_HIGH;
/* no break here, fall through */
case INPUT_ST_HIGH:
-#if 0
- /* FIXME:
- * this is an invalid test. It tries to catch transitions from single-key
- * to multiple-key, but doesn't take into account the contacts polarity.
- * The only solution to the problem is to parse keys from the most complex
- * to the simplest combinations, and mark them as 'caught' once a combination
- * matches, then unmatch it for all other ones.
- */
-
- /* try to catch dangerous transitions cases :
- * someone adds a bit, so this signal was a false
- * positive resulting from a transition. We should invalidate
- * the signal immediately and not call the release function.
- * eg: 0 -(press A)-> A -(press B)-> AB : don't match A's release.
- */
- if (((phys_prev & input->mask) == input->value)
- && ((phys_curr & input->mask) > input->value)) {
- input->state = INPUT_ST_LOW; /* invalidate */
- break;
- }
-#endif
-
- if ((phys_curr & input->mask) == input->value) {
- if ((input->type == INPUT_TYPE_STD)
- && (input->high_timer == 0)) {
- input->high_timer++;
- if (input->u.std.press_fct != NULL)
- input->u.std.press_fct(input->u.
- std.
- press_data);
- } else if (input->type == INPUT_TYPE_KBD) {
- keypressed = 1; /* will turn on the light */
-
- if (input->high_timer == 0) {
- if (input->u.kbd.press_str[0])
- keypad_send_key(input->
- u.kbd.
- press_str,
- sizeof
- (input->
- u.kbd.
- press_str));
- }
-
- if (input->u.kbd.repeat_str[0]) {
- if (input->high_timer >=
- KEYPAD_REP_START) {
- input->high_timer -=
- KEYPAD_REP_DELAY;
- keypad_send_key(input->
- u.kbd.
- repeat_str,
- sizeof
- (input->
- u.kbd.
- repeat_str));
- }
- inputs_stable = 0; /* we will need to come back here soon */
- }
-
- if (input->high_timer < 255)
- input->high_timer++;
- }
+ if (input_state_high(input))
break;
- } else {
- /* else signal falling down. Let's fall through. */
- input->state = INPUT_ST_FALLING;
- input->fall_timer = 0;
- }
/* no break here, fall through */
case INPUT_ST_FALLING:
-#if 0
- /* FIXME !!! same comment as above */
- if (((phys_prev & input->mask) == input->value)
- && ((phys_curr & input->mask) > input->value)) {
- input->state = INPUT_ST_LOW; /* invalidate */
- break;
- }
-#endif
-
- if ((phys_curr & input->mask) == input->value) {
- if (input->type == INPUT_TYPE_KBD) {
- keypressed = 1; /* will turn on the light */
-
- if (input->u.kbd.repeat_str[0]) {
- if (input->high_timer >= KEYPAD_REP_START)
- input->high_timer -= KEYPAD_REP_DELAY;
- keypad_send_key(input->u.kbd.repeat_str,
- sizeof(input->u.kbd.repeat_str));
- inputs_stable = 0; /* we will need to come back here soon */
- }
-
- if (input->high_timer < 255)
- input->high_timer++;
- }
- input->state = INPUT_ST_HIGH;
- break;
- } else if (input->fall_timer >= input->fall_time) {
- /* call release event */
- if (input->type == INPUT_TYPE_STD) {
- if (input->u.std.release_fct != NULL)
- input->u.std.release_fct(input->u.std.release_data);
-
- } else if (input->type == INPUT_TYPE_KBD) {
- if (input->u.kbd.release_str[0])
- keypad_send_key(input->u.kbd.release_str,
- sizeof(input->u.kbd.release_str));
- }
-
- input->state = INPUT_ST_LOW;
- break;
- } else {
- input->fall_timer++;
- inputs_stable = 0;
- break;
- }
+ input_state_falling(input);
}
}
}
@@ -1815,7 +1895,9 @@ static void panel_scan_timer(void)
if (keypad_enabled && keypad_initialized) {
if (spin_trylock(&pprt_lock)) {
phys_scan_contacts();
- spin_unlock(&pprt_lock); /* no need for the parport anymore */
+
+ /* no need for the parport anymore */
+ spin_unlock(&pprt_lock);
}
if (!inputs_stable || phys_curr != phys_prev)
@@ -1850,8 +1932,8 @@ static void init_scan_timer(void)
}
/* converts a name of the form "({BbAaPpSsEe}{01234567-})*" to a series of bits.
- * if <omask> or <imask> are non-null, they will be or'ed with the bits corresponding
- * to out and in bits respectively.
+ * if <omask> or <imask> are non-null, they will be or'ed with the bits
+ * corresponding to out and in bits respectively.
* returns 1 if ok, 0 if error (in which case, nothing is written).
*/
static int input_name2mask(char *name, pmask_t *mask, pmask_t *value,
@@ -1864,7 +1946,8 @@ static int input_name2mask(char *name, pmask_t *mask, pmask_t *value,
om = im = m = v = 0ULL;
while (*name) {
int in, out, bit, neg;
- for (in = 0; (in < sizeof(sigtab)) && (sigtab[in] != *name); in++)
+ for (in = 0; (in < sizeof(sigtab)) &&
+ (sigtab[in] != *name); in++)
;
if (in >= sizeof(sigtab))
return 0; /* input name not found */
@@ -1912,8 +1995,10 @@ static struct logical_input *panel_bind_key(char *name, char *press,
return NULL;
}
if (!input_name2mask(name, &key->mask, &key->value, &scan_mask_i,
- &scan_mask_o))
+ &scan_mask_o)) {
+ kfree(key);
return NULL;
+ }
key->type = INPUT_TYPE_KBD;
key->state = INPUT_ST_LOW;
@@ -1936,7 +2021,8 @@ static struct logical_input *panel_bind_key(char *name, char *press,
/* tries to bind a callback function to the signal name <name>. The function
* <press_fct> will be called with the <press_data> arg when the signal is
* activated, and so on for <release_fct>/<release_data>
- * Returns the pointer to the new signal if ok, NULL if the signal could not be bound.
+ * Returns the pointer to the new signal if ok, NULL if the signal could not
+ * be bound.
*/
static struct logical_input *panel_bind_callback(char *name,
void (*press_fct) (int),
@@ -2028,33 +2114,52 @@ static void panel_attach(struct parport *port)
if (pprt) {
printk(KERN_ERR
- "panel_attach(): port->number=%d parport=%d, already registered !\n",
+ "panel_attach(): port->number=%d parport=%d, "
+ "already registered !\n",
port->number, parport);
return;
}
- pprt = parport_register_device(port, "panel", NULL, NULL, /* pf, kf */
+ pprt = parport_register_device(port, "panel", NULL, NULL, /* pf, kf */
NULL,
/*PARPORT_DEV_EXCL */
0, (void *)&pprt);
+ if (pprt == NULL) {
+ pr_err("panel_attach(): port->number=%d parport=%d, "
+ "parport_register_device() failed\n",
+ port->number, parport);
+ return;
+ }
if (parport_claim(pprt)) {
printk(KERN_ERR
- "Panel: could not claim access to parport%d. Aborting.\n",
- parport);
- return;
+ "Panel: could not claim access to parport%d. "
+ "Aborting.\n", parport);
+ goto err_unreg_device;
}
- /* must init LCD first, just in case an IRQ from the keypad is generated at keypad init */
+ /* must init LCD first, just in case an IRQ from the keypad is
+ * generated at keypad init
+ */
if (lcd_enabled) {
lcd_init();
- misc_register(&lcd_dev);
+ if (misc_register(&lcd_dev))
+ goto err_unreg_device;
}
if (keypad_enabled) {
keypad_init();
- misc_register(&keypad_dev);
+ if (misc_register(&keypad_dev))
+ goto err_lcd_unreg;
}
+ return;
+
+err_lcd_unreg:
+ if (lcd_enabled)
+ misc_deregister(&lcd_dev);
+err_unreg_device:
+ parport_unregister_device(pprt);
+ pprt = NULL;
}
static void panel_detach(struct parport *port)
@@ -2064,7 +2169,8 @@ static void panel_detach(struct parport *port)
if (!pprt) {
printk(KERN_ERR
- "panel_detach(): port->number=%d parport=%d, nothing to unregister.\n",
+ "panel_detach(): port->number=%d parport=%d, "
+ "nothing to unregister.\n",
port->number, parport);
return;
}
@@ -2105,13 +2211,15 @@ int panel_init(void)
/* take care of an eventual profile */
switch (profile) {
- case PANEL_PROFILE_CUSTOM: /* custom profile */
+ case PANEL_PROFILE_CUSTOM:
+ /* custom profile */
if (keypad_type < 0)
keypad_type = DEFAULT_KEYPAD;
if (lcd_type < 0)
lcd_type = DEFAULT_LCD;
break;
- case PANEL_PROFILE_OLD: /* 8 bits, 2*16, old keypad */
+ case PANEL_PROFILE_OLD:
+ /* 8 bits, 2*16, old keypad */
if (keypad_type < 0)
keypad_type = KEYPAD_TYPE_OLD;
if (lcd_type < 0)
@@ -2121,25 +2229,29 @@ int panel_init(void)
if (lcd_hwidth < 0)
lcd_hwidth = 16;
break;
- case PANEL_PROFILE_NEW: /* serial, 2*16, new keypad */
+ case PANEL_PROFILE_NEW:
+ /* serial, 2*16, new keypad */
if (keypad_type < 0)
keypad_type = KEYPAD_TYPE_NEW;
if (lcd_type < 0)
lcd_type = LCD_TYPE_KS0074;
break;
- case PANEL_PROFILE_HANTRONIX: /* 8 bits, 2*16 hantronix-like, no keypad */
+ case PANEL_PROFILE_HANTRONIX:
+ /* 8 bits, 2*16 hantronix-like, no keypad */
if (keypad_type < 0)
keypad_type = KEYPAD_TYPE_NONE;
if (lcd_type < 0)
lcd_type = LCD_TYPE_HANTRONIX;
break;
- case PANEL_PROFILE_NEXCOM: /* generic 8 bits, 2*16, nexcom keypad, eg. Nexcom. */
+ case PANEL_PROFILE_NEXCOM:
+ /* generic 8 bits, 2*16, nexcom keypad, eg. Nexcom. */
if (keypad_type < 0)
keypad_type = KEYPAD_TYPE_NEXCOM;
if (lcd_type < 0)
lcd_type = LCD_TYPE_NEXCOM;
break;
- case PANEL_PROFILE_LARGE: /* 8 bits, 2*40, old keypad */
+ case PANEL_PROFILE_LARGE:
+ /* 8 bits, 2*40, old keypad */
if (keypad_type < 0)
keypad_type = KEYPAD_TYPE_OLD;
if (lcd_type < 0)
@@ -2179,6 +2291,7 @@ int panel_init(void)
if (pprt) {
parport_release(pprt);
parport_unregister_device(pprt);
+ pprt = NULL;
}
parport_unregister_driver(&panel_driver);
printk(KERN_ERR "Panel driver version " PANEL_VERSION
@@ -2195,7 +2308,8 @@ int panel_init(void)
else
printk(KERN_INFO "Panel driver version " PANEL_VERSION
" not yet registered\n");
- /* tells various subsystems about the fact that initialization is finished */
+ /* tells various subsystems about the fact that initialization
+ is finished */
init_in_progress = 0;
return 0;
}
@@ -2228,6 +2342,7 @@ static void __exit panel_cleanup_module(void)
/* TODO: free all input signals */
parport_release(pprt);
parport_unregister_device(pprt);
+ pprt = NULL;
}
parport_unregister_driver(&panel_driver);
}
diff --git a/drivers/staging/pohmelfs/inode.c b/drivers/staging/pohmelfs/inode.c
index 643b413d9f0..bc1c6051a6f 100644
--- a/drivers/staging/pohmelfs/inode.c
+++ b/drivers/staging/pohmelfs/inode.c
@@ -815,7 +815,7 @@ static int pohmelfs_readpages(struct file *file, struct address_space *mapping,
}
/*
- * Small addres space operations for POHMELFS.
+ * Small address space operations for POHMELFS.
*/
const struct address_space_operations pohmelfs_aops = {
.readpage = pohmelfs_readpage,
@@ -847,7 +847,7 @@ static void pohmelfs_destroy_inode(struct inode *inode)
}
/*
- * ->alloc_inode() callback. Allocates inode and initilizes private data.
+ * ->alloc_inode() callback. Allocates inode and initializes private data.
*/
static struct inode *pohmelfs_alloc_inode(struct super_block *sb)
{
@@ -1266,7 +1266,7 @@ static void pohmelfs_put_super(struct super_block *sb)
{
struct pohmelfs_sb *psb = POHMELFS_SB(sb);
struct pohmelfs_inode *pi;
- unsigned int count;
+ unsigned int count = 0;
unsigned int in_drop_list = 0;
struct inode *inode, *tmp;
diff --git a/drivers/staging/quatech_usb2/quatech_usb2.c b/drivers/staging/quatech_usb2/quatech_usb2.c
index ecd73135b31..9838ea279c5 100644
--- a/drivers/staging/quatech_usb2/quatech_usb2.c
+++ b/drivers/staging/quatech_usb2/quatech_usb2.c
@@ -258,8 +258,6 @@ static int qt2_box_get_register(struct usb_serial *serial,
static int qt2_box_set_register(struct usb_serial *serial,
unsigned short Uart_Number, unsigned short Register_Num,
unsigned short Value);
-static int qt2_box_flush(struct usb_serial *serial, unsigned char uart_number,
- unsigned short rcv_or_xmit);
static int qt2_boxsetuart(struct usb_serial *serial, unsigned short Uart_Number,
unsigned short default_divisor, unsigned char default_LCR);
static int qt2_boxsethw_flowctl(struct usb_serial *serial,
@@ -645,9 +643,6 @@ static void qt2_close(struct usb_serial_port *port)
/* get the device private data */
port_extra = qt2_get_port_private(port); /* port private data */
- /* we don't need to force flush though the hardware, so we skip using
- * qt2_box_flush() here */
-
/* we can now (and only now) stop reading data */
port_extra->close_pending = true;
dbg("%s(): port_extra->close_pending = true", __func__);
@@ -1841,24 +1836,6 @@ static int qt2_box_set_register(struct usb_serial *serial,
return result;
}
-
-/** @brief Request the Tx or Rx buffers on the USB side be flushed
- *
- * Tx flush: When all the currently buffered data has been sent, send an escape
- * sequence back up the data stream to us
- * Rx flush: add a flag in the data stream now so we know when it's made it's
- * way up to us.
- */
-static int qt2_box_flush(struct usb_serial *serial, unsigned char uart_number,
- unsigned short rcv_or_xmit)
-{
- int result;
- result = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
- QT2_FLUSH_DEVICE, 0x40, rcv_or_xmit, uart_number, NULL, 0,
- 300);
- return result;
-}
-
/** qt2_boxsetuart - Issue a SET_UART vendor-spcific request on the default
* control pipe. If successful sets baud rate divisor and LCR value.
*/
@@ -1873,6 +1850,7 @@ static int qt2_boxsetuart(struct usb_serial *serial, unsigned short Uart_Number,
QT2_GET_SET_UART, 0x40, default_divisor, UartNumandLCR,
NULL, 0, 300);
}
+
/** qt2_boxsethw_flowctl - Turn hardware (RTS/CTS) flow control on and off for
* a hardware UART.
*/
diff --git a/drivers/staging/quickstart/Kconfig b/drivers/staging/quickstart/Kconfig
new file mode 100644
index 00000000000..5bea4875d37
--- /dev/null
+++ b/drivers/staging/quickstart/Kconfig
@@ -0,0 +1,10 @@
+config ACPI_QUICKSTART
+ tristate "ACPI Quickstart key driver"
+ depends on ACPI && INPUT
+ help
+ Say Y here if you have a platform that supports the ACPI
+ quickstart key protocol.
+
+ To compile this driver as a module, choose M here: the module will be
+ called quickstart.
+
diff --git a/drivers/staging/quickstart/Makefile b/drivers/staging/quickstart/Makefile
new file mode 100644
index 00000000000..290e0e47679
--- /dev/null
+++ b/drivers/staging/quickstart/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_ACPI_QUICKSTART) += quickstart.o
diff --git a/drivers/staging/quickstart/quickstart.c b/drivers/staging/quickstart/quickstart.c
new file mode 100644
index 00000000000..66122479d52
--- /dev/null
+++ b/drivers/staging/quickstart/quickstart.c
@@ -0,0 +1,474 @@
+/*
+ * quickstart.c - ACPI Direct App Launch driver
+ *
+ *
+ * Copyright (C) 2007-2010 Angelo Arrifano <miknix@gmail.com>
+ *
+ * Information gathered from disassebled dsdt and from here:
+ * "http://download.microsoft.com/download/9/c/5/
+ * 9c5b2167-8017-4bae-9fde-d599bac8184a/DirAppLaunch_Vista.doc"
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * 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 QUICKSTART_VERSION "1.03"
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <acpi/acpi_drivers.h>
+#include <linux/platform_device.h>
+#include <linux/input.h>
+
+MODULE_AUTHOR("Angelo Arrifano");
+MODULE_DESCRIPTION("ACPI Direct App Launch driver");
+MODULE_LICENSE("GPL");
+
+#define QUICKSTART_ACPI_DEVICE_NAME "quickstart"
+#define QUICKSTART_ACPI_CLASS "quickstart"
+#define QUICKSTART_ACPI_HID "PNP0C32"
+
+#define QUICKSTART_PF_DRIVER_NAME "quickstart"
+#define QUICKSTART_PF_DEVICE_NAME "quickstart"
+#define QUICKSTART_PF_DEVATTR_NAME "pressed_button"
+
+#define QUICKSTART_MAX_BTN_NAME_LEN 16
+
+/* There will be two events:
+ * 0x02 - A hot button was pressed while device was off/sleeping.
+ * 0x80 - A hot button was pressed while device was up. */
+#define QUICKSTART_EVENT_WAKE 0x02
+#define QUICKSTART_EVENT_RUNTIME 0x80
+
+struct quickstart_btn {
+ char *name;
+ unsigned int id;
+ struct quickstart_btn *next;
+};
+
+static struct quickstart_driver_data {
+ struct quickstart_btn *btn_lst;
+ struct quickstart_btn *pressed;
+} quickstart_data;
+
+/* ACPI driver Structs */
+struct quickstart_acpi {
+ struct acpi_device *device;
+ struct quickstart_btn *btn;
+};
+static int quickstart_acpi_add(struct acpi_device *device);
+static int quickstart_acpi_remove(struct acpi_device *device, int type);
+static const struct acpi_device_id quickstart_device_ids[] = {
+ {QUICKSTART_ACPI_HID, 0},
+ {"", 0},
+};
+
+static struct acpi_driver quickstart_acpi_driver = {
+ .name = "quickstart",
+ .class = QUICKSTART_ACPI_CLASS,
+ .ids = quickstart_device_ids,
+ .ops = {
+ .add = quickstart_acpi_add,
+ .remove = quickstart_acpi_remove,
+ },
+};
+
+/* Input device structs */
+struct input_dev *quickstart_input;
+
+/* Platform driver structs */
+static ssize_t buttons_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf);
+static ssize_t pressed_button_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf);
+static ssize_t pressed_button_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t count);
+static DEVICE_ATTR(pressed_button, 0666, pressed_button_show,
+ pressed_button_store);
+static DEVICE_ATTR(buttons, 0444, buttons_show, NULL);
+static struct platform_device *pf_device;
+static struct platform_driver pf_driver = {
+ .driver = {
+ .name = QUICKSTART_PF_DRIVER_NAME,
+ .owner = THIS_MODULE,
+ }
+};
+
+/*
+ * Platform driver functions
+ */
+static ssize_t buttons_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ int count = 0;
+ struct quickstart_btn *ptr = quickstart_data.btn_lst;
+
+ if (!ptr)
+ return snprintf(buf, PAGE_SIZE, "none");
+
+ while (ptr && (count < PAGE_SIZE)) {
+ if (ptr->name) {
+ count += snprintf(buf + count,
+ PAGE_SIZE - count,
+ "%d\t%s\n", ptr->id, ptr->name);
+ }
+ ptr = ptr->next;
+ }
+
+ return count;
+}
+
+static ssize_t pressed_button_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "%s\n",
+ (quickstart_data.pressed?quickstart_data.pressed->name:"none"));
+}
+
+
+static ssize_t pressed_button_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ if (count < 2)
+ return -EINVAL;
+
+ if (strncasecmp(buf, "none", 4) != 0)
+ return -EINVAL;
+
+ quickstart_data.pressed = NULL;
+ return count;
+}
+
+/* Hotstart Helper functions */
+static int quickstart_btnlst_add(struct quickstart_btn **data)
+{
+ struct quickstart_btn **ptr = &quickstart_data.btn_lst;
+
+ while (*ptr)
+ ptr = &((*ptr)->next);
+
+ *ptr = kzalloc(sizeof(struct quickstart_btn), GFP_KERNEL);
+ if (!*ptr) {
+ *data = NULL;
+ return -ENOMEM;
+ }
+ *data = *ptr;
+
+ return 0;
+}
+
+static void quickstart_btnlst_del(struct quickstart_btn *data)
+{
+ struct quickstart_btn **ptr = &quickstart_data.btn_lst;
+
+ if (!data)
+ return;
+
+ while (*ptr) {
+ if (*ptr == data) {
+ *ptr = (*ptr)->next;
+ kfree(data);
+ return;
+ }
+ ptr = &((*ptr)->next);
+ }
+
+ return;
+}
+
+static void quickstart_btnlst_free(void)
+{
+ struct quickstart_btn *ptr = quickstart_data.btn_lst;
+ struct quickstart_btn *lptr = NULL;
+
+ while (ptr) {
+ lptr = ptr;
+ ptr = ptr->next;
+ kfree(lptr->name);
+ kfree(lptr);
+ }
+
+ return;
+}
+
+/* ACPI Driver functions */
+static void quickstart_acpi_notify(acpi_handle handle, u32 event, void *data)
+{
+ struct quickstart_acpi *quickstart = data;
+
+ if (!quickstart)
+ return;
+
+ if (event == QUICKSTART_EVENT_WAKE)
+ quickstart_data.pressed = quickstart->btn;
+ else if (event == QUICKSTART_EVENT_RUNTIME) {
+ input_report_key(quickstart_input, quickstart->btn->id, 1);
+ input_sync(quickstart_input);
+ input_report_key(quickstart_input, quickstart->btn->id, 0);
+ input_sync(quickstart_input);
+ }
+ return;
+}
+
+static void quickstart_acpi_ghid(struct quickstart_acpi *quickstart)
+{
+ acpi_status status;
+ struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
+ uint32_t usageid = 0;
+
+ if (!quickstart)
+ return;
+
+ /* This returns a buffer telling the button usage ID,
+ * and triggers pending notify events (The ones before booting). */
+ status = acpi_evaluate_object(quickstart->device->handle,
+ "GHID", NULL, &buffer);
+ if (ACPI_FAILURE(status) || !buffer.pointer) {
+ printk(KERN_ERR "quickstart: %s GHID method failed.\n",
+ quickstart->btn->name);
+ return;
+ }
+
+ if (buffer.length < 8)
+ return;
+
+ /* <<The GHID method can return a BYTE, WORD, or DWORD.
+ * The value must be encoded in little-endian byte
+ * order (least significant byte first).>> */
+ usageid = *((uint32_t *)(buffer.pointer + (buffer.length - 8)));
+ quickstart->btn->id = usageid;
+
+ kfree(buffer.pointer);
+}
+
+static int quickstart_acpi_config(struct quickstart_acpi *quickstart, char *bid)
+{
+ int len = strlen(bid);
+ int ret;
+
+ /* Add button to list */
+ ret = quickstart_btnlst_add(&quickstart->btn);
+ if (ret)
+ return ret;
+
+ quickstart->btn->name = kzalloc(len + 1, GFP_KERNEL);
+ if (!quickstart->btn->name) {
+ quickstart_btnlst_free();
+ return -ENOMEM;
+ }
+ strcpy(quickstart->btn->name, bid);
+
+ return 0;
+}
+
+static int quickstart_acpi_add(struct acpi_device *device)
+{
+ int ret = 0;
+ acpi_status status = AE_OK;
+ struct quickstart_acpi *quickstart = NULL;
+
+ if (!device)
+ return -EINVAL;
+
+ quickstart = kzalloc(sizeof(struct quickstart_acpi), GFP_KERNEL);
+ if (!quickstart)
+ return -ENOMEM;
+
+ quickstart->device = device;
+ strcpy(acpi_device_name(device), QUICKSTART_ACPI_DEVICE_NAME);
+ strcpy(acpi_device_class(device), QUICKSTART_ACPI_CLASS);
+ device->driver_data = quickstart;
+
+ /* Add button to list and initialize some stuff */
+ ret = quickstart_acpi_config(quickstart, acpi_device_bid(device));
+ if (ret)
+ goto fail_config;
+
+ status = acpi_install_notify_handler(device->handle,
+ ACPI_ALL_NOTIFY,
+ quickstart_acpi_notify,
+ quickstart);
+ if (ACPI_FAILURE(status)) {
+ printk(KERN_ERR "quickstart: Notify handler install error\n");
+ ret = -ENODEV;
+ goto fail_installnotify;
+ }
+
+ quickstart_acpi_ghid(quickstart);
+
+ return 0;
+
+fail_installnotify:
+ quickstart_btnlst_del(quickstart->btn);
+
+fail_config:
+
+ kfree(quickstart);
+
+ return ret;
+}
+
+static int quickstart_acpi_remove(struct acpi_device *device, int type)
+{
+ acpi_status status = 0;
+ struct quickstart_acpi *quickstart = NULL;
+
+ if (!device || !acpi_driver_data(device))
+ return -EINVAL;
+
+ quickstart = acpi_driver_data(device);
+
+ status = acpi_remove_notify_handler(device->handle,
+ ACPI_ALL_NOTIFY,
+ quickstart_acpi_notify);
+ if (ACPI_FAILURE(status))
+ printk(KERN_ERR "quickstart: Error removing notify handler\n");
+
+
+ kfree(quickstart);
+
+ return 0;
+}
+
+/* Module functions */
+
+static void quickstart_exit(void)
+{
+ input_unregister_device(quickstart_input);
+ input_free_device(quickstart_input);
+
+ device_remove_file(&pf_device->dev, &dev_attr_pressed_button);
+ device_remove_file(&pf_device->dev, &dev_attr_buttons);
+
+ platform_device_unregister(pf_device);
+
+ platform_driver_unregister(&pf_driver);
+
+ acpi_bus_unregister_driver(&quickstart_acpi_driver);
+
+ quickstart_btnlst_free();
+
+ return;
+}
+
+static int __init quickstart_init_input(void)
+{
+ struct quickstart_btn **ptr = &quickstart_data.btn_lst;
+ int count;
+
+ quickstart_input = input_allocate_device();
+
+ if (!quickstart_input)
+ return -ENOMEM;
+
+ quickstart_input->name = "Quickstart ACPI Buttons";
+ quickstart_input->id.bustype = BUS_HOST;
+
+ while (*ptr) {
+ count++;
+ set_bit(EV_KEY, quickstart_input->evbit);
+ set_bit((*ptr)->id, quickstart_input->keybit);
+ ptr = &((*ptr)->next);
+ }
+
+ return input_register_device(quickstart_input);
+}
+
+static int __init quickstart_init(void)
+{
+ int ret;
+ acpi_status status = 0;
+
+ /* ACPI Check */
+ if (acpi_disabled)
+ return -ENODEV;
+
+ /* ACPI driver register */
+ status = acpi_bus_register_driver(&quickstart_acpi_driver);
+ if (status < 0)
+ return -ENODEV;
+
+ /* If existing bus with no devices */
+ if (!quickstart_data.btn_lst) {
+ ret = -ENODEV;
+ goto fail_pfdrv_reg;
+ }
+
+ /* Platform driver register */
+ ret = platform_driver_register(&pf_driver);
+ if (ret)
+ goto fail_pfdrv_reg;
+
+ /* Platform device register */
+ pf_device = platform_device_alloc(QUICKSTART_PF_DEVICE_NAME, -1);
+ if (!pf_device) {
+ ret = -ENOMEM;
+ goto fail_pfdev_alloc;
+ }
+ ret = platform_device_add(pf_device);
+ if (ret)
+ goto fail_pfdev_add;
+
+ /* Create device sysfs file */
+ ret = device_create_file(&pf_device->dev, &dev_attr_pressed_button);
+ if (ret)
+ goto fail_dev_file;
+
+ ret = device_create_file(&pf_device->dev, &dev_attr_buttons);
+ if (ret)
+ goto fail_dev_file2;
+
+
+ /* Input device */
+ ret = quickstart_init_input();
+ if (ret)
+ goto fail_input;
+
+ printk(KERN_INFO "quickstart: ACPI Direct App Launch ver %s\n",
+ QUICKSTART_VERSION);
+
+ return 0;
+fail_input:
+ device_remove_file(&pf_device->dev, &dev_attr_buttons);
+
+fail_dev_file2:
+ device_remove_file(&pf_device->dev, &dev_attr_pressed_button);
+
+fail_dev_file:
+ platform_device_del(pf_device);
+
+fail_pfdev_add:
+ platform_device_put(pf_device);
+
+fail_pfdev_alloc:
+ platform_driver_unregister(&pf_driver);
+
+fail_pfdrv_reg:
+ acpi_bus_unregister_driver(&quickstart_acpi_driver);
+
+ return ret;
+}
+
+module_init(quickstart_init);
+module_exit(quickstart_exit);
diff --git a/drivers/staging/ramzswap/Kconfig b/drivers/staging/ramzswap/Kconfig
deleted file mode 100644
index 127b3c6c959..00000000000
--- a/drivers/staging/ramzswap/Kconfig
+++ /dev/null
@@ -1,21 +0,0 @@
-config RAMZSWAP
- tristate "Compressed in-memory swap device (ramzswap)"
- depends on SWAP
- select LZO_COMPRESS
- select LZO_DECOMPRESS
- default n
- help
- Creates virtual block devices which can (only) be used as swap
- disks. Pages swapped to these disks are compressed and stored in
- memory itself.
-
- See ramzswap.txt for more information.
- Project home: http://compcache.googlecode.com/
-
-config RAMZSWAP_STATS
- bool "Enable ramzswap stats"
- depends on RAMZSWAP
- default y
- help
- Enable statistics collection for ramzswap. This adds only a minimal
- overhead. In unsure, say Y.
diff --git a/drivers/staging/ramzswap/Makefile b/drivers/staging/ramzswap/Makefile
deleted file mode 100644
index 507d7dc3b86..00000000000
--- a/drivers/staging/ramzswap/Makefile
+++ /dev/null
@@ -1,3 +0,0 @@
-ramzswap-objs := ramzswap_drv.o xvmalloc.o
-
-obj-$(CONFIG_RAMZSWAP) += ramzswap.o
diff --git a/drivers/staging/ramzswap/ramzswap.txt b/drivers/staging/ramzswap/ramzswap.txt
deleted file mode 100644
index 9694acfeb43..00000000000
--- a/drivers/staging/ramzswap/ramzswap.txt
+++ /dev/null
@@ -1,51 +0,0 @@
-ramzswap: Compressed RAM based swap device
--------------------------------------------
-
-Project home: http://compcache.googlecode.com/
-
-* Introduction
-
-The ramzswap module creates RAM based block devices which can (only) be used as
-swap disks. Pages swapped to these devices are compressed and stored in memory
-itself. See project home for use cases, performance numbers and a lot more.
-
-Individual ramzswap devices are configured and initialized using rzscontrol
-userspace utility as shown in examples below. See rzscontrol man page for more
-details.
-
-* Usage
-
-Following shows a typical sequence of steps for using ramzswap.
-
-1) Load Modules:
- modprobe ramzswap num_devices=4
- This creates 4 (uninitialized) devices: /dev/ramzswap{0,1,2,3}
- (num_devices parameter is optional. Default: 1)
-
-2) Initialize:
- Use rzscontrol utility to configure and initialize individual
- ramzswap devices. Example:
- rzscontrol /dev/ramzswap2 --init # uses default value of disksize_kb
-
- *See rzscontrol man page for more details and examples*
-
-3) Activate:
- swapon /dev/ramzswap2 # or any other initialized ramzswap device
-
-4) Stats:
- rzscontrol /dev/ramzswap2 --stats
-
-5) Deactivate:
- swapoff /dev/ramzswap2
-
-6) Reset:
- rzscontrol /dev/ramzswap2 --reset
- (This frees all the memory allocated for this device).
-
-
-Please report any problems at:
- - Mailing list: linux-mm-cc at laptop dot org
- - Issue tracker: http://code.google.com/p/compcache/issues/list
-
-Nitin Gupta
-ngupta@vflare.org
diff --git a/drivers/staging/ramzswap/ramzswap_drv.c b/drivers/staging/ramzswap/ramzswap_drv.c
deleted file mode 100644
index d14bf9129e3..00000000000
--- a/drivers/staging/ramzswap/ramzswap_drv.c
+++ /dev/null
@@ -1,837 +0,0 @@
-/*
- * Compressed RAM based swap device
- *
- * Copyright (C) 2008, 2009, 2010 Nitin Gupta
- *
- * This code is released using a dual license strategy: BSD/GPL
- * You can choose the licence that better fits your requirements.
- *
- * Released under the terms of 3-clause BSD License
- * Released under the terms of GNU General Public License Version 2.0
- *
- * Project home: http://compcache.googlecode.com
- */
-
-#define KMSG_COMPONENT "ramzswap"
-#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/bitops.h>
-#include <linux/blkdev.h>
-#include <linux/buffer_head.h>
-#include <linux/device.h>
-#include <linux/genhd.h>
-#include <linux/highmem.h>
-#include <linux/slab.h>
-#include <linux/lzo.h>
-#include <linux/string.h>
-#include <linux/swap.h>
-#include <linux/swapops.h>
-#include <linux/vmalloc.h>
-
-#include "ramzswap_drv.h"
-
-/* Globals */
-static int ramzswap_major;
-static struct ramzswap *devices;
-
-/* Module params (documentation at end) */
-static unsigned int num_devices;
-
-static int rzs_test_flag(struct ramzswap *rzs, u32 index,
- enum rzs_pageflags flag)
-{
- return rzs->table[index].flags & BIT(flag);
-}
-
-static void rzs_set_flag(struct ramzswap *rzs, u32 index,
- enum rzs_pageflags flag)
-{
- rzs->table[index].flags |= BIT(flag);
-}
-
-static void rzs_clear_flag(struct ramzswap *rzs, u32 index,
- enum rzs_pageflags flag)
-{
- rzs->table[index].flags &= ~BIT(flag);
-}
-
-static int page_zero_filled(void *ptr)
-{
- unsigned int pos;
- unsigned long *page;
-
- page = (unsigned long *)ptr;
-
- for (pos = 0; pos != PAGE_SIZE / sizeof(*page); pos++) {
- if (page[pos])
- return 0;
- }
-
- return 1;
-}
-
-static void ramzswap_set_disksize(struct ramzswap *rzs, size_t totalram_bytes)
-{
- if (!rzs->disksize) {
- pr_info(
- "disk size not provided. You can use disksize_kb module "
- "param to specify size.\nUsing default: (%u%% of RAM).\n",
- default_disksize_perc_ram
- );
- rzs->disksize = default_disksize_perc_ram *
- (totalram_bytes / 100);
- }
-
- if (rzs->disksize > 2 * (totalram_bytes)) {
- pr_info(
- "There is little point creating a ramzswap of greater than "
- "twice the size of memory since we expect a 2:1 compression "
- "ratio. Note that ramzswap uses about 0.1%% of the size of "
- "the swap device when not in use so a huge ramzswap is "
- "wasteful.\n"
- "\tMemory Size: %zu kB\n"
- "\tSize you selected: %zu kB\n"
- "Continuing anyway ...\n",
- totalram_bytes >> 10, rzs->disksize
- );
- }
-
- rzs->disksize &= PAGE_MASK;
-}
-
-/*
- * Swap header (1st page of swap device) contains information
- * about a swap file/partition. Prepare such a header for the
- * given ramzswap device so that swapon can identify it as a
- * swap partition.
- */
-static void setup_swap_header(struct ramzswap *rzs, union swap_header *s)
-{
- s->info.version = 1;
- s->info.last_page = (rzs->disksize >> PAGE_SHIFT) - 1;
- s->info.nr_badpages = 0;
- memcpy(s->magic.magic, "SWAPSPACE2", 10);
-}
-
-static void ramzswap_ioctl_get_stats(struct ramzswap *rzs,
- struct ramzswap_ioctl_stats *s)
-{
- s->disksize = rzs->disksize;
-
-#if defined(CONFIG_RAMZSWAP_STATS)
- {
- struct ramzswap_stats *rs = &rzs->stats;
- size_t succ_writes, mem_used;
- unsigned int good_compress_perc = 0, no_compress_perc = 0;
-
- mem_used = xv_get_total_size_bytes(rzs->mem_pool)
- + (rs->pages_expand << PAGE_SHIFT);
- succ_writes = rzs_stat64_read(rzs, &rs->num_writes) -
- rzs_stat64_read(rzs, &rs->failed_writes);
-
- if (succ_writes && rs->pages_stored) {
- good_compress_perc = rs->good_compress * 100
- / rs->pages_stored;
- no_compress_perc = rs->pages_expand * 100
- / rs->pages_stored;
- }
-
- s->num_reads = rzs_stat64_read(rzs, &rs->num_reads);
- s->num_writes = rzs_stat64_read(rzs, &rs->num_writes);
- s->failed_reads = rzs_stat64_read(rzs, &rs->failed_reads);
- s->failed_writes = rzs_stat64_read(rzs, &rs->failed_writes);
- s->invalid_io = rzs_stat64_read(rzs, &rs->invalid_io);
- s->notify_free = rzs_stat64_read(rzs, &rs->notify_free);
- s->pages_zero = rs->pages_zero;
-
- s->good_compress_pct = good_compress_perc;
- s->pages_expand_pct = no_compress_perc;
-
- s->pages_stored = rs->pages_stored;
- s->pages_used = mem_used >> PAGE_SHIFT;
- s->orig_data_size = rs->pages_stored << PAGE_SHIFT;
- s->compr_data_size = rs->compr_size;
- s->mem_used_total = mem_used;
- }
-#endif /* CONFIG_RAMZSWAP_STATS */
-}
-
-static void ramzswap_free_page(struct ramzswap *rzs, size_t index)
-{
- u32 clen;
- void *obj;
-
- struct page *page = rzs->table[index].page;
- u32 offset = rzs->table[index].offset;
-
- if (unlikely(!page)) {
- /*
- * No memory is allocated for zero filled pages.
- * Simply clear zero page flag.
- */
- if (rzs_test_flag(rzs, index, RZS_ZERO)) {
- rzs_clear_flag(rzs, index, RZS_ZERO);
- rzs_stat_dec(&rzs->stats.pages_zero);
- }
- return;
- }
-
- if (unlikely(rzs_test_flag(rzs, index, RZS_UNCOMPRESSED))) {
- clen = PAGE_SIZE;
- __free_page(page);
- rzs_clear_flag(rzs, index, RZS_UNCOMPRESSED);
- rzs_stat_dec(&rzs->stats.pages_expand);
- goto out;
- }
-
- obj = kmap_atomic(page, KM_USER0) + offset;
- clen = xv_get_object_size(obj) - sizeof(struct zobj_header);
- kunmap_atomic(obj, KM_USER0);
-
- xv_free(rzs->mem_pool, page, offset);
- if (clen <= PAGE_SIZE / 2)
- rzs_stat_dec(&rzs->stats.good_compress);
-
-out:
- rzs->stats.compr_size -= clen;
- rzs_stat_dec(&rzs->stats.pages_stored);
-
- rzs->table[index].page = NULL;
- rzs->table[index].offset = 0;
-}
-
-static int handle_zero_page(struct bio *bio)
-{
- void *user_mem;
- struct page *page = bio->bi_io_vec[0].bv_page;
-
- user_mem = kmap_atomic(page, KM_USER0);
- memset(user_mem, 0, PAGE_SIZE);
- kunmap_atomic(user_mem, KM_USER0);
-
- flush_dcache_page(page);
-
- set_bit(BIO_UPTODATE, &bio->bi_flags);
- bio_endio(bio, 0);
- return 0;
-}
-
-static int handle_uncompressed_page(struct ramzswap *rzs, struct bio *bio)
-{
- u32 index;
- struct page *page;
- unsigned char *user_mem, *cmem;
-
- page = bio->bi_io_vec[0].bv_page;
- index = bio->bi_sector >> SECTORS_PER_PAGE_SHIFT;
-
- user_mem = kmap_atomic(page, KM_USER0);
- cmem = kmap_atomic(rzs->table[index].page, KM_USER1) +
- rzs->table[index].offset;
-
- memcpy(user_mem, cmem, PAGE_SIZE);
- kunmap_atomic(user_mem, KM_USER0);
- kunmap_atomic(cmem, KM_USER1);
-
- flush_dcache_page(page);
-
- set_bit(BIO_UPTODATE, &bio->bi_flags);
- bio_endio(bio, 0);
- return 0;
-}
-
-/*
- * Called when request page is not present in ramzswap.
- * This is an attempt to read before any previous write
- * to this location - this happens due to readahead when
- * swap device is read from user-space (e.g. during swapon)
- */
-static int handle_ramzswap_fault(struct ramzswap *rzs, struct bio *bio)
-{
- pr_debug("Read before write on swap device: "
- "sector=%lu, size=%u, offset=%u\n",
- (ulong)(bio->bi_sector), bio->bi_size,
- bio->bi_io_vec[0].bv_offset);
-
- /* Do nothing. Just return success */
- set_bit(BIO_UPTODATE, &bio->bi_flags);
- bio_endio(bio, 0);
- return 0;
-}
-
-static int ramzswap_read(struct ramzswap *rzs, struct bio *bio)
-{
- int ret;
- u32 index;
- size_t clen;
- struct page *page;
- struct zobj_header *zheader;
- unsigned char *user_mem, *cmem;
-
- rzs_stat64_inc(rzs, &rzs->stats.num_reads);
-
- page = bio->bi_io_vec[0].bv_page;
- index = bio->bi_sector >> SECTORS_PER_PAGE_SHIFT;
-
- if (rzs_test_flag(rzs, index, RZS_ZERO))
- return handle_zero_page(bio);
-
- /* Requested page is not present in compressed area */
- if (!rzs->table[index].page)
- return handle_ramzswap_fault(rzs, bio);
-
- /* Page is stored uncompressed since it's incompressible */
- if (unlikely(rzs_test_flag(rzs, index, RZS_UNCOMPRESSED)))
- return handle_uncompressed_page(rzs, bio);
-
- user_mem = kmap_atomic(page, KM_USER0);
- clen = PAGE_SIZE;
-
- cmem = kmap_atomic(rzs->table[index].page, KM_USER1) +
- rzs->table[index].offset;
-
- ret = lzo1x_decompress_safe(
- cmem + sizeof(*zheader),
- xv_get_object_size(cmem) - sizeof(*zheader),
- user_mem, &clen);
-
- kunmap_atomic(user_mem, KM_USER0);
- kunmap_atomic(cmem, KM_USER1);
-
- /* should NEVER happen */
- if (unlikely(ret != LZO_E_OK)) {
- pr_err("Decompression failed! err=%d, page=%u\n",
- ret, index);
- rzs_stat64_inc(rzs, &rzs->stats.failed_reads);
- goto out;
- }
-
- flush_dcache_page(page);
-
- set_bit(BIO_UPTODATE, &bio->bi_flags);
- bio_endio(bio, 0);
- return 0;
-
-out:
- bio_io_error(bio);
- return 0;
-}
-
-static int ramzswap_write(struct ramzswap *rzs, struct bio *bio)
-{
- int ret;
- u32 offset, index;
- size_t clen;
- struct zobj_header *zheader;
- struct page *page, *page_store;
- unsigned char *user_mem, *cmem, *src;
-
- rzs_stat64_inc(rzs, &rzs->stats.num_writes);
-
- page = bio->bi_io_vec[0].bv_page;
- index = bio->bi_sector >> SECTORS_PER_PAGE_SHIFT;
-
- src = rzs->compress_buffer;
-
- mutex_lock(&rzs->lock);
-
- user_mem = kmap_atomic(page, KM_USER0);
- if (page_zero_filled(user_mem)) {
- kunmap_atomic(user_mem, KM_USER0);
- mutex_unlock(&rzs->lock);
- rzs_stat_inc(&rzs->stats.pages_zero);
- rzs_set_flag(rzs, index, RZS_ZERO);
-
- set_bit(BIO_UPTODATE, &bio->bi_flags);
- bio_endio(bio, 0);
- return 0;
- }
-
- ret = lzo1x_1_compress(user_mem, PAGE_SIZE, src, &clen,
- rzs->compress_workmem);
-
- kunmap_atomic(user_mem, KM_USER0);
-
- if (unlikely(ret != LZO_E_OK)) {
- mutex_unlock(&rzs->lock);
- pr_err("Compression failed! err=%d\n", ret);
- rzs_stat64_inc(rzs, &rzs->stats.failed_writes);
- goto out;
- }
-
- /*
- * Page is incompressible. Store it as-is (uncompressed)
- * since we do not want to return too many swap write
- * errors which has side effect of hanging the system.
- */
- if (unlikely(clen > max_zpage_size)) {
- clen = PAGE_SIZE;
- page_store = alloc_page(GFP_NOIO | __GFP_HIGHMEM);
- if (unlikely(!page_store)) {
- mutex_unlock(&rzs->lock);
- pr_info("Error allocating memory for incompressible "
- "page: %u\n", index);
- rzs_stat64_inc(rzs, &rzs->stats.failed_writes);
- goto out;
- }
-
- offset = 0;
- rzs_set_flag(rzs, index, RZS_UNCOMPRESSED);
- rzs_stat_inc(&rzs->stats.pages_expand);
- rzs->table[index].page = page_store;
- src = kmap_atomic(page, KM_USER0);
- goto memstore;
- }
-
- if (xv_malloc(rzs->mem_pool, clen + sizeof(*zheader),
- &rzs->table[index].page, &offset,
- GFP_NOIO | __GFP_HIGHMEM)) {
- mutex_unlock(&rzs->lock);
- pr_info("Error allocating memory for compressed "
- "page: %u, size=%zu\n", index, clen);
- rzs_stat64_inc(rzs, &rzs->stats.failed_writes);
- goto out;
- }
-
-memstore:
- rzs->table[index].offset = offset;
-
- cmem = kmap_atomic(rzs->table[index].page, KM_USER1) +
- rzs->table[index].offset;
-
-#if 0
- /* Back-reference needed for memory defragmentation */
- if (!rzs_test_flag(rzs, index, RZS_UNCOMPRESSED)) {
- zheader = (struct zobj_header *)cmem;
- zheader->table_idx = index;
- cmem += sizeof(*zheader);
- }
-#endif
-
- memcpy(cmem, src, clen);
-
- kunmap_atomic(cmem, KM_USER1);
- if (unlikely(rzs_test_flag(rzs, index, RZS_UNCOMPRESSED)))
- kunmap_atomic(src, KM_USER0);
-
- /* Update stats */
- rzs->stats.compr_size += clen;
- rzs_stat_inc(&rzs->stats.pages_stored);
- if (clen <= PAGE_SIZE / 2)
- rzs_stat_inc(&rzs->stats.good_compress);
-
- mutex_unlock(&rzs->lock);
-
- set_bit(BIO_UPTODATE, &bio->bi_flags);
- bio_endio(bio, 0);
- return 0;
-
-out:
- bio_io_error(bio);
- return 0;
-}
-
-/*
- * Check if request is within bounds and page aligned.
- */
-static inline int valid_swap_request(struct ramzswap *rzs, struct bio *bio)
-{
- if (unlikely(
- (bio->bi_sector >= (rzs->disksize >> SECTOR_SHIFT)) ||
- (bio->bi_sector & (SECTORS_PER_PAGE - 1)) ||
- (bio->bi_vcnt != 1) ||
- (bio->bi_size != PAGE_SIZE) ||
- (bio->bi_io_vec[0].bv_offset != 0))) {
-
- return 0;
- }
-
- /* swap request is valid */
- return 1;
-}
-
-/*
- * Handler function for all ramzswap I/O requests.
- */
-static int ramzswap_make_request(struct request_queue *queue, struct bio *bio)
-{
- int ret = 0;
- struct ramzswap *rzs = queue->queuedata;
-
- if (unlikely(!rzs->init_done)) {
- bio_io_error(bio);
- return 0;
- }
-
- if (!valid_swap_request(rzs, bio)) {
- rzs_stat64_inc(rzs, &rzs->stats.invalid_io);
- bio_io_error(bio);
- return 0;
- }
-
- switch (bio_data_dir(bio)) {
- case READ:
- ret = ramzswap_read(rzs, bio);
- break;
-
- case WRITE:
- ret = ramzswap_write(rzs, bio);
- break;
- }
-
- return ret;
-}
-
-static void reset_device(struct ramzswap *rzs)
-{
- size_t index;
-
- /* Do not accept any new I/O request */
- rzs->init_done = 0;
-
- /* Free various per-device buffers */
- kfree(rzs->compress_workmem);
- free_pages((unsigned long)rzs->compress_buffer, 1);
-
- rzs->compress_workmem = NULL;
- rzs->compress_buffer = NULL;
-
- /* Free all pages that are still in this ramzswap device */
- for (index = 0; index < rzs->disksize >> PAGE_SHIFT; index++) {
- struct page *page;
- u16 offset;
-
- page = rzs->table[index].page;
- offset = rzs->table[index].offset;
-
- if (!page)
- continue;
-
- if (unlikely(rzs_test_flag(rzs, index, RZS_UNCOMPRESSED)))
- __free_page(page);
- else
- xv_free(rzs->mem_pool, page, offset);
- }
-
- vfree(rzs->table);
- rzs->table = NULL;
-
- xv_destroy_pool(rzs->mem_pool);
- rzs->mem_pool = NULL;
-
- /* Reset stats */
- memset(&rzs->stats, 0, sizeof(rzs->stats));
-
- rzs->disksize = 0;
-}
-
-static int ramzswap_ioctl_init_device(struct ramzswap *rzs)
-{
- int ret;
- size_t num_pages;
- struct page *page;
- union swap_header *swap_header;
-
- if (rzs->init_done) {
- pr_info("Device already initialized!\n");
- return -EBUSY;
- }
-
- ramzswap_set_disksize(rzs, totalram_pages << PAGE_SHIFT);
-
- rzs->compress_workmem = kzalloc(LZO1X_MEM_COMPRESS, GFP_KERNEL);
- if (!rzs->compress_workmem) {
- pr_err("Error allocating compressor working memory!\n");
- ret = -ENOMEM;
- goto fail;
- }
-
- rzs->compress_buffer = (void *)__get_free_pages(__GFP_ZERO, 1);
- if (!rzs->compress_buffer) {
- pr_err("Error allocating compressor buffer space\n");
- ret = -ENOMEM;
- goto fail;
- }
-
- num_pages = rzs->disksize >> PAGE_SHIFT;
- rzs->table = vmalloc(num_pages * sizeof(*rzs->table));
- if (!rzs->table) {
- pr_err("Error allocating ramzswap address table\n");
- /* To prevent accessing table entries during cleanup */
- rzs->disksize = 0;
- ret = -ENOMEM;
- goto fail;
- }
- memset(rzs->table, 0, num_pages * sizeof(*rzs->table));
-
- page = alloc_page(__GFP_ZERO);
- if (!page) {
- pr_err("Error allocating swap header page\n");
- ret = -ENOMEM;
- goto fail;
- }
- rzs->table[0].page = page;
- rzs_set_flag(rzs, 0, RZS_UNCOMPRESSED);
-
- swap_header = kmap(page);
- setup_swap_header(rzs, swap_header);
- kunmap(page);
-
- set_capacity(rzs->disk, rzs->disksize >> SECTOR_SHIFT);
-
- /* ramzswap devices sort of resembles non-rotational disks */
- queue_flag_set_unlocked(QUEUE_FLAG_NONROT, rzs->disk->queue);
-
- rzs->mem_pool = xv_create_pool();
- if (!rzs->mem_pool) {
- pr_err("Error creating memory pool\n");
- ret = -ENOMEM;
- goto fail;
- }
-
- rzs->init_done = 1;
-
- pr_debug("Initialization done!\n");
- return 0;
-
-fail:
- reset_device(rzs);
-
- pr_err("Initialization failed: err=%d\n", ret);
- return ret;
-}
-
-static int ramzswap_ioctl_reset_device(struct ramzswap *rzs)
-{
- if (rzs->init_done)
- reset_device(rzs);
-
- return 0;
-}
-
-static int ramzswap_ioctl(struct block_device *bdev, fmode_t mode,
- unsigned int cmd, unsigned long arg)
-{
- int ret = 0;
- size_t disksize_kb;
-
- struct ramzswap *rzs = bdev->bd_disk->private_data;
-
- switch (cmd) {
- case RZSIO_SET_DISKSIZE_KB:
- if (rzs->init_done) {
- ret = -EBUSY;
- goto out;
- }
- if (copy_from_user(&disksize_kb, (void *)arg,
- _IOC_SIZE(cmd))) {
- ret = -EFAULT;
- goto out;
- }
- rzs->disksize = disksize_kb << 10;
- pr_info("Disk size set to %zu kB\n", disksize_kb);
- break;
-
- case RZSIO_GET_STATS:
- {
- struct ramzswap_ioctl_stats *stats;
- if (!rzs->init_done) {
- ret = -ENOTTY;
- goto out;
- }
- stats = kzalloc(sizeof(*stats), GFP_KERNEL);
- if (!stats) {
- ret = -ENOMEM;
- goto out;
- }
- ramzswap_ioctl_get_stats(rzs, stats);
- if (copy_to_user((void *)arg, stats, sizeof(*stats))) {
- kfree(stats);
- ret = -EFAULT;
- goto out;
- }
- kfree(stats);
- break;
- }
- case RZSIO_INIT:
- ret = ramzswap_ioctl_init_device(rzs);
- break;
-
- case RZSIO_RESET:
- /* Do not reset an active device! */
- if (bdev->bd_holders) {
- ret = -EBUSY;
- goto out;
- }
-
- /* Make sure all pending I/O is finished */
- if (bdev)
- fsync_bdev(bdev);
-
- ret = ramzswap_ioctl_reset_device(rzs);
- break;
-
- default:
- pr_info("Invalid ioctl %u\n", cmd);
- ret = -ENOTTY;
- }
-
-out:
- return ret;
-}
-
-void ramzswap_slot_free_notify(struct block_device *bdev, unsigned long index)
-{
- struct ramzswap *rzs;
-
- rzs = bdev->bd_disk->private_data;
- ramzswap_free_page(rzs, index);
- rzs_stat64_inc(rzs, &rzs->stats.notify_free);
-
- return;
-}
-
-static struct block_device_operations ramzswap_devops = {
- .ioctl = ramzswap_ioctl,
- .swap_slot_free_notify = ramzswap_slot_free_notify,
- .owner = THIS_MODULE
-};
-
-static int create_device(struct ramzswap *rzs, int device_id)
-{
- int ret = 0;
-
- mutex_init(&rzs->lock);
- spin_lock_init(&rzs->stat64_lock);
-
- rzs->queue = blk_alloc_queue(GFP_KERNEL);
- if (!rzs->queue) {
- pr_err("Error allocating disk queue for device %d\n",
- device_id);
- ret = -ENOMEM;
- goto out;
- }
-
- blk_queue_make_request(rzs->queue, ramzswap_make_request);
- rzs->queue->queuedata = rzs;
-
- /* gendisk structure */
- rzs->disk = alloc_disk(1);
- if (!rzs->disk) {
- blk_cleanup_queue(rzs->queue);
- pr_warning("Error allocating disk structure for device %d\n",
- device_id);
- ret = -ENOMEM;
- goto out;
- }
-
- rzs->disk->major = ramzswap_major;
- rzs->disk->first_minor = device_id;
- rzs->disk->fops = &ramzswap_devops;
- rzs->disk->queue = rzs->queue;
- rzs->disk->private_data = rzs;
- snprintf(rzs->disk->disk_name, 16, "ramzswap%d", device_id);
-
- /* Actual capacity set using RZSIO_SET_DISKSIZE_KB ioctl */
- set_capacity(rzs->disk, 0);
-
- blk_queue_physical_block_size(rzs->disk->queue, PAGE_SIZE);
- blk_queue_logical_block_size(rzs->disk->queue, PAGE_SIZE);
-
- add_disk(rzs->disk);
-
- rzs->init_done = 0;
-
-out:
- return ret;
-}
-
-static void destroy_device(struct ramzswap *rzs)
-{
- if (rzs->disk) {
- del_gendisk(rzs->disk);
- put_disk(rzs->disk);
- }
-
- if (rzs->queue)
- blk_cleanup_queue(rzs->queue);
-}
-
-static int __init ramzswap_init(void)
-{
- int ret, dev_id;
-
- if (num_devices > max_num_devices) {
- pr_warning("Invalid value for num_devices: %u\n",
- num_devices);
- ret = -EINVAL;
- goto out;
- }
-
- ramzswap_major = register_blkdev(0, "ramzswap");
- if (ramzswap_major <= 0) {
- pr_warning("Unable to get major number\n");
- ret = -EBUSY;
- goto out;
- }
-
- if (!num_devices) {
- pr_info("num_devices not specified. Using default: 1\n");
- num_devices = 1;
- }
-
- /* Allocate the device array and initialize each one */
- pr_info("Creating %u devices ...\n", num_devices);
- devices = kzalloc(num_devices * sizeof(struct ramzswap), GFP_KERNEL);
- if (!devices) {
- ret = -ENOMEM;
- goto unregister;
- }
-
- for (dev_id = 0; dev_id < num_devices; dev_id++) {
- ret = create_device(&devices[dev_id], dev_id);
- if (ret)
- goto free_devices;
- }
-
- return 0;
-
-free_devices:
- while (dev_id)
- destroy_device(&devices[--dev_id]);
-unregister:
- unregister_blkdev(ramzswap_major, "ramzswap");
-out:
- return ret;
-}
-
-static void __exit ramzswap_exit(void)
-{
- int i;
- struct ramzswap *rzs;
-
- for (i = 0; i < num_devices; i++) {
- rzs = &devices[i];
-
- destroy_device(rzs);
- if (rzs->init_done)
- reset_device(rzs);
- }
-
- unregister_blkdev(ramzswap_major, "ramzswap");
-
- kfree(devices);
- pr_debug("Cleanup done!\n");
-}
-
-module_param(num_devices, uint, 0);
-MODULE_PARM_DESC(num_devices, "Number of ramzswap devices");
-
-module_init(ramzswap_init);
-module_exit(ramzswap_exit);
-
-MODULE_LICENSE("Dual BSD/GPL");
-MODULE_AUTHOR("Nitin Gupta <ngupta@vflare.org>");
-MODULE_DESCRIPTION("Compressed RAM Based Swap Device");
diff --git a/drivers/staging/rar_register/Kconfig b/drivers/staging/rar_register/Kconfig
deleted file mode 100644
index e9c27738199..00000000000
--- a/drivers/staging/rar_register/Kconfig
+++ /dev/null
@@ -1,30 +0,0 @@
-#
-# RAR device configuration
-#
-
-menu "RAR Register Driver"
-#
-# Restricted Access Register Manager
-#
-config RAR_REGISTER
- tristate "Restricted Access Region Register Driver"
- depends on PCI
- default n
- ---help---
- This driver allows other kernel drivers access to the
- contents of the restricted access region control registers.
-
- The restricted access region control registers
- (rar_registers) are used to pass address and
- locking information on restricted access regions
- to other drivers that use restricted access regions.
-
- The restricted access regions are regions of memory
- on the Intel MID Platform that are not accessible to
- the x86 processor, but are accessible to dedicated
- processors on board peripheral devices.
-
- The purpose of the restricted access regions is to
- protect sensitive data from compromise by unauthorized
- programs running on the x86 processor.
-endmenu
diff --git a/drivers/staging/rar_register/Makefile b/drivers/staging/rar_register/Makefile
deleted file mode 100644
index d5954ccc16c..00000000000
--- a/drivers/staging/rar_register/Makefile
+++ /dev/null
@@ -1,2 +0,0 @@
-EXTRA_CFLAGS += -DLITTLE__ENDIAN
-obj-$(CONFIG_RAR_REGISTER) += rar_register.o
diff --git a/drivers/staging/rt2860/ap.h b/drivers/staging/rt2860/ap.h
index 3f744a52aac..faac85d931d 100644
--- a/drivers/staging/rt2860/ap.h
+++ b/drivers/staging/rt2860/ap.h
@@ -42,7 +42,8 @@
/* ap_wpa.c */
void WpaStateMachineInit(struct rt_rtmp_adapter *pAd,
- struct rt_state_machine *Sm, OUT STATE_MACHINE_FUNC Trans[]);
+ struct rt_state_machine *Sm,
+ OUT STATE_MACHINE_FUNC Trans[]);
#ifdef RTMP_MAC_USB
void BeaconUpdateExec(void *SystemSpecific1,
@@ -61,6 +62,7 @@ struct rt_mac_table_entry *MacTableInsertEntry(struct rt_rtmp_adapter *pAd,
BOOLEAN MacTableDeleteEntry(struct rt_rtmp_adapter *pAd,
u16 wcid, u8 *pAddr);
-struct rt_mac_table_entry *MacTableLookup(struct rt_rtmp_adapter *pAd, u8 *pAddr);
+struct rt_mac_table_entry *MacTableLookup(struct rt_rtmp_adapter *pAd,
+ u8 *pAddr);
#endif /* __AP_H__ */
diff --git a/drivers/staging/rt2860/chlist.h b/drivers/staging/rt2860/chlist.h
index ada65e5ac61..1231e69d518 100644
--- a/drivers/staging/rt2860/chlist.h
+++ b/drivers/staging/rt2860/chlist.h
@@ -73,35 +73,31 @@ struct rt_ch_freq_map {
extern struct rt_ch_freq_map CH_HZ_ID_MAP[];
extern int CH_HZ_ID_MAP_NUM;
-#define MAP_CHANNEL_ID_TO_KHZ(_ch, _khz) \
- do{ \
- int _chIdx; \
- for (_chIdx = 0; _chIdx < CH_HZ_ID_MAP_NUM; _chIdx++)\
- { \
- if ((_ch) == CH_HZ_ID_MAP[_chIdx].channel) \
- { \
- (_khz) = CH_HZ_ID_MAP[_chIdx].freqKHz * 1000; \
- break; \
- } \
- } \
- if (_chIdx == CH_HZ_ID_MAP_NUM) \
- (_khz) = 2412000; \
- }while(0)
+#define MAP_CHANNEL_ID_TO_KHZ(_ch, _khz) \
+ do { \
+ int _chIdx; \
+ for (_chIdx = 0; _chIdx < CH_HZ_ID_MAP_NUM; _chIdx++) {\
+ if ((_ch) == CH_HZ_ID_MAP[_chIdx].channel) { \
+ (_khz) = CH_HZ_ID_MAP[_chIdx].freqKHz * 1000;\
+ break; \
+ } \
+ } \
+ if (_chIdx == CH_HZ_ID_MAP_NUM) \
+ (_khz) = 2412000; \
+ } while (0)
#define MAP_KHZ_TO_CHANNEL_ID(_khz, _ch) \
- do{ \
- int _chIdx; \
- for (_chIdx = 0; _chIdx < CH_HZ_ID_MAP_NUM; _chIdx++)\
- { \
- if ((_khz) == CH_HZ_ID_MAP[_chIdx].freqKHz) \
- { \
- (_ch) = CH_HZ_ID_MAP[_chIdx].channel; \
- break; \
- } \
- } \
- if (_chIdx == CH_HZ_ID_MAP_NUM) \
- (_ch) = 1; \
- }while(0)
+ do { \
+ int _chIdx; \
+ for (_chIdx = 0; _chIdx < CH_HZ_ID_MAP_NUM; _chIdx++) {\
+ if ((_khz) == CH_HZ_ID_MAP[_chIdx].freqKHz) {\
+ (_ch) = CH_HZ_ID_MAP[_chIdx].channel; \
+ break; \
+ } \
+ } \
+ if (_chIdx == CH_HZ_ID_MAP_NUM) \
+ (_ch) = 1; \
+ } while (0)
void BuildChannelListEx(struct rt_rtmp_adapter *pAd);
diff --git a/drivers/staging/rt2860/common/cmm_wpa.c b/drivers/staging/rt2860/common/cmm_wpa.c
index c16f3763cca..9414aa34437 100644
--- a/drivers/staging/rt2860/common/cmm_wpa.c
+++ b/drivers/staging/rt2860/common/cmm_wpa.c
@@ -427,7 +427,7 @@ void RTMPToWirelessSta(struct rt_rtmp_adapter *pAd,
/*
==========================================================================
Description:
- This is a function to initilize 4-way handshake
+ This is a function to initialize 4-way handshake
Return:
@@ -867,7 +867,7 @@ void PeerPairMsg3Action(struct rt_rtmp_adapter *pAd,
==========================================================================
Description:
When receiving the last packet of 4-way pairwisekey handshake.
- Initilize 2-way groupkey handshake following.
+ Initialize 2-way groupkey handshake following.
Return:
==========================================================================
*/
diff --git a/drivers/staging/rt2860/common/rtmp_timer.c b/drivers/staging/rt2860/common/rtmp_timer.c
index 42e47d9dc2c..ab520909490 100644
--- a/drivers/staging/rt2860/common/rtmp_timer.c
+++ b/drivers/staging/rt2860/common/rtmp_timer.c
@@ -143,8 +143,8 @@ int RtmpTimerQThread(IN void *Context)
struct rt_rtmp_os_task *pTask;
struct rt_rtmp_adapter *pAd;
- pTask = (struct rt_rtmp_os_task *)Context;
- pAd = (struct rt_rtmp_adapter *)pTask->priv;
+ pTask = Context;
+ pAd = pTask->priv;
RtmpOSTaskCustomize(pTask);
diff --git a/drivers/staging/rt2860/mlme.h b/drivers/staging/rt2860/mlme.h
index 99c9362bae8..01414c3b488 100644
--- a/drivers/staging/rt2860/mlme.h
+++ b/drivers/staging/rt2860/mlme.h
@@ -31,7 +31,7 @@
Revision History:
Who When What
- -------- ---------- ----------------------------------------------
+ -------- ---------- ------------------------------
John Chang 2003-08-28 Created
John Chang 2004-09-06 modified for RT2600
@@ -50,7 +50,7 @@
#define MLME_TASK_EXEC_INTV 100/*200*/ /* */
#define LEAD_TIME 5
#define MLME_TASK_EXEC_MULTIPLE 10 /*5*/ /* MLME_TASK_EXEC_MULTIPLE * MLME_TASK_EXEC_INTV = 1 sec */
-#define REORDER_EXEC_INTV 100 /* 0.1 sec */
+#define REORDER_EXEC_INTV 100 /* 0.1 sec */
/* The definition of Radar detection duration region */
#define CE 0
@@ -60,7 +60,7 @@
#define JAP_W56 4
#define MAX_RD_REGION 5
-#define BEACON_LOST_TIME 4 * OS_HZ /* 2048 msec = 2 sec */
+#define BEACON_LOST_TIME (4 * OS_HZ) /* 2048 msec = 2 sec */
#define DLS_TIMEOUT 1200 /* unit: msec */
#define AUTH_TIMEOUT 300 /* unit: msec */
@@ -119,8 +119,8 @@
#define MAC_ADDR_IS_GROUP(Addr) (((Addr[0]) & 0x01))
#define MAC_ADDR_HASH(Addr) (Addr[0] ^ Addr[1] ^ Addr[2] ^ Addr[3] ^ Addr[4] ^ Addr[5])
#define MAC_ADDR_HASH_INDEX(Addr) (MAC_ADDR_HASH(Addr) % HASH_TABLE_SIZE)
-#define TID_MAC_HASH(Addr,TID) (TID^Addr[0] ^ Addr[1] ^ Addr[2] ^ Addr[3] ^ Addr[4] ^ Addr[5])
-#define TID_MAC_HASH_INDEX(Addr,TID) (TID_MAC_HASH(Addr,TID) % HASH_TABLE_SIZE)
+#define TID_MAC_HASH(Addr, TID) (TID^Addr[0] ^ Addr[1] ^ Addr[2] ^ Addr[3] ^ Addr[4] ^ Addr[5])
+#define TID_MAC_HASH_INDEX(Addr, TID) (TID_MAC_HASH(Addr, TID) % HASH_TABLE_SIZE)
/* LED Control */
/* assoiation ON. one LED ON. another blinking when TX, OFF when idle */
@@ -145,7 +145,7 @@
#define CAP_IS_DSSS_OFDM(x) (((x) & 0x2000) != 0)
#define CAP_IS_DELAY_BA(x) (((x) & 0x4000) != 0) /* 802.11e d9 */
-#define CAP_GENERATE(ess,ibss,priv,s_pre,s_slot,spectrum) (((ess) ? 0x0001 : 0x0000) | ((ibss) ? 0x0002 : 0x0000) | ((priv) ? 0x0010 : 0x0000) | ((s_pre) ? 0x0020 : 0x0000) | ((s_slot) ? 0x0400 : 0x0000) | ((spectrum) ? 0x0100 : 0x0000))
+#define CAP_GENERATE(ess, ibss, priv, s_pre, s_slot, spectrum) (((ess) ? 0x0001 : 0x0000) | ((ibss) ? 0x0002 : 0x0000) | ((priv) ? 0x0010 : 0x0000) | ((s_pre) ? 0x0020 : 0x0000) | ((s_slot) ? 0x0400 : 0x0000) | ((spectrum) ? 0x0100 : 0x0000))
#define ERP_IS_NON_ERP_PRESENT(x) (((x) & 0x01) != 0) /* 802.11g */
#define ERP_IS_USE_PROTECTION(x) (((x) & 0x02) != 0) /* 802.11g */
@@ -154,9 +154,9 @@
#define DRS_TX_QUALITY_WORST_BOUND 8 /* 3 // just test by gary */
#define DRS_PENALTY 8
-#define BA_NOTUSE 2
+#define BA_NOTUSE 2
/*BA Policy subfiled value in ADDBA frame */
-#define IMMED_BA 1
+#define IMMED_BA 1
#define DELAY_BA 0
/* BA Initiator subfield in DELBA frame */
@@ -176,8 +176,7 @@
/* reset all OneSecTx counters */
#define RESET_ONE_SEC_TX_CNT(__pEntry) \
-if (((__pEntry)) != NULL) \
-{ \
+if (((__pEntry)) != NULL) { \
(__pEntry)->OneSecTxRetryOkCount = 0; \
(__pEntry)->OneSecTxFailCount = 0; \
(__pEntry)->OneSecTxNoRetryOkCount = 0; \
@@ -846,7 +845,7 @@ struct rt_mlme_queue {
struct rt_mlme_queue_elem Entry[MAX_LEN_OF_MLME_QUEUE];
};
-typedef void(*STATE_MACHINE_FUNC) (void * Adaptor, struct rt_mlme_queue_elem *Elem);
+typedef void(*STATE_MACHINE_FUNC) (void *Adaptor, struct rt_mlme_queue_elem *Elem);
struct rt_state_machine {
unsigned long Base;
diff --git a/drivers/staging/rt2860/rt_linux.c b/drivers/staging/rt2860/rt_linux.c
index 0029b2d73b7..6536965df3f 100644
--- a/drivers/staging/rt2860/rt_linux.c
+++ b/drivers/staging/rt2860/rt_linux.c
@@ -1015,7 +1015,7 @@ int RtmpOSTaskKill(struct rt_rtmp_os_task *pTask)
struct rt_rtmp_adapter *pAd;
int ret = NDIS_STATUS_FAILURE;
- pAd = (struct rt_rtmp_adapter *)pTask->priv;
+ pAd = pTask->priv;
#ifdef KTHREAD_SUPPORT
if (pTask->kthread_task) {
diff --git a/drivers/staging/rt2860/rtmp.h b/drivers/staging/rt2860/rtmp.h
index 82b6e783b33..282935caba2 100644
--- a/drivers/staging/rt2860/rtmp.h
+++ b/drivers/staging/rt2860/rtmp.h
@@ -2511,7 +2511,7 @@ void RTMPWriteTxWI(struct rt_rtmp_adapter *pAd, struct rt_txwi * pTxWI, IN BOOLE
u8 TID,
u8 TxRate,
u8 Txopmode,
- IN BOOLEAN CfAck, IN HTTRANSMIT_SETTING * pTransmit);
+ IN BOOLEAN CfAck, IN HTTRANSMIT_SETTING *pTransmit);
void RTMPWriteTxWI_Data(struct rt_rtmp_adapter *pAd,
struct rt_txwi *pTxWI, struct rt_tx_blk *pTxBlk);
@@ -3059,7 +3059,7 @@ BOOLEAN PeerBeaconAndProbeRspSanity(struct rt_rtmp_adapter *pAd,
u16 *pBeaconPeriod,
u8 *pChannel,
u8 *pNewChannel,
- OUT LARGE_INTEGER * pTimestamp,
+ OUT LARGE_INTEGER *pTimestamp,
struct rt_cf_parm *pCfParm,
u16 *pAtimWin,
u16 *pCapabilityInfo,
diff --git a/drivers/staging/rt2860/usb_main_dev.c b/drivers/staging/rt2860/usb_main_dev.c
index 674769d2b59..a0fe31de0a6 100644
--- a/drivers/staging/rt2860/usb_main_dev.c
+++ b/drivers/staging/rt2860/usb_main_dev.c
@@ -64,6 +64,7 @@ struct usb_device_id rtusb_usb_id[] = {
{USB_DEVICE(0x14B2, 0x3C07)}, /* AL */
{USB_DEVICE(0x050D, 0x8053)}, /* Belkin */
{USB_DEVICE(0x050D, 0x825B)}, /* Belkin */
+ {USB_DEVICE(0x050D, 0x935B)}, /* Belkin F6D4050 v2 */
{USB_DEVICE(0x14B2, 0x3C23)}, /* Airlink */
{USB_DEVICE(0x14B2, 0x3C27)}, /* Airlink */
{USB_DEVICE(0x07AA, 0x002F)}, /* Corega */
@@ -422,8 +423,8 @@ int MlmeThread(IN void *Context)
int status;
status = 0;
- pTask = (struct rt_rtmp_os_task *)Context;
- pAd = (struct rt_rtmp_adapter *)pTask->priv;
+ pTask = Context;
+ pAd = pTask->priv;
RtmpOSTaskCustomize(pTask);
@@ -491,8 +492,8 @@ int RTUSBCmdThread(IN void *Context)
int status;
status = 0;
- pTask = (struct rt_rtmp_os_task *)Context;
- pAd = (struct rt_rtmp_adapter *)pTask->priv;
+ pTask = Context;
+ pAd = pTask->priv;
RtmpOSTaskCustomize(pTask);
diff --git a/drivers/staging/rt3070/md4.h b/drivers/staging/rt3070/md4.h
deleted file mode 100644
index b3fb6372618..00000000000
--- a/drivers/staging/rt3070/md4.h
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- *************************************************************************
- * Ralink Tech Inc.
- * 5F., No.36, Taiyuan St., Jhubei City,
- * Hsinchu County 302,
- * Taiwan, R.O.C.
- *
- * (c) Copyright 2002-2007, Ralink Technology, 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., *
- * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
- * *
- *************************************************************************
- */
-
-#ifndef __MD4_H__
-#define __MD4_H__
-
-/* MD4 context. */
-typedef struct _MD4_CTX_ {
- unsigned long state[4]; /* state (ABCD) */
- unsigned long count[2]; /* number of bits, modulo 2^64 (lsb first) */
- u8 buffer[64]; /* input buffer */
-} MD4_CTX;
-
-void MD4Init(MD4_CTX *);
-void MD4Update(MD4_CTX *, u8 *, UINT);
-void MD4Final(u8 [16], MD4_CTX *);
-
-#endif /*__MD4_H__*/
diff --git a/drivers/staging/rtl8187se/Kconfig b/drivers/staging/rtl8187se/Kconfig
index 155a78e0740..1b3103fbf29 100644
--- a/drivers/staging/rtl8187se/Kconfig
+++ b/drivers/staging/rtl8187se/Kconfig
@@ -4,6 +4,7 @@ config R8187SE
select WIRELESS_EXT
select WEXT_PRIV
select EEPROM_93CX6
+ select CRYPTO
default N
---help---
If built as a module, it will be called r8187se.ko.
diff --git a/drivers/staging/rtl8192e/Kconfig b/drivers/staging/rtl8192e/Kconfig
index 2ae3745f775..2e64b239e24 100644
--- a/drivers/staging/rtl8192e/Kconfig
+++ b/drivers/staging/rtl8192e/Kconfig
@@ -3,5 +3,6 @@ config RTL8192E
depends on PCI && WLAN
select WIRELESS_EXT
select WEXT_PRIV
+ select CRYPTO
default N
---help---
diff --git a/drivers/staging/rtl8192e/ieee80211/dot11d.c b/drivers/staging/rtl8192e/ieee80211/dot11d.c
index 908f6051d57..6bbf0919cdf 100644
--- a/drivers/staging/rtl8192e/ieee80211/dot11d.c
+++ b/drivers/staging/rtl8192e/ieee80211/dot11d.c
@@ -218,22 +218,4 @@ int ToLegalChannel(
return default_chn;
}
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
-//EXPORT_SYMBOL(Dot11d_Init);
-//EXPORT_SYMBOL(Dot11d_Reset);
-//EXPORT_SYMBOL(Dot11d_UpdateCountryIe);
-//EXPORT_SYMBOL(DOT11D_GetMaxTxPwrInDbm);
-//EXPORT_SYMBOL(DOT11D_ScanComplete);
-//EXPORT_SYMBOL(IsLegalChannel);
-//EXPORT_SYMBOL(ToLegalChannel);
-#else
-EXPORT_SYMBOL_NOVERS(Dot11d_Init);
-EXPORT_SYMBOL_NOVERS(Dot11d_Reset);
-EXPORT_SYMBOL_NOVERS(Dot11d_UpdateCountryIe);
-EXPORT_SYMBOL_NOVERS(DOT11D_GetMaxTxPwrInDbm);
-EXPORT_SYMBOL_NOVERS(DOT11D_ScanComplete);
-EXPORT_SYMBOL_NOVERS(IsLegalChannel);
-EXPORT_SYMBOL_NOVERS(ToLegalChannel);
-#endif
-
#endif
diff --git a/drivers/staging/rtl8192e/ieee80211/ieee80211.h b/drivers/staging/rtl8192e/ieee80211/ieee80211.h
index 50728f6e9c5..dda6719234c 100644
--- a/drivers/staging/rtl8192e/ieee80211/ieee80211.h
+++ b/drivers/staging/rtl8192e/ieee80211/ieee80211.h
@@ -27,12 +27,7 @@
#include <linux/kernel.h> /* ARRAY_SIZE */
#include <linux/version.h>
#include <linux/module.h>
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
#include <linux/jiffies.h>
-#else
-#include <linux/jffs.h>
-#include <linux/tqueue.h>
-#endif
#include <linux/timer.h>
#include <linux/sched.h>
#include <linux/semaphore.h>
@@ -44,12 +39,6 @@
#include "rtl819x_BA.h"
#include "rtl819x_TS.h"
-#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20))
-#ifndef bool
-typedef enum{false = 0, true} bool;
-#endif
-#endif
-
#ifndef IW_MODE_MONITOR
#define IW_MODE_MONITOR 6
#endif
@@ -428,46 +417,9 @@ typedef struct ieee_param {
#define IW_QUAL_NOISE_UPDATED 0x4
#endif
-#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
-static inline void tq_init(struct tq_struct * task, void(*func)(void *), void *data)
-{
- task->routine = func;
- task->data = data;
- //task->next = NULL;
- INIT_LIST_HEAD(&task->list);
- task->sync = 0;
-}
-#endif
-
// linux under 2.6.9 release may not support it, so modify it for common use
-#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,9))
-//#define MSECS(t) (1000 * ((t) / HZ) + 1000 * ((t) % HZ) / HZ)
-#define MSECS(t) (HZ * ((t) / 1000) + (HZ * ((t) % 1000)) / 1000)
-static inline unsigned long msleep_interruptible_rsl(unsigned int msecs)
-{
- unsigned long timeout = MSECS(msecs) + 1;
-
- while (timeout) {
- set_current_state(TASK_INTERRUPTIBLE);
- timeout = schedule_timeout(timeout);
- }
- return timeout;
-}
-#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,31))
-static inline void msleep(unsigned int msecs)
-{
- unsigned long timeout = MSECS(msecs) + 1;
-
- while (timeout) {
- set_current_state(TASK_UNINTERRUPTIBLE);
- timeout = schedule_timeout(timeout);
- }
-}
-#endif
-#else
#define MSECS(t) msecs_to_jiffies(t)
#define msleep_interruptible_rsl msleep_interruptible
-#endif
#define IEEE80211_DATA_LEN 2304
/* Maximum size for the MA-UNITDATA primitive, 802.11 standard section
@@ -1747,21 +1699,6 @@ enum ieee80211_state {
#define IEEE80211_52GHZ_CHANNELS (IEEE80211_52GHZ_MAX_CHANNEL - \
IEEE80211_52GHZ_MIN_CHANNEL + 1)
-#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,11))
-extern inline int is_multicast_ether_addr(const u8 *addr)
-{
- return ((addr[0] != 0xff) && (0x01 & addr[0]));
-}
-#endif
-
-#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,13))
-extern inline int is_broadcast_ether_addr(const u8 *addr)
-{
- return ((addr[0] == 0xff) && (addr[1] == 0xff) && (addr[2] == 0xff) && \
- (addr[3] == 0xff) && (addr[4] == 0xff) && (addr[5] == 0xff));
-}
-#endif
-
typedef struct tx_pending_t{
int frag;
struct ieee80211_txb *txb;
@@ -1838,11 +1775,7 @@ typedef struct _RT_POWER_SAVE_CONTROL
bool bIPSModeBackup;
bool bSwRfProcessing;
RT_RF_POWER_STATE eInactivePowerState;
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)
struct work_struct InactivePsWorkItem;
-#else
- struct tq_struct InactivePsWorkItem;
-#endif
struct timer_list InactivePsTimer;
// Return point for join action
@@ -2329,36 +2262,16 @@ struct ieee80211_device {
/* used if IEEE_SOFTMAC_BEACONS is set */
struct timer_list beacon_timer;
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)
struct work_struct associate_complete_wq;
struct work_struct associate_procedure_wq;
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)
struct delayed_work softmac_scan_wq;
struct delayed_work associate_retry_wq;
struct delayed_work start_ibss_wq;
struct delayed_work hw_wakeup_wq;
struct delayed_work hw_sleep_wq;
-#else
- struct work_struct softmac_scan_wq;
- struct work_struct associate_retry_wq;
- struct work_struct start_ibss_wq;
- struct work_struct hw_wakeup_wq;
- struct work_struct hw_sleep_wq;
-#endif
+
struct work_struct wx_sync_scan_wq;
struct workqueue_struct *wq;
-#else
- /* used for periodly scan */
- struct timer_list scan_timer;
-
- struct tq_struct associate_complete_wq;
- struct tq_struct associate_retry_wq;
- struct tq_struct start_ibss_wq;
- struct tq_struct associate_procedure_wq;
- struct tq_struct softmac_scan_wq;
- struct tq_struct wx_sync_scan_wq;
-
-#endif
// Qos related. Added by Annie, 2005-11-01.
//STA_QOS StaQos;
@@ -2557,11 +2470,7 @@ struct ieee80211_device {
static inline void *ieee80211_priv(struct net_device *dev)
{
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)
return ((struct ieee80211_device *)netdev_priv(dev))->priv;
-#else
- return ((struct ieee80211_device *)dev->priv)->priv;
-#endif
}
extern inline int ieee80211_is_empty_essid(const char *essid, int essid_len)
@@ -2814,11 +2723,7 @@ extern int ieee80211_wx_get_freq(struct ieee80211_device *ieee, struct iw_reques
union iwreq_data *wrqu, char *b);
//extern void ieee80211_wx_sync_scan_wq(struct ieee80211_device *ieee);
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20))
extern void ieee80211_wx_sync_scan_wq(struct work_struct *work);
-#else
- extern void ieee80211_wx_sync_scan_wq(struct ieee80211_device *ieee);
-#endif
extern int ieee80211_wx_set_rawtx(struct ieee80211_device *ieee,
diff --git a/drivers/staging/rtl8192e/ieee80211/ieee80211_crypt.c b/drivers/staging/rtl8192e/ieee80211/ieee80211_crypt.c
index d5aa9af3d9f..ae503791890 100644
--- a/drivers/staging/rtl8192e/ieee80211/ieee80211_crypt.c
+++ b/drivers/staging/rtl8192e/ieee80211/ieee80211_crypt.c
@@ -243,23 +243,3 @@ void ieee80211_crypto_deinit(void)
kfree(hcrypt);
}
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
-//EXPORT_SYMBOL(ieee80211_crypt_deinit_entries);
-//EXPORT_SYMBOL(ieee80211_crypt_deinit_handler);
-//EXPORT_SYMBOL(ieee80211_crypt_delayed_deinit);
-
-//EXPORT_SYMBOL(ieee80211_register_crypto_ops);
-//EXPORT_SYMBOL(ieee80211_unregister_crypto_ops);
-//EXPORT_SYMBOL(ieee80211_get_crypto_ops);
-#else
-EXPORT_SYMBOL_NOVERS(ieee80211_crypt_deinit_entries);
-EXPORT_SYMBOL_NOVERS(ieee80211_crypt_deinit_handler);
-EXPORT_SYMBOL_NOVERS(ieee80211_crypt_delayed_deinit);
-
-EXPORT_SYMBOL_NOVERS(ieee80211_register_crypto_ops);
-EXPORT_SYMBOL_NOVERS(ieee80211_unregister_crypto_ops);
-EXPORT_SYMBOL_NOVERS(ieee80211_get_crypto_ops);
-#endif
-
-//module_init(ieee80211_crypto_init);
-//module_exit(ieee80211_crypto_deinit);
diff --git a/drivers/staging/rtl8192e/ieee80211/ieee80211_crypt.h b/drivers/staging/rtl8192e/ieee80211/ieee80211_crypt.h
index a84df4b7648..ca7dd0dda82 100644
--- a/drivers/staging/rtl8192e/ieee80211/ieee80211_crypt.h
+++ b/drivers/staging/rtl8192e/ieee80211/ieee80211_crypt.h
@@ -82,12 +82,4 @@ void ieee80211_crypt_deinit_entries(struct ieee80211_device *, int);
void ieee80211_crypt_deinit_handler(unsigned long);
void ieee80211_crypt_delayed_deinit(struct ieee80211_device *ieee,
struct ieee80211_crypt_data **crypt);
-#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
-#define offset_in_page(p) ((unsigned long)(p) & ~PAGE_MASK)
-#endif
-#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,31))
-#define crypto_alloc_tfm crypto_alloc_tfm_rsl
-#define crypto_free_tfm crypto_free_tfm_rsl
-#endif
-
#endif
diff --git a/drivers/staging/rtl8192e/ieee80211/ieee80211_crypt_ccmp.c b/drivers/staging/rtl8192e/ieee80211/ieee80211_crypt_ccmp.c
index 7165c4c75c7..a4e21cbcdf1 100644
--- a/drivers/staging/rtl8192e/ieee80211/ieee80211_crypt_ccmp.c
+++ b/drivers/staging/rtl8192e/ieee80211/ieee80211_crypt_ccmp.c
@@ -24,18 +24,9 @@
#include "ieee80211.h"
-#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
-#include "rtl_crypto.h"
-#else
#include <linux/crypto.h>
-#endif
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
- #include <asm/scatterlist.h>
-#else
#include <linux/scatterlist.h>
-#endif
-//#include <asm/scatterlist.h>
MODULE_AUTHOR("Jouni Malinen");
MODULE_DESCRIPTION("Host AP crypt: CCMP");
@@ -75,21 +66,7 @@ struct ieee80211_ccmp_data {
void ieee80211_ccmp_aes_encrypt(struct crypto_tfm *tfm,
const u8 pt[16], u8 ct[16])
{
-#if((LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21)) && (!OPENSUSE_SLED))
- struct scatterlist src, dst;
-
- src.page = virt_to_page(pt);
- src.offset = offset_in_page(pt);
- src.length = AES_BLOCK_LEN;
-
- dst.page = virt_to_page(ct);
- dst.offset = offset_in_page(ct);
- dst.length = AES_BLOCK_LEN;
-
- crypto_cipher_encrypt(tfm, &dst, &src, AES_BLOCK_LEN);
-#else
crypto_cipher_encrypt_one((void*)tfm, ct, pt);
-#endif
}
static void * ieee80211_ccmp_init(int key_idx)
@@ -101,14 +78,6 @@ static void * ieee80211_ccmp_init(int key_idx)
goto fail;
priv->key_idx = key_idx;
-#if((LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21)) && (!OPENSUSE_SLED))
- priv->tfm = crypto_alloc_tfm("aes", 0);
- if (priv->tfm == NULL) {
- printk(KERN_DEBUG "ieee80211_crypt_ccmp: could not allocate "
- "crypto API aes\n");
- goto fail;
- }
- #else
priv->tfm = (void*)crypto_alloc_cipher("aes", 0, CRYPTO_ALG_ASYNC);
if (IS_ERR(priv->tfm)) {
printk(KERN_DEBUG "ieee80211_crypt_ccmp: could not allocate "
@@ -116,17 +85,12 @@ static void * ieee80211_ccmp_init(int key_idx)
priv->tfm = NULL;
goto fail;
}
- #endif
return priv;
fail:
if (priv) {
if (priv->tfm)
- #if(LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21))
- crypto_free_tfm(priv->tfm);
- #else
crypto_free_cipher((void*)priv->tfm);
- #endif
kfree(priv);
}
@@ -138,11 +102,7 @@ static void ieee80211_ccmp_deinit(void *priv)
{
struct ieee80211_ccmp_data *_priv = priv;
if (_priv && _priv->tfm)
-#if(LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21))
- crypto_free_tfm(_priv->tfm);
-#else
crypto_free_cipher((void*)_priv->tfm);
-#endif
kfree(priv);
}
@@ -528,11 +488,3 @@ void ieee80211_crypto_ccmp_exit(void)
ieee80211_unregister_crypto_ops(&ieee80211_crypt_ccmp);
}
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
-//EXPORT_SYMBOL(ieee80211_ccmp_null);
-#else
-EXPORT_SYMBOL_NOVERS(ieee80211_ccmp_null);
-#endif
-
-//module_init(ieee80211_crypto_ccmp_init);
-//module_exit(ieee80211_crypto_ccmp_exit);
diff --git a/drivers/staging/rtl8192e/ieee80211/ieee80211_crypt_tkip.c b/drivers/staging/rtl8192e/ieee80211/ieee80211_crypt_tkip.c
index 65f48896bfa..14ca61087c0 100644
--- a/drivers/staging/rtl8192e/ieee80211/ieee80211_crypt_tkip.c
+++ b/drivers/staging/rtl8192e/ieee80211/ieee80211_crypt_tkip.c
@@ -24,17 +24,8 @@
#include "ieee80211.h"
-#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
-#include "rtl_crypto.h"
-#else
#include <linux/crypto.h>
-#endif
-//#include <asm/scatterlist.h>
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
- #include <asm/scatterlist.h>
-#else
- #include <linux/scatterlist.h>
-#endif
+#include <linux/scatterlist.h>
#include <linux/crc32.h>
@@ -68,17 +59,10 @@ struct ieee80211_tkip_data {
u32 dot11RSNAStatsTKIPLocalMICFailures;
int key_idx;
-#if((LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,21)) || (OPENSUSE_SLED))
struct crypto_blkcipher *rx_tfm_arc4;
struct crypto_hash *rx_tfm_michael;
struct crypto_blkcipher *tx_tfm_arc4;
struct crypto_hash *tx_tfm_michael;
-#else
- struct crypto_tfm *tx_tfm_arc4;
- struct crypto_tfm *tx_tfm_michael;
- struct crypto_tfm *rx_tfm_arc4;
- struct crypto_tfm *rx_tfm_michael;
-#endif
/* scratch buffers for virt_to_page() (crypto API) */
u8 rx_hdr[16], tx_hdr[16];
};
@@ -91,35 +75,6 @@ static void * ieee80211_tkip_init(int key_idx)
if (priv == NULL)
goto fail;
priv->key_idx = key_idx;
-#if((LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21)) && (!OPENSUSE_SLED))
- priv->tx_tfm_arc4 = crypto_alloc_tfm("arc4", 0);
- if (priv->tx_tfm_arc4 == NULL) {
- printk(KERN_DEBUG "ieee80211_crypt_tkip: could not allocate "
- "crypto API arc4\n");
- goto fail;
- }
-
- priv->tx_tfm_michael = crypto_alloc_tfm("michael_mic", 0);
- if (priv->tx_tfm_michael == NULL) {
- printk(KERN_DEBUG "ieee80211_crypt_tkip: could not allocate "
- "crypto API michael_mic\n");
- goto fail;
- }
-
- priv->rx_tfm_arc4 = crypto_alloc_tfm("arc4", 0);
- if (priv->rx_tfm_arc4 == NULL) {
- printk(KERN_DEBUG "ieee80211_crypt_tkip: could not allocate "
- "crypto API arc4\n");
- goto fail;
- }
-
- priv->rx_tfm_michael = crypto_alloc_tfm("michael_mic", 0);
- if (priv->rx_tfm_michael == NULL) {
- printk(KERN_DEBUG "ieee80211_crypt_tkip: could not allocate "
- "crypto API michael_mic\n");
- goto fail;
- }
-#else
priv->tx_tfm_arc4 = crypto_alloc_blkcipher("ecb(arc4)", 0,
CRYPTO_ALG_ASYNC);
if (IS_ERR(priv->tx_tfm_arc4)) {
@@ -155,22 +110,10 @@ static void * ieee80211_tkip_init(int key_idx)
priv->rx_tfm_michael = NULL;
goto fail;
}
-#endif
return priv;
fail:
if (priv) {
-#if((LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21)) && (!OPENSUSE_SLED))
- if (priv->tx_tfm_michael)
- crypto_free_tfm(priv->tx_tfm_michael);
- if (priv->tx_tfm_arc4)
- crypto_free_tfm(priv->tx_tfm_arc4);
- if (priv->rx_tfm_michael)
- crypto_free_tfm(priv->rx_tfm_michael);
- if (priv->rx_tfm_arc4)
- crypto_free_tfm(priv->rx_tfm_arc4);
-
-#else
if (priv->tx_tfm_michael)
crypto_free_hash(priv->tx_tfm_michael);
if (priv->tx_tfm_arc4)
@@ -179,7 +122,6 @@ fail:
crypto_free_hash(priv->rx_tfm_michael);
if (priv->rx_tfm_arc4)
crypto_free_blkcipher(priv->rx_tfm_arc4);
-#endif
kfree(priv);
}
@@ -190,16 +132,6 @@ fail:
static void ieee80211_tkip_deinit(void *priv)
{
struct ieee80211_tkip_data *_priv = priv;
-#if((LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21)) && (!OPENSUSE_SLED))
- if (_priv->tx_tfm_michael)
- crypto_free_tfm(_priv->tx_tfm_michael);
- if (_priv->tx_tfm_arc4)
- crypto_free_tfm(_priv->tx_tfm_arc4);
- if (_priv->rx_tfm_michael)
- crypto_free_tfm(_priv->rx_tfm_michael);
- if (_priv->rx_tfm_arc4)
- crypto_free_tfm(_priv->rx_tfm_arc4);
-#else
if (_priv) {
if (_priv->tx_tfm_michael)
crypto_free_hash(_priv->tx_tfm_michael);
@@ -210,7 +142,6 @@ static void ieee80211_tkip_deinit(void *priv)
if (_priv->rx_tfm_arc4)
crypto_free_blkcipher(_priv->rx_tfm_arc4);
}
-#endif
kfree(priv);
}
@@ -381,10 +312,8 @@ static int ieee80211_tkip_encrypt(struct sk_buff *skb, int hdr_len, void *priv)
struct ieee80211_hdr_4addr *hdr;
cb_desc *tcb_desc = (cb_desc *)(skb->cb + MAX_DEV_ADDR_SIZE);
- #if((LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,21)) || (OPENSUSE_SLED))
struct blkcipher_desc desc = {.tfm = tkey->tx_tfm_arc4};
int ret = 0;
- #endif
u8 rc4key[16], *icv;
u32 crc;
struct scatterlist sg;
@@ -447,32 +376,14 @@ printk("%x\n", ((u32*)tkey->key)[7]);
if (!tcb_desc->bHwSec)
{
icv = skb_put(skb, 4);
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
crc = ~crc32_le(~0, pos, len);
-#else
- crc = ~ether_crc_le(len, pos);
-#endif
icv[0] = crc;
icv[1] = crc >> 8;
icv[2] = crc >> 16;
icv[3] = crc >> 24;
-#if((LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21)) && (!OPENSUSE_SLED))
- crypto_cipher_setkey(tkey->tx_tfm_arc4, rc4key, 16);
- sg.page = virt_to_page(pos);
- sg.offset = offset_in_page(pos);
- sg.length = len + 4;
- crypto_cipher_encrypt(tkey->tx_tfm_arc4, &sg, &sg, len + 4);
-#else
crypto_blkcipher_setkey(tkey->tx_tfm_arc4, rc4key, 16);
-#if(LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24))
- sg.page = virt_to_page(pos);
- sg.offset = offset_in_page(pos);
- sg.length = len + 4;
-#else
sg_init_one(&sg, pos, len+4);
-#endif
ret= crypto_blkcipher_encrypt(&desc, &sg, &sg, len + 4);
-#endif
}
@@ -483,11 +394,7 @@ printk("%x\n", ((u32*)tkey->key)[7]);
}
if (!tcb_desc->bHwSec)
-#if((LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21)) && (!OPENSUSE_SLED))
- return 0;
- #else
return ret;
- #endif
else
return 0;
@@ -502,9 +409,7 @@ static int ieee80211_tkip_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
u16 iv16;
struct ieee80211_hdr_4addr *hdr;
cb_desc *tcb_desc = (cb_desc *)(skb->cb + MAX_DEV_ADDR_SIZE);
- #if((LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,21)) || (OPENSUSE_SLED))
struct blkcipher_desc desc = {.tfm = tkey->rx_tfm_arc4};
- #endif
u8 rc4key[16];
u8 icv[4];
u32 crc;
@@ -563,21 +468,8 @@ static int ieee80211_tkip_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
plen = skb->len - hdr_len - 12;
-#if((LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21)) && (!OPENSUSE_SLED))
- crypto_cipher_setkey(tkey->rx_tfm_arc4, rc4key, 16);
- sg.page = virt_to_page(pos);
- sg.offset = offset_in_page(pos);
- sg.length = plen + 4;
- crypto_cipher_decrypt(tkey->rx_tfm_arc4, &sg, &sg, plen + 4);
-#else
crypto_blkcipher_setkey(tkey->rx_tfm_arc4, rc4key, 16);
-#if(LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24))
- sg.page = virt_to_page(pos);
- sg.offset = offset_in_page(pos);
- sg.length = plen + 4;
-#else
sg_init_one(&sg, pos, plen+4);
-#endif
if (crypto_blkcipher_decrypt(&desc, &sg, &sg, plen + 4)) {
if (net_ratelimit()) {
printk(KERN_DEBUG ": TKIP: failed to decrypt "
@@ -586,13 +478,8 @@ static int ieee80211_tkip_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
}
return -7;
}
-#endif
- #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
crc = ~crc32_le(~0, pos, plen);
- #else
- crc = ~ether_crc_le(plen, pos);
- #endif
icv[0] = crc;
icv[1] = crc >> 8;
icv[2] = crc >> 16;
@@ -641,47 +528,6 @@ if( ((u16*)skb->data)[0] & 0x4000){
}
-#if((LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21)) && (!OPENSUSE_SLED))
-static int michael_mic(struct crypto_tfm * tfm_michael, u8 *key, u8 *hdr,
- u8 *data, size_t data_len, u8 *mic)
-{
- struct scatterlist sg[2];
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)
- struct hash_desc desc;
- int ret = 0;
-#endif
-
- if (tfm_michael == NULL){
- printk(KERN_WARNING "michael_mic: tfm_michael == NULL\n");
- return -1;
- }
- sg[0].page = virt_to_page(hdr);
- sg[0].offset = offset_in_page(hdr);
- sg[0].length = 16;
-
- sg[1].page = virt_to_page(data);
- sg[1].offset = offset_in_page(data);
- sg[1].length = data_len;
-
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
- crypto_digest_init(tfm_michael);
- crypto_digest_setkey(tfm_michael, key, 8);
- crypto_digest_update(tfm_michael, sg, 2);
- crypto_digest_final(tfm_michael, mic);
- return 0;
-#else
-if (crypto_hash_setkey(tkey->tfm_michael, key, 8))
- return -1;
-
-// return 0;
- desc.tfm = tkey->tfm_michael;
- desc.flags = 0;
- ret = crypto_hash_digest(&desc, sg, data_len + 16, mic);
- return ret;
-#endif
-}
-#else
static int michael_mic(struct crypto_hash *tfm_michael, u8 * key, u8 * hdr,
u8 * data, size_t data_len, u8 * mic)
{
@@ -692,19 +538,9 @@ static int michael_mic(struct crypto_hash *tfm_michael, u8 * key, u8 * hdr,
printk(KERN_WARNING "michael_mic: tfm_michael == NULL\n");
return -1;
}
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
- sg[0].page = virt_to_page(hdr);
- sg[0].offset = offset_in_page(hdr);
- sg[0].length = 16;
-
- sg[1].page = virt_to_page(data);
- sg[1].offset = offset_in_page(data);
- sg[1].length = data_len;
-#else
sg_init_table(sg, 2);
sg_set_buf(&sg[0], hdr, 16);
sg_set_buf(&sg[1], data, data_len);
-#endif
if (crypto_hash_setkey(tfm_michael, key, 8))
return -1;
@@ -713,7 +549,6 @@ static int michael_mic(struct crypto_hash *tfm_michael, u8 * key, u8 * hdr,
desc.flags = 0;
return crypto_hash_digest(&desc, sg, data_len + 16, mic);
}
-#endif
@@ -772,13 +607,8 @@ static int ieee80211_michael_mic_add(struct sk_buff *skb, int hdr_len, void *pri
}
// }
pos = skb_put(skb, 8);
-#if((LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21)) && (!OPENSUSE_SLED))
- if (michael_mic(tkey->tx_tfm_michael, &tkey->key[16], tkey->tx_hdr,
- skb->data + hdr_len, skb->len - 8 - hdr_len, pos))
-#else
if (michael_mic(tkey->tx_tfm_michael, &tkey->key[16], tkey->tx_hdr,
skb->data + hdr_len, skb->len - 8 - hdr_len, pos))
-#endif
return -1;
return 0;
@@ -850,13 +680,8 @@ static int ieee80211_michael_mic_verify(struct sk_buff *skb, int keyidx,
}
// }
-#if((LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21)) && (!OPENSUSE_SLED))
- if (michael_mic(tkey->rx_tfm_michael, &tkey->key[24], tkey->rx_hdr,
- skb->data + hdr_len, skb->len - 8 - hdr_len, mic))
-#else
if (michael_mic(tkey->rx_tfm_michael, &tkey->key[24], tkey->rx_hdr,
skb->data + hdr_len, skb->len - 8 - hdr_len, mic))
-#endif
return -1;
if (memcmp(mic, skb->data + skb->len - 8, 8) != 0) {
struct ieee80211_hdr_4addr *hdr;
@@ -886,32 +711,18 @@ static int ieee80211_tkip_set_key(void *key, int len, u8 *seq, void *priv)
{
struct ieee80211_tkip_data *tkey = priv;
int keyidx;
-#if((LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21)) && (!OPENSUSE_SLED))
- struct crypto_tfm *tfm = tkey->tx_tfm_michael;
- struct crypto_tfm *tfm2 = tkey->tx_tfm_arc4;
- struct crypto_tfm *tfm3 = tkey->rx_tfm_michael;
- struct crypto_tfm *tfm4 = tkey->rx_tfm_arc4;
-#else
struct crypto_hash *tfm = tkey->tx_tfm_michael;
struct crypto_blkcipher *tfm2 = tkey->tx_tfm_arc4;
struct crypto_hash *tfm3 = tkey->rx_tfm_michael;
struct crypto_blkcipher *tfm4 = tkey->rx_tfm_arc4;
-#endif
keyidx = tkey->key_idx;
memset(tkey, 0, sizeof(*tkey));
tkey->key_idx = keyidx;
-#if((LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21)) && (!OPENSUSE_SLED))
tkey->tx_tfm_michael = tfm;
tkey->tx_tfm_arc4 = tfm2;
tkey->rx_tfm_michael = tfm3;
tkey->rx_tfm_arc4 = tfm4;
-#else
- tkey->tx_tfm_michael = tfm;
- tkey->tx_tfm_arc4 = tfm2;
- tkey->rx_tfm_michael = tfm3;
- tkey->rx_tfm_arc4 = tfm4;
-#endif
if (len == TKIP_KEY_LEN) {
memcpy(tkey->key, key, TKIP_KEY_LEN);
@@ -1021,11 +832,4 @@ void ieee80211_tkip_null(void)
// printk("============>%s()\n", __FUNCTION__);
return;
}
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
-//EXPORT_SYMBOL(ieee80211_tkip_null);
-#else
-EXPORT_SYMBOL_NOVERS(ieee80211_tkip_null);
-#endif
-//module_init(ieee80211_crypto_tkip_init);
-//module_exit(ieee80211_crypto_tkip_exit);
diff --git a/drivers/staging/rtl8192e/ieee80211/ieee80211_crypt_wep.c b/drivers/staging/rtl8192e/ieee80211/ieee80211_crypt_wep.c
index c4bbc8ddbad..5dc976498aa 100644
--- a/drivers/staging/rtl8192e/ieee80211/ieee80211_crypt_wep.c
+++ b/drivers/staging/rtl8192e/ieee80211/ieee80211_crypt_wep.c
@@ -21,30 +21,11 @@
#include "ieee80211.h"
-#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
-#include "rtl_crypto.h"
-#else
#include <linux/crypto.h>
-#endif
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
- #include <asm/scatterlist.h>
-#else
- #include <linux/scatterlist.h>
-#endif
-//#include <asm/scatterlist.h>
+#include <linux/scatterlist.h>
#include <linux/crc32.h>
-//
-/*
-#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
-#include "rtl_crypto.h"
-#else
-#include <linux/crypto.h>
-#endif
-#include <asm/scatterlist.h>
-#include <linux/crc32.h>
-*/
MODULE_AUTHOR("Jouni Malinen");
MODULE_DESCRIPTION("Host AP crypt: WEP");
MODULE_LICENSE("GPL");
@@ -58,12 +39,8 @@ struct prism2_wep_data {
u8 key[WEP_KEY_LEN + 1];
u8 key_len;
u8 key_idx;
-#if((LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21)) && (!OPENSUSE_SLED))
- struct crypto_tfm *tfm;
- #else
struct crypto_blkcipher *tx_tfm;
struct crypto_blkcipher *rx_tfm;
- #endif
};
@@ -76,14 +53,6 @@ static void * prism2_wep_init(int keyidx)
goto fail;
priv->key_idx = keyidx;
-#if((LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21)) && (!OPENSUSE_SLED))
- priv->tfm = crypto_alloc_tfm("arc4", 0);
- if (priv->tfm == NULL) {
- printk(KERN_DEBUG "ieee80211_crypt_wep: could not allocate "
- "crypto API arc4\n");
- goto fail;
- }
- #else
priv->tx_tfm = crypto_alloc_blkcipher("ecb(arc4)", 0, CRYPTO_ALG_ASYNC);
if (IS_ERR(priv->tx_tfm)) {
printk(KERN_DEBUG "ieee80211_crypt_wep: could not allocate "
@@ -98,7 +67,6 @@ static void * prism2_wep_init(int keyidx)
priv->rx_tfm = NULL;
goto fail;
}
- #endif
/* start WEP IV from a random value */
get_random_bytes(&priv->iv, 4);
@@ -106,13 +74,6 @@ static void * prism2_wep_init(int keyidx)
return priv;
fail:
-#if((LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21)) && (!OPENSUSE_SLED))
- if (priv) {
- if (priv->tfm)
- crypto_free_tfm(priv->tfm);
- kfree(priv);
- }
- #else
if (priv) {
if (priv->tx_tfm)
crypto_free_blkcipher(priv->tx_tfm);
@@ -120,7 +81,6 @@ fail:
crypto_free_blkcipher(priv->rx_tfm);
kfree(priv);
}
- #endif
return NULL;
}
@@ -128,17 +88,12 @@ fail:
static void prism2_wep_deinit(void *priv)
{
struct prism2_wep_data *_priv = priv;
-#if((LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21)) && (!OPENSUSE_SLED))
- if (_priv && _priv->tfm)
- crypto_free_tfm(_priv->tfm);
- #else
if (_priv) {
if (_priv->tx_tfm)
crypto_free_blkcipher(_priv->tx_tfm);
if (_priv->rx_tfm)
crypto_free_blkcipher(_priv->rx_tfm);
}
- #endif
kfree(priv);
}
@@ -155,9 +110,7 @@ static int prism2_wep_encrypt(struct sk_buff *skb, int hdr_len, void *priv)
u8 key[WEP_KEY_LEN + 3];
u8 *pos;
cb_desc *tcb_desc = (cb_desc *)(skb->cb + MAX_DEV_ADDR_SIZE);
- #if((LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,21)) || (OPENSUSE_SLED))
struct blkcipher_desc desc = {.tfm = wep->tx_tfm};
- #endif
u32 crc;
u8 *icv;
struct scatterlist sg;
@@ -196,35 +149,16 @@ static int prism2_wep_encrypt(struct sk_buff *skb, int hdr_len, void *priv)
{
/* Append little-endian CRC32 and encrypt it to produce ICV */
- #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
crc = ~crc32_le(~0, pos, len);
- #else
- crc = ~ether_crc_le(len, pos);
- #endif
icv = skb_put(skb, 4);
icv[0] = crc;
icv[1] = crc >> 8;
icv[2] = crc >> 16;
icv[3] = crc >> 24;
-#if((LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21)) && (!OPENSUSE_SLED))
- crypto_cipher_setkey(wep->tfm, key, klen);
- sg.page = virt_to_page(pos);
- sg.offset = offset_in_page(pos);
- sg.length = len + 4;
- crypto_cipher_encrypt(wep->tfm, &sg, &sg, len + 4);
- return 0;
- #else
crypto_blkcipher_setkey(wep->tx_tfm, key, klen);
- #if(LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24))
- sg.page = virt_to_page(pos);
- sg.offset = offset_in_page(pos);
- sg.length = len + 4;
- #else
sg_init_one(&sg, pos, len+4);
- #endif
return crypto_blkcipher_encrypt(&desc, &sg, &sg, len + 4);
- #endif
}
return 0;
@@ -245,9 +179,7 @@ static int prism2_wep_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
u8 key[WEP_KEY_LEN + 3];
u8 keyidx, *pos;
cb_desc *tcb_desc = (cb_desc *)(skb->cb + MAX_DEV_ADDR_SIZE);
- #if((LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,21)) || (OPENSUSE_SLED))
struct blkcipher_desc desc = {.tfm = wep->rx_tfm};
- #endif
u32 crc;
u8 icv[4];
struct scatterlist sg;
@@ -272,29 +204,11 @@ static int prism2_wep_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
if (!tcb_desc->bHwSec)
{
-#if((LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21)) && (!OPENSUSE_SLED))
- crypto_cipher_setkey(wep->tfm, key, klen);
- sg.page = virt_to_page(pos);
- sg.offset = offset_in_page(pos);
- sg.length = plen + 4;
- crypto_cipher_decrypt(wep->tfm, &sg, &sg, plen + 4);
- #else
crypto_blkcipher_setkey(wep->rx_tfm, key, klen);
- #if(LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24))
- sg.page = virt_to_page(pos);
- sg.offset = offset_in_page(pos);
- sg.length = plen + 4;
- #else
sg_init_one(&sg, pos, plen+4);
- #endif
if (crypto_blkcipher_decrypt(&desc, &sg, &sg, plen + 4))
return -7;
- #endif
- #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
crc = ~crc32_le(~0, pos, plen);
- #else
- crc = ~ether_crc_le(plen, pos);
- #endif
icv[0] = crc;
icv[1] = crc >> 8;
icv[2] = crc >> 16;
@@ -379,14 +293,6 @@ void __exit ieee80211_crypto_wep_exit(void)
void ieee80211_wep_null(void)
{
-// printk("============>%s()\n", __FUNCTION__);
return;
}
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
-//EXPORT_SYMBOL(ieee80211_wep_null);
-#else
-EXPORT_SYMBOL_NOVERS(ieee80211_wep_null);
-#endif
-//module_init(ieee80211_crypto_wep_init);
-//module_exit(ieee80211_crypto_wep_exit);
diff --git a/drivers/staging/rtl8192e/ieee80211/ieee80211_module.c b/drivers/staging/rtl8192e/ieee80211/ieee80211_module.c
index 614a8b630e6..7edf5c897a6 100644
--- a/drivers/staging/rtl8192e/ieee80211/ieee80211_module.c
+++ b/drivers/staging/rtl8192e/ieee80211/ieee80211_module.c
@@ -31,7 +31,6 @@
*******************************************************************************/
#include <linux/compiler.h>
-//#include <linux/config.h>
#include <linux/errno.h>
#include <linux/if_arp.h>
#include <linux/in6.h>
@@ -110,14 +109,7 @@ struct net_device *alloc_ieee80211(int sizeof_priv)
goto failed;
}
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0))
ieee = netdev_priv(dev);
-#else
- ieee = (struct ieee80211_device *)dev->priv;
-#endif
-#if 0
- dev->hard_start_xmit = ieee80211_rtl_xmit;
-#endif
memset(ieee, 0, sizeof(struct ieee80211_device)+sizeof_priv);
ieee->dev = dev;
@@ -166,12 +158,7 @@ struct net_device *alloc_ieee80211(int sizeof_priv)
ieee80211_softmac_init(ieee);
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,13))
ieee->pHTInfo = kzalloc(sizeof(RT_HIGH_THROUGHPUT), GFP_KERNEL);
-#else
- ieee->pHTInfo = (RT_HIGH_THROUGHPUT*)kmalloc(sizeof(RT_HIGH_THROUGHPUT), GFP_KERNEL);
- memset(ieee->pHTInfo,0,sizeof(RT_HIGH_THROUGHPUT));
-#endif
if (ieee->pHTInfo == NULL)
{
IEEE80211_DEBUG(IEEE80211_DL_ERR, "can't alloc memory for HTInfo\n");
@@ -180,13 +167,6 @@ struct net_device *alloc_ieee80211(int sizeof_priv)
HTUpdateDefaultSetting(ieee);
HTInitializeHTInfo(ieee); //may move to other place.
TSInitialize(ieee);
-#if 0
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20))
- INIT_WORK(&ieee->ht_onAssRsp, (void(*)(void*)) HTOnAssocRsp_wq);
-#else
- INIT_WORK(&ieee->ht_onAssRsp, (void(*)(void*)) HTOnAssocRsp_wq, ieee);
-#endif
-#endif
for (i = 0; i < IEEE_IBSS_MAC_HASH_SIZE; i++)
INIT_LIST_HEAD(&ieee->ibss_mac_hash[i]);
@@ -205,32 +185,20 @@ struct net_device *alloc_ieee80211(int sizeof_priv)
failed:
if (dev)
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0))
free_netdev(dev);
-#else
- kfree(dev);
-#endif
return NULL;
}
void free_ieee80211(struct net_device *dev)
{
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0))
struct ieee80211_device *ieee = netdev_priv(dev);
-#else
- struct ieee80211_device *ieee = (struct ieee80211_device *)dev->priv;
-#endif
int i;
- //struct list_head *p, *q;
-// del_timer_sync(&ieee->SwBwTimer);
-#if 1
if (ieee->pHTInfo != NULL)
{
kfree(ieee->pHTInfo);
ieee->pHTInfo = NULL;
}
-#endif
RemoveAllTS(ieee);
ieee80211_softmac_free(ieee);
del_timer_sync(&ieee->crypt_deinit_timer);
@@ -247,20 +215,7 @@ void free_ieee80211(struct net_device *dev)
}
ieee80211_networks_free(ieee);
-#if 0
- for (i = 0; i < IEEE_IBSS_MAC_HASH_SIZE; i++) {
- list_for_each_safe(p, q, &ieee->ibss_mac_hash[i]) {
- kfree(list_entry(p, struct ieee_ibss_seq, list));
- list_del(p);
- }
- }
-
-#endif
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0))
free_netdev(dev);
-#else
- kfree(dev);
-#endif
}
#ifdef CONFIG_IEEE80211_DEBUG
@@ -358,11 +313,7 @@ int __init ieee80211_rtl_init(void)
}
ieee80211_debug_level = debug;
-#if(LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24))
- ieee80211_proc = create_proc_entry(DRV_NAME, S_IFDIR, proc_net);
-#else
ieee80211_proc = create_proc_entry(DRV_NAME, S_IFDIR, init_net.proc_net);
-#endif
if (ieee80211_proc == NULL) {
IEEE80211_ERROR("Unable to create " DRV_NAME
" proc directory\n");
@@ -371,11 +322,7 @@ int __init ieee80211_rtl_init(void)
e = create_proc_entry("debug_level", S_IFREG | S_IRUGO | S_IWUSR,
ieee80211_proc);
if (!e) {
-#if(LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24))
- remove_proc_entry(DRV_NAME, proc_net);
-#else
remove_proc_entry(DRV_NAME, init_net.proc_net);
-#endif
ieee80211_proc = NULL;
return -EIO;
}
@@ -390,11 +337,7 @@ void __exit ieee80211_rtl_exit(void)
{
if (ieee80211_proc) {
remove_proc_entry("debug_level", ieee80211_proc);
-#if(LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24))
- remove_proc_entry(DRV_NAME, proc_net);
-#else
remove_proc_entry(DRV_NAME, init_net.proc_net);
-#endif
ieee80211_proc = NULL;
}
ieee80211_crypto_wep_exit();
@@ -403,21 +346,10 @@ void __exit ieee80211_rtl_exit(void)
ieee80211_crypto_deinit();
}
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
#include <linux/moduleparam.h>
module_param(debug, int, 0444);
MODULE_PARM_DESC(debug, "debug output mask");
-//module_exit(ieee80211_rtl_exit);
-//module_init(ieee80211_rtl_init);
-#endif
#endif
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
-//EXPORT_SYMBOL(alloc_ieee80211);
-//EXPORT_SYMBOL(free_ieee80211);
-#else
-EXPORT_SYMBOL_NOVERS(alloc_ieee80211);
-EXPORT_SYMBOL_NOVERS(free_ieee80211);
-#endif
diff --git a/drivers/staging/rtl8192e/ieee80211/ieee80211_rx.c b/drivers/staging/rtl8192e/ieee80211/ieee80211_rx.c
index da10067485e..aaf9b9dc45e 100644
--- a/drivers/staging/rtl8192e/ieee80211/ieee80211_rx.c
+++ b/drivers/staging/rtl8192e/ieee80211/ieee80211_rx.c
@@ -55,11 +55,7 @@ static inline void ieee80211_monitor_rx(struct ieee80211_device *ieee,
u16 fc = le16_to_cpu(hdr->frame_ctl);
skb->dev = ieee->dev;
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
skb_reset_mac_header(skb);
-#else
- skb->mac.raw = skb->data;
-#endif
skb_pull(skb, ieee80211_get_hdrlen(fc));
skb->pkt_type = PACKET_OTHERHOST;
@@ -2793,8 +2789,6 @@ static inline void ieee80211_process_probe_response(
#endif
memcpy(target, &network, sizeof(*target));
list_add_tail(&target->list, &ieee->network_list);
- if(ieee->softmac_features & IEEE_SOFTMAC_ASSOCIATE)
- ieee80211_softmac_new_net(ieee,&network);
} else {
IEEE80211_DEBUG_SCAN("Updating '%s' (%pM) via %s.\n",
escape_essid(target->ssid,
@@ -2821,8 +2815,6 @@ static inline void ieee80211_process_probe_response(
//YJ,add,080819,for hidden ap,end
update_network(target, &network);
- if(renew && (ieee->softmac_features & IEEE_SOFTMAC_ASSOCIATE))
- ieee80211_softmac_new_net(ieee,&network);
}
spin_unlock_irqrestore(&ieee->lock, flags);
@@ -2880,11 +2872,3 @@ void ieee80211_rx_mgt(struct ieee80211_device *ieee,
}
}
-
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
-//EXPORT_SYMBOL(ieee80211_rx_mgt);
-//EXPORT_SYMBOL(ieee80211_rx);
-#else
-EXPORT_SYMBOL_NOVERS(ieee80211_rx_mgt);
-EXPORT_SYMBOL_NOVERS(ieee80211_rx);
-#endif
diff --git a/drivers/staging/rtl8192e/ieee80211/ieee80211_softmac.c b/drivers/staging/rtl8192e/ieee80211/ieee80211_softmac.c
index 46b6e8c900e..b7ec1ddee70 100644
--- a/drivers/staging/rtl8192e/ieee80211/ieee80211_softmac.c
+++ b/drivers/staging/rtl8192e/ieee80211/ieee80211_softmac.c
@@ -510,34 +510,11 @@ out:
}
}
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-/* called both by wq with ieee->lock held */
-void ieee80211_softmac_scan(struct ieee80211_device *ieee)
-{
-#if 0
- short watchdog = 0;
- do{
- ieee->current_network.channel =
- (ieee->current_network.channel + 1) % MAX_CHANNEL_NUMBER;
- if (watchdog++ > MAX_CHANNEL_NUMBER)
- return; /* no good chans */
- }while(!ieee->channel_map[ieee->current_network.channel]);
-#endif
-
- schedule_task(&ieee->softmac_scan_wq);
-}
-#endif
-
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20))
void ieee80211_softmac_scan_wq(struct work_struct *work)
{
struct delayed_work *dwork = container_of(work, struct delayed_work, work);
struct ieee80211_device *ieee = container_of(dwork, struct ieee80211_device, softmac_scan_wq);
-#else
-void ieee80211_softmac_scan_wq(struct ieee80211_device *ieee)
-{
-#endif
static short watchdog = 0;
u8 last_channel = ieee->current_network.channel;
#ifdef ENABLE_DOT11D
@@ -575,13 +552,7 @@ void ieee80211_softmac_scan_wq(struct ieee80211_device *ieee)
ieee80211_send_probe_requests(ieee);
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)
queue_delayed_work(ieee->wq, &ieee->softmac_scan_wq, IEEE80211_SOFTMAC_SCAN_TIME);
-#else
- //ieee->scan_timer.expires = jiffies + MSECS(IEEE80211_SOFTMAC_SCAN_TIME);
- if (ieee->scanning == 1)
- mod_timer(&ieee->scan_timer,(jiffies + MSECS(IEEE80211_SOFTMAC_SCAN_TIME)));
-#endif
up(&ieee->scan_sem);
return;
@@ -597,19 +568,6 @@ out:
up(&ieee->scan_sem);
}
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-void ieee80211_softmac_scan_cb(unsigned long _dev)
-{
- unsigned long flags;
- struct ieee80211_device *ieee = (struct ieee80211_device *)_dev;
-
- spin_lock_irqsave(&ieee->lock, flags);
- ieee80211_softmac_scan(ieee);
- spin_unlock_irqrestore(&ieee->lock, flags);
-}
-#endif
-
-
void ieee80211_beacons_start(struct ieee80211_device *ieee)
{
unsigned long flags;
@@ -665,11 +623,7 @@ void ieee80211_softmac_stop_scan(struct ieee80211_device *ieee)
if (ieee->scanning == 1){
ieee->scanning = 0;
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)
cancel_delayed_work(&ieee->softmac_scan_wq);
-#else
- del_timer_sync(&ieee->scan_timer);
-#endif
}
// spin_unlock_irqrestore(&ieee->lock, flags);
@@ -704,16 +658,7 @@ void ieee80211_rtl_start_scan(struct ieee80211_device *ieee)
if (ieee->softmac_features & IEEE_SOFTMAC_SCAN){
if (ieee->scanning == 0){
ieee->scanning = 1;
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)
queue_delayed_work(ieee->wq, &ieee->softmac_scan_wq, 0);
-#else
-
- queue_work(ieee->wq, &ieee->softmac_scan_wq);
-#endif
-#else
- ieee80211_softmac_scan(ieee);
-#endif
}
}else
ieee->start_scan(ieee->dev);
@@ -1428,13 +1373,8 @@ void ieee80211_associate_abort(struct ieee80211_device *ieee)
ieee->state = IEEE80211_ASSOCIATING_RETRY;
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)
queue_delayed_work(ieee->wq, &ieee->associate_retry_wq, \
IEEE80211_SOFTMAC_ASSOC_RETRY_TIME);
-#else
- schedule_task(&ieee->associate_retry_wq);
-#endif
-
spin_unlock_irqrestore(&ieee->lock, flags);
}
@@ -1527,14 +1467,9 @@ void ieee80211_associate_step2(struct ieee80211_device *ieee)
//dev_kfree_skb_any(skb);//edit by thomas
}
}
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20))
void ieee80211_associate_complete_wq(struct work_struct *work)
{
struct ieee80211_device *ieee = container_of(work, struct ieee80211_device, associate_complete_wq);
-#else
-void ieee80211_associate_complete_wq(struct ieee80211_device *ieee)
-{
-#endif
printk(KERN_INFO "Associated successfully\n");
ieee->is_roaming = false;
if(ieee80211_is_54g(ieee->current_network) &&
@@ -1606,21 +1541,12 @@ void ieee80211_associate_complete(struct ieee80211_device *ieee)
}
#endif
//ieee->UpdateHalRATRTableHandler(dev, ieee->dot11HTOperationalRateSet);
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)
queue_work(ieee->wq, &ieee->associate_complete_wq);
-#else
- schedule_task(&ieee->associate_complete_wq);
-#endif
}
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20))
void ieee80211_associate_procedure_wq(struct work_struct *work)
{
struct ieee80211_device *ieee = container_of(work, struct ieee80211_device, associate_procedure_wq);
-#else
-void ieee80211_associate_procedure_wq(struct ieee80211_device *ieee)
-{
-#endif
ieee->sync_scan_hurryup = 1;
#ifdef ENABLE_IPS
if(ieee->ieee80211_ips_leave != NULL)
@@ -1734,11 +1660,7 @@ inline void ieee80211_softmac_new_net(struct ieee80211_device *ieee, struct ieee
}
ieee->state = IEEE80211_ASSOCIATING;
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)
queue_work(ieee->wq, &ieee->associate_procedure_wq);
-#else
- schedule_task(&ieee->associate_procedure_wq);
-#endif
}else{
if(ieee80211_is_54g(ieee->current_network) &&
(ieee->modulation & IEEE80211_OFDM_MODULATION)){
@@ -2332,11 +2254,7 @@ ieee80211_rx_frame_softmac(struct ieee80211_device *ieee, struct sk_buff *skb,
"Association response status code 0x%x\n",
errcode);
if(ieee->AsocRetryCount < RT_ASOC_RETRY_LIMIT) {
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)
queue_work(ieee->wq, &ieee->associate_procedure_wq);
-#else
- schedule_task(&ieee->associate_procedure_wq);
-#endif
} else {
ieee80211_associate_abort(ieee);
}
@@ -2446,11 +2364,7 @@ ieee80211_rx_frame_softmac(struct ieee80211_device *ieee, struct sk_buff *skb,
// notify_wx_assoc_event(ieee);
//HTSetConnectBwMode(ieee, HT_CHANNEL_WIDTH_20, HT_EXTCHNL_OFFSET_NO_EXT);
RemovePeerTS(ieee, header->addr2);
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)
queue_work(ieee->wq, &ieee->associate_procedure_wq);
-#else
- schedule_task(&ieee->associate_procedure_wq);
-#endif
}
break;
case IEEE80211_STYPE_MANAGE_ACT:
@@ -2687,16 +2601,11 @@ void ieee80211_start_monitor_mode(struct ieee80211_device *ieee)
netif_carrier_on(ieee->dev);
}
}
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20))
void ieee80211_start_ibss_wq(struct work_struct *work)
{
struct delayed_work *dwork = container_of(work, struct delayed_work, work);
struct ieee80211_device *ieee = container_of(dwork, struct ieee80211_device, start_ibss_wq);
-#else
-void ieee80211_start_ibss_wq(struct ieee80211_device *ieee)
-{
-#endif
/* iwconfig mode ad-hoc will schedule this and return
* on the other hand this will block further iwconfig SET
* operations because of the wx_sem hold.
@@ -2807,11 +2716,7 @@ void ieee80211_start_ibss_wq(struct ieee80211_device *ieee)
inline void ieee80211_start_ibss(struct ieee80211_device *ieee)
{
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)
queue_delayed_work(ieee->wq, &ieee->start_ibss_wq, 150);
-#else
- schedule_task(&ieee->start_ibss_wq);
-#endif
}
/* this is called only in user context, with wx_sem held */
@@ -2873,22 +2778,22 @@ void ieee80211_disassociate(struct ieee80211_device *ieee)
if(IS_DOT11D_ENABLE(ieee))
Dot11d_Reset(ieee);
#endif
- ieee->state = IEEE80211_NOLINK;
ieee->is_set_key = false;
ieee->link_change(ieee->dev);
//HTSetConnectBwMode(ieee, HT_CHANNEL_WIDTH_20, HT_EXTCHNL_OFFSET_NO_EXT);
- notify_wx_assoc_event(ieee);
+ if (ieee->state == IEEE80211_LINKED ||
+ ieee->state == IEEE80211_ASSOCIATING) {
+ ieee->state = IEEE80211_NOLINK;
+ notify_wx_assoc_event(ieee);
+ }
+
+ ieee->state = IEEE80211_NOLINK;
}
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20))
void ieee80211_associate_retry_wq(struct work_struct *work)
{
struct delayed_work *dwork = container_of(work, struct delayed_work, work);
struct ieee80211_device *ieee = container_of(dwork, struct ieee80211_device, associate_retry_wq);
-#else
-void ieee80211_associate_retry_wq(struct ieee80211_device *ieee)
-{
-#endif
unsigned long flags;
down(&ieee->wx_sem);
@@ -2990,10 +2895,8 @@ void ieee80211_stop_protocol(struct ieee80211_device *ieee, u8 shutdown)
ieee80211_stop_send_beacons(ieee);
del_timer_sync(&ieee->associate_timer);
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)
cancel_delayed_work(&ieee->associate_retry_wq);
cancel_delayed_work(&ieee->start_ibss_wq);
-#endif
ieee80211_stop_scan(ieee);
ieee80211_disassociate(ieee);
@@ -3114,11 +3017,6 @@ void ieee80211_softmac_init(struct ieee80211_device *ieee)
ieee->sta_edca_param[3] = 0x002F3262;
ieee->aggregation = true;
ieee->enable_rx_imm_BA = 1;
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
- init_timer(&ieee->scan_timer);
- ieee->scan_timer.data = (unsigned long)ieee;
- ieee->scan_timer.function = ieee80211_softmac_scan_cb;
-#endif
ieee->tx_pending.txb = NULL;
init_timer(&ieee->associate_timer);
@@ -3129,16 +3027,12 @@ void ieee80211_softmac_init(struct ieee80211_device *ieee)
ieee->beacon_timer.data = (unsigned long) ieee;
ieee->beacon_timer.function = ieee80211_send_beacon_cb;
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)
#ifdef PF_SYNCTHREAD
ieee->wq = create_workqueue(DRV_NAME,0);
#else
ieee->wq = create_workqueue(DRV_NAME);
#endif
-#endif
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)
INIT_DELAYED_WORK(&ieee->start_ibss_wq,ieee80211_start_ibss_wq);
INIT_WORK(&ieee->associate_complete_wq, ieee80211_associate_complete_wq);
INIT_WORK(&ieee->associate_procedure_wq, ieee80211_associate_procedure_wq);
@@ -3146,23 +3040,6 @@ void ieee80211_softmac_init(struct ieee80211_device *ieee)
INIT_DELAYED_WORK(&ieee->associate_retry_wq, ieee80211_associate_retry_wq);
INIT_WORK(&ieee->wx_sync_scan_wq,ieee80211_wx_sync_scan_wq);
-#else
- INIT_WORK(&ieee->start_ibss_wq,(void(*)(void*)) ieee80211_start_ibss_wq,ieee);
- INIT_WORK(&ieee->associate_retry_wq,(void(*)(void*)) ieee80211_associate_retry_wq,ieee);
- INIT_WORK(&ieee->associate_complete_wq,(void(*)(void*)) ieee80211_associate_complete_wq,ieee);
- INIT_WORK(&ieee->associate_procedure_wq,(void(*)(void*)) ieee80211_associate_procedure_wq,ieee);
- INIT_WORK(&ieee->softmac_scan_wq,(void(*)(void*)) ieee80211_softmac_scan_wq,ieee);
- INIT_WORK(&ieee->wx_sync_scan_wq,(void(*)(void*)) ieee80211_wx_sync_scan_wq,ieee);
-#endif
-
-#else
- tq_init(&ieee->start_ibss_wq,(void(*)(void*)) ieee80211_start_ibss_wq,ieee);
- tq_init(&ieee->associate_retry_wq,(void(*)(void*)) ieee80211_associate_retry_wq,ieee);
- tq_init(&ieee->associate_complete_wq,(void(*)(void*)) ieee80211_associate_complete_wq,ieee);
- tq_init(&ieee->associate_procedure_wq,(void(*)(void*)) ieee80211_associate_procedure_wq,ieee);
- tq_init(&ieee->softmac_scan_wq,(void(*)(void*)) ieee80211_softmac_scan_wq,ieee);
- tq_init(&ieee->wx_sync_scan_wq,(void(*)(void*)) ieee80211_wx_sync_scan_wq,ieee);
-#endif
sema_init(&ieee->wx_sem, 1);
sema_init(&ieee->scan_sem, 1);
#ifdef ENABLE_IPS
@@ -3189,10 +3066,8 @@ void ieee80211_softmac_free(struct ieee80211_device *ieee)
#endif
del_timer_sync(&ieee->associate_timer);
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)
cancel_delayed_work(&ieee->associate_retry_wq);
destroy_workqueue(ieee->wq);
-#endif
up(&ieee->wx_sem);
}
@@ -3647,49 +3522,3 @@ void notify_wx_assoc_event(struct ieee80211_device *ieee)
memset(wrqu.ap_addr.sa_data, 0, ETH_ALEN);
wireless_send_event(ieee->dev, SIOCGIWAP, &wrqu, NULL);
}
-
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
-//EXPORT_SYMBOL(ieee80211_get_beacon);
-//EXPORT_SYMBOL(ieee80211_rtl_wake_queue);
-//EXPORT_SYMBOL(ieee80211_rtl_stop_queue);
-//EXPORT_SYMBOL(ieee80211_reset_queue);
-//EXPORT_SYMBOL(ieee80211_softmac_stop_protocol);
-//EXPORT_SYMBOL(ieee80211_softmac_start_protocol);
-//EXPORT_SYMBOL(ieee80211_is_shortslot);
-//EXPORT_SYMBOL(ieee80211_is_54g);
-//EXPORT_SYMBOL(ieee80211_wpa_supplicant_ioctl);
-//EXPORT_SYMBOL(ieee80211_ps_tx_ack);
-//EXPORT_SYMBOL(ieee80211_softmac_xmit);
-//EXPORT_SYMBOL(ieee80211_stop_send_beacons);
-//EXPORT_SYMBOL(notify_wx_assoc_event);
-//EXPORT_SYMBOL(SendDisassociation);
-//EXPORT_SYMBOL(ieee80211_disassociate);
-//EXPORT_SYMBOL(ieee80211_start_send_beacons);
-//EXPORT_SYMBOL(ieee80211_stop_scan);
-//EXPORT_SYMBOL(ieee80211_send_probe_requests);
-//EXPORT_SYMBOL(ieee80211_softmac_scan_syncro);
-//EXPORT_SYMBOL(ieee80211_start_scan_syncro);
-#else
-EXPORT_SYMBOL_NOVERS(ieee80211_get_beacon);
-EXPORT_SYMBOL_NOVERS(ieee80211_rtl_wake_queue);
-EXPORT_SYMBOL_NOVERS(ieee80211_rtl_stop_queue);
-EXPORT_SYMBOL_NOVERS(ieee80211_reset_queue);
-EXPORT_SYMBOL_NOVERS(ieee80211_softmac_stop_protocol);
-EXPORT_SYMBOL_NOVERS(ieee80211_softmac_start_protocol);
-EXPORT_SYMBOL_NOVERS(ieee80211_is_shortslot);
-EXPORT_SYMBOL_NOVERS(ieee80211_is_54g);
-EXPORT_SYMBOL_NOVERS(ieee80211_wpa_supplicant_ioctl);
-EXPORT_SYMBOL_NOVERS(ieee80211_ps_tx_ack);
-EXPORT_SYMBOL_NOVERS(ieee80211_softmac_xmit);
-EXPORT_SYMBOL_NOVERS(ieee80211_stop_send_beacons);
-EXPORT_SYMBOL_NOVERS(notify_wx_assoc_event);
-EXPORT_SYMBOL_NOVERS(SendDisassociation);
-EXPORT_SYMBOL_NOVERS(ieee80211_disassociate);
-EXPORT_SYMBOL_NOVERS(ieee80211_start_send_beacons);
-EXPORT_SYMBOL_NOVERS(ieee80211_stop_scan);
-EXPORT_SYMBOL_NOVERS(ieee80211_send_probe_requests);
-EXPORT_SYMBOL_NOVERS(ieee80211_softmac_scan_syncro);
-EXPORT_SYMBOL_NOVERS(ieee80211_start_scan_syncro);
-EXPORT_SYMBOL_NOVERS(ieee80211_sta_ps_send_null_frame);
-EXPORT_SYMBOL_NOVERS(ieee80211_sta_ps_send_pspoll_frame);
-#endif
diff --git a/drivers/staging/rtl8192e/ieee80211/ieee80211_softmac_wx.c b/drivers/staging/rtl8192e/ieee80211/ieee80211_softmac_wx.c
index 1bbd49f1d6f..d0a10807f7f 100644
--- a/drivers/staging/rtl8192e/ieee80211/ieee80211_softmac_wx.c
+++ b/drivers/staging/rtl8192e/ieee80211/ieee80211_softmac_wx.c
@@ -312,14 +312,9 @@ out:
return 0;
}
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)
void ieee80211_wx_sync_scan_wq(struct work_struct *work)
{
struct ieee80211_device *ieee = container_of(work, struct ieee80211_device, wx_sync_scan_wq);
-#else
-void ieee80211_wx_sync_scan_wq(struct ieee80211_device *ieee)
-{
-#endif
short chan;
HT_EXTCHNL_OFFSET chan_offset=0;
HT_CHANNEL_WIDTH bandwidth=0;
@@ -337,8 +332,6 @@ void ieee80211_wx_sync_scan_wq(struct ieee80211_device *ieee)
ieee80211_sta_ps_send_null_frame(ieee, 1);
#endif
- netif_carrier_off(ieee->dev);
-
if (ieee->data_hard_stop)
ieee->data_hard_stop(ieee->dev);
@@ -389,7 +382,6 @@ void ieee80211_wx_sync_scan_wq(struct ieee80211_device *ieee)
if(ieee->iw_mode == IW_MODE_ADHOC || ieee->iw_mode == IW_MODE_MASTER)
ieee80211_start_send_beacons(ieee);
- netif_carrier_on(ieee->dev);
count = 0;
up(&ieee->wx_sem);
@@ -408,11 +400,7 @@ int ieee80211_wx_set_scan(struct ieee80211_device *ieee, struct iw_request_info
}
if ( ieee->state == IEEE80211_LINKED){
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)
queue_work(ieee->wq, &ieee->wx_sync_scan_wq);
-#else
- schedule_task(&ieee->wx_sync_scan_wq);
-#endif
/* intentionally forget to up sem */
return 0;
}
@@ -459,29 +447,8 @@ int ieee80211_wx_set_essid(struct ieee80211_device *ieee,
if (wrqu->essid.flags && wrqu->essid.length) {
//first flush current network.ssid
len = ((wrqu->essid.length-1) < IW_ESSID_MAX_SIZE) ? (wrqu->essid.length-1) : IW_ESSID_MAX_SIZE;
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
- strncpy(ieee->current_network.ssid, extra, len);
- ieee->current_network.ssid_len = len;
-#if 0
- {
- int i;
- for (i=0; i<len; i++)
- printk("%c ", extra[i]);
- printk("\n");
- }
-#endif
-#else
strncpy(ieee->current_network.ssid, extra, len+1);
ieee->current_network.ssid_len = len+1;
-#if 0
- {
- int i;
- for (i=0; i<len + 1; i++)
- printk("%c ", extra[i]);
- printk("\n");
- }
-#endif
-#endif
ieee->ssid_set = 1;
}
else{
@@ -659,42 +626,4 @@ exit:
return ret;
}
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
-//EXPORT_SYMBOL(ieee80211_wx_get_essid);
-//EXPORT_SYMBOL(ieee80211_wx_set_essid);
-//EXPORT_SYMBOL(ieee80211_wx_set_rate);
-//EXPORT_SYMBOL(ieee80211_wx_get_rate);
-//EXPORT_SYMBOL(ieee80211_wx_set_wap);
-//EXPORT_SYMBOL(ieee80211_wx_get_wap);
-//EXPORT_SYMBOL(ieee80211_wx_set_mode);
-//EXPORT_SYMBOL(ieee80211_wx_get_mode);
-//EXPORT_SYMBOL(ieee80211_wx_set_scan);
-//EXPORT_SYMBOL(ieee80211_wx_get_freq);
-//EXPORT_SYMBOL(ieee80211_wx_set_freq);
-//EXPORT_SYMBOL(ieee80211_wx_set_rawtx);
-//EXPORT_SYMBOL(ieee80211_wx_get_name);
-//EXPORT_SYMBOL(ieee80211_wx_set_power);
-//EXPORT_SYMBOL(ieee80211_wx_get_power);
-//EXPORT_SYMBOL(ieee80211_wlan_frequencies);
-//EXPORT_SYMBOL(ieee80211_wx_set_rts);
-//EXPORT_SYMBOL(ieee80211_wx_get_rts);
-#else
-EXPORT_SYMBOL_NOVERS(ieee80211_wx_get_essid);
-EXPORT_SYMBOL_NOVERS(ieee80211_wx_set_essid);
-EXPORT_SYMBOL_NOVERS(ieee80211_wx_set_rate);
-EXPORT_SYMBOL_NOVERS(ieee80211_wx_get_rate);
-EXPORT_SYMBOL_NOVERS(ieee80211_wx_set_wap);
-EXPORT_SYMBOL_NOVERS(ieee80211_wx_get_wap);
-EXPORT_SYMBOL_NOVERS(ieee80211_wx_set_mode);
-EXPORT_SYMBOL_NOVERS(ieee80211_wx_get_mode);
-EXPORT_SYMBOL_NOVERS(ieee80211_wx_set_scan);
-EXPORT_SYMBOL_NOVERS(ieee80211_wx_get_freq);
-EXPORT_SYMBOL_NOVERS(ieee80211_wx_set_freq);
-EXPORT_SYMBOL_NOVERS(ieee80211_wx_set_rawtx);
-EXPORT_SYMBOL_NOVERS(ieee80211_wx_get_name);
-EXPORT_SYMBOL_NOVERS(ieee80211_wx_set_power);
-EXPORT_SYMBOL_NOVERS(ieee80211_wx_get_power);
-EXPORT_SYMBOL_NOVERS(ieee80211_wlan_frequencies);
-EXPORT_SYMBOL_NOVERS(ieee80211_wx_set_rts);
-EXPORT_SYMBOL_NOVERS(ieee80211_wx_get_rts);
-#endif
+
diff --git a/drivers/staging/rtl8192e/ieee80211/ieee80211_tx.c b/drivers/staging/rtl8192e/ieee80211/ieee80211_tx.c
index a75f3668a40..dd8a221e21a 100644
--- a/drivers/staging/rtl8192e/ieee80211/ieee80211_tx.c
+++ b/drivers/staging/rtl8192e/ieee80211/ieee80211_tx.c
@@ -286,12 +286,7 @@ ieee80211_classify(struct sk_buff *skb, struct ieee80211_network *network)
if (eth->h_proto != htons(ETH_P_IP))
return 0;
-// IEEE80211_DEBUG_DATA(IEEE80211_DL_DATA, skb->data, skb->len);
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22))
ip = ip_hdr(skb);
-#else
- ip = (struct iphdr*)(skb->data + sizeof(struct ether_header));
-#endif
switch (ip->tos & 0xfc) {
case 0x20:
return 2;
@@ -613,11 +608,7 @@ void ieee80211_query_seqnum(struct ieee80211_device*ieee, struct sk_buff* skb, u
int ieee80211_rtl_xmit(struct sk_buff *skb, struct net_device *dev)
{
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0))
struct ieee80211_device *ieee = netdev_priv(dev);
-#else
- struct ieee80211_device *ieee = (struct ieee80211_device *)dev->priv;
-#endif
struct ieee80211_txb *txb = NULL;
struct ieee80211_hdr_3addrqos *frag_hdr;
int i, bytes_per_frag, nr_frags, bytes_last_frag, frag_size;
diff --git a/drivers/staging/rtl8192e/ieee80211/ieee80211_wx.c b/drivers/staging/rtl8192e/ieee80211/ieee80211_wx.c
index 4971b1c8e7d..b74491c38ec 100644
--- a/drivers/staging/rtl8192e/ieee80211/ieee80211_wx.c
+++ b/drivers/staging/rtl8192e/ieee80211/ieee80211_wx.c
@@ -54,25 +54,7 @@ struct modes_unit ieee80211_modes[] = {
{"N-5G",4},
};
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,4,20)) && (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
-static inline char *
-iwe_stream_add_event_rsl(char * stream, /* Stream of events */
- char * ends, /* End of stream */
- struct iw_event *iwe, /* Payload */
- int event_len) /* Real size of payload */
-{
- /* Check if it's possible */
- if((stream + event_len) < ends) {
- iwe->len = event_len;
- ndelay(1); //new
- memcpy(stream, (char *) iwe, event_len);
- stream += event_len;
- }
- return stream;
-}
-#else
#define iwe_stream_add_event_rsl iwe_stream_add_event
-#endif
#define MAX_CUSTOM_LEN 64
static inline char *rtl819x_translate_scan(struct ieee80211_device *ieee,
@@ -93,11 +75,7 @@ static inline char *rtl819x_translate_scan(struct ieee80211_device *ieee,
iwe.cmd = SIOCGIWAP;
iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
memcpy(iwe.u.ap_addr.sa_data, network->bssid, ETH_ALEN);
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)
start = iwe_stream_add_event_rsl(info, start, stop, &iwe, IW_EV_ADDR_LEN);
-#else
- start = iwe_stream_add_event_rsl(start, stop, &iwe, IW_EV_ADDR_LEN);
-#endif
/* Remaining entries will be displayed in the order we provide them */
/* Add the ESSID */
@@ -106,22 +84,14 @@ static inline char *rtl819x_translate_scan(struct ieee80211_device *ieee,
// if (network->flags & NETWORK_EMPTY_ESSID) {
if (network->ssid_len == 0) {
iwe.u.data.length = sizeof("<hidden>");
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)
start = iwe_stream_add_point(info, start, stop, &iwe, "<hidden>");
-#else
- start = iwe_stream_add_point(start, stop, &iwe, "<hidden>");
-#endif
} else {
iwe.u.data.length = min(network->ssid_len, (u8)32);
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)
start = iwe_stream_add_point(info, start, stop, &iwe, network->ssid);
-#else
- start = iwe_stream_add_point(start, stop, &iwe, network->ssid);
-#endif
}
/* Add the protocol name */
iwe.cmd = SIOCGIWNAME;
- for(i=0; i<(sizeof(ieee80211_modes)/sizeof(ieee80211_modes[0])); i++) {
+ for(i=0; i<ARRAY_SIZE(ieee80211_modes); i++) {
if(network->mode&(1<<i)) {
sprintf(pname,ieee80211_modes[i].mode_string,ieee80211_modes[i].mode_size);
pname +=ieee80211_modes[i].mode_size;
@@ -129,11 +99,7 @@ static inline char *rtl819x_translate_scan(struct ieee80211_device *ieee,
}
*pname = '\0';
snprintf(iwe.u.name, IFNAMSIZ, "IEEE802.11%s", proto_name);
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)
start = iwe_stream_add_event_rsl(info, start, stop, &iwe, IW_EV_CHAR_LEN);
-#else
- start = iwe_stream_add_event_rsl(start, stop, &iwe, IW_EV_CHAR_LEN);
-#endif
/* Add mode */
iwe.cmd = SIOCGIWMODE;
if (network->capability &
@@ -142,11 +108,7 @@ static inline char *rtl819x_translate_scan(struct ieee80211_device *ieee,
iwe.u.mode = IW_MODE_MASTER;
else
iwe.u.mode = IW_MODE_ADHOC;
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)
start = iwe_stream_add_event_rsl(info, start, stop, &iwe, IW_EV_UINT_LEN);
-#else
- start = iwe_stream_add_event_rsl(start, stop, &iwe, IW_EV_UINT_LEN);
-#endif
}
/* Add frequency/channel */
@@ -156,11 +118,7 @@ static inline char *rtl819x_translate_scan(struct ieee80211_device *ieee,
iwe.u.freq.m = network->channel;
iwe.u.freq.e = 0;
iwe.u.freq.i = 0;
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)
start = iwe_stream_add_event_rsl(info, start, stop, &iwe, IW_EV_FREQ_LEN);
-#else
- start = iwe_stream_add_event_rsl(start, stop, &iwe, IW_EV_FREQ_LEN);
-#endif
/* Add encryption capability */
iwe.cmd = SIOCGIWENCODE;
if (network->capability & WLAN_CAPABILITY_PRIVACY)
@@ -168,11 +126,7 @@ static inline char *rtl819x_translate_scan(struct ieee80211_device *ieee,
else
iwe.u.data.flags = IW_ENCODE_DISABLED;
iwe.u.data.length = 0;
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)
start = iwe_stream_add_point(info, start, stop, &iwe, network->ssid);
-#else
- start = iwe_stream_add_point(start, stop, &iwe, network->ssid);
-#endif
/* Add basic and extended rates */
max_rate = 0;
p = custom;
@@ -216,33 +170,15 @@ static inline char *rtl819x_translate_scan(struct ieee80211_device *ieee,
if (rate > max_rate)
max_rate = rate;
}
-#if 0
- printk("max rate:%d ===basic rate:\n", max_rate);
- for (i=0;i<network->rates_len;i++)
- printk(" %x", network->rates[i]);
- printk("\n=======extend rate\n");
- for (i=0; i<network->rates_ex_len; i++)
- printk(" %x", network->rates_ex[i]);
- printk("\n");
-#endif
iwe.cmd = SIOCGIWRATE;
iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0;
iwe.u.bitrate.value = max_rate * 500000;
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)
start = iwe_stream_add_event_rsl(info, start, stop, &iwe,
IW_EV_PARAM_LEN);
-#else
- start = iwe_stream_add_event_rsl(start, stop, &iwe,
- IW_EV_PARAM_LEN);
-#endif
iwe.cmd = IWEVCUSTOM;
iwe.u.data.length = p - custom;
if (iwe.u.data.length)
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)
start = iwe_stream_add_point(info, start, stop, &iwe, custom);
-#else
- start = iwe_stream_add_point(start, stop, &iwe, custom);
-#endif
/* Add quality statistics */
/* TODO: Fix these values... */
iwe.cmd = IWEVQUAL;
@@ -257,21 +193,13 @@ static inline char *rtl819x_translate_scan(struct ieee80211_device *ieee,
if (!(network->stats.mask & IEEE80211_STATMASK_SIGNAL))
iwe.u.qual.updated |= IW_QUAL_QUAL_INVALID;
iwe.u.qual.updated = 7;
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)
start = iwe_stream_add_event_rsl(info, start, stop, &iwe, IW_EV_QUAL_LEN);
-#else
- start = iwe_stream_add_event_rsl(start, stop, &iwe, IW_EV_QUAL_LEN);
-#endif
iwe.cmd = IWEVCUSTOM;
p = custom;
iwe.u.data.length = p - custom;
if (iwe.u.data.length)
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)
start = iwe_stream_add_point(info, start, stop, &iwe, custom);
-#else
- start = iwe_stream_add_point(start, stop, &iwe, custom);
-#endif
#if (WIRELESS_EXT < 18)
if (ieee->wpa_enabled && network->wpa_ie_len){
char buf[MAX_WPA_IE_LEN * 2 + 30];
@@ -285,11 +213,7 @@ static inline char *rtl819x_translate_scan(struct ieee80211_device *ieee,
memset(&iwe, 0, sizeof(iwe));
iwe.cmd = IWEVCUSTOM;
iwe.u.data.length = strlen(buf);
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)
start = iwe_stream_add_point(info, start, stop, &iwe, buf);
-#else
- start = iwe_stream_add_point(start, stop, &iwe, buf);
-#endif
}
if (ieee->wpa_enabled && network->rsn_ie_len){
@@ -304,11 +228,7 @@ static inline char *rtl819x_translate_scan(struct ieee80211_device *ieee,
memset(&iwe, 0, sizeof(iwe));
iwe.cmd = IWEVCUSTOM;
iwe.u.data.length = strlen(buf);
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)
start = iwe_stream_add_point(info, start, stop, &iwe, buf);
-#else
- start = iwe_stream_add_point(start, stop, &iwe, buf);
-#endif
}
#else
memset(&iwe, 0, sizeof(iwe));
@@ -318,11 +238,7 @@ static inline char *rtl819x_translate_scan(struct ieee80211_device *ieee,
memcpy(buf, network->wpa_ie, network->wpa_ie_len);
iwe.cmd = IWEVGENIE;
iwe.u.data.length = network->wpa_ie_len;
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)
start = iwe_stream_add_point(info, start, stop, &iwe, buf);
-#else
- start = iwe_stream_add_point(start, stop, &iwe, buf);
-#endif
}
memset(&iwe, 0, sizeof(iwe));
if (network->rsn_ie_len)
@@ -331,11 +247,7 @@ static inline char *rtl819x_translate_scan(struct ieee80211_device *ieee,
memcpy(buf, network->rsn_ie, network->rsn_ie_len);
iwe.cmd = IWEVGENIE;
iwe.u.data.length = network->rsn_ie_len;
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)
start = iwe_stream_add_point(info, start, stop, &iwe, buf);
-#else
- start = iwe_stream_add_point(start, stop, &iwe, buf);
-#endif
}
#endif
@@ -348,11 +260,7 @@ static inline char *rtl819x_translate_scan(struct ieee80211_device *ieee,
" Last beacon: %lums ago", (jiffies - network->last_scanned) / (HZ / 100));
iwe.u.data.length = p - custom;
if (iwe.u.data.length)
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)
start = iwe_stream_add_point(info, start, stop, &iwe, custom);
-#else
- start = iwe_stream_add_point(start, stop, &iwe, custom);
-#endif
return start;
}
@@ -632,7 +540,6 @@ int ieee80211_wx_set_encode_ext(struct ieee80211_device *ieee,
union iwreq_data *wrqu, char *extra)
{
int ret = 0;
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)
struct net_device *dev = ieee->dev;
struct iw_point *encoding = &wrqu->encoding;
struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
@@ -807,7 +714,6 @@ done:
IEEE80211_DEBUG_WX("%s: reset_port failed\n", dev->name);
return -EINVAL;
}
-#endif
return ret;
}
@@ -870,7 +776,6 @@ int ieee80211_wx_set_mlme(struct ieee80211_device *ieee,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)
struct iw_mlme *mlme = (struct iw_mlme *) extra;
switch (mlme->cmd) {
case IW_MLME_DEAUTH:
@@ -880,7 +785,6 @@ int ieee80211_wx_set_mlme(struct ieee80211_device *ieee,
default:
return -EOPNOTSUPP;
}
-#endif
return 0;
}
@@ -888,7 +792,6 @@ int ieee80211_wx_set_auth(struct ieee80211_device *ieee,
struct iw_request_info *info,
struct iw_param *data, char *extra)
{
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)
switch (data->flags & IW_AUTH_INDEX) {
case IW_AUTH_WPA_VERSION:
/*need to support wpa2 here*/
@@ -946,23 +849,12 @@ int ieee80211_wx_set_auth(struct ieee80211_device *ieee,
default:
return -EOPNOTSUPP;
}
-#endif
return 0;
}
#endif
#if 1
int ieee80211_wx_set_gen_ie(struct ieee80211_device *ieee, u8 *ie, size_t len)
{
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)
-#if 0
- printk("====>%s()\n", __FUNCTION__);
- {
- int i;
- for (i=0; i<len; i++)
- printk("%2x ", ie[i]&0xff);
- printk("\n");
- }
-#endif
u8 *buf;
if (len>MAX_WPA_IE_LEN || (len && ie == NULL))
@@ -992,29 +884,7 @@ int ieee80211_wx_set_gen_ie(struct ieee80211_device *ieee, u8 *ie, size_t len)
ieee->wpa_ie = NULL;
ieee->wpa_ie_len = 0;
}
-#endif
return 0;
}
#endif
-
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
-//EXPORT_SYMBOL(ieee80211_wx_set_gen_ie);
-#if (WIRELESS_EXT >= 18)
-//EXPORT_SYMBOL(ieee80211_wx_set_mlme);
-//EXPORT_SYMBOL(ieee80211_wx_set_auth);
-//EXPORT_SYMBOL(ieee80211_wx_set_encode_ext);
-//EXPORT_SYMBOL(ieee80211_wx_get_encode_ext);
-#endif
-//EXPORT_SYMBOL(ieee80211_wx_get_scan);
-//EXPORT_SYMBOL(ieee80211_wx_set_encode);
-//EXPORT_SYMBOL(ieee80211_wx_get_encode);
-#else
-//EXPORT_SYMBOL_NOVERS(ieee80211_wx_set_gen_ie);
-//EXPORT_SYMBOL_NOVERS(ieee80211_wx_set_mlme);
-//EXPORT_SYMBOL_NOVERS(ieee80211_wx_set_auth);
-//EXPORT_SYMBOL_NOVERS(ieee80211_wx_set_encode_ext);
-//EXPORT_SYMBOL_NOVERS(ieee80211_wx_get_scan);
-//EXPORT_SYMBOL_NOVERS(ieee80211_wx_set_encode);
-//EXPORT_SYMBOL_NOVERS(ieee80211_wx_get_encode);
-#endif
diff --git a/drivers/staging/rtl8192e/ieee80211/rtl819x_HTProc.c b/drivers/staging/rtl8192e/ieee80211/rtl819x_HTProc.c
index 4c4b1df350a..b0c9c78eca4 100644
--- a/drivers/staging/rtl8192e/ieee80211/rtl819x_HTProc.c
+++ b/drivers/staging/rtl8192e/ieee80211/rtl819x_HTProc.c
@@ -1024,17 +1024,6 @@ u8 HTFilterMCSRate( struct ieee80211_device* ieee, u8* pSupportMCS, u8* pOperate
return true;
}
void HTSetConnectBwMode(struct ieee80211_device* ieee, HT_CHANNEL_WIDTH Bandwidth, HT_EXTCHNL_OFFSET Offset);
-#if 0
-//I need move this function to other places, such as rx?
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20))
-void HTOnAssocRsp_wq(struct work_struct *work)
-{
- struct ieee80211_device *ieee = container_of(work, struct ieee80211_device, ht_onAssRsp);
-#else
-void HTOnAssocRsp_wq(struct ieee80211_device *ieee)
-{
-#endif
-#endif
void HTOnAssocRsp(struct ieee80211_device *ieee)
{
PRT_HIGH_THROUGHPUT pHTInfo = ieee->pHTInfo;
@@ -1760,9 +1749,3 @@ void HTSetConnectBwModeCallback(struct ieee80211_device* ieee)
pHTInfo->bSwBwInProgress = false;
}
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-//EXPORT_SYMBOL_NOVERS(HTUpdateSelfAndPeerSetting);
-#else
-//EXPORT_SYMBOL(HTUpdateSelfAndPeerSetting);
-#endif
diff --git a/drivers/staging/rtl8192e/r8190_rtl8256.c b/drivers/staging/rtl8192e/r8190_rtl8256.c
index 7391f5f8f25..8bd5b173a7d 100644
--- a/drivers/staging/rtl8192e/r8190_rtl8256.c
+++ b/drivers/staging/rtl8192e/r8190_rtl8256.c
@@ -501,13 +501,13 @@ SetRFPowerState8190(
if((priv->ieee80211->eRFPowerState == eRfOff) && RT_IN_PS_LEVEL(pPSC, RT_RF_OFF_LEVL_HALT_NIC))
{ // The current RF state is OFF and the RF OFF level is halting the NIC, re-initialize the NIC.
bool rtstatus = true;
- u32 InitilizeCount = 3;
+ u32 InitializeCount = 3;
do
{
- InitilizeCount--;
+ InitializeCount--;
priv->RegRfOff = false;
rtstatus = NicIFEnableNIC(dev);
- }while( (rtstatus != true) &&(InitilizeCount >0) );
+ }while( (rtstatus != true) &&(InitializeCount >0) );
if(rtstatus != true)
{
diff --git a/drivers/staging/rtl8192e/r8192E.h b/drivers/staging/rtl8192e/r8192E.h
index f4be9cc1100..865cdc00897 100644
--- a/drivers/staging/rtl8192e/r8192E.h
+++ b/drivers/staging/rtl8192e/r8192E.h
@@ -1468,7 +1468,6 @@ typedef union _AC_PARAM{
#endif
bool init_firmware(struct net_device *dev);
-void rtl819xE_tx_cmd(struct net_device *dev, struct sk_buff *skb);
short rtl8192_tx(struct net_device *dev, struct sk_buff* skb);
u32 read_cam(struct net_device *dev, u8 addr);
void write_cam(struct net_device *dev, u8 addr, u32 data);
@@ -1503,10 +1502,9 @@ void write_phy_ofdm(struct net_device *dev, u8 adr, u32 data);
void rtl8185_tx_antenna(struct net_device *dev, u8 ant);
void rtl8187_set_rxconf(struct net_device *dev);
//short check_nic_enough_desc(struct net_device *dev, priority_t priority);
-void rtl8192_start_beacon(struct net_device *dev);
void CamResetAllEntry(struct net_device* dev);
void EnableHWSecurityConfig8192(struct net_device *dev);
-void setKey(struct net_device *dev, u8 EntryNo, u8 KeyIndex, u16 KeyType, u8 *MacAddr, u8 DefaultKey, u32 *KeyContent );
+void setKey(struct net_device *dev, u8 EntryNo, u8 KeyIndex, u16 KeyType, const u8 *MacAddr, u8 DefaultKey, u32 *KeyContent );
void CamPrintDbgReg(struct net_device* dev);
extern void dm_cck_txpower_adjust(struct net_device *dev,bool binch14);
extern void firmware_init_param(struct net_device *dev);
diff --git a/drivers/staging/rtl8192e/r8192E_core.c b/drivers/staging/rtl8192e/r8192E_core.c
index eb41402d1d3..4cd071adf84 100644
--- a/drivers/staging/rtl8192e/r8192E_core.c
+++ b/drivers/staging/rtl8192e/r8192E_core.c
@@ -92,12 +92,8 @@ u32 rt_global_debug_component = \
// COMP_POWER_TRACKING |
// COMP_INTR |
COMP_ERR ; //always open err flags on
-#ifndef PCI_DEVICE
-#define PCI_DEVICE(vend,dev)\
- .vendor=(vend),.device=(dev),\
- .subvendor=PCI_ANY_ID,.subdevice=PCI_ANY_ID
-#endif
-static struct pci_device_id rtl8192_pci_id_tbl[] __devinitdata = {
+
+static const struct pci_device_id rtl8192_pci_id_tbl[] __devinitdata = {
#ifdef RTL8190P
/* Realtek */
/* Dlink */
@@ -155,6 +151,16 @@ static struct pci_driver rtl8192_pci_driver = {
#endif
};
+static void rtl8192_start_beacon(struct net_device *dev);
+static void rtl8192_stop_beacon(struct net_device *dev);
+static void rtl819x_watchdog_wqcallback(struct work_struct *work);
+static void rtl8192_irq_rx_tasklet(struct r8192_priv *priv);
+static void rtl8192_irq_tx_tasklet(struct r8192_priv *priv);
+static void rtl8192_prepare_beacon(struct r8192_priv *priv);
+static irqreturn_t rtl8192_interrupt(int irq, void *netdev);
+static void rtl8192_try_wake_queue(struct net_device *dev, int pri);
+static void rtl819xE_tx_cmd(struct net_device *dev, struct sk_buff *skb);
+
#ifdef ENABLE_DOT11D
typedef struct _CHANNEL_LIST
@@ -163,7 +169,7 @@ typedef struct _CHANNEL_LIST
u8 Len;
}CHANNEL_LIST, *PCHANNEL_LIST;
-static CHANNEL_LIST ChannelPlan[] = {
+static const CHANNEL_LIST ChannelPlan[] = {
{{1,2,3,4,5,6,7,8,9,10,11,36,40,44,48,52,56,60,64,149,153,157,161,165},24}, //FCC
{{1,2,3,4,5,6,7,8,9,10,11},11}, //IC
{{1,2,3,4,5,6,7,8,9,10,11,12,13,36,40,44,48,52,56,60,64},21}, //ETSI
@@ -349,8 +355,8 @@ u8 rtl8192e_ap_sec_type(struct ieee80211_device *ieee)
//struct r8192_priv* priv = ieee80211_priv(dev);
//struct ieee80211_device *ieee = priv->ieee80211;
- static u8 ccmp_ie[4] = {0x00,0x50,0xf2,0x04};
- static u8 ccmp_rsn_ie[4] = {0x00, 0x0f, 0xac, 0x04};
+ static const u8 ccmp_ie[4] = {0x00,0x50,0xf2,0x04};
+ static const u8 ccmp_rsn_ie[4] = {0x00, 0x0f, 0xac, 0x04};
int wpa_ie_len= ieee->wpa_ie_len;
struct ieee80211_crypt_data* crypt;
int encrypt;
@@ -487,15 +493,13 @@ rtl8192e_SetHwReg(struct net_device *dev,u8 variable,u8* val)
/* this might still called in what was the PHY rtl8185/rtl8192 common code
* plans are to possibilty turn it again in one common code...
*/
-inline void force_pci_posting(struct net_device *dev)
+void force_pci_posting(struct net_device *dev)
{
}
//warning message WB
-irqreturn_t rtl8192_interrupt(int irq, void *netdev);
//static struct net_device_stats *rtl8192_stats(struct net_device *dev);
-void rtl8192_commit(struct net_device *dev);
//void rtl8192_restart(struct net_device *dev);
void rtl8192_restart(struct work_struct *work);
//void rtl8192_rq_tx_ack(struct work_struct *work);
@@ -940,7 +944,7 @@ void rtl8192_rx_enable(struct net_device *dev)
* HIGH_QUEUE ===> 7
* BEACON_QUEUE ===> 8
* */
-static u32 TX_DESC_BASE[] = {BKQDA, BEQDA, VIQDA, VOQDA, HCCAQDA, CQDA, MQDA, HQDA, BQDA};
+static const u32 TX_DESC_BASE[] = {BKQDA, BEQDA, VIQDA, VOQDA, HCCAQDA, CQDA, MQDA, HQDA, BQDA};
void rtl8192_tx_enable(struct net_device *dev)
{
struct r8192_priv *priv = (struct r8192_priv *)ieee80211_priv(dev);
@@ -1116,7 +1120,7 @@ static void rtl8192_reset(struct net_device *dev)
}
#endif
-static u16 rtl_rate[] = {10,20,55,110,60,90,120,180,240,360,480,540};
+static const u16 rtl_rate[] = {10,20,55,110,60,90,120,180,240,360,480,540};
inline u16 rtl8192_rate2rate(short rate)
{
if (rate >11) return 0;
@@ -1252,8 +1256,6 @@ static int rtl8192_hard_start_xmit(struct sk_buff *skb,struct net_device *dev)
}
-void rtl8192_try_wake_queue(struct net_device *dev, int pri);
-
static void rtl8192_tx_isr(struct net_device *dev, int prio)
{
struct r8192_priv *priv = (struct r8192_priv *)ieee80211_priv(dev);
@@ -1733,11 +1735,6 @@ short rtl8192_tx(struct net_device *dev, struct sk_buff* skb)
pdesc->NoEnc = 1;
pdesc->SecType = 0x0;
if (tcb_desc->bHwSec) {
- static u8 tmp =0;
- if (!tmp) {
- printk("==>================hw sec\n");
- tmp = 1;
- }
switch (priv->ieee80211->pairwise_key_type) {
case KEY_TYPE_WEP40:
case KEY_TYPE_WEP104:
@@ -1988,7 +1985,7 @@ static void rtl8192_update_beacon(struct work_struct * work)
/*
* background support to run QoS activate functionality
*/
-static int WDCAPARA_ADD[] = {EDCAPARA_BE,EDCAPARA_BK,EDCAPARA_VI,EDCAPARA_VO};
+static const int WDCAPARA_ADD[] = {EDCAPARA_BE,EDCAPARA_BK,EDCAPARA_VI,EDCAPARA_VO};
static void rtl8192_qos_activate(struct work_struct * work)
{
struct r8192_priv *priv = container_of(work, struct r8192_priv, qos_activate);
@@ -2646,11 +2643,6 @@ static void rtl8192_init_priv_lock(struct r8192_priv* priv)
mutex_init(&priv->mutex);
}
-extern void rtl819x_watchdog_wqcallback(struct work_struct *work);
-
-void rtl8192_irq_rx_tasklet(struct r8192_priv *priv);
-void rtl8192_irq_tx_tasklet(struct r8192_priv *priv);
-void rtl8192_prepare_beacon(struct r8192_priv *priv);
//init tasklet and wait_queue here. only 2.6 above kernel is considered
#define DRV_NAME "wlan0"
static void rtl8192_init_priv_task(struct net_device* dev)
@@ -3807,7 +3799,7 @@ static RT_STATUS rtl8192_adapter_start(struct net_device *dev)
}
-void rtl8192_prepare_beacon(struct r8192_priv *priv)
+static void rtl8192_prepare_beacon(struct r8192_priv *priv)
{
struct sk_buff *skb;
//unsigned long flags;
@@ -3837,7 +3829,7 @@ void rtl8192_prepare_beacon(struct r8192_priv *priv)
* rtl8192_beacon_tx_enable(). rtl8192_beacon_tx_disable() might
* be used to stop beacon transmission
*/
-void rtl8192_start_beacon(struct net_device *dev)
+static void rtl8192_start_beacon(struct net_device *dev)
{
struct r8192_priv *priv = (struct r8192_priv *)ieee80211_priv(dev);
struct ieee80211_network *net = &priv->ieee80211->current_network;
@@ -4124,14 +4116,14 @@ static void CamRestoreAllEntry(struct net_device *dev)
{
u8 EntryId = 0;
struct r8192_priv *priv = ieee80211_priv(dev);
- u8* MacAddr = priv->ieee80211->current_network.bssid;
+ const u8* MacAddr = priv->ieee80211->current_network.bssid;
- static u8 CAM_CONST_ADDR[4][6] = {
+ static const u8 CAM_CONST_ADDR[4][6] = {
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
{0x00, 0x00, 0x00, 0x00, 0x00, 0x01},
{0x00, 0x00, 0x00, 0x00, 0x00, 0x02},
{0x00, 0x00, 0x00, 0x00, 0x00, 0x03}};
- static u8 CAM_CONST_BROAD[] =
+ static const u8 CAM_CONST_BROAD[] =
{0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
RT_TRACE(COMP_SEC, "CamRestoreAllEntry: \n");
@@ -4318,7 +4310,6 @@ RESET_START:
del_timer_sync(&ieee->associate_timer);
cancel_delayed_work(&ieee->associate_retry_wq);
ieee80211_stop_scan(ieee);
- netif_carrier_off(dev);
up(&ieee->wx_sem);
}
else{
@@ -4669,7 +4660,7 @@ static void rtl819x_update_rxcounts(
}
-void rtl819x_watchdog_wqcallback(struct work_struct *work)
+static void rtl819x_watchdog_wqcallback(struct work_struct *work)
{
struct delayed_work *dwork = container_of(work,struct delayed_work,work);
struct r8192_priv *priv = container_of(dwork,struct r8192_priv,watch_dog_wq);
@@ -6076,7 +6067,7 @@ static void rtl8192_tx_resume(struct net_device *dev)
}
}
-void rtl8192_irq_tx_tasklet(struct r8192_priv *priv)
+static void rtl8192_irq_tx_tasklet(struct r8192_priv *priv)
{
rtl8192_tx_resume(priv->ieee80211->dev);
}
@@ -6305,7 +6296,7 @@ done:
}
-void rtl8192_irq_rx_tasklet(struct r8192_priv *priv)
+static void rtl8192_irq_rx_tasklet(struct r8192_priv *priv)
{
rtl8192_rx(priv->ieee80211->dev);
/* unmask RDU */
@@ -6640,7 +6631,7 @@ static void __exit rtl8192_pci_module_exit(void)
}
//warning message WB
-irqreturn_t rtl8192_interrupt(int irq, void *netdev)
+static irqreturn_t rtl8192_interrupt(int irq, void *netdev)
{
struct net_device *dev = (struct net_device *) netdev;
struct r8192_priv *priv = (struct r8192_priv *)ieee80211_priv(dev);
@@ -6784,7 +6775,7 @@ irqreturn_t rtl8192_interrupt(int irq, void *netdev)
return IRQ_HANDLED;
}
-void rtl8192_try_wake_queue(struct net_device *dev, int pri)
+static void rtl8192_try_wake_queue(struct net_device *dev, int pri)
{
#if 0
unsigned long flags;
@@ -6847,7 +6838,7 @@ void setKey( struct net_device *dev,
u8 EntryNo,
u8 KeyIndex,
u16 KeyType,
- u8 *MacAddr,
+ const u8 *MacAddr,
u8 DefaultKey,
u32 *KeyContent )
{
diff --git a/drivers/staging/rtl8192e/r8192E_dm.c b/drivers/staging/rtl8192e/r8192E_dm.c
index a249f00da60..a5884c6bcc2 100644
--- a/drivers/staging/rtl8192e/r8192E_dm.c
+++ b/drivers/staging/rtl8192e/r8192E_dm.c
@@ -26,20 +26,20 @@ Major Change History:
// Indicate different AP vendor for IOT issue.
//
#ifdef RTL8190P
-static u32 edca_setting_DL[HT_IOT_PEER_MAX] =
+static const u32 edca_setting_DL[HT_IOT_PEER_MAX] =
{ 0x5e4322, 0x5e4322, 0x5e4322, 0x604322, 0xa44f, 0x5e4322, 0x5e4322};
-static u32 edca_setting_UL[HT_IOT_PEER_MAX] =
+static const u32 edca_setting_UL[HT_IOT_PEER_MAX] =
{ 0x5e4322, 0xa44f, 0x5e4322, 0x604322, 0x5e4322, 0x5e4322, 0x5e4322};
#else
#ifdef RTL8192E
-static u32 edca_setting_DL[HT_IOT_PEER_MAX] =
+static const u32 edca_setting_DL[HT_IOT_PEER_MAX] =
{ 0x5e4322, 0x5e4322, 0x5e4322, 0x604322, 0xa44f, 0x5e4322, 0x5e4322};
-static u32 edca_setting_UL[HT_IOT_PEER_MAX] =
+static const u32 edca_setting_UL[HT_IOT_PEER_MAX] =
{ 0x5e4322, 0xa44f, 0x5e4322, 0x604322, 0x5e4322, 0x5e4322, 0x5e4322};
#else
-static u32 edca_setting_DL[HT_IOT_PEER_MAX] =
+static const u32 edca_setting_DL[HT_IOT_PEER_MAX] =
{ 0x5e4322, 0x5e4322, 0x5e4322, 0x604322, 0xa44f, 0x5ea44f, 0x5e4322};
-static u32 edca_setting_UL[HT_IOT_PEER_MAX] =
+static const u32 edca_setting_UL[HT_IOT_PEER_MAX] =
{ 0x5e4322, 0xa44f, 0x5e4322, 0x604322, 0x5ea44f, 0x5ea44f, 0x5e4322};
#endif
#endif
@@ -592,7 +592,7 @@ static void dm_bandwidth_autoswitch(struct net_device * dev)
//OFDM default at 0db, index=6.
#ifndef RTL8190P
-static u32 OFDMSwingTable[OFDM_Table_Length] = {
+static const u32 OFDMSwingTable[OFDM_Table_Length] = {
0x7f8001fe, // 0, +6db
0x71c001c7, // 1, +5db
0x65400195, // 2, +4db
@@ -613,7 +613,7 @@ static u32 OFDMSwingTable[OFDM_Table_Length] = {
0x12000048, // 17, -11db
0x10000040 // 18, -12db
};
-static u8 CCKSwingTable_Ch1_Ch13[CCK_Table_length][8] = {
+static const u8 CCKSwingTable_Ch1_Ch13[CCK_Table_length][8] = {
{0x36, 0x35, 0x2e, 0x25, 0x1c, 0x12, 0x09, 0x04}, // 0, +0db ===> CCK40M default
{0x30, 0x2f, 0x29, 0x21, 0x19, 0x10, 0x08, 0x03}, // 1, -1db
{0x2b, 0x2a, 0x25, 0x1e, 0x16, 0x0e, 0x07, 0x03}, // 2, -2db
@@ -628,7 +628,7 @@ static u8 CCKSwingTable_Ch1_Ch13[CCK_Table_length][8] = {
{0x0f, 0x0f, 0x0d, 0x0b, 0x08, 0x05, 0x03, 0x01} // 11, -11db
};
-static u8 CCKSwingTable_Ch14[CCK_Table_length][8] = {
+static const u8 CCKSwingTable_Ch14[CCK_Table_length][8] = {
{0x36, 0x35, 0x2e, 0x1b, 0x00, 0x00, 0x00, 0x00}, // 0, +0db ===> CCK40M default
{0x30, 0x2f, 0x29, 0x18, 0x00, 0x00, 0x00, 0x00}, // 1, -1db
{0x2b, 0x2a, 0x25, 0x15, 0x00, 0x00, 0x00, 0x00}, // 2, -2db
@@ -2094,8 +2094,6 @@ static void dm_ctrl_initgain_byrssi(struct net_device *dev)
dm_ctrl_initgain_byrssi_by_fwfalse_alarm(dev);
else if(dm_digtable.dig_algorithm == DIG_ALGO_BY_RSSI)
dm_ctrl_initgain_byrssi_by_driverrssi(dev);
- else
- return;
}
@@ -2938,8 +2936,6 @@ void dm_gpio_change_rf_callback(struct work_struct *work)
RT_RF_POWER_STATE eRfPowerStateToSet;
bool bActuallySet = false;
- bActuallySet=false;
-
if(!priv->up)
{
RT_TRACE((COMP_INIT | COMP_POWER | COMP_RF),"dm_gpio_change_rf_callback(): Callback function breaks out!!\n");
diff --git a/drivers/staging/rtl8192e/r8192E_wx.c b/drivers/staging/rtl8192e/r8192E_wx.c
index 0b0f39ce3ce..5742cee8120 100644
--- a/drivers/staging/rtl8192e/r8192E_wx.c
+++ b/drivers/staging/rtl8192e/r8192E_wx.c
@@ -26,7 +26,7 @@
#endif
#define RATE_COUNT 12
-static u32 rtl8180_rates[] = {1000000,2000000,5500000,11000000,
+static const u32 rtl8180_rates[] = {1000000,2000000,5500000,11000000,
6000000,9000000,12000000,18000000,24000000,36000000,48000000,54000000};
@@ -137,161 +137,6 @@ static int r8192_wx_get_power(struct net_device *dev,
return ieee80211_wx_get_power(priv->ieee80211,info,wrqu,extra);
}
-#ifdef JOHN_IOCTL
-u16 read_rtl8225(struct net_device *dev, u8 addr);
-void write_rtl8225(struct net_device *dev, u8 adr, u16 data);
-u32 john_read_rtl8225(struct net_device *dev, u8 adr);
-void _write_rtl8225(struct net_device *dev, u8 adr, u16 data);
-
-static int r8192_wx_read_regs(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct r8192_priv *priv = ieee80211_priv(dev);
- u8 addr;
- u16 data1;
-
- down(&priv->wx_sem);
-
-
- get_user(addr,(u8*)wrqu->data.pointer);
- data1 = read_rtl8225(dev, addr);
- wrqu->data.length = data1;
-
- up(&priv->wx_sem);
- return 0;
-
-}
-
-static int r8192_wx_write_regs(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct r8192_priv *priv = ieee80211_priv(dev);
- u8 addr;
-
- down(&priv->wx_sem);
-
- get_user(addr, (u8*)wrqu->data.pointer);
- write_rtl8225(dev, addr, wrqu->data.length);
-
- up(&priv->wx_sem);
- return 0;
-
-}
-
-void rtl8187_write_phy(struct net_device *dev, u8 adr, u32 data);
-u8 rtl8187_read_phy(struct net_device *dev,u8 adr, u32 data);
-
-static int r8192_wx_read_bb(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct r8192_priv *priv = ieee80211_priv(dev);
- u8 databb;
-#if 0
- int i;
- for(i=0;i<12;i++) printk("%8x\n", read_cam(dev, i) );
-#endif
-
- down(&priv->wx_sem);
-
- databb = rtl8187_read_phy(dev, (u8)wrqu->data.length, 0x00000000);
- wrqu->data.length = databb;
-
- up(&priv->wx_sem);
- return 0;
-}
-
-void rtl8187_write_phy(struct net_device *dev, u8 adr, u32 data);
-static int r8192_wx_write_bb(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct r8192_priv *priv = ieee80211_priv(dev);
- u8 databb;
-
- down(&priv->wx_sem);
-
- get_user(databb, (u8*)wrqu->data.pointer);
- rtl8187_write_phy(dev, wrqu->data.length, databb);
-
- up(&priv->wx_sem);
- return 0;
-
-}
-
-
-static int r8192_wx_write_nicb(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct r8192_priv *priv = ieee80211_priv(dev);
- u32 addr;
-
- down(&priv->wx_sem);
-
- get_user(addr, (u32*)wrqu->data.pointer);
- write_nic_byte(dev, addr, wrqu->data.length);
-
- up(&priv->wx_sem);
- return 0;
-
-}
-static int r8192_wx_read_nicb(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct r8192_priv *priv = ieee80211_priv(dev);
- u32 addr;
- u16 data1;
-
- down(&priv->wx_sem);
-
- get_user(addr,(u32*)wrqu->data.pointer);
- data1 = read_nic_byte(dev, addr);
- wrqu->data.length = data1;
-
- up(&priv->wx_sem);
- return 0;
-}
-
-static int r8192_wx_get_ap_status(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct r8192_priv *priv = ieee80211_priv(dev);
- struct ieee80211_device *ieee = priv->ieee80211;
- struct ieee80211_network *target;
- int name_len;
-
- down(&priv->wx_sem);
-
- //count the length of input ssid
- for(name_len=0 ; ((char*)wrqu->data.pointer)[name_len]!='\0' ; name_len++);
-
- //search for the correspoding info which is received
- list_for_each_entry(target, &ieee->network_list, list) {
- if ( (target->ssid_len == name_len) &&
- (strncmp(target->ssid, (char*)wrqu->data.pointer, name_len)==0)){
- if(target->wpa_ie_len>0 || target->rsn_ie_len>0 )
- //set flags=1 to indicate this ap is WPA
- wrqu->data.flags = 1;
- else wrqu->data.flags = 0;
-
-
- break;
- }
- }
-
- up(&priv->wx_sem);
- return 0;
-}
-
-
-
-#endif
-
static int r8192_wx_set_rawtx(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
diff --git a/drivers/staging/rtl8192e/r819xE_phy.c b/drivers/staging/rtl8192e/r819xE_phy.c
index 7bd4fae0667..ffd1e97e27b 100644
--- a/drivers/staging/rtl8192e/r819xE_phy.c
+++ b/drivers/staging/rtl8192e/r819xE_phy.c
@@ -7,7 +7,7 @@
#ifdef ENABLE_DOT11D
#include "ieee80211/dot11d.h"
#endif
-static u32 RF_CHANNEL_TABLE_ZEBRA[] = {
+static const u32 RF_CHANNEL_TABLE_ZEBRA[] = {
0,
0x085c, //2412 1
0x08dc, //2417 2
diff --git a/drivers/staging/rtl8192su/Kconfig b/drivers/staging/rtl8192su/Kconfig
index b422ea1ecf9..27b89a43267 100644
--- a/drivers/staging/rtl8192su/Kconfig
+++ b/drivers/staging/rtl8192su/Kconfig
@@ -4,5 +4,6 @@ config RTL8192SU
select WIRELESS_EXT
select WEXT_PRIV
select EEPROM_93CX6
+ select CRYPTO
default N
---help---
diff --git a/drivers/staging/rtl8192su/TODO b/drivers/staging/rtl8192su/TODO
index 3c8da157a93..b15204ea4ec 100644
--- a/drivers/staging/rtl8192su/TODO
+++ b/drivers/staging/rtl8192su/TODO
@@ -1,4 +1,10 @@
TODO:
+- merge realteks bugfixes and new features into the driver:
+ - an updated version of this driver can be found here:
+ http://www.getnet.eu/products_GN-621U.html
+ - note:
+ realtek has stripped alomost all comments from the source,
+ so please leave all comments that may help in development in the code.
- prepare private ieee80211 stack for merge with rtl8187se's version:
- remove rtl8192su's specific dead code
- cleanup ieee80211.h
@@ -7,7 +13,6 @@ TODO:
- switch to use shared "librtl" instead of private ieee80211 stack
- switch to use LIB80211
- switch to use MAC80211
-- switch to use EEPROM_93CX6
- use kernel coding style
- checkpatch.pl fixes
- sparse fixes
diff --git a/drivers/staging/rtl8192su/ieee80211/dot11d.c b/drivers/staging/rtl8192su/ieee80211/dot11d.c
index 22484621478..6275cc75ec8 100644
--- a/drivers/staging/rtl8192su/ieee80211/dot11d.c
+++ b/drivers/staging/rtl8192su/ieee80211/dot11d.c
@@ -1,11 +1,21 @@
-//-----------------------------------------------------------------------------
-// File:
-// Dot11d.c
-//
-// Description:
-// Implement 802.11d.
-//
-//-----------------------------------------------------------------------------
+/******************************************************************************
+ * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved.
+ *
+ * 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, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+******************************************************************************/
#include "dot11d.h"
@@ -50,7 +60,6 @@ Dot11d_Reset(struct ieee80211_device *ieee)
pDot11dInfo->CountryIeLen = 0;
RESET_CIE_WATCHDOG(ieee);
- //printk("Dot11d_Reset()\n");
}
//
@@ -105,7 +114,6 @@ Dot11d_UpdateCountryIe(
pTriple = (PCHNL_TXPOWER_TRIPLE)((u8*)pTriple + 3);
}
#if 1
- //printk("Dot11d_UpdateCountryIe(): Channel List:\n");
printk("Channel List:");
for(i=1; i<= MAX_CHANNEL_NUMBER; i++)
if(pDot11dInfo->channel_map[i] > 0)
diff --git a/drivers/staging/rtl8192su/ieee80211/dot11d.h b/drivers/staging/rtl8192su/ieee80211/dot11d.h
index 913ac5d97e7..62a2c905e1f 100644
--- a/drivers/staging/rtl8192su/ieee80211/dot11d.h
+++ b/drivers/staging/rtl8192su/ieee80211/dot11d.h
@@ -1,10 +1,26 @@
+/******************************************************************************
+ * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved.
+ *
+ * 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, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+******************************************************************************/
#ifndef __INC_DOT11D_H
#define __INC_DOT11D_H
#include "ieee80211.h"
-//#define DOT11D_MAX_CHNL_NUM 83
-
typedef struct _CHNL_TXPOWER_TRIPLE {
u8 FirstChnl;
u8 NumChnls;
@@ -18,7 +34,6 @@ typedef enum _DOT11D_STATE {
}DOT11D_STATE;
typedef struct _RT_DOT11D_INFO {
- //DECLARE_RT_OBJECT(RT_DOT11D_INFO);
bool bEnabled; // dot11MultiDomainCapabilityEnabled
@@ -28,8 +43,6 @@ typedef struct _RT_DOT11D_INFO {
u8 CountryIeWatchdog;
u8 channel_map[MAX_CHANNEL_NUMBER+1]; //!!!Value 0: Invalid, 1: Valid (active scan), 2: Valid (passive scan)
- //u8 ChnlListLen; // #Bytes valid in ChnlList[].
- //u8 ChnlList[DOT11D_MAX_CHNL_NUM];
u8 MaxTxPwrDbmList[MAX_CHANNEL_NUMBER+1];
DOT11D_STATE State;
@@ -95,4 +108,4 @@ int ToLegalChannel(
struct ieee80211_device * dev,
u8 channel
);
-#endif // #ifndef __INC_DOT11D_H
+#endif
diff --git a/drivers/staging/rtl8192su/ieee80211/ieee80211.h b/drivers/staging/rtl8192su/ieee80211/ieee80211.h
index bcb2b12a839..1d6789db4e4 100644
--- a/drivers/staging/rtl8192su/ieee80211/ieee80211.h
+++ b/drivers/staging/rtl8192su/ieee80211/ieee80211.h
@@ -168,6 +168,10 @@ typedef struct ieee_param {
/* QOS control */
#define IEEE80211_QCTL_TID 0x000F
+#define OUI_SUBTYPE_WMM_INFO 0
+#define OUI_SUBTYPE_WMM_PARAM 1
+#define OUI_SUBTYPE_QOS_CAPABI 5
+
/* debug macros */
#define CONFIG_IEEE80211_DEBUG
#ifdef CONFIG_IEEE80211_DEBUG
@@ -1120,11 +1124,27 @@ enum {
COUNTRY_CODE_MKK = 5,
COUNTRY_CODE_MKK1 = 6,
COUNTRY_CODE_ISRAEL = 7,
- COUNTRY_CODE_TELEC,
- COUNTRY_CODE_MIC,
- COUNTRY_CODE_GLOBAL_DOMAIN
+ COUNTRY_CODE_TELEC = 8,
+ COUNTRY_CODE_MIC = 9,
+ COUNTRY_CODE_GLOBAL_DOMAIN = 10,
+ COUNTRY_CODE_WORLD_WIDE_13 = 11,
+ COUNTRY_CODE_TELEC_NETGEAR = 12,
+ COUNTRY_CODE_MAX
};
+#define NUM_PMKID_CACHE 16
+
+typedef struct _RT_PMKID_LIST
+{
+ u8 bUsed;
+ u8 Bssid[6];
+ u8 PMKID[16];
+ u8 SsidBuf[33];
+ u8* ssid_octet;
+ u16 ssid_length;
+} RT_PMKID_LIST, *PRT_PMKID_LIST;
+
+
#include "ieee80211_r8192s.h"
struct ieee80211_device {
@@ -1134,6 +1154,7 @@ struct ieee80211_device {
/* hw security related */
u8 hwsec_active;
bool is_silent_reset;
+ bool force_mic_error;
bool is_roaming;
bool ieee_up;
bool bSupportRemoteWakeUp;
@@ -1247,6 +1268,7 @@ struct ieee80211_device {
int bcrx_sta_key; /* use individual keys to override default keys even
* with RX of broad/multicast frames */
+ RT_PMKID_LIST PMKIDList[NUM_PMKID_CACHE];
/* Fragmentation structures */
// each streaming contain a entry
struct ieee80211_frag_entry frag_cache[17][IEEE80211_FRAG_CACHE_LEN];
@@ -1295,6 +1317,10 @@ struct ieee80211_device {
*/
void *pDot11dInfo;
bool bGlobalDomain;
+
+ u8 IbssStartChnl;
+ u8 ibss_maxjoin_chal;
+
int rate; /* current rate */
int basic_rate;
//FIXME: pleace callback, see if redundant with softmac_features
diff --git a/drivers/staging/rtl8192su/ieee80211/ieee80211_crypt.c b/drivers/staging/rtl8192su/ieee80211/ieee80211_crypt.c
index 80194233943..24e7d595e3c 100644
--- a/drivers/staging/rtl8192su/ieee80211/ieee80211_crypt.c
+++ b/drivers/staging/rtl8192su/ieee80211/ieee80211_crypt.c
@@ -11,7 +11,6 @@
*
*/
-//#include <linux/config.h>
#include <linux/version.h>
#include <linux/module.h>
#include <linux/init.h>
@@ -201,7 +200,7 @@ static struct ieee80211_crypto_ops ieee80211_crypt_null = {
.owner = THIS_MODULE,
};
-int __init ieee80211_crypto_init(void)
+int ieee80211_crypto_init(void)
{
int ret = -ENOMEM;
@@ -221,7 +220,7 @@ out:
return ret;
}
-void __exit ieee80211_crypto_deinit(void)
+void ieee80211_crypto_deinit(void)
{
struct list_head *ptr, *n;
struct ieee80211_crypto_alg *alg = NULL;
diff --git a/drivers/staging/rtl8192su/ieee80211/ieee80211_crypt.h b/drivers/staging/rtl8192su/ieee80211/ieee80211_crypt.h
index b58a3bcc0dc..42e52aedd29 100644
--- a/drivers/staging/rtl8192su/ieee80211/ieee80211_crypt.h
+++ b/drivers/staging/rtl8192su/ieee80211/ieee80211_crypt.h
@@ -49,7 +49,7 @@ struct ieee80211_crypto_ops {
* These can be NULL if full MSDU operations are not needed. */
int (*encrypt_msdu)(struct sk_buff *skb, int hdr_len, void *priv);
int (*decrypt_msdu)(struct sk_buff *skb, int keyidx, int hdr_len,
- void *priv);
+ void *priv, struct ieee80211_device* ieee);
int (*set_key)(void *key, int len, u8 *seq, void *priv);
int (*get_key)(void *key, int len, u8 *seq, void *priv);
diff --git a/drivers/staging/rtl8192su/ieee80211/ieee80211_crypt_ccmp.c b/drivers/staging/rtl8192su/ieee80211/ieee80211_crypt_ccmp.c
index 77de957f1b1..caee44ba3bc 100644
--- a/drivers/staging/rtl8192su/ieee80211/ieee80211_crypt_ccmp.c
+++ b/drivers/staging/rtl8192su/ieee80211/ieee80211_crypt_ccmp.c
@@ -9,7 +9,6 @@
* more details.
*/
-//#include <linux/config.h>
#include <linux/version.h>
#include <linux/module.h>
#include <linux/init.h>
@@ -131,7 +130,6 @@ static void ccmp_init_blocks(struct crypto_tfm *tfm,
qc_included = ((WLAN_FC_GET_TYPE(fc) == IEEE80211_FTYPE_DATA) &&
(WLAN_FC_GET_STYPE(fc) & 0x08));
*/
- // fixed by David :2006.9.6
qc_included = ((WLAN_FC_GET_TYPE(fc) == IEEE80211_FTYPE_DATA) &&
(WLAN_FC_GET_STYPE(fc) & 0x80));
aad_len = 22;
@@ -210,7 +208,6 @@ static int ieee80211_ccmp_encrypt(struct sk_buff *skb, int hdr_len, void *priv)
pos = skb_push(skb, CCMP_HDR_LEN);
memmove(pos, pos + CCMP_HDR_LEN, hdr_len);
pos += hdr_len;
-// mic = skb_put(skb, CCMP_MIC_LEN);
i = CCMP_PN_LEN - 1;
while (i >= 0) {
@@ -240,7 +237,6 @@ static int ieee80211_ccmp_encrypt(struct sk_buff *skb, int hdr_len, void *priv)
u8 *e = key->tx_e;
u8 *s0 = key->tx_s0;
- //mic is moved to here by john
mic = skb_put(skb, CCMP_MIC_LEN);
ccmp_init_blocks(key->tfm, hdr, key->tx_pn, data_len, b0, b, s0);
@@ -445,7 +441,6 @@ static char * ieee80211_ccmp_print_stats(char *p, void *priv)
void ieee80211_ccmp_null(void)
{
-// printk("============>%s()\n", __FUNCTION__);
return;
}
@@ -470,7 +465,7 @@ int __init ieee80211_crypto_ccmp_init(void)
return ieee80211_register_crypto_ops(&ieee80211_crypt_ccmp);
}
-void __exit ieee80211_crypto_ccmp_exit(void)
+void ieee80211_crypto_ccmp_exit(void)
{
ieee80211_unregister_crypto_ops(&ieee80211_crypt_ccmp);
}
diff --git a/drivers/staging/rtl8192su/ieee80211/ieee80211_crypt_tkip.c b/drivers/staging/rtl8192su/ieee80211/ieee80211_crypt_tkip.c
index ade5f6f1366..5ab94a9665e 100644
--- a/drivers/staging/rtl8192su/ieee80211/ieee80211_crypt_tkip.c
+++ b/drivers/staging/rtl8192su/ieee80211/ieee80211_crypt_tkip.c
@@ -9,7 +9,6 @@
* more details.
*/
-//#include <linux/config.h>
#include <linux/version.h>
#include <linux/module.h>
#include <linux/init.h>
@@ -43,6 +42,7 @@ struct ieee80211_tkip_data {
u32 rx_iv32;
u16 rx_iv16;
+ bool initialized;
u16 rx_ttak[5];
int rx_phase1_done;
u32 rx_iv32_new;
@@ -433,8 +433,8 @@ static int ieee80211_tkip_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
if (!tcb_desc->bHwSec)
{
- if (iv32 < tkey->rx_iv32 ||
- (iv32 == tkey->rx_iv32 && iv16 <= tkey->rx_iv16)) {
+ if ((iv32 < tkey->rx_iv32 ||
+ (iv32 == tkey->rx_iv32 && iv16 <= tkey->rx_iv16))&&tkey->initialized) {
if (net_ratelimit()) {
printk(KERN_DEBUG "TKIP: replay detected: STA=%pM"
" previous TSC %08x%04x received TSC "
@@ -444,6 +444,7 @@ static int ieee80211_tkip_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
tkey->dot11RSNAStatsTKIPReplays++;
return -4;
}
+ tkey->initialized = true;
if (iv32 != tkey->rx_iv32 || !tkey->rx_phase1_done) {
tkip_mixing_phase1(tkey->rx_ttak, tkey->key, hdr->addr2, iv32);
@@ -452,10 +453,8 @@ static int ieee80211_tkip_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
tkip_mixing_phase2(rc4key, tkey->key, tkey->rx_ttak, iv16);
plen = skb->len - hdr_len - 12;
-
+ sg_init_one(&sg, pos, plen+4);
crypto_blkcipher_setkey(tkey->rx_tfm_arc4, rc4key, 16);
- sg_init_one(&sg, pos, plen + 4);
-
if (crypto_blkcipher_decrypt(&desc, &sg, &sg, plen + 4)) {
if (net_ratelimit()) {
printk(KERN_DEBUG ": TKIP: failed to decrypt "
@@ -571,12 +570,9 @@ static int ieee80211_michael_mic_add(struct sk_buff *skb, int hdr_len, void *pri
michael_mic_hdr(skb, tkey->tx_hdr);
- // { david, 2006.9.1
- // fix the wpa process with wmm enabled.
if(IEEE80211_QOS_HAS_SEQ(le16_to_cpu(hdr->frame_ctl))) {
tkey->tx_hdr[12] = *(skb->data + hdr_len - 2) & 0x07;
}
- // }
pos = skb_put(skb, 8);
if (michael_mic(tkey->tx_tfm_michael, &tkey->key[16], tkey->tx_hdr,
@@ -608,7 +604,7 @@ static void ieee80211_michael_mic_failure(struct net_device *dev,
}
static int ieee80211_michael_mic_verify(struct sk_buff *skb, int keyidx,
- int hdr_len, void *priv)
+ int hdr_len, void *priv, struct ieee80211_device* ieee)
{
struct ieee80211_tkip_data *tkey = priv;
u8 mic[8];
@@ -620,12 +616,9 @@ static int ieee80211_michael_mic_verify(struct sk_buff *skb, int keyidx,
return -1;
michael_mic_hdr(skb, tkey->rx_hdr);
- // { david, 2006.9.1
- // fix the wpa process with wmm enabled.
if(IEEE80211_QOS_HAS_SEQ(le16_to_cpu(hdr->frame_ctl))) {
tkey->rx_hdr[12] = *(skb->data + hdr_len - 2) & 0x07;
}
- // }
if (michael_mic(tkey->rx_tfm_michael, &tkey->key[24], tkey->rx_hdr,
skb->data + hdr_len, skb->len - 8 - hdr_len, mic))
@@ -637,9 +630,14 @@ static int ieee80211_michael_mic_verify(struct sk_buff *skb, int keyidx,
"MSDU from %pM keyidx=%d\n",
skb->dev ? skb->dev->name : "N/A", hdr->addr2,
keyidx);
- if (skb->dev)
+ printk("%d, force_mic_error = %d\n", (memcmp(mic, skb->data + skb->len - 8, 8) != 0),\
+ ieee->force_mic_error);
+ if (skb->dev) {
+ printk("skb->dev != NULL\n");
ieee80211_michael_mic_failure(skb->dev, hdr, keyidx);
+ }
tkey->dot11RSNAStatsTKIPLocalMICFailures++;
+ ieee->force_mic_error = false;
return -1;
}
@@ -762,18 +760,17 @@ static struct ieee80211_crypto_ops ieee80211_crypt_tkip = {
.owner = THIS_MODULE,
};
-int __init ieee80211_crypto_tkip_init(void)
+int ieee80211_crypto_tkip_init(void)
{
return ieee80211_register_crypto_ops(&ieee80211_crypt_tkip);
}
-void __exit ieee80211_crypto_tkip_exit(void)
+void ieee80211_crypto_tkip_exit(void)
{
ieee80211_unregister_crypto_ops(&ieee80211_crypt_tkip);
}
void ieee80211_tkip_null(void)
{
-// printk("============>%s()\n", __FUNCTION__);
return;
}
diff --git a/drivers/staging/rtl8192su/ieee80211/ieee80211_crypt_wep.c b/drivers/staging/rtl8192su/ieee80211/ieee80211_crypt_wep.c
index a1c0a59122b..5219bfd4ea8 100644
--- a/drivers/staging/rtl8192su/ieee80211/ieee80211_crypt_wep.c
+++ b/drivers/staging/rtl8192su/ieee80211/ieee80211_crypt_wep.c
@@ -9,7 +9,6 @@
* more details.
*/
-//#include <linux/config.h>
#include <linux/version.h>
#include <linux/module.h>
#include <linux/init.h>
@@ -279,18 +278,17 @@ static struct ieee80211_crypto_ops ieee80211_crypt_wep = {
.owner = THIS_MODULE,
};
-int __init ieee80211_crypto_wep_init(void)
+int ieee80211_crypto_wep_init(void)
{
return ieee80211_register_crypto_ops(&ieee80211_crypt_wep);
}
-void __exit ieee80211_crypto_wep_exit(void)
+void ieee80211_crypto_wep_exit(void)
{
ieee80211_unregister_crypto_ops(&ieee80211_crypt_wep);
}
void ieee80211_wep_null(void)
{
-// printk("============>%s()\n", __FUNCTION__);
return;
}
diff --git a/drivers/staging/rtl8192su/ieee80211/ieee80211_module.c b/drivers/staging/rtl8192su/ieee80211/ieee80211_module.c
index a87650a517b..4945b3dbf72 100644
--- a/drivers/staging/rtl8192su/ieee80211/ieee80211_module.c
+++ b/drivers/staging/rtl8192su/ieee80211/ieee80211_module.c
@@ -31,7 +31,6 @@
*******************************************************************************/
#include <linux/compiler.h>
-//#include <linux/config.h>
#include <linux/errno.h>
#include <linux/if_arp.h>
#include <linux/in6.h>
@@ -142,7 +141,6 @@ struct net_device *alloc_ieee80211(int sizeof_priv)
spin_lock_init(&ieee->wpax_suitlist_lock);
spin_lock_init(&ieee->bw_spinlock);
spin_lock_init(&ieee->reorder_spinlock);
- //added by WB
atomic_set(&(ieee->atm_chnlop), 0);
atomic_set(&(ieee->atm_swbw), 0);
@@ -153,7 +151,6 @@ struct net_device *alloc_ieee80211(int sizeof_priv)
ieee->privacy_invoked = 0;
ieee->ieee802_1x = 1;
ieee->raw_tx = 0;
- //ieee->hwsec_support = 1; //default support hw security. //use module_param instead.
ieee->hwsec_active = 0; //disable hwsec, switch it on when necessary.
ieee80211_softmac_init(ieee);
@@ -196,8 +193,6 @@ void free_ieee80211(struct net_device *dev)
{
struct ieee80211_device *ieee = netdev_priv(dev);
int i;
- //struct list_head *p, *q;
-// del_timer_sync(&ieee->SwBwTimer);
#if 1
if (ieee->pHTInfo != NULL)
{
@@ -228,23 +223,6 @@ void free_ieee80211(struct net_device *dev)
u32 ieee80211_debug_level = 0;
static int debug = \
- // IEEE80211_DL_INFO |
- // IEEE80211_DL_WX |
- // IEEE80211_DL_SCAN |
- // IEEE80211_DL_STATE |
- // IEEE80211_DL_MGMT |
- // IEEE80211_DL_FRAG |
- // IEEE80211_DL_EAP |
- // IEEE80211_DL_DROP |
- // IEEE80211_DL_TX |
- // IEEE80211_DL_RX |
- //IEEE80211_DL_QOS |
- // IEEE80211_DL_HT |
- // IEEE80211_DL_TS |
-// IEEE80211_DL_BA |
- // IEEE80211_DL_REORDER|
-// IEEE80211_DL_TRACE |
- //IEEE80211_DL_DATA |
IEEE80211_DL_ERR //awayls open this flags to show error out
;
struct proc_dir_entry *ieee80211_proc = NULL;
@@ -282,7 +260,7 @@ static int store_debug_level(struct file *file, const char *buffer,
return strnlen(buf, count);
}
-int __init ieee80211_debug_init(void)
+int ieee80211_debug_init(void)
{
struct proc_dir_entry *e;
@@ -308,7 +286,7 @@ int __init ieee80211_debug_init(void)
return 0;
}
-void __exit ieee80211_debug_exit(void)
+void ieee80211_debug_exit(void)
{
if (ieee80211_proc) {
remove_proc_entry("debug_level", ieee80211_proc);
diff --git a/drivers/staging/rtl8192su/ieee80211/ieee80211_r8192s.h b/drivers/staging/rtl8192su/ieee80211/ieee80211_r8192s.h
index 1824cda790d..7e7fbb26980 100644
--- a/drivers/staging/rtl8192su/ieee80211/ieee80211_r8192s.h
+++ b/drivers/staging/rtl8192su/ieee80211/ieee80211_r8192s.h
@@ -339,28 +339,39 @@ enum {
};
/* Firmware related CMD IO. */
-typedef enum _FW_CMD_IO_TYPE {
- FW_CMD_DIG_ENABLE = 0, /* for DIG DM */
+typedef enum _FW_CMD_IO_TYPE{
+ FW_CMD_DIG_ENABLE = 0, /* for DIG DM */
FW_CMD_DIG_DISABLE = 1,
FW_CMD_DIG_HALT = 2,
FW_CMD_DIG_RESUME = 3,
- FW_CMD_HIGH_PWR_ENABLE = 4, /* for High Power DM */
+ FW_CMD_HIGH_PWR_ENABLE = 4, /* for DIG DM */
FW_CMD_HIGH_PWR_DISABLE = 5,
- FW_CMD_RA_RESET = 6, /* for Rate adaptive DM */
- FW_CMD_RA_ACTIVE = 7,
- FW_CMD_RA_REFRESH_N = 8,
- FW_CMD_RA_REFRESH_BG = 9,
- FW_CMD_IQK_ENABLE = 10, /* for FW supported IQK */
- FW_CMD_TXPWR_TRACK_ENABLE = 11, /* Tx power tracking switch */
- FW_CMD_TXPWR_TRACK_DISABLE = 12,/* Tx power tracking switch */
- FW_CMD_PAUSE_DM_BY_SCAN = 13,
- FW_CMD_RESUME_DM_BY_SCAN = 14,
- FW_CMD_MID_HIGH_PWR_ENABLE = 15,
+ FW_CMD_RA_RESET = 6, /* for DIG DM */
+ FW_CMD_RA_ACTIVE= 7,
+ FW_CMD_RA_REFRESH_N= 8,
+ FW_CMD_RA_REFRESH_BG= 9,
+ FW_CMD_RA_INIT= 10, /* for FW supported IQK */
+ FW_CMD_IQK_ENABLE = 11, /* Tx power tracking switch */
+ FW_CMD_TXPWR_TRACK_ENABLE = 12, /* Tx power tracking switch */
+ FW_CMD_TXPWR_TRACK_DISABLE = 13,
+ FW_CMD_TXPWR_TRACK_THERMAL = 14,
+ FW_CMD_PAUSE_DM_BY_SCAN = 15,
/* indicate firmware that driver enters LPS, for PS-Poll hardware bug */
- FW_CMD_LPS_ENTER = 16,
+ FW_CMD_RESUME_DM_BY_SCAN = 16,
/* indicate firmware that driver leave LPS */
- FW_CMD_LPS_LEAVE = 17,
-} FW_CMD_IO_TYPE;
+ FW_CMD_RA_REFRESH_N_COMB = 17,
+ FW_CMD_RA_REFRESH_BG_COMB = 18,
+ FW_CMD_ANTENNA_SW_ENABLE = 19,
+ FW_CMD_ANTENNA_SW_DISABLE = 20,
+ FW_CMD_TX_FEEDBACK_CCX_ENABLE = 21,
+ FW_CMD_LPS_ENTER = 22,
+ FW_CMD_LPS_LEAVE = 23,
+ FW_CMD_DIG_MODE_SS = 24,
+ FW_CMD_DIG_MODE_FA = 25,
+ FW_CMD_ADD_A2_ENTRY = 26,
+ FW_CMD_CTRL_DM_BY_DRIVER = 27,
+ FW_CMD_CTRL_DM_BY_DRIVER_NEW = 28,
+}FW_CMD_IO_TYPE,*PFW_CMD_IO_TYPE;
#define RT_MAX_LD_SLOT_NUM 10
struct rt_link_detect {
diff --git a/drivers/staging/rtl8192su/ieee80211/ieee80211_rx.c b/drivers/staging/rtl8192su/ieee80211/ieee80211_rx.c
index 1f2bc7ac6f7..09a02f7e39f 100644
--- a/drivers/staging/rtl8192su/ieee80211/ieee80211_rx.c
+++ b/drivers/staging/rtl8192su/ieee80211/ieee80211_rx.c
@@ -360,7 +360,7 @@ ieee80211_rx_frame_decrypt_msdu(struct ieee80211_device* ieee, struct sk_buff *s
hdrlen = ieee80211_get_hdrlen(le16_to_cpu(hdr->frame_ctl));
atomic_inc(&crypt->refcnt);
- res = crypt->ops->decrypt_msdu(skb, keyidx, hdrlen, crypt->priv);
+ res = crypt->ops->decrypt_msdu(skb, keyidx, hdrlen, crypt->priv,ieee);
atomic_dec(&crypt->refcnt);
if (res < 0) {
printk(KERN_DEBUG "%s: MSDU decryption/MIC verification failed"
diff --git a/drivers/staging/rtl8192su/ieee80211/ieee80211_softmac.c b/drivers/staging/rtl8192su/ieee80211/ieee80211_softmac.c
index 4f1f2f08b2d..02850479dd6 100644
--- a/drivers/staging/rtl8192su/ieee80211/ieee80211_softmac.c
+++ b/drivers/staging/rtl8192su/ieee80211/ieee80211_softmac.c
@@ -160,7 +160,6 @@ void enqueue_mgmt(struct ieee80211_device *ieee, struct sk_buff *skb)
ieee->mgmt_queue_head = nh;
ieee->mgmt_queue_ring[nh] = skb;
- //return 0;
}
struct sk_buff *dequeue_mgmt(struct ieee80211_device *ieee)
@@ -183,19 +182,53 @@ void init_mgmt_queue(struct ieee80211_device *ieee)
ieee->mgmt_queue_tail = ieee->mgmt_queue_head = 0;
}
+u8
+MgntQuery_TxRateExcludeCCKRates(struct ieee80211_device *ieee)
+{
+ u16 i;
+ u8 QueryRate = 0;
+ u8 BasicRate;
+
+
+ for( i = 0; i < ieee->current_network.rates_len; i++)
+ {
+ BasicRate = ieee->current_network.rates[i]&0x7F;
+ if(!ieee80211_is_cck_rate(BasicRate))
+ {
+ if(QueryRate == 0)
+ {
+ QueryRate = BasicRate;
+ }
+ else
+ {
+ if(BasicRate < QueryRate)
+ {
+ QueryRate = BasicRate;
+ }
+ }
+ }
+ }
+
+ if(QueryRate == 0)
+ {
+ QueryRate = 12;
+ printk("No BasicRate found!!\n");
+ }
+ return QueryRate;
+}
u8 MgntQuery_MgntFrameTxRate(struct ieee80211_device *ieee)
{
PRT_HIGH_THROUGHPUT pHTInfo = ieee->pHTInfo;
u8 rate;
- // 2008/01/25 MH For broadcom, MGNT frame set as OFDM 6M.
- if(pHTInfo->IOTAction & HT_IOT_ACT_MGNT_USE_CCK_6M)
- rate = 0x0c;
+ if(pHTInfo->IOTAction & HT_IOT_ACT_WA_IOT_Broadcom)
+ {
+ rate = MgntQuery_TxRateExcludeCCKRates(ieee);
+ }
else
rate = ieee->basic_rate & 0x7f;
if(rate == 0){
- // 2005.01.26, by rcnjko.
if(ieee->mode == IEEE_A||
ieee->mode== IEEE_N_5G||
(ieee->mode== IEEE_N_24G&&!pHTInfo->bCurSuppCCK))
@@ -203,17 +236,6 @@ u8 MgntQuery_MgntFrameTxRate(struct ieee80211_device *ieee)
else
rate = 0x02;
}
-
- /*
- // Data rate of ProbeReq is already decided. Annie, 2005-03-31
- if( pMgntInfo->bScanInProgress || (pMgntInfo->bDualModeScanStep!=0) )
- {
- if(pMgntInfo->dot11CurrentWirelessMode==WIRELESS_MODE_A)
- rate = 0x0c;
- else
- rate = 0x02;
- }
- */
return rate;
}
@@ -251,9 +273,7 @@ inline void softmac_mgmt_xmit(struct sk_buff *skb, struct ieee80211_device *ieee
ieee->seq_ctrl[0]++;
/* avoid watchdog triggers */
- // ieee->dev->trans_start = jiffies;
ieee->softmac_data_hard_start_xmit(skb,ieee->dev,ieee->basic_rate);
- //dev_kfree_skb_any(skb);//edit by thomas
}
spin_unlock_irqrestore(&ieee->lock, flags);
@@ -279,9 +299,7 @@ inline void softmac_mgmt_xmit(struct sk_buff *skb, struct ieee80211_device *ieee
printk("%s():insert to waitqueue!\n",__FUNCTION__);
skb_queue_tail(&ieee->skb_waitQ[tcb_desc->queue_index], skb);
} else {
- //printk("TX packet!\n");
ieee->softmac_hard_start_xmit(skb,ieee->dev);
- //dev_kfree_skb_any(skb);//edit by thomas
}
spin_unlock_irqrestore(&ieee->mgmt_tx_lock, flags);
}
@@ -293,16 +311,24 @@ inline void softmac_ps_mgmt_xmit(struct sk_buff *skb, struct ieee80211_device *i
short single = ieee->softmac_features & IEEE_SOFTMAC_SINGLE_QUEUE;
struct ieee80211_hdr_3addr *header =
(struct ieee80211_hdr_3addr *) skb->data;
+ u16 fc,type,stype;
cb_desc *tcb_desc = (cb_desc *)(skb->cb + 8);
+ fc = header->frame_control;
+ type = WLAN_FC_GET_TYPE(fc);
+ stype = WLAN_FC_GET_STYPE(fc);
+
+
+ if(stype != IEEE80211_STYPE_PSPOLL)
tcb_desc->queue_index = MGNT_QUEUE;
+ else
+ tcb_desc->queue_index = HIGH_QUEUE;
tcb_desc->data_rate = MgntQuery_MgntFrameTxRate(ieee);
tcb_desc->RATRIndex = 7;
tcb_desc->bTxDisableRateFallBack = 1;
tcb_desc->bTxUseDriverAssingedRate = 1;
- //printk("=============>%s()\n", __FUNCTION__);
if(single){
-
+ if(!(type == IEEE80211_FTYPE_CTL)) {
header->seq_ctrl = cpu_to_le16(ieee->seq_ctrl[0] << 4);
if (ieee->seq_ctrl[0] == 0xFFF)
@@ -310,12 +336,12 @@ inline void softmac_ps_mgmt_xmit(struct sk_buff *skb, struct ieee80211_device *i
else
ieee->seq_ctrl[0]++;
+ }
/* avoid watchdog triggers */
- // ieee->dev->trans_start = jiffies;
ieee->softmac_data_hard_start_xmit(skb,ieee->dev,ieee->basic_rate);
}else{
-
+ if(!(type == IEEE80211_FTYPE_CTL)) {
header->seq_ctrl = cpu_to_le16(ieee->seq_ctrl[0] << 4);
if (ieee->seq_ctrl[0] == 0xFFF)
@@ -323,10 +349,10 @@ inline void softmac_ps_mgmt_xmit(struct sk_buff *skb, struct ieee80211_device *i
else
ieee->seq_ctrl[0]++;
+ }
ieee->softmac_hard_start_xmit(skb,ieee->dev);
}
- //dev_kfree_skb_any(skb);//edit by thomas
}
inline struct sk_buff *ieee80211_probe_req(struct ieee80211_device *ieee)
@@ -373,24 +399,16 @@ void ieee80211_send_beacon(struct ieee80211_device *ieee)
struct sk_buff *skb;
if(!ieee->ieee_up)
return;
- //unsigned long flags;
skb = ieee80211_get_beacon_(ieee);
if (skb){
softmac_mgmt_xmit(skb, ieee);
ieee->softmac_stats.tx_beacons++;
- //dev_kfree_skb_any(skb);//edit by thomas
}
-// ieee->beacon_timer.expires = jiffies +
-// (MSECS( ieee->current_network.beacon_interval -5));
- //spin_lock_irqsave(&ieee->beacon_lock,flags);
if(ieee->beacon_txing && ieee->ieee_up){
-// if(!timer_pending(&ieee->beacon_timer))
-// add_timer(&ieee->beacon_timer);
mod_timer(&ieee->beacon_timer,jiffies+(MSECS(ieee->current_network.beacon_interval-5)));
}
- //spin_unlock_irqrestore(&ieee->beacon_lock,flags);
}
@@ -414,7 +432,6 @@ void ieee80211_send_probe(struct ieee80211_device *ieee)
if (skb){
softmac_mgmt_xmit(skb, ieee);
ieee->softmac_stats.tx_probe_rq++;
- //dev_kfree_skb_any(skb);//edit by thomas
}
}
@@ -585,12 +602,8 @@ void ieee80211_start_send_beacons(struct ieee80211_device *ieee)
void ieee80211_softmac_stop_scan(struct ieee80211_device *ieee)
{
-// unsigned long flags;
-
- //ieee->sync_scan_hurryup = 1;
down(&ieee->scan_sem);
-// spin_lock_irqsave(&ieee->lock, flags);
ieee->scan_watch_dog = 0;
if (ieee->scanning == 1){
ieee->scanning = 0;
@@ -598,7 +611,6 @@ void ieee80211_softmac_stop_scan(struct ieee80211_device *ieee)
cancel_delayed_work(&ieee->softmac_scan_wq);
}
-// spin_unlock_irqrestore(&ieee->lock, flags);
up(&ieee->scan_sem);
}
@@ -672,7 +684,6 @@ inline struct sk_buff *ieee80211_authentication_req(struct ieee80211_network *be
memcpy(auth->header.addr2, ieee->dev->dev_addr, ETH_ALEN);
memcpy(auth->header.addr3, beacon->bssid, ETH_ALEN);
- //auth->algorithm = ieee->open_wep ? WLAN_AUTH_OPEN : WLAN_AUTH_SHARED_KEY;
if(ieee->auth_mode == 0)
auth->algorithm = WLAN_AUTH_OPEN;
else if(ieee->auth_mode == 1)
@@ -689,6 +700,26 @@ inline struct sk_buff *ieee80211_authentication_req(struct ieee80211_network *be
}
+void constructWMMIE(u8* wmmie, u8* wmm_len,u8 oui_subtype)
+{
+ u8 szQoSOUI[] ={221, 0, 0x00, 0x50, 0xf2, 0x02, 0, 1};
+
+ if (oui_subtype == OUI_SUBTYPE_QOS_CAPABI)
+ {
+ szQoSOUI[0] = 46;
+ szQoSOUI[1] = *wmm_len;
+ memcpy(wmmie,szQoSOUI,3);
+ *wmm_len = 3;
+ }
+ else
+ {
+ szQoSOUI[1] = *wmm_len + 6;
+ szQoSOUI[6] = oui_subtype;
+ memcpy(wmmie, szQoSOUI, 8);
+ *(wmmie+8) = 0;
+ *wmm_len = 9;
+ }
+}
static struct sk_buff* ieee80211_probe_resp(struct ieee80211_device *ieee, u8 *dest)
{
@@ -707,14 +738,18 @@ static struct sk_buff* ieee80211_probe_resp(struct ieee80211_device *ieee, u8 *d
int wpa_ie_len = ieee->wpa_ie_len;
u8 erpinfo_content = 0;
- u8* tmp_ht_cap_buf;
+ u8* tmp_ht_cap_buf=NULL;
u8 tmp_ht_cap_len=0;
- u8* tmp_ht_info_buf;
+ u8* tmp_ht_info_buf=NULL;
u8 tmp_ht_info_len=0;
PRT_HIGH_THROUGHPUT pHTInfo = ieee->pHTInfo;
u8* tmp_generic_ie_buf=NULL;
u8 tmp_generic_ie_len=0;
+
+ u8 wmmie[9] = {0};
+ u8 wmm_len = 0;
+
if(rate_ex_len > 0) rate_ex_len+=2;
if(ieee->current_network.capability & WLAN_CAPABILITY_IBSS)
@@ -722,7 +757,7 @@ static struct sk_buff* ieee80211_probe_resp(struct ieee80211_device *ieee, u8 *d
else
atim_len = 0;
-#if 1
+#if 0
if(ieee80211_is_54g(ieee->current_network))
erp_len = 3;
else
@@ -747,22 +782,35 @@ static struct sk_buff* ieee80211_probe_resp(struct ieee80211_device *ieee, u8 *d
((0 == strcmp(crypt->ops->name, "WEP") || wpa_ie_len));
//HT ralated element
#if 1
- tmp_ht_cap_buf =(u8*) &(ieee->pHTInfo->SelfHTCap);
- tmp_ht_cap_len = sizeof(ieee->pHTInfo->SelfHTCap);
- tmp_ht_info_buf =(u8*) &(ieee->pHTInfo->SelfHTInfo);
- tmp_ht_info_len = sizeof(ieee->pHTInfo->SelfHTInfo);
- HTConstructCapabilityElement(ieee, tmp_ht_cap_buf, &tmp_ht_cap_len,encrypt);
- HTConstructInfoElement(ieee,tmp_ht_info_buf,&tmp_ht_info_len, encrypt);
-
-
- if(pHTInfo->bRegRT2RTAggregation)
- {
- tmp_generic_ie_buf = ieee->pHTInfo->szRT2RTAggBuffer;
- tmp_generic_ie_len = sizeof(ieee->pHTInfo->szRT2RTAggBuffer);
- HTConstructRT2RTAggElement(ieee, tmp_generic_ie_buf, &tmp_generic_ie_len);
- }
-// printk("===============>tmp_ht_cap_len is %d,tmp_ht_info_len is %d, tmp_generic_ie_len is %d\n",tmp_ht_cap_len,tmp_ht_info_len,tmp_generic_ie_len);
+ if(ieee->pHTInfo->bCurrentHTSupport){
+ tmp_ht_cap_buf =(u8*) &(ieee->pHTInfo->SelfHTCap);
+ tmp_ht_cap_len = sizeof(ieee->pHTInfo->SelfHTCap);
+ tmp_ht_info_buf =(u8*) &(ieee->pHTInfo->SelfHTInfo);
+ tmp_ht_info_len = sizeof(ieee->pHTInfo->SelfHTInfo);
+
+ HTConstructCapabilityElement(ieee, tmp_ht_cap_buf, &tmp_ht_cap_len,encrypt);
+
+ HTConstructInfoElement(ieee,tmp_ht_info_buf,&tmp_ht_info_len, encrypt);
+
+
+ if(pHTInfo->bRegRT2RTAggregation)
+ {
+ tmp_generic_ie_buf = ieee->pHTInfo->szRT2RTAggBuffer;
+ tmp_generic_ie_len = sizeof(ieee->pHTInfo->szRT2RTAggBuffer);
+ HTConstructRT2RTAggElement(ieee, tmp_generic_ie_buf, &tmp_generic_ie_len);
+ }
+ }
#endif
+
+ if(ieee->qos_support){
+
+ if(ieee->iw_mode == IW_MODE_ADHOC)
+ {
+ wmm_len = 1;
+ constructWMMIE(wmmie,&wmm_len,OUI_SUBTYPE_WMM_INFO);
+ }
+ }
+
beacon_size = sizeof(struct ieee80211_probe_response)+2+
ssid_len
+3 //channel
@@ -825,7 +873,6 @@ static struct sk_buff* ieee80211_probe_resp(struct ieee80211_device *ieee, u8 *d
u16 val16;
*(tag++) = MFIE_TYPE_IBSS_SET;
*(tag++) = 2;
- //*((u16*)(tag)) = cpu_to_le16(ieee->current_network.atim_window);
val16 = cpu_to_le16(ieee->current_network.atim_window);
memcpy((u8 *)tag, (u8 *)&val16, 2);
tag+=2;
@@ -854,7 +901,6 @@ static struct sk_buff* ieee80211_probe_resp(struct ieee80211_device *ieee, u8 *d
tag += wpa_ie_len;
}
- //skb->dev = ieee->dev;
return skb;
}
@@ -996,19 +1042,39 @@ void ieee80211_resp_to_probe(struct ieee80211_device *ieee, u8 *dest)
}
+inline int SecIsInPMKIDList(struct ieee80211_device *ieee, u8 *bssid)
+{
+ int i = 0;
+
+ do
+ {
+ if ((ieee->PMKIDList[i].bUsed) && (memcmp(ieee->PMKIDList[i].Bssid, bssid, ETH_ALEN) == 0))
+ {
+ break;
+ }
+ else
+ {
+ i++;
+ }
+ } while (i < NUM_PMKID_CACHE);
+
+ if (i == NUM_PMKID_CACHE)
+ {
+ i = -1;
+ }
+ else
+ {
+ }
+
+ return (i);
+
+}
inline struct sk_buff *ieee80211_association_req(struct ieee80211_network *beacon,struct ieee80211_device *ieee)
{
struct sk_buff *skb;
- //unsigned long flags;
struct ieee80211_assoc_request_frame *hdr;
u8 *tag;//,*rsn_ie;
- //short info_addr = 0;
- //int i;
- //u16 suite_count = 0;
- //u8 suit_select = 0;
- //unsigned int wpa_len = beacon->wpa_ie_len;
- //for HT
u8* ht_cap_buf = NULL;
u8 ht_cap_len=0;
u8* realtek_ie_buf=NULL;
@@ -1019,6 +1085,7 @@ inline struct sk_buff *ieee80211_association_req(struct ieee80211_network *beaco
unsigned int cxvernum_ie_len=0;
struct ieee80211_crypt_data* crypt;
int encrypt;
+ int PMKCacheIdx;
unsigned int rate_len = ieee80211_MFIE_rate_len(ieee);
unsigned int wmm_info_len = beacon->qos_data.supported?9:0;
@@ -1060,6 +1127,14 @@ inline struct sk_buff *ieee80211_association_req(struct ieee80211_network *beaco
{
cxvernum_ie_len = 5+2;
}
+
+ PMKCacheIdx = SecIsInPMKIDList(ieee, ieee->current_network.bssid);
+ if (PMKCacheIdx >= 0)
+ {
+ wpa_ie_len += 18;
+ printk("[PMK cache]: WPA2 IE length: %x\n", wpa_ie_len);
+ }
+
len = sizeof(struct ieee80211_assoc_request_frame)+ 2
+ beacon->ssid_len//essid tagged val
+ rate_len//rates tagged val
@@ -1187,6 +1262,13 @@ inline struct sk_buff *ieee80211_association_req(struct ieee80211_network *beaco
tag = skb_put(skb, wpa_ie_len);
if (wpa_ie_len){
memcpy(tag, ieee->wpa_ie, ieee->wpa_ie_len);
+ if (PMKCacheIdx >= 0)
+ {
+ tag = skb_put(skb, 18);
+ *tag = 1;
+ *(tag + 1) = 0;
+ memcpy((tag + 2), &ieee->PMKIDList[PMKCacheIdx].PMKID, 16);
+ }
}
tag = skb_put(skb,wmm_info_len);
@@ -1215,8 +1297,6 @@ inline struct sk_buff *ieee80211_association_req(struct ieee80211_network *beaco
memcpy(tag, realtek_ie_buf,realtek_ie_len -2 );
}
}
-// printk("<=====%s(), %p, %p\n", __FUNCTION__, ieee->dev, ieee->dev->dev_addr);
-// IEEE80211_DEBUG_DATA(IEEE80211_DL_DATA, skb->data, skb->len);
return skb;
}
@@ -1271,7 +1351,6 @@ void ieee80211_associate_step1(struct ieee80211_device *ieee)
else{
ieee->state = IEEE80211_ASSOCIATING_AUTHENTICATING ;
IEEE80211_DEBUG_MGMT("Sending authentication request\n");
- //printk(KERN_WARNING "Sending authentication request\n");
softmac_mgmt_xmit(skb, ieee);
//BUGON when you try to add_timer twice, using mod_timer may be better, john0709
if(!timer_pending(&ieee->associate_timer)){
@@ -1287,7 +1366,6 @@ void ieee80211_rtl_auth_challenge(struct ieee80211_device *ieee, u8 *challenge,
u8 *c;
struct sk_buff *skb;
struct ieee80211_network *beacon = &ieee->current_network;
-// int hlen = sizeof(struct ieee80211_authentication);
ieee->associate_seq++;
ieee->softmac_stats.tx_auth_rq++;
@@ -1307,7 +1385,6 @@ void ieee80211_rtl_auth_challenge(struct ieee80211_device *ieee, u8 *challenge,
softmac_mgmt_xmit(skb, ieee);
mod_timer(&ieee->associate_timer, jiffies + (HZ/2));
- //dev_kfree_skb_any(skb);//edit by thomas
}
kfree(challenge);
}
@@ -1328,7 +1405,6 @@ void ieee80211_associate_step2(struct ieee80211_device *ieee)
else{
softmac_mgmt_xmit(skb, ieee);
mod_timer(&ieee->associate_timer, jiffies + (HZ/2));
- //dev_kfree_skb_any(skb);//edit by thomas
}
}
@@ -1356,7 +1432,6 @@ void ieee80211_associate_complete_wq(struct work_struct *work)
{
printk("Successfully associated, ht not enabled(%d, %d)\n", ieee->pHTInfo->bCurrentHTSupport, ieee->pHTInfo->bEnableHT);
memset(ieee->dot11HTOperationalRateSet, 0, 16);
- //HTSetConnectBwMode(ieee, HT_CHANNEL_WIDTH_20, HT_EXTCHNL_OFFSET_NO_EXT);
}
ieee->LinkDetectInfo.SlotNum = 2 * (1 + ieee->current_network.beacon_interval/500);
// To prevent the immediately calling watch_dog after association.
@@ -1388,7 +1463,6 @@ void ieee80211_associate_complete(struct ieee80211_device *ieee)
del_timer_sync(&ieee->associate_timer);
ieee->state = IEEE80211_LINKED;
- //ieee->UpdateHalRATRTableHandler(dev, ieee->dot11HTOperationalRateSet);
queue_work(ieee->wq, &ieee->associate_complete_wq);
}
@@ -1404,9 +1478,14 @@ void ieee80211_associate_procedure_wq(struct work_struct *work)
ieee80211_stop_scan(ieee);
printk("===>%s(), chan:%d\n", __FUNCTION__, ieee->current_network.channel);
- //ieee->set_chan(ieee->dev, ieee->current_network.channel);
HTSetConnectBwMode(ieee, HT_CHANNEL_WIDTH_20, HT_EXTCHNL_OFFSET_NO_EXT);
+ if(ieee->eRFPowerState == eRfOff)
+ {
+ printk("=============>%s():Rf state is eRfOff, schedule ipsleave wq again,return\n",__FUNCTION__);
+ up(&ieee->wx_sem);
+ return;
+ }
ieee->associate_seq = 1;
ieee80211_associate_step1(ieee);
@@ -1432,14 +1511,16 @@ inline void ieee80211_softmac_new_net(struct ieee80211_device *ieee, struct ieee
if ((ieee->iw_mode == IW_MODE_ADHOC) && !(net->capability & WLAN_CAPABILITY_IBSS))
return;
+ if ((ieee->iw_mode == IW_MODE_ADHOC) && (net->channel > ieee->ibss_maxjoin_chal))
+ return;
if (ieee->iw_mode == IW_MODE_INFRA || ieee->iw_mode == IW_MODE_ADHOC){
/* if the user specified the AP MAC, we need also the essid
* This could be obtained by beacons or, if the network does not
* broadcast it, it can be put manually.
*/
- apset = ieee->wap_set;//(memcmp(ieee->current_network.bssid, zero,ETH_ALEN)!=0 );
- ssidset = ieee->ssid_set;//ieee->current_network.ssid[0] != '\0';
+ apset = ieee->wap_set;
+ ssidset = ieee->ssid_set;
ssidbroad = !(net->ssid_len == 0 || net->ssid[0]== '\0');
apmatch = (memcmp(ieee->current_network.bssid, net->bssid, ETH_ALEN)==0);
ssidmatch = (ieee->current_network.ssid_len == net->ssid_len)&&\
@@ -1480,7 +1561,6 @@ inline void ieee80211_softmac_new_net(struct ieee80211_device *ieee, struct ieee
ieee->AsocRetryCount = 0;
//for HT by amy 080514
if((ieee->current_network.qos_data.supported == 1) &&
- // (ieee->pHTInfo->bEnableHT && ieee->current_network.bssht.bdSupportHT))
ieee->current_network.bssht.bdSupportHT)
/*WB, 2008.09.09:bCurrentHTSupport and bEnableHT two flags are going to put together to check whether we are in HT now, so needn't to check bEnableHT flags here. That's is to say we will set to HT support whenever joined AP has the ability to support HT. And whether we are in HT or not, please check bCurrentHTSupport&&bEnableHT now please.*/
{
@@ -1508,7 +1588,6 @@ inline void ieee80211_softmac_new_net(struct ieee80211_device *ieee, struct ieee
printk(KERN_INFO"Using B rates\n");
}
memset(ieee->dot11HTOperationalRateSet, 0, 16);
- //HTSetConnectBwMode(ieee, HT_CHANNEL_WIDTH_20, HT_EXTCHNL_OFFSET_NO_EXT);
ieee->state = IEEE80211_LINKED;
}
@@ -1598,6 +1677,16 @@ static short probe_rq_parse(struct ieee80211_device *ieee, struct sk_buff *skb,
if (skb->len < sizeof (struct ieee80211_hdr_3addr ))
return -1; /* corrupted */
+ if((memcmp(header->addr3,ieee->current_network.bssid,ETH_ALEN) != 0)&&
+ (memcmp(header->addr3,"\xff\xff\xff\xff\xff\xff",ETH_ALEN) != 0)) {
+ return -1;
+ }
+
+ if(memcmp(header->addr3,ieee->current_network.bssid,ETH_ALEN) == 0) {
+ }
+
+ if(memcmp(header->addr3,"\xff\xff\xff\xff\xff\xff",ETH_ALEN) == 0) {
+ }
memcpy(src,header->addr2, ETH_ALEN);
skbend = (u8*)skb->data + skb->len;
@@ -1615,7 +1704,6 @@ static short probe_rq_parse(struct ieee80211_device *ieee, struct sk_buff *skb,
tag++; /* point to the next tag */
}
- //IEEE80211DMESG("Card MAC address is "MACSTR, MAC2STR(src));
if (ssidlen == 0) return 1;
if (!ssid) return 1; /* ssid not found in tagged param */
@@ -1673,11 +1761,8 @@ ieee80211_rx_probe_rq(struct ieee80211_device *ieee, struct sk_buff *skb)
{
u8 dest[ETH_ALEN];
- //IEEE80211DMESG("Rx probe");
ieee->softmac_stats.rx_probe_rq++;
- //DMESG("Dest is "MACSTR, MAC2STR(dest));
if (probe_rq_parse(ieee, skb, dest)){
- //IEEE80211DMESG("Was for me!");
ieee->softmac_stats.tx_probe_rs++;
ieee80211_resp_to_probe(ieee, dest);
}
@@ -1688,14 +1773,12 @@ ieee80211_rx_auth_rq(struct ieee80211_device *ieee, struct sk_buff *skb)
{
u8 dest[ETH_ALEN];
int status;
- //IEEE80211DMESG("Rx probe");
ieee->softmac_stats.rx_auth_rq++;
status = auth_rq_parse(skb, dest);
if (status != -1) {
ieee80211_resp_to_auth(ieee, status, dest);
}
- //DMESG("Dest is "MACSTR, MAC2STR(dest));
}
@@ -1704,7 +1787,6 @@ ieee80211_rx_assoc_rq(struct ieee80211_device *ieee, struct sk_buff *skb)
{
u8 dest[ETH_ALEN];
- //unsigned long flags;
ieee->softmac_stats.rx_ass_rq++;
if (assoc_rq_parse(skb,dest) != -1){
@@ -1739,7 +1821,6 @@ short ieee80211_sta_ps_sleep(struct ieee80211_device *ieee, u32 *time_h, u32 *ti
return 0;
*/
dtim = ieee->current_network.dtim_data;
- //printk("DTIM\n");
if(!(dtim & IEEE80211_DTIM_VALID))
return 0;
timeout = ieee->current_network.beacon_interval; //should we use ps_timeout value or beacon_interval
@@ -1762,7 +1843,6 @@ short ieee80211_sta_ps_sleep(struct ieee80211_device *ieee, u32 *time_h, u32 *ti
if(time_l){
*time_l = ieee->current_network.last_dtim_sta_time[0]
+ (ieee->current_network.beacon_interval);
- // * ieee->current_network.dtim_period) * 1000;
}
if(time_h){
@@ -1790,7 +1870,6 @@ inline void ieee80211_sta_ps(struct ieee80211_device *ieee)
ieee->iw_mode != IW_MODE_INFRA ||
ieee->state != IEEE80211_LINKED)){
- // #warning CHECK_LOCK_HERE
spin_lock_irqsave(&ieee->mgmt_tx_lock, flags2);
ieee80211_sta_wakeup(ieee, 1);
@@ -1809,7 +1888,6 @@ inline void ieee80211_sta_ps(struct ieee80211_device *ieee)
ieee->enter_sleep_state(ieee->dev,th,tl);
else if(ieee->sta_sleep == 0){
- // printk("send null 1\n");
spin_lock_irqsave(&ieee->mgmt_tx_lock, flags2);
if(ieee->ps_is_queue_empty(ieee->dev)){
@@ -1918,8 +1996,6 @@ void ieee80211_process_action(struct ieee80211_device* ieee, struct sk_buff* skb
ieee80211_rx_DELBA(ieee, skb);
break;
default:
-// if (net_ratelimit())
-// IEEE80211_DEBUG(IEEE80211_DL_BA, "unknown action frame(%d)\n", tmp);
break;
}
return;
@@ -1936,7 +2012,6 @@ ieee80211_rx_frame_softmac(struct ieee80211_device *ieee, struct sk_buff *skb,
int chlen=0;
int aid;
struct ieee80211_assoc_response_frame *assoc_resp;
-// struct ieee80211_info_element *info_element;
bool bSupportNmode = true, bHalfSupportNmode = false; //default support N mode, disable halfNmode
if(!ieee->proto_started)
@@ -2095,8 +2170,6 @@ ieee80211_rx_frame_softmac(struct ieee80211_device *ieee, struct sk_buff *skb,
ieee->softmac_stats.reassoc++;
ieee->is_roaming = true;
ieee80211_disassociate(ieee);
- // notify_wx_assoc_event(ieee);
- //HTSetConnectBwMode(ieee, HT_CHANNEL_WIDTH_20, HT_EXTCHNL_OFFSET_NO_EXT);
RemovePeerTS(ieee, header->addr2);
if(ieee->LedControlHandler != NULL)
ieee->LedControlHandler(ieee->dev, LED_CTL_START_TO_LINK); //added by amy for LED 090318
@@ -2111,7 +2184,6 @@ ieee80211_rx_frame_softmac(struct ieee80211_device *ieee, struct sk_buff *skb,
break;
}
- //dev_kfree_skb_any(skb);
return 0;
}
@@ -2163,22 +2235,16 @@ void ieee80211_softmac_xmit(struct ieee80211_txb *txb, struct ieee80211_device *
/* as for the completion function, it does not need
* to check it any more.
* */
- //printk("error:no descriptor left@queue_index %d, %d, %d\n", queue_index, skb_queue_len(&ieee->skb_waitQ[queue_index]), ieee->check_nic_enough_desc(ieee->dev,queue_index));
- //ieee80211_rtl_stop_queue(ieee);
skb_queue_tail(&ieee->skb_waitQ[queue_index], txb->fragments[i]);
}else{
ieee->softmac_data_hard_start_xmit(
txb->fragments[i],
ieee->dev,ieee->rate);
- //ieee->stats.tx_packets++;
- //ieee->stats.tx_bytes += txb->fragments[i]->len;
- //ieee->dev->trans_start = jiffies;
}
}
#endif
ieee80211_txb_free(txb);
-//exit:
spin_unlock_irqrestore(&ieee->lock,flags);
}
@@ -2197,9 +2263,7 @@ void ieee80211_resume_tx(struct ieee80211_device *ieee)
ieee->softmac_data_hard_start_xmit(
ieee->tx_pending.txb->fragments[i],
ieee->dev,ieee->rate);
- //(i+1)<ieee->tx_pending.txb->nr_frags);
ieee->stats.tx_packets++;
- // ieee->dev->trans_start = jiffies;
}
}
@@ -2249,7 +2313,6 @@ void ieee80211_rtl_wake_queue(struct ieee80211_device *ieee)
ieee->seq_ctrl[0]++;
ieee->softmac_data_hard_start_xmit(skb,ieee->dev,ieee->basic_rate);
- //dev_kfree_skb_any(skb);//edit by thomas
}
}
if (!ieee->queue_stop && ieee->tx_pending.txb)
@@ -2267,15 +2330,12 @@ exit :
void ieee80211_rtl_stop_queue(struct ieee80211_device *ieee)
{
- //unsigned long flags;
- //spin_lock_irqsave(&ieee->lock,flags);
if (! netif_queue_stopped(ieee->dev)){
netif_stop_queue(ieee->dev);
ieee->softmac_stats.swtxstop++;
}
ieee->queue_stop = 1;
- //spin_unlock_irqrestore(&ieee->lock,flags);
}
@@ -2362,7 +2422,7 @@ void ieee80211_start_ibss_wq(struct work_struct *work)
// if((IS_DOT11D_ENABLE(ieee)) && (ieee->state == IEEE80211_NOLINK))
if (ieee->state == IEEE80211_NOLINK)
- ieee->current_network.channel = 6;
+ ieee->current_network.channel = ieee->IbssStartChnl;
/* if not then the state is not linked. Maybe the user swithced to
* ad-hoc mode just after being in monitor mode, or just after
* being very few time in managed mode (so the card have had no
@@ -2509,11 +2569,9 @@ void ieee80211_disassociate(struct ieee80211_device *ieee)
ieee->state = IEEE80211_NOLINK;
ieee->is_set_key = false;
- //LZM for usb dev crash.
- //ieee->link_change(ieee->dev);
queue_delayed_work(ieee->wq, &ieee->link_change_wq, 0);
- //HTSetConnectBwMode(ieee, HT_CHANNEL_WIDTH_20, HT_EXTCHNL_OFFSET_NO_EXT);
+
notify_wx_assoc_event(ieee);
}
@@ -2657,8 +2715,6 @@ void ieee80211_start_protocol(struct ieee80211_device *ieee)
if (ieee->current_network.beacon_interval == 0)
ieee->current_network.beacon_interval = 100;
-// printk("===>%s(), chan:%d\n", __FUNCTION__, ieee->current_network.channel);
-// ieee->set_chan(ieee->dev,ieee->current_network.channel);
for(i = 0; i < 17; i++) {
ieee->last_rxseq_num[i] = -1;
@@ -2721,7 +2777,6 @@ void ieee80211_softmac_init(struct ieee80211_device *ieee)
ieee->Regdot11HTOperationalRateSet[0]= 0xff;//support MCS 0~7
ieee->Regdot11HTOperationalRateSet[1]= 0xff;//support MCS 8~15
ieee->Regdot11HTOperationalRateSet[4]= 0x01;
- //added by amy
ieee->actscanning = false;
ieee->beinretry = false;
ieee->is_set_key = false;
@@ -2891,8 +2946,6 @@ static int ieee80211_wpa_set_auth_algs(struct ieee80211_device *ieee, int value)
if (ieee->set_security)
ieee->set_security(ieee->dev, &sec);
- //else
- // ret = -EOPNOTSUPP;
return ret;
}
@@ -3173,7 +3226,6 @@ int ieee80211_wpa_supplicant_ioctl(struct ieee80211_device *ieee, struct iw_poin
int ret=0;
down(&ieee->wx_sem);
- //IEEE_DEBUG_INFO("wpa_supplicant: len=%d\n", p->length);
if (p->length < sizeof(struct ieee_param) || !p->pointer){
ret = -EINVAL;
diff --git a/drivers/staging/rtl8192su/ieee80211/ieee80211_tx.c b/drivers/staging/rtl8192su/ieee80211/ieee80211_tx.c
index 484c3aba5cb..a6a5d68df3a 100644
--- a/drivers/staging/rtl8192su/ieee80211/ieee80211_tx.c
+++ b/drivers/staging/rtl8192su/ieee80211/ieee80211_tx.c
@@ -32,7 +32,6 @@
******************************************************************************/
#include <linux/compiler.h>
-//#include <linux/config.h>
#include <linux/errno.h>
#include <linux/if_arp.h>
#include <linux/in6.h>
@@ -208,7 +207,6 @@ int ieee80211_encrypt_fragment(
/* To encrypt, frame format is:
* IV (4 bytes), clear payload (including SNAP), ICV (4 bytes) */
- // PR: FIXME: Copied from hostap. Check fragmentation/MSDU/MPDU encryption.
/* Host-based IEEE 802.11 fragmentation for TX is not yet supported, so
* call both MSDU and MPDU encryption functions from here. */
atomic_inc(&crypt->refcnt);
@@ -231,7 +229,6 @@ int ieee80211_encrypt_fragment(
void ieee80211_txb_free(struct ieee80211_txb *txb) {
- //int i;
if (unlikely(!txb))
return;
kfree(txb);
@@ -280,7 +277,6 @@ ieee80211_classify(struct sk_buff *skb, struct ieee80211_network *network)
if (eth->h_proto != htons(ETH_P_IP))
return 0;
-// IEEE80211_DEBUG_DATA(IEEE80211_DL_DATA, skb->data, skb->len);
ip = ip_hdr(skb);
switch (ip->tos & 0xfc) {
@@ -681,10 +677,8 @@ int rtl8192_ieee80211_rtl_xmit(struct sk_buff *skb, struct net_device *dev)
if (encrypt)
fc = IEEE80211_FTYPE_DATA | IEEE80211_FCTL_WEP;
else
-
fc = IEEE80211_FTYPE_DATA;
- //if(ieee->current_network.QoS_Enable)
if(qos_actived)
fc |= IEEE80211_STYPE_QOS_DATA;
else
@@ -765,7 +759,6 @@ int rtl8192_ieee80211_rtl_xmit(struct sk_buff *skb, struct net_device *dev)
txb->encrypted = encrypt;
txb->payload_size = bytes;
- //if (ieee->current_network.QoS_Enable)
if(qos_actived)
{
txb->queue_index = UP2AC(skb->priority);
@@ -812,7 +805,6 @@ int rtl8192_ieee80211_rtl_xmit(struct sk_buff *skb, struct net_device *dev)
/* The last fragment takes the remaining length */
bytes = bytes_last_frag;
}
- //if(ieee->current_network.QoS_Enable)
if(qos_actived)
{
// add 1 only indicate to corresponding seq number control 2006/7/12
@@ -889,7 +881,6 @@ int rtl8192_ieee80211_rtl_xmit(struct sk_buff *skb, struct net_device *dev)
if ( tcb_desc->bMulticast || tcb_desc->bBroadcast)
tcb_desc->data_rate = ieee->basic_rate;
else
- //tcb_desc->data_rate = CURRENT_RATE(ieee->current_network.mode, ieee->rate, ieee->HTCurrentOperaRate);
tcb_desc->data_rate = CURRENT_RATE(ieee->mode, ieee->rate, ieee->HTCurrentOperaRate);
ieee80211_qurey_ShortPreambleMode(ieee, tcb_desc);
ieee80211_tx_query_agg_cap(ieee, txb->fragments[0], tcb_desc);
@@ -897,8 +888,6 @@ int rtl8192_ieee80211_rtl_xmit(struct sk_buff *skb, struct net_device *dev)
ieee80211_query_BandwidthMode(ieee, tcb_desc);
ieee80211_query_protectionmode(ieee, tcb_desc, txb->fragments[0]);
ieee80211_query_seqnum(ieee, txb->fragments[0], header.addr1);
-// IEEE80211_DEBUG_DATA(IEEE80211_DL_DATA, txb->fragments[0]->data, txb->fragments[0]->len);
- //IEEE80211_DEBUG_DATA(IEEE80211_DL_DATA, tcb_desc, sizeof(cb_desc));
#endif
}
spin_unlock_irqrestore(&ieee->lock, flags);
diff --git a/drivers/staging/rtl8192su/ieee80211/ieee80211_wx.c b/drivers/staging/rtl8192su/ieee80211/ieee80211_wx.c
index 2ce5bd543ea..984a3608561 100644
--- a/drivers/staging/rtl8192su/ieee80211/ieee80211_wx.c
+++ b/drivers/staging/rtl8192su/ieee80211/ieee80211_wx.c
@@ -77,7 +77,6 @@ static inline char *rtl819x_translate_scan(struct ieee80211_device *ieee,
/* Add the ESSID */
iwe.cmd = SIOCGIWESSID;
iwe.u.data.flags = 1;
-// if (network->flags & NETWORK_EMPTY_ESSID) {
if (network->ssid_len == 0) {
iwe.u.data.length = sizeof("<hidden>");
start = iwe_stream_add_point(info, start, stop, &iwe, "<hidden>");
@@ -240,9 +239,7 @@ int ieee80211_wx_get_scan(struct ieee80211_device *ieee,
unsigned long flags;
char *ev = extra;
-// char *stop = ev + IW_SCAN_MAX_DATA;
char *stop = ev + wrqu->data.length;//IW_SCAN_MAX_DATA;
- //char *stop = ev + IW_SCAN_MAX_DATA;
int i = 0;
int err = 0;
IEEE80211_DEBUG_WX("Getting scan\n");
@@ -511,7 +508,6 @@ int ieee80211_wx_set_encode_ext(struct ieee80211_device *ieee,
struct ieee80211_security sec = {
.flags = 0,
};
- //printk("======>encoding flag:%x,ext flag:%x, ext alg:%d\n", encoding->flags,ext->ext_flags, ext->alg);
idx = encoding->flags & IW_ENCODE_INDEX;
if (idx) {
if (idx < 1 || idx > WEP_KEYS)
@@ -562,7 +558,6 @@ int ieee80211_wx_set_encode_ext(struct ieee80211_device *ieee,
}
sec.enabled = 1;
- // sec.encrypt = 1;
switch (ext->alg) {
case IW_ENCODE_ALG_WEP:
@@ -580,7 +575,7 @@ int ieee80211_wx_set_encode_ext(struct ieee80211_device *ieee,
ret = -EINVAL;
goto done;
}
- printk("alg name:%s\n",alg);
+ IEEE80211_DEBUG_WX("alg name: %s\n", alg);
ops = ieee80211_get_crypto_ops(alg);
if (ops == NULL)
@@ -624,8 +619,6 @@ int ieee80211_wx_set_encode_ext(struct ieee80211_device *ieee,
goto done;
}
#if 1
- //skip_host_crypt:
- //printk("skip_host_crypt:ext_flags:%x\n", ext->ext_flags);
if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) {
ieee->tx_keyidx = idx;
sec.active_key = idx;
@@ -633,7 +626,6 @@ int ieee80211_wx_set_encode_ext(struct ieee80211_device *ieee,
}
if (ext->alg != IW_ENCODE_ALG_NONE) {
- //memcpy(sec.keys[idx], ext->key, ext->key_len);
sec.key_sizes[idx] = ext->key_len;
sec.flags |= (1 << idx);
if (ext->alg == IW_ENCODE_ALG_WEP) {
@@ -690,7 +682,6 @@ int ieee80211_wx_set_auth(struct ieee80211_device *ieee,
switch (data->flags & IW_AUTH_INDEX) {
case IW_AUTH_WPA_VERSION:
/*need to support wpa2 here*/
- //printk("wpa version:%x\n", data->value);
break;
case IW_AUTH_CIPHER_PAIRWISE:
case IW_AUTH_CIPHER_GROUP:
@@ -708,8 +699,6 @@ int ieee80211_wx_set_auth(struct ieee80211_device *ieee,
break;
case IW_AUTH_80211_AUTH_ALG:
- //printk("======>%s():data->value is %d\n",__FUNCTION__,data->value);
- // ieee->open_wep = (data->value&IW_AUTH_ALG_OPEN_SYSTEM)?1:0;
if(data->value & IW_AUTH_ALG_SHARED_KEY){
ieee->open_wep = 0;
ieee->auth_mode = 1;
@@ -721,17 +710,14 @@ int ieee80211_wx_set_auth(struct ieee80211_device *ieee,
else if(data->value & IW_AUTH_ALG_LEAP){
ieee->open_wep = 1;
ieee->auth_mode = 2;
- //printk("hahahaa:LEAP\n");
}
else
return -EINVAL;
- //printk("open_wep:%d\n", ieee->open_wep);
break;
#if 1
case IW_AUTH_WPA_ENABLED:
ieee->wpa_enabled = (data->value)?1:0;
- //printk("enable wpa:%d\n", ieee->wpa_enabled);
break;
#endif
@@ -755,7 +741,6 @@ int ieee80211_wx_set_gen_ie(struct ieee80211_device *ieee, u8 *ie, size_t len)
if (len>MAX_WPA_IE_LEN || (len && ie == NULL))
{
- // printk("return error out, len:%d\n", len);
return -EINVAL;
}
diff --git a/drivers/staging/rtl8192su/ieee80211/rtl819x_BA.h b/drivers/staging/rtl8192su/ieee80211/rtl819x_BA.h
index 8ddc8bf9dc2..1c2a40b75a1 100644
--- a/drivers/staging/rtl8192su/ieee80211/rtl819x_BA.h
+++ b/drivers/staging/rtl8192su/ieee80211/rtl819x_BA.h
@@ -1,3 +1,21 @@
+/******************************************************************************
+ * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved.
+ *
+ * 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, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+******************************************************************************/
#ifndef _BATYPE_H_
#define _BATYPE_H_
@@ -18,14 +36,7 @@
#define DELBA_REASON_END_BA 37
#define DELBA_REASON_UNKNOWN_BA 38
#define DELBA_REASON_TIMEOUT 39
-/* whether need define BA Action frames here?
-struct ieee80211_ADDBA_Req{
- struct ieee80211_header_data header;
- u8 category;
- u8
-} __attribute__ ((packed));
-*/
-//Is this need?I put here just to make it easier to define structure BA_RECORD //WB
+
typedef union _SEQUENCE_CONTROL{
u16 ShortData;
struct
@@ -65,5 +76,4 @@ typedef struct _BA_RECORD {
SEQUENCE_CONTROL BaStartSeqCtrl;
} BA_RECORD, *PBA_RECORD;
-#endif //end _BATYPE_H_
-
+#endif
diff --git a/drivers/staging/rtl8192su/ieee80211/rtl819x_BAProc.c b/drivers/staging/rtl8192su/ieee80211/rtl819x_BAProc.c
index 8c37dd124fc..ca611faf17b 100644
--- a/drivers/staging/rtl8192su/ieee80211/rtl819x_BAProc.c
+++ b/drivers/staging/rtl8192su/ieee80211/rtl819x_BAProc.c
@@ -1,9 +1,21 @@
-/********************************************************************************************************************************
- * This file is created to process BA Action Frame. According to 802.11 spec, there are 3 BA action types at all. And as BA is
- * related to TS, this part need some struture defined in QOS side code. Also TX RX is going to be resturctured, so how to send
- * ADDBAREQ ADDBARSP and DELBA packet is still on consideration. Temporarily use MANAGE QUEUE instead of Normal Queue.
- * WB 2008-05-27
- * *****************************************************************************************************************************/
+/******************************************************************************
+ * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved.
+ *
+ * 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, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+******************************************************************************/
#include "ieee80211.h"
#include "rtl819x_BA.h"
@@ -112,7 +124,6 @@ static struct sk_buff* ieee80211_ADDBA(struct ieee80211_device* ieee, u8* Dst, P
u8* tag = NULL;
u16 tmp = 0;
u16 len = ieee->tx_headroom + 9;
- //category(1) + action field(1) + Dialog Token(1) + BA Parameter Set(2) + BA Timeout Value(2) + BA Start SeqCtrl(2)(or StatusCode(2))
IEEE80211_DEBUG(IEEE80211_DL_TRACE | IEEE80211_DL_BA, "========>%s(), frame(%d) sentd to:%pM, ieee->dev:%p\n", __FUNCTION__, type, Dst, ieee->dev);
if (pBA == NULL||ieee == NULL)
{
@@ -138,7 +149,6 @@ static struct sk_buff* ieee80211_ADDBA(struct ieee80211_device* ieee, u8* Dst, P
BAReq->frame_control = cpu_to_le16(IEEE80211_STYPE_MANAGE_ACT); //action frame
- //tag += sizeof( struct ieee80211_hdr_3addr); //move to action field
tag = (u8*)skb_put(skb, 9);
*tag ++= ACT_CAT_BA;
*tag ++= type;
@@ -171,7 +181,6 @@ static struct sk_buff* ieee80211_ADDBA(struct ieee80211_device* ieee, u8* Dst, P
IEEE80211_DEBUG_DATA(IEEE80211_DL_DATA|IEEE80211_DL_BA, skb->data, skb->len);
return skb;
- //return NULL;
}
/********************************************************************************************************************
@@ -196,7 +205,6 @@ static struct sk_buff* ieee80211_DELBA(
struct ieee80211_hdr_3addr* Delba = NULL;
u8* tag = NULL;
u16 tmp = 0;
- //len = head len + DELBA Parameter Set(2) + Reason Code(2)
u16 len = 6 + ieee->tx_headroom;
if (net_ratelimit())
@@ -213,7 +221,6 @@ static struct sk_buff* ieee80211_DELBA(
IEEE80211_DEBUG(IEEE80211_DL_ERR, "can't alloc skb for ADDBA_REQ\n");
return NULL;
}
-// memset(skb->data, 0, len+sizeof( struct ieee80211_hdr_3addr));
skb_reserve(skb, ieee->tx_headroom);
Delba = ( struct ieee80211_hdr_3addr *) skb_put(skb,sizeof( struct ieee80211_hdr_3addr));
@@ -258,9 +265,6 @@ void ieee80211_send_ADDBAReq(struct ieee80211_device* ieee, u8* dst, PBA_RECORD
if (skb)
{
softmac_mgmt_xmit(skb, ieee);
- //add statistic needed here.
- //and skb will be freed in softmac_mgmt_xmit(), so omit all dev_kfree_skb_any() outside softmac_mgmt_xmit()
- //WB
}
else
{
@@ -284,7 +288,6 @@ void ieee80211_send_ADDBARsp(struct ieee80211_device* ieee, u8* dst, PBA_RECORD
if (skb)
{
softmac_mgmt_xmit(skb, ieee);
- //same above
}
else
{
@@ -311,7 +314,6 @@ void ieee80211_send_DELBA(struct ieee80211_device* ieee, u8* dst, PBA_RECORD pBA
if (skb)
{
softmac_mgmt_xmit(skb, ieee);
- //same above
}
else
{
@@ -361,8 +363,7 @@ int ieee80211_rx_ADDBAReq( struct ieee80211_device* ieee, struct sk_buff *skb)
//some other capability is not ready now.
if( (ieee->current_network.qos_data.active == 0) ||
(ieee->pHTInfo->bCurrentHTSupport == false) ||
- (ieee->pHTInfo->IOTAction & HT_IOT_ACT_REJECT_ADDBA_REQ)) //||
- // (ieee->pStaQos->bEnableRxImmBA == false) )
+ (ieee->pHTInfo->IOTAction & HT_IOT_ACT_REJECT_ADDBA_REQ))
{
rc = ADDBA_STATUS_REFUSED;
IEEE80211_DEBUG(IEEE80211_DL_ERR, "Failed to reply on ADDBA_REQ as some capability is not ready(%d, %d)\n", ieee->current_network.qos_data.active, ieee->pHTInfo->bCurrentHTSupport);
@@ -394,7 +395,6 @@ int ieee80211_rx_ADDBAReq( struct ieee80211_device* ieee, struct sk_buff *skb)
goto OnADDBAReq_Fail;
}
// Admit the ADDBA Request
- //
DeActivateBAEntry(ieee, pBA);
pBA->DialogToken = *pDialogToken;
pBA->BaParamSet = *pBaParamSet;
@@ -406,10 +406,9 @@ int ieee80211_rx_ADDBAReq( struct ieee80211_device* ieee, struct sk_buff *skb)
pBA->BaParamSet.field.BufferSize = 1;
else
pBA->BaParamSet.field.BufferSize = 32;
- ActivateBAEntry(ieee, pBA, 0);//pBA->BaTimeoutValue);
+ ActivateBAEntry(ieee, pBA, 0);
ieee80211_send_ADDBARsp(ieee, dst, pBA, ADDBA_STATUS_SUCCESS);
- // End of procedure.
return 0;
OnADDBAReq_Fail:
@@ -541,11 +540,11 @@ int ieee80211_rx_ADDBARsp( struct ieee80211_device* ieee, struct sk_buff *skb)
pAdmittedBA->BaParamSet = *pBaParamSet;
DeActivateBAEntry(ieee, pAdmittedBA);
ActivateBAEntry(ieee, pAdmittedBA, *pBaTimeoutVal);
- }
- else
- {
- // Delay next ADDBA process.
+ } else {
pTS->bAddBaReqDelayed = true;
+ pTS->bDisable_AddBa = true;
+ ReasonCode = DELBA_REASON_END_BA;
+ goto OnADDBARsp_Reject;
}
// End of procedure
@@ -635,7 +634,6 @@ int ieee80211_rx_DELBA(struct ieee80211_device* ieee,struct sk_buff *skb)
pTxTs->bAddBaReqInProgress = false;
pTxTs->bAddBaReqDelayed = false;
del_timer_sync(&pTxTs->TsAddBaTimer);
- //PlatformCancelTimer(Adapter, &pTxTs->TsAddBaTimer);
TxTsDeleteBA(ieee, pTxTs);
}
return 0;
diff --git a/drivers/staging/rtl8192su/ieee80211/rtl819x_HT.h b/drivers/staging/rtl8192su/ieee80211/rtl819x_HT.h
index a97c901edbf..17121891433 100644
--- a/drivers/staging/rtl8192su/ieee80211/rtl819x_HT.h
+++ b/drivers/staging/rtl8192su/ieee80211/rtl819x_HT.h
@@ -1,3 +1,21 @@
+/******************************************************************************
+ * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved.
+ *
+ * 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, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+******************************************************************************/
#ifndef _RTL819XU_HTTYPE_H_
#define _RTL819XU_HTTYPE_H_
@@ -381,8 +399,7 @@ typedef struct _BSS_HT{
u16 bdHTInfoLen;
HT_SPEC_VER bdHTSpecVer;
- //HT_CAPABILITY_ELE bdHTCapEle;
- //HT_INFORMATION_ELE bdHTInfoEle;
+ HT_CHANNEL_WIDTH bdBandWidth;
u8 bdRT2RTAggregation;
u8 bdRT2RTLongSlotTime;
@@ -406,7 +423,7 @@ typedef struct _MIMO_EVM{
typedef struct _FALSE_ALARM_STATISTICS{
u32 Cnt_Parity_Fail;
- u32 Cnt_Rate_Illegal;
+ u32 Cnt_Rate_Illegal;
u32 Cnt_Crc8_fail;
u32 Cnt_all;
}FALSE_ALARM_STATISTICS, *PFALSE_ALARM_STATISTICS;
@@ -476,10 +493,9 @@ typedef enum _HT_IOT_ACTION{
HT_IOT_ACT_FORCED_CTS2SELF = 0x00000200,
HT_IOT_ACT_FORCED_RTS = 0x00000400,
HT_IOT_ACT_AMSDU_ENABLE = 0x00000800,
- HT_IOT_ACT_MID_HIGHPOWER = 0x00001000,
- HT_IOT_ACT_REJECT_ADDBA_REQ = 0x00002000,
- HT_IOT_ACT_ALLOW_PEER_AGG_ONE_PKT = 0x00004000,
- HT_IOT_ACT_EDCA_BIAS_ON_RX = 0x00008000,
+ HT_IOT_ACT_REJECT_ADDBA_REQ = 0x00001000,
+ HT_IOT_ACT_ALLOW_PEER_AGG_ONE_PKT = 0x00002000,
+ HT_IOT_ACT_EDCA_BIAS_ON_RX = 0x00004000,
HT_IOT_ACT_HYBRID_AGGREGATION = 0x00010000,
HT_IOT_ACT_DISABLE_SHORT_GI = 0x00020000,
@@ -487,12 +503,19 @@ typedef enum _HT_IOT_ACTION{
HT_IOT_ACT_DISABLE_TX_40_MHZ = 0x00080000,
HT_IOT_ACT_TX_NO_AGGREGATION = 0x00100000,
HT_IOT_ACT_DISABLE_TX_2SS = 0x00200000,
+
+ HT_IOT_ACT_MID_HIGHPOWER = 0x00400000,
+ HT_IOT_ACT_NULL_DATA_POWER_SAVING = 0x00800000,
+
+ HT_IOT_ACT_DISABLE_CCK_RATE = 0x01000000,
+ HT_IOT_ACT_FORCED_ENABLE_BE_TXOP = 0x02000000,
+ HT_IOT_ACT_WA_IOT_Broadcom = 0x04000000,
}HT_IOT_ACTION_E, *PHT_IOT_ACTION_E;
typedef enum _HT_IOT_RAFUNC{
+ HT_IOT_RAFUNC_DISABLE_ALL = 0x00,
HT_IOT_RAFUNC_PEER_1R = 0x01,
HT_IOT_RAFUNC_TX_AMSDU = 0x02,
- HT_IOT_RAFUNC_DISABLE_ALL = 0x80,
}HT_IOT_RAFUNC, *PHT_IOT_RAFUNC;
typedef enum _RT_HT_CAP{
@@ -504,5 +527,4 @@ typedef enum _RT_HT_CAP{
RT_HT_CAP_USE_92SE = 0x20,
}RT_HT_CAPBILITY, *PRT_HT_CAPBILITY;
-#endif //_RTL819XU_HTTYPE_H_
-
+#endif
diff --git a/drivers/staging/rtl8192su/ieee80211/rtl819x_HTProc.c b/drivers/staging/rtl8192su/ieee80211/rtl819x_HTProc.c
index 01114c5181b..cfd9a1a5b38 100644
--- a/drivers/staging/rtl8192su/ieee80211/rtl819x_HTProc.c
+++ b/drivers/staging/rtl8192su/ieee80211/rtl819x_HTProc.c
@@ -1,5 +1,21 @@
-
-//As this function is mainly ported from Windows driver, so leave the name little changed. If any confusion caused, tell me. Created by WB. 2008.05.08
+/******************************************************************************
+ * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved.
+ *
+ * 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, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+******************************************************************************/
#include "ieee80211.h"
#include "rtl819x_HT.h"
u8 MCS_FILTER_ALL[16] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
@@ -8,32 +24,31 @@ u8 MCS_FILTER_1SS[16] = {0xff, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0
u16 MCS_DATA_RATE[2][2][77] =
{ { {13, 26, 39, 52, 78, 104, 117, 130, 26, 52, 78 ,104, 156, 208, 234, 260,
- 39, 78, 117, 234, 312, 351, 390, 52, 104, 156, 208, 312, 416, 468, 520,
+ 39, 78, 117, 234, 312, 351, 390, 52, 104, 156, 208, 312, 416, 468, 520,
0, 78, 104, 130, 117, 156, 195, 104, 130, 130, 156, 182, 182, 208, 156, 195,
- 195, 234, 273, 273, 312, 130, 156, 181, 156, 181, 208, 234, 208, 234, 260, 260,
- 286, 195, 234, 273, 234, 273, 312, 351, 312, 351, 390, 390, 429}, // Long GI, 20MHz
- {14, 29, 43, 58, 87, 116, 130, 144, 29, 58, 87, 116, 173, 231, 260, 289,
- 43, 87, 130, 173, 260, 347, 390, 433, 58, 116, 173, 231, 347, 462, 520, 578,
- 0, 87, 116, 144, 130, 173, 217, 116, 144, 144, 173, 202, 202, 231, 173, 217,
- 217, 260, 303, 303, 347, 144, 173, 202, 173, 202, 231, 260, 231, 260, 289, 289,
- 318, 217, 260, 303, 260, 303, 347, 390, 347, 390, 433, 433, 477} }, // Short GI, 20MHz
- { {27, 54, 81, 108, 162, 216, 243, 270, 54, 108, 162, 216, 324, 432, 486, 540,
- 81, 162, 243, 324, 486, 648, 729, 810, 108, 216, 324, 432, 648, 864, 972, 1080,
- 12, 162, 216, 270, 243, 324, 405, 216, 270, 270, 324, 378, 378, 432, 324, 405,
- 405, 486, 567, 567, 648, 270, 324, 378, 324, 378, 432, 486, 432, 486, 540, 540,
- 594, 405, 486, 567, 486, 567, 648, 729, 648, 729, 810, 810, 891}, // Long GI, 40MHz
- {30, 60, 90, 120, 180, 240, 270, 300, 60, 120, 180, 240, 360, 480, 540, 600,
- 90, 180, 270, 360, 540, 720, 810, 900, 120, 240, 360, 480, 720, 960, 1080, 1200,
- 13, 180, 240, 300, 270, 360, 450, 240, 300, 300, 360, 420, 420, 480, 360, 450,
- 450, 540, 630, 630, 720, 300, 360, 420, 360, 420, 480, 540, 480, 540, 600, 600,
- 660, 450, 540, 630, 540, 630, 720, 810, 720, 810, 900, 900, 990} } // Short GI, 40MHz
+ 195, 234, 273, 273, 312, 130, 156, 181, 156, 181, 208, 234, 208, 234, 260, 260,
+ 286, 195, 234, 273, 234, 273, 312, 351, 312, 351, 390, 390, 429},
+ {14, 29, 43, 58, 87, 116, 130, 144, 29, 58, 87, 116, 173, 231, 260, 289,
+ 43, 87, 130, 173, 260, 347, 390, 433, 58, 116, 173, 231, 347, 462, 520, 578,
+ 0, 87, 116, 144, 130, 173, 217, 116, 144, 144, 173, 202, 202, 231, 173, 217,
+ 217, 260, 303, 303, 347, 144, 173, 202, 173, 202, 231, 260, 231, 260, 289, 289,
+ 318, 217, 260, 303, 260, 303, 347, 390, 347, 390, 433, 433, 477} },
+ { {27, 54, 81, 108, 162, 216, 243, 270, 54, 108, 162, 216, 324, 432, 486, 540,
+ 81, 162, 243, 324, 486, 648, 729, 810, 108, 216, 324, 432, 648, 864, 972, 1080,
+ 12, 162, 216, 270, 243, 324, 405, 216, 270, 270, 324, 378, 378, 432, 324, 405,
+ 405, 486, 567, 567, 648, 270, 324, 378, 324, 378, 432, 486, 432, 486, 540, 540,
+ 594, 405, 486, 567, 486, 567, 648, 729, 648, 729, 810, 810, 891},
+ {30, 60, 90, 120, 180, 240, 270, 300, 60, 120, 180, 240, 360, 480, 540, 600,
+ 90, 180, 270, 360, 540, 720, 810, 900, 120, 240, 360, 480, 720, 960, 1080, 1200,
+ 13, 180, 240, 300, 270, 360, 450, 240, 300, 300, 360, 420, 420, 480, 360, 450,
+ 450, 540, 630, 630, 720, 300, 360, 420, 360, 420, 480, 540, 480, 540, 600, 600,
+ 660, 450, 540, 630, 540, 630, 720, 810, 720, 810, 900, 900, 990} }
};
static u8 UNKNOWN_BORADCOM[3] = {0x00, 0x14, 0xbf};
static u8 LINKSYSWRT330_LINKSYSWRT300_BROADCOM[3] = {0x00, 0x1a, 0x70};
static u8 LINKSYSWRT350_LINKSYSWRT150_BROADCOM[3] = {0x00, 0x1d, 0x7e};
-static u8 NETGEAR834Bv2_BROADCOM[3] = {0x00, 0x1b, 0x2f};
-static u8 BELKINF5D8233V1_RALINK[3] = {0x00, 0x17, 0x3f}; //cosa 03202008
+static u8 BELKINF5D8233V1_RALINK[3] = {0x00, 0x17, 0x3f};
static u8 BELKINF5D82334V3_RALINK[3] = {0x00, 0x1c, 0xdf};
static u8 PCI_RALINK[3] = {0x00, 0x90, 0xcc};
static u8 EDIMAX_RALINK[3] = {0x00, 0x0e, 0x2e};
@@ -41,10 +56,9 @@ static u8 AIRLINK_RALINK[3] = {0x00, 0x18, 0x02};
static u8 DLINK_ATHEROS_1[3] = {0x00, 0x1c, 0xf0};
static u8 DLINK_ATHEROS_2[3] = {0x00, 0x21, 0x91};
static u8 CISCO_BROADCOM[3] = {0x00, 0x17, 0x94};
+static u8 NETGEAR_BROADCOM[3] = {0x00, 0x1f, 0x33};
static u8 LINKSYS_MARVELL_4400N[3] = {0x00, 0x14, 0xa4};
-// 2008/04/01 MH For Cisco G mode RX TP We need to change FW duration. Should we put the
-// code in other place??
-//static u8 WIFI_CISCO_G_AP[3] = {0x00, 0x40, 0x96};
+
/********************************************************************************************************************
*function: This function update default settings in pHTInfo structure
* input: PRT_HIGH_THROUGHPUT pHTInfo
@@ -55,10 +69,7 @@ static u8 LINKSYS_MARVELL_4400N[3] = {0x00, 0x14, 0xa4};
void HTUpdateDefaultSetting(struct ieee80211_device* ieee)
{
PRT_HIGH_THROUGHPUT pHTInfo = ieee->pHTInfo;
- //const typeof( ((struct ieee80211_device *)0)->pHTInfo ) *__mptr = &pHTInfo;
- //printk("pHTinfo:%p, &pHTinfo:%p, mptr:%p, offsetof:%x\n", pHTInfo, &pHTInfo, __mptr, offsetof(struct ieee80211_device, pHTInfo));
- //printk("===>ieee:%p,\n", ieee);
// ShortGI support
pHTInfo->bRegShortGI20MHz= 1;
pHTInfo->bRegShortGI40MHz= 1;
@@ -291,7 +302,6 @@ u16 HTMcsToDataRate( struct ieee80211_device* ieee, u8 nMcsRate)
* *****************************************************************************************************************/
u16 TxCountToDataRate( struct ieee80211_device* ieee, u8 nDataRate)
{
- //PRT_HIGH_THROUGHPUT pHTInfo = ieee->pHTInfo;
u16 CCKOFDMRate[12] = {0x02 , 0x04 , 0x0b , 0x16 , 0x0c , 0x12 , 0x18 , 0x24 , 0x30 , 0x48 , 0x60 , 0x6c};
u8 is40MHz = 0;
u8 isShortGI = 0;
@@ -307,28 +317,24 @@ u16 TxCountToDataRate( struct ieee80211_device* ieee, u8 nDataRate)
is40MHz = 0;
isShortGI = 0;
- // nDataRate = nDataRate - 12;
}
else if(nDataRate >=0x20 && nDataRate <= 0x2f ) //(27, 44)
{
is40MHz = 1;
isShortGI = 0;
- //nDataRate = nDataRate - 28;
}
else if(nDataRate >= 0x30 && nDataRate <= 0x3f ) //(43, 60)
{
is40MHz = 0;
isShortGI = 1;
- //nDataRate = nDataRate - 44;
}
else if(nDataRate >= 0x40 && nDataRate <= 0x4f ) //(59, 76)
{
is40MHz = 1;
isShortGI = 1;
- //nDataRate = nDataRate - 60;
}
return MCS_DATA_RATE[is40MHz][isShortGI][nDataRate&0xf];
}
@@ -351,7 +357,6 @@ bool IsHTHalfNmodeAPs(struct ieee80211_device* ieee)
else if((memcmp(net->bssid, UNKNOWN_BORADCOM, 3)==0) ||
(memcmp(net->bssid, LINKSYSWRT330_LINKSYSWRT300_BROADCOM, 3)==0)||
(memcmp(net->bssid, LINKSYSWRT350_LINKSYSWRT150_BROADCOM, 3)==0)||
- (memcmp(net->bssid, NETGEAR834Bv2_BROADCOM, 3)==0) ||
(net->broadcom_cap_exist))
retValue = true;
else if(net->bssht.bdRT2RTAggregation)
@@ -379,13 +384,15 @@ void HTIOTPeerDetermine(struct ieee80211_device* ieee)
if(net->bssht.RT2RT_HT_Mode & RT_HT_CAP_USE_92SE){
pHTInfo->IOTPeer = HT_IOT_PEER_REALTEK_92SE;
}
+ if(net->bssht.RT2RT_HT_Mode & RT_HT_CAP_USE_SOFTAP){
+ pHTInfo->IOTPeer = HT_IOT_PEER_92U_SOFTAP;
+ }
}
else if(net->broadcom_cap_exist)
pHTInfo->IOTPeer = HT_IOT_PEER_BROADCOM;
else if((memcmp(net->bssid, UNKNOWN_BORADCOM, 3)==0) ||
(memcmp(net->bssid, LINKSYSWRT330_LINKSYSWRT300_BROADCOM, 3)==0)||
- (memcmp(net->bssid, LINKSYSWRT350_LINKSYSWRT150_BROADCOM, 3)==0)||
- (memcmp(net->bssid, NETGEAR834Bv2_BROADCOM, 3)==0) )
+ (memcmp(net->bssid, LINKSYSWRT350_LINKSYSWRT150_BROADCOM, 3)==0))
pHTInfo->IOTPeer = HT_IOT_PEER_BROADCOM;
else if((memcmp(net->bssid, BELKINF5D8233V1_RALINK, 3)==0) ||
(memcmp(net->bssid, BELKINF5D82334V3_RALINK, 3)==0) ||
@@ -398,7 +405,7 @@ void HTIOTPeerDetermine(struct ieee80211_device* ieee)
(memcmp(net->bssid, DLINK_ATHEROS_1, 3) == 0)||
(memcmp(net->bssid, DLINK_ATHEROS_2, 3) == 0))
pHTInfo->IOTPeer = HT_IOT_PEER_ATHEROS;
- else if(memcmp(net->bssid, CISCO_BROADCOM, 3)==0)
+ else if ((memcmp(net->bssid, CISCO_BROADCOM, 3)==0)||net->cisco_cap_exist)
pHTInfo->IOTPeer = HT_IOT_PEER_CISCO;
else if ((memcmp(net->bssid, LINKSYS_MARVELL_4400N, 3) == 0) ||
net->marvell_cap_exist)
@@ -439,25 +446,6 @@ u8 HTIOTActIsDisableMCS14(struct ieee80211_device* ieee, u8* PeerMacAddr)
bool HTIOTActIsDisableMCS15(struct ieee80211_device* ieee)
{
bool retValue = false;
-
-#ifdef TODO
- // Apply for 819u only
-#if (HAL_CODE_BASE==RTL8192)
-
-#if (DEV_BUS_TYPE == USB_INTERFACE)
- // Alway disable MCS15 by Jerry Chang's request.by Emily, 2008.04.15
- retValue = true;
-#elif (DEV_BUS_TYPE == PCI_INTERFACE)
- // Enable MCS15 if the peer is Cisco AP. by Emily, 2008.05.12
-// if(pBssDesc->bCiscoCapExist)
-// retValue = false;
-// else
- retValue = false;
-#endif
-#endif
-#endif
- // Jerry Chang suggest that 8190 1x2 does not need to disable MCS15
-
return retValue;
}
@@ -624,17 +612,11 @@ HTIOCActRejcectADDBARequest(struct ieee80211_network *network)
HTIOTActIsEDCABiasRx(struct ieee80211_device* ieee,struct ieee80211_network *network)
{
u8 retValue = 0;
- //if(IS_HARDWARE_TYPE_8192SU(Adapter))
PRT_HIGH_THROUGHPUT pHTInfo = ieee->pHTInfo;
{
-//#if UNDER_VISTA
-// if(pBssDesc->Vender==HT_IOT_PEER_ATHEROS ||
-// pBssDesc->Vender==HT_IOT_PEER_RALINK)
-//#else
if(pHTInfo->IOTPeer==HT_IOT_PEER_ATHEROS ||
pHTInfo->IOTPeer==HT_IOT_PEER_BROADCOM ||
pHTInfo->IOTPeer==HT_IOT_PEER_RALINK)
-//#endif
return 1;
}
@@ -649,7 +631,6 @@ HTIOTActDisableShortGI(struct ieee80211_device* ieee,struct ieee80211_network *n
if(pHTInfo->IOTPeer==HT_IOT_PEER_RALINK)
{
- if(network->bssht.bdHT1R)
retValue = 1;
}
@@ -662,9 +643,10 @@ HTIOTActDisableHighPower(struct ieee80211_device* ieee,struct ieee80211_network
u8 retValue = 0;
PRT_HIGH_THROUGHPUT pHTInfo = ieee->pHTInfo;
- if(pHTInfo->IOTPeer==HT_IOT_PEER_RALINK)
+ if(pHTInfo->IOTPeer==HT_IOT_PEER_RALINK ||
+ pHTInfo->IOTPeer==HT_IOT_PEER_REALTEK ||
+ pHTInfo->IOTPeer==HT_IOT_PEER_REALTEK_92SE)
{
- if(network->bssht.bdHT1R)
retValue = 1;
}
@@ -718,8 +700,7 @@ HTIOTActIsTxNoAggregation(struct ieee80211_device* ieee,struct ieee80211_network
(KEY_TYPE_WEP40 == ieee->group_key_type) ||
(KEY_TYPE_TKIP == ieee->pairwise_key_type) )
{
- if(pHTInfo->IOTPeer==HT_IOT_PEER_REALTEK ||
- pHTInfo->IOTPeer==HT_IOT_PEER_UNKNOWN)
+ if(pHTInfo->IOTPeer==HT_IOT_PEER_REALTEK)
retValue = 1;
}
@@ -751,10 +732,11 @@ bool HTIOCActAllowPeerAggOnePacket(struct ieee80211_device* ieee,struct ieee8021
{
bool retValue = false;
PRT_HIGH_THROUGHPUT pHTInfo = ieee->pHTInfo;
+ if(pHTInfo->IOTPeer == HT_IOT_PEER_BROADCOM)
{
- if(pHTInfo->IOTPeer == HT_IOT_PEER_MARVELL)
+ if((memcmp(network->bssid, NETGEAR_BROADCOM, 3)==0)
+ && (network->bssht.bdBandWidth == HT_CHANNEL_WIDTH_20_40))
return true;
-
}
return retValue;
}
@@ -783,7 +765,6 @@ void HTConstructCapabilityElement(struct ieee80211_device* ieee, u8* posHTCap, u
{
PRT_HIGH_THROUGHPUT pHT = ieee->pHTInfo;
PHT_CAPABILITY_ELE pCapELE = NULL;
- //u8 bIsDeclareMCS13;
if ((posHTCap == NULL) || (pHT == NULL))
{
@@ -813,13 +794,11 @@ void HTConstructCapabilityElement(struct ieee80211_device* ieee, u8* posHTCap, u
pCapELE->ChlWidth = (pHT->bRegBW40MHz?1:0);
}
-// pCapELE->ChlWidth = (pHT->bRegBW40MHz?1:0);
pCapELE->MimoPwrSave = pHT->SelfMimoPs;
pCapELE->GreenField = 0; // This feature is not supported now!!
pCapELE->ShortGI20Mhz = 1; // We can receive Short GI!!
pCapELE->ShortGI40Mhz = 1; // We can receive Short GI!!
- //DbgPrint("TX HT cap/info ele BW=%d SG20=%d SG40=%d\n\r",
- //pCapELE->ChlWidth, pCapELE->ShortGI20Mhz, pCapELE->ShortGI40Mhz);
+
pCapELE->TxSTBC = 1;
pCapELE->RxSTBC = 0;
pCapELE->DelayBA = 0; // Do not support now!!
@@ -879,12 +858,6 @@ void HTConstructCapabilityElement(struct ieee80211_device* ieee, u8* posHTCap, u
else
*len = 26 + 2;
-
-
-// IEEE80211_DEBUG_DATA(IEEE80211_DL_DATA | IEEE80211_DL_HT, posHTCap, *len -2);
-
- //Print each field in detail. Driver should not print out this message by default
-// HTDebugHTCapability(posHTCap, (u8*)"HTConstructCapability()");
return;
}
@@ -938,8 +911,6 @@ void HTConstructInfoElement(struct ieee80211_device* ieee, u8* posHTInfo, u8* le
//STA should not generate High Throughput Information Element
*len = 0;
}
- //IEEE80211_DEBUG_DATA(IEEE80211_DL_DATA | IEEE80211_DL_HT, posHTInfo, *len - 2);
- //HTDebugHTInfo(posHTInfo, "HTConstructInforElement");
return;
}
@@ -1005,7 +976,6 @@ void HTConstructRT2RTAggElement(struct ieee80211_device* ieee, u8* posRT2RTAgg,
*/
#else
- // Do Nothing
#endif
posRT2RTAgg->Length = 6;
@@ -1188,12 +1158,7 @@ void HTOnAssocRsp(struct ieee80211_device *ieee)
return;
}
IEEE80211_DEBUG(IEEE80211_DL_HT, "===> HTOnAssocRsp_wq(): HT_ENABLE\n");
-// IEEE80211_DEBUG_DATA(IEEE80211_DL_DATA, pHTInfo->PeerHTCapBuf, sizeof(HT_CAPABILITY_ELE));
-// IEEE80211_DEBUG_DATA(IEEE80211_DL_DATA, pHTInfo->PeerHTInfoBuf, sizeof(HT_INFORMATION_ELE));
-// HTDebugHTCapability(pHTInfo->PeerHTCapBuf,"HTOnAssocRsp_wq");
-// HTDebugHTInfo(pHTInfo->PeerHTInfoBuf,"HTOnAssocRsp_wq");
- //
if(!memcmp(pHTInfo->PeerHTCapBuf,EWC11NHTCap, sizeof(EWC11NHTCap)))
pPeerHTCap = (PHT_CAPABILITY_ELE)(&pHTInfo->PeerHTCapBuf[4]);
else
@@ -1209,12 +1174,10 @@ void HTOnAssocRsp(struct ieee80211_device *ieee)
// Configurations:
////////////////////////////////////////////////////////
IEEE80211_DEBUG_DATA(IEEE80211_DL_DATA|IEEE80211_DL_HT, pPeerHTCap, sizeof(HT_CAPABILITY_ELE));
-// IEEE80211_DEBUG_DATA(IEEE80211_DL_DATA|IEEE80211_DL_HT, pPeerHTInfo, sizeof(HT_INFORMATION_ELE));
- // Config Supported Channel Width setting
- //
+
HTSetConnectBwMode(ieee, (HT_CHANNEL_WIDTH)(pPeerHTCap->ChlWidth), (HT_EXTCHNL_OFFSET)(pPeerHTInfo->ExtChlOffset));
-// if(pHTInfo->bCurBW40MHz == true)
+ if(pHTInfo->bCurBW40MHz == true)
pHTInfo->bCurTxBW40MHz = ((pPeerHTInfo->RecommemdedTxWidth == 1)?true:false);
//
@@ -1295,7 +1258,7 @@ void HTOnAssocRsp(struct ieee80211_device *ieee)
// <2> Set AMPDU Minimum MPDU Start Spacing
// 802.11n 3.0 section 9.7d.3
-#if 1
+#if 0
if(pHTInfo->MPDU_Density > pPeerHTCap->MPDUDensity)
pHTInfo->CurrentMPDUDensity = pHTInfo->MPDU_Density;
else
diff --git a/drivers/staging/rtl8192su/ieee80211/rtl819x_Qos.h b/drivers/staging/rtl8192su/ieee80211/rtl819x_Qos.h
index d4565ecc7ab..928062f3571 100644
--- a/drivers/staging/rtl8192su/ieee80211/rtl819x_Qos.h
+++ b/drivers/staging/rtl8192su/ieee80211/rtl819x_Qos.h
@@ -1,3 +1,21 @@
+/******************************************************************************
+ * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved.
+ *
+ * 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, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+******************************************************************************/
#ifndef __INC_QOS_TYPE_H
#define __INC_QOS_TYPE_H
@@ -36,18 +54,6 @@
#define MAX_WMMELE_LENGTH 64
-//
-// QoS mode.
-// enum 0, 1, 2, 4: since we can use the OR(|) operation.
-//
-// QOS_MODE is redefined for enum can't be ++, | under C++ compiler, 2006.05.17, by rcnjko.
-//typedef enum _QOS_MODE{
-// QOS_DISABLE = 0,
-// QOS_WMM = 1,
-// QOS_EDCA = 2,
-// QOS_HCCA = 4,
-//}QOS_MODE,*PQOS_MODE;
-//
typedef u32 QOS_MODE, *PQOS_MODE;
#define QOS_DISABLE 0
#define QOS_WMM 1
@@ -219,19 +225,6 @@ typedef union _QOS_INFO_FIELD{
}QOS_INFO_FIELD, *PQOS_INFO_FIELD;
-//
-// ACI to AC coding.
-// Ref: WMM spec 2.2.2: WME Parameter Element, p.13.
-//
-// AC_CODING is redefined for enum can't be ++, | under C++ compiler, 2006.05.17, by rcnjko.
-//typedef enum _AC_CODING{
-// AC0_BE = 0, // ACI: 0x00 // Best Effort
-// AC1_BK = 1, // ACI: 0x01 // Background
-// AC2_VI = 2, // ACI: 0x10 // Video
-// AC3_VO = 3, // ACI: 0x11 // Voice
-// AC_MAX = 4, // Max: define total number; Should not to be used as a real enum.
-//}AC_CODING,*PAC_CODING;
-//
typedef u32 AC_CODING;
#define AC0_BE 0 // ACI: 0x00 // Best Effort
#define AC1_BK 1 // ACI: 0x01 // Background
@@ -252,7 +245,7 @@ typedef union _ACI_AIFSN{
u8 ACM:1;
u8 ACI:2;
u8 Reserved:1;
- }f; // Field
+ }f;
}ACI_AIFSN, *PACI_AIFSN;
//
@@ -265,7 +258,7 @@ typedef union _ECW{
{
u8 ECWmin:4;
u8 ECWmax:4;
- }f; // Field
+ }f;
}ECW, *PECW;
//
@@ -281,7 +274,7 @@ typedef union _AC_PARAM{
ACI_AIFSN AciAifsn;
ECW Ecw;
u16 TXOPLimit;
- }f; // Field
+ }f;
}AC_PARAM, *PAC_PARAM;
@@ -354,7 +347,7 @@ typedef union _TSPEC_BODY{
u32 MinPhyRate;
u16 SurplusBandwidthAllowance;
u16 MediumTime;
- } f; // Field
+ } f;
}TSPEC_BODY, *PTSPEC_BODY;
@@ -384,7 +377,6 @@ typedef enum _ACM_METHOD{
typedef struct _ACM{
-// u8 RegEnableACM;
u64 UsedTime;
u64 MediumTime;
u8 HwAcmCtl; // TRUE: UsedTime exceed => Do NOT USE this AC. It wll be written to ACM_CONTROL(0xBF BIT 0/1/2 in 8185B).
@@ -404,10 +396,6 @@ typedef u8 AC_UAPSD, *PAC_UAPSD;
#define GET_BE_UAPSD(_apsd) ((_apsd) & BIT3)
#define SET_BE_UAPSD(_apsd) ((_apsd) |= BIT3)
-
-//typedef struct _TCLASS{
-// TODO
-//} TCLASS, *PTCLASS;
typedef union _QOS_TCLAS{
struct _TYPE_GENERAL{
@@ -459,32 +447,12 @@ typedef union _QOS_TCLAS{
} TYPE2_8021Q;
} QOS_TCLAS, *PQOS_TCLAS;
-//typedef struct _WMM_TSTREAM{
-//
-//- TSPEC
-//- AC (which to mapping)
-//} WMM_TSTREAM, *PWMM_TSTREAM;
typedef struct _QOS_TSTREAM{
u8 AC;
WMM_TSPEC TSpec;
QOS_TCLAS TClass;
} QOS_TSTREAM, *PQOS_TSTREAM;
-//typedef struct _U_APSD{
-//- TriggerEnable [4]
-//- MaxSPLength
-//- HighestAcBuffered
-//} U_APSD, *PU_APSD;
-
-//joseph TODO:
-// UAPSD function should be implemented by 2 data structure
-// "Qos control field" and "Qos info field"
-//typedef struct _QOS_UAPSD{
-// u8 bTriggerEnable[4];
-// u8 MaxSPLength;
-// u8 HighestBufAC;
-//} QOS_UAPSD, *PQOS_APSD;
-
//----------------------------------------------------------------------------
// 802.11 Management frame Status Code field
//----------------------------------------------------------------------------
@@ -498,7 +466,6 @@ typedef struct _OCTET_STRING{
// Ref: DOT11_QOS in 8185 code. [def. in QoS_mp.h]
//
typedef struct _STA_QOS{
- //DECLARE_RT_OBJECT(STA_QOS);
u8 WMMIEBuf[MAX_WMMELE_LENGTH];
u8* WMMIE;
@@ -565,18 +532,9 @@ typedef struct _BSS_QOS{
AC_PARAM AcParameter[4];
}BSS_QOS, *PBSS_QOS;
-
-//
-// Ref: sQoSCtlLng and QoSCtl definition in 8185 QoS code.
-//#define QoSCtl (( (Adapter->bRegQoS) && (Adapter->dot11QoS.QoSMode &(QOS_EDCA|QOS_HCCA)) ) ?sQoSCtlLng:0)
-//
#define sQoSCtlLng 2
#define QOS_CTRL_LEN(_QosMode) ((_QosMode > QOS_DISABLE)? sQoSCtlLng : 0)
-
-//Added by joseph
-//UP Mapping to AC, using in MgntQuery_SequenceNumber() and maybe for DSCP
-//#define UP2AC(up) ((up<3)?((up==0)?1:0):(up>>1))
#define IsACValid(ac) ((ac<=7 )?true:false )
-#endif // #ifndef __INC_QOS_TYPE_H
+#endif
diff --git a/drivers/staging/rtl8192su/ieee80211/rtl819x_TS.h b/drivers/staging/rtl8192su/ieee80211/rtl819x_TS.h
index baaac2149de..a07b2344a6f 100644
--- a/drivers/staging/rtl8192su/ieee80211/rtl819x_TS.h
+++ b/drivers/staging/rtl8192su/ieee80211/rtl819x_TS.h
@@ -1,3 +1,21 @@
+/******************************************************************************
+ * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved.
+ *
+ * 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, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+******************************************************************************/
#ifndef _TSTYPE_H_
#define _TSTYPE_H_
#include "rtl819x_Qos.h"
@@ -30,10 +48,10 @@ typedef struct _TX_TS_RECORD{
u16 TxCurSeq;
BA_RECORD TxPendingBARecord; // For BA Originator
BA_RECORD TxAdmittedBARecord; // For BA Originator
-// QOS_DL_RECORD DLRecord;
u8 bAddBaReqInProgress;
u8 bAddBaReqDelayed;
u8 bUsingBa;
+ u8 bDisable_AddBa;
struct timer_list TsAddBaTimer;
u8 num;
} TX_TS_RECORD, *PTX_TS_RECORD;
@@ -48,9 +66,6 @@ typedef struct _RX_TS_RECORD {
u16 RxLastSeqNum;
u8 RxLastFragNum;
u8 num;
-// QOS_DL_RECORD DLRecord;
} RX_TS_RECORD, *PRX_TS_RECORD;
-
#endif
-
diff --git a/drivers/staging/rtl8192su/ieee80211/rtl819x_TSProc.c b/drivers/staging/rtl8192su/ieee80211/rtl819x_TSProc.c
index de143ecae5f..7ffc06ca89a 100644
--- a/drivers/staging/rtl8192su/ieee80211/rtl819x_TSProc.c
+++ b/drivers/staging/rtl8192su/ieee80211/rtl819x_TSProc.c
@@ -1,3 +1,21 @@
+/******************************************************************************
+ * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved.
+ *
+ * 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, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+******************************************************************************/
#include "ieee80211.h"
#include <linux/etherdevice.h>
#include <linux/slab.h>
@@ -29,7 +47,6 @@ void RxPktPendingTimeout(unsigned long data)
PRX_REORDER_ENTRY pReorderEntry = NULL;
- //u32 flags = 0;
unsigned long flags = 0;
struct ieee80211_rxb *stats_IndicateArray[REORDER_WIN_SIZE];
u8 index = 0;
@@ -37,7 +54,6 @@ void RxPktPendingTimeout(unsigned long data)
spin_lock_irqsave(&(ieee->reorder_spinlock), flags);
- //PlatformAcquireSpinLock(Adapter, RT_RX_SPINLOCK);
IEEE80211_DEBUG(IEEE80211_DL_REORDER,"==================>%s()\n",__FUNCTION__);
if(pRxTs->RxTimeoutIndicateSeq != 0xffff)
{
@@ -72,7 +88,6 @@ void RxPktPendingTimeout(unsigned long data)
if(index>0)
{
- // Set RxTimeoutIndicateSeq to 0xffff to indicate no pending packets in buffer now.
pRxTs->RxTimeoutIndicateSeq = 0xffff;
// Indicate packets
@@ -82,6 +97,7 @@ void RxPktPendingTimeout(unsigned long data)
return;
}
ieee80211_indicate_packets(ieee, stats_IndicateArray, index);
+ bPktInBuf = false;
}
if(bPktInBuf && (pRxTs->RxTimeoutIndicateSeq==0xffff))
@@ -126,6 +142,7 @@ void ResetTxTsEntry(PTX_TS_RECORD pTS)
pTS->bAddBaReqInProgress = false;
pTS->bAddBaReqDelayed = false;
pTS->bUsingBa = false;
+ pTS->bDisable_AddBa = false;
ResetBaEntry(&pTS->TxAdmittedBARecord); //For BA Originator
ResetBaEntry(&pTS->TxPendingBARecord);
}
@@ -212,7 +229,6 @@ void TSInitialize(struct ieee80211_device *ieee)
}
// Initialize unused Rx Reorder List.
INIT_LIST_HEAD(&ieee->RxReorder_Unused_List);
-//#ifdef TO_DO_LIST
for(count = 0; count < REORDER_ENTRY_NUM; count++)
{
list_add_tail( &pRxReorderEntry->List,&ieee->RxReorder_Unused_List);
@@ -220,7 +236,6 @@ void TSInitialize(struct ieee80211_device *ieee)
break;
pRxReorderEntry = &ieee->RxReorderEntry[count+1];
}
-//#endif
}
@@ -236,7 +251,6 @@ void AdmitTS(struct ieee80211_device *ieee, PTS_COMMON_INFO pTsCommonInfo, u32 I
PTS_COMMON_INFO SearchAdmitTRStream(struct ieee80211_device *ieee, u8* Addr, u8 TID, TR_SELECT TxRxSelect)
{
- //DIRECTION_VALUE dir;
u8 dir;
bool search_dir[4] = {0, 0, 0, 0};
struct list_head* psearch_list; //FIXME
@@ -282,18 +296,15 @@ PTS_COMMON_INFO SearchAdmitTRStream(struct ieee80211_device *ieee, u8* Addr, u8
else
psearch_list = &ieee->Rx_TS_Admit_List;
- //for(dir = DIR_UP; dir <= DIR_BI_DIR; dir++)
for(dir = 0; dir <= DIR_BI_DIR; dir++)
{
if(search_dir[dir] ==false )
continue;
list_for_each_entry(pRet, psearch_list, List){
- // IEEE80211_DEBUG(IEEE80211_DL_TS, "ADD:%pM, TID:%d, dir:%d\n", pRet->Addr, pRet->TSpec.f.TSInfo.field.ucTSID, pRet->TSpec.f.TSInfo.field.ucDirection);
if (memcmp(pRet->Addr, Addr, 6) == 0)
if (pRet->TSpec.f.TSInfo.field.ucTSID == TID)
if(pRet->TSpec.f.TSInfo.field.ucDirection == dir)
{
- // printk("Bingo! got it\n");
break;
}
@@ -352,10 +363,9 @@ bool GetTs(
//
if(is_broadcast_ether_addr(Addr) || is_multicast_ether_addr(Addr))
{
- IEEE80211_DEBUG(IEEE80211_DL_ERR, "get TS for Broadcast or Multicast\n");
+ IEEE80211_DEBUG(IEEE80211_DL_ERR, "ERR! get TS for Broadcast or Multicast\n");
return false;
}
-
if (ieee->current_network.qos_data.supported == 0)
UP = 0;
else
@@ -363,7 +373,7 @@ bool GetTs(
// In WMM case: we use 4 TID only
if (!IsACValid(TID))
{
- IEEE80211_DEBUG(IEEE80211_DL_ERR, " in %s(), TID(%d) is not valid\n", __FUNCTION__, TID);
+ IEEE80211_DEBUG(IEEE80211_DL_ERR, "ERR! in %s(), TID(%d) is not valid\n", __FUNCTION__, TID);
return false;
}
@@ -478,7 +488,6 @@ void RemoveTsEntry(
TR_SELECT TxRxSelect
)
{
- //u32 flags = 0;
unsigned long flags = 0;
del_timer_sync(&pTs->SetupTimer);
del_timer_sync(&pTs->InactTimer);
@@ -486,7 +495,6 @@ void RemoveTsEntry(
if(TxRxSelect == RX_DIR)
{
-//#ifdef TO_DO_LIST
PRX_REORDER_ENTRY pRxReorderEntry;
PRX_TS_RECORD pRxTS = (PRX_TS_RECORD)pTs;
if(timer_pending(&pRxTS->RxPktPendingTimer))
@@ -494,9 +502,7 @@ void RemoveTsEntry(
while(!list_empty(&pRxTS->RxPendingPktList))
{
- // PlatformAcquireSpinLock(Adapter, RT_RX_SPINLOCK);
spin_lock_irqsave(&(ieee->reorder_spinlock), flags);
- //pRxReorderEntry = list_entry(&pRxTS->RxPendingPktList.prev,RX_REORDER_ENTRY,List);
pRxReorderEntry = (PRX_REORDER_ENTRY)list_entry(pRxTS->RxPendingPktList.prev,RX_REORDER_ENTRY,List);
list_del_init(&pRxReorderEntry->List);
{
@@ -514,11 +520,8 @@ void RemoveTsEntry(
prxb = NULL;
}
list_add_tail(&pRxReorderEntry->List,&ieee->RxReorder_Unused_List);
- //PlatformReleaseSpinLock(Adapter, RT_RX_SPINLOCK);
spin_unlock_irqrestore(&(ieee->reorder_spinlock), flags);
}
-
-//#endif
}
else
{
diff --git a/drivers/staging/rtl8192su/r8192SU_HWImg.c b/drivers/staging/rtl8192su/r8192SU_HWImg.c
index ba8e12c209c..7c4fd18d89c 100644
--- a/drivers/staging/rtl8192su/r8192SU_HWImg.c
+++ b/drivers/staging/rtl8192su/r8192SU_HWImg.c
@@ -93,7 +93,7 @@ u32 Rtl8192SUPHY_REG_2T2RArray[PHY_REG_2T2RArrayLength] = {
0x900,0x00000000,
0x904,0x00000023,
0x908,0x00000000,
-0x90c,0x03321333,
+0x90c,0x01121313,
0xa00,0x00d047c8,
0xa04,0x80ff0008,
0xa08,0x8ccd8300,
@@ -135,7 +135,7 @@ u32 Rtl8192SUPHY_REG_2T2RArray[PHY_REG_2T2RArrayLength] = {
0xc68,0x69543420,
0xc6c,0x433c0094,
0xc70,0x2c7f000d,
-0xc74,0x0186155b,
+0xc74,0x0186175b,
0xc78,0x0000001f,
0xc7c,0x00b91612,
0xc80,0x40000100,
@@ -256,13 +256,34 @@ u32 Rtl8192SUPHY_ChangeTo_2T2RArray[PHY_ChangeTo_2T2RArrayLength] = {
};
u32 Rtl8192SUPHY_REG_Array_PG[PHY_REG_Array_PGLength] = {
-0xe00,0xffffffff,0x06090909,
-0xe04,0xffffffff,0x00030406,
+0xe00,0xffffffff,0x04060606,
+0xe04,0xffffffff,0x00020204,
0xe08,0x0000ff00,0x00000000,
-0xe10,0xffffffff,0x0a0c0d0e,
-0xe14,0xffffffff,0x04070809,
-0xe18,0xffffffff,0x0a0c0d0e,
-0xe1c,0xffffffff,0x04070809,
+0xe10,0xffffffff,0x0408080a,
+0xe14,0xffffffff,0x00020204,
+0xe18,0xffffffff,0x0408080a,
+0xe1c,0xffffffff,0x00020204,
+0xe00,0xffffffff,0x00000000,
+0xe04,0xffffffff,0x00000000,
+0xe08,0x0000ff00,0x00000000,
+0xe10,0xffffffff,0x00000000,
+0xe14,0xffffffff,0x00000000,
+0xe18,0xffffffff,0x00000000,
+0xe1c,0xffffffff,0x00000000,
+0xe00,0xffffffff,0x00000000,
+0xe04,0xffffffff,0x00000000,
+0xe08,0x0000ff00,0x00000000,
+0xe10,0xffffffff,0x00000000,
+0xe14,0xffffffff,0x00000000,
+0xe18,0xffffffff,0x00000000,
+0xe1c,0xffffffff,0x00000000,
+0xe00,0xffffffff,0x00000000,
+0xe04,0xffffffff,0x00000000,
+0xe08,0x0000ff00,0x00000000,
+0xe10,0xffffffff,0x00000000,
+0xe14,0xffffffff,0x00000000,
+0xe18,0xffffffff,0x00000000,
+0xe1c,0xffffffff,0x00000000,
};
u32 Rtl8192SURadioA_1T_Array[RadioA_1T_ArrayLength] = {
diff --git a/drivers/staging/rtl8192su/r8192SU_HWImg.h b/drivers/staging/rtl8192su/r8192SU_HWImg.h
index 36e84aff6ed..69a66c39960 100644
--- a/drivers/staging/rtl8192su/r8192SU_HWImg.h
+++ b/drivers/staging/rtl8192su/r8192SU_HWImg.h
@@ -1,3 +1,21 @@
+/******************************************************************************
+ * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved.
+ *
+ * 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, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+******************************************************************************/
#ifndef __INC_HAL8192SU_FW_IMG_H
#define __INC_HAL8192SU_FW_IMG_H
@@ -19,7 +37,7 @@ extern u32 Rtl8192SUPHY_ChangeTo_1T1RArray[PHY_ChangeTo_1T1RArrayLength];
extern u32 Rtl8192SUPHY_ChangeTo_1T2RArray[PHY_ChangeTo_1T2RArrayLength];
#define PHY_ChangeTo_2T2RArrayLength 45
extern u32 Rtl8192SUPHY_ChangeTo_2T2RArray[PHY_ChangeTo_2T2RArrayLength];
-#define PHY_REG_Array_PGLength 21
+#define PHY_REG_Array_PGLength 84
extern u32 Rtl8192SUPHY_REG_Array_PG[PHY_REG_Array_PGLength];
#define RadioA_1T_ArrayLength 202
extern u32 Rtl8192SURadioA_1T_Array[RadioA_1T_ArrayLength];
@@ -38,5 +56,5 @@ extern u32 Rtl8192SUMACPHY_Array_PG[MACPHY_Array_PGLength];
#define AGCTAB_ArrayLength 320
extern u32 Rtl8192SUAGCTAB_Array[AGCTAB_ArrayLength];
-#endif //__INC_HAL8192SU_FW_IMG_H
+#endif
diff --git a/drivers/staging/rtl8192su/r8192SU_led.c b/drivers/staging/rtl8192su/r8192SU_led.c
index 609dba67eb4..5d96b356bf1 100644
--- a/drivers/staging/rtl8192su/r8192SU_led.c
+++ b/drivers/staging/rtl8192su/r8192SU_led.c
@@ -1087,22 +1087,13 @@ BlinkTimerCallback(
struct net_device *dev = (struct net_device *)data;
struct r8192_priv *priv = ieee80211_priv(dev);
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)
schedule_work(&(priv->BlinkWorkItem));
-#endif
}
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)
void BlinkWorkItemCallback(struct work_struct *work)
{
struct r8192_priv *priv = container_of(work, struct r8192_priv, BlinkWorkItem);
-#else
-void BlinkWorkItemCallback(void * Context)
-{
- struct net_device *dev = (struct net_device *)Context;
- struct r8192_priv *priv = ieee80211_priv(dev);
-#endif
PLED_819xUsb pLed = priv->pLed;
diff --git a/drivers/staging/rtl8192su/r8192S_Efuse.c b/drivers/staging/rtl8192su/r8192S_Efuse.c
index f0ce6562c23..bbefd0f3034 100644
--- a/drivers/staging/rtl8192su/r8192S_Efuse.c
+++ b/drivers/staging/rtl8192su/r8192S_Efuse.c
@@ -1,27 +1,26 @@
/******************************************************************************
+ * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved.
*
- * (c) Copyright 2008, RealTEK Technologies Inc. All Rights Reserved.
+ * Based on the r8180 driver, which is:
+ * Copyright 2004-2005 Andrea Merello <andreamrl@tiscali.it>, et al.
+ * 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.
*
- * Module: Efuse.c ( Source C File)
+ * 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.
*
- * Note: Copy from WMAC for the first version!!!!
+ * 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, USA
*
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
*
- * Function:
- *
- * Export:
- *
- * Abbrev:
- *
- * History:
- * Data Who Remark
- *
- * 09/23/2008 MHC Porting Efuse R/W API from WMAC.
- * 11/10/2008 MHC 1. Porting from 8712 EFUSE.
- * 2. Add description and reorganize code arch.
- * 11/16/2008 MHC 1. Reorganize code architecture.
- * 2. Rename for some API and change extern or static type.
- *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
******************************************************************************/
#include "r8192U.h"
#include "r8192S_hw.h"
@@ -30,20 +29,14 @@
#include "r8192S_Efuse.h"
#include <linux/types.h>
+#include <linux/ctype.h>
-//typedef int INT32;
-//
-// In the future, we will always support EFUSE!!
-//
-/*---------------------------Define Local Constant---------------------------*/
#define _POWERON_DELAY_
#define _PRE_EXECUTE_READ_CMD_
#define EFUSE_REPEAT_THRESHOLD_ 3
#define EFUSE_ERROE_HANDLE 1
-
-// From 8712!!!!!
typedef struct _EFUSE_MAP_A{
u8 offset; //0~15
u8 word_start; //0~3
@@ -91,14 +84,11 @@ struct efuse_priv
u8 tx_power_g[14];
};
-/*---------------------------Define Local Constant---------------------------*/
-
-
-/*------------------------Define global variable-----------------------------*/
const u8 MAX_PGPKT_SIZE = 9; //header+ 2* 4 words (BYTES)
const u8 PGPKT_DATA_SIZE = 8; //BYTES sizeof(u8)*8
const u32 EFUSE_MAX_SIZE = 512;
+const u8 EFUSE_OOB_PROTECT_BYTES = 14;
const EFUSE_MAP RTL8712_SDIO_EFUSE_TABLE[]={
//offset word_s byte_start byte_cnts
@@ -117,15 +107,6 @@ const EFUSE_MAP RTL8712_SDIO_EFUSE_TABLE[]={
/*TxPwIndex */ {11 ,0 ,0 ,28 } // 58~73h 3...4
};
-/*------------------------Define global variable-----------------------------*/
-
-
-/*------------------------Define local variable------------------------------*/
-
-/*------------------------Define local variable------------------------------*/
-
-
-/*--------------------Define function prototype-----------------------*/
//
// From WMAC Efuse one byte R/W
//
@@ -176,7 +157,7 @@ efuse_ParsingMap(char* szStr,u32* pu4bVal,u32* pu4bMove);
//
static u8
efuse_PgPacketRead( struct net_device* dev,u8 offset,u8 *data);
-static u8
+static u32
efuse_PgPacketWrite(struct net_device* dev,u8 offset,u8 word_en,u8 *data);
static void
efuse_WordEnableDataRead( u8 word_en,u8 *sourdata,u8 *targetdata);
@@ -194,7 +175,6 @@ efuse_CalculateWordCnts(u8 word_en);
#ifdef TO_DO_LIST
static void efuse_reg_ctrl(struct net_device* dev, u8 bPowerOn);
#endif
-/*--------------------Define function prototype-----------------------*/
@@ -242,8 +222,7 @@ EFUSE_Initialize(struct net_device* dev)
//Set E-fuse program time & read time : 0x30[30:24]=1110010b
write_nic_byte(dev, EFUSE_CTRL+3, 0x72);
-} /* EFUSE_Initialize */
-
+}
/*-----------------------------------------------------------------------------
* Function: EFUSE_Read1Byte
@@ -302,7 +281,7 @@ EFUSE_Read1Byte(struct net_device* dev, u16 Address)
else
return 0xFF;
-} /* EFUSE_Read1Byte */
+}
/*-----------------------------------------------------------------------------
@@ -324,13 +303,10 @@ EFUSE_Read1Byte(struct net_device* dev, u16 Address)
extern void
EFUSE_Write1Byte(struct net_device* dev, u16 Address,u8 Value)
{
- //u8 data;
u8 Bytetemp = {0x00};
u8 temp = {0x00};
u32 k=0;
- //RT_TRACE(COMP_EFUSE, "Addr=%x Data =%x\n", Address, Value);
-
if( Address < EFUSE_MAC_LEN) //E-fuse 512Byte
{
write_nic_byte(dev, EFUSE_CTRL, Value);
@@ -349,7 +325,6 @@ EFUSE_Write1Byte(struct net_device* dev, u16 Address,u8 Value)
temp = Bytetemp | 0x80;
write_nic_byte(dev, EFUSE_CTRL+3, temp);
- //Wait Write-ready (0x30[31]=0)
Bytetemp = read_nic_byte(dev, EFUSE_CTRL+3);
while(Bytetemp & 0x80)
{
@@ -363,8 +338,7 @@ EFUSE_Write1Byte(struct net_device* dev, u16 Address,u8 Value)
}
}
-} /* EFUSE_Write1Byte */
-
+}
#ifdef EFUSE_FOR_92SU
//
@@ -380,12 +354,10 @@ EFUSE_Write1Byte(struct net_device* dev, u16 Address,u8 Value)
//
void do_93c46(struct net_device* dev, u8 addorvalue)
{
- //u8 clear[1] = {0x0}; // cs=0 , sk=0 , di=0 , do=0
u8 cs[1] = {0x88}; // cs=1 , sk=0 , di=0 , do=0
u8 cssk[1] = {0x8c}; // cs=1 , sk=1 , di=0 , do=0
u8 csdi[1] = {0x8a}; // cs=1 , sk=0 , di=1 , do=0
u8 csskdi[1] = {0x8e}; // cs=1 , sk=1 , di=1 , do=0
- //u8 di[1] = {0x82}; // cs=0 , sk=0 , di=1 , do=0
u8 count;
for(count=0 ; count<8 ; count++)
@@ -424,7 +396,6 @@ u16 Read93C46(struct net_device* dev, u16 Reg )
u8 cssk[1] = {0x8c}; // cs=1 , sk=1 , di=0 , do=0
u8 csdi[1] = {0x8a}; // cs=1 , sk=0 , di=1 , do=0
u8 csskdi[1] = {0x8e}; // cs=1 , sk=1 , di=1 , do=0
- //u8 di[1] = {0x82}; // cs=0 , sk=0 , di=1 , do=0
u8 EepromSEL[1]={0x00};
u8 address;
@@ -434,7 +405,6 @@ u16 Read93C46(struct net_device* dev, u16 Reg )
address = (u8)Reg;
- // Suggested by SD1 Alex, 2008.10.20. Revised by Roger.
*EepromSEL= read_nic_byte(dev, EPROM_CMD);
if((*EepromSEL & 0x10) == 0x10) // select 93c46
@@ -486,13 +456,10 @@ u16 Read93C46(struct net_device* dev, u16 Reg )
void
ReadEFuseByte(struct net_device* dev,u16 _offset, u8 *pbuf)
{
-
- //u16 indexk=0;
u32 value32;
u8 readbyte;
u16 retry;
-
//Write Address
write_nic_byte(dev, EFUSE_CTRL+1, (_offset & 0xff));
readbyte = read_nic_byte(dev, EFUSE_CTRL+2);
@@ -505,7 +472,6 @@ ReadEFuseByte(struct net_device* dev,u16 _offset, u8 *pbuf)
//Check bit 32 read-ready
retry = 0;
value32 = read_nic_dword(dev, EFUSE_CTRL);
- //while(!(((value32 >> 24) & 0xff) & 0x80) && (retry<10))
while(!(((value32 >> 24) & 0xff) & 0x80) && (retry<10000))
{
value32 = read_nic_dword(dev, EFUSE_CTRL);
@@ -532,78 +498,145 @@ void
ReadEFuse(struct net_device* dev, u16 _offset, u16 _size_byte, u8 *pbuf)
{
- u8 efuseTbl[128];
+ struct r8192_priv *priv = ieee80211_priv(dev);
+ u8 efuseTbl[EFUSE_MAP_LEN];
u8 rtemp8[1];
u16 eFuse_Addr = 0;
u8 offset, wren;
u16 i, j;
- u16 eFuseWord[16][4];// = {0xFF};//FIXLZM
-
- for(i=0; i<16; i++)
- for(j=0; j<4; j++)
- eFuseWord[i][j]=0xFF;
+ u16 eFuseWord[EFUSE_MAX_SECTION][EFUSE_MAX_WORD_UNIT];
+ u16 efuse_utilized = 0;
+ u16 efuse_usage = 0;
- // Do NOT excess total size of EFuse table. Added by Roger, 2008.11.10.
- if((_offset + _size_byte)>128)
- {// total E-Fuse table is 128bytes
- //RT_TRACE(COMP_EFUSE, "ReadEFuse(): Invalid offset(%#x) with read bytes(%#x)!!\n",_offset, _size_byte);
+ if((_offset + _size_byte)>EFUSE_MAP_LEN)
+ {
printk("ReadEFuse(): Invalid offset with read bytes!!\n");
return;
}
- // Refresh efuse init map as all oxFF.
- for (i = 0; i < 128; i++)
- efuseTbl[i] = 0xFF;
+ for(i = 0; i < EFUSE_MAX_SECTION; i++)
+ for(j = 0; j < EFUSE_MAX_WORD_UNIT; j++)
+ eFuseWord[i][j]=0xFFFF;
#if (EFUSE_READ_SWITCH == 1)
ReadEFuseByte(dev, eFuse_Addr, rtemp8);
#else
rtemp8[0] = EFUSE_Read1Byte(dev, eFuse_Addr);
#endif
- if(*rtemp8 != 0xFF) eFuse_Addr++;
- while((*rtemp8 != 0xFF) && (eFuse_Addr < 512)){
+ if(*rtemp8 != 0xFF){
+ efuse_utilized++;
+ RT_TRACE(COMP_EPROM, "Addr=%d\n", eFuse_Addr);
+ eFuse_Addr++;
+ }
+
+ while((*rtemp8 != 0xFF) && (eFuse_Addr < EFUSE_REAL_CONTENT_LEN))
+ {
offset = ((*rtemp8 >> 4) & 0x0f);
- if(offset <= 0x0F){
+ if(offset < EFUSE_MAX_SECTION)
+ {
wren = (*rtemp8 & 0x0f);
- for(i=0; i<4; i++){
- if(!(wren & 0x01)){
+ RT_TRACE(COMP_EPROM, "Offset-%d Worden=%x\n", offset, wren);
+
+ for(i = 0; i < EFUSE_MAX_WORD_UNIT; i++)
+ {
+ if(!(wren & 0x01))
+ {
+ RT_TRACE(COMP_EPROM, "Addr=%d\n", eFuse_Addr);
#if (EFUSE_READ_SWITCH == 1)
ReadEFuseByte(dev, eFuse_Addr, rtemp8); eFuse_Addr++;
#else
rtemp8[0] = EFUSE_Read1Byte(dev, eFuse_Addr); eFuse_Addr++;
#endif
+ efuse_utilized++;
eFuseWord[offset][i] = (*rtemp8 & 0xff);
- if(eFuse_Addr >= 512) break;
+ if(eFuse_Addr >= EFUSE_REAL_CONTENT_LEN)
+ break;
+
+ RT_TRACE(COMP_EPROM, "Addr=%d\n", eFuse_Addr);
#if (EFUSE_READ_SWITCH == 1)
ReadEFuseByte(dev, eFuse_Addr, rtemp8); eFuse_Addr++;
#else
rtemp8[0] = EFUSE_Read1Byte(dev, eFuse_Addr); eFuse_Addr++;
#endif
+ efuse_utilized++;
eFuseWord[offset][i] |= (((u16)*rtemp8 << 8) & 0xff00);
- if(eFuse_Addr >= 512) break;
+ if(eFuse_Addr >= EFUSE_REAL_CONTENT_LEN)
+ break;
}
wren >>= 1;
}
}
+
+ RT_TRACE(COMP_EPROM, "Addr=%d\n", eFuse_Addr);
#if (EFUSE_READ_SWITCH == 1)
ReadEFuseByte(dev, eFuse_Addr, rtemp8);
#else
rtemp8[0] = EFUSE_Read1Byte(dev, eFuse_Addr); eFuse_Addr++;
#endif
- if(*rtemp8 != 0xFF && (eFuse_Addr < 512)) eFuse_Addr++;
+ if(*rtemp8 != 0xFF && (eFuse_Addr < 512))
+ {
+ efuse_utilized++;
+ eFuse_Addr++;
+ }
}
- for(i=0; i<16; i++){
- for(j=0; j<4; j++){
+ for(i=0; i<EFUSE_MAX_SECTION; i++)
+ {
+ for(j=0; j<EFUSE_MAX_WORD_UNIT; j++)
+ {
efuseTbl[(i*8)+(j*2)]=(eFuseWord[i][j] & 0xff);
efuseTbl[(i*8)+((j*2)+1)]=((eFuseWord[i][j] >> 8) & 0xff);
}
}
for(i=0; i<_size_byte; i++)
pbuf[i] = efuseTbl[_offset+i];
+
+ efuse_usage = (u8)((efuse_utilized*100)/EFUSE_REAL_CONTENT_LEN);
+ priv->EfuseUsedBytes = efuse_utilized;
+ priv->EfuseUsedPercentage = (u8)efuse_usage;
}
-#endif // #if (EFUSE_FOR_92SU == 1)
+#endif
+
+extern bool
+EFUSE_ShadowUpdateChk(struct net_device* dev)
+{
+ struct r8192_priv *priv = ieee80211_priv(dev);
+ u8 SectionIdx, i, Base;
+ u16 WordsNeed = 0, HdrNum = 0, TotalBytes = 0, EfuseUsed = 0;
+ bool bWordChanged, bResult = true;
+
+ for (SectionIdx = 0; SectionIdx < 16; SectionIdx++)
+ {
+ Base = SectionIdx * 8;
+ bWordChanged = false;
+
+ for (i = 0; i < 8; i=i+2)
+ {
+ if((priv->EfuseMap[EFUSE_INIT_MAP][Base+i] !=
+ priv->EfuseMap[EFUSE_MODIFY_MAP][Base+i]) ||
+ (priv->EfuseMap[EFUSE_INIT_MAP][Base+i+1] !=
+ priv->EfuseMap[EFUSE_MODIFY_MAP][Base+i+1]))
+ {
+ WordsNeed++;
+ bWordChanged = true;
+ }
+ }
+ if( bWordChanged==true )
+ HdrNum++;
+ }
+
+ TotalBytes = HdrNum + WordsNeed*2;
+ EfuseUsed = priv->EfuseUsedBytes;
+
+ if( (TotalBytes + EfuseUsed) >= (EFUSE_MAX_SIZE-EFUSE_OOB_PROTECT_BYTES))
+ bResult = true;
+
+ RT_TRACE(COMP_EPROM, "EFUSE_ShadowUpdateChk(): TotalBytes(%x), HdrNum(%x), WordsNeed(%x), EfuseUsed(%d)\n",
+ TotalBytes, HdrNum, WordsNeed, EfuseUsed);
+
+ return bResult;
+}
/*-----------------------------------------------------------------------------
* Function: EFUSE_ShadowRead
@@ -624,8 +657,6 @@ ReadEFuse(struct net_device* dev, u16 _offset, u16 _size_byte, u8 *pbuf)
extern void
EFUSE_ShadowRead( struct net_device* dev, u8 Type, u16 Offset, u32 *Value)
{
- //HAL_DATA_TYPE *pHalData = GET_HAL_DATA(pAdapter);
-
if (Type == 1)
efuse_ShadowRead1Byte(dev, Offset, (u8 *)Value);
else if (Type == 2)
@@ -633,8 +664,7 @@ EFUSE_ShadowRead( struct net_device* dev, u8 Type, u16 Offset, u32 *Value)
else if (Type == 4)
efuse_ShadowRead4Byte(dev, Offset, (u32 *)Value);
-} // EFUSE_ShadowRead
-
+}
/*-----------------------------------------------------------------------------
* Function: EFUSE_ShadowWrite
@@ -655,8 +685,6 @@ EFUSE_ShadowRead( struct net_device* dev, u8 Type, u16 Offset, u32 *Value)
extern void
EFUSE_ShadowWrite( struct net_device* dev, u8 Type, u16 Offset,u32 Value)
{
- //HAL_DATA_TYPE *pHalData = GET_HAL_DATA(pAdapter);
-
if (Offset >= 0x18 && Offset <= 0x1F)
return;
@@ -667,8 +695,7 @@ EFUSE_ShadowWrite( struct net_device* dev, u8 Type, u16 Offset,u32 Value)
else if (Type == 4)
efuse_ShadowWrite4Byte(dev, Offset, (u32)Value);
-} // EFUSE_ShadowWrite
-
+}
/*-----------------------------------------------------------------------------
* Function: EFUSE_ShadowUpdate
@@ -686,15 +713,25 @@ EFUSE_ShadowWrite( struct net_device* dev, u8 Type, u16 Offset,u32 Value)
* 11/12/2008 MHC Create Version 0.
*
*---------------------------------------------------------------------------*/
-extern void
+extern bool
EFUSE_ShadowUpdate(struct net_device* dev)
{
- //HAL_DATA_TYPE *pHalData = GET_HAL_DATA(pAdapter);
struct r8192_priv *priv = ieee80211_priv(dev);
u16 i, offset, base = 0;
u8 word_en = 0x0F;
- bool first_pg = false;
- // For Efuse write action, we must enable LDO2.5V and 40MHZ clk.
+ bool first_pg = false;
+
+ RT_TRACE(COMP_EPROM, "--->EFUSE_ShadowUpdate()\n");
+
+ if(!EFUSE_ShadowUpdateChk(dev))
+ {
+ efuse_ReadAllMap(dev, &priv->EfuseMap[EFUSE_INIT_MAP][0]);
+ memcpy((void *)&priv->EfuseMap[EFUSE_MODIFY_MAP][0],
+ (void *)&priv->EfuseMap[EFUSE_INIT_MAP][0], HWSET_MAX_SIZE_92S);
+
+ RT_TRACE(COMP_EPROM, "<---EFUSE_ShadowUpdate(): Efuse out of capacity!!\n");
+ return false;
+ }
efuse_PowerSwitch(dev, TRUE);
//
@@ -712,16 +749,12 @@ EFUSE_ShadowUpdate(struct net_device* dev)
//
for (i = 0; i < 8; i++)
{
- if (offset == 0 && priv->EfuseMap[EFUSE_INIT_MAP][base+i] == 0xFF)
- {
- first_pg = TRUE;
- }
-
- // 2008/12/11 MH HW autoload fail workaround for A/BCUT.
-
if (first_pg == TRUE)
{
word_en &= ~(1<<(i/2));
+ RT_TRACE(COMP_EPROM,"Section(%x) Addr[%x] %x update to %x, Word_En=%02x\n",
+ offset, base+i, priv->EfuseMap[EFUSE_INIT_MAP][base+i],
+ priv->EfuseMap[EFUSE_MODIFY_MAP][base+i],word_en);
priv->EfuseMap[EFUSE_INIT_MAP][base+i] =
priv->EfuseMap[EFUSE_MODIFY_MAP][base+i];
}else
@@ -730,8 +763,9 @@ EFUSE_ShadowUpdate(struct net_device* dev)
priv->EfuseMap[EFUSE_MODIFY_MAP][base+i])
{
word_en &= ~(EFUSE_BIT(i/2));
- //RT_TRACE(COMP_EFUSE, "Offset=%d Addr%x %x ==> %x Word_En=%02x\n",
- //offset, base+i, priv->EfuseMap[0][base+i], priv->EfuseMap[1][base+i],word_en);
+ RT_TRACE(COMP_EPROM, "Section(%x) Addr[%x] %x update to %x, Word_En=%02x\n",
+ offset, base+i, priv->EfuseMap[0][base+i],
+ priv->EfuseMap[1][base+i],word_en);
// Update init table!!!
priv->EfuseMap[EFUSE_INIT_MAP][base+i] =
@@ -747,25 +781,27 @@ EFUSE_ShadowUpdate(struct net_device* dev)
{
u8 tmpdata[8];
- //FIXLZM
- memcpy(tmpdata, &(priv->EfuseMap[EFUSE_MODIFY_MAP][base]), 8);
- //RT_PRINT_DATA(COMP_INIT, DBG_LOUD, ("U-EFUSE\n"), tmpdata, 8);
- efuse_PgPacketWrite(dev,(u8)offset,word_en,tmpdata);
+ memcpy((void *)tmpdata, (void *)&(priv->EfuseMap[EFUSE_MODIFY_MAP][base]), 8);
+ RT_TRACE(COMP_INIT, "U-EFUSE\n");
+
+ if(!efuse_PgPacketWrite(dev,(u8)offset,word_en,tmpdata))
+ {
+ RT_TRACE(COMP_EPROM,"EFUSE_ShadowUpdate(): PG section(%x) fail!!\n", offset);
+ break;
+ }
}
}
- // 2008/12/01 MH For Efuse HW load bug workarounf method!!!!
- // We will force write 0x10EC into address 10&11 after all Efuse content.
- //
-
-
// For warm reboot, we must resume Efuse clock to 500K.
+
efuse_PowerSwitch(dev, FALSE);
- // 2008/12/01 MH We update shadow content again!!!!
- EFUSE_ShadowMapUpdate(dev);
-} // EFUSE_ShadowUpdate
+ efuse_ReadAllMap(dev, &priv->EfuseMap[EFUSE_INIT_MAP][0]);
+ memcpy((void *)&priv->EfuseMap[EFUSE_MODIFY_MAP][0],
+ (void *)&priv->EfuseMap[EFUSE_INIT_MAP][0], HWSET_MAX_SIZE_92S);
+ return true;
+}
/*-----------------------------------------------------------------------------
* Function: EFUSE_ShadowMapUpdate
@@ -792,12 +828,10 @@ extern void EFUSE_ShadowMapUpdate(struct net_device* dev)
}else{
efuse_ReadAllMap(dev, &priv->EfuseMap[EFUSE_INIT_MAP][0]);
}
- //PlatformMoveMemory(&priv->EfuseMap[EFUSE_MODIFY_MAP][0],
- //&priv->EfuseMap[EFUSE_INIT_MAP][0], HWSET_MAX_SIZE_92S);//FIXLZM
- memcpy(&priv->EfuseMap[EFUSE_MODIFY_MAP][0],
- &priv->EfuseMap[EFUSE_INIT_MAP][0], HWSET_MAX_SIZE_92S);
+ memcpy((void *)&priv->EfuseMap[EFUSE_MODIFY_MAP][0],
+ (void *)&priv->EfuseMap[EFUSE_INIT_MAP][0], HWSET_MAX_SIZE_92S);
-} // EFUSE_ShadowMapUpdate
+}
extern void
EFUSE_ForceWriteVendorId( struct net_device* dev)
@@ -810,7 +844,7 @@ EFUSE_ForceWriteVendorId( struct net_device* dev)
efuse_PowerSwitch(dev, FALSE);
-} // EFUSE_ForceWriteVendorId
+}
/*-----------------------------------------------------------------------------
* Function: efuse_ShadowRead1Byte
@@ -837,7 +871,7 @@ efuse_ShadowRead1Byte(struct net_device* dev, u16 Offset, u8 *Value)
*Value = priv->EfuseMap[EFUSE_MODIFY_MAP][Offset];
-} // EFUSE_ShadowRead1Byte
+}
//---------------Read Two Bytes
static void
@@ -848,7 +882,7 @@ efuse_ShadowRead2Byte(struct net_device* dev, u16 Offset, u16 *Value)
*Value = priv->EfuseMap[EFUSE_MODIFY_MAP][Offset];
*Value |= priv->EfuseMap[EFUSE_MODIFY_MAP][Offset+1]<<8;
-} // EFUSE_ShadowRead2Byte
+}
//---------------Read Four Bytes
static void
@@ -861,7 +895,7 @@ efuse_ShadowRead4Byte(struct net_device* dev, u16 Offset, u32 *Value)
*Value |= priv->EfuseMap[EFUSE_MODIFY_MAP][Offset+2]<<16;
*Value |= priv->EfuseMap[EFUSE_MODIFY_MAP][Offset+3]<<24;
-} // efuse_ShadowRead4Byte
+}
@@ -890,7 +924,7 @@ efuse_ShadowWrite1Byte(struct net_device* dev, u16 Offset, u8 Value)
priv->EfuseMap[EFUSE_MODIFY_MAP][Offset] = Value;
-} // efuse_ShadowWrite1Byte
+}
//---------------Write Two Bytes
static void
@@ -901,7 +935,7 @@ efuse_ShadowWrite2Byte(struct net_device* dev, u16 Offset, u16 Value)
priv->EfuseMap[EFUSE_MODIFY_MAP][Offset] = Value&0x00FF;
priv->EfuseMap[EFUSE_MODIFY_MAP][Offset+1] = Value>>8;
-} // efuse_ShadowWrite1Byte
+}
//---------------Write Four Bytes
static void
@@ -914,10 +948,8 @@ efuse_ShadowWrite4Byte(struct net_device* dev, u16 Offset, u32 Value)
priv->EfuseMap[EFUSE_MODIFY_MAP][Offset+2] = (u8)((Value>>16)&0x00FF);
priv->EfuseMap[EFUSE_MODIFY_MAP][Offset+3] = (u8)((Value>>24)&0xFF);
-} // efuse_ShadowWrite1Byte
-
+}
-/* 11/16/2008 MH Read one byte from real Efuse. */
static u8
efuse_OneByteRead(struct net_device* dev, u16 addr,u8 *data)
{
@@ -947,7 +979,7 @@ efuse_OneByteRead(struct net_device* dev, u16 addr,u8 *data)
bResult = FALSE;
}
return bResult;
-} // efuse_OneByteRead
+}
/* 11/16/2008 MH Write one byte to reald Efuse. */
static u8
@@ -956,10 +988,6 @@ efuse_OneByteWrite(struct net_device* dev, u16 addr, u8 data)
u8 tmpidx = 0;
u8 bResult;
- //RT_TRACE(COMP_EFUSE, "Addr = %x Data=%x\n", addr, data);
-
- //return 0;
-
// -----------------e-fuse reg ctrl ---------------------------------
//address
write_nic_byte(dev, EFUSE_CTRL+1, (u8)(addr&0xff));
@@ -983,8 +1011,7 @@ efuse_OneByteWrite(struct net_device* dev, u16 addr, u8 data)
}
return bResult;
-} // efuse_OneByteWrite
-
+}
/*-----------------------------------------------------------------------------
* Function: efuse_ReadAllMap
@@ -1005,19 +1032,13 @@ efuse_OneByteWrite(struct net_device* dev, u16 addr, u8 data)
static void
efuse_ReadAllMap(struct net_device* dev, u8 *Efuse)
{
- //u8 pg_data[8];
- //u8 offset = 0;
- //u8 tmpidx;
- //static u8 index = 0;
-
//
// We must enable clock and LDO 2.5V otherwise, read all map will be fail!!!!
//
efuse_PowerSwitch(dev, TRUE);
ReadEFuse(dev, 0, 128, Efuse);
efuse_PowerSwitch(dev, FALSE);
-} // efuse_ReadAllMap
-
+}
/*-----------------------------------------------------------------------------
* Function: efuse_WriteAllMap
@@ -1057,18 +1078,11 @@ efuse_WriteAllMap(struct net_device* dev,u8 *eeprom, u32 eeprom_size)
// 0x18-1f Reserve >0x50 Reserve for tx power
if (offset == 3/* || offset > 9*/)
continue;//word_en = 0x0F;
- //else if (offset == 9) // 0x4c-4f Reserve
- //word_en = 0x0C;
else
word_en = 0x00;
}
- //RT_TRACE(COMP_EFUSE, ("Addr=%d size=%d Word_En=%02x\n", offset, eeprom_size, word_en));
- //memcpy(tmpdata,eeprom+(offset*PGPKT_DATA_SIZE),8);
memcpy(tmpdata, (eeprom+(offset*PGPKT_DATA_SIZE)), 8);
-
- //RT_PRINT_DATA(COMP_INIT, DBG_LOUD, ("EFUSE\t"), tmpdata, 8);
-
efuse_PgPacketWrite(dev,offset,word_en,tmpdata);
@@ -1077,7 +1091,7 @@ efuse_WriteAllMap(struct net_device* dev,u8 *eeprom, u32 eeprom_size)
// For warm reboot, we must resume Efuse clock to 500K.
efuse_PowerSwitch(dev, FALSE);
-} // efuse_WriteAllMap
+}
#endif
/*-----------------------------------------------------------------------------
@@ -1114,15 +1128,9 @@ efuse_PgPacketRead( struct net_device* dev, u8 offset, u8 *data)
if(data==NULL) return FALSE;
if(offset>15) return FALSE;
- //FIXLZM
- //PlatformFillMemory((PVOID)data, sizeof(u8)*PGPKT_DATA_SIZE, 0xff);
- //PlatformFillMemory((PVOID)tmpdata, sizeof(u8)*PGPKT_DATA_SIZE, 0xff);
memset(data, 0xff, sizeof(u8)*PGPKT_DATA_SIZE);
memset(tmpdata, 0xff, sizeof(u8)*PGPKT_DATA_SIZE);
- //RT_PRINT_DATA(COMP_EFUSE, DBG_LOUD, ("efuse_PgPacketRead-1\n"), data, 8);
-
- //efuse_reg_ctrl(pAdapter,TRUE);//power on
while(bContinual && (efuse_addr < EFUSE_MAX_SIZE) )
{
//------- Header Read -------------
@@ -1169,9 +1177,6 @@ efuse_PgPacketRead( struct net_device* dev, u8 offset, u8 *data)
}
}
- //efuse_reg_ctrl(pAdapter,FALSE);//power off
-
- //RT_PRINT_DATA(COMP_EFUSE, DBG_LOUD, ("efuse_PgPacketRead-2\n"), data, 8);
if( (data[0]==0xff) &&(data[1]==0xff) && (data[2]==0xff) && (data[3]==0xff) &&
(data[4]==0xff) &&(data[5]==0xff) && (data[6]==0xff) && (data[7]==0xff))
@@ -1179,8 +1184,7 @@ efuse_PgPacketRead( struct net_device* dev, u8 offset, u8 *data)
else
return TRUE;
-} // efuse_PgPacketRead
-
+}
/*-----------------------------------------------------------------------------
* Function: efuse_PgPacketWrite
@@ -1200,7 +1204,7 @@ efuse_PgPacketRead( struct net_device* dev, u8 offset, u8 *data)
* 11/16/2008 MHC Reorganize code Arch and assign as local API.
*
*---------------------------------------------------------------------------*/
-static u8 efuse_PgPacketWrite(struct net_device* dev, u8 offset, u8 word_en,u8 *data)
+static u32 efuse_PgPacketWrite(struct net_device* dev, u8 offset, u8 word_en,u8 *data)
{
u8 WriteState = PG_STATE_HEADER;
@@ -1210,12 +1214,9 @@ static u8 efuse_PgPacketWrite(struct net_device* dev, u8 offset, u8 word_en,u8 *
u8 pg_header = 0;
- //u16 tmp_addr=0;
u8 tmp_word_cnts=0,target_word_cnts=0;
u8 tmp_header,match_word_en,tmp_word_en;
- //u8 efuse_clk_ori,efuse_clk_new;
-
PGPKT_STRUCT target_pkt;
PGPKT_STRUCT tmp_pkt;
@@ -1240,7 +1241,6 @@ static u8 efuse_PgPacketWrite(struct net_device* dev, u8 offset, u8 word_en,u8 *
efuse_WordEnableDataRead(word_en,data,target_pkt.data);
target_word_cnts = efuse_CalculateWordCnts(target_pkt.word_en);
- //efuse_reg_ctrl(pAdapter,TRUE);//power on
printk("EFUSE Power ON\n");
while( bContinual && (efuse_addr < EFUSE_MAX_SIZE) )
@@ -1312,14 +1312,12 @@ static u8 efuse_PgPacketWrite(struct net_device* dev, u8 offset, u8 word_en,u8 *
badworden = efuse_WordEnableDataWrite(dev,efuse_addr+1, tmp_pkt.word_en ,target_pkt.data);
//************ so-2-2-A-1 *******************
- //############################
if(0x0F != (badworden&0x0F))
{
u8 reorg_offset = offset;
u8 reorg_worden=badworden;
efuse_PgPacketWrite(dev,reorg_offset,reorg_worden,originaldata);
}
- //############################
tmp_word_en = 0x0F;
if( (target_pkt.word_en&BIT0)^(match_word_en&BIT0) )
@@ -1342,13 +1340,13 @@ static u8 efuse_PgPacketWrite(struct net_device* dev, u8 offset, u8 word_en,u8 *
//************ so-2-2-A-2 *******************
if((tmp_word_en&0x0F)!=0x0F){
//reorganize other pg packet
- //efuse_addr = efuse_addr + (2*tmp_word_cnts) +1;//next pg packet addr
- efuse_addr = efuse_GetCurrentSize(dev);
- //===========================
- target_pkt.offset = offset;
+
+ efuse_addr = efuse_GetCurrentSize(dev);
+
+ target_pkt.offset = offset;
target_pkt.word_en= tmp_word_en;
- //===========================
- }else{
+
+ }else{
bContinual = FALSE;
}
#if (EFUSE_ERROE_HANDLE == 1)
@@ -1363,10 +1361,8 @@ static u8 efuse_PgPacketWrite(struct net_device* dev, u8 offset, u8 word_en,u8 *
else{//************ so-2-2-B *******************
//reorganize other pg packet
efuse_addr = efuse_addr + (2*tmp_word_cnts) +1;//next pg packet addr
- //===========================
target_pkt.offset = offset;
target_pkt.word_en= target_pkt.word_en;
- //===========================
#if (EFUSE_ERROE_HANDLE == 1)
WriteState=PG_STATE_HEADER;
#endif
@@ -1405,13 +1401,10 @@ static u8 efuse_PgPacketWrite(struct net_device* dev, u8 offset, u8 word_en,u8 *
//************ s1-2-A :cover the exist data *******************
memset(originaldata,0xff,sizeof(u8)*8);
- //PlatformFillMemory((PVOID)originaldata, sizeof(u8)*8, 0xff);
if(efuse_PgPacketRead( dev, tmp_pkt.offset,originaldata))
{ //check if data exist
- //efuse_reg_ctrl(pAdapter,TRUE);//power on
badworden = efuse_WordEnableDataWrite(dev,efuse_addr+1,tmp_pkt.word_en,originaldata);
- //############################
if(0x0F != (badworden&0x0F))
{
u8 reorg_offset = tmp_pkt.offset;
@@ -1419,7 +1412,6 @@ static u8 efuse_PgPacketWrite(struct net_device* dev, u8 offset, u8 word_en,u8 *
efuse_PgPacketWrite(dev,reorg_offset,reorg_worden,originaldata);
efuse_addr = efuse_GetCurrentSize(dev);
}
- //############################
else{
efuse_addr = efuse_addr + (tmp_word_cnts*2) +1; //Next pg_packet
}
@@ -1459,11 +1451,9 @@ static u8 efuse_PgPacketWrite(struct net_device* dev, u8 offset, u8 word_en,u8 *
{//reorganize other pg packet //************ s1-1-B *******************
efuse_addr = efuse_addr + (2*target_word_cnts) +1;//next pg packet addr
- //===========================
target_pkt.offset = offset;
target_pkt.word_en= badworden;
target_word_cnts = efuse_CalculateWordCnts(target_pkt.word_en);
- //===========================
#if (EFUSE_ERROE_HANDLE == 1)
WriteState=PG_STATE_HEADER;
repeat_times++;
@@ -1477,11 +1467,12 @@ static u8 efuse_PgPacketWrite(struct net_device* dev, u8 offset, u8 word_en,u8 *
}
}
- //efuse_reg_ctrl(pAdapter,FALSE);//power off
-
+ if(efuse_addr >= (EFUSE_MAX_SIZE-EFUSE_OOB_PROTECT_BYTES))
+ {
+ RT_TRACE(COMP_EPROM, "efuse_PgPacketWrite(): efuse_addr(%x) Out of size!!\n", efuse_addr);
+ }
return TRUE;
-} // efuse_PgPacketWrite
-
+}
/*-----------------------------------------------------------------------------
* Function: efuse_WordEnableDataRead
@@ -1503,12 +1494,6 @@ static u8 efuse_PgPacketWrite(struct net_device* dev, u8 offset, u8 word_en,u8 *
static void
efuse_WordEnableDataRead( u8 word_en,u8 *sourdata,u8 *targetdata)
{
- //u8 tmpindex = 0;
-
- //DbgPrint("efuse_WordEnableDataRead word_en = %x\n", word_en);
-
- //RT_PRINT_DATA(COMP_EFUSE, DBG_LOUD, ("sourdata\n"), sourdata, 8);
- //RT_PRINT_DATA(COMP_EFUSE, DBG_LOUD, ("targetdata\n"), targetdata, 8);
if (!(word_en&BIT0))
{
@@ -1530,8 +1515,7 @@ efuse_WordEnableDataRead( u8 word_en,u8 *sourdata,u8 *targetdata)
targetdata[6] = sourdata[6];//sourdata[tmpindex++];
targetdata[7] = sourdata[7];//sourdata[tmpindex++];
}
-} // efuse_WordEnableDataRead
-
+}
/*-----------------------------------------------------------------------------
* Function: efuse_WordEnableDataWrite
@@ -1555,15 +1539,9 @@ efuse_WordEnableDataWrite( struct net_device* dev, u16 efuse_addr, u8 word_en, u
u16 tmpaddr = 0;
u16 start_addr = efuse_addr;
u8 badworden = 0x0F;
- //u8 NextState;
u8 tmpdata[8];
memset(tmpdata,0xff,PGPKT_DATA_SIZE);
- //PlatformFillMemory((PVOID)tmpdata, PGPKT_DATA_SIZE, 0xff);
-
- //RT_TRACE(COMP_EFUSE, "word_en = %x efuse_addr=%x\n", word_en, efuse_addr);
-
- //RT_PRINT_DATA(COMP_EFUSE, DBG_LOUD, ("U-EFUSE\n"), data, 8);
if(!(word_en&BIT0))
{
@@ -1614,8 +1592,7 @@ efuse_WordEnableDataWrite( struct net_device* dev, u16 efuse_addr, u8 word_en, u
}
}
return badworden;
-} // efuse_WordEnableDataWrite
-
+}
/*-----------------------------------------------------------------------------
* Function: efuse_PowerSwitch
@@ -1658,8 +1635,7 @@ efuse_PowerSwitch(struct net_device* dev, u8 PwrState)
write_nic_byte(dev, EFUSE_CLK, 0x02);
}
-} /* efuse_PowerSwitch */
-
+}
/*-----------------------------------------------------------------------------
* Function: efuse_GetCurrentSize
@@ -1686,8 +1662,6 @@ efuse_GetCurrentSize(struct net_device* dev)
u8 hoffset=0,hworden=0;
u8 efuse_data,word_cnts=0;
- //efuse_reg_ctrl(pAdapter,TRUE);//power on
-
while ( bContinual &&
efuse_OneByteRead(dev, efuse_addr ,&efuse_data) &&
(efuse_addr < EFUSE_MAX_SIZE) )
@@ -1706,12 +1680,9 @@ efuse_GetCurrentSize(struct net_device* dev)
}
}
- //efuse_reg_ctrl(pAdapter,FALSE);//power off
-
return efuse_addr;
-} // efuse_GetCurrentSize}
-
+}
/* 11/16/2008 MH Add description. Get current efuse area enabled word!!. */
static u8
@@ -1723,7 +1694,7 @@ efuse_CalculateWordCnts(u8 word_en)
if(!(word_en & BIT2)) word_cnts++;
if(!(word_en & BIT3)) word_cnts++;
return word_cnts;
-} // efuse_CalculateWordCnts
+}
/*-----------------------------------------------------------------------------
* Function: EFUSE_ProgramMap
@@ -1786,12 +1757,10 @@ EFUSE_ProgramMap(struct net_device* dev, char* pFileName,u8 TableType)
{
u32 j;
- //GetHexValueFromString(szLine, &u4bRegValue, &u4bMove);
efuse_ParsingMap(szLine, &u4bRegValue, &u4bMove);
// Get next hex value as EEPROM value.
szLine += u4bMove;
- //WriteEEprom(dev, (u16)(ithLine*8+i), (u16)u4bRegValue);
eeprom[index++] = (u8)(u4bRegValue&0xff);
eeprom[index++] = (u8)((u4bRegValue>>8)&0xff);
@@ -1808,9 +1777,6 @@ EFUSE_ProgramMap(struct net_device* dev, char* pFileName,u8 TableType)
return RT_STATUS_FAILURE;
}
-
- //RT_PRINT_DATA(COMP_EFUSE, DBG_LOUD, ("EFUSE "), eeprom, HWSET_MAX_SIZE_92S);
-
// Use map file to update real Efuse or shadow modify table.
if (TableType == 1)
{
@@ -1824,45 +1790,9 @@ EFUSE_ProgramMap(struct net_device* dev, char* pFileName,u8 TableType)
}
return rtStatus;
-} /* EFUSE_ProgramMap */
-
-#endif
-
-//
-// Description:
-// Return TRUE if chTmp is represent for hex digit and
-// FALSE otherwise.
-//
-//
-bool IsHexDigit( char chTmp)
-{
- if( (chTmp >= '0' && chTmp <= '9') ||
- (chTmp >= 'a' && chTmp <= 'f') ||
- (chTmp >= 'A' && chTmp <= 'F') )
- {
- return TRUE;
- }
- else
- {
- return FALSE;
- }
}
-//
-// Description:
-// Translate a character to hex digit.
-//
-u32 MapCharToHexDigit(char chTmp)
-{
- if(chTmp >= '0' && chTmp <= '9')
- return (chTmp - '0');
- else if(chTmp >= 'a' && chTmp <= 'f')
- return (10 + (chTmp - 'a'));
- else if(chTmp >= 'A' && chTmp <= 'F')
- return (10 + (chTmp - 'A'));
- else
- return 0;
-}
+#endif
/*-----------------------------------------------------------------------------
* Function: efuse_ParsingMap
@@ -1889,9 +1819,6 @@ efuse_ParsingMap(char* szStr,u32* pu4bVal,u32* pu4bMove)
// Check input parameter.
if(szStr == NULL || pu4bVal == NULL || pu4bMove == NULL)
{
- //RT_TRACE(COMP_EFUSE,
- //"eeprom_ParsingMap(): Invalid IN args! szStr: %p, pu4bVal: %p, pu4bMove: %p\n",
- //szStr, pu4bVal, pu4bMove);
return FALSE;
}
@@ -1909,34 +1836,26 @@ efuse_ParsingMap(char* szStr,u32* pu4bVal,u32* pu4bMove)
// Check if szScan is now pointer to a character for hex digit,
// if not, it means this is not a valid hex number.
- if(!IsHexDigit(*szScan))
- {
+ if (!isxdigit(*szScan))
return FALSE;
- }
// Parse each digit.
do
{
- (*pu4bVal) <<= 4;
- *pu4bVal += MapCharToHexDigit(*szScan);
+ *pu4bVal = (*pu4bVal << 4) + hex_to_bin(*szScan);
szScan++;
(*pu4bMove)++;
- } while(IsHexDigit(*szScan));
+ } while (isxdigit(*szScan));
return TRUE;
-} /* efuse_ParsingMap */
+}
#endif
-//
-// Useless Section Code Now!!!!!!
-//
-// Porting from 8712 SDIO
int efuse_one_byte_rw(struct net_device* dev, u8 bRead, u16 addr, u8 *data)
{
u32 bResult;
- //u8 efuse_ctlreg,tmpidx = 0;
u8 tmpidx = 0;
u8 tmpv8=0;
@@ -1965,7 +1884,6 @@ int efuse_one_byte_rw(struct net_device* dev, u8 bRead, u16 addr, u8 *data)
}
else{
- //return 0;
write_nic_byte(dev, EFUSE_CTRL, *data);//data
write_nic_byte(dev, EFUSE_CTRL+3, 0xF2);//write cmd
@@ -1987,21 +1905,18 @@ int efuse_one_byte_rw(struct net_device* dev, u8 bRead, u16 addr, u8 *data)
}
return bResult;
}
-//------------------------------------------------------------------------------
+
void efuse_access(struct net_device* dev, u8 bRead,u16 start_addr, u8 cnts, u8 *data)
{
u8 efuse_clk_ori,efuse_clk_new;//,tmp8;
u32 i = 0;
if(start_addr>0x200) return;
- //RT_TRACE(_module_rtl871x_mp_ioctl_c_,_drv_err_,
- // ("\n ===> efuse_access [start_addr=0x%x cnts:%d dataarray:0x%08x Query Efuse].\n",start_addr,cnts,data));
// -----------------SYS_FUNC_EN Digital Core Vdd enable ---------------------------------
efuse_clk_ori = read_nic_byte(dev,SYS_FUNC_EN+1);
efuse_clk_new = efuse_clk_ori|0x20;
if(efuse_clk_new!= efuse_clk_ori){
- //RT_TRACE(_module_rtl871x_mp_ioctl_c_,_drv_err_,("====write 0x10250003=====\n"));
write_nic_byte(dev, SYS_FUNC_EN+1, efuse_clk_new);
}
#ifdef _POWERON_DELAY_
@@ -2021,9 +1936,8 @@ void efuse_access(struct net_device* dev, u8 bRead,u16 start_addr, u8 cnts, u8 *
//-----------------e-fuse one byte read / write ------------------------------
for(i=0;i<cnts;i++){
efuse_one_byte_rw(dev,bRead, start_addr+i , data+i);
- ////RT_TRACE(_module_rtl871x_mp_ioctl_c_,_drv_err_,("==>efuse_access addr:0x%02x value:0x%02x\n",data+i,*(data+i)));
+
}
- // -----------------e-fuse pwr & clk reg ctrl ---------------------------------
write_nic_byte(dev, EFUSE_TEST+3, read_nic_byte(dev, EFUSE_TEST+3)&0x7f);
write_nic_byte(dev, EFUSE_CLK_CTRL, read_nic_byte(dev, EFUSE_CLK_CTRL)&0xfd);
@@ -2031,8 +1945,6 @@ void efuse_access(struct net_device* dev, u8 bRead,u16 start_addr, u8 cnts, u8 *
if(efuse_clk_new != efuse_clk_ori) write_nic_byte(dev, 0x10250003, efuse_clk_ori);
}
-//------------------------------------------------------------------------------
-//------------------------------------------------------------------------------
#ifdef TO_DO_LIST
static void efuse_reg_ctrl(struct net_device* dev, u8 bPowerOn)
@@ -2060,15 +1972,12 @@ static void efuse_reg_ctrl(struct net_device* dev, u8 bPowerOn)
write_nic_byte(dev, EFUSE_CLK_CTRL, read_nic_byte(dev, EFUSE_CLK_CTRL)&0xfd);
// -----------------SYS_FUNC_EN Digital Core Vdd disable ---------------------------------
- //write_nic_byte(pAdapter, SYS_FUNC_EN+1, read_nic_byte(pAdapter,SYS_FUNC_EN+1)&0xDF);
}
}
#endif
-//------------------------------------------------------------------------------
-//------------------------------------------------------------------------------
void efuse_read_data(struct net_device* dev,u8 efuse_read_item,u8 *data,u32 data_size)
{
u8 offset, word_start,byte_start,byte_cnts;
@@ -2079,10 +1988,8 @@ void efuse_read_data(struct net_device* dev,u8 efuse_read_item,u8 *data,u32 data
u8 tmpidx;
u8 pg_data[8];
- //u8 temp_value[8] = {0xff};
if(efuse_read_item> (sizeof(RTL8712_SDIO_EFUSE_TABLE)/sizeof(EFUSE_MAP))){
- //error msg
return ;
}
@@ -2092,48 +1999,39 @@ void efuse_read_data(struct net_device* dev,u8 efuse_read_item,u8 *data,u32 data
byte_cnts = RTL8712_SDIO_EFUSE_TABLE[efuse_read_item].byte_cnts;
if(data_size!=byte_cnts){
- //error msg
return;
}
pg_pkt_cnts = (byte_cnts /PGPKT_DATA_SIZE) +1;
if(pg_pkt_cnts > 1){
- //tmpdata = _malloc(pg_pkt_cnts*PGPKT_DATA_SIZE);
tmpdata = efusedata;
if(tmpdata!=NULL)
{
memset(tmpdata,0xff,pg_pkt_cnts*PGPKT_DATA_SIZE);
- //PlatformFillMemory((PVOID)pg_data, pg_pkt_cnts*PGPKT_DATA_SIZE, 0xff);
for(tmpidx=0;tmpidx<pg_pkt_cnts;tmpidx++)
{
memset(pg_data,0xff,PGPKT_DATA_SIZE);
- //PlatformFillMemory((PVOID)pg_data, PGPKT_DATA_SIZE, 0xff);
if(TRUE== efuse_PgPacketRead(dev,offset+tmpidx,pg_data))
{
memcpy(tmpdata+(PGPKT_DATA_SIZE*tmpidx),pg_data,PGPKT_DATA_SIZE);
- //PlatformMoveMemory((PVOID)(tmpdata+(PGPKT_DATA_SIZE*tmpidx)), (PVOID)pg_data, PGPKT_DATA_SIZE);
}
}
memcpy(data,(tmpdata+ (2*word_start)+byte_start ),data_size);
- //PlatformMoveMemory((PVOID)data, (PVOID)(tmpdata+ (2*word_start)+byte_start ), data_size);
- //_mfree(tmpdata, pg_pkt_cnts*PGPKT_DATA_SIZE);
}
}
else
{
memset(pg_data,0xff,PGPKT_DATA_SIZE);
- //PlatformFillMemory((PVOID)pg_data, PGPKT_DATA_SIZE, 0xff);
if(TRUE==efuse_PgPacketRead(dev,offset,pg_data)){
memcpy(data,pg_data+ (2*word_start)+byte_start ,data_size);
- //PlatformMoveMemory((PVOID)data, (PVOID)(pg_data+ (2*word_start)+byte_start), data_size);
}
}
}
-//------------------------------------------------------------------------------
+
//per interface doesn't alike
void efuse_write_data(struct net_device* dev,u8 efuse_write_item,u8 *data,u32 data_size,u32 bWordUnit)
{
@@ -2145,7 +2043,6 @@ void efuse_write_data(struct net_device* dev,u8 efuse_write_item,u8 *data,u32 da
u8 pg_data[8],tmpbytes=0;
if(efuse_write_item> (sizeof(RTL8712_SDIO_EFUSE_TABLE)/sizeof(EFUSE_MAP))){
- //error msg
return ;
}
@@ -2155,7 +2052,6 @@ void efuse_write_data(struct net_device* dev,u8 efuse_write_item,u8 *data,u32 da
byte_cnts = RTL8712_SDIO_EFUSE_TABLE[efuse_write_item].byte_cnts;
if(data_size > byte_cnts){
- //error msg
return;
}
pg_pkt_cnts = (byte_cnts /PGPKT_DATA_SIZE) +1;
@@ -2168,13 +2064,11 @@ void efuse_write_data(struct net_device* dev,u8 efuse_write_item,u8 *data,u32 da
if((efuse_write_item==EFUSE_F0CIS)||(efuse_write_item==EFUSE_F1CIS)){
memset(pg_data,0xff,PGPKT_DATA_SIZE);
- //PlatformFillMemory((PVOID)pg_data, PGPKT_DATA_SIZE, 0xff);
efuse_PgPacketRead(dev,offset,pg_data);
if(efuse_write_item==EFUSE_F0CIS){
word_en = 0x07;
memcpy(pg_data+word_start*2+byte_start,data,sizeof(u8)*2);
- //PlatformMoveMemory((PVOID)(pg_data+word_start*2+byte_start), (PVOID)data, sizeof(u8)*2);
efuse_PgPacketWrite(dev,offset,word_en,pg_data+(word_start*2));
word_en = 0x00;
@@ -2183,7 +2077,6 @@ void efuse_write_data(struct net_device* dev,u8 efuse_write_item,u8 *data,u32 da
word_en = 0x00;
efuse_PgPacketRead(dev,offset+2,pg_data);
memcpy(pg_data,data+2+8,sizeof(u8)*7);
- //PlatformMoveMemory((PVOID)(pg_data), (PVOID)(data+2+8), sizeof(u8)*7);
efuse_PgPacketWrite(dev,(offset+2),word_en,pg_data);
}
@@ -2202,7 +2095,6 @@ void efuse_write_data(struct net_device* dev,u8 efuse_write_item,u8 *data,u32 da
}
else{
memset(pg_data,0xff,PGPKT_DATA_SIZE);
- //PlatformFillMemory((PVOID)pg_data, PGPKT_DATA_SIZE, 0xff);
if((efuse_write_item==EFUSE_SDIO_SETTING)||(efuse_write_item==EFUSE_CCCR)){
word_en = 0x0e ;
tmpbytes = 2;
@@ -2221,12 +2113,10 @@ void efuse_write_data(struct net_device* dev,u8 efuse_write_item,u8 *data,u32 da
}
if(bWordUnit==TRUE){
memcpy(pg_data+word_start*2 ,data,sizeof(u8)*tmpbytes);
- //PlatformMoveMemory((PVOID)(pg_data+word_start*2), (PVOID)(data), sizeof(u8)*tmpbytes);
}
else{
efuse_PgPacketRead(dev,offset,pg_data);
memcpy(pg_data+(2*word_start)+byte_start,data,sizeof(u8)*byte_cnts);
- //PlatformMoveMemory((PVOID)(pg_data+(2*word_start)+byte_start), (PVOID)(data), sizeof(u8)*byte_cnts);
}
efuse_PgPacketWrite(dev,offset,word_en,pg_data+(word_start*2));
@@ -2234,7 +2124,6 @@ void efuse_write_data(struct net_device* dev,u8 efuse_write_item,u8 *data,u32 da
}
}
- //========================================================================
else if(pg_pkt_cnts>1){//situation B
if(word_start==0){
word_en = 0x00;
@@ -2255,7 +2144,6 @@ void efuse_write_data(struct net_device* dev,u8 efuse_write_item,u8 *data,u32 da
}
}
- //========================================================================
else{//situation C
word_en = 0x0f;
for(tmpidx= 0; tmpidx<word_cnts ; tmpidx++)
@@ -2267,7 +2155,6 @@ void efuse_write_data(struct net_device* dev,u8 efuse_write_item,u8 *data,u32 da
}
}
-//------------------------------------------------------------------------------
void efuset_test_func_read(struct net_device* dev)
{
@@ -2288,7 +2175,6 @@ void efuset_test_func_read(struct net_device* dev)
memset(txpowertable,0,sizeof(u8)*28);
efuse_read_data(dev,EFUSE_TXPW_TAB,txpowertable,sizeof(txpowertable));
}
-//------------------------------------------------------------------------------
void efuset_test_func_write(struct net_device* dev)
{
@@ -2311,19 +2197,3 @@ void efuset_test_func_write(struct net_device* dev)
efuse_write_data(dev,EFUSE_SDIO_SETTING,tmpdata,sizeof(tmpdata),bWordUnit);
}
-//------------------------------------------------------------------------------
-
-
-
-
-
-
-
-
-
-
-/* End of Efuse.c */
-
-
-
-
diff --git a/drivers/staging/rtl8192su/r8192S_Efuse.h b/drivers/staging/rtl8192su/r8192S_Efuse.h
index 1e50153ba02..c48a11bc06f 100644
--- a/drivers/staging/rtl8192su/r8192S_Efuse.h
+++ b/drivers/staging/rtl8192su/r8192S_Efuse.h
@@ -1,39 +1,38 @@
/******************************************************************************
+ * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved.
*
- * (c) Copyright 2008, RealTEK Technologies Inc. All Rights Reserved.
+ * Based on the r8180 driver, which is:
+ * Copyright 2004-2005 Andrea Merello <andreamrl@tiscali.it>, et al.
+ * 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.
*
- * Module: Efuse.h ( Header File)
+ * 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.
*
- * Note:
- *
- * Function:
- *
- * Export:
- *
- * Abbrev:
- *
- * History:
- * Data Who Remark
- *
- * 09/23/2008 MHC Porting Efuse R/W API from WMAC.
- * 11/10/2008 MHC Porting Efuse.h from 8712 SDIO.
- * 1. We muse redefine the header file to fit our coding
- * style.
- * 2. THe API we export to other module, we must redefine
- * for 8192S series.
+ * 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, USA
*
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
*
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
******************************************************************************/
-/* Check to see if the file has been included already. */
#ifndef __INC_EFUSE_H
#define __INC_EFUSE_H
-// Roger porting for 8192SU
#define EFUSE_FOR_92SU 1
-/*--------------------------Define Parameters-------------------------------*/
#define EFUSE_MAC_LEN 0x200
+#define EFUSE_REAL_CONTENT_LEN 512
+#define EFUSE_MAP_LEN 128
+#define EFUSE_MAX_SECTION 16
+#define EFUSE_MAX_WORD_UNIT 4
#define EFUSE_INIT_MAP 0
#define EFUSE_MODIFY_MAP 1
@@ -41,7 +40,6 @@
#define EFUSE_CLK_CTRL EFUSE_CTRL
#define EFUSE_BIT(x) (1 << (x))
-// From 8712!!!!!!!!
#define PG_STATE_HEADER 0x01
#define PG_STATE_WORD_0 0x02
#define PG_STATE_WORD_1 0x04
@@ -52,23 +50,6 @@
#define PG_SWBYTE_H 0x01
#define PG_SWBYTE_L 0x02
-/*--------------------------Define Parameters-------------------------------*/
-
-
-/*------------------------------Define structure----------------------------*/
-
-/*------------------------------Define structure----------------------------*/
-
-
-/*------------------------Export global variable----------------------------*/
-/*------------------------Export global variable----------------------------*/
-
-/*------------------------Export Marco Definition---------------------------*/
-
-/*------------------------Export Marco Definition---------------------------*/
-
-
-/*--------------------------Exported Function prototype---------------------*/
extern void
EFUSE_Initialize(struct net_device* dev);
extern u8
@@ -81,21 +62,18 @@ extern void
ReadEFuse(struct net_device* dev,u16 _offset,u16 _size_byte,u8* pbuf);
extern void
ReadEFuseByte(struct net_device* dev,u16 _offset,u8 *pbuf);
-#endif // #if (EFUSE_FOR_92SU == 1)
+#endif
extern void
EFUSE_ShadowRead(struct net_device* dev,unsigned char Type,unsigned short Offset,u32 *Value);
extern void
EFUSE_ShadowWrite(struct net_device* dev,unsigned char Type,unsigned short Offset,u32 Value);
-extern void
+extern bool
EFUSE_ShadowUpdate(struct net_device* dev);
extern void
EFUSE_ShadowMapUpdate(struct net_device* dev);
extern bool
EFUSE_ProgramMap(struct net_device* dev,char* pFileName, u8 TableType); // 0=Shadow 1=Real Efuse
-/*--------------------------Exported Function prototype---------------------*/
-
-/* End of Efuse.h */
-#endif //__INC_EFUSE_H
+#endif
diff --git a/drivers/staging/rtl8192su/r8192S_firmware.c b/drivers/staging/rtl8192su/r8192S_firmware.c
index 5036d547d5d..db0d2d5fc61 100644
--- a/drivers/staging/rtl8192su/r8192S_firmware.c
+++ b/drivers/staging/rtl8192su/r8192S_firmware.c
@@ -1,16 +1,22 @@
-/**************************************************************************************************
- * Procedure: Init boot code/firmware code/data session
+/******************************************************************************
+ * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved.
*
- * Description: This routine will intialize firmware. If any error occurs during the initialization
- * process, the routine shall terminate immediately and return fail.
- * NIC driver should call NdisOpenFile only from MiniportInitialize.
+ * 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.
*
- * Arguments: The pointer of the adapter
+ * 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, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+******************************************************************************/
- * Returns:
- * NDIS_STATUS_FAILURE - the following initialization process should be terminated
- * NDIS_STATUS_SUCCESS - if firmware initialization process success
-**************************************************************************************************/
#include "r8192U.h"
#include "r8192S_firmware.h"
#include <linux/unistd.h>
diff --git a/drivers/staging/rtl8192su/r8192S_firmware.h b/drivers/staging/rtl8192su/r8192S_firmware.h
index 2c2cf8032de..7f268a8de5e 100644
--- a/drivers/staging/rtl8192su/r8192S_firmware.h
+++ b/drivers/staging/rtl8192su/r8192S_firmware.h
@@ -1,44 +1,32 @@
+/******************************************************************************
+ * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved.
+ *
+ * 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, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+******************************************************************************/
#ifndef __INC_FIRMWARE_H
#define __INC_FIRMWARE_H
-//#define RTL8190_CPU_START_OFFSET 0x80
-/* TODO: this definition is TBD */
-//#define USB_HWDESC_HEADER_LEN 0
-
-/* It should be double word alignment */
-//#if DEV_BUS_TYPE==PCI_INTERFACE
-//#define GET_COMMAND_PACKET_FRAG_THRESHOLD(v) 4*(v/4) - 8
-//#else
-//#define GET_COMMAND_PACKET_FRAG_THRESHOLD(v) (4*(v/4) - 8 - USB_HWDESC_HEADER_LEN)
-//#endif
-
-//typedef enum _firmware_init_step{
-// FW_INIT_STEP0_BOOT = 0,
-// FW_INIT_STEP1_MAIN = 1,
-// FW_INIT_STEP2_DATA = 2,
-//}firmware_init_step_e;
-
-//typedef enum _DESC_PACKET_TYPE{
-// DESC_PACKET_TYPE_INIT = 0,
-// DESC_PACKET_TYPE_NORMAL = 1,
-//}DESC_PACKET_TYPE;
-#define RTL8192S_FW_PKT_FRAG_SIZE 0xFF00 // 64K
-
-
#define RTL8190_MAX_FIRMWARE_CODE_SIZE 64000 //64k
#define MAX_FIRMWARE_CODE_SIZE 0xFF00 // Firmware Local buffer size.
#define RTL8190_CPU_START_OFFSET 0x80
-
+#define RTL8192S_FW_PKT_FRAG_SIZE 0x4000
#define GET_COMMAND_PACKET_FRAG_THRESHOLD(v) (4*(v/4) - 8 - USB_HWDESC_HEADER_LEN)
-//typedef enum _DESC_PACKET_TYPE{
-// DESC_PACKET_TYPE_INIT = 0,
-// DESC_PACKET_TYPE_NORMAL = 1,
-//}DESC_PACKET_TYPE;
-// Forward declaration.
-//typedef struct _ADAPTER ADAPTER, *PADAPTER;
#ifdef RTL8192S
typedef enum _firmware_init_step{
FW_INIT_STEP0_IMEM = 0,
@@ -64,17 +52,8 @@ typedef enum _opt_rst_type{
OPT_FIRMWARE_RESET = 1,
}opt_rst_type_e;
-/*typedef enum _FIRMWARE_STATUS{
- FW_STATUS_0_INIT = 0,
- FW_STATUS_1_MOVE_BOOT_CODE = 1,
- FW_STATUS_2_MOVE_MAIN_CODE = 2,
- FW_STATUS_3_TURNON_CPU = 3,
- FW_STATUS_4_MOVE_DATA_CODE = 4,
- FW_STATUS_5_READY = 5,
-}FIRMWARE_STATUS;
-*/
//--------------------------------------------------------------------------------
-// RTL8192S Firmware related, Revised by Roger, 2008.12.18.
+// RTL8192S Firmware related
//--------------------------------------------------------------------------------
typedef struct _RT_8192S_FIRMWARE_PRIV { //8-bytes alignment required
@@ -181,7 +160,6 @@ typedef enum _FIRMWARE_8192S_STATUS{
typedef struct _rt_firmware{
PRT_8192S_FIRMWARE_HDR pFwHeader;
FIRMWARE_8192S_STATUS FWStatus;
- u16 FirmwareVersion;
u8 FwIMEM[RTL8190_MAX_FIRMWARE_CODE_SIZE];
u8 FwEMEM[RTL8190_MAX_FIRMWARE_CODE_SIZE];
u32 FwIMEMLen;
@@ -189,11 +167,43 @@ typedef struct _rt_firmware{
u8 szFwTmpBuffer[164000];
u32 szFwTmpBufferLen;
u16 CmdPacketFragThresold;
+ u16 FirmwareVersion;
}rt_firmware, *prt_firmware;
-//typedef struct _RT_FIRMWARE_INFO_8192SU{
-// u8 szInfo[16];
-//}RT_FIRMWARE_INFO_8192SU, *PRT_FIRMWARE_INFO_8192SU;
+#define FW_DIG_ENABLE_CTL BIT0
+#define FW_HIGH_PWR_ENABLE_CTL BIT1
+#define FW_SS_CTL BIT2
+#define FW_RA_INIT_CTL BIT3
+#define FW_RA_BG_CTL BIT4
+#define FW_RA_N_CTL BIT5
+#define FW_PWR_TRK_CTL BIT6
+#define FW_IQK_CTL BIT7
+#define FW_ANTENNA_SW BIT8
+#define FW_DISABLE_ALL_DM 0
+
+#define FW_PWR_TRK_PARAM_CLR 0x0000ffff
+#define FW_RA_PARAM_CLR 0xffff0000
+
+#define FW_CMD_IO_CLR(_pdev, _Bit) \
+ udelay(1000); \
+ ((struct r8192_priv *)ieee80211_priv(_pdev))->FwCmdIOMap &= (~_Bit);
+
+#define FW_CMD_IO_UPDATE(_pdev, _val) \
+ ((struct r8192_priv *)ieee80211_priv(_pdev))->FwCmdIOMap = _val;
+
+#define FW_CMD_IO_SET(_pdev, _val) \
+ write_nic_word(_pdev, LBUS_MON_ADDR, (u16)_val); \
+ FW_CMD_IO_UPDATE(_pdev, _val);
+
+#define FW_CMD_PARA_SET(_pdev, _val) \
+ write_nic_dword(_pdev, LBUS_ADDR_MASK, _val); \
+ ((struct r8192_priv *)ieee80211_priv(_pdev))->FwCmdIOParam = _val;
+
+#define FW_CMD_IO_QUERY(_pdev) (u16)(((struct r8192_priv *)ieee80211_priv(_pdev))->FwCmdIOMap)
+#define FW_CMD_IO_PARA_QUERY(_pdev) (u32)(((struct r8192_priv *)ieee80211_priv(_pdev))->FwCmdIOParam)
+
+
+
bool FirmwareDownload92S(struct net_device *dev);
#endif
diff --git a/drivers/staging/rtl8192su/r8192S_hw.h b/drivers/staging/rtl8192su/r8192S_hw.h
index 82ea96b6f4d..e62b79df5ba 100644
--- a/drivers/staging/rtl8192su/r8192S_hw.h
+++ b/drivers/staging/rtl8192su/r8192S_hw.h
@@ -1,25 +1,22 @@
-/*****************************************************************************
- * Copyright(c) 2008, RealTEK Technology Inc. All Right Reserved.
+/******************************************************************************
+ * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved.
*
- * Module: __INC_HAL8192SEREG_H
+ * 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, USA
*
- * Note: 1. Define Mac register address and corresponding bit mask map
- * 2. CCX register
- * 3. Backward compatible register with useless address.
- * 4. Define 92SU required register address and definition.
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
*
- *
- * Export: Constants, macro, functions(API), global variables(None).
- *
- * Abbrev:
- *
- * History:
- * Data Who Remark
- * 08/07/2007 MHC 1. Porting from 9x series PHYCFG.h.
- * 2. Reorganize code architecture.
- *
- *****************************************************************************/
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+******************************************************************************/
+
#ifndef R8192S_HW
#define R8192S_HW
@@ -29,21 +26,14 @@ typedef enum _VERSION_8192S{
VERSION_8192S_CCUT
}VERSION_8192S,*PVERSION_8192S;
-//#ifdef RTL8192SU
typedef enum _VERSION_8192SUsb{
VERSION_8192SU_A, //A-Cut
VERSION_8192SU_B, //B-Cut
VERSION_8192SU_C, //C-Cut
}VERSION_8192SUsb, *PVERSION_8192SUsb;
-//#else
-typedef enum _VERSION_819xU{
- VERSION_819xU_A, // A-cut
- VERSION_819xU_B, // B-cut
- VERSION_819xU_C,// C-cut
-}VERSION_819xU,*PVERSION_819xU;
-//#endif
-
-/* 2007/11/15 MH Define different RF type. */
+
+
+/* RF type. */
typedef enum _RT_RF_TYPE_DEFINITION
{
RF_1T2R = 0,
@@ -51,9 +41,6 @@ typedef enum _RT_RF_TYPE_DEFINITION
RF_2T2R,
RF_1T1R,
RF_2T2R_GREEN,
- //RF_3T3R,
- //RF_3T4R,
- //RF_4T4R,
RF_819X_MAX_TYPE
}RT_RF_TYPE_DEF_E;
@@ -68,12 +55,10 @@ typedef enum _BaseBand_Config_Type{
#define RTL8187_REQ_SET_REGS 0x05
#define MAX_TX_URB 5
-#define MAX_RX_URB 16
+#define MAX_RX_URB 8
#define R8180_MAX_RETRY 255
-//#define MAX_RX_NORMAL_URB 3
-//#define MAX_RX_COMMAND_URB 2
-#define RX_URB_SIZE 9100
+#define RX_URB_SIZE 0x4000
#define BB_ANTATTEN_CHAN14 0x0c
#define BB_ANTENNA_B 0x40
@@ -134,7 +119,6 @@ typedef enum _BaseBand_Config_Type{
#define MSR_LINK_ENEDCA (1<<4)
-//#define Cmd9346CR_9356SEL (1<<4)
#define EPROM_CMD_RESERVED_MASK (1<<5)
#define EPROM_CMD_OPERATING_MODE_SHIFT 6
#define EPROM_CMD_OPERATING_MODE_MASK ((1<<7)|(1<<6))
@@ -147,13 +131,6 @@ typedef enum _BaseBand_Config_Type{
#define EPROM_W_SHIFT 1
#define EPROM_R_SHIFT 0
-//#define MAC0 0x000,
-//#define MAC1 0x001,
-//#define MAC2 0x002,
-//#define MAC3 0x003,
-//#define MAC4 0x004,
-//#define MAC5 0x005,
-
//============================================================
// 8192S Regsiter offset definition
//============================================================
@@ -529,14 +506,6 @@ typedef enum _BaseBand_Config_Type{
// USB RPWM register
#define USB_RPWM 0xFE58
-//FIXLZM SVN_BRACH NOT MOD HERE, IF MOD RX IS LITTLE LOW
-//#if ((HAL_CODE_BASE == RTL8192_S) && (DEV_BUS_TYPE==PCI_INTERFACE))
-//#define RPWM PCI_RPWM
-//#elif ((HAL_CODE_BASE == RTL8192_S) && (DEV_BUS_TYPE==USB_INTERFACE))
-//#define RPWM USB_RPWM
-//#endif
-
-
//============================================================================
// 8190 Regsiter offset definition
//============================================================================
@@ -777,13 +746,11 @@ typedef enum _BaseBand_Config_Type{
#define RCR_MXDMA_OFFSET 8
#define RCR_FIFO_OFFSET 13
-//in 92U FIXLZM
-//#ifdef RTL8192U
#define RCR_ONLYERLPKT BIT31 // Early Receiving based on Packet Size.
#define RCR_ENCS2 BIT30 // Enable Carrier Sense Detection Method 2
#define RCR_ENCS1 BIT29 // Enable Carrier Sense Detection Method 1
#define RCR_ACKTXBW (BIT24|BIT25) // TXBW Setting of ACK frames
-//#endif
+
//----------------------------------------------------------------------------
// 8192S (MSR) Media Status Register (Offset 0x4C, 8 bits)
//----------------------------------------------------------------------------
@@ -1259,17 +1226,18 @@ Default: 00b.
#define EEPROM_CHANNEL_PLAN_GLOBAL_DOMAIN 0x9
#define EEPROM_CHANNEL_PLAN_WORLD_WIDE_13 0xA
#define EEPROM_CHANNEL_PLAN_BY_HW_MASK 0x80
+#define EEPROM_CID_DEFAULT 0x0
+#define EEPROM_CID_ALPHA 0x1
+#define EEPROM_CID_Senao 0x3
+#define EEPROM_CID_CAMEO 0X8
+#define EEPROM_CID_SITECOM 0x9
+#define EEPROM_CID_COREGA 0xB
+#define EEPROM_CID_EDIMAX_BELKIN 0xC
+#define EEPROM_CID_SERCOMM_BELKIN 0xE
+#define EEPROM_CID_CAMEO1 0xF
+#define EEPROM_CID_WHQL 0xFE
+#define EEPROM_CID_NetCore 0x5
-#define EEPROM_CID_DEFAULT 0x0
-#define EEPROM_CID_ALPHA 0x1
-#define EEPROM_CID_CAMEO 0X8
-#define EEPROM_CID_SITECOM 0x9
-
-//#define EEPROM_CID_RUNTOP 0x2
-//#define EEPROM_CID_Senao 0x3
-//#define EEPROM_CID_TOSHIBA 0x4
-//#define EEPROM_CID_NetCore 0x5
-#define EEPROM_CID_WHQL 0xFE // added by chiyoko for dtm, 20090108
//-----------------------------------------------------------------
// 0x2c0 FW Command Control register definition, added by Roger, 2008.11.27.
@@ -1282,18 +1250,32 @@ Default: 00b.
#define FW_HIGH_PWR_ENABLE 0xfd000009
#define FW_TXPWR_TRACK_ENABLE 0xfd000017
#define FW_TXPWR_TRACK_DISABLE 0xfd000018
-#define FW_RA_RESET 0xfd0000af
-#define FW_RA_ACTIVE 0xfd0000a6
+#define FW_TXPWR_TRACK_THERMAL 0xfd000019
+#define FW_RA_INIT 0xfd000026
+#define FW_RA_IOT_BG_COMB 0xfd000030
+#define FW_RA_IOT_N_COMB 0xfd000031
#define FW_RA_REFRESH 0xfd0000a0
-#define FW_RA_ENABLE_BG 0xfd0000ac
+#define FW_RA_DISABLE 0xfd0000a4
+#define FW_RA_ACTIVE 0xfd0000a6
+#define FW_RA_DISABLE_RSSI_MASK 0xfd0000ac
+#define FW_RA_ENABLE_RSSI_MASK 0xfd0000ad
+#define FW_RA_RESET 0xfd0000af
+#define FW_DM_DISABLE 0xfd00aa00
#define FW_IQK_ENABLE 0xf0000020
#define FW_IQK_SUCCESS 0x0000dddd
#define FW_IQK_FAIL 0x0000ffff
#define FW_OP_FAILURE 0xffffffff
-#define FW_DM_DISABLE 0xfd00aa00
+#define FW_TX_FEEDBACK_NONE 0xfb000000
+#define FW_TX_FEEDBACK_DTM_ENABLE (FW_TX_FEEDBACK_NONE | 0x1)
+#define FW_TX_FEEDBACK_CCX_ENABLE (FW_TX_FEEDBACK_NONE | 0x2)
#define FW_BB_RESET_ENABLE 0xff00000d
#define FW_BB_RESET_DISABLE 0xff00000e
-
+#define FW_LPS_ENTER 0xfe000010
+#define FW_LPS_LEAVE 0xfe000011
+#define FW_INDIRECT_READ 0xf2000000
+#define FW_INDIRECT_WRITE 0xf2000001
+#define FW_TXANT_SWITCH_ENABLE 0xfd000023
+#define FW_TXANT_SWITCH_DISABLE 0xfd000024
//
//--------------92SU require delete or move to other place later
//
@@ -1460,34 +1442,4 @@ Default: 00b.
#define HAL_8192S_HW_GPIO_OFF_MASK 0xF7
#define HAL_8192S_HW_GPIO_WPS_BIT BIT4
-#endif //R8192S_HW
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+#endif
diff --git a/drivers/staging/rtl8192su/r8192S_phy.c b/drivers/staging/rtl8192su/r8192S_phy.c
index b6c0f199074..a5fc2d1cb06 100644
--- a/drivers/staging/rtl8192su/r8192S_phy.c
+++ b/drivers/staging/rtl8192su/r8192S_phy.c
@@ -1,35 +1,20 @@
/******************************************************************************
-
- (c) Copyright 2008, RealTEK Technologies Inc. All Rights Reserved.
-
- Module: hal8192sphy.c
-
- Note: Merge 92SE/SU PHY config as below
- 1. BB register R/W API
- 2. RF register R/W API
- 3. Initial BB/RF/MAC config by reading BB/MAC/RF txt.
- 3. Power setting API
- 4. Channel switch API
- 5. Initial gain switch API.
- 6. Other BB/MAC/RF API.
-
- Function: PHY: Extern function, phy: local function
-
- Export: PHY_FunctionName
-
- Abbrev: NONE
-
- History:
- Data Who Remark
- 08/08/2008 MHC 1. Port from 9x series phycfg.c
- 2. Reorganize code arch and ad description.
- 3. Collect similar function.
- 4. Seperate extern/local API.
- 08/12/2008 MHC We must merge or move USB PHY relative function later.
- 10/07/2008 MHC Add IQ calibration for PHY.(Only 1T2R mode now!!!)
- 11/06/2008 MHC Add TX Power index PG file to config in 0xExx register
- area to map with EEPROM/EFUSE tx pwr index.
-
+ * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved.
+ *
+ * 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, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
******************************************************************************/
#include "r8192U.h"
#include "r8192U_dm.h"
@@ -42,16 +27,12 @@
#include "ieee80211/dot11d.h"
-/*---------------------------Define Local Constant---------------------------*/
/* Channel switch:The size of command tables for switch channel*/
#define MAX_PRECMD_CNT 16
#define MAX_RFDEPENDCMD_CNT 16
#define MAX_POSTCMD_CNT 16
#define MAX_DOZE_WAITING_TIMES_9x 64
-/*------------------------Define local variable------------------------------*/
-// 2004-05-11
-
static u32
phy_CalculateBitShift(u32 BitMask);
static RT_STATUS
@@ -86,7 +67,6 @@ static long phy_TxPwrIdxToDbm( struct net_device* dev, WIRELESS_MODE WirelessM
static u8 phy_DbmToTxPwrIdx( struct net_device* dev, WIRELESS_MODE WirelessMode, long PowerInDbm);
void phy_SetFwCmdIOCallback(struct net_device* dev);
-//#if ((HAL_CODE_BASE == RTL8192_S) && (DEV_BUS_TYPE==USB_INTERFACE))
//
// Description:
// Base Band read by 4181 to make sure that operation could be done in unlimited cycle.
@@ -95,8 +75,6 @@ void phy_SetFwCmdIOCallback(struct net_device* dev);
// - Only use on RTL8192S USB interface.
// - PASSIVE LEVEL
//
-// Created by Roger, 2008.09.06.
-//
//use in phy only
u32 phy_QueryUsbBBReg(struct net_device* dev, u32 RegAddr)
{
@@ -118,7 +96,7 @@ u32 phy_QueryUsbBBReg(struct net_device* dev, u32 RegAddr)
msleep(1); // 1 ms
// Wait too long, return FALSE to avoid to be stuck here.
- if((BBWaitCounter > 100) )//||RT_USB_CANNOT_IO(Adapter))
+ if((BBWaitCounter > 100) )
{
RT_TRACE(COMP_RF, "phy_QueryUsbBBReg(): (%d) Wait too logn to query BB!!\n", BBWaitCounter);
return ReturnValue;
@@ -160,9 +138,6 @@ u32 phy_QueryUsbBBReg(struct net_device* dev, u32 RegAddr)
// Assumption:
// - Only use on RTL8192S USB interface.
// - PASSIVE LEVEL
-//
-// Created by Roger, 2008.09.06.
-//
//use in phy only
void
phy_SetUsbBBReg(struct net_device* dev,u32 RegAddr,u32 Data)
@@ -191,7 +166,6 @@ phy_SetUsbBBReg(struct net_device* dev,u32 RegAddr,u32 Data)
}
priv->bChangeBBInProgress = true;
- //printk("**************%s: RegAddr:%x Data:%x\n", __FUNCTION__,RegAddr, Data);
write_nic_dword(dev, RegAddr, Data);
priv->bChangeBBInProgress = false;
@@ -215,9 +189,7 @@ u32 phy_QueryUsbRFReg( struct net_device* dev, RF90_RADIO_PATH_E eRFPath, u32 Of
{
struct r8192_priv *priv = ieee80211_priv(dev);
- //u32 value = 0, ReturnValue = 0;
u32 ReturnValue = 0;
- //u32 tmplong,tmplong2;
u8 PollingCnt = 50;
u8 RFWaitCounter = 0;
@@ -229,8 +201,6 @@ u32 phy_QueryUsbRFReg( struct net_device* dev, RF90_RADIO_PATH_E eRFPath, u32 Of
//
while(priv->bChangeRFInProgress)
{
- //PlatformReleaseSpinLock(Adapter, RT_RF_OPERATE_SPINLOCK);
- //spin_lock_irqsave(&priv->rf_lock, flags); //LZM,090318
down(&priv->rf_sem);
RFWaitCounter ++;
@@ -244,14 +214,10 @@ u32 phy_QueryUsbRFReg( struct net_device* dev, RF90_RADIO_PATH_E eRFPath, u32 Of
}
else
{
- //PlatformAcquireSpinLock(Adapter, RT_RF_OPERATE_SPINLOCK);
}
}
priv->bChangeRFInProgress = true;
- //PlatformReleaseSpinLock(Adapter, RT_RF_OPERATE_SPINLOCK);
-
-
Offset &= 0x3f; //RF_Offset= 0x00~0x3F
write_nic_dword(dev, RF_BB_CMD_ADDR, 0xF0000002|
@@ -267,8 +233,6 @@ u32 phy_QueryUsbRFReg( struct net_device* dev, RF90_RADIO_PATH_E eRFPath, u32 Of
// Data FW read back.
ReturnValue = read_nic_dword(dev, RF_BB_CMD_DATA);
- //PlatformAcquireSpinLock(Adapter, RT_RF_OPERATE_SPINLOCK);
- //spin_unlock_irqrestore(&priv->rf_lock, flags); //LZM,090318
up(&priv->rf_sem);
priv->bChangeRFInProgress = false;
@@ -306,27 +270,23 @@ void phy_SetUsbRFReg(struct net_device* dev,RF90_RADIO_PATH_E eRFPath,u32 RegAdd
//
while(priv->bChangeRFInProgress)
{
- //PlatformReleaseSpinLock(Adapter, RT_RF_OPERATE_SPINLOCK);
- //spin_lock_irqsave(&priv->rf_lock, flags); //LZM,090318
down(&priv->rf_sem);
RFWaitCounter ++;
RT_TRACE(COMP_RF, "phy_SetUsbRFReg(): Wait 1 ms (%d times)...\n", RFWaitCounter);
msleep(1); // 1 ms
- if((RFWaitCounter > 100))// || RT_USB_CANNOT_IO(Adapter))
+ if((RFWaitCounter > 100))
{
RT_TRACE(COMP_RF, "phy_SetUsbRFReg(): (%d) Wait too logn to query BB!!\n", RFWaitCounter);
return;
}
else
{
- //PlatformAcquireSpinLock(Adapter, RT_RF_OPERATE_SPINLOCK);
}
}
priv->bChangeRFInProgress = true;
- //PlatformReleaseSpinLock(Adapter, RT_RF_OPERATE_SPINLOCK);
RegAddr &= 0x3f; //RF_Offset= 0x00~0x3F
@@ -347,18 +307,11 @@ void phy_SetUsbRFReg(struct net_device* dev,RF90_RADIO_PATH_E eRFPath,u32 RegAdd
RT_TRACE(COMP_RF, "phy_SetUsbRFReg(): Set RegAddr(%#x) = %#x Fail!!!\n", RegAddr, Data);
}
- //PlatformAcquireSpinLock(Adapter, RT_RF_OPERATE_SPINLOCK);
- //spin_unlock_irqrestore(&priv->rf_lock, flags); //LZM,090318
up(&priv->rf_sem);
priv->bChangeRFInProgress = false;
}
-
-/*---------------------Define local function prototype-----------------------*/
-
-
-/*----------------------------Function Body----------------------------------*/
//
// 1. BB register R/W API
//
@@ -376,8 +329,6 @@ void phy_SetUsbRFReg(struct net_device* dev,RF90_RADIO_PATH_E eRFPath,u32 RegAdd
* Return: u32 Data //The readback register value
* Note: This function is equal to "GetRegSetting" in PHY programming guide
*/
-//use phy dm core 8225 8256 6052
-//u32 PHY_QueryBBReg(struct net_device* dev,u32 RegAddr, u32 BitMask)
u32 rtl8192_QueryBBReg(struct net_device* dev, u32 RegAddr, u32 BitMask)
{
@@ -392,10 +343,8 @@ u32 rtl8192_QueryBBReg(struct net_device* dev, u32 RegAddr, u32 BitMask)
// infinite cycle.
// 2008.09.06.
//
-//#if ((HAL_CODE_BASE == RTL8192_S) && (DEV_BUS_TYPE==USB_INTERFACE))
if(IS_BB_REG_OFFSET_92S(RegAddr))
{
- //if(RT_USB_CANNOT_IO(Adapter)) return FALSE;
if((RegAddr & 0x03) != 0)
{
@@ -413,7 +362,7 @@ u32 rtl8192_QueryBBReg(struct net_device* dev, u32 RegAddr, u32 BitMask)
BitShift = phy_CalculateBitShift(BitMask);
ReturnValue = (OriginalValue & BitMask) >> BitShift;
- //RTPRINT(FPHY, PHY_BBR, ("BBR MASK=0x%x Addr[0x%x]=0x%x\n", BitMask, RegAddr, OriginalValue));
+
RT_TRACE(COMP_RF, "<---PHY_QueryBBReg(): RegAddr(%#x), BitMask(%#x), OriginalValue(%#x)\n", RegAddr, BitMask, OriginalValue);
return (ReturnValue);
}
@@ -435,8 +384,6 @@ u32 rtl8192_QueryBBReg(struct net_device* dev, u32 RegAddr, u32 BitMask)
* Return: None
* Note: This function is equal to "PutRegSetting" in PHY programming guide
*/
-//use phy dm core 8225 8256
-//void PHY_SetBBReg(struct net_device* dev,u32 RegAddr, u32 BitMask, u32 Data )
void rtl8192_setBBreg(struct net_device* dev, u32 RegAddr, u32 BitMask, u32 Data)
{
u32 OriginalValue, BitShift, NewValue;
@@ -450,7 +397,6 @@ void rtl8192_setBBreg(struct net_device* dev, u32 RegAddr, u32 BitMask, u32 Data
// infinite cycle.
// 2008.09.06.
//
-//#if ((HAL_CODE_BASE == RTL8192_S) && (DEV_BUS_TYPE==USB_INTERFACE))
if(IS_BB_REG_OFFSET_92S(RegAddr))
{
if((RegAddr & 0x03) != 0)
@@ -480,7 +426,6 @@ void rtl8192_setBBreg(struct net_device* dev, u32 RegAddr, u32 BitMask, u32 Data
write_nic_dword(dev, RegAddr, Data);
}
- //RT_TRACE(COMP_RF, "<---PHY_SetBBReg(): RegAddr(%#x), BitMask(%#x), Data(%#x)\n", RegAddr, BitMask, Data);
return;
}
@@ -505,8 +450,6 @@ void rtl8192_setBBreg(struct net_device* dev, u32 RegAddr, u32 BitMask, u32 Data
* Return: u32 Readback value
* Note: This function is equal to "GetRFRegSetting" in PHY programming guide
*/
-//in dm 8256 and phy
-//u32 PHY_QueryRFReg(struct net_device* dev, RF90_RADIO_PATH_E eRFPath, u32 RegAddr, u32 BitMask)
u32 rtl8192_phy_QueryRFReg(struct net_device* dev, RF90_RADIO_PATH_E eRFPath, u32 RegAddr, u32 BitMask)
{
u32 Original_Value, Readback_Value, BitShift;//, flags;
@@ -527,9 +470,6 @@ u32 rtl8192_phy_QueryRFReg(struct net_device* dev, RF90_RADIO_PATH_E eRFPath, u3
return 0;
}
- /* 2008/01/17 MH We get and release spin lock when reading RF register. */
- //PlatformAcquireSpinLock(dev, RT_RF_OPERATE_SPINLOCK);FIXLZM
- //spin_lock_irqsave(&priv->rf_lock, flags); //YJ,test,090113
down(&priv->rf_sem);
//
// <Roger_Notes> Due to 8051 operation cycle (limitation cycle: 6us) and 1-Byte access issue, we should use
@@ -537,17 +477,11 @@ u32 rtl8192_phy_QueryRFReg(struct net_device* dev, RF90_RADIO_PATH_E eRFPath, u3
// infinite cycle.
// 2008.09.06.
//
-//#if (HAL_CODE_BASE == RTL8192_S && DEV_BUS_TYPE==USB_INTERFACE)
- //if(RT_USB_CANNOT_IO(Adapter)) return FALSE;
Original_Value = phy_QueryUsbRFReg(dev, eRFPath, RegAddr);
BitShift = phy_CalculateBitShift(BitMask);
Readback_Value = (Original_Value & BitMask) >> BitShift;
- //spin_unlock_irqrestore(&priv->rf_lock, flags); //YJ,test,090113
up(&priv->rf_sem);
- //PlatformReleaseSpinLock(dev, RT_RF_OPERATE_SPINLOCK);
-
- //RTPRINT(FPHY, PHY_RFR, ("RFR-%d MASK=0x%x Addr[0x%x]=0x%x\n", eRFPath, BitMask, RegAddr, Original_Value));
return (Readback_Value);
}
@@ -570,8 +504,6 @@ u32 rtl8192_phy_QueryRFReg(struct net_device* dev, RF90_RADIO_PATH_E eRFPath, u3
* Return: None
* Note: This function is equal to "PutRFRegSetting" in PHY programming guide
*/
-//use phy 8225 8256
-//void PHY_SetRFReg(struct net_device* dev,RF90_RADIO_PATH_E eRFPath, u32 RegAddr, u32 BitMask,u32 Data )
void rtl8192_phy_SetRFReg(struct net_device* dev, RF90_RADIO_PATH_E eRFPath, u32 RegAddr, u32 BitMask, u32 Data)
{
@@ -592,18 +524,11 @@ void rtl8192_phy_SetRFReg(struct net_device* dev, RF90_RADIO_PATH_E eRFPath, u32
return;
}
- /* 2008/01/17 MH We get and release spin lock when writing RF register. */
- //PlatformAcquireSpinLock(dev, RT_RF_OPERATE_SPINLOCK);
- //spin_lock_irqsave(&priv->rf_lock, flags); //YJ,test,090113
down(&priv->rf_sem);
//
// <Roger_Notes> Due to 8051 operation cycle (limitation cycle: 6us) and 1-Byte access issue, we should use
// 4181 to access Base Band instead of 8051 on USB interface to make sure that access could be done in
// infinite cycle.
- // 2008.09.06.
- //
-//#if (HAL_CODE_BASE == RTL8192_S && DEV_BUS_TYPE==USB_INTERFACE)
- //if(RT_USB_CANNOT_IO(Adapter)) return;
if (BitMask != bRFRegOffsetMask) // RF data is 12 bits only
{
@@ -614,10 +539,7 @@ void rtl8192_phy_SetRFReg(struct net_device* dev, RF90_RADIO_PATH_E eRFPath, u32
}
else
phy_SetUsbRFReg(dev, eRFPath, RegAddr, Data);
- //PlatformReleaseSpinLock(dev, RT_RF_OPERATE_SPINLOCK);
- //spin_unlock_irqrestore(&priv->rf_lock, flags); //YJ,test,090113
up(&priv->rf_sem);
- //RTPRINT(FPHY, PHY_RFW, ("RFW-%d MASK=0x%x Addr[0x%x]=0x%x\n", eRFPath, BitMask, RegAddr, Data));
RT_TRACE(COMP_RF, "<---PHY_SetRFReg(): RegAddr(%#x), BitMask(%#x), Data(%#x), eRFPath(%#x)\n",
RegAddr, BitMask, Data, eRFPath);
@@ -691,29 +613,9 @@ PHY_BBConfig8192S(struct net_device* dev)
struct r8192_priv *priv = ieee80211_priv(dev);
phy_InitBBRFRegisterDefinition(dev);
- //
- // Config BB and AGC
- //
- //switch( Adapter->MgntInfo.bRegHwParaFile )
- //{
- // case 0:
- // phy_BB8190_Config_HardCode(dev);
- // break;
- // case 1:
rtStatus = phy_BB8192S_Config_ParaFile(dev);
- // break;
-
- // case 2:
- // Partial Modify.
- // phy_BB8190_Config_HardCode(dev);
- // phy_BB8192S_Config_ParaFile(dev);
- // break;
-
- // default:
- // phy_BB8190_Config_HardCode(dev);
- // break;
- //}
+
PathMap = (u8)(rtl8192_QueryBBReg(dev, rFPGA0_TxInfo, 0xf) |
rtl8192_QueryBBReg(dev, rOFDM0_TRxPathEnable, 0xf));
priv->rf_pathmap = PathMap;
@@ -774,15 +676,10 @@ PHY_RFConfig8192S(struct net_device* dev)
}
-// Joseph test: new initialize order!!
-// Test only!! This part need to be re-organized.
-// Now it is just for 8256.
-//use in phy only
#ifdef TO_DO_LIST
static RT_STATUS
phy_BB8190_Config_HardCode(struct net_device* dev)
{
- //RT_ASSERT(FALSE, ("This function is not implement yet!! \n"));
return RT_STATUS_SUCCESS;
}
#endif
@@ -811,7 +708,6 @@ phy_SetBBtoDiffRFWithHeaderFile(struct net_device* dev, u8 ConfigType)
u32* Rtl819XPHY_REGArraytoXTXR_Table;
u16 PHY_REGArraytoXTXRLen;
-//#if (HAL_CODE_BASE != RTL8192_S)
if(priv->rf_type == RF_1T1R)
{
@@ -823,11 +719,6 @@ phy_SetBBtoDiffRFWithHeaderFile(struct net_device* dev, u8 ConfigType)
Rtl819XPHY_REGArraytoXTXR_Table = Rtl819XPHY_REG_to1T2R_Array;
PHY_REGArraytoXTXRLen = PHY_ChangeTo_1T2RArrayLength;
}
- //else if(priv->rf_type == RF_2T2R || priv->rf_type == RF_2T2R_GREEN)
- //{
- // Rtl819XPHY_REGArraytoXTXR_Table = Rtl819XPHY_REG_to2T2R_Array;
- // PHY_REGArraytoXTXRLen = PHY_ChangeTo_2T2RArrayLength;
- //}
else
{
return RT_STATUS_FAILURE;
@@ -850,15 +741,11 @@ phy_SetBBtoDiffRFWithHeaderFile(struct net_device* dev, u8 ConfigType)
else if (Rtl819XPHY_REGArraytoXTXR_Table[i] == 0xf9)
udelay(1);
rtl8192_setBBreg(dev, Rtl819XPHY_REGArraytoXTXR_Table[i], Rtl819XPHY_REGArraytoXTXR_Table[i+1], Rtl819XPHY_REGArraytoXTXR_Table[i+2]);
- //RT_TRACE(COMP_SEND,
- //"The Rtl819XPHY_REGArraytoXTXR_Table[0] is %lx Rtl819XPHY_REGArraytoXTXR_Table[1] is %lx Rtl819XPHY_REGArraytoXTXR_Table[2] is %lx \n",
- //Rtl819XPHY_REGArraytoXTXR_Table[i],Rtl819XPHY_REGArraytoXTXR_Table[i+1], Rtl819XPHY_REGArraytoXTXR_Table[i+2]);
}
}
else {
RT_TRACE(COMP_SEND, "phy_SetBBtoDiffRFWithHeaderFile(): ConfigType != BaseBand_Config_PHY_REG\n");
}
-//#endif // #if (HAL_CODE_BASE != RTL8192_S)
return RT_STATUS_SUCCESS;
}
@@ -869,14 +756,6 @@ phy_BB8192S_Config_ParaFile(struct net_device* dev)
{
struct r8192_priv *priv = ieee80211_priv(dev);
RT_STATUS rtStatus = RT_STATUS_SUCCESS;
- //u8 u2RegValue;
- //u16 u4RegValue;
- //char szBBRegFile[] = RTL819X_PHY_REG;
- //char szBBRegFile1T2R[] = RTL819X_PHY_REG_1T2R;
- //char szBBRegPgFile[] = RTL819X_PHY_REG_PG;
- //char szAGCTableFile[] = RTL819X_AGC_TAB;
- //char szBBRegto1T1RFile[] = RTL819X_PHY_REG_to1T1R;
- //char szBBRegto1T2RFile[] = RTL819X_PHY_REG_to1T2R;
RT_TRACE(COMP_INIT, "==>phy_BB8192S_Config_ParaFile\n");
@@ -956,42 +835,16 @@ phy_ConfigMACWithHeaderFile(struct net_device* dev)
u32 i = 0;
u32 ArrayLength = 0;
u32* ptrArray;
- //struct r8192_priv *priv = ieee80211_priv(dev);
-//#if (HAL_CODE_BASE != RTL8192_S)
- /*if(Adapter->bInHctTest)
- {
- RT_TRACE(COMP_INIT, DBG_LOUD, ("Rtl819XMACPHY_ArrayDTM\n"));
- ArrayLength = MACPHY_ArrayLengthDTM;
- ptrArray = Rtl819XMACPHY_ArrayDTM;
- }
- else if(pHalData->bTXPowerDataReadFromEEPORM)
- {
-// RT_TRACE(COMP_INIT, DBG_LOUD, ("Rtl819XMACPHY_Array_PG\n"));
-// ArrayLength = MACPHY_Array_PGLength;
-// ptrArray = Rtl819XMACPHY_Array_PG;
-
- }else*/
{ //2008.11.06 Modified by tynli.
RT_TRACE(COMP_INIT, "Read Rtl819XMACPHY_Array\n");
ArrayLength = MAC_2T_ArrayLength;
ptrArray = Rtl819XMAC_Array;
}
- /*for(i = 0 ;i < ArrayLength;i=i+3){
- RT_TRACE(COMP_SEND, DBG_LOUD, ("The Rtl819XMACPHY_Array[0] is %lx Rtl819XMACPHY_Array[1] is %lx Rtl819XMACPHY_Array[2] is %lx\n",ptrArray[i], ptrArray[i+1], ptrArray[i+2]));
- if(ptrArray[i] == 0x318)
- {
- ptrArray[i+2] = 0x00000800;
- //DbgPrint("ptrArray[i], ptrArray[i+1], ptrArray[i+2] = %x, %x, %x\n",
- // ptrArray[i], ptrArray[i+1], ptrArray[i+2]);
- }
- PHY_SetBBReg(Adapter, ptrArray[i], ptrArray[i+1], ptrArray[i+2]);
- }*/
for(i = 0 ;i < ArrayLength;i=i+2){ // Add by tynli for 2 column
write_nic_byte(dev, ptrArray[i], (u8)ptrArray[i+1]);
}
-//#endif
return RT_STATUS_SUCCESS;
}
@@ -1015,41 +868,14 @@ static RT_STATUS
phy_ConfigBBWithHeaderFile(struct net_device* dev,u8 ConfigType)
{
int i;
- //u8 ArrayLength;
u32* Rtl819XPHY_REGArray_Table;
u32* Rtl819XAGCTAB_Array_Table;
u16 PHY_REGArrayLen, AGCTAB_ArrayLen;
- //struct r8192_priv *priv = ieee80211_priv(dev);
-//#if (HAL_CODE_BASE != RTL8192_S)
- /*if(Adapter->bInHctTest)
- {
-
- AGCTAB_ArrayLen = AGCTAB_ArrayLengthDTM;
- Rtl819XAGCTAB_Array_Table = Rtl819XAGCTAB_ArrayDTM;
-
- if(pHalData->RF_Type == RF_2T4R)
- {
- PHY_REGArrayLen = PHY_REGArrayLengthDTM;
- Rtl819XPHY_REGArray_Table = Rtl819XPHY_REGArrayDTM;
- }
- else if (pHalData->RF_Type == RF_1T2R)
- {
- PHY_REGArrayLen = PHY_REG_1T2RArrayLengthDTM;
- Rtl819XPHY_REGArray_Table = Rtl819XPHY_REG_1T2RArrayDTM;
- }
- }
- else
- */
- //{
- //
- // 2008.11.06 Modified by tynli.
- //
AGCTAB_ArrayLen = AGCTAB_ArrayLength;
Rtl819XAGCTAB_Array_Table = Rtl819XAGCTAB_Array;
PHY_REGArrayLen = PHY_REG_2T2RArrayLength; // Default RF_type: 2T2R
Rtl819XPHY_REGArray_Table = Rtl819XPHY_REG_Array;
- //}
if(ConfigType == BaseBand_Config_PHY_REG)
{
@@ -1068,7 +894,6 @@ phy_ConfigBBWithHeaderFile(struct net_device* dev,u8 ConfigType)
else if (Rtl819XPHY_REGArray_Table[i] == 0xf9)
udelay(1);
rtl8192_setBBreg(dev, Rtl819XPHY_REGArray_Table[i], bMaskDWord, Rtl819XPHY_REGArray_Table[i+1]);
- //RT_TRACE(COMP_SEND, "The Rtl819XPHY_REGArray_Table[0] is %lx Rtl819XPHY_REGArray[1] is %lx \n",Rtl819XPHY_REGArray_Table[i], Rtl819XPHY_REGArray_Table[i+1]);
}
}
@@ -1078,7 +903,6 @@ phy_ConfigBBWithHeaderFile(struct net_device* dev,u8 ConfigType)
rtl8192_setBBreg(dev, Rtl819XAGCTAB_Array_Table[i], bMaskDWord, Rtl819XAGCTAB_Array_Table[i+1]);
}
}
-//#endif // #if (HAL_CODE_BASE != RTL8192_S)
return RT_STATUS_SUCCESS;
}
@@ -1103,12 +927,8 @@ static RT_STATUS
phy_ConfigBBWithPgHeaderFile(struct net_device* dev,u8 ConfigType)
{
int i;
- //u8 ArrayLength;
u32* Rtl819XPHY_REGArray_Table_PG;
u16 PHY_REGArrayPGLen;
- //struct r8192_priv *priv = ieee80211_priv(dev);
-//#if (HAL_CODE_BASE != RTL8192_S)
- // Default: pHalData->RF_Type = RF_2T2R.
PHY_REGArrayPGLen = PHY_REG_Array_PGLength;
Rtl819XPHY_REGArray_Table_PG = Rtl819XPHY_REG_Array_PG;
@@ -1130,15 +950,13 @@ phy_ConfigBBWithPgHeaderFile(struct net_device* dev,u8 ConfigType)
else if (Rtl819XPHY_REGArray_Table_PG[i] == 0xf9)
udelay(1);
rtl8192_setBBreg(dev, Rtl819XPHY_REGArray_Table_PG[i], Rtl819XPHY_REGArray_Table_PG[i+1], Rtl819XPHY_REGArray_Table_PG[i+2]);
- //RT_TRACE(COMP_SEND, "The Rtl819XPHY_REGArray_Table_PG[0] is %lx Rtl819XPHY_REGArray_Table_PG[1] is %lx \n",
- // Rtl819XPHY_REGArray_Table_PG[i], Rtl819XPHY_REGArray_Table_PG[i+1]);
}
}else{
RT_TRACE(COMP_SEND, "phy_ConfigBBWithPgHeaderFile(): ConfigType != BaseBand_Config_PHY_REG\n");
}
return RT_STATUS_SUCCESS;
-} /* phy_ConfigBBWithPgHeaderFile */
+}
/*-----------------------------------------------------------------------------
* Function: PHY_ConfigRFWithHeaderFile()
@@ -1155,19 +973,14 @@ phy_ConfigBBWithPgHeaderFile(struct net_device* dev,u8 ConfigType)
*
* Note: Delay may be required for RF configuration
*---------------------------------------------------------------------------*/
-//in 8256 phy_RF8256_Config_ParaFile only
-//RT_STATUS PHY_ConfigRFWithHeaderFile(struct net_device* dev,RF90_RADIO_PATH_E eRFPath)
u8 rtl8192_phy_ConfigRFWithHeaderFile(struct net_device* dev, RF90_RADIO_PATH_E eRFPath)
{
struct r8192_priv *priv = ieee80211_priv(dev);
int i;
- //u32* pRFArray;
RT_STATUS rtStatus = RT_STATUS_SUCCESS;
u32 *Rtl819XRadioA_Array_Table;
u32 *Rtl819XRadioB_Array_Table;
- //u32* Rtl819XRadioC_Array_Table;
- //u32* Rtl819XRadioD_Array_Table;
u16 RadioA_ArrayLen,RadioB_ArrayLen;
{ //2008.11.06 Modified by tynli
@@ -1190,18 +1003,12 @@ u8 rtl8192_phy_ConfigRFWithHeaderFile(struct net_device* dev, RF90_RADIO_PATH_E
rtStatus = RT_STATUS_SUCCESS;
- // When initialization, we want the delay function(mdelay(), delay_us()
- // ==> actually we call PlatformStallExecution()) to do NdisStallExecution()
- // [busy wait] instead of NdisMSleep(). So we acquire RT_INITIAL_SPINLOCK
- // to run at Dispatch level to achive it.
- //cosa PlatformAcquireSpinLock(Adapter, RT_INITIAL_SPINLOCK);
switch(eRFPath){
case RF90_PATH_A:
for(i = 0;i<RadioA_ArrayLen; i=i+2){
if(Rtl819XRadioA_Array_Table[i] == 0xfe)
{ // Deay specific ms. Only RF configuration require delay.
-//#if (DEV_BUS_TYPE == USB_INTERFACE)
mdelay(1000);
}
else if (Rtl819XRadioA_Array_Table[i] == 0xfd)
@@ -1210,7 +1017,6 @@ u8 rtl8192_phy_ConfigRFWithHeaderFile(struct net_device* dev, RF90_RADIO_PATH_E
mdelay(1);
else if (Rtl819XRadioA_Array_Table[i] == 0xfb)
udelay(50);
- //PlatformStallExecution(50);
else if (Rtl819XRadioA_Array_Table[i] == 0xfa)
udelay(5);
else if (Rtl819XRadioA_Array_Table[i] == 0xf9)
@@ -1225,7 +1031,6 @@ u8 rtl8192_phy_ConfigRFWithHeaderFile(struct net_device* dev, RF90_RADIO_PATH_E
for(i = 0;i<RadioB_ArrayLen; i=i+2){
if(Rtl819XRadioB_Array_Table[i] == 0xfe)
{ // Deay specific ms. Only RF configuration require delay.
-//#if (DEV_BUS_TYPE == USB_INTERFACE)
mdelay(1000);
}
else if (Rtl819XRadioB_Array_Table[i] == 0xfd)
@@ -1281,7 +1086,6 @@ PHY_CheckBBAndRFOK(
RF90_RADIO_PATH_E eRFPath
)
{
- //struct r8192_priv *priv = ieee80211_priv(dev);
RT_STATUS rtStatus = RT_STATUS_SUCCESS;
u32 i, CheckTimes = 4,ulRegRead = 0;
u32 WriteAddr[4];
@@ -1302,7 +1106,6 @@ PHY_CheckBBAndRFOK(
switch(CheckBlock)
{
case HW90_BLOCK_MAC:
- //RT_ASSERT(FALSE, ("PHY_CheckBBRFOK(): Never Write 0x100 here!"));
RT_TRACE(COMP_INIT, "PHY_CheckBBRFOK(): Never Write 0x100 here!\n");
break;
@@ -1313,18 +1116,12 @@ PHY_CheckBBAndRFOK(
break;
case HW90_BLOCK_RF:
- // When initialization, we want the delay function(mdelay(), delay_us()
- // ==> actually we call PlatformStallExecution()) to do NdisStallExecution()
- // [busy wait] instead of NdisMSleep(). So we acquire RT_INITIAL_SPINLOCK
- // to run at Dispatch level to achive it.
- //cosa PlatformAcquireSpinLock(dev, RT_INITIAL_SPINLOCK);
WriteData[i] &= 0xfff;
rtl8192_phy_SetRFReg(dev, eRFPath, WriteAddr[HW90_BLOCK_RF], bRFRegOffsetMask, WriteData[i]);
// TODO: we should not delay for such a long time. Ask SD3
mdelay(10);
ulRegRead = rtl8192_phy_QueryRFReg(dev, eRFPath, WriteAddr[HW90_BLOCK_RF], bMaskDWord);
mdelay(10);
- //cosa PlatformReleaseSpinLock(dev, RT_INITIAL_SPINLOCK);
break;
default:
@@ -1338,7 +1135,6 @@ PHY_CheckBBAndRFOK(
//
if(ulRegRead != WriteData[i])
{
- //RT_TRACE(COMP_FPGA, ("ulRegRead: %x, WriteData: %x \n", ulRegRead, WriteData[i]));
RT_TRACE(COMP_ERR, "read back error(read:%x, write:%x)\n", ulRegRead, WriteData[i]);
rtStatus = RT_STATUS_FAILURE;
break;
@@ -1348,7 +1144,6 @@ PHY_CheckBBAndRFOK(
return rtStatus;
}
-//no use temp in windows driver
#ifdef TO_DO_LIST
void
PHY_SetRFPowerState8192SUsb(
@@ -1359,7 +1154,6 @@ PHY_SetRFPowerState8192SUsb(
struct r8192_priv *priv = ieee80211_priv(dev);
bool WaitShutDown = FALSE;
u32 DWordContent;
- //RF90_RADIO_PATH_E eRFPath;
u8 eRFPath;
BB_REGISTER_DEFINITION_T *pPhyReg;
@@ -1368,7 +1162,6 @@ PHY_SetRFPowerState8192SUsb(
priv->SetRFPowerStateInProgress = TRUE;
- // TODO: Emily, 2006.11.21, we should rewrite this function
if(RFPowerState==RF_SHUT_DOWN)
{
@@ -1420,22 +1213,20 @@ PHY_SetRFPowerState8192SUsb(
case RF_8258:
break;
- }// switch( priv->rf_chip )
+ }
priv->SetRFPowerStateInProgress = FALSE;
}
#endif
#ifdef RTL8192U
-//no use temp in windows driver
void
PHY_UpdateInitialGain(
struct net_device* dev
)
{
struct r8192_priv *priv = ieee80211_priv(dev);
- //unsigned char *IGTable;
- //u8 DIG_CurrentInitialGain = 4;
+
switch(priv->rf_chip)
{
@@ -1456,7 +1247,6 @@ PHY_UpdateInitialGain(
}
#endif
-//YJ,modified,090107
void PHY_GetHWRegOriginalValue(struct net_device* dev)
{
struct r8192_priv *priv = ieee80211_priv(dev);
@@ -1625,8 +1415,6 @@ static void phy_InitBBRFRegisterDefinition( struct net_device* dev)
// Tranceiver LSSI Readback PI mode
priv->PHYRegDef[RF90_PATH_A].rfLSSIReadBackPi = TransceiverA_HSPI_Readback;
priv->PHYRegDef[RF90_PATH_B].rfLSSIReadBackPi = TransceiverB_HSPI_Readback;
- //pHalData->PHYRegDef[RF90_PATH_C].rfLSSIReadBackPi = rFPGA0_XC_LSSIReadBack;
- //pHalData->PHYRegDef[RF90_PATH_D].rfLSSIReadBackPi = rFPGA0_XD_LSSIReadBack;
}
@@ -1637,9 +1425,7 @@ static void phy_InitBBRFRegisterDefinition( struct net_device* dev)
// Assumption: This function must be executed in re-schdulable context,
// ie. PASSIVE_LEVEL.
//
-// 050823, by rcnjko.
-//not understand it seem's use in init
-//SetHwReg8192SUsb--->HalFunc.SetHwRegHandler
+
bool PHY_SetRFPowerState(struct net_device* dev, RT_RF_POWER_STATE eRFPowerState)
{
struct r8192_priv *priv = ieee80211_priv(dev);
@@ -1665,8 +1451,6 @@ static bool phy_SetRFPowerState8192SU(struct net_device* dev,RT_RF_POWER_STATE e
{
struct r8192_priv *priv = ieee80211_priv(dev);
bool bResult = TRUE;
- //u8 eRFPath;
- //u8 i, QueueID;
u8 u1bTmp;
if(priv->SetRFPowerStateInProgress == TRUE)
@@ -1697,9 +1481,6 @@ static bool phy_SetRFPowerState8192SU(struct net_device* dev,RT_RF_POWER_STATE e
break;
//
//RF Off/Sleep sequence. Designed/tested from SD4 Scott, SD1 Grent and Jonbon.
- // Added by Bruce, 2008-11-22.
- //
- //==================================================================
// (0) Disable FW BB reset checking
write_nic_dword(dev, WFM5, FW_BB_RESET_DISABLE);
@@ -1728,7 +1509,6 @@ static bool phy_SetRFPowerState8192SU(struct net_device* dev,RT_RF_POWER_STATE e
default:
bResult = FALSE;
- //RT_ASSERT(FALSE, ("phy_SetRFPowerState8192SU(): unknown state to set: 0x%X!!!\n", eRFPowerState));
break;
}
break;
@@ -1860,7 +1640,6 @@ PHY_GetTxPowerLevel8192S(
void PHY_SetTxPowerLevel8192S(struct net_device* dev, u8 channel)
{
struct r8192_priv *priv = ieee80211_priv(dev);
- //HAL_DATA_TYPE *pHalData = GET_HAL_DATA(dev);
u8 powerlevel = (u8)EEPROM_Default_TxPower, powerlevelOFDM24G = 0x10;
s8 ant_pwr_diff = 0;
u32 u4RegValue;
@@ -1909,14 +1688,6 @@ PHY_GetTxPowerLevel8192S(
// RF B HT OFDM pwr-RFA HT OFDM pwr
ant_pwr_diff = priv->RfTxPwrLevelOfdm2T[1][index] -
priv->RfTxPwrLevelOfdm2T[0][index];
- // RF B (HT OFDM pwr+legacy-ht-diff) -(RFA HT OFDM pwr+legacy-ht-diff)
- // We can not handle Path B&A HT/Legacy pwr diff for 92S now.
-
- //RTPRINT(FPHY, PHY_TXPWR, ("CH-%d HT40 A/B Pwr index = %x/%x(%d/%d)\n",
- //channel, priv->RfTxPwrLevelOfdm2T[0][index],
- //priv->RfTxPwrLevelOfdm2T[1][index],
- //priv->RfTxPwrLevelOfdm2T[0][index],
- //priv->RfTxPwrLevelOfdm2T[1][index]));
ht20pwr[0] = ht40pwr[0] = priv->RfTxPwrLevelOfdm2T[0][index];
ht20pwr[1] = ht40pwr[1] = priv->RfTxPwrLevelOfdm2T[1][index];
@@ -1949,10 +1720,6 @@ PHY_GetTxPowerLevel8192S(
// RF B HT OFDM pwr-RFA HT OFDM pwr
if (priv->rf_type == RF_2T2R)
ant_pwr_diff = ht20pwr[1] - ht20pwr[0];
-
- //RTPRINT(FPHY, PHY_TXPWR,
- //("HT20 to HT40 pwrdiff[A/B]=%d/%d, ant_pwr_diff=%d(B-A=%d-%d)\n",
- //pwrdiff[0], pwrdiff[1], ant_pwr_diff, ht20pwr[1], ht20pwr[0]));
}
// Band Edge scheme is enabled for FCC mode
@@ -1997,18 +1764,12 @@ PHY_GetTxPowerLevel8192S(
{
if (channel <= 1 || channel >= 11)
{
- //RTPRINT(FPHY, PHY_TXPWR,
- //("HT20 Band-edge pwrdiff[A/B]=%d/%d, ant_pwr_diff=%d(B-A=%d-%d)\n",
- //pwrdiff[0], pwrdiff[1], ant_pwr_diff, ht20pwr[1], ht20pwr[0]));
}
}
else
{
if (channel <= 3 || channel >= 9)
{
- //RTPRINT(FPHY, PHY_TXPWR,
- //("HT40 Band-edge pwrdiff[A/B]=%d/%d, ant_pwr_diff=%d(B-A=%d-%d)\n",
- //pwrdiff[0], pwrdiff[1], ant_pwr_diff, ht40pwr[1], ht40pwr[0]));
}
}
}
@@ -2021,10 +1782,6 @@ PHY_GetTxPowerLevel8192S(
if(ant_pwr_diff < -8)
ant_pwr_diff = -8;
- //RTPRINT(FPHY, PHY_TXPWR,
- //("CCK/HT Power index = %x/%x(%d/%d), ant_pwr_diff=%d\n",
- //powerlevel, powerlevelOFDM24G, powerlevel, powerlevelOFDM24G, ant_pwr_diff));
-
ant_pwr_diff &= 0xf;
// Antenna TX power difference
@@ -2050,7 +1807,6 @@ PHY_GetTxPowerLevel8192S(
// TODO:
// 1. 802.11h power contraint
//
- // 071011, by rcnjko.
//
#ifdef TODO //WB, 11h has not implemented now.
if( priv->ieee80211->iw_mode != IW_MODE_INFRA && priv->bWithCcxCellPwr &&
@@ -2095,8 +1851,6 @@ PHY_GetTxPowerLevel8192S(
switch(priv->rf_chip)
{
case RF_8225:
- //PHY_SetRF8225CckTxPower(dev, powerlevel);
- //PHY_SetRF8225OfdmTxPower(dev, powerlevelOFDM24G);
break;
case RF_8256:
@@ -2121,8 +1875,6 @@ PHY_GetTxPowerLevel8192S(
//
// TODO:
// A mode.
-// By Bruce, 2008-02-04.
-// no use temp
bool PHY_UpdateTxPowerDbm8192S(struct net_device* dev, long powerInDbm)
{
struct r8192_priv *priv = ieee80211_priv(dev);
@@ -2164,8 +1916,6 @@ bool PHY_UpdateTxPowerDbm8192S(struct net_device* dev, long powerInDbm)
Description:
When beacon interval is changed, the values of the
hw registers should be modified.
- By tynli, 2008.10.24.
-
*/
extern void PHY_SetBeaconHwReg( struct net_device* dev, u16 BeaconInterval)
@@ -2173,8 +1923,6 @@ extern void PHY_SetBeaconHwReg( struct net_device* dev, u16 BeaconInterval)
u32 NewBeaconNum;
NewBeaconNum = BeaconInterval *32 - 64;
- //PlatformEFIOWrite4Byte(Adapter, WFM3+4, NewBeaconNum);
- //PlatformEFIOWrite4Byte(Adapter, WFM3, 0xB026007C);
write_nic_dword(dev, WFM3+4, NewBeaconNum);
write_nic_dword(dev, WFM3, 0xB026007C);
}
@@ -2184,7 +1932,6 @@ extern void PHY_SetBeaconHwReg( struct net_device* dev, u16 BeaconInterval)
// Map dBm into Tx power index according to
// current HW model, for example, RF and PA, and
// current wireless mode.
-// By Bruce, 2008-01-29.
// use in phy only
static u8 phy_DbmToTxPwrIdx(
struct net_device* dev,
@@ -2192,7 +1939,6 @@ static u8 phy_DbmToTxPwrIdx(
long PowerInDbm
)
{
- //struct r8192_priv *priv = ieee80211_priv(dev);
u8 TxPwrIdx = 0;
long Offset = 0;
@@ -2202,7 +1948,6 @@ static u8 phy_DbmToTxPwrIdx(
// 3dbm, and OFDM HT equals to 0dbm repectively.
// Note:
// The mapping may be different by different NICs. Do not use this formula for what needs accurate result.
- // By Bruce, 2008-01-29.
//
switch(WirelessMode)
{
@@ -2238,7 +1983,6 @@ static u8 phy_DbmToTxPwrIdx(
// Map Tx power index into dBm according to
// current HW model, for example, RF and PA, and
// current wireless mode.
-// By Bruce, 2008-01-29.
// use in phy only
static long phy_TxPwrIdxToDbm(
struct net_device* dev,
@@ -2255,7 +1999,6 @@ static long phy_TxPwrIdxToDbm(
// 3dbm, and OFDM HT equals to 0dbm repectively.
// Note:
// The mapping may be different by different NICs. Do not use this formula for what needs accurate result.
- // By Bruce, 2008-01-29.
//
switch(WirelessMode)
{
@@ -2327,9 +2070,6 @@ PHY_ScanOperationBackup8192S(
void PHY_InitialGain8192S(struct net_device* dev,u8 Operation )
{
- //struct r8192_priv *priv = ieee80211_priv(dev);
- //u32 BitMask;
- //u8 initial_gain;
}
/*-----------------------------------------------------------------------------
@@ -2353,11 +2093,6 @@ void PHY_SetBWModeCallback8192S(struct net_device *dev)
struct r8192_priv *priv = ieee80211_priv(dev);
u8 regBwOpMode;
- //return;
-
- // Added it for 20/40 mhz switch time evaluation by guangan 070531
- //u32 NowL, NowH;
- //u8Byte BeginTime, EndTime;
u8 regRRSR_RSC;
RT_TRACE(COMP_SWBW, "==>SetBWModeCallback8190Pci() Switch to %s bandwidth\n", \
@@ -2372,10 +2107,6 @@ void PHY_SetBWModeCallback8192S(struct net_device *dev)
if(!priv->up)
return;
- // Added it for 20/40 mhz switch time evaluation by guangan 070531
- //NowL = read_nic_dword(dev, TSFR);
- //NowH = read_nic_dword(dev, TSFR+4);
- //BeginTime = ((u8Byte)NowH << 32) + NowL;
//3//
//3//<1>Set MAC register
@@ -2386,8 +2117,6 @@ void PHY_SetBWModeCallback8192S(struct net_device *dev)
switch(priv->CurrentChannelBW)
{
case HT_CHANNEL_WIDTH_20:
- //if(priv->card_8192_version >= VERSION_8192S_BCUT)
- // write_nic_byte(dev, rFPGA0_AnalogParameter2, 0x58);
regBwOpMode |= BW_OPMODE_20MHZ;
// 2007/02/07 Mark by Emily becasue we have not verify whether this register works
@@ -2395,8 +2124,6 @@ void PHY_SetBWModeCallback8192S(struct net_device *dev)
break;
case HT_CHANNEL_WIDTH_20_40:
- //if(priv->card_8192_version >= VERSION_8192S_BCUT)
- // write_nic_byte(dev, rFPGA0_AnalogParameter2, 0x18);
regBwOpMode &= ~BW_OPMODE_20MHZ;
// 2007/02/07 Mark by Emily becasue we have not verify whether this register works
@@ -2421,12 +2148,6 @@ void PHY_SetBWModeCallback8192S(struct net_device *dev)
rtl8192_setBBreg(dev, rFPGA0_RFMOD, bRFMOD, 0x0);
rtl8192_setBBreg(dev, rFPGA1_RFMOD, bRFMOD, 0x0);
- // Correct the tx power for CCK rate in 40M. Suggest by YN, 20071207
- // It is set in Tx descriptor for 8192x series
- //write_nic_dword(dev, rCCK0_TxFilter1, 0x1a1b0000);
- //write_nic_dword(dev, rCCK0_TxFilter2, 0x090e1317);
- //write_nic_dword(dev, rCCK0_DebugPort, 0x00000204);
-
if (priv->card_8192_version >= VERSION_8192S_BCUT)
write_nic_byte(dev, rFPGA0_AnalogParameter2, 0x58);
@@ -2438,16 +2159,11 @@ void PHY_SetBWModeCallback8192S(struct net_device *dev)
rtl8192_setBBreg(dev, rFPGA0_RFMOD, bRFMOD, 0x1);
rtl8192_setBBreg(dev, rFPGA1_RFMOD, bRFMOD, 0x1);
- // Correct the tx power for CCK rate in 40M. Suggest by YN, 20071207
- //write_nic_dword(dev, rCCK0_TxFilter1, 0x35360000);
- //write_nic_dword(dev, rCCK0_TxFilter2, 0x121c252e);
- //write_nic_dword(dev, rCCK0_DebugPort, 0x00000409);
// Set Control channel to upper or lower. These settings are required only for 40MHz
rtl8192_setBBreg(dev, rCCK0_System, bCCKSideBand, (priv->nCur40MhzPrimeSC>>1));
rtl8192_setBBreg(dev, rOFDM1_LSTF, 0xC00, priv->nCur40MhzPrimeSC);
- //rtl8192_setBBreg(dev, rFPGA0_AnalogParameter1, 0x00300000, 3);
if (priv->card_8192_version >= VERSION_8192S_BCUT)
write_nic_byte(dev, rFPGA0_AnalogParameter2, 0x18);
@@ -2461,11 +2177,6 @@ void PHY_SetBWModeCallback8192S(struct net_device *dev)
}
//Skip over setting of J-mode in BB register here. Default value is "None J mode". Emily 20070315
- // Added it for 20/40 mhz switch time evaluation by guangan 070531
- //NowL = read_nic_dword(dev, TSFR);
- //NowH = read_nic_dword(dev, TSFR+4);
- //EndTime = ((u8Byte)NowH << 32) + NowL;
- //RT_TRACE(COMP_SCAN, DBG_LOUD, ("SetBWModeCallback8190Pci: time of SetBWMode = %I64d us!\n", (EndTime - BeginTime)));
//3<3>Set RF related register
switch( priv->rf_chip )
@@ -2516,36 +2227,11 @@ void PHY_SetBWModeCallback8192S(struct net_device *dev)
*
* Note: We do not take j mode into consideration now
*---------------------------------------------------------------------------*/
-//extern void PHY_SetBWMode8192S( struct net_device* dev,
-// HT_CHANNEL_WIDTH Bandwidth, // 20M or 40M
-// HT_EXTCHNL_OFFSET Offset // Upper, Lower, or Don't care
void rtl8192_SetBWMode(struct net_device *dev, HT_CHANNEL_WIDTH Bandwidth, HT_EXTCHNL_OFFSET Offset)
{
struct r8192_priv *priv = ieee80211_priv(dev);
HT_CHANNEL_WIDTH tmpBW = priv->CurrentChannelBW;
-
- // Modified it for 20/40 mhz switch by guangan 070531
-
- //return;
-
- //if(priv->SwChnlInProgress)
-// if(pMgntInfo->bScanInProgress)
-// {
-// RT_TRACE(COMP_SCAN, DBG_LOUD, ("SetBWMode8190Pci() %s Exit because bScanInProgress!\n",
-// Bandwidth == HT_CHANNEL_WIDTH_20?"20MHz":"40MHz"));
-// return;
-// }
-
-// if(priv->SetBWModeInProgress)
-// {
-// // Modified it for 20/40 mhz switch by guangan 070531
-// RT_TRACE(COMP_SCAN, DBG_LOUD, ("SetBWMode8190Pci() %s cancel last timer because SetBWModeInProgress!\n",
-// Bandwidth == HT_CHANNEL_WIDTH_20?"20MHz":"40MHz"));
-// PlatformCancelTimer(dev, &priv->SetBWModeTimer);
-// //return;
-// }
-
if(priv->SetBWModeInProgress)
return;
@@ -2560,7 +2246,7 @@ void rtl8192_SetBWMode(struct net_device *dev, HT_CHANNEL_WIDTH Bandwidth, HT_EX
else
priv->nCur40MhzPrimeSC = HAL_PRIME_CHNL_OFFSET_DONT_CARE;
- if((priv->up) )// && !(RT_CANNOT_IO(Adapter) && Adapter->bInSetPower) )
+ if((priv->up) )
{
SetBWModeCallback8192SUsbWorkItem(dev);
}
@@ -2578,7 +2264,6 @@ void PHY_SwChnlCallback8192S(struct net_device *dev)
struct r8192_priv *priv = ieee80211_priv(dev);
u32 delay;
- //bool ret;
RT_TRACE(COMP_CH, "==>SwChnlCallback8190Pci(), switch to channel %d\n", priv->chan);
@@ -2595,16 +2280,11 @@ void PHY_SwChnlCallback8192S(struct net_device *dev)
if(!priv->SwChnlInProgress)
break;
- //if(!phy_SwChnlStepByStep(dev, priv->CurrentChannel, &priv->SwChnlStage, &priv->SwChnlStep, &delay))
if(!phy_SwChnlStepByStep(dev, priv->chan, &priv->SwChnlStage, &priv->SwChnlStep, &delay))
{
if(delay>0)
{
mdelay(delay);
- //PlatformSetTimer(dev, &priv->SwChnlTimer, delay);
- //mod_timer(&priv->SwChnlTimer, jiffies + MSECS(delay));
- //==>PHY_SwChnlCallback8192S(dev); for 92se
- //==>SwChnlCallback8192SUsb(dev) for 92su
}
else
continue;
@@ -2618,12 +2298,9 @@ void PHY_SwChnlCallback8192S(struct net_device *dev)
}
// Call after initialization
-//extern void PHY_SwChnl8192S(struct net_device* dev, u8 channel)
u8 rtl8192_phy_SwChnl(struct net_device* dev, u8 channel)
{
struct r8192_priv *priv = ieee80211_priv(dev);
- //u8 tmpchannel =channel;
- //bool bResult = false;
if(!priv->up)
return false;
@@ -2634,7 +2311,6 @@ u8 rtl8192_phy_SwChnl(struct net_device* dev, u8 channel)
if(priv->SetBWModeInProgress)
return false;
- //--------------------------------------------
switch(priv->ieee80211->mode)
{
case WIRELESS_MODE_A:
@@ -2661,10 +2337,9 @@ u8 rtl8192_phy_SwChnl(struct net_device* dev, u8 channel)
break;
default:
- ;//RT_TRACE(COMP_ERR, "Invalid WirelessMode(%#x)!!\n", priv->ieee80211->mode);
+ ;
break;
}
- //--------------------------------------------
priv->SwChnlInProgress = TRUE;
if( channel == 0)
@@ -2675,7 +2350,7 @@ u8 rtl8192_phy_SwChnl(struct net_device* dev, u8 channel)
priv->SwChnlStage=0;
priv->SwChnlStep=0;
- if((priv->up))// && !(RT_CANNOT_IO(Adapter) && Adapter->bInSetPower))
+ if((priv->up))
{
SwChnlCallback8192SUsbWorkItem(dev);
#ifdef TO_DO_LIST
@@ -2695,7 +2370,6 @@ u8 rtl8192_phy_SwChnl(struct net_device* dev, u8 channel)
{
RT_TRACE(COMP_SCAN, "PHY_SwChnl8192S SwChnlInProgress FALSE driver sleep or unload\n");
priv->SwChnlInProgress = false;
- //priv->CurrentChannel = tmpchannel;
}
return true;
}
@@ -2709,8 +2383,7 @@ u8 rtl8192_phy_SwChnl(struct net_device* dev, u8 channel)
// The following procedure is operted according to SwChanlCallback8190Pci().
// However, this procedure is performed synchronously which should be running under
// passive level.
-//
-//not understand it
+
void PHY_SwChnlPhy8192S( // Only called during initialize
struct net_device* dev,
u8 channel
@@ -2767,14 +2440,10 @@ phy_SetSwChnlCmdArray(
if(CmdTable == NULL)
{
- //RT_ASSERT(FALSE, ("phy_SetSwChnlCmdArray(): CmdTable cannot be NULL.\n"));
return FALSE;
}
if(CmdTableIdx >= CmdTableSz)
{
- //RT_ASSERT(FALSE,
- // ("phy_SetSwChnlCmdArray(): Access invalid index, please check size of the table, CmdTableIdx:%d, CmdTableSz:%d\n",
- //CmdTableIdx, CmdTableSz));
return FALSE;
}
@@ -2798,7 +2467,6 @@ phy_SwChnlStepByStep(
)
{
struct r8192_priv *priv = ieee80211_priv(dev);
- //PCHANNEL_ACCESS_SETTING pChnlAccessSetting;
SwChnlCmd PreCommonCmd[MAX_PRECMD_CNT];
u32 PreCommonCmdCnt;
SwChnlCmd PostCommonCmd[MAX_POSTCMD_CNT];
@@ -2808,22 +2476,13 @@ phy_SwChnlStepByStep(
SwChnlCmd *CurrentCmd = NULL;
u8 eRFPath;
- //RT_ASSERT((dev != NULL), ("Adapter should not be NULL\n"));
- //RT_ASSERT(IsLegalChannel(dev, channel), ("illegal channel: %d\n", channel));
RT_TRACE(COMP_CH, "===========>%s(), channel:%d, stage:%d, step:%d\n", __FUNCTION__, channel, *stage, *step);
- //RT_ASSERT((pHalData != NULL), ("pHalData should not be NULL\n"));
if (!IsLegalChannel(priv->ieee80211, channel))
{
RT_TRACE(COMP_ERR, "=============>set to illegal channel:%d\n", channel);
return true; //return true to tell upper caller function this channel setting is finished! Or it will in while loop.
}
- //pChnlAccessSetting = &Adapter->MgntInfo.Info8185.ChannelAccessSetting;
- //RT_ASSERT((pChnlAccessSetting != NULL), ("pChnlAccessSetting should not be NULL\n"));
-
- //for(eRFPath = RF90_PATH_A; eRFPath <priv->NumTotalRFPath; eRFPath++)
- //for(eRFPath = 0; eRFPath <priv->NumTotalRFPath; eRFPath++)
- //{
// <1> Fill up pre common command.
PreCommonCmdCnt = 0;
phy_SetSwChnlCmdArray(PreCommonCmd, PreCommonCmdCnt++, MAX_PRECMD_CNT,
@@ -2844,8 +2503,7 @@ phy_SwChnlStepByStep(
case RF_8225:
if (channel < 1 || channel > 14)
RT_TRACE(COMP_ERR, "illegal channel for zebra:%d\n", channel);
- //RT_ASSERT((channel >= 1 && channel <= 14), ("illegal channel for Zebra: %d\n", channel));
- // 2008/09/04 MH Change channel.
+
phy_SetSwChnlCmdArray(RfDependCmd, RfDependCmdCnt++, MAX_RFDEPENDCMD_CNT,
CmdID_RF_WriteReg, rRfChannel, channel, 10);
phy_SetSwChnlCmdArray(RfDependCmd, RfDependCmdCnt++, MAX_RFDEPENDCMD_CNT,
@@ -2855,8 +2513,6 @@ phy_SwChnlStepByStep(
case RF_8256:
if (channel < 1 || channel > 14)
RT_TRACE(COMP_ERR, "illegal channel for zebra:%d\n", channel);
- // TEST!! This is not the table for 8256!!
- //RT_ASSERT((channel >= 1 && channel <= 14), ("illegal channel for Zebra: %d\n", channel));
phy_SetSwChnlCmdArray(RfDependCmd, RfDependCmdCnt++, MAX_RFDEPENDCMD_CNT,
CmdID_RF_WriteReg, rRfChannel, channel, 10);
phy_SetSwChnlCmdArray(RfDependCmd, RfDependCmdCnt++, MAX_RFDEPENDCMD_CNT,
@@ -2876,7 +2532,6 @@ phy_SwChnlStepByStep(
break;
default:
- //RT_ASSERT(FALSE, ("Unknown rf_chip: %d\n", priv->rf_chip));
return FALSE;
break;
}
@@ -2913,7 +2568,6 @@ phy_SwChnlStepByStep(
switch(CurrentCmd->CmdID)
{
case CmdID_SetTxPowerLevel:
- //if(priv->card_8192_version > VERSION_8190_BD)
PHY_SetTxPowerLevel8192S(dev,channel);
break;
case CmdID_WritePortUlong:
@@ -2930,7 +2584,6 @@ phy_SwChnlStepByStep(
{
// For new T65 RF 0222d register 0x18 bit 0-9 = channel number.
rtl8192_phy_SetRFReg(dev, (RF90_RADIO_PATH_E)eRFPath, CurrentCmd->Para1, 0x1f, (CurrentCmd->Para2));
- //printk("====>%x, %x, read_back:%x\n", CurrentCmd->Para2,CurrentCmd->Para1, rtl8192_phy_QueryRFReg(dev, (RF90_RADIO_PATH_E)eRFPath, CurrentCmd->Para1, 0x1f));
}
break;
default:
@@ -2939,7 +2592,6 @@ phy_SwChnlStepByStep(
break;
}while(TRUE);
- //cosa }/*for(Number of RF paths)*/
(*delay)=CurrentCmd->msDelay;
(*step)++;
@@ -2985,14 +2637,8 @@ phy_FinishSwChnlNow( // We should not call this function directly
* 11/15/2007 MHC Create Version 0.
*
*---------------------------------------------------------------------------*/
- //called by rtl8192_phy_QueryRFReg, rtl8192_phy_SetRFReg, PHY_SetRFPowerState8192SUsb
-//extern bool
-//PHY_CheckIsLegalRfPath8192S(
-// struct net_device* dev,
-// u32 eRFPath)
u8 rtl8192_phy_CheckIsLegalRFPath(struct net_device* dev, u32 eRFPath)
{
-// struct r8192_priv *priv = ieee80211_priv(dev);
bool rtValue = TRUE;
// NOt check RF Path now.!
@@ -3023,7 +2669,6 @@ u8 rtl8192_phy_CheckIsLegalRFPath(struct net_device* dev, u32 eRFPath)
void
PHY_IQCalibrate( struct net_device* dev)
{
- //struct r8192_priv *priv = ieee80211_priv(dev);
u32 i, reg;
u32 old_value;
long X, Y, TX0[4];
@@ -3039,7 +2684,6 @@ PHY_IQCalibrate( struct net_device* dev)
{
// IQK
rtl8192_setBBreg(dev, 0xc04, bMaskDWord, 0x00a05430);
- //PlatformStallExecution(5);
udelay(5);
rtl8192_setBBreg(dev, 0xc08, bMaskDWord, 0x000800e4);
udelay(5);
@@ -3169,8 +2813,6 @@ PHY_IQCalibrate( struct net_device* dev)
*---------------------------------------------------------------------------*/
extern void PHY_IQCalibrateBcut(struct net_device* dev)
{
- //struct r8192_priv *priv = ieee80211_priv(dev);
- //PMGNT_INFO pMgntInfo = &pAdapter->MgntInfo;
u32 i, reg;
u32 old_value;
long X, Y, TX0[4];
@@ -3184,21 +2826,6 @@ extern void PHY_IQCalibrateBcut(struct net_device* dev)
//
// 1. Save e70~ee0 register setting, and load calibration setting
//
- /*
- 0xee0[31:0]=0x3fed92fb;
- 0xedc[31:0] =0x3fed92fb;
- 0xe70[31:0] =0x3fed92fb;
- 0xe74[31:0] =0x3fed92fb;
- 0xe78[31:0] =0x3fed92fb;
- 0xe7c[31:0]= 0x3fed92fb;
- 0xe80[31:0]= 0x3fed92fb;
- 0xe84[31:0]= 0x3fed92fb;
- 0xe88[31:0]= 0x3fed92fb;
- 0xe8c[31:0]= 0x3fed92fb;
- 0xed0[31:0]= 0x3fed92fb;
- 0xed4[31:0]= 0x3fed92fb;
- 0xed8[31:0]= 0x3fed92fb;
- */
calibrate_set [0] = 0xee0;
calibrate_set [1] = 0xedc;
calibrate_set [2] = 0xe70;
@@ -3212,7 +2839,6 @@ extern void PHY_IQCalibrateBcut(struct net_device* dev)
calibrate_set [10] = 0xed0;
calibrate_set [11] = 0xed4;
calibrate_set [12] = 0xed8;
- //RT_TRACE(COMP_INIT, DBG_LOUD, ("Save e70~ee0 register setting\n"));
for (i = 0; i < 13; i++)
{
load_value[i] = rtl8192_QueryBBReg(dev, calibrate_set[i], bMaskDWord);
@@ -3232,7 +2858,6 @@ extern void PHY_IQCalibrateBcut(struct net_device* dev)
//BB switch to PI mode. If default is PI mode, ignoring 2 commands below.
if (!RfPiEnable) //if original is SI mode, then switch to PI mode.
{
- //DbgPrint("IQK Switch to PI mode\n");
rtl8192_setBBreg(dev, 0x820, bMaskDWord, 0x01000100);
rtl8192_setBBreg(dev, 0x828, bMaskDWord, 0x01000100);
}
@@ -3286,7 +2911,6 @@ extern void PHY_IQCalibrateBcut(struct net_device* dev)
if (!RfPiEnable) //if original is SI mode, then switch to PI mode.
{
- //DbgPrint("IQK Switch back to SI mode\n");
rtl8192_setBBreg(dev, 0x820, bMaskDWord, 0x01000000);
rtl8192_setBBreg(dev, 0x828, bMaskDWord, 0x01000000);
}
@@ -3369,7 +2993,6 @@ extern void PHY_IQCalibrateBcut(struct net_device* dev)
//
// 4. Reload e70~ee0 register setting.
//
- //RT_TRACE(COMP_INIT, DBG_LOUD, ("Reload e70~ee0 register setting.\n"));
for (i = 0; i < 13; i++)
rtl8192_setBBreg(dev, calibrate_set[i], bMaskDWord, load_value[i]);
@@ -3380,14 +3003,12 @@ extern void PHY_IQCalibrateBcut(struct net_device* dev)
-} // PHY_IQCalibrateBcut
+}
//
// Move from phycfg.c to gen.c to be code independent later
//
-//-------------------------Move to other DIR later----------------------------*/
-//#if (DEV_BUS_TYPE == USB_INTERFACE)
// use in phy only (in win it's timer)
void SwChnlCallback8192SUsb(struct net_device *dev)
@@ -3395,7 +3016,6 @@ void SwChnlCallback8192SUsb(struct net_device *dev)
struct r8192_priv *priv = ieee80211_priv(dev);
u32 delay;
-// bool ret;
RT_TRACE(COMP_SCAN, "==>SwChnlCallback8190Pci(), switch to channel %d\n",
priv->chan);
@@ -3418,7 +3038,6 @@ void SwChnlCallback8192SUsb(struct net_device *dev)
{
if(delay>0)
{
- //PlatformSetTimer(dev, &priv->SwChnlTimer, delay);
}
else
@@ -3473,16 +3092,12 @@ void SwChnlCallback8192SUsbWorkItem(struct net_device *dev )
* (2) Will two workitem of "switch channel" and "switch channel bandwidth" run
* concurrently?
*---------------------------------------------------------------------------*/
-//====>//rtl8192_SetBWMode
-// use in phy only (in win it's timer)
+// use in phy only
void SetBWModeCallback8192SUsb(struct net_device *dev)
{
struct r8192_priv *priv = ieee80211_priv(dev);
u8 regBwOpMode;
- // Added it for 20/40 mhz switch time evaluation by guangan 070531
- //u32 NowL, NowH;
- //u8Byte BeginTime, EndTime;
u8 regRRSR_RSC;
RT_TRACE(COMP_SCAN, "==>SetBWModeCallback8190Pci() Switch to %s bandwidth\n", \
@@ -3497,10 +3112,6 @@ void SetBWModeCallback8192SUsb(struct net_device *dev)
if(!priv->up)
return;
- // Added it for 20/40 mhz switch time evaluation by guangan 070531
- //NowL = read_nic_dword(dev, TSFR);
- //NowH = read_nic_dword(dev, TSFR+4);
- //BeginTime = ((u8Byte)NowH << 32) + NowL;
//3<1>Set MAC register
regBwOpMode = read_nic_byte(dev, BW_OPMODE);
@@ -3510,13 +3121,11 @@ void SetBWModeCallback8192SUsb(struct net_device *dev)
{
case HT_CHANNEL_WIDTH_20:
regBwOpMode |= BW_OPMODE_20MHZ;
- // 2007/02/07 Mark by Emily becasue we have not verify whether this register works
write_nic_byte(dev, BW_OPMODE, regBwOpMode);
break;
case HT_CHANNEL_WIDTH_20_40:
regBwOpMode &= ~BW_OPMODE_20MHZ;
- // 2007/02/07 Mark by Emily becasue we have not verify whether this register works
write_nic_byte(dev, BW_OPMODE, regBwOpMode);
regRRSR_RSC = (regRRSR_RSC&0x90) |(priv->nCur40MhzPrimeSC<<5);
@@ -3546,12 +3155,6 @@ void SetBWModeCallback8192SUsb(struct net_device *dev)
rtl8192_setBBreg(dev, rCCK0_System, bCCKSideBand, (priv->nCur40MhzPrimeSC>>1));
rtl8192_setBBreg(dev, rOFDM1_LSTF, 0xC00, priv->nCur40MhzPrimeSC);
- // Correct the tx power for CCK rate in 40M. Suggest by YN, 20071207
- //PHY_SetBBReg(Adapter, rCCK0_TxFilter1, bMaskDWord, 0x35360000);
- //PHY_SetBBReg(Adapter, rCCK0_TxFilter2, bMaskDWord, 0x121c252e);
- //PHY_SetBBReg(Adapter, rCCK0_DebugPort, bMaskDWord, 0x00000409);
- //PHY_SetBBReg(Adapter, rFPGA0_AnalogParameter1, bADClkPhase, 0);
-
if (priv->card_8192_version >= VERSION_8192S_BCUT)
rtl8192_setBBreg(dev, rFPGA0_AnalogParameter2, 0xff, 0x18);
@@ -3564,12 +3167,6 @@ void SetBWModeCallback8192SUsb(struct net_device *dev)
}
//Skip over setting of J-mode in BB register here. Default value is "None J mode". Emily 20070315
- // Added it for 20/40 mhz switch time evaluation by guangan 070531
- //NowL = read_nic_dword(dev, TSFR);
- //NowH = read_nic_dword(dev, TSFR+4);
- //EndTime = ((u8Byte)NowH << 32) + NowL;
- //RT_TRACE(COMP_SCAN, DBG_LOUD, ("SetBWModeCallback8190Pci: time of SetBWMode = %I64d us!\n", (EndTime - BeginTime)));
-
#if 1
//3<3>Set RF related register
switch( priv->rf_chip )
@@ -3597,7 +3194,6 @@ void SetBWModeCallback8192SUsb(struct net_device *dev)
break;
default:
- //RT_ASSERT(FALSE, ("Unknown rf_chip: %d\n", priv->rf_chip));
break;
}
#endif
@@ -3705,7 +3301,6 @@ void SetBWModeCallback8192SUsbWorkItem(struct net_device *dev)
priv->SetBWModeInProgress= FALSE;
}
-//--------------------------Move to oter DIR later-------------------------------*/
void InitialGain8192S(struct net_device *dev, u8 Operation)
{
#ifdef TO_DO_LIST
@@ -3812,7 +3407,6 @@ bool HalSetFwCmd8192S(struct net_device* dev, FW_CMD_IO_TYPE FwCmdIO)
u16 FwCmdWaitLimit = 1000;
- //if(IS_HARDWARE_TYPE_8192SU(Adapter) && Adapter->bInHctTest)
if(priv->bInHctTest)
return true;
@@ -3828,11 +3422,6 @@ bool HalSetFwCmd8192S(struct net_device* dev, FW_CMD_IO_TYPE FwCmdIO)
#if 1
while(priv->SetFwCmdInProgress && FwCmdWaitCounter<FwCmdWaitLimit)
{
- //if(RT_USB_CANNOT_IO(Adapter))
- //{
- // RT_TRACE(COMP_CMD, DBG_WARNING, ("HalSetFwCmd8192S(): USB can NOT IO!!\n"));
- // return FALSE;
- //}
RT_TRACE(COMP_CMD, "HalSetFwCmd8192S(): previous workitem not finish!!\n");
return false;
@@ -3843,9 +3432,7 @@ bool HalSetFwCmd8192S(struct net_device* dev, FW_CMD_IO_TYPE FwCmdIO)
if(FwCmdWaitCounter == FwCmdWaitLimit)
{
- //RT_ASSERT(FALSE, ("SetFwCmdIOWorkItemCallback(): Wait too logn to set FW CMD\n"));
RT_TRACE(COMP_CMD, "HalSetFwCmd8192S(): Wait too logn to set FW CMD\n");
- //return false;
}
#endif
if (priv->SetFwCmdInProgress)
@@ -3898,10 +3485,10 @@ void ChkFwCmdIoDone(struct net_device* dev)
//
void phy_SetFwCmdIOCallback(struct net_device* dev)
{
- //struct net_device* dev = (struct net_device*) data;
- u32 input;
- static u32 ScanRegister;
struct r8192_priv *priv = ieee80211_priv(dev);
+ PRT_HIGH_THROUGHPUT pHTInfo = priv->ieee80211->pHTInfo;
+ rt_firmware *pFirmware = priv->pFirmware;
+ u32 input, CurrentAID = 0;;
if(!priv->up)
{
RT_TRACE(COMP_CMD, "SetFwCmdIOTimerCallback(): driver is going to unload\n");
@@ -3910,61 +3497,22 @@ void phy_SetFwCmdIOCallback(struct net_device* dev)
RT_TRACE(COMP_CMD, "--->SetFwCmdIOTimerCallback(): Cmd(%#x), SetFwCmdInProgress(%d)\n", priv->CurrentFwCmdIO, priv->SetFwCmdInProgress);
- switch(priv->CurrentFwCmdIO)
+ if(pFirmware->FirmwareVersion >= 0x34)
{
- case FW_CMD_HIGH_PWR_ENABLE:
- if((priv->ieee80211->pHTInfo->IOTAction & HT_IOT_ACT_DISABLE_HIGH_POWER)==0)
- write_nic_dword(dev, WFM5, FW_HIGH_PWR_ENABLE);
- break;
-
- case FW_CMD_HIGH_PWR_DISABLE:
- write_nic_dword(dev, WFM5, FW_HIGH_PWR_DISABLE);
- break;
-
- case FW_CMD_DIG_RESUME:
- write_nic_dword(dev, WFM5, FW_DIG_RESUME);
- break;
-
- case FW_CMD_DIG_HALT:
- write_nic_dword(dev, WFM5, FW_DIG_HALT);
- break;
-
- //
- // <Roger_Notes> The following FW CMD IO was combined into single operation
- // (i.e., to prevent number of system workitem out of resource!!).
- // 2008.12.04.
- //
- case FW_CMD_RESUME_DM_BY_SCAN:
- RT_TRACE(COMP_CMD, "[FW CMD] Set HIGHPWR enable and DIG resume!!\n");
- if((priv->ieee80211->pHTInfo->IOTAction & HT_IOT_ACT_DISABLE_HIGH_POWER)==0)
- {
- write_nic_dword(dev, WFM5, FW_HIGH_PWR_ENABLE); //break;
- ChkFwCmdIoDone(dev);
- }
- write_nic_dword(dev, WFM5, FW_DIG_RESUME);
- break;
-
- case FW_CMD_PAUSE_DM_BY_SCAN:
- RT_TRACE(COMP_CMD, "[FW CMD] Set HIGHPWR disable and DIG halt!!\n");
- write_nic_dword(dev, WFM5, FW_HIGH_PWR_DISABLE); //break;
- ChkFwCmdIoDone(dev);
- write_nic_dword(dev, WFM5, FW_DIG_HALT);
+ switch(priv->CurrentFwCmdIO)
+ {
+ case FW_CMD_RA_REFRESH_N:
+ priv->CurrentFwCmdIO = FW_CMD_RA_REFRESH_N_COMB;
break;
-
- //
- // <Roger_Notes> The following FW CMD IO should be checked
- // (i.e., workitem schedule timing issue!!).
- // 2008.12.04.
- //
- case FW_CMD_DIG_DISABLE:
- RT_TRACE(COMP_CMD, "[FW CMD] Set DIG disable!!\n");
- write_nic_dword(dev, WFM5, FW_DIG_DISABLE);
+ case FW_CMD_RA_REFRESH_BG:
+ priv->CurrentFwCmdIO = FW_CMD_RA_REFRESH_BG_COMB;
break;
-
- case FW_CMD_DIG_ENABLE:
- RT_TRACE(COMP_CMD, "[FW CMD] Set DIG enable!!\n");
- write_nic_dword(dev, WFM5, FW_DIG_ENABLE);
+ default:
break;
+ }
+ }
+ switch(priv->CurrentFwCmdIO)
+ {
case FW_CMD_RA_RESET:
write_nic_dword(dev, WFM5, FW_RA_RESET);
@@ -3975,82 +3523,111 @@ void phy_SetFwCmdIOCallback(struct net_device* dev)
break;
case FW_CMD_RA_REFRESH_N:
- RT_TRACE(COMP_CMD, "[FW CMD] Set RA refresh!! N\n");
- if(priv->ieee80211->pHTInfo->IOTRaFunc & HT_IOT_RAFUNC_DISABLE_ALL)
+ RT_TRACE(COMP_CMD, "[FW CMD] Set RA n refresh!!\n");
+ if(pHTInfo->IOTRaFunc & HT_IOT_RAFUNC_DISABLE_ALL)
input = FW_RA_REFRESH;
else
- input = FW_RA_REFRESH | (priv->ieee80211->pHTInfo->IOTRaFunc << 8);
+ input = FW_RA_REFRESH | (pHTInfo->IOTRaFunc << 8);
write_nic_dword(dev, WFM5, input);
+ ChkFwCmdIoDone(dev);
+ write_nic_dword(dev, WFM5, FW_RA_ENABLE_RSSI_MASK);
+ ChkFwCmdIoDone(dev);
break;
case FW_CMD_RA_REFRESH_BG:
- RT_TRACE(COMP_CMD, "[FW CMD] Set RA refresh!! B/G\n");
+ RT_TRACE(COMP_CMD, "[FW CMD] Set RA BG refresh!!\n");
write_nic_dword(dev, WFM5, FW_RA_REFRESH);
ChkFwCmdIoDone(dev);
- write_nic_dword(dev, WFM5, FW_RA_ENABLE_BG);
+ write_nic_dword(dev, WFM5, FW_RA_DISABLE_RSSI_MASK);
+ ChkFwCmdIoDone(dev);
+ break;
+
+ case FW_CMD_RA_REFRESH_N_COMB:
+ RT_TRACE(COMP_CMD, "[FW CMD] Set RA n Combo refresh!!\n");
+ if(pHTInfo->IOTRaFunc & HT_IOT_RAFUNC_DISABLE_ALL)
+ input = FW_RA_IOT_N_COMB;
+ else
+ input = FW_RA_IOT_N_COMB | (((pHTInfo->IOTRaFunc)&0x0f) << 8);
+ input = input |((pHTInfo->IOTPeer & 0xf) <<12);
+ RT_TRACE(COMP_CMD, "[FW CMD] Set RA/IOT Comb in n mode!! input(%#x)\n", input);
+ write_nic_dword(dev, WFM5, input);
+ ChkFwCmdIoDone(dev);
+ break;
+
+ case FW_CMD_RA_REFRESH_BG_COMB:
+ RT_TRACE(COMP_CMD, "[FW CMD] Set RA B/G Combo refresh!!\n");
+ if(pHTInfo->IOTRaFunc & HT_IOT_RAFUNC_DISABLE_ALL)
+ input = FW_RA_IOT_BG_COMB;
+ else
+ input = FW_RA_IOT_BG_COMB | (((pHTInfo->IOTRaFunc)&0x0f) << 8);
+ input = input |((pHTInfo->IOTPeer & 0xf) <<12);
+ RT_TRACE(COMP_CMD, "[FW CMD] Set RA/IOT Comb in B/G mode!! input(%#x)\n", input);
+ write_nic_dword(dev, WFM5, input);
+ ChkFwCmdIoDone(dev);
break;
case FW_CMD_IQK_ENABLE:
write_nic_dword(dev, WFM5, FW_IQK_ENABLE);
+ ChkFwCmdIoDone(dev);
break;
case FW_CMD_TXPWR_TRACK_ENABLE:
write_nic_dword(dev, WFM5, FW_TXPWR_TRACK_ENABLE);
+ ChkFwCmdIoDone(dev);
break;
case FW_CMD_TXPWR_TRACK_DISABLE:
write_nic_dword(dev, WFM5, FW_TXPWR_TRACK_DISABLE);
+ ChkFwCmdIoDone(dev);
break;
- default:
- RT_TRACE(COMP_CMD,"Unknown FW Cmd IO(%#x)\n", priv->CurrentFwCmdIO);
+ case FW_CMD_PAUSE_DM_BY_SCAN:
+ RT_TRACE(COMP_CMD,"[FW CMD] Pause DM by Scan!!\n");
+ rtl8192_setBBreg(dev, rOFDM0_XAAGCCore1, bMaskByte0, 0x17);
+ rtl8192_setBBreg(dev, rOFDM0_XBAGCCore1, bMaskByte0, 0x17);
+ rtl8192_setBBreg(dev, rCCK0_CCA, bMaskByte2, 0x40);
break;
- }
-
- ChkFwCmdIoDone(dev);
- switch(priv->CurrentFwCmdIO)
- {
+ case FW_CMD_RESUME_DM_BY_SCAN:
+ RT_TRACE(COMP_CMD, "[FW CMD] Resume DM by Scan!!\n");
+ rtl8192_setBBreg(dev, rCCK0_CCA, bMaskByte2, 0x83);
+ PHY_SetTxPowerLevel8192S(dev, priv->chan);
+ break;
case FW_CMD_HIGH_PWR_DISABLE:
- //if(pMgntInfo->bTurboScan)
- {
- //Lower initial gain
- rtl8192_setBBreg(dev, rOFDM0_XAAGCCore1, bMaskByte0, 0x17);
- rtl8192_setBBreg(dev, rOFDM0_XBAGCCore1, bMaskByte0, 0x17);
- // CCA threshold
- rtl8192_setBBreg(dev, rCCK0_CCA, bMaskByte2, 0x40);
- // Disable OFDM Part
- rtl8192_setBBreg(dev, rOFDM0_TRMuxPar, bMaskByte2, 0x1);
- ScanRegister = rtl8192_QueryBBReg(dev, rOFDM0_RxDetector1,bMaskDWord);
- rtl8192_setBBreg(dev, rOFDM0_RxDetector1, 0xf, 0xf);
- rtl8192_setBBreg(dev, rOFDM1_TRxPathEnable, 0xf, 0x0);
- }
+ RT_TRACE(COMP_CMD, "[FW CMD] High Pwr Disable!!\n");
+ if(priv->DMFlag & HAL_DM_HIPWR_DISABLE)
+ break;
+ rtl8192_setBBreg(dev, rOFDM0_XAAGCCore1, bMaskByte0, 0x17);
+ rtl8192_setBBreg(dev, rOFDM0_XBAGCCore1, bMaskByte0, 0x17);
+ rtl8192_setBBreg(dev, rCCK0_CCA, bMaskByte2, 0x40);
break;
case FW_CMD_HIGH_PWR_ENABLE:
- //if(pMgntInfo->bTurboScan)
- {
- rtl8192_setBBreg(dev, rOFDM0_XAAGCCore1, bMaskByte0, 0x36);
- rtl8192_setBBreg(dev, rOFDM0_XBAGCCore1, bMaskByte0, 0x36);
+ RT_TRACE(COMP_CMD, "[FW CMD] High Pwr Enable!!\n");
+ if(priv->DMFlag & HAL_DM_HIPWR_DISABLE)
+ break;
+ rtl8192_setBBreg(dev, rCCK0_CCA, bMaskByte2, 0x83);
+ break;
- // CCA threshold
- rtl8192_setBBreg(dev, rCCK0_CCA, bMaskByte2, 0x83);
- // Enable OFDM Part
- rtl8192_setBBreg(dev, rOFDM0_TRMuxPar, bMaskByte2, 0x0);
+ case FW_CMD_LPS_ENTER:
+ RT_TRACE(COMP_CMD, "[FW CMD] Enter LPS mode!!\n");
+ CurrentAID = priv->ieee80211->assoc_id;
+ write_nic_dword(dev, WFM5, (FW_LPS_ENTER| ((CurrentAID|0xc000)<<8)) );
+ ChkFwCmdIoDone(dev);
+ pHTInfo->IOTAction |= HT_IOT_ACT_DISABLE_EDCA_TURBO;
+ break;
- //LZM ADD because sometimes there is no FW_CMD_HIGH_PWR_DISABLE, this value will be 0.
- if(ScanRegister != 0){
- rtl8192_setBBreg(dev, rOFDM0_RxDetector1, bMaskDWord, ScanRegister);
- }
+ case FW_CMD_LPS_LEAVE:
+ RT_TRACE(COMP_CMD, "[FW CMD] Leave LPS mode!!\n");
+ write_nic_dword(dev, WFM5, FW_LPS_LEAVE );
+ ChkFwCmdIoDone(dev);
+ pHTInfo->IOTAction &= (~HT_IOT_ACT_DISABLE_EDCA_TURBO);
+ break;
- if(priv->rf_type == RF_1T2R || priv->rf_type == RF_2T2R)
- rtl8192_setBBreg(dev, rOFDM1_TRxPathEnable, 0xf, 0x3);
- else
- rtl8192_setBBreg(dev, rOFDM1_TRxPathEnable, 0xf, 0x1);
- }
+ default:
break;
}
- priv->SetFwCmdInProgress = false;// Clear FW CMD operation flag.
+ priv->SetFwCmdInProgress = false;
RT_TRACE(COMP_CMD, "<---SetFwCmdIOWorkItemCallback()\n");
}
diff --git a/drivers/staging/rtl8192su/r8192U.h b/drivers/staging/rtl8192su/r8192U.h
index eccf4478fba..741c6bf9a01 100644
--- a/drivers/staging/rtl8192su/r8192U.h
+++ b/drivers/staging/rtl8192su/r8192U.h
@@ -1,33 +1,40 @@
-/*
- This is part of rtl8187 OpenSource driver.
- Copyright (C) Andrea Merello 2004-2005 <andreamrl@tiscali.it>
- Released under the terms of GPL (General Public Licence)
-
- Parts of this driver are based on the GPL part of the
- official realtek driver
-
- Parts of this driver are based on the rtl8192 driver skeleton
- from Patric Schenke & Andres Salomon
-
- Parts of this driver are based on the Intel Pro Wireless 2100 GPL driver
-
- We want to tanks the Authors of those projects and the Ndiswrapper
- project Authors.
-*/
+/******************************************************************************
+ * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved.
+ * Linux device driver for RTL8192U
+ *
+ * Based on the r8187 driver, which is:
+ * Copyright 2004-2005 Andrea Merello <andreamrl@tiscali.it>, et al.
+ * 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.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+******************************************************************************/
#ifndef R819xU_H
#define R819xU_H
#include <linux/module.h>
#include <linux/kernel.h>
-//#include <linux/config.h>
#include <linux/init.h>
#include <linux/ioport.h>
#include <linux/sched.h>
#include <linux/types.h>
#include <linux/slab.h>
#include <linux/netdevice.h>
-//#include <linux/pci.h>
#include <linux/usb.h>
#include <linux/etherdevice.h>
#include <linux/delay.h>
@@ -51,9 +58,7 @@
#define RTL819X_EEPROM_CMD_CK (1 << 2)
#define RTL819X_EEPROM_CMD_CS (1 << 3)
-//#define RTL8192U
#define RTL819xU_MODULE_NAME "rtl819xU"
-//added for HW security, john.0629
#define FALSE 0
#define TRUE 1
#define MAX_KEY_LEN 61
@@ -114,6 +119,7 @@ do { if(rt_global_debug_component & component) \
#define COMP_TRACE BIT0 // For function call tracing.
#define COMP_DBG BIT1 // Only for temporary debug message.
+#define COMP_MLME BIT1
#define COMP_INIT BIT2 // during driver initialization / halt / reset.
@@ -137,14 +143,14 @@ do { if(rt_global_debug_component & component) \
#define COMP_SEC BIT20 // Event handling
#define COMP_LED BIT21 // For LED.
#define COMP_RF BIT22 // For RF.
-//1!!!!!!!!!!!!!!!!!!!!!!!!!!!
+#define COMP_RXDESC BIT23
+
#define COMP_RXDESC BIT23 // Show Rx desc information for SD3 debug. Added by Annie, 2006-07-15.
-//1//1Attention Please!!!<11n or 8190 specific code should be put below this line>
-//1!!!!!!!!!!!!!!!!!!!!!!!!!!!
#define COMP_FIRMWARE BIT24 //for firmware downloading
#define COMP_HT BIT25 // For 802.11n HT related information. by Emily 2006-8-11
#define COMP_AMSDU BIT26 // For A-MSDU Debugging
+#define COMP_PS BIT26
#define COMP_SCAN BIT27
#define COMP_CMD BIT28
@@ -159,8 +165,7 @@ do { if(rt_global_debug_component & component) \
printk( "Assertion failed! %s,%s,%s,line=%d\n", \
#expr,__FILE__,__FUNCTION__,__LINE__); \
}
-//wb added to debug out data buf
-//if you want print DATA buffer related BA, please set ieee80211_debug_level to DATA|BA
+
#define RT_DEBUG_DATA(level, data, datalen) \
do{ if ((rt_global_debug_component & (level)) == (level)) \
{ \
@@ -180,25 +185,17 @@ do { if(rt_global_debug_component & component) \
#define RT_DEBUG_DATA(level, data, datalen) do {} while(0)
#endif /* RTL8169_DEBUG */
-//#ifdef RTL8192SU
//2TODO: We should define 8192S firmware related macro settings here!!
#define RTL819X_DEFAULT_RF_TYPE RF_1T2R
#define RTL819X_TOTAL_RF_PATH 2
- //#define Rtl819XFwBootArray Rtl8192UsbFwBootArray
- //#define Rtl819XFwMainArray Rtl8192UsbFwMainArray
- //#define Rtl819XFwDataArray Rtl8192UsbFwDataArray
-
#define Rtl819XMACPHY_Array_PG Rtl8192UsbMACPHY_Array_PG
#define Rtl819XMACPHY_Array Rtl8192UsbMACPHY_Array
#define Rtl819XPHY_REGArray Rtl8192UsbPHY_REGArray
#define Rtl819XPHY_REG_1T2RArray Rtl8192UsbPHY_REG_1T2RArray
- //#define Rtl819XRadioA_Array Rtl8192UsbRadioA_Array
- //#define Rtl819XRadioB_Array Rtl8192UsbRadioB_Array
#define Rtl819XRadioC_Array Rtl8192UsbRadioC_Array
#define Rtl819XRadioD_Array Rtl8192UsbRadioD_Array
- //2008.11.06 Add.
#define Rtl819XFwImageArray Rtl8192SUFwImgArray
#define Rtl819XMAC_Array Rtl8192SUMAC_2T_Array
#define Rtl819XAGCTAB_Array Rtl8192SUAGCTAB_Array
@@ -212,8 +209,6 @@ do { if(rt_global_debug_component & component) \
#define Rtl819XRadioB_GM_Array Rtl8192SURadioB_GM_Array
#define Rtl819XRadioA_to1T_Array Rtl8192SURadioA_to1T_Array
#define Rtl819XRadioA_to2T_Array Rtl8192SURadioA_to2T_Array
-//#endif
-
//
// Queue Select Value in TxDesc
//
@@ -256,7 +251,6 @@ do { if(rt_global_debug_component & component) \
#define DESC90_RATEMCS15 0x0f
#define DESC90_RATEMCS32 0x20
-//#ifdef RTL8192SU
// CCK Rates, TxHT = 0
#define DESC92S_RATE1M 0x00
#define DESC92S_RATE2M 0x01
@@ -292,13 +286,12 @@ do { if(rt_global_debug_component & component) \
#define DESC92S_RATEMCS15 0x1b
#define DESC92S_RATEMCS15_SG 0x1c
#define DESC92S_RATEMCS32 0x20
-//#endif
#define RTL819X_DEFAULT_RF_TYPE RF_1T2R
#define IEEE80211_WATCH_DOG_TIME 2000
#define PHY_Beacon_RSSI_SLID_WIN_MAX 10
-//for txpowertracking by amy
+//for txpowertracking
#define OFDM_Table_Length 19
#define CCK_Table_length 12
@@ -522,7 +515,6 @@ typedef struct rtl8192_rx_info {
u8 out_pipe;
}rtl8192_rx_info ;
-//typedef struct _RX_DESC_STATUS_8192SU{
typedef struct rx_desc_819x_usb{
//DWORD 0
u16 Length:14;
@@ -582,77 +574,34 @@ typedef struct rx_desc_819x_usb{
//DWORD 5
u32 TSFL;
-//}RX_DESC_STATUS_8192SU, *PRX_DESC_STATUS_8192SU;
}rx_desc_819x_usb, *prx_desc_819x_usb;
//
// Driver info are written to the begining of the RxBuffer
//
-//typedef struct _RX_DRIVER_INFO_8192S{
typedef struct rx_drvinfo_819x_usb{
- //
- // Driver info contain PHY status and other variabel size info
- // PHY Status content as below
- //
-
- //DWORD 0
- /*u4Byte gain_0:7;
- u4Byte trsw_0:1;
- u4Byte gain_1:7;
- u4Byte trsw_1:1;
- u4Byte gain_2:7;
- u4Byte trsw_2:1;
- u4Byte gain_3:7;
- u4Byte trsw_3:1; */
u8 gain_trsw[4];
//DWORD 1
- /*u4Byte pwdb_all:8;
- u4Byte cfosho_0:8;
- u4Byte cfosho_1:8;
- u4Byte cfosho_2:8;*/
u8 pwdb_all;
u8 cfosho[4];
//DWORD 2
- /*u4Byte cfosho_3:8;
- u4Byte cfotail_0:8;
- u4Byte cfotail_1:8;
- u4Byte cfotail_2:8;*/
u8 cfotail[4];
//DWORD 3
- /*u4Byte cfotail_3:8;
- u4Byte rxevm_0:8;
- u4Byte rxevm_1:8;
- u4Byte rxsnr_0:8;*/
char rxevm[2];
char rxsnr[4];
//DWORD 4
- /*u4Byte rxsnr_1:8;
- u4Byte rxsnr_2:8;
- u4Byte rxsnr_3:8;
- u4Byte pdsnr_0:8;*/
u8 pdsnr[2];
//DWORD 5
- /*u4Byte pdsnr_1:8;
- u4Byte csi_current_0:8;
- u4Byte csi_current_1:8;
- u4Byte csi_target_0:8;*/
u8 csi_current[2];
u8 csi_target[2];
//DWORD 6
- /*u4Byte csi_target_1:8;
- u4Byte sigevm:8;
- u4Byte max_ex_pwr:8;
- u4Byte ex_intf_flag:1;
- u4Byte sgi_en:1;
- u4Byte rxsc:2;
- u4Byte reserve:4;*/
u8 sigevm;
u8 max_ex_pwr;
u8 ex_intf_flag:1;
@@ -669,10 +618,8 @@ typedef struct rx_drvinfo_819x_usb{
#define MAX_DEV_ADDR_SIZE 8 /* support till 64 bit bus width OS */
#define MAX_FIRMWARE_INFORMATION_SIZE 32 /*2006/04/30 by Emily forRTL8190*/
-//#define MAX_802_11_HEADER_LENGTH (40 + MAX_FIRMWARE_INFORMATION_SIZE)
#define ENCRYPTION_MAX_OVERHEAD 128
#define USB_HWDESC_HEADER_LEN sizeof(tx_desc_819x_usb)
-//#define TX_PACKET_SHIFT_BYTES (USB_HWDESC_HEADER_LEN + sizeof(tx_fwinfo_819x_usb))
#define MAX_FRAGMENT_COUNT 8
#ifdef RTL8192U
#define MAX_TRANSMIT_BUFFER_SIZE 8000
@@ -681,19 +628,15 @@ typedef struct rx_drvinfo_819x_usb{
#endif
#define scrclng 4 // octets for crc32 (FCS, ICV)
+#define HAL_DM_DIG_DISABLE BIT0
+#define HAL_DM_HIPWR_DISABLE BIT1
+
typedef enum rf_optype
{
RF_OP_By_SW_3wire = 0,
RF_OP_By_FW,
RF_OP_MAX
}rf_op_type;
-/* 8190 Loopback Mode definition */
-typedef enum _rtl819xUsb_loopback{
- RTL819xU_NO_LOOPBACK = 0,
- RTL819xU_MAC_LOOPBACK = 1,
- RTL819xU_DMA_LOOPBACK = 2,
- RTL819xU_CCK_LOOPBACK = 3,
-}rtl819xUsb_loopback_e;
/* for rtl819x */
typedef enum _RT_STATUS{
@@ -703,16 +646,13 @@ typedef enum _RT_STATUS{
RT_STATUS_RESOURCE = 3
}RT_STATUS,*PRT_STATUS;
-//#ifdef RTL8192SU
typedef enum _RTL8192SUSB_LOOPBACK{
RTL8192SU_NO_LOOPBACK = 0,
RTL8192SU_MAC_LOOPBACK = 1,
RTL8192SU_DMA_LOOPBACK = 2,
RTL8192SU_CCK_LOOPBACK = 3,
}RTL8192SUSB_LOOPBACK_E;
-//#endif
-//+by amy 080507
#define MAX_RECEIVE_BUFFER_SIZE 9100 // Add this to 9100 bytes to receive A-MSDU from RT-AP
@@ -790,10 +730,6 @@ typedef struct rtl_reg_debug{
typedef struct _rt_9x_tx_rate_history {
u32 cck[4];
u32 ofdm[8];
- // HT_MCS[0][]: BW=0 SG=0
- // HT_MCS[1][]: BW=1 SG=0
- // HT_MCS[2][]: BW=0 SG=1
- // HT_MCS[3][]: BW=1 SG=1
u32 ht_mcs[4][16];
}rt_tx_rahis_t, *prt_tx_rahis_t;
typedef struct _RT_SMOOTH_DATA_4RF {
@@ -808,11 +744,6 @@ typedef struct _RT_SMOOTH_DATA_4RF {
typedef struct Stats
{
unsigned long txrdu;
-// unsigned long rxrdu;
- //unsigned long rxnolast;
- //unsigned long rxnodata;
-// unsigned long rxreset;
-// unsigned long rxnopointer;
unsigned long rxok;
unsigned long rxframgment;
unsigned long rxcmdpkt[4]; //08/05/08 amy rx cmd element txfeedback/bcn report/cfg set/query
@@ -832,18 +763,8 @@ typedef struct Stats
unsigned long txnperr;
unsigned long txnpdrop;
unsigned long txresumed;
-// unsigned long rxerr;
-// unsigned long rxoverflow;
-// unsigned long rxint;
unsigned long txnpokint;
-// unsigned long txhpokint;
-// unsigned long txhperr;
-// unsigned long ints;
-// unsigned long shints;
unsigned long txoverflow;
-// unsigned long rxdmafail;
-// unsigned long txbeacon;
-// unsigned long txbeaconerr;
unsigned long txlpokint;
unsigned long txlpdrop;
unsigned long txlperr;
@@ -909,14 +830,11 @@ typedef struct Stats
u32 CurrentShowTxate;
} Stats;
-
// Bandwidth Offset
#define HAL_PRIME_CHNL_OFFSET_DONT_CARE 0
#define HAL_PRIME_CHNL_OFFSET_LOWER 1
#define HAL_PRIME_CHNL_OFFSET_UPPER 2
-//+by amy 080507
-
typedef struct ChnlAccessSetting {
u16 SIFS_Timer;
u16 DIFS_Timer;
@@ -956,14 +874,12 @@ typedef enum _RT_RF_TYPE_819xU{
RF_PSEUDO_11N = 5,
}RT_RF_TYPE_819xU, *PRT_RF_TYPE_819xU;
-//#ifdef RTL8192SU
typedef enum _RF_POWER_STATE{
RF_ON,
RF_SLEEP,
RF_OFF,
RF_SHUT_DOWN,
}RF_POWER_STATE, *PRF_POWER_STATE;
-//#endif
typedef struct _rate_adaptive
{
@@ -1014,7 +930,6 @@ typedef struct _init_gain
u8 cca;
} init_gain, *pinit_gain;
-//by amy 0606
typedef struct _phy_ofdm_rx_status_report_819xusb
{
@@ -1066,8 +981,26 @@ typedef enum _RT_CUSTOMER_ID
RT_CID_Nettronix = 11,
RT_CID_DLINK = 12,
RT_CID_PRONET = 13,
+ RT_CID_COREGA = 14,
+ RT_CID_819x_ALPHA = 15,
+ RT_CID_819x_Sitecom = 16,
+ RT_CID_CCX = 17,
+ RT_CID_819x_Lenovo = 18,
+ RT_CID_819x_QMI = 19,
+ RT_CID_819x_Edimax_Belkin = 20,
+ RT_CID_819x_Sercomm_Belkin = 21,
+ RT_CID_819x_CAMEO1 = 22,
+ RT_CID_819x_MSI = 23,
+ RT_CID_819x_Acer = 24,
}RT_CUSTOMER_ID, *PRT_CUSTOMER_ID;
+typedef enum _RT_OP_MODE{
+ RT_OP_MODE_AP,
+ RT_OP_MODE_INFRASTRUCTURE,
+ RT_OP_MODE_IBSS,
+ RT_OP_MODE_NO_LINK,
+}RT_OP_MODE, *PRT_OP_MODE;
+
typedef enum _RESET_TYPE {
RESET_TYPE_NORESET = 0x00,
RESET_TYPE_NORMAL = 0x01,
@@ -1093,8 +1026,6 @@ typedef enum{
NIC_8192SU = 5,
} nic_t;
-//definded by WB. Ready to fill handlers for different NIC types.
-//add handle here when necessary.
struct rtl819x_ops{
nic_t nic_type;
void (* rtl819x_read_eeprom_info)(struct net_device *dev);
@@ -1113,11 +1044,12 @@ typedef struct r8192_priv
struct rtl819x_ops* ops;
struct usb_device *udev;
/* added for maintain info from eeprom */
+ short epromtype;
u16 eeprom_vid;
u16 eeprom_pid;
u8 eeprom_CustomerID;
u8 eeprom_SubCustomerID;
- u8 eeprom_ChannelPlan;
+ u16 eeprom_ChannelPlan;
RT_CUSTOMER_ID CustomerID;
LED_STRATEGY_819xUsb LedStrategy;
u8 txqueue_to_outpipemap[9];
@@ -1129,76 +1061,55 @@ typedef struct r8192_priv
int irq;
struct ieee80211_device *ieee80211;
+ u8 RATRTableBitmap;
+
+ u32 IC_Cut;
short card_8192; /* O: rtl8192, 1:rtl8185 V B/C, 2:rtl8185 V D */
- u8 card_8192_version; /* if TCR reports card V B/C this discriminates */
-// short phy_ver; /* meaningful for rtl8225 1:A 2:B 3:C */
+ u32 card_8192_version; /* if TCR reports card V B/C this discriminates */
short enable_gpio0;
enum card_type {PCI,MINIPCI,CARDBUS,USB}card_type;
short hw_plcp_len;
short plcp_preamble_mode;
spinlock_t irq_lock;
-// spinlock_t irq_th_lock;
spinlock_t tx_lock;
spinlock_t ps_lock;
struct mutex mutex;
+ bool ps_force;
spinlock_t rf_lock; //used to lock rf write operation added by wb
+ spinlock_t rf_ps_lock;
u16 irq_mask;
-// short irq_enabled;
-// struct net_device *dev; //comment this out.
short chan;
short sens;
short max_sens;
-
- // u8 chtxpwr[15]; //channels from 1 to 14, 0 not used
-// u8 chtxpwr_ofdm[15]; //channels from 1 to 14, 0 not used
-// u8 cck_txpwr_base;
-// u8 ofdm_txpwr_base;
-// u8 challow[15]; //channels from 1 to 14, 0 not used
short up;
short crcmon; //if 1 allow bad crc frame reception in monitor mode
-// short prism_hdr;
-
-// struct timer_list scan_timer;
- /*short scanpending;
- short stopscan;*/
-// spinlock_t scan_lock;
-// u8 active_probe;
- //u8 active_scan_num;
+ bool bSurpriseRemoved;
+
struct semaphore wx_sem;
struct semaphore rf_sem; //used to lock rf write operation added by wb, modified by david
-// short hw_wep;
-// short digphy;
-// short antb;
-// short diversity;
-// u8 cs_treshold;
-// short rcr_csense;
u8 rf_type; //0 means 1T2R, 1 means 2T4R
RT_RF_TYPE_819xU rf_chip;
-// u32 key0[4];
short (*rf_set_sens)(struct net_device *dev,short sens);
u8 (*rf_set_chan)(struct net_device *dev,u8 ch);
void (*rf_close)(struct net_device *dev);
void (*rf_init)(struct net_device *dev);
- //short rate;
short promisc;
+ u32 mc_filter[2];
/*stats*/
struct Stats stats;
struct iw_statistics wstats;
struct proc_dir_entry *dir_dev;
/*RX stuff*/
-// u32 *rxring;
-// u32 *rxringtail;
-// dma_addr_t rxringdma;
struct urb **rx_urb;
struct urb **rx_cmd_urb;
-/* modified by davad for Rx process */
+/* for Rx process */
struct sk_buff_head rx_queue;
struct sk_buff_head skb_queue;
@@ -1209,6 +1120,7 @@ typedef struct r8192_priv
struct tasklet_struct irq_rx_tasklet;
+ struct tasklet_struct irq_tx_tasklet;
struct urb *rxurb_task;
//2 Tx Related variables
@@ -1235,6 +1147,7 @@ typedef struct r8192_priv
struct ChnlAccessSetting ChannelAccessSetting;
struct work_struct reset_wq;
+ struct work_struct mcast_wq;
/**********************************************************/
//for rtl819xUsb
@@ -1244,21 +1157,28 @@ typedef struct r8192_priv
bool bDcut;
bool bCurrentRxAggrEnable;
u8 Rf_Mode; //add for Firmware RF -R/W switch
+ u8 FwRsvdTxPageCfg;
prt_firmware pFirmware;
- rtl819xUsb_loopback_e LoopbackMode;
+ RTL8192SUSB_LOOPBACK_E LoopbackMode;
bool usb_error;
u16 EEPROMTxPowerDiff;
u8 EEPROMThermalMeter;
u8 EEPROMPwDiff;
u8 EEPROMCrystalCap;
+ u8 EEPROMBluetoothCoexist;
u8 EEPROM_Def_Ver;
u8 EEPROMTxPowerLevelCCK;// CCK channel 1~14
u8 EEPROMTxPowerLevelCCK_V1[3];
u8 EEPROMTxPowerLevelOFDM24G[3]; // OFDM 2.4G channel 1~14
u8 EEPROMTxPowerLevelOFDM5G[24]; // OFDM 5G
-//RTL8192SU
+ u8 EEPROMOptional;
+ u8 ShowRateMode;
+ bool bForcedShowRxRate;
+
+ u32 RfRegChnlVal[2];
+
bool bDmDisableProtect;
bool bIgnoreDiffRateTxPowerOffset;
@@ -1278,6 +1198,9 @@ typedef struct r8192_priv
bool EepromOrEfuse;
bool bBootFromEfuse; // system boot form EFUSE
u8 EfuseMap[2][HWSET_MAX_SIZE_92S];
+ u16 EfuseUsedBytes;
+ u8 EfuseUsedPercentage;
+
u8 EEPROMUsbOption;
u8 EEPROMUsbPhyParam[5];
@@ -1290,6 +1213,8 @@ typedef struct r8192_priv
u8 EEPROMTxPwrTkMode;
u8 bTXPowerDataReadFromEEPORM;
+ u8 EEPROMRegulatory;
+ u8 EEPROMPwrGroup[2][3];
u8 EEPROMVersion;
u8 EEPROMUsbEndPointNumber;
@@ -1298,7 +1223,7 @@ typedef struct r8192_priv
u8 RfTxPwrLevelCck[2][14];
u8 RfTxPwrLevelOfdm1T[2][14];
u8 RfTxPwrLevelOfdm2T[2][14];
- // 2009/01/20 MH Add for new EEPROM format.
+ // new EEPROM format.
u8 TxPwrHt20Diff[2][14]; // HT 20<->40 Pwr diff
u8 TxPwrLegacyHtDiff[2][14]; // For HT<->legacy pwr diff
u8 TxPwrbandEdgeHt40[2][2]; // Band edge for HY 40MHZlow/up channel
@@ -1310,7 +1235,6 @@ typedef struct r8192_priv
u8 MidHighPwrTHR_L1;
u8 MidHighPwrTHR_L2;
u8 TxPwrSafetyFlag; // for Tx power safety spec
-//RTL8192SU
/*PHY related*/
BB_REGISTER_DEFINITION_T PHYRegDef[4]; //Radio A/B/C/D
@@ -1323,8 +1247,11 @@ typedef struct r8192_priv
u32 Pwr_Track;
u8 TxPowerDiff;
u8 AntennaTxPwDiff[2]; // Antenna gain offset, index 0 for B, 1 for C, and 2 for D
+ u8 ThermalMeter[2]; // ThermalMeter, index 0 for RFIC0, and 1 for RFIC1
+ u8 ThermalValue;
u8 CrystalCap; // CrystalCap.
- u8 ThermalMeter[2]; // ThermalMeter, index 0 for RFIC0, and 1 for RFIC1
+ u8 BluetoothCoexist;
+ u8 ExternalPA;
u8 CckPwEnl;
// Use to calculate PWBD.
@@ -1337,24 +1264,22 @@ typedef struct r8192_priv
u8 SwChnlStep;
u8 SetBWModeInProgress;
HT_CHANNEL_WIDTH CurrentChannelBW;
+ bool bChnlPlanFromHW;
u8 ChannelPlan;
+ u16 RegChannelPlan;
u8 pwrGroupCnt;
// 8190 40MHz mode
//
u8 nCur40MhzPrimeSC; // Control channel sub-carrier
- // Joseph test for shorten RF configuration time.
- // We save RF reg0 in this variable to reduce RF reading.
- //
+
u32 RfReg0Value[4];
u8 NumTotalRFPath;
bool brfpath_rxenable[4];
//RF set related
bool SetRFPowerStateInProgress;
-//+by amy 080507
+
struct timer_list watch_dog_timer;
-//+by amy 080515 for dynamic mechenism
- //Add by amy Tx Power Control for Near/Far Range 2008/05/15
bool bdynamic_txpower; //bDynamicTxPower
bool bDynamicTxHighPower; // Tx high power state
bool bDynamicTxLowPower; // Tx low power state
@@ -1363,17 +1288,18 @@ typedef struct r8192_priv
bool bstore_last_dtpflag;
bool bstart_txctrl_bydtp; //Define to discriminate on High power State or on sitesuvey to change Tx gain index
- //Add by amy for Rate Adaptive
+
rate_adaptive rate_adaptive;
- //Add by amy for TX power tracking
- //2008/05/15 Mars OPEN/CLOSE TX POWER TRACKING
+ // TX power tracking
txbbgain_struct txbbgain_table[TxBBGainTableLength];
u8 EEPROMTxPowerTrackEnable;
u8 txpower_count;//For 6 sec do tracking again
bool btxpower_trackingInit;
u8 OFDM_index;
u8 CCK_index;
- //2007/09/10 Mars Add CCK TX Power Tracking
+ u8 Record_CCK_20Mindex;
+ u8 Record_CCK_40Mindex;
+ // CCK TX Power Tracking
ccktxbbgain_struct cck_txbbgain_table[CCKTxBBGainTableLength];
ccktxbbgain_struct cck_txbbgain_ch14_table[CCKTxBBGainTableLength];
u8 rfa_txpowertrackingindex;
@@ -1390,10 +1316,15 @@ typedef struct r8192_priv
bool bcck_in_ch14;
bool btxpowerdata_readfromEEPORM;
u16 TSSI_13dBm;
+ u8 CCKPresentAttentuation_20Mdefault;
+ u8 CCKPresentAttentuation_40Mdefault;
+ char CCKPresentAttentuation_difference;
+ char CCKPresentAttentuation;
+ bool bDMInitialGainEnable;
//For Backup Initial Gain
init_gain initgain_backup;
u8 DefaultInitialGain[4];
- // For EDCA Turbo mode, Added by amy 080515.
+ // For EDCA Turbo mode
bool bis_any_nonbepkts;
bool bcurrent_turbo_EDCA;
bool bis_cur_rdlstate;
@@ -1407,17 +1338,23 @@ typedef struct r8192_priv
u8 framesync;
u32 framesyncC34;
u8 framesyncMonitor;
- //Added by amy 080516 for RX related
+ // RX related
u16 nrxAMPDU_size;
u8 nrxAMPDU_aggr_num;
- //by amy for gpio
+ // gpio
bool bHwRadioOff;
- //by amy for reset_count
+ bool isRFOff;
+ bool bInPowerSaveMode;
+
+ bool RFChangeInProgress;
+ bool RegRfOff;
+ u8 bHwRfOffAction;
+
u32 reset_count;
bool bpbc_pressed;
- //by amy for debug
+ // debug
u32 txpower_checkcnt;
u32 txpower_tracking_callback_cnt;
u8 thermal_read_val[40];
@@ -1426,7 +1363,7 @@ typedef struct r8192_priv
u32 ccktxpower_adjustcnt_ch14;
u8 tx_fwinfo_force_subcarriermode;
u8 tx_fwinfo_force_subcarrierval;
- //by amy for silent reset
+ // silent reset
RESET_TYPE ResetProgress;
bool bForcedSilentReset;
bool bDisableNormalResetCheck;
@@ -1435,11 +1372,11 @@ typedef struct r8192_priv
int IrpPendingCount;
bool bResetInProgress;
bool force_reset;
+ bool force_lps;
u8 InitialGainOperateType;
u16 SifsTime;
- //define work item by amy 080526
struct delayed_work update_beacon_wq;
struct delayed_work watch_dog_wq;
struct delayed_work txpower_tracking_wq;
@@ -1448,8 +1385,7 @@ typedef struct r8192_priv
struct delayed_work initialgain_operate_wq;
struct workqueue_struct *priv_wq;
-//#ifdef RTL8192SU
- //lzm add for 8192S
+
u32 IntrMask;
// RF and BB access related synchronization flags.
bool bChangeBBInProgress; // BaseBand RW is still in progress.
@@ -1464,7 +1400,6 @@ typedef struct r8192_priv
u8 ThermalReadBackIndex; //debug only
u8 ThermalReadVal[40]; //debug only
- // For HCT test, 2005.07.15, by rcnjko.
// not realize true, just define it, set it 0 default, because some func use it
bool bInHctTest;
@@ -1481,7 +1416,6 @@ typedef struct r8192_priv
char RF_C_TxPwDiff; // Antenna gain offset, rf-c to rf-a
bool bRFSiOrPi;//0=si, 1=pi.
- //lzm add for 8192S
bool SetFwCmdInProgress; //is set FW CMD in Progress? 92S only
u8 CurrentFwCmdIO;
@@ -1495,25 +1429,17 @@ typedef struct r8192_priv
LED_819xUsb SwLed0;
LED_819xUsb SwLed1;
u8 bRegUseLed;
- struct work_struct BlinkWorkItem;
+ struct work_struct BlinkWorkItem;
/* added for led control */
u16 FwCmdIOMap;
u32 FwCmdIOParam;
- u8 DMFlag;
+ u8 DMFlag;
}r8192_priv;
-// for rtl8187
-// now mirging to rtl8187B
-/*
-typedef enum{
- LOW_PRIORITY = 0x02,
- NORM_PRIORITY
- } priority_t;
-*/
//for rtl8187B
typedef enum{
BULK_PRIORITY = 0x01,
@@ -1542,6 +1468,9 @@ struct ssid_thread {
};
#endif
+void LedControl8192SUsb(struct net_device *dev, LED_CTL_MODE LedAction);
+void InitSwLeds(struct net_device *dev);
+void DeInitSwLeds(struct net_device *dev);
short rtl8192SU_tx_cmd(struct net_device *dev, struct sk_buff *skb);
short rtl8192SU_tx(struct net_device *dev, struct sk_buff* skb);
bool FirmwareDownload92S(struct net_device *dev);
@@ -1567,7 +1496,6 @@ void rtl8192_rx_enable(struct net_device *);
void rtl8192_tx_enable(struct net_device *);
void rtl8192_disassociate(struct net_device *dev);
-//void fix_rx_fifo(struct net_device *dev);
void rtl8185_set_rf_pins_enable(struct net_device *dev,u32 a);
void rtl8192_set_anaparam(struct net_device *dev,u32 a);
@@ -1582,7 +1510,6 @@ void write_phy_cck(struct net_device *dev, u8 adr, u32 data);
void write_phy_ofdm(struct net_device *dev, u8 adr, u32 data);
void rtl8185_tx_antenna(struct net_device *dev, u8 ant);
void rtl8192_set_rxconf(struct net_device *dev);
-//short check_nic_enough_desc(struct net_device *dev, priority_t priority);
extern void rtl819xusb_beacon_tx(struct net_device *dev,u16 tx_rate);
void CamResetAllEntry(struct net_device* dev);
void EnableHWSecurityConfig8192(struct net_device *dev);
diff --git a/drivers/staging/rtl8192su/r8192U_core.c b/drivers/staging/rtl8192su/r8192U_core.c
index 1b6890611fb..6970c97713d 100644
--- a/drivers/staging/rtl8192su/r8192U_core.c
+++ b/drivers/staging/rtl8192su/r8192U_core.c
@@ -27,6 +27,7 @@
#include <linux/vmalloc.h>
#include <linux/slab.h>
#include <linux/eeprom_93cx6.h>
+#include <linux/notifier.h>
#undef LOOP_TEST
#undef DUMP_RX
@@ -162,6 +163,8 @@ MODULE_PARM_DESC(channels," Channel bitmask for specific locales. NYI");
static int __devinit rtl8192_usb_probe(struct usb_interface *intf,
const struct usb_device_id *id);
static void __devexit rtl8192_usb_disconnect(struct usb_interface *intf);
+static const struct net_device_ops rtl8192_netdev_ops;
+static struct notifier_block proc_netdev_notifier;
static struct usb_driver rtl8192_usb_driver = {
.name = RTL819xU_MODULE_NAME, /* Driver name */
@@ -252,53 +255,49 @@ static void rtl819x_set_channel_map(u8 channel_plan, struct r8192_priv* priv)
{
int i, max_chan=-1, min_chan=-1;
struct ieee80211_device* ieee = priv->ieee80211;
- switch (channel_plan)
- {
- case COUNTRY_CODE_FCC:
- case COUNTRY_CODE_IC:
- case COUNTRY_CODE_ETSI:
- case COUNTRY_CODE_SPAIN:
- case COUNTRY_CODE_FRANCE:
- case COUNTRY_CODE_MKK:
- case COUNTRY_CODE_MKK1:
- case COUNTRY_CODE_ISRAEL:
- case COUNTRY_CODE_TELEC:
- case COUNTRY_CODE_MIC:
- {
- Dot11d_Init(ieee);
- ieee->bGlobalDomain = false;
- //acturally 8225 & 8256 rf chip only support B,G,24N mode
- if ((priv->rf_chip == RF_8225) || (priv->rf_chip == RF_8256) || (priv->rf_chip == RF_6052))
- {
- min_chan = 1;
- max_chan = 14;
- }
- else
- {
- RT_TRACE(COMP_ERR, "unknown rf chip, can't set channel map in function:%s()\n", __FUNCTION__);
- }
- if (ChannelPlan[channel_plan].Len != 0){
- // Clear old channel map
- memset(GET_DOT11D_INFO(ieee)->channel_map, 0, sizeof(GET_DOT11D_INFO(ieee)->channel_map));
- // Set new channel map
- for (i=0;i<ChannelPlan[channel_plan].Len;i++)
- {
- if (ChannelPlan[channel_plan].Channel[i] < min_chan || ChannelPlan[channel_plan].Channel[i] > max_chan)
- break;
- GET_DOT11D_INFO(ieee)->channel_map[ChannelPlan[channel_plan].Channel[i]] = 1;
- }
- }
- break;
- }
- case COUNTRY_CODE_GLOBAL_DOMAIN:
- {
- GET_DOT11D_INFO(ieee)->bEnabled = 0;//this flag enabled to follow 11d country IE setting, otherwise, it shall follow global domain settings.
- Dot11d_Reset(ieee);
- ieee->bGlobalDomain = true;
- break;
+
+ ieee->bGlobalDomain = false;
+ switch (priv->rf_chip) {
+ case RF_8225:
+ case RF_8256:
+ case RF_6052:
+ min_chan = 1;
+ max_chan = 14;
+ break;
+ default:
+ pr_err("%s(): unknown rf chip, can't set channel map\n",
+ __func__);
+ break;
+ }
+ if (ChannelPlan[channel_plan].Len != 0) {
+ memset(GET_DOT11D_INFO(ieee)->channel_map, 0,
+ sizeof(GET_DOT11D_INFO(ieee)->channel_map));
+
+ for (i = 0; i < ChannelPlan[channel_plan].Len; i++) {
+ if (ChannelPlan[channel_plan].Channel[i] < min_chan || ChannelPlan[channel_plan].Channel[i] > max_chan)
+ break;
+ GET_DOT11D_INFO(ieee)->channel_map[ChannelPlan[channel_plan].Channel[i]] = 1;
}
- default:
- break;
+ }
+ switch (channel_plan) {
+ case COUNTRY_CODE_GLOBAL_DOMAIN:
+ ieee->bGlobalDomain = true;
+ for (i = 12; i <= 14; i++)
+ GET_DOT11D_INFO(ieee)->channel_map[i] = 2;
+ ieee->IbssStartChnl = 10;
+ ieee->ibss_maxjoin_chal = 11;
+ break;
+ case COUNTRY_CODE_WORLD_WIDE_13:
+ printk(KERN_INFO "world wide 13\n");
+ for (i = 12; i <= 13; i++)
+ GET_DOT11D_INFO(ieee)->channel_map[i] = 2;
+ ieee->IbssStartChnl = 10;
+ ieee->ibss_maxjoin_chal = 11;
+ break;
+ default:
+ ieee->IbssStartChnl = 1;
+ ieee->ibss_maxjoin_chal = 14;
+ break;
}
return;
}
@@ -991,15 +990,24 @@ static int proc_get_stats_rx(char *page, char **start,
return len;
}
-void rtl8192_proc_module_init(void)
+int rtl8192_proc_module_init(void)
{
+ int ret;
+
RT_TRACE(COMP_INIT, "Initializing proc filesystem");
rtl8192_proc=create_proc_entry(RTL819xU_MODULE_NAME, S_IFDIR, init_net.proc_net);
+ if (!rtl8192_proc)
+ return -ENOMEM;
+ ret = register_netdevice_notifier(&proc_netdev_notifier);
+ if (ret)
+ remove_proc_entry(RTL819xU_MODULE_NAME, init_net.proc_net);
+ return ret;
}
void rtl8192_proc_module_remove(void)
{
+ unregister_netdevice_notifier(&proc_netdev_notifier);
remove_proc_entry(RTL819xU_MODULE_NAME, init_net.proc_net);
}
@@ -1027,8 +1035,7 @@ void rtl8192_proc_remove_one(struct net_device *dev)
remove_proc_entry("registers-e", priv->dir_dev);
// remove_proc_entry("cck-registers",priv->dir_dev);
// remove_proc_entry("ofdm-registers",priv->dir_dev);
- //remove_proc_entry(dev->name, rtl8192_proc);
- remove_proc_entry("wlan0", rtl8192_proc);
+ remove_proc_entry(priv->dir_dev->name, rtl8192_proc);
priv->dir_dev = NULL;
}
}
@@ -1145,6 +1152,25 @@ void rtl8192_proc_init_one(struct net_device *dev)
dev->name);
}
}
+
+static int proc_netdev_event(struct notifier_block *this,
+ unsigned long event, void *ptr)
+{
+ struct net_device *net_dev = ptr;
+
+ if (net_dev->netdev_ops == &rtl8192_netdev_ops &&
+ event == NETDEV_CHANGENAME) {
+ rtl8192_proc_remove_one(net_dev);
+ rtl8192_proc_init_one(net_dev);
+ }
+
+ return NOTIFY_DONE;
+}
+
+static struct notifier_block proc_netdev_notifier = {
+ .notifier_call = proc_netdev_event,
+};
+
/****************************************************************************
-----------------------------MISC STUFF-------------------------
*****************************************************************************/
@@ -7355,6 +7381,8 @@ static int __devinit rtl8192_usb_probe(struct usb_interface *intf,
RT_TRACE(COMP_INIT, "Oops: i'm coming\n");
dev = alloc_ieee80211(sizeof(struct r8192_priv));
+ if (dev == NULL)
+ return -ENOMEM;
usb_set_intfdata(intf, dev);
SET_NETDEV_DEV(dev, &intf->dev);
@@ -7392,7 +7420,8 @@ static int __devinit rtl8192_usb_probe(struct usb_interface *intf,
netif_carrier_off(dev);
netif_stop_queue(dev);
- register_netdev(dev);
+ if (register_netdev(dev))
+ goto fail;
RT_TRACE(COMP_INIT, "dev name=======> %s\n",dev->name);
rtl8192_proc_init_one(dev);
@@ -7474,35 +7503,63 @@ static int __init rtl8192_usb_module_init(void)
ret = ieee80211_crypto_init();
if (ret) {
printk(KERN_ERR "ieee80211_crypto_init() failed %d\n", ret);
- return ret;
+ goto fail_crypto;
}
ret = ieee80211_crypto_tkip_init();
if (ret) {
printk(KERN_ERR "ieee80211_crypto_tkip_init() failed %d\n",
ret);
- return ret;
+ goto fail_crypto_tkip;
}
ret = ieee80211_crypto_ccmp_init();
if (ret) {
printk(KERN_ERR "ieee80211_crypto_ccmp_init() failed %d\n",
ret);
- return ret;
+ goto fail_crypto_ccmp;
}
ret = ieee80211_crypto_wep_init();
if (ret) {
printk(KERN_ERR "ieee80211_crypto_wep_init() failed %d\n", ret);
- return ret;
+ goto fail_crypto_wep;
}
printk(KERN_INFO "\nLinux kernel driver for RTL8192 based WLAN cards\n");
printk(KERN_INFO "Copyright (c) 2007-2008, Realsil Wlan\n");
RT_TRACE(COMP_INIT, "Initializing module");
RT_TRACE(COMP_INIT, "Wireless extensions version %d", WIRELESS_EXT);
- rtl8192_proc_module_init();
- return usb_register(&rtl8192_usb_driver);
+
+ ret = rtl8192_proc_module_init();
+ if (ret) {
+ pr_err("rtl8192_proc_module_init() failed %d\n", ret);
+ goto fail_proc;
+ }
+
+ ret = usb_register(&rtl8192_usb_driver);
+ if (ret) {
+ pr_err("usb_register() failed %d\n", ret);
+ goto fail_usb;
+ }
+
+ return 0;
+
+fail_usb:
+ rtl8192_proc_module_remove();
+fail_proc:
+ ieee80211_crypto_wep_exit();
+fail_crypto_wep:
+ ieee80211_crypto_ccmp_exit();
+fail_crypto_ccmp:
+ ieee80211_crypto_tkip_exit();
+fail_crypto_tkip:
+ ieee80211_crypto_deinit();
+fail_crypto:
+#ifdef CONFIG_IEEE80211_DEBUG
+ ieee80211_debug_exit();
+#endif
+ return ret;
}
diff --git a/drivers/staging/rtl8192su/r8192U_dm.c b/drivers/staging/rtl8192su/r8192U_dm.c
index fa5e24416dd..ce7e1ee4c3a 100644
--- a/drivers/staging/rtl8192su/r8192U_dm.c
+++ b/drivers/staging/rtl8192su/r8192U_dm.c
@@ -2673,7 +2673,6 @@ static void dm_check_edca_turbo(
{
struct r8192_priv *priv = ieee80211_priv(dev);
PRT_HIGH_THROUGHPUT pHTInfo = priv->ieee80211->pHTInfo;
- //PSTA_QOS pStaQos = pMgntInfo->pStaQos;
// Keep past Tx/Rx packet count for RT-to-RT EDCA turbo.
static unsigned long lastTxOkCnt = 0;
@@ -2681,10 +2680,8 @@ static void dm_check_edca_turbo(
unsigned long curTxOkCnt = 0;
unsigned long curRxOkCnt = 0;
- //
- // Do not be Turbo if it's under WiFi config and Qos Enabled, because the EDCA parameters
- // should follow the settings from QAP. By Bruce, 2007-12-07.
- //
+ u32 EDCA_BE_UL = edca_setting_UL[pHTInfo->IOTPeer];
+ u32 EDCA_BE_DL = edca_setting_DL[pHTInfo->IOTPeer];
#if 1
if(priv->ieee80211->state != IEEE80211_LINKED)
goto dm_CheckEdcaTurbo_EXIT;
@@ -2693,6 +2690,14 @@ static void dm_check_edca_turbo(
if(priv->ieee80211->pHTInfo->IOTAction & HT_IOT_ACT_DISABLE_EDCA_TURBO)
goto dm_CheckEdcaTurbo_EXIT;
+ if(priv->ieee80211->pHTInfo->IOTAction & HT_IOT_ACT_FORCED_ENABLE_BE_TXOP)
+ {
+ if(!(EDCA_BE_UL & 0xffff0000))
+ EDCA_BE_UL |= 0x005e0000;
+ if(!(EDCA_BE_DL & 0xffff0000))
+ EDCA_BE_DL |= 0x005e0000;
+ }
+
{
u8* peername[11] = {"unknown", "realtek", "realtek_92se", "broadcom", "ralink", "atheros", "cisco", "marvell", "92u_softap", "self_softap"};
static int wb_tmp = 0;
@@ -2714,7 +2719,7 @@ static void dm_check_edca_turbo(
{
if(priv->bis_cur_rdlstate || !priv->bcurrent_turbo_EDCA)
{
- write_nic_dword(dev, EDCAPARA_BE, edca_setting_UL[pHTInfo->IOTPeer]);
+ write_nic_dword(dev, EDCAPARA_BE, EDCA_BE_UL);
priv->bis_cur_rdlstate = false;
}
}
@@ -2722,7 +2727,7 @@ static void dm_check_edca_turbo(
{
if(!priv->bis_cur_rdlstate || !priv->bcurrent_turbo_EDCA)
{
- write_nic_dword(dev, EDCAPARA_BE, edca_setting_DL[pHTInfo->IOTPeer]);
+ write_nic_dword(dev, EDCAPARA_BE, EDCA_BE_DL);
priv->bis_cur_rdlstate = true;
}
}
@@ -2734,7 +2739,7 @@ static void dm_check_edca_turbo(
{
if(!priv->bis_cur_rdlstate || !priv->bcurrent_turbo_EDCA)
{
- write_nic_dword(dev, EDCAPARA_BE, edca_setting_DL[pHTInfo->IOTPeer]);
+ write_nic_dword(dev, EDCAPARA_BE, EDCA_BE_DL);
priv->bis_cur_rdlstate = true;
}
}
@@ -2742,7 +2747,7 @@ static void dm_check_edca_turbo(
{
if(priv->bis_cur_rdlstate || !priv->bcurrent_turbo_EDCA)
{
- write_nic_dword(dev, EDCAPARA_BE, edca_setting_UL[pHTInfo->IOTPeer]);
+ write_nic_dword(dev, EDCAPARA_BE, EDCA_BE_UL);
priv->bis_cur_rdlstate = false;
}
}
@@ -2771,7 +2776,7 @@ static void dm_check_edca_turbo(
(((u32)(qos_parameters->cw_max[0]))<< AC_PARAM_ECW_MAX_OFFSET)|
(((u32)(qos_parameters->cw_min[0]))<< AC_PARAM_ECW_MIN_OFFSET)|
((u32)u1bAIFS << AC_PARAM_AIFS_OFFSET));
- //write_nic_dword(dev, WDCAPARA_ADD[i], u4bAcParam);
+
write_nic_dword(dev, EDCAPARA_BE, u4bAcParam);
// Check ACM bit.
@@ -2780,7 +2785,7 @@ static void dm_check_edca_turbo(
// TODO: Modified this part and try to set acm control in only 1 IO processing!!
PACI_AIFSN pAciAifsn = (PACI_AIFSN)&(qos_parameters->aifs[0]);
- u8 AcmCtrl = read_nic_byte( dev, AcmHwCtrl );
+ u8 AcmCtrl = priv->AcmControl | 0x1;
if( pAciAifsn->f.ACM )
{ // ACM bit is 1.
AcmCtrl |= AcmHw_BeqEn;
@@ -2804,7 +2809,7 @@ dm_CheckEdcaTurbo_EXIT:
priv->ieee80211->bis_any_nonbepkts = false;
lastTxOkCnt = priv->stats.txbytesunicast;
lastRxOkCnt = priv->stats.rxbytesunicast;
-} // dm_CheckEdcaTurbo
+}
#endif
extern void DM_CTSToSelfSetting(struct net_device * dev,u32 DM_Type, u32 DM_Value)
diff --git a/drivers/staging/rtl8192su/r8192U_wx.c b/drivers/staging/rtl8192su/r8192U_wx.c
index a7cc6f9a473..2005b811eba 100644
--- a/drivers/staging/rtl8192su/r8192U_wx.c
+++ b/drivers/staging/rtl8192su/r8192U_wx.c
@@ -1,21 +1,23 @@
-/*
- This file contains wireless extension handlers.
+/******************************************************************************
+ * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved.
+ * Linux device driver for RTL8192U
+ *
+ * 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, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+******************************************************************************/
- This is part of rtl8180 OpenSource driver.
- Copyright (C) Andrea Merello 2004-2005 <andreamrl@tiscali.it>
- Released under the terms of GPL (General Public Licence)
-
- Parts of this driver are based on the GPL part
- of the official realtek driver.
-
- Parts of this driver are based on the rtl8180 driver skeleton
- from Patric Schenke & Andres Salomon.
-
- Parts of this driver are based on the Intel Pro Wireless 2100 GPL driver.
-
- We want to tanks the Authors of those projects and the Ndiswrapper
- project Authors.
-*/
#include <linux/string.h>
#include "r8192U.h"
@@ -248,6 +250,7 @@ static int r8192_wx_get_ap_status(struct net_device *dev,
struct r8192_priv *priv = ieee80211_priv(dev);
struct ieee80211_device *ieee = priv->ieee80211;
struct ieee80211_network *target;
+ struct ieee80211_network *latest = NULL;
int name_len;
down(&priv->wx_sem);
@@ -259,13 +262,20 @@ static int r8192_wx_get_ap_status(struct net_device *dev,
list_for_each_entry(target, &ieee->network_list, list) {
if ( (target->ssid_len == name_len) &&
(strncmp(target->ssid, (char*)wrqu->data.pointer, name_len)==0)){
- if(target->wpa_ie_len>0 || target->rsn_ie_len>0 )
- //set flags=1 to indicate this ap is WPA
- wrqu->data.flags = 1;
- else wrqu->data.flags = 0;
+ if ((latest == NULL) ||(target->last_scanned > latest->last_scanned))
+ latest = target;
+
+ }
+ }
+ if(latest != NULL)
+ {
+ wrqu->data.length = latest->SignalStrength;
- break;
+ if(latest->wpa_ie_len>0 || latest->rsn_ie_len>0 ) {
+ wrqu->data.flags = 1;
+ } else {
+ wrqu->data.flags = 0;
}
}
@@ -460,14 +470,6 @@ static int rtl8180_wx_get_range(struct net_device *dev,
range->we_version_compiled = WIRELESS_EXT;
range->we_version_source = 16;
-// range->retry_capa; /* What retry options are supported */
-// range->retry_flags; /* How to decode max/min retry limit */
-// range->r_time_flags; /* How to decode max/min retry life */
-// range->min_retry; /* Minimal number of retries */
-// range->max_retry; /* Maximal number of retries */
-// range->min_r_time; /* Minimal retry lifetime */
-// range->max_r_time; /* Maximal retry lifetime */
-
for (i = 0, val = 0; i < 14; i++) {
@@ -1011,6 +1013,70 @@ static int r8192_wx_set_mlme(struct net_device *dev,
return ret;
}
+static int r8192_wx_set_pmkid(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ int i;
+ struct r8192_priv *priv = ieee80211_priv(dev);
+ struct ieee80211_device* ieee = priv->ieee80211;
+ struct iw_pmksa* pPMK = (struct iw_pmksa*)extra;
+ int intReturn = false;
+
+ switch (pPMK->cmd)
+ {
+ case IW_PMKSA_ADD:
+ for (i = 0; i < NUM_PMKID_CACHE; i++)
+ {
+ if (memcmp(ieee->PMKIDList[i].Bssid, pPMK->bssid.sa_data, ETH_ALEN) == 0)
+ {
+ memcpy(ieee->PMKIDList[i].PMKID, pPMK->pmkid, IW_PMKID_LEN);
+ memcpy(ieee->PMKIDList[i].Bssid, pPMK->bssid.sa_data, ETH_ALEN);
+ ieee->PMKIDList[i].bUsed = true;
+ intReturn = true;
+ goto __EXIT__;
+ }
+ }
+
+ for (i = 0; i < NUM_PMKID_CACHE; i++)
+ {
+ if (ieee->PMKIDList[i].bUsed == false)
+ {
+ memcpy(ieee->PMKIDList[i].PMKID, pPMK->pmkid, IW_PMKID_LEN);
+ memcpy(ieee->PMKIDList[i].Bssid, pPMK->bssid.sa_data, ETH_ALEN);
+ ieee->PMKIDList[i].bUsed = true;
+ intReturn = true;
+ goto __EXIT__;
+ }
+ }
+ break;
+
+ case IW_PMKSA_REMOVE:
+ for (i = 0; i < NUM_PMKID_CACHE; i++)
+ {
+ if (memcmp(ieee->PMKIDList[i].Bssid, pPMK->bssid.sa_data, ETH_ALEN) == true)
+ {
+ memset(&ieee->PMKIDList[i], 0x00, sizeof(RT_PMKID_LIST));
+ intReturn = true;
+ break;
+ }
+ }
+ break;
+
+ case IW_PMKSA_FLUSH:
+ memset(&ieee->PMKIDList[0], 0x00, (sizeof(RT_PMKID_LIST) * NUM_PMKID_CACHE));
+ intReturn = true;
+ break;
+
+ default:
+ break;
+ }
+
+__EXIT__:
+ return (intReturn);
+
+}
+
static int r8192_wx_set_gen_ie(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *data, char *extra)
@@ -1093,7 +1159,7 @@ static iw_handler r8192_wx_handlers[] =
NULL,//r8192_wx_get_auth,//NULL, /* SIOCSIWAUTH */
r8192_wx_set_enc_ext, /* SIOCSIWENCODEEXT */
NULL,//r8192_wx_get_enc_ext,//NULL, /* SIOCSIWENCODEEXT */
- NULL, /* SIOCSIWPMKSA */
+ r8192_wx_set_pmkid, /* SIOCSIWPMKSA */
NULL, /*---hole---*/
};
diff --git a/drivers/staging/rtl8192su/r819xU_cmdpkt.c b/drivers/staging/rtl8192su/r819xU_cmdpkt.c
index a8e9d2d96f5..7ab9e22f895 100644
--- a/drivers/staging/rtl8192su/r819xU_cmdpkt.c
+++ b/drivers/staging/rtl8192su/r819xU_cmdpkt.c
@@ -1,13 +1,22 @@
-/*
- * (c) Copyright 2008, RealTEK Technologies Inc. All Rights Reserved.
+/******************************************************************************
+ * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved.
+ * Linux device driver for RTL8192U
*
- * Module: r819xusb_cmdpkt.c
- * (RTL8190 TX/RX command packet handler Source C File)
+ * 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.
*
- * Note: The module is responsible for handling TX and RX command packet.
- * 1.TX: Send set and query configuration command packet.
- * 2.RX: Receive tx feedback, beacon state, query configuration, command packet.
- */
+ * 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, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+******************************************************************************/
#include "r8192U.h"
#include "r819xU_cmdpkt.h"
@@ -19,19 +28,13 @@ bool SendTxCommandPacket(struct net_device *dev, void *pData, u32 DataLen)
cb_desc *tcb_desc;
unsigned char *ptr_buf;
- /* PlatformAcquireSpinLock(Adapter, RT_TX_SPINLOCK); */
-
/*
* Get TCB and local buffer from common pool.
* (It is shared by CmdQ, MgntQ, and USB coalesce DataQ)
*/
skb = dev_alloc_skb(USB_HWDESC_HEADER_LEN + DataLen + 4);
- if (skb == NULL) {
- RT_TRACE(COMP_ERR, "(%s): unable to alloc skb buffer\n",
- __func__);
- rtStatus = false;
- return rtStatus;
- }
+ if (!skb)
+ return false;
memcpy((unsigned char *)(skb->cb), &dev, sizeof(dev));
tcb_desc = (cb_desc *)(skb->cb + MAX_DEV_ADDR_SIZE);
tcb_desc->queue_index = TXCMD_QUEUE;
@@ -51,7 +54,6 @@ bool SendTxCommandPacket(struct net_device *dev, void *pData, u32 DataLen)
priv->ieee80211->softmac_hard_start_xmit(skb, dev);
}
- //PlatformReleaseSpinLock(Adapter, RT_TX_SPINLOCK);
return rtStatus;
}
@@ -224,7 +226,6 @@ static void cmpk_handle_interrupt_status(struct net_device *dev, u8 *pmsg)
if (priv->ieee80211->iw_mode == IW_MODE_ADHOC) {
//2 maybe need endian transform?
rx_intr_status.interrupt_status = *((u32 *)(pmsg + 4));
- //rx_intr_status.InterruptStatus = N2H4BYTE(*((UINT32 *)(pMsg + 4)));
DMESG("interrupt status = 0x%x\n", rx_intr_status.interrupt_status);
@@ -491,6 +492,13 @@ cmpk_message_handle_rx(
cmpk_handle_tx_rate_history(dev, pcmd_buff);
cmd_length = CMPK_TX_RAHIS_SIZE;
break;
+ case RX_TX_TSSI_MEAN_BACK:
+ {
+ u32 *pMsg;
+ pMsg = (u32 *)pcmd_buff;
+ }
+ cmd_length = 32;
+ break;
default:
RT_TRACE(COMP_ERR, "(%s): unknown CMD Element\n",
__func__);
diff --git a/drivers/staging/rtl8192su/r819xU_cmdpkt.h b/drivers/staging/rtl8192su/r819xU_cmdpkt.h
index d3c56155188..95885bee7a4 100644
--- a/drivers/staging/rtl8192su/r819xU_cmdpkt.h
+++ b/drivers/staging/rtl8192su/r819xU_cmdpkt.h
@@ -173,6 +173,7 @@ typedef enum tag_command_packet_directories {
RX_DBGINFO_FEEDBACK = 5,
RX_TX_PER_PKT_FEEDBACK = 6,
RX_TX_RATE_HISTORY = 7,
+ RX_TX_TSSI_MEAN_BACK = 8,
RX_CMD_ELE_MAX
} cmpk_element_e;
diff --git a/drivers/staging/rtl8192u/Kconfig b/drivers/staging/rtl8192u/Kconfig
index 0439c90b416..28969198e7e 100644
--- a/drivers/staging/rtl8192u/Kconfig
+++ b/drivers/staging/rtl8192u/Kconfig
@@ -3,5 +3,6 @@ config RTL8192U
depends on PCI && WLAN && USB
select WIRELESS_EXT
select WEXT_PRIV
+ select CRYPTO
default N
---help---
diff --git a/drivers/staging/rtl8192u/dot11d.h b/drivers/staging/rtl8192u/dot11d.h
index 0851b9db17a..d99cc030ec7 100644
--- a/drivers/staging/rtl8192u/dot11d.h
+++ b/drivers/staging/rtl8192u/dot11d.h
@@ -2,7 +2,7 @@
#define __INC_DOT11D_H
#ifdef ENABLE_DOT11D
-#include "ieee80211.h"
+#include "ieee80211/ieee80211.h"
typedef struct _CHNL_TXPOWER_TRIPLE {
diff --git a/drivers/staging/rtl8192u/ieee80211.h b/drivers/staging/rtl8192u/ieee80211.h
deleted file mode 100644
index 9c726113214..00000000000
--- a/drivers/staging/rtl8192u/ieee80211.h
+++ /dev/null
@@ -1,2595 +0,0 @@
-/*
- * Merged with mainline ieee80211.h in Aug 2004. Original ieee802_11
- * remains copyright by the original authors
- *
- * Portions of the merged code are based on Host AP (software wireless
- * LAN access point) driver for Intersil Prism2/2.5/3.
- *
- * Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen
- * <jkmaline@cc.hut.fi>
- * Copyright (c) 2002-2003, Jouni Malinen <jkmaline@cc.hut.fi>
- *
- * Adaption to a generic IEEE 802.11 stack by James Ketrenos
- * <jketreno@linux.intel.com>
- * Copyright (c) 2004, Intel Corporation
- *
- * Modified for Realtek's wi-fi cards by Andrea Merello
- * <andreamrl@tiscali.it>
- *
- * 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 README and COPYING for
- * more details.
- */
-#ifndef IEEE80211_H
-#define IEEE80211_H
-#include <linux/if_ether.h> /* ETH_ALEN */
-#include <linux/kernel.h> /* ARRAY_SIZE */
-#include <linux/version.h>
-#include <linux/module.h>
-#include <linux/jiffies.h>
-#include <linux/timer.h>
-#include <linux/sched.h>
-
-#include <linux/delay.h>
-#include <linux/wireless.h>
-
-#include "ieee80211/rtl819x_HT.h"
-#include "ieee80211/rtl819x_BA.h"
-#include "ieee80211/rtl819x_TS.h"
-
-
-#ifndef IW_MODE_MONITOR
-#define IW_MODE_MONITOR 6
-#endif
-
-#ifndef IWEVCUSTOM
-#define IWEVCUSTOM 0x8c02
-#endif
-
-
-#ifndef container_of
-/**
- * container_of - cast a member of a structure out to the containing structure
- *
- * @ptr: the pointer to the member.
- * @type: the type of the container struct this is embedded in.
- * @member: the name of the member within the struct.
- *
- */
-#define container_of(ptr, type, member) ({ \
- const typeof(((type *)0)->member) (*__mptr = (ptr)); \
- (type *)((char *)__mptr - offsetof(type, member)); })
-#endif
-
-#define KEY_TYPE_NA 0x0
-#define KEY_TYPE_WEP40 0x1
-#define KEY_TYPE_TKIP 0x2
-#define KEY_TYPE_CCMP 0x4
-#define KEY_TYPE_WEP104 0x5
-
-/* added for rtl819x tx procedure */
-#define MAX_QUEUE_SIZE 0x10
-
-/*
- * 8190 queue mapping
- */
-#define BK_QUEUE 0
-#define BE_QUEUE 1
-#define VI_QUEUE 2
-#define VO_QUEUE 3
-#define HCCA_QUEUE 4
-#define TXCMD_QUEUE 5
-#define MGNT_QUEUE 6
-#define HIGH_QUEUE 7
-#define BEACON_QUEUE 8
-
-#define LOW_QUEUE BE_QUEUE
-#define NORMAL_QUEUE MGNT_QUEUE
-
-/* added by amy for ps */
-#define SWRF_TIMEOUT 50
-
-/* added by amy for LEAP related */
-#define IE_CISCO_FLAG_POSITION 0x08 /* Flag byte: byte 8, numbered from 0. */
-#define SUPPORT_CKIP_MIC 0x08 /* bit3 */
-#define SUPPORT_CKIP_PK 0x10 /* bit4 */
-/* defined for skb cb field */
-/* At most 28 byte */
-typedef struct cb_desc {
- /* Tx Desc Related flags (8-9) */
- u8 bLastIniPkt:1;
- u8 bCmdOrInit:1;
- u8 bFirstSeg:1;
- u8 bLastSeg:1;
- u8 bEncrypt:1;
- u8 bTxDisableRateFallBack:1;
- u8 bTxUseDriverAssingedRate:1;
- u8 bHwSec:1; /* indicate whether use Hw security. WB */
-
- u8 reserved1;
-
- /* Tx Firmware Relaged flags (10-11)*/
- u8 bCTSEnable:1;
- u8 bRTSEnable:1;
- u8 bUseShortGI:1;
- u8 bUseShortPreamble:1;
- u8 bTxEnableFwCalcDur:1;
- u8 bAMPDUEnable:1;
- u8 bRTSSTBC:1;
- u8 RTSSC:1;
-
- u8 bRTSBW:1;
- u8 bPacketBW:1;
- u8 bRTSUseShortPreamble:1;
- u8 bRTSUseShortGI:1;
- u8 bMulticast:1;
- u8 bBroadcast:1;
- u8 drv_agg_enable:1;
- u8 reserved2:1;
-
- /* Tx Desc related element(12-19) */
- u8 rata_index;
- u8 queue_index;
- u16 txbuf_size;
- u8 RATRIndex;
- u8 reserved6;
- u8 reserved7;
- u8 reserved8;
-
- /* Tx firmware related element(20-27) */
- u8 data_rate;
- u8 rts_rate;
- u8 ampdu_factor;
- u8 ampdu_density;
- u8 DrvAggrNum;
- u16 pkt_size;
- u8 reserved12;
-} cb_desc, *pcb_desc;
-
-/*--------------------------Define -------------------------------------------*/
-#define MGN_1M 0x02
-#define MGN_2M 0x04
-#define MGN_5_5M 0x0b
-#define MGN_11M 0x16
-
-#define MGN_6M 0x0c
-#define MGN_9M 0x12
-#define MGN_12M 0x18
-#define MGN_18M 0x24
-#define MGN_24M 0x30
-#define MGN_36M 0x48
-#define MGN_48M 0x60
-#define MGN_54M 0x6c
-
-#define MGN_MCS0 0x80
-#define MGN_MCS1 0x81
-#define MGN_MCS2 0x82
-#define MGN_MCS3 0x83
-#define MGN_MCS4 0x84
-#define MGN_MCS5 0x85
-#define MGN_MCS6 0x86
-#define MGN_MCS7 0x87
-#define MGN_MCS8 0x88
-#define MGN_MCS9 0x89
-#define MGN_MCS10 0x8a
-#define MGN_MCS11 0x8b
-#define MGN_MCS12 0x8c
-#define MGN_MCS13 0x8d
-#define MGN_MCS14 0x8e
-#define MGN_MCS15 0x8f
-
-/*
- * 802.11 Management frame Reason Code field
- */
-enum _ReasonCode{
- unspec_reason = 0x1,
- auth_not_valid = 0x2,
- deauth_lv_ss = 0x3,
- inactivity = 0x4,
- ap_overload = 0x5,
- class2_err = 0x6,
- class3_err = 0x7,
- disas_lv_ss = 0x8,
- asoc_not_auth = 0x9,
-
- /* ----MIC_CHECK */
- mic_failure = 0xe,
- /* ----END MIC_CHECK */
-
- /* Reason code defined in 802.11i D10.0 p.28. */
- invalid_IE = 0x0d,
- four_way_tmout = 0x0f,
- two_way_tmout = 0x10,
- IE_dismatch = 0x11,
- invalid_Gcipher = 0x12,
- invalid_Pcipher = 0x13,
- invalid_AKMP = 0x14,
- unsup_RSNIEver = 0x15,
- invalid_RSNIE = 0x16,
- auth_802_1x_fail = 0x17,
- ciper_reject = 0x18,
-
- /* Reason code defined in 7.3.1.7, 802.1e D13.0, p.42. */
- QoS_unspec = 0x20, /* 32 */
- QAP_bandwidth = 0x21, /* 33 */
- poor_condition = 0x22, /* 34 */
- no_facility = 0x23, /* 35 */
- /* Where is 36??? */
- req_declined = 0x25, /* 37 */
- invalid_param = 0x26, /* 38 */
- req_not_honored = 0x27, /* 39 */
- TS_not_created = 0x2F, /* 47 */
- DL_not_allowed = 0x30, /* 48 */
- dest_not_exist = 0x31, /* 49 */
- dest_not_QSTA = 0x32, /* 50 */
-};
-
-
-
-#define aSifsTime ((priv->ieee80211->current_network.mode == IEEE_A) || \
- (priv->ieee80211->current_network.mode == IEEE_N_24G) || \
- (priv->ieee80211->current_network.mode == IEEE_N_5G)) ? 16 : 10
-
-#define MGMT_QUEUE_NUM 5
-
-#define IEEE_CMD_SET_WPA_PARAM 1
-#define IEEE_CMD_SET_WPA_IE 2
-#define IEEE_CMD_SET_ENCRYPTION 3
-#define IEEE_CMD_MLME 4
-
-#define IEEE_PARAM_WPA_ENABLED 1
-#define IEEE_PARAM_TKIP_COUNTERMEASURES 2
-#define IEEE_PARAM_DROP_UNENCRYPTED 3
-#define IEEE_PARAM_PRIVACY_INVOKED 4
-#define IEEE_PARAM_AUTH_ALGS 5
-#define IEEE_PARAM_IEEE_802_1X 6
-/* It should consistent with the driver_XXX.c */
-#define IEEE_PARAM_WPAX_SELECT 7
-/* Added for notify the encryption type selection */
-#define IEEE_PROTO_WPA 1
-#define IEEE_PROTO_RSN 2
-/* Added for notify the encryption type selection */
-#define IEEE_WPAX_USEGROUP 0
-#define IEEE_WPAX_WEP40 1
-#define IEEE_WPAX_TKIP 2
-#define IEEE_WPAX_WRAP 3
-#define IEEE_WPAX_CCMP 4
-#define IEEE_WPAX_WEP104 5
-
-#define IEEE_KEY_MGMT_IEEE8021X 1
-#define IEEE_KEY_MGMT_PSK 2
-
-#define IEEE_MLME_STA_DEAUTH 1
-#define IEEE_MLME_STA_DISASSOC 2
-
-
-#define IEEE_CRYPT_ERR_UNKNOWN_ALG 2
-#define IEEE_CRYPT_ERR_UNKNOWN_ADDR 3
-#define IEEE_CRYPT_ERR_CRYPT_INIT_FAILED 4
-#define IEEE_CRYPT_ERR_KEY_SET_FAILED 5
-#define IEEE_CRYPT_ERR_TX_KEY_SET_FAILED 6
-#define IEEE_CRYPT_ERR_CARD_CONF_FAILED 7
-
-
-#define IEEE_CRYPT_ALG_NAME_LEN 16
-
-#define MAX_IE_LEN 0xff
-
-/* added for kernel conflict */
-#define ieee80211_crypt_deinit_entries ieee80211_crypt_deinit_entries_rsl
-#define ieee80211_crypt_deinit_handler ieee80211_crypt_deinit_handler_rsl
-#define ieee80211_crypt_delayed_deinit ieee80211_crypt_delayed_deinit_rsl
-#define ieee80211_register_crypto_ops ieee80211_register_crypto_ops_rsl
-#define ieee80211_unregister_crypto_ops ieee80211_unregister_crypto_ops_rsl
-#define ieee80211_get_crypto_ops ieee80211_get_crypto_ops_rsl
-
-#define ieee80211_ccmp_null ieee80211_ccmp_null_rsl
-
-#define ieee80211_tkip_null ieee80211_tkip_null_rsl
-
-#define ieee80211_wep_null ieee80211_wep_null_rsl
-
-#define free_ieee80211 free_ieee80211_rsl
-#define alloc_ieee80211 alloc_ieee80211_rsl
-
-#define ieee80211_rx ieee80211_rx_rsl
-#define ieee80211_rx_mgt ieee80211_rx_mgt_rsl
-
-#define ieee80211_get_beacon ieee80211_get_beacon_rsl
-#define ieee80211_wake_queue ieee80211_wake_queue_rsl
-#define ieee80211_stop_queue ieee80211_stop_queue_rsl
-#define ieee80211_reset_queue ieee80211_reset_queue_rsl
-#define ieee80211_softmac_stop_protocol ieee80211_softmac_stop_protocol_rsl
-#define ieee80211_softmac_start_protocol ieee80211_softmac_start_protocol_rsl
-#define ieee80211_is_shortslot ieee80211_is_shortslot_rsl
-#define ieee80211_is_54g ieee80211_is_54g_rsl
-#define ieee80211_wpa_supplicant_ioctl ieee80211_wpa_supplicant_ioctl_rsl
-#define ieee80211_ps_tx_ack ieee80211_ps_tx_ack_rsl
-#define ieee80211_softmac_xmit ieee80211_softmac_xmit_rsl
-#define ieee80211_stop_send_beacons ieee80211_stop_send_beacons_rsl
-#define notify_wx_assoc_event notify_wx_assoc_event_rsl
-#define SendDisassociation SendDisassociation_rsl
-#define ieee80211_disassociate ieee80211_disassociate_rsl
-#define ieee80211_start_send_beacons ieee80211_start_send_beacons_rsl
-#define ieee80211_stop_scan ieee80211_stop_scan_rsl
-#define ieee80211_send_probe_requests ieee80211_send_probe_requests_rsl
-#define ieee80211_softmac_scan_syncro ieee80211_softmac_scan_syncro_rsl
-#define ieee80211_start_scan_syncro ieee80211_start_scan_syncro_rsl
-
-#define ieee80211_wx_get_essid ieee80211_wx_get_essid_rsl
-#define ieee80211_wx_set_essid ieee80211_wx_set_essid_rsl
-#define ieee80211_wx_set_rate ieee80211_wx_set_rate_rsl
-#define ieee80211_wx_get_rate ieee80211_wx_get_rate_rsl
-#define ieee80211_wx_set_wap ieee80211_wx_set_wap_rsl
-#define ieee80211_wx_get_wap ieee80211_wx_get_wap_rsl
-#define ieee80211_wx_set_mode ieee80211_wx_set_mode_rsl
-#define ieee80211_wx_get_mode ieee80211_wx_get_mode_rsl
-#define ieee80211_wx_set_scan ieee80211_wx_set_scan_rsl
-#define ieee80211_wx_get_freq ieee80211_wx_get_freq_rsl
-#define ieee80211_wx_set_freq ieee80211_wx_set_freq_rsl
-#define ieee80211_wx_set_rawtx ieee80211_wx_set_rawtx_rsl
-#define ieee80211_wx_get_name ieee80211_wx_get_name_rsl
-#define ieee80211_wx_set_power ieee80211_wx_set_power_rsl
-#define ieee80211_wx_get_power ieee80211_wx_get_power_rsl
-#define ieee80211_wlan_frequencies ieee80211_wlan_frequencies_rsl
-#define ieee80211_wx_set_rts ieee80211_wx_set_rts_rsl
-#define ieee80211_wx_get_rts ieee80211_wx_get_rts_rsl
-
-#define ieee80211_txb_free ieee80211_txb_free_rsl
-
-#define ieee80211_wx_set_gen_ie ieee80211_wx_set_gen_ie_rsl
-#define ieee80211_wx_get_scan ieee80211_wx_get_scan_rsl
-#define ieee80211_wx_set_encode ieee80211_wx_set_encode_rsl
-#define ieee80211_wx_get_encode ieee80211_wx_get_encode_rsl
-#if WIRELESS_EXT >= 18
-#define ieee80211_wx_set_mlme ieee80211_wx_set_mlme_rsl
-#define ieee80211_wx_set_auth ieee80211_wx_set_auth_rsl
-#define ieee80211_wx_set_encode_ext ieee80211_wx_set_encode_ext_rsl
-#define ieee80211_wx_get_encode_ext ieee80211_wx_get_encode_ext_rsl
-#endif
-
-
-typedef struct ieee_param {
- u32 cmd;
- u8 sta_addr[ETH_ALEN];
- union {
- struct {
- u8 name;
- u32 value;
- } wpa_param;
- struct {
- u32 len;
- u8 reserved[32];
- u8 data[0];
- } wpa_ie;
- struct{
- int command;
- int reason_code;
- } mlme;
- struct {
- u8 alg[IEEE_CRYPT_ALG_NAME_LEN];
- u8 set_tx;
- u32 err;
- u8 idx;
- u8 seq[8]; /* sequence counter (set: RX, get: TX) */
- u16 key_len;
- u8 key[0];
- } crypt;
- } u;
-} ieee_param;
-
-
-#if WIRELESS_EXT < 17
-#define IW_QUAL_QUAL_INVALID 0x10
-#define IW_QUAL_LEVEL_INVALID 0x20
-#define IW_QUAL_NOISE_INVALID 0x40
-#define IW_QUAL_QUAL_UPDATED 0x1
-#define IW_QUAL_LEVEL_UPDATED 0x2
-#define IW_QUAL_NOISE_UPDATED 0x4
-#endif
-
-
-/* linux under 2.6.9 release may not support it, so modify it for common use */
-#define MSECS(t) msecs_to_jiffies(t)
-#define msleep_interruptible_rsl msleep_interruptible
-
-#define IEEE80211_DATA_LEN 2304
-/* Maximum size for the MA-UNITDATA primitive, 802.11 standard section
- 6.2.1.1.2.
-
- The figure in section 7.1.2 suggests a body size of up to 2312
- bytes is allowed, which is a bit confusing, I suspect this
- represents the 2304 bytes of real data, plus a possible 8 bytes of
- WEP IV and ICV. (this interpretation suggested by Ramiro Barreiro) */
-#define IEEE80211_1ADDR_LEN 10
-#define IEEE80211_2ADDR_LEN 16
-#define IEEE80211_3ADDR_LEN 24
-#define IEEE80211_4ADDR_LEN 30
-#define IEEE80211_FCS_LEN 4
-#define IEEE80211_HLEN (IEEE80211_4ADDR_LEN)
-#define IEEE80211_FRAME_LEN (IEEE80211_DATA_LEN + IEEE80211_HLEN)
-#define IEEE80211_MGMT_HDR_LEN 24
-#define IEEE80211_DATA_HDR3_LEN 24
-#define IEEE80211_DATA_HDR4_LEN 30
-
-#define MIN_FRAG_THRESHOLD 256U
-#define MAX_FRAG_THRESHOLD 2346U
-
-
-/* Frame control field constants */
-#define IEEE80211_FCTL_VERS 0x0003
-#define IEEE80211_FCTL_FTYPE 0x000c
-#define IEEE80211_FCTL_STYPE 0x00f0
-#define IEEE80211_FCTL_FRAMETYPE 0x00fc
-#define IEEE80211_FCTL_TODS 0x0100
-#define IEEE80211_FCTL_FROMDS 0x0200
-#define IEEE80211_FCTL_DSTODS 0x0300
-#define IEEE80211_FCTL_MOREFRAGS 0x0400
-#define IEEE80211_FCTL_RETRY 0x0800
-#define IEEE80211_FCTL_PM 0x1000
-#define IEEE80211_FCTL_MOREDATA 0x2000
-#define IEEE80211_FCTL_WEP 0x4000
-#define IEEE80211_FCTL_ORDER 0x8000
-
-#define IEEE80211_FTYPE_MGMT 0x0000
-#define IEEE80211_FTYPE_CTL 0x0004
-#define IEEE80211_FTYPE_DATA 0x0008
-
-/* management */
-#define IEEE80211_STYPE_ASSOC_REQ 0x0000
-#define IEEE80211_STYPE_ASSOC_RESP 0x0010
-#define IEEE80211_STYPE_REASSOC_REQ 0x0020
-#define IEEE80211_STYPE_REASSOC_RESP 0x0030
-#define IEEE80211_STYPE_PROBE_REQ 0x0040
-#define IEEE80211_STYPE_PROBE_RESP 0x0050
-#define IEEE80211_STYPE_BEACON 0x0080
-#define IEEE80211_STYPE_ATIM 0x0090
-#define IEEE80211_STYPE_DISASSOC 0x00A0
-#define IEEE80211_STYPE_AUTH 0x00B0
-#define IEEE80211_STYPE_DEAUTH 0x00C0
-#define IEEE80211_STYPE_MANAGE_ACT 0x00D0
-
-/* control */
-#define IEEE80211_STYPE_PSPOLL 0x00A0
-#define IEEE80211_STYPE_RTS 0x00B0
-#define IEEE80211_STYPE_CTS 0x00C0
-#define IEEE80211_STYPE_ACK 0x00D0
-#define IEEE80211_STYPE_CFEND 0x00E0
-#define IEEE80211_STYPE_CFENDACK 0x00F0
-#define IEEE80211_STYPE_BLOCKACK 0x0094
-
-/* data */
-#define IEEE80211_STYPE_DATA 0x0000
-#define IEEE80211_STYPE_DATA_CFACK 0x0010
-#define IEEE80211_STYPE_DATA_CFPOLL 0x0020
-#define IEEE80211_STYPE_DATA_CFACKPOLL 0x0030
-#define IEEE80211_STYPE_NULLFUNC 0x0040
-#define IEEE80211_STYPE_CFACK 0x0050
-#define IEEE80211_STYPE_CFPOLL 0x0060
-#define IEEE80211_STYPE_CFACKPOLL 0x0070
-#define IEEE80211_STYPE_QOS_DATA 0x0080
-#define IEEE80211_STYPE_QOS_NULL 0x00C0
-
-#define IEEE80211_SCTL_FRAG 0x000F
-#define IEEE80211_SCTL_SEQ 0xFFF0
-
-/* QOS control */
-#define IEEE80211_QCTL_TID 0x000F
-
-#define FC_QOS_BIT BIT7
-#define IsDataFrame(pdu) (((pdu[0] & 0x0C) == 0x08) ? true : false)
-#define IsLegacyDataFrame(pdu) (IsDataFrame(pdu) && (!(pdu[0]&FC_QOS_BIT)))
-
-#define IsQoSDataFrame(pframe) ((*(u16 *)pframe&(IEEE80211_STYPE_QOS_DATA|IEEE80211_FTYPE_DATA)) == (IEEE80211_STYPE_QOS_DATA|IEEE80211_FTYPE_DATA))
-#define Frame_Order(pframe) (*(u16 *)pframe&IEEE80211_FCTL_ORDER)
-#define SN_LESS(a, b) (((a-b)&0x800) != 0)
-#define SN_EQUAL(a, b) (a == b)
-#define MAX_DEV_ADDR_SIZE 8
-typedef enum _ACT_CATEGORY{
- ACT_CAT_QOS = 1,
- ACT_CAT_DLS = 2,
- ACT_CAT_BA = 3,
- ACT_CAT_HT = 7,
- ACT_CAT_WMM = 17,
-} ACT_CATEGORY, *PACT_CATEGORY;
-
-typedef enum _TS_ACTION{
- ACT_ADDTSREQ = 0,
- ACT_ADDTSRSP = 1,
- ACT_DELTS = 2,
- ACT_SCHEDULE = 3,
-} TS_ACTION, *PTS_ACTION;
-
-typedef enum _BA_ACTION{
- ACT_ADDBAREQ = 0,
- ACT_ADDBARSP = 1,
- ACT_DELBA = 2,
-} BA_ACTION, *PBA_ACTION;
-
-typedef enum _InitialGainOpType{
- IG_Backup = 0,
- IG_Restore,
- IG_Max
-} InitialGainOpType;
-
-/* debug macros */
-#define CONFIG_IEEE80211_DEBUG
-#ifdef CONFIG_IEEE80211_DEBUG
-extern u32 ieee80211_debug_level;
-#define IEEE80211_DEBUG(level, fmt, args...) \
-do { if (ieee80211_debug_level & (level)) \
- printk(KERN_DEBUG "ieee80211: " fmt, ## args); } while (0)
-/* wb added to debug out data buf
- * if you want print DATA buffer related BA, please set ieee80211_debug_level
- * to DATA|BA
- */
-#define IEEE80211_DEBUG_DATA(level, data, datalen) \
- do { if ((ieee80211_debug_level & (level)) == (level)) { \
- int i; \
- u8* pdata = (u8 *) data; \
- printk(KERN_DEBUG "ieee80211: %s()\n", __FUNCTION__); \
- for (i = 0; i < (int)(datalen); i++) { \
- printk("%2x ", pdata[i]); \
- if ((i+1)%16 == 0) \
- printk("\n"); \
- } \
- printk("\n"); \
- } \
- } while (0)
-#else
-#define IEEE80211_DEBUG(level, fmt, args...) do {} while (0)
-#define IEEE80211_DEBUG_DATA(level, data, datalen) do {} while (0)
-#endif /* CONFIG_IEEE80211_DEBUG */
-
-/* debug macros not dependent on CONFIG_IEEE80211_DEBUG */
-
-/*
- * To use the debug system;
- *
- * If you are defining a new debug classification, simply add it to the #define
- * list here in the form of:
- *
- * #define IEEE80211_DL_xxxx VALUE
- *
- * shifting value to the left one bit from the previous entry. xxxx should be
- * the name of the classification (for example, WEP)
- *
- * You then need to either add a IEEE80211_xxxx_DEBUG() macro definition for your
- * classification, or use IEEE80211_DEBUG(IEEE80211_DL_xxxx, ...) whenever you want
- * to send output to that classification.
- *
- * To add your debug level to the list of levels seen when you perform
- *
- * % cat /proc/net/ipw/debug_level
- *
- * you simply need to add your entry to the ipw_debug_levels array.
- *
- * If you do not see debug_level in /proc/net/ipw then you do not have
- * CONFIG_IEEE80211_DEBUG defined in your kernel configuration
- *
- */
-
-#define IEEE80211_DL_INFO (1<<0)
-#define IEEE80211_DL_WX (1<<1)
-#define IEEE80211_DL_SCAN (1<<2)
-#define IEEE80211_DL_STATE (1<<3)
-#define IEEE80211_DL_MGMT (1<<4)
-#define IEEE80211_DL_FRAG (1<<5)
-#define IEEE80211_DL_EAP (1<<6)
-#define IEEE80211_DL_DROP (1<<7)
-
-#define IEEE80211_DL_TX (1<<8)
-#define IEEE80211_DL_RX (1<<9)
-
-#define IEEE80211_DL_HT (1<<10) /* HT */
-#define IEEE80211_DL_BA (1<<11) /* ba */
-#define IEEE80211_DL_TS (1<<12) /* TS */
-#define IEEE80211_DL_QOS (1<<13)
-#define IEEE80211_DL_REORDER (1<<14)
-#define IEEE80211_DL_IOT (1<<15)
-#define IEEE80211_DL_IPS (1<<16)
-#define IEEE80211_DL_TRACE (1<<29) /* trace function, need to user net_ratelimit() together in order not to print too much to the screen */
-#define IEEE80211_DL_DATA (1<<30) /* use this flag to control whether print data buf out. */
-#define IEEE80211_DL_ERR (1<<31) /* always open */
-#define IEEE80211_ERROR(f, a...) printk(KERN_ERR "ieee80211: " f, ## a)
-#define IEEE80211_WARNING(f, a...) printk(KERN_WARNING "ieee80211: " f, ## a)
-#define IEEE80211_DEBUG_INFO(f, a...) IEEE80211_DEBUG(IEEE80211_DL_INFO, f, ## a)
-
-#define IEEE80211_DEBUG_WX(f, a...) IEEE80211_DEBUG(IEEE80211_DL_WX, f, ## a)
-#define IEEE80211_DEBUG_SCAN(f, a...) IEEE80211_DEBUG(IEEE80211_DL_SCAN, f, ## a)
-#define IEEE80211_DEBUG_STATE(f, a...) IEEE80211_DEBUG(IEEE80211_DL_STATE, f, ## a)
-#define IEEE80211_DEBUG_MGMT(f, a...) IEEE80211_DEBUG(IEEE80211_DL_MGMT, f, ## a)
-#define IEEE80211_DEBUG_FRAG(f, a...) IEEE80211_DEBUG(IEEE80211_DL_FRAG, f, ## a)
-#define IEEE80211_DEBUG_EAP(f, a...) IEEE80211_DEBUG(IEEE80211_DL_EAP, f, ## a)
-#define IEEE80211_DEBUG_DROP(f, a...) IEEE80211_DEBUG(IEEE80211_DL_DROP, f, ## a)
-#define IEEE80211_DEBUG_TX(f, a...) IEEE80211_DEBUG(IEEE80211_DL_TX, f, ## a)
-#define IEEE80211_DEBUG_RX(f, a...) IEEE80211_DEBUG(IEEE80211_DL_RX, f, ## a)
-#define IEEE80211_DEBUG_QOS(f, a...) IEEE80211_DEBUG(IEEE80211_DL_QOS, f, ## a)
-
-#ifdef CONFIG_IEEE80211_DEBUG
-/* Added by Annie, 2005-11-22. */
-#define MAX_STR_LEN 64
-/* I want to see ASCII 33 to 126 only. Otherwise, I print '?'. Annie, 2005-11-22.*/
-#define PRINTABLE(_ch) (_ch > '!' && _ch < '~')
-#define IEEE80211_PRINT_STR(_Comp, _TitleString, _Ptr, _Len) \
- if ((_Comp) & level) { \
- int __i; \
- u8 buffer[MAX_STR_LEN]; \
- int length = (_Len < MAX_STR_LEN) ? _Len : (MAX_STR_LEN - 1); \
- memset(buffer, 0, MAX_STR_LEN); \
- memcpy(buffer, (u8 *)_Ptr, length); \
- for (__i = 0; __i < MAX_STR_LEN; __i++) { \
- if (!PRINTABLE(buffer[__i])) \
- buffer[__i] = '?'; \
- } \
- buffer[length] = '\0'; \
- printk("Rtl819x: "); \
- printk(_TitleString); \
- printk(": %d, <%s>\n", _Len, buffer); \
- }
-#else
-#define IEEE80211_PRINT_STR(_Comp, _TitleString, _Ptr, _Len) do {} while (0)
-#endif
-
-#include <linux/netdevice.h>
-#include <linux/if_arp.h> /* ARPHRD_ETHER */
-
-#ifndef WIRELESS_SPY
-#define WIRELESS_SPY /* enable iwspy support */
-#endif
-#include <net/iw_handler.h> /* new driver API */
-
-#ifndef ETH_P_PAE
-#define ETH_P_PAE 0x888E /* Port Access Entity (IEEE 802.1X) */
-#endif /* ETH_P_PAE */
-
-#define ETH_P_PREAUTH 0x88C7 /* IEEE 802.11i pre-authentication */
-
-#ifndef ETH_P_80211_RAW
-#define ETH_P_80211_RAW (ETH_P_ECONET + 1)
-#endif
-
-/* IEEE 802.11 defines */
-
-#define P80211_OUI_LEN 3
-
-struct ieee80211_snap_hdr {
-
- u8 dsap; /* always 0xAA */
- u8 ssap; /* always 0xAA */
- u8 ctrl; /* always 0x03 */
- u8 oui[P80211_OUI_LEN]; /* organizational universal id */
-
-} __attribute__ ((packed));
-
-#define SNAP_SIZE sizeof(struct ieee80211_snap_hdr)
-
-#define WLAN_FC_GET_VERS(fc) ((fc) & IEEE80211_FCTL_VERS)
-#define WLAN_FC_GET_TYPE(fc) ((fc) & IEEE80211_FCTL_FTYPE)
-#define WLAN_FC_GET_STYPE(fc) ((fc) & IEEE80211_FCTL_STYPE)
-
-#define WLAN_FC_GET_FRAMETYPE(fc) ((fc) & IEEE80211_FCTL_FRAMETYPE)
-#define WLAN_GET_SEQ_FRAG(seq) ((seq) & IEEE80211_SCTL_FRAG)
-#define WLAN_GET_SEQ_SEQ(seq) (((seq) & IEEE80211_SCTL_SEQ) >> 4)
-
-/* Authentication algorithms */
-#define WLAN_AUTH_OPEN 0
-#define WLAN_AUTH_SHARED_KEY 1
-#define WLAN_AUTH_LEAP 2
-
-#define WLAN_AUTH_CHALLENGE_LEN 128
-
-#define WLAN_CAPABILITY_BSS (1<<0)
-#define WLAN_CAPABILITY_IBSS (1<<1)
-#define WLAN_CAPABILITY_CF_POLLABLE (1<<2)
-#define WLAN_CAPABILITY_CF_POLL_REQUEST (1<<3)
-#define WLAN_CAPABILITY_PRIVACY (1<<4)
-#define WLAN_CAPABILITY_SHORT_PREAMBLE (1<<5)
-#define WLAN_CAPABILITY_PBCC (1<<6)
-#define WLAN_CAPABILITY_CHANNEL_AGILITY (1<<7)
-#define WLAN_CAPABILITY_SPECTRUM_MGMT (1<<8)
-#define WLAN_CAPABILITY_QOS (1<<9)
-#define WLAN_CAPABILITY_SHORT_SLOT (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)
-
-/* Status codes */
-enum ieee80211_statuscode {
- WLAN_STATUS_SUCCESS = 0,
- WLAN_STATUS_UNSPECIFIED_FAILURE = 1,
- WLAN_STATUS_CAPS_UNSUPPORTED = 10,
- WLAN_STATUS_REASSOC_NO_ASSOC = 11,
- WLAN_STATUS_ASSOC_DENIED_UNSPEC = 12,
- WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG = 13,
- WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION = 14,
- WLAN_STATUS_CHALLENGE_FAIL = 15,
- WLAN_STATUS_AUTH_TIMEOUT = 16,
- WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA = 17,
- WLAN_STATUS_ASSOC_DENIED_RATES = 18,
- /* 802.11b */
- WLAN_STATUS_ASSOC_DENIED_NOSHORTPREAMBLE = 19,
- WLAN_STATUS_ASSOC_DENIED_NOPBCC = 20,
- WLAN_STATUS_ASSOC_DENIED_NOAGILITY = 21,
- /* 802.11h */
- WLAN_STATUS_ASSOC_DENIED_NOSPECTRUM = 22,
- WLAN_STATUS_ASSOC_REJECTED_BAD_POWER = 23,
- WLAN_STATUS_ASSOC_REJECTED_BAD_SUPP_CHAN = 24,
- /* 802.11g */
- WLAN_STATUS_ASSOC_DENIED_NOSHORTTIME = 25,
- WLAN_STATUS_ASSOC_DENIED_NODSSSOFDM = 26,
- /* 802.11i */
- WLAN_STATUS_INVALID_IE = 40,
- WLAN_STATUS_INVALID_GROUP_CIPHER = 41,
- WLAN_STATUS_INVALID_PAIRWISE_CIPHER = 42,
- WLAN_STATUS_INVALID_AKMP = 43,
- WLAN_STATUS_UNSUPP_RSN_VERSION = 44,
- WLAN_STATUS_INVALID_RSN_IE_CAP = 45,
- WLAN_STATUS_CIPHER_SUITE_REJECTED = 46,
-};
-
-/* Reason codes */
-enum ieee80211_reasoncode {
- WLAN_REASON_UNSPECIFIED = 1,
- WLAN_REASON_PREV_AUTH_NOT_VALID = 2,
- WLAN_REASON_DEAUTH_LEAVING = 3,
- WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY = 4,
- WLAN_REASON_DISASSOC_AP_BUSY = 5,
- WLAN_REASON_CLASS2_FRAME_FROM_NONAUTH_STA = 6,
- WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA = 7,
- WLAN_REASON_DISASSOC_STA_HAS_LEFT = 8,
- WLAN_REASON_STA_REQ_ASSOC_WITHOUT_AUTH = 9,
- /* 802.11h */
- WLAN_REASON_DISASSOC_BAD_POWER = 10,
- WLAN_REASON_DISASSOC_BAD_SUPP_CHAN = 11,
- /* 802.11i */
- WLAN_REASON_INVALID_IE = 13,
- WLAN_REASON_MIC_FAILURE = 14,
- WLAN_REASON_4WAY_HANDSHAKE_TIMEOUT = 15,
- WLAN_REASON_GROUP_KEY_HANDSHAKE_TIMEOUT = 16,
- WLAN_REASON_IE_DIFFERENT = 17,
- WLAN_REASON_INVALID_GROUP_CIPHER = 18,
- WLAN_REASON_INVALID_PAIRWISE_CIPHER = 19,
- WLAN_REASON_INVALID_AKMP = 20,
- WLAN_REASON_UNSUPP_RSN_VERSION = 21,
- WLAN_REASON_INVALID_RSN_IE_CAP = 22,
- WLAN_REASON_IEEE8021X_FAILED = 23,
- WLAN_REASON_CIPHER_SUITE_REJECTED = 24,
-};
-
-#define IEEE80211_STATMASK_SIGNAL (1<<0)
-#define IEEE80211_STATMASK_RSSI (1<<1)
-#define IEEE80211_STATMASK_NOISE (1<<2)
-#define IEEE80211_STATMASK_RATE (1<<3)
-#define IEEE80211_STATMASK_WEMASK 0x7
-
-#define IEEE80211_CCK_MODULATION (1<<0)
-#define IEEE80211_OFDM_MODULATION (1<<1)
-
-#define IEEE80211_24GHZ_BAND (1<<0)
-#define IEEE80211_52GHZ_BAND (1<<1)
-
-#define IEEE80211_CCK_RATE_LEN 4
-#define IEEE80211_CCK_RATE_1MB 0x02
-#define IEEE80211_CCK_RATE_2MB 0x04
-#define IEEE80211_CCK_RATE_5MB 0x0B
-#define IEEE80211_CCK_RATE_11MB 0x16
-#define IEEE80211_OFDM_RATE_LEN 8
-#define IEEE80211_OFDM_RATE_6MB 0x0C
-#define IEEE80211_OFDM_RATE_9MB 0x12
-#define IEEE80211_OFDM_RATE_12MB 0x18
-#define IEEE80211_OFDM_RATE_18MB 0x24
-#define IEEE80211_OFDM_RATE_24MB 0x30
-#define IEEE80211_OFDM_RATE_36MB 0x48
-#define IEEE80211_OFDM_RATE_48MB 0x60
-#define IEEE80211_OFDM_RATE_54MB 0x6C
-#define IEEE80211_BASIC_RATE_MASK 0x80
-
-#define IEEE80211_CCK_RATE_1MB_MASK (1<<0)
-#define IEEE80211_CCK_RATE_2MB_MASK (1<<1)
-#define IEEE80211_CCK_RATE_5MB_MASK (1<<2)
-#define IEEE80211_CCK_RATE_11MB_MASK (1<<3)
-#define IEEE80211_OFDM_RATE_6MB_MASK (1<<4)
-#define IEEE80211_OFDM_RATE_9MB_MASK (1<<5)
-#define IEEE80211_OFDM_RATE_12MB_MASK (1<<6)
-#define IEEE80211_OFDM_RATE_18MB_MASK (1<<7)
-#define IEEE80211_OFDM_RATE_24MB_MASK (1<<8)
-#define IEEE80211_OFDM_RATE_36MB_MASK (1<<9)
-#define IEEE80211_OFDM_RATE_48MB_MASK (1<<10)
-#define IEEE80211_OFDM_RATE_54MB_MASK (1<<11)
-
-#define IEEE80211_CCK_RATES_MASK 0x0000000F
-#define IEEE80211_CCK_BASIC_RATES_MASK (IEEE80211_CCK_RATE_1MB_MASK | \
- IEEE80211_CCK_RATE_2MB_MASK)
-#define IEEE80211_CCK_DEFAULT_RATES_MASK (IEEE80211_CCK_BASIC_RATES_MASK | \
- IEEE80211_CCK_RATE_5MB_MASK | \
- IEEE80211_CCK_RATE_11MB_MASK)
-
-#define IEEE80211_OFDM_RATES_MASK 0x00000FF0
-#define IEEE80211_OFDM_BASIC_RATES_MASK (IEEE80211_OFDM_RATE_6MB_MASK | \
- IEEE80211_OFDM_RATE_12MB_MASK | \
- IEEE80211_OFDM_RATE_24MB_MASK)
-#define IEEE80211_OFDM_DEFAULT_RATES_MASK (IEEE80211_OFDM_BASIC_RATES_MASK | \
- IEEE80211_OFDM_RATE_9MB_MASK | \
- IEEE80211_OFDM_RATE_18MB_MASK | \
- IEEE80211_OFDM_RATE_36MB_MASK | \
- IEEE80211_OFDM_RATE_48MB_MASK | \
- IEEE80211_OFDM_RATE_54MB_MASK)
-#define IEEE80211_DEFAULT_RATES_MASK (IEEE80211_OFDM_DEFAULT_RATES_MASK | \
- IEEE80211_CCK_DEFAULT_RATES_MASK)
-
-#define IEEE80211_NUM_OFDM_RATES 8
-#define IEEE80211_NUM_CCK_RATES 4
-#define IEEE80211_OFDM_SHIFT_MASK_A 4
-
-
-/* this is stolen and modified from the madwifi driver*/
-#define IEEE80211_FC0_TYPE_MASK 0x0c
-#define IEEE80211_FC0_TYPE_DATA 0x08
-#define IEEE80211_FC0_SUBTYPE_MASK 0xB0
-#define IEEE80211_FC0_SUBTYPE_QOS 0x80
-
-#define IEEE80211_QOS_HAS_SEQ(fc) \
- (((fc) & (IEEE80211_FC0_TYPE_MASK | IEEE80211_FC0_SUBTYPE_MASK)) == \
- (IEEE80211_FC0_TYPE_DATA | IEEE80211_FC0_SUBTYPE_QOS))
-
-/* this is stolen from ipw2200 driver */
-#define IEEE_IBSS_MAC_HASH_SIZE 31
-struct ieee_ibss_seq {
- u8 mac[ETH_ALEN];
- u16 seq_num[17];
- u16 frag_num[17];
- unsigned long packet_time[17];
- struct list_head list;
-};
-
-/* NOTE: This data is for statistical purposes; not all hardware provides this
- * information for frames received. Not setting these will not cause
- * any adverse affects. */
-struct ieee80211_rx_stats {
- u32 mac_time[2];
- s8 rssi;
- u8 signal;
- u8 noise;
- u16 rate; /* in 100 kbps */
- u8 received_channel;
- u8 control;
- u8 mask;
- u8 freq;
- u16 len;
- u64 tsf;
- u32 beacon_time;
- u8 nic_type;
- u16 Length;
- u8 SignalQuality; /* in 0-100 index. */
- s32 RecvSignalPower; /* Real power in dBm for this packet, no beautification and aggregation. */
- s8 RxPower; /* in dBm Translate from PWdB */
- u8 SignalStrength; /* in 0-100 index. */
- u16 bHwError:1;
- u16 bCRC:1;
- u16 bICV:1;
- u16 bShortPreamble:1;
- u16 Antenna:1; /* for rtl8185 */
- u16 Decrypted:1; /* for rtl8185, rtl8187 */
- u16 Wakeup:1; /* for rtl8185 */
- u16 Reserved0:1; /* for rtl8185 */
- u8 AGC;
- u32 TimeStampLow;
- u32 TimeStampHigh;
- bool bShift;
- bool bIsQosData;
- u8 UserPriority;
-
- /*
- * 1Attention Please!!!<11n or 8190 specific code should be put below this line>
- */
-
- u8 RxDrvInfoSize;
- u8 RxBufShift;
- bool bIsAMPDU;
- bool bFirstMPDU;
- bool bContainHTC;
- bool RxIs40MHzPacket;
- u32 RxPWDBAll;
- u8 RxMIMOSignalStrength[4]; /* in 0~100 index */
- s8 RxMIMOSignalQuality[2];
- bool bPacketMatchBSSID;
- bool bIsCCK;
- bool bPacketToSelf;
- u8 *virtual_address;
- u16 packetlength; /* Total packet length: Must equal to sum of all FragLength */
- u16 fraglength; /* FragLength should equal to PacketLength in non-fragment case */
- u16 fragoffset; /* Data offset for this fragment */
- u16 ntotalfrag;
- bool bisrxaggrsubframe;
- bool bPacketBeacon; /* cosa add for rssi */
- bool bToSelfBA; /* cosa add for rssi */
- char cck_adc_pwdb[4]; /* cosa add for rx path selection */
- u16 Seq_Num;
-
-};
-
-/* IEEE 802.11 requires that STA supports concurrent reception of at least
- * three fragmented frames. This define can be increased to support more
- * concurrent frames, but it should be noted that each entry can consume about
- * 2 kB of RAM and increasing cache size will slow down frame reassembly. */
-#define IEEE80211_FRAG_CACHE_LEN 4
-
-struct ieee80211_frag_entry {
- unsigned long first_frag_time;
- unsigned int seq;
- unsigned int last_frag;
- struct sk_buff *skb;
- u8 src_addr[ETH_ALEN];
- u8 dst_addr[ETH_ALEN];
-};
-
-struct ieee80211_stats {
- unsigned int tx_unicast_frames;
- unsigned int tx_multicast_frames;
- unsigned int tx_fragments;
- unsigned int tx_unicast_octets;
- unsigned int tx_multicast_octets;
- unsigned int tx_deferred_transmissions;
- unsigned int tx_single_retry_frames;
- unsigned int tx_multiple_retry_frames;
- unsigned int tx_retry_limit_exceeded;
- unsigned int tx_discards;
- unsigned int rx_unicast_frames;
- unsigned int rx_multicast_frames;
- unsigned int rx_fragments;
- unsigned int rx_unicast_octets;
- unsigned int rx_multicast_octets;
- unsigned int rx_fcs_errors;
- unsigned int rx_discards_no_buffer;
- unsigned int tx_discards_wrong_sa;
- unsigned int rx_discards_undecryptable;
- unsigned int rx_message_in_msg_fragments;
- unsigned int rx_message_in_bad_msg_fragments;
-};
-
-struct ieee80211_device;
-
-#include "ieee80211_crypt.h"
-
-#define SEC_KEY_1 (1<<0)
-#define SEC_KEY_2 (1<<1)
-#define SEC_KEY_3 (1<<2)
-#define SEC_KEY_4 (1<<3)
-#define SEC_ACTIVE_KEY (1<<4)
-#define SEC_AUTH_MODE (1<<5)
-#define SEC_UNICAST_GROUP (1<<6)
-#define SEC_LEVEL (1<<7)
-#define SEC_ENABLED (1<<8)
-#define SEC_ENCRYPT (1<<9)
-
-#define SEC_LEVEL_0 0 /* None */
-#define SEC_LEVEL_1 1 /* WEP 40 and 104 bit */
-#define SEC_LEVEL_2 2 /* Level 1 + TKIP */
-#define SEC_LEVEL_2_CKIP 3 /* Level 1 + CKIP */
-#define SEC_LEVEL_3 4 /* Level 2 + CCMP */
-
-#define SEC_ALG_NONE 0
-#define SEC_ALG_WEP 1
-#define SEC_ALG_TKIP 2
-#define SEC_ALG_CCMP 3
-
-#define WEP_KEYS 4
-#define WEP_KEY_LEN 13
-#define SCM_KEY_LEN 32
-#define SCM_TEMPORAL_KEY_LENGTH 16
-
-struct ieee80211_security {
- u16 active_key:2,
- enabled:1,
- auth_mode:2,
- auth_algo:4,
- unicast_uses_group:1,
- encrypt:1;
- u8 key_sizes[WEP_KEYS];
- u8 keys[WEP_KEYS][SCM_KEY_LEN];
- u8 level;
- u16 flags;
-} __attribute__ ((packed));
-
-
-/*
- 802.11 data frame from AP
- ,-------------------------------------------------------------------.
-Bytes | 2 | 2 | 6 | 6 | 6 | 2 | 0..2312 | 4 |
- |------|------|---------|---------|---------|------|---------|------|
-Desc. | ctrl | dura | DA/RA | TA | SA | Sequ | frame | fcs |
- | | tion | (BSSID) | | | ence | data | |
- `-------------------------------------------------------------------'
-Total: 28-2340 bytes
-*/
-
-/* Management Frame Information Element Types */
-enum ieee80211_mfie {
- MFIE_TYPE_SSID = 0,
- MFIE_TYPE_RATES = 1,
- MFIE_TYPE_FH_SET = 2,
- MFIE_TYPE_DS_SET = 3,
- MFIE_TYPE_CF_SET = 4,
- MFIE_TYPE_TIM = 5,
- MFIE_TYPE_IBSS_SET = 6,
- MFIE_TYPE_COUNTRY = 7,
- MFIE_TYPE_HOP_PARAMS = 8,
- MFIE_TYPE_HOP_TABLE = 9,
- MFIE_TYPE_REQUEST = 10,
- MFIE_TYPE_CHALLENGE = 16,
- MFIE_TYPE_POWER_CONSTRAINT = 32,
- MFIE_TYPE_POWER_CAPABILITY = 33,
- MFIE_TYPE_TPC_REQUEST = 34,
- MFIE_TYPE_TPC_REPORT = 35,
- MFIE_TYPE_SUPP_CHANNELS = 36,
- MFIE_TYPE_CSA = 37,
- MFIE_TYPE_MEASURE_REQUEST = 38,
- MFIE_TYPE_MEASURE_REPORT = 39,
- MFIE_TYPE_QUIET = 40,
- MFIE_TYPE_IBSS_DFS = 41,
- MFIE_TYPE_ERP = 42,
- MFIE_TYPE_RSN = 48,
- MFIE_TYPE_RATES_EX = 50,
- MFIE_TYPE_HT_CAP = 45,
- MFIE_TYPE_HT_INFO = 61,
- MFIE_TYPE_AIRONET = 133,
- MFIE_TYPE_GENERIC = 221,
- MFIE_TYPE_QOS_PARAMETER = 222,
-};
-
-/* Minimal header; can be used for passing 802.11 frames with sufficient
- * information to determine what type of underlying data type is actually
- * stored in the data. */
-struct ieee80211_hdr {
- __le16 frame_ctl;
- __le16 duration_id;
- u8 payload[0];
-} __attribute__ ((packed));
-
-struct ieee80211_hdr_1addr {
- __le16 frame_ctl;
- __le16 duration_id;
- u8 addr1[ETH_ALEN];
- u8 payload[0];
-} __attribute__ ((packed));
-
-struct ieee80211_hdr_2addr {
- __le16 frame_ctl;
- __le16 duration_id;
- u8 addr1[ETH_ALEN];
- u8 addr2[ETH_ALEN];
- u8 payload[0];
-} __attribute__ ((packed));
-
-struct ieee80211_hdr_3addr {
- __le16 frame_ctl;
- __le16 duration_id;
- u8 addr1[ETH_ALEN];
- u8 addr2[ETH_ALEN];
- u8 addr3[ETH_ALEN];
- __le16 seq_ctl;
- u8 payload[0];
-} __attribute__ ((packed));
-
-struct ieee80211_hdr_4addr {
- __le16 frame_ctl;
- __le16 duration_id;
- u8 addr1[ETH_ALEN];
- u8 addr2[ETH_ALEN];
- u8 addr3[ETH_ALEN];
- __le16 seq_ctl;
- u8 addr4[ETH_ALEN];
- u8 payload[0];
-} __attribute__ ((packed));
-
-struct ieee80211_hdr_3addrqos {
- __le16 frame_ctl;
- __le16 duration_id;
- u8 addr1[ETH_ALEN];
- u8 addr2[ETH_ALEN];
- u8 addr3[ETH_ALEN];
- __le16 seq_ctl;
- u8 payload[0];
- __le16 qos_ctl;
-} __attribute__ ((packed));
-
-struct ieee80211_hdr_4addrqos {
- __le16 frame_ctl;
- __le16 duration_id;
- u8 addr1[ETH_ALEN];
- u8 addr2[ETH_ALEN];
- u8 addr3[ETH_ALEN];
- __le16 seq_ctl;
- u8 addr4[ETH_ALEN];
- u8 payload[0];
- __le16 qos_ctl;
-} __attribute__ ((packed));
-
-struct ieee80211_info_element {
- u8 id;
- u8 len;
- u8 data[0];
-} __attribute__ ((packed));
-
-struct ieee80211_authentication {
- struct ieee80211_hdr_3addr header;
- __le16 algorithm;
- __le16 transaction;
- __le16 status;
- /*challenge*/
- struct ieee80211_info_element info_element[0];
-} __attribute__ ((packed));
-
-struct ieee80211_disassoc {
- struct ieee80211_hdr_3addr header;
- __le16 reason;
-} __attribute__ ((packed));
-
-struct ieee80211_probe_request {
- struct ieee80211_hdr_3addr header;
- /* SSID, supported rates */
- struct ieee80211_info_element info_element[0];
-} __attribute__ ((packed));
-
-struct ieee80211_probe_response {
- struct ieee80211_hdr_3addr header;
- u32 time_stamp[2];
- __le16 beacon_interval;
- __le16 capability;
- /* SSID, supported rates, FH params, DS params,
- * CF params, IBSS params, TIM (if beacon), RSN */
- struct ieee80211_info_element info_element[0];
-} __attribute__ ((packed));
-
-/* Alias beacon for probe_response */
-#define ieee80211_beacon ieee80211_probe_response
-
-struct ieee80211_assoc_request_frame {
- struct ieee80211_hdr_3addr header;
- __le16 capability;
- __le16 listen_interval;
- /* SSID, supported rates, RSN */
- struct ieee80211_info_element info_element[0];
-} __attribute__ ((packed));
-
-struct ieee80211_reassoc_request_frame {
- struct ieee80211_hdr_3addr header;
- __le16 capability;
- __le16 listen_interval;
- u8 current_ap[ETH_ALEN];
- /* SSID, supported rates, RSN */
- struct ieee80211_info_element info_element[0];
-} __attribute__ ((packed));
-
-struct ieee80211_assoc_response_frame {
- struct ieee80211_hdr_3addr header;
- __le16 capability;
- __le16 status;
- __le16 aid;
- struct ieee80211_info_element info_element[0]; /* supported rates */
-} __attribute__ ((packed));
-
-struct ieee80211_txb {
- u8 nr_frags;
- u8 encrypted;
- u8 queue_index;
- u8 rts_included;
- u16 reserved;
- __le16 frag_size;
- __le16 payload_size;
- struct sk_buff *fragments[0];
-};
-
-#define MAX_TX_AGG_COUNT 16
-struct ieee80211_drv_agg_txb {
- u8 nr_drv_agg_frames;
- struct sk_buff *tx_agg_frames[MAX_TX_AGG_COUNT];
-} __attribute__((packed));
-
-#define MAX_SUBFRAME_COUNT 64
-struct ieee80211_rxb {
- u8 nr_subframes;
- struct sk_buff *subframes[MAX_SUBFRAME_COUNT];
- u8 dst[ETH_ALEN];
- u8 src[ETH_ALEN];
-} __attribute__((packed));
-
-typedef union _frameqos {
- u16 shortdata;
- u8 chardata[2];
- struct {
- u16 tid:4;
- u16 eosp:1;
- u16 ack_policy:2;
- u16 reserved:1;
- u16 txop:8;
- } field;
-} frameqos, *pframeqos;
-
-/* SWEEP TABLE ENTRIES NUMBER*/
-#define MAX_SWEEP_TAB_ENTRIES 42
-#define MAX_SWEEP_TAB_ENTRIES_PER_PACKET 7
-/* MAX_RATES_LENGTH needs to be 12. The spec says 8, and many APs
- * only use 8, and then use extended rates for the remaining supported
- * rates. Other APs, however, stick all of their supported rates on the
- * main rates information element... */
-#define MAX_RATES_LENGTH ((u8)12)
-#define MAX_RATES_EX_LENGTH ((u8)16)
-#define MAX_NETWORK_COUNT 128
-
-#define MAX_CHANNEL_NUMBER 161
-#define IEEE80211_SOFTMAC_SCAN_TIME 100
-/* (HZ / 2) */
-#define IEEE80211_SOFTMAC_ASSOC_RETRY_TIME (HZ * 2)
-
-#define CRC_LENGTH 4U
-
-#define MAX_WPA_IE_LEN 64
-
-#define NETWORK_EMPTY_ESSID (1<<0)
-#define NETWORK_HAS_OFDM (1<<1)
-#define NETWORK_HAS_CCK (1<<2)
-
-/* QoS structure */
-#define NETWORK_HAS_QOS_PARAMETERS (1<<3)
-#define NETWORK_HAS_QOS_INFORMATION (1<<4)
-#define NETWORK_HAS_QOS_MASK (NETWORK_HAS_QOS_PARAMETERS | \
- NETWORK_HAS_QOS_INFORMATION)
-/* 802.11h */
-#define NETWORK_HAS_POWER_CONSTRAINT (1<<5)
-#define NETWORK_HAS_CSA (1<<6)
-#define NETWORK_HAS_QUIET (1<<7)
-#define NETWORK_HAS_IBSS_DFS (1<<8)
-#define NETWORK_HAS_TPC_REPORT (1<<9)
-
-#define NETWORK_HAS_ERP_VALUE (1<<10)
-
-#define QOS_QUEUE_NUM 4
-#define QOS_OUI_LEN 3
-#define QOS_OUI_TYPE 2
-#define QOS_ELEMENT_ID 221
-#define QOS_OUI_INFO_SUB_TYPE 0
-#define QOS_OUI_PARAM_SUB_TYPE 1
-#define QOS_VERSION_1 1
-#define QOS_AIFSN_MIN_VALUE 2
-struct ieee80211_qos_information_element {
- u8 elementID;
- u8 length;
- u8 qui[QOS_OUI_LEN];
- u8 qui_type;
- u8 qui_subtype;
- u8 version;
- u8 ac_info;
-} __attribute__ ((packed));
-
-struct ieee80211_qos_ac_parameter {
- u8 aci_aifsn;
- u8 ecw_min_max;
- __le16 tx_op_limit;
-} __attribute__ ((packed));
-
-struct ieee80211_qos_parameter_info {
- struct ieee80211_qos_information_element info_element;
- u8 reserved;
- struct ieee80211_qos_ac_parameter ac_params_record[QOS_QUEUE_NUM];
-} __attribute__ ((packed));
-
-struct ieee80211_qos_parameters {
- __le16 cw_min[QOS_QUEUE_NUM];
- __le16 cw_max[QOS_QUEUE_NUM];
- u8 aifs[QOS_QUEUE_NUM];
- u8 flag[QOS_QUEUE_NUM];
- __le16 tx_op_limit[QOS_QUEUE_NUM];
-} __attribute__ ((packed));
-
-struct ieee80211_qos_data {
- struct ieee80211_qos_parameters parameters;
- int active;
- int supported;
- u8 param_count;
- u8 old_param_count;
-};
-
-struct ieee80211_tim_parameters {
- u8 tim_count;
- u8 tim_period;
-} __attribute__ ((packed));
-
-struct ieee80211_wmm_ac_param {
- u8 ac_aci_acm_aifsn;
- u8 ac_ecwmin_ecwmax;
- u16 ac_txop_limit;
-};
-
-struct ieee80211_wmm_ts_info {
- u8 ac_dir_tid;
- u8 ac_up_psb;
- u8 reserved;
-} __attribute__ ((packed));
-
-struct ieee80211_wmm_tspec_elem {
- struct ieee80211_wmm_ts_info ts_info;
- u16 norm_msdu_size;
- u16 max_msdu_size;
- u32 min_serv_inter;
- u32 max_serv_inter;
- u32 inact_inter;
- u32 suspen_inter;
- u32 serv_start_time;
- u32 min_data_rate;
- u32 mean_data_rate;
- u32 peak_data_rate;
- u32 max_burst_size;
- u32 delay_bound;
- u32 min_phy_rate;
- u16 surp_band_allow;
- u16 medium_time;
-} __attribute__((packed));
-enum eap_type {
- EAP_PACKET = 0,
- EAPOL_START,
- EAPOL_LOGOFF,
- EAPOL_KEY,
- EAPOL_ENCAP_ASF_ALERT
-};
-
-static const char *eap_types[] = {
- [EAP_PACKET] = "EAP-Packet",
- [EAPOL_START] = "EAPOL-Start",
- [EAPOL_LOGOFF] = "EAPOL-Logoff",
- [EAPOL_KEY] = "EAPOL-Key",
- [EAPOL_ENCAP_ASF_ALERT] = "EAPOL-Encap-ASF-Alert"
-};
-
-static inline const char *eap_get_type(int type)
-{
- return ((u32)type >= ARRAY_SIZE(eap_types)) ? "Unknown" : eap_types[type];
-}
-static inline u8 Frame_QoSTID(u8 *buf)
-{
- struct ieee80211_hdr_3addr *hdr;
- u16 fc;
- hdr = (struct ieee80211_hdr_3addr *)buf;
- fc = le16_to_cpu(hdr->frame_ctl);
- return (u8)((frameqos *)(buf + (((fc & IEEE80211_FCTL_TODS) && (fc & IEEE80211_FCTL_FROMDS)) ? 30 : 24)))->field.tid;
-}
-
-
-struct eapol {
- u8 snap[6];
- u16 ethertype;
- u8 version;
- u8 type;
- u16 length;
-} __attribute__ ((packed));
-
-struct ieee80211_softmac_stats{
- unsigned int rx_ass_ok;
- unsigned int rx_ass_err;
- unsigned int rx_probe_rq;
- unsigned int tx_probe_rs;
- unsigned int tx_beacons;
- unsigned int rx_auth_rq;
- unsigned int rx_auth_rs_ok;
- unsigned int rx_auth_rs_err;
- unsigned int tx_auth_rq;
- unsigned int no_auth_rs;
- unsigned int no_ass_rs;
- unsigned int tx_ass_rq;
- unsigned int rx_ass_rq;
- unsigned int tx_probe_rq;
- unsigned int reassoc;
- unsigned int swtxstop;
- unsigned int swtxawake;
- unsigned char CurrentShowTxate;
- unsigned char last_packet_rate;
- unsigned int txretrycount;
-};
-
-#define BEACON_PROBE_SSID_ID_POSITION 12
-
-struct ieee80211_info_element_hdr {
- u8 id;
- u8 len;
-} __attribute__ ((packed));
-
-/*
- * These are the data types that can make up management packets
- *
- u16 auth_algorithm;
- u16 auth_sequence;
- u16 beacon_interval;
- u16 capability;
- u8 current_ap[ETH_ALEN];
- u16 listen_interval;
- struct {
- u16 association_id:14, reserved:2;
- } __attribute__ ((packed));
- u32 time_stamp[2];
- u16 reason;
- u16 status;
-*/
-
-#define IEEE80211_DEFAULT_TX_ESSID "Penguin"
-#define IEEE80211_DEFAULT_BASIC_RATE 2 /* 1Mbps */
-
-enum {WMM_all_frame, WMM_two_frame, WMM_four_frame, WMM_six_frame};
-#define MAX_SP_Len (WMM_all_frame << 4)
-#define IEEE80211_QOS_TID 0x0f
-#define QOS_CTL_NOTCONTAIN_ACK (0x01 << 5)
-
-#define IEEE80211_DTIM_MBCAST 4
-#define IEEE80211_DTIM_UCAST 2
-#define IEEE80211_DTIM_VALID 1
-#define IEEE80211_DTIM_INVALID 0
-
-#define IEEE80211_PS_DISABLED 0
-#define IEEE80211_PS_UNICAST IEEE80211_DTIM_UCAST
-#define IEEE80211_PS_MBCAST IEEE80211_DTIM_MBCAST
-
-
-#ifdef WMM_Hang_8187
-#undef WMM_Hang_8187
-#endif
-
-#define WME_AC_BK 0x00
-#define WME_AC_BE 0x01
-#define WME_AC_VI 0x02
-#define WME_AC_VO 0x03
-#define WME_ACI_MASK 0x03
-#define WME_AIFSN_MASK 0x03
-#define WME_AC_PRAM_LEN 16
-
-#define MAX_RECEIVE_BUFFER_SIZE 9100
-
-/* UP Mapping to AC, using in MgntQuery_SequenceNumber() and maybe for DSCP */
-#define UP2AC(up) ( \
- ((up) < 1) ? WME_AC_BE : \
- ((up) < 3) ? WME_AC_BK : \
- ((up) < 4) ? WME_AC_BE : \
- ((up) < 6) ? WME_AC_VI : \
- WME_AC_VO)
-/* AC Mapping to UP, using in Tx part for selecting the corresponding TX queue */
-#define AC2UP(_ac) ( \
- ((_ac) == WME_AC_VO) ? 6 : \
- ((_ac) == WME_AC_VI) ? 5 : \
- ((_ac) == WME_AC_BK) ? 1 : \
- 0)
-
-#define ETHER_ADDR_LEN 6 /* length of an Ethernet address */
-#define ETHERNET_HEADER_SIZE 14 /* length of two Ethernet address plus ether type*/
-
-struct ether_header {
- u8 ether_dhost[ETHER_ADDR_LEN];
- u8 ether_shost[ETHER_ADDR_LEN];
- u16 ether_type;
-} __attribute__((packed));
-
-#ifndef ETHERTYPE_PAE
-#define ETHERTYPE_PAE 0x888e /* EAPOL PAE/802.1x */
-#endif
-#ifndef ETHERTYPE_IP
-#define ETHERTYPE_IP 0x0800 /* IP protocol */
-#endif
-
-typedef struct _bss_ht{
-
- bool support_ht;
-
- /* HT related elements */
- u8 ht_cap_buf[32];
- u16 ht_cap_len;
- u8 ht_info_buf[32];
- u16 ht_info_len;
-
- HT_SPEC_VER ht_spec_ver;
- /* HT_CAPABILITY_ELE bdHTCapEle; */
- /* HT_INFORMATION_ELE bdHTInfoEle; */
-
- bool aggregation;
- bool long_slot_time;
-} bss_ht, *pbss_ht;
-
-typedef enum _erp_t{
- ERP_NonERPpresent = 0x01,
- ERP_UseProtection = 0x02,
- ERP_BarkerPreambleMode = 0x04,
-} erp_t;
-
-
-struct ieee80211_network {
- /* These entries are used to identify a unique network */
- u8 bssid[ETH_ALEN];
- u8 channel;
- /* Ensure null-terminated for any debug msgs */
- u8 ssid[IW_ESSID_MAX_SIZE + 1];
- u8 ssid_len;
- struct ieee80211_qos_data qos_data;
- bool bWithAironetIE;
- bool bCkipSupported;
- bool bCcxRmEnable;
- u16 CcxRmState[2];
- /* CCXv4 S59, MBSSID. */
- bool bMBssidValid;
- u8 MBssidMask;
- u8 MBssid[6];
- /* CCX 2 S38, WLAN Device Version Number element. */
- bool bWithCcxVerNum;
- u8 BssCcxVerNumber;
- /* These are network statistics */
- struct ieee80211_rx_stats stats;
- u16 capability;
- u8 rates[MAX_RATES_LENGTH];
- u8 rates_len;
- u8 rates_ex[MAX_RATES_EX_LENGTH];
- u8 rates_ex_len;
- unsigned long last_scanned;
- u8 mode;
- u32 flags;
- u32 last_associate;
- u32 time_stamp[2];
- u16 beacon_interval;
- u16 listen_interval;
- u16 atim_window;
- u8 erp_value;
- u8 wpa_ie[MAX_WPA_IE_LEN];
- size_t wpa_ie_len;
- u8 rsn_ie[MAX_WPA_IE_LEN];
- size_t rsn_ie_len;
-
- struct ieee80211_tim_parameters tim;
- u8 dtim_period;
- u8 dtim_data;
- u32 last_dtim_sta_time[2];
-
- /* appeded for QoS */
- u8 wmm_info;
- struct ieee80211_wmm_ac_param wmm_param[4];
- u8 QoS_Enable;
-#ifdef THOMAS_TURBO
- u8 Turbo_Enable;/* enable turbo mode, added by thomas */
-#endif
-#ifdef ENABLE_DOT11D
- u16 CountryIeLen;
- u8 CountryIeBuf[MAX_IE_LEN];
-#endif
- /* HT Related */
- BSS_HT bssht;
- /* Add to handle broadcom AP management frame CCK rate. */
- bool broadcom_cap_exist;
- bool ralink_cap_exist;
- bool atheros_cap_exist;
- bool cisco_cap_exist;
- bool unknown_cap_exist;
- bool berp_info_valid;
- bool buseprotection;
- /* put at the end of the structure. */
- struct list_head list;
-};
-
-enum ieee80211_state {
-
- /* the card is not linked at all */
- IEEE80211_NOLINK = 0,
-
- /* IEEE80211_ASSOCIATING* are for BSS client mode
- * the driver shall not perform RX filtering unless
- * the state is LINKED.
- * The driver shall just check for the state LINKED and
- * defaults to NOLINK for ALL the other states (including
- * LINKED_SCANNING)
- */
-
- /* the association procedure will start (wq scheduling)*/
- IEEE80211_ASSOCIATING,
- IEEE80211_ASSOCIATING_RETRY,
-
- /* the association procedure is sending AUTH request*/
- IEEE80211_ASSOCIATING_AUTHENTICATING,
-
- /* the association procedure has successfully authentcated
- * and is sending association request
- */
- IEEE80211_ASSOCIATING_AUTHENTICATED,
-
- /* the link is ok. the card associated to a BSS or linked
- * to a ibss cell or acting as an AP and creating the bss
- */
- IEEE80211_LINKED,
-
- /* same as LINKED, but the driver shall apply RX filter
- * rules as we are in NO_LINK mode. As the card is still
- * logically linked, but it is doing a syncro site survey
- * then it will be back to LINKED state.
- */
- IEEE80211_LINKED_SCANNING,
-
-};
-
-#define DEFAULT_MAX_SCAN_AGE (15 * HZ)
-#define DEFAULT_FTS 2346
-
-#define CFG_IEEE80211_RESERVE_FCS (1<<0)
-#define CFG_IEEE80211_COMPUTE_FCS (1<<1)
-#define CFG_IEEE80211_RTS (1<<2)
-
-#define IEEE80211_24GHZ_MIN_CHANNEL 1
-#define IEEE80211_24GHZ_MAX_CHANNEL 14
-#define IEEE80211_24GHZ_CHANNELS (IEEE80211_24GHZ_MAX_CHANNEL - \
- IEEE80211_24GHZ_MIN_CHANNEL + 1)
-
-#define IEEE80211_52GHZ_MIN_CHANNEL 34
-#define IEEE80211_52GHZ_MAX_CHANNEL 165
-#define IEEE80211_52GHZ_CHANNELS (IEEE80211_52GHZ_MAX_CHANNEL - \
- IEEE80211_52GHZ_MIN_CHANNEL + 1)
-
-
-
-typedef struct tx_pending_t{
- int frag;
- struct ieee80211_txb *txb;
-} tx_pending_t;
-
-typedef struct _bandwidth_autoswitch {
- long threshold_20Mhzto40Mhz;
- long threshold_40Mhzto20Mhz;
- bool bforced_tx20Mhz;
- bool bautoswitch_enable;
-} bandwidth_autoswitch, *pbandwidth_autoswitch;
-
-
-
-#define REORDER_WIN_SIZE 128
-#define REORDER_ENTRY_NUM 128
-typedef struct _RX_REORDER_ENTRY {
- struct list_head List;
- u16 SeqNum;
- struct ieee80211_rxb *prxb;
-} RX_REORDER_ENTRY, *PRX_REORDER_ENTRY;
-
-typedef enum _Fsync_State {
- Default_Fsync,
- HW_Fsync,
- SW_Fsync
-} Fsync_State;
-
-/* Power save mode configured. */
-typedef enum _RT_PS_MODE {
- eActive, /* Active/Continuous access. */
- eMaxPs, /* Max power save mode. */
- eFastPs /* Fast power save mode. */
-} RT_PS_MODE;
-
-typedef enum _IPS_CALLBACK_FUNCION {
- IPS_CALLBACK_NONE = 0,
- IPS_CALLBACK_MGNT_LINK_REQUEST = 1,
- IPS_CALLBACK_JOIN_REQUEST = 2,
-} IPS_CALLBACK_FUNCION;
-
-typedef enum _RT_JOIN_ACTION {
- RT_JOIN_INFRA = 1,
- RT_JOIN_IBSS = 2,
- RT_START_IBSS = 3,
- RT_NO_ACTION = 4,
-} RT_JOIN_ACTION;
-
-typedef struct _IbssParms {
- u16 atimWin;
-} IbssParms, *PIbssParms;
-#define MAX_NUM_RATES 264 /* Max num of support rates element: 8, Max num of ext. support rate: 255. 061122, by rcnjko. */
-
-/* RF state. */
-typedef enum _RT_RF_POWER_STATE {
- eRfOn,
- eRfSleep,
- eRfOff
-} RT_RF_POWER_STATE;
-
-typedef struct _RT_POWER_SAVE_CONTROL {
-
- /* Inactive Power Save(IPS) : Disable RF when disconnected */
- bool bInactivePs;
- bool bIPSModeBackup;
- bool bSwRfProcessing;
- RT_RF_POWER_STATE eInactivePowerState;
- struct work_struct InactivePsWorkItem;
- struct timer_list InactivePsTimer;
-
- /* Return point for join action */
- IPS_CALLBACK_FUNCION ReturnPoint;
-
- /* Recored Parameters for rescheduled JoinRequest */
- bool bTmpBssDesc;
- RT_JOIN_ACTION tmpJoinAction;
- struct ieee80211_network tmpBssDesc;
-
- /* Recored Parameters for rescheduled MgntLinkRequest */
- bool bTmpScanOnly;
- bool bTmpActiveScan;
- bool bTmpFilterHiddenAP;
- bool bTmpUpdateParms;
- u8 tmpSsidBuf[33];
- OCTET_STRING tmpSsid2Scan;
- bool bTmpSsid2Scan;
- u8 tmpNetworkType;
- u8 tmpChannelNumber;
- u16 tmpBcnPeriod;
- u8 tmpDtimPeriod;
- u16 tmpmCap;
- OCTET_STRING tmpSuppRateSet;
- u8 tmpSuppRateBuf[MAX_NUM_RATES];
- bool bTmpSuppRate;
- IbssParms tmpIbpm;
- bool bTmpIbpm;
-
- /* Leisre Poswer Save : Disable RF if connected but traffic is not busy */
- bool bLeisurePs;
-
-} RT_POWER_SAVE_CONTROL, *PRT_POWER_SAVE_CONTROL;
-
-typedef u32 RT_RF_CHANGE_SOURCE;
-#define RF_CHANGE_BY_SW BIT31
-#define RF_CHANGE_BY_HW BIT30
-#define RF_CHANGE_BY_PS BIT29
-#define RF_CHANGE_BY_IPS BIT28
-#define RF_CHANGE_BY_INIT 0 /* Do not change the RFOff reason. */
-
-#ifdef ENABLE_DOT11D
-typedef enum {
- COUNTRY_CODE_FCC = 0,
- COUNTRY_CODE_IC = 1,
- COUNTRY_CODE_ETSI = 2,
- COUNTRY_CODE_SPAIN = 3,
- COUNTRY_CODE_FRANCE = 4,
- COUNTRY_CODE_MKK = 5,
- COUNTRY_CODE_MKK1 = 6,
- COUNTRY_CODE_ISRAEL = 7,
- COUNTRY_CODE_TELEC,
- COUNTRY_CODE_MIC,
- COUNTRY_CODE_GLOBAL_DOMAIN
-} country_code_type_t;
-#endif
-
-#define RT_MAX_LD_SLOT_NUM 10
-typedef struct _RT_LINK_DETECT_T {
-
- u32 NumRecvBcnInPeriod;
- u32 NumRecvDataInPeriod;
-
- u32 RxBcnNum[RT_MAX_LD_SLOT_NUM]; /* number of Rx beacon / CheckForHang_period to determine link status */
- u32 RxDataNum[RT_MAX_LD_SLOT_NUM]; /* number of Rx data / CheckForHang_period to determine link status */
- u16 SlotNum; /* number of CheckForHang period to determine link status */
- u16 SlotIndex;
-
- u32 NumTxOkInPeriod;
- u32 NumRxOkInPeriod;
- bool bBusyTraffic;
-} RT_LINK_DETECT_T, *PRT_LINK_DETECT_T;
-
-
-struct ieee80211_device {
- struct net_device *dev;
- struct ieee80211_security sec;
-
- /* hw security related */
- u8 hwsec_active; /* hw security active. */
- bool is_silent_reset;
- bool ieee_up;
- bool bSupportRemoteWakeUp;
- RT_PS_MODE dot11PowerSaveMode; /* Power save mode configured. */
- bool actscanning;
- bool beinretry;
- RT_RF_POWER_STATE eRFPowerState;
- RT_RF_CHANGE_SOURCE RfOffReason;
- bool is_set_key;
- /* 11n spec related I wonder if These info structure need to be moved out of ieee80211_device */
-
- /* 11n HT below */
- PRT_HIGH_THROUGHPUT pHTInfo;
- spinlock_t bw_spinlock;
-
- spinlock_t reorder_spinlock;
- /* for HT operation rate set. we use this one for HT data rate to
- * separate different descriptors
- * the way fill this is the same as in the IE
- */
- u8 Regdot11HTOperationalRateSet[16]; /* use RATR format */
- u8 dot11HTOperationalRateSet[16]; /* use RATR format */
- u8 RegHTSuppRateSet[16];
- u8 HTCurrentOperaRate;
- u8 HTHighestOperaRate;
- /* wb added for rate operation mode to firmware */
- u8 bTxDisableRateFallBack;
- u8 bTxUseDriverAssingedRate;
- atomic_t atm_chnlop;
- atomic_t atm_swbw;
-
- /* 802.11e and WMM Traffic Stream Info (TX) */
- struct list_head Tx_TS_Admit_List;
- struct list_head Tx_TS_Pending_List;
- struct list_head Tx_TS_Unused_List;
- TX_TS_RECORD TxTsRecord[TOTAL_TS_NUM];
- /* 802.11e and WMM Traffic Stream Info (RX) */
- struct list_head Rx_TS_Admit_List;
- struct list_head Rx_TS_Pending_List;
- struct list_head Rx_TS_Unused_List;
- RX_TS_RECORD RxTsRecord[TOTAL_TS_NUM];
- RX_REORDER_ENTRY RxReorderEntry[128];
- struct list_head RxReorder_Unused_List;
- /* Qos related. */
-/* PSTA_QOS pStaQos; */
- u8 ForcedPriority; /* Force per-packet priority 1~7. (default: 0, not to force it.) */
-
-
- /* Bookkeeping structures */
- struct net_device_stats stats;
- struct ieee80211_stats ieee_stats;
- struct ieee80211_softmac_stats softmac_stats;
-
- /* Probe / Beacon management */
- struct list_head network_free_list;
- struct list_head network_list;
- struct ieee80211_network *networks;
- int scans;
- int scan_age;
-
- int iw_mode; /* operating mode (IW_MODE_*) */
- struct iw_spy_data spy_data;
-
- spinlock_t lock;
- spinlock_t wpax_suitlist_lock;
-
- int tx_headroom; /* Set to size of any additional room needed at front
- * of allocated Tx SKBs */
- u32 config;
-
- /* WEP and other encryption related settings at the device level */
- int open_wep; /* Set to 1 to allow unencrypted frames */
- int auth_mode;
- int reset_on_keychange; /* Set to 1 if the HW needs to be reset on
- * WEP key changes */
-
- /* If the host performs {en,de}cryption, then set to 1 */
- int host_encrypt;
- int host_encrypt_msdu;
- int host_decrypt;
- /* host performs multicast decryption */
- int host_mc_decrypt;
-
- /* host should strip IV and ICV from protected frames */
- /* meaningful only when hardware decryption is being used */
- int host_strip_iv_icv;
-
- int host_open_frag;
- int host_build_iv;
- int ieee802_1x; /* is IEEE 802.1X used */
-
- /* WPA data */
- bool bHalfWirelessN24GMode;
- int wpa_enabled;
- int drop_unencrypted;
- int tkip_countermeasures;
- int privacy_invoked;
- size_t wpa_ie_len;
- u8 *wpa_ie;
- u8 ap_mac_addr[6];
- u16 pairwise_key_type;
- u16 group_key_type;
- struct list_head crypt_deinit_list;
- struct ieee80211_crypt_data *crypt[WEP_KEYS];
- int tx_keyidx; /* default TX key index (crypt[tx_keyidx]) */
- struct timer_list crypt_deinit_timer;
- int crypt_quiesced;
-
- int bcrx_sta_key; /* use individual keys to override default keys even
- * with RX of broad/multicast frames */
-
- /* Fragmentation structures */
- /* each streaming contain a entry */
- struct ieee80211_frag_entry frag_cache[17][IEEE80211_FRAG_CACHE_LEN];
- unsigned int frag_next_idx[17];
- u16 fts; /* Fragmentation Threshold */
-#define DEFAULT_RTS_THRESHOLD 2346U
-#define MIN_RTS_THRESHOLD 1
-#define MAX_RTS_THRESHOLD 2346U
- u16 rts; /* RTS threshold */
-
- /* Association info */
- u8 bssid[ETH_ALEN];
-
- /* This stores infos for the current network.
- * Either the network we are associated in INFRASTRUCTURE
- * or the network that we are creating in MASTER mode.
- * ad-hoc is a mixture ;-).
- * Note that in infrastructure mode, even when not associated,
- * fields bssid and essid may be valid (if wpa_set and essid_set
- * are true) as thy carry the value set by the user via iwconfig
- */
- struct ieee80211_network current_network;
-
- enum ieee80211_state state;
-
- int short_slot;
- int reg_mode;
- int mode; /* A, B, G */
- int modulation; /* CCK, OFDM */
- int freq_band; /* 2.4Ghz, 5.2Ghz, Mixed */
- int abg_true; /* ABG flag */
-
- /* used for forcing the ibss workqueue to terminate
- * without wait for the syncro scan to terminate
- */
- short sync_scan_hurryup;
-
- int perfect_rssi;
- int worst_rssi;
-
- u16 prev_seq_ctl; /* used to drop duplicate frames */
-
- /* map of allowed channels. 0 is dummy */
- /* FIXME: remeber to default to a basic channel plan depending of the PHY type */
-#ifdef ENABLE_DOT11D
- void *pDot11dInfo;
- bool bGlobalDomain;
-#else
- int channel_map[MAX_CHANNEL_NUMBER+1];
-#endif
- int rate; /* current rate */
- int basic_rate;
- /* FIXME: pleace callback, see if redundant with softmac_features */
- short active_scan;
-
- /* this contains flags for selectively enable softmac support */
- u16 softmac_features;
-
- /* if the sequence control field is not filled by HW */
- u16 seq_ctrl[5];
-
- /* association procedure transaction sequence number */
- u16 associate_seq;
-
- /* AID for RTXed association responses */
- u16 assoc_id;
-
- /* power save mode related*/
- short ps;
- short sta_sleep;
- int ps_timeout;
- int ps_period;
- struct tasklet_struct ps_task;
- u32 ps_th;
- u32 ps_tl;
-
- short raw_tx;
- /* used if IEEE_SOFTMAC_TX_QUEUE is set */
- short queue_stop;
- short scanning;
- short proto_started;
-
- struct semaphore wx_sem;
- struct semaphore scan_sem;
-
- spinlock_t mgmt_tx_lock;
- spinlock_t beacon_lock;
-
- short beacon_txing;
-
- short wap_set;
- short ssid_set;
-
- u8 wpax_type_set;
- u32 wpax_type_notify;
-
- /* QoS related flag */
- char init_wmmparam_flag;
- /* set on initialization */
- u8 qos_support;
-
- /* for discarding duplicated packets in IBSS */
- struct list_head ibss_mac_hash[IEEE_IBSS_MAC_HASH_SIZE];
-
- /* for discarding duplicated packets in BSS */
- u16 last_rxseq_num[17]; /* rx seq previous per-tid */
- u16 last_rxfrag_num[17];/* tx frag previous per-tid */
- unsigned long last_packet_time[17];
-
- /* for PS mode */
- unsigned long last_rx_ps_time;
-
- /* used if IEEE_SOFTMAC_SINGLE_QUEUE is set */
- struct sk_buff *mgmt_queue_ring[MGMT_QUEUE_NUM];
- int mgmt_queue_head;
- int mgmt_queue_tail;
-/* added for rtl819x */
-#define IEEE80211_QUEUE_LIMIT 128
- u8 AsocRetryCount;
- unsigned int hw_header;
- struct sk_buff_head skb_waitQ[MAX_QUEUE_SIZE];
- struct sk_buff_head skb_aggQ[MAX_QUEUE_SIZE];
- struct sk_buff_head skb_drv_aggQ[MAX_QUEUE_SIZE];
- u32 sta_edca_param[4];
- bool aggregation;
- /* Enable/Disable Rx immediate BA capability. */
- bool enable_rx_imm_BA;
- bool bibsscoordinator;
-
- /*+by amy for DM ,080515 */
- /* Dynamic Tx power for near/far range enable/Disable */
- bool bdynamic_txpower_enable;
-
- bool bCTSToSelfEnable;
- u8 CTSToSelfTH;
-
- u32 fsync_time_interval;
- u32 fsync_rate_bitmap;
- u8 fsync_rssi_threshold;
- bool bfsync_enable;
-
- u8 fsync_multiple_timeinterval; /* FsyncMultipleTimeInterval * FsyncTimeInterval */
- u32 fsync_firstdiff_ratethreshold; /* low threshold */
- u32 fsync_seconddiff_ratethreshold; /* decrease threshold */
- Fsync_State fsync_state;
- bool bis_any_nonbepkts;
- /* 20Mhz 40Mhz AutoSwitch Threshold */
- bandwidth_autoswitch bandwidth_auto_switch;
- /* for txpower tracking */
- bool FwRWRF;
-
- /* added by amy for AP roaming */
- RT_LINK_DETECT_T LinkDetectInfo;
- /* added by amy for ps */
- RT_POWER_SAVE_CONTROL PowerSaveControl;
- /* used if IEEE_SOFTMAC_TX_QUEUE is set */
- struct tx_pending_t tx_pending;
-
- /* used if IEEE_SOFTMAC_ASSOCIATE is set */
- struct timer_list associate_timer;
-
- /* used if IEEE_SOFTMAC_BEACONS is set */
- struct timer_list beacon_timer;
- struct work_struct associate_complete_wq;
- struct work_struct associate_procedure_wq;
- struct delayed_work softmac_scan_wq;
- struct delayed_work associate_retry_wq;
- struct delayed_work start_ibss_wq;
- struct work_struct wx_sync_scan_wq;
- struct workqueue_struct *wq;
- /* Qos related. Added by Annie, 2005-11-01. */
- /* STA_QOS StaQos; */
-
-
- /* Callback functions */
- void (*set_security)(struct net_device *dev,
- struct ieee80211_security *sec);
-
- /* Used to TX data frame by using txb structs.
- * this is not used if in the softmac_features
- * is set the flag IEEE_SOFTMAC_TX_QUEUE
- */
- int (*hard_start_xmit)(struct ieee80211_txb *txb,
- struct net_device *dev);
-
- int (*reset_port)(struct net_device *dev);
- int (*is_queue_full) (struct net_device *dev, int pri);
-
- int (*handle_management) (struct net_device *dev,
- struct ieee80211_network *network, u16 type);
- int (*is_qos_active) (struct net_device *dev, struct sk_buff *skb);
-
- /* Softmac-generated frames (mamagement) are TXed via this
- * callback if the flag IEEE_SOFTMAC_SINGLE_QUEUE is
- * not set. As some cards may have different HW queues that
- * one might want to use for data and management frames
- * the option to have two callbacks might be useful.
- * This fucntion can't sleep.
- */
- int (*softmac_hard_start_xmit)(struct sk_buff *skb,
- struct net_device *dev);
-
- /* used instead of hard_start_xmit (not softmac_hard_start_xmit)
- * if the IEEE_SOFTMAC_TX_QUEUE feature is used to TX data
- * frames. I the option IEEE_SOFTMAC_SINGLE_QUEUE is also set
- * then also management frames are sent via this callback.
- * This function can't sleep.
- */
- void (*softmac_data_hard_start_xmit)(struct sk_buff *skb,
- struct net_device *dev, int rate);
-
- /* stops the HW queue for DATA frames. Useful to avoid
- * waste time to TX data frame when we are reassociating
- * This function can sleep.
- */
- void (*data_hard_stop)(struct net_device *dev);
-
- /* OK this is complementar to data_poll_hard_stop */
- void (*data_hard_resume)(struct net_device *dev);
-
- /* ask to the driver to retune the radio .
- * This function can sleep. the driver should ensure
- * the radio has been swithced before return.
- */
- void (*set_chan)(struct net_device *dev, short ch);
-
- /* These are not used if the ieee stack takes care of
- * scanning (IEEE_SOFTMAC_SCAN feature set).
- * In this case only the set_chan is used.
- *
- * The syncro version is similar to the start_scan but
- * does not return until all channels has been scanned.
- * this is called in user context and should sleep,
- * it is called in a work_queue when swithcing to ad-hoc mode
- * or in behalf of iwlist scan when the card is associated
- * and root user ask for a scan.
- * the fucntion stop_scan should stop both the syncro and
- * background scanning and can sleep.
- * The fucntion start_scan should initiate the background
- * scanning and can't sleep.
- */
- void (*scan_syncro)(struct net_device *dev);
- void (*start_scan)(struct net_device *dev);
- void (*stop_scan)(struct net_device *dev);
-
- /* indicate the driver that the link state is changed
- * for example it may indicate the card is associated now.
- * Driver might be interested in this to apply RX filter
- * rules or simply light the LINK led
- */
- void (*link_change)(struct net_device *dev);
-
- /* these two function indicates to the HW when to start
- * and stop to send beacons. This is used when the
- * IEEE_SOFTMAC_BEACONS is not set. For now the
- * stop_send_bacons is NOT guaranteed to be called only
- * after start_send_beacons.
- */
- void (*start_send_beacons) (struct net_device *dev, u16 tx_rate);
- void (*stop_send_beacons) (struct net_device *dev);
-
- /* power save mode related */
- void (*sta_wake_up) (struct net_device *dev);
- void (*ps_request_tx_ack) (struct net_device *dev);
- void (*enter_sleep_state) (struct net_device *dev, u32 th, u32 tl);
- short (*ps_is_queue_empty) (struct net_device *dev);
- int (*handle_beacon) (struct net_device *dev, struct ieee80211_beacon *beacon, struct ieee80211_network *network);
- int (*handle_assoc_response) (struct net_device *dev, struct ieee80211_assoc_response_frame *resp, struct ieee80211_network *network);
-
-
- /* check whether Tx hw resouce available */
- short (*check_nic_enough_desc)(struct net_device *dev, int queue_index);
- /* added by wb for HT related */
- void (*SetBWModeHandler)(struct net_device *dev, HT_CHANNEL_WIDTH Bandwidth, HT_EXTCHNL_OFFSET Offset);
- bool (*GetNmodeSupportBySecCfg)(struct net_device *dev);
- void (*SetWirelessMode)(struct net_device *dev, u8 wireless_mode);
- bool (*GetHalfNmodeSupportByAPsHandler)(struct net_device *dev);
- void (*InitialGainHandler)(struct net_device *dev, u8 Operation);
-
- /* This must be the last item so that it points to the data
- * allocated beyond this structure by alloc_ieee80211 */
- u8 priv[0];
-};
-
-#define IEEE_A (1<<0)
-#define IEEE_B (1<<1)
-#define IEEE_G (1<<2)
-#define IEEE_N_24G (1<<4)
-#define IEEE_N_5G (1<<5)
-#define IEEE_MODE_MASK (IEEE_A|IEEE_B|IEEE_G)
-
-/* Generate a 802.11 header */
-
-/* Uses the channel change callback directly
- * instead of [start/stop] scan callbacks
- */
-#define IEEE_SOFTMAC_SCAN (1<<2)
-
-/* Perform authentication and association handshake */
-#define IEEE_SOFTMAC_ASSOCIATE (1<<3)
-
-/* Generate probe requests */
-#define IEEE_SOFTMAC_PROBERQ (1<<4)
-
-/* Generate respones to probe requests */
-#define IEEE_SOFTMAC_PROBERS (1<<5)
-
-/* The ieee802.11 stack will manages the netif queue
- * wake/stop for the driver, taking care of 802.11
- * fragmentation. See softmac.c for details. */
-#define IEEE_SOFTMAC_TX_QUEUE (1<<7)
-
-/* Uses only the softmac_data_hard_start_xmit
- * even for TX management frames.
- */
-#define IEEE_SOFTMAC_SINGLE_QUEUE (1<<8)
-
-/* Generate beacons. The stack will enqueue beacons
- * to the card
- */
-#define IEEE_SOFTMAC_BEACONS (1<<6)
-
-static inline void *ieee80211_priv(struct net_device *dev)
-{
- return ((struct ieee80211_device *)netdev_priv(dev))->priv;
-}
-
-extern inline int ieee80211_is_empty_essid(const char *essid, int essid_len)
-{
- /* Single white space is for Linksys APs */
- if (essid_len == 1 && essid[0] == ' ')
- return 1;
-
- /* Otherwise, if the entire essid is 0, we assume it is hidden */
- while (essid_len) {
- essid_len--;
- if (essid[essid_len] != '\0')
- return 0;
- }
-
- return 1;
-}
-
-extern inline int ieee80211_is_valid_mode(struct ieee80211_device *ieee, int mode)
-{
- /*
- * It is possible for both access points and our device to support
- * combinations of modes, so as long as there is one valid combination
- * of ap/device supported modes, then return success
- *
- */
- if ((mode & IEEE_A) &&
- (ieee->modulation & IEEE80211_OFDM_MODULATION) &&
- (ieee->freq_band & IEEE80211_52GHZ_BAND))
- return 1;
-
- if ((mode & IEEE_G) &&
- (ieee->modulation & IEEE80211_OFDM_MODULATION) &&
- (ieee->freq_band & IEEE80211_24GHZ_BAND))
- return 1;
-
- if ((mode & IEEE_B) &&
- (ieee->modulation & IEEE80211_CCK_MODULATION) &&
- (ieee->freq_band & IEEE80211_24GHZ_BAND))
- return 1;
-
- return 0;
-}
-
-extern inline int ieee80211_get_hdrlen(u16 fc)
-{
- int hdrlen = IEEE80211_3ADDR_LEN;
-
- switch (WLAN_FC_GET_TYPE(fc)) {
- case IEEE80211_FTYPE_DATA:
- if ((fc & IEEE80211_FCTL_FROMDS) && (fc & IEEE80211_FCTL_TODS))
- hdrlen = IEEE80211_4ADDR_LEN; /* Addr4 */
- if (IEEE80211_QOS_HAS_SEQ(fc))
- hdrlen += 2; /* QOS ctrl*/
- break;
- case IEEE80211_FTYPE_CTL:
- switch (WLAN_FC_GET_STYPE(fc)) {
- case IEEE80211_STYPE_CTS:
- case IEEE80211_STYPE_ACK:
- hdrlen = IEEE80211_1ADDR_LEN;
- break;
- default:
- hdrlen = IEEE80211_2ADDR_LEN;
- break;
- }
- break;
- }
-
- return hdrlen;
-}
-
-static inline u8 *ieee80211_get_payload(struct ieee80211_hdr *hdr)
-{
- switch (ieee80211_get_hdrlen(le16_to_cpu(hdr->frame_ctl))) {
- case IEEE80211_1ADDR_LEN:
- return ((struct ieee80211_hdr_1addr *)hdr)->payload;
- case IEEE80211_2ADDR_LEN:
- return ((struct ieee80211_hdr_2addr *)hdr)->payload;
- case IEEE80211_3ADDR_LEN:
- return ((struct ieee80211_hdr_3addr *)hdr)->payload;
- case IEEE80211_4ADDR_LEN:
- return ((struct ieee80211_hdr_4addr *)hdr)->payload;
- }
- return NULL;
-}
-
-static inline int ieee80211_is_ofdm_rate(u8 rate)
-{
- switch (rate & ~IEEE80211_BASIC_RATE_MASK) {
- case IEEE80211_OFDM_RATE_6MB:
- case IEEE80211_OFDM_RATE_9MB:
- case IEEE80211_OFDM_RATE_12MB:
- case IEEE80211_OFDM_RATE_18MB:
- case IEEE80211_OFDM_RATE_24MB:
- case IEEE80211_OFDM_RATE_36MB:
- case IEEE80211_OFDM_RATE_48MB:
- case IEEE80211_OFDM_RATE_54MB:
- return 1;
- }
- return 0;
-}
-
-static inline int ieee80211_is_cck_rate(u8 rate)
-{
- switch (rate & ~IEEE80211_BASIC_RATE_MASK) {
- case IEEE80211_CCK_RATE_1MB:
- case IEEE80211_CCK_RATE_2MB:
- case IEEE80211_CCK_RATE_5MB:
- case IEEE80211_CCK_RATE_11MB:
- return 1;
- }
- return 0;
-}
-
-
-/* ieee80211.c */
-extern void free_ieee80211(struct net_device *dev);
-extern struct net_device *alloc_ieee80211(int sizeof_priv);
-
-extern int ieee80211_set_encryption(struct ieee80211_device *ieee);
-
-/* ieee80211_tx.c */
-
-extern int ieee80211_encrypt_fragment(
- struct ieee80211_device *ieee,
- struct sk_buff *frag,
- int hdr_len);
-
-extern int ieee80211_xmit(struct sk_buff *skb,
- struct net_device *dev);
-extern void ieee80211_txb_free(struct ieee80211_txb *);
-
-
-/* ieee80211_rx.c */
-extern int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb,
- struct ieee80211_rx_stats *rx_stats);
-extern void ieee80211_rx_mgt(struct ieee80211_device *ieee,
- struct ieee80211_hdr_4addr *header,
- struct ieee80211_rx_stats *stats);
-
-/* ieee80211_wx.c */
-extern int ieee80211_wx_get_scan(struct ieee80211_device *ieee,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *key);
-extern int ieee80211_wx_set_encode(struct ieee80211_device *ieee,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *key);
-extern int ieee80211_wx_get_encode(struct ieee80211_device *ieee,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *key);
-#if WIRELESS_EXT >= 18
-extern int ieee80211_wx_get_encode_ext(struct ieee80211_device *ieee,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra);
-extern int ieee80211_wx_set_encode_ext(struct ieee80211_device *ieee,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra);
-extern int ieee80211_wx_set_auth(struct ieee80211_device *ieee,
- struct iw_request_info *info,
- struct iw_param *data, char *extra);
-extern int ieee80211_wx_set_mlme(struct ieee80211_device *ieee,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra);
-#endif
-extern int ieee80211_wx_set_gen_ie(struct ieee80211_device *ieee, u8 *ie, size_t len);
-
-/* ieee80211_softmac.c */
-extern short ieee80211_is_54g(struct ieee80211_network net);
-extern short ieee80211_is_shortslot(struct ieee80211_network net);
-extern int ieee80211_rx_frame_softmac(struct ieee80211_device *ieee, struct sk_buff *skb,
- struct ieee80211_rx_stats *rx_stats, u16 type,
- u16 stype);
-extern void ieee80211_softmac_new_net(struct ieee80211_device *ieee, struct ieee80211_network *net);
-
-void SendDisassociation(struct ieee80211_device *ieee, u8* asSta, u8 asRsn);
-extern void ieee80211_softmac_xmit(struct ieee80211_txb *txb, struct ieee80211_device *ieee);
-
-extern void ieee80211_stop_send_beacons(struct ieee80211_device *ieee);
-extern void notify_wx_assoc_event(struct ieee80211_device *ieee);
-extern void ieee80211_softmac_check_all_nets(struct ieee80211_device *ieee);
-extern void ieee80211_start_bss(struct ieee80211_device *ieee);
-extern void ieee80211_start_master_bss(struct ieee80211_device *ieee);
-extern void ieee80211_start_ibss(struct ieee80211_device *ieee);
-extern void ieee80211_softmac_init(struct ieee80211_device *ieee);
-extern void ieee80211_softmac_free(struct ieee80211_device *ieee);
-extern void ieee80211_associate_abort(struct ieee80211_device *ieee);
-extern void ieee80211_disassociate(struct ieee80211_device *ieee);
-extern void ieee80211_stop_scan(struct ieee80211_device *ieee);
-extern void ieee80211_start_scan_syncro(struct ieee80211_device *ieee);
-extern void ieee80211_check_all_nets(struct ieee80211_device *ieee);
-extern void ieee80211_start_protocol(struct ieee80211_device *ieee);
-extern void ieee80211_stop_protocol(struct ieee80211_device *ieee);
-extern void ieee80211_softmac_start_protocol(struct ieee80211_device *ieee);
-extern void ieee80211_softmac_stop_protocol(struct ieee80211_device *ieee);
-extern void ieee80211_reset_queue(struct ieee80211_device *ieee);
-extern void ieee80211_wake_queue(struct ieee80211_device *ieee);
-extern void ieee80211_stop_queue(struct ieee80211_device *ieee);
-extern struct sk_buff *ieee80211_get_beacon(struct ieee80211_device *ieee);
-extern void ieee80211_start_send_beacons(struct ieee80211_device *ieee);
-extern void ieee80211_stop_send_beacons(struct ieee80211_device *ieee);
-extern int ieee80211_wpa_supplicant_ioctl(struct ieee80211_device *ieee, struct iw_point *p);
-extern void notify_wx_assoc_event(struct ieee80211_device *ieee);
-extern void ieee80211_ps_tx_ack(struct ieee80211_device *ieee, short success);
-
-extern void softmac_mgmt_xmit(struct sk_buff *skb, struct ieee80211_device *ieee);
-
-/* ieee80211_crypt_ccmp&tkip&wep.c */
-extern void ieee80211_tkip_null(void);
-extern void ieee80211_wep_null(void);
-extern void ieee80211_ccmp_null(void);
-
-/* ieee80211_softmac_wx.c */
-
-extern int ieee80211_wx_get_wap(struct ieee80211_device *ieee,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *ext);
-
-extern int ieee80211_wx_set_wap(struct ieee80211_device *ieee,
- struct iw_request_info *info,
- union iwreq_data *awrq,
- char *extra);
-
-extern int ieee80211_wx_get_essid(struct ieee80211_device *ieee,
- struct iw_request_info *a,
- union iwreq_data *wrqu, char *b);
-
-extern int ieee80211_wx_set_rate(struct ieee80211_device *ieee,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra);
-
-extern int ieee80211_wx_get_rate(struct ieee80211_device *ieee,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra);
-
-extern int ieee80211_wx_set_mode(struct ieee80211_device *ieee, struct iw_request_info *a,
- union iwreq_data *wrqu, char *b);
-
-extern int ieee80211_wx_set_scan(struct ieee80211_device *ieee, struct iw_request_info *a,
- union iwreq_data *wrqu, char *b);
-
-extern int ieee80211_wx_set_essid(struct ieee80211_device *ieee,
- struct iw_request_info *a,
- union iwreq_data *wrqu, char *extra);
-
-extern int ieee80211_wx_get_mode(struct ieee80211_device *ieee, struct iw_request_info *a,
- union iwreq_data *wrqu, char *b);
-
-extern int ieee80211_wx_set_freq(struct ieee80211_device *ieee, struct iw_request_info *a,
- union iwreq_data *wrqu, char *b);
-
-extern int ieee80211_wx_get_freq(struct ieee80211_device *ieee, struct iw_request_info *a,
- union iwreq_data *wrqu, char *b);
-
-extern void ieee80211_wx_sync_scan_wq(struct work_struct *work);
-
-
-extern int ieee80211_wx_set_rawtx(struct ieee80211_device *ieee,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra);
-
-extern int ieee80211_wx_get_name(struct ieee80211_device *ieee,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra);
-
-extern int ieee80211_wx_set_power(struct ieee80211_device *ieee,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra);
-
-extern int ieee80211_wx_get_power(struct ieee80211_device *ieee,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra);
-
-extern int ieee80211_wx_set_rts(struct ieee80211_device *ieee,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra);
-
-extern int ieee80211_wx_get_rts(struct ieee80211_device *ieee,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra);
-/* HT */
-#define MAX_RECEIVE_BUFFER_SIZE 9100
-extern void HTDebugHTCapability(u8 *CapIE, u8 *TitleString);
-extern void HTDebugHTInfo(u8 *InfoIE, u8 *TitleString);
-
-void HTSetConnectBwMode(struct ieee80211_device *ieee, HT_CHANNEL_WIDTH Bandwidth, HT_EXTCHNL_OFFSET Offset);
-extern void HTUpdateDefaultSetting(struct ieee80211_device *ieee);
-extern void HTConstructCapabilityElement(struct ieee80211_device *ieee, u8 *posHTCap, u8 *len, u8 isEncrypt);
-extern void HTConstructInfoElement(struct ieee80211_device *ieee, u8 *posHTInfo, u8 *len, u8 isEncrypt);
-extern void HTConstructRT2RTAggElement(struct ieee80211_device *ieee, u8 *posRT2RTAgg, u8 *len);
-extern void HTOnAssocRsp(struct ieee80211_device *ieee);
-extern void HTInitializeHTInfo(struct ieee80211_device *ieee);
-extern void HTInitializeBssDesc(PBSS_HT pBssHT);
-extern void HTResetSelfAndSavePeerSetting(struct ieee80211_device *ieee, struct ieee80211_network *pNetwork);
-extern void HTUpdateSelfAndPeerSetting(struct ieee80211_device *ieee, struct ieee80211_network *pNetwork);
-extern u8 HTGetHighestMCSRate(struct ieee80211_device *ieee, u8 *pMCSRateSet, u8 *pMCSFilter);
-extern u8 MCS_FILTER_ALL[];
-extern u16 MCS_DATA_RATE[2][2][77] ;
-extern u8 HTCCheck(struct ieee80211_device *ieee, u8 *pFrame);
-extern void HTResetIOTSetting(PRT_HIGH_THROUGHPUT pHTInfo);
-extern bool IsHTHalfNmodeAPs(struct ieee80211_device *ieee);
-extern u16 HTHalfMcsToDataRate(struct ieee80211_device *ieee, u8 nMcsRate);
-extern u16 HTMcsToDataRate(struct ieee80211_device *ieee, u8 nMcsRate);
-extern u16 TxCountToDataRate(struct ieee80211_device *ieee, u8 nDataRate);
-/* function in BAPROC.c */
-extern int ieee80211_rx_ADDBAReq(struct ieee80211_device *ieee, struct sk_buff *skb);
-extern int ieee80211_rx_ADDBARsp(struct ieee80211_device *ieee, struct sk_buff *skb);
-extern int ieee80211_rx_DELBA(struct ieee80211_device *ieee, struct sk_buff *skb);
-extern void TsInitAddBA(struct ieee80211_device *ieee, PTX_TS_RECORD pTS, u8 Policy, u8 bOverwritePending);
-extern void TsInitDelBA(struct ieee80211_device *ieee, PTS_COMMON_INFO pTsCommonInfo, TR_SELECT TxRxSelect);
-extern void BaSetupTimeOut(unsigned long data);
-extern void TxBaInactTimeout(unsigned long data);
-extern void RxBaInactTimeout(unsigned long data);
-extern void ResetBaEntry(PBA_RECORD pBA);
-/* function in TS.c */
-extern bool GetTs(
- struct ieee80211_device *ieee,
- PTS_COMMON_INFO *ppTS,
- u8 *Addr,
- u8 TID,
- TR_SELECT TxRxSelect, /* Rx:1, Tx:0 */
- bool bAddNewTs
- );
-extern void TSInitialize(struct ieee80211_device *ieee);
-extern void TsStartAddBaProcess(struct ieee80211_device *ieee, PTX_TS_RECORD pTxTS);
-extern void RemovePeerTS(struct ieee80211_device *ieee, u8 *Addr);
-extern void RemoveAllTS(struct ieee80211_device *ieee);
-void ieee80211_softmac_scan_syncro(struct ieee80211_device *ieee);
-
-extern const long ieee80211_wlan_frequencies[];
-
-extern inline void ieee80211_increment_scans(struct ieee80211_device *ieee)
-{
- ieee->scans++;
-}
-
-extern inline int ieee80211_get_scans(struct ieee80211_device *ieee)
-{
- return ieee->scans;
-}
-
-static inline const char *escape_essid(const char *essid, u8 essid_len)
-{
- static char escaped[IW_ESSID_MAX_SIZE * 2 + 1];
- const char *s = essid;
- char *d = escaped;
-
- if (ieee80211_is_empty_essid(essid, essid_len)) {
- memcpy(escaped, "<hidden>", sizeof("<hidden>"));
- return escaped;
- }
-
- essid_len = min(essid_len, (u8)IW_ESSID_MAX_SIZE);
- while (essid_len--) {
- if (*s == '\0') {
- *d++ = '\\';
- *d++ = '0';
- s++;
- } else {
- *d++ = *s++;
- }
- }
- *d = '\0';
- return escaped;
-}
-
-/* For the function is more related to hardware setting, it's better to use the
- * ieee handler to refer to it.
- */
-extern short check_nic_enough_desc(struct net_device *dev, int queue_index);
-extern int ieee80211_data_xmit(struct sk_buff *skb, struct net_device *dev);
-extern int ieee80211_parse_info_param(struct ieee80211_device *ieee,
- struct ieee80211_info_element *info_element,
- u16 length,
- struct ieee80211_network *network,
- struct ieee80211_rx_stats *stats);
-
-void ieee80211_indicate_packets(struct ieee80211_device *ieee, struct ieee80211_rxb **prxbIndicateArray, u8 index);
-#define RT_ASOC_RETRY_LIMIT 5
-#endif /* IEEE80211_H */
diff --git a/drivers/staging/rtl8192u/ieee80211/ieee80211_wx.c b/drivers/staging/rtl8192u/ieee80211/ieee80211_wx.c
index fb78ed2876e..d6f55c290db 100644
--- a/drivers/staging/rtl8192u/ieee80211/ieee80211_wx.c
+++ b/drivers/staging/rtl8192u/ieee80211/ieee80211_wx.c
@@ -85,7 +85,7 @@ static inline char *rtl819x_translate_scan(struct ieee80211_device *ieee,
}
/* Add the protocol name */
iwe.cmd = SIOCGIWNAME;
- for(i=0; i<(sizeof(ieee80211_modes)/sizeof(ieee80211_modes[0])); i++) {
+ for(i=0; i<ARRAY_SIZE(ieee80211_modes); i++) {
if(network->mode&(1<<i)) {
sprintf(pname,ieee80211_modes[i].mode_string,ieee80211_modes[i].mode_size);
pname +=ieee80211_modes[i].mode_size;
diff --git a/drivers/staging/rtl8192u/r8192U.h b/drivers/staging/rtl8192u/r8192U.h
index 69a2721e850..6206f929a65 100644
--- a/drivers/staging/rtl8192u/r8192U.h
+++ b/drivers/staging/rtl8192u/r8192U.h
@@ -39,7 +39,7 @@
#include <linux/random.h>
#include <linux/version.h>
#include <asm/io.h>
-#include "ieee80211.h"
+#include "ieee80211/ieee80211.h"
#define RTL8192U
#define RTL819xU_MODULE_NAME "rtl819xU"
diff --git a/drivers/staging/rtl8192u/r8192U_core.c b/drivers/staging/rtl8192u/r8192U_core.c
index f38472c2e75..1ff7850cc1e 100644
--- a/drivers/staging/rtl8192u/r8192U_core.c
+++ b/drivers/staging/rtl8192u/r8192U_core.c
@@ -410,14 +410,12 @@ u16 read_nic_word(struct net_device *dev, int indx)
struct usb_device *udev = priv->udev;
status = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
- RTL8187_REQ_GET_REGS, RTL8187_REQT_READ,
- (indx&0xff)|0xff00, (indx>>8)&0x0f, &data, 2, HZ / 2);
+ RTL8187_REQ_GET_REGS, RTL8187_REQT_READ,
+ (indx&0xff)|0xff00, (indx>>8)&0x0f,
+ &data, 2, HZ / 2);
if (status < 0)
- {
printk("read_nic_word TimeOut! status:%d\n", status);
- }
-
return data;
}
@@ -431,13 +429,10 @@ u16 read_nic_word_E(struct net_device *dev, int indx)
status = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
RTL8187_REQ_GET_REGS, RTL8187_REQT_READ,
- indx|0xfe00, 0, &data, 2, HZ / 2);
+ indx|0xfe00, 0, &data, 2, HZ / 2);
if (status < 0)
- {
printk("read_nic_word TimeOut! status:%d\n", status);
- }
-
return data;
}
@@ -446,31 +441,29 @@ u32 read_nic_dword(struct net_device *dev, int indx)
{
u32 data;
int status;
-// int result;
+ /* int result; */
struct r8192_priv *priv = (struct r8192_priv *)ieee80211_priv(dev);
struct usb_device *udev = priv->udev;
status = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
- RTL8187_REQ_GET_REGS, RTL8187_REQT_READ,
- (indx&0xff)|0xff00, (indx>>8)&0x0f, &data, 4, HZ / 2);
-// if(0 != result) {
-// printk(KERN_WARNING "read size of data = %d\, date = %d\n", result, data);
-// }
+ RTL8187_REQ_GET_REGS, RTL8187_REQT_READ,
+ (indx&0xff)|0xff00, (indx>>8)&0x0f,
+ &data, 4, HZ / 2);
+ /* if(0 != result) {
+ * printk(KERN_WARNING "read size of data = %d\, date = %d\n",
+ * result, data);
+ * }
+ */
if (status < 0)
- {
printk("read_nic_dword TimeOut! status:%d\n", status);
- }
-
-
return data;
}
-
-//u8 read_phy_cck(struct net_device *dev, u8 adr);
-//u8 read_phy_ofdm(struct net_device *dev, u8 adr);
+/* u8 read_phy_cck(struct net_device *dev, u8 adr); */
+/* u8 read_phy_ofdm(struct net_device *dev, u8 adr); */
/* this might still called in what was the PHY rtl8185/rtl8192 common code
* plans are to possibilty turn it again in one common code...
*/
@@ -478,26 +471,22 @@ inline void force_pci_posting(struct net_device *dev)
{
}
-
static struct net_device_stats *rtl8192_stats(struct net_device *dev);
void rtl8192_commit(struct net_device *dev);
-//void rtl8192_restart(struct net_device *dev);
+/* void rtl8192_restart(struct net_device *dev); */
void rtl8192_restart(struct work_struct *work);
-//void rtl8192_rq_tx_ack(struct work_struct *work);
-
+/* void rtl8192_rq_tx_ack(struct work_struct *work); */
void watch_dog_timer_callback(unsigned long data);
/****************************************************************************
- -----------------------------PROCFS STUFF-------------------------
-*****************************************************************************/
-
-static struct proc_dir_entry *rtl8192_proc = NULL;
-
+ * -----------------------------PROCFS STUFF-------------------------
+*****************************************************************************
+ */
+static struct proc_dir_entry *rtl8192_proc;
-static int proc_get_stats_ap(char *page, char **start,
- off_t offset, int count,
- int *eof, void *data)
+static int proc_get_stats_ap(char *page, char **start, off_t offset, int count,
+ int *eof, void *data)
{
struct net_device *dev = data;
struct r8192_priv *priv = (struct r8192_priv *)ieee80211_priv(dev);
@@ -508,18 +497,12 @@ static int proc_get_stats_ap(char *page, char **start,
list_for_each_entry(target, &ieee->network_list, list) {
- len += snprintf(page + len, count - len,
- "%s ", target->ssid);
-
- if(target->wpa_ie_len>0 || target->rsn_ie_len>0){
- len += snprintf(page + len, count - len,
- "WPA\n");
- }
- else{
- len += snprintf(page + len, count - len,
- "non_WPA\n");
- }
+ len += snprintf(page + len, count - len, "%s ", target->ssid);
+ if (target->wpa_ie_len > 0 || target->rsn_ie_len > 0)
+ len += snprintf(page + len, count - len, "WPA\n");
+ else
+ len += snprintf(page + len, count - len, "non_WPA\n");
}
*eof = 1;
diff --git a/drivers/staging/rtl8192u/r8192U_wx.h b/drivers/staging/rtl8192u/r8192U_wx.h
index b2f7a571b1c..f4cf2801136 100644
--- a/drivers/staging/rtl8192u/r8192U_wx.h
+++ b/drivers/staging/rtl8192u/r8192U_wx.h
@@ -15,7 +15,7 @@
#ifndef R8180_WX_H
#define R8180_WX_H
//#include <linux/wireless.h>
-//#include "ieee80211.h"
+
extern struct iw_handler_def r8192_wx_handlers_def;
/* Enable the rtl819x_core.c to share this function, david 2008.9.22 */
extern struct iw_statistics *r8192_get_wireless_stats(struct net_device *dev);
diff --git a/drivers/staging/rtl8192u/r819xU_firmware.c b/drivers/staging/rtl8192u/r819xU_firmware.c
index 3cc2d571f9b..b136ee48828 100644
--- a/drivers/staging/rtl8192u/r819xU_firmware.c
+++ b/drivers/staging/rtl8192u/r819xU_firmware.c
@@ -11,7 +11,7 @@
* NDIS_STATUS_FAILURE - the following initialization process should be terminated
* NDIS_STATUS_SUCCESS - if firmware initialization process success
**************************************************************************************************/
-//#include "ieee80211.h"
+
#include "r8192U.h"
#include "r8192U_hw.h"
#include "r819xU_firmware_img.h"
diff --git a/drivers/staging/sep/sep_driver_api.h b/drivers/staging/sep/sep_driver_api.h
index 383543d97f9..7ef16da7c4e 100644
--- a/drivers/staging/sep/sep_driver_api.h
+++ b/drivers/staging/sep/sep_driver_api.h
@@ -65,7 +65,7 @@
/* free dynamic data aalocated during table creation */
#define SEP_IOCFREEDMATABLEDATA _IO(SEP_IOC_MAGIC_NUMBER , 7)
-/* get the static pool area addersses (physical and virtual) */
+/* get the static pool area addresses (physical and virtual) */
#define SEP_IOCGETSTATICPOOLADDR _IO(SEP_IOC_MAGIC_NUMBER , 8)
/* set flow id command */
diff --git a/drivers/staging/slicoss/slic.h b/drivers/staging/slicoss/slic.h
index eb3a619c6a9..beab400805a 100644
--- a/drivers/staging/slicoss/slic.h
+++ b/drivers/staging/slicoss/slic.h
@@ -168,17 +168,6 @@ struct slic_cmdqueue {
struct slic_spinlock lock;
};
-#ifdef STATUS_SUCCESS
-#undef STATUS_SUCCESS
-#endif
-
-#define STATUS_SUCCESS 0
-#define STATUS_PENDING 0
-#define STATUS_FAILURE -1
-#define STATUS_ERROR -2
-#define STATUS_NOT_SUPPORTED -3
-#define STATUS_BUFFER_TOO_SHORT -4
-
#define SLIC_MAX_CARDS 32
#define SLIC_MAX_PORTS 4 /* Max # of ports per card */
@@ -510,7 +499,6 @@ struct adapter {
struct slic_ifevents if_events;
struct slic_stats inicstats_prev;
struct slicnet_stats slic_stats;
- struct net_device_stats stats;
};
diff --git a/drivers/staging/slicoss/slicoss.c b/drivers/staging/slicoss/slicoss.c
index bebf0fd2af8..f8c4b127e83 100644
--- a/drivers/staging/slicoss/slicoss.c
+++ b/drivers/staging/slicoss/slicoss.c
@@ -97,66 +97,6 @@
#include "slichw.h"
#include "slic.h"
-static struct net_device_stats *slic_get_stats(struct net_device *dev);
-static int slic_entry_open(struct net_device *dev);
-static int slic_entry_halt(struct net_device *dev);
-static int slic_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
-static netdev_tx_t slic_xmit_start(struct sk_buff *skb, struct net_device *dev);
-static void slic_xmit_fail(struct adapter *adapter, struct sk_buff *skb,
- void *cmd, u32 skbtype, u32 status);
-static void slic_config_pci(struct pci_dev *pcidev);
-static struct sk_buff *slic_rcvqueue_getnext(struct adapter *adapter);
-static int slic_mac_set_address(struct net_device *dev, void *ptr);
-static void slic_link_event_handler(struct adapter *adapter);
-static void slic_upr_request_complete(struct adapter *adapter, u32 isr);
-static int slic_rspqueue_init(struct adapter *adapter);
-static void slic_rspqueue_free(struct adapter *adapter);
-static struct slic_rspbuf *slic_rspqueue_getnext(struct adapter *adapter);
-static int slic_cmdq_init(struct adapter *adapter);
-static void slic_cmdq_free(struct adapter *adapter);
-static void slic_cmdq_reset(struct adapter *adapter);
-static void slic_cmdq_addcmdpage(struct adapter *adapter, u32 *page);
-static void slic_cmdq_getdone(struct adapter *adapter);
-static void slic_cmdq_putdone_irq(struct adapter *adapter,
- struct slic_hostcmd *cmd);
-static struct slic_hostcmd *slic_cmdq_getfree(struct adapter *adapter);
-static int slic_rcvqueue_init(struct adapter *adapter);
-static int slic_rcvqueue_fill(struct adapter *adapter);
-static u32 slic_rcvqueue_reinsert(struct adapter *adapter, struct sk_buff *skb);
-static void slic_rcvqueue_free(struct adapter *adapter);
-static void slic_adapter_set_hwaddr(struct adapter *adapter);
-static int slic_card_init(struct sliccard *card, struct adapter *adapter);
-static void slic_intagg_set(struct adapter *adapter, u32 value);
-static int slic_card_download(struct adapter *adapter);
-static u32 slic_card_locate(struct adapter *adapter);
-static int slic_if_init(struct adapter *adapter);
-static int slic_adapter_allocresources(struct adapter *adapter);
-static void slic_adapter_freeresources(struct adapter *adapter);
-static void slic_link_config(struct adapter *adapter, u32 linkspeed,
- u32 linkduplex);
-static void slic_unmap_mmio_space(struct adapter *adapter);
-static void slic_card_cleanup(struct sliccard *card);
-static void slic_soft_reset(struct adapter *adapter);
-static bool slic_mac_filter(struct adapter *adapter,
- struct ether_header *ether_frame);
-static void slic_mac_address_config(struct adapter *adapter);
-static void slic_mac_config(struct adapter *adapter);
-static void slic_mcast_set_mask(struct adapter *adapter);
-static void slic_config_set(struct adapter *adapter, bool linkchange);
-static void slic_config_clear(struct adapter *adapter);
-static void slic_config_get(struct adapter *adapter, u32 config,
- u32 configh);
-static void slic_timer_load_check(ulong context);
-static void slic_assert_fail(void);
-static ushort slic_eeprom_cksum(char *m, int len);
-static void slic_upr_start(struct adapter *adapter);
-static void slic_link_upr_complete(struct adapter *adapter, u32 Isr);
-static int slic_upr_request(struct adapter *adapter, u32 upr_request,
- u32 upr_data, u32 upr_data_h, u32 upr_buffer,
- u32 upr_buffer_h);
-static void slic_mcast_set_list(struct net_device *dev);
-
-
static uint slic_first_init = 1;
static char *slic_banner = "Alacritech SLIC Technology(tm) Server "\
"and Storage Accelerator (Non-Accelerated)";
@@ -206,6 +146,17 @@ MODULE_DEVICE_TABLE(pci, slic_pci_tbl);
#undef ASSERT
#endif
+static void slic_assert_fail(void)
+{
+ u32 cpuid;
+ u32 curr_pid;
+ cpuid = smp_processor_id();
+ curr_pid = current->pid;
+
+ printk(KERN_ERR "%s CPU # %d ---- PID # %d\n",
+ __func__, cpuid, curr_pid);
+}
+
#ifndef ASSERT
#define ASSERT(a) do { \
if (!(a)) { \
@@ -241,13 +192,6 @@ MODULE_DEVICE_TABLE(pci, slic_pci_tbl);
_adapter->handle_lock.flags); \
}
-static void slic_debug_init(void);
-static void slic_debug_cleanup(void);
-static void slic_debug_adapter_create(struct adapter *adapter);
-static void slic_debug_adapter_destroy(struct adapter *adapter);
-static void slic_debug_card_create(struct sliccard *card);
-static void slic_debug_card_destroy(struct sliccard *card);
-
static inline void slic_reg32_write(void __iomem *reg, u32 value, bool flush)
{
writel(value, reg);
@@ -272,1016 +216,6 @@ static inline void slic_reg64_write(struct adapter *adapter, void __iomem *reg,
adapter->bit64reglock.flags);
}
-static void slic_init_driver(void)
-{
- if (slic_first_init) {
- slic_first_init = 0;
- spin_lock_init(&slic_global.driver_lock.lock);
- slic_debug_init();
- }
-}
-
-static void slic_init_adapter(struct net_device *netdev,
- struct pci_dev *pcidev,
- const struct pci_device_id *pci_tbl_entry,
- void __iomem *memaddr, int chip_idx)
-{
- ushort index;
- struct slic_handle *pslic_handle;
- struct adapter *adapter = netdev_priv(netdev);
-
-/* adapter->pcidev = pcidev;*/
- adapter->vendid = pci_tbl_entry->vendor;
- adapter->devid = pci_tbl_entry->device;
- adapter->subsysid = pci_tbl_entry->subdevice;
- adapter->busnumber = pcidev->bus->number;
- adapter->slotnumber = ((pcidev->devfn >> 3) & 0x1F);
- adapter->functionnumber = (pcidev->devfn & 0x7);
- adapter->memorylength = pci_resource_len(pcidev, 0);
- adapter->slic_regs = (__iomem struct slic_regs *)memaddr;
- adapter->irq = pcidev->irq;
-/* adapter->netdev = netdev;*/
- adapter->next_netdevice = head_netdevice;
- head_netdevice = netdev;
- adapter->chipid = chip_idx;
- adapter->port = 0; /*adapter->functionnumber;*/
- adapter->cardindex = adapter->port;
- adapter->memorybase = memaddr;
- spin_lock_init(&adapter->upr_lock.lock);
- spin_lock_init(&adapter->bit64reglock.lock);
- spin_lock_init(&adapter->adapter_lock.lock);
- spin_lock_init(&adapter->reset_lock.lock);
- spin_lock_init(&adapter->handle_lock.lock);
-
- adapter->card_size = 1;
- /*
- Initialize slic_handle array
- */
- ASSERT(SLIC_CMDQ_MAXCMDS <= 0xFFFF);
- /*
- Start with 1. 0 is an invalid host handle.
- */
- for (index = 1, pslic_handle = &adapter->slic_handles[1];
- index < SLIC_CMDQ_MAXCMDS; index++, pslic_handle++) {
-
- pslic_handle->token.handle_index = index;
- pslic_handle->type = SLIC_HANDLE_FREE;
- pslic_handle->next = adapter->pfree_slic_handles;
- adapter->pfree_slic_handles = pslic_handle;
- }
- adapter->pshmem = (struct slic_shmem *)
- pci_alloc_consistent(adapter->pcidev,
- sizeof(struct slic_shmem),
- &adapter->
- phys_shmem);
- ASSERT(adapter->pshmem);
-
- memset(adapter->pshmem, 0, sizeof(struct slic_shmem));
-
- return;
-}
-
-static const struct net_device_ops slic_netdev_ops = {
- .ndo_open = slic_entry_open,
- .ndo_stop = slic_entry_halt,
- .ndo_start_xmit = slic_xmit_start,
- .ndo_do_ioctl = slic_ioctl,
- .ndo_set_mac_address = slic_mac_set_address,
- .ndo_get_stats = slic_get_stats,
- .ndo_set_multicast_list = slic_mcast_set_list,
- .ndo_validate_addr = eth_validate_addr,
- .ndo_change_mtu = eth_change_mtu,
-};
-
-static int __devinit slic_entry_probe(struct pci_dev *pcidev,
- const struct pci_device_id *pci_tbl_entry)
-{
- static int cards_found;
- static int did_version;
- int err = -ENODEV;
- struct net_device *netdev;
- struct adapter *adapter;
- void __iomem *memmapped_ioaddr = NULL;
- u32 status = 0;
- ulong mmio_start = 0;
- ulong mmio_len = 0;
- struct sliccard *card = NULL;
- int pci_using_dac = 0;
-
- slic_global.dynamic_intagg = dynamic_intagg;
-
- err = pci_enable_device(pcidev);
-
- if (err)
- return err;
-
- if (slic_debug > 0 && did_version++ == 0) {
- printk(KERN_DEBUG "%s\n", slic_banner);
- printk(KERN_DEBUG "%s\n", slic_proc_version);
- }
-
- if (!pci_set_dma_mask(pcidev, DMA_BIT_MASK(64))) {
- pci_using_dac = 1;
- if (pci_set_consistent_dma_mask(pcidev, DMA_BIT_MASK(64))) {
- dev_err(&pcidev->dev, "unable to obtain 64-bit DMA for "
- "consistent allocations\n");
- goto err_out_disable_pci;
- }
- } else if (pci_set_dma_mask(pcidev, DMA_BIT_MASK(32))) {
- pci_using_dac = 0;
- pci_set_consistent_dma_mask(pcidev, DMA_BIT_MASK(32));
- } else {
- dev_err(&pcidev->dev, "no usable DMA configuration\n");
- goto err_out_disable_pci;
- }
-
- err = pci_request_regions(pcidev, DRV_NAME);
- if (err) {
- dev_err(&pcidev->dev, "can't obtain PCI resources\n");
- goto err_out_disable_pci;
- }
-
- pci_set_master(pcidev);
-
- netdev = alloc_etherdev(sizeof(struct adapter));
- if (!netdev) {
- err = -ENOMEM;
- goto err_out_exit_slic_probe;
- }
-
- SET_NETDEV_DEV(netdev, &pcidev->dev);
-
- pci_set_drvdata(pcidev, netdev);
- adapter = netdev_priv(netdev);
- adapter->netdev = netdev;
- adapter->pcidev = pcidev;
- if (pci_using_dac)
- netdev->features |= NETIF_F_HIGHDMA;
-
- mmio_start = pci_resource_start(pcidev, 0);
- mmio_len = pci_resource_len(pcidev, 0);
-
-
-/* memmapped_ioaddr = (u32)ioremap_nocache(mmio_start, mmio_len);*/
- memmapped_ioaddr = ioremap(mmio_start, mmio_len);
- if (!memmapped_ioaddr) {
- dev_err(&pcidev->dev, "cannot remap MMIO region %lx @ %lx\n",
- mmio_len, mmio_start);
- goto err_out_free_netdev;
- }
-
- slic_config_pci(pcidev);
-
- slic_init_driver();
-
- slic_init_adapter(netdev,
- pcidev, pci_tbl_entry, memmapped_ioaddr, cards_found);
-
- status = slic_card_locate(adapter);
- if (status) {
- dev_err(&pcidev->dev, "cannot locate card\n");
- goto err_out_free_mmio_region;
- }
-
- card = adapter->card;
-
- if (!adapter->allocated) {
- card->adapters_allocated++;
- adapter->allocated = 1;
- }
-
- status = slic_card_init(card, adapter);
-
- if (status != STATUS_SUCCESS) {
- card->state = CARD_FAIL;
- adapter->state = ADAPT_FAIL;
- adapter->linkstate = LINK_DOWN;
- dev_err(&pcidev->dev, "FAILED status[%x]\n", status);
- } else {
- slic_adapter_set_hwaddr(adapter);
- }
-
- netdev->base_addr = (unsigned long)adapter->memorybase;
- netdev->irq = adapter->irq;
- netdev->netdev_ops = &slic_netdev_ops;
-
- slic_debug_adapter_create(adapter);
-
- strcpy(netdev->name, "eth%d");
- err = register_netdev(netdev);
- if (err) {
- dev_err(&pcidev->dev, "Cannot register net device, aborting.\n");
- goto err_out_unmap;
- }
-
- cards_found++;
-
- return status;
-
-err_out_unmap:
- iounmap(memmapped_ioaddr);
-err_out_free_mmio_region:
- release_mem_region(mmio_start, mmio_len);
-err_out_free_netdev:
- free_netdev(netdev);
-err_out_exit_slic_probe:
- pci_release_regions(pcidev);
-err_out_disable_pci:
- pci_disable_device(pcidev);
- return err;
-}
-
-static int slic_entry_open(struct net_device *dev)
-{
- struct adapter *adapter = netdev_priv(dev);
- struct sliccard *card = adapter->card;
- u32 locked = 0;
- int status;
-
- ASSERT(adapter);
- ASSERT(card);
-
- netif_stop_queue(adapter->netdev);
-
- spin_lock_irqsave(&slic_global.driver_lock.lock,
- slic_global.driver_lock.flags);
- locked = 1;
- if (!adapter->activated) {
- card->adapters_activated++;
- slic_global.num_slic_ports_active++;
- adapter->activated = 1;
- }
- status = slic_if_init(adapter);
-
- if (status != STATUS_SUCCESS) {
- if (adapter->activated) {
- card->adapters_activated--;
- slic_global.num_slic_ports_active--;
- adapter->activated = 0;
- }
- if (locked) {
- spin_unlock_irqrestore(&slic_global.driver_lock.lock,
- slic_global.driver_lock.flags);
- locked = 0;
- }
- return status;
- }
- if (!card->master)
- card->master = adapter;
-
- if (locked) {
- spin_unlock_irqrestore(&slic_global.driver_lock.lock,
- slic_global.driver_lock.flags);
- locked = 0;
- }
-
- return STATUS_SUCCESS;
-}
-
-static void __devexit slic_entry_remove(struct pci_dev *pcidev)
-{
- struct net_device *dev = pci_get_drvdata(pcidev);
- u32 mmio_start = 0;
- uint mmio_len = 0;
- struct adapter *adapter = netdev_priv(dev);
- struct sliccard *card;
- struct mcast_address *mcaddr, *mlist;
-
- ASSERT(adapter);
- slic_adapter_freeresources(adapter);
- slic_unmap_mmio_space(adapter);
- unregister_netdev(dev);
-
- mmio_start = pci_resource_start(pcidev, 0);
- mmio_len = pci_resource_len(pcidev, 0);
-
- release_mem_region(mmio_start, mmio_len);
-
- iounmap((void __iomem *)dev->base_addr);
- /* free multicast addresses */
- mlist = adapter->mcastaddrs;
- while (mlist) {
- mcaddr = mlist;
- mlist = mlist->next;
- kfree(mcaddr);
- }
- ASSERT(adapter->card);
- card = adapter->card;
- ASSERT(card->adapters_allocated);
- card->adapters_allocated--;
- adapter->allocated = 0;
- if (!card->adapters_allocated) {
- struct sliccard *curr_card = slic_global.slic_card;
- if (curr_card == card) {
- slic_global.slic_card = card->next;
- } else {
- while (curr_card->next != card)
- curr_card = curr_card->next;
- ASSERT(curr_card);
- curr_card->next = card->next;
- }
- ASSERT(slic_global.num_slic_cards);
- slic_global.num_slic_cards--;
- slic_card_cleanup(card);
- }
- kfree(dev);
- pci_release_regions(pcidev);
-}
-
-static int slic_entry_halt(struct net_device *dev)
-{
- struct adapter *adapter = netdev_priv(dev);
- struct sliccard *card = adapter->card;
- __iomem struct slic_regs *slic_regs = adapter->slic_regs;
-
- spin_lock_irqsave(&slic_global.driver_lock.lock,
- slic_global.driver_lock.flags);
- ASSERT(card);
- netif_stop_queue(adapter->netdev);
- adapter->state = ADAPT_DOWN;
- adapter->linkstate = LINK_DOWN;
- adapter->upr_list = NULL;
- adapter->upr_busy = 0;
- adapter->devflags_prev = 0;
- ASSERT(card->adapter[adapter->cardindex] == adapter);
- slic_reg32_write(&slic_regs->slic_icr, ICR_INT_OFF, FLUSH);
- adapter->all_reg_writes++;
- adapter->icr_reg_writes++;
- slic_config_clear(adapter);
- if (adapter->activated) {
- card->adapters_activated--;
- slic_global.num_slic_ports_active--;
- adapter->activated = 0;
- }
-#ifdef AUTOMATIC_RESET
- slic_reg32_write(&slic_regs->slic_reset_iface, 0, FLUSH);
-#endif
- /*
- * Reset the adapter's cmd queues
- */
- slic_cmdq_reset(adapter);
-
-#ifdef AUTOMATIC_RESET
- if (!card->adapters_activated)
- slic_card_init(card, adapter);
-#endif
-
- spin_unlock_irqrestore(&slic_global.driver_lock.lock,
- slic_global.driver_lock.flags);
- return STATUS_SUCCESS;
-}
-
-static int slic_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
-{
- struct adapter *adapter = netdev_priv(dev);
- struct ethtool_cmd edata;
- struct ethtool_cmd ecmd;
- u32 data[7];
- u32 intagg;
-
- ASSERT(rq);
- switch (cmd) {
- case SIOCSLICSETINTAGG:
- if (copy_from_user(data, rq->ifr_data, 28))
- return -EFAULT;
- intagg = data[0];
- dev_err(&dev->dev, "%s: set interrupt aggregation to %d\n",
- __func__, intagg);
- slic_intagg_set(adapter, intagg);
- return 0;
-
-#ifdef SLIC_TRACE_DUMP_ENABLED
- case SIOCSLICTRACEDUMP:
- {
- u32 value;
- DBG_IOCTL("slic_ioctl SIOCSLIC_TRACE_DUMP\n");
-
- if (copy_from_user(data, rq->ifr_data, 28)) {
- PRINT_ERROR
- ("slic: copy_from_user FAILED getting initial simba param\n");
- return -EFAULT;
- }
-
- value = data[0];
- if (tracemon_request == SLIC_DUMP_DONE) {
- PRINT_ERROR
- ("ATK Diagnostic Trace Dump Requested\n");
- tracemon_request = SLIC_DUMP_REQUESTED;
- tracemon_request_type = value;
- tracemon_timestamp = jiffies;
- } else if ((tracemon_request == SLIC_DUMP_REQUESTED) ||
- (tracemon_request ==
- SLIC_DUMP_IN_PROGRESS)) {
- PRINT_ERROR
- ("ATK Diagnostic Trace Dump Requested but already in progress... ignore\n");
- } else {
- PRINT_ERROR
- ("ATK Diagnostic Trace Dump Requested\n");
- tracemon_request = SLIC_DUMP_REQUESTED;
- tracemon_request_type = value;
- tracemon_timestamp = jiffies;
- }
- return 0;
- }
-#endif
- case SIOCETHTOOL:
- ASSERT(adapter);
- if (copy_from_user(&ecmd, rq->ifr_data, sizeof(ecmd)))
- return -EFAULT;
-
- if (ecmd.cmd == ETHTOOL_GSET) {
- edata.supported = (SUPPORTED_10baseT_Half |
- SUPPORTED_10baseT_Full |
- SUPPORTED_100baseT_Half |
- SUPPORTED_100baseT_Full |
- SUPPORTED_Autoneg | SUPPORTED_MII);
- edata.port = PORT_MII;
- edata.transceiver = XCVR_INTERNAL;
- edata.phy_address = 0;
- if (adapter->linkspeed == LINK_100MB)
- edata.speed = SPEED_100;
- else if (adapter->linkspeed == LINK_10MB)
- edata.speed = SPEED_10;
- else
- edata.speed = 0;
-
- if (adapter->linkduplex == LINK_FULLD)
- edata.duplex = DUPLEX_FULL;
- else
- edata.duplex = DUPLEX_HALF;
-
- edata.autoneg = AUTONEG_ENABLE;
- edata.maxtxpkt = 1;
- edata.maxrxpkt = 1;
- if (copy_to_user(rq->ifr_data, &edata, sizeof(edata)))
- return -EFAULT;
-
- } else if (ecmd.cmd == ETHTOOL_SSET) {
- if (!capable(CAP_NET_ADMIN))
- return -EPERM;
-
- if (adapter->linkspeed == LINK_100MB)
- edata.speed = SPEED_100;
- else if (adapter->linkspeed == LINK_10MB)
- edata.speed = SPEED_10;
- else
- edata.speed = 0;
-
- if (adapter->linkduplex == LINK_FULLD)
- edata.duplex = DUPLEX_FULL;
- else
- edata.duplex = DUPLEX_HALF;
-
- edata.autoneg = AUTONEG_ENABLE;
- edata.maxtxpkt = 1;
- edata.maxrxpkt = 1;
- if ((ecmd.speed != edata.speed) ||
- (ecmd.duplex != edata.duplex)) {
- u32 speed;
- u32 duplex;
-
- if (ecmd.speed == SPEED_10)
- speed = 0;
- else
- speed = PCR_SPEED_100;
- if (ecmd.duplex == DUPLEX_FULL)
- duplex = PCR_DUPLEX_FULL;
- else
- duplex = 0;
- slic_link_config(adapter, speed, duplex);
- slic_link_event_handler(adapter);
- }
- }
- return 0;
- default:
- return -EOPNOTSUPP;
- }
-}
-
-#define XMIT_FAIL_LINK_STATE 1
-#define XMIT_FAIL_ZERO_LENGTH 2
-#define XMIT_FAIL_HOSTCMD_FAIL 3
-
-static void slic_xmit_build_request(struct adapter *adapter,
- struct slic_hostcmd *hcmd, struct sk_buff *skb)
-{
- struct slic_host64_cmd *ihcmd;
- ulong phys_addr;
-
- ihcmd = &hcmd->cmd64;
-
- ihcmd->flags = (adapter->port << IHFLG_IFSHFT);
- ihcmd->command = IHCMD_XMT_REQ;
- ihcmd->u.slic_buffers.totlen = skb->len;
- phys_addr = pci_map_single(adapter->pcidev, skb->data, skb->len,
- PCI_DMA_TODEVICE);
- ihcmd->u.slic_buffers.bufs[0].paddrl = SLIC_GET_ADDR_LOW(phys_addr);
- ihcmd->u.slic_buffers.bufs[0].paddrh = SLIC_GET_ADDR_HIGH(phys_addr);
- ihcmd->u.slic_buffers.bufs[0].length = skb->len;
-#if defined(CONFIG_X86_64)
- hcmd->cmdsize = (u32) ((((u64)&ihcmd->u.slic_buffers.bufs[1] -
- (u64) hcmd) + 31) >> 5);
-#elif defined(CONFIG_X86)
- hcmd->cmdsize = ((((u32) &ihcmd->u.slic_buffers.bufs[1] -
- (u32) hcmd) + 31) >> 5);
-#else
- Stop Compilation;
-#endif
-}
-
-#define NORMAL_ETHFRAME 0
-
-static netdev_tx_t slic_xmit_start(struct sk_buff *skb, struct net_device *dev)
-{
- struct sliccard *card;
- struct adapter *adapter = netdev_priv(dev);
- struct slic_hostcmd *hcmd = NULL;
- u32 status = 0;
- u32 skbtype = NORMAL_ETHFRAME;
- void *offloadcmd = NULL;
-
- card = adapter->card;
- ASSERT(card);
- if ((adapter->linkstate != LINK_UP) ||
- (adapter->state != ADAPT_UP) || (card->state != CARD_UP)) {
- status = XMIT_FAIL_LINK_STATE;
- goto xmit_fail;
-
- } else if (skb->len == 0) {
- status = XMIT_FAIL_ZERO_LENGTH;
- goto xmit_fail;
- }
-
- if (skbtype == NORMAL_ETHFRAME) {
- hcmd = slic_cmdq_getfree(adapter);
- if (!hcmd) {
- adapter->xmitq_full = 1;
- status = XMIT_FAIL_HOSTCMD_FAIL;
- goto xmit_fail;
- }
- ASSERT(hcmd->pslic_handle);
- ASSERT(hcmd->cmd64.hosthandle ==
- hcmd->pslic_handle->token.handle_token);
- hcmd->skb = skb;
- hcmd->busy = 1;
- hcmd->type = SLIC_CMD_DUMB;
- if (skbtype == NORMAL_ETHFRAME)
- slic_xmit_build_request(adapter, hcmd, skb);
- }
- adapter->stats.tx_packets++;
- adapter->stats.tx_bytes += skb->len;
-
-#ifdef DEBUG_DUMP
- if (adapter->kill_card) {
- struct slic_host64_cmd ihcmd;
-
- ihcmd = &hcmd->cmd64;
-
- ihcmd->flags |= 0x40;
- adapter->kill_card = 0; /* only do this once */
- }
-#endif
- if (hcmd->paddrh == 0) {
- slic_reg32_write(&adapter->slic_regs->slic_cbar,
- (hcmd->paddrl | hcmd->cmdsize), DONT_FLUSH);
- } else {
- slic_reg64_write(adapter, &adapter->slic_regs->slic_cbar64,
- (hcmd->paddrl | hcmd->cmdsize),
- &adapter->slic_regs->slic_addr_upper,
- hcmd->paddrh, DONT_FLUSH);
- }
-xmit_done:
- return NETDEV_TX_OK;
-xmit_fail:
- slic_xmit_fail(adapter, skb, offloadcmd, skbtype, status);
- goto xmit_done;
-}
-
-static void slic_xmit_fail(struct adapter *adapter,
- struct sk_buff *skb,
- void *cmd, u32 skbtype, u32 status)
-{
- if (adapter->xmitq_full)
- netif_stop_queue(adapter->netdev);
- if ((cmd == NULL) && (status <= XMIT_FAIL_HOSTCMD_FAIL)) {
- switch (status) {
- case XMIT_FAIL_LINK_STATE:
- dev_err(&adapter->netdev->dev,
- "reject xmit skb[%p: %x] linkstate[%s] "
- "adapter[%s:%d] card[%s:%d]\n",
- skb, skb->pkt_type,
- SLIC_LINKSTATE(adapter->linkstate),
- SLIC_ADAPTER_STATE(adapter->state),
- adapter->state,
- SLIC_CARD_STATE(adapter->card->state),
- adapter->card->state);
- break;
- case XMIT_FAIL_ZERO_LENGTH:
- dev_err(&adapter->netdev->dev,
- "xmit_start skb->len == 0 skb[%p] type[%x]\n",
- skb, skb->pkt_type);
- break;
- case XMIT_FAIL_HOSTCMD_FAIL:
- dev_err(&adapter->netdev->dev,
- "xmit_start skb[%p] type[%x] No host commands "
- "available\n", skb, skb->pkt_type);
- break;
- default:
- ASSERT(0);
- }
- }
- dev_kfree_skb(skb);
- adapter->stats.tx_dropped++;
-}
-
-static void slic_rcv_handle_error(struct adapter *adapter,
- struct slic_rcvbuf *rcvbuf)
-{
- struct slic_hddr_wds *hdr = (struct slic_hddr_wds *)rcvbuf->data;
-
- if (adapter->devid != SLIC_1GB_DEVICE_ID) {
- if (hdr->frame_status14 & VRHSTAT_802OE)
- adapter->if_events.oflow802++;
- if (hdr->frame_status14 & VRHSTAT_TPOFLO)
- adapter->if_events.Tprtoflow++;
- if (hdr->frame_status_b14 & VRHSTATB_802UE)
- adapter->if_events.uflow802++;
- if (hdr->frame_status_b14 & VRHSTATB_RCVE) {
- adapter->if_events.rcvearly++;
- adapter->stats.rx_fifo_errors++;
- }
- if (hdr->frame_status_b14 & VRHSTATB_BUFF) {
- adapter->if_events.Bufov++;
- adapter->stats.rx_over_errors++;
- }
- if (hdr->frame_status_b14 & VRHSTATB_CARRE) {
- adapter->if_events.Carre++;
- adapter->stats.tx_carrier_errors++;
- }
- if (hdr->frame_status_b14 & VRHSTATB_LONGE)
- adapter->if_events.Longe++;
- if (hdr->frame_status_b14 & VRHSTATB_PREA)
- adapter->if_events.Invp++;
- if (hdr->frame_status_b14 & VRHSTATB_CRC) {
- adapter->if_events.Crc++;
- adapter->stats.rx_crc_errors++;
- }
- if (hdr->frame_status_b14 & VRHSTATB_DRBL)
- adapter->if_events.Drbl++;
- if (hdr->frame_status_b14 & VRHSTATB_CODE)
- adapter->if_events.Code++;
- if (hdr->frame_status_b14 & VRHSTATB_TPCSUM)
- adapter->if_events.TpCsum++;
- if (hdr->frame_status_b14 & VRHSTATB_TPHLEN)
- adapter->if_events.TpHlen++;
- if (hdr->frame_status_b14 & VRHSTATB_IPCSUM)
- adapter->if_events.IpCsum++;
- if (hdr->frame_status_b14 & VRHSTATB_IPLERR)
- adapter->if_events.IpLen++;
- if (hdr->frame_status_b14 & VRHSTATB_IPHERR)
- adapter->if_events.IpHlen++;
- } else {
- if (hdr->frame_statusGB & VGBSTAT_XPERR) {
- u32 xerr = hdr->frame_statusGB >> VGBSTAT_XERRSHFT;
-
- if (xerr == VGBSTAT_XCSERR)
- adapter->if_events.TpCsum++;
- if (xerr == VGBSTAT_XUFLOW)
- adapter->if_events.Tprtoflow++;
- if (xerr == VGBSTAT_XHLEN)
- adapter->if_events.TpHlen++;
- }
- if (hdr->frame_statusGB & VGBSTAT_NETERR) {
- u32 nerr =
- (hdr->
- frame_statusGB >> VGBSTAT_NERRSHFT) &
- VGBSTAT_NERRMSK;
- if (nerr == VGBSTAT_NCSERR)
- adapter->if_events.IpCsum++;
- if (nerr == VGBSTAT_NUFLOW)
- adapter->if_events.IpLen++;
- if (nerr == VGBSTAT_NHLEN)
- adapter->if_events.IpHlen++;
- }
- if (hdr->frame_statusGB & VGBSTAT_LNKERR) {
- u32 lerr = hdr->frame_statusGB & VGBSTAT_LERRMSK;
-
- if (lerr == VGBSTAT_LDEARLY)
- adapter->if_events.rcvearly++;
- if (lerr == VGBSTAT_LBOFLO)
- adapter->if_events.Bufov++;
- if (lerr == VGBSTAT_LCODERR)
- adapter->if_events.Code++;
- if (lerr == VGBSTAT_LDBLNBL)
- adapter->if_events.Drbl++;
- if (lerr == VGBSTAT_LCRCERR)
- adapter->if_events.Crc++;
- if (lerr == VGBSTAT_LOFLO)
- adapter->if_events.oflow802++;
- if (lerr == VGBSTAT_LUFLO)
- adapter->if_events.uflow802++;
- }
- }
- return;
-}
-
-#define TCP_OFFLOAD_FRAME_PUSHFLAG 0x10000000
-#define M_FAST_PATH 0x0040
-
-static void slic_rcv_handler(struct adapter *adapter)
-{
- struct sk_buff *skb;
- struct slic_rcvbuf *rcvbuf;
- u32 frames = 0;
-
- while ((skb = slic_rcvqueue_getnext(adapter))) {
- u32 rx_bytes;
-
- ASSERT(skb->head);
- rcvbuf = (struct slic_rcvbuf *)skb->head;
- adapter->card->events++;
- if (rcvbuf->status & IRHDDR_ERR) {
- adapter->rx_errors++;
- slic_rcv_handle_error(adapter, rcvbuf);
- slic_rcvqueue_reinsert(adapter, skb);
- continue;
- }
-
- if (!slic_mac_filter(adapter, (struct ether_header *)
- rcvbuf->data)) {
- slic_rcvqueue_reinsert(adapter, skb);
- continue;
- }
- skb_pull(skb, SLIC_RCVBUF_HEADSIZE);
- rx_bytes = (rcvbuf->length & IRHDDR_FLEN_MSK);
- skb_put(skb, rx_bytes);
- adapter->stats.rx_packets++;
- adapter->stats.rx_bytes += rx_bytes;
-#if SLIC_OFFLOAD_IP_CHECKSUM
- skb->ip_summed = CHECKSUM_UNNECESSARY;
-#endif
-
- skb->dev = adapter->netdev;
- skb->protocol = eth_type_trans(skb, skb->dev);
- netif_rx(skb);
-
- ++frames;
-#if SLIC_INTERRUPT_PROCESS_LIMIT
- if (frames >= SLIC_RCVQ_MAX_PROCESS_ISR) {
- adapter->rcv_interrupt_yields++;
- break;
- }
-#endif
- }
- adapter->max_isr_rcvs = max(adapter->max_isr_rcvs, frames);
-}
-
-static void slic_xmit_complete(struct adapter *adapter)
-{
- struct slic_hostcmd *hcmd;
- struct slic_rspbuf *rspbuf;
- u32 frames = 0;
- struct slic_handle_word slic_handle_word;
-
- do {
- rspbuf = slic_rspqueue_getnext(adapter);
- if (!rspbuf)
- break;
- adapter->xmit_completes++;
- adapter->card->events++;
- /*
- Get the complete host command buffer
- */
- slic_handle_word.handle_token = rspbuf->hosthandle;
- ASSERT(slic_handle_word.handle_index);
- ASSERT(slic_handle_word.handle_index <= SLIC_CMDQ_MAXCMDS);
- hcmd =
- (struct slic_hostcmd *)
- adapter->slic_handles[slic_handle_word.handle_index].
- address;
-/* hcmd = (struct slic_hostcmd *) rspbuf->hosthandle; */
- ASSERT(hcmd);
- ASSERT(hcmd->pslic_handle ==
- &adapter->slic_handles[slic_handle_word.handle_index]);
- if (hcmd->type == SLIC_CMD_DUMB) {
- if (hcmd->skb)
- dev_kfree_skb_irq(hcmd->skb);
- slic_cmdq_putdone_irq(adapter, hcmd);
- }
- rspbuf->status = 0;
- rspbuf->hosthandle = 0;
- frames++;
- } while (1);
- adapter->max_isr_xmits = max(adapter->max_isr_xmits, frames);
-}
-
-static irqreturn_t slic_interrupt(int irq, void *dev_id)
-{
- struct net_device *dev = (struct net_device *)dev_id;
- struct adapter *adapter = netdev_priv(dev);
- u32 isr;
-
- if ((adapter->pshmem) && (adapter->pshmem->isr)) {
- slic_reg32_write(&adapter->slic_regs->slic_icr,
- ICR_INT_MASK, FLUSH);
- isr = adapter->isrcopy = adapter->pshmem->isr;
- adapter->pshmem->isr = 0;
- adapter->num_isrs++;
- switch (adapter->card->state) {
- case CARD_UP:
- if (isr & ~ISR_IO) {
- if (isr & ISR_ERR) {
- adapter->error_interrupts++;
- if (isr & ISR_RMISS) {
- int count;
- int pre_count;
- int errors;
-
- struct slic_rcvqueue *rcvq =
- &adapter->rcvqueue;
-
- adapter->
- error_rmiss_interrupts++;
- if (!rcvq->errors)
- rcv_count = rcvq->count;
- pre_count = rcvq->count;
- errors = rcvq->errors;
-
- while (rcvq->count <
- SLIC_RCVQ_FILLTHRESH) {
- count =
- slic_rcvqueue_fill
- (adapter);
- if (!count)
- break;
- }
- } else if (isr & ISR_XDROP) {
- dev_err(&dev->dev,
- "isr & ISR_ERR [%x] "
- "ISR_XDROP \n", isr);
- } else {
- dev_err(&dev->dev,
- "isr & ISR_ERR [%x]\n",
- isr);
- }
- }
-
- if (isr & ISR_LEVENT) {
- adapter->linkevent_interrupts++;
- slic_link_event_handler(adapter);
- }
-
- if ((isr & ISR_UPC) ||
- (isr & ISR_UPCERR) || (isr & ISR_UPCBSY)) {
- adapter->upr_interrupts++;
- slic_upr_request_complete(adapter, isr);
- }
- }
-
- if (isr & ISR_RCV) {
- adapter->rcv_interrupts++;
- slic_rcv_handler(adapter);
- }
-
- if (isr & ISR_CMD) {
- adapter->xmit_interrupts++;
- slic_xmit_complete(adapter);
- }
- break;
-
- case CARD_DOWN:
- if ((isr & ISR_UPC) ||
- (isr & ISR_UPCERR) || (isr & ISR_UPCBSY)) {
- adapter->upr_interrupts++;
- slic_upr_request_complete(adapter, isr);
- }
- break;
-
- default:
- break;
- }
-
- adapter->isrcopy = 0;
- adapter->all_reg_writes += 2;
- adapter->isr_reg_writes++;
- slic_reg32_write(&adapter->slic_regs->slic_isr, 0, FLUSH);
- } else {
- adapter->false_interrupts++;
- }
- return IRQ_HANDLED;
-}
-
-/*
- * slic_link_event_handler -
- *
- * Initiate a link configuration sequence. The link configuration begins
- * by issuing a READ_LINK_STATUS command to the Utility Processor on the
- * SLIC. Since the command finishes asynchronously, the slic_upr_comlete
- * routine will follow it up witha UP configuration write command, which
- * will also complete asynchronously.
- *
- */
-static void slic_link_event_handler(struct adapter *adapter)
-{
- int status;
- struct slic_shmem *pshmem;
-
- if (adapter->state != ADAPT_UP) {
- /* Adapter is not operational. Ignore. */
- return;
- }
-
- pshmem = (struct slic_shmem *)adapter->phys_shmem;
-
-#if defined(CONFIG_X86_64)
- status = slic_upr_request(adapter,
- SLIC_UPR_RLSR,
- SLIC_GET_ADDR_LOW(&pshmem->linkstatus),
- SLIC_GET_ADDR_HIGH(&pshmem->linkstatus),
- 0, 0);
-#elif defined(CONFIG_X86)
- status = slic_upr_request(adapter, SLIC_UPR_RLSR,
- (u32) &pshmem->linkstatus, /* no 4GB wrap guaranteed */
- 0, 0, 0);
-#else
- Stop compilation;
-#endif
- ASSERT((status == STATUS_SUCCESS) || (status == STATUS_PENDING));
-}
-
-static void slic_init_cleanup(struct adapter *adapter)
-{
- if (adapter->intrregistered) {
- adapter->intrregistered = 0;
- free_irq(adapter->netdev->irq, adapter->netdev);
-
- }
- if (adapter->pshmem) {
- pci_free_consistent(adapter->pcidev,
- sizeof(struct slic_shmem),
- adapter->pshmem, adapter->phys_shmem);
- adapter->pshmem = NULL;
- adapter->phys_shmem = (dma_addr_t) NULL;
- }
-
- if (adapter->pingtimerset) {
- adapter->pingtimerset = 0;
- del_timer(&adapter->pingtimer);
- }
-
- slic_rspqueue_free(adapter);
- slic_cmdq_free(adapter);
- slic_rcvqueue_free(adapter);
-}
-
-static struct net_device_stats *slic_get_stats(struct net_device *dev)
-{
- struct adapter *adapter = netdev_priv(dev);
-
- ASSERT(adapter);
- dev->stats.collisions = adapter->slic_stats.iface.xmit_collisions;
- dev->stats.rx_errors = adapter->slic_stats.iface.rcv_errors;
- dev->stats.tx_errors = adapter->slic_stats.iface.xmt_errors;
- dev->stats.rx_missed_errors = adapter->slic_stats.iface.rcv_discards;
- dev->stats.tx_heartbeat_errors = 0;
- dev->stats.tx_aborted_errors = 0;
- dev->stats.tx_window_errors = 0;
- dev->stats.tx_fifo_errors = 0;
- dev->stats.rx_frame_errors = 0;
- dev->stats.rx_length_errors = 0;
-
- return &dev->stats;
-}
-
-/*
- * Allocate a mcast_address structure to hold the multicast address.
- * Link it in.
- */
-static int slic_mcast_add_list(struct adapter *adapter, char *address)
-{
- struct mcast_address *mcaddr, *mlist;
-
- /* Check to see if it already exists */
- mlist = adapter->mcastaddrs;
- while (mlist) {
- if (!compare_ether_addr(mlist->address, address))
- return STATUS_SUCCESS;
- mlist = mlist->next;
- }
-
- /* Doesn't already exist. Allocate a structure to hold it */
- mcaddr = kmalloc(sizeof(struct mcast_address), GFP_ATOMIC);
- if (mcaddr == NULL)
- return 1;
-
- memcpy(mcaddr->address, address, 6);
-
- mcaddr->next = adapter->mcastaddrs;
- adapter->mcastaddrs = mcaddr;
-
- return STATUS_SUCCESS;
-}
-
/*
* Functions to obtain the CRC corresponding to the destination mac address.
* This is a standard ethernet CRC in that it is a 32-bit, reflected CRC using
@@ -1362,44 +296,6 @@ static void slic_mcast_set_bit(struct adapter *adapter, char *address)
adapter->mcastmask |= (u64) 1 << crcpoly;
}
-static void slic_mcast_set_list(struct net_device *dev)
-{
- struct adapter *adapter = netdev_priv(dev);
- int status = STATUS_SUCCESS;
- char *addresses;
- struct netdev_hw_addr *ha;
-
- ASSERT(adapter);
-
- netdev_for_each_mc_addr(ha, dev) {
- addresses = (char *) &ha->addr;
- status = slic_mcast_add_list(adapter, addresses);
- if (status != STATUS_SUCCESS)
- break;
- slic_mcast_set_bit(adapter, addresses);
- }
-
- if (adapter->devflags_prev != dev->flags) {
- adapter->macopts = MAC_DIRECTED;
- if (dev->flags) {
- if (dev->flags & IFF_BROADCAST)
- adapter->macopts |= MAC_BCAST;
- if (dev->flags & IFF_PROMISC)
- adapter->macopts |= MAC_PROMISC;
- if (dev->flags & IFF_ALLMULTI)
- adapter->macopts |= MAC_ALLMCAST;
- if (dev->flags & IFF_MULTICAST)
- adapter->macopts |= MAC_MCAST;
- }
- adapter->devflags_prev = dev->flags;
- slic_config_set(adapter, true);
- } else {
- if (status == STATUS_SUCCESS)
- slic_mcast_set_mask(adapter);
- }
- return;
-}
-
static void slic_mcast_set_mask(struct adapter *adapter)
{
__iomem struct slic_regs *slic_regs = adapter->slic_regs;
@@ -1439,123 +335,6 @@ static void slic_timer_ping(ulong dev)
add_timer(&adapter->pingtimer);
}
-/*
- * slic_if_init
- *
- * Perform initialization of our slic interface.
- *
- */
-static int slic_if_init(struct adapter *adapter)
-{
- struct sliccard *card = adapter->card;
- struct net_device *dev = adapter->netdev;
- __iomem struct slic_regs *slic_regs = adapter->slic_regs;
- struct slic_shmem *pshmem;
- int status = 0;
-
- ASSERT(card);
-
- /* adapter should be down at this point */
- if (adapter->state != ADAPT_DOWN) {
- dev_err(&dev->dev, "%s: adapter->state != ADAPT_DOWN\n",
- __func__);
- return -EIO;
- }
- ASSERT(adapter->linkstate == LINK_DOWN);
-
- adapter->devflags_prev = dev->flags;
- adapter->macopts = MAC_DIRECTED;
- if (dev->flags) {
- if (dev->flags & IFF_BROADCAST)
- adapter->macopts |= MAC_BCAST;
- if (dev->flags & IFF_PROMISC)
- adapter->macopts |= MAC_PROMISC;
- if (dev->flags & IFF_ALLMULTI)
- adapter->macopts |= MAC_ALLMCAST;
- if (dev->flags & IFF_MULTICAST)
- adapter->macopts |= MAC_MCAST;
- }
- status = slic_adapter_allocresources(adapter);
- if (status != STATUS_SUCCESS) {
- dev_err(&dev->dev,
- "%s: slic_adapter_allocresources FAILED %x\n",
- __func__, status);
- slic_adapter_freeresources(adapter);
- return status;
- }
-
- if (!adapter->queues_initialized) {
- if (slic_rspqueue_init(adapter))
- return -ENOMEM;
- if (slic_cmdq_init(adapter))
- return -ENOMEM;
- if (slic_rcvqueue_init(adapter))
- return -ENOMEM;
- adapter->queues_initialized = 1;
- }
-
- slic_reg32_write(&slic_regs->slic_icr, ICR_INT_OFF, FLUSH);
- mdelay(1);
-
- if (!adapter->isp_initialized) {
- pshmem = (struct slic_shmem *)adapter->phys_shmem;
-
- spin_lock_irqsave(&adapter->bit64reglock.lock,
- adapter->bit64reglock.flags);
-
-#if defined(CONFIG_X86_64)
- slic_reg32_write(&slic_regs->slic_addr_upper,
- SLIC_GET_ADDR_HIGH(&pshmem->isr), DONT_FLUSH);
- slic_reg32_write(&slic_regs->slic_isp,
- SLIC_GET_ADDR_LOW(&pshmem->isr), FLUSH);
-#elif defined(CONFIG_X86)
- slic_reg32_write(&slic_regs->slic_addr_upper, 0, DONT_FLUSH);
- slic_reg32_write(&slic_regs->slic_isp, (u32)&pshmem->isr, FLUSH);
-#else
- Stop Compilations
-#endif
- spin_unlock_irqrestore(&adapter->bit64reglock.lock,
- adapter->bit64reglock.flags);
- adapter->isp_initialized = 1;
- }
-
- adapter->state = ADAPT_UP;
- if (!card->loadtimerset) {
- init_timer(&card->loadtimer);
- card->loadtimer.expires =
- jiffies + (SLIC_LOADTIMER_PERIOD * HZ);
- card->loadtimer.data = (ulong) card;
- card->loadtimer.function = &slic_timer_load_check;
- add_timer(&card->loadtimer);
-
- card->loadtimerset = 1;
- }
-
- if (!adapter->pingtimerset) {
- init_timer(&adapter->pingtimer);
- adapter->pingtimer.expires =
- jiffies + (PING_TIMER_INTERVAL * HZ);
- adapter->pingtimer.data = (ulong) dev;
- adapter->pingtimer.function = &slic_timer_ping;
- add_timer(&adapter->pingtimer);
- adapter->pingtimerset = 1;
- adapter->card->pingstatus = ISR_PINGMASK;
- }
-
- /*
- * clear any pending events, then enable interrupts
- */
- adapter->isrcopy = 0;
- adapter->pshmem->isr = 0;
- slic_reg32_write(&slic_regs->slic_isr, 0, FLUSH);
- slic_reg32_write(&slic_regs->slic_icr, ICR_INT_ON, FLUSH);
-
- slic_link_config(adapter, LINK_AUTOSPEED, LINK_AUTOD);
- slic_link_event_handler(adapter);
-
- return STATUS_SUCCESS;
-}
-
static void slic_unmap_mmio_space(struct adapter *adapter)
{
if (adapter->slic_regs)
@@ -1563,64 +342,6 @@ static void slic_unmap_mmio_space(struct adapter *adapter)
adapter->slic_regs = NULL;
}
-static int slic_adapter_allocresources(struct adapter *adapter)
-{
- if (!adapter->intrregistered) {
- int retval;
-
- spin_unlock_irqrestore(&slic_global.driver_lock.lock,
- slic_global.driver_lock.flags);
-
- retval = request_irq(adapter->netdev->irq,
- &slic_interrupt,
- IRQF_SHARED,
- adapter->netdev->name, adapter->netdev);
-
- spin_lock_irqsave(&slic_global.driver_lock.lock,
- slic_global.driver_lock.flags);
-
- if (retval) {
- dev_err(&adapter->netdev->dev,
- "request_irq (%s) FAILED [%x]\n",
- adapter->netdev->name, retval);
- return retval;
- }
- adapter->intrregistered = 1;
- }
- return STATUS_SUCCESS;
-}
-
-static void slic_config_pci(struct pci_dev *pcidev)
-{
- u16 pci_command;
- u16 new_command;
-
- pci_read_config_word(pcidev, PCI_COMMAND, &pci_command);
-
- new_command = pci_command | PCI_COMMAND_MASTER
- | PCI_COMMAND_MEMORY
- | PCI_COMMAND_INVALIDATE
- | PCI_COMMAND_PARITY | PCI_COMMAND_SERR | PCI_COMMAND_FAST_BACK;
- if (pci_command != new_command)
- pci_write_config_word(pcidev, PCI_COMMAND, new_command);
-}
-
-static void slic_adapter_freeresources(struct adapter *adapter)
-{
- slic_init_cleanup(adapter);
- memset(&adapter->stats, 0, sizeof(struct net_device_stats));
- adapter->error_interrupts = 0;
- adapter->rcv_interrupts = 0;
- adapter->xmit_interrupts = 0;
- adapter->linkevent_interrupts = 0;
- adapter->upr_interrupts = 0;
- adapter->num_isrs = 0;
- adapter->xmit_completes = 0;
- adapter->rcv_broadcasts = 0;
- adapter->rcv_multicasts = 0;
- adapter->rcv_unicasts = 0;
-}
-
/*
* slic_link_config
*
@@ -1774,18 +495,6 @@ static void slic_link_config(struct adapter *adapter,
}
}
-static void slic_card_cleanup(struct sliccard *card)
-{
- if (card->loadtimerset) {
- card->loadtimerset = 0;
- del_timer(&card->loadtimer);
- }
-
- slic_debug_card_destroy(card);
-
- kfree(card);
-}
-
static int slic_card_download_gbrcv(struct adapter *adapter)
{
const struct firmware *fw;
@@ -1967,7 +676,7 @@ static int slic_card_download(struct adapter *adapter)
and reach mainloop */
mdelay(20);
- return STATUS_SUCCESS;
+ return 0;
}
MODULE_FIRMWARE("slicoss/oasisdownload.sys");
@@ -1999,327 +708,72 @@ static void slic_intagg_set(struct adapter *adapter, u32 value)
adapter->card->loadlevel_current = value;
}
-static int slic_card_init(struct sliccard *card, struct adapter *adapter)
+static void slic_soft_reset(struct adapter *adapter)
{
- __iomem struct slic_regs *slic_regs = adapter->slic_regs;
- struct slic_eeprom *peeprom;
- struct oslic_eeprom *pOeeprom;
- dma_addr_t phys_config;
- u32 phys_configh;
- u32 phys_configl;
- u32 i = 0;
- struct slic_shmem *pshmem;
- int status;
- uint macaddrs = card->card_size;
- ushort eecodesize;
- ushort dramsize;
- ushort ee_chksum;
- ushort calc_chksum;
- struct slic_config_mac *pmac;
- unsigned char fruformat;
- unsigned char oemfruformat;
- struct atk_fru *patkfru;
- union oemfru *poemfru;
-
- /* Reset everything except PCI configuration space */
- slic_soft_reset(adapter);
-
- /* Download the microcode */
- status = slic_card_download(adapter);
-
- if (status != STATUS_SUCCESS) {
- dev_err(&adapter->pcidev->dev,
- "download failed bus %d slot %d\n",
- adapter->busnumber, adapter->slotnumber);
- return status;
- }
-
- if (!card->config_set) {
- peeprom = pci_alloc_consistent(adapter->pcidev,
- sizeof(struct slic_eeprom),
- &phys_config);
-
- phys_configl = SLIC_GET_ADDR_LOW(phys_config);
- phys_configh = SLIC_GET_ADDR_HIGH(phys_config);
-
- if (!peeprom) {
- dev_err(&adapter->pcidev->dev,
- "eeprom read failed to get memory "
- "bus %d slot %d\n", adapter->busnumber,
- adapter->slotnumber);
- return -ENOMEM;
- } else {
- memset(peeprom, 0, sizeof(struct slic_eeprom));
- }
- slic_reg32_write(&slic_regs->slic_icr, ICR_INT_OFF, FLUSH);
+ if (adapter->card->state == CARD_UP) {
+ slic_reg32_write(&adapter->slic_regs->slic_quiesce, 0, FLUSH);
mdelay(1);
- pshmem = (struct slic_shmem *)adapter->phys_shmem;
-
- spin_lock_irqsave(&adapter->bit64reglock.lock,
- adapter->bit64reglock.flags);
- slic_reg32_write(&slic_regs->slic_addr_upper, 0, DONT_FLUSH);
- slic_reg32_write(&slic_regs->slic_isp,
- SLIC_GET_ADDR_LOW(&pshmem->isr), FLUSH);
- spin_unlock_irqrestore(&adapter->bit64reglock.lock,
- adapter->bit64reglock.flags);
-
- slic_config_get(adapter, phys_configl, phys_configh);
-
- for (;;) {
- if (adapter->pshmem->isr) {
- if (adapter->pshmem->isr & ISR_UPC) {
- adapter->pshmem->isr = 0;
- slic_reg64_write(adapter,
- &slic_regs->slic_isp, 0,
- &slic_regs->slic_addr_upper,
- 0, FLUSH);
- slic_reg32_write(&slic_regs->slic_isr,
- 0, FLUSH);
-
- slic_upr_request_complete(adapter, 0);
- break;
- } else {
- adapter->pshmem->isr = 0;
- slic_reg32_write(&slic_regs->slic_isr,
- 0, FLUSH);
- }
- } else {
- mdelay(1);
- i++;
- if (i > 5000) {
- dev_err(&adapter->pcidev->dev,
- "%d config data fetch timed out!\n",
- adapter->port);
- slic_reg64_write(adapter,
- &slic_regs->slic_isp, 0,
- &slic_regs->slic_addr_upper,
- 0, FLUSH);
- return -EINVAL;
- }
- }
- }
-
- switch (adapter->devid) {
- /* Oasis card */
- case SLIC_2GB_DEVICE_ID:
- /* extract EEPROM data and pointers to EEPROM data */
- pOeeprom = (struct oslic_eeprom *) peeprom;
- eecodesize = pOeeprom->EecodeSize;
- dramsize = pOeeprom->DramSize;
- pmac = pOeeprom->MacInfo;
- fruformat = pOeeprom->FruFormat;
- patkfru = &pOeeprom->AtkFru;
- oemfruformat = pOeeprom->OemFruFormat;
- poemfru = &pOeeprom->OemFru;
- macaddrs = 2;
- /* Minor kludge for Oasis card
- get 2 MAC addresses from the
- EEPROM to ensure that function 1
- gets the Port 1 MAC address */
- break;
- default:
- /* extract EEPROM data and pointers to EEPROM data */
- eecodesize = peeprom->EecodeSize;
- dramsize = peeprom->DramSize;
- pmac = peeprom->u2.mac.MacInfo;
- fruformat = peeprom->FruFormat;
- patkfru = &peeprom->AtkFru;
- oemfruformat = peeprom->OemFruFormat;
- poemfru = &peeprom->OemFru;
- break;
- }
-
- card->config.EepromValid = false;
-
- /* see if the EEPROM is valid by checking it's checksum */
- if ((eecodesize <= MAX_EECODE_SIZE) &&
- (eecodesize >= MIN_EECODE_SIZE)) {
-
- ee_chksum =
- *(u16 *) ((char *) peeprom + (eecodesize - 2));
- /*
- calculate the EEPROM checksum
- */
- calc_chksum =
- ~slic_eeprom_cksum((char *) peeprom,
- (eecodesize - 2));
- /*
- if the ucdoe chksum flag bit worked,
- we wouldn't need this shit
- */
- if (ee_chksum == calc_chksum)
- card->config.EepromValid = true;
- }
- /* copy in the DRAM size */
- card->config.DramSize = dramsize;
-
- /* copy in the MAC address(es) */
- for (i = 0; i < macaddrs; i++) {
- memcpy(&card->config.MacInfo[i],
- &pmac[i], sizeof(struct slic_config_mac));
- }
-
- /* copy the Alacritech FRU information */
- card->config.FruFormat = fruformat;
- memcpy(&card->config.AtkFru, patkfru,
- sizeof(struct atk_fru));
-
- pci_free_consistent(adapter->pcidev,
- sizeof(struct slic_eeprom),
- peeprom, phys_config);
-
- if ((!card->config.EepromValid) &&
- (adapter->reg_params.fail_on_bad_eeprom)) {
- slic_reg64_write(adapter, &slic_regs->slic_isp, 0,
- &slic_regs->slic_addr_upper,
- 0, FLUSH);
- dev_err(&adapter->pcidev->dev,
- "unsupported CONFIGURATION EEPROM invalid\n");
- return -EINVAL;
- }
-
- card->config_set = 1;
}
- if (slic_card_download_gbrcv(adapter)) {
- dev_err(&adapter->pcidev->dev,
- "unable to download GB receive microcode\n");
- return -EINVAL;
- }
-
- if (slic_global.dynamic_intagg)
- slic_intagg_set(adapter, 0);
- else
- slic_intagg_set(adapter, intagg_delay);
-
- /*
- * Initialize ping status to "ok"
- */
- card->pingstatus = ISR_PINGMASK;
-
- /*
- * Lastly, mark our card state as up and return success
- */
- card->state = CARD_UP;
- card->reset_in_progress = 0;
-
- return STATUS_SUCCESS;
+ slic_reg32_write(&adapter->slic_regs->slic_reset, SLIC_RESET_MAGIC,
+ FLUSH);
+ mdelay(1);
}
-static u32 slic_card_locate(struct adapter *adapter)
+static void slic_mac_address_config(struct adapter *adapter)
{
- struct sliccard *card = slic_global.slic_card;
- struct physcard *physcard = slic_global.phys_card;
- ushort card_hostid;
- u16 __iomem *hostid_reg;
- uint i;
- uint rdhostid_offset = 0;
-
- switch (adapter->devid) {
- case SLIC_2GB_DEVICE_ID:
- rdhostid_offset = SLIC_RDHOSTID_2GB;
- break;
- case SLIC_1GB_DEVICE_ID:
- rdhostid_offset = SLIC_RDHOSTID_1GB;
- break;
- default:
- ASSERT(0);
- break;
- }
+ u32 value;
+ u32 value2;
+ __iomem struct slic_regs *slic_regs = adapter->slic_regs;
- hostid_reg =
- (u16 __iomem *) (((u8 __iomem *) (adapter->slic_regs)) +
- rdhostid_offset);
+ value = *(u32 *) &adapter->currmacaddr[2];
+ value = ntohl(value);
+ slic_reg32_write(&slic_regs->slic_wraddral, value, FLUSH);
+ slic_reg32_write(&slic_regs->slic_wraddrbl, value, FLUSH);
- /* read the 16 bit hostid from SRAM */
- card_hostid = (ushort) readw(hostid_reg);
+ value2 = (u32) ((adapter->currmacaddr[0] << 8 |
+ adapter->currmacaddr[1]) & 0xFFFF);
- /* Initialize a new card structure if need be */
- if (card_hostid == SLIC_HOSTID_DEFAULT) {
- card = kzalloc(sizeof(struct sliccard), GFP_KERNEL);
- if (card == NULL)
- return -ENOMEM;
+ slic_reg32_write(&slic_regs->slic_wraddrah, value2, FLUSH);
+ slic_reg32_write(&slic_regs->slic_wraddrbh, value2, FLUSH);
- card->next = slic_global.slic_card;
- slic_global.slic_card = card;
- card->busnumber = adapter->busnumber;
- card->slotnumber = adapter->slotnumber;
+ /* Write our multicast mask out to the card. This is done */
+ /* here in addition to the slic_mcast_addr_set routine */
+ /* because ALL_MCAST may have been enabled or disabled */
+ slic_mcast_set_mask(adapter);
+}
- /* Find an available cardnum */
- for (i = 0; i < SLIC_MAX_CARDS; i++) {
- if (slic_global.cardnuminuse[i] == 0) {
- slic_global.cardnuminuse[i] = 1;
- card->cardnum = i;
- break;
- }
- }
- slic_global.num_slic_cards++;
+static void slic_mac_config(struct adapter *adapter)
+{
+ u32 value;
+ __iomem struct slic_regs *slic_regs = adapter->slic_regs;
- slic_debug_card_create(card);
+ /* Setup GMAC gaps */
+ if (adapter->linkspeed == LINK_1000MB) {
+ value = ((GMCR_GAPBB_1000 << GMCR_GAPBB_SHIFT) |
+ (GMCR_GAPR1_1000 << GMCR_GAPR1_SHIFT) |
+ (GMCR_GAPR2_1000 << GMCR_GAPR2_SHIFT));
} else {
- /* Card exists, find the card this adapter belongs to */
- while (card) {
- if (card->cardnum == card_hostid)
- break;
- card = card->next;
- }
- }
-
- ASSERT(card);
- if (!card)
- return STATUS_FAILURE;
- /* Put the adapter in the card's adapter list */
- ASSERT(card->adapter[adapter->port] == NULL);
- if (!card->adapter[adapter->port]) {
- card->adapter[adapter->port] = adapter;
- adapter->card = card;
+ value = ((GMCR_GAPBB_100 << GMCR_GAPBB_SHIFT) |
+ (GMCR_GAPR1_100 << GMCR_GAPR1_SHIFT) |
+ (GMCR_GAPR2_100 << GMCR_GAPR2_SHIFT));
}
- card->card_size = 1; /* one port per *logical* card */
-
- while (physcard) {
- for (i = 0; i < SLIC_MAX_PORTS; i++) {
- if (!physcard->adapter[i])
- continue;
- else
- break;
- }
- ASSERT(i != SLIC_MAX_PORTS);
- if (physcard->adapter[i]->slotnumber == adapter->slotnumber)
- break;
- physcard = physcard->next;
- }
- if (!physcard) {
- /* no structure allocated for this physical card yet */
- physcard = kzalloc(sizeof(struct physcard), GFP_ATOMIC);
- ASSERT(physcard);
+ /* enable GMII */
+ if (adapter->linkspeed == LINK_1000MB)
+ value |= GMCR_GBIT;
- physcard->next = slic_global.phys_card;
- slic_global.phys_card = physcard;
- physcard->adapters_allocd = 1;
- } else {
- physcard->adapters_allocd++;
+ /* enable fullduplex */
+ if ((adapter->linkduplex == LINK_FULLD)
+ || (adapter->macopts & MAC_LOOPBACK)) {
+ value |= GMCR_FULLD;
}
- /* Note - this is ZERO relative */
- adapter->physport = physcard->adapters_allocd - 1;
-
- ASSERT(physcard->adapter[adapter->physport] == NULL);
- physcard->adapter[adapter->physport] = adapter;
- adapter->physcard = physcard;
-
- return 0;
-}
-static void slic_soft_reset(struct adapter *adapter)
-{
- if (adapter->card->state == CARD_UP) {
- slic_reg32_write(&adapter->slic_regs->slic_quiesce, 0, FLUSH);
- mdelay(1);
- }
+ /* write mac config */
+ slic_reg32_write(&slic_regs->slic_wmcfg, value, FLUSH);
- slic_reg32_write(&adapter->slic_regs->slic_reset, SLIC_RESET_MAGIC,
- FLUSH);
- mdelay(1);
+ /* setup mac addresses */
+ slic_mac_address_config(adapter);
}
static void slic_config_set(struct adapter *adapter, bool linkchange)
@@ -2403,76 +857,10 @@ static void slic_config_clear(struct adapter *adapter)
slic_reg32_write(&slic_regs->slic_wphy, phy_config, FLUSH);
}
-static void slic_config_get(struct adapter *adapter, u32 config,
- u32 config_h)
-{
- int status;
-
- status = slic_upr_request(adapter,
- SLIC_UPR_RCONFIG,
- (u32) config, (u32) config_h, 0, 0);
- ASSERT(status == 0);
-}
-
-static void slic_mac_address_config(struct adapter *adapter)
-{
- u32 value;
- u32 value2;
- __iomem struct slic_regs *slic_regs = adapter->slic_regs;
-
- value = *(u32 *) &adapter->currmacaddr[2];
- value = ntohl(value);
- slic_reg32_write(&slic_regs->slic_wraddral, value, FLUSH);
- slic_reg32_write(&slic_regs->slic_wraddrbl, value, FLUSH);
-
- value2 = (u32) ((adapter->currmacaddr[0] << 8 |
- adapter->currmacaddr[1]) & 0xFFFF);
-
- slic_reg32_write(&slic_regs->slic_wraddrah, value2, FLUSH);
- slic_reg32_write(&slic_regs->slic_wraddrbh, value2, FLUSH);
-
- /* Write our multicast mask out to the card. This is done */
- /* here in addition to the slic_mcast_addr_set routine */
- /* because ALL_MCAST may have been enabled or disabled */
- slic_mcast_set_mask(adapter);
-}
-
-static void slic_mac_config(struct adapter *adapter)
-{
- u32 value;
- __iomem struct slic_regs *slic_regs = adapter->slic_regs;
-
- /* Setup GMAC gaps */
- if (adapter->linkspeed == LINK_1000MB) {
- value = ((GMCR_GAPBB_1000 << GMCR_GAPBB_SHIFT) |
- (GMCR_GAPR1_1000 << GMCR_GAPR1_SHIFT) |
- (GMCR_GAPR2_1000 << GMCR_GAPR2_SHIFT));
- } else {
- value = ((GMCR_GAPBB_100 << GMCR_GAPBB_SHIFT) |
- (GMCR_GAPR1_100 << GMCR_GAPR1_SHIFT) |
- (GMCR_GAPR2_100 << GMCR_GAPR2_SHIFT));
- }
-
- /* enable GMII */
- if (adapter->linkspeed == LINK_1000MB)
- value |= GMCR_GBIT;
-
- /* enable fullduplex */
- if ((adapter->linkduplex == LINK_FULLD)
- || (adapter->macopts & MAC_LOOPBACK)) {
- value |= GMCR_FULLD;
- }
-
- /* write mac config */
- slic_reg32_write(&slic_regs->slic_wmcfg, value, FLUSH);
-
- /* setup mac addresses */
- slic_mac_address_config(adapter);
-}
-
static bool slic_mac_filter(struct adapter *adapter,
struct ether_header *ether_frame)
{
+ struct net_device *netdev = adapter->netdev;
u32 opts = adapter->macopts;
u32 *dhost4 = (u32 *)&ether_frame->ether_dhost[0];
u16 *dhost2 = (u16 *)&ether_frame->ether_dhost[4];
@@ -2492,7 +880,7 @@ static bool slic_mac_filter(struct adapter *adapter,
if (ether_frame->ether_dhost[0] & 0x01) {
if (opts & MAC_ALLMCAST) {
adapter->rcv_multicasts++;
- adapter->stats.multicast++;
+ netdev->stats.multicast++;
return true;
}
if (opts & MAC_MCAST) {
@@ -2502,7 +890,7 @@ static bool slic_mac_filter(struct adapter *adapter,
if (!compare_ether_addr(mcaddr->address,
ether_frame->ether_dhost)) {
adapter->rcv_multicasts++;
- adapter->stats.multicast++;
+ netdev->stats.multicast++;
return true;
}
mcaddr = mcaddr->next;
@@ -2597,17 +985,6 @@ static void slic_timer_load_check(ulong cardaddr)
add_timer(&card->loadtimer);
}
-static void slic_assert_fail(void)
-{
- u32 cpuid;
- u32 curr_pid;
- cpuid = smp_processor_id();
- curr_pid = current->pid;
-
- printk(KERN_ERR "%s CPU # %d ---- PID # %d\n",
- __func__, cpuid, curr_pid);
-}
-
static int slic_upr_queue_request(struct adapter *adapter,
u32 upr_request,
u32 upr_data,
@@ -2637,7 +1014,55 @@ static int slic_upr_queue_request(struct adapter *adapter,
} else {
adapter->upr_list = upr;
}
- return STATUS_SUCCESS;
+ return 0;
+}
+
+static void slic_upr_start(struct adapter *adapter)
+{
+ struct slic_upr *upr;
+ __iomem struct slic_regs *slic_regs = adapter->slic_regs;
+/*
+ char * ptr1;
+ char * ptr2;
+ uint cmdoffset;
+*/
+ upr = adapter->upr_list;
+ if (!upr)
+ return;
+ if (adapter->upr_busy)
+ return;
+ adapter->upr_busy = 1;
+
+ switch (upr->upr_request) {
+ case SLIC_UPR_STATS:
+ if (upr->upr_data_h == 0) {
+ slic_reg32_write(&slic_regs->slic_stats, upr->upr_data,
+ FLUSH);
+ } else {
+ slic_reg64_write(adapter, &slic_regs->slic_stats64,
+ upr->upr_data,
+ &slic_regs->slic_addr_upper,
+ upr->upr_data_h, FLUSH);
+ }
+ break;
+
+ case SLIC_UPR_RLSR:
+ slic_reg64_write(adapter, &slic_regs->slic_rlsr, upr->upr_data,
+ &slic_regs->slic_addr_upper, upr->upr_data_h,
+ FLUSH);
+ break;
+
+ case SLIC_UPR_RCONFIG:
+ slic_reg64_write(adapter, &slic_regs->slic_rconfig,
+ upr->upr_data, &slic_regs->slic_addr_upper,
+ upr->upr_data_h, FLUSH);
+ break;
+ case SLIC_UPR_PING:
+ slic_reg32_write(&slic_regs->slic_ping, 1, FLUSH);
+ break;
+ default:
+ ASSERT(0);
+ }
}
static int slic_upr_request(struct adapter *adapter,
@@ -2646,22 +1071,97 @@ static int slic_upr_request(struct adapter *adapter,
u32 upr_data_h,
u32 upr_buffer, u32 upr_buffer_h)
{
- int status;
+ int rc;
spin_lock_irqsave(&adapter->upr_lock.lock, adapter->upr_lock.flags);
- status = slic_upr_queue_request(adapter,
+ rc = slic_upr_queue_request(adapter,
upr_request,
upr_data,
upr_data_h, upr_buffer, upr_buffer_h);
- if (status != STATUS_SUCCESS) {
- spin_unlock_irqrestore(&adapter->upr_lock.lock,
- adapter->upr_lock.flags);
- return status;
- }
+ if (rc)
+ goto err_unlock_irq;
+
slic_upr_start(adapter);
+err_unlock_irq:
spin_unlock_irqrestore(&adapter->upr_lock.lock,
adapter->upr_lock.flags);
- return STATUS_PENDING;
+ return rc;
+}
+
+static void slic_link_upr_complete(struct adapter *adapter, u32 isr)
+{
+ u32 linkstatus = adapter->pshmem->linkstatus;
+ uint linkup;
+ unsigned char linkspeed;
+ unsigned char linkduplex;
+
+ if ((isr & ISR_UPCERR) || (isr & ISR_UPCBSY)) {
+ struct slic_shmem *pshmem;
+
+ pshmem = (struct slic_shmem *)adapter->phys_shmem;
+#if defined(CONFIG_X86_64)
+ slic_upr_queue_request(adapter,
+ SLIC_UPR_RLSR,
+ SLIC_GET_ADDR_LOW(&pshmem->linkstatus),
+ SLIC_GET_ADDR_HIGH(&pshmem->linkstatus),
+ 0, 0);
+#elif defined(CONFIG_X86)
+ slic_upr_queue_request(adapter,
+ SLIC_UPR_RLSR,
+ (u32) &pshmem->linkstatus,
+ SLIC_GET_ADDR_HIGH(pshmem), 0, 0);
+#else
+ Stop Compilation;
+#endif
+ return;
+ }
+ if (adapter->state != ADAPT_UP)
+ return;
+
+ ASSERT((adapter->devid == SLIC_1GB_DEVICE_ID)
+ || (adapter->devid == SLIC_2GB_DEVICE_ID));
+
+ linkup = linkstatus & GIG_LINKUP ? LINK_UP : LINK_DOWN;
+ if (linkstatus & GIG_SPEED_1000)
+ linkspeed = LINK_1000MB;
+ else if (linkstatus & GIG_SPEED_100)
+ linkspeed = LINK_100MB;
+ else
+ linkspeed = LINK_10MB;
+
+ if (linkstatus & GIG_FULLDUPLEX)
+ linkduplex = LINK_FULLD;
+ else
+ linkduplex = LINK_HALFD;
+
+ if ((adapter->linkstate == LINK_DOWN) && (linkup == LINK_DOWN))
+ return;
+
+ /* link up event, but nothing has changed */
+ if ((adapter->linkstate == LINK_UP) &&
+ (linkup == LINK_UP) &&
+ (adapter->linkspeed == linkspeed) &&
+ (adapter->linkduplex == linkduplex))
+ return;
+
+ /* link has changed at this point */
+
+ /* link has gone from up to down */
+ if (linkup == LINK_DOWN) {
+ adapter->linkstate = LINK_DOWN;
+ return;
+ }
+
+ /* link has gone from down to up */
+ adapter->linkspeed = linkspeed;
+ adapter->linkduplex = linkduplex;
+
+ if (adapter->linkstate != LINK_UP) {
+ /* setup the mac */
+ slic_config_set(adapter, true);
+ adapter->linkstate = LINK_UP;
+ netif_start_queue(adapter->netdev);
+ }
}
static void slic_upr_request_complete(struct adapter *adapter, u32 isr)
@@ -2786,128 +1286,15 @@ static void slic_upr_request_complete(struct adapter *adapter, u32 isr)
adapter->upr_lock.flags);
}
-static void slic_upr_start(struct adapter *adapter)
-{
- struct slic_upr *upr;
- __iomem struct slic_regs *slic_regs = adapter->slic_regs;
-/*
- char * ptr1;
- char * ptr2;
- uint cmdoffset;
-*/
- upr = adapter->upr_list;
- if (!upr)
- return;
- if (adapter->upr_busy)
- return;
- adapter->upr_busy = 1;
-
- switch (upr->upr_request) {
- case SLIC_UPR_STATS:
- if (upr->upr_data_h == 0) {
- slic_reg32_write(&slic_regs->slic_stats, upr->upr_data,
- FLUSH);
- } else {
- slic_reg64_write(adapter, &slic_regs->slic_stats64,
- upr->upr_data,
- &slic_regs->slic_addr_upper,
- upr->upr_data_h, FLUSH);
- }
- break;
-
- case SLIC_UPR_RLSR:
- slic_reg64_write(adapter, &slic_regs->slic_rlsr, upr->upr_data,
- &slic_regs->slic_addr_upper, upr->upr_data_h,
- FLUSH);
- break;
-
- case SLIC_UPR_RCONFIG:
- slic_reg64_write(adapter, &slic_regs->slic_rconfig,
- upr->upr_data, &slic_regs->slic_addr_upper,
- upr->upr_data_h, FLUSH);
- break;
- case SLIC_UPR_PING:
- slic_reg32_write(&slic_regs->slic_ping, 1, FLUSH);
- break;
- default:
- ASSERT(0);
- }
-}
-
-static void slic_link_upr_complete(struct adapter *adapter, u32 isr)
+static void slic_config_get(struct adapter *adapter, u32 config,
+ u32 config_h)
{
- u32 linkstatus = adapter->pshmem->linkstatus;
- uint linkup;
- unsigned char linkspeed;
- unsigned char linkduplex;
-
- if ((isr & ISR_UPCERR) || (isr & ISR_UPCBSY)) {
- struct slic_shmem *pshmem;
-
- pshmem = (struct slic_shmem *)adapter->phys_shmem;
-#if defined(CONFIG_X86_64)
- slic_upr_queue_request(adapter,
- SLIC_UPR_RLSR,
- SLIC_GET_ADDR_LOW(&pshmem->linkstatus),
- SLIC_GET_ADDR_HIGH(&pshmem->linkstatus),
- 0, 0);
-#elif defined(CONFIG_X86)
- slic_upr_queue_request(adapter,
- SLIC_UPR_RLSR,
- (u32) &pshmem->linkstatus,
- SLIC_GET_ADDR_HIGH(pshmem), 0, 0);
-#else
- Stop Compilation;
-#endif
- return;
- }
- if (adapter->state != ADAPT_UP)
- return;
-
- ASSERT((adapter->devid == SLIC_1GB_DEVICE_ID)
- || (adapter->devid == SLIC_2GB_DEVICE_ID));
-
- linkup = linkstatus & GIG_LINKUP ? LINK_UP : LINK_DOWN;
- if (linkstatus & GIG_SPEED_1000)
- linkspeed = LINK_1000MB;
- else if (linkstatus & GIG_SPEED_100)
- linkspeed = LINK_100MB;
- else
- linkspeed = LINK_10MB;
-
- if (linkstatus & GIG_FULLDUPLEX)
- linkduplex = LINK_FULLD;
- else
- linkduplex = LINK_HALFD;
-
- if ((adapter->linkstate == LINK_DOWN) && (linkup == LINK_DOWN))
- return;
-
- /* link up event, but nothing has changed */
- if ((adapter->linkstate == LINK_UP) &&
- (linkup == LINK_UP) &&
- (adapter->linkspeed == linkspeed) &&
- (adapter->linkduplex == linkduplex))
- return;
-
- /* link has changed at this point */
-
- /* link has gone from up to down */
- if (linkup == LINK_DOWN) {
- adapter->linkstate = LINK_DOWN;
- return;
- }
-
- /* link has gone from down to up */
- adapter->linkspeed = linkspeed;
- adapter->linkduplex = linkduplex;
+ int status;
- if (adapter->linkstate != LINK_UP) {
- /* setup the mac */
- slic_config_set(adapter, true);
- adapter->linkstate = LINK_UP;
- netif_start_queue(adapter->netdev);
- }
+ status = slic_upr_request(adapter,
+ SLIC_UPR_RCONFIG,
+ (u32) config, (u32) config_h, 0, 0);
+ ASSERT(status == 0);
}
/*
@@ -3012,6 +1399,24 @@ static ushort slic_eeprom_cksum(char *m, int len)
return (ushort) sum;
}
+static void slic_rspqueue_free(struct adapter *adapter)
+{
+ int i;
+ struct slic_rspqueue *rspq = &adapter->rspqueue;
+
+ for (i = 0; i < rspq->num_pages; i++) {
+ if (rspq->vaddr[i]) {
+ pci_free_consistent(adapter->pcidev, PAGE_SIZE,
+ rspq->vaddr[i], rspq->paddr[i]);
+ }
+ rspq->vaddr[i] = NULL;
+ rspq->paddr[i] = 0;
+ }
+ rspq->offset = 0;
+ rspq->pageindex = 0;
+ rspq->rspbuf = NULL;
+}
+
static int slic_rspqueue_init(struct adapter *adapter)
{
int i;
@@ -3032,7 +1437,7 @@ static int slic_rspqueue_init(struct adapter *adapter)
dev_err(&adapter->pcidev->dev,
"pci_alloc_consistent failed\n");
slic_rspqueue_free(adapter);
- return STATUS_FAILURE;
+ return -ENOMEM;
}
#ifndef CONFIG_X86_64
ASSERT(((u32) rspq->vaddr[i] & 0xFFFFF000) ==
@@ -3056,25 +1461,7 @@ static int slic_rspqueue_init(struct adapter *adapter)
rspq->offset = 0;
rspq->pageindex = 0;
rspq->rspbuf = (struct slic_rspbuf *)rspq->vaddr[0];
- return STATUS_SUCCESS;
-}
-
-static void slic_rspqueue_free(struct adapter *adapter)
-{
- int i;
- struct slic_rspqueue *rspq = &adapter->rspqueue;
-
- for (i = 0; i < rspq->num_pages; i++) {
- if (rspq->vaddr[i]) {
- pci_free_consistent(adapter->pcidev, PAGE_SIZE,
- rspq->vaddr[i], rspq->paddr[i]);
- }
- rspq->vaddr[i] = NULL;
- rspq->paddr[i] = 0;
- }
- rspq->offset = 0;
- rspq->pageindex = 0;
- rspq->rspbuf = NULL;
+ return 0;
}
static struct slic_rspbuf *slic_rspqueue_getnext(struct adapter *adapter)
@@ -3159,36 +1546,6 @@ static u32 *slic_cmdqmem_addpage(struct adapter *adapter)
return pageaddr;
}
-static int slic_cmdq_init(struct adapter *adapter)
-{
- int i;
- u32 *pageaddr;
-
- ASSERT(adapter->state == ADAPT_DOWN);
- memset(&adapter->cmdq_all, 0, sizeof(struct slic_cmdqueue));
- memset(&adapter->cmdq_free, 0, sizeof(struct slic_cmdqueue));
- memset(&adapter->cmdq_done, 0, sizeof(struct slic_cmdqueue));
- spin_lock_init(&adapter->cmdq_all.lock.lock);
- spin_lock_init(&adapter->cmdq_free.lock.lock);
- spin_lock_init(&adapter->cmdq_done.lock.lock);
- slic_cmdqmem_init(adapter);
- adapter->slic_handle_ix = 1;
- for (i = 0; i < SLIC_CMDQ_INITPAGES; i++) {
- pageaddr = slic_cmdqmem_addpage(adapter);
-#ifndef CONFIG_X86_64
- ASSERT(((u32) pageaddr & 0xFFFFF000) == (u32) pageaddr);
-#endif
- if (!pageaddr) {
- slic_cmdq_free(adapter);
- return STATUS_FAILURE;
- }
- slic_cmdq_addcmdpage(adapter, pageaddr);
- }
- adapter->slic_handle_ix = 1;
-
- return STATUS_SUCCESS;
-}
-
static void slic_cmdq_free(struct adapter *adapter)
{
struct slic_hostcmd *cmd;
@@ -3212,53 +1569,6 @@ static void slic_cmdq_free(struct adapter *adapter)
slic_cmdqmem_free(adapter);
}
-static void slic_cmdq_reset(struct adapter *adapter)
-{
- struct slic_hostcmd *hcmd;
- struct sk_buff *skb;
- u32 outstanding;
-
- spin_lock_irqsave(&adapter->cmdq_free.lock.lock,
- adapter->cmdq_free.lock.flags);
- spin_lock_irqsave(&adapter->cmdq_done.lock.lock,
- adapter->cmdq_done.lock.flags);
- outstanding = adapter->cmdq_all.count - adapter->cmdq_done.count;
- outstanding -= adapter->cmdq_free.count;
- hcmd = adapter->cmdq_all.head;
- while (hcmd) {
- if (hcmd->busy) {
- skb = hcmd->skb;
- ASSERT(skb);
- hcmd->busy = 0;
- hcmd->skb = NULL;
- dev_kfree_skb_irq(skb);
- }
- hcmd = hcmd->next_all;
- }
- adapter->cmdq_free.count = 0;
- adapter->cmdq_free.head = NULL;
- adapter->cmdq_free.tail = NULL;
- adapter->cmdq_done.count = 0;
- adapter->cmdq_done.head = NULL;
- adapter->cmdq_done.tail = NULL;
- adapter->cmdq_free.head = adapter->cmdq_all.head;
- hcmd = adapter->cmdq_all.head;
- while (hcmd) {
- adapter->cmdq_free.count++;
- hcmd->next = hcmd->next_all;
- hcmd = hcmd->next_all;
- }
- if (adapter->cmdq_free.count != adapter->cmdq_all.count) {
- dev_err(&adapter->netdev->dev,
- "free_count %d != all count %d\n",
- adapter->cmdq_free.count, adapter->cmdq_all.count);
- }
- spin_unlock_irqrestore(&adapter->cmdq_done.lock.lock,
- adapter->cmdq_done.lock.flags);
- spin_unlock_irqrestore(&adapter->cmdq_free.lock.lock,
- adapter->cmdq_free.lock.flags);
-}
-
static void slic_cmdq_addcmdpage(struct adapter *adapter, u32 *page)
{
struct slic_hostcmd *cmd;
@@ -3324,6 +1634,99 @@ static void slic_cmdq_addcmdpage(struct adapter *adapter, u32 *page)
spin_unlock_irqrestore(&cmdq->lock.lock, cmdq->lock.flags);
}
+static int slic_cmdq_init(struct adapter *adapter)
+{
+ int i;
+ u32 *pageaddr;
+
+ ASSERT(adapter->state == ADAPT_DOWN);
+ memset(&adapter->cmdq_all, 0, sizeof(struct slic_cmdqueue));
+ memset(&adapter->cmdq_free, 0, sizeof(struct slic_cmdqueue));
+ memset(&adapter->cmdq_done, 0, sizeof(struct slic_cmdqueue));
+ spin_lock_init(&adapter->cmdq_all.lock.lock);
+ spin_lock_init(&adapter->cmdq_free.lock.lock);
+ spin_lock_init(&adapter->cmdq_done.lock.lock);
+ slic_cmdqmem_init(adapter);
+ adapter->slic_handle_ix = 1;
+ for (i = 0; i < SLIC_CMDQ_INITPAGES; i++) {
+ pageaddr = slic_cmdqmem_addpage(adapter);
+#ifndef CONFIG_X86_64
+ ASSERT(((u32) pageaddr & 0xFFFFF000) == (u32) pageaddr);
+#endif
+ if (!pageaddr) {
+ slic_cmdq_free(adapter);
+ return -ENOMEM;
+ }
+ slic_cmdq_addcmdpage(adapter, pageaddr);
+ }
+ adapter->slic_handle_ix = 1;
+
+ return 0;
+}
+
+static void slic_cmdq_reset(struct adapter *adapter)
+{
+ struct slic_hostcmd *hcmd;
+ struct sk_buff *skb;
+ u32 outstanding;
+
+ spin_lock_irqsave(&adapter->cmdq_free.lock.lock,
+ adapter->cmdq_free.lock.flags);
+ spin_lock_irqsave(&adapter->cmdq_done.lock.lock,
+ adapter->cmdq_done.lock.flags);
+ outstanding = adapter->cmdq_all.count - adapter->cmdq_done.count;
+ outstanding -= adapter->cmdq_free.count;
+ hcmd = adapter->cmdq_all.head;
+ while (hcmd) {
+ if (hcmd->busy) {
+ skb = hcmd->skb;
+ ASSERT(skb);
+ hcmd->busy = 0;
+ hcmd->skb = NULL;
+ dev_kfree_skb_irq(skb);
+ }
+ hcmd = hcmd->next_all;
+ }
+ adapter->cmdq_free.count = 0;
+ adapter->cmdq_free.head = NULL;
+ adapter->cmdq_free.tail = NULL;
+ adapter->cmdq_done.count = 0;
+ adapter->cmdq_done.head = NULL;
+ adapter->cmdq_done.tail = NULL;
+ adapter->cmdq_free.head = adapter->cmdq_all.head;
+ hcmd = adapter->cmdq_all.head;
+ while (hcmd) {
+ adapter->cmdq_free.count++;
+ hcmd->next = hcmd->next_all;
+ hcmd = hcmd->next_all;
+ }
+ if (adapter->cmdq_free.count != adapter->cmdq_all.count) {
+ dev_err(&adapter->netdev->dev,
+ "free_count %d != all count %d\n",
+ adapter->cmdq_free.count, adapter->cmdq_all.count);
+ }
+ spin_unlock_irqrestore(&adapter->cmdq_done.lock.lock,
+ adapter->cmdq_done.lock.flags);
+ spin_unlock_irqrestore(&adapter->cmdq_free.lock.lock,
+ adapter->cmdq_free.lock.flags);
+}
+
+static void slic_cmdq_getdone(struct adapter *adapter)
+{
+ struct slic_cmdqueue *done_cmdq = &adapter->cmdq_done;
+ struct slic_cmdqueue *free_cmdq = &adapter->cmdq_free;
+
+ ASSERT(free_cmdq->head == NULL);
+ spin_lock_irqsave(&done_cmdq->lock.lock, done_cmdq->lock.flags);
+
+ free_cmdq->head = done_cmdq->head;
+ free_cmdq->count = done_cmdq->count;
+ done_cmdq->head = NULL;
+ done_cmdq->tail = NULL;
+ done_cmdq->count = 0;
+ spin_unlock_irqrestore(&done_cmdq->lock.lock, done_cmdq->lock.flags);
+}
+
static struct slic_hostcmd *slic_cmdq_getfree(struct adapter *adapter)
{
struct slic_cmdqueue *cmdq = &adapter->cmdq_free;
@@ -3357,22 +1760,6 @@ retry:
return cmd;
}
-static void slic_cmdq_getdone(struct adapter *adapter)
-{
- struct slic_cmdqueue *done_cmdq = &adapter->cmdq_done;
- struct slic_cmdqueue *free_cmdq = &adapter->cmdq_free;
-
- ASSERT(free_cmdq->head == NULL);
- spin_lock_irqsave(&done_cmdq->lock.lock, done_cmdq->lock.flags);
-
- free_cmdq->head = done_cmdq->head;
- free_cmdq->count = done_cmdq->count;
- done_cmdq->head = NULL;
- done_cmdq->tail = NULL;
- done_cmdq->count = 0;
- spin_unlock_irqrestore(&done_cmdq->lock.lock, done_cmdq->lock.flags);
-}
-
static void slic_cmdq_putdone_irq(struct adapter *adapter,
struct slic_hostcmd *cmd)
{
@@ -3388,79 +1775,6 @@ static void slic_cmdq_putdone_irq(struct adapter *adapter,
spin_unlock(&cmdq->lock.lock);
}
-static int slic_rcvqueue_init(struct adapter *adapter)
-{
- int i, count;
- struct slic_rcvqueue *rcvq = &adapter->rcvqueue;
-
- ASSERT(adapter->state == ADAPT_DOWN);
- rcvq->tail = NULL;
- rcvq->head = NULL;
- rcvq->size = SLIC_RCVQ_ENTRIES;
- rcvq->errors = 0;
- rcvq->count = 0;
- i = (SLIC_RCVQ_ENTRIES / SLIC_RCVQ_FILLENTRIES);
- count = 0;
- while (i) {
- count += slic_rcvqueue_fill(adapter);
- i--;
- }
- if (rcvq->count < SLIC_RCVQ_MINENTRIES) {
- slic_rcvqueue_free(adapter);
- return STATUS_FAILURE;
- }
- return STATUS_SUCCESS;
-}
-
-static void slic_rcvqueue_free(struct adapter *adapter)
-{
- struct slic_rcvqueue *rcvq = &adapter->rcvqueue;
- struct sk_buff *skb;
-
- while (rcvq->head) {
- skb = rcvq->head;
- rcvq->head = rcvq->head->next;
- dev_kfree_skb(skb);
- }
- rcvq->tail = NULL;
- rcvq->head = NULL;
- rcvq->count = 0;
-}
-
-static struct sk_buff *slic_rcvqueue_getnext(struct adapter *adapter)
-{
- struct slic_rcvqueue *rcvq = &adapter->rcvqueue;
- struct sk_buff *skb;
- struct slic_rcvbuf *rcvbuf;
- int count;
-
- if (rcvq->count) {
- skb = rcvq->head;
- rcvbuf = (struct slic_rcvbuf *)skb->head;
- ASSERT(rcvbuf);
-
- if (rcvbuf->status & IRHDDR_SVALID) {
- rcvq->head = rcvq->head->next;
- skb->next = NULL;
- rcvq->count--;
- } else {
- skb = NULL;
- }
- } else {
- dev_err(&adapter->netdev->dev,
- "RcvQ Empty!! rcvq[%p] count[%x]\n", rcvq, rcvq->count);
- skb = NULL;
- }
- while (rcvq->count < SLIC_RCVQ_FILLTHRESH) {
- count = slic_rcvqueue_fill(adapter);
- if (!count)
- break;
- }
- if (skb)
- rcvq->errors = 0;
- return skb;
-}
-
static int slic_rcvqueue_fill(struct adapter *adapter)
{
void *paddr;
@@ -3548,6 +1862,79 @@ retry_rcvqfill:
return i;
}
+static void slic_rcvqueue_free(struct adapter *adapter)
+{
+ struct slic_rcvqueue *rcvq = &adapter->rcvqueue;
+ struct sk_buff *skb;
+
+ while (rcvq->head) {
+ skb = rcvq->head;
+ rcvq->head = rcvq->head->next;
+ dev_kfree_skb(skb);
+ }
+ rcvq->tail = NULL;
+ rcvq->head = NULL;
+ rcvq->count = 0;
+}
+
+static int slic_rcvqueue_init(struct adapter *adapter)
+{
+ int i, count;
+ struct slic_rcvqueue *rcvq = &adapter->rcvqueue;
+
+ ASSERT(adapter->state == ADAPT_DOWN);
+ rcvq->tail = NULL;
+ rcvq->head = NULL;
+ rcvq->size = SLIC_RCVQ_ENTRIES;
+ rcvq->errors = 0;
+ rcvq->count = 0;
+ i = (SLIC_RCVQ_ENTRIES / SLIC_RCVQ_FILLENTRIES);
+ count = 0;
+ while (i) {
+ count += slic_rcvqueue_fill(adapter);
+ i--;
+ }
+ if (rcvq->count < SLIC_RCVQ_MINENTRIES) {
+ slic_rcvqueue_free(adapter);
+ return -ENOMEM;
+ }
+ return 0;
+}
+
+static struct sk_buff *slic_rcvqueue_getnext(struct adapter *adapter)
+{
+ struct slic_rcvqueue *rcvq = &adapter->rcvqueue;
+ struct sk_buff *skb;
+ struct slic_rcvbuf *rcvbuf;
+ int count;
+
+ if (rcvq->count) {
+ skb = rcvq->head;
+ rcvbuf = (struct slic_rcvbuf *)skb->head;
+ ASSERT(rcvbuf);
+
+ if (rcvbuf->status & IRHDDR_SVALID) {
+ rcvq->head = rcvq->head->next;
+ skb->next = NULL;
+ rcvq->count--;
+ } else {
+ skb = NULL;
+ }
+ } else {
+ dev_err(&adapter->netdev->dev,
+ "RcvQ Empty!! rcvq[%p] count[%x]\n", rcvq, rcvq->count);
+ skb = NULL;
+ }
+ while (rcvq->count < SLIC_RCVQ_FILLTHRESH) {
+ count = slic_rcvqueue_fill(adapter);
+ if (!count)
+ break;
+ }
+ if (skb)
+ rcvq->errors = 0;
+ return skb;
+}
+
static u32 slic_rcvqueue_reinsert(struct adapter *adapter, struct sk_buff *skb)
{
struct slic_rcvqueue *rcvq = &adapter->rcvqueue;
@@ -3813,11 +2200,10 @@ static int slic_debug_card_show(struct seq_file *seq, void *v)
static int slic_debug_adapter_show(struct seq_file *seq, void *v)
{
struct adapter *adapter = seq->private;
+ struct net_device *netdev = adapter->netdev;
- if ((adapter->netdev) && (adapter->netdev->name)) {
- seq_printf(seq, "info: interface : %s\n",
+ seq_printf(seq, "info: interface : %s\n",
adapter->netdev->name);
- }
seq_printf(seq, "info: status : %s\n",
SLIC_LINKSTATE(adapter->linkstate));
seq_printf(seq, "info: port : %d\n",
@@ -3835,9 +2221,9 @@ static int slic_debug_adapter_show(struct seq_file *seq, void *v)
seq_printf(seq, "info: RcvQ current : %4.4X\n",
adapter->rcvqueue.count);
seq_printf(seq, "rx stats: packets : %8.8lX\n",
- adapter->stats.rx_packets);
+ netdev->stats.rx_packets);
seq_printf(seq, "rx stats: bytes : %8.8lX\n",
- adapter->stats.rx_bytes);
+ netdev->stats.rx_bytes);
seq_printf(seq, "rx stats: broadcasts : %8.8X\n",
adapter->rcv_broadcasts);
seq_printf(seq, "rx stats: multicasts : %8.8X\n",
@@ -3851,13 +2237,13 @@ static int slic_debug_adapter_show(struct seq_file *seq, void *v)
seq_printf(seq, "rx stats: drops : %8.8X\n",
(u32) adapter->rcv_drops);
seq_printf(seq, "tx stats: packets : %8.8lX\n",
- adapter->stats.tx_packets);
+ netdev->stats.tx_packets);
seq_printf(seq, "tx stats: bytes : %8.8lX\n",
- adapter->stats.tx_bytes);
+ netdev->stats.tx_bytes);
seq_printf(seq, "tx stats: errors : %8.8X\n",
(u32) adapter->slic_stats.iface.xmt_errors);
seq_printf(seq, "rx stats: multicasts : %8.8lX\n",
- adapter->stats.multicast);
+ netdev->stats.multicast);
seq_printf(seq, "tx stats: collision errors : %8.8X\n",
(u32) adapter->slic_stats.iface.xmit_collisions);
seq_printf(seq, "perf: Max rcv frames/isr : %8.8X\n",
@@ -4039,9 +2425,1555 @@ static void slic_debug_cleanup(void)
}
}
-/******************************************************************************/
-/**************** MODULE INITIATION / TERMINATION FUNCTIONS ***************/
-/******************************************************************************/
+/*
+ * slic_link_event_handler -
+ *
+ * Initiate a link configuration sequence. The link configuration begins
+ * by issuing a READ_LINK_STATUS command to the Utility Processor on the
+ * SLIC. Since the command finishes asynchronously, the slic_upr_comlete
+ * routine will follow it up witha UP configuration write command, which
+ * will also complete asynchronously.
+ *
+ */
+static void slic_link_event_handler(struct adapter *adapter)
+{
+ int status;
+ struct slic_shmem *pshmem;
+
+ if (adapter->state != ADAPT_UP) {
+ /* Adapter is not operational. Ignore. */
+ return;
+ }
+
+ pshmem = (struct slic_shmem *)adapter->phys_shmem;
+
+#if defined(CONFIG_X86_64)
+ status = slic_upr_request(adapter,
+ SLIC_UPR_RLSR,
+ SLIC_GET_ADDR_LOW(&pshmem->linkstatus),
+ SLIC_GET_ADDR_HIGH(&pshmem->linkstatus),
+ 0, 0);
+#elif defined(CONFIG_X86)
+ status = slic_upr_request(adapter, SLIC_UPR_RLSR,
+ (u32) &pshmem->linkstatus, /* no 4GB wrap guaranteed */
+ 0, 0, 0);
+#else
+ Stop compilation;
+#endif
+ ASSERT(status == 0);
+}
+
+static void slic_init_cleanup(struct adapter *adapter)
+{
+ if (adapter->intrregistered) {
+ adapter->intrregistered = 0;
+ free_irq(adapter->netdev->irq, adapter->netdev);
+
+ }
+ if (adapter->pshmem) {
+ pci_free_consistent(adapter->pcidev,
+ sizeof(struct slic_shmem),
+ adapter->pshmem, adapter->phys_shmem);
+ adapter->pshmem = NULL;
+ adapter->phys_shmem = (dma_addr_t) NULL;
+ }
+
+ if (adapter->pingtimerset) {
+ adapter->pingtimerset = 0;
+ del_timer(&adapter->pingtimer);
+ }
+
+ slic_rspqueue_free(adapter);
+ slic_cmdq_free(adapter);
+ slic_rcvqueue_free(adapter);
+}
+
+/*
+ * Allocate a mcast_address structure to hold the multicast address.
+ * Link it in.
+ */
+static int slic_mcast_add_list(struct adapter *adapter, char *address)
+{
+ struct mcast_address *mcaddr, *mlist;
+
+ /* Check to see if it already exists */
+ mlist = adapter->mcastaddrs;
+ while (mlist) {
+ if (!compare_ether_addr(mlist->address, address))
+ return 0;
+ mlist = mlist->next;
+ }
+
+ /* Doesn't already exist. Allocate a structure to hold it */
+ mcaddr = kmalloc(sizeof(struct mcast_address), GFP_ATOMIC);
+ if (mcaddr == NULL)
+ return 1;
+
+ memcpy(mcaddr->address, address, 6);
+
+ mcaddr->next = adapter->mcastaddrs;
+ adapter->mcastaddrs = mcaddr;
+
+ return 0;
+}
+
+static void slic_mcast_set_list(struct net_device *dev)
+{
+ struct adapter *adapter = netdev_priv(dev);
+ int status = 0;
+ char *addresses;
+ struct netdev_hw_addr *ha;
+
+ ASSERT(adapter);
+
+ netdev_for_each_mc_addr(ha, dev) {
+ addresses = (char *) &ha->addr;
+ status = slic_mcast_add_list(adapter, addresses);
+ if (status != 0)
+ break;
+ slic_mcast_set_bit(adapter, addresses);
+ }
+
+ if (adapter->devflags_prev != dev->flags) {
+ adapter->macopts = MAC_DIRECTED;
+ if (dev->flags) {
+ if (dev->flags & IFF_BROADCAST)
+ adapter->macopts |= MAC_BCAST;
+ if (dev->flags & IFF_PROMISC)
+ adapter->macopts |= MAC_PROMISC;
+ if (dev->flags & IFF_ALLMULTI)
+ adapter->macopts |= MAC_ALLMCAST;
+ if (dev->flags & IFF_MULTICAST)
+ adapter->macopts |= MAC_MCAST;
+ }
+ adapter->devflags_prev = dev->flags;
+ slic_config_set(adapter, true);
+ } else {
+ if (status == 0)
+ slic_mcast_set_mask(adapter);
+ }
+ return;
+}
+
+#define XMIT_FAIL_LINK_STATE 1
+#define XMIT_FAIL_ZERO_LENGTH 2
+#define XMIT_FAIL_HOSTCMD_FAIL 3
+
+static void slic_xmit_build_request(struct adapter *adapter,
+ struct slic_hostcmd *hcmd, struct sk_buff *skb)
+{
+ struct slic_host64_cmd *ihcmd;
+ ulong phys_addr;
+
+ ihcmd = &hcmd->cmd64;
+
+ ihcmd->flags = (adapter->port << IHFLG_IFSHFT);
+ ihcmd->command = IHCMD_XMT_REQ;
+ ihcmd->u.slic_buffers.totlen = skb->len;
+ phys_addr = pci_map_single(adapter->pcidev, skb->data, skb->len,
+ PCI_DMA_TODEVICE);
+ ihcmd->u.slic_buffers.bufs[0].paddrl = SLIC_GET_ADDR_LOW(phys_addr);
+ ihcmd->u.slic_buffers.bufs[0].paddrh = SLIC_GET_ADDR_HIGH(phys_addr);
+ ihcmd->u.slic_buffers.bufs[0].length = skb->len;
+#if defined(CONFIG_X86_64)
+ hcmd->cmdsize = (u32) ((((u64)&ihcmd->u.slic_buffers.bufs[1] -
+ (u64) hcmd) + 31) >> 5);
+#elif defined(CONFIG_X86)
+ hcmd->cmdsize = ((((u32) &ihcmd->u.slic_buffers.bufs[1] -
+ (u32) hcmd) + 31) >> 5);
+#else
+ Stop Compilation;
+#endif
+}
+
+static void slic_xmit_fail(struct adapter *adapter,
+ struct sk_buff *skb,
+ void *cmd, u32 skbtype, u32 status)
+{
+ if (adapter->xmitq_full)
+ netif_stop_queue(adapter->netdev);
+ if ((cmd == NULL) && (status <= XMIT_FAIL_HOSTCMD_FAIL)) {
+ switch (status) {
+ case XMIT_FAIL_LINK_STATE:
+ dev_err(&adapter->netdev->dev,
+ "reject xmit skb[%p: %x] linkstate[%s] "
+ "adapter[%s:%d] card[%s:%d]\n",
+ skb, skb->pkt_type,
+ SLIC_LINKSTATE(adapter->linkstate),
+ SLIC_ADAPTER_STATE(adapter->state),
+ adapter->state,
+ SLIC_CARD_STATE(adapter->card->state),
+ adapter->card->state);
+ break;
+ case XMIT_FAIL_ZERO_LENGTH:
+ dev_err(&adapter->netdev->dev,
+ "xmit_start skb->len == 0 skb[%p] type[%x]\n",
+ skb, skb->pkt_type);
+ break;
+ case XMIT_FAIL_HOSTCMD_FAIL:
+ dev_err(&adapter->netdev->dev,
+ "xmit_start skb[%p] type[%x] No host commands "
+ "available\n", skb, skb->pkt_type);
+ break;
+ default:
+ ASSERT(0);
+ }
+ }
+ dev_kfree_skb(skb);
+ adapter->netdev->stats.tx_dropped++;
+}
+
+static void slic_rcv_handle_error(struct adapter *adapter,
+ struct slic_rcvbuf *rcvbuf)
+{
+ struct slic_hddr_wds *hdr = (struct slic_hddr_wds *)rcvbuf->data;
+ struct net_device *netdev = adapter->netdev;
+
+ if (adapter->devid != SLIC_1GB_DEVICE_ID) {
+ if (hdr->frame_status14 & VRHSTAT_802OE)
+ adapter->if_events.oflow802++;
+ if (hdr->frame_status14 & VRHSTAT_TPOFLO)
+ adapter->if_events.Tprtoflow++;
+ if (hdr->frame_status_b14 & VRHSTATB_802UE)
+ adapter->if_events.uflow802++;
+ if (hdr->frame_status_b14 & VRHSTATB_RCVE) {
+ adapter->if_events.rcvearly++;
+ netdev->stats.rx_fifo_errors++;
+ }
+ if (hdr->frame_status_b14 & VRHSTATB_BUFF) {
+ adapter->if_events.Bufov++;
+ netdev->stats.rx_over_errors++;
+ }
+ if (hdr->frame_status_b14 & VRHSTATB_CARRE) {
+ adapter->if_events.Carre++;
+ netdev->stats.tx_carrier_errors++;
+ }
+ if (hdr->frame_status_b14 & VRHSTATB_LONGE)
+ adapter->if_events.Longe++;
+ if (hdr->frame_status_b14 & VRHSTATB_PREA)
+ adapter->if_events.Invp++;
+ if (hdr->frame_status_b14 & VRHSTATB_CRC) {
+ adapter->if_events.Crc++;
+ netdev->stats.rx_crc_errors++;
+ }
+ if (hdr->frame_status_b14 & VRHSTATB_DRBL)
+ adapter->if_events.Drbl++;
+ if (hdr->frame_status_b14 & VRHSTATB_CODE)
+ adapter->if_events.Code++;
+ if (hdr->frame_status_b14 & VRHSTATB_TPCSUM)
+ adapter->if_events.TpCsum++;
+ if (hdr->frame_status_b14 & VRHSTATB_TPHLEN)
+ adapter->if_events.TpHlen++;
+ if (hdr->frame_status_b14 & VRHSTATB_IPCSUM)
+ adapter->if_events.IpCsum++;
+ if (hdr->frame_status_b14 & VRHSTATB_IPLERR)
+ adapter->if_events.IpLen++;
+ if (hdr->frame_status_b14 & VRHSTATB_IPHERR)
+ adapter->if_events.IpHlen++;
+ } else {
+ if (hdr->frame_statusGB & VGBSTAT_XPERR) {
+ u32 xerr = hdr->frame_statusGB >> VGBSTAT_XERRSHFT;
+
+ if (xerr == VGBSTAT_XCSERR)
+ adapter->if_events.TpCsum++;
+ if (xerr == VGBSTAT_XUFLOW)
+ adapter->if_events.Tprtoflow++;
+ if (xerr == VGBSTAT_XHLEN)
+ adapter->if_events.TpHlen++;
+ }
+ if (hdr->frame_statusGB & VGBSTAT_NETERR) {
+ u32 nerr =
+ (hdr->
+ frame_statusGB >> VGBSTAT_NERRSHFT) &
+ VGBSTAT_NERRMSK;
+ if (nerr == VGBSTAT_NCSERR)
+ adapter->if_events.IpCsum++;
+ if (nerr == VGBSTAT_NUFLOW)
+ adapter->if_events.IpLen++;
+ if (nerr == VGBSTAT_NHLEN)
+ adapter->if_events.IpHlen++;
+ }
+ if (hdr->frame_statusGB & VGBSTAT_LNKERR) {
+ u32 lerr = hdr->frame_statusGB & VGBSTAT_LERRMSK;
+
+ if (lerr == VGBSTAT_LDEARLY)
+ adapter->if_events.rcvearly++;
+ if (lerr == VGBSTAT_LBOFLO)
+ adapter->if_events.Bufov++;
+ if (lerr == VGBSTAT_LCODERR)
+ adapter->if_events.Code++;
+ if (lerr == VGBSTAT_LDBLNBL)
+ adapter->if_events.Drbl++;
+ if (lerr == VGBSTAT_LCRCERR)
+ adapter->if_events.Crc++;
+ if (lerr == VGBSTAT_LOFLO)
+ adapter->if_events.oflow802++;
+ if (lerr == VGBSTAT_LUFLO)
+ adapter->if_events.uflow802++;
+ }
+ }
+ return;
+}
+
+#define TCP_OFFLOAD_FRAME_PUSHFLAG 0x10000000
+#define M_FAST_PATH 0x0040
+
+static void slic_rcv_handler(struct adapter *adapter)
+{
+ struct net_device *netdev = adapter->netdev;
+ struct sk_buff *skb;
+ struct slic_rcvbuf *rcvbuf;
+ u32 frames = 0;
+
+ while ((skb = slic_rcvqueue_getnext(adapter))) {
+ u32 rx_bytes;
+
+ ASSERT(skb->head);
+ rcvbuf = (struct slic_rcvbuf *)skb->head;
+ adapter->card->events++;
+ if (rcvbuf->status & IRHDDR_ERR) {
+ adapter->rx_errors++;
+ slic_rcv_handle_error(adapter, rcvbuf);
+ slic_rcvqueue_reinsert(adapter, skb);
+ continue;
+ }
+
+ if (!slic_mac_filter(adapter, (struct ether_header *)
+ rcvbuf->data)) {
+ slic_rcvqueue_reinsert(adapter, skb);
+ continue;
+ }
+ skb_pull(skb, SLIC_RCVBUF_HEADSIZE);
+ rx_bytes = (rcvbuf->length & IRHDDR_FLEN_MSK);
+ skb_put(skb, rx_bytes);
+ netdev->stats.rx_packets++;
+ netdev->stats.rx_bytes += rx_bytes;
+#if SLIC_OFFLOAD_IP_CHECKSUM
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+#endif
+
+ skb->dev = adapter->netdev;
+ skb->protocol = eth_type_trans(skb, skb->dev);
+ netif_rx(skb);
+
+ ++frames;
+#if SLIC_INTERRUPT_PROCESS_LIMIT
+ if (frames >= SLIC_RCVQ_MAX_PROCESS_ISR) {
+ adapter->rcv_interrupt_yields++;
+ break;
+ }
+#endif
+ }
+ adapter->max_isr_rcvs = max(adapter->max_isr_rcvs, frames);
+}
+
+static void slic_xmit_complete(struct adapter *adapter)
+{
+ struct slic_hostcmd *hcmd;
+ struct slic_rspbuf *rspbuf;
+ u32 frames = 0;
+ struct slic_handle_word slic_handle_word;
+
+ do {
+ rspbuf = slic_rspqueue_getnext(adapter);
+ if (!rspbuf)
+ break;
+ adapter->xmit_completes++;
+ adapter->card->events++;
+ /*
+ Get the complete host command buffer
+ */
+ slic_handle_word.handle_token = rspbuf->hosthandle;
+ ASSERT(slic_handle_word.handle_index);
+ ASSERT(slic_handle_word.handle_index <= SLIC_CMDQ_MAXCMDS);
+ hcmd =
+ (struct slic_hostcmd *)
+ adapter->slic_handles[slic_handle_word.handle_index].
+ address;
+/* hcmd = (struct slic_hostcmd *) rspbuf->hosthandle; */
+ ASSERT(hcmd);
+ ASSERT(hcmd->pslic_handle ==
+ &adapter->slic_handles[slic_handle_word.handle_index]);
+ if (hcmd->type == SLIC_CMD_DUMB) {
+ if (hcmd->skb)
+ dev_kfree_skb_irq(hcmd->skb);
+ slic_cmdq_putdone_irq(adapter, hcmd);
+ }
+ rspbuf->status = 0;
+ rspbuf->hosthandle = 0;
+ frames++;
+ } while (1);
+ adapter->max_isr_xmits = max(adapter->max_isr_xmits, frames);
+}
+
+static irqreturn_t slic_interrupt(int irq, void *dev_id)
+{
+ struct net_device *dev = (struct net_device *)dev_id;
+ struct adapter *adapter = netdev_priv(dev);
+ u32 isr;
+
+ if ((adapter->pshmem) && (adapter->pshmem->isr)) {
+ slic_reg32_write(&adapter->slic_regs->slic_icr,
+ ICR_INT_MASK, FLUSH);
+ isr = adapter->isrcopy = adapter->pshmem->isr;
+ adapter->pshmem->isr = 0;
+ adapter->num_isrs++;
+ switch (adapter->card->state) {
+ case CARD_UP:
+ if (isr & ~ISR_IO) {
+ if (isr & ISR_ERR) {
+ adapter->error_interrupts++;
+ if (isr & ISR_RMISS) {
+ int count;
+ int pre_count;
+ int errors;
+
+ struct slic_rcvqueue *rcvq =
+ &adapter->rcvqueue;
+
+ adapter->
+ error_rmiss_interrupts++;
+ if (!rcvq->errors)
+ rcv_count = rcvq->count;
+ pre_count = rcvq->count;
+ errors = rcvq->errors;
+
+ while (rcvq->count <
+ SLIC_RCVQ_FILLTHRESH) {
+ count =
+ slic_rcvqueue_fill
+ (adapter);
+ if (!count)
+ break;
+ }
+ } else if (isr & ISR_XDROP) {
+ dev_err(&dev->dev,
+ "isr & ISR_ERR [%x] "
+ "ISR_XDROP \n", isr);
+ } else {
+ dev_err(&dev->dev,
+ "isr & ISR_ERR [%x]\n",
+ isr);
+ }
+ }
+
+ if (isr & ISR_LEVENT) {
+ adapter->linkevent_interrupts++;
+ slic_link_event_handler(adapter);
+ }
+
+ if ((isr & ISR_UPC) ||
+ (isr & ISR_UPCERR) || (isr & ISR_UPCBSY)) {
+ adapter->upr_interrupts++;
+ slic_upr_request_complete(adapter, isr);
+ }
+ }
+
+ if (isr & ISR_RCV) {
+ adapter->rcv_interrupts++;
+ slic_rcv_handler(adapter);
+ }
+
+ if (isr & ISR_CMD) {
+ adapter->xmit_interrupts++;
+ slic_xmit_complete(adapter);
+ }
+ break;
+
+ case CARD_DOWN:
+ if ((isr & ISR_UPC) ||
+ (isr & ISR_UPCERR) || (isr & ISR_UPCBSY)) {
+ adapter->upr_interrupts++;
+ slic_upr_request_complete(adapter, isr);
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ adapter->isrcopy = 0;
+ adapter->all_reg_writes += 2;
+ adapter->isr_reg_writes++;
+ slic_reg32_write(&adapter->slic_regs->slic_isr, 0, FLUSH);
+ } else {
+ adapter->false_interrupts++;
+ }
+ return IRQ_HANDLED;
+}
+
+#define NORMAL_ETHFRAME 0
+
+static netdev_tx_t slic_xmit_start(struct sk_buff *skb, struct net_device *dev)
+{
+ struct sliccard *card;
+ struct adapter *adapter = netdev_priv(dev);
+ struct slic_hostcmd *hcmd = NULL;
+ u32 status = 0;
+ u32 skbtype = NORMAL_ETHFRAME;
+ void *offloadcmd = NULL;
+
+ card = adapter->card;
+ ASSERT(card);
+ if ((adapter->linkstate != LINK_UP) ||
+ (adapter->state != ADAPT_UP) || (card->state != CARD_UP)) {
+ status = XMIT_FAIL_LINK_STATE;
+ goto xmit_fail;
+
+ } else if (skb->len == 0) {
+ status = XMIT_FAIL_ZERO_LENGTH;
+ goto xmit_fail;
+ }
+
+ if (skbtype == NORMAL_ETHFRAME) {
+ hcmd = slic_cmdq_getfree(adapter);
+ if (!hcmd) {
+ adapter->xmitq_full = 1;
+ status = XMIT_FAIL_HOSTCMD_FAIL;
+ goto xmit_fail;
+ }
+ ASSERT(hcmd->pslic_handle);
+ ASSERT(hcmd->cmd64.hosthandle ==
+ hcmd->pslic_handle->token.handle_token);
+ hcmd->skb = skb;
+ hcmd->busy = 1;
+ hcmd->type = SLIC_CMD_DUMB;
+ if (skbtype == NORMAL_ETHFRAME)
+ slic_xmit_build_request(adapter, hcmd, skb);
+ }
+ dev->stats.tx_packets++;
+ dev->stats.tx_bytes += skb->len;
+
+#ifdef DEBUG_DUMP
+ if (adapter->kill_card) {
+ struct slic_host64_cmd ihcmd;
+
+ ihcmd = &hcmd->cmd64;
+
+ ihcmd->flags |= 0x40;
+ adapter->kill_card = 0; /* only do this once */
+ }
+#endif
+ if (hcmd->paddrh == 0) {
+ slic_reg32_write(&adapter->slic_regs->slic_cbar,
+ (hcmd->paddrl | hcmd->cmdsize), DONT_FLUSH);
+ } else {
+ slic_reg64_write(adapter, &adapter->slic_regs->slic_cbar64,
+ (hcmd->paddrl | hcmd->cmdsize),
+ &adapter->slic_regs->slic_addr_upper,
+ hcmd->paddrh, DONT_FLUSH);
+ }
+xmit_done:
+ return NETDEV_TX_OK;
+xmit_fail:
+ slic_xmit_fail(adapter, skb, offloadcmd, skbtype, status);
+ goto xmit_done;
+}
+
+
+static void slic_adapter_freeresources(struct adapter *adapter)
+{
+ slic_init_cleanup(adapter);
+ adapter->error_interrupts = 0;
+ adapter->rcv_interrupts = 0;
+ adapter->xmit_interrupts = 0;
+ adapter->linkevent_interrupts = 0;
+ adapter->upr_interrupts = 0;
+ adapter->num_isrs = 0;
+ adapter->xmit_completes = 0;
+ adapter->rcv_broadcasts = 0;
+ adapter->rcv_multicasts = 0;
+ adapter->rcv_unicasts = 0;
+}
+
+static int slic_adapter_allocresources(struct adapter *adapter)
+{
+ if (!adapter->intrregistered) {
+ int retval;
+
+ spin_unlock_irqrestore(&slic_global.driver_lock.lock,
+ slic_global.driver_lock.flags);
+
+ retval = request_irq(adapter->netdev->irq,
+ &slic_interrupt,
+ IRQF_SHARED,
+ adapter->netdev->name, adapter->netdev);
+
+ spin_lock_irqsave(&slic_global.driver_lock.lock,
+ slic_global.driver_lock.flags);
+
+ if (retval) {
+ dev_err(&adapter->netdev->dev,
+ "request_irq (%s) FAILED [%x]\n",
+ adapter->netdev->name, retval);
+ return retval;
+ }
+ adapter->intrregistered = 1;
+ }
+ return 0;
+}
+
+/*
+ * slic_if_init
+ *
+ * Perform initialization of our slic interface.
+ *
+ */
+static int slic_if_init(struct adapter *adapter)
+{
+ struct sliccard *card = adapter->card;
+ struct net_device *dev = adapter->netdev;
+ __iomem struct slic_regs *slic_regs = adapter->slic_regs;
+ struct slic_shmem *pshmem;
+ int rc;
+
+ ASSERT(card);
+
+ /* adapter should be down at this point */
+ if (adapter->state != ADAPT_DOWN) {
+ dev_err(&dev->dev, "%s: adapter->state != ADAPT_DOWN\n",
+ __func__);
+ rc = -EIO;
+ goto err;
+ }
+ ASSERT(adapter->linkstate == LINK_DOWN);
+
+ adapter->devflags_prev = dev->flags;
+ adapter->macopts = MAC_DIRECTED;
+ if (dev->flags) {
+ if (dev->flags & IFF_BROADCAST)
+ adapter->macopts |= MAC_BCAST;
+ if (dev->flags & IFF_PROMISC)
+ adapter->macopts |= MAC_PROMISC;
+ if (dev->flags & IFF_ALLMULTI)
+ adapter->macopts |= MAC_ALLMCAST;
+ if (dev->flags & IFF_MULTICAST)
+ adapter->macopts |= MAC_MCAST;
+ }
+ rc = slic_adapter_allocresources(adapter);
+ if (rc) {
+ dev_err(&dev->dev,
+ "%s: slic_adapter_allocresources FAILED %x\n",
+ __func__, rc);
+ slic_adapter_freeresources(adapter);
+ goto err;
+ }
+
+ if (!adapter->queues_initialized) {
+ if ((rc = slic_rspqueue_init(adapter)))
+ goto err;
+ if ((rc = slic_cmdq_init(adapter)))
+ goto err;
+ if ((rc = slic_rcvqueue_init(adapter)))
+ goto err;
+ adapter->queues_initialized = 1;
+ }
+
+ slic_reg32_write(&slic_regs->slic_icr, ICR_INT_OFF, FLUSH);
+ mdelay(1);
+
+ if (!adapter->isp_initialized) {
+ pshmem = (struct slic_shmem *)adapter->phys_shmem;
+
+ spin_lock_irqsave(&adapter->bit64reglock.lock,
+ adapter->bit64reglock.flags);
+
+#if defined(CONFIG_X86_64)
+ slic_reg32_write(&slic_regs->slic_addr_upper,
+ SLIC_GET_ADDR_HIGH(&pshmem->isr), DONT_FLUSH);
+ slic_reg32_write(&slic_regs->slic_isp,
+ SLIC_GET_ADDR_LOW(&pshmem->isr), FLUSH);
+#elif defined(CONFIG_X86)
+ slic_reg32_write(&slic_regs->slic_addr_upper, 0, DONT_FLUSH);
+ slic_reg32_write(&slic_regs->slic_isp, (u32)&pshmem->isr, FLUSH);
+#else
+ Stop Compilations
+#endif
+ spin_unlock_irqrestore(&adapter->bit64reglock.lock,
+ adapter->bit64reglock.flags);
+ adapter->isp_initialized = 1;
+ }
+
+ adapter->state = ADAPT_UP;
+ if (!card->loadtimerset) {
+ init_timer(&card->loadtimer);
+ card->loadtimer.expires =
+ jiffies + (SLIC_LOADTIMER_PERIOD * HZ);
+ card->loadtimer.data = (ulong) card;
+ card->loadtimer.function = &slic_timer_load_check;
+ add_timer(&card->loadtimer);
+
+ card->loadtimerset = 1;
+ }
+
+ if (!adapter->pingtimerset) {
+ init_timer(&adapter->pingtimer);
+ adapter->pingtimer.expires =
+ jiffies + (PING_TIMER_INTERVAL * HZ);
+ adapter->pingtimer.data = (ulong) dev;
+ adapter->pingtimer.function = &slic_timer_ping;
+ add_timer(&adapter->pingtimer);
+ adapter->pingtimerset = 1;
+ adapter->card->pingstatus = ISR_PINGMASK;
+ }
+
+ /*
+ * clear any pending events, then enable interrupts
+ */
+ adapter->isrcopy = 0;
+ adapter->pshmem->isr = 0;
+ slic_reg32_write(&slic_regs->slic_isr, 0, FLUSH);
+ slic_reg32_write(&slic_regs->slic_icr, ICR_INT_ON, FLUSH);
+
+ slic_link_config(adapter, LINK_AUTOSPEED, LINK_AUTOD);
+ slic_link_event_handler(adapter);
+
+err:
+ return rc;
+}
+
+static int slic_entry_open(struct net_device *dev)
+{
+ struct adapter *adapter = netdev_priv(dev);
+ struct sliccard *card = adapter->card;
+ u32 locked = 0;
+ int status;
+
+ ASSERT(adapter);
+ ASSERT(card);
+
+ netif_stop_queue(adapter->netdev);
+
+ spin_lock_irqsave(&slic_global.driver_lock.lock,
+ slic_global.driver_lock.flags);
+ locked = 1;
+ if (!adapter->activated) {
+ card->adapters_activated++;
+ slic_global.num_slic_ports_active++;
+ adapter->activated = 1;
+ }
+ status = slic_if_init(adapter);
+
+ if (status != 0) {
+ if (adapter->activated) {
+ card->adapters_activated--;
+ slic_global.num_slic_ports_active--;
+ adapter->activated = 0;
+ }
+ if (locked) {
+ spin_unlock_irqrestore(&slic_global.driver_lock.lock,
+ slic_global.driver_lock.flags);
+ locked = 0;
+ }
+ return status;
+ }
+ if (!card->master)
+ card->master = adapter;
+
+ if (locked) {
+ spin_unlock_irqrestore(&slic_global.driver_lock.lock,
+ slic_global.driver_lock.flags);
+ locked = 0;
+ }
+
+ return 0;
+}
+
+static void slic_card_cleanup(struct sliccard *card)
+{
+ if (card->loadtimerset) {
+ card->loadtimerset = 0;
+ del_timer(&card->loadtimer);
+ }
+
+ slic_debug_card_destroy(card);
+
+ kfree(card);
+}
+
+static void __devexit slic_entry_remove(struct pci_dev *pcidev)
+{
+ struct net_device *dev = pci_get_drvdata(pcidev);
+ u32 mmio_start = 0;
+ uint mmio_len = 0;
+ struct adapter *adapter = netdev_priv(dev);
+ struct sliccard *card;
+ struct mcast_address *mcaddr, *mlist;
+
+ ASSERT(adapter);
+ slic_adapter_freeresources(adapter);
+ slic_unmap_mmio_space(adapter);
+ unregister_netdev(dev);
+
+ mmio_start = pci_resource_start(pcidev, 0);
+ mmio_len = pci_resource_len(pcidev, 0);
+
+ release_mem_region(mmio_start, mmio_len);
+
+ iounmap((void __iomem *)dev->base_addr);
+ /* free multicast addresses */
+ mlist = adapter->mcastaddrs;
+ while (mlist) {
+ mcaddr = mlist;
+ mlist = mlist->next;
+ kfree(mcaddr);
+ }
+ ASSERT(adapter->card);
+ card = adapter->card;
+ ASSERT(card->adapters_allocated);
+ card->adapters_allocated--;
+ adapter->allocated = 0;
+ if (!card->adapters_allocated) {
+ struct sliccard *curr_card = slic_global.slic_card;
+ if (curr_card == card) {
+ slic_global.slic_card = card->next;
+ } else {
+ while (curr_card->next != card)
+ curr_card = curr_card->next;
+ ASSERT(curr_card);
+ curr_card->next = card->next;
+ }
+ ASSERT(slic_global.num_slic_cards);
+ slic_global.num_slic_cards--;
+ slic_card_cleanup(card);
+ }
+ kfree(dev);
+ pci_release_regions(pcidev);
+}
+
+static int slic_entry_halt(struct net_device *dev)
+{
+ struct adapter *adapter = netdev_priv(dev);
+ struct sliccard *card = adapter->card;
+ __iomem struct slic_regs *slic_regs = adapter->slic_regs;
+
+ spin_lock_irqsave(&slic_global.driver_lock.lock,
+ slic_global.driver_lock.flags);
+ ASSERT(card);
+ netif_stop_queue(adapter->netdev);
+ adapter->state = ADAPT_DOWN;
+ adapter->linkstate = LINK_DOWN;
+ adapter->upr_list = NULL;
+ adapter->upr_busy = 0;
+ adapter->devflags_prev = 0;
+ ASSERT(card->adapter[adapter->cardindex] == adapter);
+ slic_reg32_write(&slic_regs->slic_icr, ICR_INT_OFF, FLUSH);
+ adapter->all_reg_writes++;
+ adapter->icr_reg_writes++;
+ slic_config_clear(adapter);
+ if (adapter->activated) {
+ card->adapters_activated--;
+ slic_global.num_slic_ports_active--;
+ adapter->activated = 0;
+ }
+#ifdef AUTOMATIC_RESET
+ slic_reg32_write(&slic_regs->slic_reset_iface, 0, FLUSH);
+#endif
+ /*
+ * Reset the adapter's cmd queues
+ */
+ slic_cmdq_reset(adapter);
+
+#ifdef AUTOMATIC_RESET
+ if (!card->adapters_activated)
+ slic_card_init(card, adapter);
+#endif
+
+ spin_unlock_irqrestore(&slic_global.driver_lock.lock,
+ slic_global.driver_lock.flags);
+ return 0;
+}
+
+static struct net_device_stats *slic_get_stats(struct net_device *dev)
+{
+ struct adapter *adapter = netdev_priv(dev);
+
+ ASSERT(adapter);
+ dev->stats.collisions = adapter->slic_stats.iface.xmit_collisions;
+ dev->stats.rx_errors = adapter->slic_stats.iface.rcv_errors;
+ dev->stats.tx_errors = adapter->slic_stats.iface.xmt_errors;
+ dev->stats.rx_missed_errors = adapter->slic_stats.iface.rcv_discards;
+ dev->stats.tx_heartbeat_errors = 0;
+ dev->stats.tx_aborted_errors = 0;
+ dev->stats.tx_window_errors = 0;
+ dev->stats.tx_fifo_errors = 0;
+ dev->stats.rx_frame_errors = 0;
+ dev->stats.rx_length_errors = 0;
+
+ return &dev->stats;
+}
+
+static int slic_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+{
+ struct adapter *adapter = netdev_priv(dev);
+ struct ethtool_cmd edata;
+ struct ethtool_cmd ecmd;
+ u32 data[7];
+ u32 intagg;
+
+ ASSERT(rq);
+ switch (cmd) {
+ case SIOCSLICSETINTAGG:
+ if (copy_from_user(data, rq->ifr_data, 28))
+ return -EFAULT;
+ intagg = data[0];
+ dev_err(&dev->dev, "%s: set interrupt aggregation to %d\n",
+ __func__, intagg);
+ slic_intagg_set(adapter, intagg);
+ return 0;
+
+#ifdef SLIC_TRACE_DUMP_ENABLED
+ case SIOCSLICTRACEDUMP:
+ {
+ u32 value;
+ DBG_IOCTL("slic_ioctl SIOCSLIC_TRACE_DUMP\n");
+
+ if (copy_from_user(data, rq->ifr_data, 28)) {
+ PRINT_ERROR
+ ("slic: copy_from_user FAILED getting initial simba param\n");
+ return -EFAULT;
+ }
+
+ value = data[0];
+ if (tracemon_request == SLIC_DUMP_DONE) {
+ PRINT_ERROR
+ ("ATK Diagnostic Trace Dump Requested\n");
+ tracemon_request = SLIC_DUMP_REQUESTED;
+ tracemon_request_type = value;
+ tracemon_timestamp = jiffies;
+ } else if ((tracemon_request == SLIC_DUMP_REQUESTED) ||
+ (tracemon_request ==
+ SLIC_DUMP_IN_PROGRESS)) {
+ PRINT_ERROR
+ ("ATK Diagnostic Trace Dump Requested but already in progress... ignore\n");
+ } else {
+ PRINT_ERROR
+ ("ATK Diagnostic Trace Dump Requested\n");
+ tracemon_request = SLIC_DUMP_REQUESTED;
+ tracemon_request_type = value;
+ tracemon_timestamp = jiffies;
+ }
+ return 0;
+ }
+#endif
+ case SIOCETHTOOL:
+ ASSERT(adapter);
+ if (copy_from_user(&ecmd, rq->ifr_data, sizeof(ecmd)))
+ return -EFAULT;
+
+ if (ecmd.cmd == ETHTOOL_GSET) {
+ edata.supported = (SUPPORTED_10baseT_Half |
+ SUPPORTED_10baseT_Full |
+ SUPPORTED_100baseT_Half |
+ SUPPORTED_100baseT_Full |
+ SUPPORTED_Autoneg | SUPPORTED_MII);
+ edata.port = PORT_MII;
+ edata.transceiver = XCVR_INTERNAL;
+ edata.phy_address = 0;
+ if (adapter->linkspeed == LINK_100MB)
+ edata.speed = SPEED_100;
+ else if (adapter->linkspeed == LINK_10MB)
+ edata.speed = SPEED_10;
+ else
+ edata.speed = 0;
+
+ if (adapter->linkduplex == LINK_FULLD)
+ edata.duplex = DUPLEX_FULL;
+ else
+ edata.duplex = DUPLEX_HALF;
+
+ edata.autoneg = AUTONEG_ENABLE;
+ edata.maxtxpkt = 1;
+ edata.maxrxpkt = 1;
+ if (copy_to_user(rq->ifr_data, &edata, sizeof(edata)))
+ return -EFAULT;
+
+ } else if (ecmd.cmd == ETHTOOL_SSET) {
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+
+ if (adapter->linkspeed == LINK_100MB)
+ edata.speed = SPEED_100;
+ else if (adapter->linkspeed == LINK_10MB)
+ edata.speed = SPEED_10;
+ else
+ edata.speed = 0;
+
+ if (adapter->linkduplex == LINK_FULLD)
+ edata.duplex = DUPLEX_FULL;
+ else
+ edata.duplex = DUPLEX_HALF;
+
+ edata.autoneg = AUTONEG_ENABLE;
+ edata.maxtxpkt = 1;
+ edata.maxrxpkt = 1;
+ if ((ecmd.speed != edata.speed) ||
+ (ecmd.duplex != edata.duplex)) {
+ u32 speed;
+ u32 duplex;
+
+ if (ecmd.speed == SPEED_10)
+ speed = 0;
+ else
+ speed = PCR_SPEED_100;
+ if (ecmd.duplex == DUPLEX_FULL)
+ duplex = PCR_DUPLEX_FULL;
+ else
+ duplex = 0;
+ slic_link_config(adapter, speed, duplex);
+ slic_link_event_handler(adapter);
+ }
+ }
+ return 0;
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
+static void slic_config_pci(struct pci_dev *pcidev)
+{
+ u16 pci_command;
+ u16 new_command;
+
+ pci_read_config_word(pcidev, PCI_COMMAND, &pci_command);
+
+ new_command = pci_command | PCI_COMMAND_MASTER
+ | PCI_COMMAND_MEMORY
+ | PCI_COMMAND_INVALIDATE
+ | PCI_COMMAND_PARITY | PCI_COMMAND_SERR | PCI_COMMAND_FAST_BACK;
+ if (pci_command != new_command)
+ pci_write_config_word(pcidev, PCI_COMMAND, new_command);
+}
+
+static int slic_card_init(struct sliccard *card, struct adapter *adapter)
+{
+ __iomem struct slic_regs *slic_regs = adapter->slic_regs;
+ struct slic_eeprom *peeprom;
+ struct oslic_eeprom *pOeeprom;
+ dma_addr_t phys_config;
+ u32 phys_configh;
+ u32 phys_configl;
+ u32 i = 0;
+ struct slic_shmem *pshmem;
+ int status;
+ uint macaddrs = card->card_size;
+ ushort eecodesize;
+ ushort dramsize;
+ ushort ee_chksum;
+ ushort calc_chksum;
+ struct slic_config_mac *pmac;
+ unsigned char fruformat;
+ unsigned char oemfruformat;
+ struct atk_fru *patkfru;
+ union oemfru *poemfru;
+
+ /* Reset everything except PCI configuration space */
+ slic_soft_reset(adapter);
+
+ /* Download the microcode */
+ status = slic_card_download(adapter);
+
+ if (status != 0) {
+ dev_err(&adapter->pcidev->dev,
+ "download failed bus %d slot %d\n",
+ adapter->busnumber, adapter->slotnumber);
+ return status;
+ }
+
+ if (!card->config_set) {
+ peeprom = pci_alloc_consistent(adapter->pcidev,
+ sizeof(struct slic_eeprom),
+ &phys_config);
+
+ phys_configl = SLIC_GET_ADDR_LOW(phys_config);
+ phys_configh = SLIC_GET_ADDR_HIGH(phys_config);
+
+ if (!peeprom) {
+ dev_err(&adapter->pcidev->dev,
+ "eeprom read failed to get memory "
+ "bus %d slot %d\n", adapter->busnumber,
+ adapter->slotnumber);
+ return -ENOMEM;
+ } else {
+ memset(peeprom, 0, sizeof(struct slic_eeprom));
+ }
+ slic_reg32_write(&slic_regs->slic_icr, ICR_INT_OFF, FLUSH);
+ mdelay(1);
+ pshmem = (struct slic_shmem *)adapter->phys_shmem;
+
+ spin_lock_irqsave(&adapter->bit64reglock.lock,
+ adapter->bit64reglock.flags);
+ slic_reg32_write(&slic_regs->slic_addr_upper, 0, DONT_FLUSH);
+ slic_reg32_write(&slic_regs->slic_isp,
+ SLIC_GET_ADDR_LOW(&pshmem->isr), FLUSH);
+ spin_unlock_irqrestore(&adapter->bit64reglock.lock,
+ adapter->bit64reglock.flags);
+
+ slic_config_get(adapter, phys_configl, phys_configh);
+
+ for (;;) {
+ if (adapter->pshmem->isr) {
+ if (adapter->pshmem->isr & ISR_UPC) {
+ adapter->pshmem->isr = 0;
+ slic_reg64_write(adapter,
+ &slic_regs->slic_isp, 0,
+ &slic_regs->slic_addr_upper,
+ 0, FLUSH);
+ slic_reg32_write(&slic_regs->slic_isr,
+ 0, FLUSH);
+
+ slic_upr_request_complete(adapter, 0);
+ break;
+ } else {
+ adapter->pshmem->isr = 0;
+ slic_reg32_write(&slic_regs->slic_isr,
+ 0, FLUSH);
+ }
+ } else {
+ mdelay(1);
+ i++;
+ if (i > 5000) {
+ dev_err(&adapter->pcidev->dev,
+ "%d config data fetch timed out!\n",
+ adapter->port);
+ slic_reg64_write(adapter,
+ &slic_regs->slic_isp, 0,
+ &slic_regs->slic_addr_upper,
+ 0, FLUSH);
+ return -EINVAL;
+ }
+ }
+ }
+
+ switch (adapter->devid) {
+ /* Oasis card */
+ case SLIC_2GB_DEVICE_ID:
+ /* extract EEPROM data and pointers to EEPROM data */
+ pOeeprom = (struct oslic_eeprom *) peeprom;
+ eecodesize = pOeeprom->EecodeSize;
+ dramsize = pOeeprom->DramSize;
+ pmac = pOeeprom->MacInfo;
+ fruformat = pOeeprom->FruFormat;
+ patkfru = &pOeeprom->AtkFru;
+ oemfruformat = pOeeprom->OemFruFormat;
+ poemfru = &pOeeprom->OemFru;
+ macaddrs = 2;
+ /* Minor kludge for Oasis card
+ get 2 MAC addresses from the
+ EEPROM to ensure that function 1
+ gets the Port 1 MAC address */
+ break;
+ default:
+ /* extract EEPROM data and pointers to EEPROM data */
+ eecodesize = peeprom->EecodeSize;
+ dramsize = peeprom->DramSize;
+ pmac = peeprom->u2.mac.MacInfo;
+ fruformat = peeprom->FruFormat;
+ patkfru = &peeprom->AtkFru;
+ oemfruformat = peeprom->OemFruFormat;
+ poemfru = &peeprom->OemFru;
+ break;
+ }
+
+ card->config.EepromValid = false;
+
+ /* see if the EEPROM is valid by checking it's checksum */
+ if ((eecodesize <= MAX_EECODE_SIZE) &&
+ (eecodesize >= MIN_EECODE_SIZE)) {
+
+ ee_chksum =
+ *(u16 *) ((char *) peeprom + (eecodesize - 2));
+ /*
+ calculate the EEPROM checksum
+ */
+ calc_chksum =
+ ~slic_eeprom_cksum((char *) peeprom,
+ (eecodesize - 2));
+ /*
+ if the ucdoe chksum flag bit worked,
+ we wouldn't need this shit
+ */
+ if (ee_chksum == calc_chksum)
+ card->config.EepromValid = true;
+ }
+ /* copy in the DRAM size */
+ card->config.DramSize = dramsize;
+
+ /* copy in the MAC address(es) */
+ for (i = 0; i < macaddrs; i++) {
+ memcpy(&card->config.MacInfo[i],
+ &pmac[i], sizeof(struct slic_config_mac));
+ }
+
+ /* copy the Alacritech FRU information */
+ card->config.FruFormat = fruformat;
+ memcpy(&card->config.AtkFru, patkfru,
+ sizeof(struct atk_fru));
+
+ pci_free_consistent(adapter->pcidev,
+ sizeof(struct slic_eeprom),
+ peeprom, phys_config);
+
+ if ((!card->config.EepromValid) &&
+ (adapter->reg_params.fail_on_bad_eeprom)) {
+ slic_reg64_write(adapter, &slic_regs->slic_isp, 0,
+ &slic_regs->slic_addr_upper,
+ 0, FLUSH);
+ dev_err(&adapter->pcidev->dev,
+ "unsupported CONFIGURATION EEPROM invalid\n");
+ return -EINVAL;
+ }
+
+ card->config_set = 1;
+ }
+
+ if (slic_card_download_gbrcv(adapter)) {
+ dev_err(&adapter->pcidev->dev,
+ "unable to download GB receive microcode\n");
+ return -EINVAL;
+ }
+
+ if (slic_global.dynamic_intagg)
+ slic_intagg_set(adapter, 0);
+ else
+ slic_intagg_set(adapter, intagg_delay);
+
+ /*
+ * Initialize ping status to "ok"
+ */
+ card->pingstatus = ISR_PINGMASK;
+
+ /*
+ * Lastly, mark our card state as up and return success
+ */
+ card->state = CARD_UP;
+ card->reset_in_progress = 0;
+
+ return 0;
+}
+
+static void slic_init_driver(void)
+{
+ if (slic_first_init) {
+ slic_first_init = 0;
+ spin_lock_init(&slic_global.driver_lock.lock);
+ slic_debug_init();
+ }
+}
+
+static void slic_init_adapter(struct net_device *netdev,
+ struct pci_dev *pcidev,
+ const struct pci_device_id *pci_tbl_entry,
+ void __iomem *memaddr, int chip_idx)
+{
+ ushort index;
+ struct slic_handle *pslic_handle;
+ struct adapter *adapter = netdev_priv(netdev);
+
+/* adapter->pcidev = pcidev;*/
+ adapter->vendid = pci_tbl_entry->vendor;
+ adapter->devid = pci_tbl_entry->device;
+ adapter->subsysid = pci_tbl_entry->subdevice;
+ adapter->busnumber = pcidev->bus->number;
+ adapter->slotnumber = ((pcidev->devfn >> 3) & 0x1F);
+ adapter->functionnumber = (pcidev->devfn & 0x7);
+ adapter->memorylength = pci_resource_len(pcidev, 0);
+ adapter->slic_regs = (__iomem struct slic_regs *)memaddr;
+ adapter->irq = pcidev->irq;
+/* adapter->netdev = netdev;*/
+ adapter->next_netdevice = head_netdevice;
+ head_netdevice = netdev;
+ adapter->chipid = chip_idx;
+ adapter->port = 0; /*adapter->functionnumber;*/
+ adapter->cardindex = adapter->port;
+ adapter->memorybase = memaddr;
+ spin_lock_init(&adapter->upr_lock.lock);
+ spin_lock_init(&adapter->bit64reglock.lock);
+ spin_lock_init(&adapter->adapter_lock.lock);
+ spin_lock_init(&adapter->reset_lock.lock);
+ spin_lock_init(&adapter->handle_lock.lock);
+
+ adapter->card_size = 1;
+ /*
+ Initialize slic_handle array
+ */
+ ASSERT(SLIC_CMDQ_MAXCMDS <= 0xFFFF);
+ /*
+ Start with 1. 0 is an invalid host handle.
+ */
+ for (index = 1, pslic_handle = &adapter->slic_handles[1];
+ index < SLIC_CMDQ_MAXCMDS; index++, pslic_handle++) {
+
+ pslic_handle->token.handle_index = index;
+ pslic_handle->type = SLIC_HANDLE_FREE;
+ pslic_handle->next = adapter->pfree_slic_handles;
+ adapter->pfree_slic_handles = pslic_handle;
+ }
+ adapter->pshmem = (struct slic_shmem *)
+ pci_alloc_consistent(adapter->pcidev,
+ sizeof(struct slic_shmem),
+ &adapter->
+ phys_shmem);
+ ASSERT(adapter->pshmem);
+
+ memset(adapter->pshmem, 0, sizeof(struct slic_shmem));
+
+ return;
+}
+
+static const struct net_device_ops slic_netdev_ops = {
+ .ndo_open = slic_entry_open,
+ .ndo_stop = slic_entry_halt,
+ .ndo_start_xmit = slic_xmit_start,
+ .ndo_do_ioctl = slic_ioctl,
+ .ndo_set_mac_address = slic_mac_set_address,
+ .ndo_get_stats = slic_get_stats,
+ .ndo_set_multicast_list = slic_mcast_set_list,
+ .ndo_validate_addr = eth_validate_addr,
+ .ndo_change_mtu = eth_change_mtu,
+};
+
+static u32 slic_card_locate(struct adapter *adapter)
+{
+ struct sliccard *card = slic_global.slic_card;
+ struct physcard *physcard = slic_global.phys_card;
+ ushort card_hostid;
+ u16 __iomem *hostid_reg;
+ uint i;
+ uint rdhostid_offset = 0;
+
+ switch (adapter->devid) {
+ case SLIC_2GB_DEVICE_ID:
+ rdhostid_offset = SLIC_RDHOSTID_2GB;
+ break;
+ case SLIC_1GB_DEVICE_ID:
+ rdhostid_offset = SLIC_RDHOSTID_1GB;
+ break;
+ default:
+ ASSERT(0);
+ break;
+ }
+
+ hostid_reg =
+ (u16 __iomem *) (((u8 __iomem *) (adapter->slic_regs)) +
+ rdhostid_offset);
+
+ /* read the 16 bit hostid from SRAM */
+ card_hostid = (ushort) readw(hostid_reg);
+
+ /* Initialize a new card structure if need be */
+ if (card_hostid == SLIC_HOSTID_DEFAULT) {
+ card = kzalloc(sizeof(struct sliccard), GFP_KERNEL);
+ if (card == NULL)
+ return -ENOMEM;
+
+ card->next = slic_global.slic_card;
+ slic_global.slic_card = card;
+ card->busnumber = adapter->busnumber;
+ card->slotnumber = adapter->slotnumber;
+
+ /* Find an available cardnum */
+ for (i = 0; i < SLIC_MAX_CARDS; i++) {
+ if (slic_global.cardnuminuse[i] == 0) {
+ slic_global.cardnuminuse[i] = 1;
+ card->cardnum = i;
+ break;
+ }
+ }
+ slic_global.num_slic_cards++;
+
+ slic_debug_card_create(card);
+ } else {
+ /* Card exists, find the card this adapter belongs to */
+ while (card) {
+ if (card->cardnum == card_hostid)
+ break;
+ card = card->next;
+ }
+ }
+
+ ASSERT(card);
+ if (!card)
+ return -ENXIO;
+ /* Put the adapter in the card's adapter list */
+ ASSERT(card->adapter[adapter->port] == NULL);
+ if (!card->adapter[adapter->port]) {
+ card->adapter[adapter->port] = adapter;
+ adapter->card = card;
+ }
+
+ card->card_size = 1; /* one port per *logical* card */
+
+ while (physcard) {
+ for (i = 0; i < SLIC_MAX_PORTS; i++) {
+ if (!physcard->adapter[i])
+ continue;
+ else
+ break;
+ }
+ ASSERT(i != SLIC_MAX_PORTS);
+ if (physcard->adapter[i]->slotnumber == adapter->slotnumber)
+ break;
+ physcard = physcard->next;
+ }
+ if (!physcard) {
+ /* no structure allocated for this physical card yet */
+ physcard = kzalloc(sizeof(struct physcard), GFP_ATOMIC);
+ ASSERT(physcard);
+
+ physcard->next = slic_global.phys_card;
+ slic_global.phys_card = physcard;
+ physcard->adapters_allocd = 1;
+ } else {
+ physcard->adapters_allocd++;
+ }
+ /* Note - this is ZERO relative */
+ adapter->physport = physcard->adapters_allocd - 1;
+
+ ASSERT(physcard->adapter[adapter->physport] == NULL);
+ physcard->adapter[adapter->physport] = adapter;
+ adapter->physcard = physcard;
+
+ return 0;
+}
+
+static int __devinit slic_entry_probe(struct pci_dev *pcidev,
+ const struct pci_device_id *pci_tbl_entry)
+{
+ static int cards_found;
+ static int did_version;
+ int err = -ENODEV;
+ struct net_device *netdev;
+ struct adapter *adapter;
+ void __iomem *memmapped_ioaddr = NULL;
+ u32 status = 0;
+ ulong mmio_start = 0;
+ ulong mmio_len = 0;
+ struct sliccard *card = NULL;
+ int pci_using_dac = 0;
+
+ slic_global.dynamic_intagg = dynamic_intagg;
+
+ err = pci_enable_device(pcidev);
+
+ if (err)
+ return err;
+
+ if (slic_debug > 0 && did_version++ == 0) {
+ printk(KERN_DEBUG "%s\n", slic_banner);
+ printk(KERN_DEBUG "%s\n", slic_proc_version);
+ }
+
+ if (!pci_set_dma_mask(pcidev, DMA_BIT_MASK(64))) {
+ pci_using_dac = 1;
+ if (pci_set_consistent_dma_mask(pcidev, DMA_BIT_MASK(64))) {
+ dev_err(&pcidev->dev, "unable to obtain 64-bit DMA for "
+ "consistent allocations\n");
+ goto err_out_disable_pci;
+ }
+ } else if (pci_set_dma_mask(pcidev, DMA_BIT_MASK(32))) {
+ pci_using_dac = 0;
+ pci_set_consistent_dma_mask(pcidev, DMA_BIT_MASK(32));
+ } else {
+ dev_err(&pcidev->dev, "no usable DMA configuration\n");
+ goto err_out_disable_pci;
+ }
+
+ err = pci_request_regions(pcidev, DRV_NAME);
+ if (err) {
+ dev_err(&pcidev->dev, "can't obtain PCI resources\n");
+ goto err_out_disable_pci;
+ }
+
+ pci_set_master(pcidev);
+
+ netdev = alloc_etherdev(sizeof(struct adapter));
+ if (!netdev) {
+ err = -ENOMEM;
+ goto err_out_exit_slic_probe;
+ }
+
+ SET_NETDEV_DEV(netdev, &pcidev->dev);
+
+ pci_set_drvdata(pcidev, netdev);
+ adapter = netdev_priv(netdev);
+ adapter->netdev = netdev;
+ adapter->pcidev = pcidev;
+ if (pci_using_dac)
+ netdev->features |= NETIF_F_HIGHDMA;
+
+ mmio_start = pci_resource_start(pcidev, 0);
+ mmio_len = pci_resource_len(pcidev, 0);
+
+
+/* memmapped_ioaddr = (u32)ioremap_nocache(mmio_start, mmio_len);*/
+ memmapped_ioaddr = ioremap(mmio_start, mmio_len);
+ if (!memmapped_ioaddr) {
+ dev_err(&pcidev->dev, "cannot remap MMIO region %lx @ %lx\n",
+ mmio_len, mmio_start);
+ goto err_out_free_netdev;
+ }
+
+ slic_config_pci(pcidev);
+
+ slic_init_driver();
+
+ slic_init_adapter(netdev,
+ pcidev, pci_tbl_entry, memmapped_ioaddr, cards_found);
+
+ status = slic_card_locate(adapter);
+ if (status) {
+ dev_err(&pcidev->dev, "cannot locate card\n");
+ goto err_out_free_mmio_region;
+ }
+
+ card = adapter->card;
+
+ if (!adapter->allocated) {
+ card->adapters_allocated++;
+ adapter->allocated = 1;
+ }
+
+ status = slic_card_init(card, adapter);
+
+ if (status != 0) {
+ card->state = CARD_FAIL;
+ adapter->state = ADAPT_FAIL;
+ adapter->linkstate = LINK_DOWN;
+ dev_err(&pcidev->dev, "FAILED status[%x]\n", status);
+ } else {
+ slic_adapter_set_hwaddr(adapter);
+ }
+
+ netdev->base_addr = (unsigned long)adapter->memorybase;
+ netdev->irq = adapter->irq;
+ netdev->netdev_ops = &slic_netdev_ops;
+
+ slic_debug_adapter_create(adapter);
+
+ strcpy(netdev->name, "eth%d");
+ err = register_netdev(netdev);
+ if (err) {
+ dev_err(&pcidev->dev, "Cannot register net device, aborting.\n");
+ goto err_out_unmap;
+ }
+
+ cards_found++;
+
+ return status;
+
+err_out_unmap:
+ iounmap(memmapped_ioaddr);
+err_out_free_mmio_region:
+ release_mem_region(mmio_start, mmio_len);
+err_out_free_netdev:
+ free_netdev(netdev);
+err_out_exit_slic_probe:
+ pci_release_regions(pcidev);
+err_out_disable_pci:
+ pci_disable_device(pcidev);
+ return err;
+}
static struct pci_driver slic_driver = {
.name = DRV_NAME,
diff --git a/drivers/staging/sm7xx/smtcfb.c b/drivers/staging/sm7xx/smtcfb.c
index 9ffeb36ddde..f6b401c0ccc 100644
--- a/drivers/staging/sm7xx/smtcfb.c
+++ b/drivers/staging/sm7xx/smtcfb.c
@@ -835,7 +835,7 @@ __setup("vga=", sm712vga_setup);
* Original init function changed to probe method to be used by pci_drv
* process used to detect chips replaced with kernel process in pci_drv
*/
-static int __init smtcfb_pci_probe(struct pci_dev *pdev,
+static int __devinit smtcfb_pci_probe(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
struct smtcfb_info *sfb;
diff --git a/drivers/staging/solo6x10/Kconfig b/drivers/staging/solo6x10/Kconfig
new file mode 100644
index 00000000000..d96398c701f
--- /dev/null
+++ b/drivers/staging/solo6x10/Kconfig
@@ -0,0 +1,7 @@
+config SOLO6X10
+ tristate "Softlogic 6x10 MPEG codec cards"
+ depends on PCI && VIDEO_DEV && SND
+ select VIDEOBUF_DMA_CONTIG
+ ---help---
+ This driver supports the Softlogic based MPEG-4 and h.264 codec
+ codec cards.
diff --git a/drivers/staging/solo6x10/Makefile b/drivers/staging/solo6x10/Makefile
new file mode 100644
index 00000000000..7e70044d8da
--- /dev/null
+++ b/drivers/staging/solo6x10/Makefile
@@ -0,0 +1,6 @@
+solo6x10-objs := solo6010-core.o solo6010-i2c.o solo6010-p2m.o \
+ solo6010-v4l2.o solo6010-tw28.o solo6010-gpio.o \
+ solo6010-disp.o solo6010-enc.o solo6010-v4l2-enc.o \
+ solo6010-g723.o
+
+obj-$(CONFIG_SOLO6X10) := solo6x10.o
diff --git a/drivers/staging/solo6x10/TODO b/drivers/staging/solo6x10/TODO
new file mode 100644
index 00000000000..e6a2ee22674
--- /dev/null
+++ b/drivers/staging/solo6x10/TODO
@@ -0,0 +1,28 @@
+TODO (staging => main):
+
+ * checkpatch.pl (haven't run it yet)
+ * Lindent (should be clean, but check)
+ * Motion detection flags need to be moved to v4l2
+ * Some private CIDs need to be moved to v4l2
+
+TODO (general):
+
+ * encoder on/off controls
+ * mpeg cid bitrate mode (vbr/cbr)
+ * mpeg cid bitrate/bitrate-peak
+ * mpeg encode of user data
+ * mpeg decode of user data
+ * switch between 4 frames/irq to 1 when using mjpeg (and then back
+ when not)
+ * implement a CID control for motion areas/thresholds
+ * implement CID controls for mozaic areas
+ * allow for higher level of interval (for < 1 fps)
+ * sound:
+ - implement playback via external sound jack
+ - implement loopback of external sound jack with incoming audio?
+ - implement pause/resume
+ - check into jacking sound from tx28xx chips directly (to avoid
+ g.723/8khz limitations)
+
+Plase send patches to Greg Kroah-Hartman <greg@kroah.com> and Cc Ben Collins
+<bcollins@bluecherry.net>
diff --git a/drivers/staging/solo6x10/solo6010-core.c b/drivers/staging/solo6x10/solo6010-core.c
new file mode 100644
index 00000000000..98c6739fc19
--- /dev/null
+++ b/drivers/staging/solo6x10/solo6010-core.c
@@ -0,0 +1,282 @@
+/*
+ * Copyright (C) 2010 Bluecherry, LLC www.bluecherrydvr.com
+ * Copyright (C) 2010 Ben Collins <bcollins@bluecherry.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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/interrupt.h>
+#include <linux/videodev2.h>
+
+#include "solo6010.h"
+#include "solo6010-tw28.h"
+
+MODULE_DESCRIPTION("Softlogic 6010 MP4 Encoder/Decoder V4L2/ALSA Driver");
+MODULE_AUTHOR("Ben Collins <bcollins@bluecherry.net>");
+MODULE_VERSION(SOLO6010_VERSION);
+MODULE_LICENSE("GPL");
+
+void solo6010_irq_on(struct solo6010_dev *solo_dev, u32 mask)
+{
+ solo_dev->irq_mask |= mask;
+ solo_reg_write(solo_dev, SOLO_IRQ_ENABLE, solo_dev->irq_mask);
+}
+
+void solo6010_irq_off(struct solo6010_dev *solo_dev, u32 mask)
+{
+ solo_dev->irq_mask &= ~mask;
+ solo_reg_write(solo_dev, SOLO_IRQ_ENABLE, solo_dev->irq_mask);
+}
+
+/* XXX We should check the return value of the sub-device ISR's */
+static irqreturn_t solo6010_isr(int irq, void *data)
+{
+ struct solo6010_dev *solo_dev = data;
+ u32 status;
+ int i;
+
+ status = solo_reg_read(solo_dev, SOLO_IRQ_STAT);
+ if (!status)
+ return IRQ_NONE;
+
+ if (status & ~solo_dev->irq_mask) {
+ solo_reg_write(solo_dev, SOLO_IRQ_STAT,
+ status & ~solo_dev->irq_mask);
+ status &= solo_dev->irq_mask;
+ }
+
+ if (status & SOLO_IRQ_PCI_ERR) {
+ u32 err = solo_reg_read(solo_dev, SOLO_PCI_ERR);
+ solo_p2m_error_isr(solo_dev, err);
+ solo_reg_write(solo_dev, SOLO_IRQ_STAT, SOLO_IRQ_PCI_ERR);
+ }
+
+ for (i = 0; i < SOLO_NR_P2M; i++)
+ if (status & SOLO_IRQ_P2M(i))
+ solo_p2m_isr(solo_dev, i);
+
+ if (status & SOLO_IRQ_IIC)
+ solo_i2c_isr(solo_dev);
+
+ if (status & SOLO_IRQ_VIDEO_IN)
+ solo_video_in_isr(solo_dev);
+
+ /* Call this first so enc gets detected flag set */
+ if (status & SOLO_IRQ_MOTION)
+ solo_motion_isr(solo_dev);
+
+ if (status & SOLO_IRQ_ENCODER)
+ solo_enc_v4l2_isr(solo_dev);
+
+ if (status & SOLO_IRQ_G723)
+ solo_g723_isr(solo_dev);
+
+ return IRQ_HANDLED;
+}
+
+static void free_solo_dev(struct solo6010_dev *solo_dev)
+{
+ struct pci_dev *pdev;
+
+ if (!solo_dev)
+ return;
+
+ pdev = solo_dev->pdev;
+
+ /* If we never initialized the PCI device, then nothing else
+ * below here needs cleanup */
+ if (!pdev) {
+ kfree(solo_dev);
+ return;
+ }
+
+ /* Bring down the sub-devices first */
+ solo_g723_exit(solo_dev);
+ solo_enc_v4l2_exit(solo_dev);
+ solo_enc_exit(solo_dev);
+ solo_v4l2_exit(solo_dev);
+ solo_disp_exit(solo_dev);
+ solo_gpio_exit(solo_dev);
+ solo_p2m_exit(solo_dev);
+ solo_i2c_exit(solo_dev);
+
+ /* Now cleanup the PCI device */
+ if (solo_dev->reg_base) {
+ solo6010_irq_off(solo_dev, ~0);
+ pci_iounmap(pdev, solo_dev->reg_base);
+ free_irq(pdev->irq, solo_dev);
+ }
+
+ pci_release_regions(pdev);
+ pci_disable_device(pdev);
+ pci_set_drvdata(pdev, NULL);
+
+ kfree(solo_dev);
+}
+
+static int __devinit solo6010_pci_probe(struct pci_dev *pdev,
+ const struct pci_device_id *id)
+{
+ struct solo6010_dev *solo_dev;
+ int ret;
+ int sdram;
+ u8 chip_id;
+
+ if ((solo_dev = kzalloc(sizeof(*solo_dev), GFP_KERNEL)) == NULL)
+ return -ENOMEM;
+
+ solo_dev->pdev = pdev;
+ spin_lock_init(&solo_dev->reg_io_lock);
+ pci_set_drvdata(pdev, solo_dev);
+
+ if ((ret = pci_enable_device(pdev)))
+ goto fail_probe;
+
+ pci_set_master(pdev);
+
+ if ((ret = pci_request_regions(pdev, SOLO6010_NAME)))
+ goto fail_probe;
+
+ if ((solo_dev->reg_base = pci_ioremap_bar(pdev, 0)) == NULL) {
+ ret = -ENOMEM;
+ goto fail_probe;
+ }
+
+ chip_id = solo_reg_read(solo_dev, SOLO_CHIP_OPTION) &
+ SOLO_CHIP_ID_MASK;
+ switch (chip_id) {
+ case 7:
+ solo_dev->nr_chans = 16;
+ solo_dev->nr_ext = 5;
+ break;
+ case 6:
+ solo_dev->nr_chans = 8;
+ solo_dev->nr_ext = 2;
+ break;
+ default:
+ dev_warn(&pdev->dev, "Invalid chip_id 0x%02x, "
+ "defaulting to 4 channels\n",
+ chip_id);
+ case 5:
+ solo_dev->nr_chans = 4;
+ solo_dev->nr_ext = 1;
+ }
+
+ /* Disable all interrupts to start */
+ solo6010_irq_off(solo_dev, ~0);
+
+ /* Initial global settings */
+ solo_reg_write(solo_dev, SOLO_SYS_CFG, SOLO_SYS_CFG_SDRAM64BIT |
+ SOLO_SYS_CFG_INPUTDIV(25) |
+ SOLO_SYS_CFG_FEEDBACKDIV((SOLO_CLOCK_MHZ * 2) - 2) |
+ SOLO_SYS_CFG_OUTDIV(3));
+ solo_reg_write(solo_dev, SOLO_TIMER_CLOCK_NUM, SOLO_CLOCK_MHZ - 1);
+
+ /* PLL locking time of 1ms */
+ mdelay(1);
+
+ ret = request_irq(pdev->irq, solo6010_isr, IRQF_SHARED, SOLO6010_NAME,
+ solo_dev);
+ if (ret)
+ goto fail_probe;
+
+ /* Handle this from the start */
+ solo6010_irq_on(solo_dev, SOLO_IRQ_PCI_ERR);
+
+ if ((ret = solo_i2c_init(solo_dev)))
+ goto fail_probe;
+
+ /* Setup the DMA engine */
+ sdram = (solo_dev->nr_chans >= 8) ? 2 : 1;
+ solo_reg_write(solo_dev, SOLO_DMA_CTRL,
+ SOLO_DMA_CTRL_REFRESH_CYCLE(1) |
+ SOLO_DMA_CTRL_SDRAM_SIZE(sdram) |
+ SOLO_DMA_CTRL_SDRAM_CLK_INVERT |
+ SOLO_DMA_CTRL_READ_CLK_SELECT |
+ SOLO_DMA_CTRL_LATENCY(1));
+
+ if ((ret = solo_p2m_init(solo_dev)))
+ goto fail_probe;
+
+ if ((ret = solo_disp_init(solo_dev)))
+ goto fail_probe;
+
+ if ((ret = solo_gpio_init(solo_dev)))
+ goto fail_probe;
+
+ if ((ret = solo_tw28_init(solo_dev)))
+ goto fail_probe;
+
+ if ((ret = solo_v4l2_init(solo_dev)))
+ goto fail_probe;
+
+ if ((ret = solo_enc_init(solo_dev)))
+ goto fail_probe;
+
+ if ((ret = solo_enc_v4l2_init(solo_dev)))
+ goto fail_probe;
+
+ if ((ret = solo_g723_init(solo_dev)))
+ goto fail_probe;
+
+ return 0;
+
+fail_probe:
+ free_solo_dev(solo_dev);
+ return ret;
+}
+
+static void __devexit solo6010_pci_remove(struct pci_dev *pdev)
+{
+ struct solo6010_dev *solo_dev = pci_get_drvdata(pdev);
+
+ free_solo_dev(solo_dev);
+}
+
+static struct pci_device_id solo6010_id_table[] = {
+ {PCI_DEVICE(PCI_VENDOR_ID_SOFTLOGIC, PCI_DEVICE_ID_SOLO6010)},
+ {PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_NEUSOLO_4)},
+ {PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_NEUSOLO_9)},
+ {PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_NEUSOLO_16)},
+ {PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_COMMSOLO_4)},
+ {PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_COMMSOLO_9)},
+ {PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_COMMSOLO_16)},
+ {0,}
+};
+
+MODULE_DEVICE_TABLE(pci, solo6010_id_table);
+
+static struct pci_driver solo6010_pci_driver = {
+ .name = SOLO6010_NAME,
+ .id_table = solo6010_id_table,
+ .probe = solo6010_pci_probe,
+ .remove = solo6010_pci_remove,
+};
+
+static int __init solo6010_module_init(void)
+{
+ return pci_register_driver(&solo6010_pci_driver);
+}
+
+static void __exit solo6010_module_exit(void)
+{
+ pci_unregister_driver(&solo6010_pci_driver);
+}
+
+module_init(solo6010_module_init);
+module_exit(solo6010_module_exit);
diff --git a/drivers/staging/solo6x10/solo6010-disp.c b/drivers/staging/solo6x10/solo6010-disp.c
new file mode 100644
index 00000000000..555f024f72e
--- /dev/null
+++ b/drivers/staging/solo6x10/solo6010-disp.c
@@ -0,0 +1,271 @@
+/*
+ * Copyright (C) 2010 Bluecherry, LLC www.bluecherrydvr.com
+ * Copyright (C) 2010 Ben Collins <bcollins@bluecherry.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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-ioctl.h>
+
+#include "solo6010.h"
+
+#define SOLO_VCLK_DELAY 3
+#define SOLO_PROGRESSIVE_VSIZE 1024
+
+#define SOLO_MOT_THRESH_W 64
+#define SOLO_MOT_THRESH_H 64
+#define SOLO_MOT_THRESH_SIZE 8192
+#define SOLO_MOT_THRESH_REAL (SOLO_MOT_THRESH_W * SOLO_MOT_THRESH_H)
+#define SOLO_MOT_FLAG_SIZE 512
+#define SOLO_MOT_FLAG_AREA (SOLO_MOT_FLAG_SIZE * 32)
+
+static unsigned video_type;
+module_param(video_type, uint, 0644);
+MODULE_PARM_DESC(video_type, "video_type (0 = NTSC/Default, 1 = PAL)");
+
+static void solo_vin_config(struct solo6010_dev *solo_dev)
+{
+ solo_dev->vin_hstart = 8;
+ solo_dev->vin_vstart = 2;
+
+ solo_reg_write(solo_dev, SOLO_SYS_VCLK,
+ SOLO_VCLK_SELECT(2) |
+ SOLO_VCLK_VIN1415_DELAY(SOLO_VCLK_DELAY) |
+ SOLO_VCLK_VIN1213_DELAY(SOLO_VCLK_DELAY) |
+ SOLO_VCLK_VIN1011_DELAY(SOLO_VCLK_DELAY) |
+ SOLO_VCLK_VIN0809_DELAY(SOLO_VCLK_DELAY) |
+ SOLO_VCLK_VIN0607_DELAY(SOLO_VCLK_DELAY) |
+ SOLO_VCLK_VIN0405_DELAY(SOLO_VCLK_DELAY) |
+ SOLO_VCLK_VIN0203_DELAY(SOLO_VCLK_DELAY) |
+ SOLO_VCLK_VIN0001_DELAY(SOLO_VCLK_DELAY));
+
+ solo_reg_write(solo_dev, SOLO_VI_ACT_I_P,
+ SOLO_VI_H_START(solo_dev->vin_hstart) |
+ SOLO_VI_V_START(solo_dev->vin_vstart) |
+ SOLO_VI_V_STOP(solo_dev->vin_vstart +
+ solo_dev->video_vsize));
+
+ solo_reg_write(solo_dev, SOLO_VI_ACT_I_S,
+ SOLO_VI_H_START(solo_dev->vout_hstart) |
+ SOLO_VI_V_START(solo_dev->vout_vstart) |
+ SOLO_VI_V_STOP(solo_dev->vout_vstart +
+ solo_dev->video_vsize));
+
+ solo_reg_write(solo_dev, SOLO_VI_ACT_P,
+ SOLO_VI_H_START(0) |
+ SOLO_VI_V_START(1) |
+ SOLO_VI_V_STOP(SOLO_PROGRESSIVE_VSIZE));
+
+ solo_reg_write(solo_dev, SOLO_VI_CH_FORMAT,
+ SOLO_VI_FD_SEL_MASK(0) | SOLO_VI_PROG_MASK(0));
+
+ solo_reg_write(solo_dev, SOLO_VI_FMT_CFG, 0);
+ solo_reg_write(solo_dev, SOLO_VI_PAGE_SW, 2);
+
+ if (solo_dev->video_type == SOLO_VO_FMT_TYPE_NTSC) {
+ solo_reg_write(solo_dev, SOLO_VI_PB_CONFIG,
+ SOLO_VI_PB_USER_MODE);
+ solo_reg_write(solo_dev, SOLO_VI_PB_RANGE_HV,
+ SOLO_VI_PB_HSIZE(858) | SOLO_VI_PB_VSIZE(246));
+ solo_reg_write(solo_dev, SOLO_VI_PB_ACT_V,
+ SOLO_VI_PB_VSTART(4) |
+ SOLO_VI_PB_VSTOP(4 + 240));
+ } else {
+ solo_reg_write(solo_dev, SOLO_VI_PB_CONFIG,
+ SOLO_VI_PB_USER_MODE | SOLO_VI_PB_PAL);
+ solo_reg_write(solo_dev, SOLO_VI_PB_RANGE_HV,
+ SOLO_VI_PB_HSIZE(864) | SOLO_VI_PB_VSIZE(294));
+ solo_reg_write(solo_dev, SOLO_VI_PB_ACT_V,
+ SOLO_VI_PB_VSTART(4) |
+ SOLO_VI_PB_VSTOP(4 + 288));
+ }
+ solo_reg_write(solo_dev, SOLO_VI_PB_ACT_H, SOLO_VI_PB_HSTART(16) |
+ SOLO_VI_PB_HSTOP(16 + 720));
+}
+
+static void solo_disp_config(struct solo6010_dev *solo_dev)
+{
+ solo_dev->vout_hstart = 6;
+ solo_dev->vout_vstart = 8;
+
+ solo_reg_write(solo_dev, SOLO_VO_BORDER_LINE_COLOR,
+ (0xa0 << 24) | (0x88 << 16) | (0xa0 << 8) | 0x88);
+ solo_reg_write(solo_dev, SOLO_VO_BORDER_FILL_COLOR,
+ (0x10 << 24) | (0x8f << 16) | (0x10 << 8) | 0x8f);
+ solo_reg_write(solo_dev, SOLO_VO_BKG_COLOR,
+ (16 << 24) | (128 << 16) | (16 << 8) | 128);
+
+ solo_reg_write(solo_dev, SOLO_VO_FMT_ENC,
+ solo_dev->video_type |
+ SOLO_VO_USER_COLOR_SET_NAV |
+ SOLO_VO_NA_COLOR_Y(0) |
+ SOLO_VO_NA_COLOR_CB(0) |
+ SOLO_VO_NA_COLOR_CR(0));
+
+ solo_reg_write(solo_dev, SOLO_VO_ACT_H,
+ SOLO_VO_H_START(solo_dev->vout_hstart) |
+ SOLO_VO_H_STOP(solo_dev->vout_hstart +
+ solo_dev->video_hsize));
+
+ solo_reg_write(solo_dev, SOLO_VO_ACT_V,
+ SOLO_VO_V_START(solo_dev->vout_vstart) |
+ SOLO_VO_V_STOP(solo_dev->vout_vstart +
+ solo_dev->video_vsize));
+
+ solo_reg_write(solo_dev, SOLO_VO_RANGE_HV,
+ SOLO_VO_H_LEN(solo_dev->video_hsize) |
+ SOLO_VO_V_LEN(solo_dev->video_vsize));
+
+ solo_reg_write(solo_dev, SOLO_VI_WIN_SW, 5);
+
+ solo_reg_write(solo_dev, SOLO_VO_DISP_CTRL, SOLO_VO_DISP_ON |
+ SOLO_VO_DISP_ERASE_COUNT(8) |
+ SOLO_VO_DISP_BASE(SOLO_DISP_EXT_ADDR(solo_dev)));
+
+ solo_reg_write(solo_dev, SOLO_VO_DISP_ERASE, SOLO_VO_DISP_ERASE_ON);
+
+ /* Enable channels we support */
+ solo_reg_write(solo_dev, SOLO_VI_CH_ENA, (1 << solo_dev->nr_chans) - 1);
+
+ /* Disable the watchdog */
+ solo_reg_write(solo_dev, SOLO_WATCHDOG, 0);
+}
+
+static int solo_dma_vin_region(struct solo6010_dev *solo_dev, u32 off,
+ u16 val, int reg_size)
+{
+ u16 buf[64];
+ int i;
+ int ret = 0;
+
+ for (i = 0; i < sizeof(buf) >> 1; i++)
+ buf[i] = val;
+
+ for (i = 0; i < reg_size; i += sizeof(buf))
+ ret |= solo_p2m_dma(solo_dev, SOLO_P2M_DMA_ID_VIN, 1, buf,
+ SOLO_MOTION_EXT_ADDR(solo_dev) + off + i,
+ sizeof(buf));
+
+ return ret;
+}
+
+void solo_set_motion_threshold(struct solo6010_dev *solo_dev, u8 ch, u16 val)
+{
+ if (ch > solo_dev->nr_chans)
+ return;
+
+ solo_dma_vin_region(solo_dev, SOLO_MOT_FLAG_AREA +
+ (ch * SOLO_MOT_THRESH_SIZE * 2),
+ val, SOLO_MOT_THRESH_REAL);
+}
+
+/* First 8k is motion flag (512 bytes * 16). Following that is an 8k+8k
+ * threshold and working table for each channel. Atleast that's what the
+ * spec says. However, this code (take from rdk) has some mystery 8k
+ * block right after the flag area, before the first thresh table. */
+static void solo_motion_config(struct solo6010_dev *solo_dev)
+{
+ int i;
+
+ for (i = 0; i < solo_dev->nr_chans; i++) {
+ /* Clear motion flag area */
+ solo_dma_vin_region(solo_dev, i * SOLO_MOT_FLAG_SIZE, 0x0000,
+ SOLO_MOT_FLAG_SIZE);
+
+ /* Clear working cache table */
+ solo_dma_vin_region(solo_dev, SOLO_MOT_FLAG_AREA +
+ SOLO_MOT_THRESH_SIZE +
+ (i * SOLO_MOT_THRESH_SIZE * 2),
+ 0x0000, SOLO_MOT_THRESH_REAL);
+
+ /* Set default threshold table */
+ solo_set_motion_threshold(solo_dev, i, SOLO_DEF_MOT_THRESH);
+ }
+
+ /* Default motion settings */
+ solo_reg_write(solo_dev, SOLO_VI_MOT_ADR, SOLO_VI_MOTION_EN(0) |
+ (SOLO_MOTION_EXT_ADDR(solo_dev) >> 16));
+ solo_reg_write(solo_dev, SOLO_VI_MOT_CTRL,
+ SOLO_VI_MOTION_FRAME_COUNT(3) |
+ SOLO_VI_MOTION_SAMPLE_LENGTH(solo_dev->video_hsize / 16)
+ | //SOLO_VI_MOTION_INTR_START_STOP |
+ SOLO_VI_MOTION_SAMPLE_COUNT(10));
+
+ solo_reg_write(solo_dev, SOLO_VI_MOTION_BORDER, 0);
+ solo_reg_write(solo_dev, SOLO_VI_MOTION_BAR, 0);
+}
+
+int solo_disp_init(struct solo6010_dev *solo_dev)
+{
+ int i;
+
+ solo_dev->video_hsize = 704;
+ if (video_type == 0) {
+ solo_dev->video_type = SOLO_VO_FMT_TYPE_NTSC;
+ solo_dev->video_vsize = 240;
+ solo_dev->fps = 30;
+ } else {
+ solo_dev->video_type = SOLO_VO_FMT_TYPE_PAL;
+ solo_dev->video_vsize = 288;
+ solo_dev->fps = 25;
+ }
+
+ solo_vin_config(solo_dev);
+ solo_motion_config(solo_dev);
+ solo_disp_config(solo_dev);
+
+ for (i = 0; i < solo_dev->nr_chans; i++)
+ solo_reg_write(solo_dev, SOLO_VI_WIN_ON(i), 1);
+
+ return 0;
+}
+
+void solo_disp_exit(struct solo6010_dev *solo_dev)
+{
+ int i;
+
+ solo6010_irq_off(solo_dev, SOLO_IRQ_MOTION);
+
+ solo_reg_write(solo_dev, SOLO_VO_DISP_CTRL, 0);
+ solo_reg_write(solo_dev, SOLO_VO_ZOOM_CTRL, 0);
+ solo_reg_write(solo_dev, SOLO_VO_FREEZE_CTRL, 0);
+
+ for (i = 0; i < solo_dev->nr_chans; i++) {
+ solo_reg_write(solo_dev, SOLO_VI_WIN_CTRL0(i), 0);
+ solo_reg_write(solo_dev, SOLO_VI_WIN_CTRL1(i), 0);
+ solo_reg_write(solo_dev, SOLO_VI_WIN_ON(i), 0);
+ }
+
+ /* Set default border */
+ for (i = 0; i < 5; i++)
+ solo_reg_write(solo_dev, SOLO_VO_BORDER_X(i), 0);
+
+ for (i = 0; i < 5; i++)
+ solo_reg_write(solo_dev, SOLO_VO_BORDER_Y(i), 0);
+
+ solo_reg_write(solo_dev, SOLO_VO_BORDER_LINE_MASK, 0);
+ solo_reg_write(solo_dev, SOLO_VO_BORDER_FILL_MASK, 0);
+
+ solo_reg_write(solo_dev, SOLO_VO_RECTANGLE_CTRL(0), 0);
+ solo_reg_write(solo_dev, SOLO_VO_RECTANGLE_START(0), 0);
+ solo_reg_write(solo_dev, SOLO_VO_RECTANGLE_STOP(0), 0);
+
+ solo_reg_write(solo_dev, SOLO_VO_RECTANGLE_CTRL(1), 0);
+ solo_reg_write(solo_dev, SOLO_VO_RECTANGLE_START(1), 0);
+ solo_reg_write(solo_dev, SOLO_VO_RECTANGLE_STOP(1), 0);
+}
diff --git a/drivers/staging/solo6x10/solo6010-enc.c b/drivers/staging/solo6x10/solo6010-enc.c
new file mode 100644
index 00000000000..a6cf0a8a3f2
--- /dev/null
+++ b/drivers/staging/solo6x10/solo6010-enc.c
@@ -0,0 +1,229 @@
+/*
+ * Copyright (C) 2010 Bluecherry, LLC www.bluecherrydvr.com
+ * Copyright (C) 2010 Ben Collins <bcollins@bluecherry.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.
+ *
+ * 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 "solo6010.h"
+#include "solo6010-osd-font.h"
+
+#define CAPTURE_MAX_BANDWIDTH 32 // D1 4channel (D1 == 4)
+#define OSG_BUFFER_SIZE 1024
+
+#define VI_PROG_HSIZE (1280 - 16)
+#define VI_PROG_VSIZE (1024 - 16)
+
+static void solo_capture_config(struct solo6010_dev *solo_dev)
+{
+ int i, j;
+ unsigned long height;
+ unsigned long width;
+ unsigned char *buf;
+
+ solo_reg_write(solo_dev, SOLO_CAP_BASE,
+ SOLO_CAP_MAX_PAGE(SOLO_CAP_EXT_MAX_PAGE *
+ solo_dev->nr_chans) |
+ SOLO_CAP_BASE_ADDR(SOLO_CAP_EXT_ADDR(solo_dev) >> 16));
+ solo_reg_write(solo_dev, SOLO_CAP_BTW,
+ (1 << 17) | SOLO_CAP_PROG_BANDWIDTH(2) |
+ SOLO_CAP_MAX_BANDWIDTH(CAPTURE_MAX_BANDWIDTH));
+
+ /* Set scale 1, 9 dimension */
+ width = solo_dev->video_hsize;
+ height = solo_dev->video_vsize;
+ solo_reg_write(solo_dev, SOLO_DIM_SCALE1,
+ SOLO_DIM_H_MB_NUM(width / 16) |
+ SOLO_DIM_V_MB_NUM_FRAME(height / 8) |
+ SOLO_DIM_V_MB_NUM_FIELD(height / 16));
+
+ /* Set scale 2, 10 dimension */
+ width = solo_dev->video_hsize / 2;
+ height = solo_dev->video_vsize;
+ solo_reg_write(solo_dev, SOLO_DIM_SCALE2,
+ SOLO_DIM_H_MB_NUM(width / 16) |
+ SOLO_DIM_V_MB_NUM_FRAME(height / 8) |
+ SOLO_DIM_V_MB_NUM_FIELD(height / 16));
+
+ /* Set scale 3, 11 dimension */
+ width = solo_dev->video_hsize / 2;
+ height = solo_dev->video_vsize / 2;
+ solo_reg_write(solo_dev, SOLO_DIM_SCALE3,
+ SOLO_DIM_H_MB_NUM(width / 16) |
+ SOLO_DIM_V_MB_NUM_FRAME(height / 8) |
+ SOLO_DIM_V_MB_NUM_FIELD(height / 16));
+
+ /* Set scale 4, 12 dimension */
+ width = solo_dev->video_hsize / 3;
+ height = solo_dev->video_vsize / 3;
+ solo_reg_write(solo_dev, SOLO_DIM_SCALE4,
+ SOLO_DIM_H_MB_NUM(width / 16) |
+ SOLO_DIM_V_MB_NUM_FRAME(height / 8) |
+ SOLO_DIM_V_MB_NUM_FIELD(height / 16));
+
+ /* Set scale 5, 13 dimension */
+ width = solo_dev->video_hsize / 4;
+ height = solo_dev->video_vsize / 2;
+ solo_reg_write(solo_dev, SOLO_DIM_SCALE5,
+ SOLO_DIM_H_MB_NUM(width / 16) |
+ SOLO_DIM_V_MB_NUM_FRAME(height / 8) |
+ SOLO_DIM_V_MB_NUM_FIELD(height / 16));
+
+ /* Progressive */
+ width = VI_PROG_HSIZE;
+ height = VI_PROG_VSIZE;
+ solo_reg_write(solo_dev, SOLO_DIM_PROG,
+ SOLO_DIM_H_MB_NUM(width / 16) |
+ SOLO_DIM_V_MB_NUM_FRAME(height / 16) |
+ SOLO_DIM_V_MB_NUM_FIELD(height / 16));
+
+ /* Clear OSD */
+ solo_reg_write(solo_dev, SOLO_VE_OSD_CH, 0);
+ solo_reg_write(solo_dev, SOLO_VE_OSD_BASE,
+ SOLO_EOSD_EXT_ADDR(solo_dev) >> 16);
+ solo_reg_write(solo_dev, SOLO_VE_OSD_CLR,
+ 0xF0 << 16 | 0x80 << 8 | 0x80);
+ solo_reg_write(solo_dev, SOLO_VE_OSD_OPT, 0);
+
+ /* Clear OSG buffer */
+ buf = kzalloc(OSG_BUFFER_SIZE, GFP_KERNEL);
+ if (!buf)
+ return;
+
+ for (i = 0; i < solo_dev->nr_chans; i++) {
+ for (j = 0; j < SOLO_EOSD_EXT_SIZE; j += OSG_BUFFER_SIZE) {
+ solo_p2m_dma(solo_dev, SOLO_P2M_DMA_ID_MP4E, 1, buf,
+ SOLO_EOSD_EXT_ADDR(solo_dev) +
+ (i * SOLO_EOSD_EXT_SIZE) + j,
+ OSG_BUFFER_SIZE);
+ }
+ }
+ kfree(buf);
+}
+
+int solo_osd_print(struct solo_enc_dev *solo_enc)
+{
+ struct solo6010_dev *solo_dev = solo_enc->solo_dev;
+ char *str = solo_enc->osd_text;
+ u8 *buf;
+ u32 reg = solo_reg_read(solo_dev, SOLO_VE_OSD_CH);
+ int len = strlen(str);
+ int i, j;
+ int x = 1, y = 1;
+
+ if (len == 0) {
+ reg &= ~(1 << solo_enc->ch);
+ solo_reg_write(solo_dev, SOLO_VE_OSD_CH, reg);
+ return 0;
+ }
+
+ buf = kzalloc(SOLO_EOSD_EXT_SIZE, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ for (i = 0; i < len; i++) {
+ for (j = 0; j < 16; j++) {
+ buf[(j*2) + (i%2) + ((x + (i/2)) * 32) + (y * 2048)] =
+ (solo_osd_font[(str[i] * 4) + (j / 4)]
+ >> ((3 - (j % 4)) * 8)) & 0xff;
+ }
+ }
+
+ solo_p2m_dma(solo_dev, 0, 1, buf, SOLO_EOSD_EXT_ADDR(solo_dev) +
+ (solo_enc->ch * SOLO_EOSD_EXT_SIZE), SOLO_EOSD_EXT_SIZE);
+ reg |= (1 << solo_enc->ch);
+ solo_reg_write(solo_dev, SOLO_VE_OSD_CH, reg);
+
+ kfree(buf);
+
+ return 0;
+}
+
+static void solo_jpeg_config(struct solo6010_dev *solo_dev)
+{
+ solo_reg_write(solo_dev, SOLO_VE_JPEG_QP_TBL,
+ (2 << 24) | (2 << 16) | (2 << 8) | (2 << 0));
+ solo_reg_write(solo_dev, SOLO_VE_JPEG_QP_CH_L, 0);
+ solo_reg_write(solo_dev, SOLO_VE_JPEG_QP_CH_H, 0);
+ solo_reg_write(solo_dev, SOLO_VE_JPEG_CFG,
+ (SOLO_JPEG_EXT_SIZE(solo_dev) & 0xffff0000) |
+ ((SOLO_JPEG_EXT_ADDR(solo_dev) >> 16) & 0x0000ffff));
+ solo_reg_write(solo_dev, SOLO_VE_JPEG_CTRL, 0xffffffff);
+}
+
+static void solo_mp4e_config(struct solo6010_dev *solo_dev)
+{
+ int i;
+
+ /* We can only use VE_INTR_CTRL(0) if we want to support mjpeg */
+ solo_reg_write(solo_dev, SOLO_VE_CFG0,
+ SOLO_VE_INTR_CTRL(0) |
+ SOLO_VE_BLOCK_SIZE(SOLO_MP4E_EXT_SIZE(solo_dev) >> 16) |
+ SOLO_VE_BLOCK_BASE(SOLO_MP4E_EXT_ADDR(solo_dev) >> 16));
+
+ solo_reg_write(solo_dev, SOLO_VE_CFG1,
+ SOLO_VE_BYTE_ALIGN(2) |
+ SOLO_VE_INSERT_INDEX | SOLO_VE_MOTION_MODE(0));
+
+ solo_reg_write(solo_dev, SOLO_VE_WMRK_POLY, 0);
+ solo_reg_write(solo_dev, SOLO_VE_VMRK_INIT_KEY, 0);
+ solo_reg_write(solo_dev, SOLO_VE_WMRK_STRL, 0);
+ solo_reg_write(solo_dev, SOLO_VE_ENCRYP_POLY, 0);
+ solo_reg_write(solo_dev, SOLO_VE_ENCRYP_INIT, 0);
+
+ solo_reg_write(solo_dev, SOLO_VE_ATTR,
+ SOLO_VE_LITTLE_ENDIAN |
+ SOLO_COMP_ATTR_FCODE(1) |
+ SOLO_COMP_TIME_INC(0) |
+ SOLO_COMP_TIME_WIDTH(15) |
+ SOLO_DCT_INTERVAL(36 / 4));
+
+ for (i = 0; i < solo_dev->nr_chans; i++)
+ solo_reg_write(solo_dev, SOLO_VE_CH_REF_BASE(i),
+ (SOLO_EREF_EXT_ADDR(solo_dev) +
+ (i * SOLO_EREF_EXT_SIZE)) >> 16);
+}
+
+int solo_enc_init(struct solo6010_dev *solo_dev)
+{
+ int i;
+
+ solo_capture_config(solo_dev);
+ solo_mp4e_config(solo_dev);
+ solo_jpeg_config(solo_dev);
+
+ for (i = 0; i < solo_dev->nr_chans; i++) {
+ solo_reg_write(solo_dev, SOLO_CAP_CH_SCALE(i), 0);
+ solo_reg_write(solo_dev, SOLO_CAP_CH_COMP_ENA_E(i), 0);
+ }
+
+ solo6010_irq_on(solo_dev, SOLO_IRQ_ENCODER);
+
+ return 0;
+}
+
+void solo_enc_exit(struct solo6010_dev *solo_dev)
+{
+ int i;
+
+ solo6010_irq_off(solo_dev, SOLO_IRQ_ENCODER);
+
+ for (i = 0; i < solo_dev->nr_chans; i++) {
+ solo_reg_write(solo_dev, SOLO_CAP_CH_SCALE(i), 0);
+ solo_reg_write(solo_dev, SOLO_CAP_CH_COMP_ENA_E(i), 0);
+ }
+}
diff --git a/drivers/staging/solo6x10/solo6010-g723.c b/drivers/staging/solo6x10/solo6010-g723.c
new file mode 100644
index 00000000000..e82846c1d6c
--- /dev/null
+++ b/drivers/staging/solo6x10/solo6010-g723.c
@@ -0,0 +1,398 @@
+/*
+ * Copyright (C) 2010 Bluecherry, LLC www.bluecherrydvr.com
+ * Copyright (C) 2010 Ben Collins <bcollins@bluecherry.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.
+ *
+ * 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/mempool.h>
+#include <linux/poll.h>
+#include <linux/kthread.h>
+#include <linux/freezer.h>
+
+#include <sound/core.h>
+#include <sound/initval.h>
+#include <sound/pcm.h>
+#include <sound/control.h>
+
+#include "solo6010.h"
+#include "solo6010-tw28.h"
+
+#define G723_INTR_ORDER 0
+#define G723_FDMA_PAGES 32
+#define G723_PERIOD_BYTES 48
+#define G723_PERIOD_BLOCK 1024
+#define G723_FRAMES_PER_PAGE 48
+
+/* Sets up channels 16-19 for decoding and 0-15 for encoding */
+#define OUTMODE_MASK 0x300
+
+#define SAMPLERATE 8000
+#define BITRATE 25
+
+/* The solo writes to 1k byte pages, 32 pages, in the dma. Each 1k page
+ * is broken down to 20 * 48 byte regions (one for each channel possible)
+ * with the rest of the page being dummy data. */
+#define MAX_BUFFER (G723_PERIOD_BYTES * PERIODS_MAX)
+#define IRQ_PAGES 4 // 0 - 4
+#define PERIODS_MIN (1 << IRQ_PAGES)
+#define PERIODS_MAX G723_FDMA_PAGES
+
+struct solo_snd_pcm {
+ int on;
+ spinlock_t lock;
+ struct solo6010_dev *solo_dev;
+ unsigned char g723_buf[G723_PERIOD_BYTES];
+};
+
+static void solo_g723_config(struct solo6010_dev *solo_dev)
+{
+ int clk_div;
+
+ clk_div = SOLO_CLOCK_MHZ / (SAMPLERATE * (BITRATE * 2) * 2);
+
+ solo_reg_write(solo_dev, SOLO_AUDIO_SAMPLE,
+ SOLO_AUDIO_BITRATE(BITRATE) |
+ SOLO_AUDIO_CLK_DIV(clk_div));
+
+ solo_reg_write(solo_dev, SOLO_AUDIO_FDMA_INTR,
+ SOLO_AUDIO_FDMA_INTERVAL(IRQ_PAGES) |
+ SOLO_AUDIO_INTR_ORDER(G723_INTR_ORDER) |
+ SOLO_AUDIO_FDMA_BASE(SOLO_G723_EXT_ADDR(solo_dev) >> 16));
+
+ solo_reg_write(solo_dev, SOLO_AUDIO_CONTROL,
+ SOLO_AUDIO_ENABLE | SOLO_AUDIO_I2S_MODE |
+ SOLO_AUDIO_I2S_MULTI(3) | SOLO_AUDIO_MODE(OUTMODE_MASK));
+}
+
+void solo_g723_isr(struct solo6010_dev *solo_dev)
+{
+ struct snd_pcm_str *pstr =
+ &solo_dev->snd_pcm->streams[SNDRV_PCM_STREAM_CAPTURE];
+ struct snd_pcm_substream *ss;
+ struct solo_snd_pcm *solo_pcm;
+
+ solo_reg_write(solo_dev, SOLO_IRQ_STAT, SOLO_IRQ_G723);
+
+ for (ss = pstr->substream; ss != NULL; ss = ss->next) {
+ if (snd_pcm_substream_chip(ss) == NULL)
+ continue;
+
+ /* This means open() hasn't been called on this one */
+ if (snd_pcm_substream_chip(ss) == solo_dev)
+ continue;
+
+ /* Haven't triggered a start yet */
+ solo_pcm = snd_pcm_substream_chip(ss);
+ if (!solo_pcm->on)
+ continue;
+
+ snd_pcm_period_elapsed(ss);
+ }
+}
+
+static int snd_solo_hw_params(struct snd_pcm_substream *ss,
+ struct snd_pcm_hw_params *hw_params)
+{
+ return snd_pcm_lib_malloc_pages(ss, params_buffer_bytes(hw_params));
+}
+
+static int snd_solo_hw_free(struct snd_pcm_substream *ss)
+{
+ return snd_pcm_lib_free_pages(ss);
+}
+
+static struct snd_pcm_hardware snd_solo_pcm_hw = {
+ .info = (SNDRV_PCM_INFO_MMAP |
+ SNDRV_PCM_INFO_INTERLEAVED |
+ SNDRV_PCM_INFO_BLOCK_TRANSFER |
+ SNDRV_PCM_INFO_MMAP_VALID),
+ .formats = SNDRV_PCM_FMTBIT_U8,
+ .rates = SNDRV_PCM_RATE_8000,
+ .rate_min = 8000,
+ .rate_max = 8000,
+ .channels_min = 1,
+ .channels_max = 1,
+ .buffer_bytes_max = MAX_BUFFER,
+ .period_bytes_min = G723_PERIOD_BYTES,
+ .period_bytes_max = G723_PERIOD_BYTES,
+ .periods_min = PERIODS_MIN,
+ .periods_max = PERIODS_MAX,
+};
+
+static int snd_solo_pcm_open(struct snd_pcm_substream *ss)
+{
+ struct solo6010_dev *solo_dev = snd_pcm_substream_chip(ss);
+ struct solo_snd_pcm *solo_pcm;
+
+ solo_pcm = kzalloc(sizeof(*solo_pcm), GFP_KERNEL);
+ if (solo_pcm == NULL)
+ return -ENOMEM;
+
+ spin_lock_init(&solo_pcm->lock);
+ solo_pcm->solo_dev = solo_dev;
+ ss->runtime->hw = snd_solo_pcm_hw;
+
+ snd_pcm_substream_chip(ss) = solo_pcm;
+
+ return 0;
+}
+
+static int snd_solo_pcm_close(struct snd_pcm_substream *ss)
+{
+ struct solo_snd_pcm *solo_pcm = snd_pcm_substream_chip(ss);
+
+ snd_pcm_substream_chip(ss) = solo_pcm->solo_dev;
+ kfree(solo_pcm);
+
+ return 0;
+}
+
+static int snd_solo_pcm_trigger(struct snd_pcm_substream *ss, int cmd)
+{
+ struct solo_snd_pcm *solo_pcm = snd_pcm_substream_chip(ss);
+ struct solo6010_dev *solo_dev = solo_pcm->solo_dev;
+ int ret = 0;
+
+ spin_lock(&solo_pcm->lock);
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ if (solo_pcm->on == 0) {
+ /* If this is the first user, switch on interrupts */
+ if (atomic_inc_return(&solo_dev->snd_users) == 1)
+ solo6010_irq_on(solo_dev, SOLO_IRQ_G723);
+ solo_pcm->on = 1;
+ }
+ break;
+ case SNDRV_PCM_TRIGGER_STOP:
+ if (solo_pcm->on) {
+ /* If this was our last user, switch them off */
+ if (atomic_dec_return(&solo_dev->snd_users) == 0)
+ solo6010_irq_off(solo_dev, SOLO_IRQ_G723);
+ solo_pcm->on = 0;
+ }
+ break;
+ default:
+ ret = -EINVAL;
+ }
+
+ spin_unlock(&solo_pcm->lock);
+
+ return ret;
+}
+
+static int snd_solo_pcm_prepare(struct snd_pcm_substream *ss)
+{
+ return 0;
+}
+
+static snd_pcm_uframes_t snd_solo_pcm_pointer(struct snd_pcm_substream *ss)
+{
+ struct solo_snd_pcm *solo_pcm = snd_pcm_substream_chip(ss);
+ struct solo6010_dev *solo_dev = solo_pcm->solo_dev;
+ snd_pcm_uframes_t idx = solo_reg_read(solo_dev, SOLO_AUDIO_STA) & 0x1f;
+
+ return idx * G723_FRAMES_PER_PAGE;
+}
+
+static int snd_solo_pcm_copy(struct snd_pcm_substream *ss, int channel,
+ snd_pcm_uframes_t pos, void __user *dst,
+ snd_pcm_uframes_t count)
+{
+ struct solo_snd_pcm *solo_pcm = snd_pcm_substream_chip(ss);
+ struct solo6010_dev *solo_dev = solo_pcm->solo_dev;
+ int err, i;
+
+ for (i = 0; i < (count / G723_FRAMES_PER_PAGE); i++) {
+ int page = (pos / G723_FRAMES_PER_PAGE) + i;
+
+ err = solo_p2m_dma(solo_dev, SOLO_P2M_DMA_ID_G723E, 0,
+ solo_pcm->g723_buf,
+ SOLO_G723_EXT_ADDR(solo_dev) +
+ (page * G723_PERIOD_BLOCK) +
+ (ss->number * G723_PERIOD_BYTES),
+ G723_PERIOD_BYTES);
+ if (err)
+ return err;
+
+ err = copy_to_user(dst + (i * G723_PERIOD_BYTES),
+ solo_pcm->g723_buf, G723_PERIOD_BYTES);
+
+ if (err)
+ return err;
+ }
+
+ return 0;
+}
+
+static struct snd_pcm_ops snd_solo_pcm_ops = {
+ .open = snd_solo_pcm_open,
+ .close = snd_solo_pcm_close,
+ .ioctl = snd_pcm_lib_ioctl,
+ .hw_params = snd_solo_hw_params,
+ .hw_free = snd_solo_hw_free,
+ .prepare = snd_solo_pcm_prepare,
+ .trigger = snd_solo_pcm_trigger,
+ .pointer = snd_solo_pcm_pointer,
+ .copy = snd_solo_pcm_copy,
+};
+
+static int snd_solo_capture_volume_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *info)
+{
+ info->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ info->count = 1;
+ info->value.integer.min = 0;
+ info->value.integer.max = 15;
+ info->value.integer.step = 1;
+
+ return 0;
+}
+
+static int snd_solo_capture_volume_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *value)
+{
+ struct solo6010_dev *solo_dev = snd_kcontrol_chip(kcontrol);
+ u8 ch = value->id.numid - 1;
+
+ value->value.integer.value[0] = tw28_get_audio_gain(solo_dev, ch);
+
+ return 0;
+}
+
+static int snd_solo_capture_volume_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *value)
+{
+ struct solo6010_dev *solo_dev = snd_kcontrol_chip(kcontrol);
+ u8 ch = value->id.numid - 1;
+ u8 old_val;
+
+ old_val = tw28_get_audio_gain(solo_dev, ch);
+ if (old_val == value->value.integer.value[0])
+ return 0;
+
+ tw28_set_audio_gain(solo_dev, ch, value->value.integer.value[0]);
+
+ return 1;
+}
+
+static struct snd_kcontrol_new snd_solo_capture_volume = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Capture Volume",
+ .info = snd_solo_capture_volume_info,
+ .get = snd_solo_capture_volume_get,
+ .put = snd_solo_capture_volume_put,
+};
+
+static int solo_snd_pcm_init(struct solo6010_dev *solo_dev)
+{
+ struct snd_card *card = solo_dev->snd_card;
+ struct snd_pcm *pcm;
+ struct snd_pcm_substream *ss;
+ int ret;
+ int i;
+
+ ret = snd_pcm_new(card, card->driver, 0, 0, solo_dev->nr_chans,
+ &pcm);
+ if (ret < 0)
+ return ret;
+
+ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE,
+ &snd_solo_pcm_ops);
+
+ snd_pcm_chip(pcm) = solo_dev;
+ pcm->info_flags = 0;
+ strcpy(pcm->name, card->shortname);
+
+ for (i = 0, ss = pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream;
+ ss; ss = ss->next, i++)
+ sprintf(ss->name, "Camera #%d Audio", i);
+
+ ret = snd_pcm_lib_preallocate_pages_for_all(pcm,
+ SNDRV_DMA_TYPE_CONTINUOUS,
+ snd_dma_continuous_data(GFP_KERNEL),
+ MAX_BUFFER, MAX_BUFFER);
+ if (ret < 0)
+ return ret;
+
+ solo_dev->snd_pcm = pcm;
+
+ return 0;
+}
+
+int solo_g723_init(struct solo6010_dev *solo_dev)
+{
+ static struct snd_device_ops ops = { NULL };
+ struct snd_card *card;
+ struct snd_kcontrol_new kctl;
+ char name[32];
+ int ret;
+
+ atomic_set(&solo_dev->snd_users, 0);
+
+ /* Allows for easier mapping between video and audio */
+ sprintf(name, "Softlogic%d", solo_dev->vfd->num);
+
+ ret = snd_card_create(SNDRV_DEFAULT_IDX1, name, THIS_MODULE, 0,
+ &solo_dev->snd_card);
+ if (ret < 0)
+ return ret;
+
+ card = solo_dev->snd_card;
+
+ strcpy(card->driver, SOLO6010_NAME);
+ strcpy(card->shortname, "SOLO-6010 Audio");
+ sprintf(card->longname, "%s on %s IRQ %d", card->shortname,
+ pci_name(solo_dev->pdev), solo_dev->pdev->irq);
+ snd_card_set_dev(card, &solo_dev->pdev->dev);
+
+ ret = snd_device_new(card, SNDRV_DEV_LOWLEVEL, solo_dev, &ops);
+ if (ret < 0)
+ goto snd_error;
+
+ /* Mixer controls */
+ strcpy(card->mixername, "SOLO-6010");
+ kctl = snd_solo_capture_volume;
+ kctl.count = solo_dev->nr_chans;
+ ret = snd_ctl_add(card, snd_ctl_new1(&kctl, solo_dev));
+ if (ret < 0)
+ return ret;
+
+ if ((ret = solo_snd_pcm_init(solo_dev)) < 0)
+ goto snd_error;
+
+ if ((ret = snd_card_register(card)) < 0)
+ goto snd_error;
+
+ solo_g723_config(solo_dev);
+
+ dev_info(&solo_dev->pdev->dev, "Alsa sound card as %s\n", name);
+
+ return 0;
+
+snd_error:
+ snd_card_free(card);
+ return ret;
+}
+
+void solo_g723_exit(struct solo6010_dev *solo_dev)
+{
+ solo_reg_write(solo_dev, SOLO_AUDIO_CONTROL, 0);
+ solo6010_irq_off(solo_dev, SOLO_IRQ_G723);
+
+ snd_card_free(solo_dev->snd_card);
+}
diff --git a/drivers/staging/solo6x10/solo6010-gpio.c b/drivers/staging/solo6x10/solo6010-gpio.c
new file mode 100644
index 00000000000..46f7a71edab
--- /dev/null
+++ b/drivers/staging/solo6x10/solo6010-gpio.c
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2010 Bluecherry, LLC www.bluecherrydvr.com
+ * Copyright (C) 2010 Ben Collins <bcollins@bluecherry.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.
+ *
+ * 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/fs.h>
+#include <asm/uaccess.h>
+
+#include "solo6010.h"
+
+static void solo_gpio_mode(struct solo6010_dev *solo_dev,
+ unsigned int port_mask, unsigned int mode)
+{
+ int port;
+ unsigned int ret;
+
+ ret = solo_reg_read(solo_dev, SOLO_GPIO_CONFIG_0);
+
+ /* To set gpio */
+ for (port = 0; port < 16; port++) {
+ if (!((1 << port) & port_mask))
+ continue;
+
+ ret &= (~(3 << (port << 1)));
+ ret |= ((mode & 3) << (port << 1));
+ }
+
+ solo_reg_write(solo_dev, SOLO_GPIO_CONFIG_0, ret);
+
+ /* To set extended gpio - sensor */
+ ret = solo_reg_read(solo_dev, SOLO_GPIO_CONFIG_1);
+
+ for (port = 0; port < 16; port++) {
+ if (!((1 << (port + 16)) & port_mask))
+ continue;
+
+ if (!mode)
+ ret &= ~(1 << port);
+ else
+ ret |= 1 << port;
+ }
+
+ solo_reg_write(solo_dev, SOLO_GPIO_CONFIG_1, ret);
+}
+
+static void solo_gpio_set(struct solo6010_dev *solo_dev, unsigned int value)
+{
+ solo_reg_write(solo_dev, SOLO_GPIO_DATA_OUT,
+ solo_reg_read(solo_dev, SOLO_GPIO_DATA_OUT) | value);
+}
+
+static void solo_gpio_clear(struct solo6010_dev *solo_dev, unsigned int value)
+{
+ solo_reg_write(solo_dev, SOLO_GPIO_DATA_OUT,
+ solo_reg_read(solo_dev, SOLO_GPIO_DATA_OUT) & ~value);
+}
+
+static void solo_gpio_config(struct solo6010_dev *solo_dev)
+{
+ /* Video reset */
+ solo_gpio_mode(solo_dev, 0x30, 1);
+ solo_gpio_clear(solo_dev, 0x30);
+ udelay(100);
+ solo_gpio_set(solo_dev, 0x30);
+ udelay(100);
+
+ /* Warning: Don't touch the next line unless you're sure of what
+ * you're doing: first four gpio [0-3] are used for video. */
+ solo_gpio_mode(solo_dev, 0x0f, 2);
+
+ /* We use bit 8-15 of SOLO_GPIO_CONFIG_0 for relay purposes */
+ solo_gpio_mode(solo_dev, 0xff00, 1);
+
+ /* Initially set relay status to 0 */
+ solo_gpio_clear(solo_dev, 0xff00);
+}
+
+int solo_gpio_init(struct solo6010_dev *solo_dev)
+{
+ solo_gpio_config(solo_dev);
+ return 0;
+}
+
+void solo_gpio_exit(struct solo6010_dev *solo_dev)
+{
+ solo_gpio_clear(solo_dev, 0x30);
+ solo_gpio_config(solo_dev);
+}
diff --git a/drivers/staging/solo6x10/solo6010-i2c.c b/drivers/staging/solo6x10/solo6010-i2c.c
new file mode 100644
index 00000000000..2bb86fa9e9e
--- /dev/null
+++ b/drivers/staging/solo6x10/solo6010-i2c.c
@@ -0,0 +1,331 @@
+/*
+ * Copyright (C) 2010 Bluecherry, LLC www.bluecherrydvr.com
+ * Copyright (C) 2010 Ben Collins <bcollins@bluecherry.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.
+ *
+ * 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.
+ */
+
+/* XXX: The SOLO6010 i2c does not have separate interrupts for each i2c
+ * channel. The bus can only handle one i2c event at a time. The below handles
+ * this all wrong. We should be using the status registers to see if the bus
+ * is in use, and have a global lock to check the status register. Also,
+ * the bulk of the work should be handled out-of-interrupt. The ugly loops
+ * that occur during interrupt scare me. The ISR should merely signal
+ * thread context, ACK the interrupt, and move on. -- BenC */
+
+#include <linux/kernel.h>
+
+#include "solo6010.h"
+
+u8 solo_i2c_readbyte(struct solo6010_dev *solo_dev, int id, u8 addr, u8 off)
+{
+ struct i2c_msg msgs[2];
+ u8 data;
+
+ msgs[0].flags = 0;
+ msgs[0].addr = addr;
+ msgs[0].len = 1;
+ msgs[0].buf = &off;
+
+ msgs[1].flags = I2C_M_RD;
+ msgs[1].addr = addr;
+ msgs[1].len = 1;
+ msgs[1].buf = &data;
+
+ i2c_transfer(&solo_dev->i2c_adap[id], msgs, 2);
+
+ return data;
+}
+
+void solo_i2c_writebyte(struct solo6010_dev *solo_dev, int id, u8 addr,
+ u8 off, u8 data)
+{
+ struct i2c_msg msgs;
+ u8 buf[2];
+
+ buf[0] = off;
+ buf[1] = data;
+ msgs.flags = 0;
+ msgs.addr = addr;
+ msgs.len = 2;
+ msgs.buf = buf;
+
+ i2c_transfer(&solo_dev->i2c_adap[id], &msgs, 1);
+}
+
+static void solo_i2c_flush(struct solo6010_dev *solo_dev, int wr)
+{
+ u32 ctrl;
+
+ ctrl = SOLO_IIC_CH_SET(solo_dev->i2c_id);
+
+ if (solo_dev->i2c_state == IIC_STATE_START)
+ ctrl |= SOLO_IIC_START;
+
+ if (wr) {
+ ctrl |= SOLO_IIC_WRITE;
+ } else {
+ ctrl |= SOLO_IIC_READ;
+ if (!(solo_dev->i2c_msg->flags & I2C_M_NO_RD_ACK))
+ ctrl |= SOLO_IIC_ACK_EN;
+ }
+
+ if (solo_dev->i2c_msg_ptr == solo_dev->i2c_msg->len)
+ ctrl |= SOLO_IIC_STOP;
+
+ solo_reg_write(solo_dev, SOLO_IIC_CTRL, ctrl);
+}
+
+static void solo_i2c_start(struct solo6010_dev *solo_dev)
+{
+ u32 addr = solo_dev->i2c_msg->addr << 1;
+
+ if (solo_dev->i2c_msg->flags & I2C_M_RD)
+ addr |= 1;
+
+ solo_dev->i2c_state = IIC_STATE_START;
+ solo_reg_write(solo_dev, SOLO_IIC_TXD, addr);
+ solo_i2c_flush(solo_dev, 1);
+}
+
+static void solo_i2c_stop(struct solo6010_dev *solo_dev)
+{
+ solo6010_irq_off(solo_dev, SOLO_IRQ_IIC);
+ solo_reg_write(solo_dev, SOLO_IIC_CTRL, 0);
+ solo_dev->i2c_state = IIC_STATE_STOP;
+ wake_up(&solo_dev->i2c_wait);
+}
+
+static int solo_i2c_handle_read(struct solo6010_dev *solo_dev)
+{
+prepare_read:
+ if (solo_dev->i2c_msg_ptr != solo_dev->i2c_msg->len) {
+ solo_i2c_flush(solo_dev, 0);
+ return 0;
+ }
+
+ solo_dev->i2c_msg_ptr = 0;
+ solo_dev->i2c_msg++;
+ solo_dev->i2c_msg_num--;
+
+ if (solo_dev->i2c_msg_num == 0) {
+ solo_i2c_stop(solo_dev);
+ return 0;
+ }
+
+ if (!(solo_dev->i2c_msg->flags & I2C_M_NOSTART)) {
+ solo_i2c_start(solo_dev);
+ } else {
+ if (solo_dev->i2c_msg->flags & I2C_M_RD)
+ goto prepare_read;
+ else
+ solo_i2c_stop(solo_dev);
+ }
+
+ return 0;
+}
+
+static int solo_i2c_handle_write(struct solo6010_dev *solo_dev)
+{
+retry_write:
+ if (solo_dev->i2c_msg_ptr != solo_dev->i2c_msg->len) {
+ solo_reg_write(solo_dev, SOLO_IIC_TXD,
+ solo_dev->i2c_msg->buf[solo_dev->i2c_msg_ptr]);
+ solo_dev->i2c_msg_ptr++;
+ solo_i2c_flush(solo_dev, 1);
+ return 0;
+ }
+
+ solo_dev->i2c_msg_ptr = 0;
+ solo_dev->i2c_msg++;
+ solo_dev->i2c_msg_num--;
+
+ if (solo_dev->i2c_msg_num == 0) {
+ solo_i2c_stop(solo_dev);
+ return 0;
+ }
+
+ if (!(solo_dev->i2c_msg->flags & I2C_M_NOSTART)) {
+ solo_i2c_start(solo_dev);
+ } else {
+ if (solo_dev->i2c_msg->flags & I2C_M_RD)
+ solo_i2c_stop(solo_dev);
+ else
+ goto retry_write;
+ }
+
+ return 0;
+}
+
+int solo_i2c_isr(struct solo6010_dev *solo_dev)
+{
+ u32 status = solo_reg_read(solo_dev, SOLO_IIC_CTRL);
+ int ret = -EINVAL;
+
+ solo_reg_write(solo_dev, SOLO_IRQ_STAT, SOLO_IRQ_IIC);
+
+ if (status & (SOLO_IIC_STATE_TRNS & SOLO_IIC_STATE_SIG_ERR) ||
+ solo_dev->i2c_id < 0) {
+ solo_i2c_stop(solo_dev);
+ return -ENXIO;
+ }
+
+ switch (solo_dev->i2c_state) {
+ case IIC_STATE_START:
+ if (solo_dev->i2c_msg->flags & I2C_M_RD) {
+ solo_dev->i2c_state = IIC_STATE_READ;
+ ret = solo_i2c_handle_read(solo_dev);
+ break;
+ }
+
+ solo_dev->i2c_state = IIC_STATE_WRITE;
+ case IIC_STATE_WRITE:
+ ret = solo_i2c_handle_write(solo_dev);
+ break;
+
+ case IIC_STATE_READ:
+ solo_dev->i2c_msg->buf[solo_dev->i2c_msg_ptr] =
+ solo_reg_read(solo_dev, SOLO_IIC_RXD);
+ solo_dev->i2c_msg_ptr++;
+
+ ret = solo_i2c_handle_read(solo_dev);
+ break;
+
+ default:
+ solo_i2c_stop(solo_dev);
+ }
+
+ return ret;
+}
+
+static int solo_i2c_master_xfer(struct i2c_adapter *adap,
+ struct i2c_msg msgs[], int num)
+{
+ struct solo6010_dev *solo_dev = adap->algo_data;
+ unsigned long timeout;
+ int ret;
+ int i;
+ DEFINE_WAIT(wait);
+
+ for (i = 0; i < SOLO_I2C_ADAPTERS; i++) {
+ if (&solo_dev->i2c_adap[i] == adap)
+ break;
+ }
+
+ if (i == SOLO_I2C_ADAPTERS)
+ return num; // XXX Right return value for failure?
+
+ down(&solo_dev->i2c_sem);
+ solo_dev->i2c_id = i;
+ solo_dev->i2c_msg = msgs;
+ solo_dev->i2c_msg_num = num;
+ solo_dev->i2c_msg_ptr = 0;
+
+ solo_reg_write(solo_dev, SOLO_IIC_CTRL, 0);
+ solo6010_irq_on(solo_dev, SOLO_IRQ_IIC);
+ solo_i2c_start(solo_dev);
+
+ timeout = HZ / 2;
+
+ for (;;) {
+ prepare_to_wait(&solo_dev->i2c_wait, &wait, TASK_INTERRUPTIBLE);
+
+ if (solo_dev->i2c_state == IIC_STATE_STOP)
+ break;
+
+ timeout = schedule_timeout(timeout);
+ if (!timeout)
+ break;
+
+ if (signal_pending(current))
+ break;
+ }
+
+ finish_wait(&solo_dev->i2c_wait, &wait);
+ ret = num - solo_dev->i2c_msg_num;
+ solo_dev->i2c_state = IIC_STATE_IDLE;
+ solo_dev->i2c_id = -1;
+
+ up(&solo_dev->i2c_sem);
+
+ return ret;
+}
+
+static u32 solo_i2c_functionality(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_I2C;
+}
+
+static struct i2c_algorithm solo_i2c_algo = {
+ .master_xfer = solo_i2c_master_xfer,
+ .functionality = solo_i2c_functionality,
+};
+
+int solo_i2c_init(struct solo6010_dev *solo_dev)
+{
+ int i;
+ int ret;
+
+ solo_reg_write(solo_dev, SOLO_IIC_CFG,
+ SOLO_IIC_PRESCALE(8) | SOLO_IIC_ENABLE);
+
+ solo_dev->i2c_id = -1;
+ solo_dev->i2c_state = IIC_STATE_IDLE;
+ init_waitqueue_head(&solo_dev->i2c_wait);
+ init_MUTEX(&solo_dev->i2c_sem);
+
+ for (i = 0; i < SOLO_I2C_ADAPTERS; i++) {
+ struct i2c_adapter *adap = &solo_dev->i2c_adap[i];
+
+ snprintf(adap->name, I2C_NAME_SIZE, "%s I2C %d",
+ SOLO6010_NAME, i);
+ adap->algo = &solo_i2c_algo;
+ adap->algo_data = solo_dev;
+ adap->retries = 1;
+ adap->dev.parent = &solo_dev->pdev->dev;
+
+ if ((ret = i2c_add_adapter(adap))) {
+ adap->algo_data = NULL;
+ break;
+ }
+ }
+
+ if (ret) {
+ for (i = 0; i < SOLO_I2C_ADAPTERS; i++) {
+ if (!solo_dev->i2c_adap[i].algo_data)
+ break;
+ i2c_del_adapter(&solo_dev->i2c_adap[i]);
+ solo_dev->i2c_adap[i].algo_data = NULL;
+ }
+ return ret;
+ }
+
+ dev_info(&solo_dev->pdev->dev, "Enabled %d i2c adapters\n",
+ SOLO_I2C_ADAPTERS);
+
+ return 0;
+}
+
+void solo_i2c_exit(struct solo6010_dev *solo_dev)
+{
+ int i;
+
+ for (i = 0; i < SOLO_I2C_ADAPTERS; i++) {
+ if (!solo_dev->i2c_adap[i].algo_data)
+ continue;
+ i2c_del_adapter(&solo_dev->i2c_adap[i]);
+ solo_dev->i2c_adap[i].algo_data = NULL;
+ }
+}
diff --git a/drivers/staging/solo6x10/solo6010-jpeg.h b/drivers/staging/solo6x10/solo6010-jpeg.h
new file mode 100644
index 00000000000..fb0507ecb30
--- /dev/null
+++ b/drivers/staging/solo6x10/solo6010-jpeg.h
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2010 Bluecherry, LLC www.bluecherrydvr.com
+ * Copyright (C) 2010 Ben Collins <bcollins@bluecherry.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.
+ *
+ * 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 __SOLO6010_JPEG_H
+#define __SOLO6010_JPEG_H
+
+static unsigned char jpeg_header[] = {
+ 0xff, 0xd8, 0xff, 0xfe, 0x00, 0x0d, 0x42, 0x6c,
+ 0x75, 0x65, 0x63, 0x68, 0x65, 0x72, 0x72, 0x79,
+ 0x20, 0xff, 0xdb, 0x00, 0x43, 0x00, 0x20, 0x16,
+ 0x18, 0x1c, 0x18, 0x14, 0x20, 0x1c, 0x1a, 0x1c,
+ 0x24, 0x22, 0x20, 0x26, 0x30, 0x50, 0x34, 0x30,
+ 0x2c, 0x2c, 0x30, 0x62, 0x46, 0x4a, 0x3a, 0x50,
+ 0x74, 0x66, 0x7a, 0x78, 0x72, 0x66, 0x70, 0x6e,
+ 0x80, 0x90, 0xb8, 0x9c, 0x80, 0x88, 0xae, 0x8a,
+ 0x6e, 0x70, 0xa0, 0xda, 0xa2, 0xae, 0xbe, 0xc4,
+ 0xce, 0xd0, 0xce, 0x7c, 0x9a, 0xe2, 0xf2, 0xe0,
+ 0xc8, 0xf0, 0xb8, 0xca, 0xce, 0xc6, 0xff, 0xdb,
+ 0x00, 0x43, 0x01, 0x22, 0x24, 0x24, 0x30, 0x2a,
+ 0x30, 0x5e, 0x34, 0x34, 0x5e, 0xc6, 0x84, 0x70,
+ 0x84, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
+ 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
+ 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
+ 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
+ 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
+ 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
+ 0xc6, 0xc6, 0xc6, 0xff, 0xc4, 0x01, 0xa2, 0x00,
+ 0x00, 0x01, 0x05, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x10, 0x00, 0x02, 0x01,
+ 0x03, 0x03, 0x02, 0x04, 0x03, 0x05, 0x05, 0x04,
+ 0x04, 0x00, 0x00, 0x01, 0x7d, 0x01, 0x02, 0x03,
+ 0x00, 0x04, 0x11, 0x05, 0x12, 0x21, 0x31, 0x41,
+ 0x06, 0x13, 0x51, 0x61, 0x07, 0x22, 0x71, 0x14,
+ 0x32, 0x81, 0x91, 0xa1, 0x08, 0x23, 0x42, 0xb1,
+ 0xc1, 0x15, 0x52, 0xd1, 0xf0, 0x24, 0x33, 0x62,
+ 0x72, 0x82, 0x09, 0x0a, 0x16, 0x17, 0x18, 0x19,
+ 0x1a, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x34,
+ 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x43, 0x44,
+ 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x53, 0x54,
+ 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x63, 0x64,
+ 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x73, 0x74,
+ 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x83, 0x84,
+ 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x92, 0x93,
+ 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0xa2,
+ 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa,
+ 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9,
+ 0xba, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8,
+ 0xc9, 0xca, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
+ 0xd8, 0xd9, 0xda, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5,
+ 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xf1, 0xf2, 0xf3,
+ 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0x01,
+ 0x00, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x11, 0x00, 0x02, 0x01,
+ 0x02, 0x04, 0x04, 0x03, 0x04, 0x07, 0x05, 0x04,
+ 0x04, 0x00, 0x01, 0x02, 0x77, 0x00, 0x01, 0x02,
+ 0x03, 0x11, 0x04, 0x05, 0x21, 0x31, 0x06, 0x12,
+ 0x41, 0x51, 0x07, 0x61, 0x71, 0x13, 0x22, 0x32,
+ 0x81, 0x08, 0x14, 0x42, 0x91, 0xa1, 0xb1, 0xc1,
+ 0x09, 0x23, 0x33, 0x52, 0xf0, 0x15, 0x62, 0x72,
+ 0xd1, 0x0a, 0x16, 0x24, 0x34, 0xe1, 0x25, 0xf1,
+ 0x17, 0x18, 0x19, 0x1a, 0x26, 0x27, 0x28, 0x29,
+ 0x2a, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x43,
+ 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x53,
+ 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x63,
+ 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x73,
+ 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x82,
+ 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a,
+ 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99,
+ 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8,
+ 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
+ 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6,
+ 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, 0xd5,
+ 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe2, 0xe3, 0xe4,
+ 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xf2, 0xf3,
+ 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xff,
+ 0xc0, 0x00, 0x11, 0x08, 0x00, 0xf0, 0x02, 0xc0,
+ 0x03, 0x01, 0x22, 0x00, 0x02, 0x11, 0x01, 0x03,
+ 0x11, 0x01, 0xff, 0xda, 0x00, 0x0c, 0x03, 0x01,
+ 0x00, 0x02, 0x11, 0x03, 0x11, 0x00, 0x3f, 0x00
+};
+
+/* This is the byte marker for the start of SOF0: 0xffc0 marker */
+#define SOF0_START 575
+
+#endif /* __SOLO6010_JPEG_H */
diff --git a/drivers/staging/solo6x10/solo6010-offsets.h b/drivers/staging/solo6x10/solo6010-offsets.h
new file mode 100644
index 00000000000..2431de989c0
--- /dev/null
+++ b/drivers/staging/solo6x10/solo6010-offsets.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2010 Bluecherry, LLC www.bluecherrydvr.com
+ * Copyright (C) 2010 Ben Collins <bcollins@bluecherry.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.
+ *
+ * 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 __SOLO6010_OFFSETS_H
+#define __SOLO6010_OFFSETS_H
+
+/* Offsets and sizes of the external address */
+#define SOLO_DISP_EXT_ADDR(__solo) 0x00000000
+#define SOLO_DISP_EXT_SIZE 0x00480000
+
+#define SOLO_DEC2LIVE_EXT_ADDR(__solo) \
+ (SOLO_DISP_EXT_ADDR(__solo) + SOLO_DISP_EXT_SIZE)
+#define SOLO_DEC2LIVE_EXT_SIZE 0x00240000
+
+#define SOLO_OSG_EXT_ADDR(__solo) \
+ (SOLO_DEC2LIVE_EXT_ADDR(__solo) + SOLO_DEC2LIVE_EXT_SIZE)
+#define SOLO_OSG_EXT_SIZE 0x00120000
+
+#define SOLO_EOSD_EXT_ADDR(__solo) \
+ (SOLO_OSG_EXT_ADDR(__solo) + SOLO_OSG_EXT_SIZE)
+#define SOLO_EOSD_EXT_SIZE 0x00010000
+
+#define SOLO_MOTION_EXT_ADDR(__solo) \
+ (SOLO_EOSD_EXT_ADDR(__solo) + \
+ (SOLO_EOSD_EXT_SIZE * __solo->nr_chans))
+#define SOLO_MOTION_EXT_SIZE 0x00080000
+
+#define SOLO_G723_EXT_ADDR(__solo) \
+ (SOLO_MOTION_EXT_ADDR(__solo) + SOLO_MOTION_EXT_SIZE)
+#define SOLO_G723_EXT_SIZE 0x00010000
+
+#define SOLO_CAP_EXT_ADDR(__solo) \
+ (SOLO_G723_EXT_ADDR(__solo) + SOLO_G723_EXT_SIZE)
+#define SOLO_CAP_EXT_MAX_PAGE (18 + 15)
+#define SOLO_CAP_EXT_SIZE (SOLO_CAP_EXT_MAX_PAGE * 65536)
+
+/* This +1 is very important -- Why?! -- BenC */
+#define SOLO_EREF_EXT_ADDR(__solo) \
+ (SOLO_CAP_EXT_ADDR(__solo) + \
+ (SOLO_CAP_EXT_SIZE * (__solo->nr_chans + 1)))
+#define SOLO_EREF_EXT_SIZE 0x00140000
+
+#define SOLO_MP4E_EXT_ADDR(__solo) \
+ (SOLO_EREF_EXT_ADDR(__solo) + \
+ (SOLO_EREF_EXT_SIZE * __solo->nr_chans))
+#define SOLO_MP4E_EXT_SIZE(__solo) (0x00080000 * __solo->nr_chans)
+
+#define SOLO_DREF_EXT_ADDR(__solo) \
+ (SOLO_MP4E_EXT_ADDR(__solo) + SOLO_MP4E_EXT_SIZE(__solo))
+#define SOLO_DREF_EXT_SIZE 0x00140000
+
+#define SOLO_MP4D_EXT_ADDR(__solo) \
+ (SOLO_DREF_EXT_ADDR(__solo) + \
+ (SOLO_DREF_EXT_SIZE * __solo->nr_chans))
+#define SOLO_MP4D_EXT_SIZE 0x00080000
+
+#define SOLO_JPEG_EXT_ADDR(__solo) \
+ (SOLO_MP4D_EXT_ADDR(__solo) + \
+ (SOLO_MP4D_EXT_SIZE * __solo->nr_chans))
+#define SOLO_JPEG_EXT_SIZE(__solo) (0x00080000 * __solo->nr_chans)
+
+#endif /* __SOLO6010_OFFSETS_H */
diff --git a/drivers/staging/solo6x10/solo6010-osd-font.h b/drivers/staging/solo6x10/solo6010-osd-font.h
new file mode 100644
index 00000000000..d6f565bd76c
--- /dev/null
+++ b/drivers/staging/solo6x10/solo6010-osd-font.h
@@ -0,0 +1,154 @@
+/*
+ * Copyright (C) 2010 Bluecherry, LLC www.bluecherrydvr.com
+ * Copyright (C) 2010 Ben Collins <bcollins@bluecherry.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.
+ *
+ * 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 __SOLO6010_OSD_FONT_H
+#define __SOLO6010_OSD_FONT_H
+
+static const unsigned int solo_osd_font[] = {
+ 0x00000000, 0x0000c0c8, 0xccfefe0c, 0x08000000,
+ 0x00000000, 0x10103838, 0x7c7cfefe, 0x00000000, // 0
+ 0x00000000, 0xfefe7c7c, 0x38381010, 0x10000000,
+ 0x00000000, 0x7c82fefe, 0xfefefe7c, 0x00000000,
+ 0x00000000, 0x00001038, 0x10000000, 0x00000000,
+ 0x00000000, 0x0010387c, 0xfe7c3810, 0x00000000,
+ 0x00000000, 0x00384444, 0x44380000, 0x00000000,
+ 0x00000000, 0x38448282, 0x82443800, 0x00000000,
+ 0x00000000, 0x007c7c7c, 0x7c7c0000, 0x00000000,
+ 0x00000000, 0x6c6c6c6c, 0x6c6c6c6c, 0x00000000,
+ 0x00000000, 0x061e7efe, 0xfe7e1e06, 0x00000000,
+ 0x00000000, 0xc0f0fcfe, 0xfefcf0c0, 0x00000000,
+ 0x00000000, 0xc6cedefe, 0xfedecec6, 0x00000000,
+ 0x00000000, 0xc6e6f6fe, 0xfef6e6c6, 0x00000000,
+ 0x00000000, 0x12367efe, 0xfe7e3612, 0x00000000,
+ 0x00000000, 0x90d8fcfe, 0xfefcd890, 0x00000000,
+ 0x00000038, 0x7cc692ba, 0x92c67c38, 0x00000000,
+ 0x00000038, 0x7cc6aa92, 0xaac67c38, 0x00000000,
+ 0x00000038, 0x7830107c, 0xbaa8680c, 0x00000000,
+ 0x00000038, 0x3c18127c, 0xb8382c60, 0x00000000,
+ 0x00000044, 0xaa6c8254, 0x38eec67c, 0x00000000,
+ 0x00000082, 0x44288244, 0x38c6827c, 0x00000000,
+ 0x00000038, 0x444444fe, 0xfeeec6fe, 0x00000000,
+ 0x00000018, 0x78187818, 0x3c7e7e3c, 0x00000000,
+ 0x00000000, 0x3854929a, 0x82443800, 0x00000000,
+ 0x00000000, 0x00c0c8cc, 0xfefe0c08, 0x00000000,
+ 0x0000e0a0, 0xe040e00e, 0x8a0ea40e, 0x00000000,
+ 0x0000e0a0, 0xe040e00e, 0x0a8e440e, 0x00000000,
+ 0x0000007c, 0x82829292, 0x929282fe, 0x00000000,
+ 0x000000f8, 0xfc046494, 0x946404fc, 0x00000000,
+ 0x0000003f, 0x7f404c52, 0x524c407f, 0x00000000,
+ 0x0000007c, 0x82ba82ba, 0x82ba82fe, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x183c3c3c, 0x18180018, 0x18000000, // 32 !
+ 0x00000066, 0x66240000, 0x00000000, 0x00000000,
+ 0x00000000, 0x6c6cfe6c, 0x6c6cfe6c, 0x6c000000, // 34 " #
+ 0x00001010, 0x7cd6d616, 0x7cd0d6d6, 0x7c101000,
+ 0x00000000, 0x0086c660, 0x30180cc6, 0xc2000000, // 36 $ %
+ 0x00000000, 0x386c6c38, 0xdc766666, 0xdc000000,
+ 0x0000000c, 0x0c0c0600, 0x00000000, 0x00000000, // 38 & '
+ 0x00000000, 0x30180c0c, 0x0c0c0c18, 0x30000000,
+ 0x00000000, 0x0c183030, 0x30303018, 0x0c000000, // 40 ( )
+ 0x00000000, 0x0000663c, 0xff3c6600, 0x00000000,
+ 0x00000000, 0x00001818, 0x7e181800, 0x00000000, // 42 * +
+ 0x00000000, 0x00000000, 0x00000e0e, 0x0c060000,
+ 0x00000000, 0x00000000, 0x7e000000, 0x00000000, // 44 , -
+ 0x00000000, 0x00000000, 0x00000006, 0x06000000,
+ 0x00000000, 0x80c06030, 0x180c0602, 0x00000000, // 46 . /
+ 0x0000007c, 0xc6e6f6de, 0xcec6c67c, 0x00000000,
+ 0x00000030, 0x383c3030, 0x303030fc, 0x00000000, // 48 0 1
+ 0x0000007c, 0xc6c06030, 0x180cc6fe, 0x00000000,
+ 0x0000007c, 0xc6c0c07c, 0xc0c0c67c, 0x00000000, // 50 2 3
+ 0x00000060, 0x70786c66, 0xfe6060f0, 0x00000000,
+ 0x000000fe, 0x0606067e, 0xc0c0c67c, 0x00000000, // 52 4 5
+ 0x00000038, 0x0c06067e, 0xc6c6c67c, 0x00000000,
+ 0x000000fe, 0xc6c06030, 0x18181818, 0x00000000, // 54 6 7
+ 0x0000007c, 0xc6c6c67c, 0xc6c6c67c, 0x00000000,
+ 0x0000007c, 0xc6c6c6fc, 0xc0c06038, 0x00000000, // 56 8 9
+ 0x00000000, 0x18180000, 0x00181800, 0x00000000,
+ 0x00000000, 0x18180000, 0x0018180c, 0x00000000, // 58 : ;
+ 0x00000060, 0x30180c06, 0x0c183060, 0x00000000,
+ 0x00000000, 0x007e0000, 0x007e0000, 0x00000000,
+ 0x00000006, 0x0c183060, 0x30180c06, 0x00000000,
+ 0x0000007c, 0xc6c66030, 0x30003030, 0x00000000,
+ 0x0000007c, 0xc6f6d6d6, 0x7606067c, 0x00000000,
+ 0x00000010, 0x386cc6c6, 0xfec6c6c6, 0x00000000, // 64 @ A
+ 0x0000007e, 0xc6c6c67e, 0xc6c6c67e, 0x00000000,
+ 0x00000078, 0xcc060606, 0x0606cc78, 0x00000000, // 66
+ 0x0000003e, 0x66c6c6c6, 0xc6c6663e, 0x00000000,
+ 0x000000fe, 0x0606063e, 0x060606fe, 0x00000000, // 68
+ 0x000000fe, 0x0606063e, 0x06060606, 0x00000000,
+ 0x00000078, 0xcc060606, 0xf6c6ccb8, 0x00000000, // 70
+ 0x000000c6, 0xc6c6c6fe, 0xc6c6c6c6, 0x00000000,
+ 0x0000003c, 0x18181818, 0x1818183c, 0x00000000, // 72
+ 0x00000060, 0x60606060, 0x6066663c, 0x00000000,
+ 0x000000c6, 0xc666361e, 0x3666c6c6, 0x00000000, // 74
+ 0x00000006, 0x06060606, 0x060606fe, 0x00000000,
+ 0x000000c6, 0xeefed6c6, 0xc6c6c6c6, 0x00000000, // 76
+ 0x000000c6, 0xcedefef6, 0xe6c6c6c6, 0x00000000,
+ 0x00000038, 0x6cc6c6c6, 0xc6c66c38, 0x00000000, // 78
+ 0x0000007e, 0xc6c6c67e, 0x06060606, 0x00000000,
+ 0x00000038, 0x6cc6c6c6, 0xc6d67c38, 0x60000000, // 80
+ 0x0000007e, 0xc6c6c67e, 0x66c6c6c6, 0x00000000,
+ 0x0000007c, 0xc6c60c38, 0x60c6c67c, 0x00000000, // 82
+ 0x0000007e, 0x18181818, 0x18181818, 0x00000000,
+ 0x000000c6, 0xc6c6c6c6, 0xc6c6c67c, 0x00000000, // 84
+ 0x000000c6, 0xc6c6c6c6, 0xc66c3810, 0x00000000,
+ 0x000000c6, 0xc6c6c6c6, 0xd6d6fe6c, 0x00000000, // 86
+ 0x000000c6, 0xc6c66c38, 0x6cc6c6c6, 0x00000000,
+ 0x00000066, 0x66666666, 0x3c181818, 0x00000000, // 88
+ 0x000000fe, 0xc0603018, 0x0c0606fe, 0x00000000,
+ 0x0000003c, 0x0c0c0c0c, 0x0c0c0c3c, 0x00000000, // 90
+ 0x00000002, 0x060c1830, 0x60c08000, 0x00000000,
+ 0x0000003c, 0x30303030, 0x3030303c, 0x00000000, // 92
+ 0x00001038, 0x6cc60000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00fe0000,
+ 0x00001818, 0x30000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00003c60, 0x7c66667c, 0x00000000,
+ 0x0000000c, 0x0c0c7ccc, 0xcccccc7c, 0x00000000,
+ 0x00000000, 0x00007cc6, 0x0606c67c, 0x00000000,
+ 0x00000060, 0x60607c66, 0x6666667c, 0x00000000,
+ 0x00000000, 0x00007cc6, 0xfe06c67c, 0x00000000,
+ 0x00000078, 0x0c0c0c3e, 0x0c0c0c0c, 0x00000000,
+ 0x00000000, 0x00007c66, 0x6666667c, 0x60603e00,
+ 0x0000000c, 0x0c0c7ccc, 0xcccccccc, 0x00000000,
+ 0x00000030, 0x30003830, 0x30303078, 0x00000000,
+ 0x00000030, 0x30003c30, 0x30303030, 0x30301f00,
+ 0x0000000c, 0x0c0ccc6c, 0x3c6ccccc, 0x00000000,
+ 0x00000030, 0x30303030, 0x30303030, 0x00000000,
+ 0x00000000, 0x000066fe, 0xd6d6d6d6, 0x00000000,
+ 0x00000000, 0x000078cc, 0xcccccccc, 0x00000000,
+ 0x00000000, 0x00007cc6, 0xc6c6c67c, 0x00000000,
+ 0x00000000, 0x00007ccc, 0xcccccc7c, 0x0c0c0c00,
+ 0x00000000, 0x00007c66, 0x6666667c, 0x60606000,
+ 0x00000000, 0x000076dc, 0x0c0c0c0c, 0x00000000,
+ 0x00000000, 0x00007cc6, 0x1c70c67c, 0x00000000,
+ 0x00000000, 0x1818fe18, 0x18181870, 0x00000000,
+ 0x00000000, 0x00006666, 0x6666663c, 0x00000000,
+ 0x00000000, 0x0000c6c6, 0xc66c3810, 0x00000000,
+ 0x00000000, 0x0000c6d6, 0xd6d6fe6c, 0x00000000,
+ 0x00000000, 0x0000c66c, 0x38386cc6, 0x00000000,
+ 0x00000000, 0x00006666, 0x6666667c, 0x60603e00,
+ 0x00000000, 0x0000fe60, 0x30180cfe, 0x00000000,
+ 0x00000070, 0x1818180e, 0x18181870, 0x00000000,
+ 0x00000018, 0x18181800, 0x18181818, 0x00000000,
+ 0x0000000e, 0x18181870, 0x1818180e, 0x00000000,
+ 0x000000dc, 0x76000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x0010386c, 0xc6c6fe00, 0x00000000
+};
+
+#endif /* __SOLO6010_OSD_FONT_H */
diff --git a/drivers/staging/solo6x10/solo6010-p2m.c b/drivers/staging/solo6x10/solo6010-p2m.c
new file mode 100644
index 00000000000..1b81f069c7f
--- /dev/null
+++ b/drivers/staging/solo6x10/solo6010-p2m.c
@@ -0,0 +1,208 @@
+/*
+ * Copyright (C) 2010 Bluecherry, LLC www.bluecherrydvr.com
+ * Copyright (C) 2010 Ben Collins <bcollins@bluecherry.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.
+ *
+ * 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 "solo6010.h"
+
+// #define SOLO_TEST_P2M
+
+int solo_p2m_dma(struct solo6010_dev *solo_dev, u8 id, int wr,
+ void *sys_addr, u32 ext_addr, u32 size)
+{
+ dma_addr_t dma_addr;
+ int ret;
+
+ WARN_ON(!size);
+ WARN_ON(id >= SOLO_NR_P2M);
+ if (!size || id >= SOLO_NR_P2M)
+ return -EINVAL;
+
+ dma_addr = pci_map_single(solo_dev->pdev, sys_addr, size,
+ wr ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE);
+
+ ret = solo_p2m_dma_t(solo_dev, id, wr, dma_addr, ext_addr, size);
+
+ pci_unmap_single(solo_dev->pdev, dma_addr, size,
+ wr ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE);
+
+ return ret;
+}
+
+int solo_p2m_dma_t(struct solo6010_dev *solo_dev, u8 id, int wr,
+ dma_addr_t dma_addr, u32 ext_addr, u32 size)
+{
+ struct solo_p2m_dev *p2m_dev;
+ unsigned int timeout = 0;
+
+ WARN_ON(!size);
+ WARN_ON(id >= SOLO_NR_P2M);
+ if (!size || id >= SOLO_NR_P2M)
+ return -EINVAL;
+
+ p2m_dev = &solo_dev->p2m_dev[id];
+
+ down(&p2m_dev->sem);
+
+start_dma:
+ INIT_COMPLETION(p2m_dev->completion);
+ p2m_dev->error = 0;
+ solo_reg_write(solo_dev, SOLO_P2M_TAR_ADR(id), dma_addr);
+ solo_reg_write(solo_dev, SOLO_P2M_EXT_ADR(id), ext_addr);
+ solo_reg_write(solo_dev, SOLO_P2M_EXT_CFG(id),
+ SOLO_P2M_COPY_SIZE(size >> 2));
+ solo_reg_write(solo_dev, SOLO_P2M_CONTROL(id),
+ SOLO_P2M_BURST_SIZE(SOLO_P2M_BURST_256) |
+ (wr ? SOLO_P2M_WRITE : 0) | SOLO_P2M_TRANS_ON);
+
+ timeout = wait_for_completion_timeout(&p2m_dev->completion, HZ);
+
+ solo_reg_write(solo_dev, SOLO_P2M_CONTROL(id), 0);
+
+ /* XXX Really looks to me like we will get stuck here if a
+ * real PCI P2M error occurs */
+ if (p2m_dev->error)
+ goto start_dma;
+
+ up(&p2m_dev->sem);
+
+ return (timeout == 0) ? -EAGAIN : 0;
+}
+
+#ifdef SOLO_TEST_P2M
+
+#define P2M_TEST_CHAR 0xbe
+
+static unsigned long long p2m_test(struct solo6010_dev *solo_dev, u8 id,
+ u32 base, int size)
+{
+ u8 *wr_buf;
+ u8 *rd_buf;
+ int i;
+ unsigned long long err_cnt = 0;
+
+ wr_buf = kmalloc(size, GFP_KERNEL);
+ if (!wr_buf) {
+ printk(SOLO6010_NAME ": Failed to malloc for p2m_test\n");
+ return size;
+ }
+
+ rd_buf = kmalloc(size, GFP_KERNEL);
+ if (!rd_buf) {
+ printk(SOLO6010_NAME ": Failed to malloc for p2m_test\n");
+ kfree(wr_buf);
+ return size;
+ }
+
+ memset(wr_buf, P2M_TEST_CHAR, size);
+ memset(rd_buf, P2M_TEST_CHAR + 1, size);
+
+ solo_p2m_dma(solo_dev, id, 1, wr_buf, base, size);
+ solo_p2m_dma(solo_dev, id, 0, rd_buf, base, size);
+
+ for (i = 0; i < size; i++)
+ if (wr_buf[i] != rd_buf[i])
+ err_cnt++;
+
+ kfree(wr_buf);
+ kfree(rd_buf);
+
+ return err_cnt;
+}
+
+#define TEST_CHUNK_SIZE (8 * 1024)
+
+static void run_p2m_test(struct solo6010_dev *solo_dev)
+{
+ unsigned long long errs = 0;
+ u32 size = SOLO_JPEG_EXT_ADDR(solo_dev) + SOLO_JPEG_EXT_SIZE(solo_dev);
+ int i, d;
+
+ printk(KERN_WARNING "%s: Testing %u bytes of external ram\n",
+ SOLO6010_NAME, size);
+
+ for (i = 0; i < size; i += TEST_CHUNK_SIZE)
+ for (d = 0; d < 4; d++)
+ errs += p2m_test(solo_dev, d, i, TEST_CHUNK_SIZE);
+
+ printk(KERN_WARNING "%s: Found %llu errors during p2m test\n",
+ SOLO6010_NAME, errs);
+
+ return;
+}
+#else
+#define run_p2m_test(__solo) do{}while(0)
+#endif
+
+void solo_p2m_isr(struct solo6010_dev *solo_dev, int id)
+{
+ solo_reg_write(solo_dev, SOLO_IRQ_STAT, SOLO_IRQ_P2M(id));
+ complete(&solo_dev->p2m_dev[id].completion);
+}
+
+void solo_p2m_error_isr(struct solo6010_dev *solo_dev, u32 status)
+{
+ struct solo_p2m_dev *p2m_dev;
+ int i;
+
+ if (!(status & SOLO_PCI_ERR_P2M))
+ return;
+
+ for (i = 0; i < SOLO_NR_P2M; i++) {
+ p2m_dev = &solo_dev->p2m_dev[i];
+ p2m_dev->error = 1;
+ solo_reg_write(solo_dev, SOLO_P2M_CONTROL(i), 0);
+ complete(&p2m_dev->completion);
+ }
+}
+
+void solo_p2m_exit(struct solo6010_dev *solo_dev)
+{
+ int i;
+
+ for (i = 0; i < SOLO_NR_P2M; i++)
+ solo6010_irq_off(solo_dev, SOLO_IRQ_P2M(i));
+}
+
+int solo_p2m_init(struct solo6010_dev *solo_dev)
+{
+ struct solo_p2m_dev *p2m_dev;
+ int i;
+
+ for (i = 0; i < SOLO_NR_P2M; i++) {
+ p2m_dev = &solo_dev->p2m_dev[i];
+
+ init_MUTEX(&p2m_dev->sem);
+ init_completion(&p2m_dev->completion);
+
+ solo_reg_write(solo_dev, SOLO_P2M_DES_ADR(i),
+ __pa(p2m_dev->desc));
+
+ solo_reg_write(solo_dev, SOLO_P2M_CONTROL(i), 0);
+ solo_reg_write(solo_dev, SOLO_P2M_CONFIG(i),
+ SOLO_P2M_CSC_16BIT_565 |
+ SOLO_P2M_DMA_INTERVAL(0) |
+ SOLO_P2M_PCI_MASTER_MODE);
+ solo6010_irq_on(solo_dev, SOLO_IRQ_P2M(i));
+ }
+
+ run_p2m_test(solo_dev);
+
+ return 0;
+}
diff --git a/drivers/staging/solo6x10/solo6010-registers.h b/drivers/staging/solo6x10/solo6010-registers.h
new file mode 100644
index 00000000000..d39d3c636f5
--- /dev/null
+++ b/drivers/staging/solo6x10/solo6010-registers.h
@@ -0,0 +1,657 @@
+/*
+ * Copyright (C) 2010 Bluecherry, LLC www.bluecherrydvr.com
+ * Copyright (C) 2010 Ben Collins <bcollins@bluecherry.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.
+ *
+ * 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 __SOLO6010_REGISTERS_H
+#define __SOLO6010_REGISTERS_H
+
+#include "solo6010-offsets.h"
+
+/* Global 6010 system configuration */
+#define SOLO_SYS_CFG 0x0000
+#define SOLO_SYS_CFG_FOUT_EN 0x00000001
+#define SOLO_SYS_CFG_PLL_BYPASS 0x00000002
+#define SOLO_SYS_CFG_PLL_PWDN 0x00000004
+#define SOLO_SYS_CFG_OUTDIV(__n) (((__n) & 0x003) << 3)
+#define SOLO_SYS_CFG_FEEDBACKDIV(__n) (((__n) & 0x1ff) << 5)
+#define SOLO_SYS_CFG_INPUTDIV(__n) (((__n) & 0x01f) << 14)
+#define SOLO_SYS_CFG_CLOCK_DIV 0x00080000
+#define SOLO_SYS_CFG_NCLK_DELAY(__n) (((__n) & 0x003) << 24)
+#define SOLO_SYS_CFG_PCLK_DELAY(__n) (((__n) & 0x00f) << 26)
+#define SOLO_SYS_CFG_SDRAM64BIT 0x40000000
+#define SOLO_SYS_CFG_RESET 0x80000000
+
+#define SOLO_DMA_CTRL 0x0004
+#define SOLO_DMA_CTRL_REFRESH_CYCLE(n) ((n)<<8)
+/* 0=16/32MB, 1=32/64MB, 2=64/128MB, 3=128/256MB */
+#define SOLO_DMA_CTRL_SDRAM_SIZE(n) ((n)<<6)
+#define SOLO_DMA_CTRL_SDRAM_CLK_INVERT (1<<5)
+#define SOLO_DMA_CTRL_STROBE_SELECT (1<<4)
+#define SOLO_DMA_CTRL_READ_DATA_SELECT (1<<3)
+#define SOLO_DMA_CTRL_READ_CLK_SELECT (1<<2)
+#define SOLO_DMA_CTRL_LATENCY(n) ((n)<<0)
+
+#define SOLO_SYS_VCLK 0x000C
+#define SOLO_VCLK_INVERT (1<<22)
+/* 0=sys_clk/4, 1=sys_clk/2, 2=clk_in/2 of system input */
+#define SOLO_VCLK_SELECT(n) ((n)<<20)
+#define SOLO_VCLK_VIN1415_DELAY(n) ((n)<<14)
+#define SOLO_VCLK_VIN1213_DELAY(n) ((n)<<12)
+#define SOLO_VCLK_VIN1011_DELAY(n) ((n)<<10)
+#define SOLO_VCLK_VIN0809_DELAY(n) ((n)<<8)
+#define SOLO_VCLK_VIN0607_DELAY(n) ((n)<<6)
+#define SOLO_VCLK_VIN0405_DELAY(n) ((n)<<4)
+#define SOLO_VCLK_VIN0203_DELAY(n) ((n)<<2)
+#define SOLO_VCLK_VIN0001_DELAY(n) ((n)<<0)
+
+#define SOLO_IRQ_STAT 0x0010
+#define SOLO_IRQ_ENABLE 0x0014
+#define SOLO_IRQ_P2M(n) (1<<((n)+17))
+#define SOLO_IRQ_GPIO (1<<16)
+#define SOLO_IRQ_VIDEO_LOSS (1<<15)
+#define SOLO_IRQ_VIDEO_IN (1<<14)
+#define SOLO_IRQ_MOTION (1<<13)
+#define SOLO_IRQ_ATA_CMD (1<<12)
+#define SOLO_IRQ_ATA_DIR (1<<11)
+#define SOLO_IRQ_PCI_ERR (1<<10)
+#define SOLO_IRQ_PS2_1 (1<<9)
+#define SOLO_IRQ_PS2_0 (1<<8)
+#define SOLO_IRQ_SPI (1<<7)
+#define SOLO_IRQ_IIC (1<<6)
+#define SOLO_IRQ_UART(n) (1<<((n) + 4))
+#define SOLO_IRQ_G723 (1<<3)
+#define SOLO_IRQ_DECODER (1<<1)
+#define SOLO_IRQ_ENCODER (1<<0)
+
+#define SOLO_CHIP_OPTION 0x001C
+#define SOLO_CHIP_ID_MASK 0x00000007
+
+#define SOLO_EEPROM_CTRL 0x0060
+#define SOLO_EEPROM_ACCESS_EN (1<<7)
+#define SOLO_EEPROM_CS (1<<3)
+#define SOLO_EEPROM_CLK (1<<2)
+#define SOLO_EEPROM_DO (1<<1)
+#define SOLO_EEPROM_DI (1<<0)
+#define SOLO_EEPROM_ENABLE (EEPROM_ACCESS_EN | EEPROM_CS)
+
+#define SOLO_PCI_ERR 0x0070
+#define SOLO_PCI_ERR_FATAL 0x00000001
+#define SOLO_PCI_ERR_PARITY 0x00000002
+#define SOLO_PCI_ERR_TARGET 0x00000004
+#define SOLO_PCI_ERR_TIMEOUT 0x00000008
+#define SOLO_PCI_ERR_P2M 0x00000010
+#define SOLO_PCI_ERR_ATA 0x00000020
+#define SOLO_PCI_ERR_P2M_DESC 0x00000040
+#define SOLO_PCI_ERR_FSM0(__s) (((__s) >> 16) & 0x0f)
+#define SOLO_PCI_ERR_FSM1(__s) (((__s) >> 20) & 0x0f)
+#define SOLO_PCI_ERR_FSM2(__s) (((__s) >> 24) & 0x1f)
+
+#define SOLO_P2M_BASE 0x0080
+
+#define SOLO_P2M_CONFIG(n) (0x0080 + ((n)*0x20))
+#define SOLO_P2M_DMA_INTERVAL(n) ((n)<<6)/* N*32 clocks */
+#define SOLO_P2M_CSC_BYTE_REORDER (1<<5) /* BGR -> RGB */
+/* 0:r=[14:10] g=[9:5] b=[4:0], 1:r=[15:11] g=[10:5] b=[4:0] */
+#define SOLO_P2M_CSC_16BIT_565 (1<<4)
+#define SOLO_P2M_UV_SWAP (1<<3)
+#define SOLO_P2M_PCI_MASTER_MODE (1<<2)
+#define SOLO_P2M_DESC_INTR_OPT (1<<1) /* 1:Empty, 0:Each */
+#define SOLO_P2M_DESC_MODE (1<<0)
+
+#define SOLO_P2M_DES_ADR(n) (0x0084 + ((n)*0x20))
+
+#define SOLO_P2M_DESC_ID(n) (0x0088 + ((n)*0x20))
+#define SOLO_P2M_UPDATE_ID(n) ((n)<<0)
+
+#define SOLO_P2M_STATUS(n) (0x008C + ((n)*0x20))
+#define SOLO_P2M_COMMAND_DONE (1<<8)
+#define SOLO_P2M_CURRENT_ID(stat) (0xff & (stat))
+
+#define SOLO_P2M_CONTROL(n) (0x0090 + ((n)*0x20))
+#define SOLO_P2M_PCI_INC(n) ((n)<<20)
+#define SOLO_P2M_REPEAT(n) ((n)<<10)
+/* 0:512, 1:256, 2:128, 3:64, 4:32, 5:128(2page) */
+#define SOLO_P2M_BURST_SIZE(n) ((n)<<7)
+#define SOLO_P2M_BURST_512 0
+#define SOLO_P2M_BURST_256 1
+#define SOLO_P2M_BURST_128 2
+#define SOLO_P2M_BURST_64 3
+#define SOLO_P2M_BURST_32 4
+#define SOLO_P2M_CSC_16BIT (1<<6) /* 0:24bit, 1:16bit */
+/* 0:Y[0]<-0(OFF), 1:Y[0]<-1(ON), 2:Y[0]<-G[0], 3:Y[0]<-Bit[15] */
+#define SOLO_P2M_ALPHA_MODE(n) ((n)<<4)
+#define SOLO_P2M_CSC_ON (1<<3)
+#define SOLO_P2M_INTERRUPT_REQ (1<<2)
+#define SOLO_P2M_WRITE (1<<1)
+#define SOLO_P2M_TRANS_ON (1<<0)
+
+#define SOLO_P2M_EXT_CFG(n) (0x0094 + ((n)*0x20))
+#define SOLO_P2M_EXT_INC(n) ((n)<<20)
+#define SOLO_P2M_COPY_SIZE(n) ((n)<<0)
+
+#define SOLO_P2M_TAR_ADR(n) (0x0098 + ((n)*0x20))
+
+#define SOLO_P2M_EXT_ADR(n) (0x009C + ((n)*0x20))
+
+#define SOLO_P2M_BUFFER(i) (0x2000 + ((i)*4))
+
+#define SOLO_VI_CH_SWITCH_0 0x0100
+#define SOLO_VI_CH_SWITCH_1 0x0104
+#define SOLO_VI_CH_SWITCH_2 0x0108
+
+#define SOLO_VI_CH_ENA 0x010C
+#define SOLO_VI_CH_FORMAT 0x0110
+#define SOLO_VI_FD_SEL_MASK(n) ((n)<<16)
+#define SOLO_VI_PROG_MASK(n) ((n)<<0)
+
+#define SOLO_VI_FMT_CFG 0x0114
+#define SOLO_VI_FMT_CHECK_VCOUNT (1<<31)
+#define SOLO_VI_FMT_CHECK_HCOUNT (1<<30)
+#define SOLO_VI_FMT_TEST_SIGNAL (1<<28)
+
+#define SOLO_VI_PAGE_SW 0x0118
+#define SOLO_FI_INV_DISP_LIVE(n) ((n)<<8)
+#define SOLO_FI_INV_DISP_OUT(n) ((n)<<7)
+#define SOLO_DISP_SYNC_FI(n) ((n)<<6)
+#define SOLO_PIP_PAGE_ADD(n) ((n)<<3)
+#define SOLO_NORMAL_PAGE_ADD(n) ((n)<<0)
+
+#define SOLO_VI_ACT_I_P 0x011C
+#define SOLO_VI_ACT_I_S 0x0120
+#define SOLO_VI_ACT_P 0x0124
+#define SOLO_VI_FI_INVERT (1<<31)
+#define SOLO_VI_H_START(n) ((n)<<21)
+#define SOLO_VI_V_START(n) ((n)<<11)
+#define SOLO_VI_V_STOP(n) ((n)<<0)
+
+#define SOLO_VI_STATUS0 0x0128
+#define SOLO_VI_STATUS0_PAGE(__n) ((__n) & 0x07)
+#define SOLO_VI_STATUS1 0x012C
+
+/* XXX: Might be better off in kernel level disp.h */
+#define DISP_PAGE(stat) ((stat) & 0x07)
+
+#define SOLO_VI_PB_CONFIG 0x0130
+#define SOLO_VI_PB_USER_MODE (1<<1)
+#define SOLO_VI_PB_PAL (1<<0)
+#define SOLO_VI_PB_RANGE_HV 0x0134
+#define SOLO_VI_PB_HSIZE(h) ((h)<<12)
+#define SOLO_VI_PB_VSIZE(v) ((v)<<0)
+#define SOLO_VI_PB_ACT_H 0x0138
+#define SOLO_VI_PB_HSTART(n) ((n)<<12)
+#define SOLO_VI_PB_HSTOP(n) ((n)<<0)
+#define SOLO_VI_PB_ACT_V 0x013C
+#define SOLO_VI_PB_VSTART(n) ((n)<<12)
+#define SOLO_VI_PB_VSTOP(n) ((n)<<0)
+
+#define SOLO_VI_MOSAIC(ch) (0x0140 + ((ch)*4))
+#define SOLO_VI_MOSAIC_SX(x) ((x)<<24)
+#define SOLO_VI_MOSAIC_EX(x) ((x)<<16)
+#define SOLO_VI_MOSAIC_SY(x) ((x)<<8)
+#define SOLO_VI_MOSAIC_EY(x) ((x)<<0)
+
+#define SOLO_VI_WIN_CTRL0(ch) (0x0180 + ((ch)*4))
+#define SOLO_VI_WIN_CTRL1(ch) (0x01C0 + ((ch)*4))
+
+#define SOLO_VI_WIN_CHANNEL(n) ((n)<<28)
+
+#define SOLO_VI_WIN_PIP(n) ((n)<<27)
+#define SOLO_VI_WIN_SCALE(n) ((n)<<24)
+
+#define SOLO_VI_WIN_SX(x) ((x)<<12)
+#define SOLO_VI_WIN_EX(x) ((x)<<0)
+
+#define SOLO_VI_WIN_SY(x) ((x)<<12)
+#define SOLO_VI_WIN_EY(x) ((x)<<0)
+
+#define SOLO_VI_WIN_ON(ch) (0x0200 + ((ch)*4))
+
+#define SOLO_VI_WIN_SW 0x0240
+#define SOLO_VI_WIN_LIVE_AUTO_MUTE 0x0244
+
+#define SOLO_VI_MOT_ADR 0x0260
+#define SOLO_VI_MOTION_EN(mask) ((mask)<<16)
+#define SOLO_VI_MOT_CTRL 0x0264
+#define SOLO_VI_MOTION_FRAME_COUNT(n) ((n)<<24)
+#define SOLO_VI_MOTION_SAMPLE_LENGTH(n) ((n)<<16)
+#define SOLO_VI_MOTION_INTR_START_STOP (1<<15)
+#define SOLO_VI_MOTION_FREEZE_DATA (1<<14)
+#define SOLO_VI_MOTION_SAMPLE_COUNT(n) ((n)<<0)
+#define SOLO_VI_MOT_CLEAR 0x0268
+#define SOLO_VI_MOT_STATUS 0x026C
+#define SOLO_VI_MOTION_CNT(n) ((n)<<0)
+#define SOLO_VI_MOTION_BORDER 0x0270
+#define SOLO_VI_MOTION_BAR 0x0274
+#define SOLO_VI_MOTION_Y_SET (1<<29)
+#define SOLO_VI_MOTION_Y_ADD (1<<28)
+#define SOLO_VI_MOTION_CB_SET (1<<27)
+#define SOLO_VI_MOTION_CB_ADD (1<<26)
+#define SOLO_VI_MOTION_CR_SET (1<<25)
+#define SOLO_VI_MOTION_CR_ADD (1<<24)
+#define SOLO_VI_MOTION_Y_VALUE(v) ((v)<<16)
+#define SOLO_VI_MOTION_CB_VALUE(v) ((v)<<8)
+#define SOLO_VI_MOTION_CR_VALUE(v) ((v)<<0)
+
+#define SOLO_VO_FMT_ENC 0x0300
+#define SOLO_VO_SCAN_MODE_PROGRESSIVE (1<<31)
+#define SOLO_VO_FMT_TYPE_PAL (1<<30)
+#define SOLO_VO_FMT_TYPE_NTSC 0
+#define SOLO_VO_USER_SET (1<<29)
+
+#define SOLO_VO_FI_CHANGE (1<<20)
+#define SOLO_VO_USER_COLOR_SET_VSYNC (1<<19)
+#define SOLO_VO_USER_COLOR_SET_HSYNC (1<<18)
+#define SOLO_VO_USER_COLOR_SET_NAV (1<<17)
+#define SOLO_VO_USER_COLOR_SET_NAH (1<<16)
+#define SOLO_VO_NA_COLOR_Y(Y) ((Y)<<8)
+#define SOLO_VO_NA_COLOR_CB(CB) (((CB)/16)<<4)
+#define SOLO_VO_NA_COLOR_CR(CR) (((CR)/16)<<0)
+
+#define SOLO_VO_ACT_H 0x0304
+#define SOLO_VO_H_BLANK(n) ((n)<<22)
+#define SOLO_VO_H_START(n) ((n)<<11)
+#define SOLO_VO_H_STOP(n) ((n)<<0)
+
+#define SOLO_VO_ACT_V 0x0308
+#define SOLO_VO_V_BLANK(n) ((n)<<22)
+#define SOLO_VO_V_START(n) ((n)<<11)
+#define SOLO_VO_V_STOP(n) ((n)<<0)
+
+#define SOLO_VO_RANGE_HV 0x030C
+#define SOLO_VO_SYNC_INVERT (1<<24)
+#define SOLO_VO_HSYNC_INVERT (1<<23)
+#define SOLO_VO_VSYNC_INVERT (1<<22)
+#define SOLO_VO_H_LEN(n) ((n)<<11)
+#define SOLO_VO_V_LEN(n) ((n)<<0)
+
+#define SOLO_VO_DISP_CTRL 0x0310
+#define SOLO_VO_DISP_ON (1<<31)
+#define SOLO_VO_DISP_ERASE_COUNT(n) ((n&0xf)<<24)
+#define SOLO_VO_DISP_DOUBLE_SCAN (1<<22)
+#define SOLO_VO_DISP_SINGLE_PAGE (1<<21)
+#define SOLO_VO_DISP_BASE(n) (((n)>>16) & 0xffff)
+
+#define SOLO_VO_DISP_ERASE 0x0314
+#define SOLO_VO_DISP_ERASE_ON (1<<0)
+
+#define SOLO_VO_ZOOM_CTRL 0x0318
+#define SOLO_VO_ZOOM_VER_ON (1<<24)
+#define SOLO_VO_ZOOM_HOR_ON (1<<23)
+#define SOLO_VO_ZOOM_V_COMP (1<<22)
+#define SOLO_VO_ZOOM_SX(h) (((h)/2)<<11)
+#define SOLO_VO_ZOOM_SY(v) (((v)/2)<<0)
+
+#define SOLO_VO_FREEZE_CTRL 0x031C
+#define SOLO_VO_FREEZE_ON (1<<1)
+#define SOLO_VO_FREEZE_INTERPOLATION (1<<0)
+
+#define SOLO_VO_BKG_COLOR 0x0320
+#define SOLO_BG_Y(y) ((y)<<16)
+#define SOLO_BG_U(u) ((u)<<8)
+#define SOLO_BG_V(v) ((v)<<0)
+
+#define SOLO_VO_DEINTERLACE 0x0324
+#define SOLO_VO_DEINTERLACE_THRESHOLD(n) ((n)<<8)
+#define SOLO_VO_DEINTERLACE_EDGE_VALUE(n) ((n)<<0)
+
+#define SOLO_VO_BORDER_LINE_COLOR 0x0330
+#define SOLO_VO_BORDER_FILL_COLOR 0x0334
+#define SOLO_VO_BORDER_LINE_MASK 0x0338
+#define SOLO_VO_BORDER_FILL_MASK 0x033c
+
+#define SOLO_VO_BORDER_X(n) (0x0340+((n)*4))
+#define SOLO_VO_BORDER_Y(n) (0x0354+((n)*4))
+
+#define SOLO_VO_CELL_EXT_SET 0x0368
+#define SOLO_VO_CELL_EXT_START 0x036c
+#define SOLO_VO_CELL_EXT_STOP 0x0370
+
+#define SOLO_VO_CELL_EXT_SET2 0x0374
+#define SOLO_VO_CELL_EXT_START2 0x0378
+#define SOLO_VO_CELL_EXT_STOP2 0x037c
+
+#define SOLO_VO_RECTANGLE_CTRL(n) (0x0368+((n)*12))
+#define SOLO_VO_RECTANGLE_START(n) (0x036c+((n)*12))
+#define SOLO_VO_RECTANGLE_STOP(n) (0x0370+((n)*12))
+
+#define SOLO_VO_CURSOR_POS (0x0380)
+#define SOLO_VO_CURSOR_CLR (0x0384)
+#define SOLO_VO_CURSOR_CLR2 (0x0388)
+#define SOLO_VO_CURSOR_MASK(id) (0x0390+((id)*4))
+
+#define SOLO_VO_EXPANSION(id) (0x0250+((id)*4))
+
+#define SOLO_OSG_CONFIG 0x03E0
+#define SOLO_VO_OSG_ON (1<<31)
+#define SOLO_VO_OSG_COLOR_MUTE (1<<28)
+#define SOLO_VO_OSG_ALPHA_RATE(n) ((n)<<22)
+#define SOLO_VO_OSG_ALPHA_BG_RATE(n) ((n)<<16)
+#define SOLO_VO_OSG_BASE(offset) (((offset)>>16)&0xffff)
+
+#define SOLO_OSG_ERASE 0x03E4
+#define SOLO_OSG_ERASE_ON (0x80)
+#define SOLO_OSG_ERASE_OFF (0x00)
+
+#define SOLO_VO_OSG_BLINK 0x03E8
+#define SOLO_VO_OSG_BLINK_ON (1<<1)
+#define SOLO_VO_OSG_BLINK_INTREVAL18 (1<<0)
+
+#define SOLO_CAP_BASE 0x0400
+#define SOLO_CAP_MAX_PAGE(n) ((n)<<16)
+#define SOLO_CAP_BASE_ADDR(n) ((n)<<0)
+#define SOLO_CAP_BTW 0x0404
+#define SOLO_CAP_PROG_BANDWIDTH(n) ((n)<<8)
+#define SOLO_CAP_MAX_BANDWIDTH(n) ((n)<<0)
+
+#define SOLO_DIM_SCALE1 0x0408
+#define SOLO_DIM_SCALE2 0x040C
+#define SOLO_DIM_SCALE3 0x0410
+#define SOLO_DIM_SCALE4 0x0414
+#define SOLO_DIM_SCALE5 0x0418
+#define SOLO_DIM_V_MB_NUM_FRAME(n) ((n)<<16)
+#define SOLO_DIM_V_MB_NUM_FIELD(n) ((n)<<8)
+#define SOLO_DIM_H_MB_NUM(n) ((n)<<0)
+
+#define SOLO_DIM_PROG 0x041C
+#define SOLO_CAP_STATUS 0x0420
+
+#define SOLO_CAP_CH_SCALE(ch) (0x0440+((ch)*4))
+#define SOLO_CAP_CH_COMP_ENA_E(ch) (0x0480+((ch)*4))
+#define SOLO_CAP_CH_INTV(ch) (0x04C0+((ch)*4))
+#define SOLO_CAP_CH_INTV_E(ch) (0x0500+((ch)*4))
+
+
+#define SOLO_VE_CFG0 0x0610
+#define SOLO_VE_TWO_PAGE_MODE (1<<31)
+#define SOLO_VE_INTR_CTRL(n) ((n)<<24)
+#define SOLO_VE_BLOCK_SIZE(n) ((n)<<16)
+#define SOLO_VE_BLOCK_BASE(n) ((n)<<0)
+
+#define SOLO_VE_CFG1 0x0614
+#define SOLO_VE_BYTE_ALIGN(n) ((n)<<24)
+#define SOLO_VE_INSERT_INDEX (1<<18)
+#define SOLO_VE_MOTION_MODE(n) ((n)<<16)
+#define SOLO_VE_MOTION_BASE(n) ((n)<<0)
+
+#define SOLO_VE_WMRK_POLY 0x061C
+#define SOLO_VE_VMRK_INIT_KEY 0x0620
+#define SOLO_VE_WMRK_STRL 0x0624
+#define SOLO_VE_ENCRYP_POLY 0x0628
+#define SOLO_VE_ENCRYP_INIT 0x062C
+#define SOLO_VE_ATTR 0x0630
+#define SOLO_VE_LITTLE_ENDIAN (1<<31)
+#define SOLO_COMP_ATTR_RN (1<<30)
+#define SOLO_COMP_ATTR_FCODE(n) ((n)<<27)
+#define SOLO_COMP_TIME_INC(n) ((n)<<25)
+#define SOLO_COMP_TIME_WIDTH(n) ((n)<<21)
+#define SOLO_DCT_INTERVAL(n) ((n)<<16)
+
+#define SOLO_VE_STATE(n) (0x0640+((n)*4))
+struct videnc_status {
+ union {
+ u32 status0;
+ struct {
+ u32 mp4_enc_code_size:20, sad_motion:1, vid_motion:1,
+ vop_type:2, video_channel:5, source_field_idx:1,
+ interlace:1, progressive:1;
+ } status0_st;
+ };
+ union {
+ u32 status1;
+ struct {
+ u32 vsize:8, hsize:8, last_queue:4, foo1:8, scale:4;
+ } status1_st;
+ };
+ union {
+ u32 status4;
+ struct {
+ u32 jpeg_code_size:20, interval:10, foo1:2;
+ } status4_st;
+ };
+ union {
+ u32 status9;
+ struct {
+ u32 channel:5, foo1:27;
+ } status9_st;
+ };
+ union {
+ u32 status10;
+ struct {
+ u32 mp4_code_size:20, foo:12;
+ } status10_st;
+ };
+ union {
+ u32 status11;
+ struct {
+ u32 last_queue:8, foo1:24;
+ } status11_st;
+ };
+};
+
+#define SOLO_VE_JPEG_QP_TBL 0x0670
+#define SOLO_VE_JPEG_QP_CH_L 0x0674
+#define SOLO_VE_JPEG_QP_CH_H 0x0678
+#define SOLO_VE_JPEG_CFG 0x067C
+#define SOLO_VE_JPEG_CTRL 0x0680
+
+#define SOLO_VE_OSD_CH 0x0690
+#define SOLO_VE_OSD_BASE 0x0694
+#define SOLO_VE_OSD_CLR 0x0698
+#define SOLO_VE_OSD_OPT 0x069C
+
+#define SOLO_VE_CH_INTL(ch) (0x0700+((ch)*4))
+#define SOLO_VE_CH_MOT(ch) (0x0740+((ch)*4))
+#define SOLO_VE_CH_QP(ch) (0x0780+((ch)*4))
+#define SOLO_VE_CH_QP_E(ch) (0x07C0+((ch)*4))
+#define SOLO_VE_CH_GOP(ch) (0x0800+((ch)*4))
+#define SOLO_VE_CH_GOP_E(ch) (0x0840+((ch)*4))
+#define SOLO_VE_CH_REF_BASE(ch) (0x0880+((ch)*4))
+#define SOLO_VE_CH_REF_BASE_E(ch) (0x08C0+((ch)*4))
+
+#define SOLO_VE_MPEG4_QUE(n) (0x0A00+((n)*8))
+#define SOLO_VE_JPEG_QUE(n) (0x0A04+((n)*8))
+
+#define SOLO_VD_CFG0 0x0900
+#define SOLO_VD_CFG_NO_WRITE_NO_WINDOW (1<<24)
+#define SOLO_VD_CFG_BUSY_WIAT_CODE (1<<23)
+#define SOLO_VD_CFG_BUSY_WIAT_REF (1<<22)
+#define SOLO_VD_CFG_BUSY_WIAT_RES (1<<21)
+#define SOLO_VD_CFG_BUSY_WIAT_MS (1<<20)
+#define SOLO_VD_CFG_SINGLE_MODE (1<<18)
+#define SOLO_VD_CFG_SCAL_MANUAL (1<<17)
+#define SOLO_VD_CFG_USER_PAGE_CTRL (1<<16)
+#define SOLO_VD_CFG_LITTLE_ENDIAN (1<<15)
+#define SOLO_VD_CFG_START_FI (1<<14)
+#define SOLO_VD_CFG_ERR_LOCK (1<<13)
+#define SOLO_VD_CFG_ERR_INT_ENA (1<<12)
+#define SOLO_VD_CFG_TIME_WIDTH(n) ((n)<<8)
+#define SOLO_VD_CFG_DCT_INTERVAL(n) ((n)<<0)
+
+#define SOLO_VD_CFG1 0x0904
+
+#define SOLO_VD_DEINTERLACE 0x0908
+#define SOLO_VD_DEINTERLACE_THRESHOLD(n) ((n)<<8)
+#define SOLO_VD_DEINTERLACE_EDGE_VALUE(n) ((n)<<0)
+
+#define SOLO_VD_CODE_ADR 0x090C
+
+#define SOLO_VD_CTRL 0x0910
+#define SOLO_VD_OPER_ON (1<<31)
+#define SOLO_VD_MAX_ITEM(n) ((n)<<0)
+
+#define SOLO_VD_STATUS0 0x0920
+#define SOLO_VD_STATUS0_INTR_ACK (1<<22)
+#define SOLO_VD_STATUS0_INTR_EMPTY (1<<21)
+#define SOLO_VD_STATUS0_INTR_ERR (1<<20)
+
+#define SOLO_VD_STATUS1 0x0924
+
+#define SOLO_VD_IDX0 0x0930
+#define SOLO_VD_IDX_INTERLACE (1<<30)
+#define SOLO_VD_IDX_CHANNEL(n) ((n)<<24)
+#define SOLO_VD_IDX_SIZE(n) ((n)<<0)
+
+#define SOLO_VD_IDX1 0x0934
+#define SOLO_VD_IDX_SRC_SCALE(n) ((n)<<28)
+#define SOLO_VD_IDX_WINDOW(n) ((n)<<24)
+#define SOLO_VD_IDX_DEINTERLACE (1<<16)
+#define SOLO_VD_IDX_H_BLOCK(n) ((n)<<8)
+#define SOLO_VD_IDX_V_BLOCK(n) ((n)<<0)
+
+#define SOLO_VD_IDX2 0x0938
+#define SOLO_VD_IDX_REF_BASE_SIDE (1<<31)
+#define SOLO_VD_IDX_REF_BASE(n) (((n)>>16)&0xffff)
+
+#define SOLO_VD_IDX3 0x093C
+#define SOLO_VD_IDX_DISP_SCALE(n) ((n)<<28)
+#define SOLO_VD_IDX_INTERLACE_WR (1<<27)
+#define SOLO_VD_IDX_INTERPOL (1<<26)
+#define SOLO_VD_IDX_HOR2X (1<<25)
+#define SOLO_VD_IDX_OFFSET_X(n) ((n)<<12)
+#define SOLO_VD_IDX_OFFSET_Y(n) ((n)<<0)
+
+#define SOLO_VD_IDX4 0x0940
+#define SOLO_VD_IDX_DEC_WR_PAGE(n) ((n)<<8)
+#define SOLO_VD_IDX_DISP_RD_PAGE(n) ((n)<<0)
+
+#define SOLO_VD_WR_PAGE(n) (0x03F0 + ((n) * 4))
+
+
+#define SOLO_GPIO_CONFIG_0 0x0B00
+#define SOLO_GPIO_CONFIG_1 0x0B04
+#define SOLO_GPIO_DATA_OUT 0x0B08
+#define SOLO_GPIO_DATA_IN 0x0B0C
+#define SOLO_GPIO_INT_ACK_STA 0x0B10
+#define SOLO_GPIO_INT_ENA 0x0B14
+#define SOLO_GPIO_INT_CFG_0 0x0B18
+#define SOLO_GPIO_INT_CFG_1 0x0B1C
+
+
+#define SOLO_IIC_CFG 0x0B20
+#define SOLO_IIC_ENABLE (1<<8)
+#define SOLO_IIC_PRESCALE(n) ((n)<<0)
+
+#define SOLO_IIC_CTRL 0x0B24
+#define SOLO_IIC_AUTO_CLEAR (1<<20)
+#define SOLO_IIC_STATE_RX_ACK (1<<19)
+#define SOLO_IIC_STATE_BUSY (1<<18)
+#define SOLO_IIC_STATE_SIG_ERR (1<<17)
+#define SOLO_IIC_STATE_TRNS (1<<16)
+#define SOLO_IIC_CH_SET(n) ((n)<<5)
+#define SOLO_IIC_ACK_EN (1<<4)
+#define SOLO_IIC_START (1<<3)
+#define SOLO_IIC_STOP (1<<2)
+#define SOLO_IIC_READ (1<<1)
+#define SOLO_IIC_WRITE (1<<0)
+
+#define SOLO_IIC_TXD 0x0B28
+#define SOLO_IIC_RXD 0x0B2C
+
+/*
+ * UART REGISTER
+ */
+#define SOLO_UART_CONTROL(n) (0x0BA0 + ((n)*0x20))
+#define SOLO_UART_CLK_DIV(n) ((n)<<24)
+#define SOLO_MODEM_CTRL_EN (1<<20)
+#define SOLO_PARITY_ERROR_DROP (1<<18)
+#define SOLO_IRQ_ERR_EN (1<<17)
+#define SOLO_IRQ_RX_EN (1<<16)
+#define SOLO_IRQ_TX_EN (1<<15)
+#define SOLO_RX_EN (1<<14)
+#define SOLO_TX_EN (1<<13)
+#define SOLO_UART_HALF_DUPLEX (1<<12)
+#define SOLO_UART_LOOPBACK (1<<11)
+
+#define SOLO_BAUDRATE_230400 ((0<<9)|(0<<6))
+#define SOLO_BAUDRATE_115200 ((0<<9)|(1<<6))
+#define SOLO_BAUDRATE_57600 ((0<<9)|(2<<6))
+#define SOLO_BAUDRATE_38400 ((0<<9)|(3<<6))
+#define SOLO_BAUDRATE_19200 ((0<<9)|(4<<6))
+#define SOLO_BAUDRATE_9600 ((0<<9)|(5<<6))
+#define SOLO_BAUDRATE_4800 ((0<<9)|(6<<6))
+#define SOLO_BAUDRATE_2400 ((1<<9)|(6<<6))
+#define SOLO_BAUDRATE_1200 ((2<<9)|(6<<6))
+#define SOLO_BAUDRATE_300 ((3<<9)|(6<<6))
+
+#define SOLO_UART_DATA_BIT_8 (3<<4)
+#define SOLO_UART_DATA_BIT_7 (2<<4)
+#define SOLO_UART_DATA_BIT_6 (1<<4)
+#define SOLO_UART_DATA_BIT_5 (0<<4)
+
+#define SOLO_UART_STOP_BIT_1 (0<<2)
+#define SOLO_UART_STOP_BIT_2 (1<<2)
+
+#define SOLO_UART_PARITY_NONE (0<<0)
+#define SOLO_UART_PARITY_EVEN (2<<0)
+#define SOLO_UART_PARITY_ODD (3<<0)
+
+#define SOLO_UART_STATUS(n) (0x0BA4 + ((n)*0x20))
+#define SOLO_UART_CTS (1<<15)
+#define SOLO_UART_RX_BUSY (1<<14)
+#define SOLO_UART_OVERRUN (1<<13)
+#define SOLO_UART_FRAME_ERR (1<<12)
+#define SOLO_UART_PARITY_ERR (1<<11)
+#define SOLO_UART_TX_BUSY (1<<5)
+
+#define SOLO_UART_RX_BUFF_CNT(stat) (((stat)>>6) & 0x1f)
+#define SOLO_UART_RX_BUFF_SIZE 8
+#define SOLO_UART_TX_BUFF_CNT(stat) (((stat)>>0) & 0x1f)
+#define SOLO_UART_TX_BUFF_SIZE 8
+
+#define SOLO_UART_TX_DATA(n) (0x0BA8 + ((n)*0x20))
+#define SOLO_UART_TX_DATA_PUSH (1<<8)
+#define SOLO_UART_RX_DATA(n) (0x0BAC + ((n)*0x20))
+#define SOLO_UART_RX_DATA_POP (1<<8)
+
+#define SOLO_TIMER_CLOCK_NUM 0x0be0
+#define SOLO_TIMER_WATCHDOG 0x0be4
+#define SOLO_TIMER_USEC 0x0be8
+#define SOLO_TIMER_SEC 0x0bec
+
+#define SOLO_AUDIO_CONTROL 0x0D00
+#define SOLO_AUDIO_ENABLE (1<<31)
+#define SOLO_AUDIO_MASTER_MODE (1<<30)
+#define SOLO_AUDIO_I2S_MODE (1<<29)
+#define SOLO_AUDIO_I2S_LR_SWAP (1<<27)
+#define SOLO_AUDIO_I2S_8BIT (1<<26)
+#define SOLO_AUDIO_I2S_MULTI(n) ((n)<<24)
+#define SOLO_AUDIO_MIX_9TO0 (1<<23)
+#define SOLO_AUDIO_DEC_9TO0_VOL(n) ((n)<<20)
+#define SOLO_AUDIO_MIX_19TO10 (1<<19)
+#define SOLO_AUDIO_DEC_19TO10_VOL(n) ((n)<<16)
+#define SOLO_AUDIO_MODE(n) ((n)<<0)
+#define SOLO_AUDIO_SAMPLE 0x0D04
+#define SOLO_AUDIO_EE_MODE_ON (1<<30)
+#define SOLO_AUDIO_EE_ENC_CH(ch) ((ch)<<25)
+#define SOLO_AUDIO_BITRATE(n) ((n)<<16)
+#define SOLO_AUDIO_CLK_DIV(n) ((n)<<0)
+#define SOLO_AUDIO_FDMA_INTR 0x0D08
+#define SOLO_AUDIO_FDMA_INTERVAL(n) ((n)<<19)
+#define SOLO_AUDIO_INTR_ORDER(n) ((n)<<16)
+#define SOLO_AUDIO_FDMA_BASE(n) ((n)<<0)
+#define SOLO_AUDIO_EVOL_0 0x0D0C
+#define SOLO_AUDIO_EVOL_1 0x0D10
+#define SOLO_AUDIO_EVOL(ch, value) ((value)<<((ch)%10))
+#define SOLO_AUDIO_STA 0x0D14
+
+
+#define SOLO_WATCHDOG 0x0BE4
+#define WATCHDOG_STAT(status) (status<<8)
+#define WATCHDOG_TIME(sec) (sec&0xff)
+
+#endif /* __SOLO6010_REGISTERS_H */
diff --git a/drivers/staging/solo6x10/solo6010-tw28.c b/drivers/staging/solo6x10/solo6010-tw28.c
new file mode 100644
index 00000000000..0159c839243
--- /dev/null
+++ b/drivers/staging/solo6x10/solo6010-tw28.c
@@ -0,0 +1,823 @@
+/*
+ * Copyright (C) 2010 Bluecherry, LLC www.bluecherrydvr.com
+ * Copyright (C) 2010 Ben Collins <bcollins@bluecherry.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.
+ *
+ * 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 "solo6010.h"
+#include "solo6010-tw28.h"
+
+/* XXX: Some of these values are masked into an 8-bit regs, and shifted
+ * around for other 8-bit regs. What are the magic bits in these values? */
+#define DEFAULT_HDELAY_NTSC (32 - 4)
+#define DEFAULT_HACTIVE_NTSC (720 + 16)
+#define DEFAULT_VDELAY_NTSC (7 - 2)
+#define DEFAULT_VACTIVE_NTSC (240 + 4)
+
+#define DEFAULT_HDELAY_PAL (32 + 4)
+#define DEFAULT_HACTIVE_PAL (864-DEFAULT_HDELAY_PAL)
+#define DEFAULT_VDELAY_PAL (6)
+#define DEFAULT_VACTIVE_PAL (312-DEFAULT_VDELAY_PAL)
+
+static u8 tbl_tw2864_template[] = {
+ 0x00, 0x00, 0x80, 0x10, 0x80, 0x80, 0x00, 0x02, // 0x00
+ 0x12, 0xf5, 0x09, 0xd0, 0x00, 0x00, 0x00, 0x7f,
+ 0x00, 0x00, 0x80, 0x10, 0x80, 0x80, 0x00, 0x02, // 0x10
+ 0x12, 0xf5, 0x09, 0xd0, 0x00, 0x00, 0x00, 0x7f,
+ 0x00, 0x00, 0x80, 0x10, 0x80, 0x80, 0x00, 0x02, // 0x20
+ 0x12, 0xf5, 0x09, 0xd0, 0x00, 0x00, 0x00, 0x7f,
+ 0x00, 0x00, 0x80, 0x10, 0x80, 0x80, 0x00, 0x02, // 0x30
+ 0x12, 0xf5, 0x09, 0xd0, 0x00, 0x00, 0x00, 0x7f,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x40
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x50
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x60
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x70
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA3, 0x00,
+ 0x00, 0x02, 0x00, 0xcc, 0x00, 0x80, 0x44, 0x50, // 0x80
+ 0x22, 0x01, 0xd8, 0xbc, 0xb8, 0x44, 0x38, 0x00,
+ 0x00, 0x78, 0x72, 0x3e, 0x14, 0xa5, 0xe4, 0x05, // 0x90
+ 0x00, 0x28, 0x44, 0x44, 0xa0, 0x88, 0x5a, 0x01,
+ 0x08, 0x08, 0x08, 0x08, 0x1a, 0x1a, 0x1a, 0x1a, // 0xa0
+ 0x00, 0x00, 0x00, 0xf0, 0xf0, 0xf0, 0xf0, 0x44,
+ 0x44, 0x0a, 0x00, 0xff, 0xef, 0xef, 0xef, 0xef, // 0xb0
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xc0
+ 0x00, 0x00, 0x55, 0x00, 0xb1, 0xe4, 0x40, 0x00,
+ 0x77, 0x77, 0x01, 0x13, 0x57, 0x9b, 0xdf, 0x20, // 0xd0
+ 0x64, 0xa8, 0xec, 0xd1, 0x0f, 0x11, 0x11, 0x81,
+ 0x10, 0xe0, 0xbb, 0xbb, 0x00, 0x11, 0x00, 0x00, // 0xe0
+ 0x11, 0x00, 0x00, 0x11, 0x00, 0x00, 0x11, 0x00,
+ 0x83, 0xb5, 0x09, 0x78, 0x85, 0x00, 0x01, 0x20, // 0xf0
+ 0x64, 0x11, 0x40, 0xaf, 0xff, 0x00, 0x00, 0x00,
+};
+
+static u8 tbl_tw2865_ntsc_template[] = {
+ 0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x02, // 0x00
+ 0x12, 0xff, 0x09, 0xd0, 0x00, 0x00, 0x00, 0x7f,
+ 0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x02, // 0x10
+ 0x12, 0xff, 0x09, 0xd0, 0x00, 0x00, 0x00, 0x7f,
+ 0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x02, // 0x20
+ 0x12, 0xff, 0x09, 0xd0, 0x00, 0x00, 0x00, 0x7f,
+ 0x00, 0xf0, 0x70, 0x48, 0x80, 0x80, 0x00, 0x02, // 0x30
+ 0x12, 0xff, 0x09, 0xd0, 0x00, 0x00, 0x00, 0x7f,
+ 0x00, 0x00, 0x90, 0x68, 0x00, 0x38, 0x80, 0x80, // 0x40
+ 0x80, 0x80, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x50
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x45, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x60
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x21, 0x43,
+ 0x08, 0x00, 0x00, 0x01, 0xf1, 0x03, 0xEF, 0x03, // 0x70
+ 0xE9, 0x03, 0xD9, 0x15, 0x15, 0xE4, 0xA3, 0x80,
+ 0x00, 0x02, 0x00, 0xCC, 0x00, 0x80, 0x44, 0x50, // 0x80
+ 0x22, 0x01, 0xD8, 0xBC, 0xB8, 0x44, 0x38, 0x00,
+ 0x00, 0x78, 0x44, 0x3D, 0x14, 0xA5, 0xE0, 0x05, // 0x90
+ 0x00, 0x28, 0x44, 0x44, 0xA0, 0x90, 0x52, 0x13,
+ 0x08, 0x08, 0x08, 0x08, 0x1A, 0x1A, 0x1B, 0x1A, // 0xa0
+ 0x00, 0x00, 0x00, 0xF0, 0xF0, 0xF0, 0xF0, 0x44,
+ 0x44, 0x4A, 0x00, 0xFF, 0xEF, 0xEF, 0xEF, 0xEF, // 0xb0
+ 0xFF, 0xE7, 0xE9, 0xE9, 0xEB, 0xFF, 0xD6, 0xD8,
+ 0xD8, 0xD7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xc0
+ 0x00, 0x00, 0x55, 0x00, 0xE4, 0x39, 0x00, 0x80,
+ 0x77, 0x77, 0x03, 0x20, 0x57, 0x9b, 0xdf, 0x31, // 0xd0
+ 0x64, 0xa8, 0xec, 0xd1, 0x0f, 0x11, 0x11, 0x81,
+ 0x10, 0xC0, 0xAA, 0xAA, 0x00, 0x11, 0x00, 0x00, // 0xe0
+ 0x11, 0x00, 0x00, 0x11, 0x00, 0x00, 0x11, 0x00,
+ 0x83, 0xB5, 0x09, 0x78, 0x85, 0x00, 0x01, 0x20, // 0xf0
+ 0x64, 0x51, 0x40, 0xaf, 0xFF, 0xF0, 0x00, 0xC0,
+};
+
+static u8 tbl_tw2865_pal_template[] = {
+ 0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x12, // 0x00
+ 0x11, 0xff, 0x01, 0xc3, 0x00, 0x00, 0x01, 0x7f,
+ 0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x12, // 0x10
+ 0x11, 0xff, 0x01, 0xc3, 0x00, 0x00, 0x01, 0x7f,
+ 0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x12, // 0x20
+ 0x11, 0xff, 0x01, 0xc3, 0x00, 0x00, 0x01, 0x7f,
+ 0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x12, // 0x30
+ 0x11, 0xff, 0x01, 0xc3, 0x00, 0x00, 0x01, 0x7f,
+ 0x00, 0x94, 0x90, 0x48, 0x00, 0x38, 0x7F, 0x80, // 0x40
+ 0x80, 0x80, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x50
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x45, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x60
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x21, 0x43,
+ 0x08, 0x00, 0x00, 0x01, 0xf1, 0x03, 0xEF, 0x03, // 0x70
+ 0xEA, 0x03, 0xD9, 0x15, 0x15, 0xE4, 0xA3, 0x80,
+ 0x00, 0x02, 0x00, 0xCC, 0x00, 0x80, 0x44, 0x50, // 0x80
+ 0x22, 0x01, 0xD8, 0xBC, 0xB8, 0x44, 0x38, 0x00,
+ 0x00, 0x78, 0x44, 0x3D, 0x14, 0xA5, 0xE0, 0x05, // 0x90
+ 0x00, 0x28, 0x44, 0x44, 0xA0, 0x90, 0x52, 0x13,
+ 0x08, 0x08, 0x08, 0x08, 0x1A, 0x1A, 0x1A, 0x1A, // 0xa0
+ 0x00, 0x00, 0x00, 0xF0, 0xF0, 0xF0, 0xF0, 0x44,
+ 0x44, 0x4A, 0x00, 0xFF, 0xEF, 0xEF, 0xEF, 0xEF, // 0xb0
+ 0xFF, 0xE7, 0xE9, 0xE9, 0xE9, 0xFF, 0xD7, 0xD8,
+ 0xD9, 0xD8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xc0
+ 0x00, 0x00, 0x55, 0x00, 0xE4, 0x39, 0x00, 0x80,
+ 0x77, 0x77, 0x03, 0x20, 0x57, 0x9b, 0xdf, 0x31, // 0xd0
+ 0x64, 0xa8, 0xec, 0xd1, 0x0f, 0x11, 0x11, 0x81,
+ 0x10, 0xC0, 0xAA, 0xAA, 0x00, 0x11, 0x00, 0x00, // 0xe0
+ 0x11, 0x00, 0x00, 0x11, 0x00, 0x00, 0x11, 0x00,
+ 0x83, 0xB5, 0x09, 0x00, 0xA0, 0x00, 0x01, 0x20, // 0xf0
+ 0x64, 0x51, 0x40, 0xaf, 0xFF, 0xF0, 0x00, 0xC0,
+};
+
+#define is_tw286x(__solo, __id) (!(__solo->tw2815 & (1 << __id)))
+
+static u8 tw_readbyte(struct solo6010_dev *solo_dev, int chip_id, u8 tw6x_off,
+ u8 tw_off)
+{
+ if (is_tw286x(solo_dev, chip_id))
+ return solo_i2c_readbyte(solo_dev, SOLO_I2C_TW,
+ TW_CHIP_OFFSET_ADDR(chip_id),
+ tw6x_off);
+ else
+ return solo_i2c_readbyte(solo_dev, SOLO_I2C_TW,
+ TW_CHIP_OFFSET_ADDR(chip_id),
+ tw_off);
+}
+
+static void tw_writebyte(struct solo6010_dev *solo_dev, int chip_id,
+ u8 tw6x_off, u8 tw_off, u8 val)
+{
+ if (is_tw286x(solo_dev, chip_id))
+ solo_i2c_writebyte(solo_dev, SOLO_I2C_TW,
+ TW_CHIP_OFFSET_ADDR(chip_id),
+ tw6x_off, val);
+ else
+ solo_i2c_writebyte(solo_dev, SOLO_I2C_TW,
+ TW_CHIP_OFFSET_ADDR(chip_id),
+ tw_off, val);
+}
+
+static void tw_write_and_verify(struct solo6010_dev *solo_dev, u8 addr, u8 off,
+ u8 val)
+{
+ int i;
+
+ for (i = 0; i < 5; i++) {
+ u8 rval = solo_i2c_readbyte(solo_dev, SOLO_I2C_TW, addr, off);
+ if (rval == val)
+ return;
+
+ solo_i2c_writebyte(solo_dev, SOLO_I2C_TW, addr, off, val);
+ msleep_interruptible(1);
+ }
+
+// printk("solo6010/tw28: Error writing register: %02x->%02x [%02x]\n",
+// addr, off, val);
+}
+
+static int tw2865_setup(struct solo6010_dev *solo_dev, u8 dev_addr)
+{
+ u8 tbl_tw2865_common[256];
+ int i;
+
+ if (solo_dev->video_type == SOLO_VO_FMT_TYPE_PAL)
+ memcpy(tbl_tw2865_common, tbl_tw2865_pal_template,
+ sizeof(tbl_tw2865_common));
+ else
+ memcpy(tbl_tw2865_common, tbl_tw2865_ntsc_template,
+ sizeof(tbl_tw2865_common));
+
+ /* ALINK Mode */
+ if (solo_dev->nr_chans == 4) {
+ tbl_tw2865_common[0xd2] = 0x01;
+ tbl_tw2865_common[0xcf] = 0x00;
+ } else if (solo_dev->nr_chans == 8) {
+ tbl_tw2865_common[0xd2] = 0x02;
+ if (dev_addr == TW_CHIP_OFFSET_ADDR(1))
+ tbl_tw2865_common[0xcf] = 0x80;
+ } else if (solo_dev->nr_chans == 16) {
+ tbl_tw2865_common[0xd2] = 0x03;
+ if (dev_addr == TW_CHIP_OFFSET_ADDR(1))
+ tbl_tw2865_common[0xcf] = 0x83;
+ else if (dev_addr == TW_CHIP_OFFSET_ADDR(2))
+ tbl_tw2865_common[0xcf] = 0x83;
+ else if (dev_addr == TW_CHIP_OFFSET_ADDR(3))
+ tbl_tw2865_common[0xcf] = 0x80;
+ }
+
+ for (i = 0; i < 0xff; i++) {
+ /* Skip read only registers */
+ if (i >= 0xb8 && i <= 0xc1 )
+ continue;
+ if ((i & ~0x30) == 0x00 ||
+ (i & ~0x30) == 0x0c ||
+ (i & ~0x30) == 0x0d)
+ continue;
+ if (i >= 0xc4 && i <= 0xc7)
+ continue;
+ if (i == 0xfd)
+ continue;
+
+ tw_write_and_verify(solo_dev, dev_addr, i,
+ tbl_tw2865_common[i]);
+ }
+
+ return 0;
+}
+
+static int tw2864_setup(struct solo6010_dev *solo_dev, u8 dev_addr)
+{
+ u8 tbl_tw2864_common[sizeof(tbl_tw2864_template)];
+ int i;
+
+ memcpy(tbl_tw2864_common, tbl_tw2864_template,
+ sizeof(tbl_tw2864_common));
+
+ if (solo_dev->tw2865 == 0) {
+ /* IRQ Mode */
+ if (solo_dev->nr_chans == 4) {
+ tbl_tw2864_common[0xd2] = 0x01;
+ tbl_tw2864_common[0xcf] = 0x00;
+ } else if (solo_dev->nr_chans == 8) {
+ tbl_tw2864_common[0xd2] = 0x02;
+ if (dev_addr == TW_CHIP_OFFSET_ADDR(0))
+ tbl_tw2864_common[0xcf] = 0x43;
+ else if (dev_addr == TW_CHIP_OFFSET_ADDR(1))
+ tbl_tw2864_common[0xcf] = 0x40;
+ } else if (solo_dev->nr_chans == 16) {
+ tbl_tw2864_common[0xd2] = 0x03;
+ if (dev_addr == TW_CHIP_OFFSET_ADDR(0))
+ tbl_tw2864_common[0xcf] = 0x43;
+ else if (dev_addr == TW_CHIP_OFFSET_ADDR(1))
+ tbl_tw2864_common[0xcf] = 0x43;
+ else if (dev_addr == TW_CHIP_OFFSET_ADDR(2))
+ tbl_tw2864_common[0xcf] = 0x43;
+ else if (dev_addr == TW_CHIP_OFFSET_ADDR(3))
+ tbl_tw2864_common[0xcf] = 0x40;
+ }
+ } else {
+ /* ALINK Mode. Assumes that the first tw28xx is a
+ * 2865 and these are in cascade. */
+ for (i = 0; i <= 4; i++)
+ tbl_tw2864_common[0x08 | i << 4] = 0x12;
+
+ if (solo_dev->nr_chans == 8) {
+ tbl_tw2864_common[0xd2] = 0x02;
+ if (dev_addr == TW_CHIP_OFFSET_ADDR(1))
+ tbl_tw2864_common[0xcf] = 0x80;
+ } else if (solo_dev->nr_chans == 16) {
+ tbl_tw2864_common[0xd2] = 0x03;
+ if (dev_addr == TW_CHIP_OFFSET_ADDR(1))
+ tbl_tw2864_common[0xcf] = 0x83;
+ else if (dev_addr == TW_CHIP_OFFSET_ADDR(2))
+ tbl_tw2864_common[0xcf] = 0x83;
+ else if (dev_addr == TW_CHIP_OFFSET_ADDR(3))
+ tbl_tw2864_common[0xcf] = 0x80;
+ }
+ }
+
+ /* NTSC or PAL */
+ if (solo_dev->video_type == SOLO_VO_FMT_TYPE_PAL) {
+ for (i = 0; i < 4; i++) {
+ tbl_tw2864_common[0x07 | (i << 4)] |= 0x10;
+ tbl_tw2864_common[0x08 | (i << 4)] |= 0x06;
+ tbl_tw2864_common[0x0a | (i << 4)] |= 0x08;
+ tbl_tw2864_common[0x0b | (i << 4)] |= 0x13;
+ tbl_tw2864_common[0x0e | (i << 4)] |= 0x01;
+ }
+ tbl_tw2864_common[0x9d] = 0x90;
+ tbl_tw2864_common[0xf3] = 0x00;
+ tbl_tw2864_common[0xf4] = 0xa0;
+ }
+
+ for (i = 0; i < 0xff; i++) {
+ /* Skip read only registers */
+ if (i >= 0xb8 && i <= 0xc1 )
+ continue;
+ if ((i & ~0x30) == 0x00 ||
+ (i & ~0x30) == 0x0c ||
+ (i & ~0x30) == 0x0d)
+ continue;
+ if (i == 0x74 || i == 0x77 || i == 0x78 ||
+ i == 0x79 || i == 0x7a)
+ continue;
+ if (i == 0xfd)
+ continue;
+
+ tw_write_and_verify(solo_dev, dev_addr, i,
+ tbl_tw2864_common[i]);
+ }
+
+ return 0;
+}
+
+static int tw2815_setup(struct solo6010_dev *solo_dev, u8 dev_addr)
+{
+ u8 tbl_ntsc_tw2815_common[] = {
+ 0x00, 0xc8, 0x20, 0xd0, 0x06, 0xf0, 0x08, 0x80,
+ 0x80, 0x80, 0x80, 0x02, 0x06, 0x00, 0x11,
+ };
+
+ u8 tbl_pal_tw2815_common[] = {
+ 0x00, 0x88, 0x20, 0xd0, 0x05, 0x20, 0x28, 0x80,
+ 0x80, 0x80, 0x80, 0x82, 0x06, 0x00, 0x11,
+ };
+
+ u8 tbl_tw2815_sfr[] = {
+ 0x00, 0x00, 0x00, 0xc0, 0x45, 0xa0, 0xd0, 0x2f, // 0x00
+ 0x64, 0x80, 0x80, 0x82, 0x82, 0x00, 0x00, 0x00,
+ 0x00, 0x0f, 0x05, 0x00, 0x00, 0x80, 0x06, 0x00, // 0x10
+ 0x00, 0x00, 0x00, 0xff, 0x8f, 0x00, 0x00, 0x00,
+ 0x88, 0x88, 0xc0, 0x00, 0x20, 0x64, 0xa8, 0xec, // 0x20
+ 0x31, 0x75, 0xb9, 0xfd, 0x00, 0x00, 0x88, 0x88,
+ 0x88, 0x11, 0x00, 0x88, 0x88, 0x00, // 0x30
+ };
+ u8 *tbl_tw2815_common;
+ int i;
+ int ch;
+
+ tbl_ntsc_tw2815_common[0x06] = 0;
+
+ /* Horizontal Delay Control */
+ tbl_ntsc_tw2815_common[0x02] = DEFAULT_HDELAY_NTSC & 0xff;
+ tbl_ntsc_tw2815_common[0x06] |= 0x03 & (DEFAULT_HDELAY_NTSC >> 8);
+
+ /* Horizontal Active Control */
+ tbl_ntsc_tw2815_common[0x03] = DEFAULT_HACTIVE_NTSC & 0xff;
+ tbl_ntsc_tw2815_common[0x06] |=
+ ((0x03 & (DEFAULT_HACTIVE_NTSC >> 8)) << 2);
+
+ /* Vertical Delay Control */
+ tbl_ntsc_tw2815_common[0x04] = DEFAULT_VDELAY_NTSC & 0xff;
+ tbl_ntsc_tw2815_common[0x06] |=
+ ((0x01 & (DEFAULT_VDELAY_NTSC >> 8)) << 4);
+
+ /* Vertical Active Control */
+ tbl_ntsc_tw2815_common[0x05] = DEFAULT_VACTIVE_NTSC & 0xff;
+ tbl_ntsc_tw2815_common[0x06] |=
+ ((0x01 & (DEFAULT_VACTIVE_NTSC >> 8)) << 5);
+
+ tbl_pal_tw2815_common[0x06] = 0;
+
+ /* Horizontal Delay Control */
+ tbl_pal_tw2815_common[0x02] = DEFAULT_HDELAY_PAL & 0xff;
+ tbl_pal_tw2815_common[0x06] |= 0x03 & (DEFAULT_HDELAY_PAL >> 8);
+
+ /* Horizontal Active Control */
+ tbl_pal_tw2815_common[0x03] = DEFAULT_HACTIVE_PAL & 0xff;
+ tbl_pal_tw2815_common[0x06] |=
+ ((0x03 & (DEFAULT_HACTIVE_PAL >> 8)) << 2);
+
+ /* Vertical Delay Control */
+ tbl_pal_tw2815_common[0x04] = DEFAULT_VDELAY_PAL & 0xff;
+ tbl_pal_tw2815_common[0x06] |=
+ ((0x01 & (DEFAULT_VDELAY_PAL >> 8)) << 4);
+
+ /* Vertical Active Control */
+ tbl_pal_tw2815_common[0x05] = DEFAULT_VACTIVE_PAL & 0xff;
+ tbl_pal_tw2815_common[0x06] |=
+ ((0x01 & (DEFAULT_VACTIVE_PAL >> 8)) << 5);
+
+ tbl_tw2815_common =
+ (solo_dev->video_type == SOLO_VO_FMT_TYPE_NTSC) ?
+ tbl_ntsc_tw2815_common : tbl_pal_tw2815_common;
+
+ /* Dual ITU-R BT.656 format */
+ tbl_tw2815_common[0x0d] |= 0x04;
+
+ /* Audio configuration */
+ tbl_tw2815_sfr[0x62 - 0x40] &= ~(3 << 6);
+
+ if (solo_dev->nr_chans == 4) {
+ tbl_tw2815_sfr[0x63 - 0x40] |= 1;
+ tbl_tw2815_sfr[0x62 - 0x40] |= 3 << 6;
+ } else if (solo_dev->nr_chans == 8) {
+ tbl_tw2815_sfr[0x63 - 0x40] |= 2;
+ if (dev_addr == TW_CHIP_OFFSET_ADDR(0))
+ tbl_tw2815_sfr[0x62 - 0x40] |= 1 << 6;
+ else if (dev_addr == TW_CHIP_OFFSET_ADDR(1))
+ tbl_tw2815_sfr[0x62 - 0x40] |= 2 << 6;
+ } else if (solo_dev->nr_chans == 16) {
+ tbl_tw2815_sfr[0x63 - 0x40] |= 3;
+ if (dev_addr == TW_CHIP_OFFSET_ADDR(0))
+ tbl_tw2815_sfr[0x62 - 0x40] |= 1 << 6;
+ else if (dev_addr == TW_CHIP_OFFSET_ADDR(1))
+ tbl_tw2815_sfr[0x62 - 0x40] |= 0 << 6;
+ else if (dev_addr == TW_CHIP_OFFSET_ADDR(2))
+ tbl_tw2815_sfr[0x62 - 0x40] |= 0 << 6;
+ else if (dev_addr == TW_CHIP_OFFSET_ADDR(3))
+ tbl_tw2815_sfr[0x62 - 0x40] |= 2 << 6;
+ }
+
+ /* Output mode of R_ADATM pin (0 mixing, 1 record) */
+ /* tbl_tw2815_sfr[0x63 - 0x40] |= 0 << 2; */
+
+ /* 8KHz, used to be 16KHz, but changed for remote client compat */
+ tbl_tw2815_sfr[0x62 - 0x40] |= 0 << 2;
+ tbl_tw2815_sfr[0x6c - 0x40] |= 0 << 2;
+
+ /* Playback of right channel */
+ tbl_tw2815_sfr[0x6c - 0x40] |= 1 << 5;
+
+ /* Reserved value (XXX ??) */
+ tbl_tw2815_sfr[0x5c - 0x40] |= 1 << 5;
+
+ /* Analog output gain and mix ratio playback on full */
+ tbl_tw2815_sfr[0x70 - 0x40] |= 0xff;
+ /* Select playback audio and mute all except */
+ tbl_tw2815_sfr[0x71 - 0x40] |= 0x10;
+ tbl_tw2815_sfr[0x6d - 0x40] |= 0x0f;
+
+ /* End of audio configuration */
+
+ for (ch = 0; ch < 4; ch++) {
+ tbl_tw2815_common[0x0d] &= ~3;
+ switch (ch) {
+ case 0:
+ tbl_tw2815_common[0x0d] |= 0x21;
+ break;
+ case 1:
+ tbl_tw2815_common[0x0d] |= 0x20;
+ break;
+ case 2:
+ tbl_tw2815_common[0x0d] |= 0x23;
+ break;
+ case 3:
+ tbl_tw2815_common[0x0d] |= 0x22;
+ break;
+ }
+
+ for (i = 0; i < 0x0f; i++) {
+ if (i == 0x00)
+ continue; // read-only
+ solo_i2c_writebyte(solo_dev, SOLO_I2C_TW,
+ dev_addr, (ch * 0x10) + i,
+ tbl_tw2815_common[i]);
+ }
+ }
+
+ for (i = 0x40; i < 0x76; i++) {
+ /* Skip read-only and nop registers */
+ if (i == 0x40 || i == 0x59 || i == 0x5a ||
+ i == 0x5d || i == 0x5e || i == 0x5f)
+ continue;
+
+ solo_i2c_writebyte(solo_dev, SOLO_I2C_TW, dev_addr, i,
+ tbl_tw2815_sfr[i - 0x40]);
+ }
+
+ return 0;
+}
+
+#define FIRST_ACTIVE_LINE 0x0008
+#define LAST_ACTIVE_LINE 0x0102
+
+static void saa7128_setup(struct solo6010_dev *solo_dev)
+{
+ int i;
+ unsigned char regs[128] = {
+ 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x1C, 0x2B, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00,
+ 0x59, 0x1d, 0x75, 0x3f, 0x06, 0x3f, 0x00, 0x00,
+ 0x1c, 0x33, 0x00, 0x3f, 0x00, 0x00, 0x3f, 0x00,
+ 0x1a, 0x1a, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x68, 0x10, 0x97, 0x4c, 0x18,
+ 0x9b, 0x93, 0x9f, 0xff, 0x7c, 0x34, 0x3f, 0x3f,
+ 0x3f, 0x83, 0x83, 0x80, 0x0d, 0x0f, 0xc3, 0x06,
+ 0x02, 0x80, 0x71, 0x77, 0xa7, 0x67, 0x66, 0x2e,
+ 0x7b, 0x11, 0x4f, 0x1f, 0x7c, 0xf0, 0x21, 0x77,
+ 0x41, 0x88, 0x41, 0x12, 0xed, 0x10, 0x10, 0x00,
+ 0x41, 0xc3, 0x00, 0x3e, 0xb8, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x08, 0xff, 0x80, 0x00, 0xff, 0xff,
+ };
+
+ regs[0x7A] = FIRST_ACTIVE_LINE & 0xff;
+ regs[0x7B] = LAST_ACTIVE_LINE & 0xff;
+ regs[0x7C] = ((1 << 7) |
+ (((LAST_ACTIVE_LINE >> 8) & 1) << 6) |
+ (((FIRST_ACTIVE_LINE >> 8) & 1) << 4));
+
+ /* PAL: XXX: We could do a second set of regs to avoid this */
+ if (solo_dev->video_type != SOLO_VO_FMT_TYPE_NTSC) {
+ regs[0x28] = 0xE1;
+
+ regs[0x5A] = 0x0F;
+ regs[0x61] = 0x02;
+ regs[0x62] = 0x35;
+ regs[0x63] = 0xCB;
+ regs[0x64] = 0x8A;
+ regs[0x65] = 0x09;
+ regs[0x66] = 0x2A;
+
+ regs[0x6C] = 0xf1;
+ regs[0x6E] = 0x20;
+
+ regs[0x7A] = 0x06 + 12;
+ regs[0x7b] = 0x24 + 12;
+ regs[0x7c] |= 1 << 6;
+ }
+
+ /* First 0x25 bytes are read-only? */
+ for (i = 0x26; i < 128; i++) {
+ if (i == 0x60 || i == 0x7D)
+ continue;
+ solo_i2c_writebyte(solo_dev, SOLO_I2C_SAA, 0x46, i, regs[i]);
+ }
+
+ return;
+}
+
+int solo_tw28_init(struct solo6010_dev *solo_dev)
+{
+ int i;
+ u8 value;
+
+ /* Detect techwell chip type */
+ for (i = 0; i < TW_NUM_CHIP; i++) {
+ value = solo_i2c_readbyte(solo_dev, SOLO_I2C_TW,
+ TW_CHIP_OFFSET_ADDR(i), 0xFF);
+
+ switch (value >> 3) {
+ case 0x18:
+ solo_dev->tw2865 |= 1 << i;
+ solo_dev->tw28_cnt++;
+ break;
+ case 0x0c:
+ solo_dev->tw2864 |= 1 << i;
+ solo_dev->tw28_cnt++;
+ break;
+ default:
+ value = solo_i2c_readbyte(solo_dev, SOLO_I2C_TW,
+ TW_CHIP_OFFSET_ADDR(i), 0x59);
+ if ((value >> 3) == 0x04) {
+ solo_dev->tw2815 |= 1 << i;
+ solo_dev->tw28_cnt++;
+ }
+ }
+ }
+
+ if (!solo_dev->tw28_cnt)
+ return -EINVAL;
+
+ saa7128_setup(solo_dev);
+
+ for (i = 0; i < solo_dev->tw28_cnt; i++) {
+ if ((solo_dev->tw2865 & (1 << i)))
+ tw2865_setup(solo_dev, TW_CHIP_OFFSET_ADDR(i));
+ else if ((solo_dev->tw2864 & (1 << i)))
+ tw2864_setup(solo_dev, TW_CHIP_OFFSET_ADDR(i));
+ else
+ tw2815_setup(solo_dev, TW_CHIP_OFFSET_ADDR(i));
+ }
+
+ dev_info(&solo_dev->pdev->dev, "Initialized %d tw28xx chip%s:",
+ solo_dev->tw28_cnt, solo_dev->tw28_cnt == 1 ? "" : "s");
+
+ if (solo_dev->tw2865)
+ printk(" tw2865[%d]", hweight32(solo_dev->tw2865));
+ if (solo_dev->tw2864)
+ printk(" tw2864[%d]", hweight32(solo_dev->tw2864));
+ if (solo_dev->tw2815)
+ printk(" tw2815[%d]", hweight32(solo_dev->tw2815));
+ printk("\n");
+
+ return 0;
+}
+
+/*
+ * We accessed the video status signal in the Techwell chip through
+ * iic/i2c because the video status reported by register REG_VI_STATUS1
+ * (address 0x012C) of the SOLO6010 chip doesn't give the correct video
+ * status signal values.
+ */
+int tw28_get_video_status(struct solo6010_dev *solo_dev, u8 ch)
+{
+ u8 val, chip_num;
+
+ /* Get the right chip and on-chip channel */
+ chip_num = ch / 4;
+ ch %= 4;
+
+ val = tw_readbyte(solo_dev, chip_num, TW286X_AV_STAT_ADDR,
+ TW_AV_STAT_ADDR) & 0x0f;
+
+ return val & (1 << ch) ? 1 : 0;
+}
+
+#if 0
+/* Status of audio from up to 4 techwell chips are combined into 1 variable.
+ * See techwell datasheet for details. */
+u16 tw28_get_audio_status(struct solo6010_dev *solo_dev)
+{
+ u8 val;
+ u16 status = 0;
+ int i;
+
+ for (i = 0; i < solo_dev->tw28_cnt; i++) {
+ val = (tw_readbyte(solo_dev, i, TW286X_AV_STAT_ADDR,
+ TW_AV_STAT_ADDR) & 0xf0) >> 4;
+ status |= val << (i * 4);
+ }
+
+ return status;
+}
+#endif
+
+int tw28_set_ctrl_val(struct solo6010_dev *solo_dev, u32 ctrl, u8 ch,
+ s32 val)
+{
+ char sval;
+ u8 chip_num;
+
+ /* Get the right chip and on-chip channel */
+ chip_num = ch / 4;
+ ch %= 4;
+
+ if (val > 255 || val < 0)
+ return -ERANGE;
+
+ switch (ctrl) {
+ case V4L2_CID_SHARPNESS:
+ /* Only 286x has sharpness */
+ if (val > 0x0f || val < 0)
+ return -ERANGE;
+ if (is_tw286x(solo_dev, chip_num)) {
+ u8 v = solo_i2c_readbyte(solo_dev, SOLO_I2C_TW,
+ TW_CHIP_OFFSET_ADDR(chip_num),
+ TW286x_SHARPNESS(chip_num));
+ v &= 0xf0;
+ v |= val;
+ solo_i2c_writebyte(solo_dev, SOLO_I2C_TW,
+ TW_CHIP_OFFSET_ADDR(chip_num),
+ TW286x_SHARPNESS(chip_num), v);
+ } else if (val != 0)
+ return -ERANGE;
+ break;
+
+ case V4L2_CID_HUE:
+ if (is_tw286x(solo_dev, chip_num))
+ sval = val - 128;
+ else
+ sval = (char)val;
+ tw_writebyte(solo_dev, chip_num, TW286x_HUE_ADDR(ch),
+ TW_HUE_ADDR(ch), sval);
+
+ break;
+
+ case V4L2_CID_SATURATION:
+ if (is_tw286x(solo_dev, chip_num)) {
+ solo_i2c_writebyte(solo_dev, SOLO_I2C_TW,
+ TW_CHIP_OFFSET_ADDR(chip_num),
+ TW286x_SATURATIONU_ADDR(ch), val);
+ }
+ tw_writebyte(solo_dev, chip_num, TW286x_SATURATIONV_ADDR(ch),
+ TW_SATURATION_ADDR(ch), val);
+
+ break;
+
+ case V4L2_CID_CONTRAST:
+ tw_writebyte(solo_dev, chip_num, TW286x_CONTRAST_ADDR(ch),
+ TW_CONTRAST_ADDR(ch), val);
+ break;
+
+ case V4L2_CID_BRIGHTNESS:
+ if (is_tw286x(solo_dev, chip_num))
+ sval = val - 128;
+ else
+ sval = (char)val;
+ tw_writebyte(solo_dev, chip_num, TW286x_BRIGHTNESS_ADDR(ch),
+ TW_BRIGHTNESS_ADDR(ch), sval);
+
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+int tw28_get_ctrl_val(struct solo6010_dev *solo_dev, u32 ctrl, u8 ch,
+ s32 *val)
+{
+ u8 rval, chip_num;
+
+ /* Get the right chip and on-chip channel */
+ chip_num = ch / 4;
+ ch %= 4;
+
+ switch (ctrl) {
+ case V4L2_CID_SHARPNESS:
+ /* Only 286x has sharpness */
+ if (is_tw286x(solo_dev, chip_num)) {
+ rval = solo_i2c_readbyte(solo_dev, SOLO_I2C_TW,
+ TW_CHIP_OFFSET_ADDR(chip_num),
+ TW286x_SHARPNESS(chip_num));
+ *val = rval & 0x0f;
+ } else
+ *val = 0;
+ break;
+ case V4L2_CID_HUE:
+ rval = tw_readbyte(solo_dev, chip_num, TW286x_HUE_ADDR(ch),
+ TW_HUE_ADDR(ch));
+ if (is_tw286x(solo_dev, chip_num))
+ *val = (s32)((char)rval) + 128;
+ else
+ *val = rval;
+ break;
+ case V4L2_CID_SATURATION:
+ *val = tw_readbyte(solo_dev, chip_num,
+ TW286x_SATURATIONU_ADDR(ch),
+ TW_SATURATION_ADDR(ch));
+ break;
+ case V4L2_CID_CONTRAST:
+ *val = tw_readbyte(solo_dev, chip_num,
+ TW286x_CONTRAST_ADDR(ch),
+ TW_CONTRAST_ADDR(ch));
+ break;
+ case V4L2_CID_BRIGHTNESS:
+ rval = tw_readbyte(solo_dev, chip_num,
+ TW286x_BRIGHTNESS_ADDR(ch),
+ TW_BRIGHTNESS_ADDR(ch));
+ if (is_tw286x(solo_dev, chip_num))
+ *val = (s32)((char)rval) + 128;
+ else
+ *val = rval;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+#if 0
+/*
+ * For audio output volume, the output channel is only 1. In this case we
+ * don't need to offset TW_CHIP_OFFSET_ADDR. The TW_CHIP_OFFSET_ADDR used
+ * is the base address of the techwell chip.
+ */
+void tw2815_Set_AudioOutVol(struct solo6010_dev *solo_dev, unsigned int u_val)
+{
+ unsigned int val;
+ unsigned int chip_num;
+
+ chip_num = (solo_dev->nr_chans - 1) / 4;
+
+ val = tw_readbyte(solo_dev, chip_num, TW286x_AUDIO_OUTPUT_VOL_ADDR,
+ TW_AUDIO_OUTPUT_VOL_ADDR);
+
+ u_val = (val & 0x0f) | (u_val << 4);
+
+ tw_writebyte(solo_dev, chip_num, TW286x_AUDIO_OUTPUT_VOL_ADDR,
+ TW_AUDIO_OUTPUT_VOL_ADDR, u_val);
+}
+#endif
+
+u8 tw28_get_audio_gain(struct solo6010_dev *solo_dev, u8 ch)
+{
+ u8 val;
+ u8 chip_num;
+
+ /* Get the right chip and on-chip channel */
+ chip_num = ch / 4;
+ ch %= 4;
+
+ val = tw_readbyte(solo_dev, chip_num,
+ TW286x_AUDIO_INPUT_GAIN_ADDR(ch),
+ TW_AUDIO_INPUT_GAIN_ADDR(ch));
+
+ return (ch % 2) ? (val >> 4) : (val & 0x0f);
+}
+
+void tw28_set_audio_gain(struct solo6010_dev *solo_dev, u8 ch, u8 val)
+{
+ u8 old_val;
+ u8 chip_num;
+
+ /* Get the right chip and on-chip channel */
+ chip_num = ch / 4;
+ ch %= 4;
+
+ old_val = tw_readbyte(solo_dev, chip_num,
+ TW286x_AUDIO_INPUT_GAIN_ADDR(ch),
+ TW_AUDIO_INPUT_GAIN_ADDR(ch));
+
+ val = (old_val & ((ch % 2) ? 0x0f : 0xf0)) |
+ ((ch % 2) ? (val << 4) : val);
+
+ tw_writebyte(solo_dev, chip_num, TW286x_AUDIO_INPUT_GAIN_ADDR(ch),
+ TW_AUDIO_INPUT_GAIN_ADDR(ch), val);
+}
diff --git a/drivers/staging/solo6x10/solo6010-tw28.h b/drivers/staging/solo6x10/solo6010-tw28.h
new file mode 100644
index 00000000000..a7eecfa1a81
--- /dev/null
+++ b/drivers/staging/solo6x10/solo6010-tw28.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2010 Bluecherry, LLC www.bluecherrydvr.com
+ * Copyright (C) 2010 Ben Collins <bcollins@bluecherry.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.
+ *
+ * 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 __SOLO6010_TW28_H
+#define __SOLO6010_TW28_H
+
+#include "solo6010.h"
+
+#define TW_NUM_CHIP 4
+#define TW_BASE_ADDR 0x28
+#define TW_CHIP_OFFSET_ADDR(n) (TW_BASE_ADDR + (n))
+
+/* tw2815 */
+#define TW_AV_STAT_ADDR 0x5a
+#define TW_HUE_ADDR(n) (0x07 | ((n) << 4))
+#define TW_SATURATION_ADDR(n) (0x08 | ((n) << 4))
+#define TW_CONTRAST_ADDR(n) (0x09 | ((n) << 4))
+#define TW_BRIGHTNESS_ADDR(n) (0x0a | ((n) << 4))
+#define TW_AUDIO_OUTPUT_VOL_ADDR 0x70
+#define TW_AUDIO_INPUT_GAIN_ADDR(n) (0x60 + ((n > 1) ? 1 : 0))
+
+/* tw286x */
+#define TW286X_AV_STAT_ADDR 0xfd
+#define TW286x_HUE_ADDR(n) (0x06 | ((n) << 4))
+#define TW286x_SATURATIONU_ADDR(n) (0x04 | ((n) << 4))
+#define TW286x_SATURATIONV_ADDR(n) (0x05 | ((n) << 4))
+#define TW286x_CONTRAST_ADDR(n) (0x02 | ((n) << 4))
+#define TW286x_BRIGHTNESS_ADDR(n) (0x01 | ((n) << 4))
+#define TW286x_SHARPNESS(n) (0x03 | ((n) << 4))
+#define TW286x_AUDIO_OUTPUT_VOL_ADDR 0xdf
+#define TW286x_AUDIO_INPUT_GAIN_ADDR(n) (0xD0 + ((n > 1) ? 1 : 0))
+
+int solo_tw28_init(struct solo6010_dev *solo_dev);
+
+int tw28_set_ctrl_val(struct solo6010_dev *solo_dev, u32 ctrl, u8 ch,
+ s32 val);
+int tw28_get_ctrl_val(struct solo6010_dev *solo_dev, u32 ctrl, u8 ch,
+ s32 *val);
+
+u8 tw28_get_audio_gain(struct solo6010_dev *solo_dev, u8 ch);
+void tw28_set_audio_gain(struct solo6010_dev *solo_dev, u8 ch, u8 val);
+int tw28_get_video_status(struct solo6010_dev *solo_dev, u8 ch);
+
+#if 0
+unsigned int tw2815_get_audio_status(struct SOLO6010 *solo6010);
+void tw2815_Set_AudioOutVol(struct SOLO6010 *solo6010, unsigned int u_val);
+#endif
+
+#endif /* __SOLO6010_TW28_H */
diff --git a/drivers/staging/solo6x10/solo6010-v4l2-enc.c b/drivers/staging/solo6x10/solo6010-v4l2-enc.c
new file mode 100644
index 00000000000..f114b4b7d8e
--- /dev/null
+++ b/drivers/staging/solo6x10/solo6010-v4l2-enc.c
@@ -0,0 +1,1564 @@
+/*
+ * Copyright (C) 2010 Bluecherry, LLC www.bluecherrydvr.com
+ * Copyright (C) 2010 Ben Collins <bcollins@bluecherry.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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/kthread.h>
+#include <linux/freezer.h>
+
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-common.h>
+#include <media/videobuf-dma-contig.h>
+
+#include "solo6010.h"
+#include "solo6010-tw28.h"
+#include "solo6010-jpeg.h"
+
+#define MIN_VID_BUFFERS 4
+#define FRAME_BUF_SIZE (128 * 1024)
+#define MP4_QS 16
+
+static int solo_enc_thread(void *data);
+
+extern unsigned video_nr;
+
+struct solo_enc_fh {
+ struct solo_enc_dev *enc;
+ u32 fmt;
+ u16 rd_idx;
+ u8 enc_on;
+ enum solo_enc_types type;
+ struct videobuf_queue vidq;
+ struct list_head vidq_active;
+ struct task_struct *kthread;
+};
+
+static unsigned char vid_vop_header[] = {
+ 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x20,
+ 0x02, 0x48, 0x05, 0xc0, 0x00, 0x40, 0x00, 0x40,
+ 0x00, 0x40, 0x00, 0x80, 0x00, 0x97, 0x53, 0x04,
+ 0x1f, 0x4c, 0x58, 0x10, 0x78, 0x51, 0x18, 0x3e,
+};
+
+/*
+ * Things we can change around:
+ *
+ * byte 10, 4-bits 01111000 aspect
+ * bytes 21,22,23 16-bits 000x1111 11111111 1111x000 fps/res
+ * bytes 23,24,25 15-bits 00000n11 11111111 11111x00 interval
+ * bytes 25,26,27 13-bits 00000x11 11111111 111x0000 width
+ * bytes 27,28,29 13-bits 000x1111 11111111 1x000000 height
+ * byte 29 1-bit 0x100000 interlace
+ */
+
+/* For aspect */
+#define XVID_PAR_43_PAL 2
+#define XVID_PAR_43_NTSC 3
+
+static const u32 solo_user_ctrls[] = {
+ V4L2_CID_BRIGHTNESS,
+ V4L2_CID_CONTRAST,
+ V4L2_CID_SATURATION,
+ V4L2_CID_HUE,
+ V4L2_CID_SHARPNESS,
+ 0
+};
+
+static const u32 solo_mpeg_ctrls[] = {
+ V4L2_CID_MPEG_VIDEO_ENCODING,
+ V4L2_CID_MPEG_VIDEO_GOP_SIZE,
+ 0
+};
+
+static const u32 solo_private_ctrls[] = {
+ V4L2_CID_MOTION_ENABLE,
+ V4L2_CID_MOTION_THRESHOLD,
+ 0
+};
+
+static const u32 solo_fmtx_ctrls[] = {
+ V4L2_CID_RDS_TX_RADIO_TEXT,
+ 0
+};
+
+static const u32 *solo_ctrl_classes[] = {
+ solo_user_ctrls,
+ solo_mpeg_ctrls,
+ solo_fmtx_ctrls,
+ solo_private_ctrls,
+ NULL
+};
+
+struct vop_header {
+ /* VD_IDX0 */
+ u32 size:20, sync_start:1, page_stop:1, vop_type:2, channel:4,
+ nop0:1, source_fl:1, interlace:1, progressive:1;
+
+ /* VD_IDX1 */
+ u32 vsize:8, hsize:8, frame_interop:1, nop1:7, win_id:4, scale:4;
+
+ /* VD_IDX2 */
+ u32 base_addr:16, nop2:15, hoff:1;
+
+ /* VD_IDX3 - User set macros */
+ u32 sy:12, sx:12, nop3:1, hzoom:1, read_interop:1, write_interlace:1,
+ scale_mode:4;
+
+ /* VD_IDX4 - User set macros continued */
+ u32 write_page:8, nop4:24;
+
+ /* VD_IDX5 */
+ u32 next_code_addr;
+
+ u32 end_nops[10];
+} __attribute__((packed));
+
+static int solo_is_motion_on(struct solo_enc_dev *solo_enc)
+{
+ struct solo6010_dev *solo_dev = solo_enc->solo_dev;
+ u8 ch = solo_enc->ch;
+
+ if (solo_dev->motion_mask & (1 << ch))
+ return 1;
+ return 0;
+}
+
+static void solo_motion_toggle(struct solo_enc_dev *solo_enc, int on)
+{
+ struct solo6010_dev *solo_dev = solo_enc->solo_dev;
+ u8 ch = solo_enc->ch;
+
+ spin_lock(&solo_enc->lock);
+
+ if (on)
+ solo_dev->motion_mask |= (1 << ch);
+ else
+ solo_dev->motion_mask &= ~(1 << ch);
+
+ solo_reg_write(solo_dev, SOLO_VI_MOT_ADR,
+ SOLO_VI_MOTION_EN(solo_dev->motion_mask) |
+ (SOLO_MOTION_EXT_ADDR(solo_dev) >> 16));
+
+ if (solo_dev->motion_mask)
+ solo6010_irq_on(solo_dev, SOLO_IRQ_MOTION);
+ else
+ solo6010_irq_off(solo_dev, SOLO_IRQ_MOTION);
+
+ spin_unlock(&solo_enc->lock);
+}
+
+/* Should be called with solo_enc->lock held */
+static void solo_update_mode(struct solo_enc_dev *solo_enc)
+{
+ struct solo6010_dev *solo_dev = solo_enc->solo_dev;
+
+ assert_spin_locked(&solo_enc->lock);
+
+ solo_enc->interlaced = (solo_enc->mode & 0x08) ? 1 : 0;
+ solo_enc->bw_weight = max(solo_dev->fps / solo_enc->interval, 1);
+
+ switch (solo_enc->mode) {
+ case SOLO_ENC_MODE_CIF:
+ solo_enc->width = solo_dev->video_hsize >> 1;
+ solo_enc->height = solo_dev->video_vsize;
+ break;
+ case SOLO_ENC_MODE_D1:
+ solo_enc->width = solo_dev->video_hsize;
+ solo_enc->height = solo_dev->video_vsize << 1;
+ solo_enc->bw_weight <<= 2;
+ break;
+ default:
+ WARN(1, "mode is unknown");
+ }
+}
+
+/* Should be called with solo_enc->lock held */
+static int solo_enc_on(struct solo_enc_fh *fh)
+{
+ struct solo_enc_dev *solo_enc = fh->enc;
+ u8 ch = solo_enc->ch;
+ struct solo6010_dev *solo_dev = solo_enc->solo_dev;
+ u8 interval;
+
+ assert_spin_locked(&solo_enc->lock);
+
+ if (fh->enc_on)
+ return 0;
+
+ solo_update_mode(solo_enc);
+
+ /* Make sure to bw check on first reader */
+ if (!atomic_read(&solo_enc->readers)) {
+ if (solo_enc->bw_weight > solo_dev->enc_bw_remain)
+ return -EBUSY;
+ else
+ solo_dev->enc_bw_remain -= solo_enc->bw_weight;
+ }
+
+ fh->kthread = kthread_run(solo_enc_thread, fh, SOLO6010_NAME "_enc");
+
+ if (IS_ERR(fh->kthread))
+ return PTR_ERR(fh->kthread);
+
+ fh->enc_on = 1;
+ fh->rd_idx = solo_enc->solo_dev->enc_wr_idx;
+
+ if (fh->type == SOLO_ENC_TYPE_EXT)
+ solo_reg_write(solo_dev, SOLO_CAP_CH_COMP_ENA_E(ch), 1);
+
+ if (atomic_inc_return(&solo_enc->readers) > 1)
+ return 0;
+
+ /* Disable all encoding for this channel */
+ solo_reg_write(solo_dev, SOLO_CAP_CH_SCALE(ch), 0);
+
+ /* Common for both std and ext encoding */
+ solo_reg_write(solo_dev, SOLO_VE_CH_INTL(ch),
+ solo_enc->interlaced ? 1 : 0);
+
+ if (solo_enc->interlaced)
+ interval = solo_enc->interval - 1;
+ else
+ interval = solo_enc->interval;
+
+ /* Standard encoding only */
+ solo_reg_write(solo_dev, SOLO_VE_CH_GOP(ch), solo_enc->gop);
+ solo_reg_write(solo_dev, SOLO_VE_CH_QP(ch), solo_enc->qp);
+ solo_reg_write(solo_dev, SOLO_CAP_CH_INTV(ch), interval);
+
+ /* Extended encoding only */
+ solo_reg_write(solo_dev, SOLO_VE_CH_GOP_E(ch), solo_enc->gop);
+ solo_reg_write(solo_dev, SOLO_VE_CH_QP_E(ch), solo_enc->qp);
+ solo_reg_write(solo_dev, SOLO_CAP_CH_INTV_E(ch), interval);
+
+ /* Enables the standard encoder */
+ solo_reg_write(solo_dev, SOLO_CAP_CH_SCALE(ch), solo_enc->mode);
+
+ /* Settle down Beavis... */
+ mdelay(10);
+
+ return 0;
+}
+
+static void solo_enc_off(struct solo_enc_fh *fh)
+{
+ struct solo_enc_dev *solo_enc = fh->enc;
+ struct solo6010_dev *solo_dev = solo_enc->solo_dev;
+
+ if (!fh->enc_on)
+ return;
+
+ if (fh->kthread) {
+ kthread_stop(fh->kthread);
+ fh->kthread = NULL;
+ }
+
+ solo_dev->enc_bw_remain += solo_enc->bw_weight;
+ fh->enc_on = 0;
+
+ if (atomic_dec_return(&solo_enc->readers) > 0)
+ return;
+
+ solo_reg_write(solo_dev, SOLO_CAP_CH_SCALE(solo_enc->ch), 0);
+ solo_reg_write(solo_dev, SOLO_CAP_CH_COMP_ENA_E(solo_enc->ch), 0);
+}
+
+static void enc_reset_gop(struct solo6010_dev *solo_dev, u8 ch)
+{
+ BUG_ON(ch >= solo_dev->nr_chans);
+ solo_reg_write(solo_dev, SOLO_VE_CH_GOP(ch), 1);
+ solo_dev->v4l2_enc[ch]->reset_gop = 1;
+}
+
+static int enc_gop_reset(struct solo6010_dev *solo_dev, u8 ch, u8 vop)
+{
+ BUG_ON(ch >= solo_dev->nr_chans);
+ if (!solo_dev->v4l2_enc[ch]->reset_gop)
+ return 0;
+ if (vop)
+ return 1;
+ solo_dev->v4l2_enc[ch]->reset_gop = 0;
+ solo_reg_write(solo_dev, SOLO_VE_CH_GOP(ch),
+ solo_dev->v4l2_enc[ch]->gop);
+ return 0;
+}
+
+static int enc_get_mpeg_dma_t(struct solo6010_dev *solo_dev, dma_addr_t buf,
+ unsigned int off, unsigned int size)
+{
+ int ret;
+
+ if (off > SOLO_MP4E_EXT_SIZE(solo_dev))
+ return -EINVAL;
+
+ if (off + size <= SOLO_MP4E_EXT_SIZE(solo_dev))
+ return solo_p2m_dma_t(solo_dev, SOLO_P2M_DMA_ID_MP4E, 0, buf,
+ SOLO_MP4E_EXT_ADDR(solo_dev) + off, size);
+
+ /* Buffer wrap */
+ ret = solo_p2m_dma_t(solo_dev, SOLO_P2M_DMA_ID_MP4E, 0, buf,
+ SOLO_MP4E_EXT_ADDR(solo_dev) + off,
+ SOLO_MP4E_EXT_SIZE(solo_dev) - off);
+
+ ret |= solo_p2m_dma_t(solo_dev, SOLO_P2M_DMA_ID_MP4E, 0,
+ buf + SOLO_MP4E_EXT_SIZE(solo_dev) - off,
+ SOLO_MP4E_EXT_ADDR(solo_dev),
+ size + off - SOLO_MP4E_EXT_SIZE(solo_dev));
+
+ return ret;
+}
+
+static int enc_get_mpeg_dma(struct solo6010_dev *solo_dev, void *buf,
+ unsigned int off, unsigned int size)
+{
+ int ret;
+
+ dma_addr_t dma_addr = pci_map_single(solo_dev->pdev, buf, size,
+ PCI_DMA_FROMDEVICE);
+ ret = enc_get_mpeg_dma_t(solo_dev, dma_addr, off, size);
+ pci_unmap_single(solo_dev->pdev, dma_addr, size, PCI_DMA_FROMDEVICE);
+
+ return ret;
+}
+
+static int enc_get_jpeg_dma(struct solo6010_dev *solo_dev, dma_addr_t buf,
+ unsigned int off, unsigned int size)
+{
+ int ret;
+
+ if (off > SOLO_JPEG_EXT_SIZE(solo_dev))
+ return -EINVAL;
+
+ if (off + size <= SOLO_JPEG_EXT_SIZE(solo_dev))
+ return solo_p2m_dma_t(solo_dev, SOLO_P2M_DMA_ID_JPEG, 0, buf,
+ SOLO_JPEG_EXT_ADDR(solo_dev) + off, size);
+
+ /* Buffer wrap */
+ ret = solo_p2m_dma_t(solo_dev, SOLO_P2M_DMA_ID_JPEG, 0, buf,
+ SOLO_JPEG_EXT_ADDR(solo_dev) + off,
+ SOLO_JPEG_EXT_SIZE(solo_dev) - off);
+
+ ret |= solo_p2m_dma_t(solo_dev, SOLO_P2M_DMA_ID_JPEG, 0,
+ buf + SOLO_JPEG_EXT_SIZE(solo_dev) - off,
+ SOLO_JPEG_EXT_ADDR(solo_dev),
+ size + off - SOLO_JPEG_EXT_SIZE(solo_dev));
+
+ return ret;
+}
+
+static int solo_fill_jpeg(struct solo_enc_fh *fh, struct solo_enc_buf *enc_buf,
+ struct videobuf_buffer *vb, dma_addr_t vbuf)
+{
+ struct solo_enc_dev *solo_enc = fh->enc;
+ struct solo6010_dev *solo_dev = solo_enc->solo_dev;
+ u8 *p = videobuf_queue_to_vaddr(&fh->vidq, vb);
+
+ memcpy(p, jpeg_header, sizeof(jpeg_header));
+ p[SOF0_START + 5] = 0xff & (solo_enc->height >> 8);
+ p[SOF0_START + 6] = 0xff & solo_enc->height;
+ p[SOF0_START + 7] = 0xff & (solo_enc->width >> 8);
+ p[SOF0_START + 8] = 0xff & solo_enc->width;
+
+ vbuf += sizeof(jpeg_header);
+ vb->size = enc_buf->jpeg_size + sizeof(jpeg_header);
+
+ return enc_get_jpeg_dma(solo_dev, vbuf, enc_buf->jpeg_off,
+ enc_buf->jpeg_size);
+}
+
+static int solo_fill_mpeg(struct solo_enc_fh *fh, struct solo_enc_buf *enc_buf,
+ struct videobuf_buffer *vb, dma_addr_t vbuf)
+{
+ struct solo_enc_dev *solo_enc = fh->enc;
+ struct solo6010_dev *solo_dev = solo_enc->solo_dev;
+ struct vop_header vh;
+ int ret;
+ int frame_size, frame_off;
+
+ if (WARN_ON_ONCE(enc_buf->size <= sizeof(vh)))
+ return -1;
+
+ /* First get the hardware vop header (not real mpeg) */
+ ret = enc_get_mpeg_dma(solo_dev, &vh, enc_buf->off, sizeof(vh));
+ if (ret)
+ return -1;
+
+ if (WARN_ON_ONCE(vh.size > enc_buf->size))
+ return -1;
+
+ vb->width = vh.hsize << 4;
+ vb->height = vh.vsize << 4;
+ vb->size = vh.size;
+
+ /* If this is a key frame, add extra m4v header */
+ if (!enc_buf->vop) {
+ u16 fps = solo_dev->fps * 1000;
+ u16 interval = solo_enc->interval * 1000;
+ u8 *p = videobuf_queue_to_vaddr(&fh->vidq, vb);
+
+ memcpy(p, vid_vop_header, sizeof(vid_vop_header));
+
+ if (solo_dev->video_type == SOLO_VO_FMT_TYPE_NTSC)
+ p[10] |= ((XVID_PAR_43_NTSC << 3) & 0x78);
+ else
+ p[10] |= ((XVID_PAR_43_PAL << 3) & 0x78);
+
+ /* Frame rate and interval */
+ p[22] = fps >> 4;
+ p[23] = ((fps << 4) & 0xf0) | 0x0c | ((interval >> 13) & 0x3);
+ p[24] = (interval >> 5) & 0xff;
+ p[25] = ((interval << 3) & 0xf8) | 0x04;
+
+ /* Width and height */
+ p[26] = (vb->width >> 3) & 0xff;
+ p[27] = ((vb->height >> 9) & 0x0f) | 0x10;
+ p[28] = (vb->height >> 1) & 0xff;
+
+ /* Interlace */
+ if (vh.interlace)
+ p[29] |= 0x20;
+
+ /* Adjust the dma buffer past this header */
+ vb->size += sizeof(vid_vop_header);
+ vbuf += sizeof(vid_vop_header);
+ }
+
+ /* Now get the actual mpeg payload */
+ frame_off = (enc_buf->off + sizeof(vh)) % SOLO_MP4E_EXT_SIZE(solo_dev);
+ frame_size = enc_buf->size - sizeof(vh);
+ ret = enc_get_mpeg_dma_t(solo_dev, vbuf, frame_off, frame_size);
+ if (WARN_ON_ONCE(ret))
+ return -1;
+
+ return 0;
+}
+
+/* On successful return (0), leaves solo_enc->lock unlocked */
+static int solo_enc_fillbuf(struct solo_enc_fh *fh,
+ struct videobuf_buffer *vb)
+{
+ struct solo_enc_dev *solo_enc = fh->enc;
+ struct solo6010_dev *solo_dev = solo_enc->solo_dev;
+ struct solo_enc_buf *enc_buf = NULL;
+ dma_addr_t vbuf;
+ int ret;
+ u16 idx = fh->rd_idx;
+
+ while (idx != solo_dev->enc_wr_idx) {
+ struct solo_enc_buf *ebuf = &solo_dev->enc_buf[idx];
+ idx = (idx + 1) % SOLO_NR_RING_BUFS;
+ if (fh->fmt == V4L2_PIX_FMT_MPEG) {
+ if (fh->type != ebuf->type)
+ continue;
+ if (ebuf->ch == solo_enc->ch) {
+ enc_buf = ebuf;
+ break;
+ }
+ } else if (ebuf->ch == solo_enc->ch) {
+ /* For mjpeg, keep reading to the newest frame */
+ enc_buf = ebuf;
+ }
+ }
+
+ fh->rd_idx = idx;
+
+ if (!enc_buf)
+ return -1;
+
+ if ((fh->fmt == V4L2_PIX_FMT_MPEG &&
+ vb->bsize < enc_buf->size) ||
+ (fh->fmt == V4L2_PIX_FMT_MJPEG &&
+ vb->bsize < (enc_buf->jpeg_size + sizeof(jpeg_header)))) {
+ return -1;
+ }
+
+ if (!(vbuf = videobuf_to_dma_contig(vb)))
+ return -1;
+
+ /* Is it ok that we mess with this buffer out of lock? */
+ spin_unlock(&solo_enc->lock);
+
+ if (fh->fmt == V4L2_PIX_FMT_MPEG)
+ ret = solo_fill_mpeg(fh, enc_buf, vb, vbuf);
+ else
+ ret = solo_fill_jpeg(fh, enc_buf, vb, vbuf);
+
+ if (ret) // Ignore failures
+ return 0;
+
+ list_del(&vb->queue);
+ vb->field_count++;
+ vb->ts = enc_buf->ts;
+ vb->state = VIDEOBUF_DONE;
+
+ wake_up(&vb->done);
+
+ return 0;
+}
+
+static void solo_enc_thread_try(struct solo_enc_fh *fh)
+{
+ struct solo_enc_dev *solo_enc = fh->enc;
+ struct videobuf_buffer *vb;
+
+ for (;;) {
+ spin_lock(&solo_enc->lock);
+
+ if (list_empty(&fh->vidq_active))
+ break;
+
+ vb = list_first_entry(&fh->vidq_active,
+ struct videobuf_buffer, queue);
+
+ if (!waitqueue_active(&vb->done))
+ break;
+
+ /* On success, returns with solo_enc->lock unlocked */
+ if (solo_enc_fillbuf(fh, vb))
+ break;
+ }
+
+ assert_spin_locked(&solo_enc->lock);
+ spin_unlock(&solo_enc->lock);
+}
+
+static int solo_enc_thread(void *data)
+{
+ struct solo_enc_fh *fh = data;
+ struct solo_enc_dev *solo_enc = fh->enc;
+ DECLARE_WAITQUEUE(wait, current);
+
+ set_freezable();
+ add_wait_queue(&solo_enc->thread_wait, &wait);
+
+ for (;;) {
+ long timeout = schedule_timeout_interruptible(HZ);
+ if (timeout == -ERESTARTSYS || kthread_should_stop())
+ break;
+ solo_enc_thread_try(fh);
+ try_to_freeze();
+ }
+
+ remove_wait_queue(&solo_enc->thread_wait, &wait);
+
+ return 0;
+}
+
+void solo_motion_isr(struct solo6010_dev *solo_dev)
+{
+ u32 status;
+ int i;
+
+ solo_reg_write(solo_dev, SOLO_IRQ_STAT, SOLO_IRQ_MOTION);
+
+ status = solo_reg_read(solo_dev, SOLO_VI_MOT_STATUS);
+
+ for (i = 0; i < solo_dev->nr_chans; i++) {
+ struct solo_enc_dev *solo_enc = solo_dev->v4l2_enc[i];
+
+ BUG_ON(solo_enc == NULL);
+
+ if (solo_enc->motion_detected)
+ continue;
+ if (!(status & (1 << i)))
+ continue;
+
+ solo_enc->motion_detected = 1;
+ }
+}
+
+void solo_enc_v4l2_isr(struct solo6010_dev *solo_dev)
+{
+ struct solo_enc_buf *enc_buf;
+ struct videnc_status vstatus;
+ u32 mpeg_current, mpeg_next, mpeg_size;
+ u32 jpeg_current, jpeg_next, jpeg_size;
+ u32 reg_mpeg_size;
+ u8 cur_q, vop_type;
+ u8 ch;
+ enum solo_enc_types enc_type;
+
+ solo_reg_write(solo_dev, SOLO_IRQ_STAT, SOLO_IRQ_ENCODER);
+
+ vstatus.status11 = solo_reg_read(solo_dev, SOLO_VE_STATE(11));
+ cur_q = (vstatus.status11_st.last_queue + 1) % MP4_QS;
+
+ vstatus.status0 = solo_reg_read(solo_dev, SOLO_VE_STATE(0));
+ reg_mpeg_size = (vstatus.status0_st.mp4_enc_code_size + 64 + 32) &
+ (~31);
+
+ while (solo_dev->enc_idx != cur_q) {
+ mpeg_current = solo_reg_read(solo_dev,
+ SOLO_VE_MPEG4_QUE(solo_dev->enc_idx));
+ jpeg_current = solo_reg_read(solo_dev,
+ SOLO_VE_JPEG_QUE(solo_dev->enc_idx));
+ solo_dev->enc_idx = (solo_dev->enc_idx + 1) % MP4_QS;
+ mpeg_next = solo_reg_read(solo_dev,
+ SOLO_VE_MPEG4_QUE(solo_dev->enc_idx));
+ jpeg_next = solo_reg_read(solo_dev,
+ SOLO_VE_JPEG_QUE(solo_dev->enc_idx));
+
+ if ((ch = (mpeg_current >> 24) & 0x1f) >= SOLO_MAX_CHANNELS) {
+ ch -= SOLO_MAX_CHANNELS;
+ enc_type = SOLO_ENC_TYPE_EXT;
+ } else
+ enc_type = SOLO_ENC_TYPE_STD;
+
+ vop_type = (mpeg_current >> 29) & 3;
+
+ mpeg_current &= 0x00ffffff;
+ mpeg_next &= 0x00ffffff;
+ jpeg_current &= 0x00ffffff;
+ jpeg_next &= 0x00ffffff;
+
+ mpeg_size = (SOLO_MP4E_EXT_SIZE(solo_dev) +
+ mpeg_next - mpeg_current) %
+ SOLO_MP4E_EXT_SIZE(solo_dev);
+
+ jpeg_size = (SOLO_JPEG_EXT_SIZE(solo_dev) +
+ jpeg_next - jpeg_current) %
+ SOLO_JPEG_EXT_SIZE(solo_dev);
+
+ /* XXX I think this means we had a ring overflow? */
+ if (mpeg_current > mpeg_next && mpeg_size != reg_mpeg_size) {
+ enc_reset_gop(solo_dev, ch);
+ continue;
+ }
+
+ /* When resetting the GOP, skip frames until I-frame */
+ if (enc_gop_reset(solo_dev, ch, vop_type))
+ continue;
+
+ enc_buf = &solo_dev->enc_buf[solo_dev->enc_wr_idx];
+
+ enc_buf->vop = vop_type;
+ enc_buf->ch = ch;
+ enc_buf->off = mpeg_current;
+ enc_buf->size = mpeg_size;
+ enc_buf->jpeg_off = jpeg_current;
+ enc_buf->jpeg_size = jpeg_size;
+ enc_buf->type = enc_type;
+
+ do_gettimeofday(&enc_buf->ts);
+
+ solo_dev->enc_wr_idx = (solo_dev->enc_wr_idx + 1) %
+ SOLO_NR_RING_BUFS;
+
+ wake_up_interruptible(&solo_dev->v4l2_enc[ch]->thread_wait);
+ }
+
+ return;
+}
+
+static int solo_enc_buf_setup(struct videobuf_queue *vq, unsigned int *count,
+ unsigned int *size)
+{
+ *size = FRAME_BUF_SIZE;
+
+ if (*count < MIN_VID_BUFFERS)
+ *count = MIN_VID_BUFFERS;
+
+ return 0;
+}
+
+static int solo_enc_buf_prepare(struct videobuf_queue *vq,
+ struct videobuf_buffer *vb,
+ enum v4l2_field field)
+{
+ struct solo_enc_fh *fh = vq->priv_data;
+ struct solo_enc_dev *solo_enc = fh->enc;
+
+ vb->size = FRAME_BUF_SIZE;
+ if (vb->baddr != 0 && vb->bsize < vb->size)
+ return -EINVAL;
+
+ /* These properties only change when queue is idle */
+ vb->width = solo_enc->width;
+ vb->height = solo_enc->height;
+ vb->field = field;
+
+ if (vb->state == VIDEOBUF_NEEDS_INIT) {
+ int rc = videobuf_iolock(vq, vb, NULL);
+ if (rc < 0) {
+ videobuf_dma_contig_free(vq, vb);
+ vb->state = VIDEOBUF_NEEDS_INIT;
+ return rc;
+ }
+ }
+ vb->state = VIDEOBUF_PREPARED;
+
+ return 0;
+}
+
+static void solo_enc_buf_queue(struct videobuf_queue *vq,
+ struct videobuf_buffer *vb)
+{
+ struct solo_enc_fh *fh = vq->priv_data;
+
+ vb->state = VIDEOBUF_QUEUED;
+ list_add_tail(&vb->queue, &fh->vidq_active);
+ wake_up_interruptible(&fh->enc->thread_wait);
+}
+
+static void solo_enc_buf_release(struct videobuf_queue *vq,
+ struct videobuf_buffer *vb)
+{
+ videobuf_dma_contig_free(vq, vb);
+ vb->state = VIDEOBUF_NEEDS_INIT;
+}
+
+static struct videobuf_queue_ops solo_enc_video_qops = {
+ .buf_setup = solo_enc_buf_setup,
+ .buf_prepare = solo_enc_buf_prepare,
+ .buf_queue = solo_enc_buf_queue,
+ .buf_release = solo_enc_buf_release,
+};
+
+static unsigned int solo_enc_poll(struct file *file,
+ struct poll_table_struct *wait)
+{
+ struct solo_enc_fh *fh = file->private_data;
+
+ return videobuf_poll_stream(file, &fh->vidq, wait);
+}
+
+static int solo_enc_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ struct solo_enc_fh *fh = file->private_data;
+
+ return videobuf_mmap_mapper(&fh->vidq, vma);
+}
+
+static int solo_enc_open(struct file *file)
+{
+ struct solo_enc_dev *solo_enc = video_drvdata(file);
+ struct solo_enc_fh *fh;
+
+ if ((fh = kzalloc(sizeof(*fh), GFP_KERNEL)) == NULL)
+ return -ENOMEM;
+
+ spin_lock(&solo_enc->lock);
+
+ fh->enc = solo_enc;
+ file->private_data = fh;
+ INIT_LIST_HEAD(&fh->vidq_active);
+ fh->fmt = V4L2_PIX_FMT_MPEG;
+ fh->type = SOLO_ENC_TYPE_STD;
+
+ videobuf_queue_dma_contig_init(&fh->vidq, &solo_enc_video_qops,
+ &solo_enc->solo_dev->pdev->dev,
+ &solo_enc->lock,
+ V4L2_BUF_TYPE_VIDEO_CAPTURE,
+ V4L2_FIELD_INTERLACED,
+ sizeof(struct videobuf_buffer), fh);
+
+ spin_unlock(&solo_enc->lock);
+
+ return 0;
+}
+
+static ssize_t solo_enc_read(struct file *file, char __user *data,
+ size_t count, loff_t *ppos)
+{
+ struct solo_enc_fh *fh = file->private_data;
+ struct solo_enc_dev *solo_enc = fh->enc;
+
+ /* Make sure the encoder is on */
+ if (!fh->enc_on) {
+ int ret;
+
+ spin_lock(&solo_enc->lock);
+ ret = solo_enc_on(fh);
+ spin_unlock(&solo_enc->lock);
+ if (ret)
+ return ret;
+ }
+
+ return videobuf_read_stream(&fh->vidq, data, count, ppos, 0,
+ file->f_flags & O_NONBLOCK);
+}
+
+static int solo_enc_release(struct file *file)
+{
+ struct solo_enc_fh *fh = file->private_data;
+
+ videobuf_stop(&fh->vidq);
+ videobuf_mmap_free(&fh->vidq);
+ solo_enc_off(fh);
+ kfree(fh);
+
+ return 0;
+}
+
+static int solo_enc_querycap(struct file *file, void *priv,
+ struct v4l2_capability *cap)
+{
+ struct solo_enc_fh *fh = priv;
+ struct solo_enc_dev *solo_enc = fh->enc;
+ struct solo6010_dev *solo_dev = solo_enc->solo_dev;
+
+ strcpy(cap->driver, SOLO6010_NAME);
+ snprintf(cap->card, sizeof(cap->card), "Softlogic 6010 Enc %d",
+ solo_enc->ch);
+ snprintf(cap->bus_info, sizeof(cap->bus_info), "PCI %s",
+ pci_name(solo_dev->pdev));
+ cap->version = SOLO6010_VER_NUM;
+ cap->capabilities = V4L2_CAP_VIDEO_CAPTURE |
+ V4L2_CAP_READWRITE |
+ V4L2_CAP_STREAMING;
+ return 0;
+}
+
+static int solo_enc_enum_input(struct file *file, void *priv,
+ struct v4l2_input *input)
+{
+ struct solo_enc_fh *fh = priv;
+ struct solo_enc_dev *solo_enc = fh->enc;
+ struct solo6010_dev *solo_dev = solo_enc->solo_dev;
+
+ if (input->index)
+ return -EINVAL;
+
+ snprintf(input->name, sizeof(input->name), "Encoder %d",
+ solo_enc->ch + 1);
+ input->type = V4L2_INPUT_TYPE_CAMERA;
+
+ if (solo_dev->video_type == SOLO_VO_FMT_TYPE_NTSC)
+ input->std = V4L2_STD_NTSC_M;
+ else
+ input->std = V4L2_STD_PAL_M;
+
+ if (!tw28_get_video_status(solo_dev, solo_enc->ch))
+ input->status = V4L2_IN_ST_NO_SIGNAL;
+
+ return 0;
+}
+
+static int solo_enc_set_input(struct file *file, void *priv, unsigned int index)
+{
+ if (index)
+ return -EINVAL;
+
+ return 0;
+}
+
+static int solo_enc_get_input(struct file *file, void *priv,
+ unsigned int *index)
+{
+ *index = 0;
+
+ return 0;
+}
+
+static int solo_enc_enum_fmt_cap(struct file *file, void *priv,
+ struct v4l2_fmtdesc *f)
+{
+ switch (f->index) {
+ case 0:
+ f->pixelformat = V4L2_PIX_FMT_MPEG;
+ strcpy(f->description, "MPEG-4 AVC");
+ break;
+ case 1:
+ f->pixelformat = V4L2_PIX_FMT_MJPEG;
+ strcpy(f->description, "MJPEG");
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ f->flags = V4L2_FMT_FLAG_COMPRESSED;
+
+ return 0;
+}
+
+static int solo_enc_try_fmt_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct solo_enc_fh *fh = priv;
+ struct solo_enc_dev *solo_enc = fh->enc;
+ struct solo6010_dev *solo_dev = solo_enc->solo_dev;
+ struct v4l2_pix_format *pix = &f->fmt.pix;
+
+ if (pix->pixelformat != V4L2_PIX_FMT_MPEG &&
+ pix->pixelformat != V4L2_PIX_FMT_MJPEG)
+ return -EINVAL;
+
+ /* We cannot change width/height in mid read */
+ if (atomic_read(&solo_enc->readers) > 0) {
+ if (pix->width != solo_enc->width ||
+ pix->height != solo_enc->height)
+ return -EBUSY;
+ } else if (!(pix->width == solo_dev->video_hsize &&
+ pix->height == solo_dev->video_vsize << 1) &&
+ !(pix->width == solo_dev->video_hsize >> 1 &&
+ pix->height == solo_dev->video_vsize)) {
+ /* Default to CIF 1/2 size */
+ pix->width = solo_dev->video_hsize >> 1;
+ pix->height = solo_dev->video_vsize;
+ }
+
+ if (pix->field == V4L2_FIELD_ANY)
+ pix->field = V4L2_FIELD_INTERLACED;
+ else if (pix->field != V4L2_FIELD_INTERLACED) {
+ pix->field = V4L2_FIELD_INTERLACED;
+ }
+
+ /* Just set these */
+ pix->colorspace = V4L2_COLORSPACE_SMPTE170M;
+ pix->sizeimage = FRAME_BUF_SIZE;
+
+ return 0;
+}
+
+static int solo_enc_set_fmt_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct solo_enc_fh *fh = priv;
+ struct solo_enc_dev *solo_enc = fh->enc;
+ struct solo6010_dev *solo_dev = solo_enc->solo_dev;
+ struct v4l2_pix_format *pix = &f->fmt.pix;
+ int ret;
+
+ spin_lock(&solo_enc->lock);
+
+ if ((ret = solo_enc_try_fmt_cap(file, priv, f))) {
+ spin_unlock(&solo_enc->lock);
+ return ret;
+ }
+
+ if (pix->width == solo_dev->video_hsize)
+ solo_enc->mode = SOLO_ENC_MODE_D1;
+ else
+ solo_enc->mode = SOLO_ENC_MODE_CIF;
+
+ /* This does not change the encoder at all */
+ fh->fmt = pix->pixelformat;
+
+ if (pix->priv)
+ fh->type = SOLO_ENC_TYPE_EXT;
+ ret = solo_enc_on(fh);
+
+ spin_unlock(&solo_enc->lock);
+
+ return ret;
+}
+
+static int solo_enc_get_fmt_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct solo_enc_fh *fh = priv;
+ struct solo_enc_dev *solo_enc = fh->enc;
+ struct v4l2_pix_format *pix = &f->fmt.pix;
+
+ pix->width = solo_enc->width;
+ pix->height = solo_enc->height;
+ pix->pixelformat = fh->fmt;
+ pix->field = solo_enc->interlaced ? V4L2_FIELD_INTERLACED :
+ V4L2_FIELD_NONE;
+ pix->sizeimage = FRAME_BUF_SIZE;
+ pix->colorspace = V4L2_COLORSPACE_SMPTE170M;
+
+ return 0;
+}
+
+static int solo_enc_reqbufs(struct file *file, void *priv,
+ struct v4l2_requestbuffers *req)
+{
+ struct solo_enc_fh *fh = priv;
+
+ return videobuf_reqbufs(&fh->vidq, req);
+}
+
+static int solo_enc_querybuf(struct file *file, void *priv,
+ struct v4l2_buffer *buf)
+{
+ struct solo_enc_fh *fh = priv;
+
+ return videobuf_querybuf(&fh->vidq, buf);
+}
+
+static int solo_enc_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
+{
+ struct solo_enc_fh *fh = priv;
+
+ return videobuf_qbuf(&fh->vidq, buf);
+}
+
+static int solo_enc_dqbuf(struct file *file, void *priv,
+ struct v4l2_buffer *buf)
+{
+ struct solo_enc_fh *fh = priv;
+ struct solo_enc_dev *solo_enc = fh->enc;
+ int ret;
+
+ /* Make sure the encoder is on */
+ if (!fh->enc_on) {
+ spin_lock(&solo_enc->lock);
+ ret = solo_enc_on(fh);
+ spin_unlock(&solo_enc->lock);
+ if (ret)
+ return ret;
+ }
+
+ ret = videobuf_dqbuf(&fh->vidq, buf, file->f_flags & O_NONBLOCK);
+ if (ret)
+ return ret;
+
+ /* Signal motion detection */
+ if (solo_is_motion_on(solo_enc)) {
+ buf->flags |= V4L2_BUF_FLAG_MOTION_ON;
+ if (solo_enc->motion_detected) {
+ buf->flags |= V4L2_BUF_FLAG_MOTION_DETECTED;
+ solo_reg_write(solo_enc->solo_dev, SOLO_VI_MOT_CLEAR,
+ 1 << solo_enc->ch);
+ solo_enc->motion_detected = 0;
+ }
+ }
+
+ /* Check for key frame on mpeg data */
+ if (fh->fmt == V4L2_PIX_FMT_MPEG) {
+ struct videobuf_buffer *vb = fh->vidq.bufs[buf->index];
+ u8 *p = videobuf_queue_to_vaddr(&fh->vidq, vb);
+ if (p[3] == 0x00)
+ buf->flags |= V4L2_BUF_FLAG_KEYFRAME;
+ else
+ buf->flags |= V4L2_BUF_FLAG_PFRAME;
+ }
+
+ return 0;
+}
+
+static int solo_enc_streamon(struct file *file, void *priv,
+ enum v4l2_buf_type i)
+{
+ struct solo_enc_fh *fh = priv;
+
+ if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ return videobuf_streamon(&fh->vidq);
+}
+
+static int solo_enc_streamoff(struct file *file, void *priv,
+ enum v4l2_buf_type i)
+{
+ struct solo_enc_fh *fh = priv;
+
+ if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ return videobuf_streamoff(&fh->vidq);
+}
+
+static int solo_enc_s_std(struct file *file, void *priv, v4l2_std_id *i)
+{
+ return 0;
+}
+
+static int solo_enum_framesizes(struct file *file, void *priv,
+ struct v4l2_frmsizeenum *fsize)
+{
+ struct solo_enc_fh *fh = priv;
+ struct solo6010_dev *solo_dev = fh->enc->solo_dev;
+
+ if (fsize->pixel_format != V4L2_PIX_FMT_MPEG)
+ return -EINVAL;
+
+ switch (fsize->index) {
+ case 0:
+ fsize->discrete.width = solo_dev->video_hsize >> 1;
+ fsize->discrete.height = solo_dev->video_vsize;
+ break;
+ case 1:
+ fsize->discrete.width = solo_dev->video_hsize;
+ fsize->discrete.height = solo_dev->video_vsize << 1;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE;
+
+ return 0;
+}
+
+static int solo_enum_frameintervals(struct file *file, void *priv,
+ struct v4l2_frmivalenum *fintv)
+{
+ struct solo_enc_fh *fh = priv;
+ struct solo6010_dev *solo_dev = fh->enc->solo_dev;
+
+ if (fintv->pixel_format != V4L2_PIX_FMT_MPEG || fintv->index)
+ return -EINVAL;
+
+ fintv->type = V4L2_FRMIVAL_TYPE_STEPWISE;
+
+ fintv->stepwise.min.numerator = solo_dev->fps;
+ fintv->stepwise.min.denominator = 1;
+
+ fintv->stepwise.max.numerator = solo_dev->fps;
+ fintv->stepwise.max.denominator = 15;
+
+ fintv->stepwise.step.numerator = 1;
+ fintv->stepwise.step.denominator = 1;
+
+ return 0;
+}
+
+static int solo_g_parm(struct file *file, void *priv,
+ struct v4l2_streamparm *sp)
+{
+ struct solo_enc_fh *fh = priv;
+ struct solo_enc_dev *solo_enc = fh->enc;
+ struct solo6010_dev *solo_dev = solo_enc->solo_dev;
+ struct v4l2_captureparm *cp = &sp->parm.capture;
+
+ cp->capability = V4L2_CAP_TIMEPERFRAME;
+ cp->timeperframe.numerator = solo_enc->interval;
+ cp->timeperframe.denominator = solo_dev->fps;
+ cp->capturemode = 0;
+ /* XXX: Shouldn't we be able to get/set this from videobuf? */
+ cp->readbuffers = 2;
+
+ return 0;
+}
+
+static int solo_s_parm(struct file *file, void *priv,
+ struct v4l2_streamparm *sp)
+{
+ struct solo_enc_fh *fh = priv;
+ struct solo_enc_dev *solo_enc = fh->enc;
+ struct solo6010_dev *solo_dev = solo_enc->solo_dev;
+ struct v4l2_captureparm *cp = &sp->parm.capture;
+
+ spin_lock(&solo_enc->lock);
+
+ if (atomic_read(&solo_enc->readers) > 0) {
+ spin_unlock(&solo_enc->lock);
+ return -EBUSY;
+ }
+
+ if ((cp->timeperframe.numerator == 0) ||
+ (cp->timeperframe.denominator == 0)) {
+ /* reset framerate */
+ cp->timeperframe.numerator = 1;
+ cp->timeperframe.denominator = solo_dev->fps;
+ }
+
+ if (cp->timeperframe.denominator != solo_dev->fps)
+ cp->timeperframe.denominator = solo_dev->fps;
+
+ if (cp->timeperframe.numerator > 15)
+ cp->timeperframe.numerator = 15;
+
+ solo_enc->interval = cp->timeperframe.numerator;
+
+ cp->capability = V4L2_CAP_TIMEPERFRAME;
+
+ solo_enc->gop = max(solo_dev->fps / solo_enc->interval, 1);
+ solo_update_mode(solo_enc);
+
+ spin_unlock(&solo_enc->lock);
+
+ return 0;
+}
+
+static int solo_queryctrl(struct file *file, void *priv,
+ struct v4l2_queryctrl *qc)
+{
+ struct solo_enc_fh *fh = priv;
+ struct solo_enc_dev *solo_enc = fh->enc;
+ struct solo6010_dev *solo_dev = solo_enc->solo_dev;
+
+ qc->id = v4l2_ctrl_next(solo_ctrl_classes, qc->id);
+ if (!qc->id)
+ return -EINVAL;
+
+ switch (qc->id) {
+ case V4L2_CID_BRIGHTNESS:
+ case V4L2_CID_CONTRAST:
+ case V4L2_CID_SATURATION:
+ case V4L2_CID_HUE:
+ return v4l2_ctrl_query_fill(qc, 0x00, 0xff, 1, 0x80);
+ case V4L2_CID_SHARPNESS:
+ return v4l2_ctrl_query_fill(qc, 0x00, 0x0f, 1, 0x00);
+ case V4L2_CID_MPEG_VIDEO_ENCODING:
+ return v4l2_ctrl_query_fill(
+ qc, V4L2_MPEG_VIDEO_ENCODING_MPEG_1,
+ V4L2_MPEG_VIDEO_ENCODING_MPEG_4_AVC, 1,
+ V4L2_MPEG_VIDEO_ENCODING_MPEG_4_AVC);
+ case V4L2_CID_MPEG_VIDEO_GOP_SIZE:
+ return v4l2_ctrl_query_fill(qc, 1, 255, 1, solo_dev->fps);
+#ifdef PRIVATE_CIDS
+ case V4L2_CID_MOTION_THRESHOLD:
+ qc->flags |= V4L2_CTRL_FLAG_SLIDER;
+ qc->type = V4L2_CTRL_TYPE_INTEGER;
+ qc->minimum = 0;
+ qc->maximum = 0xffff;
+ qc->step = 1;
+ qc->default_value = SOLO_DEF_MOT_THRESH;
+ strlcpy(qc->name, "Motion Detection Threshold",
+ sizeof(qc->name));
+ return 0;
+ case V4L2_CID_MOTION_ENABLE:
+ qc->type = V4L2_CTRL_TYPE_BOOLEAN;
+ qc->minimum = 0;
+ qc->maximum = qc->step = 1;
+ qc->default_value = 0;
+ strlcpy(qc->name, "Motion Detection Enable", sizeof(qc->name));
+ return 0;
+#else
+ case V4L2_CID_MOTION_THRESHOLD:
+ return v4l2_ctrl_query_fill(qc, 0, 0xffff, 1,
+ SOLO_DEF_MOT_THRESH);
+ case V4L2_CID_MOTION_ENABLE:
+ return v4l2_ctrl_query_fill(qc, 0, 1, 1, 0);
+#endif
+ case V4L2_CID_RDS_TX_RADIO_TEXT:
+ qc->type = V4L2_CTRL_TYPE_STRING;
+ qc->minimum = 0;
+ qc->maximum = OSD_TEXT_MAX;
+ qc->step = 1;
+ qc->default_value = 0;
+ strlcpy(qc->name, "OSD Text", sizeof(qc->name));
+ return 0;
+ }
+
+ return -EINVAL;
+}
+
+static int solo_querymenu(struct file *file, void *priv,
+ struct v4l2_querymenu *qmenu)
+{
+ struct v4l2_queryctrl qctrl;
+ int err;
+
+ qctrl.id = qmenu->id;
+ if ((err = solo_queryctrl(file, priv, &qctrl)))
+ return err;
+
+ return v4l2_ctrl_query_menu(qmenu, &qctrl, NULL);
+}
+
+static int solo_g_ctrl(struct file *file, void *priv,
+ struct v4l2_control *ctrl)
+{
+ struct solo_enc_fh *fh = priv;
+ struct solo_enc_dev *solo_enc = fh->enc;
+ struct solo6010_dev *solo_dev = solo_enc->solo_dev;
+
+ switch (ctrl->id) {
+ case V4L2_CID_BRIGHTNESS:
+ case V4L2_CID_CONTRAST:
+ case V4L2_CID_SATURATION:
+ case V4L2_CID_HUE:
+ case V4L2_CID_SHARPNESS:
+ return tw28_get_ctrl_val(solo_dev, ctrl->id, solo_enc->ch,
+ &ctrl->value);
+ case V4L2_CID_MPEG_VIDEO_ENCODING:
+ ctrl->value = V4L2_MPEG_VIDEO_ENCODING_MPEG_4_AVC;
+ break;
+ case V4L2_CID_MPEG_VIDEO_GOP_SIZE:
+ ctrl->value = solo_enc->gop;
+ break;
+ case V4L2_CID_MOTION_THRESHOLD:
+ ctrl->value = solo_enc->motion_thresh;
+ break;
+ case V4L2_CID_MOTION_ENABLE:
+ ctrl->value = solo_is_motion_on(solo_enc);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int solo_s_ctrl(struct file *file, void *priv,
+ struct v4l2_control *ctrl)
+{
+ struct solo_enc_fh *fh = priv;
+ struct solo_enc_dev *solo_enc = fh->enc;
+ struct solo6010_dev *solo_dev = solo_enc->solo_dev;
+
+ switch (ctrl->id) {
+ case V4L2_CID_BRIGHTNESS:
+ case V4L2_CID_CONTRAST:
+ case V4L2_CID_SATURATION:
+ case V4L2_CID_HUE:
+ case V4L2_CID_SHARPNESS:
+ return tw28_set_ctrl_val(solo_dev, ctrl->id, solo_enc->ch,
+ ctrl->value);
+ case V4L2_CID_MPEG_VIDEO_ENCODING:
+ if (ctrl->value != V4L2_MPEG_VIDEO_ENCODING_MPEG_4_AVC)
+ return -ERANGE;
+ break;
+ case V4L2_CID_MPEG_VIDEO_GOP_SIZE:
+ if (ctrl->value < 1 || ctrl->value > 255)
+ return -ERANGE;
+ solo_enc->gop = ctrl->value;
+ solo_reg_write(solo_dev, SOLO_VE_CH_GOP(solo_enc->ch),
+ solo_enc->gop);
+ solo_reg_write(solo_dev, SOLO_VE_CH_GOP_E(solo_enc->ch),
+ solo_enc->gop);
+ break;
+ case V4L2_CID_MOTION_THRESHOLD:
+ /* TODO accept value on lower 16-bits and use high
+ * 16-bits to assign the value to a specific block */
+ if (ctrl->value < 0 || ctrl->value > 0xffff)
+ return -ERANGE;
+ solo_enc->motion_thresh = ctrl->value;
+ solo_set_motion_threshold(solo_dev, solo_enc->ch, ctrl->value);
+ break;
+ case V4L2_CID_MOTION_ENABLE:
+ solo_motion_toggle(solo_enc, ctrl->value);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int solo_s_ext_ctrls(struct file *file, void *priv,
+ struct v4l2_ext_controls *ctrls)
+{
+ struct solo_enc_fh *fh = priv;
+ struct solo_enc_dev *solo_enc = fh->enc;
+ int i;
+
+ for (i = 0; i < ctrls->count; i++) {
+ struct v4l2_ext_control *ctrl = (ctrls->controls + i);
+ int err;
+
+ switch (ctrl->id) {
+ case V4L2_CID_RDS_TX_RADIO_TEXT:
+ if (ctrl->size - 1 > OSD_TEXT_MAX)
+ err = -ERANGE;
+ else {
+ err = copy_from_user(solo_enc->osd_text,
+ ctrl->string,
+ OSD_TEXT_MAX);
+ solo_enc->osd_text[OSD_TEXT_MAX] = '\0';
+ if (!err)
+ err = solo_osd_print(solo_enc);
+ }
+ break;
+ default:
+ err = -EINVAL;
+ }
+
+ if (err < 0) {
+ ctrls->error_idx = i;
+ return err;
+ }
+ }
+
+ return 0;
+}
+
+static int solo_g_ext_ctrls(struct file *file, void *priv,
+ struct v4l2_ext_controls *ctrls)
+{
+ struct solo_enc_fh *fh = priv;
+ struct solo_enc_dev *solo_enc = fh->enc;
+ int i;
+
+ for (i = 0; i < ctrls->count; i++) {
+ struct v4l2_ext_control *ctrl = (ctrls->controls + i);
+ int err;
+
+ switch (ctrl->id) {
+ case V4L2_CID_RDS_TX_RADIO_TEXT:
+ if (ctrl->size < OSD_TEXT_MAX) {
+ ctrl->size = OSD_TEXT_MAX;
+ err = -ENOSPC;
+ } else {
+ err = copy_to_user(ctrl->string,
+ solo_enc->osd_text,
+ OSD_TEXT_MAX);
+ }
+ break;
+ default:
+ err = -EINVAL;
+ }
+
+ if (err < 0) {
+ ctrls->error_idx = i;
+ return err;
+ }
+ }
+
+ return 0;
+}
+
+static const struct v4l2_file_operations solo_enc_fops = {
+ .owner = THIS_MODULE,
+ .open = solo_enc_open,
+ .release = solo_enc_release,
+ .read = solo_enc_read,
+ .poll = solo_enc_poll,
+ .mmap = solo_enc_mmap,
+ .ioctl = video_ioctl2,
+};
+
+static const struct v4l2_ioctl_ops solo_enc_ioctl_ops = {
+ .vidioc_querycap = solo_enc_querycap,
+ .vidioc_s_std = solo_enc_s_std,
+ /* Input callbacks */
+ .vidioc_enum_input = solo_enc_enum_input,
+ .vidioc_s_input = solo_enc_set_input,
+ .vidioc_g_input = solo_enc_get_input,
+ /* Video capture format callbacks */
+ .vidioc_enum_fmt_vid_cap = solo_enc_enum_fmt_cap,
+ .vidioc_try_fmt_vid_cap = solo_enc_try_fmt_cap,
+ .vidioc_s_fmt_vid_cap = solo_enc_set_fmt_cap,
+ .vidioc_g_fmt_vid_cap = solo_enc_get_fmt_cap,
+ /* Streaming I/O */
+ .vidioc_reqbufs = solo_enc_reqbufs,
+ .vidioc_querybuf = solo_enc_querybuf,
+ .vidioc_qbuf = solo_enc_qbuf,
+ .vidioc_dqbuf = solo_enc_dqbuf,
+ .vidioc_streamon = solo_enc_streamon,
+ .vidioc_streamoff = solo_enc_streamoff,
+ /* Frame size and interval */
+ .vidioc_enum_framesizes = solo_enum_framesizes,
+ .vidioc_enum_frameintervals = solo_enum_frameintervals,
+ /* Video capture parameters */
+ .vidioc_s_parm = solo_s_parm,
+ .vidioc_g_parm = solo_g_parm,
+ /* Controls */
+ .vidioc_queryctrl = solo_queryctrl,
+ .vidioc_querymenu = solo_querymenu,
+ .vidioc_g_ctrl = solo_g_ctrl,
+ .vidioc_s_ctrl = solo_s_ctrl,
+ .vidioc_g_ext_ctrls = solo_g_ext_ctrls,
+ .vidioc_s_ext_ctrls = solo_s_ext_ctrls,
+};
+
+static struct video_device solo_enc_template = {
+ .name = SOLO6010_NAME,
+ .fops = &solo_enc_fops,
+ .ioctl_ops = &solo_enc_ioctl_ops,
+ .minor = -1,
+ .release = video_device_release,
+
+ .tvnorms = V4L2_STD_NTSC_M | V4L2_STD_PAL_M,
+ .current_norm = V4L2_STD_NTSC_M,
+};
+
+static struct solo_enc_dev *solo_enc_alloc(struct solo6010_dev *solo_dev, u8 ch)
+{
+ struct solo_enc_dev *solo_enc;
+ int ret;
+
+ solo_enc = kzalloc(sizeof(*solo_enc), GFP_KERNEL);
+ if (!solo_enc)
+ return ERR_PTR(-ENOMEM);
+
+ solo_enc->vfd = video_device_alloc();
+ if (!solo_enc->vfd) {
+ kfree(solo_enc);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ solo_enc->solo_dev = solo_dev;
+ solo_enc->ch = ch;
+
+ *solo_enc->vfd = solo_enc_template;
+ solo_enc->vfd->parent = &solo_dev->pdev->dev;
+ ret = video_register_device(solo_enc->vfd, VFL_TYPE_GRABBER,
+ video_nr);
+ if (ret < 0) {
+ video_device_release(solo_enc->vfd);
+ kfree(solo_enc);
+ return ERR_PTR(ret);
+ }
+
+ video_set_drvdata(solo_enc->vfd, solo_enc);
+
+ snprintf(solo_enc->vfd->name, sizeof(solo_enc->vfd->name),
+ "%s-enc (%i/%i)", SOLO6010_NAME, solo_dev->vfd->num,
+ solo_enc->vfd->num);
+
+ if (video_nr >= 0)
+ video_nr++;
+
+ spin_lock_init(&solo_enc->lock);
+ init_waitqueue_head(&solo_enc->thread_wait);
+ atomic_set(&solo_enc->readers, 0);
+
+ solo_enc->qp = SOLO_DEFAULT_QP;
+ solo_enc->gop = solo_dev->fps;
+ solo_enc->interval = 1;
+ solo_enc->mode = SOLO_ENC_MODE_CIF;
+ solo_enc->motion_thresh = SOLO_DEF_MOT_THRESH;
+
+ spin_lock(&solo_enc->lock);
+ solo_update_mode(solo_enc);
+ spin_unlock(&solo_enc->lock);
+
+ return solo_enc;
+}
+
+static void solo_enc_free(struct solo_enc_dev *solo_enc)
+{
+ if (solo_enc == NULL)
+ return;
+
+ video_unregister_device(solo_enc->vfd);
+ kfree(solo_enc);
+}
+
+int solo_enc_v4l2_init(struct solo6010_dev *solo_dev)
+{
+ int i;
+
+ for (i = 0; i < solo_dev->nr_chans; i++) {
+ solo_dev->v4l2_enc[i] = solo_enc_alloc(solo_dev, i);
+ if (IS_ERR(solo_dev->v4l2_enc[i]))
+ break;
+ }
+
+ if (i != solo_dev->nr_chans) {
+ int ret = PTR_ERR(solo_dev->v4l2_enc[i]);
+ while (i--)
+ solo_enc_free(solo_dev->v4l2_enc[i]);
+ return ret;
+ }
+
+ /* D1@MAX-FPS * 4 */
+ solo_dev->enc_bw_remain = solo_dev->fps * 4 * 4;
+
+ dev_info(&solo_dev->pdev->dev, "Encoders as /dev/video%d-%d\n",
+ solo_dev->v4l2_enc[0]->vfd->num,
+ solo_dev->v4l2_enc[solo_dev->nr_chans - 1]->vfd->num);
+
+ return 0;
+}
+
+void solo_enc_v4l2_exit(struct solo6010_dev *solo_dev)
+{
+ int i;
+
+ solo6010_irq_off(solo_dev, SOLO_IRQ_MOTION);
+
+ for (i = 0; i < solo_dev->nr_chans; i++)
+ solo_enc_free(solo_dev->v4l2_enc[i]);
+}
diff --git a/drivers/staging/solo6x10/solo6010-v4l2.c b/drivers/staging/solo6x10/solo6010-v4l2.c
new file mode 100644
index 00000000000..9537cc6ee3b
--- /dev/null
+++ b/drivers/staging/solo6x10/solo6010-v4l2.c
@@ -0,0 +1,859 @@
+/*
+ * Copyright (C) 2010 Bluecherry, LLC www.bluecherrydvr.com
+ * Copyright (C) 2010 Ben Collins <bcollins@bluecherry.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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/kthread.h>
+#include <linux/freezer.h>
+
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-common.h>
+#include <media/videobuf-dma-contig.h>
+
+#include "solo6010.h"
+#include "solo6010-tw28.h"
+
+#define SOLO_HW_BPL 2048
+#define SOLO_DISP_PIX_FIELD V4L2_FIELD_INTERLACED
+#define SOLO_DISP_BUF_SIZE (64 * 1024) // 64k
+
+/* Image size is two fields, SOLO_HW_BPL is one horizontal line */
+#define solo_vlines(__solo) (__solo->video_vsize * 2)
+#define solo_image_size(__solo) (solo_bytesperline(__solo) * \
+ solo_vlines(__solo))
+#define solo_bytesperline(__solo) (__solo->video_hsize * 2)
+
+#define MIN_VID_BUFFERS 4
+
+/* Simple file handle */
+struct solo_filehandle {
+ struct solo6010_dev *solo_dev;
+ struct videobuf_queue vidq;
+ struct task_struct *kthread;
+ spinlock_t slock;
+ int old_write;
+ struct list_head vidq_active;
+};
+
+unsigned video_nr = -1;
+module_param(video_nr, uint, 0644);
+MODULE_PARM_DESC(video_nr, "videoX start number, -1 is autodetect (default)");
+
+static void erase_on(struct solo6010_dev *solo_dev)
+{
+ solo_reg_write(solo_dev, SOLO_VO_DISP_ERASE, SOLO_VO_DISP_ERASE_ON);
+ solo_dev->erasing = 1;
+ solo_dev->frame_blank = 0;
+}
+
+static int erase_off(struct solo6010_dev *solo_dev)
+{
+ if (!solo_dev->erasing)
+ return 0;
+
+ /* First time around, assert erase off */
+ if (!solo_dev->frame_blank)
+ solo_reg_write(solo_dev, SOLO_VO_DISP_ERASE, 0);
+ /* Keep the erasing flag on for 8 frames minimum */
+ if (solo_dev->frame_blank++ >= 8)
+ solo_dev->erasing = 0;
+
+ return 1;
+}
+
+void solo_video_in_isr(struct solo6010_dev *solo_dev)
+{
+ solo_reg_write(solo_dev, SOLO_IRQ_STAT, SOLO_IRQ_VIDEO_IN);
+ wake_up_interruptible(&solo_dev->disp_thread_wait);
+}
+
+static void solo_win_setup(struct solo6010_dev *solo_dev, u8 ch,
+ int sx, int sy, int ex, int ey, int scale)
+{
+ if (ch >= solo_dev->nr_chans)
+ return;
+
+ /* Here, we just keep window/channel the same */
+ solo_reg_write(solo_dev, SOLO_VI_WIN_CTRL0(ch),
+ SOLO_VI_WIN_CHANNEL(ch) |
+ SOLO_VI_WIN_SX(sx) |
+ SOLO_VI_WIN_EX(ex) |
+ SOLO_VI_WIN_SCALE(scale));
+
+ solo_reg_write(solo_dev, SOLO_VI_WIN_CTRL1(ch),
+ SOLO_VI_WIN_SY(sy) |
+ SOLO_VI_WIN_EY(ey));
+}
+
+static int solo_v4l2_ch_ext_4up(struct solo6010_dev *solo_dev, u8 idx, int on)
+{
+ u8 ch = idx * 4;
+
+ if (ch >= solo_dev->nr_chans)
+ return -EINVAL;
+
+ if (!on) {
+ u8 i;
+ for (i = ch; i < ch + 4; i++)
+ solo_win_setup(solo_dev, i, solo_dev->video_hsize,
+ solo_vlines(solo_dev),
+ solo_dev->video_hsize,
+ solo_vlines(solo_dev), 0);
+ return 0;
+ }
+
+ /* Row 1 */
+ solo_win_setup(solo_dev, ch, 0, 0, solo_dev->video_hsize / 2,
+ solo_vlines(solo_dev) / 2, 3);
+ solo_win_setup(solo_dev, ch + 1, solo_dev->video_hsize / 2, 0,
+ solo_dev->video_hsize, solo_vlines(solo_dev) / 2, 3);
+ /* Row 2 */
+ solo_win_setup(solo_dev, ch + 2, 0, solo_vlines(solo_dev) / 2,
+ solo_dev->video_hsize / 2, solo_vlines(solo_dev), 3);
+ solo_win_setup(solo_dev, ch + 3, solo_dev->video_hsize / 2,
+ solo_vlines(solo_dev) / 2, solo_dev->video_hsize,
+ solo_vlines(solo_dev), 3);
+
+ return 0;
+}
+
+static int solo_v4l2_ch_ext_16up(struct solo6010_dev *solo_dev, int on)
+{
+ int sy, ysize, hsize, i;
+
+ if (!on) {
+ for (i = 0; i < 16; i++)
+ solo_win_setup(solo_dev, i, solo_dev->video_hsize,
+ solo_vlines(solo_dev),
+ solo_dev->video_hsize,
+ solo_vlines(solo_dev), 0);
+ return 0;
+ }
+
+ ysize = solo_vlines(solo_dev) / 4;
+ hsize = solo_dev->video_hsize / 4;
+
+ for (sy = 0, i = 0; i < 4; i++, sy += ysize) {
+ solo_win_setup(solo_dev, i * 4, 0, sy, hsize,
+ sy + ysize, 5);
+ solo_win_setup(solo_dev, (i * 4) + 1, hsize, sy,
+ hsize * 2, sy + ysize, 5);
+ solo_win_setup(solo_dev, (i * 4) + 2, hsize * 2, sy,
+ hsize * 3, sy + ysize, 5);
+ solo_win_setup(solo_dev, (i * 4) + 3, hsize * 3, sy,
+ solo_dev->video_hsize, sy + ysize, 5);
+ }
+
+ return 0;
+}
+
+static int solo_v4l2_ch(struct solo6010_dev *solo_dev, u8 ch, int on)
+{
+ u8 ext_ch;
+
+ if (ch < solo_dev->nr_chans) {
+ solo_win_setup(solo_dev, ch, on ? 0 : solo_dev->video_hsize,
+ on ? 0 : solo_vlines(solo_dev),
+ solo_dev->video_hsize, solo_vlines(solo_dev),
+ on ? 1 : 0);
+ return 0;
+ }
+
+ if (ch >= solo_dev->nr_chans + solo_dev->nr_ext)
+ return -EINVAL;
+
+ ext_ch = ch - solo_dev->nr_chans;
+
+ /* 4up's first */
+ if (ext_ch < 4)
+ return solo_v4l2_ch_ext_4up(solo_dev, ext_ch, on);
+
+ /* Remaining case is 16up for 16-port */
+ return solo_v4l2_ch_ext_16up(solo_dev, on);
+}
+
+static int solo_v4l2_set_ch(struct solo6010_dev *solo_dev, u8 ch)
+{
+ if (ch >= solo_dev->nr_chans + solo_dev->nr_ext)
+ return -EINVAL;
+
+ erase_on(solo_dev);
+
+ solo_v4l2_ch(solo_dev, solo_dev->cur_disp_ch, 0);
+ solo_v4l2_ch(solo_dev, ch, 1);
+
+ solo_dev->cur_disp_ch = ch;
+
+ return 0;
+}
+
+static void solo_fillbuf(struct solo_filehandle *fh,
+ struct videobuf_buffer *vb)
+{
+ struct solo6010_dev *solo_dev = fh->solo_dev;
+ dma_addr_t vbuf;
+ unsigned int fdma_addr;
+ int frame_size;
+ int error = 1;
+ int i;
+
+ if (!(vbuf = videobuf_to_dma_contig(vb)))
+ goto finish_buf;
+
+ if (erase_off(solo_dev)) {
+ void *p = videobuf_queue_to_vaddr(&fh->vidq, vb);
+ int image_size = solo_image_size(solo_dev);
+ for (i = 0; i < image_size; i += 2) {
+ ((u8 *)p)[i] = 0x80;
+ ((u8 *)p)[i + 1] = 0x00;
+ }
+ error = 0;
+ goto finish_buf;
+ }
+
+ frame_size = SOLO_HW_BPL * solo_vlines(solo_dev);
+ fdma_addr = SOLO_DISP_EXT_ADDR(solo_dev) + (fh->old_write * frame_size);
+
+ for (i = 0; i < frame_size / SOLO_DISP_BUF_SIZE; i++) {
+ int j;
+ for (j = 0; j < (SOLO_DISP_BUF_SIZE / SOLO_HW_BPL); j++) {
+ if (solo_p2m_dma_t(solo_dev, SOLO_P2M_DMA_ID_DISP, 0,
+ vbuf, fdma_addr + (j * SOLO_HW_BPL),
+ solo_bytesperline(solo_dev)))
+ goto finish_buf;
+ vbuf += solo_bytesperline(solo_dev);
+ }
+ fdma_addr += SOLO_DISP_BUF_SIZE;
+ }
+ error = 0;
+
+finish_buf:
+ if (error) {
+ vb->state = VIDEOBUF_ERROR;
+ } else {
+ vb->state = VIDEOBUF_DONE;
+ vb->field_count++;
+ do_gettimeofday(&vb->ts);
+ }
+
+ wake_up(&vb->done);
+
+ return;
+}
+
+static void solo_thread_try(struct solo_filehandle *fh)
+{
+ struct videobuf_buffer *vb;
+ unsigned int cur_write;
+
+ for (;;) {
+ spin_lock(&fh->slock);
+
+ if (list_empty(&fh->vidq_active))
+ break;
+
+ vb = list_first_entry(&fh->vidq_active, struct videobuf_buffer,
+ queue);
+
+ if (!waitqueue_active(&vb->done))
+ break;
+
+ cur_write = SOLO_VI_STATUS0_PAGE(solo_reg_read(fh->solo_dev,
+ SOLO_VI_STATUS0));
+ if (cur_write == fh->old_write)
+ break;
+
+ fh->old_write = cur_write;
+ list_del(&vb->queue);
+
+ spin_unlock(&fh->slock);
+
+ solo_fillbuf(fh, vb);
+ }
+
+ assert_spin_locked(&fh->slock);
+ spin_unlock(&fh->slock);
+}
+
+static int solo_thread(void *data)
+{
+ struct solo_filehandle *fh = data;
+ struct solo6010_dev *solo_dev = fh->solo_dev;
+ DECLARE_WAITQUEUE(wait, current);
+
+ set_freezable();
+ add_wait_queue(&solo_dev->disp_thread_wait, &wait);
+
+ for (;;) {
+ long timeout = schedule_timeout_interruptible(HZ);
+ if (timeout == -ERESTARTSYS || kthread_should_stop())
+ break;
+ solo_thread_try(fh);
+ try_to_freeze();
+ }
+
+ remove_wait_queue(&solo_dev->disp_thread_wait, &wait);
+
+ return 0;
+}
+
+static int solo_start_thread(struct solo_filehandle *fh)
+{
+ fh->kthread = kthread_run(solo_thread, fh, SOLO6010_NAME "_disp");
+
+ if (IS_ERR(fh->kthread))
+ return PTR_ERR(fh->kthread);
+
+ return 0;
+}
+
+static void solo_stop_thread(struct solo_filehandle *fh)
+{
+ if (fh->kthread) {
+ kthread_stop(fh->kthread);
+ fh->kthread = NULL;
+ }
+}
+
+static int solo_buf_setup(struct videobuf_queue *vq, unsigned int *count,
+ unsigned int *size)
+{
+ struct solo_filehandle *fh = vq->priv_data;
+ struct solo6010_dev *solo_dev = fh->solo_dev;
+
+ *size = solo_image_size(solo_dev);
+
+ if (*count < MIN_VID_BUFFERS)
+ *count = MIN_VID_BUFFERS;
+
+ return 0;
+}
+
+static int solo_buf_prepare(struct videobuf_queue *vq,
+ struct videobuf_buffer *vb, enum v4l2_field field)
+{
+ struct solo_filehandle *fh = vq->priv_data;
+ struct solo6010_dev *solo_dev = fh->solo_dev;
+
+ vb->size = solo_image_size(solo_dev);
+ if (vb->baddr != 0 && vb->bsize < vb->size)
+ return -EINVAL;
+
+ /* XXX: These properties only change when queue is idle */
+ vb->width = solo_dev->video_hsize;
+ vb->height = solo_vlines(solo_dev);
+ vb->bytesperline = solo_bytesperline(solo_dev);
+ vb->field = field;
+
+ if (vb->state == VIDEOBUF_NEEDS_INIT) {
+ int rc = videobuf_iolock(vq, vb, NULL);
+ if (rc < 0) {
+ videobuf_dma_contig_free(vq, vb);
+ vb->state = VIDEOBUF_NEEDS_INIT;
+ return rc;
+ }
+ }
+ vb->state = VIDEOBUF_PREPARED;
+
+ return 0;
+}
+
+static void solo_buf_queue(struct videobuf_queue *vq,
+ struct videobuf_buffer *vb)
+{
+ struct solo_filehandle *fh = vq->priv_data;
+ struct solo6010_dev *solo_dev = fh->solo_dev;
+
+ vb->state = VIDEOBUF_QUEUED;
+ list_add_tail(&vb->queue, &fh->vidq_active);
+ wake_up_interruptible(&solo_dev->disp_thread_wait);
+}
+
+static void solo_buf_release(struct videobuf_queue *vq,
+ struct videobuf_buffer *vb)
+{
+ videobuf_dma_contig_free(vq, vb);
+ vb->state = VIDEOBUF_NEEDS_INIT;
+}
+
+static struct videobuf_queue_ops solo_video_qops = {
+ .buf_setup = solo_buf_setup,
+ .buf_prepare = solo_buf_prepare,
+ .buf_queue = solo_buf_queue,
+ .buf_release = solo_buf_release,
+};
+
+static unsigned int solo_v4l2_poll(struct file *file,
+ struct poll_table_struct *wait)
+{
+ struct solo_filehandle *fh = file->private_data;
+
+ return videobuf_poll_stream(file, &fh->vidq, wait);
+}
+
+static int solo_v4l2_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ struct solo_filehandle *fh = file->private_data;
+
+ return videobuf_mmap_mapper(&fh->vidq, vma);
+}
+
+static int solo_v4l2_open(struct file *file)
+{
+ struct solo6010_dev *solo_dev = video_drvdata(file);
+ struct solo_filehandle *fh;
+ int ret;
+
+ if ((fh = kzalloc(sizeof(*fh), GFP_KERNEL)) == NULL)
+ return -ENOMEM;
+
+ spin_lock_init(&fh->slock);
+ INIT_LIST_HEAD(&fh->vidq_active);
+ fh->solo_dev = solo_dev;
+ file->private_data = fh;
+
+ if ((ret = solo_start_thread(fh))) {
+ kfree(fh);
+ return ret;
+ }
+
+ videobuf_queue_dma_contig_init(&fh->vidq, &solo_video_qops,
+ &solo_dev->pdev->dev, &fh->slock,
+ V4L2_BUF_TYPE_VIDEO_CAPTURE,
+ SOLO_DISP_PIX_FIELD,
+ sizeof(struct videobuf_buffer), fh);
+
+ return 0;
+}
+
+static ssize_t solo_v4l2_read(struct file *file, char __user *data,
+ size_t count, loff_t *ppos)
+{
+ struct solo_filehandle *fh = file->private_data;
+
+ return videobuf_read_stream(&fh->vidq, data, count, ppos, 0,
+ file->f_flags & O_NONBLOCK);
+}
+
+static int solo_v4l2_release(struct file *file)
+{
+ struct solo_filehandle *fh = file->private_data;
+
+ videobuf_stop(&fh->vidq);
+ videobuf_mmap_free(&fh->vidq);
+ solo_stop_thread(fh);
+ kfree(fh);
+
+ return 0;
+}
+
+static int solo_querycap(struct file *file, void *priv,
+ struct v4l2_capability *cap)
+{
+ struct solo_filehandle *fh = priv;
+ struct solo6010_dev *solo_dev = fh->solo_dev;
+
+ strcpy(cap->driver, SOLO6010_NAME);
+ strcpy(cap->card, "Softlogic 6010");
+ snprintf(cap->bus_info, sizeof(cap->bus_info), "PCI %s",
+ pci_name(solo_dev->pdev));
+ cap->version = SOLO6010_VER_NUM;
+ cap->capabilities = V4L2_CAP_VIDEO_CAPTURE |
+ V4L2_CAP_READWRITE |
+ V4L2_CAP_STREAMING;
+ return 0;
+}
+
+static int solo_enum_ext_input(struct solo6010_dev *solo_dev,
+ struct v4l2_input *input)
+{
+ static const char *dispnames_1[] = { "4UP" };
+ static const char *dispnames_2[] = { "4UP-1", "4UP-2" };
+ static const char *dispnames_5[] = {
+ "4UP-1", "4UP-2", "4UP-3", "4UP-4", "16UP"
+ };
+ const char **dispnames;
+
+ if (input->index >= (solo_dev->nr_chans + solo_dev->nr_ext))
+ return -EINVAL;
+
+ if (solo_dev->nr_ext == 5)
+ dispnames = dispnames_5;
+ else if (solo_dev->nr_ext == 2)
+ dispnames = dispnames_2;
+ else
+ dispnames = dispnames_1;
+
+ snprintf(input->name, sizeof(input->name), "Multi %s",
+ dispnames[input->index - solo_dev->nr_chans]);
+
+ return 0;
+}
+
+static int solo_enum_input(struct file *file, void *priv,
+ struct v4l2_input *input)
+{
+ struct solo_filehandle *fh = priv;
+ struct solo6010_dev *solo_dev = fh->solo_dev;
+
+ if (input->index >= solo_dev->nr_chans) {
+ int ret = solo_enum_ext_input(solo_dev, input);
+ if (ret < 0)
+ return ret;
+ } else {
+ snprintf(input->name, sizeof(input->name), "Camera %d",
+ input->index + 1);
+
+ /* We can only check this for normal inputs */
+ if (!tw28_get_video_status(solo_dev, input->index))
+ input->status = V4L2_IN_ST_NO_SIGNAL;
+ }
+
+ input->type = V4L2_INPUT_TYPE_CAMERA;
+
+ if (solo_dev->video_type == SOLO_VO_FMT_TYPE_NTSC)
+ input->std = V4L2_STD_NTSC_M;
+ else
+ input->std = V4L2_STD_PAL_M;
+
+ return 0;
+}
+
+static int solo_set_input(struct file *file, void *priv, unsigned int index)
+{
+ struct solo_filehandle *fh = priv;
+
+ return solo_v4l2_set_ch(fh->solo_dev, index);
+}
+
+static int solo_get_input(struct file *file, void *priv, unsigned int *index)
+{
+ struct solo_filehandle *fh = priv;
+
+ *index = fh->solo_dev->cur_disp_ch;
+
+ return 0;
+}
+
+static int solo_enum_fmt_cap(struct file *file, void *priv,
+ struct v4l2_fmtdesc *f)
+{
+ if (f->index)
+ return -EINVAL;
+
+ f->pixelformat = V4L2_PIX_FMT_UYVY;
+ strlcpy(f->description, "UYUV 4:2:2 Packed", sizeof(f->description));
+
+ return 0;
+}
+
+static int solo_try_fmt_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct solo_filehandle *fh = priv;
+ struct solo6010_dev *solo_dev = fh->solo_dev;
+ struct v4l2_pix_format *pix = &f->fmt.pix;
+ int image_size = solo_image_size(solo_dev);
+
+ /* Check supported sizes */
+ if (pix->width != solo_dev->video_hsize)
+ pix->width = solo_dev->video_hsize;
+ if (pix->height != solo_vlines(solo_dev))
+ pix->height = solo_vlines(solo_dev);
+ if (pix->sizeimage != image_size)
+ pix->sizeimage = image_size;
+
+ /* Check formats */
+ if (pix->field == V4L2_FIELD_ANY)
+ pix->field = SOLO_DISP_PIX_FIELD;
+
+ if (pix->pixelformat != V4L2_PIX_FMT_UYVY ||
+ pix->field != SOLO_DISP_PIX_FIELD ||
+ pix->colorspace != V4L2_COLORSPACE_SMPTE170M)
+ return -EINVAL;
+
+ return 0;
+}
+
+static int solo_set_fmt_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct solo_filehandle *fh = priv;
+
+ if (videobuf_queue_is_busy(&fh->vidq))
+ return -EBUSY;
+
+ /* For right now, if it doesn't match our running config,
+ * then fail */
+ return solo_try_fmt_cap(file, priv, f);
+}
+
+static int solo_get_fmt_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct solo_filehandle *fh = priv;
+ struct solo6010_dev *solo_dev = fh->solo_dev;
+ struct v4l2_pix_format *pix = &f->fmt.pix;
+
+ pix->width = solo_dev->video_hsize;
+ pix->height = solo_vlines(solo_dev);
+ pix->pixelformat = V4L2_PIX_FMT_UYVY;
+ pix->field = SOLO_DISP_PIX_FIELD;
+ pix->sizeimage = solo_image_size(solo_dev);
+ pix->colorspace = V4L2_COLORSPACE_SMPTE170M;
+ pix->bytesperline = solo_bytesperline(solo_dev);
+
+ return 0;
+}
+
+static int solo_reqbufs(struct file *file, void *priv,
+ struct v4l2_requestbuffers *req)
+{
+ struct solo_filehandle *fh = priv;
+
+ return videobuf_reqbufs(&fh->vidq, req);
+}
+
+static int solo_querybuf(struct file *file, void *priv, struct v4l2_buffer *buf)
+{
+ struct solo_filehandle *fh = priv;
+
+ return videobuf_querybuf(&fh->vidq, buf);
+}
+
+static int solo_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
+{
+ struct solo_filehandle *fh = priv;
+
+ return videobuf_qbuf(&fh->vidq, buf);
+}
+
+static int solo_dqbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
+{
+ struct solo_filehandle *fh = priv;
+
+ return videobuf_dqbuf(&fh->vidq, buf, file->f_flags & O_NONBLOCK);
+}
+
+static int solo_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
+{
+ struct solo_filehandle *fh = priv;
+
+ if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ return videobuf_streamon(&fh->vidq);
+}
+
+static int solo_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
+{
+ struct solo_filehandle *fh = priv;
+
+ if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ return videobuf_streamoff(&fh->vidq);
+}
+
+static int solo_s_std(struct file *file, void *priv, v4l2_std_id *i)
+{
+ return 0;
+}
+
+static const u32 solo_motion_ctrls[] = {
+ V4L2_CID_MOTION_TRACE,
+ 0
+};
+
+static const u32 *solo_ctrl_classes[] = {
+ solo_motion_ctrls,
+ NULL
+};
+
+static int solo_disp_queryctrl(struct file *file, void *priv,
+ struct v4l2_queryctrl *qc)
+{
+ qc->id = v4l2_ctrl_next(solo_ctrl_classes, qc->id);
+ if (!qc->id)
+ return -EINVAL;
+
+ switch (qc->id) {
+#ifdef PRIVATE_CIDS
+ case V4L2_CID_MOTION_TRACE:
+ qc->type = V4L2_CTRL_TYPE_BOOLEAN;
+ qc->minimum = 0;
+ qc->maximum = qc->step = 1;
+ qc->default_value = 0;
+ strlcpy(qc->name, "Motion Detection Trace", sizeof(qc->name));
+ return 0;
+#else
+ case V4L2_CID_MOTION_TRACE:
+ return v4l2_ctrl_query_fill(qc, 0, 1, 1, 0);
+#endif
+ }
+ return -EINVAL;
+}
+
+static int solo_disp_g_ctrl(struct file *file, void *priv,
+ struct v4l2_control *ctrl)
+{
+ struct solo_filehandle *fh = priv;
+ struct solo6010_dev *solo_dev = fh->solo_dev;
+
+ switch (ctrl->id) {
+ case V4L2_CID_MOTION_TRACE:
+ ctrl->value = solo_reg_read(solo_dev, SOLO_VI_MOTION_BAR)
+ ? 1 : 0;
+ return 0;
+ }
+ return -EINVAL;
+}
+
+static int solo_disp_s_ctrl(struct file *file, void *priv,
+ struct v4l2_control *ctrl)
+{
+ struct solo_filehandle *fh = priv;
+ struct solo6010_dev *solo_dev = fh->solo_dev;
+
+ switch (ctrl->id) {
+ case V4L2_CID_MOTION_TRACE:
+ if (ctrl->value) {
+ solo_reg_write(solo_dev, SOLO_VI_MOTION_BORDER,
+ SOLO_VI_MOTION_Y_ADD |
+ SOLO_VI_MOTION_Y_VALUE(0x20) |
+ SOLO_VI_MOTION_CB_VALUE(0x10) |
+ SOLO_VI_MOTION_CR_VALUE(0x10));
+ solo_reg_write(solo_dev, SOLO_VI_MOTION_BAR,
+ SOLO_VI_MOTION_CR_ADD |
+ SOLO_VI_MOTION_Y_VALUE(0x10) |
+ SOLO_VI_MOTION_CB_VALUE(0x80) |
+ SOLO_VI_MOTION_CR_VALUE(0x10));
+ } else {
+ solo_reg_write(solo_dev, SOLO_VI_MOTION_BORDER, 0);
+ solo_reg_write(solo_dev, SOLO_VI_MOTION_BAR, 0);
+ }
+ return 0;
+ }
+ return -EINVAL;
+}
+
+static const struct v4l2_file_operations solo_v4l2_fops = {
+ .owner = THIS_MODULE,
+ .open = solo_v4l2_open,
+ .release = solo_v4l2_release,
+ .read = solo_v4l2_read,
+ .poll = solo_v4l2_poll,
+ .mmap = solo_v4l2_mmap,
+ .ioctl = video_ioctl2,
+};
+
+static const struct v4l2_ioctl_ops solo_v4l2_ioctl_ops = {
+ .vidioc_querycap = solo_querycap,
+ .vidioc_s_std = solo_s_std,
+ /* Input callbacks */
+ .vidioc_enum_input = solo_enum_input,
+ .vidioc_s_input = solo_set_input,
+ .vidioc_g_input = solo_get_input,
+ /* Video capture format callbacks */
+ .vidioc_enum_fmt_vid_cap = solo_enum_fmt_cap,
+ .vidioc_try_fmt_vid_cap = solo_try_fmt_cap,
+ .vidioc_s_fmt_vid_cap = solo_set_fmt_cap,
+ .vidioc_g_fmt_vid_cap = solo_get_fmt_cap,
+ /* Streaming I/O */
+ .vidioc_reqbufs = solo_reqbufs,
+ .vidioc_querybuf = solo_querybuf,
+ .vidioc_qbuf = solo_qbuf,
+ .vidioc_dqbuf = solo_dqbuf,
+ .vidioc_streamon = solo_streamon,
+ .vidioc_streamoff = solo_streamoff,
+ /* Controls */
+ .vidioc_queryctrl = solo_disp_queryctrl,
+ .vidioc_g_ctrl = solo_disp_g_ctrl,
+ .vidioc_s_ctrl = solo_disp_s_ctrl,
+};
+
+static struct video_device solo_v4l2_template = {
+ .name = SOLO6010_NAME,
+ .fops = &solo_v4l2_fops,
+ .ioctl_ops = &solo_v4l2_ioctl_ops,
+ .minor = -1,
+ .release = video_device_release,
+
+ .tvnorms = V4L2_STD_NTSC_M | V4L2_STD_PAL_M,
+ .current_norm = V4L2_STD_NTSC_M,
+};
+
+int solo_v4l2_init(struct solo6010_dev *solo_dev)
+{
+ int ret;
+ int i;
+
+ init_waitqueue_head(&solo_dev->disp_thread_wait);
+
+ solo_dev->vfd = video_device_alloc();
+ if (!solo_dev->vfd)
+ return -ENOMEM;
+
+ *solo_dev->vfd = solo_v4l2_template;
+ solo_dev->vfd->parent = &solo_dev->pdev->dev;
+
+ ret = video_register_device(solo_dev->vfd, VFL_TYPE_GRABBER, video_nr);
+ if (ret < 0) {
+ video_device_release(solo_dev->vfd);
+ solo_dev->vfd = NULL;
+ return ret;
+ }
+
+ video_set_drvdata(solo_dev->vfd, solo_dev);
+
+ snprintf(solo_dev->vfd->name, sizeof(solo_dev->vfd->name), "%s (%i)",
+ SOLO6010_NAME, solo_dev->vfd->num);
+
+ if (video_nr >= 0)
+ video_nr++;
+
+ dev_info(&solo_dev->pdev->dev, "Display as /dev/video%d with "
+ "%d inputs (%d extended)\n", solo_dev->vfd->num,
+ solo_dev->nr_chans, solo_dev->nr_ext);
+
+ /* Cycle all the channels and clear */
+ for (i = 0; i < solo_dev->nr_chans; i++) {
+ solo_v4l2_set_ch(solo_dev, i);
+ while (erase_off(solo_dev))
+ ;// Do nothing
+ }
+
+ /* Set the default display channel */
+ solo_v4l2_set_ch(solo_dev, 0);
+ while (erase_off(solo_dev))
+ ;// Do nothing
+
+ solo6010_irq_on(solo_dev, SOLO_IRQ_VIDEO_IN);
+
+ return 0;
+}
+
+void solo_v4l2_exit(struct solo6010_dev *solo_dev)
+{
+ solo6010_irq_off(solo_dev, SOLO_IRQ_VIDEO_IN);
+ if (solo_dev->vfd) {
+ video_unregister_device(solo_dev->vfd);
+ solo_dev->vfd = NULL;
+ }
+}
diff --git a/drivers/staging/solo6x10/solo6010.h b/drivers/staging/solo6x10/solo6010.h
new file mode 100644
index 00000000000..dca8e3e1545
--- /dev/null
+++ b/drivers/staging/solo6x10/solo6010.h
@@ -0,0 +1,317 @@
+/*
+ * Copyright (C) 2010 Bluecherry, LLC www.bluecherrydvr.com
+ * Copyright (C) 2010 Ben Collins <bcollins@bluecherry.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.
+ *
+ * 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 __SOLO6010_H
+#define __SOLO6010_H
+
+#include <linux/version.h>
+#include <linux/pci.h>
+#include <linux/i2c.h>
+#include <linux/semaphore.h>
+#include <linux/mutex.h>
+#include <linux/list.h>
+#include <linux/delay.h>
+#include <linux/wait.h>
+#include <asm/io.h>
+#include <asm/atomic.h>
+
+#include <linux/videodev2.h>
+#include <media/v4l2-dev.h>
+#include <media/videobuf-core.h>
+
+#include "solo6010-registers.h"
+
+#ifndef PCI_VENDOR_ID_SOFTLOGIC
+#define PCI_VENDOR_ID_SOFTLOGIC 0x9413
+#define PCI_DEVICE_ID_SOLO6010 0x6010
+#endif
+
+#ifndef PCI_VENDOR_ID_BLUECHERRY
+#define PCI_VENDOR_ID_BLUECHERRY 0x1BB3
+/* Neugent Softlogic 6010 based cards */
+#define PCI_DEVICE_ID_NEUSOLO_4 0x4304
+#define PCI_DEVICE_ID_NEUSOLO_9 0x4309
+#define PCI_DEVICE_ID_NEUSOLO_16 0x4310
+/* Commell Softlogic 6010 based cards */
+#define PCI_DEVICE_ID_COMMSOLO_4 0x4E04
+#define PCI_DEVICE_ID_COMMSOLO_9 0x4E09
+#define PCI_DEVICE_ID_COMMSOLO_16 0x4E10
+#endif /* Bluecherry */
+
+#define SOLO6010_NAME "solo6010"
+
+#define SOLO_MAX_CHANNELS 16
+
+/* Make sure these two match */
+#define SOLO6010_VERSION "2.0.0"
+#define SOLO6010_VER_MAJOR 2
+#define SOLO6010_VER_MINOR 0
+#define SOLO6010_VER_SUB 0
+#define SOLO6010_VER_NUM \
+ KERNEL_VERSION(SOLO6010_VER_MAJOR, SOLO6010_VER_MINOR, SOLO6010_VER_SUB)
+
+/*
+ * The SOLO6010 actually has 8 i2c channels, but we only use 2.
+ * 0 - Techwell chip(s)
+ * 1 - SAA7128
+ */
+#define SOLO_I2C_ADAPTERS 2
+#define SOLO_I2C_TW 0
+#define SOLO_I2C_SAA 1
+
+/* DMA Engine setup */
+#define SOLO_NR_P2M 4
+#define SOLO_NR_P2M_DESC 256
+#define SOLO_P2M_DESC_SIZE (SOLO_NR_P2M_DESC * 16)
+/* MPEG and JPEG share the same interrupt and locks so they must be together
+ * in the same dma channel. */
+#define SOLO_P2M_DMA_ID_MP4E 0
+#define SOLO_P2M_DMA_ID_JPEG 0
+#define SOLO_P2M_DMA_ID_MP4D 1
+#define SOLO_P2M_DMA_ID_G723D 1
+#define SOLO_P2M_DMA_ID_DISP 2
+#define SOLO_P2M_DMA_ID_OSG 2
+#define SOLO_P2M_DMA_ID_G723E 3
+#define SOLO_P2M_DMA_ID_VIN 3
+
+/* Encoder standard modes */
+#define SOLO_ENC_MODE_CIF 2
+#define SOLO_ENC_MODE_HD1 1
+#define SOLO_ENC_MODE_D1 9
+
+#define SOLO_DEFAULT_GOP 30
+#define SOLO_DEFAULT_QP 3
+
+/* There is 8MB memory available for solo to buffer MPEG4 frames.
+ * This gives us 512 * 16kbyte queues. */
+#define SOLO_NR_RING_BUFS 512
+
+#define SOLO_CLOCK_MHZ 108
+
+#ifndef V4L2_BUF_FLAG_MOTION_ON
+#define V4L2_BUF_FLAG_MOTION_ON 0x0400
+#define V4L2_BUF_FLAG_MOTION_DETECTED 0x0800
+#endif
+#ifndef V4L2_CID_MOTION_ENABLE
+#define PRIVATE_CIDS
+#define V4L2_CID_MOTION_ENABLE (V4L2_CID_PRIVATE_BASE+0)
+#define V4L2_CID_MOTION_THRESHOLD (V4L2_CID_PRIVATE_BASE+1)
+#define V4L2_CID_MOTION_TRACE (V4L2_CID_PRIVATE_BASE+2)
+#endif
+
+enum SOLO_I2C_STATE {
+ IIC_STATE_IDLE,
+ IIC_STATE_START,
+ IIC_STATE_READ,
+ IIC_STATE_WRITE,
+ IIC_STATE_STOP
+};
+
+struct solo_p2m_dev {
+ struct semaphore sem;
+ struct completion completion;
+ int error;
+ u8 desc[SOLO_P2M_DESC_SIZE];
+};
+
+#define OSD_TEXT_MAX 30
+
+enum solo_enc_types {
+ SOLO_ENC_TYPE_STD,
+ SOLO_ENC_TYPE_EXT,
+};
+
+struct solo_enc_dev {
+ struct solo6010_dev *solo_dev;
+ /* V4L2 Items */
+ struct video_device *vfd;
+ /* General accounting */
+ wait_queue_head_t thread_wait;
+ spinlock_t lock;
+ atomic_t readers;
+ u8 ch;
+ u8 mode, gop, qp, interlaced, interval;
+ u8 reset_gop;
+ u8 bw_weight;
+ u8 motion_detected;
+ u16 motion_thresh;
+ u16 width;
+ u16 height;
+ char osd_text[OSD_TEXT_MAX + 1];
+};
+
+struct solo_enc_buf {
+ u8 vop;
+ u8 ch;
+ enum solo_enc_types type;
+ u32 off;
+ u32 size;
+ u32 jpeg_off;
+ u32 jpeg_size;
+ struct timeval ts;
+};
+
+/* The SOLO6010 PCI Device */
+struct solo6010_dev {
+ /* General stuff */
+ struct pci_dev *pdev;
+ u8 __iomem *reg_base;
+ int nr_chans;
+ int nr_ext;
+ u32 irq_mask;
+ u32 motion_mask;
+ spinlock_t reg_io_lock;
+
+ /* tw28xx accounting */
+ u8 tw2865, tw2864, tw2815;
+ u8 tw28_cnt;
+
+ /* i2c related items */
+ struct i2c_adapter i2c_adap[SOLO_I2C_ADAPTERS];
+ enum SOLO_I2C_STATE i2c_state;
+ struct semaphore i2c_sem;
+ int i2c_id;
+ wait_queue_head_t i2c_wait;
+ struct i2c_msg *i2c_msg;
+ unsigned int i2c_msg_num;
+ unsigned int i2c_msg_ptr;
+
+ /* P2M DMA Engine */
+ struct solo_p2m_dev p2m_dev[SOLO_NR_P2M];
+
+ /* V4L2 Display items */
+ struct video_device *vfd;
+ unsigned int erasing;
+ unsigned int frame_blank;
+ u8 cur_disp_ch;
+ wait_queue_head_t disp_thread_wait;
+
+ /* V4L2 Encoder items */
+ struct solo_enc_dev *v4l2_enc[SOLO_MAX_CHANNELS];
+ u16 enc_bw_remain;
+ /* IDX into hw mp4 encoder */
+ u8 enc_idx;
+ /* Our software ring of enc buf references */
+ u16 enc_wr_idx;
+ struct solo_enc_buf enc_buf[SOLO_NR_RING_BUFS];
+
+ /* Current video settings */
+ u32 video_type;
+ u16 video_hsize, video_vsize;
+ u16 vout_hstart, vout_vstart;
+ u16 vin_hstart, vin_vstart;
+ u8 fps;
+
+ /* Audio components */
+ struct snd_card *snd_card;
+ struct snd_pcm *snd_pcm;
+ atomic_t snd_users;
+ int g723_hw_idx;
+};
+
+static inline u32 solo_reg_read(struct solo6010_dev *solo_dev, int reg)
+{
+ unsigned long flags;
+ u32 ret;
+ u16 val;
+
+ spin_lock_irqsave(&solo_dev->reg_io_lock, flags);
+
+ ret = readl(solo_dev->reg_base + reg);
+ rmb();
+ pci_read_config_word(solo_dev->pdev, PCI_STATUS, &val);
+ rmb();
+
+ spin_unlock_irqrestore(&solo_dev->reg_io_lock, flags);
+
+ return ret;
+}
+
+static inline void solo_reg_write(struct solo6010_dev *solo_dev, int reg,
+ u32 data)
+{
+ unsigned long flags;
+ u16 val;
+
+ spin_lock_irqsave(&solo_dev->reg_io_lock, flags);
+
+ writel(data, solo_dev->reg_base + reg);
+ wmb();
+ pci_read_config_word(solo_dev->pdev, PCI_STATUS, &val);
+ rmb();
+
+ spin_unlock_irqrestore(&solo_dev->reg_io_lock, flags);
+}
+
+void solo6010_irq_on(struct solo6010_dev *solo_dev, u32 mask);
+void solo6010_irq_off(struct solo6010_dev *solo_dev, u32 mask);
+
+/* Init/exit routeines for subsystems */
+int solo_disp_init(struct solo6010_dev *solo_dev);
+void solo_disp_exit(struct solo6010_dev *solo_dev);
+
+int solo_gpio_init(struct solo6010_dev *solo_dev);
+void solo_gpio_exit(struct solo6010_dev *solo_dev);
+
+int solo_i2c_init(struct solo6010_dev *solo_dev);
+void solo_i2c_exit(struct solo6010_dev *solo_dev);
+
+int solo_p2m_init(struct solo6010_dev *solo_dev);
+void solo_p2m_exit(struct solo6010_dev *solo_dev);
+
+int solo_v4l2_init(struct solo6010_dev *solo_dev);
+void solo_v4l2_exit(struct solo6010_dev *solo_dev);
+
+int solo_enc_init(struct solo6010_dev *solo_dev);
+void solo_enc_exit(struct solo6010_dev *solo_dev);
+
+int solo_enc_v4l2_init(struct solo6010_dev *solo_dev);
+void solo_enc_v4l2_exit(struct solo6010_dev *solo_dev);
+
+int solo_g723_init(struct solo6010_dev *solo_dev);
+void solo_g723_exit(struct solo6010_dev *solo_dev);
+
+/* ISR's */
+int solo_i2c_isr(struct solo6010_dev *solo_dev);
+void solo_p2m_isr(struct solo6010_dev *solo_dev, int id);
+void solo_p2m_error_isr(struct solo6010_dev *solo_dev, u32 status);
+void solo_enc_v4l2_isr(struct solo6010_dev *solo_dev);
+void solo_g723_isr(struct solo6010_dev *solo_dev);
+void solo_motion_isr(struct solo6010_dev *solo_dev);
+void solo_video_in_isr(struct solo6010_dev *solo_dev);
+
+/* i2c read/write */
+u8 solo_i2c_readbyte(struct solo6010_dev *solo_dev, int id, u8 addr, u8 off);
+void solo_i2c_writebyte(struct solo6010_dev *solo_dev, int id, u8 addr, u8 off,
+ u8 data);
+
+/* P2M DMA */
+int solo_p2m_dma_t(struct solo6010_dev *solo_dev, u8 id, int wr,
+ dma_addr_t dma_addr, u32 ext_addr, u32 size);
+int solo_p2m_dma(struct solo6010_dev *solo_dev, u8 id, int wr,
+ void *sys_addr, u32 ext_addr, u32 size);
+
+/* Set the threshold for motion detection */
+void solo_set_motion_threshold(struct solo6010_dev *solo_dev, u8 ch, u16 val);
+#define SOLO_DEF_MOT_THRESH 0x0300
+
+/* Write text on OSD */
+int solo_osd_print(struct solo_enc_dev *solo_enc);
+
+#endif /* __SOLO6010_H */
diff --git a/drivers/staging/spectra/Kconfig b/drivers/staging/spectra/Kconfig
new file mode 100644
index 00000000000..5e2ffefb60a
--- /dev/null
+++ b/drivers/staging/spectra/Kconfig
@@ -0,0 +1,40 @@
+
+menuconfig SPECTRA
+ tristate "Denali Spectra Flash Translation Layer"
+ depends on BLOCK
+ default n
+ ---help---
+ Enable the FTL pseudo-filesystem used with the NAND Flash
+ controller on Intel Moorestown Platform to pretend to be a disk
+
+choice
+ prompt "Compile for"
+ depends on SPECTRA
+ default SPECTRA_MRST_HW
+
+config SPECTRA_MRST_HW
+ bool "Moorestown hardware mode"
+ help
+ Driver communicates with the Moorestown hardware's register interface.
+ in DMA mode.
+
+config SPECTRA_MTD
+ bool "Linux MTD mode"
+ depends on MTD
+ help
+ Driver communicates with the kernel MTD subsystem instead of its own
+ built-in hardware driver.
+
+config SPECTRA_EMU
+ bool "RAM emulator testing"
+ help
+ Driver emulates Flash on a RAM buffer and / or disk file. Useful to test the behavior of FTL layer.
+
+endchoice
+
+config SPECTRA_MRST_HW_DMA
+ bool
+ default n
+ depends on SPECTRA_MRST_HW
+ help
+ Use DMA for native hardware interface.
diff --git a/drivers/staging/spectra/Makefile b/drivers/staging/spectra/Makefile
new file mode 100644
index 00000000000..f777dfba05a
--- /dev/null
+++ b/drivers/staging/spectra/Makefile
@@ -0,0 +1,11 @@
+#
+# Makefile of Intel Moorestown NAND controller driver
+#
+
+obj-$(CONFIG_SPECTRA) += spectra.o
+spectra-y := ffsport.o flash.o lld.o
+spectra-$(CONFIG_SPECTRA_MRST_HW) += lld_nand.o
+spectra-$(CONFIG_SPECTRA_MRST_HW_DMA) += lld_cdma.o
+spectra-$(CONFIG_SPECTRA_EMU) += lld_emu.o
+spectra-$(CONFIG_SPECTRA_MTD) += lld_mtd.o
+
diff --git a/drivers/staging/spectra/README b/drivers/staging/spectra/README
new file mode 100644
index 00000000000..ecba559b899
--- /dev/null
+++ b/drivers/staging/spectra/README
@@ -0,0 +1,29 @@
+This is a driver for NAND controller of Intel Moorestown platform.
+
+This driver is a standalone linux block device driver, it acts as if it's a normal hard disk.
+It includes three layer:
+ block layer interface - file ffsport.c
+ Flash Translation Layer (FTL) - file flash.c (implement the NAND flash Translation Layer, includs address mapping, garbage collection, wear-leveling and so on)
+ Low level layer - file lld_nand.c/lld_cdma.c/lld_emu.c (which implements actual controller hardware registers access)
+
+This driver can be build as modules or build-in.
+
+Dependency:
+This driver has dependency on IA Firmware of Intel Moorestown platform.
+It need the IA Firmware to create the block table for the first time.
+And to validate this driver code without IA Firmware, you can change the
+macro AUTO_FORMAT_FLASH from 0 to 1 in file spectraswconfig.h. Thus the
+driver will erase the whole nand flash and create a new block table.
+
+TODO:
+ - Enable Command DMA feature support
+ - lower the memory footprint
+ - Remove most of the unnecessary global variables
+ - Change all the upcase variable / functions name to lowercase
+ - Some other misc bugs
+
+Please send patches to:
+ Greg Kroah-Hartman <gregkh@suse.de>
+
+And Cc to: Gao Yunpeng <yunpeng.gao@intel.com>
+
diff --git a/drivers/staging/spectra/ffsdefs.h b/drivers/staging/spectra/ffsdefs.h
new file mode 100644
index 00000000000..a9e9cd233d2
--- /dev/null
+++ b/drivers/staging/spectra/ffsdefs.h
@@ -0,0 +1,58 @@
+/*
+ * NAND Flash Controller Device Driver
+ * Copyright (c) 2009, Intel Corporation and its suppliers.
+ *
+ * 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 _FFSDEFS_
+#define _FFSDEFS_
+
+#define CLEAR 0 /*use this to clear a field instead of "fail"*/
+#define SET 1 /*use this to set a field instead of "pass"*/
+#define FAIL 1 /*failed flag*/
+#define PASS 0 /*success flag*/
+#define ERR -1 /*error flag*/
+
+#define ERASE_CMD 10
+#define WRITE_MAIN_CMD 11
+#define READ_MAIN_CMD 12
+#define WRITE_SPARE_CMD 13
+#define READ_SPARE_CMD 14
+#define WRITE_MAIN_SPARE_CMD 15
+#define READ_MAIN_SPARE_CMD 16
+#define MEMCOPY_CMD 17
+#define DUMMY_CMD 99
+
+#define EVENT_PASS 0x00
+#define EVENT_CORRECTABLE_DATA_ERROR_FIXED 0x01
+#define EVENT_UNCORRECTABLE_DATA_ERROR 0x02
+#define EVENT_TIME_OUT 0x03
+#define EVENT_PROGRAM_FAILURE 0x04
+#define EVENT_ERASE_FAILURE 0x05
+#define EVENT_MEMCOPY_FAILURE 0x06
+#define EVENT_FAIL 0x07
+
+#define EVENT_NONE 0x22
+#define EVENT_DMA_CMD_COMP 0x77
+#define EVENT_ECC_TRANSACTION_DONE 0x88
+#define EVENT_DMA_CMD_FAIL 0x99
+
+#define CMD_PASS 0
+#define CMD_FAIL 1
+#define CMD_ABORT 2
+#define CMD_NOT_DONE 3
+
+#endif /* _FFSDEFS_ */
diff --git a/drivers/staging/spectra/ffsport.c b/drivers/staging/spectra/ffsport.c
new file mode 100644
index 00000000000..d0c5c97eda3
--- /dev/null
+++ b/drivers/staging/spectra/ffsport.c
@@ -0,0 +1,827 @@
+/*
+ * NAND Flash Controller Device Driver
+ * Copyright (c) 2009, Intel Corporation and its suppliers.
+ *
+ * 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 "ffsport.h"
+#include "flash.h"
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/blkdev.h>
+#include <linux/wait.h>
+#include <linux/mutex.h>
+#include <linux/kthread.h>
+#include <linux/log2.h>
+#include <linux/init.h>
+
+/**** Helper functions used for Div, Remainder operation on u64 ****/
+
+/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
+* Function: GLOB_Calc_Used_Bits
+* Inputs: Power of 2 number
+* Outputs: Number of Used Bits
+* 0, if the argument is 0
+* Description: Calculate the number of bits used by a given power of 2 number
+* Number can be upto 32 bit
+*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/
+int GLOB_Calc_Used_Bits(u32 n)
+{
+ int tot_bits = 0;
+
+ if (n >= 1 << 16) {
+ n >>= 16;
+ tot_bits += 16;
+ }
+
+ if (n >= 1 << 8) {
+ n >>= 8;
+ tot_bits += 8;
+ }
+
+ if (n >= 1 << 4) {
+ n >>= 4;
+ tot_bits += 4;
+ }
+
+ if (n >= 1 << 2) {
+ n >>= 2;
+ tot_bits += 2;
+ }
+
+ if (n >= 1 << 1)
+ tot_bits += 1;
+
+ return ((n == 0) ? (0) : tot_bits);
+}
+
+/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
+* Function: GLOB_u64_Div
+* Inputs: Number of u64
+* A power of 2 number as Division
+* Outputs: Quotient of the Divisor operation
+* Description: It divides the address by divisor by using bit shift operation
+* (essentially without explicitely using "/").
+* Divisor is a power of 2 number and Divided is of u64
+*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/
+u64 GLOB_u64_Div(u64 addr, u32 divisor)
+{
+ return (u64)(addr >> GLOB_Calc_Used_Bits(divisor));
+}
+
+/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
+* Function: GLOB_u64_Remainder
+* Inputs: Number of u64
+* Divisor Type (1 -PageAddress, 2- BlockAddress)
+* Outputs: Remainder of the Division operation
+* Description: It calculates the remainder of a number (of u64) by
+* divisor(power of 2 number ) by using bit shifting and multiply
+* operation(essentially without explicitely using "/").
+*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/
+u64 GLOB_u64_Remainder(u64 addr, u32 divisor_type)
+{
+ u64 result = 0;
+
+ if (divisor_type == 1) { /* Remainder -- Page */
+ result = (addr >> DeviceInfo.nBitsInPageDataSize);
+ result = result * DeviceInfo.wPageDataSize;
+ } else if (divisor_type == 2) { /* Remainder -- Block */
+ result = (addr >> DeviceInfo.nBitsInBlockDataSize);
+ result = result * DeviceInfo.wBlockDataSize;
+ }
+
+ result = addr - result;
+
+ return result;
+}
+
+#define NUM_DEVICES 1
+#define PARTITIONS 8
+
+#define GLOB_SBD_NAME "nd"
+#define GLOB_SBD_IRQ_NUM (29)
+#define GLOB_VERSION "driver version 20091110"
+
+#define GLOB_SBD_IOCTL_GC (0x7701)
+#define GLOB_SBD_IOCTL_WL (0x7702)
+#define GLOB_SBD_IOCTL_FORMAT (0x7703)
+#define GLOB_SBD_IOCTL_ERASE_FLASH (0x7704)
+#define GLOB_SBD_IOCTL_FLUSH_CACHE (0x7705)
+#define GLOB_SBD_IOCTL_COPY_BLK_TABLE (0x7706)
+#define GLOB_SBD_IOCTL_COPY_WEAR_LEVELING_TABLE (0x7707)
+#define GLOB_SBD_IOCTL_GET_NAND_INFO (0x7708)
+#define GLOB_SBD_IOCTL_WRITE_DATA (0x7709)
+#define GLOB_SBD_IOCTL_READ_DATA (0x770A)
+
+static int reserved_mb = 0;
+module_param(reserved_mb, int, 0);
+MODULE_PARM_DESC(reserved_mb, "Reserved space for OS image, in MiB (default 25 MiB)");
+
+int nand_debug_level;
+module_param(nand_debug_level, int, 0644);
+MODULE_PARM_DESC(nand_debug_level, "debug level value: 1-3");
+
+MODULE_LICENSE("GPL");
+
+struct spectra_nand_dev {
+ struct pci_dev *dev;
+ u64 size;
+ u16 users;
+ spinlock_t qlock;
+ void __iomem *ioaddr; /* Mapped address */
+ struct request_queue *queue;
+ struct task_struct *thread;
+ struct gendisk *gd;
+ u8 *tmp_buf;
+};
+
+
+static int GLOB_SBD_majornum;
+
+static char *GLOB_version = GLOB_VERSION;
+
+static struct spectra_nand_dev nand_device[NUM_DEVICES];
+
+static struct mutex spectra_lock;
+
+static int res_blks_os = 1;
+
+struct spectra_indentfy_dev_tag IdentifyDeviceData;
+
+static int force_flush_cache(void)
+{
+ nand_dbg_print(NAND_DBG_DEBUG, "%s, Line %d, Function: %s\n",
+ __FILE__, __LINE__, __func__);
+
+ if (ERR == GLOB_FTL_Flush_Cache()) {
+ printk(KERN_ERR "Fail to Flush FTL Cache!\n");
+ return -EFAULT;
+ }
+#if CMD_DMA
+ if (glob_ftl_execute_cmds())
+ return -EIO;
+ else
+ return 0;
+#endif
+ return 0;
+}
+
+struct ioctl_rw_page_info {
+ u8 *data;
+ unsigned int page;
+};
+
+static int ioctl_read_page_data(unsigned long arg)
+{
+ u8 *buf;
+ struct ioctl_rw_page_info info;
+ int result = PASS;
+
+ if (copy_from_user(&info, (void __user *)arg, sizeof(info)))
+ return -EFAULT;
+
+ buf = kmalloc(IdentifyDeviceData.PageDataSize, GFP_ATOMIC);
+ if (!buf) {
+ printk(KERN_ERR "ioctl_read_page_data: "
+ "failed to allocate memory\n");
+ return -ENOMEM;
+ }
+
+ mutex_lock(&spectra_lock);
+ result = GLOB_FTL_Page_Read(buf,
+ (u64)info.page * IdentifyDeviceData.PageDataSize);
+ mutex_unlock(&spectra_lock);
+
+ if (copy_to_user((void __user *)info.data, buf,
+ IdentifyDeviceData.PageDataSize)) {
+ printk(KERN_ERR "ioctl_read_page_data: "
+ "failed to copy user data\n");
+ kfree(buf);
+ return -EFAULT;
+ }
+
+ kfree(buf);
+ return result;
+}
+
+static int ioctl_write_page_data(unsigned long arg)
+{
+ u8 *buf;
+ struct ioctl_rw_page_info info;
+ int result = PASS;
+
+ if (copy_from_user(&info, (void __user *)arg, sizeof(info)))
+ return -EFAULT;
+
+ buf = kmalloc(IdentifyDeviceData.PageDataSize, GFP_ATOMIC);
+ if (!buf) {
+ printk(KERN_ERR "ioctl_write_page_data: "
+ "failed to allocate memory\n");
+ return -ENOMEM;
+ }
+
+ if (copy_from_user(buf, (void __user *)info.data,
+ IdentifyDeviceData.PageDataSize)) {
+ printk(KERN_ERR "ioctl_write_page_data: "
+ "failed to copy user data\n");
+ kfree(buf);
+ return -EFAULT;
+ }
+
+ mutex_lock(&spectra_lock);
+ result = GLOB_FTL_Page_Write(buf,
+ (u64)info.page * IdentifyDeviceData.PageDataSize);
+ mutex_unlock(&spectra_lock);
+
+ kfree(buf);
+ return result;
+}
+
+/* Return how many blocks should be reserved for bad block replacement */
+static int get_res_blk_num_bad_blk(void)
+{
+ return IdentifyDeviceData.wDataBlockNum / 10;
+}
+
+/* Return how many blocks should be reserved for OS image */
+static int get_res_blk_num_os(void)
+{
+ u32 res_blks, blk_size;
+
+ blk_size = IdentifyDeviceData.PageDataSize *
+ IdentifyDeviceData.PagesPerBlock;
+
+ res_blks = (reserved_mb * 1024 * 1024) / blk_size;
+
+ if ((res_blks < 1) || (res_blks >= IdentifyDeviceData.wDataBlockNum))
+ res_blks = 1; /* Reserved 1 block for block table */
+
+ return res_blks;
+}
+
+static void SBD_prepare_flush(struct request_queue *q, struct request *rq)
+{
+ rq->cmd_type = REQ_TYPE_LINUX_BLOCK;
+ /* rq->timeout = 5 * HZ; */
+ rq->cmd[0] = REQ_LB_OP_FLUSH;
+}
+
+/* Transfer a full request. */
+static int do_transfer(struct spectra_nand_dev *tr, struct request *req)
+{
+ u64 start_addr, addr;
+ u32 logical_start_sect, hd_start_sect;
+ u32 nsect, hd_sects;
+ u32 rsect, tsect = 0;
+ char *buf;
+ u32 ratio = IdentifyDeviceData.PageDataSize >> 9;
+
+ start_addr = (u64)(blk_rq_pos(req)) << 9;
+ /* Add a big enough offset to prevent the OS Image from
+ * being accessed or damaged by file system */
+ start_addr += IdentifyDeviceData.PageDataSize *
+ IdentifyDeviceData.PagesPerBlock *
+ res_blks_os;
+
+ if (req->cmd_type == REQ_TYPE_LINUX_BLOCK &&
+ req->cmd[0] == REQ_LB_OP_FLUSH) {
+ if (force_flush_cache()) /* Fail to flush cache */
+ return -EIO;
+ else
+ return 0;
+ }
+
+ if (req->cmd_type != REQ_TYPE_FS)
+ return -EIO;
+
+ if (blk_rq_pos(req) + blk_rq_cur_sectors(req) > get_capacity(tr->gd)) {
+ printk(KERN_ERR "Spectra error: request over the NAND "
+ "capacity!sector %d, current_nr_sectors %d, "
+ "while capacity is %d\n",
+ (int)blk_rq_pos(req),
+ blk_rq_cur_sectors(req),
+ (int)get_capacity(tr->gd));
+ return -EIO;
+ }
+
+ logical_start_sect = start_addr >> 9;
+ hd_start_sect = logical_start_sect / ratio;
+ rsect = logical_start_sect - hd_start_sect * ratio;
+
+ addr = (u64)hd_start_sect * ratio * 512;
+ buf = req->buffer;
+ nsect = blk_rq_cur_sectors(req);
+
+ if (rsect)
+ tsect = (ratio - rsect) < nsect ? (ratio - rsect) : nsect;
+
+ switch (rq_data_dir(req)) {
+ case READ:
+ /* Read the first NAND page */
+ if (rsect) {
+ if (GLOB_FTL_Page_Read(tr->tmp_buf, addr)) {
+ printk(KERN_ERR "Error in %s, Line %d\n",
+ __FILE__, __LINE__);
+ return -EIO;
+ }
+ memcpy(buf, tr->tmp_buf + (rsect << 9), tsect << 9);
+ addr += IdentifyDeviceData.PageDataSize;
+ buf += tsect << 9;
+ nsect -= tsect;
+ }
+
+ /* Read the other NAND pages */
+ for (hd_sects = nsect / ratio; hd_sects > 0; hd_sects--) {
+ if (GLOB_FTL_Page_Read(buf, addr)) {
+ printk(KERN_ERR "Error in %s, Line %d\n",
+ __FILE__, __LINE__);
+ return -EIO;
+ }
+ addr += IdentifyDeviceData.PageDataSize;
+ buf += IdentifyDeviceData.PageDataSize;
+ }
+
+ /* Read the last NAND pages */
+ if (nsect % ratio) {
+ if (GLOB_FTL_Page_Read(tr->tmp_buf, addr)) {
+ printk(KERN_ERR "Error in %s, Line %d\n",
+ __FILE__, __LINE__);
+ return -EIO;
+ }
+ memcpy(buf, tr->tmp_buf, (nsect % ratio) << 9);
+ }
+#if CMD_DMA
+ if (glob_ftl_execute_cmds())
+ return -EIO;
+ else
+ return 0;
+#endif
+ return 0;
+
+ case WRITE:
+ /* Write the first NAND page */
+ if (rsect) {
+ if (GLOB_FTL_Page_Read(tr->tmp_buf, addr)) {
+ printk(KERN_ERR "Error in %s, Line %d\n",
+ __FILE__, __LINE__);
+ return -EIO;
+ }
+ memcpy(tr->tmp_buf + (rsect << 9), buf, tsect << 9);
+ if (GLOB_FTL_Page_Write(tr->tmp_buf, addr)) {
+ printk(KERN_ERR "Error in %s, Line %d\n",
+ __FILE__, __LINE__);
+ return -EIO;
+ }
+ addr += IdentifyDeviceData.PageDataSize;
+ buf += tsect << 9;
+ nsect -= tsect;
+ }
+
+ /* Write the other NAND pages */
+ for (hd_sects = nsect / ratio; hd_sects > 0; hd_sects--) {
+ if (GLOB_FTL_Page_Write(buf, addr)) {
+ printk(KERN_ERR "Error in %s, Line %d\n",
+ __FILE__, __LINE__);
+ return -EIO;
+ }
+ addr += IdentifyDeviceData.PageDataSize;
+ buf += IdentifyDeviceData.PageDataSize;
+ }
+
+ /* Write the last NAND pages */
+ if (nsect % ratio) {
+ if (GLOB_FTL_Page_Read(tr->tmp_buf, addr)) {
+ printk(KERN_ERR "Error in %s, Line %d\n",
+ __FILE__, __LINE__);
+ return -EIO;
+ }
+ memcpy(tr->tmp_buf, buf, (nsect % ratio) << 9);
+ if (GLOB_FTL_Page_Write(tr->tmp_buf, addr)) {
+ printk(KERN_ERR "Error in %s, Line %d\n",
+ __FILE__, __LINE__);
+ return -EIO;
+ }
+ }
+#if CMD_DMA
+ if (glob_ftl_execute_cmds())
+ return -EIO;
+ else
+ return 0;
+#endif
+ return 0;
+
+ default:
+ printk(KERN_NOTICE "Unknown request %u\n", rq_data_dir(req));
+ return -EIO;
+ }
+}
+
+/* This function is copied from drivers/mtd/mtd_blkdevs.c */
+static int spectra_trans_thread(void *arg)
+{
+ struct spectra_nand_dev *tr = arg;
+ struct request_queue *rq = tr->queue;
+ struct request *req = NULL;
+
+ /* we might get involved when memory gets low, so use PF_MEMALLOC */
+ current->flags |= PF_MEMALLOC;
+
+ spin_lock_irq(rq->queue_lock);
+ while (!kthread_should_stop()) {
+ int res;
+
+ if (!req) {
+ req = blk_fetch_request(rq);
+ if (!req) {
+ set_current_state(TASK_INTERRUPTIBLE);
+ spin_unlock_irq(rq->queue_lock);
+ schedule();
+ spin_lock_irq(rq->queue_lock);
+ continue;
+ }
+ }
+
+ spin_unlock_irq(rq->queue_lock);
+
+ mutex_lock(&spectra_lock);
+ res = do_transfer(tr, req);
+ mutex_unlock(&spectra_lock);
+
+ spin_lock_irq(rq->queue_lock);
+
+ if (!__blk_end_request_cur(req, res))
+ req = NULL;
+ }
+
+ if (req)
+ __blk_end_request_all(req, -EIO);
+
+ spin_unlock_irq(rq->queue_lock);
+
+ return 0;
+}
+
+
+/* Request function that "handles clustering". */
+static void GLOB_SBD_request(struct request_queue *rq)
+{
+ struct spectra_nand_dev *pdev = rq->queuedata;
+ wake_up_process(pdev->thread);
+}
+
+static int GLOB_SBD_open(struct block_device *bdev, fmode_t mode)
+
+{
+ nand_dbg_print(NAND_DBG_WARN, "%s, Line %d, Function: %s\n",
+ __FILE__, __LINE__, __func__);
+ return 0;
+}
+
+static int GLOB_SBD_release(struct gendisk *disk, fmode_t mode)
+{
+ int ret;
+
+ nand_dbg_print(NAND_DBG_WARN, "%s, Line %d, Function: %s\n",
+ __FILE__, __LINE__, __func__);
+
+ mutex_lock(&spectra_lock);
+ ret = force_flush_cache();
+ mutex_unlock(&spectra_lock);
+
+ return 0;
+}
+
+static int GLOB_SBD_getgeo(struct block_device *bdev, struct hd_geometry *geo)
+{
+ geo->heads = 4;
+ geo->sectors = 16;
+ geo->cylinders = get_capacity(bdev->bd_disk) / (4 * 16);
+
+ nand_dbg_print(NAND_DBG_DEBUG,
+ "heads: %d, sectors: %d, cylinders: %d\n",
+ geo->heads, geo->sectors, geo->cylinders);
+
+ return 0;
+}
+
+int GLOB_SBD_ioctl(struct block_device *bdev, fmode_t mode,
+ unsigned int cmd, unsigned long arg)
+{
+ int ret;
+
+ nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n",
+ __FILE__, __LINE__, __func__);
+
+ switch (cmd) {
+ case GLOB_SBD_IOCTL_GC:
+ nand_dbg_print(NAND_DBG_DEBUG,
+ "Spectra IOCTL: Garbage Collection "
+ "being performed\n");
+ if (PASS != GLOB_FTL_Garbage_Collection())
+ return -EFAULT;
+ return 0;
+
+ case GLOB_SBD_IOCTL_WL:
+ nand_dbg_print(NAND_DBG_DEBUG,
+ "Spectra IOCTL: Static Wear Leveling "
+ "being performed\n");
+ if (PASS != GLOB_FTL_Wear_Leveling())
+ return -EFAULT;
+ return 0;
+
+ case GLOB_SBD_IOCTL_FORMAT:
+ nand_dbg_print(NAND_DBG_DEBUG, "Spectra IOCTL: Flash format "
+ "being performed\n");
+ if (PASS != GLOB_FTL_Flash_Format())
+ return -EFAULT;
+ return 0;
+
+ case GLOB_SBD_IOCTL_FLUSH_CACHE:
+ nand_dbg_print(NAND_DBG_DEBUG, "Spectra IOCTL: Cache flush "
+ "being performed\n");
+ mutex_lock(&spectra_lock);
+ ret = force_flush_cache();
+ mutex_unlock(&spectra_lock);
+ return ret;
+
+ case GLOB_SBD_IOCTL_COPY_BLK_TABLE:
+ nand_dbg_print(NAND_DBG_DEBUG, "Spectra IOCTL: "
+ "Copy block table\n");
+ if (copy_to_user((void __user *)arg,
+ get_blk_table_start_addr(),
+ get_blk_table_len()))
+ return -EFAULT;
+ return 0;
+
+ case GLOB_SBD_IOCTL_COPY_WEAR_LEVELING_TABLE:
+ nand_dbg_print(NAND_DBG_DEBUG, "Spectra IOCTL: "
+ "Copy wear leveling table\n");
+ if (copy_to_user((void __user *)arg,
+ get_wear_leveling_table_start_addr(),
+ get_wear_leveling_table_len()))
+ return -EFAULT;
+ return 0;
+
+ case GLOB_SBD_IOCTL_GET_NAND_INFO:
+ nand_dbg_print(NAND_DBG_DEBUG, "Spectra IOCTL: "
+ "Get NAND info\n");
+ if (copy_to_user((void __user *)arg, &IdentifyDeviceData,
+ sizeof(IdentifyDeviceData)))
+ return -EFAULT;
+ return 0;
+
+ case GLOB_SBD_IOCTL_WRITE_DATA:
+ nand_dbg_print(NAND_DBG_DEBUG, "Spectra IOCTL: "
+ "Write one page data\n");
+ return ioctl_write_page_data(arg);
+
+ case GLOB_SBD_IOCTL_READ_DATA:
+ nand_dbg_print(NAND_DBG_DEBUG, "Spectra IOCTL: "
+ "Read one page data\n");
+ return ioctl_read_page_data(arg);
+ }
+
+ return -ENOTTY;
+}
+
+static struct block_device_operations GLOB_SBD_ops = {
+ .owner = THIS_MODULE,
+ .open = GLOB_SBD_open,
+ .release = GLOB_SBD_release,
+ .locked_ioctl = GLOB_SBD_ioctl,
+ .getgeo = GLOB_SBD_getgeo,
+};
+
+static int SBD_setup_device(struct spectra_nand_dev *dev, int which)
+{
+ int res_blks;
+ u32 sects;
+
+ nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n",
+ __FILE__, __LINE__, __func__);
+
+ memset(dev, 0, sizeof(struct spectra_nand_dev));
+
+ nand_dbg_print(NAND_DBG_WARN, "Reserved %d blocks "
+ "for OS image, %d blocks for bad block replacement.\n",
+ get_res_blk_num_os(),
+ get_res_blk_num_bad_blk());
+
+ res_blks = get_res_blk_num_bad_blk() + get_res_blk_num_os();
+
+ dev->size = (u64)IdentifyDeviceData.PageDataSize *
+ IdentifyDeviceData.PagesPerBlock *
+ (IdentifyDeviceData.wDataBlockNum - res_blks);
+
+ res_blks_os = get_res_blk_num_os();
+
+ spin_lock_init(&dev->qlock);
+
+ dev->tmp_buf = kmalloc(IdentifyDeviceData.PageDataSize, GFP_ATOMIC);
+ if (!dev->tmp_buf) {
+ printk(KERN_ERR "Failed to kmalloc memory in %s Line %d, exit.\n",
+ __FILE__, __LINE__);
+ goto out_vfree;
+ }
+
+ dev->queue = blk_init_queue(GLOB_SBD_request, &dev->qlock);
+ if (dev->queue == NULL) {
+ printk(KERN_ERR
+ "Spectra: Request queue could not be initialized."
+ " Aborting\n ");
+ goto out_vfree;
+ }
+ dev->queue->queuedata = dev;
+
+ /* As Linux block layer doens't support >4KB hardware sector, */
+ /* Here we force report 512 byte hardware sector size to Kernel */
+ blk_queue_logical_block_size(dev->queue, 512);
+
+ blk_queue_ordered(dev->queue, QUEUE_ORDERED_DRAIN_FLUSH,
+ SBD_prepare_flush);
+
+ dev->thread = kthread_run(spectra_trans_thread, dev, "nand_thd");
+ if (IS_ERR(dev->thread)) {
+ blk_cleanup_queue(dev->queue);
+ unregister_blkdev(GLOB_SBD_majornum, GLOB_SBD_NAME);
+ return PTR_ERR(dev->thread);
+ }
+
+ dev->gd = alloc_disk(PARTITIONS);
+ if (!dev->gd) {
+ printk(KERN_ERR
+ "Spectra: Could not allocate disk. Aborting \n ");
+ goto out_vfree;
+ }
+ dev->gd->major = GLOB_SBD_majornum;
+ dev->gd->first_minor = which * PARTITIONS;
+ dev->gd->fops = &GLOB_SBD_ops;
+ dev->gd->queue = dev->queue;
+ dev->gd->private_data = dev;
+ snprintf(dev->gd->disk_name, 32, "%s%c", GLOB_SBD_NAME, which + 'a');
+
+ sects = dev->size >> 9;
+ nand_dbg_print(NAND_DBG_WARN, "Capacity sects: %d\n", sects);
+ set_capacity(dev->gd, sects);
+
+ add_disk(dev->gd);
+
+ return 0;
+out_vfree:
+ return -ENOMEM;
+}
+
+/*
+static ssize_t show_nand_block_num(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "%d\n",
+ (int)IdentifyDeviceData.wDataBlockNum);
+}
+
+static ssize_t show_nand_pages_per_block(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "%d\n",
+ (int)IdentifyDeviceData.PagesPerBlock);
+}
+
+static ssize_t show_nand_page_size(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "%d\n",
+ (int)IdentifyDeviceData.PageDataSize);
+}
+
+static DEVICE_ATTR(nand_block_num, 0444, show_nand_block_num, NULL);
+static DEVICE_ATTR(nand_pages_per_block, 0444, show_nand_pages_per_block, NULL);
+static DEVICE_ATTR(nand_page_size, 0444, show_nand_page_size, NULL);
+
+static void create_sysfs_entry(struct device *dev)
+{
+ if (device_create_file(dev, &dev_attr_nand_block_num))
+ printk(KERN_ERR "Spectra: "
+ "failed to create sysfs entry nand_block_num.\n");
+ if (device_create_file(dev, &dev_attr_nand_pages_per_block))
+ printk(KERN_ERR "Spectra: "
+ "failed to create sysfs entry nand_pages_per_block.\n");
+ if (device_create_file(dev, &dev_attr_nand_page_size))
+ printk(KERN_ERR "Spectra: "
+ "failed to create sysfs entry nand_page_size.\n");
+}
+*/
+
+static int GLOB_SBD_init(void)
+{
+ int i;
+
+ /* Set debug output level (0~3) here. 3 is most verbose */
+ printk(KERN_ALERT "Spectra: %s\n", GLOB_version);
+
+ mutex_init(&spectra_lock);
+
+ GLOB_SBD_majornum = register_blkdev(0, GLOB_SBD_NAME);
+ if (GLOB_SBD_majornum <= 0) {
+ printk(KERN_ERR "Unable to get the major %d for Spectra",
+ GLOB_SBD_majornum);
+ return -EBUSY;
+ }
+
+ if (PASS != GLOB_FTL_Flash_Init()) {
+ printk(KERN_ERR "Spectra: Unable to Initialize Flash Device. "
+ "Aborting\n");
+ goto out_flash_register;
+ }
+
+ /* create_sysfs_entry(&dev->dev); */
+
+ if (PASS != GLOB_FTL_IdentifyDevice(&IdentifyDeviceData)) {
+ printk(KERN_ERR "Spectra: Unable to Read Flash Device. "
+ "Aborting\n");
+ goto out_flash_register;
+ } else {
+ nand_dbg_print(NAND_DBG_WARN, "In GLOB_SBD_init: "
+ "Num blocks=%d, pagesperblock=%d, "
+ "pagedatasize=%d, ECCBytesPerSector=%d\n",
+ (int)IdentifyDeviceData.NumBlocks,
+ (int)IdentifyDeviceData.PagesPerBlock,
+ (int)IdentifyDeviceData.PageDataSize,
+ (int)IdentifyDeviceData.wECCBytesPerSector);
+ }
+
+ printk(KERN_ALERT "Spectra: searching block table, please wait ...\n");
+ if (GLOB_FTL_Init() != PASS) {
+ printk(KERN_ERR "Spectra: Unable to Initialize FTL Layer. "
+ "Aborting\n");
+ goto out_ftl_flash_register;
+ }
+ printk(KERN_ALERT "Spectra: block table has been found.\n");
+
+ for (i = 0; i < NUM_DEVICES; i++)
+ if (SBD_setup_device(&nand_device[i], i) == -ENOMEM)
+ goto out_ftl_flash_register;
+
+ nand_dbg_print(NAND_DBG_DEBUG,
+ "Spectra: module loaded with major number %d\n",
+ GLOB_SBD_majornum);
+
+ return 0;
+
+out_ftl_flash_register:
+ GLOB_FTL_Cache_Release();
+out_flash_register:
+ GLOB_FTL_Flash_Release();
+ unregister_blkdev(GLOB_SBD_majornum, GLOB_SBD_NAME);
+ printk(KERN_ERR "Spectra: Module load failed.\n");
+
+ return -ENOMEM;
+}
+
+static void __exit GLOB_SBD_exit(void)
+{
+ int i;
+
+ nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n",
+ __FILE__, __LINE__, __func__);
+
+ for (i = 0; i < NUM_DEVICES; i++) {
+ struct spectra_nand_dev *dev = &nand_device[i];
+ if (dev->gd) {
+ del_gendisk(dev->gd);
+ put_disk(dev->gd);
+ }
+ if (dev->queue)
+ blk_cleanup_queue(dev->queue);
+ kfree(dev->tmp_buf);
+ }
+
+ unregister_blkdev(GLOB_SBD_majornum, GLOB_SBD_NAME);
+
+ mutex_lock(&spectra_lock);
+ force_flush_cache();
+ mutex_unlock(&spectra_lock);
+
+ GLOB_FTL_Cache_Release();
+
+ GLOB_FTL_Flash_Release();
+
+ nand_dbg_print(NAND_DBG_DEBUG,
+ "Spectra FTL module (major number %d) unloaded.\n",
+ GLOB_SBD_majornum);
+}
+
+module_init(GLOB_SBD_init);
+module_exit(GLOB_SBD_exit);
diff --git a/drivers/staging/spectra/ffsport.h b/drivers/staging/spectra/ffsport.h
new file mode 100644
index 00000000000..6c5d90c5343
--- /dev/null
+++ b/drivers/staging/spectra/ffsport.h
@@ -0,0 +1,84 @@
+/*
+ * NAND Flash Controller Device Driver
+ * Copyright (c) 2009, Intel Corporation and its suppliers.
+ *
+ * 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 _FFSPORT_
+#define _FFSPORT_
+
+#include "ffsdefs.h"
+
+#if defined __GNUC__
+#define PACKED
+#define PACKED_GNU __attribute__ ((packed))
+#define UNALIGNED
+#endif
+
+#include <linux/semaphore.h>
+#include <linux/string.h> /* for strcpy(), stricmp(), etc */
+#include <linux/mm.h> /* for kmalloc(), kfree() */
+#include <linux/vmalloc.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+
+#include <linux/kernel.h> /* printk() */
+#include <linux/fs.h> /* everything... */
+#include <linux/errno.h> /* error codes */
+#include <linux/types.h> /* size_t */
+#include <linux/genhd.h>
+#include <linux/blkdev.h>
+#include <linux/hdreg.h>
+#include <linux/pci.h>
+#include "flash.h"
+
+#define VERBOSE 1
+
+#define NAND_DBG_WARN 1
+#define NAND_DBG_DEBUG 2
+#define NAND_DBG_TRACE 3
+
+extern int nand_debug_level;
+
+#ifdef VERBOSE
+#define nand_dbg_print(level, args...) \
+ do { \
+ if (level <= nand_debug_level) \
+ printk(KERN_ALERT args); \
+ } while (0)
+#else
+#define nand_dbg_print(level, args...)
+#endif
+
+#ifdef SUPPORT_BIG_ENDIAN
+#define INVERTUINT16(w) ((u16)(((u16)(w)) << 8) | \
+ (u16)((u16)(w) >> 8))
+
+#define INVERTUINT32(dw) (((u32)(dw) << 24) | \
+ (((u32)(dw) << 8) & 0x00ff0000) | \
+ (((u32)(dw) >> 8) & 0x0000ff00) | \
+ ((u32)(dw) >> 24))
+#else
+#define INVERTUINT16(w) w
+#define INVERTUINT32(dw) dw
+#endif
+
+extern int GLOB_Calc_Used_Bits(u32 n);
+extern u64 GLOB_u64_Div(u64 addr, u32 divisor);
+extern u64 GLOB_u64_Remainder(u64 addr, u32 divisor_type);
+
+#endif /* _FFSPORT_ */
diff --git a/drivers/staging/spectra/flash.c b/drivers/staging/spectra/flash.c
new file mode 100644
index 00000000000..134aa5166a8
--- /dev/null
+++ b/drivers/staging/spectra/flash.c
@@ -0,0 +1,4731 @@
+/*
+ * NAND Flash Controller Device Driver
+ * Copyright (c) 2009, Intel Corporation and its suppliers.
+ *
+ * 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/fs.h>
+#include <linux/slab.h>
+
+#include "flash.h"
+#include "ffsdefs.h"
+#include "lld.h"
+#include "lld_nand.h"
+#if CMD_DMA
+#include "lld_cdma.h"
+#endif
+
+#define BLK_FROM_ADDR(addr) ((u32)(addr >> DeviceInfo.nBitsInBlockDataSize))
+#define PAGE_FROM_ADDR(addr, Block) ((u16)((addr - (u64)Block * \
+ DeviceInfo.wBlockDataSize) >> DeviceInfo.nBitsInPageDataSize))
+
+#define IS_SPARE_BLOCK(blk) (BAD_BLOCK != (pbt[blk] &\
+ BAD_BLOCK) && SPARE_BLOCK == (pbt[blk] & SPARE_BLOCK))
+
+#define IS_DATA_BLOCK(blk) (0 == (pbt[blk] & BAD_BLOCK))
+
+#define IS_DISCARDED_BLOCK(blk) (BAD_BLOCK != (pbt[blk] &\
+ BAD_BLOCK) && DISCARD_BLOCK == (pbt[blk] & DISCARD_BLOCK))
+
+#define IS_BAD_BLOCK(blk) (BAD_BLOCK == (pbt[blk] & BAD_BLOCK))
+
+#if DEBUG_BNDRY
+void debug_boundary_lineno_error(int chnl, int limit, int no,
+ int lineno, char *filename)
+{
+ if (chnl >= limit)
+ printk(KERN_ERR "Boundary Check Fail value %d >= limit %d, "
+ "at %s:%d. Other info:%d. Aborting...\n",
+ chnl, limit, filename, lineno, no);
+}
+/* static int globalmemsize; */
+#endif
+
+static u16 FTL_Cache_If_Hit(u64 dwPageAddr);
+static int FTL_Cache_Read(u64 dwPageAddr);
+static void FTL_Cache_Read_Page(u8 *pData, u64 dwPageAddr,
+ u16 cache_blk);
+static void FTL_Cache_Write_Page(u8 *pData, u64 dwPageAddr,
+ u8 cache_blk, u16 flag);
+static int FTL_Cache_Write(void);
+static int FTL_Cache_Write_Back(u8 *pData, u64 blk_addr);
+static void FTL_Calculate_LRU(void);
+static u32 FTL_Get_Block_Index(u32 wBlockNum);
+
+static int FTL_Search_Block_Table_IN_Block(u32 BT_Block,
+ u8 BT_Tag, u16 *Page);
+static int FTL_Read_Block_Table(void);
+static int FTL_Write_Block_Table(int wForce);
+static int FTL_Write_Block_Table_Data(void);
+static int FTL_Check_Block_Table(int wOldTable);
+static int FTL_Static_Wear_Leveling(void);
+static u32 FTL_Replace_Block_Table(void);
+static int FTL_Write_IN_Progress_Block_Table_Page(void);
+
+static u32 FTL_Get_Page_Num(u64 length);
+static u64 FTL_Get_Physical_Block_Addr(u64 blk_addr);
+
+static u32 FTL_Replace_OneBlock(u32 wBlockNum,
+ u32 wReplaceNum);
+static u32 FTL_Replace_LWBlock(u32 wBlockNum,
+ int *pGarbageCollect);
+static u32 FTL_Replace_MWBlock(void);
+static int FTL_Replace_Block(u64 blk_addr);
+static int FTL_Adjust_Relative_Erase_Count(u32 Index_of_MAX);
+
+static int FTL_Flash_Error_Handle(u8 *pData, u64 old_page_addr, u64 blk_addr);
+
+struct device_info_tag DeviceInfo;
+struct flash_cache_tag Cache;
+static struct spectra_l2_cache_info cache_l2;
+
+static u8 *cache_l2_page_buf;
+static u8 *cache_l2_blk_buf;
+
+u8 *g_pBlockTable;
+u8 *g_pWearCounter;
+u16 *g_pReadCounter;
+u32 *g_pBTBlocks;
+static u16 g_wBlockTableOffset;
+static u32 g_wBlockTableIndex;
+static u8 g_cBlockTableStatus;
+
+static u8 *g_pTempBuf;
+static u8 *flag_check_blk_table;
+static u8 *tmp_buf_search_bt_in_block;
+static u8 *spare_buf_search_bt_in_block;
+static u8 *spare_buf_bt_search_bt_in_block;
+static u8 *tmp_buf1_read_blk_table;
+static u8 *tmp_buf2_read_blk_table;
+static u8 *flags_static_wear_leveling;
+static u8 *tmp_buf_write_blk_table_data;
+static u8 *tmp_buf_read_disturbance;
+
+u8 *buf_read_page_main_spare;
+u8 *buf_write_page_main_spare;
+u8 *buf_read_page_spare;
+u8 *buf_get_bad_block;
+
+#if (RESTORE_CACHE_ON_CDMA_CHAIN_FAILURE && CMD_DMA)
+struct flash_cache_delta_list_tag int_cache[MAX_CHANS + MAX_DESCS];
+struct flash_cache_tag cache_start_copy;
+#endif
+
+int g_wNumFreeBlocks;
+u8 g_SBDCmdIndex;
+
+static u8 *g_pIPF;
+static u8 bt_flag = FIRST_BT_ID;
+static u8 bt_block_changed;
+
+static u16 cache_block_to_write;
+static u8 last_erased = FIRST_BT_ID;
+
+static u8 GC_Called;
+static u8 BT_GC_Called;
+
+#if CMD_DMA
+#define COPY_BACK_BUF_NUM 10
+
+static u8 ftl_cmd_cnt; /* Init value is 0 */
+u8 *g_pBTDelta;
+u8 *g_pBTDelta_Free;
+u8 *g_pBTStartingCopy;
+u8 *g_pWearCounterCopy;
+u16 *g_pReadCounterCopy;
+u8 *g_pBlockTableCopies;
+u8 *g_pNextBlockTable;
+static u8 *cp_back_buf_copies[COPY_BACK_BUF_NUM];
+static int cp_back_buf_idx;
+
+static u8 *g_temp_buf;
+
+#pragma pack(push, 1)
+#pragma pack(1)
+struct BTableChangesDelta {
+ u8 ftl_cmd_cnt;
+ u8 ValidFields;
+ u16 g_wBlockTableOffset;
+ u32 g_wBlockTableIndex;
+ u32 BT_Index;
+ u32 BT_Entry_Value;
+ u32 WC_Index;
+ u8 WC_Entry_Value;
+ u32 RC_Index;
+ u16 RC_Entry_Value;
+};
+
+#pragma pack(pop)
+
+struct BTableChangesDelta *p_BTableChangesDelta;
+#endif
+
+
+#define MARK_BLOCK_AS_BAD(blocknode) (blocknode |= BAD_BLOCK)
+#define MARK_BLK_AS_DISCARD(blk) (blk = (blk & ~SPARE_BLOCK) | DISCARD_BLOCK)
+
+#define FTL_Get_LBAPBA_Table_Mem_Size_Bytes() (DeviceInfo.wDataBlockNum *\
+ sizeof(u32))
+#define FTL_Get_WearCounter_Table_Mem_Size_Bytes() (DeviceInfo.wDataBlockNum *\
+ sizeof(u8))
+#define FTL_Get_ReadCounter_Table_Mem_Size_Bytes() (DeviceInfo.wDataBlockNum *\
+ sizeof(u16))
+#if SUPPORT_LARGE_BLOCKNUM
+#define FTL_Get_LBAPBA_Table_Flash_Size_Bytes() (DeviceInfo.wDataBlockNum *\
+ sizeof(u8) * 3)
+#else
+#define FTL_Get_LBAPBA_Table_Flash_Size_Bytes() (DeviceInfo.wDataBlockNum *\
+ sizeof(u16))
+#endif
+#define FTL_Get_WearCounter_Table_Flash_Size_Bytes \
+ FTL_Get_WearCounter_Table_Mem_Size_Bytes
+#define FTL_Get_ReadCounter_Table_Flash_Size_Bytes \
+ FTL_Get_ReadCounter_Table_Mem_Size_Bytes
+
+static u32 FTL_Get_Block_Table_Flash_Size_Bytes(void)
+{
+ u32 byte_num;
+
+ if (DeviceInfo.MLCDevice) {
+ byte_num = FTL_Get_LBAPBA_Table_Flash_Size_Bytes() +
+ DeviceInfo.wDataBlockNum * sizeof(u8) +
+ DeviceInfo.wDataBlockNum * sizeof(u16);
+ } else {
+ byte_num = FTL_Get_LBAPBA_Table_Flash_Size_Bytes() +
+ DeviceInfo.wDataBlockNum * sizeof(u8);
+ }
+
+ byte_num += 4 * sizeof(u8);
+
+ return byte_num;
+}
+
+static u16 FTL_Get_Block_Table_Flash_Size_Pages(void)
+{
+ return (u16)FTL_Get_Page_Num(FTL_Get_Block_Table_Flash_Size_Bytes());
+}
+
+static int FTL_Copy_Block_Table_To_Flash(u8 *flashBuf, u32 sizeToTx,
+ u32 sizeTxed)
+{
+ u32 wBytesCopied, blk_tbl_size, wBytes;
+ u32 *pbt = (u32 *)g_pBlockTable;
+
+ blk_tbl_size = FTL_Get_LBAPBA_Table_Flash_Size_Bytes();
+ for (wBytes = 0;
+ (wBytes < sizeToTx) && ((wBytes + sizeTxed) < blk_tbl_size);
+ wBytes++) {
+#if SUPPORT_LARGE_BLOCKNUM
+ flashBuf[wBytes] = (u8)(pbt[(wBytes + sizeTxed) / 3]
+ >> (((wBytes + sizeTxed) % 3) ?
+ ((((wBytes + sizeTxed) % 3) == 2) ? 0 : 8) : 16)) & 0xFF;
+#else
+ flashBuf[wBytes] = (u8)(pbt[(wBytes + sizeTxed) / 2]
+ >> (((wBytes + sizeTxed) % 2) ? 0 : 8)) & 0xFF;
+#endif
+ }
+
+ sizeTxed = (sizeTxed > blk_tbl_size) ? (sizeTxed - blk_tbl_size) : 0;
+ blk_tbl_size = FTL_Get_WearCounter_Table_Flash_Size_Bytes();
+ wBytesCopied = wBytes;
+ wBytes = ((blk_tbl_size - sizeTxed) > (sizeToTx - wBytesCopied)) ?
+ (sizeToTx - wBytesCopied) : (blk_tbl_size - sizeTxed);
+ memcpy(flashBuf + wBytesCopied, g_pWearCounter + sizeTxed, wBytes);
+
+ sizeTxed = (sizeTxed > blk_tbl_size) ? (sizeTxed - blk_tbl_size) : 0;
+
+ if (DeviceInfo.MLCDevice) {
+ blk_tbl_size = FTL_Get_ReadCounter_Table_Flash_Size_Bytes();
+ wBytesCopied += wBytes;
+ for (wBytes = 0; ((wBytes + wBytesCopied) < sizeToTx) &&
+ ((wBytes + sizeTxed) < blk_tbl_size); wBytes++)
+ flashBuf[wBytes + wBytesCopied] =
+ (g_pReadCounter[(wBytes + sizeTxed) / 2] >>
+ (((wBytes + sizeTxed) % 2) ? 0 : 8)) & 0xFF;
+ }
+
+ return wBytesCopied + wBytes;
+}
+
+static int FTL_Copy_Block_Table_From_Flash(u8 *flashBuf,
+ u32 sizeToTx, u32 sizeTxed)
+{
+ u32 wBytesCopied, blk_tbl_size, wBytes;
+ u32 *pbt = (u32 *)g_pBlockTable;
+
+ blk_tbl_size = FTL_Get_LBAPBA_Table_Flash_Size_Bytes();
+ for (wBytes = 0; (wBytes < sizeToTx) &&
+ ((wBytes + sizeTxed) < blk_tbl_size); wBytes++) {
+#if SUPPORT_LARGE_BLOCKNUM
+ if (!((wBytes + sizeTxed) % 3))
+ pbt[(wBytes + sizeTxed) / 3] = 0;
+ pbt[(wBytes + sizeTxed) / 3] |=
+ (flashBuf[wBytes] << (((wBytes + sizeTxed) % 3) ?
+ ((((wBytes + sizeTxed) % 3) == 2) ? 0 : 8) : 16));
+#else
+ if (!((wBytes + sizeTxed) % 2))
+ pbt[(wBytes + sizeTxed) / 2] = 0;
+ pbt[(wBytes + sizeTxed) / 2] |=
+ (flashBuf[wBytes] << (((wBytes + sizeTxed) % 2) ?
+ 0 : 8));
+#endif
+ }
+
+ sizeTxed = (sizeTxed > blk_tbl_size) ? (sizeTxed - blk_tbl_size) : 0;
+ blk_tbl_size = FTL_Get_WearCounter_Table_Flash_Size_Bytes();
+ wBytesCopied = wBytes;
+ wBytes = ((blk_tbl_size - sizeTxed) > (sizeToTx - wBytesCopied)) ?
+ (sizeToTx - wBytesCopied) : (blk_tbl_size - sizeTxed);
+ memcpy(g_pWearCounter + sizeTxed, flashBuf + wBytesCopied, wBytes);
+ sizeTxed = (sizeTxed > blk_tbl_size) ? (sizeTxed - blk_tbl_size) : 0;
+
+ if (DeviceInfo.MLCDevice) {
+ wBytesCopied += wBytes;
+ blk_tbl_size = FTL_Get_ReadCounter_Table_Flash_Size_Bytes();
+ for (wBytes = 0; ((wBytes + wBytesCopied) < sizeToTx) &&
+ ((wBytes + sizeTxed) < blk_tbl_size); wBytes++) {
+ if (((wBytes + sizeTxed) % 2))
+ g_pReadCounter[(wBytes + sizeTxed) / 2] = 0;
+ g_pReadCounter[(wBytes + sizeTxed) / 2] |=
+ (flashBuf[wBytes] <<
+ (((wBytes + sizeTxed) % 2) ? 0 : 8));
+ }
+ }
+
+ return wBytesCopied+wBytes;
+}
+
+static int FTL_Insert_Block_Table_Signature(u8 *buf, u8 tag)
+{
+ int i;
+
+ for (i = 0; i < BTSIG_BYTES; i++)
+ buf[BTSIG_OFFSET + i] =
+ ((tag + (i * BTSIG_DELTA) - FIRST_BT_ID) %
+ (1 + LAST_BT_ID-FIRST_BT_ID)) + FIRST_BT_ID;
+
+ return PASS;
+}
+
+static int FTL_Extract_Block_Table_Tag(u8 *buf, u8 **tagarray)
+{
+ static u8 tag[BTSIG_BYTES >> 1];
+ int i, j, k, tagi, tagtemp, status;
+
+ *tagarray = (u8 *)tag;
+ tagi = 0;
+
+ for (i = 0; i < (BTSIG_BYTES - 1); i++) {
+ for (j = i + 1; (j < BTSIG_BYTES) &&
+ (tagi < (BTSIG_BYTES >> 1)); j++) {
+ tagtemp = buf[BTSIG_OFFSET + j] -
+ buf[BTSIG_OFFSET + i];
+ if (tagtemp && !(tagtemp % BTSIG_DELTA)) {
+ tagtemp = (buf[BTSIG_OFFSET + i] +
+ (1 + LAST_BT_ID - FIRST_BT_ID) -
+ (i * BTSIG_DELTA)) %
+ (1 + LAST_BT_ID - FIRST_BT_ID);
+ status = FAIL;
+ for (k = 0; k < tagi; k++) {
+ if (tagtemp == tag[k])
+ status = PASS;
+ }
+
+ if (status == FAIL) {
+ tag[tagi++] = tagtemp;
+ i = (j == (i + 1)) ? i + 1 : i;
+ j = (j == (i + 1)) ? i + 1 : i;
+ }
+ }
+ }
+ }
+
+ return tagi;
+}
+
+
+static int FTL_Execute_SPL_Recovery(void)
+{
+ u32 j, block, blks;
+ u32 *pbt = (u32 *)g_pBlockTable;
+ int ret;
+
+ nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n",
+ __FILE__, __LINE__, __func__);
+
+ blks = DeviceInfo.wSpectraEndBlock - DeviceInfo.wSpectraStartBlock;
+ for (j = 0; j <= blks; j++) {
+ block = (pbt[j]);
+ if (((block & BAD_BLOCK) != BAD_BLOCK) &&
+ ((block & SPARE_BLOCK) == SPARE_BLOCK)) {
+ ret = GLOB_LLD_Erase_Block(block & ~BAD_BLOCK);
+ if (FAIL == ret) {
+ nand_dbg_print(NAND_DBG_WARN,
+ "NAND Program fail in %s, Line %d, "
+ "Function: %s, new Bad Block %d "
+ "generated!\n",
+ __FILE__, __LINE__, __func__,
+ (int)(block & ~BAD_BLOCK));
+ MARK_BLOCK_AS_BAD(pbt[j]);
+ }
+ }
+ }
+
+ return PASS;
+}
+
+/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
+* Function: GLOB_FTL_IdentifyDevice
+* Inputs: pointer to identify data structure
+* Outputs: PASS / FAIL
+* Description: the identify data structure is filled in with
+* information for the block driver.
+*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/
+int GLOB_FTL_IdentifyDevice(struct spectra_indentfy_dev_tag *dev_data)
+{
+ nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n",
+ __FILE__, __LINE__, __func__);
+
+ dev_data->NumBlocks = DeviceInfo.wTotalBlocks;
+ dev_data->PagesPerBlock = DeviceInfo.wPagesPerBlock;
+ dev_data->PageDataSize = DeviceInfo.wPageDataSize;
+ dev_data->wECCBytesPerSector = DeviceInfo.wECCBytesPerSector;
+ dev_data->wDataBlockNum = DeviceInfo.wDataBlockNum;
+
+ return PASS;
+}
+
+/* ..... */
+static int allocate_memory(void)
+{
+ u32 block_table_size, page_size, block_size, mem_size;
+ u32 total_bytes = 0;
+ int i;
+#if CMD_DMA
+ int j;
+#endif
+
+ nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n",
+ __FILE__, __LINE__, __func__);
+
+ page_size = DeviceInfo.wPageSize;
+ block_size = DeviceInfo.wPagesPerBlock * DeviceInfo.wPageDataSize;
+
+ block_table_size = DeviceInfo.wDataBlockNum *
+ (sizeof(u32) + sizeof(u8) + sizeof(u16));
+ block_table_size += (DeviceInfo.wPageDataSize -
+ (block_table_size % DeviceInfo.wPageDataSize)) %
+ DeviceInfo.wPageDataSize;
+
+ /* Malloc memory for block tables */
+ g_pBlockTable = kmalloc(block_table_size, GFP_ATOMIC);
+ if (!g_pBlockTable)
+ goto block_table_fail;
+ memset(g_pBlockTable, 0, block_table_size);
+ total_bytes += block_table_size;
+
+ g_pWearCounter = (u8 *)(g_pBlockTable +
+ DeviceInfo.wDataBlockNum * sizeof(u32));
+
+ if (DeviceInfo.MLCDevice)
+ g_pReadCounter = (u16 *)(g_pBlockTable +
+ DeviceInfo.wDataBlockNum *
+ (sizeof(u32) + sizeof(u8)));
+
+ /* Malloc memory and init for cache items */
+ for (i = 0; i < CACHE_ITEM_NUM; i++) {
+ Cache.array[i].address = NAND_CACHE_INIT_ADDR;
+ Cache.array[i].use_cnt = 0;
+ Cache.array[i].changed = CLEAR;
+ Cache.array[i].buf = kmalloc(Cache.cache_item_size,
+ GFP_ATOMIC);
+ if (!Cache.array[i].buf)
+ goto cache_item_fail;
+ memset(Cache.array[i].buf, 0, Cache.cache_item_size);
+ total_bytes += Cache.cache_item_size;
+ }
+
+ /* Malloc memory for IPF */
+ g_pIPF = kmalloc(page_size, GFP_ATOMIC);
+ if (!g_pIPF)
+ goto ipf_fail;
+ memset(g_pIPF, 0, page_size);
+ total_bytes += page_size;
+
+ /* Malloc memory for data merging during Level2 Cache flush */
+ cache_l2_page_buf = kmalloc(page_size, GFP_ATOMIC);
+ if (!cache_l2_page_buf)
+ goto cache_l2_page_buf_fail;
+ memset(cache_l2_page_buf, 0xff, page_size);
+ total_bytes += page_size;
+
+ cache_l2_blk_buf = kmalloc(block_size, GFP_ATOMIC);
+ if (!cache_l2_blk_buf)
+ goto cache_l2_blk_buf_fail;
+ memset(cache_l2_blk_buf, 0xff, block_size);
+ total_bytes += block_size;
+
+ /* Malloc memory for temp buffer */
+ g_pTempBuf = kmalloc(Cache.cache_item_size, GFP_ATOMIC);
+ if (!g_pTempBuf)
+ goto Temp_buf_fail;
+ memset(g_pTempBuf, 0, Cache.cache_item_size);
+ total_bytes += Cache.cache_item_size;
+
+ /* Malloc memory for block table blocks */
+ mem_size = (1 + LAST_BT_ID - FIRST_BT_ID) * sizeof(u32);
+ g_pBTBlocks = kmalloc(mem_size, GFP_ATOMIC);
+ if (!g_pBTBlocks)
+ goto bt_blocks_fail;
+ memset(g_pBTBlocks, 0xff, mem_size);
+ total_bytes += mem_size;
+
+ /* Malloc memory for function FTL_Check_Block_Table */
+ flag_check_blk_table = kmalloc(DeviceInfo.wDataBlockNum, GFP_ATOMIC);
+ if (!flag_check_blk_table)
+ goto flag_check_blk_table_fail;
+ total_bytes += DeviceInfo.wDataBlockNum;
+
+ /* Malloc memory for function FTL_Search_Block_Table_IN_Block */
+ tmp_buf_search_bt_in_block = kmalloc(page_size, GFP_ATOMIC);
+ if (!tmp_buf_search_bt_in_block)
+ goto tmp_buf_search_bt_in_block_fail;
+ memset(tmp_buf_search_bt_in_block, 0xff, page_size);
+ total_bytes += page_size;
+
+ mem_size = DeviceInfo.wPageSize - DeviceInfo.wPageDataSize;
+ spare_buf_search_bt_in_block = kmalloc(mem_size, GFP_ATOMIC);
+ if (!spare_buf_search_bt_in_block)
+ goto spare_buf_search_bt_in_block_fail;
+ memset(spare_buf_search_bt_in_block, 0xff, mem_size);
+ total_bytes += mem_size;
+
+ spare_buf_bt_search_bt_in_block = kmalloc(mem_size, GFP_ATOMIC);
+ if (!spare_buf_bt_search_bt_in_block)
+ goto spare_buf_bt_search_bt_in_block_fail;
+ memset(spare_buf_bt_search_bt_in_block, 0xff, mem_size);
+ total_bytes += mem_size;
+
+ /* Malloc memory for function FTL_Read_Block_Table */
+ tmp_buf1_read_blk_table = kmalloc(page_size, GFP_ATOMIC);
+ if (!tmp_buf1_read_blk_table)
+ goto tmp_buf1_read_blk_table_fail;
+ memset(tmp_buf1_read_blk_table, 0xff, page_size);
+ total_bytes += page_size;
+
+ tmp_buf2_read_blk_table = kmalloc(page_size, GFP_ATOMIC);
+ if (!tmp_buf2_read_blk_table)
+ goto tmp_buf2_read_blk_table_fail;
+ memset(tmp_buf2_read_blk_table, 0xff, page_size);
+ total_bytes += page_size;
+
+ /* Malloc memory for function FTL_Static_Wear_Leveling */
+ flags_static_wear_leveling = kmalloc(DeviceInfo.wDataBlockNum,
+ GFP_ATOMIC);
+ if (!flags_static_wear_leveling)
+ goto flags_static_wear_leveling_fail;
+ total_bytes += DeviceInfo.wDataBlockNum;
+
+ /* Malloc memory for function FTL_Write_Block_Table_Data */
+ if (FTL_Get_Block_Table_Flash_Size_Pages() > 3)
+ mem_size = FTL_Get_Block_Table_Flash_Size_Bytes() -
+ 2 * DeviceInfo.wPageSize;
+ else
+ mem_size = DeviceInfo.wPageSize;
+ tmp_buf_write_blk_table_data = kmalloc(mem_size, GFP_ATOMIC);
+ if (!tmp_buf_write_blk_table_data)
+ goto tmp_buf_write_blk_table_data_fail;
+ memset(tmp_buf_write_blk_table_data, 0xff, mem_size);
+ total_bytes += mem_size;
+
+ /* Malloc memory for function FTL_Read_Disturbance */
+ tmp_buf_read_disturbance = kmalloc(block_size, GFP_ATOMIC);
+ if (!tmp_buf_read_disturbance)
+ goto tmp_buf_read_disturbance_fail;
+ memset(tmp_buf_read_disturbance, 0xff, block_size);
+ total_bytes += block_size;
+
+ /* Alloc mem for function NAND_Read_Page_Main_Spare of lld_nand.c */
+ buf_read_page_main_spare = kmalloc(DeviceInfo.wPageSize, GFP_ATOMIC);
+ if (!buf_read_page_main_spare)
+ goto buf_read_page_main_spare_fail;
+ total_bytes += DeviceInfo.wPageSize;
+
+ /* Alloc mem for function NAND_Write_Page_Main_Spare of lld_nand.c */
+ buf_write_page_main_spare = kmalloc(DeviceInfo.wPageSize, GFP_ATOMIC);
+ if (!buf_write_page_main_spare)
+ goto buf_write_page_main_spare_fail;
+ total_bytes += DeviceInfo.wPageSize;
+
+ /* Alloc mem for function NAND_Read_Page_Spare of lld_nand.c */
+ buf_read_page_spare = kmalloc(DeviceInfo.wPageSpareSize, GFP_ATOMIC);
+ if (!buf_read_page_spare)
+ goto buf_read_page_spare_fail;
+ memset(buf_read_page_spare, 0xff, DeviceInfo.wPageSpareSize);
+ total_bytes += DeviceInfo.wPageSpareSize;
+
+ /* Alloc mem for function NAND_Get_Bad_Block of lld_nand.c */
+ buf_get_bad_block = kmalloc(DeviceInfo.wPageSpareSize, GFP_ATOMIC);
+ if (!buf_get_bad_block)
+ goto buf_get_bad_block_fail;
+ memset(buf_get_bad_block, 0xff, DeviceInfo.wPageSpareSize);
+ total_bytes += DeviceInfo.wPageSpareSize;
+
+#if CMD_DMA
+ g_temp_buf = kmalloc(block_size, GFP_ATOMIC);
+ if (!g_temp_buf)
+ goto temp_buf_fail;
+ memset(g_temp_buf, 0xff, block_size);
+ total_bytes += block_size;
+
+ /* Malloc memory for copy of block table used in CDMA mode */
+ g_pBTStartingCopy = kmalloc(block_table_size, GFP_ATOMIC);
+ if (!g_pBTStartingCopy)
+ goto bt_starting_copy;
+ memset(g_pBTStartingCopy, 0, block_table_size);
+ total_bytes += block_table_size;
+
+ g_pWearCounterCopy = (u8 *)(g_pBTStartingCopy +
+ DeviceInfo.wDataBlockNum * sizeof(u32));
+
+ if (DeviceInfo.MLCDevice)
+ g_pReadCounterCopy = (u16 *)(g_pBTStartingCopy +
+ DeviceInfo.wDataBlockNum *
+ (sizeof(u32) + sizeof(u8)));
+
+ /* Malloc memory for block table copies */
+ mem_size = 5 * DeviceInfo.wDataBlockNum * sizeof(u32) +
+ 5 * DeviceInfo.wDataBlockNum * sizeof(u8);
+ if (DeviceInfo.MLCDevice)
+ mem_size += 5 * DeviceInfo.wDataBlockNum * sizeof(u16);
+ g_pBlockTableCopies = kmalloc(mem_size, GFP_ATOMIC);
+ if (!g_pBlockTableCopies)
+ goto blk_table_copies_fail;
+ memset(g_pBlockTableCopies, 0, mem_size);
+ total_bytes += mem_size;
+ g_pNextBlockTable = g_pBlockTableCopies;
+
+ /* Malloc memory for Block Table Delta */
+ mem_size = MAX_DESCS * sizeof(struct BTableChangesDelta);
+ g_pBTDelta = kmalloc(mem_size, GFP_ATOMIC);
+ if (!g_pBTDelta)
+ goto bt_delta_fail;
+ memset(g_pBTDelta, 0, mem_size);
+ total_bytes += mem_size;
+ g_pBTDelta_Free = g_pBTDelta;
+
+ /* Malloc memory for Copy Back Buffers */
+ for (j = 0; j < COPY_BACK_BUF_NUM; j++) {
+ cp_back_buf_copies[j] = kmalloc(block_size, GFP_ATOMIC);
+ if (!cp_back_buf_copies[j])
+ goto cp_back_buf_copies_fail;
+ memset(cp_back_buf_copies[j], 0, block_size);
+ total_bytes += block_size;
+ }
+ cp_back_buf_idx = 0;
+
+ /* Malloc memory for pending commands list */
+ mem_size = sizeof(struct pending_cmd) * MAX_DESCS;
+ info.pcmds = kzalloc(mem_size, GFP_KERNEL);
+ if (!info.pcmds)
+ goto pending_cmds_buf_fail;
+ total_bytes += mem_size;
+
+ /* Malloc memory for CDMA descripter table */
+ mem_size = sizeof(struct cdma_descriptor) * MAX_DESCS;
+ info.cdma_desc_buf = kzalloc(mem_size, GFP_KERNEL);
+ if (!info.cdma_desc_buf)
+ goto cdma_desc_buf_fail;
+ total_bytes += mem_size;
+
+ /* Malloc memory for Memcpy descripter table */
+ mem_size = sizeof(struct memcpy_descriptor) * MAX_DESCS;
+ info.memcp_desc_buf = kzalloc(mem_size, GFP_KERNEL);
+ if (!info.memcp_desc_buf)
+ goto memcp_desc_buf_fail;
+ total_bytes += mem_size;
+#endif
+
+ nand_dbg_print(NAND_DBG_WARN,
+ "Total memory allocated in FTL layer: %d\n", total_bytes);
+
+ return PASS;
+
+#if CMD_DMA
+memcp_desc_buf_fail:
+ kfree(info.cdma_desc_buf);
+cdma_desc_buf_fail:
+ kfree(info.pcmds);
+pending_cmds_buf_fail:
+cp_back_buf_copies_fail:
+ j--;
+ for (; j >= 0; j--)
+ kfree(cp_back_buf_copies[j]);
+ kfree(g_pBTDelta);
+bt_delta_fail:
+ kfree(g_pBlockTableCopies);
+blk_table_copies_fail:
+ kfree(g_pBTStartingCopy);
+bt_starting_copy:
+ kfree(g_temp_buf);
+temp_buf_fail:
+ kfree(buf_get_bad_block);
+#endif
+
+buf_get_bad_block_fail:
+ kfree(buf_read_page_spare);
+buf_read_page_spare_fail:
+ kfree(buf_write_page_main_spare);
+buf_write_page_main_spare_fail:
+ kfree(buf_read_page_main_spare);
+buf_read_page_main_spare_fail:
+ kfree(tmp_buf_read_disturbance);
+tmp_buf_read_disturbance_fail:
+ kfree(tmp_buf_write_blk_table_data);
+tmp_buf_write_blk_table_data_fail:
+ kfree(flags_static_wear_leveling);
+flags_static_wear_leveling_fail:
+ kfree(tmp_buf2_read_blk_table);
+tmp_buf2_read_blk_table_fail:
+ kfree(tmp_buf1_read_blk_table);
+tmp_buf1_read_blk_table_fail:
+ kfree(spare_buf_bt_search_bt_in_block);
+spare_buf_bt_search_bt_in_block_fail:
+ kfree(spare_buf_search_bt_in_block);
+spare_buf_search_bt_in_block_fail:
+ kfree(tmp_buf_search_bt_in_block);
+tmp_buf_search_bt_in_block_fail:
+ kfree(flag_check_blk_table);
+flag_check_blk_table_fail:
+ kfree(g_pBTBlocks);
+bt_blocks_fail:
+ kfree(g_pTempBuf);
+Temp_buf_fail:
+ kfree(cache_l2_blk_buf);
+cache_l2_blk_buf_fail:
+ kfree(cache_l2_page_buf);
+cache_l2_page_buf_fail:
+ kfree(g_pIPF);
+ipf_fail:
+cache_item_fail:
+ i--;
+ for (; i >= 0; i--)
+ kfree(Cache.array[i].buf);
+ kfree(g_pBlockTable);
+block_table_fail:
+ printk(KERN_ERR "Failed to kmalloc memory in %s Line %d.\n",
+ __FILE__, __LINE__);
+
+ return -ENOMEM;
+}
+
+/* .... */
+static int free_memory(void)
+{
+ int i;
+
+#if CMD_DMA
+ kfree(info.memcp_desc_buf);
+ kfree(info.cdma_desc_buf);
+ kfree(info.pcmds);
+ for (i = COPY_BACK_BUF_NUM - 1; i >= 0; i--)
+ kfree(cp_back_buf_copies[i]);
+ kfree(g_pBTDelta);
+ kfree(g_pBlockTableCopies);
+ kfree(g_pBTStartingCopy);
+ kfree(g_temp_buf);
+ kfree(buf_get_bad_block);
+#endif
+ kfree(buf_read_page_spare);
+ kfree(buf_write_page_main_spare);
+ kfree(buf_read_page_main_spare);
+ kfree(tmp_buf_read_disturbance);
+ kfree(tmp_buf_write_blk_table_data);
+ kfree(flags_static_wear_leveling);
+ kfree(tmp_buf2_read_blk_table);
+ kfree(tmp_buf1_read_blk_table);
+ kfree(spare_buf_bt_search_bt_in_block);
+ kfree(spare_buf_search_bt_in_block);
+ kfree(tmp_buf_search_bt_in_block);
+ kfree(flag_check_blk_table);
+ kfree(g_pBTBlocks);
+ kfree(g_pTempBuf);
+ kfree(g_pIPF);
+ for (i = CACHE_ITEM_NUM - 1; i >= 0; i--)
+ kfree(Cache.array[i].buf);
+ kfree(g_pBlockTable);
+
+ return 0;
+}
+
+static void dump_cache_l2_table(void)
+{
+ struct list_head *p;
+ struct spectra_l2_cache_list *pnd;
+ int n, i;
+
+ n = 0;
+ list_for_each(p, &cache_l2.table.list) {
+ pnd = list_entry(p, struct spectra_l2_cache_list, list);
+ nand_dbg_print(NAND_DBG_WARN, "dump_cache_l2_table node: %d, logical_blk_num: %d\n", n, pnd->logical_blk_num);
+/*
+ for (i = 0; i < DeviceInfo.wPagesPerBlock; i++) {
+ if (pnd->pages_array[i] != MAX_U32_VALUE)
+ nand_dbg_print(NAND_DBG_WARN, " pages_array[%d]: 0x%x\n", i, pnd->pages_array[i]);
+ }
+*/
+ n++;
+ }
+}
+
+/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
+* Function: GLOB_FTL_Init
+* Inputs: none
+* Outputs: PASS=0 / FAIL=1
+* Description: allocates the memory for cache array,
+* important data structures
+* clears the cache array
+* reads the block table from flash into array
+*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/
+int GLOB_FTL_Init(void)
+{
+ int i;
+
+ nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n",
+ __FILE__, __LINE__, __func__);
+
+ Cache.pages_per_item = 1;
+ Cache.cache_item_size = 1 * DeviceInfo.wPageDataSize;
+
+ if (allocate_memory() != PASS)
+ return FAIL;
+
+#if CMD_DMA
+#if RESTORE_CACHE_ON_CDMA_CHAIN_FAILURE
+ memcpy((void *)&cache_start_copy, (void *)&Cache,
+ sizeof(struct flash_cache_tag));
+ memset((void *)&int_cache, -1,
+ sizeof(struct flash_cache_delta_list_tag) *
+ (MAX_CHANS + MAX_DESCS));
+#endif
+ ftl_cmd_cnt = 0;
+#endif
+
+ if (FTL_Read_Block_Table() != PASS)
+ return FAIL;
+
+ /* Init the Level2 Cache data structure */
+ for (i = 0; i < BLK_NUM_FOR_L2_CACHE; i++)
+ cache_l2.blk_array[i] = MAX_U32_VALUE;
+ cache_l2.cur_blk_idx = 0;
+ cache_l2.cur_page_num = 0;
+ INIT_LIST_HEAD(&cache_l2.table.list);
+ cache_l2.table.logical_blk_num = MAX_U32_VALUE;
+
+ dump_cache_l2_table();
+
+ return 0;
+}
+
+
+#if CMD_DMA
+#if 0
+static void save_blk_table_changes(u16 idx)
+{
+ u8 ftl_cmd;
+ u32 *pbt = (u32 *)g_pBTStartingCopy;
+
+#if RESTORE_CACHE_ON_CDMA_CHAIN_FAILURE
+ u16 id;
+ u8 cache_blks;
+
+ id = idx - MAX_CHANS;
+ if (int_cache[id].item != -1) {
+ cache_blks = int_cache[id].item;
+ cache_start_copy.array[cache_blks].address =
+ int_cache[id].cache.address;
+ cache_start_copy.array[cache_blks].changed =
+ int_cache[id].cache.changed;
+ }
+#endif
+
+ ftl_cmd = p_BTableChangesDelta->ftl_cmd_cnt;
+
+ while (ftl_cmd <= PendingCMD[idx].Tag) {
+ if (p_BTableChangesDelta->ValidFields == 0x01) {
+ g_wBlockTableOffset =
+ p_BTableChangesDelta->g_wBlockTableOffset;
+ } else if (p_BTableChangesDelta->ValidFields == 0x0C) {
+ pbt[p_BTableChangesDelta->BT_Index] =
+ p_BTableChangesDelta->BT_Entry_Value;
+ debug_boundary_error(((
+ p_BTableChangesDelta->BT_Index)),
+ DeviceInfo.wDataBlockNum, 0);
+ } else if (p_BTableChangesDelta->ValidFields == 0x03) {
+ g_wBlockTableOffset =
+ p_BTableChangesDelta->g_wBlockTableOffset;
+ g_wBlockTableIndex =
+ p_BTableChangesDelta->g_wBlockTableIndex;
+ } else if (p_BTableChangesDelta->ValidFields == 0x30) {
+ g_pWearCounterCopy[p_BTableChangesDelta->WC_Index] =
+ p_BTableChangesDelta->WC_Entry_Value;
+ } else if ((DeviceInfo.MLCDevice) &&
+ (p_BTableChangesDelta->ValidFields == 0xC0)) {
+ g_pReadCounterCopy[p_BTableChangesDelta->RC_Index] =
+ p_BTableChangesDelta->RC_Entry_Value;
+ nand_dbg_print(NAND_DBG_DEBUG,
+ "In event status setting read counter "
+ "GLOB_ftl_cmd_cnt %u Count %u Index %u\n",
+ ftl_cmd,
+ p_BTableChangesDelta->RC_Entry_Value,
+ (unsigned int)p_BTableChangesDelta->RC_Index);
+ } else {
+ nand_dbg_print(NAND_DBG_DEBUG,
+ "This should never occur \n");
+ }
+ p_BTableChangesDelta += 1;
+ ftl_cmd = p_BTableChangesDelta->ftl_cmd_cnt;
+ }
+}
+
+static void discard_cmds(u16 n)
+{
+ u32 *pbt = (u32 *)g_pBTStartingCopy;
+ u8 ftl_cmd;
+ unsigned long k;
+#if RESTORE_CACHE_ON_CDMA_CHAIN_FAILURE
+ u8 cache_blks;
+ u16 id;
+#endif
+
+ if ((PendingCMD[n].CMD == WRITE_MAIN_CMD) ||
+ (PendingCMD[n].CMD == WRITE_MAIN_SPARE_CMD)) {
+ for (k = 0; k < DeviceInfo.wDataBlockNum; k++) {
+ if (PendingCMD[n].Block == (pbt[k] & (~BAD_BLOCK)))
+ MARK_BLK_AS_DISCARD(pbt[k]);
+ }
+ }
+
+ ftl_cmd = p_BTableChangesDelta->ftl_cmd_cnt;
+ while (ftl_cmd <= PendingCMD[n].Tag) {
+ p_BTableChangesDelta += 1;
+ ftl_cmd = p_BTableChangesDelta->ftl_cmd_cnt;
+ }
+
+#if RESTORE_CACHE_ON_CDMA_CHAIN_FAILURE
+ id = n - MAX_CHANS;
+
+ if (int_cache[id].item != -1) {
+ cache_blks = int_cache[id].item;
+ if (PendingCMD[n].CMD == MEMCOPY_CMD) {
+ if ((cache_start_copy.array[cache_blks].buf <=
+ PendingCMD[n].DataDestAddr) &&
+ ((cache_start_copy.array[cache_blks].buf +
+ Cache.cache_item_size) >
+ PendingCMD[n].DataDestAddr)) {
+ cache_start_copy.array[cache_blks].address =
+ NAND_CACHE_INIT_ADDR;
+ cache_start_copy.array[cache_blks].use_cnt =
+ 0;
+ cache_start_copy.array[cache_blks].changed =
+ CLEAR;
+ }
+ } else {
+ cache_start_copy.array[cache_blks].address =
+ int_cache[id].cache.address;
+ cache_start_copy.array[cache_blks].changed =
+ int_cache[id].cache.changed;
+ }
+ }
+#endif
+}
+
+static void process_cmd_pass(int *first_failed_cmd, u16 idx)
+{
+ if (0 == *first_failed_cmd)
+ save_blk_table_changes(idx);
+ else
+ discard_cmds(idx);
+}
+
+static void process_cmd_fail_abort(int *first_failed_cmd,
+ u16 idx, int event)
+{
+ u32 *pbt = (u32 *)g_pBTStartingCopy;
+ u8 ftl_cmd;
+ unsigned long i;
+ int erase_fail, program_fail;
+#if RESTORE_CACHE_ON_CDMA_CHAIN_FAILURE
+ u8 cache_blks;
+ u16 id;
+#endif
+
+ if (0 == *first_failed_cmd)
+ *first_failed_cmd = PendingCMD[idx].SBDCmdIndex;
+
+ nand_dbg_print(NAND_DBG_DEBUG, "Uncorrectable error has occured "
+ "while executing %u Command %u accesing Block %u\n",
+ (unsigned int)p_BTableChangesDelta->ftl_cmd_cnt,
+ PendingCMD[idx].CMD,
+ (unsigned int)PendingCMD[idx].Block);
+
+ ftl_cmd = p_BTableChangesDelta->ftl_cmd_cnt;
+ while (ftl_cmd <= PendingCMD[idx].Tag) {
+ p_BTableChangesDelta += 1;
+ ftl_cmd = p_BTableChangesDelta->ftl_cmd_cnt;
+ }
+
+#if RESTORE_CACHE_ON_CDMA_CHAIN_FAILURE
+ id = idx - MAX_CHANS;
+
+ if (int_cache[id].item != -1) {
+ cache_blks = int_cache[id].item;
+ if ((PendingCMD[idx].CMD == WRITE_MAIN_CMD)) {
+ cache_start_copy.array[cache_blks].address =
+ int_cache[id].cache.address;
+ cache_start_copy.array[cache_blks].changed = SET;
+ } else if ((PendingCMD[idx].CMD == READ_MAIN_CMD)) {
+ cache_start_copy.array[cache_blks].address =
+ NAND_CACHE_INIT_ADDR;
+ cache_start_copy.array[cache_blks].use_cnt = 0;
+ cache_start_copy.array[cache_blks].changed =
+ CLEAR;
+ } else if (PendingCMD[idx].CMD == ERASE_CMD) {
+ /* ? */
+ } else if (PendingCMD[idx].CMD == MEMCOPY_CMD) {
+ /* ? */
+ }
+ }
+#endif
+
+ erase_fail = (event == EVENT_ERASE_FAILURE) &&
+ (PendingCMD[idx].CMD == ERASE_CMD);
+
+ program_fail = (event == EVENT_PROGRAM_FAILURE) &&
+ ((PendingCMD[idx].CMD == WRITE_MAIN_CMD) ||
+ (PendingCMD[idx].CMD == WRITE_MAIN_SPARE_CMD));
+
+ if (erase_fail || program_fail) {
+ for (i = 0; i < DeviceInfo.wDataBlockNum; i++) {
+ if (PendingCMD[idx].Block ==
+ (pbt[i] & (~BAD_BLOCK)))
+ MARK_BLOCK_AS_BAD(pbt[i]);
+ }
+ }
+}
+
+static void process_cmd(int *first_failed_cmd, u16 idx, int event)
+{
+ u8 ftl_cmd;
+ int cmd_match = 0;
+
+ if (p_BTableChangesDelta->ftl_cmd_cnt == PendingCMD[idx].Tag)
+ cmd_match = 1;
+
+ if (PendingCMD[idx].Status == CMD_PASS) {
+ process_cmd_pass(first_failed_cmd, idx);
+ } else if ((PendingCMD[idx].Status == CMD_FAIL) ||
+ (PendingCMD[idx].Status == CMD_ABORT)) {
+ process_cmd_fail_abort(first_failed_cmd, idx, event);
+ } else if ((PendingCMD[idx].Status == CMD_NOT_DONE) &&
+ PendingCMD[idx].Tag) {
+ nand_dbg_print(NAND_DBG_DEBUG,
+ " Command no. %hu is not executed\n",
+ (unsigned int)PendingCMD[idx].Tag);
+ ftl_cmd = p_BTableChangesDelta->ftl_cmd_cnt;
+ while (ftl_cmd <= PendingCMD[idx].Tag) {
+ p_BTableChangesDelta += 1;
+ ftl_cmd = p_BTableChangesDelta->ftl_cmd_cnt;
+ }
+ }
+}
+#endif
+
+static void process_cmd(int *first_failed_cmd, u16 idx, int event)
+{
+ printk(KERN_ERR "temporary workaround function. "
+ "Should not be called! \n");
+}
+
+/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
+* Function: GLOB_FTL_Event_Status
+* Inputs: none
+* Outputs: Event Code
+* Description: It is called by SBD after hardware interrupt signalling
+* completion of commands chain
+* It does following things
+* get event status from LLD
+* analyze command chain status
+* determine last command executed
+* analyze results
+* rebuild the block table in case of uncorrectable error
+* return event code
+*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/
+int GLOB_FTL_Event_Status(int *first_failed_cmd)
+{
+ int event_code = PASS;
+ u16 i_P;
+
+ nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n",
+ __FILE__, __LINE__, __func__);
+
+ *first_failed_cmd = 0;
+
+ event_code = GLOB_LLD_Event_Status();
+
+ switch (event_code) {
+ case EVENT_PASS:
+ nand_dbg_print(NAND_DBG_DEBUG, "Handling EVENT_PASS\n");
+ break;
+ case EVENT_UNCORRECTABLE_DATA_ERROR:
+ nand_dbg_print(NAND_DBG_DEBUG, "Handling Uncorrectable ECC!\n");
+ break;
+ case EVENT_PROGRAM_FAILURE:
+ case EVENT_ERASE_FAILURE:
+ nand_dbg_print(NAND_DBG_WARN, "Handling Ugly case. "
+ "Event code: 0x%x\n", event_code);
+ p_BTableChangesDelta =
+ (struct BTableChangesDelta *)g_pBTDelta;
+ for (i_P = MAX_CHANS; i_P < (ftl_cmd_cnt + MAX_CHANS);
+ i_P++)
+ process_cmd(first_failed_cmd, i_P, event_code);
+ memcpy(g_pBlockTable, g_pBTStartingCopy,
+ DeviceInfo.wDataBlockNum * sizeof(u32));
+ memcpy(g_pWearCounter, g_pWearCounterCopy,
+ DeviceInfo.wDataBlockNum * sizeof(u8));
+ if (DeviceInfo.MLCDevice)
+ memcpy(g_pReadCounter, g_pReadCounterCopy,
+ DeviceInfo.wDataBlockNum * sizeof(u16));
+
+#if RESTORE_CACHE_ON_CDMA_CHAIN_FAILURE
+ memcpy((void *)&Cache, (void *)&cache_start_copy,
+ sizeof(struct flash_cache_tag));
+ memset((void *)&int_cache, -1,
+ sizeof(struct flash_cache_delta_list_tag) *
+ (MAX_DESCS + MAX_CHANS));
+#endif
+ break;
+ default:
+ nand_dbg_print(NAND_DBG_WARN,
+ "Handling unexpected event code - 0x%x\n",
+ event_code);
+ event_code = ERR;
+ break;
+ }
+
+ memcpy(g_pBTStartingCopy, g_pBlockTable,
+ DeviceInfo.wDataBlockNum * sizeof(u32));
+ memcpy(g_pWearCounterCopy, g_pWearCounter,
+ DeviceInfo.wDataBlockNum * sizeof(u8));
+ if (DeviceInfo.MLCDevice)
+ memcpy(g_pReadCounterCopy, g_pReadCounter,
+ DeviceInfo.wDataBlockNum * sizeof(u16));
+
+ g_pBTDelta_Free = g_pBTDelta;
+ ftl_cmd_cnt = 0;
+ g_pNextBlockTable = g_pBlockTableCopies;
+ cp_back_buf_idx = 0;
+
+#if RESTORE_CACHE_ON_CDMA_CHAIN_FAILURE
+ memcpy((void *)&cache_start_copy, (void *)&Cache,
+ sizeof(struct flash_cache_tag));
+ memset((void *)&int_cache, -1,
+ sizeof(struct flash_cache_delta_list_tag) *
+ (MAX_DESCS + MAX_CHANS));
+#endif
+
+ return event_code;
+}
+
+/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
+* Function: glob_ftl_execute_cmds
+* Inputs: none
+* Outputs: none
+* Description: pass thru to LLD
+***************************************************************/
+u16 glob_ftl_execute_cmds(void)
+{
+ nand_dbg_print(NAND_DBG_TRACE,
+ "glob_ftl_execute_cmds: ftl_cmd_cnt %u\n",
+ (unsigned int)ftl_cmd_cnt);
+ g_SBDCmdIndex = 0;
+ return glob_lld_execute_cmds();
+}
+
+#endif
+
+#if !CMD_DMA
+/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
+* Function: GLOB_FTL_Read Immediate
+* Inputs: pointer to data
+* address of data
+* Outputs: PASS / FAIL
+* Description: Reads one page of data into RAM directly from flash without
+* using or disturbing cache.It is assumed this function is called
+* with CMD-DMA disabled.
+*****************************************************************/
+int GLOB_FTL_Read_Immediate(u8 *read_data, u64 addr)
+{
+ int wResult = FAIL;
+ u32 Block;
+ u16 Page;
+ u32 phy_blk;
+ u32 *pbt = (u32 *)g_pBlockTable;
+
+ nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n",
+ __FILE__, __LINE__, __func__);
+
+ Block = BLK_FROM_ADDR(addr);
+ Page = PAGE_FROM_ADDR(addr, Block);
+
+ if (!IS_SPARE_BLOCK(Block))
+ return FAIL;
+
+ phy_blk = pbt[Block];
+ wResult = GLOB_LLD_Read_Page_Main(read_data, phy_blk, Page, 1);
+
+ if (DeviceInfo.MLCDevice) {
+ g_pReadCounter[phy_blk - DeviceInfo.wSpectraStartBlock]++;
+ if (g_pReadCounter[phy_blk - DeviceInfo.wSpectraStartBlock]
+ >= MAX_READ_COUNTER)
+ FTL_Read_Disturbance(phy_blk);
+ if (g_cBlockTableStatus != IN_PROGRESS_BLOCK_TABLE) {
+ g_cBlockTableStatus = IN_PROGRESS_BLOCK_TABLE;
+ FTL_Write_IN_Progress_Block_Table_Page();
+ }
+ }
+
+ return wResult;
+}
+#endif
+
+#ifdef SUPPORT_BIG_ENDIAN
+/*********************************************************************
+* Function: FTL_Invert_Block_Table
+* Inputs: none
+* Outputs: none
+* Description: Re-format the block table in ram based on BIG_ENDIAN and
+* LARGE_BLOCKNUM if necessary
+**********************************************************************/
+static void FTL_Invert_Block_Table(void)
+{
+ u32 i;
+ u32 *pbt = (u32 *)g_pBlockTable;
+
+ nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n",
+ __FILE__, __LINE__, __func__);
+
+#ifdef SUPPORT_LARGE_BLOCKNUM
+ for (i = 0; i < DeviceInfo.wDataBlockNum; i++) {
+ pbt[i] = INVERTUINT32(pbt[i]);
+ g_pWearCounter[i] = INVERTUINT32(g_pWearCounter[i]);
+ }
+#else
+ for (i = 0; i < DeviceInfo.wDataBlockNum; i++) {
+ pbt[i] = INVERTUINT16(pbt[i]);
+ g_pWearCounter[i] = INVERTUINT16(g_pWearCounter[i]);
+ }
+#endif
+}
+#endif
+
+/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
+* Function: GLOB_FTL_Flash_Init
+* Inputs: none
+* Outputs: PASS=0 / FAIL=0x01 (based on read ID)
+* Description: The flash controller is initialized
+* The flash device is reset
+* Perform a flash READ ID command to confirm that a
+* valid device is attached and active.
+* The DeviceInfo structure gets filled in
+*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/
+int GLOB_FTL_Flash_Init(void)
+{
+ int status = FAIL;
+
+ nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n",
+ __FILE__, __LINE__, __func__);
+
+ g_SBDCmdIndex = 0;
+
+ GLOB_LLD_Flash_Init();
+
+ status = GLOB_LLD_Read_Device_ID();
+
+ return status;
+}
+
+/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
+* Inputs: none
+* Outputs: PASS=0 / FAIL=0x01 (based on read ID)
+* Description: The flash controller is released
+*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/
+int GLOB_FTL_Flash_Release(void)
+{
+ nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n",
+ __FILE__, __LINE__, __func__);
+
+ return GLOB_LLD_Flash_Release();
+}
+
+
+/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
+* Function: GLOB_FTL_Cache_Release
+* Inputs: none
+* Outputs: none
+* Description: release all allocated memory in GLOB_FTL_Init
+* (allocated in GLOB_FTL_Init)
+*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/
+void GLOB_FTL_Cache_Release(void)
+{
+ nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n",
+ __FILE__, __LINE__, __func__);
+
+ free_memory();
+}
+
+/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
+* Function: FTL_Cache_If_Hit
+* Inputs: Page Address
+* Outputs: Block number/UNHIT BLOCK
+* Description: Determines if the addressed page is in cache
+*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/
+static u16 FTL_Cache_If_Hit(u64 page_addr)
+{
+ u16 item;
+ u64 addr;
+ int i;
+
+ nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n",
+ __FILE__, __LINE__, __func__);
+
+ item = UNHIT_CACHE_ITEM;
+ for (i = 0; i < CACHE_ITEM_NUM; i++) {
+ addr = Cache.array[i].address;
+ if ((page_addr >= addr) &&
+ (page_addr < (addr + Cache.cache_item_size))) {
+ item = i;
+ break;
+ }
+ }
+
+ return item;
+}
+
+/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
+* Function: FTL_Calculate_LRU
+* Inputs: None
+* Outputs: None
+* Description: Calculate the least recently block in a cache and record its
+* index in LRU field.
+*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/
+static void FTL_Calculate_LRU(void)
+{
+ u16 i, bCurrentLRU, bTempCount;
+
+ nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n",
+ __FILE__, __LINE__, __func__);
+
+ bCurrentLRU = 0;
+ bTempCount = MAX_WORD_VALUE;
+
+ for (i = 0; i < CACHE_ITEM_NUM; i++) {
+ if (Cache.array[i].use_cnt < bTempCount) {
+ bCurrentLRU = i;
+ bTempCount = Cache.array[i].use_cnt;
+ }
+ }
+
+ Cache.LRU = bCurrentLRU;
+}
+
+/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
+* Function: FTL_Cache_Read_Page
+* Inputs: pointer to read buffer, logical address and cache item number
+* Outputs: None
+* Description: Read the page from the cached block addressed by blocknumber
+*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/
+static void FTL_Cache_Read_Page(u8 *data_buf, u64 logic_addr, u16 cache_item)
+{
+ u8 *start_addr;
+
+ nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n",
+ __FILE__, __LINE__, __func__);
+
+ start_addr = Cache.array[cache_item].buf;
+ start_addr += (u32)(((logic_addr - Cache.array[cache_item].address) >>
+ DeviceInfo.nBitsInPageDataSize) * DeviceInfo.wPageDataSize);
+
+#if CMD_DMA
+ GLOB_LLD_MemCopy_CMD(data_buf, start_addr,
+ DeviceInfo.wPageDataSize, 0);
+ ftl_cmd_cnt++;
+#else
+ memcpy(data_buf, start_addr, DeviceInfo.wPageDataSize);
+#endif
+
+ if (Cache.array[cache_item].use_cnt < MAX_WORD_VALUE)
+ Cache.array[cache_item].use_cnt++;
+}
+
+/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
+* Function: FTL_Cache_Read_All
+* Inputs: pointer to read buffer,block address
+* Outputs: PASS=0 / FAIL =1
+* Description: It reads pages in cache
+*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/
+static int FTL_Cache_Read_All(u8 *pData, u64 phy_addr)
+{
+ int wResult = PASS;
+ u32 Block;
+ u32 lba;
+ u16 Page;
+ u16 PageCount;
+ u32 *pbt = (u32 *)g_pBlockTable;
+ u32 i;
+
+ Block = BLK_FROM_ADDR(phy_addr);
+ Page = PAGE_FROM_ADDR(phy_addr, Block);
+ PageCount = Cache.pages_per_item;
+
+ nand_dbg_print(NAND_DBG_DEBUG,
+ "%s, Line %d, Function: %s, Block: 0x%x\n",
+ __FILE__, __LINE__, __func__, Block);
+
+ lba = 0xffffffff;
+ for (i = 0; i < DeviceInfo.wDataBlockNum; i++) {
+ if ((pbt[i] & (~BAD_BLOCK)) == Block) {
+ lba = i;
+ if (IS_SPARE_BLOCK(i) || IS_BAD_BLOCK(i) ||
+ IS_DISCARDED_BLOCK(i)) {
+ /* Add by yunpeng -2008.12.3 */
+#if CMD_DMA
+ GLOB_LLD_MemCopy_CMD(pData, g_temp_buf,
+ PageCount * DeviceInfo.wPageDataSize, 0);
+ ftl_cmd_cnt++;
+#else
+ memset(pData, 0xFF,
+ PageCount * DeviceInfo.wPageDataSize);
+#endif
+ return wResult;
+ } else {
+ continue; /* break ?? */
+ }
+ }
+ }
+
+ if (0xffffffff == lba)
+ printk(KERN_ERR "FTL_Cache_Read_All: Block is not found in BT\n");
+
+#if CMD_DMA
+ wResult = GLOB_LLD_Read_Page_Main_cdma(pData, Block, Page,
+ PageCount, LLD_CMD_FLAG_MODE_CDMA);
+ if (DeviceInfo.MLCDevice) {
+ g_pReadCounter[Block - DeviceInfo.wSpectraStartBlock]++;
+ nand_dbg_print(NAND_DBG_DEBUG,
+ "Read Counter modified in ftl_cmd_cnt %u"
+ " Block %u Counter%u\n",
+ ftl_cmd_cnt, (unsigned int)Block,
+ g_pReadCounter[Block -
+ DeviceInfo.wSpectraStartBlock]);
+
+ p_BTableChangesDelta =
+ (struct BTableChangesDelta *)g_pBTDelta_Free;
+ g_pBTDelta_Free += sizeof(struct BTableChangesDelta);
+ p_BTableChangesDelta->ftl_cmd_cnt = ftl_cmd_cnt;
+ p_BTableChangesDelta->RC_Index =
+ Block - DeviceInfo.wSpectraStartBlock;
+ p_BTableChangesDelta->RC_Entry_Value =
+ g_pReadCounter[Block - DeviceInfo.wSpectraStartBlock];
+ p_BTableChangesDelta->ValidFields = 0xC0;
+
+ ftl_cmd_cnt++;
+
+ if (g_pReadCounter[Block - DeviceInfo.wSpectraStartBlock] >=
+ MAX_READ_COUNTER)
+ FTL_Read_Disturbance(Block);
+ if (g_cBlockTableStatus != IN_PROGRESS_BLOCK_TABLE) {
+ g_cBlockTableStatus = IN_PROGRESS_BLOCK_TABLE;
+ FTL_Write_IN_Progress_Block_Table_Page();
+ }
+ } else {
+ ftl_cmd_cnt++;
+ }
+#else
+ wResult = GLOB_LLD_Read_Page_Main(pData, Block, Page, PageCount);
+ if (wResult == FAIL)
+ return wResult;
+
+ if (DeviceInfo.MLCDevice) {
+ g_pReadCounter[Block - DeviceInfo.wSpectraStartBlock]++;
+ if (g_pReadCounter[Block - DeviceInfo.wSpectraStartBlock] >=
+ MAX_READ_COUNTER)
+ FTL_Read_Disturbance(Block);
+ if (g_cBlockTableStatus != IN_PROGRESS_BLOCK_TABLE) {
+ g_cBlockTableStatus = IN_PROGRESS_BLOCK_TABLE;
+ FTL_Write_IN_Progress_Block_Table_Page();
+ }
+ }
+#endif
+ return wResult;
+}
+
+/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
+* Function: FTL_Cache_Write_All
+* Inputs: pointer to cache in sys memory
+* address of free block in flash
+* Outputs: PASS=0 / FAIL=1
+* Description: writes all the pages of the block in cache to flash
+*
+* NOTE:need to make sure this works ok when cache is limited
+* to a partial block. This is where copy-back would be
+* activated. This would require knowing which pages in the
+* cached block are clean/dirty.Right now we only know if
+* the whole block is clean/dirty.
+*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/
+static int FTL_Cache_Write_All(u8 *pData, u64 blk_addr)
+{
+ u16 wResult = PASS;
+ u32 Block;
+ u16 Page;
+ u16 PageCount;
+
+ nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n",
+ __FILE__, __LINE__, __func__);
+
+ nand_dbg_print(NAND_DBG_DEBUG, "This block %d going to be written "
+ "on %d\n", cache_block_to_write,
+ (u32)(blk_addr >> DeviceInfo.nBitsInBlockDataSize));
+
+ Block = BLK_FROM_ADDR(blk_addr);
+ Page = PAGE_FROM_ADDR(blk_addr, Block);
+ PageCount = Cache.pages_per_item;
+
+#if CMD_DMA
+ if (FAIL == GLOB_LLD_Write_Page_Main_cdma(pData,
+ Block, Page, PageCount)) {
+ nand_dbg_print(NAND_DBG_WARN,
+ "NAND Program fail in %s, Line %d, "
+ "Function: %s, new Bad Block %d generated! "
+ "Need Bad Block replacing.\n",
+ __FILE__, __LINE__, __func__, Block);
+ wResult = FAIL;
+ }
+ ftl_cmd_cnt++;
+#else
+ if (FAIL == GLOB_LLD_Write_Page_Main(pData, Block, Page, PageCount)) {
+ nand_dbg_print(NAND_DBG_WARN, "NAND Program fail in %s,"
+ " Line %d, Function %s, new Bad Block %d generated!"
+ "Need Bad Block replacing.\n",
+ __FILE__, __LINE__, __func__, Block);
+ wResult = FAIL;
+ }
+#endif
+ return wResult;
+}
+
+/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
+* Function: FTL_Cache_Update_Block
+* Inputs: pointer to buffer,page address,block address
+* Outputs: PASS=0 / FAIL=1
+* Description: It updates the cache
+*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/
+static int FTL_Cache_Update_Block(u8 *pData,
+ u64 old_page_addr, u64 blk_addr)
+{
+ int i, j;
+ u8 *buf = pData;
+ int wResult = PASS;
+ int wFoundInCache;
+ u64 page_addr;
+ u64 addr;
+ u64 old_blk_addr;
+ u16 page_offset;
+
+ nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n",
+ __FILE__, __LINE__, __func__);
+
+ old_blk_addr = (u64)(old_page_addr >>
+ DeviceInfo.nBitsInBlockDataSize) * DeviceInfo.wBlockDataSize;
+ page_offset = (u16)(GLOB_u64_Remainder(old_page_addr, 2) >>
+ DeviceInfo.nBitsInPageDataSize);
+
+ for (i = 0; i < DeviceInfo.wPagesPerBlock; i += Cache.pages_per_item) {
+ page_addr = old_blk_addr + i * DeviceInfo.wPageDataSize;
+ if (i != page_offset) {
+ wFoundInCache = FAIL;
+ for (j = 0; j < CACHE_ITEM_NUM; j++) {
+ addr = Cache.array[j].address;
+ addr = FTL_Get_Physical_Block_Addr(addr) +
+ GLOB_u64_Remainder(addr, 2);
+ if ((addr >= page_addr) && addr <
+ (page_addr + Cache.cache_item_size)) {
+ wFoundInCache = PASS;
+ buf = Cache.array[j].buf;
+ Cache.array[j].changed = SET;
+#if CMD_DMA
+#if RESTORE_CACHE_ON_CDMA_CHAIN_FAILURE
+ int_cache[ftl_cmd_cnt].item = j;
+ int_cache[ftl_cmd_cnt].cache.address =
+ Cache.array[j].address;
+ int_cache[ftl_cmd_cnt].cache.changed =
+ Cache.array[j].changed;
+#endif
+#endif
+ break;
+ }
+ }
+ if (FAIL == wFoundInCache) {
+ if (ERR == FTL_Cache_Read_All(g_pTempBuf,
+ page_addr)) {
+ wResult = FAIL;
+ break;
+ }
+ buf = g_pTempBuf;
+ }
+ } else {
+ buf = pData;
+ }
+
+ if (FAIL == FTL_Cache_Write_All(buf,
+ blk_addr + (page_addr - old_blk_addr))) {
+ wResult = FAIL;
+ break;
+ }
+ }
+
+ return wResult;
+}
+
+/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
+* Function: FTL_Copy_Block
+* Inputs: source block address
+* Destination block address
+* Outputs: PASS=0 / FAIL=1
+* Description: used only for static wear leveling to move the block
+* containing static data to new blocks(more worn)
+*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/
+int FTL_Copy_Block(u64 old_blk_addr, u64 blk_addr)
+{
+ int i, r1, r2, wResult = PASS;
+
+ nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n",
+ __FILE__, __LINE__, __func__);
+
+ for (i = 0; i < DeviceInfo.wPagesPerBlock; i += Cache.pages_per_item) {
+ r1 = FTL_Cache_Read_All(g_pTempBuf, old_blk_addr +
+ i * DeviceInfo.wPageDataSize);
+ r2 = FTL_Cache_Write_All(g_pTempBuf, blk_addr +
+ i * DeviceInfo.wPageDataSize);
+ if ((ERR == r1) || (FAIL == r2)) {
+ wResult = FAIL;
+ break;
+ }
+ }
+
+ return wResult;
+}
+
+/* Search the block table to find out the least wear block and then return it */
+static u32 find_least_worn_blk_for_l2_cache(void)
+{
+ int i;
+ u32 *pbt = (u32 *)g_pBlockTable;
+ u8 least_wear_cnt = MAX_BYTE_VALUE;
+ u32 least_wear_blk_idx = MAX_U32_VALUE;
+ u32 phy_idx;
+
+ for (i = 0; i < DeviceInfo.wDataBlockNum; i++) {
+ if (IS_SPARE_BLOCK(i)) {
+ phy_idx = (u32)((~BAD_BLOCK) & pbt[i]);
+ if (phy_idx > DeviceInfo.wSpectraEndBlock)
+ printk(KERN_ERR "find_least_worn_blk_for_l2_cache: "
+ "Too big phy block num (%d)\n", phy_idx);
+ if (g_pWearCounter[phy_idx -DeviceInfo.wSpectraStartBlock] < least_wear_cnt) {
+ least_wear_cnt = g_pWearCounter[phy_idx - DeviceInfo.wSpectraStartBlock];
+ least_wear_blk_idx = i;
+ }
+ }
+ }
+
+ nand_dbg_print(NAND_DBG_WARN,
+ "find_least_worn_blk_for_l2_cache: "
+ "find block %d with least worn counter (%d)\n",
+ least_wear_blk_idx, least_wear_cnt);
+
+ return least_wear_blk_idx;
+}
+
+
+
+/* Get blocks for Level2 Cache */
+static int get_l2_cache_blks(void)
+{
+ int n;
+ u32 blk;
+ u32 *pbt = (u32 *)g_pBlockTable;
+
+ for (n = 0; n < BLK_NUM_FOR_L2_CACHE; n++) {
+ blk = find_least_worn_blk_for_l2_cache();
+ if (blk > DeviceInfo.wDataBlockNum) {
+ nand_dbg_print(NAND_DBG_WARN,
+ "find_least_worn_blk_for_l2_cache: "
+ "No enough free NAND blocks (n: %d) for L2 Cache!\n", n);
+ return FAIL;
+ }
+ /* Tag the free block as discard in block table */
+ pbt[blk] = (pbt[blk] & (~BAD_BLOCK)) | DISCARD_BLOCK;
+ /* Add the free block to the L2 Cache block array */
+ cache_l2.blk_array[n] = pbt[blk] & (~BAD_BLOCK);
+ }
+
+ return PASS;
+}
+
+static int erase_l2_cache_blocks(void)
+{
+ int i, ret = PASS;
+ u32 pblk, lblk;
+ u64 addr;
+ u32 *pbt = (u32 *)g_pBlockTable;
+
+ nand_dbg_print(NAND_DBG_WARN, "%s, Line %d, Function: %s\n",
+ __FILE__, __LINE__, __func__);
+
+ for (i = 0; i < BLK_NUM_FOR_L2_CACHE; i++) {
+ pblk = cache_l2.blk_array[i];
+
+ /* If the L2 cache block is invalid, then just skip it */
+ if (MAX_U32_VALUE == pblk)
+ continue;
+
+ BUG_ON(pblk > DeviceInfo.wSpectraEndBlock);
+
+ addr = (u64)pblk << DeviceInfo.nBitsInBlockDataSize;
+ if (PASS == GLOB_FTL_Block_Erase(addr)) {
+ /* Get logical block number of the erased block */
+ lblk = FTL_Get_Block_Index(pblk);
+ BUG_ON(BAD_BLOCK == lblk);
+ /* Tag it as free in the block table */
+ pbt[lblk] &= (u32)(~DISCARD_BLOCK);
+ pbt[lblk] |= (u32)(SPARE_BLOCK);
+ } else {
+ MARK_BLOCK_AS_BAD(pbt[lblk]);
+ ret = ERR;
+ }
+ }
+
+ return ret;
+}
+
+/*
+ * Merge the valid data page in the L2 cache blocks into NAND.
+*/
+static int flush_l2_cache(void)
+{
+ struct list_head *p;
+ struct spectra_l2_cache_list *pnd, *tmp_pnd;
+ u32 *pbt = (u32 *)g_pBlockTable;
+ u32 phy_blk, l2_blk;
+ u64 addr;
+ u16 l2_page;
+ int i, ret = PASS;
+
+ nand_dbg_print(NAND_DBG_WARN, "%s, Line %d, Function: %s\n",
+ __FILE__, __LINE__, __func__);
+
+ if (list_empty(&cache_l2.table.list)) /* No data to flush */
+ return ret;
+
+ //dump_cache_l2_table();
+
+ if (IN_PROGRESS_BLOCK_TABLE != g_cBlockTableStatus) {
+ g_cBlockTableStatus = IN_PROGRESS_BLOCK_TABLE;
+ FTL_Write_IN_Progress_Block_Table_Page();
+ }
+
+ list_for_each(p, &cache_l2.table.list) {
+ pnd = list_entry(p, struct spectra_l2_cache_list, list);
+ if (IS_SPARE_BLOCK(pnd->logical_blk_num) ||
+ IS_BAD_BLOCK(pnd->logical_blk_num) ||
+ IS_DISCARDED_BLOCK(pnd->logical_blk_num)) {
+ nand_dbg_print(NAND_DBG_WARN, "%s, Line %d\n", __FILE__, __LINE__);
+ memset(cache_l2_blk_buf, 0xff, DeviceInfo.wPagesPerBlock * DeviceInfo.wPageDataSize);
+ } else {
+ nand_dbg_print(NAND_DBG_WARN, "%s, Line %d\n", __FILE__, __LINE__);
+ phy_blk = pbt[pnd->logical_blk_num] & (~BAD_BLOCK);
+ ret = GLOB_LLD_Read_Page_Main(cache_l2_blk_buf,
+ phy_blk, 0, DeviceInfo.wPagesPerBlock);
+ if (ret == FAIL) {
+ printk(KERN_ERR "Read NAND page fail in %s, Line %d\n", __FILE__, __LINE__);
+ }
+ }
+
+ for (i = 0; i < DeviceInfo.wPagesPerBlock; i++) {
+ if (pnd->pages_array[i] != MAX_U32_VALUE) {
+ l2_blk = cache_l2.blk_array[(pnd->pages_array[i] >> 16) & 0xffff];
+ l2_page = pnd->pages_array[i] & 0xffff;
+ ret = GLOB_LLD_Read_Page_Main(cache_l2_page_buf, l2_blk, l2_page, 1);
+ if (ret == FAIL) {
+ printk(KERN_ERR "Read NAND page fail in %s, Line %d\n", __FILE__, __LINE__);
+ }
+ memcpy(cache_l2_blk_buf + i * DeviceInfo.wPageDataSize, cache_l2_page_buf, DeviceInfo.wPageDataSize);
+ }
+ }
+
+ /* Find a free block and tag the original block as discarded */
+ addr = (u64)pnd->logical_blk_num << DeviceInfo.nBitsInBlockDataSize;
+ ret = FTL_Replace_Block(addr);
+ if (ret == FAIL) {
+ printk(KERN_ERR "FTL_Replace_Block fail in %s, Line %d\n", __FILE__, __LINE__);
+ }
+
+ /* Write back the updated data into NAND */
+ phy_blk = pbt[pnd->logical_blk_num] & (~BAD_BLOCK);
+ if (FAIL == GLOB_LLD_Write_Page_Main(cache_l2_blk_buf, phy_blk, 0, DeviceInfo.wPagesPerBlock)) {
+ nand_dbg_print(NAND_DBG_WARN,
+ "Program NAND block %d fail in %s, Line %d\n",
+ phy_blk, __FILE__, __LINE__);
+ /* This may not be really a bad block. So just tag it as discarded. */
+ /* Then it has a chance to be erased when garbage collection. */
+ /* If it is really bad, then the erase will fail and it will be marked */
+ /* as bad then. Otherwise it will be marked as free and can be used again */
+ MARK_BLK_AS_DISCARD(pbt[pnd->logical_blk_num]);
+ /* Find another free block and write it again */
+ FTL_Replace_Block(addr);
+ phy_blk = pbt[pnd->logical_blk_num] & (~BAD_BLOCK);
+ if (FAIL == GLOB_LLD_Write_Page_Main(cache_l2_blk_buf, phy_blk, 0, DeviceInfo.wPagesPerBlock)) {
+ printk(KERN_ERR "Failed to write back block %d when flush L2 cache."
+ "Some data will be lost!\n", phy_blk);
+ MARK_BLOCK_AS_BAD(pbt[pnd->logical_blk_num]);
+ }
+ } else {
+ /* tag the new free block as used block */
+ pbt[pnd->logical_blk_num] &= (~SPARE_BLOCK);
+ }
+ }
+
+ /* Destroy the L2 Cache table and free the memory of all nodes */
+ list_for_each_entry_safe(pnd, tmp_pnd, &cache_l2.table.list, list) {
+ list_del(&pnd->list);
+ kfree(pnd);
+ }
+
+ /* Erase discard L2 cache blocks */
+ if (erase_l2_cache_blocks() != PASS)
+ nand_dbg_print(NAND_DBG_WARN,
+ " Erase L2 cache blocks error in %s, Line %d\n",
+ __FILE__, __LINE__);
+
+ /* Init the Level2 Cache data structure */
+ for (i = 0; i < BLK_NUM_FOR_L2_CACHE; i++)
+ cache_l2.blk_array[i] = MAX_U32_VALUE;
+ cache_l2.cur_blk_idx = 0;
+ cache_l2.cur_page_num = 0;
+ INIT_LIST_HEAD(&cache_l2.table.list);
+ cache_l2.table.logical_blk_num = MAX_U32_VALUE;
+
+ return ret;
+}
+
+/*
+ * Write back a changed victim cache item to the Level2 Cache
+ * and update the L2 Cache table to map the change.
+ * If the L2 Cache is full, then start to do the L2 Cache flush.
+*/
+static int write_back_to_l2_cache(u8 *buf, u64 logical_addr)
+{
+ u32 logical_blk_num;
+ u16 logical_page_num;
+ struct list_head *p;
+ struct spectra_l2_cache_list *pnd, *pnd_new;
+ u32 node_size;
+ int i, found;
+
+ nand_dbg_print(NAND_DBG_DEBUG, "%s, Line %d, Function: %s\n",
+ __FILE__, __LINE__, __func__);
+
+ /*
+ * If Level2 Cache table is empty, then it means either:
+ * 1. This is the first time that the function called after FTL_init
+ * or
+ * 2. The Level2 Cache has just been flushed
+ *
+ * So, 'steal' some free blocks from NAND for L2 Cache using
+ * by just mask them as discard in the block table
+ */
+ if (list_empty(&cache_l2.table.list)) {
+ BUG_ON(cache_l2.cur_blk_idx != 0);
+ BUG_ON(cache_l2.cur_page_num!= 0);
+ BUG_ON(cache_l2.table.logical_blk_num != MAX_U32_VALUE);
+ if (FAIL == get_l2_cache_blks()) {
+ GLOB_FTL_Garbage_Collection();
+ if (FAIL == get_l2_cache_blks()) {
+ printk(KERN_ALERT "Fail to get L2 cache blks!\n");
+ return FAIL;
+ }
+ }
+ }
+
+ logical_blk_num = BLK_FROM_ADDR(logical_addr);
+ logical_page_num = PAGE_FROM_ADDR(logical_addr, logical_blk_num);
+ BUG_ON(logical_blk_num == MAX_U32_VALUE);
+
+ /* Write the cache item data into the current position of L2 Cache */
+#if CMD_DMA
+ /*
+ * TODO
+ */
+#else
+ if (FAIL == GLOB_LLD_Write_Page_Main(buf,
+ cache_l2.blk_array[cache_l2.cur_blk_idx],
+ cache_l2.cur_page_num, 1)) {
+ nand_dbg_print(NAND_DBG_WARN, "NAND Program fail in "
+ "%s, Line %d, new Bad Block %d generated!\n",
+ __FILE__, __LINE__,
+ cache_l2.blk_array[cache_l2.cur_blk_idx]);
+
+ /* TODO: tag the current block as bad and try again */
+
+ return FAIL;
+ }
+#endif
+
+ /*
+ * Update the L2 Cache table.
+ *
+ * First seaching in the table to see whether the logical block
+ * has been mapped. If not, then kmalloc a new node for the
+ * logical block, fill data, and then insert it to the list.
+ * Otherwise, just update the mapped node directly.
+ */
+ found = 0;
+ list_for_each(p, &cache_l2.table.list) {
+ pnd = list_entry(p, struct spectra_l2_cache_list, list);
+ if (pnd->logical_blk_num == logical_blk_num) {
+ pnd->pages_array[logical_page_num] =
+ (cache_l2.cur_blk_idx << 16) |
+ cache_l2.cur_page_num;
+ found = 1;
+ break;
+ }
+ }
+ if (!found) { /* Create new node for the logical block here */
+
+ /* The logical pages to physical pages map array is
+ * located at the end of struct spectra_l2_cache_list.
+ */
+ node_size = sizeof(struct spectra_l2_cache_list) +
+ sizeof(u32) * DeviceInfo.wPagesPerBlock;
+ pnd_new = kmalloc(node_size, GFP_ATOMIC);
+ if (!pnd_new) {
+ printk(KERN_ERR "Failed to kmalloc in %s Line %d\n",
+ __FILE__, __LINE__);
+ /*
+ * TODO: Need to flush all the L2 cache into NAND ASAP
+ * since no memory available here
+ */
+ }
+ pnd_new->logical_blk_num = logical_blk_num;
+ for (i = 0; i < DeviceInfo.wPagesPerBlock; i++)
+ pnd_new->pages_array[i] = MAX_U32_VALUE;
+ pnd_new->pages_array[logical_page_num] =
+ (cache_l2.cur_blk_idx << 16) | cache_l2.cur_page_num;
+ list_add(&pnd_new->list, &cache_l2.table.list);
+ }
+
+ /* Increasing the current position pointer of the L2 Cache */
+ cache_l2.cur_page_num++;
+ if (cache_l2.cur_page_num >= DeviceInfo.wPagesPerBlock) {
+ cache_l2.cur_blk_idx++;
+ if (cache_l2.cur_blk_idx >= BLK_NUM_FOR_L2_CACHE) {
+ /* The L2 Cache is full. Need to flush it now */
+ nand_dbg_print(NAND_DBG_WARN,
+ "L2 Cache is full, will start to flush it\n");
+ flush_l2_cache();
+ } else {
+ cache_l2.cur_page_num = 0;
+ }
+ }
+
+ return PASS;
+}
+
+/*
+ * Seach in the Level2 Cache table to find the cache item.
+ * If find, read the data from the NAND page of L2 Cache,
+ * Otherwise, return FAIL.
+ */
+static int search_l2_cache(u8 *buf, u64 logical_addr)
+{
+ u32 logical_blk_num;
+ u16 logical_page_num;
+ struct list_head *p;
+ struct spectra_l2_cache_list *pnd;
+ u32 tmp = MAX_U32_VALUE;
+ u32 phy_blk;
+ u16 phy_page;
+ int ret = FAIL;
+
+ logical_blk_num = BLK_FROM_ADDR(logical_addr);
+ logical_page_num = PAGE_FROM_ADDR(logical_addr, logical_blk_num);
+
+ list_for_each(p, &cache_l2.table.list) {
+ pnd = list_entry(p, struct spectra_l2_cache_list, list);
+ if (pnd->logical_blk_num == logical_blk_num) {
+ tmp = pnd->pages_array[logical_page_num];
+ break;
+ }
+ }
+
+ if (tmp != MAX_U32_VALUE) { /* Found valid map */
+ phy_blk = cache_l2.blk_array[(tmp >> 16) & 0xFFFF];
+ phy_page = tmp & 0xFFFF;
+#if CMD_DMA
+ /* TODO */
+#else
+ ret = GLOB_LLD_Read_Page_Main(buf, phy_blk, phy_page, 1);
+#endif
+ }
+
+ return ret;
+}
+
+/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
+* Function: FTL_Cache_Write_Back
+* Inputs: pointer to data cached in sys memory
+* address of free block in flash
+* Outputs: PASS=0 / FAIL=1
+* Description: writes all the pages of Cache Block to flash
+*
+*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/
+static int FTL_Cache_Write_Back(u8 *pData, u64 blk_addr)
+{
+ int i, j, iErase;
+ u64 old_page_addr, addr, phy_addr;
+ u32 *pbt = (u32 *)g_pBlockTable;
+ u32 lba;
+
+ nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n",
+ __FILE__, __LINE__, __func__);
+
+ old_page_addr = FTL_Get_Physical_Block_Addr(blk_addr) +
+ GLOB_u64_Remainder(blk_addr, 2);
+
+ iErase = (FAIL == FTL_Replace_Block(blk_addr)) ? PASS : FAIL;
+
+ pbt[BLK_FROM_ADDR(blk_addr)] &= (~SPARE_BLOCK);
+
+#if CMD_DMA
+ p_BTableChangesDelta = (struct BTableChangesDelta *)g_pBTDelta_Free;
+ g_pBTDelta_Free += sizeof(struct BTableChangesDelta);
+
+ p_BTableChangesDelta->ftl_cmd_cnt = ftl_cmd_cnt;
+ p_BTableChangesDelta->BT_Index = (u32)(blk_addr >>
+ DeviceInfo.nBitsInBlockDataSize);
+ p_BTableChangesDelta->BT_Entry_Value =
+ pbt[(u32)(blk_addr >> DeviceInfo.nBitsInBlockDataSize)];
+ p_BTableChangesDelta->ValidFields = 0x0C;
+#endif
+
+ if (IN_PROGRESS_BLOCK_TABLE != g_cBlockTableStatus) {
+ g_cBlockTableStatus = IN_PROGRESS_BLOCK_TABLE;
+ FTL_Write_IN_Progress_Block_Table_Page();
+ }
+
+ for (i = 0; i < RETRY_TIMES; i++) {
+ if (PASS == iErase) {
+ phy_addr = FTL_Get_Physical_Block_Addr(blk_addr);
+ if (FAIL == GLOB_FTL_Block_Erase(phy_addr)) {
+ lba = BLK_FROM_ADDR(blk_addr);
+ MARK_BLOCK_AS_BAD(pbt[lba]);
+ i = RETRY_TIMES;
+ break;
+ }
+ }
+
+ for (j = 0; j < CACHE_ITEM_NUM; j++) {
+ addr = Cache.array[j].address;
+ if ((addr <= blk_addr) &&
+ ((addr + Cache.cache_item_size) > blk_addr))
+ cache_block_to_write = j;
+ }
+
+ phy_addr = FTL_Get_Physical_Block_Addr(blk_addr);
+ if (PASS == FTL_Cache_Update_Block(pData,
+ old_page_addr, phy_addr)) {
+ cache_block_to_write = UNHIT_CACHE_ITEM;
+ break;
+ } else {
+ iErase = PASS;
+ }
+ }
+
+ if (i >= RETRY_TIMES) {
+ if (ERR == FTL_Flash_Error_Handle(pData,
+ old_page_addr, blk_addr))
+ return ERR;
+ else
+ return FAIL;
+ }
+
+ return PASS;
+}
+
+/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
+* Function: FTL_Cache_Write_Page
+* Inputs: Pointer to buffer, page address, cache block number
+* Outputs: PASS=0 / FAIL=1
+* Description: It writes the data in Cache Block
+*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/
+static void FTL_Cache_Write_Page(u8 *pData, u64 page_addr,
+ u8 cache_blk, u16 flag)
+{
+ u8 *pDest;
+ u64 addr;
+
+ nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n",
+ __FILE__, __LINE__, __func__);
+
+ addr = Cache.array[cache_blk].address;
+ pDest = Cache.array[cache_blk].buf;
+
+ pDest += (unsigned long)(page_addr - addr);
+ Cache.array[cache_blk].changed = SET;
+#if CMD_DMA
+#if RESTORE_CACHE_ON_CDMA_CHAIN_FAILURE
+ int_cache[ftl_cmd_cnt].item = cache_blk;
+ int_cache[ftl_cmd_cnt].cache.address =
+ Cache.array[cache_blk].address;
+ int_cache[ftl_cmd_cnt].cache.changed =
+ Cache.array[cache_blk].changed;
+#endif
+ GLOB_LLD_MemCopy_CMD(pDest, pData, DeviceInfo.wPageDataSize, flag);
+ ftl_cmd_cnt++;
+#else
+ memcpy(pDest, pData, DeviceInfo.wPageDataSize);
+#endif
+ if (Cache.array[cache_blk].use_cnt < MAX_WORD_VALUE)
+ Cache.array[cache_blk].use_cnt++;
+}
+
+/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
+* Function: FTL_Cache_Write
+* Inputs: none
+* Outputs: PASS=0 / FAIL=1
+* Description: It writes least frequently used Cache block to flash if it
+* has been changed
+*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/
+static int FTL_Cache_Write(void)
+{
+ int i, bResult = PASS;
+ u16 bNO, least_count = 0xFFFF;
+
+ nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n",
+ __FILE__, __LINE__, __func__);
+
+ FTL_Calculate_LRU();
+
+ bNO = Cache.LRU;
+ nand_dbg_print(NAND_DBG_DEBUG, "FTL_Cache_Write: "
+ "Least used cache block is %d\n", bNO);
+
+ if (Cache.array[bNO].changed != SET)
+ return bResult;
+
+ nand_dbg_print(NAND_DBG_DEBUG, "FTL_Cache_Write: Cache"
+ " Block %d containing logical block %d is dirty\n",
+ bNO,
+ (u32)(Cache.array[bNO].address >>
+ DeviceInfo.nBitsInBlockDataSize));
+#if CMD_DMA
+#if RESTORE_CACHE_ON_CDMA_CHAIN_FAILURE
+ int_cache[ftl_cmd_cnt].item = bNO;
+ int_cache[ftl_cmd_cnt].cache.address =
+ Cache.array[bNO].address;
+ int_cache[ftl_cmd_cnt].cache.changed = CLEAR;
+#endif
+#endif
+ bResult = write_back_to_l2_cache(Cache.array[bNO].buf,
+ Cache.array[bNO].address);
+ if (bResult != ERR)
+ Cache.array[bNO].changed = CLEAR;
+
+ least_count = Cache.array[bNO].use_cnt;
+
+ for (i = 0; i < CACHE_ITEM_NUM; i++) {
+ if (i == bNO)
+ continue;
+ if (Cache.array[i].use_cnt > 0)
+ Cache.array[i].use_cnt -= least_count;
+ }
+
+ return bResult;
+}
+
+/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
+* Function: FTL_Cache_Read
+* Inputs: Page address
+* Outputs: PASS=0 / FAIL=1
+* Description: It reads the block from device in Cache Block
+* Set the LRU count to 1
+* Mark the Cache Block as clean
+*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/
+static int FTL_Cache_Read(u64 logical_addr)
+{
+ u64 item_addr, phy_addr;
+ u16 num;
+ int ret;
+
+ nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n",
+ __FILE__, __LINE__, __func__);
+
+ num = Cache.LRU; /* The LRU cache item will be overwritten */
+
+ item_addr = (u64)GLOB_u64_Div(logical_addr, Cache.cache_item_size) *
+ Cache.cache_item_size;
+ Cache.array[num].address = item_addr;
+ Cache.array[num].use_cnt = 1;
+ Cache.array[num].changed = CLEAR;
+
+#if CMD_DMA
+#if RESTORE_CACHE_ON_CDMA_CHAIN_FAILURE
+ int_cache[ftl_cmd_cnt].item = num;
+ int_cache[ftl_cmd_cnt].cache.address =
+ Cache.array[num].address;
+ int_cache[ftl_cmd_cnt].cache.changed =
+ Cache.array[num].changed;
+#endif
+#endif
+ /*
+ * Search in L2 Cache. If hit, fill data into L1 Cache item buffer,
+ * Otherwise, read it from NAND
+ */
+ ret = search_l2_cache(Cache.array[num].buf, logical_addr);
+ if (PASS == ret) /* Hit in L2 Cache */
+ return ret;
+
+ /* Compute the physical start address of NAND device according to */
+ /* the logical start address of the cache item (LRU cache item) */
+ phy_addr = FTL_Get_Physical_Block_Addr(item_addr) +
+ GLOB_u64_Remainder(item_addr, 2);
+
+ return FTL_Cache_Read_All(Cache.array[num].buf, phy_addr);
+}
+
+/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
+* Function: FTL_Check_Block_Table
+* Inputs: ?
+* Outputs: PASS=0 / FAIL=1
+* Description: It checks the correctness of each block table entry
+*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/
+static int FTL_Check_Block_Table(int wOldTable)
+{
+ u32 i;
+ int wResult = PASS;
+ u32 blk_idx;
+ u32 *pbt = (u32 *)g_pBlockTable;
+ u8 *pFlag = flag_check_blk_table;
+
+ nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n",
+ __FILE__, __LINE__, __func__);
+
+ if (NULL != pFlag) {
+ memset(pFlag, FAIL, DeviceInfo.wDataBlockNum);
+ for (i = 0; i < DeviceInfo.wDataBlockNum; i++) {
+ blk_idx = (u32)(pbt[i] & (~BAD_BLOCK));
+
+ /*
+ * 20081006/KBV - Changed to pFlag[i] reference
+ * to avoid buffer overflow
+ */
+
+ /*
+ * 2008-10-20 Yunpeng Note: This change avoid
+ * buffer overflow, but changed function of
+ * the code, so it should be re-write later
+ */
+ if ((blk_idx > DeviceInfo.wSpectraEndBlock) ||
+ PASS == pFlag[i]) {
+ wResult = FAIL;
+ break;
+ } else {
+ pFlag[i] = PASS;
+ }
+ }
+ }
+
+ return wResult;
+}
+
+
+/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
+* Function: FTL_Write_Block_Table
+* Inputs: flasg
+* Outputs: 0=Block Table was updated. No write done. 1=Block write needs to
+* happen. -1 Error
+* Description: It writes the block table
+* Block table always mapped to LBA 0 which inturn mapped
+* to any physical block
+*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/
+static int FTL_Write_Block_Table(int wForce)
+{
+ u32 *pbt = (u32 *)g_pBlockTable;
+ int wSuccess = PASS;
+ u32 wTempBlockTableIndex;
+ u16 bt_pages, new_bt_offset;
+ u8 blockchangeoccured = 0;
+
+ nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n",
+ __FILE__, __LINE__, __func__);
+
+ bt_pages = FTL_Get_Block_Table_Flash_Size_Pages();
+
+ if (IN_PROGRESS_BLOCK_TABLE != g_cBlockTableStatus)
+ return 0;
+
+ if (PASS == wForce) {
+ g_wBlockTableOffset =
+ (u16)(DeviceInfo.wPagesPerBlock - bt_pages);
+#if CMD_DMA
+ p_BTableChangesDelta =
+ (struct BTableChangesDelta *)g_pBTDelta_Free;
+ g_pBTDelta_Free += sizeof(struct BTableChangesDelta);
+
+ p_BTableChangesDelta->ftl_cmd_cnt = ftl_cmd_cnt;
+ p_BTableChangesDelta->g_wBlockTableOffset =
+ g_wBlockTableOffset;
+ p_BTableChangesDelta->ValidFields = 0x01;
+#endif
+ }
+
+ nand_dbg_print(NAND_DBG_DEBUG,
+ "Inside FTL_Write_Block_Table: block %d Page:%d\n",
+ g_wBlockTableIndex, g_wBlockTableOffset);
+
+ do {
+ new_bt_offset = g_wBlockTableOffset + bt_pages + 1;
+ if ((0 == (new_bt_offset % DeviceInfo.wPagesPerBlock)) ||
+ (new_bt_offset > DeviceInfo.wPagesPerBlock) ||
+ (FAIL == wSuccess)) {
+ wTempBlockTableIndex = FTL_Replace_Block_Table();
+ if (BAD_BLOCK == wTempBlockTableIndex)
+ return ERR;
+ if (!blockchangeoccured) {
+ bt_block_changed = 1;
+ blockchangeoccured = 1;
+ }
+
+ g_wBlockTableIndex = wTempBlockTableIndex;
+ g_wBlockTableOffset = 0;
+ pbt[BLOCK_TABLE_INDEX] = g_wBlockTableIndex;
+#if CMD_DMA
+ p_BTableChangesDelta =
+ (struct BTableChangesDelta *)g_pBTDelta_Free;
+ g_pBTDelta_Free += sizeof(struct BTableChangesDelta);
+
+ p_BTableChangesDelta->ftl_cmd_cnt =
+ ftl_cmd_cnt;
+ p_BTableChangesDelta->g_wBlockTableOffset =
+ g_wBlockTableOffset;
+ p_BTableChangesDelta->g_wBlockTableIndex =
+ g_wBlockTableIndex;
+ p_BTableChangesDelta->ValidFields = 0x03;
+
+ p_BTableChangesDelta =
+ (struct BTableChangesDelta *)g_pBTDelta_Free;
+ g_pBTDelta_Free +=
+ sizeof(struct BTableChangesDelta);
+
+ p_BTableChangesDelta->ftl_cmd_cnt =
+ ftl_cmd_cnt;
+ p_BTableChangesDelta->BT_Index =
+ BLOCK_TABLE_INDEX;
+ p_BTableChangesDelta->BT_Entry_Value =
+ pbt[BLOCK_TABLE_INDEX];
+ p_BTableChangesDelta->ValidFields = 0x0C;
+#endif
+ }
+
+ wSuccess = FTL_Write_Block_Table_Data();
+ if (FAIL == wSuccess)
+ MARK_BLOCK_AS_BAD(pbt[BLOCK_TABLE_INDEX]);
+ } while (FAIL == wSuccess);
+
+ g_cBlockTableStatus = CURRENT_BLOCK_TABLE;
+
+ return 1;
+}
+
+/******************************************************************
+* Function: GLOB_FTL_Flash_Format
+* Inputs: none
+* Outputs: PASS
+* Description: The block table stores bad block info, including MDF+
+* blocks gone bad over the ages. Therefore, if we have a
+* block table in place, then use it to scan for bad blocks
+* If not, then scan for MDF.
+* Now, a block table will only be found if spectra was already
+* being used. For a fresh flash, we'll go thru scanning for
+* MDF. If spectra was being used, then there is a chance that
+* the MDF has been corrupted. Spectra avoids writing to the
+* first 2 bytes of the spare area to all pages in a block. This
+* covers all known flash devices. However, since flash
+* manufacturers have no standard of where the MDF is stored,
+* this cannot guarantee that the MDF is protected for future
+* devices too. The initial scanning for the block table assures
+* this. It is ok even if the block table is outdated, as all
+* we're looking for are bad block markers.
+* Use this when mounting a file system or starting a
+* new flash.
+*
+*********************************************************************/
+static int FTL_Format_Flash(u8 valid_block_table)
+{
+ u32 i, j;
+ u32 *pbt = (u32 *)g_pBlockTable;
+ u32 tempNode;
+ int ret;
+
+#if CMD_DMA
+ u32 *pbtStartingCopy = (u32 *)g_pBTStartingCopy;
+ if (ftl_cmd_cnt)
+ return FAIL;
+#endif
+
+ if (FAIL == FTL_Check_Block_Table(FAIL))
+ valid_block_table = 0;
+
+ if (valid_block_table) {
+ u8 switched = 1;
+ u32 block, k;
+
+ k = DeviceInfo.wSpectraStartBlock;
+ while (switched && (k < DeviceInfo.wSpectraEndBlock)) {
+ switched = 0;
+ k++;
+ for (j = DeviceInfo.wSpectraStartBlock, i = 0;
+ j <= DeviceInfo.wSpectraEndBlock;
+ j++, i++) {
+ block = (pbt[i] & ~BAD_BLOCK) -
+ DeviceInfo.wSpectraStartBlock;
+ if (block != i) {
+ switched = 1;
+ tempNode = pbt[i];
+ pbt[i] = pbt[block];
+ pbt[block] = tempNode;
+ }
+ }
+ }
+ if ((k == DeviceInfo.wSpectraEndBlock) && switched)
+ valid_block_table = 0;
+ }
+
+ if (!valid_block_table) {
+ memset(g_pBlockTable, 0,
+ DeviceInfo.wDataBlockNum * sizeof(u32));
+ memset(g_pWearCounter, 0,
+ DeviceInfo.wDataBlockNum * sizeof(u8));
+ if (DeviceInfo.MLCDevice)
+ memset(g_pReadCounter, 0,
+ DeviceInfo.wDataBlockNum * sizeof(u16));
+#if CMD_DMA
+ memset(g_pBTStartingCopy, 0,
+ DeviceInfo.wDataBlockNum * sizeof(u32));
+ memset(g_pWearCounterCopy, 0,
+ DeviceInfo.wDataBlockNum * sizeof(u8));
+ if (DeviceInfo.MLCDevice)
+ memset(g_pReadCounterCopy, 0,
+ DeviceInfo.wDataBlockNum * sizeof(u16));
+#endif
+ for (j = DeviceInfo.wSpectraStartBlock, i = 0;
+ j <= DeviceInfo.wSpectraEndBlock;
+ j++, i++) {
+ if (GLOB_LLD_Get_Bad_Block((u32)j))
+ pbt[i] = (u32)(BAD_BLOCK | j);
+ }
+ }
+
+ nand_dbg_print(NAND_DBG_WARN, "Erasing all blocks in the NAND\n");
+
+ for (j = DeviceInfo.wSpectraStartBlock, i = 0;
+ j <= DeviceInfo.wSpectraEndBlock;
+ j++, i++) {
+ if ((pbt[i] & BAD_BLOCK) != BAD_BLOCK) {
+ ret = GLOB_LLD_Erase_Block(j);
+ if (FAIL == ret) {
+ pbt[i] = (u32)(j);
+ MARK_BLOCK_AS_BAD(pbt[i]);
+ nand_dbg_print(NAND_DBG_WARN,
+ "NAND Program fail in %s, Line %d, "
+ "Function: %s, new Bad Block %d generated!\n",
+ __FILE__, __LINE__, __func__, (int)j);
+ } else {
+ pbt[i] = (u32)(SPARE_BLOCK | j);
+ }
+ }
+#if CMD_DMA
+ pbtStartingCopy[i] = pbt[i];
+#endif
+ }
+
+ g_wBlockTableOffset = 0;
+ for (i = 0; (i <= (DeviceInfo.wSpectraEndBlock -
+ DeviceInfo.wSpectraStartBlock))
+ && ((pbt[i] & BAD_BLOCK) == BAD_BLOCK); i++)
+ ;
+ if (i > (DeviceInfo.wSpectraEndBlock - DeviceInfo.wSpectraStartBlock)) {
+ printk(KERN_ERR "All blocks bad!\n");
+ return FAIL;
+ } else {
+ g_wBlockTableIndex = pbt[i] & ~BAD_BLOCK;
+ if (i != BLOCK_TABLE_INDEX) {
+ tempNode = pbt[i];
+ pbt[i] = pbt[BLOCK_TABLE_INDEX];
+ pbt[BLOCK_TABLE_INDEX] = tempNode;
+ }
+ }
+ pbt[BLOCK_TABLE_INDEX] &= (~SPARE_BLOCK);
+
+#if CMD_DMA
+ pbtStartingCopy[BLOCK_TABLE_INDEX] &= (~SPARE_BLOCK);
+#endif
+
+ g_cBlockTableStatus = IN_PROGRESS_BLOCK_TABLE;
+ memset(g_pBTBlocks, 0xFF,
+ (1 + LAST_BT_ID - FIRST_BT_ID) * sizeof(u32));
+ g_pBTBlocks[FIRST_BT_ID-FIRST_BT_ID] = g_wBlockTableIndex;
+ FTL_Write_Block_Table(FAIL);
+
+ for (i = 0; i < CACHE_ITEM_NUM; i++) {
+ Cache.array[i].address = NAND_CACHE_INIT_ADDR;
+ Cache.array[i].use_cnt = 0;
+ Cache.array[i].changed = CLEAR;
+ }
+
+#if (RESTORE_CACHE_ON_CDMA_CHAIN_FAILURE && CMD_DMA)
+ memcpy((void *)&cache_start_copy, (void *)&Cache,
+ sizeof(struct flash_cache_tag));
+#endif
+ return PASS;
+}
+
+static int force_format_nand(void)
+{
+ u32 i;
+
+ /* Force erase the whole unprotected physical partiton of NAND */
+ printk(KERN_ALERT "Start to force erase whole NAND device ...\n");
+ printk(KERN_ALERT "From phyical block %d to %d\n",
+ DeviceInfo.wSpectraStartBlock, DeviceInfo.wSpectraEndBlock);
+ for (i = DeviceInfo.wSpectraStartBlock; i <= DeviceInfo.wSpectraEndBlock; i++) {
+ if (GLOB_LLD_Erase_Block(i))
+ printk(KERN_ERR "Failed to force erase NAND block %d\n", i);
+ }
+ printk(KERN_ALERT "Force Erase ends. Please reboot the system ...\n");
+ while(1);
+
+ return PASS;
+}
+
+int GLOB_FTL_Flash_Format(void)
+{
+ //return FTL_Format_Flash(1);
+ return force_format_nand();
+
+}
+
+/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
+* Function: FTL_Search_Block_Table_IN_Block
+* Inputs: Block Number
+* Pointer to page
+* Outputs: PASS / FAIL
+* Page contatining the block table
+* Description: It searches the block table in the block
+* passed as an argument.
+*
+*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/
+static int FTL_Search_Block_Table_IN_Block(u32 BT_Block,
+ u8 BT_Tag, u16 *Page)
+{
+ u16 i, j, k;
+ u16 Result = PASS;
+ u16 Last_IPF = 0;
+ u8 BT_Found = 0;
+ u8 *tagarray;
+ u8 *tempbuf = tmp_buf_search_bt_in_block;
+ u8 *pSpareBuf = spare_buf_search_bt_in_block;
+ u8 *pSpareBufBTLastPage = spare_buf_bt_search_bt_in_block;
+ u8 bt_flag_last_page = 0xFF;
+ u8 search_in_previous_pages = 0;
+ u16 bt_pages;
+
+ nand_dbg_print(NAND_DBG_DEBUG, "%s, Line %d, Function: %s\n",
+ __FILE__, __LINE__, __func__);
+
+ nand_dbg_print(NAND_DBG_DEBUG,
+ "Searching block table in %u block\n",
+ (unsigned int)BT_Block);
+
+ bt_pages = FTL_Get_Block_Table_Flash_Size_Pages();
+
+ for (i = bt_pages; i < DeviceInfo.wPagesPerBlock;
+ i += (bt_pages + 1)) {
+ nand_dbg_print(NAND_DBG_DEBUG,
+ "Searching last IPF: %d\n", i);
+ Result = GLOB_LLD_Read_Page_Main_Polling(tempbuf,
+ BT_Block, i, 1);
+
+ if (0 == memcmp(tempbuf, g_pIPF, DeviceInfo.wPageDataSize)) {
+ if ((i + bt_pages + 1) < DeviceInfo.wPagesPerBlock) {
+ continue;
+ } else {
+ search_in_previous_pages = 1;
+ Last_IPF = i;
+ }
+ }
+
+ if (!search_in_previous_pages) {
+ if (i != bt_pages) {
+ i -= (bt_pages + 1);
+ Last_IPF = i;
+ }
+ }
+
+ if (0 == Last_IPF)
+ break;
+
+ if (!search_in_previous_pages) {
+ i = i + 1;
+ nand_dbg_print(NAND_DBG_DEBUG,
+ "Reading the spare area of Block %u Page %u",
+ (unsigned int)BT_Block, i);
+ Result = GLOB_LLD_Read_Page_Spare(pSpareBuf,
+ BT_Block, i, 1);
+ nand_dbg_print(NAND_DBG_DEBUG,
+ "Reading the spare area of Block %u Page %u",
+ (unsigned int)BT_Block, i + bt_pages - 1);
+ Result = GLOB_LLD_Read_Page_Spare(pSpareBufBTLastPage,
+ BT_Block, i + bt_pages - 1, 1);
+
+ k = 0;
+ j = FTL_Extract_Block_Table_Tag(pSpareBuf, &tagarray);
+ if (j) {
+ for (; k < j; k++) {
+ if (tagarray[k] == BT_Tag)
+ break;
+ }
+ }
+
+ if (k < j)
+ bt_flag = tagarray[k];
+ else
+ Result = FAIL;
+
+ if (Result == PASS) {
+ k = 0;
+ j = FTL_Extract_Block_Table_Tag(
+ pSpareBufBTLastPage, &tagarray);
+ if (j) {
+ for (; k < j; k++) {
+ if (tagarray[k] == BT_Tag)
+ break;
+ }
+ }
+
+ if (k < j)
+ bt_flag_last_page = tagarray[k];
+ else
+ Result = FAIL;
+
+ if (Result == PASS) {
+ if (bt_flag == bt_flag_last_page) {
+ nand_dbg_print(NAND_DBG_DEBUG,
+ "Block table is found"
+ " in page after IPF "
+ "at block %d "
+ "page %d\n",
+ (int)BT_Block, i);
+ BT_Found = 1;
+ *Page = i;
+ g_cBlockTableStatus =
+ CURRENT_BLOCK_TABLE;
+ break;
+ } else {
+ Result = FAIL;
+ }
+ }
+ }
+ }
+
+ if (search_in_previous_pages)
+ i = i - bt_pages;
+ else
+ i = i - (bt_pages + 1);
+
+ Result = PASS;
+
+ nand_dbg_print(NAND_DBG_DEBUG,
+ "Reading the spare area of Block %d Page %d",
+ (int)BT_Block, i);
+
+ Result = GLOB_LLD_Read_Page_Spare(pSpareBuf, BT_Block, i, 1);
+ nand_dbg_print(NAND_DBG_DEBUG,
+ "Reading the spare area of Block %u Page %u",
+ (unsigned int)BT_Block, i + bt_pages - 1);
+
+ Result = GLOB_LLD_Read_Page_Spare(pSpareBufBTLastPage,
+ BT_Block, i + bt_pages - 1, 1);
+
+ k = 0;
+ j = FTL_Extract_Block_Table_Tag(pSpareBuf, &tagarray);
+ if (j) {
+ for (; k < j; k++) {
+ if (tagarray[k] == BT_Tag)
+ break;
+ }
+ }
+
+ if (k < j)
+ bt_flag = tagarray[k];
+ else
+ Result = FAIL;
+
+ if (Result == PASS) {
+ k = 0;
+ j = FTL_Extract_Block_Table_Tag(pSpareBufBTLastPage,
+ &tagarray);
+ if (j) {
+ for (; k < j; k++) {
+ if (tagarray[k] == BT_Tag)
+ break;
+ }
+ }
+
+ if (k < j) {
+ bt_flag_last_page = tagarray[k];
+ } else {
+ Result = FAIL;
+ break;
+ }
+
+ if (Result == PASS) {
+ if (bt_flag == bt_flag_last_page) {
+ nand_dbg_print(NAND_DBG_DEBUG,
+ "Block table is found "
+ "in page prior to IPF "
+ "at block %u page %d\n",
+ (unsigned int)BT_Block, i);
+ BT_Found = 1;
+ *Page = i;
+ g_cBlockTableStatus =
+ IN_PROGRESS_BLOCK_TABLE;
+ break;
+ } else {
+ Result = FAIL;
+ break;
+ }
+ }
+ }
+ }
+
+ if (Result == FAIL) {
+ if ((Last_IPF > bt_pages) && (i < Last_IPF) && (!BT_Found)) {
+ BT_Found = 1;
+ *Page = i - (bt_pages + 1);
+ }
+ if ((Last_IPF == bt_pages) && (i < Last_IPF) && (!BT_Found))
+ goto func_return;
+ }
+
+ if (Last_IPF == 0) {
+ i = 0;
+ Result = PASS;
+ nand_dbg_print(NAND_DBG_DEBUG, "Reading the spare area of "
+ "Block %u Page %u", (unsigned int)BT_Block, i);
+
+ Result = GLOB_LLD_Read_Page_Spare(pSpareBuf, BT_Block, i, 1);
+ nand_dbg_print(NAND_DBG_DEBUG,
+ "Reading the spare area of Block %u Page %u",
+ (unsigned int)BT_Block, i + bt_pages - 1);
+ Result = GLOB_LLD_Read_Page_Spare(pSpareBufBTLastPage,
+ BT_Block, i + bt_pages - 1, 1);
+
+ k = 0;
+ j = FTL_Extract_Block_Table_Tag(pSpareBuf, &tagarray);
+ if (j) {
+ for (; k < j; k++) {
+ if (tagarray[k] == BT_Tag)
+ break;
+ }
+ }
+
+ if (k < j)
+ bt_flag = tagarray[k];
+ else
+ Result = FAIL;
+
+ if (Result == PASS) {
+ k = 0;
+ j = FTL_Extract_Block_Table_Tag(pSpareBufBTLastPage,
+ &tagarray);
+ if (j) {
+ for (; k < j; k++) {
+ if (tagarray[k] == BT_Tag)
+ break;
+ }
+ }
+
+ if (k < j)
+ bt_flag_last_page = tagarray[k];
+ else
+ Result = FAIL;
+
+ if (Result == PASS) {
+ if (bt_flag == bt_flag_last_page) {
+ nand_dbg_print(NAND_DBG_DEBUG,
+ "Block table is found "
+ "in page after IPF at "
+ "block %u page %u\n",
+ (unsigned int)BT_Block,
+ (unsigned int)i);
+ BT_Found = 1;
+ *Page = i;
+ g_cBlockTableStatus =
+ CURRENT_BLOCK_TABLE;
+ goto func_return;
+ } else {
+ Result = FAIL;
+ }
+ }
+ }
+
+ if (Result == FAIL)
+ goto func_return;
+ }
+func_return:
+ return Result;
+}
+
+u8 *get_blk_table_start_addr(void)
+{
+ return g_pBlockTable;
+}
+
+unsigned long get_blk_table_len(void)
+{
+ return DeviceInfo.wDataBlockNum * sizeof(u32);
+}
+
+u8 *get_wear_leveling_table_start_addr(void)
+{
+ return g_pWearCounter;
+}
+
+unsigned long get_wear_leveling_table_len(void)
+{
+ return DeviceInfo.wDataBlockNum * sizeof(u8);
+}
+
+/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
+* Function: FTL_Read_Block_Table
+* Inputs: none
+* Outputs: PASS / FAIL
+* Description: read the flash spare area and find a block containing the
+* most recent block table(having largest block_table_counter).
+* Find the last written Block table in this block.
+* Check the correctness of Block Table
+* If CDMA is enabled, this function is called in
+* polling mode.
+* We don't need to store changes in Block table in this
+* function as it is called only at initialization
+*
+* Note: Currently this function is called at initialization
+* before any read/erase/write command issued to flash so,
+* there is no need to wait for CDMA list to complete as of now
+*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/
+static int FTL_Read_Block_Table(void)
+{
+ u16 i = 0;
+ int k, j;
+ u8 *tempBuf, *tagarray;
+ int wResult = FAIL;
+ int status = FAIL;
+ u8 block_table_found = 0;
+ int search_result;
+ u32 Block;
+ u16 Page = 0;
+ u16 PageCount;
+ u16 bt_pages;
+ int wBytesCopied = 0, tempvar;
+
+ nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n",
+ __FILE__, __LINE__, __func__);
+
+ tempBuf = tmp_buf1_read_blk_table;
+ bt_pages = FTL_Get_Block_Table_Flash_Size_Pages();
+
+ for (j = DeviceInfo.wSpectraStartBlock;
+ j <= (int)DeviceInfo.wSpectraEndBlock;
+ j++) {
+ status = GLOB_LLD_Read_Page_Spare(tempBuf, j, 0, 1);
+ k = 0;
+ i = FTL_Extract_Block_Table_Tag(tempBuf, &tagarray);
+ if (i) {
+ status = GLOB_LLD_Read_Page_Main_Polling(tempBuf,
+ j, 0, 1);
+ for (; k < i; k++) {
+ if (tagarray[k] == tempBuf[3])
+ break;
+ }
+ }
+
+ if (k < i)
+ k = tagarray[k];
+ else
+ continue;
+
+ nand_dbg_print(NAND_DBG_DEBUG,
+ "Block table is contained in Block %d %d\n",
+ (unsigned int)j, (unsigned int)k);
+
+ if (g_pBTBlocks[k-FIRST_BT_ID] == BTBLOCK_INVAL) {
+ g_pBTBlocks[k-FIRST_BT_ID] = j;
+ block_table_found = 1;
+ } else {
+ printk(KERN_ERR "FTL_Read_Block_Table -"
+ "This should never happens. "
+ "Two block table have same counter %u!\n", k);
+ }
+ }
+
+ if (block_table_found) {
+ if (g_pBTBlocks[FIRST_BT_ID - FIRST_BT_ID] != BTBLOCK_INVAL &&
+ g_pBTBlocks[LAST_BT_ID - FIRST_BT_ID] != BTBLOCK_INVAL) {
+ j = LAST_BT_ID;
+ while ((j > FIRST_BT_ID) &&
+ (g_pBTBlocks[j - FIRST_BT_ID] != BTBLOCK_INVAL))
+ j--;
+ if (j == FIRST_BT_ID) {
+ j = LAST_BT_ID;
+ last_erased = LAST_BT_ID;
+ } else {
+ last_erased = (u8)j + 1;
+ while ((j > FIRST_BT_ID) && (BTBLOCK_INVAL ==
+ g_pBTBlocks[j - FIRST_BT_ID]))
+ j--;
+ }
+ } else {
+ j = FIRST_BT_ID;
+ while (g_pBTBlocks[j - FIRST_BT_ID] == BTBLOCK_INVAL)
+ j++;
+ last_erased = (u8)j;
+ while ((j < LAST_BT_ID) && (BTBLOCK_INVAL !=
+ g_pBTBlocks[j - FIRST_BT_ID]))
+ j++;
+ if (g_pBTBlocks[j-FIRST_BT_ID] == BTBLOCK_INVAL)
+ j--;
+ }
+
+ if (last_erased > j)
+ j += (1 + LAST_BT_ID - FIRST_BT_ID);
+
+ for (; (j >= last_erased) && (FAIL == wResult); j--) {
+ i = (j - FIRST_BT_ID) %
+ (1 + LAST_BT_ID - FIRST_BT_ID);
+ search_result =
+ FTL_Search_Block_Table_IN_Block(g_pBTBlocks[i],
+ i + FIRST_BT_ID, &Page);
+ if (g_cBlockTableStatus == IN_PROGRESS_BLOCK_TABLE)
+ block_table_found = 0;
+
+ while ((search_result == PASS) && (FAIL == wResult)) {
+ nand_dbg_print(NAND_DBG_DEBUG,
+ "FTL_Read_Block_Table:"
+ "Block: %u Page: %u "
+ "contains block table\n",
+ (unsigned int)g_pBTBlocks[i],
+ (unsigned int)Page);
+
+ tempBuf = tmp_buf2_read_blk_table;
+
+ for (k = 0; k < bt_pages; k++) {
+ Block = g_pBTBlocks[i];
+ PageCount = 1;
+
+ status =
+ GLOB_LLD_Read_Page_Main_Polling(
+ tempBuf, Block, Page, PageCount);
+
+ tempvar = k ? 0 : 4;
+
+ wBytesCopied +=
+ FTL_Copy_Block_Table_From_Flash(
+ tempBuf + tempvar,
+ DeviceInfo.wPageDataSize - tempvar,
+ wBytesCopied);
+
+ Page++;
+ }
+
+ wResult = FTL_Check_Block_Table(FAIL);
+ if (FAIL == wResult) {
+ block_table_found = 0;
+ if (Page > bt_pages)
+ Page -= ((bt_pages<<1) + 1);
+ else
+ search_result = FAIL;
+ }
+ }
+ }
+ }
+
+ if (PASS == wResult) {
+ if (!block_table_found)
+ FTL_Execute_SPL_Recovery();
+
+ if (g_cBlockTableStatus == IN_PROGRESS_BLOCK_TABLE)
+ g_wBlockTableOffset = (u16)Page + 1;
+ else
+ g_wBlockTableOffset = (u16)Page - bt_pages;
+
+ g_wBlockTableIndex = (u32)g_pBTBlocks[i];
+
+#if CMD_DMA
+ if (DeviceInfo.MLCDevice)
+ memcpy(g_pBTStartingCopy, g_pBlockTable,
+ DeviceInfo.wDataBlockNum * sizeof(u32)
+ + DeviceInfo.wDataBlockNum * sizeof(u8)
+ + DeviceInfo.wDataBlockNum * sizeof(u16));
+ else
+ memcpy(g_pBTStartingCopy, g_pBlockTable,
+ DeviceInfo.wDataBlockNum * sizeof(u32)
+ + DeviceInfo.wDataBlockNum * sizeof(u8));
+#endif
+ }
+
+ if (FAIL == wResult)
+ printk(KERN_ERR "Yunpeng - "
+ "Can not find valid spectra block table!\n");
+
+#if AUTO_FORMAT_FLASH
+ if (FAIL == wResult) {
+ nand_dbg_print(NAND_DBG_DEBUG, "doing auto-format\n");
+ wResult = FTL_Format_Flash(0);
+ }
+#endif
+
+ return wResult;
+}
+
+
+/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
+* Function: FTL_Flash_Error_Handle
+* Inputs: Pointer to data
+* Page address
+* Block address
+* Outputs: PASS=0 / FAIL=1
+* Description: It handles any error occured during Spectra operation
+*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/
+static int FTL_Flash_Error_Handle(u8 *pData, u64 old_page_addr,
+ u64 blk_addr)
+{
+ u32 i;
+ int j;
+ u32 tmp_node, blk_node = BLK_FROM_ADDR(blk_addr);
+ u64 phy_addr;
+ int wErase = FAIL;
+ int wResult = FAIL;
+ u32 *pbt = (u32 *)g_pBlockTable;
+
+ nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n",
+ __FILE__, __LINE__, __func__);
+
+ if (ERR == GLOB_FTL_Garbage_Collection())
+ return ERR;
+
+ do {
+ for (i = DeviceInfo.wSpectraEndBlock -
+ DeviceInfo.wSpectraStartBlock;
+ i > 0; i--) {
+ if (IS_SPARE_BLOCK(i)) {
+ tmp_node = (u32)(BAD_BLOCK |
+ pbt[blk_node]);
+ pbt[blk_node] = (u32)(pbt[i] &
+ (~SPARE_BLOCK));
+ pbt[i] = tmp_node;
+#if CMD_DMA
+ p_BTableChangesDelta =
+ (struct BTableChangesDelta *)
+ g_pBTDelta_Free;
+ g_pBTDelta_Free +=
+ sizeof(struct BTableChangesDelta);
+
+ p_BTableChangesDelta->ftl_cmd_cnt =
+ ftl_cmd_cnt;
+ p_BTableChangesDelta->BT_Index =
+ blk_node;
+ p_BTableChangesDelta->BT_Entry_Value =
+ pbt[blk_node];
+ p_BTableChangesDelta->ValidFields = 0x0C;
+
+ p_BTableChangesDelta =
+ (struct BTableChangesDelta *)
+ g_pBTDelta_Free;
+ g_pBTDelta_Free +=
+ sizeof(struct BTableChangesDelta);
+
+ p_BTableChangesDelta->ftl_cmd_cnt =
+ ftl_cmd_cnt;
+ p_BTableChangesDelta->BT_Index = i;
+ p_BTableChangesDelta->BT_Entry_Value = pbt[i];
+ p_BTableChangesDelta->ValidFields = 0x0C;
+#endif
+ wResult = PASS;
+ break;
+ }
+ }
+
+ if (FAIL == wResult) {
+ if (FAIL == GLOB_FTL_Garbage_Collection())
+ break;
+ else
+ continue;
+ }
+
+ if (IN_PROGRESS_BLOCK_TABLE != g_cBlockTableStatus) {
+ g_cBlockTableStatus = IN_PROGRESS_BLOCK_TABLE;
+ FTL_Write_IN_Progress_Block_Table_Page();
+ }
+
+ phy_addr = FTL_Get_Physical_Block_Addr(blk_addr);
+
+ for (j = 0; j < RETRY_TIMES; j++) {
+ if (PASS == wErase) {
+ if (FAIL == GLOB_FTL_Block_Erase(phy_addr)) {
+ MARK_BLOCK_AS_BAD(pbt[blk_node]);
+ break;
+ }
+ }
+ if (PASS == FTL_Cache_Update_Block(pData,
+ old_page_addr,
+ phy_addr)) {
+ wResult = PASS;
+ break;
+ } else {
+ wResult = FAIL;
+ wErase = PASS;
+ }
+ }
+ } while (FAIL == wResult);
+
+ FTL_Write_Block_Table(FAIL);
+
+ return wResult;
+}
+
+/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
+* Function: FTL_Get_Page_Num
+* Inputs: Size in bytes
+* Outputs: Size in pages
+* Description: It calculates the pages required for the length passed
+*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/
+static u32 FTL_Get_Page_Num(u64 length)
+{
+ return (u32)((length >> DeviceInfo.nBitsInPageDataSize) +
+ (GLOB_u64_Remainder(length , 1) > 0 ? 1 : 0));
+}
+
+/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
+* Function: FTL_Get_Physical_Block_Addr
+* Inputs: Block Address (byte format)
+* Outputs: Physical address of the block.
+* Description: It translates LBA to PBA by returning address stored
+* at the LBA location in the block table
+*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/
+static u64 FTL_Get_Physical_Block_Addr(u64 logical_addr)
+{
+ u32 *pbt;
+ u64 physical_addr;
+
+ nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n",
+ __FILE__, __LINE__, __func__);
+
+ pbt = (u32 *)g_pBlockTable;
+ physical_addr = (u64) DeviceInfo.wBlockDataSize *
+ (pbt[BLK_FROM_ADDR(logical_addr)] & (~BAD_BLOCK));
+
+ return physical_addr;
+}
+
+/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
+* Function: FTL_Get_Block_Index
+* Inputs: Physical Block no.
+* Outputs: Logical block no. /BAD_BLOCK
+* Description: It returns the logical block no. for the PBA passed
+*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/
+static u32 FTL_Get_Block_Index(u32 wBlockNum)
+{
+ u32 *pbt = (u32 *)g_pBlockTable;
+ u32 i;
+
+ nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n",
+ __FILE__, __LINE__, __func__);
+
+ for (i = 0; i < DeviceInfo.wDataBlockNum; i++)
+ if (wBlockNum == (pbt[i] & (~BAD_BLOCK)))
+ return i;
+
+ return BAD_BLOCK;
+}
+
+/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
+* Function: GLOB_FTL_Wear_Leveling
+* Inputs: none
+* Outputs: PASS=0
+* Description: This is static wear leveling (done by explicit call)
+* do complete static wear leveling
+* do complete garbage collection
+*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/
+int GLOB_FTL_Wear_Leveling(void)
+{
+ nand_dbg_print(NAND_DBG_WARN, "%s, Line %d, Function: %s\n",
+ __FILE__, __LINE__, __func__);
+
+ FTL_Static_Wear_Leveling();
+ GLOB_FTL_Garbage_Collection();
+
+ return PASS;
+}
+
+static void find_least_most_worn(u8 *chg,
+ u32 *least_idx, u8 *least_cnt,
+ u32 *most_idx, u8 *most_cnt)
+{
+ u32 *pbt = (u32 *)g_pBlockTable;
+ u32 idx;
+ u8 cnt;
+ int i;
+
+ for (i = BLOCK_TABLE_INDEX + 1; i < DeviceInfo.wDataBlockNum; i++) {
+ if (IS_BAD_BLOCK(i) || PASS == chg[i])
+ continue;
+
+ idx = (u32) ((~BAD_BLOCK) & pbt[i]);
+ cnt = g_pWearCounter[idx - DeviceInfo.wSpectraStartBlock];
+
+ if (IS_SPARE_BLOCK(i)) {
+ if (cnt > *most_cnt) {
+ *most_cnt = cnt;
+ *most_idx = idx;
+ }
+ }
+
+ if (IS_DATA_BLOCK(i)) {
+ if (cnt < *least_cnt) {
+ *least_cnt = cnt;
+ *least_idx = idx;
+ }
+ }
+
+ if (PASS == chg[*most_idx] || PASS == chg[*least_idx]) {
+ debug_boundary_error(*most_idx,
+ DeviceInfo.wDataBlockNum, 0);
+ debug_boundary_error(*least_idx,
+ DeviceInfo.wDataBlockNum, 0);
+ continue;
+ }
+ }
+}
+
+static int move_blks_for_wear_leveling(u8 *chg,
+ u32 *least_idx, u32 *rep_blk_num, int *result)
+{
+ u32 *pbt = (u32 *)g_pBlockTable;
+ u32 rep_blk;
+ int j, ret_cp_blk, ret_erase;
+ int ret = PASS;
+
+ chg[*least_idx] = PASS;
+ debug_boundary_error(*least_idx, DeviceInfo.wDataBlockNum, 0);
+
+ rep_blk = FTL_Replace_MWBlock();
+ if (rep_blk != BAD_BLOCK) {
+ nand_dbg_print(NAND_DBG_DEBUG,
+ "More than two spare blocks exist so do it\n");
+ nand_dbg_print(NAND_DBG_DEBUG, "Block Replaced is %d\n",
+ rep_blk);
+
+ chg[rep_blk] = PASS;
+
+ if (IN_PROGRESS_BLOCK_TABLE != g_cBlockTableStatus) {
+ g_cBlockTableStatus = IN_PROGRESS_BLOCK_TABLE;
+ FTL_Write_IN_Progress_Block_Table_Page();
+ }
+
+ for (j = 0; j < RETRY_TIMES; j++) {
+ ret_cp_blk = FTL_Copy_Block((u64)(*least_idx) *
+ DeviceInfo.wBlockDataSize,
+ (u64)rep_blk * DeviceInfo.wBlockDataSize);
+ if (FAIL == ret_cp_blk) {
+ ret_erase = GLOB_FTL_Block_Erase((u64)rep_blk
+ * DeviceInfo.wBlockDataSize);
+ if (FAIL == ret_erase)
+ MARK_BLOCK_AS_BAD(pbt[rep_blk]);
+ } else {
+ nand_dbg_print(NAND_DBG_DEBUG,
+ "FTL_Copy_Block == OK\n");
+ break;
+ }
+ }
+
+ if (j < RETRY_TIMES) {
+ u32 tmp;
+ u32 old_idx = FTL_Get_Block_Index(*least_idx);
+ u32 rep_idx = FTL_Get_Block_Index(rep_blk);
+ tmp = (u32)(DISCARD_BLOCK | pbt[old_idx]);
+ pbt[old_idx] = (u32)((~SPARE_BLOCK) &
+ pbt[rep_idx]);
+ pbt[rep_idx] = tmp;
+#if CMD_DMA
+ p_BTableChangesDelta = (struct BTableChangesDelta *)
+ g_pBTDelta_Free;
+ g_pBTDelta_Free += sizeof(struct BTableChangesDelta);
+ p_BTableChangesDelta->ftl_cmd_cnt =
+ ftl_cmd_cnt;
+ p_BTableChangesDelta->BT_Index = old_idx;
+ p_BTableChangesDelta->BT_Entry_Value = pbt[old_idx];
+ p_BTableChangesDelta->ValidFields = 0x0C;
+
+ p_BTableChangesDelta = (struct BTableChangesDelta *)
+ g_pBTDelta_Free;
+ g_pBTDelta_Free += sizeof(struct BTableChangesDelta);
+
+ p_BTableChangesDelta->ftl_cmd_cnt =
+ ftl_cmd_cnt;
+ p_BTableChangesDelta->BT_Index = rep_idx;
+ p_BTableChangesDelta->BT_Entry_Value = pbt[rep_idx];
+ p_BTableChangesDelta->ValidFields = 0x0C;
+#endif
+ } else {
+ pbt[FTL_Get_Block_Index(rep_blk)] |= BAD_BLOCK;
+#if CMD_DMA
+ p_BTableChangesDelta = (struct BTableChangesDelta *)
+ g_pBTDelta_Free;
+ g_pBTDelta_Free += sizeof(struct BTableChangesDelta);
+
+ p_BTableChangesDelta->ftl_cmd_cnt =
+ ftl_cmd_cnt;
+ p_BTableChangesDelta->BT_Index =
+ FTL_Get_Block_Index(rep_blk);
+ p_BTableChangesDelta->BT_Entry_Value =
+ pbt[FTL_Get_Block_Index(rep_blk)];
+ p_BTableChangesDelta->ValidFields = 0x0C;
+#endif
+ *result = FAIL;
+ ret = FAIL;
+ }
+
+ if (((*rep_blk_num)++) > WEAR_LEVELING_BLOCK_NUM)
+ ret = FAIL;
+ } else {
+ printk(KERN_ERR "Less than 3 spare blocks exist so quit\n");
+ ret = FAIL;
+ }
+
+ return ret;
+}
+
+/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
+* Function: FTL_Static_Wear_Leveling
+* Inputs: none
+* Outputs: PASS=0 / FAIL=1
+* Description: This is static wear leveling (done by explicit call)
+* search for most&least used
+* if difference < GATE:
+* update the block table with exhange
+* mark block table in flash as IN_PROGRESS
+* copy flash block
+* the caller should handle GC clean up after calling this function
+*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/
+int FTL_Static_Wear_Leveling(void)
+{
+ u8 most_worn_cnt;
+ u8 least_worn_cnt;
+ u32 most_worn_idx;
+ u32 least_worn_idx;
+ int result = PASS;
+ int go_on = PASS;
+ u32 replaced_blks = 0;
+ u8 *chang_flag = flags_static_wear_leveling;
+
+ nand_dbg_print(NAND_DBG_WARN, "%s, Line %d, Function: %s\n",
+ __FILE__, __LINE__, __func__);
+
+ if (!chang_flag)
+ return FAIL;
+
+ memset(chang_flag, FAIL, DeviceInfo.wDataBlockNum);
+ while (go_on == PASS) {
+ nand_dbg_print(NAND_DBG_DEBUG,
+ "starting static wear leveling\n");
+ most_worn_cnt = 0;
+ least_worn_cnt = 0xFF;
+ least_worn_idx = BLOCK_TABLE_INDEX;
+ most_worn_idx = BLOCK_TABLE_INDEX;
+
+ find_least_most_worn(chang_flag, &least_worn_idx,
+ &least_worn_cnt, &most_worn_idx, &most_worn_cnt);
+
+ nand_dbg_print(NAND_DBG_DEBUG,
+ "Used and least worn is block %u, whos count is %u\n",
+ (unsigned int)least_worn_idx,
+ (unsigned int)least_worn_cnt);
+
+ nand_dbg_print(NAND_DBG_DEBUG,
+ "Free and most worn is block %u, whos count is %u\n",
+ (unsigned int)most_worn_idx,
+ (unsigned int)most_worn_cnt);
+
+ if ((most_worn_cnt > least_worn_cnt) &&
+ (most_worn_cnt - least_worn_cnt > WEAR_LEVELING_GATE))
+ go_on = move_blks_for_wear_leveling(chang_flag,
+ &least_worn_idx, &replaced_blks, &result);
+ else
+ go_on = FAIL;
+ }
+
+ return result;
+}
+
+#if CMD_DMA
+static int do_garbage_collection(u32 discard_cnt)
+{
+ u32 *pbt = (u32 *)g_pBlockTable;
+ u32 pba;
+ u8 bt_block_erased = 0;
+ int i, cnt, ret = FAIL;
+ u64 addr;
+
+ i = 0;
+ while ((i < DeviceInfo.wDataBlockNum) && (discard_cnt > 0) &&
+ ((ftl_cmd_cnt + 28) < 256)) {
+ if (((pbt[i] & BAD_BLOCK) != BAD_BLOCK) &&
+ (pbt[i] & DISCARD_BLOCK)) {
+ if (IN_PROGRESS_BLOCK_TABLE != g_cBlockTableStatus) {
+ g_cBlockTableStatus = IN_PROGRESS_BLOCK_TABLE;
+ FTL_Write_IN_Progress_Block_Table_Page();
+ }
+
+ addr = FTL_Get_Physical_Block_Addr((u64)i *
+ DeviceInfo.wBlockDataSize);
+ pba = BLK_FROM_ADDR(addr);
+
+ for (cnt = FIRST_BT_ID; cnt <= LAST_BT_ID; cnt++) {
+ if (pba == g_pBTBlocks[cnt - FIRST_BT_ID]) {
+ nand_dbg_print(NAND_DBG_DEBUG,
+ "GC will erase BT block %u\n",
+ (unsigned int)pba);
+ discard_cnt--;
+ i++;
+ bt_block_erased = 1;
+ break;
+ }
+ }
+
+ if (bt_block_erased) {
+ bt_block_erased = 0;
+ continue;
+ }
+
+ addr = FTL_Get_Physical_Block_Addr((u64)i *
+ DeviceInfo.wBlockDataSize);
+
+ if (PASS == GLOB_FTL_Block_Erase(addr)) {
+ pbt[i] &= (u32)(~DISCARD_BLOCK);
+ pbt[i] |= (u32)(SPARE_BLOCK);
+ p_BTableChangesDelta =
+ (struct BTableChangesDelta *)
+ g_pBTDelta_Free;
+ g_pBTDelta_Free +=
+ sizeof(struct BTableChangesDelta);
+ p_BTableChangesDelta->ftl_cmd_cnt =
+ ftl_cmd_cnt - 1;
+ p_BTableChangesDelta->BT_Index = i;
+ p_BTableChangesDelta->BT_Entry_Value = pbt[i];
+ p_BTableChangesDelta->ValidFields = 0x0C;
+ discard_cnt--;
+ ret = PASS;
+ } else {
+ MARK_BLOCK_AS_BAD(pbt[i]);
+ }
+ }
+
+ i++;
+ }
+
+ return ret;
+}
+
+#else
+static int do_garbage_collection(u32 discard_cnt)
+{
+ u32 *pbt = (u32 *)g_pBlockTable;
+ u32 pba;
+ u8 bt_block_erased = 0;
+ int i, cnt, ret = FAIL;
+ u64 addr;
+
+ i = 0;
+ while ((i < DeviceInfo.wDataBlockNum) && (discard_cnt > 0)) {
+ if (((pbt[i] & BAD_BLOCK) != BAD_BLOCK) &&
+ (pbt[i] & DISCARD_BLOCK)) {
+ if (IN_PROGRESS_BLOCK_TABLE != g_cBlockTableStatus) {
+ g_cBlockTableStatus = IN_PROGRESS_BLOCK_TABLE;
+ FTL_Write_IN_Progress_Block_Table_Page();
+ }
+
+ addr = FTL_Get_Physical_Block_Addr((u64)i *
+ DeviceInfo.wBlockDataSize);
+ pba = BLK_FROM_ADDR(addr);
+
+ for (cnt = FIRST_BT_ID; cnt <= LAST_BT_ID; cnt++) {
+ if (pba == g_pBTBlocks[cnt - FIRST_BT_ID]) {
+ nand_dbg_print(NAND_DBG_DEBUG,
+ "GC will erase BT block %d\n",
+ pba);
+ discard_cnt--;
+ i++;
+ bt_block_erased = 1;
+ break;
+ }
+ }
+
+ if (bt_block_erased) {
+ bt_block_erased = 0;
+ continue;
+ }
+
+ /* If the discard block is L2 cache block, then just skip it */
+ for (cnt = 0; cnt < BLK_NUM_FOR_L2_CACHE; cnt++) {
+ if (cache_l2.blk_array[cnt] == pba) {
+ nand_dbg_print(NAND_DBG_DEBUG,
+ "GC will erase L2 cache blk %d\n",
+ pba);
+ break;
+ }
+ }
+ if (cnt < BLK_NUM_FOR_L2_CACHE) { /* Skip it */
+ discard_cnt--;
+ i++;
+ continue;
+ }
+
+ addr = FTL_Get_Physical_Block_Addr((u64)i *
+ DeviceInfo.wBlockDataSize);
+
+ if (PASS == GLOB_FTL_Block_Erase(addr)) {
+ pbt[i] &= (u32)(~DISCARD_BLOCK);
+ pbt[i] |= (u32)(SPARE_BLOCK);
+ discard_cnt--;
+ ret = PASS;
+ } else {
+ MARK_BLOCK_AS_BAD(pbt[i]);
+ }
+ }
+
+ i++;
+ }
+
+ return ret;
+}
+#endif
+
+/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
+* Function: GLOB_FTL_Garbage_Collection
+* Inputs: none
+* Outputs: PASS / FAIL (returns the number of un-erased blocks
+* Description: search the block table for all discarded blocks to erase
+* for each discarded block:
+* set the flash block to IN_PROGRESS
+* erase the block
+* update the block table
+* write the block table to flash
+*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/
+int GLOB_FTL_Garbage_Collection(void)
+{
+ u32 i;
+ u32 wDiscard = 0;
+ int wResult = FAIL;
+ u32 *pbt = (u32 *)g_pBlockTable;
+
+ nand_dbg_print(NAND_DBG_WARN, "%s, Line %d, Function: %s\n",
+ __FILE__, __LINE__, __func__);
+
+ if (GC_Called) {
+ printk(KERN_ALERT "GLOB_FTL_Garbage_Collection() "
+ "has been re-entered! Exit.\n");
+ return PASS;
+ }
+
+ GC_Called = 1;
+
+ GLOB_FTL_BT_Garbage_Collection();
+
+ for (i = 0; i < DeviceInfo.wDataBlockNum; i++) {
+ if (IS_DISCARDED_BLOCK(i))
+ wDiscard++;
+ }
+
+ if (wDiscard <= 0) {
+ GC_Called = 0;
+ return wResult;
+ }
+
+ nand_dbg_print(NAND_DBG_DEBUG,
+ "Found %d discarded blocks\n", wDiscard);
+
+ FTL_Write_Block_Table(FAIL);
+
+ wResult = do_garbage_collection(wDiscard);
+
+ FTL_Write_Block_Table(FAIL);
+
+ GC_Called = 0;
+
+ return wResult;
+}
+
+
+#if CMD_DMA
+static int do_bt_garbage_collection(void)
+{
+ u32 pba, lba;
+ u32 *pbt = (u32 *)g_pBlockTable;
+ u32 *pBTBlocksNode = (u32 *)g_pBTBlocks;
+ u64 addr;
+ int i, ret = FAIL;
+
+ nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n",
+ __FILE__, __LINE__, __func__);
+
+ if (BT_GC_Called)
+ return PASS;
+
+ BT_GC_Called = 1;
+
+ for (i = last_erased; (i <= LAST_BT_ID) &&
+ (g_pBTBlocks[((i + 2) % (1 + LAST_BT_ID - FIRST_BT_ID)) +
+ FIRST_BT_ID - FIRST_BT_ID] != BTBLOCK_INVAL) &&
+ ((ftl_cmd_cnt + 28)) < 256; i++) {
+ pba = pBTBlocksNode[i - FIRST_BT_ID];
+ lba = FTL_Get_Block_Index(pba);
+ nand_dbg_print(NAND_DBG_DEBUG,
+ "do_bt_garbage_collection: pba %d, lba %d\n",
+ pba, lba);
+ nand_dbg_print(NAND_DBG_DEBUG,
+ "Block Table Entry: %d", pbt[lba]);
+
+ if (((pbt[lba] & BAD_BLOCK) != BAD_BLOCK) &&
+ (pbt[lba] & DISCARD_BLOCK)) {
+ nand_dbg_print(NAND_DBG_DEBUG,
+ "do_bt_garbage_collection_cdma: "
+ "Erasing Block tables present in block %d\n",
+ pba);
+ addr = FTL_Get_Physical_Block_Addr((u64)lba *
+ DeviceInfo.wBlockDataSize);
+ if (PASS == GLOB_FTL_Block_Erase(addr)) {
+ pbt[lba] &= (u32)(~DISCARD_BLOCK);
+ pbt[lba] |= (u32)(SPARE_BLOCK);
+
+ p_BTableChangesDelta =
+ (struct BTableChangesDelta *)
+ g_pBTDelta_Free;
+ g_pBTDelta_Free +=
+ sizeof(struct BTableChangesDelta);
+
+ p_BTableChangesDelta->ftl_cmd_cnt =
+ ftl_cmd_cnt - 1;
+ p_BTableChangesDelta->BT_Index = lba;
+ p_BTableChangesDelta->BT_Entry_Value =
+ pbt[lba];
+
+ p_BTableChangesDelta->ValidFields = 0x0C;
+
+ ret = PASS;
+ pBTBlocksNode[last_erased - FIRST_BT_ID] =
+ BTBLOCK_INVAL;
+ nand_dbg_print(NAND_DBG_DEBUG,
+ "resetting bt entry at index %d "
+ "value %d\n", i,
+ pBTBlocksNode[i - FIRST_BT_ID]);
+ if (last_erased == LAST_BT_ID)
+ last_erased = FIRST_BT_ID;
+ else
+ last_erased++;
+ } else {
+ MARK_BLOCK_AS_BAD(pbt[lba]);
+ }
+ }
+ }
+
+ BT_GC_Called = 0;
+
+ return ret;
+}
+
+#else
+static int do_bt_garbage_collection(void)
+{
+ u32 pba, lba;
+ u32 *pbt = (u32 *)g_pBlockTable;
+ u32 *pBTBlocksNode = (u32 *)g_pBTBlocks;
+ u64 addr;
+ int i, ret = FAIL;
+
+ nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n",
+ __FILE__, __LINE__, __func__);
+
+ if (BT_GC_Called)
+ return PASS;
+
+ BT_GC_Called = 1;
+
+ for (i = last_erased; (i <= LAST_BT_ID) &&
+ (g_pBTBlocks[((i + 2) % (1 + LAST_BT_ID - FIRST_BT_ID)) +
+ FIRST_BT_ID - FIRST_BT_ID] != BTBLOCK_INVAL); i++) {
+ pba = pBTBlocksNode[i - FIRST_BT_ID];
+ lba = FTL_Get_Block_Index(pba);
+ nand_dbg_print(NAND_DBG_DEBUG,
+ "do_bt_garbage_collection_cdma: pba %d, lba %d\n",
+ pba, lba);
+ nand_dbg_print(NAND_DBG_DEBUG,
+ "Block Table Entry: %d", pbt[lba]);
+
+ if (((pbt[lba] & BAD_BLOCK) != BAD_BLOCK) &&
+ (pbt[lba] & DISCARD_BLOCK)) {
+ nand_dbg_print(NAND_DBG_DEBUG,
+ "do_bt_garbage_collection: "
+ "Erasing Block tables present in block %d\n",
+ pba);
+ addr = FTL_Get_Physical_Block_Addr((u64)lba *
+ DeviceInfo.wBlockDataSize);
+ if (PASS == GLOB_FTL_Block_Erase(addr)) {
+ pbt[lba] &= (u32)(~DISCARD_BLOCK);
+ pbt[lba] |= (u32)(SPARE_BLOCK);
+ ret = PASS;
+ pBTBlocksNode[last_erased - FIRST_BT_ID] =
+ BTBLOCK_INVAL;
+ nand_dbg_print(NAND_DBG_DEBUG,
+ "resetting bt entry at index %d "
+ "value %d\n", i,
+ pBTBlocksNode[i - FIRST_BT_ID]);
+ if (last_erased == LAST_BT_ID)
+ last_erased = FIRST_BT_ID;
+ else
+ last_erased++;
+ } else {
+ MARK_BLOCK_AS_BAD(pbt[lba]);
+ }
+ }
+ }
+
+ BT_GC_Called = 0;
+
+ return ret;
+}
+
+#endif
+
+/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
+* Function: GLOB_FTL_BT_Garbage_Collection
+* Inputs: none
+* Outputs: PASS / FAIL (returns the number of un-erased blocks
+* Description: Erases discarded blocks containing Block table
+*
+*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/
+int GLOB_FTL_BT_Garbage_Collection(void)
+{
+ return do_bt_garbage_collection();
+}
+
+/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
+* Function: FTL_Replace_OneBlock
+* Inputs: Block number 1
+* Block number 2
+* Outputs: Replaced Block Number
+* Description: Interchange block table entries at wBlockNum and wReplaceNum
+*
+*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/
+static u32 FTL_Replace_OneBlock(u32 blk, u32 rep_blk)
+{
+ u32 tmp_blk;
+ u32 replace_node = BAD_BLOCK;
+ u32 *pbt = (u32 *)g_pBlockTable;
+
+ nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n",
+ __FILE__, __LINE__, __func__);
+
+ if (rep_blk != BAD_BLOCK) {
+ if (IS_BAD_BLOCK(blk))
+ tmp_blk = pbt[blk];
+ else
+ tmp_blk = DISCARD_BLOCK | (~SPARE_BLOCK & pbt[blk]);
+
+ replace_node = (u32) ((~SPARE_BLOCK) & pbt[rep_blk]);
+ pbt[blk] = replace_node;
+ pbt[rep_blk] = tmp_blk;
+
+#if CMD_DMA
+ p_BTableChangesDelta =
+ (struct BTableChangesDelta *)g_pBTDelta_Free;
+ g_pBTDelta_Free += sizeof(struct BTableChangesDelta);
+
+ p_BTableChangesDelta->ftl_cmd_cnt = ftl_cmd_cnt;
+ p_BTableChangesDelta->BT_Index = blk;
+ p_BTableChangesDelta->BT_Entry_Value = pbt[blk];
+
+ p_BTableChangesDelta->ValidFields = 0x0C;
+
+ p_BTableChangesDelta =
+ (struct BTableChangesDelta *)g_pBTDelta_Free;
+ g_pBTDelta_Free += sizeof(struct BTableChangesDelta);
+
+ p_BTableChangesDelta->ftl_cmd_cnt = ftl_cmd_cnt;
+ p_BTableChangesDelta->BT_Index = rep_blk;
+ p_BTableChangesDelta->BT_Entry_Value = pbt[rep_blk];
+ p_BTableChangesDelta->ValidFields = 0x0C;
+#endif
+ }
+
+ return replace_node;
+}
+
+/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
+* Function: FTL_Write_Block_Table_Data
+* Inputs: Block table size in pages
+* Outputs: PASS=0 / FAIL=1
+* Description: Write block table data in flash
+* If first page and last page
+* Write data+BT flag
+* else
+* Write data
+* BT flag is a counter. Its value is incremented for block table
+* write in a new Block
+*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/
+static int FTL_Write_Block_Table_Data(void)
+{
+ u64 dwBlockTableAddr, pTempAddr;
+ u32 Block;
+ u16 Page, PageCount;
+ u8 *tempBuf = tmp_buf_write_blk_table_data;
+ int wBytesCopied;
+ u16 bt_pages;
+
+ nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n",
+ __FILE__, __LINE__, __func__);
+
+ dwBlockTableAddr =
+ (u64)((u64)g_wBlockTableIndex * DeviceInfo.wBlockDataSize +
+ (u64)g_wBlockTableOffset * DeviceInfo.wPageDataSize);
+ pTempAddr = dwBlockTableAddr;
+
+ bt_pages = FTL_Get_Block_Table_Flash_Size_Pages();
+
+ nand_dbg_print(NAND_DBG_DEBUG, "FTL_Write_Block_Table_Data: "
+ "page= %d BlockTableIndex= %d "
+ "BlockTableOffset=%d\n", bt_pages,
+ g_wBlockTableIndex, g_wBlockTableOffset);
+
+ Block = BLK_FROM_ADDR(pTempAddr);
+ Page = PAGE_FROM_ADDR(pTempAddr, Block);
+ PageCount = 1;
+
+ if (bt_block_changed) {
+ if (bt_flag == LAST_BT_ID) {
+ bt_flag = FIRST_BT_ID;
+ g_pBTBlocks[bt_flag - FIRST_BT_ID] = Block;
+ } else if (bt_flag < LAST_BT_ID) {
+ bt_flag++;
+ g_pBTBlocks[bt_flag - FIRST_BT_ID] = Block;
+ }
+
+ if ((bt_flag > (LAST_BT_ID-4)) &&
+ g_pBTBlocks[FIRST_BT_ID - FIRST_BT_ID] !=
+ BTBLOCK_INVAL) {
+ bt_block_changed = 0;
+ GLOB_FTL_BT_Garbage_Collection();
+ }
+
+ bt_block_changed = 0;
+ nand_dbg_print(NAND_DBG_DEBUG,
+ "Block Table Counter is %u Block %u\n",
+ bt_flag, (unsigned int)Block);
+ }
+
+ memset(tempBuf, 0, 3);
+ tempBuf[3] = bt_flag;
+ wBytesCopied = FTL_Copy_Block_Table_To_Flash(tempBuf + 4,
+ DeviceInfo.wPageDataSize - 4, 0);
+ memset(&tempBuf[wBytesCopied + 4], 0xff,
+ DeviceInfo.wPageSize - (wBytesCopied + 4));
+ FTL_Insert_Block_Table_Signature(&tempBuf[DeviceInfo.wPageDataSize],
+ bt_flag);
+
+#if CMD_DMA
+ memcpy(g_pNextBlockTable, tempBuf,
+ DeviceInfo.wPageSize * sizeof(u8));
+ nand_dbg_print(NAND_DBG_DEBUG, "Writing First Page of Block Table "
+ "Block %u Page %u\n", (unsigned int)Block, Page);
+ if (FAIL == GLOB_LLD_Write_Page_Main_Spare_cdma(g_pNextBlockTable,
+ Block, Page, 1,
+ LLD_CMD_FLAG_MODE_CDMA | LLD_CMD_FLAG_ORDER_BEFORE_REST)) {
+ nand_dbg_print(NAND_DBG_WARN, "NAND Program fail in "
+ "%s, Line %d, Function: %s, "
+ "new Bad Block %d generated!\n",
+ __FILE__, __LINE__, __func__, Block);
+ goto func_return;
+ }
+
+ ftl_cmd_cnt++;
+ g_pNextBlockTable += ((DeviceInfo.wPageSize * sizeof(u8)));
+#else
+ if (FAIL == GLOB_LLD_Write_Page_Main_Spare(tempBuf, Block, Page, 1)) {
+ nand_dbg_print(NAND_DBG_WARN,
+ "NAND Program fail in %s, Line %d, Function: %s, "
+ "new Bad Block %d generated!\n",
+ __FILE__, __LINE__, __func__, Block);
+ goto func_return;
+ }
+#endif
+
+ if (bt_pages > 1) {
+ PageCount = bt_pages - 1;
+ if (PageCount > 1) {
+ wBytesCopied += FTL_Copy_Block_Table_To_Flash(tempBuf,
+ DeviceInfo.wPageDataSize * (PageCount - 1),
+ wBytesCopied);
+
+#if CMD_DMA
+ memcpy(g_pNextBlockTable, tempBuf,
+ (PageCount - 1) * DeviceInfo.wPageDataSize);
+ if (FAIL == GLOB_LLD_Write_Page_Main_cdma(
+ g_pNextBlockTable, Block, Page + 1,
+ PageCount - 1)) {
+ nand_dbg_print(NAND_DBG_WARN,
+ "NAND Program fail in %s, Line %d, "
+ "Function: %s, "
+ "new Bad Block %d generated!\n",
+ __FILE__, __LINE__, __func__,
+ (int)Block);
+ goto func_return;
+ }
+
+ ftl_cmd_cnt++;
+ g_pNextBlockTable += (PageCount - 1) *
+ DeviceInfo.wPageDataSize * sizeof(u8);
+#else
+ if (FAIL == GLOB_LLD_Write_Page_Main(tempBuf,
+ Block, Page + 1, PageCount - 1)) {
+ nand_dbg_print(NAND_DBG_WARN,
+ "NAND Program fail in %s, Line %d, "
+ "Function: %s, "
+ "new Bad Block %d generated!\n",
+ __FILE__, __LINE__, __func__,
+ (int)Block);
+ goto func_return;
+ }
+#endif
+ }
+
+ wBytesCopied = FTL_Copy_Block_Table_To_Flash(tempBuf,
+ DeviceInfo.wPageDataSize, wBytesCopied);
+ memset(&tempBuf[wBytesCopied], 0xff,
+ DeviceInfo.wPageSize-wBytesCopied);
+ FTL_Insert_Block_Table_Signature(
+ &tempBuf[DeviceInfo.wPageDataSize], bt_flag);
+#if CMD_DMA
+ memcpy(g_pNextBlockTable, tempBuf,
+ DeviceInfo.wPageSize * sizeof(u8));
+ nand_dbg_print(NAND_DBG_DEBUG,
+ "Writing the last Page of Block Table "
+ "Block %u Page %u\n",
+ (unsigned int)Block, Page + bt_pages - 1);
+ if (FAIL == GLOB_LLD_Write_Page_Main_Spare_cdma(
+ g_pNextBlockTable, Block, Page + bt_pages - 1, 1,
+ LLD_CMD_FLAG_MODE_CDMA |
+ LLD_CMD_FLAG_ORDER_BEFORE_REST)) {
+ nand_dbg_print(NAND_DBG_WARN,
+ "NAND Program fail in %s, Line %d, "
+ "Function: %s, new Bad Block %d generated!\n",
+ __FILE__, __LINE__, __func__, Block);
+ goto func_return;
+ }
+ ftl_cmd_cnt++;
+#else
+ if (FAIL == GLOB_LLD_Write_Page_Main_Spare(tempBuf,
+ Block, Page+bt_pages - 1, 1)) {
+ nand_dbg_print(NAND_DBG_WARN,
+ "NAND Program fail in %s, Line %d, "
+ "Function: %s, "
+ "new Bad Block %d generated!\n",
+ __FILE__, __LINE__, __func__, Block);
+ goto func_return;
+ }
+#endif
+ }
+
+ nand_dbg_print(NAND_DBG_DEBUG, "FTL_Write_Block_Table_Data: done\n");
+
+func_return:
+ return PASS;
+}
+
+/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
+* Function: FTL_Replace_Block_Table
+* Inputs: None
+* Outputs: PASS=0 / FAIL=1
+* Description: Get a new block to write block table
+*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/
+static u32 FTL_Replace_Block_Table(void)
+{
+ u32 blk;
+ int gc;
+
+ nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n",
+ __FILE__, __LINE__, __func__);
+
+ blk = FTL_Replace_LWBlock(BLOCK_TABLE_INDEX, &gc);
+
+ if ((BAD_BLOCK == blk) && (PASS == gc)) {
+ GLOB_FTL_Garbage_Collection();
+ blk = FTL_Replace_LWBlock(BLOCK_TABLE_INDEX, &gc);
+ }
+ if (BAD_BLOCK == blk)
+ printk(KERN_ERR "%s, %s: There is no spare block. "
+ "It should never happen\n",
+ __FILE__, __func__);
+
+ nand_dbg_print(NAND_DBG_DEBUG, "New Block table Block is %d\n", blk);
+
+ return blk;
+}
+
+/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
+* Function: FTL_Replace_LWBlock
+* Inputs: Block number
+* Pointer to Garbage Collect flag
+* Outputs:
+* Description: Determine the least weared block by traversing
+* block table
+* Set Garbage collection to be called if number of spare
+* block is less than Free Block Gate count
+* Change Block table entry to map least worn block for current
+* operation
+*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/
+static u32 FTL_Replace_LWBlock(u32 wBlockNum, int *pGarbageCollect)
+{
+ u32 i;
+ u32 *pbt = (u32 *)g_pBlockTable;
+ u8 wLeastWornCounter = 0xFF;
+ u32 wLeastWornIndex = BAD_BLOCK;
+ u32 wSpareBlockNum = 0;
+ u32 wDiscardBlockNum = 0;
+
+ nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n",
+ __FILE__, __LINE__, __func__);
+
+ if (IS_SPARE_BLOCK(wBlockNum)) {
+ *pGarbageCollect = FAIL;
+ pbt[wBlockNum] = (u32)(pbt[wBlockNum] & (~SPARE_BLOCK));
+#if CMD_DMA
+ p_BTableChangesDelta =
+ (struct BTableChangesDelta *)g_pBTDelta_Free;
+ g_pBTDelta_Free += sizeof(struct BTableChangesDelta);
+ p_BTableChangesDelta->ftl_cmd_cnt =
+ ftl_cmd_cnt;
+ p_BTableChangesDelta->BT_Index = (u32)(wBlockNum);
+ p_BTableChangesDelta->BT_Entry_Value = pbt[wBlockNum];
+ p_BTableChangesDelta->ValidFields = 0x0C;
+#endif
+ return pbt[wBlockNum];
+ }
+
+ for (i = 0; i < DeviceInfo.wDataBlockNum; i++) {
+ if (IS_DISCARDED_BLOCK(i))
+ wDiscardBlockNum++;
+
+ if (IS_SPARE_BLOCK(i)) {
+ u32 wPhysicalIndex = (u32)((~BAD_BLOCK) & pbt[i]);
+ if (wPhysicalIndex > DeviceInfo.wSpectraEndBlock)
+ printk(KERN_ERR "FTL_Replace_LWBlock: "
+ "This should never occur!\n");
+ if (g_pWearCounter[wPhysicalIndex -
+ DeviceInfo.wSpectraStartBlock] <
+ wLeastWornCounter) {
+ wLeastWornCounter =
+ g_pWearCounter[wPhysicalIndex -
+ DeviceInfo.wSpectraStartBlock];
+ wLeastWornIndex = i;
+ }
+ wSpareBlockNum++;
+ }
+ }
+
+ nand_dbg_print(NAND_DBG_WARN,
+ "FTL_Replace_LWBlock: Least Worn Counter %d\n",
+ (int)wLeastWornCounter);
+
+ if ((wDiscardBlockNum >= NUM_FREE_BLOCKS_GATE) ||
+ (wSpareBlockNum <= NUM_FREE_BLOCKS_GATE))
+ *pGarbageCollect = PASS;
+ else
+ *pGarbageCollect = FAIL;
+
+ nand_dbg_print(NAND_DBG_DEBUG,
+ "FTL_Replace_LWBlock: Discarded Blocks %u Spare"
+ " Blocks %u\n",
+ (unsigned int)wDiscardBlockNum,
+ (unsigned int)wSpareBlockNum);
+
+ return FTL_Replace_OneBlock(wBlockNum, wLeastWornIndex);
+}
+
+/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
+* Function: FTL_Replace_MWBlock
+* Inputs: None
+* Outputs: most worn spare block no./BAD_BLOCK
+* Description: It finds most worn spare block.
+*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/
+static u32 FTL_Replace_MWBlock(void)
+{
+ u32 i;
+ u32 *pbt = (u32 *)g_pBlockTable;
+ u8 wMostWornCounter = 0;
+ u32 wMostWornIndex = BAD_BLOCK;
+ u32 wSpareBlockNum = 0;
+
+ nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n",
+ __FILE__, __LINE__, __func__);
+
+ for (i = 0; i < DeviceInfo.wDataBlockNum; i++) {
+ if (IS_SPARE_BLOCK(i)) {
+ u32 wPhysicalIndex = (u32)((~SPARE_BLOCK) & pbt[i]);
+ if (g_pWearCounter[wPhysicalIndex -
+ DeviceInfo.wSpectraStartBlock] >
+ wMostWornCounter) {
+ wMostWornCounter =
+ g_pWearCounter[wPhysicalIndex -
+ DeviceInfo.wSpectraStartBlock];
+ wMostWornIndex = wPhysicalIndex;
+ }
+ wSpareBlockNum++;
+ }
+ }
+
+ if (wSpareBlockNum <= 2)
+ return BAD_BLOCK;
+
+ return wMostWornIndex;
+}
+
+/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
+* Function: FTL_Replace_Block
+* Inputs: Block Address
+* Outputs: PASS=0 / FAIL=1
+* Description: If block specified by blk_addr parameter is not free,
+* replace it with the least worn block.
+*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/
+static int FTL_Replace_Block(u64 blk_addr)
+{
+ u32 current_blk = BLK_FROM_ADDR(blk_addr);
+ u32 *pbt = (u32 *)g_pBlockTable;
+ int wResult = PASS;
+ int GarbageCollect = FAIL;
+
+ nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n",
+ __FILE__, __LINE__, __func__);
+
+ if (IS_SPARE_BLOCK(current_blk)) {
+ pbt[current_blk] = (~SPARE_BLOCK) & pbt[current_blk];
+#if CMD_DMA
+ p_BTableChangesDelta =
+ (struct BTableChangesDelta *)g_pBTDelta_Free;
+ g_pBTDelta_Free += sizeof(struct BTableChangesDelta);
+ p_BTableChangesDelta->ftl_cmd_cnt =
+ ftl_cmd_cnt;
+ p_BTableChangesDelta->BT_Index = current_blk;
+ p_BTableChangesDelta->BT_Entry_Value = pbt[current_blk];
+ p_BTableChangesDelta->ValidFields = 0x0C ;
+#endif
+ return wResult;
+ }
+
+ FTL_Replace_LWBlock(current_blk, &GarbageCollect);
+
+ if (PASS == GarbageCollect)
+ wResult = GLOB_FTL_Garbage_Collection();
+
+ return wResult;
+}
+
+/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
+* Function: GLOB_FTL_Is_BadBlock
+* Inputs: block number to test
+* Outputs: PASS (block is BAD) / FAIL (block is not bad)
+* Description: test if this block number is flagged as bad
+*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/
+int GLOB_FTL_Is_BadBlock(u32 wBlockNum)
+{
+ u32 *pbt = (u32 *)g_pBlockTable;
+
+ nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n",
+ __FILE__, __LINE__, __func__);
+
+ if (wBlockNum >= DeviceInfo.wSpectraStartBlock
+ && BAD_BLOCK == (pbt[wBlockNum] & BAD_BLOCK))
+ return PASS;
+ else
+ return FAIL;
+}
+
+/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
+* Function: GLOB_FTL_Flush_Cache
+* Inputs: none
+* Outputs: PASS=0 / FAIL=1
+* Description: flush all the cache blocks to flash
+* if a cache block is not dirty, don't do anything with it
+* else, write the block and update the block table
+* Note: This function should be called at shutdown/power down.
+* to write important data into device
+*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/
+int GLOB_FTL_Flush_Cache(void)
+{
+ int i, ret;
+
+ nand_dbg_print(NAND_DBG_WARN, "%s, Line %d, Function: %s\n",
+ __FILE__, __LINE__, __func__);
+
+ for (i = 0; i < CACHE_ITEM_NUM; i++) {
+ if (SET == Cache.array[i].changed) {
+#if CMD_DMA
+#if RESTORE_CACHE_ON_CDMA_CHAIN_FAILURE
+ int_cache[ftl_cmd_cnt].item = i;
+ int_cache[ftl_cmd_cnt].cache.address =
+ Cache.array[i].address;
+ int_cache[ftl_cmd_cnt].cache.changed = CLEAR;
+#endif
+#endif
+ ret = write_back_to_l2_cache(Cache.array[i].buf, Cache.array[i].address);
+ if (PASS == ret) {
+ Cache.array[i].changed = CLEAR;
+ } else {
+ printk(KERN_ALERT "Failed when write back to L2 cache!\n");
+ /* TODO - How to handle this? */
+ }
+ }
+ }
+
+ flush_l2_cache();
+
+ return FTL_Write_Block_Table(FAIL);
+}
+
+/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
+* Function: GLOB_FTL_Page_Read
+* Inputs: pointer to data
+* logical address of data (u64 is LBA * Bytes/Page)
+* Outputs: PASS=0 / FAIL=1
+* Description: reads a page of data into RAM from the cache
+* if the data is not already in cache, read from flash to cache
+*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/
+int GLOB_FTL_Page_Read(u8 *data, u64 logical_addr)
+{
+ u16 cache_item;
+ int res = PASS;
+
+ nand_dbg_print(NAND_DBG_DEBUG, "GLOB_FTL_Page_Read - "
+ "page_addr: %llu\n", logical_addr);
+
+ cache_item = FTL_Cache_If_Hit(logical_addr);
+
+ if (UNHIT_CACHE_ITEM == cache_item) {
+ nand_dbg_print(NAND_DBG_DEBUG,
+ "GLOB_FTL_Page_Read: Cache not hit\n");
+ res = FTL_Cache_Write();
+ if (ERR == FTL_Cache_Read(logical_addr))
+ res = ERR;
+ cache_item = Cache.LRU;
+ }
+
+ FTL_Cache_Read_Page(data, logical_addr, cache_item);
+
+ return res;
+}
+
+/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
+* Function: GLOB_FTL_Page_Write
+* Inputs: pointer to data
+* address of data (ADDRESSTYPE is LBA * Bytes/Page)
+* Outputs: PASS=0 / FAIL=1
+* Description: writes a page of data from RAM to the cache
+* if the data is not already in cache, write back the
+* least recently used block and read the addressed block
+* from flash to cache
+*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/
+int GLOB_FTL_Page_Write(u8 *pData, u64 dwPageAddr)
+{
+ u16 cache_blk;
+ u32 *pbt = (u32 *)g_pBlockTable;
+ int wResult = PASS;
+
+ nand_dbg_print(NAND_DBG_TRACE, "GLOB_FTL_Page_Write - "
+ "dwPageAddr: %llu\n", dwPageAddr);
+
+ cache_blk = FTL_Cache_If_Hit(dwPageAddr);
+
+ if (UNHIT_CACHE_ITEM == cache_blk) {
+ wResult = FTL_Cache_Write();
+ if (IS_BAD_BLOCK(BLK_FROM_ADDR(dwPageAddr))) {
+ wResult = FTL_Replace_Block(dwPageAddr);
+ pbt[BLK_FROM_ADDR(dwPageAddr)] |= SPARE_BLOCK;
+ if (wResult == FAIL)
+ return FAIL;
+ }
+ if (ERR == FTL_Cache_Read(dwPageAddr))
+ wResult = ERR;
+ cache_blk = Cache.LRU;
+ FTL_Cache_Write_Page(pData, dwPageAddr, cache_blk, 0);
+ } else {
+#if CMD_DMA
+ FTL_Cache_Write_Page(pData, dwPageAddr, cache_blk,
+ LLD_CMD_FLAG_ORDER_BEFORE_REST);
+#else
+ FTL_Cache_Write_Page(pData, dwPageAddr, cache_blk, 0);
+#endif
+ }
+
+ return wResult;
+}
+
+/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
+* Function: GLOB_FTL_Block_Erase
+* Inputs: address of block to erase (now in byte format, should change to
+* block format)
+* Outputs: PASS=0 / FAIL=1
+* Description: erases the specified block
+* increments the erase count
+* If erase count reaches its upper limit,call function to
+* do the ajustment as per the relative erase count values
+*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/
+int GLOB_FTL_Block_Erase(u64 blk_addr)
+{
+ int status;
+ u32 BlkIdx;
+
+ nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n",
+ __FILE__, __LINE__, __func__);
+
+ BlkIdx = (u32)(blk_addr >> DeviceInfo.nBitsInBlockDataSize);
+
+ if (BlkIdx < DeviceInfo.wSpectraStartBlock) {
+ printk(KERN_ERR "GLOB_FTL_Block_Erase: "
+ "This should never occur\n");
+ return FAIL;
+ }
+
+#if CMD_DMA
+ status = GLOB_LLD_Erase_Block_cdma(BlkIdx, LLD_CMD_FLAG_MODE_CDMA);
+ if (status == FAIL)
+ nand_dbg_print(NAND_DBG_WARN,
+ "NAND Program fail in %s, Line %d, "
+ "Function: %s, new Bad Block %d generated!\n",
+ __FILE__, __LINE__, __func__, BlkIdx);
+#else
+ status = GLOB_LLD_Erase_Block(BlkIdx);
+ if (status == FAIL) {
+ nand_dbg_print(NAND_DBG_WARN,
+ "NAND Program fail in %s, Line %d, "
+ "Function: %s, new Bad Block %d generated!\n",
+ __FILE__, __LINE__, __func__, BlkIdx);
+ return status;
+ }
+#endif
+
+ if (DeviceInfo.MLCDevice) {
+ g_pReadCounter[BlkIdx - DeviceInfo.wSpectraStartBlock] = 0;
+ if (g_cBlockTableStatus != IN_PROGRESS_BLOCK_TABLE) {
+ g_cBlockTableStatus = IN_PROGRESS_BLOCK_TABLE;
+ FTL_Write_IN_Progress_Block_Table_Page();
+ }
+ }
+
+ g_pWearCounter[BlkIdx - DeviceInfo.wSpectraStartBlock]++;
+
+#if CMD_DMA
+ p_BTableChangesDelta =
+ (struct BTableChangesDelta *)g_pBTDelta_Free;
+ g_pBTDelta_Free += sizeof(struct BTableChangesDelta);
+ p_BTableChangesDelta->ftl_cmd_cnt = ftl_cmd_cnt;
+ p_BTableChangesDelta->WC_Index =
+ BlkIdx - DeviceInfo.wSpectraStartBlock;
+ p_BTableChangesDelta->WC_Entry_Value =
+ g_pWearCounter[BlkIdx - DeviceInfo.wSpectraStartBlock];
+ p_BTableChangesDelta->ValidFields = 0x30;
+
+ if (DeviceInfo.MLCDevice) {
+ p_BTableChangesDelta =
+ (struct BTableChangesDelta *)g_pBTDelta_Free;
+ g_pBTDelta_Free += sizeof(struct BTableChangesDelta);
+ p_BTableChangesDelta->ftl_cmd_cnt =
+ ftl_cmd_cnt;
+ p_BTableChangesDelta->RC_Index =
+ BlkIdx - DeviceInfo.wSpectraStartBlock;
+ p_BTableChangesDelta->RC_Entry_Value =
+ g_pReadCounter[BlkIdx -
+ DeviceInfo.wSpectraStartBlock];
+ p_BTableChangesDelta->ValidFields = 0xC0;
+ }
+
+ ftl_cmd_cnt++;
+#endif
+
+ if (g_pWearCounter[BlkIdx - DeviceInfo.wSpectraStartBlock] == 0xFE)
+ FTL_Adjust_Relative_Erase_Count(BlkIdx);
+
+ return status;
+}
+
+
+/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
+* Function: FTL_Adjust_Relative_Erase_Count
+* Inputs: index to block that was just incremented and is at the max
+* Outputs: PASS=0 / FAIL=1
+* Description: If any erase counts at MAX, adjusts erase count of every
+* block by substracting least worn
+* counter from counter value of every entry in wear table
+*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/
+static int FTL_Adjust_Relative_Erase_Count(u32 Index_of_MAX)
+{
+ u8 wLeastWornCounter = MAX_BYTE_VALUE;
+ u8 wWearCounter;
+ u32 i, wWearIndex;
+ u32 *pbt = (u32 *)g_pBlockTable;
+ int wResult = PASS;
+
+ nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n",
+ __FILE__, __LINE__, __func__);
+
+ for (i = 0; i < DeviceInfo.wDataBlockNum; i++) {
+ if (IS_BAD_BLOCK(i))
+ continue;
+ wWearIndex = (u32)(pbt[i] & (~BAD_BLOCK));
+
+ if ((wWearIndex - DeviceInfo.wSpectraStartBlock) < 0)
+ printk(KERN_ERR "FTL_Adjust_Relative_Erase_Count:"
+ "This should never occur\n");
+ wWearCounter = g_pWearCounter[wWearIndex -
+ DeviceInfo.wSpectraStartBlock];
+ if (wWearCounter < wLeastWornCounter)
+ wLeastWornCounter = wWearCounter;
+ }
+
+ if (wLeastWornCounter == 0) {
+ nand_dbg_print(NAND_DBG_WARN,
+ "Adjusting Wear Levelling Counters: Special Case\n");
+ g_pWearCounter[Index_of_MAX -
+ DeviceInfo.wSpectraStartBlock]--;
+#if CMD_DMA
+ p_BTableChangesDelta =
+ (struct BTableChangesDelta *)g_pBTDelta_Free;
+ g_pBTDelta_Free += sizeof(struct BTableChangesDelta);
+ p_BTableChangesDelta->ftl_cmd_cnt = ftl_cmd_cnt;
+ p_BTableChangesDelta->WC_Index =
+ Index_of_MAX - DeviceInfo.wSpectraStartBlock;
+ p_BTableChangesDelta->WC_Entry_Value =
+ g_pWearCounter[Index_of_MAX -
+ DeviceInfo.wSpectraStartBlock];
+ p_BTableChangesDelta->ValidFields = 0x30;
+#endif
+ FTL_Static_Wear_Leveling();
+ } else {
+ for (i = 0; i < DeviceInfo.wDataBlockNum; i++)
+ if (!IS_BAD_BLOCK(i)) {
+ wWearIndex = (u32)(pbt[i] & (~BAD_BLOCK));
+ g_pWearCounter[wWearIndex -
+ DeviceInfo.wSpectraStartBlock] =
+ (u8)(g_pWearCounter
+ [wWearIndex -
+ DeviceInfo.wSpectraStartBlock] -
+ wLeastWornCounter);
+#if CMD_DMA
+ p_BTableChangesDelta =
+ (struct BTableChangesDelta *)g_pBTDelta_Free;
+ g_pBTDelta_Free +=
+ sizeof(struct BTableChangesDelta);
+
+ p_BTableChangesDelta->ftl_cmd_cnt =
+ ftl_cmd_cnt;
+ p_BTableChangesDelta->WC_Index = wWearIndex -
+ DeviceInfo.wSpectraStartBlock;
+ p_BTableChangesDelta->WC_Entry_Value =
+ g_pWearCounter[wWearIndex -
+ DeviceInfo.wSpectraStartBlock];
+ p_BTableChangesDelta->ValidFields = 0x30;
+#endif
+ }
+ }
+
+ return wResult;
+}
+
+/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
+* Function: FTL_Write_IN_Progress_Block_Table_Page
+* Inputs: None
+* Outputs: None
+* Description: It writes in-progress flag page to the page next to
+* block table
+***********************************************************************/
+static int FTL_Write_IN_Progress_Block_Table_Page(void)
+{
+ int wResult = PASS;
+ u16 bt_pages;
+ u16 dwIPFPageAddr;
+#if CMD_DMA
+#else
+ u32 *pbt = (u32 *)g_pBlockTable;
+ u32 wTempBlockTableIndex;
+#endif
+
+ nand_dbg_print(NAND_DBG_WARN, "%s, Line %d, Function: %s\n",
+ __FILE__, __LINE__, __func__);
+
+ bt_pages = FTL_Get_Block_Table_Flash_Size_Pages();
+
+ dwIPFPageAddr = g_wBlockTableOffset + bt_pages;
+
+ nand_dbg_print(NAND_DBG_DEBUG, "Writing IPF at "
+ "Block %d Page %d\n",
+ g_wBlockTableIndex, dwIPFPageAddr);
+
+#if CMD_DMA
+ wResult = GLOB_LLD_Write_Page_Main_Spare_cdma(g_pIPF,
+ g_wBlockTableIndex, dwIPFPageAddr, 1,
+ LLD_CMD_FLAG_MODE_CDMA | LLD_CMD_FLAG_ORDER_BEFORE_REST);
+ if (wResult == FAIL) {
+ nand_dbg_print(NAND_DBG_WARN,
+ "NAND Program fail in %s, Line %d, "
+ "Function: %s, new Bad Block %d generated!\n",
+ __FILE__, __LINE__, __func__,
+ g_wBlockTableIndex);
+ }
+ g_wBlockTableOffset = dwIPFPageAddr + 1;
+ p_BTableChangesDelta = (struct BTableChangesDelta *)g_pBTDelta_Free;
+ g_pBTDelta_Free += sizeof(struct BTableChangesDelta);
+ p_BTableChangesDelta->ftl_cmd_cnt = ftl_cmd_cnt;
+ p_BTableChangesDelta->g_wBlockTableOffset = g_wBlockTableOffset;
+ p_BTableChangesDelta->ValidFields = 0x01;
+ ftl_cmd_cnt++;
+#else
+ wResult = GLOB_LLD_Write_Page_Main_Spare(g_pIPF,
+ g_wBlockTableIndex, dwIPFPageAddr, 1);
+ if (wResult == FAIL) {
+ nand_dbg_print(NAND_DBG_WARN,
+ "NAND Program fail in %s, Line %d, "
+ "Function: %s, new Bad Block %d generated!\n",
+ __FILE__, __LINE__, __func__,
+ (int)g_wBlockTableIndex);
+ MARK_BLOCK_AS_BAD(pbt[BLOCK_TABLE_INDEX]);
+ wTempBlockTableIndex = FTL_Replace_Block_Table();
+ bt_block_changed = 1;
+ if (BAD_BLOCK == wTempBlockTableIndex)
+ return ERR;
+ g_wBlockTableIndex = wTempBlockTableIndex;
+ g_wBlockTableOffset = 0;
+ /* Block table tag is '00'. Means it's used one */
+ pbt[BLOCK_TABLE_INDEX] = g_wBlockTableIndex;
+ return FAIL;
+ }
+ g_wBlockTableOffset = dwIPFPageAddr + 1;
+#endif
+ return wResult;
+}
+
+/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
+* Function: FTL_Read_Disturbance
+* Inputs: block address
+* Outputs: PASS=0 / FAIL=1
+* Description: used to handle read disturbance. Data in block that
+* reaches its read limit is moved to new block
+*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/
+int FTL_Read_Disturbance(u32 blk_addr)
+{
+ int wResult = FAIL;
+ u32 *pbt = (u32 *) g_pBlockTable;
+ u32 dwOldBlockAddr = blk_addr;
+ u32 wBlockNum;
+ u32 i;
+ u32 wLeastReadCounter = 0xFFFF;
+ u32 wLeastReadIndex = BAD_BLOCK;
+ u32 wSpareBlockNum = 0;
+ u32 wTempNode;
+ u32 wReplacedNode;
+ u8 *g_pTempBuf;
+
+ nand_dbg_print(NAND_DBG_DEBUG, "%s, Line %d, Function: %s\n",
+ __FILE__, __LINE__, __func__);
+
+#if CMD_DMA
+ g_pTempBuf = cp_back_buf_copies[cp_back_buf_idx];
+ cp_back_buf_idx++;
+ if (cp_back_buf_idx > COPY_BACK_BUF_NUM) {
+ printk(KERN_ERR "cp_back_buf_copies overflow! Exit."
+ "Maybe too many pending commands in your CDMA chain.\n");
+ return FAIL;
+ }
+#else
+ g_pTempBuf = tmp_buf_read_disturbance;
+#endif
+
+ wBlockNum = FTL_Get_Block_Index(blk_addr);
+
+ do {
+ /* This is a bug.Here 'i' should be logical block number
+ * and start from 1 (0 is reserved for block table).
+ * Have fixed it. - Yunpeng 2008. 12. 19
+ */
+ for (i = 1; i < DeviceInfo.wDataBlockNum; i++) {
+ if (IS_SPARE_BLOCK(i)) {
+ u32 wPhysicalIndex =
+ (u32)((~SPARE_BLOCK) & pbt[i]);
+ if (g_pReadCounter[wPhysicalIndex -
+ DeviceInfo.wSpectraStartBlock] <
+ wLeastReadCounter) {
+ wLeastReadCounter =
+ g_pReadCounter[wPhysicalIndex -
+ DeviceInfo.wSpectraStartBlock];
+ wLeastReadIndex = i;
+ }
+ wSpareBlockNum++;
+ }
+ }
+
+ if (wSpareBlockNum <= NUM_FREE_BLOCKS_GATE) {
+ wResult = GLOB_FTL_Garbage_Collection();
+ if (PASS == wResult)
+ continue;
+ else
+ break;
+ } else {
+ wTempNode = (u32)(DISCARD_BLOCK | pbt[wBlockNum]);
+ wReplacedNode = (u32)((~SPARE_BLOCK) &
+ pbt[wLeastReadIndex]);
+#if CMD_DMA
+ pbt[wBlockNum] = wReplacedNode;
+ pbt[wLeastReadIndex] = wTempNode;
+ p_BTableChangesDelta =
+ (struct BTableChangesDelta *)g_pBTDelta_Free;
+ g_pBTDelta_Free += sizeof(struct BTableChangesDelta);
+
+ p_BTableChangesDelta->ftl_cmd_cnt =
+ ftl_cmd_cnt;
+ p_BTableChangesDelta->BT_Index = wBlockNum;
+ p_BTableChangesDelta->BT_Entry_Value = pbt[wBlockNum];
+ p_BTableChangesDelta->ValidFields = 0x0C;
+
+ p_BTableChangesDelta =
+ (struct BTableChangesDelta *)g_pBTDelta_Free;
+ g_pBTDelta_Free += sizeof(struct BTableChangesDelta);
+
+ p_BTableChangesDelta->ftl_cmd_cnt =
+ ftl_cmd_cnt;
+ p_BTableChangesDelta->BT_Index = wLeastReadIndex;
+ p_BTableChangesDelta->BT_Entry_Value =
+ pbt[wLeastReadIndex];
+ p_BTableChangesDelta->ValidFields = 0x0C;
+
+ wResult = GLOB_LLD_Read_Page_Main_cdma(g_pTempBuf,
+ dwOldBlockAddr, 0, DeviceInfo.wPagesPerBlock,
+ LLD_CMD_FLAG_MODE_CDMA);
+ if (wResult == FAIL)
+ return wResult;
+
+ ftl_cmd_cnt++;
+
+ if (wResult != FAIL) {
+ if (FAIL == GLOB_LLD_Write_Page_Main_cdma(
+ g_pTempBuf, pbt[wBlockNum], 0,
+ DeviceInfo.wPagesPerBlock)) {
+ nand_dbg_print(NAND_DBG_WARN,
+ "NAND Program fail in "
+ "%s, Line %d, Function: %s, "
+ "new Bad Block %d "
+ "generated!\n",
+ __FILE__, __LINE__, __func__,
+ (int)pbt[wBlockNum]);
+ wResult = FAIL;
+ MARK_BLOCK_AS_BAD(pbt[wBlockNum]);
+ }
+ ftl_cmd_cnt++;
+ }
+#else
+ wResult = GLOB_LLD_Read_Page_Main(g_pTempBuf,
+ dwOldBlockAddr, 0, DeviceInfo.wPagesPerBlock);
+ if (wResult == FAIL)
+ return wResult;
+
+ if (wResult != FAIL) {
+ /* This is a bug. At this time, pbt[wBlockNum]
+ is still the physical address of
+ discard block, and should not be write.
+ Have fixed it as below.
+ -- Yunpeng 2008.12.19
+ */
+ wResult = GLOB_LLD_Write_Page_Main(g_pTempBuf,
+ wReplacedNode, 0,
+ DeviceInfo.wPagesPerBlock);
+ if (wResult == FAIL) {
+ nand_dbg_print(NAND_DBG_WARN,
+ "NAND Program fail in "
+ "%s, Line %d, Function: %s, "
+ "new Bad Block %d "
+ "generated!\n",
+ __FILE__, __LINE__, __func__,
+ (int)wReplacedNode);
+ MARK_BLOCK_AS_BAD(wReplacedNode);
+ } else {
+ pbt[wBlockNum] = wReplacedNode;
+ pbt[wLeastReadIndex] = wTempNode;
+ }
+ }
+
+ if ((wResult == PASS) && (g_cBlockTableStatus !=
+ IN_PROGRESS_BLOCK_TABLE)) {
+ g_cBlockTableStatus = IN_PROGRESS_BLOCK_TABLE;
+ FTL_Write_IN_Progress_Block_Table_Page();
+ }
+#endif
+ }
+ } while (wResult != PASS)
+ ;
+
+#if CMD_DMA
+ /* ... */
+#endif
+
+ return wResult;
+}
+
diff --git a/drivers/staging/spectra/flash.h b/drivers/staging/spectra/flash.h
new file mode 100644
index 00000000000..5ed05805cf6
--- /dev/null
+++ b/drivers/staging/spectra/flash.h
@@ -0,0 +1,198 @@
+/*
+ * NAND Flash Controller Device Driver
+ * Copyright (c) 2009, Intel Corporation and its suppliers.
+ *
+ * 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 _FLASH_INTERFACE_
+#define _FLASH_INTERFACE_
+
+#include "ffsport.h"
+#include "spectraswconfig.h"
+
+#define MAX_BYTE_VALUE 0xFF
+#define MAX_WORD_VALUE 0xFFFF
+#define MAX_U32_VALUE 0xFFFFFFFF
+
+#define MAX_BLOCKNODE_VALUE 0xFFFFFF
+#define DISCARD_BLOCK 0x800000
+#define SPARE_BLOCK 0x400000
+#define BAD_BLOCK 0xC00000
+
+#define UNHIT_CACHE_ITEM 0xFFFF
+
+#define NAND_CACHE_INIT_ADDR 0xffffffffffffffffULL
+
+#define IN_PROGRESS_BLOCK_TABLE 0x00
+#define CURRENT_BLOCK_TABLE 0x01
+
+#define BTSIG_OFFSET (0)
+#define BTSIG_BYTES (5)
+#define BTSIG_DELTA (3)
+
+#define MAX_READ_COUNTER 0x2710
+
+#define FIRST_BT_ID (1)
+#define LAST_BT_ID (254)
+#define BTBLOCK_INVAL (u32)(0xFFFFFFFF)
+
+struct device_info_tag {
+ u16 wDeviceMaker;
+ u16 wDeviceID;
+ u32 wDeviceType;
+ u32 wSpectraStartBlock;
+ u32 wSpectraEndBlock;
+ u32 wTotalBlocks;
+ u16 wPagesPerBlock;
+ u16 wPageSize;
+ u16 wPageDataSize;
+ u16 wPageSpareSize;
+ u16 wNumPageSpareFlag;
+ u16 wECCBytesPerSector;
+ u32 wBlockSize;
+ u32 wBlockDataSize;
+ u32 wDataBlockNum;
+ u8 bPlaneNum;
+ u16 wDeviceMainAreaSize;
+ u16 wDeviceSpareAreaSize;
+ u16 wDevicesConnected;
+ u16 wDeviceWidth;
+ u16 wHWRevision;
+ u16 wHWFeatures;
+
+ u16 wONFIDevFeatures;
+ u16 wONFIOptCommands;
+ u16 wONFITimingMode;
+ u16 wONFIPgmCacheTimingMode;
+
+ u16 MLCDevice;
+ u16 wSpareSkipBytes;
+
+ u8 nBitsInPageNumber;
+ u8 nBitsInPageDataSize;
+ u8 nBitsInBlockDataSize;
+};
+
+extern struct device_info_tag DeviceInfo;
+
+/* Cache item format */
+struct flash_cache_item_tag {
+ u64 address;
+ u16 use_cnt;
+ u16 changed;
+ u8 *buf;
+};
+
+struct flash_cache_tag {
+ u32 cache_item_size; /* Size in bytes of each cache item */
+ u16 pages_per_item; /* How many NAND pages in each cache item */
+ u16 LRU; /* No. of the least recently used cache item */
+ struct flash_cache_item_tag array[CACHE_ITEM_NUM];
+};
+
+/*
+ *Data structure for each list node of the managment table
+ * used for the Level 2 Cache. Each node maps one logical NAND block.
+ */
+struct spectra_l2_cache_list {
+ struct list_head list;
+ u32 logical_blk_num; /* Logical block number */
+ u32 pages_array[]; /* Page map array of this logical block.
+ * Array index is the logical block number,
+ * and for every item of this arry:
+ * high 16 bit is index of the L2 cache block num,
+ * low 16 bit is the phy page num
+ * of the above L2 cache block.
+ * This array will be kmalloc during run time.
+ */
+};
+
+struct spectra_l2_cache_info {
+ u32 blk_array[BLK_NUM_FOR_L2_CACHE];
+ u16 cur_blk_idx; /* idx to the phy block number of current using */
+ u16 cur_page_num; /* pages number of current using */
+ struct spectra_l2_cache_list table; /* First node of the table */
+};
+
+#define RESTORE_CACHE_ON_CDMA_CHAIN_FAILURE 1
+
+#if RESTORE_CACHE_ON_CDMA_CHAIN_FAILURE
+struct flash_cache_mod_item_tag {
+ u64 address;
+ u8 changed;
+};
+
+struct flash_cache_delta_list_tag {
+ u8 item; /* used cache item */
+ struct flash_cache_mod_item_tag cache;
+};
+#endif
+
+extern struct flash_cache_tag Cache;
+
+extern u8 *buf_read_page_main_spare;
+extern u8 *buf_write_page_main_spare;
+extern u8 *buf_read_page_spare;
+extern u8 *buf_get_bad_block;
+extern u8 *cdma_desc_buf;
+extern u8 *memcp_desc_buf;
+
+/* struture used for IndentfyDevice function */
+struct spectra_indentfy_dev_tag {
+ u32 NumBlocks;
+ u16 PagesPerBlock;
+ u16 PageDataSize;
+ u16 wECCBytesPerSector;
+ u32 wDataBlockNum;
+};
+
+int GLOB_FTL_Flash_Init(void);
+int GLOB_FTL_Flash_Release(void);
+/*void GLOB_FTL_Erase_Flash(void);*/
+int GLOB_FTL_Block_Erase(u64 block_addr);
+int GLOB_FTL_Is_BadBlock(u32 block_num);
+int GLOB_FTL_IdentifyDevice(struct spectra_indentfy_dev_tag *dev_data);
+int GLOB_FTL_Event_Status(int *);
+u16 glob_ftl_execute_cmds(void);
+
+/*int FTL_Read_Disturbance(ADDRESSTYPE dwBlockAddr);*/
+int FTL_Read_Disturbance(u32 dwBlockAddr);
+
+/*Flash r/w based on cache*/
+int GLOB_FTL_Page_Read(u8 *read_data, u64 page_addr);
+int GLOB_FTL_Page_Write(u8 *write_data, u64 page_addr);
+int GLOB_FTL_Wear_Leveling(void);
+int GLOB_FTL_Flash_Format(void);
+int GLOB_FTL_Init(void);
+int GLOB_FTL_Flush_Cache(void);
+int GLOB_FTL_Garbage_Collection(void);
+int GLOB_FTL_BT_Garbage_Collection(void);
+void GLOB_FTL_Cache_Release(void);
+u8 *get_blk_table_start_addr(void);
+u8 *get_wear_leveling_table_start_addr(void);
+unsigned long get_blk_table_len(void);
+unsigned long get_wear_leveling_table_len(void);
+
+#if DEBUG_BNDRY
+void debug_boundary_lineno_error(int chnl, int limit, int no, int lineno,
+ char *filename);
+#define debug_boundary_error(chnl, limit, no) debug_boundary_lineno_error(chnl,\
+ limit, no, __LINE__, __FILE__)
+#else
+#define debug_boundary_error(chnl, limit, no) ;
+#endif
+
+#endif /*_FLASH_INTERFACE_*/
diff --git a/drivers/staging/spectra/lld.c b/drivers/staging/spectra/lld.c
new file mode 100644
index 00000000000..5c3b9762dc3
--- /dev/null
+++ b/drivers/staging/spectra/lld.c
@@ -0,0 +1,339 @@
+/*
+ * NAND Flash Controller Device Driver
+ * Copyright (c) 2009, Intel Corporation and its suppliers.
+ *
+ * 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 "spectraswconfig.h"
+#include "ffsport.h"
+#include "ffsdefs.h"
+#include "lld.h"
+#include "lld_nand.h"
+
+/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/
+#if FLASH_EMU /* vector all the LLD calls to the LLD_EMU code */
+#include "lld_emu.h"
+#include "lld_cdma.h"
+
+/* common functions: */
+u16 GLOB_LLD_Flash_Reset(void)
+{
+ return emu_Flash_Reset();
+}
+
+u16 GLOB_LLD_Read_Device_ID(void)
+{
+ return emu_Read_Device_ID();
+}
+
+int GLOB_LLD_Flash_Release(void)
+{
+ return emu_Flash_Release();
+}
+
+u16 GLOB_LLD_Flash_Init(void)
+{
+ return emu_Flash_Init();
+}
+
+u16 GLOB_LLD_Erase_Block(u32 block_add)
+{
+ return emu_Erase_Block(block_add);
+}
+
+u16 GLOB_LLD_Write_Page_Main(u8 *write_data, u32 block, u16 Page,
+ u16 PageCount)
+{
+ return emu_Write_Page_Main(write_data, block, Page, PageCount);
+}
+
+u16 GLOB_LLD_Read_Page_Main(u8 *read_data, u32 block, u16 Page,
+ u16 PageCount)
+{
+ return emu_Read_Page_Main(read_data, block, Page, PageCount);
+}
+
+u16 GLOB_LLD_Read_Page_Main_Polling(u8 *read_data,
+ u32 block, u16 page, u16 page_count)
+{
+ return emu_Read_Page_Main(read_data, block, page, page_count);
+}
+
+u16 GLOB_LLD_Write_Page_Main_Spare(u8 *write_data, u32 block,
+ u16 Page, u16 PageCount)
+{
+ return emu_Write_Page_Main_Spare(write_data, block, Page, PageCount);
+}
+
+u16 GLOB_LLD_Read_Page_Main_Spare(u8 *read_data, u32 block,
+ u16 Page, u16 PageCount)
+{
+ return emu_Read_Page_Main_Spare(read_data, block, Page, PageCount);
+}
+
+u16 GLOB_LLD_Write_Page_Spare(u8 *write_data, u32 block, u16 Page,
+ u16 PageCount)
+{
+ return emu_Write_Page_Spare(write_data, block, Page, PageCount);
+}
+
+u16 GLOB_LLD_Read_Page_Spare(u8 *read_data, u32 block, u16 Page,
+ u16 PageCount)
+{
+ return emu_Read_Page_Spare(read_data, block, Page, PageCount);
+}
+
+u16 GLOB_LLD_Get_Bad_Block(u32 block)
+{
+ return emu_Get_Bad_Block(block);
+}
+
+#endif /* FLASH_EMU */
+
+/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/
+#if FLASH_MTD /* vector all the LLD calls to the LLD_MTD code */
+#include "lld_mtd.h"
+#include "lld_cdma.h"
+
+/* common functions: */
+u16 GLOB_LLD_Flash_Reset(void)
+{
+ return mtd_Flash_Reset();
+}
+
+u16 GLOB_LLD_Read_Device_ID(void)
+{
+ return mtd_Read_Device_ID();
+}
+
+int GLOB_LLD_Flash_Release(void)
+{
+ return mtd_Flash_Release();
+}
+
+u16 GLOB_LLD_Flash_Init(void)
+{
+ return mtd_Flash_Init();
+}
+
+u16 GLOB_LLD_Erase_Block(u32 block_add)
+{
+ return mtd_Erase_Block(block_add);
+}
+
+u16 GLOB_LLD_Write_Page_Main(u8 *write_data, u32 block, u16 Page,
+ u16 PageCount)
+{
+ return mtd_Write_Page_Main(write_data, block, Page, PageCount);
+}
+
+u16 GLOB_LLD_Read_Page_Main(u8 *read_data, u32 block, u16 Page,
+ u16 PageCount)
+{
+ return mtd_Read_Page_Main(read_data, block, Page, PageCount);
+}
+
+u16 GLOB_LLD_Read_Page_Main_Polling(u8 *read_data,
+ u32 block, u16 page, u16 page_count)
+{
+ return mtd_Read_Page_Main(read_data, block, page, page_count);
+}
+
+u16 GLOB_LLD_Write_Page_Main_Spare(u8 *write_data, u32 block,
+ u16 Page, u16 PageCount)
+{
+ return mtd_Write_Page_Main_Spare(write_data, block, Page, PageCount);
+}
+
+u16 GLOB_LLD_Read_Page_Main_Spare(u8 *read_data, u32 block,
+ u16 Page, u16 PageCount)
+{
+ return mtd_Read_Page_Main_Spare(read_data, block, Page, PageCount);
+}
+
+u16 GLOB_LLD_Write_Page_Spare(u8 *write_data, u32 block, u16 Page,
+ u16 PageCount)
+{
+ return mtd_Write_Page_Spare(write_data, block, Page, PageCount);
+}
+
+u16 GLOB_LLD_Read_Page_Spare(u8 *read_data, u32 block, u16 Page,
+ u16 PageCount)
+{
+ return mtd_Read_Page_Spare(read_data, block, Page, PageCount);
+}
+
+u16 GLOB_LLD_Get_Bad_Block(u32 block)
+{
+ return mtd_Get_Bad_Block(block);
+}
+
+#endif /* FLASH_MTD */
+
+/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/
+#if FLASH_NAND /* vector all the LLD calls to the NAND controller code */
+#include "lld_nand.h"
+#include "lld_cdma.h"
+#include "flash.h"
+
+/* common functions for LLD_NAND */
+void GLOB_LLD_ECC_Control(int enable)
+{
+ NAND_ECC_Ctrl(enable);
+}
+
+/* common functions for LLD_NAND */
+u16 GLOB_LLD_Flash_Reset(void)
+{
+ return NAND_Flash_Reset();
+}
+
+u16 GLOB_LLD_Read_Device_ID(void)
+{
+ return NAND_Read_Device_ID();
+}
+
+u16 GLOB_LLD_UnlockArrayAll(void)
+{
+ return NAND_UnlockArrayAll();
+}
+
+u16 GLOB_LLD_Flash_Init(void)
+{
+ return NAND_Flash_Init();
+}
+
+int GLOB_LLD_Flash_Release(void)
+{
+ return nand_release_spectra();
+}
+
+u16 GLOB_LLD_Erase_Block(u32 block_add)
+{
+ return NAND_Erase_Block(block_add);
+}
+
+
+u16 GLOB_LLD_Write_Page_Main(u8 *write_data, u32 block, u16 Page,
+ u16 PageCount)
+{
+ return NAND_Write_Page_Main(write_data, block, Page, PageCount);
+}
+
+u16 GLOB_LLD_Read_Page_Main(u8 *read_data, u32 block, u16 page,
+ u16 page_count)
+{
+ if (page_count == 1) /* Using polling to improve read speed */
+ return NAND_Read_Page_Main_Polling(read_data, block, page, 1);
+ else
+ return NAND_Read_Page_Main(read_data, block, page, page_count);
+}
+
+u16 GLOB_LLD_Read_Page_Main_Polling(u8 *read_data,
+ u32 block, u16 page, u16 page_count)
+{
+ return NAND_Read_Page_Main_Polling(read_data,
+ block, page, page_count);
+}
+
+u16 GLOB_LLD_Write_Page_Main_Spare(u8 *write_data, u32 block,
+ u16 Page, u16 PageCount)
+{
+ return NAND_Write_Page_Main_Spare(write_data, block, Page, PageCount);
+}
+
+u16 GLOB_LLD_Write_Page_Spare(u8 *write_data, u32 block, u16 Page,
+ u16 PageCount)
+{
+ return NAND_Write_Page_Spare(write_data, block, Page, PageCount);
+}
+
+u16 GLOB_LLD_Read_Page_Main_Spare(u8 *read_data, u32 block,
+ u16 page, u16 page_count)
+{
+ return NAND_Read_Page_Main_Spare(read_data, block, page, page_count);
+}
+
+u16 GLOB_LLD_Read_Page_Spare(u8 *read_data, u32 block, u16 Page,
+ u16 PageCount)
+{
+ return NAND_Read_Page_Spare(read_data, block, Page, PageCount);
+}
+
+u16 GLOB_LLD_Get_Bad_Block(u32 block)
+{
+ return NAND_Get_Bad_Block(block);
+}
+
+#if CMD_DMA
+u16 GLOB_LLD_Event_Status(void)
+{
+ return CDMA_Event_Status();
+}
+
+u16 glob_lld_execute_cmds(void)
+{
+ return CDMA_Execute_CMDs();
+}
+
+u16 GLOB_LLD_MemCopy_CMD(u8 *dest, u8 *src,
+ u32 ByteCount, u16 flag)
+{
+ /* Replace the hardware memcopy with software memcpy function */
+ if (CDMA_Execute_CMDs())
+ return FAIL;
+ memcpy(dest, src, ByteCount);
+ return PASS;
+
+ /* return CDMA_MemCopy_CMD(dest, src, ByteCount, flag); */
+}
+
+u16 GLOB_LLD_Erase_Block_cdma(u32 block, u16 flags)
+{
+ return CDMA_Data_CMD(ERASE_CMD, 0, block, 0, 0, flags);
+}
+
+u16 GLOB_LLD_Write_Page_Main_cdma(u8 *data, u32 block, u16 page, u16 count)
+{
+ return CDMA_Data_CMD(WRITE_MAIN_CMD, data, block, page, count, 0);
+}
+
+u16 GLOB_LLD_Read_Page_Main_cdma(u8 *data, u32 block, u16 page,
+ u16 count, u16 flags)
+{
+ return CDMA_Data_CMD(READ_MAIN_CMD, data, block, page, count, flags);
+}
+
+u16 GLOB_LLD_Write_Page_Main_Spare_cdma(u8 *data, u32 block, u16 page,
+ u16 count, u16 flags)
+{
+ return CDMA_Data_CMD(WRITE_MAIN_SPARE_CMD,
+ data, block, page, count, flags);
+}
+
+u16 GLOB_LLD_Read_Page_Main_Spare_cdma(u8 *data,
+ u32 block, u16 page, u16 count)
+{
+ return CDMA_Data_CMD(READ_MAIN_SPARE_CMD, data, block, page, count,
+ LLD_CMD_FLAG_MODE_CDMA);
+}
+
+#endif /* CMD_DMA */
+#endif /* FLASH_NAND */
+
+/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/
+
+/* end of LLD.c */
diff --git a/drivers/staging/spectra/lld.h b/drivers/staging/spectra/lld.h
new file mode 100644
index 00000000000..d3738e0e1fe
--- /dev/null
+++ b/drivers/staging/spectra/lld.h
@@ -0,0 +1,111 @@
+/*
+ * NAND Flash Controller Device Driver
+ * Copyright (c) 2009, Intel Corporation and its suppliers.
+ *
+ * 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 _LLD_
+#define _LLD_
+
+#include "ffsport.h"
+#include "spectraswconfig.h"
+#include "flash.h"
+
+#define GOOD_BLOCK 0
+#define DEFECTIVE_BLOCK 1
+#define READ_ERROR 2
+
+#define CLK_X 5
+#define CLK_MULTI 4
+
+/* Typedefs */
+
+/* prototypes: API for LLD */
+/* Currently, Write_Page_Main
+ * MemCopy
+ * Read_Page_Main_Spare
+ * do not have flag because they were not implemented prior to this
+ * They are not being added to keep changes to a minimum for now.
+ * Currently, they are not required (only reqd for Wr_P_M_S.)
+ * Later on, these NEED to be changed.
+ */
+
+extern void GLOB_LLD_ECC_Control(int enable);
+
+extern u16 GLOB_LLD_Flash_Reset(void);
+
+extern u16 GLOB_LLD_Read_Device_ID(void);
+
+extern u16 GLOB_LLD_UnlockArrayAll(void);
+
+extern u16 GLOB_LLD_Flash_Init(void);
+
+extern int GLOB_LLD_Flash_Release(void);
+
+extern u16 GLOB_LLD_Erase_Block(u32 block_add);
+
+extern u16 GLOB_LLD_Write_Page_Main(u8 *write_data,
+ u32 block, u16 Page, u16 PageCount);
+
+extern u16 GLOB_LLD_Read_Page_Main(u8 *read_data,
+ u32 block, u16 page, u16 page_count);
+
+extern u16 GLOB_LLD_Read_Page_Main_Polling(u8 *read_data,
+ u32 block, u16 page, u16 page_count);
+
+extern u16 GLOB_LLD_Write_Page_Main_Spare(u8 *write_data,
+ u32 block, u16 Page, u16 PageCount);
+
+extern u16 GLOB_LLD_Write_Page_Spare(u8 *write_data,
+ u32 block, u16 Page, u16 PageCount);
+
+extern u16 GLOB_LLD_Read_Page_Main_Spare(u8 *read_data,
+ u32 block, u16 page, u16 page_count);
+
+extern u16 GLOB_LLD_Read_Page_Spare(u8 *read_data,
+ u32 block, u16 Page, u16 PageCount);
+
+extern u16 GLOB_LLD_Get_Bad_Block(u32 block);
+
+extern u16 GLOB_LLD_Event_Status(void);
+
+extern u16 GLOB_LLD_MemCopy_CMD(u8 *dest, u8 *src, u32 ByteCount, u16 flag);
+
+extern u16 glob_lld_execute_cmds(void);
+
+extern u16 GLOB_LLD_Erase_Block_cdma(u32 block, u16 flags);
+
+extern u16 GLOB_LLD_Write_Page_Main_cdma(u8 *data,
+ u32 block, u16 page, u16 count);
+
+extern u16 GLOB_LLD_Read_Page_Main_cdma(u8 *data,
+ u32 block, u16 page, u16 count, u16 flags);
+
+extern u16 GLOB_LLD_Write_Page_Main_Spare_cdma(u8 *data,
+ u32 block, u16 page, u16 count, u16 flags);
+
+extern u16 GLOB_LLD_Read_Page_Main_Spare_cdma(u8 *data,
+ u32 block, u16 page, u16 count);
+
+#define LLD_CMD_FLAG_ORDER_BEFORE_REST (0x1)
+#define LLD_CMD_FLAG_MODE_CDMA (0x8)
+
+
+#endif /*_LLD_ */
+
+
diff --git a/drivers/staging/spectra/lld_cdma.c b/drivers/staging/spectra/lld_cdma.c
new file mode 100644
index 00000000000..c6e76103d43
--- /dev/null
+++ b/drivers/staging/spectra/lld_cdma.c
@@ -0,0 +1,910 @@
+/*
+ * NAND Flash Controller Device Driver
+ * Copyright (c) 2009, Intel Corporation and its suppliers.
+ *
+ * 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/fs.h>
+#include <linux/slab.h>
+
+#include "spectraswconfig.h"
+#include "lld.h"
+#include "lld_nand.h"
+#include "lld_cdma.h"
+#include "lld_emu.h"
+#include "flash.h"
+#include "nand_regs.h"
+
+#define MAX_PENDING_CMDS 4
+#define MODE_02 (0x2 << 26)
+
+/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
+* Function: CDMA_Data_Cmd
+* Inputs: cmd code (aligned for hw)
+* data: pointer to source or destination
+* block: block address
+* page: page address
+* num: num pages to transfer
+* Outputs: PASS
+* Description: This function takes the parameters and puts them
+* into the "pending commands" array.
+* It does not parse or validate the parameters.
+* The array index is same as the tag.
+*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/
+u16 CDMA_Data_CMD(u8 cmd, u8 *data, u32 block, u16 page, u16 num, u16 flags)
+{
+ u8 bank;
+
+ nand_dbg_print(NAND_DBG_DEBUG, "%s, Line %d, Function: %s\n",
+ __FILE__, __LINE__, __func__);
+
+ if (0 == cmd)
+ nand_dbg_print(NAND_DBG_DEBUG,
+ "%s, Line %d, Illegal cmd (0)\n", __FILE__, __LINE__);
+
+ /* If a command of another bank comes, then first execute */
+ /* pending commands of the current bank, then set the new */
+ /* bank as current bank */
+ bank = block / (DeviceInfo.wTotalBlocks / totalUsedBanks);
+ if (bank != info.flash_bank) {
+ nand_dbg_print(NAND_DBG_WARN,
+ "Will access new bank. old bank: %d, new bank: %d\n",
+ info.flash_bank, bank);
+ if (CDMA_Execute_CMDs()) {
+ printk(KERN_ERR "CDMA_Execute_CMDs fail!\n");
+ return FAIL;
+ }
+ info.flash_bank = bank;
+ }
+
+ info.pcmds[info.pcmds_num].CMD = cmd;
+ info.pcmds[info.pcmds_num].DataAddr = data;
+ info.pcmds[info.pcmds_num].Block = block;
+ info.pcmds[info.pcmds_num].Page = page;
+ info.pcmds[info.pcmds_num].PageCount = num;
+ info.pcmds[info.pcmds_num].DataDestAddr = 0;
+ info.pcmds[info.pcmds_num].DataSrcAddr = 0;
+ info.pcmds[info.pcmds_num].MemCopyByteCnt = 0;
+ info.pcmds[info.pcmds_num].Flags = flags;
+ info.pcmds[info.pcmds_num].Status = 0xB0B;
+
+ switch (cmd) {
+ case WRITE_MAIN_SPARE_CMD:
+ Conv_Main_Spare_Data_Log2Phy_Format(data, num);
+ break;
+ case WRITE_SPARE_CMD:
+ Conv_Spare_Data_Log2Phy_Format(data);
+ break;
+ default:
+ break;
+ }
+
+ info.pcmds_num++;
+
+ if (info.pcmds_num >= MAX_PENDING_CMDS) {
+ if (CDMA_Execute_CMDs()) {
+ printk(KERN_ERR "CDMA_Execute_CMDs fail!\n");
+ return FAIL;
+ }
+ }
+
+ return PASS;
+}
+
+/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
+* Function: CDMA_MemCopy_CMD
+* Inputs: dest: pointer to destination
+* src: pointer to source
+* count: num bytes to transfer
+* Outputs: PASS
+* Description: This function takes the parameters and puts them
+* into the "pending commands" array.
+* It does not parse or validate the parameters.
+* The array index is same as the tag.
+*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/
+u16 CDMA_MemCopy_CMD(u8 *dest, u8 *src, u32 byte_cnt, u16 flags)
+{
+ nand_dbg_print(NAND_DBG_DEBUG, "%s, Line %d, Function: %s\n",
+ __FILE__, __LINE__, __func__);
+
+ info.pcmds[info.pcmds_num].CMD = MEMCOPY_CMD;
+ info.pcmds[info.pcmds_num].DataAddr = 0;
+ info.pcmds[info.pcmds_num].Block = 0;
+ info.pcmds[info.pcmds_num].Page = 0;
+ info.pcmds[info.pcmds_num].PageCount = 0;
+ info.pcmds[info.pcmds_num].DataDestAddr = dest;
+ info.pcmds[info.pcmds_num].DataSrcAddr = src;
+ info.pcmds[info.pcmds_num].MemCopyByteCnt = byte_cnt;
+ info.pcmds[info.pcmds_num].Flags = flags;
+ info.pcmds[info.pcmds_num].Status = 0xB0B;
+
+ info.pcmds_num++;
+
+ if (info.pcmds_num >= MAX_PENDING_CMDS) {
+ if (CDMA_Execute_CMDs()) {
+ printk(KERN_ERR "CDMA_Execute_CMDs fail!\n");
+ return FAIL;
+ }
+ }
+
+ return PASS;
+}
+
+#if 0
+/* Prints the PendingCMDs array */
+void print_pending_cmds(void)
+{
+ u16 i;
+
+ nand_dbg_print(NAND_DBG_DEBUG, "%s, Line %d, Function: %s\n",
+ __FILE__, __LINE__, __func__);
+
+ for (i = 0; i < info.pcmds_num; i++) {
+ nand_dbg_print(NAND_DBG_DEBUG, "\ni: %d\n", i);
+ switch (info.pcmds[i].CMD) {
+ case ERASE_CMD:
+ nand_dbg_print(NAND_DBG_DEBUG,
+ "Erase Command (0x%x)\n",
+ info.pcmds[i].CMD);
+ break;
+ case WRITE_MAIN_CMD:
+ nand_dbg_print(NAND_DBG_DEBUG,
+ "Write Main Command (0x%x)\n",
+ info.pcmds[i].CMD);
+ break;
+ case WRITE_MAIN_SPARE_CMD:
+ nand_dbg_print(NAND_DBG_DEBUG,
+ "Write Main Spare Command (0x%x)\n",
+ info.pcmds[i].CMD);
+ break;
+ case READ_MAIN_SPARE_CMD:
+ nand_dbg_print(NAND_DBG_DEBUG,
+ "Read Main Spare Command (0x%x)\n",
+ info.pcmds[i].CMD);
+ break;
+ case READ_MAIN_CMD:
+ nand_dbg_print(NAND_DBG_DEBUG,
+ "Read Main Command (0x%x)\n",
+ info.pcmds[i].CMD);
+ break;
+ case MEMCOPY_CMD:
+ nand_dbg_print(NAND_DBG_DEBUG,
+ "Memcopy Command (0x%x)\n",
+ info.pcmds[i].CMD);
+ break;
+ case DUMMY_CMD:
+ nand_dbg_print(NAND_DBG_DEBUG,
+ "Dummy Command (0x%x)\n",
+ info.pcmds[i].CMD);
+ break;
+ default:
+ nand_dbg_print(NAND_DBG_DEBUG,
+ "Illegal Command (0x%x)\n",
+ info.pcmds[i].CMD);
+ break;
+ }
+
+ nand_dbg_print(NAND_DBG_DEBUG, "DataAddr: 0x%x\n",
+ (u32)info.pcmds[i].DataAddr);
+ nand_dbg_print(NAND_DBG_DEBUG, "Block: %d\n",
+ info.pcmds[i].Block);
+ nand_dbg_print(NAND_DBG_DEBUG, "Page: %d\n",
+ info.pcmds[i].Page);
+ nand_dbg_print(NAND_DBG_DEBUG, "PageCount: %d\n",
+ info.pcmds[i].PageCount);
+ nand_dbg_print(NAND_DBG_DEBUG, "DataDestAddr: 0x%x\n",
+ (u32)info.pcmds[i].DataDestAddr);
+ nand_dbg_print(NAND_DBG_DEBUG, "DataSrcAddr: 0x%x\n",
+ (u32)info.pcmds[i].DataSrcAddr);
+ nand_dbg_print(NAND_DBG_DEBUG, "MemCopyByteCnt: %d\n",
+ info.pcmds[i].MemCopyByteCnt);
+ nand_dbg_print(NAND_DBG_DEBUG, "Flags: 0x%x\n",
+ info.pcmds[i].Flags);
+ nand_dbg_print(NAND_DBG_DEBUG, "Status: 0x%x\n",
+ info.pcmds[i].Status);
+ }
+}
+
+/* Print the CDMA descriptors */
+void print_cdma_descriptors(void)
+{
+ struct cdma_descriptor *pc;
+ int i;
+
+ pc = (struct cdma_descriptor *)info.cdma_desc_buf;
+
+ nand_dbg_print(NAND_DBG_DEBUG, "\nWill dump cdma descriptors:\n");
+
+ for (i = 0; i < info.cdma_num; i++) {
+ nand_dbg_print(NAND_DBG_DEBUG, "\ni: %d\n", i);
+ nand_dbg_print(NAND_DBG_DEBUG,
+ "NxtPointerHi: 0x%x, NxtPointerLo: 0x%x\n",
+ pc[i].NxtPointerHi, pc[i].NxtPointerLo);
+ nand_dbg_print(NAND_DBG_DEBUG,
+ "FlashPointerHi: 0x%x, FlashPointerLo: 0x%x\n",
+ pc[i].FlashPointerHi, pc[i].FlashPointerLo);
+ nand_dbg_print(NAND_DBG_DEBUG, "CommandType: 0x%x\n",
+ pc[i].CommandType);
+ nand_dbg_print(NAND_DBG_DEBUG,
+ "MemAddrHi: 0x%x, MemAddrLo: 0x%x\n",
+ pc[i].MemAddrHi, pc[i].MemAddrLo);
+ nand_dbg_print(NAND_DBG_DEBUG, "CommandFlags: 0x%x\n",
+ pc[i].CommandFlags);
+ nand_dbg_print(NAND_DBG_DEBUG, "Channel: %d, Status: 0x%x\n",
+ pc[i].Channel, pc[i].Status);
+ nand_dbg_print(NAND_DBG_DEBUG,
+ "MemCopyPointerHi: 0x%x, MemCopyPointerLo: 0x%x\n",
+ pc[i].MemCopyPointerHi, pc[i].MemCopyPointerLo);
+ nand_dbg_print(NAND_DBG_DEBUG,
+ "Reserved12: 0x%x, Reserved13: 0x%x, "
+ "Reserved14: 0x%x, pcmd: %d\n",
+ pc[i].Reserved12, pc[i].Reserved13,
+ pc[i].Reserved14, pc[i].pcmd);
+ }
+}
+
+/* Print the Memory copy descriptors */
+static void print_memcp_descriptors(void)
+{
+ struct memcpy_descriptor *pm;
+ int i;
+
+ pm = (struct memcpy_descriptor *)info.memcp_desc_buf;
+
+ nand_dbg_print(NAND_DBG_DEBUG, "\nWill dump mem_cpy descriptors:\n");
+
+ for (i = 0; i < info.cdma_num; i++) {
+ nand_dbg_print(NAND_DBG_DEBUG, "\ni: %d\n", i);
+ nand_dbg_print(NAND_DBG_DEBUG,
+ "NxtPointerHi: 0x%x, NxtPointerLo: 0x%x\n",
+ pm[i].NxtPointerHi, pm[i].NxtPointerLo);
+ nand_dbg_print(NAND_DBG_DEBUG,
+ "SrcAddrHi: 0x%x, SrcAddrLo: 0x%x\n",
+ pm[i].SrcAddrHi, pm[i].SrcAddrLo);
+ nand_dbg_print(NAND_DBG_DEBUG,
+ "DestAddrHi: 0x%x, DestAddrLo: 0x%x\n",
+ pm[i].DestAddrHi, pm[i].DestAddrLo);
+ nand_dbg_print(NAND_DBG_DEBUG, "XferSize: %d\n",
+ pm[i].XferSize);
+ nand_dbg_print(NAND_DBG_DEBUG, "MemCopyFlags: 0x%x\n",
+ pm[i].MemCopyFlags);
+ nand_dbg_print(NAND_DBG_DEBUG, "MemCopyStatus: %d\n",
+ pm[i].MemCopyStatus);
+ nand_dbg_print(NAND_DBG_DEBUG, "reserved9: 0x%x\n",
+ pm[i].reserved9);
+ nand_dbg_print(NAND_DBG_DEBUG, "reserved10: 0x%x\n",
+ pm[i].reserved10);
+ nand_dbg_print(NAND_DBG_DEBUG, "reserved11: 0x%x\n",
+ pm[i].reserved11);
+ nand_dbg_print(NAND_DBG_DEBUG, "reserved12: 0x%x\n",
+ pm[i].reserved12);
+ nand_dbg_print(NAND_DBG_DEBUG, "reserved13: 0x%x\n",
+ pm[i].reserved13);
+ nand_dbg_print(NAND_DBG_DEBUG, "reserved14: 0x%x\n",
+ pm[i].reserved14);
+ nand_dbg_print(NAND_DBG_DEBUG, "reserved15: 0x%x\n",
+ pm[i].reserved15);
+ }
+}
+#endif
+
+/* Reset cdma_descriptor chain to 0 */
+static void reset_cdma_desc(int i)
+{
+ struct cdma_descriptor *ptr;
+
+ BUG_ON(i >= MAX_DESCS);
+
+ ptr = (struct cdma_descriptor *)info.cdma_desc_buf;
+
+ ptr[i].NxtPointerHi = 0;
+ ptr[i].NxtPointerLo = 0;
+ ptr[i].FlashPointerHi = 0;
+ ptr[i].FlashPointerLo = 0;
+ ptr[i].CommandType = 0;
+ ptr[i].MemAddrHi = 0;
+ ptr[i].MemAddrLo = 0;
+ ptr[i].CommandFlags = 0;
+ ptr[i].Channel = 0;
+ ptr[i].Status = 0;
+ ptr[i].MemCopyPointerHi = 0;
+ ptr[i].MemCopyPointerLo = 0;
+}
+
+/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
+* Function: CDMA_UpdateEventStatus
+* Inputs: none
+* Outputs: none
+* Description: This function update the event status of all the channels
+* when an error condition is reported.
+*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/
+void CDMA_UpdateEventStatus(void)
+{
+ int i, j, active_chan;
+ struct cdma_descriptor *ptr;
+
+ nand_dbg_print(NAND_DBG_DEBUG, "%s, Line %d, Function: %s\n",
+ __FILE__, __LINE__, __func__);
+
+ ptr = (struct cdma_descriptor *)info.cdma_desc_buf;
+
+ for (j = 0; j < info.cdma_num; j++) {
+ /* Check for the descriptor with failure */
+ if ((ptr[j].Status & CMD_DMA_DESC_FAIL))
+ break;
+
+ }
+
+ /* All the previous cmd's status for this channel must be good */
+ for (i = 0; i < j; i++) {
+ if (ptr[i].pcmd != 0xff)
+ info.pcmds[ptr[i].pcmd].Status = CMD_PASS;
+ }
+
+ /* Abort the channel with type 0 reset command. It resets the */
+ /* selected channel after the descriptor completes the flash */
+ /* operation and status has been updated for the descriptor. */
+ /* Memory Copy and Sync associated with this descriptor will */
+ /* not be executed */
+ active_chan = ioread32(FlashReg + CHNL_ACTIVE);
+ if ((active_chan & (1 << info.flash_bank)) == (1 << info.flash_bank)) {
+ iowrite32(MODE_02 | (0 << 4), FlashMem); /* Type 0 reset */
+ iowrite32((0xF << 4) | info.flash_bank, FlashMem + 0x10);
+ } else { /* Should not reached here */
+ printk(KERN_ERR "Error! Used bank is not set in"
+ " reg CHNL_ACTIVE\n");
+ }
+}
+
+static void cdma_trans(u16 chan)
+{
+ u32 addr;
+
+ addr = info.cdma_desc;
+
+ iowrite32(MODE_10 | (chan << 24), FlashMem);
+ iowrite32((1 << 7) | chan, FlashMem + 0x10);
+
+ iowrite32(MODE_10 | (chan << 24) | ((0x0FFFF & (addr >> 16)) << 8),
+ FlashMem);
+ iowrite32((1 << 7) | (1 << 4) | 0, FlashMem + 0x10);
+
+ iowrite32(MODE_10 | (chan << 24) | ((0x0FFFF & addr) << 8), FlashMem);
+ iowrite32((1 << 7) | (1 << 5) | 0, FlashMem + 0x10);
+
+ iowrite32(MODE_10 | (chan << 24), FlashMem);
+ iowrite32((1 << 7) | (1 << 5) | (1 << 4) | 0, FlashMem + 0x10);
+}
+
+/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
+* Function: CDMA_Execute_CMDs (for use with CMD_DMA)
+* Inputs: tag_count: the number of pending cmds to do
+* Outputs: PASS/FAIL
+* Description: Build the SDMA chain(s) by making one CMD-DMA descriptor
+* for each pending command, start the CDMA engine, and return.
+*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/
+u16 CDMA_Execute_CMDs(void)
+{
+ int i, ret;
+ u64 flash_add;
+ u32 ptr;
+ dma_addr_t map_addr, next_ptr;
+ u16 status = PASS;
+ u16 tmp_c;
+ struct cdma_descriptor *pc;
+ struct memcpy_descriptor *pm;
+
+ nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n",
+ __FILE__, __LINE__, __func__);
+
+ /* No pending cmds to execute, just exit */
+ if (0 == info.pcmds_num) {
+ nand_dbg_print(NAND_DBG_TRACE,
+ "No pending cmds to execute. Just exit.\n");
+ return PASS;
+ }
+
+ for (i = 0; i < MAX_DESCS; i++)
+ reset_cdma_desc(i);
+
+ pc = (struct cdma_descriptor *)info.cdma_desc_buf;
+ pm = (struct memcpy_descriptor *)info.memcp_desc_buf;
+
+ info.cdma_desc = virt_to_bus(info.cdma_desc_buf);
+ info.memcp_desc = virt_to_bus(info.memcp_desc_buf);
+ next_ptr = info.cdma_desc;
+ info.cdma_num = 0;
+
+ for (i = 0; i < info.pcmds_num; i++) {
+ if (info.pcmds[i].Block >= DeviceInfo.wTotalBlocks) {
+ info.pcmds[i].Status = CMD_NOT_DONE;
+ continue;
+ }
+
+ next_ptr += sizeof(struct cdma_descriptor);
+ pc[info.cdma_num].NxtPointerHi = next_ptr >> 16;
+ pc[info.cdma_num].NxtPointerLo = next_ptr & 0xffff;
+
+ /* Use the Block offset within a bank */
+ tmp_c = info.pcmds[i].Block /
+ (DeviceInfo.wTotalBlocks / totalUsedBanks);
+ flash_add = (u64)(info.pcmds[i].Block - tmp_c *
+ (DeviceInfo.wTotalBlocks / totalUsedBanks)) *
+ DeviceInfo.wBlockDataSize +
+ (u64)(info.pcmds[i].Page) *
+ DeviceInfo.wPageDataSize;
+
+ ptr = MODE_10 | (info.flash_bank << 24) |
+ (u32)GLOB_u64_Div(flash_add,
+ DeviceInfo.wPageDataSize);
+ pc[info.cdma_num].FlashPointerHi = ptr >> 16;
+ pc[info.cdma_num].FlashPointerLo = ptr & 0xffff;
+
+ if ((info.pcmds[i].CMD == WRITE_MAIN_SPARE_CMD) ||
+ (info.pcmds[i].CMD == READ_MAIN_SPARE_CMD)) {
+ /* Descriptor to set Main+Spare Access Mode */
+ pc[info.cdma_num].CommandType = 0x43;
+ pc[info.cdma_num].CommandFlags =
+ (0 << 10) | (1 << 9) | (0 << 8) | 0x40;
+ pc[info.cdma_num].MemAddrHi = 0;
+ pc[info.cdma_num].MemAddrLo = 0;
+ pc[info.cdma_num].Channel = 0;
+ pc[info.cdma_num].Status = 0;
+ pc[info.cdma_num].pcmd = i;
+
+ info.cdma_num++;
+ BUG_ON(info.cdma_num >= MAX_DESCS);
+
+ reset_cdma_desc(info.cdma_num);
+ next_ptr += sizeof(struct cdma_descriptor);
+ pc[info.cdma_num].NxtPointerHi = next_ptr >> 16;
+ pc[info.cdma_num].NxtPointerLo = next_ptr & 0xffff;
+ pc[info.cdma_num].FlashPointerHi = ptr >> 16;
+ pc[info.cdma_num].FlashPointerLo = ptr & 0xffff;
+ }
+
+ switch (info.pcmds[i].CMD) {
+ case ERASE_CMD:
+ pc[info.cdma_num].CommandType = 1;
+ pc[info.cdma_num].CommandFlags =
+ (0 << 10) | (1 << 9) | (0 << 8) | 0x40;
+ pc[info.cdma_num].MemAddrHi = 0;
+ pc[info.cdma_num].MemAddrLo = 0;
+ break;
+
+ case WRITE_MAIN_CMD:
+ pc[info.cdma_num].CommandType =
+ 0x2100 | info.pcmds[i].PageCount;
+ pc[info.cdma_num].CommandFlags =
+ (0 << 10) | (1 << 9) | (0 << 8) | 0x40;
+ map_addr = virt_to_bus(info.pcmds[i].DataAddr);
+ pc[info.cdma_num].MemAddrHi = map_addr >> 16;
+ pc[info.cdma_num].MemAddrLo = map_addr & 0xffff;
+ break;
+
+ case READ_MAIN_CMD:
+ pc[info.cdma_num].CommandType =
+ 0x2000 | info.pcmds[i].PageCount;
+ pc[info.cdma_num].CommandFlags =
+ (0 << 10) | (1 << 9) | (0 << 8) | 0x40;
+ map_addr = virt_to_bus(info.pcmds[i].DataAddr);
+ pc[info.cdma_num].MemAddrHi = map_addr >> 16;
+ pc[info.cdma_num].MemAddrLo = map_addr & 0xffff;
+ break;
+
+ case WRITE_MAIN_SPARE_CMD:
+ pc[info.cdma_num].CommandType =
+ 0x2100 | info.pcmds[i].PageCount;
+ pc[info.cdma_num].CommandFlags =
+ (0 << 10) | (1 << 9) | (0 << 8) | 0x40;
+ map_addr = virt_to_bus(info.pcmds[i].DataAddr);
+ pc[info.cdma_num].MemAddrHi = map_addr >> 16;
+ pc[info.cdma_num].MemAddrLo = map_addr & 0xffff;
+ break;
+
+ case READ_MAIN_SPARE_CMD:
+ pc[info.cdma_num].CommandType =
+ 0x2000 | info.pcmds[i].PageCount;
+ pc[info.cdma_num].CommandFlags =
+ (0 << 10) | (1 << 9) | (0 << 8) | 0x40;
+ map_addr = virt_to_bus(info.pcmds[i].DataAddr);
+ pc[info.cdma_num].MemAddrHi = map_addr >> 16;
+ pc[info.cdma_num].MemAddrLo = map_addr & 0xffff;
+ break;
+
+ case MEMCOPY_CMD:
+ pc[info.cdma_num].CommandType = 0xFFFF; /* NOP cmd */
+ /* Set bit 11 to let the CDMA engine continue to */
+ /* execute only after it has finished processing */
+ /* the memcopy descriptor. */
+ /* Also set bit 10 and bit 9 to 1 */
+ pc[info.cdma_num].CommandFlags = 0x0E40;
+ map_addr = info.memcp_desc + info.cdma_num *
+ sizeof(struct memcpy_descriptor);
+ pc[info.cdma_num].MemCopyPointerHi = map_addr >> 16;
+ pc[info.cdma_num].MemCopyPointerLo = map_addr & 0xffff;
+
+ pm[info.cdma_num].NxtPointerHi = 0;
+ pm[info.cdma_num].NxtPointerLo = 0;
+
+ map_addr = virt_to_bus(info.pcmds[i].DataSrcAddr);
+ pm[info.cdma_num].SrcAddrHi = map_addr >> 16;
+ pm[info.cdma_num].SrcAddrLo = map_addr & 0xffff;
+ map_addr = virt_to_bus(info.pcmds[i].DataDestAddr);
+ pm[info.cdma_num].DestAddrHi = map_addr >> 16;
+ pm[info.cdma_num].DestAddrLo = map_addr & 0xffff;
+
+ pm[info.cdma_num].XferSize =
+ info.pcmds[i].MemCopyByteCnt;
+ pm[info.cdma_num].MemCopyFlags =
+ (0 << 15 | 0 << 14 | 27 << 8 | 0x40);
+ pm[info.cdma_num].MemCopyStatus = 0;
+ break;
+
+ case DUMMY_CMD:
+ default:
+ pc[info.cdma_num].CommandType = 0XFFFF;
+ pc[info.cdma_num].CommandFlags =
+ (0 << 10) | (1 << 9) | (0 << 8) | 0x40;
+ pc[info.cdma_num].MemAddrHi = 0;
+ pc[info.cdma_num].MemAddrLo = 0;
+ break;
+ }
+
+ pc[info.cdma_num].Channel = 0;
+ pc[info.cdma_num].Status = 0;
+ pc[info.cdma_num].pcmd = i;
+
+ info.cdma_num++;
+ BUG_ON(info.cdma_num >= MAX_DESCS);
+
+ if ((info.pcmds[i].CMD == WRITE_MAIN_SPARE_CMD) ||
+ (info.pcmds[i].CMD == READ_MAIN_SPARE_CMD)) {
+ /* Descriptor to set back Main Area Access Mode */
+ reset_cdma_desc(info.cdma_num);
+ next_ptr += sizeof(struct cdma_descriptor);
+ pc[info.cdma_num].NxtPointerHi = next_ptr >> 16;
+ pc[info.cdma_num].NxtPointerLo = next_ptr & 0xffff;
+
+ pc[info.cdma_num].FlashPointerHi = ptr >> 16;
+ pc[info.cdma_num].FlashPointerLo = ptr & 0xffff;
+
+ pc[info.cdma_num].CommandType = 0x42;
+ pc[info.cdma_num].CommandFlags =
+ (0 << 10) | (1 << 9) | (0 << 8) | 0x40;
+ pc[info.cdma_num].MemAddrHi = 0;
+ pc[info.cdma_num].MemAddrLo = 0;
+
+ pc[info.cdma_num].Channel = 0;
+ pc[info.cdma_num].Status = 0;
+ pc[info.cdma_num].pcmd = i;
+
+ info.cdma_num++;
+ BUG_ON(info.cdma_num >= MAX_DESCS);
+ }
+ }
+
+ /* Add a dummy descriptor at end of the CDMA chain */
+ reset_cdma_desc(info.cdma_num);
+ ptr = MODE_10 | (info.flash_bank << 24);
+ pc[info.cdma_num].FlashPointerHi = ptr >> 16;
+ pc[info.cdma_num].FlashPointerLo = ptr & 0xffff;
+ pc[info.cdma_num].CommandType = 0xFFFF; /* NOP command */
+ /* Set Command Flags for the last CDMA descriptor: */
+ /* set Continue bit (bit 9) to 0 and Interrupt bit (bit 8) to 1 */
+ pc[info.cdma_num].CommandFlags =
+ (0 << 10) | (0 << 9) | (1 << 8) | 0x40;
+ pc[info.cdma_num].pcmd = 0xff; /* Set it to an illegal value */
+ info.cdma_num++;
+ BUG_ON(info.cdma_num >= MAX_DESCS);
+
+ iowrite32(1, FlashReg + GLOBAL_INT_ENABLE); /* Enable Interrupt */
+
+ iowrite32(1, FlashReg + DMA_ENABLE);
+ /* Wait for DMA to be enabled before issuing the next command */
+ while (!(ioread32(FlashReg + DMA_ENABLE) & DMA_ENABLE__FLAG))
+ ;
+ cdma_trans(info.flash_bank);
+
+ ret = wait_for_completion_timeout(&info.complete, 50 * HZ);
+ if (!ret)
+ printk(KERN_ERR "Wait for completion timeout "
+ "in %s, Line %d\n", __FILE__, __LINE__);
+ status = info.ret;
+
+ info.pcmds_num = 0; /* Clear the pending cmds number to 0 */
+
+ return status;
+}
+
+int is_cdma_interrupt(void)
+{
+ u32 ints_b0, ints_b1, ints_b2, ints_b3, ints_cdma;
+ u32 int_en_mask;
+ u32 cdma_int_en_mask;
+
+ nand_dbg_print(NAND_DBG_DEBUG, "%s, Line %d, Function: %s\n",
+ __FILE__, __LINE__, __func__);
+
+ /* Set the global Enable masks for only those interrupts
+ * that are supported */
+ cdma_int_en_mask = (DMA_INTR__DESC_COMP_CHANNEL0 |
+ DMA_INTR__DESC_COMP_CHANNEL1 |
+ DMA_INTR__DESC_COMP_CHANNEL2 |
+ DMA_INTR__DESC_COMP_CHANNEL3 |
+ DMA_INTR__MEMCOPY_DESC_COMP);
+
+ int_en_mask = (INTR_STATUS0__ECC_ERR |
+ INTR_STATUS0__PROGRAM_FAIL |
+ INTR_STATUS0__ERASE_FAIL);
+
+ ints_b0 = ioread32(FlashReg + INTR_STATUS0) & int_en_mask;
+ ints_b1 = ioread32(FlashReg + INTR_STATUS1) & int_en_mask;
+ ints_b2 = ioread32(FlashReg + INTR_STATUS2) & int_en_mask;
+ ints_b3 = ioread32(FlashReg + INTR_STATUS3) & int_en_mask;
+ ints_cdma = ioread32(FlashReg + DMA_INTR) & cdma_int_en_mask;
+
+ nand_dbg_print(NAND_DBG_WARN, "ints_bank0 to ints_bank3: "
+ "0x%x, 0x%x, 0x%x, 0x%x, ints_cdma: 0x%x\n",
+ ints_b0, ints_b1, ints_b2, ints_b3, ints_cdma);
+
+ if (ints_b0 || ints_b1 || ints_b2 || ints_b3 || ints_cdma) {
+ return 1;
+ } else {
+ iowrite32(ints_b0, FlashReg + INTR_STATUS0);
+ iowrite32(ints_b1, FlashReg + INTR_STATUS1);
+ iowrite32(ints_b2, FlashReg + INTR_STATUS2);
+ iowrite32(ints_b3, FlashReg + INTR_STATUS3);
+ nand_dbg_print(NAND_DBG_DEBUG,
+ "Not a NAND controller interrupt! Ignore it.\n");
+ return 0;
+ }
+}
+
+static void update_event_status(void)
+{
+ int i;
+ struct cdma_descriptor *ptr;
+
+ nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n",
+ __FILE__, __LINE__, __func__);
+
+ ptr = (struct cdma_descriptor *)info.cdma_desc_buf;
+
+ for (i = 0; i < info.cdma_num; i++) {
+ if (ptr[i].pcmd != 0xff)
+ info.pcmds[ptr[i].pcmd].Status = CMD_PASS;
+ if ((ptr[i].CommandType == 0x41) ||
+ (ptr[i].CommandType == 0x42) ||
+ (ptr[i].CommandType == 0x43))
+ continue;
+
+ switch (info.pcmds[ptr[i].pcmd].CMD) {
+ case READ_MAIN_SPARE_CMD:
+ Conv_Main_Spare_Data_Phy2Log_Format(
+ info.pcmds[ptr[i].pcmd].DataAddr,
+ info.pcmds[ptr[i].pcmd].PageCount);
+ break;
+ case READ_SPARE_CMD:
+ Conv_Spare_Data_Phy2Log_Format(
+ info.pcmds[ptr[i].pcmd].DataAddr);
+ break;
+ }
+ }
+}
+
+static u16 do_ecc_for_desc(u32 ch, u8 *buf, u16 page)
+{
+ u16 event = EVENT_NONE;
+ u16 err_byte;
+ u16 err_page = 0;
+ u8 err_sector;
+ u8 err_device;
+ u16 ecc_correction_info;
+ u16 err_address;
+ u32 eccSectorSize;
+ u8 *err_pos;
+
+ nand_dbg_print(NAND_DBG_WARN, "%s, Line %d, Function: %s\n",
+ __FILE__, __LINE__, __func__);
+
+ eccSectorSize = ECC_SECTOR_SIZE * (DeviceInfo.wDevicesConnected);
+
+ do {
+ if (0 == ch)
+ err_page = ioread32(FlashReg + ERR_PAGE_ADDR0);
+ else if (1 == ch)
+ err_page = ioread32(FlashReg + ERR_PAGE_ADDR1);
+ else if (2 == ch)
+ err_page = ioread32(FlashReg + ERR_PAGE_ADDR2);
+ else if (3 == ch)
+ err_page = ioread32(FlashReg + ERR_PAGE_ADDR3);
+
+ err_address = ioread32(FlashReg + ECC_ERROR_ADDRESS);
+ err_byte = err_address & ECC_ERROR_ADDRESS__OFFSET;
+ err_sector = ((err_address &
+ ECC_ERROR_ADDRESS__SECTOR_NR) >> 12);
+
+ ecc_correction_info = ioread32(FlashReg + ERR_CORRECTION_INFO);
+ err_device = ((ecc_correction_info &
+ ERR_CORRECTION_INFO__DEVICE_NR) >> 8);
+
+ if (ecc_correction_info & ERR_CORRECTION_INFO__ERROR_TYPE) {
+ event = EVENT_UNCORRECTABLE_DATA_ERROR;
+ } else {
+ event = EVENT_CORRECTABLE_DATA_ERROR_FIXED;
+ if (err_byte < ECC_SECTOR_SIZE) {
+ err_pos = buf +
+ (err_page - page) *
+ DeviceInfo.wPageDataSize +
+ err_sector * eccSectorSize +
+ err_byte *
+ DeviceInfo.wDevicesConnected +
+ err_device;
+ *err_pos ^= ecc_correction_info &
+ ERR_CORRECTION_INFO__BYTEMASK;
+ }
+ }
+ } while (!(ecc_correction_info & ERR_CORRECTION_INFO__LAST_ERR_INFO));
+
+ return event;
+}
+
+static u16 process_ecc_int(u32 c, u16 *p_desc_num)
+{
+ struct cdma_descriptor *ptr;
+ u16 j;
+ int event = EVENT_PASS;
+
+ nand_dbg_print(NAND_DBG_WARN, "%s, Line %d, Function: %s\n",
+ __FILE__, __LINE__, __func__);
+
+ if (c != info.flash_bank)
+ printk(KERN_ERR "Error!info.flash_bank is %d, while c is %d\n",
+ info.flash_bank, c);
+
+ ptr = (struct cdma_descriptor *)info.cdma_desc_buf;
+
+ for (j = 0; j < info.cdma_num; j++)
+ if ((ptr[j].Status & CMD_DMA_DESC_COMP) != CMD_DMA_DESC_COMP)
+ break;
+
+ *p_desc_num = j; /* Pass the descripter number found here */
+
+ if (j >= info.cdma_num) {
+ printk(KERN_ERR "Can not find the correct descriptor number "
+ "when ecc interrupt triggered!"
+ "info.cdma_num: %d, j: %d\n", info.cdma_num, j);
+ return EVENT_UNCORRECTABLE_DATA_ERROR;
+ }
+
+ event = do_ecc_for_desc(c, info.pcmds[ptr[j].pcmd].DataAddr,
+ info.pcmds[ptr[j].pcmd].Page);
+
+ if (EVENT_UNCORRECTABLE_DATA_ERROR == event) {
+ printk(KERN_ERR "Uncorrectable ECC error!"
+ "info.cdma_num: %d, j: %d, "
+ "pending cmd CMD: 0x%x, "
+ "Block: 0x%x, Page: 0x%x, PageCount: 0x%x\n",
+ info.cdma_num, j,
+ info.pcmds[ptr[j].pcmd].CMD,
+ info.pcmds[ptr[j].pcmd].Block,
+ info.pcmds[ptr[j].pcmd].Page,
+ info.pcmds[ptr[j].pcmd].PageCount);
+
+ if (ptr[j].pcmd != 0xff)
+ info.pcmds[ptr[j].pcmd].Status = CMD_FAIL;
+ CDMA_UpdateEventStatus();
+ }
+
+ return event;
+}
+
+static void process_prog_erase_fail_int(u16 desc_num)
+{
+ struct cdma_descriptor *ptr;
+
+ nand_dbg_print(NAND_DBG_DEBUG, "%s, Line %d, Function: %s\n",
+ __FILE__, __LINE__, __func__);
+
+ ptr = (struct cdma_descriptor *)info.cdma_desc_buf;
+
+ if (ptr[desc_num].pcmd != 0xFF)
+ info.pcmds[ptr[desc_num].pcmd].Status = CMD_FAIL;
+
+ CDMA_UpdateEventStatus();
+}
+
+/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
+* Function: CDMA_Event_Status (for use with CMD_DMA)
+* Inputs: none
+* Outputs: Event_Status code
+* Description: This function is called after an interrupt has happened
+* It reads the HW status register and ...tbd
+* It returns the appropriate event status
+*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/
+u16 CDMA_Event_Status(void)
+{
+ u32 ints_addr[4] = {INTR_STATUS0, INTR_STATUS1,
+ INTR_STATUS2, INTR_STATUS3};
+ u32 dma_intr_bit[4] = {DMA_INTR__DESC_COMP_CHANNEL0,
+ DMA_INTR__DESC_COMP_CHANNEL1,
+ DMA_INTR__DESC_COMP_CHANNEL2,
+ DMA_INTR__DESC_COMP_CHANNEL3};
+ u32 cdma_int_status, int_status;
+ u32 ecc_enable = 0;
+ u16 event = EVENT_PASS;
+ u16 cur_desc = 0;
+
+ nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n",
+ __FILE__, __LINE__, __func__);
+
+ ecc_enable = ioread32(FlashReg + ECC_ENABLE);
+
+ while (1) {
+ int_status = ioread32(FlashReg + ints_addr[info.flash_bank]);
+ if (ecc_enable && (int_status & INTR_STATUS0__ECC_ERR)) {
+ event = process_ecc_int(info.flash_bank, &cur_desc);
+ iowrite32(INTR_STATUS0__ECC_ERR,
+ FlashReg + ints_addr[info.flash_bank]);
+ if (EVENT_UNCORRECTABLE_DATA_ERROR == event) {
+ nand_dbg_print(NAND_DBG_WARN,
+ "ints_bank0 to ints_bank3: "
+ "0x%x, 0x%x, 0x%x, 0x%x, "
+ "ints_cdma: 0x%x\n",
+ ioread32(FlashReg + INTR_STATUS0),
+ ioread32(FlashReg + INTR_STATUS1),
+ ioread32(FlashReg + INTR_STATUS2),
+ ioread32(FlashReg + INTR_STATUS3),
+ ioread32(FlashReg + DMA_INTR));
+ break;
+ }
+ } else if (int_status & INTR_STATUS0__PROGRAM_FAIL) {
+ printk(KERN_ERR "NAND program fail interrupt!\n");
+ process_prog_erase_fail_int(cur_desc);
+ event = EVENT_PROGRAM_FAILURE;
+ break;
+ } else if (int_status & INTR_STATUS0__ERASE_FAIL) {
+ printk(KERN_ERR "NAND erase fail interrupt!\n");
+ process_prog_erase_fail_int(cur_desc);
+ event = EVENT_ERASE_FAILURE;
+ break;
+ } else {
+ cdma_int_status = ioread32(FlashReg + DMA_INTR);
+ if (cdma_int_status & dma_intr_bit[info.flash_bank]) {
+ iowrite32(dma_intr_bit[info.flash_bank],
+ FlashReg + DMA_INTR);
+ update_event_status();
+ event = EVENT_PASS;
+ break;
+ }
+ }
+ }
+
+ int_status = ioread32(FlashReg + ints_addr[info.flash_bank]);
+ iowrite32(int_status, FlashReg + ints_addr[info.flash_bank]);
+ cdma_int_status = ioread32(FlashReg + DMA_INTR);
+ iowrite32(cdma_int_status, FlashReg + DMA_INTR);
+
+ iowrite32(0, FlashReg + DMA_ENABLE);
+ while ((ioread32(FlashReg + DMA_ENABLE) & DMA_ENABLE__FLAG))
+ ;
+
+ return event;
+}
+
+
+
diff --git a/drivers/staging/spectra/lld_cdma.h b/drivers/staging/spectra/lld_cdma.h
new file mode 100644
index 00000000000..854ea066f0c
--- /dev/null
+++ b/drivers/staging/spectra/lld_cdma.h
@@ -0,0 +1,123 @@
+/*
+ * NAND Flash Controller Device Driver
+ * Copyright (c) 2009, Intel Corporation and its suppliers.
+ *
+ * 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.
+ *
+ */
+
+/* header for LLD_CDMA.c module */
+
+#ifndef _LLD_CDMA_
+#define _LLD_CDMA_
+
+#include "flash.h"
+
+#define DEBUG_SYNC 1
+
+/*/////////// CDMA specific MACRO definition */
+#define MAX_DESCS (255)
+#define MAX_CHANS (4)
+#define MAX_SYNC_POINTS (16)
+#define MAX_DESC_PER_CHAN (MAX_DESCS * 3 + MAX_SYNC_POINTS + 2)
+
+#define CHANNEL_SYNC_MASK (0x000F)
+#define CHANNEL_DMA_MASK (0x00F0)
+#define CHANNEL_ID_MASK (0x0300)
+#define CHANNEL_CONT_MASK (0x4000)
+#define CHANNEL_INTR_MASK (0x8000)
+
+#define CHANNEL_SYNC_OFFSET (0)
+#define CHANNEL_DMA_OFFSET (4)
+#define CHANNEL_ID_OFFSET (8)
+#define CHANNEL_CONT_OFFSET (14)
+#define CHANNEL_INTR_OFFSET (15)
+
+u16 CDMA_Data_CMD(u8 cmd, u8 *data, u32 block, u16 page, u16 num, u16 flags);
+u16 CDMA_MemCopy_CMD(u8 *dest, u8 *src, u32 byte_cnt, u16 flags);
+u16 CDMA_Execute_CMDs(void);
+void print_pending_cmds(void);
+void print_cdma_descriptors(void);
+
+extern u8 g_SBDCmdIndex;
+extern struct mrst_nand_info info;
+
+
+/*/////////// prototypes: APIs for LLD_CDMA */
+int is_cdma_interrupt(void);
+u16 CDMA_Event_Status(void);
+
+/* CMD-DMA Descriptor Struct. These are defined by the CMD_DMA HW */
+struct cdma_descriptor {
+ u32 NxtPointerHi;
+ u32 NxtPointerLo;
+ u32 FlashPointerHi;
+ u32 FlashPointerLo;
+ u32 CommandType;
+ u32 MemAddrHi;
+ u32 MemAddrLo;
+ u32 CommandFlags;
+ u32 Channel;
+ u32 Status;
+ u32 MemCopyPointerHi;
+ u32 MemCopyPointerLo;
+ u32 Reserved12;
+ u32 Reserved13;
+ u32 Reserved14;
+ u32 pcmd; /* pending cmd num related to this descriptor */
+};
+
+/* This struct holds one MemCopy descriptor as defined by the HW */
+struct memcpy_descriptor {
+ u32 NxtPointerHi;
+ u32 NxtPointerLo;
+ u32 SrcAddrHi;
+ u32 SrcAddrLo;
+ u32 DestAddrHi;
+ u32 DestAddrLo;
+ u32 XferSize;
+ u32 MemCopyFlags;
+ u32 MemCopyStatus;
+ u32 reserved9;
+ u32 reserved10;
+ u32 reserved11;
+ u32 reserved12;
+ u32 reserved13;
+ u32 reserved14;
+ u32 reserved15;
+};
+
+/* Pending CMD table entries (includes MemCopy parameters */
+struct pending_cmd {
+ u8 CMD;
+ u8 *DataAddr;
+ u32 Block;
+ u16 Page;
+ u16 PageCount;
+ u8 *DataDestAddr;
+ u8 *DataSrcAddr;
+ u32 MemCopyByteCnt;
+ u16 Flags;
+ u16 Status;
+};
+
+#if DEBUG_SYNC
+extern u32 debug_sync_cnt;
+#endif
+
+/* Definitions for CMD DMA descriptor chain fields */
+#define CMD_DMA_DESC_COMP 0x8000
+#define CMD_DMA_DESC_FAIL 0x4000
+
+#endif /*_LLD_CDMA_*/
diff --git a/drivers/staging/spectra/lld_emu.c b/drivers/staging/spectra/lld_emu.c
new file mode 100644
index 00000000000..60eb0f6fdba
--- /dev/null
+++ b/drivers/staging/spectra/lld_emu.c
@@ -0,0 +1,780 @@
+/*
+ * NAND Flash Controller Device Driver
+ * Copyright (c) 2009, Intel Corporation and its suppliers.
+ *
+ * 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/fs.h>
+#include <linux/slab.h>
+#include "flash.h"
+#include "ffsdefs.h"
+#include "lld_emu.h"
+#include "lld.h"
+#if CMD_DMA
+#include "lld_cdma.h"
+#endif
+
+#define GLOB_LLD_PAGES 64
+#define GLOB_LLD_PAGE_SIZE (512+16)
+#define GLOB_LLD_PAGE_DATA_SIZE 512
+#define GLOB_LLD_BLOCKS 2048
+
+#if (CMD_DMA && FLASH_EMU)
+#include "lld_cdma.h"
+u32 totalUsedBanks;
+u32 valid_banks[MAX_CHANS];
+#endif
+
+#if FLASH_EMU /* This is for entire module */
+
+static u8 *flash_memory[GLOB_LLD_BLOCKS * GLOB_LLD_PAGES];
+
+/* Read nand emu file and then fill it's content to flash_memory */
+int emu_load_file_to_mem(void)
+{
+ mm_segment_t fs;
+ struct file *nef_filp = NULL;
+ struct inode *inode = NULL;
+ loff_t nef_size = 0;
+ loff_t tmp_file_offset, file_offset;
+ ssize_t nread;
+ int i, rc = -EINVAL;
+
+ nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n",
+ __FILE__, __LINE__, __func__);
+
+ fs = get_fs();
+ set_fs(get_ds());
+
+ nef_filp = filp_open("/root/nand_emu_file", O_RDWR | O_LARGEFILE, 0);
+ if (IS_ERR(nef_filp)) {
+ printk(KERN_ERR "filp_open error: "
+ "Unable to open nand emu file!\n");
+ return PTR_ERR(nef_filp);
+ }
+
+ if (nef_filp->f_path.dentry) {
+ inode = nef_filp->f_path.dentry->d_inode;
+ } else {
+ printk(KERN_ERR "Can not get valid inode!\n");
+ goto out;
+ }
+
+ nef_size = i_size_read(inode->i_mapping->host);
+ if (nef_size <= 0) {
+ printk(KERN_ERR "Invalid nand emu file size: "
+ "0x%llx\n", nef_size);
+ goto out;
+ } else {
+ nand_dbg_print(NAND_DBG_DEBUG, "nand emu file size: %lld\n",
+ nef_size);
+ }
+
+ file_offset = 0;
+ for (i = 0; i < GLOB_LLD_BLOCKS * GLOB_LLD_PAGES; i++) {
+ tmp_file_offset = file_offset;
+ nread = vfs_read(nef_filp,
+ (char __user *)flash_memory[i],
+ GLOB_LLD_PAGE_SIZE, &tmp_file_offset);
+ if (nread < GLOB_LLD_PAGE_SIZE) {
+ printk(KERN_ERR "%s, Line %d - "
+ "nand emu file partial read: "
+ "%d bytes\n", __FILE__, __LINE__, (int)nread);
+ goto out;
+ }
+ file_offset += GLOB_LLD_PAGE_SIZE;
+ }
+ rc = 0;
+
+out:
+ filp_close(nef_filp, current->files);
+ set_fs(fs);
+ return rc;
+}
+
+/* Write contents of flash_memory to nand emu file */
+int emu_write_mem_to_file(void)
+{
+ mm_segment_t fs;
+ struct file *nef_filp = NULL;
+ struct inode *inode = NULL;
+ loff_t nef_size = 0;
+ loff_t tmp_file_offset, file_offset;
+ ssize_t nwritten;
+ int i, rc = -EINVAL;
+
+ nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n",
+ __FILE__, __LINE__, __func__);
+
+ fs = get_fs();
+ set_fs(get_ds());
+
+ nef_filp = filp_open("/root/nand_emu_file", O_RDWR | O_LARGEFILE, 0);
+ if (IS_ERR(nef_filp)) {
+ printk(KERN_ERR "filp_open error: "
+ "Unable to open nand emu file!\n");
+ return PTR_ERR(nef_filp);
+ }
+
+ if (nef_filp->f_path.dentry) {
+ inode = nef_filp->f_path.dentry->d_inode;
+ } else {
+ printk(KERN_ERR "Invalid " "nef_filp->f_path.dentry value!\n");
+ goto out;
+ }
+
+ nef_size = i_size_read(inode->i_mapping->host);
+ if (nef_size <= 0) {
+ printk(KERN_ERR "Invalid "
+ "nand emu file size: 0x%llx\n", nef_size);
+ goto out;
+ } else {
+ nand_dbg_print(NAND_DBG_DEBUG, "nand emu file size: "
+ "%lld\n", nef_size);
+ }
+
+ file_offset = 0;
+ for (i = 0; i < GLOB_LLD_BLOCKS * GLOB_LLD_PAGES; i++) {
+ tmp_file_offset = file_offset;
+ nwritten = vfs_write(nef_filp,
+ (char __user *)flash_memory[i],
+ GLOB_LLD_PAGE_SIZE, &tmp_file_offset);
+ if (nwritten < GLOB_LLD_PAGE_SIZE) {
+ printk(KERN_ERR "%s, Line %d - "
+ "nand emu file partial write: "
+ "%d bytes\n", __FILE__, __LINE__, (int)nwritten);
+ goto out;
+ }
+ file_offset += GLOB_LLD_PAGE_SIZE;
+ }
+ rc = 0;
+
+out:
+ filp_close(nef_filp, current->files);
+ set_fs(fs);
+ return rc;
+}
+
+/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
+* Function: emu_Flash_Init
+* Inputs: none
+* Outputs: PASS=0 (notice 0=ok here)
+* Description: Creates & initializes the flash RAM array.
+*
+*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/
+u16 emu_Flash_Init(void)
+{
+ int i;
+
+ nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n",
+ __FILE__, __LINE__, __func__);
+
+ flash_memory[0] = (u8 *)vmalloc(GLOB_LLD_PAGE_SIZE *
+ GLOB_LLD_BLOCKS *
+ GLOB_LLD_PAGES *
+ sizeof(u8));
+ if (!flash_memory[0]) {
+ printk(KERN_ERR "Fail to allocate memory "
+ "for nand emulator!\n");
+ return ERR;
+ }
+
+ memset((char *)(flash_memory[0]), 0xFF,
+ GLOB_LLD_PAGE_SIZE * GLOB_LLD_BLOCKS * GLOB_LLD_PAGES *
+ sizeof(u8));
+
+ for (i = 1; i < GLOB_LLD_BLOCKS * GLOB_LLD_PAGES; i++)
+ flash_memory[i] = flash_memory[i - 1] + GLOB_LLD_PAGE_SIZE;
+
+ emu_load_file_to_mem(); /* Load nand emu file to mem */
+
+ return PASS;
+}
+
+/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
+* Function: emu_Flash_Release
+* Inputs: none
+* Outputs: PASS=0 (notice 0=ok here)
+* Description: Releases the flash.
+*
+*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/
+int emu_Flash_Release(void)
+{
+ nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n",
+ __FILE__, __LINE__, __func__);
+
+ emu_write_mem_to_file(); /* Write back mem to nand emu file */
+
+ vfree(flash_memory[0]);
+ return PASS;
+}
+
+/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
+* Function: emu_Read_Device_ID
+* Inputs: none
+* Outputs: PASS=1 FAIL=0
+* Description: Reads the info from the controller registers.
+* Sets up DeviceInfo structure with device parameters
+*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/
+
+u16 emu_Read_Device_ID(void)
+{
+ nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n",
+ __FILE__, __LINE__, __func__);
+
+ DeviceInfo.wDeviceMaker = 0;
+ DeviceInfo.wDeviceType = 8;
+ DeviceInfo.wSpectraStartBlock = 36;
+ DeviceInfo.wSpectraEndBlock = GLOB_LLD_BLOCKS - 1;
+ DeviceInfo.wTotalBlocks = GLOB_LLD_BLOCKS;
+ DeviceInfo.wPagesPerBlock = GLOB_LLD_PAGES;
+ DeviceInfo.wPageSize = GLOB_LLD_PAGE_SIZE;
+ DeviceInfo.wPageDataSize = GLOB_LLD_PAGE_DATA_SIZE;
+ DeviceInfo.wPageSpareSize = GLOB_LLD_PAGE_SIZE -
+ GLOB_LLD_PAGE_DATA_SIZE;
+ DeviceInfo.wBlockSize = DeviceInfo.wPageSize * GLOB_LLD_PAGES;
+ DeviceInfo.wBlockDataSize = DeviceInfo.wPageDataSize * GLOB_LLD_PAGES;
+ DeviceInfo.wDataBlockNum = (u32) (DeviceInfo.wSpectraEndBlock -
+ DeviceInfo.wSpectraStartBlock
+ + 1);
+ DeviceInfo.MLCDevice = 1; /* Emulate MLC device */
+ DeviceInfo.nBitsInPageNumber =
+ (u8)GLOB_Calc_Used_Bits(DeviceInfo.wPagesPerBlock);
+ DeviceInfo.nBitsInPageDataSize =
+ (u8)GLOB_Calc_Used_Bits(DeviceInfo.wPageDataSize);
+ DeviceInfo.nBitsInBlockDataSize =
+ (u8)GLOB_Calc_Used_Bits(DeviceInfo.wBlockDataSize);
+
+#if CMD_DMA
+ totalUsedBanks = 4;
+ valid_banks[0] = 1;
+ valid_banks[1] = 1;
+ valid_banks[2] = 1;
+ valid_banks[3] = 1;
+#endif
+
+ return PASS;
+}
+
+/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
+* Function: emu_Flash_Reset
+* Inputs: none
+* Outputs: PASS=0 (notice 0=ok here)
+* Description: Reset the flash
+*
+*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/
+u16 emu_Flash_Reset(void)
+{
+ nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n",
+ __FILE__, __LINE__, __func__);
+
+ return PASS;
+}
+
+/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
+* Function: emu_Erase_Block
+* Inputs: Address
+* Outputs: PASS=0 (notice 0=ok here)
+* Description: Erase a block
+*
+*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/
+u16 emu_Erase_Block(u32 block_add)
+{
+ int i;
+
+ nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n",
+ __FILE__, __LINE__, __func__);
+
+ if (block_add >= DeviceInfo.wTotalBlocks) {
+ printk(KERN_ERR "emu_Erase_Block error! "
+ "Too big block address: %d\n", block_add);
+ return FAIL;
+ }
+
+ nand_dbg_print(NAND_DBG_DEBUG, "Erasing block %d\n",
+ (int)block_add);
+
+ for (i = block_add * GLOB_LLD_PAGES;
+ i < ((block_add + 1) * GLOB_LLD_PAGES); i++) {
+ if (flash_memory[i]) {
+ memset((u8 *)(flash_memory[i]), 0xFF,
+ DeviceInfo.wPageSize * sizeof(u8));
+ }
+ }
+
+ return PASS;
+}
+
+/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
+* Function: emu_Write_Page_Main
+* Inputs: Write buffer address pointer
+* Block number
+* Page number
+* Number of pages to process
+* Outputs: PASS=0 (notice 0=ok here)
+* Description: Write the data in the buffer to main area of flash
+*
+*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/
+u16 emu_Write_Page_Main(u8 *write_data, u32 Block,
+ u16 Page, u16 PageCount)
+{
+ int i;
+
+ nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n",
+ __FILE__, __LINE__, __func__);
+
+ if (Block >= DeviceInfo.wTotalBlocks)
+ return FAIL;
+
+ if (Page + PageCount > DeviceInfo.wPagesPerBlock)
+ return FAIL;
+
+ nand_dbg_print(NAND_DBG_DEBUG, "emu_Write_Page_Main: "
+ "lba %u Page %u PageCount %u\n",
+ (unsigned int)Block,
+ (unsigned int)Page, (unsigned int)PageCount);
+
+ for (i = 0; i < PageCount; i++) {
+ if (NULL == flash_memory[Block * GLOB_LLD_PAGES + Page]) {
+ printk(KERN_ERR "Run out of memory\n");
+ return FAIL;
+ }
+ memcpy((u8 *) (flash_memory[Block * GLOB_LLD_PAGES + Page]),
+ write_data, DeviceInfo.wPageDataSize);
+ write_data += DeviceInfo.wPageDataSize;
+ Page++;
+ }
+
+ return PASS;
+}
+
+/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
+* Function: emu_Read_Page_Main
+* Inputs: Read buffer address pointer
+* Block number
+* Page number
+* Number of pages to process
+* Outputs: PASS=0 (notice 0=ok here)
+* Description: Read the data from the flash main area to the buffer
+*
+*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/
+u16 emu_Read_Page_Main(u8 *read_data, u32 Block,
+ u16 Page, u16 PageCount)
+{
+ int i;
+
+ nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n",
+ __FILE__, __LINE__, __func__);
+
+ if (Block >= DeviceInfo.wTotalBlocks)
+ return FAIL;
+
+ if (Page + PageCount > DeviceInfo.wPagesPerBlock)
+ return FAIL;
+
+ nand_dbg_print(NAND_DBG_DEBUG, "emu_Read_Page_Main: "
+ "lba %u Page %u PageCount %u\n",
+ (unsigned int)Block,
+ (unsigned int)Page, (unsigned int)PageCount);
+
+ for (i = 0; i < PageCount; i++) {
+ if (NULL == flash_memory[Block * GLOB_LLD_PAGES + Page]) {
+ memset(read_data, 0xFF, DeviceInfo.wPageDataSize);
+ } else {
+ memcpy(read_data,
+ (u8 *) (flash_memory[Block * GLOB_LLD_PAGES
+ + Page]),
+ DeviceInfo.wPageDataSize);
+ }
+ read_data += DeviceInfo.wPageDataSize;
+ Page++;
+ }
+
+ return PASS;
+}
+
+#ifndef ELDORA
+/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
+* Function: emu_Read_Page_Main_Spare
+* Inputs: Write Buffer
+* Address
+* Buffer size
+* Outputs: PASS=0 (notice 0=ok here)
+* Description: Read from flash main+spare area
+*
+*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/
+u16 emu_Read_Page_Main_Spare(u8 *read_data, u32 Block,
+ u16 Page, u16 PageCount)
+{
+ int i;
+
+ nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n",
+ __FILE__, __LINE__, __func__);
+
+ if (Block >= DeviceInfo.wTotalBlocks) {
+ printk(KERN_ERR "Read Page Main+Spare "
+ "Error: Block Address too big\n");
+ return FAIL;
+ }
+
+ if (Page + PageCount > DeviceInfo.wPagesPerBlock) {
+ printk(KERN_ERR "Read Page Main+Spare "
+ "Error: Page number too big\n");
+ return FAIL;
+ }
+
+ nand_dbg_print(NAND_DBG_DEBUG, "Read Page Main + Spare - "
+ "No. of pages %u block %u start page %u\n",
+ (unsigned int)PageCount,
+ (unsigned int)Block, (unsigned int)Page);
+
+ for (i = 0; i < PageCount; i++) {
+ if (NULL == flash_memory[Block * GLOB_LLD_PAGES + Page]) {
+ memset(read_data, 0xFF, DeviceInfo.wPageSize);
+ } else {
+ memcpy(read_data, (u8 *) (flash_memory[Block *
+ GLOB_LLD_PAGES
+ + Page]),
+ DeviceInfo.wPageSize);
+ }
+
+ read_data += DeviceInfo.wPageSize;
+ Page++;
+ }
+
+ return PASS;
+}
+
+/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
+* Function: emu_Write_Page_Main_Spare
+* Inputs: Write buffer
+* address
+* buffer length
+* Outputs: PASS=0 (notice 0=ok here)
+* Description: Write the buffer to main+spare area of flash
+*
+*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/
+u16 emu_Write_Page_Main_Spare(u8 *write_data, u32 Block,
+ u16 Page, u16 page_count)
+{
+ u16 i;
+
+ nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n",
+ __FILE__, __LINE__, __func__);
+
+ if (Block >= DeviceInfo.wTotalBlocks) {
+ printk(KERN_ERR "Write Page Main + Spare "
+ "Error: Block Address too big\n");
+ return FAIL;
+ }
+
+ if (Page + page_count > DeviceInfo.wPagesPerBlock) {
+ printk(KERN_ERR "Write Page Main + Spare "
+ "Error: Page number too big\n");
+ return FAIL;
+ }
+
+ nand_dbg_print(NAND_DBG_DEBUG, "Write Page Main+Spare - "
+ "No. of pages %u block %u start page %u\n",
+ (unsigned int)page_count,
+ (unsigned int)Block, (unsigned int)Page);
+
+ for (i = 0; i < page_count; i++) {
+ if (NULL == flash_memory[Block * GLOB_LLD_PAGES + Page]) {
+ printk(KERN_ERR "Run out of memory!\n");
+ return FAIL;
+ }
+ memcpy((u8 *) (flash_memory[Block * GLOB_LLD_PAGES + Page]),
+ write_data, DeviceInfo.wPageSize);
+ write_data += DeviceInfo.wPageSize;
+ Page++;
+ }
+
+ return PASS;
+}
+
+/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
+* Function: emu_Write_Page_Spare
+* Inputs: Write buffer
+* Address
+* buffer size
+* Outputs: PASS=0 (notice 0=ok here)
+* Description: Write the buffer in the spare area
+*
+*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/
+u16 emu_Write_Page_Spare(u8 *write_data, u32 Block,
+ u16 Page, u16 PageCount)
+{
+ nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n",
+ __FILE__, __LINE__, __func__);
+
+ if (Block >= DeviceInfo.wTotalBlocks) {
+ printk(KERN_ERR "Read Page Spare Error: "
+ "Block Address too big\n");
+ return FAIL;
+ }
+
+ if (Page + PageCount > DeviceInfo.wPagesPerBlock) {
+ printk(KERN_ERR "Read Page Spare Error: "
+ "Page number too big\n");
+ return FAIL;
+ }
+
+ nand_dbg_print(NAND_DBG_DEBUG, "Write Page Spare- "
+ "block %u page %u\n",
+ (unsigned int)Block, (unsigned int)Page);
+
+ if (NULL == flash_memory[Block * GLOB_LLD_PAGES + Page]) {
+ printk(KERN_ERR "Run out of memory!\n");
+ return FAIL;
+ }
+
+ memcpy((u8 *) (flash_memory[Block * GLOB_LLD_PAGES + Page] +
+ DeviceInfo.wPageDataSize), write_data,
+ (DeviceInfo.wPageSize - DeviceInfo.wPageDataSize));
+
+ return PASS;
+}
+
+/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
+* Function: emu_Read_Page_Spare
+* Inputs: Write Buffer
+* Address
+* Buffer size
+* Outputs: PASS=0 (notice 0=ok here)
+* Description: Read data from the spare area
+*
+*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/
+u16 emu_Read_Page_Spare(u8 *write_data, u32 Block,
+ u16 Page, u16 PageCount)
+{
+ nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n",
+ __FILE__, __LINE__, __func__);
+
+ if (Block >= DeviceInfo.wTotalBlocks) {
+ printk(KERN_ERR "Read Page Spare "
+ "Error: Block Address too big\n");
+ return FAIL;
+ }
+
+ if (Page + PageCount > DeviceInfo.wPagesPerBlock) {
+ printk(KERN_ERR "Read Page Spare "
+ "Error: Page number too big\n");
+ return FAIL;
+ }
+
+ nand_dbg_print(NAND_DBG_DEBUG, "Read Page Spare- "
+ "block %u page %u\n",
+ (unsigned int)Block, (unsigned int)Page);
+
+ if (NULL == flash_memory[Block * GLOB_LLD_PAGES + Page]) {
+ memset(write_data, 0xFF,
+ (DeviceInfo.wPageSize - DeviceInfo.wPageDataSize));
+ } else {
+ memcpy(write_data,
+ (u8 *) (flash_memory[Block * GLOB_LLD_PAGES + Page]
+ + DeviceInfo.wPageDataSize),
+ (DeviceInfo.wPageSize - DeviceInfo.wPageDataSize));
+ }
+
+ return PASS;
+}
+
+/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
+* Function: emu_Enable_Disable_Interrupts
+* Inputs: enable or disable
+* Outputs: none
+* Description: NOP
+*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/
+void emu_Enable_Disable_Interrupts(u16 INT_ENABLE)
+{
+ nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n",
+ __FILE__, __LINE__, __func__);
+}
+
+u16 emu_Get_Bad_Block(u32 block)
+{
+ return 0;
+}
+
+#if CMD_DMA
+/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
+* Support for CDMA functions
+************************************
+* emu_CDMA_Flash_Init
+* CDMA_process_data command (use LLD_CDMA)
+* CDMA_MemCopy_CMD (use LLD_CDMA)
+* emu_CDMA_execute all commands
+* emu_CDMA_Event_Status
+*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/
+u16 emu_CDMA_Flash_Init(void)
+{
+ u16 i;
+
+ nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n",
+ __FILE__, __LINE__, __func__);
+
+ for (i = 0; i < MAX_DESCS + MAX_CHANS; i++) {
+ PendingCMD[i].CMD = 0;
+ PendingCMD[i].Tag = 0;
+ PendingCMD[i].DataAddr = 0;
+ PendingCMD[i].Block = 0;
+ PendingCMD[i].Page = 0;
+ PendingCMD[i].PageCount = 0;
+ PendingCMD[i].DataDestAddr = 0;
+ PendingCMD[i].DataSrcAddr = 0;
+ PendingCMD[i].MemCopyByteCnt = 0;
+ PendingCMD[i].ChanSync[0] = 0;
+ PendingCMD[i].ChanSync[1] = 0;
+ PendingCMD[i].ChanSync[2] = 0;
+ PendingCMD[i].ChanSync[3] = 0;
+ PendingCMD[i].ChanSync[4] = 0;
+ PendingCMD[i].Status = 3;
+ }
+
+ return PASS;
+}
+
+static void emu_isr(int irq, void *dev_id)
+{
+ /* TODO: ... */
+}
+
+/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
+* Function: CDMA_Execute_CMDs
+* Inputs: tag_count: the number of pending cmds to do
+* Outputs: PASS/FAIL
+* Description: execute each command in the pending CMD array
+*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/
+u16 emu_CDMA_Execute_CMDs(u16 tag_count)
+{
+ u16 i, j;
+ u8 CMD; /* cmd parameter */
+ u8 *data;
+ u32 block;
+ u16 page;
+ u16 count;
+ u16 status = PASS;
+
+ nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n",
+ __FILE__, __LINE__, __func__);
+
+ nand_dbg_print(NAND_DBG_TRACE, "At start of Execute CMDs: "
+ "Tag Count %u\n", tag_count);
+
+ for (i = 0; i < totalUsedBanks; i++) {
+ PendingCMD[i].CMD = DUMMY_CMD;
+ PendingCMD[i].Tag = 0xFF;
+ PendingCMD[i].Block =
+ (DeviceInfo.wTotalBlocks / totalUsedBanks) * i;
+
+ for (j = 0; j <= MAX_CHANS; j++)
+ PendingCMD[i].ChanSync[j] = 0;
+ }
+
+ CDMA_Execute_CMDs(tag_count);
+
+ print_pending_cmds(tag_count);
+
+#if DEBUG_SYNC
+ }
+ debug_sync_cnt++;
+#endif
+
+ for (i = MAX_CHANS;
+ i < tag_count + MAX_CHANS; i++) {
+ CMD = PendingCMD[i].CMD;
+ data = PendingCMD[i].DataAddr;
+ block = PendingCMD[i].Block;
+ page = PendingCMD[i].Page;
+ count = PendingCMD[i].PageCount;
+
+ switch (CMD) {
+ case ERASE_CMD:
+ emu_Erase_Block(block);
+ PendingCMD[i].Status = PASS;
+ break;
+ case WRITE_MAIN_CMD:
+ emu_Write_Page_Main(data, block, page, count);
+ PendingCMD[i].Status = PASS;
+ break;
+ case WRITE_MAIN_SPARE_CMD:
+ emu_Write_Page_Main_Spare(data, block, page, count);
+ PendingCMD[i].Status = PASS;
+ break;
+ case READ_MAIN_CMD:
+ emu_Read_Page_Main(data, block, page, count);
+ PendingCMD[i].Status = PASS;
+ break;
+ case MEMCOPY_CMD:
+ memcpy(PendingCMD[i].DataDestAddr,
+ PendingCMD[i].DataSrcAddr,
+ PendingCMD[i].MemCopyByteCnt);
+ case DUMMY_CMD:
+ PendingCMD[i].Status = PASS;
+ break;
+ default:
+ PendingCMD[i].Status = FAIL;
+ break;
+ }
+ }
+
+ /*
+ * Temperory adding code to reset PendingCMD array for basic testing.
+ * It should be done at the end of event status function.
+ */
+ for (i = tag_count + MAX_CHANS; i < MAX_DESCS; i++) {
+ PendingCMD[i].CMD = 0;
+ PendingCMD[i].Tag = 0;
+ PendingCMD[i].DataAddr = 0;
+ PendingCMD[i].Block = 0;
+ PendingCMD[i].Page = 0;
+ PendingCMD[i].PageCount = 0;
+ PendingCMD[i].DataDestAddr = 0;
+ PendingCMD[i].DataSrcAddr = 0;
+ PendingCMD[i].MemCopyByteCnt = 0;
+ PendingCMD[i].ChanSync[0] = 0;
+ PendingCMD[i].ChanSync[1] = 0;
+ PendingCMD[i].ChanSync[2] = 0;
+ PendingCMD[i].ChanSync[3] = 0;
+ PendingCMD[i].ChanSync[4] = 0;
+ PendingCMD[i].Status = CMD_NOT_DONE;
+ }
+
+ nand_dbg_print(NAND_DBG_TRACE, "At end of Execute CMDs.\n");
+
+ emu_isr(0, 0); /* This is a null isr now. Need fill it in future */
+
+ return status;
+}
+
+/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
+* Function: emu_Event_Status
+* Inputs: none
+* Outputs: Event_Status code
+* Description: This function can also be used to force errors
+*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/
+u16 emu_CDMA_Event_Status(void)
+{
+ nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n",
+ __FILE__, __LINE__, __func__);
+
+ return EVENT_PASS;
+}
+
+#endif /* CMD_DMA */
+#endif /* !ELDORA */
+#endif /* FLASH_EMU */
diff --git a/drivers/staging/spectra/lld_emu.h b/drivers/staging/spectra/lld_emu.h
new file mode 100644
index 00000000000..63f84c38d3c
--- /dev/null
+++ b/drivers/staging/spectra/lld_emu.h
@@ -0,0 +1,51 @@
+/*
+ * NAND Flash Controller Device Driver
+ * Copyright (c) 2009, Intel Corporation and its suppliers.
+ *
+ * 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 _LLD_EMU_
+#define _LLD_EMU_
+
+#include "ffsport.h"
+#include "ffsdefs.h"
+
+/* prototypes: emulator API functions */
+extern u16 emu_Flash_Reset(void);
+extern u16 emu_Flash_Init(void);
+extern int emu_Flash_Release(void);
+extern u16 emu_Read_Device_ID(void);
+extern u16 emu_Erase_Block(u32 block_addr);
+extern u16 emu_Write_Page_Main(u8 *write_data, u32 Block,
+ u16 Page, u16 PageCount);
+extern u16 emu_Read_Page_Main(u8 *read_data, u32 Block, u16 Page,
+ u16 PageCount);
+extern u16 emu_Event_Status(void);
+extern void emu_Enable_Disable_Interrupts(u16 INT_ENABLE);
+extern u16 emu_Write_Page_Main_Spare(u8 *write_data, u32 Block,
+ u16 Page, u16 PageCount);
+extern u16 emu_Write_Page_Spare(u8 *write_data, u32 Block,
+ u16 Page, u16 PageCount);
+extern u16 emu_Read_Page_Main_Spare(u8 *read_data, u32 Block,
+ u16 Page, u16 PageCount);
+extern u16 emu_Read_Page_Spare(u8 *read_data, u32 Block, u16 Page,
+ u16 PageCount);
+extern u16 emu_Get_Bad_Block(u32 block);
+
+u16 emu_CDMA_Flash_Init(void);
+u16 emu_CDMA_Execute_CMDs(u16 tag_count);
+u16 emu_CDMA_Event_Status(void);
+#endif /*_LLD_EMU_*/
diff --git a/drivers/staging/spectra/lld_mtd.c b/drivers/staging/spectra/lld_mtd.c
new file mode 100644
index 00000000000..0de05b1e75f
--- /dev/null
+++ b/drivers/staging/spectra/lld_mtd.c
@@ -0,0 +1,687 @@
+/*
+ * NAND Flash Controller Device Driver
+ * Copyright (c) 2009, Intel Corporation and its suppliers.
+ *
+ * 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/fs.h>
+#include <linux/slab.h>
+#include <linux/mtd/mtd.h>
+#include "flash.h"
+#include "ffsdefs.h"
+#include "lld_emu.h"
+#include "lld.h"
+#if CMD_DMA
+#include "lld_cdma.h"
+#endif
+
+#define GLOB_LLD_PAGES 64
+#define GLOB_LLD_PAGE_SIZE (512+16)
+#define GLOB_LLD_PAGE_DATA_SIZE 512
+#define GLOB_LLD_BLOCKS 2048
+
+#if CMD_DMA
+#include "lld_cdma.h"
+u32 totalUsedBanks;
+u32 valid_banks[MAX_CHANS];
+#endif
+
+static struct mtd_info *spectra_mtd;
+static int mtddev = -1;
+module_param(mtddev, int, 0);
+
+/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
+* Function: mtd_Flash_Init
+* Inputs: none
+* Outputs: PASS=0 (notice 0=ok here)
+* Description: Creates & initializes the flash RAM array.
+*
+*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/
+u16 mtd_Flash_Init(void)
+{
+ if (mtddev == -1) {
+ printk(KERN_ERR "No MTD device specified. Give mtddev parameter\n");
+ return FAIL;
+ }
+
+ spectra_mtd = get_mtd_device(NULL, mtddev);
+ if (!spectra_mtd) {
+ printk(KERN_ERR "Failed to obtain MTD device #%d\n", mtddev);
+ return FAIL;
+ }
+
+ nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n",
+ __FILE__, __LINE__, __func__);
+
+ return PASS;
+}
+
+/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
+* Function: mtd_Flash_Release
+* Inputs: none
+* Outputs: PASS=0 (notice 0=ok here)
+* Description: Releases the flash.
+*
+*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/
+int mtd_Flash_Release(void)
+{
+ nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n",
+ __FILE__, __LINE__, __func__);
+ if (!spectra_mtd)
+ return PASS;
+
+ put_mtd_device(spectra_mtd);
+ spectra_mtd = NULL;
+
+ return PASS;
+}
+
+/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
+* Function: mtd_Read_Device_ID
+* Inputs: none
+* Outputs: PASS=1 FAIL=0
+* Description: Reads the info from the controller registers.
+* Sets up DeviceInfo structure with device parameters
+*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/
+
+u16 mtd_Read_Device_ID(void)
+{
+ uint64_t tmp;
+ nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n",
+ __FILE__, __LINE__, __func__);
+
+ if (!spectra_mtd)
+ return FAIL;
+
+ DeviceInfo.wDeviceMaker = 0;
+ DeviceInfo.wDeviceType = 8;
+ DeviceInfo.wSpectraStartBlock = SPECTRA_START_BLOCK;
+ tmp = spectra_mtd->size;
+ do_div(tmp, spectra_mtd->erasesize);
+ DeviceInfo.wTotalBlocks = tmp;
+ DeviceInfo.wSpectraEndBlock = DeviceInfo.wTotalBlocks - 1;
+ DeviceInfo.wPagesPerBlock = spectra_mtd->erasesize / spectra_mtd->writesize;
+ DeviceInfo.wPageSize = spectra_mtd->writesize + spectra_mtd->oobsize;
+ DeviceInfo.wPageDataSize = spectra_mtd->writesize;
+ DeviceInfo.wPageSpareSize = spectra_mtd->oobsize;
+ DeviceInfo.wBlockSize = DeviceInfo.wPageSize * DeviceInfo.wPagesPerBlock;
+ DeviceInfo.wBlockDataSize = DeviceInfo.wPageDataSize * DeviceInfo.wPagesPerBlock;
+ DeviceInfo.wDataBlockNum = (u32) (DeviceInfo.wSpectraEndBlock -
+ DeviceInfo.wSpectraStartBlock
+ + 1);
+ DeviceInfo.MLCDevice = 0;//spectra_mtd->celltype & NAND_CI_CELLTYPE_MSK;
+ DeviceInfo.nBitsInPageNumber =
+ (u8)GLOB_Calc_Used_Bits(DeviceInfo.wPagesPerBlock);
+ DeviceInfo.nBitsInPageDataSize =
+ (u8)GLOB_Calc_Used_Bits(DeviceInfo.wPageDataSize);
+ DeviceInfo.nBitsInBlockDataSize =
+ (u8)GLOB_Calc_Used_Bits(DeviceInfo.wBlockDataSize);
+
+#if CMD_DMA
+ totalUsedBanks = 4;
+ valid_banks[0] = 1;
+ valid_banks[1] = 1;
+ valid_banks[2] = 1;
+ valid_banks[3] = 1;
+#endif
+
+ return PASS;
+}
+
+/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
+* Function: mtd_Flash_Reset
+* Inputs: none
+* Outputs: PASS=0 (notice 0=ok here)
+* Description: Reset the flash
+*
+*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/
+u16 mtd_Flash_Reset(void)
+{
+ nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n",
+ __FILE__, __LINE__, __func__);
+
+ return PASS;
+}
+
+void erase_callback(struct erase_info *e)
+{
+ complete((void *)e->priv);
+}
+
+/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
+* Function: mtd_Erase_Block
+* Inputs: Address
+* Outputs: PASS=0 (notice 0=ok here)
+* Description: Erase a block
+*
+*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/
+u16 mtd_Erase_Block(u32 block_add)
+{
+ struct erase_info erase;
+ DECLARE_COMPLETION_ONSTACK(comp);
+ int ret;
+
+ nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n",
+ __FILE__, __LINE__, __func__);
+
+ if (block_add >= DeviceInfo.wTotalBlocks) {
+ printk(KERN_ERR "mtd_Erase_Block error! "
+ "Too big block address: %d\n", block_add);
+ return FAIL;
+ }
+
+ nand_dbg_print(NAND_DBG_DEBUG, "Erasing block %d\n",
+ (int)block_add);
+
+ erase.mtd = spectra_mtd;
+ erase.callback = erase_callback;
+ erase.addr = block_add * spectra_mtd->erasesize;
+ erase.len = spectra_mtd->erasesize;
+ erase.priv = (unsigned long)&comp;
+
+ ret = spectra_mtd->erase(spectra_mtd, &erase);
+ if (!ret) {
+ wait_for_completion(&comp);
+ if (erase.state != MTD_ERASE_DONE)
+ ret = -EIO;
+ }
+ if (ret) {
+ printk(KERN_WARNING "mtd_Erase_Block error! "
+ "erase of region [0x%llx, 0x%llx] failed\n",
+ erase.addr, erase.len);
+ return FAIL;
+ }
+
+ return PASS;
+}
+
+/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
+* Function: mtd_Write_Page_Main
+* Inputs: Write buffer address pointer
+* Block number
+* Page number
+* Number of pages to process
+* Outputs: PASS=0 (notice 0=ok here)
+* Description: Write the data in the buffer to main area of flash
+*
+*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/
+u16 mtd_Write_Page_Main(u8 *write_data, u32 Block,
+ u16 Page, u16 PageCount)
+{
+ size_t retlen;
+ int ret = 0;
+
+ if (Block >= DeviceInfo.wTotalBlocks)
+ return FAIL;
+
+ if (Page + PageCount > DeviceInfo.wPagesPerBlock)
+ return FAIL;
+
+ nand_dbg_print(NAND_DBG_DEBUG, "mtd_Write_Page_Main: "
+ "lba %u Page %u PageCount %u\n",
+ (unsigned int)Block,
+ (unsigned int)Page, (unsigned int)PageCount);
+
+
+ while (PageCount) {
+ ret = spectra_mtd->write(spectra_mtd,
+ (Block * spectra_mtd->erasesize) + (Page * spectra_mtd->writesize),
+ DeviceInfo.wPageDataSize, &retlen, write_data);
+ if (ret) {
+ printk(KERN_ERR "%s failed %d\n", __func__, ret);
+ return FAIL;
+ }
+ write_data += DeviceInfo.wPageDataSize;
+ Page++;
+ PageCount--;
+ }
+
+ nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n",
+ __FILE__, __LINE__, __func__);
+
+ return PASS;
+}
+
+/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
+* Function: mtd_Read_Page_Main
+* Inputs: Read buffer address pointer
+* Block number
+* Page number
+* Number of pages to process
+* Outputs: PASS=0 (notice 0=ok here)
+* Description: Read the data from the flash main area to the buffer
+*
+*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/
+u16 mtd_Read_Page_Main(u8 *read_data, u32 Block,
+ u16 Page, u16 PageCount)
+{
+ size_t retlen;
+ int ret = 0;
+
+ nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n",
+ __FILE__, __LINE__, __func__);
+
+ if (Block >= DeviceInfo.wTotalBlocks)
+ return FAIL;
+
+ if (Page + PageCount > DeviceInfo.wPagesPerBlock)
+ return FAIL;
+
+ nand_dbg_print(NAND_DBG_DEBUG, "mtd_Read_Page_Main: "
+ "lba %u Page %u PageCount %u\n",
+ (unsigned int)Block,
+ (unsigned int)Page, (unsigned int)PageCount);
+
+
+ while (PageCount) {
+ ret = spectra_mtd->read(spectra_mtd,
+ (Block * spectra_mtd->erasesize) + (Page * spectra_mtd->writesize),
+ DeviceInfo.wPageDataSize, &retlen, read_data);
+ if (ret) {
+ printk(KERN_ERR "%s failed %d\n", __func__, ret);
+ return FAIL;
+ }
+ read_data += DeviceInfo.wPageDataSize;
+ Page++;
+ PageCount--;
+ }
+
+ nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n",
+ __FILE__, __LINE__, __func__);
+
+ return PASS;
+}
+
+#ifndef ELDORA
+/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
+* Function: mtd_Read_Page_Main_Spare
+* Inputs: Write Buffer
+* Address
+* Buffer size
+* Outputs: PASS=0 (notice 0=ok here)
+* Description: Read from flash main+spare area
+*
+*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/
+u16 mtd_Read_Page_Main_Spare(u8 *read_data, u32 Block,
+ u16 Page, u16 PageCount)
+{
+ nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n",
+ __FILE__, __LINE__, __func__);
+
+ if (Block >= DeviceInfo.wTotalBlocks) {
+ printk(KERN_ERR "Read Page Main+Spare "
+ "Error: Block Address too big\n");
+ return FAIL;
+ }
+
+ if (Page + PageCount > DeviceInfo.wPagesPerBlock) {
+ printk(KERN_ERR "Read Page Main+Spare "
+ "Error: Page number %d+%d too big in block %d\n",
+ Page, PageCount, Block);
+ return FAIL;
+ }
+
+ nand_dbg_print(NAND_DBG_DEBUG, "Read Page Main + Spare - "
+ "No. of pages %u block %u start page %u\n",
+ (unsigned int)PageCount,
+ (unsigned int)Block, (unsigned int)Page);
+
+
+ while (PageCount) {
+ struct mtd_oob_ops ops;
+ int ret;
+
+ ops.mode = MTD_OOB_AUTO;
+ ops.datbuf = read_data;
+ ops.len = DeviceInfo.wPageDataSize;
+ ops.oobbuf = read_data + DeviceInfo.wPageDataSize + BTSIG_OFFSET;
+ ops.ooblen = BTSIG_BYTES;
+ ops.ooboffs = 0;
+
+ ret = spectra_mtd->read_oob(spectra_mtd,
+ (Block * spectra_mtd->erasesize) + (Page * spectra_mtd->writesize),
+ &ops);
+ if (ret) {
+ printk(KERN_ERR "%s failed %d\n", __func__, ret);
+ return FAIL;
+ }
+ read_data += DeviceInfo.wPageSize;
+ Page++;
+ PageCount--;
+ }
+
+ return PASS;
+}
+
+/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
+* Function: mtd_Write_Page_Main_Spare
+* Inputs: Write buffer
+* address
+* buffer length
+* Outputs: PASS=0 (notice 0=ok here)
+* Description: Write the buffer to main+spare area of flash
+*
+*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/
+u16 mtd_Write_Page_Main_Spare(u8 *write_data, u32 Block,
+ u16 Page, u16 page_count)
+{
+ nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n",
+ __FILE__, __LINE__, __func__);
+
+ if (Block >= DeviceInfo.wTotalBlocks) {
+ printk(KERN_ERR "Write Page Main + Spare "
+ "Error: Block Address too big\n");
+ return FAIL;
+ }
+
+ if (Page + page_count > DeviceInfo.wPagesPerBlock) {
+ printk(KERN_ERR "Write Page Main + Spare "
+ "Error: Page number %d+%d too big in block %d\n",
+ Page, page_count, Block);
+ WARN_ON(1);
+ return FAIL;
+ }
+
+ nand_dbg_print(NAND_DBG_DEBUG, "Write Page Main+Spare - "
+ "No. of pages %u block %u start page %u\n",
+ (unsigned int)page_count,
+ (unsigned int)Block, (unsigned int)Page);
+
+ while (page_count) {
+ struct mtd_oob_ops ops;
+ int ret;
+
+ ops.mode = MTD_OOB_AUTO;
+ ops.datbuf = write_data;
+ ops.len = DeviceInfo.wPageDataSize;
+ ops.oobbuf = write_data + DeviceInfo.wPageDataSize + BTSIG_OFFSET;
+ ops.ooblen = BTSIG_BYTES;
+ ops.ooboffs = 0;
+
+ ret = spectra_mtd->write_oob(spectra_mtd,
+ (Block * spectra_mtd->erasesize) + (Page * spectra_mtd->writesize),
+ &ops);
+ if (ret) {
+ printk(KERN_ERR "%s failed %d\n", __func__, ret);
+ return FAIL;
+ }
+ write_data += DeviceInfo.wPageSize;
+ Page++;
+ page_count--;
+ }
+
+ return PASS;
+}
+
+/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
+* Function: mtd_Write_Page_Spare
+* Inputs: Write buffer
+* Address
+* buffer size
+* Outputs: PASS=0 (notice 0=ok here)
+* Description: Write the buffer in the spare area
+*
+*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/
+u16 mtd_Write_Page_Spare(u8 *write_data, u32 Block,
+ u16 Page, u16 PageCount)
+{
+ WARN_ON(1);
+ return FAIL;
+}
+
+/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
+* Function: mtd_Read_Page_Spare
+* Inputs: Write Buffer
+* Address
+* Buffer size
+* Outputs: PASS=0 (notice 0=ok here)
+* Description: Read data from the spare area
+*
+*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/
+u16 mtd_Read_Page_Spare(u8 *read_data, u32 Block,
+ u16 Page, u16 PageCount)
+{
+ nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n",
+ __FILE__, __LINE__, __func__);
+
+ if (Block >= DeviceInfo.wTotalBlocks) {
+ printk(KERN_ERR "Read Page Spare "
+ "Error: Block Address too big\n");
+ return FAIL;
+ }
+
+ if (Page + PageCount > DeviceInfo.wPagesPerBlock) {
+ printk(KERN_ERR "Read Page Spare "
+ "Error: Page number too big\n");
+ return FAIL;
+ }
+
+ nand_dbg_print(NAND_DBG_DEBUG, "Read Page Spare- "
+ "block %u page %u (%u pages)\n",
+ (unsigned int)Block, (unsigned int)Page, PageCount);
+
+ while (PageCount) {
+ struct mtd_oob_ops ops;
+ int ret;
+
+ ops.mode = MTD_OOB_AUTO;
+ ops.datbuf = NULL;
+ ops.len = 0;
+ ops.oobbuf = read_data;
+ ops.ooblen = BTSIG_BYTES;
+ ops.ooboffs = 0;
+
+ ret = spectra_mtd->read_oob(spectra_mtd,
+ (Block * spectra_mtd->erasesize) + (Page * spectra_mtd->writesize),
+ &ops);
+ if (ret) {
+ printk(KERN_ERR "%s failed %d\n", __func__, ret);
+ return FAIL;
+ }
+
+ read_data += DeviceInfo.wPageSize;
+ Page++;
+ PageCount--;
+ }
+
+ return PASS;
+}
+
+/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
+* Function: mtd_Enable_Disable_Interrupts
+* Inputs: enable or disable
+* Outputs: none
+* Description: NOP
+*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/
+void mtd_Enable_Disable_Interrupts(u16 INT_ENABLE)
+{
+ nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n",
+ __FILE__, __LINE__, __func__);
+}
+
+u16 mtd_Get_Bad_Block(u32 block)
+{
+ return 0;
+}
+
+#if CMD_DMA
+/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
+* Support for CDMA functions
+************************************
+* mtd_CDMA_Flash_Init
+* CDMA_process_data command (use LLD_CDMA)
+* CDMA_MemCopy_CMD (use LLD_CDMA)
+* mtd_CDMA_execute all commands
+* mtd_CDMA_Event_Status
+*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/
+u16 mtd_CDMA_Flash_Init(void)
+{
+ u16 i;
+
+ nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n",
+ __FILE__, __LINE__, __func__);
+
+ for (i = 0; i < MAX_DESCS + MAX_CHANS; i++) {
+ PendingCMD[i].CMD = 0;
+ PendingCMD[i].Tag = 0;
+ PendingCMD[i].DataAddr = 0;
+ PendingCMD[i].Block = 0;
+ PendingCMD[i].Page = 0;
+ PendingCMD[i].PageCount = 0;
+ PendingCMD[i].DataDestAddr = 0;
+ PendingCMD[i].DataSrcAddr = 0;
+ PendingCMD[i].MemCopyByteCnt = 0;
+ PendingCMD[i].ChanSync[0] = 0;
+ PendingCMD[i].ChanSync[1] = 0;
+ PendingCMD[i].ChanSync[2] = 0;
+ PendingCMD[i].ChanSync[3] = 0;
+ PendingCMD[i].ChanSync[4] = 0;
+ PendingCMD[i].Status = 3;
+ }
+
+ return PASS;
+}
+
+static void mtd_isr(int irq, void *dev_id)
+{
+ /* TODO: ... */
+}
+
+/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
+* Function: CDMA_Execute_CMDs
+* Inputs: tag_count: the number of pending cmds to do
+* Outputs: PASS/FAIL
+* Description: execute each command in the pending CMD array
+*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/
+u16 mtd_CDMA_Execute_CMDs(u16 tag_count)
+{
+ u16 i, j;
+ u8 CMD; /* cmd parameter */
+ u8 *data;
+ u32 block;
+ u16 page;
+ u16 count;
+ u16 status = PASS;
+
+ nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n",
+ __FILE__, __LINE__, __func__);
+
+ nand_dbg_print(NAND_DBG_TRACE, "At start of Execute CMDs: "
+ "Tag Count %u\n", tag_count);
+
+ for (i = 0; i < totalUsedBanks; i++) {
+ PendingCMD[i].CMD = DUMMY_CMD;
+ PendingCMD[i].Tag = 0xFF;
+ PendingCMD[i].Block =
+ (DeviceInfo.wTotalBlocks / totalUsedBanks) * i;
+
+ for (j = 0; j <= MAX_CHANS; j++)
+ PendingCMD[i].ChanSync[j] = 0;
+ }
+
+ CDMA_Execute_CMDs(tag_count);
+
+#ifdef VERBOSE
+ print_pending_cmds(tag_count);
+#endif
+#if DEBUG_SYNC
+ }
+ debug_sync_cnt++;
+#endif
+
+ for (i = MAX_CHANS;
+ i < tag_count + MAX_CHANS; i++) {
+ CMD = PendingCMD[i].CMD;
+ data = PendingCMD[i].DataAddr;
+ block = PendingCMD[i].Block;
+ page = PendingCMD[i].Page;
+ count = PendingCMD[i].PageCount;
+
+ switch (CMD) {
+ case ERASE_CMD:
+ mtd_Erase_Block(block);
+ PendingCMD[i].Status = PASS;
+ break;
+ case WRITE_MAIN_CMD:
+ mtd_Write_Page_Main(data, block, page, count);
+ PendingCMD[i].Status = PASS;
+ break;
+ case WRITE_MAIN_SPARE_CMD:
+ mtd_Write_Page_Main_Spare(data, block, page, count);
+ PendingCMD[i].Status = PASS;
+ break;
+ case READ_MAIN_CMD:
+ mtd_Read_Page_Main(data, block, page, count);
+ PendingCMD[i].Status = PASS;
+ break;
+ case MEMCOPY_CMD:
+ memcpy(PendingCMD[i].DataDestAddr,
+ PendingCMD[i].DataSrcAddr,
+ PendingCMD[i].MemCopyByteCnt);
+ case DUMMY_CMD:
+ PendingCMD[i].Status = PASS;
+ break;
+ default:
+ PendingCMD[i].Status = FAIL;
+ break;
+ }
+ }
+
+ /*
+ * Temperory adding code to reset PendingCMD array for basic testing.
+ * It should be done at the end of event status function.
+ */
+ for (i = tag_count + MAX_CHANS; i < MAX_DESCS; i++) {
+ PendingCMD[i].CMD = 0;
+ PendingCMD[i].Tag = 0;
+ PendingCMD[i].DataAddr = 0;
+ PendingCMD[i].Block = 0;
+ PendingCMD[i].Page = 0;
+ PendingCMD[i].PageCount = 0;
+ PendingCMD[i].DataDestAddr = 0;
+ PendingCMD[i].DataSrcAddr = 0;
+ PendingCMD[i].MemCopyByteCnt = 0;
+ PendingCMD[i].ChanSync[0] = 0;
+ PendingCMD[i].ChanSync[1] = 0;
+ PendingCMD[i].ChanSync[2] = 0;
+ PendingCMD[i].ChanSync[3] = 0;
+ PendingCMD[i].ChanSync[4] = 0;
+ PendingCMD[i].Status = CMD_NOT_DONE;
+ }
+
+ nand_dbg_print(NAND_DBG_TRACE, "At end of Execute CMDs.\n");
+
+ mtd_isr(0, 0); /* This is a null isr now. Need fill it in future */
+
+ return status;
+}
+
+/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
+* Function: mtd_Event_Status
+* Inputs: none
+* Outputs: Event_Status code
+* Description: This function can also be used to force errors
+*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/
+u16 mtd_CDMA_Event_Status(void)
+{
+ nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n",
+ __FILE__, __LINE__, __func__);
+
+ return EVENT_PASS;
+}
+
+#endif /* CMD_DMA */
+#endif /* !ELDORA */
diff --git a/drivers/staging/spectra/lld_mtd.h b/drivers/staging/spectra/lld_mtd.h
new file mode 100644
index 00000000000..4e81ee87b53
--- /dev/null
+++ b/drivers/staging/spectra/lld_mtd.h
@@ -0,0 +1,51 @@
+/*
+ * NAND Flash Controller Device Driver
+ * Copyright (c) 2009, Intel Corporation and its suppliers.
+ *
+ * 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 _LLD_MTD_
+#define _LLD_MTD_
+
+#include "ffsport.h"
+#include "ffsdefs.h"
+
+/* prototypes: MTD API functions */
+extern u16 mtd_Flash_Reset(void);
+extern u16 mtd_Flash_Init(void);
+extern int mtd_Flash_Release(void);
+extern u16 mtd_Read_Device_ID(void);
+extern u16 mtd_Erase_Block(u32 block_addr);
+extern u16 mtd_Write_Page_Main(u8 *write_data, u32 Block,
+ u16 Page, u16 PageCount);
+extern u16 mtd_Read_Page_Main(u8 *read_data, u32 Block, u16 Page,
+ u16 PageCount);
+extern u16 mtd_Event_Status(void);
+extern void mtd_Enable_Disable_Interrupts(u16 INT_ENABLE);
+extern u16 mtd_Write_Page_Main_Spare(u8 *write_data, u32 Block,
+ u16 Page, u16 PageCount);
+extern u16 mtd_Write_Page_Spare(u8 *write_data, u32 Block,
+ u16 Page, u16 PageCount);
+extern u16 mtd_Read_Page_Main_Spare(u8 *read_data, u32 Block,
+ u16 Page, u16 PageCount);
+extern u16 mtd_Read_Page_Spare(u8 *read_data, u32 Block, u16 Page,
+ u16 PageCount);
+extern u16 mtd_Get_Bad_Block(u32 block);
+
+u16 mtd_CDMA_Flash_Init(void);
+u16 mtd_CDMA_Execute_CMDs(u16 tag_count);
+u16 mtd_CDMA_Event_Status(void);
+#endif /*_LLD_MTD_*/
diff --git a/drivers/staging/spectra/lld_nand.c b/drivers/staging/spectra/lld_nand.c
new file mode 100644
index 00000000000..13c3ad2db39
--- /dev/null
+++ b/drivers/staging/spectra/lld_nand.c
@@ -0,0 +1,2601 @@
+/*
+ * NAND Flash Controller Device Driver
+ * Copyright (c) 2009, Intel Corporation and its suppliers.
+ *
+ * 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 "lld.h"
+#include "lld_nand.h"
+#include "lld_cdma.h"
+
+#include "spectraswconfig.h"
+#include "flash.h"
+#include "ffsdefs.h"
+
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/wait.h>
+#include <linux/mutex.h>
+
+#include "nand_regs.h"
+
+#define SPECTRA_NAND_NAME "nd"
+
+#define CEIL_DIV(X, Y) (((X)%(Y)) ? ((X)/(Y)+1) : ((X)/(Y)))
+#define MAX_PAGES_PER_RW 128
+
+#define INT_IDLE_STATE 0
+#define INT_READ_PAGE_MAIN 0x01
+#define INT_WRITE_PAGE_MAIN 0x02
+#define INT_PIPELINE_READ_AHEAD 0x04
+#define INT_PIPELINE_WRITE_AHEAD 0x08
+#define INT_MULTI_PLANE_READ 0x10
+#define INT_MULTI_PLANE_WRITE 0x11
+
+static u32 enable_ecc;
+
+struct mrst_nand_info info;
+
+int totalUsedBanks;
+u32 GLOB_valid_banks[LLD_MAX_FLASH_BANKS];
+
+void __iomem *FlashReg;
+void __iomem *FlashMem;
+
+u16 conf_parameters[] = {
+ 0x0000,
+ 0x0000,
+ 0x01F4,
+ 0x01F4,
+ 0x01F4,
+ 0x01F4,
+ 0x0000,
+ 0x0000,
+ 0x0001,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0040,
+ 0x0001,
+ 0x000A,
+ 0x000A,
+ 0x000A,
+ 0x0000,
+ 0x0000,
+ 0x0005,
+ 0x0012,
+ 0x000C
+};
+
+u16 NAND_Get_Bad_Block(u32 block)
+{
+ u32 status = PASS;
+ u32 flag_bytes = 0;
+ u32 skip_bytes = DeviceInfo.wSpareSkipBytes;
+ u32 page, i;
+ u8 *pReadSpareBuf = buf_get_bad_block;
+
+ if (enable_ecc)
+ flag_bytes = DeviceInfo.wNumPageSpareFlag;
+
+ for (page = 0; page < 2; page++) {
+ status = NAND_Read_Page_Spare(pReadSpareBuf, block, page, 1);
+ if (status != PASS)
+ return READ_ERROR;
+ for (i = flag_bytes; i < (flag_bytes + skip_bytes); i++)
+ if (pReadSpareBuf[i] != 0xff)
+ return DEFECTIVE_BLOCK;
+ }
+
+ for (page = 1; page < 3; page++) {
+ status = NAND_Read_Page_Spare(pReadSpareBuf, block,
+ DeviceInfo.wPagesPerBlock - page , 1);
+ if (status != PASS)
+ return READ_ERROR;
+ for (i = flag_bytes; i < (flag_bytes + skip_bytes); i++)
+ if (pReadSpareBuf[i] != 0xff)
+ return DEFECTIVE_BLOCK;
+ }
+
+ return GOOD_BLOCK;
+}
+
+
+u16 NAND_Flash_Reset(void)
+{
+ u32 i;
+ u32 intr_status_rst_comp[4] = {INTR_STATUS0__RST_COMP,
+ INTR_STATUS1__RST_COMP,
+ INTR_STATUS2__RST_COMP,
+ INTR_STATUS3__RST_COMP};
+ u32 intr_status_time_out[4] = {INTR_STATUS0__TIME_OUT,
+ INTR_STATUS1__TIME_OUT,
+ INTR_STATUS2__TIME_OUT,
+ INTR_STATUS3__TIME_OUT};
+ u32 intr_status[4] = {INTR_STATUS0, INTR_STATUS1,
+ INTR_STATUS2, INTR_STATUS3};
+ u32 device_reset_banks[4] = {DEVICE_RESET__BANK0,
+ DEVICE_RESET__BANK1,
+ DEVICE_RESET__BANK2,
+ DEVICE_RESET__BANK3};
+
+ nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n",
+ __FILE__, __LINE__, __func__);
+
+ for (i = 0 ; i < LLD_MAX_FLASH_BANKS; i++)
+ iowrite32(intr_status_rst_comp[i] | intr_status_time_out[i],
+ FlashReg + intr_status[i]);
+
+ for (i = 0 ; i < LLD_MAX_FLASH_BANKS; i++) {
+ iowrite32(device_reset_banks[i], FlashReg + DEVICE_RESET);
+ while (!(ioread32(FlashReg + intr_status[i]) &
+ (intr_status_rst_comp[i] | intr_status_time_out[i])))
+ ;
+ if (ioread32(FlashReg + intr_status[i]) &
+ intr_status_time_out[i])
+ nand_dbg_print(NAND_DBG_WARN,
+ "NAND Reset operation timed out on bank %d\n", i);
+ }
+
+ for (i = 0; i < LLD_MAX_FLASH_BANKS; i++)
+ iowrite32(intr_status_rst_comp[i] | intr_status_time_out[i],
+ FlashReg + intr_status[i]);
+
+ return PASS;
+}
+
+static void NAND_ONFi_Timing_Mode(u16 mode)
+{
+ u16 Trea[6] = {40, 30, 25, 20, 20, 16};
+ u16 Trp[6] = {50, 25, 17, 15, 12, 10};
+ u16 Treh[6] = {30, 15, 15, 10, 10, 7};
+ u16 Trc[6] = {100, 50, 35, 30, 25, 20};
+ u16 Trhoh[6] = {0, 15, 15, 15, 15, 15};
+ u16 Trloh[6] = {0, 0, 0, 0, 5, 5};
+ u16 Tcea[6] = {100, 45, 30, 25, 25, 25};
+ u16 Tadl[6] = {200, 100, 100, 100, 70, 70};
+ u16 Trhw[6] = {200, 100, 100, 100, 100, 100};
+ u16 Trhz[6] = {200, 100, 100, 100, 100, 100};
+ u16 Twhr[6] = {120, 80, 80, 60, 60, 60};
+ u16 Tcs[6] = {70, 35, 25, 25, 20, 15};
+
+ u16 TclsRising = 1;
+ u16 data_invalid_rhoh, data_invalid_rloh, data_invalid;
+ u16 dv_window = 0;
+ u16 en_lo, en_hi;
+ u16 acc_clks;
+ u16 addr_2_data, re_2_we, re_2_re, we_2_re, cs_cnt;
+
+ nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n",
+ __FILE__, __LINE__, __func__);
+
+ en_lo = CEIL_DIV(Trp[mode], CLK_X);
+ en_hi = CEIL_DIV(Treh[mode], CLK_X);
+
+#if ONFI_BLOOM_TIME
+ if ((en_hi * CLK_X) < (Treh[mode] + 2))
+ en_hi++;
+#endif
+
+ if ((en_lo + en_hi) * CLK_X < Trc[mode])
+ en_lo += CEIL_DIV((Trc[mode] - (en_lo + en_hi) * CLK_X), CLK_X);
+
+ if ((en_lo + en_hi) < CLK_MULTI)
+ en_lo += CLK_MULTI - en_lo - en_hi;
+
+ while (dv_window < 8) {
+ data_invalid_rhoh = en_lo * CLK_X + Trhoh[mode];
+
+ data_invalid_rloh = (en_lo + en_hi) * CLK_X + Trloh[mode];
+
+ data_invalid =
+ data_invalid_rhoh <
+ data_invalid_rloh ? data_invalid_rhoh : data_invalid_rloh;
+
+ dv_window = data_invalid - Trea[mode];
+
+ if (dv_window < 8)
+ en_lo++;
+ }
+
+ acc_clks = CEIL_DIV(Trea[mode], CLK_X);
+
+ while (((acc_clks * CLK_X) - Trea[mode]) < 3)
+ acc_clks++;
+
+ if ((data_invalid - acc_clks * CLK_X) < 2)
+ nand_dbg_print(NAND_DBG_WARN, "%s, Line %d: Warning!\n",
+ __FILE__, __LINE__);
+
+ addr_2_data = CEIL_DIV(Tadl[mode], CLK_X);
+ re_2_we = CEIL_DIV(Trhw[mode], CLK_X);
+ re_2_re = CEIL_DIV(Trhz[mode], CLK_X);
+ we_2_re = CEIL_DIV(Twhr[mode], CLK_X);
+ cs_cnt = CEIL_DIV((Tcs[mode] - Trp[mode]), CLK_X);
+ if (!TclsRising)
+ cs_cnt = CEIL_DIV(Tcs[mode], CLK_X);
+ if (cs_cnt == 0)
+ cs_cnt = 1;
+
+ if (Tcea[mode]) {
+ while (((cs_cnt * CLK_X) + Trea[mode]) < Tcea[mode])
+ cs_cnt++;
+ }
+
+#if MODE5_WORKAROUND
+ if (mode == 5)
+ acc_clks = 5;
+#endif
+
+ /* Sighting 3462430: Temporary hack for MT29F128G08CJABAWP:B */
+ if ((ioread32(FlashReg + MANUFACTURER_ID) == 0) &&
+ (ioread32(FlashReg + DEVICE_ID) == 0x88))
+ acc_clks = 6;
+
+ iowrite32(acc_clks, FlashReg + ACC_CLKS);
+ iowrite32(re_2_we, FlashReg + RE_2_WE);
+ iowrite32(re_2_re, FlashReg + RE_2_RE);
+ iowrite32(we_2_re, FlashReg + WE_2_RE);
+ iowrite32(addr_2_data, FlashReg + ADDR_2_DATA);
+ iowrite32(en_lo, FlashReg + RDWR_EN_LO_CNT);
+ iowrite32(en_hi, FlashReg + RDWR_EN_HI_CNT);
+ iowrite32(cs_cnt, FlashReg + CS_SETUP_CNT);
+}
+
+static void index_addr(u32 address, u32 data)
+{
+ iowrite32(address, FlashMem);
+ iowrite32(data, FlashMem + 0x10);
+}
+
+static void index_addr_read_data(u32 address, u32 *pdata)
+{
+ iowrite32(address, FlashMem);
+ *pdata = ioread32(FlashMem + 0x10);
+}
+
+static void set_ecc_config(void)
+{
+#if SUPPORT_8BITECC
+ if ((ioread32(FlashReg + DEVICE_MAIN_AREA_SIZE) < 4096) ||
+ (ioread32(FlashReg + DEVICE_SPARE_AREA_SIZE) <= 128))
+ iowrite32(8, FlashReg + ECC_CORRECTION);
+#endif
+
+ if ((ioread32(FlashReg + ECC_CORRECTION) & ECC_CORRECTION__VALUE)
+ == 1) {
+ DeviceInfo.wECCBytesPerSector = 4;
+ DeviceInfo.wECCBytesPerSector *= DeviceInfo.wDevicesConnected;
+ DeviceInfo.wNumPageSpareFlag =
+ DeviceInfo.wPageSpareSize -
+ DeviceInfo.wPageDataSize /
+ (ECC_SECTOR_SIZE * DeviceInfo.wDevicesConnected) *
+ DeviceInfo.wECCBytesPerSector
+ - DeviceInfo.wSpareSkipBytes;
+ } else {
+ DeviceInfo.wECCBytesPerSector =
+ (ioread32(FlashReg + ECC_CORRECTION) &
+ ECC_CORRECTION__VALUE) * 13 / 8;
+ if ((DeviceInfo.wECCBytesPerSector) % 2 == 0)
+ DeviceInfo.wECCBytesPerSector += 2;
+ else
+ DeviceInfo.wECCBytesPerSector += 1;
+
+ DeviceInfo.wECCBytesPerSector *= DeviceInfo.wDevicesConnected;
+ DeviceInfo.wNumPageSpareFlag = DeviceInfo.wPageSpareSize -
+ DeviceInfo.wPageDataSize /
+ (ECC_SECTOR_SIZE * DeviceInfo.wDevicesConnected) *
+ DeviceInfo.wECCBytesPerSector
+ - DeviceInfo.wSpareSkipBytes;
+ }
+}
+
+static u16 get_onfi_nand_para(void)
+{
+ int i;
+ u16 blks_lun_l, blks_lun_h, n_of_luns;
+ u32 blockperlun, id;
+
+ iowrite32(DEVICE_RESET__BANK0, FlashReg + DEVICE_RESET);
+
+ while (!((ioread32(FlashReg + INTR_STATUS0) &
+ INTR_STATUS0__RST_COMP) |
+ (ioread32(FlashReg + INTR_STATUS0) &
+ INTR_STATUS0__TIME_OUT)))
+ ;
+
+ if (ioread32(FlashReg + INTR_STATUS0) & INTR_STATUS0__RST_COMP) {
+ iowrite32(DEVICE_RESET__BANK1, FlashReg + DEVICE_RESET);
+ while (!((ioread32(FlashReg + INTR_STATUS1) &
+ INTR_STATUS1__RST_COMP) |
+ (ioread32(FlashReg + INTR_STATUS1) &
+ INTR_STATUS1__TIME_OUT)))
+ ;
+
+ if (ioread32(FlashReg + INTR_STATUS1) &
+ INTR_STATUS1__RST_COMP) {
+ iowrite32(DEVICE_RESET__BANK2,
+ FlashReg + DEVICE_RESET);
+ while (!((ioread32(FlashReg + INTR_STATUS2) &
+ INTR_STATUS2__RST_COMP) |
+ (ioread32(FlashReg + INTR_STATUS2) &
+ INTR_STATUS2__TIME_OUT)))
+ ;
+
+ if (ioread32(FlashReg + INTR_STATUS2) &
+ INTR_STATUS2__RST_COMP) {
+ iowrite32(DEVICE_RESET__BANK3,
+ FlashReg + DEVICE_RESET);
+ while (!((ioread32(FlashReg + INTR_STATUS3) &
+ INTR_STATUS3__RST_COMP) |
+ (ioread32(FlashReg + INTR_STATUS3) &
+ INTR_STATUS3__TIME_OUT)))
+ ;
+ } else {
+ printk(KERN_ERR "Getting a time out for bank 2!\n");
+ }
+ } else {
+ printk(KERN_ERR "Getting a time out for bank 1!\n");
+ }
+ }
+
+ iowrite32(INTR_STATUS0__TIME_OUT, FlashReg + INTR_STATUS0);
+ iowrite32(INTR_STATUS1__TIME_OUT, FlashReg + INTR_STATUS1);
+ iowrite32(INTR_STATUS2__TIME_OUT, FlashReg + INTR_STATUS2);
+ iowrite32(INTR_STATUS3__TIME_OUT, FlashReg + INTR_STATUS3);
+
+ DeviceInfo.wONFIDevFeatures =
+ ioread32(FlashReg + ONFI_DEVICE_FEATURES);
+ DeviceInfo.wONFIOptCommands =
+ ioread32(FlashReg + ONFI_OPTIONAL_COMMANDS);
+ DeviceInfo.wONFITimingMode =
+ ioread32(FlashReg + ONFI_TIMING_MODE);
+ DeviceInfo.wONFIPgmCacheTimingMode =
+ ioread32(FlashReg + ONFI_PGM_CACHE_TIMING_MODE);
+
+ n_of_luns = ioread32(FlashReg + ONFI_DEVICE_NO_OF_LUNS) &
+ ONFI_DEVICE_NO_OF_LUNS__NO_OF_LUNS;
+ blks_lun_l = ioread32(FlashReg + ONFI_DEVICE_NO_OF_BLOCKS_PER_LUN_L);
+ blks_lun_h = ioread32(FlashReg + ONFI_DEVICE_NO_OF_BLOCKS_PER_LUN_U);
+
+ blockperlun = (blks_lun_h << 16) | blks_lun_l;
+
+ DeviceInfo.wTotalBlocks = n_of_luns * blockperlun;
+
+ if (!(ioread32(FlashReg + ONFI_TIMING_MODE) &
+ ONFI_TIMING_MODE__VALUE))
+ return FAIL;
+
+ for (i = 5; i > 0; i--) {
+ if (ioread32(FlashReg + ONFI_TIMING_MODE) & (0x01 << i))
+ break;
+ }
+
+ NAND_ONFi_Timing_Mode(i);
+
+ index_addr(MODE_11 | 0, 0x90);
+ index_addr(MODE_11 | 1, 0);
+
+ for (i = 0; i < 3; i++)
+ index_addr_read_data(MODE_11 | 2, &id);
+
+ nand_dbg_print(NAND_DBG_DEBUG, "3rd ID: 0x%x\n", id);
+
+ DeviceInfo.MLCDevice = id & 0x0C;
+
+ /* By now, all the ONFI devices we know support the page cache */
+ /* rw feature. So here we enable the pipeline_rw_ahead feature */
+ /* iowrite32(1, FlashReg + CACHE_WRITE_ENABLE); */
+ /* iowrite32(1, FlashReg + CACHE_READ_ENABLE); */
+
+ return PASS;
+}
+
+static void get_samsung_nand_para(void)
+{
+ u8 no_of_planes;
+ u32 blk_size;
+ u64 plane_size, capacity;
+ u32 id_bytes[5];
+ int i;
+
+ index_addr((u32)(MODE_11 | 0), 0x90);
+ index_addr((u32)(MODE_11 | 1), 0);
+ for (i = 0; i < 5; i++)
+ index_addr_read_data((u32)(MODE_11 | 2), &id_bytes[i]);
+
+ nand_dbg_print(NAND_DBG_DEBUG,
+ "ID bytes: 0x%x, 0x%x, 0x%x, 0x%x, 0x%x\n",
+ id_bytes[0], id_bytes[1], id_bytes[2],
+ id_bytes[3], id_bytes[4]);
+
+ if ((id_bytes[1] & 0xff) == 0xd3) { /* Samsung K9WAG08U1A */
+ /* Set timing register values according to datasheet */
+ iowrite32(5, FlashReg + ACC_CLKS);
+ iowrite32(20, FlashReg + RE_2_WE);
+ iowrite32(12, FlashReg + WE_2_RE);
+ iowrite32(14, FlashReg + ADDR_2_DATA);
+ iowrite32(3, FlashReg + RDWR_EN_LO_CNT);
+ iowrite32(2, FlashReg + RDWR_EN_HI_CNT);
+ iowrite32(2, FlashReg + CS_SETUP_CNT);
+ }
+
+ no_of_planes = 1 << ((id_bytes[4] & 0x0c) >> 2);
+ plane_size = (u64)64 << ((id_bytes[4] & 0x70) >> 4);
+ blk_size = 64 << ((ioread32(FlashReg + DEVICE_PARAM_1) & 0x30) >> 4);
+ capacity = (u64)128 * plane_size * no_of_planes;
+
+ DeviceInfo.wTotalBlocks = (u32)GLOB_u64_Div(capacity, blk_size);
+}
+
+static void get_toshiba_nand_para(void)
+{
+ void __iomem *scratch_reg;
+ u32 tmp;
+
+ /* Workaround to fix a controller bug which reports a wrong */
+ /* spare area size for some kind of Toshiba NAND device */
+ if ((ioread32(FlashReg + DEVICE_MAIN_AREA_SIZE) == 4096) &&
+ (ioread32(FlashReg + DEVICE_SPARE_AREA_SIZE) == 64)) {
+ iowrite32(216, FlashReg + DEVICE_SPARE_AREA_SIZE);
+ tmp = ioread32(FlashReg + DEVICES_CONNECTED) *
+ ioread32(FlashReg + DEVICE_SPARE_AREA_SIZE);
+ iowrite32(tmp, FlashReg + LOGICAL_PAGE_SPARE_SIZE);
+#if SUPPORT_15BITECC
+ iowrite32(15, FlashReg + ECC_CORRECTION);
+#elif SUPPORT_8BITECC
+ iowrite32(8, FlashReg + ECC_CORRECTION);
+#endif
+ }
+
+ /* As Toshiba NAND can not provide it's block number, */
+ /* so here we need user to provide the correct block */
+ /* number in a scratch register before the Linux NAND */
+ /* driver is loaded. If no valid value found in the scratch */
+ /* register, then we use default block number value */
+ scratch_reg = ioremap_nocache(SCRATCH_REG_ADDR, SCRATCH_REG_SIZE);
+ if (!scratch_reg) {
+ printk(KERN_ERR "Spectra: ioremap failed in %s, Line %d",
+ __FILE__, __LINE__);
+ DeviceInfo.wTotalBlocks = GLOB_HWCTL_DEFAULT_BLKS;
+ } else {
+ nand_dbg_print(NAND_DBG_WARN,
+ "Spectra: ioremap reg address: 0x%p\n", scratch_reg);
+ DeviceInfo.wTotalBlocks = 1 << ioread8(scratch_reg);
+ if (DeviceInfo.wTotalBlocks < 512)
+ DeviceInfo.wTotalBlocks = GLOB_HWCTL_DEFAULT_BLKS;
+ iounmap(scratch_reg);
+ }
+}
+
+static void get_hynix_nand_para(void)
+{
+ void __iomem *scratch_reg;
+ u32 main_size, spare_size;
+
+ switch (DeviceInfo.wDeviceID) {
+ case 0xD5: /* Hynix H27UAG8T2A, H27UBG8U5A or H27UCG8VFA */
+ case 0xD7: /* Hynix H27UDG8VEM, H27UCG8UDM or H27UCG8V5A */
+ iowrite32(128, FlashReg + PAGES_PER_BLOCK);
+ iowrite32(4096, FlashReg + DEVICE_MAIN_AREA_SIZE);
+ iowrite32(224, FlashReg + DEVICE_SPARE_AREA_SIZE);
+ main_size = 4096 * ioread32(FlashReg + DEVICES_CONNECTED);
+ spare_size = 224 * ioread32(FlashReg + DEVICES_CONNECTED);
+ iowrite32(main_size, FlashReg + LOGICAL_PAGE_DATA_SIZE);
+ iowrite32(spare_size, FlashReg + LOGICAL_PAGE_SPARE_SIZE);
+ iowrite32(0, FlashReg + DEVICE_WIDTH);
+#if SUPPORT_15BITECC
+ iowrite32(15, FlashReg + ECC_CORRECTION);
+#elif SUPPORT_8BITECC
+ iowrite32(8, FlashReg + ECC_CORRECTION);
+#endif
+ DeviceInfo.MLCDevice = 1;
+ break;
+ default:
+ nand_dbg_print(NAND_DBG_WARN,
+ "Spectra: Unknown Hynix NAND (Device ID: 0x%x)."
+ "Will use default parameter values instead.\n",
+ DeviceInfo.wDeviceID);
+ }
+
+ scratch_reg = ioremap_nocache(SCRATCH_REG_ADDR, SCRATCH_REG_SIZE);
+ if (!scratch_reg) {
+ printk(KERN_ERR "Spectra: ioremap failed in %s, Line %d",
+ __FILE__, __LINE__);
+ DeviceInfo.wTotalBlocks = GLOB_HWCTL_DEFAULT_BLKS;
+ } else {
+ nand_dbg_print(NAND_DBG_WARN,
+ "Spectra: ioremap reg address: 0x%p\n", scratch_reg);
+ DeviceInfo.wTotalBlocks = 1 << ioread8(scratch_reg);
+ if (DeviceInfo.wTotalBlocks < 512)
+ DeviceInfo.wTotalBlocks = GLOB_HWCTL_DEFAULT_BLKS;
+ iounmap(scratch_reg);
+ }
+}
+
+static void find_valid_banks(void)
+{
+ u32 id[LLD_MAX_FLASH_BANKS];
+ int i;
+
+ totalUsedBanks = 0;
+ for (i = 0; i < LLD_MAX_FLASH_BANKS; i++) {
+ index_addr((u32)(MODE_11 | (i << 24) | 0), 0x90);
+ index_addr((u32)(MODE_11 | (i << 24) | 1), 0);
+ index_addr_read_data((u32)(MODE_11 | (i << 24) | 2), &id[i]);
+
+ nand_dbg_print(NAND_DBG_DEBUG,
+ "Return 1st ID for bank[%d]: %x\n", i, id[i]);
+
+ if (i == 0) {
+ if (id[i] & 0x0ff)
+ GLOB_valid_banks[i] = 1;
+ } else {
+ if ((id[i] & 0x0ff) == (id[0] & 0x0ff))
+ GLOB_valid_banks[i] = 1;
+ }
+
+ totalUsedBanks += GLOB_valid_banks[i];
+ }
+
+ nand_dbg_print(NAND_DBG_DEBUG,
+ "totalUsedBanks: %d\n", totalUsedBanks);
+}
+
+static void detect_partition_feature(void)
+{
+ if (ioread32(FlashReg + FEATURES) & FEATURES__PARTITION) {
+ if ((ioread32(FlashReg + PERM_SRC_ID_1) &
+ PERM_SRC_ID_1__SRCID) == SPECTRA_PARTITION_ID) {
+ DeviceInfo.wSpectraStartBlock =
+ ((ioread32(FlashReg + MIN_MAX_BANK_1) &
+ MIN_MAX_BANK_1__MIN_VALUE) *
+ DeviceInfo.wTotalBlocks)
+ +
+ (ioread32(FlashReg + MIN_BLK_ADDR_1) &
+ MIN_BLK_ADDR_1__VALUE);
+
+ DeviceInfo.wSpectraEndBlock =
+ (((ioread32(FlashReg + MIN_MAX_BANK_1) &
+ MIN_MAX_BANK_1__MAX_VALUE) >> 2) *
+ DeviceInfo.wTotalBlocks)
+ +
+ (ioread32(FlashReg + MAX_BLK_ADDR_1) &
+ MAX_BLK_ADDR_1__VALUE);
+
+ DeviceInfo.wTotalBlocks *= totalUsedBanks;
+
+ if (DeviceInfo.wSpectraEndBlock >=
+ DeviceInfo.wTotalBlocks) {
+ DeviceInfo.wSpectraEndBlock =
+ DeviceInfo.wTotalBlocks - 1;
+ }
+
+ DeviceInfo.wDataBlockNum =
+ DeviceInfo.wSpectraEndBlock -
+ DeviceInfo.wSpectraStartBlock + 1;
+ } else {
+ DeviceInfo.wTotalBlocks *= totalUsedBanks;
+ DeviceInfo.wSpectraStartBlock = SPECTRA_START_BLOCK;
+ DeviceInfo.wSpectraEndBlock =
+ DeviceInfo.wTotalBlocks - 1;
+ DeviceInfo.wDataBlockNum =
+ DeviceInfo.wSpectraEndBlock -
+ DeviceInfo.wSpectraStartBlock + 1;
+ }
+ } else {
+ DeviceInfo.wTotalBlocks *= totalUsedBanks;
+ DeviceInfo.wSpectraStartBlock = SPECTRA_START_BLOCK;
+ DeviceInfo.wSpectraEndBlock = DeviceInfo.wTotalBlocks - 1;
+ DeviceInfo.wDataBlockNum =
+ DeviceInfo.wSpectraEndBlock -
+ DeviceInfo.wSpectraStartBlock + 1;
+ }
+}
+
+static void dump_device_info(void)
+{
+ nand_dbg_print(NAND_DBG_DEBUG, "DeviceInfo:\n");
+ nand_dbg_print(NAND_DBG_DEBUG, "DeviceMaker: 0x%x\n",
+ DeviceInfo.wDeviceMaker);
+ nand_dbg_print(NAND_DBG_DEBUG, "DeviceID: 0x%x\n",
+ DeviceInfo.wDeviceID);
+ nand_dbg_print(NAND_DBG_DEBUG, "DeviceType: 0x%x\n",
+ DeviceInfo.wDeviceType);
+ nand_dbg_print(NAND_DBG_DEBUG, "SpectraStartBlock: %d\n",
+ DeviceInfo.wSpectraStartBlock);
+ nand_dbg_print(NAND_DBG_DEBUG, "SpectraEndBlock: %d\n",
+ DeviceInfo.wSpectraEndBlock);
+ nand_dbg_print(NAND_DBG_DEBUG, "TotalBlocks: %d\n",
+ DeviceInfo.wTotalBlocks);
+ nand_dbg_print(NAND_DBG_DEBUG, "PagesPerBlock: %d\n",
+ DeviceInfo.wPagesPerBlock);
+ nand_dbg_print(NAND_DBG_DEBUG, "PageSize: %d\n",
+ DeviceInfo.wPageSize);
+ nand_dbg_print(NAND_DBG_DEBUG, "PageDataSize: %d\n",
+ DeviceInfo.wPageDataSize);
+ nand_dbg_print(NAND_DBG_DEBUG, "PageSpareSize: %d\n",
+ DeviceInfo.wPageSpareSize);
+ nand_dbg_print(NAND_DBG_DEBUG, "NumPageSpareFlag: %d\n",
+ DeviceInfo.wNumPageSpareFlag);
+ nand_dbg_print(NAND_DBG_DEBUG, "ECCBytesPerSector: %d\n",
+ DeviceInfo.wECCBytesPerSector);
+ nand_dbg_print(NAND_DBG_DEBUG, "BlockSize: %d\n",
+ DeviceInfo.wBlockSize);
+ nand_dbg_print(NAND_DBG_DEBUG, "BlockDataSize: %d\n",
+ DeviceInfo.wBlockDataSize);
+ nand_dbg_print(NAND_DBG_DEBUG, "DataBlockNum: %d\n",
+ DeviceInfo.wDataBlockNum);
+ nand_dbg_print(NAND_DBG_DEBUG, "PlaneNum: %d\n",
+ DeviceInfo.bPlaneNum);
+ nand_dbg_print(NAND_DBG_DEBUG, "DeviceMainAreaSize: %d\n",
+ DeviceInfo.wDeviceMainAreaSize);
+ nand_dbg_print(NAND_DBG_DEBUG, "DeviceSpareAreaSize: %d\n",
+ DeviceInfo.wDeviceSpareAreaSize);
+ nand_dbg_print(NAND_DBG_DEBUG, "DevicesConnected: %d\n",
+ DeviceInfo.wDevicesConnected);
+ nand_dbg_print(NAND_DBG_DEBUG, "DeviceWidth: %d\n",
+ DeviceInfo.wDeviceWidth);
+ nand_dbg_print(NAND_DBG_DEBUG, "HWRevision: 0x%x\n",
+ DeviceInfo.wHWRevision);
+ nand_dbg_print(NAND_DBG_DEBUG, "HWFeatures: 0x%x\n",
+ DeviceInfo.wHWFeatures);
+ nand_dbg_print(NAND_DBG_DEBUG, "ONFIDevFeatures: 0x%x\n",
+ DeviceInfo.wONFIDevFeatures);
+ nand_dbg_print(NAND_DBG_DEBUG, "ONFIOptCommands: 0x%x\n",
+ DeviceInfo.wONFIOptCommands);
+ nand_dbg_print(NAND_DBG_DEBUG, "ONFITimingMode: 0x%x\n",
+ DeviceInfo.wONFITimingMode);
+ nand_dbg_print(NAND_DBG_DEBUG, "ONFIPgmCacheTimingMode: 0x%x\n",
+ DeviceInfo.wONFIPgmCacheTimingMode);
+ nand_dbg_print(NAND_DBG_DEBUG, "MLCDevice: %s\n",
+ DeviceInfo.MLCDevice ? "Yes" : "No");
+ nand_dbg_print(NAND_DBG_DEBUG, "SpareSkipBytes: %d\n",
+ DeviceInfo.wSpareSkipBytes);
+ nand_dbg_print(NAND_DBG_DEBUG, "BitsInPageNumber: %d\n",
+ DeviceInfo.nBitsInPageNumber);
+ nand_dbg_print(NAND_DBG_DEBUG, "BitsInPageDataSize: %d\n",
+ DeviceInfo.nBitsInPageDataSize);
+ nand_dbg_print(NAND_DBG_DEBUG, "BitsInBlockDataSize: %d\n",
+ DeviceInfo.nBitsInBlockDataSize);
+}
+
+u16 NAND_Read_Device_ID(void)
+{
+ u16 status = PASS;
+ u8 no_of_planes;
+
+ nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n",
+ __FILE__, __LINE__, __func__);
+
+ iowrite32(0x02, FlashReg + SPARE_AREA_SKIP_BYTES);
+ iowrite32(0xffff, FlashReg + SPARE_AREA_MARKER);
+ DeviceInfo.wDeviceMaker = ioread32(FlashReg + MANUFACTURER_ID);
+ DeviceInfo.wDeviceID = ioread32(FlashReg + DEVICE_ID);
+ DeviceInfo.MLCDevice = ioread32(FlashReg + DEVICE_PARAM_0) & 0x0c;
+
+ if (ioread32(FlashReg + ONFI_DEVICE_NO_OF_LUNS) &
+ ONFI_DEVICE_NO_OF_LUNS__ONFI_DEVICE) { /* ONFI 1.0 NAND */
+ if (FAIL == get_onfi_nand_para())
+ return FAIL;
+ } else if (DeviceInfo.wDeviceMaker == 0xEC) { /* Samsung NAND */
+ get_samsung_nand_para();
+ } else if (DeviceInfo.wDeviceMaker == 0x98) { /* Toshiba NAND */
+ get_toshiba_nand_para();
+ } else if (DeviceInfo.wDeviceMaker == 0xAD) { /* Hynix NAND */
+ get_hynix_nand_para();
+ } else {
+ DeviceInfo.wTotalBlocks = GLOB_HWCTL_DEFAULT_BLKS;
+ }
+
+ nand_dbg_print(NAND_DBG_DEBUG, "Dump timing register values:"
+ "acc_clks: %d, re_2_we: %d, we_2_re: %d,"
+ "addr_2_data: %d, rdwr_en_lo_cnt: %d, "
+ "rdwr_en_hi_cnt: %d, cs_setup_cnt: %d\n",
+ ioread32(FlashReg + ACC_CLKS),
+ ioread32(FlashReg + RE_2_WE),
+ ioread32(FlashReg + WE_2_RE),
+ ioread32(FlashReg + ADDR_2_DATA),
+ ioread32(FlashReg + RDWR_EN_LO_CNT),
+ ioread32(FlashReg + RDWR_EN_HI_CNT),
+ ioread32(FlashReg + CS_SETUP_CNT));
+
+ DeviceInfo.wHWRevision = ioread32(FlashReg + REVISION);
+ DeviceInfo.wHWFeatures = ioread32(FlashReg + FEATURES);
+
+ DeviceInfo.wDeviceMainAreaSize =
+ ioread32(FlashReg + DEVICE_MAIN_AREA_SIZE);
+ DeviceInfo.wDeviceSpareAreaSize =
+ ioread32(FlashReg + DEVICE_SPARE_AREA_SIZE);
+
+ DeviceInfo.wPageDataSize =
+ ioread32(FlashReg + LOGICAL_PAGE_DATA_SIZE);
+
+ /* Note: When using the Micon 4K NAND device, the controller will report
+ * Page Spare Size as 216 bytes. But Micron's Spec say it's 218 bytes.
+ * And if force set it to 218 bytes, the controller can not work
+ * correctly. So just let it be. But keep in mind that this bug may
+ * cause
+ * other problems in future. - Yunpeng 2008-10-10
+ */
+ DeviceInfo.wPageSpareSize =
+ ioread32(FlashReg + LOGICAL_PAGE_SPARE_SIZE);
+
+ DeviceInfo.wPagesPerBlock = ioread32(FlashReg + PAGES_PER_BLOCK);
+
+ DeviceInfo.wPageSize =
+ DeviceInfo.wPageDataSize + DeviceInfo.wPageSpareSize;
+ DeviceInfo.wBlockSize =
+ DeviceInfo.wPageSize * DeviceInfo.wPagesPerBlock;
+ DeviceInfo.wBlockDataSize =
+ DeviceInfo.wPagesPerBlock * DeviceInfo.wPageDataSize;
+
+ DeviceInfo.wDeviceWidth = ioread32(FlashReg + DEVICE_WIDTH);
+ DeviceInfo.wDeviceType =
+ ((ioread32(FlashReg + DEVICE_WIDTH) > 0) ? 16 : 8);
+
+ DeviceInfo.wDevicesConnected = ioread32(FlashReg + DEVICES_CONNECTED);
+
+ DeviceInfo.wSpareSkipBytes =
+ ioread32(FlashReg + SPARE_AREA_SKIP_BYTES) *
+ DeviceInfo.wDevicesConnected;
+
+ DeviceInfo.nBitsInPageNumber =
+ (u8)GLOB_Calc_Used_Bits(DeviceInfo.wPagesPerBlock);
+ DeviceInfo.nBitsInPageDataSize =
+ (u8)GLOB_Calc_Used_Bits(DeviceInfo.wPageDataSize);
+ DeviceInfo.nBitsInBlockDataSize =
+ (u8)GLOB_Calc_Used_Bits(DeviceInfo.wBlockDataSize);
+
+ set_ecc_config();
+
+ no_of_planes = ioread32(FlashReg + NUMBER_OF_PLANES) &
+ NUMBER_OF_PLANES__VALUE;
+
+ switch (no_of_planes) {
+ case 0:
+ case 1:
+ case 3:
+ case 7:
+ DeviceInfo.bPlaneNum = no_of_planes + 1;
+ break;
+ default:
+ status = FAIL;
+ break;
+ }
+
+ find_valid_banks();
+
+ detect_partition_feature();
+
+ dump_device_info();
+
+ return status;
+}
+
+u16 NAND_UnlockArrayAll(void)
+{
+ u64 start_addr, end_addr;
+
+ nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n",
+ __FILE__, __LINE__, __func__);
+
+ start_addr = 0;
+ end_addr = ((u64)DeviceInfo.wBlockSize *
+ (DeviceInfo.wTotalBlocks - 1)) >>
+ DeviceInfo.nBitsInPageDataSize;
+
+ index_addr((u32)(MODE_10 | (u32)start_addr), 0x10);
+ index_addr((u32)(MODE_10 | (u32)end_addr), 0x11);
+
+ return PASS;
+}
+
+void NAND_LLD_Enable_Disable_Interrupts(u16 INT_ENABLE)
+{
+ nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n",
+ __FILE__, __LINE__, __func__);
+
+ if (INT_ENABLE)
+ iowrite32(1, FlashReg + GLOBAL_INT_ENABLE);
+ else
+ iowrite32(0, FlashReg + GLOBAL_INT_ENABLE);
+}
+
+u16 NAND_Erase_Block(u32 block)
+{
+ u16 status = PASS;
+ u64 flash_add;
+ u16 flash_bank;
+ u32 intr_status = 0;
+ u32 intr_status_addresses[4] = {INTR_STATUS0,
+ INTR_STATUS1, INTR_STATUS2, INTR_STATUS3};
+
+ nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n",
+ __FILE__, __LINE__, __func__);
+
+ flash_add = (u64)(block % (DeviceInfo.wTotalBlocks / totalUsedBanks))
+ * DeviceInfo.wBlockDataSize;
+
+ flash_bank = block / (DeviceInfo.wTotalBlocks / totalUsedBanks);
+
+ if (block >= DeviceInfo.wTotalBlocks)
+ status = FAIL;
+
+ if (status == PASS) {
+ intr_status = intr_status_addresses[flash_bank];
+
+ iowrite32(INTR_STATUS0__ERASE_COMP | INTR_STATUS0__ERASE_FAIL,
+ FlashReg + intr_status);
+
+ index_addr((u32)(MODE_10 | (flash_bank << 24) |
+ (flash_add >> DeviceInfo.nBitsInPageDataSize)), 1);
+
+ while (!(ioread32(FlashReg + intr_status) &
+ (INTR_STATUS0__ERASE_COMP | INTR_STATUS0__ERASE_FAIL)))
+ ;
+
+ if (ioread32(FlashReg + intr_status) &
+ INTR_STATUS0__ERASE_FAIL)
+ status = FAIL;
+
+ iowrite32(INTR_STATUS0__ERASE_COMP | INTR_STATUS0__ERASE_FAIL,
+ FlashReg + intr_status);
+ }
+
+ return status;
+}
+
+static u32 Boundary_Check_Block_Page(u32 block, u16 page,
+ u16 page_count)
+{
+ u32 status = PASS;
+
+ if (block >= DeviceInfo.wTotalBlocks)
+ status = FAIL;
+
+ if (page + page_count > DeviceInfo.wPagesPerBlock)
+ status = FAIL;
+
+ return status;
+}
+
+u16 NAND_Read_Page_Spare(u8 *read_data, u32 block, u16 page,
+ u16 page_count)
+{
+ u32 status = PASS;
+ u32 i;
+ u64 flash_add;
+ u32 PageSpareSize = DeviceInfo.wPageSpareSize;
+ u32 spareFlagBytes = DeviceInfo.wNumPageSpareFlag;
+ u32 flash_bank;
+ u32 intr_status = 0;
+ u32 intr_status_addresses[4] = {INTR_STATUS0,
+ INTR_STATUS1, INTR_STATUS2, INTR_STATUS3};
+ u8 *page_spare = buf_read_page_spare;
+
+ if (block >= DeviceInfo.wTotalBlocks) {
+ printk(KERN_ERR "block too big: %d\n", (int)block);
+ status = FAIL;
+ }
+
+ if (page >= DeviceInfo.wPagesPerBlock) {
+ printk(KERN_ERR "page too big: %d\n", page);
+ status = FAIL;
+ }
+
+ if (page_count > 1) {
+ printk(KERN_ERR "page count too big: %d\n", page_count);
+ status = FAIL;
+ }
+
+ flash_add = (u64)(block % (DeviceInfo.wTotalBlocks / totalUsedBanks))
+ * DeviceInfo.wBlockDataSize +
+ (u64)page * DeviceInfo.wPageDataSize;
+
+ flash_bank = block / (DeviceInfo.wTotalBlocks / totalUsedBanks);
+
+ if (status == PASS) {
+ intr_status = intr_status_addresses[flash_bank];
+ iowrite32(ioread32(FlashReg + intr_status),
+ FlashReg + intr_status);
+
+ index_addr((u32)(MODE_10 | (flash_bank << 24) |
+ (flash_add >> DeviceInfo.nBitsInPageDataSize)),
+ 0x41);
+ index_addr((u32)(MODE_10 | (flash_bank << 24) |
+ (flash_add >> DeviceInfo.nBitsInPageDataSize)),
+ 0x2000 | page_count);
+ while (!(ioread32(FlashReg + intr_status) &
+ INTR_STATUS0__LOAD_COMP))
+ ;
+
+ iowrite32((u32)(MODE_01 | (flash_bank << 24) |
+ (flash_add >> DeviceInfo.nBitsInPageDataSize)),
+ FlashMem);
+
+ for (i = 0; i < (PageSpareSize / 4); i++)
+ *((u32 *)page_spare + i) =
+ ioread32(FlashMem + 0x10);
+
+ if (enable_ecc) {
+ for (i = 0; i < spareFlagBytes; i++)
+ read_data[i] =
+ page_spare[PageSpareSize -
+ spareFlagBytes + i];
+ for (i = 0; i < (PageSpareSize - spareFlagBytes); i++)
+ read_data[spareFlagBytes + i] =
+ page_spare[i];
+ } else {
+ for (i = 0; i < PageSpareSize; i++)
+ read_data[i] = page_spare[i];
+ }
+
+ index_addr((u32)(MODE_10 | (flash_bank << 24) |
+ (flash_add >> DeviceInfo.nBitsInPageDataSize)), 0x42);
+ }
+
+ return status;
+}
+
+/* No use function. Should be removed later */
+u16 NAND_Write_Page_Spare(u8 *write_data, u32 block, u16 page,
+ u16 page_count)
+{
+ printk(KERN_ERR
+ "Error! This function (NAND_Write_Page_Spare) should never"
+ " be called!\n");
+ return ERR;
+}
+
+/* op value: 0 - DDMA read; 1 - DDMA write */
+static void ddma_trans(u8 *data, u64 flash_add,
+ u32 flash_bank, int op, u32 numPages)
+{
+ u32 data_addr;
+
+ /* Map virtual address to bus address for DDMA */
+ data_addr = virt_to_bus(data);
+
+ index_addr((u32)(MODE_10 | (flash_bank << 24) |
+ (flash_add >> DeviceInfo.nBitsInPageDataSize)),
+ (u16)(2 << 12) | (op << 8) | numPages);
+
+ index_addr((u32)(MODE_10 | (flash_bank << 24) |
+ ((u16)(0x0FFFF & (data_addr >> 16)) << 8)),
+ (u16)(2 << 12) | (2 << 8) | 0);
+
+ index_addr((u32)(MODE_10 | (flash_bank << 24) |
+ ((u16)(0x0FFFF & data_addr) << 8)),
+ (u16)(2 << 12) | (3 << 8) | 0);
+
+ index_addr((u32)(MODE_10 | (flash_bank << 24) |
+ (1 << 16) | (0x40 << 8)),
+ (u16)(2 << 12) | (4 << 8) | 0);
+}
+
+/* If data in buf are all 0xff, then return 1; otherwise return 0 */
+static int check_all_1(u8 *buf)
+{
+ int i, j, cnt;
+
+ for (i = 0; i < DeviceInfo.wPageDataSize; i++) {
+ if (buf[i] != 0xff) {
+ cnt = 0;
+ nand_dbg_print(NAND_DBG_WARN,
+ "the first non-0xff data byte is: %d\n", i);
+ for (j = i; j < DeviceInfo.wPageDataSize; j++) {
+ nand_dbg_print(NAND_DBG_WARN, "0x%x ", buf[j]);
+ cnt++;
+ if (cnt > 8)
+ break;
+ }
+ nand_dbg_print(NAND_DBG_WARN, "\n");
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+static int do_ecc_new(unsigned long bank, u8 *buf,
+ u32 block, u16 page)
+{
+ int status = PASS;
+ u16 err_page = 0;
+ u16 err_byte;
+ u8 err_sect;
+ u8 err_dev;
+ u16 err_fix_info;
+ u16 err_addr;
+ u32 ecc_sect_size;
+ u8 *err_pos;
+ u32 err_page_addr[4] = {ERR_PAGE_ADDR0,
+ ERR_PAGE_ADDR1, ERR_PAGE_ADDR2, ERR_PAGE_ADDR3};
+
+ ecc_sect_size = ECC_SECTOR_SIZE * (DeviceInfo.wDevicesConnected);
+
+ do {
+ err_page = ioread32(FlashReg + err_page_addr[bank]);
+ err_addr = ioread32(FlashReg + ECC_ERROR_ADDRESS);
+ err_byte = err_addr & ECC_ERROR_ADDRESS__OFFSET;
+ err_sect = ((err_addr & ECC_ERROR_ADDRESS__SECTOR_NR) >> 12);
+ err_fix_info = ioread32(FlashReg + ERR_CORRECTION_INFO);
+ err_dev = ((err_fix_info & ERR_CORRECTION_INFO__DEVICE_NR)
+ >> 8);
+ if (err_fix_info & ERR_CORRECTION_INFO__ERROR_TYPE) {
+ nand_dbg_print(NAND_DBG_WARN,
+ "%s, Line %d Uncorrectable ECC error "
+ "when read block %d page %d."
+ "PTN_INTR register: 0x%x "
+ "err_page: %d, err_sect: %d, err_byte: %d, "
+ "err_dev: %d, ecc_sect_size: %d, "
+ "err_fix_info: 0x%x\n",
+ __FILE__, __LINE__, block, page,
+ ioread32(FlashReg + PTN_INTR),
+ err_page, err_sect, err_byte, err_dev,
+ ecc_sect_size, (u32)err_fix_info);
+
+ if (check_all_1(buf))
+ nand_dbg_print(NAND_DBG_WARN, "%s, Line %d"
+ "All 0xff!\n",
+ __FILE__, __LINE__);
+ else
+ nand_dbg_print(NAND_DBG_WARN, "%s, Line %d"
+ "Not all 0xff!\n",
+ __FILE__, __LINE__);
+ status = FAIL;
+ } else {
+ nand_dbg_print(NAND_DBG_WARN,
+ "%s, Line %d Found ECC error "
+ "when read block %d page %d."
+ "err_page: %d, err_sect: %d, err_byte: %d, "
+ "err_dev: %d, ecc_sect_size: %d, "
+ "err_fix_info: 0x%x\n",
+ __FILE__, __LINE__, block, page,
+ err_page, err_sect, err_byte, err_dev,
+ ecc_sect_size, (u32)err_fix_info);
+ if (err_byte < ECC_SECTOR_SIZE) {
+ err_pos = buf +
+ (err_page - page) *
+ DeviceInfo.wPageDataSize +
+ err_sect * ecc_sect_size +
+ err_byte *
+ DeviceInfo.wDevicesConnected +
+ err_dev;
+
+ *err_pos ^= err_fix_info &
+ ERR_CORRECTION_INFO__BYTEMASK;
+ }
+ }
+ } while (!(err_fix_info & ERR_CORRECTION_INFO__LAST_ERR_INFO));
+
+ return status;
+}
+
+u16 NAND_Read_Page_Main_Polling(u8 *read_data,
+ u32 block, u16 page, u16 page_count)
+{
+ u32 status = PASS;
+ u64 flash_add;
+ u32 intr_status = 0;
+ u32 flash_bank;
+ u32 intr_status_addresses[4] = {INTR_STATUS0,
+ INTR_STATUS1, INTR_STATUS2, INTR_STATUS3};
+ u8 *read_data_l;
+
+ nand_dbg_print(NAND_DBG_WARN, "%s, Line %d, Function: %s\n",
+ __FILE__, __LINE__, __func__);
+
+ status = Boundary_Check_Block_Page(block, page, page_count);
+ if (status != PASS)
+ return status;
+
+ flash_add = (u64)(block % (DeviceInfo.wTotalBlocks / totalUsedBanks))
+ * DeviceInfo.wBlockDataSize +
+ (u64)page * DeviceInfo.wPageDataSize;
+ flash_bank = block / (DeviceInfo.wTotalBlocks / totalUsedBanks);
+
+ iowrite32(0, FlashReg + TRANSFER_SPARE_REG);
+
+ intr_status = intr_status_addresses[flash_bank];
+ iowrite32(ioread32(FlashReg + intr_status), FlashReg + intr_status);
+
+ if (page_count > 1) {
+ read_data_l = read_data;
+ while (page_count > MAX_PAGES_PER_RW) {
+ if (ioread32(FlashReg + MULTIPLANE_OPERATION))
+ status = NAND_Multiplane_Read(read_data_l,
+ block, page, MAX_PAGES_PER_RW);
+ else
+ status = NAND_Pipeline_Read_Ahead_Polling(
+ read_data_l, block, page,
+ MAX_PAGES_PER_RW);
+
+ if (status == FAIL)
+ return status;
+
+ read_data_l += DeviceInfo.wPageDataSize *
+ MAX_PAGES_PER_RW;
+ page_count -= MAX_PAGES_PER_RW;
+ page += MAX_PAGES_PER_RW;
+ }
+ if (ioread32(FlashReg + MULTIPLANE_OPERATION))
+ status = NAND_Multiplane_Read(read_data_l,
+ block, page, page_count);
+ else
+ status = NAND_Pipeline_Read_Ahead_Polling(
+ read_data_l, block, page, page_count);
+
+ return status;
+ }
+
+ iowrite32(1, FlashReg + DMA_ENABLE);
+ while (!(ioread32(FlashReg + DMA_ENABLE) & DMA_ENABLE__FLAG))
+ ;
+
+ iowrite32(0, FlashReg + TRANSFER_SPARE_REG);
+ iowrite32(ioread32(FlashReg + intr_status), FlashReg + intr_status);
+
+ ddma_trans(read_data, flash_add, flash_bank, 0, 1);
+
+ if (enable_ecc) {
+ while (!(ioread32(FlashReg + intr_status) &
+ (INTR_STATUS0__ECC_TRANSACTION_DONE |
+ INTR_STATUS0__ECC_ERR)))
+ ;
+
+ if (ioread32(FlashReg + intr_status) &
+ INTR_STATUS0__ECC_ERR) {
+ iowrite32(INTR_STATUS0__ECC_ERR,
+ FlashReg + intr_status);
+ status = do_ecc_new(flash_bank, read_data,
+ block, page);
+ }
+
+ if (ioread32(FlashReg + intr_status) &
+ INTR_STATUS0__ECC_TRANSACTION_DONE &
+ INTR_STATUS0__ECC_ERR)
+ iowrite32(INTR_STATUS0__ECC_TRANSACTION_DONE |
+ INTR_STATUS0__ECC_ERR,
+ FlashReg + intr_status);
+ else if (ioread32(FlashReg + intr_status) &
+ INTR_STATUS0__ECC_TRANSACTION_DONE)
+ iowrite32(INTR_STATUS0__ECC_TRANSACTION_DONE,
+ FlashReg + intr_status);
+ else if (ioread32(FlashReg + intr_status) &
+ INTR_STATUS0__ECC_ERR)
+ iowrite32(INTR_STATUS0__ECC_ERR,
+ FlashReg + intr_status);
+ } else {
+ while (!(ioread32(FlashReg + intr_status) &
+ INTR_STATUS0__DMA_CMD_COMP))
+ ;
+ iowrite32(INTR_STATUS0__DMA_CMD_COMP, FlashReg + intr_status);
+ }
+
+ iowrite32(ioread32(FlashReg + intr_status), FlashReg + intr_status);
+
+ iowrite32(0, FlashReg + DMA_ENABLE);
+ while ((ioread32(FlashReg + DMA_ENABLE) & DMA_ENABLE__FLAG))
+ ;
+
+ return status;
+}
+
+u16 NAND_Pipeline_Read_Ahead_Polling(u8 *read_data,
+ u32 block, u16 page, u16 page_count)
+{
+ u32 status = PASS;
+ u32 NumPages = page_count;
+ u64 flash_add;
+ u32 flash_bank;
+ u32 intr_status = 0;
+ u32 intr_status_addresses[4] = {INTR_STATUS0,
+ INTR_STATUS1, INTR_STATUS2, INTR_STATUS3};
+ u32 ecc_done_OR_dma_comp;
+
+ nand_dbg_print(NAND_DBG_WARN, "%s, Line %d, Function: %s\n",
+ __FILE__, __LINE__, __func__);
+
+ status = Boundary_Check_Block_Page(block, page, page_count);
+
+ if (page_count < 2)
+ status = FAIL;
+
+ flash_add = (u64)(block % (DeviceInfo.wTotalBlocks / totalUsedBanks))
+ *DeviceInfo.wBlockDataSize +
+ (u64)page * DeviceInfo.wPageDataSize;
+
+ flash_bank = block / (DeviceInfo.wTotalBlocks / totalUsedBanks);
+
+ if (status == PASS) {
+ intr_status = intr_status_addresses[flash_bank];
+ iowrite32(ioread32(FlashReg + intr_status),
+ FlashReg + intr_status);
+
+ iowrite32(1, FlashReg + DMA_ENABLE);
+ while (!(ioread32(FlashReg + DMA_ENABLE) & DMA_ENABLE__FLAG))
+ ;
+
+ iowrite32(0, FlashReg + TRANSFER_SPARE_REG);
+
+ index_addr((u32)(MODE_10 | (flash_bank << 24) |
+ (flash_add >> DeviceInfo.nBitsInPageDataSize)), 0x42);
+ ddma_trans(read_data, flash_add, flash_bank, 0, NumPages);
+
+ ecc_done_OR_dma_comp = 0;
+ while (1) {
+ if (enable_ecc) {
+ while (!ioread32(FlashReg + intr_status))
+ ;
+
+ if (ioread32(FlashReg + intr_status) &
+ INTR_STATUS0__ECC_ERR) {
+ iowrite32(INTR_STATUS0__ECC_ERR,
+ FlashReg + intr_status);
+ status = do_ecc_new(flash_bank,
+ read_data, block, page);
+ } else if (ioread32(FlashReg + intr_status) &
+ INTR_STATUS0__DMA_CMD_COMP) {
+ iowrite32(INTR_STATUS0__DMA_CMD_COMP,
+ FlashReg + intr_status);
+
+ if (1 == ecc_done_OR_dma_comp)
+ break;
+
+ ecc_done_OR_dma_comp = 1;
+ } else if (ioread32(FlashReg + intr_status) &
+ INTR_STATUS0__ECC_TRANSACTION_DONE) {
+ iowrite32(
+ INTR_STATUS0__ECC_TRANSACTION_DONE,
+ FlashReg + intr_status);
+
+ if (1 == ecc_done_OR_dma_comp)
+ break;
+
+ ecc_done_OR_dma_comp = 1;
+ }
+ } else {
+ while (!(ioread32(FlashReg + intr_status) &
+ INTR_STATUS0__DMA_CMD_COMP))
+ ;
+
+ iowrite32(INTR_STATUS0__DMA_CMD_COMP,
+ FlashReg + intr_status);
+ break;
+ }
+
+ iowrite32((~INTR_STATUS0__ECC_ERR) &
+ (~INTR_STATUS0__ECC_TRANSACTION_DONE) &
+ (~INTR_STATUS0__DMA_CMD_COMP),
+ FlashReg + intr_status);
+
+ }
+
+ iowrite32(ioread32(FlashReg + intr_status),
+ FlashReg + intr_status);
+
+ iowrite32(0, FlashReg + DMA_ENABLE);
+
+ while ((ioread32(FlashReg + DMA_ENABLE) & DMA_ENABLE__FLAG))
+ ;
+ }
+ return status;
+}
+
+u16 NAND_Read_Page_Main(u8 *read_data, u32 block, u16 page,
+ u16 page_count)
+{
+ u32 status = PASS;
+ u64 flash_add;
+ u32 intr_status = 0;
+ u32 flash_bank;
+ u32 intr_status_addresses[4] = {INTR_STATUS0,
+ INTR_STATUS1, INTR_STATUS2, INTR_STATUS3};
+ int ret;
+ u8 *read_data_l;
+
+ nand_dbg_print(NAND_DBG_DEBUG, "%s, Line %d, Function: %s\n",
+ __FILE__, __LINE__, __func__);
+
+ status = Boundary_Check_Block_Page(block, page, page_count);
+ if (status != PASS)
+ return status;
+
+ flash_add = (u64)(block % (DeviceInfo.wTotalBlocks / totalUsedBanks))
+ * DeviceInfo.wBlockDataSize +
+ (u64)page * DeviceInfo.wPageDataSize;
+ flash_bank = block / (DeviceInfo.wTotalBlocks / totalUsedBanks);
+
+ iowrite32(0, FlashReg + TRANSFER_SPARE_REG);
+
+ intr_status = intr_status_addresses[flash_bank];
+ iowrite32(ioread32(FlashReg + intr_status), FlashReg + intr_status);
+
+ if (page_count > 1) {
+ read_data_l = read_data;
+ while (page_count > MAX_PAGES_PER_RW) {
+ if (ioread32(FlashReg + MULTIPLANE_OPERATION))
+ status = NAND_Multiplane_Read(read_data_l,
+ block, page, MAX_PAGES_PER_RW);
+ else
+ status = NAND_Pipeline_Read_Ahead(
+ read_data_l, block, page,
+ MAX_PAGES_PER_RW);
+
+ if (status == FAIL)
+ return status;
+
+ read_data_l += DeviceInfo.wPageDataSize *
+ MAX_PAGES_PER_RW;
+ page_count -= MAX_PAGES_PER_RW;
+ page += MAX_PAGES_PER_RW;
+ }
+ if (ioread32(FlashReg + MULTIPLANE_OPERATION))
+ status = NAND_Multiplane_Read(read_data_l,
+ block, page, page_count);
+ else
+ status = NAND_Pipeline_Read_Ahead(
+ read_data_l, block, page, page_count);
+
+ return status;
+ }
+
+ iowrite32(1, FlashReg + DMA_ENABLE);
+ while (!(ioread32(FlashReg + DMA_ENABLE) & DMA_ENABLE__FLAG))
+ ;
+
+ iowrite32(0, FlashReg + TRANSFER_SPARE_REG);
+ iowrite32(ioread32(FlashReg + intr_status), FlashReg + intr_status);
+
+ /* Fill the mrst_nand_info structure */
+ info.state = INT_READ_PAGE_MAIN;
+ info.read_data = read_data;
+ info.flash_bank = flash_bank;
+ info.block = block;
+ info.page = page;
+ info.ret = PASS;
+
+ ddma_trans(read_data, flash_add, flash_bank, 0, 1);
+
+ iowrite32(1, FlashReg + GLOBAL_INT_ENABLE); /* Enable Interrupt */
+
+ ret = wait_for_completion_timeout(&info.complete, 10 * HZ);
+ if (!ret) {
+ printk(KERN_ERR "Wait for completion timeout "
+ "in %s, Line %d\n", __FILE__, __LINE__);
+ status = ERR;
+ } else {
+ status = info.ret;
+ }
+
+ iowrite32(ioread32(FlashReg + intr_status), FlashReg + intr_status);
+
+ iowrite32(0, FlashReg + DMA_ENABLE);
+ while ((ioread32(FlashReg + DMA_ENABLE) & DMA_ENABLE__FLAG))
+ ;
+
+ return status;
+}
+
+void Conv_Spare_Data_Log2Phy_Format(u8 *data)
+{
+ int i;
+ const u32 spareFlagBytes = DeviceInfo.wNumPageSpareFlag;
+ const u32 PageSpareSize = DeviceInfo.wPageSpareSize;
+
+ if (enable_ecc) {
+ for (i = spareFlagBytes - 1; i >= 0; i++)
+ data[PageSpareSize - spareFlagBytes + i] = data[i];
+ }
+}
+
+void Conv_Spare_Data_Phy2Log_Format(u8 *data)
+{
+ int i;
+ const u32 spareFlagBytes = DeviceInfo.wNumPageSpareFlag;
+ const u32 PageSpareSize = DeviceInfo.wPageSpareSize;
+
+ if (enable_ecc) {
+ for (i = 0; i < spareFlagBytes; i++)
+ data[i] = data[PageSpareSize - spareFlagBytes + i];
+ }
+}
+
+
+void Conv_Main_Spare_Data_Log2Phy_Format(u8 *data, u16 page_count)
+{
+ const u32 PageSize = DeviceInfo.wPageSize;
+ const u32 PageDataSize = DeviceInfo.wPageDataSize;
+ const u32 eccBytes = DeviceInfo.wECCBytesPerSector;
+ const u32 spareSkipBytes = DeviceInfo.wSpareSkipBytes;
+ const u32 spareFlagBytes = DeviceInfo.wNumPageSpareFlag;
+ u32 eccSectorSize;
+ u32 page_offset;
+ int i, j;
+
+ eccSectorSize = ECC_SECTOR_SIZE * (DeviceInfo.wDevicesConnected);
+ if (enable_ecc) {
+ while (page_count > 0) {
+ page_offset = (page_count - 1) * PageSize;
+ j = (DeviceInfo.wPageDataSize / eccSectorSize);
+ for (i = spareFlagBytes - 1; i >= 0; i--)
+ data[page_offset +
+ (eccSectorSize + eccBytes) * j + i] =
+ data[page_offset + PageDataSize + i];
+ for (j--; j >= 1; j--) {
+ for (i = eccSectorSize - 1; i >= 0; i--)
+ data[page_offset +
+ (eccSectorSize + eccBytes) * j + i] =
+ data[page_offset +
+ eccSectorSize * j + i];
+ }
+ for (i = (PageSize - spareSkipBytes) - 1;
+ i >= PageDataSize; i--)
+ data[page_offset + i + spareSkipBytes] =
+ data[page_offset + i];
+ page_count--;
+ }
+ }
+}
+
+void Conv_Main_Spare_Data_Phy2Log_Format(u8 *data, u16 page_count)
+{
+ const u32 PageSize = DeviceInfo.wPageSize;
+ const u32 PageDataSize = DeviceInfo.wPageDataSize;
+ const u32 eccBytes = DeviceInfo.wECCBytesPerSector;
+ const u32 spareSkipBytes = DeviceInfo.wSpareSkipBytes;
+ const u32 spareFlagBytes = DeviceInfo.wNumPageSpareFlag;
+ u32 eccSectorSize;
+ u32 page_offset;
+ int i, j;
+
+ eccSectorSize = ECC_SECTOR_SIZE * (DeviceInfo.wDevicesConnected);
+ if (enable_ecc) {
+ while (page_count > 0) {
+ page_offset = (page_count - 1) * PageSize;
+ for (i = PageDataSize;
+ i < PageSize - spareSkipBytes;
+ i++)
+ data[page_offset + i] =
+ data[page_offset + i +
+ spareSkipBytes];
+ for (j = 1;
+ j < DeviceInfo.wPageDataSize / eccSectorSize;
+ j++) {
+ for (i = 0; i < eccSectorSize; i++)
+ data[page_offset +
+ eccSectorSize * j + i] =
+ data[page_offset +
+ (eccSectorSize + eccBytes) * j
+ + i];
+ }
+ for (i = 0; i < spareFlagBytes; i++)
+ data[page_offset + PageDataSize + i] =
+ data[page_offset +
+ (eccSectorSize + eccBytes) * j + i];
+ page_count--;
+ }
+ }
+}
+
+/* Un-tested function */
+u16 NAND_Multiplane_Read(u8 *read_data, u32 block, u16 page,
+ u16 page_count)
+{
+ u32 status = PASS;
+ u32 NumPages = page_count;
+ u64 flash_add;
+ u32 flash_bank;
+ u32 intr_status = 0;
+ u32 intr_status_addresses[4] = {INTR_STATUS0,
+ INTR_STATUS1, INTR_STATUS2, INTR_STATUS3};
+ u32 ecc_done_OR_dma_comp;
+
+ nand_dbg_print(NAND_DBG_WARN, "%s, Line %d, Function: %s\n",
+ __FILE__, __LINE__, __func__);
+
+ status = Boundary_Check_Block_Page(block, page, page_count);
+
+ flash_add = (u64)(block % (DeviceInfo.wTotalBlocks / totalUsedBanks))
+ * DeviceInfo.wBlockDataSize +
+ (u64)page * DeviceInfo.wPageDataSize;
+
+ flash_bank = block / (DeviceInfo.wTotalBlocks / totalUsedBanks);
+
+ if (status == PASS) {
+ intr_status = intr_status_addresses[flash_bank];
+ iowrite32(ioread32(FlashReg + intr_status),
+ FlashReg + intr_status);
+
+ iowrite32(0, FlashReg + TRANSFER_SPARE_REG);
+ iowrite32(0x01, FlashReg + MULTIPLANE_OPERATION);
+
+ iowrite32(1, FlashReg + DMA_ENABLE);
+ while (!(ioread32(FlashReg + DMA_ENABLE) & DMA_ENABLE__FLAG))
+ ;
+ index_addr((u32)(MODE_10 | (flash_bank << 24) |
+ (flash_add >> DeviceInfo.nBitsInPageDataSize)), 0x42);
+ ddma_trans(read_data, flash_add, flash_bank, 0, NumPages);
+
+ ecc_done_OR_dma_comp = 0;
+ while (1) {
+ if (enable_ecc) {
+ while (!ioread32(FlashReg + intr_status))
+ ;
+
+ if (ioread32(FlashReg + intr_status) &
+ INTR_STATUS0__ECC_ERR) {
+ iowrite32(INTR_STATUS0__ECC_ERR,
+ FlashReg + intr_status);
+ status = do_ecc_new(flash_bank,
+ read_data, block, page);
+ } else if (ioread32(FlashReg + intr_status) &
+ INTR_STATUS0__DMA_CMD_COMP) {
+ iowrite32(INTR_STATUS0__DMA_CMD_COMP,
+ FlashReg + intr_status);
+
+ if (1 == ecc_done_OR_dma_comp)
+ break;
+
+ ecc_done_OR_dma_comp = 1;
+ } else if (ioread32(FlashReg + intr_status) &
+ INTR_STATUS0__ECC_TRANSACTION_DONE) {
+ iowrite32(
+ INTR_STATUS0__ECC_TRANSACTION_DONE,
+ FlashReg + intr_status);
+
+ if (1 == ecc_done_OR_dma_comp)
+ break;
+
+ ecc_done_OR_dma_comp = 1;
+ }
+ } else {
+ while (!(ioread32(FlashReg + intr_status) &
+ INTR_STATUS0__DMA_CMD_COMP))
+ ;
+ iowrite32(INTR_STATUS0__DMA_CMD_COMP,
+ FlashReg + intr_status);
+ break;
+ }
+
+ iowrite32((~INTR_STATUS0__ECC_ERR) &
+ (~INTR_STATUS0__ECC_TRANSACTION_DONE) &
+ (~INTR_STATUS0__DMA_CMD_COMP),
+ FlashReg + intr_status);
+
+ }
+
+ iowrite32(ioread32(FlashReg + intr_status),
+ FlashReg + intr_status);
+
+ iowrite32(0, FlashReg + DMA_ENABLE);
+
+ while ((ioread32(FlashReg + DMA_ENABLE) & DMA_ENABLE__FLAG))
+ ;
+
+ iowrite32(0, FlashReg + MULTIPLANE_OPERATION);
+ }
+
+ return status;
+}
+
+u16 NAND_Pipeline_Read_Ahead(u8 *read_data, u32 block,
+ u16 page, u16 page_count)
+{
+ u32 status = PASS;
+ u32 NumPages = page_count;
+ u64 flash_add;
+ u32 flash_bank;
+ u32 intr_status = 0;
+ u32 intr_status_addresses[4] = {INTR_STATUS0,
+ INTR_STATUS1, INTR_STATUS2, INTR_STATUS3};
+ int ret;
+
+ nand_dbg_print(NAND_DBG_DEBUG, "%s, Line %d, Function: %s\n",
+ __FILE__, __LINE__, __func__);
+
+ status = Boundary_Check_Block_Page(block, page, page_count);
+
+ if (page_count < 2)
+ status = FAIL;
+
+ if (status != PASS)
+ return status;
+
+ flash_add = (u64)(block % (DeviceInfo.wTotalBlocks / totalUsedBanks))
+ *DeviceInfo.wBlockDataSize +
+ (u64)page * DeviceInfo.wPageDataSize;
+
+ flash_bank = block / (DeviceInfo.wTotalBlocks / totalUsedBanks);
+
+ intr_status = intr_status_addresses[flash_bank];
+ iowrite32(ioread32(FlashReg + intr_status), FlashReg + intr_status);
+
+ iowrite32(1, FlashReg + DMA_ENABLE);
+ while (!(ioread32(FlashReg + DMA_ENABLE) & DMA_ENABLE__FLAG))
+ ;
+
+ iowrite32(0, FlashReg + TRANSFER_SPARE_REG);
+
+ /* Fill the mrst_nand_info structure */
+ info.state = INT_PIPELINE_READ_AHEAD;
+ info.read_data = read_data;
+ info.flash_bank = flash_bank;
+ info.block = block;
+ info.page = page;
+ info.ret = PASS;
+
+ index_addr((u32)(MODE_10 | (flash_bank << 24) |
+ (flash_add >> DeviceInfo.nBitsInPageDataSize)), 0x42);
+
+ ddma_trans(read_data, flash_add, flash_bank, 0, NumPages);
+
+ iowrite32(1, FlashReg + GLOBAL_INT_ENABLE); /* Enable Interrupt */
+
+ ret = wait_for_completion_timeout(&info.complete, 10 * HZ);
+ if (!ret) {
+ printk(KERN_ERR "Wait for completion timeout "
+ "in %s, Line %d\n", __FILE__, __LINE__);
+ status = ERR;
+ } else {
+ status = info.ret;
+ }
+
+ iowrite32(ioread32(FlashReg + intr_status), FlashReg + intr_status);
+
+ iowrite32(0, FlashReg + DMA_ENABLE);
+
+ while ((ioread32(FlashReg + DMA_ENABLE) & DMA_ENABLE__FLAG))
+ ;
+
+ return status;
+}
+
+
+u16 NAND_Write_Page_Main(u8 *write_data, u32 block, u16 page,
+ u16 page_count)
+{
+ u32 status = PASS;
+ u64 flash_add;
+ u32 intr_status = 0;
+ u32 flash_bank;
+ u32 intr_status_addresses[4] = {INTR_STATUS0,
+ INTR_STATUS1, INTR_STATUS2, INTR_STATUS3};
+ int ret;
+ u8 *write_data_l;
+
+ nand_dbg_print(NAND_DBG_DEBUG, "%s, Line %d, Function: %s\n",
+ __FILE__, __LINE__, __func__);
+
+ status = Boundary_Check_Block_Page(block, page, page_count);
+ if (status != PASS)
+ return status;
+
+ flash_add = (u64)(block % (DeviceInfo.wTotalBlocks / totalUsedBanks))
+ * DeviceInfo.wBlockDataSize +
+ (u64)page * DeviceInfo.wPageDataSize;
+
+ flash_bank = block / (DeviceInfo.wTotalBlocks / totalUsedBanks);
+
+ intr_status = intr_status_addresses[flash_bank];
+
+ iowrite32(0, FlashReg + TRANSFER_SPARE_REG);
+
+ iowrite32(INTR_STATUS0__PROGRAM_COMP |
+ INTR_STATUS0__PROGRAM_FAIL, FlashReg + intr_status);
+
+ if (page_count > 1) {
+ write_data_l = write_data;
+ while (page_count > MAX_PAGES_PER_RW) {
+ if (ioread32(FlashReg + MULTIPLANE_OPERATION))
+ status = NAND_Multiplane_Write(write_data_l,
+ block, page, MAX_PAGES_PER_RW);
+ else
+ status = NAND_Pipeline_Write_Ahead(
+ write_data_l, block, page,
+ MAX_PAGES_PER_RW);
+ if (status == FAIL)
+ return status;
+
+ write_data_l += DeviceInfo.wPageDataSize *
+ MAX_PAGES_PER_RW;
+ page_count -= MAX_PAGES_PER_RW;
+ page += MAX_PAGES_PER_RW;
+ }
+ if (ioread32(FlashReg + MULTIPLANE_OPERATION))
+ status = NAND_Multiplane_Write(write_data_l,
+ block, page, page_count);
+ else
+ status = NAND_Pipeline_Write_Ahead(write_data_l,
+ block, page, page_count);
+
+ return status;
+ }
+
+ iowrite32(1, FlashReg + DMA_ENABLE);
+ while (!(ioread32(FlashReg + DMA_ENABLE) & DMA_ENABLE__FLAG))
+ ;
+
+ iowrite32(0, FlashReg + TRANSFER_SPARE_REG);
+
+ iowrite32(ioread32(FlashReg + intr_status), FlashReg + intr_status);
+
+ /* Fill the mrst_nand_info structure */
+ info.state = INT_WRITE_PAGE_MAIN;
+ info.write_data = write_data;
+ info.flash_bank = flash_bank;
+ info.block = block;
+ info.page = page;
+ info.ret = PASS;
+
+ ddma_trans(write_data, flash_add, flash_bank, 1, 1);
+
+ iowrite32(1, FlashReg + GLOBAL_INT_ENABLE); /* Enable interrupt */
+
+ ret = wait_for_completion_timeout(&info.complete, 10 * HZ);
+ if (!ret) {
+ printk(KERN_ERR "Wait for completion timeout "
+ "in %s, Line %d\n", __FILE__, __LINE__);
+ status = ERR;
+ } else {
+ status = info.ret;
+ }
+
+ iowrite32(ioread32(FlashReg + intr_status), FlashReg + intr_status);
+
+ iowrite32(0, FlashReg + DMA_ENABLE);
+ while (ioread32(FlashReg + DMA_ENABLE) & DMA_ENABLE__FLAG)
+ ;
+
+ return status;
+}
+
+void NAND_ECC_Ctrl(int enable)
+{
+ if (enable) {
+ nand_dbg_print(NAND_DBG_WARN,
+ "Will enable ECC in %s, Line %d, Function: %s\n",
+ __FILE__, __LINE__, __func__);
+ iowrite32(1, FlashReg + ECC_ENABLE);
+ enable_ecc = 1;
+ } else {
+ nand_dbg_print(NAND_DBG_WARN,
+ "Will disable ECC in %s, Line %d, Function: %s\n",
+ __FILE__, __LINE__, __func__);
+ iowrite32(0, FlashReg + ECC_ENABLE);
+ enable_ecc = 0;
+ }
+}
+
+u16 NAND_Write_Page_Main_Spare(u8 *write_data, u32 block,
+ u16 page, u16 page_count)
+{
+ u32 status = PASS;
+ u32 i, j, page_num = 0;
+ u32 PageSize = DeviceInfo.wPageSize;
+ u32 PageDataSize = DeviceInfo.wPageDataSize;
+ u32 eccBytes = DeviceInfo.wECCBytesPerSector;
+ u32 spareFlagBytes = DeviceInfo.wNumPageSpareFlag;
+ u32 spareSkipBytes = DeviceInfo.wSpareSkipBytes;
+ u64 flash_add;
+ u32 eccSectorSize;
+ u32 flash_bank;
+ u32 intr_status = 0;
+ u32 intr_status_addresses[4] = {INTR_STATUS0,
+ INTR_STATUS1, INTR_STATUS2, INTR_STATUS3};
+ u8 *page_main_spare = buf_write_page_main_spare;
+
+ nand_dbg_print(NAND_DBG_WARN, "%s, Line %d, Function: %s\n",
+ __FILE__, __LINE__, __func__);
+
+ eccSectorSize = ECC_SECTOR_SIZE * (DeviceInfo.wDevicesConnected);
+
+ status = Boundary_Check_Block_Page(block, page, page_count);
+
+ flash_bank = block / (DeviceInfo.wTotalBlocks / totalUsedBanks);
+
+ if (status == PASS) {
+ intr_status = intr_status_addresses[flash_bank];
+
+ iowrite32(1, FlashReg + TRANSFER_SPARE_REG);
+
+ while ((status != FAIL) && (page_count > 0)) {
+ flash_add = (u64)(block %
+ (DeviceInfo.wTotalBlocks / totalUsedBanks)) *
+ DeviceInfo.wBlockDataSize +
+ (u64)page * DeviceInfo.wPageDataSize;
+
+ iowrite32(ioread32(FlashReg + intr_status),
+ FlashReg + intr_status);
+
+ iowrite32((u32)(MODE_01 | (flash_bank << 24) |
+ (flash_add >>
+ DeviceInfo.nBitsInPageDataSize)),
+ FlashMem);
+
+ if (enable_ecc) {
+ for (j = 0;
+ j <
+ DeviceInfo.wPageDataSize / eccSectorSize;
+ j++) {
+ for (i = 0; i < eccSectorSize; i++)
+ page_main_spare[(eccSectorSize +
+ eccBytes) * j +
+ i] =
+ write_data[eccSectorSize *
+ j + i];
+
+ for (i = 0; i < eccBytes; i++)
+ page_main_spare[(eccSectorSize +
+ eccBytes) * j +
+ eccSectorSize +
+ i] =
+ write_data[PageDataSize +
+ spareFlagBytes +
+ eccBytes * j +
+ i];
+ }
+
+ for (i = 0; i < spareFlagBytes; i++)
+ page_main_spare[(eccSectorSize +
+ eccBytes) * j + i] =
+ write_data[PageDataSize + i];
+
+ for (i = PageSize - 1; i >= PageDataSize +
+ spareSkipBytes; i--)
+ page_main_spare[i] = page_main_spare[i -
+ spareSkipBytes];
+
+ for (i = PageDataSize; i < PageDataSize +
+ spareSkipBytes; i++)
+ page_main_spare[i] = 0xff;
+
+ for (i = 0; i < PageSize / 4; i++)
+ iowrite32(
+ *((u32 *)page_main_spare + i),
+ FlashMem + 0x10);
+ } else {
+
+ for (i = 0; i < PageSize / 4; i++)
+ iowrite32(*((u32 *)write_data + i),
+ FlashMem + 0x10);
+ }
+
+ while (!(ioread32(FlashReg + intr_status) &
+ (INTR_STATUS0__PROGRAM_COMP |
+ INTR_STATUS0__PROGRAM_FAIL)))
+ ;
+
+ if (ioread32(FlashReg + intr_status) &
+ INTR_STATUS0__PROGRAM_FAIL)
+ status = FAIL;
+
+ iowrite32(ioread32(FlashReg + intr_status),
+ FlashReg + intr_status);
+
+ page_num++;
+ page_count--;
+ write_data += PageSize;
+ }
+
+ iowrite32(0, FlashReg + TRANSFER_SPARE_REG);
+ }
+
+ return status;
+}
+
+u16 NAND_Read_Page_Main_Spare(u8 *read_data, u32 block, u16 page,
+ u16 page_count)
+{
+ u32 status = PASS;
+ u32 i, j;
+ u64 flash_add = 0;
+ u32 PageSize = DeviceInfo.wPageSize;
+ u32 PageDataSize = DeviceInfo.wPageDataSize;
+ u32 PageSpareSize = DeviceInfo.wPageSpareSize;
+ u32 eccBytes = DeviceInfo.wECCBytesPerSector;
+ u32 spareFlagBytes = DeviceInfo.wNumPageSpareFlag;
+ u32 spareSkipBytes = DeviceInfo.wSpareSkipBytes;
+ u32 eccSectorSize;
+ u32 flash_bank;
+ u32 intr_status = 0;
+ u8 *read_data_l = read_data;
+ u32 intr_status_addresses[4] = {INTR_STATUS0,
+ INTR_STATUS1, INTR_STATUS2, INTR_STATUS3};
+ u8 *page_main_spare = buf_read_page_main_spare;
+
+ nand_dbg_print(NAND_DBG_WARN, "%s, Line %d, Function: %s\n",
+ __FILE__, __LINE__, __func__);
+
+ eccSectorSize = ECC_SECTOR_SIZE * (DeviceInfo.wDevicesConnected);
+
+ status = Boundary_Check_Block_Page(block, page, page_count);
+
+ flash_bank = block / (DeviceInfo.wTotalBlocks / totalUsedBanks);
+
+ if (status == PASS) {
+ intr_status = intr_status_addresses[flash_bank];
+
+ iowrite32(1, FlashReg + TRANSFER_SPARE_REG);
+
+ iowrite32(ioread32(FlashReg + intr_status),
+ FlashReg + intr_status);
+
+ while ((status != FAIL) && (page_count > 0)) {
+ flash_add = (u64)(block %
+ (DeviceInfo.wTotalBlocks / totalUsedBanks))
+ * DeviceInfo.wBlockDataSize +
+ (u64)page * DeviceInfo.wPageDataSize;
+
+ index_addr((u32)(MODE_10 | (flash_bank << 24) |
+ (flash_add >> DeviceInfo.nBitsInPageDataSize)),
+ 0x43);
+ index_addr((u32)(MODE_10 | (flash_bank << 24) |
+ (flash_add >> DeviceInfo.nBitsInPageDataSize)),
+ 0x2000 | page_count);
+
+ while (!(ioread32(FlashReg + intr_status) &
+ INTR_STATUS0__LOAD_COMP))
+ ;
+
+ iowrite32((u32)(MODE_01 | (flash_bank << 24) |
+ (flash_add >>
+ DeviceInfo.nBitsInPageDataSize)),
+ FlashMem);
+
+ for (i = 0; i < PageSize / 4; i++)
+ *(((u32 *)page_main_spare) + i) =
+ ioread32(FlashMem + 0x10);
+
+ if (enable_ecc) {
+ for (i = PageDataSize; i < PageSize -
+ spareSkipBytes; i++)
+ page_main_spare[i] = page_main_spare[i +
+ spareSkipBytes];
+
+ for (j = 0;
+ j < DeviceInfo.wPageDataSize / eccSectorSize;
+ j++) {
+
+ for (i = 0; i < eccSectorSize; i++)
+ read_data_l[eccSectorSize * j +
+ i] =
+ page_main_spare[
+ (eccSectorSize +
+ eccBytes) * j + i];
+
+ for (i = 0; i < eccBytes; i++)
+ read_data_l[PageDataSize +
+ spareFlagBytes +
+ eccBytes * j + i] =
+ page_main_spare[
+ (eccSectorSize +
+ eccBytes) * j +
+ eccSectorSize + i];
+ }
+
+ for (i = 0; i < spareFlagBytes; i++)
+ read_data_l[PageDataSize + i] =
+ page_main_spare[(eccSectorSize +
+ eccBytes) * j + i];
+ } else {
+ for (i = 0; i < (PageDataSize + PageSpareSize);
+ i++)
+ read_data_l[i] = page_main_spare[i];
+
+ }
+
+ if (enable_ecc) {
+ while (!(ioread32(FlashReg + intr_status) &
+ (INTR_STATUS0__ECC_TRANSACTION_DONE |
+ INTR_STATUS0__ECC_ERR)))
+ ;
+
+ if (ioread32(FlashReg + intr_status) &
+ INTR_STATUS0__ECC_ERR) {
+ iowrite32(INTR_STATUS0__ECC_ERR,
+ FlashReg + intr_status);
+ status = do_ecc_new(flash_bank,
+ read_data, block, page);
+ }
+
+ if (ioread32(FlashReg + intr_status) &
+ INTR_STATUS0__ECC_TRANSACTION_DONE &
+ INTR_STATUS0__ECC_ERR) {
+ iowrite32(INTR_STATUS0__ECC_ERR |
+ INTR_STATUS0__ECC_TRANSACTION_DONE,
+ FlashReg + intr_status);
+ } else if (ioread32(FlashReg + intr_status) &
+ INTR_STATUS0__ECC_TRANSACTION_DONE) {
+ iowrite32(
+ INTR_STATUS0__ECC_TRANSACTION_DONE,
+ FlashReg + intr_status);
+ } else if (ioread32(FlashReg + intr_status) &
+ INTR_STATUS0__ECC_ERR) {
+ iowrite32(INTR_STATUS0__ECC_ERR,
+ FlashReg + intr_status);
+ }
+ }
+
+ page++;
+ page_count--;
+ read_data_l += PageSize;
+ }
+ }
+
+ iowrite32(0, FlashReg + TRANSFER_SPARE_REG);
+
+ index_addr((u32)(MODE_10 | (flash_bank << 24) |
+ (flash_add >> DeviceInfo.nBitsInPageDataSize)), 0x42);
+
+ return status;
+}
+
+u16 NAND_Pipeline_Write_Ahead(u8 *write_data, u32 block,
+ u16 page, u16 page_count)
+{
+ u16 status = PASS;
+ u32 NumPages = page_count;
+ u64 flash_add;
+ u32 flash_bank;
+ u32 intr_status = 0;
+ u32 intr_status_addresses[4] = {INTR_STATUS0,
+ INTR_STATUS1, INTR_STATUS2, INTR_STATUS3};
+ int ret;
+
+ nand_dbg_print(NAND_DBG_DEBUG, "%s, Line %d, Function: %s\n",
+ __FILE__, __LINE__, __func__);
+
+ status = Boundary_Check_Block_Page(block, page, page_count);
+
+ if (page_count < 2)
+ status = FAIL;
+
+ if (status != PASS)
+ return status;
+
+ flash_add = (u64)(block % (DeviceInfo.wTotalBlocks / totalUsedBanks))
+ * DeviceInfo.wBlockDataSize +
+ (u64)page * DeviceInfo.wPageDataSize;
+
+ flash_bank = block / (DeviceInfo.wTotalBlocks / totalUsedBanks);
+
+ intr_status = intr_status_addresses[flash_bank];
+ iowrite32(ioread32(FlashReg + intr_status), FlashReg + intr_status);
+
+ iowrite32(1, FlashReg + DMA_ENABLE);
+ while (!(ioread32(FlashReg + DMA_ENABLE) & DMA_ENABLE__FLAG))
+ ;
+
+ iowrite32(0, FlashReg + TRANSFER_SPARE_REG);
+
+ /* Fill the mrst_nand_info structure */
+ info.state = INT_PIPELINE_WRITE_AHEAD;
+ info.write_data = write_data;
+ info.flash_bank = flash_bank;
+ info.block = block;
+ info.page = page;
+ info.ret = PASS;
+
+ index_addr((u32)(MODE_10 | (flash_bank << 24) |
+ (flash_add >> DeviceInfo.nBitsInPageDataSize)), 0x42);
+
+ ddma_trans(write_data, flash_add, flash_bank, 1, NumPages);
+
+ iowrite32(1, FlashReg + GLOBAL_INT_ENABLE); /* Enable interrupt */
+
+ ret = wait_for_completion_timeout(&info.complete, 10 * HZ);
+ if (!ret) {
+ printk(KERN_ERR "Wait for completion timeout "
+ "in %s, Line %d\n", __FILE__, __LINE__);
+ status = ERR;
+ } else {
+ status = info.ret;
+ }
+
+ iowrite32(ioread32(FlashReg + intr_status), FlashReg + intr_status);
+
+ iowrite32(0, FlashReg + DMA_ENABLE);
+ while ((ioread32(FlashReg + DMA_ENABLE) & DMA_ENABLE__FLAG))
+ ;
+
+ return status;
+}
+
+/* Un-tested function */
+u16 NAND_Multiplane_Write(u8 *write_data, u32 block, u16 page,
+ u16 page_count)
+{
+ u16 status = PASS;
+ u32 NumPages = page_count;
+ u64 flash_add;
+ u32 flash_bank;
+ u32 intr_status = 0;
+ u32 intr_status_addresses[4] = {INTR_STATUS0,
+ INTR_STATUS1, INTR_STATUS2, INTR_STATUS3};
+ u16 status2 = PASS;
+ u32 t;
+
+ nand_dbg_print(NAND_DBG_WARN, "%s, Line %d, Function: %s\n",
+ __FILE__, __LINE__, __func__);
+
+ status = Boundary_Check_Block_Page(block, page, page_count);
+ if (status != PASS)
+ return status;
+
+ flash_add = (u64)(block % (DeviceInfo.wTotalBlocks / totalUsedBanks))
+ * DeviceInfo.wBlockDataSize +
+ (u64)page * DeviceInfo.wPageDataSize;
+
+ flash_bank = block / (DeviceInfo.wTotalBlocks / totalUsedBanks);
+
+ intr_status = intr_status_addresses[flash_bank];
+ iowrite32(ioread32(FlashReg + intr_status), FlashReg + intr_status);
+
+ iowrite32(0, FlashReg + TRANSFER_SPARE_REG);
+ iowrite32(0x01, FlashReg + MULTIPLANE_OPERATION);
+
+ iowrite32(1, FlashReg + DMA_ENABLE);
+ while (!(ioread32(FlashReg + DMA_ENABLE) & DMA_ENABLE__FLAG))
+ ;
+
+ iowrite32(0, FlashReg + TRANSFER_SPARE_REG);
+
+ index_addr((u32)(MODE_10 | (flash_bank << 24) |
+ (flash_add >> DeviceInfo.nBitsInPageDataSize)), 0x42);
+
+ ddma_trans(write_data, flash_add, flash_bank, 1, NumPages);
+
+ while (1) {
+ while (!ioread32(FlashReg + intr_status))
+ ;
+
+ if (ioread32(FlashReg + intr_status) &
+ INTR_STATUS0__DMA_CMD_COMP) {
+ iowrite32(INTR_STATUS0__DMA_CMD_COMP,
+ FlashReg + intr_status);
+ status = PASS;
+ if (status2 == FAIL)
+ status = FAIL;
+ break;
+ } else if (ioread32(FlashReg + intr_status) &
+ INTR_STATUS0__PROGRAM_FAIL) {
+ status2 = FAIL;
+ status = FAIL;
+ t = ioread32(FlashReg + intr_status) &
+ INTR_STATUS0__PROGRAM_FAIL;
+ iowrite32(t, FlashReg + intr_status);
+ } else {
+ iowrite32((~INTR_STATUS0__PROGRAM_FAIL) &
+ (~INTR_STATUS0__DMA_CMD_COMP),
+ FlashReg + intr_status);
+ }
+ }
+
+ iowrite32(ioread32(FlashReg + intr_status), FlashReg + intr_status);
+
+ iowrite32(0, FlashReg + DMA_ENABLE);
+
+ while ((ioread32(FlashReg + DMA_ENABLE) & DMA_ENABLE__FLAG))
+ ;
+
+ iowrite32(0, FlashReg + MULTIPLANE_OPERATION);
+
+ return status;
+}
+
+
+#if CMD_DMA
+static irqreturn_t cdma_isr(int irq, void *dev_id)
+{
+ struct mrst_nand_info *dev = dev_id;
+ int first_failed_cmd;
+
+ nand_dbg_print(NAND_DBG_DEBUG, "%s, Line %d, Function: %s\n",
+ __FILE__, __LINE__, __func__);
+
+ if (!is_cdma_interrupt())
+ return IRQ_NONE;
+
+ /* Disable controller interrupts */
+ iowrite32(0, FlashReg + GLOBAL_INT_ENABLE);
+ GLOB_FTL_Event_Status(&first_failed_cmd);
+ complete(&dev->complete);
+
+ return IRQ_HANDLED;
+}
+#else
+static void handle_nand_int_read(struct mrst_nand_info *dev)
+{
+ u32 intr_status_addresses[4] = {INTR_STATUS0,
+ INTR_STATUS1, INTR_STATUS2, INTR_STATUS3};
+ u32 intr_status;
+ u32 ecc_done_OR_dma_comp = 0;
+
+ nand_dbg_print(NAND_DBG_DEBUG, "%s, Line %d, Function: %s\n",
+ __FILE__, __LINE__, __func__);
+
+ dev->ret = PASS;
+ intr_status = intr_status_addresses[dev->flash_bank];
+
+ while (1) {
+ if (enable_ecc) {
+ if (ioread32(FlashReg + intr_status) &
+ INTR_STATUS0__ECC_ERR) {
+ iowrite32(INTR_STATUS0__ECC_ERR,
+ FlashReg + intr_status);
+ dev->ret = do_ecc_new(dev->flash_bank,
+ dev->read_data,
+ dev->block, dev->page);
+ } else if (ioread32(FlashReg + intr_status) &
+ INTR_STATUS0__DMA_CMD_COMP) {
+ iowrite32(INTR_STATUS0__DMA_CMD_COMP,
+ FlashReg + intr_status);
+ if (1 == ecc_done_OR_dma_comp)
+ break;
+ ecc_done_OR_dma_comp = 1;
+ } else if (ioread32(FlashReg + intr_status) &
+ INTR_STATUS0__ECC_TRANSACTION_DONE) {
+ iowrite32(INTR_STATUS0__ECC_TRANSACTION_DONE,
+ FlashReg + intr_status);
+ if (1 == ecc_done_OR_dma_comp)
+ break;
+ ecc_done_OR_dma_comp = 1;
+ }
+ } else {
+ if (ioread32(FlashReg + intr_status) &
+ INTR_STATUS0__DMA_CMD_COMP) {
+ iowrite32(INTR_STATUS0__DMA_CMD_COMP,
+ FlashReg + intr_status);
+ break;
+ } else {
+ printk(KERN_ERR "Illegal INTS "
+ "(offset addr 0x%x) value: 0x%x\n",
+ intr_status,
+ ioread32(FlashReg + intr_status));
+ }
+ }
+
+ iowrite32((~INTR_STATUS0__ECC_ERR) &
+ (~INTR_STATUS0__ECC_TRANSACTION_DONE) &
+ (~INTR_STATUS0__DMA_CMD_COMP),
+ FlashReg + intr_status);
+ }
+}
+
+static void handle_nand_int_write(struct mrst_nand_info *dev)
+{
+ u32 intr_status;
+ u32 intr[4] = {INTR_STATUS0, INTR_STATUS1,
+ INTR_STATUS2, INTR_STATUS3};
+ int status = PASS;
+
+ nand_dbg_print(NAND_DBG_DEBUG, "%s, Line %d, Function: %s\n",
+ __FILE__, __LINE__, __func__);
+
+ dev->ret = PASS;
+ intr_status = intr[dev->flash_bank];
+
+ while (1) {
+ while (!ioread32(FlashReg + intr_status))
+ ;
+
+ if (ioread32(FlashReg + intr_status) &
+ INTR_STATUS0__DMA_CMD_COMP) {
+ iowrite32(INTR_STATUS0__DMA_CMD_COMP,
+ FlashReg + intr_status);
+ if (FAIL == status)
+ dev->ret = FAIL;
+ break;
+ } else if (ioread32(FlashReg + intr_status) &
+ INTR_STATUS0__PROGRAM_FAIL) {
+ status = FAIL;
+ iowrite32(INTR_STATUS0__PROGRAM_FAIL,
+ FlashReg + intr_status);
+ } else {
+ iowrite32((~INTR_STATUS0__PROGRAM_FAIL) &
+ (~INTR_STATUS0__DMA_CMD_COMP),
+ FlashReg + intr_status);
+ }
+ }
+}
+
+static irqreturn_t ddma_isr(int irq, void *dev_id)
+{
+ struct mrst_nand_info *dev = dev_id;
+ u32 int_mask, ints0, ints1, ints2, ints3, ints_offset;
+ u32 intr[4] = {INTR_STATUS0, INTR_STATUS1,
+ INTR_STATUS2, INTR_STATUS3};
+
+ int_mask = INTR_STATUS0__DMA_CMD_COMP |
+ INTR_STATUS0__ECC_TRANSACTION_DONE |
+ INTR_STATUS0__ECC_ERR |
+ INTR_STATUS0__PROGRAM_FAIL |
+ INTR_STATUS0__ERASE_FAIL;
+
+ ints0 = ioread32(FlashReg + INTR_STATUS0);
+ ints1 = ioread32(FlashReg + INTR_STATUS1);
+ ints2 = ioread32(FlashReg + INTR_STATUS2);
+ ints3 = ioread32(FlashReg + INTR_STATUS3);
+
+ ints_offset = intr[dev->flash_bank];
+
+ nand_dbg_print(NAND_DBG_DEBUG,
+ "INTR0: 0x%x, INTR1: 0x%x, INTR2: 0x%x, INTR3: 0x%x, "
+ "DMA_INTR: 0x%x, "
+ "dev->state: 0x%x, dev->flash_bank: %d\n",
+ ints0, ints1, ints2, ints3,
+ ioread32(FlashReg + DMA_INTR),
+ dev->state, dev->flash_bank);
+
+ if (!(ioread32(FlashReg + ints_offset) & int_mask)) {
+ iowrite32(ints0, FlashReg + INTR_STATUS0);
+ iowrite32(ints1, FlashReg + INTR_STATUS1);
+ iowrite32(ints2, FlashReg + INTR_STATUS2);
+ iowrite32(ints3, FlashReg + INTR_STATUS3);
+ nand_dbg_print(NAND_DBG_WARN,
+ "ddma_isr: Invalid interrupt for NAND controller. "
+ "Ignore it\n");
+ return IRQ_NONE;
+ }
+
+ switch (dev->state) {
+ case INT_READ_PAGE_MAIN:
+ case INT_PIPELINE_READ_AHEAD:
+ /* Disable controller interrupts */
+ iowrite32(0, FlashReg + GLOBAL_INT_ENABLE);
+ handle_nand_int_read(dev);
+ break;
+ case INT_WRITE_PAGE_MAIN:
+ case INT_PIPELINE_WRITE_AHEAD:
+ iowrite32(0, FlashReg + GLOBAL_INT_ENABLE);
+ handle_nand_int_write(dev);
+ break;
+ default:
+ printk(KERN_ERR "ddma_isr - Illegal state: 0x%x\n",
+ dev->state);
+ return IRQ_NONE;
+ }
+
+ dev->state = INT_IDLE_STATE;
+ complete(&dev->complete);
+ return IRQ_HANDLED;
+}
+#endif
+
+static const struct pci_device_id nand_pci_ids[] = {
+ {
+ .vendor = 0x8086,
+ .device = 0x0809,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ },
+ { /* end: all zeroes */ }
+};
+
+static int nand_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
+{
+ int ret = -ENODEV;
+ unsigned long csr_base;
+ unsigned long csr_len;
+ struct mrst_nand_info *pndev = &info;
+
+ nand_dbg_print(NAND_DBG_WARN, "%s, Line %d, Function: %s\n",
+ __FILE__, __LINE__, __func__);
+
+ ret = pci_enable_device(dev);
+ if (ret) {
+ printk(KERN_ERR "Spectra: pci_enable_device failed.\n");
+ return ret;
+ }
+
+ pci_set_master(dev);
+ pndev->dev = dev;
+
+ csr_base = pci_resource_start(dev, 0);
+ if (!csr_base) {
+ printk(KERN_ERR "Spectra: pci_resource_start failed!\n");
+ return -ENODEV;
+ }
+
+ csr_len = pci_resource_len(dev, 0);
+ if (!csr_len) {
+ printk(KERN_ERR "Spectra: pci_resource_len failed!\n");
+ return -ENODEV;
+ }
+
+ ret = pci_request_regions(dev, SPECTRA_NAND_NAME);
+ if (ret) {
+ printk(KERN_ERR "Spectra: Unable to request "
+ "memory region\n");
+ goto failed_req_csr;
+ }
+
+ pndev->ioaddr = ioremap_nocache(csr_base, csr_len);
+ if (!pndev->ioaddr) {
+ printk(KERN_ERR "Spectra: Unable to remap memory region\n");
+ ret = -ENOMEM;
+ goto failed_remap_csr;
+ }
+ nand_dbg_print(NAND_DBG_DEBUG, "Spectra: CSR 0x%08lx -> 0x%p (0x%lx)\n",
+ csr_base, pndev->ioaddr, csr_len);
+
+ init_completion(&pndev->complete);
+ nand_dbg_print(NAND_DBG_DEBUG, "Spectra: IRQ %d\n", dev->irq);
+
+#if CMD_DMA
+ if (request_irq(dev->irq, cdma_isr, IRQF_SHARED,
+ SPECTRA_NAND_NAME, &info)) {
+ printk(KERN_ERR "Spectra: Unable to allocate IRQ\n");
+ ret = -ENODEV;
+ iounmap(pndev->ioaddr);
+ goto failed_remap_csr;
+ }
+#else
+ if (request_irq(dev->irq, ddma_isr, IRQF_SHARED,
+ SPECTRA_NAND_NAME, &info)) {
+ printk(KERN_ERR "Spectra: Unable to allocate IRQ\n");
+ ret = -ENODEV;
+ iounmap(pndev->ioaddr);
+ goto failed_remap_csr;
+ }
+#endif
+
+ pci_set_drvdata(dev, pndev);
+
+ return 0;
+
+failed_remap_csr:
+ pci_release_regions(dev);
+failed_req_csr:
+
+ return ret;
+}
+
+static void nand_pci_remove(struct pci_dev *dev)
+{
+ struct mrst_nand_info *pndev = pci_get_drvdata(dev);
+
+ nand_dbg_print(NAND_DBG_WARN, "%s, Line %d, Function: %s\n",
+ __FILE__, __LINE__, __func__);
+
+#if CMD_DMA
+ free_irq(dev->irq, pndev);
+#endif
+ iounmap(pndev->ioaddr);
+ pci_release_regions(dev);
+ pci_disable_device(dev);
+}
+
+MODULE_DEVICE_TABLE(pci, nand_pci_ids);
+
+static struct pci_driver nand_pci_driver = {
+ .name = SPECTRA_NAND_NAME,
+ .id_table = nand_pci_ids,
+ .probe = nand_pci_probe,
+ .remove = nand_pci_remove,
+};
+
+int NAND_Flash_Init(void)
+{
+ int retval;
+ u32 int_mask;
+
+ nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n",
+ __FILE__, __LINE__, __func__);
+
+ FlashReg = ioremap_nocache(GLOB_HWCTL_REG_BASE,
+ GLOB_HWCTL_REG_SIZE);
+ if (!FlashReg) {
+ printk(KERN_ERR "Spectra: ioremap_nocache failed!");
+ return -ENOMEM;
+ }
+ nand_dbg_print(NAND_DBG_WARN,
+ "Spectra: Remapped reg base address: "
+ "0x%p, len: %d\n",
+ FlashReg, GLOB_HWCTL_REG_SIZE);
+
+ FlashMem = ioremap_nocache(GLOB_HWCTL_MEM_BASE,
+ GLOB_HWCTL_MEM_SIZE);
+ if (!FlashMem) {
+ printk(KERN_ERR "Spectra: ioremap_nocache failed!");
+ iounmap(FlashReg);
+ return -ENOMEM;
+ }
+ nand_dbg_print(NAND_DBG_WARN,
+ "Spectra: Remapped flash base address: "
+ "0x%p, len: %d\n",
+ (void *)FlashMem, GLOB_HWCTL_MEM_SIZE);
+
+ nand_dbg_print(NAND_DBG_DEBUG, "Dump timing register values:"
+ "acc_clks: %d, re_2_we: %d, we_2_re: %d,"
+ "addr_2_data: %d, rdwr_en_lo_cnt: %d, "
+ "rdwr_en_hi_cnt: %d, cs_setup_cnt: %d\n",
+ ioread32(FlashReg + ACC_CLKS),
+ ioread32(FlashReg + RE_2_WE),
+ ioread32(FlashReg + WE_2_RE),
+ ioread32(FlashReg + ADDR_2_DATA),
+ ioread32(FlashReg + RDWR_EN_LO_CNT),
+ ioread32(FlashReg + RDWR_EN_HI_CNT),
+ ioread32(FlashReg + CS_SETUP_CNT));
+
+ NAND_Flash_Reset();
+
+ iowrite32(0, FlashReg + GLOBAL_INT_ENABLE);
+
+#if CMD_DMA
+ info.pcmds_num = 0;
+ info.flash_bank = 0;
+ info.cdma_num = 0;
+ int_mask = (DMA_INTR__DESC_COMP_CHANNEL0 |
+ DMA_INTR__DESC_COMP_CHANNEL1 |
+ DMA_INTR__DESC_COMP_CHANNEL2 |
+ DMA_INTR__DESC_COMP_CHANNEL3 |
+ DMA_INTR__MEMCOPY_DESC_COMP);
+ iowrite32(int_mask, FlashReg + DMA_INTR_EN);
+ iowrite32(0xFFFF, FlashReg + DMA_INTR);
+
+ int_mask = (INTR_STATUS0__ECC_ERR |
+ INTR_STATUS0__PROGRAM_FAIL |
+ INTR_STATUS0__ERASE_FAIL);
+#else
+ int_mask = INTR_STATUS0__DMA_CMD_COMP |
+ INTR_STATUS0__ECC_TRANSACTION_DONE |
+ INTR_STATUS0__ECC_ERR |
+ INTR_STATUS0__PROGRAM_FAIL |
+ INTR_STATUS0__ERASE_FAIL;
+#endif
+ iowrite32(int_mask, FlashReg + INTR_EN0);
+ iowrite32(int_mask, FlashReg + INTR_EN1);
+ iowrite32(int_mask, FlashReg + INTR_EN2);
+ iowrite32(int_mask, FlashReg + INTR_EN3);
+
+ /* Clear all status bits */
+ iowrite32(0xFFFF, FlashReg + INTR_STATUS0);
+ iowrite32(0xFFFF, FlashReg + INTR_STATUS1);
+ iowrite32(0xFFFF, FlashReg + INTR_STATUS2);
+ iowrite32(0xFFFF, FlashReg + INTR_STATUS3);
+
+ iowrite32(0x0F, FlashReg + RB_PIN_ENABLED);
+ iowrite32(CHIP_EN_DONT_CARE__FLAG, FlashReg + CHIP_ENABLE_DONT_CARE);
+
+ /* Should set value for these registers when init */
+ iowrite32(0, FlashReg + TWO_ROW_ADDR_CYCLES);
+ iowrite32(1, FlashReg + ECC_ENABLE);
+ enable_ecc = 1;
+
+ retval = pci_register_driver(&nand_pci_driver);
+ if (retval)
+ return -ENOMEM;
+
+ return PASS;
+}
+
+/* Free memory */
+int nand_release_spectra(void)
+{
+ pci_unregister_driver(&nand_pci_driver);
+ iounmap(FlashMem);
+ iounmap(FlashReg);
+
+ return 0;
+}
+
+
+
diff --git a/drivers/staging/spectra/lld_nand.h b/drivers/staging/spectra/lld_nand.h
new file mode 100644
index 00000000000..d08388287da
--- /dev/null
+++ b/drivers/staging/spectra/lld_nand.h
@@ -0,0 +1,131 @@
+/*
+ * NAND Flash Controller Device Driver
+ * Copyright (c) 2009, Intel Corporation and its suppliers.
+ *
+ * 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 _LLD_NAND_
+#define _LLD_NAND_
+
+#ifdef ELDORA
+#include "defs.h"
+#else
+#include "flash.h"
+#include "ffsport.h"
+#endif
+
+#define MODE_00 0x00000000
+#define MODE_01 0x04000000
+#define MODE_10 0x08000000
+#define MODE_11 0x0C000000
+
+
+#define DATA_TRANSFER_MODE 0
+#define PROTECTION_PER_BLOCK 1
+#define LOAD_WAIT_COUNT 2
+#define PROGRAM_WAIT_COUNT 3
+#define ERASE_WAIT_COUNT 4
+#define INT_MONITOR_CYCLE_COUNT 5
+#define READ_BUSY_PIN_ENABLED 6
+#define MULTIPLANE_OPERATION_SUPPORT 7
+#define PRE_FETCH_MODE 8
+#define CE_DONT_CARE_SUPPORT 9
+#define COPYBACK_SUPPORT 10
+#define CACHE_WRITE_SUPPORT 11
+#define CACHE_READ_SUPPORT 12
+#define NUM_PAGES_IN_BLOCK 13
+#define ECC_ENABLE_SELECT 14
+#define WRITE_ENABLE_2_READ_ENABLE 15
+#define ADDRESS_2_DATA 16
+#define READ_ENABLE_2_WRITE_ENABLE 17
+#define TWO_ROW_ADDRESS_CYCLES 18
+#define MULTIPLANE_ADDRESS_RESTRICT 19
+#define ACC_CLOCKS 20
+#define READ_WRITE_ENABLE_LOW_COUNT 21
+#define READ_WRITE_ENABLE_HIGH_COUNT 22
+
+#define ECC_SECTOR_SIZE 512
+#define LLD_MAX_FLASH_BANKS 4
+
+struct mrst_nand_info {
+ struct pci_dev *dev;
+ u32 state;
+ u32 flash_bank;
+ u8 *read_data;
+ u8 *write_data;
+ u32 block;
+ u16 page;
+ u32 use_dma;
+ void __iomem *ioaddr; /* Mapped io reg base address */
+ int ret;
+ u32 pcmds_num;
+ struct pending_cmd *pcmds;
+ int cdma_num; /* CDMA descriptor number in this chan */
+ u8 *cdma_desc_buf; /* CDMA descriptor table */
+ u8 *memcp_desc_buf; /* Memory copy descriptor table */
+ dma_addr_t cdma_desc; /* Mapped CDMA descriptor table */
+ dma_addr_t memcp_desc; /* Mapped memory copy descriptor table */
+ struct completion complete;
+};
+
+int NAND_Flash_Init(void);
+int nand_release_spectra(void);
+u16 NAND_Flash_Reset(void);
+u16 NAND_Read_Device_ID(void);
+u16 NAND_Erase_Block(u32 flash_add);
+u16 NAND_Write_Page_Main(u8 *write_data, u32 block, u16 page,
+ u16 page_count);
+u16 NAND_Read_Page_Main(u8 *read_data, u32 block, u16 page,
+ u16 page_count);
+u16 NAND_UnlockArrayAll(void);
+u16 NAND_Write_Page_Main_Spare(u8 *write_data, u32 block,
+ u16 page, u16 page_count);
+u16 NAND_Write_Page_Spare(u8 *read_data, u32 block, u16 page,
+ u16 page_count);
+u16 NAND_Read_Page_Main_Spare(u8 *read_data, u32 block, u16 page,
+ u16 page_count);
+u16 NAND_Read_Page_Spare(u8 *read_data, u32 block, u16 page,
+ u16 page_count);
+void NAND_LLD_Enable_Disable_Interrupts(u16 INT_ENABLE);
+u16 NAND_Get_Bad_Block(u32 block);
+u16 NAND_Pipeline_Read_Ahead(u8 *read_data, u32 block, u16 page,
+ u16 page_count);
+u16 NAND_Pipeline_Write_Ahead(u8 *write_data, u32 block,
+ u16 page, u16 page_count);
+u16 NAND_Multiplane_Read(u8 *read_data, u32 block, u16 page,
+ u16 page_count);
+u16 NAND_Multiplane_Write(u8 *write_data, u32 block, u16 page,
+ u16 page_count);
+void NAND_ECC_Ctrl(int enable);
+u16 NAND_Read_Page_Main_Polling(u8 *read_data,
+ u32 block, u16 page, u16 page_count);
+u16 NAND_Pipeline_Read_Ahead_Polling(u8 *read_data,
+ u32 block, u16 page, u16 page_count);
+void Conv_Spare_Data_Log2Phy_Format(u8 *data);
+void Conv_Spare_Data_Phy2Log_Format(u8 *data);
+void Conv_Main_Spare_Data_Log2Phy_Format(u8 *data, u16 page_count);
+void Conv_Main_Spare_Data_Phy2Log_Format(u8 *data, u16 page_count);
+
+extern void __iomem *FlashReg;
+extern void __iomem *FlashMem;
+
+extern int totalUsedBanks;
+extern u32 GLOB_valid_banks[LLD_MAX_FLASH_BANKS];
+
+#endif /*_LLD_NAND_*/
+
+
+
diff --git a/drivers/staging/spectra/nand_regs.h b/drivers/staging/spectra/nand_regs.h
new file mode 100644
index 00000000000..e192e4ae8c1
--- /dev/null
+++ b/drivers/staging/spectra/nand_regs.h
@@ -0,0 +1,619 @@
+/*
+ * NAND Flash Controller Device Driver
+ * Copyright (c) 2009, Intel Corporation and its suppliers.
+ *
+ * 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.
+ *
+ */
+
+#define DEVICE_RESET 0x0
+#define DEVICE_RESET__BANK0 0x0001
+#define DEVICE_RESET__BANK1 0x0002
+#define DEVICE_RESET__BANK2 0x0004
+#define DEVICE_RESET__BANK3 0x0008
+
+#define TRANSFER_SPARE_REG 0x10
+#define TRANSFER_SPARE_REG__FLAG 0x0001
+
+#define LOAD_WAIT_CNT 0x20
+#define LOAD_WAIT_CNT__VALUE 0xffff
+
+#define PROGRAM_WAIT_CNT 0x30
+#define PROGRAM_WAIT_CNT__VALUE 0xffff
+
+#define ERASE_WAIT_CNT 0x40
+#define ERASE_WAIT_CNT__VALUE 0xffff
+
+#define INT_MON_CYCCNT 0x50
+#define INT_MON_CYCCNT__VALUE 0xffff
+
+#define RB_PIN_ENABLED 0x60
+#define RB_PIN_ENABLED__BANK0 0x0001
+#define RB_PIN_ENABLED__BANK1 0x0002
+#define RB_PIN_ENABLED__BANK2 0x0004
+#define RB_PIN_ENABLED__BANK3 0x0008
+
+#define MULTIPLANE_OPERATION 0x70
+#define MULTIPLANE_OPERATION__FLAG 0x0001
+
+#define MULTIPLANE_READ_ENABLE 0x80
+#define MULTIPLANE_READ_ENABLE__FLAG 0x0001
+
+#define COPYBACK_DISABLE 0x90
+#define COPYBACK_DISABLE__FLAG 0x0001
+
+#define CACHE_WRITE_ENABLE 0xa0
+#define CACHE_WRITE_ENABLE__FLAG 0x0001
+
+#define CACHE_READ_ENABLE 0xb0
+#define CACHE_READ_ENABLE__FLAG 0x0001
+
+#define PREFETCH_MODE 0xc0
+#define PREFETCH_MODE__PREFETCH_EN 0x0001
+#define PREFETCH_MODE__PREFETCH_BURST_LENGTH 0xfff0
+
+#define CHIP_ENABLE_DONT_CARE 0xd0
+#define CHIP_EN_DONT_CARE__FLAG 0x01
+
+#define ECC_ENABLE 0xe0
+#define ECC_ENABLE__FLAG 0x0001
+
+#define GLOBAL_INT_ENABLE 0xf0
+#define GLOBAL_INT_EN_FLAG 0x01
+
+#define WE_2_RE 0x100
+#define WE_2_RE__VALUE 0x003f
+
+#define ADDR_2_DATA 0x110
+#define ADDR_2_DATA__VALUE 0x003f
+
+#define RE_2_WE 0x120
+#define RE_2_WE__VALUE 0x003f
+
+#define ACC_CLKS 0x130
+#define ACC_CLKS__VALUE 0x000f
+
+#define NUMBER_OF_PLANES 0x140
+#define NUMBER_OF_PLANES__VALUE 0x0007
+
+#define PAGES_PER_BLOCK 0x150
+#define PAGES_PER_BLOCK__VALUE 0xffff
+
+#define DEVICE_WIDTH 0x160
+#define DEVICE_WIDTH__VALUE 0x0003
+
+#define DEVICE_MAIN_AREA_SIZE 0x170
+#define DEVICE_MAIN_AREA_SIZE__VALUE 0xffff
+
+#define DEVICE_SPARE_AREA_SIZE 0x180
+#define DEVICE_SPARE_AREA_SIZE__VALUE 0xffff
+
+#define TWO_ROW_ADDR_CYCLES 0x190
+#define TWO_ROW_ADDR_CYCLES__FLAG 0x0001
+
+#define MULTIPLANE_ADDR_RESTRICT 0x1a0
+#define MULTIPLANE_ADDR_RESTRICT__FLAG 0x0001
+
+#define ECC_CORRECTION 0x1b0
+#define ECC_CORRECTION__VALUE 0x001f
+
+#define READ_MODE 0x1c0
+#define READ_MODE__VALUE 0x000f
+
+#define WRITE_MODE 0x1d0
+#define WRITE_MODE__VALUE 0x000f
+
+#define COPYBACK_MODE 0x1e0
+#define COPYBACK_MODE__VALUE 0x000f
+
+#define RDWR_EN_LO_CNT 0x1f0
+#define RDWR_EN_LO_CNT__VALUE 0x001f
+
+#define RDWR_EN_HI_CNT 0x200
+#define RDWR_EN_HI_CNT__VALUE 0x001f
+
+#define MAX_RD_DELAY 0x210
+#define MAX_RD_DELAY__VALUE 0x000f
+
+#define CS_SETUP_CNT 0x220
+#define CS_SETUP_CNT__VALUE 0x001f
+
+#define SPARE_AREA_SKIP_BYTES 0x230
+#define SPARE_AREA_SKIP_BYTES__VALUE 0x003f
+
+#define SPARE_AREA_MARKER 0x240
+#define SPARE_AREA_MARKER__VALUE 0xffff
+
+#define DEVICES_CONNECTED 0x250
+#define DEVICES_CONNECTED__VALUE 0x0007
+
+#define DIE_MASK 0x260
+#define DIE_MASK__VALUE 0x00ff
+
+#define FIRST_BLOCK_OF_NEXT_PLANE 0x270
+#define FIRST_BLOCK_OF_NEXT_PLANE__VALUE 0xffff
+
+#define WRITE_PROTECT 0x280
+#define WRITE_PROTECT__FLAG 0x0001
+
+#define RE_2_RE 0x290
+#define RE_2_RE__VALUE 0x003f
+
+#define MANUFACTURER_ID 0x300
+#define MANUFACTURER_ID__VALUE 0x00ff
+
+#define DEVICE_ID 0x310
+#define DEVICE_ID__VALUE 0x00ff
+
+#define DEVICE_PARAM_0 0x320
+#define DEVICE_PARAM_0__VALUE 0x00ff
+
+#define DEVICE_PARAM_1 0x330
+#define DEVICE_PARAM_1__VALUE 0x00ff
+
+#define DEVICE_PARAM_2 0x340
+#define DEVICE_PARAM_2__VALUE 0x00ff
+
+#define LOGICAL_PAGE_DATA_SIZE 0x350
+#define LOGICAL_PAGE_DATA_SIZE__VALUE 0xffff
+
+#define LOGICAL_PAGE_SPARE_SIZE 0x360
+#define LOGICAL_PAGE_SPARE_SIZE__VALUE 0xffff
+
+#define REVISION 0x370
+#define REVISION__VALUE 0xffff
+
+#define ONFI_DEVICE_FEATURES 0x380
+#define ONFI_DEVICE_FEATURES__VALUE 0x003f
+
+#define ONFI_OPTIONAL_COMMANDS 0x390
+#define ONFI_OPTIONAL_COMMANDS__VALUE 0x003f
+
+#define ONFI_TIMING_MODE 0x3a0
+#define ONFI_TIMING_MODE__VALUE 0x003f
+
+#define ONFI_PGM_CACHE_TIMING_MODE 0x3b0
+#define ONFI_PGM_CACHE_TIMING_MODE__VALUE 0x003f
+
+#define ONFI_DEVICE_NO_OF_LUNS 0x3c0
+#define ONFI_DEVICE_NO_OF_LUNS__NO_OF_LUNS 0x00ff
+#define ONFI_DEVICE_NO_OF_LUNS__ONFI_DEVICE 0x0100
+
+#define ONFI_DEVICE_NO_OF_BLOCKS_PER_LUN_L 0x3d0
+#define ONFI_DEVICE_NO_OF_BLOCKS_PER_LUN_L__VALUE 0xffff
+
+#define ONFI_DEVICE_NO_OF_BLOCKS_PER_LUN_U 0x3e0
+#define ONFI_DEVICE_NO_OF_BLOCKS_PER_LUN_U__VALUE 0xffff
+
+#define FEATURES 0x3f0
+#define FEATURES__N_BANKS 0x0003
+#define FEATURES__ECC_MAX_ERR 0x003c
+#define FEATURES__DMA 0x0040
+#define FEATURES__CMD_DMA 0x0080
+#define FEATURES__PARTITION 0x0100
+#define FEATURES__XDMA_SIDEBAND 0x0200
+#define FEATURES__GPREG 0x0400
+#define FEATURES__INDEX_ADDR 0x0800
+
+#define TRANSFER_MODE 0x400
+#define TRANSFER_MODE__VALUE 0x0003
+
+#define INTR_STATUS0 0x410
+#define INTR_STATUS0__ECC_TRANSACTION_DONE 0x0001
+#define INTR_STATUS0__ECC_ERR 0x0002
+#define INTR_STATUS0__DMA_CMD_COMP 0x0004
+#define INTR_STATUS0__TIME_OUT 0x0008
+#define INTR_STATUS0__PROGRAM_FAIL 0x0010
+#define INTR_STATUS0__ERASE_FAIL 0x0020
+#define INTR_STATUS0__LOAD_COMP 0x0040
+#define INTR_STATUS0__PROGRAM_COMP 0x0080
+#define INTR_STATUS0__ERASE_COMP 0x0100
+#define INTR_STATUS0__PIPE_CPYBCK_CMD_COMP 0x0200
+#define INTR_STATUS0__LOCKED_BLK 0x0400
+#define INTR_STATUS0__UNSUP_CMD 0x0800
+#define INTR_STATUS0__INT_ACT 0x1000
+#define INTR_STATUS0__RST_COMP 0x2000
+#define INTR_STATUS0__PIPE_CMD_ERR 0x4000
+#define INTR_STATUS0__PAGE_XFER_INC 0x8000
+
+#define INTR_EN0 0x420
+#define INTR_EN0__ECC_TRANSACTION_DONE 0x0001
+#define INTR_EN0__ECC_ERR 0x0002
+#define INTR_EN0__DMA_CMD_COMP 0x0004
+#define INTR_EN0__TIME_OUT 0x0008
+#define INTR_EN0__PROGRAM_FAIL 0x0010
+#define INTR_EN0__ERASE_FAIL 0x0020
+#define INTR_EN0__LOAD_COMP 0x0040
+#define INTR_EN0__PROGRAM_COMP 0x0080
+#define INTR_EN0__ERASE_COMP 0x0100
+#define INTR_EN0__PIPE_CPYBCK_CMD_COMP 0x0200
+#define INTR_EN0__LOCKED_BLK 0x0400
+#define INTR_EN0__UNSUP_CMD 0x0800
+#define INTR_EN0__INT_ACT 0x1000
+#define INTR_EN0__RST_COMP 0x2000
+#define INTR_EN0__PIPE_CMD_ERR 0x4000
+#define INTR_EN0__PAGE_XFER_INC 0x8000
+
+#define PAGE_CNT0 0x430
+#define PAGE_CNT0__VALUE 0x00ff
+
+#define ERR_PAGE_ADDR0 0x440
+#define ERR_PAGE_ADDR0__VALUE 0xffff
+
+#define ERR_BLOCK_ADDR0 0x450
+#define ERR_BLOCK_ADDR0__VALUE 0xffff
+
+#define INTR_STATUS1 0x460
+#define INTR_STATUS1__ECC_TRANSACTION_DONE 0x0001
+#define INTR_STATUS1__ECC_ERR 0x0002
+#define INTR_STATUS1__DMA_CMD_COMP 0x0004
+#define INTR_STATUS1__TIME_OUT 0x0008
+#define INTR_STATUS1__PROGRAM_FAIL 0x0010
+#define INTR_STATUS1__ERASE_FAIL 0x0020
+#define INTR_STATUS1__LOAD_COMP 0x0040
+#define INTR_STATUS1__PROGRAM_COMP 0x0080
+#define INTR_STATUS1__ERASE_COMP 0x0100
+#define INTR_STATUS1__PIPE_CPYBCK_CMD_COMP 0x0200
+#define INTR_STATUS1__LOCKED_BLK 0x0400
+#define INTR_STATUS1__UNSUP_CMD 0x0800
+#define INTR_STATUS1__INT_ACT 0x1000
+#define INTR_STATUS1__RST_COMP 0x2000
+#define INTR_STATUS1__PIPE_CMD_ERR 0x4000
+#define INTR_STATUS1__PAGE_XFER_INC 0x8000
+
+#define INTR_EN1 0x470
+#define INTR_EN1__ECC_TRANSACTION_DONE 0x0001
+#define INTR_EN1__ECC_ERR 0x0002
+#define INTR_EN1__DMA_CMD_COMP 0x0004
+#define INTR_EN1__TIME_OUT 0x0008
+#define INTR_EN1__PROGRAM_FAIL 0x0010
+#define INTR_EN1__ERASE_FAIL 0x0020
+#define INTR_EN1__LOAD_COMP 0x0040
+#define INTR_EN1__PROGRAM_COMP 0x0080
+#define INTR_EN1__ERASE_COMP 0x0100
+#define INTR_EN1__PIPE_CPYBCK_CMD_COMP 0x0200
+#define INTR_EN1__LOCKED_BLK 0x0400
+#define INTR_EN1__UNSUP_CMD 0x0800
+#define INTR_EN1__INT_ACT 0x1000
+#define INTR_EN1__RST_COMP 0x2000
+#define INTR_EN1__PIPE_CMD_ERR 0x4000
+#define INTR_EN1__PAGE_XFER_INC 0x8000
+
+#define PAGE_CNT1 0x480
+#define PAGE_CNT1__VALUE 0x00ff
+
+#define ERR_PAGE_ADDR1 0x490
+#define ERR_PAGE_ADDR1__VALUE 0xffff
+
+#define ERR_BLOCK_ADDR1 0x4a0
+#define ERR_BLOCK_ADDR1__VALUE 0xffff
+
+#define INTR_STATUS2 0x4b0
+#define INTR_STATUS2__ECC_TRANSACTION_DONE 0x0001
+#define INTR_STATUS2__ECC_ERR 0x0002
+#define INTR_STATUS2__DMA_CMD_COMP 0x0004
+#define INTR_STATUS2__TIME_OUT 0x0008
+#define INTR_STATUS2__PROGRAM_FAIL 0x0010
+#define INTR_STATUS2__ERASE_FAIL 0x0020
+#define INTR_STATUS2__LOAD_COMP 0x0040
+#define INTR_STATUS2__PROGRAM_COMP 0x0080
+#define INTR_STATUS2__ERASE_COMP 0x0100
+#define INTR_STATUS2__PIPE_CPYBCK_CMD_COMP 0x0200
+#define INTR_STATUS2__LOCKED_BLK 0x0400
+#define INTR_STATUS2__UNSUP_CMD 0x0800
+#define INTR_STATUS2__INT_ACT 0x1000
+#define INTR_STATUS2__RST_COMP 0x2000
+#define INTR_STATUS2__PIPE_CMD_ERR 0x4000
+#define INTR_STATUS2__PAGE_XFER_INC 0x8000
+
+#define INTR_EN2 0x4c0
+#define INTR_EN2__ECC_TRANSACTION_DONE 0x0001
+#define INTR_EN2__ECC_ERR 0x0002
+#define INTR_EN2__DMA_CMD_COMP 0x0004
+#define INTR_EN2__TIME_OUT 0x0008
+#define INTR_EN2__PROGRAM_FAIL 0x0010
+#define INTR_EN2__ERASE_FAIL 0x0020
+#define INTR_EN2__LOAD_COMP 0x0040
+#define INTR_EN2__PROGRAM_COMP 0x0080
+#define INTR_EN2__ERASE_COMP 0x0100
+#define INTR_EN2__PIPE_CPYBCK_CMD_COMP 0x0200
+#define INTR_EN2__LOCKED_BLK 0x0400
+#define INTR_EN2__UNSUP_CMD 0x0800
+#define INTR_EN2__INT_ACT 0x1000
+#define INTR_EN2__RST_COMP 0x2000
+#define INTR_EN2__PIPE_CMD_ERR 0x4000
+#define INTR_EN2__PAGE_XFER_INC 0x8000
+
+#define PAGE_CNT2 0x4d0
+#define PAGE_CNT2__VALUE 0x00ff
+
+#define ERR_PAGE_ADDR2 0x4e0
+#define ERR_PAGE_ADDR2__VALUE 0xffff
+
+#define ERR_BLOCK_ADDR2 0x4f0
+#define ERR_BLOCK_ADDR2__VALUE 0xffff
+
+#define INTR_STATUS3 0x500
+#define INTR_STATUS3__ECC_TRANSACTION_DONE 0x0001
+#define INTR_STATUS3__ECC_ERR 0x0002
+#define INTR_STATUS3__DMA_CMD_COMP 0x0004
+#define INTR_STATUS3__TIME_OUT 0x0008
+#define INTR_STATUS3__PROGRAM_FAIL 0x0010
+#define INTR_STATUS3__ERASE_FAIL 0x0020
+#define INTR_STATUS3__LOAD_COMP 0x0040
+#define INTR_STATUS3__PROGRAM_COMP 0x0080
+#define INTR_STATUS3__ERASE_COMP 0x0100
+#define INTR_STATUS3__PIPE_CPYBCK_CMD_COMP 0x0200
+#define INTR_STATUS3__LOCKED_BLK 0x0400
+#define INTR_STATUS3__UNSUP_CMD 0x0800
+#define INTR_STATUS3__INT_ACT 0x1000
+#define INTR_STATUS3__RST_COMP 0x2000
+#define INTR_STATUS3__PIPE_CMD_ERR 0x4000
+#define INTR_STATUS3__PAGE_XFER_INC 0x8000
+
+#define INTR_EN3 0x510
+#define INTR_EN3__ECC_TRANSACTION_DONE 0x0001
+#define INTR_EN3__ECC_ERR 0x0002
+#define INTR_EN3__DMA_CMD_COMP 0x0004
+#define INTR_EN3__TIME_OUT 0x0008
+#define INTR_EN3__PROGRAM_FAIL 0x0010
+#define INTR_EN3__ERASE_FAIL 0x0020
+#define INTR_EN3__LOAD_COMP 0x0040
+#define INTR_EN3__PROGRAM_COMP 0x0080
+#define INTR_EN3__ERASE_COMP 0x0100
+#define INTR_EN3__PIPE_CPYBCK_CMD_COMP 0x0200
+#define INTR_EN3__LOCKED_BLK 0x0400
+#define INTR_EN3__UNSUP_CMD 0x0800
+#define INTR_EN3__INT_ACT 0x1000
+#define INTR_EN3__RST_COMP 0x2000
+#define INTR_EN3__PIPE_CMD_ERR 0x4000
+#define INTR_EN3__PAGE_XFER_INC 0x8000
+
+#define PAGE_CNT3 0x520
+#define PAGE_CNT3__VALUE 0x00ff
+
+#define ERR_PAGE_ADDR3 0x530
+#define ERR_PAGE_ADDR3__VALUE 0xffff
+
+#define ERR_BLOCK_ADDR3 0x540
+#define ERR_BLOCK_ADDR3__VALUE 0xffff
+
+#define DATA_INTR 0x550
+#define DATA_INTR__WRITE_SPACE_AV 0x0001
+#define DATA_INTR__READ_DATA_AV 0x0002
+
+#define DATA_INTR_EN 0x560
+#define DATA_INTR_EN__WRITE_SPACE_AV 0x0001
+#define DATA_INTR_EN__READ_DATA_AV 0x0002
+
+#define GPREG_0 0x570
+#define GPREG_0__VALUE 0xffff
+
+#define GPREG_1 0x580
+#define GPREG_1__VALUE 0xffff
+
+#define GPREG_2 0x590
+#define GPREG_2__VALUE 0xffff
+
+#define GPREG_3 0x5a0
+#define GPREG_3__VALUE 0xffff
+
+#define ECC_THRESHOLD 0x600
+#define ECC_THRESHOLD__VALUE 0x03ff
+
+#define ECC_ERROR_BLOCK_ADDRESS 0x610
+#define ECC_ERROR_BLOCK_ADDRESS__VALUE 0xffff
+
+#define ECC_ERROR_PAGE_ADDRESS 0x620
+#define ECC_ERROR_PAGE_ADDRESS__VALUE 0x0fff
+#define ECC_ERROR_PAGE_ADDRESS__BANK 0xf000
+
+#define ECC_ERROR_ADDRESS 0x630
+#define ECC_ERROR_ADDRESS__OFFSET 0x0fff
+#define ECC_ERROR_ADDRESS__SECTOR_NR 0xf000
+
+#define ERR_CORRECTION_INFO 0x640
+#define ERR_CORRECTION_INFO__BYTEMASK 0x00ff
+#define ERR_CORRECTION_INFO__DEVICE_NR 0x0f00
+#define ERR_CORRECTION_INFO__ERROR_TYPE 0x4000
+#define ERR_CORRECTION_INFO__LAST_ERR_INFO 0x8000
+
+#define DMA_ENABLE 0x700
+#define DMA_ENABLE__FLAG 0x0001
+
+#define IGNORE_ECC_DONE 0x710
+#define IGNORE_ECC_DONE__FLAG 0x0001
+
+#define DMA_INTR 0x720
+#define DMA_INTR__TARGET_ERROR 0x0001
+#define DMA_INTR__DESC_COMP_CHANNEL0 0x0002
+#define DMA_INTR__DESC_COMP_CHANNEL1 0x0004
+#define DMA_INTR__DESC_COMP_CHANNEL2 0x0008
+#define DMA_INTR__DESC_COMP_CHANNEL3 0x0010
+#define DMA_INTR__MEMCOPY_DESC_COMP 0x0020
+
+#define DMA_INTR_EN 0x730
+#define DMA_INTR_EN__TARGET_ERROR 0x0001
+#define DMA_INTR_EN__DESC_COMP_CHANNEL0 0x0002
+#define DMA_INTR_EN__DESC_COMP_CHANNEL1 0x0004
+#define DMA_INTR_EN__DESC_COMP_CHANNEL2 0x0008
+#define DMA_INTR_EN__DESC_COMP_CHANNEL3 0x0010
+#define DMA_INTR_EN__MEMCOPY_DESC_COMP 0x0020
+
+#define TARGET_ERR_ADDR_LO 0x740
+#define TARGET_ERR_ADDR_LO__VALUE 0xffff
+
+#define TARGET_ERR_ADDR_HI 0x750
+#define TARGET_ERR_ADDR_HI__VALUE 0xffff
+
+#define CHNL_ACTIVE 0x760
+#define CHNL_ACTIVE__CHANNEL0 0x0001
+#define CHNL_ACTIVE__CHANNEL1 0x0002
+#define CHNL_ACTIVE__CHANNEL2 0x0004
+#define CHNL_ACTIVE__CHANNEL3 0x0008
+
+#define ACTIVE_SRC_ID 0x800
+#define ACTIVE_SRC_ID__VALUE 0x00ff
+
+#define PTN_INTR 0x810
+#define PTN_INTR__CONFIG_ERROR 0x0001
+#define PTN_INTR__ACCESS_ERROR_BANK0 0x0002
+#define PTN_INTR__ACCESS_ERROR_BANK1 0x0004
+#define PTN_INTR__ACCESS_ERROR_BANK2 0x0008
+#define PTN_INTR__ACCESS_ERROR_BANK3 0x0010
+#define PTN_INTR__REG_ACCESS_ERROR 0x0020
+
+#define PTN_INTR_EN 0x820
+#define PTN_INTR_EN__CONFIG_ERROR 0x0001
+#define PTN_INTR_EN__ACCESS_ERROR_BANK0 0x0002
+#define PTN_INTR_EN__ACCESS_ERROR_BANK1 0x0004
+#define PTN_INTR_EN__ACCESS_ERROR_BANK2 0x0008
+#define PTN_INTR_EN__ACCESS_ERROR_BANK3 0x0010
+#define PTN_INTR_EN__REG_ACCESS_ERROR 0x0020
+
+#define PERM_SRC_ID_0 0x830
+#define PERM_SRC_ID_0__SRCID 0x00ff
+#define PERM_SRC_ID_0__DIRECT_ACCESS_ACTIVE 0x0800
+#define PERM_SRC_ID_0__WRITE_ACTIVE 0x2000
+#define PERM_SRC_ID_0__READ_ACTIVE 0x4000
+#define PERM_SRC_ID_0__PARTITION_VALID 0x8000
+
+#define MIN_BLK_ADDR_0 0x840
+#define MIN_BLK_ADDR_0__VALUE 0xffff
+
+#define MAX_BLK_ADDR_0 0x850
+#define MAX_BLK_ADDR_0__VALUE 0xffff
+
+#define MIN_MAX_BANK_0 0x860
+#define MIN_MAX_BANK_0__MIN_VALUE 0x0003
+#define MIN_MAX_BANK_0__MAX_VALUE 0x000c
+
+#define PERM_SRC_ID_1 0x870
+#define PERM_SRC_ID_1__SRCID 0x00ff
+#define PERM_SRC_ID_1__DIRECT_ACCESS_ACTIVE 0x0800
+#define PERM_SRC_ID_1__WRITE_ACTIVE 0x2000
+#define PERM_SRC_ID_1__READ_ACTIVE 0x4000
+#define PERM_SRC_ID_1__PARTITION_VALID 0x8000
+
+#define MIN_BLK_ADDR_1 0x880
+#define MIN_BLK_ADDR_1__VALUE 0xffff
+
+#define MAX_BLK_ADDR_1 0x890
+#define MAX_BLK_ADDR_1__VALUE 0xffff
+
+#define MIN_MAX_BANK_1 0x8a0
+#define MIN_MAX_BANK_1__MIN_VALUE 0x0003
+#define MIN_MAX_BANK_1__MAX_VALUE 0x000c
+
+#define PERM_SRC_ID_2 0x8b0
+#define PERM_SRC_ID_2__SRCID 0x00ff
+#define PERM_SRC_ID_2__DIRECT_ACCESS_ACTIVE 0x0800
+#define PERM_SRC_ID_2__WRITE_ACTIVE 0x2000
+#define PERM_SRC_ID_2__READ_ACTIVE 0x4000
+#define PERM_SRC_ID_2__PARTITION_VALID 0x8000
+
+#define MIN_BLK_ADDR_2 0x8c0
+#define MIN_BLK_ADDR_2__VALUE 0xffff
+
+#define MAX_BLK_ADDR_2 0x8d0
+#define MAX_BLK_ADDR_2__VALUE 0xffff
+
+#define MIN_MAX_BANK_2 0x8e0
+#define MIN_MAX_BANK_2__MIN_VALUE 0x0003
+#define MIN_MAX_BANK_2__MAX_VALUE 0x000c
+
+#define PERM_SRC_ID_3 0x8f0
+#define PERM_SRC_ID_3__SRCID 0x00ff
+#define PERM_SRC_ID_3__DIRECT_ACCESS_ACTIVE 0x0800
+#define PERM_SRC_ID_3__WRITE_ACTIVE 0x2000
+#define PERM_SRC_ID_3__READ_ACTIVE 0x4000
+#define PERM_SRC_ID_3__PARTITION_VALID 0x8000
+
+#define MIN_BLK_ADDR_3 0x900
+#define MIN_BLK_ADDR_3__VALUE 0xffff
+
+#define MAX_BLK_ADDR_3 0x910
+#define MAX_BLK_ADDR_3__VALUE 0xffff
+
+#define MIN_MAX_BANK_3 0x920
+#define MIN_MAX_BANK_3__MIN_VALUE 0x0003
+#define MIN_MAX_BANK_3__MAX_VALUE 0x000c
+
+#define PERM_SRC_ID_4 0x930
+#define PERM_SRC_ID_4__SRCID 0x00ff
+#define PERM_SRC_ID_4__DIRECT_ACCESS_ACTIVE 0x0800
+#define PERM_SRC_ID_4__WRITE_ACTIVE 0x2000
+#define PERM_SRC_ID_4__READ_ACTIVE 0x4000
+#define PERM_SRC_ID_4__PARTITION_VALID 0x8000
+
+#define MIN_BLK_ADDR_4 0x940
+#define MIN_BLK_ADDR_4__VALUE 0xffff
+
+#define MAX_BLK_ADDR_4 0x950
+#define MAX_BLK_ADDR_4__VALUE 0xffff
+
+#define MIN_MAX_BANK_4 0x960
+#define MIN_MAX_BANK_4__MIN_VALUE 0x0003
+#define MIN_MAX_BANK_4__MAX_VALUE 0x000c
+
+#define PERM_SRC_ID_5 0x970
+#define PERM_SRC_ID_5__SRCID 0x00ff
+#define PERM_SRC_ID_5__DIRECT_ACCESS_ACTIVE 0x0800
+#define PERM_SRC_ID_5__WRITE_ACTIVE 0x2000
+#define PERM_SRC_ID_5__READ_ACTIVE 0x4000
+#define PERM_SRC_ID_5__PARTITION_VALID 0x8000
+
+#define MIN_BLK_ADDR_5 0x980
+#define MIN_BLK_ADDR_5__VALUE 0xffff
+
+#define MAX_BLK_ADDR_5 0x990
+#define MAX_BLK_ADDR_5__VALUE 0xffff
+
+#define MIN_MAX_BANK_5 0x9a0
+#define MIN_MAX_BANK_5__MIN_VALUE 0x0003
+#define MIN_MAX_BANK_5__MAX_VALUE 0x000c
+
+#define PERM_SRC_ID_6 0x9b0
+#define PERM_SRC_ID_6__SRCID 0x00ff
+#define PERM_SRC_ID_6__DIRECT_ACCESS_ACTIVE 0x0800
+#define PERM_SRC_ID_6__WRITE_ACTIVE 0x2000
+#define PERM_SRC_ID_6__READ_ACTIVE 0x4000
+#define PERM_SRC_ID_6__PARTITION_VALID 0x8000
+
+#define MIN_BLK_ADDR_6 0x9c0
+#define MIN_BLK_ADDR_6__VALUE 0xffff
+
+#define MAX_BLK_ADDR_6 0x9d0
+#define MAX_BLK_ADDR_6__VALUE 0xffff
+
+#define MIN_MAX_BANK_6 0x9e0
+#define MIN_MAX_BANK_6__MIN_VALUE 0x0003
+#define MIN_MAX_BANK_6__MAX_VALUE 0x000c
+
+#define PERM_SRC_ID_7 0x9f0
+#define PERM_SRC_ID_7__SRCID 0x00ff
+#define PERM_SRC_ID_7__DIRECT_ACCESS_ACTIVE 0x0800
+#define PERM_SRC_ID_7__WRITE_ACTIVE 0x2000
+#define PERM_SRC_ID_7__READ_ACTIVE 0x4000
+#define PERM_SRC_ID_7__PARTITION_VALID 0x8000
+
+#define MIN_BLK_ADDR_7 0xa00
+#define MIN_BLK_ADDR_7__VALUE 0xffff
+
+#define MAX_BLK_ADDR_7 0xa10
+#define MAX_BLK_ADDR_7__VALUE 0xffff
+
+#define MIN_MAX_BANK_7 0xa20
+#define MIN_MAX_BANK_7__MIN_VALUE 0x0003
+#define MIN_MAX_BANK_7__MAX_VALUE 0x000c
diff --git a/drivers/staging/spectra/spectraswconfig.h b/drivers/staging/spectra/spectraswconfig.h
new file mode 100644
index 00000000000..17259469e95
--- /dev/null
+++ b/drivers/staging/spectra/spectraswconfig.h
@@ -0,0 +1,82 @@
+/*
+ * NAND Flash Controller Device Driver
+ * Copyright (c) 2009, Intel Corporation and its suppliers.
+ *
+ * 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 _SPECTRASWCONFIG_
+#define _SPECTRASWCONFIG_
+
+/* NAND driver version */
+#define GLOB_VERSION "driver version 20100311"
+
+
+/***** Common Parameters *****/
+#define RETRY_TIMES 3
+
+#define READ_BADBLOCK_INFO 1
+#define READBACK_VERIFY 0
+#define AUTO_FORMAT_FLASH 0
+
+/***** Cache Parameters *****/
+#define CACHE_ITEM_NUM 128
+#define BLK_NUM_FOR_L2_CACHE 16
+
+/***** Block Table Parameters *****/
+#define BLOCK_TABLE_INDEX 0
+
+/***** Wear Leveling Parameters *****/
+#define WEAR_LEVELING_GATE 0x10
+#define WEAR_LEVELING_BLOCK_NUM 10
+
+#define DEBUG_BNDRY 0
+
+/***** Product Feature Support *****/
+#define FLASH_EMU defined(CONFIG_SPECTRA_EMU)
+#define FLASH_NAND defined(CONFIG_SPECTRA_MRST_HW)
+#define FLASH_MTD defined(CONFIG_SPECTRA_MTD)
+#define CMD_DMA defined(CONFIG_SPECTRA_MRST_HW_DMA)
+
+#define SPECTRA_PARTITION_ID 0
+
+/* Enable this macro if the number of flash blocks is larger than 16K. */
+#define SUPPORT_LARGE_BLOCKNUM 1
+
+/**** Block Table and Reserved Block Parameters *****/
+#define SPECTRA_START_BLOCK 3
+//#define NUM_FREE_BLOCKS_GATE 30
+#define NUM_FREE_BLOCKS_GATE 60
+
+/**** Hardware Parameters ****/
+#define GLOB_HWCTL_REG_BASE 0xFFA40000
+#define GLOB_HWCTL_REG_SIZE 4096
+
+#define GLOB_HWCTL_MEM_BASE 0xFFA48000
+#define GLOB_HWCTL_MEM_SIZE 4096
+
+/* KBV - Updated to LNW scratch register address */
+#define SCRATCH_REG_ADDR 0xFF108018
+#define SCRATCH_REG_SIZE 64
+
+#define GLOB_HWCTL_DEFAULT_BLKS 2048
+
+#define SUPPORT_15BITECC 1
+#define SUPPORT_8BITECC 1
+
+#define ONFI_BLOOM_TIME 0
+#define MODE5_WORKAROUND 1
+
+#endif /*_SPECTRASWCONFIG_*/
diff --git a/drivers/staging/ti-st/Kconfig b/drivers/staging/ti-st/Kconfig
index 3ab204ddc29..68ad3d0b84a 100644
--- a/drivers/staging/ti-st/Kconfig
+++ b/drivers/staging/ti-st/Kconfig
@@ -4,7 +4,7 @@
#
menu "Texas Instruments shared transport line discipline"
config TI_ST
- tristate "shared transport core driver"
+ tristate "Shared transport core driver"
depends on RFKILL
select FW_LOADER
help
diff --git a/drivers/staging/ti-st/TODO b/drivers/staging/ti-st/TODO
index 2c4fe583901..ebfd6bb6017 100644
--- a/drivers/staging/ti-st/TODO
+++ b/drivers/staging/ti-st/TODO
@@ -1,17 +1,6 @@
TODO:
-1. A per-device/tty port context required to support multiple devices
-on same platform.
-
-2. REMOVE the sysfs entry PID passing mechanism, since there should
-be a better way to request user-space to install line discipline.
-
-3. Re-view/Re-work on the locking.
-
-4. Re-structure to make the ldisc driver more generic for chipsets which mux
-multiple connectivity (BT, FM, GPS) upon 1 TTY port.
-
-5. Step up and maintain this driver to ensure that it continues
+1. Step up and maintain this driver to ensure that it continues
to work. Having the hardware for this is pretty much a
requirement. If this does not happen, the will be removed in
the 2.6.35 kernel release.
diff --git a/drivers/staging/ti-st/bt_drv.c b/drivers/staging/ti-st/bt_drv.c
index d8420b5c91f..61ae98833b1 100644
--- a/drivers/staging/ti-st/bt_drv.c
+++ b/drivers/staging/ti-st/bt_drv.c
@@ -80,31 +80,33 @@ static inline void hci_st_tx_complete(struct hci_st *hst, int pkt_type)
* status.hci_st_open() function will wait for signal from this
* API when st_register() function returns ST_PENDING.
*/
-static void hci_st_registration_completion_cb(char data)
+static void hci_st_registration_completion_cb(void *priv_data, char data)
{
+ struct hci_st *lhst = (struct hci_st *)priv_data;
BTDRV_API_START();
/* hci_st_open() function needs value of 'data' to know
* the registration status(success/fail),So have a back
* up of it.
*/
- hst->streg_cbdata = data;
+ lhst->streg_cbdata = data;
/* Got a feedback from ST for BT driver registration
* request.Wackup hci_st_open() function to continue
* it's open operation.
*/
- complete(&hst->wait_for_btdrv_reg_completion);
+ complete(&lhst->wait_for_btdrv_reg_completion);
BTDRV_API_EXIT(0);
}
/* Called by Shared Transport layer when receive data is
* available */
-static long hci_st_receive(struct sk_buff *skb)
+static long hci_st_receive(void *priv_data, struct sk_buff *skb)
{
int err;
int len;
+ struct hci_st *lhst = (struct hci_st *)priv_data;
BTDRV_API_START();
@@ -116,13 +118,13 @@ static long hci_st_receive(struct sk_buff *skb)
BTDRV_API_EXIT(-EFAULT);
return -EFAULT;
}
- if (!hst) {
+ if (!lhst) {
kfree_skb(skb);
BT_DRV_ERR("Invalid hci_st memory,freeing SKB");
BTDRV_API_EXIT(-EFAULT);
return -EFAULT;
}
- if (!test_bit(BT_DRV_RUNNING, &hst->flags)) {
+ if (!test_bit(BT_DRV_RUNNING, &lhst->flags)) {
kfree_skb(skb);
BT_DRV_ERR("Device is not running,freeing SKB");
BTDRV_API_EXIT(-EINVAL);
@@ -130,7 +132,7 @@ static long hci_st_receive(struct sk_buff *skb)
}
len = skb->len;
- skb->dev = (struct net_device *)hst->hdev;
+ skb->dev = (struct net_device *)lhst->hdev;
/* Forward skb to HCI CORE layer */
err = hci_recv_frame(skb);
@@ -141,7 +143,7 @@ static long hci_st_receive(struct sk_buff *skb)
BTDRV_API_EXIT(err);
return err;
}
- hst->hdev->stat.byte_rx += len;
+ lhst->hdev->stat.byte_rx += len;
BTDRV_API_EXIT(0);
return 0;
@@ -189,9 +191,14 @@ static int hci_st_open(struct hci_dev *hdev)
* make it as NULL */
hci_st_proto.write = NULL;
+ /* send in the hst to be received at registration complete callback
+ * and during st's receive
+ */
+ hci_st_proto.priv_data = hst;
+
/* Register with ST layer */
err = st_register(&hci_st_proto);
- if (err == ST_ERR_PENDING) {
+ if (err == -EINPROGRESS) {
/* Prepare wait-for-completion handler data structures.
* Needed to syncronize this and st_registration_completion_cb()
* functions.
@@ -232,7 +239,7 @@ static int hci_st_open(struct hci_dev *hdev)
return -EAGAIN;
}
err = 0;
- } else if (err == ST_ERR_FAILURE) {
+ } else if (err == -1) {
BT_DRV_ERR("st_register failed %d", err);
BTDRV_API_EXIT(-EAGAIN);
return -EAGAIN;
@@ -280,7 +287,7 @@ static int hci_st_close(struct hci_dev *hdev)
/* Unregister from ST layer */
if (test_and_clear_bit(BT_ST_REGISTERED, &hst->flags)) {
err = st_unregister(ST_BT);
- if (err != ST_SUCCESS) {
+ if (err != 0) {
BT_DRV_ERR("st_unregister failed %d", err);
BTDRV_API_EXIT(-EBUSY);
return -EBUSY;
diff --git a/drivers/staging/ti-st/st.h b/drivers/staging/ti-st/st.h
index e8fc97e32c9..9952579425b 100644
--- a/drivers/staging/ti-st/st.h
+++ b/drivers/staging/ti-st/st.h
@@ -24,24 +24,24 @@
#define ST_H
#include <linux/skbuff.h>
-/*
- * st.h
- */
/* TODO:
* Move the following to tty.h upon acceptance
*/
#define N_TI_WL 20 /* Ldisc for TI's WL BT, FM, GPS combo chips */
-/* some gpios have active high, others like fm have
- * active low
+/**
+ * enum kim_gpio_state - Few protocols such as FM have ACTIVE LOW
+ * gpio states for their chip/core enable gpios
*/
enum kim_gpio_state {
KIM_GPIO_INACTIVE,
KIM_GPIO_ACTIVE,
};
-/*
- * the list of protocols on chip
+
+/**
+ * enum proto-type - The protocol on WiLink chips which share a
+ * common physical interface like UART.
*/
enum proto_type {
ST_BT,
@@ -50,41 +50,35 @@ enum proto_type {
ST_MAX,
};
-enum {
- ST_ERR_FAILURE = -1, /* check struct */
- ST_SUCCESS,
- ST_ERR_PENDING = -5, /* to call reg_complete_cb */
- ST_ERR_ALREADY, /* already registered */
- ST_ERR_INPROGRESS,
- ST_ERR_NOPROTO, /* protocol not supported */
-};
-
-/* per protocol structure
- * for BT/FM and GPS
+/**
+ * struct st_proto_s - Per Protocol structure from BT/FM/GPS to ST
+ * @type: type of the protocol being registered among the
+ * available proto_type(BT, FM, GPS the protocol which share TTY).
+ * @recv: the receiver callback pointing to a function in the
+ * protocol drivers called by the ST driver upon receiving
+ * relevant data.
+ * @match_packet: reserved for future use, to make ST more generic
+ * @reg_complete_cb: callback handler pointing to a function in protocol
+ * handler called by ST when the pending registrations are complete.
+ * The registrations are marked pending, in situations when fw
+ * download is in progress.
+ * @write: pointer to function in ST provided to protocol drivers from ST,
+ * to be made use when protocol drivers have data to send to TTY.
+ * @priv_data: privdate data holder for the protocol drivers, sent
+ * from the protocol drivers during registration, and sent back on
+ * reg_complete_cb and recv.
*/
struct st_proto_s {
enum proto_type type;
-/*
- * to be called by ST when data arrives
- */
- long (*recv) (struct sk_buff *);
-/*
- * for future use, logic now to be in ST
- */
+ long (*recv) (void *, struct sk_buff *);
unsigned char (*match_packet) (const unsigned char *data);
-/*
- * subsequent registration return PENDING,
- * signalled complete by this callback function
- */
- void (*reg_complete_cb) (char data);
-/*
- * write function, sent in as NULL and to be returned to
- * protocol drivers
- */
+ void (*reg_complete_cb) (void *, char data);
long (*write) (struct sk_buff *skb);
+ void *priv_data;
};
-extern long st_register(struct st_proto_s *new_proto);
-extern long st_unregister(enum proto_type type);
+extern long st_register(struct st_proto_s *);
+extern long st_unregister(enum proto_type);
+extern struct platform_device *st_get_plat_device(void);
#endif /* ST_H */
diff --git a/drivers/staging/ti-st/st_core.c b/drivers/staging/ti-st/st_core.c
index 4e93694e1c2..063c9b1db1a 100644
--- a/drivers/staging/ti-st/st_core.c
+++ b/drivers/staging/ti-st/st_core.c
@@ -38,7 +38,7 @@
#include "st_ll.h"
#include "st.h"
-#ifdef DEBUG
+#define VERBOSE
/* strings to be used for rfkill entries and by
* ST Core to be used for sysfs debug entry
*/
@@ -48,7 +48,6 @@ const unsigned char *protocol_strngs[] = {
PROTO_ENTRY(ST_FM, "FM"),
PROTO_ENTRY(ST_GPS, "GPS"),
};
-#endif
/* function pointer pointing to either,
* st_kim_recv during registration to receive fw download responses
* st_int_recv after registration to receive proto stack responses
@@ -61,7 +60,7 @@ void (*st_recv) (void*, const unsigned char*, long);
bool is_protocol_list_empty(void)
{
unsigned char i = 0;
- pr_info(" %s ", __func__);
+ pr_debug(" %s ", __func__);
for (i = 0; i < ST_MAX; i++) {
if (st_gdata->list[i] != NULL)
return ST_NOTEMPTY;
@@ -71,6 +70,7 @@ bool is_protocol_list_empty(void)
return ST_EMPTY;
}
#endif
+
/* can be called in from
* -- KIM (during fw download)
* -- ST Core (during st_write)
@@ -81,20 +81,15 @@ bool is_protocol_list_empty(void)
int st_int_write(struct st_data_s *st_gdata,
const unsigned char *data, int count)
{
-#ifdef VERBOSE /* for debug */
- int i;
-#endif
struct tty_struct *tty;
if (unlikely(st_gdata == NULL || st_gdata->tty == NULL)) {
pr_err("tty unavailable to perform write");
- return ST_ERR_FAILURE;
+ return -1;
}
tty = st_gdata->tty;
#ifdef VERBOSE
- printk(KERN_ERR "start data..\n");
- for (i = 0; i < count; i++) /* no newlines for each datum */
- printk(" %x", data[i]);
- printk(KERN_ERR "\n ..end data\n");
+ print_hex_dump(KERN_DEBUG, "<out<", DUMP_PREFIX_NONE,
+ 16, 1, data, count, 0);
#endif
return tty->ops->write(tty, data, count);
@@ -122,8 +117,10 @@ void st_send_frame(enum proto_type protoid, struct st_data_s *st_gdata)
* protocol stack driver
*/
if (likely(st_gdata->list[protoid]->recv != NULL)) {
- if (unlikely(st_gdata->list[protoid]->recv(st_gdata->rx_skb)
- != ST_SUCCESS)) {
+ if (unlikely
+ (st_gdata->list[protoid]->recv
+ (st_gdata->list[protoid]->priv_data, st_gdata->rx_skb)
+ != 0)) {
pr_err(" proto stack %d's ->recv failed", protoid);
kfree_skb(st_gdata->rx_skb);
return;
@@ -132,11 +129,11 @@ void st_send_frame(enum proto_type protoid, struct st_data_s *st_gdata)
pr_err(" proto stack %d's ->recv null", protoid);
kfree_skb(st_gdata->rx_skb);
}
- pr_info(" done %s", __func__);
return;
}
-/*
+/**
+ * st_reg_complete -
* to call registration complete callbacks
* of all protocol stack drivers
*/
@@ -147,7 +144,8 @@ void st_reg_complete(struct st_data_s *st_gdata, char err)
for (i = 0; i < ST_MAX; i++) {
if (likely(st_gdata != NULL && st_gdata->list[i] != NULL &&
st_gdata->list[i]->reg_complete_cb != NULL))
- st_gdata->list[i]->reg_complete_cb(err);
+ st_gdata->list[i]->reg_complete_cb
+ (st_gdata->list[i]->priv_data, err);
}
}
@@ -156,7 +154,7 @@ static inline int st_check_data_len(struct st_data_s *st_gdata,
{
register int room = skb_tailroom(st_gdata->rx_skb);
- pr_info("len %d room %d", len, room);
+ pr_debug("len %d room %d", len, room);
if (!len) {
/* Received packet has only packet header and
@@ -190,8 +188,9 @@ static inline int st_check_data_len(struct st_data_s *st_gdata,
return 0;
}
-/* internal function for action when wake-up ack
- * received
+/**
+ * st_wakeup_ack - internal function for action when wake-up ack
+ * received
*/
static inline void st_wakeup_ack(struct st_data_s *st_gdata,
unsigned char cmd)
@@ -214,9 +213,13 @@ static inline void st_wakeup_ack(struct st_data_s *st_gdata,
st_tx_wakeup(st_gdata);
}
-/* Decodes received RAW data and forwards to corresponding
- * client drivers (Bluetooth,FM,GPS..etc).
- *
+/**
+ * st_int_recv - ST's internal receive function.
+ * Decodes received RAW data and forwards to corresponding
+ * client drivers (Bluetooth,FM,GPS..etc).
+ * This can receive various types of packets,
+ * HCI-Events, ACL, SCO, 4 types of HCI-LL PM packets
+ * CH-8 packets from FM, CH-9 packets from GPS cores.
*/
void st_int_recv(void *disc_data,
const unsigned char *data, long count)
@@ -259,7 +262,7 @@ void st_int_recv(void *disc_data,
/* Waiting for complete packet ? */
case ST_BT_W4_DATA:
- pr_info("Complete pkt received");
+ pr_debug("Complete pkt received");
/* Ask ST CORE to forward
* the packet to protocol driver */
@@ -275,7 +278,7 @@ void st_int_recv(void *disc_data,
eh = (struct hci_event_hdr *)st_gdata->rx_skb->
data;
- pr_info("Event header: evt 0x%2.2x"
+ pr_debug("Event header: evt 0x%2.2x"
"plen %d", eh->evt, eh->plen);
st_check_data_len(st_gdata, protoid, eh->plen);
@@ -439,45 +442,43 @@ void st_int_recv(void *disc_data,
break;
}
}
- pr_info("done %s", __func__);
+ pr_debug("done %s", __func__);
return;
}
-/* internal de-Q function
- * -- return previous in-completely written skb
- * or return the skb in the txQ
+/**
+ * st_int_dequeue - internal de-Q function.
+ * If the previous data set was not written
+ * completely, return that skb which has the pending data.
+ * In normal cases, return top of txq.
*/
struct sk_buff *st_int_dequeue(struct st_data_s *st_gdata)
{
struct sk_buff *returning_skb;
- pr_info("%s", __func__);
- /* if the previous skb wasn't written completely
- */
+ pr_debug("%s", __func__);
if (st_gdata->tx_skb != NULL) {
returning_skb = st_gdata->tx_skb;
st_gdata->tx_skb = NULL;
return returning_skb;
}
-
- /* de-Q from the txQ always if previous write is complete */
return skb_dequeue(&st_gdata->txq);
}
-/* internal Q-ing function
- * will either Q the skb to txq or the tx_waitq
- * depending on the ST LL state
- *
- * lock the whole func - since ll_getstate and Q-ing should happen
- * in one-shot
+/**
+ * st_int_enqueue - internal Q-ing function.
+ * Will either Q the skb to txq or the tx_waitq
+ * depending on the ST LL state.
+ * If the chip is asleep, then Q it onto waitq and
+ * wakeup the chip.
+ * txq and waitq needs protection since the other contexts
+ * may be sending data, waking up chip.
*/
void st_int_enqueue(struct st_data_s *st_gdata, struct sk_buff *skb)
{
unsigned long flags = 0;
- pr_info("%s", __func__);
- /* this function can be invoked in more then one context.
- * so have a lock */
+ pr_debug("%s", __func__);
spin_lock_irqsave(&st_gdata->lock, flags);
switch (st_ll_getstate(st_gdata)) {
@@ -488,16 +489,12 @@ void st_int_enqueue(struct st_data_s *st_gdata, struct sk_buff *skb)
case ST_LL_ASLEEP_TO_AWAKE:
skb_queue_tail(&st_gdata->tx_waitq, skb);
break;
- case ST_LL_AWAKE_TO_ASLEEP: /* host cannot be in this state */
+ case ST_LL_AWAKE_TO_ASLEEP:
pr_err("ST LL is illegal state(%ld),"
"purging received skb.", st_ll_getstate(st_gdata));
kfree_skb(skb);
break;
-
case ST_LL_ASLEEP:
- /* call a function of ST LL to put data
- * in tx_waitQ and wake_ind in txQ
- */
skb_queue_tail(&st_gdata->tx_waitq, skb);
st_ll_wakeup(st_gdata);
break;
@@ -507,8 +504,9 @@ void st_int_enqueue(struct st_data_s *st_gdata, struct sk_buff *skb)
kfree_skb(skb);
break;
}
+
spin_unlock_irqrestore(&st_gdata->lock, flags);
- pr_info("done %s", __func__);
+ pr_debug("done %s", __func__);
return;
}
@@ -522,7 +520,7 @@ void st_tx_wakeup(struct st_data_s *st_data)
{
struct sk_buff *skb;
unsigned long flags; /* for irq save flags */
- pr_info("%s", __func__);
+ pr_debug("%s", __func__);
/* check for sending & set flag sending here */
if (test_and_set_bit(ST_TX_SENDING, &st_data->tx_state)) {
pr_info("ST already sending");
@@ -563,33 +561,13 @@ void st_tx_wakeup(struct st_data_s *st_data)
/********************************************************************/
/* functions called from ST KIM
*/
-void kim_st_list_protocols(struct st_data_s *st_gdata, char *buf)
+void kim_st_list_protocols(struct st_data_s *st_gdata, void *buf)
{
- unsigned long flags = 0;
-#ifdef DEBUG
- unsigned char i = ST_MAX;
-#endif
- spin_lock_irqsave(&st_gdata->lock, flags);
-#ifdef DEBUG /* more detailed log */
- for (i = 0; i < ST_MAX; i++) {
- if (i == 0) {
- sprintf(buf, "%s is %s", protocol_strngs[i],
- st_gdata->list[i] !=
- NULL ? "Registered" : "Unregistered");
- } else {
- sprintf(buf, "%s\n%s is %s", buf, protocol_strngs[i],
- st_gdata->list[i] !=
- NULL ? "Registered" : "Unregistered");
- }
- }
- sprintf(buf, "%s\n", buf);
-#else /* limited info */
- sprintf(buf, "BT=%c\nFM=%c\nGPS=%c\n",
- st_gdata->list[ST_BT] != NULL ? 'R' : 'U',
- st_gdata->list[ST_FM] != NULL ? 'R' : 'U',
- st_gdata->list[ST_GPS] != NULL ? 'R' : 'U');
-#endif
- spin_unlock_irqrestore(&st_gdata->lock, flags);
+ seq_printf(buf, "[%d]\nBT=%c\nFM=%c\nGPS=%c\n",
+ st_gdata->protos_registered,
+ st_gdata->list[ST_BT] != NULL ? 'R' : 'U',
+ st_gdata->list[ST_FM] != NULL ? 'R' : 'U',
+ st_gdata->list[ST_GPS] != NULL ? 'R' : 'U');
}
/********************************************************************/
@@ -600,7 +578,7 @@ void kim_st_list_protocols(struct st_data_s *st_gdata, char *buf)
long st_register(struct st_proto_s *new_proto)
{
struct st_data_s *st_gdata;
- long err = ST_SUCCESS;
+ long err = 0;
unsigned long flags = 0;
st_kim_ref(&st_gdata);
@@ -608,17 +586,17 @@ long st_register(struct st_proto_s *new_proto)
if (st_gdata == NULL || new_proto == NULL || new_proto->recv == NULL
|| new_proto->reg_complete_cb == NULL) {
pr_err("gdata/new_proto/recv or reg_complete_cb not ready");
- return ST_ERR_FAILURE;
+ return -1;
}
if (new_proto->type < ST_BT || new_proto->type >= ST_MAX) {
pr_err("protocol %d not supported", new_proto->type);
- return ST_ERR_NOPROTO;
+ return -EPROTONOSUPPORT;
}
if (st_gdata->list[new_proto->type] != NULL) {
pr_err("protocol %d already registered", new_proto->type);
- return ST_ERR_ALREADY;
+ return -EALREADY;
}
/* can be from process context only */
@@ -630,11 +608,12 @@ long st_register(struct st_proto_s *new_proto)
st_kim_chip_toggle(new_proto->type, KIM_GPIO_ACTIVE);
st_gdata->list[new_proto->type] = new_proto;
+ st_gdata->protos_registered++;
new_proto->write = st_write;
set_bit(ST_REG_PENDING, &st_gdata->st_state);
spin_unlock_irqrestore(&st_gdata->lock, flags);
- return ST_ERR_PENDING;
+ return -EINPROGRESS;
} else if (st_gdata->protos_registered == ST_EMPTY) {
pr_info(" protocol list empty :%d ", new_proto->type);
set_bit(ST_REG_IN_PROGRESS, &st_gdata->st_state);
@@ -648,16 +627,16 @@ long st_register(struct st_proto_s *new_proto)
/* this may take a while to complete
* since it involves BT fw download
*/
- err = st_kim_start();
- if (err != ST_SUCCESS) {
+ err = st_kim_start(st_gdata->kim_data);
+ if (err != 0) {
clear_bit(ST_REG_IN_PROGRESS, &st_gdata->st_state);
if ((st_gdata->protos_registered != ST_EMPTY) &&
(test_bit(ST_REG_PENDING, &st_gdata->st_state))) {
pr_err(" KIM failure complete callback ");
- st_reg_complete(st_gdata, ST_ERR_FAILURE);
+ st_reg_complete(st_gdata, -1);
}
- return ST_ERR_FAILURE;
+ return -1;
}
/* the protocol might require other gpios to be toggled
@@ -672,9 +651,8 @@ long st_register(struct st_proto_s *new_proto)
*/
if ((st_gdata->protos_registered != ST_EMPTY) &&
(test_bit(ST_REG_PENDING, &st_gdata->st_state))) {
- pr_info(" call reg complete callback ");
- st_gdata->protos_registered++;
- st_reg_complete(st_gdata, ST_SUCCESS);
+ pr_debug(" call reg complete callback ");
+ st_reg_complete(st_gdata, 0);
}
clear_bit(ST_REG_PENDING, &st_gdata->st_state);
@@ -684,11 +662,12 @@ long st_register(struct st_proto_s *new_proto)
if (st_gdata->list[new_proto->type] != NULL) {
pr_err(" proto %d already registered ",
new_proto->type);
- return ST_ERR_ALREADY;
+ return -EALREADY;
}
spin_lock_irqsave(&st_gdata->lock, flags);
st_gdata->list[new_proto->type] = new_proto;
+ st_gdata->protos_registered++;
new_proto->write = st_write;
spin_unlock_irqrestore(&st_gdata->lock, flags);
return err;
@@ -707,18 +686,19 @@ long st_register(struct st_proto_s *new_proto)
default:
pr_err("%d protocol not supported",
new_proto->type);
- err = ST_ERR_NOPROTO;
+ err = -EPROTONOSUPPORT;
/* something wrong */
break;
}
st_gdata->list[new_proto->type] = new_proto;
+ st_gdata->protos_registered++;
new_proto->write = st_write;
/* lock already held before entering else */
spin_unlock_irqrestore(&st_gdata->lock, flags);
return err;
}
- pr_info("done %s(%d) ", __func__, new_proto->type);
+ pr_debug("done %s(%d) ", __func__, new_proto->type);
}
EXPORT_SYMBOL_GPL(st_register);
@@ -727,16 +707,16 @@ EXPORT_SYMBOL_GPL(st_register);
*/
long st_unregister(enum proto_type type)
{
- long err = ST_SUCCESS;
+ long err = 0;
unsigned long flags = 0;
struct st_data_s *st_gdata;
- pr_info("%s: %d ", __func__, type);
+ pr_debug("%s: %d ", __func__, type);
st_kim_ref(&st_gdata);
if (type < ST_BT || type >= ST_MAX) {
pr_err(" protocol %d not supported", type);
- return ST_ERR_NOPROTO;
+ return -EPROTONOSUPPORT;
}
spin_lock_irqsave(&st_gdata->lock, flags);
@@ -744,7 +724,7 @@ long st_unregister(enum proto_type type)
if (st_gdata->list[type] == NULL) {
pr_err(" protocol %d not registered", type);
spin_unlock_irqrestore(&st_gdata->lock, flags);
- return ST_ERR_NOPROTO;
+ return -EPROTONOSUPPORT;
}
st_gdata->protos_registered--;
@@ -768,7 +748,7 @@ long st_unregister(enum proto_type type)
}
/* all protocols now unregistered */
- st_kim_stop();
+ st_kim_stop(st_gdata->kim_data);
/* disable ST LL */
st_ll_disable(st_gdata);
}
@@ -791,7 +771,7 @@ long st_write(struct sk_buff *skb)
if (unlikely(skb == NULL || st_gdata == NULL
|| st_gdata->tty == NULL)) {
pr_err("data/tty unavailable to perform write");
- return ST_ERR_FAILURE;
+ return -1;
}
#ifdef DEBUG /* open-up skb to read the 1st byte */
switch (skb->data[0]) {
@@ -810,10 +790,10 @@ long st_write(struct sk_buff *skb)
if (unlikely(st_gdata->list[protoid] == NULL)) {
pr_err(" protocol %d not registered, and writing? ",
protoid);
- return ST_ERR_FAILURE;
+ return -1;
}
#endif
- pr_info("%d to be written", skb->len);
+ pr_debug("%d to be written", skb->len);
len = skb->len;
/* st_ll to decide where to enqueue the skb */
@@ -834,7 +814,7 @@ EXPORT_SYMBOL_GPL(st_unregister);
*/
static int st_tty_open(struct tty_struct *tty)
{
- int err = ST_SUCCESS;
+ int err = 0;
struct st_data_s *st_gdata;
pr_info("%s ", __func__);
@@ -855,8 +835,8 @@ static int st_tty_open(struct tty_struct *tty)
* signal to UIM via KIM that -
* installation of N_TI_WL ldisc is complete
*/
- st_kim_complete();
- pr_info("done %s", __func__);
+ st_kim_complete(st_gdata->kim_data);
+ pr_debug("done %s", __func__);
return err;
}
@@ -878,12 +858,13 @@ static void st_tty_close(struct tty_struct *tty)
pr_err("%d not un-registered", i);
st_gdata->list[i] = NULL;
}
+ st_gdata->protos_registered = 0;
spin_unlock_irqrestore(&st_gdata->lock, flags);
/*
* signal to UIM via KIM that -
* N_TI_WL ldisc is un-installed
*/
- st_kim_complete();
+ st_kim_complete(st_gdata->kim_data);
st_gdata->tty = NULL;
/* Flush any pending characters in the driver and discipline. */
tty_ldisc_flush(tty);
@@ -900,7 +881,7 @@ static void st_tty_close(struct tty_struct *tty)
st_gdata->rx_skb = NULL;
spin_unlock_irqrestore(&st_gdata->lock, flags);
- pr_info("%s: done ", __func__);
+ pr_debug("%s: done ", __func__);
}
static void st_tty_receive(struct tty_struct *tty, const unsigned char *data,
@@ -908,11 +889,8 @@ static void st_tty_receive(struct tty_struct *tty, const unsigned char *data,
{
#ifdef VERBOSE
- long i;
- printk(KERN_ERR "incoming data...\n");
- for (i = 0; i < count; i++)
- printk(" %x", data[i]);
- printk(KERN_ERR "\n.. data end\n");
+ print_hex_dump(KERN_DEBUG, ">in>", DUMP_PREFIX_NONE,
+ 16, 1, data, count, 0);
#endif
/*
@@ -920,7 +898,7 @@ static void st_tty_receive(struct tty_struct *tty, const unsigned char *data,
* to KIM for validation
*/
st_recv(tty->disc_data, data, count);
- pr_info("done %s", __func__);
+ pr_debug("done %s", __func__);
}
/* wake-up function called in from the TTY layer
@@ -929,7 +907,7 @@ static void st_tty_receive(struct tty_struct *tty, const unsigned char *data,
static void st_tty_wakeup(struct tty_struct *tty)
{
struct st_data_s *st_gdata = tty->disc_data;
- pr_info("%s ", __func__);
+ pr_debug("%s ", __func__);
/* don't do an wakeup for now */
clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
@@ -940,7 +918,7 @@ static void st_tty_wakeup(struct tty_struct *tty)
static void st_tty_flush_buffer(struct tty_struct *tty)
{
struct st_data_s *st_gdata = tty->disc_data;
- pr_info("%s ", __func__);
+ pr_debug("%s ", __func__);
kfree_skb(st_gdata->tx_skb);
st_gdata->tx_skb = NULL;
@@ -979,7 +957,7 @@ int st_core_init(struct st_data_s **core_data)
kfree(st_ldisc_ops);
return err;
}
- pr_info("registered n_shared line discipline");
+ pr_debug("registered n_shared line discipline");
st_gdata = kzalloc(sizeof(struct st_data_s), GFP_KERNEL);
if (!st_gdata) {
diff --git a/drivers/staging/ti-st/st_core.h b/drivers/staging/ti-st/st_core.h
index f271c88a808..e0c32d149f5 100644
--- a/drivers/staging/ti-st/st_core.h
+++ b/drivers/staging/ti-st/st_core.h
@@ -36,57 +36,87 @@
#define ST_REG_PENDING 3
#define ST_WAITING_FOR_RESP 4
-/*
- * local data required for ST/KIM/ST-HCI-LL
+/**
+ * struct st_data_s - ST core internal structure
+ * @st_state: different states of ST like initializing, registration
+ * in progress, this is mainly used to return relevant err codes
+ * when protocol drivers are registering. It is also used to track
+ * the recv function, as in during fw download only HCI events
+ * can occur , where as during other times other events CH8, CH9
+ * can occur.
+ * @tty: tty provided by the TTY core for line disciplines.
+ * @ldisc_ops: the procedures that this line discipline registers with TTY.
+ * @tx_skb: If for some reason the tty's write returns lesser bytes written
+ * then to maintain the rest of data to be written on next instance.
+ * This needs to be protected, hence the lock inside wakeup func.
+ * @tx_state: if the data is being written onto the TTY and protocol driver
+ * wants to send more, queue up data and mark that there is
+ * more data to send.
+ * @list: the list of protocols registered, only MAX can exist, one protocol
+ * can register only once.
+ * @rx_state: states to be maintained inside st's tty receive
+ * @rx_count: count to be maintained inside st's tty receieve
+ * @rx_skb: the skb where all data for a protocol gets accumulated,
+ * since tty might not call receive when a complete event packet
+ * is received, the states, count and the skb needs to be maintained.
+ * @txq: the list of skbs which needs to be sent onto the TTY.
+ * @tx_waitq: if the chip is not in AWAKE state, the skbs needs to be queued
+ * up in here, PM(WAKEUP_IND) data needs to be sent and then the skbs
+ * from waitq can be moved onto the txq.
+ * Needs locking too.
+ * @lock: the lock to protect skbs, queues, and ST states.
+ * @protos_registered: count of the protocols registered, also when 0 the
+ * chip enable gpio can be toggled, and when it changes to 1 the fw
+ * needs to be downloaded to initialize chip side ST.
+ * @ll_state: the various PM states the chip can be, the states are notified
+ * to us, when the chip sends relevant PM packets(SLEEP_IND, WAKE_IND).
+ * @kim_data: reference to the parent encapsulating structure.
+ *
*/
struct st_data_s {
unsigned long st_state;
-/*
- * an instance of tty_struct & ldisc ops to move around
- */
struct tty_struct *tty;
struct tty_ldisc_ops *ldisc_ops;
-/*
- * the tx skb -
- * if the skb is already dequeued and the tty failed to write the same
- * maintain the skb to write in the next transaction
- */
struct sk_buff *tx_skb;
#define ST_TX_SENDING 1
#define ST_TX_WAKEUP 2
unsigned long tx_state;
-/*
- * list of protocol registered
- */
struct st_proto_s *list[ST_MAX];
-/*
- * lock
- */
unsigned long rx_state;
unsigned long rx_count;
struct sk_buff *rx_skb;
struct sk_buff_head txq, tx_waitq;
- spinlock_t lock; /* ST LL state lock */
+ spinlock_t lock;
unsigned char protos_registered;
- unsigned long ll_state; /* ST LL power state */
+ unsigned long ll_state;
+ void *kim_data;
};
-/* point this to tty->driver->write or tty->ops->write
+/**
+ * st_int_write -
+ * point this to tty->driver->write or tty->ops->write
* depending upon the kernel version
*/
int st_int_write(struct st_data_s*, const unsigned char*, int);
-/* internal write function, passed onto protocol drivers
+
+/**
+ * st_write -
+ * internal write function, passed onto protocol drivers
* via the write function ptr of protocol struct
*/
long st_write(struct sk_buff *);
-/* function to be called from ST-LL
- */
+
+/* function to be called from ST-LL */
void st_ll_send_frame(enum proto_type, struct sk_buff *);
+
/* internal wake up function */
void st_tx_wakeup(struct st_data_s *st_data);
+/* init, exit entry funcs called from KIM */
int st_core_init(struct st_data_s **);
void st_core_exit(struct st_data_s *);
+
+/* ask for reference from KIM */
void st_kim_ref(struct st_data_s **);
#define GPS_STUB_TEST
diff --git a/drivers/staging/ti-st/st_kim.c b/drivers/staging/ti-st/st_kim.c
index 98cbabba384..b4a6c7fdc4e 100644
--- a/drivers/staging/ti-st/st_kim.c
+++ b/drivers/staging/ti-st/st_kim.c
@@ -26,6 +26,8 @@
#include <linux/delay.h>
#include <linux/wait.h>
#include <linux/gpio.h>
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
#include <linux/sched.h>
@@ -55,37 +57,10 @@ static struct platform_driver kim_platform_driver = {
},
};
-#ifndef LEGACY_RFKILL_SUPPORT
-static ssize_t show_pid(struct device *dev, struct device_attribute
- *attr, char *buf);
-static ssize_t store_pid(struct device *dev, struct device_attribute
- *devattr, char *buf, size_t count);
-static ssize_t show_list(struct device *dev, struct device_attribute
- *attr, char *buf);
-
-/* structures specific for sysfs entries */
-static struct kobj_attribute pid_attr =
-__ATTR(pid, 0644, (void *)show_pid, (void *)store_pid);
-
-static struct kobj_attribute list_protocols =
-__ATTR(protocols, 0444, (void *)show_list, NULL);
-
-static struct attribute *uim_attrs[] = {
- &pid_attr.attr,
- /* add more debug sysfs entries */
- &list_protocols.attr,
- NULL,
-};
-
-static struct attribute_group uim_attr_grp = {
- .attrs = uim_attrs,
-};
-#else
static int kim_toggle_radio(void*, bool);
static const struct rfkill_ops kim_rfkill_ops = {
.set_block = kim_toggle_radio,
};
-#endif /* LEGACY_RFKILL_SUPPORT */
/* strings to be used for rfkill entries and by
* ST Core to be used for sysfs debug entry
@@ -97,18 +72,19 @@ const unsigned char *protocol_names[] = {
PROTO_ENTRY(ST_GPS, "GPS"),
};
-struct kim_data_s *kim_gdata;
/**********************************************************************/
/* internal functions */
-/*
- * function to return whether the firmware response was proper
- * in case of error don't complete so that waiting for proper
- * response times out
+/**
+ * validate_firmware_response -
+ * function to return whether the firmware response was proper
+ * in case of error don't complete so that waiting for proper
+ * response times out
*/
-void validate_firmware_response(struct sk_buff *skb)
+void validate_firmware_response(struct kim_data_s *kim_gdata)
{
+ struct sk_buff *skb = kim_gdata->rx_skb;
if (unlikely(skb->data[5] != 0)) {
pr_err("no proper response during fw download");
pr_err("data6 %x", skb->data[5]);
@@ -122,14 +98,14 @@ void validate_firmware_response(struct sk_buff *skb)
/* check for data len received inside kim_int_recv
* most often hit the last case to update state to waiting for data
*/
-static inline int kim_check_data_len(int len)
+static inline int kim_check_data_len(struct kim_data_s *kim_gdata, int len)
{
register int room = skb_tailroom(kim_gdata->rx_skb);
- pr_info("len %d room %d", len, room);
+ pr_debug("len %d room %d", len, room);
if (!len) {
- validate_firmware_response(kim_gdata->rx_skb);
+ validate_firmware_response(kim_gdata);
} else if (len > room) {
/* Received packet's payload length is larger.
* We can't accommodate it in created skb.
@@ -155,18 +131,20 @@ static inline int kim_check_data_len(int len)
return 0;
}
-/* receive function called during firmware download
- * - firmware download responses on different UART drivers
- * have been observed to come in bursts of different
- * tty_receive and hence the logic
+/**
+ * kim_int_recv - receive function called during firmware download
+ * firmware download responses on different UART drivers
+ * have been observed to come in bursts of different
+ * tty_receive and hence the logic
*/
-void kim_int_recv(const unsigned char *data, long count)
+void kim_int_recv(struct kim_data_s *kim_gdata,
+ const unsigned char *data, long count)
{
register char *ptr;
struct hci_event_hdr *eh;
register int len = 0, type = 0;
- pr_info("%s", __func__);
+ pr_debug("%s", __func__);
/* Decode received bytes here */
ptr = (char *)data;
if (unlikely(ptr == NULL)) {
@@ -188,8 +166,8 @@ void kim_int_recv(const unsigned char *data, long count)
switch (kim_gdata->rx_state) {
/* Waiting for complete packet ? */
case ST_BT_W4_DATA:
- pr_info("Complete pkt received");
- validate_firmware_response(kim_gdata->rx_skb);
+ pr_debug("Complete pkt received");
+ validate_firmware_response(kim_gdata);
kim_gdata->rx_state = ST_W4_PACKET_TYPE;
kim_gdata->rx_skb = NULL;
continue;
@@ -197,9 +175,9 @@ void kim_int_recv(const unsigned char *data, long count)
case ST_BT_W4_EVENT_HDR:
eh = (struct hci_event_hdr *)kim_gdata->
rx_skb->data;
- pr_info("Event header: evt 0x%2.2x"
+ pr_debug("Event header: evt 0x%2.2x"
"plen %d", eh->evt, eh->plen);
- kim_check_data_len(eh->plen);
+ kim_check_data_len(kim_gdata, eh->plen);
continue;
} /* end of switch */
} /* end of if rx_state */
@@ -216,7 +194,7 @@ void kim_int_recv(const unsigned char *data, long count)
ptr++;
count--;
continue;
- } /* end of switch *ptr */
+ }
ptr++;
count--;
kim_gdata->rx_skb =
@@ -226,34 +204,35 @@ void kim_int_recv(const unsigned char *data, long count)
kim_gdata->rx_state = ST_W4_PACKET_TYPE;
kim_gdata->rx_count = 0;
return;
- } /* not necessary in this case */
+ }
bt_cb(kim_gdata->rx_skb)->pkt_type = type;
- } /* end of while count */
+ }
pr_info("done %s", __func__);
return;
}
-static long read_local_version(char *bts_scr_name)
+static long read_local_version(struct kim_data_s *kim_gdata, char *bts_scr_name)
{
unsigned short version = 0, chip = 0, min_ver = 0, maj_ver = 0;
char read_ver_cmd[] = { 0x01, 0x01, 0x10, 0x00 };
- pr_info("%s", __func__);
+ pr_debug("%s", __func__);
INIT_COMPLETION(kim_gdata->kim_rcvd);
if (4 != st_int_write(kim_gdata->core_data, read_ver_cmd, 4)) {
pr_err("kim: couldn't write 4 bytes");
- return ST_ERR_FAILURE;
+ return -1;
}
if (!wait_for_completion_timeout
(&kim_gdata->kim_rcvd, msecs_to_jiffies(CMD_RESP_TIME))) {
pr_err(" waiting for ver info- timed out ");
- return ST_ERR_FAILURE;
+ return -1;
}
version =
- MAKEWORD(kim_gdata->resp_buffer[13], kim_gdata->resp_buffer[14]);
+ MAKEWORD(kim_gdata->resp_buffer[13],
+ kim_gdata->resp_buffer[14]);
chip = (version & 0x7C00) >> 10;
min_ver = (version & 0x007F);
maj_ver = (version & 0x0380) >> 7;
@@ -262,25 +241,32 @@ static long read_local_version(char *bts_scr_name)
maj_ver |= 0x0008;
sprintf(bts_scr_name, "TIInit_%d.%d.%d.bts", chip, maj_ver, min_ver);
+
+ /* to be accessed later via sysfs entry */
+ kim_gdata->version.full = version;
+ kim_gdata->version.chip = chip;
+ kim_gdata->version.maj_ver = maj_ver;
+ kim_gdata->version.min_ver = min_ver;
+
pr_info("%s", bts_scr_name);
- return ST_SUCCESS;
+ return 0;
}
-/* internal function which parses through the .bts firmware script file
- * intreprets SEND, DELAY actions only as of now
+/**
+ * download_firmware -
+ * internal function which parses through the .bts firmware
+ * script file intreprets SEND, DELAY actions only as of now
*/
-static long download_firmware(void)
+static long download_firmware(struct kim_data_s *kim_gdata)
{
- long err = ST_SUCCESS;
+ long err = 0;
long len = 0;
register unsigned char *ptr = NULL;
register unsigned char *action_ptr = NULL;
unsigned char bts_scr_name[30] = { 0 }; /* 30 char long bts scr name? */
- pr_info("%s", __func__);
-
- err = read_local_version(bts_scr_name);
- if (err != ST_SUCCESS) {
+ err = read_local_version(kim_gdata, bts_scr_name);
+ if (err != 0) {
pr_err("kim: failed to read local ver");
return err;
}
@@ -291,7 +277,7 @@ static long download_firmware(void)
(kim_gdata->fw_entry->size == 0))) {
pr_err(" request_firmware failed(errno %ld) for %s", err,
bts_scr_name);
- return ST_ERR_FAILURE;
+ return -1;
}
ptr = (void *)kim_gdata->fw_entry->data;
len = kim_gdata->fw_entry->size;
@@ -302,7 +288,7 @@ static long download_firmware(void)
len -= sizeof(struct bts_header);
while (len > 0 && ptr) {
- pr_info(" action size %d, type %d ",
+ pr_debug(" action size %d, type %d ",
((struct bts_action *)ptr)->size,
((struct bts_action *)ptr)->type);
@@ -315,8 +301,8 @@ static long download_firmware(void)
/* ignore remote change
* baud rate HCI VS command */
pr_err
- (" change remote baud\
- rate command in firmware");
+ (" change remote baud"
+ " rate command in firmware");
break;
}
@@ -326,7 +312,7 @@ static long download_firmware(void)
((struct bts_action *)ptr)->size);
if (unlikely(err < 0)) {
release_firmware(kim_gdata->fw_entry);
- return ST_ERR_FAILURE;
+ return -1;
}
if (!wait_for_completion_timeout
(&kim_gdata->kim_rcvd,
@@ -335,7 +321,7 @@ static long download_firmware(void)
(" response timeout during fw download ");
/* timed out */
release_firmware(kim_gdata->fw_entry);
- return ST_ERR_FAILURE;
+ return -1;
}
break;
case ACTION_DELAY: /* sleep */
@@ -353,19 +339,23 @@ static long download_firmware(void)
}
/* fw download complete */
release_firmware(kim_gdata->fw_entry);
- return ST_SUCCESS;
+ return 0;
}
/**********************************************************************/
/* functions called from ST core */
-
/* function to toggle the GPIO
* needs to know whether the GPIO is active high or active low
*/
void st_kim_chip_toggle(enum proto_type type, enum kim_gpio_state state)
{
+ struct platform_device *kim_pdev;
+ struct kim_data_s *kim_gdata;
pr_info(" %s ", __func__);
+ kim_pdev = st_get_plat_device();
+ kim_gdata = dev_get_drvdata(&kim_pdev->dev);
+
if (kim_gdata->gpios[type] == -1) {
pr_info(" gpio not requested for protocol %s",
protocol_names[type]);
@@ -405,6 +395,9 @@ void st_kim_chip_toggle(enum proto_type type, enum kim_gpio_state state)
*/
void st_kim_recv(void *disc_data, const unsigned char *data, long count)
{
+ struct st_data_s *st_gdata = (struct st_data_s *)disc_data;
+ struct kim_data_s *kim_gdata = st_gdata->kim_data;
+
pr_info(" %s ", __func__);
/* copy to local buffer */
if (unlikely(data[4] == 0x01 && data[5] == 0x10 && data[0] == 0x04)) {
@@ -413,7 +406,7 @@ void st_kim_recv(void *disc_data, const unsigned char *data, long count)
complete_all(&kim_gdata->kim_rcvd);
return;
} else {
- kim_int_recv(data, count);
+ kim_int_recv(kim_gdata, data, count);
/* either completes or times out */
}
return;
@@ -422,27 +415,33 @@ void st_kim_recv(void *disc_data, const unsigned char *data, long count)
/* to signal completion of line discipline installation
* called from ST Core, upon tty_open
*/
-void st_kim_complete(void)
+void st_kim_complete(void *kim_data)
{
+ struct kim_data_s *kim_gdata = (struct kim_data_s *)kim_data;
complete(&kim_gdata->ldisc_installed);
}
-/* called from ST Core upon 1st registration
-*/
-long st_kim_start(void)
+/**
+ * st_kim_start - called from ST Core upon 1st registration
+ * This involves toggling the chip enable gpio, reading
+ * the firmware version from chip, forming the fw file name
+ * based on the chip version, requesting the fw, parsing it
+ * and perform download(send/recv).
+ */
+long st_kim_start(void *kim_data)
{
- long err = ST_SUCCESS;
+ long err = 0;
long retry = POR_RETRY_COUNT;
+ struct kim_data_s *kim_gdata = (struct kim_data_s *)kim_data;
+
pr_info(" %s", __func__);
do {
-#ifdef LEGACY_RFKILL_SUPPORT
/* TODO: this is only because rfkill sub-system
* doesn't send events to user-space if the state
* isn't changed
*/
rfkill_set_hw_state(kim_gdata->rfkill[ST_BT], 1);
-#endif
/* Configure BT nShutdown to HIGH state */
gpio_set_value(kim_gdata->gpios[ST_BT], GPIO_LOW);
mdelay(5); /* FIXME: a proper toggle */
@@ -450,30 +449,29 @@ long st_kim_start(void)
mdelay(100);
/* re-initialize the completion */
INIT_COMPLETION(kim_gdata->ldisc_installed);
-#ifndef LEGACY_RFKILL_SUPPORT
+#if 0 /* older way of signalling user-space UIM */
/* send signal to UIM */
err = kill_pid(find_get_pid(kim_gdata->uim_pid), SIGUSR2, 0);
if (err != 0) {
pr_info(" sending SIGUSR2 to uim failed %ld", err);
- err = ST_ERR_FAILURE;
+ err = -1;
continue;
}
-#else
+#endif
/* unblock and send event to UIM via /dev/rfkill */
rfkill_set_hw_state(kim_gdata->rfkill[ST_BT], 0);
-#endif
/* wait for ldisc to be installed */
err = wait_for_completion_timeout(&kim_gdata->ldisc_installed,
msecs_to_jiffies(LDISC_TIME));
if (!err) { /* timeout */
pr_err("line disc installation timed out ");
- err = ST_ERR_FAILURE;
+ err = -1;
continue;
} else {
/* ldisc installed now */
pr_info(" line discipline installed ");
- err = download_firmware();
- if (err != ST_SUCCESS) {
+ err = download_firmware(kim_gdata);
+ if (err != 0) {
pr_err("download firmware failed");
continue;
} else { /* on success don't retry */
@@ -484,31 +482,33 @@ long st_kim_start(void)
return err;
}
-/* called from ST Core, on the last un-registration
-*/
-long st_kim_stop(void)
+/**
+ * st_kim_stop - called from ST Core, on the last un-registration
+ * toggle low the chip enable gpio
+ */
+long st_kim_stop(void *kim_data)
{
- long err = ST_SUCCESS;
+ long err = 0;
+ struct kim_data_s *kim_gdata = (struct kim_data_s *)kim_data;
INIT_COMPLETION(kim_gdata->ldisc_installed);
-#ifndef LEGACY_RFKILL_SUPPORT
+#if 0 /* older way of signalling user-space UIM */
/* send signal to UIM */
err = kill_pid(find_get_pid(kim_gdata->uim_pid), SIGUSR2, 1);
if (err != 0) {
pr_err("sending SIGUSR2 to uim failed %ld", err);
- return ST_ERR_FAILURE;
+ return -1;
}
-#else
+#endif
/* set BT rfkill to be blocked */
err = rfkill_set_hw_state(kim_gdata->rfkill[ST_BT], 1);
-#endif
/* wait for ldisc to be un-installed */
err = wait_for_completion_timeout(&kim_gdata->ldisc_installed,
msecs_to_jiffies(LDISC_TIME));
if (!err) { /* timeout */
pr_err(" timed out waiting for ldisc to be un-installed");
- return ST_ERR_FAILURE;
+ return -1;
}
/* By default configure BT nShutdown to LOW state */
@@ -522,37 +522,24 @@ long st_kim_stop(void)
/**********************************************************************/
/* functions called from subsystems */
+/* called when debugfs entry is read from */
-#ifndef LEGACY_RFKILL_SUPPORT
-/* called when sysfs entry is written to */
-static ssize_t store_pid(struct device *dev, struct device_attribute
- *devattr, char *buf, size_t count)
+static int show_version(struct seq_file *s, void *unused)
{
- pr_info("%s: pid %s ", __func__, buf);
- sscanf(buf, "%ld", &kim_gdata->uim_pid);
- /* to be made use by kim_start to signal SIGUSR2
- */
- return strlen(buf);
-}
-
-/* called when sysfs entry is read from */
-static ssize_t show_pid(struct device *dev, struct device_attribute
- *attr, char *buf)
-{
- sprintf(buf, "%ld", kim_gdata->uim_pid);
- return strlen(buf);
+ struct kim_data_s *kim_gdata = (struct kim_data_s *)s->private;
+ seq_printf(s, "%04X %d.%d.%d\n", kim_gdata->version.full,
+ kim_gdata->version.chip, kim_gdata->version.maj_ver,
+ kim_gdata->version.min_ver);
+ return 0;
}
-/* called when sysfs entry is read from */
-static ssize_t show_list(struct device *dev, struct device_attribute
- *attr, char *buf)
+static int show_list(struct seq_file *s, void *unused)
{
- kim_st_list_protocols(kim_gdata->core_data, buf);
- return strlen(buf);
+ struct kim_data_s *kim_gdata = (struct kim_data_s *)s->private;
+ kim_st_list_protocols(kim_gdata->core_data, s);
+ return 0;
}
-#else /* LEGACY_RFKILL_SUPPORT */
-
/* function called from rfkill subsystem, when someone from
* user space would write 0/1 on the sysfs entry
* /sys/class/rfkill/rfkill0,1,3/state
@@ -560,7 +547,7 @@ static ssize_t show_list(struct device *dev, struct device_attribute
static int kim_toggle_radio(void *data, bool blocked)
{
enum proto_type type = *((enum proto_type *)data);
- pr_info(" %s: %d ", __func__, type);
+ pr_debug(" %s: %d ", __func__, type);
switch (type) {
case ST_BT:
@@ -577,33 +564,79 @@ static int kim_toggle_radio(void *data, bool blocked)
pr_err(" wrong proto type ");
break;
}
- return ST_SUCCESS;
+ return 0;
}
-#endif /* LEGACY_RFKILL_SUPPORT */
-
+/**
+ * st_kim_ref - reference the core's data
+ * This references the per-ST platform device in the arch/xx/
+ * board-xx.c file.
+ * This would enable multiple such platform devices to exist
+ * on a given platform
+ */
void st_kim_ref(struct st_data_s **core_data)
{
+ struct platform_device *pdev;
+ struct kim_data_s *kim_gdata;
+ /* get kim_gdata reference from platform device */
+ pdev = st_get_plat_device();
+ kim_gdata = dev_get_drvdata(&pdev->dev);
*core_data = kim_gdata->core_data;
}
+static int kim_version_open(struct inode *i, struct file *f)
+{
+ return single_open(f, show_version, i->i_private);
+}
+
+static int kim_list_open(struct inode *i, struct file *f)
+{
+ return single_open(f, show_list, i->i_private);
+}
+
+static const struct file_operations version_debugfs_fops = {
+ /* version info */
+ .open = kim_version_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+static const struct file_operations list_debugfs_fops = {
+ /* protocols info */
+ .open = kim_list_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
/**********************************************************************/
/* functions called from platform device driver subsystem
* need to have a relevant platform device entry in the platform's
* board-*.c file
*/
+struct dentry *kim_debugfs_dir;
static int kim_probe(struct platform_device *pdev)
{
long status;
long proto;
long *gpios = pdev->dev.platform_data;
+ struct kim_data_s *kim_gdata;
+
+ kim_gdata = kzalloc(sizeof(struct kim_data_s), GFP_ATOMIC);
+ if (!kim_gdata) {
+ pr_err("no mem to allocate");
+ return -ENOMEM;
+ }
+ dev_set_drvdata(&pdev->dev, kim_gdata);
status = st_core_init(&kim_gdata->core_data);
if (status != 0) {
pr_err(" ST core init failed");
- return ST_ERR_FAILURE;
+ return -1;
}
+ /* refer to itself */
+ kim_gdata->core_data->kim_data = kim_gdata;
for (proto = 0; proto < ST_MAX; proto++) {
kim_gdata->gpios[proto] = gpios[proto];
@@ -639,30 +672,12 @@ static int kim_probe(struct platform_device *pdev)
return status;
}
}
-#ifndef LEGACY_RFKILL_SUPPORT
- /* pdev to contain BT, FM and GPS enable/N-Shutdown GPIOs
- * execute request_gpio, set output direction
- */
- kim_gdata->kim_kobj = kobject_create_and_add("uim", NULL);
- /* create the sysfs entry for UIM to put in pid */
- if (sysfs_create_group(kim_gdata->kim_kobj, &uim_attr_grp)) {
- pr_err(" sysfs entry creation failed");
- kobject_put(kim_gdata->kim_kobj);
- /* free requested GPIOs and fail probe */
- for (proto = ST_BT; proto < ST_MAX; proto++) {
- if (gpios[proto] != -1)
- gpio_free(gpios[proto]);
- }
- return -1; /* fail insmod */
- }
- pr_info(" sysfs entry created ");
-#endif
/* get reference of pdev for request_firmware
*/
kim_gdata->kim_pdev = pdev;
init_completion(&kim_gdata->kim_rcvd);
init_completion(&kim_gdata->ldisc_installed);
-#ifdef LEGACY_RFKILL_SUPPORT
+
for (proto = 0; (proto < ST_MAX) && (gpios[proto] != -1); proto++) {
/* TODO: should all types be rfkill_type_bt ? */
kim_gdata->rf_protos[proto] = proto;
@@ -685,8 +700,20 @@ static int kim_probe(struct platform_device *pdev)
}
pr_info("rfkill entry created for %ld", gpios[proto]);
}
-#endif
- return ST_SUCCESS;
+
+ kim_debugfs_dir = debugfs_create_dir("ti-st", NULL);
+ if (IS_ERR(kim_debugfs_dir)) {
+ pr_err(" debugfs entries creation failed ");
+ kim_debugfs_dir = NULL;
+ return -1;
+ }
+
+ debugfs_create_file("version", S_IRUGO, kim_debugfs_dir,
+ kim_gdata, &version_debugfs_fops);
+ debugfs_create_file("protocols", S_IRUGO, kim_debugfs_dir,
+ kim_gdata, &list_debugfs_fops);
+ pr_info(" debugfs entries created ");
+ return 0;
}
static int kim_remove(struct platform_device *pdev)
@@ -695,27 +722,27 @@ static int kim_remove(struct platform_device *pdev)
*/
long *gpios = pdev->dev.platform_data;
long proto;
+ struct kim_data_s *kim_gdata;
+
+ kim_gdata = dev_get_drvdata(&pdev->dev);
for (proto = 0; (proto < ST_MAX) && (gpios[proto] != -1); proto++) {
/* Claim the Bluetooth/FM/GPIO
* nShutdown gpio from the system
*/
gpio_free(gpios[proto]);
-#ifdef LEGACY_RFKILL_SUPPORT
rfkill_unregister(kim_gdata->rfkill[proto]);
rfkill_destroy(kim_gdata->rfkill[proto]);
kim_gdata->rfkill[proto] = NULL;
-#endif
}
pr_info("kim: GPIO Freed");
-#ifndef LEGACY_RFKILL_SUPPORT
- /* delete the sysfs entries */
- sysfs_remove_group(kim_gdata->kim_kobj, &uim_attr_grp);
- kobject_put(kim_gdata->kim_kobj);
-#endif
+ debugfs_remove_recursive(kim_debugfs_dir);
kim_gdata->kim_pdev = NULL;
st_core_exit(kim_gdata->core_data);
- return ST_SUCCESS;
+
+ kfree(kim_gdata);
+ kim_gdata = NULL;
+ return 0;
}
/**********************************************************************/
@@ -723,27 +750,19 @@ static int kim_remove(struct platform_device *pdev)
static int __init st_kim_init(void)
{
- long ret = ST_SUCCESS;
- kim_gdata = kzalloc(sizeof(struct kim_data_s), GFP_ATOMIC);
- if (!kim_gdata) {
- pr_err("no mem to allocate");
- return -ENOMEM;
- }
-
+ long ret = 0;
ret = platform_driver_register(&kim_platform_driver);
if (ret != 0) {
pr_err("platform drv registration failed");
- return ST_ERR_FAILURE;
+ return -1;
}
- return ST_SUCCESS;
+ return 0;
}
static void __exit st_kim_deinit(void)
{
/* the following returns void */
platform_driver_unregister(&kim_platform_driver);
- kfree(kim_gdata);
- kim_gdata = NULL;
}
diff --git a/drivers/staging/ti-st/st_kim.h b/drivers/staging/ti-st/st_kim.h
index ff3270ec784..7de2541f2de 100644
--- a/drivers/staging/ti-st/st_kim.h
+++ b/drivers/staging/ti-st/st_kim.h
@@ -43,50 +43,72 @@
* since the self-test for chip takes a while
*/
#define POR_RETRY_COUNT 5
-/*
- * legacy rfkill support where-in 3 rfkill
- * devices are created for the 3 gpios
- * that ST has requested
+
+/**
+ * struct chip_version - save the chip version
*/
-#define LEGACY_RFKILL_SUPPORT
-/*
- * header file for ST provided by KIM
+struct chip_version {
+ unsigned short full;
+ unsigned short chip;
+ unsigned short min_ver;
+ unsigned short maj_ver;
+};
+
+/**
+ * struct kim_data_s - the KIM internal data, embedded as the
+ * platform's drv data. One for each ST device in the system.
+ * @uim_pid: KIM needs to communicate with UIM to request to install
+ * the ldisc by opening UART when protocol drivers register.
+ * @kim_pdev: the platform device added in one of the board-XX.c file
+ * in arch/XX/ directory, 1 for each ST device.
+ * @kim_rcvd: completion handler to notify when data was received,
+ * mainly used during fw download, which involves multiple send/wait
+ * for each of the HCI-VS commands.
+ * @ldisc_installed: completion handler to notify that the UIM accepted
+ * the request to install ldisc, notify from tty_open which suggests
+ * the ldisc was properly installed.
+ * @resp_buffer: data buffer for the .bts fw file name.
+ * @fw_entry: firmware class struct to request/release the fw.
+ * @gpios: the list of core/chip enable gpios for BT, FM and GPS cores.
+ * @rx_state: the rx state for kim's receive func during fw download.
+ * @rx_count: the rx count for the kim's receive func during fw download.
+ * @rx_skb: all of fw data might not come at once, and hence data storage for
+ * whole of the fw response, only HCI_EVENTs and hence diff from ST's
+ * response.
+ * @rfkill: rfkill data for each of the cores to be registered with rfkill.
+ * @rf_protos: proto types of the data registered with rfkill sub-system.
+ * @core_data: ST core's data, which mainly is the tty's disc_data
+ * @version: chip version available via a sysfs entry.
+ *
*/
struct kim_data_s {
long uim_pid;
struct platform_device *kim_pdev;
struct completion kim_rcvd, ldisc_installed;
- /* MAX len of the .bts firmware script name */
char resp_buffer[30];
const struct firmware *fw_entry;
long gpios[ST_MAX];
- struct kobject *kim_kobj;
-/* used by kim_int_recv to validate fw response */
unsigned long rx_state;
unsigned long rx_count;
struct sk_buff *rx_skb;
-#ifdef LEGACY_RFKILL_SUPPORT
struct rfkill *rfkill[ST_MAX];
enum proto_type rf_protos[ST_MAX];
-#endif
struct st_data_s *core_data;
+ struct chip_version version;
};
-long st_kim_start(void);
-long st_kim_stop(void);
-/*
- * called from st_tty_receive to authenticate fw_download
+/**
+ * functions called when 1 of the protocol drivers gets
+ * registered, these need to communicate with UIM to request
+ * ldisc installed, read chip_version, download relevant fw
*/
-void st_kim_recv(void *, const unsigned char *, long count);
+long st_kim_start(void *);
+long st_kim_stop(void *);
+void st_kim_recv(void *, const unsigned char *, long count);
void st_kim_chip_toggle(enum proto_type, enum kim_gpio_state);
-
-void st_kim_complete(void);
-
-/* function called from ST KIM to ST Core, to
- * list out the protocols registered
- */
-void kim_st_list_protocols(struct st_data_s *, char *);
+void st_kim_complete(void *);
+void kim_st_list_protocols(struct st_data_s *, void *);
/*
* BTS headers
@@ -98,9 +120,13 @@ void kim_st_list_protocols(struct st_data_s *, char *);
#define ACTION_RUN_SCRIPT 5
#define ACTION_REMARKS 6
-/*
- * * BRF Firmware header
- * */
+/**
+ * struct bts_header - the fw file is NOT binary which can
+ * be sent onto TTY as is. The .bts is more a script
+ * file which has different types of actions.
+ * Each such action needs to be parsed by the KIM and
+ * relevant procedure to be called.
+ */
struct bts_header {
uint32_t magic;
uint32_t version;
@@ -108,9 +134,10 @@ struct bts_header {
uint8_t actions[0];
} __attribute__ ((packed));
-/*
- * * BRF Actions structure
- * */
+/**
+ * struct bts_action - Each .bts action has its own type of
+ * data.
+ */
struct bts_action {
uint16_t type;
uint16_t size;
@@ -136,8 +163,11 @@ struct bts_action_serial {
uint32_t flow_control;
} __attribute__ ((packed));
-/* for identifying the change speed HCI VS
- * command
+/**
+ * struct hci_command - the HCI-VS for intrepreting
+ * the change baud rate of host-side UART, which
+ * needs to be ignored, since UIM would do that
+ * when it receives request from KIM for ldisc installation.
*/
struct hci_command {
uint8_t prefix;
diff --git a/drivers/staging/ti-st/st_ll.c b/drivers/staging/ti-st/st_ll.c
index 0685a100db6..7a1fb6de830 100644
--- a/drivers/staging/ti-st/st_ll.c
+++ b/drivers/staging/ti-st/st_ll.c
@@ -34,7 +34,7 @@ static void send_ll_cmd(struct st_data_s *st_data,
static void ll_device_want_to_sleep(struct st_data_s *st_data)
{
- pr_info("%s", __func__);
+ pr_debug("%s", __func__);
/* sanity check */
if (st_data->ll_state != ST_LL_AWAKE)
pr_err("ERR hcill: ST_LL_GO_TO_SLEEP_IND"
@@ -101,7 +101,7 @@ void st_ll_wakeup(struct st_data_s *ll)
/* called when ST Core wants the state */
unsigned long st_ll_getstate(struct st_data_s *ll)
{
- pr_info(" returning state %ld", ll->ll_state);
+ pr_debug(" returning state %ld", ll->ll_state);
return ll->ll_state;
}
@@ -127,9 +127,9 @@ unsigned long st_ll_sleep_state(struct st_data_s *st_data,
break;
default:
pr_err(" unknown input/state ");
- return ST_ERR_FAILURE;
+ return -1;
}
- return ST_SUCCESS;
+ return 0;
}
/* Called from ST CORE to initialize ST LL */
diff --git a/drivers/staging/ti-st/st_ll.h b/drivers/staging/ti-st/st_ll.h
index 77dfbf07e7b..e4dfacd83d9 100644
--- a/drivers/staging/ti-st/st_ll.h
+++ b/drivers/staging/ti-st/st_ll.h
@@ -41,6 +41,7 @@
#define ST_LL_AWAKE_TO_ASLEEP 3
#define ST_LL_INVALID 4
+/* different PM notifications coming from chip */
#define LL_SLEEP_IND 0x30
#define LL_SLEEP_ACK 0x31
#define LL_WAKE_UP_IND 0x32
@@ -50,13 +51,19 @@
long st_ll_init(struct st_data_s *);
long st_ll_deinit(struct st_data_s *);
-/* enable/disable ST LL along with KIM start/stop
+/**
+ * enable/disable ST LL along with KIM start/stop
* called by ST Core
*/
void st_ll_enable(struct st_data_s *);
void st_ll_disable(struct st_data_s *);
+/**
+ * various funcs used by ST core to set/get the various PM states
+ * of the chip.
+ */
unsigned long st_ll_getstate(struct st_data_s *);
unsigned long st_ll_sleep_state(struct st_data_s *, unsigned char);
void st_ll_wakeup(struct st_data_s *);
+
#endif /* ST_LL_H */
diff --git a/drivers/staging/ti-st/sysfs-uim b/drivers/staging/ti-st/sysfs-uim
index 10311afcbd4..626bda51ee8 100644
--- a/drivers/staging/ti-st/sysfs-uim
+++ b/drivers/staging/ti-st/sysfs-uim
@@ -14,3 +14,15 @@ Description:
uninstallation would be ppolling on this device and listening
on events which would suggest either to install or un-install
line discipline
+
+What: /sys/kernel/debug/ti-st/version
+Contact: Pavan Savoy <pavan_savoy@ti.com>
+Description:
+ WiLink chip's ROM version exposed to user-space for some
+ proprietary protocol stacks to make use of.
+
+What: /sys/kernel/debug/ti-st/protocols
+Contact: Pavan Savoy <pavan_savoy@ti.com>
+Description:
+ The reason for chip being ON, the list of protocols registered.
+
diff --git a/drivers/staging/tidspbridge/Documentation/CONTRIBUTORS b/drivers/staging/tidspbridge/Documentation/CONTRIBUTORS
new file mode 100644
index 00000000000..86f578727f9
--- /dev/null
+++ b/drivers/staging/tidspbridge/Documentation/CONTRIBUTORS
@@ -0,0 +1,45 @@
+TI DSP/Bridge Driver - Contributors File
+
+The DSP/Bridge project wish to thank all of its contributors, current bridge
+driver is the result of the work of all of them. If any name is accidentally
+omitted, let us know by sending a mail to omar.ramirez@ti.com or
+x095840@ti.com.
+
+Please keep the following list in alphabetical order.
+
+ Suman Anna
+ Sripal Bagadia
+ Felipe Balbi
+ Ohad Ben-Cohen
+ Phil Carmody
+ Deepak Chitriki
+ Felipe Contreras
+ Hiroshi Doyu
+ Seth Forshee
+ Ivan Gomez Castellanos
+ Mark Grosen
+ Ramesh Gupta G
+ Fernando Guzman Lugo
+ Axel Haslam
+ Janet Head
+ Shivananda Hebbar
+ Hari Kanigeri
+ Tony Lindgren
+ Antonio Luna
+ Hari Nagalla
+ Nishanth Menon
+ Ameya Palande
+ Vijay Pasam
+ Gilbert Pitney
+ Omar Ramirez Luna
+ Ernesto Ramos
+ Chris Ring
+ Larry Schiefer
+ Rebecca Schultz Zavin
+ Bhavin Shah
+ Andy Shevchenko
+ Jeff Taylor
+ Roman Tereshonkov
+ Armando Uribe de Leon
+ Nischal Varide
+ Wenbiao Wang
diff --git a/drivers/staging/tidspbridge/Documentation/README b/drivers/staging/tidspbridge/Documentation/README
new file mode 100644
index 00000000000..df6d371161e
--- /dev/null
+++ b/drivers/staging/tidspbridge/Documentation/README
@@ -0,0 +1,70 @@
+ Linux DSP/BIOS Bridge release
+
+DSP/BIOS Bridge overview
+========================
+
+DSP/BIOS Bridge is designed for platforms that contain a GPP and one or more
+attached DSPs. The GPP is considered the master or "host" processor, and the
+attached DSPs are processing resources that can be utilized by applications
+and drivers running on the GPP.
+
+The abstraction that DSP/BIOS Bridge supplies, is a direct link between a GPP
+program and a DSP task. This communication link is partitioned into two
+types of sub-links: messaging (short, fixed-length packets) and data
+streaming (multiple, large buffers). Each sub-link operates independently,
+and features in-order delivery of data, meaning that messages are delivered
+in the order they were submitted to the message link, and stream buffers are
+delivered in the order they were submitted to the stream link.
+
+In addition, a GPP client can specify what inputs and outputs a DSP task
+uses. DSP tasks typically use message objects for passing control and status
+information and stream objects for efficient streaming of real-time data.
+
+GPP Software Architecture
+=========================
+
+A GPP application communicates with its associated DSP task running on the
+DSP subsystem using the DSP/BIOS Bridge API. For example, a GPP audio
+application can use the API to pass messages to a DSP task that is managing
+data flowing from analog-to-digital converters (ADCs) to digital-to-analog
+converters (DACs).
+
+From the perspective of the GPP OS, the DSP is treated as just another
+peripheral device. Most high level GPP OS typically support a device driver
+model, whereby applications can safely access and share a hardware peripheral
+through standard driver interfaces. Therefore, to allow multiple GPP
+applications to share access to the DSP, the GPP side of DSP/BIOS Bridge
+implements a device driver for the DSP.
+
+Since driver interfaces are not always standard across GPP OS, and to provide
+some level of interoperability of application code using DSP/BIOS Bridge
+between GPP OS, DSP/BIOS Bridge provides a standard library of APIs which
+wrap calls into the device driver. So, rather than calling GPP OS specific
+driver interfaces, applications (and even other device drivers) can use the
+standard API library directly.
+
+DSP Software Architecture
+=========================
+
+For DSP/BIOS, DSP/BIOS Bridge adds a device-independent streaming I/O (STRM)
+interface, a messaging interface (NODE), and a Resource Manager (RM) Server.
+The RM Server runs as a task of DSP/BIOS and is subservient to commands
+and queries from the GPP. It executes commands to start and stop DSP signal
+processing nodes in response to GPP programs making requests through the
+(GPP-side) API.
+
+DSP tasks started by the RM Server are similar to any other DSP task with two
+important differences: they must follow a specific task model consisting of
+three C-callable functions (node create, execute, and delete), with specific
+sets of arguments, and they have a pre-defined task environment established
+by the RM Server.
+
+Tasks started by the RM Server communicate using the STRM and NODE interfaces
+and act as servers for their corresponding GPP clients, performing signal
+processing functions as requested by messages sent by their GPP client.
+Typically, a DSP task moves data from source devices to sink devices using
+device independent I/O streams, performing application-specific processing
+and transformations on the data while it is moved. For example, an audio
+task might perform audio decompression (ADPCM, MPEG, CELP) on data received
+from a GPP audio driver and then send the decompressed linear samples to a
+digital-to-analog converter.
diff --git a/drivers/staging/tidspbridge/Documentation/error-codes b/drivers/staging/tidspbridge/Documentation/error-codes
new file mode 100644
index 00000000000..12826e2a3aa
--- /dev/null
+++ b/drivers/staging/tidspbridge/Documentation/error-codes
@@ -0,0 +1,157 @@
+ DSP/Bridge Error Code Guide
+
+
+Success code is always taken as 0, except for one case where a success status
+different than 0 can be possible, this is when enumerating a series of dsp
+objects, if the enumeration doesn't have any more objects it is considered as a
+successful case. In this case a positive ENODATA is returned (TODO: Change to
+avoid this case).
+
+Error codes are returned as a negative 1, if an specific code is expected, it
+can be propagated to user space by reading errno symbol defined in errno.h, for
+specific details on the implementation a copy of the standard used should be
+read first.
+
+The error codes used by this driver are:
+
+[EPERM]
+ General driver failure.
+
+ According to the use case the following might apply:
+ - Device is in 'sleep/suspend' mode due to DPM.
+ - User cannot mark end of stream on an input channel.
+ - Requested operation is invalid for the node type.
+ - Invalid alignment for the node messaging buffer.
+ - The specified direction is invalid for the stream.
+ - Invalid stream mode.
+
+[ENOENT]
+ The specified object or file was not found.
+
+[ESRCH]
+ A shared memory buffer contained in a message or stream could not be mapped
+ to the GPP client process's virtual space.
+
+[EIO]
+ Driver interface I/O error.
+
+ or:
+ - Unable to plug channel ISR for configured IRQ.
+ - No free I/O request packets are available.
+
+[ENXIO]
+ Unable to find a named section in DSP executable or a non-existent memory
+ segment identifier was specified.
+
+[EBADF]
+ General error for file handling:
+
+ - Unable to open file.
+ - Unable to read file.
+ - An error occurred while parsing the DSP executable file.
+
+[ENOMEM]
+ A memory allocation failure occurred.
+
+[EACCES]
+ - Unable to read content of DCD data section; this is typically caused by
+ improperly configured nodes.
+ - Unable to decode DCD data section content; this is typically caused by
+ changes to DSP/BIOS Bridge data structures.
+ - Unable to get pointer to DCD data section; this is typically caused by
+ improperly configured UUIDs.
+ - Unable to load file containing DCD data section; this is typically
+ caused by a missing COFF file.
+ - The specified COFF file does not contain a valid node registration
+ section.
+
+[EFAULT]
+ Invalid pointer or handler.
+
+[EEXIST]
+ Attempted to create a channel manager when one already exists.
+
+[EINVAL]
+ Invalid argument.
+
+[ESPIPE]
+ Symbol not found in the COFF file. DSPNode_Create will return this if
+ the iAlg function table for an xDAIS socket is not found in the COFF file.
+ In this case, force the symbol to be linked into the COFF file.
+ DSPNode_Create, DSPNode_Execute, and DSPNode_Delete will return this if
+ the create, execute, or delete phase function, respectively, could not be
+ found in the COFF file.
+
+ - No symbol table is loaded/found for this board.
+ - Unable to initialize the ZL COFF parsing module.
+
+[EPIPE]
+ I/O is currently pending.
+
+ - End of stream was already requested on this output channel.
+
+[EDOM]
+ A parameter is specified outside its valid range.
+
+[ENOSYS]
+ The indicated operation is not supported.
+
+[EIDRM]
+ During enumeration a change in the number or properties of the objects
+ has occurred.
+
+[ECHRNG]
+ Attempt to created channel manager with too many channels or channel ID out
+ of range.
+
+[EBADR]
+ The state of the specified object is incorrect for the requested operation.
+
+ - Invalid segment ID.
+
+[ENODATA]
+ Unable to retrieve resource information from the registry.
+
+ - No more registry values.
+
+[ETIME]
+ A timeout occurred before the requested operation could complete.
+
+[ENOSR]
+ A stream has been issued the maximum number of buffers allowed in the
+ stream at once; buffers must be reclaimed from the stream before any more
+ can be issued.
+
+ - No free channels are available.
+
+[EILSEQ]
+ Error occurred in a dynamic loader library function.
+
+[EISCONN]
+ The Specified Connection already exists.
+
+[ENOTCONN]
+ Nodes not connected.
+
+[ETIMEDOUT]
+ Timeout occurred waiting for a response from the hardware.
+
+ - Wait for flush operation on an output channel timed out.
+
+[ECONNREFUSED]
+ No more connections can be made for this node.
+
+[EALREADY]
+ Channel is already in use.
+
+[EREMOTEIO]
+ dwTimeOut parameter was CHNL_IOCNOWAIT, yet no I/O completions were
+ queued.
+
+[ECANCELED]
+ I/O has been cancelled on this channel.
+
+[ENOKEY]
+ Invalid subkey parameter.
+
+ - UUID not found in registry.
diff --git a/drivers/staging/tidspbridge/Kconfig b/drivers/staging/tidspbridge/Kconfig
new file mode 100644
index 00000000000..93de4f2e8bf
--- /dev/null
+++ b/drivers/staging/tidspbridge/Kconfig
@@ -0,0 +1,90 @@
+#
+# DSP Bridge Driver Support
+#
+
+menuconfig TIDSPBRIDGE
+ tristate "DSP Bridge driver"
+ depends on ARCH_OMAP3
+ select OMAP_MBOX_FWK
+ help
+ DSP/BIOS Bridge is designed for platforms that contain a GPP and
+ one or more attached DSPs. The GPP is considered the master or
+ "host" processor, and the attached DSPs are processing resources
+ that can be utilized by applications and drivers running on the GPP.
+
+ This driver depends on OMAP Mailbox (OMAP_MBOX_FWK).
+
+config TIDSPBRIDGE_DVFS
+ bool "Enable Bridge Dynamic Voltage and Frequency Scaling (DVFS)"
+ depends on TIDSPBRIDGE && OMAP_PM_SRF && CPU_FREQ
+ help
+ DVFS allows DSP Bridge to initiate the operating point change to
+ scale the chip voltage and frequency in order to match the
+ performance and power consumption to the current processing
+ requirements.
+
+config TIDSPBRIDGE_MEMPOOL_SIZE
+ hex "Physical memory pool size (Byte)"
+ depends on TIDSPBRIDGE
+ default 0x600000
+ help
+ Allocate specified size of memory at booting time to avoid allocation
+ failure under heavy memory fragmentation after some use time.
+
+config TIDSPBRIDGE_DEBUG
+ bool "Debug Support"
+ depends on TIDSPBRIDGE
+ help
+ Say Y to enable Bridge debugging capabilities
+
+config TIDSPBRIDGE_RECOVERY
+ bool "Recovery Support"
+ depends on TIDSPBRIDGE
+ default y
+ help
+ In case of DSP fatal error, BRIDGE driver will try to
+ recover itself.
+
+config TIDSPBRIDGE_CACHE_LINE_CHECK
+ bool "Check buffers to be 128 byte aligned"
+ depends on TIDSPBRIDGE
+ help
+ When the DSP processes data, the DSP cache controller loads 128-Byte
+ chunks (lines) from SDRAM and writes the data back in 128-Byte chunks.
+ If a DMM buffer does not start and end on a 128-Byte boundary, the data
+ preceding the start address (SA) from the 128-Byte boundary to the SA
+ and the data at addresses trailing the end address (EA) from the EA to
+ the next 128-Byte boundary will be loaded and written back as well.
+ This can lead to heap corruption. Say Y, to enforce the check for 128
+ byte alignment, buffers failing this check will be rejected.
+
+config TIDSPBRIDGE_WDT3
+ bool "Enable watchdog timer"
+ depends on TIDSPBRIDGE
+ help
+ WTD3 is managed by DSP and once it is enabled, DSP side bridge is in
+ charge of refreshing the timer before overflow, if the DSP hangs MPU
+ will caught the interrupt and try to recover DSP.
+
+config TIDSPBRIDGE_WDT_TIMEOUT
+ int "Watchdog timer timeout (in secs)"
+ depends on TIDSPBRIDGE && TIDSPBRIDGE_WDT3
+ default 5
+ help
+ Watchdog timer timeout value, after that time if the watchdog timer
+ counter is not reset the wdt overflow interrupt will be triggered
+
+config TIDSPBRIDGE_NTFY_PWRERR
+ bool "Notify power errors"
+ depends on TIDSPBRIDGE
+ help
+ Enable notifications to registered clients on the event of power errror
+ trying to suspend bridge driver. Say Y, to signal this event as a fatal
+ error, this will require a bridge restart to recover.
+
+config TIDSPBRIDGE_BACKTRACE
+ bool "Dump backtraces on fatal errors"
+ depends on TIDSPBRIDGE
+ help
+ Enable useful information to backtrace fatal errors. Say Y if you
+ want to dump information for testing purposes.
diff --git a/drivers/staging/tidspbridge/Makefile b/drivers/staging/tidspbridge/Makefile
new file mode 100644
index 00000000000..65671724e6f
--- /dev/null
+++ b/drivers/staging/tidspbridge/Makefile
@@ -0,0 +1,34 @@
+obj-$(CONFIG_TIDSPBRIDGE) += bridgedriver.o
+
+libgen = gen/gb.o gen/gs.o gen/gh.o gen/uuidutil.o
+libservices = services/sync.o services/cfg.o \
+ services/ntfy.o services/services.o
+libcore = core/chnl_sm.o core/msg_sm.o core/io_sm.o core/tiomap3430.o \
+ core/tiomap3430_pwr.o core/tiomap_io.o \
+ core/ue_deh.o core/wdt.o core/dsp-clock.o
+libpmgr = pmgr/chnl.o pmgr/io.o pmgr/msg.o pmgr/cod.o pmgr/dev.o pmgr/dspapi.o \
+ pmgr/dmm.o pmgr/cmm.o pmgr/dbll.o
+librmgr = rmgr/dbdcd.o rmgr/disp.o rmgr/drv.o rmgr/mgr.o rmgr/node.o \
+ rmgr/proc.o rmgr/pwr.o rmgr/rmm.o rmgr/strm.o rmgr/dspdrv.o \
+ rmgr/nldr.o rmgr/drv_interface.o
+libdload = dynload/cload.o dynload/getsection.o dynload/reloc.o \
+ dynload/tramp.o
+libhw = hw/hw_mmu.o
+
+bridgedriver-objs = $(libgen) $(libservices) $(libcore) $(libpmgr) $(librmgr) \
+ $(libdload) $(libhw)
+
+#Machine dependent
+ccflags-y += -D_TI_ -D_DB_TIOMAP -DTMS32060 \
+ -DTICFG_PROC_VER -DTICFG_EVM_TYPE -DCHNL_SMCLASS \
+ -DCHNL_MESSAGES -DUSE_LEVEL_1_MACROS
+
+ccflags-y += -Idrivers/staging/tidspbridge/include
+ccflags-y += -Idrivers/staging/tidspbridge/services
+ccflags-y += -Idrivers/staging/tidspbridge/core
+ccflags-y += -Idrivers/staging/tidspbridge/pmgr
+ccflags-y += -Idrivers/staging/tidspbridge/rmgr
+ccflags-y += -Idrivers/staging/tidspbridge/dynload
+ccflags-y += -Idrivers/staging/tidspbridge/hw
+ccflags-y += -Iarch/arm
+
diff --git a/drivers/staging/tidspbridge/TODO b/drivers/staging/tidspbridge/TODO
new file mode 100644
index 00000000000..54f4a296738
--- /dev/null
+++ b/drivers/staging/tidspbridge/TODO
@@ -0,0 +1,18 @@
+* Migrate to (and if necessary, extend) existing upstream code such as
+ iommu, wdt, mcbsp, gptimers
+* Decouple hardware-specific code (e.g. bridge_brd_start/stop/delete/monitor)
+* DOFF binary loader: consider pushing to user space. at the very least
+ eliminate the direct filesystem access
+* Eliminate general services and libraries - use or extend existing kernel
+ libraries instead (e.g. gcf/lcm in nldr.c, global helpers in gen/)
+* Eliminate direct manipulation of OMAP_SYSC_BASE
+* Eliminate list.h : seem like a redundant wrapper to existing kernel lists
+* Eliminate DSP_SUCCEEDED macros and their imposed redundant indentations
+ (adopt the kernel way of checking for return values)
+* Audit interfaces exposed to user space
+* Audit and clean up header files folder
+* Use kernel coding style
+* checkpatch.pl fixes
+
+Please send any patches to Greg Kroah-Hartman <greg@kroah.com>
+and Omar Ramirez Luna <omar.ramirez@ti.com>.
diff --git a/drivers/staging/tidspbridge/core/_cmm.h b/drivers/staging/tidspbridge/core/_cmm.h
new file mode 100644
index 00000000000..7660bef6ebb
--- /dev/null
+++ b/drivers/staging/tidspbridge/core/_cmm.h
@@ -0,0 +1,45 @@
+/*
+ * _cmm.h
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * Private header file defining CMM manager objects and defines needed
+ * by IO manager to register shared memory regions when DSP base image
+ * is loaded(bridge_io_on_loaded).
+ *
+ * Copyright (C) 2005-2006 Texas Instruments, Inc.
+ *
+ * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef _CMM_
+#define _CMM_
+
+/*
+ * These target side symbols define the beginning and ending addresses
+ * of the section of shared memory used for shared memory manager CMM.
+ * They are defined in the *cfg.cmd file by cdb code.
+ */
+#define SHM0_SHARED_BASE_SYM "_SHM0_BEG"
+#define SHM0_SHARED_END_SYM "_SHM0_END"
+#define SHM0_SHARED_RESERVED_BASE_SYM "_SHM0_RSVDSTRT"
+
+/*
+ * Shared Memory Region #0(SHMSEG0) is used in the following way:
+ *
+ * |(_SHM0_BEG) | (_SHM0_RSVDSTRT) | (_SHM0_END)
+ * V V V
+ * ------------------------------------------------------------
+ * | DSP-side allocations | GPP-side allocations |
+ * ------------------------------------------------------------
+ *
+ *
+ */
+
+#endif /* _CMM_ */
diff --git a/drivers/staging/tidspbridge/core/_deh.h b/drivers/staging/tidspbridge/core/_deh.h
new file mode 100644
index 00000000000..16723cd3483
--- /dev/null
+++ b/drivers/staging/tidspbridge/core/_deh.h
@@ -0,0 +1,35 @@
+/*
+ * _deh.h
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * Private header for DEH module.
+ *
+ * Copyright (C) 2005-2006 Texas Instruments, Inc.
+ * Copyright (C) 2010 Felipe Contreras
+ *
+ * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef _DEH_
+#define _DEH_
+
+#include <dspbridge/ntfy.h>
+#include <dspbridge/dspdefs.h>
+
+/* DEH Manager: only one created per board: */
+struct deh_mgr {
+ struct bridge_dev_context *hbridge_context; /* Bridge context. */
+ struct ntfy_object *ntfy_obj; /* NTFY object */
+
+ /* MMU Fault DPC */
+ struct tasklet_struct dpc_tasklet;
+};
+
+#endif /* _DEH_ */
diff --git a/drivers/staging/tidspbridge/core/_msg_sm.h b/drivers/staging/tidspbridge/core/_msg_sm.h
new file mode 100644
index 00000000000..556de5c025d
--- /dev/null
+++ b/drivers/staging/tidspbridge/core/_msg_sm.h
@@ -0,0 +1,142 @@
+/*
+ * _msg_sm.h
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * Private header file defining msg_ctrl manager objects and defines needed
+ * by IO manager.
+ *
+ * Copyright (C) 2005-2006 Texas Instruments, Inc.
+ *
+ * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef _MSG_SM_
+#define _MSG_SM_
+
+#include <dspbridge/list.h>
+#include <dspbridge/msgdefs.h>
+
+/*
+ * These target side symbols define the beginning and ending addresses
+ * of the section of shared memory used for messages. They are
+ * defined in the *cfg.cmd file by cdb code.
+ */
+#define MSG_SHARED_BUFFER_BASE_SYM "_MSG_BEG"
+#define MSG_SHARED_BUFFER_LIMIT_SYM "_MSG_END"
+
+#ifndef _CHNL_WORDSIZE
+#define _CHNL_WORDSIZE 4 /* default _CHNL_WORDSIZE is 2 bytes/word */
+#endif
+
+/*
+ * ======== msg_ctrl ========
+ * There is a control structure for messages to the DSP, and a control
+ * structure for messages from the DSP. The shared memory region for
+ * transferring messages is partitioned as follows:
+ *
+ * ----------------------------------------------------------
+ * |Control | Messages from DSP | Control | Messages to DSP |
+ * ----------------------------------------------------------
+ *
+ * msg_ctrl control structure for messages to the DSP is used in the following
+ * way:
+ *
+ * buf_empty - This flag is set to FALSE by the GPP after it has output
+ * messages for the DSP. The DSP host driver sets it to
+ * TRUE after it has copied the messages.
+ * post_swi - Set to 1 by the GPP after it has written the messages,
+ * set the size, and set buf_empty to FALSE.
+ * The DSP Host driver uses SWI_andn of the post_swi field
+ * when a host interrupt occurs. The host driver clears
+ * this after posting the SWI.
+ * size - Number of messages to be read by the DSP.
+ *
+ * For messages from the DSP:
+ * buf_empty - This flag is set to FALSE by the DSP after it has output
+ * messages for the GPP. The DPC on the GPP sets it to
+ * TRUE after it has copied the messages.
+ * post_swi - Set to 1 the DPC on the GPP after copying the messages.
+ * size - Number of messages to be read by the GPP.
+ */
+struct msg_ctrl {
+ u32 buf_empty; /* to/from DSP buffer is empty */
+ u32 post_swi; /* Set to "1" to post msg_ctrl SWI */
+ u32 size; /* Number of messages to/from the DSP */
+ u32 resvd;
+};
+
+/*
+ * ======== msg_mgr ========
+ * The msg_mgr maintains a list of all MSG_QUEUEs. Each NODE object can
+ * have msg_queue to hold all messages that come up from the corresponding
+ * node on the DSP. The msg_mgr also has a shared queue of messages
+ * ready to go to the DSP.
+ */
+struct msg_mgr {
+ /* The first field must match that in msgobj.h */
+
+ /* Function interface to Bridge driver */
+ struct bridge_drv_interface *intf_fxns;
+
+ struct io_mgr *hio_mgr; /* IO manager */
+ struct lst_list *queue_list; /* List of MSG_QUEUEs */
+ spinlock_t msg_mgr_lock; /* For critical sections */
+ /* Signalled when MsgFrame is available */
+ struct sync_object *sync_event;
+ struct lst_list *msg_free_list; /* Free MsgFrames ready to be filled */
+ struct lst_list *msg_used_list; /* MsgFrames ready to go to DSP */
+ u32 msgs_pending; /* # of queued messages to go to DSP */
+ u32 max_msgs; /* Max # of msgs that fit in buffer */
+ msg_onexit on_exit; /* called when RMS_EXIT is received */
+};
+
+/*
+ * ======== msg_queue ========
+ * Each NODE has a msg_queue for receiving messages from the
+ * corresponding node on the DSP. The msg_queue object maintains a list
+ * of messages that have been sent to the host, but not yet read (MSG_Get),
+ * and a list of free frames that can be filled when new messages arrive
+ * from the DSP.
+ * The msg_queue's hSynEvent gets posted when a message is ready.
+ */
+struct msg_queue {
+ struct list_head list_elem;
+ struct msg_mgr *hmsg_mgr;
+ u32 max_msgs; /* Node message depth */
+ u32 msgq_id; /* Node environment pointer */
+ struct lst_list *msg_free_list; /* Free MsgFrames ready to be filled */
+ /* Filled MsgFramess waiting to be read */
+ struct lst_list *msg_used_list;
+ void *arg; /* Handle passed to mgr on_exit callback */
+ struct sync_object *sync_event; /* Signalled when message is ready */
+ struct sync_object *sync_done; /* For synchronizing cleanup */
+ struct sync_object *sync_done_ack; /* For synchronizing cleanup */
+ struct ntfy_object *ntfy_obj; /* For notification of message ready */
+ bool done; /* TRUE <==> deleting the object */
+ u32 io_msg_pend; /* Number of pending MSG_get/put calls */
+};
+
+/*
+ * ======== msg_dspmsg ========
+ */
+struct msg_dspmsg {
+ struct dsp_msg msg;
+ u32 msgq_id; /* Identifies the node the message goes to */
+};
+
+/*
+ * ======== msg_frame ========
+ */
+struct msg_frame {
+ struct list_head list_elem;
+ struct msg_dspmsg msg_data;
+};
+
+#endif /* _MSG_SM_ */
diff --git a/drivers/staging/tidspbridge/core/_tiomap.h b/drivers/staging/tidspbridge/core/_tiomap.h
new file mode 100644
index 00000000000..1c1f157e167
--- /dev/null
+++ b/drivers/staging/tidspbridge/core/_tiomap.h
@@ -0,0 +1,371 @@
+/*
+ * _tiomap.h
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * Definitions and types private to this Bridge driver.
+ *
+ * Copyright (C) 2005-2006 Texas Instruments, Inc.
+ *
+ * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef _TIOMAP_
+#define _TIOMAP_
+
+#include <plat/powerdomain.h>
+#include <plat/clockdomain.h>
+#include <mach-omap2/prm-regbits-34xx.h>
+#include <mach-omap2/cm-regbits-34xx.h>
+#include <dspbridge/devdefs.h>
+#include <hw_defs.h>
+#include <dspbridge/dspioctl.h> /* for bridge_ioctl_extproc defn */
+#include <dspbridge/sync.h>
+#include <dspbridge/clk.h>
+
+struct map_l4_peripheral {
+ u32 phys_addr;
+ u32 dsp_virt_addr;
+};
+
+#define ARM_MAILBOX_START 0xfffcf000
+#define ARM_MAILBOX_LENGTH 0x800
+
+/* New Registers in OMAP3.1 */
+
+#define TESTBLOCK_ID_START 0xfffed400
+#define TESTBLOCK_ID_LENGTH 0xff
+
+/* ID Returned by OMAP1510 */
+#define TBC_ID_VALUE 0xB47002F
+
+#define SPACE_LENGTH 0x2000
+#define API_CLKM_DPLL_DMA 0xfffec000
+#define ARM_INTERRUPT_OFFSET 0xb00
+
+#define BIOS24XX
+
+#define L4_PERIPHERAL_NULL 0x0
+#define DSPVA_PERIPHERAL_NULL 0x0
+
+#define MAX_LOCK_TLB_ENTRIES 15
+
+#define L4_PERIPHERAL_PRM 0x48306000 /*PRM L4 Peripheral */
+#define DSPVA_PERIPHERAL_PRM 0x1181e000
+#define L4_PERIPHERAL_SCM 0x48002000 /*SCM L4 Peripheral */
+#define DSPVA_PERIPHERAL_SCM 0x1181f000
+#define L4_PERIPHERAL_MMU 0x5D000000 /*MMU L4 Peripheral */
+#define DSPVA_PERIPHERAL_MMU 0x11820000
+#define L4_PERIPHERAL_CM 0x48004000 /* Core L4, Clock Management */
+#define DSPVA_PERIPHERAL_CM 0x1181c000
+#define L4_PERIPHERAL_PER 0x48005000 /* PER */
+#define DSPVA_PERIPHERAL_PER 0x1181d000
+
+#define L4_PERIPHERAL_GPIO1 0x48310000
+#define DSPVA_PERIPHERAL_GPIO1 0x11809000
+#define L4_PERIPHERAL_GPIO2 0x49050000
+#define DSPVA_PERIPHERAL_GPIO2 0x1180a000
+#define L4_PERIPHERAL_GPIO3 0x49052000
+#define DSPVA_PERIPHERAL_GPIO3 0x1180b000
+#define L4_PERIPHERAL_GPIO4 0x49054000
+#define DSPVA_PERIPHERAL_GPIO4 0x1180c000
+#define L4_PERIPHERAL_GPIO5 0x49056000
+#define DSPVA_PERIPHERAL_GPIO5 0x1180d000
+
+#define L4_PERIPHERAL_IVA2WDT 0x49030000
+#define DSPVA_PERIPHERAL_IVA2WDT 0x1180e000
+
+#define L4_PERIPHERAL_DISPLAY 0x48050000
+#define DSPVA_PERIPHERAL_DISPLAY 0x1180f000
+
+#define L4_PERIPHERAL_SSI 0x48058000
+#define DSPVA_PERIPHERAL_SSI 0x11804000
+#define L4_PERIPHERAL_GDD 0x48059000
+#define DSPVA_PERIPHERAL_GDD 0x11805000
+#define L4_PERIPHERAL_SS1 0x4805a000
+#define DSPVA_PERIPHERAL_SS1 0x11806000
+#define L4_PERIPHERAL_SS2 0x4805b000
+#define DSPVA_PERIPHERAL_SS2 0x11807000
+
+#define L4_PERIPHERAL_CAMERA 0x480BC000
+#define DSPVA_PERIPHERAL_CAMERA 0x11819000
+
+#define L4_PERIPHERAL_SDMA 0x48056000
+#define DSPVA_PERIPHERAL_SDMA 0x11810000 /* 0x1181d000 conflict w/ PER */
+
+#define L4_PERIPHERAL_UART1 0x4806a000
+#define DSPVA_PERIPHERAL_UART1 0x11811000
+#define L4_PERIPHERAL_UART2 0x4806c000
+#define DSPVA_PERIPHERAL_UART2 0x11812000
+#define L4_PERIPHERAL_UART3 0x49020000
+#define DSPVA_PERIPHERAL_UART3 0x11813000
+
+#define L4_PERIPHERAL_MCBSP1 0x48074000
+#define DSPVA_PERIPHERAL_MCBSP1 0x11814000
+#define L4_PERIPHERAL_MCBSP2 0x49022000
+#define DSPVA_PERIPHERAL_MCBSP2 0x11815000
+#define L4_PERIPHERAL_MCBSP3 0x49024000
+#define DSPVA_PERIPHERAL_MCBSP3 0x11816000
+#define L4_PERIPHERAL_MCBSP4 0x49026000
+#define DSPVA_PERIPHERAL_MCBSP4 0x11817000
+#define L4_PERIPHERAL_MCBSP5 0x48096000
+#define DSPVA_PERIPHERAL_MCBSP5 0x11818000
+
+#define L4_PERIPHERAL_GPTIMER5 0x49038000
+#define DSPVA_PERIPHERAL_GPTIMER5 0x11800000
+#define L4_PERIPHERAL_GPTIMER6 0x4903a000
+#define DSPVA_PERIPHERAL_GPTIMER6 0x11801000
+#define L4_PERIPHERAL_GPTIMER7 0x4903c000
+#define DSPVA_PERIPHERAL_GPTIMER7 0x11802000
+#define L4_PERIPHERAL_GPTIMER8 0x4903e000
+#define DSPVA_PERIPHERAL_GPTIMER8 0x11803000
+
+#define L4_PERIPHERAL_SPI1 0x48098000
+#define DSPVA_PERIPHERAL_SPI1 0x1181a000
+#define L4_PERIPHERAL_SPI2 0x4809a000
+#define DSPVA_PERIPHERAL_SPI2 0x1181b000
+
+#define L4_PERIPHERAL_MBOX 0x48094000
+#define DSPVA_PERIPHERAL_MBOX 0x11808000
+
+#define PM_GRPSEL_BASE 0x48307000
+#define DSPVA_GRPSEL_BASE 0x11821000
+
+#define L4_PERIPHERAL_SIDETONE_MCBSP2 0x49028000
+#define DSPVA_PERIPHERAL_SIDETONE_MCBSP2 0x11824000
+#define L4_PERIPHERAL_SIDETONE_MCBSP3 0x4902a000
+#define DSPVA_PERIPHERAL_SIDETONE_MCBSP3 0x11825000
+
+/* define a static array with L4 mappings */
+static const struct map_l4_peripheral l4_peripheral_table[] = {
+ {L4_PERIPHERAL_MBOX, DSPVA_PERIPHERAL_MBOX},
+ {L4_PERIPHERAL_SCM, DSPVA_PERIPHERAL_SCM},
+ {L4_PERIPHERAL_MMU, DSPVA_PERIPHERAL_MMU},
+ {L4_PERIPHERAL_GPTIMER5, DSPVA_PERIPHERAL_GPTIMER5},
+ {L4_PERIPHERAL_GPTIMER6, DSPVA_PERIPHERAL_GPTIMER6},
+ {L4_PERIPHERAL_GPTIMER7, DSPVA_PERIPHERAL_GPTIMER7},
+ {L4_PERIPHERAL_GPTIMER8, DSPVA_PERIPHERAL_GPTIMER8},
+ {L4_PERIPHERAL_GPIO1, DSPVA_PERIPHERAL_GPIO1},
+ {L4_PERIPHERAL_GPIO2, DSPVA_PERIPHERAL_GPIO2},
+ {L4_PERIPHERAL_GPIO3, DSPVA_PERIPHERAL_GPIO3},
+ {L4_PERIPHERAL_GPIO4, DSPVA_PERIPHERAL_GPIO4},
+ {L4_PERIPHERAL_GPIO5, DSPVA_PERIPHERAL_GPIO5},
+ {L4_PERIPHERAL_IVA2WDT, DSPVA_PERIPHERAL_IVA2WDT},
+ {L4_PERIPHERAL_DISPLAY, DSPVA_PERIPHERAL_DISPLAY},
+ {L4_PERIPHERAL_SSI, DSPVA_PERIPHERAL_SSI},
+ {L4_PERIPHERAL_GDD, DSPVA_PERIPHERAL_GDD},
+ {L4_PERIPHERAL_SS1, DSPVA_PERIPHERAL_SS1},
+ {L4_PERIPHERAL_SS2, DSPVA_PERIPHERAL_SS2},
+ {L4_PERIPHERAL_UART1, DSPVA_PERIPHERAL_UART1},
+ {L4_PERIPHERAL_UART2, DSPVA_PERIPHERAL_UART2},
+ {L4_PERIPHERAL_UART3, DSPVA_PERIPHERAL_UART3},
+ {L4_PERIPHERAL_MCBSP1, DSPVA_PERIPHERAL_MCBSP1},
+ {L4_PERIPHERAL_MCBSP2, DSPVA_PERIPHERAL_MCBSP2},
+ {L4_PERIPHERAL_MCBSP3, DSPVA_PERIPHERAL_MCBSP3},
+ {L4_PERIPHERAL_MCBSP4, DSPVA_PERIPHERAL_MCBSP4},
+ {L4_PERIPHERAL_MCBSP5, DSPVA_PERIPHERAL_MCBSP5},
+ {L4_PERIPHERAL_CAMERA, DSPVA_PERIPHERAL_CAMERA},
+ {L4_PERIPHERAL_SPI1, DSPVA_PERIPHERAL_SPI1},
+ {L4_PERIPHERAL_SPI2, DSPVA_PERIPHERAL_SPI2},
+ {L4_PERIPHERAL_PRM, DSPVA_PERIPHERAL_PRM},
+ {L4_PERIPHERAL_CM, DSPVA_PERIPHERAL_CM},
+ {L4_PERIPHERAL_PER, DSPVA_PERIPHERAL_PER},
+ {PM_GRPSEL_BASE, DSPVA_GRPSEL_BASE},
+ {L4_PERIPHERAL_SIDETONE_MCBSP2, DSPVA_PERIPHERAL_SIDETONE_MCBSP2},
+ {L4_PERIPHERAL_SIDETONE_MCBSP3, DSPVA_PERIPHERAL_SIDETONE_MCBSP3},
+ {L4_PERIPHERAL_NULL, DSPVA_PERIPHERAL_NULL}
+};
+
+/*
+ * 15 10 0
+ * ---------------------------------
+ * |0|0|1|0|0|0|c|c|c|i|i|i|i|i|i|i|
+ * ---------------------------------
+ * | (class) | (module specific) |
+ *
+ * where c -> Externel Clock Command: Clk & Autoidle Disable/Enable
+ * i -> External Clock ID Timers 5,6,7,8, McBSP1,2 and WDT3
+ */
+
+/* MBX_PM_CLK_IDMASK: DSP External clock id mask. */
+#define MBX_PM_CLK_IDMASK 0x7F
+
+/* MBX_PM_CLK_CMDSHIFT: DSP External clock command shift. */
+#define MBX_PM_CLK_CMDSHIFT 7
+
+/* MBX_PM_CLK_CMDMASK: DSP External clock command mask. */
+#define MBX_PM_CLK_CMDMASK 7
+
+/* MBX_PM_MAX_RESOURCES: CORE 1 Clock resources. */
+#define MBX_CORE1_RESOURCES 7
+
+/* MBX_PM_MAX_RESOURCES: CORE 2 Clock Resources. */
+#define MBX_CORE2_RESOURCES 1
+
+/* MBX_PM_MAX_RESOURCES: TOTAL Clock Reosurces. */
+#define MBX_PM_MAX_RESOURCES 11
+
+/* Power Management Commands */
+#define BPWR_DISABLE_CLOCK 0
+#define BPWR_ENABLE_CLOCK 1
+
+/* OMAP242x specific resources */
+enum bpwr_ext_clock_id {
+ BPWR_GP_TIMER5 = 0x10,
+ BPWR_GP_TIMER6,
+ BPWR_GP_TIMER7,
+ BPWR_GP_TIMER8,
+ BPWR_WD_TIMER3,
+ BPWR_MCBSP1,
+ BPWR_MCBSP2,
+ BPWR_MCBSP3,
+ BPWR_MCBSP4,
+ BPWR_MCBSP5,
+ BPWR_SSI = 0x20
+};
+
+static const u32 bpwr_clkid[] = {
+ (u32) BPWR_GP_TIMER5,
+ (u32) BPWR_GP_TIMER6,
+ (u32) BPWR_GP_TIMER7,
+ (u32) BPWR_GP_TIMER8,
+ (u32) BPWR_WD_TIMER3,
+ (u32) BPWR_MCBSP1,
+ (u32) BPWR_MCBSP2,
+ (u32) BPWR_MCBSP3,
+ (u32) BPWR_MCBSP4,
+ (u32) BPWR_MCBSP5,
+ (u32) BPWR_SSI
+};
+
+struct bpwr_clk_t {
+ u32 clk_id;
+ enum dsp_clk_id clk;
+};
+
+static const struct bpwr_clk_t bpwr_clks[] = {
+ {(u32) BPWR_GP_TIMER5, DSP_CLK_GPT5},
+ {(u32) BPWR_GP_TIMER6, DSP_CLK_GPT6},
+ {(u32) BPWR_GP_TIMER7, DSP_CLK_GPT7},
+ {(u32) BPWR_GP_TIMER8, DSP_CLK_GPT8},
+ {(u32) BPWR_WD_TIMER3, DSP_CLK_WDT3},
+ {(u32) BPWR_MCBSP1, DSP_CLK_MCBSP1},
+ {(u32) BPWR_MCBSP2, DSP_CLK_MCBSP2},
+ {(u32) BPWR_MCBSP3, DSP_CLK_MCBSP3},
+ {(u32) BPWR_MCBSP4, DSP_CLK_MCBSP4},
+ {(u32) BPWR_MCBSP5, DSP_CLK_MCBSP5},
+ {(u32) BPWR_SSI, DSP_CLK_SSI}
+};
+
+/* Interrupt Register Offsets */
+#define INTH_IT_REG_OFFSET 0x00 /* Interrupt register offset */
+#define INTH_MASK_IT_REG_OFFSET 0x04 /* Mask Interrupt reg offset */
+
+#define DSP_MAILBOX1_INT 10
+/*
+ * Bit definition of Interrupt Level Registers
+ */
+
+/* Mail Box defines */
+#define MB_ARM2DSP1_REG_OFFSET 0x00
+
+#define MB_ARM2DSP1B_REG_OFFSET 0x04
+
+#define MB_DSP2ARM1B_REG_OFFSET 0x0C
+
+#define MB_ARM2DSP1_FLAG_REG_OFFSET 0x18
+
+#define MB_ARM2DSP_FLAG 0x0001
+
+#define MBOX_ARM2DSP HW_MBOX_ID0
+#define MBOX_DSP2ARM HW_MBOX_ID1
+#define MBOX_ARM HW_MBOX_U0_ARM
+#define MBOX_DSP HW_MBOX_U1_DSP1
+
+#define ENABLE true
+#define DISABLE false
+
+#define HIGH_LEVEL true
+#define LOW_LEVEL false
+
+/* Macro's */
+#define CLEAR_BIT(reg, mask) (reg &= ~mask)
+#define SET_BIT(reg, mask) (reg |= mask)
+
+#define SET_GROUP_BITS16(reg, position, width, value) \
+ do {\
+ reg &= ~((0xFFFF >> (16 - (width))) << (position)) ; \
+ reg |= ((value & (0xFFFF >> (16 - (width)))) << (position)); \
+ } while (0);
+
+#define CLEAR_BIT_INDEX(reg, index) (reg &= ~(1 << (index)))
+
+/* This Bridge driver's device context: */
+struct bridge_dev_context {
+ struct dev_object *hdev_obj; /* Handle to Bridge device object. */
+ u32 dw_dsp_base_addr; /* Arm's API to DSP virt base addr */
+ /*
+ * DSP External memory prog address as seen virtually by the OS on
+ * the host side.
+ */
+ u32 dw_dsp_ext_base_addr; /* See the comment above */
+ u32 dw_api_reg_base; /* API mem map'd registers */
+ void __iomem *dw_dsp_mmu_base; /* DSP MMU Mapped registers */
+ u32 dw_api_clk_base; /* CLK Registers */
+ u32 dw_dsp_clk_m2_base; /* DSP Clock Module m2 */
+ u32 dw_public_rhea; /* Pub Rhea */
+ u32 dw_int_addr; /* MB INTR reg */
+ u32 dw_tc_endianism; /* TC Endianism register */
+ u32 dw_test_base; /* DSP MMU Mapped registers */
+ u32 dw_self_loop; /* Pointer to the selfloop */
+ u32 dw_dsp_start_add; /* API Boot vector */
+ u32 dw_internal_size; /* Internal memory size */
+
+ struct omap_mbox *mbox; /* Mail box handle */
+
+ struct cfg_hostres *resources; /* Host Resources */
+
+ /*
+ * Processor specific info is set when prog loaded and read from DCD.
+ * [See bridge_dev_ctrl()] PROC info contains DSP-MMU TLB entries.
+ */
+ /* DMMU TLB entries */
+ struct bridge_ioctl_extproc atlb_entry[BRDIOCTL_NUMOFMMUTLB];
+ u32 dw_brd_state; /* Last known board state. */
+
+ /* TC Settings */
+ bool tc_word_swap_on; /* Traffic Controller Word Swap */
+ struct pg_table_attrs *pt_attrs;
+ u32 dsp_per_clks;
+};
+
+/*
+ * If dsp_debug is true, do not branch to the DSP entry
+ * point and wait for DSP to boot.
+ */
+extern s32 dsp_debug;
+
+/*
+ * ======== sm_interrupt_dsp ========
+ * Purpose:
+ * Set interrupt value & send an interrupt to the DSP processor(s).
+ * This is typicaly used when mailbox interrupt mechanisms allow data
+ * to be associated with interrupt such as for OMAP's CMD/DATA regs.
+ * Parameters:
+ * dev_context: Handle to Bridge driver defined device info.
+ * mb_val: Value associated with interrupt(e.g. mailbox value).
+ * Returns:
+ * 0: Interrupt sent;
+ * else: Unable to send interrupt.
+ * Requires:
+ * Ensures:
+ */
+int sm_interrupt_dsp(struct bridge_dev_context *dev_context, u16 mb_val);
+
+#endif /* _TIOMAP_ */
diff --git a/drivers/staging/tidspbridge/core/_tiomap_pwr.h b/drivers/staging/tidspbridge/core/_tiomap_pwr.h
new file mode 100644
index 00000000000..bd0354d9ad0
--- /dev/null
+++ b/drivers/staging/tidspbridge/core/_tiomap_pwr.h
@@ -0,0 +1,85 @@
+/*
+ * _tiomap_pwr.h
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * Definitions and types for the DSP wake/sleep routines.
+ *
+ * Copyright (C) 2005-2006 Texas Instruments, Inc.
+ *
+ * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef _TIOMAP_PWR_
+#define _TIOMAP_PWR_
+
+#ifdef CONFIG_PM
+extern s32 dsp_test_sleepstate;
+#endif
+
+extern struct mailbox_context mboxsetting;
+
+/*
+ * ======== wake_dsp =========
+ * Wakes up the DSP from DeepSleep
+ */
+extern int wake_dsp(struct bridge_dev_context *dev_context,
+ void *pargs);
+
+/*
+ * ======== sleep_dsp =========
+ * Places the DSP in DeepSleep.
+ */
+extern int sleep_dsp(struct bridge_dev_context *dev_context,
+ u32 dw_cmd, void *pargs);
+/*
+ * ========interrupt_dsp========
+ * Sends an interrupt to DSP unconditionally.
+ */
+extern void interrupt_dsp(struct bridge_dev_context *dev_context,
+ u16 mb_val);
+
+/*
+ * ======== wake_dsp =========
+ * Wakes up the DSP from DeepSleep
+ */
+extern int dsp_peripheral_clk_ctrl(struct bridge_dev_context
+ *dev_context, void *pargs);
+/*
+ * ======== handle_hibernation_from_dsp ========
+ * Handle Hibernation requested from DSP
+ */
+int handle_hibernation_from_dsp(struct bridge_dev_context *dev_context);
+/*
+ * ======== post_scale_dsp ========
+ * Handle Post Scale notification to DSP
+ */
+int post_scale_dsp(struct bridge_dev_context *dev_context,
+ void *pargs);
+/*
+ * ======== pre_scale_dsp ========
+ * Handle Pre Scale notification to DSP
+ */
+int pre_scale_dsp(struct bridge_dev_context *dev_context,
+ void *pargs);
+/*
+ * ======== handle_constraints_set ========
+ * Handle constraints request from DSP
+ */
+int handle_constraints_set(struct bridge_dev_context *dev_context,
+ void *pargs);
+
+/*
+ * ======== dsp_clk_wakeup_event_ctrl ========
+ * This function sets the group selction bits for while
+ * enabling/disabling.
+ */
+void dsp_clk_wakeup_event_ctrl(u32 clock_id, bool enable);
+
+#endif /* _TIOMAP_PWR_ */
diff --git a/drivers/staging/tidspbridge/core/chnl_sm.c b/drivers/staging/tidspbridge/core/chnl_sm.c
new file mode 100644
index 00000000000..bee2b23a09a
--- /dev/null
+++ b/drivers/staging/tidspbridge/core/chnl_sm.c
@@ -0,0 +1,1014 @@
+/*
+ * chnl_sm.c
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * Implements upper edge functions for Bridge driver channel module.
+ *
+ * Copyright (C) 2005-2006 Texas Instruments, Inc.
+ *
+ * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+/*
+ * The lower edge functions must be implemented by the Bridge driver
+ * writer, and are declared in chnl_sm.h.
+ *
+ * Care is taken in this code to prevent simulataneous access to channel
+ * queues from
+ * 1. Threads.
+ * 2. io_dpc(), scheduled from the io_isr() as an event.
+ *
+ * This is done primarily by:
+ * - Semaphores.
+ * - state flags in the channel object; and
+ * - ensuring the IO_Dispatch() routine, which is called from both
+ * CHNL_AddIOReq() and the DPC(if implemented), is not re-entered.
+ *
+ * Channel Invariant:
+ * There is an important invariant condition which must be maintained per
+ * channel outside of bridge_chnl_get_ioc() and IO_Dispatch(), violation of
+ * which may cause timeouts and/or failure offunction sync_wait_on_event.
+ * This invariant condition is:
+ *
+ * LST_Empty(pchnl->pio_completions) ==> pchnl->sync_event is reset
+ * and
+ * !LST_Empty(pchnl->pio_completions) ==> pchnl->sync_event is set.
+ */
+
+#include <linux/types.h>
+
+/* ----------------------------------- OS */
+#include <dspbridge/host_os.h>
+
+/* ----------------------------------- DSP/BIOS Bridge */
+#include <dspbridge/dbdefs.h>
+
+/* ----------------------------------- Trace & Debug */
+#include <dspbridge/dbc.h>
+
+/* ----------------------------------- OS Adaptation Layer */
+#include <dspbridge/cfg.h>
+#include <dspbridge/sync.h>
+
+/* ----------------------------------- Bridge Driver */
+#include <dspbridge/dspdefs.h>
+#include <dspbridge/dspchnl.h>
+#include "_tiomap.h"
+
+/* ----------------------------------- Platform Manager */
+#include <dspbridge/dev.h>
+
+/* ----------------------------------- Others */
+#include <dspbridge/io_sm.h>
+
+/* ----------------------------------- Define for This */
+#define USERMODE_ADDR PAGE_OFFSET
+
+#define MAILBOX_IRQ INT_MAIL_MPU_IRQ
+
+/* ----------------------------------- Function Prototypes */
+static struct lst_list *create_chirp_list(u32 chirps);
+
+static void free_chirp_list(struct lst_list *chirp_list);
+
+static struct chnl_irp *make_new_chirp(void);
+
+static int search_free_channel(struct chnl_mgr *chnl_mgr_obj,
+ u32 *chnl);
+
+/*
+ * ======== bridge_chnl_add_io_req ========
+ * Enqueue an I/O request for data transfer on a channel to the DSP.
+ * The direction (mode) is specified in the channel object. Note the DSP
+ * address is specified for channels opened in direct I/O mode.
+ */
+int bridge_chnl_add_io_req(struct chnl_object *chnl_obj, void *host_buf,
+ u32 byte_size, u32 buf_size,
+ u32 dw_dsp_addr, u32 dw_arg)
+{
+ int status = 0;
+ struct chnl_object *pchnl = (struct chnl_object *)chnl_obj;
+ struct chnl_irp *chnl_packet_obj = NULL;
+ struct bridge_dev_context *dev_ctxt;
+ struct dev_object *dev_obj;
+ u8 dw_state;
+ bool is_eos;
+ struct chnl_mgr *chnl_mgr_obj = pchnl->chnl_mgr_obj;
+ u8 *host_sys_buf = NULL;
+ bool sched_dpc = false;
+ u16 mb_val = 0;
+
+ is_eos = (byte_size == 0);
+
+ /* Validate args */
+ if (!host_buf || !pchnl) {
+ status = -EFAULT;
+ } else if (is_eos && CHNL_IS_INPUT(pchnl->chnl_mode)) {
+ status = -EPERM;
+ } else {
+ /*
+ * Check the channel state: only queue chirp if channel state
+ * allows it.
+ */
+ dw_state = pchnl->dw_state;
+ if (dw_state != CHNL_STATEREADY) {
+ if (dw_state & CHNL_STATECANCEL)
+ status = -ECANCELED;
+ else if ((dw_state & CHNL_STATEEOS) &&
+ CHNL_IS_OUTPUT(pchnl->chnl_mode))
+ status = -EPIPE;
+ else
+ /* No other possible states left */
+ DBC_ASSERT(0);
+ }
+ }
+
+ dev_obj = dev_get_first();
+ dev_get_bridge_context(dev_obj, &dev_ctxt);
+ if (!dev_ctxt)
+ status = -EFAULT;
+
+ if (status)
+ goto func_end;
+
+ if (pchnl->chnl_type == CHNL_PCPY && pchnl->chnl_id > 1 && host_buf) {
+ if (!(host_buf < (void *)USERMODE_ADDR)) {
+ host_sys_buf = host_buf;
+ goto func_cont;
+ }
+ /* if addr in user mode, then copy to kernel space */
+ host_sys_buf = kmalloc(buf_size, GFP_KERNEL);
+ if (host_sys_buf == NULL) {
+ status = -ENOMEM;
+ goto func_end;
+ }
+ if (CHNL_IS_OUTPUT(pchnl->chnl_mode)) {
+ status = copy_from_user(host_sys_buf, host_buf,
+ buf_size);
+ if (status) {
+ kfree(host_sys_buf);
+ host_sys_buf = NULL;
+ status = -EFAULT;
+ goto func_end;
+ }
+ }
+ }
+func_cont:
+ /* Mailbox IRQ is disabled to avoid race condition with DMA/ZCPY
+ * channels. DPCCS is held to avoid race conditions with PCPY channels.
+ * If DPC is scheduled in process context (iosm_schedule) and any
+ * non-mailbox interrupt occurs, that DPC will run and break CS. Hence
+ * we disable ALL DPCs. We will try to disable ONLY IO DPC later. */
+ spin_lock_bh(&chnl_mgr_obj->chnl_mgr_lock);
+ omap_mbox_disable_irq(dev_ctxt->mbox, IRQ_RX);
+ if (pchnl->chnl_type == CHNL_PCPY) {
+ /* This is a processor-copy channel. */
+ if (!status && CHNL_IS_OUTPUT(pchnl->chnl_mode)) {
+ /* Check buffer size on output channels for fit. */
+ if (byte_size >
+ io_buf_size(pchnl->chnl_mgr_obj->hio_mgr))
+ status = -EINVAL;
+
+ }
+ }
+ if (!status) {
+ /* Get a free chirp: */
+ chnl_packet_obj =
+ (struct chnl_irp *)lst_get_head(pchnl->free_packets_list);
+ if (chnl_packet_obj == NULL)
+ status = -EIO;
+
+ }
+ if (!status) {
+ /* Enqueue the chirp on the chnl's IORequest queue: */
+ chnl_packet_obj->host_user_buf = chnl_packet_obj->host_sys_buf =
+ host_buf;
+ if (pchnl->chnl_type == CHNL_PCPY && pchnl->chnl_id > 1)
+ chnl_packet_obj->host_sys_buf = host_sys_buf;
+
+ /*
+ * Note: for dma chans dw_dsp_addr contains dsp address
+ * of SM buffer.
+ */
+ DBC_ASSERT(chnl_mgr_obj->word_size != 0);
+ /* DSP address */
+ chnl_packet_obj->dsp_tx_addr =
+ dw_dsp_addr / chnl_mgr_obj->word_size;
+ chnl_packet_obj->byte_size = byte_size;
+ chnl_packet_obj->buf_size = buf_size;
+ /* Only valid for output channel */
+ chnl_packet_obj->dw_arg = dw_arg;
+ chnl_packet_obj->status = (is_eos ? CHNL_IOCSTATEOS :
+ CHNL_IOCSTATCOMPLETE);
+ lst_put_tail(pchnl->pio_requests,
+ (struct list_head *)chnl_packet_obj);
+ pchnl->cio_reqs++;
+ DBC_ASSERT(pchnl->cio_reqs <= pchnl->chnl_packets);
+ /*
+ * If end of stream, update the channel state to prevent
+ * more IOR's.
+ */
+ if (is_eos)
+ pchnl->dw_state |= CHNL_STATEEOS;
+
+ /* Legacy DSM Processor-Copy */
+ DBC_ASSERT(pchnl->chnl_type == CHNL_PCPY);
+ /* Request IO from the DSP */
+ io_request_chnl(chnl_mgr_obj->hio_mgr, pchnl,
+ (CHNL_IS_INPUT(pchnl->chnl_mode) ? IO_INPUT :
+ IO_OUTPUT), &mb_val);
+ sched_dpc = true;
+
+ }
+ omap_mbox_enable_irq(dev_ctxt->mbox, IRQ_RX);
+ spin_unlock_bh(&chnl_mgr_obj->chnl_mgr_lock);
+ if (mb_val != 0)
+ sm_interrupt_dsp(dev_ctxt, mb_val);
+
+ /* Schedule a DPC, to do the actual data transfer */
+ if (sched_dpc)
+ iosm_schedule(chnl_mgr_obj->hio_mgr);
+
+func_end:
+ return status;
+}
+
+/*
+ * ======== bridge_chnl_cancel_io ========
+ * Return all I/O requests to the client which have not yet been
+ * transferred. The channel's I/O completion object is
+ * signalled, and all the I/O requests are queued as IOC's, with the
+ * status field set to CHNL_IOCSTATCANCEL.
+ * This call is typically used in abort situations, and is a prelude to
+ * chnl_close();
+ */
+int bridge_chnl_cancel_io(struct chnl_object *chnl_obj)
+{
+ int status = 0;
+ struct chnl_object *pchnl = (struct chnl_object *)chnl_obj;
+ u32 chnl_id = -1;
+ s8 chnl_mode;
+ struct chnl_irp *chnl_packet_obj;
+ struct chnl_mgr *chnl_mgr_obj = NULL;
+
+ /* Check args: */
+ if (pchnl && pchnl->chnl_mgr_obj) {
+ chnl_id = pchnl->chnl_id;
+ chnl_mode = pchnl->chnl_mode;
+ chnl_mgr_obj = pchnl->chnl_mgr_obj;
+ } else {
+ status = -EFAULT;
+ }
+ if (status)
+ goto func_end;
+
+ /* Mark this channel as cancelled, to prevent further IORequests or
+ * IORequests or dispatching. */
+ spin_lock_bh(&chnl_mgr_obj->chnl_mgr_lock);
+ pchnl->dw_state |= CHNL_STATECANCEL;
+ if (LST_IS_EMPTY(pchnl->pio_requests))
+ goto func_cont;
+
+ if (pchnl->chnl_type == CHNL_PCPY) {
+ /* Indicate we have no more buffers available for transfer: */
+ if (CHNL_IS_INPUT(pchnl->chnl_mode)) {
+ io_cancel_chnl(chnl_mgr_obj->hio_mgr, chnl_id);
+ } else {
+ /* Record that we no longer have output buffers
+ * available: */
+ chnl_mgr_obj->dw_output_mask &= ~(1 << chnl_id);
+ }
+ }
+ /* Move all IOR's to IOC queue: */
+ while (!LST_IS_EMPTY(pchnl->pio_requests)) {
+ chnl_packet_obj =
+ (struct chnl_irp *)lst_get_head(pchnl->pio_requests);
+ if (chnl_packet_obj) {
+ chnl_packet_obj->byte_size = 0;
+ chnl_packet_obj->status |= CHNL_IOCSTATCANCEL;
+ lst_put_tail(pchnl->pio_completions,
+ (struct list_head *)chnl_packet_obj);
+ pchnl->cio_cs++;
+ pchnl->cio_reqs--;
+ DBC_ASSERT(pchnl->cio_reqs >= 0);
+ }
+ }
+func_cont:
+ spin_unlock_bh(&chnl_mgr_obj->chnl_mgr_lock);
+func_end:
+ return status;
+}
+
+/*
+ * ======== bridge_chnl_close ========
+ * Purpose:
+ * Ensures all pending I/O on this channel is cancelled, discards all
+ * queued I/O completion notifications, then frees the resources allocated
+ * for this channel, and makes the corresponding logical channel id
+ * available for subsequent use.
+ */
+int bridge_chnl_close(struct chnl_object *chnl_obj)
+{
+ int status;
+ struct chnl_object *pchnl = (struct chnl_object *)chnl_obj;
+
+ /* Check args: */
+ if (!pchnl) {
+ status = -EFAULT;
+ goto func_cont;
+ }
+ {
+ /* Cancel IO: this ensures no further IO requests or
+ * notifications. */
+ status = bridge_chnl_cancel_io(chnl_obj);
+ }
+func_cont:
+ if (!status) {
+ /* Assert I/O on this channel is now cancelled: Protects
+ * from io_dpc. */
+ DBC_ASSERT((pchnl->dw_state & CHNL_STATECANCEL));
+ /* Invalidate channel object: Protects from
+ * CHNL_GetIOCompletion(). */
+ /* Free the slot in the channel manager: */
+ pchnl->chnl_mgr_obj->ap_channel[pchnl->chnl_id] = NULL;
+ spin_lock_bh(&pchnl->chnl_mgr_obj->chnl_mgr_lock);
+ pchnl->chnl_mgr_obj->open_channels -= 1;
+ spin_unlock_bh(&pchnl->chnl_mgr_obj->chnl_mgr_lock);
+ if (pchnl->ntfy_obj) {
+ ntfy_delete(pchnl->ntfy_obj);
+ kfree(pchnl->ntfy_obj);
+ pchnl->ntfy_obj = NULL;
+ }
+ /* Reset channel event: (NOTE: user_event freed in user
+ * context.). */
+ if (pchnl->sync_event) {
+ sync_reset_event(pchnl->sync_event);
+ kfree(pchnl->sync_event);
+ pchnl->sync_event = NULL;
+ }
+ /* Free I/O request and I/O completion queues: */
+ if (pchnl->pio_completions) {
+ free_chirp_list(pchnl->pio_completions);
+ pchnl->pio_completions = NULL;
+ pchnl->cio_cs = 0;
+ }
+ if (pchnl->pio_requests) {
+ free_chirp_list(pchnl->pio_requests);
+ pchnl->pio_requests = NULL;
+ pchnl->cio_reqs = 0;
+ }
+ if (pchnl->free_packets_list) {
+ free_chirp_list(pchnl->free_packets_list);
+ pchnl->free_packets_list = NULL;
+ }
+ /* Release channel object. */
+ kfree(pchnl);
+ pchnl = NULL;
+ }
+ DBC_ENSURE(status || !pchnl);
+ return status;
+}
+
+/*
+ * ======== bridge_chnl_create ========
+ * Create a channel manager object, responsible for opening new channels
+ * and closing old ones for a given board.
+ */
+int bridge_chnl_create(struct chnl_mgr **channel_mgr,
+ struct dev_object *hdev_obj,
+ const struct chnl_mgrattrs *mgr_attrts)
+{
+ int status = 0;
+ struct chnl_mgr *chnl_mgr_obj = NULL;
+ u8 max_channels;
+
+ /* Check DBC requirements: */
+ DBC_REQUIRE(channel_mgr != NULL);
+ DBC_REQUIRE(mgr_attrts != NULL);
+ DBC_REQUIRE(mgr_attrts->max_channels > 0);
+ DBC_REQUIRE(mgr_attrts->max_channels <= CHNL_MAXCHANNELS);
+ DBC_REQUIRE(mgr_attrts->word_size != 0);
+
+ /* Allocate channel manager object */
+ chnl_mgr_obj = kzalloc(sizeof(struct chnl_mgr), GFP_KERNEL);
+ if (chnl_mgr_obj) {
+ /*
+ * The max_channels attr must equal the # of supported chnls for
+ * each transport(# chnls for PCPY = DDMA = ZCPY): i.e.
+ * mgr_attrts->max_channels = CHNL_MAXCHANNELS =
+ * DDMA_MAXDDMACHNLS = DDMA_MAXZCPYCHNLS.
+ */
+ DBC_ASSERT(mgr_attrts->max_channels == CHNL_MAXCHANNELS);
+ max_channels = CHNL_MAXCHANNELS + CHNL_MAXCHANNELS * CHNL_PCPY;
+ /* Create array of channels */
+ chnl_mgr_obj->ap_channel = kzalloc(sizeof(struct chnl_object *)
+ * max_channels, GFP_KERNEL);
+ if (chnl_mgr_obj->ap_channel) {
+ /* Initialize chnl_mgr object */
+ chnl_mgr_obj->dw_type = CHNL_TYPESM;
+ chnl_mgr_obj->word_size = mgr_attrts->word_size;
+ /* Total # chnls supported */
+ chnl_mgr_obj->max_channels = max_channels;
+ chnl_mgr_obj->open_channels = 0;
+ chnl_mgr_obj->dw_output_mask = 0;
+ chnl_mgr_obj->dw_last_output = 0;
+ chnl_mgr_obj->hdev_obj = hdev_obj;
+ spin_lock_init(&chnl_mgr_obj->chnl_mgr_lock);
+ } else {
+ status = -ENOMEM;
+ }
+ } else {
+ status = -ENOMEM;
+ }
+
+ if (status) {
+ bridge_chnl_destroy(chnl_mgr_obj);
+ *channel_mgr = NULL;
+ } else {
+ /* Return channel manager object to caller... */
+ *channel_mgr = chnl_mgr_obj;
+ }
+ return status;
+}
+
+/*
+ * ======== bridge_chnl_destroy ========
+ * Purpose:
+ * Close all open channels, and destroy the channel manager.
+ */
+int bridge_chnl_destroy(struct chnl_mgr *hchnl_mgr)
+{
+ int status = 0;
+ struct chnl_mgr *chnl_mgr_obj = hchnl_mgr;
+ u32 chnl_id;
+
+ if (hchnl_mgr) {
+ /* Close all open channels: */
+ for (chnl_id = 0; chnl_id < chnl_mgr_obj->max_channels;
+ chnl_id++) {
+ status =
+ bridge_chnl_close(chnl_mgr_obj->ap_channel
+ [chnl_id]);
+ if (status)
+ dev_dbg(bridge, "%s: Error status 0x%x\n",
+ __func__, status);
+ }
+
+ /* Free channel manager object: */
+ kfree(chnl_mgr_obj->ap_channel);
+
+ /* Set hchnl_mgr to NULL in device object. */
+ dev_set_chnl_mgr(chnl_mgr_obj->hdev_obj, NULL);
+ /* Free this Chnl Mgr object: */
+ kfree(hchnl_mgr);
+ } else {
+ status = -EFAULT;
+ }
+ return status;
+}
+
+/*
+ * ======== bridge_chnl_flush_io ========
+ * purpose:
+ * Flushes all the outstanding data requests on a channel.
+ */
+int bridge_chnl_flush_io(struct chnl_object *chnl_obj, u32 timeout)
+{
+ int status = 0;
+ struct chnl_object *pchnl = (struct chnl_object *)chnl_obj;
+ s8 chnl_mode = -1;
+ struct chnl_mgr *chnl_mgr_obj;
+ struct chnl_ioc chnl_ioc_obj;
+ /* Check args: */
+ if (pchnl) {
+ if ((timeout == CHNL_IOCNOWAIT)
+ && CHNL_IS_OUTPUT(pchnl->chnl_mode)) {
+ status = -EINVAL;
+ } else {
+ chnl_mode = pchnl->chnl_mode;
+ chnl_mgr_obj = pchnl->chnl_mgr_obj;
+ }
+ } else {
+ status = -EFAULT;
+ }
+ if (!status) {
+ /* Note: Currently, if another thread continues to add IO
+ * requests to this channel, this function will continue to
+ * flush all such queued IO requests. */
+ if (CHNL_IS_OUTPUT(chnl_mode)
+ && (pchnl->chnl_type == CHNL_PCPY)) {
+ /* Wait for IO completions, up to the specified
+ * timeout: */
+ while (!LST_IS_EMPTY(pchnl->pio_requests) && !status) {
+ status = bridge_chnl_get_ioc(chnl_obj,
+ timeout, &chnl_ioc_obj);
+ if (status)
+ continue;
+
+ if (chnl_ioc_obj.status & CHNL_IOCSTATTIMEOUT)
+ status = -ETIMEDOUT;
+
+ }
+ } else {
+ status = bridge_chnl_cancel_io(chnl_obj);
+ /* Now, leave the channel in the ready state: */
+ pchnl->dw_state &= ~CHNL_STATECANCEL;
+ }
+ }
+ DBC_ENSURE(status || LST_IS_EMPTY(pchnl->pio_requests));
+ return status;
+}
+
+/*
+ * ======== bridge_chnl_get_info ========
+ * Purpose:
+ * Retrieve information related to a channel.
+ */
+int bridge_chnl_get_info(struct chnl_object *chnl_obj,
+ struct chnl_info *channel_info)
+{
+ int status = 0;
+ struct chnl_object *pchnl = (struct chnl_object *)chnl_obj;
+ if (channel_info != NULL) {
+ if (pchnl) {
+ /* Return the requested information: */
+ channel_info->hchnl_mgr = pchnl->chnl_mgr_obj;
+ channel_info->event_obj = pchnl->user_event;
+ channel_info->cnhl_id = pchnl->chnl_id;
+ channel_info->dw_mode = pchnl->chnl_mode;
+ channel_info->bytes_tx = pchnl->bytes_moved;
+ channel_info->process = pchnl->process;
+ channel_info->sync_event = pchnl->sync_event;
+ channel_info->cio_cs = pchnl->cio_cs;
+ channel_info->cio_reqs = pchnl->cio_reqs;
+ channel_info->dw_state = pchnl->dw_state;
+ } else {
+ status = -EFAULT;
+ }
+ } else {
+ status = -EFAULT;
+ }
+ return status;
+}
+
+/*
+ * ======== bridge_chnl_get_ioc ========
+ * Optionally wait for I/O completion on a channel. Dequeue an I/O
+ * completion record, which contains information about the completed
+ * I/O request.
+ * Note: Ensures Channel Invariant (see notes above).
+ */
+int bridge_chnl_get_ioc(struct chnl_object *chnl_obj, u32 timeout,
+ struct chnl_ioc *chan_ioc)
+{
+ int status = 0;
+ struct chnl_object *pchnl = (struct chnl_object *)chnl_obj;
+ struct chnl_irp *chnl_packet_obj;
+ int stat_sync;
+ bool dequeue_ioc = true;
+ struct chnl_ioc ioc = { NULL, 0, 0, 0, 0 };
+ u8 *host_sys_buf = NULL;
+ struct bridge_dev_context *dev_ctxt;
+ struct dev_object *dev_obj;
+
+ /* Check args: */
+ if (!chan_ioc || !pchnl) {
+ status = -EFAULT;
+ } else if (timeout == CHNL_IOCNOWAIT) {
+ if (LST_IS_EMPTY(pchnl->pio_completions))
+ status = -EREMOTEIO;
+
+ }
+
+ dev_obj = dev_get_first();
+ dev_get_bridge_context(dev_obj, &dev_ctxt);
+ if (!dev_ctxt)
+ status = -EFAULT;
+
+ if (status)
+ goto func_end;
+
+ ioc.status = CHNL_IOCSTATCOMPLETE;
+ if (timeout !=
+ CHNL_IOCNOWAIT && LST_IS_EMPTY(pchnl->pio_completions)) {
+ if (timeout == CHNL_IOCINFINITE)
+ timeout = SYNC_INFINITE;
+
+ stat_sync = sync_wait_on_event(pchnl->sync_event, timeout);
+ if (stat_sync == -ETIME) {
+ /* No response from DSP */
+ ioc.status |= CHNL_IOCSTATTIMEOUT;
+ dequeue_ioc = false;
+ } else if (stat_sync == -EPERM) {
+ /* This can occur when the user mode thread is
+ * aborted (^C), or when _VWIN32_WaitSingleObject()
+ * fails due to unkown causes. */
+ /* Even though Wait failed, there may be something in
+ * the Q: */
+ if (LST_IS_EMPTY(pchnl->pio_completions)) {
+ ioc.status |= CHNL_IOCSTATCANCEL;
+ dequeue_ioc = false;
+ }
+ }
+ }
+ /* See comment in AddIOReq */
+ spin_lock_bh(&pchnl->chnl_mgr_obj->chnl_mgr_lock);
+ omap_mbox_disable_irq(dev_ctxt->mbox, IRQ_RX);
+ if (dequeue_ioc) {
+ /* Dequeue IOC and set chan_ioc; */
+ DBC_ASSERT(!LST_IS_EMPTY(pchnl->pio_completions));
+ chnl_packet_obj =
+ (struct chnl_irp *)lst_get_head(pchnl->pio_completions);
+ /* Update chan_ioc from channel state and chirp: */
+ if (chnl_packet_obj) {
+ pchnl->cio_cs--;
+ /* If this is a zero-copy channel, then set IOC's pbuf
+ * to the DSP's address. This DSP address will get
+ * translated to user's virtual addr later. */
+ {
+ host_sys_buf = chnl_packet_obj->host_sys_buf;
+ ioc.pbuf = chnl_packet_obj->host_user_buf;
+ }
+ ioc.byte_size = chnl_packet_obj->byte_size;
+ ioc.buf_size = chnl_packet_obj->buf_size;
+ ioc.dw_arg = chnl_packet_obj->dw_arg;
+ ioc.status |= chnl_packet_obj->status;
+ /* Place the used chirp on the free list: */
+ lst_put_tail(pchnl->free_packets_list,
+ (struct list_head *)chnl_packet_obj);
+ } else {
+ ioc.pbuf = NULL;
+ ioc.byte_size = 0;
+ }
+ } else {
+ ioc.pbuf = NULL;
+ ioc.byte_size = 0;
+ ioc.dw_arg = 0;
+ ioc.buf_size = 0;
+ }
+ /* Ensure invariant: If any IOC's are queued for this channel... */
+ if (!LST_IS_EMPTY(pchnl->pio_completions)) {
+ /* Since DSPStream_Reclaim() does not take a timeout
+ * parameter, we pass the stream's timeout value to
+ * bridge_chnl_get_ioc. We cannot determine whether or not
+ * we have waited in User mode. Since the stream's timeout
+ * value may be non-zero, we still have to set the event.
+ * Therefore, this optimization is taken out.
+ *
+ * if (timeout == CHNL_IOCNOWAIT) {
+ * ... ensure event is set..
+ * sync_set_event(pchnl->sync_event);
+ * } */
+ sync_set_event(pchnl->sync_event);
+ } else {
+ /* else, if list is empty, ensure event is reset. */
+ sync_reset_event(pchnl->sync_event);
+ }
+ omap_mbox_enable_irq(dev_ctxt->mbox, IRQ_RX);
+ spin_unlock_bh(&pchnl->chnl_mgr_obj->chnl_mgr_lock);
+ if (dequeue_ioc
+ && (pchnl->chnl_type == CHNL_PCPY && pchnl->chnl_id > 1)) {
+ if (!(ioc.pbuf < (void *)USERMODE_ADDR))
+ goto func_cont;
+
+ /* If the addr is in user mode, then copy it */
+ if (!host_sys_buf || !ioc.pbuf) {
+ status = -EFAULT;
+ goto func_cont;
+ }
+ if (!CHNL_IS_INPUT(pchnl->chnl_mode))
+ goto func_cont1;
+
+ /*host_user_buf */
+ status = copy_to_user(ioc.pbuf, host_sys_buf, ioc.byte_size);
+ if (status) {
+ if (current->flags & PF_EXITING)
+ status = 0;
+ }
+ if (status)
+ status = -EFAULT;
+func_cont1:
+ kfree(host_sys_buf);
+ }
+func_cont:
+ /* Update User's IOC block: */
+ *chan_ioc = ioc;
+func_end:
+ return status;
+}
+
+/*
+ * ======== bridge_chnl_get_mgr_info ========
+ * Retrieve information related to the channel manager.
+ */
+int bridge_chnl_get_mgr_info(struct chnl_mgr *hchnl_mgr, u32 ch_id,
+ struct chnl_mgrinfo *mgr_info)
+{
+ int status = 0;
+ struct chnl_mgr *chnl_mgr_obj = (struct chnl_mgr *)hchnl_mgr;
+
+ if (mgr_info != NULL) {
+ if (ch_id <= CHNL_MAXCHANNELS) {
+ if (hchnl_mgr) {
+ /* Return the requested information: */
+ mgr_info->chnl_obj =
+ chnl_mgr_obj->ap_channel[ch_id];
+ mgr_info->open_channels =
+ chnl_mgr_obj->open_channels;
+ mgr_info->dw_type = chnl_mgr_obj->dw_type;
+ /* total # of chnls */
+ mgr_info->max_channels =
+ chnl_mgr_obj->max_channels;
+ } else {
+ status = -EFAULT;
+ }
+ } else {
+ status = -ECHRNG;
+ }
+ } else {
+ status = -EFAULT;
+ }
+
+ return status;
+}
+
+/*
+ * ======== bridge_chnl_idle ========
+ * Idles a particular channel.
+ */
+int bridge_chnl_idle(struct chnl_object *chnl_obj, u32 timeout,
+ bool flush_data)
+{
+ s8 chnl_mode;
+ struct chnl_mgr *chnl_mgr_obj;
+ int status = 0;
+
+ DBC_REQUIRE(chnl_obj);
+
+ chnl_mode = chnl_obj->chnl_mode;
+ chnl_mgr_obj = chnl_obj->chnl_mgr_obj;
+
+ if (CHNL_IS_OUTPUT(chnl_mode) && !flush_data) {
+ /* Wait for IO completions, up to the specified timeout: */
+ status = bridge_chnl_flush_io(chnl_obj, timeout);
+ } else {
+ status = bridge_chnl_cancel_io(chnl_obj);
+
+ /* Reset the byte count and put channel back in ready state. */
+ chnl_obj->bytes_moved = 0;
+ chnl_obj->dw_state &= ~CHNL_STATECANCEL;
+ }
+
+ return status;
+}
+
+/*
+ * ======== bridge_chnl_open ========
+ * Open a new half-duplex channel to the DSP board.
+ */
+int bridge_chnl_open(struct chnl_object **chnl,
+ struct chnl_mgr *hchnl_mgr, s8 chnl_mode,
+ u32 ch_id, const struct chnl_attr *pattrs)
+{
+ int status = 0;
+ struct chnl_mgr *chnl_mgr_obj = hchnl_mgr;
+ struct chnl_object *pchnl = NULL;
+ struct sync_object *sync_event = NULL;
+ /* Ensure DBC requirements: */
+ DBC_REQUIRE(chnl != NULL);
+ DBC_REQUIRE(pattrs != NULL);
+ DBC_REQUIRE(hchnl_mgr != NULL);
+ *chnl = NULL;
+ /* Validate Args: */
+ if (pattrs->uio_reqs == 0) {
+ status = -EINVAL;
+ } else {
+ if (!hchnl_mgr) {
+ status = -EFAULT;
+ } else {
+ if (ch_id != CHNL_PICKFREE) {
+ if (ch_id >= chnl_mgr_obj->max_channels)
+ status = -ECHRNG;
+ else if (chnl_mgr_obj->ap_channel[ch_id] !=
+ NULL)
+ status = -EALREADY;
+ } else {
+ /* Check for free channel */
+ status =
+ search_free_channel(chnl_mgr_obj, &ch_id);
+ }
+ }
+ }
+ if (status)
+ goto func_end;
+
+ DBC_ASSERT(ch_id < chnl_mgr_obj->max_channels);
+ /* Create channel object: */
+ pchnl = kzalloc(sizeof(struct chnl_object), GFP_KERNEL);
+ if (!pchnl) {
+ status = -ENOMEM;
+ goto func_end;
+ }
+ /* Protect queues from io_dpc: */
+ pchnl->dw_state = CHNL_STATECANCEL;
+ /* Allocate initial IOR and IOC queues: */
+ pchnl->free_packets_list = create_chirp_list(pattrs->uio_reqs);
+ pchnl->pio_requests = create_chirp_list(0);
+ pchnl->pio_completions = create_chirp_list(0);
+ pchnl->chnl_packets = pattrs->uio_reqs;
+ pchnl->cio_cs = 0;
+ pchnl->cio_reqs = 0;
+ sync_event = kzalloc(sizeof(struct sync_object), GFP_KERNEL);
+ if (sync_event)
+ sync_init_event(sync_event);
+ else
+ status = -ENOMEM;
+
+ if (!status) {
+ pchnl->ntfy_obj = kmalloc(sizeof(struct ntfy_object),
+ GFP_KERNEL);
+ if (pchnl->ntfy_obj)
+ ntfy_init(pchnl->ntfy_obj);
+ else
+ status = -ENOMEM;
+ }
+
+ if (!status) {
+ if (pchnl->pio_completions && pchnl->pio_requests &&
+ pchnl->free_packets_list) {
+ /* Initialize CHNL object fields: */
+ pchnl->chnl_mgr_obj = chnl_mgr_obj;
+ pchnl->chnl_id = ch_id;
+ pchnl->chnl_mode = chnl_mode;
+ pchnl->user_event = sync_event;
+ pchnl->sync_event = sync_event;
+ /* Get the process handle */
+ pchnl->process = current->tgid;
+ pchnl->pcb_arg = 0;
+ pchnl->bytes_moved = 0;
+ /* Default to proc-copy */
+ pchnl->chnl_type = CHNL_PCPY;
+ } else {
+ status = -ENOMEM;
+ }
+ }
+
+ if (status) {
+ /* Free memory */
+ if (pchnl->pio_completions) {
+ free_chirp_list(pchnl->pio_completions);
+ pchnl->pio_completions = NULL;
+ pchnl->cio_cs = 0;
+ }
+ if (pchnl->pio_requests) {
+ free_chirp_list(pchnl->pio_requests);
+ pchnl->pio_requests = NULL;
+ }
+ if (pchnl->free_packets_list) {
+ free_chirp_list(pchnl->free_packets_list);
+ pchnl->free_packets_list = NULL;
+ }
+ kfree(sync_event);
+ sync_event = NULL;
+
+ if (pchnl->ntfy_obj) {
+ ntfy_delete(pchnl->ntfy_obj);
+ kfree(pchnl->ntfy_obj);
+ pchnl->ntfy_obj = NULL;
+ }
+ kfree(pchnl);
+ } else {
+ /* Insert channel object in channel manager: */
+ chnl_mgr_obj->ap_channel[pchnl->chnl_id] = pchnl;
+ spin_lock_bh(&chnl_mgr_obj->chnl_mgr_lock);
+ chnl_mgr_obj->open_channels++;
+ spin_unlock_bh(&chnl_mgr_obj->chnl_mgr_lock);
+ /* Return result... */
+ pchnl->dw_state = CHNL_STATEREADY;
+ *chnl = pchnl;
+ }
+func_end:
+ DBC_ENSURE((!status && pchnl) || (*chnl == NULL));
+ return status;
+}
+
+/*
+ * ======== bridge_chnl_register_notify ========
+ * Registers for events on a particular channel.
+ */
+int bridge_chnl_register_notify(struct chnl_object *chnl_obj,
+ u32 event_mask, u32 notify_type,
+ struct dsp_notification *hnotification)
+{
+ int status = 0;
+
+ DBC_ASSERT(!(event_mask & ~(DSP_STREAMDONE | DSP_STREAMIOCOMPLETION)));
+
+ if (event_mask)
+ status = ntfy_register(chnl_obj->ntfy_obj, hnotification,
+ event_mask, notify_type);
+ else
+ status = ntfy_unregister(chnl_obj->ntfy_obj, hnotification);
+
+ return status;
+}
+
+/*
+ * ======== create_chirp_list ========
+ * Purpose:
+ * Initialize a queue of channel I/O Request/Completion packets.
+ * Parameters:
+ * chirps: Number of Chirps to allocate.
+ * Returns:
+ * Pointer to queue of IRPs, or NULL.
+ * Requires:
+ * Ensures:
+ */
+static struct lst_list *create_chirp_list(u32 chirps)
+{
+ struct lst_list *chirp_list;
+ struct chnl_irp *chnl_packet_obj;
+ u32 i;
+
+ chirp_list = kzalloc(sizeof(struct lst_list), GFP_KERNEL);
+
+ if (chirp_list) {
+ INIT_LIST_HEAD(&chirp_list->head);
+ /* Make N chirps and place on queue. */
+ for (i = 0; (i < chirps)
+ && ((chnl_packet_obj = make_new_chirp()) != NULL); i++) {
+ lst_put_tail(chirp_list,
+ (struct list_head *)chnl_packet_obj);
+ }
+
+ /* If we couldn't allocate all chirps, free those allocated: */
+ if (i != chirps) {
+ free_chirp_list(chirp_list);
+ chirp_list = NULL;
+ }
+ }
+
+ return chirp_list;
+}
+
+/*
+ * ======== free_chirp_list ========
+ * Purpose:
+ * Free the queue of Chirps.
+ */
+static void free_chirp_list(struct lst_list *chirp_list)
+{
+ DBC_REQUIRE(chirp_list != NULL);
+
+ while (!LST_IS_EMPTY(chirp_list))
+ kfree(lst_get_head(chirp_list));
+
+ kfree(chirp_list);
+}
+
+/*
+ * ======== make_new_chirp ========
+ * Allocate the memory for a new channel IRP.
+ */
+static struct chnl_irp *make_new_chirp(void)
+{
+ struct chnl_irp *chnl_packet_obj;
+
+ chnl_packet_obj = kzalloc(sizeof(struct chnl_irp), GFP_KERNEL);
+ if (chnl_packet_obj != NULL) {
+ /* lst_init_elem only resets the list's member values. */
+ lst_init_elem(&chnl_packet_obj->link);
+ }
+
+ return chnl_packet_obj;
+}
+
+/*
+ * ======== search_free_channel ========
+ * Search for a free channel slot in the array of channel pointers.
+ */
+static int search_free_channel(struct chnl_mgr *chnl_mgr_obj,
+ u32 *chnl)
+{
+ int status = -ENOSR;
+ u32 i;
+
+ DBC_REQUIRE(chnl_mgr_obj);
+
+ for (i = 0; i < chnl_mgr_obj->max_channels; i++) {
+ if (chnl_mgr_obj->ap_channel[i] == NULL) {
+ status = 0;
+ *chnl = i;
+ break;
+ }
+ }
+
+ return status;
+}
diff --git a/drivers/staging/tidspbridge/core/dsp-clock.c b/drivers/staging/tidspbridge/core/dsp-clock.c
new file mode 100644
index 00000000000..5b1a0c5bb14
--- /dev/null
+++ b/drivers/staging/tidspbridge/core/dsp-clock.c
@@ -0,0 +1,422 @@
+/*
+ * clk.c
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * Clock and Timer services.
+ *
+ * Copyright (C) 2005-2006 Texas Instruments, Inc.
+ *
+ * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include <linux/types.h>
+
+/* ----------------------------------- Host OS */
+#include <dspbridge/host_os.h>
+#include <plat/dmtimer.h>
+#include <plat/mcbsp.h>
+
+/* ----------------------------------- DSP/BIOS Bridge */
+#include <dspbridge/dbdefs.h>
+#include <dspbridge/cfg.h>
+#include <dspbridge/drv.h>
+#include <dspbridge/dev.h>
+#include "_tiomap.h"
+
+/* ----------------------------------- Trace & Debug */
+#include <dspbridge/dbc.h>
+
+/* ----------------------------------- This */
+#include <dspbridge/clk.h>
+
+/* ----------------------------------- Defines, Data Structures, Typedefs */
+
+#define OMAP_SSI_OFFSET 0x58000
+#define OMAP_SSI_SIZE 0x1000
+#define OMAP_SSI_SYSCONFIG_OFFSET 0x10
+
+#define SSI_AUTOIDLE (1 << 0)
+#define SSI_SIDLE_SMARTIDLE (2 << 3)
+#define SSI_MIDLE_NOIDLE (1 << 12)
+
+/* Clk types requested by the dsp */
+#define IVA2_CLK 0
+#define GPT_CLK 1
+#define WDT_CLK 2
+#define MCBSP_CLK 3
+#define SSI_CLK 4
+
+/* Bridge GPT id (1 - 4), DM Timer id (5 - 8) */
+#define DMT_ID(id) ((id) + 4)
+
+/* Bridge MCBSP id (6 - 10), OMAP Mcbsp id (0 - 4) */
+#define MCBSP_ID(id) ((id) - 6)
+
+static struct omap_dm_timer *timer[4];
+
+struct clk *iva2_clk;
+
+struct dsp_ssi {
+ struct clk *sst_fck;
+ struct clk *ssr_fck;
+ struct clk *ick;
+};
+
+static struct dsp_ssi ssi;
+
+static u32 dsp_clocks;
+
+static inline u32 is_dsp_clk_active(u32 clk, u8 id)
+{
+ return clk & (1 << id);
+}
+
+static inline void set_dsp_clk_active(u32 *clk, u8 id)
+{
+ *clk |= (1 << id);
+}
+
+static inline void set_dsp_clk_inactive(u32 *clk, u8 id)
+{
+ *clk &= ~(1 << id);
+}
+
+static s8 get_clk_type(u8 id)
+{
+ s8 type;
+
+ if (id == DSP_CLK_IVA2)
+ type = IVA2_CLK;
+ else if (id <= DSP_CLK_GPT8)
+ type = GPT_CLK;
+ else if (id == DSP_CLK_WDT3)
+ type = WDT_CLK;
+ else if (id <= DSP_CLK_MCBSP5)
+ type = MCBSP_CLK;
+ else if (id == DSP_CLK_SSI)
+ type = SSI_CLK;
+ else
+ type = -1;
+
+ return type;
+}
+
+/*
+ * ======== dsp_clk_exit ========
+ * Purpose:
+ * Cleanup CLK module.
+ */
+void dsp_clk_exit(void)
+{
+ dsp_clock_disable_all(dsp_clocks);
+
+ clk_put(iva2_clk);
+ clk_put(ssi.sst_fck);
+ clk_put(ssi.ssr_fck);
+ clk_put(ssi.ick);
+}
+
+/*
+ * ======== dsp_clk_init ========
+ * Purpose:
+ * Initialize CLK module.
+ */
+void dsp_clk_init(void)
+{
+ static struct platform_device dspbridge_device;
+
+ dspbridge_device.dev.bus = &platform_bus_type;
+
+ iva2_clk = clk_get(&dspbridge_device.dev, "iva2_ck");
+ if (IS_ERR(iva2_clk))
+ dev_err(bridge, "failed to get iva2 clock %p\n", iva2_clk);
+
+ ssi.sst_fck = clk_get(&dspbridge_device.dev, "ssi_sst_fck");
+ ssi.ssr_fck = clk_get(&dspbridge_device.dev, "ssi_ssr_fck");
+ ssi.ick = clk_get(&dspbridge_device.dev, "ssi_ick");
+
+ if (IS_ERR(ssi.sst_fck) || IS_ERR(ssi.ssr_fck) || IS_ERR(ssi.ick))
+ dev_err(bridge, "failed to get ssi: sst %p, ssr %p, ick %p\n",
+ ssi.sst_fck, ssi.ssr_fck, ssi.ick);
+}
+
+#ifdef CONFIG_OMAP_MCBSP
+static void mcbsp_clk_prepare(bool flag, u8 id)
+{
+ struct cfg_hostres *resources;
+ struct dev_object *hdev_object = NULL;
+ struct bridge_dev_context *bridge_context = NULL;
+ u32 val;
+
+ hdev_object = (struct dev_object *)drv_get_first_dev_object();
+ if (!hdev_object)
+ return;
+
+ dev_get_bridge_context(hdev_object, &bridge_context);
+ if (!bridge_context)
+ return;
+
+ resources = bridge_context->resources;
+ if (!resources)
+ return;
+
+ if (flag) {
+ if (id == DSP_CLK_MCBSP1) {
+ /* set MCBSP1_CLKS, on McBSP1 ON */
+ val = __raw_readl(resources->dw_sys_ctrl_base + 0x274);
+ val |= 1 << 2;
+ __raw_writel(val, resources->dw_sys_ctrl_base + 0x274);
+ } else if (id == DSP_CLK_MCBSP2) {
+ /* set MCBSP2_CLKS, on McBSP2 ON */
+ val = __raw_readl(resources->dw_sys_ctrl_base + 0x274);
+ val |= 1 << 6;
+ __raw_writel(val, resources->dw_sys_ctrl_base + 0x274);
+ }
+ } else {
+ if (id == DSP_CLK_MCBSP1) {
+ /* clear MCBSP1_CLKS, on McBSP1 OFF */
+ val = __raw_readl(resources->dw_sys_ctrl_base + 0x274);
+ val &= ~(1 << 2);
+ __raw_writel(val, resources->dw_sys_ctrl_base + 0x274);
+ } else if (id == DSP_CLK_MCBSP2) {
+ /* clear MCBSP2_CLKS, on McBSP2 OFF */
+ val = __raw_readl(resources->dw_sys_ctrl_base + 0x274);
+ val &= ~(1 << 6);
+ __raw_writel(val, resources->dw_sys_ctrl_base + 0x274);
+ }
+ }
+}
+#endif
+
+/**
+ * dsp_gpt_wait_overflow - set gpt overflow and wait for fixed timeout
+ * @clk_id: GP Timer clock id.
+ * @load: Overflow value.
+ *
+ * Sets an overflow interrupt for the desired GPT waiting for a timeout
+ * of 5 msecs for the interrupt to occur.
+ */
+void dsp_gpt_wait_overflow(short int clk_id, unsigned int load)
+{
+ struct omap_dm_timer *gpt = timer[clk_id - 1];
+ unsigned long timeout;
+
+ if (!gpt)
+ return;
+
+ /* Enable overflow interrupt */
+ omap_dm_timer_set_int_enable(gpt, OMAP_TIMER_INT_OVERFLOW);
+
+ /*
+ * Set counter value to overflow counter after
+ * one tick and start timer.
+ */
+ omap_dm_timer_set_load_start(gpt, 0, load);
+
+ /* Wait 80us for timer to overflow */
+ udelay(80);
+
+ timeout = msecs_to_jiffies(5);
+ /* Check interrupt status and wait for interrupt */
+ while (!(omap_dm_timer_read_status(gpt) & OMAP_TIMER_INT_OVERFLOW)) {
+ if (time_is_after_jiffies(timeout)) {
+ pr_err("%s: GPTimer interrupt failed\n", __func__);
+ break;
+ }
+ }
+}
+
+/*
+ * ======== dsp_clk_enable ========
+ * Purpose:
+ * Enable Clock .
+ *
+ */
+int dsp_clk_enable(enum dsp_clk_id clk_id)
+{
+ int status = 0;
+
+ if (is_dsp_clk_active(dsp_clocks, clk_id)) {
+ dev_err(bridge, "WARN: clock id %d already enabled\n", clk_id);
+ goto out;
+ }
+
+ switch (get_clk_type(clk_id)) {
+ case IVA2_CLK:
+ clk_enable(iva2_clk);
+ break;
+ case GPT_CLK:
+ timer[clk_id - 1] =
+ omap_dm_timer_request_specific(DMT_ID(clk_id));
+ break;
+#ifdef CONFIG_OMAP_MCBSP
+ case MCBSP_CLK:
+ mcbsp_clk_prepare(true, clk_id);
+ omap_mcbsp_set_io_type(MCBSP_ID(clk_id), OMAP_MCBSP_POLL_IO);
+ omap_mcbsp_request(MCBSP_ID(clk_id));
+ break;
+#endif
+ case WDT_CLK:
+ dev_err(bridge, "ERROR: DSP requested to enable WDT3 clk\n");
+ break;
+ case SSI_CLK:
+ clk_enable(ssi.sst_fck);
+ clk_enable(ssi.ssr_fck);
+ clk_enable(ssi.ick);
+
+ /*
+ * The SSI module need to configured not to have the Forced
+ * idle for master interface. If it is set to forced idle,
+ * the SSI module is transitioning to standby thereby causing
+ * the client in the DSP hang waiting for the SSI module to
+ * be active after enabling the clocks
+ */
+ ssi_clk_prepare(true);
+ break;
+ default:
+ dev_err(bridge, "Invalid clock id for enable\n");
+ status = -EPERM;
+ }
+
+ if (!status)
+ set_dsp_clk_active(&dsp_clocks, clk_id);
+
+out:
+ return status;
+}
+
+/**
+ * dsp_clock_enable_all - Enable clocks used by the DSP
+ * @dev_context Driver's device context strucure
+ *
+ * This function enables all the peripheral clocks that were requested by DSP.
+ */
+u32 dsp_clock_enable_all(u32 dsp_per_clocks)
+{
+ u32 clk_id;
+ u32 status = -EPERM;
+
+ for (clk_id = 0; clk_id < DSP_CLK_NOT_DEFINED; clk_id++) {
+ if (is_dsp_clk_active(dsp_per_clocks, clk_id))
+ status = dsp_clk_enable(clk_id);
+ }
+
+ return status;
+}
+
+/*
+ * ======== dsp_clk_disable ========
+ * Purpose:
+ * Disable the clock.
+ *
+ */
+int dsp_clk_disable(enum dsp_clk_id clk_id)
+{
+ int status = 0;
+
+ if (!is_dsp_clk_active(dsp_clocks, clk_id)) {
+ dev_err(bridge, "ERR: clock id %d already disabled\n", clk_id);
+ goto out;
+ }
+
+ switch (get_clk_type(clk_id)) {
+ case IVA2_CLK:
+ clk_disable(iva2_clk);
+ break;
+ case GPT_CLK:
+ omap_dm_timer_free(timer[clk_id - 1]);
+ break;
+#ifdef CONFIG_OMAP_MCBSP
+ case MCBSP_CLK:
+ mcbsp_clk_prepare(false, clk_id);
+ omap_mcbsp_free(MCBSP_ID(clk_id));
+ break;
+#endif
+ case WDT_CLK:
+ dev_err(bridge, "ERROR: DSP requested to disable WDT3 clk\n");
+ break;
+ case SSI_CLK:
+ ssi_clk_prepare(false);
+ ssi_clk_prepare(false);
+ clk_disable(ssi.sst_fck);
+ clk_disable(ssi.ssr_fck);
+ clk_disable(ssi.ick);
+ break;
+ default:
+ dev_err(bridge, "Invalid clock id for disable\n");
+ status = -EPERM;
+ }
+
+ if (!status)
+ set_dsp_clk_inactive(&dsp_clocks, clk_id);
+
+out:
+ return status;
+}
+
+/**
+ * dsp_clock_disable_all - Disable all active clocks
+ * @dev_context Driver's device context structure
+ *
+ * This function disables all the peripheral clocks that were enabled by DSP.
+ * It is meant to be called only when DSP is entering hibernation or when DSP
+ * is in error state.
+ */
+u32 dsp_clock_disable_all(u32 dsp_per_clocks)
+{
+ u32 clk_id;
+ u32 status = -EPERM;
+
+ for (clk_id = 0; clk_id < DSP_CLK_NOT_DEFINED; clk_id++) {
+ if (is_dsp_clk_active(dsp_per_clocks, clk_id))
+ status = dsp_clk_disable(clk_id);
+ }
+
+ return status;
+}
+
+u32 dsp_clk_get_iva2_rate(void)
+{
+ u32 clk_speed_khz;
+
+ clk_speed_khz = clk_get_rate(iva2_clk);
+ clk_speed_khz /= 1000;
+ dev_dbg(bridge, "%s: clk speed Khz = %d\n", __func__, clk_speed_khz);
+
+ return clk_speed_khz;
+}
+
+void ssi_clk_prepare(bool FLAG)
+{
+ void __iomem *ssi_base;
+ unsigned int value;
+
+ ssi_base = ioremap(L4_34XX_BASE + OMAP_SSI_OFFSET, OMAP_SSI_SIZE);
+ if (!ssi_base) {
+ pr_err("%s: error, SSI not configured\n", __func__);
+ return;
+ }
+
+ if (FLAG) {
+ /* Set Autoidle, SIDLEMode to smart idle, and MIDLEmode to
+ * no idle
+ */
+ value = SSI_AUTOIDLE | SSI_SIDLE_SMARTIDLE | SSI_MIDLE_NOIDLE;
+ } else {
+ /* Set Autoidle, SIDLEMode to forced idle, and MIDLEmode to
+ * forced idle
+ */
+ value = SSI_AUTOIDLE;
+ }
+
+ __raw_writel(value, ssi_base + OMAP_SSI_SYSCONFIG_OFFSET);
+ iounmap(ssi_base);
+}
+
diff --git a/drivers/staging/tidspbridge/core/io_sm.c b/drivers/staging/tidspbridge/core/io_sm.c
new file mode 100644
index 00000000000..02c660dbcf6
--- /dev/null
+++ b/drivers/staging/tidspbridge/core/io_sm.c
@@ -0,0 +1,2333 @@
+/*
+ * io_sm.c
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * IO dispatcher for a shared memory channel driver.
+ *
+ * Copyright (C) 2005-2006 Texas Instruments, Inc.
+ *
+ * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+/*
+ * Channel Invariant:
+ * There is an important invariant condition which must be maintained per
+ * channel outside of bridge_chnl_get_ioc() and IO_Dispatch(), violation of
+ * which may cause timeouts and/or failure of the sync_wait_on_event
+ * function.
+ */
+#include <linux/types.h>
+
+/* Host OS */
+#include <dspbridge/host_os.h>
+#include <linux/workqueue.h>
+
+/* ----------------------------------- DSP/BIOS Bridge */
+#include <dspbridge/dbdefs.h>
+
+/* Trace & Debug */
+#include <dspbridge/dbc.h>
+
+/* Services Layer */
+#include <dspbridge/cfg.h>
+#include <dspbridge/ntfy.h>
+#include <dspbridge/sync.h>
+
+/* Hardware Abstraction Layer */
+#include <hw_defs.h>
+#include <hw_mmu.h>
+
+/* Bridge Driver */
+#include <dspbridge/dspdeh.h>
+#include <dspbridge/dspio.h>
+#include <dspbridge/dspioctl.h>
+#include <dspbridge/wdt.h>
+#include <_tiomap.h>
+#include <tiomap_io.h>
+#include <_tiomap_pwr.h>
+
+/* Platform Manager */
+#include <dspbridge/cod.h>
+#include <dspbridge/node.h>
+#include <dspbridge/dev.h>
+
+/* Others */
+#include <dspbridge/rms_sh.h>
+#include <dspbridge/mgr.h>
+#include <dspbridge/drv.h>
+#include "_cmm.h"
+#include "module_list.h"
+
+/* This */
+#include <dspbridge/io_sm.h>
+#include "_msg_sm.h"
+
+/* Defines, Data Structures, Typedefs */
+#define OUTPUTNOTREADY 0xffff
+#define NOTENABLED 0xffff /* Channel(s) not enabled */
+
+#define EXTEND "_EXT_END"
+
+#define SWAP_WORD(x) (x)
+#define UL_PAGE_ALIGN_SIZE 0x10000 /* Page Align Size */
+
+#define MAX_PM_REQS 32
+
+#define MMU_FAULT_HEAD1 0xa5a5a5a5
+#define MMU_FAULT_HEAD2 0x96969696
+#define POLL_MAX 1000
+#define MAX_MMU_DBGBUFF 10240
+
+/* IO Manager: only one created per board */
+struct io_mgr {
+ /* These four fields must be the first fields in a io_mgr_ struct */
+ /* Bridge device context */
+ struct bridge_dev_context *hbridge_context;
+ /* Function interface to Bridge driver */
+ struct bridge_drv_interface *intf_fxns;
+ struct dev_object *hdev_obj; /* Device this board represents */
+
+ /* These fields initialized in bridge_io_create() */
+ struct chnl_mgr *hchnl_mgr;
+ struct shm *shared_mem; /* Shared Memory control */
+ u8 *input; /* Address of input channel */
+ u8 *output; /* Address of output channel */
+ struct msg_mgr *hmsg_mgr; /* Message manager */
+ /* Msg control for from DSP messages */
+ struct msg_ctrl *msg_input_ctrl;
+ /* Msg control for to DSP messages */
+ struct msg_ctrl *msg_output_ctrl;
+ u8 *msg_input; /* Address of input messages */
+ u8 *msg_output; /* Address of output messages */
+ u32 usm_buf_size; /* Size of a shared memory I/O channel */
+ bool shared_irq; /* Is this IRQ shared? */
+ u32 word_size; /* Size in bytes of DSP word */
+ u16 intr_val; /* Interrupt value */
+ /* Private extnd proc info; mmu setup */
+ struct mgr_processorextinfo ext_proc_info;
+ struct cmm_object *hcmm_mgr; /* Shared Mem Mngr */
+ struct work_struct io_workq; /* workqueue */
+#if defined(CONFIG_TIDSPBRIDGE_BACKTRACE) || defined(CONFIG_TIDSPBRIDGE_DEBUG)
+ u32 ul_trace_buffer_begin; /* Trace message start address */
+ u32 ul_trace_buffer_end; /* Trace message end address */
+ u32 ul_trace_buffer_current; /* Trace message current address */
+ u32 ul_gpp_read_pointer; /* GPP Read pointer to Trace buffer */
+ u8 *pmsg;
+ u32 ul_gpp_va;
+ u32 ul_dsp_va;
+#endif
+ /* IO Dpc */
+ u32 dpc_req; /* Number of requested DPC's. */
+ u32 dpc_sched; /* Number of executed DPC's. */
+ struct tasklet_struct dpc_tasklet;
+ spinlock_t dpc_lock;
+
+};
+
+/* Function Prototypes */
+static void io_dispatch_pm(struct io_mgr *pio_mgr);
+static void notify_chnl_complete(struct chnl_object *pchnl,
+ struct chnl_irp *chnl_packet_obj);
+static void input_chnl(struct io_mgr *pio_mgr, struct chnl_object *pchnl,
+ u8 io_mode);
+static void output_chnl(struct io_mgr *pio_mgr, struct chnl_object *pchnl,
+ u8 io_mode);
+static void input_msg(struct io_mgr *pio_mgr, struct msg_mgr *hmsg_mgr);
+static void output_msg(struct io_mgr *pio_mgr, struct msg_mgr *hmsg_mgr);
+static u32 find_ready_output(struct chnl_mgr *chnl_mgr_obj,
+ struct chnl_object *pchnl, u32 mask);
+
+/* Bus Addr (cached kernel) */
+static int register_shm_segs(struct io_mgr *hio_mgr,
+ struct cod_manager *cod_man,
+ u32 dw_gpp_base_pa);
+
+static inline void set_chnl_free(struct shm *sm, u32 chnl)
+{
+ sm->host_free_mask &= ~(1 << chnl);
+}
+
+static inline void set_chnl_busy(struct shm *sm, u32 chnl)
+{
+ sm->host_free_mask |= 1 << chnl;
+}
+
+
+/*
+ * ======== bridge_io_create ========
+ * Create an IO manager object.
+ */
+int bridge_io_create(struct io_mgr **io_man,
+ struct dev_object *hdev_obj,
+ const struct io_attrs *mgr_attrts)
+{
+ int status = 0;
+ struct io_mgr *pio_mgr = NULL;
+ struct shm *shared_mem = NULL;
+ struct bridge_dev_context *hbridge_context = NULL;
+ struct cfg_devnode *dev_node_obj;
+ struct chnl_mgr *hchnl_mgr;
+ u8 dev_type;
+
+ /* Check requirements */
+ if (!io_man || !mgr_attrts || mgr_attrts->word_size == 0) {
+ status = -EFAULT;
+ goto func_end;
+ }
+ dev_get_chnl_mgr(hdev_obj, &hchnl_mgr);
+ if (!hchnl_mgr || hchnl_mgr->hio_mgr) {
+ status = -EFAULT;
+ goto func_end;
+ }
+ /*
+ * Message manager will be created when a file is loaded, since
+ * size of message buffer in shared memory is configurable in
+ * the base image.
+ */
+ dev_get_bridge_context(hdev_obj, &hbridge_context);
+ if (!hbridge_context) {
+ status = -EFAULT;
+ goto func_end;
+ }
+ dev_get_dev_type(hdev_obj, &dev_type);
+ /*
+ * DSP shared memory area will get set properly when
+ * a program is loaded. They are unknown until a COFF file is
+ * loaded. I chose the value -1 because it was less likely to be
+ * a valid address than 0.
+ */
+ shared_mem = (struct shm *)-1;
+
+ /* Allocate IO manager object */
+ pio_mgr = kzalloc(sizeof(struct io_mgr), GFP_KERNEL);
+ if (pio_mgr == NULL) {
+ status = -ENOMEM;
+ goto func_end;
+ }
+
+ /* Initialize chnl_mgr object */
+#if defined(CONFIG_TIDSPBRIDGE_BACKTRACE) || defined(CONFIG_TIDSPBRIDGE_DEBUG)
+ pio_mgr->pmsg = NULL;
+#endif
+ pio_mgr->hchnl_mgr = hchnl_mgr;
+ pio_mgr->word_size = mgr_attrts->word_size;
+ pio_mgr->shared_mem = shared_mem;
+
+ if (dev_type == DSP_UNIT) {
+ /* Create an IO DPC */
+ tasklet_init(&pio_mgr->dpc_tasklet, io_dpc, (u32) pio_mgr);
+
+ /* Initialize DPC counters */
+ pio_mgr->dpc_req = 0;
+ pio_mgr->dpc_sched = 0;
+
+ spin_lock_init(&pio_mgr->dpc_lock);
+
+ status = dev_get_dev_node(hdev_obj, &dev_node_obj);
+ }
+
+ if (!status) {
+ pio_mgr->hbridge_context = hbridge_context;
+ pio_mgr->shared_irq = mgr_attrts->irq_shared;
+ if (dsp_wdt_init())
+ status = -EPERM;
+ } else {
+ status = -EIO;
+ }
+func_end:
+ if (status) {
+ /* Cleanup */
+ bridge_io_destroy(pio_mgr);
+ if (io_man)
+ *io_man = NULL;
+ } else {
+ /* Return IO manager object to caller... */
+ hchnl_mgr->hio_mgr = pio_mgr;
+ *io_man = pio_mgr;
+ }
+ return status;
+}
+
+/*
+ * ======== bridge_io_destroy ========
+ * Purpose:
+ * Disable interrupts, destroy the IO manager.
+ */
+int bridge_io_destroy(struct io_mgr *hio_mgr)
+{
+ int status = 0;
+ if (hio_mgr) {
+ /* Free IO DPC object */
+ tasklet_kill(&hio_mgr->dpc_tasklet);
+
+#if defined(CONFIG_TIDSPBRIDGE_BACKTRACE) || defined(CONFIG_TIDSPBRIDGE_DEBUG)
+ kfree(hio_mgr->pmsg);
+#endif
+ dsp_wdt_exit();
+ /* Free this IO manager object */
+ kfree(hio_mgr);
+ } else {
+ status = -EFAULT;
+ }
+
+ return status;
+}
+
+/*
+ * ======== bridge_io_on_loaded ========
+ * Purpose:
+ * Called when a new program is loaded to get shared memory buffer
+ * parameters from COFF file. ulSharedBufferBase and ulSharedBufferLimit
+ * are in DSP address units.
+ */
+int bridge_io_on_loaded(struct io_mgr *hio_mgr)
+{
+ struct cod_manager *cod_man;
+ struct chnl_mgr *hchnl_mgr;
+ struct msg_mgr *hmsg_mgr;
+ u32 ul_shm_base;
+ u32 ul_shm_base_offset;
+ u32 ul_shm_limit;
+ u32 ul_shm_length = -1;
+ u32 ul_mem_length = -1;
+ u32 ul_msg_base;
+ u32 ul_msg_limit;
+ u32 ul_msg_length = -1;
+ u32 ul_ext_end;
+ u32 ul_gpp_pa = 0;
+ u32 ul_gpp_va = 0;
+ u32 ul_dsp_va = 0;
+ u32 ul_seg_size = 0;
+ u32 ul_pad_size = 0;
+ u32 i;
+ int status = 0;
+ u8 num_procs = 0;
+ s32 ndx = 0;
+ /* DSP MMU setup table */
+ struct bridge_ioctl_extproc ae_proc[BRDIOCTL_NUMOFMMUTLB];
+ struct cfg_hostres *host_res;
+ struct bridge_dev_context *pbridge_context;
+ u32 map_attrs;
+ u32 shm0_end;
+ u32 ul_dyn_ext_base;
+ u32 ul_seg1_size = 0;
+ u32 pa_curr = 0;
+ u32 va_curr = 0;
+ u32 gpp_va_curr = 0;
+ u32 num_bytes = 0;
+ u32 all_bits = 0;
+ u32 page_size[] = { HW_PAGE_SIZE16MB, HW_PAGE_SIZE1MB,
+ HW_PAGE_SIZE64KB, HW_PAGE_SIZE4KB
+ };
+
+ status = dev_get_bridge_context(hio_mgr->hdev_obj, &pbridge_context);
+ if (!pbridge_context) {
+ status = -EFAULT;
+ goto func_end;
+ }
+
+ host_res = pbridge_context->resources;
+ if (!host_res) {
+ status = -EFAULT;
+ goto func_end;
+ }
+ status = dev_get_cod_mgr(hio_mgr->hdev_obj, &cod_man);
+ if (!cod_man) {
+ status = -EFAULT;
+ goto func_end;
+ }
+ hchnl_mgr = hio_mgr->hchnl_mgr;
+ /* The message manager is destroyed when the board is stopped. */
+ dev_get_msg_mgr(hio_mgr->hdev_obj, &hio_mgr->hmsg_mgr);
+ hmsg_mgr = hio_mgr->hmsg_mgr;
+ if (!hchnl_mgr || !hmsg_mgr) {
+ status = -EFAULT;
+ goto func_end;
+ }
+ if (hio_mgr->shared_mem)
+ hio_mgr->shared_mem = NULL;
+
+ /* Get start and length of channel part of shared memory */
+ status = cod_get_sym_value(cod_man, CHNL_SHARED_BUFFER_BASE_SYM,
+ &ul_shm_base);
+ if (status) {
+ status = -EFAULT;
+ goto func_end;
+ }
+ status = cod_get_sym_value(cod_man, CHNL_SHARED_BUFFER_LIMIT_SYM,
+ &ul_shm_limit);
+ if (status) {
+ status = -EFAULT;
+ goto func_end;
+ }
+ if (ul_shm_limit <= ul_shm_base) {
+ status = -EINVAL;
+ goto func_end;
+ }
+ /* Get total length in bytes */
+ ul_shm_length = (ul_shm_limit - ul_shm_base + 1) * hio_mgr->word_size;
+ /* Calculate size of a PROCCOPY shared memory region */
+ dev_dbg(bridge, "%s: (proc)proccopy shmmem size: 0x%x bytes\n",
+ __func__, (ul_shm_length - sizeof(struct shm)));
+
+ /* Get start and length of message part of shared memory */
+ status = cod_get_sym_value(cod_man, MSG_SHARED_BUFFER_BASE_SYM,
+ &ul_msg_base);
+ if (!status) {
+ status = cod_get_sym_value(cod_man, MSG_SHARED_BUFFER_LIMIT_SYM,
+ &ul_msg_limit);
+ if (!status) {
+ if (ul_msg_limit <= ul_msg_base) {
+ status = -EINVAL;
+ } else {
+ /*
+ * Length (bytes) of messaging part of shared
+ * memory.
+ */
+ ul_msg_length =
+ (ul_msg_limit - ul_msg_base +
+ 1) * hio_mgr->word_size;
+ /*
+ * Total length (bytes) of shared memory:
+ * chnl + msg.
+ */
+ ul_mem_length = ul_shm_length + ul_msg_length;
+ }
+ } else {
+ status = -EFAULT;
+ }
+ } else {
+ status = -EFAULT;
+ }
+ if (!status) {
+#if defined(CONFIG_TIDSPBRIDGE_BACKTRACE) || defined(CONFIG_TIDSPBRIDGE_DEBUG)
+ status =
+ cod_get_sym_value(cod_man, DSP_TRACESEC_END, &shm0_end);
+#else
+ status = cod_get_sym_value(cod_man, SHM0_SHARED_END_SYM,
+ &shm0_end);
+#endif
+ if (status)
+ status = -EFAULT;
+ }
+ if (!status) {
+ status =
+ cod_get_sym_value(cod_man, DYNEXTBASE, &ul_dyn_ext_base);
+ if (status)
+ status = -EFAULT;
+ }
+ if (!status) {
+ status = cod_get_sym_value(cod_man, EXTEND, &ul_ext_end);
+ if (status)
+ status = -EFAULT;
+ }
+ if (!status) {
+ /* Get memory reserved in host resources */
+ (void)mgr_enum_processor_info(0, (struct dsp_processorinfo *)
+ &hio_mgr->ext_proc_info,
+ sizeof(struct
+ mgr_processorextinfo),
+ &num_procs);
+
+ /* The first MMU TLB entry(TLB_0) in DCD is ShmBase. */
+ ndx = 0;
+ ul_gpp_pa = host_res->dw_mem_phys[1];
+ ul_gpp_va = host_res->dw_mem_base[1];
+ /* This is the virtual uncached ioremapped address!!! */
+ /* Why can't we directly take the DSPVA from the symbols? */
+ ul_dsp_va = hio_mgr->ext_proc_info.ty_tlb[0].ul_dsp_virt;
+ ul_seg_size = (shm0_end - ul_dsp_va) * hio_mgr->word_size;
+ ul_seg1_size =
+ (ul_ext_end - ul_dyn_ext_base) * hio_mgr->word_size;
+ /* 4K align */
+ ul_seg1_size = (ul_seg1_size + 0xFFF) & (~0xFFFUL);
+ /* 64K align */
+ ul_seg_size = (ul_seg_size + 0xFFFF) & (~0xFFFFUL);
+ ul_pad_size = UL_PAGE_ALIGN_SIZE - ((ul_gpp_pa + ul_seg1_size) %
+ UL_PAGE_ALIGN_SIZE);
+ if (ul_pad_size == UL_PAGE_ALIGN_SIZE)
+ ul_pad_size = 0x0;
+
+ dev_dbg(bridge, "%s: ul_gpp_pa %x, ul_gpp_va %x, ul_dsp_va %x, "
+ "shm0_end %x, ul_dyn_ext_base %x, ul_ext_end %x, "
+ "ul_seg_size %x ul_seg1_size %x \n", __func__,
+ ul_gpp_pa, ul_gpp_va, ul_dsp_va, shm0_end,
+ ul_dyn_ext_base, ul_ext_end, ul_seg_size, ul_seg1_size);
+
+ if ((ul_seg_size + ul_seg1_size + ul_pad_size) >
+ host_res->dw_mem_length[1]) {
+ pr_err("%s: shm Error, reserved 0x%x required 0x%x\n",
+ __func__, host_res->dw_mem_length[1],
+ ul_seg_size + ul_seg1_size + ul_pad_size);
+ status = -ENOMEM;
+ }
+ }
+ if (status)
+ goto func_end;
+
+ pa_curr = ul_gpp_pa;
+ va_curr = ul_dyn_ext_base * hio_mgr->word_size;
+ gpp_va_curr = ul_gpp_va;
+ num_bytes = ul_seg1_size;
+
+ /*
+ * Try to fit into TLB entries. If not possible, push them to page
+ * tables. It is quite possible that if sections are not on
+ * bigger page boundary, we may end up making several small pages.
+ * So, push them onto page tables, if that is the case.
+ */
+ map_attrs = 0x00000000;
+ map_attrs = DSP_MAPLITTLEENDIAN;
+ map_attrs |= DSP_MAPPHYSICALADDR;
+ map_attrs |= DSP_MAPELEMSIZE32;
+ map_attrs |= DSP_MAPDONOTLOCK;
+
+ while (num_bytes) {
+ /*
+ * To find the max. page size with which both PA & VA are
+ * aligned.
+ */
+ all_bits = pa_curr | va_curr;
+ dev_dbg(bridge, "all_bits %x, pa_curr %x, va_curr %x, "
+ "num_bytes %x\n", all_bits, pa_curr, va_curr,
+ num_bytes);
+ for (i = 0; i < 4; i++) {
+ if ((num_bytes >= page_size[i]) && ((all_bits &
+ (page_size[i] -
+ 1)) == 0)) {
+ status =
+ hio_mgr->intf_fxns->
+ pfn_brd_mem_map(hio_mgr->hbridge_context,
+ pa_curr, va_curr,
+ page_size[i], map_attrs,
+ NULL);
+ if (status)
+ goto func_end;
+ pa_curr += page_size[i];
+ va_curr += page_size[i];
+ gpp_va_curr += page_size[i];
+ num_bytes -= page_size[i];
+ /*
+ * Don't try smaller sizes. Hopefully we have
+ * reached an address aligned to a bigger page
+ * size.
+ */
+ break;
+ }
+ }
+ }
+ pa_curr += ul_pad_size;
+ va_curr += ul_pad_size;
+ gpp_va_curr += ul_pad_size;
+
+ /* Configure the TLB entries for the next cacheable segment */
+ num_bytes = ul_seg_size;
+ va_curr = ul_dsp_va * hio_mgr->word_size;
+ while (num_bytes) {
+ /*
+ * To find the max. page size with which both PA & VA are
+ * aligned.
+ */
+ all_bits = pa_curr | va_curr;
+ dev_dbg(bridge, "all_bits for Seg1 %x, pa_curr %x, "
+ "va_curr %x, num_bytes %x\n", all_bits, pa_curr,
+ va_curr, num_bytes);
+ for (i = 0; i < 4; i++) {
+ if (!(num_bytes >= page_size[i]) ||
+ !((all_bits & (page_size[i] - 1)) == 0))
+ continue;
+ if (ndx < MAX_LOCK_TLB_ENTRIES) {
+ /*
+ * This is the physical address written to
+ * DSP MMU.
+ */
+ ae_proc[ndx].ul_gpp_pa = pa_curr;
+ /*
+ * This is the virtual uncached ioremapped
+ * address!!!
+ */
+ ae_proc[ndx].ul_gpp_va = gpp_va_curr;
+ ae_proc[ndx].ul_dsp_va =
+ va_curr / hio_mgr->word_size;
+ ae_proc[ndx].ul_size = page_size[i];
+ ae_proc[ndx].endianism = HW_LITTLE_ENDIAN;
+ ae_proc[ndx].elem_size = HW_ELEM_SIZE16BIT;
+ ae_proc[ndx].mixed_mode = HW_MMU_CPUES;
+ dev_dbg(bridge, "shm MMU TLB entry PA %x"
+ " VA %x DSP_VA %x Size %x\n",
+ ae_proc[ndx].ul_gpp_pa,
+ ae_proc[ndx].ul_gpp_va,
+ ae_proc[ndx].ul_dsp_va *
+ hio_mgr->word_size, page_size[i]);
+ ndx++;
+ } else {
+ status =
+ hio_mgr->intf_fxns->
+ pfn_brd_mem_map(hio_mgr->hbridge_context,
+ pa_curr, va_curr,
+ page_size[i], map_attrs,
+ NULL);
+ dev_dbg(bridge,
+ "shm MMU PTE entry PA %x"
+ " VA %x DSP_VA %x Size %x\n",
+ ae_proc[ndx].ul_gpp_pa,
+ ae_proc[ndx].ul_gpp_va,
+ ae_proc[ndx].ul_dsp_va *
+ hio_mgr->word_size, page_size[i]);
+ if (status)
+ goto func_end;
+ }
+ pa_curr += page_size[i];
+ va_curr += page_size[i];
+ gpp_va_curr += page_size[i];
+ num_bytes -= page_size[i];
+ /*
+ * Don't try smaller sizes. Hopefully we have reached
+ * an address aligned to a bigger page size.
+ */
+ break;
+ }
+ }
+
+ /*
+ * Copy remaining entries from CDB. All entries are 1 MB and
+ * should not conflict with shm entries on MPU or DSP side.
+ */
+ for (i = 3; i < 7 && ndx < BRDIOCTL_NUMOFMMUTLB; i++) {
+ if (hio_mgr->ext_proc_info.ty_tlb[i].ul_gpp_phys == 0)
+ continue;
+
+ if ((hio_mgr->ext_proc_info.ty_tlb[i].ul_gpp_phys >
+ ul_gpp_pa - 0x100000
+ && hio_mgr->ext_proc_info.ty_tlb[i].ul_gpp_phys <=
+ ul_gpp_pa + ul_seg_size)
+ || (hio_mgr->ext_proc_info.ty_tlb[i].ul_dsp_virt >
+ ul_dsp_va - 0x100000 / hio_mgr->word_size
+ && hio_mgr->ext_proc_info.ty_tlb[i].ul_dsp_virt <=
+ ul_dsp_va + ul_seg_size / hio_mgr->word_size)) {
+ dev_dbg(bridge,
+ "CDB MMU entry %d conflicts with "
+ "shm.\n\tCDB: GppPa %x, DspVa %x.\n\tSHM: "
+ "GppPa %x, DspVa %x, Bytes %x.\n", i,
+ hio_mgr->ext_proc_info.ty_tlb[i].ul_gpp_phys,
+ hio_mgr->ext_proc_info.ty_tlb[i].ul_dsp_virt,
+ ul_gpp_pa, ul_dsp_va, ul_seg_size);
+ status = -EPERM;
+ } else {
+ if (ndx < MAX_LOCK_TLB_ENTRIES) {
+ ae_proc[ndx].ul_dsp_va =
+ hio_mgr->ext_proc_info.ty_tlb[i].
+ ul_dsp_virt;
+ ae_proc[ndx].ul_gpp_pa =
+ hio_mgr->ext_proc_info.ty_tlb[i].
+ ul_gpp_phys;
+ ae_proc[ndx].ul_gpp_va = 0;
+ /* 1 MB */
+ ae_proc[ndx].ul_size = 0x100000;
+ dev_dbg(bridge, "shm MMU entry PA %x "
+ "DSP_VA 0x%x\n", ae_proc[ndx].ul_gpp_pa,
+ ae_proc[ndx].ul_dsp_va);
+ ndx++;
+ } else {
+ status = hio_mgr->intf_fxns->pfn_brd_mem_map
+ (hio_mgr->hbridge_context,
+ hio_mgr->ext_proc_info.ty_tlb[i].
+ ul_gpp_phys,
+ hio_mgr->ext_proc_info.ty_tlb[i].
+ ul_dsp_virt, 0x100000, map_attrs,
+ NULL);
+ }
+ }
+ if (status)
+ goto func_end;
+ }
+
+ map_attrs = 0x00000000;
+ map_attrs = DSP_MAPLITTLEENDIAN;
+ map_attrs |= DSP_MAPPHYSICALADDR;
+ map_attrs |= DSP_MAPELEMSIZE32;
+ map_attrs |= DSP_MAPDONOTLOCK;
+
+ /* Map the L4 peripherals */
+ i = 0;
+ while (l4_peripheral_table[i].phys_addr) {
+ status = hio_mgr->intf_fxns->pfn_brd_mem_map
+ (hio_mgr->hbridge_context, l4_peripheral_table[i].phys_addr,
+ l4_peripheral_table[i].dsp_virt_addr, HW_PAGE_SIZE4KB,
+ map_attrs, NULL);
+ if (status)
+ goto func_end;
+ i++;
+ }
+
+ for (i = ndx; i < BRDIOCTL_NUMOFMMUTLB; i++) {
+ ae_proc[i].ul_dsp_va = 0;
+ ae_proc[i].ul_gpp_pa = 0;
+ ae_proc[i].ul_gpp_va = 0;
+ ae_proc[i].ul_size = 0;
+ }
+ /*
+ * Set the shm physical address entry (grayed out in CDB file)
+ * to the virtual uncached ioremapped address of shm reserved
+ * on MPU.
+ */
+ hio_mgr->ext_proc_info.ty_tlb[0].ul_gpp_phys =
+ (ul_gpp_va + ul_seg1_size + ul_pad_size);
+
+ /*
+ * Need shm Phys addr. IO supports only one DSP for now:
+ * num_procs = 1.
+ */
+ if (!hio_mgr->ext_proc_info.ty_tlb[0].ul_gpp_phys || num_procs != 1) {
+ status = -EFAULT;
+ goto func_end;
+ } else {
+ if (ae_proc[0].ul_dsp_va > ul_shm_base) {
+ status = -EPERM;
+ goto func_end;
+ }
+ /* ul_shm_base may not be at ul_dsp_va address */
+ ul_shm_base_offset = (ul_shm_base - ae_proc[0].ul_dsp_va) *
+ hio_mgr->word_size;
+ /*
+ * bridge_dev_ctrl() will set dev context dsp-mmu info. In
+ * bridge_brd_start() the MMU will be re-programed with MMU
+ * DSPVa-GPPPa pair info while DSP is in a known
+ * (reset) state.
+ */
+
+ status =
+ hio_mgr->intf_fxns->pfn_dev_cntrl(hio_mgr->hbridge_context,
+ BRDIOCTL_SETMMUCONFIG,
+ ae_proc);
+ if (status)
+ goto func_end;
+ ul_shm_base = hio_mgr->ext_proc_info.ty_tlb[0].ul_gpp_phys;
+ ul_shm_base += ul_shm_base_offset;
+ ul_shm_base = (u32) MEM_LINEAR_ADDRESS((void *)ul_shm_base,
+ ul_mem_length);
+ if (ul_shm_base == 0) {
+ status = -EFAULT;
+ goto func_end;
+ }
+ /* Register SM */
+ status =
+ register_shm_segs(hio_mgr, cod_man, ae_proc[0].ul_gpp_pa);
+ }
+
+ hio_mgr->shared_mem = (struct shm *)ul_shm_base;
+ hio_mgr->input = (u8 *) hio_mgr->shared_mem + sizeof(struct shm);
+ hio_mgr->output = hio_mgr->input + (ul_shm_length -
+ sizeof(struct shm)) / 2;
+ hio_mgr->usm_buf_size = hio_mgr->output - hio_mgr->input;
+
+ /* Set up Shared memory addresses for messaging. */
+ hio_mgr->msg_input_ctrl = (struct msg_ctrl *)((u8 *) hio_mgr->shared_mem
+ + ul_shm_length);
+ hio_mgr->msg_input =
+ (u8 *) hio_mgr->msg_input_ctrl + sizeof(struct msg_ctrl);
+ hio_mgr->msg_output_ctrl =
+ (struct msg_ctrl *)((u8 *) hio_mgr->msg_input_ctrl +
+ ul_msg_length / 2);
+ hio_mgr->msg_output =
+ (u8 *) hio_mgr->msg_output_ctrl + sizeof(struct msg_ctrl);
+ hmsg_mgr->max_msgs =
+ ((u8 *) hio_mgr->msg_output_ctrl - hio_mgr->msg_input)
+ / sizeof(struct msg_dspmsg);
+ dev_dbg(bridge, "IO MGR shm details: shared_mem %p, input %p, "
+ "output %p, msg_input_ctrl %p, msg_input %p, "
+ "msg_output_ctrl %p, msg_output %p\n",
+ (u8 *) hio_mgr->shared_mem, hio_mgr->input,
+ hio_mgr->output, (u8 *) hio_mgr->msg_input_ctrl,
+ hio_mgr->msg_input, (u8 *) hio_mgr->msg_output_ctrl,
+ hio_mgr->msg_output);
+ dev_dbg(bridge, "(proc) Mas msgs in shared memory: 0x%x\n",
+ hmsg_mgr->max_msgs);
+ memset((void *)hio_mgr->shared_mem, 0, sizeof(struct shm));
+
+#if defined(CONFIG_TIDSPBRIDGE_BACKTRACE) || defined(CONFIG_TIDSPBRIDGE_DEBUG)
+ /* Get the start address of trace buffer */
+ status = cod_get_sym_value(cod_man, SYS_PUTCBEG,
+ &hio_mgr->ul_trace_buffer_begin);
+ if (status) {
+ status = -EFAULT;
+ goto func_end;
+ }
+
+ hio_mgr->ul_gpp_read_pointer = hio_mgr->ul_trace_buffer_begin =
+ (ul_gpp_va + ul_seg1_size + ul_pad_size) +
+ (hio_mgr->ul_trace_buffer_begin - ul_dsp_va);
+ /* Get the end address of trace buffer */
+ status = cod_get_sym_value(cod_man, SYS_PUTCEND,
+ &hio_mgr->ul_trace_buffer_end);
+ if (status) {
+ status = -EFAULT;
+ goto func_end;
+ }
+ hio_mgr->ul_trace_buffer_end =
+ (ul_gpp_va + ul_seg1_size + ul_pad_size) +
+ (hio_mgr->ul_trace_buffer_end - ul_dsp_va);
+ /* Get the current address of DSP write pointer */
+ status = cod_get_sym_value(cod_man, BRIDGE_SYS_PUTC_CURRENT,
+ &hio_mgr->ul_trace_buffer_current);
+ if (status) {
+ status = -EFAULT;
+ goto func_end;
+ }
+ hio_mgr->ul_trace_buffer_current =
+ (ul_gpp_va + ul_seg1_size + ul_pad_size) +
+ (hio_mgr->ul_trace_buffer_current - ul_dsp_va);
+ /* Calculate the size of trace buffer */
+ kfree(hio_mgr->pmsg);
+ hio_mgr->pmsg = kmalloc(((hio_mgr->ul_trace_buffer_end -
+ hio_mgr->ul_trace_buffer_begin) *
+ hio_mgr->word_size) + 2, GFP_KERNEL);
+ if (!hio_mgr->pmsg)
+ status = -ENOMEM;
+
+ hio_mgr->ul_dsp_va = ul_dsp_va;
+ hio_mgr->ul_gpp_va = (ul_gpp_va + ul_seg1_size + ul_pad_size);
+
+#endif
+func_end:
+ return status;
+}
+
+/*
+ * ======== io_buf_size ========
+ * Size of shared memory I/O channel.
+ */
+u32 io_buf_size(struct io_mgr *hio_mgr)
+{
+ if (hio_mgr)
+ return hio_mgr->usm_buf_size;
+ else
+ return 0;
+}
+
+/*
+ * ======== io_cancel_chnl ========
+ * Cancel IO on a given PCPY channel.
+ */
+void io_cancel_chnl(struct io_mgr *hio_mgr, u32 chnl)
+{
+ struct io_mgr *pio_mgr = (struct io_mgr *)hio_mgr;
+ struct shm *sm;
+
+ if (!hio_mgr)
+ goto func_end;
+ sm = hio_mgr->shared_mem;
+
+ /* Inform DSP that we have no more buffers on this channel */
+ set_chnl_free(sm, chnl);
+
+ sm_interrupt_dsp(pio_mgr->hbridge_context, MBX_PCPY_CLASS);
+func_end:
+ return;
+}
+
+
+/*
+ * ======== io_dispatch_pm ========
+ * Performs I/O dispatch on PM related messages from DSP
+ */
+static void io_dispatch_pm(struct io_mgr *pio_mgr)
+{
+ int status;
+ u32 parg[2];
+
+ /* Perform Power message processing here */
+ parg[0] = pio_mgr->intr_val;
+
+ /* Send the command to the Bridge clk/pwr manager to handle */
+ if (parg[0] == MBX_PM_HIBERNATE_EN) {
+ dev_dbg(bridge, "PM: Hibernate command\n");
+ status = pio_mgr->intf_fxns->
+ pfn_dev_cntrl(pio_mgr->hbridge_context,
+ BRDIOCTL_PWR_HIBERNATE, parg);
+ if (status)
+ pr_err("%s: hibernate cmd failed 0x%x\n",
+ __func__, status);
+ } else if (parg[0] == MBX_PM_OPP_REQ) {
+ parg[1] = pio_mgr->shared_mem->opp_request.rqst_opp_pt;
+ dev_dbg(bridge, "PM: Requested OPP = 0x%x\n", parg[1]);
+ status = pio_mgr->intf_fxns->
+ pfn_dev_cntrl(pio_mgr->hbridge_context,
+ BRDIOCTL_CONSTRAINT_REQUEST, parg);
+ if (status)
+ dev_dbg(bridge, "PM: Failed to set constraint "
+ "= 0x%x\n", parg[1]);
+ } else {
+ dev_dbg(bridge, "PM: clk control value of msg = 0x%x\n",
+ parg[0]);
+ status = pio_mgr->intf_fxns->
+ pfn_dev_cntrl(pio_mgr->hbridge_context,
+ BRDIOCTL_CLK_CTRL, parg);
+ if (status)
+ dev_dbg(bridge, "PM: Failed to ctrl the DSP clk"
+ "= 0x%x\n", *parg);
+ }
+}
+
+/*
+ * ======== io_dpc ========
+ * Deferred procedure call for shared memory channel driver ISR. Carries
+ * out the dispatch of I/O as a non-preemptible event.It can only be
+ * pre-empted by an ISR.
+ */
+void io_dpc(unsigned long ref_data)
+{
+ struct io_mgr *pio_mgr = (struct io_mgr *)ref_data;
+ struct chnl_mgr *chnl_mgr_obj;
+ struct msg_mgr *msg_mgr_obj;
+ struct deh_mgr *hdeh_mgr;
+ u32 requested;
+ u32 serviced;
+
+ if (!pio_mgr)
+ goto func_end;
+ chnl_mgr_obj = pio_mgr->hchnl_mgr;
+ dev_get_msg_mgr(pio_mgr->hdev_obj, &msg_mgr_obj);
+ dev_get_deh_mgr(pio_mgr->hdev_obj, &hdeh_mgr);
+ if (!chnl_mgr_obj)
+ goto func_end;
+
+ requested = pio_mgr->dpc_req;
+ serviced = pio_mgr->dpc_sched;
+
+ if (serviced == requested)
+ goto func_end;
+
+ /* Process pending DPC's */
+ do {
+ /* Check value of interrupt reg to ensure it's a valid error */
+ if ((pio_mgr->intr_val > DEH_BASE) &&
+ (pio_mgr->intr_val < DEH_LIMIT)) {
+ /* Notify DSP/BIOS exception */
+ if (hdeh_mgr) {
+#ifdef CONFIG_TIDSPBRIDGE_BACKTRACE
+ print_dsp_debug_trace(pio_mgr);
+#endif
+ bridge_deh_notify(hdeh_mgr, DSP_SYSERROR,
+ pio_mgr->intr_val);
+ }
+ }
+ /* Proc-copy chanel dispatch */
+ input_chnl(pio_mgr, NULL, IO_SERVICE);
+ output_chnl(pio_mgr, NULL, IO_SERVICE);
+
+#ifdef CHNL_MESSAGES
+ if (msg_mgr_obj) {
+ /* Perform I/O dispatch on message queues */
+ input_msg(pio_mgr, msg_mgr_obj);
+ output_msg(pio_mgr, msg_mgr_obj);
+ }
+
+#endif
+#ifdef CONFIG_TIDSPBRIDGE_DEBUG
+ if (pio_mgr->intr_val & MBX_DBG_SYSPRINTF) {
+ /* Notify DSP Trace message */
+ print_dsp_debug_trace(pio_mgr);
+ }
+#endif
+ serviced++;
+ } while (serviced != requested);
+ pio_mgr->dpc_sched = requested;
+func_end:
+ return;
+}
+
+/*
+ * ======== io_mbox_msg ========
+ * Main interrupt handler for the shared memory IO manager.
+ * Calls the Bridge's CHNL_ISR to determine if this interrupt is ours, then
+ * schedules a DPC to dispatch I/O.
+ */
+void io_mbox_msg(u32 msg)
+{
+ struct io_mgr *pio_mgr;
+ struct dev_object *dev_obj;
+ unsigned long flags;
+
+ dev_obj = dev_get_first();
+ dev_get_io_mgr(dev_obj, &pio_mgr);
+
+ if (!pio_mgr)
+ return;
+
+ pio_mgr->intr_val = (u16)msg;
+ if (pio_mgr->intr_val & MBX_PM_CLASS)
+ io_dispatch_pm(pio_mgr);
+
+ if (pio_mgr->intr_val == MBX_DEH_RESET) {
+ pio_mgr->intr_val = 0;
+ } else {
+ spin_lock_irqsave(&pio_mgr->dpc_lock, flags);
+ pio_mgr->dpc_req++;
+ spin_unlock_irqrestore(&pio_mgr->dpc_lock, flags);
+ tasklet_schedule(&pio_mgr->dpc_tasklet);
+ }
+ return;
+}
+
+/*
+ * ======== io_request_chnl ========
+ * Purpose:
+ * Request chanenel I/O from the DSP. Sets flags in shared memory, then
+ * interrupts the DSP.
+ */
+void io_request_chnl(struct io_mgr *io_manager, struct chnl_object *pchnl,
+ u8 io_mode, u16 *mbx_val)
+{
+ struct chnl_mgr *chnl_mgr_obj;
+ struct shm *sm;
+
+ if (!pchnl || !mbx_val)
+ goto func_end;
+ chnl_mgr_obj = io_manager->hchnl_mgr;
+ sm = io_manager->shared_mem;
+ if (io_mode == IO_INPUT) {
+ /*
+ * Assertion fires if CHNL_AddIOReq() called on a stream
+ * which was cancelled, or attached to a dead board.
+ */
+ DBC_ASSERT((pchnl->dw_state == CHNL_STATEREADY) ||
+ (pchnl->dw_state == CHNL_STATEEOS));
+ /* Indicate to the DSP we have a buffer available for input */
+ set_chnl_busy(sm, pchnl->chnl_id);
+ *mbx_val = MBX_PCPY_CLASS;
+ } else if (io_mode == IO_OUTPUT) {
+ /*
+ * This assertion fails if CHNL_AddIOReq() was called on a
+ * stream which was cancelled, or attached to a dead board.
+ */
+ DBC_ASSERT((pchnl->dw_state & ~CHNL_STATEEOS) ==
+ CHNL_STATEREADY);
+ /*
+ * Record the fact that we have a buffer available for
+ * output.
+ */
+ chnl_mgr_obj->dw_output_mask |= (1 << pchnl->chnl_id);
+ } else {
+ DBC_ASSERT(io_mode); /* Shouldn't get here. */
+ }
+func_end:
+ return;
+}
+
+/*
+ * ======== iosm_schedule ========
+ * Schedule DPC for IO.
+ */
+void iosm_schedule(struct io_mgr *io_manager)
+{
+ unsigned long flags;
+
+ if (!io_manager)
+ return;
+
+ /* Increment count of DPC's pending. */
+ spin_lock_irqsave(&io_manager->dpc_lock, flags);
+ io_manager->dpc_req++;
+ spin_unlock_irqrestore(&io_manager->dpc_lock, flags);
+
+ /* Schedule DPC */
+ tasklet_schedule(&io_manager->dpc_tasklet);
+}
+
+/*
+ * ======== find_ready_output ========
+ * Search for a host output channel which is ready to send. If this is
+ * called as a result of servicing the DPC, then implement a round
+ * robin search; otherwise, this was called by a client thread (via
+ * IO_Dispatch()), so just start searching from the current channel id.
+ */
+static u32 find_ready_output(struct chnl_mgr *chnl_mgr_obj,
+ struct chnl_object *pchnl, u32 mask)
+{
+ u32 ret = OUTPUTNOTREADY;
+ u32 id, start_id;
+ u32 shift;
+
+ id = (pchnl !=
+ NULL ? pchnl->chnl_id : (chnl_mgr_obj->dw_last_output + 1));
+ id = ((id == CHNL_MAXCHANNELS) ? 0 : id);
+ if (id >= CHNL_MAXCHANNELS)
+ goto func_end;
+ if (mask) {
+ shift = (1 << id);
+ start_id = id;
+ do {
+ if (mask & shift) {
+ ret = id;
+ if (pchnl == NULL)
+ chnl_mgr_obj->dw_last_output = id;
+ break;
+ }
+ id = id + 1;
+ id = ((id == CHNL_MAXCHANNELS) ? 0 : id);
+ shift = (1 << id);
+ } while (id != start_id);
+ }
+func_end:
+ return ret;
+}
+
+/*
+ * ======== input_chnl ========
+ * Dispatch a buffer on an input channel.
+ */
+static void input_chnl(struct io_mgr *pio_mgr, struct chnl_object *pchnl,
+ u8 io_mode)
+{
+ struct chnl_mgr *chnl_mgr_obj;
+ struct shm *sm;
+ u32 chnl_id;
+ u32 bytes;
+ struct chnl_irp *chnl_packet_obj = NULL;
+ u32 dw_arg;
+ bool clear_chnl = false;
+ bool notify_client = false;
+
+ sm = pio_mgr->shared_mem;
+ chnl_mgr_obj = pio_mgr->hchnl_mgr;
+
+ /* Attempt to perform input */
+ if (!sm->input_full)
+ goto func_end;
+
+ bytes = sm->input_size * chnl_mgr_obj->word_size;
+ chnl_id = sm->input_id;
+ dw_arg = sm->arg;
+ if (chnl_id >= CHNL_MAXCHANNELS) {
+ /* Shouldn't be here: would indicate corrupted shm. */
+ DBC_ASSERT(chnl_id);
+ goto func_end;
+ }
+ pchnl = chnl_mgr_obj->ap_channel[chnl_id];
+ if ((pchnl != NULL) && CHNL_IS_INPUT(pchnl->chnl_mode)) {
+ if ((pchnl->dw_state & ~CHNL_STATEEOS) == CHNL_STATEREADY) {
+ if (!pchnl->pio_requests)
+ goto func_end;
+ /* Get the I/O request, and attempt a transfer */
+ chnl_packet_obj = (struct chnl_irp *)
+ lst_get_head(pchnl->pio_requests);
+ if (chnl_packet_obj) {
+ pchnl->cio_reqs--;
+ if (pchnl->cio_reqs < 0)
+ goto func_end;
+ /*
+ * Ensure we don't overflow the client's
+ * buffer.
+ */
+ bytes = min(bytes, chnl_packet_obj->byte_size);
+ memcpy(chnl_packet_obj->host_sys_buf,
+ pio_mgr->input, bytes);
+ pchnl->bytes_moved += bytes;
+ chnl_packet_obj->byte_size = bytes;
+ chnl_packet_obj->dw_arg = dw_arg;
+ chnl_packet_obj->status = CHNL_IOCSTATCOMPLETE;
+
+ if (bytes == 0) {
+ /*
+ * This assertion fails if the DSP
+ * sends EOS more than once on this
+ * channel.
+ */
+ if (pchnl->dw_state & CHNL_STATEEOS)
+ goto func_end;
+ /*
+ * Zero bytes indicates EOS. Update
+ * IOC status for this chirp, and also
+ * the channel state.
+ */
+ chnl_packet_obj->status |=
+ CHNL_IOCSTATEOS;
+ pchnl->dw_state |= CHNL_STATEEOS;
+ /*
+ * Notify that end of stream has
+ * occurred.
+ */
+ ntfy_notify(pchnl->ntfy_obj,
+ DSP_STREAMDONE);
+ }
+ /* Tell DSP if no more I/O buffers available */
+ if (!pchnl->pio_requests)
+ goto func_end;
+ if (LST_IS_EMPTY(pchnl->pio_requests)) {
+ set_chnl_free(sm, pchnl->chnl_id);
+ }
+ clear_chnl = true;
+ notify_client = true;
+ } else {
+ /*
+ * Input full for this channel, but we have no
+ * buffers available. The channel must be
+ * "idling". Clear out the physical input
+ * channel.
+ */
+ clear_chnl = true;
+ }
+ } else {
+ /* Input channel cancelled: clear input channel */
+ clear_chnl = true;
+ }
+ } else {
+ /* DPC fired after host closed channel: clear input channel */
+ clear_chnl = true;
+ }
+ if (clear_chnl) {
+ /* Indicate to the DSP we have read the input */
+ sm->input_full = 0;
+ sm_interrupt_dsp(pio_mgr->hbridge_context, MBX_PCPY_CLASS);
+ }
+ if (notify_client) {
+ /* Notify client with IO completion record */
+ notify_chnl_complete(pchnl, chnl_packet_obj);
+ }
+func_end:
+ return;
+}
+
+/*
+ * ======== input_msg ========
+ * Copies messages from shared memory to the message queues.
+ */
+static void input_msg(struct io_mgr *pio_mgr, struct msg_mgr *hmsg_mgr)
+{
+ u32 num_msgs;
+ u32 i;
+ u8 *msg_input;
+ struct msg_queue *msg_queue_obj;
+ struct msg_frame *pmsg;
+ struct msg_dspmsg msg;
+ struct msg_ctrl *msg_ctr_obj;
+ u32 input_empty;
+ u32 addr;
+
+ msg_ctr_obj = pio_mgr->msg_input_ctrl;
+ /* Get the number of input messages to be read */
+ input_empty = msg_ctr_obj->buf_empty;
+ num_msgs = msg_ctr_obj->size;
+ if (input_empty)
+ goto func_end;
+
+ msg_input = pio_mgr->msg_input;
+ for (i = 0; i < num_msgs; i++) {
+ /* Read the next message */
+ addr = (u32) &(((struct msg_dspmsg *)msg_input)->msg.dw_cmd);
+ msg.msg.dw_cmd =
+ read_ext32_bit_dsp_data(pio_mgr->hbridge_context, addr);
+ addr = (u32) &(((struct msg_dspmsg *)msg_input)->msg.dw_arg1);
+ msg.msg.dw_arg1 =
+ read_ext32_bit_dsp_data(pio_mgr->hbridge_context, addr);
+ addr = (u32) &(((struct msg_dspmsg *)msg_input)->msg.dw_arg2);
+ msg.msg.dw_arg2 =
+ read_ext32_bit_dsp_data(pio_mgr->hbridge_context, addr);
+ addr = (u32) &(((struct msg_dspmsg *)msg_input)->msgq_id);
+ msg.msgq_id =
+ read_ext32_bit_dsp_data(pio_mgr->hbridge_context, addr);
+ msg_input += sizeof(struct msg_dspmsg);
+ if (!hmsg_mgr->queue_list)
+ goto func_end;
+
+ /* Determine which queue to put the message in */
+ msg_queue_obj =
+ (struct msg_queue *)lst_first(hmsg_mgr->queue_list);
+ dev_dbg(bridge, "input msg: dw_cmd=0x%x dw_arg1=0x%x "
+ "dw_arg2=0x%x msgq_id=0x%x \n", msg.msg.dw_cmd,
+ msg.msg.dw_arg1, msg.msg.dw_arg2, msg.msgq_id);
+ /*
+ * Interrupt may occur before shared memory and message
+ * input locations have been set up. If all nodes were
+ * cleaned up, hmsg_mgr->max_msgs should be 0.
+ */
+ while (msg_queue_obj != NULL) {
+ if (msg.msgq_id == msg_queue_obj->msgq_id) {
+ /* Found it */
+ if (msg.msg.dw_cmd == RMS_EXITACK) {
+ /*
+ * Call the node exit notification.
+ * The exit message does not get
+ * queued.
+ */
+ (*hmsg_mgr->on_exit) ((void *)
+ msg_queue_obj->arg,
+ msg.msg.dw_arg1);
+ } else {
+ /*
+ * Not an exit acknowledgement, queue
+ * the message.
+ */
+ if (!msg_queue_obj->msg_free_list)
+ goto func_end;
+ pmsg = (struct msg_frame *)lst_get_head
+ (msg_queue_obj->msg_free_list);
+ if (msg_queue_obj->msg_used_list
+ && pmsg) {
+ pmsg->msg_data = msg;
+ lst_put_tail
+ (msg_queue_obj->msg_used_list,
+ (struct list_head *)pmsg);
+ ntfy_notify
+ (msg_queue_obj->ntfy_obj,
+ DSP_NODEMESSAGEREADY);
+ sync_set_event
+ (msg_queue_obj->sync_event);
+ } else {
+ /*
+ * No free frame to copy the
+ * message into.
+ */
+ pr_err("%s: no free msg frames,"
+ " discarding msg\n",
+ __func__);
+ }
+ }
+ break;
+ }
+
+ if (!hmsg_mgr->queue_list || !msg_queue_obj)
+ goto func_end;
+ msg_queue_obj =
+ (struct msg_queue *)lst_next(hmsg_mgr->queue_list,
+ (struct list_head *)
+ msg_queue_obj);
+ }
+ }
+ /* Set the post SWI flag */
+ if (num_msgs > 0) {
+ /* Tell the DSP we've read the messages */
+ msg_ctr_obj->buf_empty = true;
+ msg_ctr_obj->post_swi = true;
+ sm_interrupt_dsp(pio_mgr->hbridge_context, MBX_PCPY_CLASS);
+ }
+func_end:
+ return;
+}
+
+/*
+ * ======== notify_chnl_complete ========
+ * Purpose:
+ * Signal the channel event, notifying the client that I/O has completed.
+ */
+static void notify_chnl_complete(struct chnl_object *pchnl,
+ struct chnl_irp *chnl_packet_obj)
+{
+ bool signal_event;
+
+ if (!pchnl || !pchnl->sync_event ||
+ !pchnl->pio_completions || !chnl_packet_obj)
+ goto func_end;
+
+ /*
+ * Note: we signal the channel event only if the queue of IO
+ * completions is empty. If it is not empty, the event is sure to be
+ * signalled by the only IO completion list consumer:
+ * bridge_chnl_get_ioc().
+ */
+ signal_event = LST_IS_EMPTY(pchnl->pio_completions);
+ /* Enqueue the IO completion info for the client */
+ lst_put_tail(pchnl->pio_completions,
+ (struct list_head *)chnl_packet_obj);
+ pchnl->cio_cs++;
+
+ if (pchnl->cio_cs > pchnl->chnl_packets)
+ goto func_end;
+ /* Signal the channel event (if not already set) that IO is complete */
+ if (signal_event)
+ sync_set_event(pchnl->sync_event);
+
+ /* Notify that IO is complete */
+ ntfy_notify(pchnl->ntfy_obj, DSP_STREAMIOCOMPLETION);
+func_end:
+ return;
+}
+
+/*
+ * ======== output_chnl ========
+ * Purpose:
+ * Dispatch a buffer on an output channel.
+ */
+static void output_chnl(struct io_mgr *pio_mgr, struct chnl_object *pchnl,
+ u8 io_mode)
+{
+ struct chnl_mgr *chnl_mgr_obj;
+ struct shm *sm;
+ u32 chnl_id;
+ struct chnl_irp *chnl_packet_obj;
+ u32 dw_dsp_f_mask;
+
+ chnl_mgr_obj = pio_mgr->hchnl_mgr;
+ sm = pio_mgr->shared_mem;
+ /* Attempt to perform output */
+ if (sm->output_full)
+ goto func_end;
+
+ if (pchnl && !((pchnl->dw_state & ~CHNL_STATEEOS) == CHNL_STATEREADY))
+ goto func_end;
+
+ /* Look to see if both a PC and DSP output channel are ready */
+ dw_dsp_f_mask = sm->dsp_free_mask;
+ chnl_id =
+ find_ready_output(chnl_mgr_obj, pchnl,
+ (chnl_mgr_obj->dw_output_mask & dw_dsp_f_mask));
+ if (chnl_id == OUTPUTNOTREADY)
+ goto func_end;
+
+ pchnl = chnl_mgr_obj->ap_channel[chnl_id];
+ if (!pchnl || !pchnl->pio_requests) {
+ /* Shouldn't get here */
+ goto func_end;
+ }
+ /* Get the I/O request, and attempt a transfer */
+ chnl_packet_obj = (struct chnl_irp *)lst_get_head(pchnl->pio_requests);
+ if (!chnl_packet_obj)
+ goto func_end;
+
+ pchnl->cio_reqs--;
+ if (pchnl->cio_reqs < 0 || !pchnl->pio_requests)
+ goto func_end;
+
+ /* Record fact that no more I/O buffers available */
+ if (LST_IS_EMPTY(pchnl->pio_requests))
+ chnl_mgr_obj->dw_output_mask &= ~(1 << chnl_id);
+
+ /* Transfer buffer to DSP side */
+ chnl_packet_obj->byte_size = min(pio_mgr->usm_buf_size,
+ chnl_packet_obj->byte_size);
+ memcpy(pio_mgr->output, chnl_packet_obj->host_sys_buf,
+ chnl_packet_obj->byte_size);
+ pchnl->bytes_moved += chnl_packet_obj->byte_size;
+ /* Write all 32 bits of arg */
+ sm->arg = chnl_packet_obj->dw_arg;
+#if _CHNL_WORDSIZE == 2
+ /* Access can be different SM access word size (e.g. 16/32 bit words) */
+ sm->output_id = (u16) chnl_id;
+ sm->output_size = (u16) (chnl_packet_obj->byte_size +
+ chnl_mgr_obj->word_size - 1) /
+ (u16) chnl_mgr_obj->word_size;
+#else
+ sm->output_id = chnl_id;
+ sm->output_size = (chnl_packet_obj->byte_size +
+ chnl_mgr_obj->word_size - 1) / chnl_mgr_obj->word_size;
+#endif
+ sm->output_full = 1;
+ /* Indicate to the DSP we have written the output */
+ sm_interrupt_dsp(pio_mgr->hbridge_context, MBX_PCPY_CLASS);
+ /* Notify client with IO completion record (keep EOS) */
+ chnl_packet_obj->status &= CHNL_IOCSTATEOS;
+ notify_chnl_complete(pchnl, chnl_packet_obj);
+ /* Notify if stream is done. */
+ if (chnl_packet_obj->status & CHNL_IOCSTATEOS)
+ ntfy_notify(pchnl->ntfy_obj, DSP_STREAMDONE);
+
+func_end:
+ return;
+}
+
+/*
+ * ======== output_msg ========
+ * Copies messages from the message queues to the shared memory.
+ */
+static void output_msg(struct io_mgr *pio_mgr, struct msg_mgr *hmsg_mgr)
+{
+ u32 num_msgs = 0;
+ u32 i;
+ u8 *msg_output;
+ struct msg_frame *pmsg;
+ struct msg_ctrl *msg_ctr_obj;
+ u32 output_empty;
+ u32 val;
+ u32 addr;
+
+ msg_ctr_obj = pio_mgr->msg_output_ctrl;
+
+ /* Check if output has been cleared */
+ output_empty = msg_ctr_obj->buf_empty;
+ if (output_empty) {
+ num_msgs = (hmsg_mgr->msgs_pending > hmsg_mgr->max_msgs) ?
+ hmsg_mgr->max_msgs : hmsg_mgr->msgs_pending;
+ msg_output = pio_mgr->msg_output;
+ /* Copy num_msgs messages into shared memory */
+ for (i = 0; i < num_msgs; i++) {
+ if (!hmsg_mgr->msg_used_list) {
+ pmsg = NULL;
+ goto func_end;
+ } else {
+ pmsg = (struct msg_frame *)
+ lst_get_head(hmsg_mgr->msg_used_list);
+ }
+ if (pmsg != NULL) {
+ val = (pmsg->msg_data).msgq_id;
+ addr = (u32) &(((struct msg_dspmsg *)
+ msg_output)->msgq_id);
+ write_ext32_bit_dsp_data(
+ pio_mgr->hbridge_context, addr, val);
+ val = (pmsg->msg_data).msg.dw_cmd;
+ addr = (u32) &((((struct msg_dspmsg *)
+ msg_output)->msg).dw_cmd);
+ write_ext32_bit_dsp_data(
+ pio_mgr->hbridge_context, addr, val);
+ val = (pmsg->msg_data).msg.dw_arg1;
+ addr = (u32) &((((struct msg_dspmsg *)
+ msg_output)->msg).dw_arg1);
+ write_ext32_bit_dsp_data(
+ pio_mgr->hbridge_context, addr, val);
+ val = (pmsg->msg_data).msg.dw_arg2;
+ addr = (u32) &((((struct msg_dspmsg *)
+ msg_output)->msg).dw_arg2);
+ write_ext32_bit_dsp_data(
+ pio_mgr->hbridge_context, addr, val);
+ msg_output += sizeof(struct msg_dspmsg);
+ if (!hmsg_mgr->msg_free_list)
+ goto func_end;
+ lst_put_tail(hmsg_mgr->msg_free_list,
+ (struct list_head *)pmsg);
+ sync_set_event(hmsg_mgr->sync_event);
+ }
+ }
+
+ if (num_msgs > 0) {
+ hmsg_mgr->msgs_pending -= num_msgs;
+#if _CHNL_WORDSIZE == 2
+ /*
+ * Access can be different SM access word size
+ * (e.g. 16/32 bit words)
+ */
+ msg_ctr_obj->size = (u16) num_msgs;
+#else
+ msg_ctr_obj->size = num_msgs;
+#endif
+ msg_ctr_obj->buf_empty = false;
+ /* Set the post SWI flag */
+ msg_ctr_obj->post_swi = true;
+ /* Tell the DSP we have written the output. */
+ sm_interrupt_dsp(pio_mgr->hbridge_context,
+ MBX_PCPY_CLASS);
+ }
+ }
+func_end:
+ return;
+}
+
+/*
+ * ======== register_shm_segs ========
+ * purpose:
+ * Registers GPP SM segment with CMM.
+ */
+static int register_shm_segs(struct io_mgr *hio_mgr,
+ struct cod_manager *cod_man,
+ u32 dw_gpp_base_pa)
+{
+ int status = 0;
+ u32 ul_shm0_base = 0;
+ u32 shm0_end = 0;
+ u32 ul_shm0_rsrvd_start = 0;
+ u32 ul_rsrvd_size = 0;
+ u32 ul_gpp_phys;
+ u32 ul_dsp_virt;
+ u32 ul_shm_seg_id0 = 0;
+ u32 dw_offset, dw_gpp_base_va, ul_dsp_size;
+
+ /*
+ * Read address and size info for first SM region.
+ * Get start of 1st SM Heap region.
+ */
+ status =
+ cod_get_sym_value(cod_man, SHM0_SHARED_BASE_SYM, &ul_shm0_base);
+ if (ul_shm0_base == 0) {
+ status = -EPERM;
+ goto func_end;
+ }
+ /* Get end of 1st SM Heap region */
+ if (!status) {
+ /* Get start and length of message part of shared memory */
+ status = cod_get_sym_value(cod_man, SHM0_SHARED_END_SYM,
+ &shm0_end);
+ if (shm0_end == 0) {
+ status = -EPERM;
+ goto func_end;
+ }
+ }
+ /* Start of Gpp reserved region */
+ if (!status) {
+ /* Get start and length of message part of shared memory */
+ status =
+ cod_get_sym_value(cod_man, SHM0_SHARED_RESERVED_BASE_SYM,
+ &ul_shm0_rsrvd_start);
+ if (ul_shm0_rsrvd_start == 0) {
+ status = -EPERM;
+ goto func_end;
+ }
+ }
+ /* Register with CMM */
+ if (!status) {
+ status = dev_get_cmm_mgr(hio_mgr->hdev_obj, &hio_mgr->hcmm_mgr);
+ if (!status) {
+ status = cmm_un_register_gppsm_seg(hio_mgr->hcmm_mgr,
+ CMM_ALLSEGMENTS);
+ }
+ }
+ /* Register new SM region(s) */
+ if (!status && (shm0_end - ul_shm0_base) > 0) {
+ /* Calc size (bytes) of SM the GPP can alloc from */
+ ul_rsrvd_size =
+ (shm0_end - ul_shm0_rsrvd_start + 1) * hio_mgr->word_size;
+ if (ul_rsrvd_size <= 0) {
+ status = -EPERM;
+ goto func_end;
+ }
+ /* Calc size of SM DSP can alloc from */
+ ul_dsp_size =
+ (ul_shm0_rsrvd_start - ul_shm0_base) * hio_mgr->word_size;
+ if (ul_dsp_size <= 0) {
+ status = -EPERM;
+ goto func_end;
+ }
+ /* First TLB entry reserved for Bridge SM use. */
+ ul_gpp_phys = hio_mgr->ext_proc_info.ty_tlb[0].ul_gpp_phys;
+ /* Get size in bytes */
+ ul_dsp_virt =
+ hio_mgr->ext_proc_info.ty_tlb[0].ul_dsp_virt *
+ hio_mgr->word_size;
+ /*
+ * Calc byte offset used to convert GPP phys <-> DSP byte
+ * address.
+ */
+ if (dw_gpp_base_pa > ul_dsp_virt)
+ dw_offset = dw_gpp_base_pa - ul_dsp_virt;
+ else
+ dw_offset = ul_dsp_virt - dw_gpp_base_pa;
+
+ if (ul_shm0_rsrvd_start * hio_mgr->word_size < ul_dsp_virt) {
+ status = -EPERM;
+ goto func_end;
+ }
+ /*
+ * Calc Gpp phys base of SM region.
+ * This is actually uncached kernel virtual address.
+ */
+ dw_gpp_base_va =
+ ul_gpp_phys + ul_shm0_rsrvd_start * hio_mgr->word_size -
+ ul_dsp_virt;
+ /*
+ * Calc Gpp phys base of SM region.
+ * This is the physical address.
+ */
+ dw_gpp_base_pa =
+ dw_gpp_base_pa + ul_shm0_rsrvd_start * hio_mgr->word_size -
+ ul_dsp_virt;
+ /* Register SM Segment 0. */
+ status =
+ cmm_register_gppsm_seg(hio_mgr->hcmm_mgr, dw_gpp_base_pa,
+ ul_rsrvd_size, dw_offset,
+ (dw_gpp_base_pa >
+ ul_dsp_virt) ? CMM_ADDTODSPPA :
+ CMM_SUBFROMDSPPA,
+ (u32) (ul_shm0_base *
+ hio_mgr->word_size),
+ ul_dsp_size, &ul_shm_seg_id0,
+ dw_gpp_base_va);
+ /* First SM region is seg_id = 1 */
+ if (ul_shm_seg_id0 != 1)
+ status = -EPERM;
+ }
+func_end:
+ return status;
+}
+
+/* ZCPY IO routines. */
+/*
+ * ======== IO_SHMcontrol ========
+ * Sets the requested shm setting.
+ */
+int io_sh_msetting(struct io_mgr *hio_mgr, u8 desc, void *pargs)
+{
+#ifdef CONFIG_TIDSPBRIDGE_DVFS
+ u32 i;
+ struct dspbridge_platform_data *pdata =
+ omap_dspbridge_dev->dev.platform_data;
+
+ switch (desc) {
+ case SHM_CURROPP:
+ /* Update the shared memory with requested OPP information */
+ if (pargs != NULL)
+ hio_mgr->shared_mem->opp_table_struct.curr_opp_pt =
+ *(u32 *) pargs;
+ else
+ return -EPERM;
+ break;
+ case SHM_OPPINFO:
+ /*
+ * Update the shared memory with the voltage, frequency,
+ * min and max frequency values for an OPP.
+ */
+ for (i = 0; i <= dsp_max_opps; i++) {
+ hio_mgr->shared_mem->opp_table_struct.opp_point[i].
+ voltage = vdd1_dsp_freq[i][0];
+ dev_dbg(bridge, "OPP-shm: voltage: %d\n",
+ vdd1_dsp_freq[i][0]);
+ hio_mgr->shared_mem->opp_table_struct.
+ opp_point[i].frequency = vdd1_dsp_freq[i][1];
+ dev_dbg(bridge, "OPP-shm: frequency: %d\n",
+ vdd1_dsp_freq[i][1]);
+ hio_mgr->shared_mem->opp_table_struct.opp_point[i].
+ min_freq = vdd1_dsp_freq[i][2];
+ dev_dbg(bridge, "OPP-shm: min freq: %d\n",
+ vdd1_dsp_freq[i][2]);
+ hio_mgr->shared_mem->opp_table_struct.opp_point[i].
+ max_freq = vdd1_dsp_freq[i][3];
+ dev_dbg(bridge, "OPP-shm: max freq: %d\n",
+ vdd1_dsp_freq[i][3]);
+ }
+ hio_mgr->shared_mem->opp_table_struct.num_opp_pts =
+ dsp_max_opps;
+ dev_dbg(bridge, "OPP-shm: max OPP number: %d\n", dsp_max_opps);
+ /* Update the current OPP number */
+ if (pdata->dsp_get_opp)
+ i = (*pdata->dsp_get_opp) ();
+ hio_mgr->shared_mem->opp_table_struct.curr_opp_pt = i;
+ dev_dbg(bridge, "OPP-shm: value programmed = %d\n", i);
+ break;
+ case SHM_GETOPP:
+ /* Get the OPP that DSP has requested */
+ *(u32 *) pargs = hio_mgr->shared_mem->opp_request.rqst_opp_pt;
+ break;
+ default:
+ break;
+ }
+#endif
+ return 0;
+}
+
+/*
+ * ======== bridge_io_get_proc_load ========
+ * Gets the Processor's Load information
+ */
+int bridge_io_get_proc_load(struct io_mgr *hio_mgr,
+ struct dsp_procloadstat *proc_lstat)
+{
+ proc_lstat->curr_load =
+ hio_mgr->shared_mem->load_mon_info.curr_dsp_load;
+ proc_lstat->predicted_load =
+ hio_mgr->shared_mem->load_mon_info.pred_dsp_load;
+ proc_lstat->curr_dsp_freq =
+ hio_mgr->shared_mem->load_mon_info.curr_dsp_freq;
+ proc_lstat->predicted_freq =
+ hio_mgr->shared_mem->load_mon_info.pred_dsp_freq;
+
+ dev_dbg(bridge, "Curr Load = %d, Pred Load = %d, Curr Freq = %d, "
+ "Pred Freq = %d\n", proc_lstat->curr_load,
+ proc_lstat->predicted_load, proc_lstat->curr_dsp_freq,
+ proc_lstat->predicted_freq);
+ return 0;
+}
+
+void io_sm_init(void)
+{
+ /* Do nothing */
+}
+
+#if defined(CONFIG_TIDSPBRIDGE_BACKTRACE) || defined(CONFIG_TIDSPBRIDGE_DEBUG)
+void print_dsp_debug_trace(struct io_mgr *hio_mgr)
+{
+ u32 ul_new_message_length = 0, ul_gpp_cur_pointer;
+
+ while (true) {
+ /* Get the DSP current pointer */
+ ul_gpp_cur_pointer =
+ *(u32 *) (hio_mgr->ul_trace_buffer_current);
+ ul_gpp_cur_pointer =
+ hio_mgr->ul_gpp_va + (ul_gpp_cur_pointer -
+ hio_mgr->ul_dsp_va);
+
+ /* No new debug messages available yet */
+ if (ul_gpp_cur_pointer == hio_mgr->ul_gpp_read_pointer) {
+ break;
+ } else if (ul_gpp_cur_pointer > hio_mgr->ul_gpp_read_pointer) {
+ /* Continuous data */
+ ul_new_message_length =
+ ul_gpp_cur_pointer - hio_mgr->ul_gpp_read_pointer;
+
+ memcpy(hio_mgr->pmsg,
+ (char *)hio_mgr->ul_gpp_read_pointer,
+ ul_new_message_length);
+ hio_mgr->pmsg[ul_new_message_length] = '\0';
+ /*
+ * Advance the GPP trace pointer to DSP current
+ * pointer.
+ */
+ hio_mgr->ul_gpp_read_pointer += ul_new_message_length;
+ /* Print the trace messages */
+ pr_info("DSPTrace: %s\n", hio_mgr->pmsg);
+ } else if (ul_gpp_cur_pointer < hio_mgr->ul_gpp_read_pointer) {
+ /* Handle trace buffer wraparound */
+ memcpy(hio_mgr->pmsg,
+ (char *)hio_mgr->ul_gpp_read_pointer,
+ hio_mgr->ul_trace_buffer_end -
+ hio_mgr->ul_gpp_read_pointer);
+ ul_new_message_length =
+ ul_gpp_cur_pointer - hio_mgr->ul_trace_buffer_begin;
+ memcpy(&hio_mgr->pmsg[hio_mgr->ul_trace_buffer_end -
+ hio_mgr->ul_gpp_read_pointer],
+ (char *)hio_mgr->ul_trace_buffer_begin,
+ ul_new_message_length);
+ hio_mgr->pmsg[hio_mgr->ul_trace_buffer_end -
+ hio_mgr->ul_gpp_read_pointer +
+ ul_new_message_length] = '\0';
+ /*
+ * Advance the GPP trace pointer to DSP current
+ * pointer.
+ */
+ hio_mgr->ul_gpp_read_pointer =
+ hio_mgr->ul_trace_buffer_begin +
+ ul_new_message_length;
+ /* Print the trace messages */
+ pr_info("DSPTrace: %s\n", hio_mgr->pmsg);
+ }
+ }
+}
+#endif
+
+#ifdef CONFIG_TIDSPBRIDGE_BACKTRACE
+/*
+ * ======== print_dsp_trace_buffer ========
+ * Prints the trace buffer returned from the DSP (if DBG_Trace is enabled).
+ * Parameters:
+ * hdeh_mgr: Handle to DEH manager object
+ * number of extra carriage returns to generate.
+ * Returns:
+ * 0: Success.
+ * -ENOMEM: Unable to allocate memory.
+ * Requires:
+ * hdeh_mgr muse be valid. Checked in bridge_deh_notify.
+ */
+int print_dsp_trace_buffer(struct bridge_dev_context *hbridge_context)
+{
+ int status = 0;
+ struct cod_manager *cod_mgr;
+ u32 ul_trace_end;
+ u32 ul_trace_begin;
+ u32 trace_cur_pos;
+ u32 ul_num_bytes = 0;
+ u32 ul_num_words = 0;
+ u32 ul_word_size = 2;
+ char *psz_buf;
+ char *str_beg;
+ char *trace_end;
+ char *buf_end;
+ char *new_line;
+
+ struct bridge_dev_context *pbridge_context = hbridge_context;
+ struct bridge_drv_interface *intf_fxns;
+ struct dev_object *dev_obj = (struct dev_object *)
+ pbridge_context->hdev_obj;
+
+ status = dev_get_cod_mgr(dev_obj, &cod_mgr);
+
+ if (cod_mgr) {
+ /* Look for SYS_PUTCBEG/SYS_PUTCEND */
+ status =
+ cod_get_sym_value(cod_mgr, COD_TRACEBEG, &ul_trace_begin);
+ } else {
+ status = -EFAULT;
+ }
+ if (!status)
+ status =
+ cod_get_sym_value(cod_mgr, COD_TRACEEND, &ul_trace_end);
+
+ if (!status)
+ /* trace_cur_pos will hold the address of a DSP pointer */
+ status = cod_get_sym_value(cod_mgr, COD_TRACECURPOS,
+ &trace_cur_pos);
+
+ if (status)
+ goto func_end;
+
+ ul_num_bytes = (ul_trace_end - ul_trace_begin);
+
+ ul_num_words = ul_num_bytes * ul_word_size;
+ status = dev_get_intf_fxns(dev_obj, &intf_fxns);
+
+ if (status)
+ goto func_end;
+
+ psz_buf = kzalloc(ul_num_bytes + 2, GFP_ATOMIC);
+ if (psz_buf != NULL) {
+ /* Read trace buffer data */
+ status = (*intf_fxns->pfn_brd_read)(pbridge_context,
+ (u8 *)psz_buf, (u32)ul_trace_begin,
+ ul_num_bytes, 0);
+
+ if (status)
+ goto func_end;
+
+ /* Pack and do newline conversion */
+ pr_debug("PrintDspTraceBuffer: "
+ "before pack and unpack.\n");
+ pr_debug("%s: DSP Trace Buffer Begin:\n"
+ "=======================\n%s\n",
+ __func__, psz_buf);
+
+ /* Read the value at the DSP address in trace_cur_pos. */
+ status = (*intf_fxns->pfn_brd_read)(pbridge_context,
+ (u8 *)&trace_cur_pos, (u32)trace_cur_pos,
+ 4, 0);
+ if (status)
+ goto func_end;
+ /* Pack and do newline conversion */
+ pr_info("DSP Trace Buffer Begin:\n"
+ "=======================\n%s\n",
+ psz_buf);
+
+
+ /* convert to offset */
+ trace_cur_pos = trace_cur_pos - ul_trace_begin;
+
+ if (ul_num_bytes) {
+ /*
+ * The buffer is not full, find the end of the
+ * data -- buf_end will be >= pszBuf after
+ * while.
+ */
+ buf_end = &psz_buf[ul_num_bytes+1];
+ /* DSP print position */
+ trace_end = &psz_buf[trace_cur_pos];
+
+ /*
+ * Search buffer for a new_line and replace it
+ * with '\0', then print as string.
+ * Continue until end of buffer is reached.
+ */
+ str_beg = trace_end;
+ ul_num_bytes = buf_end - str_beg;
+
+ while (str_beg < buf_end) {
+ new_line = strnchr(str_beg, ul_num_bytes,
+ '\n');
+ if (new_line && new_line < buf_end) {
+ *new_line = 0;
+ pr_debug("%s\n", str_beg);
+ str_beg = ++new_line;
+ ul_num_bytes = buf_end - str_beg;
+ } else {
+ /*
+ * Assume buffer empty if it contains
+ * a zero
+ */
+ if (*str_beg != '\0') {
+ str_beg[ul_num_bytes] = 0;
+ pr_debug("%s\n", str_beg);
+ }
+ str_beg = buf_end;
+ ul_num_bytes = 0;
+ }
+ }
+ /*
+ * Search buffer for a nNewLine and replace it
+ * with '\0', then print as string.
+ * Continue until buffer is exhausted.
+ */
+ str_beg = psz_buf;
+ ul_num_bytes = trace_end - str_beg;
+
+ while (str_beg < trace_end) {
+ new_line = strnchr(str_beg, ul_num_bytes, '\n');
+ if (new_line != NULL && new_line < trace_end) {
+ *new_line = 0;
+ pr_debug("%s\n", str_beg);
+ str_beg = ++new_line;
+ ul_num_bytes = trace_end - str_beg;
+ } else {
+ /*
+ * Assume buffer empty if it contains
+ * a zero
+ */
+ if (*str_beg != '\0') {
+ str_beg[ul_num_bytes] = 0;
+ pr_debug("%s\n", str_beg);
+ }
+ str_beg = trace_end;
+ ul_num_bytes = 0;
+ }
+ }
+ }
+ pr_info("\n=======================\n"
+ "DSP Trace Buffer End:\n");
+ kfree(psz_buf);
+ } else {
+ status = -ENOMEM;
+ }
+func_end:
+ if (status)
+ dev_dbg(bridge, "%s Failed, status 0x%x\n", __func__, status);
+ return status;
+}
+
+/**
+ * dump_dsp_stack() - This function dumps the data on the DSP stack.
+ * @bridge_context: Bridge driver's device context pointer.
+ *
+ */
+int dump_dsp_stack(struct bridge_dev_context *bridge_context)
+{
+ int status = 0;
+ struct cod_manager *code_mgr;
+ struct node_mgr *node_mgr;
+ u32 trace_begin;
+ char name[256];
+ struct {
+ u32 head[2];
+ u32 size;
+ } mmu_fault_dbg_info;
+ u32 *buffer;
+ u32 *buffer_beg;
+ u32 *buffer_end;
+ u32 exc_type;
+ u32 dyn_ext_base;
+ u32 i;
+ u32 offset_output;
+ u32 total_size;
+ u32 poll_cnt;
+ const char *dsp_regs[] = {"EFR", "IERR", "ITSR", "NTSR",
+ "IRP", "NRP", "AMR", "SSR",
+ "ILC", "RILC", "IER", "CSR"};
+ const char *exec_ctxt[] = {"Task", "SWI", "HWI", "Unknown"};
+ struct bridge_drv_interface *intf_fxns;
+ struct dev_object *dev_object = bridge_context->hdev_obj;
+
+ status = dev_get_cod_mgr(dev_object, &code_mgr);
+ if (!code_mgr) {
+ pr_debug("%s: Failed on dev_get_cod_mgr.\n", __func__);
+ status = -EFAULT;
+ }
+
+ if (!status) {
+ status = dev_get_node_manager(dev_object, &node_mgr);
+ if (!node_mgr) {
+ pr_debug("%s: Failed on dev_get_node_manager.\n",
+ __func__);
+ status = -EFAULT;
+ }
+ }
+
+ if (!status) {
+ /* Look for SYS_PUTCBEG/SYS_PUTCEND: */
+ status =
+ cod_get_sym_value(code_mgr, COD_TRACEBEG, &trace_begin);
+ pr_debug("%s: trace_begin Value 0x%x\n",
+ __func__, trace_begin);
+ if (status)
+ pr_debug("%s: Failed on cod_get_sym_value.\n",
+ __func__);
+ }
+ if (!status)
+ status = dev_get_intf_fxns(dev_object, &intf_fxns);
+ /*
+ * Check for the "magic number" in the trace buffer. If it has
+ * yet to appear then poll the trace buffer to wait for it. Its
+ * appearance signals that the DSP has finished dumping its state.
+ */
+ mmu_fault_dbg_info.head[0] = 0;
+ mmu_fault_dbg_info.head[1] = 0;
+ if (!status) {
+ poll_cnt = 0;
+ while ((mmu_fault_dbg_info.head[0] != MMU_FAULT_HEAD1 ||
+ mmu_fault_dbg_info.head[1] != MMU_FAULT_HEAD2) &&
+ poll_cnt < POLL_MAX) {
+
+ /* Read DSP dump size from the DSP trace buffer... */
+ status = (*intf_fxns->pfn_brd_read)(bridge_context,
+ (u8 *)&mmu_fault_dbg_info, (u32)trace_begin,
+ sizeof(mmu_fault_dbg_info), 0);
+
+ if (status)
+ break;
+
+ poll_cnt++;
+ }
+
+ if (mmu_fault_dbg_info.head[0] != MMU_FAULT_HEAD1 &&
+ mmu_fault_dbg_info.head[1] != MMU_FAULT_HEAD2) {
+ status = -ETIME;
+ pr_err("%s:No DSP MMU-Fault information available.\n",
+ __func__);
+ }
+ }
+
+ if (!status) {
+ total_size = mmu_fault_dbg_info.size;
+ /* Limit the size in case DSP went crazy */
+ if (total_size > MAX_MMU_DBGBUFF)
+ total_size = MAX_MMU_DBGBUFF;
+
+ buffer = kzalloc(total_size, GFP_ATOMIC);
+ if (!buffer) {
+ status = -ENOMEM;
+ pr_debug("%s: Failed to "
+ "allocate stack dump buffer.\n", __func__);
+ goto func_end;
+ }
+
+ buffer_beg = buffer;
+ buffer_end = buffer + total_size / 4;
+
+ /* Read bytes from the DSP trace buffer... */
+ status = (*intf_fxns->pfn_brd_read)(bridge_context,
+ (u8 *)buffer, (u32)trace_begin,
+ total_size, 0);
+ if (status) {
+ pr_debug("%s: Failed to Read Trace Buffer.\n",
+ __func__);
+ goto func_end;
+ }
+
+ pr_err("\nAproximate Crash Position:\n"
+ "--------------------------\n");
+
+ exc_type = buffer[3];
+ if (!exc_type)
+ i = buffer[79]; /* IRP */
+ else
+ i = buffer[80]; /* NRP */
+
+ status =
+ cod_get_sym_value(code_mgr, DYNEXTBASE, &dyn_ext_base);
+ if (status) {
+ status = -EFAULT;
+ goto func_end;
+ }
+
+ if ((i > dyn_ext_base) && (node_find_addr(node_mgr, i,
+ 0x1000, &offset_output, name) == 0))
+ pr_err("0x%-8x [\"%s\" + 0x%x]\n", i, name,
+ i - offset_output);
+ else
+ pr_err("0x%-8x [Unable to match to a symbol.]\n", i);
+
+ buffer += 4;
+
+ pr_err("\nExecution Info:\n"
+ "---------------\n");
+
+ if (*buffer < ARRAY_SIZE(exec_ctxt)) {
+ pr_err("Execution context \t%s\n",
+ exec_ctxt[*buffer++]);
+ } else {
+ pr_err("Execution context corrupt\n");
+ kfree(buffer_beg);
+ return -EFAULT;
+ }
+ pr_err("Task Handle\t\t0x%x\n", *buffer++);
+ pr_err("Stack Pointer\t\t0x%x\n", *buffer++);
+ pr_err("Stack Top\t\t0x%x\n", *buffer++);
+ pr_err("Stack Bottom\t\t0x%x\n", *buffer++);
+ pr_err("Stack Size\t\t0x%x\n", *buffer++);
+ pr_err("Stack Size In Use\t0x%x\n", *buffer++);
+
+ pr_err("\nCPU Registers\n"
+ "---------------\n");
+
+ for (i = 0; i < 32; i++) {
+ if (i == 4 || i == 6 || i == 8)
+ pr_err("A%d 0x%-8x [Function Argument %d]\n",
+ i, *buffer++, i-3);
+ else if (i == 15)
+ pr_err("A15 0x%-8x [Frame Pointer]\n",
+ *buffer++);
+ else
+ pr_err("A%d 0x%x\n", i, *buffer++);
+ }
+
+ pr_err("\nB0 0x%x\n", *buffer++);
+ pr_err("B1 0x%x\n", *buffer++);
+ pr_err("B2 0x%x\n", *buffer++);
+
+ if ((*buffer > dyn_ext_base) && (node_find_addr(node_mgr,
+ *buffer, 0x1000, &offset_output, name) == 0))
+
+ pr_err("B3 0x%-8x [Function Return Pointer:"
+ " \"%s\" + 0x%x]\n", *buffer, name,
+ *buffer - offset_output);
+ else
+ pr_err("B3 0x%-8x [Function Return Pointer:"
+ "Unable to match to a symbol.]\n", *buffer);
+
+ buffer++;
+
+ for (i = 4; i < 32; i++) {
+ if (i == 4 || i == 6 || i == 8)
+ pr_err("B%d 0x%-8x [Function Argument %d]\n",
+ i, *buffer++, i-2);
+ else if (i == 14)
+ pr_err("B14 0x%-8x [Data Page Pointer]\n",
+ *buffer++);
+ else
+ pr_err("B%d 0x%x\n", i, *buffer++);
+ }
+
+ pr_err("\n");
+
+ for (i = 0; i < ARRAY_SIZE(dsp_regs); i++)
+ pr_err("%s 0x%x\n", dsp_regs[i], *buffer++);
+
+ pr_err("\nStack:\n"
+ "------\n");
+
+ for (i = 0; buffer < buffer_end; i++, buffer++) {
+ if ((*buffer > dyn_ext_base) && (
+ node_find_addr(node_mgr, *buffer , 0x600,
+ &offset_output, name) == 0))
+ pr_err("[%d] 0x%-8x [\"%s\" + 0x%x]\n",
+ i, *buffer, name,
+ *buffer - offset_output);
+ else
+ pr_err("[%d] 0x%x\n", i, *buffer);
+ }
+ kfree(buffer_beg);
+ }
+func_end:
+ return status;
+}
+
+/**
+ * dump_dl_modules() - This functions dumps the _DLModules loaded in DSP side
+ * @bridge_context: Bridge driver's device context pointer.
+ *
+ */
+void dump_dl_modules(struct bridge_dev_context *bridge_context)
+{
+ struct cod_manager *code_mgr;
+ struct bridge_drv_interface *intf_fxns;
+ struct bridge_dev_context *bridge_ctxt = bridge_context;
+ struct dev_object *dev_object = bridge_ctxt->hdev_obj;
+ struct modules_header modules_hdr;
+ struct dll_module *module_struct = NULL;
+ u32 module_dsp_addr;
+ u32 module_size;
+ u32 module_struct_size = 0;
+ u32 sect_ndx;
+ char *sect_str ;
+ int status = 0;
+
+ status = dev_get_intf_fxns(dev_object, &intf_fxns);
+ if (status) {
+ pr_debug("%s: Failed on dev_get_intf_fxns.\n", __func__);
+ goto func_end;
+ }
+
+ status = dev_get_cod_mgr(dev_object, &code_mgr);
+ if (!code_mgr) {
+ pr_debug("%s: Failed on dev_get_cod_mgr.\n", __func__);
+ status = -EFAULT;
+ goto func_end;
+ }
+
+ /* Lookup the address of the modules_header structure */
+ status = cod_get_sym_value(code_mgr, "_DLModules", &module_dsp_addr);
+ if (status) {
+ pr_debug("%s: Failed on cod_get_sym_value for _DLModules.\n",
+ __func__);
+ goto func_end;
+ }
+
+ pr_debug("%s: _DLModules at 0x%x\n", __func__, module_dsp_addr);
+
+ /* Copy the modules_header structure from DSP memory. */
+ status = (*intf_fxns->pfn_brd_read)(bridge_context, (u8 *) &modules_hdr,
+ (u32) module_dsp_addr, sizeof(modules_hdr), 0);
+
+ if (status) {
+ pr_debug("%s: Failed failed to read modules header.\n",
+ __func__);
+ goto func_end;
+ }
+
+ module_dsp_addr = modules_hdr.first_module;
+ module_size = modules_hdr.first_module_size;
+
+ pr_debug("%s: dll_module_header 0x%x %d\n", __func__, module_dsp_addr,
+ module_size);
+
+ pr_err("\nDynamically Loaded Modules:\n"
+ "---------------------------\n");
+
+ /* For each dll_module structure in the list... */
+ while (module_size) {
+ /*
+ * Allocate/re-allocate memory to hold the dll_module
+ * structure. The memory is re-allocated only if the existing
+ * allocation is too small.
+ */
+ if (module_size > module_struct_size) {
+ kfree(module_struct);
+ module_struct = kzalloc(module_size+128, GFP_ATOMIC);
+ module_struct_size = module_size+128;
+ pr_debug("%s: allocated module struct %p %d\n",
+ __func__, module_struct, module_struct_size);
+ if (!module_struct)
+ goto func_end;
+ }
+ /* Copy the dll_module structure from DSP memory */
+ status = (*intf_fxns->pfn_brd_read)(bridge_context,
+ (u8 *)module_struct, module_dsp_addr, module_size, 0);
+
+ if (status) {
+ pr_debug(
+ "%s: Failed to read dll_module stuct for 0x%x.\n",
+ __func__, module_dsp_addr);
+ break;
+ }
+
+ /* Update info regarding the _next_ module in the list. */
+ module_dsp_addr = module_struct->next_module;
+ module_size = module_struct->next_module_size;
+
+ pr_debug("%s: next module 0x%x %d, this module num sects %d\n",
+ __func__, module_dsp_addr, module_size,
+ module_struct->num_sects);
+
+ /*
+ * The section name strings start immedialty following
+ * the array of dll_sect structures.
+ */
+ sect_str = (char *) &module_struct->
+ sects[module_struct->num_sects];
+ pr_err("%s\n", sect_str);
+
+ /*
+ * Advance to the first section name string.
+ * Each string follows the one before.
+ */
+ sect_str += strlen(sect_str) + 1;
+
+ /* Access each dll_sect structure and its name string. */
+ for (sect_ndx = 0;
+ sect_ndx < module_struct->num_sects; sect_ndx++) {
+ pr_err(" Section: 0x%x ",
+ module_struct->sects[sect_ndx].sect_load_adr);
+
+ if (((u32) sect_str - (u32) module_struct) <
+ module_struct_size) {
+ pr_err("%s\n", sect_str);
+ /* Each string follows the one before. */
+ sect_str += strlen(sect_str)+1;
+ } else {
+ pr_err("<string error>\n");
+ pr_debug("%s: section name sting address "
+ "is invalid %p\n", __func__, sect_str);
+ }
+ }
+ }
+func_end:
+ kfree(module_struct);
+}
+#endif
diff --git a/drivers/staging/tidspbridge/core/msg_sm.c b/drivers/staging/tidspbridge/core/msg_sm.c
new file mode 100644
index 00000000000..87712e24dfb
--- /dev/null
+++ b/drivers/staging/tidspbridge/core/msg_sm.c
@@ -0,0 +1,673 @@
+/*
+ * msg_sm.c
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * Implements upper edge functions for Bridge message module.
+ *
+ * Copyright (C) 2005-2006 Texas Instruments, Inc.
+ *
+ * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+#include <linux/types.h>
+
+/* ----------------------------------- DSP/BIOS Bridge */
+#include <dspbridge/dbdefs.h>
+
+/* ----------------------------------- Trace & Debug */
+#include <dspbridge/dbc.h>
+
+/* ----------------------------------- OS Adaptation Layer */
+#include <dspbridge/list.h>
+#include <dspbridge/sync.h>
+
+/* ----------------------------------- Platform Manager */
+#include <dspbridge/dev.h>
+
+/* ----------------------------------- Others */
+#include <dspbridge/io_sm.h>
+
+/* ----------------------------------- This */
+#include <_msg_sm.h>
+#include <dspbridge/dspmsg.h>
+
+/* ----------------------------------- Function Prototypes */
+static int add_new_msg(struct lst_list *msg_list);
+static void delete_msg_mgr(struct msg_mgr *hmsg_mgr);
+static void delete_msg_queue(struct msg_queue *msg_queue_obj, u32 num_to_dsp);
+static void free_msg_list(struct lst_list *msg_list);
+
+/*
+ * ======== bridge_msg_create ========
+ * Create an object to manage message queues. Only one of these objects
+ * can exist per device object.
+ */
+int bridge_msg_create(struct msg_mgr **msg_man,
+ struct dev_object *hdev_obj,
+ msg_onexit msg_callback)
+{
+ struct msg_mgr *msg_mgr_obj;
+ struct io_mgr *hio_mgr;
+ int status = 0;
+
+ if (!msg_man || !msg_callback || !hdev_obj) {
+ status = -EFAULT;
+ goto func_end;
+ }
+ dev_get_io_mgr(hdev_obj, &hio_mgr);
+ if (!hio_mgr) {
+ status = -EFAULT;
+ goto func_end;
+ }
+ *msg_man = NULL;
+ /* Allocate msg_ctrl manager object */
+ msg_mgr_obj = kzalloc(sizeof(struct msg_mgr), GFP_KERNEL);
+
+ if (msg_mgr_obj) {
+ msg_mgr_obj->on_exit = msg_callback;
+ msg_mgr_obj->hio_mgr = hio_mgr;
+ /* List of MSG_QUEUEs */
+ msg_mgr_obj->queue_list = kzalloc(sizeof(struct lst_list),
+ GFP_KERNEL);
+ /* Queues of message frames for messages to the DSP. Message
+ * frames will only be added to the free queue when a
+ * msg_queue object is created. */
+ msg_mgr_obj->msg_free_list = kzalloc(sizeof(struct lst_list),
+ GFP_KERNEL);
+ msg_mgr_obj->msg_used_list = kzalloc(sizeof(struct lst_list),
+ GFP_KERNEL);
+ if (msg_mgr_obj->queue_list == NULL ||
+ msg_mgr_obj->msg_free_list == NULL ||
+ msg_mgr_obj->msg_used_list == NULL) {
+ status = -ENOMEM;
+ } else {
+ INIT_LIST_HEAD(&msg_mgr_obj->queue_list->head);
+ INIT_LIST_HEAD(&msg_mgr_obj->msg_free_list->head);
+ INIT_LIST_HEAD(&msg_mgr_obj->msg_used_list->head);
+ spin_lock_init(&msg_mgr_obj->msg_mgr_lock);
+ }
+
+ /* Create an event to be used by bridge_msg_put() in waiting
+ * for an available free frame from the message manager. */
+ msg_mgr_obj->sync_event =
+ kzalloc(sizeof(struct sync_object), GFP_KERNEL);
+ if (!msg_mgr_obj->sync_event)
+ status = -ENOMEM;
+ else
+ sync_init_event(msg_mgr_obj->sync_event);
+
+ if (!status)
+ *msg_man = msg_mgr_obj;
+ else
+ delete_msg_mgr(msg_mgr_obj);
+
+ } else {
+ status = -ENOMEM;
+ }
+func_end:
+ return status;
+}
+
+/*
+ * ======== bridge_msg_create_queue ========
+ * Create a msg_queue for sending/receiving messages to/from a node
+ * on the DSP.
+ */
+int bridge_msg_create_queue(struct msg_mgr *hmsg_mgr,
+ struct msg_queue **msgq,
+ u32 msgq_id, u32 max_msgs, void *arg)
+{
+ u32 i;
+ u32 num_allocated = 0;
+ struct msg_queue *msg_q;
+ int status = 0;
+
+ if (!hmsg_mgr || msgq == NULL || !hmsg_mgr->msg_free_list) {
+ status = -EFAULT;
+ goto func_end;
+ }
+
+ *msgq = NULL;
+ /* Allocate msg_queue object */
+ msg_q = kzalloc(sizeof(struct msg_queue), GFP_KERNEL);
+ if (!msg_q) {
+ status = -ENOMEM;
+ goto func_end;
+ }
+ lst_init_elem((struct list_head *)msg_q);
+ msg_q->max_msgs = max_msgs;
+ msg_q->hmsg_mgr = hmsg_mgr;
+ msg_q->arg = arg; /* Node handle */
+ msg_q->msgq_id = msgq_id; /* Node env (not valid yet) */
+ /* Queues of Message frames for messages from the DSP */
+ msg_q->msg_free_list = kzalloc(sizeof(struct lst_list), GFP_KERNEL);
+ msg_q->msg_used_list = kzalloc(sizeof(struct lst_list), GFP_KERNEL);
+ if (msg_q->msg_free_list == NULL || msg_q->msg_used_list == NULL)
+ status = -ENOMEM;
+ else {
+ INIT_LIST_HEAD(&msg_q->msg_free_list->head);
+ INIT_LIST_HEAD(&msg_q->msg_used_list->head);
+ }
+
+ /* Create event that will be signalled when a message from
+ * the DSP is available. */
+ if (!status) {
+ msg_q->sync_event = kzalloc(sizeof(struct sync_object),
+ GFP_KERNEL);
+ if (msg_q->sync_event)
+ sync_init_event(msg_q->sync_event);
+ else
+ status = -ENOMEM;
+ }
+
+ /* Create a notification list for message ready notification. */
+ if (!status) {
+ msg_q->ntfy_obj = kmalloc(sizeof(struct ntfy_object),
+ GFP_KERNEL);
+ if (msg_q->ntfy_obj)
+ ntfy_init(msg_q->ntfy_obj);
+ else
+ status = -ENOMEM;
+ }
+
+ /* Create events that will be used to synchronize cleanup
+ * when the object is deleted. sync_done will be set to
+ * unblock threads in MSG_Put() or MSG_Get(). sync_done_ack
+ * will be set by the unblocked thread to signal that it
+ * is unblocked and will no longer reference the object. */
+ if (!status) {
+ msg_q->sync_done = kzalloc(sizeof(struct sync_object),
+ GFP_KERNEL);
+ if (msg_q->sync_done)
+ sync_init_event(msg_q->sync_done);
+ else
+ status = -ENOMEM;
+ }
+
+ if (!status) {
+ msg_q->sync_done_ack = kzalloc(sizeof(struct sync_object),
+ GFP_KERNEL);
+ if (msg_q->sync_done_ack)
+ sync_init_event(msg_q->sync_done_ack);
+ else
+ status = -ENOMEM;
+ }
+
+ if (!status) {
+ /* Enter critical section */
+ spin_lock_bh(&hmsg_mgr->msg_mgr_lock);
+ /* Initialize message frames and put in appropriate queues */
+ for (i = 0; i < max_msgs && !status; i++) {
+ status = add_new_msg(hmsg_mgr->msg_free_list);
+ if (!status) {
+ num_allocated++;
+ status = add_new_msg(msg_q->msg_free_list);
+ }
+ }
+ if (status) {
+ /* Stay inside CS to prevent others from taking any
+ * of the newly allocated message frames. */
+ delete_msg_queue(msg_q, num_allocated);
+ } else {
+ lst_put_tail(hmsg_mgr->queue_list,
+ (struct list_head *)msg_q);
+ *msgq = msg_q;
+ /* Signal that free frames are now available */
+ if (!LST_IS_EMPTY(hmsg_mgr->msg_free_list))
+ sync_set_event(hmsg_mgr->sync_event);
+
+ }
+ /* Exit critical section */
+ spin_unlock_bh(&hmsg_mgr->msg_mgr_lock);
+ } else {
+ delete_msg_queue(msg_q, 0);
+ }
+func_end:
+ return status;
+}
+
+/*
+ * ======== bridge_msg_delete ========
+ * Delete a msg_ctrl manager allocated in bridge_msg_create().
+ */
+void bridge_msg_delete(struct msg_mgr *hmsg_mgr)
+{
+ if (hmsg_mgr)
+ delete_msg_mgr(hmsg_mgr);
+}
+
+/*
+ * ======== bridge_msg_delete_queue ========
+ * Delete a msg_ctrl queue allocated in bridge_msg_create_queue.
+ */
+void bridge_msg_delete_queue(struct msg_queue *msg_queue_obj)
+{
+ struct msg_mgr *hmsg_mgr;
+ u32 io_msg_pend;
+
+ if (!msg_queue_obj || !msg_queue_obj->hmsg_mgr)
+ goto func_end;
+
+ hmsg_mgr = msg_queue_obj->hmsg_mgr;
+ msg_queue_obj->done = true;
+ /* Unblock all threads blocked in MSG_Get() or MSG_Put(). */
+ io_msg_pend = msg_queue_obj->io_msg_pend;
+ while (io_msg_pend) {
+ /* Unblock thread */
+ sync_set_event(msg_queue_obj->sync_done);
+ /* Wait for acknowledgement */
+ sync_wait_on_event(msg_queue_obj->sync_done_ack, SYNC_INFINITE);
+ io_msg_pend = msg_queue_obj->io_msg_pend;
+ }
+ /* Remove message queue from hmsg_mgr->queue_list */
+ spin_lock_bh(&hmsg_mgr->msg_mgr_lock);
+ lst_remove_elem(hmsg_mgr->queue_list,
+ (struct list_head *)msg_queue_obj);
+ /* Free the message queue object */
+ delete_msg_queue(msg_queue_obj, msg_queue_obj->max_msgs);
+ if (!hmsg_mgr->msg_free_list)
+ goto func_cont;
+ if (LST_IS_EMPTY(hmsg_mgr->msg_free_list))
+ sync_reset_event(hmsg_mgr->sync_event);
+func_cont:
+ spin_unlock_bh(&hmsg_mgr->msg_mgr_lock);
+func_end:
+ return;
+}
+
+/*
+ * ======== bridge_msg_get ========
+ * Get a message from a msg_ctrl queue.
+ */
+int bridge_msg_get(struct msg_queue *msg_queue_obj,
+ struct dsp_msg *pmsg, u32 utimeout)
+{
+ struct msg_frame *msg_frame_obj;
+ struct msg_mgr *hmsg_mgr;
+ bool got_msg = false;
+ struct sync_object *syncs[2];
+ u32 index;
+ int status = 0;
+
+ if (!msg_queue_obj || pmsg == NULL) {
+ status = -ENOMEM;
+ goto func_end;
+ }
+
+ hmsg_mgr = msg_queue_obj->hmsg_mgr;
+ if (!msg_queue_obj->msg_used_list) {
+ status = -EFAULT;
+ goto func_end;
+ }
+
+ /* Enter critical section */
+ spin_lock_bh(&hmsg_mgr->msg_mgr_lock);
+ /* If a message is already there, get it */
+ if (!LST_IS_EMPTY(msg_queue_obj->msg_used_list)) {
+ msg_frame_obj = (struct msg_frame *)
+ lst_get_head(msg_queue_obj->msg_used_list);
+ if (msg_frame_obj != NULL) {
+ *pmsg = msg_frame_obj->msg_data.msg;
+ lst_put_tail(msg_queue_obj->msg_free_list,
+ (struct list_head *)msg_frame_obj);
+ if (LST_IS_EMPTY(msg_queue_obj->msg_used_list))
+ sync_reset_event(msg_queue_obj->sync_event);
+
+ got_msg = true;
+ }
+ } else {
+ if (msg_queue_obj->done)
+ status = -EPERM;
+ else
+ msg_queue_obj->io_msg_pend++;
+
+ }
+ /* Exit critical section */
+ spin_unlock_bh(&hmsg_mgr->msg_mgr_lock);
+ if (!status && !got_msg) {
+ /* Wait til message is available, timeout, or done. We don't
+ * have to schedule the DPC, since the DSP will send messages
+ * when they are available. */
+ syncs[0] = msg_queue_obj->sync_event;
+ syncs[1] = msg_queue_obj->sync_done;
+ status = sync_wait_on_multiple_events(syncs, 2, utimeout,
+ &index);
+ /* Enter critical section */
+ spin_lock_bh(&hmsg_mgr->msg_mgr_lock);
+ if (msg_queue_obj->done) {
+ msg_queue_obj->io_msg_pend--;
+ /* Exit critical section */
+ spin_unlock_bh(&hmsg_mgr->msg_mgr_lock);
+ /* Signal that we're not going to access msg_queue_obj
+ * anymore, so it can be deleted. */
+ (void)sync_set_event(msg_queue_obj->sync_done_ack);
+ status = -EPERM;
+ } else {
+ if (!status) {
+ DBC_ASSERT(!LST_IS_EMPTY
+ (msg_queue_obj->msg_used_list));
+ /* Get msg from used list */
+ msg_frame_obj = (struct msg_frame *)
+ lst_get_head(msg_queue_obj->msg_used_list);
+ /* Copy message into pmsg and put frame on the
+ * free list */
+ if (msg_frame_obj != NULL) {
+ *pmsg = msg_frame_obj->msg_data.msg;
+ lst_put_tail
+ (msg_queue_obj->msg_free_list,
+ (struct list_head *)
+ msg_frame_obj);
+ }
+ }
+ msg_queue_obj->io_msg_pend--;
+ /* Reset the event if there are still queued messages */
+ if (!LST_IS_EMPTY(msg_queue_obj->msg_used_list))
+ sync_set_event(msg_queue_obj->sync_event);
+
+ /* Exit critical section */
+ spin_unlock_bh(&hmsg_mgr->msg_mgr_lock);
+ }
+ }
+func_end:
+ return status;
+}
+
+/*
+ * ======== bridge_msg_put ========
+ * Put a message onto a msg_ctrl queue.
+ */
+int bridge_msg_put(struct msg_queue *msg_queue_obj,
+ const struct dsp_msg *pmsg, u32 utimeout)
+{
+ struct msg_frame *msg_frame_obj;
+ struct msg_mgr *hmsg_mgr;
+ bool put_msg = false;
+ struct sync_object *syncs[2];
+ u32 index;
+ int status = 0;
+
+ if (!msg_queue_obj || !pmsg || !msg_queue_obj->hmsg_mgr) {
+ status = -ENOMEM;
+ goto func_end;
+ }
+ hmsg_mgr = msg_queue_obj->hmsg_mgr;
+ if (!hmsg_mgr->msg_free_list) {
+ status = -EFAULT;
+ goto func_end;
+ }
+
+ spin_lock_bh(&hmsg_mgr->msg_mgr_lock);
+
+ /* If a message frame is available, use it */
+ if (!LST_IS_EMPTY(hmsg_mgr->msg_free_list)) {
+ msg_frame_obj =
+ (struct msg_frame *)lst_get_head(hmsg_mgr->msg_free_list);
+ if (msg_frame_obj != NULL) {
+ msg_frame_obj->msg_data.msg = *pmsg;
+ msg_frame_obj->msg_data.msgq_id =
+ msg_queue_obj->msgq_id;
+ lst_put_tail(hmsg_mgr->msg_used_list,
+ (struct list_head *)msg_frame_obj);
+ hmsg_mgr->msgs_pending++;
+ put_msg = true;
+ }
+ if (LST_IS_EMPTY(hmsg_mgr->msg_free_list))
+ sync_reset_event(hmsg_mgr->sync_event);
+
+ /* Release critical section before scheduling DPC */
+ spin_unlock_bh(&hmsg_mgr->msg_mgr_lock);
+ /* Schedule a DPC, to do the actual data transfer: */
+ iosm_schedule(hmsg_mgr->hio_mgr);
+ } else {
+ if (msg_queue_obj->done)
+ status = -EPERM;
+ else
+ msg_queue_obj->io_msg_pend++;
+
+ spin_unlock_bh(&hmsg_mgr->msg_mgr_lock);
+ }
+ if (!status && !put_msg) {
+ /* Wait til a free message frame is available, timeout,
+ * or done */
+ syncs[0] = hmsg_mgr->sync_event;
+ syncs[1] = msg_queue_obj->sync_done;
+ status = sync_wait_on_multiple_events(syncs, 2, utimeout,
+ &index);
+ if (status)
+ goto func_end;
+ /* Enter critical section */
+ spin_lock_bh(&hmsg_mgr->msg_mgr_lock);
+ if (msg_queue_obj->done) {
+ msg_queue_obj->io_msg_pend--;
+ /* Exit critical section */
+ spin_unlock_bh(&hmsg_mgr->msg_mgr_lock);
+ /* Signal that we're not going to access msg_queue_obj
+ * anymore, so it can be deleted. */
+ (void)sync_set_event(msg_queue_obj->sync_done_ack);
+ status = -EPERM;
+ } else {
+ if (LST_IS_EMPTY(hmsg_mgr->msg_free_list)) {
+ status = -EFAULT;
+ goto func_cont;
+ }
+ /* Get msg from free list */
+ msg_frame_obj = (struct msg_frame *)
+ lst_get_head(hmsg_mgr->msg_free_list);
+ /*
+ * Copy message into pmsg and put frame on the
+ * used list.
+ */
+ if (msg_frame_obj) {
+ msg_frame_obj->msg_data.msg = *pmsg;
+ msg_frame_obj->msg_data.msgq_id =
+ msg_queue_obj->msgq_id;
+ lst_put_tail(hmsg_mgr->msg_used_list,
+ (struct list_head *)msg_frame_obj);
+ hmsg_mgr->msgs_pending++;
+ /*
+ * Schedule a DPC, to do the actual
+ * data transfer.
+ */
+ iosm_schedule(hmsg_mgr->hio_mgr);
+ }
+
+ msg_queue_obj->io_msg_pend--;
+ /* Reset event if there are still frames available */
+ if (!LST_IS_EMPTY(hmsg_mgr->msg_free_list))
+ sync_set_event(hmsg_mgr->sync_event);
+func_cont:
+ /* Exit critical section */
+ spin_unlock_bh(&hmsg_mgr->msg_mgr_lock);
+ }
+ }
+func_end:
+ return status;
+}
+
+/*
+ * ======== bridge_msg_register_notify ========
+ */
+int bridge_msg_register_notify(struct msg_queue *msg_queue_obj,
+ u32 event_mask, u32 notify_type,
+ struct dsp_notification *hnotification)
+{
+ int status = 0;
+
+ if (!msg_queue_obj || !hnotification) {
+ status = -ENOMEM;
+ goto func_end;
+ }
+
+ if (!(event_mask == DSP_NODEMESSAGEREADY || event_mask == 0)) {
+ status = -EPERM;
+ goto func_end;
+ }
+
+ if (notify_type != DSP_SIGNALEVENT) {
+ status = -EBADR;
+ goto func_end;
+ }
+
+ if (event_mask)
+ status = ntfy_register(msg_queue_obj->ntfy_obj, hnotification,
+ event_mask, notify_type);
+ else
+ status = ntfy_unregister(msg_queue_obj->ntfy_obj,
+ hnotification);
+
+ if (status == -EINVAL) {
+ /* Not registered. Ok, since we couldn't have known. Node
+ * notifications are split between node state change handled
+ * by NODE, and message ready handled by msg_ctrl. */
+ status = 0;
+ }
+func_end:
+ return status;
+}
+
+/*
+ * ======== bridge_msg_set_queue_id ========
+ */
+void bridge_msg_set_queue_id(struct msg_queue *msg_queue_obj, u32 msgq_id)
+{
+ /*
+ * A message queue must be created when a node is allocated,
+ * so that node_register_notify() can be called before the node
+ * is created. Since we don't know the node environment until the
+ * node is created, we need this function to set msg_queue_obj->msgq_id
+ * to the node environment, after the node is created.
+ */
+ if (msg_queue_obj)
+ msg_queue_obj->msgq_id = msgq_id;
+}
+
+/*
+ * ======== add_new_msg ========
+ * Must be called in message manager critical section.
+ */
+static int add_new_msg(struct lst_list *msg_list)
+{
+ struct msg_frame *pmsg;
+ int status = 0;
+
+ pmsg = kzalloc(sizeof(struct msg_frame), GFP_ATOMIC);
+ if (pmsg != NULL) {
+ lst_init_elem((struct list_head *)pmsg);
+ lst_put_tail(msg_list, (struct list_head *)pmsg);
+ } else {
+ status = -ENOMEM;
+ }
+
+ return status;
+}
+
+/*
+ * ======== delete_msg_mgr ========
+ */
+static void delete_msg_mgr(struct msg_mgr *hmsg_mgr)
+{
+ if (!hmsg_mgr)
+ goto func_end;
+
+ if (hmsg_mgr->queue_list) {
+ if (LST_IS_EMPTY(hmsg_mgr->queue_list)) {
+ kfree(hmsg_mgr->queue_list);
+ hmsg_mgr->queue_list = NULL;
+ }
+ }
+
+ if (hmsg_mgr->msg_free_list) {
+ free_msg_list(hmsg_mgr->msg_free_list);
+ hmsg_mgr->msg_free_list = NULL;
+ }
+
+ if (hmsg_mgr->msg_used_list) {
+ free_msg_list(hmsg_mgr->msg_used_list);
+ hmsg_mgr->msg_used_list = NULL;
+ }
+
+ kfree(hmsg_mgr->sync_event);
+
+ kfree(hmsg_mgr);
+func_end:
+ return;
+}
+
+/*
+ * ======== delete_msg_queue ========
+ */
+static void delete_msg_queue(struct msg_queue *msg_queue_obj, u32 num_to_dsp)
+{
+ struct msg_mgr *hmsg_mgr;
+ struct msg_frame *pmsg;
+ u32 i;
+
+ if (!msg_queue_obj ||
+ !msg_queue_obj->hmsg_mgr || !msg_queue_obj->hmsg_mgr->msg_free_list)
+ goto func_end;
+
+ hmsg_mgr = msg_queue_obj->hmsg_mgr;
+
+ /* Pull off num_to_dsp message frames from Msg manager and free */
+ for (i = 0; i < num_to_dsp; i++) {
+
+ if (!LST_IS_EMPTY(hmsg_mgr->msg_free_list)) {
+ pmsg = (struct msg_frame *)
+ lst_get_head(hmsg_mgr->msg_free_list);
+ kfree(pmsg);
+ } else {
+ /* Cannot free all of the message frames */
+ break;
+ }
+ }
+
+ if (msg_queue_obj->msg_free_list) {
+ free_msg_list(msg_queue_obj->msg_free_list);
+ msg_queue_obj->msg_free_list = NULL;
+ }
+
+ if (msg_queue_obj->msg_used_list) {
+ free_msg_list(msg_queue_obj->msg_used_list);
+ msg_queue_obj->msg_used_list = NULL;
+ }
+
+ if (msg_queue_obj->ntfy_obj) {
+ ntfy_delete(msg_queue_obj->ntfy_obj);
+ kfree(msg_queue_obj->ntfy_obj);
+ }
+
+ kfree(msg_queue_obj->sync_event);
+ kfree(msg_queue_obj->sync_done);
+ kfree(msg_queue_obj->sync_done_ack);
+
+ kfree(msg_queue_obj);
+func_end:
+ return;
+
+}
+
+/*
+ * ======== free_msg_list ========
+ */
+static void free_msg_list(struct lst_list *msg_list)
+{
+ struct msg_frame *pmsg;
+
+ if (!msg_list)
+ goto func_end;
+
+ while ((pmsg = (struct msg_frame *)lst_get_head(msg_list)) != NULL)
+ kfree(pmsg);
+
+ DBC_ASSERT(LST_IS_EMPTY(msg_list));
+
+ kfree(msg_list);
+func_end:
+ return;
+}
diff --git a/drivers/staging/tidspbridge/core/tiomap3430.c b/drivers/staging/tidspbridge/core/tiomap3430.c
new file mode 100644
index 00000000000..f914829c70f
--- /dev/null
+++ b/drivers/staging/tidspbridge/core/tiomap3430.c
@@ -0,0 +1,1802 @@
+/*
+ * tiomap.c
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * Processor Manager Driver for TI OMAP3430 EVM.
+ *
+ * Copyright (C) 2005-2006 Texas Instruments, Inc.
+ *
+ * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include <linux/types.h>
+/* ----------------------------------- Host OS */
+#include <dspbridge/host_os.h>
+#include <linux/mm.h>
+#include <linux/mmzone.h>
+#include <plat/control.h>
+
+/* ----------------------------------- DSP/BIOS Bridge */
+#include <dspbridge/dbdefs.h>
+
+/* ----------------------------------- Trace & Debug */
+#include <dspbridge/dbc.h>
+
+/* ----------------------------------- OS Adaptation Layer */
+#include <dspbridge/cfg.h>
+#include <dspbridge/drv.h>
+#include <dspbridge/sync.h>
+
+/* ------------------------------------ Hardware Abstraction Layer */
+#include <hw_defs.h>
+#include <hw_mmu.h>
+
+/* ----------------------------------- Link Driver */
+#include <dspbridge/dspdefs.h>
+#include <dspbridge/dspchnl.h>
+#include <dspbridge/dspdeh.h>
+#include <dspbridge/dspio.h>
+#include <dspbridge/dspmsg.h>
+#include <dspbridge/pwr.h>
+#include <dspbridge/io_sm.h>
+
+/* ----------------------------------- Platform Manager */
+#include <dspbridge/dev.h>
+#include <dspbridge/dspapi.h>
+#include <dspbridge/dmm.h>
+#include <dspbridge/wdt.h>
+
+/* ----------------------------------- Local */
+#include "_tiomap.h"
+#include "_tiomap_pwr.h"
+#include "tiomap_io.h"
+
+/* Offset in shared mem to write to in order to synchronize start with DSP */
+#define SHMSYNCOFFSET 4 /* GPP byte offset */
+
+#define BUFFERSIZE 1024
+
+#define TIHELEN_ACKTIMEOUT 10000
+
+#define MMU_SECTION_ADDR_MASK 0xFFF00000
+#define MMU_SSECTION_ADDR_MASK 0xFF000000
+#define MMU_LARGE_PAGE_MASK 0xFFFF0000
+#define MMU_SMALL_PAGE_MASK 0xFFFFF000
+#define OMAP3_IVA2_BOOTADDR_MASK 0xFFFFFC00
+#define PAGES_II_LVL_TABLE 512
+#define PHYS_TO_PAGE(phys) pfn_to_page((phys) >> PAGE_SHIFT)
+
+/* Forward Declarations: */
+static int bridge_brd_monitor(struct bridge_dev_context *dev_ctxt);
+static int bridge_brd_read(struct bridge_dev_context *dev_ctxt,
+ u8 *host_buff,
+ u32 dsp_addr, u32 ul_num_bytes,
+ u32 mem_type);
+static int bridge_brd_start(struct bridge_dev_context *dev_ctxt,
+ u32 dsp_addr);
+static int bridge_brd_status(struct bridge_dev_context *dev_ctxt,
+ int *board_state);
+static int bridge_brd_stop(struct bridge_dev_context *dev_ctxt);
+static int bridge_brd_write(struct bridge_dev_context *dev_ctxt,
+ u8 *host_buff,
+ u32 dsp_addr, u32 ul_num_bytes,
+ u32 mem_type);
+static int bridge_brd_set_state(struct bridge_dev_context *dev_ctxt,
+ u32 brd_state);
+static int bridge_brd_mem_copy(struct bridge_dev_context *dev_ctxt,
+ u32 dsp_dest_addr, u32 dsp_src_addr,
+ u32 ul_num_bytes, u32 mem_type);
+static int bridge_brd_mem_write(struct bridge_dev_context *dev_ctxt,
+ u8 *host_buff, u32 dsp_addr,
+ u32 ul_num_bytes, u32 mem_type);
+static int bridge_brd_mem_map(struct bridge_dev_context *dev_ctxt,
+ u32 ul_mpu_addr, u32 virt_addr,
+ u32 ul_num_bytes, u32 ul_map_attr,
+ struct page **mapped_pages);
+static int bridge_brd_mem_un_map(struct bridge_dev_context *dev_ctxt,
+ u32 virt_addr, u32 ul_num_bytes);
+static int bridge_dev_create(struct bridge_dev_context
+ **dev_cntxt,
+ struct dev_object *hdev_obj,
+ struct cfg_hostres *config_param);
+static int bridge_dev_ctrl(struct bridge_dev_context *dev_context,
+ u32 dw_cmd, void *pargs);
+static int bridge_dev_destroy(struct bridge_dev_context *dev_ctxt);
+static u32 user_va2_pa(struct mm_struct *mm, u32 address);
+static int pte_update(struct bridge_dev_context *dev_ctxt, u32 pa,
+ u32 va, u32 size,
+ struct hw_mmu_map_attrs_t *map_attrs);
+static int pte_set(struct pg_table_attrs *pt, u32 pa, u32 va,
+ u32 size, struct hw_mmu_map_attrs_t *attrs);
+static int mem_map_vmalloc(struct bridge_dev_context *dev_context,
+ u32 ul_mpu_addr, u32 virt_addr,
+ u32 ul_num_bytes,
+ struct hw_mmu_map_attrs_t *hw_attrs);
+
+bool wait_for_start(struct bridge_dev_context *dev_context, u32 dw_sync_addr);
+
+/* ----------------------------------- Globals */
+
+/* Attributes of L2 page tables for DSP MMU */
+struct page_info {
+ u32 num_entries; /* Number of valid PTEs in the L2 PT */
+};
+
+/* Attributes used to manage the DSP MMU page tables */
+struct pg_table_attrs {
+ spinlock_t pg_lock; /* Critical section object handle */
+
+ u32 l1_base_pa; /* Physical address of the L1 PT */
+ u32 l1_base_va; /* Virtual address of the L1 PT */
+ u32 l1_size; /* Size of the L1 PT */
+ u32 l1_tbl_alloc_pa;
+ /* Physical address of Allocated mem for L1 table. May not be aligned */
+ u32 l1_tbl_alloc_va;
+ /* Virtual address of Allocated mem for L1 table. May not be aligned */
+ u32 l1_tbl_alloc_sz;
+ /* Size of consistent memory allocated for L1 table.
+ * May not be aligned */
+
+ u32 l2_base_pa; /* Physical address of the L2 PT */
+ u32 l2_base_va; /* Virtual address of the L2 PT */
+ u32 l2_size; /* Size of the L2 PT */
+ u32 l2_tbl_alloc_pa;
+ /* Physical address of Allocated mem for L2 table. May not be aligned */
+ u32 l2_tbl_alloc_va;
+ /* Virtual address of Allocated mem for L2 table. May not be aligned */
+ u32 l2_tbl_alloc_sz;
+ /* Size of consistent memory allocated for L2 table.
+ * May not be aligned */
+
+ u32 l2_num_pages; /* Number of allocated L2 PT */
+ /* Array [l2_num_pages] of L2 PT info structs */
+ struct page_info *pg_info;
+};
+
+/*
+ * This Bridge driver's function interface table.
+ */
+static struct bridge_drv_interface drv_interface_fxns = {
+ /* Bridge API ver. for which this bridge driver is built. */
+ BRD_API_MAJOR_VERSION,
+ BRD_API_MINOR_VERSION,
+ bridge_dev_create,
+ bridge_dev_destroy,
+ bridge_dev_ctrl,
+ bridge_brd_monitor,
+ bridge_brd_start,
+ bridge_brd_stop,
+ bridge_brd_status,
+ bridge_brd_read,
+ bridge_brd_write,
+ bridge_brd_set_state,
+ bridge_brd_mem_copy,
+ bridge_brd_mem_write,
+ bridge_brd_mem_map,
+ bridge_brd_mem_un_map,
+ /* The following CHNL functions are provided by chnl_io.lib: */
+ bridge_chnl_create,
+ bridge_chnl_destroy,
+ bridge_chnl_open,
+ bridge_chnl_close,
+ bridge_chnl_add_io_req,
+ bridge_chnl_get_ioc,
+ bridge_chnl_cancel_io,
+ bridge_chnl_flush_io,
+ bridge_chnl_get_info,
+ bridge_chnl_get_mgr_info,
+ bridge_chnl_idle,
+ bridge_chnl_register_notify,
+ /* The following IO functions are provided by chnl_io.lib: */
+ bridge_io_create,
+ bridge_io_destroy,
+ bridge_io_on_loaded,
+ bridge_io_get_proc_load,
+ /* The following msg_ctrl functions are provided by chnl_io.lib: */
+ bridge_msg_create,
+ bridge_msg_create_queue,
+ bridge_msg_delete,
+ bridge_msg_delete_queue,
+ bridge_msg_get,
+ bridge_msg_put,
+ bridge_msg_register_notify,
+ bridge_msg_set_queue_id,
+};
+
+static inline void flush_all(struct bridge_dev_context *dev_context)
+{
+ if (dev_context->dw_brd_state == BRD_DSP_HIBERNATION ||
+ dev_context->dw_brd_state == BRD_HIBERNATION)
+ wake_dsp(dev_context, NULL);
+
+ hw_mmu_tlb_flush_all(dev_context->dw_dsp_mmu_base);
+}
+
+static void bad_page_dump(u32 pa, struct page *pg)
+{
+ pr_emerg("DSPBRIDGE: MAP function: COUNT 0 FOR PA 0x%x\n", pa);
+ pr_emerg("Bad page state in process '%s'\n"
+ "page:%p flags:0x%0*lx mapping:%p mapcount:%d count:%d\n"
+ "Backtrace:\n",
+ current->comm, pg, (int)(2 * sizeof(unsigned long)),
+ (unsigned long)pg->flags, pg->mapping,
+ page_mapcount(pg), page_count(pg));
+ dump_stack();
+}
+
+/*
+ * ======== bridge_drv_entry ========
+ * purpose:
+ * Bridge Driver entry point.
+ */
+void bridge_drv_entry(struct bridge_drv_interface **drv_intf,
+ const char *driver_file_name)
+{
+
+ DBC_REQUIRE(driver_file_name != NULL);
+
+ io_sm_init(); /* Initialization of io_sm module */
+
+ if (strcmp(driver_file_name, "UMA") == 0)
+ *drv_intf = &drv_interface_fxns;
+ else
+ dev_dbg(bridge, "%s Unknown Bridge file name", __func__);
+
+}
+
+/*
+ * ======== bridge_brd_monitor ========
+ * purpose:
+ * This bridge_brd_monitor puts DSP into a Loadable state.
+ * i.e Application can load and start the device.
+ *
+ * Preconditions:
+ * Device in 'OFF' state.
+ */
+static int bridge_brd_monitor(struct bridge_dev_context *dev_ctxt)
+{
+ struct bridge_dev_context *dev_context = dev_ctxt;
+ u32 temp;
+ struct dspbridge_platform_data *pdata =
+ omap_dspbridge_dev->dev.platform_data;
+
+ temp = (*pdata->dsp_prm_read)(OMAP3430_IVA2_MOD, OMAP2_PM_PWSTST) &
+ OMAP_POWERSTATEST_MASK;
+ if (!(temp & 0x02)) {
+ /* IVA2 is not in ON state */
+ /* Read and set PM_PWSTCTRL_IVA2 to ON */
+ (*pdata->dsp_prm_rmw_bits)(OMAP_POWERSTATEST_MASK,
+ PWRDM_POWER_ON, OMAP3430_IVA2_MOD, OMAP2_PM_PWSTCTRL);
+ /* Set the SW supervised state transition */
+ (*pdata->dsp_cm_write)(OMAP34XX_CLKSTCTRL_FORCE_WAKEUP,
+ OMAP3430_IVA2_MOD, OMAP2_CM_CLKSTCTRL);
+
+ /* Wait until the state has moved to ON */
+ while ((*pdata->dsp_prm_read)(OMAP3430_IVA2_MOD, OMAP2_PM_PWSTST) &
+ OMAP_INTRANSITION_MASK)
+ ;
+ /* Disable Automatic transition */
+ (*pdata->dsp_cm_write)(OMAP34XX_CLKSTCTRL_DISABLE_AUTO,
+ OMAP3430_IVA2_MOD, OMAP2_CM_CLKSTCTRL);
+ }
+ (*pdata->dsp_prm_rmw_bits)(OMAP3430_RST2_IVA2_MASK, 0,
+ OMAP3430_IVA2_MOD, OMAP2_RM_RSTCTRL);
+ dsp_clk_enable(DSP_CLK_IVA2);
+
+ /* set the device state to IDLE */
+ dev_context->dw_brd_state = BRD_IDLE;
+
+ return 0;
+}
+
+/*
+ * ======== bridge_brd_read ========
+ * purpose:
+ * Reads buffers for DSP memory.
+ */
+static int bridge_brd_read(struct bridge_dev_context *dev_ctxt,
+ u8 *host_buff, u32 dsp_addr,
+ u32 ul_num_bytes, u32 mem_type)
+{
+ int status = 0;
+ struct bridge_dev_context *dev_context = dev_ctxt;
+ u32 offset;
+ u32 dsp_base_addr = dev_ctxt->dw_dsp_base_addr;
+
+ if (dsp_addr < dev_context->dw_dsp_start_add) {
+ status = -EPERM;
+ return status;
+ }
+ /* change here to account for the 3 bands of the DSP internal memory */
+ if ((dsp_addr - dev_context->dw_dsp_start_add) <
+ dev_context->dw_internal_size) {
+ offset = dsp_addr - dev_context->dw_dsp_start_add;
+ } else {
+ status = read_ext_dsp_data(dev_context, host_buff, dsp_addr,
+ ul_num_bytes, mem_type);
+ return status;
+ }
+ /* copy the data from DSP memory, */
+ memcpy(host_buff, (void *)(dsp_base_addr + offset), ul_num_bytes);
+ return status;
+}
+
+/*
+ * ======== bridge_brd_set_state ========
+ * purpose:
+ * This routine updates the Board status.
+ */
+static int bridge_brd_set_state(struct bridge_dev_context *dev_ctxt,
+ u32 brd_state)
+{
+ int status = 0;
+ struct bridge_dev_context *dev_context = dev_ctxt;
+
+ dev_context->dw_brd_state = brd_state;
+ return status;
+}
+
+/*
+ * ======== bridge_brd_start ========
+ * purpose:
+ * Initializes DSP MMU and Starts DSP.
+ *
+ * Preconditions:
+ * a) DSP domain is 'ACTIVE'.
+ * b) DSP_RST1 is asserted.
+ * b) DSP_RST2 is released.
+ */
+static int bridge_brd_start(struct bridge_dev_context *dev_ctxt,
+ u32 dsp_addr)
+{
+ int status = 0;
+ struct bridge_dev_context *dev_context = dev_ctxt;
+ u32 dw_sync_addr = 0;
+ u32 ul_shm_base; /* Gpp Phys SM base addr(byte) */
+ u32 ul_shm_base_virt; /* Dsp Virt SM base addr */
+ u32 ul_tlb_base_virt; /* Base of MMU TLB entry */
+ /* Offset of shm_base_virt from tlb_base_virt */
+ u32 ul_shm_offset_virt;
+ s32 entry_ndx;
+ s32 itmp_entry_ndx = 0; /* DSP-MMU TLB entry base address */
+ struct cfg_hostres *resources = NULL;
+ u32 temp;
+ u32 ul_dsp_clk_rate;
+ u32 ul_dsp_clk_addr;
+ u32 ul_bios_gp_timer;
+ u32 clk_cmd;
+ struct io_mgr *hio_mgr;
+ u32 ul_load_monitor_timer;
+ struct dspbridge_platform_data *pdata =
+ omap_dspbridge_dev->dev.platform_data;
+
+ /* The device context contains all the mmu setup info from when the
+ * last dsp base image was loaded. The first entry is always
+ * SHMMEM base. */
+ /* Get SHM_BEG - convert to byte address */
+ (void)dev_get_symbol(dev_context->hdev_obj, SHMBASENAME,
+ &ul_shm_base_virt);
+ ul_shm_base_virt *= DSPWORDSIZE;
+ DBC_ASSERT(ul_shm_base_virt != 0);
+ /* DSP Virtual address */
+ ul_tlb_base_virt = dev_context->atlb_entry[0].ul_dsp_va;
+ DBC_ASSERT(ul_tlb_base_virt <= ul_shm_base_virt);
+ ul_shm_offset_virt =
+ ul_shm_base_virt - (ul_tlb_base_virt * DSPWORDSIZE);
+ /* Kernel logical address */
+ ul_shm_base = dev_context->atlb_entry[0].ul_gpp_va + ul_shm_offset_virt;
+
+ DBC_ASSERT(ul_shm_base != 0);
+ /* 2nd wd is used as sync field */
+ dw_sync_addr = ul_shm_base + SHMSYNCOFFSET;
+ /* Write a signature into the shm base + offset; this will
+ * get cleared when the DSP program starts. */
+ if ((ul_shm_base_virt == 0) || (ul_shm_base == 0)) {
+ pr_err("%s: Illegal SM base\n", __func__);
+ status = -EPERM;
+ } else
+ __raw_writel(0xffffffff, dw_sync_addr);
+
+ if (!status) {
+ resources = dev_context->resources;
+ if (!resources)
+ status = -EPERM;
+
+ /* Assert RST1 i.e only the RST only for DSP megacell */
+ if (!status) {
+ (*pdata->dsp_prm_rmw_bits)(OMAP3430_RST1_IVA2_MASK,
+ OMAP3430_RST1_IVA2_MASK, OMAP3430_IVA2_MOD,
+ OMAP2_RM_RSTCTRL);
+ /* Mask address with 1K for compatibility */
+ __raw_writel(dsp_addr & OMAP3_IVA2_BOOTADDR_MASK,
+ OMAP343X_CTRL_REGADDR(
+ OMAP343X_CONTROL_IVA2_BOOTADDR));
+ /*
+ * Set bootmode to self loop if dsp_debug flag is true
+ */
+ __raw_writel((dsp_debug) ? OMAP3_IVA2_BOOTMOD_IDLE : 0,
+ OMAP343X_CTRL_REGADDR(
+ OMAP343X_CONTROL_IVA2_BOOTMOD));
+ }
+ }
+ if (!status) {
+ /* Reset and Unreset the RST2, so that BOOTADDR is copied to
+ * IVA2 SYSC register */
+ (*pdata->dsp_prm_rmw_bits)(OMAP3430_RST2_IVA2_MASK,
+ OMAP3430_RST2_IVA2_MASK, OMAP3430_IVA2_MOD, OMAP2_RM_RSTCTRL);
+ udelay(100);
+ (*pdata->dsp_prm_rmw_bits)(OMAP3430_RST2_IVA2_MASK, 0,
+ OMAP3430_IVA2_MOD, OMAP2_RM_RSTCTRL);
+ udelay(100);
+
+ /* Disbale the DSP MMU */
+ hw_mmu_disable(resources->dw_dmmu_base);
+ /* Disable TWL */
+ hw_mmu_twl_disable(resources->dw_dmmu_base);
+
+ /* Only make TLB entry if both addresses are non-zero */
+ for (entry_ndx = 0; entry_ndx < BRDIOCTL_NUMOFMMUTLB;
+ entry_ndx++) {
+ struct bridge_ioctl_extproc *e = &dev_context->atlb_entry[entry_ndx];
+ struct hw_mmu_map_attrs_t map_attrs = {
+ .endianism = e->endianism,
+ .element_size = e->elem_size,
+ .mixed_size = e->mixed_mode,
+ };
+
+ if (!e->ul_gpp_pa || !e->ul_dsp_va)
+ continue;
+
+ dev_dbg(bridge,
+ "MMU %d, pa: 0x%x, va: 0x%x, size: 0x%x",
+ itmp_entry_ndx,
+ e->ul_gpp_pa,
+ e->ul_dsp_va,
+ e->ul_size);
+
+ hw_mmu_tlb_add(dev_context->dw_dsp_mmu_base,
+ e->ul_gpp_pa,
+ e->ul_dsp_va,
+ e->ul_size,
+ itmp_entry_ndx,
+ &map_attrs, 1, 1);
+
+ itmp_entry_ndx++;
+ }
+ }
+
+ /* Lock the above TLB entries and get the BIOS and load monitor timer
+ * information */
+ if (!status) {
+ hw_mmu_num_locked_set(resources->dw_dmmu_base, itmp_entry_ndx);
+ hw_mmu_victim_num_set(resources->dw_dmmu_base, itmp_entry_ndx);
+ hw_mmu_ttb_set(resources->dw_dmmu_base,
+ dev_context->pt_attrs->l1_base_pa);
+ hw_mmu_twl_enable(resources->dw_dmmu_base);
+ /* Enable the SmartIdle and AutoIdle bit for MMU_SYSCONFIG */
+
+ temp = __raw_readl((resources->dw_dmmu_base) + 0x10);
+ temp = (temp & 0xFFFFFFEF) | 0x11;
+ __raw_writel(temp, (resources->dw_dmmu_base) + 0x10);
+
+ /* Let the DSP MMU run */
+ hw_mmu_enable(resources->dw_dmmu_base);
+
+ /* Enable the BIOS clock */
+ (void)dev_get_symbol(dev_context->hdev_obj,
+ BRIDGEINIT_BIOSGPTIMER, &ul_bios_gp_timer);
+ (void)dev_get_symbol(dev_context->hdev_obj,
+ BRIDGEINIT_LOADMON_GPTIMER,
+ &ul_load_monitor_timer);
+ }
+
+ if (!status) {
+ if (ul_load_monitor_timer != 0xFFFF) {
+ clk_cmd = (BPWR_ENABLE_CLOCK << MBX_PM_CLK_CMDSHIFT) |
+ ul_load_monitor_timer;
+ dsp_peripheral_clk_ctrl(dev_context, &clk_cmd);
+ } else {
+ dev_dbg(bridge, "Not able to get the symbol for Load "
+ "Monitor Timer\n");
+ }
+ }
+
+ if (!status) {
+ if (ul_bios_gp_timer != 0xFFFF) {
+ clk_cmd = (BPWR_ENABLE_CLOCK << MBX_PM_CLK_CMDSHIFT) |
+ ul_bios_gp_timer;
+ dsp_peripheral_clk_ctrl(dev_context, &clk_cmd);
+ } else {
+ dev_dbg(bridge,
+ "Not able to get the symbol for BIOS Timer\n");
+ }
+ }
+
+ if (!status) {
+ /* Set the DSP clock rate */
+ (void)dev_get_symbol(dev_context->hdev_obj,
+ "_BRIDGEINIT_DSP_FREQ", &ul_dsp_clk_addr);
+ /*Set Autoidle Mode for IVA2 PLL */
+ (*pdata->dsp_cm_write)(1 << OMAP3430_AUTO_IVA2_DPLL_SHIFT,
+ OMAP3430_IVA2_MOD, OMAP3430_CM_AUTOIDLE_PLL);
+
+ if ((unsigned int *)ul_dsp_clk_addr != NULL) {
+ /* Get the clock rate */
+ ul_dsp_clk_rate = dsp_clk_get_iva2_rate();
+ dev_dbg(bridge, "%s: DSP clock rate (KHZ): 0x%x \n",
+ __func__, ul_dsp_clk_rate);
+ (void)bridge_brd_write(dev_context,
+ (u8 *) &ul_dsp_clk_rate,
+ ul_dsp_clk_addr, sizeof(u32), 0);
+ }
+ /*
+ * Enable Mailbox events and also drain any pending
+ * stale messages.
+ */
+ dev_context->mbox = omap_mbox_get("dsp");
+ if (IS_ERR(dev_context->mbox)) {
+ dev_context->mbox = NULL;
+ pr_err("%s: Failed to get dsp mailbox handle\n",
+ __func__);
+ status = -EPERM;
+ }
+
+ }
+ if (!status) {
+ dev_context->mbox->rxq->callback = (int (*)(void *))io_mbox_msg;
+
+/*PM_IVA2GRPSEL_PER = 0xC0;*/
+ temp = readl(resources->dw_per_pm_base + 0xA8);
+ temp = (temp & 0xFFFFFF30) | 0xC0;
+ writel(temp, resources->dw_per_pm_base + 0xA8);
+
+/*PM_MPUGRPSEL_PER &= 0xFFFFFF3F; */
+ temp = readl(resources->dw_per_pm_base + 0xA4);
+ temp = (temp & 0xFFFFFF3F);
+ writel(temp, resources->dw_per_pm_base + 0xA4);
+/*CM_SLEEPDEP_PER |= 0x04; */
+ temp = readl(resources->dw_per_base + 0x44);
+ temp = (temp & 0xFFFFFFFB) | 0x04;
+ writel(temp, resources->dw_per_base + 0x44);
+
+/*CM_CLKSTCTRL_IVA2 = 0x00000003 -To Allow automatic transitions */
+ (*pdata->dsp_cm_write)(OMAP34XX_CLKSTCTRL_ENABLE_AUTO,
+ OMAP3430_IVA2_MOD, OMAP2_CM_CLKSTCTRL);
+
+ /* Let DSP go */
+ dev_dbg(bridge, "%s Unreset\n", __func__);
+ /* Enable DSP MMU Interrupts */
+ hw_mmu_event_enable(resources->dw_dmmu_base,
+ HW_MMU_ALL_INTERRUPTS);
+ /* release the RST1, DSP starts executing now .. */
+ (*pdata->dsp_prm_rmw_bits)(OMAP3430_RST1_IVA2_MASK, 0,
+ OMAP3430_IVA2_MOD, OMAP2_RM_RSTCTRL);
+
+ dev_dbg(bridge, "Waiting for Sync @ 0x%x\n", dw_sync_addr);
+ dev_dbg(bridge, "DSP c_int00 Address = 0x%x\n", dsp_addr);
+ if (dsp_debug)
+ while (__raw_readw(dw_sync_addr))
+ ;;
+
+ /* Wait for DSP to clear word in shared memory */
+ /* Read the Location */
+ if (!wait_for_start(dev_context, dw_sync_addr))
+ status = -ETIMEDOUT;
+
+ /* Start wdt */
+ dsp_wdt_sm_set((void *)ul_shm_base);
+ dsp_wdt_enable(true);
+
+ status = dev_get_io_mgr(dev_context->hdev_obj, &hio_mgr);
+ if (hio_mgr) {
+ io_sh_msetting(hio_mgr, SHM_OPPINFO, NULL);
+ /* Write the synchronization bit to indicate the
+ * completion of OPP table update to DSP
+ */
+ __raw_writel(0XCAFECAFE, dw_sync_addr);
+
+ /* update board state */
+ dev_context->dw_brd_state = BRD_RUNNING;
+ /* (void)chnlsm_enable_interrupt(dev_context); */
+ } else {
+ dev_context->dw_brd_state = BRD_UNKNOWN;
+ }
+ }
+ return status;
+}
+
+/*
+ * ======== bridge_brd_stop ========
+ * purpose:
+ * Puts DSP in self loop.
+ *
+ * Preconditions :
+ * a) None
+ */
+static int bridge_brd_stop(struct bridge_dev_context *dev_ctxt)
+{
+ int status = 0;
+ struct bridge_dev_context *dev_context = dev_ctxt;
+ struct pg_table_attrs *pt_attrs;
+ u32 dsp_pwr_state;
+ int clk_status;
+ struct dspbridge_platform_data *pdata =
+ omap_dspbridge_dev->dev.platform_data;
+
+ if (dev_context->dw_brd_state == BRD_STOPPED)
+ return status;
+
+ /* as per TRM, it is advised to first drive the IVA2 to 'Standby' mode,
+ * before turning off the clocks.. This is to ensure that there are no
+ * pending L3 or other transactons from IVA2 */
+ dsp_pwr_state = (*pdata->dsp_prm_read)(OMAP3430_IVA2_MOD, OMAP2_PM_PWSTST) &
+ OMAP_POWERSTATEST_MASK;
+ if (dsp_pwr_state != PWRDM_POWER_OFF) {
+ (*pdata->dsp_prm_rmw_bits)(OMAP3430_RST2_IVA2_MASK, 0,
+ OMAP3430_IVA2_MOD, OMAP2_RM_RSTCTRL);
+ sm_interrupt_dsp(dev_context, MBX_PM_DSPIDLE);
+ mdelay(10);
+
+ /* IVA2 is not in OFF state */
+ /* Set PM_PWSTCTRL_IVA2 to OFF */
+ (*pdata->dsp_prm_rmw_bits)(OMAP_POWERSTATEST_MASK,
+ PWRDM_POWER_OFF, OMAP3430_IVA2_MOD, OMAP2_PM_PWSTCTRL);
+ /* Set the SW supervised state transition for Sleep */
+ (*pdata->dsp_cm_write)(OMAP34XX_CLKSTCTRL_FORCE_SLEEP,
+ OMAP3430_IVA2_MOD, OMAP2_CM_CLKSTCTRL);
+ }
+ udelay(10);
+ /* Release the Ext Base virtual Address as the next DSP Program
+ * may have a different load address */
+ if (dev_context->dw_dsp_ext_base_addr)
+ dev_context->dw_dsp_ext_base_addr = 0;
+
+ dev_context->dw_brd_state = BRD_STOPPED; /* update board state */
+
+ dsp_wdt_enable(false);
+
+ /* This is a good place to clear the MMU page tables as well */
+ if (dev_context->pt_attrs) {
+ pt_attrs = dev_context->pt_attrs;
+ memset((u8 *) pt_attrs->l1_base_va, 0x00, pt_attrs->l1_size);
+ memset((u8 *) pt_attrs->l2_base_va, 0x00, pt_attrs->l2_size);
+ memset((u8 *) pt_attrs->pg_info, 0x00,
+ (pt_attrs->l2_num_pages * sizeof(struct page_info)));
+ }
+ /* Disable the mailbox interrupts */
+ if (dev_context->mbox) {
+ omap_mbox_disable_irq(dev_context->mbox, IRQ_RX);
+ omap_mbox_put(dev_context->mbox);
+ dev_context->mbox = NULL;
+ }
+ /* Reset IVA2 clocks*/
+ (*pdata->dsp_prm_write)(OMAP3430_RST1_IVA2_MASK | OMAP3430_RST2_IVA2_MASK |
+ OMAP3430_RST3_IVA2_MASK, OMAP3430_IVA2_MOD, OMAP2_RM_RSTCTRL);
+
+ clk_status = dsp_clk_disable(DSP_CLK_IVA2);
+
+ return status;
+}
+
+/*
+ * ======== bridge_brd_status ========
+ * Returns the board status.
+ */
+static int bridge_brd_status(struct bridge_dev_context *dev_ctxt,
+ int *board_state)
+{
+ struct bridge_dev_context *dev_context = dev_ctxt;
+ *board_state = dev_context->dw_brd_state;
+ return 0;
+}
+
+/*
+ * ======== bridge_brd_write ========
+ * Copies the buffers to DSP internal or external memory.
+ */
+static int bridge_brd_write(struct bridge_dev_context *dev_ctxt,
+ u8 *host_buff, u32 dsp_addr,
+ u32 ul_num_bytes, u32 mem_type)
+{
+ int status = 0;
+ struct bridge_dev_context *dev_context = dev_ctxt;
+
+ if (dsp_addr < dev_context->dw_dsp_start_add) {
+ status = -EPERM;
+ return status;
+ }
+ if ((dsp_addr - dev_context->dw_dsp_start_add) <
+ dev_context->dw_internal_size) {
+ status = write_dsp_data(dev_ctxt, host_buff, dsp_addr,
+ ul_num_bytes, mem_type);
+ } else {
+ status = write_ext_dsp_data(dev_context, host_buff, dsp_addr,
+ ul_num_bytes, mem_type, false);
+ }
+
+ return status;
+}
+
+/*
+ * ======== bridge_dev_create ========
+ * Creates a driver object. Puts DSP in self loop.
+ */
+static int bridge_dev_create(struct bridge_dev_context
+ **dev_cntxt,
+ struct dev_object *hdev_obj,
+ struct cfg_hostres *config_param)
+{
+ int status = 0;
+ struct bridge_dev_context *dev_context = NULL;
+ s32 entry_ndx;
+ struct cfg_hostres *resources = config_param;
+ struct pg_table_attrs *pt_attrs;
+ u32 pg_tbl_pa;
+ u32 pg_tbl_va;
+ u32 align_size;
+ struct drv_data *drv_datap = dev_get_drvdata(bridge);
+
+ /* Allocate and initialize a data structure to contain the bridge driver
+ * state, which becomes the context for later calls into this driver */
+ dev_context = kzalloc(sizeof(struct bridge_dev_context), GFP_KERNEL);
+ if (!dev_context) {
+ status = -ENOMEM;
+ goto func_end;
+ }
+
+ dev_context->dw_dsp_start_add = (u32) OMAP_GEM_BASE;
+ dev_context->dw_self_loop = (u32) NULL;
+ dev_context->dsp_per_clks = 0;
+ dev_context->dw_internal_size = OMAP_DSP_SIZE;
+ /* Clear dev context MMU table entries.
+ * These get set on bridge_io_on_loaded() call after program loaded. */
+ for (entry_ndx = 0; entry_ndx < BRDIOCTL_NUMOFMMUTLB; entry_ndx++) {
+ dev_context->atlb_entry[entry_ndx].ul_gpp_pa =
+ dev_context->atlb_entry[entry_ndx].ul_dsp_va = 0;
+ }
+ dev_context->dw_dsp_base_addr = (u32) MEM_LINEAR_ADDRESS((void *)
+ (config_param->
+ dw_mem_base
+ [3]),
+ config_param->
+ dw_mem_length
+ [3]);
+ if (!dev_context->dw_dsp_base_addr)
+ status = -EPERM;
+
+ pt_attrs = kzalloc(sizeof(struct pg_table_attrs), GFP_KERNEL);
+ if (pt_attrs != NULL) {
+ /* Assuming that we use only DSP's memory map
+ * until 0x4000:0000 , we would need only 1024
+ * L1 enties i.e L1 size = 4K */
+ pt_attrs->l1_size = 0x1000;
+ align_size = pt_attrs->l1_size;
+ /* Align sizes are expected to be power of 2 */
+ /* we like to get aligned on L1 table size */
+ pg_tbl_va = (u32) mem_alloc_phys_mem(pt_attrs->l1_size,
+ align_size, &pg_tbl_pa);
+
+ /* Check if the PA is aligned for us */
+ if ((pg_tbl_pa) & (align_size - 1)) {
+ /* PA not aligned to page table size ,
+ * try with more allocation and align */
+ mem_free_phys_mem((void *)pg_tbl_va, pg_tbl_pa,
+ pt_attrs->l1_size);
+ /* we like to get aligned on L1 table size */
+ pg_tbl_va =
+ (u32) mem_alloc_phys_mem((pt_attrs->l1_size) * 2,
+ align_size, &pg_tbl_pa);
+ /* We should be able to get aligned table now */
+ pt_attrs->l1_tbl_alloc_pa = pg_tbl_pa;
+ pt_attrs->l1_tbl_alloc_va = pg_tbl_va;
+ pt_attrs->l1_tbl_alloc_sz = pt_attrs->l1_size * 2;
+ /* Align the PA to the next 'align' boundary */
+ pt_attrs->l1_base_pa =
+ ((pg_tbl_pa) +
+ (align_size - 1)) & (~(align_size - 1));
+ pt_attrs->l1_base_va =
+ pg_tbl_va + (pt_attrs->l1_base_pa - pg_tbl_pa);
+ } else {
+ /* We got aligned PA, cool */
+ pt_attrs->l1_tbl_alloc_pa = pg_tbl_pa;
+ pt_attrs->l1_tbl_alloc_va = pg_tbl_va;
+ pt_attrs->l1_tbl_alloc_sz = pt_attrs->l1_size;
+ pt_attrs->l1_base_pa = pg_tbl_pa;
+ pt_attrs->l1_base_va = pg_tbl_va;
+ }
+ if (pt_attrs->l1_base_va)
+ memset((u8 *) pt_attrs->l1_base_va, 0x00,
+ pt_attrs->l1_size);
+
+ /* number of L2 page tables = DMM pool used + SHMMEM +EXTMEM +
+ * L4 pages */
+ pt_attrs->l2_num_pages = ((DMMPOOLSIZE >> 20) + 6);
+ pt_attrs->l2_size = HW_MMU_COARSE_PAGE_SIZE *
+ pt_attrs->l2_num_pages;
+ align_size = 4; /* Make it u32 aligned */
+ /* we like to get aligned on L1 table size */
+ pg_tbl_va = (u32) mem_alloc_phys_mem(pt_attrs->l2_size,
+ align_size, &pg_tbl_pa);
+ pt_attrs->l2_tbl_alloc_pa = pg_tbl_pa;
+ pt_attrs->l2_tbl_alloc_va = pg_tbl_va;
+ pt_attrs->l2_tbl_alloc_sz = pt_attrs->l2_size;
+ pt_attrs->l2_base_pa = pg_tbl_pa;
+ pt_attrs->l2_base_va = pg_tbl_va;
+
+ if (pt_attrs->l2_base_va)
+ memset((u8 *) pt_attrs->l2_base_va, 0x00,
+ pt_attrs->l2_size);
+
+ pt_attrs->pg_info = kzalloc(pt_attrs->l2_num_pages *
+ sizeof(struct page_info), GFP_KERNEL);
+ dev_dbg(bridge,
+ "L1 pa %x, va %x, size %x\n L2 pa %x, va "
+ "%x, size %x\n", pt_attrs->l1_base_pa,
+ pt_attrs->l1_base_va, pt_attrs->l1_size,
+ pt_attrs->l2_base_pa, pt_attrs->l2_base_va,
+ pt_attrs->l2_size);
+ dev_dbg(bridge, "pt_attrs %p L2 NumPages %x pg_info %p\n",
+ pt_attrs, pt_attrs->l2_num_pages, pt_attrs->pg_info);
+ }
+ if ((pt_attrs != NULL) && (pt_attrs->l1_base_va != 0) &&
+ (pt_attrs->l2_base_va != 0) && (pt_attrs->pg_info != NULL))
+ dev_context->pt_attrs = pt_attrs;
+ else
+ status = -ENOMEM;
+
+ if (!status) {
+ spin_lock_init(&pt_attrs->pg_lock);
+ dev_context->tc_word_swap_on = drv_datap->tc_wordswapon;
+
+ /* Set the Clock Divisor for the DSP module */
+ udelay(5);
+ /* MMU address is obtained from the host
+ * resources struct */
+ dev_context->dw_dsp_mmu_base = resources->dw_dmmu_base;
+ }
+ if (!status) {
+ dev_context->hdev_obj = hdev_obj;
+ /* Store current board state. */
+ dev_context->dw_brd_state = BRD_UNKNOWN;
+ dev_context->resources = resources;
+ dsp_clk_enable(DSP_CLK_IVA2);
+ bridge_brd_stop(dev_context);
+ /* Return ptr to our device state to the DSP API for storage */
+ *dev_cntxt = dev_context;
+ } else {
+ if (pt_attrs != NULL) {
+ kfree(pt_attrs->pg_info);
+
+ if (pt_attrs->l2_tbl_alloc_va) {
+ mem_free_phys_mem((void *)
+ pt_attrs->l2_tbl_alloc_va,
+ pt_attrs->l2_tbl_alloc_pa,
+ pt_attrs->l2_tbl_alloc_sz);
+ }
+ if (pt_attrs->l1_tbl_alloc_va) {
+ mem_free_phys_mem((void *)
+ pt_attrs->l1_tbl_alloc_va,
+ pt_attrs->l1_tbl_alloc_pa,
+ pt_attrs->l1_tbl_alloc_sz);
+ }
+ }
+ kfree(pt_attrs);
+ kfree(dev_context);
+ }
+func_end:
+ return status;
+}
+
+/*
+ * ======== bridge_dev_ctrl ========
+ * Receives device specific commands.
+ */
+static int bridge_dev_ctrl(struct bridge_dev_context *dev_context,
+ u32 dw_cmd, void *pargs)
+{
+ int status = 0;
+ struct bridge_ioctl_extproc *pa_ext_proc =
+ (struct bridge_ioctl_extproc *)pargs;
+ s32 ndx;
+
+ switch (dw_cmd) {
+ case BRDIOCTL_CHNLREAD:
+ break;
+ case BRDIOCTL_CHNLWRITE:
+ break;
+ case BRDIOCTL_SETMMUCONFIG:
+ /* store away dsp-mmu setup values for later use */
+ for (ndx = 0; ndx < BRDIOCTL_NUMOFMMUTLB; ndx++, pa_ext_proc++)
+ dev_context->atlb_entry[ndx] = *pa_ext_proc;
+ break;
+ case BRDIOCTL_DEEPSLEEP:
+ case BRDIOCTL_EMERGENCYSLEEP:
+ /* Currently only DSP Idle is supported Need to update for
+ * later releases */
+ status = sleep_dsp(dev_context, PWR_DEEPSLEEP, pargs);
+ break;
+ case BRDIOCTL_WAKEUP:
+ status = wake_dsp(dev_context, pargs);
+ break;
+ case BRDIOCTL_CLK_CTRL:
+ status = 0;
+ /* Looking For Baseport Fix for Clocks */
+ status = dsp_peripheral_clk_ctrl(dev_context, pargs);
+ break;
+ case BRDIOCTL_PWR_HIBERNATE:
+ status = handle_hibernation_from_dsp(dev_context);
+ break;
+ case BRDIOCTL_PRESCALE_NOTIFY:
+ status = pre_scale_dsp(dev_context, pargs);
+ break;
+ case BRDIOCTL_POSTSCALE_NOTIFY:
+ status = post_scale_dsp(dev_context, pargs);
+ break;
+ case BRDIOCTL_CONSTRAINT_REQUEST:
+ status = handle_constraints_set(dev_context, pargs);
+ break;
+ default:
+ status = -EPERM;
+ break;
+ }
+ return status;
+}
+
+/*
+ * ======== bridge_dev_destroy ========
+ * Destroys the driver object.
+ */
+static int bridge_dev_destroy(struct bridge_dev_context *dev_ctxt)
+{
+ struct pg_table_attrs *pt_attrs;
+ int status = 0;
+ struct bridge_dev_context *dev_context = (struct bridge_dev_context *)
+ dev_ctxt;
+ struct cfg_hostres *host_res;
+ u32 shm_size;
+ struct drv_data *drv_datap = dev_get_drvdata(bridge);
+
+ /* It should never happen */
+ if (!dev_ctxt)
+ return -EFAULT;
+
+ /* first put the device to stop state */
+ bridge_brd_stop(dev_context);
+ if (dev_context->pt_attrs) {
+ pt_attrs = dev_context->pt_attrs;
+ kfree(pt_attrs->pg_info);
+
+ if (pt_attrs->l2_tbl_alloc_va) {
+ mem_free_phys_mem((void *)pt_attrs->l2_tbl_alloc_va,
+ pt_attrs->l2_tbl_alloc_pa,
+ pt_attrs->l2_tbl_alloc_sz);
+ }
+ if (pt_attrs->l1_tbl_alloc_va) {
+ mem_free_phys_mem((void *)pt_attrs->l1_tbl_alloc_va,
+ pt_attrs->l1_tbl_alloc_pa,
+ pt_attrs->l1_tbl_alloc_sz);
+ }
+ kfree(pt_attrs);
+
+ }
+
+ if (dev_context->resources) {
+ host_res = dev_context->resources;
+ shm_size = drv_datap->shm_size;
+ if (shm_size >= 0x10000) {
+ if ((host_res->dw_mem_base[1]) &&
+ (host_res->dw_mem_phys[1])) {
+ mem_free_phys_mem((void *)
+ host_res->dw_mem_base
+ [1],
+ host_res->dw_mem_phys
+ [1], shm_size);
+ }
+ } else {
+ dev_dbg(bridge, "%s: Error getting shm size "
+ "from registry: %x. Not calling "
+ "mem_free_phys_mem\n", __func__,
+ status);
+ }
+ host_res->dw_mem_base[1] = 0;
+ host_res->dw_mem_phys[1] = 0;
+
+ if (host_res->dw_mem_base[0])
+ iounmap((void *)host_res->dw_mem_base[0]);
+ if (host_res->dw_mem_base[2])
+ iounmap((void *)host_res->dw_mem_base[2]);
+ if (host_res->dw_mem_base[3])
+ iounmap((void *)host_res->dw_mem_base[3]);
+ if (host_res->dw_mem_base[4])
+ iounmap((void *)host_res->dw_mem_base[4]);
+ if (host_res->dw_dmmu_base)
+ iounmap(host_res->dw_dmmu_base);
+ if (host_res->dw_per_base)
+ iounmap(host_res->dw_per_base);
+ if (host_res->dw_per_pm_base)
+ iounmap((void *)host_res->dw_per_pm_base);
+ if (host_res->dw_core_pm_base)
+ iounmap((void *)host_res->dw_core_pm_base);
+ if (host_res->dw_sys_ctrl_base)
+ iounmap(host_res->dw_sys_ctrl_base);
+
+ host_res->dw_mem_base[0] = (u32) NULL;
+ host_res->dw_mem_base[2] = (u32) NULL;
+ host_res->dw_mem_base[3] = (u32) NULL;
+ host_res->dw_mem_base[4] = (u32) NULL;
+ host_res->dw_dmmu_base = NULL;
+ host_res->dw_sys_ctrl_base = NULL;
+
+ kfree(host_res);
+ }
+
+ /* Free the driver's device context: */
+ kfree(drv_datap->base_img);
+ kfree(drv_datap);
+ dev_set_drvdata(bridge, NULL);
+ kfree((void *)dev_ctxt);
+ return status;
+}
+
+static int bridge_brd_mem_copy(struct bridge_dev_context *dev_ctxt,
+ u32 dsp_dest_addr, u32 dsp_src_addr,
+ u32 ul_num_bytes, u32 mem_type)
+{
+ int status = 0;
+ u32 src_addr = dsp_src_addr;
+ u32 dest_addr = dsp_dest_addr;
+ u32 copy_bytes = 0;
+ u32 total_bytes = ul_num_bytes;
+ u8 host_buf[BUFFERSIZE];
+ struct bridge_dev_context *dev_context = dev_ctxt;
+ while (total_bytes > 0 && !status) {
+ copy_bytes =
+ total_bytes > BUFFERSIZE ? BUFFERSIZE : total_bytes;
+ /* Read from External memory */
+ status = read_ext_dsp_data(dev_ctxt, host_buf, src_addr,
+ copy_bytes, mem_type);
+ if (!status) {
+ if (dest_addr < (dev_context->dw_dsp_start_add +
+ dev_context->dw_internal_size)) {
+ /* Write to Internal memory */
+ status = write_dsp_data(dev_ctxt, host_buf,
+ dest_addr, copy_bytes,
+ mem_type);
+ } else {
+ /* Write to External memory */
+ status =
+ write_ext_dsp_data(dev_ctxt, host_buf,
+ dest_addr, copy_bytes,
+ mem_type, false);
+ }
+ }
+ total_bytes -= copy_bytes;
+ src_addr += copy_bytes;
+ dest_addr += copy_bytes;
+ }
+ return status;
+}
+
+/* Mem Write does not halt the DSP to write unlike bridge_brd_write */
+static int bridge_brd_mem_write(struct bridge_dev_context *dev_ctxt,
+ u8 *host_buff, u32 dsp_addr,
+ u32 ul_num_bytes, u32 mem_type)
+{
+ int status = 0;
+ struct bridge_dev_context *dev_context = dev_ctxt;
+ u32 ul_remain_bytes = 0;
+ u32 ul_bytes = 0;
+ ul_remain_bytes = ul_num_bytes;
+ while (ul_remain_bytes > 0 && !status) {
+ ul_bytes =
+ ul_remain_bytes > BUFFERSIZE ? BUFFERSIZE : ul_remain_bytes;
+ if (dsp_addr < (dev_context->dw_dsp_start_add +
+ dev_context->dw_internal_size)) {
+ status =
+ write_dsp_data(dev_ctxt, host_buff, dsp_addr,
+ ul_bytes, mem_type);
+ } else {
+ status = write_ext_dsp_data(dev_ctxt, host_buff,
+ dsp_addr, ul_bytes,
+ mem_type, true);
+ }
+ ul_remain_bytes -= ul_bytes;
+ dsp_addr += ul_bytes;
+ host_buff = host_buff + ul_bytes;
+ }
+ return status;
+}
+
+/*
+ * ======== bridge_brd_mem_map ========
+ * This function maps MPU buffer to the DSP address space. It performs
+ * linear to physical address translation if required. It translates each
+ * page since linear addresses can be physically non-contiguous
+ * All address & size arguments are assumed to be page aligned (in proc.c)
+ *
+ * TODO: Disable MMU while updating the page tables (but that'll stall DSP)
+ */
+static int bridge_brd_mem_map(struct bridge_dev_context *dev_ctxt,
+ u32 ul_mpu_addr, u32 virt_addr,
+ u32 ul_num_bytes, u32 ul_map_attr,
+ struct page **mapped_pages)
+{
+ u32 attrs;
+ int status = 0;
+ struct bridge_dev_context *dev_context = dev_ctxt;
+ struct hw_mmu_map_attrs_t hw_attrs;
+ struct vm_area_struct *vma;
+ struct mm_struct *mm = current->mm;
+ u32 write = 0;
+ u32 num_usr_pgs = 0;
+ struct page *mapped_page, *pg;
+ s32 pg_num;
+ u32 va = virt_addr;
+ struct task_struct *curr_task = current;
+ u32 pg_i = 0;
+ u32 mpu_addr, pa;
+
+ dev_dbg(bridge,
+ "%s hDevCtxt %p, pa %x, va %x, size %x, ul_map_attr %x\n",
+ __func__, dev_ctxt, ul_mpu_addr, virt_addr, ul_num_bytes,
+ ul_map_attr);
+ if (ul_num_bytes == 0)
+ return -EINVAL;
+
+ if (ul_map_attr & DSP_MAP_DIR_MASK) {
+ attrs = ul_map_attr;
+ } else {
+ /* Assign default attributes */
+ attrs = ul_map_attr | (DSP_MAPVIRTUALADDR | DSP_MAPELEMSIZE16);
+ }
+ /* Take mapping properties */
+ if (attrs & DSP_MAPBIGENDIAN)
+ hw_attrs.endianism = HW_BIG_ENDIAN;
+ else
+ hw_attrs.endianism = HW_LITTLE_ENDIAN;
+
+ hw_attrs.mixed_size = (enum hw_mmu_mixed_size_t)
+ ((attrs & DSP_MAPMIXEDELEMSIZE) >> 2);
+ /* Ignore element_size if mixed_size is enabled */
+ if (hw_attrs.mixed_size == 0) {
+ if (attrs & DSP_MAPELEMSIZE8) {
+ /* Size is 8 bit */
+ hw_attrs.element_size = HW_ELEM_SIZE8BIT;
+ } else if (attrs & DSP_MAPELEMSIZE16) {
+ /* Size is 16 bit */
+ hw_attrs.element_size = HW_ELEM_SIZE16BIT;
+ } else if (attrs & DSP_MAPELEMSIZE32) {
+ /* Size is 32 bit */
+ hw_attrs.element_size = HW_ELEM_SIZE32BIT;
+ } else if (attrs & DSP_MAPELEMSIZE64) {
+ /* Size is 64 bit */
+ hw_attrs.element_size = HW_ELEM_SIZE64BIT;
+ } else {
+ /*
+ * Mixedsize isn't enabled, so size can't be
+ * zero here
+ */
+ return -EINVAL;
+ }
+ }
+ if (attrs & DSP_MAPDONOTLOCK)
+ hw_attrs.donotlockmpupage = 1;
+ else
+ hw_attrs.donotlockmpupage = 0;
+
+ if (attrs & DSP_MAPVMALLOCADDR) {
+ return mem_map_vmalloc(dev_ctxt, ul_mpu_addr, virt_addr,
+ ul_num_bytes, &hw_attrs);
+ }
+ /*
+ * Do OS-specific user-va to pa translation.
+ * Combine physically contiguous regions to reduce TLBs.
+ * Pass the translated pa to pte_update.
+ */
+ if ((attrs & DSP_MAPPHYSICALADDR)) {
+ status = pte_update(dev_context, ul_mpu_addr, virt_addr,
+ ul_num_bytes, &hw_attrs);
+ goto func_cont;
+ }
+
+ /*
+ * Important Note: ul_mpu_addr is mapped from user application process
+ * to current process - it must lie completely within the current
+ * virtual memory address space in order to be of use to us here!
+ */
+ down_read(&mm->mmap_sem);
+ vma = find_vma(mm, ul_mpu_addr);
+ if (vma)
+ dev_dbg(bridge,
+ "VMAfor UserBuf: ul_mpu_addr=%x, ul_num_bytes=%x, "
+ "vm_start=%lx, vm_end=%lx, vm_flags=%lx\n", ul_mpu_addr,
+ ul_num_bytes, vma->vm_start, vma->vm_end,
+ vma->vm_flags);
+
+ /*
+ * It is observed that under some circumstances, the user buffer is
+ * spread across several VMAs. So loop through and check if the entire
+ * user buffer is covered
+ */
+ while ((vma) && (ul_mpu_addr + ul_num_bytes > vma->vm_end)) {
+ /* jump to the next VMA region */
+ vma = find_vma(mm, vma->vm_end + 1);
+ dev_dbg(bridge,
+ "VMA for UserBuf ul_mpu_addr=%x ul_num_bytes=%x, "
+ "vm_start=%lx, vm_end=%lx, vm_flags=%lx\n", ul_mpu_addr,
+ ul_num_bytes, vma->vm_start, vma->vm_end,
+ vma->vm_flags);
+ }
+ if (!vma) {
+ pr_err("%s: Failed to get VMA region for 0x%x (%d)\n",
+ __func__, ul_mpu_addr, ul_num_bytes);
+ status = -EINVAL;
+ up_read(&mm->mmap_sem);
+ goto func_cont;
+ }
+
+ if (vma->vm_flags & VM_IO) {
+ num_usr_pgs = ul_num_bytes / PG_SIZE4K;
+ mpu_addr = ul_mpu_addr;
+
+ /* Get the physical addresses for user buffer */
+ for (pg_i = 0; pg_i < num_usr_pgs; pg_i++) {
+ pa = user_va2_pa(mm, mpu_addr);
+ if (!pa) {
+ status = -EPERM;
+ pr_err("DSPBRIDGE: VM_IO mapping physical"
+ "address is invalid\n");
+ break;
+ }
+ if (pfn_valid(__phys_to_pfn(pa))) {
+ pg = PHYS_TO_PAGE(pa);
+ get_page(pg);
+ if (page_count(pg) < 1) {
+ pr_err("Bad page in VM_IO buffer\n");
+ bad_page_dump(pa, pg);
+ }
+ }
+ status = pte_set(dev_context->pt_attrs, pa,
+ va, HW_PAGE_SIZE4KB, &hw_attrs);
+ if (status)
+ break;
+
+ va += HW_PAGE_SIZE4KB;
+ mpu_addr += HW_PAGE_SIZE4KB;
+ pa += HW_PAGE_SIZE4KB;
+ }
+ } else {
+ num_usr_pgs = ul_num_bytes / PG_SIZE4K;
+ if (vma->vm_flags & (VM_WRITE | VM_MAYWRITE))
+ write = 1;
+
+ for (pg_i = 0; pg_i < num_usr_pgs; pg_i++) {
+ pg_num = get_user_pages(curr_task, mm, ul_mpu_addr, 1,
+ write, 1, &mapped_page, NULL);
+ if (pg_num > 0) {
+ if (page_count(mapped_page) < 1) {
+ pr_err("Bad page count after doing"
+ "get_user_pages on"
+ "user buffer\n");
+ bad_page_dump(page_to_phys(mapped_page),
+ mapped_page);
+ }
+ status = pte_set(dev_context->pt_attrs,
+ page_to_phys(mapped_page), va,
+ HW_PAGE_SIZE4KB, &hw_attrs);
+ if (status)
+ break;
+
+ if (mapped_pages)
+ mapped_pages[pg_i] = mapped_page;
+
+ va += HW_PAGE_SIZE4KB;
+ ul_mpu_addr += HW_PAGE_SIZE4KB;
+ } else {
+ pr_err("DSPBRIDGE: get_user_pages FAILED,"
+ "MPU addr = 0x%x,"
+ "vma->vm_flags = 0x%lx,"
+ "get_user_pages Err"
+ "Value = %d, Buffer"
+ "size=0x%x\n", ul_mpu_addr,
+ vma->vm_flags, pg_num, ul_num_bytes);
+ status = -EPERM;
+ break;
+ }
+ }
+ }
+ up_read(&mm->mmap_sem);
+func_cont:
+ if (status) {
+ /*
+ * Roll out the mapped pages incase it failed in middle of
+ * mapping
+ */
+ if (pg_i) {
+ bridge_brd_mem_un_map(dev_context, virt_addr,
+ (pg_i * PG_SIZE4K));
+ }
+ status = -EPERM;
+ }
+ /*
+ * In any case, flush the TLB
+ * This is called from here instead from pte_update to avoid unnecessary
+ * repetition while mapping non-contiguous physical regions of a virtual
+ * region
+ */
+ flush_all(dev_context);
+ dev_dbg(bridge, "%s status %x\n", __func__, status);
+ return status;
+}
+
+/*
+ * ======== bridge_brd_mem_un_map ========
+ * Invalidate the PTEs for the DSP VA block to be unmapped.
+ *
+ * PTEs of a mapped memory block are contiguous in any page table
+ * So, instead of looking up the PTE address for every 4K block,
+ * we clear consecutive PTEs until we unmap all the bytes
+ */
+static int bridge_brd_mem_un_map(struct bridge_dev_context *dev_ctxt,
+ u32 virt_addr, u32 ul_num_bytes)
+{
+ u32 l1_base_va;
+ u32 l2_base_va;
+ u32 l2_base_pa;
+ u32 l2_page_num;
+ u32 pte_val;
+ u32 pte_size;
+ u32 pte_count;
+ u32 pte_addr_l1;
+ u32 pte_addr_l2 = 0;
+ u32 rem_bytes;
+ u32 rem_bytes_l2;
+ u32 va_curr;
+ struct page *pg = NULL;
+ int status = 0;
+ struct bridge_dev_context *dev_context = dev_ctxt;
+ struct pg_table_attrs *pt = dev_context->pt_attrs;
+ u32 temp;
+ u32 paddr;
+ u32 numof4k_pages = 0;
+
+ va_curr = virt_addr;
+ rem_bytes = ul_num_bytes;
+ rem_bytes_l2 = 0;
+ l1_base_va = pt->l1_base_va;
+ pte_addr_l1 = hw_mmu_pte_addr_l1(l1_base_va, va_curr);
+ dev_dbg(bridge, "%s dev_ctxt %p, va %x, NumBytes %x l1_base_va %x, "
+ "pte_addr_l1 %x\n", __func__, dev_ctxt, virt_addr,
+ ul_num_bytes, l1_base_va, pte_addr_l1);
+
+ while (rem_bytes && !status) {
+ u32 va_curr_orig = va_curr;
+ /* Find whether the L1 PTE points to a valid L2 PT */
+ pte_addr_l1 = hw_mmu_pte_addr_l1(l1_base_va, va_curr);
+ pte_val = *(u32 *) pte_addr_l1;
+ pte_size = hw_mmu_pte_size_l1(pte_val);
+
+ if (pte_size != HW_MMU_COARSE_PAGE_SIZE)
+ goto skip_coarse_page;
+
+ /*
+ * Get the L2 PA from the L1 PTE, and find
+ * corresponding L2 VA
+ */
+ l2_base_pa = hw_mmu_pte_coarse_l1(pte_val);
+ l2_base_va = l2_base_pa - pt->l2_base_pa + pt->l2_base_va;
+ l2_page_num =
+ (l2_base_pa - pt->l2_base_pa) / HW_MMU_COARSE_PAGE_SIZE;
+ /*
+ * Find the L2 PTE address from which we will start
+ * clearing, the number of PTEs to be cleared on this
+ * page, and the size of VA space that needs to be
+ * cleared on this L2 page
+ */
+ pte_addr_l2 = hw_mmu_pte_addr_l2(l2_base_va, va_curr);
+ pte_count = pte_addr_l2 & (HW_MMU_COARSE_PAGE_SIZE - 1);
+ pte_count = (HW_MMU_COARSE_PAGE_SIZE - pte_count) / sizeof(u32);
+ if (rem_bytes < (pte_count * PG_SIZE4K))
+ pte_count = rem_bytes / PG_SIZE4K;
+ rem_bytes_l2 = pte_count * PG_SIZE4K;
+
+ /*
+ * Unmap the VA space on this L2 PT. A quicker way
+ * would be to clear pte_count entries starting from
+ * pte_addr_l2. However, below code checks that we don't
+ * clear invalid entries or less than 64KB for a 64KB
+ * entry. Similar checking is done for L1 PTEs too
+ * below
+ */
+ while (rem_bytes_l2 && !status) {
+ pte_val = *(u32 *) pte_addr_l2;
+ pte_size = hw_mmu_pte_size_l2(pte_val);
+ /* va_curr aligned to pte_size? */
+ if (pte_size == 0 || rem_bytes_l2 < pte_size ||
+ va_curr & (pte_size - 1)) {
+ status = -EPERM;
+ break;
+ }
+
+ /* Collect Physical addresses from VA */
+ paddr = (pte_val & ~(pte_size - 1));
+ if (pte_size == HW_PAGE_SIZE64KB)
+ numof4k_pages = 16;
+ else
+ numof4k_pages = 1;
+ temp = 0;
+ while (temp++ < numof4k_pages) {
+ if (!pfn_valid(__phys_to_pfn(paddr))) {
+ paddr += HW_PAGE_SIZE4KB;
+ continue;
+ }
+ pg = PHYS_TO_PAGE(paddr);
+ if (page_count(pg) < 1) {
+ pr_info("DSPBRIDGE: UNMAP function: "
+ "COUNT 0 FOR PA 0x%x, size = "
+ "0x%x\n", paddr, ul_num_bytes);
+ bad_page_dump(paddr, pg);
+ } else {
+ set_page_dirty(pg);
+ page_cache_release(pg);
+ }
+ paddr += HW_PAGE_SIZE4KB;
+ }
+ if (hw_mmu_pte_clear(pte_addr_l2, va_curr, pte_size)) {
+ status = -EPERM;
+ goto EXIT_LOOP;
+ }
+
+ status = 0;
+ rem_bytes_l2 -= pte_size;
+ va_curr += pte_size;
+ pte_addr_l2 += (pte_size >> 12) * sizeof(u32);
+ }
+ spin_lock(&pt->pg_lock);
+ if (rem_bytes_l2 == 0) {
+ pt->pg_info[l2_page_num].num_entries -= pte_count;
+ if (pt->pg_info[l2_page_num].num_entries == 0) {
+ /*
+ * Clear the L1 PTE pointing to the L2 PT
+ */
+ if (!hw_mmu_pte_clear(l1_base_va, va_curr_orig,
+ HW_MMU_COARSE_PAGE_SIZE))
+ status = 0;
+ else {
+ status = -EPERM;
+ spin_unlock(&pt->pg_lock);
+ goto EXIT_LOOP;
+ }
+ }
+ rem_bytes -= pte_count * PG_SIZE4K;
+ } else
+ status = -EPERM;
+
+ spin_unlock(&pt->pg_lock);
+ continue;
+skip_coarse_page:
+ /* va_curr aligned to pte_size? */
+ /* pte_size = 1 MB or 16 MB */
+ if (pte_size == 0 || rem_bytes < pte_size ||
+ va_curr & (pte_size - 1)) {
+ status = -EPERM;
+ break;
+ }
+
+ if (pte_size == HW_PAGE_SIZE1MB)
+ numof4k_pages = 256;
+ else
+ numof4k_pages = 4096;
+ temp = 0;
+ /* Collect Physical addresses from VA */
+ paddr = (pte_val & ~(pte_size - 1));
+ while (temp++ < numof4k_pages) {
+ if (pfn_valid(__phys_to_pfn(paddr))) {
+ pg = PHYS_TO_PAGE(paddr);
+ if (page_count(pg) < 1) {
+ pr_info("DSPBRIDGE: UNMAP function: "
+ "COUNT 0 FOR PA 0x%x, size = "
+ "0x%x\n", paddr, ul_num_bytes);
+ bad_page_dump(paddr, pg);
+ } else {
+ set_page_dirty(pg);
+ page_cache_release(pg);
+ }
+ }
+ paddr += HW_PAGE_SIZE4KB;
+ }
+ if (!hw_mmu_pte_clear(l1_base_va, va_curr, pte_size)) {
+ status = 0;
+ rem_bytes -= pte_size;
+ va_curr += pte_size;
+ } else {
+ status = -EPERM;
+ goto EXIT_LOOP;
+ }
+ }
+ /*
+ * It is better to flush the TLB here, so that any stale old entries
+ * get flushed
+ */
+EXIT_LOOP:
+ flush_all(dev_context);
+ dev_dbg(bridge,
+ "%s: va_curr %x, pte_addr_l1 %x pte_addr_l2 %x rem_bytes %x,"
+ " rem_bytes_l2 %x status %x\n", __func__, va_curr, pte_addr_l1,
+ pte_addr_l2, rem_bytes, rem_bytes_l2, status);
+ return status;
+}
+
+/*
+ * ======== user_va2_pa ========
+ * Purpose:
+ * This function walks through the page tables to convert a userland
+ * virtual address to physical address
+ */
+static u32 user_va2_pa(struct mm_struct *mm, u32 address)
+{
+ pgd_t *pgd;
+ pmd_t *pmd;
+ pte_t *ptep, pte;
+
+ pgd = pgd_offset(mm, address);
+ if (!(pgd_none(*pgd) || pgd_bad(*pgd))) {
+ pmd = pmd_offset(pgd, address);
+ if (!(pmd_none(*pmd) || pmd_bad(*pmd))) {
+ ptep = pte_offset_map(pmd, address);
+ if (ptep) {
+ pte = *ptep;
+ if (pte_present(pte))
+ return pte & PAGE_MASK;
+ }
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * ======== pte_update ========
+ * This function calculates the optimum page-aligned addresses and sizes
+ * Caller must pass page-aligned values
+ */
+static int pte_update(struct bridge_dev_context *dev_ctxt, u32 pa,
+ u32 va, u32 size,
+ struct hw_mmu_map_attrs_t *map_attrs)
+{
+ u32 i;
+ u32 all_bits;
+ u32 pa_curr = pa;
+ u32 va_curr = va;
+ u32 num_bytes = size;
+ struct bridge_dev_context *dev_context = dev_ctxt;
+ int status = 0;
+ u32 page_size[] = { HW_PAGE_SIZE16MB, HW_PAGE_SIZE1MB,
+ HW_PAGE_SIZE64KB, HW_PAGE_SIZE4KB
+ };
+
+ while (num_bytes && !status) {
+ /* To find the max. page size with which both PA & VA are
+ * aligned */
+ all_bits = pa_curr | va_curr;
+
+ for (i = 0; i < 4; i++) {
+ if ((num_bytes >= page_size[i]) && ((all_bits &
+ (page_size[i] -
+ 1)) == 0)) {
+ status =
+ pte_set(dev_context->pt_attrs, pa_curr,
+ va_curr, page_size[i], map_attrs);
+ pa_curr += page_size[i];
+ va_curr += page_size[i];
+ num_bytes -= page_size[i];
+ /* Don't try smaller sizes. Hopefully we have
+ * reached an address aligned to a bigger page
+ * size */
+ break;
+ }
+ }
+ }
+
+ return status;
+}
+
+/*
+ * ======== pte_set ========
+ * This function calculates PTE address (MPU virtual) to be updated
+ * It also manages the L2 page tables
+ */
+static int pte_set(struct pg_table_attrs *pt, u32 pa, u32 va,
+ u32 size, struct hw_mmu_map_attrs_t *attrs)
+{
+ u32 i;
+ u32 pte_val;
+ u32 pte_addr_l1;
+ u32 pte_size;
+ /* Base address of the PT that will be updated */
+ u32 pg_tbl_va;
+ u32 l1_base_va;
+ /* Compiler warns that the next three variables might be used
+ * uninitialized in this function. Doesn't seem so. Working around,
+ * anyways. */
+ u32 l2_base_va = 0;
+ u32 l2_base_pa = 0;
+ u32 l2_page_num = 0;
+ int status = 0;
+
+ l1_base_va = pt->l1_base_va;
+ pg_tbl_va = l1_base_va;
+ if ((size == HW_PAGE_SIZE64KB) || (size == HW_PAGE_SIZE4KB)) {
+ /* Find whether the L1 PTE points to a valid L2 PT */
+ pte_addr_l1 = hw_mmu_pte_addr_l1(l1_base_va, va);
+ if (pte_addr_l1 <= (pt->l1_base_va + pt->l1_size)) {
+ pte_val = *(u32 *) pte_addr_l1;
+ pte_size = hw_mmu_pte_size_l1(pte_val);
+ } else {
+ return -EPERM;
+ }
+ spin_lock(&pt->pg_lock);
+ if (pte_size == HW_MMU_COARSE_PAGE_SIZE) {
+ /* Get the L2 PA from the L1 PTE, and find
+ * corresponding L2 VA */
+ l2_base_pa = hw_mmu_pte_coarse_l1(pte_val);
+ l2_base_va =
+ l2_base_pa - pt->l2_base_pa + pt->l2_base_va;
+ l2_page_num =
+ (l2_base_pa -
+ pt->l2_base_pa) / HW_MMU_COARSE_PAGE_SIZE;
+ } else if (pte_size == 0) {
+ /* L1 PTE is invalid. Allocate a L2 PT and
+ * point the L1 PTE to it */
+ /* Find a free L2 PT. */
+ for (i = 0; (i < pt->l2_num_pages) &&
+ (pt->pg_info[i].num_entries != 0); i++)
+ ;;
+ if (i < pt->l2_num_pages) {
+ l2_page_num = i;
+ l2_base_pa = pt->l2_base_pa + (l2_page_num *
+ HW_MMU_COARSE_PAGE_SIZE);
+ l2_base_va = pt->l2_base_va + (l2_page_num *
+ HW_MMU_COARSE_PAGE_SIZE);
+ /* Endianness attributes are ignored for
+ * HW_MMU_COARSE_PAGE_SIZE */
+ status =
+ hw_mmu_pte_set(l1_base_va, l2_base_pa, va,
+ HW_MMU_COARSE_PAGE_SIZE,
+ attrs);
+ } else {
+ status = -ENOMEM;
+ }
+ } else {
+ /* Found valid L1 PTE of another size.
+ * Should not overwrite it. */
+ status = -EPERM;
+ }
+ if (!status) {
+ pg_tbl_va = l2_base_va;
+ if (size == HW_PAGE_SIZE64KB)
+ pt->pg_info[l2_page_num].num_entries += 16;
+ else
+ pt->pg_info[l2_page_num].num_entries++;
+ dev_dbg(bridge, "PTE: L2 BaseVa %x, BasePa %x, PageNum "
+ "%x, num_entries %x\n", l2_base_va,
+ l2_base_pa, l2_page_num,
+ pt->pg_info[l2_page_num].num_entries);
+ }
+ spin_unlock(&pt->pg_lock);
+ }
+ if (!status) {
+ dev_dbg(bridge, "PTE: pg_tbl_va %x, pa %x, va %x, size %x\n",
+ pg_tbl_va, pa, va, size);
+ dev_dbg(bridge, "PTE: endianism %x, element_size %x, "
+ "mixed_size %x\n", attrs->endianism,
+ attrs->element_size, attrs->mixed_size);
+ status = hw_mmu_pte_set(pg_tbl_va, pa, va, size, attrs);
+ }
+
+ return status;
+}
+
+/* Memory map kernel VA -- memory allocated with vmalloc */
+static int mem_map_vmalloc(struct bridge_dev_context *dev_context,
+ u32 ul_mpu_addr, u32 virt_addr,
+ u32 ul_num_bytes,
+ struct hw_mmu_map_attrs_t *hw_attrs)
+{
+ int status = 0;
+ struct page *page[1];
+ u32 i;
+ u32 pa_curr;
+ u32 pa_next;
+ u32 va_curr;
+ u32 size_curr;
+ u32 num_pages;
+ u32 pa;
+ u32 num_of4k_pages;
+ u32 temp = 0;
+
+ /*
+ * Do Kernel va to pa translation.
+ * Combine physically contiguous regions to reduce TLBs.
+ * Pass the translated pa to pte_update.
+ */
+ num_pages = ul_num_bytes / PAGE_SIZE; /* PAGE_SIZE = OS page size */
+ i = 0;
+ va_curr = ul_mpu_addr;
+ page[0] = vmalloc_to_page((void *)va_curr);
+ pa_next = page_to_phys(page[0]);
+ while (!status && (i < num_pages)) {
+ /*
+ * Reuse pa_next from the previous iteraion to avoid
+ * an extra va2pa call
+ */
+ pa_curr = pa_next;
+ size_curr = PAGE_SIZE;
+ /*
+ * If the next page is physically contiguous,
+ * map it with the current one by increasing
+ * the size of the region to be mapped
+ */
+ while (++i < num_pages) {
+ page[0] =
+ vmalloc_to_page((void *)(va_curr + size_curr));
+ pa_next = page_to_phys(page[0]);
+
+ if (pa_next == (pa_curr + size_curr))
+ size_curr += PAGE_SIZE;
+ else
+ break;
+
+ }
+ if (pa_next == 0) {
+ status = -ENOMEM;
+ break;
+ }
+ pa = pa_curr;
+ num_of4k_pages = size_curr / HW_PAGE_SIZE4KB;
+ while (temp++ < num_of4k_pages) {
+ get_page(PHYS_TO_PAGE(pa));
+ pa += HW_PAGE_SIZE4KB;
+ }
+ status = pte_update(dev_context, pa_curr, virt_addr +
+ (va_curr - ul_mpu_addr), size_curr,
+ hw_attrs);
+ va_curr += size_curr;
+ }
+ /*
+ * In any case, flush the TLB
+ * This is called from here instead from pte_update to avoid unnecessary
+ * repetition while mapping non-contiguous physical regions of a virtual
+ * region
+ */
+ flush_all(dev_context);
+ dev_dbg(bridge, "%s status %x\n", __func__, status);
+ return status;
+}
+
+/*
+ * ======== wait_for_start ========
+ * Wait for the singal from DSP that it has started, or time out.
+ */
+bool wait_for_start(struct bridge_dev_context *dev_context, u32 dw_sync_addr)
+{
+ u16 timeout = TIHELEN_ACKTIMEOUT;
+
+ /* Wait for response from board */
+ while (__raw_readw(dw_sync_addr) && --timeout)
+ udelay(10);
+
+ /* If timed out: return false */
+ if (!timeout) {
+ pr_err("%s: Timed out waiting DSP to Start\n", __func__);
+ return false;
+ }
+ return true;
+}
diff --git a/drivers/staging/tidspbridge/core/tiomap3430_pwr.c b/drivers/staging/tidspbridge/core/tiomap3430_pwr.c
new file mode 100644
index 00000000000..b789f8fdd89
--- /dev/null
+++ b/drivers/staging/tidspbridge/core/tiomap3430_pwr.c
@@ -0,0 +1,550 @@
+/*
+ * tiomap_pwr.c
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * Implementation of DSP wake/sleep routines.
+ *
+ * Copyright (C) 2007-2008 Texas Instruments, Inc.
+ *
+ * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+/* ----------------------------------- DSP/BIOS Bridge */
+#include <dspbridge/dbdefs.h>
+#include <dspbridge/cfg.h>
+#include <dspbridge/drv.h>
+#include <dspbridge/io_sm.h>
+
+/* ----------------------------------- Platform Manager */
+#include <dspbridge/brddefs.h>
+#include <dspbridge/dev.h>
+#include <dspbridge/iodefs.h>
+
+/* ------------------------------------ Hardware Abstraction Layer */
+#include <hw_defs.h>
+#include <hw_mmu.h>
+
+#include <dspbridge/pwr_sh.h>
+
+/* ----------------------------------- Bridge Driver */
+#include <dspbridge/dspdeh.h>
+#include <dspbridge/wdt.h>
+
+/* ----------------------------------- specific to this file */
+#include "_tiomap.h"
+#include "_tiomap_pwr.h"
+#include <mach-omap2/prm-regbits-34xx.h>
+#include <mach-omap2/cm-regbits-34xx.h>
+
+#define PWRSTST_TIMEOUT 200
+
+/*
+ * ======== handle_constraints_set ========
+ * Sets new DSP constraint
+ */
+int handle_constraints_set(struct bridge_dev_context *dev_context,
+ void *pargs)
+{
+#ifdef CONFIG_TIDSPBRIDGE_DVFS
+ u32 *constraint_val;
+ struct dspbridge_platform_data *pdata =
+ omap_dspbridge_dev->dev.platform_data;
+
+ constraint_val = (u32 *) (pargs);
+ /* Read the target value requested by DSP */
+ dev_dbg(bridge, "OPP: %s opp requested = 0x%x\n", __func__,
+ (u32) *(constraint_val + 1));
+
+ /* Set the new opp value */
+ if (pdata->dsp_set_min_opp)
+ (*pdata->dsp_set_min_opp) ((u32) *(constraint_val + 1));
+#endif /* #ifdef CONFIG_TIDSPBRIDGE_DVFS */
+ return 0;
+}
+
+/*
+ * ======== handle_hibernation_from_dsp ========
+ * Handle Hibernation requested from DSP
+ */
+int handle_hibernation_from_dsp(struct bridge_dev_context *dev_context)
+{
+ int status = 0;
+#ifdef CONFIG_PM
+ u16 timeout = PWRSTST_TIMEOUT / 10;
+ u32 pwr_state;
+#ifdef CONFIG_TIDSPBRIDGE_DVFS
+ u32 opplevel;
+ struct io_mgr *hio_mgr;
+#endif
+ struct dspbridge_platform_data *pdata =
+ omap_dspbridge_dev->dev.platform_data;
+
+ pwr_state = (*pdata->dsp_prm_read)(OMAP3430_IVA2_MOD, OMAP2_PM_PWSTST) &
+ OMAP_POWERSTATEST_MASK;
+ /* Wait for DSP to move into OFF state */
+ while ((pwr_state != PWRDM_POWER_OFF) && --timeout) {
+ if (msleep_interruptible(10)) {
+ pr_err("Waiting for DSP OFF mode interrupted\n");
+ return -EPERM;
+ }
+ pwr_state = (*pdata->dsp_prm_read)(OMAP3430_IVA2_MOD,
+ OMAP2_PM_PWSTST) & OMAP_POWERSTATEST_MASK;
+ }
+ if (timeout == 0) {
+ pr_err("%s: Timed out waiting for DSP off mode\n", __func__);
+ status = -ETIMEDOUT;
+ return status;
+ } else {
+
+ /* Save mailbox settings */
+ omap_mbox_save_ctx(dev_context->mbox);
+
+ /* Turn off DSP Peripheral clocks and DSP Load monitor timer */
+ status = dsp_clock_disable_all(dev_context->dsp_per_clks);
+
+ /* Disable wdt on hibernation. */
+ dsp_wdt_enable(false);
+
+ if (!status) {
+ /* Update the Bridger Driver state */
+ dev_context->dw_brd_state = BRD_DSP_HIBERNATION;
+#ifdef CONFIG_TIDSPBRIDGE_DVFS
+ status =
+ dev_get_io_mgr(dev_context->hdev_obj, &hio_mgr);
+ if (!hio_mgr) {
+ status = DSP_EHANDLE;
+ return status;
+ }
+ io_sh_msetting(hio_mgr, SHM_GETOPP, &opplevel);
+
+ /*
+ * Set the OPP to low level before moving to OFF
+ * mode
+ */
+ if (pdata->dsp_set_min_opp)
+ (*pdata->dsp_set_min_opp) (VDD1_OPP1);
+ status = 0;
+#endif /* CONFIG_TIDSPBRIDGE_DVFS */
+ }
+ }
+#endif
+ return status;
+}
+
+/*
+ * ======== sleep_dsp ========
+ * Put DSP in low power consuming state.
+ */
+int sleep_dsp(struct bridge_dev_context *dev_context, u32 dw_cmd,
+ void *pargs)
+{
+ int status = 0;
+#ifdef CONFIG_PM
+#ifdef CONFIG_TIDSPBRIDGE_NTFY_PWRERR
+ struct deh_mgr *hdeh_mgr;
+#endif /* CONFIG_TIDSPBRIDGE_NTFY_PWRERR */
+ u16 timeout = PWRSTST_TIMEOUT / 10;
+ u32 pwr_state, target_pwr_state;
+ struct dspbridge_platform_data *pdata =
+ omap_dspbridge_dev->dev.platform_data;
+
+ /* Check if sleep code is valid */
+ if ((dw_cmd != PWR_DEEPSLEEP) && (dw_cmd != PWR_EMERGENCYDEEPSLEEP))
+ return -EINVAL;
+
+ switch (dev_context->dw_brd_state) {
+ case BRD_RUNNING:
+ omap_mbox_save_ctx(dev_context->mbox);
+ if (dsp_test_sleepstate == PWRDM_POWER_OFF) {
+ sm_interrupt_dsp(dev_context, MBX_PM_DSPHIBERNATE);
+ dev_dbg(bridge, "PM: %s - sent hibernate cmd to DSP\n",
+ __func__);
+ target_pwr_state = PWRDM_POWER_OFF;
+ } else {
+ sm_interrupt_dsp(dev_context, MBX_PM_DSPRETENTION);
+ target_pwr_state = PWRDM_POWER_RET;
+ }
+ break;
+ case BRD_RETENTION:
+ omap_mbox_save_ctx(dev_context->mbox);
+ if (dsp_test_sleepstate == PWRDM_POWER_OFF) {
+ sm_interrupt_dsp(dev_context, MBX_PM_DSPHIBERNATE);
+ target_pwr_state = PWRDM_POWER_OFF;
+ } else
+ return 0;
+ break;
+ case BRD_HIBERNATION:
+ case BRD_DSP_HIBERNATION:
+ /* Already in Hibernation, so just return */
+ dev_dbg(bridge, "PM: %s - DSP already in hibernation\n",
+ __func__);
+ return 0;
+ case BRD_STOPPED:
+ dev_dbg(bridge, "PM: %s - Board in STOP state\n", __func__);
+ return 0;
+ default:
+ dev_dbg(bridge, "PM: %s - Bridge in Illegal state\n", __func__);
+ return -EPERM;
+ }
+
+ /* Get the PRCM DSP power domain status */
+ pwr_state = (*pdata->dsp_prm_read)(OMAP3430_IVA2_MOD, OMAP2_PM_PWSTST) &
+ OMAP_POWERSTATEST_MASK;
+
+ /* Wait for DSP to move into target power state */
+ while ((pwr_state != target_pwr_state) && --timeout) {
+ if (msleep_interruptible(10)) {
+ pr_err("Waiting for DSP to Suspend interrupted\n");
+ return -EPERM;
+ }
+ pwr_state = (*pdata->dsp_prm_read)(OMAP3430_IVA2_MOD,
+ OMAP2_PM_PWSTST) & OMAP_POWERSTATEST_MASK;
+ }
+
+ if (!timeout) {
+ pr_err("%s: Timed out waiting for DSP off mode, state %x\n",
+ __func__, pwr_state);
+#ifdef CONFIG_TIDSPBRIDGE_NTFY_PWRERR
+ dev_get_deh_mgr(dev_context->hdev_obj, &hdeh_mgr);
+ bridge_deh_notify(hdeh_mgr, DSP_PWRERROR, 0);
+#endif /* CONFIG_TIDSPBRIDGE_NTFY_PWRERR */
+ return -ETIMEDOUT;
+ } else {
+ /* Update the Bridger Driver state */
+ if (dsp_test_sleepstate == PWRDM_POWER_OFF)
+ dev_context->dw_brd_state = BRD_HIBERNATION;
+ else
+ dev_context->dw_brd_state = BRD_RETENTION;
+
+ /* Disable wdt on hibernation. */
+ dsp_wdt_enable(false);
+
+ /* Turn off DSP Peripheral clocks */
+ status = dsp_clock_disable_all(dev_context->dsp_per_clks);
+ if (status)
+ return status;
+#ifdef CONFIG_TIDSPBRIDGE_DVFS
+ else if (target_pwr_state == PWRDM_POWER_OFF) {
+ /*
+ * Set the OPP to low level before moving to OFF mode
+ */
+ if (pdata->dsp_set_min_opp)
+ (*pdata->dsp_set_min_opp) (VDD1_OPP1);
+ }
+#endif /* CONFIG_TIDSPBRIDGE_DVFS */
+ }
+#endif /* CONFIG_PM */
+ return status;
+}
+
+/*
+ * ======== wake_dsp ========
+ * Wake up DSP from sleep.
+ */
+int wake_dsp(struct bridge_dev_context *dev_context, void *pargs)
+{
+ int status = 0;
+#ifdef CONFIG_PM
+
+ /* Check the board state, if it is not 'SLEEP' then return */
+ if (dev_context->dw_brd_state == BRD_RUNNING ||
+ dev_context->dw_brd_state == BRD_STOPPED) {
+ /* The Device is in 'RET' or 'OFF' state and Bridge state is not
+ * 'SLEEP', this means state inconsistency, so return */
+ return 0;
+ }
+
+ /* Send a wakeup message to DSP */
+ sm_interrupt_dsp(dev_context, MBX_PM_DSPWAKEUP);
+
+ /* Set the device state to RUNNIG */
+ dev_context->dw_brd_state = BRD_RUNNING;
+#endif /* CONFIG_PM */
+ return status;
+}
+
+/*
+ * ======== dsp_peripheral_clk_ctrl ========
+ * Enable/Disable the DSP peripheral clocks as needed..
+ */
+int dsp_peripheral_clk_ctrl(struct bridge_dev_context *dev_context,
+ void *pargs)
+{
+ u32 ext_clk = 0;
+ u32 ext_clk_id = 0;
+ u32 ext_clk_cmd = 0;
+ u32 clk_id_index = MBX_PM_MAX_RESOURCES;
+ u32 tmp_index;
+ u32 dsp_per_clks_before;
+ int status = 0;
+
+ dsp_per_clks_before = dev_context->dsp_per_clks;
+
+ ext_clk = (u32) *((u32 *) pargs);
+ ext_clk_id = ext_clk & MBX_PM_CLK_IDMASK;
+
+ /* process the power message -- TODO, keep it in a separate function */
+ for (tmp_index = 0; tmp_index < MBX_PM_MAX_RESOURCES; tmp_index++) {
+ if (ext_clk_id == bpwr_clkid[tmp_index]) {
+ clk_id_index = tmp_index;
+ break;
+ }
+ }
+ /* TODO -- Assert may be a too hard restriction here.. May be we should
+ * just return with failure when the CLK ID does not match */
+ /* DBC_ASSERT(clk_id_index < MBX_PM_MAX_RESOURCES); */
+ if (clk_id_index == MBX_PM_MAX_RESOURCES) {
+ /* return with a more meaningfull error code */
+ return -EPERM;
+ }
+ ext_clk_cmd = (ext_clk >> MBX_PM_CLK_CMDSHIFT) & MBX_PM_CLK_CMDMASK;
+ switch (ext_clk_cmd) {
+ case BPWR_DISABLE_CLOCK:
+ status = dsp_clk_disable(bpwr_clks[clk_id_index].clk);
+ dsp_clk_wakeup_event_ctrl(bpwr_clks[clk_id_index].clk_id,
+ false);
+ if (!status) {
+ (dev_context->dsp_per_clks) &=
+ (~((u32) (1 << bpwr_clks[clk_id_index].clk)));
+ }
+ break;
+ case BPWR_ENABLE_CLOCK:
+ status = dsp_clk_enable(bpwr_clks[clk_id_index].clk);
+ dsp_clk_wakeup_event_ctrl(bpwr_clks[clk_id_index].clk_id, true);
+ if (!status)
+ (dev_context->dsp_per_clks) |=
+ (1 << bpwr_clks[clk_id_index].clk);
+ break;
+ default:
+ dev_dbg(bridge, "%s: Unsupported CMD\n", __func__);
+ /* unsupported cmd */
+ /* TODO -- provide support for AUTOIDLE Enable/Disable
+ * commands */
+ }
+ return status;
+}
+
+/*
+ * ========pre_scale_dsp========
+ * Sends prescale notification to DSP
+ *
+ */
+int pre_scale_dsp(struct bridge_dev_context *dev_context, void *pargs)
+{
+#ifdef CONFIG_TIDSPBRIDGE_DVFS
+ u32 level;
+ u32 voltage_domain;
+
+ voltage_domain = *((u32 *) pargs);
+ level = *((u32 *) pargs + 1);
+
+ dev_dbg(bridge, "OPP: %s voltage_domain = %x, level = 0x%x\n",
+ __func__, voltage_domain, level);
+ if ((dev_context->dw_brd_state == BRD_HIBERNATION) ||
+ (dev_context->dw_brd_state == BRD_RETENTION) ||
+ (dev_context->dw_brd_state == BRD_DSP_HIBERNATION)) {
+ dev_dbg(bridge, "OPP: %s IVA in sleep. No message to DSP\n");
+ return 0;
+ } else if ((dev_context->dw_brd_state == BRD_RUNNING)) {
+ /* Send a prenotificatio to DSP */
+ dev_dbg(bridge, "OPP: %s sent notification to DSP\n", __func__);
+ sm_interrupt_dsp(dev_context, MBX_PM_SETPOINT_PRENOTIFY);
+ return 0;
+ } else {
+ return -EPERM;
+ }
+#endif /* #ifdef CONFIG_TIDSPBRIDGE_DVFS */
+ return 0;
+}
+
+/*
+ * ========post_scale_dsp========
+ * Sends postscale notification to DSP
+ *
+ */
+int post_scale_dsp(struct bridge_dev_context *dev_context,
+ void *pargs)
+{
+ int status = 0;
+#ifdef CONFIG_TIDSPBRIDGE_DVFS
+ u32 level;
+ u32 voltage_domain;
+ struct io_mgr *hio_mgr;
+
+ status = dev_get_io_mgr(dev_context->hdev_obj, &hio_mgr);
+ if (!hio_mgr)
+ return -EFAULT;
+
+ voltage_domain = *((u32 *) pargs);
+ level = *((u32 *) pargs + 1);
+ dev_dbg(bridge, "OPP: %s voltage_domain = %x, level = 0x%x\n",
+ __func__, voltage_domain, level);
+ if ((dev_context->dw_brd_state == BRD_HIBERNATION) ||
+ (dev_context->dw_brd_state == BRD_RETENTION) ||
+ (dev_context->dw_brd_state == BRD_DSP_HIBERNATION)) {
+ /* Update the OPP value in shared memory */
+ io_sh_msetting(hio_mgr, SHM_CURROPP, &level);
+ dev_dbg(bridge, "OPP: %s IVA in sleep. Wrote to shm\n",
+ __func__);
+ } else if ((dev_context->dw_brd_state == BRD_RUNNING)) {
+ /* Update the OPP value in shared memory */
+ io_sh_msetting(hio_mgr, SHM_CURROPP, &level);
+ /* Send a post notification to DSP */
+ sm_interrupt_dsp(dev_context, MBX_PM_SETPOINT_POSTNOTIFY);
+ dev_dbg(bridge, "OPP: %s wrote to shm. Sent post notification "
+ "to DSP\n", __func__);
+ } else {
+ status = -EPERM;
+ }
+#endif /* #ifdef CONFIG_TIDSPBRIDGE_DVFS */
+ return status;
+}
+
+void dsp_clk_wakeup_event_ctrl(u32 clock_id, bool enable)
+{
+ struct cfg_hostres *resources;
+ int status = 0;
+ u32 iva2_grpsel;
+ u32 mpu_grpsel;
+ struct dev_object *hdev_object = NULL;
+ struct bridge_dev_context *bridge_context = NULL;
+
+ hdev_object = (struct dev_object *)drv_get_first_dev_object();
+ if (!hdev_object)
+ return;
+
+ status = dev_get_bridge_context(hdev_object, &bridge_context);
+ if (!bridge_context)
+ return;
+
+ resources = bridge_context->resources;
+ if (!resources)
+ return;
+
+ switch (clock_id) {
+ case BPWR_GP_TIMER5:
+ iva2_grpsel = readl(resources->dw_per_pm_base + 0xA8);
+ mpu_grpsel = readl(resources->dw_per_pm_base + 0xA4);
+ if (enable) {
+ iva2_grpsel |= OMAP3430_GRPSEL_GPT5_MASK;
+ mpu_grpsel &= ~OMAP3430_GRPSEL_GPT5_MASK;
+ } else {
+ mpu_grpsel |= OMAP3430_GRPSEL_GPT5_MASK;
+ iva2_grpsel &= ~OMAP3430_GRPSEL_GPT5_MASK;
+ }
+ writel(iva2_grpsel, resources->dw_per_pm_base + 0xA8);
+ writel(mpu_grpsel, resources->dw_per_pm_base + 0xA4);
+ break;
+ case BPWR_GP_TIMER6:
+ iva2_grpsel = readl(resources->dw_per_pm_base + 0xA8);
+ mpu_grpsel = readl(resources->dw_per_pm_base + 0xA4);
+ if (enable) {
+ iva2_grpsel |= OMAP3430_GRPSEL_GPT6_MASK;
+ mpu_grpsel &= ~OMAP3430_GRPSEL_GPT6_MASK;
+ } else {
+ mpu_grpsel |= OMAP3430_GRPSEL_GPT6_MASK;
+ iva2_grpsel &= ~OMAP3430_GRPSEL_GPT6_MASK;
+ }
+ writel(iva2_grpsel, resources->dw_per_pm_base + 0xA8);
+ writel(mpu_grpsel, resources->dw_per_pm_base + 0xA4);
+ break;
+ case BPWR_GP_TIMER7:
+ iva2_grpsel = readl(resources->dw_per_pm_base + 0xA8);
+ mpu_grpsel = readl(resources->dw_per_pm_base + 0xA4);
+ if (enable) {
+ iva2_grpsel |= OMAP3430_GRPSEL_GPT7_MASK;
+ mpu_grpsel &= ~OMAP3430_GRPSEL_GPT7_MASK;
+ } else {
+ mpu_grpsel |= OMAP3430_GRPSEL_GPT7_MASK;
+ iva2_grpsel &= ~OMAP3430_GRPSEL_GPT7_MASK;
+ }
+ writel(iva2_grpsel, resources->dw_per_pm_base + 0xA8);
+ writel(mpu_grpsel, resources->dw_per_pm_base + 0xA4);
+ break;
+ case BPWR_GP_TIMER8:
+ iva2_grpsel = readl(resources->dw_per_pm_base + 0xA8);
+ mpu_grpsel = readl(resources->dw_per_pm_base + 0xA4);
+ if (enable) {
+ iva2_grpsel |= OMAP3430_GRPSEL_GPT8_MASK;
+ mpu_grpsel &= ~OMAP3430_GRPSEL_GPT8_MASK;
+ } else {
+ mpu_grpsel |= OMAP3430_GRPSEL_GPT8_MASK;
+ iva2_grpsel &= ~OMAP3430_GRPSEL_GPT8_MASK;
+ }
+ writel(iva2_grpsel, resources->dw_per_pm_base + 0xA8);
+ writel(mpu_grpsel, resources->dw_per_pm_base + 0xA4);
+ break;
+ case BPWR_MCBSP1:
+ iva2_grpsel = readl(resources->dw_core_pm_base + 0xA8);
+ mpu_grpsel = readl(resources->dw_core_pm_base + 0xA4);
+ if (enable) {
+ iva2_grpsel |= OMAP3430_GRPSEL_MCBSP1_MASK;
+ mpu_grpsel &= ~OMAP3430_GRPSEL_MCBSP1_MASK;
+ } else {
+ mpu_grpsel |= OMAP3430_GRPSEL_MCBSP1_MASK;
+ iva2_grpsel &= ~OMAP3430_GRPSEL_MCBSP1_MASK;
+ }
+ writel(iva2_grpsel, resources->dw_core_pm_base + 0xA8);
+ writel(mpu_grpsel, resources->dw_core_pm_base + 0xA4);
+ break;
+ case BPWR_MCBSP2:
+ iva2_grpsel = readl(resources->dw_per_pm_base + 0xA8);
+ mpu_grpsel = readl(resources->dw_per_pm_base + 0xA4);
+ if (enable) {
+ iva2_grpsel |= OMAP3430_GRPSEL_MCBSP2_MASK;
+ mpu_grpsel &= ~OMAP3430_GRPSEL_MCBSP2_MASK;
+ } else {
+ mpu_grpsel |= OMAP3430_GRPSEL_MCBSP2_MASK;
+ iva2_grpsel &= ~OMAP3430_GRPSEL_MCBSP2_MASK;
+ }
+ writel(iva2_grpsel, resources->dw_per_pm_base + 0xA8);
+ writel(mpu_grpsel, resources->dw_per_pm_base + 0xA4);
+ break;
+ case BPWR_MCBSP3:
+ iva2_grpsel = readl(resources->dw_per_pm_base + 0xA8);
+ mpu_grpsel = readl(resources->dw_per_pm_base + 0xA4);
+ if (enable) {
+ iva2_grpsel |= OMAP3430_GRPSEL_MCBSP3_MASK;
+ mpu_grpsel &= ~OMAP3430_GRPSEL_MCBSP3_MASK;
+ } else {
+ mpu_grpsel |= OMAP3430_GRPSEL_MCBSP3_MASK;
+ iva2_grpsel &= ~OMAP3430_GRPSEL_MCBSP3_MASK;
+ }
+ writel(iva2_grpsel, resources->dw_per_pm_base + 0xA8);
+ writel(mpu_grpsel, resources->dw_per_pm_base + 0xA4);
+ break;
+ case BPWR_MCBSP4:
+ iva2_grpsel = readl(resources->dw_per_pm_base + 0xA8);
+ mpu_grpsel = readl(resources->dw_per_pm_base + 0xA4);
+ if (enable) {
+ iva2_grpsel |= OMAP3430_GRPSEL_MCBSP4_MASK;
+ mpu_grpsel &= ~OMAP3430_GRPSEL_MCBSP4_MASK;
+ } else {
+ mpu_grpsel |= OMAP3430_GRPSEL_MCBSP4_MASK;
+ iva2_grpsel &= ~OMAP3430_GRPSEL_MCBSP4_MASK;
+ }
+ writel(iva2_grpsel, resources->dw_per_pm_base + 0xA8);
+ writel(mpu_grpsel, resources->dw_per_pm_base + 0xA4);
+ break;
+ case BPWR_MCBSP5:
+ iva2_grpsel = readl(resources->dw_per_pm_base + 0xA8);
+ mpu_grpsel = readl(resources->dw_per_pm_base + 0xA4);
+ if (enable) {
+ iva2_grpsel |= OMAP3430_GRPSEL_MCBSP5_MASK;
+ mpu_grpsel &= ~OMAP3430_GRPSEL_MCBSP5_MASK;
+ } else {
+ mpu_grpsel |= OMAP3430_GRPSEL_MCBSP5_MASK;
+ iva2_grpsel &= ~OMAP3430_GRPSEL_MCBSP5_MASK;
+ }
+ writel(iva2_grpsel, resources->dw_per_pm_base + 0xA8);
+ writel(mpu_grpsel, resources->dw_per_pm_base + 0xA4);
+ break;
+ }
+}
diff --git a/drivers/staging/tidspbridge/core/tiomap_io.c b/drivers/staging/tidspbridge/core/tiomap_io.c
new file mode 100644
index 00000000000..190c028afe9
--- /dev/null
+++ b/drivers/staging/tidspbridge/core/tiomap_io.c
@@ -0,0 +1,455 @@
+/*
+ * tiomap_io.c
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * Implementation for the io read/write routines.
+ *
+ * Copyright (C) 2005-2006 Texas Instruments, Inc.
+ *
+ * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+/* ----------------------------------- DSP/BIOS Bridge */
+#include <dspbridge/dbdefs.h>
+
+/* ----------------------------------- Trace & Debug */
+#include <dspbridge/dbc.h>
+
+/* ----------------------------------- Platform Manager */
+#include <dspbridge/dev.h>
+#include <dspbridge/drv.h>
+
+/* ----------------------------------- OS Adaptation Layer */
+#include <dspbridge/cfg.h>
+#include <dspbridge/wdt.h>
+
+/* ----------------------------------- specific to this file */
+#include "_tiomap.h"
+#include "_tiomap_pwr.h"
+#include "tiomap_io.h"
+
+static u32 ul_ext_base;
+static u32 ul_ext_end;
+
+static u32 shm0_end;
+static u32 ul_dyn_ext_base;
+static u32 ul_trace_sec_beg;
+static u32 ul_trace_sec_end;
+static u32 ul_shm_base_virt;
+
+bool symbols_reloaded = true;
+
+/*
+ * ======== read_ext_dsp_data ========
+ * Copies DSP external memory buffers to the host side buffers.
+ */
+int read_ext_dsp_data(struct bridge_dev_context *dev_ctxt,
+ u8 *host_buff, u32 dsp_addr,
+ u32 ul_num_bytes, u32 mem_type)
+{
+ int status = 0;
+ struct bridge_dev_context *dev_context = dev_ctxt;
+ u32 offset;
+ u32 ul_tlb_base_virt = 0;
+ u32 ul_shm_offset_virt = 0;
+ u32 dw_ext_prog_virt_mem;
+ u32 dw_base_addr = dev_context->dw_dsp_ext_base_addr;
+ bool trace_read = false;
+
+ if (!ul_shm_base_virt) {
+ status = dev_get_symbol(dev_context->hdev_obj,
+ SHMBASENAME, &ul_shm_base_virt);
+ }
+ DBC_ASSERT(ul_shm_base_virt != 0);
+
+ /* Check if it is a read of Trace section */
+ if (!status && !ul_trace_sec_beg) {
+ status = dev_get_symbol(dev_context->hdev_obj,
+ DSP_TRACESEC_BEG, &ul_trace_sec_beg);
+ }
+ DBC_ASSERT(ul_trace_sec_beg != 0);
+
+ if (!status && !ul_trace_sec_end) {
+ status = dev_get_symbol(dev_context->hdev_obj,
+ DSP_TRACESEC_END, &ul_trace_sec_end);
+ }
+ DBC_ASSERT(ul_trace_sec_end != 0);
+
+ if (!status) {
+ if ((dsp_addr <= ul_trace_sec_end) &&
+ (dsp_addr >= ul_trace_sec_beg))
+ trace_read = true;
+ }
+
+ /* If reading from TRACE, force remap/unmap */
+ if (trace_read && dw_base_addr) {
+ dw_base_addr = 0;
+ dev_context->dw_dsp_ext_base_addr = 0;
+ }
+
+ if (!dw_base_addr) {
+ /* Initialize ul_ext_base and ul_ext_end */
+ ul_ext_base = 0;
+ ul_ext_end = 0;
+
+ /* Get DYNEXT_BEG, EXT_BEG and EXT_END. */
+ if (!status && !ul_dyn_ext_base) {
+ status = dev_get_symbol(dev_context->hdev_obj,
+ DYNEXTBASE, &ul_dyn_ext_base);
+ }
+ DBC_ASSERT(ul_dyn_ext_base != 0);
+
+ if (!status) {
+ status = dev_get_symbol(dev_context->hdev_obj,
+ EXTBASE, &ul_ext_base);
+ }
+ DBC_ASSERT(ul_ext_base != 0);
+
+ if (!status) {
+ status = dev_get_symbol(dev_context->hdev_obj,
+ EXTEND, &ul_ext_end);
+ }
+ DBC_ASSERT(ul_ext_end != 0);
+
+ /* Trace buffer is right after the shm SEG0,
+ * so set the base address to SHMBASE */
+ if (trace_read) {
+ ul_ext_base = ul_shm_base_virt;
+ ul_ext_end = ul_trace_sec_end;
+ }
+
+ DBC_ASSERT(ul_ext_end != 0);
+ DBC_ASSERT(ul_ext_end > ul_ext_base);
+
+ if (ul_ext_end < ul_ext_base)
+ status = -EPERM;
+
+ if (!status) {
+ ul_tlb_base_virt =
+ dev_context->atlb_entry[0].ul_dsp_va * DSPWORDSIZE;
+ DBC_ASSERT(ul_tlb_base_virt <= ul_shm_base_virt);
+ dw_ext_prog_virt_mem =
+ dev_context->atlb_entry[0].ul_gpp_va;
+
+ if (!trace_read) {
+ ul_shm_offset_virt =
+ ul_shm_base_virt - ul_tlb_base_virt;
+ ul_shm_offset_virt +=
+ PG_ALIGN_HIGH(ul_ext_end - ul_dyn_ext_base +
+ 1, HW_PAGE_SIZE64KB);
+ dw_ext_prog_virt_mem -= ul_shm_offset_virt;
+ dw_ext_prog_virt_mem +=
+ (ul_ext_base - ul_dyn_ext_base);
+ dev_context->dw_dsp_ext_base_addr =
+ dw_ext_prog_virt_mem;
+
+ /*
+ * This dw_dsp_ext_base_addr will get cleared
+ * only when the board is stopped.
+ */
+ if (!dev_context->dw_dsp_ext_base_addr)
+ status = -EPERM;
+ }
+
+ dw_base_addr = dw_ext_prog_virt_mem;
+ }
+ }
+
+ if (!dw_base_addr || !ul_ext_base || !ul_ext_end)
+ status = -EPERM;
+
+ offset = dsp_addr - ul_ext_base;
+
+ if (!status)
+ memcpy(host_buff, (u8 *) dw_base_addr + offset, ul_num_bytes);
+
+ return status;
+}
+
+/*
+ * ======== write_dsp_data ========
+ * purpose:
+ * Copies buffers to the DSP internal/external memory.
+ */
+int write_dsp_data(struct bridge_dev_context *dev_context,
+ u8 *host_buff, u32 dsp_addr, u32 ul_num_bytes,
+ u32 mem_type)
+{
+ u32 offset;
+ u32 dw_base_addr = dev_context->dw_dsp_base_addr;
+ struct cfg_hostres *resources = dev_context->resources;
+ int status = 0;
+ u32 base1, base2, base3;
+ base1 = OMAP_DSP_MEM1_SIZE;
+ base2 = OMAP_DSP_MEM2_BASE - OMAP_DSP_MEM1_BASE;
+ base3 = OMAP_DSP_MEM3_BASE - OMAP_DSP_MEM1_BASE;
+
+ if (!resources)
+ return -EPERM;
+
+ offset = dsp_addr - dev_context->dw_dsp_start_add;
+ if (offset < base1) {
+ dw_base_addr = MEM_LINEAR_ADDRESS(resources->dw_mem_base[2],
+ resources->dw_mem_length[2]);
+ } else if (offset > base1 && offset < base2 + OMAP_DSP_MEM2_SIZE) {
+ dw_base_addr = MEM_LINEAR_ADDRESS(resources->dw_mem_base[3],
+ resources->dw_mem_length[3]);
+ offset = offset - base2;
+ } else if (offset >= base2 + OMAP_DSP_MEM2_SIZE &&
+ offset < base3 + OMAP_DSP_MEM3_SIZE) {
+ dw_base_addr = MEM_LINEAR_ADDRESS(resources->dw_mem_base[4],
+ resources->dw_mem_length[4]);
+ offset = offset - base3;
+ } else {
+ return -EPERM;
+ }
+ if (ul_num_bytes)
+ memcpy((u8 *) (dw_base_addr + offset), host_buff, ul_num_bytes);
+ else
+ *((u32 *) host_buff) = dw_base_addr + offset;
+
+ return status;
+}
+
+/*
+ * ======== write_ext_dsp_data ========
+ * purpose:
+ * Copies buffers to the external memory.
+ *
+ */
+int write_ext_dsp_data(struct bridge_dev_context *dev_context,
+ u8 *host_buff, u32 dsp_addr,
+ u32 ul_num_bytes, u32 mem_type,
+ bool dynamic_load)
+{
+ u32 dw_base_addr = dev_context->dw_dsp_ext_base_addr;
+ u32 dw_offset = 0;
+ u8 temp_byte1, temp_byte2;
+ u8 remain_byte[4];
+ s32 i;
+ int ret = 0;
+ u32 dw_ext_prog_virt_mem;
+ u32 ul_tlb_base_virt = 0;
+ u32 ul_shm_offset_virt = 0;
+ struct cfg_hostres *host_res = dev_context->resources;
+ bool trace_load = false;
+ temp_byte1 = 0x0;
+ temp_byte2 = 0x0;
+
+ if (symbols_reloaded) {
+ /* Check if it is a load to Trace section */
+ ret = dev_get_symbol(dev_context->hdev_obj,
+ DSP_TRACESEC_BEG, &ul_trace_sec_beg);
+ if (!ret)
+ ret = dev_get_symbol(dev_context->hdev_obj,
+ DSP_TRACESEC_END,
+ &ul_trace_sec_end);
+ }
+ if (!ret) {
+ if ((dsp_addr <= ul_trace_sec_end) &&
+ (dsp_addr >= ul_trace_sec_beg))
+ trace_load = true;
+ }
+
+ /* If dynamic, force remap/unmap */
+ if ((dynamic_load || trace_load) && dw_base_addr) {
+ dw_base_addr = 0;
+ MEM_UNMAP_LINEAR_ADDRESS((void *)
+ dev_context->dw_dsp_ext_base_addr);
+ dev_context->dw_dsp_ext_base_addr = 0x0;
+ }
+ if (!dw_base_addr) {
+ if (symbols_reloaded)
+ /* Get SHM_BEG EXT_BEG and EXT_END. */
+ ret = dev_get_symbol(dev_context->hdev_obj,
+ SHMBASENAME, &ul_shm_base_virt);
+ DBC_ASSERT(ul_shm_base_virt != 0);
+ if (dynamic_load) {
+ if (!ret) {
+ if (symbols_reloaded)
+ ret =
+ dev_get_symbol
+ (dev_context->hdev_obj, DYNEXTBASE,
+ &ul_ext_base);
+ }
+ DBC_ASSERT(ul_ext_base != 0);
+ if (!ret) {
+ /* DR OMAPS00013235 : DLModules array may be
+ * in EXTMEM. It is expected that DYNEXTMEM and
+ * EXTMEM are contiguous, so checking for the
+ * upper bound at EXTEND should be Ok. */
+ if (symbols_reloaded)
+ ret =
+ dev_get_symbol
+ (dev_context->hdev_obj, EXTEND,
+ &ul_ext_end);
+ }
+ } else {
+ if (symbols_reloaded) {
+ if (!ret)
+ ret =
+ dev_get_symbol
+ (dev_context->hdev_obj, EXTBASE,
+ &ul_ext_base);
+ DBC_ASSERT(ul_ext_base != 0);
+ if (!ret)
+ ret =
+ dev_get_symbol
+ (dev_context->hdev_obj, EXTEND,
+ &ul_ext_end);
+ }
+ }
+ /* Trace buffer it right after the shm SEG0, so set the
+ * base address to SHMBASE */
+ if (trace_load)
+ ul_ext_base = ul_shm_base_virt;
+
+ DBC_ASSERT(ul_ext_end != 0);
+ DBC_ASSERT(ul_ext_end > ul_ext_base);
+ if (ul_ext_end < ul_ext_base)
+ ret = -EPERM;
+
+ if (!ret) {
+ ul_tlb_base_virt =
+ dev_context->atlb_entry[0].ul_dsp_va * DSPWORDSIZE;
+ DBC_ASSERT(ul_tlb_base_virt <= ul_shm_base_virt);
+
+ if (symbols_reloaded) {
+ ret = dev_get_symbol
+ (dev_context->hdev_obj,
+ DSP_TRACESEC_END, &shm0_end);
+ if (!ret) {
+ ret =
+ dev_get_symbol
+ (dev_context->hdev_obj, DYNEXTBASE,
+ &ul_dyn_ext_base);
+ }
+ }
+ ul_shm_offset_virt =
+ ul_shm_base_virt - ul_tlb_base_virt;
+ if (trace_load) {
+ dw_ext_prog_virt_mem =
+ dev_context->atlb_entry[0].ul_gpp_va;
+ } else {
+ dw_ext_prog_virt_mem = host_res->dw_mem_base[1];
+ dw_ext_prog_virt_mem +=
+ (ul_ext_base - ul_dyn_ext_base);
+ }
+
+ dev_context->dw_dsp_ext_base_addr =
+ (u32) MEM_LINEAR_ADDRESS((void *)
+ dw_ext_prog_virt_mem,
+ ul_ext_end - ul_ext_base);
+ dw_base_addr += dev_context->dw_dsp_ext_base_addr;
+ /* This dw_dsp_ext_base_addr will get cleared only when
+ * the board is stopped. */
+ if (!dev_context->dw_dsp_ext_base_addr)
+ ret = -EPERM;
+ }
+ }
+ if (!dw_base_addr || !ul_ext_base || !ul_ext_end)
+ ret = -EPERM;
+
+ if (!ret) {
+ for (i = 0; i < 4; i++)
+ remain_byte[i] = 0x0;
+
+ dw_offset = dsp_addr - ul_ext_base;
+ /* Also make sure the dsp_addr is < ul_ext_end */
+ if (dsp_addr > ul_ext_end || dw_offset > dsp_addr)
+ ret = -EPERM;
+ }
+ if (!ret) {
+ if (ul_num_bytes)
+ memcpy((u8 *) dw_base_addr + dw_offset, host_buff,
+ ul_num_bytes);
+ else
+ *((u32 *) host_buff) = dw_base_addr + dw_offset;
+ }
+ /* Unmap here to force remap for other Ext loads */
+ if ((dynamic_load || trace_load) && dev_context->dw_dsp_ext_base_addr) {
+ MEM_UNMAP_LINEAR_ADDRESS((void *)
+ dev_context->dw_dsp_ext_base_addr);
+ dev_context->dw_dsp_ext_base_addr = 0x0;
+ }
+ symbols_reloaded = false;
+ return ret;
+}
+
+int sm_interrupt_dsp(struct bridge_dev_context *dev_context, u16 mb_val)
+{
+#ifdef CONFIG_TIDSPBRIDGE_DVFS
+ u32 opplevel = 0;
+#endif
+ struct dspbridge_platform_data *pdata =
+ omap_dspbridge_dev->dev.platform_data;
+ struct cfg_hostres *resources = dev_context->resources;
+ int status = 0;
+ u32 temp;
+
+ if (!dev_context->mbox)
+ return 0;
+
+ if (!resources)
+ return -EPERM;
+
+ if (dev_context->dw_brd_state == BRD_DSP_HIBERNATION ||
+ dev_context->dw_brd_state == BRD_HIBERNATION) {
+#ifdef CONFIG_TIDSPBRIDGE_DVFS
+ if (pdata->dsp_get_opp)
+ opplevel = (*pdata->dsp_get_opp) ();
+ if (opplevel == VDD1_OPP1) {
+ if (pdata->dsp_set_min_opp)
+ (*pdata->dsp_set_min_opp) (VDD1_OPP2);
+ }
+#endif
+ /* Restart the peripheral clocks */
+ dsp_clock_enable_all(dev_context->dsp_per_clks);
+ dsp_wdt_enable(true);
+
+ /*
+ * 2:0 AUTO_IVA2_DPLL - Enabling IVA2 DPLL auto control
+ * in CM_AUTOIDLE_PLL_IVA2 register
+ */
+ (*pdata->dsp_cm_write)(1 << OMAP3430_AUTO_IVA2_DPLL_SHIFT,
+ OMAP3430_IVA2_MOD, OMAP3430_CM_AUTOIDLE_PLL);
+
+ /*
+ * 7:4 IVA2_DPLL_FREQSEL - IVA2 internal frq set to
+ * 0.75 MHz - 1.0 MHz
+ * 2:0 EN_IVA2_DPLL - Enable IVA2 DPLL in lock mode
+ */
+ (*pdata->dsp_cm_rmw_bits)(OMAP3430_IVA2_DPLL_FREQSEL_MASK |
+ OMAP3430_EN_IVA2_DPLL_MASK,
+ 0x3 << OMAP3430_IVA2_DPLL_FREQSEL_SHIFT |
+ 0x7 << OMAP3430_EN_IVA2_DPLL_SHIFT,
+ OMAP3430_IVA2_MOD, OMAP3430_CM_CLKEN_PLL);
+
+ /* Restore mailbox settings */
+ omap_mbox_restore_ctx(dev_context->mbox);
+
+ /* Access MMU SYS CONFIG register to generate a short wakeup */
+ temp = readl(resources->dw_dmmu_base + 0x10);
+
+ dev_context->dw_brd_state = BRD_RUNNING;
+ } else if (dev_context->dw_brd_state == BRD_RETENTION) {
+ /* Restart the peripheral clocks */
+ dsp_clock_enable_all(dev_context->dsp_per_clks);
+ }
+
+ status = omap_mbox_msg_send(dev_context->mbox, mb_val);
+
+ if (status) {
+ pr_err("omap_mbox_msg_send Fail and status = %d\n", status);
+ status = -EPERM;
+ }
+
+ return 0;
+}
diff --git a/drivers/staging/tidspbridge/core/tiomap_io.h b/drivers/staging/tidspbridge/core/tiomap_io.h
new file mode 100644
index 00000000000..a3f19c7b79f
--- /dev/null
+++ b/drivers/staging/tidspbridge/core/tiomap_io.h
@@ -0,0 +1,104 @@
+/*
+ * tiomap_io.h
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * Definitions, types and function prototypes for the io (r/w external mem).
+ *
+ * Copyright (C) 2005-2006 Texas Instruments, Inc.
+ *
+ * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef _TIOMAP_IO_
+#define _TIOMAP_IO_
+
+/*
+ * Symbol that defines beginning of shared memory.
+ * For OMAP (Helen) this is the DSP Virtual base address of SDRAM.
+ * This will be used to program DSP MMU to map DSP Virt to GPP phys.
+ * (see dspMmuTlbEntry()).
+ */
+#define SHMBASENAME "SHM_BEG"
+#define EXTBASE "EXT_BEG"
+#define EXTEND "_EXT_END"
+#define DYNEXTBASE "_DYNEXT_BEG"
+#define DYNEXTEND "_DYNEXT_END"
+#define IVAEXTMEMBASE "_IVAEXTMEM_BEG"
+#define IVAEXTMEMEND "_IVAEXTMEM_END"
+
+#define DSP_TRACESEC_BEG "_BRIDGE_TRACE_BEG"
+#define DSP_TRACESEC_END "_BRIDGE_TRACE_END"
+
+#define SYS_PUTCBEG "_SYS_PUTCBEG"
+#define SYS_PUTCEND "_SYS_PUTCEND"
+#define BRIDGE_SYS_PUTC_CURRENT "_BRIDGE_SYS_PUTC_current"
+
+#define WORDSWAP_ENABLE 0x3 /* Enable word swap */
+
+/*
+ * ======== read_ext_dsp_data ========
+ * Reads it from DSP External memory. The external memory for the DSP
+ * is configured by the combination of DSP MMU and shm Memory manager in the CDB
+ */
+extern int read_ext_dsp_data(struct bridge_dev_context *dev_ctxt,
+ u8 *host_buff, u32 dsp_addr,
+ u32 ul_num_bytes, u32 mem_type);
+
+/*
+ * ======== write_dsp_data ========
+ */
+extern int write_dsp_data(struct bridge_dev_context *dev_context,
+ u8 *host_buff, u32 dsp_addr,
+ u32 ul_num_bytes, u32 mem_type);
+
+/*
+ * ======== write_ext_dsp_data ========
+ * Writes to the DSP External memory for external program.
+ * The ext mem for progra is configured by the combination of DSP MMU and
+ * shm Memory manager in the CDB
+ */
+extern int write_ext_dsp_data(struct bridge_dev_context *dev_context,
+ u8 *host_buff, u32 dsp_addr,
+ u32 ul_num_bytes, u32 mem_type,
+ bool dynamic_load);
+
+/*
+ * ======== write_ext32_bit_dsp_data ========
+ * Writes 32 bit data to the external memory
+ */
+extern inline void write_ext32_bit_dsp_data(const
+ struct bridge_dev_context *dev_context,
+ u32 dsp_addr, u32 val)
+{
+ *(u32 *) dsp_addr = ((dev_context->tc_word_swap_on) ? (((val << 16) &
+ 0xFFFF0000) |
+ ((val >> 16) &
+ 0x0000FFFF)) :
+ val);
+}
+
+/*
+ * ======== read_ext32_bit_dsp_data ========
+ * Reads 32 bit data from the external memory
+ */
+extern inline u32 read_ext32_bit_dsp_data(const struct bridge_dev_context
+ *dev_context, u32 dsp_addr)
+{
+ u32 ret;
+ ret = *(u32 *) dsp_addr;
+
+ ret = ((dev_context->tc_word_swap_on) ? (((ret << 16)
+ & 0xFFFF0000) | ((ret >> 16) &
+ 0x0000FFFF))
+ : ret);
+ return ret;
+}
+
+#endif /* _TIOMAP_IO_ */
diff --git a/drivers/staging/tidspbridge/core/ue_deh.c b/drivers/staging/tidspbridge/core/ue_deh.c
new file mode 100644
index 00000000000..3430418190d
--- /dev/null
+++ b/drivers/staging/tidspbridge/core/ue_deh.c
@@ -0,0 +1,273 @@
+/*
+ * ue_deh.c
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * Implements upper edge DSP exception handling (DEH) functions.
+ *
+ * Copyright (C) 2005-2006 Texas Instruments, Inc.
+ * Copyright (C) 2010 Felipe Contreras
+ *
+ * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <plat/dmtimer.h>
+
+#include <dspbridge/dbdefs.h>
+#include <dspbridge/dspdeh.h>
+#include <dspbridge/dev.h>
+#include "_tiomap.h"
+#include "_deh.h"
+
+#include <dspbridge/io_sm.h>
+#include <dspbridge/drv.h>
+#include <dspbridge/wdt.h>
+
+static u32 fault_addr;
+
+static void mmu_fault_dpc(unsigned long data)
+{
+ struct deh_mgr *deh = (void *)data;
+
+ if (!deh)
+ return;
+
+ bridge_deh_notify(deh, DSP_MMUFAULT, 0);
+}
+
+static irqreturn_t mmu_fault_isr(int irq, void *data)
+{
+ struct deh_mgr *deh = data;
+ struct cfg_hostres *resources;
+ u32 event;
+
+ if (!deh)
+ return IRQ_HANDLED;
+
+ resources = deh->hbridge_context->resources;
+ if (!resources) {
+ dev_dbg(bridge, "%s: Failed to get Host Resources\n",
+ __func__);
+ return IRQ_HANDLED;
+ }
+
+ hw_mmu_event_status(resources->dw_dmmu_base, &event);
+ if (event == HW_MMU_TRANSLATION_FAULT) {
+ hw_mmu_fault_addr_read(resources->dw_dmmu_base, &fault_addr);
+ dev_dbg(bridge, "%s: event=0x%x, fault_addr=0x%x\n", __func__,
+ event, fault_addr);
+ /*
+ * Schedule a DPC directly. In the future, it may be
+ * necessary to check if DSP MMU fault is intended for
+ * Bridge.
+ */
+ tasklet_schedule(&deh->dpc_tasklet);
+
+ /* Disable the MMU events, else once we clear it will
+ * start to raise INTs again */
+ hw_mmu_event_disable(resources->dw_dmmu_base,
+ HW_MMU_TRANSLATION_FAULT);
+ } else {
+ hw_mmu_event_disable(resources->dw_dmmu_base,
+ HW_MMU_ALL_INTERRUPTS);
+ }
+ return IRQ_HANDLED;
+}
+
+int bridge_deh_create(struct deh_mgr **ret_deh,
+ struct dev_object *hdev_obj)
+{
+ int status;
+ struct deh_mgr *deh;
+ struct bridge_dev_context *hbridge_context = NULL;
+
+ /* Message manager will be created when a file is loaded, since
+ * size of message buffer in shared memory is configurable in
+ * the base image. */
+ /* Get Bridge context info. */
+ dev_get_bridge_context(hdev_obj, &hbridge_context);
+ /* Allocate IO manager object: */
+ deh = kzalloc(sizeof(*deh), GFP_KERNEL);
+ if (!deh) {
+ status = -ENOMEM;
+ goto err;
+ }
+
+ /* Create an NTFY object to manage notifications */
+ deh->ntfy_obj = kmalloc(sizeof(struct ntfy_object), GFP_KERNEL);
+ if (!deh->ntfy_obj) {
+ status = -ENOMEM;
+ goto err;
+ }
+ ntfy_init(deh->ntfy_obj);
+
+ /* Create a MMUfault DPC */
+ tasklet_init(&deh->dpc_tasklet, mmu_fault_dpc, (u32) deh);
+
+ /* Fill in context structure */
+ deh->hbridge_context = hbridge_context;
+
+ /* Install ISR function for DSP MMU fault */
+ status = request_irq(INT_DSP_MMU_IRQ, mmu_fault_isr, 0,
+ "DspBridge\tiommu fault", deh);
+ if (status < 0)
+ goto err;
+
+ *ret_deh = deh;
+ return 0;
+
+err:
+ bridge_deh_destroy(deh);
+ *ret_deh = NULL;
+ return status;
+}
+
+int bridge_deh_destroy(struct deh_mgr *deh)
+{
+ if (!deh)
+ return -EFAULT;
+
+ /* If notification object exists, delete it */
+ if (deh->ntfy_obj) {
+ ntfy_delete(deh->ntfy_obj);
+ kfree(deh->ntfy_obj);
+ }
+ /* Disable DSP MMU fault */
+ free_irq(INT_DSP_MMU_IRQ, deh);
+
+ /* Free DPC object */
+ tasklet_kill(&deh->dpc_tasklet);
+
+ /* Deallocate the DEH manager object */
+ kfree(deh);
+
+ return 0;
+}
+
+int bridge_deh_register_notify(struct deh_mgr *deh, u32 event_mask,
+ u32 notify_type,
+ struct dsp_notification *hnotification)
+{
+ if (!deh)
+ return -EFAULT;
+
+ if (event_mask)
+ return ntfy_register(deh->ntfy_obj, hnotification,
+ event_mask, notify_type);
+ else
+ return ntfy_unregister(deh->ntfy_obj, hnotification);
+}
+
+#ifdef CONFIG_TIDSPBRIDGE_BACKTRACE
+static void mmu_fault_print_stack(struct bridge_dev_context *dev_context)
+{
+ struct cfg_hostres *resources;
+ struct hw_mmu_map_attrs_t map_attrs = {
+ .endianism = HW_LITTLE_ENDIAN,
+ .element_size = HW_ELEM_SIZE16BIT,
+ .mixed_size = HW_MMU_CPUES,
+ };
+ void *dummy_va_addr;
+
+ resources = dev_context->resources;
+ dummy_va_addr = (void*)__get_free_page(GFP_ATOMIC);
+
+ /*
+ * Before acking the MMU fault, let's make sure MMU can only
+ * access entry #0. Then add a new entry so that the DSP OS
+ * can continue in order to dump the stack.
+ */
+ hw_mmu_twl_disable(resources->dw_dmmu_base);
+ hw_mmu_tlb_flush_all(resources->dw_dmmu_base);
+
+ hw_mmu_tlb_add(resources->dw_dmmu_base,
+ virt_to_phys(dummy_va_addr), fault_addr,
+ HW_PAGE_SIZE4KB, 1,
+ &map_attrs, HW_SET, HW_SET);
+
+ dsp_clk_enable(DSP_CLK_GPT8);
+
+ dsp_gpt_wait_overflow(DSP_CLK_GPT8, 0xfffffffe);
+
+ /* Clear MMU interrupt */
+ hw_mmu_event_ack(resources->dw_dmmu_base,
+ HW_MMU_TRANSLATION_FAULT);
+ dump_dsp_stack(dev_context);
+ dsp_clk_disable(DSP_CLK_GPT8);
+
+ hw_mmu_disable(resources->dw_dmmu_base);
+ free_page((unsigned long)dummy_va_addr);
+}
+#endif
+
+static inline const char *event_to_string(int event)
+{
+ switch (event) {
+ case DSP_SYSERROR: return "DSP_SYSERROR"; break;
+ case DSP_MMUFAULT: return "DSP_MMUFAULT"; break;
+ case DSP_PWRERROR: return "DSP_PWRERROR"; break;
+ case DSP_WDTOVERFLOW: return "DSP_WDTOVERFLOW"; break;
+ default: return "unkown event"; break;
+ }
+}
+
+void bridge_deh_notify(struct deh_mgr *deh, int event, int info)
+{
+ struct bridge_dev_context *dev_context;
+ const char *str = event_to_string(event);
+
+ if (!deh)
+ return;
+
+ dev_dbg(bridge, "%s: device exception", __func__);
+ dev_context = deh->hbridge_context;
+
+ switch (event) {
+ case DSP_SYSERROR:
+ dev_err(bridge, "%s: %s, info=0x%x", __func__,
+ str, info);
+#ifdef CONFIG_TIDSPBRIDGE_BACKTRACE
+ dump_dl_modules(dev_context);
+ dump_dsp_stack(dev_context);
+#endif
+ break;
+ case DSP_MMUFAULT:
+ dev_err(bridge, "%s: %s, addr=0x%x", __func__,
+ str, fault_addr);
+#ifdef CONFIG_TIDSPBRIDGE_BACKTRACE
+ print_dsp_trace_buffer(dev_context);
+ dump_dl_modules(dev_context);
+ mmu_fault_print_stack(dev_context);
+#endif
+ break;
+ default:
+ dev_err(bridge, "%s: %s", __func__, str);
+ break;
+ }
+
+ /* Filter subsequent notifications when an error occurs */
+ if (dev_context->dw_brd_state != BRD_ERROR) {
+ ntfy_notify(deh->ntfy_obj, event);
+#ifdef CONFIG_TIDSPBRIDGE_RECOVERY
+ bridge_recover_schedule();
+#endif
+ }
+
+ /* Set the Board state as ERROR */
+ dev_context->dw_brd_state = BRD_ERROR;
+ /* Disable all the clocks that were enabled by DSP */
+ dsp_clock_disable_all(dev_context->dsp_per_clks);
+ /*
+ * Avoid the subsequent WDT if it happens once,
+ * also if fatal error occurs.
+ */
+ dsp_wdt_enable(false);
+}
diff --git a/drivers/staging/tidspbridge/core/wdt.c b/drivers/staging/tidspbridge/core/wdt.c
new file mode 100644
index 00000000000..2126f597753
--- /dev/null
+++ b/drivers/staging/tidspbridge/core/wdt.c
@@ -0,0 +1,150 @@
+/*
+ * wdt.c
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * IO dispatcher for a shared memory channel driver.
+ *
+ * Copyright (C) 2010 Texas Instruments, Inc.
+ *
+ * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+#include <linux/types.h>
+
+#include <dspbridge/dbdefs.h>
+#include <dspbridge/dspdeh.h>
+#include <dspbridge/dev.h>
+#include <dspbridge/_chnl_sm.h>
+#include <dspbridge/wdt.h>
+#include <dspbridge/host_os.h>
+
+
+#ifdef CONFIG_TIDSPBRIDGE_WDT3
+
+#define OMAP34XX_WDT3_BASE (L4_PER_34XX_BASE + 0x30000)
+
+static struct dsp_wdt_setting dsp_wdt;
+
+void dsp_wdt_dpc(unsigned long data)
+{
+ struct deh_mgr *deh_mgr;
+ dev_get_deh_mgr(dev_get_first(), &deh_mgr);
+ if (deh_mgr)
+ bridge_deh_notify(deh_mgr, DSP_WDTOVERFLOW, 0);
+}
+
+irqreturn_t dsp_wdt_isr(int irq, void *data)
+{
+ u32 value;
+ /* ack wdt3 interrupt */
+ value = __raw_readl(dsp_wdt.reg_base + OMAP3_WDT3_ISR_OFFSET);
+ __raw_writel(value, dsp_wdt.reg_base + OMAP3_WDT3_ISR_OFFSET);
+
+ tasklet_schedule(&dsp_wdt.wdt3_tasklet);
+ return IRQ_HANDLED;
+}
+
+int dsp_wdt_init(void)
+{
+ int ret = 0;
+
+ dsp_wdt.sm_wdt = NULL;
+ dsp_wdt.reg_base = OMAP2_L4_IO_ADDRESS(OMAP34XX_WDT3_BASE);
+ tasklet_init(&dsp_wdt.wdt3_tasklet, dsp_wdt_dpc, 0);
+
+ dsp_wdt.fclk = clk_get(NULL, "wdt3_fck");
+
+ if (dsp_wdt.fclk) {
+ dsp_wdt.iclk = clk_get(NULL, "wdt3_ick");
+ if (!dsp_wdt.iclk) {
+ clk_put(dsp_wdt.fclk);
+ dsp_wdt.fclk = NULL;
+ ret = -EFAULT;
+ }
+ } else
+ ret = -EFAULT;
+
+ if (!ret)
+ ret = request_irq(INT_34XX_WDT3_IRQ, dsp_wdt_isr, 0,
+ "dsp_wdt", &dsp_wdt);
+
+ /* Disable at this moment, it will be enabled when DSP starts */
+ if (!ret)
+ disable_irq(INT_34XX_WDT3_IRQ);
+
+ return ret;
+}
+
+void dsp_wdt_sm_set(void *data)
+{
+ dsp_wdt.sm_wdt = data;
+ dsp_wdt.sm_wdt->wdt_overflow = CONFIG_TIDSPBRIDGE_WDT_TIMEOUT;
+}
+
+
+void dsp_wdt_exit(void)
+{
+ free_irq(INT_34XX_WDT3_IRQ, &dsp_wdt);
+ tasklet_kill(&dsp_wdt.wdt3_tasklet);
+
+ if (dsp_wdt.fclk)
+ clk_put(dsp_wdt.fclk);
+ if (dsp_wdt.iclk)
+ clk_put(dsp_wdt.iclk);
+
+ dsp_wdt.fclk = NULL;
+ dsp_wdt.iclk = NULL;
+ dsp_wdt.sm_wdt = NULL;
+ dsp_wdt.reg_base = NULL;
+}
+
+void dsp_wdt_enable(bool enable)
+{
+ u32 tmp;
+ static bool wdt_enable;
+
+ if (wdt_enable == enable || !dsp_wdt.fclk || !dsp_wdt.iclk)
+ return;
+
+ wdt_enable = enable;
+
+ if (enable) {
+ clk_enable(dsp_wdt.fclk);
+ clk_enable(dsp_wdt.iclk);
+ dsp_wdt.sm_wdt->wdt_setclocks = 1;
+ tmp = __raw_readl(dsp_wdt.reg_base + OMAP3_WDT3_ISR_OFFSET);
+ __raw_writel(tmp, dsp_wdt.reg_base + OMAP3_WDT3_ISR_OFFSET);
+ enable_irq(INT_34XX_WDT3_IRQ);
+ } else {
+ disable_irq(INT_34XX_WDT3_IRQ);
+ dsp_wdt.sm_wdt->wdt_setclocks = 0;
+ clk_disable(dsp_wdt.iclk);
+ clk_disable(dsp_wdt.fclk);
+ }
+}
+
+#else
+void dsp_wdt_enable(bool enable)
+{
+}
+
+void dsp_wdt_sm_set(void *data)
+{
+}
+
+int dsp_wdt_init(void)
+{
+ return 0;
+}
+
+void dsp_wdt_exit(void)
+{
+}
+#endif
+
diff --git a/drivers/staging/tidspbridge/dynload/cload.c b/drivers/staging/tidspbridge/dynload/cload.c
new file mode 100644
index 00000000000..c85a5e88361
--- /dev/null
+++ b/drivers/staging/tidspbridge/dynload/cload.c
@@ -0,0 +1,1953 @@
+/*
+ * cload.c
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * Copyright (C) 2005-2006 Texas Instruments, Inc.
+ *
+ * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include "header.h"
+
+#include "module_list.h"
+#define LINKER_MODULES_HEADER ("_" MODULES_HEADER)
+
+/*
+ * forward references
+ */
+static void dload_symbols(struct dload_state *dlthis);
+static void dload_data(struct dload_state *dlthis);
+static void allocate_sections(struct dload_state *dlthis);
+static void string_table_free(struct dload_state *dlthis);
+static void symbol_table_free(struct dload_state *dlthis);
+static void section_table_free(struct dload_state *dlthis);
+static void init_module_handle(struct dload_state *dlthis);
+#if BITS_PER_AU > BITS_PER_BYTE
+static char *unpack_name(struct dload_state *dlthis, u32 soffset);
+#endif
+
+static const char cinitname[] = { ".cinit" };
+static const char loader_dllview_root[] = { "?DLModules?" };
+
+/*
+ * Error strings
+ */
+static const char readstrm[] = { "Error reading %s from input stream" };
+static const char err_alloc[] = { "Syms->dload_allocate( %d ) failed" };
+static const char tgtalloc[] = {
+ "Target memory allocate failed, section %s size " FMT_UI32 };
+static const char initfail[] = { "%s to target address " FMT_UI32 " failed" };
+static const char dlvwrite[] = { "Write to DLLview list failed" };
+static const char iconnect[] = { "Connect call to init interface failed" };
+static const char err_checksum[] = { "Checksum failed on %s" };
+
+/*************************************************************************
+ * Procedure dload_error
+ *
+ * Parameters:
+ * errtxt description of the error, printf style
+ * ... additional information
+ *
+ * Effect:
+ * Reports or records the error as appropriate.
+ *********************************************************************** */
+void dload_error(struct dload_state *dlthis, const char *errtxt, ...)
+{
+ va_list args;
+
+ va_start(args, errtxt);
+ dlthis->mysym->error_report(dlthis->mysym, errtxt, args);
+ va_end(args);
+ dlthis->dload_errcount += 1;
+
+} /* dload_error */
+
+#define DL_ERROR(zza, zzb) dload_error(dlthis, zza, zzb)
+
+/*************************************************************************
+ * Procedure dload_syms_error
+ *
+ * Parameters:
+ * errtxt description of the error, printf style
+ * ... additional information
+ *
+ * Effect:
+ * Reports or records the error as appropriate.
+ *********************************************************************** */
+void dload_syms_error(struct dynamic_loader_sym *syms, const char *errtxt, ...)
+{
+ va_list args;
+
+ va_start(args, errtxt);
+ syms->error_report(syms, errtxt, args);
+ va_end(args);
+}
+
+/*************************************************************************
+ * Procedure dynamic_load_module
+ *
+ * Parameters:
+ * module The input stream that supplies the module image
+ * syms Host-side symbol table and malloc/free functions
+ * alloc Target-side memory allocation
+ * init Target-side memory initialization
+ * options Option flags DLOAD_*
+ * mhandle A module handle for use with Dynamic_Unload
+ *
+ * Effect:
+ * The module image is read using *module. Target storage for the new
+ * image is
+ * obtained from *alloc. Symbols defined and referenced by the module are
+ * managed using *syms. The image is then relocated and references
+ * resolved as necessary, and the resulting executable bits are placed
+ * into target memory using *init.
+ *
+ * Returns:
+ * On a successful load, a module handle is placed in *mhandle,
+ * and zero is returned. On error, the number of errors detected is
+ * returned. Individual errors are reported during the load process
+ * using syms->error_report().
+ ********************************************************************** */
+int dynamic_load_module(struct dynamic_loader_stream *module,
+ struct dynamic_loader_sym *syms,
+ struct dynamic_loader_allocate *alloc,
+ struct dynamic_loader_initialize *init,
+ unsigned options, void **mhandle)
+{
+ register unsigned *dp, sz;
+ struct dload_state dl_state; /* internal state for this call */
+
+ /* blast our internal state */
+ dp = (unsigned *)&dl_state;
+ for (sz = sizeof(dl_state) / sizeof(unsigned); sz > 0; sz -= 1)
+ *dp++ = 0;
+
+ /* Enable _only_ BSS initialization if enabled by user */
+ if ((options & DLOAD_INITBSS) == DLOAD_INITBSS)
+ dl_state.myoptions = DLOAD_INITBSS;
+
+ /* Check that mandatory arguments are present */
+ if (!module || !syms) {
+ dload_error(&dl_state, "Required parameter is NULL");
+ } else {
+ dl_state.strm = module;
+ dl_state.mysym = syms;
+ dload_headers(&dl_state);
+ if (!dl_state.dload_errcount)
+ dload_strings(&dl_state, false);
+ if (!dl_state.dload_errcount)
+ dload_sections(&dl_state);
+
+ if (init && !dl_state.dload_errcount) {
+ if (init->connect(init)) {
+ dl_state.myio = init;
+ dl_state.myalloc = alloc;
+ /* do now, before reducing symbols */
+ allocate_sections(&dl_state);
+ } else
+ dload_error(&dl_state, iconnect);
+ }
+
+ if (!dl_state.dload_errcount) {
+ /* fix up entry point address */
+ unsigned sref = dl_state.dfile_hdr.df_entry_secn - 1;
+ if (sref < dl_state.allocated_secn_count)
+ dl_state.dfile_hdr.df_entrypt +=
+ dl_state.ldr_sections[sref].run_addr;
+
+ dload_symbols(&dl_state);
+ }
+
+ if (init && !dl_state.dload_errcount)
+ dload_data(&dl_state);
+
+ init_module_handle(&dl_state);
+
+ /* dl_state.myio is init or 0 at this point. */
+ if (dl_state.myio) {
+ if ((!dl_state.dload_errcount) &&
+ (dl_state.dfile_hdr.df_entry_secn != DN_UNDEF) &&
+ (!init->execute(init,
+ dl_state.dfile_hdr.df_entrypt)))
+ dload_error(&dl_state, "Init->Execute Failed");
+ init->release(init);
+ }
+
+ symbol_table_free(&dl_state);
+ section_table_free(&dl_state);
+ string_table_free(&dl_state);
+ dload_tramp_cleanup(&dl_state);
+
+ if (dl_state.dload_errcount) {
+ dynamic_unload_module(dl_state.myhandle, syms, alloc,
+ init);
+ dl_state.myhandle = NULL;
+ }
+ }
+
+ if (mhandle)
+ *mhandle = dl_state.myhandle; /* give back the handle */
+
+ return dl_state.dload_errcount;
+} /* DLOAD_File */
+
+/*************************************************************************
+ * Procedure dynamic_open_module
+ *
+ * Parameters:
+ * module The input stream that supplies the module image
+ * syms Host-side symbol table and malloc/free functions
+ * alloc Target-side memory allocation
+ * init Target-side memory initialization
+ * options Option flags DLOAD_*
+ * mhandle A module handle for use with Dynamic_Unload
+ *
+ * Effect:
+ * The module image is read using *module. Target storage for the new
+ * image is
+ * obtained from *alloc. Symbols defined and referenced by the module are
+ * managed using *syms. The image is then relocated and references
+ * resolved as necessary, and the resulting executable bits are placed
+ * into target memory using *init.
+ *
+ * Returns:
+ * On a successful load, a module handle is placed in *mhandle,
+ * and zero is returned. On error, the number of errors detected is
+ * returned. Individual errors are reported during the load process
+ * using syms->error_report().
+ ********************************************************************** */
+int
+dynamic_open_module(struct dynamic_loader_stream *module,
+ struct dynamic_loader_sym *syms,
+ struct dynamic_loader_allocate *alloc,
+ struct dynamic_loader_initialize *init,
+ unsigned options, void **mhandle)
+{
+ register unsigned *dp, sz;
+ struct dload_state dl_state; /* internal state for this call */
+
+ /* blast our internal state */
+ dp = (unsigned *)&dl_state;
+ for (sz = sizeof(dl_state) / sizeof(unsigned); sz > 0; sz -= 1)
+ *dp++ = 0;
+
+ /* Enable _only_ BSS initialization if enabled by user */
+ if ((options & DLOAD_INITBSS) == DLOAD_INITBSS)
+ dl_state.myoptions = DLOAD_INITBSS;
+
+ /* Check that mandatory arguments are present */
+ if (!module || !syms) {
+ dload_error(&dl_state, "Required parameter is NULL");
+ } else {
+ dl_state.strm = module;
+ dl_state.mysym = syms;
+ dload_headers(&dl_state);
+ if (!dl_state.dload_errcount)
+ dload_strings(&dl_state, false);
+ if (!dl_state.dload_errcount)
+ dload_sections(&dl_state);
+
+ if (init && !dl_state.dload_errcount) {
+ if (init->connect(init)) {
+ dl_state.myio = init;
+ dl_state.myalloc = alloc;
+ /* do now, before reducing symbols */
+ allocate_sections(&dl_state);
+ } else
+ dload_error(&dl_state, iconnect);
+ }
+
+ if (!dl_state.dload_errcount) {
+ /* fix up entry point address */
+ unsigned sref = dl_state.dfile_hdr.df_entry_secn - 1;
+ if (sref < dl_state.allocated_secn_count)
+ dl_state.dfile_hdr.df_entrypt +=
+ dl_state.ldr_sections[sref].run_addr;
+
+ dload_symbols(&dl_state);
+ }
+
+ init_module_handle(&dl_state);
+
+ /* dl_state.myio is either 0 or init at this point. */
+ if (dl_state.myio) {
+ if ((!dl_state.dload_errcount) &&
+ (dl_state.dfile_hdr.df_entry_secn != DN_UNDEF) &&
+ (!init->execute(init,
+ dl_state.dfile_hdr.df_entrypt)))
+ dload_error(&dl_state, "Init->Execute Failed");
+ init->release(init);
+ }
+
+ symbol_table_free(&dl_state);
+ section_table_free(&dl_state);
+ string_table_free(&dl_state);
+
+ if (dl_state.dload_errcount) {
+ dynamic_unload_module(dl_state.myhandle, syms, alloc,
+ init);
+ dl_state.myhandle = NULL;
+ }
+ }
+
+ if (mhandle)
+ *mhandle = dl_state.myhandle; /* give back the handle */
+
+ return dl_state.dload_errcount;
+} /* DLOAD_File */
+
+/*************************************************************************
+ * Procedure dload_headers
+ *
+ * Parameters:
+ * none
+ *
+ * Effect:
+ * Loads the DOFF header and verify record. Deals with any byte-order
+ * issues and checks them for validity.
+ *********************************************************************** */
+#define COMBINED_HEADER_SIZE (sizeof(struct doff_filehdr_t)+ \
+ sizeof(struct doff_verify_rec_t))
+
+void dload_headers(struct dload_state *dlthis)
+{
+ u32 map;
+
+ /* Read the header and the verify record as one. If we don't get it
+ all, we're done */
+ if (dlthis->strm->read_buffer(dlthis->strm, &dlthis->dfile_hdr,
+ COMBINED_HEADER_SIZE) !=
+ COMBINED_HEADER_SIZE) {
+ DL_ERROR(readstrm, "File Headers");
+ return;
+ }
+ /*
+ * Verify that we have the byte order of the file correct.
+ * If not, must fix it before we can continue
+ */
+ map = REORDER_MAP(dlthis->dfile_hdr.df_byte_reshuffle);
+ if (map != REORDER_MAP(BYTE_RESHUFFLE_VALUE)) {
+ /* input is either byte-shuffled or bad */
+ if ((map & 0xFCFCFCFC) == 0) { /* no obviously bogus bits */
+ dload_reorder(&dlthis->dfile_hdr, COMBINED_HEADER_SIZE,
+ map);
+ }
+ if (dlthis->dfile_hdr.df_byte_reshuffle !=
+ BYTE_RESHUFFLE_VALUE) {
+ /* didn't fix the problem, the byte swap map is bad */
+ dload_error(dlthis,
+ "Bad byte swap map " FMT_UI32 " in header",
+ dlthis->dfile_hdr.df_byte_reshuffle);
+ return;
+ }
+ dlthis->reorder_map = map; /* keep map for future use */
+ }
+
+ /*
+ * Verify checksum of header and verify record
+ */
+ if (~dload_checksum(&dlthis->dfile_hdr,
+ sizeof(struct doff_filehdr_t)) ||
+ ~dload_checksum(&dlthis->verify,
+ sizeof(struct doff_verify_rec_t))) {
+ DL_ERROR(err_checksum, "header or verify record");
+ return;
+ }
+#if HOST_ENDIANNESS
+ dlthis->dfile_hdr.df_byte_reshuffle = map; /* put back for later */
+#endif
+
+ /* Check for valid target ID */
+ if ((dlthis->dfile_hdr.df_target_id != TARGET_ID) &&
+ -(dlthis->dfile_hdr.df_target_id != TMS470_ID)) {
+ dload_error(dlthis, "Bad target ID 0x%x and TARGET_ID 0x%x",
+ dlthis->dfile_hdr.df_target_id, TARGET_ID);
+ return;
+ }
+ /* Check for valid file format */
+ if ((dlthis->dfile_hdr.df_doff_version != DOFF0)) {
+ dload_error(dlthis, "Bad DOFF version 0x%x",
+ dlthis->dfile_hdr.df_doff_version);
+ return;
+ }
+
+ /*
+ * Apply reasonableness checks to count fields
+ */
+ if (dlthis->dfile_hdr.df_strtab_size > MAX_REASONABLE_STRINGTAB) {
+ dload_error(dlthis, "Excessive string table size " FMT_UI32,
+ dlthis->dfile_hdr.df_strtab_size);
+ return;
+ }
+ if (dlthis->dfile_hdr.df_no_scns > MAX_REASONABLE_SECTIONS) {
+ dload_error(dlthis, "Excessive section count 0x%x",
+ dlthis->dfile_hdr.df_no_scns);
+ return;
+ }
+#ifndef TARGET_ENDIANNESS
+ /*
+ * Check that endianness does not disagree with explicit specification
+ */
+ if ((dlthis->dfile_hdr.df_flags >> ALIGN_COFF_ENDIANNESS) &
+ dlthis->myoptions & ENDIANNESS_MASK) {
+ dload_error(dlthis,
+ "Input endianness disagrees with specified option");
+ return;
+ }
+ dlthis->big_e_target = dlthis->dfile_hdr.df_flags & DF_BIG;
+#endif
+
+} /* dload_headers */
+
+/* COFF Section Processing
+ *
+ * COFF sections are read in and retained intact. Each record is embedded
+ * in a new structure that records the updated load and
+ * run addresses of the section */
+
+static const char secn_errid[] = { "section" };
+
+/*************************************************************************
+ * Procedure dload_sections
+ *
+ * Parameters:
+ * none
+ *
+ * Effect:
+ * Loads the section records into an internal table.
+ *********************************************************************** */
+void dload_sections(struct dload_state *dlthis)
+{
+ s16 siz;
+ struct doff_scnhdr_t *shp;
+ unsigned nsecs = dlthis->dfile_hdr.df_no_scns;
+
+ /* allocate space for the DOFF section records */
+ siz = nsecs * sizeof(struct doff_scnhdr_t);
+ shp =
+ (struct doff_scnhdr_t *)dlthis->mysym->dload_allocate(dlthis->mysym,
+ siz);
+ if (!shp) { /* not enough storage */
+ DL_ERROR(err_alloc, siz);
+ return;
+ }
+ dlthis->sect_hdrs = shp;
+
+ /* read in the section records */
+ if (dlthis->strm->read_buffer(dlthis->strm, shp, siz) != siz) {
+ DL_ERROR(readstrm, secn_errid);
+ return;
+ }
+
+ /* if we need to fix up byte order, do it now */
+ if (dlthis->reorder_map)
+ dload_reorder(shp, siz, dlthis->reorder_map);
+
+ /* check for validity */
+ if (~dload_checksum(dlthis->sect_hdrs, siz) !=
+ dlthis->verify.dv_scn_rec_checksum) {
+ DL_ERROR(err_checksum, secn_errid);
+ return;
+ }
+
+} /* dload_sections */
+
+/*****************************************************************************
+ * Procedure allocate_sections
+ *
+ * Parameters:
+ * alloc target memory allocator class
+ *
+ * Effect:
+ * Assigns new (target) addresses for sections
+ **************************************************************************** */
+static void allocate_sections(struct dload_state *dlthis)
+{
+ u16 curr_sect, nsecs, siz;
+ struct doff_scnhdr_t *shp;
+ struct ldr_section_info *asecs;
+ struct my_handle *hndl;
+ nsecs = dlthis->dfile_hdr.df_no_scns;
+ if (!nsecs)
+ return;
+ if ((dlthis->myalloc == NULL) &&
+ (dlthis->dfile_hdr.df_target_scns > 0)) {
+ DL_ERROR("Arg 3 (alloc) required but NULL", 0);
+ return;
+ }
+ /*
+ * allocate space for the module handle, which we will keep for unload
+ * purposes include an additional section store for an auto-generated
+ * trampoline section in case we need it.
+ */
+ siz = (dlthis->dfile_hdr.df_target_scns + 1) *
+ sizeof(struct ldr_section_info) + MY_HANDLE_SIZE;
+
+ hndl =
+ (struct my_handle *)dlthis->mysym->dload_allocate(dlthis->mysym,
+ siz);
+ if (!hndl) { /* not enough storage */
+ DL_ERROR(err_alloc, siz);
+ return;
+ }
+ /* initialize the handle header */
+ hndl->dm.hnext = hndl->dm.hprev = hndl; /* circular list */
+ hndl->dm.hroot = NULL;
+ hndl->dm.dbthis = 0;
+ dlthis->myhandle = hndl; /* save away for return */
+ /* pointer to the section list of allocated sections */
+ dlthis->ldr_sections = asecs = hndl->secns;
+ /* * Insert names into all sections, make copies of
+ the sections we allocate */
+ shp = dlthis->sect_hdrs;
+ for (curr_sect = 0; curr_sect < nsecs; curr_sect++) {
+ u32 soffset = shp->ds_offset;
+#if BITS_PER_AU <= BITS_PER_BYTE
+ /* attempt to insert the name of this section */
+ if (soffset < dlthis->dfile_hdr.df_strtab_size)
+ ((struct ldr_section_info *)shp)->name =
+ dlthis->str_head + soffset;
+ else {
+ dload_error(dlthis, "Bad name offset in section %d",
+ curr_sect);
+ ((struct ldr_section_info *)shp)->name = NULL;
+ }
+#endif
+ /* allocate target storage for sections that require it */
+ if (ds_needs_allocation(shp)) {
+ *asecs = *(struct ldr_section_info *)shp;
+ asecs->context = 0; /* zero the context field */
+#if BITS_PER_AU > BITS_PER_BYTE
+ asecs->name = unpack_name(dlthis, soffset);
+ dlthis->debug_string_size = soffset + dlthis->temp_len;
+#else
+ dlthis->debug_string_size = soffset;
+#endif
+ if (dlthis->myalloc != NULL) {
+ if (!dlthis->myalloc->
+ dload_allocate(dlthis->myalloc, asecs,
+ ds_alignment(asecs->type))) {
+ dload_error(dlthis, tgtalloc,
+ asecs->name, asecs->size);
+ return;
+ }
+ }
+ /* keep address deltas in original section table */
+ shp->ds_vaddr = asecs->load_addr - shp->ds_vaddr;
+ shp->ds_paddr = asecs->run_addr - shp->ds_paddr;
+ dlthis->allocated_secn_count += 1;
+ } /* allocate target storage */
+ shp += 1;
+ asecs += 1;
+ }
+#if BITS_PER_AU <= BITS_PER_BYTE
+ dlthis->debug_string_size +=
+ strlen(dlthis->str_head + dlthis->debug_string_size) + 1;
+#endif
+} /* allocate sections */
+
+/*************************************************************************
+ * Procedure section_table_free
+ *
+ * Parameters:
+ * none
+ *
+ * Effect:
+ * Frees any state used by the symbol table.
+ *
+ * WARNING:
+ * This routine is not allowed to declare errors!
+ *********************************************************************** */
+static void section_table_free(struct dload_state *dlthis)
+{
+ struct doff_scnhdr_t *shp;
+
+ shp = dlthis->sect_hdrs;
+ if (shp)
+ dlthis->mysym->dload_deallocate(dlthis->mysym, shp);
+
+} /* section_table_free */
+
+/*************************************************************************
+ * Procedure dload_strings
+ *
+ * Parameters:
+ * sec_names_only If true only read in the "section names"
+ * portion of the string table
+ *
+ * Effect:
+ * Loads the DOFF string table into memory. DOFF keeps all strings in a
+ * big unsorted array. We just read that array into memory in bulk.
+ *********************************************************************** */
+static const char stringtbl[] = { "string table" };
+
+void dload_strings(struct dload_state *dlthis, bool sec_names_only)
+{
+ u32 ssiz;
+ char *strbuf;
+
+ if (sec_names_only) {
+ ssiz = BYTE_TO_HOST(DOFF_ALIGN
+ (dlthis->dfile_hdr.df_scn_name_size));
+ } else {
+ ssiz = BYTE_TO_HOST(DOFF_ALIGN
+ (dlthis->dfile_hdr.df_strtab_size));
+ }
+ if (ssiz == 0)
+ return;
+
+ /* get some memory for the string table */
+#if BITS_PER_AU > BITS_PER_BYTE
+ strbuf = (char *)dlthis->mysym->dload_allocate(dlthis->mysym, ssiz +
+ dlthis->dfile_hdr.
+ df_max_str_len);
+#else
+ strbuf = (char *)dlthis->mysym->dload_allocate(dlthis->mysym, ssiz);
+#endif
+ if (strbuf == NULL) {
+ DL_ERROR(err_alloc, ssiz);
+ return;
+ }
+ dlthis->str_head = strbuf;
+#if BITS_PER_AU > BITS_PER_BYTE
+ dlthis->str_temp = strbuf + ssiz;
+#endif
+ /* read in the strings and verify them */
+ if ((unsigned)(dlthis->strm->read_buffer(dlthis->strm, strbuf,
+ ssiz)) != ssiz) {
+ DL_ERROR(readstrm, stringtbl);
+ }
+ /* if we need to fix up byte order, do it now */
+#ifndef _BIG_ENDIAN
+ if (dlthis->reorder_map)
+ dload_reorder(strbuf, ssiz, dlthis->reorder_map);
+
+ if ((!sec_names_only) && (~dload_checksum(strbuf, ssiz) !=
+ dlthis->verify.dv_str_tab_checksum)) {
+ DL_ERROR(err_checksum, stringtbl);
+ }
+#else
+ if (dlthis->dfile_hdr.df_byte_reshuffle !=
+ HOST_BYTE_ORDER(REORDER_MAP(BYTE_RESHUFFLE_VALUE))) {
+ /* put strings in big-endian order, not in PC order */
+ dload_reorder(strbuf, ssiz,
+ HOST_BYTE_ORDER(dlthis->
+ dfile_hdr.df_byte_reshuffle));
+ }
+ if ((!sec_names_only) && (~dload_reverse_checksum(strbuf, ssiz) !=
+ dlthis->verify.dv_str_tab_checksum)) {
+ DL_ERROR(err_checksum, stringtbl);
+ }
+#endif
+} /* dload_strings */
+
+/*************************************************************************
+ * Procedure string_table_free
+ *
+ * Parameters:
+ * none
+ *
+ * Effect:
+ * Frees any state used by the string table.
+ *
+ * WARNING:
+ * This routine is not allowed to declare errors!
+ ************************************************************************ */
+static void string_table_free(struct dload_state *dlthis)
+{
+ if (dlthis->str_head)
+ dlthis->mysym->dload_deallocate(dlthis->mysym,
+ dlthis->str_head);
+
+} /* string_table_free */
+
+/*
+ * Symbol Table Maintenance Functions
+ *
+ * COFF symbols are read by dload_symbols(), which is called after
+ * sections have been allocated. Symbols which might be used in
+ * relocation (ie, not debug info) are retained in an internal temporary
+ * compressed table (type local_symbol). A particular symbol is recovered
+ * by index by calling dload_find_symbol(). dload_find_symbol
+ * reconstructs a more explicit representation (type SLOTVEC) which is
+ * used by reloc.c
+ */
+/* real size of debug header */
+#define DBG_HDR_SIZE (sizeof(struct dll_module) - sizeof(struct dll_sect))
+
+static const char sym_errid[] = { "symbol" };
+
+/**************************************************************************
+ * Procedure dload_symbols
+ *
+ * Parameters:
+ * none
+ *
+ * Effect:
+ * Reads in symbols and retains ones that might be needed for relocation
+ * purposes.
+ *********************************************************************** */
+/* size of symbol buffer no bigger than target data buffer, to limit stack
+ * usage */
+#define MY_SYM_BUF_SIZ (BYTE_TO_HOST(IMAGE_PACKET_SIZE)/\
+ sizeof(struct doff_syment_t))
+
+static void dload_symbols(struct dload_state *dlthis)
+{
+ u32 sym_count, siz, dsiz, symbols_left;
+ u32 checks;
+ struct local_symbol *sp;
+ struct dynload_symbol *symp;
+ struct dynload_symbol *newsym;
+
+ sym_count = dlthis->dfile_hdr.df_no_syms;
+ if (sym_count == 0)
+ return;
+
+ /*
+ * We keep a local symbol table for all of the symbols in the input.
+ * This table contains only section & value info, as we do not have
+ * to do any name processing for locals. We reuse this storage
+ * as a temporary for .dllview record construction.
+ * Allocate storage for the whole table. Add 1 to the section count
+ * in case a trampoline section is auto-generated as well as the
+ * size of the trampoline section name so DLLView doens't get lost.
+ */
+
+ siz = sym_count * sizeof(struct local_symbol);
+ dsiz = DBG_HDR_SIZE +
+ (sizeof(struct dll_sect) * dlthis->allocated_secn_count) +
+ BYTE_TO_HOST_ROUND(dlthis->debug_string_size + 1);
+ if (dsiz > siz)
+ siz = dsiz; /* larger of symbols and .dllview temp */
+ sp = (struct local_symbol *)dlthis->mysym->dload_allocate(dlthis->mysym,
+ siz);
+ if (!sp) {
+ DL_ERROR(err_alloc, siz);
+ return;
+ }
+ dlthis->local_symtab = sp;
+ /* Read the symbols in the input, store them in the table, and post any
+ * globals to the global symbol table. In the process, externals
+ become defined from the global symbol table */
+ checks = dlthis->verify.dv_sym_tab_checksum;
+ symbols_left = sym_count;
+ do { /* read all symbols */
+ char *sname;
+ u32 val;
+ s32 delta;
+ struct doff_syment_t *input_sym;
+ unsigned syms_in_buf;
+ struct doff_syment_t my_sym_buf[MY_SYM_BUF_SIZ];
+ input_sym = my_sym_buf;
+ syms_in_buf = symbols_left > MY_SYM_BUF_SIZ ?
+ MY_SYM_BUF_SIZ : symbols_left;
+ siz = syms_in_buf * sizeof(struct doff_syment_t);
+ if (dlthis->strm->read_buffer(dlthis->strm, input_sym, siz) !=
+ siz) {
+ DL_ERROR(readstrm, sym_errid);
+ return;
+ }
+ if (dlthis->reorder_map)
+ dload_reorder(input_sym, siz, dlthis->reorder_map);
+
+ checks += dload_checksum(input_sym, siz);
+ do { /* process symbols in buffer */
+ symbols_left -= 1;
+ /* attempt to derive the name of this symbol */
+ sname = NULL;
+ if (input_sym->dn_offset > 0) {
+#if BITS_PER_AU <= BITS_PER_BYTE
+ if ((u32) input_sym->dn_offset <
+ dlthis->dfile_hdr.df_strtab_size)
+ sname = dlthis->str_head +
+ BYTE_TO_HOST(input_sym->dn_offset);
+ else
+ dload_error(dlthis,
+ "Bad name offset in symbol "
+ " %d", symbols_left);
+#else
+ sname = unpack_name(dlthis,
+ input_sym->dn_offset);
+#endif
+ }
+ val = input_sym->dn_value;
+ delta = 0;
+ sp->sclass = input_sym->dn_sclass;
+ sp->secnn = input_sym->dn_scnum;
+ /* if this is an undefined symbol,
+ * define it (or fail) now */
+ if (sp->secnn == DN_UNDEF) {
+ /* pointless for static undefined */
+ if (input_sym->dn_sclass != DN_EXT)
+ goto loop_cont;
+
+ /* try to define symbol from previously
+ * loaded images */
+ symp = dlthis->mysym->find_matching_symbol
+ (dlthis->mysym, sname);
+ if (!symp) {
+ DL_ERROR
+ ("Undefined external symbol %s",
+ sname);
+ goto loop_cont;
+ }
+ val = delta = symp->value;
+#ifdef ENABLE_TRAMP_DEBUG
+ dload_syms_error(dlthis->mysym,
+ "===> ext sym [%s] at %x",
+ sname, val);
+#endif
+
+ goto loop_cont;
+ }
+ /* symbol defined by this module */
+ if (sp->secnn > 0) {
+ /* symbol references a section */
+ if ((unsigned)sp->secnn <=
+ dlthis->allocated_secn_count) {
+ /* section was allocated */
+ struct doff_scnhdr_t *srefp =
+ &dlthis->sect_hdrs[sp->secnn - 1];
+
+ if (input_sym->dn_sclass ==
+ DN_STATLAB ||
+ input_sym->dn_sclass == DN_EXTLAB) {
+ /* load */
+ delta = srefp->ds_vaddr;
+ } else {
+ /* run */
+ delta = srefp->ds_paddr;
+ }
+ val += delta;
+ }
+ goto loop_itr;
+ }
+ /* This symbol is an absolute symbol */
+ if (sp->secnn == DN_ABS && ((sp->sclass == DN_EXT) ||
+ (sp->sclass ==
+ DN_EXTLAB))) {
+ symp =
+ dlthis->mysym->find_matching_symbol(dlthis->
+ mysym,
+ sname);
+ if (!symp)
+ goto loop_itr;
+ /* This absolute symbol is already defined. */
+ if (symp->value == input_sym->dn_value) {
+ /* If symbol values are equal, continue
+ * but don't add to the global symbol
+ * table */
+ sp->value = val;
+ sp->delta = delta;
+ sp += 1;
+ input_sym += 1;
+ continue;
+ } else {
+ /* If symbol values are not equal,
+ * return with redefinition error */
+ DL_ERROR("Absolute symbol %s is "
+ "defined multiple times with "
+ "different values", sname);
+ return;
+ }
+ }
+loop_itr:
+ /* if this is a global symbol, post it to the
+ * global table */
+ if (input_sym->dn_sclass == DN_EXT ||
+ input_sym->dn_sclass == DN_EXTLAB) {
+ /* Keep this global symbol for subsequent
+ * modules. Don't complain on error, to allow
+ * symbol API to suppress global symbols */
+ if (!sname)
+ goto loop_cont;
+
+ newsym = dlthis->mysym->add_to_symbol_table
+ (dlthis->mysym, sname,
+ (unsigned)dlthis->myhandle);
+ if (newsym)
+ newsym->value = val;
+
+ } /* global */
+loop_cont:
+ sp->value = val;
+ sp->delta = delta;
+ sp += 1;
+ input_sym += 1;
+ } while ((syms_in_buf -= 1) > 0); /* process sym in buf */
+ } while (symbols_left > 0); /* read all symbols */
+ if (~checks)
+ dload_error(dlthis, "Checksum of symbols failed");
+
+} /* dload_symbols */
+
+/*****************************************************************************
+ * Procedure symbol_table_free
+ *
+ * Parameters:
+ * none
+ *
+ * Effect:
+ * Frees any state used by the symbol table.
+ *
+ * WARNING:
+ * This routine is not allowed to declare errors!
+ **************************************************************************** */
+static void symbol_table_free(struct dload_state *dlthis)
+{
+ if (dlthis->local_symtab) {
+ if (dlthis->dload_errcount) { /* blow off our symbols */
+ dlthis->mysym->purge_symbol_table(dlthis->mysym,
+ (unsigned)
+ dlthis->myhandle);
+ }
+ dlthis->mysym->dload_deallocate(dlthis->mysym,
+ dlthis->local_symtab);
+ }
+} /* symbol_table_free */
+
+/* .cinit Processing
+ *
+ * The dynamic loader does .cinit interpretation. cload_cinit()
+ * acts as a special write-to-target function, in that it takes relocated
+ * data from the normal data flow, and interprets it as .cinit actions.
+ * Because the normal data flow does not necessarily process the whole
+ * .cinit section in one buffer, cload_cinit() must be prepared to
+ * interpret the data piecemeal. A state machine is used for this
+ * purpose.
+ */
+
+/* The following are only for use by reloc.c and things it calls */
+static const struct ldr_section_info cinit_info_init = { cinitname, 0, 0,
+ (ldr_addr)-1, 0, DLOAD_BSS, 0
+};
+
+/*************************************************************************
+ * Procedure cload_cinit
+ *
+ * Parameters:
+ * ipacket Pointer to data packet to be loaded
+ *
+ * Effect:
+ * Interprets the data in the buffer as .cinit data, and performs the
+ * appropriate initializations.
+ *********************************************************************** */
+static void cload_cinit(struct dload_state *dlthis,
+ struct image_packet_t *ipacket)
+{
+#if TDATA_TO_HOST(CINIT_COUNT)*BITS_PER_AU > 16
+ s32 init_count, left;
+#else
+ s16 init_count, left;
+#endif
+ unsigned char *pktp = ipacket->img_data;
+ unsigned char *pktend = pktp + BYTE_TO_HOST_ROUND(ipacket->packet_size);
+ int temp;
+ ldr_addr atmp;
+ struct ldr_section_info cinit_info;
+
+ /* PROCESS ALL THE INITIALIZATION RECORDS THE BUFFER. */
+ while (true) {
+ left = pktend - pktp;
+ switch (dlthis->cinit_state) {
+ case CI_COUNT: /* count field */
+ if (left < TDATA_TO_HOST(CINIT_COUNT))
+ goto loopexit;
+ temp = dload_unpack(dlthis, (tgt_au_t *) pktp,
+ CINIT_COUNT * TDATA_AU_BITS, 0,
+ ROP_SGN);
+ pktp += TDATA_TO_HOST(CINIT_COUNT);
+ /* negative signifies BSS table, zero means done */
+ if (temp <= 0) {
+ dlthis->cinit_state = CI_DONE;
+ break;
+ }
+ dlthis->cinit_count = temp;
+ dlthis->cinit_state = CI_ADDRESS;
+ break;
+#if CINIT_ALIGN < CINIT_ADDRESS
+ case CI_PARTADDRESS:
+ pktp -= TDATA_TO_HOST(CINIT_ALIGN);
+ /* back up pointer into space courtesy of caller */
+ *(uint16_t *) pktp = dlthis->cinit_addr;
+ /* stuff in saved bits !! FALL THRU !! */
+#endif
+ case CI_ADDRESS: /* Address field for a copy packet */
+ if (left < TDATA_TO_HOST(CINIT_ADDRESS)) {
+#if CINIT_ALIGN < CINIT_ADDRESS
+ if (left == TDATA_TO_HOST(CINIT_ALIGN)) {
+ /* address broken into halves */
+ dlthis->cinit_addr = *(uint16_t *) pktp;
+ /* remember 1st half */
+ dlthis->cinit_state = CI_PARTADDRESS;
+ left = 0;
+ }
+#endif
+ goto loopexit;
+ }
+ atmp = dload_unpack(dlthis, (tgt_au_t *) pktp,
+ CINIT_ADDRESS * TDATA_AU_BITS, 0,
+ ROP_UNS);
+ pktp += TDATA_TO_HOST(CINIT_ADDRESS);
+#if CINIT_PAGE_BITS > 0
+ dlthis->cinit_page = atmp &
+ ((1 << CINIT_PAGE_BITS) - 1);
+ atmp >>= CINIT_PAGE_BITS;
+#else
+ dlthis->cinit_page = CINIT_DEFAULT_PAGE;
+#endif
+ dlthis->cinit_addr = atmp;
+ dlthis->cinit_state = CI_COPY;
+ break;
+ case CI_COPY: /* copy bits to the target */
+ init_count = HOST_TO_TDATA(left);
+ if (init_count > dlthis->cinit_count)
+ init_count = dlthis->cinit_count;
+ if (init_count == 0)
+ goto loopexit; /* get more bits */
+ cinit_info = cinit_info_init;
+ cinit_info.page = dlthis->cinit_page;
+ if (!dlthis->myio->writemem(dlthis->myio, pktp,
+ TDATA_TO_TADDR
+ (dlthis->cinit_addr),
+ &cinit_info,
+ TDATA_TO_HOST(init_count))) {
+ dload_error(dlthis, initfail, "write",
+ dlthis->cinit_addr);
+ }
+ dlthis->cinit_count -= init_count;
+ if (dlthis->cinit_count <= 0) {
+ dlthis->cinit_state = CI_COUNT;
+ init_count = (init_count + CINIT_ALIGN - 1) &
+ -CINIT_ALIGN;
+ /* align to next init */
+ }
+ pktp += TDATA_TO_HOST(init_count);
+ dlthis->cinit_addr += init_count;
+ break;
+ case CI_DONE: /* no more .cinit to do */
+ return;
+ } /* switch (cinit_state) */
+ } /* while */
+
+loopexit:
+ if (left > 0) {
+ dload_error(dlthis, "%d bytes left over in cinit packet", left);
+ dlthis->cinit_state = CI_DONE; /* left over bytes are bad */
+ }
+} /* cload_cinit */
+
+/* Functions to interface to reloc.c
+ *
+ * reloc.c is the relocation module borrowed from the linker, with
+ * minimal (we hope) changes for our purposes. cload_sect_data() invokes
+ * this module on a section to relocate and load the image data for that
+ * section. The actual read and write actions are supplied by the global
+ * routines below.
+ */
+
+/************************************************************************
+ * Procedure relocate_packet
+ *
+ * Parameters:
+ * ipacket Pointer to an image packet to relocate
+ *
+ * Effect:
+ * Performs the required relocations on the packet. Returns a checksum
+ * of the relocation operations.
+ *********************************************************************** */
+#define MY_RELOC_BUF_SIZ 8
+/* careful! exists at the same time as the image buffer */
+static int relocate_packet(struct dload_state *dlthis,
+ struct image_packet_t *ipacket,
+ u32 *checks, bool *tramps_generated)
+{
+ u32 rnum;
+ *tramps_generated = false;
+
+ rnum = ipacket->num_relocs;
+ do { /* all relocs */
+ unsigned rinbuf;
+ int siz;
+ struct reloc_record_t *rp, rrec[MY_RELOC_BUF_SIZ];
+ rp = rrec;
+ rinbuf = rnum > MY_RELOC_BUF_SIZ ? MY_RELOC_BUF_SIZ : rnum;
+ siz = rinbuf * sizeof(struct reloc_record_t);
+ if (dlthis->strm->read_buffer(dlthis->strm, rp, siz) != siz) {
+ DL_ERROR(readstrm, "relocation");
+ return 0;
+ }
+ /* reorder the bytes if need be */
+ if (dlthis->reorder_map)
+ dload_reorder(rp, siz, dlthis->reorder_map);
+
+ *checks += dload_checksum(rp, siz);
+ do {
+ /* perform the relocation operation */
+ dload_relocate(dlthis, (tgt_au_t *) ipacket->img_data,
+ rp, tramps_generated, false);
+ rp += 1;
+ rnum -= 1;
+ } while ((rinbuf -= 1) > 0);
+ } while (rnum > 0); /* all relocs */
+ /* If trampoline(s) were generated, we need to do an update of the
+ * trampoline copy of the packet since a 2nd phase relo will be done
+ * later. */
+ if (*tramps_generated == true) {
+ dload_tramp_pkt_udpate(dlthis,
+ (dlthis->image_secn -
+ dlthis->ldr_sections),
+ dlthis->image_offset, ipacket);
+ }
+
+ return 1;
+} /* dload_read_reloc */
+
+#define IPH_SIZE (sizeof(struct image_packet_t) - sizeof(u32))
+
+/* VERY dangerous */
+static const char imagepak[] = { "image packet" };
+
+/*************************************************************************
+ * Procedure dload_data
+ *
+ * Parameters:
+ * none
+ *
+ * Effect:
+ * Read image data from input file, relocate it, and download it to the
+ * target.
+ *********************************************************************** */
+static void dload_data(struct dload_state *dlthis)
+{
+ u16 curr_sect;
+ struct doff_scnhdr_t *sptr = dlthis->sect_hdrs;
+ struct ldr_section_info *lptr = dlthis->ldr_sections;
+#ifdef OPT_ZERO_COPY_LOADER
+ bool zero_copy = false;
+#endif
+ u8 *dest;
+
+ struct {
+ struct image_packet_t ipacket;
+ u8 bufr[BYTE_TO_HOST(IMAGE_PACKET_SIZE)];
+ } ibuf;
+
+ /* Indicates whether CINIT processing has occurred */
+ bool cinit_processed = false;
+
+ /* Loop through the sections and load them one at a time.
+ */
+ for (curr_sect = 0; curr_sect < dlthis->dfile_hdr.df_no_scns;
+ curr_sect += 1) {
+ if (ds_needs_download(sptr)) {
+ s32 nip;
+ ldr_addr image_offset = 0;
+ /* set relocation info for this section */
+ if (curr_sect < dlthis->allocated_secn_count)
+ dlthis->delta_runaddr = sptr->ds_paddr;
+ else {
+ lptr = (struct ldr_section_info *)sptr;
+ dlthis->delta_runaddr = 0;
+ }
+ dlthis->image_secn = lptr;
+#if BITS_PER_AU > BITS_PER_BYTE
+ lptr->name = unpack_name(dlthis, sptr->ds_offset);
+#endif
+ nip = sptr->ds_nipacks;
+ while ((nip -= 1) >= 0) { /* process packets */
+
+ s32 ipsize;
+ u32 checks;
+ bool tramp_generated = false;
+
+ /* get the fixed header bits */
+ if (dlthis->strm->read_buffer(dlthis->strm,
+ &ibuf.ipacket,
+ IPH_SIZE) !=
+ IPH_SIZE) {
+ DL_ERROR(readstrm, imagepak);
+ return;
+ }
+ /* reorder the header if need be */
+ if (dlthis->reorder_map) {
+ dload_reorder(&ibuf.ipacket, IPH_SIZE,
+ dlthis->reorder_map);
+ }
+ /* now read the rest of the packet */
+ ipsize =
+ BYTE_TO_HOST(DOFF_ALIGN
+ (ibuf.ipacket.packet_size));
+ if (ipsize > BYTE_TO_HOST(IMAGE_PACKET_SIZE)) {
+ DL_ERROR("Bad image packet size %d",
+ ipsize);
+ return;
+ }
+ dest = ibuf.bufr;
+#ifdef OPT_ZERO_COPY_LOADER
+ zero_copy = false;
+ if (!dload_check_type(sptr, DLOAD_CINIT) {
+ dlthis->myio->writemem(dlthis->myio,
+ &dest,
+ lptr->load_addr +
+ image_offset,
+ lptr, 0);
+ zero_copy = (dest != ibuf.bufr);
+ }
+#endif
+ /* End of determination */
+
+ if (dlthis->strm->read_buffer(dlthis->strm,
+ ibuf.bufr,
+ ipsize) !=
+ ipsize) {
+ DL_ERROR(readstrm, imagepak);
+ return;
+ }
+ ibuf.ipacket.img_data = dest;
+
+ /* reorder the bytes if need be */
+#if !defined(_BIG_ENDIAN) || (TARGET_AU_BITS > 16)
+ if (dlthis->reorder_map) {
+ dload_reorder(dest, ipsize,
+ dlthis->reorder_map);
+ }
+ checks = dload_checksum(dest, ipsize);
+#else
+ if (dlthis->dfile_hdr.df_byte_reshuffle !=
+ TARGET_ORDER(REORDER_MAP
+ (BYTE_RESHUFFLE_VALUE))) {
+ /* put image bytes in big-endian order,
+ * not PC order */
+ dload_reorder(dest, ipsize,
+ TARGET_ORDER
+ (dlthis->dfile_hdr.
+ df_byte_reshuffle));
+ }
+#if TARGET_AU_BITS > 8
+ checks = dload_reverse_checksum16(dest, ipsize);
+#else
+ checks = dload_reverse_checksum(dest, ipsize);
+#endif
+#endif
+
+ checks += dload_checksum(&ibuf.ipacket,
+ IPH_SIZE);
+ /* relocate the image bits as needed */
+ if (ibuf.ipacket.num_relocs) {
+ dlthis->image_offset = image_offset;
+ if (!relocate_packet(dlthis,
+ &ibuf.ipacket,
+ &checks,
+ &tramp_generated))
+ return; /* serious error */
+ }
+ if (~checks)
+ DL_ERROR(err_checksum, imagepak);
+ /* Only write the result to the target if no
+ * trampoline was generated. Otherwise it
+ *will be done during trampoline finalize. */
+
+ if (tramp_generated == false) {
+
+ /* stuff the result into target
+ * memory */
+ if (dload_check_type(sptr,
+ DLOAD_CINIT)) {
+ cload_cinit(dlthis,
+ &ibuf.ipacket);
+ cinit_processed = true;
+ } else {
+#ifdef OPT_ZERO_COPY_LOADER
+ if (!zero_copy) {
+#endif
+ /* FIXME */
+ if (!dlthis->myio->
+ writemem(dlthis->
+ myio,
+ ibuf.bufr,
+ lptr->
+ load_addr +
+ image_offset,
+ lptr,
+ BYTE_TO_HOST
+ (ibuf.
+ ipacket.
+ packet_size))) {
+ DL_ERROR
+ ("Write to "
+ FMT_UI32
+ " failed",
+ lptr->
+ load_addr +
+ image_offset);
+ }
+#ifdef OPT_ZERO_COPY_LOADER
+ }
+#endif
+ }
+ }
+ image_offset +=
+ BYTE_TO_TADDR(ibuf.ipacket.packet_size);
+ } /* process packets */
+ /* if this is a BSS section, we may want to fill it */
+ if (!dload_check_type(sptr, DLOAD_BSS))
+ goto loop_cont;
+
+ if (!(dlthis->myoptions & DLOAD_INITBSS))
+ goto loop_cont;
+
+ if (cinit_processed) {
+ /* Don't clear BSS after load-time
+ * initialization */
+ DL_ERROR
+ ("Zero-initialization at " FMT_UI32
+ " after " "load-time initialization!",
+ lptr->load_addr);
+ goto loop_cont;
+ }
+ /* fill the .bss area */
+ dlthis->myio->fillmem(dlthis->myio,
+ TADDR_TO_HOST(lptr->load_addr),
+ lptr, TADDR_TO_HOST(lptr->size),
+ DLOAD_FILL_BSS);
+ goto loop_cont;
+ }
+ /* if DS_DOWNLOAD_MASK */
+ /* If not loading, but BSS, zero initialize */
+ if (!dload_check_type(sptr, DLOAD_BSS))
+ goto loop_cont;
+
+ if (!(dlthis->myoptions & DLOAD_INITBSS))
+ goto loop_cont;
+
+ if (curr_sect >= dlthis->allocated_secn_count)
+ lptr = (struct ldr_section_info *)sptr;
+
+ if (cinit_processed) {
+ /*Don't clear BSS after load-time initialization */
+ DL_ERROR("Zero-initialization at " FMT_UI32
+ " attempted after "
+ "load-time initialization!", lptr->load_addr);
+ goto loop_cont;
+ }
+ /* fill the .bss area */
+ dlthis->myio->fillmem(dlthis->myio,
+ TADDR_TO_HOST(lptr->load_addr), lptr,
+ TADDR_TO_HOST(lptr->size),
+ DLOAD_FILL_BSS);
+loop_cont:
+ sptr += 1;
+ lptr += 1;
+ } /* load sections */
+
+ /* Finalize any trampolines that were created during the load */
+ if (dload_tramp_finalize(dlthis) == 0) {
+ DL_ERROR("Finalization of auto-trampolines (size = " FMT_UI32
+ ") failed", dlthis->tramp.tramp_sect_next_addr);
+ }
+} /* dload_data */
+
+/*************************************************************************
+ * Procedure dload_reorder
+ *
+ * Parameters:
+ * data 32-bit aligned pointer to data to be byte-swapped
+ * dsiz size of the data to be reordered in sizeof() units.
+ * map 32-bit map defining how to reorder the data. Value
+ * must be REORDER_MAP() of some permutation
+ * of 0x00 01 02 03
+ *
+ * Effect:
+ * Re-arranges the bytes in each word according to the map specified.
+ *
+ *********************************************************************** */
+/* mask for byte shift count */
+#define SHIFT_COUNT_MASK (3 << LOG_BITS_PER_BYTE)
+
+void dload_reorder(void *data, int dsiz, unsigned int map)
+{
+ register u32 tmp, tmap, datv;
+ u32 *dp = (u32 *) data;
+
+ map <<= LOG_BITS_PER_BYTE; /* align map with SHIFT_COUNT_MASK */
+ do {
+ tmp = 0;
+ datv = *dp;
+ tmap = map;
+ do {
+ tmp |= (datv & BYTE_MASK) << (tmap & SHIFT_COUNT_MASK);
+ tmap >>= BITS_PER_BYTE;
+ } while (datv >>= BITS_PER_BYTE);
+ *dp++ = tmp;
+ } while ((dsiz -= sizeof(u32)) > 0);
+} /* dload_reorder */
+
+/*************************************************************************
+ * Procedure dload_checksum
+ *
+ * Parameters:
+ * data 32-bit aligned pointer to data to be checksummed
+ * siz size of the data to be checksummed in sizeof() units.
+ *
+ * Effect:
+ * Returns a checksum of the specified block
+ *
+ *********************************************************************** */
+u32 dload_checksum(void *data, unsigned siz)
+{
+ u32 sum;
+ u32 *dp;
+ int left;
+
+ sum = 0;
+ dp = (u32 *) data;
+ for (left = siz; left > 0; left -= sizeof(u32))
+ sum += *dp++;
+ return sum;
+} /* dload_checksum */
+
+#if HOST_ENDIANNESS
+/*************************************************************************
+ * Procedure dload_reverse_checksum
+ *
+ * Parameters:
+ * data 32-bit aligned pointer to data to be checksummed
+ * siz size of the data to be checksummed in sizeof() units.
+ *
+ * Effect:
+ * Returns a checksum of the specified block, which is assumed to be bytes
+ * in big-endian order.
+ *
+ * Notes:
+ * In a big-endian host, things like the string table are stored as bytes
+ * in host order. But dllcreate always checksums in little-endian order.
+ * It is most efficient to just handle the difference a word at a time.
+ *
+ ********************************************************************** */
+u32 dload_reverse_checksum(void *data, unsigned siz)
+{
+ u32 sum, temp;
+ u32 *dp;
+ int left;
+
+ sum = 0;
+ dp = (u32 *) data;
+
+ for (left = siz; left > 0; left -= sizeof(u32)) {
+ temp = *dp++;
+ sum += temp << BITS_PER_BYTE * 3;
+ sum += temp >> BITS_PER_BYTE * 3;
+ sum += (temp >> BITS_PER_BYTE) & (BYTE_MASK << BITS_PER_BYTE);
+ sum += (temp & (BYTE_MASK << BITS_PER_BYTE)) << BITS_PER_BYTE;
+ }
+
+ return sum;
+} /* dload_reverse_checksum */
+
+#if (TARGET_AU_BITS > 8) && (TARGET_AU_BITS < 32)
+u32 dload_reverse_checksum16(void *data, unsigned siz)
+{
+ uint_fast32_t sum, temp;
+ u32 *dp;
+ int left;
+
+ sum = 0;
+ dp = (u32 *) data;
+
+ for (left = siz; left > 0; left -= sizeof(u32)) {
+ temp = *dp++;
+ sum += temp << BITS_PER_BYTE * 2;
+ sum += temp >> BITS_PER_BYTE * 2;
+ }
+
+ return sum;
+} /* dload_reverse_checksum16 */
+#endif
+#endif
+
+/*************************************************************************
+ * Procedure swap_words
+ *
+ * Parameters:
+ * data 32-bit aligned pointer to data to be swapped
+ * siz size of the data to be swapped.
+ * bitmap Bit map of how to swap each 32-bit word; 1 => 2 shorts,
+ * 0 => 1 long
+ *
+ * Effect:
+ * Swaps the specified data according to the specified map
+ *
+ *********************************************************************** */
+static void swap_words(void *data, unsigned siz, unsigned bitmap)
+{
+ register int i;
+#if TARGET_AU_BITS < 16
+ register u16 *sp;
+#endif
+ register u32 *lp;
+
+ siz /= sizeof(u16);
+
+#if TARGET_AU_BITS < 16
+ /* pass 1: do all the bytes */
+ i = siz;
+ sp = (u16 *) data;
+ do {
+ register u16 tmp;
+ tmp = *sp;
+ *sp++ = SWAP16BY8(tmp);
+ } while ((i -= 1) > 0);
+#endif
+
+#if TARGET_AU_BITS < 32
+ /* pass 2: fixup the 32-bit words */
+ i = siz >> 1;
+ lp = (u32 *) data;
+ do {
+ if ((bitmap & 1) == 0) {
+ register u32 tmp;
+ tmp = *lp;
+ *lp = SWAP32BY16(tmp);
+ }
+ lp += 1;
+ bitmap >>= 1;
+ } while ((i -= 1) > 0);
+#endif
+} /* swap_words */
+
+/*************************************************************************
+ * Procedure copy_tgt_strings
+ *
+ * Parameters:
+ * dstp Destination address. Assumed to be 32-bit aligned
+ * srcp Source address. Assumed to be 32-bit aligned
+ * charcount Number of characters to copy.
+ *
+ * Effect:
+ * Copies strings from the source (which is in usual .dof file order on
+ * the loading processor) to the destination buffer (which should be in proper
+ * target addressable unit order). Makes sure the last string in the
+ * buffer is NULL terminated (for safety).
+ * Returns the first unused destination address.
+ *********************************************************************** */
+static char *copy_tgt_strings(void *dstp, void *srcp, unsigned charcount)
+{
+ register tgt_au_t *src = (tgt_au_t *) srcp;
+ register tgt_au_t *dst = (tgt_au_t *) dstp;
+ register int cnt = charcount;
+ do {
+#if TARGET_AU_BITS <= BITS_PER_AU
+ /* byte-swapping issues may exist for strings on target */
+ *dst++ = *src++;
+#else
+ *dst++ = *src++;
+#endif
+ } while ((cnt -= (sizeof(tgt_au_t) * BITS_PER_AU / BITS_PER_BYTE)) > 0);
+ /*apply force to make sure that the string table has null terminator */
+#if (BITS_PER_AU == BITS_PER_BYTE) && (TARGET_AU_BITS == BITS_PER_BYTE)
+ dst[-1] = 0;
+#else
+ /* little endian */
+ dst[-1] &= (1 << (BITS_PER_AU - BITS_PER_BYTE)) - 1;
+#endif
+ return (char *)dst;
+} /* copy_tgt_strings */
+
+/*************************************************************************
+ * Procedure init_module_handle
+ *
+ * Parameters:
+ * none
+ *
+ * Effect:
+ * Initializes the module handle we use to enable unloading, and installs
+ * the debug information required by the target.
+ *
+ * Notes:
+ * The handle returned from dynamic_load_module needs to encapsulate all the
+ * allocations done for the module, and enable them plus the modules symbols to
+ * be deallocated.
+ *
+ *********************************************************************** */
+#ifndef _BIG_ENDIAN
+static const struct ldr_section_info dllview_info_init = { ".dllview", 0, 0,
+ (ldr_addr)-1, DBG_LIST_PAGE, DLOAD_DATA, 0
+};
+#else
+static const struct ldr_section_info dllview_info_init = { ".dllview", 0, 0,
+ (ldr_addr)-1, DLOAD_DATA, DBG_LIST_PAGE, 0
+};
+#endif
+static void init_module_handle(struct dload_state *dlthis)
+{
+ struct my_handle *hndl;
+ u16 curr_sect;
+ struct ldr_section_info *asecs;
+ struct dll_module *dbmod;
+ struct dll_sect *dbsec;
+ struct dbg_mirror_root *mlist;
+ register char *cp;
+ struct modules_header mhdr;
+ struct ldr_section_info dllview_info;
+ struct dynload_symbol *debug_mirror_sym;
+ hndl = dlthis->myhandle;
+ if (!hndl)
+ return; /* must be errors detected, so forget it */
+
+ /* Store the section count */
+ hndl->secn_count = dlthis->allocated_secn_count;
+
+ /* If a trampoline section was created, add it in */
+ if (dlthis->tramp.tramp_sect_next_addr != 0)
+ hndl->secn_count += 1;
+
+ hndl->secn_count = hndl->secn_count << 1;
+
+ hndl->secn_count = dlthis->allocated_secn_count << 1;
+#ifndef TARGET_ENDIANNESS
+ if (dlthis->big_e_target)
+ hndl->secn_count += 1; /* flag for big-endian */
+#endif
+ if (dlthis->dload_errcount)
+ return; /* abandon if errors detected */
+ /* Locate the symbol that names the header for the CCS debug list
+ of modules. If not found, we just don't generate the debug record.
+ If found, we create our modules list. We make sure to create the
+ loader_dllview_root even if there is no relocation info to record,
+ just to try to put both symbols in the same symbol table and
+ module. */
+ debug_mirror_sym = dlthis->mysym->find_matching_symbol(dlthis->mysym,
+ loader_dllview_root);
+ if (!debug_mirror_sym) {
+ struct dynload_symbol *dlmodsym;
+ struct dbg_mirror_root *mlst;
+
+ /* our root symbol is not yet present;
+ check if we have DLModules defined */
+ dlmodsym = dlthis->mysym->find_matching_symbol(dlthis->mysym,
+ LINKER_MODULES_HEADER);
+ if (!dlmodsym)
+ return; /* no DLModules list so no debug info */
+ /* if we have DLModules defined, construct our header */
+ mlst = (struct dbg_mirror_root *)
+ dlthis->mysym->dload_allocate(dlthis->mysym,
+ sizeof(struct
+ dbg_mirror_root));
+ if (!mlst) {
+ DL_ERROR(err_alloc, sizeof(struct dbg_mirror_root));
+ return;
+ }
+ mlst->hnext = NULL;
+ mlst->changes = 0;
+ mlst->refcount = 0;
+ mlst->dbthis = TDATA_TO_TADDR(dlmodsym->value);
+ /* add our root symbol */
+ debug_mirror_sym = dlthis->mysym->add_to_symbol_table
+ (dlthis->mysym, loader_dllview_root,
+ (unsigned)dlthis->myhandle);
+ if (!debug_mirror_sym) {
+ /* failed, recover memory */
+ dlthis->mysym->dload_deallocate(dlthis->mysym, mlst);
+ return;
+ }
+ debug_mirror_sym->value = (u32) mlst;
+ }
+ /* First create the DLLview record and stuff it into the buffer.
+ Then write it to the DSP. Record pertinent locations in our hndl,
+ and add it to the per-processor list of handles with debug info. */
+#ifndef DEBUG_HEADER_IN_LOADER
+ mlist = (struct dbg_mirror_root *)debug_mirror_sym->value;
+ if (!mlist)
+ return;
+#else
+ mlist = (struct dbg_mirror_root *)&debug_list_header;
+#endif
+ hndl->dm.hroot = mlist; /* set pointer to root into our handle */
+ if (!dlthis->allocated_secn_count)
+ return; /* no load addresses to be recorded */
+ /* reuse temporary symbol storage */
+ dbmod = (struct dll_module *)dlthis->local_symtab;
+ /* Create the DLLview record in the memory we retain for our handle */
+ dbmod->num_sects = dlthis->allocated_secn_count;
+ dbmod->timestamp = dlthis->verify.dv_timdat;
+ dbmod->version = INIT_VERSION;
+ dbmod->verification = VERIFICATION;
+ asecs = dlthis->ldr_sections;
+ dbsec = dbmod->sects;
+ for (curr_sect = dlthis->allocated_secn_count;
+ curr_sect > 0; curr_sect -= 1) {
+ dbsec->sect_load_adr = asecs->load_addr;
+ dbsec->sect_run_adr = asecs->run_addr;
+ dbsec += 1;
+ asecs += 1;
+ }
+
+ /* If a trampoline section was created go ahead and add its info */
+ if (dlthis->tramp.tramp_sect_next_addr != 0) {
+ dbmod->num_sects++;
+ dbsec->sect_load_adr = asecs->load_addr;
+ dbsec->sect_run_adr = asecs->run_addr;
+ dbsec++;
+ asecs++;
+ }
+
+ /* now cram in the names */
+ cp = copy_tgt_strings(dbsec, dlthis->str_head,
+ dlthis->debug_string_size);
+
+ /* If a trampoline section was created, add its name so DLLView
+ * can show the user the section info. */
+ if (dlthis->tramp.tramp_sect_next_addr != 0) {
+ cp = copy_tgt_strings(cp,
+ dlthis->tramp.final_string_table,
+ strlen(dlthis->tramp.final_string_table) +
+ 1);
+ }
+
+ /* round off the size of the debug record, and remember same */
+ hndl->dm.dbsiz = HOST_TO_TDATA_ROUND(cp - (char *)dbmod);
+ *cp = 0; /* strictly to make our test harness happy */
+ dllview_info = dllview_info_init;
+ dllview_info.size = TDATA_TO_TADDR(hndl->dm.dbsiz);
+ /* Initialize memory context to default heap */
+ dllview_info.context = 0;
+ hndl->dm.context = 0;
+ /* fill in next pointer and size */
+ if (mlist->hnext) {
+ dbmod->next_module = TADDR_TO_TDATA(mlist->hnext->dm.dbthis);
+ dbmod->next_module_size = mlist->hnext->dm.dbsiz;
+ } else {
+ dbmod->next_module_size = 0;
+ dbmod->next_module = 0;
+ }
+ /* allocate memory for on-DSP DLLview debug record */
+ if (!dlthis->myalloc)
+ return;
+ if (!dlthis->myalloc->dload_allocate(dlthis->myalloc, &dllview_info,
+ HOST_TO_TADDR(sizeof(u32)))) {
+ return;
+ }
+ /* Store load address of .dllview section */
+ hndl->dm.dbthis = dllview_info.load_addr;
+ /* Store memory context (segid) in which .dllview section
+ * was allocated */
+ hndl->dm.context = dllview_info.context;
+ mlist->refcount += 1;
+ /* swap bytes in the entire debug record, but not the string table */
+ if (TARGET_ENDIANNESS_DIFFERS(TARGET_BIG_ENDIAN)) {
+ swap_words(dbmod, (char *)dbsec - (char *)dbmod,
+ DLL_MODULE_BITMAP);
+ }
+ /* Update the DLLview list on the DSP write new record */
+ if (!dlthis->myio->writemem(dlthis->myio, dbmod,
+ dllview_info.load_addr, &dllview_info,
+ TADDR_TO_HOST(dllview_info.size))) {
+ return;
+ }
+ /* write new header */
+ mhdr.first_module_size = hndl->dm.dbsiz;
+ mhdr.first_module = TADDR_TO_TDATA(dllview_info.load_addr);
+ /* swap bytes in the module header, if needed */
+ if (TARGET_ENDIANNESS_DIFFERS(TARGET_BIG_ENDIAN)) {
+ swap_words(&mhdr, sizeof(struct modules_header) - sizeof(u16),
+ MODULES_HEADER_BITMAP);
+ }
+ dllview_info = dllview_info_init;
+ if (!dlthis->myio->writemem(dlthis->myio, &mhdr, mlist->dbthis,
+ &dllview_info,
+ sizeof(struct modules_header) -
+ sizeof(u16))) {
+ return;
+ }
+ /* Add the module handle to this processor's list
+ of handles with debug info */
+ hndl->dm.hnext = mlist->hnext;
+ if (hndl->dm.hnext)
+ hndl->dm.hnext->dm.hprev = hndl;
+ hndl->dm.hprev = (struct my_handle *)mlist;
+ mlist->hnext = hndl; /* insert after root */
+} /* init_module_handle */
+
+/*************************************************************************
+ * Procedure dynamic_unload_module
+ *
+ * Parameters:
+ * mhandle A module handle from dynamic_load_module
+ * syms Host-side symbol table and malloc/free functions
+ * alloc Target-side memory allocation
+ *
+ * Effect:
+ * The module specified by mhandle is unloaded. Unloading causes all
+ * target memory to be deallocated, all symbols defined by the module to
+ * be purged, and any host-side storage used by the dynamic loader for
+ * this module to be released.
+ *
+ * Returns:
+ * Zero for success. On error, the number of errors detected is returned.
+ * Individual errors are reported using syms->error_report().
+ *********************************************************************** */
+int dynamic_unload_module(void *mhandle,
+ struct dynamic_loader_sym *syms,
+ struct dynamic_loader_allocate *alloc,
+ struct dynamic_loader_initialize *init)
+{
+ s16 curr_sect;
+ struct ldr_section_info *asecs;
+ struct my_handle *hndl;
+ struct dbg_mirror_root *root;
+ unsigned errcount = 0;
+ struct ldr_section_info dllview_info = dllview_info_init;
+ struct modules_header mhdr;
+
+ hndl = (struct my_handle *)mhandle;
+ if (!hndl)
+ return 0; /* if handle is null, nothing to do */
+ /* Clear out the module symbols
+ * Note that if this is the module that defined MODULES_HEADER
+ (the head of the target debug list)
+ * then this operation will blow away that symbol.
+ It will therefore be impossible for subsequent
+ * operations to add entries to this un-referenceable list. */
+ if (!syms)
+ return 1;
+ syms->purge_symbol_table(syms, (unsigned)hndl);
+ /* Deallocate target memory for sections
+ * NOTE: The trampoline section, if created, gets deleted here, too */
+
+ asecs = hndl->secns;
+ if (alloc)
+ for (curr_sect = (hndl->secn_count >> 1); curr_sect > 0;
+ curr_sect -= 1) {
+ asecs->name = NULL;
+ alloc->dload_deallocate(alloc, asecs++);
+ }
+ root = hndl->dm.hroot;
+ if (!root) {
+ /* there is a debug list containing this module */
+ goto func_end;
+ }
+ if (!hndl->dm.dbthis) { /* target-side dllview record exists */
+ goto loop_end;
+ }
+ /* Retrieve memory context in which .dllview was allocated */
+ dllview_info.context = hndl->dm.context;
+ if (hndl->dm.hprev == hndl)
+ goto exitunltgt;
+
+ /* target-side dllview record is in list */
+ /* dequeue this record from our GPP-side mirror list */
+ hndl->dm.hprev->dm.hnext = hndl->dm.hnext;
+ if (hndl->dm.hnext)
+ hndl->dm.hnext->dm.hprev = hndl->dm.hprev;
+ /* Update next_module of previous entry in target list
+ * We are using mhdr here as a surrogate for either a
+ struct modules_header or a dll_module */
+ if (hndl->dm.hnext) {
+ mhdr.first_module = TADDR_TO_TDATA(hndl->dm.hnext->dm.dbthis);
+ mhdr.first_module_size = hndl->dm.hnext->dm.dbsiz;
+ } else {
+ mhdr.first_module = 0;
+ mhdr.first_module_size = 0;
+ }
+ if (!init)
+ goto exitunltgt;
+
+ if (!init->connect(init)) {
+ dload_syms_error(syms, iconnect);
+ errcount += 1;
+ goto exitunltgt;
+ }
+ /* swap bytes in the module header, if needed */
+ if (TARGET_ENDIANNESS_DIFFERS(hndl->secn_count & 0x1)) {
+ swap_words(&mhdr, sizeof(struct modules_header) - sizeof(u16),
+ MODULES_HEADER_BITMAP);
+ }
+ if (!init->writemem(init, &mhdr, hndl->dm.hprev->dm.dbthis,
+ &dllview_info, sizeof(struct modules_header) -
+ sizeof(mhdr.update_flag))) {
+ dload_syms_error(syms, dlvwrite);
+ errcount += 1;
+ }
+ /* update change counter */
+ root->changes += 1;
+ if (!init->writemem(init, &(root->changes),
+ root->dbthis + HOST_TO_TADDR
+ (sizeof(mhdr.first_module) +
+ sizeof(mhdr.first_module_size)),
+ &dllview_info, sizeof(mhdr.update_flag))) {
+ dload_syms_error(syms, dlvwrite);
+ errcount += 1;
+ }
+ init->release(init);
+exitunltgt:
+ /* release target storage */
+ dllview_info.size = TDATA_TO_TADDR(hndl->dm.dbsiz);
+ dllview_info.load_addr = hndl->dm.dbthis;
+ if (alloc)
+ alloc->dload_deallocate(alloc, &dllview_info);
+ root->refcount -= 1;
+ /* target-side dllview record exists */
+loop_end:
+#ifndef DEBUG_HEADER_IN_LOADER
+ if (root->refcount <= 0) {
+ /* if all references gone, blow off the header */
+ /* our root symbol may be gone due to the Purge above,
+ but if not, do not destroy the root */
+ if (syms->find_matching_symbol
+ (syms, loader_dllview_root) == NULL)
+ syms->dload_deallocate(syms, root);
+ }
+#endif
+func_end:
+ /* there is a debug list containing this module */
+ syms->dload_deallocate(syms, mhandle); /* release our storage */
+ return errcount;
+} /* dynamic_unload_module */
+
+#if BITS_PER_AU > BITS_PER_BYTE
+/*************************************************************************
+ * Procedure unpack_name
+ *
+ * Parameters:
+ * soffset Byte offset into the string table
+ *
+ * Effect:
+ * Returns a pointer to the string specified by the offset supplied, or
+ * NULL for error.
+ *
+ *********************************************************************** */
+static char *unpack_name(struct dload_state *dlthis, u32 soffset)
+{
+ u8 tmp, *src;
+ char *dst;
+
+ if (soffset >= dlthis->dfile_hdr.df_strtab_size) {
+ dload_error(dlthis, "Bad string table offset " FMT_UI32,
+ soffset);
+ return NULL;
+ }
+ src = (uint_least8_t *) dlthis->str_head +
+ (soffset >> (LOG_BITS_PER_AU - LOG_BITS_PER_BYTE));
+ dst = dlthis->str_temp;
+ if (soffset & 1)
+ *dst++ = *src++; /* only 1 character in first word */
+ do {
+ tmp = *src++;
+ *dst = (tmp >> BITS_PER_BYTE);
+ if (!(*dst++))
+ break;
+ } while ((*dst++ = tmp & BYTE_MASK));
+ dlthis->temp_len = dst - dlthis->str_temp;
+ /* squirrel away length including terminating null */
+ return dlthis->str_temp;
+} /* unpack_name */
+#endif
diff --git a/drivers/staging/tidspbridge/dynload/dload_internal.h b/drivers/staging/tidspbridge/dynload/dload_internal.h
new file mode 100644
index 00000000000..302a7c53e12
--- /dev/null
+++ b/drivers/staging/tidspbridge/dynload/dload_internal.h
@@ -0,0 +1,344 @@
+/*
+ * dload_internal.h
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * Copyright (C) 2005-2006 Texas Instruments, Inc.
+ *
+ * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef _DLOAD_INTERNAL_
+#define _DLOAD_INTERNAL_
+
+#include <linux/types.h>
+
+/*
+ * Internal state definitions for the dynamic loader
+ */
+
+/* type used for relocation intermediate results */
+typedef s32 rvalue;
+
+/* unsigned version of same; must have at least as many bits */
+typedef u32 urvalue;
+
+/*
+ * Dynamic loader configuration constants
+ */
+/* error issued if input has more sections than this limit */
+#define REASONABLE_SECTION_LIMIT 100
+
+/* (Addressable unit) value used to clear BSS section */
+#define DLOAD_FILL_BSS 0
+
+/*
+ * Reorder maps explained (?)
+ *
+ * The doff file format defines a 32-bit pattern used to determine the
+ * byte order of an image being read. That value is
+ * BYTE_RESHUFFLE_VALUE == 0x00010203
+ * For purposes of the reorder routine, we would rather have the all-is-OK
+ * for 32-bits pattern be 0x03020100. This first macro makes the
+ * translation from doff file header value to MAP value: */
+#define REORDER_MAP(rawmap) ((rawmap) ^ 0x3030303)
+/* This translation is made in dload_headers. Thereafter, the all-is-OK
+ * value for the maps stored in dlthis is REORDER_MAP(BYTE_RESHUFFLE_VALUE).
+ * But sadly, not all bits of the doff file are 32-bit integers.
+ * The notable exceptions are strings and image bits.
+ * Strings obey host byte order: */
+#if defined(_BIG_ENDIAN)
+#define HOST_BYTE_ORDER(cookedmap) ((cookedmap) ^ 0x3030303)
+#else
+#define HOST_BYTE_ORDER(cookedmap) (cookedmap)
+#endif
+/* Target bits consist of target AUs (could be bytes, or 16-bits,
+ * or 32-bits) stored as an array in host order. A target order
+ * map is defined by: */
+#if !defined(_BIG_ENDIAN) || TARGET_AU_BITS > 16
+#define TARGET_ORDER(cookedmap) (cookedmap)
+#elif TARGET_AU_BITS > 8
+#define TARGET_ORDER(cookedmap) ((cookedmap) ^ 0x2020202)
+#else
+#define TARGET_ORDER(cookedmap) ((cookedmap) ^ 0x3030303)
+#endif
+
+/* forward declaration for handle returned by dynamic loader */
+struct my_handle;
+
+/*
+ * a list of module handles, which mirrors the debug list on the target
+ */
+struct dbg_mirror_root {
+ /* must be same as dbg_mirror_list; __DLModules address on target */
+ u32 dbthis;
+ struct my_handle *hnext; /* must be same as dbg_mirror_list */
+ u16 changes; /* change counter */
+ u16 refcount; /* number of modules referencing this root */
+};
+
+struct dbg_mirror_list {
+ u32 dbthis;
+ struct my_handle *hnext, *hprev;
+ struct dbg_mirror_root *hroot;
+ u16 dbsiz;
+ u32 context; /* Save context for .dllview memory allocation */
+};
+
+#define VARIABLE_SIZE 1
+/*
+ * the structure we actually return as an opaque module handle
+ */
+struct my_handle {
+ struct dbg_mirror_list dm; /* !!! must be first !!! */
+ /* sections following << 1, LSB is set for big-endian target */
+ u16 secn_count;
+ struct ldr_section_info secns[VARIABLE_SIZE];
+};
+#define MY_HANDLE_SIZE (sizeof(struct my_handle) -\
+ sizeof(struct ldr_section_info))
+/* real size of my_handle */
+
+/*
+ * reduced symbol structure used for symbols during relocation
+ */
+struct local_symbol {
+ s32 value; /* Relocated symbol value */
+ s32 delta; /* Original value in input file */
+ s16 secnn; /* section number */
+ s16 sclass; /* symbol class */
+};
+
+/*
+ * Trampoline data structures
+ */
+#define TRAMP_NO_GEN_AVAIL 65535
+#define TRAMP_SYM_PREFIX "__$dbTR__"
+#define TRAMP_SECT_NAME ".dbTR"
+/* MUST MATCH THE LENGTH ABOVE!! */
+#define TRAMP_SYM_PREFIX_LEN 9
+/* Includes NULL termination */
+#define TRAMP_SYM_HEX_ASCII_LEN 9
+
+#define GET_CONTAINER(ptr, type, field) ((type *)((unsigned long)ptr -\
+ (unsigned long)(&((type *)0)->field)))
+#ifndef FIELD_OFFSET
+#define FIELD_OFFSET(type, field) ((unsigned long)(&((type *)0)->field))
+#endif
+
+/*
+ The trampoline code for the target is located in a table called
+ "tramp_gen_info" with is indexed by looking up the index in the table
+ "tramp_map". The tramp_map index is acquired using the target
+ HASH_FUNC on the relocation type that caused the trampoline. Each
+ trampoline code table entry MUST follow this format:
+
+ |----------------------------------------------|
+ | tramp_gen_code_hdr |
+ |----------------------------------------------|
+ | Trampoline image code |
+ | (the raw instruction code for the target) |
+ |----------------------------------------------|
+ | Relocation entries for the image code |
+ |----------------------------------------------|
+
+ This is very similar to how image data is laid out in the DOFF file
+ itself.
+ */
+struct tramp_gen_code_hdr {
+ u32 tramp_code_size; /* in BYTES */
+ u32 num_relos;
+ u32 relo_offset; /* in BYTES */
+};
+
+struct tramp_img_pkt {
+ struct tramp_img_pkt *next; /* MUST BE FIRST */
+ u32 base;
+ struct tramp_gen_code_hdr hdr;
+ u8 payload[VARIABLE_SIZE];
+};
+
+struct tramp_img_dup_relo {
+ struct tramp_img_dup_relo *next;
+ struct reloc_record_t relo;
+};
+
+struct tramp_img_dup_pkt {
+ struct tramp_img_dup_pkt *next; /* MUST BE FIRST */
+ s16 secnn;
+ u32 offset;
+ struct image_packet_t img_pkt;
+ struct tramp_img_dup_relo *relo_chain;
+
+ /* PAYLOAD OF IMG PKT FOLLOWS */
+};
+
+struct tramp_sym {
+ struct tramp_sym *next; /* MUST BE FIRST */
+ u32 index;
+ u32 str_index;
+ struct local_symbol sym_info;
+};
+
+struct tramp_string {
+ struct tramp_string *next; /* MUST BE FIRST */
+ u32 index;
+ char str[VARIABLE_SIZE]; /* NULL terminated */
+};
+
+struct tramp_info {
+ u32 tramp_sect_next_addr;
+ struct ldr_section_info sect_info;
+
+ struct tramp_sym *symbol_head;
+ struct tramp_sym *symbol_tail;
+ u32 tramp_sym_next_index;
+ struct local_symbol *final_sym_table;
+
+ struct tramp_string *string_head;
+ struct tramp_string *string_tail;
+ u32 tramp_string_next_index;
+ u32 tramp_string_size;
+ char *final_string_table;
+
+ struct tramp_img_pkt *tramp_pkts;
+ struct tramp_img_dup_pkt *dup_pkts;
+};
+
+/*
+ * States of the .cinit state machine
+ */
+enum cinit_mode {
+ CI_COUNT = 0, /* expecting a count */
+ CI_ADDRESS, /* expecting an address */
+#if CINIT_ALIGN < CINIT_ADDRESS /* handle case of partial address field */
+ CI_PARTADDRESS, /* have only part of the address */
+#endif
+ CI_COPY, /* in the middle of copying data */
+ CI_DONE /* end of .cinit table */
+};
+
+/*
+ * The internal state of the dynamic loader, which is passed around as
+ * an object
+ */
+struct dload_state {
+ struct dynamic_loader_stream *strm; /* The module input stream */
+ struct dynamic_loader_sym *mysym; /* Symbols for this session */
+ /* target memory allocator */
+ struct dynamic_loader_allocate *myalloc;
+ struct dynamic_loader_initialize *myio; /* target memory initializer */
+ unsigned myoptions; /* Options parameter dynamic_load_module */
+
+ char *str_head; /* Pointer to string table */
+#if BITS_PER_AU > BITS_PER_BYTE
+ char *str_temp; /* Pointer to temporary buffer for strings */
+ /* big enough to hold longest string */
+ unsigned temp_len; /* length of last temporary string */
+ char *xstrings; /* Pointer to buffer for expanded */
+ /* strings for sec names */
+#endif
+ /* Total size of strings for DLLView section names */
+ unsigned debug_string_size;
+ /* Pointer to parallel section info for allocated sections only */
+ struct doff_scnhdr_t *sect_hdrs; /* Pointer to section table */
+ struct ldr_section_info *ldr_sections;
+#if TMS32060
+ /* The address of the start of the .bss section */
+ ldr_addr bss_run_base;
+#endif
+ struct local_symbol *local_symtab; /* Relocation symbol table */
+
+ /* pointer to DL section info for the section being relocated */
+ struct ldr_section_info *image_secn;
+ /* change in run address for current section during relocation */
+ ldr_addr delta_runaddr;
+ ldr_addr image_offset; /* offset of current packet in section */
+ enum cinit_mode cinit_state; /* current state of cload_cinit() */
+ int cinit_count; /* the current count */
+ ldr_addr cinit_addr; /* the current address */
+ s16 cinit_page; /* the current page */
+ /* Handle to be returned by dynamic_load_module */
+ struct my_handle *myhandle;
+ unsigned dload_errcount; /* Total # of errors reported so far */
+ /* Number of target sections that require allocation and relocation */
+ unsigned allocated_secn_count;
+#ifndef TARGET_ENDIANNESS
+ int big_e_target; /* Target data in big-endian format */
+#endif
+ /* map for reordering bytes, 0 if not needed */
+ u32 reorder_map;
+ struct doff_filehdr_t dfile_hdr; /* DOFF file header structure */
+ struct doff_verify_rec_t verify; /* Verify record */
+
+ struct tramp_info tramp; /* Trampoline data, if needed */
+
+ int relstkidx; /* index into relocation value stack */
+ /* relocation value stack used in relexp.c */
+ rvalue relstk[STATIC_EXPR_STK_SIZE];
+
+};
+
+#ifdef TARGET_ENDIANNESS
+#define TARGET_BIG_ENDIAN TARGET_ENDIANNESS
+#else
+#define TARGET_BIG_ENDIAN (dlthis->big_e_target)
+#endif
+
+/*
+ * Exports from cload.c to rest of the world
+ */
+extern void dload_error(struct dload_state *dlthis, const char *errtxt, ...);
+extern void dload_syms_error(struct dynamic_loader_sym *syms,
+ const char *errtxt, ...);
+extern void dload_headers(struct dload_state *dlthis);
+extern void dload_strings(struct dload_state *dlthis, bool sec_names_only);
+extern void dload_sections(struct dload_state *dlthis);
+extern void dload_reorder(void *data, int dsiz, u32 map);
+extern u32 dload_checksum(void *data, unsigned siz);
+
+#if HOST_ENDIANNESS
+extern uint32_t dload_reverse_checksum(void *data, unsigned siz);
+#if (TARGET_AU_BITS > 8) && (TARGET_AU_BITS < 32)
+extern uint32_t dload_reverse_checksum16(void *data, unsigned siz);
+#endif
+#endif
+
+/*
+ * exported by reloc.c
+ */
+extern void dload_relocate(struct dload_state *dlthis, tgt_au_t * data,
+ struct reloc_record_t *rp, bool * tramps_generated,
+ bool second_pass);
+
+extern rvalue dload_unpack(struct dload_state *dlthis, tgt_au_t * data,
+ int fieldsz, int offset, unsigned sgn);
+
+extern int dload_repack(struct dload_state *dlthis, rvalue val, tgt_au_t * data,
+ int fieldsz, int offset, unsigned sgn);
+
+/*
+ * exported by tramp.c
+ */
+extern bool dload_tramp_avail(struct dload_state *dlthis,
+ struct reloc_record_t *rp);
+
+int dload_tramp_generate(struct dload_state *dlthis, s16 secnn,
+ u32 image_offset, struct image_packet_t *ipacket,
+ struct reloc_record_t *rp);
+
+extern int dload_tramp_pkt_udpate(struct dload_state *dlthis,
+ s16 secnn, u32 image_offset,
+ struct image_packet_t *ipacket);
+
+extern int dload_tramp_finalize(struct dload_state *dlthis);
+
+extern void dload_tramp_cleanup(struct dload_state *dlthis);
+
+#endif /* _DLOAD_INTERNAL_ */
diff --git a/drivers/staging/tidspbridge/dynload/doff.h b/drivers/staging/tidspbridge/dynload/doff.h
new file mode 100644
index 00000000000..a7c3145746e
--- /dev/null
+++ b/drivers/staging/tidspbridge/dynload/doff.h
@@ -0,0 +1,354 @@
+/*
+ * doff.h
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * Structures & definitions used for dynamically loaded modules file format.
+ * This format is a reformatted version of COFF. It optimizes the layout for
+ * the dynamic loader.
+ *
+ * .dof files, when viewed as a sequence of 32-bit integers, look the same
+ * on big-endian and little-endian machines.
+ *
+ * Copyright (C) 2005-2006 Texas Instruments, Inc.
+ *
+ * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef _DOFF_H
+#define _DOFF_H
+
+
+#define BYTE_RESHUFFLE_VALUE 0x00010203
+
+/* DOFF file header containing fields categorizing the remainder of the file */
+struct doff_filehdr_t {
+
+ /* string table size, including filename, in bytes */
+ u32 df_strtab_size;
+
+ /* entry point if one exists */
+ u32 df_entrypt;
+
+ /* identifies byte ordering of file;
+ * always set to BYTE_RESHUFFLE_VALUE */
+ u32 df_byte_reshuffle;
+
+ /* Size of the string table up to and including the last section name */
+ /* Size includes the name of the COFF file also */
+ u32 df_scn_name_size;
+
+#ifndef _BIG_ENDIAN
+ /* number of symbols */
+ u16 df_no_syms;
+
+ /* length in bytes of the longest string, including terminating NULL */
+ /* excludes the name of the file */
+ u16 df_max_str_len;
+
+ /* total number of sections including no-load ones */
+ u16 df_no_scns;
+
+ /* number of sections containing target code allocated or downloaded */
+ u16 df_target_scns;
+
+ /* unique id for dll file format & version */
+ u16 df_doff_version;
+
+ /* identifies ISA */
+ u16 df_target_id;
+
+ /* useful file flags */
+ u16 df_flags;
+
+ /* section reference for entry point, N_UNDEF for none, */
+ /* N_ABS for absolute address */
+ s16 df_entry_secn;
+#else
+ /* length of the longest string, including terminating NULL */
+ u16 df_max_str_len;
+
+ /* number of symbols */
+ u16 df_no_syms;
+
+ /* number of sections containing target code allocated or downloaded */
+ u16 df_target_scns;
+
+ /* total number of sections including no-load ones */
+ u16 df_no_scns;
+
+ /* identifies ISA */
+ u16 df_target_id;
+
+ /* unique id for dll file format & version */
+ u16 df_doff_version;
+
+ /* section reference for entry point, N_UNDEF for none, */
+ /* N_ABS for absolute address */
+ s16 df_entry_secn;
+
+ /* useful file flags */
+ u16 df_flags;
+#endif
+ /* checksum for file header record */
+ u32 df_checksum;
+
+};
+
+/* flags in the df_flags field */
+#define DF_LITTLE 0x100
+#define DF_BIG 0x200
+#define DF_BYTE_ORDER (DF_LITTLE | DF_BIG)
+
+/* Supported processors */
+#define TMS470_ID 0x97
+#define LEAD_ID 0x98
+#define TMS32060_ID 0x99
+#define LEAD3_ID 0x9c
+
+/* Primary processor for loading */
+#if TMS32060
+#define TARGET_ID TMS32060_ID
+#endif
+
+/* Verification record containing values used to test integrity of the bits */
+struct doff_verify_rec_t {
+
+ /* time and date stamp */
+ u32 dv_timdat;
+
+ /* checksum for all section records */
+ u32 dv_scn_rec_checksum;
+
+ /* checksum for string table */
+ u32 dv_str_tab_checksum;
+
+ /* checksum for symbol table */
+ u32 dv_sym_tab_checksum;
+
+ /* checksum for verification record */
+ u32 dv_verify_rec_checksum;
+
+};
+
+/* String table is an array of null-terminated strings. The first entry is
+ * the filename, which is added by DLLcreate. No new structure definitions
+ * are required.
+ */
+
+/* Section Records including information on the corresponding image packets */
+/*
+ * !!WARNING!!
+ *
+ * This structure is expected to match in form ldr_section_info in
+ * dynamic_loader.h
+ */
+
+struct doff_scnhdr_t {
+
+ s32 ds_offset; /* offset into string table of name */
+ s32 ds_paddr; /* RUN address, in target AU */
+ s32 ds_vaddr; /* LOAD address, in target AU */
+ s32 ds_size; /* section size, in target AU */
+#ifndef _BIG_ENDIAN
+ u16 ds_page; /* memory page id */
+ u16 ds_flags; /* section flags */
+#else
+ u16 ds_flags; /* section flags */
+ u16 ds_page; /* memory page id */
+#endif
+ u32 ds_first_pkt_offset;
+ /* Absolute byte offset into the file */
+ /* where the first image record resides */
+
+ s32 ds_nipacks; /* number of image packets */
+
+};
+
+/* Symbol table entry */
+struct doff_syment_t {
+
+ s32 dn_offset; /* offset into string table of name */
+ s32 dn_value; /* value of symbol */
+#ifndef _BIG_ENDIAN
+ s16 dn_scnum; /* section number */
+ s16 dn_sclass; /* storage class */
+#else
+ s16 dn_sclass; /* storage class */
+ s16 dn_scnum; /* section number, 1-based */
+#endif
+
+};
+
+/* special values for dn_scnum */
+#define DN_UNDEF 0 /* undefined symbol */
+#define DN_ABS (-1) /* value of symbol is absolute */
+/* special values for dn_sclass */
+#define DN_EXT 2
+#define DN_STATLAB 20
+#define DN_EXTLAB 21
+
+/* Default value of image bits in packet */
+/* Configurable by user on the command line */
+#define IMAGE_PACKET_SIZE 1024
+
+/* An image packet contains a chunk of data from a section along with */
+/* information necessary for its processing. */
+struct image_packet_t {
+
+ s32 num_relocs; /* number of relocations for */
+ /* this packet */
+
+ s32 packet_size; /* number of bytes in array */
+ /* "bits" occupied by */
+ /* valid data. Could be */
+ /* < IMAGE_PACKET_SIZE to */
+ /* prevent splitting a */
+ /* relocation across packets. */
+ /* Last packet of a section */
+ /* will most likely contain */
+ /* < IMAGE_PACKET_SIZE bytes */
+ /* of valid data */
+
+ s32 img_chksum; /* Checksum for image packet */
+ /* and the corresponding */
+ /* relocation records */
+
+ u8 *img_data; /* Actual data in section */
+
+};
+
+/* The relocation structure definition matches the COFF version. Offsets */
+/* however are relative to the image packet base not the section base. */
+struct reloc_record_t {
+
+ s32 vaddr;
+
+ /* expressed in target AUs */
+
+ union {
+ struct {
+#ifndef _BIG_ENDIAN
+ u8 _offset; /* bit offset of rel fld */
+ u8 _fieldsz; /* size of rel fld */
+ u8 _wordsz; /* # bytes containing rel fld */
+ u8 _dum1;
+ u16 _dum2;
+ u16 _type;
+#else
+ unsigned _dum1:8;
+ unsigned _wordsz:8; /* # bytes containing rel fld */
+ unsigned _fieldsz:8; /* size of rel fld */
+ unsigned _offset:8; /* bit offset of rel fld */
+ u16 _type;
+ u16 _dum2;
+#endif
+ } _r_field;
+
+ struct {
+ u32 _spc; /* image packet relative PC */
+#ifndef _BIG_ENDIAN
+ u16 _dum;
+ u16 _type; /* relocation type */
+#else
+ u16 _type; /* relocation type */
+ u16 _dum;
+#endif
+ } _r_spc;
+
+ struct {
+ u32 _uval; /* constant value */
+#ifndef _BIG_ENDIAN
+ u16 _dum;
+ u16 _type; /* relocation type */
+#else
+ u16 _type; /* relocation type */
+ u16 _dum;
+#endif
+ } _r_uval;
+
+ struct {
+ s32 _symndx; /* 32-bit sym tbl index */
+#ifndef _BIG_ENDIAN
+ u16 _disp; /* extra addr encode data */
+ u16 _type; /* relocation type */
+#else
+ u16 _type; /* relocation type */
+ u16 _disp; /* extra addr encode data */
+#endif
+ } _r_sym;
+ } _u_reloc;
+
+};
+
+/* abbreviations for convenience */
+#ifndef TYPE
+#define TYPE _u_reloc._r_sym._type
+#define UVAL _u_reloc._r_uval._uval
+#define SYMNDX _u_reloc._r_sym._symndx
+#define OFFSET _u_reloc._r_field._offset
+#define FIELDSZ _u_reloc._r_field._fieldsz
+#define WORDSZ _u_reloc._r_field._wordsz
+#define R_DISP _u_reloc._r_sym._disp
+#endif
+
+/**************************************************************************** */
+/* */
+/* Important DOFF macros used for file processing */
+/* */
+/**************************************************************************** */
+
+/* DOFF Versions */
+#define DOFF0 0
+
+/* Return the address/size >= to addr that is at a 32-bit boundary */
+/* This assumes that a byte is 8 bits */
+#define DOFF_ALIGN(addr) (((addr) + 3) & ~3UL)
+
+/**************************************************************************** */
+/* */
+/* The DOFF section header flags field is laid out as follows: */
+/* */
+/* Bits 0-3 : Section Type */
+/* Bit 4 : Set when section requires target memory to be allocated by DL */
+/* Bit 5 : Set when section requires downloading */
+/* Bits 8-11: Alignment, same as COFF */
+/* */
+/**************************************************************************** */
+
+/* Enum for DOFF section types (bits 0-3 of flag): See dynamic_loader.h */
+#define DS_SECTION_TYPE_MASK 0xF
+/* DS_ALLOCATE indicates whether a section needs space on the target */
+#define DS_ALLOCATE_MASK 0x10
+/* DS_DOWNLOAD indicates that the loader needs to copy bits */
+#define DS_DOWNLOAD_MASK 0x20
+/* Section alignment requirement in AUs */
+#define DS_ALIGNMENT_SHIFT 8
+
+static inline bool dload_check_type(struct doff_scnhdr_t *sptr, u32 flag)
+{
+ return (sptr->ds_flags & DS_SECTION_TYPE_MASK) == flag;
+}
+static inline bool ds_needs_allocation(struct doff_scnhdr_t *sptr)
+{
+ return sptr->ds_flags & DS_ALLOCATE_MASK;
+}
+
+static inline bool ds_needs_download(struct doff_scnhdr_t *sptr)
+{
+ return sptr->ds_flags & DS_DOWNLOAD_MASK;
+}
+
+static inline int ds_alignment(u16 ds_flags)
+{
+ return 1 << ((ds_flags >> DS_ALIGNMENT_SHIFT) & DS_SECTION_TYPE_MASK);
+}
+
+
+#endif /* _DOFF_H */
diff --git a/drivers/staging/tidspbridge/dynload/getsection.c b/drivers/staging/tidspbridge/dynload/getsection.c
new file mode 100644
index 00000000000..e0b37714dd6
--- /dev/null
+++ b/drivers/staging/tidspbridge/dynload/getsection.c
@@ -0,0 +1,407 @@
+/*
+ * getsection.c
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * Copyright (C) 2005-2006 Texas Instruments, Inc.
+ *
+ * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include <dspbridge/getsection.h>
+#include "header.h"
+
+/*
+ * Error strings
+ */
+static const char readstrm[] = { "Error reading %s from input stream" };
+static const char seek[] = { "Set file position to %d failed" };
+static const char isiz[] = { "Bad image packet size %d" };
+static const char err_checksum[] = { "Checksum failed on %s" };
+
+static const char err_reloc[] = { "dload_get_section unable to read"
+ "sections containing relocation entries"
+};
+
+#if BITS_PER_AU > BITS_PER_BYTE
+static const char err_alloc[] = { "Syms->dload_allocate( %d ) failed" };
+static const char stbl[] = { "Bad string table offset " FMT_UI32 };
+#endif
+
+/************************************************************** */
+/********************* SUPPORT FUNCTIONS ********************** */
+/************************************************************** */
+
+#if BITS_PER_AU > BITS_PER_BYTE
+/**************************************************************************
+ * Procedure unpack_sec_name
+ *
+ * Parameters:
+ * dlthis Handle from dload_module_open for this module
+ * soffset Byte offset into the string table
+ * dst Place to store the expanded string
+ *
+ * Effect:
+ * Stores a string from the string table into the destination, expanding
+ * it in the process. Returns a pointer just past the end of the stored
+ * string on success, or NULL on failure.
+ *
+ ************************************************************************ */
+static char *unpack_sec_name(struct dload_state *dlthis, u32 soffset, char *dst)
+{
+ u8 tmp, *src;
+
+ if (soffset >= dlthis->dfile_hdr.df_scn_name_size) {
+ dload_error(dlthis, stbl, soffset);
+ return NULL;
+ }
+ src = (u8 *) dlthis->str_head +
+ (soffset >> (LOG_BITS_PER_AU - LOG_BITS_PER_BYTE));
+ if (soffset & 1)
+ *dst++ = *src++; /* only 1 character in first word */
+ do {
+ tmp = *src++;
+ *dst = (tmp >> BITS_PER_BYTE)
+ if (!(*dst++))
+ break;
+ } while ((*dst++ = tmp & BYTE_MASK));
+
+ return dst;
+}
+
+/**************************************************************************
+ * Procedure expand_sec_names
+ *
+ * Parameters:
+ * dlthis Handle from dload_module_open for this module
+ *
+ * Effect:
+ * Allocates a buffer, unpacks and copies strings from string table into it.
+ * Stores a pointer to the buffer into a state variable.
+ ************************************************************************* */
+static void expand_sec_names(struct dload_state *dlthis)
+{
+ char *xstrings, *curr, *next;
+ u32 xsize;
+ u16 sec;
+ struct ldr_section_info *shp;
+ /* assume worst-case size requirement */
+ xsize = dlthis->dfile_hdr.df_max_str_len * dlthis->dfile_hdr.df_no_scns;
+ xstrings = (char *)dlthis->mysym->dload_allocate(dlthis->mysym, xsize);
+ if (xstrings == NULL) {
+ dload_error(dlthis, err_alloc, xsize);
+ return;
+ }
+ dlthis->xstrings = xstrings;
+ /* For each sec, copy and expand its name */
+ curr = xstrings;
+ for (sec = 0; sec < dlthis->dfile_hdr.df_no_scns; sec++) {
+ shp = (struct ldr_section_info *)&dlthis->sect_hdrs[sec];
+ next = unpack_sec_name(dlthis, *(u32 *) &shp->name, curr);
+ if (next == NULL)
+ break; /* error */
+ shp->name = curr;
+ curr = next;
+ }
+}
+
+#endif
+
+/************************************************************** */
+/********************* EXPORTED FUNCTIONS ********************* */
+/************************************************************** */
+
+/**************************************************************************
+ * Procedure dload_module_open
+ *
+ * Parameters:
+ * module The input stream that supplies the module image
+ * syms Host-side malloc/free and error reporting functions.
+ * Other methods are unused.
+ *
+ * Effect:
+ * Reads header information from a dynamic loader module using the
+ specified
+ * stream object, and returns a handle for the module information. This
+ * handle may be used in subsequent query calls to obtain information
+ * contained in the module.
+ *
+ * Returns:
+ * NULL if an error is encountered, otherwise a module handle for use
+ * in subsequent operations.
+ ************************************************************************* */
+void *dload_module_open(struct dynamic_loader_stream *module,
+ struct dynamic_loader_sym *syms)
+{
+ struct dload_state *dlthis; /* internal state for this call */
+ unsigned *dp, sz;
+ u32 sec_start;
+#if BITS_PER_AU <= BITS_PER_BYTE
+ u16 sec;
+#endif
+
+ /* Check that mandatory arguments are present */
+ if (!module || !syms) {
+ if (syms != NULL)
+ dload_syms_error(syms, "Required parameter is NULL");
+
+ return NULL;
+ }
+
+ dlthis = (struct dload_state *)
+ syms->dload_allocate(syms, sizeof(struct dload_state));
+ if (!dlthis) {
+ /* not enough storage */
+ dload_syms_error(syms, "Can't allocate module info");
+ return NULL;
+ }
+
+ /* clear our internal state */
+ dp = (unsigned *)dlthis;
+ for (sz = sizeof(struct dload_state) / sizeof(unsigned);
+ sz > 0; sz -= 1)
+ *dp++ = 0;
+
+ dlthis->strm = module;
+ dlthis->mysym = syms;
+
+ /* read in the doff image and store in our state variable */
+ dload_headers(dlthis);
+
+ if (!dlthis->dload_errcount)
+ dload_strings(dlthis, true);
+
+ /* skip ahead past the unread portion of the string table */
+ sec_start = sizeof(struct doff_filehdr_t) +
+ sizeof(struct doff_verify_rec_t) +
+ BYTE_TO_HOST(DOFF_ALIGN(dlthis->dfile_hdr.df_strtab_size));
+
+ if (dlthis->strm->set_file_posn(dlthis->strm, sec_start) != 0) {
+ dload_error(dlthis, seek, sec_start);
+ return NULL;
+ }
+
+ if (!dlthis->dload_errcount)
+ dload_sections(dlthis);
+
+ if (dlthis->dload_errcount) {
+ dload_module_close(dlthis); /* errors, blow off our state */
+ dlthis = NULL;
+ return NULL;
+ }
+#if BITS_PER_AU > BITS_PER_BYTE
+ /* Expand all section names from the string table into the */
+ /* state variable, and convert section names from a relative */
+ /* string table offset to a pointers to the expanded string. */
+ expand_sec_names(dlthis);
+#else
+ /* Convert section names from a relative string table offset */
+ /* to a pointer into the string table. */
+ for (sec = 0; sec < dlthis->dfile_hdr.df_no_scns; sec++) {
+ struct ldr_section_info *shp =
+ (struct ldr_section_info *)&dlthis->sect_hdrs[sec];
+ shp->name = dlthis->str_head + *(u32 *) &shp->name;
+ }
+#endif
+
+ return dlthis;
+}
+
+/***************************************************************************
+ * Procedure dload_get_section_info
+ *
+ * Parameters:
+ * minfo Handle from dload_module_open for this module
+ * section_name Pointer to the string name of the section desired
+ * section_info Address of a section info structure pointer to be
+ * initialized
+ *
+ * Effect:
+ * Finds the specified section in the module information, and initializes
+ * the provided struct ldr_section_info pointer.
+ *
+ * Returns:
+ * true for success, false for section not found
+ ************************************************************************* */
+int dload_get_section_info(void *minfo, const char *section_name,
+ const struct ldr_section_info **const section_info)
+{
+ struct dload_state *dlthis;
+ struct ldr_section_info *shp;
+ u16 sec;
+
+ dlthis = (struct dload_state *)minfo;
+ if (!dlthis)
+ return false;
+
+ for (sec = 0; sec < dlthis->dfile_hdr.df_no_scns; sec++) {
+ shp = (struct ldr_section_info *)&dlthis->sect_hdrs[sec];
+ if (strcmp(section_name, shp->name) == 0) {
+ *section_info = shp;
+ return true;
+ }
+ }
+
+ return false;
+}
+
+#define IPH_SIZE (sizeof(struct image_packet_t) - sizeof(u32))
+
+/**************************************************************************
+ * Procedure dload_get_section
+ *
+ * Parameters:
+ * minfo Handle from dload_module_open for this module
+ * section_info Pointer to a section info structure for the desired
+ * section
+ * section_data Buffer to contain the section initialized data
+ *
+ * Effect:
+ * Copies the initialized data for the specified section into the
+ * supplied buffer.
+ *
+ * Returns:
+ * true for success, false for section not found
+ ************************************************************************* */
+int dload_get_section(void *minfo,
+ const struct ldr_section_info *section_info,
+ void *section_data)
+{
+ struct dload_state *dlthis;
+ u32 pos;
+ struct doff_scnhdr_t *sptr = NULL;
+ s32 nip;
+ struct image_packet_t ipacket;
+ s32 ipsize;
+ u32 checks;
+ s8 *dest = (s8 *) section_data;
+
+ dlthis = (struct dload_state *)minfo;
+ if (!dlthis)
+ return false;
+ sptr = (struct doff_scnhdr_t *)section_info;
+ if (sptr == NULL)
+ return false;
+
+ /* skip ahead to the start of the first packet */
+ pos = BYTE_TO_HOST(DOFF_ALIGN((u32) sptr->ds_first_pkt_offset));
+ if (dlthis->strm->set_file_posn(dlthis->strm, pos) != 0) {
+ dload_error(dlthis, seek, pos);
+ return false;
+ }
+
+ nip = sptr->ds_nipacks;
+ while ((nip -= 1) >= 0) { /* for each packet */
+ /* get the fixed header bits */
+ if (dlthis->strm->read_buffer(dlthis->strm, &ipacket,
+ IPH_SIZE) != IPH_SIZE) {
+ dload_error(dlthis, readstrm, "image packet");
+ return false;
+ }
+ /* reorder the header if need be */
+ if (dlthis->reorder_map)
+ dload_reorder(&ipacket, IPH_SIZE, dlthis->reorder_map);
+
+ /* Now read the packet image bits. Note: round the size up to
+ * the next multiple of 4 bytes; this is what checksum
+ * routines want. */
+ ipsize = BYTE_TO_HOST(DOFF_ALIGN(ipacket.packet_size));
+ if (ipsize > BYTE_TO_HOST(IMAGE_PACKET_SIZE)) {
+ dload_error(dlthis, isiz, ipsize);
+ return false;
+ }
+ if (dlthis->strm->read_buffer
+ (dlthis->strm, dest, ipsize) != ipsize) {
+ dload_error(dlthis, readstrm, "image packet");
+ return false;
+ }
+ /* reorder the bytes if need be */
+#if !defined(_BIG_ENDIAN) || (TARGET_AU_BITS > 16)
+ if (dlthis->reorder_map)
+ dload_reorder(dest, ipsize, dlthis->reorder_map);
+
+ checks = dload_checksum(dest, ipsize);
+#else
+ if (dlthis->dfile_hdr.df_byte_reshuffle !=
+ TARGET_ORDER(REORDER_MAP(BYTE_RESHUFFLE_VALUE))) {
+ /* put image bytes in big-endian order, not PC order */
+ dload_reorder(dest, ipsize,
+ TARGET_ORDER(dlthis->
+ dfile_hdr.df_byte_reshuffle));
+ }
+#if TARGET_AU_BITS > 8
+ checks = dload_reverse_checksum16(dest, ipsize);
+#else
+ checks = dload_reverse_checksum(dest, ipsize);
+#endif
+#endif
+ checks += dload_checksum(&ipacket, IPH_SIZE);
+
+ /* NYI: unable to handle relocation entries here. Reloc
+ * entries referring to fields that span the packet boundaries
+ * may result in packets of sizes that are not multiple of
+ * 4 bytes. Our checksum implementation works on 32-bit words
+ * only. */
+ if (ipacket.num_relocs != 0) {
+ dload_error(dlthis, err_reloc, ipsize);
+ return false;
+ }
+
+ if (~checks) {
+ dload_error(dlthis, err_checksum, "image packet");
+ return false;
+ }
+
+ /*Advance destination ptr by the size of the just-read packet */
+ dest += ipsize;
+ }
+
+ return true;
+}
+
+/***************************************************************************
+ * Procedure dload_module_close
+ *
+ * Parameters:
+ * minfo Handle from dload_module_open for this module
+ *
+ * Effect:
+ * Releases any storage associated with the module handle. On return,
+ * the module handle is invalid.
+ *
+ * Returns:
+ * Zero for success. On error, the number of errors detected is returned.
+ * Individual errors are reported using syms->error_report(), where syms was
+ * an argument to dload_module_open
+ ************************************************************************* */
+void dload_module_close(void *minfo)
+{
+ struct dload_state *dlthis;
+
+ dlthis = (struct dload_state *)minfo;
+ if (!dlthis)
+ return;
+
+ if (dlthis->str_head)
+ dlthis->mysym->dload_deallocate(dlthis->mysym,
+ dlthis->str_head);
+
+ if (dlthis->sect_hdrs)
+ dlthis->mysym->dload_deallocate(dlthis->mysym,
+ dlthis->sect_hdrs);
+
+#if BITS_PER_AU > BITS_PER_BYTE
+ if (dlthis->xstrings)
+ dlthis->mysym->dload_deallocate(dlthis->mysym,
+ dlthis->xstrings);
+
+#endif
+
+ dlthis->mysym->dload_deallocate(dlthis->mysym, dlthis);
+}
diff --git a/drivers/staging/tidspbridge/dynload/header.h b/drivers/staging/tidspbridge/dynload/header.h
new file mode 100644
index 00000000000..5b50a15a343
--- /dev/null
+++ b/drivers/staging/tidspbridge/dynload/header.h
@@ -0,0 +1,49 @@
+/*
+ * header.h
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * Copyright (C) 2005-2006 Texas Instruments, Inc.
+ *
+ * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include <linux/string.h>
+#define DL_STRCMP strcmp
+
+/* maximum parenthesis nesting in relocation stack expressions */
+#define STATIC_EXPR_STK_SIZE 10
+
+#include <linux/types.h>
+
+#include "doff.h"
+#include <dspbridge/dynamic_loader.h>
+#include "params.h"
+#include "dload_internal.h"
+#include "reloc_table.h"
+
+/*
+ * Plausibility limits
+ *
+ * These limits are imposed upon the input DOFF file as a check for validity.
+ * They are hard limits, in that the load will fail if they are exceeded.
+ * The numbers selected are arbitrary, in that the loader implementation does
+ * not require these limits.
+ */
+
+/* maximum number of bytes in string table */
+#define MAX_REASONABLE_STRINGTAB (0x100000)
+/* maximum number of code,data,etc. sections */
+#define MAX_REASONABLE_SECTIONS (200)
+/* maximum number of linker symbols */
+#define MAX_REASONABLE_SYMBOLS (100000)
+
+/* shift count to align F_BIG with DLOAD_LITTLE */
+#define ALIGN_COFF_ENDIANNESS 7
+#define ENDIANNESS_MASK (DF_BYTE_ORDER >> ALIGN_COFF_ENDIANNESS)
diff --git a/drivers/staging/tidspbridge/dynload/module_list.h b/drivers/staging/tidspbridge/dynload/module_list.h
new file mode 100644
index 00000000000..a216bb131a4
--- /dev/null
+++ b/drivers/staging/tidspbridge/dynload/module_list.h
@@ -0,0 +1,159 @@
+/*
+ * dspbridge/mpu_driver/src/dynload/module_list.h
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * Copyright (C) 2008 Texas Instruments, Inc.
+ *
+ * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+/*
+ * This C header file gives the layout of the data structure created by the
+ * dynamic loader to describe the set of modules loaded into the DSP.
+ *
+ * Linked List Structure:
+ * ----------------------
+ * The data structure defined here is a singly-linked list. The list
+ * represents the set of modules which are currently loaded in the DSP memory.
+ * The first entry in the list is a header record which contains a flag
+ * representing the state of the list. The rest of the entries in the list
+ * are module records.
+ *
+ * Global symbol _DLModules designates the first record in the list (i.e. the
+ * header record). This symbol must be defined in any program that wishes to
+ * use DLLview plug-in.
+ *
+ * String Representation:
+ * ----------------------
+ * The string names of the module and its sections are stored in a block of
+ * memory which follows the module record itself. The strings are ordered:
+ * module name first, followed by section names in order from the first
+ * section to the last. String names are tightly packed arrays of 8-bit
+ * characters (two characters per 16-bit word on the C55x). Strings are
+ * zero-byte-terminated.
+ *
+ * Creating and updating the list:
+ * -------------------------------
+ * Upon loading a new module into the DSP memory the dynamic loader inserts a
+ * new module record as the first module record in the list. The fields of
+ * this module record are initialized to reflect the properties of the module.
+ * The dynamic loader does NOT increment the flag/counter in the list's header
+ * record.
+ *
+ * Upon unloading a module from the DSP memory the dynamic loader removes the
+ * module's record from this list. The dynamic loader also increments the
+ * flag/counter in the list's header record to indicate that the list has been
+ * changed.
+ */
+
+#ifndef _MODULE_LIST_H_
+#define _MODULE_LIST_H_
+
+#include <linux/types.h>
+
+/* Global pointer to the modules_header structure */
+#define MODULES_HEADER "_DLModules"
+#define MODULES_HEADER_NO_UNDERSCORE "DLModules"
+
+/* Initial version number */
+#define INIT_VERSION 1
+
+/* Verification number -- to be recorded in each module record */
+#define VERIFICATION 0x79
+
+/* forward declarations */
+struct dll_module;
+struct dll_sect;
+
+/* the first entry in the list is the modules_header record;
+ * its address is contained in the global _DLModules pointer */
+struct modules_header {
+
+ /*
+ * Address of the first dll_module record in the list or NULL.
+ * Note: for C55x this is a word address (C55x data is
+ * word-addressable)
+ */
+ u32 first_module;
+
+ /* Combined storage size (in target addressable units) of the
+ * dll_module record which follows this header record, or zero
+ * if the list is empty. This size includes the module's string table.
+ * Note: for C55x the unit is a 16-bit word */
+ u16 first_module_size;
+
+ /* Counter is incremented whenever a module record is removed from
+ * the list */
+ u16 update_flag;
+
+};
+
+/* for each 32-bits in above structure, a bitmap, LSB first, whose bits are:
+ * 0 => a 32-bit value, 1 => 2 16-bit values */
+/* swapping bitmap for type modules_header */
+#define MODULES_HEADER_BITMAP 0x2
+
+/* information recorded about each section in a module */
+struct dll_sect {
+
+ /* Load-time address of the section.
+ * Note: for C55x this is a byte address for program sections, and
+ * a word address for data sections. C55x program memory is
+ * byte-addressable, while data memory is word-addressable. */
+ u32 sect_load_adr;
+
+ /* Run-time address of the section.
+ * Note 1: for C55x this is a byte address for program sections, and
+ * a word address for data sections.
+ * Note 2: for C55x two most significant bits of this field indicate
+ * the section type: '00' for a code section, '11' for a data section
+ * (C55 addresses are really only 24-bits wide). */
+ u32 sect_run_adr;
+
+};
+
+/* the rest of the entries in the list are module records */
+struct dll_module {
+
+ /* Address of the next dll_module record in the list, or 0 if this is
+ * the last record in the list.
+ * Note: for C55x this is a word address (C55x data is
+ * word-addressable) */
+ u32 next_module;
+
+ /* Combined storage size (in target addressable units) of the
+ * dll_module record which follows this one, or zero if this is the
+ * last record in the list. This size includes the module's string
+ * table.
+ * Note: for C55x the unit is a 16-bit word. */
+ u16 next_module_size;
+
+ /* version number of the tooling; set to INIT_VERSION for Phase 1 */
+ u16 version;
+
+ /* the verification word; set to VERIFICATION */
+ u16 verification;
+
+ /* Number of sections in the sects array */
+ u16 num_sects;
+
+ /* Module's "unique" id; copy of the timestamp from the host
+ * COFF file */
+ u32 timestamp;
+
+ /* Array of num_sects elements of the module's section records */
+ struct dll_sect sects[1];
+};
+
+/* for each 32 bits in above structure, a bitmap, LSB first, whose bits are:
+ * 0 => a 32-bit value, 1 => 2 16-bit values */
+#define DLL_MODULE_BITMAP 0x6 /* swapping bitmap for type dll_module */
+
+#endif /* _MODULE_LIST_H_ */
diff --git a/drivers/staging/tidspbridge/dynload/params.h b/drivers/staging/tidspbridge/dynload/params.h
new file mode 100644
index 00000000000..d797fcd3b66
--- /dev/null
+++ b/drivers/staging/tidspbridge/dynload/params.h
@@ -0,0 +1,226 @@
+/*
+ * params.h
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * This file defines host and target properties for all machines
+ * supported by the dynamic loader. To be tedious...
+ *
+ * host: the machine on which the dynamic loader runs
+ * target: the machine that the dynamic loader is loading
+ *
+ * Host and target may or may not be the same, depending upon the particular
+ * use.
+ *
+ * Copyright (C) 2005-2006 Texas Instruments, Inc.
+ *
+ * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+/******************************************************************************
+ *
+ * Host Properties
+ *
+ **************************************************************************** */
+
+#define BITS_PER_BYTE 8 /* bits in the standard PC/SUN byte */
+#define LOG_BITS_PER_BYTE 3 /* log base 2 of same */
+#define BYTE_MASK ((1U<<BITS_PER_BYTE)-1)
+
+#if defined(__TMS320C55X__) || defined(_TMS320C5XX)
+#define BITS_PER_AU 16
+#define LOG_BITS_PER_AU 4
+ /* use this print string in error messages for uint32_t */
+#define FMT_UI32 "0x%lx"
+#define FMT8_UI32 "%08lx" /* same but no 0x, fixed width field */
+#else
+/* bits in the smallest addressable data storage unit */
+#define BITS_PER_AU 8
+/* log base 2 of the same; useful for shift counts */
+#define LOG_BITS_PER_AU 3
+#define FMT_UI32 "0x%x"
+#define FMT8_UI32 "%08x"
+#endif
+
+/* generic fastest method for swapping bytes and shorts */
+#define SWAP32BY16(zz) (((zz) << 16) | ((zz) >> 16))
+#define SWAP16BY8(zz) (((zz) << 8) | ((zz) >> 8))
+
+/* !! don't be tempted to insert type definitions here; use <stdint.h> !! */
+
+/******************************************************************************
+ *
+ * Target Properties
+ *
+ **************************************************************************** */
+
+/*-------------------------------------------------------------------------- */
+/* TMS320C6x Target Specific Parameters (byte-addressable) */
+/*-------------------------------------------------------------------------- */
+#if TMS32060
+#define MEMORG 0x0L /* Size of configured memory */
+#define MEMSIZE 0x0L /* (full address space) */
+
+#define CINIT_ALIGN 8 /* alignment of cinit record in TDATA AUs */
+#define CINIT_COUNT 4 /* width of count field in TDATA AUs */
+#define CINIT_ADDRESS 4 /* width of address field in TDATA AUs */
+#define CINIT_PAGE_BITS 0 /* Number of LSBs of address that
+ * are page number */
+
+#define LENIENT_SIGNED_RELEXPS 0 /* DOES SIGNED ALLOW MAX UNSIGNED */
+
+#undef TARGET_ENDIANNESS /* may be big or little endian */
+
+/* align a target address to a word boundary */
+#define TARGET_WORD_ALIGN(zz) (((zz) + 0x3) & -0x4)
+#endif
+
+/*--------------------------------------------------------------------------
+ *
+ * DEFAULT SETTINGS and DERIVED PROPERTIES
+ *
+ * This section establishes defaults for values not specified above
+ *-------------------------------------------------------------------------- */
+#ifndef TARGET_AU_BITS
+#define TARGET_AU_BITS 8 /* width of the target addressable unit */
+#define LOG_TARGET_AU_BITS 3 /* log2 of same */
+#endif
+
+#ifndef CINIT_DEFAULT_PAGE
+#define CINIT_DEFAULT_PAGE 0 /* default .cinit page number */
+#endif
+
+#ifndef DATA_RUN2LOAD
+#define DATA_RUN2LOAD(zz) (zz) /* translate data run address to load address */
+#endif
+
+#ifndef DBG_LIST_PAGE
+#define DBG_LIST_PAGE 0 /* page number for .dllview section */
+#endif
+
+#ifndef TARGET_WORD_ALIGN
+/* align a target address to a word boundary */
+#define TARGET_WORD_ALIGN(zz) (zz)
+#endif
+
+#ifndef TDATA_TO_TADDR
+#define TDATA_TO_TADDR(zz) (zz) /* target data address to target AU address */
+#define TADDR_TO_TDATA(zz) (zz) /* target AU address to target data address */
+#define TDATA_AU_BITS TARGET_AU_BITS /* bits per data AU */
+#define LOG_TDATA_AU_BITS LOG_TARGET_AU_BITS
+#endif
+
+/*
+ *
+ * Useful properties and conversions derived from the above
+ *
+ */
+
+/*
+ * Conversions between host and target addresses
+ */
+#if LOG_BITS_PER_AU == LOG_TARGET_AU_BITS
+/* translate target addressable unit to host address */
+#define TADDR_TO_HOST(x) (x)
+/* translate host address to target addressable unit */
+#define HOST_TO_TADDR(x) (x)
+#elif LOG_BITS_PER_AU > LOG_TARGET_AU_BITS
+#define TADDR_TO_HOST(x) ((x) >> (LOG_BITS_PER_AU-LOG_TARGET_AU_BITS))
+#define HOST_TO_TADDR(x) ((x) << (LOG_BITS_PER_AU-LOG_TARGET_AU_BITS))
+#else
+#define TADDR_TO_HOST(x) ((x) << (LOG_TARGET_AU_BITS-LOG_BITS_PER_AU))
+#define HOST_TO_TADDR(x) ((x) >> (LOG_TARGET_AU_BITS-LOG_BITS_PER_AU))
+#endif
+
+#if LOG_BITS_PER_AU == LOG_TDATA_AU_BITS
+/* translate target addressable unit to host address */
+#define TDATA_TO_HOST(x) (x)
+/* translate host address to target addressable unit */
+#define HOST_TO_TDATA(x) (x)
+/* translate host address to target addressable unit, round up */
+#define HOST_TO_TDATA_ROUND(x) (x)
+/* byte offset to host offset, rounded up for TDATA size */
+#define BYTE_TO_HOST_TDATA_ROUND(x) BYTE_TO_HOST_ROUND(x)
+#elif LOG_BITS_PER_AU > LOG_TDATA_AU_BITS
+#define TDATA_TO_HOST(x) ((x) >> (LOG_BITS_PER_AU-LOG_TDATA_AU_BITS))
+#define HOST_TO_TDATA(x) ((x) << (LOG_BITS_PER_AU-LOG_TDATA_AU_BITS))
+#define HOST_TO_TDATA_ROUND(x) ((x) << (LOG_BITS_PER_AU-LOG_TDATA_AU_BITS))
+#define BYTE_TO_HOST_TDATA_ROUND(x) BYTE_TO_HOST_ROUND(x)
+#else
+#define TDATA_TO_HOST(x) ((x) << (LOG_TDATA_AU_BITS-LOG_BITS_PER_AU))
+#define HOST_TO_TDATA(x) ((x) >> (LOG_TDATA_AU_BITS-LOG_BITS_PER_AU))
+#define HOST_TO_TDATA_ROUND(x) (((x) +\
+ (1<<(LOG_TDATA_AU_BITS-LOG_BITS_PER_AU))-1) >>\
+ (LOG_TDATA_AU_BITS-LOG_BITS_PER_AU))
+#define BYTE_TO_HOST_TDATA_ROUND(x) (BYTE_TO_HOST((x) +\
+ (1<<(LOG_TDATA_AU_BITS-LOG_BITS_PER_BYTE))-1) &\
+ -(TDATA_AU_BITS/BITS_PER_AU))
+#endif
+
+/*
+ * Input in DOFF format is always expresed in bytes, regardless of loading host
+ * so we wind up converting from bytes to target and host units even when the
+ * host is not a byte machine.
+ */
+#if LOG_BITS_PER_AU == LOG_BITS_PER_BYTE
+#define BYTE_TO_HOST(x) (x)
+#define BYTE_TO_HOST_ROUND(x) (x)
+#define HOST_TO_BYTE(x) (x)
+#elif LOG_BITS_PER_AU >= LOG_BITS_PER_BYTE
+#define BYTE_TO_HOST(x) ((x) >> (LOG_BITS_PER_AU - LOG_BITS_PER_BYTE))
+#define BYTE_TO_HOST_ROUND(x) ((x + (BITS_PER_AU/BITS_PER_BYTE-1)) >>\
+ (LOG_BITS_PER_AU - LOG_BITS_PER_BYTE))
+#define HOST_TO_BYTE(x) ((x) << (LOG_BITS_PER_AU - LOG_BITS_PER_BYTE))
+#else
+/* lets not try to deal with sub-8-bit byte machines */
+#endif
+
+#if LOG_TARGET_AU_BITS == LOG_BITS_PER_BYTE
+/* translate target addressable unit to byte address */
+#define TADDR_TO_BYTE(x) (x)
+/* translate byte address to target addressable unit */
+#define BYTE_TO_TADDR(x) (x)
+#elif LOG_TARGET_AU_BITS > LOG_BITS_PER_BYTE
+#define TADDR_TO_BYTE(x) ((x) << (LOG_TARGET_AU_BITS-LOG_BITS_PER_BYTE))
+#define BYTE_TO_TADDR(x) ((x) >> (LOG_TARGET_AU_BITS-LOG_BITS_PER_BYTE))
+#else
+/* lets not try to deal with sub-8-bit byte machines */
+#endif
+
+#ifdef _BIG_ENDIAN
+#define HOST_ENDIANNESS 1
+#else
+#define HOST_ENDIANNESS 0
+#endif
+
+#ifdef TARGET_ENDIANNESS
+#define TARGET_ENDIANNESS_DIFFERS(rtend) (HOST_ENDIANNESS^TARGET_ENDIANNESS)
+#elif HOST_ENDIANNESS
+#define TARGET_ENDIANNESS_DIFFERS(rtend) (!(rtend))
+#else
+#define TARGET_ENDIANNESS_DIFFERS(rtend) (rtend)
+#endif
+
+/* the unit in which we process target image data */
+#if TARGET_AU_BITS <= 8
+typedef u8 tgt_au_t;
+#elif TARGET_AU_BITS <= 16
+typedef u16 tgt_au_t;
+#else
+typedef u32 tgt_au_t;
+#endif
+
+/* size of that unit */
+#if TARGET_AU_BITS < BITS_PER_AU
+#define TGTAU_BITS BITS_PER_AU
+#define LOG_TGTAU_BITS LOG_BITS_PER_AU
+#else
+#define TGTAU_BITS TARGET_AU_BITS
+#define LOG_TGTAU_BITS LOG_TARGET_AU_BITS
+#endif
diff --git a/drivers/staging/tidspbridge/dynload/reloc.c b/drivers/staging/tidspbridge/dynload/reloc.c
new file mode 100644
index 00000000000..7b28c07ed7c
--- /dev/null
+++ b/drivers/staging/tidspbridge/dynload/reloc.c
@@ -0,0 +1,484 @@
+/*
+ * reloc.c
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * Copyright (C) 2005-2006 Texas Instruments, Inc.
+ *
+ * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include "header.h"
+
+#if TMS32060
+/* the magic symbol for the start of BSS */
+static const char bsssymbol[] = { ".bss" };
+#endif
+
+#if TMS32060
+#include "reloc_table_c6000.c"
+#endif
+
+#if TMS32060
+/* From coff.h - ignore these relocation operations */
+#define R_C60ALIGN 0x76 /* C60: Alignment info for compressor */
+#define R_C60FPHEAD 0x77 /* C60: Explicit assembly directive */
+#define R_C60NOCMP 0x100 /* C60: Don't compress this code scn */
+#endif
+
+/**************************************************************************
+ * Procedure dload_unpack
+ *
+ * Parameters:
+ * data pointer to storage unit containing lowest host address of
+ * image data
+ * fieldsz Size of bit field, 0 < fieldsz <= sizeof(rvalue)*BITS_PER_AU
+ * offset Offset from LSB, 0 <= offset < BITS_PER_AU
+ * sgn Signedness of the field (ROP_SGN, ROP_UNS, ROP_MAX, ROP_ANY)
+ *
+ * Effect:
+ * Extracts the specified field and returns it.
+ ************************************************************************* */
+rvalue dload_unpack(struct dload_state *dlthis, tgt_au_t * data, int fieldsz,
+ int offset, unsigned sgn)
+{
+ register rvalue objval;
+ register int shift, direction;
+ register tgt_au_t *dp = data;
+
+ fieldsz -= 1; /* avoid nastiness with 32-bit shift of 32-bit value */
+ /* * collect up enough bits to contain the desired field */
+ if (TARGET_BIG_ENDIAN) {
+ dp += (fieldsz + offset) >> LOG_TGTAU_BITS;
+ direction = -1;
+ } else
+ direction = 1;
+ objval = *dp >> offset;
+ shift = TGTAU_BITS - offset;
+ while (shift <= fieldsz) {
+ dp += direction;
+ objval += (rvalue) *dp << shift;
+ shift += TGTAU_BITS;
+ }
+
+ /* * sign or zero extend the value appropriately */
+ if (sgn == ROP_UNS)
+ objval &= (2 << fieldsz) - 1;
+ else {
+ shift = sizeof(rvalue) * BITS_PER_AU - 1 - fieldsz;
+ objval = (objval << shift) >> shift;
+ }
+
+ return objval;
+
+} /* dload_unpack */
+
+/**************************************************************************
+ * Procedure dload_repack
+ *
+ * Parameters:
+ * val Value to insert
+ * data Pointer to storage unit containing lowest host address of
+ * image data
+ * fieldsz Size of bit field, 0 < fieldsz <= sizeof(rvalue)*BITS_PER_AU
+ * offset Offset from LSB, 0 <= offset < BITS_PER_AU
+ * sgn Signedness of the field (ROP_SGN, ROP_UNS, ROP_MAX, ROP_ANY)
+ *
+ * Effect:
+ * Stuffs the specified value in the specified field. Returns 0 for
+ * success
+ * or 1 if the value will not fit in the specified field according to the
+ * specified signedness rule.
+ ************************************************************************* */
+static const unsigned char ovf_limit[] = { 1, 2, 2 };
+
+int dload_repack(struct dload_state *dlthis, rvalue val, tgt_au_t * data,
+ int fieldsz, int offset, unsigned sgn)
+{
+ register urvalue objval, mask;
+ register int shift, direction;
+ register tgt_au_t *dp = data;
+
+ fieldsz -= 1; /* avoid nastiness with 32-bit shift of 32-bit value */
+ /* clip the bits */
+ mask = (2UL << fieldsz) - 1;
+ objval = (val & mask);
+ /* * store the bits through the specified mask */
+ if (TARGET_BIG_ENDIAN) {
+ dp += (fieldsz + offset) >> LOG_TGTAU_BITS;
+ direction = -1;
+ } else
+ direction = 1;
+
+ /* insert LSBs */
+ *dp = (*dp & ~(mask << offset)) + (objval << offset);
+ shift = TGTAU_BITS - offset;
+ /* align mask and objval with AU boundary */
+ objval >>= shift;
+ mask >>= shift;
+
+ while (mask) {
+ dp += direction;
+ *dp = (*dp & ~mask) + objval;
+ objval >>= TGTAU_BITS;
+ mask >>= TGTAU_BITS;
+ }
+
+ /*
+ * check for overflow
+ */
+ if (sgn) {
+ unsigned tmp = (val >> fieldsz) + (sgn & 0x1);
+ if (tmp > ovf_limit[sgn - 1])
+ return 1;
+ }
+ return 0;
+
+} /* dload_repack */
+
+/* lookup table for the scaling amount in a C6x instruction */
+#if TMS32060
+#define SCALE_BITS 4 /* there are 4 bits in the scale field */
+#define SCALE_MASK 0x7 /* we really only use the bottom 3 bits */
+static const u8 c60_scale[SCALE_MASK + 1] = {
+ 1, 0, 0, 0, 1, 1, 2, 2
+};
+#endif
+
+/**************************************************************************
+ * Procedure dload_relocate
+ *
+ * Parameters:
+ * data Pointer to base of image data
+ * rp Pointer to relocation operation
+ *
+ * Effect:
+ * Performs the specified relocation operation
+ ************************************************************************* */
+void dload_relocate(struct dload_state *dlthis, tgt_au_t * data,
+ struct reloc_record_t *rp, bool *tramps_generated,
+ bool second_pass)
+{
+ rvalue val, reloc_amt, orig_val = 0;
+ unsigned int fieldsz = 0;
+ unsigned int offset = 0;
+ unsigned int reloc_info = 0;
+ unsigned int reloc_action = 0;
+ register int rx = 0;
+ rvalue *stackp = NULL;
+ int top;
+ struct local_symbol *svp = NULL;
+#ifdef RFV_SCALE
+ unsigned int scale = 0;
+#endif
+ struct image_packet_t *img_pkt = NULL;
+
+ /* The image packet data struct is only used during first pass
+ * relocation in the event that a trampoline is needed. 2nd pass
+ * relocation doesn't guarantee that data is coming from an
+ * image_packet_t structure. See cload.c, dload_data for how img_data is
+ * set. If that changes this needs to be updated!!! */
+ if (second_pass == false)
+ img_pkt = (struct image_packet_t *)((u8 *) data -
+ sizeof(struct
+ image_packet_t));
+
+ rx = HASH_FUNC(rp->TYPE);
+ while (rop_map1[rx] != rp->TYPE) {
+ rx = HASH_L(rop_map2[rx]);
+ if (rx < 0) {
+#if TMS32060
+ switch (rp->TYPE) {
+ case R_C60ALIGN:
+ case R_C60NOCMP:
+ case R_C60FPHEAD:
+ /* Ignore these reloc types and return */
+ break;
+ default:
+ /* Unknown reloc type, print error and return */
+ dload_error(dlthis, "Bad coff operator 0x%x",
+ rp->TYPE);
+ }
+#else
+ dload_error(dlthis, "Bad coff operator 0x%x", rp->TYPE);
+#endif
+ return;
+ }
+ }
+ rx = HASH_I(rop_map2[rx]);
+ if ((rx < (sizeof(rop_action) / sizeof(u16)))
+ && (rx < (sizeof(rop_info) / sizeof(u16))) && (rx > 0)) {
+ reloc_action = rop_action[rx];
+ reloc_info = rop_info[rx];
+ } else {
+ dload_error(dlthis, "Buffer Overflow - Array Index Out "
+ "of Bounds");
+ }
+
+ /* Compute the relocation amount for the referenced symbol, if any */
+ reloc_amt = rp->UVAL;
+ if (RFV_SYM(reloc_info)) { /* relocation uses a symbol reference */
+ /* If this is first pass, use the module local symbol table,
+ * else use the trampoline symbol table. */
+ if (second_pass == false) {
+ if ((u32) rp->SYMNDX < dlthis->dfile_hdr.df_no_syms) {
+ /* real symbol reference */
+ svp = &dlthis->local_symtab[rp->SYMNDX];
+ reloc_amt = (RFV_SYM(reloc_info) == ROP_SYMD) ?
+ svp->delta : svp->value;
+ }
+ /* reloc references current section */
+ else if (rp->SYMNDX == -1) {
+ reloc_amt = (RFV_SYM(reloc_info) == ROP_SYMD) ?
+ dlthis->delta_runaddr :
+ dlthis->image_secn->run_addr;
+ }
+ }
+ }
+ /* relocation uses a symbol reference */
+ /* Handle stack adjustment */
+ val = 0;
+ top = RFV_STK(reloc_info);
+ if (top) {
+ top += dlthis->relstkidx - RSTK_UOP;
+ if (top >= STATIC_EXPR_STK_SIZE) {
+ dload_error(dlthis,
+ "Expression stack overflow in %s at offset "
+ FMT_UI32, dlthis->image_secn->name,
+ rp->vaddr + dlthis->image_offset);
+ return;
+ }
+ val = dlthis->relstk[dlthis->relstkidx];
+ dlthis->relstkidx = top;
+ stackp = &dlthis->relstk[top];
+ }
+ /* Derive field position and size, if we need them */
+ if (reloc_info & ROP_RW) { /* read or write action in our future */
+ fieldsz = RFV_WIDTH(reloc_action);
+ if (fieldsz) { /* field info from table */
+ offset = RFV_POSN(reloc_action);
+ if (TARGET_BIG_ENDIAN)
+ /* make sure vaddr is the lowest target
+ * address containing bits */
+ rp->vaddr += RFV_BIGOFF(reloc_info);
+ } else { /* field info from relocation op */
+ fieldsz = rp->FIELDSZ;
+ offset = rp->OFFSET;
+ if (TARGET_BIG_ENDIAN)
+ /* make sure vaddr is the lowest target
+ address containing bits */
+ rp->vaddr += (rp->WORDSZ - offset - fieldsz)
+ >> LOG_TARGET_AU_BITS;
+ }
+ data = (tgt_au_t *) ((char *)data + TADDR_TO_HOST(rp->vaddr));
+ /* compute lowest host location of referenced data */
+#if BITS_PER_AU > TARGET_AU_BITS
+ /* conversion from target address to host address may lose
+ address bits; add loss to offset */
+ if (TARGET_BIG_ENDIAN) {
+ offset += -((rp->vaddr << LOG_TARGET_AU_BITS) +
+ offset + fieldsz) &
+ (BITS_PER_AU - TARGET_AU_BITS);
+ } else {
+ offset += (rp->vaddr << LOG_TARGET_AU_BITS) &
+ (BITS_PER_AU - 1);
+ }
+#endif
+#ifdef RFV_SCALE
+ scale = RFV_SCALE(reloc_info);
+#endif
+ }
+ /* read the object value from the current image, if so ordered */
+ if (reloc_info & ROP_R) {
+ /* relocation reads current image value */
+ val = dload_unpack(dlthis, data, fieldsz, offset,
+ RFV_SIGN(reloc_info));
+ /* Save off the original value in case the relo overflows and
+ * we can trampoline it. */
+ orig_val = val;
+
+#ifdef RFV_SCALE
+ val <<= scale;
+#endif
+ }
+ /* perform the necessary arithmetic */
+ switch (RFV_ACTION(reloc_action)) { /* relocation actions */
+ case RACT_VAL:
+ break;
+ case RACT_ASGN:
+ val = reloc_amt;
+ break;
+ case RACT_ADD:
+ val += reloc_amt;
+ break;
+ case RACT_PCR:
+ /*-----------------------------------------------------------
+ * Handle special cases of jumping from absolute sections
+ * (special reloc type) or to absolute destination
+ * (symndx == -1). In either case, set the appropriate
+ * relocation amount to 0.
+ *----------------------------------------------------------- */
+ if (rp->SYMNDX == -1)
+ reloc_amt = 0;
+ val += reloc_amt - dlthis->delta_runaddr;
+ break;
+ case RACT_ADDISP:
+ val += rp->R_DISP + reloc_amt;
+ break;
+ case RACT_ASGPC:
+ val = dlthis->image_secn->run_addr + reloc_amt;
+ break;
+ case RACT_PLUS:
+ if (stackp != NULL)
+ val += *stackp;
+ break;
+ case RACT_SUB:
+ if (stackp != NULL)
+ val = *stackp - val;
+ break;
+ case RACT_NEG:
+ val = -val;
+ break;
+ case RACT_MPY:
+ if (stackp != NULL)
+ val *= *stackp;
+ break;
+ case RACT_DIV:
+ if (stackp != NULL)
+ val = *stackp / val;
+ break;
+ case RACT_MOD:
+ if (stackp != NULL)
+ val = *stackp % val;
+ break;
+ case RACT_SR:
+ if (val >= sizeof(rvalue) * BITS_PER_AU)
+ val = 0;
+ else if (stackp != NULL)
+ val = (urvalue) *stackp >> val;
+ break;
+ case RACT_ASR:
+ if (val >= sizeof(rvalue) * BITS_PER_AU)
+ val = sizeof(rvalue) * BITS_PER_AU - 1;
+ else if (stackp != NULL)
+ val = *stackp >> val;
+ break;
+ case RACT_SL:
+ if (val >= sizeof(rvalue) * BITS_PER_AU)
+ val = 0;
+ else if (stackp != NULL)
+ val = *stackp << val;
+ break;
+ case RACT_AND:
+ if (stackp != NULL)
+ val &= *stackp;
+ break;
+ case RACT_OR:
+ if (stackp != NULL)
+ val |= *stackp;
+ break;
+ case RACT_XOR:
+ if (stackp != NULL)
+ val ^= *stackp;
+ break;
+ case RACT_NOT:
+ val = ~val;
+ break;
+#if TMS32060
+ case RACT_C6SECT:
+ /* actually needed address of secn containing symbol */
+ if (svp != NULL) {
+ if (rp->SYMNDX >= 0)
+ if (svp->secnn > 0)
+ reloc_amt = dlthis->ldr_sections
+ [svp->secnn - 1].run_addr;
+ }
+ /* !!! FALL THRU !!! */
+ case RACT_C6BASE:
+ if (dlthis->bss_run_base == 0) {
+ struct dynload_symbol *symp;
+ symp = dlthis->mysym->find_matching_symbol
+ (dlthis->mysym, bsssymbol);
+ /* lookup value of global BSS base */
+ if (symp)
+ dlthis->bss_run_base = symp->value;
+ else
+ dload_error(dlthis,
+ "Global BSS base referenced in %s "
+ "offset" FMT_UI32 " but not "
+ "defined",
+ dlthis->image_secn->name,
+ rp->vaddr + dlthis->image_offset);
+ }
+ reloc_amt -= dlthis->bss_run_base;
+ /* !!! FALL THRU !!! */
+ case RACT_C6DSPL:
+ /* scale factor determined by 3 LSBs of field */
+ scale = c60_scale[val & SCALE_MASK];
+ offset += SCALE_BITS;
+ fieldsz -= SCALE_BITS;
+ val >>= SCALE_BITS; /* ignore the scale field hereafter */
+ val <<= scale;
+ val += reloc_amt; /* do the usual relocation */
+ if (((1 << scale) - 1) & val)
+ dload_error(dlthis,
+ "Unaligned reference in %s offset "
+ FMT_UI32, dlthis->image_secn->name,
+ rp->vaddr + dlthis->image_offset);
+ break;
+#endif
+ } /* relocation actions */
+ /* * Put back result as required */
+ if (reloc_info & ROP_W) { /* relocation writes image value */
+#ifdef RFV_SCALE
+ val >>= scale;
+#endif
+ if (dload_repack(dlthis, val, data, fieldsz, offset,
+ RFV_SIGN(reloc_info))) {
+ /* Check to see if this relo can be trampolined,
+ * but only in first phase relocation. 2nd phase
+ * relocation cannot trampoline. */
+ if ((second_pass == false) &&
+ (dload_tramp_avail(dlthis, rp) == true)) {
+
+ /* Before generating the trampoline, restore
+ * the value to its original so the 2nd pass
+ * relo will work. */
+ dload_repack(dlthis, orig_val, data, fieldsz,
+ offset, RFV_SIGN(reloc_info));
+ if (!dload_tramp_generate(dlthis,
+ (dlthis->image_secn -
+ dlthis->ldr_sections),
+ dlthis->image_offset,
+ img_pkt, rp)) {
+ dload_error(dlthis,
+ "Failed to "
+ "generate trampoline for "
+ "bit overflow");
+ dload_error(dlthis,
+ "Relocation val " FMT_UI32
+ " overflows %d bits in %s "
+ "offset " FMT_UI32, val,
+ fieldsz,
+ dlthis->image_secn->name,
+ dlthis->image_offset +
+ rp->vaddr);
+ } else
+ *tramps_generated = true;
+ } else {
+ dload_error(dlthis, "Relocation value "
+ FMT_UI32 " overflows %d bits in %s"
+ " offset " FMT_UI32, val, fieldsz,
+ dlthis->image_secn->name,
+ dlthis->image_offset + rp->vaddr);
+ }
+ }
+ } else if (top)
+ *stackp = val;
+} /* reloc_value */
diff --git a/drivers/staging/tidspbridge/dynload/reloc_table.h b/drivers/staging/tidspbridge/dynload/reloc_table.h
new file mode 100644
index 00000000000..6aab03d4668
--- /dev/null
+++ b/drivers/staging/tidspbridge/dynload/reloc_table.h
@@ -0,0 +1,102 @@
+/*
+ * reloc_table.h
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * Copyright (C) 2005-2006 Texas Instruments, Inc.
+ *
+ * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef _RELOC_TABLE_H_
+#define _RELOC_TABLE_H_
+/*
+ * Table of relocation operator properties
+ */
+#include <linux/types.h>
+
+/* How does this relocation operation access the program image? */
+#define ROP_N 0 /* does not access image */
+#define ROP_R 1 /* read from image */
+#define ROP_W 2 /* write to image */
+#define ROP_RW 3 /* read from and write to image */
+
+/* For program image access, what are the overflow rules for the bit field? */
+/* Beware! Procedure repack depends on this encoding */
+#define ROP_ANY 0 /* no overflow ever, just truncate the value */
+#define ROP_SGN 1 /* signed field */
+#define ROP_UNS 2 /* unsigned field */
+#define ROP_MAX 3 /* allow maximum range of either signed or unsigned */
+
+/* How does the relocation operation use the symbol reference */
+#define ROP_IGN 0 /* no symbol is referenced */
+#define ROP_LIT 0 /* use rp->UVAL literal field */
+#define ROP_SYM 1 /* symbol value is used in relocation */
+#define ROP_SYMD 2 /* delta value vs last link is used */
+
+/* How does the reloc op use the stack? */
+#define RSTK_N 0 /* Does not use */
+#define RSTK_POP 1 /* Does a POP */
+#define RSTK_UOP 2 /* Unary op, stack position unaffected */
+#define RSTK_PSH 3 /* Does a push */
+
+/*
+ * Computational actions performed by the dynamic loader
+ */
+enum dload_actions {
+ /* don't alter the current val (from stack or mem fetch) */
+ RACT_VAL,
+ /* set value to reference amount (from symbol reference) */
+ RACT_ASGN,
+ RACT_ADD, /* add reference to value */
+ RACT_PCR, /* add reference minus PC delta to value */
+ RACT_ADDISP, /* add reference plus R_DISP */
+ RACT_ASGPC, /* set value to section addr plus reference */
+
+ RACT_PLUS, /* stack + */
+ RACT_SUB, /* stack - */
+ RACT_NEG, /* stack unary - */
+
+ RACT_MPY, /* stack * */
+ RACT_DIV, /* stack / */
+ RACT_MOD, /* stack % */
+
+ RACT_SR, /* stack unsigned >> */
+ RACT_ASR, /* stack signed >> */
+ RACT_SL, /* stack << */
+ RACT_AND, /* stack & */
+ RACT_OR, /* stack | */
+ RACT_XOR, /* stack ^ */
+ RACT_NOT, /* stack ~ */
+ RACT_C6SECT, /* for C60 R_SECT op */
+ RACT_C6BASE, /* for C60 R_BASE op */
+ RACT_C6DSPL, /* for C60 scaled 15-bit displacement */
+ RACT_PCR23T /* for ARM Thumb long branch */
+};
+
+/*
+ * macros used to extract values
+ */
+#define RFV_POSN(aaa) ((aaa) & 0xF)
+#define RFV_WIDTH(aaa) (((aaa) >> 4) & 0x3F)
+#define RFV_ACTION(aaa) ((aaa) >> 10)
+
+#define RFV_SIGN(iii) (((iii) >> 2) & 0x3)
+#define RFV_SYM(iii) (((iii) >> 4) & 0x3)
+#define RFV_STK(iii) (((iii) >> 6) & 0x3)
+#define RFV_ACCS(iii) ((iii) & 0x3)
+
+#if (TMS32060)
+#define RFV_SCALE(iii) ((iii) >> 11)
+#define RFV_BIGOFF(iii) (((iii) >> 8) & 0x7)
+#else
+#define RFV_BIGOFF(iii) ((iii) >> 8)
+#endif
+
+#endif /* _RELOC_TABLE_H_ */
diff --git a/drivers/staging/tidspbridge/dynload/reloc_table_c6000.c b/drivers/staging/tidspbridge/dynload/reloc_table_c6000.c
new file mode 100644
index 00000000000..a28bc044249
--- /dev/null
+++ b/drivers/staging/tidspbridge/dynload/reloc_table_c6000.c
@@ -0,0 +1,257 @@
+/*
+ * reloc_table_c6000.c
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * Copyright (C) 2005-2006 Texas Instruments, Inc.
+ *
+ * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+/* Tables generated for c6000 */
+
+#define HASH_FUNC(zz) (((((zz) + 1) * 1845UL) >> 11) & 63)
+#define HASH_L(zz) ((zz) >> 8)
+#define HASH_I(zz) ((zz) & 0xFF)
+
+static const u16 rop_map1[] = {
+ 0,
+ 1,
+ 2,
+ 20,
+ 4,
+ 5,
+ 6,
+ 15,
+ 80,
+ 81,
+ 82,
+ 83,
+ 84,
+ 85,
+ 86,
+ 87,
+ 17,
+ 18,
+ 19,
+ 21,
+ 16,
+ 16394,
+ 16404,
+ 65535,
+ 65535,
+ 65535,
+ 65535,
+ 65535,
+ 65535,
+ 32,
+ 65535,
+ 65535,
+ 65535,
+ 65535,
+ 65535,
+ 65535,
+ 40,
+ 112,
+ 113,
+ 65535,
+ 16384,
+ 16385,
+ 16386,
+ 16387,
+ 16388,
+ 16389,
+ 16390,
+ 16391,
+ 16392,
+ 16393,
+ 16395,
+ 16396,
+ 16397,
+ 16398,
+ 16399,
+ 16400,
+ 16401,
+ 16402,
+ 16403,
+ 16405,
+ 16406,
+ 65535,
+ 65535,
+ 65535
+};
+
+static const s16 rop_map2[] = {
+ -256,
+ -255,
+ -254,
+ -245,
+ -253,
+ -252,
+ -251,
+ -250,
+ -241,
+ -240,
+ -239,
+ -238,
+ -237,
+ -236,
+ 1813,
+ 5142,
+ -248,
+ -247,
+ 778,
+ -244,
+ -249,
+ -221,
+ -211,
+ -1,
+ -1,
+ -1,
+ -1,
+ -1,
+ -1,
+ -243,
+ -1,
+ -1,
+ -1,
+ -1,
+ -1,
+ -1,
+ -242,
+ -233,
+ -232,
+ -1,
+ -231,
+ -230,
+ -229,
+ -228,
+ -227,
+ -226,
+ -225,
+ -224,
+ -223,
+ 5410,
+ -220,
+ -219,
+ -218,
+ -217,
+ -216,
+ -215,
+ -214,
+ -213,
+ 5676,
+ -210,
+ -209,
+ -1,
+ -1,
+ -1
+};
+
+static const u16 rop_action[] = {
+ 2560,
+ 2304,
+ 2304,
+ 2432,
+ 2432,
+ 2560,
+ 2176,
+ 2304,
+ 2560,
+ 3200,
+ 3328,
+ 3584,
+ 3456,
+ 2304,
+ 4208,
+ 20788,
+ 21812,
+ 3415,
+ 3245,
+ 2311,
+ 4359,
+ 19764,
+ 2311,
+ 3191,
+ 3280,
+ 6656,
+ 7680,
+ 8704,
+ 9728,
+ 10752,
+ 11776,
+ 12800,
+ 13824,
+ 14848,
+ 15872,
+ 16896,
+ 17920,
+ 18944,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1536,
+ 1536,
+ 1536,
+ 5632,
+ 512,
+ 0
+};
+
+static const u16 rop_info[] = {
+ 0,
+ 35,
+ 35,
+ 35,
+ 35,
+ 35,
+ 35,
+ 35,
+ 35,
+ 39,
+ 39,
+ 39,
+ 39,
+ 35,
+ 34,
+ 283,
+ 299,
+ 4135,
+ 4391,
+ 291,
+ 33059,
+ 283,
+ 295,
+ 4647,
+ 4135,
+ 64,
+ 64,
+ 128,
+ 64,
+ 64,
+ 64,
+ 64,
+ 64,
+ 64,
+ 64,
+ 64,
+ 64,
+ 128,
+ 201,
+ 197,
+ 74,
+ 70,
+ 208,
+ 196,
+ 200,
+ 192,
+ 192,
+ 66
+};
diff --git a/drivers/staging/tidspbridge/dynload/tramp.c b/drivers/staging/tidspbridge/dynload/tramp.c
new file mode 100644
index 00000000000..60d22ea4705
--- /dev/null
+++ b/drivers/staging/tidspbridge/dynload/tramp.c
@@ -0,0 +1,1143 @@
+/*
+ * tramp.c
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * Copyright (C) 2009 Texas Instruments, Inc.
+ *
+ * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include "header.h"
+
+#if TMS32060
+#include "tramp_table_c6000.c"
+#endif
+
+#define MAX_RELOS_PER_PASS 4
+
+/*
+ * Function: priv_tramp_sect_tgt_alloc
+ * Description: Allocate target memory for the trampoline section. The
+ * target mem size is easily obtained as the next available address.
+ */
+static int priv_tramp_sect_tgt_alloc(struct dload_state *dlthis)
+{
+ int ret_val = 0;
+ struct ldr_section_info *sect_info;
+
+ /* Populate the trampoline loader section and allocate it on the
+ * target. The section name is ALWAYS the first string in the final
+ * string table for trampolines. The trampoline section is always
+ * 1 beyond the total number of allocated sections. */
+ sect_info = &dlthis->ldr_sections[dlthis->allocated_secn_count];
+
+ sect_info->name = dlthis->tramp.final_string_table;
+ sect_info->size = dlthis->tramp.tramp_sect_next_addr;
+ sect_info->context = 0;
+ sect_info->type =
+ (4 << 8) | DLOAD_TEXT | DS_ALLOCATE_MASK | DS_DOWNLOAD_MASK;
+ sect_info->page = 0;
+ sect_info->run_addr = 0;
+ sect_info->load_addr = 0;
+ ret_val = dlthis->myalloc->dload_allocate(dlthis->myalloc,
+ sect_info,
+ ds_alignment
+ (sect_info->type));
+
+ if (ret_val == 0)
+ dload_error(dlthis, "Failed to allocate target memory for"
+ " trampoline");
+
+ return ret_val;
+}
+
+/*
+ * Function: priv_h2a
+ * Description: Helper function to convert a hex value to its ASCII
+ * representation. Used for trampoline symbol name generation.
+ */
+static u8 priv_h2a(u8 value)
+{
+ if (value > 0xF)
+ return 0xFF;
+
+ if (value <= 9)
+ value += 0x30;
+ else
+ value += 0x37;
+
+ return value;
+}
+
+/*
+ * Function: priv_tramp_sym_gen_name
+ * Description: Generate a trampoline symbol name (ASCII) using the value
+ * of the symbol. This places the new name into the user buffer.
+ * The name is fixed in length and of the form: __$dbTR__xxxxxxxx
+ * (where "xxxxxxxx" is the hex value.
+ */
+static void priv_tramp_sym_gen_name(u32 value, char *dst)
+{
+ u32 i;
+ char *prefix = TRAMP_SYM_PREFIX;
+ char *dst_local = dst;
+ u8 tmp;
+
+ /* Clear out the destination, including the ending NULL */
+ for (i = 0; i < (TRAMP_SYM_PREFIX_LEN + TRAMP_SYM_HEX_ASCII_LEN); i++)
+ *(dst_local + i) = 0;
+
+ /* Copy the prefix to start */
+ for (i = 0; i < strlen(TRAMP_SYM_PREFIX); i++) {
+ *dst_local = *(prefix + i);
+ dst_local++;
+ }
+
+ /* Now convert the value passed in to a string equiv of the hex */
+ for (i = 0; i < sizeof(value); i++) {
+#ifndef _BIG_ENDIAN
+ tmp = *(((u8 *) &value) + (sizeof(value) - 1) - i);
+ *dst_local = priv_h2a((tmp & 0xF0) >> 4);
+ dst_local++;
+ *dst_local = priv_h2a(tmp & 0x0F);
+ dst_local++;
+#else
+ tmp = *(((u8 *) &value) + i);
+ *dst_local = priv_h2a((tmp & 0xF0) >> 4);
+ dst_local++;
+ *dst_local = priv_h2a(tmp & 0x0F);
+ dst_local++;
+#endif
+ }
+
+ /* NULL terminate */
+ *dst_local = 0;
+}
+
+/*
+ * Function: priv_tramp_string_create
+ * Description: Create a new string specific to the trampoline loading and add
+ * it to the trampoline string list. This list contains the
+ * trampoline section name and trampoline point symbols.
+ */
+static struct tramp_string *priv_tramp_string_create(struct dload_state *dlthis,
+ u32 str_len, char *str)
+{
+ struct tramp_string *new_string = NULL;
+ u32 i;
+
+ /* Create a new string object with the specified size. */
+ new_string =
+ (struct tramp_string *)dlthis->mysym->dload_allocate(dlthis->mysym,
+ (sizeof
+ (struct
+ tramp_string)
+ + str_len +
+ 1));
+ if (new_string != NULL) {
+ /* Clear the string first. This ensures the ending NULL is
+ * present and the optimizer won't touch it. */
+ for (i = 0; i < (sizeof(struct tramp_string) + str_len + 1);
+ i++)
+ *((u8 *) new_string + i) = 0;
+
+ /* Add this string to our virtual table by assigning it the
+ * next index and pushing it to the tail of the list. */
+ new_string->index = dlthis->tramp.tramp_string_next_index;
+ dlthis->tramp.tramp_string_next_index++;
+ dlthis->tramp.tramp_string_size += str_len + 1;
+
+ new_string->next = NULL;
+ if (dlthis->tramp.string_head == NULL)
+ dlthis->tramp.string_head = new_string;
+ else
+ dlthis->tramp.string_tail->next = new_string;
+
+ dlthis->tramp.string_tail = new_string;
+
+ /* Copy the string over to the new object */
+ for (i = 0; i < str_len; i++)
+ new_string->str[i] = str[i];
+ }
+
+ return new_string;
+}
+
+/*
+ * Function: priv_tramp_string_find
+ * Description: Walk the trampoline string list and find a match for the
+ * provided string. If not match is found, NULL is returned.
+ */
+static struct tramp_string *priv_tramp_string_find(struct dload_state *dlthis,
+ char *str)
+{
+ struct tramp_string *cur_str = NULL;
+ struct tramp_string *ret_val = NULL;
+ u32 i;
+ u32 str_len = strlen(str);
+
+ for (cur_str = dlthis->tramp.string_head;
+ (ret_val == NULL) && (cur_str != NULL); cur_str = cur_str->next) {
+ /* If the string lengths aren't equal, don't bother
+ * comparing */
+ if (str_len != strlen(cur_str->str))
+ continue;
+
+ /* Walk the strings until one of them ends */
+ for (i = 0; i < str_len; i++) {
+ /* If they don't match in the current position then
+ * break out now, no sense in continuing to look at
+ * this string. */
+ if (str[i] != cur_str->str[i])
+ break;
+ }
+
+ if (i == str_len)
+ ret_val = cur_str;
+ }
+
+ return ret_val;
+}
+
+/*
+ * Function: priv_string_tbl_finalize
+ * Description: Flatten the trampoline string list into a table of NULL
+ * terminated strings. This is the same format of string table
+ * as used by the COFF/DOFF file.
+ */
+static int priv_string_tbl_finalize(struct dload_state *dlthis)
+{
+ int ret_val = 0;
+ struct tramp_string *cur_string;
+ char *cur_loc;
+ char *tmp;
+
+ /* Allocate enough space for all strings that have been created. The
+ * table is simply all strings concatenated together will NULL
+ * endings. */
+ dlthis->tramp.final_string_table =
+ (char *)dlthis->mysym->dload_allocate(dlthis->mysym,
+ dlthis->tramp.
+ tramp_string_size);
+ if (dlthis->tramp.final_string_table != NULL) {
+ /* We got our buffer, walk the list and release the nodes as*
+ * we go */
+ cur_loc = dlthis->tramp.final_string_table;
+ cur_string = dlthis->tramp.string_head;
+ while (cur_string != NULL) {
+ /* Move the head/tail pointers */
+ dlthis->tramp.string_head = cur_string->next;
+ if (dlthis->tramp.string_tail == cur_string)
+ dlthis->tramp.string_tail = NULL;
+
+ /* Copy the string contents */
+ for (tmp = cur_string->str;
+ *tmp != '\0'; tmp++, cur_loc++)
+ *cur_loc = *tmp;
+
+ /* Pick up the NULL termination since it was missed by
+ * breaking using it to end the above loop. */
+ *cur_loc = '\0';
+ cur_loc++;
+
+ /* Free the string node, we don't need it any more. */
+ dlthis->mysym->dload_deallocate(dlthis->mysym,
+ cur_string);
+
+ /* Move our pointer to the next one */
+ cur_string = dlthis->tramp.string_head;
+ }
+
+ /* Update our return value to success */
+ ret_val = 1;
+ } else
+ dload_error(dlthis, "Failed to allocate trampoline "
+ "string table");
+
+ return ret_val;
+}
+
+/*
+ * Function: priv_tramp_sect_alloc
+ * Description: Virtually allocate space from the trampoline section. This
+ * function returns the next offset within the trampoline section
+ * that is available and moved the next available offset by the
+ * requested size. NO TARGET ALLOCATION IS DONE AT THIS TIME.
+ */
+static u32 priv_tramp_sect_alloc(struct dload_state *dlthis, u32 tramp_size)
+{
+ u32 ret_val;
+
+ /* If the next available address is 0, this is our first allocation.
+ * Create a section name string to go into the string table . */
+ if (dlthis->tramp.tramp_sect_next_addr == 0) {
+ dload_syms_error(dlthis->mysym, "*** WARNING *** created "
+ "dynamic TRAMPOLINE section for module %s",
+ dlthis->str_head);
+ }
+
+ /* Reserve space for the new trampoline */
+ ret_val = dlthis->tramp.tramp_sect_next_addr;
+ dlthis->tramp.tramp_sect_next_addr += tramp_size;
+ return ret_val;
+}
+
+/*
+ * Function: priv_tramp_sym_create
+ * Description: Allocate and create a new trampoline specific symbol and add
+ * it to the trampoline symbol list. These symbols will include
+ * trampoline points as well as the external symbols they
+ * reference.
+ */
+static struct tramp_sym *priv_tramp_sym_create(struct dload_state *dlthis,
+ u32 str_index,
+ struct local_symbol *tmp_sym)
+{
+ struct tramp_sym *new_sym = NULL;
+ u32 i;
+
+ /* Allocate new space for the symbol in the symbol table. */
+ new_sym =
+ (struct tramp_sym *)dlthis->mysym->dload_allocate(dlthis->mysym,
+ sizeof(struct tramp_sym));
+ if (new_sym != NULL) {
+ for (i = 0; i != sizeof(struct tramp_sym); i++)
+ *((char *)new_sym + i) = 0;
+
+ /* Assign this symbol the next symbol index for easier
+ * reference later during relocation. */
+ new_sym->index = dlthis->tramp.tramp_sym_next_index;
+ dlthis->tramp.tramp_sym_next_index++;
+
+ /* Populate the symbol information. At this point any
+ * trampoline symbols will be the offset location, not the
+ * final. Copy over the symbol info to start, then be sure to
+ * get the string index from the trampoline string table. */
+ new_sym->sym_info = *tmp_sym;
+ new_sym->str_index = str_index;
+
+ /* Push the new symbol to the tail of the symbol table list */
+ new_sym->next = NULL;
+ if (dlthis->tramp.symbol_head == NULL)
+ dlthis->tramp.symbol_head = new_sym;
+ else
+ dlthis->tramp.symbol_tail->next = new_sym;
+
+ dlthis->tramp.symbol_tail = new_sym;
+ }
+
+ return new_sym;
+}
+
+/*
+ * Function: priv_tramp_sym_get
+ * Description: Search for the symbol with the matching string index (from
+ * the trampoline string table) and return the trampoline
+ * symbol object, if found. Otherwise return NULL.
+ */
+static struct tramp_sym *priv_tramp_sym_get(struct dload_state *dlthis,
+ u32 string_index)
+{
+ struct tramp_sym *sym_found = NULL;
+
+ /* Walk the symbol table list and search vs. the string index */
+ for (sym_found = dlthis->tramp.symbol_head;
+ sym_found != NULL; sym_found = sym_found->next) {
+ if (sym_found->str_index == string_index)
+ break;
+ }
+
+ return sym_found;
+}
+
+/*
+ * Function: priv_tramp_sym_find
+ * Description: Search for a trampoline symbol based on the string name of
+ * the symbol. Return the symbol object, if found, otherwise
+ * return NULL.
+ */
+static struct tramp_sym *priv_tramp_sym_find(struct dload_state *dlthis,
+ char *string)
+{
+ struct tramp_sym *sym_found = NULL;
+ struct tramp_string *str_found = NULL;
+
+ /* First, search for the string, then search for the sym based on the
+ string index. */
+ str_found = priv_tramp_string_find(dlthis, string);
+ if (str_found != NULL)
+ sym_found = priv_tramp_sym_get(dlthis, str_found->index);
+
+ return sym_found;
+}
+
+/*
+ * Function: priv_tramp_sym_finalize
+ * Description: Allocate a flat symbol table for the trampoline section,
+ * put each trampoline symbol into the table, adjust the
+ * symbol value based on the section address on the target and
+ * free the trampoline symbol list nodes.
+ */
+static int priv_tramp_sym_finalize(struct dload_state *dlthis)
+{
+ int ret_val = 0;
+ struct tramp_sym *cur_sym;
+ struct ldr_section_info *tramp_sect =
+ &dlthis->ldr_sections[dlthis->allocated_secn_count];
+ struct local_symbol *new_sym;
+
+ /* Allocate a table to hold a flattened version of all symbols
+ * created. */
+ dlthis->tramp.final_sym_table =
+ (struct local_symbol *)dlthis->mysym->dload_allocate(dlthis->mysym,
+ (sizeof(struct local_symbol) * dlthis->tramp.
+ tramp_sym_next_index));
+ if (dlthis->tramp.final_sym_table != NULL) {
+ /* Walk the list of all symbols, copy it over to the flattened
+ * table. After it has been copied, the node can be freed as
+ * it is no longer needed. */
+ new_sym = dlthis->tramp.final_sym_table;
+ cur_sym = dlthis->tramp.symbol_head;
+ while (cur_sym != NULL) {
+ /* Pop it off the list */
+ dlthis->tramp.symbol_head = cur_sym->next;
+ if (cur_sym == dlthis->tramp.symbol_tail)
+ dlthis->tramp.symbol_tail = NULL;
+
+ /* Copy the symbol contents into the flat table */
+ *new_sym = cur_sym->sym_info;
+
+ /* Now finaize the symbol. If it is in the tramp
+ * section, we need to adjust for the section start.
+ * If it is external then we don't need to adjust at
+ * all.
+ * NOTE: THIS CODE ASSUMES THAT THE TRAMPOLINE IS
+ * REFERENCED LIKE A CALL TO AN EXTERNAL SO VALUE AND
+ * DELTA ARE THE SAME. SEE THE FUNCTION dload_symbols
+ * WHERE DN_UNDEF IS HANDLED FOR MORE REFERENCE. */
+ if (new_sym->secnn < 0) {
+ new_sym->value += tramp_sect->load_addr;
+ new_sym->delta = new_sym->value;
+ }
+
+ /* Let go of the symbol node */
+ dlthis->mysym->dload_deallocate(dlthis->mysym, cur_sym);
+
+ /* Move to the next node */
+ cur_sym = dlthis->tramp.symbol_head;
+ new_sym++;
+ }
+
+ ret_val = 1;
+ } else
+ dload_error(dlthis, "Failed to alloc trampoline sym table");
+
+ return ret_val;
+}
+
+/*
+ * Function: priv_tgt_img_gen
+ * Description: Allocate storage for and copy the target specific image data
+ * and fix up its relocations for the new external symbol. If
+ * a trampoline image packet was successfully created it is added
+ * to the trampoline list.
+ */
+static int priv_tgt_img_gen(struct dload_state *dlthis, u32 base,
+ u32 gen_index, struct tramp_sym *new_ext_sym)
+{
+ struct tramp_img_pkt *new_img_pkt = NULL;
+ u32 i;
+ u32 pkt_size = tramp_img_pkt_size_get();
+ u8 *gen_tbl_entry;
+ u8 *pkt_data;
+ struct reloc_record_t *cur_relo;
+ int ret_val = 0;
+
+ /* Allocate a new image packet and set it up. */
+ new_img_pkt =
+ (struct tramp_img_pkt *)dlthis->mysym->dload_allocate(dlthis->mysym,
+ pkt_size);
+ if (new_img_pkt != NULL) {
+ /* Save the base, this is where it goes in the section */
+ new_img_pkt->base = base;
+
+ /* Copy over the image data and relos from the target table */
+ pkt_data = (u8 *) &new_img_pkt->hdr;
+ gen_tbl_entry = (u8 *) &tramp_gen_info[gen_index];
+ for (i = 0; i < pkt_size; i++) {
+ *pkt_data = *gen_tbl_entry;
+ pkt_data++;
+ gen_tbl_entry++;
+ }
+
+ /* Update the relocations to point to the external symbol */
+ cur_relo =
+ (struct reloc_record_t *)((u8 *) &new_img_pkt->hdr +
+ new_img_pkt->hdr.relo_offset);
+ for (i = 0; i < new_img_pkt->hdr.num_relos; i++)
+ cur_relo[i].SYMNDX = new_ext_sym->index;
+
+ /* Add it to the trampoline list. */
+ new_img_pkt->next = dlthis->tramp.tramp_pkts;
+ dlthis->tramp.tramp_pkts = new_img_pkt;
+
+ ret_val = 1;
+ }
+
+ return ret_val;
+}
+
+/*
+ * Function: priv_pkt_relo
+ * Description: Take the provided image data and the collection of relocations
+ * for it and perform the relocations. Note that all relocations
+ * at this stage are considered SECOND PASS since the original
+ * image has already been processed in the first pass. This means
+ * TRAMPOLINES ARE TREATED AS 2ND PASS even though this is really
+ * the first (and only) relocation that will be performed on them.
+ */
+static int priv_pkt_relo(struct dload_state *dlthis, tgt_au_t * data,
+ struct reloc_record_t *rp[], u32 relo_count)
+{
+ int ret_val = 1;
+ u32 i;
+ bool tmp;
+
+ /* Walk through all of the relos and process them. This function is
+ * the equivalent of relocate_packet() from cload.c, but specialized
+ * for trampolines and 2nd phase relocations. */
+ for (i = 0; i < relo_count; i++)
+ dload_relocate(dlthis, data, rp[i], &tmp, true);
+
+ return ret_val;
+}
+
+/*
+ * Function: priv_tramp_pkt_finalize
+ * Description: Walk the list of all trampoline packets and finalize them.
+ * Each trampoline image packet will be relocated now that the
+ * trampoline section has been allocated on the target. Once
+ * all of the relocations are done the trampoline image data
+ * is written into target memory and the trampoline packet
+ * is freed: it is no longer needed after this point.
+ */
+static int priv_tramp_pkt_finalize(struct dload_state *dlthis)
+{
+ int ret_val = 1;
+ struct tramp_img_pkt *cur_pkt = NULL;
+ struct reloc_record_t *relos[MAX_RELOS_PER_PASS];
+ u32 relos_done;
+ u32 i;
+ struct reloc_record_t *cur_relo;
+ struct ldr_section_info *sect_info =
+ &dlthis->ldr_sections[dlthis->allocated_secn_count];
+
+ /* Walk the list of trampoline packets and relocate each packet. This
+ * function is the trampoline equivalent of dload_data() from
+ * cload.c. */
+ cur_pkt = dlthis->tramp.tramp_pkts;
+ while ((ret_val != 0) && (cur_pkt != NULL)) {
+ /* Remove the pkt from the list */
+ dlthis->tramp.tramp_pkts = cur_pkt->next;
+
+ /* Setup section and image offset information for the relo */
+ dlthis->image_secn = sect_info;
+ dlthis->image_offset = cur_pkt->base;
+ dlthis->delta_runaddr = sect_info->run_addr;
+
+ /* Walk through all relos for the packet */
+ relos_done = 0;
+ cur_relo = (struct reloc_record_t *)((u8 *) &cur_pkt->hdr +
+ cur_pkt->hdr.relo_offset);
+ while (relos_done < cur_pkt->hdr.num_relos) {
+#ifdef ENABLE_TRAMP_DEBUG
+ dload_syms_error(dlthis->mysym,
+ "===> Trampoline %x branches to %x",
+ sect_info->run_addr +
+ dlthis->image_offset,
+ dlthis->
+ tramp.final_sym_table[cur_relo->
+ SYMNDX].value);
+#endif
+
+ for (i = 0;
+ ((i < MAX_RELOS_PER_PASS) &&
+ ((i + relos_done) < cur_pkt->hdr.num_relos)); i++)
+ relos[i] = cur_relo + i;
+
+ /* Do the actual relo */
+ ret_val = priv_pkt_relo(dlthis,
+ (tgt_au_t *) &cur_pkt->payload,
+ relos, i);
+ if (ret_val == 0) {
+ dload_error(dlthis,
+ "Relocation of trampoline pkt at %x"
+ " failed", cur_pkt->base +
+ sect_info->run_addr);
+ break;
+ }
+
+ relos_done += i;
+ cur_relo += i;
+ }
+
+ /* Make sure we didn't hit a problem */
+ if (ret_val != 0) {
+ /* Relos are done for the packet, write it to the
+ * target */
+ ret_val = dlthis->myio->writemem(dlthis->myio,
+ &cur_pkt->payload,
+ sect_info->load_addr +
+ cur_pkt->base,
+ sect_info,
+ BYTE_TO_HOST
+ (cur_pkt->hdr.
+ tramp_code_size));
+ if (ret_val == 0) {
+ dload_error(dlthis,
+ "Write to " FMT_UI32 " failed",
+ sect_info->load_addr +
+ cur_pkt->base);
+ }
+
+ /* Done with the pkt, let it go */
+ dlthis->mysym->dload_deallocate(dlthis->mysym, cur_pkt);
+
+ /* Get the next packet to process */
+ cur_pkt = dlthis->tramp.tramp_pkts;
+ }
+ }
+
+ return ret_val;
+}
+
+/*
+ * Function: priv_dup_pkt_finalize
+ * Description: Walk the list of duplicate image packets and finalize them.
+ * Each duplicate packet will be relocated again for the
+ * relocations that previously failed and have been adjusted
+ * to point at a trampoline. Once all relocations for a packet
+ * have been done, write the packet into target memory. The
+ * duplicate packet and its relocation chain are all freed
+ * after use here as they are no longer needed after this.
+ */
+static int priv_dup_pkt_finalize(struct dload_state *dlthis)
+{
+ int ret_val = 1;
+ struct tramp_img_dup_pkt *cur_pkt;
+ struct tramp_img_dup_relo *cur_relo;
+ struct reloc_record_t *relos[MAX_RELOS_PER_PASS];
+ struct doff_scnhdr_t *sect_hdr = NULL;
+ s32 i;
+
+ /* Similar to the trampoline pkt finalize, this function walks each dup
+ * pkt that was generated and performs all relocations that were
+ * deferred to a 2nd pass. This is the equivalent of dload_data() from
+ * cload.c, but does not need the additional reorder and checksum
+ * processing as it has already been done. */
+ cur_pkt = dlthis->tramp.dup_pkts;
+ while ((ret_val != 0) && (cur_pkt != NULL)) {
+ /* Remove the node from the list, we'll be freeing it
+ * shortly */
+ dlthis->tramp.dup_pkts = cur_pkt->next;
+
+ /* Setup the section and image offset for relocation */
+ dlthis->image_secn = &dlthis->ldr_sections[cur_pkt->secnn];
+ dlthis->image_offset = cur_pkt->offset;
+
+ /* In order to get the delta run address, we need to reference
+ * the original section header. It's a bit ugly, but needed
+ * for relo. */
+ i = (s32) (dlthis->image_secn - dlthis->ldr_sections);
+ sect_hdr = dlthis->sect_hdrs + i;
+ dlthis->delta_runaddr = sect_hdr->ds_paddr;
+
+ /* Walk all relos in the chain and process each. */
+ cur_relo = cur_pkt->relo_chain;
+ while (cur_relo != NULL) {
+ /* Process them a chunk at a time to be efficient */
+ for (i = 0; (i < MAX_RELOS_PER_PASS)
+ && (cur_relo != NULL);
+ i++, cur_relo = cur_relo->next) {
+ relos[i] = &cur_relo->relo;
+ cur_pkt->relo_chain = cur_relo->next;
+ }
+
+ /* Do the actual relo */
+ ret_val = priv_pkt_relo(dlthis,
+ cur_pkt->img_pkt.img_data,
+ relos, i);
+ if (ret_val == 0) {
+ dload_error(dlthis,
+ "Relocation of dup pkt at %x"
+ " failed", cur_pkt->offset +
+ dlthis->image_secn->run_addr);
+ break;
+ }
+
+ /* Release all of these relos, we're done with them */
+ while (i > 0) {
+ dlthis->mysym->dload_deallocate(dlthis->mysym,
+ GET_CONTAINER
+ (relos[i - 1],
+ struct tramp_img_dup_relo,
+ relo));
+ i--;
+ }
+
+ /* DO NOT ADVANCE cur_relo, IT IS ALREADY READY TO
+ * GO! */
+ }
+
+ /* Done with all relos. Make sure we didn't have a problem and
+ * write it out to the target */
+ if (ret_val != 0) {
+ ret_val = dlthis->myio->writemem(dlthis->myio,
+ cur_pkt->img_pkt.
+ img_data,
+ dlthis->image_secn->
+ load_addr +
+ cur_pkt->offset,
+ dlthis->image_secn,
+ BYTE_TO_HOST
+ (cur_pkt->img_pkt.
+ packet_size));
+ if (ret_val == 0) {
+ dload_error(dlthis,
+ "Write to " FMT_UI32 " failed",
+ dlthis->image_secn->load_addr +
+ cur_pkt->offset);
+ }
+
+ dlthis->mysym->dload_deallocate(dlthis->mysym, cur_pkt);
+
+ /* Advance to the next packet */
+ cur_pkt = dlthis->tramp.dup_pkts;
+ }
+ }
+
+ return ret_val;
+}
+
+/*
+ * Function: priv_dup_find
+ * Description: Walk the list of existing duplicate packets and find a
+ * match based on the section number and image offset. Return
+ * the duplicate packet if found, otherwise NULL.
+ */
+static struct tramp_img_dup_pkt *priv_dup_find(struct dload_state *dlthis,
+ s16 secnn, u32 image_offset)
+{
+ struct tramp_img_dup_pkt *cur_pkt = NULL;
+
+ for (cur_pkt = dlthis->tramp.dup_pkts;
+ cur_pkt != NULL; cur_pkt = cur_pkt->next) {
+ if ((cur_pkt->secnn == secnn) &&
+ (cur_pkt->offset == image_offset)) {
+ /* Found a match, break out */
+ break;
+ }
+ }
+
+ return cur_pkt;
+}
+
+/*
+ * Function: priv_img_pkt_dup
+ * Description: Duplicate the original image packet. If this is the first
+ * time this image packet has been seen (based on section number
+ * and image offset), create a new duplicate packet and add it
+ * to the dup packet list. If not, just get the existing one and
+ * update it with the current packet contents (since relocation
+ * on the packet is still ongoing in first pass.) Create a
+ * duplicate of the provided relocation, but update it to point
+ * to the new trampoline symbol. Add the new relocation dup to
+ * the dup packet's relo chain for 2nd pass relocation later.
+ */
+static int priv_img_pkt_dup(struct dload_state *dlthis,
+ s16 secnn, u32 image_offset,
+ struct image_packet_t *ipacket,
+ struct reloc_record_t *rp,
+ struct tramp_sym *new_tramp_sym)
+{
+ struct tramp_img_dup_pkt *dup_pkt = NULL;
+ u32 new_dup_size;
+ s32 i;
+ int ret_val = 0;
+ struct tramp_img_dup_relo *dup_relo = NULL;
+
+ /* Determinne if this image packet is already being tracked in the
+ dup list for other trampolines. */
+ dup_pkt = priv_dup_find(dlthis, secnn, image_offset);
+
+ if (dup_pkt == NULL) {
+ /* This image packet does not exist in our tracking, so create
+ * a new one and add it to the head of the list. */
+ new_dup_size = sizeof(struct tramp_img_dup_pkt) +
+ ipacket->packet_size;
+
+ dup_pkt = (struct tramp_img_dup_pkt *)
+ dlthis->mysym->dload_allocate(dlthis->mysym, new_dup_size);
+ if (dup_pkt != NULL) {
+ /* Save off the section and offset information */
+ dup_pkt->secnn = secnn;
+ dup_pkt->offset = image_offset;
+ dup_pkt->relo_chain = NULL;
+
+ /* Copy the original packet content */
+ dup_pkt->img_pkt = *ipacket;
+ dup_pkt->img_pkt.img_data = (u8 *) (dup_pkt + 1);
+ for (i = 0; i < ipacket->packet_size; i++)
+ *(dup_pkt->img_pkt.img_data + i) =
+ *(ipacket->img_data + i);
+
+ /* Add the packet to the dup list */
+ dup_pkt->next = dlthis->tramp.dup_pkts;
+ dlthis->tramp.dup_pkts = dup_pkt;
+ } else
+ dload_error(dlthis, "Failed to create dup packet!");
+ } else {
+ /* The image packet contents could have changed since
+ * trampoline detection happens during relocation of the image
+ * packets. So, we need to update the image packet contents
+ * before adding relo information. */
+ for (i = 0; i < dup_pkt->img_pkt.packet_size; i++)
+ *(dup_pkt->img_pkt.img_data + i) =
+ *(ipacket->img_data + i);
+ }
+
+ /* Since the previous code may have allocated a new dup packet for us,
+ double check that we actually have one. */
+ if (dup_pkt != NULL) {
+ /* Allocate a new node for the relo chain. Each image packet
+ * can potentially have multiple relocations that cause a
+ * trampoline to be generated. So, we keep them in a chain,
+ * order is not important. */
+ dup_relo = dlthis->mysym->dload_allocate(dlthis->mysym,
+ sizeof(struct tramp_img_dup_relo));
+ if (dup_relo != NULL) {
+ /* Copy the relo contents, adjust for the new
+ * trampoline and add it to the list. */
+ dup_relo->relo = *rp;
+ dup_relo->relo.SYMNDX = new_tramp_sym->index;
+
+ dup_relo->next = dup_pkt->relo_chain;
+ dup_pkt->relo_chain = dup_relo;
+
+ /* That's it, we're done. Make sure we update our
+ * return value to be success since everything finished
+ * ok */
+ ret_val = 1;
+ } else
+ dload_error(dlthis, "Unable to alloc dup relo");
+ }
+
+ return ret_val;
+}
+
+/*
+ * Function: dload_tramp_avail
+ * Description: Check to see if the target supports a trampoline for this type
+ * of relocation. Return true if it does, otherwise false.
+ */
+bool dload_tramp_avail(struct dload_state *dlthis, struct reloc_record_t *rp)
+{
+ bool ret_val = false;
+ u16 map_index;
+ u16 gen_index;
+
+ /* Check type hash vs. target tramp table */
+ map_index = HASH_FUNC(rp->TYPE);
+ gen_index = tramp_map[map_index];
+ if (gen_index != TRAMP_NO_GEN_AVAIL)
+ ret_val = true;
+
+ return ret_val;
+}
+
+/*
+ * Function: dload_tramp_generate
+ * Description: Create a new trampoline for the provided image packet and
+ * relocation causing problems. This will create the trampoline
+ * as well as duplicate/update the image packet and relocation
+ * causing the problem, which will be relo'd again during
+ * finalization.
+ */
+int dload_tramp_generate(struct dload_state *dlthis, s16 secnn,
+ u32 image_offset, struct image_packet_t *ipacket,
+ struct reloc_record_t *rp)
+{
+ u16 map_index;
+ u16 gen_index;
+ int ret_val = 1;
+ char tramp_sym_str[TRAMP_SYM_PREFIX_LEN + TRAMP_SYM_HEX_ASCII_LEN];
+ struct local_symbol *ref_sym;
+ struct tramp_sym *new_tramp_sym;
+ struct tramp_sym *new_ext_sym;
+ struct tramp_string *new_tramp_str;
+ u32 new_tramp_base;
+ struct local_symbol tmp_sym;
+ struct local_symbol ext_tmp_sym;
+
+ /* Hash the relo type to get our generator information */
+ map_index = HASH_FUNC(rp->TYPE);
+ gen_index = tramp_map[map_index];
+ if (gen_index != TRAMP_NO_GEN_AVAIL) {
+ /* If this is the first trampoline, create the section name in
+ * our string table for debug help later. */
+ if (dlthis->tramp.string_head == NULL) {
+ priv_tramp_string_create(dlthis,
+ strlen(TRAMP_SECT_NAME),
+ TRAMP_SECT_NAME);
+ }
+#ifdef ENABLE_TRAMP_DEBUG
+ dload_syms_error(dlthis->mysym,
+ "Trampoline at img loc %x, references %x",
+ dlthis->ldr_sections[secnn].run_addr +
+ image_offset + rp->vaddr,
+ dlthis->local_symtab[rp->SYMNDX].value);
+#endif
+
+ /* Generate the trampoline string, check if already defined.
+ * If the relo symbol index is -1, it means we need the section
+ * info for relo later. To do this we'll dummy up a symbol
+ * with the section delta and run addresses. */
+ if (rp->SYMNDX == -1) {
+ ext_tmp_sym.value =
+ dlthis->ldr_sections[secnn].run_addr;
+ ext_tmp_sym.delta = dlthis->sect_hdrs[secnn].ds_paddr;
+ ref_sym = &ext_tmp_sym;
+ } else
+ ref_sym = &(dlthis->local_symtab[rp->SYMNDX]);
+
+ priv_tramp_sym_gen_name(ref_sym->value, tramp_sym_str);
+ new_tramp_sym = priv_tramp_sym_find(dlthis, tramp_sym_str);
+ if (new_tramp_sym == NULL) {
+ /* If tramp string not defined, create it and a new
+ * string, and symbol for it as well as the original
+ * symbol which caused the trampoline. */
+ new_tramp_str = priv_tramp_string_create(dlthis,
+ strlen
+ (tramp_sym_str),
+ tramp_sym_str);
+ if (new_tramp_str == NULL) {
+ dload_error(dlthis, "Failed to create new "
+ "trampoline string\n");
+ ret_val = 0;
+ } else {
+ /* Allocate tramp section space for the new
+ * tramp from the target */
+ new_tramp_base = priv_tramp_sect_alloc(dlthis,
+ tramp_size_get());
+
+ /* We have a string, create the new symbol and
+ * duplicate the external. */
+ tmp_sym.value = new_tramp_base;
+ tmp_sym.delta = 0;
+ tmp_sym.secnn = -1;
+ tmp_sym.sclass = 0;
+ new_tramp_sym = priv_tramp_sym_create(dlthis,
+ new_tramp_str->
+ index,
+ &tmp_sym);
+
+ new_ext_sym = priv_tramp_sym_create(dlthis, -1,
+ ref_sym);
+
+ if ((new_tramp_sym != NULL) &&
+ (new_ext_sym != NULL)) {
+ /* Call the image generator to get the
+ * new image data and fix up its
+ * relocations for the external
+ * symbol. */
+ ret_val = priv_tgt_img_gen(dlthis,
+ new_tramp_base,
+ gen_index,
+ new_ext_sym);
+
+ /* Add generated image data to tramp
+ * image list */
+ if (ret_val != 1) {
+ dload_error(dlthis, "Failed to "
+ "create img pkt for"
+ " trampoline\n");
+ }
+ } else {
+ dload_error(dlthis, "Failed to create "
+ "new tramp syms "
+ "(%8.8X, %8.8X)\n",
+ new_tramp_sym, new_ext_sym);
+ ret_val = 0;
+ }
+ }
+ }
+
+ /* Duplicate the image data and relo record that caused the
+ * tramp, including update the relo data to point to the tramp
+ * symbol. */
+ if (ret_val == 1) {
+ ret_val = priv_img_pkt_dup(dlthis, secnn, image_offset,
+ ipacket, rp, new_tramp_sym);
+ if (ret_val != 1) {
+ dload_error(dlthis, "Failed to create dup of "
+ "original img pkt\n");
+ }
+ }
+ }
+
+ return ret_val;
+}
+
+/*
+ * Function: dload_tramp_pkt_update
+ * Description: Update the duplicate copy of this image packet, which the
+ * trampoline layer is already tracking. This is call is critical
+ * to make if trampolines were generated anywhere within the
+ * packet and first pass relo continued on the remainder. The
+ * trampoline layer needs the updates image data so when 2nd
+ * pass relo is done during finalize the image packet can be
+ * written to the target since all relo is done.
+ */
+int dload_tramp_pkt_udpate(struct dload_state *dlthis, s16 secnn,
+ u32 image_offset, struct image_packet_t *ipacket)
+{
+ struct tramp_img_dup_pkt *dup_pkt = NULL;
+ s32 i;
+ int ret_val = 0;
+
+ /* Find the image packet in question, the caller needs us to update it
+ since a trampoline was previously generated. */
+ dup_pkt = priv_dup_find(dlthis, secnn, image_offset);
+ if (dup_pkt != NULL) {
+ for (i = 0; i < dup_pkt->img_pkt.packet_size; i++)
+ *(dup_pkt->img_pkt.img_data + i) =
+ *(ipacket->img_data + i);
+
+ ret_val = 1;
+ } else {
+ dload_error(dlthis,
+ "Unable to find existing DUP pkt for %x, offset %x",
+ secnn, image_offset);
+
+ }
+
+ return ret_val;
+}
+
+/*
+ * Function: dload_tramp_finalize
+ * Description: If any trampolines were created, finalize everything on the
+ * target by allocating the trampoline section on the target,
+ * finalizing the trampoline symbols, finalizing the trampoline
+ * packets (write the new section to target memory) and finalize
+ * the duplicate packets by doing 2nd pass relo over them.
+ */
+int dload_tramp_finalize(struct dload_state *dlthis)
+{
+ int ret_val = 1;
+
+ if (dlthis->tramp.tramp_sect_next_addr != 0) {
+ /* Finalize strings into a flat table. This is needed so it
+ * can be added to the debug string table later. */
+ ret_val = priv_string_tbl_finalize(dlthis);
+
+ /* Do target allocation for section BEFORE finalizing
+ * symbols. */
+ if (ret_val != 0)
+ ret_val = priv_tramp_sect_tgt_alloc(dlthis);
+
+ /* Finalize symbols with their correct target information and
+ * flatten */
+ if (ret_val != 0)
+ ret_val = priv_tramp_sym_finalize(dlthis);
+
+ /* Finalize all trampoline packets. This performs the
+ * relocation on the packets as well as writing them to target
+ * memory. */
+ if (ret_val != 0)
+ ret_val = priv_tramp_pkt_finalize(dlthis);
+
+ /* Perform a 2nd pass relocation on the dup list. */
+ if (ret_val != 0)
+ ret_val = priv_dup_pkt_finalize(dlthis);
+ }
+
+ return ret_val;
+}
+
+/*
+ * Function: dload_tramp_cleanup
+ * Description: Release all temporary resources used in the trampoline layer.
+ * Note that the target memory which may have been allocated and
+ * written to store the trampolines is NOT RELEASED HERE since it
+ * is potentially still in use. It is automatically released
+ * when the module is unloaded.
+ */
+void dload_tramp_cleanup(struct dload_state *dlthis)
+{
+ struct tramp_info *tramp = &dlthis->tramp;
+ struct tramp_sym *cur_sym;
+ struct tramp_string *cur_string;
+ struct tramp_img_pkt *cur_tramp_pkt;
+ struct tramp_img_dup_pkt *cur_dup_pkt;
+ struct tramp_img_dup_relo *cur_dup_relo;
+
+ /* If there were no tramps generated, just return */
+ if (tramp->tramp_sect_next_addr == 0)
+ return;
+
+ /* Destroy all tramp information */
+ for (cur_sym = tramp->symbol_head;
+ cur_sym != NULL; cur_sym = tramp->symbol_head) {
+ tramp->symbol_head = cur_sym->next;
+ if (tramp->symbol_tail == cur_sym)
+ tramp->symbol_tail = NULL;
+
+ dlthis->mysym->dload_deallocate(dlthis->mysym, cur_sym);
+ }
+
+ if (tramp->final_sym_table != NULL)
+ dlthis->mysym->dload_deallocate(dlthis->mysym,
+ tramp->final_sym_table);
+
+ for (cur_string = tramp->string_head;
+ cur_string != NULL; cur_string = tramp->string_head) {
+ tramp->string_head = cur_string->next;
+ if (tramp->string_tail == cur_string)
+ tramp->string_tail = NULL;
+
+ dlthis->mysym->dload_deallocate(dlthis->mysym, cur_string);
+ }
+
+ if (tramp->final_string_table != NULL)
+ dlthis->mysym->dload_deallocate(dlthis->mysym,
+ tramp->final_string_table);
+
+ for (cur_tramp_pkt = tramp->tramp_pkts;
+ cur_tramp_pkt != NULL; cur_tramp_pkt = tramp->tramp_pkts) {
+ tramp->tramp_pkts = cur_tramp_pkt->next;
+ dlthis->mysym->dload_deallocate(dlthis->mysym, cur_tramp_pkt);
+ }
+
+ for (cur_dup_pkt = tramp->dup_pkts;
+ cur_dup_pkt != NULL; cur_dup_pkt = tramp->dup_pkts) {
+ tramp->dup_pkts = cur_dup_pkt->next;
+
+ for (cur_dup_relo = cur_dup_pkt->relo_chain;
+ cur_dup_relo != NULL;
+ cur_dup_relo = cur_dup_pkt->relo_chain) {
+ cur_dup_pkt->relo_chain = cur_dup_relo->next;
+ dlthis->mysym->dload_deallocate(dlthis->mysym,
+ cur_dup_relo);
+ }
+
+ dlthis->mysym->dload_deallocate(dlthis->mysym, cur_dup_pkt);
+ }
+}
diff --git a/drivers/staging/tidspbridge/dynload/tramp_table_c6000.c b/drivers/staging/tidspbridge/dynload/tramp_table_c6000.c
new file mode 100644
index 00000000000..09cc64f213c
--- /dev/null
+++ b/drivers/staging/tidspbridge/dynload/tramp_table_c6000.c
@@ -0,0 +1,164 @@
+/*
+ * tramp_table_c6000.c
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * Copyright (C) 2005-2006 Texas Instruments, Inc.
+ *
+ * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include "dload_internal.h"
+
+/* These are defined in coff.h, but may not be available on all platforms
+ so we'll go ahead and define them here. */
+#ifndef R_C60LO16
+#define R_C60LO16 0x54 /* C60: MVK Low Half Register */
+#define R_C60HI16 0x55 /* C60: MVKH/MVKLH High Half Register */
+#endif
+
+#define C6X_TRAMP_WORD_COUNT 8
+#define C6X_TRAMP_MAX_RELOS 8
+
+/* THIS HASH FUNCTION MUST MATCH THE ONE reloc_table_c6000.c */
+#define HASH_FUNC(zz) (((((zz) + 1) * 1845UL) >> 11) & 63)
+
+/* THIS MUST MATCH reloc_record_t FOR A SYMBOL BASED RELO */
+struct c6000_relo_record {
+ s32 vaddr;
+ s32 symndx;
+#ifndef _BIG_ENDIAN
+ u16 disp;
+ u16 type;
+#else
+ u16 type;
+ u16 disp;
+#endif
+};
+
+struct c6000_gen_code {
+ struct tramp_gen_code_hdr hdr;
+ u32 tramp_instrs[C6X_TRAMP_WORD_COUNT];
+ struct c6000_relo_record relos[C6X_TRAMP_MAX_RELOS];
+};
+
+/* Hash mapping for relos that can cause trampolines. */
+static const u16 tramp_map[] = {
+ 65535,
+ 65535,
+ 65535,
+ 65535,
+ 65535,
+ 65535,
+ 65535,
+ 65535,
+ 65535,
+ 65535,
+ 0,
+ 65535,
+ 65535,
+ 65535,
+ 65535,
+ 65535,
+ 65535,
+ 65535,
+ 65535,
+ 65535,
+ 65535,
+ 65535,
+ 65535,
+ 65535,
+ 65535,
+ 65535,
+ 65535,
+ 65535,
+ 65535,
+ 65535,
+ 65535,
+ 65535,
+ 65535,
+ 65535,
+ 65535,
+ 65535,
+ 65535,
+ 65535,
+ 65535,
+ 65535,
+ 65535,
+ 65535,
+ 65535,
+ 65535,
+ 65535,
+ 65535,
+ 65535,
+ 65535,
+ 65535,
+ 65535,
+ 65535,
+ 65535,
+ 65535,
+ 65535,
+ 65535,
+ 65535,
+ 65535,
+ 65535,
+ 65535,
+ 65535,
+ 65535,
+ 65535,
+ 65535,
+ 65535
+};
+
+static const struct c6000_gen_code tramp_gen_info[] = {
+ /* Tramp caused by R_C60PCR21 */
+ {
+ /* Header - 8 instructions, 2 relos */
+ {
+ sizeof(u32) * C6X_TRAMP_WORD_COUNT,
+ 2,
+ FIELD_OFFSET(struct c6000_gen_code, relos)
+ },
+
+ /* Trampoline instructions */
+ {
+ 0x053C54F7, /* STW.D2T2 B10, *sp--[2] */
+ 0x0500002A, /* || MVK.S2 <blank>, B10 */
+ 0x0500006A, /* MVKH.S2 <blank>, B10 */
+ 0x00280362, /* B.S2 B10 */
+ 0x053C52E6, /* LDW.D2T2 *++sp[2], B10 */
+ 0x00006000, /* NOP 4 */
+ 0x00000000, /* NOP */
+ 0x00000000 /* NOP */
+ },
+
+ /* Relocations */
+ {
+ {4, 0, 0, R_C60LO16},
+ {8, 0, 0, R_C60HI16},
+ {0, 0, 0, 0x0000},
+ {0, 0, 0, 0x0000},
+ {0, 0, 0, 0x0000},
+ {0, 0, 0, 0x0000},
+ {0, 0, 0, 0x0000},
+ {0, 0, 0, 0x0000}
+ }
+ }
+};
+
+/* TARGET SPECIFIC FUNCTIONS THAT MUST BE DEFINED */
+static u32 tramp_size_get(void)
+{
+ return sizeof(u32) * C6X_TRAMP_WORD_COUNT;
+}
+
+static u32 tramp_img_pkt_size_get(void)
+{
+ return sizeof(struct c6000_gen_code);
+}
diff --git a/drivers/staging/tidspbridge/gen/gb.c b/drivers/staging/tidspbridge/gen/gb.c
new file mode 100644
index 00000000000..06eb3d36122
--- /dev/null
+++ b/drivers/staging/tidspbridge/gen/gb.c
@@ -0,0 +1,167 @@
+/*
+ * gb.c
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * Generic bitmap operations.
+ *
+ * Copyright (C) 2005-2006 Texas Instruments, Inc.
+ *
+ * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+#include <linux/types.h>
+
+/* ----------------------------------- DSP/BIOS Bridge */
+#include <linux/types.h>
+/* ----------------------------------- This */
+#include <dspbridge/gs.h>
+#include <dspbridge/gb.h>
+
+struct gb_t_map {
+ u32 len;
+ u32 wcnt;
+ u32 *words;
+};
+
+/*
+ * ======== gb_clear ========
+ * purpose:
+ * Clears a bit in the bit map.
+ */
+
+void gb_clear(struct gb_t_map *map, u32 bitn)
+{
+ u32 mask;
+
+ mask = 1L << (bitn % BITS_PER_LONG);
+ map->words[bitn / BITS_PER_LONG] &= ~mask;
+}
+
+/*
+ * ======== gb_create ========
+ * purpose:
+ * Creates a bit map.
+ */
+
+struct gb_t_map *gb_create(u32 len)
+{
+ struct gb_t_map *map;
+ u32 i;
+ map = (struct gb_t_map *)gs_alloc(sizeof(struct gb_t_map));
+ if (map != NULL) {
+ map->len = len;
+ map->wcnt = len / BITS_PER_LONG + 1;
+ map->words = (u32 *) gs_alloc(map->wcnt * sizeof(u32));
+ if (map->words != NULL) {
+ for (i = 0; i < map->wcnt; i++)
+ map->words[i] = 0L;
+
+ } else {
+ gs_frees(map, sizeof(struct gb_t_map));
+ map = NULL;
+ }
+ }
+
+ return map;
+}
+
+/*
+ * ======== gb_delete ========
+ * purpose:
+ * Frees a bit map.
+ */
+
+void gb_delete(struct gb_t_map *map)
+{
+ gs_frees(map->words, map->wcnt * sizeof(u32));
+ gs_frees(map, sizeof(struct gb_t_map));
+}
+
+/*
+ * ======== gb_findandset ========
+ * purpose:
+ * Finds a free bit and sets it.
+ */
+u32 gb_findandset(struct gb_t_map *map)
+{
+ u32 bitn;
+
+ bitn = gb_minclear(map);
+
+ if (bitn != GB_NOBITS)
+ gb_set(map, bitn);
+
+ return bitn;
+}
+
+/*
+ * ======== gb_minclear ========
+ * purpose:
+ * returns the location of the first unset bit in the bit map.
+ */
+u32 gb_minclear(struct gb_t_map *map)
+{
+ u32 bit_location = 0;
+ u32 bit_acc = 0;
+ u32 i;
+ u32 bit;
+ u32 *word;
+
+ for (word = map->words, i = 0; i < map->wcnt; word++, i++) {
+ if (~*word) {
+ for (bit = 0; bit < BITS_PER_LONG; bit++, bit_acc++) {
+ if (bit_acc == map->len)
+ return GB_NOBITS;
+
+ if (~*word & (1L << bit)) {
+ bit_location = i * BITS_PER_LONG + bit;
+ return bit_location;
+ }
+
+ }
+ } else {
+ bit_acc += BITS_PER_LONG;
+ }
+ }
+
+ return GB_NOBITS;
+}
+
+/*
+ * ======== gb_set ========
+ * purpose:
+ * Sets a bit in the bit map.
+ */
+
+void gb_set(struct gb_t_map *map, u32 bitn)
+{
+ u32 mask;
+
+ mask = 1L << (bitn % BITS_PER_LONG);
+ map->words[bitn / BITS_PER_LONG] |= mask;
+}
+
+/*
+ * ======== gb_test ========
+ * purpose:
+ * Returns true if the bit is set in the specified location.
+ */
+
+bool gb_test(struct gb_t_map *map, u32 bitn)
+{
+ bool state;
+ u32 mask;
+ u32 word;
+
+ mask = 1L << (bitn % BITS_PER_LONG);
+ word = map->words[bitn / BITS_PER_LONG];
+ state = word & mask ? true : false;
+
+ return state;
+}
diff --git a/drivers/staging/tidspbridge/gen/gh.c b/drivers/staging/tidspbridge/gen/gh.c
new file mode 100644
index 00000000000..f72d943c480
--- /dev/null
+++ b/drivers/staging/tidspbridge/gen/gh.c
@@ -0,0 +1,215 @@
+/*
+ * gh.c
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * Copyright (C) 2005-2006 Texas Instruments, Inc.
+ *
+ * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include <linux/types.h>
+
+#include <dspbridge/host_os.h>
+
+#include <dspbridge/gs.h>
+
+#include <dspbridge/gh.h>
+
+struct element {
+ struct element *next;
+ u8 data[1];
+};
+
+struct gh_t_hash_tab {
+ u16 max_bucket;
+ u16 val_size;
+ struct element **buckets;
+ u16(*hash) (void *, u16);
+ bool(*match) (void *, void *);
+ void (*delete) (void *);
+};
+
+static void noop(void *p);
+static s32 cur_init;
+static void myfree(void *ptr, s32 size);
+
+/*
+ * ======== gh_create ========
+ */
+
+struct gh_t_hash_tab *gh_create(u16 max_bucket, u16 val_size,
+ u16(*hash) (void *, u16), bool(*match) (void *,
+ void *),
+ void (*delete) (void *))
+{
+ struct gh_t_hash_tab *hash_tab;
+ u16 i;
+ hash_tab =
+ (struct gh_t_hash_tab *)gs_alloc(sizeof(struct gh_t_hash_tab));
+ if (hash_tab == NULL)
+ return NULL;
+ hash_tab->max_bucket = max_bucket;
+ hash_tab->val_size = val_size;
+ hash_tab->hash = hash;
+ hash_tab->match = match;
+ hash_tab->delete = delete == NULL ? noop : delete;
+
+ hash_tab->buckets = (struct element **)
+ gs_alloc(sizeof(struct element *) * max_bucket);
+ if (hash_tab->buckets == NULL) {
+ gh_delete(hash_tab);
+ return NULL;
+ }
+
+ for (i = 0; i < max_bucket; i++)
+ hash_tab->buckets[i] = NULL;
+
+ return hash_tab;
+}
+
+/*
+ * ======== gh_delete ========
+ */
+void gh_delete(struct gh_t_hash_tab *hash_tab)
+{
+ struct element *elem, *next;
+ u16 i;
+
+ if (hash_tab != NULL) {
+ if (hash_tab->buckets != NULL) {
+ for (i = 0; i < hash_tab->max_bucket; i++) {
+ for (elem = hash_tab->buckets[i]; elem != NULL;
+ elem = next) {
+ next = elem->next;
+ (*hash_tab->delete) (elem->data);
+ myfree(elem,
+ sizeof(struct element) - 1 +
+ hash_tab->val_size);
+ }
+ }
+
+ myfree(hash_tab->buckets, sizeof(struct element *)
+ * hash_tab->max_bucket);
+ }
+
+ myfree(hash_tab, sizeof(struct gh_t_hash_tab));
+ }
+}
+
+/*
+ * ======== gh_exit ========
+ */
+
+void gh_exit(void)
+{
+ if (cur_init-- == 1)
+ gs_exit();
+
+}
+
+/*
+ * ======== gh_find ========
+ */
+
+void *gh_find(struct gh_t_hash_tab *hash_tab, void *key)
+{
+ struct element *elem;
+
+ elem = hash_tab->buckets[(*hash_tab->hash) (key, hash_tab->max_bucket)];
+
+ for (; elem; elem = elem->next) {
+ if ((*hash_tab->match) (key, elem->data))
+ return elem->data;
+ }
+
+ return NULL;
+}
+
+/*
+ * ======== gh_init ========
+ */
+
+void gh_init(void)
+{
+ if (cur_init++ == 0)
+ gs_init();
+}
+
+/*
+ * ======== gh_insert ========
+ */
+
+void *gh_insert(struct gh_t_hash_tab *hash_tab, void *key, void *value)
+{
+ struct element *elem;
+ u16 i;
+ char *src, *dst;
+
+ elem = (struct element *)gs_alloc(sizeof(struct element) - 1 +
+ hash_tab->val_size);
+ if (elem != NULL) {
+
+ dst = (char *)elem->data;
+ src = (char *)value;
+ for (i = 0; i < hash_tab->val_size; i++)
+ *dst++ = *src++;
+
+ i = (*hash_tab->hash) (key, hash_tab->max_bucket);
+ elem->next = hash_tab->buckets[i];
+ hash_tab->buckets[i] = elem;
+
+ return elem->data;
+ }
+
+ return NULL;
+}
+
+/*
+ * ======== noop ========
+ */
+/* ARGSUSED */
+static void noop(void *p)
+{
+ p = p; /* stifle compiler warning */
+}
+
+/*
+ * ======== myfree ========
+ */
+static void myfree(void *ptr, s32 size)
+{
+ gs_free(ptr);
+}
+
+#ifdef CONFIG_TIDSPBRIDGE_BACKTRACE
+/**
+ * gh_iterate() - This function goes through all the elements in the hash table
+ * looking for the dsp symbols.
+ * @hash_tab: Hash table
+ * @callback: pointer to callback function
+ * @user_data: User data, contains the find_symbol_context pointer
+ *
+ */
+void gh_iterate(struct gh_t_hash_tab *hash_tab,
+ void (*callback)(void *, void *), void *user_data)
+{
+ struct element *elem;
+ u32 i;
+
+ if (hash_tab && hash_tab->buckets)
+ for (i = 0; i < hash_tab->max_bucket; i++) {
+ elem = hash_tab->buckets[i];
+ while (elem) {
+ callback(&elem->data, user_data);
+ elem = elem->next;
+ }
+ }
+}
+#endif
diff --git a/drivers/staging/tidspbridge/gen/gs.c b/drivers/staging/tidspbridge/gen/gs.c
new file mode 100644
index 00000000000..9fc614439ba
--- /dev/null
+++ b/drivers/staging/tidspbridge/gen/gs.c
@@ -0,0 +1,89 @@
+/*
+ * gs.c
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * General storage memory allocator services.
+ *
+ * Copyright (C) 2005-2006 Texas Instruments, Inc.
+ *
+ * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include <linux/types.h>
+/* ----------------------------------- DSP/BIOS Bridge */
+#include <dspbridge/dbdefs.h>
+#include <linux/types.h>
+
+/* ----------------------------------- This */
+#include <dspbridge/gs.h>
+
+#include <linux/slab.h>
+
+/* ----------------------------------- Globals */
+static u32 cumsize;
+
+/*
+ * ======== gs_alloc ========
+ * purpose:
+ * Allocates memory of the specified size.
+ */
+void *gs_alloc(u32 size)
+{
+ void *p;
+
+ p = kzalloc(size, GFP_KERNEL);
+ if (p == NULL)
+ return NULL;
+ cumsize += size;
+ return p;
+}
+
+/*
+ * ======== gs_exit ========
+ * purpose:
+ * Discontinue the usage of the GS module.
+ */
+void gs_exit(void)
+{
+ /* Do nothing */
+}
+
+/*
+ * ======== gs_free ========
+ * purpose:
+ * Frees the memory.
+ */
+void gs_free(void *ptr)
+{
+ kfree(ptr);
+ /* ack! no size info */
+ /* cumsize -= size; */
+}
+
+/*
+ * ======== gs_frees ========
+ * purpose:
+ * Frees the memory.
+ */
+void gs_frees(void *ptr, u32 size)
+{
+ kfree(ptr);
+ cumsize -= size;
+}
+
+/*
+ * ======== gs_init ========
+ * purpose:
+ * Initializes the GS module.
+ */
+void gs_init(void)
+{
+ /* Do nothing */
+}
diff --git a/drivers/staging/tidspbridge/gen/uuidutil.c b/drivers/staging/tidspbridge/gen/uuidutil.c
new file mode 100644
index 00000000000..da39c4fbf33
--- /dev/null
+++ b/drivers/staging/tidspbridge/gen/uuidutil.c
@@ -0,0 +1,113 @@
+/*
+ * uuidutil.c
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * This file contains the implementation of UUID helper functions.
+ *
+ * Copyright (C) 2005-2006 Texas Instruments, Inc.
+ *
+ * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+#include <linux/types.h>
+
+/* ----------------------------------- Host OS */
+#include <dspbridge/host_os.h>
+
+/* ----------------------------------- DSP/BIOS Bridge */
+#include <dspbridge/dbdefs.h>
+
+/* ----------------------------------- Trace & Debug */
+#include <dspbridge/dbc.h>
+
+/* ----------------------------------- This */
+#include <dspbridge/uuidutil.h>
+
+/*
+ * ======== uuid_uuid_to_string ========
+ * Purpose:
+ * Converts a struct dsp_uuid to a string.
+ * Note: snprintf format specifier is:
+ * %[flags] [width] [.precision] [{h | l | I64 | L}]type
+ */
+void uuid_uuid_to_string(struct dsp_uuid *uuid_obj, char *sz_uuid,
+ s32 size)
+{
+ s32 i; /* return result from snprintf. */
+
+ DBC_REQUIRE(uuid_obj && sz_uuid);
+
+ i = snprintf(sz_uuid, size,
+ "%.8X_%.4X_%.4X_%.2X%.2X_%.2X%.2X%.2X%.2X%.2X%.2X",
+ uuid_obj->ul_data1, uuid_obj->us_data2, uuid_obj->us_data3,
+ uuid_obj->uc_data4, uuid_obj->uc_data5,
+ uuid_obj->uc_data6[0], uuid_obj->uc_data6[1],
+ uuid_obj->uc_data6[2], uuid_obj->uc_data6[3],
+ uuid_obj->uc_data6[4], uuid_obj->uc_data6[5]);
+
+ DBC_ENSURE(i != -1);
+}
+
+static s32 uuid_hex_to_bin(char *buf, s32 len)
+{
+ s32 i;
+ s32 result = 0;
+ int value;
+
+ for (i = 0; i < len; i++) {
+ value = hex_to_bin(*buf++);
+ result *= 16;
+ if (value > 0)
+ result += value;
+ }
+
+ return result;
+}
+
+/*
+ * ======== uuid_uuid_from_string ========
+ * Purpose:
+ * Converts a string to a struct dsp_uuid.
+ */
+void uuid_uuid_from_string(char *sz_uuid, struct dsp_uuid *uuid_obj)
+{
+ s32 j;
+
+ uuid_obj->ul_data1 = uuid_hex_to_bin(sz_uuid, 8);
+ sz_uuid += 8;
+
+ /* Step over underscore */
+ sz_uuid++;
+
+ uuid_obj->us_data2 = (u16) uuid_hex_to_bin(sz_uuid, 4);
+ sz_uuid += 4;
+
+ /* Step over underscore */
+ sz_uuid++;
+
+ uuid_obj->us_data3 = (u16) uuid_hex_to_bin(sz_uuid, 4);
+ sz_uuid += 4;
+
+ /* Step over underscore */
+ sz_uuid++;
+
+ uuid_obj->uc_data4 = (u8) uuid_hex_to_bin(sz_uuid, 2);
+ sz_uuid += 2;
+
+ uuid_obj->uc_data5 = (u8) uuid_hex_to_bin(sz_uuid, 2);
+ sz_uuid += 2;
+
+ /* Step over underscore */
+ sz_uuid++;
+
+ for (j = 0; j < 6; j++) {
+ uuid_obj->uc_data6[j] = (u8) uuid_hex_to_bin(sz_uuid, 2);
+ sz_uuid += 2;
+ }
+}
diff --git a/drivers/staging/tidspbridge/hw/EasiGlobal.h b/drivers/staging/tidspbridge/hw/EasiGlobal.h
new file mode 100644
index 00000000000..e48d7f67c60
--- /dev/null
+++ b/drivers/staging/tidspbridge/hw/EasiGlobal.h
@@ -0,0 +1,41 @@
+/*
+ * EasiGlobal.h
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * Copyright (C) 2007 Texas Instruments, Inc.
+ *
+ * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef _EASIGLOBAL_H
+#define _EASIGLOBAL_H
+#include <linux/types.h>
+
+/*
+ * DEFINE: READ_ONLY, WRITE_ONLY & READ_WRITE
+ *
+ * DESCRIPTION: Defines used to describe register types for EASI-checker tests.
+ */
+
+#define READ_ONLY 1
+#define WRITE_ONLY 2
+#define READ_WRITE 3
+
+/*
+ * MACRO: _DEBUG_LEVEL1_EASI
+ *
+ * DESCRIPTION: A MACRO which can be used to indicate that a particular beach
+ * register access function was called.
+ *
+ * NOTE: We currently dont use this functionality.
+ */
+#define _DEBUG_LEVEL1_EASI(easi_num) ((void)0)
+
+#endif /* _EASIGLOBAL_H */
diff --git a/drivers/staging/tidspbridge/hw/MMUAccInt.h b/drivers/staging/tidspbridge/hw/MMUAccInt.h
new file mode 100644
index 00000000000..1cefca321d7
--- /dev/null
+++ b/drivers/staging/tidspbridge/hw/MMUAccInt.h
@@ -0,0 +1,76 @@
+/*
+ * MMUAccInt.h
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * Copyright (C) 2007 Texas Instruments, Inc.
+ *
+ * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef _MMU_ACC_INT_H
+#define _MMU_ACC_INT_H
+
+/* Mappings of level 1 EASI function numbers to function names */
+
+#define EASIL1_MMUMMU_SYSCONFIG_READ_REGISTER32 (MMU_BASE_EASIL1 + 3)
+#define EASIL1_MMUMMU_SYSCONFIG_IDLE_MODE_WRITE32 (MMU_BASE_EASIL1 + 17)
+#define EASIL1_MMUMMU_SYSCONFIG_AUTO_IDLE_WRITE32 (MMU_BASE_EASIL1 + 39)
+#define EASIL1_MMUMMU_IRQSTATUS_WRITE_REGISTER32 (MMU_BASE_EASIL1 + 51)
+#define EASIL1_MMUMMU_IRQENABLE_READ_REGISTER32 (MMU_BASE_EASIL1 + 102)
+#define EASIL1_MMUMMU_IRQENABLE_WRITE_REGISTER32 (MMU_BASE_EASIL1 + 103)
+#define EASIL1_MMUMMU_WALKING_STTWL_RUNNING_READ32 (MMU_BASE_EASIL1 + 156)
+#define EASIL1_MMUMMU_CNTLTWL_ENABLE_READ32 (MMU_BASE_EASIL1 + 174)
+#define EASIL1_MMUMMU_CNTLTWL_ENABLE_WRITE32 (MMU_BASE_EASIL1 + 180)
+#define EASIL1_MMUMMU_CNTLMMU_ENABLE_WRITE32 (MMU_BASE_EASIL1 + 190)
+#define EASIL1_MMUMMU_FAULT_AD_READ_REGISTER32 (MMU_BASE_EASIL1 + 194)
+#define EASIL1_MMUMMU_TTB_WRITE_REGISTER32 (MMU_BASE_EASIL1 + 198)
+#define EASIL1_MMUMMU_LOCK_READ_REGISTER32 (MMU_BASE_EASIL1 + 203)
+#define EASIL1_MMUMMU_LOCK_WRITE_REGISTER32 (MMU_BASE_EASIL1 + 204)
+#define EASIL1_MMUMMU_LOCK_BASE_VALUE_READ32 (MMU_BASE_EASIL1 + 205)
+#define EASIL1_MMUMMU_LOCK_CURRENT_VICTIM_READ32 (MMU_BASE_EASIL1 + 209)
+#define EASIL1_MMUMMU_LOCK_CURRENT_VICTIM_WRITE32 (MMU_BASE_EASIL1 + 211)
+#define EASIL1_MMUMMU_LOCK_CURRENT_VICTIM_SET32 (MMU_BASE_EASIL1 + 212)
+#define EASIL1_MMUMMU_LD_TLB_READ_REGISTER32 (MMU_BASE_EASIL1 + 213)
+#define EASIL1_MMUMMU_LD_TLB_WRITE_REGISTER32 (MMU_BASE_EASIL1 + 214)
+#define EASIL1_MMUMMU_CAM_WRITE_REGISTER32 (MMU_BASE_EASIL1 + 226)
+#define EASIL1_MMUMMU_RAM_WRITE_REGISTER32 (MMU_BASE_EASIL1 + 268)
+#define EASIL1_MMUMMU_FLUSH_ENTRY_WRITE_REGISTER32 (MMU_BASE_EASIL1 + 322)
+
+/* Register offset address definitions */
+#define MMU_MMU_SYSCONFIG_OFFSET 0x10
+#define MMU_MMU_IRQSTATUS_OFFSET 0x18
+#define MMU_MMU_IRQENABLE_OFFSET 0x1c
+#define MMU_MMU_WALKING_ST_OFFSET 0x40
+#define MMU_MMU_CNTL_OFFSET 0x44
+#define MMU_MMU_FAULT_AD_OFFSET 0x48
+#define MMU_MMU_TTB_OFFSET 0x4c
+#define MMU_MMU_LOCK_OFFSET 0x50
+#define MMU_MMU_LD_TLB_OFFSET 0x54
+#define MMU_MMU_CAM_OFFSET 0x58
+#define MMU_MMU_RAM_OFFSET 0x5c
+#define MMU_MMU_GFLUSH_OFFSET 0x60
+#define MMU_MMU_FLUSH_ENTRY_OFFSET 0x64
+/* Bitfield mask and offset declarations */
+#define MMU_MMU_SYSCONFIG_IDLE_MODE_MASK 0x18
+#define MMU_MMU_SYSCONFIG_IDLE_MODE_OFFSET 3
+#define MMU_MMU_SYSCONFIG_AUTO_IDLE_MASK 0x1
+#define MMU_MMU_SYSCONFIG_AUTO_IDLE_OFFSET 0
+#define MMU_MMU_WALKING_ST_TWL_RUNNING_MASK 0x1
+#define MMU_MMU_WALKING_ST_TWL_RUNNING_OFFSET 0
+#define MMU_MMU_CNTL_TWL_ENABLE_MASK 0x4
+#define MMU_MMU_CNTL_TWL_ENABLE_OFFSET 2
+#define MMU_MMU_CNTL_MMU_ENABLE_MASK 0x2
+#define MMU_MMU_CNTL_MMU_ENABLE_OFFSET 1
+#define MMU_MMU_LOCK_BASE_VALUE_MASK 0xfc00
+#define MMU_MMU_LOCK_BASE_VALUE_OFFSET 10
+#define MMU_MMU_LOCK_CURRENT_VICTIM_MASK 0x3f0
+#define MMU_MMU_LOCK_CURRENT_VICTIM_OFFSET 4
+
+#endif /* _MMU_ACC_INT_H */
diff --git a/drivers/staging/tidspbridge/hw/MMURegAcM.h b/drivers/staging/tidspbridge/hw/MMURegAcM.h
new file mode 100644
index 00000000000..ab1a16da731
--- /dev/null
+++ b/drivers/staging/tidspbridge/hw/MMURegAcM.h
@@ -0,0 +1,225 @@
+/*
+ * MMURegAcM.h
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * Copyright (C) 2007 Texas Instruments, Inc.
+ *
+ * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef _MMU_REG_ACM_H
+#define _MMU_REG_ACM_H
+
+#include <linux/io.h>
+#include <EasiGlobal.h>
+
+#include "MMUAccInt.h"
+
+#if defined(USE_LEVEL_1_MACROS)
+
+#define MMUMMU_SYSCONFIG_READ_REGISTER32(base_address)\
+ (_DEBUG_LEVEL1_EASI(EASIL1_MMUMMU_SYSCONFIG_READ_REGISTER32),\
+ __raw_readl((base_address)+MMU_MMU_SYSCONFIG_OFFSET))
+
+#define MMUMMU_SYSCONFIG_IDLE_MODE_WRITE32(base_address, value)\
+{\
+ const u32 offset = MMU_MMU_SYSCONFIG_OFFSET;\
+ register u32 data = __raw_readl((base_address)+offset);\
+ register u32 new_value = (value);\
+ _DEBUG_LEVEL1_EASI(EASIL1_MMUMMU_SYSCONFIG_IDLE_MODE_WRITE32);\
+ data &= ~(MMU_MMU_SYSCONFIG_IDLE_MODE_MASK);\
+ new_value <<= MMU_MMU_SYSCONFIG_IDLE_MODE_OFFSET;\
+ new_value &= MMU_MMU_SYSCONFIG_IDLE_MODE_MASK;\
+ new_value |= data;\
+ __raw_writel(new_value, base_address+offset);\
+}
+
+#define MMUMMU_SYSCONFIG_AUTO_IDLE_WRITE32(base_address, value)\
+{\
+ const u32 offset = MMU_MMU_SYSCONFIG_OFFSET;\
+ register u32 data = __raw_readl((base_address)+offset);\
+ register u32 new_value = (value);\
+ _DEBUG_LEVEL1_EASI(EASIL1_MMUMMU_SYSCONFIG_AUTO_IDLE_WRITE32);\
+ data &= ~(MMU_MMU_SYSCONFIG_AUTO_IDLE_MASK);\
+ new_value <<= MMU_MMU_SYSCONFIG_AUTO_IDLE_OFFSET;\
+ new_value &= MMU_MMU_SYSCONFIG_AUTO_IDLE_MASK;\
+ new_value |= data;\
+ __raw_writel(new_value, base_address+offset);\
+}
+
+#define MMUMMU_IRQSTATUS_READ_REGISTER32(base_address)\
+ (_DEBUG_LEVEL1_EASI(easil1_mmummu_irqstatus_read_register32),\
+ __raw_readl((base_address)+MMU_MMU_IRQSTATUS_OFFSET))
+
+#define MMUMMU_IRQSTATUS_WRITE_REGISTER32(base_address, value)\
+{\
+ const u32 offset = MMU_MMU_IRQSTATUS_OFFSET;\
+ register u32 new_value = (value);\
+ _DEBUG_LEVEL1_EASI(EASIL1_MMUMMU_IRQSTATUS_WRITE_REGISTER32);\
+ __raw_writel(new_value, (base_address)+offset);\
+}
+
+#define MMUMMU_IRQENABLE_READ_REGISTER32(base_address)\
+ (_DEBUG_LEVEL1_EASI(EASIL1_MMUMMU_IRQENABLE_READ_REGISTER32),\
+ __raw_readl((base_address)+MMU_MMU_IRQENABLE_OFFSET))
+
+#define MMUMMU_IRQENABLE_WRITE_REGISTER32(base_address, value)\
+{\
+ const u32 offset = MMU_MMU_IRQENABLE_OFFSET;\
+ register u32 new_value = (value);\
+ _DEBUG_LEVEL1_EASI(EASIL1_MMUMMU_IRQENABLE_WRITE_REGISTER32);\
+ __raw_writel(new_value, (base_address)+offset);\
+}
+
+#define MMUMMU_WALKING_STTWL_RUNNING_READ32(base_address)\
+ (_DEBUG_LEVEL1_EASI(EASIL1_MMUMMU_WALKING_STTWL_RUNNING_READ32),\
+ (((__raw_readl(((base_address)+(MMU_MMU_WALKING_ST_OFFSET))))\
+ & MMU_MMU_WALKING_ST_TWL_RUNNING_MASK) >>\
+ MMU_MMU_WALKING_ST_TWL_RUNNING_OFFSET))
+
+#define MMUMMU_CNTLTWL_ENABLE_READ32(base_address)\
+ (_DEBUG_LEVEL1_EASI(EASIL1_MMUMMU_CNTLTWL_ENABLE_READ32),\
+ (((__raw_readl(((base_address)+(MMU_MMU_CNTL_OFFSET)))) &\
+ MMU_MMU_CNTL_TWL_ENABLE_MASK) >>\
+ MMU_MMU_CNTL_TWL_ENABLE_OFFSET))
+
+#define MMUMMU_CNTLTWL_ENABLE_WRITE32(base_address, value)\
+{\
+ const u32 offset = MMU_MMU_CNTL_OFFSET;\
+ register u32 data = __raw_readl((base_address)+offset);\
+ register u32 new_value = (value);\
+ _DEBUG_LEVEL1_EASI(EASIL1_MMUMMU_CNTLTWL_ENABLE_WRITE32);\
+ data &= ~(MMU_MMU_CNTL_TWL_ENABLE_MASK);\
+ new_value <<= MMU_MMU_CNTL_TWL_ENABLE_OFFSET;\
+ new_value &= MMU_MMU_CNTL_TWL_ENABLE_MASK;\
+ new_value |= data;\
+ __raw_writel(new_value, base_address+offset);\
+}
+
+#define MMUMMU_CNTLMMU_ENABLE_WRITE32(base_address, value)\
+{\
+ const u32 offset = MMU_MMU_CNTL_OFFSET;\
+ register u32 data = __raw_readl((base_address)+offset);\
+ register u32 new_value = (value);\
+ _DEBUG_LEVEL1_EASI(EASIL1_MMUMMU_CNTLMMU_ENABLE_WRITE32);\
+ data &= ~(MMU_MMU_CNTL_MMU_ENABLE_MASK);\
+ new_value <<= MMU_MMU_CNTL_MMU_ENABLE_OFFSET;\
+ new_value &= MMU_MMU_CNTL_MMU_ENABLE_MASK;\
+ new_value |= data;\
+ __raw_writel(new_value, base_address+offset);\
+}
+
+#define MMUMMU_FAULT_AD_READ_REGISTER32(base_address)\
+ (_DEBUG_LEVEL1_EASI(EASIL1_MMUMMU_FAULT_AD_READ_REGISTER32),\
+ __raw_readl((base_address)+MMU_MMU_FAULT_AD_OFFSET))
+
+#define MMUMMU_TTB_WRITE_REGISTER32(base_address, value)\
+{\
+ const u32 offset = MMU_MMU_TTB_OFFSET;\
+ register u32 new_value = (value);\
+ _DEBUG_LEVEL1_EASI(EASIL1_MMUMMU_TTB_WRITE_REGISTER32);\
+ __raw_writel(new_value, (base_address)+offset);\
+}
+
+#define MMUMMU_LOCK_READ_REGISTER32(base_address)\
+ (_DEBUG_LEVEL1_EASI(EASIL1_MMUMMU_LOCK_READ_REGISTER32),\
+ __raw_readl((base_address)+MMU_MMU_LOCK_OFFSET))
+
+#define MMUMMU_LOCK_WRITE_REGISTER32(base_address, value)\
+{\
+ const u32 offset = MMU_MMU_LOCK_OFFSET;\
+ register u32 new_value = (value);\
+ _DEBUG_LEVEL1_EASI(EASIL1_MMUMMU_LOCK_WRITE_REGISTER32);\
+ __raw_writel(new_value, (base_address)+offset);\
+}
+
+#define MMUMMU_LOCK_BASE_VALUE_READ32(base_address)\
+ (_DEBUG_LEVEL1_EASI(EASIL1_MMUMMU_LOCK_BASE_VALUE_READ32),\
+ (((__raw_readl(((base_address)+(MMU_MMU_LOCK_OFFSET)))) &\
+ MMU_MMU_LOCK_BASE_VALUE_MASK) >>\
+ MMU_MMU_LOCK_BASE_VALUE_OFFSET))
+
+#define MMUMMU_LOCK_BASE_VALUE_WRITE32(base_address, value)\
+{\
+ const u32 offset = MMU_MMU_LOCK_OFFSET;\
+ register u32 data = __raw_readl((base_address)+offset);\
+ register u32 new_value = (value);\
+ _DEBUG_LEVEL1_EASI(easil1_mmummu_lock_base_value_write32);\
+ data &= ~(MMU_MMU_LOCK_BASE_VALUE_MASK);\
+ new_value <<= MMU_MMU_LOCK_BASE_VALUE_OFFSET;\
+ new_value &= MMU_MMU_LOCK_BASE_VALUE_MASK;\
+ new_value |= data;\
+ __raw_writel(new_value, base_address+offset);\
+}
+
+#define MMUMMU_LOCK_CURRENT_VICTIM_READ32(base_address)\
+ (_DEBUG_LEVEL1_EASI(EASIL1_MMUMMU_LOCK_CURRENT_VICTIM_READ32),\
+ (((__raw_readl(((base_address)+(MMU_MMU_LOCK_OFFSET)))) &\
+ MMU_MMU_LOCK_CURRENT_VICTIM_MASK) >>\
+ MMU_MMU_LOCK_CURRENT_VICTIM_OFFSET))
+
+#define MMUMMU_LOCK_CURRENT_VICTIM_WRITE32(base_address, value)\
+{\
+ const u32 offset = MMU_MMU_LOCK_OFFSET;\
+ register u32 data = __raw_readl((base_address)+offset);\
+ register u32 new_value = (value);\
+ _DEBUG_LEVEL1_EASI(EASIL1_MMUMMU_LOCK_CURRENT_VICTIM_WRITE32);\
+ data &= ~(MMU_MMU_LOCK_CURRENT_VICTIM_MASK);\
+ new_value <<= MMU_MMU_LOCK_CURRENT_VICTIM_OFFSET;\
+ new_value &= MMU_MMU_LOCK_CURRENT_VICTIM_MASK;\
+ new_value |= data;\
+ __raw_writel(new_value, base_address+offset);\
+}
+
+#define MMUMMU_LOCK_CURRENT_VICTIM_SET32(var, value)\
+ (_DEBUG_LEVEL1_EASI(EASIL1_MMUMMU_LOCK_CURRENT_VICTIM_SET32),\
+ (((var) & ~(MMU_MMU_LOCK_CURRENT_VICTIM_MASK)) |\
+ (((value) << MMU_MMU_LOCK_CURRENT_VICTIM_OFFSET) &\
+ MMU_MMU_LOCK_CURRENT_VICTIM_MASK)))
+
+#define MMUMMU_LD_TLB_READ_REGISTER32(base_address)\
+ (_DEBUG_LEVEL1_EASI(EASIL1_MMUMMU_LD_TLB_READ_REGISTER32),\
+ __raw_readl((base_address)+MMU_MMU_LD_TLB_OFFSET))
+
+#define MMUMMU_LD_TLB_WRITE_REGISTER32(base_address, value)\
+{\
+ const u32 offset = MMU_MMU_LD_TLB_OFFSET;\
+ register u32 new_value = (value);\
+ _DEBUG_LEVEL1_EASI(EASIL1_MMUMMU_LD_TLB_WRITE_REGISTER32);\
+ __raw_writel(new_value, (base_address)+offset);\
+}
+
+#define MMUMMU_CAM_WRITE_REGISTER32(base_address, value)\
+{\
+ const u32 offset = MMU_MMU_CAM_OFFSET;\
+ register u32 new_value = (value);\
+ _DEBUG_LEVEL1_EASI(EASIL1_MMUMMU_CAM_WRITE_REGISTER32);\
+ __raw_writel(new_value, (base_address)+offset);\
+}
+
+#define MMUMMU_RAM_WRITE_REGISTER32(base_address, value)\
+{\
+ const u32 offset = MMU_MMU_RAM_OFFSET;\
+ register u32 new_value = (value);\
+ _DEBUG_LEVEL1_EASI(EASIL1_MMUMMU_RAM_WRITE_REGISTER32);\
+ __raw_writel(new_value, (base_address)+offset);\
+}
+
+#define MMUMMU_FLUSH_ENTRY_WRITE_REGISTER32(base_address, value)\
+{\
+ const u32 offset = MMU_MMU_FLUSH_ENTRY_OFFSET;\
+ register u32 new_value = (value);\
+ _DEBUG_LEVEL1_EASI(EASIL1_MMUMMU_FLUSH_ENTRY_WRITE_REGISTER32);\
+ __raw_writel(new_value, (base_address)+offset);\
+}
+
+#endif /* USE_LEVEL_1_MACROS */
+
+#endif /* _MMU_REG_ACM_H */
diff --git a/drivers/staging/tidspbridge/hw/hw_defs.h b/drivers/staging/tidspbridge/hw/hw_defs.h
new file mode 100644
index 00000000000..d5266d4c163
--- /dev/null
+++ b/drivers/staging/tidspbridge/hw/hw_defs.h
@@ -0,0 +1,58 @@
+/*
+ * hw_defs.h
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * Global HW definitions
+ *
+ * Copyright (C) 2007 Texas Instruments, Inc.
+ *
+ * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef _HW_DEFS_H
+#define _HW_DEFS_H
+
+/* Page size */
+#define HW_PAGE_SIZE4KB 0x1000
+#define HW_PAGE_SIZE64KB 0x10000
+#define HW_PAGE_SIZE1MB 0x100000
+#define HW_PAGE_SIZE16MB 0x1000000
+
+/* hw_status: return type for HW API */
+typedef long hw_status;
+
+/* Macro used to set and clear any bit */
+#define HW_CLEAR 0
+#define HW_SET 1
+
+/* hw_endianism_t: Enumerated Type used to specify the endianism
+ * Do NOT change these values. They are used as bit fields. */
+enum hw_endianism_t {
+ HW_LITTLE_ENDIAN,
+ HW_BIG_ENDIAN
+};
+
+/* hw_element_size_t: Enumerated Type used to specify the element size
+ * Do NOT change these values. They are used as bit fields. */
+enum hw_element_size_t {
+ HW_ELEM_SIZE8BIT,
+ HW_ELEM_SIZE16BIT,
+ HW_ELEM_SIZE32BIT,
+ HW_ELEM_SIZE64BIT
+};
+
+/* hw_idle_mode_t: Enumerated Type used to specify Idle modes */
+enum hw_idle_mode_t {
+ HW_FORCE_IDLE,
+ HW_NO_IDLE,
+ HW_SMART_IDLE
+};
+
+#endif /* _HW_DEFS_H */
diff --git a/drivers/staging/tidspbridge/hw/hw_mmu.c b/drivers/staging/tidspbridge/hw/hw_mmu.c
new file mode 100644
index 00000000000..014f5d5293a
--- /dev/null
+++ b/drivers/staging/tidspbridge/hw/hw_mmu.c
@@ -0,0 +1,562 @@
+/*
+ * hw_mmu.c
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * API definitions to setup MMU TLB and PTE
+ *
+ * Copyright (C) 2007 Texas Instruments, Inc.
+ *
+ * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include <linux/io.h>
+#include "MMURegAcM.h"
+#include <hw_defs.h>
+#include <hw_mmu.h>
+#include <linux/types.h>
+#include <linux/err.h>
+
+#define MMU_BASE_VAL_MASK 0xFC00
+#define MMU_PAGE_MAX 3
+#define MMU_ELEMENTSIZE_MAX 3
+#define MMU_ADDR_MASK 0xFFFFF000
+#define MMU_TTB_MASK 0xFFFFC000
+#define MMU_SECTION_ADDR_MASK 0xFFF00000
+#define MMU_SSECTION_ADDR_MASK 0xFF000000
+#define MMU_PAGE_TABLE_MASK 0xFFFFFC00
+#define MMU_LARGE_PAGE_MASK 0xFFFF0000
+#define MMU_SMALL_PAGE_MASK 0xFFFFF000
+
+#define MMU_LOAD_TLB 0x00000001
+#define MMU_GFLUSH 0x60
+
+/*
+ * hw_mmu_page_size_t: Enumerated Type used to specify the MMU Page Size(SLSS)
+ */
+enum hw_mmu_page_size_t {
+ HW_MMU_SECTION,
+ HW_MMU_LARGE_PAGE,
+ HW_MMU_SMALL_PAGE,
+ HW_MMU_SUPERSECTION
+};
+
+/*
+ * FUNCTION : mmu_flush_entry
+ *
+ * INPUTS:
+ *
+ * Identifier : base_address
+ * Type : const u32
+ * Description : Base Address of instance of MMU module
+ *
+ * RETURNS:
+ *
+ * Type : hw_status
+ * Description : 0 -- No errors occured
+ * RET_BAD_NULL_PARAM -- A Pointer
+ * Paramater was set to NULL
+ *
+ * PURPOSE: : Flush the TLB entry pointed by the
+ * lock counter register
+ * even if this entry is set protected
+ *
+ * METHOD: : Check the Input parameter and Flush a
+ * single entry in the TLB.
+ */
+static hw_status mmu_flush_entry(const void __iomem *base_address);
+
+/*
+ * FUNCTION : mmu_set_cam_entry
+ *
+ * INPUTS:
+ *
+ * Identifier : base_address
+ * TypE : const u32
+ * Description : Base Address of instance of MMU module
+ *
+ * Identifier : page_sz
+ * TypE : const u32
+ * Description : It indicates the page size
+ *
+ * Identifier : preserved_bit
+ * Type : const u32
+ * Description : It indicates the TLB entry is preserved entry
+ * or not
+ *
+ * Identifier : valid_bit
+ * Type : const u32
+ * Description : It indicates the TLB entry is valid entry or not
+ *
+ *
+ * Identifier : virtual_addr_tag
+ * Type : const u32
+ * Description : virtual Address
+ *
+ * RETURNS:
+ *
+ * Type : hw_status
+ * Description : 0 -- No errors occured
+ * RET_BAD_NULL_PARAM -- A Pointer Paramater
+ * was set to NULL
+ * RET_PARAM_OUT_OF_RANGE -- Input Parameter out
+ * of Range
+ *
+ * PURPOSE: : Set MMU_CAM reg
+ *
+ * METHOD: : Check the Input parameters and set the CAM entry.
+ */
+static hw_status mmu_set_cam_entry(const void __iomem *base_address,
+ const u32 page_sz,
+ const u32 preserved_bit,
+ const u32 valid_bit,
+ const u32 virtual_addr_tag);
+
+/*
+ * FUNCTION : mmu_set_ram_entry
+ *
+ * INPUTS:
+ *
+ * Identifier : base_address
+ * Type : const u32
+ * Description : Base Address of instance of MMU module
+ *
+ * Identifier : physical_addr
+ * Type : const u32
+ * Description : Physical Address to which the corresponding
+ * virtual Address shouldpoint
+ *
+ * Identifier : endianism
+ * Type : hw_endianism_t
+ * Description : endianism for the given page
+ *
+ * Identifier : element_size
+ * Type : hw_element_size_t
+ * Description : The element size ( 8,16, 32 or 64 bit)
+ *
+ * Identifier : mixed_size
+ * Type : hw_mmu_mixed_size_t
+ * Description : Element Size to follow CPU or TLB
+ *
+ * RETURNS:
+ *
+ * Type : hw_status
+ * Description : 0 -- No errors occured
+ * RET_BAD_NULL_PARAM -- A Pointer Paramater
+ * was set to NULL
+ * RET_PARAM_OUT_OF_RANGE -- Input Parameter
+ * out of Range
+ *
+ * PURPOSE: : Set MMU_CAM reg
+ *
+ * METHOD: : Check the Input parameters and set the RAM entry.
+ */
+static hw_status mmu_set_ram_entry(const void __iomem *base_address,
+ const u32 physical_addr,
+ enum hw_endianism_t endianism,
+ enum hw_element_size_t element_size,
+ enum hw_mmu_mixed_size_t mixed_size);
+
+/* HW FUNCTIONS */
+
+hw_status hw_mmu_enable(const void __iomem *base_address)
+{
+ hw_status status = 0;
+
+ MMUMMU_CNTLMMU_ENABLE_WRITE32(base_address, HW_SET);
+
+ return status;
+}
+
+hw_status hw_mmu_disable(const void __iomem *base_address)
+{
+ hw_status status = 0;
+
+ MMUMMU_CNTLMMU_ENABLE_WRITE32(base_address, HW_CLEAR);
+
+ return status;
+}
+
+hw_status hw_mmu_num_locked_set(const void __iomem *base_address,
+ u32 num_locked_entries)
+{
+ hw_status status = 0;
+
+ MMUMMU_LOCK_BASE_VALUE_WRITE32(base_address, num_locked_entries);
+
+ return status;
+}
+
+hw_status hw_mmu_victim_num_set(const void __iomem *base_address,
+ u32 victim_entry_num)
+{
+ hw_status status = 0;
+
+ MMUMMU_LOCK_CURRENT_VICTIM_WRITE32(base_address, victim_entry_num);
+
+ return status;
+}
+
+hw_status hw_mmu_event_ack(const void __iomem *base_address, u32 irq_mask)
+{
+ hw_status status = 0;
+
+ MMUMMU_IRQSTATUS_WRITE_REGISTER32(base_address, irq_mask);
+
+ return status;
+}
+
+hw_status hw_mmu_event_disable(const void __iomem *base_address, u32 irq_mask)
+{
+ hw_status status = 0;
+ u32 irq_reg;
+
+ irq_reg = MMUMMU_IRQENABLE_READ_REGISTER32(base_address);
+
+ MMUMMU_IRQENABLE_WRITE_REGISTER32(base_address, irq_reg & ~irq_mask);
+
+ return status;
+}
+
+hw_status hw_mmu_event_enable(const void __iomem *base_address, u32 irq_mask)
+{
+ hw_status status = 0;
+ u32 irq_reg;
+
+ irq_reg = MMUMMU_IRQENABLE_READ_REGISTER32(base_address);
+
+ MMUMMU_IRQENABLE_WRITE_REGISTER32(base_address, irq_reg | irq_mask);
+
+ return status;
+}
+
+hw_status hw_mmu_event_status(const void __iomem *base_address, u32 *irq_mask)
+{
+ hw_status status = 0;
+
+ *irq_mask = MMUMMU_IRQSTATUS_READ_REGISTER32(base_address);
+
+ return status;
+}
+
+hw_status hw_mmu_fault_addr_read(const void __iomem *base_address, u32 *addr)
+{
+ hw_status status = 0;
+
+ /* read values from register */
+ *addr = MMUMMU_FAULT_AD_READ_REGISTER32(base_address);
+
+ return status;
+}
+
+hw_status hw_mmu_ttb_set(const void __iomem *base_address, u32 ttb_phys_addr)
+{
+ hw_status status = 0;
+ u32 load_ttb;
+
+ load_ttb = ttb_phys_addr & ~0x7FUL;
+ /* write values to register */
+ MMUMMU_TTB_WRITE_REGISTER32(base_address, load_ttb);
+
+ return status;
+}
+
+hw_status hw_mmu_twl_enable(const void __iomem *base_address)
+{
+ hw_status status = 0;
+
+ MMUMMU_CNTLTWL_ENABLE_WRITE32(base_address, HW_SET);
+
+ return status;
+}
+
+hw_status hw_mmu_twl_disable(const void __iomem *base_address)
+{
+ hw_status status = 0;
+
+ MMUMMU_CNTLTWL_ENABLE_WRITE32(base_address, HW_CLEAR);
+
+ return status;
+}
+
+hw_status hw_mmu_tlb_flush(const void __iomem *base_address, u32 virtual_addr,
+ u32 page_sz)
+{
+ hw_status status = 0;
+ u32 virtual_addr_tag;
+ enum hw_mmu_page_size_t pg_size_bits;
+
+ switch (page_sz) {
+ case HW_PAGE_SIZE4KB:
+ pg_size_bits = HW_MMU_SMALL_PAGE;
+ break;
+
+ case HW_PAGE_SIZE64KB:
+ pg_size_bits = HW_MMU_LARGE_PAGE;
+ break;
+
+ case HW_PAGE_SIZE1MB:
+ pg_size_bits = HW_MMU_SECTION;
+ break;
+
+ case HW_PAGE_SIZE16MB:
+ pg_size_bits = HW_MMU_SUPERSECTION;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ /* Generate the 20-bit tag from virtual address */
+ virtual_addr_tag = ((virtual_addr & MMU_ADDR_MASK) >> 12);
+
+ mmu_set_cam_entry(base_address, pg_size_bits, 0, 0, virtual_addr_tag);
+
+ mmu_flush_entry(base_address);
+
+ return status;
+}
+
+hw_status hw_mmu_tlb_add(const void __iomem *base_address,
+ u32 physical_addr,
+ u32 virtual_addr,
+ u32 page_sz,
+ u32 entry_num,
+ struct hw_mmu_map_attrs_t *map_attrs,
+ s8 preserved_bit, s8 valid_bit)
+{
+ hw_status status = 0;
+ u32 lock_reg;
+ u32 virtual_addr_tag;
+ enum hw_mmu_page_size_t mmu_pg_size;
+
+ /*Check the input Parameters */
+ switch (page_sz) {
+ case HW_PAGE_SIZE4KB:
+ mmu_pg_size = HW_MMU_SMALL_PAGE;
+ break;
+
+ case HW_PAGE_SIZE64KB:
+ mmu_pg_size = HW_MMU_LARGE_PAGE;
+ break;
+
+ case HW_PAGE_SIZE1MB:
+ mmu_pg_size = HW_MMU_SECTION;
+ break;
+
+ case HW_PAGE_SIZE16MB:
+ mmu_pg_size = HW_MMU_SUPERSECTION;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ lock_reg = MMUMMU_LOCK_READ_REGISTER32(base_address);
+
+ /* Generate the 20-bit tag from virtual address */
+ virtual_addr_tag = ((virtual_addr & MMU_ADDR_MASK) >> 12);
+
+ /* Write the fields in the CAM Entry Register */
+ mmu_set_cam_entry(base_address, mmu_pg_size, preserved_bit, valid_bit,
+ virtual_addr_tag);
+
+ /* Write the different fields of the RAM Entry Register */
+ /* endianism of the page,Element Size of the page (8, 16, 32, 64 bit) */
+ mmu_set_ram_entry(base_address, physical_addr, map_attrs->endianism,
+ map_attrs->element_size, map_attrs->mixed_size);
+
+ /* Update the MMU Lock Register */
+ /* currentVictim between lockedBaseValue and (MMU_Entries_Number - 1) */
+ MMUMMU_LOCK_CURRENT_VICTIM_WRITE32(base_address, entry_num);
+
+ /* Enable loading of an entry in TLB by writing 1
+ into LD_TLB_REG register */
+ MMUMMU_LD_TLB_WRITE_REGISTER32(base_address, MMU_LOAD_TLB);
+
+ MMUMMU_LOCK_WRITE_REGISTER32(base_address, lock_reg);
+
+ return status;
+}
+
+hw_status hw_mmu_pte_set(const u32 pg_tbl_va,
+ u32 physical_addr,
+ u32 virtual_addr,
+ u32 page_sz, struct hw_mmu_map_attrs_t *map_attrs)
+{
+ hw_status status = 0;
+ u32 pte_addr, pte_val;
+ s32 num_entries = 1;
+
+ switch (page_sz) {
+ case HW_PAGE_SIZE4KB:
+ pte_addr = hw_mmu_pte_addr_l2(pg_tbl_va,
+ virtual_addr &
+ MMU_SMALL_PAGE_MASK);
+ pte_val =
+ ((physical_addr & MMU_SMALL_PAGE_MASK) |
+ (map_attrs->endianism << 9) | (map_attrs->
+ element_size << 4) |
+ (map_attrs->mixed_size << 11) | 2);
+ break;
+
+ case HW_PAGE_SIZE64KB:
+ num_entries = 16;
+ pte_addr = hw_mmu_pte_addr_l2(pg_tbl_va,
+ virtual_addr &
+ MMU_LARGE_PAGE_MASK);
+ pte_val =
+ ((physical_addr & MMU_LARGE_PAGE_MASK) |
+ (map_attrs->endianism << 9) | (map_attrs->
+ element_size << 4) |
+ (map_attrs->mixed_size << 11) | 1);
+ break;
+
+ case HW_PAGE_SIZE1MB:
+ pte_addr = hw_mmu_pte_addr_l1(pg_tbl_va,
+ virtual_addr &
+ MMU_SECTION_ADDR_MASK);
+ pte_val =
+ ((((physical_addr & MMU_SECTION_ADDR_MASK) |
+ (map_attrs->endianism << 15) | (map_attrs->
+ element_size << 10) |
+ (map_attrs->mixed_size << 17)) & ~0x40000) | 0x2);
+ break;
+
+ case HW_PAGE_SIZE16MB:
+ num_entries = 16;
+ pte_addr = hw_mmu_pte_addr_l1(pg_tbl_va,
+ virtual_addr &
+ MMU_SSECTION_ADDR_MASK);
+ pte_val =
+ (((physical_addr & MMU_SSECTION_ADDR_MASK) |
+ (map_attrs->endianism << 15) | (map_attrs->
+ element_size << 10) |
+ (map_attrs->mixed_size << 17)
+ ) | 0x40000 | 0x2);
+ break;
+
+ case HW_MMU_COARSE_PAGE_SIZE:
+ pte_addr = hw_mmu_pte_addr_l1(pg_tbl_va,
+ virtual_addr &
+ MMU_SECTION_ADDR_MASK);
+ pte_val = (physical_addr & MMU_PAGE_TABLE_MASK) | 1;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ while (--num_entries >= 0)
+ ((u32 *) pte_addr)[num_entries] = pte_val;
+
+ return status;
+}
+
+hw_status hw_mmu_pte_clear(const u32 pg_tbl_va, u32 virtual_addr, u32 page_size)
+{
+ hw_status status = 0;
+ u32 pte_addr;
+ s32 num_entries = 1;
+
+ switch (page_size) {
+ case HW_PAGE_SIZE4KB:
+ pte_addr = hw_mmu_pte_addr_l2(pg_tbl_va,
+ virtual_addr &
+ MMU_SMALL_PAGE_MASK);
+ break;
+
+ case HW_PAGE_SIZE64KB:
+ num_entries = 16;
+ pte_addr = hw_mmu_pte_addr_l2(pg_tbl_va,
+ virtual_addr &
+ MMU_LARGE_PAGE_MASK);
+ break;
+
+ case HW_PAGE_SIZE1MB:
+ case HW_MMU_COARSE_PAGE_SIZE:
+ pte_addr = hw_mmu_pte_addr_l1(pg_tbl_va,
+ virtual_addr &
+ MMU_SECTION_ADDR_MASK);
+ break;
+
+ case HW_PAGE_SIZE16MB:
+ num_entries = 16;
+ pte_addr = hw_mmu_pte_addr_l1(pg_tbl_va,
+ virtual_addr &
+ MMU_SSECTION_ADDR_MASK);
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ while (--num_entries >= 0)
+ ((u32 *) pte_addr)[num_entries] = 0;
+
+ return status;
+}
+
+/* mmu_flush_entry */
+static hw_status mmu_flush_entry(const void __iomem *base_address)
+{
+ hw_status status = 0;
+ u32 flush_entry_data = 0x1;
+
+ /* write values to register */
+ MMUMMU_FLUSH_ENTRY_WRITE_REGISTER32(base_address, flush_entry_data);
+
+ return status;
+}
+
+/* mmu_set_cam_entry */
+static hw_status mmu_set_cam_entry(const void __iomem *base_address,
+ const u32 page_sz,
+ const u32 preserved_bit,
+ const u32 valid_bit,
+ const u32 virtual_addr_tag)
+{
+ hw_status status = 0;
+ u32 mmu_cam_reg;
+
+ mmu_cam_reg = (virtual_addr_tag << 12);
+ mmu_cam_reg = (mmu_cam_reg) | (page_sz) | (valid_bit << 2) |
+ (preserved_bit << 3);
+
+ /* write values to register */
+ MMUMMU_CAM_WRITE_REGISTER32(base_address, mmu_cam_reg);
+
+ return status;
+}
+
+/* mmu_set_ram_entry */
+static hw_status mmu_set_ram_entry(const void __iomem *base_address,
+ const u32 physical_addr,
+ enum hw_endianism_t endianism,
+ enum hw_element_size_t element_size,
+ enum hw_mmu_mixed_size_t mixed_size)
+{
+ hw_status status = 0;
+ u32 mmu_ram_reg;
+
+ mmu_ram_reg = (physical_addr & MMU_ADDR_MASK);
+ mmu_ram_reg = (mmu_ram_reg) | ((endianism << 9) | (element_size << 7) |
+ (mixed_size << 6));
+
+ /* write values to register */
+ MMUMMU_RAM_WRITE_REGISTER32(base_address, mmu_ram_reg);
+
+ return status;
+
+}
+
+void hw_mmu_tlb_flush_all(const void __iomem *base)
+{
+ __raw_writeb(1, base + MMU_GFLUSH);
+}
diff --git a/drivers/staging/tidspbridge/hw/hw_mmu.h b/drivers/staging/tidspbridge/hw/hw_mmu.h
new file mode 100644
index 00000000000..1458a2c6027
--- /dev/null
+++ b/drivers/staging/tidspbridge/hw/hw_mmu.h
@@ -0,0 +1,163 @@
+/*
+ * hw_mmu.h
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * MMU types and API declarations
+ *
+ * Copyright (C) 2007 Texas Instruments, Inc.
+ *
+ * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef _HW_MMU_H
+#define _HW_MMU_H
+
+#include <linux/types.h>
+
+/* Bitmasks for interrupt sources */
+#define HW_MMU_TRANSLATION_FAULT 0x2
+#define HW_MMU_ALL_INTERRUPTS 0x1F
+
+#define HW_MMU_COARSE_PAGE_SIZE 0x400
+
+/* hw_mmu_mixed_size_t: Enumerated Type used to specify whether to follow
+ CPU/TLB Element size */
+enum hw_mmu_mixed_size_t {
+ HW_MMU_TLBES,
+ HW_MMU_CPUES
+};
+
+/* hw_mmu_map_attrs_t: Struct containing MMU mapping attributes */
+struct hw_mmu_map_attrs_t {
+ enum hw_endianism_t endianism;
+ enum hw_element_size_t element_size;
+ enum hw_mmu_mixed_size_t mixed_size;
+ bool donotlockmpupage;
+};
+
+extern hw_status hw_mmu_enable(const void __iomem *base_address);
+
+extern hw_status hw_mmu_disable(const void __iomem *base_address);
+
+extern hw_status hw_mmu_num_locked_set(const void __iomem *base_address,
+ u32 num_locked_entries);
+
+extern hw_status hw_mmu_victim_num_set(const void __iomem *base_address,
+ u32 victim_entry_num);
+
+/* For MMU faults */
+extern hw_status hw_mmu_event_ack(const void __iomem *base_address,
+ u32 irq_mask);
+
+extern hw_status hw_mmu_event_disable(const void __iomem *base_address,
+ u32 irq_mask);
+
+extern hw_status hw_mmu_event_enable(const void __iomem *base_address,
+ u32 irq_mask);
+
+extern hw_status hw_mmu_event_status(const void __iomem *base_address,
+ u32 *irq_mask);
+
+extern hw_status hw_mmu_fault_addr_read(const void __iomem *base_address,
+ u32 *addr);
+
+/* Set the TT base address */
+extern hw_status hw_mmu_ttb_set(const void __iomem *base_address,
+ u32 ttb_phys_addr);
+
+extern hw_status hw_mmu_twl_enable(const void __iomem *base_address);
+
+extern hw_status hw_mmu_twl_disable(const void __iomem *base_address);
+
+extern hw_status hw_mmu_tlb_flush(const void __iomem *base_address,
+ u32 virtual_addr, u32 page_sz);
+
+extern hw_status hw_mmu_tlb_add(const void __iomem *base_address,
+ u32 physical_addr,
+ u32 virtual_addr,
+ u32 page_sz,
+ u32 entry_num,
+ struct hw_mmu_map_attrs_t *map_attrs,
+ s8 preserved_bit, s8 valid_bit);
+
+/* For PTEs */
+extern hw_status hw_mmu_pte_set(const u32 pg_tbl_va,
+ u32 physical_addr,
+ u32 virtual_addr,
+ u32 page_sz,
+ struct hw_mmu_map_attrs_t *map_attrs);
+
+extern hw_status hw_mmu_pte_clear(const u32 pg_tbl_va,
+ u32 virtual_addr, u32 page_size);
+
+void hw_mmu_tlb_flush_all(const void __iomem *base);
+
+static inline u32 hw_mmu_pte_addr_l1(u32 l1_base, u32 va)
+{
+ u32 pte_addr;
+ u32 va31_to20;
+
+ va31_to20 = va >> (20 - 2); /* Left-shift by 2 here itself */
+ va31_to20 &= 0xFFFFFFFCUL;
+ pte_addr = l1_base + va31_to20;
+
+ return pte_addr;
+}
+
+static inline u32 hw_mmu_pte_addr_l2(u32 l2_base, u32 va)
+{
+ u32 pte_addr;
+
+ pte_addr = (l2_base & 0xFFFFFC00) | ((va >> 10) & 0x3FC);
+
+ return pte_addr;
+}
+
+static inline u32 hw_mmu_pte_coarse_l1(u32 pte_val)
+{
+ u32 pte_coarse;
+
+ pte_coarse = pte_val & 0xFFFFFC00;
+
+ return pte_coarse;
+}
+
+static inline u32 hw_mmu_pte_size_l1(u32 pte_val)
+{
+ u32 pte_size = 0;
+
+ if ((pte_val & 0x3) == 0x1) {
+ /* Points to L2 PT */
+ pte_size = HW_MMU_COARSE_PAGE_SIZE;
+ }
+
+ if ((pte_val & 0x3) == 0x2) {
+ if (pte_val & (1 << 18))
+ pte_size = HW_PAGE_SIZE16MB;
+ else
+ pte_size = HW_PAGE_SIZE1MB;
+ }
+
+ return pte_size;
+}
+
+static inline u32 hw_mmu_pte_size_l2(u32 pte_val)
+{
+ u32 pte_size = 0;
+
+ if (pte_val & 0x2)
+ pte_size = HW_PAGE_SIZE4KB;
+ else if (pte_val & 0x1)
+ pte_size = HW_PAGE_SIZE64KB;
+
+ return pte_size;
+}
+
+#endif /* _HW_MMU_H */
diff --git a/drivers/staging/tidspbridge/include/dspbridge/_chnl_sm.h b/drivers/staging/tidspbridge/include/dspbridge/_chnl_sm.h
new file mode 100644
index 00000000000..8efd1fba2f6
--- /dev/null
+++ b/drivers/staging/tidspbridge/include/dspbridge/_chnl_sm.h
@@ -0,0 +1,181 @@
+/*
+ * _chnl_sm.h
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * Private header file defining channel manager and channel objects for
+ * a shared memory channel driver.
+ *
+ * Shared between the modules implementing the shared memory channel class
+ * library.
+ *
+ * Copyright (C) 2005-2006 Texas Instruments, Inc.
+ *
+ * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef _CHNL_SM_
+#define _CHNL_SM_
+
+#include <dspbridge/dspapi.h>
+#include <dspbridge/dspdefs.h>
+
+#include <dspbridge/list.h>
+#include <dspbridge/ntfy.h>
+
+/*
+ * These target side symbols define the beginning and ending addresses
+ * of shared memory buffer. They are defined in the *cfg.cmd file by
+ * cdb code.
+ */
+#define CHNL_SHARED_BUFFER_BASE_SYM "_SHM_BEG"
+#define CHNL_SHARED_BUFFER_LIMIT_SYM "_SHM_END"
+#define BRIDGEINIT_BIOSGPTIMER "_BRIDGEINIT_BIOSGPTIMER"
+#define BRIDGEINIT_LOADMON_GPTIMER "_BRIDGEINIT_LOADMON_GPTIMER"
+
+#ifndef _CHNL_WORDSIZE
+#define _CHNL_WORDSIZE 4 /* default _CHNL_WORDSIZE is 2 bytes/word */
+#endif
+
+#define MAXOPPS 16
+
+/* Shared memory config options */
+#define SHM_CURROPP 0 /* Set current OPP in shm */
+#define SHM_OPPINFO 1 /* Set dsp voltage and freq table values */
+#define SHM_GETOPP 2 /* Get opp requested by DSP */
+
+struct opp_table_entry {
+ u32 voltage;
+ u32 frequency;
+ u32 min_freq;
+ u32 max_freq;
+};
+
+struct opp_struct {
+ u32 curr_opp_pt;
+ u32 num_opp_pts;
+ struct opp_table_entry opp_point[MAXOPPS];
+};
+
+/* Request to MPU */
+struct opp_rqst_struct {
+ u32 rqst_dsp_freq;
+ u32 rqst_opp_pt;
+};
+
+/* Info to MPU */
+struct load_mon_struct {
+ u32 curr_dsp_load;
+ u32 curr_dsp_freq;
+ u32 pred_dsp_load;
+ u32 pred_dsp_freq;
+};
+
+/* Structure in shared between DSP and PC for communication. */
+struct shm {
+ u32 dsp_free_mask; /* Written by DSP, read by PC. */
+ u32 host_free_mask; /* Written by PC, read by DSP */
+
+ u32 input_full; /* Input channel has unread data. */
+ u32 input_id; /* Channel for which input is available. */
+ u32 input_size; /* Size of data block (in DSP words). */
+
+ u32 output_full; /* Output channel has unread data. */
+ u32 output_id; /* Channel for which output is available. */
+ u32 output_size; /* Size of data block (in DSP words). */
+
+ u32 arg; /* Arg for Issue/Reclaim (23 bits for 55x). */
+ u32 resvd; /* Keep structure size even for 32-bit DSPs */
+
+ /* Operating Point structure */
+ struct opp_struct opp_table_struct;
+ /* Operating Point Request structure */
+ struct opp_rqst_struct opp_request;
+ /* load monitor information structure */
+ struct load_mon_struct load_mon_info;
+#ifdef CONFIG_TIDSPBRIDGE_WDT3
+ /* Flag for WDT enable/disable F/I clocks */
+ u32 wdt_setclocks;
+ u32 wdt_overflow; /* WDT overflow time */
+ char dummy[176]; /* padding to 256 byte boundary */
+#else
+ char dummy[184]; /* padding to 256 byte boundary */
+#endif
+ u32 shm_dbg_var[64]; /* shared memory debug variables */
+};
+
+ /* Channel Manager: only one created per board: */
+struct chnl_mgr {
+ /* Function interface to Bridge driver */
+ struct bridge_drv_interface *intf_fxns;
+ struct io_mgr *hio_mgr; /* IO manager */
+ /* Device this board represents */
+ struct dev_object *hdev_obj;
+
+ /* These fields initialized in bridge_chnl_create(): */
+ u32 dw_output_mask; /* Host output channels w/ full buffers */
+ u32 dw_last_output; /* Last output channel fired from DPC */
+ /* Critical section object handle */
+ spinlock_t chnl_mgr_lock;
+ u32 word_size; /* Size in bytes of DSP word */
+ u8 max_channels; /* Total number of channels */
+ u8 open_channels; /* Total number of open channels */
+ struct chnl_object **ap_channel; /* Array of channels */
+ u8 dw_type; /* Type of channel class library */
+ /* If no shm syms, return for CHNL_Open */
+ int chnl_open_status;
+};
+
+/*
+ * Channel: up to CHNL_MAXCHANNELS per board or if DSP-DMA supported then
+ * up to CHNL_MAXCHANNELS + CHNL_MAXDDMACHNLS per board.
+ */
+struct chnl_object {
+ /* Pointer back to channel manager */
+ struct chnl_mgr *chnl_mgr_obj;
+ u32 chnl_id; /* Channel id */
+ u8 dw_state; /* Current channel state */
+ s8 chnl_mode; /* Chnl mode and attributes */
+ /* Chnl I/O completion event (user mode) */
+ void *user_event;
+ /* Abstract syncronization object */
+ struct sync_object *sync_event;
+ u32 process; /* Process which created this channel */
+ u32 pcb_arg; /* Argument to use with callback */
+ struct lst_list *pio_requests; /* List of IOR's to driver */
+ s32 cio_cs; /* Number of IOC's in queue */
+ s32 cio_reqs; /* Number of IORequests in queue */
+ s32 chnl_packets; /* Initial number of free Irps */
+ /* List of IOC's from driver */
+ struct lst_list *pio_completions;
+ struct lst_list *free_packets_list; /* List of free Irps */
+ struct ntfy_object *ntfy_obj;
+ u32 bytes_moved; /* Total number of bytes transfered */
+
+ /* For DSP-DMA */
+
+ /* Type of chnl transport:CHNL_[PCPY][DDMA] */
+ u32 chnl_type;
+};
+
+/* I/O Request/completion packet: */
+struct chnl_irp {
+ struct list_head link; /* Link to next CHIRP in queue. */
+ /* Buffer to be filled/emptied. (User) */
+ u8 *host_user_buf;
+ /* Buffer to be filled/emptied. (System) */
+ u8 *host_sys_buf;
+ u32 dw_arg; /* Issue/Reclaim argument. */
+ u32 dsp_tx_addr; /* Transfer address on DSP side. */
+ u32 byte_size; /* Bytes transferred. */
+ u32 buf_size; /* Actual buffer size when allocated. */
+ u32 status; /* Status of IO completion. */
+};
+
+#endif /* _CHNL_SM_ */
diff --git a/drivers/staging/tidspbridge/include/dspbridge/brddefs.h b/drivers/staging/tidspbridge/include/dspbridge/brddefs.h
new file mode 100644
index 00000000000..f80d9a5f05a
--- /dev/null
+++ b/drivers/staging/tidspbridge/include/dspbridge/brddefs.h
@@ -0,0 +1,39 @@
+/*
+ * brddefs.h
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * Global BRD constants and types, shared between DSP API and Bridge driver.
+ *
+ * Copyright (C) 2005-2006 Texas Instruments, Inc.
+ *
+ * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef BRDDEFS_
+#define BRDDEFS_
+
+/* platform status values */
+#define BRD_STOPPED 0x0 /* No Monitor Loaded, Not running. */
+#define BRD_IDLE 0x1 /* Monitor Loaded, but suspended. */
+#define BRD_RUNNING 0x2 /* Monitor loaded, and executing. */
+#define BRD_UNKNOWN 0x3 /* Board state is indeterminate. */
+#define BRD_SYNCINIT 0x4
+#define BRD_LOADED 0x5
+#define BRD_LASTSTATE BRD_LOADED /* Set to highest legal board state. */
+#define BRD_SLEEP_TRANSITION 0x6 /* Sleep transition in progress */
+#define BRD_HIBERNATION 0x7 /* MPU initiated hibernation */
+#define BRD_RETENTION 0x8 /* Retention mode */
+#define BRD_DSP_HIBERNATION 0x9 /* DSP initiated hibernation */
+#define BRD_ERROR 0xA /* Board state is Error */
+
+/* BRD Object */
+struct brd_object;
+
+#endif /* BRDDEFS_ */
diff --git a/drivers/staging/tidspbridge/include/dspbridge/cfg.h b/drivers/staging/tidspbridge/include/dspbridge/cfg.h
new file mode 100644
index 00000000000..05a8999070f
--- /dev/null
+++ b/drivers/staging/tidspbridge/include/dspbridge/cfg.h
@@ -0,0 +1,222 @@
+/*
+ * cfg.h
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * PM Configuration module.
+ *
+ * Copyright (C) 2005-2006 Texas Instruments, Inc.
+ *
+ * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef CFG_
+#define CFG_
+#include <dspbridge/host_os.h>
+#include <dspbridge/cfgdefs.h>
+
+/*
+ * ======== cfg_exit ========
+ * Purpose:
+ * Discontinue usage of the CFG module.
+ * Parameters:
+ * Returns:
+ * Requires:
+ * cfg_init(void) was previously called.
+ * Ensures:
+ * Resources acquired in cfg_init(void) are freed.
+ */
+extern void cfg_exit(void);
+
+/*
+ * ======== cfg_get_auto_start ========
+ * Purpose:
+ * Retreive the autostart mask, if any, for this board.
+ * Parameters:
+ * dev_node_obj: Handle to the dev_node who's driver we are querying.
+ * auto_start: Ptr to location for 32 bit autostart mask.
+ * Returns:
+ * 0: Success.
+ * -EFAULT: dev_node_obj is invalid.
+ * -ENODATA: Unable to retreive resource.
+ * Requires:
+ * CFG initialized.
+ * Ensures:
+ * 0: *auto_start contains autostart mask for this devnode.
+ */
+extern int cfg_get_auto_start(struct cfg_devnode *dev_node_obj,
+ u32 *auto_start);
+
+/*
+ * ======== cfg_get_cd_version ========
+ * Purpose:
+ * Retrieves the version of the PM Class Driver.
+ * Parameters:
+ * version: Ptr to u32 to contain version number upon return.
+ * Returns:
+ * 0: Success. version contains Class Driver version in
+ * the form: 0xAABBCCDD where AABB is Major version and
+ * CCDD is Minor.
+ * -EPERM: Failure.
+ * Requires:
+ * CFG initialized.
+ * Ensures:
+ * 0: Success.
+ * else: *version is NULL.
+ */
+extern int cfg_get_cd_version(u32 *version);
+
+/*
+ * ======== cfg_get_dev_object ========
+ * Purpose:
+ * Retrieve the Device Object handle for a given devnode.
+ * Parameters:
+ * dev_node_obj: Platform's dev_node handle from which to retrieve
+ * value.
+ * value: Ptr to location to store the value.
+ * Returns:
+ * 0: Success.
+ * -EFAULT: dev_node_obj is invalid or device_obj is invalid.
+ * -ENODATA: The resource is not available.
+ * Requires:
+ * CFG initialized.
+ * Ensures:
+ * 0: *value is set to the retrieved u32.
+ * else: *value is set to 0L.
+ */
+extern int cfg_get_dev_object(struct cfg_devnode *dev_node_obj,
+ u32 *value);
+
+/*
+ * ======== cfg_get_exec_file ========
+ * Purpose:
+ * Retreive the default executable, if any, for this board.
+ * Parameters:
+ * dev_node_obj: Handle to the dev_node who's driver we are querying.
+ * buf_size: Size of buffer.
+ * str_exec_file: Ptr to character buf to hold ExecFile.
+ * Returns:
+ * 0: Success.
+ * -EFAULT: dev_node_obj is invalid or str_exec_file is invalid.
+ * -ENODATA: The resource is not available.
+ * Requires:
+ * CFG initialized.
+ * Ensures:
+ * 0: Not more than buf_size bytes were copied into str_exec_file,
+ * and *str_exec_file contains default executable for this
+ * devnode.
+ */
+extern int cfg_get_exec_file(struct cfg_devnode *dev_node_obj,
+ u32 buf_size, char *str_exec_file);
+
+/*
+ * ======== cfg_get_object ========
+ * Purpose:
+ * Retrieve the Driver Object handle From the Registry
+ * Parameters:
+ * value: Ptr to location to store the value.
+ * dw_type Type of Object to Get
+ * Returns:
+ * 0: Success.
+ * Requires:
+ * CFG initialized.
+ * Ensures:
+ * 0: *value is set to the retrieved u32(non-Zero).
+ * else: *value is set to 0L.
+ */
+extern int cfg_get_object(u32 *value, u8 dw_type);
+
+/*
+ * ======== cfg_get_perf_value ========
+ * Purpose:
+ * Retrieve a flag indicating whether PERF should log statistics for the
+ * PM class driver.
+ * Parameters:
+ * enable_perf: Location to store flag. 0 indicates the key was
+ * not found, or had a zero value. A nonzero value
+ * means the key was found and had a nonzero value.
+ * Returns:
+ * Requires:
+ * enable_perf != NULL;
+ * Ensures:
+ */
+extern void cfg_get_perf_value(bool *enable_perf);
+
+/*
+ * ======== cfg_get_zl_file ========
+ * Purpose:
+ * Retreive the ZLFile, if any, for this board.
+ * Parameters:
+ * dev_node_obj: Handle to the dev_node who's driver we are querying.
+ * buf_size: Size of buffer.
+ * str_zl_file_name: Ptr to character buf to hold ZLFileName.
+ * Returns:
+ * 0: Success.
+ * -EFAULT: str_zl_file_name is invalid or dev_node_obj is invalid.
+ * -ENODATA: couldn't find the ZLFileName.
+ * Requires:
+ * CFG initialized.
+ * Ensures:
+ * 0: Not more than buf_size bytes were copied into
+ * str_zl_file_name, and *str_zl_file_name contains ZLFileName
+ * for this devnode.
+ */
+extern int cfg_get_zl_file(struct cfg_devnode *dev_node_obj,
+ u32 buf_size, char *str_zl_file_name);
+
+/*
+ * ======== cfg_init ========
+ * Purpose:
+ * Initialize the CFG module's private state.
+ * Parameters:
+ * Returns:
+ * TRUE if initialized; FALSE if error occured.
+ * Requires:
+ * Ensures:
+ * A requirement for each of the other public CFG functions.
+ */
+extern bool cfg_init(void);
+
+/*
+ * ======== cfg_set_dev_object ========
+ * Purpose:
+ * Store the Device Object handle for a given devnode.
+ * Parameters:
+ * dev_node_obj: Platform's dev_node handle we are storing value with.
+ * value: Arbitrary value to store.
+ * Returns:
+ * 0: Success.
+ * -EFAULT: dev_node_obj is invalid.
+ * -EPERM: Internal Error.
+ * Requires:
+ * CFG initialized.
+ * Ensures:
+ * 0: The Private u32 was successfully set.
+ */
+extern int cfg_set_dev_object(struct cfg_devnode *dev_node_obj,
+ u32 value);
+
+/*
+ * ======== CFG_SetDrvObject ========
+ * Purpose:
+ * Store the Driver Object handle.
+ * Parameters:
+ * value: Arbitrary value to store.
+ * dw_type Type of Object to Store
+ * Returns:
+ * 0: Success.
+ * -EPERM: Internal Error.
+ * Requires:
+ * CFG initialized.
+ * Ensures:
+ * 0: The Private u32 was successfully set.
+ */
+extern int cfg_set_object(u32 value, u8 dw_type);
+
+#endif /* CFG_ */
diff --git a/drivers/staging/tidspbridge/include/dspbridge/cfgdefs.h b/drivers/staging/tidspbridge/include/dspbridge/cfgdefs.h
new file mode 100644
index 00000000000..38122dbf877
--- /dev/null
+++ b/drivers/staging/tidspbridge/include/dspbridge/cfgdefs.h
@@ -0,0 +1,81 @@
+/*
+ * cfgdefs.h
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * Global CFG constants and types, shared between DSP API and Bridge driver.
+ *
+ * Copyright (C) 2005-2006 Texas Instruments, Inc.
+ *
+ * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef CFGDEFS_
+#define CFGDEFS_
+
+/* Maximum length of module search path. */
+#define CFG_MAXSEARCHPATHLEN 255
+
+/* Maximum length of general paths. */
+#define CFG_MAXPATH 255
+
+/* Host Resources: */
+#define CFG_MAXMEMREGISTERS 9
+#define CFG_MAXIOPORTS 20
+#define CFG_MAXIRQS 7
+#define CFG_MAXDMACHANNELS 7
+
+/* IRQ flag */
+#define CFG_IRQSHARED 0x01 /* IRQ can be shared */
+
+/* DSP Resources: */
+#define CFG_DSPMAXMEMTYPES 10
+#define CFG_DEFAULT_NUM_WINDOWS 1 /* We support only one window. */
+
+/* A platform-related device handle: */
+struct cfg_devnode;
+
+/*
+ * Host resource structure.
+ */
+struct cfg_hostres {
+ u32 num_mem_windows; /* Set to default */
+ /* This is the base.memory */
+ u32 dw_mem_base[CFG_MAXMEMREGISTERS]; /* shm virtual address */
+ u32 dw_mem_length[CFG_MAXMEMREGISTERS]; /* Length of the Base */
+ u32 dw_mem_phys[CFG_MAXMEMREGISTERS]; /* shm Physical address */
+ u8 birq_registers; /* IRQ Number */
+ u8 birq_attrib; /* IRQ Attribute */
+ u32 dw_offset_for_monitor; /* The Shared memory starts from
+ * dw_mem_base + this offset */
+ /*
+ * Info needed by NODE for allocating channels to communicate with RMS:
+ * dw_chnl_offset: Offset of RMS channels. Lower channels are
+ * reserved.
+ * dw_chnl_buf_size: Size of channel buffer to send to RMS
+ * dw_num_chnls: Total number of channels
+ * (including reserved).
+ */
+ u32 dw_chnl_offset;
+ u32 dw_chnl_buf_size;
+ u32 dw_num_chnls;
+ void __iomem *dw_per_base;
+ u32 dw_per_pm_base;
+ u32 dw_core_pm_base;
+ void __iomem *dw_dmmu_base;
+ void __iomem *dw_sys_ctrl_base;
+};
+
+struct cfg_dspmemdesc {
+ u32 mem_type; /* Type of memory. */
+ u32 ul_min; /* Minimum amount of memory of this type. */
+ u32 ul_max; /* Maximum amount of memory of this type. */
+};
+
+#endif /* CFGDEFS_ */
diff --git a/drivers/staging/tidspbridge/include/dspbridge/chnl.h b/drivers/staging/tidspbridge/include/dspbridge/chnl.h
new file mode 100644
index 00000000000..8733b3b8193
--- /dev/null
+++ b/drivers/staging/tidspbridge/include/dspbridge/chnl.h
@@ -0,0 +1,130 @@
+/*
+ * chnl.h
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * DSP API channel interface: multiplexes data streams through the single
+ * physical link managed by a Bridge driver.
+ *
+ * See DSP API chnl.h for more details.
+ *
+ * Copyright (C) 2005-2006 Texas Instruments, Inc.
+ *
+ * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef CHNL_
+#define CHNL_
+
+#include <dspbridge/chnlpriv.h>
+
+/*
+ * ======== chnl_close ========
+ * Purpose:
+ * Ensures all pending I/O on this channel is cancelled, discards all
+ * queued I/O completion notifications, then frees the resources allocated
+ * for this channel, and makes the corresponding logical channel id
+ * available for subsequent use.
+ * Parameters:
+ * chnl_obj: Channel object handle.
+ * Returns:
+ * 0: Success;
+ * -EFAULT: Invalid chnl_obj.
+ * Requires:
+ * chnl_init(void) called.
+ * No thread must be blocked on this channel's I/O completion event.
+ * Ensures:
+ * 0: The I/O completion event for this channel is freed.
+ * chnl_obj is no longer valid.
+ */
+extern int chnl_close(struct chnl_object *chnl_obj);
+
+/*
+ * ======== chnl_create ========
+ * Purpose:
+ * Create a channel manager object, responsible for opening new channels
+ * and closing old ones for a given board.
+ * Parameters:
+ * channel_mgr: Location to store a channel manager object on output.
+ * hdev_obj: Handle to a device object.
+ * mgr_attrts: Channel manager attributes.
+ * mgr_attrts->max_channels: Max channels
+ * mgr_attrts->birq: Channel's I/O IRQ number.
+ * mgr_attrts->irq_shared: TRUE if the IRQ is shareable.
+ * mgr_attrts->word_size: DSP Word size in equivalent PC bytes..
+ * Returns:
+ * 0: Success;
+ * -EFAULT: hdev_obj is invalid.
+ * -EINVAL: max_channels is 0.
+ * Invalid DSP word size (must be > 0).
+ * Invalid base address for DSP communications.
+ * -ENOMEM: Insufficient memory for requested resources.
+ * -EIO: Unable to plug channel ISR for configured IRQ.
+ * -ECHRNG: This manager cannot handle this many channels.
+ * -EEXIST: Channel manager already exists for this device.
+ * Requires:
+ * chnl_init(void) called.
+ * channel_mgr != NULL.
+ * mgr_attrts != NULL.
+ * Ensures:
+ * 0: Subsequent calls to chnl_create() for the same
+ * board without an intervening call to
+ * chnl_destroy() will fail.
+ */
+extern int chnl_create(struct chnl_mgr **channel_mgr,
+ struct dev_object *hdev_obj,
+ const struct chnl_mgrattrs *mgr_attrts);
+
+/*
+ * ======== chnl_destroy ========
+ * Purpose:
+ * Close all open channels, and destroy the channel manager.
+ * Parameters:
+ * hchnl_mgr: Channel manager object.
+ * Returns:
+ * 0: Success.
+ * -EFAULT: hchnl_mgr was invalid.
+ * Requires:
+ * chnl_init(void) called.
+ * Ensures:
+ * 0: Cancels I/O on each open channel.
+ * Closes each open channel.
+ * chnl_create may subsequently be called for the
+ * same board.
+ */
+extern int chnl_destroy(struct chnl_mgr *hchnl_mgr);
+
+/*
+ * ======== chnl_exit ========
+ * Purpose:
+ * Discontinue usage of the CHNL module.
+ * Parameters:
+ * Returns:
+ * Requires:
+ * chnl_init(void) previously called.
+ * Ensures:
+ * Resources, if any acquired in chnl_init(void), are freed when the last
+ * client of CHNL calls chnl_exit(void).
+ */
+extern void chnl_exit(void);
+
+/*
+ * ======== chnl_init ========
+ * Purpose:
+ * Initialize the CHNL module's private state.
+ * Parameters:
+ * Returns:
+ * TRUE if initialized; FALSE if error occurred.
+ * Requires:
+ * Ensures:
+ * A requirement for each of the other public CHNL functions.
+ */
+extern bool chnl_init(void);
+
+#endif /* CHNL_ */
diff --git a/drivers/staging/tidspbridge/include/dspbridge/chnldefs.h b/drivers/staging/tidspbridge/include/dspbridge/chnldefs.h
new file mode 100644
index 00000000000..5bf5f6b0b7b
--- /dev/null
+++ b/drivers/staging/tidspbridge/include/dspbridge/chnldefs.h
@@ -0,0 +1,66 @@
+/*
+ * chnldefs.h
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * System-wide channel objects and constants.
+ *
+ * Copyright (C) 2005-2006 Texas Instruments, Inc.
+ *
+ * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef CHNLDEFS_
+#define CHNLDEFS_
+
+/* Channel id option. */
+#define CHNL_PICKFREE (~0UL) /* Let manager pick a free channel. */
+
+/* Channel manager limits: */
+#define CHNL_INITIOREQS 4 /* Default # of I/O requests. */
+
+/* Channel modes */
+#define CHNL_MODETODSP 0 /* Data streaming to the DSP. */
+#define CHNL_MODEFROMDSP 1 /* Data streaming from the DSP. */
+
+/* GetIOCompletion flags */
+#define CHNL_IOCINFINITE 0xffffffff /* Wait forever for IO completion. */
+#define CHNL_IOCNOWAIT 0x0 /* Dequeue an IOC, if available. */
+
+/* IO Completion Record status: */
+#define CHNL_IOCSTATCOMPLETE 0x0000 /* IO Completed. */
+#define CHNL_IOCSTATCANCEL 0x0002 /* IO was cancelled */
+#define CHNL_IOCSTATTIMEOUT 0x0008 /* Wait for IOC timed out. */
+#define CHNL_IOCSTATEOS 0x8000 /* End Of Stream reached. */
+
+/* Macros for checking I/O Completion status: */
+#define CHNL_IS_IO_COMPLETE(ioc) (!(ioc.status & ~CHNL_IOCSTATEOS))
+#define CHNL_IS_IO_CANCELLED(ioc) (ioc.status & CHNL_IOCSTATCANCEL)
+#define CHNL_IS_TIMED_OUT(ioc) (ioc.status & CHNL_IOCSTATTIMEOUT)
+
+/* Channel attributes: */
+struct chnl_attr {
+ u32 uio_reqs; /* Max # of preallocated I/O requests. */
+ void *event_obj; /* User supplied auto-reset event object. */
+ char *pstr_event_name; /* Ptr to name of user event object. */
+ void *reserved1; /* Reserved for future use. */
+ u32 reserved2; /* Reserved for future use. */
+
+};
+
+/* I/O completion record: */
+struct chnl_ioc {
+ void *pbuf; /* Buffer to be filled/emptied. */
+ u32 byte_size; /* Bytes transferred. */
+ u32 buf_size; /* Actual buffer size in bytes */
+ u32 status; /* Status of IO completion. */
+ u32 dw_arg; /* User argument associated with pbuf. */
+};
+
+#endif /* CHNLDEFS_ */
diff --git a/drivers/staging/tidspbridge/include/dspbridge/chnlpriv.h b/drivers/staging/tidspbridge/include/dspbridge/chnlpriv.h
new file mode 100644
index 00000000000..9292100b1c0
--- /dev/null
+++ b/drivers/staging/tidspbridge/include/dspbridge/chnlpriv.h
@@ -0,0 +1,98 @@
+/*
+ * chnlpriv.h
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * Private channel header shared between DSPSYS, DSPAPI and
+ * Bridge driver modules.
+ *
+ * Copyright (C) 2005-2006 Texas Instruments, Inc.
+ *
+ * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef CHNLPRIV_
+#define CHNLPRIV_
+
+#include <dspbridge/chnldefs.h>
+#include <dspbridge/devdefs.h>
+#include <dspbridge/sync.h>
+
+/* Channel manager limits: */
+#define CHNL_MAXCHANNELS 32 /* Max channels available per transport */
+
+/*
+ * Trans port channel Id definitions:(must match dsp-side).
+ *
+ * For CHNL_MAXCHANNELS = 16:
+ *
+ * ChnlIds:
+ * 0-15 (PCPY) - transport 0)
+ * 16-31 (DDMA) - transport 1)
+ * 32-47 (ZCPY) - transport 2)
+ */
+#define CHNL_PCPY 0 /* Proc-copy transport 0 */
+
+#define CHNL_MAXIRQ 0xff /* Arbitrarily large number. */
+
+/* The following modes are private: */
+#define CHNL_MODEUSEREVENT 0x1000 /* User provided the channel event. */
+#define CHNL_MODEMASK 0x1001
+
+/* Higher level channel states: */
+#define CHNL_STATEREADY 0 /* Channel ready for I/O. */
+#define CHNL_STATECANCEL 1 /* I/O was cancelled. */
+#define CHNL_STATEEOS 2 /* End Of Stream reached. */
+
+/* Macros for checking mode: */
+#define CHNL_IS_INPUT(mode) (mode & CHNL_MODEFROMDSP)
+#define CHNL_IS_OUTPUT(mode) (!CHNL_IS_INPUT(mode))
+
+/* Types of channel class libraries: */
+#define CHNL_TYPESM 1 /* Shared memory driver. */
+#define CHNL_TYPEBM 2 /* Bus Mastering driver. */
+
+/* Max string length of channel I/O completion event name - change if needed */
+#define CHNL_MAXEVTNAMELEN 32
+
+/* Max memory pages lockable in CHNL_PrepareBuffer() - change if needed */
+#define CHNL_MAXLOCKPAGES 64
+
+/* Channel info. */
+struct chnl_info {
+ struct chnl_mgr *hchnl_mgr; /* Owning channel manager. */
+ u32 cnhl_id; /* Channel ID. */
+ void *event_obj; /* Channel I/O completion event. */
+ /*Abstraction of I/O completion event. */
+ struct sync_object *sync_event;
+ s8 dw_mode; /* Channel mode. */
+ u8 dw_state; /* Current channel state. */
+ u32 bytes_tx; /* Total bytes transferred. */
+ u32 cio_cs; /* Number of IOCs in queue. */
+ u32 cio_reqs; /* Number of IO Requests in queue. */
+ u32 process; /* Process owning this channel. */
+};
+
+/* Channel manager info: */
+struct chnl_mgrinfo {
+ u8 dw_type; /* Type of channel class library. */
+ /* Channel handle, given the channel id. */
+ struct chnl_object *chnl_obj;
+ u8 open_channels; /* Number of open channels. */
+ u8 max_channels; /* total # of chnls supported */
+};
+
+/* Channel Manager Attrs: */
+struct chnl_mgrattrs {
+ /* Max number of channels this manager can use. */
+ u8 max_channels;
+ u32 word_size; /* DSP Word size. */
+};
+
+#endif /* CHNLPRIV_ */
diff --git a/drivers/staging/tidspbridge/include/dspbridge/clk.h b/drivers/staging/tidspbridge/include/dspbridge/clk.h
new file mode 100644
index 00000000000..b2395032342
--- /dev/null
+++ b/drivers/staging/tidspbridge/include/dspbridge/clk.h
@@ -0,0 +1,101 @@
+/*
+ * clk.h
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * Provides Clock functions.
+ *
+ * Copyright (C) 2005-2006 Texas Instruments, Inc.
+ *
+ * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef _CLK_H
+#define _CLK_H
+
+enum dsp_clk_id {
+ DSP_CLK_IVA2 = 0,
+ DSP_CLK_GPT5,
+ DSP_CLK_GPT6,
+ DSP_CLK_GPT7,
+ DSP_CLK_GPT8,
+ DSP_CLK_WDT3,
+ DSP_CLK_MCBSP1,
+ DSP_CLK_MCBSP2,
+ DSP_CLK_MCBSP3,
+ DSP_CLK_MCBSP4,
+ DSP_CLK_MCBSP5,
+ DSP_CLK_SSI,
+ DSP_CLK_NOT_DEFINED
+};
+
+/*
+ * ======== dsp_clk_exit ========
+ * Purpose:
+ * Discontinue usage of module; free resources when reference count
+ * reaches 0.
+ * Parameters:
+ * Returns:
+ * Requires:
+ * CLK initialized.
+ * Ensures:
+ * Resources used by module are freed when cRef reaches zero.
+ */
+extern void dsp_clk_exit(void);
+
+/*
+ * ======== dsp_clk_init ========
+ * Purpose:
+ * Initializes private state of CLK module.
+ * Parameters:
+ * Returns:
+ * TRUE if initialized; FALSE if error occured.
+ * Requires:
+ * Ensures:
+ * CLK initialized.
+ */
+extern void dsp_clk_init(void);
+
+void dsp_gpt_wait_overflow(short int clk_id, unsigned int load);
+
+/*
+ * ======== dsp_clk_enable ========
+ * Purpose:
+ * Enables the clock requested.
+ * Parameters:
+ * Returns:
+ * 0: Success.
+ * -EPERM: Error occured while enabling the clock.
+ * Requires:
+ * Ensures:
+ */
+extern int dsp_clk_enable(enum dsp_clk_id clk_id);
+
+u32 dsp_clock_enable_all(u32 dsp_per_clocks);
+
+/*
+ * ======== dsp_clk_disable ========
+ * Purpose:
+ * Disables the clock requested.
+ * Parameters:
+ * Returns:
+ * 0: Success.
+ * -EPERM: Error occured while disabling the clock.
+ * Requires:
+ * Ensures:
+ */
+extern int dsp_clk_disable(enum dsp_clk_id clk_id);
+
+extern u32 dsp_clk_get_iva2_rate(void);
+
+u32 dsp_clock_disable_all(u32 dsp_per_clocks);
+
+extern void ssi_clk_prepare(bool FLAG);
+
+#endif /* _SYNC_H */
diff --git a/drivers/staging/tidspbridge/include/dspbridge/cmm.h b/drivers/staging/tidspbridge/include/dspbridge/cmm.h
new file mode 100644
index 00000000000..a921f1b6ee7
--- /dev/null
+++ b/drivers/staging/tidspbridge/include/dspbridge/cmm.h
@@ -0,0 +1,386 @@
+/*
+ * cmm.h
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * The Communication Memory Management(CMM) module provides shared memory
+ * management services for DSP/BIOS Bridge data streaming and messaging.
+ * Multiple shared memory segments can be registered with CMM. Memory is
+ * coelesced back to the appropriate pool when a buffer is freed.
+ *
+ * The CMM_Xlator[xxx] functions are used for node messaging and data
+ * streaming address translation to perform zero-copy inter-processor
+ * data transfer(GPP<->DSP). A "translator" object is created for a node or
+ * stream object that contains per thread virtual address information. This
+ * translator info is used at runtime to perform SM address translation
+ * to/from the DSP address space.
+ *
+ * Notes:
+ * cmm_xlator_alloc_buf - Used by Node and Stream modules for SM address
+ * translation.
+ *
+ * Copyright (C) 2008 Texas Instruments, Inc.
+ *
+ * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef CMM_
+#define CMM_
+
+#include <dspbridge/devdefs.h>
+
+#include <dspbridge/cmmdefs.h>
+#include <dspbridge/host_os.h>
+
+/*
+ * ======== cmm_calloc_buf ========
+ * Purpose:
+ * Allocate memory buffers that can be used for data streaming or
+ * messaging.
+ * Parameters:
+ * hcmm_mgr: Cmm Mgr handle.
+ * usize: Number of bytes to allocate.
+ * pattr: Attributes of memory to allocate.
+ * pp_buf_va: Address of where to place VA.
+ * Returns:
+ * Pointer to a zero'd block of SM memory;
+ * NULL if memory couldn't be allocated,
+ * or if byte_size == 0,
+ * Requires:
+ * Valid hcmm_mgr.
+ * CMM initialized.
+ * Ensures:
+ * The returned pointer, if not NULL, points to a valid memory block of
+ * the size requested.
+ *
+ */
+extern void *cmm_calloc_buf(struct cmm_object *hcmm_mgr,
+ u32 usize, struct cmm_attrs *pattrs,
+ void **pp_buf_va);
+
+/*
+ * ======== cmm_create ========
+ * Purpose:
+ * Create a communication memory manager object.
+ * Parameters:
+ * ph_cmm_mgr: Location to store a communication manager handle on
+ * output.
+ * hdev_obj: Handle to a device object.
+ * mgr_attrts: Comm mem manager attributes.
+ * Returns:
+ * 0: Success;
+ * -ENOMEM: Insufficient memory for requested resources.
+ * -EPERM: Failed to initialize critical sect sync object.
+ *
+ * Requires:
+ * cmm_init(void) called.
+ * ph_cmm_mgr != NULL.
+ * mgr_attrts->ul_min_block_size >= 4 bytes.
+ * Ensures:
+ *
+ */
+extern int cmm_create(struct cmm_object **ph_cmm_mgr,
+ struct dev_object *hdev_obj,
+ const struct cmm_mgrattrs *mgr_attrts);
+
+/*
+ * ======== cmm_destroy ========
+ * Purpose:
+ * Destroy the communication memory manager object.
+ * Parameters:
+ * hcmm_mgr: Cmm Mgr handle.
+ * force: Force deallocation of all cmm memory immediately if set TRUE.
+ * If FALSE, and outstanding allocations will return -EPERM
+ * status.
+ * Returns:
+ * 0: CMM object & resources deleted.
+ * -EPERM: Unable to free CMM object due to outstanding allocation.
+ * -EFAULT: Unable to free CMM due to bad handle.
+ * Requires:
+ * CMM is initialized.
+ * hcmm_mgr != NULL.
+ * Ensures:
+ * Memory resources used by Cmm Mgr are freed.
+ */
+extern int cmm_destroy(struct cmm_object *hcmm_mgr, bool force);
+
+/*
+ * ======== cmm_exit ========
+ * Purpose:
+ * Discontinue usage of module. Cleanup CMM module if CMM cRef reaches zero.
+ * Parameters:
+ * n/a
+ * Returns:
+ * n/a
+ * Requires:
+ * CMM is initialized.
+ * Ensures:
+ */
+extern void cmm_exit(void);
+
+/*
+ * ======== cmm_free_buf ========
+ * Purpose:
+ * Free the given buffer.
+ * Parameters:
+ * hcmm_mgr: Cmm Mgr handle.
+ * pbuf: Pointer to memory allocated by cmm_calloc_buf().
+ * ul_seg_id: SM segment Id used in CMM_Calloc() attrs.
+ * Set to 0 to use default segment.
+ * Returns:
+ * 0
+ * -EPERM
+ * Requires:
+ * CMM initialized.
+ * buf_pa != NULL
+ * Ensures:
+ *
+ */
+extern int cmm_free_buf(struct cmm_object *hcmm_mgr,
+ void *buf_pa, u32 ul_seg_id);
+
+/*
+ * ======== cmm_get_handle ========
+ * Purpose:
+ * Return the handle to the cmm mgr for the given device obj.
+ * Parameters:
+ * hprocessor: Handle to a Processor.
+ * ph_cmm_mgr: Location to store the shared memory mgr handle on
+ * output.
+ *
+ * Returns:
+ * 0: Cmm Mgr opaque handle returned.
+ * -EFAULT: Invalid handle.
+ * Requires:
+ * ph_cmm_mgr != NULL
+ * hdev_obj != NULL
+ * Ensures:
+ */
+extern int cmm_get_handle(void *hprocessor,
+ struct cmm_object **ph_cmm_mgr);
+
+/*
+ * ======== cmm_get_info ========
+ * Purpose:
+ * Return the current SM and VM utilization information.
+ * Parameters:
+ * hcmm_mgr: Handle to a Cmm Mgr.
+ * cmm_info_obj: Location to store the Cmm information on output.
+ *
+ * Returns:
+ * 0: Success.
+ * -EFAULT: Invalid handle.
+ * -EINVAL Invalid input argument.
+ * Requires:
+ * Ensures:
+ *
+ */
+extern int cmm_get_info(struct cmm_object *hcmm_mgr,
+ struct cmm_info *cmm_info_obj);
+
+/*
+ * ======== cmm_init ========
+ * Purpose:
+ * Initializes private state of CMM module.
+ * Parameters:
+ * Returns:
+ * TRUE if initialized; FALSE if error occured.
+ * Requires:
+ * Ensures:
+ * CMM initialized.
+ */
+extern bool cmm_init(void);
+
+/*
+ * ======== cmm_register_gppsm_seg ========
+ * Purpose:
+ * Register a block of SM with the CMM.
+ * Parameters:
+ * hcmm_mgr: Handle to a Cmm Mgr.
+ * lpGPPBasePA: GPP Base Physical address.
+ * ul_size: Size in GPP bytes.
+ * dsp_addr_offset GPP PA to DSP PA Offset.
+ * c_factor: Add offset if CMM_ADDTODSPPA, sub if CMM_SUBFROMDSPPA.
+ * dw_dsp_base: DSP virtual base byte address.
+ * ul_dsp_size: Size of DSP segment in bytes.
+ * sgmt_id: Address to store segment Id.
+ *
+ * Returns:
+ * 0: Success.
+ * -EFAULT: Invalid hcmm_mgr handle.
+ * -EINVAL: Invalid input argument.
+ * -EPERM: Unable to register.
+ * - On success *sgmt_id is a valid SM segment ID.
+ * Requires:
+ * ul_size > 0
+ * sgmt_id != NULL
+ * dw_gpp_base_pa != 0
+ * c_factor = CMM_ADDTODSPPA || c_factor = CMM_SUBFROMDSPPA
+ * Ensures:
+ *
+ */
+extern int cmm_register_gppsm_seg(struct cmm_object *hcmm_mgr,
+ unsigned int dw_gpp_base_pa,
+ u32 ul_size,
+ u32 dsp_addr_offset,
+ s8 c_factor,
+ unsigned int dw_dsp_base,
+ u32 ul_dsp_size,
+ u32 *sgmt_id, u32 gpp_base_va);
+
+/*
+ * ======== cmm_un_register_gppsm_seg ========
+ * Purpose:
+ * Unregister the given memory segment that was previously registered
+ * by cmm_register_gppsm_seg.
+ * Parameters:
+ * hcmm_mgr: Handle to a Cmm Mgr.
+ * ul_seg_id Segment identifier returned by cmm_register_gppsm_seg.
+ * Returns:
+ * 0: Success.
+ * -EFAULT: Invalid handle.
+ * -EINVAL: Invalid ul_seg_id.
+ * -EPERM: Unable to unregister for unknown reason.
+ * Requires:
+ * Ensures:
+ *
+ */
+extern int cmm_un_register_gppsm_seg(struct cmm_object *hcmm_mgr,
+ u32 ul_seg_id);
+
+/*
+ * ======== cmm_xlator_alloc_buf ========
+ * Purpose:
+ * Allocate the specified SM buffer and create a local memory descriptor.
+ * Place on the descriptor on the translator's HaQ (Host Alloc'd Queue).
+ * Parameters:
+ * xlator: Handle to a Xlator object.
+ * va_buf: Virtual address ptr(client context)
+ * pa_size: Size of SM memory to allocate.
+ * Returns:
+ * Ptr to valid physical address(Pa) of pa_size bytes, NULL if failed.
+ * Requires:
+ * va_buf != 0.
+ * pa_size != 0.
+ * Ensures:
+ *
+ */
+extern void *cmm_xlator_alloc_buf(struct cmm_xlatorobject *xlator,
+ void *va_buf, u32 pa_size);
+
+/*
+ * ======== cmm_xlator_create ========
+ * Purpose:
+ * Create a translator(xlator) object used for process specific Va<->Pa
+ * address translation. Node messaging and streams use this to perform
+ * inter-processor(GPP<->DSP) zero-copy data transfer.
+ * Parameters:
+ * xlator: Address to place handle to a new Xlator handle.
+ * hcmm_mgr: Handle to Cmm Mgr associated with this translator.
+ * xlator_attrs: Translator attributes used for the client NODE or STREAM.
+ * Returns:
+ * 0: Success.
+ * -EINVAL: Bad input Attrs.
+ * -ENOMEM: Insufficient memory(local) for requested resources.
+ * Requires:
+ * xlator != NULL
+ * hcmm_mgr != NULL
+ * xlator_attrs != NULL
+ * Ensures:
+ *
+ */
+extern int cmm_xlator_create(struct cmm_xlatorobject **xlator,
+ struct cmm_object *hcmm_mgr,
+ struct cmm_xlatorattrs *xlator_attrs);
+
+/*
+ * ======== cmm_xlator_delete ========
+ * Purpose:
+ * Delete translator resources
+ * Parameters:
+ * xlator: handle to translator.
+ * force: force = TRUE will free XLators SM buffers/dscriptrs.
+ * Returns:
+ * 0: Success.
+ * -EFAULT: Bad translator handle.
+ * -EPERM: Unable to free translator resources.
+ * Requires:
+ * refs > 0
+ * Ensures:
+ *
+ */
+extern int cmm_xlator_delete(struct cmm_xlatorobject *xlator,
+ bool force);
+
+/*
+ * ======== cmm_xlator_free_buf ========
+ * Purpose:
+ * Free SM buffer and descriptor.
+ * Does not free client process VM.
+ * Parameters:
+ * xlator: handle to translator.
+ * buf_va Virtual address of PA to free.
+ * Returns:
+ * 0: Success.
+ * -EFAULT: Bad translator handle.
+ * Requires:
+ * Ensures:
+ *
+ */
+extern int cmm_xlator_free_buf(struct cmm_xlatorobject *xlator,
+ void *buf_va);
+
+/*
+ * ======== cmm_xlator_info ========
+ * Purpose:
+ * Set/Get process specific "translator" address info.
+ * This is used to perform fast virtaul address translation
+ * for shared memory buffers between the GPP and DSP.
+ * Parameters:
+ * xlator: handle to translator.
+ * paddr: Virtual base address of segment.
+ * ul_size: Size in bytes.
+ * segm_id: Segment identifier of SM segment(s)
+ * set_info Set xlator fields if TRUE, else return base addr
+ * Returns:
+ * 0: Success.
+ * -EFAULT: Bad translator handle.
+ * Requires:
+ * (refs > 0)
+ * (paddr != NULL)
+ * (ul_size > 0)
+ * Ensures:
+ *
+ */
+extern int cmm_xlator_info(struct cmm_xlatorobject *xlator,
+ u8 **paddr,
+ u32 ul_size, u32 segm_id, bool set_info);
+
+/*
+ * ======== cmm_xlator_translate ========
+ * Purpose:
+ * Perform address translation VA<->PA for the specified stream or
+ * message shared memory buffer.
+ * Parameters:
+ * xlator: handle to translator.
+ * paddr address of buffer to translate.
+ * xtype Type of address xlation. CMM_PA2VA or CMM_VA2PA.
+ * Returns:
+ * Valid address on success, else NULL.
+ * Requires:
+ * refs > 0
+ * paddr != NULL
+ * xtype >= CMM_VA2PA) && (xtype <= CMM_DSPPA2PA)
+ * Ensures:
+ *
+ */
+extern void *cmm_xlator_translate(struct cmm_xlatorobject *xlator,
+ void *paddr, enum cmm_xlatetype xtype);
+
+#endif /* CMM_ */
diff --git a/drivers/staging/tidspbridge/include/dspbridge/cmmdefs.h b/drivers/staging/tidspbridge/include/dspbridge/cmmdefs.h
new file mode 100644
index 00000000000..fbff372d2f5
--- /dev/null
+++ b/drivers/staging/tidspbridge/include/dspbridge/cmmdefs.h
@@ -0,0 +1,105 @@
+/*
+ * cmmdefs.h
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * Global MEM constants and types.
+ *
+ * Copyright (C) 2008 Texas Instruments, Inc.
+ *
+ * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef CMMDEFS_
+#define CMMDEFS_
+
+#include <dspbridge/list.h>
+
+/* Cmm attributes used in cmm_create() */
+struct cmm_mgrattrs {
+ /* Minimum SM allocation; default 32 bytes. */
+ u32 ul_min_block_size;
+};
+
+/* Attributes for CMM_AllocBuf() & CMM_AllocDesc() */
+struct cmm_attrs {
+ u32 ul_seg_id; /* 1,2... are SM segments. 0 is not. */
+ u32 ul_alignment; /* 0,1,2,4....ul_min_block_size */
+};
+
+/*
+ * DSPPa to GPPPa Conversion Factor.
+ *
+ * For typical platforms:
+ * converted Address = PaDSP + ( c_factor * addressToConvert).
+ */
+#define CMM_SUBFROMDSPPA -1
+#define CMM_ADDTODSPPA 1
+
+#define CMM_ALLSEGMENTS 0xFFFFFF /* All SegIds */
+#define CMM_MAXGPPSEGS 1 /* Maximum # of SM segs */
+
+/*
+ * SMSEGs are SM segments the DSP allocates from.
+ *
+ * This info is used by the GPP to xlate DSP allocated PAs.
+ */
+
+struct cmm_seginfo {
+ u32 dw_seg_base_pa; /* Start Phys address of SM segment */
+ /* Total size in bytes of segment: DSP+GPP */
+ u32 ul_total_seg_size;
+ u32 dw_gpp_base_pa; /* Start Phys addr of Gpp SM seg */
+ u32 ul_gpp_size; /* Size of Gpp SM seg in bytes */
+ u32 dw_dsp_base_va; /* DSP virt base byte address */
+ u32 ul_dsp_size; /* DSP seg size in bytes */
+ /* # of current GPP allocations from this segment */
+ u32 ul_in_use_cnt;
+ u32 dw_seg_base_va; /* Start Virt address of SM seg */
+
+};
+
+/* CMM useful information */
+struct cmm_info {
+ /* # of SM segments registered with this Cmm. */
+ u32 ul_num_gppsm_segs;
+ /* Total # of allocations outstanding for CMM */
+ u32 ul_total_in_use_cnt;
+ /* Min SM block size allocation from cmm_create() */
+ u32 ul_min_block_size;
+ /* Info per registered SM segment. */
+ struct cmm_seginfo seg_info[CMM_MAXGPPSEGS];
+};
+
+/* XlatorCreate attributes */
+struct cmm_xlatorattrs {
+ u32 ul_seg_id; /* segment Id used for SM allocations */
+ u32 dw_dsp_bufs; /* # of DSP-side bufs */
+ u32 dw_dsp_buf_size; /* size of DSP-side bufs in GPP bytes */
+ /* Vm base address alloc'd in client process context */
+ void *vm_base;
+ /* dw_vm_size must be >= (dwMaxNumBufs * dwMaxSize) */
+ u32 dw_vm_size;
+};
+
+/*
+ * Cmm translation types. Use to map SM addresses to process context.
+ */
+enum cmm_xlatetype {
+ CMM_VA2PA = 0, /* Virtual to GPP physical address xlation */
+ CMM_PA2VA = 1, /* GPP Physical to virtual */
+ CMM_VA2DSPPA = 2, /* Va to DSP Pa */
+ CMM_PA2DSPPA = 3, /* GPP Pa to DSP Pa */
+ CMM_DSPPA2PA = 4, /* DSP Pa to GPP Pa */
+};
+
+struct cmm_object;
+struct cmm_xlatorobject;
+
+#endif /* CMMDEFS_ */
diff --git a/drivers/staging/tidspbridge/include/dspbridge/cod.h b/drivers/staging/tidspbridge/include/dspbridge/cod.h
new file mode 100644
index 00000000000..42bce2eec80
--- /dev/null
+++ b/drivers/staging/tidspbridge/include/dspbridge/cod.h
@@ -0,0 +1,369 @@
+/*
+ * cod.h
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * Code management module for DSPs. This module provides an interface
+ * interface for loading both static and dynamic code objects onto DSP
+ * systems.
+ *
+ * Copyright (C) 2005-2006 Texas Instruments, Inc.
+ *
+ * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef COD_
+#define COD_
+
+#include <dspbridge/dblldefs.h>
+
+#define COD_MAXPATHLENGTH 255
+#define COD_TRACEBEG "SYS_PUTCBEG"
+#define COD_TRACEEND "SYS_PUTCEND"
+#define COD_TRACECURPOS "BRIDGE_SYS_PUTC_current"
+#define COD_TRACESECT "trace"
+#define COD_TRACEBEGOLD "PUTCBEG"
+#define COD_TRACEENDOLD "PUTCEND"
+
+#define COD_NOLOAD DBLL_NOLOAD
+#define COD_SYMB DBLL_SYMB
+
+/* COD code manager handle */
+struct cod_manager;
+
+/* COD library handle */
+struct cod_libraryobj;
+
+/* COD attributes */
+struct cod_attrs {
+ u32 ul_reserved;
+};
+
+/*
+ * Function prototypes for writing memory to a DSP system, allocating
+ * and freeing DSP memory.
+ */
+typedef u32(*cod_writefxn) (void *priv_ref, u32 dsp_add,
+ void *pbuf, u32 ul_num_bytes, u32 mem_space);
+
+/*
+ * ======== cod_close ========
+ * Purpose:
+ * Close a library opened with cod_open().
+ * Parameters:
+ * lib - Library handle returned by cod_open().
+ * Returns:
+ * None.
+ * Requires:
+ * COD module initialized.
+ * valid lib.
+ * Ensures:
+ *
+ */
+extern void cod_close(struct cod_libraryobj *lib);
+
+/*
+ * ======== cod_create ========
+ * Purpose:
+ * Create an object to manage code on a DSP system. This object can be
+ * used to load an initial program image with arguments that can later
+ * be expanded with dynamically loaded object files.
+ * Symbol table information is managed by this object and can be retrieved
+ * using the cod_get_sym_value() function.
+ * Parameters:
+ * manager: created manager object
+ * str_zl_file: ZL DLL filename, of length < COD_MAXPATHLENGTH.
+ * attrs: attributes to be used by this object. A NULL value
+ * will cause default attrs to be used.
+ * Returns:
+ * 0: Success.
+ * -ESPIPE: ZL_Create failed.
+ * -ENOSYS: attrs was not NULL. We don't yet support
+ * non default values of attrs.
+ * Requires:
+ * COD module initialized.
+ * str_zl_file != NULL
+ * Ensures:
+ */
+extern int cod_create(struct cod_manager **mgr,
+ char *str_zl_file,
+ const struct cod_attrs *attrs);
+
+/*
+ * ======== cod_delete ========
+ * Purpose:
+ * Delete a code manager object.
+ * Parameters:
+ * cod_mgr_obj: handle of manager to be deleted
+ * Returns:
+ * None.
+ * Requires:
+ * COD module initialized.
+ * valid cod_mgr_obj.
+ * Ensures:
+ */
+extern void cod_delete(struct cod_manager *cod_mgr_obj);
+
+/*
+ * ======== cod_exit ========
+ * Purpose:
+ * Discontinue usage of the COD module.
+ * Parameters:
+ * None.
+ * Returns:
+ * None.
+ * Requires:
+ * COD initialized.
+ * Ensures:
+ * Resources acquired in cod_init(void) are freed.
+ */
+extern void cod_exit(void);
+
+/*
+ * ======== cod_get_base_lib ========
+ * Purpose:
+ * Get handle to the base image DBL library.
+ * Parameters:
+ * cod_mgr_obj: handle of manager to be deleted
+ * plib: location to store library handle on output.
+ * Returns:
+ * 0: Success.
+ * Requires:
+ * COD module initialized.
+ * valid cod_mgr_obj.
+ * plib != NULL.
+ * Ensures:
+ */
+extern int cod_get_base_lib(struct cod_manager *cod_mgr_obj,
+ struct dbll_library_obj **plib);
+
+/*
+ * ======== cod_get_base_name ========
+ * Purpose:
+ * Get the name of the base image DBL library.
+ * Parameters:
+ * cod_mgr_obj: handle of manager to be deleted
+ * sz_name: location to store library name on output.
+ * usize: size of name buffer.
+ * Returns:
+ * 0: Success.
+ * -EPERM: Buffer too small.
+ * Requires:
+ * COD module initialized.
+ * valid cod_mgr_obj.
+ * sz_name != NULL.
+ * Ensures:
+ */
+extern int cod_get_base_name(struct cod_manager *cod_mgr_obj,
+ char *sz_name, u32 usize);
+
+/*
+ * ======== cod_get_entry ========
+ * Purpose:
+ * Retrieve the entry point of a loaded DSP program image
+ * Parameters:
+ * cod_mgr_obj: handle of manager to be deleted
+ * entry_pt: pointer to location for entry point
+ * Returns:
+ * 0: Success.
+ * Requires:
+ * COD module initialized.
+ * valid cod_mgr_obj.
+ * entry_pt != NULL.
+ * Ensures:
+ */
+extern int cod_get_entry(struct cod_manager *cod_mgr_obj,
+ u32 *entry_pt);
+
+/*
+ * ======== cod_get_loader ========
+ * Purpose:
+ * Get handle to the DBL loader.
+ * Parameters:
+ * cod_mgr_obj: handle of manager to be deleted
+ * loader: location to store loader handle on output.
+ * Returns:
+ * 0: Success.
+ * Requires:
+ * COD module initialized.
+ * valid cod_mgr_obj.
+ * loader != NULL.
+ * Ensures:
+ */
+extern int cod_get_loader(struct cod_manager *cod_mgr_obj,
+ struct dbll_tar_obj **loader);
+
+/*
+ * ======== cod_get_section ========
+ * Purpose:
+ * Retrieve the starting address and length of a section in the COFF file
+ * given the section name.
+ * Parameters:
+ * lib Library handle returned from cod_open().
+ * str_sect: name of the section, with or without leading "."
+ * addr: Location to store address.
+ * len: Location to store length.
+ * Returns:
+ * 0: Success
+ * -ESPIPE: Symbols could not be found or have not been loaded onto
+ * the board.
+ * Requires:
+ * COD module initialized.
+ * valid cod_mgr_obj.
+ * str_sect != NULL;
+ * addr != NULL;
+ * len != NULL;
+ * Ensures:
+ * 0: *addr and *len contain the address and length of the
+ * section.
+ * else: *addr == 0 and *len == 0;
+ *
+ */
+extern int cod_get_section(struct cod_libraryobj *lib,
+ char *str_sect,
+ u32 *addr, u32 *len);
+
+/*
+ * ======== cod_get_sym_value ========
+ * Purpose:
+ * Retrieve the value for the specified symbol. The symbol is first
+ * searched for literally and then, if not found, searched for as a
+ * C symbol.
+ * Parameters:
+ * lib: library handle returned from cod_open().
+ * pstrSymbol: name of the symbol
+ * value: value of the symbol
+ * Returns:
+ * 0: Success.
+ * -ESPIPE: Symbols could not be found or have not been loaded onto
+ * the board.
+ * Requires:
+ * COD module initialized.
+ * Valid cod_mgr_obj.
+ * str_sym != NULL.
+ * pul_value != NULL.
+ * Ensures:
+ */
+extern int cod_get_sym_value(struct cod_manager *cod_mgr_obj,
+ char *str_sym, u32 * pul_value);
+
+/*
+ * ======== cod_init ========
+ * Purpose:
+ * Initialize the COD module's private state.
+ * Parameters:
+ * None.
+ * Returns:
+ * TRUE if initialized; FALSE if error occured.
+ * Requires:
+ * Ensures:
+ * A requirement for each of the other public COD functions.
+ */
+extern bool cod_init(void);
+
+/*
+ * ======== cod_load_base ========
+ * Purpose:
+ * Load the initial program image, optionally with command-line arguments,
+ * on the DSP system managed by the supplied handle. The program to be
+ * loaded must be the first element of the args array and must be a fully
+ * qualified pathname.
+ * Parameters:
+ * hmgr: manager to load the code with
+ * num_argc: number of arguments in the args array
+ * args: array of strings for arguments to DSP program
+ * write_fxn: board-specific function to write data to DSP system
+ * arb: arbitrary pointer to be passed as first arg to write_fxn
+ * envp: array of environment strings for DSP exec.
+ * Returns:
+ * 0: Success.
+ * -EBADF: Failed to open target code.
+ * Requires:
+ * COD module initialized.
+ * hmgr is valid.
+ * num_argc > 0.
+ * args != NULL.
+ * args[0] != NULL.
+ * pfn_write != NULL.
+ * Ensures:
+ */
+extern int cod_load_base(struct cod_manager *cod_mgr_obj,
+ u32 num_argc, char *args[],
+ cod_writefxn pfn_write, void *arb,
+ char *envp[]);
+
+/*
+ * ======== cod_open ========
+ * Purpose:
+ * Open a library for reading sections. Does not load or set the base.
+ * Parameters:
+ * hmgr: manager to load the code with
+ * sz_coff_path: Coff file to open.
+ * flags: COD_NOLOAD (don't load symbols) or COD_SYMB (load
+ * symbols).
+ * lib_obj: Handle returned that can be used in calls to cod_close
+ * and cod_get_section.
+ * Returns:
+ * S_OK: Success.
+ * -EBADF: Failed to open target code.
+ * Requires:
+ * COD module initialized.
+ * hmgr is valid.
+ * flags == COD_NOLOAD || flags == COD_SYMB.
+ * sz_coff_path != NULL.
+ * Ensures:
+ */
+extern int cod_open(struct cod_manager *hmgr,
+ char *sz_coff_path,
+ u32 flags, struct cod_libraryobj **lib_obj);
+
+/*
+ * ======== cod_open_base ========
+ * Purpose:
+ * Open base image for reading sections. Does not load the base.
+ * Parameters:
+ * hmgr: manager to load the code with
+ * sz_coff_path: Coff file to open.
+ * flags: Specifies whether to load symbols.
+ * Returns:
+ * 0: Success.
+ * -EBADF: Failed to open target code.
+ * Requires:
+ * COD module initialized.
+ * hmgr is valid.
+ * sz_coff_path != NULL.
+ * Ensures:
+ */
+extern int cod_open_base(struct cod_manager *hmgr, char *sz_coff_path,
+ dbll_flags flags);
+
+/*
+ * ======== cod_read_section ========
+ * Purpose:
+ * Retrieve the content of a code section given the section name.
+ * Parameters:
+ * cod_mgr_obj - manager in which to search for the symbol
+ * str_sect - name of the section, with or without leading "."
+ * str_content - buffer to store content of the section.
+ * Returns:
+ * 0: on success, error code on failure
+ * -ESPIPE: Symbols have not been loaded onto the board.
+ * Requires:
+ * COD module initialized.
+ * valid cod_mgr_obj.
+ * str_sect != NULL;
+ * str_content != NULL;
+ * Ensures:
+ * 0: *str_content stores the content of the named section.
+ */
+extern int cod_read_section(struct cod_libraryobj *lib,
+ char *str_sect,
+ char *str_content, u32 content_size);
+
+#endif /* COD_ */
diff --git a/drivers/staging/tidspbridge/include/dspbridge/dbc.h b/drivers/staging/tidspbridge/include/dspbridge/dbc.h
new file mode 100644
index 00000000000..463760f499a
--- /dev/null
+++ b/drivers/staging/tidspbridge/include/dspbridge/dbc.h
@@ -0,0 +1,46 @@
+/*
+ * dbc.h
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * "Design by Contract" programming macros.
+ *
+ * Notes:
+ * Requires that the GT->ERROR function has been defaulted to a valid
+ * error handler for the given execution environment.
+ *
+ * Does not require that GT_init() be called.
+ *
+ * Copyright (C) 2008 Texas Instruments, Inc.
+ *
+ * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef DBC_
+#define DBC_
+
+/* Assertion Macros: */
+#ifdef CONFIG_TIDSPBRIDGE_DEBUG
+
+#define DBC_ASSERT(exp) \
+ if (!(exp)) \
+ pr_err("%s, line %d: Assertion (" #exp ") failed.\n", \
+ __FILE__, __LINE__)
+#define DBC_REQUIRE DBC_ASSERT /* Function Precondition. */
+#define DBC_ENSURE DBC_ASSERT /* Function Postcondition. */
+
+#else
+
+#define DBC_ASSERT(exp) {}
+#define DBC_REQUIRE(exp) {}
+#define DBC_ENSURE(exp) {}
+
+#endif /* DEBUG */
+
+#endif /* DBC_ */
diff --git a/drivers/staging/tidspbridge/include/dspbridge/dbdcd.h b/drivers/staging/tidspbridge/include/dspbridge/dbdcd.h
new file mode 100644
index 00000000000..7cc3e12686e
--- /dev/null
+++ b/drivers/staging/tidspbridge/include/dspbridge/dbdcd.h
@@ -0,0 +1,358 @@
+/*
+ * dbdcd.h
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * Defines the DSP/BIOS Bridge Configuration Database (DCD) API.
+ *
+ * Copyright (C) 2008 Texas Instruments, Inc.
+ *
+ * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef DBDCD_
+#define DBDCD_
+
+#include <dspbridge/dbdcddef.h>
+#include <dspbridge/host_os.h>
+#include <dspbridge/nldrdefs.h>
+
+/*
+ * ======== dcd_auto_register ========
+ * Purpose:
+ * This function automatically registers DCD objects specified in a
+ * special COFF section called ".dcd_register"
+ * Parameters:
+ * hdcd_mgr: A DCD manager handle.
+ * sz_coff_path: Pointer to name of COFF file containing DCD
+ * objects to be registered.
+ * Returns:
+ * 0: Success.
+ * -EACCES: Unable to find auto-registration/read/load section.
+ * -EFAULT: Invalid DCD_HMANAGER handle..
+ * Requires:
+ * DCD initialized.
+ * Ensures:
+ * Note:
+ * Due to the DCD database construction, it is essential for a DCD-enabled
+ * COFF file to contain the right COFF sections, especially
+ * ".dcd_register", which is used for auto registration.
+ */
+extern int dcd_auto_register(struct dcd_manager *hdcd_mgr,
+ char *sz_coff_path);
+
+/*
+ * ======== dcd_auto_unregister ========
+ * Purpose:
+ * This function automatically unregisters DCD objects specified in a
+ * special COFF section called ".dcd_register"
+ * Parameters:
+ * hdcd_mgr: A DCD manager handle.
+ * sz_coff_path: Pointer to name of COFF file containing
+ * DCD objects to be unregistered.
+ * Returns:
+ * 0: Success.
+ * -EACCES: Unable to find auto-registration/read/load section.
+ * -EFAULT: Invalid DCD_HMANAGER handle..
+ * Requires:
+ * DCD initialized.
+ * Ensures:
+ * Note:
+ * Due to the DCD database construction, it is essential for a DCD-enabled
+ * COFF file to contain the right COFF sections, especially
+ * ".dcd_register", which is used for auto unregistration.
+ */
+extern int dcd_auto_unregister(struct dcd_manager *hdcd_mgr,
+ char *sz_coff_path);
+
+/*
+ * ======== dcd_create_manager ========
+ * Purpose:
+ * This function creates a DCD module manager.
+ * Parameters:
+ * sz_zl_dll_name: Pointer to a DLL name string.
+ * dcd_mgr: A pointer to a DCD manager handle.
+ * Returns:
+ * 0: Success.
+ * -ENOMEM: Unable to allocate memory for DCD manager handle.
+ * -EPERM: General failure.
+ * Requires:
+ * DCD initialized.
+ * sz_zl_dll_name is non-NULL.
+ * dcd_mgr is non-NULL.
+ * Ensures:
+ * A DCD manager handle is created.
+ */
+extern int dcd_create_manager(char *sz_zl_dll_name,
+ struct dcd_manager **dcd_mgr);
+
+/*
+ * ======== dcd_destroy_manager ========
+ * Purpose:
+ * This function destroys a DCD module manager.
+ * Parameters:
+ * hdcd_mgr: A DCD manager handle.
+ * Returns:
+ * 0: Success.
+ * -EFAULT: Invalid DCD manager handle.
+ * Requires:
+ * DCD initialized.
+ * Ensures:
+ */
+extern int dcd_destroy_manager(struct dcd_manager *hdcd_mgr);
+
+/*
+ * ======== dcd_enumerate_object ========
+ * Purpose:
+ * This function enumerates currently visible DSP/BIOS Bridge objects
+ * and returns the UUID and type of each enumerated object.
+ * Parameters:
+ * index: The object enumeration index.
+ * obj_type: Type of object to enumerate.
+ * uuid_obj: Pointer to a dsp_uuid object.
+ * Returns:
+ * 0: Success.
+ * -EPERM: Unable to enumerate through the DCD database.
+ * ENODATA: Enumeration completed. This is not an error code.
+ * Requires:
+ * DCD initialized.
+ * uuid_obj is a valid pointer.
+ * Ensures:
+ * Details:
+ * This function can be used in conjunction with dcd_get_object_def to
+ * retrieve object properties.
+ */
+extern int dcd_enumerate_object(s32 index,
+ enum dsp_dcdobjtype obj_type,
+ struct dsp_uuid *uuid_obj);
+
+/*
+ * ======== dcd_exit ========
+ * Purpose:
+ * This function cleans up the DCD module.
+ * Parameters:
+ * Returns:
+ * Requires:
+ * DCD initialized.
+ * Ensures:
+ */
+extern void dcd_exit(void);
+
+/*
+ * ======== dcd_get_dep_libs ========
+ * Purpose:
+ * Given the uuid of a library and size of array of uuids, this function
+ * fills the array with the uuids of all dependent libraries of the input
+ * library.
+ * Parameters:
+ * hdcd_mgr: A DCD manager handle.
+ * uuid_obj: Pointer to a dsp_uuid for a library.
+ * num_libs: Size of uuid array (number of library uuids).
+ * dep_lib_uuids: Array of dependent library uuids to be filled in.
+ * prstnt_dep_libs: Array indicating if corresponding lib is persistent.
+ * phase: phase to obtain correct input library
+ * Returns:
+ * 0: Success.
+ * -ENOMEM: Memory allocation failure.
+ * -EACCES: Failure to read section containing library info.
+ * -EPERM: General failure.
+ * Requires:
+ * DCD initialized.
+ * Valid hdcd_mgr.
+ * uuid_obj != NULL
+ * dep_lib_uuids != NULL.
+ * Ensures:
+ */
+extern int dcd_get_dep_libs(struct dcd_manager *hdcd_mgr,
+ struct dsp_uuid *uuid_obj,
+ u16 num_libs,
+ struct dsp_uuid *dep_lib_uuids,
+ bool *prstnt_dep_libs,
+ enum nldr_phase phase);
+
+/*
+ * ======== dcd_get_num_dep_libs ========
+ * Purpose:
+ * Given the uuid of a library, determine its number of dependent
+ * libraries.
+ * Parameters:
+ * hdcd_mgr: A DCD manager handle.
+ * uuid_obj: Pointer to a dsp_uuid for a library.
+ * num_libs: Size of uuid array (number of library uuids).
+ * num_pers_libs: number of persistent dependent library.
+ * phase: Phase to obtain correct input library
+ * Returns:
+ * 0: Success.
+ * -ENOMEM: Memory allocation failure.
+ * -EACCES: Failure to read section containing library info.
+ * -EPERM: General failure.
+ * Requires:
+ * DCD initialized.
+ * Valid hdcd_mgr.
+ * uuid_obj != NULL
+ * num_libs != NULL.
+ * Ensures:
+ */
+extern int dcd_get_num_dep_libs(struct dcd_manager *hdcd_mgr,
+ struct dsp_uuid *uuid_obj,
+ u16 *num_libs,
+ u16 *num_pers_libs,
+ enum nldr_phase phase);
+
+/*
+ * ======== dcd_get_library_name ========
+ * Purpose:
+ * This function returns the name of a (dynamic) library for a given
+ * UUID.
+ * Parameters:
+ * hdcd_mgr: A DCD manager handle.
+ * uuid_obj: Pointer to a dsp_uuid that represents a unique DSP/BIOS
+ * Bridge object.
+ * str_lib_name: Buffer to hold library name.
+ * buff_size: Contains buffer size. Set to string size on output.
+ * phase: Which phase to load
+ * phase_split: Are phases in multiple libraries
+ * Returns:
+ * 0: Success.
+ * -EPERM: General failure.
+ * Requires:
+ * DCD initialized.
+ * Valid hdcd_mgr.
+ * str_lib_name != NULL.
+ * uuid_obj != NULL
+ * buff_size != NULL.
+ * Ensures:
+ */
+extern int dcd_get_library_name(struct dcd_manager *hdcd_mgr,
+ struct dsp_uuid *uuid_obj,
+ char *str_lib_name,
+ u32 *buff_size,
+ enum nldr_phase phase,
+ bool *phase_split);
+
+/*
+ * ======== dcd_get_object_def ========
+ * Purpose:
+ * This function returns the properties/attributes of a DSP/BIOS Bridge
+ * object.
+ * Parameters:
+ * hdcd_mgr: A DCD manager handle.
+ * uuid_obj: Pointer to a dsp_uuid that represents a unique
+ * DSP/BIOS Bridge object.
+ * obj_type: The type of DSP/BIOS Bridge object to be
+ * referenced (node, processor, etc).
+ * obj_def: Pointer to an object definition structure. A
+ * union of various possible DCD object types.
+ * Returns:
+ * 0: Success.
+ * -EACCES: Unable to access/read/parse/load content of object code
+ * section.
+ * -EPERM: General failure.
+ * -EFAULT: Invalid DCD_HMANAGER handle.
+ * Requires:
+ * DCD initialized.
+ * obj_uuid is non-NULL.
+ * obj_def is non-NULL.
+ * Ensures:
+ */
+extern int dcd_get_object_def(struct dcd_manager *hdcd_mgr,
+ struct dsp_uuid *obj_uuid,
+ enum dsp_dcdobjtype obj_type,
+ struct dcd_genericobj *obj_def);
+
+/*
+ * ======== dcd_get_objects ========
+ * Purpose:
+ * This function finds all DCD objects specified in a special
+ * COFF section called ".dcd_register", and for each object,
+ * call a "register" function. The "register" function may perform
+ * various actions, such as 1) register nodes in the node database, 2)
+ * unregister nodes from the node database, and 3) add overlay nodes.
+ * Parameters:
+ * hdcd_mgr: A DCD manager handle.
+ * sz_coff_path: Pointer to name of COFF file containing DCD
+ * objects.
+ * register_fxn: Callback fxn to be applied on each located
+ * DCD object.
+ * handle: Handle to pass to callback.
+ * Returns:
+ * 0: Success.
+ * -EACCES: Unable to access/read/parse/load content of object code
+ * section.
+ * -EFAULT: Invalid DCD_HMANAGER handle..
+ * Requires:
+ * DCD initialized.
+ * Ensures:
+ * Note:
+ * Due to the DCD database construction, it is essential for a DCD-enabled
+ * COFF file to contain the right COFF sections, especially
+ * ".dcd_register", which is used for auto registration.
+ */
+extern int dcd_get_objects(struct dcd_manager *hdcd_mgr,
+ char *sz_coff_path,
+ dcd_registerfxn register_fxn, void *handle);
+
+/*
+ * ======== dcd_init ========
+ * Purpose:
+ * This function initializes DCD.
+ * Parameters:
+ * Returns:
+ * FALSE: Initialization failed.
+ * TRUE: Initialization succeeded.
+ * Requires:
+ * Ensures:
+ * DCD initialized.
+ */
+extern bool dcd_init(void);
+
+/*
+ * ======== dcd_register_object ========
+ * Purpose:
+ * This function registers a DSP/BIOS Bridge object in the DCD database.
+ * Parameters:
+ * uuid_obj: Pointer to a dsp_uuid that identifies a DSP/BIOS
+ * Bridge object.
+ * obj_type: Type of object.
+ * psz_path_name: Path to the object's COFF file.
+ * Returns:
+ * 0: Success.
+ * -EPERM: Failed to register object.
+ * Requires:
+ * DCD initialized.
+ * uuid_obj and szPathName are non-NULL values.
+ * obj_type is a valid type value.
+ * Ensures:
+ */
+extern int dcd_register_object(struct dsp_uuid *uuid_obj,
+ enum dsp_dcdobjtype obj_type,
+ char *psz_path_name);
+
+/*
+ * ======== dcd_unregister_object ========
+ * Purpose:
+ * This function de-registers a valid DSP/BIOS Bridge object from the DCD
+ * database.
+ * Parameters:
+ * uuid_obj: Pointer to a dsp_uuid that identifies a DSP/BIOS Bridge
+ * object.
+ * obj_type: Type of object.
+ * Returns:
+ * 0: Success.
+ * -EPERM: Unable to de-register the specified object.
+ * Requires:
+ * DCD initialized.
+ * uuid_obj is a non-NULL value.
+ * obj_type is a valid type value.
+ * Ensures:
+ */
+extern int dcd_unregister_object(struct dsp_uuid *uuid_obj,
+ enum dsp_dcdobjtype obj_type);
+
+#endif /* _DBDCD_H */
diff --git a/drivers/staging/tidspbridge/include/dspbridge/dbdcddef.h b/drivers/staging/tidspbridge/include/dspbridge/dbdcddef.h
new file mode 100644
index 00000000000..1daa4b57b73
--- /dev/null
+++ b/drivers/staging/tidspbridge/include/dspbridge/dbdcddef.h
@@ -0,0 +1,78 @@
+/*
+ * dbdcddef.h
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * DCD (DSP/BIOS Bridge Configuration Database) constants and types.
+ *
+ * Copyright (C) 2008 Texas Instruments, Inc.
+ *
+ * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef DBDCDDEF_
+#define DBDCDDEF_
+
+#include <dspbridge/dbdefs.h>
+#include <dspbridge/mgrpriv.h> /* for mgr_processorextinfo */
+
+/*
+ * The following defines are critical elements for the DCD module:
+ *
+ * - DCD_REGKEY enables DCD functions to locate registered DCD objects.
+ * - DCD_REGISTER_SECTION identifies the COFF section where the UUID of
+ * registered DCD objects are stored.
+ */
+#define DCD_REGKEY "Software\\TexasInstruments\\DspBridge\\DCD"
+#define DCD_REGISTER_SECTION ".dcd_register"
+
+#define DCD_MAXPATHLENGTH 255
+
+/* DCD Manager Object */
+struct dcd_manager;
+
+struct dcd_key_elem {
+ struct list_head link; /* Make it linked to a list */
+ char name[DCD_MAXPATHLENGTH]; /* Name of a given value entry */
+ char *path; /* Pointer to the actual data */
+};
+
+/* DCD Node Properties */
+struct dcd_nodeprops {
+ struct dsp_ndbprops ndb_props;
+ u32 msg_segid;
+ u32 msg_notify_type;
+ char *pstr_create_phase_fxn;
+ char *pstr_delete_phase_fxn;
+ char *pstr_execute_phase_fxn;
+ char *pstr_i_alg_name;
+
+ /* Dynamic load properties */
+ u16 us_load_type; /* Static, dynamic, overlay */
+ u32 ul_data_mem_seg_mask; /* Data memory requirements */
+ u32 ul_code_mem_seg_mask; /* Code memory requirements */
+};
+
+/* DCD Generic Object Type */
+struct dcd_genericobj {
+ union dcd_obj {
+ struct dcd_nodeprops node_obj; /* node object. */
+ /* processor object. */
+ struct dsp_processorinfo proc_info;
+ /* extended proc object (private) */
+ struct mgr_processorextinfo ext_proc_obj;
+ } obj_data;
+};
+
+/* DCD Internal Callback Type */
+typedef int(*dcd_registerfxn) (struct dsp_uuid *uuid_obj,
+ enum dsp_dcdobjtype obj_type,
+ void *handle);
+
+#endif /* DBDCDDEF_ */
diff --git a/drivers/staging/tidspbridge/include/dspbridge/dbdefs.h b/drivers/staging/tidspbridge/include/dspbridge/dbdefs.h
new file mode 100644
index 00000000000..5af075def87
--- /dev/null
+++ b/drivers/staging/tidspbridge/include/dspbridge/dbdefs.h
@@ -0,0 +1,514 @@
+/*
+ * dbdefs.h
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * Global definitions and constants for DSP/BIOS Bridge.
+ *
+ * Copyright (C) 2005-2006 Texas Instruments, Inc.
+ *
+ * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef DBDEFS_
+#define DBDEFS_
+
+#include <linux/types.h>
+
+#include <dspbridge/rms_sh.h> /* Types shared between GPP and DSP */
+
+#define PG_SIZE4K 4096
+#define PG_MASK(pg_size) (~((pg_size)-1))
+#define PG_ALIGN_LOW(addr, pg_size) ((addr) & PG_MASK(pg_size))
+#define PG_ALIGN_HIGH(addr, pg_size) (((addr)+(pg_size)-1) & PG_MASK(pg_size))
+
+/* API return value and calling convention */
+#define DBAPI int
+
+/* Infinite time value for the utimeout parameter to DSPStream_Select() */
+#define DSP_FOREVER (-1)
+
+/* Maximum length of node name, used in dsp_ndbprops */
+#define DSP_MAXNAMELEN 32
+
+/* notify_type values for the RegisterNotify() functions. */
+#define DSP_SIGNALEVENT 0x00000001
+
+/* Types of events for processors */
+#define DSP_PROCESSORSTATECHANGE 0x00000001
+#define DSP_PROCESSORATTACH 0x00000002
+#define DSP_PROCESSORDETACH 0x00000004
+#define DSP_PROCESSORRESTART 0x00000008
+
+/* DSP exception events (DSP/BIOS and DSP MMU fault) */
+#define DSP_MMUFAULT 0x00000010
+#define DSP_SYSERROR 0x00000020
+#define DSP_EXCEPTIONABORT 0x00000300
+#define DSP_PWRERROR 0x00000080
+#define DSP_WDTOVERFLOW 0x00000040
+
+/* IVA exception events (IVA MMU fault) */
+#define IVA_MMUFAULT 0x00000040
+/* Types of events for nodes */
+#define DSP_NODESTATECHANGE 0x00000100
+#define DSP_NODEMESSAGEREADY 0x00000200
+
+/* Types of events for streams */
+#define DSP_STREAMDONE 0x00001000
+#define DSP_STREAMIOCOMPLETION 0x00002000
+
+/* Handle definition representing the GPP node in DSPNode_Connect() calls */
+#define DSP_HGPPNODE 0xFFFFFFFF
+
+/* Node directions used in DSPNode_Connect() */
+#define DSP_TONODE 1
+#define DSP_FROMNODE 2
+
+/* Define Node Minimum and Maximum Priorities */
+#define DSP_NODE_MIN_PRIORITY 1
+#define DSP_NODE_MAX_PRIORITY 15
+
+/* Pre-Defined Message Command Codes available to user: */
+#define DSP_RMSUSERCODESTART RMS_USER /* Start of RMS user cmd codes */
+/* end of user codes */
+#define DSP_RMSUSERCODEEND (RMS_USER + RMS_MAXUSERCODES);
+/* msg_ctrl contains SM buffer description */
+#define DSP_RMSBUFDESC RMS_BUFDESC
+
+/* Shared memory identifier for MEM segment named "SHMSEG0" */
+#define DSP_SHMSEG0 (u32)(-1)
+
+/* Processor ID numbers */
+#define DSP_UNIT 0
+#define IVA_UNIT 1
+
+#define DSPWORD unsigned char
+#define DSPWORDSIZE sizeof(DSPWORD)
+
+/* Power control enumerations */
+#define PROC_PWRCONTROL 0x8070
+
+#define PROC_PWRMGT_ENABLE (PROC_PWRCONTROL + 0x3)
+#define PROC_PWRMGT_DISABLE (PROC_PWRCONTROL + 0x4)
+
+/* Bridge Code Version */
+#define BRIDGE_VERSION_CODE 333
+
+#define MAX_PROFILES 16
+
+/* DSP chip type */
+#define DSPTYPE64 0x99
+
+/* Handy Macros */
+#define VALID_PROC_EVENT (DSP_PROCESSORSTATECHANGE | DSP_PROCESSORATTACH | \
+ DSP_PROCESSORDETACH | DSP_PROCESSORRESTART | DSP_NODESTATECHANGE | \
+ DSP_STREAMDONE | DSP_STREAMIOCOMPLETION | DSP_MMUFAULT | \
+ DSP_SYSERROR | DSP_WDTOVERFLOW | DSP_PWRERROR)
+
+static inline bool is_valid_proc_event(u32 x)
+{
+ return (x == 0 || (x & VALID_PROC_EVENT && !(x & ~VALID_PROC_EVENT)));
+}
+
+/* The Node UUID structure */
+struct dsp_uuid {
+ u32 ul_data1;
+ u16 us_data2;
+ u16 us_data3;
+ u8 uc_data4;
+ u8 uc_data5;
+ u8 uc_data6[6];
+};
+
+/* DCD types */
+enum dsp_dcdobjtype {
+ DSP_DCDNODETYPE,
+ DSP_DCDPROCESSORTYPE,
+ DSP_DCDLIBRARYTYPE,
+ DSP_DCDCREATELIBTYPE,
+ DSP_DCDEXECUTELIBTYPE,
+ DSP_DCDDELETELIBTYPE,
+ /* DSP_DCDMAXOBJTYPE is meant to be the last DCD object type */
+ DSP_DCDMAXOBJTYPE
+};
+
+/* Processor states */
+enum dsp_procstate {
+ PROC_STOPPED,
+ PROC_LOADED,
+ PROC_RUNNING,
+ PROC_ERROR
+};
+
+/*
+ * Node types: Message node, task node, xDAIS socket node, and
+ * device node. _NODE_GPP is used when defining a stream connection
+ * between a task or socket node and the GPP.
+ *
+ */
+enum node_type {
+ NODE_DEVICE,
+ NODE_TASK,
+ NODE_DAISSOCKET,
+ NODE_MESSAGE,
+ NODE_GPP
+};
+
+/*
+ * ======== node_state ========
+ * Internal node states.
+ */
+enum node_state {
+ NODE_ALLOCATED,
+ NODE_CREATED,
+ NODE_RUNNING,
+ NODE_PAUSED,
+ NODE_DONE,
+ NODE_CREATING,
+ NODE_STARTING,
+ NODE_PAUSING,
+ NODE_TERMINATING,
+ NODE_DELETING,
+};
+
+/* Stream states */
+enum dsp_streamstate {
+ STREAM_IDLE,
+ STREAM_READY,
+ STREAM_PENDING,
+ STREAM_DONE
+};
+
+/* Stream connect types */
+enum dsp_connecttype {
+ CONNECTTYPE_NODEOUTPUT,
+ CONNECTTYPE_GPPOUTPUT,
+ CONNECTTYPE_NODEINPUT,
+ CONNECTTYPE_GPPINPUT
+};
+
+/* Stream mode types */
+enum dsp_strmmode {
+ STRMMODE_PROCCOPY, /* Processor(s) copy stream data payloads */
+ STRMMODE_ZEROCOPY, /* Strm buffer ptrs swapped no data copied */
+ STRMMODE_LDMA, /* Local DMA : OMAP's System-DMA device */
+ STRMMODE_RDMA /* Remote DMA: OMAP's DSP-DMA device */
+};
+
+/* Resource Types */
+enum dsp_resourceinfotype {
+ DSP_RESOURCE_DYNDARAM = 0,
+ DSP_RESOURCE_DYNSARAM,
+ DSP_RESOURCE_DYNEXTERNAL,
+ DSP_RESOURCE_DYNSRAM,
+ DSP_RESOURCE_PROCLOAD
+};
+
+/* Memory Segment Types */
+enum dsp_memtype {
+ DSP_DYNDARAM = 0,
+ DSP_DYNSARAM,
+ DSP_DYNEXTERNAL,
+ DSP_DYNSRAM
+};
+
+/* Memory Flush Types */
+enum dsp_flushtype {
+ PROC_INVALIDATE_MEM = 0,
+ PROC_WRITEBACK_MEM,
+ PROC_WRITEBACK_INVALIDATE_MEM,
+};
+
+/* Memory Segment Status Values */
+struct dsp_memstat {
+ u32 ul_size;
+ u32 ul_total_free_size;
+ u32 ul_len_max_free_block;
+ u32 ul_num_free_blocks;
+ u32 ul_num_alloc_blocks;
+};
+
+/* Processor Load information Values */
+struct dsp_procloadstat {
+ u32 curr_load;
+ u32 predicted_load;
+ u32 curr_dsp_freq;
+ u32 predicted_freq;
+};
+
+/* Attributes for STRM connections between nodes */
+struct dsp_strmattr {
+ u32 seg_id; /* Memory segment on DSP to allocate buffers */
+ u32 buf_size; /* Buffer size (DSP words) */
+ u32 num_bufs; /* Number of buffers */
+ u32 buf_alignment; /* Buffer alignment */
+ u32 utimeout; /* Timeout for blocking STRM calls */
+ enum dsp_strmmode strm_mode; /* mode of stream when opened */
+ /* DMA chnl id if dsp_strmmode is LDMA or RDMA */
+ u32 udma_chnl_id;
+ u32 udma_priority; /* DMA channel priority 0=lowest, >0=high */
+};
+
+/* The dsp_cbdata structure */
+struct dsp_cbdata {
+ u32 cb_data;
+ u8 node_data[1];
+};
+
+/* The dsp_msg structure */
+struct dsp_msg {
+ u32 dw_cmd;
+ u32 dw_arg1;
+ u32 dw_arg2;
+};
+
+/* The dsp_resourcereqmts structure for node's resource requirements */
+struct dsp_resourcereqmts {
+ u32 cb_struct;
+ u32 static_data_size;
+ u32 global_data_size;
+ u32 program_mem_size;
+ u32 uwc_execution_time;
+ u32 uwc_period;
+ u32 uwc_deadline;
+ u32 avg_exection_time;
+ u32 minimum_period;
+};
+
+/*
+ * The dsp_streamconnect structure describes a stream connection
+ * between two nodes, or between a node and the GPP
+ */
+struct dsp_streamconnect {
+ u32 cb_struct;
+ enum dsp_connecttype connect_type;
+ u32 this_node_stream_index;
+ void *connected_node;
+ struct dsp_uuid ui_connected_node_id;
+ u32 connected_node_stream_index;
+};
+
+struct dsp_nodeprofs {
+ u32 ul_heap_size;
+};
+
+/* The dsp_ndbprops structure reports the attributes of a node */
+struct dsp_ndbprops {
+ u32 cb_struct;
+ struct dsp_uuid ui_node_id;
+ char ac_name[DSP_MAXNAMELEN];
+ enum node_type ntype;
+ u32 cache_on_gpp;
+ struct dsp_resourcereqmts dsp_resource_reqmts;
+ s32 prio;
+ u32 stack_size;
+ u32 sys_stack_size;
+ u32 stack_seg;
+ u32 message_depth;
+ u32 num_input_streams;
+ u32 num_output_streams;
+ u32 utimeout;
+ u32 count_profiles; /* Number of supported profiles */
+ /* Array of profiles */
+ struct dsp_nodeprofs node_profiles[MAX_PROFILES];
+ u32 stack_seg_name; /* Stack Segment Name */
+};
+
+ /* The dsp_nodeattrin structure describes the attributes of a
+ * node client */
+struct dsp_nodeattrin {
+ u32 cb_struct;
+ s32 prio;
+ u32 utimeout;
+ u32 profile_id;
+ /* Reserved, for Bridge Internal use only */
+ u32 heap_size;
+ void *pgpp_virt_addr; /* Reserved, for Bridge Internal use only */
+};
+
+ /* The dsp_nodeinfo structure is used to retrieve information
+ * about a node */
+struct dsp_nodeinfo {
+ u32 cb_struct;
+ struct dsp_ndbprops nb_node_database_props;
+ u32 execution_priority;
+ enum node_state ns_execution_state;
+ void *device_owner;
+ u32 number_streams;
+ struct dsp_streamconnect sc_stream_connection[16];
+ u32 node_env;
+};
+
+ /* The dsp_nodeattr structure describes the attributes of a node */
+struct dsp_nodeattr {
+ u32 cb_struct;
+ struct dsp_nodeattrin in_node_attr_in;
+ u32 node_attr_inputs;
+ u32 node_attr_outputs;
+ struct dsp_nodeinfo node_info;
+};
+
+/*
+ * Notification type: either the name of an opened event, or an event or
+ * window handle.
+ */
+struct dsp_notification {
+ char *ps_name;
+ void *handle;
+};
+
+/* The dsp_processorattrin structure describes the attributes of a processor */
+struct dsp_processorattrin {
+ u32 cb_struct;
+ u32 utimeout;
+};
+/*
+ * The dsp_processorinfo structure describes basic capabilities of a
+ * DSP processor
+ */
+struct dsp_processorinfo {
+ u32 cb_struct;
+ int processor_family;
+ int processor_type;
+ u32 clock_rate;
+ u32 ul_internal_mem_size;
+ u32 ul_external_mem_size;
+ u32 processor_id;
+ int ty_running_rtos;
+ s32 node_min_priority;
+ s32 node_max_priority;
+};
+
+/* Error information of last DSP exception signalled to the GPP */
+struct dsp_errorinfo {
+ u32 dw_err_mask;
+ u32 dw_val1;
+ u32 dw_val2;
+ u32 dw_val3;
+};
+
+/* The dsp_processorstate structure describes the state of a DSP processor */
+struct dsp_processorstate {
+ u32 cb_struct;
+ enum dsp_procstate proc_state;
+};
+
+/*
+ * The dsp_resourceinfo structure is used to retrieve information about a
+ * processor's resources
+ */
+struct dsp_resourceinfo {
+ u32 cb_struct;
+ enum dsp_resourceinfotype resource_type;
+ union {
+ u32 ul_resource;
+ struct dsp_memstat mem_stat;
+ struct dsp_procloadstat proc_load_stat;
+ } result;
+};
+
+/*
+ * The dsp_streamattrin structure describes the attributes of a stream,
+ * including segment and alignment of data buffers allocated with
+ * DSPStream_AllocateBuffers(), if applicable
+ */
+struct dsp_streamattrin {
+ u32 cb_struct;
+ u32 utimeout;
+ u32 segment_id;
+ u32 buf_alignment;
+ u32 num_bufs;
+ enum dsp_strmmode strm_mode;
+ u32 udma_chnl_id;
+ u32 udma_priority;
+};
+
+/* The dsp_bufferattr structure describes the attributes of a data buffer */
+struct dsp_bufferattr {
+ u32 cb_struct;
+ u32 segment_id;
+ u32 buf_alignment;
+};
+
+/*
+ * The dsp_streaminfo structure is used to retrieve information
+ * about a stream.
+ */
+struct dsp_streaminfo {
+ u32 cb_struct;
+ u32 number_bufs_allowed;
+ u32 number_bufs_in_stream;
+ u32 ul_number_bytes;
+ void *sync_object_handle;
+ enum dsp_streamstate ss_stream_state;
+};
+
+/* DMM MAP attributes
+It is a bit mask with each bit value indicating a specific attribute
+bit 0 - GPP address type (user virtual=0, physical=1)
+bit 1 - MMU Endianism (Big Endian=1, Little Endian=0)
+bit 2 - MMU mixed page attribute (Mixed/ CPUES=1, TLBES =0)
+bit 3 - MMU element size = 8bit (valid only for non mixed page entries)
+bit 4 - MMU element size = 16bit (valid only for non mixed page entries)
+bit 5 - MMU element size = 32bit (valid only for non mixed page entries)
+bit 6 - MMU element size = 64bit (valid only for non mixed page entries)
+
+bit 14 - Input (read only) buffer
+bit 15 - Output (writeable) buffer
+*/
+
+/* Types of mapping attributes */
+
+/* MPU address is virtual and needs to be translated to physical addr */
+#define DSP_MAPVIRTUALADDR 0x00000000
+#define DSP_MAPPHYSICALADDR 0x00000001
+
+/* Mapped data is big endian */
+#define DSP_MAPBIGENDIAN 0x00000002
+#define DSP_MAPLITTLEENDIAN 0x00000000
+
+/* Element size is based on DSP r/w access size */
+#define DSP_MAPMIXEDELEMSIZE 0x00000004
+
+/*
+ * Element size for MMU mapping (8, 16, 32, or 64 bit)
+ * Ignored if DSP_MAPMIXEDELEMSIZE enabled
+ */
+#define DSP_MAPELEMSIZE8 0x00000008
+#define DSP_MAPELEMSIZE16 0x00000010
+#define DSP_MAPELEMSIZE32 0x00000020
+#define DSP_MAPELEMSIZE64 0x00000040
+
+#define DSP_MAPVMALLOCADDR 0x00000080
+
+#define DSP_MAPDONOTLOCK 0x00000100
+
+#define DSP_MAP_DIR_MASK 0x3FFF
+
+#define GEM_CACHE_LINE_SIZE 128
+#define GEM_L1P_PREFETCH_SIZE 128
+
+/*
+ * Definitions from dbreg.h
+ */
+
+#define DSPPROCTYPE_C64 6410
+#define IVAPROCTYPE_ARM7 470
+
+#define REG_MGR_OBJECT 1
+#define REG_DRV_OBJECT 2
+
+/* registry */
+#define DRVOBJECT "DrvObject"
+#define MGROBJECT "MgrObject"
+
+/* Max registry path length. Also the max registry value length. */
+#define MAXREGPATHLENGTH 255
+
+#endif /* DBDEFS_ */
diff --git a/drivers/staging/tidspbridge/include/dspbridge/dbldefs.h b/drivers/staging/tidspbridge/include/dspbridge/dbldefs.h
new file mode 100644
index 00000000000..bf4fb99529a
--- /dev/null
+++ b/drivers/staging/tidspbridge/include/dspbridge/dbldefs.h
@@ -0,0 +1,141 @@
+/*
+ * dbldefs.h
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * Copyright (C) 2005-2006 Texas Instruments, Inc.
+ *
+ * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef DBLDEFS_
+#define DBLDEFS_
+
+/*
+ * Bit masks for dbl_flags.
+ */
+#define DBL_NOLOAD 0x0 /* Don't load symbols, code, or data */
+#define DBL_SYMB 0x1 /* load symbols */
+#define DBL_CODE 0x2 /* load code */
+#define DBL_DATA 0x4 /* load data */
+#define DBL_DYNAMIC 0x8 /* dynamic load */
+#define DBL_BSS 0x20 /* Unitialized section */
+
+#define DBL_MAXPATHLENGTH 255
+
+/*
+ * ======== dbl_flags ========
+ * Specifies whether to load code, data, or symbols
+ */
+typedef s32 dbl_flags;
+
+/*
+ * ======== dbl_sect_info ========
+ * For collecting info on overlay sections
+ */
+struct dbl_sect_info {
+ const char *name; /* name of section */
+ u32 sect_run_addr; /* run address of section */
+ u32 sect_load_addr; /* load address of section */
+ u32 size; /* size of section (target MAUs) */
+ dbl_flags type; /* Code, data, or BSS */
+};
+
+/*
+ * ======== dbl_symbol ========
+ * (Needed for dynamic load library)
+ */
+struct dbl_symbol {
+ u32 value;
+};
+
+/*
+ * ======== dbl_alloc_fxn ========
+ * Allocate memory function. Allocate or reserve (if reserved == TRUE)
+ * "size" bytes of memory from segment "space" and return the address in
+ * *dsp_address (or starting at *dsp_address if reserve == TRUE). Returns 0 on
+ * success, or an error code on failure.
+ */
+typedef s32(*dbl_alloc_fxn) (void *hdl, s32 space, u32 size, u32 align,
+ u32 *dsp_address, s32 seg_id, s32 req,
+ bool reserved);
+
+/*
+ * ======== dbl_free_fxn ========
+ * Free memory function. Free, or unreserve (if reserved == TRUE) "size"
+ * bytes of memory from segment "space"
+ */
+typedef bool(*dbl_free_fxn) (void *hdl, u32 addr, s32 space, u32 size,
+ bool reserved);
+
+/*
+ * ======== dbl_log_write_fxn ========
+ * Function to call when writing data from a section, to log the info.
+ * Can be NULL if no logging is required.
+ */
+typedef int(*dbl_log_write_fxn) (void *handle,
+ struct dbl_sect_info *sect, u32 addr,
+ u32 bytes);
+
+/*
+ * ======== dbl_sym_lookup ========
+ * Symbol lookup function - Find the symbol name and return its value.
+ *
+ * Parameters:
+ * handle - Opaque handle
+ * parg - Opaque argument.
+ * name - Name of symbol to lookup.
+ * sym - Location to store address of symbol structure.
+ *
+ * Returns:
+ * TRUE: Success (symbol was found).
+ * FALSE: Failed to find symbol.
+ */
+typedef bool(*dbl_sym_lookup) (void *handle, void *parg, void *rmm_handle,
+ const char *name, struct dbl_symbol ** sym);
+
+/*
+ * ======== dbl_write_fxn ========
+ * Write memory function. Write "n" HOST bytes of memory to segment "mtype"
+ * starting at address "dsp_address" from the buffer "buf". The buffer is
+ * formatted as an array of words appropriate for the DSP.
+ */
+typedef s32(*dbl_write_fxn) (void *hdl, u32 dsp_address, void *buf,
+ u32 n, s32 mtype);
+
+/*
+ * ======== dbl_attrs ========
+ */
+struct dbl_attrs {
+ dbl_alloc_fxn alloc;
+ dbl_free_fxn free;
+ void *rmm_handle; /* Handle to pass to alloc, free functions */
+ dbl_write_fxn write;
+ void *input_params; /* Handle to pass to write, cinit function */
+
+ dbl_log_write_fxn log_write;
+ void *log_write_handle;
+
+ /* Symbol matching function and handle to pass to it */
+ dbl_sym_lookup sym_lookup;
+ void *sym_handle;
+ void *sym_arg;
+
+ /*
+ * These file manipulation functions should be compatible with the
+ * "C" run time library functions of the same name.
+ */
+ s32(*fread) (void *, size_t, size_t, void *);
+ s32(*fseek) (void *, long, int);
+ s32(*ftell) (void *);
+ s32(*fclose) (void *);
+ void *(*fopen) (const char *, const char *);
+};
+
+#endif /* DBLDEFS_ */
diff --git a/drivers/staging/tidspbridge/include/dspbridge/dbll.h b/drivers/staging/tidspbridge/include/dspbridge/dbll.h
new file mode 100644
index 00000000000..b0186761466
--- /dev/null
+++ b/drivers/staging/tidspbridge/include/dspbridge/dbll.h
@@ -0,0 +1,62 @@
+/*
+ * dbll.h
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * DSP/BIOS Bridge Dynamic load library module interface. Function header
+ * comments are in the file dblldefs.h.
+ *
+ * Copyright (C) 2005-2006 Texas Instruments, Inc.
+ *
+ * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef DBLL_
+#define DBLL_
+
+#include <dspbridge/dbdefs.h>
+#include <dspbridge/dblldefs.h>
+
+extern bool symbols_reloaded;
+
+extern void dbll_close(struct dbll_library_obj *zl_lib);
+extern int dbll_create(struct dbll_tar_obj **target_obj,
+ struct dbll_attrs *pattrs);
+extern void dbll_delete(struct dbll_tar_obj *target);
+extern void dbll_exit(void);
+extern bool dbll_get_addr(struct dbll_library_obj *zl_lib, char *name,
+ struct dbll_sym_val **sym_val);
+extern void dbll_get_attrs(struct dbll_tar_obj *target,
+ struct dbll_attrs *pattrs);
+extern bool dbll_get_c_addr(struct dbll_library_obj *zl_lib, char *name,
+ struct dbll_sym_val **sym_val);
+extern int dbll_get_sect(struct dbll_library_obj *lib, char *name,
+ u32 *paddr, u32 *psize);
+extern bool dbll_init(void);
+extern int dbll_load(struct dbll_library_obj *lib,
+ dbll_flags flags,
+ struct dbll_attrs *attrs, u32 * entry);
+extern int dbll_load_sect(struct dbll_library_obj *zl_lib,
+ char *sec_name, struct dbll_attrs *attrs);
+extern int dbll_open(struct dbll_tar_obj *target, char *file,
+ dbll_flags flags,
+ struct dbll_library_obj **lib_obj);
+extern int dbll_read_sect(struct dbll_library_obj *lib,
+ char *name, char *buf, u32 size);
+extern void dbll_set_attrs(struct dbll_tar_obj *target,
+ struct dbll_attrs *pattrs);
+extern void dbll_unload(struct dbll_library_obj *lib, struct dbll_attrs *attrs);
+extern int dbll_unload_sect(struct dbll_library_obj *lib,
+ char *sect_name, struct dbll_attrs *attrs);
+#ifdef CONFIG_TIDSPBRIDGE_BACKTRACE
+bool dbll_find_dsp_symbol(struct dbll_library_obj *zl_lib, u32 address,
+ u32 offset_range, u32 *sym_addr_output, char *name_output);
+#endif
+
+#endif /* DBLL_ */
diff --git a/drivers/staging/tidspbridge/include/dspbridge/dblldefs.h b/drivers/staging/tidspbridge/include/dspbridge/dblldefs.h
new file mode 100644
index 00000000000..d2b4fda3429
--- /dev/null
+++ b/drivers/staging/tidspbridge/include/dspbridge/dblldefs.h
@@ -0,0 +1,496 @@
+/*
+ * dblldefs.h
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * Copyright (C) 2005-2006 Texas Instruments, Inc.
+ *
+ * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef DBLLDEFS_
+#define DBLLDEFS_
+
+/*
+ * Bit masks for dbl_flags.
+ */
+#define DBLL_NOLOAD 0x0 /* Don't load symbols, code, or data */
+#define DBLL_SYMB 0x1 /* load symbols */
+#define DBLL_CODE 0x2 /* load code */
+#define DBLL_DATA 0x4 /* load data */
+#define DBLL_DYNAMIC 0x8 /* dynamic load */
+#define DBLL_BSS 0x20 /* Unitialized section */
+
+#define DBLL_MAXPATHLENGTH 255
+
+/*
+ * ======== DBLL_Target ========
+ *
+ */
+struct dbll_tar_obj;
+
+/*
+ * ======== dbll_flags ========
+ * Specifies whether to load code, data, or symbols
+ */
+typedef s32 dbll_flags;
+
+/*
+ * ======== DBLL_Library ========
+ *
+ */
+struct dbll_library_obj;
+
+/*
+ * ======== dbll_sect_info ========
+ * For collecting info on overlay sections
+ */
+struct dbll_sect_info {
+ const char *name; /* name of section */
+ u32 sect_run_addr; /* run address of section */
+ u32 sect_load_addr; /* load address of section */
+ u32 size; /* size of section (target MAUs) */
+ dbll_flags type; /* Code, data, or BSS */
+};
+
+/*
+ * ======== dbll_sym_val ========
+ * (Needed for dynamic load library)
+ */
+struct dbll_sym_val {
+ u32 value;
+};
+
+/*
+ * ======== dbll_alloc_fxn ========
+ * Allocate memory function. Allocate or reserve (if reserved == TRUE)
+ * "size" bytes of memory from segment "space" and return the address in
+ * *dsp_address (or starting at *dsp_address if reserve == TRUE). Returns 0 on
+ * success, or an error code on failure.
+ */
+typedef s32(*dbll_alloc_fxn) (void *hdl, s32 space, u32 size, u32 align,
+ u32 *dsp_address, s32 seg_id, s32 req,
+ bool reserved);
+
+/*
+ * ======== dbll_close_fxn ========
+ */
+typedef s32(*dbll_f_close_fxn) (void *);
+
+/*
+ * ======== dbll_free_fxn ========
+ * Free memory function. Free, or unreserve (if reserved == TRUE) "size"
+ * bytes of memory from segment "space"
+ */
+typedef bool(*dbll_free_fxn) (void *hdl, u32 addr, s32 space, u32 size,
+ bool reserved);
+
+/*
+ * ======== dbll_f_open_fxn ========
+ */
+typedef void *(*dbll_f_open_fxn) (const char *, const char *);
+
+/*
+ * ======== dbll_log_write_fxn ========
+ * Function to call when writing data from a section, to log the info.
+ * Can be NULL if no logging is required.
+ */
+typedef int(*dbll_log_write_fxn) (void *handle,
+ struct dbll_sect_info *sect, u32 addr,
+ u32 bytes);
+
+/*
+ * ======== dbll_read_fxn ========
+ */
+typedef s32(*dbll_read_fxn) (void *, size_t, size_t, void *);
+
+/*
+ * ======== dbll_seek_fxn ========
+ */
+typedef s32(*dbll_seek_fxn) (void *, long, int);
+
+/*
+ * ======== dbll_sym_lookup ========
+ * Symbol lookup function - Find the symbol name and return its value.
+ *
+ * Parameters:
+ * handle - Opaque handle
+ * parg - Opaque argument.
+ * name - Name of symbol to lookup.
+ * sym - Location to store address of symbol structure.
+ *
+ * Returns:
+ * TRUE: Success (symbol was found).
+ * FALSE: Failed to find symbol.
+ */
+typedef bool(*dbll_sym_lookup) (void *handle, void *parg, void *rmm_handle,
+ const char *name, struct dbll_sym_val ** sym);
+
+/*
+ * ======== dbll_tell_fxn ========
+ */
+typedef s32(*dbll_tell_fxn) (void *);
+
+/*
+ * ======== dbll_write_fxn ========
+ * Write memory function. Write "n" HOST bytes of memory to segment "mtype"
+ * starting at address "dsp_address" from the buffer "buf". The buffer is
+ * formatted as an array of words appropriate for the DSP.
+ */
+typedef s32(*dbll_write_fxn) (void *hdl, u32 dsp_address, void *buf,
+ u32 n, s32 mtype);
+
+/*
+ * ======== dbll_attrs ========
+ */
+struct dbll_attrs {
+ dbll_alloc_fxn alloc;
+ dbll_free_fxn free;
+ void *rmm_handle; /* Handle to pass to alloc, free functions */
+ dbll_write_fxn write;
+ void *input_params; /* Handle to pass to write, cinit function */
+ bool base_image;
+ dbll_log_write_fxn log_write;
+ void *log_write_handle;
+
+ /* Symbol matching function and handle to pass to it */
+ dbll_sym_lookup sym_lookup;
+ void *sym_handle;
+ void *sym_arg;
+
+ /*
+ * These file manipulation functions should be compatible with the
+ * "C" run time library functions of the same name.
+ */
+ s32(*fread) (void *, size_t, size_t, void *);
+ s32(*fseek) (void *, long, int);
+ s32(*ftell) (void *);
+ s32(*fclose) (void *);
+ void *(*fopen) (const char *, const char *);
+};
+
+/*
+ * ======== dbll_close ========
+ * Close library opened with dbll_open.
+ * Parameters:
+ * lib - Handle returned from dbll_open().
+ * Returns:
+ * Requires:
+ * DBL initialized.
+ * Valid lib.
+ * Ensures:
+ */
+typedef void (*dbll_close_fxn) (struct dbll_library_obj *library);
+
+/*
+ * ======== dbll_create ========
+ * Create a target object, specifying the alloc, free, and write functions.
+ * Parameters:
+ * target_obj - Location to store target handle on output.
+ * pattrs - Attributes.
+ * Returns:
+ * 0: Success.
+ * -ENOMEM: Memory allocation failed.
+ * Requires:
+ * DBL initialized.
+ * pattrs != NULL.
+ * target_obj != NULL;
+ * Ensures:
+ * Success: *target_obj != NULL.
+ * Failure: *target_obj == NULL.
+ */
+typedef int(*dbll_create_fxn) (struct dbll_tar_obj **target_obj,
+ struct dbll_attrs *attrs);
+
+/*
+ * ======== dbll_delete ========
+ * Delete target object and free resources for any loaded libraries.
+ * Parameters:
+ * target - Handle returned from DBLL_Create().
+ * Returns:
+ * Requires:
+ * DBL initialized.
+ * Valid target.
+ * Ensures:
+ */
+typedef void (*dbll_delete_fxn) (struct dbll_tar_obj *target);
+
+/*
+ * ======== dbll_exit ========
+ * Discontinue use of DBL module.
+ * Parameters:
+ * Returns:
+ * Requires:
+ * refs > 0.
+ * Ensures:
+ * refs >= 0.
+ */
+typedef void (*dbll_exit_fxn) (void);
+
+/*
+ * ======== dbll_get_addr ========
+ * Get address of name in the specified library.
+ * Parameters:
+ * lib - Handle returned from dbll_open().
+ * name - Name of symbol
+ * sym_val - Location to store symbol address on output.
+ * Returns:
+ * TRUE: Success.
+ * FALSE: Symbol not found.
+ * Requires:
+ * DBL initialized.
+ * Valid library.
+ * name != NULL.
+ * sym_val != NULL.
+ * Ensures:
+ */
+typedef bool(*dbll_get_addr_fxn) (struct dbll_library_obj *lib, char *name,
+ struct dbll_sym_val **sym_val);
+
+/*
+ * ======== dbll_get_attrs ========
+ * Retrieve the attributes of the target.
+ * Parameters:
+ * target - Handle returned from DBLL_Create().
+ * pattrs - Location to store attributes on output.
+ * Returns:
+ * Requires:
+ * DBL initialized.
+ * Valid target.
+ * pattrs != NULL.
+ * Ensures:
+ */
+typedef void (*dbll_get_attrs_fxn) (struct dbll_tar_obj *target,
+ struct dbll_attrs *attrs);
+
+/*
+ * ======== dbll_get_c_addr ========
+ * Get address of "C" name on the specified library.
+ * Parameters:
+ * lib - Handle returned from dbll_open().
+ * name - Name of symbol
+ * sym_val - Location to store symbol address on output.
+ * Returns:
+ * TRUE: Success.
+ * FALSE: Symbol not found.
+ * Requires:
+ * DBL initialized.
+ * Valid target.
+ * name != NULL.
+ * sym_val != NULL.
+ * Ensures:
+ */
+typedef bool(*dbll_get_c_addr_fxn) (struct dbll_library_obj *lib, char *name,
+ struct dbll_sym_val **sym_val);
+
+/*
+ * ======== dbll_get_sect ========
+ * Get address and size of a named section.
+ * Parameters:
+ * lib - Library handle returned from dbll_open().
+ * name - Name of section.
+ * paddr - Location to store section address on output.
+ * psize - Location to store section size on output.
+ * Returns:
+ * 0: Success.
+ * -ENXIO: Section not found.
+ * Requires:
+ * DBL initialized.
+ * Valid lib.
+ * name != NULL.
+ * paddr != NULL;
+ * psize != NULL.
+ * Ensures:
+ */
+typedef int(*dbll_get_sect_fxn) (struct dbll_library_obj *lib,
+ char *name, u32 * addr, u32 * size);
+
+/*
+ * ======== dbll_init ========
+ * Initialize DBL module.
+ * Parameters:
+ * Returns:
+ * TRUE: Success.
+ * FALSE: Failure.
+ * Requires:
+ * refs >= 0.
+ * Ensures:
+ * Success: refs > 0.
+ * Failure: refs >= 0.
+ */
+typedef bool(*dbll_init_fxn) (void);
+
+/*
+ * ======== dbll_load ========
+ * Load library onto the target.
+ *
+ * Parameters:
+ * lib - Library handle returned from dbll_open().
+ * flags - Load code, data and/or symbols.
+ * attrs - May contain alloc, free, and write function.
+ * entry_pt - Location to store program entry on output.
+ * Returns:
+ * 0: Success.
+ * -EBADF: File read failed.
+ * -EILSEQ: Failure in dynamic loader library.
+ * Requires:
+ * DBL initialized.
+ * Valid lib.
+ * entry != NULL.
+ * Ensures:
+ */
+typedef int(*dbll_load_fxn) (struct dbll_library_obj *lib,
+ dbll_flags flags,
+ struct dbll_attrs *attrs, u32 *entry);
+
+/*
+ * ======== dbll_load_sect ========
+ * Load a named section from an library (for overlay support).
+ * Parameters:
+ * lib - Handle returned from dbll_open().
+ * sec_name - Name of section to load.
+ * attrs - Contains write function and handle to pass to it.
+ * Returns:
+ * 0: Success.
+ * -ENXIO: Section not found.
+ * -ENOSYS: Function not implemented.
+ * Requires:
+ * Valid lib.
+ * sec_name != NULL.
+ * attrs != NULL.
+ * attrs->write != NULL.
+ * Ensures:
+ */
+typedef int(*dbll_load_sect_fxn) (struct dbll_library_obj *lib,
+ char *sz_sect_name,
+ struct dbll_attrs *attrs);
+
+/*
+ * ======== dbll_open ========
+ * dbll_open() returns a library handle that can be used to load/unload
+ * the symbols/code/data via dbll_load()/dbll_unload().
+ * Parameters:
+ * target - Handle returned from dbll_create().
+ * file - Name of file to open.
+ * flags - If flags & DBLL_SYMB, load symbols.
+ * lib_obj - Location to store library handle on output.
+ * Returns:
+ * 0: Success.
+ * -ENOMEM: Memory allocation failure.
+ * -EBADF: File open/read failure.
+ * Unable to determine target type.
+ * Requires:
+ * DBL initialized.
+ * Valid target.
+ * file != NULL.
+ * lib_obj != NULL.
+ * dbll_attrs fopen function non-NULL.
+ * Ensures:
+ * Success: Valid *lib_obj.
+ * Failure: *lib_obj == NULL.
+ */
+typedef int(*dbll_open_fxn) (struct dbll_tar_obj *target, char *file,
+ dbll_flags flags,
+ struct dbll_library_obj **lib_obj);
+
+/*
+ * ======== dbll_read_sect ========
+ * Read COFF section into a character buffer.
+ * Parameters:
+ * lib - Library handle returned from dbll_open().
+ * name - Name of section.
+ * pbuf - Buffer to write section contents into.
+ * size - Buffer size
+ * Returns:
+ * 0: Success.
+ * -ENXIO: Named section does not exists.
+ * Requires:
+ * DBL initialized.
+ * Valid lib.
+ * name != NULL.
+ * pbuf != NULL.
+ * size != 0.
+ * Ensures:
+ */
+typedef int(*dbll_read_sect_fxn) (struct dbll_library_obj *lib,
+ char *name, char *content,
+ u32 cont_size);
+
+/*
+ * ======== dbll_set_attrs ========
+ * Set the attributes of the target.
+ * Parameters:
+ * target - Handle returned from dbll_create().
+ * pattrs - New attributes.
+ * Returns:
+ * Requires:
+ * DBL initialized.
+ * Valid target.
+ * pattrs != NULL.
+ * Ensures:
+ */
+typedef void (*dbll_set_attrs_fxn) (struct dbll_tar_obj *target,
+ struct dbll_attrs *attrs);
+
+/*
+ * ======== dbll_unload ========
+ * Unload library loaded with dbll_load().
+ * Parameters:
+ * lib - Handle returned from dbll_open().
+ * attrs - Contains free() function and handle to pass to it.
+ * Returns:
+ * Requires:
+ * DBL initialized.
+ * Valid lib.
+ * Ensures:
+ */
+typedef void (*dbll_unload_fxn) (struct dbll_library_obj *library,
+ struct dbll_attrs *attrs);
+
+/*
+ * ======== dbll_unload_sect ========
+ * Unload a named section from an library (for overlay support).
+ * Parameters:
+ * lib - Handle returned from dbll_open().
+ * sec_name - Name of section to load.
+ * attrs - Contains free() function and handle to pass to it.
+ * Returns:
+ * 0: Success.
+ * -ENXIO: Named section not found.
+ * -ENOSYS
+ * Requires:
+ * DBL initialized.
+ * Valid lib.
+ * sec_name != NULL.
+ * Ensures:
+ */
+typedef int(*dbll_unload_sect_fxn) (struct dbll_library_obj *lib,
+ char *sz_sect_name,
+ struct dbll_attrs *attrs);
+
+struct dbll_fxns {
+ dbll_close_fxn close_fxn;
+ dbll_create_fxn create_fxn;
+ dbll_delete_fxn delete_fxn;
+ dbll_exit_fxn exit_fxn;
+ dbll_get_attrs_fxn get_attrs_fxn;
+ dbll_get_addr_fxn get_addr_fxn;
+ dbll_get_c_addr_fxn get_c_addr_fxn;
+ dbll_get_sect_fxn get_sect_fxn;
+ dbll_init_fxn init_fxn;
+ dbll_load_fxn load_fxn;
+ dbll_load_sect_fxn load_sect_fxn;
+ dbll_open_fxn open_fxn;
+ dbll_read_sect_fxn read_sect_fxn;
+ dbll_set_attrs_fxn set_attrs_fxn;
+ dbll_unload_fxn unload_fxn;
+ dbll_unload_sect_fxn unload_sect_fxn;
+};
+
+#endif /* DBLDEFS_ */
diff --git a/drivers/staging/tidspbridge/include/dspbridge/dehdefs.h b/drivers/staging/tidspbridge/include/dspbridge/dehdefs.h
new file mode 100644
index 00000000000..09f8bf83ab0
--- /dev/null
+++ b/drivers/staging/tidspbridge/include/dspbridge/dehdefs.h
@@ -0,0 +1,32 @@
+/*
+ * dehdefs.h
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * Definition for Bridge driver module DEH.
+ *
+ * Copyright (C) 2005-2006 Texas Instruments, Inc.
+ *
+ * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef DEHDEFS_
+#define DEHDEFS_
+
+#include <dspbridge/mbx_sh.h> /* shared mailbox codes */
+
+/* DEH object manager */
+struct deh_mgr;
+
+/* Magic code used to determine if DSP signaled exception. */
+#define DEH_BASE MBX_DEH_BASE
+#define DEH_USERS_BASE MBX_DEH_USERS_BASE
+#define DEH_LIMIT MBX_DEH_LIMIT
+
+#endif /* _DEHDEFS_H */
diff --git a/drivers/staging/tidspbridge/include/dspbridge/dev.h b/drivers/staging/tidspbridge/include/dspbridge/dev.h
new file mode 100644
index 00000000000..357458fadd2
--- /dev/null
+++ b/drivers/staging/tidspbridge/include/dspbridge/dev.h
@@ -0,0 +1,702 @@
+/*
+ * dev.h
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * Bridge Bridge driver device operations.
+ *
+ * Copyright (C) 2005-2006 Texas Instruments, Inc.
+ *
+ * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef DEV_
+#define DEV_
+
+/* ----------------------------------- Module Dependent Headers */
+#include <dspbridge/chnldefs.h>
+#include <dspbridge/cmm.h>
+#include <dspbridge/cod.h>
+#include <dspbridge/dehdefs.h>
+#include <dspbridge/nodedefs.h>
+#include <dspbridge/dispdefs.h>
+#include <dspbridge/dspdefs.h>
+#include <dspbridge/dmm.h>
+#include <dspbridge/host_os.h>
+
+/* ----------------------------------- This */
+#include <dspbridge/devdefs.h>
+
+/*
+ * ======== dev_brd_write_fxn ========
+ * Purpose:
+ * Exported function to be used as the COD write function. This function
+ * is passed a handle to a DEV_hObject by ZL in arb, then calls the
+ * device's bridge_brd_write() function.
+ * Parameters:
+ * arb: Handle to a Device Object.
+ * dev_ctxt: Handle to Bridge driver defined device info.
+ * dsp_addr: Address on DSP board (Destination).
+ * host_buf: Pointer to host buffer (Source).
+ * ul_num_bytes: Number of bytes to transfer.
+ * mem_type: Memory space on DSP to which to transfer.
+ * Returns:
+ * Number of bytes written. Returns 0 if the DEV_hObject passed in via
+ * arb is invalid.
+ * Requires:
+ * DEV Initialized.
+ * host_buf != NULL
+ * Ensures:
+ */
+extern u32 dev_brd_write_fxn(void *arb,
+ u32 dsp_add,
+ void *host_buf, u32 ul_num_bytes, u32 mem_space);
+
+/*
+ * ======== dev_create_device ========
+ * Purpose:
+ * Called by the operating system to load the Bridge Driver for a
+ * 'Bridge device.
+ * Parameters:
+ * device_obj: Ptr to location to receive the device object handle.
+ * driver_file_name: Name of Bridge driver PE DLL file to load. If the
+ * absolute path is not provided, the file is loaded
+ * through 'Bridge's module search path.
+ * host_config: Host configuration information, to be passed down
+ * to the Bridge driver when bridge_dev_create() is called.
+ * pDspConfig: DSP resources, to be passed down to the Bridge driver
+ * when bridge_dev_create() is called.
+ * dev_node_obj: Platform specific device node.
+ * Returns:
+ * 0: Module is loaded, device object has been created
+ * -ENOMEM: Insufficient memory to create needed resources.
+ * -EPERM: Unable to find Bridge driver entry point function.
+ * -ESPIPE: Unable to load ZL DLL.
+ * Requires:
+ * DEV Initialized.
+ * device_obj != NULL.
+ * driver_file_name != NULL.
+ * host_config != NULL.
+ * pDspConfig != NULL.
+ * Ensures:
+ * 0: *device_obj will contain handle to the new device object.
+ * Otherwise, does not create the device object, ensures the Bridge driver
+ * module is unloaded, and sets *device_obj to NULL.
+ */
+extern int dev_create_device(struct dev_object
+ **device_obj,
+ const char *driver_file_name,
+ struct cfg_devnode *dev_node_obj);
+
+/*
+ * ======== dev_create_iva_device ========
+ * Purpose:
+ * Called by the operating system to load the Bridge Driver for IVA.
+ * Parameters:
+ * device_obj: Ptr to location to receive the device object handle.
+ * driver_file_name: Name of Bridge driver PE DLL file to load. If the
+ * absolute path is not provided, the file is loaded
+ * through 'Bridge's module search path.
+ * host_config: Host configuration information, to be passed down
+ * to the Bridge driver when bridge_dev_create() is called.
+ * pDspConfig: DSP resources, to be passed down to the Bridge driver
+ * when bridge_dev_create() is called.
+ * dev_node_obj: Platform specific device node.
+ * Returns:
+ * 0: Module is loaded, device object has been created
+ * -ENOMEM: Insufficient memory to create needed resources.
+ * -EPERM: Unable to find Bridge driver entry point function.
+ * -ESPIPE: Unable to load ZL DLL.
+ * Requires:
+ * DEV Initialized.
+ * device_obj != NULL.
+ * driver_file_name != NULL.
+ * host_config != NULL.
+ * pDspConfig != NULL.
+ * Ensures:
+ * 0: *device_obj will contain handle to the new device object.
+ * Otherwise, does not create the device object, ensures the Bridge driver
+ * module is unloaded, and sets *device_obj to NULL.
+ */
+extern int dev_create_iva_device(struct dev_object
+ **device_obj,
+ const char *driver_file_name,
+ const struct cfg_hostres
+ *host_config,
+ struct cfg_devnode *dev_node_obj);
+
+/*
+ * ======== dev_create2 ========
+ * Purpose:
+ * After successful loading of the image from api_init_complete2
+ * (PROC Auto_Start) or proc_load this fxn is called. This creates
+ * the Node Manager and updates the DEV Object.
+ * Parameters:
+ * hdev_obj: Handle to device object created with dev_create_device().
+ * Returns:
+ * 0: Successful Creation of Node Manager
+ * -EPERM: Some Error Occurred.
+ * Requires:
+ * DEV Initialized
+ * Valid hdev_obj
+ * Ensures:
+ * 0 and hdev_obj->hnode_mgr != NULL
+ * else hdev_obj->hnode_mgr == NULL
+ */
+extern int dev_create2(struct dev_object *hdev_obj);
+
+/*
+ * ======== dev_destroy2 ========
+ * Purpose:
+ * Destroys the Node manager for this device.
+ * Parameters:
+ * hdev_obj: Handle to device object created with dev_create_device().
+ * Returns:
+ * 0: Successful Creation of Node Manager
+ * -EPERM: Some Error Occurred.
+ * Requires:
+ * DEV Initialized
+ * Valid hdev_obj
+ * Ensures:
+ * 0 and hdev_obj->hnode_mgr == NULL
+ * else -EPERM.
+ */
+extern int dev_destroy2(struct dev_object *hdev_obj);
+
+/*
+ * ======== dev_destroy_device ========
+ * Purpose:
+ * Destroys the channel manager for this device, if any, calls
+ * bridge_dev_destroy(), and then attempts to unload the Bridge module.
+ * Parameters:
+ * hdev_obj: Handle to device object created with
+ * dev_create_device().
+ * Returns:
+ * 0: Success.
+ * -EFAULT: Invalid hdev_obj.
+ * -EPERM: The Bridge driver failed it's bridge_dev_destroy() function.
+ * Requires:
+ * DEV Initialized.
+ * Ensures:
+ */
+extern int dev_destroy_device(struct dev_object
+ *hdev_obj);
+
+/*
+ * ======== dev_get_chnl_mgr ========
+ * Purpose:
+ * Retrieve the handle to the channel manager created for this device.
+ * Parameters:
+ * hdev_obj: Handle to device object created with
+ * dev_create_device().
+ * *mgr: Ptr to location to store handle.
+ * Returns:
+ * 0: Success.
+ * -EFAULT: Invalid hdev_obj.
+ * Requires:
+ * mgr != NULL.
+ * DEV Initialized.
+ * Ensures:
+ * 0: *mgr contains a handle to a channel manager object,
+ * or NULL.
+ * else: *mgr is NULL.
+ */
+extern int dev_get_chnl_mgr(struct dev_object *hdev_obj,
+ struct chnl_mgr **mgr);
+
+/*
+ * ======== dev_get_cmm_mgr ========
+ * Purpose:
+ * Retrieve the handle to the shared memory manager created for this
+ * device.
+ * Parameters:
+ * hdev_obj: Handle to device object created with
+ * dev_create_device().
+ * *mgr: Ptr to location to store handle.
+ * Returns:
+ * 0: Success.
+ * -EFAULT: Invalid hdev_obj.
+ * Requires:
+ * mgr != NULL.
+ * DEV Initialized.
+ * Ensures:
+ * 0: *mgr contains a handle to a channel manager object,
+ * or NULL.
+ * else: *mgr is NULL.
+ */
+extern int dev_get_cmm_mgr(struct dev_object *hdev_obj,
+ struct cmm_object **mgr);
+
+/*
+ * ======== dev_get_dmm_mgr ========
+ * Purpose:
+ * Retrieve the handle to the dynamic memory manager created for this
+ * device.
+ * Parameters:
+ * hdev_obj: Handle to device object created with
+ * dev_create_device().
+ * *mgr: Ptr to location to store handle.
+ * Returns:
+ * 0: Success.
+ * -EFAULT: Invalid hdev_obj.
+ * Requires:
+ * mgr != NULL.
+ * DEV Initialized.
+ * Ensures:
+ * 0: *mgr contains a handle to a channel manager object,
+ * or NULL.
+ * else: *mgr is NULL.
+ */
+extern int dev_get_dmm_mgr(struct dev_object *hdev_obj,
+ struct dmm_object **mgr);
+
+/*
+ * ======== dev_get_cod_mgr ========
+ * Purpose:
+ * Retrieve the COD manager create for this device.
+ * Parameters:
+ * hdev_obj: Handle to device object created with
+ * dev_create_device().
+ * *cod_mgr: Ptr to location to store handle.
+ * Returns:
+ * 0: Success.
+ * -EFAULT: Invalid hdev_obj.
+ * Requires:
+ * cod_mgr != NULL.
+ * DEV Initialized.
+ * Ensures:
+ * 0: *cod_mgr contains a handle to a COD manager object.
+ * else: *cod_mgr is NULL.
+ */
+extern int dev_get_cod_mgr(struct dev_object *hdev_obj,
+ struct cod_manager **cod_mgr);
+
+/*
+ * ======== dev_get_deh_mgr ========
+ * Purpose:
+ * Retrieve the DEH manager created for this device.
+ * Parameters:
+ * hdev_obj: Handle to device object created with dev_create_device().
+ * *deh_manager: Ptr to location to store handle.
+ * Returns:
+ * 0: Success.
+ * -EFAULT: Invalid hdev_obj.
+ * Requires:
+ * deh_manager != NULL.
+ * DEH Initialized.
+ * Ensures:
+ * 0: *deh_manager contains a handle to a DEH manager object.
+ * else: *deh_manager is NULL.
+ */
+extern int dev_get_deh_mgr(struct dev_object *hdev_obj,
+ struct deh_mgr **deh_manager);
+
+/*
+ * ======== dev_get_dev_node ========
+ * Purpose:
+ * Retrieve the platform specific device ID for this device.
+ * Parameters:
+ * hdev_obj: Handle to device object created with
+ * dev_create_device().
+ * dev_nde: Ptr to location to get the device node handle.
+ * Returns:
+ * 0: Returns a DEVNODE in *dev_node_obj.
+ * -EFAULT: Invalid hdev_obj.
+ * Requires:
+ * dev_nde != NULL.
+ * DEV Initialized.
+ * Ensures:
+ * 0: *dev_nde contains a platform specific device ID;
+ * else: *dev_nde is NULL.
+ */
+extern int dev_get_dev_node(struct dev_object *hdev_obj,
+ struct cfg_devnode **dev_nde);
+
+/*
+ * ======== dev_get_dev_type ========
+ * Purpose:
+ * Retrieve the platform specific device ID for this device.
+ * Parameters:
+ * hdev_obj: Handle to device object created with
+ * dev_create_device().
+ * dev_nde: Ptr to location to get the device node handle.
+ * Returns:
+ * 0: Success
+ * -EFAULT: Invalid hdev_obj.
+ * Requires:
+ * dev_nde != NULL.
+ * DEV Initialized.
+ * Ensures:
+ * 0: *dev_nde contains a platform specific device ID;
+ * else: *dev_nde is NULL.
+ */
+extern int dev_get_dev_type(struct dev_object *device_obj,
+ u8 *dev_type);
+
+/*
+ * ======== dev_get_first ========
+ * Purpose:
+ * Retrieve the first Device Object handle from an internal linked list of
+ * of DEV_OBJECTs maintained by DEV.
+ * Parameters:
+ * Returns:
+ * NULL if there are no device objects stored; else
+ * a valid DEV_HOBJECT.
+ * Requires:
+ * No calls to dev_create_device or dev_destroy_device (which my modify the
+ * internal device object list) may occur between calls to dev_get_first
+ * and dev_get_next.
+ * Ensures:
+ * The DEV_HOBJECT returned is valid.
+ * A subsequent call to dev_get_next will return the next device object in
+ * the list.
+ */
+extern struct dev_object *dev_get_first(void);
+
+/*
+ * ======== dev_get_intf_fxns ========
+ * Purpose:
+ * Retrieve the Bridge driver interface function structure for the
+ * loaded Bridge driver.
+ * Parameters:
+ * hdev_obj: Handle to device object created with
+ * dev_create_device().
+ * *if_fxns: Ptr to location to store fxn interface.
+ * Returns:
+ * 0: Success.
+ * -EFAULT: Invalid hdev_obj.
+ * Requires:
+ * if_fxns != NULL.
+ * DEV Initialized.
+ * Ensures:
+ * 0: *if_fxns contains a pointer to the Bridge
+ * driver interface;
+ * else: *if_fxns is NULL.
+ */
+extern int dev_get_intf_fxns(struct dev_object *hdev_obj,
+ struct bridge_drv_interface **if_fxns);
+
+/*
+ * ======== dev_get_io_mgr ========
+ * Purpose:
+ * Retrieve the handle to the IO manager created for this device.
+ * Parameters:
+ * hdev_obj: Handle to device object created with
+ * dev_create_device().
+ * *mgr: Ptr to location to store handle.
+ * Returns:
+ * 0: Success.
+ * -EFAULT: Invalid hdev_obj.
+ * Requires:
+ * mgr != NULL.
+ * DEV Initialized.
+ * Ensures:
+ * 0: *mgr contains a handle to an IO manager object.
+ * else: *mgr is NULL.
+ */
+extern int dev_get_io_mgr(struct dev_object *hdev_obj,
+ struct io_mgr **mgr);
+
+/*
+ * ======== dev_get_next ========
+ * Purpose:
+ * Retrieve the next Device Object handle from an internal linked list of
+ * of DEV_OBJECTs maintained by DEV, after having previously called
+ * dev_get_first() and zero or more dev_get_next
+ * Parameters:
+ * hdev_obj: Handle to the device object returned from a previous
+ * call to dev_get_first() or dev_get_next().
+ * Returns:
+ * NULL if there are no further device objects on the list or hdev_obj
+ * was invalid;
+ * else the next valid DEV_HOBJECT in the list.
+ * Requires:
+ * No calls to dev_create_device or dev_destroy_device (which my modify the
+ * internal device object list) may occur between calls to dev_get_first
+ * and dev_get_next.
+ * Ensures:
+ * The DEV_HOBJECT returned is valid.
+ * A subsequent call to dev_get_next will return the next device object in
+ * the list.
+ */
+extern struct dev_object *dev_get_next(struct dev_object
+ *hdev_obj);
+
+/*
+ * ========= dev_get_msg_mgr ========
+ * Purpose:
+ * Retrieve the msg_ctrl Manager Handle from the DevObject.
+ * Parameters:
+ * hdev_obj: Handle to the Dev Object
+ * msg_man: Location where msg_ctrl Manager handle will be returned.
+ * Returns:
+ * Requires:
+ * DEV Initialized.
+ * Valid hdev_obj.
+ * node_man != NULL.
+ * Ensures:
+ */
+extern void dev_get_msg_mgr(struct dev_object *hdev_obj,
+ struct msg_mgr **msg_man);
+
+/*
+ * ========= dev_get_node_manager ========
+ * Purpose:
+ * Retrieve the Node Manager Handle from the DevObject. It is an
+ * accessor function
+ * Parameters:
+ * hdev_obj: Handle to the Dev Object
+ * node_man: Location where Handle to the Node Manager will be
+ * returned..
+ * Returns:
+ * 0: Success
+ * -EFAULT: Invalid Dev Object handle.
+ * Requires:
+ * DEV Initialized.
+ * node_man is not null
+ * Ensures:
+ * 0: *node_man contains a handle to a Node manager object.
+ * else: *node_man is NULL.
+ */
+extern int dev_get_node_manager(struct dev_object
+ *hdev_obj,
+ struct node_mgr **node_man);
+
+/*
+ * ======== dev_get_symbol ========
+ * Purpose:
+ * Get the value of a symbol in the currently loaded program.
+ * Parameters:
+ * hdev_obj: Handle to device object created with
+ * dev_create_device().
+ * str_sym: Name of symbol to look up.
+ * pul_value: Ptr to symbol value.
+ * Returns:
+ * 0: Success.
+ * -EFAULT: Invalid hdev_obj.
+ * -ESPIPE: Symbols couldn not be found or have not been loaded onto
+ * the board.
+ * Requires:
+ * str_sym != NULL.
+ * pul_value != NULL.
+ * DEV Initialized.
+ * Ensures:
+ * 0: *pul_value contains the symbol value;
+ */
+extern int dev_get_symbol(struct dev_object *hdev_obj,
+ const char *str_sym, u32 * pul_value);
+
+/*
+ * ======== dev_get_bridge_context ========
+ * Purpose:
+ * Retrieve the Bridge Context handle, as returned by the
+ * bridge_dev_create fxn.
+ * Parameters:
+ * hdev_obj: Handle to device object created with dev_create_device()
+ * *phbridge_context: Ptr to location to store context handle.
+ * Returns:
+ * 0: Success.
+ * -EFAULT: Invalid hdev_obj.
+ * Requires:
+ * phbridge_context != NULL.
+ * DEV Initialized.
+ * Ensures:
+ * 0: *phbridge_context contains context handle;
+ * else: *phbridge_context is NULL;
+ */
+extern int dev_get_bridge_context(struct dev_object *hdev_obj,
+ struct bridge_dev_context
+ **phbridge_context);
+
+/*
+ * ======== dev_exit ========
+ * Purpose:
+ * Decrement reference count, and free resources when reference count is
+ * 0.
+ * Parameters:
+ * Returns:
+ * Requires:
+ * DEV is initialized.
+ * Ensures:
+ * When reference count == 0, DEV's private resources are freed.
+ */
+extern void dev_exit(void);
+
+/*
+ * ======== dev_init ========
+ * Purpose:
+ * Initialize DEV's private state, keeping a reference count on each call.
+ * Parameters:
+ * Returns:
+ * TRUE if initialized; FALSE if error occured.
+ * Requires:
+ * Ensures:
+ * TRUE: A requirement for the other public DEV functions.
+ */
+extern bool dev_init(void);
+
+/*
+ * ======== dev_is_locked ========
+ * Purpose:
+ * Predicate function to determine if the device has been
+ * locked by a client for exclusive access.
+ * Parameters:
+ * hdev_obj: Handle to device object created with
+ * dev_create_device().
+ * Returns:
+ * 0: TRUE: device has been locked.
+ * 0: FALSE: device not locked.
+ * -EFAULT: hdev_obj was invalid.
+ * Requires:
+ * DEV Initialized.
+ * Ensures:
+ */
+extern int dev_is_locked(struct dev_object *hdev_obj);
+
+/*
+ * ======== dev_insert_proc_object ========
+ * Purpose:
+ * Inserts the Processor Object into the List of PROC Objects
+ * kept in the DEV Object
+ * Parameters:
+ * proc_obj: Handle to the Proc Object
+ * hdev_obj Handle to the Dev Object
+ * bAttachedNew Specifies if there are already processors attached
+ * Returns:
+ * 0: Successfully inserted into the list
+ * Requires:
+ * proc_obj is not NULL
+ * hdev_obj is a valid handle to the DEV.
+ * DEV Initialized.
+ * List(of Proc object in Dev) Exists.
+ * Ensures:
+ * 0 & the PROC Object is inserted and the list is not empty
+ * Details:
+ * If the List of Proc Object is empty bAttachedNew is TRUE, it indicated
+ * this is the first Processor attaching.
+ * If it is False, there are already processors attached.
+ */
+extern int dev_insert_proc_object(struct dev_object
+ *hdev_obj,
+ u32 proc_obj,
+ bool *already_attached);
+
+/*
+ * ======== dev_remove_proc_object ========
+ * Purpose:
+ * Search for and remove a Proc object from the given list maintained
+ * by the DEV
+ * Parameters:
+ * p_proc_object: Ptr to ProcObject to insert.
+ * dev_obj: Ptr to Dev Object where the list is.
+ * already_attached: Ptr to return the bool
+ * Returns:
+ * 0: If successful.
+ * -EPERM Failure to Remove the PROC Object from the list
+ * Requires:
+ * DevObject is Valid
+ * proc_obj != 0
+ * dev_obj->proc_list != NULL
+ * !LST_IS_EMPTY(dev_obj->proc_list)
+ * already_attached !=NULL
+ * Ensures:
+ * Details:
+ * List will be deleted when the DEV is destroyed.
+ *
+ */
+extern int dev_remove_proc_object(struct dev_object
+ *hdev_obj, u32 proc_obj);
+
+/*
+ * ======== dev_notify_clients ========
+ * Purpose:
+ * Notify all clients of this device of a change in device status.
+ * Clients may include multiple users of BRD, as well as CHNL.
+ * This function is asychronous, and may be called by a timer event
+ * set up by a watchdog timer.
+ * Parameters:
+ * hdev_obj: Handle to device object created with dev_create_device().
+ * ret: A status word, most likely a BRD_STATUS.
+ * Returns:
+ * 0: All registered clients were asynchronously notified.
+ * -EINVAL: Invalid hdev_obj.
+ * Requires:
+ * DEV Initialized.
+ * Ensures:
+ * 0: Notifications are queued by the operating system to be
+ * delivered to clients. This function does not ensure that
+ * the notifications will ever be delivered.
+ */
+extern int dev_notify_clients(struct dev_object *hdev_obj, u32 ret);
+
+/*
+ * ======== dev_remove_device ========
+ * Purpose:
+ * Destroys the Device Object created by dev_start_device.
+ * Parameters:
+ * dev_node_obj: Device node as it is know to OS.
+ * Returns:
+ * 0: If success;
+ * <error code> Otherwise.
+ * Requires:
+ * Ensures:
+ */
+extern int dev_remove_device(struct cfg_devnode *dev_node_obj);
+
+/*
+ * ======== dev_set_chnl_mgr ========
+ * Purpose:
+ * Set the channel manager for this device.
+ * Parameters:
+ * hdev_obj: Handle to device object created with
+ * dev_create_device().
+ * hmgr: Handle to a channel manager, or NULL.
+ * Returns:
+ * 0: Success.
+ * -EFAULT: Invalid hdev_obj.
+ * Requires:
+ * DEV Initialized.
+ * Ensures:
+ */
+extern int dev_set_chnl_mgr(struct dev_object *hdev_obj,
+ struct chnl_mgr *hmgr);
+
+/*
+ * ======== dev_set_msg_mgr ========
+ * Purpose:
+ * Set the Message manager for this device.
+ * Parameters:
+ * hdev_obj: Handle to device object created with dev_create_device().
+ * hmgr: Handle to a message manager, or NULL.
+ * Returns:
+ * Requires:
+ * DEV Initialized.
+ * Ensures:
+ */
+extern void dev_set_msg_mgr(struct dev_object *hdev_obj, struct msg_mgr *hmgr);
+
+/*
+ * ======== dev_start_device ========
+ * Purpose:
+ * Initializes the new device with bridge environment. This involves
+ * querying CM for allocated resources, querying the registry for
+ * necessary dsp resources (requested in the INF file), and using this
+ * information to create a bridge device object.
+ * Parameters:
+ * dev_node_obj: Device node as it is know to OS.
+ * Returns:
+ * 0: If success;
+ * <error code> Otherwise.
+ * Requires:
+ * DEV initialized.
+ * Ensures:
+ */
+extern int dev_start_device(struct cfg_devnode *dev_node_obj);
+
+#endif /* DEV_ */
diff --git a/drivers/staging/tidspbridge/include/dspbridge/devdefs.h b/drivers/staging/tidspbridge/include/dspbridge/devdefs.h
new file mode 100644
index 00000000000..a2f9241ff13
--- /dev/null
+++ b/drivers/staging/tidspbridge/include/dspbridge/devdefs.h
@@ -0,0 +1,26 @@
+/*
+ * devdefs.h
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * Definition of common include typedef between dspdefs.h and dev.h. Required
+ * to break circular dependency between Bridge driver and DEV include files.
+ *
+ * Copyright (C) 2008 Texas Instruments, Inc.
+ *
+ * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef DEVDEFS_
+#define DEVDEFS_
+
+/* Bridge Device Object */
+struct dev_object;
+
+#endif /* DEVDEFS_ */
diff --git a/drivers/staging/tidspbridge/include/dspbridge/disp.h b/drivers/staging/tidspbridge/include/dspbridge/disp.h
new file mode 100644
index 00000000000..82bf721447a
--- /dev/null
+++ b/drivers/staging/tidspbridge/include/dspbridge/disp.h
@@ -0,0 +1,204 @@
+/*
+ * disp.h
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * DSP/BIOS Bridge Node Dispatcher.
+ *
+ * Copyright (C) 2005-2006 Texas Instruments, Inc.
+ *
+ * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef DISP_
+#define DISP_
+
+#include <dspbridge/dbdefs.h>
+#include <dspbridge/nodedefs.h>
+#include <dspbridge/nodepriv.h>
+#include <dspbridge/dispdefs.h>
+
+/*
+ * ======== disp_create ========
+ * Create a NODE Dispatcher object. This object handles the creation,
+ * deletion, and execution of nodes on the DSP target, through communication
+ * with the Resource Manager Server running on the target. Each NODE
+ * Manager object should have exactly one NODE Dispatcher.
+ *
+ * Parameters:
+ * dispatch_obj: Location to store node dispatcher object on output.
+ * hdev_obj: Device for this processor.
+ * disp_attrs: Node dispatcher attributes.
+ * Returns:
+ * 0: Success;
+ * -ENOMEM: Insufficient memory for requested resources.
+ * -EPERM: Unable to create dispatcher.
+ * Requires:
+ * disp_init(void) called.
+ * disp_attrs != NULL.
+ * hdev_obj != NULL.
+ * dispatch_obj != NULL.
+ * Ensures:
+ * 0: IS_VALID(*dispatch_obj).
+ * error: *dispatch_obj == NULL.
+ */
+extern int disp_create(struct disp_object **dispatch_obj,
+ struct dev_object *hdev_obj,
+ const struct disp_attr *disp_attrs);
+
+/*
+ * ======== disp_delete ========
+ * Delete the NODE Dispatcher.
+ *
+ * Parameters:
+ * disp_obj: Node Dispatcher object.
+ * Returns:
+ * Requires:
+ * disp_init(void) called.
+ * Valid disp_obj.
+ * Ensures:
+ * disp_obj is invalid.
+ */
+extern void disp_delete(struct disp_object *disp_obj);
+
+/*
+ * ======== disp_exit ========
+ * Discontinue usage of DISP module.
+ *
+ * Parameters:
+ * Returns:
+ * Requires:
+ * disp_init(void) previously called.
+ * Ensures:
+ * Any resources acquired in disp_init(void) will be freed when last DISP
+ * client calls disp_exit(void).
+ */
+extern void disp_exit(void);
+
+/*
+ * ======== disp_init ========
+ * Initialize the DISP module.
+ *
+ * Parameters:
+ * Returns:
+ * TRUE if initialization succeeded, FALSE otherwise.
+ * Ensures:
+ */
+extern bool disp_init(void);
+
+/*
+ * ======== disp_node_change_priority ========
+ * Change the priority of a node currently running on the target.
+ *
+ * Parameters:
+ * disp_obj: Node Dispatcher object.
+ * hnode: Node object representing a node currently
+ * allocated or running on the DSP.
+ * ulFxnAddress: Address of RMS function for changing priority.
+ * node_env: Address of node's environment structure.
+ * prio: New priority level to set node's priority to.
+ * Returns:
+ * 0: Success.
+ * -ETIME: A timeout occurred before the DSP responded.
+ * Requires:
+ * disp_init(void) called.
+ * Valid disp_obj.
+ * hnode != NULL.
+ * Ensures:
+ */
+extern int disp_node_change_priority(struct disp_object
+ *disp_obj,
+ struct node_object *hnode,
+ u32 rms_fxn,
+ nodeenv node_env, s32 prio);
+
+/*
+ * ======== disp_node_create ========
+ * Create a node on the DSP by remotely calling the node's create function.
+ *
+ * Parameters:
+ * disp_obj: Node Dispatcher object.
+ * hnode: Node handle obtained from node_allocate().
+ * ul_fxn_addr: Address or RMS create node function.
+ * ul_create_fxn: Address of node's create function.
+ * pargs: Arguments to pass to RMS node create function.
+ * node_env: Location to store node environment pointer on
+ * output.
+ * Returns:
+ * 0: Success.
+ * -ETIME: A timeout occurred before the DSP responded.
+ * -EPERM: A failure occurred, unable to create node.
+ * Requires:
+ * disp_init(void) called.
+ * Valid disp_obj.
+ * pargs != NULL.
+ * hnode != NULL.
+ * node_env != NULL.
+ * node_get_type(hnode) != NODE_DEVICE.
+ * Ensures:
+ */
+extern int disp_node_create(struct disp_object *disp_obj,
+ struct node_object *hnode,
+ u32 rms_fxn,
+ u32 ul_create_fxn,
+ const struct node_createargs
+ *pargs, nodeenv *node_env);
+
+/*
+ * ======== disp_node_delete ========
+ * Delete a node on the DSP by remotely calling the node's delete function.
+ *
+ * Parameters:
+ * disp_obj: Node Dispatcher object.
+ * hnode: Node object representing a node currently
+ * loaded on the DSP.
+ * ul_fxn_addr: Address or RMS delete node function.
+ * ul_delete_fxn: Address of node's delete function.
+ * node_env: Address of node's environment structure.
+ * Returns:
+ * 0: Success.
+ * -ETIME: A timeout occurred before the DSP responded.
+ * Requires:
+ * disp_init(void) called.
+ * Valid disp_obj.
+ * hnode != NULL.
+ * Ensures:
+ */
+extern int disp_node_delete(struct disp_object *disp_obj,
+ struct node_object *hnode,
+ u32 rms_fxn,
+ u32 ul_delete_fxn, nodeenv node_env);
+
+/*
+ * ======== disp_node_run ========
+ * Start execution of a node's execute phase, or resume execution of a node
+ * that has been suspended (via DISP_NodePause()) on the DSP.
+ *
+ * Parameters:
+ * disp_obj: Node Dispatcher object.
+ * hnode: Node object representing a node to be executed
+ * on the DSP.
+ * ul_fxn_addr: Address or RMS node execute function.
+ * ul_execute_fxn: Address of node's execute function.
+ * node_env: Address of node's environment structure.
+ * Returns:
+ * 0: Success.
+ * -ETIME: A timeout occurred before the DSP responded.
+ * Requires:
+ * disp_init(void) called.
+ * Valid disp_obj.
+ * hnode != NULL.
+ * Ensures:
+ */
+extern int disp_node_run(struct disp_object *disp_obj,
+ struct node_object *hnode,
+ u32 rms_fxn,
+ u32 ul_execute_fxn, nodeenv node_env);
+
+#endif /* DISP_ */
diff --git a/drivers/staging/tidspbridge/include/dspbridge/dispdefs.h b/drivers/staging/tidspbridge/include/dspbridge/dispdefs.h
new file mode 100644
index 00000000000..946551a3dbb
--- /dev/null
+++ b/drivers/staging/tidspbridge/include/dspbridge/dispdefs.h
@@ -0,0 +1,35 @@
+/*
+ * dispdefs.h
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * Global DISP constants and types, shared by PROCESSOR, NODE, and DISP.
+ *
+ * Copyright (C) 2005-2006 Texas Instruments, Inc.
+ *
+ * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef DISPDEFS_
+#define DISPDEFS_
+
+struct disp_object;
+
+/* Node Dispatcher attributes */
+struct disp_attr {
+ u32 ul_chnl_offset; /* Offset of channel ids reserved for RMS */
+ /* Size of buffer for sending data to RMS */
+ u32 ul_chnl_buf_size;
+ int proc_family; /* eg, 5000 */
+ int proc_type; /* eg, 5510 */
+ void *reserved1; /* Reserved for future use. */
+ u32 reserved2; /* Reserved for future use. */
+};
+
+#endif /* DISPDEFS_ */
diff --git a/drivers/staging/tidspbridge/include/dspbridge/dmm.h b/drivers/staging/tidspbridge/include/dspbridge/dmm.h
new file mode 100644
index 00000000000..6c58335c5f6
--- /dev/null
+++ b/drivers/staging/tidspbridge/include/dspbridge/dmm.h
@@ -0,0 +1,75 @@
+/*
+ * dmm.h
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * The Dynamic Memory Mapping(DMM) module manages the DSP Virtual address
+ * space that can be directly mapped to any MPU buffer or memory region.
+ *
+ * Copyright (C) 2005-2006 Texas Instruments, Inc.
+ *
+ * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef DMM_
+#define DMM_
+
+#include <dspbridge/dbdefs.h>
+
+struct dmm_object;
+
+/* DMM attributes used in dmm_create() */
+struct dmm_mgrattrs {
+ u32 reserved;
+};
+
+#define DMMPOOLSIZE 0x4000000
+
+/*
+ * ======== dmm_get_handle ========
+ * Purpose:
+ * Return the dynamic memory manager object for this device.
+ * This is typically called from the client process.
+ */
+
+extern int dmm_get_handle(void *hprocessor,
+ struct dmm_object **dmm_manager);
+
+extern int dmm_reserve_memory(struct dmm_object *dmm_mgr,
+ u32 size, u32 *prsv_addr);
+
+extern int dmm_un_reserve_memory(struct dmm_object *dmm_mgr,
+ u32 rsv_addr);
+
+extern int dmm_map_memory(struct dmm_object *dmm_mgr, u32 addr,
+ u32 size);
+
+extern int dmm_un_map_memory(struct dmm_object *dmm_mgr,
+ u32 addr, u32 *psize);
+
+extern int dmm_destroy(struct dmm_object *dmm_mgr);
+
+extern int dmm_delete_tables(struct dmm_object *dmm_mgr);
+
+extern int dmm_create(struct dmm_object **dmm_manager,
+ struct dev_object *hdev_obj,
+ const struct dmm_mgrattrs *mgr_attrts);
+
+extern bool dmm_init(void);
+
+extern void dmm_exit(void);
+
+extern int dmm_create_tables(struct dmm_object *dmm_mgr,
+ u32 addr, u32 size);
+
+#ifdef DSP_DMM_DEBUG
+u32 dmm_mem_map_dump(struct dmm_object *dmm_mgr);
+#endif
+
+#endif /* DMM_ */
diff --git a/drivers/staging/tidspbridge/include/dspbridge/drv.h b/drivers/staging/tidspbridge/include/dspbridge/drv.h
new file mode 100644
index 00000000000..f3650153ef3
--- /dev/null
+++ b/drivers/staging/tidspbridge/include/dspbridge/drv.h
@@ -0,0 +1,521 @@
+/*
+ * drv.h
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * DRV Resource allocation module. Driver Object gets Created
+ * at the time of Loading. It holds the List of Device Objects
+ * in the system.
+ *
+ * Copyright (C) 2005-2006 Texas Instruments, Inc.
+ *
+ * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef DRV_
+#define DRV_
+
+#include <dspbridge/devdefs.h>
+
+#include <dspbridge/drvdefs.h>
+#include <linux/idr.h>
+
+#define DRV_ASSIGN 1
+#define DRV_RELEASE 0
+
+/* Provide the DSP Internal memory windows that can be accessed from L3 address
+ * space */
+
+#define OMAP_GEM_BASE 0x107F8000
+#define OMAP_DSP_SIZE 0x00720000
+
+/* MEM1 is L2 RAM + L2 Cache space */
+#define OMAP_DSP_MEM1_BASE 0x5C7F8000
+#define OMAP_DSP_MEM1_SIZE 0x18000
+#define OMAP_DSP_GEM1_BASE 0x107F8000
+
+/* MEM2 is L1P RAM/CACHE space */
+#define OMAP_DSP_MEM2_BASE 0x5CE00000
+#define OMAP_DSP_MEM2_SIZE 0x8000
+#define OMAP_DSP_GEM2_BASE 0x10E00000
+
+/* MEM3 is L1D RAM/CACHE space */
+#define OMAP_DSP_MEM3_BASE 0x5CF04000
+#define OMAP_DSP_MEM3_SIZE 0x14000
+#define OMAP_DSP_GEM3_BASE 0x10F04000
+
+#define OMAP_IVA2_PRM_BASE 0x48306000
+#define OMAP_IVA2_PRM_SIZE 0x1000
+
+#define OMAP_IVA2_CM_BASE 0x48004000
+#define OMAP_IVA2_CM_SIZE 0x1000
+
+#define OMAP_PER_CM_BASE 0x48005000
+#define OMAP_PER_CM_SIZE 0x1000
+
+#define OMAP_PER_PRM_BASE 0x48307000
+#define OMAP_PER_PRM_SIZE 0x1000
+
+#define OMAP_CORE_PRM_BASE 0x48306A00
+#define OMAP_CORE_PRM_SIZE 0x1000
+
+#define OMAP_SYSC_BASE 0x48002000
+#define OMAP_SYSC_SIZE 0x1000
+
+#define OMAP_DMMU_BASE 0x5D000000
+#define OMAP_DMMU_SIZE 0x1000
+
+#define OMAP_PRCM_VDD1_DOMAIN 1
+#define OMAP_PRCM_VDD2_DOMAIN 2
+
+/* GPP PROCESS CLEANUP Data structures */
+
+/* New structure (member of process context) abstracts NODE resource info */
+struct node_res_object {
+ void *hnode;
+ s32 node_allocated; /* Node status */
+ s32 heap_allocated; /* Heap status */
+ s32 streams_allocated; /* Streams status */
+ int id;
+};
+
+/* used to cache dma mapping information */
+struct bridge_dma_map_info {
+ /* direction of DMA in action, or DMA_NONE */
+ enum dma_data_direction dir;
+ /* number of elements requested by us */
+ int num_pages;
+ /* number of elements returned from dma_map_sg */
+ int sg_num;
+ /* list of buffers used in this DMA action */
+ struct scatterlist *sg;
+};
+
+/* Used for DMM mapped memory accounting */
+struct dmm_map_object {
+ struct list_head link;
+ u32 dsp_addr;
+ u32 mpu_addr;
+ u32 size;
+ u32 num_usr_pgs;
+ struct page **pages;
+ struct bridge_dma_map_info dma_info;
+};
+
+/* Used for DMM reserved memory accounting */
+struct dmm_rsv_object {
+ struct list_head link;
+ u32 dsp_reserved_addr;
+};
+
+/* New structure (member of process context) abstracts DMM resource info */
+struct dspheap_res_object {
+ s32 heap_allocated; /* DMM status */
+ u32 ul_mpu_addr;
+ u32 ul_dsp_addr;
+ u32 ul_dsp_res_addr;
+ u32 heap_size;
+ void *hprocessor;
+ struct dspheap_res_object *next;
+};
+
+/* New structure (member of process context) abstracts stream resource info */
+struct strm_res_object {
+ s32 stream_allocated; /* Stream status */
+ void *hstream;
+ u32 num_bufs;
+ u32 dir;
+ int id;
+};
+
+/* Overall Bridge process resource usage state */
+enum gpp_proc_res_state {
+ PROC_RES_ALLOCATED,
+ PROC_RES_FREED
+};
+
+/* Bridge Data */
+struct drv_data {
+ char *base_img;
+ s32 shm_size;
+ int tc_wordswapon;
+ void *drv_object;
+ void *dev_object;
+ void *mgr_object;
+};
+
+/* Process Context */
+struct process_context {
+ /* Process State */
+ enum gpp_proc_res_state res_state;
+
+ /* Handle to Processor */
+ void *hprocessor;
+
+ /* DSP Node resources */
+ struct idr *node_id;
+
+ /* DMM mapped memory resources */
+ struct list_head dmm_map_list;
+ spinlock_t dmm_map_lock;
+
+ /* DMM reserved memory resources */
+ struct list_head dmm_rsv_list;
+ spinlock_t dmm_rsv_lock;
+
+ /* DSP Heap resources */
+ struct dspheap_res_object *pdspheap_list;
+
+ /* Stream resources */
+ struct idr *stream_id;
+};
+
+/*
+ * ======== drv_create ========
+ * Purpose:
+ * Creates the Driver Object. This is done during the driver loading.
+ * There is only one Driver Object in the DSP/BIOS Bridge.
+ * Parameters:
+ * drv_obj: Location to store created DRV Object handle.
+ * Returns:
+ * 0: Sucess
+ * -ENOMEM: Failed in Memory allocation
+ * -EPERM: General Failure
+ * Requires:
+ * DRV Initialized (refs > 0 )
+ * drv_obj != NULL.
+ * Ensures:
+ * 0: - *drv_obj is a valid DRV interface to the device.
+ * - List of DevObject Created and Initialized.
+ * - List of dev_node String created and intialized.
+ * - Registry is updated with the DRV Object.
+ * !0: DRV Object not created
+ * Details:
+ * There is one Driver Object for the Driver representing
+ * the driver itself. It contains the list of device
+ * Objects and the list of Device Extensions in the system.
+ * Also it can hold other neccessary
+ * information in its storage area.
+ */
+extern int drv_create(struct drv_object **drv_obj);
+
+/*
+ * ======== drv_destroy ========
+ * Purpose:
+ * destroys the Dev Object list, DrvExt list
+ * and destroy the DRV object
+ * Called upon driver unLoading.or unsuccesful loading of the driver.
+ * Parameters:
+ * driver_obj: Handle to Driver object .
+ * Returns:
+ * 0: Success.
+ * -EPERM: Failed to destroy DRV Object
+ * Requires:
+ * DRV Initialized (cRegs > 0 )
+ * hdrv_obj is not NULL and a valid DRV handle .
+ * List of DevObject is Empty.
+ * List of DrvExt is Empty
+ * Ensures:
+ * 0: - DRV Object destroyed and hdrv_obj is not a valid
+ * DRV handle.
+ * - Registry is updated with "0" as the DRV Object.
+ */
+extern int drv_destroy(struct drv_object *driver_obj);
+
+/*
+ * ======== drv_exit ========
+ * Purpose:
+ * Exit the DRV module, freeing any modules initialized in drv_init.
+ * Parameters:
+ * Returns:
+ * Requires:
+ * Ensures:
+ */
+extern void drv_exit(void);
+
+/*
+ * ======== drv_get_first_dev_object ========
+ * Purpose:
+ * Returns the Ptr to the FirstDev Object in the List
+ * Parameters:
+ * Requires:
+ * DRV Initialized
+ * Returns:
+ * dw_dev_object: Ptr to the First Dev Object as a u32
+ * 0 if it fails to retrieve the First Dev Object
+ * Ensures:
+ */
+extern u32 drv_get_first_dev_object(void);
+
+/*
+ * ======== drv_get_first_dev_extension ========
+ * Purpose:
+ * Returns the Ptr to the First Device Extension in the List
+ * Parameters:
+ * Requires:
+ * DRV Initialized
+ * Returns:
+ * dw_dev_extension: Ptr to the First Device Extension as a u32
+ * 0: Failed to Get the Device Extension
+ * Ensures:
+ */
+extern u32 drv_get_first_dev_extension(void);
+
+/*
+ * ======== drv_get_dev_object ========
+ * Purpose:
+ * Given a index, returns a handle to DevObject from the list
+ * Parameters:
+ * hdrv_obj: Handle to the Manager
+ * device_obj: Location to store the Dev Handle
+ * Requires:
+ * DRV Initialized
+ * index >= 0
+ * hdrv_obj is not NULL and Valid DRV Object
+ * device_obj is not NULL
+ * Device Object List not Empty
+ * Returns:
+ * 0: Success
+ * -EPERM: Failed to Get the Dev Object
+ * Ensures:
+ * 0: *device_obj != NULL
+ * -EPERM: *device_obj = NULL
+ */
+extern int drv_get_dev_object(u32 index,
+ struct drv_object *hdrv_obj,
+ struct dev_object **device_obj);
+
+/*
+ * ======== drv_get_next_dev_object ========
+ * Purpose:
+ * Returns the Ptr to the Next Device Object from the the List
+ * Parameters:
+ * hdev_obj: Handle to the Device Object
+ * Requires:
+ * DRV Initialized
+ * hdev_obj != 0
+ * Returns:
+ * dw_dev_object: Ptr to the Next Dev Object as a u32
+ * 0: If it fail to get the next Dev Object.
+ * Ensures:
+ */
+extern u32 drv_get_next_dev_object(u32 hdev_obj);
+
+/*
+ * ======== drv_get_next_dev_extension ========
+ * Purpose:
+ * Returns the Ptr to the Next Device Extension from the the List
+ * Parameters:
+ * dev_extension: Handle to the Device Extension
+ * Requires:
+ * DRV Initialized
+ * dev_extension != 0.
+ * Returns:
+ * dw_dev_extension: Ptr to the Next Dev Extension
+ * 0: If it fail to Get the next Dev Extension
+ * Ensures:
+ */
+extern u32 drv_get_next_dev_extension(u32 dev_extension);
+
+/*
+ * ======== drv_init ========
+ * Purpose:
+ * Initialize the DRV module.
+ * Parameters:
+ * Returns:
+ * TRUE if success; FALSE otherwise.
+ * Requires:
+ * Ensures:
+ */
+extern int drv_init(void);
+
+/*
+ * ======== drv_insert_dev_object ========
+ * Purpose:
+ * Insert a DeviceObject into the list of Driver object.
+ * Parameters:
+ * driver_obj: Handle to DrvObject
+ * hdev_obj: Handle to DeviceObject to insert.
+ * Returns:
+ * 0: If successful.
+ * -EPERM: General Failure:
+ * Requires:
+ * hdrv_obj != NULL and Valid DRV Handle.
+ * hdev_obj != NULL.
+ * Ensures:
+ * 0: Device Object is inserted and the List is not empty.
+ */
+extern int drv_insert_dev_object(struct drv_object *driver_obj,
+ struct dev_object *hdev_obj);
+
+/*
+ * ======== drv_remove_dev_object ========
+ * Purpose:
+ * Search for and remove a Device object from the given list of Device Obj
+ * objects.
+ * Parameters:
+ * driver_obj: Handle to DrvObject
+ * hdev_obj: Handle to DevObject to Remove
+ * Returns:
+ * 0: Success.
+ * -EPERM: Unable to find dev_obj.
+ * Requires:
+ * hdrv_obj != NULL and a Valid DRV Handle.
+ * hdev_obj != NULL.
+ * List exists and is not empty.
+ * Ensures:
+ * List either does not exist (NULL), or is not empty if it does exist.
+ */
+extern int drv_remove_dev_object(struct drv_object *driver_obj,
+ struct dev_object *hdev_obj);
+
+/*
+ * ======== drv_request_resources ========
+ * Purpose:
+ * Assigns the Resources or Releases them.
+ * Parameters:
+ * dw_context: Path to the driver Registry Key.
+ * dev_node_strg: Ptr to dev_node String stored in the Device Ext.
+ * Returns:
+ * TRUE if success; FALSE otherwise.
+ * Requires:
+ * Ensures:
+ * The Resources are assigned based on Bus type.
+ * The hardware is initialized. Resource information is
+ * gathered from the Registry(ISA, PCMCIA)or scanned(PCI)
+ * Resource structure is stored in the registry which will be
+ * later used by the CFG module.
+ */
+extern int drv_request_resources(u32 dw_context,
+ u32 *dev_node_strg);
+
+/*
+ * ======== drv_release_resources ========
+ * Purpose:
+ * Assigns the Resources or Releases them.
+ * Parameters:
+ * dw_context: Path to the driver Registry Key.
+ * hdrv_obj: Handle to the Driver Object.
+ * Returns:
+ * TRUE if success; FALSE otherwise.
+ * Requires:
+ * Ensures:
+ * The Resources are released based on Bus type.
+ * Resource structure is deleted from the registry
+ */
+extern int drv_release_resources(u32 dw_context,
+ struct drv_object *hdrv_obj);
+
+/**
+ * drv_request_bridge_res_dsp() - Reserves shared memory for bridge.
+ * @phost_resources: pointer to host resources.
+ */
+int drv_request_bridge_res_dsp(void **phost_resources);
+
+#ifdef CONFIG_TIDSPBRIDGE_RECOVERY
+void bridge_recover_schedule(void);
+#endif
+
+/*
+ * ======== mem_ext_phys_pool_init ========
+ * Purpose:
+ * Uses the physical memory chunk passed for internal consitent memory
+ * allocations.
+ * physical address based on the page frame address.
+ * Parameters:
+ * pool_phys_base starting address of the physical memory pool.
+ * pool_size size of the physical memory pool.
+ * Returns:
+ * none.
+ * Requires:
+ * - MEM initialized.
+ * - valid physical address for the base and size > 0
+ */
+extern void mem_ext_phys_pool_init(u32 pool_phys_base, u32 pool_size);
+
+/*
+ * ======== mem_ext_phys_pool_release ========
+ */
+extern void mem_ext_phys_pool_release(void);
+
+/* ======== mem_alloc_phys_mem ========
+ * Purpose:
+ * Allocate physically contiguous, uncached memory
+ * Parameters:
+ * byte_size: Number of bytes to allocate.
+ * align_mask: Alignment Mask.
+ * physical_address: Physical address of allocated memory.
+ * Returns:
+ * Pointer to a block of memory;
+ * NULL if memory couldn't be allocated, or if byte_size == 0.
+ * Requires:
+ * MEM initialized.
+ * Ensures:
+ * The returned pointer, if not NULL, points to a valid memory block of
+ * the size requested. Returned physical address refers to physical
+ * location of memory.
+ */
+extern void *mem_alloc_phys_mem(u32 byte_size,
+ u32 align_mask, u32 *physical_address);
+
+/*
+ * ======== mem_free_phys_mem ========
+ * Purpose:
+ * Free the given block of physically contiguous memory.
+ * Parameters:
+ * virtual_address: Pointer to virtual memory region allocated
+ * by mem_alloc_phys_mem().
+ * physical_address: Pointer to physical memory region allocated
+ * by mem_alloc_phys_mem().
+ * byte_size: Size of the memory region allocated by mem_alloc_phys_mem().
+ * Returns:
+ * Requires:
+ * MEM initialized.
+ * virtual_address is a valid memory address returned by
+ * mem_alloc_phys_mem()
+ * Ensures:
+ * virtual_address is no longer a valid pointer to memory.
+ */
+extern void mem_free_phys_mem(void *virtual_address,
+ u32 physical_address, u32 byte_size);
+
+/*
+ * ======== MEM_LINEAR_ADDRESS ========
+ * Purpose:
+ * Get the linear address corresponding to the given physical address.
+ * Parameters:
+ * phys_addr: Physical address to be mapped.
+ * byte_size: Number of bytes in physical range to map.
+ * Returns:
+ * The corresponding linear address, or NULL if unsuccessful.
+ * Requires:
+ * MEM initialized.
+ * Ensures:
+ * Notes:
+ * If valid linear address is returned, be sure to call
+ * MEM_UNMAP_LINEAR_ADDRESS().
+ */
+#define MEM_LINEAR_ADDRESS(phy_addr, byte_size) phy_addr
+
+/*
+ * ======== MEM_UNMAP_LINEAR_ADDRESS ========
+ * Purpose:
+ * Unmap the linear address mapped in MEM_LINEAR_ADDRESS.
+ * Parameters:
+ * base_addr: Ptr to mapped memory (as returned by MEM_LINEAR_ADDRESS()).
+ * Returns:
+ * Requires:
+ * - MEM initialized.
+ * - base_addr is a valid linear address mapped in MEM_LINEAR_ADDRESS.
+ * Ensures:
+ * - base_addr no longer points to a valid linear address.
+ */
+#define MEM_UNMAP_LINEAR_ADDRESS(base_addr) {}
+
+#endif /* DRV_ */
diff --git a/drivers/staging/tidspbridge/include/dspbridge/drvdefs.h b/drivers/staging/tidspbridge/include/dspbridge/drvdefs.h
new file mode 100644
index 00000000000..2920917bbc5
--- /dev/null
+++ b/drivers/staging/tidspbridge/include/dspbridge/drvdefs.h
@@ -0,0 +1,25 @@
+/*
+ * drvdefs.h
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * Definition of common struct between dspdefs.h and drv.h.
+ *
+ * Copyright (C) 2005-2006 Texas Instruments, Inc.
+ *
+ * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef DRVDEFS_
+#define DRVDEFS_
+
+/* Bridge Driver Object */
+struct drv_object;
+
+#endif /* DRVDEFS_ */
diff --git a/drivers/staging/tidspbridge/include/dspbridge/dspapi-ioctl.h b/drivers/staging/tidspbridge/include/dspbridge/dspapi-ioctl.h
new file mode 100644
index 00000000000..8da5bd8ede8
--- /dev/null
+++ b/drivers/staging/tidspbridge/include/dspbridge/dspapi-ioctl.h
@@ -0,0 +1,475 @@
+/*
+ * dspapi-ioctl.h
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * Contains structures and commands that are used for interaction
+ * between the DDSP API and Bridge driver.
+ *
+ * Copyright (C) 2008 Texas Instruments, Inc.
+ *
+ * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef DSPAPIIOCTL_
+#define DSPAPIIOCTL_
+
+#include <dspbridge/cmm.h>
+#include <dspbridge/strmdefs.h>
+#include <dspbridge/dbdcd.h>
+
+union trapped_args {
+
+ /* MGR Module */
+ struct {
+ u32 node_id;
+ struct dsp_ndbprops __user *pndb_props;
+ u32 undb_props_size;
+ u32 __user *pu_num_nodes;
+ } args_mgr_enumnode_info;
+
+ struct {
+ u32 processor_id;
+ struct dsp_processorinfo __user *processor_info;
+ u32 processor_info_size;
+ u32 __user *pu_num_procs;
+ } args_mgr_enumproc_info;
+
+ struct {
+ struct dsp_uuid *uuid_obj;
+ enum dsp_dcdobjtype obj_type;
+ char *psz_path_name;
+ } args_mgr_registerobject;
+
+ struct {
+ struct dsp_uuid *uuid_obj;
+ enum dsp_dcdobjtype obj_type;
+ } args_mgr_unregisterobject;
+
+ struct {
+ struct dsp_notification __user *__user *anotifications;
+ u32 count;
+ u32 __user *pu_index;
+ u32 utimeout;
+ } args_mgr_wait;
+
+ /* PROC Module */
+ struct {
+ u32 processor_id;
+ struct dsp_processorattrin __user *attr_in;
+ void *__user *ph_processor;
+ } args_proc_attach;
+
+ struct {
+ void *hprocessor;
+ u32 dw_cmd;
+ struct dsp_cbdata __user *pargs;
+ } args_proc_ctrl;
+
+ struct {
+ void *hprocessor;
+ } args_proc_detach;
+
+ struct {
+ void *hprocessor;
+ void *__user *node_tab;
+ u32 node_tab_size;
+ u32 __user *pu_num_nodes;
+ u32 __user *pu_allocated;
+ } args_proc_enumnode_info;
+
+ struct {
+ void *hprocessor;
+ u32 resource_type;
+ struct dsp_resourceinfo *resource_info;
+ u32 resource_info_size;
+ } args_proc_enumresources;
+
+ struct {
+ void *hprocessor;
+ struct dsp_processorstate __user *proc_state_obj;
+ u32 state_info_size;
+ } args_proc_getstate;
+
+ struct {
+ void *hprocessor;
+ u8 __user *pbuf;
+ u8 __user *psize;
+ u32 max_size;
+ } args_proc_gettrace;
+
+ struct {
+ void *hprocessor;
+ s32 argc_index;
+ char __user *__user *user_args;
+ char *__user *user_envp;
+ } args_proc_load;
+
+ struct {
+ void *hprocessor;
+ u32 event_mask;
+ u32 notify_type;
+ struct dsp_notification __user *hnotification;
+ } args_proc_register_notify;
+
+ struct {
+ void *hprocessor;
+ } args_proc_start;
+
+ struct {
+ void *hprocessor;
+ u32 ul_size;
+ void *__user *pp_rsv_addr;
+ } args_proc_rsvmem;
+
+ struct {
+ void *hprocessor;
+ u32 ul_size;
+ void *prsv_addr;
+ } args_proc_unrsvmem;
+
+ struct {
+ void *hprocessor;
+ void *pmpu_addr;
+ u32 ul_size;
+ void *req_addr;
+ void *__user *pp_map_addr;
+ u32 ul_map_attr;
+ } args_proc_mapmem;
+
+ struct {
+ void *hprocessor;
+ u32 ul_size;
+ void *map_addr;
+ } args_proc_unmapmem;
+
+ struct {
+ void *hprocessor;
+ void *pmpu_addr;
+ u32 ul_size;
+ u32 dir;
+ } args_proc_dma;
+
+ struct {
+ void *hprocessor;
+ void *pmpu_addr;
+ u32 ul_size;
+ u32 ul_flags;
+ } args_proc_flushmemory;
+
+ struct {
+ void *hprocessor;
+ } args_proc_stop;
+
+ struct {
+ void *hprocessor;
+ void *pmpu_addr;
+ u32 ul_size;
+ } args_proc_invalidatememory;
+
+ /* NODE Module */
+ struct {
+ void *hprocessor;
+ struct dsp_uuid __user *node_id_ptr;
+ struct dsp_cbdata __user *pargs;
+ struct dsp_nodeattrin __user *attr_in;
+ void *__user *ph_node;
+ } args_node_allocate;
+
+ struct {
+ void *hnode;
+ u32 usize;
+ struct dsp_bufferattr __user *pattr;
+ u8 *__user *pbuffer;
+ } args_node_allocmsgbuf;
+
+ struct {
+ void *hnode;
+ s32 prio;
+ } args_node_changepriority;
+
+ struct {
+ void *hnode;
+ u32 stream_id;
+ void *other_node;
+ u32 other_stream;
+ struct dsp_strmattr __user *pattrs;
+ struct dsp_cbdata __user *conn_param;
+ } args_node_connect;
+
+ struct {
+ void *hnode;
+ } args_node_create;
+
+ struct {
+ void *hnode;
+ } args_node_delete;
+
+ struct {
+ void *hnode;
+ struct dsp_bufferattr __user *pattr;
+ u8 *pbuffer;
+ } args_node_freemsgbuf;
+
+ struct {
+ void *hnode;
+ struct dsp_nodeattr __user *pattr;
+ u32 attr_size;
+ } args_node_getattr;
+
+ struct {
+ void *hnode;
+ struct dsp_msg __user *message;
+ u32 utimeout;
+ } args_node_getmessage;
+
+ struct {
+ void *hnode;
+ } args_node_pause;
+
+ struct {
+ void *hnode;
+ struct dsp_msg __user *message;
+ u32 utimeout;
+ } args_node_putmessage;
+
+ struct {
+ void *hnode;
+ u32 event_mask;
+ u32 notify_type;
+ struct dsp_notification __user *hnotification;
+ } args_node_registernotify;
+
+ struct {
+ void *hnode;
+ } args_node_run;
+
+ struct {
+ void *hnode;
+ int __user *pstatus;
+ } args_node_terminate;
+
+ struct {
+ void *hprocessor;
+ struct dsp_uuid __user *node_id_ptr;
+ struct dsp_ndbprops __user *node_props;
+ } args_node_getuuidprops;
+
+ /* STRM module */
+
+ struct {
+ void *hstream;
+ u32 usize;
+ u8 *__user *ap_buffer;
+ u32 num_bufs;
+ } args_strm_allocatebuffer;
+
+ struct {
+ void *hstream;
+ } args_strm_close;
+
+ struct {
+ void *hstream;
+ u8 *__user *ap_buffer;
+ u32 num_bufs;
+ } args_strm_freebuffer;
+
+ struct {
+ void *hstream;
+ void **ph_event;
+ } args_strm_geteventhandle;
+
+ struct {
+ void *hstream;
+ struct stream_info __user *stream_info;
+ u32 stream_info_size;
+ } args_strm_getinfo;
+
+ struct {
+ void *hstream;
+ bool flush_flag;
+ } args_strm_idle;
+
+ struct {
+ void *hstream;
+ u8 *pbuffer;
+ u32 dw_bytes;
+ u32 dw_buf_size;
+ u32 dw_arg;
+ } args_strm_issue;
+
+ struct {
+ void *hnode;
+ u32 direction;
+ u32 index;
+ struct strm_attr __user *attr_in;
+ void *__user *ph_stream;
+ } args_strm_open;
+
+ struct {
+ void *hstream;
+ u8 *__user *buf_ptr;
+ u32 __user *bytes;
+ u32 __user *buf_size_ptr;
+ u32 __user *pdw_arg;
+ } args_strm_reclaim;
+
+ struct {
+ void *hstream;
+ u32 event_mask;
+ u32 notify_type;
+ struct dsp_notification __user *hnotification;
+ } args_strm_registernotify;
+
+ struct {
+ void *__user *stream_tab;
+ u32 strm_num;
+ u32 __user *pmask;
+ u32 utimeout;
+ } args_strm_select;
+
+ /* CMM Module */
+ struct {
+ struct cmm_object *hcmm_mgr;
+ u32 usize;
+ struct cmm_attrs *pattrs;
+ void **pp_buf_va;
+ } args_cmm_allocbuf;
+
+ struct {
+ struct cmm_object *hcmm_mgr;
+ void *buf_pa;
+ u32 ul_seg_id;
+ } args_cmm_freebuf;
+
+ struct {
+ void *hprocessor;
+ struct cmm_object *__user *ph_cmm_mgr;
+ } args_cmm_gethandle;
+
+ struct {
+ struct cmm_object *hcmm_mgr;
+ struct cmm_info __user *cmm_info_obj;
+ } args_cmm_getinfo;
+
+ /* UTIL module */
+ struct {
+ s32 util_argc;
+ char **pp_argv;
+ } args_util_testdll;
+};
+
+/*
+ * Dspbridge Ioctl numbering scheme
+ *
+ * 7 0
+ * ---------------------------------
+ * | Module | Ioctl Number |
+ * ---------------------------------
+ * | x | x | x | 0 | 0 | 0 | 0 | 0 |
+ * ---------------------------------
+ */
+
+/* Ioctl driver identifier */
+#define DB 0xDB
+
+/*
+ * Following are used to distinguish between module ioctls, this is needed
+ * in case new ioctls are introduced.
+ */
+#define DB_MODULE_MASK 0xE0
+#define DB_IOC_MASK 0x1F
+
+/* Ioctl module masks */
+#define DB_MGR 0x0
+#define DB_PROC 0x20
+#define DB_NODE 0x40
+#define DB_STRM 0x60
+#define DB_CMM 0x80
+
+#define DB_MODULE_SHIFT 5
+
+/* Used to calculate the ioctl per dspbridge module */
+#define DB_IOC(module, num) \
+ (((module) & DB_MODULE_MASK) | ((num) & DB_IOC_MASK))
+/* Used to get dspbridge ioctl module */
+#define DB_GET_MODULE(cmd) ((cmd) & DB_MODULE_MASK)
+/* Used to get dspbridge ioctl number */
+#define DB_GET_IOC(cmd) ((cmd) & DB_IOC_MASK)
+
+/* TODO: Remove deprecated and not implemented */
+
+/* MGR Module */
+#define MGR_ENUMNODE_INFO _IOWR(DB, DB_IOC(DB_MGR, 0), unsigned long)
+#define MGR_ENUMPROC_INFO _IOWR(DB, DB_IOC(DB_MGR, 1), unsigned long)
+#define MGR_REGISTEROBJECT _IOWR(DB, DB_IOC(DB_MGR, 2), unsigned long)
+#define MGR_UNREGISTEROBJECT _IOWR(DB, DB_IOC(DB_MGR, 3), unsigned long)
+#define MGR_WAIT _IOWR(DB, DB_IOC(DB_MGR, 4), unsigned long)
+/* MGR_GET_PROC_RES Deprecated */
+#define MGR_GET_PROC_RES _IOR(DB, DB_IOC(DB_MGR, 5), unsigned long)
+
+/* PROC Module */
+#define PROC_ATTACH _IOWR(DB, DB_IOC(DB_PROC, 0), unsigned long)
+#define PROC_CTRL _IOR(DB, DB_IOC(DB_PROC, 1), unsigned long)
+/* PROC_DETACH Deprecated */
+#define PROC_DETACH _IOR(DB, DB_IOC(DB_PROC, 2), unsigned long)
+#define PROC_ENUMNODE _IOWR(DB, DB_IOC(DB_PROC, 3), unsigned long)
+#define PROC_ENUMRESOURCES _IOWR(DB, DB_IOC(DB_PROC, 4), unsigned long)
+#define PROC_GET_STATE _IOWR(DB, DB_IOC(DB_PROC, 5), unsigned long)
+#define PROC_GET_TRACE _IOWR(DB, DB_IOC(DB_PROC, 6), unsigned long)
+#define PROC_LOAD _IOW(DB, DB_IOC(DB_PROC, 7), unsigned long)
+#define PROC_REGISTERNOTIFY _IOWR(DB, DB_IOC(DB_PROC, 8), unsigned long)
+#define PROC_START _IOW(DB, DB_IOC(DB_PROC, 9), unsigned long)
+#define PROC_RSVMEM _IOWR(DB, DB_IOC(DB_PROC, 10), unsigned long)
+#define PROC_UNRSVMEM _IOW(DB, DB_IOC(DB_PROC, 11), unsigned long)
+#define PROC_MAPMEM _IOWR(DB, DB_IOC(DB_PROC, 12), unsigned long)
+#define PROC_UNMAPMEM _IOR(DB, DB_IOC(DB_PROC, 13), unsigned long)
+#define PROC_FLUSHMEMORY _IOW(DB, DB_IOC(DB_PROC, 14), unsigned long)
+#define PROC_STOP _IOWR(DB, DB_IOC(DB_PROC, 15), unsigned long)
+#define PROC_INVALIDATEMEMORY _IOW(DB, DB_IOC(DB_PROC, 16), unsigned long)
+#define PROC_BEGINDMA _IOW(DB, DB_IOC(DB_PROC, 17), unsigned long)
+#define PROC_ENDDMA _IOW(DB, DB_IOC(DB_PROC, 18), unsigned long)
+
+/* NODE Module */
+#define NODE_ALLOCATE _IOWR(DB, DB_IOC(DB_NODE, 0), unsigned long)
+#define NODE_ALLOCMSGBUF _IOWR(DB, DB_IOC(DB_NODE, 1), unsigned long)
+#define NODE_CHANGEPRIORITY _IOW(DB, DB_IOC(DB_NODE, 2), unsigned long)
+#define NODE_CONNECT _IOW(DB, DB_IOC(DB_NODE, 3), unsigned long)
+#define NODE_CREATE _IOW(DB, DB_IOC(DB_NODE, 4), unsigned long)
+#define NODE_DELETE _IOW(DB, DB_IOC(DB_NODE, 5), unsigned long)
+#define NODE_FREEMSGBUF _IOW(DB, DB_IOC(DB_NODE, 6), unsigned long)
+#define NODE_GETATTR _IOWR(DB, DB_IOC(DB_NODE, 7), unsigned long)
+#define NODE_GETMESSAGE _IOWR(DB, DB_IOC(DB_NODE, 8), unsigned long)
+#define NODE_PAUSE _IOW(DB, DB_IOC(DB_NODE, 9), unsigned long)
+#define NODE_PUTMESSAGE _IOW(DB, DB_IOC(DB_NODE, 10), unsigned long)
+#define NODE_REGISTERNOTIFY _IOWR(DB, DB_IOC(DB_NODE, 11), unsigned long)
+#define NODE_RUN _IOW(DB, DB_IOC(DB_NODE, 12), unsigned long)
+#define NODE_TERMINATE _IOWR(DB, DB_IOC(DB_NODE, 13), unsigned long)
+#define NODE_GETUUIDPROPS _IOWR(DB, DB_IOC(DB_NODE, 14), unsigned long)
+
+/* STRM Module */
+#define STRM_ALLOCATEBUFFER _IOWR(DB, DB_IOC(DB_STRM, 0), unsigned long)
+#define STRM_CLOSE _IOW(DB, DB_IOC(DB_STRM, 1), unsigned long)
+#define STRM_FREEBUFFER _IOWR(DB, DB_IOC(DB_STRM, 2), unsigned long)
+#define STRM_GETEVENTHANDLE _IO(DB, DB_IOC(DB_STRM, 3)) /* Not Impl'd */
+#define STRM_GETINFO _IOWR(DB, DB_IOC(DB_STRM, 4), unsigned long)
+#define STRM_IDLE _IOW(DB, DB_IOC(DB_STRM, 5), unsigned long)
+#define STRM_ISSUE _IOW(DB, DB_IOC(DB_STRM, 6), unsigned long)
+#define STRM_OPEN _IOWR(DB, DB_IOC(DB_STRM, 7), unsigned long)
+#define STRM_RECLAIM _IOWR(DB, DB_IOC(DB_STRM, 8), unsigned long)
+#define STRM_REGISTERNOTIFY _IOWR(DB, DB_IOC(DB_STRM, 9), unsigned long)
+#define STRM_SELECT _IOWR(DB, DB_IOC(DB_STRM, 10), unsigned long)
+
+/* CMM Module */
+#define CMM_ALLOCBUF _IO(DB, DB_IOC(DB_CMM, 0)) /* Not Impl'd */
+#define CMM_FREEBUF _IO(DB, DB_IOC(DB_CMM, 1)) /* Not Impl'd */
+#define CMM_GETHANDLE _IOR(DB, DB_IOC(DB_CMM, 2), unsigned long)
+#define CMM_GETINFO _IOR(DB, DB_IOC(DB_CMM, 3), unsigned long)
+
+#endif /* DSPAPIIOCTL_ */
diff --git a/drivers/staging/tidspbridge/include/dspbridge/dspapi.h b/drivers/staging/tidspbridge/include/dspbridge/dspapi.h
new file mode 100644
index 00000000000..c99c68738b0
--- /dev/null
+++ b/drivers/staging/tidspbridge/include/dspbridge/dspapi.h
@@ -0,0 +1,167 @@
+/*
+ * dspapi.h
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * Includes the wrapper functions called directly by the
+ * DeviceIOControl interface.
+ *
+ * Notes:
+ * Bridge services exported to Bridge driver are initialized by the DSPAPI on
+ * behalf of the Bridge driver. Bridge driver must not call module Init/Exit
+ * functions.
+ *
+ * To ensure Bridge driver binary compatibility across different platforms,
+ * for the same processor, a Bridge driver must restrict its usage of system
+ * services to those exported by the DSPAPI library.
+ *
+ * Copyright (C) 2005-2006 Texas Instruments, Inc.
+ *
+ * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef DSPAPI_
+#define DSPAPI_
+
+#include <dspbridge/dspapi-ioctl.h>
+
+/* This BRD API Library Version: */
+#define BRD_API_MAJOR_VERSION (u32)8 /* .8x - Alpha, .9x - Beta, 1.x FCS */
+#define BRD_API_MINOR_VERSION (u32)0
+
+/*
+ * ======== api_call_dev_ioctl ========
+ * Purpose:
+ * Call the (wrapper) function for the corresponding API IOCTL.
+ * Parameters:
+ * cmd: IOCTL id, base 0.
+ * args: Argument structure.
+ * result:
+ * Returns:
+ * 0 if command called; -EINVAL if command not in IOCTL
+ * table.
+ * Requires:
+ * Ensures:
+ */
+extern int api_call_dev_ioctl(unsigned int cmd,
+ union trapped_args *args,
+ u32 *result, void *pr_ctxt);
+
+/*
+ * ======== api_init ========
+ * Purpose:
+ * Initialize modules used by Bridge API.
+ * This procedure is called when the driver is loaded.
+ * Parameters:
+ * Returns:
+ * TRUE if success; FALSE otherwise.
+ * Requires:
+ * Ensures:
+ */
+extern bool api_init(void);
+
+/*
+ * ======== api_init_complete2 ========
+ * Purpose:
+ * Perform any required bridge initialization which cannot
+ * be performed in api_init() or dev_start_device() due
+ * to the fact that some services are not yet
+ * completely initialized.
+ * Parameters:
+ * Returns:
+ * 0: Allow this device to load
+ * -EPERM: Failure.
+ * Requires:
+ * Bridge API initialized.
+ * Ensures:
+ */
+extern int api_init_complete2(void);
+
+/*
+ * ======== api_exit ========
+ * Purpose:
+ * Exit all modules initialized in api_init(void).
+ * This procedure is called when the driver is unloaded.
+ * Parameters:
+ * Returns:
+ * Requires:
+ * api_init(void) was previously called.
+ * Ensures:
+ * Resources acquired in api_init(void) are freed.
+ */
+extern void api_exit(void);
+
+/* MGR wrapper functions */
+extern u32 mgrwrap_enum_node_info(union trapped_args *args, void *pr_ctxt);
+extern u32 mgrwrap_enum_proc_info(union trapped_args *args, void *pr_ctxt);
+extern u32 mgrwrap_register_object(union trapped_args *args, void *pr_ctxt);
+extern u32 mgrwrap_unregister_object(union trapped_args *args, void *pr_ctxt);
+extern u32 mgrwrap_wait_for_bridge_events(union trapped_args *args,
+ void *pr_ctxt);
+
+extern u32 mgrwrap_get_process_resources_info(union trapped_args *args,
+ void *pr_ctxt);
+
+/* CPRC (Processor) wrapper Functions */
+extern u32 procwrap_attach(union trapped_args *args, void *pr_ctxt);
+extern u32 procwrap_ctrl(union trapped_args *args, void *pr_ctxt);
+extern u32 procwrap_detach(union trapped_args *args, void *pr_ctxt);
+extern u32 procwrap_enum_node_info(union trapped_args *args, void *pr_ctxt);
+extern u32 procwrap_enum_resources(union trapped_args *args, void *pr_ctxt);
+extern u32 procwrap_get_state(union trapped_args *args, void *pr_ctxt);
+extern u32 procwrap_get_trace(union trapped_args *args, void *pr_ctxt);
+extern u32 procwrap_load(union trapped_args *args, void *pr_ctxt);
+extern u32 procwrap_register_notify(union trapped_args *args, void *pr_ctxt);
+extern u32 procwrap_start(union trapped_args *args, void *pr_ctxt);
+extern u32 procwrap_reserve_memory(union trapped_args *args, void *pr_ctxt);
+extern u32 procwrap_un_reserve_memory(union trapped_args *args, void *pr_ctxt);
+extern u32 procwrap_map(union trapped_args *args, void *pr_ctxt);
+extern u32 procwrap_un_map(union trapped_args *args, void *pr_ctxt);
+extern u32 procwrap_flush_memory(union trapped_args *args, void *pr_ctxt);
+extern u32 procwrap_stop(union trapped_args *args, void *pr_ctxt);
+extern u32 procwrap_invalidate_memory(union trapped_args *args, void *pr_ctxt);
+extern u32 procwrap_begin_dma(union trapped_args *args, void *pr_ctxt);
+extern u32 procwrap_end_dma(union trapped_args *args, void *pr_ctxt);
+
+/* NODE wrapper functions */
+extern u32 nodewrap_allocate(union trapped_args *args, void *pr_ctxt);
+extern u32 nodewrap_alloc_msg_buf(union trapped_args *args, void *pr_ctxt);
+extern u32 nodewrap_change_priority(union trapped_args *args, void *pr_ctxt);
+extern u32 nodewrap_connect(union trapped_args *args, void *pr_ctxt);
+extern u32 nodewrap_create(union trapped_args *args, void *pr_ctxt);
+extern u32 nodewrap_delete(union trapped_args *args, void *pr_ctxt);
+extern u32 nodewrap_free_msg_buf(union trapped_args *args, void *pr_ctxt);
+extern u32 nodewrap_get_attr(union trapped_args *args, void *pr_ctxt);
+extern u32 nodewrap_get_message(union trapped_args *args, void *pr_ctxt);
+extern u32 nodewrap_pause(union trapped_args *args, void *pr_ctxt);
+extern u32 nodewrap_put_message(union trapped_args *args, void *pr_ctxt);
+extern u32 nodewrap_register_notify(union trapped_args *args, void *pr_ctxt);
+extern u32 nodewrap_run(union trapped_args *args, void *pr_ctxt);
+extern u32 nodewrap_terminate(union trapped_args *args, void *pr_ctxt);
+extern u32 nodewrap_get_uuid_props(union trapped_args *args, void *pr_ctxt);
+
+/* STRM wrapper functions */
+extern u32 strmwrap_allocate_buffer(union trapped_args *args, void *pr_ctxt);
+extern u32 strmwrap_close(union trapped_args *args, void *pr_ctxt);
+extern u32 strmwrap_free_buffer(union trapped_args *args, void *pr_ctxt);
+extern u32 strmwrap_get_event_handle(union trapped_args *args, void *pr_ctxt);
+extern u32 strmwrap_get_info(union trapped_args *args, void *pr_ctxt);
+extern u32 strmwrap_idle(union trapped_args *args, void *pr_ctxt);
+extern u32 strmwrap_issue(union trapped_args *args, void *pr_ctxt);
+extern u32 strmwrap_open(union trapped_args *args, void *pr_ctxt);
+extern u32 strmwrap_reclaim(union trapped_args *args, void *pr_ctxt);
+extern u32 strmwrap_register_notify(union trapped_args *args, void *pr_ctxt);
+extern u32 strmwrap_select(union trapped_args *args, void *pr_ctxt);
+
+extern u32 cmmwrap_calloc_buf(union trapped_args *args, void *pr_ctxt);
+extern u32 cmmwrap_free_buf(union trapped_args *args, void *pr_ctxt);
+extern u32 cmmwrap_get_handle(union trapped_args *args, void *pr_ctxt);
+extern u32 cmmwrap_get_info(union trapped_args *args, void *pr_ctxt);
+
+#endif /* DSPAPI_ */
diff --git a/drivers/staging/tidspbridge/include/dspbridge/dspchnl.h b/drivers/staging/tidspbridge/include/dspbridge/dspchnl.h
new file mode 100644
index 00000000000..7146a5057e2
--- /dev/null
+++ b/drivers/staging/tidspbridge/include/dspbridge/dspchnl.h
@@ -0,0 +1,72 @@
+/*
+ * dspchnl.h
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * Declares the upper edge channel class library functions required by
+ * all Bridge driver / DSP API driver interface tables. These functions are
+ * implemented by every class of Bridge channel library.
+ *
+ * Notes:
+ * The function comment headers reside in dspdefs.h.
+ *
+ * Copyright (C) 2005-2006 Texas Instruments, Inc.
+ *
+ * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef DSPCHNL_
+#define DSPCHNL_
+
+extern int bridge_chnl_create(struct chnl_mgr **channel_mgr,
+ struct dev_object *hdev_obj,
+ const struct chnl_mgrattrs
+ *mgr_attrts);
+
+extern int bridge_chnl_destroy(struct chnl_mgr *hchnl_mgr);
+
+extern int bridge_chnl_open(struct chnl_object **chnl,
+ struct chnl_mgr *hchnl_mgr,
+ s8 chnl_mode,
+ u32 ch_id,
+ const struct chnl_attr
+ *pattrs);
+
+extern int bridge_chnl_close(struct chnl_object *chnl_obj);
+
+extern int bridge_chnl_add_io_req(struct chnl_object *chnl_obj,
+ void *host_buf,
+ u32 byte_size, u32 buf_size,
+ u32 dw_dsp_addr, u32 dw_arg);
+
+extern int bridge_chnl_get_ioc(struct chnl_object *chnl_obj,
+ u32 timeout, struct chnl_ioc *chan_ioc);
+
+extern int bridge_chnl_cancel_io(struct chnl_object *chnl_obj);
+
+extern int bridge_chnl_flush_io(struct chnl_object *chnl_obj,
+ u32 timeout);
+
+extern int bridge_chnl_get_info(struct chnl_object *chnl_obj,
+ struct chnl_info *channel_info);
+
+extern int bridge_chnl_get_mgr_info(struct chnl_mgr *hchnl_mgr,
+ u32 ch_id, struct chnl_mgrinfo
+ *mgr_info);
+
+extern int bridge_chnl_idle(struct chnl_object *chnl_obj,
+ u32 timeout, bool flush_data);
+
+extern int bridge_chnl_register_notify(struct chnl_object *chnl_obj,
+ u32 event_mask,
+ u32 notify_type,
+ struct dsp_notification
+ *hnotification);
+
+#endif /* DSPCHNL_ */
diff --git a/drivers/staging/tidspbridge/include/dspbridge/dspdefs.h b/drivers/staging/tidspbridge/include/dspbridge/dspdefs.h
new file mode 100644
index 00000000000..0ae7d1646a1
--- /dev/null
+++ b/drivers/staging/tidspbridge/include/dspbridge/dspdefs.h
@@ -0,0 +1,1054 @@
+/*
+ * dspdefs.h
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * Bridge driver entry point and interface function declarations.
+ *
+ * Notes:
+ * The DSP API obtains it's function interface to
+ * the Bridge driver via a call to bridge_drv_entry().
+ *
+ * Bridge services exported to Bridge drivers are initialized by the
+ * DSP API on behalf of the Bridge driver.
+ *
+ * Bridge function DBC Requires and Ensures are also made by the DSP API on
+ * behalf of the Bridge driver, to simplify the Bridge driver code.
+ *
+ * Copyright (C) 2005-2006 Texas Instruments, Inc.
+ *
+ * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef DSPDEFS_
+#define DSPDEFS_
+
+#include <dspbridge/brddefs.h>
+#include <dspbridge/cfgdefs.h>
+#include <dspbridge/chnlpriv.h>
+#include <dspbridge/dehdefs.h>
+#include <dspbridge/devdefs.h>
+#include <dspbridge/iodefs.h>
+#include <dspbridge/msgdefs.h>
+
+/*
+ * Any IOCTLS at or above this value are reserved for standard Bridge driver
+ * interfaces.
+ */
+#define BRD_RESERVEDIOCTLBASE 0x8000
+
+/* Handle to Bridge driver's private device context. */
+struct bridge_dev_context;
+
+/*--------------------------------------------------------------------------- */
+/* BRIDGE DRIVER FUNCTION TYPES */
+/*--------------------------------------------------------------------------- */
+
+/*
+ * ======== bridge_brd_monitor ========
+ * Purpose:
+ * Bring the board to the BRD_IDLE (monitor) state.
+ * Parameters:
+ * dev_ctxt: Handle to Bridge driver defined device context.
+ * Returns:
+ * 0: Success.
+ * -ETIMEDOUT: Timeout occured waiting for a response from hardware.
+ * -EPERM: Other, unspecified error.
+ * Requires:
+ * dev_ctxt != NULL
+ * Ensures:
+ * 0: Board is in BRD_IDLE state;
+ * else: Board state is indeterminate.
+ */
+typedef int(*fxn_brd_monitor) (struct bridge_dev_context *dev_ctxt);
+
+/*
+ * ======== fxn_brd_setstate ========
+ * Purpose:
+ * Sets the Bridge driver state
+ * Parameters:
+ * dev_ctxt: Handle to Bridge driver defined device info.
+ * brd_state: Board state
+ * Returns:
+ * 0: Success.
+ * -EPERM: Other, unspecified error.
+ * Requires:
+ * dev_ctxt != NULL;
+ * brd_state <= BRD_LASTSTATE.
+ * Ensures:
+ * brd_state <= BRD_LASTSTATE.
+ * Update the Board state to the specified state.
+ */
+typedef int(*fxn_brd_setstate) (struct bridge_dev_context
+ * dev_ctxt, u32 brd_state);
+
+/*
+ * ======== bridge_brd_start ========
+ * Purpose:
+ * Bring board to the BRD_RUNNING (start) state.
+ * Parameters:
+ * dev_ctxt: Handle to Bridge driver defined device context.
+ * dsp_addr: DSP address at which to start execution.
+ * Returns:
+ * 0: Success.
+ * -ETIMEDOUT: Timeout occured waiting for a response from hardware.
+ * -EPERM: Other, unspecified error.
+ * Requires:
+ * dev_ctxt != NULL
+ * Board is in monitor (BRD_IDLE) state.
+ * Ensures:
+ * 0: Board is in BRD_RUNNING state.
+ * Interrupts to the PC are enabled.
+ * else: Board state is indeterminate.
+ */
+typedef int(*fxn_brd_start) (struct bridge_dev_context
+ * dev_ctxt, u32 dsp_addr);
+
+/*
+ * ======== bridge_brd_mem_copy ========
+ * Purpose:
+ * Copy memory from one DSP address to another
+ * Parameters:
+ * dev_context: Pointer to context handle
+ * dsp_dest_addr: DSP address to copy to
+ * dsp_src_addr: DSP address to copy from
+ * ul_num_bytes: Number of bytes to copy
+ * mem_type: What section of memory to copy to
+ * Returns:
+ * 0: Success.
+ * -EPERM: Other, unspecified error.
+ * Requires:
+ * dev_context != NULL
+ * Ensures:
+ * 0: Board is in BRD_RUNNING state.
+ * Interrupts to the PC are enabled.
+ * else: Board state is indeterminate.
+ */
+typedef int(*fxn_brd_memcopy) (struct bridge_dev_context
+ * dev_ctxt,
+ u32 dsp_dest_addr,
+ u32 dsp_src_addr,
+ u32 ul_num_bytes, u32 mem_type);
+/*
+ * ======== bridge_brd_mem_write ========
+ * Purpose:
+ * Write a block of host memory into a DSP address, into a given memory
+ * space. Unlike bridge_brd_write, this API does reset the DSP
+ * Parameters:
+ * dev_ctxt: Handle to Bridge driver defined device info.
+ * dsp_addr: Address on DSP board (Destination).
+ * host_buf: Pointer to host buffer (Source).
+ * ul_num_bytes: Number of bytes to transfer.
+ * mem_type: Memory space on DSP to which to transfer.
+ * Returns:
+ * 0: Success.
+ * -ETIMEDOUT: Timeout occured waiting for a response from hardware.
+ * -EPERM: Other, unspecified error.
+ * Requires:
+ * dev_ctxt != NULL;
+ * host_buf != NULL.
+ * Ensures:
+ */
+typedef int(*fxn_brd_memwrite) (struct bridge_dev_context
+ * dev_ctxt,
+ u8 *host_buf,
+ u32 dsp_addr, u32 ul_num_bytes,
+ u32 mem_type);
+
+/*
+ * ======== bridge_brd_mem_map ========
+ * Purpose:
+ * Map a MPU memory region to a DSP/IVA memory space
+ * Parameters:
+ * dev_ctxt: Handle to Bridge driver defined device info.
+ * ul_mpu_addr: MPU memory region start address.
+ * virt_addr: DSP/IVA memory region u8 address.
+ * ul_num_bytes: Number of bytes to map.
+ * map_attrs: Mapping attributes (e.g. endianness).
+ * Returns:
+ * 0: Success.
+ * -EPERM: Other, unspecified error.
+ * Requires:
+ * dev_ctxt != NULL;
+ * Ensures:
+ */
+typedef int(*fxn_brd_memmap) (struct bridge_dev_context
+ * dev_ctxt, u32 ul_mpu_addr,
+ u32 virt_addr, u32 ul_num_bytes,
+ u32 map_attr,
+ struct page **mapped_pages);
+
+/*
+ * ======== bridge_brd_mem_un_map ========
+ * Purpose:
+ * UnMap an MPU memory region from DSP/IVA memory space
+ * Parameters:
+ * dev_ctxt: Handle to Bridge driver defined device info.
+ * virt_addr: DSP/IVA memory region u8 address.
+ * ul_num_bytes: Number of bytes to unmap.
+ * Returns:
+ * 0: Success.
+ * -EPERM: Other, unspecified error.
+ * Requires:
+ * dev_ctxt != NULL;
+ * Ensures:
+ */
+typedef int(*fxn_brd_memunmap) (struct bridge_dev_context
+ * dev_ctxt,
+ u32 virt_addr, u32 ul_num_bytes);
+
+/*
+ * ======== bridge_brd_stop ========
+ * Purpose:
+ * Bring board to the BRD_STOPPED state.
+ * Parameters:
+ * dev_ctxt: Handle to Bridge driver defined device context.
+ * Returns:
+ * 0: Success.
+ * -ETIMEDOUT: Timeout occured waiting for a response from hardware.
+ * -EPERM: Other, unspecified error.
+ * Requires:
+ * dev_ctxt != NULL
+ * Ensures:
+ * 0: Board is in BRD_STOPPED (stop) state;
+ * Interrupts to the PC are disabled.
+ * else: Board state is indeterminate.
+ */
+typedef int(*fxn_brd_stop) (struct bridge_dev_context *dev_ctxt);
+
+/*
+ * ======== bridge_brd_status ========
+ * Purpose:
+ * Report the current state of the board.
+ * Parameters:
+ * dev_ctxt: Handle to Bridge driver defined device context.
+ * board_state: Ptr to BRD status variable.
+ * Returns:
+ * 0:
+ * Requires:
+ * board_state != NULL;
+ * dev_ctxt != NULL
+ * Ensures:
+ * *board_state is one of
+ * {BRD_STOPPED, BRD_IDLE, BRD_RUNNING, BRD_UNKNOWN};
+ */
+typedef int(*fxn_brd_status) (struct bridge_dev_context *dev_ctxt,
+ int *board_state);
+
+/*
+ * ======== bridge_brd_read ========
+ * Purpose:
+ * Read a block of DSP memory, from a given memory space, into a host
+ * buffer.
+ * Parameters:
+ * dev_ctxt: Handle to Bridge driver defined device info.
+ * host_buf: Pointer to host buffer (Destination).
+ * dsp_addr: Address on DSP board (Source).
+ * ul_num_bytes: Number of bytes to transfer.
+ * mem_type: Memory space on DSP from which to transfer.
+ * Returns:
+ * 0: Success.
+ * -ETIMEDOUT: Timeout occured waiting for a response from hardware.
+ * -EPERM: Other, unspecified error.
+ * Requires:
+ * dev_ctxt != NULL;
+ * host_buf != NULL.
+ * Ensures:
+ * Will not write more than ul_num_bytes bytes into host_buf.
+ */
+typedef int(*fxn_brd_read) (struct bridge_dev_context *dev_ctxt,
+ u8 *host_buf,
+ u32 dsp_addr,
+ u32 ul_num_bytes, u32 mem_type);
+
+/*
+ * ======== bridge_brd_write ========
+ * Purpose:
+ * Write a block of host memory into a DSP address, into a given memory
+ * space.
+ * Parameters:
+ * dev_ctxt: Handle to Bridge driver defined device info.
+ * dsp_addr: Address on DSP board (Destination).
+ * host_buf: Pointer to host buffer (Source).
+ * ul_num_bytes: Number of bytes to transfer.
+ * mem_type: Memory space on DSP to which to transfer.
+ * Returns:
+ * 0: Success.
+ * -ETIMEDOUT: Timeout occured waiting for a response from hardware.
+ * -EPERM: Other, unspecified error.
+ * Requires:
+ * dev_ctxt != NULL;
+ * host_buf != NULL.
+ * Ensures:
+ */
+typedef int(*fxn_brd_write) (struct bridge_dev_context *dev_ctxt,
+ u8 *host_buf,
+ u32 dsp_addr,
+ u32 ul_num_bytes, u32 mem_type);
+
+/*
+ * ======== bridge_chnl_create ========
+ * Purpose:
+ * Create a channel manager object, responsible for opening new channels
+ * and closing old ones for a given 'Bridge board.
+ * Parameters:
+ * channel_mgr: Location to store a channel manager object on output.
+ * hdev_obj: Handle to a device object.
+ * mgr_attrts: Channel manager attributes.
+ * mgr_attrts->max_channels: Max channels
+ * mgr_attrts->birq: Channel's I/O IRQ number.
+ * mgr_attrts->irq_shared: TRUE if the IRQ is shareable.
+ * mgr_attrts->word_size: DSP Word size in equivalent PC bytes..
+ * mgr_attrts->shm_base: Base physical address of shared memory, if any.
+ * mgr_attrts->usm_length: Bytes of shared memory block.
+ * Returns:
+ * 0: Success;
+ * -ENOMEM: Insufficient memory for requested resources.
+ * -EIO: Unable to plug ISR for given IRQ.
+ * -EFAULT: Couldn't map physical address to a virtual one.
+ * Requires:
+ * channel_mgr != NULL.
+ * mgr_attrts != NULL
+ * mgr_attrts field are all valid:
+ * 0 < max_channels <= CHNL_MAXCHANNELS.
+ * birq <= 15.
+ * word_size > 0.
+ * hdev_obj != NULL
+ * No channel manager exists for this board.
+ * Ensures:
+ */
+typedef int(*fxn_chnl_create) (struct chnl_mgr
+ **channel_mgr,
+ struct dev_object
+ * hdev_obj,
+ const struct
+ chnl_mgrattrs * mgr_attrts);
+
+/*
+ * ======== bridge_chnl_destroy ========
+ * Purpose:
+ * Close all open channels, and destroy the channel manager.
+ * Parameters:
+ * hchnl_mgr: Channel manager object.
+ * Returns:
+ * 0: Success.
+ * -EFAULT: hchnl_mgr was invalid.
+ * Requires:
+ * Ensures:
+ * 0: Cancels I/O on each open channel. Closes each open channel.
+ * chnl_create may subsequently be called for the same device.
+ */
+typedef int(*fxn_chnl_destroy) (struct chnl_mgr *hchnl_mgr);
+/*
+ * ======== bridge_deh_notify ========
+ * Purpose:
+ * When notified of DSP error, take appropriate action.
+ * Parameters:
+ * hdeh_mgr: Handle to DEH manager object.
+ * evnt_mask: Indicate the type of exception
+ * error_info: Error information
+ * Returns:
+ *
+ * Requires:
+ * hdeh_mgr != NULL;
+ * evnt_mask with a valid exception
+ * Ensures:
+ */
+typedef void (*fxn_deh_notify) (struct deh_mgr *hdeh_mgr,
+ u32 evnt_mask, u32 error_info);
+
+/*
+ * ======== bridge_chnl_open ========
+ * Purpose:
+ * Open a new half-duplex channel to the DSP board.
+ * Parameters:
+ * chnl: Location to store a channel object handle.
+ * hchnl_mgr: Handle to channel manager, as returned by
+ * CHNL_GetMgr().
+ * chnl_mode: One of {CHNL_MODETODSP, CHNL_MODEFROMDSP} specifies
+ * direction of data transfer.
+ * ch_id: If CHNL_PICKFREE is specified, the channel manager will
+ * select a free channel id (default);
+ * otherwise this field specifies the id of the channel.
+ * pattrs: Channel attributes. Attribute fields are as follows:
+ * pattrs->uio_reqs: Specifies the maximum number of I/O requests which can
+ * be pending at any given time. All request packets are
+ * preallocated when the channel is opened.
+ * pattrs->event_obj: This field allows the user to supply an auto reset
+ * event object for channel I/O completion notifications.
+ * It is the responsibility of the user to destroy this
+ * object AFTER closing the channel.
+ * This channel event object can be retrieved using
+ * CHNL_GetEventHandle().
+ * pattrs->hReserved: The kernel mode handle of this event object.
+ *
+ * Returns:
+ * 0: Success.
+ * -EFAULT: hchnl_mgr is invalid.
+ * -ENOMEM: Insufficient memory for requested resources.
+ * -EINVAL: Invalid number of IOReqs.
+ * -ENOSR: No free channels available.
+ * -ECHRNG: Channel ID is out of range.
+ * -EALREADY: Channel is in use.
+ * -EIO: No free IO request packets available for
+ * queuing.
+ * Requires:
+ * chnl != NULL.
+ * pattrs != NULL.
+ * pattrs->event_obj is a valid event handle.
+ * pattrs->hReserved is the kernel mode handle for pattrs->event_obj.
+ * Ensures:
+ * 0: *chnl is a valid channel.
+ * else: *chnl is set to NULL if (chnl != NULL);
+ */
+typedef int(*fxn_chnl_open) (struct chnl_object
+ **chnl,
+ struct chnl_mgr *hchnl_mgr,
+ s8 chnl_mode,
+ u32 ch_id,
+ const struct
+ chnl_attr * pattrs);
+
+/*
+ * ======== bridge_chnl_close ========
+ * Purpose:
+ * Ensures all pending I/O on this channel is cancelled, discards all
+ * queued I/O completion notifications, then frees the resources allocated
+ * for this channel, and makes the corresponding logical channel id
+ * available for subsequent use.
+ * Parameters:
+ * chnl_obj: Handle to a channel object.
+ * Returns:
+ * 0: Success;
+ * -EFAULT: Invalid chnl_obj.
+ * Requires:
+ * No thread must be blocked on this channel's I/O completion event.
+ * Ensures:
+ * 0: chnl_obj is no longer valid.
+ */
+typedef int(*fxn_chnl_close) (struct chnl_object *chnl_obj);
+
+/*
+ * ======== bridge_chnl_add_io_req ========
+ * Purpose:
+ * Enqueue an I/O request for data transfer on a channel to the DSP.
+ * The direction (mode) is specified in the channel object. Note the DSP
+ * address is specified for channels opened in direct I/O mode.
+ * Parameters:
+ * chnl_obj: Channel object handle.
+ * host_buf: Host buffer address source.
+ * byte_size: Number of PC bytes to transfer. A zero value indicates
+ * that this buffer is the last in the output channel.
+ * A zero value is invalid for an input channel.
+ *! buf_size: Actual buffer size in host bytes.
+ * dw_dsp_addr: DSP address for transfer. (Currently ignored).
+ * dw_arg: A user argument that travels with the buffer.
+ * Returns:
+ * 0: Success;
+ * -EFAULT: Invalid chnl_obj or host_buf.
+ * -EPERM: User cannot mark EOS on an input channel.
+ * -ECANCELED: I/O has been cancelled on this channel. No further
+ * I/O is allowed.
+ * -EPIPE: End of stream was already marked on a previous
+ * IORequest on this channel. No further I/O is expected.
+ * -EINVAL: Buffer submitted to this output channel is larger than
+ * the size of the physical shared memory output window.
+ * Requires:
+ * Ensures:
+ * 0: The buffer will be transferred if the channel is ready;
+ * otherwise, will be queued for transfer when the channel becomes
+ * ready. In any case, notifications of I/O completion are
+ * asynchronous.
+ * If byte_size is 0 for an output channel, subsequent CHNL_AddIOReq's
+ * on this channel will fail with error code -EPIPE. The
+ * corresponding IOC for this I/O request will have its status flag
+ * set to CHNL_IOCSTATEOS.
+ */
+typedef int(*fxn_chnl_addioreq) (struct chnl_object
+ * chnl_obj,
+ void *host_buf,
+ u32 byte_size,
+ u32 buf_size,
+ u32 dw_dsp_addr, u32 dw_arg);
+
+/*
+ * ======== bridge_chnl_get_ioc ========
+ * Purpose:
+ * Dequeue an I/O completion record, which contains information about the
+ * completed I/O request.
+ * Parameters:
+ * chnl_obj: Channel object handle.
+ * timeout: A value of CHNL_IOCNOWAIT will simply dequeue the
+ * first available IOC.
+ * chan_ioc: On output, contains host buffer address, bytes
+ * transferred, and status of I/O completion.
+ * chan_ioc->status: See chnldefs.h.
+ * Returns:
+ * 0: Success.
+ * -EFAULT: Invalid chnl_obj or chan_ioc.
+ * -EREMOTEIO: CHNL_IOCNOWAIT was specified as the timeout parameter
+ * yet no I/O completions were queued.
+ * Requires:
+ * timeout == CHNL_IOCNOWAIT.
+ * Ensures:
+ * 0: if there are any remaining IOC's queued before this call
+ * returns, the channel event object will be left in a signalled
+ * state.
+ */
+typedef int(*fxn_chnl_getioc) (struct chnl_object *chnl_obj,
+ u32 timeout,
+ struct chnl_ioc *chan_ioc);
+
+/*
+ * ======== bridge_chnl_cancel_io ========
+ * Purpose:
+ * Return all I/O requests to the client which have not yet been
+ * transferred. The channel's I/O completion object is
+ * signalled, and all the I/O requests are queued as IOC's, with the
+ * status field set to CHNL_IOCSTATCANCEL.
+ * This call is typically used in abort situations, and is a prelude to
+ * chnl_close();
+ * Parameters:
+ * chnl_obj: Channel object handle.
+ * Returns:
+ * 0: Success;
+ * -EFAULT: Invalid chnl_obj.
+ * Requires:
+ * Ensures:
+ * Subsequent I/O requests to this channel will not be accepted.
+ */
+typedef int(*fxn_chnl_cancelio) (struct chnl_object *chnl_obj);
+
+/*
+ * ======== bridge_chnl_flush_io ========
+ * Purpose:
+ * For an output stream (to the DSP), indicates if any IO requests are in
+ * the output request queue. For input streams (from the DSP), will
+ * cancel all pending IO requests.
+ * Parameters:
+ * chnl_obj: Channel object handle.
+ * timeout: Timeout value for flush operation.
+ * Returns:
+ * 0: Success;
+ * S_CHNLIOREQUEST: Returned if any IORequests are in the output queue.
+ * -EFAULT: Invalid chnl_obj.
+ * Requires:
+ * Ensures:
+ * 0: No I/O requests will be pending on this channel.
+ */
+typedef int(*fxn_chnl_flushio) (struct chnl_object *chnl_obj,
+ u32 timeout);
+
+/*
+ * ======== bridge_chnl_get_info ========
+ * Purpose:
+ * Retrieve information related to a channel.
+ * Parameters:
+ * chnl_obj: Handle to a valid channel object, or NULL.
+ * channel_info: Location to store channel info.
+ * Returns:
+ * 0: Success;
+ * -EFAULT: Invalid chnl_obj or channel_info.
+ * Requires:
+ * Ensures:
+ * 0: channel_info points to a filled in chnl_info struct,
+ * if (channel_info != NULL).
+ */
+typedef int(*fxn_chnl_getinfo) (struct chnl_object *chnl_obj,
+ struct chnl_info *channel_info);
+
+/*
+ * ======== bridge_chnl_get_mgr_info ========
+ * Purpose:
+ * Retrieve information related to the channel manager.
+ * Parameters:
+ * hchnl_mgr: Handle to a valid channel manager, or NULL.
+ * ch_id: Channel ID.
+ * mgr_info: Location to store channel manager info.
+ * Returns:
+ * 0: Success;
+ * -EFAULT: Invalid hchnl_mgr or mgr_info.
+ * -ECHRNG: Invalid channel ID.
+ * Requires:
+ * Ensures:
+ * 0: mgr_info points to a filled in chnl_mgrinfo
+ * struct, if (mgr_info != NULL).
+ */
+typedef int(*fxn_chnl_getmgrinfo) (struct chnl_mgr
+ * hchnl_mgr,
+ u32 ch_id,
+ struct chnl_mgrinfo *mgr_info);
+
+/*
+ * ======== bridge_chnl_idle ========
+ * Purpose:
+ * Idle a channel. If this is an input channel, or if this is an output
+ * channel and flush_data is TRUE, all currently enqueued buffers will be
+ * dequeued (data discarded for output channel).
+ * If this is an output channel and flush_data is FALSE, this function
+ * will block until all currently buffered data is output, or the timeout
+ * specified has been reached.
+ *
+ * Parameters:
+ * chnl_obj: Channel object handle.
+ * timeout: If output channel and flush_data is FALSE, timeout value
+ * to wait for buffers to be output. (Not used for
+ * input channel).
+ * flush_data: If output channel and flush_data is TRUE, discard any
+ * currently buffered data. If FALSE, wait for currently
+ * buffered data to be output, or timeout, whichever
+ * occurs first. flush_data is ignored for input channel.
+ * Returns:
+ * 0: Success;
+ * -EFAULT: Invalid chnl_obj.
+ * -ETIMEDOUT: Timeout occured before channel could be idled.
+ * Requires:
+ * Ensures:
+ */
+typedef int(*fxn_chnl_idle) (struct chnl_object *chnl_obj,
+ u32 timeout, bool flush_data);
+
+/*
+ * ======== bridge_chnl_register_notify ========
+ * Purpose:
+ * Register for notification of events on a channel.
+ * Parameters:
+ * chnl_obj: Channel object handle.
+ * event_mask: Type of events to be notified about: IO completion
+ * (DSP_STREAMIOCOMPLETION) or end of stream
+ * (DSP_STREAMDONE).
+ * notify_type: DSP_SIGNALEVENT.
+ * hnotification: Handle of a dsp_notification object.
+ * Returns:
+ * 0: Success.
+ * -ENOMEM: Insufficient memory.
+ * -EINVAL: event_mask is 0 and hnotification was not
+ * previously registered.
+ * -EFAULT: NULL hnotification, hnotification event name
+ * too long, or hnotification event name NULL.
+ * Requires:
+ * Valid chnl_obj.
+ * hnotification != NULL.
+ * (event_mask & ~(DSP_STREAMIOCOMPLETION | DSP_STREAMDONE)) == 0.
+ * notify_type == DSP_SIGNALEVENT.
+ * Ensures:
+ */
+typedef int(*fxn_chnl_registernotify)
+ (struct chnl_object *chnl_obj,
+ u32 event_mask, u32 notify_type, struct dsp_notification *hnotification);
+
+/*
+ * ======== bridge_dev_create ========
+ * Purpose:
+ * Complete creation of the device object for this board.
+ * Parameters:
+ * device_ctx: Ptr to location to store a Bridge device context.
+ * hdev_obj: Handle to a Device Object, created and managed by DSP API.
+ * config_param: Ptr to configuration parameters provided by the
+ * Configuration Manager during device loading.
+ * pDspConfig: DSP resources, as specified in the registry key for this
+ * device.
+ * Returns:
+ * 0: Success.
+ * -ENOMEM: Unable to allocate memory for device context.
+ * Requires:
+ * device_ctx != NULL;
+ * hdev_obj != NULL;
+ * config_param != NULL;
+ * pDspConfig != NULL;
+ * Fields in config_param and pDspConfig contain valid values.
+ * Ensures:
+ * 0: All Bridge driver specific DSP resource and other
+ * board context has been allocated.
+ * -ENOMEM: Bridge failed to allocate resources.
+ * Any acquired resources have been freed. The DSP API
+ * will not call bridge_dev_destroy() if
+ * bridge_dev_create() fails.
+ * Details:
+ * Called during the CONFIGMG's Device_Init phase. Based on host and
+ * DSP configuration information, create a board context, a handle to
+ * which is passed into other Bridge BRD and CHNL functions. The
+ * board context contains state information for the device. Since the
+ * addresses of all pointer parameters may be invalid when this
+ * function returns, they must not be stored into the device context
+ * structure.
+ */
+typedef int(*fxn_dev_create) (struct bridge_dev_context
+ **device_ctx,
+ struct dev_object
+ * hdev_obj,
+ struct cfg_hostres
+ * config_param);
+
+/*
+ * ======== bridge_dev_ctrl ========
+ * Purpose:
+ * Bridge driver specific interface.
+ * Parameters:
+ * dev_ctxt: Handle to Bridge driver defined device info.
+ * dw_cmd: Bridge driver defined command code.
+ * pargs: Pointer to an arbitrary argument structure.
+ * Returns:
+ * 0 or -EPERM. Actual command error codes should be passed back in
+ * the pargs structure, and are defined by the Bridge driver implementor.
+ * Requires:
+ * All calls are currently assumed to be synchronous. There are no
+ * IOCTL completion routines provided.
+ * Ensures:
+ */
+typedef int(*fxn_dev_ctrl) (struct bridge_dev_context *dev_ctxt,
+ u32 dw_cmd, void *pargs);
+
+/*
+ * ======== bridge_dev_destroy ========
+ * Purpose:
+ * Deallocate Bridge device extension structures and all other resources
+ * acquired by the Bridge driver.
+ * No calls to other Bridge driver functions may subsequently
+ * occur, except for bridge_dev_create().
+ * Parameters:
+ * dev_ctxt: Handle to Bridge driver defined device information.
+ * Returns:
+ * 0: Success.
+ * -EPERM: Failed to release a resource previously acquired.
+ * Requires:
+ * dev_ctxt != NULL;
+ * Ensures:
+ * 0: Device context is freed.
+ */
+typedef int(*fxn_dev_destroy) (struct bridge_dev_context *dev_ctxt);
+
+/*
+ * ======== bridge_io_create ========
+ * Purpose:
+ * Create an object that manages I/O between CHNL and msg_ctrl.
+ * Parameters:
+ * io_man: Location to store IO manager on output.
+ * hchnl_mgr: Handle to channel manager.
+ * hmsg_mgr: Handle to message manager.
+ * Returns:
+ * 0: Success.
+ * -ENOMEM: Memory allocation failure.
+ * -EPERM: Creation failed.
+ * Requires:
+ * hdev_obj != NULL;
+ * Channel manager already created;
+ * Message manager already created;
+ * mgr_attrts != NULL;
+ * io_man != NULL;
+ * Ensures:
+ */
+typedef int(*fxn_io_create) (struct io_mgr **io_man,
+ struct dev_object *hdev_obj,
+ const struct io_attrs *mgr_attrts);
+
+/*
+ * ======== bridge_io_destroy ========
+ * Purpose:
+ * Destroy object created in bridge_io_create.
+ * Parameters:
+ * hio_mgr: IO Manager.
+ * Returns:
+ * 0: Success.
+ * -ENOMEM: Memory allocation failure.
+ * -EPERM: Creation failed.
+ * Requires:
+ * Valid hio_mgr;
+ * Ensures:
+ */
+typedef int(*fxn_io_destroy) (struct io_mgr *hio_mgr);
+
+/*
+ * ======== bridge_io_on_loaded ========
+ * Purpose:
+ * Called whenever a program is loaded to update internal data. For
+ * example, if shared memory is used, this function would update the
+ * shared memory location and address.
+ * Parameters:
+ * hio_mgr: IO Manager.
+ * Returns:
+ * 0: Success.
+ * -EPERM: Internal failure occurred.
+ * Requires:
+ * Valid hio_mgr;
+ * Ensures:
+ */
+typedef int(*fxn_io_onloaded) (struct io_mgr *hio_mgr);
+
+/*
+ * ======== fxn_io_getprocload ========
+ * Purpose:
+ * Called to get the Processor's current and predicted load
+ * Parameters:
+ * hio_mgr: IO Manager.
+ * proc_load_stat Processor Load statistics
+ * Returns:
+ * 0: Success.
+ * -EPERM: Internal failure occurred.
+ * Requires:
+ * Valid hio_mgr;
+ * Ensures:
+ */
+typedef int(*fxn_io_getprocload) (struct io_mgr *hio_mgr,
+ struct dsp_procloadstat *
+ proc_load_stat);
+
+/*
+ * ======== bridge_msg_create ========
+ * Purpose:
+ * Create an object to manage message queues. Only one of these objects
+ * can exist per device object.
+ * Parameters:
+ * msg_man: Location to store msg_ctrl manager on output.
+ * hdev_obj: Handle to a device object.
+ * msg_callback: Called whenever an RMS_EXIT message is received.
+ * Returns:
+ * 0: Success.
+ * -ENOMEM: Insufficient memory.
+ * Requires:
+ * msg_man != NULL.
+ * msg_callback != NULL.
+ * hdev_obj != NULL.
+ * Ensures:
+ */
+typedef int(*fxn_msg_create)
+ (struct msg_mgr **msg_man,
+ struct dev_object *hdev_obj, msg_onexit msg_callback);
+
+/*
+ * ======== bridge_msg_create_queue ========
+ * Purpose:
+ * Create a msg_ctrl queue for sending or receiving messages from a Message
+ * node on the DSP.
+ * Parameters:
+ * hmsg_mgr: msg_ctrl queue manager handle returned from
+ * bridge_msg_create.
+ * msgq: Location to store msg_ctrl queue on output.
+ * msgq_id: Identifier for messages (node environment pointer).
+ * max_msgs: Max number of simultaneous messages for the node.
+ * h: Handle passed to hmsg_mgr->msg_callback().
+ * Returns:
+ * 0: Success.
+ * -ENOMEM: Insufficient memory.
+ * Requires:
+ * msgq != NULL.
+ * h != NULL.
+ * max_msgs > 0.
+ * Ensures:
+ * msgq !=NULL <==> 0.
+ */
+typedef int(*fxn_msg_createqueue)
+ (struct msg_mgr *hmsg_mgr,
+ struct msg_queue **msgq, u32 msgq_id, u32 max_msgs, void *h);
+
+/*
+ * ======== bridge_msg_delete ========
+ * Purpose:
+ * Delete a msg_ctrl manager allocated in bridge_msg_create().
+ * Parameters:
+ * hmsg_mgr: Handle returned from bridge_msg_create().
+ * Returns:
+ * Requires:
+ * Valid hmsg_mgr.
+ * Ensures:
+ */
+typedef void (*fxn_msg_delete) (struct msg_mgr *hmsg_mgr);
+
+/*
+ * ======== bridge_msg_delete_queue ========
+ * Purpose:
+ * Delete a msg_ctrl queue allocated in bridge_msg_create_queue.
+ * Parameters:
+ * msg_queue_obj: Handle to msg_ctrl queue returned from
+ * bridge_msg_create_queue.
+ * Returns:
+ * Requires:
+ * Valid msg_queue_obj.
+ * Ensures:
+ */
+typedef void (*fxn_msg_deletequeue) (struct msg_queue *msg_queue_obj);
+
+/*
+ * ======== bridge_msg_get ========
+ * Purpose:
+ * Get a message from a msg_ctrl queue.
+ * Parameters:
+ * msg_queue_obj: Handle to msg_ctrl queue returned from
+ * bridge_msg_create_queue.
+ * pmsg: Location to copy message into.
+ * utimeout: Timeout to wait for a message.
+ * Returns:
+ * 0: Success.
+ * -ETIME: Timeout occurred.
+ * -EPERM: No frames available for message (max_msgs too
+ * small).
+ * Requires:
+ * Valid msg_queue_obj.
+ * pmsg != NULL.
+ * Ensures:
+ */
+typedef int(*fxn_msg_get) (struct msg_queue *msg_queue_obj,
+ struct dsp_msg *pmsg, u32 utimeout);
+
+/*
+ * ======== bridge_msg_put ========
+ * Purpose:
+ * Put a message onto a msg_ctrl queue.
+ * Parameters:
+ * msg_queue_obj: Handle to msg_ctrl queue returned from
+ * bridge_msg_create_queue.
+ * pmsg: Pointer to message.
+ * utimeout: Timeout to wait for a message.
+ * Returns:
+ * 0: Success.
+ * -ETIME: Timeout occurred.
+ * -EPERM: No frames available for message (max_msgs too
+ * small).
+ * Requires:
+ * Valid msg_queue_obj.
+ * pmsg != NULL.
+ * Ensures:
+ */
+typedef int(*fxn_msg_put) (struct msg_queue *msg_queue_obj,
+ const struct dsp_msg *pmsg, u32 utimeout);
+
+/*
+ * ======== bridge_msg_register_notify ========
+ * Purpose:
+ * Register notification for when a message is ready.
+ * Parameters:
+ * msg_queue_obj: Handle to msg_ctrl queue returned from
+ * bridge_msg_create_queue.
+ * event_mask: Type of events to be notified about: Must be
+ * DSP_NODEMESSAGEREADY, or 0 to unregister.
+ * notify_type: DSP_SIGNALEVENT.
+ * hnotification: Handle of notification object.
+ * Returns:
+ * 0: Success.
+ * -ENOMEM: Insufficient memory.
+ * Requires:
+ * Valid msg_queue_obj.
+ * hnotification != NULL.
+ * notify_type == DSP_SIGNALEVENT.
+ * event_mask == DSP_NODEMESSAGEREADY || event_mask == 0.
+ * Ensures:
+ */
+typedef int(*fxn_msg_registernotify)
+ (struct msg_queue *msg_queue_obj,
+ u32 event_mask, u32 notify_type, struct dsp_notification *hnotification);
+
+/*
+ * ======== bridge_msg_set_queue_id ========
+ * Purpose:
+ * Set message queue id to node environment. Allows bridge_msg_create_queue
+ * to be called in node_allocate, before the node environment is known.
+ * Parameters:
+ * msg_queue_obj: Handle to msg_ctrl queue returned from
+ * bridge_msg_create_queue.
+ * msgq_id: Node environment pointer.
+ * Returns:
+ * Requires:
+ * Valid msg_queue_obj.
+ * msgq_id != 0.
+ * Ensures:
+ */
+typedef void (*fxn_msg_setqueueid) (struct msg_queue *msg_queue_obj,
+ u32 msgq_id);
+
+/*
+ * Bridge Driver interface function table.
+ *
+ * The information in this table is filled in by the specific Bridge driver,
+ * and copied into the DSP API's own space. If any interface
+ * function field is set to a value of NULL, then the DSP API will
+ * consider that function not implemented, and return the error code
+ * -ENOSYS when a Bridge driver client attempts to call that function.
+ *
+ * This function table contains DSP API version numbers, which are used by the
+ * Bridge driver loader to help ensure backwards compatility between older
+ * Bridge drivers and newer DSP API. These must be set to
+ * BRD_API_MAJOR_VERSION and BRD_API_MINOR_VERSION, respectively.
+ *
+ * A Bridge driver need not export a CHNL interface. In this case, *all* of
+ * the bridge_chnl_* entries must be set to NULL.
+ */
+struct bridge_drv_interface {
+ u32 brd_api_major_version; /* Set to BRD_API_MAJOR_VERSION. */
+ u32 brd_api_minor_version; /* Set to BRD_API_MINOR_VERSION. */
+ fxn_dev_create pfn_dev_create; /* Create device context */
+ fxn_dev_destroy pfn_dev_destroy; /* Destroy device context */
+ fxn_dev_ctrl pfn_dev_cntrl; /* Optional vendor interface */
+ fxn_brd_monitor pfn_brd_monitor; /* Load and/or start monitor */
+ fxn_brd_start pfn_brd_start; /* Start DSP program. */
+ fxn_brd_stop pfn_brd_stop; /* Stop/reset board. */
+ fxn_brd_status pfn_brd_status; /* Get current board status. */
+ fxn_brd_read pfn_brd_read; /* Read board memory */
+ fxn_brd_write pfn_brd_write; /* Write board memory. */
+ fxn_brd_setstate pfn_brd_set_state; /* Sets the Board State */
+ fxn_brd_memcopy pfn_brd_mem_copy; /* Copies DSP Memory */
+ fxn_brd_memwrite pfn_brd_mem_write; /* Write DSP Memory w/o halt */
+ fxn_brd_memmap pfn_brd_mem_map; /* Maps MPU mem to DSP mem */
+ fxn_brd_memunmap pfn_brd_mem_un_map; /* Unmaps MPU mem to DSP mem */
+ fxn_chnl_create pfn_chnl_create; /* Create channel manager. */
+ fxn_chnl_destroy pfn_chnl_destroy; /* Destroy channel manager. */
+ fxn_chnl_open pfn_chnl_open; /* Create a new channel. */
+ fxn_chnl_close pfn_chnl_close; /* Close a channel. */
+ fxn_chnl_addioreq pfn_chnl_add_io_req; /* Req I/O on a channel. */
+ fxn_chnl_getioc pfn_chnl_get_ioc; /* Wait for I/O completion. */
+ fxn_chnl_cancelio pfn_chnl_cancel_io; /* Cancl I/O on a channel. */
+ fxn_chnl_flushio pfn_chnl_flush_io; /* Flush I/O. */
+ fxn_chnl_getinfo pfn_chnl_get_info; /* Get channel specific info */
+ /* Get channel manager info. */
+ fxn_chnl_getmgrinfo pfn_chnl_get_mgr_info;
+ fxn_chnl_idle pfn_chnl_idle; /* Idle the channel */
+ /* Register for notif. */
+ fxn_chnl_registernotify pfn_chnl_register_notify;
+ fxn_io_create pfn_io_create; /* Create IO manager */
+ fxn_io_destroy pfn_io_destroy; /* Destroy IO manager */
+ fxn_io_onloaded pfn_io_on_loaded; /* Notify of program loaded */
+ /* Get Processor's current and predicted load */
+ fxn_io_getprocload pfn_io_get_proc_load;
+ fxn_msg_create pfn_msg_create; /* Create message manager */
+ /* Create message queue */
+ fxn_msg_createqueue pfn_msg_create_queue;
+ fxn_msg_delete pfn_msg_delete; /* Delete message manager */
+ /* Delete message queue */
+ fxn_msg_deletequeue pfn_msg_delete_queue;
+ fxn_msg_get pfn_msg_get; /* Get a message */
+ fxn_msg_put pfn_msg_put; /* Send a message */
+ /* Register for notif. */
+ fxn_msg_registernotify pfn_msg_register_notify;
+ /* Set message queue id */
+ fxn_msg_setqueueid pfn_msg_set_queue_id;
+};
+
+/*
+ * ======== bridge_drv_entry ========
+ * Purpose:
+ * Registers Bridge driver functions with the DSP API. Called only once
+ * by the DSP API. The caller will first check DSP API version
+ * compatibility, and then copy the interface functions into its own
+ * memory space.
+ * Parameters:
+ * drv_intf Pointer to a location to receive a pointer to the
+ * Bridge driver interface.
+ * Returns:
+ * Requires:
+ * The code segment this function resides in must expect to be discarded
+ * after completion.
+ * Ensures:
+ * drv_intf pointer initialized to Bridge driver's function
+ * interface. No system resources are acquired by this function.
+ * Details:
+ * Called during the Device_Init phase.
+ */
+void bridge_drv_entry(struct bridge_drv_interface **drv_intf,
+ const char *driver_file_name);
+
+#endif /* DSPDEFS_ */
diff --git a/drivers/staging/tidspbridge/include/dspbridge/dspdeh.h b/drivers/staging/tidspbridge/include/dspbridge/dspdeh.h
new file mode 100644
index 00000000000..d258ab6a41d
--- /dev/null
+++ b/drivers/staging/tidspbridge/include/dspbridge/dspdeh.h
@@ -0,0 +1,43 @@
+/*
+ * dspdeh.h
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * Defines upper edge DEH functions required by all Bridge driver/DSP API
+ * interface tables.
+ *
+ * Notes:
+ * Function comment headers reside with the function typedefs in dspdefs.h.
+ *
+ * Copyright (C) 2005-2006 Texas Instruments, Inc.
+ * Copyright (C) 2010 Felipe Contreras
+ *
+ * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef DSPDEH_
+#define DSPDEH_
+
+struct deh_mgr;
+struct dev_object;
+struct dsp_notification;
+
+int bridge_deh_create(struct deh_mgr **ret_deh,
+ struct dev_object *hdev_obj);
+
+int bridge_deh_destroy(struct deh_mgr *deh);
+
+int bridge_deh_register_notify(struct deh_mgr *deh,
+ u32 event_mask,
+ u32 notify_type,
+ struct dsp_notification *hnotification);
+
+void bridge_deh_notify(struct deh_mgr *deh, int event, int info);
+
+#endif /* DSPDEH_ */
diff --git a/drivers/staging/tidspbridge/include/dspbridge/dspdrv.h b/drivers/staging/tidspbridge/include/dspbridge/dspdrv.h
new file mode 100644
index 00000000000..0bb250f95ba
--- /dev/null
+++ b/drivers/staging/tidspbridge/include/dspbridge/dspdrv.h
@@ -0,0 +1,62 @@
+/*
+ * dspdrv.h
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * This is the Stream Interface for the DSp API.
+ * All Device operations are performed via DeviceIOControl.
+ *
+ * Copyright (C) 2005-2006 Texas Instruments, Inc.
+ *
+ * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#if !defined _DSPDRV_H_
+#define _DSPDRV_H_
+
+#define MAX_DEV 10 /* Max support of 10 devices */
+
+/*
+ * ======== dsp_deinit ========
+ * Purpose:
+ * This function is called by Device Manager to de-initialize a device.
+ * This function is not called by applications.
+ * Parameters:
+ * device_context:Handle to the device context. The XXX_Init function
+ * creates and returns this identifier.
+ * Returns:
+ * TRUE indicates the device successfully de-initialized. Otherwise it
+ * returns FALSE.
+ * Requires:
+ * device_context!= NULL. For a built in device this should never
+ * get called.
+ * Ensures:
+ */
+extern bool dsp_deinit(u32 device_context);
+
+/*
+ * ======== dsp_init ========
+ * Purpose:
+ * This function is called by Device Manager to initialize a device.
+ * This function is not called by applications
+ * Parameters:
+ * dw_context: Specifies a pointer to a string containing the registry
+ * path to the active key for the stream interface driver.
+ * HKEY_LOCAL_MACHINE\Drivers\Active
+ * Returns:
+ * Returns a handle to the device context created. This is the our actual
+ * Device Object representing the DSP Device instance.
+ * Requires:
+ * Ensures:
+ * Succeeded: device context > 0
+ * Failed: device Context = 0
+ */
+extern u32 dsp_init(u32 *init_status);
+
+#endif
diff --git a/drivers/staging/tidspbridge/include/dspbridge/dspio.h b/drivers/staging/tidspbridge/include/dspbridge/dspio.h
new file mode 100644
index 00000000000..88f5f90fe92
--- /dev/null
+++ b/drivers/staging/tidspbridge/include/dspbridge/dspio.h
@@ -0,0 +1,41 @@
+/*
+ * dspio.h
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * Declares the upper edge IO functions required by all Bridge driver /DSP API
+ * interface tables.
+ *
+ * Notes:
+ * Function comment headers reside in dspdefs.h.
+ *
+ * Copyright (C) 2005-2006 Texas Instruments, Inc.
+ *
+ * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef DSPIO_
+#define DSPIO_
+
+#include <dspbridge/devdefs.h>
+#include <dspbridge/iodefs.h>
+
+extern int bridge_io_create(struct io_mgr **io_man,
+ struct dev_object *hdev_obj,
+ const struct io_attrs *mgr_attrts);
+
+extern int bridge_io_destroy(struct io_mgr *hio_mgr);
+
+extern int bridge_io_on_loaded(struct io_mgr *hio_mgr);
+
+extern int iva_io_on_loaded(struct io_mgr *hio_mgr);
+extern int bridge_io_get_proc_load(struct io_mgr *hio_mgr,
+ struct dsp_procloadstat *proc_lstat);
+
+#endif /* DSPIO_ */
diff --git a/drivers/staging/tidspbridge/include/dspbridge/dspioctl.h b/drivers/staging/tidspbridge/include/dspbridge/dspioctl.h
new file mode 100644
index 00000000000..41e0594dff3
--- /dev/null
+++ b/drivers/staging/tidspbridge/include/dspbridge/dspioctl.h
@@ -0,0 +1,73 @@
+/*
+ * dspioctl.h
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * Bridge driver BRD_IOCtl reserved command definitions.
+ *
+ * Copyright (C) 2005-2006 Texas Instruments, Inc.
+ *
+ * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef DSPIOCTL_
+#define DSPIOCTL_
+
+/* ------------------------------------ Hardware Abstraction Layer */
+#include <hw_defs.h>
+#include <hw_mmu.h>
+
+/*
+ * Any IOCTLS at or above this value are reserved for standard Bridge driver
+ * interfaces.
+ */
+#define BRDIOCTL_RESERVEDBASE 0x8000
+
+#define BRDIOCTL_CHNLREAD (BRDIOCTL_RESERVEDBASE + 0x10)
+#define BRDIOCTL_CHNLWRITE (BRDIOCTL_RESERVEDBASE + 0x20)
+#define BRDIOCTL_GETINTRCOUNT (BRDIOCTL_RESERVEDBASE + 0x30)
+#define BRDIOCTL_RESETINTRCOUNT (BRDIOCTL_RESERVEDBASE + 0x40)
+#define BRDIOCTL_INTERRUPTDSP (BRDIOCTL_RESERVEDBASE + 0x50)
+/* DMMU */
+#define BRDIOCTL_SETMMUCONFIG (BRDIOCTL_RESERVEDBASE + 0x60)
+/* PWR */
+#define BRDIOCTL_PWRCONTROL (BRDIOCTL_RESERVEDBASE + 0x70)
+
+/* attention, modifiers:
+ * Some of these control enumerations are made visible to user for power
+ * control, so any changes to this list, should also be updated in the user
+ * header file 'dbdefs.h' ***/
+/* These ioctls are reserved for PWR power commands for the DSP */
+#define BRDIOCTL_DEEPSLEEP (BRDIOCTL_PWRCONTROL + 0x0)
+#define BRDIOCTL_EMERGENCYSLEEP (BRDIOCTL_PWRCONTROL + 0x1)
+#define BRDIOCTL_WAKEUP (BRDIOCTL_PWRCONTROL + 0x2)
+#define BRDIOCTL_PWRENABLE (BRDIOCTL_PWRCONTROL + 0x3)
+#define BRDIOCTL_PWRDISABLE (BRDIOCTL_PWRCONTROL + 0x4)
+#define BRDIOCTL_CLK_CTRL (BRDIOCTL_PWRCONTROL + 0x7)
+/* DSP Initiated Hibernate */
+#define BRDIOCTL_PWR_HIBERNATE (BRDIOCTL_PWRCONTROL + 0x8)
+#define BRDIOCTL_PRESCALE_NOTIFY (BRDIOCTL_PWRCONTROL + 0x9)
+#define BRDIOCTL_POSTSCALE_NOTIFY (BRDIOCTL_PWRCONTROL + 0xA)
+#define BRDIOCTL_CONSTRAINT_REQUEST (BRDIOCTL_PWRCONTROL + 0xB)
+
+/* Number of actual DSP-MMU TLB entrries */
+#define BRDIOCTL_NUMOFMMUTLB 32
+
+struct bridge_ioctl_extproc {
+ u32 ul_dsp_va; /* DSP virtual address */
+ u32 ul_gpp_pa; /* GPP physical address */
+ /* GPP virtual address. __va does not work for ioremapped addresses */
+ u32 ul_gpp_va;
+ u32 ul_size; /* Size of the mapped memory in bytes */
+ enum hw_endianism_t endianism;
+ enum hw_mmu_mixed_size_t mixed_mode;
+ enum hw_element_size_t elem_size;
+};
+
+#endif /* DSPIOCTL_ */
diff --git a/drivers/staging/tidspbridge/include/dspbridge/dspmsg.h b/drivers/staging/tidspbridge/include/dspbridge/dspmsg.h
new file mode 100644
index 00000000000..d4bd458bc8b
--- /dev/null
+++ b/drivers/staging/tidspbridge/include/dspbridge/dspmsg.h
@@ -0,0 +1,56 @@
+/*
+ * dspmsg.h
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * Declares the upper edge message class library functions required by
+ * all Bridge driver / DSP API interface tables. These functions are
+ * implemented by every class of Bridge driver channel library.
+ *
+ * Notes:
+ * Function comment headers reside in dspdefs.h.
+ *
+ * Copyright (C) 2005-2006 Texas Instruments, Inc.
+ *
+ * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef DSPMSG_
+#define DSPMSG_
+
+#include <dspbridge/msgdefs.h>
+
+extern int bridge_msg_create(struct msg_mgr **msg_man,
+ struct dev_object *hdev_obj,
+ msg_onexit msg_callback);
+
+extern int bridge_msg_create_queue(struct msg_mgr *hmsg_mgr,
+ struct msg_queue **msgq,
+ u32 msgq_id, u32 max_msgs, void *arg);
+
+extern void bridge_msg_delete(struct msg_mgr *hmsg_mgr);
+
+extern void bridge_msg_delete_queue(struct msg_queue *msg_queue_obj);
+
+extern int bridge_msg_get(struct msg_queue *msg_queue_obj,
+ struct dsp_msg *pmsg, u32 utimeout);
+
+extern int bridge_msg_put(struct msg_queue *msg_queue_obj,
+ const struct dsp_msg *pmsg, u32 utimeout);
+
+extern int bridge_msg_register_notify(struct msg_queue *msg_queue_obj,
+ u32 event_mask,
+ u32 notify_type,
+ struct dsp_notification
+ *hnotification);
+
+extern void bridge_msg_set_queue_id(struct msg_queue *msg_queue_obj,
+ u32 msgq_id);
+
+#endif /* DSPMSG_ */
diff --git a/drivers/staging/tidspbridge/include/dspbridge/dynamic_loader.h b/drivers/staging/tidspbridge/include/dspbridge/dynamic_loader.h
new file mode 100644
index 00000000000..4b109d173b1
--- /dev/null
+++ b/drivers/staging/tidspbridge/include/dspbridge/dynamic_loader.h
@@ -0,0 +1,492 @@
+/*
+ * dynamic_loader.h
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * Copyright (C) 2008 Texas Instruments, Inc.
+ *
+ * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef _DYNAMIC_LOADER_H_
+#define _DYNAMIC_LOADER_H_
+#include <linux/kernel.h>
+#include <linux/types.h>
+
+/*
+ * Dynamic Loader
+ *
+ * The function of the dynamic loader is to load a "module" containing
+ * instructions for a "target" processor into that processor. In the process
+ * it assigns memory for the module, resolves symbol references made by the
+ * module, and remembers symbols defined by the module.
+ *
+ * The dynamic loader is parameterized for a particular system by 4 classes
+ * that supply the module and system specific functions it requires
+ */
+ /* The read functions for the module image to be loaded */
+struct dynamic_loader_stream;
+
+ /* This class defines "host" symbol and support functions */
+struct dynamic_loader_sym;
+
+ /* This class defines the allocator for "target" memory */
+struct dynamic_loader_allocate;
+
+ /* This class defines the copy-into-target-memory functions */
+struct dynamic_loader_initialize;
+
+/*
+ * Option flags to modify the behavior of module loading
+ */
+#define DLOAD_INITBSS 0x1 /* initialize BSS sections to zero */
+#define DLOAD_BIGEND 0x2 /* require big-endian load module */
+#define DLOAD_LITTLE 0x4 /* require little-endian load module */
+
+/*****************************************************************************
+ * Procedure dynamic_load_module
+ *
+ * Parameters:
+ * module The input stream that supplies the module image
+ * syms Host-side symbol table and malloc/free functions
+ * alloc Target-side memory allocation
+ * init Target-side memory initialization, or NULL for symbol read only
+ * options Option flags DLOAD_*
+ * mhandle A module handle for use with Dynamic_Unload
+ *
+ * Effect:
+ * The module image is read using *module. Target storage for the new image is
+ * obtained from *alloc. Symbols defined and referenced by the module are
+ * managed using *syms. The image is then relocated and references resolved
+ * as necessary, and the resulting executable bits are placed into target memory
+ * using *init.
+ *
+ * Returns:
+ * On a successful load, a module handle is placed in *mhandle, and zero is
+ * returned. On error, the number of errors detected is returned. Individual
+ * errors are reported during the load process using syms->error_report().
+ **************************************************************************** */
+extern int dynamic_load_module(
+ /* the source for the module image */
+ struct dynamic_loader_stream *module,
+ /* host support for symbols and storage */
+ struct dynamic_loader_sym *syms,
+ /* the target memory allocator */
+ struct dynamic_loader_allocate *alloc,
+ /* the target memory initializer */
+ struct dynamic_loader_initialize *init,
+ unsigned options, /* option flags */
+ /* the returned module handle */
+ void **mhandle);
+
+/*****************************************************************************
+ * Procedure dynamic_open_module
+ *
+ * Parameters:
+ * module The input stream that supplies the module image
+ * syms Host-side symbol table and malloc/free functions
+ * alloc Target-side memory allocation
+ * init Target-side memory initialization, or NULL for symbol read only
+ * options Option flags DLOAD_*
+ * mhandle A module handle for use with Dynamic_Unload
+ *
+ * Effect:
+ * The module image is read using *module. Target storage for the new image is
+ * obtained from *alloc. Symbols defined and referenced by the module are
+ * managed using *syms. The image is then relocated and references resolved
+ * as necessary, and the resulting executable bits are placed into target memory
+ * using *init.
+ *
+ * Returns:
+ * On a successful load, a module handle is placed in *mhandle, and zero is
+ * returned. On error, the number of errors detected is returned. Individual
+ * errors are reported during the load process using syms->error_report().
+ **************************************************************************** */
+extern int dynamic_open_module(
+ /* the source for the module image */
+ struct dynamic_loader_stream *module,
+ /* host support for symbols and storage */
+ struct dynamic_loader_sym *syms,
+ /* the target memory allocator */
+ struct dynamic_loader_allocate *alloc,
+ /* the target memory initializer */
+ struct dynamic_loader_initialize *init,
+ unsigned options, /* option flags */
+ /* the returned module handle */
+ void **mhandle);
+
+/*****************************************************************************
+ * Procedure dynamic_unload_module
+ *
+ * Parameters:
+ * mhandle A module handle from dynamic_load_module
+ * syms Host-side symbol table and malloc/free functions
+ * alloc Target-side memory allocation
+ *
+ * Effect:
+ * The module specified by mhandle is unloaded. Unloading causes all
+ * target memory to be deallocated, all symbols defined by the module to
+ * be purged, and any host-side storage used by the dynamic loader for
+ * this module to be released.
+ *
+ * Returns:
+ * Zero for success. On error, the number of errors detected is returned.
+ * Individual errors are reported using syms->error_report().
+ **************************************************************************** */
+extern int dynamic_unload_module(void *mhandle, /* the module
+ * handle */
+ /* host support for symbols and
+ * storage */
+ struct dynamic_loader_sym *syms,
+ /* the target memory allocator */
+ struct dynamic_loader_allocate *alloc,
+ /* the target memory initializer */
+ struct dynamic_loader_initialize *init);
+
+/*****************************************************************************
+ *****************************************************************************
+ * A class used by the dynamic loader for input of the module image
+ *****************************************************************************
+ **************************************************************************** */
+struct dynamic_loader_stream {
+/* public: */
+ /*************************************************************************
+ * read_buffer
+ *
+ * PARAMETERS :
+ * buffer Pointer to the buffer to fill
+ * bufsiz Amount of data desired in sizeof() units
+ *
+ * EFFECT :
+ * Reads the specified amount of data from the module input stream
+ * into the specified buffer. Returns the amount of data read in sizeof()
+ * units (which if less than the specification, represents an error).
+ *
+ * NOTES:
+ * In release 1 increments the file position by the number of bytes read
+ *
+ ************************************************************************ */
+ int (*read_buffer) (struct dynamic_loader_stream *thisptr,
+ void *buffer, unsigned bufsiz);
+
+ /*************************************************************************
+ * set_file_posn (release 1 only)
+ *
+ * PARAMETERS :
+ * posn Desired file position relative to start of file in sizeof() units.
+ *
+ * EFFECT :
+ * Adjusts the internal state of the stream object so that the next
+ * read_buffer call will begin to read at the specified offset from
+ * the beginning of the input module. Returns 0 for success, non-zero
+ * for failure.
+ *
+ ************************************************************************ */
+ int (*set_file_posn) (struct dynamic_loader_stream *thisptr,
+ /* to be eliminated in release 2 */
+ unsigned int posn);
+
+};
+
+/*****************************************************************************
+ *****************************************************************************
+ * A class used by the dynamic loader for symbol table support and
+ * miscellaneous host-side functions
+ *****************************************************************************
+ **************************************************************************** */
+
+typedef u32 ldr_addr;
+
+/*
+ * the structure of a symbol known to the dynamic loader
+ */
+struct dynload_symbol {
+ ldr_addr value;
+};
+
+struct dynamic_loader_sym {
+/* public: */
+ /*************************************************************************
+ * find_matching_symbol
+ *
+ * PARAMETERS :
+ * name The name of the desired symbol
+ *
+ * EFFECT :
+ * Locates a symbol matching the name specified. A pointer to the
+ * symbol is returned if it exists; 0 is returned if no such symbol is
+ * found.
+ *
+ ************************************************************************ */
+ struct dynload_symbol *(*find_matching_symbol)
+ (struct dynamic_loader_sym *thisptr, const char *name);
+
+ /*************************************************************************
+ * add_to_symbol_table
+ *
+ * PARAMETERS :
+ * nname Pointer to the name of the new symbol
+ * moduleid An opaque module id assigned by the dynamic loader
+ *
+ * EFFECT :
+ * The new symbol is added to the table. A pointer to the symbol is
+ * returned, or NULL is returned for failure.
+ *
+ * NOTES:
+ * It is permissible for this function to return NULL; the effect is that
+ * the named symbol will not be available to resolve references in
+ * subsequent loads. Returning NULL will not cause the current load
+ * to fail.
+ ************************************************************************ */
+ struct dynload_symbol *(*add_to_symbol_table)
+ (struct dynamic_loader_sym *
+ thisptr, const char *nname, unsigned moduleid);
+
+ /*************************************************************************
+ * purge_symbol_table
+ *
+ * PARAMETERS :
+ * moduleid An opaque module id assigned by the dynamic loader
+ *
+ * EFFECT :
+ * Each symbol in the symbol table whose moduleid matches the argument
+ * is removed from the table.
+ ************************************************************************ */
+ void (*purge_symbol_table) (struct dynamic_loader_sym *thisptr,
+ unsigned moduleid);
+
+ /*************************************************************************
+ * dload_allocate
+ *
+ * PARAMETERS :
+ * memsiz size of desired memory in sizeof() units
+ *
+ * EFFECT :
+ * Returns a pointer to some "host" memory for use by the dynamic
+ * loader, or NULL for failure.
+ * This function is serves as a replaceable form of "malloc" to
+ * allow the user to configure the memory usage of the dynamic loader.
+ ************************************************************************ */
+ void *(*dload_allocate) (struct dynamic_loader_sym *thisptr,
+ unsigned memsiz);
+
+ /*************************************************************************
+ * dload_deallocate
+ *
+ * PARAMETERS :
+ * memptr pointer to previously allocated memory
+ *
+ * EFFECT :
+ * Releases the previously allocated "host" memory.
+ ************************************************************************ */
+ void (*dload_deallocate) (struct dynamic_loader_sym *thisptr,
+ void *memptr);
+
+ /*************************************************************************
+ * error_report
+ *
+ * PARAMETERS :
+ * errstr pointer to an error string
+ * args additional arguments
+ *
+ * EFFECT :
+ * This function provides an error reporting interface for the dynamic
+ * loader. The error string and arguments are designed as for the
+ * library function vprintf.
+ ************************************************************************ */
+ void (*error_report) (struct dynamic_loader_sym *thisptr,
+ const char *errstr, va_list args);
+
+}; /* class dynamic_loader_sym */
+
+/*****************************************************************************
+ *****************************************************************************
+ * A class used by the dynamic loader to allocate and deallocate target memory.
+ *****************************************************************************
+ **************************************************************************** */
+
+struct ldr_section_info {
+ /* Name of the memory section assigned at build time */
+ const char *name;
+ ldr_addr run_addr; /* execution address of the section */
+ ldr_addr load_addr; /* load address of the section */
+ ldr_addr size; /* size of the section in addressable units */
+#ifndef _BIG_ENDIAN
+ u16 page; /* memory page or view */
+ u16 type; /* one of the section types below */
+#else
+ u16 type; /* one of the section types below */
+ u16 page; /* memory page or view */
+#endif
+ /* a context field for use by dynamic_loader_allocate;
+ * ignored but maintained by the dynamic loader */
+ u32 context;
+};
+
+/* use this macro to extract type of section from ldr_section_info.type field */
+#define DLOAD_SECTION_TYPE(typeinfo) (typeinfo & 0xF)
+
+/* type of section to be allocated */
+#define DLOAD_TEXT 0
+#define DLOAD_DATA 1
+#define DLOAD_BSS 2
+ /* internal use only, run-time cinit will be of type DLOAD_DATA */
+#define DLOAD_CINIT 3
+
+struct dynamic_loader_allocate {
+/* public: */
+
+ /*************************************************************************
+ * Function allocate
+ *
+ * Parameters:
+ * info A pointer to an information block for the section
+ * align The alignment of the storage in target AUs
+ *
+ * Effect:
+ * Allocates target memory for the specified section and fills in the
+ * load_addr and run_addr fields of the section info structure. Returns TRUE
+ * for success, FALSE for failure.
+ *
+ * Notes:
+ * Frequently load_addr and run_addr are the same, but if they are not
+ * load_addr is used with dynamic_loader_initialize, and run_addr is
+ * used for almost all relocations. This function should always initialize
+ * both fields.
+ ************************************************************************ */
+ int (*dload_allocate) (struct dynamic_loader_allocate *thisptr,
+ struct ldr_section_info *info, unsigned align);
+
+ /*************************************************************************
+ * Function deallocate
+ *
+ * Parameters:
+ * info A pointer to an information block for the section
+ *
+ * Effect:
+ * Releases the target memory previously allocated.
+ *
+ * Notes:
+ * The content of the info->name field is undefined on call to this function.
+ ************************************************************************ */
+ void (*dload_deallocate) (struct dynamic_loader_allocate *thisptr,
+ struct ldr_section_info *info);
+
+}; /* class dynamic_loader_allocate */
+
+/*****************************************************************************
+ *****************************************************************************
+ * A class used by the dynamic loader to load data into a target. This class
+ * provides the interface-specific functions needed to load data.
+ *****************************************************************************
+ **************************************************************************** */
+
+struct dynamic_loader_initialize {
+/* public: */
+ /*************************************************************************
+ * Function connect
+ *
+ * Parameters:
+ * none
+ *
+ * Effect:
+ * Connect to the initialization interface. Returns TRUE for success,
+ * FALSE for failure.
+ *
+ * Notes:
+ * This function is called prior to use of any other functions in
+ * this interface.
+ ************************************************************************ */
+ int (*connect) (struct dynamic_loader_initialize *thisptr);
+
+ /*************************************************************************
+ * Function readmem
+ *
+ * Parameters:
+ * bufr Pointer to a word-aligned buffer for the result
+ * locn Target address of first data element
+ * info Section info for the section in which the address resides
+ * bytsiz Size of the data to be read in sizeof() units
+ *
+ * Effect:
+ * Fills the specified buffer with data from the target. Returns TRUE for
+ * success, FALSE for failure.
+ ************************************************************************ */
+ int (*readmem) (struct dynamic_loader_initialize *thisptr,
+ void *bufr,
+ ldr_addr locn,
+ struct ldr_section_info *info, unsigned bytsiz);
+
+ /*************************************************************************
+ * Function writemem
+ *
+ * Parameters:
+ * bufr Pointer to a word-aligned buffer of data
+ * locn Target address of first data element to be written
+ * info Section info for the section in which the address resides
+ * bytsiz Size of the data to be written in sizeof() units
+ *
+ * Effect:
+ * Writes the specified buffer to the target. Returns TRUE for success,
+ * FALSE for failure.
+ ************************************************************************ */
+ int (*writemem) (struct dynamic_loader_initialize *thisptr,
+ void *bufr,
+ ldr_addr locn,
+ struct ldr_section_info *info, unsigned bytsiz);
+
+ /*************************************************************************
+ * Function fillmem
+ *
+ * Parameters:
+ * locn Target address of first data element to be written
+ * info Section info for the section in which the address resides
+ * bytsiz Size of the data to be written in sizeof() units
+ * val Value to be written in each byte
+ * Effect:
+ * Fills the specified area of target memory. Returns TRUE for success,
+ * FALSE for failure.
+ ************************************************************************ */
+ int (*fillmem) (struct dynamic_loader_initialize *thisptr,
+ ldr_addr locn, struct ldr_section_info *info,
+ unsigned bytsiz, unsigned val);
+
+ /*************************************************************************
+ * Function execute
+ *
+ * Parameters:
+ * start Starting address
+ *
+ * Effect:
+ * The target code at the specified starting address is executed.
+ *
+ * Notes:
+ * This function is called at the end of the dynamic load process
+ * if the input module has specified a starting address.
+ ************************************************************************ */
+ int (*execute) (struct dynamic_loader_initialize *thisptr,
+ ldr_addr start);
+
+ /*************************************************************************
+ * Function release
+ *
+ * Parameters:
+ * none
+ *
+ * Effect:
+ * Releases the connection to the load interface.
+ *
+ * Notes:
+ * This function is called at the end of the dynamic load process.
+ ************************************************************************ */
+ void (*release) (struct dynamic_loader_initialize *thisptr);
+
+}; /* class dynamic_loader_initialize */
+
+#endif /* _DYNAMIC_LOADER_H_ */
diff --git a/drivers/staging/tidspbridge/include/dspbridge/gb.h b/drivers/staging/tidspbridge/include/dspbridge/gb.h
new file mode 100644
index 00000000000..fda783aa160
--- /dev/null
+++ b/drivers/staging/tidspbridge/include/dspbridge/gb.h
@@ -0,0 +1,79 @@
+/*
+ * gb.h
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * Generic bitmap manager.
+ *
+ * Copyright (C) 2005-2006 Texas Instruments, Inc.
+ *
+ * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef GB_
+#define GB_
+
+#define GB_NOBITS (~0)
+#include <dspbridge/host_os.h>
+
+struct gb_t_map;
+
+/*
+ * ======== gb_clear ========
+ * Clear the bit in position bitn in the bitmap map. Bit positions are
+ * zero based.
+ */
+
+extern void gb_clear(struct gb_t_map *map, u32 bitn);
+
+/*
+ * ======== gb_create ========
+ * Create a bit map with len bits. Initially all bits are cleared.
+ */
+
+extern struct gb_t_map *gb_create(u32 len);
+
+/*
+ * ======== gb_delete ========
+ * Delete previously created bit map
+ */
+
+extern void gb_delete(struct gb_t_map *map);
+
+/*
+ * ======== gb_findandset ========
+ * Finds a clear bit, sets it, and returns the position
+ */
+
+extern u32 gb_findandset(struct gb_t_map *map);
+
+/*
+ * ======== gb_minclear ========
+ * gb_minclear returns the minimum clear bit position. If no bit is
+ * clear, gb_minclear returns -1.
+ */
+extern u32 gb_minclear(struct gb_t_map *map);
+
+/*
+ * ======== gb_set ========
+ * Set the bit in position bitn in the bitmap map. Bit positions are
+ * zero based.
+ */
+
+extern void gb_set(struct gb_t_map *map, u32 bitn);
+
+/*
+ * ======== gb_test ========
+ * Returns TRUE if the bit in position bitn is set in map; otherwise
+ * gb_test returns FALSE. Bit positions are zero based.
+ */
+
+extern bool gb_test(struct gb_t_map *map, u32 bitn);
+
+#endif /*GB_ */
diff --git a/drivers/staging/tidspbridge/include/dspbridge/getsection.h b/drivers/staging/tidspbridge/include/dspbridge/getsection.h
new file mode 100644
index 00000000000..626063dd9df
--- /dev/null
+++ b/drivers/staging/tidspbridge/include/dspbridge/getsection.h
@@ -0,0 +1,108 @@
+/*
+ * getsection.h
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * This file provides an API add-on to the dynamic loader that allows the user
+ * to query section information and extract section data from dynamic load
+ * modules.
+ *
+ * Notes:
+ * Functions in this API assume that the supplied dynamic_loader_stream
+ * object supports the set_file_posn method.
+ *
+ * Copyright (C) 2008 Texas Instruments, Inc.
+ *
+ * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef _GETSECTION_H_
+#define _GETSECTION_H_
+
+#include "dynamic_loader.h"
+
+/*
+ * Procedure dload_module_open
+ *
+ * Parameters:
+ * module The input stream that supplies the module image
+ * syms Host-side malloc/free and error reporting functions.
+ * Other methods are unused.
+ *
+ * Effect:
+ * Reads header information from a dynamic loader module using the specified
+ * stream object, and returns a handle for the module information. This
+ * handle may be used in subsequent query calls to obtain information
+ * contained in the module.
+ *
+ * Returns:
+ * NULL if an error is encountered, otherwise a module handle for use
+ * in subsequent operations.
+ */
+extern void *dload_module_open(struct dynamic_loader_stream
+ *module, struct dynamic_loader_sym
+ *syms);
+
+/*
+ * Procedure dload_get_section_info
+ *
+ * Parameters:
+ * minfo Handle from dload_module_open for this module
+ * section_name Pointer to the string name of the section desired
+ * section_info Address of a section info structure pointer to be initialized
+ *
+ * Effect:
+ * Finds the specified section in the module information, and fills in
+ * the provided ldr_section_info structure.
+ *
+ * Returns:
+ * TRUE for success, FALSE for section not found
+ */
+extern int dload_get_section_info(void *minfo,
+ const char *section_name,
+ const struct ldr_section_info
+ **const section_info);
+
+/*
+ * Procedure dload_get_section
+ *
+ * Parameters:
+ * minfo Handle from dload_module_open for this module
+ * section_info Pointer to a section info structure for the desired section
+ * section_data Buffer to contain the section initialized data
+ *
+ * Effect:
+ * Copies the initialized data for the specified section into the
+ * supplied buffer.
+ *
+ * Returns:
+ * TRUE for success, FALSE for section not found
+ */
+extern int dload_get_section(void *minfo,
+ const struct ldr_section_info *section_info,
+ void *section_data);
+
+/*
+ * Procedure dload_module_close
+ *
+ * Parameters:
+ * minfo Handle from dload_module_open for this module
+ *
+ * Effect:
+ * Releases any storage associated with the module handle. On return,
+ * the module handle is invalid.
+ *
+ * Returns:
+ * Zero for success. On error, the number of errors detected is returned.
+ * Individual errors are reported using syms->error_report(), where syms was
+ * an argument to dload_module_open
+ */
+extern void dload_module_close(void *minfo);
+
+#endif /* _GETSECTION_H_ */
diff --git a/drivers/staging/tidspbridge/include/dspbridge/gh.h b/drivers/staging/tidspbridge/include/dspbridge/gh.h
new file mode 100644
index 00000000000..9de291d1f56
--- /dev/null
+++ b/drivers/staging/tidspbridge/include/dspbridge/gh.h
@@ -0,0 +1,34 @@
+/*
+ * gh.h
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * Copyright (C) 2005-2006 Texas Instruments, Inc.
+ *
+ * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef GH_
+#define GH_
+#include <dspbridge/host_os.h>
+
+extern struct gh_t_hash_tab *gh_create(u16 max_bucket, u16 val_size,
+ u16(*hash) (void *, u16),
+ bool(*match) (void *, void *),
+ void (*delete) (void *));
+extern void gh_delete(struct gh_t_hash_tab *hash_tab);
+extern void gh_exit(void);
+extern void *gh_find(struct gh_t_hash_tab *hash_tab, void *key);
+extern void gh_init(void);
+extern void *gh_insert(struct gh_t_hash_tab *hash_tab, void *key, void *value);
+#ifdef CONFIG_TIDSPBRIDGE_BACKTRACE
+void gh_iterate(struct gh_t_hash_tab *hash_tab,
+ void (*callback)(void *, void *), void *user_data);
+#endif
+#endif /* GH_ */
diff --git a/drivers/staging/tidspbridge/include/dspbridge/gs.h b/drivers/staging/tidspbridge/include/dspbridge/gs.h
new file mode 100644
index 00000000000..f32d8d9af41
--- /dev/null
+++ b/drivers/staging/tidspbridge/include/dspbridge/gs.h
@@ -0,0 +1,59 @@
+/*
+ * gs.h
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * Memory allocation/release wrappers. This module allows clients to
+ * avoid OS spacific issues related to memory allocation. It also provides
+ * simple diagnostic capabilities to assist in the detection of memory
+ * leaks.
+ *
+ * Copyright (C) 2005-2006 Texas Instruments, Inc.
+ *
+ * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef GS_
+#define GS_
+
+/*
+ * ======== gs_alloc ========
+ * Alloc size bytes of space. Returns pointer to space
+ * allocated, otherwise NULL.
+ */
+extern void *gs_alloc(u32 size);
+
+/*
+ * ======== gs_exit ========
+ * Module exit. Do not change to "#define gs_init()"; in
+ * some environments this operation must actually do some work!
+ */
+extern void gs_exit(void);
+
+/*
+ * ======== gs_free ========
+ * Free space allocated by gs_alloc() or GS_calloc().
+ */
+extern void gs_free(void *ptr);
+
+/*
+ * ======== gs_frees ========
+ * Free space allocated by gs_alloc() or GS_calloc() and assert that
+ * the size of the allocation is size bytes.
+ */
+extern void gs_frees(void *ptr, u32 size);
+
+/*
+ * ======== gs_init ========
+ * Module initialization. Do not change to "#define gs_init()"; in
+ * some environments this operation must actually do some work!
+ */
+extern void gs_init(void);
+
+#endif /*GS_ */
diff --git a/drivers/staging/tidspbridge/include/dspbridge/host_os.h b/drivers/staging/tidspbridge/include/dspbridge/host_os.h
new file mode 100644
index 00000000000..6b4feb4d015
--- /dev/null
+++ b/drivers/staging/tidspbridge/include/dspbridge/host_os.h
@@ -0,0 +1,88 @@
+/*
+ * host_os.h
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * Copyright (C) 2008 Texas Instruments, Inc.
+ *
+ * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef _HOST_OS_H_
+#define _HOST_OS_H_
+
+#include <asm/system.h>
+#include <asm/atomic.h>
+#include <linux/semaphore.h>
+#include <linux/uaccess.h>
+#include <linux/irq.h>
+#include <linux/io.h>
+#include <linux/syscalls.h>
+#include <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/stddef.h>
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/sched.h>
+#include <linux/fs.h>
+#include <linux/file.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/ctype.h>
+#include <linux/mm.h>
+#include <linux/device.h>
+#include <linux/vmalloc.h>
+#include <linux/ioport.h>
+#include <linux/platform_device.h>
+#include <plat/clock.h>
+#include <linux/clk.h>
+#include <plat/mailbox.h>
+#include <linux/pagemap.h>
+#include <asm/cacheflush.h>
+#include <linux/dma-mapping.h>
+
+/* TODO -- Remove, once BP defines them */
+#define INT_DSP_MMU_IRQ 28
+
+struct dspbridge_platform_data {
+ void (*dsp_set_min_opp) (u8 opp_id);
+ u8(*dsp_get_opp) (void);
+ void (*cpu_set_freq) (unsigned long f);
+ unsigned long (*cpu_get_freq) (void);
+ unsigned long mpu_speed[6];
+
+ /* functions to write and read PRCM registers */
+ void (*dsp_prm_write)(u32, s16 , u16);
+ u32 (*dsp_prm_read)(s16 , u16);
+ u32 (*dsp_prm_rmw_bits)(u32, u32, s16, s16);
+ void (*dsp_cm_write)(u32, s16 , u16);
+ u32 (*dsp_cm_read)(s16 , u16);
+ u32 (*dsp_cm_rmw_bits)(u32, u32, s16, s16);
+
+ u32 phys_mempool_base;
+ u32 phys_mempool_size;
+};
+
+#define PRCM_VDD1 1
+
+extern struct platform_device *omap_dspbridge_dev;
+extern struct device *bridge;
+
+#if defined(CONFIG_TIDSPBRIDGE) || defined(CONFIG_TIDSPBRIDGE_MODULE)
+extern void dspbridge_reserve_sdram(void);
+#else
+static inline void dspbridge_reserve_sdram(void)
+{
+}
+#endif
+
+extern unsigned long dspbridge_get_mempool_base(void);
+#endif
diff --git a/drivers/staging/tidspbridge/include/dspbridge/io.h b/drivers/staging/tidspbridge/include/dspbridge/io.h
new file mode 100644
index 00000000000..bc346f9a01c
--- /dev/null
+++ b/drivers/staging/tidspbridge/include/dspbridge/io.h
@@ -0,0 +1,114 @@
+/*
+ * io.h
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * The io module manages IO between CHNL and msg_ctrl.
+ *
+ * Copyright (C) 2005-2006 Texas Instruments, Inc.
+ *
+ * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef IO_
+#define IO_
+
+#include <dspbridge/cfgdefs.h>
+#include <dspbridge/devdefs.h>
+
+#include <dspbridge/iodefs.h>
+
+/*
+ * ======== io_create ========
+ * Purpose:
+ * Create an IO manager object, responsible for managing IO between
+ * CHNL and msg_ctrl.
+ * Parameters:
+ * channel_mgr: Location to store a channel manager object on
+ * output.
+ * hdev_obj: Handle to a device object.
+ * mgr_attrts: IO manager attributes.
+ * mgr_attrts->birq: I/O IRQ number.
+ * mgr_attrts->irq_shared: TRUE if the IRQ is shareable.
+ * mgr_attrts->word_size: DSP Word size in equivalent PC bytes..
+ * Returns:
+ * 0: Success;
+ * -ENOMEM: Insufficient memory for requested resources.
+ * -EIO: Unable to plug channel ISR for configured IRQ.
+ * -EINVAL: Invalid DSP word size (must be > 0).
+ * Invalid base address for DSP communications.
+ * Requires:
+ * io_init(void) called.
+ * io_man != NULL.
+ * mgr_attrts != NULL.
+ * Ensures:
+ */
+extern int io_create(struct io_mgr **io_man,
+ struct dev_object *hdev_obj,
+ const struct io_attrs *mgr_attrts);
+
+/*
+ * ======== io_destroy ========
+ * Purpose:
+ * Destroy the IO manager.
+ * Parameters:
+ * hio_mgr: IOmanager object.
+ * Returns:
+ * 0: Success.
+ * -EFAULT: hio_mgr was invalid.
+ * Requires:
+ * io_init(void) called.
+ * Ensures:
+ */
+extern int io_destroy(struct io_mgr *hio_mgr);
+
+/*
+ * ======== io_exit ========
+ * Purpose:
+ * Discontinue usage of the IO module.
+ * Parameters:
+ * Returns:
+ * Requires:
+ * io_init(void) previously called.
+ * Ensures:
+ * Resources, if any acquired in io_init(void), are freed when the last
+ * client of IO calls io_exit(void).
+ */
+extern void io_exit(void);
+
+/*
+ * ======== io_init ========
+ * Purpose:
+ * Initialize the IO module's private state.
+ * Parameters:
+ * Returns:
+ * TRUE if initialized; FALSE if error occurred.
+ * Requires:
+ * Ensures:
+ * A requirement for each of the other public CHNL functions.
+ */
+extern bool io_init(void);
+
+/*
+ * ======== io_on_loaded ========
+ * Purpose:
+ * Called when a program is loaded so IO manager can update its
+ * internal state.
+ * Parameters:
+ * hio_mgr: IOmanager object.
+ * Returns:
+ * 0: Success.
+ * -EFAULT: hio_mgr was invalid.
+ * Requires:
+ * io_init(void) called.
+ * Ensures:
+ */
+extern int io_on_loaded(struct io_mgr *hio_mgr);
+
+#endif /* CHNL_ */
diff --git a/drivers/staging/tidspbridge/include/dspbridge/io_sm.h b/drivers/staging/tidspbridge/include/dspbridge/io_sm.h
new file mode 100644
index 00000000000..18aec55d864
--- /dev/null
+++ b/drivers/staging/tidspbridge/include/dspbridge/io_sm.h
@@ -0,0 +1,298 @@
+/*
+ * io_sm.h
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * IO dispatcher for a shared memory channel driver.
+ * Also, includes macros to simulate shm via port io calls.
+ *
+ * Copyright (C) 2005-2006 Texas Instruments, Inc.
+ *
+ * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef IOSM_
+#define IOSM_
+
+#include <dspbridge/_chnl_sm.h>
+#include <dspbridge/host_os.h>
+
+#include <dspbridge/iodefs.h>
+
+#define IO_INPUT 0
+#define IO_OUTPUT 1
+#define IO_SERVICE 2
+#define IO_MAXSERVICE IO_SERVICE
+
+#ifdef CONFIG_TIDSPBRIDGE_DVFS
+/* The maximum number of OPPs that are supported */
+extern s32 dsp_max_opps;
+/* The Vdd1 opp table information */
+extern u32 vdd1_dsp_freq[6][4];
+#endif
+
+/*
+ * ======== io_cancel_chnl ========
+ * Purpose:
+ * Cancel IO on a given channel.
+ * Parameters:
+ * hio_mgr: IO Manager.
+ * chnl: Index of channel to cancel IO on.
+ * Returns:
+ * Requires:
+ * Valid hio_mgr.
+ * Ensures:
+ */
+extern void io_cancel_chnl(struct io_mgr *hio_mgr, u32 chnl);
+
+/*
+ * ======== io_dpc ========
+ * Purpose:
+ * Deferred procedure call for shared memory channel driver ISR. Carries
+ * out the dispatch of I/O.
+ * Parameters:
+ * ref_data: Pointer to reference data registered via a call to
+ * DPC_Create().
+ * Returns:
+ * Requires:
+ * Must not block.
+ * Must not acquire resources.
+ * All data touched must be locked in memory if running in kernel mode.
+ * Ensures:
+ * Non-preemptible (but interruptible).
+ */
+extern void io_dpc(unsigned long ref_data);
+
+/*
+ * ======== io_mbox_msg ========
+ * Purpose:
+ * Main interrupt handler for the shared memory Bridge channel manager.
+ * Calls the Bridge's chnlsm_isr to determine if this interrupt is ours,
+ * then schedules a DPC to dispatch I/O.
+ * Parameters:
+ * ref_data: Pointer to the channel manager object for this board.
+ * Set in an initial call to ISR_Install().
+ * Returns:
+ * TRUE if interrupt handled; FALSE otherwise.
+ * Requires:
+ * Must be in locked memory if executing in kernel mode.
+ * Must only call functions which are in locked memory if Kernel mode.
+ * Must only call asynchronous services.
+ * Interrupts are disabled and EOI for this interrupt has been sent.
+ * Ensures:
+ */
+void io_mbox_msg(u32 msg);
+
+/*
+ * ======== io_request_chnl ========
+ * Purpose:
+ * Request I/O from the DSP. Sets flags in shared memory, then interrupts
+ * the DSP.
+ * Parameters:
+ * hio_mgr: IO manager handle.
+ * pchnl: Ptr to the channel requesting I/O.
+ * io_mode: Mode of channel: {IO_INPUT | IO_OUTPUT}.
+ * Returns:
+ * Requires:
+ * pchnl != NULL
+ * Ensures:
+ */
+extern void io_request_chnl(struct io_mgr *io_manager,
+ struct chnl_object *pchnl,
+ u8 io_mode, u16 *mbx_val);
+
+/*
+ * ======== iosm_schedule ========
+ * Purpose:
+ * Schedule DPC for IO.
+ * Parameters:
+ * pio_mgr: Ptr to a I/O manager.
+ * Returns:
+ * Requires:
+ * pchnl != NULL
+ * Ensures:
+ */
+extern void iosm_schedule(struct io_mgr *io_manager);
+
+/*
+ * DSP-DMA IO functions
+ */
+
+/*
+ * ======== io_ddma_init_chnl_desc ========
+ * Purpose:
+ * Initialize DSP DMA channel descriptor.
+ * Parameters:
+ * hio_mgr: Handle to a I/O manager.
+ * ddma_chnl_id: DDMA channel identifier.
+ * num_desc: Number of buffer descriptors(equals # of IOReqs &
+ * Chirps)
+ * dsp: Dsp address;
+ * Returns:
+ * Requires:
+ * ddma_chnl_id < DDMA_MAXDDMACHNLS
+ * num_desc > 0
+ * pVa != NULL
+ * pDspPa != NULL
+ *
+ * Ensures:
+ */
+extern void io_ddma_init_chnl_desc(struct io_mgr *hio_mgr, u32 ddma_chnl_id,
+ u32 num_desc, void *dsp);
+
+/*
+ * ======== io_ddma_clear_chnl_desc ========
+ * Purpose:
+ * Clear DSP DMA channel descriptor.
+ * Parameters:
+ * hio_mgr: Handle to a I/O manager.
+ * ddma_chnl_id: DDMA channel identifier.
+ * Returns:
+ * Requires:
+ * ddma_chnl_id < DDMA_MAXDDMACHNLS
+ * Ensures:
+ */
+extern void io_ddma_clear_chnl_desc(struct io_mgr *hio_mgr, u32 ddma_chnl_id);
+
+/*
+ * ======== io_ddma_request_chnl ========
+ * Purpose:
+ * Request channel DSP-DMA from the DSP. Sets up SM descriptors and
+ * control fields in shared memory.
+ * Parameters:
+ * hio_mgr: Handle to a I/O manager.
+ * pchnl: Ptr to channel object
+ * chnl_packet_obj: Ptr to channel i/o request packet.
+ * Returns:
+ * Requires:
+ * pchnl != NULL
+ * pchnl->cio_reqs > 0
+ * chnl_packet_obj != NULL
+ * Ensures:
+ */
+extern void io_ddma_request_chnl(struct io_mgr *hio_mgr,
+ struct chnl_object *pchnl,
+ struct chnl_irp *chnl_packet_obj,
+ u16 *mbx_val);
+
+/*
+ * Zero-copy IO functions
+ */
+
+/*
+ * ======== io_ddzc_init_chnl_desc ========
+ * Purpose:
+ * Initialize ZCPY channel descriptor.
+ * Parameters:
+ * hio_mgr: Handle to a I/O manager.
+ * zid: zero-copy channel identifier.
+ * Returns:
+ * Requires:
+ * ddma_chnl_id < DDMA_MAXZCPYCHNLS
+ * hio_mgr != Null
+ * Ensures:
+ */
+extern void io_ddzc_init_chnl_desc(struct io_mgr *hio_mgr, u32 zid);
+
+/*
+ * ======== io_ddzc_clear_chnl_desc ========
+ * Purpose:
+ * Clear DSP ZC channel descriptor.
+ * Parameters:
+ * hio_mgr: Handle to a I/O manager.
+ * ch_id: ZC channel identifier.
+ * Returns:
+ * Requires:
+ * hio_mgr is valid
+ * ch_id < DDMA_MAXZCPYCHNLS
+ * Ensures:
+ */
+extern void io_ddzc_clear_chnl_desc(struct io_mgr *hio_mgr, u32 ch_id);
+
+/*
+ * ======== io_ddzc_request_chnl ========
+ * Purpose:
+ * Request zero-copy channel transfer. Sets up SM descriptors and
+ * control fields in shared memory.
+ * Parameters:
+ * hio_mgr: Handle to a I/O manager.
+ * pchnl: Ptr to channel object
+ * chnl_packet_obj: Ptr to channel i/o request packet.
+ * Returns:
+ * Requires:
+ * pchnl != NULL
+ * pchnl->cio_reqs > 0
+ * chnl_packet_obj != NULL
+ * Ensures:
+ */
+extern void io_ddzc_request_chnl(struct io_mgr *hio_mgr,
+ struct chnl_object *pchnl,
+ struct chnl_irp *chnl_packet_obj,
+ u16 *mbx_val);
+
+/*
+ * ======== io_sh_msetting ========
+ * Purpose:
+ * Sets the shared memory setting
+ * Parameters:
+ * hio_mgr: Handle to a I/O manager.
+ * desc: Shared memory type
+ * pargs: Ptr to shm setting
+ * Returns:
+ * Requires:
+ * hio_mgr != NULL
+ * pargs != NULL
+ * Ensures:
+ */
+extern int io_sh_msetting(struct io_mgr *hio_mgr, u8 desc, void *pargs);
+
+/*
+ * Misc functions for the CHNL_IO shared memory library:
+ */
+
+/* Maximum channel bufsize that can be used. */
+extern u32 io_buf_size(struct io_mgr *hio_mgr);
+
+extern u32 io_read_value(struct bridge_dev_context *dev_ctxt, u32 dsp_addr);
+
+extern void io_write_value(struct bridge_dev_context *dev_ctxt,
+ u32 dsp_addr, u32 value);
+
+extern u32 io_read_value_long(struct bridge_dev_context *dev_ctxt,
+ u32 dsp_addr);
+
+extern void io_write_value_long(struct bridge_dev_context *dev_ctxt,
+ u32 dsp_addr, u32 value);
+
+extern void io_or_set_value(struct bridge_dev_context *dev_ctxt,
+ u32 dsp_addr, u32 value);
+
+extern void io_and_set_value(struct bridge_dev_context *dev_ctxt,
+ u32 dsp_addr, u32 value);
+
+extern void io_sm_init(void);
+
+#ifdef CONFIG_TIDSPBRIDGE_BACKTRACE
+/*
+ * ========print_dsp_trace_buffer ========
+ * Print DSP tracebuffer.
+ */
+extern int print_dsp_trace_buffer(struct bridge_dev_context
+ *hbridge_context);
+
+int dump_dsp_stack(struct bridge_dev_context *bridge_context);
+
+void dump_dl_modules(struct bridge_dev_context *bridge_context);
+
+#endif
+#if defined(CONFIG_TIDSPBRIDGE_BACKTRACE) || defined(CONFIG_TIDSPBRIDGE_DEBUG)
+void print_dsp_debug_trace(struct io_mgr *hio_mgr);
+#endif
+
+#endif /* IOSM_ */
diff --git a/drivers/staging/tidspbridge/include/dspbridge/iodefs.h b/drivers/staging/tidspbridge/include/dspbridge/iodefs.h
new file mode 100644
index 00000000000..8bd10a04200
--- /dev/null
+++ b/drivers/staging/tidspbridge/include/dspbridge/iodefs.h
@@ -0,0 +1,36 @@
+/*
+ * iodefs.h
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * System-wide channel objects and constants.
+ *
+ * Copyright (C) 2005-2006 Texas Instruments, Inc.
+ *
+ * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef IODEFS_
+#define IODEFS_
+
+#define IO_MAXIRQ 0xff /* Arbitrarily large number. */
+
+/* IO Objects: */
+struct io_mgr;
+
+/* IO manager attributes: */
+struct io_attrs {
+ u8 birq; /* Channel's I/O IRQ number. */
+ bool irq_shared; /* TRUE if the IRQ is shareable. */
+ u32 word_size; /* DSP Word size. */
+ u32 shm_base; /* Physical base address of shared memory. */
+ u32 usm_length; /* Size (in bytes) of shared memory. */
+};
+
+#endif /* IODEFS_ */
diff --git a/drivers/staging/tidspbridge/include/dspbridge/ldr.h b/drivers/staging/tidspbridge/include/dspbridge/ldr.h
new file mode 100644
index 00000000000..6a0269cd07e
--- /dev/null
+++ b/drivers/staging/tidspbridge/include/dspbridge/ldr.h
@@ -0,0 +1,29 @@
+/*
+ * ldr.h
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * Provide module loading services and symbol export services.
+ *
+ * Notes:
+ * This service is meant to be used by modules of the DSP/BIOS Bridge
+ * driver.
+ *
+ * Copyright (C) 2005-2006 Texas Instruments, Inc.
+ *
+ * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef LDR_
+#define LDR_
+
+/* Loader objects: */
+struct ldr_module;
+
+#endif /* LDR_ */
diff --git a/drivers/staging/tidspbridge/include/dspbridge/list.h b/drivers/staging/tidspbridge/include/dspbridge/list.h
new file mode 100644
index 00000000000..6837b614073
--- /dev/null
+++ b/drivers/staging/tidspbridge/include/dspbridge/list.h
@@ -0,0 +1,225 @@
+/*
+ * list.h
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * Declarations of list management control structures and definitions
+ * of inline list management functions.
+ *
+ * Copyright (C) 2008 Texas Instruments, Inc.
+ *
+ * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef LIST_
+#define LIST_
+
+#include <dspbridge/host_os.h>
+#include <linux/list.h>
+
+#define LST_IS_EMPTY(l) list_empty(&(l)->head)
+
+struct lst_list {
+ struct list_head head;
+};
+
+/*
+ * ======== lst_first ========
+ * Purpose:
+ * Returns a pointer to the first element of the list, or NULL if the list
+ * is empty.
+ * Parameters:
+ * lst: Pointer to list control structure.
+ * Returns:
+ * Pointer to first list element, or NULL.
+ * Requires:
+ * - LST initialized.
+ * - lst != NULL.
+ * Ensures:
+ */
+static inline struct list_head *lst_first(struct lst_list *lst)
+{
+ if (lst && !list_empty(&lst->head))
+ return lst->head.next;
+ return NULL;
+}
+
+/*
+ * ======== lst_get_head ========
+ * Purpose:
+ * Pops the head off the list and returns a pointer to it.
+ * Details:
+ * If the list is empty, returns NULL.
+ * Else, removes the element at the head of the list, making the next
+ * element the head of the list.
+ * The head is removed by making the tail element of the list point its
+ * "next" pointer at the next element after the head, and by making the
+ * "prev" pointer of the next element after the head point at the tail
+ * element. So the next element after the head becomes the new head of
+ * the list.
+ * Parameters:
+ * lst: Pointer to list control structure of list whose head
+ * element is to be removed
+ * Returns:
+ * Pointer to element that was at the head of the list (success)
+ * NULL No elements in list
+ * Requires:
+ * - LST initialized.
+ * - lst != NULL.
+ * Ensures:
+ * Notes:
+ * Because the tail of the list points forward (its "next" pointer) to
+ * the head of the list, and the head of the list points backward (its
+ * "prev" pointer) to the tail of the list, this list is circular.
+ */
+static inline struct list_head *lst_get_head(struct lst_list *lst)
+{
+ struct list_head *elem_list;
+
+ if (!lst || list_empty(&lst->head))
+ return NULL;
+
+ elem_list = lst->head.next;
+ lst->head.next = elem_list->next;
+ elem_list->next->prev = &lst->head;
+
+ return elem_list;
+}
+
+/*
+ * ======== lst_init_elem ========
+ * Purpose:
+ * Initializes a list element to default (cleared) values
+ * Details:
+ * Parameters:
+ * elem_list: Pointer to list element to be reset
+ * Returns:
+ * Requires:
+ * LST initialized.
+ * Ensures:
+ * Notes:
+ * This function must not be called to "reset" an element in the middle
+ * of a list chain -- that would break the chain.
+ *
+ */
+static inline void lst_init_elem(struct list_head *elem_list)
+{
+ if (elem_list) {
+ elem_list->next = NULL;
+ elem_list->prev = NULL;
+ }
+}
+
+/*
+ * ======== lst_insert_before ========
+ * Purpose:
+ * Insert the element before the existing element.
+ * Parameters:
+ * lst: Pointer to list control structure.
+ * elem_list: Pointer to element in list to insert.
+ * elem_existing: Pointer to existing list element.
+ * Returns:
+ * Requires:
+ * - LST initialized.
+ * - lst != NULL.
+ * - elem_list != NULL.
+ * - elem_existing != NULL.
+ * Ensures:
+ */
+static inline void lst_insert_before(struct lst_list *lst,
+ struct list_head *elem_list,
+ struct list_head *elem_existing)
+{
+ if (lst && elem_list && elem_existing)
+ list_add_tail(elem_list, elem_existing);
+}
+
+/*
+ * ======== lst_next ========
+ * Purpose:
+ * Returns a pointer to the next element of the list, or NULL if the next
+ * element is the head of the list or the list is empty.
+ * Parameters:
+ * lst: Pointer to list control structure.
+ * cur_elem: Pointer to element in list to remove.
+ * Returns:
+ * Pointer to list element, or NULL.
+ * Requires:
+ * - LST initialized.
+ * - lst != NULL.
+ * - cur_elem != NULL.
+ * Ensures:
+ */
+static inline struct list_head *lst_next(struct lst_list *lst,
+ struct list_head *cur_elem)
+{
+ if (lst && !list_empty(&lst->head) && cur_elem &&
+ (cur_elem->next != &lst->head))
+ return cur_elem->next;
+ return NULL;
+}
+
+/*
+ * ======== lst_put_tail ========
+ * Purpose:
+ * Adds the specified element to the tail of the list
+ * Details:
+ * Sets new element's "prev" pointer to the address previously held by
+ * the head element's prev pointer. This is the previous tail member of
+ * the list.
+ * Sets the new head's prev pointer to the address of the element.
+ * Sets next pointer of the previous tail member of the list to point to
+ * the new element (rather than the head, which it had been pointing at).
+ * Sets new element's next pointer to the address of the head element.
+ * Sets head's prev pointer to the address of the new element.
+ * Parameters:
+ * lst: Pointer to list control structure to which *elem_list will be
+ * added
+ * elem_list: Pointer to list element to be added
+ * Returns:
+ * Void
+ * Requires:
+ * *elem_list and *lst must both exist.
+ * LST initialized.
+ * Ensures:
+ * Notes:
+ * Because the tail is always "just before" the head of the list (the
+ * tail's "next" pointer points at the head of the list, and the head's
+ * "prev" pointer points at the tail of the list), the list is circular.
+ */
+static inline void lst_put_tail(struct lst_list *lst,
+ struct list_head *elem_list)
+{
+ if (lst && elem_list)
+ list_add_tail(elem_list, &lst->head);
+}
+
+/*
+ * ======== lst_remove_elem ========
+ * Purpose:
+ * Removes (unlinks) the given element from the list, if the list is not
+ * empty. Does not free the list element.
+ * Parameters:
+ * lst: Pointer to list control structure.
+ * cur_elem: Pointer to element in list to remove.
+ * Returns:
+ * Requires:
+ * - LST initialized.
+ * - lst != NULL.
+ * - cur_elem != NULL.
+ * Ensures:
+ */
+static inline void lst_remove_elem(struct lst_list *lst,
+ struct list_head *cur_elem)
+{
+ if (lst && !list_empty(&lst->head) && cur_elem)
+ list_del_init(cur_elem);
+}
+
+#endif /* LIST_ */
diff --git a/drivers/staging/tidspbridge/include/dspbridge/mbx_sh.h b/drivers/staging/tidspbridge/include/dspbridge/mbx_sh.h
new file mode 100644
index 00000000000..5d165cd932f
--- /dev/null
+++ b/drivers/staging/tidspbridge/include/dspbridge/mbx_sh.h
@@ -0,0 +1,184 @@
+/*
+ * mbx_sh.h
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * Definitions for shared mailbox cmd/data values.(used on both
+ * the GPP and DSP sides).
+ *
+ * Copyright (C) 2008 Texas Instruments, Inc.
+ *
+ * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+/*
+ * Bridge usage of OMAP mailbox 1 is determined by the "class" of the
+ * mailbox interrupt's cmd value received. The class value are defined
+ * as a bit (10 thru 15) being set.
+ *
+ * Note: Only 16 bits of each is used. Other 16 bit data reg available.
+ *
+ * 16 bit Mbx bit defns:
+ *
+ * A). Exception/Error handling (Module DEH) : class = 0.
+ *
+ * 15 10 0
+ * ---------------------------------
+ * |0|0|0|0|0|0|x|x|x|x|x|x|x|x|x|x|
+ * ---------------------------------
+ * | (class) | (module specific) |
+ *
+ *
+ * B: DSP-DMA link driver channels (DDMA) : class = 1.
+ *
+ * 15 10 0
+ * ---------------------------------
+ * |0|0|0|0|0|1|b|b|b|b|b|c|c|c|c|c|
+ * ---------------------------------
+ * | (class) | (module specific) |
+ *
+ * where b -> buffer index (32 DDMA buffers/chnl max)
+ * c -> channel Id (32 DDMA chnls max)
+ *
+ *
+ * C: Proc-copy link driver channels (PCPY) : class = 2.
+ *
+ * 15 10 0
+ * ---------------------------------
+ * |0|0|0|0|1|0|x|x|x|x|x|x|x|x|x|x|
+ * ---------------------------------
+ * | (class) | (module specific) |
+ *
+ *
+ * D: Zero-copy link driver channels (DDZC) : class = 4.
+ *
+ * 15 10 0
+ * ---------------------------------
+ * |0|0|0|1|0|0|x|x|x|x|x|c|c|c|c|c|
+ * ---------------------------------
+ * | (class) | (module specific) |
+ *
+ * where x -> not used
+ * c -> channel Id (32 ZCPY chnls max)
+ *
+ *
+ * E: Power management : class = 8.
+ *
+ * 15 10 0
+ * ---------------------------------
+ * |0|0|1|0|0|0|x|x|x|x|x|c|c|c|c|c|
+
+ * 0010 00xx xxxc cccc
+ * 0010 00nn pppp qqqq
+ * nn:
+ * 00 = reserved
+ * 01 = pwr state change
+ * 10 = opp pre-change
+ * 11 = opp post-change
+ *
+ * if nn = pwr state change:
+ * pppp = don't care
+ * qqqq:
+ * 0010 = hibernate
+ * 0010 0001 0000 0010
+ * 0110 = retention
+ * 0010 0001 0000 0110
+ * others reserved
+ *
+ * if nn = opp pre-change:
+ * pppp = current opp
+ * qqqq = next opp
+ *
+ * if nn = opp post-change:
+ * pppp = prev opp
+ * qqqq = current opp
+ *
+ * ---------------------------------
+ * | (class) | (module specific) |
+ *
+ * where x -> not used
+ * c -> Power management command
+ *
+ */
+
+#ifndef _MBX_SH_H
+#define _MBX_SH_H
+
+#define MBX_CLASS_MSK 0xFC00 /* Class bits are 10 thru 15 */
+#define MBX_VALUE_MSK 0x03FF /* Value is 0 thru 9 */
+
+#define MBX_DEH_CLASS 0x0000 /* DEH owns Mbx INTR */
+#define MBX_DDMA_CLASS 0x0400 /* DSP-DMA link drvr chnls owns INTR */
+#define MBX_PCPY_CLASS 0x0800 /* PROC-COPY " */
+#define MBX_ZCPY_CLASS 0x1000 /* ZERO-COPY " */
+#define MBX_PM_CLASS 0x2000 /* Power Management */
+#define MBX_DBG_CLASS 0x4000 /* For debugging purpose */
+
+/*
+ * Exception Handler codes
+ * Magic code used to determine if DSP signaled exception.
+ */
+#define MBX_DEH_BASE 0x0
+#define MBX_DEH_USERS_BASE 0x100 /* 256 */
+#define MBX_DEH_LIMIT 0x3FF /* 1023 */
+#define MBX_DEH_RESET 0x101 /* DSP RESET (DEH) */
+#define MBX_DEH_EMMU 0X103 /*DSP MMU FAULT RECOVERY */
+
+/*
+ * Link driver command/status codes.
+ */
+/* DSP-DMA */
+#define MBX_DDMA_NUMCHNLBITS 5 /* # chnl Id: # bits available */
+#define MBX_DDMA_CHNLSHIFT 0 /* # of bits to shift */
+#define MBX_DDMA_CHNLMSK 0x01F /* bits 0 thru 4 */
+
+#define MBX_DDMA_NUMBUFBITS 5 /* buffer index: # of bits avail */
+#define MBX_DDMA_BUFSHIFT (MBX_DDMA_NUMCHNLBITS + MBX_DDMA_CHNLSHIFT)
+#define MBX_DDMA_BUFMSK 0x3E0 /* bits 5 thru 9 */
+
+/* Zero-Copy */
+#define MBX_ZCPY_NUMCHNLBITS 5 /* # chnl Id: # bits available */
+#define MBX_ZCPY_CHNLSHIFT 0 /* # of bits to shift */
+#define MBX_ZCPY_CHNLMSK 0x01F /* bits 0 thru 4 */
+
+/* Power Management Commands */
+#define MBX_PM_DSPIDLE (MBX_PM_CLASS + 0x0)
+#define MBX_PM_DSPWAKEUP (MBX_PM_CLASS + 0x1)
+#define MBX_PM_EMERGENCYSLEEP (MBX_PM_CLASS + 0x2)
+#define MBX_PM_SLEEPUNTILRESTART (MBX_PM_CLASS + 0x3)
+#define MBX_PM_DSPGLOBALIDLE_OFF (MBX_PM_CLASS + 0x4)
+#define MBX_PM_DSPGLOBALIDLE_ON (MBX_PM_CLASS + 0x5)
+#define MBX_PM_SETPOINT_PRENOTIFY (MBX_PM_CLASS + 0x6)
+#define MBX_PM_SETPOINT_POSTNOTIFY (MBX_PM_CLASS + 0x7)
+#define MBX_PM_DSPRETN (MBX_PM_CLASS + 0x8)
+#define MBX_PM_DSPRETENTION (MBX_PM_CLASS + 0x8)
+#define MBX_PM_DSPHIBERNATE (MBX_PM_CLASS + 0x9)
+#define MBX_PM_HIBERNATE_EN (MBX_PM_CLASS + 0xA)
+#define MBX_PM_OPP_REQ (MBX_PM_CLASS + 0xB)
+#define MBX_PM_OPP_CHG (MBX_PM_CLASS + 0xC)
+
+#define MBX_PM_TYPE_MASK 0x0300
+#define MBX_PM_TYPE_PWR_CHNG 0x0100
+#define MBX_PM_TYPE_OPP_PRECHNG 0x0200
+#define MBX_PM_TYPE_OPP_POSTCHNG 0x0300
+#define MBX_PM_TYPE_OPP_MASK 0x0300
+#define MBX_PM_OPP_PRECHNG (MBX_PM_CLASS | MBX_PM_TYPE_OPP_PRECHNG)
+/* DSP to MPU */
+#define MBX_PM_OPP_CHNG(OPP) (MBX_PM_CLASS | MBX_PM_TYPE_OPP_PRECHNG | (OPP))
+#define MBX_PM_RET (MBX_PM_CLASS | MBX_PM_TYPE_PWR_CHNG | 0x0006)
+#define MBX_PM_HIB (MBX_PM_CLASS | MBX_PM_TYPE_PWR_CHNG | 0x0002)
+#define MBX_PM_OPP1 0
+#define MBX_PM_OPP2 1
+#define MBX_PM_OPP3 2
+#define MBX_PM_OPP4 3
+
+/* Bridge Debug Commands */
+#define MBX_DBG_SYSPRINTF (MBX_DBG_CLASS + 0x0)
+
+#endif /* _MBX_SH_H */
diff --git a/drivers/staging/tidspbridge/include/dspbridge/memdefs.h b/drivers/staging/tidspbridge/include/dspbridge/memdefs.h
new file mode 100644
index 00000000000..78d2c5d0045
--- /dev/null
+++ b/drivers/staging/tidspbridge/include/dspbridge/memdefs.h
@@ -0,0 +1,30 @@
+/*
+ * memdefs.h
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * Global MEM constants and types, shared between Bridge driver and DSP API.
+ *
+ * Copyright (C) 2008 Texas Instruments, Inc.
+ *
+ * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef MEMDEFS_
+#define MEMDEFS_
+
+/*
+ * MEM_VIRTUALSEGID is used by Node & Strm to access virtual address space in
+ * the correct client process context.
+ */
+#define MEM_SETVIRTUALSEGID 0x10000000
+#define MEM_GETVIRTUALSEGID 0x20000000
+#define MEM_MASKVIRTUALSEGID (MEM_SETVIRTUALSEGID | MEM_GETVIRTUALSEGID)
+
+#endif /* MEMDEFS_ */
diff --git a/drivers/staging/tidspbridge/include/dspbridge/mgr.h b/drivers/staging/tidspbridge/include/dspbridge/mgr.h
new file mode 100644
index 00000000000..99f7dc0116b
--- /dev/null
+++ b/drivers/staging/tidspbridge/include/dspbridge/mgr.h
@@ -0,0 +1,205 @@
+/*
+ * mgr.h
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * This is the DSP API RM module interface.
+ *
+ * Copyright (C) 2005-2006 Texas Instruments, Inc.
+ *
+ * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef MGR_
+#define MGR_
+
+#include <dspbridge/mgrpriv.h>
+
+#define MAX_EVENTS 32
+
+/*
+ * ======== mgr_wait_for_bridge_events ========
+ * Purpose:
+ * Block on any Bridge event(s)
+ * Parameters:
+ * anotifications : array of pointers to notification objects.
+ * count : number of elements in above array
+ * pu_index : index of signaled event object
+ * utimeout : timeout interval in milliseocnds
+ * Returns:
+ * 0 : Success.
+ * -ETIME : Wait timed out. *pu_index is undetermined.
+ * Details:
+ */
+
+int mgr_wait_for_bridge_events(struct dsp_notification
+ **anotifications,
+ u32 count, u32 *pu_index,
+ u32 utimeout);
+
+/*
+ * ======== mgr_create ========
+ * Purpose:
+ * Creates the Manager Object. This is done during the driver loading.
+ * There is only one Manager Object in the DSP/BIOS Bridge.
+ * Parameters:
+ * mgr_obj: Location to store created MGR Object handle.
+ * dev_node_obj: Device object as known to the system.
+ * Returns:
+ * 0: Success
+ * -ENOMEM: Failed to Create the Object
+ * -EPERM: General Failure
+ * Requires:
+ * MGR Initialized (refs > 0 )
+ * mgr_obj != NULL.
+ * Ensures:
+ * 0: *mgr_obj is a valid MGR interface to the device.
+ * MGR Object stores the DCD Manager Handle.
+ * MGR Object stored in the Regsitry.
+ * !0: MGR Object not created
+ * Details:
+ * DCD Dll is loaded and MGR Object stores the handle of the DLL.
+ */
+extern int mgr_create(struct mgr_object **mgr_obj,
+ struct cfg_devnode *dev_node_obj);
+
+/*
+ * ======== mgr_destroy ========
+ * Purpose:
+ * Destroys the MGR object. Called upon driver unloading.
+ * Parameters:
+ * hmgr_obj: Handle to Manager object .
+ * Returns:
+ * 0: Success.
+ * DCD Manager freed; MGR Object destroyed;
+ * MGR Object deleted from the Registry.
+ * -EPERM: Failed to destroy MGR Object
+ * Requires:
+ * MGR Initialized (refs > 0 )
+ * hmgr_obj is a valid MGR handle .
+ * Ensures:
+ * 0: MGR Object destroyed and hmgr_obj is Invalid MGR
+ * Handle.
+ */
+extern int mgr_destroy(struct mgr_object *hmgr_obj);
+
+/*
+ * ======== mgr_enum_node_info ========
+ * Purpose:
+ * Enumerate and get configuration information about nodes configured
+ * in the node database.
+ * Parameters:
+ * node_id: The node index (base 0).
+ * pndb_props: Ptr to the dsp_ndbprops structure for output.
+ * undb_props_size: Size of the dsp_ndbprops structure.
+ * pu_num_nodes: Location where the number of nodes configured
+ * in the database will be returned.
+ * Returns:
+ * 0: Success.
+ * -EINVAL: Parameter node_id is > than the number of nodes.
+ * configutred in the system
+ * -EIDRM: During Enumeration there has been a change in
+ * the number of nodes configured or in the
+ * the properties of the enumerated nodes.
+ * -EPERM: Failed to querry the Node Data Base
+ * Requires:
+ * pNDBPROPS is not null
+ * undb_props_size >= sizeof(dsp_ndbprops)
+ * pu_num_nodes is not null
+ * MGR Initialized (refs > 0 )
+ * Ensures:
+ * SUCCESS on successful retreival of data and *pu_num_nodes > 0 OR
+ * DSP_FAILED && *pu_num_nodes == 0.
+ * Details:
+ */
+extern int mgr_enum_node_info(u32 node_id,
+ struct dsp_ndbprops *pndb_props,
+ u32 undb_props_size,
+ u32 *pu_num_nodes);
+
+/*
+ * ======== mgr_enum_processor_info ========
+ * Purpose:
+ * Enumerate and get configuration information about available DSP
+ * processors
+ * Parameters:
+ * processor_id: The processor index (zero-based).
+ * processor_info: Ptr to the dsp_processorinfo structure .
+ * processor_info_size: Size of dsp_processorinfo structure.
+ * pu_num_procs: Location where the number of DSPs configured
+ * in the database will be returned
+ * Returns:
+ * 0: Success.
+ * -EINVAL: Parameter processor_id is > than the number of
+ * DSP Processors in the system.
+ * -EPERM: Failed to querry the Node Data Base
+ * Requires:
+ * processor_info is not null
+ * pu_num_procs is not null
+ * processor_info_size >= sizeof(dsp_processorinfo)
+ * MGR Initialized (refs > 0 )
+ * Ensures:
+ * SUCCESS on successful retreival of data and *pu_num_procs > 0 OR
+ * DSP_FAILED && *pu_num_procs == 0.
+ * Details:
+ */
+extern int mgr_enum_processor_info(u32 processor_id,
+ struct dsp_processorinfo
+ *processor_info,
+ u32 processor_info_size,
+ u8 *pu_num_procs);
+/*
+ * ======== mgr_exit ========
+ * Purpose:
+ * Decrement reference count, and free resources when reference count is
+ * 0.
+ * Parameters:
+ * Returns:
+ * Requires:
+ * MGR is initialized.
+ * Ensures:
+ * When reference count == 0, MGR's private resources are freed.
+ */
+extern void mgr_exit(void);
+
+/*
+ * ======== mgr_get_dcd_handle ========
+ * Purpose:
+ * Retrieves the MGR handle. Accessor Function
+ * Parameters:
+ * mgr_handle: Handle to the Manager Object
+ * dcd_handle: Ptr to receive the DCD Handle.
+ * Returns:
+ * 0: Sucess
+ * -EPERM: Failure to get the Handle
+ * Requires:
+ * MGR is initialized.
+ * dcd_handle != NULL
+ * Ensures:
+ * 0 and *dcd_handle != NULL ||
+ * -EPERM and *dcd_handle == NULL
+ */
+extern int mgr_get_dcd_handle(struct mgr_object
+ *mgr_handle, u32 *dcd_handle);
+
+/*
+ * ======== mgr_init ========
+ * Purpose:
+ * Initialize MGR's private state, keeping a reference count on each
+ * call. Intializes the DCD.
+ * Parameters:
+ * Returns:
+ * TRUE if initialized; FALSE if error occured.
+ * Requires:
+ * Ensures:
+ * TRUE: A requirement for the other public MGR functions.
+ */
+extern bool mgr_init(void);
+
+#endif /* MGR_ */
diff --git a/drivers/staging/tidspbridge/include/dspbridge/mgrpriv.h b/drivers/staging/tidspbridge/include/dspbridge/mgrpriv.h
new file mode 100644
index 00000000000..bca4e103c7f
--- /dev/null
+++ b/drivers/staging/tidspbridge/include/dspbridge/mgrpriv.h
@@ -0,0 +1,45 @@
+/*
+ * mgrpriv.h
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * Global MGR constants and types, shared by PROC, MGR, and DSP API.
+ *
+ * Copyright (C) 2008 Texas Instruments, Inc.
+ *
+ * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef MGRPRIV_
+#define MGRPRIV_
+
+/*
+ * OMAP1510 specific
+ */
+#define MGR_MAXTLBENTRIES 32
+
+/* RM MGR Object */
+struct mgr_object;
+
+struct mgr_tlbentry {
+ u32 ul_dsp_virt; /* DSP virtual address */
+ u32 ul_gpp_phys; /* GPP physical address */
+};
+
+/*
+ * The DSP_PROCESSOREXTINFO structure describes additional extended
+ * capabilities of a DSP processor not exposed to user.
+ */
+struct mgr_processorextinfo {
+ struct dsp_processorinfo ty_basic; /* user processor info */
+ /* private dsp mmu entries */
+ struct mgr_tlbentry ty_tlb[MGR_MAXTLBENTRIES];
+};
+
+#endif /* MGRPRIV_ */
diff --git a/drivers/staging/tidspbridge/include/dspbridge/msg.h b/drivers/staging/tidspbridge/include/dspbridge/msg.h
new file mode 100644
index 00000000000..95778bcb5aa
--- /dev/null
+++ b/drivers/staging/tidspbridge/include/dspbridge/msg.h
@@ -0,0 +1,86 @@
+/*
+ * msg.h
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * DSP/BIOS Bridge msg_ctrl Module.
+ *
+ * Copyright (C) 2005-2006 Texas Instruments, Inc.
+ *
+ * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef MSG_
+#define MSG_
+
+#include <dspbridge/devdefs.h>
+#include <dspbridge/msgdefs.h>
+
+/*
+ * ======== msg_create ========
+ * Purpose:
+ * Create an object to manage message queues. Only one of these objects
+ * can exist per device object. The msg_ctrl manager must be created before
+ * the IO Manager.
+ * Parameters:
+ * msg_man: Location to store msg_ctrl manager handle on output.
+ * hdev_obj: The device object.
+ * msg_callback: Called whenever an RMS_EXIT message is received.
+ * Returns:
+ * Requires:
+ * msg_mod_init(void) called.
+ * msg_man != NULL.
+ * hdev_obj != NULL.
+ * msg_callback != NULL.
+ * Ensures:
+ */
+extern int msg_create(struct msg_mgr **msg_man,
+ struct dev_object *hdev_obj,
+ msg_onexit msg_callback);
+
+/*
+ * ======== msg_delete ========
+ * Purpose:
+ * Delete a msg_ctrl manager allocated in msg_create().
+ * Parameters:
+ * hmsg_mgr: Handle returned from msg_create().
+ * Returns:
+ * Requires:
+ * msg_mod_init(void) called.
+ * Valid hmsg_mgr.
+ * Ensures:
+ */
+extern void msg_delete(struct msg_mgr *hmsg_mgr);
+
+/*
+ * ======== msg_exit ========
+ * Purpose:
+ * Discontinue usage of msg_ctrl module.
+ * Parameters:
+ * Returns:
+ * Requires:
+ * msg_mod_init(void) successfully called before.
+ * Ensures:
+ * Any resources acquired in msg_mod_init(void) will be freed when last
+ * msg_ctrl client calls msg_exit(void).
+ */
+extern void msg_exit(void);
+
+/*
+ * ======== msg_mod_init ========
+ * Purpose:
+ * Initialize the msg_ctrl module.
+ * Parameters:
+ * Returns:
+ * TRUE if initialization succeeded, FALSE otherwise.
+ * Ensures:
+ */
+extern bool msg_mod_init(void);
+
+#endif /* MSG_ */
diff --git a/drivers/staging/tidspbridge/include/dspbridge/msgdefs.h b/drivers/staging/tidspbridge/include/dspbridge/msgdefs.h
new file mode 100644
index 00000000000..80a3fa1a8a3
--- /dev/null
+++ b/drivers/staging/tidspbridge/include/dspbridge/msgdefs.h
@@ -0,0 +1,29 @@
+/*
+ * msgdefs.h
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * Global msg_ctrl constants and types.
+ *
+ * Copyright (C) 2005-2006 Texas Instruments, Inc.
+ *
+ * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef MSGDEFS_
+#define MSGDEFS_
+
+/* msg_ctrl Objects: */
+struct msg_mgr;
+struct msg_queue;
+
+/* Function prototype for callback to be called on RMS_EXIT message received */
+typedef void (*msg_onexit) (void *h, s32 node_status);
+
+#endif /* MSGDEFS_ */
diff --git a/drivers/staging/tidspbridge/include/dspbridge/nldr.h b/drivers/staging/tidspbridge/include/dspbridge/nldr.h
new file mode 100644
index 00000000000..d9653ee667e
--- /dev/null
+++ b/drivers/staging/tidspbridge/include/dspbridge/nldr.h
@@ -0,0 +1,57 @@
+/*
+ * nldr.h
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * DSP/BIOS Bridge dynamic loader interface.
+ *
+ * Copyright (C) 2005-2006 Texas Instruments, Inc.
+ *
+ * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include <dspbridge/dbdefs.h>
+#include <dspbridge/dbdcddef.h>
+#include <dspbridge/dev.h>
+#include <dspbridge/rmm.h>
+#include <dspbridge/nldrdefs.h>
+
+#ifndef NLDR_
+#define NLDR_
+
+extern int nldr_allocate(struct nldr_object *nldr_obj,
+ void *priv_ref, const struct dcd_nodeprops
+ *node_props,
+ struct nldr_nodeobject **nldr_nodeobj,
+ bool *pf_phase_split);
+
+extern int nldr_create(struct nldr_object **nldr,
+ struct dev_object *hdev_obj,
+ const struct nldr_attrs *pattrs);
+
+extern void nldr_delete(struct nldr_object *nldr_obj);
+extern void nldr_exit(void);
+
+extern int nldr_get_fxn_addr(struct nldr_nodeobject *nldr_node_obj,
+ char *str_fxn, u32 * addr);
+
+extern int nldr_get_rmm_manager(struct nldr_object *nldr,
+ struct rmm_target_obj **rmm_mgr);
+
+extern bool nldr_init(void);
+extern int nldr_load(struct nldr_nodeobject *nldr_node_obj,
+ enum nldr_phase phase);
+extern int nldr_unload(struct nldr_nodeobject *nldr_node_obj,
+ enum nldr_phase phase);
+#ifdef CONFIG_TIDSPBRIDGE_BACKTRACE
+int nldr_find_addr(struct nldr_nodeobject *nldr_node, u32 sym_addr,
+ u32 offset_range, void *offset_output, char *sym_name);
+#endif
+
+#endif /* NLDR_ */
diff --git a/drivers/staging/tidspbridge/include/dspbridge/nldrdefs.h b/drivers/staging/tidspbridge/include/dspbridge/nldrdefs.h
new file mode 100644
index 00000000000..c85d3da3fe2
--- /dev/null
+++ b/drivers/staging/tidspbridge/include/dspbridge/nldrdefs.h
@@ -0,0 +1,293 @@
+/*
+ * nldrdefs.h
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * Global Dynamic + static/overlay Node loader (NLDR) constants and types.
+ *
+ * Copyright (C) 2008 Texas Instruments, Inc.
+ *
+ * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef NLDRDEFS_
+#define NLDRDEFS_
+
+#include <dspbridge/dbdcddef.h>
+#include <dspbridge/devdefs.h>
+
+#define NLDR_MAXPATHLENGTH 255
+/* NLDR Objects: */
+struct nldr_object;
+struct nldr_nodeobject;
+
+/*
+ * ======== nldr_loadtype ========
+ * Load types for a node. Must match values in node.h55.
+ */
+enum nldr_loadtype {
+ NLDR_STATICLOAD, /* Linked in base image, not overlay */
+ NLDR_DYNAMICLOAD, /* Dynamically loaded node */
+ NLDR_OVLYLOAD /* Linked in base image, overlay node */
+};
+
+/*
+ * ======== nldr_ovlyfxn ========
+ * Causes code or data to be copied from load address to run address. This
+ * is the "cod_writefxn" that gets passed to the DBLL_Library and is used as
+ * the ZL write function.
+ *
+ * Parameters:
+ * priv_ref: Handle to identify the node.
+ * dsp_run_addr: Run address of code or data.
+ * dsp_load_addr: Load address of code or data.
+ * ul_num_bytes: Number of (GPP) bytes to copy.
+ * mem_space: RMS_CODE or RMS_DATA.
+ * Returns:
+ * ul_num_bytes: Success.
+ * 0: Failure.
+ * Requires:
+ * Ensures:
+ */
+typedef u32(*nldr_ovlyfxn) (void *priv_ref, u32 dsp_run_addr,
+ u32 dsp_load_addr, u32 ul_num_bytes, u32 mem_space);
+
+/*
+ * ======== nldr_writefxn ========
+ * Write memory function. Used for dynamic load writes.
+ * Parameters:
+ * priv_ref: Handle to identify the node.
+ * dsp_add: Address of code or data.
+ * pbuf: Code or data to be written
+ * ul_num_bytes: Number of (GPP) bytes to write.
+ * mem_space: DBLL_DATA or DBLL_CODE.
+ * Returns:
+ * ul_num_bytes: Success.
+ * 0: Failure.
+ * Requires:
+ * Ensures:
+ */
+typedef u32(*nldr_writefxn) (void *priv_ref,
+ u32 dsp_add, void *pbuf,
+ u32 ul_num_bytes, u32 mem_space);
+
+/*
+ * ======== nldr_attrs ========
+ * Attributes passed to nldr_create function.
+ */
+struct nldr_attrs {
+ nldr_ovlyfxn pfn_ovly;
+ nldr_writefxn pfn_write;
+ u16 us_dsp_word_size;
+ u16 us_dsp_mau_size;
+};
+
+/*
+ * ======== nldr_phase ========
+ * Indicates node create, delete, or execute phase function.
+ */
+enum nldr_phase {
+ NLDR_CREATE,
+ NLDR_DELETE,
+ NLDR_EXECUTE,
+ NLDR_NOPHASE
+};
+
+/*
+ * Typedefs of loader functions imported from a DLL, or defined in a
+ * function table.
+ */
+
+/*
+ * ======== nldr_allocate ========
+ * Allocate resources to manage the loading of a node on the DSP.
+ *
+ * Parameters:
+ * nldr_obj: Handle of loader that will load the node.
+ * priv_ref: Handle to identify the node.
+ * node_props: Pointer to a dcd_nodeprops for the node.
+ * nldr_nodeobj: Location to store node handle on output. This handle
+ * will be passed to nldr_load/nldr_unload.
+ * pf_phase_split: pointer to int variable referenced in node.c
+ * Returns:
+ * 0: Success.
+ * -ENOMEM: Insufficient memory on GPP.
+ * Requires:
+ * nldr_init(void) called.
+ * Valid nldr_obj.
+ * node_props != NULL.
+ * nldr_nodeobj != NULL.
+ * Ensures:
+ * 0: IsValidNode(*nldr_nodeobj).
+ * error: *nldr_nodeobj == NULL.
+ */
+typedef int(*nldr_allocatefxn) (struct nldr_object *nldr_obj,
+ void *priv_ref,
+ const struct dcd_nodeprops
+ * node_props,
+ struct nldr_nodeobject
+ **nldr_nodeobj,
+ bool *pf_phase_split);
+
+/*
+ * ======== nldr_create ========
+ * Create a loader object. This object handles the loading and unloading of
+ * create, delete, and execute phase functions of nodes on the DSP target.
+ *
+ * Parameters:
+ * nldr: Location to store loader handle on output.
+ * hdev_obj: Device for this processor.
+ * pattrs: Loader attributes.
+ * Returns:
+ * 0: Success;
+ * -ENOMEM: Insufficient memory for requested resources.
+ * Requires:
+ * nldr_init(void) called.
+ * nldr != NULL.
+ * hdev_obj != NULL.
+ * pattrs != NULL.
+ * Ensures:
+ * 0: Valid *nldr.
+ * error: *nldr == NULL.
+ */
+typedef int(*nldr_createfxn) (struct nldr_object **nldr,
+ struct dev_object *hdev_obj,
+ const struct nldr_attrs *pattrs);
+
+/*
+ * ======== nldr_delete ========
+ * Delete the NLDR loader.
+ *
+ * Parameters:
+ * nldr_obj: Node manager object.
+ * Returns:
+ * Requires:
+ * nldr_init(void) called.
+ * Valid nldr_obj.
+ * Ensures:
+ * nldr_obj invalid
+ */
+typedef void (*nldr_deletefxn) (struct nldr_object *nldr_obj);
+
+/*
+ * ======== nldr_exit ========
+ * Discontinue usage of NLDR module.
+ *
+ * Parameters:
+ * Returns:
+ * Requires:
+ * nldr_init(void) successfully called before.
+ * Ensures:
+ * Any resources acquired in nldr_init(void) will be freed when last NLDR
+ * client calls nldr_exit(void).
+ */
+typedef void (*nldr_exitfxn) (void);
+
+/*
+ * ======== NLDR_Free ========
+ * Free resources allocated in nldr_allocate.
+ *
+ * Parameters:
+ * nldr_node_obj: Handle returned from nldr_allocate().
+ * Returns:
+ * Requires:
+ * nldr_init(void) called.
+ * Valid nldr_node_obj.
+ * Ensures:
+ */
+typedef void (*nldr_freefxn) (struct nldr_nodeobject *nldr_node_obj);
+
+/*
+ * ======== nldr_get_fxn_addr ========
+ * Get address of create, delete, or execute phase function of a node on
+ * the DSP.
+ *
+ * Parameters:
+ * nldr_node_obj: Handle returned from nldr_allocate().
+ * str_fxn: Name of function.
+ * addr: Location to store function address.
+ * Returns:
+ * 0: Success.
+ * -ESPIPE: Address of function not found.
+ * Requires:
+ * nldr_init(void) called.
+ * Valid nldr_node_obj.
+ * addr != NULL;
+ * str_fxn != NULL;
+ * Ensures:
+ */
+typedef int(*nldr_getfxnaddrfxn) (struct nldr_nodeobject
+ * nldr_node_obj,
+ char *str_fxn, u32 * addr);
+
+/*
+ * ======== nldr_init ========
+ * Initialize the NLDR module.
+ *
+ * Parameters:
+ * Returns:
+ * TRUE if initialization succeeded, FALSE otherwise.
+ * Ensures:
+ */
+typedef bool(*nldr_initfxn) (void);
+
+/*
+ * ======== nldr_load ========
+ * Load create, delete, or execute phase function of a node on the DSP.
+ *
+ * Parameters:
+ * nldr_node_obj: Handle returned from nldr_allocate().
+ * phase: Type of function to load (create, delete, or execute).
+ * Returns:
+ * 0: Success.
+ * -ENOMEM: Insufficient memory on GPP.
+ * -ENXIO: Can't overlay phase because overlay memory
+ * is already in use.
+ * -EILSEQ: Failure in dynamic loader library.
+ * Requires:
+ * nldr_init(void) called.
+ * Valid nldr_node_obj.
+ * Ensures:
+ */
+typedef int(*nldr_loadfxn) (struct nldr_nodeobject *nldr_node_obj,
+ enum nldr_phase phase);
+
+/*
+ * ======== nldr_unload ========
+ * Unload create, delete, or execute phase function of a node on the DSP.
+ *
+ * Parameters:
+ * nldr_node_obj: Handle returned from nldr_allocate().
+ * phase: Node function to unload (create, delete, or execute).
+ * Returns:
+ * 0: Success.
+ * -ENOMEM: Insufficient memory on GPP.
+ * Requires:
+ * nldr_init(void) called.
+ * Valid nldr_node_obj.
+ * Ensures:
+ */
+typedef int(*nldr_unloadfxn) (struct nldr_nodeobject *nldr_node_obj,
+ enum nldr_phase phase);
+
+/*
+ * ======== node_ldr_fxns ========
+ */
+struct node_ldr_fxns {
+ nldr_allocatefxn pfn_allocate;
+ nldr_createfxn pfn_create;
+ nldr_deletefxn pfn_delete;
+ nldr_exitfxn pfn_exit;
+ nldr_getfxnaddrfxn pfn_get_fxn_addr;
+ nldr_initfxn pfn_init;
+ nldr_loadfxn pfn_load;
+ nldr_unloadfxn pfn_unload;
+};
+
+#endif /* NLDRDEFS_ */
diff --git a/drivers/staging/tidspbridge/include/dspbridge/node.h b/drivers/staging/tidspbridge/include/dspbridge/node.h
new file mode 100644
index 00000000000..49ed5c1128e
--- /dev/null
+++ b/drivers/staging/tidspbridge/include/dspbridge/node.h
@@ -0,0 +1,583 @@
+/*
+ * node.h
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * DSP/BIOS Bridge Node Manager.
+ *
+ * Copyright (C) 2005-2006 Texas Instruments, Inc.
+ *
+ * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef NODE_
+#define NODE_
+
+#include <dspbridge/procpriv.h>
+
+#include <dspbridge/nodedefs.h>
+#include <dspbridge/dispdefs.h>
+#include <dspbridge/nldrdefs.h>
+#include <dspbridge/drv.h>
+
+/*
+ * ======== node_allocate ========
+ * Purpose:
+ * Allocate GPP resources to manage a node on the DSP.
+ * Parameters:
+ * hprocessor: Handle of processor that is allocating the node.
+ * node_uuid: Pointer to a dsp_uuid for the node.
+ * pargs: Optional arguments to be passed to the node.
+ * attr_in: Optional pointer to node attributes (priority,
+ * timeout...)
+ * noderes: Location to store node resource info.
+ * Returns:
+ * 0: Success.
+ * -ENOMEM: Insufficient memory on GPP.
+ * -ENOKEY: Node UUID has not been registered.
+ * -ESPIPE: iAlg functions not found for a DAIS node.
+ * -EDOM: attr_in != NULL and attr_in->prio out of
+ * range.
+ * -EPERM: A failure occured, unable to allocate node.
+ * -EBADR: Proccessor is not in the running state.
+ * Requires:
+ * node_init(void) called.
+ * hprocessor != NULL.
+ * node_uuid != NULL.
+ * noderes != NULL.
+ * Ensures:
+ * 0: IsValidNode(*ph_node).
+ * error: *noderes == NULL.
+ */
+extern int node_allocate(struct proc_object *hprocessor,
+ const struct dsp_uuid *node_uuid,
+ const struct dsp_cbdata
+ *pargs, const struct dsp_nodeattrin
+ *attr_in,
+ struct node_res_object **noderes,
+ struct process_context *pr_ctxt);
+
+/*
+ * ======== node_alloc_msg_buf ========
+ * Purpose:
+ * Allocate and Prepare a buffer whose descriptor will be passed to a
+ * Node within a (dsp_msg)message
+ * Parameters:
+ * hnode: The node handle.
+ * usize: The size of the buffer to be allocated.
+ * pattr: Pointer to a dsp_bufferattr structure.
+ * pbuffer: Location to store the address of the allocated
+ * buffer on output.
+ * Returns:
+ * 0: Success.
+ * -EFAULT: Invalid node handle.
+ * -ENOMEM: Insufficent memory.
+ * -EPERM: General Failure.
+ * -EINVAL: Invalid Size.
+ * Requires:
+ * node_init(void) called.
+ * pbuffer != NULL.
+ * Ensures:
+ */
+extern int node_alloc_msg_buf(struct node_object *hnode,
+ u32 usize, struct dsp_bufferattr
+ *pattr, u8 **pbuffer);
+
+/*
+ * ======== node_change_priority ========
+ * Purpose:
+ * Change the priority of an allocated node.
+ * Parameters:
+ * hnode: Node handle returned from node_allocate.
+ * prio: New priority level to set node's priority to.
+ * Returns:
+ * 0: Success.
+ * -EFAULT: Invalid hnode.
+ * -EDOM: prio is out of range.
+ * -EPERM: The specified node is not a task node.
+ * Unable to change node's runtime priority level.
+ * -EBADR: Node is not in the NODE_ALLOCATED, NODE_PAUSED,
+ * or NODE_RUNNING state.
+ * -ETIME: A timeout occurred before the DSP responded.
+ * Requires:
+ * node_init(void) called.
+ * Ensures:
+ * 0 && (Node's current priority == prio)
+ */
+extern int node_change_priority(struct node_object *hnode, s32 prio);
+
+/*
+ * ======== node_close_orphans ========
+ * Purpose:
+ * Delete all nodes whose owning processor is being destroyed.
+ * Parameters:
+ * hnode_mgr: Node manager object.
+ * proc: Handle to processor object being destroyed.
+ * Returns:
+ * 0: Success.
+ * -EPERM: Unable to delete all nodes belonging to proc.
+ * Requires:
+ * Valid hnode_mgr.
+ * proc != NULL.
+ * Ensures:
+ */
+extern int node_close_orphans(struct node_mgr *hnode_mgr,
+ struct proc_object *proc);
+
+/*
+ * ======== node_connect ========
+ * Purpose:
+ * Connect two nodes on the DSP, or a node on the DSP to the GPP. In the
+ * case that the connnection is being made between a node on the DSP and
+ * the GPP, one of the node handles (either node1 or node2) must be
+ * the constant NODE_HGPPNODE.
+ * Parameters:
+ * node1: Handle of first node to connect to second node. If
+ * this is a connection from the GPP to node2, node1
+ * must be the constant NODE_HGPPNODE. Otherwise, node1
+ * must be a node handle returned from a successful call
+ * to Node_Allocate().
+ * node2: Handle of second node. Must be either NODE_HGPPNODE
+ * if this is a connection from DSP node to GPP, or a
+ * node handle returned from a successful call to
+ * node_allocate().
+ * stream1: Output stream index on first node, to be connected
+ * to second node's input stream. Value must range from
+ * 0 <= stream1 < number of output streams.
+ * stream2: Input stream index on second node. Value must range
+ * from 0 <= stream2 < number of input streams.
+ * pattrs: Stream attributes (NULL ==> use defaults).
+ * conn_param: A pointer to a dsp_cbdata structure that defines
+ * connection parameter for device nodes to pass to DSP
+ * side.
+ * If the value of this parameter is NULL, then this API
+ * behaves like DSPNode_Connect. This parameter will have
+ * length of the string and the null terminated string in
+ * dsp_cbdata struct. This can be extended in future tp
+ * pass binary data.
+ * Returns:
+ * 0: Success.
+ * -EFAULT: Invalid node1 or node2.
+ * -ENOMEM: Insufficient host memory.
+ * -EINVAL: A stream index parameter is invalid.
+ * -EISCONN: A connection already exists for one of the
+ * indices stream1 or stream2.
+ * -EBADR: Either node1 or node2 is not in the
+ * NODE_ALLOCATED state.
+ * -ECONNREFUSED: No more connections available.
+ * -EPERM: Attempt to make an illegal connection (eg,
+ * Device node to device node, or device node to
+ * GPP), the two nodes are on different DSPs.
+ * Requires:
+ * node_init(void) called.
+ * Ensures:
+ */
+extern int node_connect(struct node_object *node1,
+ u32 stream1,
+ struct node_object *node2,
+ u32 stream2,
+ struct dsp_strmattr *pattrs,
+ struct dsp_cbdata
+ *conn_param);
+
+/*
+ * ======== node_create ========
+ * Purpose:
+ * Create a node on the DSP by remotely calling the node's create
+ * function. If necessary, load code that contains the node's create
+ * function.
+ * Parameters:
+ * hnode: Node handle returned from node_allocate().
+ * Returns:
+ * 0: Success.
+ * -EFAULT: Invalid hnode.
+ * -ESPIPE: Create function not found in the COFF file.
+ * -EBADR: Node is not in the NODE_ALLOCATED state.
+ * -ENOMEM: Memory allocation failure on the DSP.
+ * -ETIME: A timeout occurred before the DSP responded.
+ * -EPERM: A failure occurred, unable to create node.
+ * Requires:
+ * node_init(void) called.
+ * Ensures:
+ */
+extern int node_create(struct node_object *hnode);
+
+/*
+ * ======== node_create_mgr ========
+ * Purpose:
+ * Create a NODE Manager object. This object handles the creation,
+ * deletion, and execution of nodes on the DSP target. The NODE Manager
+ * also maintains a pipe map of used and available node connections.
+ * Each DEV object should have exactly one NODE Manager object.
+ *
+ * Parameters:
+ * node_man: Location to store node manager handle on output.
+ * hdev_obj: Device for this processor.
+ * Returns:
+ * 0: Success;
+ * -ENOMEM: Insufficient memory for requested resources.
+ * -EPERM: General failure.
+ * Requires:
+ * node_init(void) called.
+ * node_man != NULL.
+ * hdev_obj != NULL.
+ * Ensures:
+ * 0: Valide *node_man.
+ * error: *node_man == NULL.
+ */
+extern int node_create_mgr(struct node_mgr **node_man,
+ struct dev_object *hdev_obj);
+
+/*
+ * ======== node_delete ========
+ * Purpose:
+ * Delete resources allocated in node_allocate(). If the node was
+ * created, delete the node on the DSP by remotely calling the node's
+ * delete function. Loads the node's delete function if necessary.
+ * GPP side resources are freed after node's delete function returns.
+ * Parameters:
+ * noderes: Node resource info handle returned from
+ * node_allocate().
+ * pr_ctxt: Poninter to process context data.
+ * Returns:
+ * 0: Success.
+ * -EFAULT: Invalid hnode.
+ * -ETIME: A timeout occurred before the DSP responded.
+ * -EPERM: A failure occurred in deleting the node.
+ * -ESPIPE: Delete function not found in the COFF file.
+ * Requires:
+ * node_init(void) called.
+ * Ensures:
+ * 0: hnode is invalid.
+ */
+extern int node_delete(struct node_res_object *noderes,
+ struct process_context *pr_ctxt);
+
+/*
+ * ======== node_delete_mgr ========
+ * Purpose:
+ * Delete the NODE Manager.
+ * Parameters:
+ * hnode_mgr: Node manager object.
+ * Returns:
+ * 0: Success.
+ * Requires:
+ * node_init(void) called.
+ * Valid hnode_mgr.
+ * Ensures:
+ */
+extern int node_delete_mgr(struct node_mgr *hnode_mgr);
+
+/*
+ * ======== node_enum_nodes ========
+ * Purpose:
+ * Enumerate the nodes currently allocated for the DSP.
+ * Parameters:
+ * hnode_mgr: Node manager returned from node_create_mgr().
+ * node_tab: Array to copy node handles into.
+ * node_tab_size: Number of handles that can be written to node_tab.
+ * pu_num_nodes: Location where number of node handles written to
+ * node_tab will be written.
+ * pu_allocated: Location to write total number of allocated nodes.
+ * Returns:
+ * 0: Success.
+ * -EINVAL: node_tab is too small to hold all node handles.
+ * Requires:
+ * Valid hnode_mgr.
+ * node_tab != NULL || node_tab_size == 0.
+ * pu_num_nodes != NULL.
+ * pu_allocated != NULL.
+ * Ensures:
+ * - (-EINVAL && *pu_num_nodes == 0)
+ * - || (0 && *pu_num_nodes <= node_tab_size) &&
+ * (*pu_allocated == *pu_num_nodes)
+ */
+extern int node_enum_nodes(struct node_mgr *hnode_mgr,
+ void **node_tab,
+ u32 node_tab_size,
+ u32 *pu_num_nodes,
+ u32 *pu_allocated);
+
+/*
+ * ======== node_exit ========
+ * Purpose:
+ * Discontinue usage of NODE module.
+ * Parameters:
+ * Returns:
+ * Requires:
+ * node_init(void) successfully called before.
+ * Ensures:
+ * Any resources acquired in node_init(void) will be freed when last NODE
+ * client calls node_exit(void).
+ */
+extern void node_exit(void);
+
+/*
+ * ======== node_free_msg_buf ========
+ * Purpose:
+ * Free a message buffer previously allocated with node_alloc_msg_buf.
+ * Parameters:
+ * hnode: The node handle.
+ * pbuffer: (Address) Buffer allocated by node_alloc_msg_buf.
+ * pattr: Same buffer attributes passed to node_alloc_msg_buf.
+ * Returns:
+ * 0: Success.
+ * -EFAULT: Invalid node handle.
+ * -EPERM: Failure to free the buffer.
+ * Requires:
+ * node_init(void) called.
+ * pbuffer != NULL.
+ * Ensures:
+ */
+extern int node_free_msg_buf(struct node_object *hnode,
+ u8 *pbuffer,
+ struct dsp_bufferattr
+ *pattr);
+
+/*
+ * ======== node_get_attr ========
+ * Purpose:
+ * Copy the current attributes of the specified node into a dsp_nodeattr
+ * structure.
+ * Parameters:
+ * hnode: Node object allocated from node_allocate().
+ * pattr: Pointer to dsp_nodeattr structure to copy node's
+ * attributes.
+ * attr_size: Size of pattr.
+ * Returns:
+ * 0: Success.
+ * -EFAULT: Invalid hnode.
+ * Requires:
+ * node_init(void) called.
+ * pattr != NULL.
+ * Ensures:
+ * 0: *pattrs contains the node's current attributes.
+ */
+extern int node_get_attr(struct node_object *hnode,
+ struct dsp_nodeattr *pattr, u32 attr_size);
+
+/*
+ * ======== node_get_message ========
+ * Purpose:
+ * Retrieve a message from a node on the DSP. The node must be either a
+ * message node, task node, or XDAIS socket node.
+ * If a message is not available, this function will block until a
+ * message is available, or the node's timeout value is reached.
+ * Parameters:
+ * hnode: Node handle returned from node_allocate().
+ * message: Pointer to dsp_msg structure to copy the
+ * message into.
+ * utimeout: Timeout in milliseconds to wait for message.
+ * Returns:
+ * 0: Success.
+ * -EFAULT: Invalid hnode.
+ * -EPERM: Cannot retrieve messages from this type of node.
+ * Error occurred while trying to retrieve a message.
+ * -ETIME: Timeout occurred and no message is available.
+ * Requires:
+ * node_init(void) called.
+ * message != NULL.
+ * Ensures:
+ */
+extern int node_get_message(struct node_object *hnode,
+ struct dsp_msg *message, u32 utimeout);
+
+/*
+ * ======== node_get_nldr_obj ========
+ * Purpose:
+ * Retrieve the Nldr manager
+ * Parameters:
+ * hnode_mgr: Node Manager
+ * nldr_ovlyobj: Pointer to a Nldr manager handle
+ * Returns:
+ * 0: Success.
+ * -EFAULT: Invalid hnode.
+ * Ensures:
+ */
+extern int node_get_nldr_obj(struct node_mgr *hnode_mgr,
+ struct nldr_object **nldr_ovlyobj);
+
+/*
+ * ======== node_init ========
+ * Purpose:
+ * Initialize the NODE module.
+ * Parameters:
+ * Returns:
+ * TRUE if initialization succeeded, FALSE otherwise.
+ * Ensures:
+ */
+extern bool node_init(void);
+
+/*
+ * ======== node_on_exit ========
+ * Purpose:
+ * Gets called when RMS_EXIT is received for a node. PROC needs to pass
+ * this function as a parameter to msg_create(). This function then gets
+ * called by the Bridge driver when an exit message for a node is received.
+ * Parameters:
+ * hnode: Handle of the node that the exit message is for.
+ * node_status: Return status of the node's execute phase.
+ * Returns:
+ * Ensures:
+ */
+void node_on_exit(struct node_object *hnode, s32 node_status);
+
+/*
+ * ======== node_pause ========
+ * Purpose:
+ * Suspend execution of a node currently running on the DSP.
+ * Parameters:
+ * hnode: Node object representing a node currently
+ * running on the DSP.
+ * Returns:
+ * 0: Success.
+ * -EFAULT: Invalid hnode.
+ * -EPERM: Node is not a task or socket node.
+ * Failed to pause node.
+ * -ETIME: A timeout occurred before the DSP responded.
+ * DSP_EWRONGSTSATE: Node is not in NODE_RUNNING state.
+ * Requires:
+ * node_init(void) called.
+ * Ensures:
+ */
+extern int node_pause(struct node_object *hnode);
+
+/*
+ * ======== node_put_message ========
+ * Purpose:
+ * Send a message to a message node, task node, or XDAIS socket node.
+ * This function will block until the message stream can accommodate
+ * the message, or a timeout occurs. The message will be copied, so Msg
+ * can be re-used immediately after return.
+ * Parameters:
+ * hnode: Node handle returned by node_allocate().
+ * pmsg: Location of message to be sent to the node.
+ * utimeout: Timeout in msecs to wait.
+ * Returns:
+ * 0: Success.
+ * -EFAULT: Invalid hnode.
+ * -EPERM: Messages can't be sent to this type of node.
+ * Unable to send message.
+ * -ETIME: Timeout occurred before message could be set.
+ * -EBADR: Node is in invalid state for sending messages.
+ * Requires:
+ * node_init(void) called.
+ * pmsg != NULL.
+ * Ensures:
+ */
+extern int node_put_message(struct node_object *hnode,
+ const struct dsp_msg *pmsg, u32 utimeout);
+
+/*
+ * ======== node_register_notify ========
+ * Purpose:
+ * Register to be notified on specific events for this node.
+ * Parameters:
+ * hnode: Node handle returned by node_allocate().
+ * event_mask: Mask of types of events to be notified about.
+ * notify_type: Type of notification to be sent.
+ * hnotification: Handle to be used for notification.
+ * Returns:
+ * 0: Success.
+ * -EFAULT: Invalid hnode.
+ * -ENOMEM: Insufficient memory on GPP.
+ * -EINVAL: event_mask is invalid.
+ * -ENOSYS: Notification type specified by notify_type is not
+ * supported.
+ * Requires:
+ * node_init(void) called.
+ * hnotification != NULL.
+ * Ensures:
+ */
+extern int node_register_notify(struct node_object *hnode,
+ u32 event_mask, u32 notify_type,
+ struct dsp_notification
+ *hnotification);
+
+/*
+ * ======== node_run ========
+ * Purpose:
+ * Start execution of a node's execute phase, or resume execution of
+ * a node that has been suspended (via node_pause()) on the DSP. Load
+ * the node's execute function if necessary.
+ * Parameters:
+ * hnode: Node object representing a node currently
+ * running on the DSP.
+ * Returns:
+ * 0: Success.
+ * -EFAULT: Invalid hnode.
+ * -EPERM: hnode doesn't represent a message, task or dais socket node.
+ * Unable to start or resume execution.
+ * -ETIME: A timeout occurred before the DSP responded.
+ * DSP_EWRONGSTSATE: Node is not in NODE_PAUSED or NODE_CREATED state.
+ * -ESPIPE: Execute function not found in the COFF file.
+ * Requires:
+ * node_init(void) called.
+ * Ensures:
+ */
+extern int node_run(struct node_object *hnode);
+
+/*
+ * ======== node_terminate ========
+ * Purpose:
+ * Signal a node running on the DSP that it should exit its execute
+ * phase function.
+ * Parameters:
+ * hnode: Node object representing a node currently
+ * running on the DSP.
+ * pstatus: Location to store execute-phase function return
+ * value.
+ * Returns:
+ * 0: Success.
+ * -EFAULT: Invalid hnode.
+ * -ETIME: A timeout occurred before the DSP responded.
+ * -EPERM: Type of node specified cannot be terminated.
+ * Unable to terminate the node.
+ * -EBADR: Operation not valid for the current node state.
+ * Requires:
+ * node_init(void) called.
+ * pstatus != NULL.
+ * Ensures:
+ */
+extern int node_terminate(struct node_object *hnode,
+ int *pstatus);
+
+/*
+ * ======== node_get_uuid_props ========
+ * Purpose:
+ * Fetch Node properties given the UUID
+ * Parameters:
+ *
+ */
+extern int node_get_uuid_props(void *hprocessor,
+ const struct dsp_uuid *node_uuid,
+ struct dsp_ndbprops
+ *node_props);
+
+#ifdef CONFIG_TIDSPBRIDGE_BACKTRACE
+/**
+ * node_find_addr() - Find the closest symbol to the given address.
+ *
+ * @node_mgr: Node manager handle
+ * @sym_addr: Given address to find the closest symbol
+ * @offset_range: offset range to look fo the closest symbol
+ * @sym_addr_output: Symbol Output address
+ * @sym_name: String with the symbol name of the closest symbol
+ *
+ * This function finds the closest symbol to the address where a MMU
+ * Fault occurred on the DSP side.
+ */
+int node_find_addr(struct node_mgr *node_mgr, u32 sym_addr,
+ u32 offset_range, void *sym_addr_output,
+ char *sym_name);
+
+enum node_state node_get_state(void *hnode);
+#endif
+
+#endif /* NODE_ */
diff --git a/drivers/staging/tidspbridge/include/dspbridge/nodedefs.h b/drivers/staging/tidspbridge/include/dspbridge/nodedefs.h
new file mode 100644
index 00000000000..fb9623d8a79
--- /dev/null
+++ b/drivers/staging/tidspbridge/include/dspbridge/nodedefs.h
@@ -0,0 +1,28 @@
+/*
+ * nodedefs.h
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * Global NODE constants and types, shared by PROCESSOR, NODE, and DISP.
+ *
+ * Copyright (C) 2005-2006 Texas Instruments, Inc.
+ *
+ * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef NODEDEFS_
+#define NODEDEFS_
+
+#define NODE_SUSPENDEDPRI -1
+
+/* NODE Objects: */
+struct node_mgr;
+struct node_object;
+
+#endif /* NODEDEFS_ */
diff --git a/drivers/staging/tidspbridge/include/dspbridge/nodepriv.h b/drivers/staging/tidspbridge/include/dspbridge/nodepriv.h
new file mode 100644
index 00000000000..16b0233fc5d
--- /dev/null
+++ b/drivers/staging/tidspbridge/include/dspbridge/nodepriv.h
@@ -0,0 +1,182 @@
+/*
+ * nodepriv.h
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * Private node header shared by NODE and DISP.
+ *
+ * Copyright (C) 2005-2006 Texas Instruments, Inc.
+ *
+ * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef NODEPRIV_
+#define NODEPRIV_
+
+#include <dspbridge/strmdefs.h>
+#include <dspbridge/nodedefs.h>
+#include <dspbridge/nldrdefs.h>
+
+/* DSP address of node environment structure */
+typedef u32 nodeenv;
+
+/*
+ * Node create structures
+ */
+
+/* Message node */
+struct node_msgargs {
+ u32 max_msgs; /* Max # of simultaneous messages for node */
+ u32 seg_id; /* Segment for allocating message buffers */
+ u32 notify_type; /* Notify type (SEM_post, SWI_post, etc.) */
+ u32 arg_length; /* Length in 32-bit words of arg data block */
+ u8 *pdata; /* Argument data for node */
+};
+
+struct node_strmdef {
+ u32 buf_size; /* Size of buffers for SIO stream */
+ u32 num_bufs; /* max # of buffers in SIO stream at once */
+ u32 seg_id; /* Memory segment id to allocate buffers */
+ u32 utimeout; /* Timeout for blocking SIO calls */
+ u32 buf_alignment; /* Buffer alignment */
+ char *sz_device; /* Device name for stream */
+};
+
+/* Task node */
+struct node_taskargs {
+ struct node_msgargs node_msg_args;
+ s32 prio;
+ u32 stack_size;
+ u32 sys_stack_size;
+ u32 stack_seg;
+ u32 udsp_heap_res_addr; /* DSP virtual heap address */
+ u32 udsp_heap_addr; /* DSP virtual heap address */
+ u32 heap_size; /* Heap size */
+ u32 ugpp_heap_addr; /* GPP virtual heap address */
+ u32 profile_id; /* Profile ID */
+ u32 num_inputs;
+ u32 num_outputs;
+ u32 ul_dais_arg; /* Address of iAlg object */
+ struct node_strmdef *strm_in_def;
+ struct node_strmdef *strm_out_def;
+};
+
+/*
+ * ======== node_createargs ========
+ */
+struct node_createargs {
+ union {
+ struct node_msgargs node_msg_args;
+ struct node_taskargs task_arg_obj;
+ } asa;
+};
+
+/*
+ * ======== node_get_channel_id ========
+ * Purpose:
+ * Get the channel index reserved for a stream connection between the
+ * host and a node. This index is reserved when node_connect() is called
+ * to connect the node with the host. This index should be passed to
+ * the CHNL_Open function when the stream is actually opened.
+ * Parameters:
+ * hnode: Node object allocated from node_allocate().
+ * dir: Input (DSP_TONODE) or output (DSP_FROMNODE).
+ * index: Stream index.
+ * chan_id: Location to store channel index.
+ * Returns:
+ * 0: Success.
+ * -EFAULT: Invalid hnode.
+ * -EPERM: Not a task or DAIS socket node.
+ * -EINVAL: The node's stream corresponding to index and dir
+ * is not a stream to or from the host.
+ * Requires:
+ * node_init(void) called.
+ * Valid dir.
+ * chan_id != NULL.
+ * Ensures:
+ */
+extern int node_get_channel_id(struct node_object *hnode,
+ u32 dir, u32 index, u32 *chan_id);
+
+/*
+ * ======== node_get_strm_mgr ========
+ * Purpose:
+ * Get the STRM manager for a node.
+ * Parameters:
+ * hnode: Node allocated with node_allocate().
+ * strm_man: Location to store STRM manager on output.
+ * Returns:
+ * 0: Success.
+ * -EFAULT: Invalid hnode.
+ * Requires:
+ * strm_man != NULL.
+ * Ensures:
+ */
+extern int node_get_strm_mgr(struct node_object *hnode,
+ struct strm_mgr **strm_man);
+
+/*
+ * ======== node_get_timeout ========
+ * Purpose:
+ * Get the timeout value of a node.
+ * Parameters:
+ * hnode: Node allocated with node_allocate(), or DSP_HGPPNODE.
+ * Returns:
+ * Node's timeout value.
+ * Requires:
+ * Valid hnode.
+ * Ensures:
+ */
+extern u32 node_get_timeout(struct node_object *hnode);
+
+/*
+ * ======== node_get_type ========
+ * Purpose:
+ * Get the type (device, message, task, or XDAIS socket) of a node.
+ * Parameters:
+ * hnode: Node allocated with node_allocate(), or DSP_HGPPNODE.
+ * Returns:
+ * Node type: NODE_DEVICE, NODE_TASK, NODE_XDAIS, or NODE_GPP.
+ * Requires:
+ * Valid hnode.
+ * Ensures:
+ */
+extern enum node_type node_get_type(struct node_object *hnode);
+
+/*
+ * ======== get_node_info ========
+ * Purpose:
+ * Get node information without holding semaphore.
+ * Parameters:
+ * hnode: Node allocated with node_allocate(), or DSP_HGPPNODE.
+ * Returns:
+ * Node info: priority, device owner, no. of streams, execution state
+ * NDB properties.
+ * Requires:
+ * Valid hnode.
+ * Ensures:
+ */
+extern void get_node_info(struct node_object *hnode,
+ struct dsp_nodeinfo *node_info);
+
+/*
+ * ======== node_get_load_type ========
+ * Purpose:
+ * Get the load type (dynamic, overlay, static) of a node.
+ * Parameters:
+ * hnode: Node allocated with node_allocate(), or DSP_HGPPNODE.
+ * Returns:
+ * Node type: NLDR_DYNAMICLOAD, NLDR_OVLYLOAD, NLDR_STATICLOAD
+ * Requires:
+ * Valid hnode.
+ * Ensures:
+ */
+extern enum nldr_loadtype node_get_load_type(struct node_object *hnode);
+
+#endif /* NODEPRIV_ */
diff --git a/drivers/staging/tidspbridge/include/dspbridge/ntfy.h b/drivers/staging/tidspbridge/include/dspbridge/ntfy.h
new file mode 100644
index 00000000000..cbc8819c61c
--- /dev/null
+++ b/drivers/staging/tidspbridge/include/dspbridge/ntfy.h
@@ -0,0 +1,217 @@
+/*
+ * ntfy.h
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * Manage lists of notification events.
+ *
+ * Copyright (C) 2005-2006 Texas Instruments, Inc.
+ *
+ * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef NTFY_
+#define NTFY_
+
+#include <dspbridge/host_os.h>
+#include <dspbridge/dbdefs.h>
+#include <dspbridge/sync.h>
+
+/**
+ * ntfy_object - head structure to nofify dspbridge events
+ * @head: List of notify objects
+ * @ntfy_lock: lock for list access.
+ *
+ */
+struct ntfy_object {
+ struct raw_notifier_head head;/* List of notifier objects */
+ spinlock_t ntfy_lock; /* For critical sections */
+};
+
+/**
+ * ntfy_event - structure store specify event to be notified
+ * @noti_block: List of notify objects
+ * @event: event that it respond
+ * @type: event type (only DSP_SIGNALEVENT supported)
+ * @sync_obj: sync_event used to set the event
+ *
+ */
+struct ntfy_event {
+ struct notifier_block noti_block;
+ u32 event; /* Events to be notified about */
+ u32 type; /* Type of notification to be sent */
+ struct sync_object sync_obj;
+};
+
+
+/**
+ * dsp_notifier_event() - callback function to nofity events
+ * @this: pointer to itself struct notifier_block
+ * @event: event to be notified.
+ * @data: Currently not used.
+ *
+ */
+int dsp_notifier_event(struct notifier_block *this, unsigned long event,
+ void *data);
+
+/**
+ * ntfy_init() - Set the initial state of the ntfy_object structure.
+ * @no: pointer to ntfy_object structure.
+ *
+ * This function sets the initial state of the ntfy_object in order it
+ * can be used by the other ntfy functions.
+ */
+
+static inline void ntfy_init(struct ntfy_object *no)
+{
+ spin_lock_init(&no->ntfy_lock);
+ RAW_INIT_NOTIFIER_HEAD(&no->head);
+}
+
+/**
+ * ntfy_delete() - delete list of nofy events registered.
+ * @ntfy_obj: Pointer to the ntfy object structure.
+ *
+ * This function is used to remove all the notify events registered.
+ * unregister function is not needed in this function, to unregister
+ * a ntfy_event please look at ntfy_register function.
+ *
+ */
+static inline void ntfy_delete(struct ntfy_object *ntfy_obj)
+{
+ struct ntfy_event *ne;
+ struct notifier_block *nb;
+
+ spin_lock_bh(&ntfy_obj->ntfy_lock);
+ nb = ntfy_obj->head.head;
+ while (nb) {
+ ne = container_of(nb, struct ntfy_event, noti_block);
+ nb = nb->next;
+ kfree(ne);
+ }
+ spin_unlock_bh(&ntfy_obj->ntfy_lock);
+}
+
+/**
+ * ntfy_notify() - nofity all event register for an specific event.
+ * @ntfy_obj: Pointer to the ntfy_object structure.
+ * @event: event to be notified.
+ *
+ * This function traverses all the ntfy events registers and
+ * set the event with mach with @event.
+ */
+static inline void ntfy_notify(struct ntfy_object *ntfy_obj, u32 event)
+{
+ spin_lock_bh(&ntfy_obj->ntfy_lock);
+ raw_notifier_call_chain(&ntfy_obj->head, event, NULL);
+ spin_unlock_bh(&ntfy_obj->ntfy_lock);
+}
+
+
+
+/**
+ * ntfy_init() - Create and initialize a ntfy_event structure.
+ * @event: event that the ntfy event will respond
+ * @type event type (only DSP_SIGNALEVENT supported)
+ *
+ * This function create a ntfy_event element and sets the event it will
+ * respond the ntfy_event in order it can be used by the other ntfy functions.
+ * In case of success it will return a pointer to the ntfy_event struct
+ * created. Otherwise it will return NULL;
+ */
+
+static inline struct ntfy_event *ntfy_event_create(u32 event, u32 type)
+{
+ struct ntfy_event *ne;
+ ne = kmalloc(sizeof(struct ntfy_event), GFP_KERNEL);
+ if (ne) {
+ sync_init_event(&ne->sync_obj);
+ ne->noti_block.notifier_call = dsp_notifier_event;
+ ne->event = event;
+ ne->type = type;
+ }
+ return ne;
+}
+
+/**
+ * ntfy_register() - register new ntfy_event into a given ntfy_object
+ * @ntfy_obj: Pointer to the ntfy_object structure.
+ * @noti: Pointer to the handle to be returned to the user space.
+ * @event event that the ntfy event will respond
+ * @type event type (only DSP_SIGNALEVENT supported)
+ *
+ * This function register a new ntfy_event into the ntfy_object list,
+ * which will respond to the @event passed.
+ * This function will return 0 in case of error.
+ * -EFAULT in case of bad pointers and
+ * DSP_EMemory in case of no memory to create ntfy_event.
+ */
+static inline int ntfy_register(struct ntfy_object *ntfy_obj,
+ struct dsp_notification *noti,
+ u32 event, u32 type)
+{
+ struct ntfy_event *ne;
+ int status = 0;
+
+ if (!noti || !ntfy_obj) {
+ status = -EFAULT;
+ goto func_end;
+ }
+ if (!event) {
+ status = -EINVAL;
+ goto func_end;
+ }
+ ne = ntfy_event_create(event, type);
+ if (!ne) {
+ status = -ENOMEM;
+ goto func_end;
+ }
+ noti->handle = &ne->sync_obj;
+
+ spin_lock_bh(&ntfy_obj->ntfy_lock);
+ raw_notifier_chain_register(&ntfy_obj->head, &ne->noti_block);
+ spin_unlock_bh(&ntfy_obj->ntfy_lock);
+func_end:
+ return status;
+}
+
+/**
+ * ntfy_unregister() - unregister a ntfy_event from a given ntfy_object
+ * @ntfy_obj: Pointer to the ntfy_object structure.
+ * @noti: Pointer to the event that will be removed.
+ *
+ * This function unregister a ntfy_event from the ntfy_object list,
+ * @noti contains the event which is wanted to be removed.
+ * This function will return 0 in case of error.
+ * -EFAULT in case of bad pointers and
+ * DSP_EMemory in case of no memory to create ntfy_event.
+ */
+static inline int ntfy_unregister(struct ntfy_object *ntfy_obj,
+ struct dsp_notification *noti)
+{
+ int status = 0;
+ struct ntfy_event *ne;
+
+ if (!noti || !ntfy_obj) {
+ status = -EFAULT;
+ goto func_end;
+ }
+
+ ne = container_of((struct sync_object *)noti, struct ntfy_event,
+ sync_obj);
+ spin_lock_bh(&ntfy_obj->ntfy_lock);
+ raw_notifier_chain_unregister(&ntfy_obj->head,
+ &ne->noti_block);
+ kfree(ne);
+ spin_unlock_bh(&ntfy_obj->ntfy_lock);
+func_end:
+ return status;
+}
+
+#endif /* NTFY_ */
diff --git a/drivers/staging/tidspbridge/include/dspbridge/proc.h b/drivers/staging/tidspbridge/include/dspbridge/proc.h
new file mode 100644
index 00000000000..5e09fd165d9
--- /dev/null
+++ b/drivers/staging/tidspbridge/include/dspbridge/proc.h
@@ -0,0 +1,621 @@
+/*
+ * proc.h
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * This is the DSP API RM module interface.
+ *
+ * Copyright (C) 2005-2006 Texas Instruments, Inc.
+ *
+ * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef PROC_
+#define PROC_
+
+#include <dspbridge/cfgdefs.h>
+#include <dspbridge/devdefs.h>
+#include <dspbridge/drv.h>
+
+extern char *iva_img;
+
+/*
+ * ======== proc_attach ========
+ * Purpose:
+ * Prepare for communication with a particular DSP processor, and return
+ * a handle to the processor object. The PROC Object gets created
+ * Parameters:
+ * processor_id : The processor index (zero-based).
+ * hmgr_obj : Handle to the Manager Object
+ * attr_in : Ptr to the dsp_processorattrin structure.
+ * A NULL value means use default values.
+ * ph_processor : Ptr to location to store processor handle.
+ * Returns:
+ * 0 : Success.
+ * -EPERM : General failure.
+ * -EFAULT : Invalid processor handle.
+ * 0: Success; Processor already attached.
+ * Requires:
+ * ph_processor != NULL.
+ * PROC Initialized.
+ * Ensures:
+ * -EPERM, and *ph_processor == NULL, OR
+ * Success and *ph_processor is a Valid Processor handle OR
+ * 0 and *ph_processor is a Valid Processor.
+ * Details:
+ * When attr_in is NULL, the default timeout value is 10 seconds.
+ */
+extern int proc_attach(u32 processor_id,
+ const struct dsp_processorattrin
+ *attr_in, void **ph_processor,
+ struct process_context *pr_ctxt);
+
+/*
+ * ======== proc_auto_start =========
+ * Purpose:
+ * A Particular device gets loaded with the default image
+ * if the AutoStart flag is set.
+ * Parameters:
+ * hdev_obj : Handle to the Device
+ * Returns:
+ * 0 : On Successful Loading
+ * -ENOENT : No DSP exec file found.
+ * -EPERM : General Failure
+ * Requires:
+ * hdev_obj != NULL.
+ * dev_node_obj != NULL.
+ * PROC Initialized.
+ * Ensures:
+ */
+extern int proc_auto_start(struct cfg_devnode *dev_node_obj,
+ struct dev_object *hdev_obj);
+
+/*
+ * ======== proc_ctrl ========
+ * Purpose:
+ * Pass control information to the GPP device driver managing the DSP
+ * processor. This will be an OEM-only function, and not part of the
+ * 'Bridge application developer's API.
+ * Parameters:
+ * hprocessor : The processor handle.
+ * dw_cmd : Private driver IOCTL cmd ID.
+ * pargs : Ptr to an driver defined argument structure.
+ * Returns:
+ * 0 : SUCCESS
+ * -EFAULT : Invalid processor handle.
+ * -ETIME: A Timeout Occured before the Control information
+ * could be sent.
+ * -EPERM : General Failure.
+ * Requires:
+ * PROC Initialized.
+ * Ensures
+ * Details:
+ * This function Calls bridge_dev_ctrl.
+ */
+extern int proc_ctrl(void *hprocessor,
+ u32 dw_cmd, struct dsp_cbdata *arg);
+
+/*
+ * ======== proc_detach ========
+ * Purpose:
+ * Close a DSP processor and de-allocate all (GPP) resources reserved
+ * for it. The Processor Object is deleted.
+ * Parameters:
+ * pr_ctxt : The processor handle.
+ * Returns:
+ * 0 : Success.
+ * -EFAULT : InValid Handle.
+ * -EPERM : General failure.
+ * Requires:
+ * PROC Initialized.
+ * Ensures:
+ * PROC Object is destroyed.
+ */
+extern int proc_detach(struct process_context *pr_ctxt);
+
+/*
+ * ======== proc_enum_nodes ========
+ * Purpose:
+ * Enumerate the nodes currently allocated on a processor.
+ * Parameters:
+ * hprocessor : The processor handle.
+ * node_tab : The first Location of an array allocated for node
+ * handles.
+ * node_tab_size: The number of (DSP_HNODE) handles that can be held
+ * to the memory the client has allocated for node_tab
+ * pu_num_nodes : Location where DSPProcessor_EnumNodes will return
+ * the number of valid handles written to node_tab
+ * pu_allocated : Location where DSPProcessor_EnumNodes will return
+ * the number of nodes that are allocated on the DSP.
+ * Returns:
+ * 0 : Success.
+ * -EFAULT : Invalid processor handle.
+ * -EINVAL : The amount of memory allocated for node_tab is
+ * insufficent. That is the number of nodes actually
+ * allocated on the DSP is greater than the value
+ * specified for node_tab_size.
+ * -EPERM : Unable to get Resource Information.
+ * Details:
+ * Requires
+ * pu_num_nodes is not NULL.
+ * pu_allocated is not NULL.
+ * node_tab is not NULL.
+ * PROC Initialized.
+ * Ensures:
+ * Details:
+ */
+extern int proc_enum_nodes(void *hprocessor,
+ void **node_tab,
+ u32 node_tab_size,
+ u32 *pu_num_nodes,
+ u32 *pu_allocated);
+
+/*
+ * ======== proc_get_resource_info ========
+ * Purpose:
+ * Enumerate the resources currently available on a processor.
+ * Parameters:
+ * hprocessor : The processor handle.
+ * resource_type: Type of resource .
+ * resource_info: Ptr to the dsp_resourceinfo structure.
+ * resource_info_size: Size of the structure.
+ * Returns:
+ * 0 : Success.
+ * -EFAULT : Invalid processor handle.
+ * -EBADR: The processor is not in the PROC_RUNNING state.
+ * -ETIME: A timeout occured before the DSP responded to the
+ * querry.
+ * -EPERM : Unable to get Resource Information
+ * Requires:
+ * resource_info is not NULL.
+ * Parameter resource_type is Valid.[TBD]
+ * resource_info_size is >= sizeof dsp_resourceinfo struct.
+ * PROC Initialized.
+ * Ensures:
+ * Details:
+ * This function currently returns
+ * -ENOSYS, and does not write any data to the resource_info struct.
+ */
+extern int proc_get_resource_info(void *hprocessor,
+ u32 resource_type,
+ struct dsp_resourceinfo
+ *resource_info,
+ u32 resource_info_size);
+
+/*
+ * ======== proc_exit ========
+ * Purpose:
+ * Decrement reference count, and free resources when reference count is
+ * 0.
+ * Parameters:
+ * Returns:
+ * Requires:
+ * PROC is initialized.
+ * Ensures:
+ * When reference count == 0, PROC's private resources are freed.
+ */
+extern void proc_exit(void);
+
+/*
+ * ======== proc_get_dev_object =========
+ * Purpose:
+ * Returns the DEV Hanlde for a given Processor handle
+ * Parameters:
+ * hprocessor : Processor Handle
+ * device_obj : Location to store the DEV Handle.
+ * Returns:
+ * 0 : Success; *device_obj has Dev handle
+ * -EPERM : Failure; *device_obj is zero.
+ * Requires:
+ * device_obj is not NULL
+ * PROC Initialized.
+ * Ensures:
+ * 0 : *device_obj is not NULL
+ * -EPERM : *device_obj is NULL.
+ */
+extern int proc_get_dev_object(void *hprocessor,
+ struct dev_object **device_obj);
+
+/*
+ * ======== proc_init ========
+ * Purpose:
+ * Initialize PROC's private state, keeping a reference count on each
+ * call.
+ * Parameters:
+ * Returns:
+ * TRUE if initialized; FALSE if error occured.
+ * Requires:
+ * Ensures:
+ * TRUE: A requirement for the other public PROC functions.
+ */
+extern bool proc_init(void);
+
+/*
+ * ======== proc_get_state ========
+ * Purpose:
+ * Report the state of the specified DSP processor.
+ * Parameters:
+ * hprocessor : The processor handle.
+ * proc_state_obj : Ptr to location to store the dsp_processorstate
+ * structure.
+ * state_info_size: Size of dsp_processorstate.
+ * Returns:
+ * 0 : Success.
+ * -EFAULT : Invalid processor handle.
+ * -EPERM : General failure while querying processor state.
+ * Requires:
+ * proc_state_obj is not NULL
+ * state_info_size is >= than the size of dsp_processorstate structure.
+ * PROC Initialized.
+ * Ensures:
+ * Details:
+ */
+extern int proc_get_state(void *hprocessor, struct dsp_processorstate
+ *proc_state_obj, u32 state_info_size);
+
+/*
+ * ======== PROC_GetProcessorID ========
+ * Purpose:
+ * Report the state of the specified DSP processor.
+ * Parameters:
+ * hprocessor : The processor handle.
+ * proc_id : Processor ID
+ *
+ * Returns:
+ * 0 : Success.
+ * -EFAULT : Invalid processor handle.
+ * -EPERM : General failure while querying processor state.
+ * Requires:
+ * proc_state_obj is not NULL
+ * state_info_size is >= than the size of dsp_processorstate structure.
+ * PROC Initialized.
+ * Ensures:
+ * Details:
+ */
+extern int proc_get_processor_id(void *proc, u32 * proc_id);
+
+/*
+ * ======== proc_get_trace ========
+ * Purpose:
+ * Retrieve the trace buffer from the specified DSP processor.
+ * Parameters:
+ * hprocessor : The processor handle.
+ * pbuf : Ptr to buffer to hold trace output.
+ * max_size : Maximum size of the output buffer.
+ * Returns:
+ * 0 : Success.
+ * -EFAULT : Invalid processor handle.
+ * -EPERM : General failure while retireving processor trace
+ * Buffer.
+ * Requires:
+ * pbuf is not NULL
+ * max_size is > 0.
+ * PROC Initialized.
+ * Ensures:
+ * Details:
+ */
+extern int proc_get_trace(void *hprocessor, u8 * pbuf, u32 max_size);
+
+/*
+ * ======== proc_load ========
+ * Purpose:
+ * Reset a processor and load a new base program image.
+ * This will be an OEM-only function.
+ * Parameters:
+ * hprocessor: The processor handle.
+ * argc_index: The number of Arguments(strings)in the aArgV[]
+ * user_args: An Array of Arguments(Unicode Strings)
+ * user_envp: An Array of Environment settings(Unicode Strings)
+ * Returns:
+ * 0: Success.
+ * -ENOENT: The DSP Execuetable was not found.
+ * -EFAULT: Invalid processor handle.
+ * -EPERM : Unable to Load the Processor
+ * Requires:
+ * user_args is not NULL
+ * argc_index is > 0
+ * PROC Initialized.
+ * Ensures:
+ * Success and ProcState == PROC_LOADED
+ * or DSP_FAILED status.
+ * Details:
+ * Does not implement access rights to control which GPP application
+ * can load the processor.
+ */
+extern int proc_load(void *hprocessor,
+ const s32 argc_index, const char **user_args,
+ const char **user_envp);
+
+/*
+ * ======== proc_register_notify ========
+ * Purpose:
+ * Register to be notified of specific processor events
+ * Parameters:
+ * hprocessor : The processor handle.
+ * event_mask : Mask of types of events to be notified about.
+ * notify_type : Type of notification to be sent.
+ * hnotification: Handle to be used for notification.
+ * Returns:
+ * 0 : Success.
+ * -EFAULT : Invalid processor handle or hnotification.
+ * -EINVAL : Parameter event_mask is Invalid
+ * DSP_ENOTIMP : The notification type specified in uNotifyMask
+ * is not supported.
+ * -EPERM : Unable to register for notification.
+ * Requires:
+ * hnotification is not NULL
+ * PROC Initialized.
+ * Ensures:
+ * Details:
+ */
+extern int proc_register_notify(void *hprocessor,
+ u32 event_mask, u32 notify_type,
+ struct dsp_notification
+ *hnotification);
+
+/*
+ * ======== proc_notify_clients ========
+ * Purpose:
+ * Notify the Processor Clients
+ * Parameters:
+ * proc : The processor handle.
+ * events : Event to be notified about.
+ * Returns:
+ * 0 : Success.
+ * -EFAULT : Invalid processor handle.
+ * -EPERM : Failure to Set or Reset the Event
+ * Requires:
+ * events is Supported or Valid type of Event
+ * proc is a valid handle
+ * PROC Initialized.
+ * Ensures:
+ */
+extern int proc_notify_clients(void *proc, u32 events);
+
+/*
+ * ======== proc_notify_all_clients ========
+ * Purpose:
+ * Notify the Processor Clients
+ * Parameters:
+ * proc : The processor handle.
+ * events : Event to be notified about.
+ * Returns:
+ * 0 : Success.
+ * -EFAULT : Invalid processor handle.
+ * -EPERM : Failure to Set or Reset the Event
+ * Requires:
+ * events is Supported or Valid type of Event
+ * proc is a valid handle
+ * PROC Initialized.
+ * Ensures:
+ * Details:
+ * NODE And STRM would use this function to notify their clients
+ * about the state changes in NODE or STRM.
+ */
+extern int proc_notify_all_clients(void *proc, u32 events);
+
+/*
+ * ======== proc_start ========
+ * Purpose:
+ * Start a processor running.
+ * Processor must be in PROC_LOADED state.
+ * This will be an OEM-only function, and not part of the 'Bridge
+ * application developer's API.
+ * Parameters:
+ * hprocessor : The processor handle.
+ * Returns:
+ * 0 : Success.
+ * -EFAULT : Invalid processor handle.
+ * -EBADR: Processor is not in PROC_LOADED state.
+ * -EPERM : Unable to start the processor.
+ * Requires:
+ * PROC Initialized.
+ * Ensures:
+ * Success and ProcState == PROC_RUNNING or DSP_FAILED status.
+ * Details:
+ */
+extern int proc_start(void *hprocessor);
+
+/*
+ * ======== proc_stop ========
+ * Purpose:
+ * Start a processor running.
+ * Processor must be in PROC_LOADED state.
+ * This will be an OEM-only function, and not part of the 'Bridge
+ * application developer's API.
+ * Parameters:
+ * hprocessor : The processor handle.
+ * Returns:
+ * 0 : Success.
+ * -EFAULT : Invalid processor handle.
+ * -EBADR: Processor is not in PROC_LOADED state.
+ * -EPERM : Unable to start the processor.
+ * Requires:
+ * PROC Initialized.
+ * Ensures:
+ * Success and ProcState == PROC_RUNNING or DSP_FAILED status.
+ * Details:
+ */
+extern int proc_stop(void *hprocessor);
+
+/*
+ * ======== proc_end_dma ========
+ * Purpose:
+ * Begin a DMA transfer
+ * Parameters:
+ * hprocessor : The processor handle.
+ * pmpu_addr : Buffer start address
+ * ul_size : Buffer size
+ * dir : The direction of the transfer
+ * Requires:
+ * Memory was previously mapped.
+ */
+extern int proc_end_dma(void *hprocessor, void *pmpu_addr, u32 ul_size,
+ enum dma_data_direction dir);
+/*
+ * ======== proc_begin_dma ========
+ * Purpose:
+ * Begin a DMA transfer
+ * Parameters:
+ * hprocessor : The processor handle.
+ * pmpu_addr : Buffer start address
+ * ul_size : Buffer size
+ * dir : The direction of the transfer
+ * Requires:
+ * Memory was previously mapped.
+ */
+extern int proc_begin_dma(void *hprocessor, void *pmpu_addr, u32 ul_size,
+ enum dma_data_direction dir);
+
+/*
+ * ======== proc_flush_memory ========
+ * Purpose:
+ * Flushes a buffer from the MPU data cache.
+ * Parameters:
+ * hprocessor : The processor handle.
+ * pmpu_addr : Buffer start address
+ * ul_size : Buffer size
+ * ul_flags : Reserved.
+ * Returns:
+ * 0 : Success.
+ * -EFAULT : Invalid processor handle.
+ * -EPERM : General failure.
+ * Requires:
+ * PROC Initialized.
+ * Ensures:
+ * Details:
+ * All the arguments are currently ignored.
+ */
+extern int proc_flush_memory(void *hprocessor,
+ void *pmpu_addr, u32 ul_size, u32 ul_flags);
+
+/*
+ * ======== proc_invalidate_memory ========
+ * Purpose:
+ * Invalidates a buffer from the MPU data cache.
+ * Parameters:
+ * hprocessor : The processor handle.
+ * pmpu_addr : Buffer start address
+ * ul_size : Buffer size
+ * Returns:
+ * 0 : Success.
+ * -EFAULT : Invalid processor handle.
+ * -EPERM : General failure.
+ * Requires:
+ * PROC Initialized.
+ * Ensures:
+ * Details:
+ * All the arguments are currently ignored.
+ */
+extern int proc_invalidate_memory(void *hprocessor,
+ void *pmpu_addr, u32 ul_size);
+
+/*
+ * ======== proc_map ========
+ * Purpose:
+ * Maps a MPU buffer to DSP address space.
+ * Parameters:
+ * hprocessor : The processor handle.
+ * pmpu_addr : Starting address of the memory region to map.
+ * ul_size : Size of the memory region to map.
+ * req_addr : Requested DSP start address. Offset-adjusted actual
+ * mapped address is in the last argument.
+ * pp_map_addr : Ptr to DSP side mapped u8 address.
+ * ul_map_attr : Optional endianness attributes, virt to phys flag.
+ * Returns:
+ * 0 : Success.
+ * -EFAULT : Invalid processor handle.
+ * -EPERM : General failure.
+ * -ENOMEM : MPU side memory allocation error.
+ * -ENOENT : Cannot find a reserved region starting with this
+ * : address.
+ * Requires:
+ * pmpu_addr is not NULL
+ * ul_size is not zero
+ * pp_map_addr is not NULL
+ * PROC Initialized.
+ * Ensures:
+ * Details:
+ */
+extern int proc_map(void *hprocessor,
+ void *pmpu_addr,
+ u32 ul_size,
+ void *req_addr,
+ void **pp_map_addr, u32 ul_map_attr,
+ struct process_context *pr_ctxt);
+
+/*
+ * ======== proc_reserve_memory ========
+ * Purpose:
+ * Reserve a virtually contiguous region of DSP address space.
+ * Parameters:
+ * hprocessor : The processor handle.
+ * ul_size : Size of the address space to reserve.
+ * pp_rsv_addr : Ptr to DSP side reserved u8 address.
+ * Returns:
+ * 0 : Success.
+ * -EFAULT : Invalid processor handle.
+ * -EPERM : General failure.
+ * -ENOMEM : Cannot reserve chunk of this size.
+ * Requires:
+ * pp_rsv_addr is not NULL
+ * PROC Initialized.
+ * Ensures:
+ * Details:
+ */
+extern int proc_reserve_memory(void *hprocessor,
+ u32 ul_size, void **pp_rsv_addr,
+ struct process_context *pr_ctxt);
+
+/*
+ * ======== proc_un_map ========
+ * Purpose:
+ * Removes a MPU buffer mapping from the DSP address space.
+ * Parameters:
+ * hprocessor : The processor handle.
+ * map_addr : Starting address of the mapped memory region.
+ * Returns:
+ * 0 : Success.
+ * -EFAULT : Invalid processor handle.
+ * -EPERM : General failure.
+ * -ENOENT : Cannot find a mapped region starting with this
+ * : address.
+ * Requires:
+ * map_addr is not NULL
+ * PROC Initialized.
+ * Ensures:
+ * Details:
+ */
+extern int proc_un_map(void *hprocessor, void *map_addr,
+ struct process_context *pr_ctxt);
+
+/*
+ * ======== proc_un_reserve_memory ========
+ * Purpose:
+ * Frees a previously reserved region of DSP address space.
+ * Parameters:
+ * hprocessor : The processor handle.
+ * prsv_addr : Ptr to DSP side reservedBYTE address.
+ * Returns:
+ * 0 : Success.
+ * -EFAULT : Invalid processor handle.
+ * -EPERM : General failure.
+ * -ENOENT : Cannot find a reserved region starting with this
+ * : address.
+ * Requires:
+ * prsv_addr is not NULL
+ * PROC Initialized.
+ * Ensures:
+ * Details:
+ */
+extern int proc_un_reserve_memory(void *hprocessor,
+ void *prsv_addr,
+ struct process_context *pr_ctxt);
+
+#endif /* PROC_ */
diff --git a/drivers/staging/tidspbridge/include/dspbridge/procpriv.h b/drivers/staging/tidspbridge/include/dspbridge/procpriv.h
new file mode 100644
index 00000000000..77d1f0ef95c
--- /dev/null
+++ b/drivers/staging/tidspbridge/include/dspbridge/procpriv.h
@@ -0,0 +1,25 @@
+/*
+ * procpriv.h
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * Global PROC constants and types, shared by PROC, MGR and DSP API.
+ *
+ * Copyright (C) 2005-2006 Texas Instruments, Inc.
+ *
+ * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef PROCPRIV_
+#define PROCPRIV_
+
+/* RM PROC Object */
+struct proc_object;
+
+#endif /* PROCPRIV_ */
diff --git a/drivers/staging/tidspbridge/include/dspbridge/pwr.h b/drivers/staging/tidspbridge/include/dspbridge/pwr.h
new file mode 100644
index 00000000000..a6dc783904e
--- /dev/null
+++ b/drivers/staging/tidspbridge/include/dspbridge/pwr.h
@@ -0,0 +1,107 @@
+/*
+ * pwr.h
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * Copyright (C) 2005-2006 Texas Instruments, Inc.
+ *
+ * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef PWR_
+#define PWR_
+
+#include <dspbridge/dbdefs.h>
+#include <dspbridge/pwr_sh.h>
+
+/*
+ * ======== pwr_sleep_dsp ========
+ * Signal the DSP to go to sleep.
+ *
+ * Parameters:
+ * sleep_code: New sleep state for DSP. (Initially, valid codes
+ * are PWR_DEEPSLEEP or PWR_EMERGENCYDEEPSLEEP; both of
+ * these codes will simply put the DSP in deep sleep.)
+ *
+ * timeout: Maximum time (msec) that PWR should wait for
+ * confirmation that the DSP sleep state has been
+ * reached. If PWR should simply send the command to
+ * the DSP to go to sleep and then return (i.e.,
+ * asynchrounous sleep), the timeout should be
+ * specified as zero.
+ *
+ * Returns:
+ * 0: Success.
+ * 0: Success, but the DSP was already asleep.
+ * -EINVAL: The specified sleep_code is not supported.
+ * -ETIME: A timeout occured while waiting for DSP sleep
+ * confirmation.
+ * -EPERM: General failure, unable to send sleep command to
+ * the DSP.
+ */
+extern int pwr_sleep_dsp(const u32 sleep_code, const u32 timeout);
+
+/*
+ * ======== pwr_wake_dsp ========
+ * Signal the DSP to wake from sleep.
+ *
+ * Parameters:
+ * timeout: Maximum time (msec) that PWR should wait for
+ * confirmation that the DSP is awake. If PWR should
+ * simply send a command to the DSP to wake and then
+ * return (i.e., asynchrounous wake), timeout should
+ * be specified as zero.
+ *
+ * Returns:
+ * 0: Success.
+ * 0: Success, but the DSP was already awake.
+ * -ETIME: A timeout occured while waiting for wake
+ * confirmation.
+ * -EPERM: General failure, unable to send wake command to
+ * the DSP.
+ */
+extern int pwr_wake_dsp(const u32 timeout);
+
+/*
+ * ======== pwr_pm_pre_scale ========
+ * Prescale notification to DSP.
+ *
+ * Parameters:
+ * voltage_domain: The voltage domain for which notification is sent
+ * level: The level of voltage domain
+ *
+ * Returns:
+ * 0: Success.
+ * 0: Success, but the DSP was already awake.
+ * -ETIME: A timeout occured while waiting for wake
+ * confirmation.
+ * -EPERM: General failure, unable to send wake command to
+ * the DSP.
+ */
+extern int pwr_pm_pre_scale(u16 voltage_domain, u32 level);
+
+/*
+ * ======== pwr_pm_post_scale ========
+ * PostScale notification to DSP.
+ *
+ * Parameters:
+ * voltage_domain: The voltage domain for which notification is sent
+ * level: The level of voltage domain
+ *
+ * Returns:
+ * 0: Success.
+ * 0: Success, but the DSP was already awake.
+ * -ETIME: A timeout occured while waiting for wake
+ * confirmation.
+ * -EPERM: General failure, unable to send wake command to
+ * the DSP.
+ */
+extern int pwr_pm_post_scale(u16 voltage_domain, u32 level);
+
+#endif /* PWR_ */
diff --git a/drivers/staging/tidspbridge/include/dspbridge/pwr_sh.h b/drivers/staging/tidspbridge/include/dspbridge/pwr_sh.h
new file mode 100644
index 00000000000..1b4a090abe7
--- /dev/null
+++ b/drivers/staging/tidspbridge/include/dspbridge/pwr_sh.h
@@ -0,0 +1,33 @@
+/*
+ * pwr_sh.h
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * Power Manager shared definitions (used on both GPP and DSP sides).
+ *
+ * Copyright (C) 2008 Texas Instruments, Inc.
+ *
+ * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef PWR_SH_
+#define PWR_SH_
+
+#include <dspbridge/mbx_sh.h>
+
+/* valid sleep command codes that can be sent by GPP via mailbox: */
+#define PWR_DEEPSLEEP MBX_PM_DSPIDLE
+#define PWR_EMERGENCYDEEPSLEEP MBX_PM_EMERGENCYSLEEP
+#define PWR_SLEEPUNTILRESTART MBX_PM_SLEEPUNTILRESTART
+#define PWR_WAKEUP MBX_PM_DSPWAKEUP
+#define PWR_AUTOENABLE MBX_PM_PWRENABLE
+#define PWR_AUTODISABLE MBX_PM_PWRDISABLE
+#define PWR_RETENTION MBX_PM_DSPRETN
+
+#endif /* PWR_SH_ */
diff --git a/drivers/staging/tidspbridge/include/dspbridge/resourcecleanup.h b/drivers/staging/tidspbridge/include/dspbridge/resourcecleanup.h
new file mode 100644
index 00000000000..dfaf0c6c06f
--- /dev/null
+++ b/drivers/staging/tidspbridge/include/dspbridge/resourcecleanup.h
@@ -0,0 +1,52 @@
+/*
+ * resourcecleanup.h
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * Copyright (C) 2005-2006 Texas Instruments, Inc.
+ *
+ * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include <dspbridge/nodepriv.h>
+#include <dspbridge/drv.h>
+
+extern int drv_get_proc_ctxt_list(struct process_context **pctxt,
+ struct drv_object *hdrv_obj);
+
+extern int drv_insert_proc_context(struct drv_object *driver_obj,
+ void *process_ctxt);
+
+extern int drv_remove_all_dmm_res_elements(void *process_ctxt);
+
+extern int drv_remove_all_node_res_elements(void *process_ctxt);
+
+extern int drv_proc_set_pid(void *ctxt, s32 process);
+
+extern int drv_remove_all_resources(void *process_ctxt);
+
+extern int drv_remove_proc_context(struct drv_object *driver_obj,
+ void *pr_ctxt);
+
+extern int drv_insert_node_res_element(void *hnode, void *node_resource,
+ void *process_ctxt);
+
+extern void drv_proc_node_update_heap_status(void *node_resource, s32 status);
+
+extern void drv_proc_node_update_status(void *node_resource, s32 status);
+
+extern int drv_proc_update_strm_res(u32 num_bufs, void *strm_resources);
+
+extern int drv_proc_insert_strm_res_element(void *stream_obj,
+ void *strm_res,
+ void *process_ctxt);
+
+extern int drv_remove_all_strm_res_elements(void *process_ctxt);
+
+extern enum node_state node_get_state(void *hnode);
diff --git a/drivers/staging/tidspbridge/include/dspbridge/rmm.h b/drivers/staging/tidspbridge/include/dspbridge/rmm.h
new file mode 100644
index 00000000000..baea536681e
--- /dev/null
+++ b/drivers/staging/tidspbridge/include/dspbridge/rmm.h
@@ -0,0 +1,181 @@
+/*
+ * rmm.h
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * This memory manager provides general heap management and arbitrary
+ * alignment for any number of memory segments, and management of overlay
+ * memory.
+ *
+ * Copyright (C) 2005-2006 Texas Instruments, Inc.
+ *
+ * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef RMM_
+#define RMM_
+
+/*
+ * ======== rmm_addr ========
+ * DSP address + segid
+ */
+struct rmm_addr {
+ u32 addr;
+ s32 segid;
+};
+
+/*
+ * ======== rmm_segment ========
+ * Memory segment on the DSP available for remote allocations.
+ */
+struct rmm_segment {
+ u32 base; /* Base of the segment */
+ u32 length; /* Size of the segment (target MAUs) */
+ s32 space; /* Code or data */
+ u32 number; /* Number of Allocated Blocks */
+};
+
+/*
+ * ======== RMM_Target ========
+ */
+struct rmm_target_obj;
+
+/*
+ * ======== rmm_alloc ========
+ *
+ * rmm_alloc is used to remotely allocate or reserve memory on the DSP.
+ *
+ * Parameters:
+ * target - Target returned from rmm_create().
+ * segid - Memory segment to allocate from.
+ * size - Size (target MAUS) to allocate.
+ * align - alignment.
+ * dsp_address - If reserve is FALSE, the location to store allocated
+ * address on output, otherwise, the DSP address to
+ * reserve.
+ * reserve - If TRUE, reserve the memory specified by dsp_address.
+ * Returns:
+ * 0: Success.
+ * -ENOMEM: Memory allocation on GPP failed.
+ * -ENXIO: Cannot "allocate" overlay memory because it's
+ * already in use.
+ * Requires:
+ * RMM initialized.
+ * Valid target.
+ * dsp_address != NULL.
+ * size > 0
+ * reserve || target->num_segs > 0.
+ * Ensures:
+ */
+extern int rmm_alloc(struct rmm_target_obj *target, u32 segid, u32 size,
+ u32 align, u32 *dsp_address, bool reserve);
+
+/*
+ * ======== rmm_create ========
+ * Create a target object with memory segments for remote allocation. If
+ * seg_tab == NULL or num_segs == 0, memory can only be reserved through
+ * rmm_alloc().
+ *
+ * Parameters:
+ * target_obj: - Location to store target on output.
+ * seg_tab: - Table of memory segments.
+ * num_segs: - Number of memory segments.
+ * Returns:
+ * 0: Success.
+ * -ENOMEM: Memory allocation failed.
+ * Requires:
+ * RMM initialized.
+ * target_obj != NULL.
+ * num_segs == 0 || seg_tab != NULL.
+ * Ensures:
+ * Success: Valid *target_obj.
+ * Failure: *target_obj == NULL.
+ */
+extern int rmm_create(struct rmm_target_obj **target_obj,
+ struct rmm_segment seg_tab[], u32 num_segs);
+
+/*
+ * ======== rmm_delete ========
+ * Delete target allocated in rmm_create().
+ *
+ * Parameters:
+ * target - Target returned from rmm_create().
+ * Returns:
+ * Requires:
+ * RMM initialized.
+ * Valid target.
+ * Ensures:
+ */
+extern void rmm_delete(struct rmm_target_obj *target);
+
+/*
+ * ======== rmm_exit ========
+ * Exit the RMM module
+ *
+ * Parameters:
+ * Returns:
+ * Requires:
+ * rmm_init successfully called.
+ * Ensures:
+ */
+extern void rmm_exit(void);
+
+/*
+ * ======== rmm_free ========
+ * Free or unreserve memory allocated through rmm_alloc().
+ *
+ * Parameters:
+ * target: - Target returned from rmm_create().
+ * segid: - Segment of memory to free.
+ * dsp_address: - Address to free or unreserve.
+ * size: - Size of memory to free or unreserve.
+ * reserved: - TRUE if memory was reserved only, otherwise FALSE.
+ * Returns:
+ * Requires:
+ * RMM initialized.
+ * Valid target.
+ * reserved || segid < target->num_segs.
+ * reserve || [dsp_address, dsp_address + size] is a valid memory range.
+ * Ensures:
+ */
+extern bool rmm_free(struct rmm_target_obj *target, u32 segid, u32 dsp_addr,
+ u32 size, bool reserved);
+
+/*
+ * ======== rmm_init ========
+ * Initialize the RMM module
+ *
+ * Parameters:
+ * Returns:
+ * TRUE: Success.
+ * FALSE: Failure.
+ * Requires:
+ * Ensures:
+ */
+extern bool rmm_init(void);
+
+/*
+ * ======== rmm_stat ========
+ * Obtain memory segment status
+ *
+ * Parameters:
+ * segid: Segment ID of the dynamic loading segment.
+ * mem_stat_buf: Pointer to allocated buffer into which memory stats are
+ * placed.
+ * Returns:
+ * TRUE: Success.
+ * FALSE: Failure.
+ * Requires:
+ * segid < target->num_segs
+ * Ensures:
+ */
+extern bool rmm_stat(struct rmm_target_obj *target, enum dsp_memtype segid,
+ struct dsp_memstat *mem_stat_buf);
+
+#endif /* RMM_ */
diff --git a/drivers/staging/tidspbridge/include/dspbridge/rms_sh.h b/drivers/staging/tidspbridge/include/dspbridge/rms_sh.h
new file mode 100644
index 00000000000..7bc5574342a
--- /dev/null
+++ b/drivers/staging/tidspbridge/include/dspbridge/rms_sh.h
@@ -0,0 +1,95 @@
+/*
+ * rms_sh.h
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * DSP/BIOS Bridge Resource Manager Server shared definitions (used on both
+ * GPP and DSP sides).
+ *
+ * Copyright (C) 2008 Texas Instruments, Inc.
+ *
+ * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef RMS_SH_
+#define RMS_SH_
+
+#include <dspbridge/rmstypes.h>
+
+/* Node Types: */
+#define RMS_TASK 1 /* Task node */
+#define RMS_DAIS 2 /* xDAIS socket node */
+#define RMS_MSG 3 /* Message node */
+
+/* Memory Types: */
+#define RMS_CODE 0 /* Program space */
+#define RMS_DATA 1 /* Data space */
+#define RMS_IO 2 /* I/O space */
+
+/* RM Server Command and Response Buffer Sizes: */
+#define RMS_COMMANDBUFSIZE 256 /* Size of command buffer */
+#define RMS_RESPONSEBUFSIZE 16 /* Size of response buffer */
+
+/* Pre-Defined Command/Response Codes: */
+#define RMS_EXIT 0x80000000 /* GPP->Node: shutdown */
+#define RMS_EXITACK 0x40000000 /* Node->GPP: ack shutdown */
+#define RMS_BUFDESC 0x20000000 /* Arg1 SM buf, Arg2 SM size */
+#define RMS_KILLTASK 0x10000000 /* GPP->Node: Kill Task */
+#define RMS_USER 0x0 /* Start of user-defined msg codes */
+#define RMS_MAXUSERCODES 0xfff /* Maximum user defined C/R Codes */
+
+/* RM Server RPC Command Structure: */
+struct rms_command {
+ rms_word fxn; /* Server function address */
+ rms_word arg1; /* First argument */
+ rms_word arg2; /* Second argument */
+ rms_word data; /* Function-specific data array */
+};
+
+/*
+ * The rms_strm_def structure defines the parameters for both input and output
+ * streams, and is passed to a node's create function.
+ */
+struct rms_strm_def {
+ rms_word bufsize; /* Buffer size (in DSP words) */
+ rms_word nbufs; /* Max number of bufs in stream */
+ rms_word segid; /* Segment to allocate buffers */
+ rms_word align; /* Alignment for allocated buffers */
+ rms_word timeout; /* Timeout (msec) for blocking calls */
+ char name[1]; /* Device Name (terminated by '\0') */
+};
+
+/* Message node create args structure: */
+struct rms_msg_args {
+ rms_word max_msgs; /* Max # simultaneous msgs to node */
+ rms_word segid; /* Mem segment for NODE_allocMsgBuf */
+ rms_word notify_type; /* Type of message notification */
+ rms_word arg_length; /* Length (in DSP chars) of arg data */
+ rms_word arg_data; /* Arg data for node */
+};
+
+/* Partial task create args structure */
+struct rms_more_task_args {
+ rms_word priority; /* Task's runtime priority level */
+ rms_word stack_size; /* Task's stack size */
+ rms_word sysstack_size; /* Task's system stack size (55x) */
+ rms_word stack_seg; /* Memory segment for task's stack */
+ rms_word heap_addr; /* base address of the node memory heap in
+ * external memory (DSP virtual address) */
+ rms_word heap_size; /* size in MAUs of the node memory heap in
+ * external memory */
+ rms_word misc; /* Misc field. Not used for 'normal'
+ * task nodes; for xDAIS socket nodes
+ * specifies the IALG_Fxn pointer.
+ */
+ /* # input STRM definition structures */
+ rms_word num_input_streams;
+};
+
+#endif /* RMS_SH_ */
diff --git a/drivers/staging/tidspbridge/include/dspbridge/rmstypes.h b/drivers/staging/tidspbridge/include/dspbridge/rmstypes.h
new file mode 100644
index 00000000000..83c0f1d9619
--- /dev/null
+++ b/drivers/staging/tidspbridge/include/dspbridge/rmstypes.h
@@ -0,0 +1,24 @@
+/*
+ * rmstypes.h
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * DSP/BIOS Bridge Resource Manager Server shared data type definitions.
+ *
+ * Copyright (C) 2008 Texas Instruments, Inc.
+ *
+ * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef RMSTYPES_
+#define RMSTYPES_
+#include <linux/types.h>
+typedef u32 rms_word;
+
+#endif /* RMSTYPES_ */
diff --git a/drivers/staging/tidspbridge/include/dspbridge/services.h b/drivers/staging/tidspbridge/include/dspbridge/services.h
new file mode 100644
index 00000000000..eb26c867c93
--- /dev/null
+++ b/drivers/staging/tidspbridge/include/dspbridge/services.h
@@ -0,0 +1,50 @@
+/*
+ * services.h
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * Provide loading and unloading of SERVICES modules.
+ *
+ * Copyright (C) 2005-2006 Texas Instruments, Inc.
+ *
+ * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef SERVICES_
+#define SERVICES_
+
+#include <dspbridge/host_os.h>
+/*
+ * ======== services_exit ========
+ * Purpose:
+ * Discontinue usage of module; free resources when reference count
+ * reaches 0.
+ * Parameters:
+ * Returns:
+ * Requires:
+ * SERVICES initialized.
+ * Ensures:
+ * Resources used by module are freed when cRef reaches zero.
+ */
+extern void services_exit(void);
+
+/*
+ * ======== services_init ========
+ * Purpose:
+ * Initializes SERVICES modules.
+ * Parameters:
+ * Returns:
+ * TRUE if all modules initialized; otherwise FALSE.
+ * Requires:
+ * Ensures:
+ * SERVICES modules initialized.
+ */
+extern bool services_init(void);
+
+#endif /* SERVICES_ */
diff --git a/drivers/staging/tidspbridge/include/dspbridge/strm.h b/drivers/staging/tidspbridge/include/dspbridge/strm.h
new file mode 100644
index 00000000000..3e4671e7f91
--- /dev/null
+++ b/drivers/staging/tidspbridge/include/dspbridge/strm.h
@@ -0,0 +1,404 @@
+/*
+ * strm.h
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * DSPBridge Stream Manager.
+ *
+ * Copyright (C) 2005-2006 Texas Instruments, Inc.
+ *
+ * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef STRM_
+#define STRM_
+
+#include <dspbridge/dev.h>
+
+#include <dspbridge/strmdefs.h>
+#include <dspbridge/proc.h>
+
+/*
+ * ======== strm_allocate_buffer ========
+ * Purpose:
+ * Allocate data buffer(s) for use with a stream.
+ * Parameter:
+ * strmres: Stream resource info handle returned from strm_open().
+ * usize: Size (GPP bytes) of the buffer(s).
+ * num_bufs: Number of buffers to allocate.
+ * ap_buffer: Array to hold buffer addresses.
+ * Returns:
+ * 0: Success.
+ * -EFAULT: Invalid stream_obj.
+ * -ENOMEM: Insufficient memory.
+ * -EPERM: Failure occurred, unable to allocate buffers.
+ * -EINVAL: usize must be > 0 bytes.
+ * Requires:
+ * strm_init(void) called.
+ * ap_buffer != NULL.
+ * Ensures:
+ */
+extern int strm_allocate_buffer(struct strm_res_object *strmres,
+ u32 usize,
+ u8 **ap_buffer,
+ u32 num_bufs,
+ struct process_context *pr_ctxt);
+
+/*
+ * ======== strm_close ========
+ * Purpose:
+ * Close a stream opened with strm_open().
+ * Parameter:
+ * strmres: Stream resource info handle returned from strm_open().
+ * Returns:
+ * 0: Success.
+ * -EFAULT: Invalid stream_obj.
+ * -EPIPE: Some data buffers issued to the stream have not
+ * been reclaimed.
+ * -EPERM: Failure to close stream.
+ * Requires:
+ * strm_init(void) called.
+ * Ensures:
+ */
+extern int strm_close(struct strm_res_object *strmres,
+ struct process_context *pr_ctxt);
+
+/*
+ * ======== strm_create ========
+ * Purpose:
+ * Create a STRM manager object. This object holds information about the
+ * device needed to open streams.
+ * Parameters:
+ * strm_man: Location to store handle to STRM manager object on
+ * output.
+ * dev_obj: Device for this processor.
+ * Returns:
+ * 0: Success;
+ * -ENOMEM: Insufficient memory for requested resources.
+ * -EPERM: General failure.
+ * Requires:
+ * strm_init(void) called.
+ * strm_man != NULL.
+ * dev_obj != NULL.
+ * Ensures:
+ * 0: Valid *strm_man.
+ * error: *strm_man == NULL.
+ */
+extern int strm_create(struct strm_mgr **strm_man,
+ struct dev_object *dev_obj);
+
+/*
+ * ======== strm_delete ========
+ * Purpose:
+ * Delete the STRM Object.
+ * Parameters:
+ * strm_mgr_obj: Handle to STRM manager object from strm_create.
+ * Returns:
+ * Requires:
+ * strm_init(void) called.
+ * Valid strm_mgr_obj.
+ * Ensures:
+ * strm_mgr_obj is not valid.
+ */
+extern void strm_delete(struct strm_mgr *strm_mgr_obj);
+
+/*
+ * ======== strm_exit ========
+ * Purpose:
+ * Discontinue usage of STRM module.
+ * Parameters:
+ * Returns:
+ * Requires:
+ * strm_init(void) successfully called before.
+ * Ensures:
+ */
+extern void strm_exit(void);
+
+/*
+ * ======== strm_free_buffer ========
+ * Purpose:
+ * Free buffer(s) allocated with strm_allocate_buffer.
+ * Parameter:
+ * strmres: Stream resource info handle returned from strm_open().
+ * ap_buffer: Array containing buffer addresses.
+ * num_bufs: Number of buffers to be freed.
+ * Returns:
+ * 0: Success.
+ * -EFAULT: Invalid stream handle.
+ * -EPERM: Failure occurred, unable to free buffers.
+ * Requires:
+ * strm_init(void) called.
+ * ap_buffer != NULL.
+ * Ensures:
+ */
+extern int strm_free_buffer(struct strm_res_object *strmres,
+ u8 **ap_buffer, u32 num_bufs,
+ struct process_context *pr_ctxt);
+
+/*
+ * ======== strm_get_event_handle ========
+ * Purpose:
+ * Get stream's user event handle. This function is used when closing
+ * a stream, so the event can be closed.
+ * Parameter:
+ * stream_obj: Stream handle returned from strm_open().
+ * ph_event: Location to store event handle on output.
+ * Returns:
+ * 0: Success.
+ * -EFAULT: Invalid stream_obj.
+ * Requires:
+ * strm_init(void) called.
+ * ph_event != NULL.
+ * Ensures:
+ */
+extern int strm_get_event_handle(struct strm_object *stream_obj,
+ void **ph_event);
+
+/*
+ * ======== strm_get_info ========
+ * Purpose:
+ * Get information about a stream. User's dsp_streaminfo is contained
+ * in stream_info struct. stream_info also contains Bridge private info.
+ * Parameters:
+ * stream_obj: Stream handle returned from strm_open().
+ * stream_info: Location to store stream info on output.
+ * uSteamInfoSize: Size of user's dsp_streaminfo structure.
+ * Returns:
+ * 0: Success.
+ * -EFAULT: Invalid stream_obj.
+ * -EINVAL: stream_info_size < sizeof(dsp_streaminfo).
+ * -EPERM: Unable to get stream info.
+ * Requires:
+ * strm_init(void) called.
+ * stream_info != NULL.
+ * Ensures:
+ */
+extern int strm_get_info(struct strm_object *stream_obj,
+ struct stream_info *stream_info,
+ u32 stream_info_size);
+
+/*
+ * ======== strm_idle ========
+ * Purpose:
+ * Idle a stream and optionally flush output data buffers.
+ * If this is an output stream and flush_data is TRUE, all data currently
+ * enqueued will be discarded.
+ * If this is an output stream and flush_data is FALSE, this function
+ * will block until all currently buffered data is output, or the timeout
+ * specified has been reached.
+ * After a successful call to strm_idle(), all buffers can immediately
+ * be reclaimed.
+ * Parameters:
+ * stream_obj: Stream handle returned from strm_open().
+ * flush_data: If TRUE, discard output buffers.
+ * Returns:
+ * 0: Success.
+ * -EFAULT: Invalid stream_obj.
+ * -ETIME: A timeout occurred before the stream could be idled.
+ * -EPERM: Unable to idle stream.
+ * Requires:
+ * strm_init(void) called.
+ * Ensures:
+ */
+extern int strm_idle(struct strm_object *stream_obj, bool flush_data);
+
+/*
+ * ======== strm_init ========
+ * Purpose:
+ * Initialize the STRM module.
+ * Parameters:
+ * Returns:
+ * TRUE if initialization succeeded, FALSE otherwise.
+ * Requires:
+ * Ensures:
+ */
+extern bool strm_init(void);
+
+/*
+ * ======== strm_issue ========
+ * Purpose:
+ * Send a buffer of data to a stream.
+ * Parameters:
+ * stream_obj: Stream handle returned from strm_open().
+ * pbuf: Pointer to buffer of data to be sent to the stream.
+ * ul_bytes: Number of bytes of data in the buffer.
+ * ul_buf_size: Actual buffer size in bytes.
+ * dw_arg: A user argument that travels with the buffer.
+ * Returns:
+ * 0: Success.
+ * -EFAULT: Invalid stream_obj.
+ * -ENOSR: The stream is full.
+ * -EPERM: Failure occurred, unable to issue buffer.
+ * Requires:
+ * strm_init(void) called.
+ * pbuf != NULL.
+ * Ensures:
+ */
+extern int strm_issue(struct strm_object *stream_obj, u8 * pbuf,
+ u32 ul_bytes, u32 ul_buf_size, u32 dw_arg);
+
+/*
+ * ======== strm_open ========
+ * Purpose:
+ * Open a stream for sending/receiving data buffers to/from a task of
+ * DAIS socket node on the DSP.
+ * Parameters:
+ * hnode: Node handle returned from node_allocate().
+ * dir: DSP_TONODE or DSP_FROMNODE.
+ * index: Stream index.
+ * pattr: Pointer to structure containing attributes to be
+ * applied to stream. Cannot be NULL.
+ * strmres: Location to store stream resuorce info handle on output.
+ * Returns:
+ * 0: Success.
+ * -EFAULT: Invalid hnode.
+ * -EPERM: Invalid direction.
+ * hnode is not a task or DAIS socket node.
+ * Unable to open stream.
+ * -EINVAL: Invalid index.
+ * Requires:
+ * strm_init(void) called.
+ * strmres != NULL.
+ * pattr != NULL.
+ * Ensures:
+ * 0: *strmres is valid.
+ * error: *strmres == NULL.
+ */
+extern int strm_open(struct node_object *hnode, u32 dir,
+ u32 index, struct strm_attr *pattr,
+ struct strm_res_object **strmres,
+ struct process_context *pr_ctxt);
+
+/*
+ * ======== strm_prepare_buffer ========
+ * Purpose:
+ * Prepare a data buffer not allocated by DSPStream_AllocateBuffers()
+ * for use with a stream.
+ * Parameter:
+ * stream_obj: Stream handle returned from strm_open().
+ * usize: Size (GPP bytes) of the buffer.
+ * pbuffer: Buffer address.
+ * Returns:
+ * 0: Success.
+ * -EFAULT: Invalid stream_obj.
+ * -EPERM: Failure occurred, unable to prepare buffer.
+ * Requires:
+ * strm_init(void) called.
+ * pbuffer != NULL.
+ * Ensures:
+ */
+extern int strm_prepare_buffer(struct strm_object *stream_obj,
+ u32 usize, u8 *pbuffer);
+
+/*
+ * ======== strm_reclaim ========
+ * Purpose:
+ * Request a buffer back from a stream.
+ * Parameters:
+ * stream_obj: Stream handle returned from strm_open().
+ * buf_ptr: Location to store pointer to reclaimed buffer.
+ * nbytes: Location where number of bytes of data in the
+ * buffer will be written.
+ * buff_size: Location where actual buffer size will be written.
+ * pdw_arg: Location where user argument that travels with
+ * the buffer will be written.
+ * Returns:
+ * 0: Success.
+ * -EFAULT: Invalid stream_obj.
+ * -ETIME: A timeout occurred before a buffer could be
+ * retrieved.
+ * -EPERM: Failure occurred, unable to reclaim buffer.
+ * Requires:
+ * strm_init(void) called.
+ * buf_ptr != NULL.
+ * nbytes != NULL.
+ * pdw_arg != NULL.
+ * Ensures:
+ */
+extern int strm_reclaim(struct strm_object *stream_obj,
+ u8 **buf_ptr, u32 * nbytes,
+ u32 *buff_size, u32 *pdw_arg);
+
+/*
+ * ======== strm_register_notify ========
+ * Purpose:
+ * Register to be notified on specific events for this stream.
+ * Parameters:
+ * stream_obj: Stream handle returned by strm_open().
+ * event_mask: Mask of types of events to be notified about.
+ * notify_type: Type of notification to be sent.
+ * hnotification: Handle to be used for notification.
+ * Returns:
+ * 0: Success.
+ * -EFAULT: Invalid stream_obj.
+ * -ENOMEM: Insufficient memory on GPP.
+ * -EINVAL: event_mask is invalid.
+ * -ENOSYS: Notification type specified by notify_type is not
+ * supported.
+ * Requires:
+ * strm_init(void) called.
+ * hnotification != NULL.
+ * Ensures:
+ */
+extern int strm_register_notify(struct strm_object *stream_obj,
+ u32 event_mask, u32 notify_type,
+ struct dsp_notification
+ *hnotification);
+
+/*
+ * ======== strm_select ========
+ * Purpose:
+ * Select a ready stream.
+ * Parameters:
+ * strm_tab: Array of stream handles returned from strm_open().
+ * strms: Number of stream handles in array.
+ * pmask: Location to store mask of ready streams on output.
+ * utimeout: Timeout value (milliseconds).
+ * Returns:
+ * 0: Success.
+ * -EDOM: strms out of range.
+
+ * -EFAULT: Invalid stream handle in array.
+ * -ETIME: A timeout occurred before a stream became ready.
+ * -EPERM: Failure occurred, unable to select a stream.
+ * Requires:
+ * strm_init(void) called.
+ * strm_tab != NULL.
+ * strms > 0.
+ * pmask != NULL.
+ * Ensures:
+ * 0: *pmask != 0 || utimeout == 0.
+ * Error: *pmask == 0.
+ */
+extern int strm_select(struct strm_object **strm_tab,
+ u32 strms, u32 *pmask, u32 utimeout);
+
+/*
+ * ======== strm_unprepare_buffer ========
+ * Purpose:
+ * Unprepare a data buffer that was previously prepared for a stream
+ * with DSPStream_PrepareBuffer(), and that will no longer be used with
+ * the stream.
+ * Parameter:
+ * stream_obj: Stream handle returned from strm_open().
+ * usize: Size (GPP bytes) of the buffer.
+ * pbuffer: Buffer address.
+ * Returns:
+ * 0: Success.
+ * -EFAULT: Invalid stream_obj.
+ * -EPERM: Failure occurred, unable to unprepare buffer.
+ * Requires:
+ * strm_init(void) called.
+ * pbuffer != NULL.
+ * Ensures:
+ */
+extern int strm_unprepare_buffer(struct strm_object *stream_obj,
+ u32 usize, u8 *pbuffer);
+
+#endif /* STRM_ */
diff --git a/drivers/staging/tidspbridge/include/dspbridge/strmdefs.h b/drivers/staging/tidspbridge/include/dspbridge/strmdefs.h
new file mode 100644
index 00000000000..b363f794de3
--- /dev/null
+++ b/drivers/staging/tidspbridge/include/dspbridge/strmdefs.h
@@ -0,0 +1,46 @@
+/*
+ * strmdefs.h
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * Global STRM constants and types.
+ *
+ * Copyright (C) 2005-2006 Texas Instruments, Inc.
+ *
+ * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef STRMDEFS_
+#define STRMDEFS_
+
+#define STRM_MAXEVTNAMELEN 32
+
+struct strm_mgr;
+
+struct strm_object;
+
+struct strm_attr {
+ void *user_event;
+ char *pstr_event_name;
+ void *virt_base; /* Process virtual base address of
+ * mapped SM */
+ u32 ul_virt_size; /* Size of virtual space in bytes */
+ struct dsp_streamattrin *stream_attr_in;
+};
+
+struct stream_info {
+ enum dsp_strmmode strm_mode; /* transport mode of
+ * stream(DMA, ZEROCOPY..) */
+ u32 segment_id; /* Segment strm allocs from. 0 is local mem */
+ void *virt_base; /* " " Stream'process virt base */
+ struct dsp_streaminfo *user_strm; /* User's stream information
+ * returned */
+};
+
+#endif /* STRMDEFS_ */
diff --git a/drivers/staging/tidspbridge/include/dspbridge/sync.h b/drivers/staging/tidspbridge/include/dspbridge/sync.h
new file mode 100644
index 00000000000..e2651e7b1c4
--- /dev/null
+++ b/drivers/staging/tidspbridge/include/dspbridge/sync.h
@@ -0,0 +1,109 @@
+/*
+ * sync.h
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * Provide synchronization services.
+ *
+ * Copyright (C) 2005-2006 Texas Instruments, Inc.
+ *
+ * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef _SYNC_H
+#define _SYNC_H
+
+#include <dspbridge/dbdefs.h>
+
+
+/* Special timeout value indicating an infinite wait: */
+#define SYNC_INFINITE 0xffffffff
+
+/**
+ * struct sync_object - the basic sync_object structure
+ * @comp: use to signal events
+ * @multi_comp: use to signal multiple events.
+ *
+ */
+struct sync_object{
+ struct completion comp;
+ struct completion *multi_comp;
+};
+
+/**
+ * sync_init_event() - set initial state for a sync_event element
+ * @event: event to be initialized.
+ *
+ * Set the initial state for a sync_event element.
+ */
+
+static inline void sync_init_event(struct sync_object *event)
+{
+ init_completion(&event->comp);
+ event->multi_comp = NULL;
+}
+
+/**
+ * sync_reset_event() - reset a sync_event element
+ * @event: event to be reset.
+ *
+ * This function reset to the initial state to @event.
+ */
+
+static inline void sync_reset_event(struct sync_object *event)
+{
+ INIT_COMPLETION(event->comp);
+ event->multi_comp = NULL;
+}
+
+/**
+ * sync_set_event() - set or signal and specified event
+ * @event: Event to be set..
+ *
+ * set the @event, if there is an thread waiting for the event
+ * it will be waken up, this function only wakes one thread.
+ */
+
+void sync_set_event(struct sync_object *event);
+
+/**
+ * sync_wait_on_event() - waits for a event to be set.
+ * @event: events to wait for it.
+ * @timeout timeout on waiting for the evetn.
+ *
+ * This functios will wait until @event is set or until timeout. In case of
+ * success the function will return 0 and
+ * in case of timeout the function will return -ETIME
+ */
+
+static inline int sync_wait_on_event(struct sync_object *event,
+ unsigned timeout)
+{
+ return wait_for_completion_timeout(&event->comp,
+ msecs_to_jiffies(timeout)) ? 0 : -ETIME;
+}
+
+/**
+ * sync_wait_on_multiple_events() - waits for multiple events to be set.
+ * @events: Array of events to wait for them.
+ * @count: number of elements of the array.
+ * @timeout timeout on waiting for the evetns.
+ * @pu_index index of the event set.
+ *
+ * This functios will wait until any of the array element is set or until
+ * timeout. In case of success the function will return 0 and
+ * @pu_index will store the index of the array element set and in case
+ * of timeout the function will return -ETIME.
+ */
+
+int sync_wait_on_multiple_events(struct sync_object **events,
+ unsigned count, unsigned timeout,
+ unsigned *index);
+
+#endif /* _SYNC_H */
diff --git a/drivers/staging/tidspbridge/include/dspbridge/utildefs.h b/drivers/staging/tidspbridge/include/dspbridge/utildefs.h
new file mode 100644
index 00000000000..8fe5414824c
--- /dev/null
+++ b/drivers/staging/tidspbridge/include/dspbridge/utildefs.h
@@ -0,0 +1,39 @@
+/*
+ * utildefs.h
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * Global UTIL constants and types, shared between DSP API and DSPSYS.
+ *
+ * Copyright (C) 2005-2006 Texas Instruments, Inc.
+ *
+ * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef UTILDEFS_
+#define UTILDEFS_
+
+/* constants taken from configmg.h */
+#define UTIL_MAXMEMREGS 9
+#define UTIL_MAXIOPORTS 20
+#define UTIL_MAXIRQS 7
+#define UTIL_MAXDMACHNLS 7
+
+/* misc. constants */
+#define UTIL_MAXARGVS 10
+
+/* Platform specific important info */
+struct util_sysinfo {
+ /* Granularity of page protection; usually 1k or 4k */
+ u32 dw_page_size;
+ u32 dw_allocation_granularity; /* VM granularity, usually 64K */
+ u32 dw_number_of_processors; /* Used as sanity check */
+};
+
+#endif /* UTILDEFS_ */
diff --git a/drivers/staging/tidspbridge/include/dspbridge/uuidutil.h b/drivers/staging/tidspbridge/include/dspbridge/uuidutil.h
new file mode 100644
index 00000000000..9a994753e9b
--- /dev/null
+++ b/drivers/staging/tidspbridge/include/dspbridge/uuidutil.h
@@ -0,0 +1,62 @@
+/*
+ * uuidutil.h
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * This file contains the specification of UUID helper functions.
+ *
+ * Copyright (C) 2005-2006 Texas Instruments, Inc.
+ *
+ * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef UUIDUTIL_
+#define UUIDUTIL_
+
+#define MAXUUIDLEN 37
+
+/*
+ * ======== uuid_uuid_to_string ========
+ * Purpose:
+ * Converts a dsp_uuid to an ANSI string.
+ * Parameters:
+ * uuid_obj: Pointer to a dsp_uuid object.
+ * sz_uuid: Pointer to a buffer to receive a NULL-terminated UUID
+ * string.
+ * size: Maximum size of the sz_uuid string.
+ * Returns:
+ * Requires:
+ * uuid_obj & sz_uuid are non-NULL values.
+ * Ensures:
+ * Lenghth of sz_uuid is less than MAXUUIDLEN.
+ * Details:
+ * UUID string limit currently set at MAXUUIDLEN.
+ */
+void uuid_uuid_to_string(struct dsp_uuid *uuid_obj, char *sz_uuid,
+ s32 size);
+
+/*
+ * ======== uuid_uuid_from_string ========
+ * Purpose:
+ * Converts an ANSI string to a dsp_uuid.
+ * Parameters:
+ * sz_uuid: Pointer to a string that represents a dsp_uuid object.
+ * uuid_obj: Pointer to a dsp_uuid object.
+ * Returns:
+ * Requires:
+ * uuid_obj & sz_uuid are non-NULL values.
+ * Ensures:
+ * Details:
+ * We assume the string representation of a UUID has the following format:
+ * "12345678_1234_1234_1234_123456789abc".
+ */
+extern void uuid_uuid_from_string(char *sz_uuid,
+ struct dsp_uuid *uuid_obj);
+
+#endif /* UUIDUTIL_ */
diff --git a/drivers/staging/tidspbridge/include/dspbridge/wdt.h b/drivers/staging/tidspbridge/include/dspbridge/wdt.h
new file mode 100644
index 00000000000..4c00ba5fa5b
--- /dev/null
+++ b/drivers/staging/tidspbridge/include/dspbridge/wdt.h
@@ -0,0 +1,79 @@
+/*
+ * wdt.h
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * IO dispatcher for a shared memory channel driver.
+ *
+ * Copyright (C) 2010 Texas Instruments, Inc.
+ *
+ * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+#ifndef __DSP_WDT3_H_
+#define __DSP_WDT3_H_
+
+/* WDT defines */
+#define OMAP3_WDT3_ISR_OFFSET 0x0018
+
+
+/**
+ * struct dsp_wdt_setting - the basic dsp_wdt_setting structure
+ * @reg_base: pointer to the base of the wdt registers
+ * @sm_wdt: pointer to flags in shared memory
+ * @wdt3_tasklet tasklet to manage wdt event
+ * @fclk handle to wdt3 functional clock
+ * @iclk handle to wdt3 interface clock
+ *
+ * This struct is used in the function to manage wdt3.
+ */
+
+struct dsp_wdt_setting {
+ void __iomem *reg_base;
+ struct shm *sm_wdt;
+ struct tasklet_struct wdt3_tasklet;
+ struct clk *fclk;
+ struct clk *iclk;
+};
+
+/**
+ * dsp_wdt_init() - initialize wdt3 module.
+ *
+ * This function initilize to wdt3 module, so that
+ * other wdt3 function can be used.
+ */
+int dsp_wdt_init(void);
+
+/**
+ * dsp_wdt_exit() - initialize wdt3 module.
+ *
+ * This function frees all resources allocated for wdt3 module.
+ */
+void dsp_wdt_exit(void);
+
+/**
+ * dsp_wdt_enable() - enable/disable wdt3
+ * @enable: bool value to enable/disable wdt3
+ *
+ * This function enables or disables wdt3 base on @enable value.
+ *
+ */
+void dsp_wdt_enable(bool enable);
+
+/**
+ * dsp_wdt_sm_set() - store pointer to the share memory
+ * @data: pointer to dspbridge share memory
+ *
+ * This function is used to pass a valid pointer to share memory,
+ * so that the flags can be set in order DSP side can read them.
+ *
+ */
+void dsp_wdt_sm_set(void *data);
+
+#endif
+
diff --git a/drivers/staging/tidspbridge/pmgr/chnl.c b/drivers/staging/tidspbridge/pmgr/chnl.c
new file mode 100644
index 00000000000..90317b58f8e
--- /dev/null
+++ b/drivers/staging/tidspbridge/pmgr/chnl.c
@@ -0,0 +1,163 @@
+/*
+ * chnl.c
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * DSP API channel interface: multiplexes data streams through the single
+ * physical link managed by a Bridge Bridge driver.
+ *
+ * Copyright (C) 2005-2006 Texas Instruments, Inc.
+ *
+ * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include <linux/types.h>
+/* ----------------------------------- Host OS */
+#include <dspbridge/host_os.h>
+
+/* ----------------------------------- DSP/BIOS Bridge */
+#include <dspbridge/dbdefs.h>
+
+/* ----------------------------------- Trace & Debug */
+#include <dspbridge/dbc.h>
+
+/* ----------------------------------- OS Adaptation Layer */
+#include <dspbridge/cfg.h>
+#include <dspbridge/sync.h>
+
+/* ----------------------------------- Platform Manager */
+#include <dspbridge/proc.h>
+#include <dspbridge/dev.h>
+
+/* ----------------------------------- Others */
+#include <dspbridge/chnlpriv.h>
+#include <chnlobj.h>
+
+/* ----------------------------------- This */
+#include <dspbridge/chnl.h>
+
+/* ----------------------------------- Globals */
+static u32 refs;
+
+/*
+ * ======== chnl_create ========
+ * Purpose:
+ * Create a channel manager object, responsible for opening new channels
+ * and closing old ones for a given 'Bridge board.
+ */
+int chnl_create(struct chnl_mgr **channel_mgr,
+ struct dev_object *hdev_obj,
+ const struct chnl_mgrattrs *mgr_attrts)
+{
+ int status;
+ struct chnl_mgr *hchnl_mgr;
+ struct chnl_mgr_ *chnl_mgr_obj = NULL;
+
+ DBC_REQUIRE(refs > 0);
+ DBC_REQUIRE(channel_mgr != NULL);
+ DBC_REQUIRE(mgr_attrts != NULL);
+
+ *channel_mgr = NULL;
+
+ /* Validate args: */
+ if ((0 < mgr_attrts->max_channels) &&
+ (mgr_attrts->max_channels <= CHNL_MAXCHANNELS))
+ status = 0;
+ else if (mgr_attrts->max_channels == 0)
+ status = -EINVAL;
+ else
+ status = -ECHRNG;
+
+ if (mgr_attrts->word_size == 0)
+ status = -EINVAL;
+
+ if (!status) {
+ status = dev_get_chnl_mgr(hdev_obj, &hchnl_mgr);
+ if (!status && hchnl_mgr != NULL)
+ status = -EEXIST;
+
+ }
+
+ if (!status) {
+ struct bridge_drv_interface *intf_fxns;
+ dev_get_intf_fxns(hdev_obj, &intf_fxns);
+ /* Let Bridge channel module finish the create: */
+ status = (*intf_fxns->pfn_chnl_create) (&hchnl_mgr, hdev_obj,
+ mgr_attrts);
+ if (!status) {
+ /* Fill in DSP API channel module's fields of the
+ * chnl_mgr structure */
+ chnl_mgr_obj = (struct chnl_mgr_ *)hchnl_mgr;
+ chnl_mgr_obj->intf_fxns = intf_fxns;
+ /* Finally, return the new channel manager handle: */
+ *channel_mgr = hchnl_mgr;
+ }
+ }
+
+ DBC_ENSURE(status || chnl_mgr_obj);
+
+ return status;
+}
+
+/*
+ * ======== chnl_destroy ========
+ * Purpose:
+ * Close all open channels, and destroy the channel manager.
+ */
+int chnl_destroy(struct chnl_mgr *hchnl_mgr)
+{
+ struct chnl_mgr_ *chnl_mgr_obj = (struct chnl_mgr_ *)hchnl_mgr;
+ struct bridge_drv_interface *intf_fxns;
+ int status;
+
+ DBC_REQUIRE(refs > 0);
+
+ if (chnl_mgr_obj) {
+ intf_fxns = chnl_mgr_obj->intf_fxns;
+ /* Let Bridge channel module destroy the chnl_mgr: */
+ status = (*intf_fxns->pfn_chnl_destroy) (hchnl_mgr);
+ } else {
+ status = -EFAULT;
+ }
+
+ return status;
+}
+
+/*
+ * ======== chnl_exit ========
+ * Purpose:
+ * Discontinue usage of the CHNL module.
+ */
+void chnl_exit(void)
+{
+ DBC_REQUIRE(refs > 0);
+
+ refs--;
+
+ DBC_ENSURE(refs >= 0);
+}
+
+/*
+ * ======== chnl_init ========
+ * Purpose:
+ * Initialize the CHNL module's private state.
+ */
+bool chnl_init(void)
+{
+ bool ret = true;
+
+ DBC_REQUIRE(refs >= 0);
+
+ if (ret)
+ refs++;
+
+ DBC_ENSURE((ret && (refs > 0)) || (!ret && (refs >= 0)));
+
+ return ret;
+}
diff --git a/drivers/staging/tidspbridge/pmgr/chnlobj.h b/drivers/staging/tidspbridge/pmgr/chnlobj.h
new file mode 100644
index 00000000000..6795e0aa8fd
--- /dev/null
+++ b/drivers/staging/tidspbridge/pmgr/chnlobj.h
@@ -0,0 +1,46 @@
+/*
+ * chnlobj.h
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * Structure subcomponents of channel class library channel objects which
+ * are exposed to DSP API from Bridge driver.
+ *
+ * Copyright (C) 2005-2006 Texas Instruments, Inc.
+ *
+ * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef CHNLOBJ_
+#define CHNLOBJ_
+
+#include <dspbridge/chnldefs.h>
+#include <dspbridge/dspdefs.h>
+
+/*
+ * This struct is the first field in a chnl_mgr struct. Other. implementation
+ * specific fields follow this structure in memory.
+ */
+struct chnl_mgr_ {
+ /* These must be the first fields in a chnl_mgr struct: */
+
+ /* Function interface to Bridge driver. */
+ struct bridge_drv_interface *intf_fxns;
+};
+
+/*
+ * This struct is the first field in a chnl_object struct. Other,
+ * implementation specific fields follow this structure in memory.
+ */
+struct chnl_object_ {
+ /* These must be the first fields in a chnl_object struct: */
+ struct chnl_mgr_ *chnl_mgr_obj; /* Pointer back to channel manager. */
+};
+
+#endif /* CHNLOBJ_ */
diff --git a/drivers/staging/tidspbridge/pmgr/cmm.c b/drivers/staging/tidspbridge/pmgr/cmm.c
new file mode 100644
index 00000000000..ce3dc8822af
--- /dev/null
+++ b/drivers/staging/tidspbridge/pmgr/cmm.c
@@ -0,0 +1,1154 @@
+/*
+ * cmm.c
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * The Communication(Shared) Memory Management(CMM) module provides
+ * shared memory management services for DSP/BIOS Bridge data streaming
+ * and messaging.
+ *
+ * Multiple shared memory segments can be registered with CMM.
+ * Each registered SM segment is represented by a SM "allocator" that
+ * describes a block of physically contiguous shared memory used for
+ * future allocations by CMM.
+ *
+ * Memory is coelesced back to the appropriate heap when a buffer is
+ * freed.
+ *
+ * Notes:
+ * Va: Virtual address.
+ * Pa: Physical or kernel system address.
+ *
+ * Copyright (C) 2005-2006 Texas Instruments, Inc.
+ *
+ * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+#include <linux/types.h>
+
+/* ----------------------------------- DSP/BIOS Bridge */
+#include <dspbridge/dbdefs.h>
+
+/* ----------------------------------- Trace & Debug */
+#include <dspbridge/dbc.h>
+
+/* ----------------------------------- OS Adaptation Layer */
+#include <dspbridge/cfg.h>
+#include <dspbridge/list.h>
+#include <dspbridge/sync.h>
+#include <dspbridge/utildefs.h>
+
+/* ----------------------------------- Platform Manager */
+#include <dspbridge/dev.h>
+#include <dspbridge/proc.h>
+
+/* ----------------------------------- This */
+#include <dspbridge/cmm.h>
+
+/* ----------------------------------- Defines, Data Structures, Typedefs */
+#define NEXT_PA(pnode) (pnode->dw_pa + pnode->ul_size)
+
+/* Other bus/platform translations */
+#define DSPPA2GPPPA(base, x, y) ((x)+(y))
+#define GPPPA2DSPPA(base, x, y) ((x)-(y))
+
+/*
+ * Allocators define a block of contiguous memory used for future allocations.
+ *
+ * sma - shared memory allocator.
+ * vma - virtual memory allocator.(not used).
+ */
+struct cmm_allocator { /* sma */
+ unsigned int shm_base; /* Start of physical SM block */
+ u32 ul_sm_size; /* Size of SM block in bytes */
+ unsigned int dw_vm_base; /* Start of VM block. (Dev driver
+ * context for 'sma') */
+ u32 dw_dsp_phys_addr_offset; /* DSP PA to GPP PA offset for this
+ * SM space */
+ s8 c_factor; /* DSPPa to GPPPa Conversion Factor */
+ unsigned int dw_dsp_base; /* DSP virt base byte address */
+ u32 ul_dsp_size; /* DSP seg size in bytes */
+ struct cmm_object *hcmm_mgr; /* back ref to parent mgr */
+ /* node list of available memory */
+ struct lst_list *free_list_head;
+ /* node list of memory in use */
+ struct lst_list *in_use_list_head;
+};
+
+struct cmm_xlator { /* Pa<->Va translator object */
+ /* CMM object this translator associated */
+ struct cmm_object *hcmm_mgr;
+ /*
+ * Client process virtual base address that corresponds to phys SM
+ * base address for translator's ul_seg_id.
+ * Only 1 segment ID currently supported.
+ */
+ unsigned int dw_virt_base; /* virtual base address */
+ u32 ul_virt_size; /* size of virt space in bytes */
+ u32 ul_seg_id; /* Segment Id */
+};
+
+/* CMM Mgr */
+struct cmm_object {
+ /*
+ * Cmm Lock is used to serialize access mem manager for multi-threads.
+ */
+ struct mutex cmm_lock; /* Lock to access cmm mgr */
+ struct lst_list *node_free_list_head; /* Free list of memory nodes */
+ u32 ul_min_block_size; /* Min SM block; default 16 bytes */
+ u32 dw_page_size; /* Memory Page size (1k/4k) */
+ /* GPP SM segment ptrs */
+ struct cmm_allocator *pa_gppsm_seg_tab[CMM_MAXGPPSEGS];
+};
+
+/* Default CMM Mgr attributes */
+static struct cmm_mgrattrs cmm_dfltmgrattrs = {
+ /* ul_min_block_size, min block size(bytes) allocated by cmm mgr */
+ 16
+};
+
+/* Default allocation attributes */
+static struct cmm_attrs cmm_dfltalctattrs = {
+ 1 /* ul_seg_id, default segment Id for allocator */
+};
+
+/* Address translator default attrs */
+static struct cmm_xlatorattrs cmm_dfltxlatorattrs = {
+ /* ul_seg_id, does not have to match cmm_dfltalctattrs ul_seg_id */
+ 1,
+ 0, /* dw_dsp_bufs */
+ 0, /* dw_dsp_buf_size */
+ NULL, /* vm_base */
+ 0, /* dw_vm_size */
+};
+
+/* SM node representing a block of memory. */
+struct cmm_mnode {
+ struct list_head link; /* must be 1st element */
+ u32 dw_pa; /* Phys addr */
+ u32 dw_va; /* Virtual address in device process context */
+ u32 ul_size; /* SM block size in bytes */
+ u32 client_proc; /* Process that allocated this mem block */
+};
+
+/* ----------------------------------- Globals */
+static u32 refs; /* module reference count */
+
+/* ----------------------------------- Function Prototypes */
+static void add_to_free_list(struct cmm_allocator *allocator,
+ struct cmm_mnode *pnode);
+static struct cmm_allocator *get_allocator(struct cmm_object *cmm_mgr_obj,
+ u32 ul_seg_id);
+static struct cmm_mnode *get_free_block(struct cmm_allocator *allocator,
+ u32 usize);
+static struct cmm_mnode *get_node(struct cmm_object *cmm_mgr_obj, u32 dw_pa,
+ u32 dw_va, u32 ul_size);
+/* get available slot for new allocator */
+static s32 get_slot(struct cmm_object *cmm_mgr_obj);
+static void un_register_gppsm_seg(struct cmm_allocator *psma);
+
+/*
+ * ======== cmm_calloc_buf ========
+ * Purpose:
+ * Allocate a SM buffer, zero contents, and return the physical address
+ * and optional driver context virtual address(pp_buf_va).
+ *
+ * The freelist is sorted in increasing size order. Get the first
+ * block that satifies the request and sort the remaining back on
+ * the freelist; if large enough. The kept block is placed on the
+ * inUseList.
+ */
+void *cmm_calloc_buf(struct cmm_object *hcmm_mgr, u32 usize,
+ struct cmm_attrs *pattrs, void **pp_buf_va)
+{
+ struct cmm_object *cmm_mgr_obj = (struct cmm_object *)hcmm_mgr;
+ void *buf_pa = NULL;
+ struct cmm_mnode *pnode = NULL;
+ struct cmm_mnode *new_node = NULL;
+ struct cmm_allocator *allocator = NULL;
+ u32 delta_size;
+ u8 *pbyte = NULL;
+ s32 cnt;
+
+ if (pattrs == NULL)
+ pattrs = &cmm_dfltalctattrs;
+
+ if (pp_buf_va != NULL)
+ *pp_buf_va = NULL;
+
+ if (cmm_mgr_obj && (usize != 0)) {
+ if (pattrs->ul_seg_id > 0) {
+ /* SegId > 0 is SM */
+ /* get the allocator object for this segment id */
+ allocator =
+ get_allocator(cmm_mgr_obj, pattrs->ul_seg_id);
+ /* keep block size a multiple of ul_min_block_size */
+ usize =
+ ((usize - 1) & ~(cmm_mgr_obj->ul_min_block_size -
+ 1))
+ + cmm_mgr_obj->ul_min_block_size;
+ mutex_lock(&cmm_mgr_obj->cmm_lock);
+ pnode = get_free_block(allocator, usize);
+ }
+ if (pnode) {
+ delta_size = (pnode->ul_size - usize);
+ if (delta_size >= cmm_mgr_obj->ul_min_block_size) {
+ /* create a new block with the leftovers and
+ * add to freelist */
+ new_node =
+ get_node(cmm_mgr_obj, pnode->dw_pa + usize,
+ pnode->dw_va + usize,
+ (u32) delta_size);
+ /* leftovers go free */
+ add_to_free_list(allocator, new_node);
+ /* adjust our node's size */
+ pnode->ul_size = usize;
+ }
+ /* Tag node with client process requesting allocation
+ * We'll need to free up a process's alloc'd SM if the
+ * client process goes away.
+ */
+ /* Return TGID instead of process handle */
+ pnode->client_proc = current->tgid;
+
+ /* put our node on InUse list */
+ lst_put_tail(allocator->in_use_list_head,
+ (struct list_head *)pnode);
+ buf_pa = (void *)pnode->dw_pa; /* physical address */
+ /* clear mem */
+ pbyte = (u8 *) pnode->dw_va;
+ for (cnt = 0; cnt < (s32) usize; cnt++, pbyte++)
+ *pbyte = 0;
+
+ if (pp_buf_va != NULL) {
+ /* Virtual address */
+ *pp_buf_va = (void *)pnode->dw_va;
+ }
+ }
+ mutex_unlock(&cmm_mgr_obj->cmm_lock);
+ }
+ return buf_pa;
+}
+
+/*
+ * ======== cmm_create ========
+ * Purpose:
+ * Create a communication memory manager object.
+ */
+int cmm_create(struct cmm_object **ph_cmm_mgr,
+ struct dev_object *hdev_obj,
+ const struct cmm_mgrattrs *mgr_attrts)
+{
+ struct cmm_object *cmm_obj = NULL;
+ int status = 0;
+ struct util_sysinfo sys_info;
+
+ DBC_REQUIRE(refs > 0);
+ DBC_REQUIRE(ph_cmm_mgr != NULL);
+
+ *ph_cmm_mgr = NULL;
+ /* create, zero, and tag a cmm mgr object */
+ cmm_obj = kzalloc(sizeof(struct cmm_object), GFP_KERNEL);
+ if (cmm_obj != NULL) {
+ if (mgr_attrts == NULL)
+ mgr_attrts = &cmm_dfltmgrattrs; /* set defaults */
+
+ /* 4 bytes minimum */
+ DBC_ASSERT(mgr_attrts->ul_min_block_size >= 4);
+ /* save away smallest block allocation for this cmm mgr */
+ cmm_obj->ul_min_block_size = mgr_attrts->ul_min_block_size;
+ /* save away the systems memory page size */
+ sys_info.dw_page_size = PAGE_SIZE;
+ sys_info.dw_allocation_granularity = PAGE_SIZE;
+ sys_info.dw_number_of_processors = 1;
+
+ cmm_obj->dw_page_size = sys_info.dw_page_size;
+
+ /* Note: DSP SM seg table(aDSPSMSegTab[]) zero'd by
+ * MEM_ALLOC_OBJECT */
+
+ /* create node free list */
+ cmm_obj->node_free_list_head =
+ kzalloc(sizeof(struct lst_list),
+ GFP_KERNEL);
+ if (cmm_obj->node_free_list_head == NULL) {
+ status = -ENOMEM;
+ cmm_destroy(cmm_obj, true);
+ } else {
+ INIT_LIST_HEAD(&cmm_obj->
+ node_free_list_head->head);
+ mutex_init(&cmm_obj->cmm_lock);
+ *ph_cmm_mgr = cmm_obj;
+ }
+ } else {
+ status = -ENOMEM;
+ }
+ return status;
+}
+
+/*
+ * ======== cmm_destroy ========
+ * Purpose:
+ * Release the communication memory manager resources.
+ */
+int cmm_destroy(struct cmm_object *hcmm_mgr, bool force)
+{
+ struct cmm_object *cmm_mgr_obj = (struct cmm_object *)hcmm_mgr;
+ struct cmm_info temp_info;
+ int status = 0;
+ s32 slot_seg;
+ struct cmm_mnode *pnode;
+
+ DBC_REQUIRE(refs > 0);
+ if (!hcmm_mgr) {
+ status = -EFAULT;
+ return status;
+ }
+ mutex_lock(&cmm_mgr_obj->cmm_lock);
+ /* If not force then fail if outstanding allocations exist */
+ if (!force) {
+ /* Check for outstanding memory allocations */
+ status = cmm_get_info(hcmm_mgr, &temp_info);
+ if (!status) {
+ if (temp_info.ul_total_in_use_cnt > 0) {
+ /* outstanding allocations */
+ status = -EPERM;
+ }
+ }
+ }
+ if (!status) {
+ /* UnRegister SM allocator */
+ for (slot_seg = 0; slot_seg < CMM_MAXGPPSEGS; slot_seg++) {
+ if (cmm_mgr_obj->pa_gppsm_seg_tab[slot_seg] != NULL) {
+ un_register_gppsm_seg
+ (cmm_mgr_obj->pa_gppsm_seg_tab[slot_seg]);
+ /* Set slot to NULL for future reuse */
+ cmm_mgr_obj->pa_gppsm_seg_tab[slot_seg] = NULL;
+ }
+ }
+ }
+ if (cmm_mgr_obj->node_free_list_head != NULL) {
+ /* Free the free nodes */
+ while (!LST_IS_EMPTY(cmm_mgr_obj->node_free_list_head)) {
+ pnode = (struct cmm_mnode *)
+ lst_get_head(cmm_mgr_obj->node_free_list_head);
+ kfree(pnode);
+ }
+ /* delete NodeFreeList list */
+ kfree(cmm_mgr_obj->node_free_list_head);
+ }
+ mutex_unlock(&cmm_mgr_obj->cmm_lock);
+ if (!status) {
+ /* delete CS & cmm mgr object */
+ mutex_destroy(&cmm_mgr_obj->cmm_lock);
+ kfree(cmm_mgr_obj);
+ }
+ return status;
+}
+
+/*
+ * ======== cmm_exit ========
+ * Purpose:
+ * Discontinue usage of module; free resources when reference count
+ * reaches 0.
+ */
+void cmm_exit(void)
+{
+ DBC_REQUIRE(refs > 0);
+
+ refs--;
+}
+
+/*
+ * ======== cmm_free_buf ========
+ * Purpose:
+ * Free the given buffer.
+ */
+int cmm_free_buf(struct cmm_object *hcmm_mgr, void *buf_pa,
+ u32 ul_seg_id)
+{
+ struct cmm_object *cmm_mgr_obj = (struct cmm_object *)hcmm_mgr;
+ int status = -EFAULT;
+ struct cmm_mnode *mnode_obj = NULL;
+ struct cmm_allocator *allocator = NULL;
+ struct cmm_attrs *pattrs;
+
+ DBC_REQUIRE(refs > 0);
+ DBC_REQUIRE(buf_pa != NULL);
+
+ if (ul_seg_id == 0) {
+ pattrs = &cmm_dfltalctattrs;
+ ul_seg_id = pattrs->ul_seg_id;
+ }
+ if (!hcmm_mgr || !(ul_seg_id > 0)) {
+ status = -EFAULT;
+ return status;
+ }
+ /* get the allocator for this segment id */
+ allocator = get_allocator(cmm_mgr_obj, ul_seg_id);
+ if (allocator != NULL) {
+ mutex_lock(&cmm_mgr_obj->cmm_lock);
+ mnode_obj =
+ (struct cmm_mnode *)lst_first(allocator->in_use_list_head);
+ while (mnode_obj) {
+ if ((u32) buf_pa == mnode_obj->dw_pa) {
+ /* Found it */
+ lst_remove_elem(allocator->in_use_list_head,
+ (struct list_head *)mnode_obj);
+ /* back to freelist */
+ add_to_free_list(allocator, mnode_obj);
+ status = 0; /* all right! */
+ break;
+ }
+ /* next node. */
+ mnode_obj = (struct cmm_mnode *)
+ lst_next(allocator->in_use_list_head,
+ (struct list_head *)mnode_obj);
+ }
+ mutex_unlock(&cmm_mgr_obj->cmm_lock);
+ }
+ return status;
+}
+
+/*
+ * ======== cmm_get_handle ========
+ * Purpose:
+ * Return the communication memory manager object for this device.
+ * This is typically called from the client process.
+ */
+int cmm_get_handle(void *hprocessor, struct cmm_object ** ph_cmm_mgr)
+{
+ int status = 0;
+ struct dev_object *hdev_obj;
+
+ DBC_REQUIRE(refs > 0);
+ DBC_REQUIRE(ph_cmm_mgr != NULL);
+ if (hprocessor != NULL)
+ status = proc_get_dev_object(hprocessor, &hdev_obj);
+ else
+ hdev_obj = dev_get_first(); /* default */
+
+ if (!status)
+ status = dev_get_cmm_mgr(hdev_obj, ph_cmm_mgr);
+
+ return status;
+}
+
+/*
+ * ======== cmm_get_info ========
+ * Purpose:
+ * Return the current memory utilization information.
+ */
+int cmm_get_info(struct cmm_object *hcmm_mgr,
+ struct cmm_info *cmm_info_obj)
+{
+ struct cmm_object *cmm_mgr_obj = (struct cmm_object *)hcmm_mgr;
+ u32 ul_seg;
+ int status = 0;
+ struct cmm_allocator *altr;
+ struct cmm_mnode *mnode_obj = NULL;
+
+ DBC_REQUIRE(cmm_info_obj != NULL);
+
+ if (!hcmm_mgr) {
+ status = -EFAULT;
+ return status;
+ }
+ mutex_lock(&cmm_mgr_obj->cmm_lock);
+ cmm_info_obj->ul_num_gppsm_segs = 0; /* # of SM segments */
+ /* Total # of outstanding alloc */
+ cmm_info_obj->ul_total_in_use_cnt = 0;
+ /* min block size */
+ cmm_info_obj->ul_min_block_size = cmm_mgr_obj->ul_min_block_size;
+ /* check SM memory segments */
+ for (ul_seg = 1; ul_seg <= CMM_MAXGPPSEGS; ul_seg++) {
+ /* get the allocator object for this segment id */
+ altr = get_allocator(cmm_mgr_obj, ul_seg);
+ if (altr != NULL) {
+ cmm_info_obj->ul_num_gppsm_segs++;
+ cmm_info_obj->seg_info[ul_seg - 1].dw_seg_base_pa =
+ altr->shm_base - altr->ul_dsp_size;
+ cmm_info_obj->seg_info[ul_seg - 1].ul_total_seg_size =
+ altr->ul_dsp_size + altr->ul_sm_size;
+ cmm_info_obj->seg_info[ul_seg - 1].dw_gpp_base_pa =
+ altr->shm_base;
+ cmm_info_obj->seg_info[ul_seg - 1].ul_gpp_size =
+ altr->ul_sm_size;
+ cmm_info_obj->seg_info[ul_seg - 1].dw_dsp_base_va =
+ altr->dw_dsp_base;
+ cmm_info_obj->seg_info[ul_seg - 1].ul_dsp_size =
+ altr->ul_dsp_size;
+ cmm_info_obj->seg_info[ul_seg - 1].dw_seg_base_va =
+ altr->dw_vm_base - altr->ul_dsp_size;
+ cmm_info_obj->seg_info[ul_seg - 1].ul_in_use_cnt = 0;
+ mnode_obj = (struct cmm_mnode *)
+ lst_first(altr->in_use_list_head);
+ /* Count inUse blocks */
+ while (mnode_obj) {
+ cmm_info_obj->ul_total_in_use_cnt++;
+ cmm_info_obj->seg_info[ul_seg -
+ 1].ul_in_use_cnt++;
+ /* next node. */
+ mnode_obj = (struct cmm_mnode *)
+ lst_next(altr->in_use_list_head,
+ (struct list_head *)mnode_obj);
+ }
+ }
+ } /* end for */
+ mutex_unlock(&cmm_mgr_obj->cmm_lock);
+ return status;
+}
+
+/*
+ * ======== cmm_init ========
+ * Purpose:
+ * Initializes private state of CMM module.
+ */
+bool cmm_init(void)
+{
+ bool ret = true;
+
+ DBC_REQUIRE(refs >= 0);
+ if (ret)
+ refs++;
+
+ DBC_ENSURE((ret && (refs > 0)) || (!ret && (refs >= 0)));
+
+ return ret;
+}
+
+/*
+ * ======== cmm_register_gppsm_seg ========
+ * Purpose:
+ * Register a block of SM with the CMM to be used for later GPP SM
+ * allocations.
+ */
+int cmm_register_gppsm_seg(struct cmm_object *hcmm_mgr,
+ u32 dw_gpp_base_pa, u32 ul_size,
+ u32 dsp_addr_offset, s8 c_factor,
+ u32 dw_dsp_base, u32 ul_dsp_size,
+ u32 *sgmt_id, u32 gpp_base_va)
+{
+ struct cmm_object *cmm_mgr_obj = (struct cmm_object *)hcmm_mgr;
+ struct cmm_allocator *psma = NULL;
+ int status = 0;
+ struct cmm_mnode *new_node;
+ s32 slot_seg;
+
+ DBC_REQUIRE(ul_size > 0);
+ DBC_REQUIRE(sgmt_id != NULL);
+ DBC_REQUIRE(dw_gpp_base_pa != 0);
+ DBC_REQUIRE(gpp_base_va != 0);
+ DBC_REQUIRE((c_factor <= CMM_ADDTODSPPA) &&
+ (c_factor >= CMM_SUBFROMDSPPA));
+ dev_dbg(bridge, "%s: dw_gpp_base_pa %x ul_size %x dsp_addr_offset %x "
+ "dw_dsp_base %x ul_dsp_size %x gpp_base_va %x\n", __func__,
+ dw_gpp_base_pa, ul_size, dsp_addr_offset, dw_dsp_base,
+ ul_dsp_size, gpp_base_va);
+ if (!hcmm_mgr) {
+ status = -EFAULT;
+ return status;
+ }
+ /* make sure we have room for another allocator */
+ mutex_lock(&cmm_mgr_obj->cmm_lock);
+ slot_seg = get_slot(cmm_mgr_obj);
+ if (slot_seg < 0) {
+ /* get a slot number */
+ status = -EPERM;
+ goto func_end;
+ }
+ /* Check if input ul_size is big enough to alloc at least one block */
+ if (ul_size < cmm_mgr_obj->ul_min_block_size) {
+ status = -EINVAL;
+ goto func_end;
+ }
+
+ /* create, zero, and tag an SM allocator object */
+ psma = kzalloc(sizeof(struct cmm_allocator), GFP_KERNEL);
+ if (psma != NULL) {
+ psma->hcmm_mgr = hcmm_mgr; /* ref to parent */
+ psma->shm_base = dw_gpp_base_pa; /* SM Base phys */
+ psma->ul_sm_size = ul_size; /* SM segment size in bytes */
+ psma->dw_vm_base = gpp_base_va;
+ psma->dw_dsp_phys_addr_offset = dsp_addr_offset;
+ psma->c_factor = c_factor;
+ psma->dw_dsp_base = dw_dsp_base;
+ psma->ul_dsp_size = ul_dsp_size;
+ if (psma->dw_vm_base == 0) {
+ status = -EPERM;
+ goto func_end;
+ }
+ /* return the actual segment identifier */
+ *sgmt_id = (u32) slot_seg + 1;
+ /* create memory free list */
+ psma->free_list_head = kzalloc(sizeof(struct lst_list),
+ GFP_KERNEL);
+ if (psma->free_list_head == NULL) {
+ status = -ENOMEM;
+ goto func_end;
+ }
+ INIT_LIST_HEAD(&psma->free_list_head->head);
+
+ /* create memory in-use list */
+ psma->in_use_list_head = kzalloc(sizeof(struct
+ lst_list), GFP_KERNEL);
+ if (psma->in_use_list_head == NULL) {
+ status = -ENOMEM;
+ goto func_end;
+ }
+ INIT_LIST_HEAD(&psma->in_use_list_head->head);
+
+ /* Get a mem node for this hunk-o-memory */
+ new_node = get_node(cmm_mgr_obj, dw_gpp_base_pa,
+ psma->dw_vm_base, ul_size);
+ /* Place node on the SM allocator's free list */
+ if (new_node) {
+ lst_put_tail(psma->free_list_head,
+ (struct list_head *)new_node);
+ } else {
+ status = -ENOMEM;
+ goto func_end;
+ }
+ } else {
+ status = -ENOMEM;
+ goto func_end;
+ }
+ /* make entry */
+ cmm_mgr_obj->pa_gppsm_seg_tab[slot_seg] = psma;
+
+func_end:
+ if (status && psma) {
+ /* Cleanup allocator */
+ un_register_gppsm_seg(psma);
+ }
+
+ mutex_unlock(&cmm_mgr_obj->cmm_lock);
+ return status;
+}
+
+/*
+ * ======== cmm_un_register_gppsm_seg ========
+ * Purpose:
+ * UnRegister GPP SM segments with the CMM.
+ */
+int cmm_un_register_gppsm_seg(struct cmm_object *hcmm_mgr,
+ u32 ul_seg_id)
+{
+ struct cmm_object *cmm_mgr_obj = (struct cmm_object *)hcmm_mgr;
+ int status = 0;
+ struct cmm_allocator *psma;
+ u32 ul_id = ul_seg_id;
+
+ DBC_REQUIRE(ul_seg_id > 0);
+ if (hcmm_mgr) {
+ if (ul_seg_id == CMM_ALLSEGMENTS)
+ ul_id = 1;
+
+ if ((ul_id > 0) && (ul_id <= CMM_MAXGPPSEGS)) {
+ while (ul_id <= CMM_MAXGPPSEGS) {
+ mutex_lock(&cmm_mgr_obj->cmm_lock);
+ /* slot = seg_id-1 */
+ psma = cmm_mgr_obj->pa_gppsm_seg_tab[ul_id - 1];
+ if (psma != NULL) {
+ un_register_gppsm_seg(psma);
+ /* Set alctr ptr to NULL for future
+ * reuse */
+ cmm_mgr_obj->pa_gppsm_seg_tab[ul_id -
+ 1] = NULL;
+ } else if (ul_seg_id != CMM_ALLSEGMENTS) {
+ status = -EPERM;
+ }
+ mutex_unlock(&cmm_mgr_obj->cmm_lock);
+ if (ul_seg_id != CMM_ALLSEGMENTS)
+ break;
+
+ ul_id++;
+ } /* end while */
+ } else {
+ status = -EINVAL;
+ }
+ } else {
+ status = -EFAULT;
+ }
+ return status;
+}
+
+/*
+ * ======== un_register_gppsm_seg ========
+ * Purpose:
+ * UnRegister the SM allocator by freeing all its resources and
+ * nulling cmm mgr table entry.
+ * Note:
+ * This routine is always called within cmm lock crit sect.
+ */
+static void un_register_gppsm_seg(struct cmm_allocator *psma)
+{
+ struct cmm_mnode *mnode_obj = NULL;
+ struct cmm_mnode *next_node = NULL;
+
+ DBC_REQUIRE(psma != NULL);
+ if (psma->free_list_head != NULL) {
+ /* free nodes on free list */
+ mnode_obj = (struct cmm_mnode *)lst_first(psma->free_list_head);
+ while (mnode_obj) {
+ next_node =
+ (struct cmm_mnode *)lst_next(psma->free_list_head,
+ (struct list_head *)
+ mnode_obj);
+ lst_remove_elem(psma->free_list_head,
+ (struct list_head *)mnode_obj);
+ kfree((void *)mnode_obj);
+ /* next node. */
+ mnode_obj = next_node;
+ }
+ kfree(psma->free_list_head); /* delete freelist */
+ /* free nodes on InUse list */
+ mnode_obj =
+ (struct cmm_mnode *)lst_first(psma->in_use_list_head);
+ while (mnode_obj) {
+ next_node =
+ (struct cmm_mnode *)lst_next(psma->in_use_list_head,
+ (struct list_head *)
+ mnode_obj);
+ lst_remove_elem(psma->in_use_list_head,
+ (struct list_head *)mnode_obj);
+ kfree((void *)mnode_obj);
+ /* next node. */
+ mnode_obj = next_node;
+ }
+ kfree(psma->in_use_list_head); /* delete InUse list */
+ }
+ if ((void *)psma->dw_vm_base != NULL)
+ MEM_UNMAP_LINEAR_ADDRESS((void *)psma->dw_vm_base);
+
+ /* Free allocator itself */
+ kfree(psma);
+}
+
+/*
+ * ======== get_slot ========
+ * Purpose:
+ * An available slot # is returned. Returns negative on failure.
+ */
+static s32 get_slot(struct cmm_object *cmm_mgr_obj)
+{
+ s32 slot_seg = -1; /* neg on failure */
+ DBC_REQUIRE(cmm_mgr_obj != NULL);
+ /* get first available slot in cmm mgr SMSegTab[] */
+ for (slot_seg = 0; slot_seg < CMM_MAXGPPSEGS; slot_seg++) {
+ if (cmm_mgr_obj->pa_gppsm_seg_tab[slot_seg] == NULL)
+ break;
+
+ }
+ if (slot_seg == CMM_MAXGPPSEGS)
+ slot_seg = -1; /* failed */
+
+ return slot_seg;
+}
+
+/*
+ * ======== get_node ========
+ * Purpose:
+ * Get a memory node from freelist or create a new one.
+ */
+static struct cmm_mnode *get_node(struct cmm_object *cmm_mgr_obj, u32 dw_pa,
+ u32 dw_va, u32 ul_size)
+{
+ struct cmm_mnode *pnode = NULL;
+
+ DBC_REQUIRE(cmm_mgr_obj != NULL);
+ DBC_REQUIRE(dw_pa != 0);
+ DBC_REQUIRE(dw_va != 0);
+ DBC_REQUIRE(ul_size != 0);
+ /* Check cmm mgr's node freelist */
+ if (LST_IS_EMPTY(cmm_mgr_obj->node_free_list_head)) {
+ pnode = kzalloc(sizeof(struct cmm_mnode), GFP_KERNEL);
+ } else {
+ /* surely a valid element */
+ pnode = (struct cmm_mnode *)
+ lst_get_head(cmm_mgr_obj->node_free_list_head);
+ }
+ if (pnode) {
+ lst_init_elem((struct list_head *)pnode); /* set self */
+ pnode->dw_pa = dw_pa; /* Physical addr of start of block */
+ pnode->dw_va = dw_va; /* Virtual " " */
+ pnode->ul_size = ul_size; /* Size of block */
+ }
+ return pnode;
+}
+
+/*
+ * ======== delete_node ========
+ * Purpose:
+ * Put a memory node on the cmm nodelist for later use.
+ * Doesn't actually delete the node. Heap thrashing friendly.
+ */
+static void delete_node(struct cmm_object *cmm_mgr_obj, struct cmm_mnode *pnode)
+{
+ DBC_REQUIRE(pnode != NULL);
+ lst_init_elem((struct list_head *)pnode); /* init .self ptr */
+ lst_put_tail(cmm_mgr_obj->node_free_list_head,
+ (struct list_head *)pnode);
+}
+
+/*
+ * ====== get_free_block ========
+ * Purpose:
+ * Scan the free block list and return the first block that satisfies
+ * the size.
+ */
+static struct cmm_mnode *get_free_block(struct cmm_allocator *allocator,
+ u32 usize)
+{
+ if (allocator) {
+ struct cmm_mnode *mnode_obj = (struct cmm_mnode *)
+ lst_first(allocator->free_list_head);
+ while (mnode_obj) {
+ if (usize <= (u32) mnode_obj->ul_size) {
+ lst_remove_elem(allocator->free_list_head,
+ (struct list_head *)mnode_obj);
+ return mnode_obj;
+ }
+ /* next node. */
+ mnode_obj = (struct cmm_mnode *)
+ lst_next(allocator->free_list_head,
+ (struct list_head *)mnode_obj);
+ }
+ }
+ return NULL;
+}
+
+/*
+ * ======== add_to_free_list ========
+ * Purpose:
+ * Coelesce node into the freelist in ascending size order.
+ */
+static void add_to_free_list(struct cmm_allocator *allocator,
+ struct cmm_mnode *pnode)
+{
+ struct cmm_mnode *node_prev = NULL;
+ struct cmm_mnode *node_next = NULL;
+ struct cmm_mnode *mnode_obj;
+ u32 dw_this_pa;
+ u32 dw_next_pa;
+
+ DBC_REQUIRE(pnode != NULL);
+ DBC_REQUIRE(allocator != NULL);
+ dw_this_pa = pnode->dw_pa;
+ dw_next_pa = NEXT_PA(pnode);
+ mnode_obj = (struct cmm_mnode *)lst_first(allocator->free_list_head);
+ while (mnode_obj) {
+ if (dw_this_pa == NEXT_PA(mnode_obj)) {
+ /* found the block ahead of this one */
+ node_prev = mnode_obj;
+ } else if (dw_next_pa == mnode_obj->dw_pa) {
+ node_next = mnode_obj;
+ }
+ if ((node_prev == NULL) || (node_next == NULL)) {
+ /* next node. */
+ mnode_obj = (struct cmm_mnode *)
+ lst_next(allocator->free_list_head,
+ (struct list_head *)mnode_obj);
+ } else {
+ /* got 'em */
+ break;
+ }
+ } /* while */
+ if (node_prev != NULL) {
+ /* combine with previous block */
+ lst_remove_elem(allocator->free_list_head,
+ (struct list_head *)node_prev);
+ /* grow node to hold both */
+ pnode->ul_size += node_prev->ul_size;
+ pnode->dw_pa = node_prev->dw_pa;
+ pnode->dw_va = node_prev->dw_va;
+ /* place node on mgr nodeFreeList */
+ delete_node((struct cmm_object *)allocator->hcmm_mgr,
+ node_prev);
+ }
+ if (node_next != NULL) {
+ /* combine with next block */
+ lst_remove_elem(allocator->free_list_head,
+ (struct list_head *)node_next);
+ /* grow da node */
+ pnode->ul_size += node_next->ul_size;
+ /* place node on mgr nodeFreeList */
+ delete_node((struct cmm_object *)allocator->hcmm_mgr,
+ node_next);
+ }
+ /* Now, let's add to freelist in increasing size order */
+ mnode_obj = (struct cmm_mnode *)lst_first(allocator->free_list_head);
+ while (mnode_obj) {
+ if (pnode->ul_size <= mnode_obj->ul_size)
+ break;
+
+ /* next node. */
+ mnode_obj =
+ (struct cmm_mnode *)lst_next(allocator->free_list_head,
+ (struct list_head *)mnode_obj);
+ }
+ /* if mnode_obj is NULL then add our pnode to the end of the freelist */
+ if (mnode_obj == NULL) {
+ lst_put_tail(allocator->free_list_head,
+ (struct list_head *)pnode);
+ } else {
+ /* insert our node before the current traversed node */
+ lst_insert_before(allocator->free_list_head,
+ (struct list_head *)pnode,
+ (struct list_head *)mnode_obj);
+ }
+}
+
+/*
+ * ======== get_allocator ========
+ * Purpose:
+ * Return the allocator for the given SM Segid.
+ * SegIds: 1,2,3..max.
+ */
+static struct cmm_allocator *get_allocator(struct cmm_object *cmm_mgr_obj,
+ u32 ul_seg_id)
+{
+ struct cmm_allocator *allocator = NULL;
+
+ DBC_REQUIRE(cmm_mgr_obj != NULL);
+ DBC_REQUIRE((ul_seg_id > 0) && (ul_seg_id <= CMM_MAXGPPSEGS));
+ allocator = cmm_mgr_obj->pa_gppsm_seg_tab[ul_seg_id - 1];
+ if (allocator != NULL) {
+ /* make sure it's for real */
+ if (!allocator) {
+ allocator = NULL;
+ DBC_ASSERT(false);
+ }
+ }
+ return allocator;
+}
+
+/*
+ * The CMM_Xlator[xxx] routines below are used by Node and Stream
+ * to perform SM address translation to the client process address space.
+ * A "translator" object is created by a node/stream for each SM seg used.
+ */
+
+/*
+ * ======== cmm_xlator_create ========
+ * Purpose:
+ * Create an address translator object.
+ */
+int cmm_xlator_create(struct cmm_xlatorobject **xlator,
+ struct cmm_object *hcmm_mgr,
+ struct cmm_xlatorattrs *xlator_attrs)
+{
+ struct cmm_xlator *xlator_object = NULL;
+ int status = 0;
+
+ DBC_REQUIRE(refs > 0);
+ DBC_REQUIRE(xlator != NULL);
+ DBC_REQUIRE(hcmm_mgr != NULL);
+
+ *xlator = NULL;
+ if (xlator_attrs == NULL)
+ xlator_attrs = &cmm_dfltxlatorattrs; /* set defaults */
+
+ xlator_object = kzalloc(sizeof(struct cmm_xlator), GFP_KERNEL);
+ if (xlator_object != NULL) {
+ xlator_object->hcmm_mgr = hcmm_mgr; /* ref back to CMM */
+ /* SM seg_id */
+ xlator_object->ul_seg_id = xlator_attrs->ul_seg_id;
+ } else {
+ status = -ENOMEM;
+ }
+ if (!status)
+ *xlator = (struct cmm_xlatorobject *)xlator_object;
+
+ return status;
+}
+
+/*
+ * ======== cmm_xlator_delete ========
+ * Purpose:
+ * Free the Xlator resources.
+ * VM gets freed later.
+ */
+int cmm_xlator_delete(struct cmm_xlatorobject *xlator, bool force)
+{
+ struct cmm_xlator *xlator_obj = (struct cmm_xlator *)xlator;
+
+ DBC_REQUIRE(refs > 0);
+
+ kfree(xlator_obj);
+
+ return 0;
+}
+
+/*
+ * ======== cmm_xlator_alloc_buf ========
+ */
+void *cmm_xlator_alloc_buf(struct cmm_xlatorobject *xlator, void *va_buf,
+ u32 pa_size)
+{
+ struct cmm_xlator *xlator_obj = (struct cmm_xlator *)xlator;
+ void *pbuf = NULL;
+ void *tmp_va_buff;
+ struct cmm_attrs attrs;
+
+ DBC_REQUIRE(refs > 0);
+ DBC_REQUIRE(xlator != NULL);
+ DBC_REQUIRE(xlator_obj->hcmm_mgr != NULL);
+ DBC_REQUIRE(va_buf != NULL);
+ DBC_REQUIRE(pa_size > 0);
+ DBC_REQUIRE(xlator_obj->ul_seg_id > 0);
+
+ if (xlator_obj) {
+ attrs.ul_seg_id = xlator_obj->ul_seg_id;
+ __raw_writel(0, va_buf);
+ /* Alloc SM */
+ pbuf =
+ cmm_calloc_buf(xlator_obj->hcmm_mgr, pa_size, &attrs, NULL);
+ if (pbuf) {
+ /* convert to translator(node/strm) process Virtual
+ * address */
+ tmp_va_buff = cmm_xlator_translate(xlator,
+ pbuf, CMM_PA2VA);
+ __raw_writel((u32)tmp_va_buff, va_buf);
+ }
+ }
+ return pbuf;
+}
+
+/*
+ * ======== cmm_xlator_free_buf ========
+ * Purpose:
+ * Free the given SM buffer and descriptor.
+ * Does not free virtual memory.
+ */
+int cmm_xlator_free_buf(struct cmm_xlatorobject *xlator, void *buf_va)
+{
+ struct cmm_xlator *xlator_obj = (struct cmm_xlator *)xlator;
+ int status = -EPERM;
+ void *buf_pa = NULL;
+
+ DBC_REQUIRE(refs > 0);
+ DBC_REQUIRE(buf_va != NULL);
+ DBC_REQUIRE(xlator_obj->ul_seg_id > 0);
+
+ if (xlator_obj) {
+ /* convert Va to Pa so we can free it. */
+ buf_pa = cmm_xlator_translate(xlator, buf_va, CMM_VA2PA);
+ if (buf_pa) {
+ status = cmm_free_buf(xlator_obj->hcmm_mgr, buf_pa,
+ xlator_obj->ul_seg_id);
+ if (status) {
+ /* Uh oh, this shouldn't happen. Descriptor
+ * gone! */
+ DBC_ASSERT(false); /* CMM is leaking mem */
+ }
+ }
+ }
+ return status;
+}
+
+/*
+ * ======== cmm_xlator_info ========
+ * Purpose:
+ * Set/Get translator info.
+ */
+int cmm_xlator_info(struct cmm_xlatorobject *xlator, u8 ** paddr,
+ u32 ul_size, u32 segm_id, bool set_info)
+{
+ struct cmm_xlator *xlator_obj = (struct cmm_xlator *)xlator;
+ int status = 0;
+
+ DBC_REQUIRE(refs > 0);
+ DBC_REQUIRE(paddr != NULL);
+ DBC_REQUIRE((segm_id > 0) && (segm_id <= CMM_MAXGPPSEGS));
+
+ if (xlator_obj) {
+ if (set_info) {
+ /* set translators virtual address range */
+ xlator_obj->dw_virt_base = (u32) *paddr;
+ xlator_obj->ul_virt_size = ul_size;
+ } else { /* return virt base address */
+ *paddr = (u8 *) xlator_obj->dw_virt_base;
+ }
+ } else {
+ status = -EFAULT;
+ }
+ return status;
+}
+
+/*
+ * ======== cmm_xlator_translate ========
+ */
+void *cmm_xlator_translate(struct cmm_xlatorobject *xlator, void *paddr,
+ enum cmm_xlatetype xtype)
+{
+ u32 dw_addr_xlate = 0;
+ struct cmm_xlator *xlator_obj = (struct cmm_xlator *)xlator;
+ struct cmm_object *cmm_mgr_obj = NULL;
+ struct cmm_allocator *allocator = NULL;
+ u32 dw_offset = 0;
+
+ DBC_REQUIRE(refs > 0);
+ DBC_REQUIRE(paddr != NULL);
+ DBC_REQUIRE((xtype >= CMM_VA2PA) && (xtype <= CMM_DSPPA2PA));
+
+ if (!xlator_obj)
+ goto loop_cont;
+
+ cmm_mgr_obj = (struct cmm_object *)xlator_obj->hcmm_mgr;
+ /* get this translator's default SM allocator */
+ DBC_ASSERT(xlator_obj->ul_seg_id > 0);
+ allocator = cmm_mgr_obj->pa_gppsm_seg_tab[xlator_obj->ul_seg_id - 1];
+ if (!allocator)
+ goto loop_cont;
+
+ if ((xtype == CMM_VA2DSPPA) || (xtype == CMM_VA2PA) ||
+ (xtype == CMM_PA2VA)) {
+ if (xtype == CMM_PA2VA) {
+ /* Gpp Va = Va Base + offset */
+ dw_offset = (u8 *) paddr - (u8 *) (allocator->shm_base -
+ allocator->
+ ul_dsp_size);
+ dw_addr_xlate = xlator_obj->dw_virt_base + dw_offset;
+ /* Check if translated Va base is in range */
+ if ((dw_addr_xlate < xlator_obj->dw_virt_base) ||
+ (dw_addr_xlate >=
+ (xlator_obj->dw_virt_base +
+ xlator_obj->ul_virt_size))) {
+ dw_addr_xlate = 0; /* bad address */
+ }
+ } else {
+ /* Gpp PA = Gpp Base + offset */
+ dw_offset =
+ (u8 *) paddr - (u8 *) xlator_obj->dw_virt_base;
+ dw_addr_xlate =
+ allocator->shm_base - allocator->ul_dsp_size +
+ dw_offset;
+ }
+ } else {
+ dw_addr_xlate = (u32) paddr;
+ }
+ /*Now convert address to proper target physical address if needed */
+ if ((xtype == CMM_VA2DSPPA) || (xtype == CMM_PA2DSPPA)) {
+ /* Got Gpp Pa now, convert to DSP Pa */
+ dw_addr_xlate =
+ GPPPA2DSPPA((allocator->shm_base - allocator->ul_dsp_size),
+ dw_addr_xlate,
+ allocator->dw_dsp_phys_addr_offset *
+ allocator->c_factor);
+ } else if (xtype == CMM_DSPPA2PA) {
+ /* Got DSP Pa, convert to GPP Pa */
+ dw_addr_xlate =
+ DSPPA2GPPPA(allocator->shm_base - allocator->ul_dsp_size,
+ dw_addr_xlate,
+ allocator->dw_dsp_phys_addr_offset *
+ allocator->c_factor);
+ }
+loop_cont:
+ return (void *)dw_addr_xlate;
+}
diff --git a/drivers/staging/tidspbridge/pmgr/cod.c b/drivers/staging/tidspbridge/pmgr/cod.c
new file mode 100644
index 00000000000..52989ab67cf
--- /dev/null
+++ b/drivers/staging/tidspbridge/pmgr/cod.c
@@ -0,0 +1,652 @@
+/*
+ * cod.c
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * This module implements DSP code management for the DSP/BIOS Bridge
+ * environment. It is mostly a thin wrapper.
+ *
+ * This module provides an interface for loading both static and
+ * dynamic code objects onto DSP systems.
+ *
+ * Copyright (C) 2005-2006 Texas Instruments, Inc.
+ *
+ * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include <linux/types.h>
+
+/* ----------------------------------- Host OS */
+#include <dspbridge/host_os.h>
+#include <linux/fs.h>
+#include <linux/uaccess.h>
+
+/* ----------------------------------- DSP/BIOS Bridge */
+#include <dspbridge/dbdefs.h>
+
+/* ----------------------------------- Trace & Debug */
+#include <dspbridge/dbc.h>
+
+/* ----------------------------------- OS Adaptation Layer */
+#include <dspbridge/ldr.h>
+
+/* ----------------------------------- Platform Manager */
+/* Include appropriate loader header file */
+#include <dspbridge/dbll.h>
+
+/* ----------------------------------- This */
+#include <dspbridge/cod.h>
+
+/*
+ * ======== cod_manager ========
+ */
+struct cod_manager {
+ struct dbll_tar_obj *target;
+ struct dbll_library_obj *base_lib;
+ bool loaded; /* Base library loaded? */
+ u32 ul_entry;
+ struct ldr_module *dll_obj;
+ struct dbll_fxns fxns;
+ struct dbll_attrs attrs;
+ char sz_zl_file[COD_MAXPATHLENGTH];
+};
+
+/*
+ * ======== cod_libraryobj ========
+ */
+struct cod_libraryobj {
+ struct dbll_library_obj *dbll_lib;
+ struct cod_manager *cod_mgr;
+};
+
+static u32 refs = 0L;
+
+static struct dbll_fxns ldr_fxns = {
+ (dbll_close_fxn) dbll_close,
+ (dbll_create_fxn) dbll_create,
+ (dbll_delete_fxn) dbll_delete,
+ (dbll_exit_fxn) dbll_exit,
+ (dbll_get_attrs_fxn) dbll_get_attrs,
+ (dbll_get_addr_fxn) dbll_get_addr,
+ (dbll_get_c_addr_fxn) dbll_get_c_addr,
+ (dbll_get_sect_fxn) dbll_get_sect,
+ (dbll_init_fxn) dbll_init,
+ (dbll_load_fxn) dbll_load,
+ (dbll_load_sect_fxn) dbll_load_sect,
+ (dbll_open_fxn) dbll_open,
+ (dbll_read_sect_fxn) dbll_read_sect,
+ (dbll_set_attrs_fxn) dbll_set_attrs,
+ (dbll_unload_fxn) dbll_unload,
+ (dbll_unload_sect_fxn) dbll_unload_sect,
+};
+
+static bool no_op(void);
+
+/*
+ * File operations (originally were under kfile.c)
+ */
+static s32 cod_f_close(struct file *filp)
+{
+ /* Check for valid handle */
+ if (!filp)
+ return -EFAULT;
+
+ filp_close(filp, NULL);
+
+ /* we can't use 0 here */
+ return 0;
+}
+
+static struct file *cod_f_open(const char *psz_file_name, const char *sz_mode)
+{
+ mm_segment_t fs;
+ struct file *filp;
+
+ fs = get_fs();
+ set_fs(get_ds());
+
+ /* ignore given mode and open file as read-only */
+ filp = filp_open(psz_file_name, O_RDONLY, 0);
+
+ if (IS_ERR(filp))
+ filp = NULL;
+
+ set_fs(fs);
+
+ return filp;
+}
+
+static s32 cod_f_read(void __user *pbuffer, s32 size, s32 count,
+ struct file *filp)
+{
+ /* check for valid file handle */
+ if (!filp)
+ return -EFAULT;
+
+ if ((size > 0) && (count > 0) && pbuffer) {
+ u32 dw_bytes_read;
+ mm_segment_t fs;
+
+ /* read from file */
+ fs = get_fs();
+ set_fs(get_ds());
+ dw_bytes_read = filp->f_op->read(filp, pbuffer, size * count,
+ &(filp->f_pos));
+ set_fs(fs);
+
+ if (!dw_bytes_read)
+ return -EBADF;
+
+ return dw_bytes_read / size;
+ }
+
+ return -EINVAL;
+}
+
+static s32 cod_f_seek(struct file *filp, s32 offset, s32 origin)
+{
+ loff_t dw_cur_pos;
+
+ /* check for valid file handle */
+ if (!filp)
+ return -EFAULT;
+
+ /* based on the origin flag, move the internal pointer */
+ dw_cur_pos = filp->f_op->llseek(filp, offset, origin);
+
+ if ((s32) dw_cur_pos < 0)
+ return -EPERM;
+
+ /* we can't use 0 here */
+ return 0;
+}
+
+static s32 cod_f_tell(struct file *filp)
+{
+ loff_t dw_cur_pos;
+
+ if (!filp)
+ return -EFAULT;
+
+ /* Get current position */
+ dw_cur_pos = filp->f_op->llseek(filp, 0, SEEK_CUR);
+
+ if ((s32) dw_cur_pos < 0)
+ return -EPERM;
+
+ return dw_cur_pos;
+}
+
+/*
+ * ======== cod_close ========
+ */
+void cod_close(struct cod_libraryobj *lib)
+{
+ struct cod_manager *hmgr;
+
+ DBC_REQUIRE(refs > 0);
+ DBC_REQUIRE(lib != NULL);
+ DBC_REQUIRE(lib->cod_mgr);
+
+ hmgr = lib->cod_mgr;
+ hmgr->fxns.close_fxn(lib->dbll_lib);
+
+ kfree(lib);
+}
+
+/*
+ * ======== cod_create ========
+ * Purpose:
+ * Create an object to manage code on a DSP system.
+ * This object can be used to load an initial program image with
+ * arguments that can later be expanded with
+ * dynamically loaded object files.
+ *
+ */
+int cod_create(struct cod_manager **mgr, char *str_zl_file,
+ const struct cod_attrs *attrs)
+{
+ struct cod_manager *mgr_new;
+ struct dbll_attrs zl_attrs;
+ int status = 0;
+
+ DBC_REQUIRE(refs > 0);
+ DBC_REQUIRE(mgr != NULL);
+
+ /* assume failure */
+ *mgr = NULL;
+
+ /* we don't support non-default attrs yet */
+ if (attrs != NULL)
+ return -ENOSYS;
+
+ mgr_new = kzalloc(sizeof(struct cod_manager), GFP_KERNEL);
+ if (mgr_new == NULL)
+ return -ENOMEM;
+
+ /* Set up loader functions */
+ mgr_new->fxns = ldr_fxns;
+
+ /* initialize the ZL module */
+ mgr_new->fxns.init_fxn();
+
+ zl_attrs.alloc = (dbll_alloc_fxn) no_op;
+ zl_attrs.free = (dbll_free_fxn) no_op;
+ zl_attrs.fread = (dbll_read_fxn) cod_f_read;
+ zl_attrs.fseek = (dbll_seek_fxn) cod_f_seek;
+ zl_attrs.ftell = (dbll_tell_fxn) cod_f_tell;
+ zl_attrs.fclose = (dbll_f_close_fxn) cod_f_close;
+ zl_attrs.fopen = (dbll_f_open_fxn) cod_f_open;
+ zl_attrs.sym_lookup = NULL;
+ zl_attrs.base_image = true;
+ zl_attrs.log_write = NULL;
+ zl_attrs.log_write_handle = NULL;
+ zl_attrs.write = NULL;
+ zl_attrs.rmm_handle = NULL;
+ zl_attrs.input_params = NULL;
+ zl_attrs.sym_handle = NULL;
+ zl_attrs.sym_arg = NULL;
+
+ mgr_new->attrs = zl_attrs;
+
+ status = mgr_new->fxns.create_fxn(&mgr_new->target, &zl_attrs);
+
+ if (status) {
+ cod_delete(mgr_new);
+ return -ESPIPE;
+ }
+
+ /* return the new manager */
+ *mgr = mgr_new;
+
+ return 0;
+}
+
+/*
+ * ======== cod_delete ========
+ * Purpose:
+ * Delete a code manager object.
+ */
+void cod_delete(struct cod_manager *cod_mgr_obj)
+{
+ DBC_REQUIRE(refs > 0);
+ DBC_REQUIRE(cod_mgr_obj);
+
+ if (cod_mgr_obj->base_lib) {
+ if (cod_mgr_obj->loaded)
+ cod_mgr_obj->fxns.unload_fxn(cod_mgr_obj->base_lib,
+ &cod_mgr_obj->attrs);
+
+ cod_mgr_obj->fxns.close_fxn(cod_mgr_obj->base_lib);
+ }
+ if (cod_mgr_obj->target) {
+ cod_mgr_obj->fxns.delete_fxn(cod_mgr_obj->target);
+ cod_mgr_obj->fxns.exit_fxn();
+ }
+ kfree(cod_mgr_obj);
+}
+
+/*
+ * ======== cod_exit ========
+ * Purpose:
+ * Discontinue usage of the COD module.
+ *
+ */
+void cod_exit(void)
+{
+ DBC_REQUIRE(refs > 0);
+
+ refs--;
+
+ DBC_ENSURE(refs >= 0);
+}
+
+/*
+ * ======== cod_get_base_lib ========
+ * Purpose:
+ * Get handle to the base image DBL library.
+ */
+int cod_get_base_lib(struct cod_manager *cod_mgr_obj,
+ struct dbll_library_obj **plib)
+{
+ int status = 0;
+
+ DBC_REQUIRE(refs > 0);
+ DBC_REQUIRE(cod_mgr_obj);
+ DBC_REQUIRE(plib != NULL);
+
+ *plib = (struct dbll_library_obj *)cod_mgr_obj->base_lib;
+
+ return status;
+}
+
+/*
+ * ======== cod_get_base_name ========
+ */
+int cod_get_base_name(struct cod_manager *cod_mgr_obj, char *sz_name,
+ u32 usize)
+{
+ int status = 0;
+
+ DBC_REQUIRE(refs > 0);
+ DBC_REQUIRE(cod_mgr_obj);
+ DBC_REQUIRE(sz_name != NULL);
+
+ if (usize <= COD_MAXPATHLENGTH)
+ strncpy(sz_name, cod_mgr_obj->sz_zl_file, usize);
+ else
+ status = -EPERM;
+
+ return status;
+}
+
+/*
+ * ======== cod_get_entry ========
+ * Purpose:
+ * Retrieve the entry point of a loaded DSP program image
+ *
+ */
+int cod_get_entry(struct cod_manager *cod_mgr_obj, u32 *entry_pt)
+{
+ DBC_REQUIRE(refs > 0);
+ DBC_REQUIRE(cod_mgr_obj);
+ DBC_REQUIRE(entry_pt != NULL);
+
+ *entry_pt = cod_mgr_obj->ul_entry;
+
+ return 0;
+}
+
+/*
+ * ======== cod_get_loader ========
+ * Purpose:
+ * Get handle to the DBLL loader.
+ */
+int cod_get_loader(struct cod_manager *cod_mgr_obj,
+ struct dbll_tar_obj **loader)
+{
+ int status = 0;
+
+ DBC_REQUIRE(refs > 0);
+ DBC_REQUIRE(cod_mgr_obj);
+ DBC_REQUIRE(loader != NULL);
+
+ *loader = (struct dbll_tar_obj *)cod_mgr_obj->target;
+
+ return status;
+}
+
+/*
+ * ======== cod_get_section ========
+ * Purpose:
+ * Retrieve the starting address and length of a section in the COFF file
+ * given the section name.
+ */
+int cod_get_section(struct cod_libraryobj *lib, char *str_sect,
+ u32 *addr, u32 *len)
+{
+ struct cod_manager *cod_mgr_obj;
+ int status = 0;
+
+ DBC_REQUIRE(refs > 0);
+ DBC_REQUIRE(lib != NULL);
+ DBC_REQUIRE(lib->cod_mgr);
+ DBC_REQUIRE(str_sect != NULL);
+ DBC_REQUIRE(addr != NULL);
+ DBC_REQUIRE(len != NULL);
+
+ *addr = 0;
+ *len = 0;
+ if (lib != NULL) {
+ cod_mgr_obj = lib->cod_mgr;
+ status = cod_mgr_obj->fxns.get_sect_fxn(lib->dbll_lib, str_sect,
+ addr, len);
+ } else {
+ status = -ESPIPE;
+ }
+
+ DBC_ENSURE(!status || ((*addr == 0) && (*len == 0)));
+
+ return status;
+}
+
+/*
+ * ======== cod_get_sym_value ========
+ * Purpose:
+ * Retrieve the value for the specified symbol. The symbol is first
+ * searched for literally and then, if not found, searched for as a
+ * C symbol.
+ *
+ */
+int cod_get_sym_value(struct cod_manager *cod_mgr_obj, char *str_sym,
+ u32 *pul_value)
+{
+ struct dbll_sym_val *dbll_sym;
+
+ DBC_REQUIRE(refs > 0);
+ DBC_REQUIRE(cod_mgr_obj);
+ DBC_REQUIRE(str_sym != NULL);
+ DBC_REQUIRE(pul_value != NULL);
+
+ dev_dbg(bridge, "%s: cod_mgr_obj: %p str_sym: %s pul_value: %p\n",
+ __func__, cod_mgr_obj, str_sym, pul_value);
+ if (cod_mgr_obj->base_lib) {
+ if (!cod_mgr_obj->fxns.
+ get_addr_fxn(cod_mgr_obj->base_lib, str_sym, &dbll_sym)) {
+ if (!cod_mgr_obj->fxns.
+ get_c_addr_fxn(cod_mgr_obj->base_lib, str_sym,
+ &dbll_sym))
+ return -ESPIPE;
+ }
+ } else {
+ return -ESPIPE;
+ }
+
+ *pul_value = dbll_sym->value;
+
+ return 0;
+}
+
+/*
+ * ======== cod_init ========
+ * Purpose:
+ * Initialize the COD module's private state.
+ *
+ */
+bool cod_init(void)
+{
+ bool ret = true;
+
+ DBC_REQUIRE(refs >= 0);
+
+ if (ret)
+ refs++;
+
+ DBC_ENSURE((ret && refs > 0) || (!ret && refs >= 0));
+ return ret;
+}
+
+/*
+ * ======== cod_load_base ========
+ * Purpose:
+ * Load the initial program image, optionally with command-line arguments,
+ * on the DSP system managed by the supplied handle. The program to be
+ * loaded must be the first element of the args array and must be a fully
+ * qualified pathname.
+ * Details:
+ * if num_argc doesn't match the number of arguments in the args array, the
+ * args array is searched for a NULL terminating entry, and argc is
+ * recalculated to reflect this. In this way, we can support NULL
+ * terminating args arrays, if num_argc is very large.
+ */
+int cod_load_base(struct cod_manager *cod_mgr_obj, u32 num_argc, char *args[],
+ cod_writefxn pfn_write, void *arb, char *envp[])
+{
+ dbll_flags flags;
+ struct dbll_attrs save_attrs;
+ struct dbll_attrs new_attrs;
+ int status;
+ u32 i;
+
+ DBC_REQUIRE(refs > 0);
+ DBC_REQUIRE(cod_mgr_obj);
+ DBC_REQUIRE(num_argc > 0);
+ DBC_REQUIRE(args != NULL);
+ DBC_REQUIRE(args[0] != NULL);
+ DBC_REQUIRE(pfn_write != NULL);
+ DBC_REQUIRE(cod_mgr_obj->base_lib != NULL);
+
+ /*
+ * Make sure every argv[] stated in argc has a value, or change argc to
+ * reflect true number in NULL terminated argv array.
+ */
+ for (i = 0; i < num_argc; i++) {
+ if (args[i] == NULL) {
+ num_argc = i;
+ break;
+ }
+ }
+
+ /* set the write function for this operation */
+ cod_mgr_obj->fxns.get_attrs_fxn(cod_mgr_obj->target, &save_attrs);
+
+ new_attrs = save_attrs;
+ new_attrs.write = (dbll_write_fxn) pfn_write;
+ new_attrs.input_params = arb;
+ new_attrs.alloc = (dbll_alloc_fxn) no_op;
+ new_attrs.free = (dbll_free_fxn) no_op;
+ new_attrs.log_write = NULL;
+ new_attrs.log_write_handle = NULL;
+
+ /* Load the image */
+ flags = DBLL_CODE | DBLL_DATA | DBLL_SYMB;
+ status = cod_mgr_obj->fxns.load_fxn(cod_mgr_obj->base_lib, flags,
+ &new_attrs,
+ &cod_mgr_obj->ul_entry);
+ if (status)
+ cod_mgr_obj->fxns.close_fxn(cod_mgr_obj->base_lib);
+
+ if (!status)
+ cod_mgr_obj->loaded = true;
+ else
+ cod_mgr_obj->base_lib = NULL;
+
+ return status;
+}
+
+/*
+ * ======== cod_open ========
+ * Open library for reading sections.
+ */
+int cod_open(struct cod_manager *hmgr, char *sz_coff_path,
+ u32 flags, struct cod_libraryobj **lib_obj)
+{
+ int status = 0;
+ struct cod_libraryobj *lib = NULL;
+
+ DBC_REQUIRE(refs > 0);
+ DBC_REQUIRE(hmgr);
+ DBC_REQUIRE(sz_coff_path != NULL);
+ DBC_REQUIRE(flags == COD_NOLOAD || flags == COD_SYMB);
+ DBC_REQUIRE(lib_obj != NULL);
+
+ *lib_obj = NULL;
+
+ lib = kzalloc(sizeof(struct cod_libraryobj), GFP_KERNEL);
+ if (lib == NULL)
+ status = -ENOMEM;
+
+ if (!status) {
+ lib->cod_mgr = hmgr;
+ status = hmgr->fxns.open_fxn(hmgr->target, sz_coff_path, flags,
+ &lib->dbll_lib);
+ if (!status)
+ *lib_obj = lib;
+ }
+
+ if (status)
+ pr_err("%s: error status 0x%x, sz_coff_path: %s flags: 0x%x\n",
+ __func__, status, sz_coff_path, flags);
+ return status;
+}
+
+/*
+ * ======== cod_open_base ========
+ * Purpose:
+ * Open base image for reading sections.
+ */
+int cod_open_base(struct cod_manager *hmgr, char *sz_coff_path,
+ dbll_flags flags)
+{
+ int status = 0;
+ struct dbll_library_obj *lib;
+
+ DBC_REQUIRE(refs > 0);
+ DBC_REQUIRE(hmgr);
+ DBC_REQUIRE(sz_coff_path != NULL);
+
+ /* if we previously opened a base image, close it now */
+ if (hmgr->base_lib) {
+ if (hmgr->loaded) {
+ hmgr->fxns.unload_fxn(hmgr->base_lib, &hmgr->attrs);
+ hmgr->loaded = false;
+ }
+ hmgr->fxns.close_fxn(hmgr->base_lib);
+ hmgr->base_lib = NULL;
+ }
+ status = hmgr->fxns.open_fxn(hmgr->target, sz_coff_path, flags, &lib);
+ if (!status) {
+ /* hang onto the library for subsequent sym table usage */
+ hmgr->base_lib = lib;
+ strncpy(hmgr->sz_zl_file, sz_coff_path, COD_MAXPATHLENGTH - 1);
+ hmgr->sz_zl_file[COD_MAXPATHLENGTH - 1] = '\0';
+ }
+
+ if (status)
+ pr_err("%s: error status 0x%x sz_coff_path: %s\n", __func__,
+ status, sz_coff_path);
+ return status;
+}
+
+/*
+ * ======== cod_read_section ========
+ * Purpose:
+ * Retrieve the content of a code section given the section name.
+ */
+int cod_read_section(struct cod_libraryobj *lib, char *str_sect,
+ char *str_content, u32 content_size)
+{
+ int status = 0;
+
+ DBC_REQUIRE(refs > 0);
+ DBC_REQUIRE(lib != NULL);
+ DBC_REQUIRE(lib->cod_mgr);
+ DBC_REQUIRE(str_sect != NULL);
+ DBC_REQUIRE(str_content != NULL);
+
+ if (lib != NULL)
+ status =
+ lib->cod_mgr->fxns.read_sect_fxn(lib->dbll_lib, str_sect,
+ str_content, content_size);
+ else
+ status = -ESPIPE;
+
+ return status;
+}
+
+/*
+ * ======== no_op ========
+ * Purpose:
+ * No Operation.
+ *
+ */
+static bool no_op(void)
+{
+ return true;
+}
diff --git a/drivers/staging/tidspbridge/pmgr/dbll.c b/drivers/staging/tidspbridge/pmgr/dbll.c
new file mode 100644
index 00000000000..23406386f61
--- /dev/null
+++ b/drivers/staging/tidspbridge/pmgr/dbll.c
@@ -0,0 +1,1585 @@
+/*
+ * dbll.c
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * Copyright (C) 2005-2006 Texas Instruments, Inc.
+ *
+ * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+#include <linux/types.h>
+
+/* ----------------------------------- Host OS */
+#include <dspbridge/host_os.h>
+
+/* ----------------------------------- DSP/BIOS Bridge */
+#include <dspbridge/dbdefs.h>
+
+/* ----------------------------------- Trace & Debug */
+#include <dspbridge/dbc.h>
+#include <dspbridge/gh.h>
+
+/* ----------------------------------- OS Adaptation Layer */
+
+/* Dynamic loader library interface */
+#include <dspbridge/dynamic_loader.h>
+#include <dspbridge/getsection.h>
+
+/* ----------------------------------- This */
+#include <dspbridge/dbll.h>
+#include <dspbridge/rmm.h>
+
+/* Number of buckets for symbol hash table */
+#define MAXBUCKETS 211
+
+/* Max buffer length */
+#define MAXEXPR 128
+
+#define DOFF_ALIGN(x) (((x) + 3) & ~3UL)
+
+/*
+ * ======== struct dbll_tar_obj* ========
+ * A target may have one or more libraries of symbols/code/data loaded
+ * onto it, where a library is simply the symbols/code/data contained
+ * in a DOFF file.
+ */
+/*
+ * ======== dbll_tar_obj ========
+ */
+struct dbll_tar_obj {
+ struct dbll_attrs attrs;
+ struct dbll_library_obj *head; /* List of all opened libraries */
+};
+
+/*
+ * The following 4 typedefs are "super classes" of the dynamic loader
+ * library types used in dynamic loader functions (dynamic_loader.h).
+ */
+/*
+ * ======== dbll_stream ========
+ * Contains dynamic_loader_stream
+ */
+struct dbll_stream {
+ struct dynamic_loader_stream dl_stream;
+ struct dbll_library_obj *lib;
+};
+
+/*
+ * ======== ldr_symbol ========
+ */
+struct ldr_symbol {
+ struct dynamic_loader_sym dl_symbol;
+ struct dbll_library_obj *lib;
+};
+
+/*
+ * ======== dbll_alloc ========
+ */
+struct dbll_alloc {
+ struct dynamic_loader_allocate dl_alloc;
+ struct dbll_library_obj *lib;
+};
+
+/*
+ * ======== dbll_init_obj ========
+ */
+struct dbll_init_obj {
+ struct dynamic_loader_initialize dl_init;
+ struct dbll_library_obj *lib;
+};
+
+/*
+ * ======== DBLL_Library ========
+ * A library handle is returned by DBLL_Open() and is passed to dbll_load()
+ * to load symbols/code/data, and to dbll_unload(), to remove the
+ * symbols/code/data loaded by dbll_load().
+ */
+
+/*
+ * ======== dbll_library_obj ========
+ */
+struct dbll_library_obj {
+ struct dbll_library_obj *next; /* Next library in target's list */
+ struct dbll_library_obj *prev; /* Previous in the list */
+ struct dbll_tar_obj *target_obj; /* target for this library */
+
+ /* Objects needed by dynamic loader */
+ struct dbll_stream stream;
+ struct ldr_symbol symbol;
+ struct dbll_alloc allocate;
+ struct dbll_init_obj init;
+ void *dload_mod_obj;
+
+ char *file_name; /* COFF file name */
+ void *fp; /* Opaque file handle */
+ u32 entry; /* Entry point */
+ void *desc; /* desc of DOFF file loaded */
+ u32 open_ref; /* Number of times opened */
+ u32 load_ref; /* Number of times loaded */
+ struct gh_t_hash_tab *sym_tab; /* Hash table of symbols */
+ u32 ul_pos;
+};
+
+/*
+ * ======== dbll_symbol ========
+ */
+struct dbll_symbol {
+ struct dbll_sym_val value;
+ char *name;
+};
+
+static void dof_close(struct dbll_library_obj *zl_lib);
+static int dof_open(struct dbll_library_obj *zl_lib);
+static s32 no_op(struct dynamic_loader_initialize *thisptr, void *bufr,
+ ldr_addr locn, struct ldr_section_info *info,
+ unsigned bytsize);
+
+/*
+ * Functions called by dynamic loader
+ *
+ */
+/* dynamic_loader_stream */
+static int dbll_read_buffer(struct dynamic_loader_stream *this, void *buffer,
+ unsigned bufsize);
+static int dbll_set_file_posn(struct dynamic_loader_stream *this,
+ unsigned int pos);
+/* dynamic_loader_sym */
+static struct dynload_symbol *dbll_find_symbol(struct dynamic_loader_sym *this,
+ const char *name);
+static struct dynload_symbol *dbll_add_to_symbol_table(struct dynamic_loader_sym
+ *this, const char *name,
+ unsigned module_id);
+static struct dynload_symbol *find_in_symbol_table(struct dynamic_loader_sym
+ *this, const char *name,
+ unsigned moduleid);
+static void dbll_purge_symbol_table(struct dynamic_loader_sym *this,
+ unsigned module_id);
+static void *allocate(struct dynamic_loader_sym *this, unsigned memsize);
+static void deallocate(struct dynamic_loader_sym *this, void *mem_ptr);
+static void dbll_err_report(struct dynamic_loader_sym *this, const char *errstr,
+ va_list args);
+/* dynamic_loader_allocate */
+static int dbll_rmm_alloc(struct dynamic_loader_allocate *this,
+ struct ldr_section_info *info, unsigned align);
+static void rmm_dealloc(struct dynamic_loader_allocate *this,
+ struct ldr_section_info *info);
+
+/* dynamic_loader_initialize */
+static int connect(struct dynamic_loader_initialize *this);
+static int read_mem(struct dynamic_loader_initialize *this, void *buf,
+ ldr_addr addr, struct ldr_section_info *info,
+ unsigned bytes);
+static int write_mem(struct dynamic_loader_initialize *this, void *buf,
+ ldr_addr addr, struct ldr_section_info *info,
+ unsigned nbytes);
+static int fill_mem(struct dynamic_loader_initialize *this, ldr_addr addr,
+ struct ldr_section_info *info, unsigned bytes,
+ unsigned val);
+static int execute(struct dynamic_loader_initialize *this, ldr_addr start);
+static void release(struct dynamic_loader_initialize *this);
+
+/* symbol table hash functions */
+static u16 name_hash(void *key, u16 max_bucket);
+static bool name_match(void *key, void *sp);
+static void sym_delete(void *value);
+
+static u32 refs; /* module reference count */
+
+/* Symbol Redefinition */
+static int redefined_symbol;
+static int gbl_search = 1;
+
+/*
+ * ======== dbll_close ========
+ */
+void dbll_close(struct dbll_library_obj *zl_lib)
+{
+ struct dbll_tar_obj *zl_target;
+
+ DBC_REQUIRE(refs > 0);
+ DBC_REQUIRE(zl_lib);
+ DBC_REQUIRE(zl_lib->open_ref > 0);
+ zl_target = zl_lib->target_obj;
+ zl_lib->open_ref--;
+ if (zl_lib->open_ref == 0) {
+ /* Remove library from list */
+ if (zl_target->head == zl_lib)
+ zl_target->head = zl_lib->next;
+
+ if (zl_lib->prev)
+ (zl_lib->prev)->next = zl_lib->next;
+
+ if (zl_lib->next)
+ (zl_lib->next)->prev = zl_lib->prev;
+
+ /* Free DOF resources */
+ dof_close(zl_lib);
+ kfree(zl_lib->file_name);
+
+ /* remove symbols from symbol table */
+ if (zl_lib->sym_tab)
+ gh_delete(zl_lib->sym_tab);
+
+ /* remove the library object itself */
+ kfree(zl_lib);
+ zl_lib = NULL;
+ }
+}
+
+/*
+ * ======== dbll_create ========
+ */
+int dbll_create(struct dbll_tar_obj **target_obj,
+ struct dbll_attrs *pattrs)
+{
+ struct dbll_tar_obj *pzl_target;
+ int status = 0;
+
+ DBC_REQUIRE(refs > 0);
+ DBC_REQUIRE(pattrs != NULL);
+ DBC_REQUIRE(target_obj != NULL);
+
+ /* Allocate DBL target object */
+ pzl_target = kzalloc(sizeof(struct dbll_tar_obj), GFP_KERNEL);
+ if (target_obj != NULL) {
+ if (pzl_target == NULL) {
+ *target_obj = NULL;
+ status = -ENOMEM;
+ } else {
+ pzl_target->attrs = *pattrs;
+ *target_obj = (struct dbll_tar_obj *)pzl_target;
+ }
+ DBC_ENSURE((!status && *target_obj) ||
+ (status && *target_obj == NULL));
+ }
+
+ return status;
+}
+
+/*
+ * ======== dbll_delete ========
+ */
+void dbll_delete(struct dbll_tar_obj *target)
+{
+ struct dbll_tar_obj *zl_target = (struct dbll_tar_obj *)target;
+
+ DBC_REQUIRE(refs > 0);
+ DBC_REQUIRE(zl_target);
+
+ if (zl_target != NULL)
+ kfree(zl_target);
+
+}
+
+/*
+ * ======== dbll_exit ========
+ * Discontinue usage of DBL module.
+ */
+void dbll_exit(void)
+{
+ DBC_REQUIRE(refs > 0);
+
+ refs--;
+
+ if (refs == 0)
+ gh_exit();
+
+ DBC_ENSURE(refs >= 0);
+}
+
+/*
+ * ======== dbll_get_addr ========
+ * Get address of name in the specified library.
+ */
+bool dbll_get_addr(struct dbll_library_obj *zl_lib, char *name,
+ struct dbll_sym_val **sym_val)
+{
+ struct dbll_symbol *sym;
+ bool status = false;
+
+ DBC_REQUIRE(refs > 0);
+ DBC_REQUIRE(zl_lib);
+ DBC_REQUIRE(name != NULL);
+ DBC_REQUIRE(sym_val != NULL);
+ DBC_REQUIRE(zl_lib->sym_tab != NULL);
+
+ sym = (struct dbll_symbol *)gh_find(zl_lib->sym_tab, name);
+ if (sym != NULL) {
+ *sym_val = &sym->value;
+ status = true;
+ }
+
+ dev_dbg(bridge, "%s: lib: %p name: %s paddr: %p, status 0x%x\n",
+ __func__, zl_lib, name, sym_val, status);
+ return status;
+}
+
+/*
+ * ======== dbll_get_attrs ========
+ * Retrieve the attributes of the target.
+ */
+void dbll_get_attrs(struct dbll_tar_obj *target, struct dbll_attrs *pattrs)
+{
+ struct dbll_tar_obj *zl_target = (struct dbll_tar_obj *)target;
+
+ DBC_REQUIRE(refs > 0);
+ DBC_REQUIRE(zl_target);
+ DBC_REQUIRE(pattrs != NULL);
+
+ if ((pattrs != NULL) && (zl_target != NULL))
+ *pattrs = zl_target->attrs;
+
+}
+
+/*
+ * ======== dbll_get_c_addr ========
+ * Get address of a "C" name in the specified library.
+ */
+bool dbll_get_c_addr(struct dbll_library_obj *zl_lib, char *name,
+ struct dbll_sym_val **sym_val)
+{
+ struct dbll_symbol *sym;
+ char cname[MAXEXPR + 1];
+ bool status = false;
+
+ DBC_REQUIRE(refs > 0);
+ DBC_REQUIRE(zl_lib);
+ DBC_REQUIRE(sym_val != NULL);
+ DBC_REQUIRE(zl_lib->sym_tab != NULL);
+ DBC_REQUIRE(name != NULL);
+
+ cname[0] = '_';
+
+ strncpy(cname + 1, name, sizeof(cname) - 2);
+ cname[MAXEXPR] = '\0'; /* insure '\0' string termination */
+
+ /* Check for C name, if not found */
+ sym = (struct dbll_symbol *)gh_find(zl_lib->sym_tab, cname);
+
+ if (sym != NULL) {
+ *sym_val = &sym->value;
+ status = true;
+ }
+
+ return status;
+}
+
+/*
+ * ======== dbll_get_sect ========
+ * Get the base address and size (in bytes) of a COFF section.
+ */
+int dbll_get_sect(struct dbll_library_obj *lib, char *name, u32 *paddr,
+ u32 *psize)
+{
+ u32 byte_size;
+ bool opened_doff = false;
+ const struct ldr_section_info *sect = NULL;
+ struct dbll_library_obj *zl_lib = (struct dbll_library_obj *)lib;
+ int status = 0;
+
+ DBC_REQUIRE(refs > 0);
+ DBC_REQUIRE(name != NULL);
+ DBC_REQUIRE(paddr != NULL);
+ DBC_REQUIRE(psize != NULL);
+ DBC_REQUIRE(zl_lib);
+
+ /* If DOFF file is not open, we open it. */
+ if (zl_lib != NULL) {
+ if (zl_lib->fp == NULL) {
+ status = dof_open(zl_lib);
+ if (!status)
+ opened_doff = true;
+
+ } else {
+ (*(zl_lib->target_obj->attrs.fseek)) (zl_lib->fp,
+ zl_lib->ul_pos,
+ SEEK_SET);
+ }
+ } else {
+ status = -EFAULT;
+ }
+ if (!status) {
+ byte_size = 1;
+ if (dload_get_section_info(zl_lib->desc, name, &sect)) {
+ *paddr = sect->load_addr;
+ *psize = sect->size * byte_size;
+ /* Make sure size is even for good swap */
+ if (*psize % 2)
+ (*psize)++;
+
+ /* Align size */
+ *psize = DOFF_ALIGN(*psize);
+ } else {
+ status = -ENXIO;
+ }
+ }
+ if (opened_doff) {
+ dof_close(zl_lib);
+ opened_doff = false;
+ }
+
+ dev_dbg(bridge, "%s: lib: %p name: %s paddr: %p psize: %p, "
+ "status 0x%x\n", __func__, lib, name, paddr, psize, status);
+
+ return status;
+}
+
+/*
+ * ======== dbll_init ========
+ */
+bool dbll_init(void)
+{
+ DBC_REQUIRE(refs >= 0);
+
+ if (refs == 0)
+ gh_init();
+
+ refs++;
+
+ return true;
+}
+
+/*
+ * ======== dbll_load ========
+ */
+int dbll_load(struct dbll_library_obj *lib, dbll_flags flags,
+ struct dbll_attrs *attrs, u32 *entry)
+{
+ struct dbll_library_obj *zl_lib = (struct dbll_library_obj *)lib;
+ struct dbll_tar_obj *dbzl;
+ bool got_symbols = true;
+ s32 err;
+ int status = 0;
+ bool opened_doff = false;
+ DBC_REQUIRE(refs > 0);
+ DBC_REQUIRE(zl_lib);
+ DBC_REQUIRE(entry != NULL);
+ DBC_REQUIRE(attrs != NULL);
+
+ /*
+ * Load if not already loaded.
+ */
+ if (zl_lib->load_ref == 0 || !(flags & DBLL_DYNAMIC)) {
+ dbzl = zl_lib->target_obj;
+ dbzl->attrs = *attrs;
+ /* Create a hash table for symbols if not already created */
+ if (zl_lib->sym_tab == NULL) {
+ got_symbols = false;
+ zl_lib->sym_tab = gh_create(MAXBUCKETS,
+ sizeof(struct dbll_symbol),
+ name_hash,
+ name_match, sym_delete);
+ if (zl_lib->sym_tab == NULL)
+ status = -ENOMEM;
+
+ }
+ /*
+ * Set up objects needed by the dynamic loader
+ */
+ /* Stream */
+ zl_lib->stream.dl_stream.read_buffer = dbll_read_buffer;
+ zl_lib->stream.dl_stream.set_file_posn = dbll_set_file_posn;
+ zl_lib->stream.lib = zl_lib;
+ /* Symbol */
+ zl_lib->symbol.dl_symbol.find_matching_symbol =
+ dbll_find_symbol;
+ if (got_symbols) {
+ zl_lib->symbol.dl_symbol.add_to_symbol_table =
+ find_in_symbol_table;
+ } else {
+ zl_lib->symbol.dl_symbol.add_to_symbol_table =
+ dbll_add_to_symbol_table;
+ }
+ zl_lib->symbol.dl_symbol.purge_symbol_table =
+ dbll_purge_symbol_table;
+ zl_lib->symbol.dl_symbol.dload_allocate = allocate;
+ zl_lib->symbol.dl_symbol.dload_deallocate = deallocate;
+ zl_lib->symbol.dl_symbol.error_report = dbll_err_report;
+ zl_lib->symbol.lib = zl_lib;
+ /* Allocate */
+ zl_lib->allocate.dl_alloc.dload_allocate = dbll_rmm_alloc;
+ zl_lib->allocate.dl_alloc.dload_deallocate = rmm_dealloc;
+ zl_lib->allocate.lib = zl_lib;
+ /* Init */
+ zl_lib->init.dl_init.connect = connect;
+ zl_lib->init.dl_init.readmem = read_mem;
+ zl_lib->init.dl_init.writemem = write_mem;
+ zl_lib->init.dl_init.fillmem = fill_mem;
+ zl_lib->init.dl_init.execute = execute;
+ zl_lib->init.dl_init.release = release;
+ zl_lib->init.lib = zl_lib;
+ /* If COFF file is not open, we open it. */
+ if (zl_lib->fp == NULL) {
+ status = dof_open(zl_lib);
+ if (!status)
+ opened_doff = true;
+
+ }
+ if (!status) {
+ zl_lib->ul_pos = (*(zl_lib->target_obj->attrs.ftell))
+ (zl_lib->fp);
+ /* Reset file cursor */
+ (*(zl_lib->target_obj->attrs.fseek)) (zl_lib->fp,
+ (long)0,
+ SEEK_SET);
+ symbols_reloaded = true;
+ /* The 5th argument, DLOAD_INITBSS, tells the DLL
+ * module to zero-init all BSS sections. In general,
+ * this is not necessary and also increases load time.
+ * We may want to make this configurable by the user */
+ err = dynamic_load_module(&zl_lib->stream.dl_stream,
+ &zl_lib->symbol.dl_symbol,
+ &zl_lib->allocate.dl_alloc,
+ &zl_lib->init.dl_init,
+ DLOAD_INITBSS,
+ &zl_lib->dload_mod_obj);
+
+ if (err != 0) {
+ status = -EILSEQ;
+ } else if (redefined_symbol) {
+ zl_lib->load_ref++;
+ dbll_unload(zl_lib, (struct dbll_attrs *)attrs);
+ redefined_symbol = false;
+ status = -EILSEQ;
+ } else {
+ *entry = zl_lib->entry;
+ }
+ }
+ }
+ if (!status)
+ zl_lib->load_ref++;
+
+ /* Clean up DOFF resources */
+ if (opened_doff)
+ dof_close(zl_lib);
+
+ DBC_ENSURE(status || zl_lib->load_ref > 0);
+
+ dev_dbg(bridge, "%s: lib: %p flags: 0x%x entry: %p, status 0x%x\n",
+ __func__, lib, flags, entry, status);
+
+ return status;
+}
+
+/*
+ * ======== dbll_load_sect ========
+ * Not supported for COFF.
+ */
+int dbll_load_sect(struct dbll_library_obj *zl_lib, char *sec_name,
+ struct dbll_attrs *attrs)
+{
+ DBC_REQUIRE(zl_lib);
+
+ return -ENOSYS;
+}
+
+/*
+ * ======== dbll_open ========
+ */
+int dbll_open(struct dbll_tar_obj *target, char *file, dbll_flags flags,
+ struct dbll_library_obj **lib_obj)
+{
+ struct dbll_tar_obj *zl_target = (struct dbll_tar_obj *)target;
+ struct dbll_library_obj *zl_lib = NULL;
+ s32 err;
+ int status = 0;
+
+ DBC_REQUIRE(refs > 0);
+ DBC_REQUIRE(zl_target);
+ DBC_REQUIRE(zl_target->attrs.fopen != NULL);
+ DBC_REQUIRE(file != NULL);
+ DBC_REQUIRE(lib_obj != NULL);
+
+ zl_lib = zl_target->head;
+ while (zl_lib != NULL) {
+ if (strcmp(zl_lib->file_name, file) == 0) {
+ /* Library is already opened */
+ zl_lib->open_ref++;
+ break;
+ }
+ zl_lib = zl_lib->next;
+ }
+ if (zl_lib == NULL) {
+ /* Allocate DBL library object */
+ zl_lib = kzalloc(sizeof(struct dbll_library_obj), GFP_KERNEL);
+ if (zl_lib == NULL) {
+ status = -ENOMEM;
+ } else {
+ zl_lib->ul_pos = 0;
+ /* Increment ref count to allow close on failure
+ * later on */
+ zl_lib->open_ref++;
+ zl_lib->target_obj = zl_target;
+ /* Keep a copy of the file name */
+ zl_lib->file_name = kzalloc(strlen(file) + 1,
+ GFP_KERNEL);
+ if (zl_lib->file_name == NULL) {
+ status = -ENOMEM;
+ } else {
+ strncpy(zl_lib->file_name, file,
+ strlen(file) + 1);
+ }
+ zl_lib->sym_tab = NULL;
+ }
+ }
+ /*
+ * Set up objects needed by the dynamic loader
+ */
+ if (status)
+ goto func_cont;
+
+ /* Stream */
+ zl_lib->stream.dl_stream.read_buffer = dbll_read_buffer;
+ zl_lib->stream.dl_stream.set_file_posn = dbll_set_file_posn;
+ zl_lib->stream.lib = zl_lib;
+ /* Symbol */
+ zl_lib->symbol.dl_symbol.add_to_symbol_table = dbll_add_to_symbol_table;
+ zl_lib->symbol.dl_symbol.find_matching_symbol = dbll_find_symbol;
+ zl_lib->symbol.dl_symbol.purge_symbol_table = dbll_purge_symbol_table;
+ zl_lib->symbol.dl_symbol.dload_allocate = allocate;
+ zl_lib->symbol.dl_symbol.dload_deallocate = deallocate;
+ zl_lib->symbol.dl_symbol.error_report = dbll_err_report;
+ zl_lib->symbol.lib = zl_lib;
+ /* Allocate */
+ zl_lib->allocate.dl_alloc.dload_allocate = dbll_rmm_alloc;
+ zl_lib->allocate.dl_alloc.dload_deallocate = rmm_dealloc;
+ zl_lib->allocate.lib = zl_lib;
+ /* Init */
+ zl_lib->init.dl_init.connect = connect;
+ zl_lib->init.dl_init.readmem = read_mem;
+ zl_lib->init.dl_init.writemem = write_mem;
+ zl_lib->init.dl_init.fillmem = fill_mem;
+ zl_lib->init.dl_init.execute = execute;
+ zl_lib->init.dl_init.release = release;
+ zl_lib->init.lib = zl_lib;
+ if (!status && zl_lib->fp == NULL)
+ status = dof_open(zl_lib);
+
+ zl_lib->ul_pos = (*(zl_lib->target_obj->attrs.ftell)) (zl_lib->fp);
+ (*(zl_lib->target_obj->attrs.fseek)) (zl_lib->fp, (long)0, SEEK_SET);
+ /* Create a hash table for symbols if flag is set */
+ if (zl_lib->sym_tab != NULL || !(flags & DBLL_SYMB))
+ goto func_cont;
+
+ zl_lib->sym_tab =
+ gh_create(MAXBUCKETS, sizeof(struct dbll_symbol), name_hash,
+ name_match, sym_delete);
+ if (zl_lib->sym_tab == NULL) {
+ status = -ENOMEM;
+ } else {
+ /* Do a fake load to get symbols - set write func to no_op */
+ zl_lib->init.dl_init.writemem = no_op;
+ err = dynamic_open_module(&zl_lib->stream.dl_stream,
+ &zl_lib->symbol.dl_symbol,
+ &zl_lib->allocate.dl_alloc,
+ &zl_lib->init.dl_init, 0,
+ &zl_lib->dload_mod_obj);
+ if (err != 0) {
+ status = -EILSEQ;
+ } else {
+ /* Now that we have the symbol table, we can unload */
+ err = dynamic_unload_module(zl_lib->dload_mod_obj,
+ &zl_lib->symbol.dl_symbol,
+ &zl_lib->allocate.dl_alloc,
+ &zl_lib->init.dl_init);
+ if (err != 0)
+ status = -EILSEQ;
+
+ zl_lib->dload_mod_obj = NULL;
+ }
+ }
+func_cont:
+ if (!status) {
+ if (zl_lib->open_ref == 1) {
+ /* First time opened - insert in list */
+ if (zl_target->head)
+ (zl_target->head)->prev = zl_lib;
+
+ zl_lib->prev = NULL;
+ zl_lib->next = zl_target->head;
+ zl_target->head = zl_lib;
+ }
+ *lib_obj = (struct dbll_library_obj *)zl_lib;
+ } else {
+ *lib_obj = NULL;
+ if (zl_lib != NULL)
+ dbll_close((struct dbll_library_obj *)zl_lib);
+
+ }
+ DBC_ENSURE((!status && (zl_lib->open_ref > 0) && *lib_obj)
+ || (status && *lib_obj == NULL));
+
+ dev_dbg(bridge, "%s: target: %p file: %s lib_obj: %p, status 0x%x\n",
+ __func__, target, file, lib_obj, status);
+
+ return status;
+}
+
+/*
+ * ======== dbll_read_sect ========
+ * Get the content of a COFF section.
+ */
+int dbll_read_sect(struct dbll_library_obj *lib, char *name,
+ char *buf, u32 size)
+{
+ struct dbll_library_obj *zl_lib = (struct dbll_library_obj *)lib;
+ bool opened_doff = false;
+ u32 byte_size; /* size of bytes */
+ u32 ul_sect_size; /* size of section */
+ const struct ldr_section_info *sect = NULL;
+ int status = 0;
+
+ DBC_REQUIRE(refs > 0);
+ DBC_REQUIRE(zl_lib);
+ DBC_REQUIRE(name != NULL);
+ DBC_REQUIRE(buf != NULL);
+ DBC_REQUIRE(size != 0);
+
+ /* If DOFF file is not open, we open it. */
+ if (zl_lib != NULL) {
+ if (zl_lib->fp == NULL) {
+ status = dof_open(zl_lib);
+ if (!status)
+ opened_doff = true;
+
+ } else {
+ (*(zl_lib->target_obj->attrs.fseek)) (zl_lib->fp,
+ zl_lib->ul_pos,
+ SEEK_SET);
+ }
+ } else {
+ status = -EFAULT;
+ }
+ if (status)
+ goto func_cont;
+
+ byte_size = 1;
+ if (!dload_get_section_info(zl_lib->desc, name, &sect)) {
+ status = -ENXIO;
+ goto func_cont;
+ }
+ /*
+ * Ensure the supplied buffer size is sufficient to store
+ * the section buf to be read.
+ */
+ ul_sect_size = sect->size * byte_size;
+ /* Make sure size is even for good swap */
+ if (ul_sect_size % 2)
+ ul_sect_size++;
+
+ /* Align size */
+ ul_sect_size = DOFF_ALIGN(ul_sect_size);
+ if (ul_sect_size > size) {
+ status = -EPERM;
+ } else {
+ if (!dload_get_section(zl_lib->desc, sect, buf))
+ status = -EBADF;
+
+ }
+func_cont:
+ if (opened_doff) {
+ dof_close(zl_lib);
+ opened_doff = false;
+ }
+
+ dev_dbg(bridge, "%s: lib: %p name: %s buf: %p size: 0x%x, "
+ "status 0x%x\n", __func__, lib, name, buf, size, status);
+ return status;
+}
+
+/*
+ * ======== dbll_set_attrs ========
+ * Set the attributes of the target.
+ */
+void dbll_set_attrs(struct dbll_tar_obj *target, struct dbll_attrs *pattrs)
+{
+ struct dbll_tar_obj *zl_target = (struct dbll_tar_obj *)target;
+ DBC_REQUIRE(refs > 0);
+ DBC_REQUIRE(zl_target);
+ DBC_REQUIRE(pattrs != NULL);
+
+ if ((pattrs != NULL) && (zl_target != NULL))
+ zl_target->attrs = *pattrs;
+
+}
+
+/*
+ * ======== dbll_unload ========
+ */
+void dbll_unload(struct dbll_library_obj *lib, struct dbll_attrs *attrs)
+{
+ struct dbll_library_obj *zl_lib = (struct dbll_library_obj *)lib;
+ s32 err = 0;
+
+ DBC_REQUIRE(refs > 0);
+ DBC_REQUIRE(zl_lib);
+ DBC_REQUIRE(zl_lib->load_ref > 0);
+ dev_dbg(bridge, "%s: lib: %p\n", __func__, lib);
+ zl_lib->load_ref--;
+ /* Unload only if reference count is 0 */
+ if (zl_lib->load_ref != 0)
+ goto func_end;
+
+ zl_lib->target_obj->attrs = *attrs;
+ if (zl_lib->dload_mod_obj) {
+ err = dynamic_unload_module(zl_lib->dload_mod_obj,
+ &zl_lib->symbol.dl_symbol,
+ &zl_lib->allocate.dl_alloc,
+ &zl_lib->init.dl_init);
+ if (err != 0)
+ dev_dbg(bridge, "%s: failed: 0x%x\n", __func__, err);
+ }
+ /* remove symbols from symbol table */
+ if (zl_lib->sym_tab != NULL) {
+ gh_delete(zl_lib->sym_tab);
+ zl_lib->sym_tab = NULL;
+ }
+ /* delete DOFF desc since it holds *lots* of host OS
+ * resources */
+ dof_close(zl_lib);
+func_end:
+ DBC_ENSURE(zl_lib->load_ref >= 0);
+}
+
+/*
+ * ======== dbll_unload_sect ========
+ * Not supported for COFF.
+ */
+int dbll_unload_sect(struct dbll_library_obj *lib, char *sec_name,
+ struct dbll_attrs *attrs)
+{
+ DBC_REQUIRE(refs > 0);
+ DBC_REQUIRE(sec_name != NULL);
+
+ return -ENOSYS;
+}
+
+/*
+ * ======== dof_close ========
+ */
+static void dof_close(struct dbll_library_obj *zl_lib)
+{
+ if (zl_lib->desc) {
+ dload_module_close(zl_lib->desc);
+ zl_lib->desc = NULL;
+ }
+ /* close file */
+ if (zl_lib->fp) {
+ (zl_lib->target_obj->attrs.fclose) (zl_lib->fp);
+ zl_lib->fp = NULL;
+ }
+}
+
+/*
+ * ======== dof_open ========
+ */
+static int dof_open(struct dbll_library_obj *zl_lib)
+{
+ void *open = *(zl_lib->target_obj->attrs.fopen);
+ int status = 0;
+
+ /* First open the file for the dynamic loader, then open COF */
+ zl_lib->fp =
+ (void *)((dbll_f_open_fxn) (open)) (zl_lib->file_name, "rb");
+
+ /* Open DOFF module */
+ if (zl_lib->fp && zl_lib->desc == NULL) {
+ (*(zl_lib->target_obj->attrs.fseek)) (zl_lib->fp, (long)0,
+ SEEK_SET);
+ zl_lib->desc =
+ dload_module_open(&zl_lib->stream.dl_stream,
+ &zl_lib->symbol.dl_symbol);
+ if (zl_lib->desc == NULL) {
+ (zl_lib->target_obj->attrs.fclose) (zl_lib->fp);
+ zl_lib->fp = NULL;
+ status = -EBADF;
+ }
+ } else {
+ status = -EBADF;
+ }
+
+ return status;
+}
+
+/*
+ * ======== name_hash ========
+ */
+static u16 name_hash(void *key, u16 max_bucket)
+{
+ u16 ret;
+ u16 hash;
+ char *name = (char *)key;
+
+ DBC_REQUIRE(name != NULL);
+
+ hash = 0;
+
+ while (*name) {
+ hash <<= 1;
+ hash ^= *name++;
+ }
+
+ ret = hash % max_bucket;
+
+ return ret;
+}
+
+/*
+ * ======== name_match ========
+ */
+static bool name_match(void *key, void *sp)
+{
+ DBC_REQUIRE(key != NULL);
+ DBC_REQUIRE(sp != NULL);
+
+ if ((key != NULL) && (sp != NULL)) {
+ if (strcmp((char *)key, ((struct dbll_symbol *)sp)->name) ==
+ 0)
+ return true;
+ }
+ return false;
+}
+
+/*
+ * ======== no_op ========
+ */
+static int no_op(struct dynamic_loader_initialize *thisptr, void *bufr,
+ ldr_addr locn, struct ldr_section_info *info, unsigned bytsize)
+{
+ return 1;
+}
+
+/*
+ * ======== sym_delete ========
+ */
+static void sym_delete(void *value)
+{
+ struct dbll_symbol *sp = (struct dbll_symbol *)value;
+
+ kfree(sp->name);
+}
+
+/*
+ * Dynamic Loader Functions
+ */
+
+/* dynamic_loader_stream */
+/*
+ * ======== dbll_read_buffer ========
+ */
+static int dbll_read_buffer(struct dynamic_loader_stream *this, void *buffer,
+ unsigned bufsize)
+{
+ struct dbll_stream *pstream = (struct dbll_stream *)this;
+ struct dbll_library_obj *lib;
+ int bytes_read = 0;
+
+ DBC_REQUIRE(this != NULL);
+ lib = pstream->lib;
+ DBC_REQUIRE(lib);
+
+ if (lib != NULL) {
+ bytes_read =
+ (*(lib->target_obj->attrs.fread)) (buffer, 1, bufsize,
+ lib->fp);
+ }
+ return bytes_read;
+}
+
+/*
+ * ======== dbll_set_file_posn ========
+ */
+static int dbll_set_file_posn(struct dynamic_loader_stream *this,
+ unsigned int pos)
+{
+ struct dbll_stream *pstream = (struct dbll_stream *)this;
+ struct dbll_library_obj *lib;
+ int status = 0; /* Success */
+
+ DBC_REQUIRE(this != NULL);
+ lib = pstream->lib;
+ DBC_REQUIRE(lib);
+
+ if (lib != NULL) {
+ status = (*(lib->target_obj->attrs.fseek)) (lib->fp, (long)pos,
+ SEEK_SET);
+ }
+
+ return status;
+}
+
+/* dynamic_loader_sym */
+
+/*
+ * ======== dbll_find_symbol ========
+ */
+static struct dynload_symbol *dbll_find_symbol(struct dynamic_loader_sym *this,
+ const char *name)
+{
+ struct dynload_symbol *ret_sym;
+ struct ldr_symbol *ldr_sym = (struct ldr_symbol *)this;
+ struct dbll_library_obj *lib;
+ struct dbll_sym_val *dbll_sym = NULL;
+ bool status = false; /* Symbol not found yet */
+
+ DBC_REQUIRE(this != NULL);
+ lib = ldr_sym->lib;
+ DBC_REQUIRE(lib);
+
+ if (lib != NULL) {
+ if (lib->target_obj->attrs.sym_lookup) {
+ /* Check current lib + base lib + dep lib +
+ * persistent lib */
+ status = (*(lib->target_obj->attrs.sym_lookup))
+ (lib->target_obj->attrs.sym_handle,
+ lib->target_obj->attrs.sym_arg,
+ lib->target_obj->attrs.rmm_handle, name,
+ &dbll_sym);
+ } else {
+ /* Just check current lib for symbol */
+ status = dbll_get_addr((struct dbll_library_obj *)lib,
+ (char *)name, &dbll_sym);
+ if (!status) {
+ status =
+ dbll_get_c_addr((struct dbll_library_obj *)
+ lib, (char *)name,
+ &dbll_sym);
+ }
+ }
+ }
+
+ if (!status && gbl_search)
+ dev_dbg(bridge, "%s: Symbol not found: %s\n", __func__, name);
+
+ DBC_ASSERT((status && (dbll_sym != NULL))
+ || (!status && (dbll_sym == NULL)));
+
+ ret_sym = (struct dynload_symbol *)dbll_sym;
+ return ret_sym;
+}
+
+/*
+ * ======== find_in_symbol_table ========
+ */
+static struct dynload_symbol *find_in_symbol_table(struct dynamic_loader_sym
+ *this, const char *name,
+ unsigned moduleid)
+{
+ struct dynload_symbol *ret_sym;
+ struct ldr_symbol *ldr_sym = (struct ldr_symbol *)this;
+ struct dbll_library_obj *lib;
+ struct dbll_symbol *sym;
+
+ DBC_REQUIRE(this != NULL);
+ lib = ldr_sym->lib;
+ DBC_REQUIRE(lib);
+ DBC_REQUIRE(lib->sym_tab != NULL);
+
+ sym = (struct dbll_symbol *)gh_find(lib->sym_tab, (char *)name);
+
+ ret_sym = (struct dynload_symbol *)&sym->value;
+ return ret_sym;
+}
+
+/*
+ * ======== dbll_add_to_symbol_table ========
+ */
+static struct dynload_symbol *dbll_add_to_symbol_table(struct dynamic_loader_sym
+ *this, const char *name,
+ unsigned module_id)
+{
+ struct dbll_symbol *sym_ptr = NULL;
+ struct dbll_symbol symbol;
+ struct dynload_symbol *dbll_sym = NULL;
+ struct ldr_symbol *ldr_sym = (struct ldr_symbol *)this;
+ struct dbll_library_obj *lib;
+ struct dynload_symbol *ret;
+
+ DBC_REQUIRE(this != NULL);
+ DBC_REQUIRE(name);
+ lib = ldr_sym->lib;
+ DBC_REQUIRE(lib);
+
+ /* Check to see if symbol is already defined in symbol table */
+ if (!(lib->target_obj->attrs.base_image)) {
+ gbl_search = false;
+ dbll_sym = dbll_find_symbol(this, name);
+ gbl_search = true;
+ if (dbll_sym) {
+ redefined_symbol = true;
+ dev_dbg(bridge, "%s already defined in symbol table\n",
+ name);
+ return NULL;
+ }
+ }
+ /* Allocate string to copy symbol name */
+ symbol.name = kzalloc(strlen((char *const)name) + 1, GFP_KERNEL);
+ if (symbol.name == NULL)
+ return NULL;
+
+ if (symbol.name != NULL) {
+ /* Just copy name (value will be filled in by dynamic loader) */
+ strncpy(symbol.name, (char *const)name,
+ strlen((char *const)name) + 1);
+
+ /* Add symbol to symbol table */
+ sym_ptr =
+ (struct dbll_symbol *)gh_insert(lib->sym_tab, (void *)name,
+ (void *)&symbol);
+ if (sym_ptr == NULL)
+ kfree(symbol.name);
+
+ }
+ if (sym_ptr != NULL)
+ ret = (struct dynload_symbol *)&sym_ptr->value;
+ else
+ ret = NULL;
+
+ return ret;
+}
+
+/*
+ * ======== dbll_purge_symbol_table ========
+ */
+static void dbll_purge_symbol_table(struct dynamic_loader_sym *this,
+ unsigned module_id)
+{
+ struct ldr_symbol *ldr_sym = (struct ldr_symbol *)this;
+ struct dbll_library_obj *lib;
+
+ DBC_REQUIRE(this != NULL);
+ lib = ldr_sym->lib;
+ DBC_REQUIRE(lib);
+
+ /* May not need to do anything */
+}
+
+/*
+ * ======== allocate ========
+ */
+static void *allocate(struct dynamic_loader_sym *this, unsigned memsize)
+{
+ struct ldr_symbol *ldr_sym = (struct ldr_symbol *)this;
+ struct dbll_library_obj *lib;
+ void *buf;
+
+ DBC_REQUIRE(this != NULL);
+ lib = ldr_sym->lib;
+ DBC_REQUIRE(lib);
+
+ buf = kzalloc(memsize, GFP_KERNEL);
+
+ return buf;
+}
+
+/*
+ * ======== deallocate ========
+ */
+static void deallocate(struct dynamic_loader_sym *this, void *mem_ptr)
+{
+ struct ldr_symbol *ldr_sym = (struct ldr_symbol *)this;
+ struct dbll_library_obj *lib;
+
+ DBC_REQUIRE(this != NULL);
+ lib = ldr_sym->lib;
+ DBC_REQUIRE(lib);
+
+ kfree(mem_ptr);
+}
+
+/*
+ * ======== dbll_err_report ========
+ */
+static void dbll_err_report(struct dynamic_loader_sym *this, const char *errstr,
+ va_list args)
+{
+ struct ldr_symbol *ldr_sym = (struct ldr_symbol *)this;
+ struct dbll_library_obj *lib;
+ char temp_buf[MAXEXPR];
+
+ DBC_REQUIRE(this != NULL);
+ lib = ldr_sym->lib;
+ DBC_REQUIRE(lib);
+ vsnprintf((char *)temp_buf, MAXEXPR, (char *)errstr, args);
+ dev_dbg(bridge, "%s\n", temp_buf);
+}
+
+/* dynamic_loader_allocate */
+
+/*
+ * ======== dbll_rmm_alloc ========
+ */
+static int dbll_rmm_alloc(struct dynamic_loader_allocate *this,
+ struct ldr_section_info *info, unsigned align)
+{
+ struct dbll_alloc *dbll_alloc_obj = (struct dbll_alloc *)this;
+ struct dbll_library_obj *lib;
+ int status = 0;
+ u32 mem_sect_type;
+ struct rmm_addr rmm_addr_obj;
+ s32 ret = true;
+ unsigned stype = DLOAD_SECTION_TYPE(info->type);
+ char *token = NULL;
+ char *sz_sec_last_token = NULL;
+ char *sz_last_token = NULL;
+ char *sz_sect_name = NULL;
+ char *psz_cur;
+ s32 token_len = 0;
+ s32 seg_id = -1;
+ s32 req = -1;
+ s32 count = 0;
+ u32 alloc_size = 0;
+ u32 run_addr_flag = 0;
+
+ DBC_REQUIRE(this != NULL);
+ lib = dbll_alloc_obj->lib;
+ DBC_REQUIRE(lib);
+
+ mem_sect_type =
+ (stype == DLOAD_TEXT) ? DBLL_CODE : (stype ==
+ DLOAD_BSS) ? DBLL_BSS :
+ DBLL_DATA;
+
+ /* Attempt to extract the segment ID and requirement information from
+ the name of the section */
+ DBC_REQUIRE(info->name);
+ token_len = strlen((char *)(info->name)) + 1;
+
+ sz_sect_name = kzalloc(token_len, GFP_KERNEL);
+ sz_last_token = kzalloc(token_len, GFP_KERNEL);
+ sz_sec_last_token = kzalloc(token_len, GFP_KERNEL);
+
+ if (sz_sect_name == NULL || sz_sec_last_token == NULL ||
+ sz_last_token == NULL) {
+ status = -ENOMEM;
+ goto func_cont;
+ }
+ strncpy(sz_sect_name, (char *)(info->name), token_len);
+ psz_cur = sz_sect_name;
+ while ((token = strsep(&psz_cur, ":")) && *token != '\0') {
+ strncpy(sz_sec_last_token, sz_last_token,
+ strlen(sz_last_token) + 1);
+ strncpy(sz_last_token, token, strlen(token) + 1);
+ token = strsep(&psz_cur, ":");
+ count++; /* optimizes processing */
+ }
+ /* If token is 0 or 1, and sz_sec_last_token is DYN_DARAM or DYN_SARAM,
+ or DYN_EXTERNAL, then mem granularity information is present
+ within the section name - only process if there are at least three
+ tokens within the section name (just a minor optimization) */
+ if (count >= 3)
+ strict_strtol(sz_last_token, 10, (long *)&req);
+
+ if ((req == 0) || (req == 1)) {
+ if (strcmp(sz_sec_last_token, "DYN_DARAM") == 0) {
+ seg_id = 0;
+ } else {
+ if (strcmp(sz_sec_last_token, "DYN_SARAM") == 0) {
+ seg_id = 1;
+ } else {
+ if (strcmp(sz_sec_last_token,
+ "DYN_EXTERNAL") == 0)
+ seg_id = 2;
+ }
+ }
+ }
+func_cont:
+ kfree(sz_sect_name);
+ sz_sect_name = NULL;
+ kfree(sz_last_token);
+ sz_last_token = NULL;
+ kfree(sz_sec_last_token);
+ sz_sec_last_token = NULL;
+
+ if (mem_sect_type == DBLL_CODE)
+ alloc_size = info->size + GEM_L1P_PREFETCH_SIZE;
+ else
+ alloc_size = info->size;
+
+ if (info->load_addr != info->run_addr)
+ run_addr_flag = 1;
+ /* TODO - ideally, we can pass the alignment requirement also
+ * from here */
+ if (lib != NULL) {
+ status =
+ (lib->target_obj->attrs.alloc) (lib->target_obj->attrs.
+ rmm_handle, mem_sect_type,
+ alloc_size, align,
+ (u32 *) &rmm_addr_obj,
+ seg_id, req, false);
+ }
+ if (status) {
+ ret = false;
+ } else {
+ /* RMM gives word address. Need to convert to byte address */
+ info->load_addr = rmm_addr_obj.addr * DSPWORDSIZE;
+ if (!run_addr_flag)
+ info->run_addr = info->load_addr;
+ info->context = (u32) rmm_addr_obj.segid;
+ dev_dbg(bridge, "%s: %s base = 0x%x len = 0x%x, "
+ "info->run_addr 0x%x, info->load_addr 0x%x\n",
+ __func__, info->name, info->load_addr / DSPWORDSIZE,
+ info->size / DSPWORDSIZE, info->run_addr,
+ info->load_addr);
+ }
+ return ret;
+}
+
+/*
+ * ======== rmm_dealloc ========
+ */
+static void rmm_dealloc(struct dynamic_loader_allocate *this,
+ struct ldr_section_info *info)
+{
+ struct dbll_alloc *dbll_alloc_obj = (struct dbll_alloc *)this;
+ struct dbll_library_obj *lib;
+ u32 segid;
+ int status = 0;
+ unsigned stype = DLOAD_SECTION_TYPE(info->type);
+ u32 mem_sect_type;
+ u32 free_size = 0;
+
+ mem_sect_type =
+ (stype == DLOAD_TEXT) ? DBLL_CODE : (stype ==
+ DLOAD_BSS) ? DBLL_BSS :
+ DBLL_DATA;
+ DBC_REQUIRE(this != NULL);
+ lib = dbll_alloc_obj->lib;
+ DBC_REQUIRE(lib);
+ /* segid was set by alloc function */
+ segid = (u32) info->context;
+ if (mem_sect_type == DBLL_CODE)
+ free_size = info->size + GEM_L1P_PREFETCH_SIZE;
+ else
+ free_size = info->size;
+ if (lib != NULL) {
+ status =
+ (lib->target_obj->attrs.free) (lib->target_obj->attrs.
+ sym_handle, segid,
+ info->load_addr /
+ DSPWORDSIZE, free_size,
+ false);
+ }
+}
+
+/* dynamic_loader_initialize */
+/*
+ * ======== connect ========
+ */
+static int connect(struct dynamic_loader_initialize *this)
+{
+ return true;
+}
+
+/*
+ * ======== read_mem ========
+ * This function does not need to be implemented.
+ */
+static int read_mem(struct dynamic_loader_initialize *this, void *buf,
+ ldr_addr addr, struct ldr_section_info *info,
+ unsigned nbytes)
+{
+ struct dbll_init_obj *init_obj = (struct dbll_init_obj *)this;
+ struct dbll_library_obj *lib;
+ int bytes_read = 0;
+
+ DBC_REQUIRE(this != NULL);
+ lib = init_obj->lib;
+ DBC_REQUIRE(lib);
+ /* Need bridge_brd_read function */
+ return bytes_read;
+}
+
+/*
+ * ======== write_mem ========
+ */
+static int write_mem(struct dynamic_loader_initialize *this, void *buf,
+ ldr_addr addr, struct ldr_section_info *info,
+ unsigned bytes)
+{
+ struct dbll_init_obj *init_obj = (struct dbll_init_obj *)this;
+ struct dbll_library_obj *lib;
+ struct dbll_tar_obj *target_obj;
+ struct dbll_sect_info sect_info;
+ u32 mem_sect_type;
+ bool ret = true;
+
+ DBC_REQUIRE(this != NULL);
+ lib = init_obj->lib;
+ if (!lib)
+ return false;
+
+ target_obj = lib->target_obj;
+
+ mem_sect_type =
+ (DLOAD_SECTION_TYPE(info->type) ==
+ DLOAD_TEXT) ? DBLL_CODE : DBLL_DATA;
+ if (target_obj && target_obj->attrs.write) {
+ ret =
+ (*target_obj->attrs.write) (target_obj->attrs.input_params,
+ addr, buf, bytes,
+ mem_sect_type);
+
+ if (target_obj->attrs.log_write) {
+ sect_info.name = info->name;
+ sect_info.sect_run_addr = info->run_addr;
+ sect_info.sect_load_addr = info->load_addr;
+ sect_info.size = info->size;
+ sect_info.type = mem_sect_type;
+ /* Pass the information about what we've written to
+ * another module */
+ (*target_obj->attrs.log_write) (target_obj->attrs.
+ log_write_handle,
+ &sect_info, addr,
+ bytes);
+ }
+ }
+ return ret;
+}
+
+/*
+ * ======== fill_mem ========
+ * Fill bytes of memory at a given address with a given value by
+ * writing from a buffer containing the given value. Write in
+ * sets of MAXEXPR (128) bytes to avoid large stack buffer issues.
+ */
+static int fill_mem(struct dynamic_loader_initialize *this, ldr_addr addr,
+ struct ldr_section_info *info, unsigned bytes, unsigned val)
+{
+ bool ret = true;
+ char *pbuf;
+ struct dbll_library_obj *lib;
+ struct dbll_init_obj *init_obj = (struct dbll_init_obj *)this;
+
+ DBC_REQUIRE(this != NULL);
+ lib = init_obj->lib;
+ pbuf = NULL;
+ /* Pass the NULL pointer to write_mem to get the start address of Shared
+ memory. This is a trick to just get the start address, there is no
+ writing taking place with this Writemem
+ */
+ if ((lib->target_obj->attrs.write) != (dbll_write_fxn) no_op)
+ write_mem(this, &pbuf, addr, info, 0);
+ if (pbuf)
+ memset(pbuf, val, bytes);
+
+ return ret;
+}
+
+/*
+ * ======== execute ========
+ */
+static int execute(struct dynamic_loader_initialize *this, ldr_addr start)
+{
+ struct dbll_init_obj *init_obj = (struct dbll_init_obj *)this;
+ struct dbll_library_obj *lib;
+ bool ret = true;
+
+ DBC_REQUIRE(this != NULL);
+ lib = init_obj->lib;
+ DBC_REQUIRE(lib);
+ /* Save entry point */
+ if (lib != NULL)
+ lib->entry = (u32) start;
+
+ return ret;
+}
+
+/*
+ * ======== release ========
+ */
+static void release(struct dynamic_loader_initialize *this)
+{
+}
+
+#ifdef CONFIG_TIDSPBRIDGE_BACKTRACE
+/**
+ * find_symbol_context - Basic symbol context structure
+ * @address: Symbol Adress
+ * @offset_range: Offset range where the search for the DSP symbol
+ * started.
+ * @cur_best_offset: Best offset to start looking for the DSP symbol
+ * @sym_addr: Address of the DSP symbol
+ * @name: Symbol name
+ *
+ */
+struct find_symbol_context {
+ /* input */
+ u32 address;
+ u32 offset_range;
+ /* state */
+ u32 cur_best_offset;
+ /* output */
+ u32 sym_addr;
+ char name[120];
+};
+
+/**
+ * find_symbol_callback() - Validates symbol address and copies the symbol name
+ * to the user data.
+ * @elem: dsp library context
+ * @user_data: Find symbol context
+ *
+ */
+void find_symbol_callback(void *elem, void *user_data)
+{
+ struct dbll_symbol *symbol = elem;
+ struct find_symbol_context *context = user_data;
+ u32 symbol_addr = symbol->value.value;
+ u32 offset = context->address - symbol_addr;
+
+ /*
+ * Address given should be greater than symbol address,
+ * symbol address should be within specified range
+ * and the offset should be better than previous one
+ */
+ if (context->address >= symbol_addr && symbol_addr < (u32)-1 &&
+ offset < context->cur_best_offset) {
+ context->cur_best_offset = offset;
+ context->sym_addr = symbol_addr;
+ strncpy(context->name, symbol->name, sizeof(context->name));
+ }
+
+ return;
+}
+
+/**
+ * dbll_find_dsp_symbol() - This function retrieves the dsp symbol from the dsp binary.
+ * @zl_lib: DSP binary obj library pointer
+ * @address: Given address to find the dsp symbol
+ * @offset_range: offset range to look for dsp symbol
+ * @sym_addr_output: Symbol Output address
+ * @name_output: String with the dsp symbol
+ *
+ * This function retrieves the dsp symbol from the dsp binary.
+ */
+bool dbll_find_dsp_symbol(struct dbll_library_obj *zl_lib, u32 address,
+ u32 offset_range, u32 *sym_addr_output,
+ char *name_output)
+{
+ bool status = false;
+ struct find_symbol_context context;
+
+ context.address = address;
+ context.offset_range = offset_range;
+ context.cur_best_offset = offset_range;
+ context.sym_addr = 0;
+ context.name[0] = '\0';
+
+ gh_iterate(zl_lib->sym_tab, find_symbol_callback, &context);
+
+ if (context.name[0]) {
+ status = true;
+ strcpy(name_output, context.name);
+ *sym_addr_output = context.sym_addr;
+ }
+
+ return status;
+}
+#endif
diff --git a/drivers/staging/tidspbridge/pmgr/dev.c b/drivers/staging/tidspbridge/pmgr/dev.c
new file mode 100644
index 00000000000..4ddf03d3b1a
--- /dev/null
+++ b/drivers/staging/tidspbridge/pmgr/dev.c
@@ -0,0 +1,1151 @@
+/*
+ * dev.c
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * Implementation of Bridge Bridge driver device operations.
+ *
+ * Copyright (C) 2005-2006 Texas Instruments, Inc.
+ *
+ * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+#include <linux/types.h>
+
+/* ----------------------------------- Host OS */
+#include <dspbridge/host_os.h>
+
+/* ----------------------------------- DSP/BIOS Bridge */
+#include <dspbridge/dbdefs.h>
+
+/* ----------------------------------- Trace & Debug */
+#include <dspbridge/dbc.h>
+
+/* ----------------------------------- OS Adaptation Layer */
+#include <dspbridge/cfg.h>
+#include <dspbridge/ldr.h>
+#include <dspbridge/list.h>
+
+/* ----------------------------------- Platform Manager */
+#include <dspbridge/cod.h>
+#include <dspbridge/drv.h>
+#include <dspbridge/proc.h>
+#include <dspbridge/dmm.h>
+
+/* ----------------------------------- Resource Manager */
+#include <dspbridge/mgr.h>
+#include <dspbridge/node.h>
+
+/* ----------------------------------- Others */
+#include <dspbridge/dspapi.h> /* DSP API version info. */
+
+#include <dspbridge/chnl.h>
+#include <dspbridge/io.h>
+#include <dspbridge/msg.h>
+#include <dspbridge/cmm.h>
+#include <dspbridge/dspdeh.h>
+
+/* ----------------------------------- This */
+#include <dspbridge/dev.h>
+
+/* ----------------------------------- Defines, Data Structures, Typedefs */
+
+#define MAKEVERSION(major, minor) (major * 10 + minor)
+#define BRD_API_VERSION MAKEVERSION(BRD_API_MAJOR_VERSION, \
+ BRD_API_MINOR_VERSION)
+
+/* The Bridge device object: */
+struct dev_object {
+ /* LST requires "link" to be first field! */
+ struct list_head link; /* Link to next dev_object. */
+ u8 dev_type; /* Device Type */
+ struct cfg_devnode *dev_node_obj; /* Platform specific dev id */
+ /* Bridge Context Handle */
+ struct bridge_dev_context *hbridge_context;
+ /* Function interface to Bridge driver. */
+ struct bridge_drv_interface bridge_interface;
+ struct brd_object *lock_owner; /* Client with exclusive access. */
+ struct cod_manager *cod_mgr; /* Code manager handle. */
+ struct chnl_mgr *hchnl_mgr; /* Channel manager. */
+ struct deh_mgr *hdeh_mgr; /* DEH manager. */
+ struct msg_mgr *hmsg_mgr; /* Message manager. */
+ struct io_mgr *hio_mgr; /* IO manager (CHNL, msg_ctrl) */
+ struct cmm_object *hcmm_mgr; /* SM memory manager. */
+ struct dmm_object *dmm_mgr; /* Dynamic memory manager. */
+ struct ldr_module *module_obj; /* Bridge Module handle. */
+ u32 word_size; /* DSP word size: quick access. */
+ struct drv_object *hdrv_obj; /* Driver Object */
+ struct lst_list *proc_list; /* List of Proceeosr attached to
+ * this device */
+ struct node_mgr *hnode_mgr;
+};
+
+/* ----------------------------------- Globals */
+static u32 refs; /* Module reference count */
+
+/* ----------------------------------- Function Prototypes */
+static int fxn_not_implemented(int arg, ...);
+static int init_cod_mgr(struct dev_object *dev_obj);
+static void store_interface_fxns(struct bridge_drv_interface *drv_fxns,
+ struct bridge_drv_interface *intf_fxns);
+/*
+ * ======== dev_brd_write_fxn ========
+ * Purpose:
+ * Exported function to be used as the COD write function. This function
+ * is passed a handle to a DEV_hObject, then calls the
+ * device's bridge_brd_write() function.
+ */
+u32 dev_brd_write_fxn(void *arb, u32 dsp_add, void *host_buf,
+ u32 ul_num_bytes, u32 mem_space)
+{
+ struct dev_object *dev_obj = (struct dev_object *)arb;
+ u32 ul_written = 0;
+ int status;
+
+ DBC_REQUIRE(refs > 0);
+ DBC_REQUIRE(host_buf != NULL); /* Required of BrdWrite(). */
+ if (dev_obj) {
+ /* Require of BrdWrite() */
+ DBC_ASSERT(dev_obj->hbridge_context != NULL);
+ status = (*dev_obj->bridge_interface.pfn_brd_write) (
+ dev_obj->hbridge_context, host_buf,
+ dsp_add, ul_num_bytes, mem_space);
+ /* Special case of getting the address only */
+ if (ul_num_bytes == 0)
+ ul_num_bytes = 1;
+ if (!status)
+ ul_written = ul_num_bytes;
+
+ }
+ return ul_written;
+}
+
+/*
+ * ======== dev_create_device ========
+ * Purpose:
+ * Called by the operating system to load the PM Bridge Driver for a
+ * PM board (device).
+ */
+int dev_create_device(struct dev_object **device_obj,
+ const char *driver_file_name,
+ struct cfg_devnode *dev_node_obj)
+{
+ struct cfg_hostres *host_res;
+ struct ldr_module *module_obj = NULL;
+ struct bridge_drv_interface *drv_fxns = NULL;
+ struct dev_object *dev_obj = NULL;
+ struct chnl_mgrattrs mgr_attrs;
+ struct io_attrs io_mgr_attrs;
+ u32 num_windows;
+ struct drv_object *hdrv_obj = NULL;
+ int status = 0;
+ DBC_REQUIRE(refs > 0);
+ DBC_REQUIRE(device_obj != NULL);
+ DBC_REQUIRE(driver_file_name != NULL);
+
+ status = drv_request_bridge_res_dsp((void *)&host_res);
+
+ if (status) {
+ dev_dbg(bridge, "%s: Failed to reserve bridge resources\n",
+ __func__);
+ goto leave;
+ }
+
+ /* Get the Bridge driver interface functions */
+ bridge_drv_entry(&drv_fxns, driver_file_name);
+ if (cfg_get_object((u32 *) &hdrv_obj, REG_DRV_OBJECT)) {
+ /* don't propogate CFG errors from this PROC function */
+ status = -EPERM;
+ }
+ /* Create the device object, and pass a handle to the Bridge driver for
+ * storage. */
+ if (!status) {
+ DBC_ASSERT(drv_fxns);
+ dev_obj = kzalloc(sizeof(struct dev_object), GFP_KERNEL);
+ if (dev_obj) {
+ /* Fill out the rest of the Dev Object structure: */
+ dev_obj->dev_node_obj = dev_node_obj;
+ dev_obj->module_obj = module_obj;
+ dev_obj->cod_mgr = NULL;
+ dev_obj->hchnl_mgr = NULL;
+ dev_obj->hdeh_mgr = NULL;
+ dev_obj->lock_owner = NULL;
+ dev_obj->word_size = DSPWORDSIZE;
+ dev_obj->hdrv_obj = hdrv_obj;
+ dev_obj->dev_type = DSP_UNIT;
+ /* Store this Bridge's interface functions, based on its
+ * version. */
+ store_interface_fxns(drv_fxns,
+ &dev_obj->bridge_interface);
+
+ /* Call fxn_dev_create() to get the Bridge's device
+ * context handle. */
+ status = (dev_obj->bridge_interface.pfn_dev_create)
+ (&dev_obj->hbridge_context, dev_obj,
+ host_res);
+ /* Assert bridge_dev_create()'s ensure clause: */
+ DBC_ASSERT(status
+ || (dev_obj->hbridge_context != NULL));
+ } else {
+ status = -ENOMEM;
+ }
+ }
+ /* Attempt to create the COD manager for this device: */
+ if (!status)
+ status = init_cod_mgr(dev_obj);
+
+ /* Attempt to create the channel manager for this device: */
+ if (!status) {
+ mgr_attrs.max_channels = CHNL_MAXCHANNELS;
+ io_mgr_attrs.birq = host_res->birq_registers;
+ io_mgr_attrs.irq_shared =
+ (host_res->birq_attrib & CFG_IRQSHARED);
+ io_mgr_attrs.word_size = DSPWORDSIZE;
+ mgr_attrs.word_size = DSPWORDSIZE;
+ num_windows = host_res->num_mem_windows;
+ if (num_windows) {
+ /* Assume last memory window is for CHNL */
+ io_mgr_attrs.shm_base = host_res->dw_mem_base[1] +
+ host_res->dw_offset_for_monitor;
+ io_mgr_attrs.usm_length =
+ host_res->dw_mem_length[1] -
+ host_res->dw_offset_for_monitor;
+ } else {
+ io_mgr_attrs.shm_base = 0;
+ io_mgr_attrs.usm_length = 0;
+ pr_err("%s: No memory reserved for shared structures\n",
+ __func__);
+ }
+ status = chnl_create(&dev_obj->hchnl_mgr, dev_obj, &mgr_attrs);
+ if (status == -ENOSYS) {
+ /* It's OK for a device not to have a channel
+ * manager: */
+ status = 0;
+ }
+ /* Create CMM mgr even if Msg Mgr not impl. */
+ status = cmm_create(&dev_obj->hcmm_mgr,
+ (struct dev_object *)dev_obj, NULL);
+ /* Only create IO manager if we have a channel manager */
+ if (!status && dev_obj->hchnl_mgr) {
+ status = io_create(&dev_obj->hio_mgr, dev_obj,
+ &io_mgr_attrs);
+ }
+ /* Only create DEH manager if we have an IO manager */
+ if (!status) {
+ /* Instantiate the DEH module */
+ status = bridge_deh_create(&dev_obj->hdeh_mgr, dev_obj);
+ }
+ /* Create DMM mgr . */
+ status = dmm_create(&dev_obj->dmm_mgr,
+ (struct dev_object *)dev_obj, NULL);
+ }
+ /* Add the new DEV_Object to the global list: */
+ if (!status) {
+ lst_init_elem(&dev_obj->link);
+ status = drv_insert_dev_object(hdrv_obj, dev_obj);
+ }
+ /* Create the Processor List */
+ if (!status) {
+ dev_obj->proc_list = kzalloc(sizeof(struct lst_list),
+ GFP_KERNEL);
+ if (!(dev_obj->proc_list))
+ status = -EPERM;
+ else
+ INIT_LIST_HEAD(&dev_obj->proc_list->head);
+ }
+leave:
+ /* If all went well, return a handle to the dev object;
+ * else, cleanup and return NULL in the OUT parameter. */
+ if (!status) {
+ *device_obj = dev_obj;
+ } else {
+ if (dev_obj) {
+ kfree(dev_obj->proc_list);
+ if (dev_obj->cod_mgr)
+ cod_delete(dev_obj->cod_mgr);
+ if (dev_obj->dmm_mgr)
+ dmm_destroy(dev_obj->dmm_mgr);
+ kfree(dev_obj);
+ }
+
+ *device_obj = NULL;
+ }
+
+ DBC_ENSURE((!status && *device_obj) || (status && !*device_obj));
+ return status;
+}
+
+/*
+ * ======== dev_create2 ========
+ * Purpose:
+ * After successful loading of the image from api_init_complete2
+ * (PROC Auto_Start) or proc_load this fxn is called. This creates
+ * the Node Manager and updates the DEV Object.
+ */
+int dev_create2(struct dev_object *hdev_obj)
+{
+ int status = 0;
+ struct dev_object *dev_obj = hdev_obj;
+
+ DBC_REQUIRE(refs > 0);
+ DBC_REQUIRE(hdev_obj);
+
+ /* There can be only one Node Manager per DEV object */
+ DBC_ASSERT(!dev_obj->hnode_mgr);
+ status = node_create_mgr(&dev_obj->hnode_mgr, hdev_obj);
+ if (status)
+ dev_obj->hnode_mgr = NULL;
+
+ DBC_ENSURE((!status && dev_obj->hnode_mgr != NULL)
+ || (status && dev_obj->hnode_mgr == NULL));
+ return status;
+}
+
+/*
+ * ======== dev_destroy2 ========
+ * Purpose:
+ * Destroys the Node manager for this device.
+ */
+int dev_destroy2(struct dev_object *hdev_obj)
+{
+ int status = 0;
+ struct dev_object *dev_obj = hdev_obj;
+
+ DBC_REQUIRE(refs > 0);
+ DBC_REQUIRE(hdev_obj);
+
+ if (dev_obj->hnode_mgr) {
+ if (node_delete_mgr(dev_obj->hnode_mgr))
+ status = -EPERM;
+ else
+ dev_obj->hnode_mgr = NULL;
+
+ }
+
+ DBC_ENSURE((!status && dev_obj->hnode_mgr == NULL) || status);
+ return status;
+}
+
+/*
+ * ======== dev_destroy_device ========
+ * Purpose:
+ * Destroys the channel manager for this device, if any, calls
+ * bridge_dev_destroy(), and then attempts to unload the Bridge module.
+ */
+int dev_destroy_device(struct dev_object *hdev_obj)
+{
+ int status = 0;
+ struct dev_object *dev_obj = hdev_obj;
+
+ DBC_REQUIRE(refs > 0);
+
+ if (hdev_obj) {
+ if (dev_obj->cod_mgr) {
+ cod_delete(dev_obj->cod_mgr);
+ dev_obj->cod_mgr = NULL;
+ }
+
+ if (dev_obj->hnode_mgr) {
+ node_delete_mgr(dev_obj->hnode_mgr);
+ dev_obj->hnode_mgr = NULL;
+ }
+
+ /* Free the io, channel, and message managers for this board: */
+ if (dev_obj->hio_mgr) {
+ io_destroy(dev_obj->hio_mgr);
+ dev_obj->hio_mgr = NULL;
+ }
+ if (dev_obj->hchnl_mgr) {
+ chnl_destroy(dev_obj->hchnl_mgr);
+ dev_obj->hchnl_mgr = NULL;
+ }
+ if (dev_obj->hmsg_mgr) {
+ msg_delete(dev_obj->hmsg_mgr);
+ dev_obj->hmsg_mgr = NULL;
+ }
+
+ if (dev_obj->hdeh_mgr) {
+ /* Uninitialize DEH module. */
+ bridge_deh_destroy(dev_obj->hdeh_mgr);
+ dev_obj->hdeh_mgr = NULL;
+ }
+ if (dev_obj->hcmm_mgr) {
+ cmm_destroy(dev_obj->hcmm_mgr, true);
+ dev_obj->hcmm_mgr = NULL;
+ }
+
+ if (dev_obj->dmm_mgr) {
+ dmm_destroy(dev_obj->dmm_mgr);
+ dev_obj->dmm_mgr = NULL;
+ }
+
+ /* Call the driver's bridge_dev_destroy() function: */
+ /* Require of DevDestroy */
+ if (dev_obj->hbridge_context) {
+ status = (*dev_obj->bridge_interface.pfn_dev_destroy)
+ (dev_obj->hbridge_context);
+ dev_obj->hbridge_context = NULL;
+ } else
+ status = -EPERM;
+ if (!status) {
+ kfree(dev_obj->proc_list);
+ dev_obj->proc_list = NULL;
+
+ /* Remove this DEV_Object from the global list: */
+ drv_remove_dev_object(dev_obj->hdrv_obj, dev_obj);
+ /* Free The library * LDR_FreeModule
+ * (dev_obj->module_obj); */
+ /* Free this dev object: */
+ kfree(dev_obj);
+ dev_obj = NULL;
+ }
+ } else {
+ status = -EFAULT;
+ }
+
+ return status;
+}
+
+/*
+ * ======== dev_get_chnl_mgr ========
+ * Purpose:
+ * Retrieve the handle to the channel manager handle created for this
+ * device.
+ */
+int dev_get_chnl_mgr(struct dev_object *hdev_obj,
+ struct chnl_mgr **mgr)
+{
+ int status = 0;
+ struct dev_object *dev_obj = hdev_obj;
+
+ DBC_REQUIRE(refs > 0);
+ DBC_REQUIRE(mgr != NULL);
+
+ if (hdev_obj) {
+ *mgr = dev_obj->hchnl_mgr;
+ } else {
+ *mgr = NULL;
+ status = -EFAULT;
+ }
+
+ DBC_ENSURE(!status || (mgr != NULL && *mgr == NULL));
+ return status;
+}
+
+/*
+ * ======== dev_get_cmm_mgr ========
+ * Purpose:
+ * Retrieve the handle to the shared memory manager created for this
+ * device.
+ */
+int dev_get_cmm_mgr(struct dev_object *hdev_obj,
+ struct cmm_object **mgr)
+{
+ int status = 0;
+ struct dev_object *dev_obj = hdev_obj;
+
+ DBC_REQUIRE(refs > 0);
+ DBC_REQUIRE(mgr != NULL);
+
+ if (hdev_obj) {
+ *mgr = dev_obj->hcmm_mgr;
+ } else {
+ *mgr = NULL;
+ status = -EFAULT;
+ }
+
+ DBC_ENSURE(!status || (mgr != NULL && *mgr == NULL));
+ return status;
+}
+
+/*
+ * ======== dev_get_dmm_mgr ========
+ * Purpose:
+ * Retrieve the handle to the dynamic memory manager created for this
+ * device.
+ */
+int dev_get_dmm_mgr(struct dev_object *hdev_obj,
+ struct dmm_object **mgr)
+{
+ int status = 0;
+ struct dev_object *dev_obj = hdev_obj;
+
+ DBC_REQUIRE(refs > 0);
+ DBC_REQUIRE(mgr != NULL);
+
+ if (hdev_obj) {
+ *mgr = dev_obj->dmm_mgr;
+ } else {
+ *mgr = NULL;
+ status = -EFAULT;
+ }
+
+ DBC_ENSURE(!status || (mgr != NULL && *mgr == NULL));
+ return status;
+}
+
+/*
+ * ======== dev_get_cod_mgr ========
+ * Purpose:
+ * Retrieve the COD manager create for this device.
+ */
+int dev_get_cod_mgr(struct dev_object *hdev_obj,
+ struct cod_manager **cod_mgr)
+{
+ int status = 0;
+ struct dev_object *dev_obj = hdev_obj;
+
+ DBC_REQUIRE(refs > 0);
+ DBC_REQUIRE(cod_mgr != NULL);
+
+ if (hdev_obj) {
+ *cod_mgr = dev_obj->cod_mgr;
+ } else {
+ *cod_mgr = NULL;
+ status = -EFAULT;
+ }
+
+ DBC_ENSURE(!status || (cod_mgr != NULL && *cod_mgr == NULL));
+ return status;
+}
+
+/*
+ * ========= dev_get_deh_mgr ========
+ */
+int dev_get_deh_mgr(struct dev_object *hdev_obj,
+ struct deh_mgr **deh_manager)
+{
+ int status = 0;
+
+ DBC_REQUIRE(refs > 0);
+ DBC_REQUIRE(deh_manager != NULL);
+ DBC_REQUIRE(hdev_obj);
+ if (hdev_obj) {
+ *deh_manager = hdev_obj->hdeh_mgr;
+ } else {
+ *deh_manager = NULL;
+ status = -EFAULT;
+ }
+ return status;
+}
+
+/*
+ * ======== dev_get_dev_node ========
+ * Purpose:
+ * Retrieve the platform specific device ID for this device.
+ */
+int dev_get_dev_node(struct dev_object *hdev_obj,
+ struct cfg_devnode **dev_nde)
+{
+ int status = 0;
+ struct dev_object *dev_obj = hdev_obj;
+
+ DBC_REQUIRE(refs > 0);
+ DBC_REQUIRE(dev_nde != NULL);
+
+ if (hdev_obj) {
+ *dev_nde = dev_obj->dev_node_obj;
+ } else {
+ *dev_nde = NULL;
+ status = -EFAULT;
+ }
+
+ DBC_ENSURE(!status || (dev_nde != NULL && *dev_nde == NULL));
+ return status;
+}
+
+/*
+ * ======== dev_get_first ========
+ * Purpose:
+ * Retrieve the first Device Object handle from an internal linked list
+ * DEV_OBJECTs maintained by DEV.
+ */
+struct dev_object *dev_get_first(void)
+{
+ struct dev_object *dev_obj = NULL;
+
+ dev_obj = (struct dev_object *)drv_get_first_dev_object();
+
+ return dev_obj;
+}
+
+/*
+ * ======== dev_get_intf_fxns ========
+ * Purpose:
+ * Retrieve the Bridge interface function structure for the loaded driver.
+ * if_fxns != NULL.
+ */
+int dev_get_intf_fxns(struct dev_object *hdev_obj,
+ struct bridge_drv_interface **if_fxns)
+{
+ int status = 0;
+ struct dev_object *dev_obj = hdev_obj;
+
+ DBC_REQUIRE(refs > 0);
+ DBC_REQUIRE(if_fxns != NULL);
+
+ if (hdev_obj) {
+ *if_fxns = &dev_obj->bridge_interface;
+ } else {
+ *if_fxns = NULL;
+ status = -EFAULT;
+ }
+
+ DBC_ENSURE(!status || ((if_fxns != NULL) && (*if_fxns == NULL)));
+ return status;
+}
+
+/*
+ * ========= dev_get_io_mgr ========
+ */
+int dev_get_io_mgr(struct dev_object *hdev_obj,
+ struct io_mgr **io_man)
+{
+ int status = 0;
+
+ DBC_REQUIRE(refs > 0);
+ DBC_REQUIRE(io_man != NULL);
+ DBC_REQUIRE(hdev_obj);
+
+ if (hdev_obj) {
+ *io_man = hdev_obj->hio_mgr;
+ } else {
+ *io_man = NULL;
+ status = -EFAULT;
+ }
+
+ return status;
+}
+
+/*
+ * ======== dev_get_next ========
+ * Purpose:
+ * Retrieve the next Device Object handle from an internal linked list
+ * of DEV_OBJECTs maintained by DEV, after having previously called
+ * dev_get_first() and zero or more dev_get_next
+ */
+struct dev_object *dev_get_next(struct dev_object *hdev_obj)
+{
+ struct dev_object *next_dev_object = NULL;
+
+ if (hdev_obj) {
+ next_dev_object = (struct dev_object *)
+ drv_get_next_dev_object((u32) hdev_obj);
+ }
+
+ return next_dev_object;
+}
+
+/*
+ * ========= dev_get_msg_mgr ========
+ */
+void dev_get_msg_mgr(struct dev_object *hdev_obj, struct msg_mgr **msg_man)
+{
+ DBC_REQUIRE(refs > 0);
+ DBC_REQUIRE(msg_man != NULL);
+ DBC_REQUIRE(hdev_obj);
+
+ *msg_man = hdev_obj->hmsg_mgr;
+}
+
+/*
+ * ======== dev_get_node_manager ========
+ * Purpose:
+ * Retrieve the Node Manager Handle
+ */
+int dev_get_node_manager(struct dev_object *hdev_obj,
+ struct node_mgr **node_man)
+{
+ int status = 0;
+ struct dev_object *dev_obj = hdev_obj;
+
+ DBC_REQUIRE(refs > 0);
+ DBC_REQUIRE(node_man != NULL);
+
+ if (hdev_obj) {
+ *node_man = dev_obj->hnode_mgr;
+ } else {
+ *node_man = NULL;
+ status = -EFAULT;
+ }
+
+ DBC_ENSURE(!status || (node_man != NULL && *node_man == NULL));
+ return status;
+}
+
+/*
+ * ======== dev_get_symbol ========
+ */
+int dev_get_symbol(struct dev_object *hdev_obj,
+ const char *str_sym, u32 * pul_value)
+{
+ int status = 0;
+ struct cod_manager *cod_mgr;
+
+ DBC_REQUIRE(refs > 0);
+ DBC_REQUIRE(str_sym != NULL && pul_value != NULL);
+
+ if (hdev_obj) {
+ status = dev_get_cod_mgr(hdev_obj, &cod_mgr);
+ if (cod_mgr)
+ status = cod_get_sym_value(cod_mgr, (char *)str_sym,
+ pul_value);
+ else
+ status = -EFAULT;
+ }
+
+ return status;
+}
+
+/*
+ * ======== dev_get_bridge_context ========
+ * Purpose:
+ * Retrieve the Bridge Context handle, as returned by the
+ * bridge_dev_create fxn.
+ */
+int dev_get_bridge_context(struct dev_object *hdev_obj,
+ struct bridge_dev_context **phbridge_context)
+{
+ int status = 0;
+ struct dev_object *dev_obj = hdev_obj;
+
+ DBC_REQUIRE(refs > 0);
+ DBC_REQUIRE(phbridge_context != NULL);
+
+ if (hdev_obj) {
+ *phbridge_context = dev_obj->hbridge_context;
+ } else {
+ *phbridge_context = NULL;
+ status = -EFAULT;
+ }
+
+ DBC_ENSURE(!status || ((phbridge_context != NULL) &&
+ (*phbridge_context == NULL)));
+ return status;
+}
+
+/*
+ * ======== dev_exit ========
+ * Purpose:
+ * Decrement reference count, and free resources when reference count is
+ * 0.
+ */
+void dev_exit(void)
+{
+ DBC_REQUIRE(refs > 0);
+
+ refs--;
+
+ if (refs == 0) {
+ cmm_exit();
+ dmm_exit();
+ }
+
+ DBC_ENSURE(refs >= 0);
+}
+
+/*
+ * ======== dev_init ========
+ * Purpose:
+ * Initialize DEV's private state, keeping a reference count on each call.
+ */
+bool dev_init(void)
+{
+ bool cmm_ret, dmm_ret, ret = true;
+
+ DBC_REQUIRE(refs >= 0);
+
+ if (refs == 0) {
+ cmm_ret = cmm_init();
+ dmm_ret = dmm_init();
+
+ ret = cmm_ret && dmm_ret;
+
+ if (!ret) {
+ if (cmm_ret)
+ cmm_exit();
+
+ if (dmm_ret)
+ dmm_exit();
+
+ }
+ }
+
+ if (ret)
+ refs++;
+
+ DBC_ENSURE((ret && (refs > 0)) || (!ret && (refs >= 0)));
+
+ return ret;
+}
+
+/*
+ * ======== dev_notify_clients ========
+ * Purpose:
+ * Notify all clients of this device of a change in device status.
+ */
+int dev_notify_clients(struct dev_object *hdev_obj, u32 ret)
+{
+ int status = 0;
+
+ struct dev_object *dev_obj = hdev_obj;
+ void *proc_obj;
+
+ for (proc_obj = (void *)lst_first(dev_obj->proc_list);
+ proc_obj != NULL;
+ proc_obj = (void *)lst_next(dev_obj->proc_list,
+ (struct list_head *)proc_obj))
+ proc_notify_clients(proc_obj, (u32) ret);
+
+ return status;
+}
+
+/*
+ * ======== dev_remove_device ========
+ */
+int dev_remove_device(struct cfg_devnode *dev_node_obj)
+{
+ struct dev_object *hdev_obj; /* handle to device object */
+ int status = 0;
+ struct dev_object *dev_obj;
+
+ /* Retrieve the device object handle originaly stored with
+ * the dev_node: */
+ status = cfg_get_dev_object(dev_node_obj, (u32 *) &hdev_obj);
+ if (!status) {
+ /* Remove the Processor List */
+ dev_obj = (struct dev_object *)hdev_obj;
+ /* Destroy the device object. */
+ status = dev_destroy_device(hdev_obj);
+ }
+
+ return status;
+}
+
+/*
+ * ======== dev_set_chnl_mgr ========
+ * Purpose:
+ * Set the channel manager for this device.
+ */
+int dev_set_chnl_mgr(struct dev_object *hdev_obj,
+ struct chnl_mgr *hmgr)
+{
+ int status = 0;
+ struct dev_object *dev_obj = hdev_obj;
+
+ DBC_REQUIRE(refs > 0);
+
+ if (hdev_obj)
+ dev_obj->hchnl_mgr = hmgr;
+ else
+ status = -EFAULT;
+
+ DBC_ENSURE(status || (dev_obj->hchnl_mgr == hmgr));
+ return status;
+}
+
+/*
+ * ======== dev_set_msg_mgr ========
+ * Purpose:
+ * Set the message manager for this device.
+ */
+void dev_set_msg_mgr(struct dev_object *hdev_obj, struct msg_mgr *hmgr)
+{
+ DBC_REQUIRE(refs > 0);
+ DBC_REQUIRE(hdev_obj);
+
+ hdev_obj->hmsg_mgr = hmgr;
+}
+
+/*
+ * ======== dev_start_device ========
+ * Purpose:
+ * Initializes the new device with the BRIDGE environment.
+ */
+int dev_start_device(struct cfg_devnode *dev_node_obj)
+{
+ struct dev_object *hdev_obj = NULL; /* handle to 'Bridge Device */
+ /* Bridge driver filename */
+ char bridge_file_name[CFG_MAXSEARCHPATHLEN] = "UMA";
+ int status;
+ struct mgr_object *hmgr_obj = NULL;
+
+ DBC_REQUIRE(refs > 0);
+
+ /* Given all resources, create a device object. */
+ status = dev_create_device(&hdev_obj, bridge_file_name,
+ dev_node_obj);
+ if (!status) {
+ /* Store away the hdev_obj with the DEVNODE */
+ status = cfg_set_dev_object(dev_node_obj, (u32) hdev_obj);
+ if (status) {
+ /* Clean up */
+ dev_destroy_device(hdev_obj);
+ hdev_obj = NULL;
+ }
+ }
+ if (!status) {
+ /* Create the Manager Object */
+ status = mgr_create(&hmgr_obj, dev_node_obj);
+ }
+ if (status) {
+ if (hdev_obj)
+ dev_destroy_device(hdev_obj);
+
+ /* Ensure the device extension is NULL */
+ cfg_set_dev_object(dev_node_obj, 0L);
+ }
+
+ return status;
+}
+
+/*
+ * ======== fxn_not_implemented ========
+ * Purpose:
+ * Takes the place of a Bridge Null Function.
+ * Parameters:
+ * Multiple, optional.
+ * Returns:
+ * -ENOSYS: Always.
+ */
+static int fxn_not_implemented(int arg, ...)
+{
+ return -ENOSYS;
+}
+
+/*
+ * ======== init_cod_mgr ========
+ * Purpose:
+ * Create a COD manager for this device.
+ * Parameters:
+ * dev_obj: Pointer to device object created with
+ * dev_create_device()
+ * Returns:
+ * 0: Success.
+ * -EFAULT: Invalid hdev_obj.
+ * Requires:
+ * Should only be called once by dev_create_device() for a given DevObject.
+ * Ensures:
+ */
+static int init_cod_mgr(struct dev_object *dev_obj)
+{
+ int status = 0;
+ char *sz_dummy_file = "dummy";
+
+ DBC_REQUIRE(refs > 0);
+ DBC_REQUIRE(!dev_obj || (dev_obj->cod_mgr == NULL));
+
+ status = cod_create(&dev_obj->cod_mgr, sz_dummy_file, NULL);
+
+ return status;
+}
+
+/*
+ * ======== dev_insert_proc_object ========
+ * Purpose:
+ * Insert a ProcObject into the list maintained by DEV.
+ * Parameters:
+ * p_proc_object: Ptr to ProcObject to insert.
+ * dev_obj: Ptr to Dev Object where the list is.
+ * already_attached: Ptr to return the bool
+ * Returns:
+ * 0: If successful.
+ * Requires:
+ * List Exists
+ * hdev_obj is Valid handle
+ * DEV Initialized
+ * already_attached != NULL
+ * proc_obj != 0
+ * Ensures:
+ * 0 and List is not Empty.
+ */
+int dev_insert_proc_object(struct dev_object *hdev_obj,
+ u32 proc_obj, bool *already_attached)
+{
+ int status = 0;
+ struct dev_object *dev_obj = (struct dev_object *)hdev_obj;
+
+ DBC_REQUIRE(refs > 0);
+ DBC_REQUIRE(dev_obj);
+ DBC_REQUIRE(proc_obj != 0);
+ DBC_REQUIRE(dev_obj->proc_list != NULL);
+ DBC_REQUIRE(already_attached != NULL);
+ if (!LST_IS_EMPTY(dev_obj->proc_list))
+ *already_attached = true;
+
+ /* Add DevObject to tail. */
+ lst_put_tail(dev_obj->proc_list, (struct list_head *)proc_obj);
+
+ DBC_ENSURE(!status && !LST_IS_EMPTY(dev_obj->proc_list));
+
+ return status;
+}
+
+/*
+ * ======== dev_remove_proc_object ========
+ * Purpose:
+ * Search for and remove a Proc object from the given list maintained
+ * by the DEV
+ * Parameters:
+ * p_proc_object: Ptr to ProcObject to insert.
+ * dev_obj Ptr to Dev Object where the list is.
+ * Returns:
+ * 0: If successful.
+ * Requires:
+ * List exists and is not empty
+ * proc_obj != 0
+ * hdev_obj is a valid Dev handle.
+ * Ensures:
+ * Details:
+ * List will be deleted when the DEV is destroyed.
+ */
+int dev_remove_proc_object(struct dev_object *hdev_obj, u32 proc_obj)
+{
+ int status = -EPERM;
+ struct list_head *cur_elem;
+ struct dev_object *dev_obj = (struct dev_object *)hdev_obj;
+
+ DBC_REQUIRE(dev_obj);
+ DBC_REQUIRE(proc_obj != 0);
+ DBC_REQUIRE(dev_obj->proc_list != NULL);
+ DBC_REQUIRE(!LST_IS_EMPTY(dev_obj->proc_list));
+
+ /* Search list for dev_obj: */
+ for (cur_elem = lst_first(dev_obj->proc_list); cur_elem != NULL;
+ cur_elem = lst_next(dev_obj->proc_list, cur_elem)) {
+ /* If found, remove it. */
+ if ((u32) cur_elem == proc_obj) {
+ lst_remove_elem(dev_obj->proc_list, cur_elem);
+ status = 0;
+ break;
+ }
+ }
+
+ return status;
+}
+
+int dev_get_dev_type(struct dev_object *device_obj, u8 *dev_type)
+{
+ int status = 0;
+ struct dev_object *dev_obj = (struct dev_object *)device_obj;
+
+ *dev_type = dev_obj->dev_type;
+
+ return status;
+}
+
+/*
+ * ======== store_interface_fxns ========
+ * Purpose:
+ * Copy the Bridge's interface functions into the device object,
+ * ensuring that fxn_not_implemented() is set for:
+ *
+ * 1. All Bridge function pointers which are NULL; and
+ * 2. All function slots in the struct dev_object structure which have no
+ * corresponding slots in the the Bridge's interface, because the Bridge
+ * is of an *older* version.
+ * Parameters:
+ * intf_fxns: Interface fxn Structure of the Bridge's Dev Object.
+ * drv_fxns: Interface Fxns offered by the Bridge during DEV_Create().
+ * Returns:
+ * Requires:
+ * Input pointers are valid.
+ * Bridge driver is *not* written for a newer DSP API.
+ * Ensures:
+ * All function pointers in the dev object's fxn interface are not NULL.
+ */
+static void store_interface_fxns(struct bridge_drv_interface *drv_fxns,
+ struct bridge_drv_interface *intf_fxns)
+{
+ u32 bridge_version;
+
+ /* Local helper macro: */
+#define STORE_FXN(cast, pfn) \
+ (intf_fxns->pfn = ((drv_fxns->pfn != NULL) ? drv_fxns->pfn : \
+ (cast)fxn_not_implemented))
+
+ DBC_REQUIRE(intf_fxns != NULL);
+ DBC_REQUIRE(drv_fxns != NULL);
+ DBC_REQUIRE(MAKEVERSION(drv_fxns->brd_api_major_version,
+ drv_fxns->brd_api_minor_version) <= BRD_API_VERSION);
+ bridge_version = MAKEVERSION(drv_fxns->brd_api_major_version,
+ drv_fxns->brd_api_minor_version);
+ intf_fxns->brd_api_major_version = drv_fxns->brd_api_major_version;
+ intf_fxns->brd_api_minor_version = drv_fxns->brd_api_minor_version;
+ /* Install functions up to DSP API version .80 (first alpha): */
+ if (bridge_version > 0) {
+ STORE_FXN(fxn_dev_create, pfn_dev_create);
+ STORE_FXN(fxn_dev_destroy, pfn_dev_destroy);
+ STORE_FXN(fxn_dev_ctrl, pfn_dev_cntrl);
+ STORE_FXN(fxn_brd_monitor, pfn_brd_monitor);
+ STORE_FXN(fxn_brd_start, pfn_brd_start);
+ STORE_FXN(fxn_brd_stop, pfn_brd_stop);
+ STORE_FXN(fxn_brd_status, pfn_brd_status);
+ STORE_FXN(fxn_brd_read, pfn_brd_read);
+ STORE_FXN(fxn_brd_write, pfn_brd_write);
+ STORE_FXN(fxn_brd_setstate, pfn_brd_set_state);
+ STORE_FXN(fxn_brd_memcopy, pfn_brd_mem_copy);
+ STORE_FXN(fxn_brd_memwrite, pfn_brd_mem_write);
+ STORE_FXN(fxn_brd_memmap, pfn_brd_mem_map);
+ STORE_FXN(fxn_brd_memunmap, pfn_brd_mem_un_map);
+ STORE_FXN(fxn_chnl_create, pfn_chnl_create);
+ STORE_FXN(fxn_chnl_destroy, pfn_chnl_destroy);
+ STORE_FXN(fxn_chnl_open, pfn_chnl_open);
+ STORE_FXN(fxn_chnl_close, pfn_chnl_close);
+ STORE_FXN(fxn_chnl_addioreq, pfn_chnl_add_io_req);
+ STORE_FXN(fxn_chnl_getioc, pfn_chnl_get_ioc);
+ STORE_FXN(fxn_chnl_cancelio, pfn_chnl_cancel_io);
+ STORE_FXN(fxn_chnl_flushio, pfn_chnl_flush_io);
+ STORE_FXN(fxn_chnl_getinfo, pfn_chnl_get_info);
+ STORE_FXN(fxn_chnl_getmgrinfo, pfn_chnl_get_mgr_info);
+ STORE_FXN(fxn_chnl_idle, pfn_chnl_idle);
+ STORE_FXN(fxn_chnl_registernotify, pfn_chnl_register_notify);
+ STORE_FXN(fxn_io_create, pfn_io_create);
+ STORE_FXN(fxn_io_destroy, pfn_io_destroy);
+ STORE_FXN(fxn_io_onloaded, pfn_io_on_loaded);
+ STORE_FXN(fxn_io_getprocload, pfn_io_get_proc_load);
+ STORE_FXN(fxn_msg_create, pfn_msg_create);
+ STORE_FXN(fxn_msg_createqueue, pfn_msg_create_queue);
+ STORE_FXN(fxn_msg_delete, pfn_msg_delete);
+ STORE_FXN(fxn_msg_deletequeue, pfn_msg_delete_queue);
+ STORE_FXN(fxn_msg_get, pfn_msg_get);
+ STORE_FXN(fxn_msg_put, pfn_msg_put);
+ STORE_FXN(fxn_msg_registernotify, pfn_msg_register_notify);
+ STORE_FXN(fxn_msg_setqueueid, pfn_msg_set_queue_id);
+ }
+ /* Add code for any additional functions in newerBridge versions here */
+ /* Ensure postcondition: */
+ DBC_ENSURE(intf_fxns->pfn_dev_create != NULL);
+ DBC_ENSURE(intf_fxns->pfn_dev_destroy != NULL);
+ DBC_ENSURE(intf_fxns->pfn_dev_cntrl != NULL);
+ DBC_ENSURE(intf_fxns->pfn_brd_monitor != NULL);
+ DBC_ENSURE(intf_fxns->pfn_brd_start != NULL);
+ DBC_ENSURE(intf_fxns->pfn_brd_stop != NULL);
+ DBC_ENSURE(intf_fxns->pfn_brd_status != NULL);
+ DBC_ENSURE(intf_fxns->pfn_brd_read != NULL);
+ DBC_ENSURE(intf_fxns->pfn_brd_write != NULL);
+ DBC_ENSURE(intf_fxns->pfn_chnl_create != NULL);
+ DBC_ENSURE(intf_fxns->pfn_chnl_destroy != NULL);
+ DBC_ENSURE(intf_fxns->pfn_chnl_open != NULL);
+ DBC_ENSURE(intf_fxns->pfn_chnl_close != NULL);
+ DBC_ENSURE(intf_fxns->pfn_chnl_add_io_req != NULL);
+ DBC_ENSURE(intf_fxns->pfn_chnl_get_ioc != NULL);
+ DBC_ENSURE(intf_fxns->pfn_chnl_cancel_io != NULL);
+ DBC_ENSURE(intf_fxns->pfn_chnl_flush_io != NULL);
+ DBC_ENSURE(intf_fxns->pfn_chnl_get_info != NULL);
+ DBC_ENSURE(intf_fxns->pfn_chnl_get_mgr_info != NULL);
+ DBC_ENSURE(intf_fxns->pfn_chnl_idle != NULL);
+ DBC_ENSURE(intf_fxns->pfn_chnl_register_notify != NULL);
+ DBC_ENSURE(intf_fxns->pfn_io_create != NULL);
+ DBC_ENSURE(intf_fxns->pfn_io_destroy != NULL);
+ DBC_ENSURE(intf_fxns->pfn_io_on_loaded != NULL);
+ DBC_ENSURE(intf_fxns->pfn_io_get_proc_load != NULL);
+ DBC_ENSURE(intf_fxns->pfn_msg_set_queue_id != NULL);
+
+#undef STORE_FXN
+}
diff --git a/drivers/staging/tidspbridge/pmgr/dmm.c b/drivers/staging/tidspbridge/pmgr/dmm.c
new file mode 100644
index 00000000000..8685233d762
--- /dev/null
+++ b/drivers/staging/tidspbridge/pmgr/dmm.c
@@ -0,0 +1,533 @@
+/*
+ * dmm.c
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * The Dynamic Memory Manager (DMM) module manages the DSP Virtual address
+ * space that can be directly mapped to any MPU buffer or memory region
+ *
+ * Notes:
+ * Region: Generic memory entitiy having a start address and a size
+ * Chunk: Reserved region
+ *
+ * Copyright (C) 2005-2006 Texas Instruments, Inc.
+ *
+ * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+#include <linux/types.h>
+
+/* ----------------------------------- Host OS */
+#include <dspbridge/host_os.h>
+
+/* ----------------------------------- DSP/BIOS Bridge */
+#include <dspbridge/dbdefs.h>
+
+/* ----------------------------------- Trace & Debug */
+#include <dspbridge/dbc.h>
+
+/* ----------------------------------- OS Adaptation Layer */
+#include <dspbridge/sync.h>
+
+/* ----------------------------------- Platform Manager */
+#include <dspbridge/dev.h>
+#include <dspbridge/proc.h>
+
+/* ----------------------------------- This */
+#include <dspbridge/dmm.h>
+
+/* ----------------------------------- Defines, Data Structures, Typedefs */
+#define DMM_ADDR_VIRTUAL(a) \
+ (((struct map_page *)(a) - virtual_mapping_table) * PG_SIZE4K +\
+ dyn_mem_map_beg)
+#define DMM_ADDR_TO_INDEX(a) (((a) - dyn_mem_map_beg) / PG_SIZE4K)
+
+/* DMM Mgr */
+struct dmm_object {
+ /* Dmm Lock is used to serialize access mem manager for
+ * multi-threads. */
+ spinlock_t dmm_lock; /* Lock to access dmm mgr */
+};
+
+/* ----------------------------------- Globals */
+static u32 refs; /* module reference count */
+struct map_page {
+ u32 region_size:15;
+ u32 mapped_size:15;
+ u32 reserved:1;
+ u32 mapped:1;
+};
+
+/* Create the free list */
+static struct map_page *virtual_mapping_table;
+static u32 free_region; /* The index of free region */
+static u32 free_size;
+static u32 dyn_mem_map_beg; /* The Beginning of dynamic memory mapping */
+static u32 table_size; /* The size of virt and phys pages tables */
+
+/* ----------------------------------- Function Prototypes */
+static struct map_page *get_region(u32 addr);
+static struct map_page *get_free_region(u32 len);
+static struct map_page *get_mapped_region(u32 addrs);
+
+/* ======== dmm_create_tables ========
+ * Purpose:
+ * Create table to hold the information of physical address
+ * the buffer pages that is passed by the user, and the table
+ * to hold the information of the virtual memory that is reserved
+ * for DSP.
+ */
+int dmm_create_tables(struct dmm_object *dmm_mgr, u32 addr, u32 size)
+{
+ struct dmm_object *dmm_obj = (struct dmm_object *)dmm_mgr;
+ int status = 0;
+
+ status = dmm_delete_tables(dmm_obj);
+ if (!status) {
+ dyn_mem_map_beg = addr;
+ table_size = PG_ALIGN_HIGH(size, PG_SIZE4K) / PG_SIZE4K;
+ /* Create the free list */
+ virtual_mapping_table = __vmalloc(table_size *
+ sizeof(struct map_page), GFP_KERNEL |
+ __GFP_HIGHMEM | __GFP_ZERO, PAGE_KERNEL);
+ if (virtual_mapping_table == NULL)
+ status = -ENOMEM;
+ else {
+ /* On successful allocation,
+ * all entries are zero ('free') */
+ free_region = 0;
+ free_size = table_size * PG_SIZE4K;
+ virtual_mapping_table[0].region_size = table_size;
+ }
+ }
+
+ if (status)
+ pr_err("%s: failure, status 0x%x\n", __func__, status);
+
+ return status;
+}
+
+/*
+ * ======== dmm_create ========
+ * Purpose:
+ * Create a dynamic memory manager object.
+ */
+int dmm_create(struct dmm_object **dmm_manager,
+ struct dev_object *hdev_obj,
+ const struct dmm_mgrattrs *mgr_attrts)
+{
+ struct dmm_object *dmm_obj = NULL;
+ int status = 0;
+ DBC_REQUIRE(refs > 0);
+ DBC_REQUIRE(dmm_manager != NULL);
+
+ *dmm_manager = NULL;
+ /* create, zero, and tag a cmm mgr object */
+ dmm_obj = kzalloc(sizeof(struct dmm_object), GFP_KERNEL);
+ if (dmm_obj != NULL) {
+ spin_lock_init(&dmm_obj->dmm_lock);
+ *dmm_manager = dmm_obj;
+ } else {
+ status = -ENOMEM;
+ }
+
+ return status;
+}
+
+/*
+ * ======== dmm_destroy ========
+ * Purpose:
+ * Release the communication memory manager resources.
+ */
+int dmm_destroy(struct dmm_object *dmm_mgr)
+{
+ struct dmm_object *dmm_obj = (struct dmm_object *)dmm_mgr;
+ int status = 0;
+
+ DBC_REQUIRE(refs > 0);
+ if (dmm_mgr) {
+ status = dmm_delete_tables(dmm_obj);
+ if (!status)
+ kfree(dmm_obj);
+ } else
+ status = -EFAULT;
+
+ return status;
+}
+
+/*
+ * ======== dmm_delete_tables ========
+ * Purpose:
+ * Delete DMM Tables.
+ */
+int dmm_delete_tables(struct dmm_object *dmm_mgr)
+{
+ int status = 0;
+
+ DBC_REQUIRE(refs > 0);
+ /* Delete all DMM tables */
+ if (dmm_mgr)
+ vfree(virtual_mapping_table);
+ else
+ status = -EFAULT;
+ return status;
+}
+
+/*
+ * ======== dmm_exit ========
+ * Purpose:
+ * Discontinue usage of module; free resources when reference count
+ * reaches 0.
+ */
+void dmm_exit(void)
+{
+ DBC_REQUIRE(refs > 0);
+
+ refs--;
+}
+
+/*
+ * ======== dmm_get_handle ========
+ * Purpose:
+ * Return the dynamic memory manager object for this device.
+ * This is typically called from the client process.
+ */
+int dmm_get_handle(void *hprocessor, struct dmm_object **dmm_manager)
+{
+ int status = 0;
+ struct dev_object *hdev_obj;
+
+ DBC_REQUIRE(refs > 0);
+ DBC_REQUIRE(dmm_manager != NULL);
+ if (hprocessor != NULL)
+ status = proc_get_dev_object(hprocessor, &hdev_obj);
+ else
+ hdev_obj = dev_get_first(); /* default */
+
+ if (!status)
+ status = dev_get_dmm_mgr(hdev_obj, dmm_manager);
+
+ return status;
+}
+
+/*
+ * ======== dmm_init ========
+ * Purpose:
+ * Initializes private state of DMM module.
+ */
+bool dmm_init(void)
+{
+ bool ret = true;
+
+ DBC_REQUIRE(refs >= 0);
+
+ if (ret)
+ refs++;
+
+ DBC_ENSURE((ret && (refs > 0)) || (!ret && (refs >= 0)));
+
+ virtual_mapping_table = NULL;
+ table_size = 0;
+
+ return ret;
+}
+
+/*
+ * ======== dmm_map_memory ========
+ * Purpose:
+ * Add a mapping block to the reserved chunk. DMM assumes that this block
+ * will be mapped in the DSP/IVA's address space. DMM returns an error if a
+ * mapping overlaps another one. This function stores the info that will be
+ * required later while unmapping the block.
+ */
+int dmm_map_memory(struct dmm_object *dmm_mgr, u32 addr, u32 size)
+{
+ struct dmm_object *dmm_obj = (struct dmm_object *)dmm_mgr;
+ struct map_page *chunk;
+ int status = 0;
+
+ spin_lock(&dmm_obj->dmm_lock);
+ /* Find the Reserved memory chunk containing the DSP block to
+ * be mapped */
+ chunk = (struct map_page *)get_region(addr);
+ if (chunk != NULL) {
+ /* Mark the region 'mapped', leave the 'reserved' info as-is */
+ chunk->mapped = true;
+ chunk->mapped_size = (size / PG_SIZE4K);
+ } else
+ status = -ENOENT;
+ spin_unlock(&dmm_obj->dmm_lock);
+
+ dev_dbg(bridge, "%s dmm_mgr %p, addr %x, size %x\n\tstatus %x, "
+ "chunk %p", __func__, dmm_mgr, addr, size, status, chunk);
+
+ return status;
+}
+
+/*
+ * ======== dmm_reserve_memory ========
+ * Purpose:
+ * Reserve a chunk of virtually contiguous DSP/IVA address space.
+ */
+int dmm_reserve_memory(struct dmm_object *dmm_mgr, u32 size,
+ u32 *prsv_addr)
+{
+ int status = 0;
+ struct dmm_object *dmm_obj = (struct dmm_object *)dmm_mgr;
+ struct map_page *node;
+ u32 rsv_addr = 0;
+ u32 rsv_size = 0;
+
+ spin_lock(&dmm_obj->dmm_lock);
+
+ /* Try to get a DSP chunk from the free list */
+ node = get_free_region(size);
+ if (node != NULL) {
+ /* DSP chunk of given size is available. */
+ rsv_addr = DMM_ADDR_VIRTUAL(node);
+ /* Calculate the number entries to use */
+ rsv_size = size / PG_SIZE4K;
+ if (rsv_size < node->region_size) {
+ /* Mark remainder of free region */
+ node[rsv_size].mapped = false;
+ node[rsv_size].reserved = false;
+ node[rsv_size].region_size =
+ node->region_size - rsv_size;
+ node[rsv_size].mapped_size = 0;
+ }
+ /* get_region will return first fit chunk. But we only use what
+ is requested. */
+ node->mapped = false;
+ node->reserved = true;
+ node->region_size = rsv_size;
+ node->mapped_size = 0;
+ /* Return the chunk's starting address */
+ *prsv_addr = rsv_addr;
+ } else
+ /*dSP chunk of given size is not available */
+ status = -ENOMEM;
+
+ spin_unlock(&dmm_obj->dmm_lock);
+
+ dev_dbg(bridge, "%s dmm_mgr %p, size %x, prsv_addr %p\n\tstatus %x, "
+ "rsv_addr %x, rsv_size %x\n", __func__, dmm_mgr, size,
+ prsv_addr, status, rsv_addr, rsv_size);
+
+ return status;
+}
+
+/*
+ * ======== dmm_un_map_memory ========
+ * Purpose:
+ * Remove the mapped block from the reserved chunk.
+ */
+int dmm_un_map_memory(struct dmm_object *dmm_mgr, u32 addr, u32 *psize)
+{
+ struct dmm_object *dmm_obj = (struct dmm_object *)dmm_mgr;
+ struct map_page *chunk;
+ int status = 0;
+
+ spin_lock(&dmm_obj->dmm_lock);
+ chunk = get_mapped_region(addr);
+ if (chunk == NULL)
+ status = -ENOENT;
+
+ if (!status) {
+ /* Unmap the region */
+ *psize = chunk->mapped_size * PG_SIZE4K;
+ chunk->mapped = false;
+ chunk->mapped_size = 0;
+ }
+ spin_unlock(&dmm_obj->dmm_lock);
+
+ dev_dbg(bridge, "%s: dmm_mgr %p, addr %x, psize %p\n\tstatus %x, "
+ "chunk %p\n", __func__, dmm_mgr, addr, psize, status, chunk);
+
+ return status;
+}
+
+/*
+ * ======== dmm_un_reserve_memory ========
+ * Purpose:
+ * Free a chunk of reserved DSP/IVA address space.
+ */
+int dmm_un_reserve_memory(struct dmm_object *dmm_mgr, u32 rsv_addr)
+{
+ struct dmm_object *dmm_obj = (struct dmm_object *)dmm_mgr;
+ struct map_page *chunk;
+ u32 i;
+ int status = 0;
+ u32 chunk_size;
+
+ spin_lock(&dmm_obj->dmm_lock);
+
+ /* Find the chunk containing the reserved address */
+ chunk = get_mapped_region(rsv_addr);
+ if (chunk == NULL)
+ status = -ENOENT;
+
+ if (!status) {
+ /* Free all the mapped pages for this reserved region */
+ i = 0;
+ while (i < chunk->region_size) {
+ if (chunk[i].mapped) {
+ /* Remove mapping from the page tables. */
+ chunk_size = chunk[i].mapped_size;
+ /* Clear the mapping flags */
+ chunk[i].mapped = false;
+ chunk[i].mapped_size = 0;
+ i += chunk_size;
+ } else
+ i++;
+ }
+ /* Clear the flags (mark the region 'free') */
+ chunk->reserved = false;
+ /* NOTE: We do NOT coalesce free regions here.
+ * Free regions are coalesced in get_region(), as it traverses
+ *the whole mapping table
+ */
+ }
+ spin_unlock(&dmm_obj->dmm_lock);
+
+ dev_dbg(bridge, "%s: dmm_mgr %p, rsv_addr %x\n\tstatus %x chunk %p",
+ __func__, dmm_mgr, rsv_addr, status, chunk);
+
+ return status;
+}
+
+/*
+ * ======== get_region ========
+ * Purpose:
+ * Returns a region containing the specified memory region
+ */
+static struct map_page *get_region(u32 addr)
+{
+ struct map_page *curr_region = NULL;
+ u32 i = 0;
+
+ if (virtual_mapping_table != NULL) {
+ /* find page mapped by this address */
+ i = DMM_ADDR_TO_INDEX(addr);
+ if (i < table_size)
+ curr_region = virtual_mapping_table + i;
+ }
+
+ dev_dbg(bridge, "%s: curr_region %p, free_region %d, free_size %d\n",
+ __func__, curr_region, free_region, free_size);
+ return curr_region;
+}
+
+/*
+ * ======== get_free_region ========
+ * Purpose:
+ * Returns the requested free region
+ */
+static struct map_page *get_free_region(u32 len)
+{
+ struct map_page *curr_region = NULL;
+ u32 i = 0;
+ u32 region_size = 0;
+ u32 next_i = 0;
+
+ if (virtual_mapping_table == NULL)
+ return curr_region;
+ if (len > free_size) {
+ /* Find the largest free region
+ * (coalesce during the traversal) */
+ while (i < table_size) {
+ region_size = virtual_mapping_table[i].region_size;
+ next_i = i + region_size;
+ if (virtual_mapping_table[i].reserved == false) {
+ /* Coalesce, if possible */
+ if (next_i < table_size &&
+ virtual_mapping_table[next_i].reserved
+ == false) {
+ virtual_mapping_table[i].region_size +=
+ virtual_mapping_table
+ [next_i].region_size;
+ continue;
+ }
+ region_size *= PG_SIZE4K;
+ if (region_size > free_size) {
+ free_region = i;
+ free_size = region_size;
+ }
+ }
+ i = next_i;
+ }
+ }
+ if (len <= free_size) {
+ curr_region = virtual_mapping_table + free_region;
+ free_region += (len / PG_SIZE4K);
+ free_size -= len;
+ }
+ return curr_region;
+}
+
+/*
+ * ======== get_mapped_region ========
+ * Purpose:
+ * Returns the requestedmapped region
+ */
+static struct map_page *get_mapped_region(u32 addrs)
+{
+ u32 i = 0;
+ struct map_page *curr_region = NULL;
+
+ if (virtual_mapping_table == NULL)
+ return curr_region;
+
+ i = DMM_ADDR_TO_INDEX(addrs);
+ if (i < table_size && (virtual_mapping_table[i].mapped ||
+ virtual_mapping_table[i].reserved))
+ curr_region = virtual_mapping_table + i;
+ return curr_region;
+}
+
+#ifdef DSP_DMM_DEBUG
+u32 dmm_mem_map_dump(struct dmm_object *dmm_mgr)
+{
+ struct map_page *curr_node = NULL;
+ u32 i;
+ u32 freemem = 0;
+ u32 bigsize = 0;
+
+ spin_lock(&dmm_mgr->dmm_lock);
+
+ if (virtual_mapping_table != NULL) {
+ for (i = 0; i < table_size; i +=
+ virtual_mapping_table[i].region_size) {
+ curr_node = virtual_mapping_table + i;
+ if (curr_node->reserved) {
+ /*printk("RESERVED size = 0x%x, "
+ "Map size = 0x%x\n",
+ (curr_node->region_size * PG_SIZE4K),
+ (curr_node->mapped == false) ? 0 :
+ (curr_node->mapped_size * PG_SIZE4K));
+ */
+ } else {
+/* printk("UNRESERVED size = 0x%x\n",
+ (curr_node->region_size * PG_SIZE4K));
+ */
+ freemem += (curr_node->region_size * PG_SIZE4K);
+ if (curr_node->region_size > bigsize)
+ bigsize = curr_node->region_size;
+ }
+ }
+ }
+ spin_unlock(&dmm_mgr->dmm_lock);
+ printk(KERN_INFO "Total DSP VA FREE memory = %d Mbytes\n",
+ freemem / (1024 * 1024));
+ printk(KERN_INFO "Total DSP VA USED memory= %d Mbytes \n",
+ (((table_size * PG_SIZE4K) - freemem)) / (1024 * 1024));
+ printk(KERN_INFO "DSP VA - Biggest FREE block = %d Mbytes \n\n",
+ (bigsize * PG_SIZE4K / (1024 * 1024)));
+
+ return 0;
+}
+#endif
diff --git a/drivers/staging/tidspbridge/pmgr/dspapi.c b/drivers/staging/tidspbridge/pmgr/dspapi.c
new file mode 100644
index 00000000000..7b42f72a97b
--- /dev/null
+++ b/drivers/staging/tidspbridge/pmgr/dspapi.c
@@ -0,0 +1,1906 @@
+/*
+ * dspapi.c
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * Common DSP API functions, also includes the wrapper
+ * functions called directly by the DeviceIOControl interface.
+ *
+ * Copyright (C) 2005-2006 Texas Instruments, Inc.
+ *
+ * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+#include <linux/types.h>
+
+/* ----------------------------------- Host OS */
+#include <dspbridge/host_os.h>
+
+/* ----------------------------------- DSP/BIOS Bridge */
+#include <dspbridge/dbdefs.h>
+
+/* ----------------------------------- Trace & Debug */
+#include <dspbridge/dbc.h>
+
+/* ----------------------------------- OS Adaptation Layer */
+#include <dspbridge/cfg.h>
+#include <dspbridge/ntfy.h>
+#include <dspbridge/services.h>
+
+/* ----------------------------------- Platform Manager */
+#include <dspbridge/chnl.h>
+#include <dspbridge/dev.h>
+#include <dspbridge/drv.h>
+
+#include <dspbridge/proc.h>
+#include <dspbridge/strm.h>
+
+/* ----------------------------------- Resource Manager */
+#include <dspbridge/disp.h>
+#include <dspbridge/mgr.h>
+#include <dspbridge/node.h>
+#include <dspbridge/rmm.h>
+
+/* ----------------------------------- Others */
+#include <dspbridge/msg.h>
+#include <dspbridge/cmm.h>
+#include <dspbridge/io.h>
+
+/* ----------------------------------- This */
+#include <dspbridge/dspapi.h>
+#include <dspbridge/dbdcd.h>
+
+#include <dspbridge/resourcecleanup.h>
+
+/* ----------------------------------- Defines, Data Structures, Typedefs */
+#define MAX_TRACEBUFLEN 255
+#define MAX_LOADARGS 16
+#define MAX_NODES 64
+#define MAX_STREAMS 16
+#define MAX_BUFS 64
+
+/* Used to get dspbridge ioctl table */
+#define DB_GET_IOC_TABLE(cmd) (DB_GET_MODULE(cmd) >> DB_MODULE_SHIFT)
+
+/* Device IOCtl function pointer */
+struct api_cmd {
+ u32(*fxn) (union trapped_args *args, void *pr_ctxt);
+ u32 dw_index;
+};
+
+/* ----------------------------------- Globals */
+static u32 api_c_refs;
+
+/*
+ * Function tables.
+ * The order of these functions MUST be the same as the order of the command
+ * numbers defined in dspapi-ioctl.h This is how an IOCTL number in user mode
+ * turns into a function call in kernel mode.
+ */
+
+/* MGR wrapper functions */
+static struct api_cmd mgr_cmd[] = {
+ {mgrwrap_enum_node_info}, /* MGR_ENUMNODE_INFO */
+ {mgrwrap_enum_proc_info}, /* MGR_ENUMPROC_INFO */
+ {mgrwrap_register_object}, /* MGR_REGISTEROBJECT */
+ {mgrwrap_unregister_object}, /* MGR_UNREGISTEROBJECT */
+ {mgrwrap_wait_for_bridge_events}, /* MGR_WAIT */
+ {mgrwrap_get_process_resources_info}, /* MGR_GET_PROC_RES */
+};
+
+/* PROC wrapper functions */
+static struct api_cmd proc_cmd[] = {
+ {procwrap_attach}, /* PROC_ATTACH */
+ {procwrap_ctrl}, /* PROC_CTRL */
+ {procwrap_detach}, /* PROC_DETACH */
+ {procwrap_enum_node_info}, /* PROC_ENUMNODE */
+ {procwrap_enum_resources}, /* PROC_ENUMRESOURCES */
+ {procwrap_get_state}, /* PROC_GET_STATE */
+ {procwrap_get_trace}, /* PROC_GET_TRACE */
+ {procwrap_load}, /* PROC_LOAD */
+ {procwrap_register_notify}, /* PROC_REGISTERNOTIFY */
+ {procwrap_start}, /* PROC_START */
+ {procwrap_reserve_memory}, /* PROC_RSVMEM */
+ {procwrap_un_reserve_memory}, /* PROC_UNRSVMEM */
+ {procwrap_map}, /* PROC_MAPMEM */
+ {procwrap_un_map}, /* PROC_UNMAPMEM */
+ {procwrap_flush_memory}, /* PROC_FLUSHMEMORY */
+ {procwrap_stop}, /* PROC_STOP */
+ {procwrap_invalidate_memory}, /* PROC_INVALIDATEMEMORY */
+ {procwrap_begin_dma}, /* PROC_BEGINDMA */
+ {procwrap_end_dma}, /* PROC_ENDDMA */
+};
+
+/* NODE wrapper functions */
+static struct api_cmd node_cmd[] = {
+ {nodewrap_allocate}, /* NODE_ALLOCATE */
+ {nodewrap_alloc_msg_buf}, /* NODE_ALLOCMSGBUF */
+ {nodewrap_change_priority}, /* NODE_CHANGEPRIORITY */
+ {nodewrap_connect}, /* NODE_CONNECT */
+ {nodewrap_create}, /* NODE_CREATE */
+ {nodewrap_delete}, /* NODE_DELETE */
+ {nodewrap_free_msg_buf}, /* NODE_FREEMSGBUF */
+ {nodewrap_get_attr}, /* NODE_GETATTR */
+ {nodewrap_get_message}, /* NODE_GETMESSAGE */
+ {nodewrap_pause}, /* NODE_PAUSE */
+ {nodewrap_put_message}, /* NODE_PUTMESSAGE */
+ {nodewrap_register_notify}, /* NODE_REGISTERNOTIFY */
+ {nodewrap_run}, /* NODE_RUN */
+ {nodewrap_terminate}, /* NODE_TERMINATE */
+ {nodewrap_get_uuid_props}, /* NODE_GETUUIDPROPS */
+};
+
+/* STRM wrapper functions */
+static struct api_cmd strm_cmd[] = {
+ {strmwrap_allocate_buffer}, /* STRM_ALLOCATEBUFFER */
+ {strmwrap_close}, /* STRM_CLOSE */
+ {strmwrap_free_buffer}, /* STRM_FREEBUFFER */
+ {strmwrap_get_event_handle}, /* STRM_GETEVENTHANDLE */
+ {strmwrap_get_info}, /* STRM_GETINFO */
+ {strmwrap_idle}, /* STRM_IDLE */
+ {strmwrap_issue}, /* STRM_ISSUE */
+ {strmwrap_open}, /* STRM_OPEN */
+ {strmwrap_reclaim}, /* STRM_RECLAIM */
+ {strmwrap_register_notify}, /* STRM_REGISTERNOTIFY */
+ {strmwrap_select}, /* STRM_SELECT */
+};
+
+/* CMM wrapper functions */
+static struct api_cmd cmm_cmd[] = {
+ {cmmwrap_calloc_buf}, /* CMM_ALLOCBUF */
+ {cmmwrap_free_buf}, /* CMM_FREEBUF */
+ {cmmwrap_get_handle}, /* CMM_GETHANDLE */
+ {cmmwrap_get_info}, /* CMM_GETINFO */
+};
+
+/* Array used to store ioctl table sizes. It can hold up to 8 entries */
+static u8 size_cmd[] = {
+ ARRAY_SIZE(mgr_cmd),
+ ARRAY_SIZE(proc_cmd),
+ ARRAY_SIZE(node_cmd),
+ ARRAY_SIZE(strm_cmd),
+ ARRAY_SIZE(cmm_cmd),
+};
+
+static inline void _cp_fm_usr(void *to, const void __user * from,
+ int *err, unsigned long bytes)
+{
+ if (*err)
+ return;
+
+ if (unlikely(!from)) {
+ *err = -EFAULT;
+ return;
+ }
+
+ if (unlikely(copy_from_user(to, from, bytes)))
+ *err = -EFAULT;
+}
+
+#define CP_FM_USR(to, from, err, n) \
+ _cp_fm_usr(to, from, &(err), (n) * sizeof(*(to)))
+
+static inline void _cp_to_usr(void __user *to, const void *from,
+ int *err, unsigned long bytes)
+{
+ if (*err)
+ return;
+
+ if (unlikely(!to)) {
+ *err = -EFAULT;
+ return;
+ }
+
+ if (unlikely(copy_to_user(to, from, bytes)))
+ *err = -EFAULT;
+}
+
+#define CP_TO_USR(to, from, err, n) \
+ _cp_to_usr(to, from, &(err), (n) * sizeof(*(from)))
+
+/*
+ * ======== api_call_dev_ioctl ========
+ * Purpose:
+ * Call the (wrapper) function for the corresponding API IOCTL.
+ */
+inline int api_call_dev_ioctl(u32 cmd, union trapped_args *args,
+ u32 *result, void *pr_ctxt)
+{
+ u32(*ioctl_cmd) (union trapped_args *args, void *pr_ctxt) = NULL;
+ int i;
+
+ if (_IOC_TYPE(cmd) != DB) {
+ pr_err("%s: Incompatible dspbridge ioctl number\n", __func__);
+ goto err;
+ }
+
+ if (DB_GET_IOC_TABLE(cmd) > ARRAY_SIZE(size_cmd)) {
+ pr_err("%s: undefined ioctl module\n", __func__);
+ goto err;
+ }
+
+ /* Check the size of the required cmd table */
+ i = DB_GET_IOC(cmd);
+ if (i > size_cmd[DB_GET_IOC_TABLE(cmd)]) {
+ pr_err("%s: requested ioctl %d out of bounds for table %d\n",
+ __func__, i, DB_GET_IOC_TABLE(cmd));
+ goto err;
+ }
+
+ switch (DB_GET_MODULE(cmd)) {
+ case DB_MGR:
+ ioctl_cmd = mgr_cmd[i].fxn;
+ break;
+ case DB_PROC:
+ ioctl_cmd = proc_cmd[i].fxn;
+ break;
+ case DB_NODE:
+ ioctl_cmd = node_cmd[i].fxn;
+ break;
+ case DB_STRM:
+ ioctl_cmd = strm_cmd[i].fxn;
+ break;
+ case DB_CMM:
+ ioctl_cmd = cmm_cmd[i].fxn;
+ break;
+ }
+
+ if (!ioctl_cmd) {
+ pr_err("%s: requested ioctl not defined\n", __func__);
+ goto err;
+ } else {
+ *result = (*ioctl_cmd) (args, pr_ctxt);
+ }
+
+ return 0;
+
+err:
+ return -EINVAL;
+}
+
+/*
+ * ======== api_exit ========
+ */
+void api_exit(void)
+{
+ DBC_REQUIRE(api_c_refs > 0);
+ api_c_refs--;
+
+ if (api_c_refs == 0) {
+ /* Release all modules initialized in api_init(). */
+ cod_exit();
+ dev_exit();
+ chnl_exit();
+ msg_exit();
+ io_exit();
+ strm_exit();
+ disp_exit();
+ node_exit();
+ proc_exit();
+ mgr_exit();
+ rmm_exit();
+ drv_exit();
+ }
+ DBC_ENSURE(api_c_refs >= 0);
+}
+
+/*
+ * ======== api_init ========
+ * Purpose:
+ * Module initialization used by Bridge API.
+ */
+bool api_init(void)
+{
+ bool ret = true;
+ bool fdrv, fdev, fcod, fchnl, fmsg, fio;
+ bool fmgr, fproc, fnode, fdisp, fstrm, frmm;
+
+ if (api_c_refs == 0) {
+ /* initialize driver and other modules */
+ fdrv = drv_init();
+ fmgr = mgr_init();
+ fproc = proc_init();
+ fnode = node_init();
+ fdisp = disp_init();
+ fstrm = strm_init();
+ frmm = rmm_init();
+ fchnl = chnl_init();
+ fmsg = msg_mod_init();
+ fio = io_init();
+ fdev = dev_init();
+ fcod = cod_init();
+ ret = fdrv && fdev && fchnl && fcod && fmsg && fio;
+ ret = ret && fmgr && fproc && frmm;
+ if (!ret) {
+ if (fdrv)
+ drv_exit();
+
+ if (fmgr)
+ mgr_exit();
+
+ if (fstrm)
+ strm_exit();
+
+ if (fproc)
+ proc_exit();
+
+ if (fnode)
+ node_exit();
+
+ if (fdisp)
+ disp_exit();
+
+ if (fchnl)
+ chnl_exit();
+
+ if (fmsg)
+ msg_exit();
+
+ if (fio)
+ io_exit();
+
+ if (fdev)
+ dev_exit();
+
+ if (fcod)
+ cod_exit();
+
+ if (frmm)
+ rmm_exit();
+
+ }
+ }
+ if (ret)
+ api_c_refs++;
+
+ return ret;
+}
+
+/*
+ * ======== api_init_complete2 ========
+ * Purpose:
+ * Perform any required bridge initialization which cannot
+ * be performed in api_init() or dev_start_device() due
+ * to the fact that some services are not yet
+ * completely initialized.
+ * Parameters:
+ * Returns:
+ * 0: Allow this device to load
+ * -EPERM: Failure.
+ * Requires:
+ * Bridge API initialized.
+ * Ensures:
+ */
+int api_init_complete2(void)
+{
+ int status = 0;
+ struct cfg_devnode *dev_node;
+ struct dev_object *hdev_obj;
+ u8 dev_type;
+ u32 tmp;
+
+ DBC_REQUIRE(api_c_refs > 0);
+
+ /* Walk the list of DevObjects, get each devnode, and attempting to
+ * autostart the board. Note that this requires COF loading, which
+ * requires KFILE. */
+ for (hdev_obj = dev_get_first(); hdev_obj != NULL;
+ hdev_obj = dev_get_next(hdev_obj)) {
+ if (dev_get_dev_node(hdev_obj, &dev_node))
+ continue;
+
+ if (dev_get_dev_type(hdev_obj, &dev_type))
+ continue;
+
+ if ((dev_type == DSP_UNIT) || (dev_type == IVA_UNIT))
+ if (cfg_get_auto_start(dev_node, &tmp) == 0
+ && tmp)
+ proc_auto_start(dev_node, hdev_obj);
+ }
+
+ return status;
+}
+
+/* TODO: Remove deprecated and not implemented ioctl wrappers */
+
+/*
+ * ======== mgrwrap_enum_node_info ========
+ */
+u32 mgrwrap_enum_node_info(union trapped_args *args, void *pr_ctxt)
+{
+ u8 *pndb_props;
+ u32 num_nodes;
+ int status = 0;
+ u32 size = args->args_mgr_enumnode_info.undb_props_size;
+
+ if (size < sizeof(struct dsp_ndbprops))
+ return -EINVAL;
+
+ pndb_props = kmalloc(size, GFP_KERNEL);
+ if (pndb_props == NULL)
+ status = -ENOMEM;
+
+ if (!status) {
+ status =
+ mgr_enum_node_info(args->args_mgr_enumnode_info.node_id,
+ (struct dsp_ndbprops *)pndb_props, size,
+ &num_nodes);
+ }
+ CP_TO_USR(args->args_mgr_enumnode_info.pndb_props, pndb_props, status,
+ size);
+ CP_TO_USR(args->args_mgr_enumnode_info.pu_num_nodes, &num_nodes, status,
+ 1);
+ kfree(pndb_props);
+
+ return status;
+}
+
+/*
+ * ======== mgrwrap_enum_proc_info ========
+ */
+u32 mgrwrap_enum_proc_info(union trapped_args *args, void *pr_ctxt)
+{
+ u8 *processor_info;
+ u8 num_procs;
+ int status = 0;
+ u32 size = args->args_mgr_enumproc_info.processor_info_size;
+
+ if (size < sizeof(struct dsp_processorinfo))
+ return -EINVAL;
+
+ processor_info = kmalloc(size, GFP_KERNEL);
+ if (processor_info == NULL)
+ status = -ENOMEM;
+
+ if (!status) {
+ status =
+ mgr_enum_processor_info(args->args_mgr_enumproc_info.
+ processor_id,
+ (struct dsp_processorinfo *)
+ processor_info, size, &num_procs);
+ }
+ CP_TO_USR(args->args_mgr_enumproc_info.processor_info, processor_info,
+ status, size);
+ CP_TO_USR(args->args_mgr_enumproc_info.pu_num_procs, &num_procs,
+ status, 1);
+ kfree(processor_info);
+
+ return status;
+}
+
+#define WRAP_MAP2CALLER(x) x
+/*
+ * ======== mgrwrap_register_object ========
+ */
+u32 mgrwrap_register_object(union trapped_args *args, void *pr_ctxt)
+{
+ u32 ret;
+ struct dsp_uuid uuid_obj;
+ u32 path_size = 0;
+ char *psz_path_name = NULL;
+ int status = 0;
+
+ CP_FM_USR(&uuid_obj, args->args_mgr_registerobject.uuid_obj, status, 1);
+ if (status)
+ goto func_end;
+ /* path_size is increased by 1 to accommodate NULL */
+ path_size = strlen_user((char *)
+ args->args_mgr_registerobject.psz_path_name) +
+ 1;
+ psz_path_name = kmalloc(path_size, GFP_KERNEL);
+ if (!psz_path_name)
+ goto func_end;
+ ret = strncpy_from_user(psz_path_name,
+ (char *)args->args_mgr_registerobject.
+ psz_path_name, path_size);
+ if (!ret) {
+ status = -EFAULT;
+ goto func_end;
+ }
+
+ if (args->args_mgr_registerobject.obj_type >= DSP_DCDMAXOBJTYPE)
+ return -EINVAL;
+
+ status = dcd_register_object(&uuid_obj,
+ args->args_mgr_registerobject.obj_type,
+ (char *)psz_path_name);
+func_end:
+ kfree(psz_path_name);
+ return status;
+}
+
+/*
+ * ======== mgrwrap_unregister_object ========
+ */
+u32 mgrwrap_unregister_object(union trapped_args *args, void *pr_ctxt)
+{
+ int status = 0;
+ struct dsp_uuid uuid_obj;
+
+ CP_FM_USR(&uuid_obj, args->args_mgr_registerobject.uuid_obj, status, 1);
+ if (status)
+ goto func_end;
+
+ status = dcd_unregister_object(&uuid_obj,
+ args->args_mgr_unregisterobject.
+ obj_type);
+func_end:
+ return status;
+
+}
+
+/*
+ * ======== mgrwrap_wait_for_bridge_events ========
+ */
+u32 mgrwrap_wait_for_bridge_events(union trapped_args *args, void *pr_ctxt)
+{
+ int status = 0;
+ struct dsp_notification *anotifications[MAX_EVENTS];
+ struct dsp_notification notifications[MAX_EVENTS];
+ u32 index, i;
+ u32 count = args->args_mgr_wait.count;
+
+ if (count > MAX_EVENTS)
+ status = -EINVAL;
+
+ /* get the array of pointers to user structures */
+ CP_FM_USR(anotifications, args->args_mgr_wait.anotifications,
+ status, count);
+ /* get the events */
+ for (i = 0; i < count; i++) {
+ CP_FM_USR(&notifications[i], anotifications[i], status, 1);
+ if (status || !notifications[i].handle) {
+ status = -EINVAL;
+ break;
+ }
+ /* set the array of pointers to kernel structures */
+ anotifications[i] = &notifications[i];
+ }
+ if (!status) {
+ status = mgr_wait_for_bridge_events(anotifications, count,
+ &index,
+ args->args_mgr_wait.
+ utimeout);
+ }
+ CP_TO_USR(args->args_mgr_wait.pu_index, &index, status, 1);
+ return status;
+}
+
+/*
+ * ======== MGRWRAP_GetProcessResourceInfo ========
+ */
+u32 __deprecated mgrwrap_get_process_resources_info(union trapped_args * args,
+ void *pr_ctxt)
+{
+ pr_err("%s: deprecated dspbridge ioctl\n", __func__);
+ return 0;
+}
+
+/*
+ * ======== procwrap_attach ========
+ */
+u32 procwrap_attach(union trapped_args *args, void *pr_ctxt)
+{
+ void *processor;
+ int status = 0;
+ struct dsp_processorattrin proc_attr_in, *attr_in = NULL;
+
+ /* Optional argument */
+ if (args->args_proc_attach.attr_in) {
+ CP_FM_USR(&proc_attr_in, args->args_proc_attach.attr_in, status,
+ 1);
+ if (!status)
+ attr_in = &proc_attr_in;
+ else
+ goto func_end;
+
+ }
+ status = proc_attach(args->args_proc_attach.processor_id, attr_in,
+ &processor, pr_ctxt);
+ CP_TO_USR(args->args_proc_attach.ph_processor, &processor, status, 1);
+func_end:
+ return status;
+}
+
+/*
+ * ======== procwrap_ctrl ========
+ */
+u32 procwrap_ctrl(union trapped_args *args, void *pr_ctxt)
+{
+ u32 cb_data_size, __user * psize = (u32 __user *)
+ args->args_proc_ctrl.pargs;
+ u8 *pargs = NULL;
+ int status = 0;
+ void *hprocessor = ((struct process_context *)pr_ctxt)->hprocessor;
+
+ if (psize) {
+ if (get_user(cb_data_size, psize)) {
+ status = -EPERM;
+ goto func_end;
+ }
+ cb_data_size += sizeof(u32);
+ pargs = kmalloc(cb_data_size, GFP_KERNEL);
+ if (pargs == NULL) {
+ status = -ENOMEM;
+ goto func_end;
+ }
+
+ CP_FM_USR(pargs, args->args_proc_ctrl.pargs, status,
+ cb_data_size);
+ }
+ if (!status) {
+ status = proc_ctrl(hprocessor,
+ args->args_proc_ctrl.dw_cmd,
+ (struct dsp_cbdata *)pargs);
+ }
+
+ /* CP_TO_USR(args->args_proc_ctrl.pargs, pargs, status, 1); */
+ kfree(pargs);
+func_end:
+ return status;
+}
+
+/*
+ * ======== procwrap_detach ========
+ */
+u32 __deprecated procwrap_detach(union trapped_args * args, void *pr_ctxt)
+{
+ /* proc_detach called at bridge_release only */
+ pr_err("%s: deprecated dspbridge ioctl\n", __func__);
+ return 0;
+}
+
+/*
+ * ======== procwrap_enum_node_info ========
+ */
+u32 procwrap_enum_node_info(union trapped_args *args, void *pr_ctxt)
+{
+ int status;
+ void *node_tab[MAX_NODES];
+ u32 num_nodes;
+ u32 alloc_cnt;
+ void *hprocessor = ((struct process_context *)pr_ctxt)->hprocessor;
+
+ if (!args->args_proc_enumnode_info.node_tab_size)
+ return -EINVAL;
+
+ status = proc_enum_nodes(hprocessor,
+ node_tab,
+ args->args_proc_enumnode_info.node_tab_size,
+ &num_nodes, &alloc_cnt);
+ CP_TO_USR(args->args_proc_enumnode_info.node_tab, node_tab, status,
+ num_nodes);
+ CP_TO_USR(args->args_proc_enumnode_info.pu_num_nodes, &num_nodes,
+ status, 1);
+ CP_TO_USR(args->args_proc_enumnode_info.pu_allocated, &alloc_cnt,
+ status, 1);
+ return status;
+}
+
+u32 procwrap_end_dma(union trapped_args *args, void *pr_ctxt)
+{
+ int status;
+
+ if (args->args_proc_dma.dir >= DMA_NONE)
+ return -EINVAL;
+
+ status = proc_end_dma(pr_ctxt,
+ args->args_proc_dma.pmpu_addr,
+ args->args_proc_dma.ul_size,
+ args->args_proc_dma.dir);
+ return status;
+}
+
+u32 procwrap_begin_dma(union trapped_args *args, void *pr_ctxt)
+{
+ int status;
+
+ if (args->args_proc_dma.dir >= DMA_NONE)
+ return -EINVAL;
+
+ status = proc_begin_dma(pr_ctxt,
+ args->args_proc_dma.pmpu_addr,
+ args->args_proc_dma.ul_size,
+ args->args_proc_dma.dir);
+ return status;
+}
+
+/*
+ * ======== procwrap_flush_memory ========
+ */
+u32 procwrap_flush_memory(union trapped_args *args, void *pr_ctxt)
+{
+ int status;
+
+ if (args->args_proc_flushmemory.ul_flags >
+ PROC_WRITEBACK_INVALIDATE_MEM)
+ return -EINVAL;
+
+ status = proc_flush_memory(pr_ctxt,
+ args->args_proc_flushmemory.pmpu_addr,
+ args->args_proc_flushmemory.ul_size,
+ args->args_proc_flushmemory.ul_flags);
+ return status;
+}
+
+/*
+ * ======== procwrap_invalidate_memory ========
+ */
+u32 procwrap_invalidate_memory(union trapped_args *args, void *pr_ctxt)
+{
+ int status;
+
+ status =
+ proc_invalidate_memory(pr_ctxt,
+ args->args_proc_invalidatememory.pmpu_addr,
+ args->args_proc_invalidatememory.ul_size);
+ return status;
+}
+
+/*
+ * ======== procwrap_enum_resources ========
+ */
+u32 procwrap_enum_resources(union trapped_args *args, void *pr_ctxt)
+{
+ int status = 0;
+ struct dsp_resourceinfo resource_info;
+ void *hprocessor = ((struct process_context *)pr_ctxt)->hprocessor;
+
+ if (args->args_proc_enumresources.resource_info_size <
+ sizeof(struct dsp_resourceinfo))
+ return -EINVAL;
+
+ status =
+ proc_get_resource_info(hprocessor,
+ args->args_proc_enumresources.resource_type,
+ &resource_info,
+ args->args_proc_enumresources.
+ resource_info_size);
+
+ CP_TO_USR(args->args_proc_enumresources.resource_info, &resource_info,
+ status, 1);
+
+ return status;
+
+}
+
+/*
+ * ======== procwrap_get_state ========
+ */
+u32 procwrap_get_state(union trapped_args *args, void *pr_ctxt)
+{
+ int status;
+ struct dsp_processorstate proc_state;
+ void *hprocessor = ((struct process_context *)pr_ctxt)->hprocessor;
+
+ if (args->args_proc_getstate.state_info_size <
+ sizeof(struct dsp_processorstate))
+ return -EINVAL;
+
+ status = proc_get_state(hprocessor, &proc_state,
+ args->args_proc_getstate.state_info_size);
+ CP_TO_USR(args->args_proc_getstate.proc_state_obj, &proc_state, status,
+ 1);
+ return status;
+
+}
+
+/*
+ * ======== procwrap_get_trace ========
+ */
+u32 procwrap_get_trace(union trapped_args *args, void *pr_ctxt)
+{
+ int status;
+ u8 *pbuf;
+ void *hprocessor = ((struct process_context *)pr_ctxt)->hprocessor;
+
+ if (args->args_proc_gettrace.max_size > MAX_TRACEBUFLEN)
+ return -EINVAL;
+
+ pbuf = kzalloc(args->args_proc_gettrace.max_size, GFP_KERNEL);
+ if (pbuf != NULL) {
+ status = proc_get_trace(hprocessor, pbuf,
+ args->args_proc_gettrace.max_size);
+ } else {
+ status = -ENOMEM;
+ }
+ CP_TO_USR(args->args_proc_gettrace.pbuf, pbuf, status,
+ args->args_proc_gettrace.max_size);
+ kfree(pbuf);
+
+ return status;
+}
+
+/*
+ * ======== procwrap_load ========
+ */
+u32 procwrap_load(union trapped_args *args, void *pr_ctxt)
+{
+ s32 i, len;
+ int status = 0;
+ char *temp;
+ s32 count = args->args_proc_load.argc_index;
+ u8 **argv = NULL, **envp = NULL;
+ void *hprocessor = ((struct process_context *)pr_ctxt)->hprocessor;
+
+ if (count <= 0 || count > MAX_LOADARGS) {
+ status = -EINVAL;
+ goto func_cont;
+ }
+
+ argv = kmalloc(count * sizeof(u8 *), GFP_KERNEL);
+ if (!argv) {
+ status = -ENOMEM;
+ goto func_cont;
+ }
+
+ CP_FM_USR(argv, args->args_proc_load.user_args, status, count);
+ if (status) {
+ kfree(argv);
+ argv = NULL;
+ goto func_cont;
+ }
+
+ for (i = 0; i < count; i++) {
+ if (argv[i]) {
+ /* User space pointer to argument */
+ temp = (char *)argv[i];
+ /* len is increased by 1 to accommodate NULL */
+ len = strlen_user((char *)temp) + 1;
+ /* Kernel space pointer to argument */
+ argv[i] = kmalloc(len, GFP_KERNEL);
+ if (argv[i]) {
+ CP_FM_USR(argv[i], temp, status, len);
+ if (status) {
+ kfree(argv[i]);
+ argv[i] = NULL;
+ goto func_cont;
+ }
+ } else {
+ status = -ENOMEM;
+ goto func_cont;
+ }
+ }
+ }
+ /* TODO: validate this */
+ if (args->args_proc_load.user_envp) {
+ /* number of elements in the envp array including NULL */
+ count = 0;
+ do {
+ get_user(temp, args->args_proc_load.user_envp + count);
+ count++;
+ } while (temp);
+ envp = kmalloc(count * sizeof(u8 *), GFP_KERNEL);
+ if (!envp) {
+ status = -ENOMEM;
+ goto func_cont;
+ }
+
+ CP_FM_USR(envp, args->args_proc_load.user_envp, status, count);
+ if (status) {
+ kfree(envp);
+ envp = NULL;
+ goto func_cont;
+ }
+ for (i = 0; envp[i]; i++) {
+ /* User space pointer to argument */
+ temp = (char *)envp[i];
+ /* len is increased by 1 to accommodate NULL */
+ len = strlen_user((char *)temp) + 1;
+ /* Kernel space pointer to argument */
+ envp[i] = kmalloc(len, GFP_KERNEL);
+ if (envp[i]) {
+ CP_FM_USR(envp[i], temp, status, len);
+ if (status) {
+ kfree(envp[i]);
+ envp[i] = NULL;
+ goto func_cont;
+ }
+ } else {
+ status = -ENOMEM;
+ goto func_cont;
+ }
+ }
+ }
+
+ if (!status) {
+ status = proc_load(hprocessor,
+ args->args_proc_load.argc_index,
+ (const char **)argv, (const char **)envp);
+ }
+func_cont:
+ if (envp) {
+ i = 0;
+ while (envp[i])
+ kfree(envp[i++]);
+
+ kfree(envp);
+ }
+
+ if (argv) {
+ count = args->args_proc_load.argc_index;
+ for (i = 0; (i < count) && argv[i]; i++)
+ kfree(argv[i]);
+
+ kfree(argv);
+ }
+
+ return status;
+}
+
+/*
+ * ======== procwrap_map ========
+ */
+u32 procwrap_map(union trapped_args *args, void *pr_ctxt)
+{
+ int status;
+ void *map_addr;
+ void *hprocessor = ((struct process_context *)pr_ctxt)->hprocessor;
+
+ if (!args->args_proc_mapmem.ul_size)
+ return -EINVAL;
+
+ status = proc_map(args->args_proc_mapmem.hprocessor,
+ args->args_proc_mapmem.pmpu_addr,
+ args->args_proc_mapmem.ul_size,
+ args->args_proc_mapmem.req_addr, &map_addr,
+ args->args_proc_mapmem.ul_map_attr, pr_ctxt);
+ if (!status) {
+ if (put_user(map_addr, args->args_proc_mapmem.pp_map_addr)) {
+ status = -EINVAL;
+ proc_un_map(hprocessor, map_addr, pr_ctxt);
+ }
+
+ }
+ return status;
+}
+
+/*
+ * ======== procwrap_register_notify ========
+ */
+u32 procwrap_register_notify(union trapped_args *args, void *pr_ctxt)
+{
+ int status;
+ struct dsp_notification notification;
+ void *hprocessor = ((struct process_context *)pr_ctxt)->hprocessor;
+
+ /* Initialize the notification data structure */
+ notification.ps_name = NULL;
+ notification.handle = NULL;
+
+ status = proc_register_notify(hprocessor,
+ args->args_proc_register_notify.event_mask,
+ args->args_proc_register_notify.notify_type,
+ &notification);
+ CP_TO_USR(args->args_proc_register_notify.hnotification, &notification,
+ status, 1);
+ return status;
+}
+
+/*
+ * ======== procwrap_reserve_memory ========
+ */
+u32 procwrap_reserve_memory(union trapped_args *args, void *pr_ctxt)
+{
+ int status;
+ void *prsv_addr;
+ void *hprocessor = ((struct process_context *)pr_ctxt)->hprocessor;
+
+ if ((args->args_proc_rsvmem.ul_size <= 0) ||
+ (args->args_proc_rsvmem.ul_size & (PG_SIZE4K - 1)) != 0)
+ return -EINVAL;
+
+ status = proc_reserve_memory(hprocessor,
+ args->args_proc_rsvmem.ul_size, &prsv_addr,
+ pr_ctxt);
+ if (!status) {
+ if (put_user(prsv_addr, args->args_proc_rsvmem.pp_rsv_addr)) {
+ status = -EINVAL;
+ proc_un_reserve_memory(args->args_proc_rsvmem.
+ hprocessor, prsv_addr, pr_ctxt);
+ }
+ }
+ return status;
+}
+
+/*
+ * ======== procwrap_start ========
+ */
+u32 procwrap_start(union trapped_args *args, void *pr_ctxt)
+{
+ u32 ret;
+
+ ret = proc_start(((struct process_context *)pr_ctxt)->hprocessor);
+ return ret;
+}
+
+/*
+ * ======== procwrap_un_map ========
+ */
+u32 procwrap_un_map(union trapped_args *args, void *pr_ctxt)
+{
+ int status;
+
+ status = proc_un_map(((struct process_context *)pr_ctxt)->hprocessor,
+ args->args_proc_unmapmem.map_addr, pr_ctxt);
+ return status;
+}
+
+/*
+ * ======== procwrap_un_reserve_memory ========
+ */
+u32 procwrap_un_reserve_memory(union trapped_args *args, void *pr_ctxt)
+{
+ int status;
+ void *hprocessor = ((struct process_context *)pr_ctxt)->hprocessor;
+
+ status = proc_un_reserve_memory(hprocessor,
+ args->args_proc_unrsvmem.prsv_addr,
+ pr_ctxt);
+ return status;
+}
+
+/*
+ * ======== procwrap_stop ========
+ */
+u32 procwrap_stop(union trapped_args *args, void *pr_ctxt)
+{
+ u32 ret;
+
+ ret = proc_stop(((struct process_context *)pr_ctxt)->hprocessor);
+
+ return ret;
+}
+
+/*
+ * ======== find_handle =========
+ */
+inline void find_node_handle(struct node_res_object **noderes,
+ void *pr_ctxt, void *hnode)
+{
+ rcu_read_lock();
+ *noderes = idr_find(((struct process_context *)pr_ctxt)->node_id,
+ (int)hnode - 1);
+ rcu_read_unlock();
+ return;
+}
+
+
+/*
+ * ======== nodewrap_allocate ========
+ */
+u32 nodewrap_allocate(union trapped_args *args, void *pr_ctxt)
+{
+ int status = 0;
+ struct dsp_uuid node_uuid;
+ u32 cb_data_size = 0;
+ u32 __user *psize = (u32 __user *) args->args_node_allocate.pargs;
+ u8 *pargs = NULL;
+ struct dsp_nodeattrin proc_attr_in, *attr_in = NULL;
+ struct node_res_object *node_res;
+ int nodeid;
+ void *hprocessor = ((struct process_context *)pr_ctxt)->hprocessor;
+
+ /* Optional argument */
+ if (psize) {
+ if (get_user(cb_data_size, psize))
+ status = -EPERM;
+
+ cb_data_size += sizeof(u32);
+ if (!status) {
+ pargs = kmalloc(cb_data_size, GFP_KERNEL);
+ if (pargs == NULL)
+ status = -ENOMEM;
+
+ }
+ CP_FM_USR(pargs, args->args_node_allocate.pargs, status,
+ cb_data_size);
+ }
+ CP_FM_USR(&node_uuid, args->args_node_allocate.node_id_ptr, status, 1);
+ if (status)
+ goto func_cont;
+ /* Optional argument */
+ if (args->args_node_allocate.attr_in) {
+ CP_FM_USR(&proc_attr_in, args->args_node_allocate.attr_in,
+ status, 1);
+ if (!status)
+ attr_in = &proc_attr_in;
+ else
+ status = -ENOMEM;
+
+ }
+ if (!status) {
+ status = node_allocate(hprocessor,
+ &node_uuid, (struct dsp_cbdata *)pargs,
+ attr_in, &node_res, pr_ctxt);
+ }
+ if (!status) {
+ nodeid = node_res->id + 1;
+ CP_TO_USR(args->args_node_allocate.ph_node, &nodeid,
+ status, 1);
+ if (status) {
+ status = -EFAULT;
+ node_delete(node_res, pr_ctxt);
+ }
+ }
+func_cont:
+ kfree(pargs);
+
+ return status;
+}
+
+/*
+ * ======== nodewrap_alloc_msg_buf ========
+ */
+u32 nodewrap_alloc_msg_buf(union trapped_args *args, void *pr_ctxt)
+{
+ int status = 0;
+ struct dsp_bufferattr *pattr = NULL;
+ struct dsp_bufferattr attr;
+ u8 *pbuffer = NULL;
+ struct node_res_object *node_res;
+
+ find_node_handle(&node_res, pr_ctxt,
+ args->args_node_allocmsgbuf.hnode);
+
+ if (!node_res)
+ return -EFAULT;
+
+ if (!args->args_node_allocmsgbuf.usize)
+ return -EINVAL;
+
+ if (args->args_node_allocmsgbuf.pattr) { /* Optional argument */
+ CP_FM_USR(&attr, args->args_node_allocmsgbuf.pattr, status, 1);
+ if (!status)
+ pattr = &attr;
+
+ }
+ /* argument */
+ CP_FM_USR(&pbuffer, args->args_node_allocmsgbuf.pbuffer, status, 1);
+ if (!status) {
+ status = node_alloc_msg_buf(node_res->hnode,
+ args->args_node_allocmsgbuf.usize,
+ pattr, &pbuffer);
+ }
+ CP_TO_USR(args->args_node_allocmsgbuf.pbuffer, &pbuffer, status, 1);
+ return status;
+}
+
+/*
+ * ======== nodewrap_change_priority ========
+ */
+u32 nodewrap_change_priority(union trapped_args *args, void *pr_ctxt)
+{
+ u32 ret;
+ struct node_res_object *node_res;
+
+ find_node_handle(&node_res, pr_ctxt,
+ args->args_node_changepriority.hnode);
+
+ if (!node_res)
+ return -EFAULT;
+
+ ret = node_change_priority(node_res->hnode,
+ args->args_node_changepriority.prio);
+
+ return ret;
+}
+
+/*
+ * ======== nodewrap_connect ========
+ */
+u32 nodewrap_connect(union trapped_args *args, void *pr_ctxt)
+{
+ int status = 0;
+ struct dsp_strmattr attrs;
+ struct dsp_strmattr *pattrs = NULL;
+ u32 cb_data_size;
+ u32 __user *psize = (u32 __user *) args->args_node_connect.conn_param;
+ u8 *pargs = NULL;
+ struct node_res_object *node_res1, *node_res2;
+ struct node_object *node1 = NULL, *node2 = NULL;
+
+ if ((int)args->args_node_connect.hnode != DSP_HGPPNODE) {
+ find_node_handle(&node_res1, pr_ctxt,
+ args->args_node_connect.hnode);
+ if (node_res1)
+ node1 = node_res1->hnode;
+ } else {
+ node1 = args->args_node_connect.hnode;
+ }
+
+ if ((int)args->args_node_connect.other_node != DSP_HGPPNODE) {
+ find_node_handle(&node_res2, pr_ctxt,
+ args->args_node_connect.other_node);
+ if (node_res2)
+ node2 = node_res2->hnode;
+ } else {
+ node2 = args->args_node_connect.other_node;
+ }
+
+ if (!node1 || !node2)
+ return -EFAULT;
+
+ /* Optional argument */
+ if (psize) {
+ if (get_user(cb_data_size, psize))
+ status = -EPERM;
+
+ cb_data_size += sizeof(u32);
+ if (!status) {
+ pargs = kmalloc(cb_data_size, GFP_KERNEL);
+ if (pargs == NULL) {
+ status = -ENOMEM;
+ goto func_cont;
+ }
+
+ }
+ CP_FM_USR(pargs, args->args_node_connect.conn_param, status,
+ cb_data_size);
+ if (status)
+ goto func_cont;
+ }
+ if (args->args_node_connect.pattrs) { /* Optional argument */
+ CP_FM_USR(&attrs, args->args_node_connect.pattrs, status, 1);
+ if (!status)
+ pattrs = &attrs;
+
+ }
+ if (!status) {
+ status = node_connect(node1,
+ args->args_node_connect.stream_id,
+ node2,
+ args->args_node_connect.other_stream,
+ pattrs, (struct dsp_cbdata *)pargs);
+ }
+func_cont:
+ kfree(pargs);
+
+ return status;
+}
+
+/*
+ * ======== nodewrap_create ========
+ */
+u32 nodewrap_create(union trapped_args *args, void *pr_ctxt)
+{
+ u32 ret;
+ struct node_res_object *node_res;
+
+ find_node_handle(&node_res, pr_ctxt, args->args_node_create.hnode);
+
+ if (!node_res)
+ return -EFAULT;
+
+ ret = node_create(node_res->hnode);
+
+ return ret;
+}
+
+/*
+ * ======== nodewrap_delete ========
+ */
+u32 nodewrap_delete(union trapped_args *args, void *pr_ctxt)
+{
+ u32 ret;
+ struct node_res_object *node_res;
+
+ find_node_handle(&node_res, pr_ctxt, args->args_node_delete.hnode);
+
+ if (!node_res)
+ return -EFAULT;
+
+ ret = node_delete(node_res, pr_ctxt);
+
+ return ret;
+}
+
+/*
+ * ======== nodewrap_free_msg_buf ========
+ */
+u32 nodewrap_free_msg_buf(union trapped_args *args, void *pr_ctxt)
+{
+ int status = 0;
+ struct dsp_bufferattr *pattr = NULL;
+ struct dsp_bufferattr attr;
+ struct node_res_object *node_res;
+
+ find_node_handle(&node_res, pr_ctxt, args->args_node_freemsgbuf.hnode);
+
+ if (!node_res)
+ return -EFAULT;
+
+ if (args->args_node_freemsgbuf.pattr) { /* Optional argument */
+ CP_FM_USR(&attr, args->args_node_freemsgbuf.pattr, status, 1);
+ if (!status)
+ pattr = &attr;
+
+ }
+
+ if (!args->args_node_freemsgbuf.pbuffer)
+ return -EFAULT;
+
+ if (!status) {
+ status = node_free_msg_buf(node_res->hnode,
+ args->args_node_freemsgbuf.pbuffer,
+ pattr);
+ }
+
+ return status;
+}
+
+/*
+ * ======== nodewrap_get_attr ========
+ */
+u32 nodewrap_get_attr(union trapped_args *args, void *pr_ctxt)
+{
+ int status = 0;
+ struct dsp_nodeattr attr;
+ struct node_res_object *node_res;
+
+ find_node_handle(&node_res, pr_ctxt, args->args_node_getattr.hnode);
+
+ if (!node_res)
+ return -EFAULT;
+
+ status = node_get_attr(node_res->hnode, &attr,
+ args->args_node_getattr.attr_size);
+ CP_TO_USR(args->args_node_getattr.pattr, &attr, status, 1);
+
+ return status;
+}
+
+/*
+ * ======== nodewrap_get_message ========
+ */
+u32 nodewrap_get_message(union trapped_args *args, void *pr_ctxt)
+{
+ int status;
+ struct dsp_msg msg;
+ struct node_res_object *node_res;
+
+ find_node_handle(&node_res, pr_ctxt, args->args_node_getmessage.hnode);
+
+ if (!node_res)
+ return -EFAULT;
+
+ status = node_get_message(node_res->hnode, &msg,
+ args->args_node_getmessage.utimeout);
+
+ CP_TO_USR(args->args_node_getmessage.message, &msg, status, 1);
+
+ return status;
+}
+
+/*
+ * ======== nodewrap_pause ========
+ */
+u32 nodewrap_pause(union trapped_args *args, void *pr_ctxt)
+{
+ u32 ret;
+ struct node_res_object *node_res;
+
+ find_node_handle(&node_res, pr_ctxt, args->args_node_pause.hnode);
+
+ if (!node_res)
+ return -EFAULT;
+
+ ret = node_pause(node_res->hnode);
+
+ return ret;
+}
+
+/*
+ * ======== nodewrap_put_message ========
+ */
+u32 nodewrap_put_message(union trapped_args *args, void *pr_ctxt)
+{
+ int status = 0;
+ struct dsp_msg msg;
+ struct node_res_object *node_res;
+
+ find_node_handle(&node_res, pr_ctxt, args->args_node_putmessage.hnode);
+
+ if (!node_res)
+ return -EFAULT;
+
+ CP_FM_USR(&msg, args->args_node_putmessage.message, status, 1);
+
+ if (!status) {
+ status =
+ node_put_message(node_res->hnode, &msg,
+ args->args_node_putmessage.utimeout);
+ }
+
+ return status;
+}
+
+/*
+ * ======== nodewrap_register_notify ========
+ */
+u32 nodewrap_register_notify(union trapped_args *args, void *pr_ctxt)
+{
+ int status = 0;
+ struct dsp_notification notification;
+ struct node_res_object *node_res;
+
+ find_node_handle(&node_res, pr_ctxt,
+ args->args_node_registernotify.hnode);
+
+ if (!node_res)
+ return -EFAULT;
+
+ /* Initialize the notification data structure */
+ notification.ps_name = NULL;
+ notification.handle = NULL;
+
+ if (!args->args_proc_register_notify.event_mask)
+ CP_FM_USR(&notification,
+ args->args_proc_register_notify.hnotification,
+ status, 1);
+
+ status = node_register_notify(node_res->hnode,
+ args->args_node_registernotify.event_mask,
+ args->args_node_registernotify.
+ notify_type, &notification);
+ CP_TO_USR(args->args_node_registernotify.hnotification, &notification,
+ status, 1);
+ return status;
+}
+
+/*
+ * ======== nodewrap_run ========
+ */
+u32 nodewrap_run(union trapped_args *args, void *pr_ctxt)
+{
+ u32 ret;
+ struct node_res_object *node_res;
+
+ find_node_handle(&node_res, pr_ctxt, args->args_node_run.hnode);
+
+ if (!node_res)
+ return -EFAULT;
+
+ ret = node_run(node_res->hnode);
+
+ return ret;
+}
+
+/*
+ * ======== nodewrap_terminate ========
+ */
+u32 nodewrap_terminate(union trapped_args *args, void *pr_ctxt)
+{
+ int status;
+ int tempstatus;
+ struct node_res_object *node_res;
+
+ find_node_handle(&node_res, pr_ctxt, args->args_node_terminate.hnode);
+
+ if (!node_res)
+ return -EFAULT;
+
+ status = node_terminate(node_res->hnode, &tempstatus);
+
+ CP_TO_USR(args->args_node_terminate.pstatus, &tempstatus, status, 1);
+
+ return status;
+}
+
+/*
+ * ======== nodewrap_get_uuid_props ========
+ */
+u32 nodewrap_get_uuid_props(union trapped_args *args, void *pr_ctxt)
+{
+ int status = 0;
+ struct dsp_uuid node_uuid;
+ struct dsp_ndbprops *pnode_props = NULL;
+ void *hprocessor = ((struct process_context *)pr_ctxt)->hprocessor;
+
+ CP_FM_USR(&node_uuid, args->args_node_getuuidprops.node_id_ptr, status,
+ 1);
+ if (status)
+ goto func_cont;
+ pnode_props = kmalloc(sizeof(struct dsp_ndbprops), GFP_KERNEL);
+ if (pnode_props != NULL) {
+ status =
+ node_get_uuid_props(hprocessor, &node_uuid, pnode_props);
+ CP_TO_USR(args->args_node_getuuidprops.node_props, pnode_props,
+ status, 1);
+ } else
+ status = -ENOMEM;
+func_cont:
+ kfree(pnode_props);
+ return status;
+}
+
+/*
+ * ======== find_strm_handle =========
+ */
+inline void find_strm_handle(struct strm_res_object **strmres,
+ void *pr_ctxt, void *hstream)
+{
+ rcu_read_lock();
+ *strmres = idr_find(((struct process_context *)pr_ctxt)->stream_id,
+ (int)hstream - 1);
+ rcu_read_unlock();
+ return;
+}
+
+/*
+ * ======== strmwrap_allocate_buffer ========
+ */
+u32 strmwrap_allocate_buffer(union trapped_args *args, void *pr_ctxt)
+{
+ int status;
+ u8 **ap_buffer = NULL;
+ u32 num_bufs = args->args_strm_allocatebuffer.num_bufs;
+ struct strm_res_object *strm_res;
+
+ find_strm_handle(&strm_res, pr_ctxt,
+ args->args_strm_allocatebuffer.hstream);
+
+ if (!strm_res)
+ return -EFAULT;
+
+ if (num_bufs > MAX_BUFS)
+ return -EINVAL;
+
+ ap_buffer = kmalloc((num_bufs * sizeof(u8 *)), GFP_KERNEL);
+ if (ap_buffer == NULL)
+ return -ENOMEM;
+
+ status = strm_allocate_buffer(strm_res,
+ args->args_strm_allocatebuffer.usize,
+ ap_buffer, num_bufs, pr_ctxt);
+ if (!status) {
+ CP_TO_USR(args->args_strm_allocatebuffer.ap_buffer, ap_buffer,
+ status, num_bufs);
+ if (status) {
+ status = -EFAULT;
+ strm_free_buffer(strm_res,
+ ap_buffer, num_bufs, pr_ctxt);
+ }
+ }
+ kfree(ap_buffer);
+
+ return status;
+}
+
+/*
+ * ======== strmwrap_close ========
+ */
+u32 strmwrap_close(union trapped_args *args, void *pr_ctxt)
+{
+ struct strm_res_object *strm_res;
+
+ find_strm_handle(&strm_res, pr_ctxt, args->args_strm_close.hstream);
+
+ if (!strm_res)
+ return -EFAULT;
+
+ return strm_close(strm_res, pr_ctxt);
+}
+
+/*
+ * ======== strmwrap_free_buffer ========
+ */
+u32 strmwrap_free_buffer(union trapped_args *args, void *pr_ctxt)
+{
+ int status = 0;
+ u8 **ap_buffer = NULL;
+ u32 num_bufs = args->args_strm_freebuffer.num_bufs;
+ struct strm_res_object *strm_res;
+
+ find_strm_handle(&strm_res, pr_ctxt,
+ args->args_strm_freebuffer.hstream);
+
+ if (!strm_res)
+ return -EFAULT;
+
+ if (num_bufs > MAX_BUFS)
+ return -EINVAL;
+
+ ap_buffer = kmalloc((num_bufs * sizeof(u8 *)), GFP_KERNEL);
+ if (ap_buffer == NULL)
+ return -ENOMEM;
+
+ CP_FM_USR(ap_buffer, args->args_strm_freebuffer.ap_buffer, status,
+ num_bufs);
+
+ if (!status)
+ status = strm_free_buffer(strm_res,
+ ap_buffer, num_bufs, pr_ctxt);
+
+ CP_TO_USR(args->args_strm_freebuffer.ap_buffer, ap_buffer, status,
+ num_bufs);
+ kfree(ap_buffer);
+
+ return status;
+}
+
+/*
+ * ======== strmwrap_get_event_handle ========
+ */
+u32 __deprecated strmwrap_get_event_handle(union trapped_args * args,
+ void *pr_ctxt)
+{
+ pr_err("%s: deprecated dspbridge ioctl\n", __func__);
+ return -ENOSYS;
+}
+
+/*
+ * ======== strmwrap_get_info ========
+ */
+u32 strmwrap_get_info(union trapped_args *args, void *pr_ctxt)
+{
+ int status = 0;
+ struct stream_info strm_info;
+ struct dsp_streaminfo user;
+ struct dsp_streaminfo *temp;
+ struct strm_res_object *strm_res;
+
+ find_strm_handle(&strm_res, pr_ctxt,
+ args->args_strm_getinfo.hstream);
+
+ if (!strm_res)
+ return -EFAULT;
+
+ CP_FM_USR(&strm_info, args->args_strm_getinfo.stream_info, status, 1);
+ temp = strm_info.user_strm;
+
+ strm_info.user_strm = &user;
+
+ if (!status) {
+ status = strm_get_info(strm_res->hstream,
+ &strm_info,
+ args->args_strm_getinfo.
+ stream_info_size);
+ }
+ CP_TO_USR(temp, strm_info.user_strm, status, 1);
+ strm_info.user_strm = temp;
+ CP_TO_USR(args->args_strm_getinfo.stream_info, &strm_info, status, 1);
+ return status;
+}
+
+/*
+ * ======== strmwrap_idle ========
+ */
+u32 strmwrap_idle(union trapped_args *args, void *pr_ctxt)
+{
+ u32 ret;
+ struct strm_res_object *strm_res;
+
+ find_strm_handle(&strm_res, pr_ctxt, args->args_strm_idle.hstream);
+
+ if (!strm_res)
+ return -EFAULT;
+
+ ret = strm_idle(strm_res->hstream, args->args_strm_idle.flush_flag);
+
+ return ret;
+}
+
+/*
+ * ======== strmwrap_issue ========
+ */
+u32 strmwrap_issue(union trapped_args *args, void *pr_ctxt)
+{
+ int status = 0;
+ struct strm_res_object *strm_res;
+
+ find_strm_handle(&strm_res, pr_ctxt, args->args_strm_issue.hstream);
+
+ if (!strm_res)
+ return -EFAULT;
+
+ if (!args->args_strm_issue.pbuffer)
+ return -EFAULT;
+
+ /* No need of doing CP_FM_USR for the user buffer (pbuffer)
+ as this is done in Bridge internal function bridge_chnl_add_io_req
+ in chnl_sm.c */
+ status = strm_issue(strm_res->hstream,
+ args->args_strm_issue.pbuffer,
+ args->args_strm_issue.dw_bytes,
+ args->args_strm_issue.dw_buf_size,
+ args->args_strm_issue.dw_arg);
+
+ return status;
+}
+
+/*
+ * ======== strmwrap_open ========
+ */
+u32 strmwrap_open(union trapped_args *args, void *pr_ctxt)
+{
+ int status = 0;
+ struct strm_attr attr;
+ struct strm_res_object *strm_res_obj;
+ struct dsp_streamattrin strm_attr_in;
+ struct node_res_object *node_res;
+ int strmid;
+
+ find_node_handle(&node_res, pr_ctxt, args->args_strm_open.hnode);
+
+ if (!node_res)
+ return -EFAULT;
+
+ CP_FM_USR(&attr, args->args_strm_open.attr_in, status, 1);
+
+ if (attr.stream_attr_in != NULL) { /* Optional argument */
+ CP_FM_USR(&strm_attr_in, attr.stream_attr_in, status, 1);
+ if (!status) {
+ attr.stream_attr_in = &strm_attr_in;
+ if (attr.stream_attr_in->strm_mode == STRMMODE_LDMA)
+ return -ENOSYS;
+ }
+
+ }
+ status = strm_open(node_res->hnode,
+ args->args_strm_open.direction,
+ args->args_strm_open.index, &attr, &strm_res_obj,
+ pr_ctxt);
+ if (!status) {
+ strmid = strm_res_obj->id + 1;
+ CP_TO_USR(args->args_strm_open.ph_stream, &strmid, status, 1);
+ }
+ return status;
+}
+
+/*
+ * ======== strmwrap_reclaim ========
+ */
+u32 strmwrap_reclaim(union trapped_args *args, void *pr_ctxt)
+{
+ int status = 0;
+ u8 *buf_ptr;
+ u32 ul_bytes;
+ u32 dw_arg;
+ u32 ul_buf_size;
+ struct strm_res_object *strm_res;
+
+ find_strm_handle(&strm_res, pr_ctxt, args->args_strm_reclaim.hstream);
+
+ if (!strm_res)
+ return -EFAULT;
+
+ status = strm_reclaim(strm_res->hstream, &buf_ptr,
+ &ul_bytes, &ul_buf_size, &dw_arg);
+ CP_TO_USR(args->args_strm_reclaim.buf_ptr, &buf_ptr, status, 1);
+ CP_TO_USR(args->args_strm_reclaim.bytes, &ul_bytes, status, 1);
+ CP_TO_USR(args->args_strm_reclaim.pdw_arg, &dw_arg, status, 1);
+
+ if (args->args_strm_reclaim.buf_size_ptr != NULL) {
+ CP_TO_USR(args->args_strm_reclaim.buf_size_ptr, &ul_buf_size,
+ status, 1);
+ }
+
+ return status;
+}
+
+/*
+ * ======== strmwrap_register_notify ========
+ */
+u32 strmwrap_register_notify(union trapped_args *args, void *pr_ctxt)
+{
+ int status = 0;
+ struct dsp_notification notification;
+ struct strm_res_object *strm_res;
+
+ find_strm_handle(&strm_res, pr_ctxt,
+ args->args_strm_registernotify.hstream);
+
+ if (!strm_res)
+ return -EFAULT;
+
+ /* Initialize the notification data structure */
+ notification.ps_name = NULL;
+ notification.handle = NULL;
+
+ status = strm_register_notify(strm_res->hstream,
+ args->args_strm_registernotify.event_mask,
+ args->args_strm_registernotify.
+ notify_type, &notification);
+ CP_TO_USR(args->args_strm_registernotify.hnotification, &notification,
+ status, 1);
+
+ return status;
+}
+
+/*
+ * ======== strmwrap_select ========
+ */
+u32 strmwrap_select(union trapped_args *args, void *pr_ctxt)
+{
+ u32 mask;
+ struct strm_object *strm_tab[MAX_STREAMS];
+ int status = 0;
+ struct strm_res_object *strm_res;
+ int *ids[MAX_STREAMS];
+ int i;
+
+ if (args->args_strm_select.strm_num > MAX_STREAMS)
+ return -EINVAL;
+
+ CP_FM_USR(ids, args->args_strm_select.stream_tab, status,
+ args->args_strm_select.strm_num);
+
+ if (status)
+ return status;
+
+ for (i = 0; i < args->args_strm_select.strm_num; i++) {
+ find_strm_handle(&strm_res, pr_ctxt, ids[i]);
+
+ if (!strm_res)
+ return -EFAULT;
+
+ strm_tab[i] = strm_res->hstream;
+ }
+
+ if (!status) {
+ status = strm_select(strm_tab, args->args_strm_select.strm_num,
+ &mask, args->args_strm_select.utimeout);
+ }
+ CP_TO_USR(args->args_strm_select.pmask, &mask, status, 1);
+ return status;
+}
+
+/* CMM */
+
+/*
+ * ======== cmmwrap_calloc_buf ========
+ */
+u32 __deprecated cmmwrap_calloc_buf(union trapped_args * args, void *pr_ctxt)
+{
+ /* This operation is done in kernel */
+ pr_err("%s: deprecated dspbridge ioctl\n", __func__);
+ return -ENOSYS;
+}
+
+/*
+ * ======== cmmwrap_free_buf ========
+ */
+u32 __deprecated cmmwrap_free_buf(union trapped_args * args, void *pr_ctxt)
+{
+ /* This operation is done in kernel */
+ pr_err("%s: deprecated dspbridge ioctl\n", __func__);
+ return -ENOSYS;
+}
+
+/*
+ * ======== cmmwrap_get_handle ========
+ */
+u32 cmmwrap_get_handle(union trapped_args *args, void *pr_ctxt)
+{
+ int status = 0;
+ struct cmm_object *hcmm_mgr;
+ void *hprocessor = ((struct process_context *)pr_ctxt)->hprocessor;
+
+ status = cmm_get_handle(hprocessor, &hcmm_mgr);
+
+ CP_TO_USR(args->args_cmm_gethandle.ph_cmm_mgr, &hcmm_mgr, status, 1);
+
+ return status;
+}
+
+/*
+ * ======== cmmwrap_get_info ========
+ */
+u32 cmmwrap_get_info(union trapped_args *args, void *pr_ctxt)
+{
+ int status = 0;
+ struct cmm_info cmm_info_obj;
+
+ status = cmm_get_info(args->args_cmm_getinfo.hcmm_mgr, &cmm_info_obj);
+
+ CP_TO_USR(args->args_cmm_getinfo.cmm_info_obj, &cmm_info_obj, status,
+ 1);
+
+ return status;
+}
diff --git a/drivers/staging/tidspbridge/pmgr/io.c b/drivers/staging/tidspbridge/pmgr/io.c
new file mode 100644
index 00000000000..7970fe55648
--- /dev/null
+++ b/drivers/staging/tidspbridge/pmgr/io.c
@@ -0,0 +1,142 @@
+/*
+ * io.c
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * IO manager interface: Manages IO between CHNL and msg_ctrl.
+ *
+ * Copyright (C) 2005-2006 Texas Instruments, Inc.
+ *
+ * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+#include <linux/types.h>
+
+/* ----------------------------------- Host OS */
+#include <dspbridge/host_os.h>
+
+/* ----------------------------------- DSP/BIOS Bridge */
+#include <dspbridge/dbdefs.h>
+
+/* ----------------------------------- Trace & Debug */
+#include <dspbridge/dbc.h>
+
+/* ----------------------------------- OS Adaptation Layer */
+#include <dspbridge/cfg.h>
+
+/* ----------------------------------- Platform Manager */
+#include <dspbridge/dev.h>
+
+/* ----------------------------------- This */
+#include <ioobj.h>
+#include <dspbridge/iodefs.h>
+#include <dspbridge/io.h>
+
+/* ----------------------------------- Globals */
+static u32 refs;
+
+/*
+ * ======== io_create ========
+ * Purpose:
+ * Create an IO manager object, responsible for managing IO between
+ * CHNL and msg_ctrl
+ */
+int io_create(struct io_mgr **io_man, struct dev_object *hdev_obj,
+ const struct io_attrs *mgr_attrts)
+{
+ struct bridge_drv_interface *intf_fxns;
+ struct io_mgr *hio_mgr = NULL;
+ struct io_mgr_ *pio_mgr = NULL;
+ int status = 0;
+
+ DBC_REQUIRE(refs > 0);
+ DBC_REQUIRE(io_man != NULL);
+ DBC_REQUIRE(mgr_attrts != NULL);
+
+ *io_man = NULL;
+
+ /* A memory base of 0 implies no memory base: */
+ if ((mgr_attrts->shm_base != 0) && (mgr_attrts->usm_length == 0))
+ status = -EINVAL;
+
+ if (mgr_attrts->word_size == 0)
+ status = -EINVAL;
+
+ if (!status) {
+ dev_get_intf_fxns(hdev_obj, &intf_fxns);
+
+ /* Let Bridge channel module finish the create: */
+ status = (*intf_fxns->pfn_io_create) (&hio_mgr, hdev_obj,
+ mgr_attrts);
+
+ if (!status) {
+ pio_mgr = (struct io_mgr_ *)hio_mgr;
+ pio_mgr->intf_fxns = intf_fxns;
+ pio_mgr->hdev_obj = hdev_obj;
+
+ /* Return the new channel manager handle: */
+ *io_man = hio_mgr;
+ }
+ }
+
+ return status;
+}
+
+/*
+ * ======== io_destroy ========
+ * Purpose:
+ * Delete IO manager.
+ */
+int io_destroy(struct io_mgr *hio_mgr)
+{
+ struct bridge_drv_interface *intf_fxns;
+ struct io_mgr_ *pio_mgr = (struct io_mgr_ *)hio_mgr;
+ int status;
+
+ DBC_REQUIRE(refs > 0);
+
+ intf_fxns = pio_mgr->intf_fxns;
+
+ /* Let Bridge channel module destroy the io_mgr: */
+ status = (*intf_fxns->pfn_io_destroy) (hio_mgr);
+
+ return status;
+}
+
+/*
+ * ======== io_exit ========
+ * Purpose:
+ * Discontinue usage of the IO module.
+ */
+void io_exit(void)
+{
+ DBC_REQUIRE(refs > 0);
+
+ refs--;
+
+ DBC_ENSURE(refs >= 0);
+}
+
+/*
+ * ======== io_init ========
+ * Purpose:
+ * Initialize the IO module's private state.
+ */
+bool io_init(void)
+{
+ bool ret = true;
+
+ DBC_REQUIRE(refs >= 0);
+
+ if (ret)
+ refs++;
+
+ DBC_ENSURE((ret && (refs > 0)) || (!ret && (refs >= 0)));
+
+ return ret;
+}
diff --git a/drivers/staging/tidspbridge/pmgr/ioobj.h b/drivers/staging/tidspbridge/pmgr/ioobj.h
new file mode 100644
index 00000000000..f46355fa7b2
--- /dev/null
+++ b/drivers/staging/tidspbridge/pmgr/ioobj.h
@@ -0,0 +1,38 @@
+/*
+ * ioobj.h
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * Structure subcomponents of channel class library IO objects which
+ * are exposed to DSP API from Bridge driver.
+ *
+ * Copyright (C) 2005-2006 Texas Instruments, Inc.
+ *
+ * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef IOOBJ_
+#define IOOBJ_
+
+#include <dspbridge/devdefs.h>
+#include <dspbridge/dspdefs.h>
+
+/*
+ * This struct is the first field in a io_mgr struct. Other, implementation
+ * specific fields follow this structure in memory.
+ */
+struct io_mgr_ {
+ /* These must be the first fields in a io_mgr struct: */
+ struct bridge_dev_context *hbridge_context; /* Bridge context. */
+ /* Function interface to Bridge driver. */
+ struct bridge_drv_interface *intf_fxns;
+ struct dev_object *hdev_obj; /* Device this board represents. */
+};
+
+#endif /* IOOBJ_ */
diff --git a/drivers/staging/tidspbridge/pmgr/msg.c b/drivers/staging/tidspbridge/pmgr/msg.c
new file mode 100644
index 00000000000..abd43659062
--- /dev/null
+++ b/drivers/staging/tidspbridge/pmgr/msg.c
@@ -0,0 +1,129 @@
+/*
+ * msg.c
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * DSP/BIOS Bridge msg_ctrl Module.
+ *
+ * Copyright (C) 2005-2006 Texas Instruments, Inc.
+ *
+ * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+#include <linux/types.h>
+
+/* ----------------------------------- Host OS */
+#include <dspbridge/host_os.h>
+
+/* ----------------------------------- DSP/BIOS Bridge */
+#include <dspbridge/dbdefs.h>
+
+/* ----------------------------------- Trace & Debug */
+#include <dspbridge/dbc.h>
+
+/* ----------------------------------- Bridge Driver */
+#include <dspbridge/dspdefs.h>
+
+/* ----------------------------------- Platform Manager */
+#include <dspbridge/dev.h>
+
+/* ----------------------------------- This */
+#include <msgobj.h>
+#include <dspbridge/msg.h>
+
+/* ----------------------------------- Globals */
+static u32 refs; /* module reference count */
+
+/*
+ * ======== msg_create ========
+ * Purpose:
+ * Create an object to manage message queues. Only one of these objects
+ * can exist per device object.
+ */
+int msg_create(struct msg_mgr **msg_man,
+ struct dev_object *hdev_obj, msg_onexit msg_callback)
+{
+ struct bridge_drv_interface *intf_fxns;
+ struct msg_mgr_ *msg_mgr_obj;
+ struct msg_mgr *hmsg_mgr;
+ int status = 0;
+
+ DBC_REQUIRE(refs > 0);
+ DBC_REQUIRE(msg_man != NULL);
+ DBC_REQUIRE(msg_callback != NULL);
+ DBC_REQUIRE(hdev_obj != NULL);
+
+ *msg_man = NULL;
+
+ dev_get_intf_fxns(hdev_obj, &intf_fxns);
+
+ /* Let Bridge message module finish the create: */
+ status =
+ (*intf_fxns->pfn_msg_create) (&hmsg_mgr, hdev_obj, msg_callback);
+
+ if (!status) {
+ /* Fill in DSP API message module's fields of the msg_mgr
+ * structure */
+ msg_mgr_obj = (struct msg_mgr_ *)hmsg_mgr;
+ msg_mgr_obj->intf_fxns = intf_fxns;
+
+ /* Finally, return the new message manager handle: */
+ *msg_man = hmsg_mgr;
+ } else {
+ status = -EPERM;
+ }
+ return status;
+}
+
+/*
+ * ======== msg_delete ========
+ * Purpose:
+ * Delete a msg_ctrl manager allocated in msg_create().
+ */
+void msg_delete(struct msg_mgr *hmsg_mgr)
+{
+ struct msg_mgr_ *msg_mgr_obj = (struct msg_mgr_ *)hmsg_mgr;
+ struct bridge_drv_interface *intf_fxns;
+
+ DBC_REQUIRE(refs > 0);
+
+ if (msg_mgr_obj) {
+ intf_fxns = msg_mgr_obj->intf_fxns;
+
+ /* Let Bridge message module destroy the msg_mgr: */
+ (*intf_fxns->pfn_msg_delete) (hmsg_mgr);
+ } else {
+ dev_dbg(bridge, "%s: Error hmsg_mgr handle: %p\n",
+ __func__, hmsg_mgr);
+ }
+}
+
+/*
+ * ======== msg_exit ========
+ */
+void msg_exit(void)
+{
+ DBC_REQUIRE(refs > 0);
+ refs--;
+
+ DBC_ENSURE(refs >= 0);
+}
+
+/*
+ * ======== msg_mod_init ========
+ */
+bool msg_mod_init(void)
+{
+ DBC_REQUIRE(refs >= 0);
+
+ refs++;
+
+ DBC_ENSURE(refs >= 0);
+
+ return true;
+}
diff --git a/drivers/staging/tidspbridge/pmgr/msgobj.h b/drivers/staging/tidspbridge/pmgr/msgobj.h
new file mode 100644
index 00000000000..14ca633c56c
--- /dev/null
+++ b/drivers/staging/tidspbridge/pmgr/msgobj.h
@@ -0,0 +1,38 @@
+/*
+ * msgobj.h
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * Structure subcomponents of channel class library msg_ctrl objects which
+ * are exposed to DSP API from Bridge driver.
+ *
+ * Copyright (C) 2005-2006 Texas Instruments, Inc.
+ *
+ * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef MSGOBJ_
+#define MSGOBJ_
+
+#include <dspbridge/dspdefs.h>
+
+#include <dspbridge/msgdefs.h>
+
+/*
+ * This struct is the first field in a msg_mgr struct. Other, implementation
+ * specific fields follow this structure in memory.
+ */
+struct msg_mgr_ {
+ /* The first field must match that in _msg_sm.h */
+
+ /* Function interface to Bridge driver. */
+ struct bridge_drv_interface *intf_fxns;
+};
+
+#endif /* MSGOBJ_ */
diff --git a/drivers/staging/tidspbridge/rmgr/dbdcd.c b/drivers/staging/tidspbridge/rmgr/dbdcd.c
new file mode 100644
index 00000000000..f71e8606f95
--- /dev/null
+++ b/drivers/staging/tidspbridge/rmgr/dbdcd.c
@@ -0,0 +1,1512 @@
+/*
+ * dbdcd.c
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * This file contains the implementation of the DSP/BIOS Bridge
+ * Configuration Database (DCD).
+ *
+ * Notes:
+ * The fxn dcd_get_objects can apply a callback fxn to each DCD object
+ * that is located in a specified COFF file. At the moment,
+ * dcd_auto_register, dcd_auto_unregister, and NLDR module all use
+ * dcd_get_objects.
+ *
+ * Copyright (C) 2005-2006 Texas Instruments, Inc.
+ *
+ * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+#include <linux/types.h>
+
+/* ----------------------------------- Host OS */
+#include <dspbridge/host_os.h>
+
+/* ----------------------------------- DSP/BIOS Bridge */
+#include <dspbridge/dbdefs.h>
+/* ----------------------------------- Trace & Debug */
+#include <dspbridge/dbc.h>
+
+/* ----------------------------------- Platform Manager */
+#include <dspbridge/cod.h>
+
+/* ----------------------------------- Others */
+#include <dspbridge/uuidutil.h>
+
+/* ----------------------------------- This */
+#include <dspbridge/dbdcd.h>
+
+/* ----------------------------------- Global defines. */
+#define MAX_INT2CHAR_LENGTH 16 /* Max int2char len of 32 bit int */
+
+/* Name of section containing dependent libraries */
+#define DEPLIBSECT ".dspbridge_deplibs"
+
+/* DCD specific structures. */
+struct dcd_manager {
+ struct cod_manager *cod_mgr; /* Handle to COD manager object. */
+};
+
+/* Pointer to the registry support key */
+static struct list_head reg_key_list;
+static DEFINE_SPINLOCK(dbdcd_lock);
+
+/* Global reference variables. */
+static u32 refs;
+static u32 enum_refs;
+
+/* Helper function prototypes. */
+static s32 atoi(char *psz_buf);
+static int get_attrs_from_buf(char *psz_buf, u32 ul_buf_size,
+ enum dsp_dcdobjtype obj_type,
+ struct dcd_genericobj *gen_obj);
+static void compress_buf(char *psz_buf, u32 ul_buf_size, s32 char_size);
+static char dsp_char2_gpp_char(char *word, s32 dsp_char_size);
+static int get_dep_lib_info(struct dcd_manager *hdcd_mgr,
+ struct dsp_uuid *uuid_obj,
+ u16 *num_libs,
+ u16 *num_pers_libs,
+ struct dsp_uuid *dep_lib_uuids,
+ bool *prstnt_dep_libs,
+ enum nldr_phase phase);
+
+/*
+ * ======== dcd_auto_register ========
+ * Purpose:
+ * Parses the supplied image and resigsters with DCD.
+ */
+int dcd_auto_register(struct dcd_manager *hdcd_mgr,
+ char *sz_coff_path)
+{
+ int status = 0;
+
+ DBC_REQUIRE(refs > 0);
+
+ if (hdcd_mgr)
+ status = dcd_get_objects(hdcd_mgr, sz_coff_path,
+ (dcd_registerfxn) dcd_register_object,
+ (void *)sz_coff_path);
+ else
+ status = -EFAULT;
+
+ return status;
+}
+
+/*
+ * ======== dcd_auto_unregister ========
+ * Purpose:
+ * Parses the supplied DSP image and unresiters from DCD.
+ */
+int dcd_auto_unregister(struct dcd_manager *hdcd_mgr,
+ char *sz_coff_path)
+{
+ int status = 0;
+
+ DBC_REQUIRE(refs > 0);
+
+ if (hdcd_mgr)
+ status = dcd_get_objects(hdcd_mgr, sz_coff_path,
+ (dcd_registerfxn) dcd_register_object,
+ NULL);
+ else
+ status = -EFAULT;
+
+ return status;
+}
+
+/*
+ * ======== dcd_create_manager ========
+ * Purpose:
+ * Creates DCD manager.
+ */
+int dcd_create_manager(char *sz_zl_dll_name,
+ struct dcd_manager **dcd_mgr)
+{
+ struct cod_manager *cod_mgr; /* COD manager handle */
+ struct dcd_manager *dcd_mgr_obj = NULL; /* DCD Manager pointer */
+ int status = 0;
+
+ DBC_REQUIRE(refs >= 0);
+ DBC_REQUIRE(dcd_mgr);
+
+ status = cod_create(&cod_mgr, sz_zl_dll_name, NULL);
+ if (status)
+ goto func_end;
+
+ /* Create a DCD object. */
+ dcd_mgr_obj = kzalloc(sizeof(struct dcd_manager), GFP_KERNEL);
+ if (dcd_mgr_obj != NULL) {
+ /* Fill out the object. */
+ dcd_mgr_obj->cod_mgr = cod_mgr;
+
+ /* Return handle to this DCD interface. */
+ *dcd_mgr = dcd_mgr_obj;
+ } else {
+ status = -ENOMEM;
+
+ /*
+ * If allocation of DcdManager object failed, delete the
+ * COD manager.
+ */
+ cod_delete(cod_mgr);
+ }
+
+ DBC_ENSURE((!status) ||
+ ((dcd_mgr_obj == NULL) && (status == -ENOMEM)));
+
+func_end:
+ return status;
+}
+
+/*
+ * ======== dcd_destroy_manager ========
+ * Purpose:
+ * Frees DCD Manager object.
+ */
+int dcd_destroy_manager(struct dcd_manager *hdcd_mgr)
+{
+ struct dcd_manager *dcd_mgr_obj = hdcd_mgr;
+ int status = -EFAULT;
+
+ DBC_REQUIRE(refs >= 0);
+
+ if (hdcd_mgr) {
+ /* Delete the COD manager. */
+ cod_delete(dcd_mgr_obj->cod_mgr);
+
+ /* Deallocate a DCD manager object. */
+ kfree(dcd_mgr_obj);
+
+ status = 0;
+ }
+
+ return status;
+}
+
+/*
+ * ======== dcd_enumerate_object ========
+ * Purpose:
+ * Enumerates objects in the DCD.
+ */
+int dcd_enumerate_object(s32 index, enum dsp_dcdobjtype obj_type,
+ struct dsp_uuid *uuid_obj)
+{
+ int status = 0;
+ char sz_reg_key[DCD_MAXPATHLENGTH];
+ char sz_value[DCD_MAXPATHLENGTH];
+ struct dsp_uuid dsp_uuid_obj;
+ char sz_obj_type[MAX_INT2CHAR_LENGTH]; /* str. rep. of obj_type. */
+ u32 dw_key_len = 0;
+ struct dcd_key_elem *dcd_key;
+ int len;
+
+ DBC_REQUIRE(refs >= 0);
+ DBC_REQUIRE(index >= 0);
+ DBC_REQUIRE(uuid_obj != NULL);
+
+ if ((index != 0) && (enum_refs == 0)) {
+ /*
+ * If an enumeration is being performed on an index greater
+ * than zero, then the current enum_refs must have been
+ * incremented to greater than zero.
+ */
+ status = -EIDRM;
+ } else {
+ /*
+ * Pre-determine final key length. It's length of DCD_REGKEY +
+ * "_\0" + length of sz_obj_type string + terminating NULL.
+ */
+ dw_key_len = strlen(DCD_REGKEY) + 1 + sizeof(sz_obj_type) + 1;
+ DBC_ASSERT(dw_key_len < DCD_MAXPATHLENGTH);
+
+ /* Create proper REG key; concatenate DCD_REGKEY with
+ * obj_type. */
+ strncpy(sz_reg_key, DCD_REGKEY, strlen(DCD_REGKEY) + 1);
+ if ((strlen(sz_reg_key) + strlen("_\0")) <
+ DCD_MAXPATHLENGTH) {
+ strncat(sz_reg_key, "_\0", 2);
+ } else {
+ status = -EPERM;
+ }
+
+ /* This snprintf is guaranteed not to exceed max size of an
+ * integer. */
+ status = snprintf(sz_obj_type, MAX_INT2CHAR_LENGTH, "%d",
+ obj_type);
+
+ if (status == -1) {
+ status = -EPERM;
+ } else {
+ status = 0;
+ if ((strlen(sz_reg_key) + strlen(sz_obj_type)) <
+ DCD_MAXPATHLENGTH) {
+ strncat(sz_reg_key, sz_obj_type,
+ strlen(sz_obj_type) + 1);
+ } else {
+ status = -EPERM;
+ }
+ }
+
+ if (!status) {
+ len = strlen(sz_reg_key);
+ spin_lock(&dbdcd_lock);
+ list_for_each_entry(dcd_key, &reg_key_list, link) {
+ if (!strncmp(dcd_key->name, sz_reg_key, len)
+ && !index--) {
+ strncpy(sz_value, &dcd_key->name[len],
+ strlen(&dcd_key->name[len]) + 1);
+ break;
+ }
+ }
+ spin_unlock(&dbdcd_lock);
+
+ if (&dcd_key->link == &reg_key_list)
+ status = -ENODATA;
+ }
+
+ if (!status) {
+ /* Create UUID value using string retrieved from
+ * registry. */
+ uuid_uuid_from_string(sz_value, &dsp_uuid_obj);
+
+ *uuid_obj = dsp_uuid_obj;
+
+ /* Increment enum_refs to update reference count. */
+ enum_refs++;
+
+ status = 0;
+ } else if (status == -ENODATA) {
+ /* At the end of enumeration. Reset enum_refs. */
+ enum_refs = 0;
+
+ /*
+ * TODO: Revisit, this is not an errror case but code
+ * expects non-zero value.
+ */
+ status = ENODATA;
+ } else {
+ status = -EPERM;
+ }
+ }
+
+ DBC_ENSURE(uuid_obj || (status == -EPERM));
+
+ return status;
+}
+
+/*
+ * ======== dcd_exit ========
+ * Purpose:
+ * Discontinue usage of the DCD module.
+ */
+void dcd_exit(void)
+{
+ struct dcd_key_elem *rv, *rv_tmp;
+ DBC_REQUIRE(refs > 0);
+
+ refs--;
+ if (refs == 0) {
+ cod_exit();
+ list_for_each_entry_safe(rv, rv_tmp, &reg_key_list, link) {
+ list_del(&rv->link);
+ kfree(rv->path);
+ kfree(rv);
+ }
+ }
+
+ DBC_ENSURE(refs >= 0);
+}
+
+/*
+ * ======== dcd_get_dep_libs ========
+ */
+int dcd_get_dep_libs(struct dcd_manager *hdcd_mgr,
+ struct dsp_uuid *uuid_obj,
+ u16 num_libs, struct dsp_uuid *dep_lib_uuids,
+ bool *prstnt_dep_libs,
+ enum nldr_phase phase)
+{
+ int status = 0;
+
+ DBC_REQUIRE(refs > 0);
+ DBC_REQUIRE(hdcd_mgr);
+ DBC_REQUIRE(uuid_obj != NULL);
+ DBC_REQUIRE(dep_lib_uuids != NULL);
+ DBC_REQUIRE(prstnt_dep_libs != NULL);
+
+ status =
+ get_dep_lib_info(hdcd_mgr, uuid_obj, &num_libs, NULL, dep_lib_uuids,
+ prstnt_dep_libs, phase);
+
+ return status;
+}
+
+/*
+ * ======== dcd_get_num_dep_libs ========
+ */
+int dcd_get_num_dep_libs(struct dcd_manager *hdcd_mgr,
+ struct dsp_uuid *uuid_obj,
+ u16 *num_libs, u16 *num_pers_libs,
+ enum nldr_phase phase)
+{
+ int status = 0;
+
+ DBC_REQUIRE(refs > 0);
+ DBC_REQUIRE(hdcd_mgr);
+ DBC_REQUIRE(num_libs != NULL);
+ DBC_REQUIRE(num_pers_libs != NULL);
+ DBC_REQUIRE(uuid_obj != NULL);
+
+ status = get_dep_lib_info(hdcd_mgr, uuid_obj, num_libs, num_pers_libs,
+ NULL, NULL, phase);
+
+ return status;
+}
+
+/*
+ * ======== dcd_get_object_def ========
+ * Purpose:
+ * Retrieves the properties of a node or processor based on the UUID and
+ * object type.
+ */
+int dcd_get_object_def(struct dcd_manager *hdcd_mgr,
+ struct dsp_uuid *obj_uuid,
+ enum dsp_dcdobjtype obj_type,
+ struct dcd_genericobj *obj_def)
+{
+ struct dcd_manager *dcd_mgr_obj = hdcd_mgr; /* ptr to DCD mgr */
+ struct cod_libraryobj *lib = NULL;
+ int status = 0;
+ u32 ul_addr = 0; /* Used by cod_get_section */
+ u32 ul_len = 0; /* Used by cod_get_section */
+ u32 dw_buf_size; /* Used by REG functions */
+ char sz_reg_key[DCD_MAXPATHLENGTH];
+ char *sz_uuid; /*[MAXUUIDLEN]; */
+ struct dcd_key_elem *dcd_key = NULL;
+ char sz_sect_name[MAXUUIDLEN + 2]; /* ".[UUID]\0" */
+ char *psz_coff_buf;
+ u32 dw_key_len; /* Len of REG key. */
+ char sz_obj_type[MAX_INT2CHAR_LENGTH]; /* str. rep. of obj_type. */
+
+ DBC_REQUIRE(refs > 0);
+ DBC_REQUIRE(obj_def != NULL);
+ DBC_REQUIRE(obj_uuid != NULL);
+
+ sz_uuid = kzalloc(MAXUUIDLEN, GFP_KERNEL);
+ if (!sz_uuid) {
+ status = -ENOMEM;
+ goto func_end;
+ }
+
+ if (!hdcd_mgr) {
+ status = -EFAULT;
+ goto func_end;
+ }
+
+ /* Pre-determine final key length. It's length of DCD_REGKEY +
+ * "_\0" + length of sz_obj_type string + terminating NULL */
+ dw_key_len = strlen(DCD_REGKEY) + 1 + sizeof(sz_obj_type) + 1;
+ DBC_ASSERT(dw_key_len < DCD_MAXPATHLENGTH);
+
+ /* Create proper REG key; concatenate DCD_REGKEY with obj_type. */
+ strncpy(sz_reg_key, DCD_REGKEY, strlen(DCD_REGKEY) + 1);
+
+ if ((strlen(sz_reg_key) + strlen("_\0")) < DCD_MAXPATHLENGTH)
+ strncat(sz_reg_key, "_\0", 2);
+ else
+ status = -EPERM;
+
+ status = snprintf(sz_obj_type, MAX_INT2CHAR_LENGTH, "%d", obj_type);
+ if (status == -1) {
+ status = -EPERM;
+ } else {
+ status = 0;
+
+ if ((strlen(sz_reg_key) + strlen(sz_obj_type)) <
+ DCD_MAXPATHLENGTH) {
+ strncat(sz_reg_key, sz_obj_type,
+ strlen(sz_obj_type) + 1);
+ } else {
+ status = -EPERM;
+ }
+
+ /* Create UUID value to set in registry. */
+ uuid_uuid_to_string(obj_uuid, sz_uuid, MAXUUIDLEN);
+
+ if ((strlen(sz_reg_key) + MAXUUIDLEN) < DCD_MAXPATHLENGTH)
+ strncat(sz_reg_key, sz_uuid, MAXUUIDLEN);
+ else
+ status = -EPERM;
+
+ /* Retrieve paths from the registry based on struct dsp_uuid */
+ dw_buf_size = DCD_MAXPATHLENGTH;
+ }
+ if (!status) {
+ spin_lock(&dbdcd_lock);
+ list_for_each_entry(dcd_key, &reg_key_list, link) {
+ if (!strncmp(dcd_key->name, sz_reg_key,
+ strlen(sz_reg_key) + 1))
+ break;
+ }
+ spin_unlock(&dbdcd_lock);
+ if (&dcd_key->link == &reg_key_list) {
+ status = -ENOKEY;
+ goto func_end;
+ }
+ }
+
+
+ /* Open COFF file. */
+ status = cod_open(dcd_mgr_obj->cod_mgr, dcd_key->path,
+ COD_NOLOAD, &lib);
+ if (status) {
+ status = -EACCES;
+ goto func_end;
+ }
+
+ /* Ensure sz_uuid + 1 is not greater than sizeof sz_sect_name. */
+ DBC_ASSERT((strlen(sz_uuid) + 1) < sizeof(sz_sect_name));
+
+ /* Create section name based on node UUID. A period is
+ * pre-pended to the UUID string to form the section name.
+ * I.e. ".24BC8D90_BB45_11d4_B756_006008BDB66F" */
+ strncpy(sz_sect_name, ".", 2);
+ strncat(sz_sect_name, sz_uuid, strlen(sz_uuid));
+
+ /* Get section information. */
+ status = cod_get_section(lib, sz_sect_name, &ul_addr, &ul_len);
+ if (status) {
+ status = -EACCES;
+ goto func_end;
+ }
+
+ /* Allocate zeroed buffer. */
+ psz_coff_buf = kzalloc(ul_len + 4, GFP_KERNEL);
+#ifdef _DB_TIOMAP
+ if (strstr(dcd_key->path, "iva") == NULL) {
+ /* Locate section by objectID and read its content. */
+ status =
+ cod_read_section(lib, sz_sect_name, psz_coff_buf, ul_len);
+ } else {
+ status =
+ cod_read_section(lib, sz_sect_name, psz_coff_buf, ul_len);
+ dev_dbg(bridge, "%s: Skipped Byte swap for IVA!!\n", __func__);
+ }
+#else
+ status = cod_read_section(lib, sz_sect_name, psz_coff_buf, ul_len);
+#endif
+ if (!status) {
+ /* Compres DSP buffer to conform to PC format. */
+ if (strstr(dcd_key->path, "iva") == NULL) {
+ compress_buf(psz_coff_buf, ul_len, DSPWORDSIZE);
+ } else {
+ compress_buf(psz_coff_buf, ul_len, 1);
+ dev_dbg(bridge, "%s: Compressing IVA COFF buffer by 1 "
+ "for IVA!!\n", __func__);
+ }
+
+ /* Parse the content of the COFF buffer. */
+ status =
+ get_attrs_from_buf(psz_coff_buf, ul_len, obj_type, obj_def);
+ if (status)
+ status = -EACCES;
+ } else {
+ status = -EACCES;
+ }
+
+ /* Free the previously allocated dynamic buffer. */
+ kfree(psz_coff_buf);
+func_end:
+ if (lib)
+ cod_close(lib);
+
+ kfree(sz_uuid);
+
+ return status;
+}
+
+/*
+ * ======== dcd_get_objects ========
+ */
+int dcd_get_objects(struct dcd_manager *hdcd_mgr,
+ char *sz_coff_path, dcd_registerfxn register_fxn,
+ void *handle)
+{
+ struct dcd_manager *dcd_mgr_obj = hdcd_mgr;
+ int status = 0;
+ char *psz_coff_buf;
+ char *psz_cur;
+ struct cod_libraryobj *lib = NULL;
+ u32 ul_addr = 0; /* Used by cod_get_section */
+ u32 ul_len = 0; /* Used by cod_get_section */
+ char seps[] = ":, ";
+ char *token = NULL;
+ struct dsp_uuid dsp_uuid_obj;
+ s32 object_type;
+
+ DBC_REQUIRE(refs > 0);
+ if (!hdcd_mgr) {
+ status = -EFAULT;
+ goto func_end;
+ }
+
+ /* Open DSP coff file, don't load symbols. */
+ status = cod_open(dcd_mgr_obj->cod_mgr, sz_coff_path, COD_NOLOAD, &lib);
+ if (status) {
+ status = -EACCES;
+ goto func_cont;
+ }
+
+ /* Get DCD_RESIGER_SECTION section information. */
+ status = cod_get_section(lib, DCD_REGISTER_SECTION, &ul_addr, &ul_len);
+ if (status || !(ul_len > 0)) {
+ status = -EACCES;
+ goto func_cont;
+ }
+
+ /* Allocate zeroed buffer. */
+ psz_coff_buf = kzalloc(ul_len + 4, GFP_KERNEL);
+#ifdef _DB_TIOMAP
+ if (strstr(sz_coff_path, "iva") == NULL) {
+ /* Locate section by objectID and read its content. */
+ status = cod_read_section(lib, DCD_REGISTER_SECTION,
+ psz_coff_buf, ul_len);
+ } else {
+ dev_dbg(bridge, "%s: Skipped Byte swap for IVA!!\n", __func__);
+ status = cod_read_section(lib, DCD_REGISTER_SECTION,
+ psz_coff_buf, ul_len);
+ }
+#else
+ status =
+ cod_read_section(lib, DCD_REGISTER_SECTION, psz_coff_buf, ul_len);
+#endif
+ if (!status) {
+ /* Compress DSP buffer to conform to PC format. */
+ if (strstr(sz_coff_path, "iva") == NULL) {
+ compress_buf(psz_coff_buf, ul_len, DSPWORDSIZE);
+ } else {
+ compress_buf(psz_coff_buf, ul_len, 1);
+ dev_dbg(bridge, "%s: Compress COFF buffer with 1 word "
+ "for IVA!!\n", __func__);
+ }
+
+ /* Read from buffer and register object in buffer. */
+ psz_cur = psz_coff_buf;
+ while ((token = strsep(&psz_cur, seps)) && *token != '\0') {
+ /* Retrieve UUID string. */
+ uuid_uuid_from_string(token, &dsp_uuid_obj);
+
+ /* Retrieve object type */
+ token = strsep(&psz_cur, seps);
+
+ /* Retrieve object type */
+ object_type = atoi(token);
+
+ /*
+ * Apply register_fxn to the found DCD object.
+ * Possible actions include:
+ *
+ * 1) Register found DCD object.
+ * 2) Unregister found DCD object (when handle == NULL)
+ * 3) Add overlay node.
+ */
+ status =
+ register_fxn(&dsp_uuid_obj, object_type, handle);
+ if (status) {
+ /* if error occurs, break from while loop. */
+ break;
+ }
+ }
+ } else {
+ status = -EACCES;
+ }
+
+ /* Free the previously allocated dynamic buffer. */
+ kfree(psz_coff_buf);
+func_cont:
+ if (lib)
+ cod_close(lib);
+
+func_end:
+ return status;
+}
+
+/*
+ * ======== dcd_get_library_name ========
+ * Purpose:
+ * Retrieves the library name for the given UUID.
+ *
+ */
+int dcd_get_library_name(struct dcd_manager *hdcd_mgr,
+ struct dsp_uuid *uuid_obj,
+ char *str_lib_name,
+ u32 *buff_size,
+ enum nldr_phase phase, bool *phase_split)
+{
+ char sz_reg_key[DCD_MAXPATHLENGTH];
+ char sz_uuid[MAXUUIDLEN];
+ u32 dw_key_len; /* Len of REG key. */
+ char sz_obj_type[MAX_INT2CHAR_LENGTH]; /* str. rep. of obj_type. */
+ int status = 0;
+ struct dcd_key_elem *dcd_key = NULL;
+
+ DBC_REQUIRE(uuid_obj != NULL);
+ DBC_REQUIRE(str_lib_name != NULL);
+ DBC_REQUIRE(buff_size != NULL);
+ DBC_REQUIRE(hdcd_mgr);
+
+ dev_dbg(bridge, "%s: hdcd_mgr %p, uuid_obj %p, str_lib_name %p,"
+ " buff_size %p\n", __func__, hdcd_mgr, uuid_obj, str_lib_name,
+ buff_size);
+
+ /*
+ * Pre-determine final key length. It's length of DCD_REGKEY +
+ * "_\0" + length of sz_obj_type string + terminating NULL.
+ */
+ dw_key_len = strlen(DCD_REGKEY) + 1 + sizeof(sz_obj_type) + 1;
+ DBC_ASSERT(dw_key_len < DCD_MAXPATHLENGTH);
+
+ /* Create proper REG key; concatenate DCD_REGKEY with obj_type. */
+ strncpy(sz_reg_key, DCD_REGKEY, strlen(DCD_REGKEY) + 1);
+ if ((strlen(sz_reg_key) + strlen("_\0")) < DCD_MAXPATHLENGTH)
+ strncat(sz_reg_key, "_\0", 2);
+ else
+ status = -EPERM;
+
+ switch (phase) {
+ case NLDR_CREATE:
+ /* create phase type */
+ sprintf(sz_obj_type, "%d", DSP_DCDCREATELIBTYPE);
+ break;
+ case NLDR_EXECUTE:
+ /* execute phase type */
+ sprintf(sz_obj_type, "%d", DSP_DCDEXECUTELIBTYPE);
+ break;
+ case NLDR_DELETE:
+ /* delete phase type */
+ sprintf(sz_obj_type, "%d", DSP_DCDDELETELIBTYPE);
+ break;
+ case NLDR_NOPHASE:
+ /* known to be a dependent library */
+ sprintf(sz_obj_type, "%d", DSP_DCDLIBRARYTYPE);
+ break;
+ default:
+ status = -EINVAL;
+ DBC_ASSERT(false);
+ }
+ if (!status) {
+ if ((strlen(sz_reg_key) + strlen(sz_obj_type)) <
+ DCD_MAXPATHLENGTH) {
+ strncat(sz_reg_key, sz_obj_type,
+ strlen(sz_obj_type) + 1);
+ } else {
+ status = -EPERM;
+ }
+ /* Create UUID value to find match in registry. */
+ uuid_uuid_to_string(uuid_obj, sz_uuid, MAXUUIDLEN);
+ if ((strlen(sz_reg_key) + MAXUUIDLEN) < DCD_MAXPATHLENGTH)
+ strncat(sz_reg_key, sz_uuid, MAXUUIDLEN);
+ else
+ status = -EPERM;
+ }
+ if (!status) {
+ spin_lock(&dbdcd_lock);
+ list_for_each_entry(dcd_key, &reg_key_list, link) {
+ /* See if the name matches. */
+ if (!strncmp(dcd_key->name, sz_reg_key,
+ strlen(sz_reg_key) + 1))
+ break;
+ }
+ spin_unlock(&dbdcd_lock);
+ }
+
+ if (&dcd_key->link == &reg_key_list)
+ status = -ENOKEY;
+
+ /* If can't find, phases might be registered as generic LIBRARYTYPE */
+ if (status && phase != NLDR_NOPHASE) {
+ if (phase_split)
+ *phase_split = false;
+
+ strncpy(sz_reg_key, DCD_REGKEY, strlen(DCD_REGKEY) + 1);
+ if ((strlen(sz_reg_key) + strlen("_\0")) <
+ DCD_MAXPATHLENGTH) {
+ strncat(sz_reg_key, "_\0", 2);
+ } else {
+ status = -EPERM;
+ }
+ sprintf(sz_obj_type, "%d", DSP_DCDLIBRARYTYPE);
+ if ((strlen(sz_reg_key) + strlen(sz_obj_type))
+ < DCD_MAXPATHLENGTH) {
+ strncat(sz_reg_key, sz_obj_type,
+ strlen(sz_obj_type) + 1);
+ } else {
+ status = -EPERM;
+ }
+ uuid_uuid_to_string(uuid_obj, sz_uuid, MAXUUIDLEN);
+ if ((strlen(sz_reg_key) + MAXUUIDLEN) < DCD_MAXPATHLENGTH)
+ strncat(sz_reg_key, sz_uuid, MAXUUIDLEN);
+ else
+ status = -EPERM;
+
+ spin_lock(&dbdcd_lock);
+ list_for_each_entry(dcd_key, &reg_key_list, link) {
+ /* See if the name matches. */
+ if (!strncmp(dcd_key->name, sz_reg_key,
+ strlen(sz_reg_key) + 1))
+ break;
+ }
+ spin_unlock(&dbdcd_lock);
+
+ status = (&dcd_key->link != &reg_key_list) ?
+ 0 : -ENOKEY;
+ }
+
+ if (!status)
+ memcpy(str_lib_name, dcd_key->path, strlen(dcd_key->path) + 1);
+ return status;
+}
+
+/*
+ * ======== dcd_init ========
+ * Purpose:
+ * Initialize the DCD module.
+ */
+bool dcd_init(void)
+{
+ bool init_cod;
+ bool ret = true;
+
+ DBC_REQUIRE(refs >= 0);
+
+ if (refs == 0) {
+ /* Initialize required modules. */
+ init_cod = cod_init();
+
+ if (!init_cod) {
+ ret = false;
+ /* Exit initialized modules. */
+ if (init_cod)
+ cod_exit();
+ }
+
+ INIT_LIST_HEAD(&reg_key_list);
+ }
+
+ if (ret)
+ refs++;
+
+ DBC_ENSURE((ret && (refs > 0)) || (!ret && (refs == 0)));
+
+ return ret;
+}
+
+/*
+ * ======== dcd_register_object ========
+ * Purpose:
+ * Registers a node or a processor with the DCD.
+ * If psz_path_name == NULL, unregister the specified DCD object.
+ */
+int dcd_register_object(struct dsp_uuid *uuid_obj,
+ enum dsp_dcdobjtype obj_type,
+ char *psz_path_name)
+{
+ int status = 0;
+ char sz_reg_key[DCD_MAXPATHLENGTH];
+ char sz_uuid[MAXUUIDLEN + 1];
+ u32 dw_path_size = 0;
+ u32 dw_key_len; /* Len of REG key. */
+ char sz_obj_type[MAX_INT2CHAR_LENGTH]; /* str. rep. of obj_type. */
+ struct dcd_key_elem *dcd_key = NULL;
+
+ DBC_REQUIRE(refs > 0);
+ DBC_REQUIRE(uuid_obj != NULL);
+ DBC_REQUIRE((obj_type == DSP_DCDNODETYPE) ||
+ (obj_type == DSP_DCDPROCESSORTYPE) ||
+ (obj_type == DSP_DCDLIBRARYTYPE) ||
+ (obj_type == DSP_DCDCREATELIBTYPE) ||
+ (obj_type == DSP_DCDEXECUTELIBTYPE) ||
+ (obj_type == DSP_DCDDELETELIBTYPE));
+
+ dev_dbg(bridge, "%s: object UUID %p, obj_type %d, szPathName %s\n",
+ __func__, uuid_obj, obj_type, psz_path_name);
+
+ /*
+ * Pre-determine final key length. It's length of DCD_REGKEY +
+ * "_\0" + length of sz_obj_type string + terminating NULL.
+ */
+ dw_key_len = strlen(DCD_REGKEY) + 1 + sizeof(sz_obj_type) + 1;
+ DBC_ASSERT(dw_key_len < DCD_MAXPATHLENGTH);
+
+ /* Create proper REG key; concatenate DCD_REGKEY with obj_type. */
+ strncpy(sz_reg_key, DCD_REGKEY, strlen(DCD_REGKEY) + 1);
+ if ((strlen(sz_reg_key) + strlen("_\0")) < DCD_MAXPATHLENGTH)
+ strncat(sz_reg_key, "_\0", 2);
+ else {
+ status = -EPERM;
+ goto func_end;
+ }
+
+ status = snprintf(sz_obj_type, MAX_INT2CHAR_LENGTH, "%d", obj_type);
+ if (status == -1) {
+ status = -EPERM;
+ } else {
+ status = 0;
+ if ((strlen(sz_reg_key) + strlen(sz_obj_type)) <
+ DCD_MAXPATHLENGTH) {
+ strncat(sz_reg_key, sz_obj_type,
+ strlen(sz_obj_type) + 1);
+ } else
+ status = -EPERM;
+
+ /* Create UUID value to set in registry. */
+ uuid_uuid_to_string(uuid_obj, sz_uuid, MAXUUIDLEN);
+ if ((strlen(sz_reg_key) + MAXUUIDLEN) < DCD_MAXPATHLENGTH)
+ strncat(sz_reg_key, sz_uuid, MAXUUIDLEN);
+ else
+ status = -EPERM;
+ }
+
+ if (status)
+ goto func_end;
+
+ /*
+ * If psz_path_name != NULL, perform registration, otherwise,
+ * perform unregistration.
+ */
+
+ if (psz_path_name) {
+ dw_path_size = strlen(psz_path_name) + 1;
+ spin_lock(&dbdcd_lock);
+ list_for_each_entry(dcd_key, &reg_key_list, link) {
+ /* See if the name matches. */
+ if (!strncmp(dcd_key->name, sz_reg_key,
+ strlen(sz_reg_key) + 1))
+ break;
+ }
+ spin_unlock(&dbdcd_lock);
+ if (&dcd_key->link == &reg_key_list) {
+ /*
+ * Add new reg value (UUID+obj_type)
+ * with COFF path info
+ */
+
+ dcd_key = kmalloc(sizeof(struct dcd_key_elem),
+ GFP_KERNEL);
+ if (!dcd_key) {
+ status = -ENOMEM;
+ goto func_end;
+ }
+
+ dcd_key->path = kmalloc(strlen(sz_reg_key) + 1,
+ GFP_KERNEL);
+
+ if (!dcd_key->path) {
+ kfree(dcd_key);
+ status = -ENOMEM;
+ goto func_end;
+ }
+
+ strncpy(dcd_key->name, sz_reg_key,
+ strlen(sz_reg_key) + 1);
+ strncpy(dcd_key->path, psz_path_name ,
+ dw_path_size);
+ spin_lock(&dbdcd_lock);
+ list_add_tail(&dcd_key->link, &reg_key_list);
+ spin_unlock(&dbdcd_lock);
+ } else {
+ /* Make sure the new data is the same. */
+ if (strncmp(dcd_key->path, psz_path_name,
+ dw_path_size)) {
+ /* The caller needs a different data size! */
+ kfree(dcd_key->path);
+ dcd_key->path = kmalloc(dw_path_size,
+ GFP_KERNEL);
+ if (dcd_key->path == NULL) {
+ status = -ENOMEM;
+ goto func_end;
+ }
+ }
+
+ /* We have a match! Copy out the data. */
+ memcpy(dcd_key->path, psz_path_name, dw_path_size);
+ }
+ dev_dbg(bridge, "%s: psz_path_name=%s, dw_path_size=%d\n",
+ __func__, psz_path_name, dw_path_size);
+ } else {
+ /* Deregister an existing object */
+ spin_lock(&dbdcd_lock);
+ list_for_each_entry(dcd_key, &reg_key_list, link) {
+ if (!strncmp(dcd_key->name, sz_reg_key,
+ strlen(sz_reg_key) + 1)) {
+ list_del(&dcd_key->link);
+ kfree(dcd_key->path);
+ kfree(dcd_key);
+ break;
+ }
+ }
+ spin_unlock(&dbdcd_lock);
+ if (&dcd_key->link == &reg_key_list)
+ status = -EPERM;
+ }
+
+ if (!status) {
+ /*
+ * Because the node database has been updated through a
+ * successful object registration/de-registration operation,
+ * we need to reset the object enumeration counter to allow
+ * current enumerations to reflect this update in the node
+ * database.
+ */
+ enum_refs = 0;
+ }
+func_end:
+ return status;
+}
+
+/*
+ * ======== dcd_unregister_object ========
+ * Call DCD_Register object with psz_path_name set to NULL to
+ * perform actual object de-registration.
+ */
+int dcd_unregister_object(struct dsp_uuid *uuid_obj,
+ enum dsp_dcdobjtype obj_type)
+{
+ int status = 0;
+
+ DBC_REQUIRE(refs > 0);
+ DBC_REQUIRE(uuid_obj != NULL);
+ DBC_REQUIRE((obj_type == DSP_DCDNODETYPE) ||
+ (obj_type == DSP_DCDPROCESSORTYPE) ||
+ (obj_type == DSP_DCDLIBRARYTYPE) ||
+ (obj_type == DSP_DCDCREATELIBTYPE) ||
+ (obj_type == DSP_DCDEXECUTELIBTYPE) ||
+ (obj_type == DSP_DCDDELETELIBTYPE));
+
+ /*
+ * When dcd_register_object is called with NULL as pathname,
+ * it indicates an unregister object operation.
+ */
+ status = dcd_register_object(uuid_obj, obj_type, NULL);
+
+ return status;
+}
+
+/*
+ **********************************************************************
+ * DCD Helper Functions
+ **********************************************************************
+ */
+
+/*
+ * ======== atoi ========
+ * Purpose:
+ * This function converts strings in decimal or hex format to integers.
+ */
+static s32 atoi(char *psz_buf)
+{
+ char *pch = psz_buf;
+ s32 base = 0;
+ unsigned long res;
+ int ret_val;
+
+ while (isspace(*pch))
+ pch++;
+
+ if (*pch == '-' || *pch == '+') {
+ base = 10;
+ pch++;
+ } else if (*pch && tolower(pch[strlen(pch) - 1]) == 'h') {
+ base = 16;
+ }
+
+ ret_val = strict_strtoul(pch, base, &res);
+
+ return ret_val ? : res;
+}
+
+/*
+ * ======== get_attrs_from_buf ========
+ * Purpose:
+ * Parse the content of a buffer filled with DSP-side data and
+ * retrieve an object's attributes from it. IMPORTANT: Assume the
+ * buffer has been converted from DSP format to GPP format.
+ */
+static int get_attrs_from_buf(char *psz_buf, u32 ul_buf_size,
+ enum dsp_dcdobjtype obj_type,
+ struct dcd_genericobj *gen_obj)
+{
+ int status = 0;
+ char seps[] = ", ";
+ char *psz_cur;
+ char *token;
+ s32 token_len = 0;
+ u32 i = 0;
+#ifdef _DB_TIOMAP
+ s32 entry_id;
+#endif
+
+ DBC_REQUIRE(psz_buf != NULL);
+ DBC_REQUIRE(ul_buf_size != 0);
+ DBC_REQUIRE((obj_type == DSP_DCDNODETYPE)
+ || (obj_type == DSP_DCDPROCESSORTYPE));
+ DBC_REQUIRE(gen_obj != NULL);
+
+ switch (obj_type) {
+ case DSP_DCDNODETYPE:
+ /*
+ * Parse COFF sect buffer to retrieve individual tokens used
+ * to fill in object attrs.
+ */
+ psz_cur = psz_buf;
+ token = strsep(&psz_cur, seps);
+
+ /* u32 cb_struct */
+ gen_obj->obj_data.node_obj.ndb_props.cb_struct =
+ (u32) atoi(token);
+ token = strsep(&psz_cur, seps);
+
+ /* dsp_uuid ui_node_id */
+ uuid_uuid_from_string(token,
+ &gen_obj->obj_data.node_obj.ndb_props.
+ ui_node_id);
+ token = strsep(&psz_cur, seps);
+
+ /* ac_name */
+ DBC_REQUIRE(token);
+ token_len = strlen(token);
+ if (token_len > DSP_MAXNAMELEN - 1)
+ token_len = DSP_MAXNAMELEN - 1;
+
+ strncpy(gen_obj->obj_data.node_obj.ndb_props.ac_name,
+ token, token_len);
+ gen_obj->obj_data.node_obj.ndb_props.ac_name[token_len] = '\0';
+ token = strsep(&psz_cur, seps);
+ /* u32 ntype */
+ gen_obj->obj_data.node_obj.ndb_props.ntype = atoi(token);
+ token = strsep(&psz_cur, seps);
+ /* u32 cache_on_gpp */
+ gen_obj->obj_data.node_obj.ndb_props.cache_on_gpp = atoi(token);
+ token = strsep(&psz_cur, seps);
+ /* dsp_resourcereqmts dsp_resource_reqmts */
+ gen_obj->obj_data.node_obj.ndb_props.dsp_resource_reqmts.
+ cb_struct = (u32) atoi(token);
+ token = strsep(&psz_cur, seps);
+
+ gen_obj->obj_data.node_obj.ndb_props.
+ dsp_resource_reqmts.static_data_size = atoi(token);
+ token = strsep(&psz_cur, seps);
+ gen_obj->obj_data.node_obj.ndb_props.
+ dsp_resource_reqmts.global_data_size = atoi(token);
+ token = strsep(&psz_cur, seps);
+ gen_obj->obj_data.node_obj.ndb_props.
+ dsp_resource_reqmts.program_mem_size = atoi(token);
+ token = strsep(&psz_cur, seps);
+ gen_obj->obj_data.node_obj.ndb_props.
+ dsp_resource_reqmts.uwc_execution_time = atoi(token);
+ token = strsep(&psz_cur, seps);
+ gen_obj->obj_data.node_obj.ndb_props.
+ dsp_resource_reqmts.uwc_period = atoi(token);
+ token = strsep(&psz_cur, seps);
+
+ gen_obj->obj_data.node_obj.ndb_props.
+ dsp_resource_reqmts.uwc_deadline = atoi(token);
+ token = strsep(&psz_cur, seps);
+
+ gen_obj->obj_data.node_obj.ndb_props.
+ dsp_resource_reqmts.avg_exection_time = atoi(token);
+ token = strsep(&psz_cur, seps);
+
+ gen_obj->obj_data.node_obj.ndb_props.
+ dsp_resource_reqmts.minimum_period = atoi(token);
+ token = strsep(&psz_cur, seps);
+
+ /* s32 prio */
+ gen_obj->obj_data.node_obj.ndb_props.prio = atoi(token);
+ token = strsep(&psz_cur, seps);
+
+ /* u32 stack_size */
+ gen_obj->obj_data.node_obj.ndb_props.stack_size = atoi(token);
+ token = strsep(&psz_cur, seps);
+
+ /* u32 sys_stack_size */
+ gen_obj->obj_data.node_obj.ndb_props.sys_stack_size =
+ atoi(token);
+ token = strsep(&psz_cur, seps);
+
+ /* u32 stack_seg */
+ gen_obj->obj_data.node_obj.ndb_props.stack_seg = atoi(token);
+ token = strsep(&psz_cur, seps);
+
+ /* u32 message_depth */
+ gen_obj->obj_data.node_obj.ndb_props.message_depth =
+ atoi(token);
+ token = strsep(&psz_cur, seps);
+
+ /* u32 num_input_streams */
+ gen_obj->obj_data.node_obj.ndb_props.num_input_streams =
+ atoi(token);
+ token = strsep(&psz_cur, seps);
+
+ /* u32 num_output_streams */
+ gen_obj->obj_data.node_obj.ndb_props.num_output_streams =
+ atoi(token);
+ token = strsep(&psz_cur, seps);
+
+ /* u32 utimeout */
+ gen_obj->obj_data.node_obj.ndb_props.utimeout = atoi(token);
+ token = strsep(&psz_cur, seps);
+
+ /* char *pstr_create_phase_fxn */
+ DBC_REQUIRE(token);
+ token_len = strlen(token);
+ gen_obj->obj_data.node_obj.pstr_create_phase_fxn =
+ kzalloc(token_len + 1, GFP_KERNEL);
+ strncpy(gen_obj->obj_data.node_obj.pstr_create_phase_fxn,
+ token, token_len);
+ gen_obj->obj_data.node_obj.pstr_create_phase_fxn[token_len] =
+ '\0';
+ token = strsep(&psz_cur, seps);
+
+ /* char *pstr_execute_phase_fxn */
+ DBC_REQUIRE(token);
+ token_len = strlen(token);
+ gen_obj->obj_data.node_obj.pstr_execute_phase_fxn =
+ kzalloc(token_len + 1, GFP_KERNEL);
+ strncpy(gen_obj->obj_data.node_obj.pstr_execute_phase_fxn,
+ token, token_len);
+ gen_obj->obj_data.node_obj.pstr_execute_phase_fxn[token_len] =
+ '\0';
+ token = strsep(&psz_cur, seps);
+
+ /* char *pstr_delete_phase_fxn */
+ DBC_REQUIRE(token);
+ token_len = strlen(token);
+ gen_obj->obj_data.node_obj.pstr_delete_phase_fxn =
+ kzalloc(token_len + 1, GFP_KERNEL);
+ strncpy(gen_obj->obj_data.node_obj.pstr_delete_phase_fxn,
+ token, token_len);
+ gen_obj->obj_data.node_obj.pstr_delete_phase_fxn[token_len] =
+ '\0';
+ token = strsep(&psz_cur, seps);
+
+ /* Segment id for message buffers */
+ gen_obj->obj_data.node_obj.msg_segid = atoi(token);
+ token = strsep(&psz_cur, seps);
+
+ /* Message notification type */
+ gen_obj->obj_data.node_obj.msg_notify_type = atoi(token);
+ token = strsep(&psz_cur, seps);
+
+ /* char *pstr_i_alg_name */
+ if (token) {
+ token_len = strlen(token);
+ gen_obj->obj_data.node_obj.pstr_i_alg_name =
+ kzalloc(token_len + 1, GFP_KERNEL);
+ strncpy(gen_obj->obj_data.node_obj.pstr_i_alg_name,
+ token, token_len);
+ gen_obj->obj_data.node_obj.pstr_i_alg_name[token_len] =
+ '\0';
+ token = strsep(&psz_cur, seps);
+ }
+
+ /* Load type (static, dynamic, or overlay) */
+ if (token) {
+ gen_obj->obj_data.node_obj.us_load_type = atoi(token);
+ token = strsep(&psz_cur, seps);
+ }
+
+ /* Dynamic load data requirements */
+ if (token) {
+ gen_obj->obj_data.node_obj.ul_data_mem_seg_mask =
+ atoi(token);
+ token = strsep(&psz_cur, seps);
+ }
+
+ /* Dynamic load code requirements */
+ if (token) {
+ gen_obj->obj_data.node_obj.ul_code_mem_seg_mask =
+ atoi(token);
+ token = strsep(&psz_cur, seps);
+ }
+
+ /* Extract node profiles into node properties */
+ if (token) {
+
+ gen_obj->obj_data.node_obj.ndb_props.count_profiles =
+ atoi(token);
+ for (i = 0;
+ i <
+ gen_obj->obj_data.node_obj.
+ ndb_props.count_profiles; i++) {
+ token = strsep(&psz_cur, seps);
+ if (token) {
+ /* Heap Size for the node */
+ gen_obj->obj_data.node_obj.
+ ndb_props.node_profiles[i].
+ ul_heap_size = atoi(token);
+ }
+ }
+ }
+ token = strsep(&psz_cur, seps);
+ if (token) {
+ gen_obj->obj_data.node_obj.ndb_props.stack_seg_name =
+ (u32) (token);
+ }
+
+ break;
+
+ case DSP_DCDPROCESSORTYPE:
+ /*
+ * Parse COFF sect buffer to retrieve individual tokens used
+ * to fill in object attrs.
+ */
+ psz_cur = psz_buf;
+ token = strsep(&psz_cur, seps);
+
+ gen_obj->obj_data.proc_info.cb_struct = atoi(token);
+ token = strsep(&psz_cur, seps);
+
+ gen_obj->obj_data.proc_info.processor_family = atoi(token);
+ token = strsep(&psz_cur, seps);
+
+ gen_obj->obj_data.proc_info.processor_type = atoi(token);
+ token = strsep(&psz_cur, seps);
+
+ gen_obj->obj_data.proc_info.clock_rate = atoi(token);
+ token = strsep(&psz_cur, seps);
+
+ gen_obj->obj_data.proc_info.ul_internal_mem_size = atoi(token);
+ token = strsep(&psz_cur, seps);
+
+ gen_obj->obj_data.proc_info.ul_external_mem_size = atoi(token);
+ token = strsep(&psz_cur, seps);
+
+ gen_obj->obj_data.proc_info.processor_id = atoi(token);
+ token = strsep(&psz_cur, seps);
+
+ gen_obj->obj_data.proc_info.ty_running_rtos = atoi(token);
+ token = strsep(&psz_cur, seps);
+
+ gen_obj->obj_data.proc_info.node_min_priority = atoi(token);
+ token = strsep(&psz_cur, seps);
+
+ gen_obj->obj_data.proc_info.node_max_priority = atoi(token);
+
+#ifdef _DB_TIOMAP
+ /* Proc object may contain additional(extended) attributes. */
+ /* attr must match proc.hxx */
+ for (entry_id = 0; entry_id < 7; entry_id++) {
+ token = strsep(&psz_cur, seps);
+ gen_obj->obj_data.ext_proc_obj.ty_tlb[entry_id].
+ ul_gpp_phys = atoi(token);
+
+ token = strsep(&psz_cur, seps);
+ gen_obj->obj_data.ext_proc_obj.ty_tlb[entry_id].
+ ul_dsp_virt = atoi(token);
+ }
+#endif
+
+ break;
+
+ default:
+ status = -EPERM;
+ break;
+ }
+
+ return status;
+}
+
+/*
+ * ======== CompressBuffer ========
+ * Purpose:
+ * Compress the DSP buffer, if necessary, to conform to PC format.
+ */
+static void compress_buf(char *psz_buf, u32 ul_buf_size, s32 char_size)
+{
+ char *p;
+ char ch;
+ char *q;
+
+ p = psz_buf;
+ if (p == NULL)
+ return;
+
+ for (q = psz_buf; q < (psz_buf + ul_buf_size);) {
+ ch = dsp_char2_gpp_char(q, char_size);
+ if (ch == '\\') {
+ q += char_size;
+ ch = dsp_char2_gpp_char(q, char_size);
+ switch (ch) {
+ case 't':
+ *p = '\t';
+ break;
+
+ case 'n':
+ *p = '\n';
+ break;
+
+ case 'r':
+ *p = '\r';
+ break;
+
+ case '0':
+ *p = '\0';
+ break;
+
+ default:
+ *p = ch;
+ break;
+ }
+ } else {
+ *p = ch;
+ }
+ p++;
+ q += char_size;
+ }
+
+ /* NULL out remainder of buffer. */
+ while (p < q)
+ *p++ = '\0';
+}
+
+/*
+ * ======== dsp_char2_gpp_char ========
+ * Purpose:
+ * Convert DSP char to host GPP char in a portable manner
+ */
+static char dsp_char2_gpp_char(char *word, s32 dsp_char_size)
+{
+ char ch = '\0';
+ char *ch_src;
+ s32 i;
+
+ for (ch_src = word, i = dsp_char_size; i > 0; i--)
+ ch |= *ch_src++;
+
+ return ch;
+}
+
+/*
+ * ======== get_dep_lib_info ========
+ */
+static int get_dep_lib_info(struct dcd_manager *hdcd_mgr,
+ struct dsp_uuid *uuid_obj,
+ u16 *num_libs,
+ u16 *num_pers_libs,
+ struct dsp_uuid *dep_lib_uuids,
+ bool *prstnt_dep_libs,
+ enum nldr_phase phase)
+{
+ struct dcd_manager *dcd_mgr_obj = hdcd_mgr;
+ char *psz_coff_buf = NULL;
+ char *psz_cur;
+ char *psz_file_name = NULL;
+ struct cod_libraryobj *lib = NULL;
+ u32 ul_addr = 0; /* Used by cod_get_section */
+ u32 ul_len = 0; /* Used by cod_get_section */
+ u32 dw_data_size = COD_MAXPATHLENGTH;
+ char seps[] = ", ";
+ char *token = NULL;
+ bool get_uuids = (dep_lib_uuids != NULL);
+ u16 dep_libs = 0;
+ int status = 0;
+
+ DBC_REQUIRE(refs > 0);
+
+ DBC_REQUIRE(hdcd_mgr);
+ DBC_REQUIRE(num_libs != NULL);
+ DBC_REQUIRE(uuid_obj != NULL);
+
+ /* Initialize to 0 dependent libraries, if only counting number of
+ * dependent libraries */
+ if (!get_uuids) {
+ *num_libs = 0;
+ *num_pers_libs = 0;
+ }
+
+ /* Allocate a buffer for file name */
+ psz_file_name = kzalloc(dw_data_size, GFP_KERNEL);
+ if (psz_file_name == NULL) {
+ status = -ENOMEM;
+ } else {
+ /* Get the name of the library */
+ status = dcd_get_library_name(hdcd_mgr, uuid_obj, psz_file_name,
+ &dw_data_size, phase, NULL);
+ }
+
+ /* Open the library */
+ if (!status) {
+ status = cod_open(dcd_mgr_obj->cod_mgr, psz_file_name,
+ COD_NOLOAD, &lib);
+ }
+ if (!status) {
+ /* Get dependent library section information. */
+ status = cod_get_section(lib, DEPLIBSECT, &ul_addr, &ul_len);
+
+ if (status) {
+ /* Ok, no dependent libraries */
+ ul_len = 0;
+ status = 0;
+ }
+ }
+
+ if (status || !(ul_len > 0))
+ goto func_cont;
+
+ /* Allocate zeroed buffer. */
+ psz_coff_buf = kzalloc(ul_len + 4, GFP_KERNEL);
+ if (psz_coff_buf == NULL)
+ status = -ENOMEM;
+
+ /* Read section contents. */
+ status = cod_read_section(lib, DEPLIBSECT, psz_coff_buf, ul_len);
+ if (status)
+ goto func_cont;
+
+ /* Compress and format DSP buffer to conform to PC format. */
+ compress_buf(psz_coff_buf, ul_len, DSPWORDSIZE);
+
+ /* Read from buffer */
+ psz_cur = psz_coff_buf;
+ while ((token = strsep(&psz_cur, seps)) && *token != '\0') {
+ if (get_uuids) {
+ if (dep_libs >= *num_libs) {
+ /* Gone beyond the limit */
+ break;
+ } else {
+ /* Retrieve UUID string. */
+ uuid_uuid_from_string(token,
+ &(dep_lib_uuids
+ [dep_libs]));
+ /* Is this library persistent? */
+ token = strsep(&psz_cur, seps);
+ prstnt_dep_libs[dep_libs] = atoi(token);
+ dep_libs++;
+ }
+ } else {
+ /* Advanc to next token */
+ token = strsep(&psz_cur, seps);
+ if (atoi(token))
+ (*num_pers_libs)++;
+
+ /* Just counting number of dependent libraries */
+ (*num_libs)++;
+ }
+ }
+func_cont:
+ if (lib)
+ cod_close(lib);
+
+ /* Free previously allocated dynamic buffers. */
+ kfree(psz_file_name);
+
+ kfree(psz_coff_buf);
+
+ return status;
+}
diff --git a/drivers/staging/tidspbridge/rmgr/disp.c b/drivers/staging/tidspbridge/rmgr/disp.c
new file mode 100644
index 00000000000..b7ce4353e06
--- /dev/null
+++ b/drivers/staging/tidspbridge/rmgr/disp.c
@@ -0,0 +1,752 @@
+/*
+ * disp.c
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * Node Dispatcher interface. Communicates with Resource Manager Server
+ * (RMS) on DSP. Access to RMS is synchronized in NODE.
+ *
+ * Copyright (C) 2005-2006 Texas Instruments, Inc.
+ *
+ * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+#include <linux/types.h>
+
+/* ----------------------------------- Host OS */
+#include <dspbridge/host_os.h>
+
+/* ----------------------------------- DSP/BIOS Bridge */
+#include <dspbridge/dbdefs.h>
+
+/* ----------------------------------- Trace & Debug */
+#include <dspbridge/dbc.h>
+
+/* ----------------------------------- OS Adaptation Layer */
+#include <dspbridge/sync.h>
+
+/* ----------------------------------- Link Driver */
+#include <dspbridge/dspdefs.h>
+
+/* ----------------------------------- Platform Manager */
+#include <dspbridge/dev.h>
+#include <dspbridge/chnldefs.h>
+
+/* ----------------------------------- Resource Manager */
+#include <dspbridge/nodedefs.h>
+#include <dspbridge/nodepriv.h>
+#include <dspbridge/rms_sh.h>
+
+/* ----------------------------------- This */
+#include <dspbridge/disp.h>
+
+/* Size of a reply from RMS */
+#define REPLYSIZE (3 * sizeof(rms_word))
+
+/* Reserved channel offsets for communication with RMS */
+#define CHNLTORMSOFFSET 0
+#define CHNLFROMRMSOFFSET 1
+
+#define CHNLIOREQS 1
+
+/*
+ * ======== disp_object ========
+ */
+struct disp_object {
+ struct dev_object *hdev_obj; /* Device for this processor */
+ /* Function interface to Bridge driver */
+ struct bridge_drv_interface *intf_fxns;
+ struct chnl_mgr *hchnl_mgr; /* Channel manager */
+ struct chnl_object *chnl_to_dsp; /* Chnl for commands to RMS */
+ struct chnl_object *chnl_from_dsp; /* Chnl for replies from RMS */
+ u8 *pbuf; /* Buffer for commands, replies */
+ u32 ul_bufsize; /* pbuf size in bytes */
+ u32 ul_bufsize_rms; /* pbuf size in RMS words */
+ u32 char_size; /* Size of DSP character */
+ u32 word_size; /* Size of DSP word */
+ u32 data_mau_size; /* Size of DSP Data MAU */
+};
+
+static u32 refs;
+
+static void delete_disp(struct disp_object *disp_obj);
+static int fill_stream_def(rms_word *pdw_buf, u32 *ptotal, u32 offset,
+ struct node_strmdef strm_def, u32 max,
+ u32 chars_in_rms_word);
+static int send_message(struct disp_object *disp_obj, u32 timeout,
+ u32 ul_bytes, u32 *pdw_arg);
+
+/*
+ * ======== disp_create ========
+ * Create a NODE Dispatcher object.
+ */
+int disp_create(struct disp_object **dispatch_obj,
+ struct dev_object *hdev_obj,
+ const struct disp_attr *disp_attrs)
+{
+ struct disp_object *disp_obj;
+ struct bridge_drv_interface *intf_fxns;
+ u32 ul_chnl_id;
+ struct chnl_attr chnl_attr_obj;
+ int status = 0;
+ u8 dev_type;
+
+ DBC_REQUIRE(refs > 0);
+ DBC_REQUIRE(dispatch_obj != NULL);
+ DBC_REQUIRE(disp_attrs != NULL);
+ DBC_REQUIRE(hdev_obj != NULL);
+
+ *dispatch_obj = NULL;
+
+ /* Allocate Node Dispatcher object */
+ disp_obj = kzalloc(sizeof(struct disp_object), GFP_KERNEL);
+ if (disp_obj == NULL)
+ status = -ENOMEM;
+ else
+ disp_obj->hdev_obj = hdev_obj;
+
+ /* Get Channel manager and Bridge function interface */
+ if (!status) {
+ status = dev_get_chnl_mgr(hdev_obj, &(disp_obj->hchnl_mgr));
+ if (!status) {
+ (void)dev_get_intf_fxns(hdev_obj, &intf_fxns);
+ disp_obj->intf_fxns = intf_fxns;
+ }
+ }
+
+ /* check device type and decide if streams or messag'ing is used for
+ * RMS/EDS */
+ if (status)
+ goto func_cont;
+
+ status = dev_get_dev_type(hdev_obj, &dev_type);
+
+ if (status)
+ goto func_cont;
+
+ if (dev_type != DSP_UNIT) {
+ status = -EPERM;
+ goto func_cont;
+ }
+
+ disp_obj->char_size = DSPWORDSIZE;
+ disp_obj->word_size = DSPWORDSIZE;
+ disp_obj->data_mau_size = DSPWORDSIZE;
+ /* Open channels for communicating with the RMS */
+ chnl_attr_obj.uio_reqs = CHNLIOREQS;
+ chnl_attr_obj.event_obj = NULL;
+ ul_chnl_id = disp_attrs->ul_chnl_offset + CHNLTORMSOFFSET;
+ status = (*intf_fxns->pfn_chnl_open) (&(disp_obj->chnl_to_dsp),
+ disp_obj->hchnl_mgr,
+ CHNL_MODETODSP, ul_chnl_id,
+ &chnl_attr_obj);
+
+ if (!status) {
+ ul_chnl_id = disp_attrs->ul_chnl_offset + CHNLFROMRMSOFFSET;
+ status =
+ (*intf_fxns->pfn_chnl_open) (&(disp_obj->chnl_from_dsp),
+ disp_obj->hchnl_mgr,
+ CHNL_MODEFROMDSP, ul_chnl_id,
+ &chnl_attr_obj);
+ }
+ if (!status) {
+ /* Allocate buffer for commands, replies */
+ disp_obj->ul_bufsize = disp_attrs->ul_chnl_buf_size;
+ disp_obj->ul_bufsize_rms = RMS_COMMANDBUFSIZE;
+ disp_obj->pbuf = kzalloc(disp_obj->ul_bufsize, GFP_KERNEL);
+ if (disp_obj->pbuf == NULL)
+ status = -ENOMEM;
+ }
+func_cont:
+ if (!status)
+ *dispatch_obj = disp_obj;
+ else
+ delete_disp(disp_obj);
+
+ DBC_ENSURE((status && *dispatch_obj == NULL) ||
+ (!status && *dispatch_obj));
+ return status;
+}
+
+/*
+ * ======== disp_delete ========
+ * Delete the NODE Dispatcher.
+ */
+void disp_delete(struct disp_object *disp_obj)
+{
+ DBC_REQUIRE(refs > 0);
+ DBC_REQUIRE(disp_obj);
+
+ delete_disp(disp_obj);
+}
+
+/*
+ * ======== disp_exit ========
+ * Discontinue usage of DISP module.
+ */
+void disp_exit(void)
+{
+ DBC_REQUIRE(refs > 0);
+
+ refs--;
+
+ DBC_ENSURE(refs >= 0);
+}
+
+/*
+ * ======== disp_init ========
+ * Initialize the DISP module.
+ */
+bool disp_init(void)
+{
+ bool ret = true;
+
+ DBC_REQUIRE(refs >= 0);
+
+ if (ret)
+ refs++;
+
+ DBC_ENSURE((ret && (refs > 0)) || (!ret && (refs >= 0)));
+ return ret;
+}
+
+/*
+ * ======== disp_node_change_priority ========
+ * Change the priority of a node currently running on the target.
+ */
+int disp_node_change_priority(struct disp_object *disp_obj,
+ struct node_object *hnode,
+ u32 rms_fxn, nodeenv node_env, s32 prio)
+{
+ u32 dw_arg;
+ struct rms_command *rms_cmd;
+ int status = 0;
+
+ DBC_REQUIRE(refs > 0);
+ DBC_REQUIRE(disp_obj);
+ DBC_REQUIRE(hnode != NULL);
+
+ /* Send message to RMS to change priority */
+ rms_cmd = (struct rms_command *)(disp_obj->pbuf);
+ rms_cmd->fxn = (rms_word) (rms_fxn);
+ rms_cmd->arg1 = (rms_word) node_env;
+ rms_cmd->arg2 = prio;
+ status = send_message(disp_obj, node_get_timeout(hnode),
+ sizeof(struct rms_command), &dw_arg);
+
+ return status;
+}
+
+/*
+ * ======== disp_node_create ========
+ * Create a node on the DSP by remotely calling the node's create function.
+ */
+int disp_node_create(struct disp_object *disp_obj,
+ struct node_object *hnode, u32 rms_fxn,
+ u32 ul_create_fxn,
+ const struct node_createargs *pargs,
+ nodeenv *node_env)
+{
+ struct node_msgargs node_msg_args;
+ struct node_taskargs task_arg_obj;
+ struct rms_command *rms_cmd;
+ struct rms_msg_args *pmsg_args;
+ struct rms_more_task_args *more_task_args;
+ enum node_type node_type;
+ u32 dw_length;
+ rms_word *pdw_buf = NULL;
+ u32 ul_bytes;
+ u32 i;
+ u32 total;
+ u32 chars_in_rms_word;
+ s32 task_args_offset;
+ s32 sio_in_def_offset;
+ s32 sio_out_def_offset;
+ s32 sio_defs_offset;
+ s32 args_offset = -1;
+ s32 offset;
+ struct node_strmdef strm_def;
+ u32 max;
+ int status = 0;
+ struct dsp_nodeinfo node_info;
+ u8 dev_type;
+
+ DBC_REQUIRE(refs > 0);
+ DBC_REQUIRE(disp_obj);
+ DBC_REQUIRE(hnode != NULL);
+ DBC_REQUIRE(node_get_type(hnode) != NODE_DEVICE);
+ DBC_REQUIRE(node_env != NULL);
+
+ status = dev_get_dev_type(disp_obj->hdev_obj, &dev_type);
+
+ if (status)
+ goto func_end;
+
+ if (dev_type != DSP_UNIT) {
+ dev_dbg(bridge, "%s: unknown device type = 0x%x\n",
+ __func__, dev_type);
+ goto func_end;
+ }
+ DBC_REQUIRE(pargs != NULL);
+ node_type = node_get_type(hnode);
+ node_msg_args = pargs->asa.node_msg_args;
+ max = disp_obj->ul_bufsize_rms; /*Max # of RMS words that can be sent */
+ DBC_ASSERT(max == RMS_COMMANDBUFSIZE);
+ chars_in_rms_word = sizeof(rms_word) / disp_obj->char_size;
+ /* Number of RMS words needed to hold arg data */
+ dw_length =
+ (node_msg_args.arg_length + chars_in_rms_word -
+ 1) / chars_in_rms_word;
+ /* Make sure msg args and command fit in buffer */
+ total = sizeof(struct rms_command) / sizeof(rms_word) +
+ sizeof(struct rms_msg_args)
+ / sizeof(rms_word) - 1 + dw_length;
+ if (total >= max) {
+ status = -EPERM;
+ dev_dbg(bridge, "%s: Message args too large for buffer! size "
+ "= %d, max = %d\n", __func__, total, max);
+ }
+ /*
+ * Fill in buffer to send to RMS.
+ * The buffer will have the following format:
+ *
+ * RMS command:
+ * Address of RMS_CreateNode()
+ * Address of node's create function
+ * dummy argument
+ * node type
+ *
+ * Message Args:
+ * max number of messages
+ * segid for message buffer allocation
+ * notification type to use when message is received
+ * length of message arg data
+ * message args data
+ *
+ * Task Args (if task or socket node):
+ * priority
+ * stack size
+ * system stack size
+ * stack segment
+ * misc
+ * number of input streams
+ * pSTRMInDef[] - offsets of STRM definitions for input streams
+ * number of output streams
+ * pSTRMOutDef[] - offsets of STRM definitions for output
+ * streams
+ * STRMInDef[] - array of STRM definitions for input streams
+ * STRMOutDef[] - array of STRM definitions for output streams
+ *
+ * Socket Args (if DAIS socket node):
+ *
+ */
+ if (!status) {
+ total = 0; /* Total number of words in buffer so far */
+ pdw_buf = (rms_word *) disp_obj->pbuf;
+ rms_cmd = (struct rms_command *)pdw_buf;
+ rms_cmd->fxn = (rms_word) (rms_fxn);
+ rms_cmd->arg1 = (rms_word) (ul_create_fxn);
+ if (node_get_load_type(hnode) == NLDR_DYNAMICLOAD) {
+ /* Flush ICACHE on Load */
+ rms_cmd->arg2 = 1; /* dummy argument */
+ } else {
+ /* Do not flush ICACHE */
+ rms_cmd->arg2 = 0; /* dummy argument */
+ }
+ rms_cmd->data = node_get_type(hnode);
+ /*
+ * args_offset is the offset of the data field in struct
+ * rms_command structure. We need this to calculate stream
+ * definition offsets.
+ */
+ args_offset = 3;
+ total += sizeof(struct rms_command) / sizeof(rms_word);
+ /* Message args */
+ pmsg_args = (struct rms_msg_args *)(pdw_buf + total);
+ pmsg_args->max_msgs = node_msg_args.max_msgs;
+ pmsg_args->segid = node_msg_args.seg_id;
+ pmsg_args->notify_type = node_msg_args.notify_type;
+ pmsg_args->arg_length = node_msg_args.arg_length;
+ total += sizeof(struct rms_msg_args) / sizeof(rms_word) - 1;
+ memcpy(pdw_buf + total, node_msg_args.pdata,
+ node_msg_args.arg_length);
+ total += dw_length;
+ }
+ if (status)
+ goto func_end;
+
+ /* If node is a task node, copy task create arguments into buffer */
+ if (node_type == NODE_TASK || node_type == NODE_DAISSOCKET) {
+ task_arg_obj = pargs->asa.task_arg_obj;
+ task_args_offset = total;
+ total += sizeof(struct rms_more_task_args) / sizeof(rms_word) +
+ 1 + task_arg_obj.num_inputs + task_arg_obj.num_outputs;
+ /* Copy task arguments */
+ if (total < max) {
+ total = task_args_offset;
+ more_task_args = (struct rms_more_task_args *)(pdw_buf +
+ total);
+ /*
+ * Get some important info about the node. Note that we
+ * don't just reach into the hnode struct because
+ * that would break the node object's abstraction.
+ */
+ get_node_info(hnode, &node_info);
+ more_task_args->priority = node_info.execution_priority;
+ more_task_args->stack_size = task_arg_obj.stack_size;
+ more_task_args->sysstack_size =
+ task_arg_obj.sys_stack_size;
+ more_task_args->stack_seg = task_arg_obj.stack_seg;
+ more_task_args->heap_addr = task_arg_obj.udsp_heap_addr;
+ more_task_args->heap_size = task_arg_obj.heap_size;
+ more_task_args->misc = task_arg_obj.ul_dais_arg;
+ more_task_args->num_input_streams =
+ task_arg_obj.num_inputs;
+ total +=
+ sizeof(struct rms_more_task_args) /
+ sizeof(rms_word);
+ dev_dbg(bridge, "%s: udsp_heap_addr %x, heap_size %x\n",
+ __func__, task_arg_obj.udsp_heap_addr,
+ task_arg_obj.heap_size);
+ /* Keep track of pSIOInDef[] and pSIOOutDef[]
+ * positions in the buffer, since this needs to be
+ * filled in later. */
+ sio_in_def_offset = total;
+ total += task_arg_obj.num_inputs;
+ pdw_buf[total++] = task_arg_obj.num_outputs;
+ sio_out_def_offset = total;
+ total += task_arg_obj.num_outputs;
+ sio_defs_offset = total;
+ /* Fill SIO defs and offsets */
+ offset = sio_defs_offset;
+ for (i = 0; i < task_arg_obj.num_inputs; i++) {
+ if (status)
+ break;
+
+ pdw_buf[sio_in_def_offset + i] =
+ (offset - args_offset)
+ * (sizeof(rms_word) / DSPWORDSIZE);
+ strm_def = task_arg_obj.strm_in_def[i];
+ status =
+ fill_stream_def(pdw_buf, &total, offset,
+ strm_def, max,
+ chars_in_rms_word);
+ offset = total;
+ }
+ for (i = 0; (i < task_arg_obj.num_outputs) &&
+ (!status); i++) {
+ pdw_buf[sio_out_def_offset + i] =
+ (offset - args_offset)
+ * (sizeof(rms_word) / DSPWORDSIZE);
+ strm_def = task_arg_obj.strm_out_def[i];
+ status =
+ fill_stream_def(pdw_buf, &total, offset,
+ strm_def, max,
+ chars_in_rms_word);
+ offset = total;
+ }
+ } else {
+ /* Args won't fit */
+ status = -EPERM;
+ }
+ }
+ if (!status) {
+ ul_bytes = total * sizeof(rms_word);
+ DBC_ASSERT(ul_bytes < (RMS_COMMANDBUFSIZE * sizeof(rms_word)));
+ status = send_message(disp_obj, node_get_timeout(hnode),
+ ul_bytes, node_env);
+ if (status >= 0) {
+ /*
+ * Message successfully received from RMS.
+ * Return the status of the Node's create function
+ * on the DSP-side
+ */
+ status = (((rms_word *) (disp_obj->pbuf))[0]);
+ if (status < 0)
+ dev_dbg(bridge, "%s: DSP-side failed: 0x%x\n",
+ __func__, status);
+ }
+ }
+func_end:
+ return status;
+}
+
+/*
+ * ======== disp_node_delete ========
+ * purpose:
+ * Delete a node on the DSP by remotely calling the node's delete function.
+ *
+ */
+int disp_node_delete(struct disp_object *disp_obj,
+ struct node_object *hnode, u32 rms_fxn,
+ u32 ul_delete_fxn, nodeenv node_env)
+{
+ u32 dw_arg;
+ struct rms_command *rms_cmd;
+ int status = 0;
+ u8 dev_type;
+
+ DBC_REQUIRE(refs > 0);
+ DBC_REQUIRE(disp_obj);
+ DBC_REQUIRE(hnode != NULL);
+
+ status = dev_get_dev_type(disp_obj->hdev_obj, &dev_type);
+
+ if (!status) {
+
+ if (dev_type == DSP_UNIT) {
+
+ /*
+ * Fill in buffer to send to RMS
+ */
+ rms_cmd = (struct rms_command *)disp_obj->pbuf;
+ rms_cmd->fxn = (rms_word) (rms_fxn);
+ rms_cmd->arg1 = (rms_word) node_env;
+ rms_cmd->arg2 = (rms_word) (ul_delete_fxn);
+ rms_cmd->data = node_get_type(hnode);
+
+ status = send_message(disp_obj, node_get_timeout(hnode),
+ sizeof(struct rms_command),
+ &dw_arg);
+ if (status >= 0) {
+ /*
+ * Message successfully received from RMS.
+ * Return the status of the Node's delete
+ * function on the DSP-side
+ */
+ status = (((rms_word *) (disp_obj->pbuf))[0]);
+ if (status < 0)
+ dev_dbg(bridge, "%s: DSP-side failed: "
+ "0x%x\n", __func__, status);
+ }
+
+ }
+ }
+ return status;
+}
+
+/*
+ * ======== disp_node_run ========
+ * purpose:
+ * Start execution of a node's execute phase, or resume execution of a node
+ * that has been suspended (via DISP_NodePause()) on the DSP.
+ */
+int disp_node_run(struct disp_object *disp_obj,
+ struct node_object *hnode, u32 rms_fxn,
+ u32 ul_execute_fxn, nodeenv node_env)
+{
+ u32 dw_arg;
+ struct rms_command *rms_cmd;
+ int status = 0;
+ u8 dev_type;
+ DBC_REQUIRE(refs > 0);
+ DBC_REQUIRE(disp_obj);
+ DBC_REQUIRE(hnode != NULL);
+
+ status = dev_get_dev_type(disp_obj->hdev_obj, &dev_type);
+
+ if (!status) {
+
+ if (dev_type == DSP_UNIT) {
+
+ /*
+ * Fill in buffer to send to RMS.
+ */
+ rms_cmd = (struct rms_command *)disp_obj->pbuf;
+ rms_cmd->fxn = (rms_word) (rms_fxn);
+ rms_cmd->arg1 = (rms_word) node_env;
+ rms_cmd->arg2 = (rms_word) (ul_execute_fxn);
+ rms_cmd->data = node_get_type(hnode);
+
+ status = send_message(disp_obj, node_get_timeout(hnode),
+ sizeof(struct rms_command),
+ &dw_arg);
+ if (status >= 0) {
+ /*
+ * Message successfully received from RMS.
+ * Return the status of the Node's execute
+ * function on the DSP-side
+ */
+ status = (((rms_word *) (disp_obj->pbuf))[0]);
+ if (status < 0)
+ dev_dbg(bridge, "%s: DSP-side failed: "
+ "0x%x\n", __func__, status);
+ }
+
+ }
+ }
+
+ return status;
+}
+
+/*
+ * ======== delete_disp ========
+ * purpose:
+ * Frees the resources allocated for the dispatcher.
+ */
+static void delete_disp(struct disp_object *disp_obj)
+{
+ int status = 0;
+ struct bridge_drv_interface *intf_fxns;
+
+ if (disp_obj) {
+ intf_fxns = disp_obj->intf_fxns;
+
+ /* Free Node Dispatcher resources */
+ if (disp_obj->chnl_from_dsp) {
+ /* Channel close can fail only if the channel handle
+ * is invalid. */
+ status = (*intf_fxns->pfn_chnl_close)
+ (disp_obj->chnl_from_dsp);
+ if (status) {
+ dev_dbg(bridge, "%s: Failed to close channel "
+ "from RMS: 0x%x\n", __func__, status);
+ }
+ }
+ if (disp_obj->chnl_to_dsp) {
+ status =
+ (*intf_fxns->pfn_chnl_close) (disp_obj->
+ chnl_to_dsp);
+ if (status) {
+ dev_dbg(bridge, "%s: Failed to close channel to"
+ " RMS: 0x%x\n", __func__, status);
+ }
+ }
+ kfree(disp_obj->pbuf);
+
+ kfree(disp_obj);
+ }
+}
+
+/*
+ * ======== fill_stream_def ========
+ * purpose:
+ * Fills stream definitions.
+ */
+static int fill_stream_def(rms_word *pdw_buf, u32 *ptotal, u32 offset,
+ struct node_strmdef strm_def, u32 max,
+ u32 chars_in_rms_word)
+{
+ struct rms_strm_def *strm_def_obj;
+ u32 total = *ptotal;
+ u32 name_len;
+ u32 dw_length;
+ int status = 0;
+
+ if (total + sizeof(struct rms_strm_def) / sizeof(rms_word) >= max) {
+ status = -EPERM;
+ } else {
+ strm_def_obj = (struct rms_strm_def *)(pdw_buf + total);
+ strm_def_obj->bufsize = strm_def.buf_size;
+ strm_def_obj->nbufs = strm_def.num_bufs;
+ strm_def_obj->segid = strm_def.seg_id;
+ strm_def_obj->align = strm_def.buf_alignment;
+ strm_def_obj->timeout = strm_def.utimeout;
+ }
+
+ if (!status) {
+ /*
+ * Since we haven't added the device name yet, subtract
+ * 1 from total.
+ */
+ total += sizeof(struct rms_strm_def) / sizeof(rms_word) - 1;
+ DBC_REQUIRE(strm_def.sz_device);
+ dw_length = strlen(strm_def.sz_device) + 1;
+
+ /* Number of RMS_WORDS needed to hold device name */
+ name_len =
+ (dw_length + chars_in_rms_word - 1) / chars_in_rms_word;
+
+ if (total + name_len >= max) {
+ status = -EPERM;
+ } else {
+ /*
+ * Zero out last word, since the device name may not
+ * extend to completely fill this word.
+ */
+ pdw_buf[total + name_len - 1] = 0;
+ /** TODO USE SERVICES * */
+ memcpy(pdw_buf + total, strm_def.sz_device, dw_length);
+ total += name_len;
+ *ptotal = total;
+ }
+ }
+
+ return status;
+}
+
+/*
+ * ======== send_message ======
+ * Send command message to RMS, get reply from RMS.
+ */
+static int send_message(struct disp_object *disp_obj, u32 timeout,
+ u32 ul_bytes, u32 *pdw_arg)
+{
+ struct bridge_drv_interface *intf_fxns;
+ struct chnl_object *chnl_obj;
+ u32 dw_arg = 0;
+ u8 *pbuf;
+ struct chnl_ioc chnl_ioc_obj;
+ int status = 0;
+
+ DBC_REQUIRE(pdw_arg != NULL);
+
+ *pdw_arg = (u32) NULL;
+ intf_fxns = disp_obj->intf_fxns;
+ chnl_obj = disp_obj->chnl_to_dsp;
+ pbuf = disp_obj->pbuf;
+
+ /* Send the command */
+ status = (*intf_fxns->pfn_chnl_add_io_req) (chnl_obj, pbuf, ul_bytes, 0,
+ 0L, dw_arg);
+ if (status)
+ goto func_end;
+
+ status =
+ (*intf_fxns->pfn_chnl_get_ioc) (chnl_obj, timeout, &chnl_ioc_obj);
+ if (!status) {
+ if (!CHNL_IS_IO_COMPLETE(chnl_ioc_obj)) {
+ if (CHNL_IS_TIMED_OUT(chnl_ioc_obj))
+ status = -ETIME;
+ else
+ status = -EPERM;
+ }
+ }
+ /* Get the reply */
+ if (status)
+ goto func_end;
+
+ chnl_obj = disp_obj->chnl_from_dsp;
+ ul_bytes = REPLYSIZE;
+ status = (*intf_fxns->pfn_chnl_add_io_req) (chnl_obj, pbuf, ul_bytes,
+ 0, 0L, dw_arg);
+ if (status)
+ goto func_end;
+
+ status =
+ (*intf_fxns->pfn_chnl_get_ioc) (chnl_obj, timeout, &chnl_ioc_obj);
+ if (!status) {
+ if (CHNL_IS_TIMED_OUT(chnl_ioc_obj)) {
+ status = -ETIME;
+ } else if (chnl_ioc_obj.byte_size < ul_bytes) {
+ /* Did not get all of the reply from the RMS */
+ status = -EPERM;
+ } else {
+ if (CHNL_IS_IO_COMPLETE(chnl_ioc_obj)) {
+ DBC_ASSERT(chnl_ioc_obj.pbuf == pbuf);
+ status = (*((rms_word *) chnl_ioc_obj.pbuf));
+ *pdw_arg =
+ (((rms_word *) (chnl_ioc_obj.pbuf))[1]);
+ } else {
+ status = -EPERM;
+ }
+ }
+ }
+func_end:
+ return status;
+}
diff --git a/drivers/staging/tidspbridge/rmgr/drv.c b/drivers/staging/tidspbridge/rmgr/drv.c
new file mode 100644
index 00000000000..8a8dea6efed
--- /dev/null
+++ b/drivers/staging/tidspbridge/rmgr/drv.c
@@ -0,0 +1,929 @@
+/*
+ * drv.c
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * DSP/BIOS Bridge resource allocation module.
+ *
+ * Copyright (C) 2005-2006 Texas Instruments, Inc.
+ *
+ * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+#include <linux/types.h>
+
+/* ----------------------------------- Host OS */
+#include <dspbridge/host_os.h>
+
+/* ----------------------------------- DSP/BIOS Bridge */
+#include <dspbridge/dbdefs.h>
+
+/* ----------------------------------- Trace & Debug */
+#include <dspbridge/dbc.h>
+
+/* ----------------------------------- OS Adaptation Layer */
+#include <dspbridge/cfg.h>
+#include <dspbridge/list.h>
+
+/* ----------------------------------- This */
+#include <dspbridge/drv.h>
+#include <dspbridge/dev.h>
+
+#include <dspbridge/node.h>
+#include <dspbridge/proc.h>
+#include <dspbridge/strm.h>
+#include <dspbridge/nodepriv.h>
+#include <dspbridge/dspchnl.h>
+#include <dspbridge/resourcecleanup.h>
+
+/* ----------------------------------- Defines, Data Structures, Typedefs */
+struct drv_object {
+ struct lst_list *dev_list;
+ struct lst_list *dev_node_string;
+};
+
+/*
+ * This is the Device Extension. Named with the Prefix
+ * DRV_ since it is living in this module
+ */
+struct drv_ext {
+ struct list_head link;
+ char sz_string[MAXREGPATHLENGTH];
+};
+
+/* ----------------------------------- Globals */
+static s32 refs;
+static bool ext_phys_mem_pool_enabled;
+struct ext_phys_mem_pool {
+ u32 phys_mem_base;
+ u32 phys_mem_size;
+ u32 virt_mem_base;
+ u32 next_phys_alloc_ptr;
+};
+static struct ext_phys_mem_pool ext_mem_pool;
+
+/* ----------------------------------- Function Prototypes */
+static int request_bridge_resources(struct cfg_hostres *res);
+
+
+/* GPP PROCESS CLEANUP CODE */
+
+static int drv_proc_free_node_res(int id, void *p, void *data);
+
+/* Allocate and add a node resource element
+* This function is called from .Node_Allocate. */
+int drv_insert_node_res_element(void *hnode, void *node_resource,
+ void *process_ctxt)
+{
+ struct node_res_object **node_res_obj =
+ (struct node_res_object **)node_resource;
+ struct process_context *ctxt = (struct process_context *)process_ctxt;
+ int status = 0;
+ int retval;
+
+ *node_res_obj = kzalloc(sizeof(struct node_res_object), GFP_KERNEL);
+ if (!*node_res_obj) {
+ status = -ENOMEM;
+ goto func_end;
+ }
+
+ (*node_res_obj)->hnode = hnode;
+ retval = idr_get_new(ctxt->node_id, *node_res_obj,
+ &(*node_res_obj)->id);
+ if (retval == -EAGAIN) {
+ if (!idr_pre_get(ctxt->node_id, GFP_KERNEL)) {
+ pr_err("%s: OUT OF MEMORY\n", __func__);
+ status = -ENOMEM;
+ goto func_end;
+ }
+
+ retval = idr_get_new(ctxt->node_id, *node_res_obj,
+ &(*node_res_obj)->id);
+ }
+ if (retval) {
+ pr_err("%s: FAILED, IDR is FULL\n", __func__);
+ status = -EFAULT;
+ }
+func_end:
+ if (status)
+ kfree(*node_res_obj);
+
+ return status;
+}
+
+/* Release all Node resources and its context
+ * Actual Node De-Allocation */
+static int drv_proc_free_node_res(int id, void *p, void *data)
+{
+ struct process_context *ctxt = data;
+ int status;
+ struct node_res_object *node_res_obj = p;
+ u32 node_state;
+
+ if (node_res_obj->node_allocated) {
+ node_state = node_get_state(node_res_obj->hnode);
+ if (node_state <= NODE_DELETING) {
+ if ((node_state == NODE_RUNNING) ||
+ (node_state == NODE_PAUSED) ||
+ (node_state == NODE_TERMINATING))
+ node_terminate
+ (node_res_obj->hnode, &status);
+
+ node_delete(node_res_obj, ctxt);
+ }
+ }
+
+ return 0;
+}
+
+/* Release all Mapped and Reserved DMM resources */
+int drv_remove_all_dmm_res_elements(void *process_ctxt)
+{
+ struct process_context *ctxt = (struct process_context *)process_ctxt;
+ int status = 0;
+ struct dmm_map_object *temp_map, *map_obj;
+ struct dmm_rsv_object *temp_rsv, *rsv_obj;
+
+ /* Free DMM mapped memory resources */
+ list_for_each_entry_safe(map_obj, temp_map, &ctxt->dmm_map_list, link) {
+ status = proc_un_map(ctxt->hprocessor,
+ (void *)map_obj->dsp_addr, ctxt);
+ if (status)
+ pr_err("%s: proc_un_map failed!"
+ " status = 0x%xn", __func__, status);
+ }
+
+ /* Free DMM reserved memory resources */
+ list_for_each_entry_safe(rsv_obj, temp_rsv, &ctxt->dmm_rsv_list, link) {
+ status = proc_un_reserve_memory(ctxt->hprocessor, (void *)
+ rsv_obj->dsp_reserved_addr,
+ ctxt);
+ if (status)
+ pr_err("%s: proc_un_reserve_memory failed!"
+ " status = 0x%xn", __func__, status);
+ }
+ return status;
+}
+
+/* Update Node allocation status */
+void drv_proc_node_update_status(void *node_resource, s32 status)
+{
+ struct node_res_object *node_res_obj =
+ (struct node_res_object *)node_resource;
+ DBC_ASSERT(node_resource != NULL);
+ node_res_obj->node_allocated = status;
+}
+
+/* Update Node Heap status */
+void drv_proc_node_update_heap_status(void *node_resource, s32 status)
+{
+ struct node_res_object *node_res_obj =
+ (struct node_res_object *)node_resource;
+ DBC_ASSERT(node_resource != NULL);
+ node_res_obj->heap_allocated = status;
+}
+
+/* Release all Node resources and its context
+* This is called from .bridge_release.
+ */
+int drv_remove_all_node_res_elements(void *process_ctxt)
+{
+ struct process_context *ctxt = process_ctxt;
+
+ idr_for_each(ctxt->node_id, drv_proc_free_node_res, ctxt);
+ idr_destroy(ctxt->node_id);
+
+ return 0;
+}
+
+/* Allocate the STRM resource element
+* This is called after the actual resource is allocated
+ */
+int drv_proc_insert_strm_res_element(void *stream_obj,
+ void *strm_res, void *process_ctxt)
+{
+ struct strm_res_object **pstrm_res =
+ (struct strm_res_object **)strm_res;
+ struct process_context *ctxt = (struct process_context *)process_ctxt;
+ int status = 0;
+ int retval;
+
+ *pstrm_res = kzalloc(sizeof(struct strm_res_object), GFP_KERNEL);
+ if (*pstrm_res == NULL) {
+ status = -EFAULT;
+ goto func_end;
+ }
+
+ (*pstrm_res)->hstream = stream_obj;
+ retval = idr_get_new(ctxt->stream_id, *pstrm_res,
+ &(*pstrm_res)->id);
+ if (retval == -EAGAIN) {
+ if (!idr_pre_get(ctxt->stream_id, GFP_KERNEL)) {
+ pr_err("%s: OUT OF MEMORY\n", __func__);
+ status = -ENOMEM;
+ goto func_end;
+ }
+
+ retval = idr_get_new(ctxt->stream_id, *pstrm_res,
+ &(*pstrm_res)->id);
+ }
+ if (retval) {
+ pr_err("%s: FAILED, IDR is FULL\n", __func__);
+ status = -EPERM;
+ }
+
+func_end:
+ return status;
+}
+
+static int drv_proc_free_strm_res(int id, void *p, void *process_ctxt)
+{
+ struct process_context *ctxt = process_ctxt;
+ struct strm_res_object *strm_res = p;
+ struct stream_info strm_info;
+ struct dsp_streaminfo user;
+ u8 **ap_buffer = NULL;
+ u8 *buf_ptr;
+ u32 ul_bytes;
+ u32 dw_arg;
+ s32 ul_buf_size;
+
+ if (strm_res->num_bufs) {
+ ap_buffer = kmalloc((strm_res->num_bufs *
+ sizeof(u8 *)), GFP_KERNEL);
+ if (ap_buffer) {
+ strm_free_buffer(strm_res,
+ ap_buffer,
+ strm_res->num_bufs,
+ ctxt);
+ kfree(ap_buffer);
+ }
+ }
+ strm_info.user_strm = &user;
+ user.number_bufs_in_stream = 0;
+ strm_get_info(strm_res->hstream, &strm_info, sizeof(strm_info));
+ while (user.number_bufs_in_stream--)
+ strm_reclaim(strm_res->hstream, &buf_ptr, &ul_bytes,
+ (u32 *) &ul_buf_size, &dw_arg);
+ strm_close(strm_res, ctxt);
+ return 0;
+}
+
+/* Release all Stream resources and its context
+* This is called from .bridge_release.
+ */
+int drv_remove_all_strm_res_elements(void *process_ctxt)
+{
+ struct process_context *ctxt = process_ctxt;
+
+ idr_for_each(ctxt->stream_id, drv_proc_free_strm_res, ctxt);
+ idr_destroy(ctxt->stream_id);
+
+ return 0;
+}
+
+/* Updating the stream resource element */
+int drv_proc_update_strm_res(u32 num_bufs, void *strm_resources)
+{
+ int status = 0;
+ struct strm_res_object **strm_res =
+ (struct strm_res_object **)strm_resources;
+
+ (*strm_res)->num_bufs = num_bufs;
+ return status;
+}
+
+/* GPP PROCESS CLEANUP CODE END */
+
+/*
+ * ======== = drv_create ======== =
+ * Purpose:
+ * DRV Object gets created only once during Driver Loading.
+ */
+int drv_create(struct drv_object **drv_obj)
+{
+ int status = 0;
+ struct drv_object *pdrv_object = NULL;
+
+ DBC_REQUIRE(drv_obj != NULL);
+ DBC_REQUIRE(refs > 0);
+
+ pdrv_object = kzalloc(sizeof(struct drv_object), GFP_KERNEL);
+ if (pdrv_object) {
+ /* Create and Initialize List of device objects */
+ pdrv_object->dev_list = kzalloc(sizeof(struct lst_list),
+ GFP_KERNEL);
+ if (pdrv_object->dev_list) {
+ /* Create and Initialize List of device Extension */
+ pdrv_object->dev_node_string =
+ kzalloc(sizeof(struct lst_list), GFP_KERNEL);
+ if (!(pdrv_object->dev_node_string)) {
+ status = -EPERM;
+ } else {
+ INIT_LIST_HEAD(&pdrv_object->
+ dev_node_string->head);
+ INIT_LIST_HEAD(&pdrv_object->dev_list->head);
+ }
+ } else {
+ status = -ENOMEM;
+ }
+ } else {
+ status = -ENOMEM;
+ }
+ /* Store the DRV Object in the Registry */
+ if (!status)
+ status = cfg_set_object((u32) pdrv_object, REG_DRV_OBJECT);
+ if (!status) {
+ *drv_obj = pdrv_object;
+ } else {
+ kfree(pdrv_object->dev_list);
+ kfree(pdrv_object->dev_node_string);
+ /* Free the DRV Object */
+ kfree(pdrv_object);
+ }
+
+ DBC_ENSURE(status || pdrv_object);
+ return status;
+}
+
+/*
+ * ======== drv_exit ========
+ * Purpose:
+ * Discontinue usage of the DRV module.
+ */
+void drv_exit(void)
+{
+ DBC_REQUIRE(refs > 0);
+
+ refs--;
+
+ DBC_ENSURE(refs >= 0);
+}
+
+/*
+ * ======== = drv_destroy ======== =
+ * purpose:
+ * Invoked during bridge de-initialization
+ */
+int drv_destroy(struct drv_object *driver_obj)
+{
+ int status = 0;
+ struct drv_object *pdrv_object = (struct drv_object *)driver_obj;
+
+ DBC_REQUIRE(refs > 0);
+ DBC_REQUIRE(pdrv_object);
+
+ /*
+ * Delete the List if it exists.Should not come here
+ * as the drv_remove_dev_object and the Last drv_request_resources
+ * removes the list if the lists are empty.
+ */
+ kfree(pdrv_object->dev_list);
+ kfree(pdrv_object->dev_node_string);
+ kfree(pdrv_object);
+ /* Update the DRV Object in Registry to be 0 */
+ (void)cfg_set_object(0, REG_DRV_OBJECT);
+
+ return status;
+}
+
+/*
+ * ======== drv_get_dev_object ========
+ * Purpose:
+ * Given a index, returns a handle to DevObject from the list.
+ */
+int drv_get_dev_object(u32 index, struct drv_object *hdrv_obj,
+ struct dev_object **device_obj)
+{
+ int status = 0;
+#ifdef CONFIG_TIDSPBRIDGE_DEBUG
+ /* used only for Assertions and debug messages */
+ struct drv_object *pdrv_obj = (struct drv_object *)hdrv_obj;
+#endif
+ struct dev_object *dev_obj;
+ u32 i;
+ DBC_REQUIRE(pdrv_obj);
+ DBC_REQUIRE(device_obj != NULL);
+ DBC_REQUIRE(index >= 0);
+ DBC_REQUIRE(refs > 0);
+ DBC_ASSERT(!(LST_IS_EMPTY(pdrv_obj->dev_list)));
+
+ dev_obj = (struct dev_object *)drv_get_first_dev_object();
+ for (i = 0; i < index; i++) {
+ dev_obj =
+ (struct dev_object *)drv_get_next_dev_object((u32) dev_obj);
+ }
+ if (dev_obj) {
+ *device_obj = (struct dev_object *)dev_obj;
+ } else {
+ *device_obj = NULL;
+ status = -EPERM;
+ }
+
+ return status;
+}
+
+/*
+ * ======== drv_get_first_dev_object ========
+ * Purpose:
+ * Retrieve the first Device Object handle from an internal linked list of
+ * of DEV_OBJECTs maintained by DRV.
+ */
+u32 drv_get_first_dev_object(void)
+{
+ u32 dw_dev_object = 0;
+ struct drv_object *pdrv_obj;
+
+ if (!cfg_get_object((u32 *) &pdrv_obj, REG_DRV_OBJECT)) {
+ if ((pdrv_obj->dev_list != NULL) &&
+ !LST_IS_EMPTY(pdrv_obj->dev_list))
+ dw_dev_object = (u32) lst_first(pdrv_obj->dev_list);
+ }
+
+ return dw_dev_object;
+}
+
+/*
+ * ======== DRV_GetFirstDevNodeString ========
+ * Purpose:
+ * Retrieve the first Device Extension from an internal linked list of
+ * of Pointer to dev_node Strings maintained by DRV.
+ */
+u32 drv_get_first_dev_extension(void)
+{
+ u32 dw_dev_extension = 0;
+ struct drv_object *pdrv_obj;
+
+ if (!cfg_get_object((u32 *) &pdrv_obj, REG_DRV_OBJECT)) {
+
+ if ((pdrv_obj->dev_node_string != NULL) &&
+ !LST_IS_EMPTY(pdrv_obj->dev_node_string)) {
+ dw_dev_extension =
+ (u32) lst_first(pdrv_obj->dev_node_string);
+ }
+ }
+
+ return dw_dev_extension;
+}
+
+/*
+ * ======== drv_get_next_dev_object ========
+ * Purpose:
+ * Retrieve the next Device Object handle from an internal linked list of
+ * of DEV_OBJECTs maintained by DRV, after having previously called
+ * drv_get_first_dev_object() and zero or more DRV_GetNext.
+ */
+u32 drv_get_next_dev_object(u32 hdev_obj)
+{
+ u32 dw_next_dev_object = 0;
+ struct drv_object *pdrv_obj;
+
+ DBC_REQUIRE(hdev_obj != 0);
+
+ if (!cfg_get_object((u32 *) &pdrv_obj, REG_DRV_OBJECT)) {
+
+ if ((pdrv_obj->dev_list != NULL) &&
+ !LST_IS_EMPTY(pdrv_obj->dev_list)) {
+ dw_next_dev_object = (u32) lst_next(pdrv_obj->dev_list,
+ (struct list_head *)
+ hdev_obj);
+ }
+ }
+ return dw_next_dev_object;
+}
+
+/*
+ * ======== drv_get_next_dev_extension ========
+ * Purpose:
+ * Retrieve the next Device Extension from an internal linked list of
+ * of pointer to DevNodeString maintained by DRV, after having previously
+ * called drv_get_first_dev_extension() and zero or more
+ * drv_get_next_dev_extension().
+ */
+u32 drv_get_next_dev_extension(u32 dev_extension)
+{
+ u32 dw_dev_extension = 0;
+ struct drv_object *pdrv_obj;
+
+ DBC_REQUIRE(dev_extension != 0);
+
+ if (!cfg_get_object((u32 *) &pdrv_obj, REG_DRV_OBJECT)) {
+ if ((pdrv_obj->dev_node_string != NULL) &&
+ !LST_IS_EMPTY(pdrv_obj->dev_node_string)) {
+ dw_dev_extension =
+ (u32) lst_next(pdrv_obj->dev_node_string,
+ (struct list_head *)dev_extension);
+ }
+ }
+
+ return dw_dev_extension;
+}
+
+/*
+ * ======== drv_init ========
+ * Purpose:
+ * Initialize DRV module private state.
+ */
+int drv_init(void)
+{
+ s32 ret = 1; /* function return value */
+
+ DBC_REQUIRE(refs >= 0);
+
+ if (ret)
+ refs++;
+
+ DBC_ENSURE((ret && (refs > 0)) || (!ret && (refs >= 0)));
+
+ return ret;
+}
+
+/*
+ * ======== drv_insert_dev_object ========
+ * Purpose:
+ * Insert a DevObject into the list of Manager object.
+ */
+int drv_insert_dev_object(struct drv_object *driver_obj,
+ struct dev_object *hdev_obj)
+{
+ struct drv_object *pdrv_object = (struct drv_object *)driver_obj;
+
+ DBC_REQUIRE(refs > 0);
+ DBC_REQUIRE(hdev_obj != NULL);
+ DBC_REQUIRE(pdrv_object);
+ DBC_ASSERT(pdrv_object->dev_list);
+
+ lst_put_tail(pdrv_object->dev_list, (struct list_head *)hdev_obj);
+
+ DBC_ENSURE(!LST_IS_EMPTY(pdrv_object->dev_list));
+
+ return 0;
+}
+
+/*
+ * ======== drv_remove_dev_object ========
+ * Purpose:
+ * Search for and remove a DeviceObject from the given list of DRV
+ * objects.
+ */
+int drv_remove_dev_object(struct drv_object *driver_obj,
+ struct dev_object *hdev_obj)
+{
+ int status = -EPERM;
+ struct drv_object *pdrv_object = (struct drv_object *)driver_obj;
+ struct list_head *cur_elem;
+
+ DBC_REQUIRE(refs > 0);
+ DBC_REQUIRE(pdrv_object);
+ DBC_REQUIRE(hdev_obj != NULL);
+
+ DBC_REQUIRE(pdrv_object->dev_list != NULL);
+ DBC_REQUIRE(!LST_IS_EMPTY(pdrv_object->dev_list));
+
+ /* Search list for p_proc_object: */
+ for (cur_elem = lst_first(pdrv_object->dev_list); cur_elem != NULL;
+ cur_elem = lst_next(pdrv_object->dev_list, cur_elem)) {
+ /* If found, remove it. */
+ if ((struct dev_object *)cur_elem == hdev_obj) {
+ lst_remove_elem(pdrv_object->dev_list, cur_elem);
+ status = 0;
+ break;
+ }
+ }
+ /* Remove list if empty. */
+ if (LST_IS_EMPTY(pdrv_object->dev_list)) {
+ kfree(pdrv_object->dev_list);
+ pdrv_object->dev_list = NULL;
+ }
+ DBC_ENSURE((pdrv_object->dev_list == NULL) ||
+ !LST_IS_EMPTY(pdrv_object->dev_list));
+
+ return status;
+}
+
+/*
+ * ======== drv_request_resources ========
+ * Purpose:
+ * Requests resources from the OS.
+ */
+int drv_request_resources(u32 dw_context, u32 *dev_node_strg)
+{
+ int status = 0;
+ struct drv_object *pdrv_object;
+ struct drv_ext *pszdev_node;
+
+ DBC_REQUIRE(dw_context != 0);
+ DBC_REQUIRE(dev_node_strg != NULL);
+
+ /*
+ * Allocate memory to hold the string. This will live untill
+ * it is freed in the Release resources. Update the driver object
+ * list.
+ */
+
+ status = cfg_get_object((u32 *) &pdrv_object, REG_DRV_OBJECT);
+ if (!status) {
+ pszdev_node = kzalloc(sizeof(struct drv_ext), GFP_KERNEL);
+ if (pszdev_node) {
+ lst_init_elem(&pszdev_node->link);
+ strncpy(pszdev_node->sz_string,
+ (char *)dw_context, MAXREGPATHLENGTH - 1);
+ pszdev_node->sz_string[MAXREGPATHLENGTH - 1] = '\0';
+ /* Update the Driver Object List */
+ *dev_node_strg = (u32) pszdev_node->sz_string;
+ lst_put_tail(pdrv_object->dev_node_string,
+ (struct list_head *)pszdev_node);
+ } else {
+ status = -ENOMEM;
+ *dev_node_strg = 0;
+ }
+ } else {
+ dev_dbg(bridge, "%s: Failed to get Driver Object from Registry",
+ __func__);
+ *dev_node_strg = 0;
+ }
+
+ DBC_ENSURE((!status && dev_node_strg != NULL &&
+ !LST_IS_EMPTY(pdrv_object->dev_node_string)) ||
+ (status && *dev_node_strg == 0));
+
+ return status;
+}
+
+/*
+ * ======== drv_release_resources ========
+ * Purpose:
+ * Releases resources from the OS.
+ */
+int drv_release_resources(u32 dw_context, struct drv_object *hdrv_obj)
+{
+ int status = 0;
+ struct drv_object *pdrv_object = (struct drv_object *)hdrv_obj;
+ struct drv_ext *pszdev_node;
+
+ /*
+ * Irrespective of the status go ahead and clean it
+ * The following will over write the status.
+ */
+ for (pszdev_node = (struct drv_ext *)drv_get_first_dev_extension();
+ pszdev_node != NULL; pszdev_node = (struct drv_ext *)
+ drv_get_next_dev_extension((u32) pszdev_node)) {
+ if (!pdrv_object->dev_node_string) {
+ /* When this could happen? */
+ continue;
+ }
+ if ((u32) pszdev_node == dw_context) {
+ /* Found it */
+ /* Delete from the Driver object list */
+ lst_remove_elem(pdrv_object->dev_node_string,
+ (struct list_head *)pszdev_node);
+ kfree((void *)pszdev_node);
+ break;
+ }
+ /* Delete the List if it is empty */
+ if (LST_IS_EMPTY(pdrv_object->dev_node_string)) {
+ kfree(pdrv_object->dev_node_string);
+ pdrv_object->dev_node_string = NULL;
+ }
+ }
+ return status;
+}
+
+/*
+ * ======== request_bridge_resources ========
+ * Purpose:
+ * Reserves shared memory for bridge.
+ */
+static int request_bridge_resources(struct cfg_hostres *res)
+{
+ struct cfg_hostres *host_res = res;
+
+ /* num_mem_windows must not be more than CFG_MAXMEMREGISTERS */
+ host_res->num_mem_windows = 2;
+
+ /* First window is for DSP internal memory */
+ host_res->dw_sys_ctrl_base = ioremap(OMAP_SYSC_BASE, OMAP_SYSC_SIZE);
+ dev_dbg(bridge, "dw_mem_base[0] 0x%x\n", host_res->dw_mem_base[0]);
+ dev_dbg(bridge, "dw_mem_base[3] 0x%x\n", host_res->dw_mem_base[3]);
+ dev_dbg(bridge, "dw_dmmu_base %p\n", host_res->dw_dmmu_base);
+
+ /* for 24xx base port is not mapping the mamory for DSP
+ * internal memory TODO Do a ioremap here */
+ /* Second window is for DSP external memory shared with MPU */
+
+ /* These are hard-coded values */
+ host_res->birq_registers = 0;
+ host_res->birq_attrib = 0;
+ host_res->dw_offset_for_monitor = 0;
+ host_res->dw_chnl_offset = 0;
+ /* CHNL_MAXCHANNELS */
+ host_res->dw_num_chnls = CHNL_MAXCHANNELS;
+ host_res->dw_chnl_buf_size = 0x400;
+
+ return 0;
+}
+
+/*
+ * ======== drv_request_bridge_res_dsp ========
+ * Purpose:
+ * Reserves shared memory for bridge.
+ */
+int drv_request_bridge_res_dsp(void **phost_resources)
+{
+ int status = 0;
+ struct cfg_hostres *host_res;
+ u32 dw_buff_size;
+ u32 dma_addr;
+ u32 shm_size;
+ struct drv_data *drv_datap = dev_get_drvdata(bridge);
+
+ dw_buff_size = sizeof(struct cfg_hostres);
+
+ host_res = kzalloc(dw_buff_size, GFP_KERNEL);
+
+ if (host_res != NULL) {
+ request_bridge_resources(host_res);
+ /* num_mem_windows must not be more than CFG_MAXMEMREGISTERS */
+ host_res->num_mem_windows = 4;
+
+ host_res->dw_mem_base[0] = 0;
+ host_res->dw_mem_base[2] = (u32) ioremap(OMAP_DSP_MEM1_BASE,
+ OMAP_DSP_MEM1_SIZE);
+ host_res->dw_mem_base[3] = (u32) ioremap(OMAP_DSP_MEM2_BASE,
+ OMAP_DSP_MEM2_SIZE);
+ host_res->dw_mem_base[4] = (u32) ioremap(OMAP_DSP_MEM3_BASE,
+ OMAP_DSP_MEM3_SIZE);
+ host_res->dw_per_base = ioremap(OMAP_PER_CM_BASE,
+ OMAP_PER_CM_SIZE);
+ host_res->dw_per_pm_base = (u32) ioremap(OMAP_PER_PRM_BASE,
+ OMAP_PER_PRM_SIZE);
+ host_res->dw_core_pm_base = (u32) ioremap(OMAP_CORE_PRM_BASE,
+ OMAP_CORE_PRM_SIZE);
+ host_res->dw_dmmu_base = ioremap(OMAP_DMMU_BASE,
+ OMAP_DMMU_SIZE);
+
+ dev_dbg(bridge, "dw_mem_base[0] 0x%x\n",
+ host_res->dw_mem_base[0]);
+ dev_dbg(bridge, "dw_mem_base[1] 0x%x\n",
+ host_res->dw_mem_base[1]);
+ dev_dbg(bridge, "dw_mem_base[2] 0x%x\n",
+ host_res->dw_mem_base[2]);
+ dev_dbg(bridge, "dw_mem_base[3] 0x%x\n",
+ host_res->dw_mem_base[3]);
+ dev_dbg(bridge, "dw_mem_base[4] 0x%x\n",
+ host_res->dw_mem_base[4]);
+ dev_dbg(bridge, "dw_dmmu_base %p\n", host_res->dw_dmmu_base);
+
+ shm_size = drv_datap->shm_size;
+ if (shm_size >= 0x10000) {
+ /* Allocate Physically contiguous,
+ * non-cacheable memory */
+ host_res->dw_mem_base[1] =
+ (u32) mem_alloc_phys_mem(shm_size, 0x100000,
+ &dma_addr);
+ if (host_res->dw_mem_base[1] == 0) {
+ status = -ENOMEM;
+ pr_err("shm reservation Failed\n");
+ } else {
+ host_res->dw_mem_length[1] = shm_size;
+ host_res->dw_mem_phys[1] = dma_addr;
+
+ dev_dbg(bridge, "%s: Bridge shm address 0x%x "
+ "dma_addr %x size %x\n", __func__,
+ host_res->dw_mem_base[1],
+ dma_addr, shm_size);
+ }
+ }
+ if (!status) {
+ /* These are hard-coded values */
+ host_res->birq_registers = 0;
+ host_res->birq_attrib = 0;
+ host_res->dw_offset_for_monitor = 0;
+ host_res->dw_chnl_offset = 0;
+ /* CHNL_MAXCHANNELS */
+ host_res->dw_num_chnls = CHNL_MAXCHANNELS;
+ host_res->dw_chnl_buf_size = 0x400;
+ dw_buff_size = sizeof(struct cfg_hostres);
+ }
+ *phost_resources = host_res;
+ }
+ /* End Mem alloc */
+ return status;
+}
+
+void mem_ext_phys_pool_init(u32 pool_phys_base, u32 pool_size)
+{
+ u32 pool_virt_base;
+
+ /* get the virtual address for the physical memory pool passed */
+ pool_virt_base = (u32) ioremap(pool_phys_base, pool_size);
+
+ if ((void **)pool_virt_base == NULL) {
+ pr_err("%s: external physical memory map failed\n", __func__);
+ ext_phys_mem_pool_enabled = false;
+ } else {
+ ext_mem_pool.phys_mem_base = pool_phys_base;
+ ext_mem_pool.phys_mem_size = pool_size;
+ ext_mem_pool.virt_mem_base = pool_virt_base;
+ ext_mem_pool.next_phys_alloc_ptr = pool_phys_base;
+ ext_phys_mem_pool_enabled = true;
+ }
+}
+
+void mem_ext_phys_pool_release(void)
+{
+ if (ext_phys_mem_pool_enabled) {
+ iounmap((void *)(ext_mem_pool.virt_mem_base));
+ ext_phys_mem_pool_enabled = false;
+ }
+}
+
+/*
+ * ======== mem_ext_phys_mem_alloc ========
+ * Purpose:
+ * Allocate physically contiguous, uncached memory from external memory pool
+ */
+
+static void *mem_ext_phys_mem_alloc(u32 bytes, u32 align, u32 * phys_addr)
+{
+ u32 new_alloc_ptr;
+ u32 offset;
+ u32 virt_addr;
+
+ if (align == 0)
+ align = 1;
+
+ if (bytes > ((ext_mem_pool.phys_mem_base + ext_mem_pool.phys_mem_size)
+ - ext_mem_pool.next_phys_alloc_ptr)) {
+ phys_addr = NULL;
+ return NULL;
+ } else {
+ offset = (ext_mem_pool.next_phys_alloc_ptr & (align - 1));
+ if (offset == 0)
+ new_alloc_ptr = ext_mem_pool.next_phys_alloc_ptr;
+ else
+ new_alloc_ptr = (ext_mem_pool.next_phys_alloc_ptr) +
+ (align - offset);
+ if ((new_alloc_ptr + bytes) <=
+ (ext_mem_pool.phys_mem_base + ext_mem_pool.phys_mem_size)) {
+ /* we can allocate */
+ *phys_addr = new_alloc_ptr;
+ ext_mem_pool.next_phys_alloc_ptr =
+ new_alloc_ptr + bytes;
+ virt_addr =
+ ext_mem_pool.virt_mem_base + (new_alloc_ptr -
+ ext_mem_pool.
+ phys_mem_base);
+ return (void *)virt_addr;
+ } else {
+ *phys_addr = 0;
+ return NULL;
+ }
+ }
+}
+
+/*
+ * ======== mem_alloc_phys_mem ========
+ * Purpose:
+ * Allocate physically contiguous, uncached memory
+ */
+void *mem_alloc_phys_mem(u32 byte_size, u32 align_mask,
+ u32 *physical_address)
+{
+ void *va_mem = NULL;
+ dma_addr_t pa_mem;
+
+ if (byte_size > 0) {
+ if (ext_phys_mem_pool_enabled) {
+ va_mem = mem_ext_phys_mem_alloc(byte_size, align_mask,
+ (u32 *) &pa_mem);
+ } else
+ va_mem = dma_alloc_coherent(NULL, byte_size, &pa_mem,
+ GFP_KERNEL);
+ if (va_mem == NULL)
+ *physical_address = 0;
+ else
+ *physical_address = pa_mem;
+ }
+ return va_mem;
+}
+
+/*
+ * ======== mem_free_phys_mem ========
+ * Purpose:
+ * Free the given block of physically contiguous memory.
+ */
+void mem_free_phys_mem(void *virtual_address, u32 physical_address,
+ u32 byte_size)
+{
+ DBC_REQUIRE(virtual_address != NULL);
+
+ if (!ext_phys_mem_pool_enabled)
+ dma_free_coherent(NULL, byte_size, virtual_address,
+ physical_address);
+}
diff --git a/drivers/staging/tidspbridge/rmgr/drv_interface.c b/drivers/staging/tidspbridge/rmgr/drv_interface.c
new file mode 100644
index 00000000000..7ee89492a75
--- /dev/null
+++ b/drivers/staging/tidspbridge/rmgr/drv_interface.c
@@ -0,0 +1,656 @@
+/*
+ * drv_interface.c
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * DSP/BIOS Bridge driver interface.
+ *
+ * Copyright (C) 2005-2006 Texas Instruments, Inc.
+ *
+ * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+/* ----------------------------------- Host OS */
+
+#include <dspbridge/host_os.h>
+#include <linux/types.h>
+#include <linux/platform_device.h>
+#include <linux/pm.h>
+
+#ifdef MODULE
+#include <linux/module.h>
+#endif
+
+#include <linux/device.h>
+#include <linux/init.h>
+#include <linux/moduleparam.h>
+#include <linux/cdev.h>
+
+/* ----------------------------------- DSP/BIOS Bridge */
+#include <dspbridge/dbdefs.h>
+
+/* ----------------------------------- Trace & Debug */
+#include <dspbridge/dbc.h>
+
+/* ----------------------------------- OS Adaptation Layer */
+#include <dspbridge/services.h>
+#include <dspbridge/clk.h>
+#include <dspbridge/sync.h>
+
+/* ----------------------------------- Platform Manager */
+#include <dspbridge/dspapi-ioctl.h>
+#include <dspbridge/dspapi.h>
+#include <dspbridge/dspdrv.h>
+
+/* ----------------------------------- Resource Manager */
+#include <dspbridge/pwr.h>
+
+/* ----------------------------------- This */
+#include <drv_interface.h>
+
+#include <dspbridge/cfg.h>
+#include <dspbridge/resourcecleanup.h>
+#include <dspbridge/chnl.h>
+#include <dspbridge/proc.h>
+#include <dspbridge/dev.h>
+#include <dspbridge/drvdefs.h>
+#include <dspbridge/drv.h>
+
+#ifdef CONFIG_TIDSPBRIDGE_DVFS
+#include <mach-omap2/omap3-opp.h>
+#endif
+
+#define BRIDGE_NAME "C6410"
+/* ----------------------------------- Globals */
+#define DRIVER_NAME "DspBridge"
+#define DSPBRIDGE_VERSION "0.3"
+s32 dsp_debug;
+
+struct platform_device *omap_dspbridge_dev;
+struct device *bridge;
+
+/* This is a test variable used by Bridge to test different sleep states */
+s32 dsp_test_sleepstate;
+
+static struct cdev bridge_cdev;
+
+static struct class *bridge_class;
+
+static u32 driver_context;
+static s32 driver_major;
+static char *base_img;
+char *iva_img;
+static s32 shm_size = 0x500000; /* 5 MB */
+static int tc_wordswapon; /* Default value is always false */
+#ifdef CONFIG_TIDSPBRIDGE_RECOVERY
+#define REC_TIMEOUT 5000 /*recovery timeout in msecs */
+static atomic_t bridge_cref; /* number of bridge open handles */
+static struct workqueue_struct *bridge_rec_queue;
+static struct work_struct bridge_recovery_work;
+static DECLARE_COMPLETION(bridge_comp);
+static DECLARE_COMPLETION(bridge_open_comp);
+static bool recover;
+#endif
+
+#ifdef CONFIG_PM
+struct omap34_xx_bridge_suspend_data {
+ int suspended;
+ wait_queue_head_t suspend_wq;
+};
+
+static struct omap34_xx_bridge_suspend_data bridge_suspend_data;
+
+static int omap34_xxbridge_suspend_lockout(struct omap34_xx_bridge_suspend_data
+ *s, struct file *f)
+{
+ if ((s)->suspended) {
+ if ((f)->f_flags & O_NONBLOCK)
+ return -EPERM;
+ wait_event_interruptible((s)->suspend_wq, (s)->suspended == 0);
+ }
+ return 0;
+}
+#endif
+
+module_param(dsp_debug, int, 0);
+MODULE_PARM_DESC(dsp_debug, "Wait after loading DSP image. default = false");
+
+module_param(dsp_test_sleepstate, int, 0);
+MODULE_PARM_DESC(dsp_test_sleepstate, "DSP Sleep state = 0");
+
+module_param(base_img, charp, 0);
+MODULE_PARM_DESC(base_img, "DSP base image, default = NULL");
+
+module_param(shm_size, int, 0);
+MODULE_PARM_DESC(shm_size, "shm size, default = 4 MB, minimum = 64 KB");
+
+module_param(tc_wordswapon, int, 0);
+MODULE_PARM_DESC(tc_wordswapon, "TC Word Swap Option. default = 0");
+
+MODULE_AUTHOR("Texas Instruments");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DSPBRIDGE_VERSION);
+
+static char *driver_name = DRIVER_NAME;
+
+static const struct file_operations bridge_fops = {
+ .open = bridge_open,
+ .release = bridge_release,
+ .unlocked_ioctl = bridge_ioctl,
+ .mmap = bridge_mmap,
+};
+
+#ifdef CONFIG_PM
+static u32 time_out = 1000;
+#ifdef CONFIG_TIDSPBRIDGE_DVFS
+s32 dsp_max_opps = VDD1_OPP5;
+#endif
+
+/* Maximum Opps that can be requested by IVA */
+/*vdd1 rate table */
+#ifdef CONFIG_TIDSPBRIDGE_DVFS
+const struct omap_opp vdd1_rate_table_bridge[] = {
+ {0, 0, 0},
+ /*OPP1 */
+ {S125M, VDD1_OPP1, 0},
+ /*OPP2 */
+ {S250M, VDD1_OPP2, 0},
+ /*OPP3 */
+ {S500M, VDD1_OPP3, 0},
+ /*OPP4 */
+ {S550M, VDD1_OPP4, 0},
+ /*OPP5 */
+ {S600M, VDD1_OPP5, 0},
+};
+#endif
+#endif
+
+struct dspbridge_platform_data *omap_dspbridge_pdata;
+
+u32 vdd1_dsp_freq[6][4] = {
+ {0, 0, 0, 0},
+ /*OPP1 */
+ {0, 90000, 0, 86000},
+ /*OPP2 */
+ {0, 180000, 80000, 170000},
+ /*OPP3 */
+ {0, 360000, 160000, 340000},
+ /*OPP4 */
+ {0, 396000, 325000, 376000},
+ /*OPP5 */
+ {0, 430000, 355000, 430000},
+};
+
+#ifdef CONFIG_TIDSPBRIDGE_RECOVERY
+static void bridge_recover(struct work_struct *work)
+{
+ struct dev_object *dev;
+ struct cfg_devnode *dev_node;
+ if (atomic_read(&bridge_cref)) {
+ INIT_COMPLETION(bridge_comp);
+ while (!wait_for_completion_timeout(&bridge_comp,
+ msecs_to_jiffies(REC_TIMEOUT)))
+ pr_info("%s:%d handle(s) still opened\n",
+ __func__, atomic_read(&bridge_cref));
+ }
+ dev = dev_get_first();
+ dev_get_dev_node(dev, &dev_node);
+ if (!dev_node || proc_auto_start(dev_node, dev))
+ pr_err("DSP could not be restarted\n");
+ recover = false;
+ complete_all(&bridge_open_comp);
+}
+
+void bridge_recover_schedule(void)
+{
+ INIT_COMPLETION(bridge_open_comp);
+ recover = true;
+ queue_work(bridge_rec_queue, &bridge_recovery_work);
+}
+#endif
+#ifdef CONFIG_TIDSPBRIDGE_DVFS
+static int dspbridge_scale_notification(struct notifier_block *op,
+ unsigned long val, void *ptr)
+{
+ struct dspbridge_platform_data *pdata =
+ omap_dspbridge_dev->dev.platform_data;
+
+ if (CPUFREQ_POSTCHANGE == val && pdata->dsp_get_opp)
+ pwr_pm_post_scale(PRCM_VDD1, pdata->dsp_get_opp());
+
+ return 0;
+}
+
+static struct notifier_block iva_clk_notifier = {
+ .notifier_call = dspbridge_scale_notification,
+ NULL,
+};
+#endif
+
+/**
+ * omap3_bridge_startup() - perform low lever initializations
+ * @pdev: pointer to platform device
+ *
+ * Initializes recovery, PM and DVFS required data, before calling
+ * clk and memory init routines.
+ */
+static int omap3_bridge_startup(struct platform_device *pdev)
+{
+ struct dspbridge_platform_data *pdata = pdev->dev.platform_data;
+ struct drv_data *drv_datap = NULL;
+ u32 phys_membase, phys_memsize;
+ int err;
+
+#ifdef CONFIG_TIDSPBRIDGE_RECOVERY
+ bridge_rec_queue = create_workqueue("bridge_rec_queue");
+ INIT_WORK(&bridge_recovery_work, bridge_recover);
+ INIT_COMPLETION(bridge_comp);
+#endif
+
+#ifdef CONFIG_PM
+ /* Initialize the wait queue */
+ bridge_suspend_data.suspended = 0;
+ init_waitqueue_head(&bridge_suspend_data.suspend_wq);
+
+#ifdef CONFIG_TIDSPBRIDGE_DVFS
+ for (i = 0; i < 6; i++)
+ pdata->mpu_speed[i] = vdd1_rate_table_bridge[i].rate;
+
+ err = cpufreq_register_notifier(&iva_clk_notifier,
+ CPUFREQ_TRANSITION_NOTIFIER);
+ if (err)
+ pr_err("%s: clk_notifier_register failed for iva2_ck\n",
+ __func__);
+#endif
+#endif
+
+ dsp_clk_init();
+ services_init();
+
+ drv_datap = kzalloc(sizeof(struct drv_data), GFP_KERNEL);
+ if (!drv_datap) {
+ err = -ENOMEM;
+ goto err1;
+ }
+
+ drv_datap->shm_size = shm_size;
+ drv_datap->tc_wordswapon = tc_wordswapon;
+
+ if (base_img) {
+ drv_datap->base_img = kmalloc(strlen(base_img) + 1, GFP_KERNEL);
+ if (!drv_datap->base_img) {
+ err = -ENOMEM;
+ goto err2;
+ }
+ strncpy(drv_datap->base_img, base_img, strlen(base_img) + 1);
+ }
+
+ dev_set_drvdata(bridge, drv_datap);
+
+ if (shm_size < 0x10000) { /* 64 KB */
+ err = -EINVAL;
+ pr_err("%s: shm size must be at least 64 KB\n", __func__);
+ goto err3;
+ }
+ dev_dbg(bridge, "%s: requested shm_size = 0x%x\n", __func__, shm_size);
+
+ phys_membase = pdata->phys_mempool_base;
+ phys_memsize = pdata->phys_mempool_size;
+ if (phys_membase > 0 && phys_memsize > 0)
+ mem_ext_phys_pool_init(phys_membase, phys_memsize);
+
+ if (tc_wordswapon)
+ dev_dbg(bridge, "%s: TC Word Swap is enabled\n", __func__);
+
+ driver_context = dsp_init(&err);
+ if (err) {
+ pr_err("DSP Bridge driver initialization failed\n");
+ goto err4;
+ }
+
+ return 0;
+
+err4:
+ mem_ext_phys_pool_release();
+err3:
+ kfree(drv_datap->base_img);
+err2:
+ kfree(drv_datap);
+err1:
+#ifdef CONFIG_TIDSPBRIDGE_DVFS
+ cpufreq_unregister_notifier(&iva_clk_notifier,
+ CPUFREQ_TRANSITION_NOTIFIER);
+#endif
+ dsp_clk_exit();
+ services_exit();
+
+ return err;
+}
+
+static int __devinit omap34_xx_bridge_probe(struct platform_device *pdev)
+{
+ int err;
+ dev_t dev = 0;
+#ifdef CONFIG_TIDSPBRIDGE_DVFS
+ int i = 0;
+#endif
+
+ omap_dspbridge_dev = pdev;
+
+ /* Global bridge device */
+ bridge = &omap_dspbridge_dev->dev;
+
+ /* Bridge low level initializations */
+ err = omap3_bridge_startup(pdev);
+ if (err)
+ goto err1;
+
+ /* use 2.6 device model */
+ err = alloc_chrdev_region(&dev, 0, 1, driver_name);
+ if (err) {
+ pr_err("%s: Can't get major %d\n", __func__, driver_major);
+ goto err1;
+ }
+
+ cdev_init(&bridge_cdev, &bridge_fops);
+ bridge_cdev.owner = THIS_MODULE;
+
+ err = cdev_add(&bridge_cdev, dev, 1);
+ if (err) {
+ pr_err("%s: Failed to add bridge device\n", __func__);
+ goto err2;
+ }
+
+ /* udev support */
+ bridge_class = class_create(THIS_MODULE, "ti_bridge");
+ if (IS_ERR(bridge_class)) {
+ pr_err("%s: Error creating bridge class\n", __func__);
+ goto err3;
+ }
+
+ driver_major = MAJOR(dev);
+ device_create(bridge_class, NULL, MKDEV(driver_major, 0),
+ NULL, "DspBridge");
+ pr_info("DSP Bridge driver loaded\n");
+
+ return 0;
+
+err3:
+ cdev_del(&bridge_cdev);
+err2:
+ unregister_chrdev_region(dev, 1);
+err1:
+ return err;
+}
+
+static int __devexit omap34_xx_bridge_remove(struct platform_device *pdev)
+{
+ dev_t devno;
+ bool ret;
+ int status = 0;
+ void *hdrv_obj = NULL;
+
+ status = cfg_get_object((u32 *) &hdrv_obj, REG_DRV_OBJECT);
+ if (status)
+ goto func_cont;
+
+#ifdef CONFIG_TIDSPBRIDGE_DVFS
+ if (cpufreq_unregister_notifier(&iva_clk_notifier,
+ CPUFREQ_TRANSITION_NOTIFIER))
+ pr_err("%s: cpufreq_unregister_notifier failed for iva2_ck\n",
+ __func__);
+#endif /* #ifdef CONFIG_TIDSPBRIDGE_DVFS */
+
+ if (driver_context) {
+ /* Put the DSP in reset state */
+ ret = dsp_deinit(driver_context);
+ driver_context = 0;
+ DBC_ASSERT(ret == true);
+ }
+
+func_cont:
+ mem_ext_phys_pool_release();
+
+ dsp_clk_exit();
+ services_exit();
+
+ devno = MKDEV(driver_major, 0);
+ cdev_del(&bridge_cdev);
+ unregister_chrdev_region(devno, 1);
+ if (bridge_class) {
+ /* remove the device from sysfs */
+ device_destroy(bridge_class, MKDEV(driver_major, 0));
+ class_destroy(bridge_class);
+
+ }
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int BRIDGE_SUSPEND(struct platform_device *pdev, pm_message_t state)
+{
+ u32 status;
+ u32 command = PWR_EMERGENCYDEEPSLEEP;
+
+ status = pwr_sleep_dsp(command, time_out);
+ if (status)
+ return -1;
+
+ bridge_suspend_data.suspended = 1;
+ return 0;
+}
+
+static int BRIDGE_RESUME(struct platform_device *pdev)
+{
+ u32 status;
+
+ status = pwr_wake_dsp(time_out);
+ if (status)
+ return -1;
+
+ bridge_suspend_data.suspended = 0;
+ wake_up(&bridge_suspend_data.suspend_wq);
+ return 0;
+}
+#else
+#define BRIDGE_SUSPEND NULL
+#define BRIDGE_RESUME NULL
+#endif
+
+static struct platform_driver bridge_driver = {
+ .driver = {
+ .name = BRIDGE_NAME,
+ },
+ .probe = omap34_xx_bridge_probe,
+ .remove = __devexit_p(omap34_xx_bridge_remove),
+ .suspend = BRIDGE_SUSPEND,
+ .resume = BRIDGE_RESUME,
+};
+
+static int __init bridge_init(void)
+{
+ return platform_driver_register(&bridge_driver);
+}
+
+static void __exit bridge_exit(void)
+{
+ platform_driver_unregister(&bridge_driver);
+}
+
+/*
+ * This function is called when an application opens handle to the
+ * bridge driver.
+ */
+static int bridge_open(struct inode *ip, struct file *filp)
+{
+ int status = 0;
+ struct process_context *pr_ctxt = NULL;
+
+ /*
+ * Allocate a new process context and insert it into global
+ * process context list.
+ */
+
+#ifdef CONFIG_TIDSPBRIDGE_RECOVERY
+ if (recover) {
+ if (filp->f_flags & O_NONBLOCK ||
+ wait_for_completion_interruptible(&bridge_open_comp))
+ return -EBUSY;
+ }
+#endif
+ pr_ctxt = kzalloc(sizeof(struct process_context), GFP_KERNEL);
+ if (pr_ctxt) {
+ pr_ctxt->res_state = PROC_RES_ALLOCATED;
+ spin_lock_init(&pr_ctxt->dmm_map_lock);
+ INIT_LIST_HEAD(&pr_ctxt->dmm_map_list);
+ spin_lock_init(&pr_ctxt->dmm_rsv_lock);
+ INIT_LIST_HEAD(&pr_ctxt->dmm_rsv_list);
+
+ pr_ctxt->node_id = kzalloc(sizeof(struct idr), GFP_KERNEL);
+ if (pr_ctxt->node_id) {
+ idr_init(pr_ctxt->node_id);
+ } else {
+ status = -ENOMEM;
+ goto err;
+ }
+
+ pr_ctxt->stream_id = kzalloc(sizeof(struct idr), GFP_KERNEL);
+ if (pr_ctxt->stream_id)
+ idr_init(pr_ctxt->stream_id);
+ else
+ status = -ENOMEM;
+ } else {
+ status = -ENOMEM;
+ }
+err:
+ filp->private_data = pr_ctxt;
+#ifdef CONFIG_TIDSPBRIDGE_RECOVERY
+ if (!status)
+ atomic_inc(&bridge_cref);
+#endif
+ return status;
+}
+
+/*
+ * This function is called when an application closes handle to the bridge
+ * driver.
+ */
+static int bridge_release(struct inode *ip, struct file *filp)
+{
+ int status = 0;
+ struct process_context *pr_ctxt;
+
+ if (!filp->private_data) {
+ status = -EIO;
+ goto err;
+ }
+
+ pr_ctxt = filp->private_data;
+ flush_signals(current);
+ drv_remove_all_resources(pr_ctxt);
+ proc_detach(pr_ctxt);
+ kfree(pr_ctxt);
+
+ filp->private_data = NULL;
+
+err:
+#ifdef CONFIG_TIDSPBRIDGE_RECOVERY
+ if (!atomic_dec_return(&bridge_cref))
+ complete(&bridge_comp);
+#endif
+ return status;
+}
+
+/* This function provides IO interface to the bridge driver. */
+static long bridge_ioctl(struct file *filp, unsigned int code,
+ unsigned long args)
+{
+ int status;
+ u32 retval = 0;
+ union trapped_args buf_in;
+
+ DBC_REQUIRE(filp != NULL);
+#ifdef CONFIG_TIDSPBRIDGE_RECOVERY
+ if (recover) {
+ status = -EIO;
+ goto err;
+ }
+#endif
+#ifdef CONFIG_PM
+ status = omap34_xxbridge_suspend_lockout(&bridge_suspend_data, filp);
+ if (status != 0)
+ return status;
+#endif
+
+ if (!filp->private_data) {
+ status = -EIO;
+ goto err;
+ }
+
+ status = copy_from_user(&buf_in, (union trapped_args *)args,
+ sizeof(union trapped_args));
+
+ if (!status) {
+ status = api_call_dev_ioctl(code, &buf_in, &retval,
+ filp->private_data);
+
+ if (!status) {
+ status = retval;
+ } else {
+ dev_dbg(bridge, "%s: IOCTL Failed, code: 0x%x "
+ "status 0x%x\n", __func__, code, status);
+ status = -1;
+ }
+
+ }
+
+err:
+ return status;
+}
+
+/* This function maps kernel space memory to user space memory. */
+static int bridge_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+ u32 offset = vma->vm_pgoff << PAGE_SHIFT;
+ u32 status;
+
+ DBC_ASSERT(vma->vm_start < vma->vm_end);
+
+ vma->vm_flags |= VM_RESERVED | VM_IO;
+ vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+
+ dev_dbg(bridge, "%s: vm filp %p offset %x start %lx end %lx page_prot "
+ "%lx flags %lx\n", __func__, filp, offset,
+ vma->vm_start, vma->vm_end, vma->vm_page_prot, vma->vm_flags);
+
+ status = remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff,
+ vma->vm_end - vma->vm_start,
+ vma->vm_page_prot);
+ if (status != 0)
+ status = -EAGAIN;
+
+ return status;
+}
+
+/* To remove all process resources before removing the process from the
+ * process context list */
+int drv_remove_all_resources(void *process_ctxt)
+{
+ int status = 0;
+ struct process_context *ctxt = (struct process_context *)process_ctxt;
+ drv_remove_all_strm_res_elements(ctxt);
+ drv_remove_all_node_res_elements(ctxt);
+ drv_remove_all_dmm_res_elements(ctxt);
+ ctxt->res_state = PROC_RES_FREED;
+ return status;
+}
+
+/* Bridge driver initialization and de-initialization functions */
+module_init(bridge_init);
+module_exit(bridge_exit);
diff --git a/drivers/staging/tidspbridge/rmgr/drv_interface.h b/drivers/staging/tidspbridge/rmgr/drv_interface.h
new file mode 100644
index 00000000000..ab070602adc
--- /dev/null
+++ b/drivers/staging/tidspbridge/rmgr/drv_interface.h
@@ -0,0 +1,28 @@
+/*
+ * drv_interface.h
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * Copyright (C) 2005-2006 Texas Instruments, Inc.
+ *
+ * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef _DRV_INTERFACE_H_
+#define _DRV_INTERFACE_H_
+
+/* Prototypes for all functions in this bridge */
+static int __init bridge_init(void); /* Initialize bridge */
+static void __exit bridge_exit(void); /* Opposite of initialize */
+static int bridge_open(struct inode *ip, struct file *filp); /* Open */
+static int bridge_release(struct inode *ip, struct file *filp); /* Release */
+static long bridge_ioctl(struct file *filp, unsigned int code,
+ unsigned long args);
+static int bridge_mmap(struct file *filp, struct vm_area_struct *vma);
+#endif /* ifndef _DRV_INTERFACE_H_ */
diff --git a/drivers/staging/tidspbridge/rmgr/dspdrv.c b/drivers/staging/tidspbridge/rmgr/dspdrv.c
new file mode 100644
index 00000000000..714f348f526
--- /dev/null
+++ b/drivers/staging/tidspbridge/rmgr/dspdrv.c
@@ -0,0 +1,142 @@
+/*
+ * dspdrv.c
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * Interface to allocate and free bridge resources.
+ *
+ * Copyright (C) 2005-2006 Texas Instruments, Inc.
+ *
+ * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+/* ----------------------------------- Host OS */
+#include <linux/types.h>
+#include <dspbridge/host_os.h>
+
+/* ----------------------------------- DSP/BIOS Bridge */
+#include <dspbridge/dbdefs.h>
+
+/* ----------------------------------- Trace & Debug */
+#include <dspbridge/dbc.h>
+
+/* ----------------------------------- OS Adaptation Layer */
+#include <dspbridge/cfg.h>
+
+/* ----------------------------------- Platform Manager */
+#include <dspbridge/drv.h>
+#include <dspbridge/dev.h>
+#include <dspbridge/dspapi.h>
+
+/* ----------------------------------- Resource Manager */
+#include <dspbridge/mgr.h>
+
+/* ----------------------------------- This */
+#include <dspbridge/dspdrv.h>
+
+/*
+ * ======== dsp_init ========
+ * Allocates bridge resources. Loads a base image onto DSP, if specified.
+ */
+u32 dsp_init(u32 *init_status)
+{
+ char dev_node[MAXREGPATHLENGTH] = "TIOMAP1510";
+ int status = -EPERM;
+ struct drv_object *drv_obj = NULL;
+ u32 device_node;
+ u32 device_node_string;
+
+ if (!api_init())
+ goto func_cont;
+
+ status = drv_create(&drv_obj);
+ if (status) {
+ api_exit();
+ goto func_cont;
+ }
+
+ /* End drv_create */
+ /* Request Resources */
+ status = drv_request_resources((u32) &dev_node, &device_node_string);
+ if (!status) {
+ /* Attempt to Start the Device */
+ status = dev_start_device((struct cfg_devnode *)
+ device_node_string);
+ if (status)
+ (void)drv_release_resources
+ ((u32) device_node_string, drv_obj);
+ } else {
+ dev_dbg(bridge, "%s: drv_request_resources Failed\n", __func__);
+ status = -EPERM;
+ }
+
+ /* Unwind whatever was loaded */
+ if (status) {
+ /* irrespective of the status of dev_remove_device we conitinue
+ * unloading. Get the Driver Object iterate through and remove.
+ * Reset the status to E_FAIL to avoid going through
+ * api_init_complete2. */
+ for (device_node = drv_get_first_dev_extension();
+ device_node != 0;
+ device_node = drv_get_next_dev_extension(device_node)) {
+ (void)dev_remove_device((struct cfg_devnode *)
+ device_node);
+ (void)drv_release_resources((u32) device_node, drv_obj);
+ }
+ /* Remove the Driver Object */
+ (void)drv_destroy(drv_obj);
+ drv_obj = NULL;
+ api_exit();
+ dev_dbg(bridge, "%s: Logical device failed init\n", __func__);
+ } /* Unwinding the loaded drivers */
+func_cont:
+ /* Attempt to Start the Board */
+ if (!status) {
+ /* BRD_AutoStart could fail if the dsp execuetable is not the
+ * correct one. We should not propagate that error
+ * into the device loader. */
+ (void)api_init_complete2();
+ } else {
+ dev_dbg(bridge, "%s: Failed\n", __func__);
+ } /* End api_init_complete2 */
+ DBC_ENSURE((!status && drv_obj != NULL) ||
+ (status && drv_obj == NULL));
+ *init_status = status;
+ /* Return the Driver Object */
+ return (u32) drv_obj;
+}
+
+/*
+ * ======== dsp_deinit ========
+ * Frees the resources allocated for bridge.
+ */
+bool dsp_deinit(u32 device_context)
+{
+ bool ret = true;
+ u32 device_node;
+ struct mgr_object *mgr_obj = NULL;
+
+ while ((device_node = drv_get_first_dev_extension()) != 0) {
+ (void)dev_remove_device((struct cfg_devnode *)device_node);
+
+ (void)drv_release_resources((u32) device_node,
+ (struct drv_object *)device_context);
+ }
+
+ (void)drv_destroy((struct drv_object *)device_context);
+
+ /* Get the Manager Object from Registry
+ * MGR Destroy will unload the DCD dll */
+ if (!cfg_get_object((u32 *) &mgr_obj, REG_MGR_OBJECT))
+ (void)mgr_destroy(mgr_obj);
+
+ api_exit();
+
+ return ret;
+}
diff --git a/drivers/staging/tidspbridge/rmgr/mgr.c b/drivers/staging/tidspbridge/rmgr/mgr.c
new file mode 100644
index 00000000000..57a39b9c274
--- /dev/null
+++ b/drivers/staging/tidspbridge/rmgr/mgr.c
@@ -0,0 +1,375 @@
+/*
+ * mgr.c
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * Implementation of Manager interface to the device object at the
+ * driver level. This queries the NDB data base and retrieves the
+ * data about Node and Processor.
+ *
+ * Copyright (C) 2005-2006 Texas Instruments, Inc.
+ *
+ * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include <linux/types.h>
+
+/* ----------------------------------- DSP/BIOS Bridge */
+#include <dspbridge/dbdefs.h>
+
+/* ----------------------------------- Trace & Debug */
+#include <dspbridge/dbc.h>
+
+/* ----------------------------------- OS Adaptation Layer */
+#include <dspbridge/cfg.h>
+#include <dspbridge/sync.h>
+
+/* ----------------------------------- Others */
+#include <dspbridge/dbdcd.h>
+#include <dspbridge/drv.h>
+#include <dspbridge/dev.h>
+
+/* ----------------------------------- This */
+#include <dspbridge/mgr.h>
+
+/* ----------------------------------- Defines, Data Structures, Typedefs */
+#define ZLDLLNAME ""
+
+struct mgr_object {
+ struct dcd_manager *hdcd_mgr; /* Proc/Node data manager */
+};
+
+/* ----------------------------------- Globals */
+static u32 refs;
+
+/*
+ * ========= mgr_create =========
+ * Purpose:
+ * MGR Object gets created only once during driver Loading.
+ */
+int mgr_create(struct mgr_object **mgr_obj,
+ struct cfg_devnode *dev_node_obj)
+{
+ int status = 0;
+ struct mgr_object *pmgr_obj = NULL;
+
+ DBC_REQUIRE(mgr_obj != NULL);
+ DBC_REQUIRE(refs > 0);
+
+ pmgr_obj = kzalloc(sizeof(struct mgr_object), GFP_KERNEL);
+ if (pmgr_obj) {
+ status = dcd_create_manager(ZLDLLNAME, &pmgr_obj->hdcd_mgr);
+ if (!status) {
+ /* If succeeded store the handle in the MGR Object */
+ status = cfg_set_object((u32) pmgr_obj, REG_MGR_OBJECT);
+ if (!status) {
+ *mgr_obj = pmgr_obj;
+ } else {
+ dcd_destroy_manager(pmgr_obj->hdcd_mgr);
+ kfree(pmgr_obj);
+ }
+ } else {
+ /* failed to Create DCD Manager */
+ kfree(pmgr_obj);
+ }
+ } else {
+ status = -ENOMEM;
+ }
+
+ DBC_ENSURE(status || pmgr_obj);
+ return status;
+}
+
+/*
+ * ========= mgr_destroy =========
+ * This function is invoked during bridge driver unloading.Frees MGR object.
+ */
+int mgr_destroy(struct mgr_object *hmgr_obj)
+{
+ int status = 0;
+ struct mgr_object *pmgr_obj = (struct mgr_object *)hmgr_obj;
+
+ DBC_REQUIRE(refs > 0);
+ DBC_REQUIRE(hmgr_obj);
+
+ /* Free resources */
+ if (hmgr_obj->hdcd_mgr)
+ dcd_destroy_manager(hmgr_obj->hdcd_mgr);
+
+ kfree(pmgr_obj);
+ /* Update the Registry with NULL for MGR Object */
+ (void)cfg_set_object(0, REG_MGR_OBJECT);
+
+ return status;
+}
+
+/*
+ * ======== mgr_enum_node_info ========
+ * Enumerate and get configuration information about nodes configured
+ * in the node database.
+ */
+int mgr_enum_node_info(u32 node_id, struct dsp_ndbprops *pndb_props,
+ u32 undb_props_size, u32 *pu_num_nodes)
+{
+ int status = 0;
+ struct dsp_uuid node_uuid, temp_uuid;
+ u32 temp_index = 0;
+ u32 node_index = 0;
+ struct dcd_genericobj gen_obj;
+ struct mgr_object *pmgr_obj = NULL;
+
+ DBC_REQUIRE(pndb_props != NULL);
+ DBC_REQUIRE(pu_num_nodes != NULL);
+ DBC_REQUIRE(undb_props_size >= sizeof(struct dsp_ndbprops));
+ DBC_REQUIRE(refs > 0);
+
+ *pu_num_nodes = 0;
+ /* Get The Manager Object from the Registry */
+ status = cfg_get_object((u32 *) &pmgr_obj, REG_MGR_OBJECT);
+ if (status)
+ goto func_cont;
+
+ DBC_ASSERT(pmgr_obj);
+ /* Forever loop till we hit failed or no more items in the
+ * Enumeration. We will exit the loop other than 0; */
+ while (status == 0) {
+ status = dcd_enumerate_object(temp_index++, DSP_DCDNODETYPE,
+ &temp_uuid);
+ if (status == 0) {
+ node_index++;
+ if (node_id == (node_index - 1))
+ node_uuid = temp_uuid;
+
+ }
+ }
+ if (!status) {
+ if (node_id > (node_index - 1)) {
+ status = -EINVAL;
+ } else {
+ status = dcd_get_object_def(pmgr_obj->hdcd_mgr,
+ (struct dsp_uuid *)
+ &node_uuid, DSP_DCDNODETYPE,
+ &gen_obj);
+ if (!status) {
+ /* Get the Obj def */
+ *pndb_props =
+ gen_obj.obj_data.node_obj.ndb_props;
+ *pu_num_nodes = node_index;
+ }
+ }
+ }
+
+func_cont:
+ DBC_ENSURE((!status && *pu_num_nodes > 0) ||
+ (status && *pu_num_nodes == 0));
+
+ return status;
+}
+
+/*
+ * ======== mgr_enum_processor_info ========
+ * Enumerate and get configuration information about available
+ * DSP processors.
+ */
+int mgr_enum_processor_info(u32 processor_id,
+ struct dsp_processorinfo *
+ processor_info, u32 processor_info_size,
+ u8 *pu_num_procs)
+{
+ int status = 0;
+ int status1 = 0;
+ int status2 = 0;
+ struct dsp_uuid temp_uuid;
+ u32 temp_index = 0;
+ u32 proc_index = 0;
+ struct dcd_genericobj gen_obj;
+ struct mgr_object *pmgr_obj = NULL;
+ struct mgr_processorextinfo *ext_info;
+ struct dev_object *hdev_obj;
+ struct drv_object *hdrv_obj;
+ u8 dev_type;
+ struct cfg_devnode *dev_node;
+ bool proc_detect = false;
+
+ DBC_REQUIRE(processor_info != NULL);
+ DBC_REQUIRE(pu_num_procs != NULL);
+ DBC_REQUIRE(processor_info_size >= sizeof(struct dsp_processorinfo));
+ DBC_REQUIRE(refs > 0);
+
+ *pu_num_procs = 0;
+ status = cfg_get_object((u32 *) &hdrv_obj, REG_DRV_OBJECT);
+ if (!status) {
+ status = drv_get_dev_object(processor_id, hdrv_obj, &hdev_obj);
+ if (!status) {
+ status = dev_get_dev_type(hdev_obj, (u8 *) &dev_type);
+ status = dev_get_dev_node(hdev_obj, &dev_node);
+ if (dev_type != DSP_UNIT)
+ status = -EPERM;
+
+ if (!status)
+ processor_info->processor_type = DSPTYPE64;
+ }
+ }
+ if (status)
+ goto func_end;
+
+ /* Get The Manager Object from the Registry */
+ if (cfg_get_object((u32 *) &pmgr_obj, REG_MGR_OBJECT)) {
+ dev_dbg(bridge, "%s: Failed to get MGR Object\n", __func__);
+ goto func_end;
+ }
+ DBC_ASSERT(pmgr_obj);
+ /* Forever loop till we hit no more items in the
+ * Enumeration. We will exit the loop other than 0; */
+ while (status1 == 0) {
+ status1 = dcd_enumerate_object(temp_index++,
+ DSP_DCDPROCESSORTYPE,
+ &temp_uuid);
+ if (status1 != 0)
+ break;
+
+ proc_index++;
+ /* Get the Object properties to find the Device/Processor
+ * Type */
+ if (proc_detect != false)
+ continue;
+
+ status2 = dcd_get_object_def(pmgr_obj->hdcd_mgr,
+ (struct dsp_uuid *)&temp_uuid,
+ DSP_DCDPROCESSORTYPE, &gen_obj);
+ if (!status2) {
+ /* Get the Obj def */
+ if (processor_info_size <
+ sizeof(struct mgr_processorextinfo)) {
+ *processor_info = gen_obj.obj_data.proc_info;
+ } else {
+ /* extended info */
+ ext_info = (struct mgr_processorextinfo *)
+ processor_info;
+ *ext_info = gen_obj.obj_data.ext_proc_obj;
+ }
+ dev_dbg(bridge, "%s: Got proctype from DCD %x\n",
+ __func__, processor_info->processor_type);
+ /* See if we got the needed processor */
+ if (dev_type == DSP_UNIT) {
+ if (processor_info->processor_type ==
+ DSPPROCTYPE_C64)
+ proc_detect = true;
+ } else if (dev_type == IVA_UNIT) {
+ if (processor_info->processor_type ==
+ IVAPROCTYPE_ARM7)
+ proc_detect = true;
+ }
+ /* User applciatiuons aonly check for chip type, so
+ * this clumsy overwrite */
+ processor_info->processor_type = DSPTYPE64;
+ } else {
+ dev_dbg(bridge, "%s: Failed to get DCD processor info "
+ "%x\n", __func__, status2);
+ status = -EPERM;
+ }
+ }
+ *pu_num_procs = proc_index;
+ if (proc_detect == false) {
+ dev_dbg(bridge, "%s: Failed to get proc info from DCD, so use "
+ "CFG registry\n", __func__);
+ processor_info->processor_type = DSPTYPE64;
+ }
+func_end:
+ return status;
+}
+
+/*
+ * ======== mgr_exit ========
+ * Decrement reference count, and free resources when reference count is
+ * 0.
+ */
+void mgr_exit(void)
+{
+ DBC_REQUIRE(refs > 0);
+ refs--;
+ if (refs == 0)
+ dcd_exit();
+
+ DBC_ENSURE(refs >= 0);
+}
+
+/*
+ * ======== mgr_get_dcd_handle ========
+ * Retrieves the MGR handle. Accessor Function.
+ */
+int mgr_get_dcd_handle(struct mgr_object *mgr_handle,
+ u32 *dcd_handle)
+{
+ int status = -EPERM;
+ struct mgr_object *pmgr_obj = (struct mgr_object *)mgr_handle;
+
+ DBC_REQUIRE(refs > 0);
+ DBC_REQUIRE(dcd_handle != NULL);
+
+ *dcd_handle = (u32) NULL;
+ if (pmgr_obj) {
+ *dcd_handle = (u32) pmgr_obj->hdcd_mgr;
+ status = 0;
+ }
+ DBC_ENSURE((!status && *dcd_handle != (u32) NULL) ||
+ (status && *dcd_handle == (u32) NULL));
+
+ return status;
+}
+
+/*
+ * ======== mgr_init ========
+ * Initialize MGR's private state, keeping a reference count on each call.
+ */
+bool mgr_init(void)
+{
+ bool ret = true;
+ bool init_dcd = false;
+
+ DBC_REQUIRE(refs >= 0);
+
+ if (refs == 0) {
+ init_dcd = dcd_init(); /* DCD Module */
+
+ if (!init_dcd)
+ ret = false;
+ }
+
+ if (ret)
+ refs++;
+
+ DBC_ENSURE((ret && (refs > 0)) || (!ret && (refs >= 0)));
+
+ return ret;
+}
+
+/*
+ * ======== mgr_wait_for_bridge_events ========
+ * Block on any Bridge event(s)
+ */
+int mgr_wait_for_bridge_events(struct dsp_notification **anotifications,
+ u32 count, u32 *pu_index,
+ u32 utimeout)
+{
+ int status;
+ struct sync_object *sync_events[MAX_EVENTS];
+ u32 i;
+
+ DBC_REQUIRE(count < MAX_EVENTS);
+
+ for (i = 0; i < count; i++)
+ sync_events[i] = anotifications[i]->handle;
+
+ status = sync_wait_on_multiple_events(sync_events, count, utimeout,
+ pu_index);
+
+ return status;
+
+}
diff --git a/drivers/staging/tidspbridge/rmgr/nldr.c b/drivers/staging/tidspbridge/rmgr/nldr.c
new file mode 100644
index 00000000000..d8f4eebf742
--- /dev/null
+++ b/drivers/staging/tidspbridge/rmgr/nldr.c
@@ -0,0 +1,1974 @@
+/*
+ * nldr.c
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * DSP/BIOS Bridge dynamic + overlay Node loader.
+ *
+ * Copyright (C) 2005-2006 Texas Instruments, Inc.
+ *
+ * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include <linux/types.h>
+
+#include <dspbridge/host_os.h>
+
+#include <dspbridge/dbdefs.h>
+
+#include <dspbridge/dbc.h>
+
+/* Platform manager */
+#include <dspbridge/cod.h>
+#include <dspbridge/dev.h>
+
+/* Resource manager */
+#include <dspbridge/dbll.h>
+#include <dspbridge/dbdcd.h>
+#include <dspbridge/rmm.h>
+#include <dspbridge/uuidutil.h>
+
+#include <dspbridge/nldr.h>
+#include <linux/gcd.h>
+
+/* Name of section containing dynamic load mem */
+#define DYNMEMSECT ".dspbridge_mem"
+
+/* Name of section containing dependent library information */
+#define DEPLIBSECT ".dspbridge_deplibs"
+
+/* Max depth of recursion for loading node's dependent libraries */
+#define MAXDEPTH 5
+
+/* Max number of persistent libraries kept by a node */
+#define MAXLIBS 5
+
+/*
+ * Defines for extracting packed dynamic load memory requirements from two
+ * masks.
+ * These defines must match node.cdb and dynm.cdb
+ * Format of data/code mask is:
+ * uuuuuuuu|fueeeeee|fudddddd|fucccccc|
+ * where
+ * u = unused
+ * cccccc = prefered/required dynamic mem segid for create phase data/code
+ * dddddd = prefered/required dynamic mem segid for delete phase data/code
+ * eeeeee = prefered/req. dynamic mem segid for execute phase data/code
+ * f = flag indicating if memory is preferred or required:
+ * f = 1 if required, f = 0 if preferred.
+ *
+ * The 6 bits of the segid are interpreted as follows:
+ *
+ * If the 6th bit (bit 5) is not set, then this specifies a memory segment
+ * between 0 and 31 (a maximum of 32 dynamic loading memory segments).
+ * If the 6th bit (bit 5) is set, segid has the following interpretation:
+ * segid = 32 - Any internal memory segment can be used.
+ * segid = 33 - Any external memory segment can be used.
+ * segid = 63 - Any memory segment can be used (in this case the
+ * required/preferred flag is irrelevant).
+ *
+ */
+/* Maximum allowed dynamic loading memory segments */
+#define MAXMEMSEGS 32
+
+#define MAXSEGID 3 /* Largest possible (real) segid */
+#define MEMINTERNALID 32 /* Segid meaning use internal mem */
+#define MEMEXTERNALID 33 /* Segid meaning use external mem */
+#define NULLID 63 /* Segid meaning no memory req/pref */
+#define FLAGBIT 7 /* 7th bit is pref./req. flag */
+#define SEGMASK 0x3f /* Bits 0 - 5 */
+
+#define CREATEBIT 0 /* Create segid starts at bit 0 */
+#define DELETEBIT 8 /* Delete segid starts at bit 8 */
+#define EXECUTEBIT 16 /* Execute segid starts at bit 16 */
+
+/*
+ * Masks that define memory type. Must match defines in dynm.cdb.
+ */
+#define DYNM_CODE 0x2
+#define DYNM_DATA 0x4
+#define DYNM_CODEDATA (DYNM_CODE | DYNM_DATA)
+#define DYNM_INTERNAL 0x8
+#define DYNM_EXTERNAL 0x10
+
+/*
+ * Defines for packing memory requirement/preference flags for code and
+ * data of each of the node's phases into one mask.
+ * The bit is set if the segid is required for loading code/data of the
+ * given phase. The bit is not set, if the segid is preferred only.
+ *
+ * These defines are also used as indeces into a segid array for the node.
+ * eg node's segid[CREATEDATAFLAGBIT] is the memory segment id that the
+ * create phase data is required or preferred to be loaded into.
+ */
+#define CREATEDATAFLAGBIT 0
+#define CREATECODEFLAGBIT 1
+#define EXECUTEDATAFLAGBIT 2
+#define EXECUTECODEFLAGBIT 3
+#define DELETEDATAFLAGBIT 4
+#define DELETECODEFLAGBIT 5
+#define MAXFLAGS 6
+
+ /*
+ * These names may be embedded in overlay sections to identify which
+ * node phase the section should be overlayed.
+ */
+#define PCREATE "create"
+#define PDELETE "delete"
+#define PEXECUTE "execute"
+
+static inline bool is_equal_uuid(struct dsp_uuid *uuid1,
+ struct dsp_uuid *uuid2)
+{
+ return !memcmp(uuid1, uuid2, sizeof(struct dsp_uuid));
+}
+
+ /*
+ * ======== mem_seg_info ========
+ * Format of dynamic loading memory segment info in coff file.
+ * Must match dynm.h55.
+ */
+struct mem_seg_info {
+ u32 segid; /* Dynamic loading memory segment number */
+ u32 base;
+ u32 len;
+ u32 type; /* Mask of DYNM_CODE, DYNM_INTERNAL, etc. */
+};
+
+/*
+ * ======== lib_node ========
+ * For maintaining a tree of library dependencies.
+ */
+struct lib_node {
+ struct dbll_library_obj *lib; /* The library */
+ u16 dep_libs; /* Number of dependent libraries */
+ struct lib_node *dep_libs_tree; /* Dependent libraries of lib */
+};
+
+/*
+ * ======== ovly_sect ========
+ * Information needed to overlay a section.
+ */
+struct ovly_sect {
+ struct ovly_sect *next_sect;
+ u32 sect_load_addr; /* Load address of section */
+ u32 sect_run_addr; /* Run address of section */
+ u32 size; /* Size of section */
+ u16 page; /* DBL_CODE, DBL_DATA */
+};
+
+/*
+ * ======== ovly_node ========
+ * For maintaining a list of overlay nodes, with sections that need to be
+ * overlayed for each of the nodes phases.
+ */
+struct ovly_node {
+ struct dsp_uuid uuid;
+ char *node_name;
+ struct ovly_sect *create_sects_list;
+ struct ovly_sect *delete_sects_list;
+ struct ovly_sect *execute_sects_list;
+ struct ovly_sect *other_sects_list;
+ u16 create_sects;
+ u16 delete_sects;
+ u16 execute_sects;
+ u16 other_sects;
+ u16 create_ref;
+ u16 delete_ref;
+ u16 execute_ref;
+ u16 other_ref;
+};
+
+/*
+ * ======== nldr_object ========
+ * Overlay loader object.
+ */
+struct nldr_object {
+ struct dev_object *hdev_obj; /* Device object */
+ struct dcd_manager *hdcd_mgr; /* Proc/Node data manager */
+ struct dbll_tar_obj *dbll; /* The DBL loader */
+ struct dbll_library_obj *base_lib; /* Base image library */
+ struct rmm_target_obj *rmm; /* Remote memory manager for DSP */
+ struct dbll_fxns ldr_fxns; /* Loader function table */
+ struct dbll_attrs ldr_attrs; /* attrs to pass to loader functions */
+ nldr_ovlyfxn ovly_fxn; /* "write" for overlay nodes */
+ nldr_writefxn write_fxn; /* "write" for dynamic nodes */
+ struct ovly_node *ovly_table; /* Table of overlay nodes */
+ u16 ovly_nodes; /* Number of overlay nodes in base */
+ u16 ovly_nid; /* Index for tracking overlay nodes */
+ u16 dload_segs; /* Number of dynamic load mem segs */
+ u32 *seg_table; /* memtypes of dynamic memory segs
+ * indexed by segid
+ */
+ u16 us_dsp_mau_size; /* Size of DSP MAU */
+ u16 us_dsp_word_size; /* Size of DSP word */
+};
+
+/*
+ * ======== nldr_nodeobject ========
+ * Dynamic node object. This object is created when a node is allocated.
+ */
+struct nldr_nodeobject {
+ struct nldr_object *nldr_obj; /* Dynamic loader handle */
+ void *priv_ref; /* Handle to pass to dbl_write_fxn */
+ struct dsp_uuid uuid; /* Node's UUID */
+ bool dynamic; /* Dynamically loaded node? */
+ bool overlay; /* Overlay node? */
+ bool *pf_phase_split; /* Multiple phase libraries? */
+ struct lib_node root; /* Library containing node phase */
+ struct lib_node create_lib; /* Library with create phase lib */
+ struct lib_node execute_lib; /* Library with execute phase lib */
+ struct lib_node delete_lib; /* Library with delete phase lib */
+ /* libs remain loaded until Delete */
+ struct lib_node pers_lib_table[MAXLIBS];
+ s32 pers_libs; /* Number of persistent libraries */
+ /* Path in lib dependency tree */
+ struct dbll_library_obj *lib_path[MAXDEPTH + 1];
+ enum nldr_phase phase; /* Node phase currently being loaded */
+
+ /*
+ * Dynamic loading memory segments for data and code of each phase.
+ */
+ u16 seg_id[MAXFLAGS];
+
+ /*
+ * Mask indicating whether each mem segment specified in seg_id[]
+ * is preferred or required.
+ * For example
+ * if (code_data_flag_mask & (1 << EXECUTEDATAFLAGBIT)) != 0,
+ * then it is required to load execute phase data into the memory
+ * specified by seg_id[EXECUTEDATAFLAGBIT].
+ */
+ u32 code_data_flag_mask;
+};
+
+/* Dynamic loader function table */
+static struct dbll_fxns ldr_fxns = {
+ (dbll_close_fxn) dbll_close,
+ (dbll_create_fxn) dbll_create,
+ (dbll_delete_fxn) dbll_delete,
+ (dbll_exit_fxn) dbll_exit,
+ (dbll_get_attrs_fxn) dbll_get_attrs,
+ (dbll_get_addr_fxn) dbll_get_addr,
+ (dbll_get_c_addr_fxn) dbll_get_c_addr,
+ (dbll_get_sect_fxn) dbll_get_sect,
+ (dbll_init_fxn) dbll_init,
+ (dbll_load_fxn) dbll_load,
+ (dbll_load_sect_fxn) dbll_load_sect,
+ (dbll_open_fxn) dbll_open,
+ (dbll_read_sect_fxn) dbll_read_sect,
+ (dbll_set_attrs_fxn) dbll_set_attrs,
+ (dbll_unload_fxn) dbll_unload,
+ (dbll_unload_sect_fxn) dbll_unload_sect,
+};
+
+static u32 refs; /* module reference count */
+
+static int add_ovly_info(void *handle, struct dbll_sect_info *sect_info,
+ u32 addr, u32 bytes);
+static int add_ovly_node(struct dsp_uuid *uuid_obj,
+ enum dsp_dcdobjtype obj_type, void *handle);
+static int add_ovly_sect(struct nldr_object *nldr_obj,
+ struct ovly_sect **lst,
+ struct dbll_sect_info *sect_inf,
+ bool *exists, u32 addr, u32 bytes);
+static s32 fake_ovly_write(void *handle, u32 dsp_address, void *buf, u32 bytes,
+ s32 mtype);
+static void free_sects(struct nldr_object *nldr_obj,
+ struct ovly_sect *phase_sects, u16 alloc_num);
+static bool get_symbol_value(void *handle, void *parg, void *rmm_handle,
+ char *sym_name, struct dbll_sym_val **sym);
+static int load_lib(struct nldr_nodeobject *nldr_node_obj,
+ struct lib_node *root, struct dsp_uuid uuid,
+ bool root_prstnt,
+ struct dbll_library_obj **lib_path,
+ enum nldr_phase phase, u16 depth);
+static int load_ovly(struct nldr_nodeobject *nldr_node_obj,
+ enum nldr_phase phase);
+static int remote_alloc(void **ref, u16 mem_sect, u32 size,
+ u32 align, u32 *dsp_address,
+ s32 segmnt_id,
+ s32 req, bool reserve);
+static int remote_free(void **ref, u16 space, u32 dsp_address, u32 size,
+ bool reserve);
+
+static void unload_lib(struct nldr_nodeobject *nldr_node_obj,
+ struct lib_node *root);
+static void unload_ovly(struct nldr_nodeobject *nldr_node_obj,
+ enum nldr_phase phase);
+static bool find_in_persistent_lib_array(struct nldr_nodeobject *nldr_node_obj,
+ struct dbll_library_obj *lib);
+static u32 find_lcm(u32 a, u32 b);
+
+/*
+ * ======== nldr_allocate ========
+ */
+int nldr_allocate(struct nldr_object *nldr_obj, void *priv_ref,
+ const struct dcd_nodeprops *node_props,
+ struct nldr_nodeobject **nldr_nodeobj,
+ bool *pf_phase_split)
+{
+ struct nldr_nodeobject *nldr_node_obj = NULL;
+ int status = 0;
+
+ DBC_REQUIRE(refs > 0);
+ DBC_REQUIRE(node_props != NULL);
+ DBC_REQUIRE(nldr_nodeobj != NULL);
+ DBC_REQUIRE(nldr_obj);
+
+ /* Initialize handle in case of failure */
+ *nldr_nodeobj = NULL;
+ /* Allocate node object */
+ nldr_node_obj = kzalloc(sizeof(struct nldr_nodeobject), GFP_KERNEL);
+
+ if (nldr_node_obj == NULL) {
+ status = -ENOMEM;
+ } else {
+ nldr_node_obj->pf_phase_split = pf_phase_split;
+ nldr_node_obj->pers_libs = 0;
+ nldr_node_obj->nldr_obj = nldr_obj;
+ nldr_node_obj->priv_ref = priv_ref;
+ /* Save node's UUID. */
+ nldr_node_obj->uuid = node_props->ndb_props.ui_node_id;
+ /*
+ * Determine if node is a dynamically loaded node from
+ * ndb_props.
+ */
+ if (node_props->us_load_type == NLDR_DYNAMICLOAD) {
+ /* Dynamic node */
+ nldr_node_obj->dynamic = true;
+ /*
+ * Extract memory requirements from ndb_props masks
+ */
+ /* Create phase */
+ nldr_node_obj->seg_id[CREATEDATAFLAGBIT] = (u16)
+ (node_props->ul_data_mem_seg_mask >> CREATEBIT) &
+ SEGMASK;
+ nldr_node_obj->code_data_flag_mask |=
+ ((node_props->ul_data_mem_seg_mask >>
+ (CREATEBIT + FLAGBIT)) & 1) << CREATEDATAFLAGBIT;
+ nldr_node_obj->seg_id[CREATECODEFLAGBIT] = (u16)
+ (node_props->ul_code_mem_seg_mask >>
+ CREATEBIT) & SEGMASK;
+ nldr_node_obj->code_data_flag_mask |=
+ ((node_props->ul_code_mem_seg_mask >>
+ (CREATEBIT + FLAGBIT)) & 1) << CREATECODEFLAGBIT;
+ /* Execute phase */
+ nldr_node_obj->seg_id[EXECUTEDATAFLAGBIT] = (u16)
+ (node_props->ul_data_mem_seg_mask >>
+ EXECUTEBIT) & SEGMASK;
+ nldr_node_obj->code_data_flag_mask |=
+ ((node_props->ul_data_mem_seg_mask >>
+ (EXECUTEBIT + FLAGBIT)) & 1) <<
+ EXECUTEDATAFLAGBIT;
+ nldr_node_obj->seg_id[EXECUTECODEFLAGBIT] = (u16)
+ (node_props->ul_code_mem_seg_mask >>
+ EXECUTEBIT) & SEGMASK;
+ nldr_node_obj->code_data_flag_mask |=
+ ((node_props->ul_code_mem_seg_mask >>
+ (EXECUTEBIT + FLAGBIT)) & 1) <<
+ EXECUTECODEFLAGBIT;
+ /* Delete phase */
+ nldr_node_obj->seg_id[DELETEDATAFLAGBIT] = (u16)
+ (node_props->ul_data_mem_seg_mask >> DELETEBIT) &
+ SEGMASK;
+ nldr_node_obj->code_data_flag_mask |=
+ ((node_props->ul_data_mem_seg_mask >>
+ (DELETEBIT + FLAGBIT)) & 1) << DELETEDATAFLAGBIT;
+ nldr_node_obj->seg_id[DELETECODEFLAGBIT] = (u16)
+ (node_props->ul_code_mem_seg_mask >>
+ DELETEBIT) & SEGMASK;
+ nldr_node_obj->code_data_flag_mask |=
+ ((node_props->ul_code_mem_seg_mask >>
+ (DELETEBIT + FLAGBIT)) & 1) << DELETECODEFLAGBIT;
+ } else {
+ /* Non-dynamically loaded nodes are part of the
+ * base image */
+ nldr_node_obj->root.lib = nldr_obj->base_lib;
+ /* Check for overlay node */
+ if (node_props->us_load_type == NLDR_OVLYLOAD)
+ nldr_node_obj->overlay = true;
+
+ }
+ *nldr_nodeobj = (struct nldr_nodeobject *)nldr_node_obj;
+ }
+ /* Cleanup on failure */
+ if (status && nldr_node_obj)
+ kfree(nldr_node_obj);
+
+ DBC_ENSURE((!status && *nldr_nodeobj)
+ || (status && *nldr_nodeobj == NULL));
+ return status;
+}
+
+/*
+ * ======== nldr_create ========
+ */
+int nldr_create(struct nldr_object **nldr,
+ struct dev_object *hdev_obj,
+ const struct nldr_attrs *pattrs)
+{
+ struct cod_manager *cod_mgr; /* COD manager */
+ char *psz_coff_buf = NULL;
+ char sz_zl_file[COD_MAXPATHLENGTH];
+ struct nldr_object *nldr_obj = NULL;
+ struct dbll_attrs save_attrs;
+ struct dbll_attrs new_attrs;
+ dbll_flags flags;
+ u32 ul_entry;
+ u16 dload_segs = 0;
+ struct mem_seg_info *mem_info_obj;
+ u32 ul_len = 0;
+ u32 ul_addr;
+ struct rmm_segment *rmm_segs = NULL;
+ u16 i;
+ int status = 0;
+ DBC_REQUIRE(refs > 0);
+ DBC_REQUIRE(nldr != NULL);
+ DBC_REQUIRE(hdev_obj != NULL);
+ DBC_REQUIRE(pattrs != NULL);
+ DBC_REQUIRE(pattrs->pfn_ovly != NULL);
+ DBC_REQUIRE(pattrs->pfn_write != NULL);
+
+ /* Allocate dynamic loader object */
+ nldr_obj = kzalloc(sizeof(struct nldr_object), GFP_KERNEL);
+ if (nldr_obj) {
+ nldr_obj->hdev_obj = hdev_obj;
+ /* warning, lazy status checking alert! */
+ dev_get_cod_mgr(hdev_obj, &cod_mgr);
+ if (cod_mgr) {
+ status = cod_get_loader(cod_mgr, &nldr_obj->dbll);
+ DBC_ASSERT(!status);
+ status = cod_get_base_lib(cod_mgr, &nldr_obj->base_lib);
+ DBC_ASSERT(!status);
+ status =
+ cod_get_base_name(cod_mgr, sz_zl_file,
+ COD_MAXPATHLENGTH);
+ DBC_ASSERT(!status);
+ }
+ status = 0;
+ /* end lazy status checking */
+ nldr_obj->us_dsp_mau_size = pattrs->us_dsp_mau_size;
+ nldr_obj->us_dsp_word_size = pattrs->us_dsp_word_size;
+ nldr_obj->ldr_fxns = ldr_fxns;
+ if (!(nldr_obj->ldr_fxns.init_fxn()))
+ status = -ENOMEM;
+
+ } else {
+ status = -ENOMEM;
+ }
+ /* Create the DCD Manager */
+ if (!status)
+ status = dcd_create_manager(NULL, &nldr_obj->hdcd_mgr);
+
+ /* Get dynamic loading memory sections from base lib */
+ if (!status) {
+ status =
+ nldr_obj->ldr_fxns.get_sect_fxn(nldr_obj->base_lib,
+ DYNMEMSECT, &ul_addr,
+ &ul_len);
+ if (!status) {
+ psz_coff_buf =
+ kzalloc(ul_len * nldr_obj->us_dsp_mau_size,
+ GFP_KERNEL);
+ if (!psz_coff_buf)
+ status = -ENOMEM;
+ } else {
+ /* Ok to not have dynamic loading memory */
+ status = 0;
+ ul_len = 0;
+ dev_dbg(bridge, "%s: failed - no dynamic loading mem "
+ "segments: 0x%x\n", __func__, status);
+ }
+ }
+ if (!status && ul_len > 0) {
+ /* Read section containing dynamic load mem segments */
+ status =
+ nldr_obj->ldr_fxns.read_sect_fxn(nldr_obj->base_lib,
+ DYNMEMSECT, psz_coff_buf,
+ ul_len);
+ }
+ if (!status && ul_len > 0) {
+ /* Parse memory segment data */
+ dload_segs = (u16) (*((u32 *) psz_coff_buf));
+ if (dload_segs > MAXMEMSEGS)
+ status = -EBADF;
+ }
+ /* Parse dynamic load memory segments */
+ if (!status && dload_segs > 0) {
+ rmm_segs = kzalloc(sizeof(struct rmm_segment) * dload_segs,
+ GFP_KERNEL);
+ nldr_obj->seg_table =
+ kzalloc(sizeof(u32) * dload_segs, GFP_KERNEL);
+ if (rmm_segs == NULL || nldr_obj->seg_table == NULL) {
+ status = -ENOMEM;
+ } else {
+ nldr_obj->dload_segs = dload_segs;
+ mem_info_obj = (struct mem_seg_info *)(psz_coff_buf +
+ sizeof(u32));
+ for (i = 0; i < dload_segs; i++) {
+ rmm_segs[i].base = (mem_info_obj + i)->base;
+ rmm_segs[i].length = (mem_info_obj + i)->len;
+ rmm_segs[i].space = 0;
+ nldr_obj->seg_table[i] =
+ (mem_info_obj + i)->type;
+ dev_dbg(bridge,
+ "(proc) DLL MEMSEGMENT: %d, "
+ "Base: 0x%x, Length: 0x%x\n", i,
+ rmm_segs[i].base, rmm_segs[i].length);
+ }
+ }
+ }
+ /* Create Remote memory manager */
+ if (!status)
+ status = rmm_create(&nldr_obj->rmm, rmm_segs, dload_segs);
+
+ if (!status) {
+ /* set the alloc, free, write functions for loader */
+ nldr_obj->ldr_fxns.get_attrs_fxn(nldr_obj->dbll, &save_attrs);
+ new_attrs = save_attrs;
+ new_attrs.alloc = (dbll_alloc_fxn) remote_alloc;
+ new_attrs.free = (dbll_free_fxn) remote_free;
+ new_attrs.sym_lookup = (dbll_sym_lookup) get_symbol_value;
+ new_attrs.sym_handle = nldr_obj;
+ new_attrs.write = (dbll_write_fxn) pattrs->pfn_write;
+ nldr_obj->ovly_fxn = pattrs->pfn_ovly;
+ nldr_obj->write_fxn = pattrs->pfn_write;
+ nldr_obj->ldr_attrs = new_attrs;
+ }
+ kfree(rmm_segs);
+
+ kfree(psz_coff_buf);
+
+ /* Get overlay nodes */
+ if (!status) {
+ status =
+ cod_get_base_name(cod_mgr, sz_zl_file, COD_MAXPATHLENGTH);
+ /* lazy check */
+ DBC_ASSERT(!status);
+ /* First count number of overlay nodes */
+ status =
+ dcd_get_objects(nldr_obj->hdcd_mgr, sz_zl_file,
+ add_ovly_node, (void *)nldr_obj);
+ /* Now build table of overlay nodes */
+ if (!status && nldr_obj->ovly_nodes > 0) {
+ /* Allocate table for overlay nodes */
+ nldr_obj->ovly_table =
+ kzalloc(sizeof(struct ovly_node) *
+ nldr_obj->ovly_nodes, GFP_KERNEL);
+ /* Put overlay nodes in the table */
+ nldr_obj->ovly_nid = 0;
+ status = dcd_get_objects(nldr_obj->hdcd_mgr, sz_zl_file,
+ add_ovly_node,
+ (void *)nldr_obj);
+ }
+ }
+ /* Do a fake reload of the base image to get overlay section info */
+ if (!status && nldr_obj->ovly_nodes > 0) {
+ save_attrs.write = fake_ovly_write;
+ save_attrs.log_write = add_ovly_info;
+ save_attrs.log_write_handle = nldr_obj;
+ flags = DBLL_CODE | DBLL_DATA | DBLL_SYMB;
+ status = nldr_obj->ldr_fxns.load_fxn(nldr_obj->base_lib, flags,
+ &save_attrs, &ul_entry);
+ }
+ if (!status) {
+ *nldr = (struct nldr_object *)nldr_obj;
+ } else {
+ if (nldr_obj)
+ nldr_delete((struct nldr_object *)nldr_obj);
+
+ *nldr = NULL;
+ }
+ /* FIXME:Temp. Fix. Must be removed */
+ DBC_ENSURE((!status && *nldr) || (status && *nldr == NULL));
+ return status;
+}
+
+/*
+ * ======== nldr_delete ========
+ */
+void nldr_delete(struct nldr_object *nldr_obj)
+{
+ struct ovly_sect *ovly_section;
+ struct ovly_sect *next;
+ u16 i;
+ DBC_REQUIRE(refs > 0);
+ DBC_REQUIRE(nldr_obj);
+
+ nldr_obj->ldr_fxns.exit_fxn();
+ if (nldr_obj->rmm)
+ rmm_delete(nldr_obj->rmm);
+
+ kfree(nldr_obj->seg_table);
+
+ if (nldr_obj->hdcd_mgr)
+ dcd_destroy_manager(nldr_obj->hdcd_mgr);
+
+ /* Free overlay node information */
+ if (nldr_obj->ovly_table) {
+ for (i = 0; i < nldr_obj->ovly_nodes; i++) {
+ ovly_section =
+ nldr_obj->ovly_table[i].create_sects_list;
+ while (ovly_section) {
+ next = ovly_section->next_sect;
+ kfree(ovly_section);
+ ovly_section = next;
+ }
+ ovly_section =
+ nldr_obj->ovly_table[i].delete_sects_list;
+ while (ovly_section) {
+ next = ovly_section->next_sect;
+ kfree(ovly_section);
+ ovly_section = next;
+ }
+ ovly_section =
+ nldr_obj->ovly_table[i].execute_sects_list;
+ while (ovly_section) {
+ next = ovly_section->next_sect;
+ kfree(ovly_section);
+ ovly_section = next;
+ }
+ ovly_section = nldr_obj->ovly_table[i].other_sects_list;
+ while (ovly_section) {
+ next = ovly_section->next_sect;
+ kfree(ovly_section);
+ ovly_section = next;
+ }
+ }
+ kfree(nldr_obj->ovly_table);
+ }
+ kfree(nldr_obj);
+}
+
+/*
+ * ======== nldr_exit ========
+ * Discontinue usage of NLDR module.
+ */
+void nldr_exit(void)
+{
+ DBC_REQUIRE(refs > 0);
+
+ refs--;
+
+ if (refs == 0)
+ rmm_exit();
+
+ DBC_ENSURE(refs >= 0);
+}
+
+/*
+ * ======== nldr_get_fxn_addr ========
+ */
+int nldr_get_fxn_addr(struct nldr_nodeobject *nldr_node_obj,
+ char *str_fxn, u32 * addr)
+{
+ struct dbll_sym_val *dbll_sym;
+ struct nldr_object *nldr_obj;
+ int status = 0;
+ bool status1 = false;
+ s32 i = 0;
+ struct lib_node root = { NULL, 0, NULL };
+ DBC_REQUIRE(refs > 0);
+ DBC_REQUIRE(nldr_node_obj);
+ DBC_REQUIRE(addr != NULL);
+ DBC_REQUIRE(str_fxn != NULL);
+
+ nldr_obj = nldr_node_obj->nldr_obj;
+ /* Called from node_create(), node_delete(), or node_run(). */
+ if (nldr_node_obj->dynamic && *nldr_node_obj->pf_phase_split) {
+ switch (nldr_node_obj->phase) {
+ case NLDR_CREATE:
+ root = nldr_node_obj->create_lib;
+ break;
+ case NLDR_EXECUTE:
+ root = nldr_node_obj->execute_lib;
+ break;
+ case NLDR_DELETE:
+ root = nldr_node_obj->delete_lib;
+ break;
+ default:
+ DBC_ASSERT(false);
+ break;
+ }
+ } else {
+ /* for Overlay nodes or non-split Dynamic nodes */
+ root = nldr_node_obj->root;
+ }
+ status1 =
+ nldr_obj->ldr_fxns.get_c_addr_fxn(root.lib, str_fxn, &dbll_sym);
+ if (!status1)
+ status1 =
+ nldr_obj->ldr_fxns.get_addr_fxn(root.lib, str_fxn,
+ &dbll_sym);
+
+ /* If symbol not found, check dependent libraries */
+ if (!status1) {
+ for (i = 0; i < root.dep_libs; i++) {
+ status1 =
+ nldr_obj->ldr_fxns.get_addr_fxn(root.dep_libs_tree
+ [i].lib, str_fxn,
+ &dbll_sym);
+ if (!status1) {
+ status1 =
+ nldr_obj->ldr_fxns.
+ get_c_addr_fxn(root.dep_libs_tree[i].lib,
+ str_fxn, &dbll_sym);
+ }
+ if (status1) {
+ /* Symbol found */
+ break;
+ }
+ }
+ }
+ /* Check persistent libraries */
+ if (!status1) {
+ for (i = 0; i < nldr_node_obj->pers_libs; i++) {
+ status1 =
+ nldr_obj->ldr_fxns.
+ get_addr_fxn(nldr_node_obj->pers_lib_table[i].lib,
+ str_fxn, &dbll_sym);
+ if (!status1) {
+ status1 =
+ nldr_obj->ldr_fxns.
+ get_c_addr_fxn(nldr_node_obj->pers_lib_table
+ [i].lib, str_fxn, &dbll_sym);
+ }
+ if (status1) {
+ /* Symbol found */
+ break;
+ }
+ }
+ }
+
+ if (status1)
+ *addr = dbll_sym->value;
+ else
+ status = -ESPIPE;
+
+ return status;
+}
+
+/*
+ * ======== nldr_get_rmm_manager ========
+ * Given a NLDR object, retrieve RMM Manager Handle
+ */
+int nldr_get_rmm_manager(struct nldr_object *nldr,
+ struct rmm_target_obj **rmm_mgr)
+{
+ int status = 0;
+ struct nldr_object *nldr_obj = nldr;
+ DBC_REQUIRE(rmm_mgr != NULL);
+
+ if (nldr) {
+ *rmm_mgr = nldr_obj->rmm;
+ } else {
+ *rmm_mgr = NULL;
+ status = -EFAULT;
+ }
+
+ DBC_ENSURE(!status || (rmm_mgr != NULL && *rmm_mgr == NULL));
+
+ return status;
+}
+
+/*
+ * ======== nldr_init ========
+ * Initialize the NLDR module.
+ */
+bool nldr_init(void)
+{
+ DBC_REQUIRE(refs >= 0);
+
+ if (refs == 0)
+ rmm_init();
+
+ refs++;
+
+ DBC_ENSURE(refs > 0);
+ return true;
+}
+
+/*
+ * ======== nldr_load ========
+ */
+int nldr_load(struct nldr_nodeobject *nldr_node_obj,
+ enum nldr_phase phase)
+{
+ struct nldr_object *nldr_obj;
+ struct dsp_uuid lib_uuid;
+ int status = 0;
+
+ DBC_REQUIRE(refs > 0);
+ DBC_REQUIRE(nldr_node_obj);
+
+ nldr_obj = nldr_node_obj->nldr_obj;
+
+ if (nldr_node_obj->dynamic) {
+ nldr_node_obj->phase = phase;
+
+ lib_uuid = nldr_node_obj->uuid;
+
+ /* At this point, we may not know if node is split into
+ * different libraries. So we'll go ahead and load the
+ * library, and then save the pointer to the appropriate
+ * location after we know. */
+
+ status =
+ load_lib(nldr_node_obj, &nldr_node_obj->root, lib_uuid,
+ false, nldr_node_obj->lib_path, phase, 0);
+
+ if (!status) {
+ if (*nldr_node_obj->pf_phase_split) {
+ switch (phase) {
+ case NLDR_CREATE:
+ nldr_node_obj->create_lib =
+ nldr_node_obj->root;
+ break;
+
+ case NLDR_EXECUTE:
+ nldr_node_obj->execute_lib =
+ nldr_node_obj->root;
+ break;
+
+ case NLDR_DELETE:
+ nldr_node_obj->delete_lib =
+ nldr_node_obj->root;
+ break;
+
+ default:
+ DBC_ASSERT(false);
+ break;
+ }
+ }
+ }
+ } else {
+ if (nldr_node_obj->overlay)
+ status = load_ovly(nldr_node_obj, phase);
+
+ }
+
+ return status;
+}
+
+/*
+ * ======== nldr_unload ========
+ */
+int nldr_unload(struct nldr_nodeobject *nldr_node_obj,
+ enum nldr_phase phase)
+{
+ int status = 0;
+ struct lib_node *root_lib = NULL;
+ s32 i = 0;
+
+ DBC_REQUIRE(refs > 0);
+ DBC_REQUIRE(nldr_node_obj);
+
+ if (nldr_node_obj != NULL) {
+ if (nldr_node_obj->dynamic) {
+ if (*nldr_node_obj->pf_phase_split) {
+ switch (phase) {
+ case NLDR_CREATE:
+ root_lib = &nldr_node_obj->create_lib;
+ break;
+ case NLDR_EXECUTE:
+ root_lib = &nldr_node_obj->execute_lib;
+ break;
+ case NLDR_DELETE:
+ root_lib = &nldr_node_obj->delete_lib;
+ /* Unload persistent libraries */
+ for (i = 0;
+ i < nldr_node_obj->pers_libs;
+ i++) {
+ unload_lib(nldr_node_obj,
+ &nldr_node_obj->
+ pers_lib_table[i]);
+ }
+ nldr_node_obj->pers_libs = 0;
+ break;
+ default:
+ DBC_ASSERT(false);
+ break;
+ }
+ } else {
+ /* Unload main library */
+ root_lib = &nldr_node_obj->root;
+ }
+ if (root_lib)
+ unload_lib(nldr_node_obj, root_lib);
+ } else {
+ if (nldr_node_obj->overlay)
+ unload_ovly(nldr_node_obj, phase);
+
+ }
+ }
+ return status;
+}
+
+/*
+ * ======== add_ovly_info ========
+ */
+static int add_ovly_info(void *handle, struct dbll_sect_info *sect_info,
+ u32 addr, u32 bytes)
+{
+ char *node_name;
+ char *sect_name = (char *)sect_info->name;
+ bool sect_exists = false;
+ char seps = ':';
+ char *pch;
+ u16 i;
+ struct nldr_object *nldr_obj = (struct nldr_object *)handle;
+ int status = 0;
+
+ /* Is this an overlay section (load address != run address)? */
+ if (sect_info->sect_load_addr == sect_info->sect_run_addr)
+ goto func_end;
+
+ /* Find the node it belongs to */
+ for (i = 0; i < nldr_obj->ovly_nodes; i++) {
+ node_name = nldr_obj->ovly_table[i].node_name;
+ DBC_REQUIRE(node_name);
+ if (strncmp(node_name, sect_name + 1, strlen(node_name)) == 0) {
+ /* Found the node */
+ break;
+ }
+ }
+ if (!(i < nldr_obj->ovly_nodes))
+ goto func_end;
+
+ /* Determine which phase this section belongs to */
+ for (pch = sect_name + 1; *pch && *pch != seps; pch++)
+ ;;
+
+ if (*pch) {
+ pch++; /* Skip over the ':' */
+ if (strncmp(pch, PCREATE, strlen(PCREATE)) == 0) {
+ status =
+ add_ovly_sect(nldr_obj,
+ &nldr_obj->
+ ovly_table[i].create_sects_list,
+ sect_info, &sect_exists, addr, bytes);
+ if (!status && !sect_exists)
+ nldr_obj->ovly_table[i].create_sects++;
+
+ } else if (strncmp(pch, PDELETE, strlen(PDELETE)) == 0) {
+ status =
+ add_ovly_sect(nldr_obj,
+ &nldr_obj->
+ ovly_table[i].delete_sects_list,
+ sect_info, &sect_exists, addr, bytes);
+ if (!status && !sect_exists)
+ nldr_obj->ovly_table[i].delete_sects++;
+
+ } else if (strncmp(pch, PEXECUTE, strlen(PEXECUTE)) == 0) {
+ status =
+ add_ovly_sect(nldr_obj,
+ &nldr_obj->
+ ovly_table[i].execute_sects_list,
+ sect_info, &sect_exists, addr, bytes);
+ if (!status && !sect_exists)
+ nldr_obj->ovly_table[i].execute_sects++;
+
+ } else {
+ /* Put in "other" sectins */
+ status =
+ add_ovly_sect(nldr_obj,
+ &nldr_obj->
+ ovly_table[i].other_sects_list,
+ sect_info, &sect_exists, addr, bytes);
+ if (!status && !sect_exists)
+ nldr_obj->ovly_table[i].other_sects++;
+
+ }
+ }
+func_end:
+ return status;
+}
+
+/*
+ * ======== add_ovly_node =========
+ * Callback function passed to dcd_get_objects.
+ */
+static int add_ovly_node(struct dsp_uuid *uuid_obj,
+ enum dsp_dcdobjtype obj_type, void *handle)
+{
+ struct nldr_object *nldr_obj = (struct nldr_object *)handle;
+ char *node_name = NULL;
+ char *pbuf = NULL;
+ u32 len;
+ struct dcd_genericobj obj_def;
+ int status = 0;
+
+ if (obj_type != DSP_DCDNODETYPE)
+ goto func_end;
+
+ status =
+ dcd_get_object_def(nldr_obj->hdcd_mgr, uuid_obj, obj_type,
+ &obj_def);
+ if (status)
+ goto func_end;
+
+ /* If overlay node, add to the list */
+ if (obj_def.obj_data.node_obj.us_load_type == NLDR_OVLYLOAD) {
+ if (nldr_obj->ovly_table == NULL) {
+ nldr_obj->ovly_nodes++;
+ } else {
+ /* Add node to table */
+ nldr_obj->ovly_table[nldr_obj->ovly_nid].uuid =
+ *uuid_obj;
+ DBC_REQUIRE(obj_def.obj_data.node_obj.ndb_props.
+ ac_name);
+ len =
+ strlen(obj_def.obj_data.node_obj.ndb_props.ac_name);
+ node_name = obj_def.obj_data.node_obj.ndb_props.ac_name;
+ pbuf = kzalloc(len + 1, GFP_KERNEL);
+ if (pbuf == NULL) {
+ status = -ENOMEM;
+ } else {
+ strncpy(pbuf, node_name, len);
+ nldr_obj->ovly_table[nldr_obj->ovly_nid].
+ node_name = pbuf;
+ nldr_obj->ovly_nid++;
+ }
+ }
+ }
+ /* These were allocated in dcd_get_object_def */
+ kfree(obj_def.obj_data.node_obj.pstr_create_phase_fxn);
+
+ kfree(obj_def.obj_data.node_obj.pstr_execute_phase_fxn);
+
+ kfree(obj_def.obj_data.node_obj.pstr_delete_phase_fxn);
+
+ kfree(obj_def.obj_data.node_obj.pstr_i_alg_name);
+
+func_end:
+ return status;
+}
+
+/*
+ * ======== add_ovly_sect ========
+ */
+static int add_ovly_sect(struct nldr_object *nldr_obj,
+ struct ovly_sect **lst,
+ struct dbll_sect_info *sect_inf,
+ bool *exists, u32 addr, u32 bytes)
+{
+ struct ovly_sect *new_sect = NULL;
+ struct ovly_sect *last_sect;
+ struct ovly_sect *ovly_section;
+ int status = 0;
+
+ ovly_section = last_sect = *lst;
+ *exists = false;
+ while (ovly_section) {
+ /*
+ * Make sure section has not already been added. Multiple
+ * 'write' calls may be made to load the section.
+ */
+ if (ovly_section->sect_load_addr == addr) {
+ /* Already added */
+ *exists = true;
+ break;
+ }
+ last_sect = ovly_section;
+ ovly_section = ovly_section->next_sect;
+ }
+
+ if (!ovly_section) {
+ /* New section */
+ new_sect = kzalloc(sizeof(struct ovly_sect), GFP_KERNEL);
+ if (new_sect == NULL) {
+ status = -ENOMEM;
+ } else {
+ new_sect->sect_load_addr = addr;
+ new_sect->sect_run_addr = sect_inf->sect_run_addr +
+ (addr - sect_inf->sect_load_addr);
+ new_sect->size = bytes;
+ new_sect->page = sect_inf->type;
+ }
+
+ /* Add to the list */
+ if (!status) {
+ if (*lst == NULL) {
+ /* First in the list */
+ *lst = new_sect;
+ } else {
+ last_sect->next_sect = new_sect;
+ }
+ }
+ }
+
+ return status;
+}
+
+/*
+ * ======== fake_ovly_write ========
+ */
+static s32 fake_ovly_write(void *handle, u32 dsp_address, void *buf, u32 bytes,
+ s32 mtype)
+{
+ return (s32) bytes;
+}
+
+/*
+ * ======== free_sects ========
+ */
+static void free_sects(struct nldr_object *nldr_obj,
+ struct ovly_sect *phase_sects, u16 alloc_num)
+{
+ struct ovly_sect *ovly_section = phase_sects;
+ u16 i = 0;
+ bool ret;
+
+ while (ovly_section && i < alloc_num) {
+ /* 'Deallocate' */
+ /* segid - page not supported yet */
+ /* Reserved memory */
+ ret =
+ rmm_free(nldr_obj->rmm, 0, ovly_section->sect_run_addr,
+ ovly_section->size, true);
+ DBC_ASSERT(ret);
+ ovly_section = ovly_section->next_sect;
+ i++;
+ }
+}
+
+/*
+ * ======== get_symbol_value ========
+ * Find symbol in library's base image. If not there, check dependent
+ * libraries.
+ */
+static bool get_symbol_value(void *handle, void *parg, void *rmm_handle,
+ char *sym_name, struct dbll_sym_val **sym)
+{
+ struct nldr_object *nldr_obj = (struct nldr_object *)handle;
+ struct nldr_nodeobject *nldr_node_obj =
+ (struct nldr_nodeobject *)rmm_handle;
+ struct lib_node *root = (struct lib_node *)parg;
+ u16 i;
+ bool status = false;
+
+ /* check the base image */
+ status = nldr_obj->ldr_fxns.get_addr_fxn(nldr_obj->base_lib,
+ sym_name, sym);
+ if (!status)
+ status =
+ nldr_obj->ldr_fxns.get_c_addr_fxn(nldr_obj->base_lib,
+ sym_name, sym);
+
+ /*
+ * Check in root lib itself. If the library consists of
+ * multiple object files linked together, some symbols in the
+ * library may need to be resolved.
+ */
+ if (!status) {
+ status = nldr_obj->ldr_fxns.get_addr_fxn(root->lib, sym_name,
+ sym);
+ if (!status) {
+ status =
+ nldr_obj->ldr_fxns.get_c_addr_fxn(root->lib,
+ sym_name, sym);
+ }
+ }
+
+ /*
+ * Check in root lib's dependent libraries, but not dependent
+ * libraries' dependents.
+ */
+ if (!status) {
+ for (i = 0; i < root->dep_libs; i++) {
+ status =
+ nldr_obj->ldr_fxns.get_addr_fxn(root->
+ dep_libs_tree
+ [i].lib,
+ sym_name, sym);
+ if (!status) {
+ status =
+ nldr_obj->ldr_fxns.
+ get_c_addr_fxn(root->dep_libs_tree[i].lib,
+ sym_name, sym);
+ }
+ if (status) {
+ /* Symbol found */
+ break;
+ }
+ }
+ }
+ /*
+ * Check in persistent libraries
+ */
+ if (!status) {
+ for (i = 0; i < nldr_node_obj->pers_libs; i++) {
+ status =
+ nldr_obj->ldr_fxns.
+ get_addr_fxn(nldr_node_obj->pers_lib_table[i].lib,
+ sym_name, sym);
+ if (!status) {
+ status = nldr_obj->ldr_fxns.get_c_addr_fxn
+ (nldr_node_obj->pers_lib_table[i].lib,
+ sym_name, sym);
+ }
+ if (status) {
+ /* Symbol found */
+ break;
+ }
+ }
+ }
+
+ return status;
+}
+
+/*
+ * ======== load_lib ========
+ * Recursively load library and all its dependent libraries. The library
+ * we're loading is specified by a uuid.
+ */
+static int load_lib(struct nldr_nodeobject *nldr_node_obj,
+ struct lib_node *root, struct dsp_uuid uuid,
+ bool root_prstnt,
+ struct dbll_library_obj **lib_path,
+ enum nldr_phase phase, u16 depth)
+{
+ struct nldr_object *nldr_obj = nldr_node_obj->nldr_obj;
+ u16 nd_libs = 0; /* Number of dependent libraries */
+ u16 np_libs = 0; /* Number of persistent libraries */
+ u16 nd_libs_loaded = 0; /* Number of dep. libraries loaded */
+ u16 i;
+ u32 entry;
+ u32 dw_buf_size = NLDR_MAXPATHLENGTH;
+ dbll_flags flags = DBLL_SYMB | DBLL_CODE | DBLL_DATA | DBLL_DYNAMIC;
+ struct dbll_attrs new_attrs;
+ char *psz_file_name = NULL;
+ struct dsp_uuid *dep_lib_uui_ds = NULL;
+ bool *persistent_dep_libs = NULL;
+ int status = 0;
+ bool lib_status = false;
+ struct lib_node *dep_lib;
+
+ if (depth > MAXDEPTH) {
+ /* Error */
+ DBC_ASSERT(false);
+ }
+ root->lib = NULL;
+ /* Allocate a buffer for library file name of size DBL_MAXPATHLENGTH */
+ psz_file_name = kzalloc(DBLL_MAXPATHLENGTH, GFP_KERNEL);
+ if (psz_file_name == NULL)
+ status = -ENOMEM;
+
+ if (!status) {
+ /* Get the name of the library */
+ if (depth == 0) {
+ status =
+ dcd_get_library_name(nldr_node_obj->nldr_obj->
+ hdcd_mgr, &uuid, psz_file_name,
+ &dw_buf_size, phase,
+ nldr_node_obj->pf_phase_split);
+ } else {
+ /* Dependent libraries are registered with a phase */
+ status =
+ dcd_get_library_name(nldr_node_obj->nldr_obj->
+ hdcd_mgr, &uuid, psz_file_name,
+ &dw_buf_size, NLDR_NOPHASE,
+ NULL);
+ }
+ }
+ if (!status) {
+ /* Open the library, don't load symbols */
+ status =
+ nldr_obj->ldr_fxns.open_fxn(nldr_obj->dbll, psz_file_name,
+ DBLL_NOLOAD, &root->lib);
+ }
+ /* Done with file name */
+ kfree(psz_file_name);
+
+ /* Check to see if library not already loaded */
+ if (!status && root_prstnt) {
+ lib_status =
+ find_in_persistent_lib_array(nldr_node_obj, root->lib);
+ /* Close library */
+ if (lib_status) {
+ nldr_obj->ldr_fxns.close_fxn(root->lib);
+ return 0;
+ }
+ }
+ if (!status) {
+ /* Check for circular dependencies. */
+ for (i = 0; i < depth; i++) {
+ if (root->lib == lib_path[i]) {
+ /* This condition could be checked by a
+ * tool at build time. */
+ status = -EILSEQ;
+ }
+ }
+ }
+ if (!status) {
+ /* Add library to current path in dependency tree */
+ lib_path[depth] = root->lib;
+ depth++;
+ /* Get number of dependent libraries */
+ status =
+ dcd_get_num_dep_libs(nldr_node_obj->nldr_obj->hdcd_mgr,
+ &uuid, &nd_libs, &np_libs, phase);
+ }
+ DBC_ASSERT(nd_libs >= np_libs);
+ if (!status) {
+ if (!(*nldr_node_obj->pf_phase_split))
+ np_libs = 0;
+
+ /* nd_libs = #of dependent libraries */
+ root->dep_libs = nd_libs - np_libs;
+ if (nd_libs > 0) {
+ dep_lib_uui_ds = kzalloc(sizeof(struct dsp_uuid) *
+ nd_libs, GFP_KERNEL);
+ persistent_dep_libs =
+ kzalloc(sizeof(bool) * nd_libs, GFP_KERNEL);
+ if (!dep_lib_uui_ds || !persistent_dep_libs)
+ status = -ENOMEM;
+
+ if (root->dep_libs > 0) {
+ /* Allocate arrays for dependent lib UUIDs,
+ * lib nodes */
+ root->dep_libs_tree = kzalloc
+ (sizeof(struct lib_node) *
+ (root->dep_libs), GFP_KERNEL);
+ if (!(root->dep_libs_tree))
+ status = -ENOMEM;
+
+ }
+
+ if (!status) {
+ /* Get the dependent library UUIDs */
+ status =
+ dcd_get_dep_libs(nldr_node_obj->
+ nldr_obj->hdcd_mgr, &uuid,
+ nd_libs, dep_lib_uui_ds,
+ persistent_dep_libs,
+ phase);
+ }
+ }
+ }
+
+ /*
+ * Recursively load dependent libraries.
+ */
+ if (!status) {
+ for (i = 0; i < nd_libs; i++) {
+ /* If root library is NOT persistent, and dep library
+ * is, then record it. If root library IS persistent,
+ * the deplib is already included */
+ if (!root_prstnt && persistent_dep_libs[i] &&
+ *nldr_node_obj->pf_phase_split) {
+ if ((nldr_node_obj->pers_libs) >= MAXLIBS) {
+ status = -EILSEQ;
+ break;
+ }
+
+ /* Allocate library outside of phase */
+ dep_lib =
+ &nldr_node_obj->pers_lib_table
+ [nldr_node_obj->pers_libs];
+ } else {
+ if (root_prstnt)
+ persistent_dep_libs[i] = true;
+
+ /* Allocate library within phase */
+ dep_lib = &root->dep_libs_tree[nd_libs_loaded];
+ }
+
+ status = load_lib(nldr_node_obj, dep_lib,
+ dep_lib_uui_ds[i],
+ persistent_dep_libs[i], lib_path,
+ phase, depth);
+
+ if (!status) {
+ if ((status != 0) &&
+ !root_prstnt && persistent_dep_libs[i] &&
+ *nldr_node_obj->pf_phase_split) {
+ (nldr_node_obj->pers_libs)++;
+ } else {
+ if (!persistent_dep_libs[i] ||
+ !(*nldr_node_obj->pf_phase_split)) {
+ nd_libs_loaded++;
+ }
+ }
+ } else {
+ break;
+ }
+ }
+ }
+
+ /* Now we can load the root library */
+ if (!status) {
+ new_attrs = nldr_obj->ldr_attrs;
+ new_attrs.sym_arg = root;
+ new_attrs.rmm_handle = nldr_node_obj;
+ new_attrs.input_params = nldr_node_obj->priv_ref;
+ new_attrs.base_image = false;
+
+ status =
+ nldr_obj->ldr_fxns.load_fxn(root->lib, flags, &new_attrs,
+ &entry);
+ }
+
+ /*
+ * In case of failure, unload any dependent libraries that
+ * were loaded, and close the root library.
+ * (Persistent libraries are unloaded from the very top)
+ */
+ if (status) {
+ if (phase != NLDR_EXECUTE) {
+ for (i = 0; i < nldr_node_obj->pers_libs; i++)
+ unload_lib(nldr_node_obj,
+ &nldr_node_obj->pers_lib_table[i]);
+
+ nldr_node_obj->pers_libs = 0;
+ }
+ for (i = 0; i < nd_libs_loaded; i++)
+ unload_lib(nldr_node_obj, &root->dep_libs_tree[i]);
+
+ if (root->lib)
+ nldr_obj->ldr_fxns.close_fxn(root->lib);
+
+ }
+
+ /* Going up one node in the dependency tree */
+ depth--;
+
+ kfree(dep_lib_uui_ds);
+ dep_lib_uui_ds = NULL;
+
+ kfree(persistent_dep_libs);
+ persistent_dep_libs = NULL;
+
+ return status;
+}
+
+/*
+ * ======== load_ovly ========
+ */
+static int load_ovly(struct nldr_nodeobject *nldr_node_obj,
+ enum nldr_phase phase)
+{
+ struct nldr_object *nldr_obj = nldr_node_obj->nldr_obj;
+ struct ovly_node *po_node = NULL;
+ struct ovly_sect *phase_sects = NULL;
+ struct ovly_sect *other_sects_list = NULL;
+ u16 i;
+ u16 alloc_num = 0;
+ u16 other_alloc = 0;
+ u16 *ref_count = NULL;
+ u16 *other_ref = NULL;
+ u32 bytes;
+ struct ovly_sect *ovly_section;
+ int status = 0;
+
+ /* Find the node in the table */
+ for (i = 0; i < nldr_obj->ovly_nodes; i++) {
+ if (is_equal_uuid
+ (&nldr_node_obj->uuid, &nldr_obj->ovly_table[i].uuid)) {
+ /* Found it */
+ po_node = &(nldr_obj->ovly_table[i]);
+ break;
+ }
+ }
+
+ DBC_ASSERT(i < nldr_obj->ovly_nodes);
+
+ if (!po_node) {
+ status = -ENOENT;
+ goto func_end;
+ }
+
+ switch (phase) {
+ case NLDR_CREATE:
+ ref_count = &(po_node->create_ref);
+ other_ref = &(po_node->other_ref);
+ phase_sects = po_node->create_sects_list;
+ other_sects_list = po_node->other_sects_list;
+ break;
+
+ case NLDR_EXECUTE:
+ ref_count = &(po_node->execute_ref);
+ phase_sects = po_node->execute_sects_list;
+ break;
+
+ case NLDR_DELETE:
+ ref_count = &(po_node->delete_ref);
+ phase_sects = po_node->delete_sects_list;
+ break;
+
+ default:
+ DBC_ASSERT(false);
+ break;
+ }
+
+ if (ref_count == NULL)
+ goto func_end;
+
+ if (*ref_count != 0)
+ goto func_end;
+
+ /* 'Allocate' memory for overlay sections of this phase */
+ ovly_section = phase_sects;
+ while (ovly_section) {
+ /* allocate *//* page not supported yet */
+ /* reserve *//* align */
+ status = rmm_alloc(nldr_obj->rmm, 0, ovly_section->size, 0,
+ &(ovly_section->sect_run_addr), true);
+ if (!status) {
+ ovly_section = ovly_section->next_sect;
+ alloc_num++;
+ } else {
+ break;
+ }
+ }
+ if (other_ref && *other_ref == 0) {
+ /* 'Allocate' memory for other overlay sections
+ * (create phase) */
+ if (!status) {
+ ovly_section = other_sects_list;
+ while (ovly_section) {
+ /* page not supported *//* align */
+ /* reserve */
+ status =
+ rmm_alloc(nldr_obj->rmm, 0,
+ ovly_section->size, 0,
+ &(ovly_section->sect_run_addr),
+ true);
+ if (!status) {
+ ovly_section = ovly_section->next_sect;
+ other_alloc++;
+ } else {
+ break;
+ }
+ }
+ }
+ }
+ if (*ref_count == 0) {
+ if (!status) {
+ /* Load sections for this phase */
+ ovly_section = phase_sects;
+ while (ovly_section && !status) {
+ bytes =
+ (*nldr_obj->ovly_fxn) (nldr_node_obj->
+ priv_ref,
+ ovly_section->
+ sect_run_addr,
+ ovly_section->
+ sect_load_addr,
+ ovly_section->size,
+ ovly_section->page);
+ if (bytes != ovly_section->size)
+ status = -EPERM;
+
+ ovly_section = ovly_section->next_sect;
+ }
+ }
+ }
+ if (other_ref && *other_ref == 0) {
+ if (!status) {
+ /* Load other sections (create phase) */
+ ovly_section = other_sects_list;
+ while (ovly_section && !status) {
+ bytes =
+ (*nldr_obj->ovly_fxn) (nldr_node_obj->
+ priv_ref,
+ ovly_section->
+ sect_run_addr,
+ ovly_section->
+ sect_load_addr,
+ ovly_section->size,
+ ovly_section->page);
+ if (bytes != ovly_section->size)
+ status = -EPERM;
+
+ ovly_section = ovly_section->next_sect;
+ }
+ }
+ }
+ if (status) {
+ /* 'Deallocate' memory */
+ free_sects(nldr_obj, phase_sects, alloc_num);
+ free_sects(nldr_obj, other_sects_list, other_alloc);
+ }
+func_end:
+ if (!status && (ref_count != NULL)) {
+ *ref_count += 1;
+ if (other_ref)
+ *other_ref += 1;
+
+ }
+
+ return status;
+}
+
+/*
+ * ======== remote_alloc ========
+ */
+static int remote_alloc(void **ref, u16 mem_sect, u32 size,
+ u32 align, u32 *dsp_address,
+ s32 segmnt_id, s32 req,
+ bool reserve)
+{
+ struct nldr_nodeobject *hnode = (struct nldr_nodeobject *)ref;
+ struct nldr_object *nldr_obj;
+ struct rmm_target_obj *rmm;
+ u16 mem_phase_bit = MAXFLAGS;
+ u16 segid = 0;
+ u16 i;
+ u16 mem_sect_type;
+ u32 word_size;
+ struct rmm_addr *rmm_addr_obj = (struct rmm_addr *)dsp_address;
+ bool mem_load_req = false;
+ int status = -ENOMEM; /* Set to fail */
+ DBC_REQUIRE(hnode);
+ DBC_REQUIRE(mem_sect == DBLL_CODE || mem_sect == DBLL_DATA ||
+ mem_sect == DBLL_BSS);
+ nldr_obj = hnode->nldr_obj;
+ rmm = nldr_obj->rmm;
+ /* Convert size to DSP words */
+ word_size =
+ (size + nldr_obj->us_dsp_word_size -
+ 1) / nldr_obj->us_dsp_word_size;
+ /* Modify memory 'align' to account for DSP cache line size */
+ align = find_lcm(GEM_CACHE_LINE_SIZE, align);
+ dev_dbg(bridge, "%s: memory align to 0x%x\n", __func__, align);
+ if (segmnt_id != -1) {
+ rmm_addr_obj->segid = segmnt_id;
+ segid = segmnt_id;
+ mem_load_req = req;
+ } else {
+ switch (hnode->phase) {
+ case NLDR_CREATE:
+ mem_phase_bit = CREATEDATAFLAGBIT;
+ break;
+ case NLDR_DELETE:
+ mem_phase_bit = DELETEDATAFLAGBIT;
+ break;
+ case NLDR_EXECUTE:
+ mem_phase_bit = EXECUTEDATAFLAGBIT;
+ break;
+ default:
+ DBC_ASSERT(false);
+ break;
+ }
+ if (mem_sect == DBLL_CODE)
+ mem_phase_bit++;
+
+ if (mem_phase_bit < MAXFLAGS)
+ segid = hnode->seg_id[mem_phase_bit];
+
+ /* Determine if there is a memory loading requirement */
+ if ((hnode->code_data_flag_mask >> mem_phase_bit) & 0x1)
+ mem_load_req = true;
+
+ }
+ mem_sect_type = (mem_sect == DBLL_CODE) ? DYNM_CODE : DYNM_DATA;
+
+ /* Find an appropriate segment based on mem_sect */
+ if (segid == NULLID) {
+ /* No memory requirements of preferences */
+ DBC_ASSERT(!mem_load_req);
+ goto func_cont;
+ }
+ if (segid <= MAXSEGID) {
+ DBC_ASSERT(segid < nldr_obj->dload_segs);
+ /* Attempt to allocate from segid first. */
+ rmm_addr_obj->segid = segid;
+ status =
+ rmm_alloc(rmm, segid, word_size, align, dsp_address, false);
+ if (status) {
+ dev_dbg(bridge, "%s: Unable allocate from segment %d\n",
+ __func__, segid);
+ }
+ } else {
+ /* segid > MAXSEGID ==> Internal or external memory */
+ DBC_ASSERT(segid == MEMINTERNALID || segid == MEMEXTERNALID);
+ /* Check for any internal or external memory segment,
+ * depending on segid. */
+ mem_sect_type |= segid == MEMINTERNALID ?
+ DYNM_INTERNAL : DYNM_EXTERNAL;
+ for (i = 0; i < nldr_obj->dload_segs; i++) {
+ if ((nldr_obj->seg_table[i] & mem_sect_type) !=
+ mem_sect_type)
+ continue;
+
+ status = rmm_alloc(rmm, i, word_size, align,
+ dsp_address, false);
+ if (!status) {
+ /* Save segid for freeing later */
+ rmm_addr_obj->segid = i;
+ break;
+ }
+ }
+ }
+func_cont:
+ /* Haven't found memory yet, attempt to find any segment that works */
+ if (status == -ENOMEM && !mem_load_req) {
+ dev_dbg(bridge, "%s: Preferred segment unavailable, trying "
+ "another\n", __func__);
+ for (i = 0; i < nldr_obj->dload_segs; i++) {
+ /* All bits of mem_sect_type must be set */
+ if ((nldr_obj->seg_table[i] & mem_sect_type) !=
+ mem_sect_type)
+ continue;
+
+ status = rmm_alloc(rmm, i, word_size, align,
+ dsp_address, false);
+ if (!status) {
+ /* Save segid */
+ rmm_addr_obj->segid = i;
+ break;
+ }
+ }
+ }
+
+ return status;
+}
+
+static int remote_free(void **ref, u16 space, u32 dsp_address,
+ u32 size, bool reserve)
+{
+ struct nldr_object *nldr_obj = (struct nldr_object *)ref;
+ struct rmm_target_obj *rmm;
+ u32 word_size;
+ int status = -ENOMEM; /* Set to fail */
+
+ DBC_REQUIRE(nldr_obj);
+
+ rmm = nldr_obj->rmm;
+
+ /* Convert size to DSP words */
+ word_size =
+ (size + nldr_obj->us_dsp_word_size -
+ 1) / nldr_obj->us_dsp_word_size;
+
+ if (rmm_free(rmm, space, dsp_address, word_size, reserve))
+ status = 0;
+
+ return status;
+}
+
+/*
+ * ======== unload_lib ========
+ */
+static void unload_lib(struct nldr_nodeobject *nldr_node_obj,
+ struct lib_node *root)
+{
+ struct dbll_attrs new_attrs;
+ struct nldr_object *nldr_obj = nldr_node_obj->nldr_obj;
+ u16 i;
+
+ DBC_ASSERT(root != NULL);
+
+ /* Unload dependent libraries */
+ for (i = 0; i < root->dep_libs; i++)
+ unload_lib(nldr_node_obj, &root->dep_libs_tree[i]);
+
+ root->dep_libs = 0;
+
+ new_attrs = nldr_obj->ldr_attrs;
+ new_attrs.rmm_handle = nldr_obj->rmm;
+ new_attrs.input_params = nldr_node_obj->priv_ref;
+ new_attrs.base_image = false;
+ new_attrs.sym_arg = root;
+
+ if (root->lib) {
+ /* Unload the root library */
+ nldr_obj->ldr_fxns.unload_fxn(root->lib, &new_attrs);
+ nldr_obj->ldr_fxns.close_fxn(root->lib);
+ }
+
+ /* Free dependent library list */
+ kfree(root->dep_libs_tree);
+ root->dep_libs_tree = NULL;
+}
+
+/*
+ * ======== unload_ovly ========
+ */
+static void unload_ovly(struct nldr_nodeobject *nldr_node_obj,
+ enum nldr_phase phase)
+{
+ struct nldr_object *nldr_obj = nldr_node_obj->nldr_obj;
+ struct ovly_node *po_node = NULL;
+ struct ovly_sect *phase_sects = NULL;
+ struct ovly_sect *other_sects_list = NULL;
+ u16 i;
+ u16 alloc_num = 0;
+ u16 other_alloc = 0;
+ u16 *ref_count = NULL;
+ u16 *other_ref = NULL;
+
+ /* Find the node in the table */
+ for (i = 0; i < nldr_obj->ovly_nodes; i++) {
+ if (is_equal_uuid
+ (&nldr_node_obj->uuid, &nldr_obj->ovly_table[i].uuid)) {
+ /* Found it */
+ po_node = &(nldr_obj->ovly_table[i]);
+ break;
+ }
+ }
+
+ DBC_ASSERT(i < nldr_obj->ovly_nodes);
+
+ if (!po_node)
+ /* TODO: Should we print warning here? */
+ return;
+
+ switch (phase) {
+ case NLDR_CREATE:
+ ref_count = &(po_node->create_ref);
+ phase_sects = po_node->create_sects_list;
+ alloc_num = po_node->create_sects;
+ break;
+ case NLDR_EXECUTE:
+ ref_count = &(po_node->execute_ref);
+ phase_sects = po_node->execute_sects_list;
+ alloc_num = po_node->execute_sects;
+ break;
+ case NLDR_DELETE:
+ ref_count = &(po_node->delete_ref);
+ other_ref = &(po_node->other_ref);
+ phase_sects = po_node->delete_sects_list;
+ /* 'Other' overlay sections are unloaded in the delete phase */
+ other_sects_list = po_node->other_sects_list;
+ alloc_num = po_node->delete_sects;
+ other_alloc = po_node->other_sects;
+ break;
+ default:
+ DBC_ASSERT(false);
+ break;
+ }
+ DBC_ASSERT(ref_count && (*ref_count > 0));
+ if (ref_count && (*ref_count > 0)) {
+ *ref_count -= 1;
+ if (other_ref) {
+ DBC_ASSERT(*other_ref > 0);
+ *other_ref -= 1;
+ }
+ }
+
+ if (ref_count && *ref_count == 0) {
+ /* 'Deallocate' memory */
+ free_sects(nldr_obj, phase_sects, alloc_num);
+ }
+ if (other_ref && *other_ref == 0)
+ free_sects(nldr_obj, other_sects_list, other_alloc);
+}
+
+/*
+ * ======== find_in_persistent_lib_array ========
+ */
+static bool find_in_persistent_lib_array(struct nldr_nodeobject *nldr_node_obj,
+ struct dbll_library_obj *lib)
+{
+ s32 i = 0;
+
+ for (i = 0; i < nldr_node_obj->pers_libs; i++) {
+ if (lib == nldr_node_obj->pers_lib_table[i].lib)
+ return true;
+
+ }
+
+ return false;
+}
+
+/*
+ * ================ Find LCM (Least Common Multiplier ===
+ */
+static u32 find_lcm(u32 a, u32 b)
+{
+ u32 ret;
+
+ ret = a * b / gcd(a, b);
+
+ return ret;
+}
+
+#ifdef CONFIG_TIDSPBRIDGE_BACKTRACE
+/**
+ * nldr_find_addr() - Find the closest symbol to the given address based on
+ * dynamic node object.
+ *
+ * @nldr_node: Dynamic node object
+ * @sym_addr: Given address to find the dsp symbol
+ * @offset_range: offset range to look for dsp symbol
+ * @offset_output: Symbol Output address
+ * @sym_name: String with the dsp symbol
+ *
+ * This function finds the node library for a given address and
+ * retrieves the dsp symbol by calling dbll_find_dsp_symbol.
+ */
+int nldr_find_addr(struct nldr_nodeobject *nldr_node, u32 sym_addr,
+ u32 offset_range, void *offset_output, char *sym_name)
+{
+ int status = 0;
+ bool status1 = false;
+ s32 i = 0;
+ struct lib_node root = { NULL, 0, NULL };
+ DBC_REQUIRE(refs > 0);
+ DBC_REQUIRE(offset_output != NULL);
+ DBC_REQUIRE(sym_name != NULL);
+ pr_debug("%s(0x%x, 0x%x, 0x%x, 0x%x, %s)\n", __func__, (u32) nldr_node,
+ sym_addr, offset_range, (u32) offset_output, sym_name);
+
+ if (nldr_node->dynamic && *nldr_node->pf_phase_split) {
+ switch (nldr_node->phase) {
+ case NLDR_CREATE:
+ root = nldr_node->create_lib;
+ break;
+ case NLDR_EXECUTE:
+ root = nldr_node->execute_lib;
+ break;
+ case NLDR_DELETE:
+ root = nldr_node->delete_lib;
+ break;
+ default:
+ DBC_ASSERT(false);
+ break;
+ }
+ } else {
+ /* for Overlay nodes or non-split Dynamic nodes */
+ root = nldr_node->root;
+ }
+
+ status1 = dbll_find_dsp_symbol(root.lib, sym_addr,
+ offset_range, offset_output, sym_name);
+
+ /* If symbol not found, check dependent libraries */
+ if (!status1)
+ for (i = 0; i < root.dep_libs; i++) {
+ status1 = dbll_find_dsp_symbol(
+ root.dep_libs_tree[i].lib, sym_addr,
+ offset_range, offset_output, sym_name);
+ if (status1)
+ /* Symbol found */
+ break;
+ }
+ /* Check persistent libraries */
+ if (!status1)
+ for (i = 0; i < nldr_node->pers_libs; i++) {
+ status1 = dbll_find_dsp_symbol(
+ nldr_node->pers_lib_table[i].lib, sym_addr,
+ offset_range, offset_output, sym_name);
+ if (status1)
+ /* Symbol found */
+ break;
+ }
+
+ if (!status1) {
+ pr_debug("%s: Address 0x%x not found in range %d.\n",
+ __func__, sym_addr, offset_range);
+ status = -ESPIPE;
+ }
+
+ return status;
+}
+#endif
diff --git a/drivers/staging/tidspbridge/rmgr/node.c b/drivers/staging/tidspbridge/rmgr/node.c
new file mode 100644
index 00000000000..6e9441e2126
--- /dev/null
+++ b/drivers/staging/tidspbridge/rmgr/node.c
@@ -0,0 +1,3234 @@
+/*
+ * node.c
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * DSP/BIOS Bridge Node Manager.
+ *
+ * Copyright (C) 2005-2006 Texas Instruments, Inc.
+ *
+ * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include <linux/types.h>
+/* ----------------------------------- Host OS */
+#include <dspbridge/host_os.h>
+
+/* ----------------------------------- DSP/BIOS Bridge */
+#include <dspbridge/dbdefs.h>
+
+/* ----------------------------------- Trace & Debug */
+#include <dspbridge/dbc.h>
+
+/* ----------------------------------- OS Adaptation Layer */
+#include <dspbridge/cfg.h>
+#include <dspbridge/list.h>
+#include <dspbridge/memdefs.h>
+#include <dspbridge/proc.h>
+#include <dspbridge/strm.h>
+#include <dspbridge/sync.h>
+#include <dspbridge/ntfy.h>
+
+/* ----------------------------------- Platform Manager */
+#include <dspbridge/cmm.h>
+#include <dspbridge/cod.h>
+#include <dspbridge/dev.h>
+#include <dspbridge/msg.h>
+
+/* ----------------------------------- Resource Manager */
+#include <dspbridge/dbdcd.h>
+#include <dspbridge/disp.h>
+#include <dspbridge/rms_sh.h>
+
+/* ----------------------------------- Link Driver */
+#include <dspbridge/dspdefs.h>
+#include <dspbridge/dspioctl.h>
+
+/* ----------------------------------- Others */
+#include <dspbridge/gb.h>
+#include <dspbridge/uuidutil.h>
+
+/* ----------------------------------- This */
+#include <dspbridge/nodepriv.h>
+#include <dspbridge/node.h>
+#include <dspbridge/dmm.h>
+
+/* Static/Dynamic Loader includes */
+#include <dspbridge/dbll.h>
+#include <dspbridge/nldr.h>
+
+#include <dspbridge/drv.h>
+#include <dspbridge/drvdefs.h>
+#include <dspbridge/resourcecleanup.h>
+#include <_tiomap.h>
+
+#include <dspbridge/dspdeh.h>
+
+#define HOSTPREFIX "/host"
+#define PIPEPREFIX "/dbpipe"
+
+#define MAX_INPUTS(h) \
+ ((h)->dcd_props.obj_data.node_obj.ndb_props.num_input_streams)
+#define MAX_OUTPUTS(h) \
+ ((h)->dcd_props.obj_data.node_obj.ndb_props.num_output_streams)
+
+#define NODE_GET_PRIORITY(h) ((h)->prio)
+#define NODE_SET_PRIORITY(hnode, prio) ((hnode)->prio = prio)
+#define NODE_SET_STATE(hnode, state) ((hnode)->node_state = state)
+
+#define MAXPIPES 100 /* Max # of /pipe connections (CSL limit) */
+#define MAXDEVSUFFIXLEN 2 /* Max(Log base 10 of MAXPIPES, MAXSTREAMS) */
+
+#define PIPENAMELEN (sizeof(PIPEPREFIX) + MAXDEVSUFFIXLEN)
+#define HOSTNAMELEN (sizeof(HOSTPREFIX) + MAXDEVSUFFIXLEN)
+
+#define MAXDEVNAMELEN 32 /* dsp_ndbprops.ac_name size */
+#define CREATEPHASE 1
+#define EXECUTEPHASE 2
+#define DELETEPHASE 3
+
+/* Define default STRM parameters */
+/*
+ * TBD: Put in header file, make global DSP_STRMATTRS with defaults,
+ * or make defaults configurable.
+ */
+#define DEFAULTBUFSIZE 32
+#define DEFAULTNBUFS 2
+#define DEFAULTSEGID 0
+#define DEFAULTALIGNMENT 0
+#define DEFAULTTIMEOUT 10000
+
+#define RMSQUERYSERVER 0
+#define RMSCONFIGURESERVER 1
+#define RMSCREATENODE 2
+#define RMSEXECUTENODE 3
+#define RMSDELETENODE 4
+#define RMSCHANGENODEPRIORITY 5
+#define RMSREADMEMORY 6
+#define RMSWRITEMEMORY 7
+#define RMSCOPY 8
+#define MAXTIMEOUT 2000
+
+#define NUMRMSFXNS 9
+
+#define PWR_TIMEOUT 500 /* default PWR timeout in msec */
+
+#define STACKSEGLABEL "L1DSRAM_HEAP" /* Label for DSP Stack Segment Addr */
+
+/*
+ * ======== node_mgr ========
+ */
+struct node_mgr {
+ struct dev_object *hdev_obj; /* Device object */
+ /* Function interface to Bridge driver */
+ struct bridge_drv_interface *intf_fxns;
+ struct dcd_manager *hdcd_mgr; /* Proc/Node data manager */
+ struct disp_object *disp_obj; /* Node dispatcher */
+ struct lst_list *node_list; /* List of all allocated nodes */
+ u32 num_nodes; /* Number of nodes in node_list */
+ u32 num_created; /* Number of nodes *created* on DSP */
+ struct gb_t_map *pipe_map; /* Pipe connection bit map */
+ struct gb_t_map *pipe_done_map; /* Pipes that are half free */
+ struct gb_t_map *chnl_map; /* Channel allocation bit map */
+ struct gb_t_map *dma_chnl_map; /* DMA Channel allocation bit map */
+ struct gb_t_map *zc_chnl_map; /* Zero-Copy Channel alloc bit map */
+ struct ntfy_object *ntfy_obj; /* Manages registered notifications */
+ struct mutex node_mgr_lock; /* For critical sections */
+ u32 ul_fxn_addrs[NUMRMSFXNS]; /* RMS function addresses */
+ struct msg_mgr *msg_mgr_obj;
+
+ /* Processor properties needed by Node Dispatcher */
+ u32 ul_num_chnls; /* Total number of channels */
+ u32 ul_chnl_offset; /* Offset of chnl ids rsvd for RMS */
+ u32 ul_chnl_buf_size; /* Buffer size for data to RMS */
+ int proc_family; /* eg, 5000 */
+ int proc_type; /* eg, 5510 */
+ u32 udsp_word_size; /* Size of DSP word on host bytes */
+ u32 udsp_data_mau_size; /* Size of DSP data MAU */
+ u32 udsp_mau_size; /* Size of MAU */
+ s32 min_pri; /* Minimum runtime priority for node */
+ s32 max_pri; /* Maximum runtime priority for node */
+
+ struct strm_mgr *strm_mgr_obj; /* STRM manager */
+
+ /* Loader properties */
+ struct nldr_object *nldr_obj; /* Handle to loader */
+ struct node_ldr_fxns nldr_fxns; /* Handle to loader functions */
+ bool loader_init; /* Loader Init function succeeded? */
+};
+
+/*
+ * ======== connecttype ========
+ */
+enum connecttype {
+ NOTCONNECTED = 0,
+ NODECONNECT,
+ HOSTCONNECT,
+ DEVICECONNECT,
+};
+
+/*
+ * ======== stream_chnl ========
+ */
+struct stream_chnl {
+ enum connecttype type; /* Type of stream connection */
+ u32 dev_id; /* pipe or channel id */
+};
+
+/*
+ * ======== node_object ========
+ */
+struct node_object {
+ struct list_head list_elem;
+ struct node_mgr *hnode_mgr; /* The manager of this node */
+ struct proc_object *hprocessor; /* Back pointer to processor */
+ struct dsp_uuid node_uuid; /* Node's ID */
+ s32 prio; /* Node's current priority */
+ u32 utimeout; /* Timeout for blocking NODE calls */
+ u32 heap_size; /* Heap Size */
+ u32 udsp_heap_virt_addr; /* Heap Size */
+ u32 ugpp_heap_virt_addr; /* Heap Size */
+ enum node_type ntype; /* Type of node: message, task, etc */
+ enum node_state node_state; /* NODE_ALLOCATED, NODE_CREATED, ... */
+ u32 num_inputs; /* Current number of inputs */
+ u32 num_outputs; /* Current number of outputs */
+ u32 max_input_index; /* Current max input stream index */
+ u32 max_output_index; /* Current max output stream index */
+ struct stream_chnl *inputs; /* Node's input streams */
+ struct stream_chnl *outputs; /* Node's output streams */
+ struct node_createargs create_args; /* Args for node create func */
+ nodeenv node_env; /* Environment returned by RMS */
+ struct dcd_genericobj dcd_props; /* Node properties from DCD */
+ struct dsp_cbdata *pargs; /* Optional args to pass to node */
+ struct ntfy_object *ntfy_obj; /* Manages registered notifications */
+ char *pstr_dev_name; /* device name, if device node */
+ struct sync_object *sync_done; /* Synchronize node_terminate */
+ s32 exit_status; /* execute function return status */
+
+ /* Information needed for node_get_attr() */
+ void *device_owner; /* If dev node, task that owns it */
+ u32 num_gpp_inputs; /* Current # of from GPP streams */
+ u32 num_gpp_outputs; /* Current # of to GPP streams */
+ /* Current stream connections */
+ struct dsp_streamconnect *stream_connect;
+
+ /* Message queue */
+ struct msg_queue *msg_queue_obj;
+
+ /* These fields used for SM messaging */
+ struct cmm_xlatorobject *xlator; /* Node's SM addr translator */
+
+ /* Handle to pass to dynamic loader */
+ struct nldr_nodeobject *nldr_node_obj;
+ bool loaded; /* Code is (dynamically) loaded */
+ bool phase_split; /* Phases split in many libs or ovly */
+
+};
+
+/* Default buffer attributes */
+static struct dsp_bufferattr node_dfltbufattrs = {
+ 0, /* cb_struct */
+ 1, /* segment_id */
+ 0, /* buf_alignment */
+};
+
+static void delete_node(struct node_object *hnode,
+ struct process_context *pr_ctxt);
+static void delete_node_mgr(struct node_mgr *hnode_mgr);
+static void fill_stream_connect(struct node_object *node1,
+ struct node_object *node2, u32 stream1,
+ u32 stream2);
+static void fill_stream_def(struct node_object *hnode,
+ struct node_strmdef *pstrm_def,
+ struct dsp_strmattr *pattrs);
+static void free_stream(struct node_mgr *hnode_mgr, struct stream_chnl stream);
+static int get_fxn_address(struct node_object *hnode, u32 * fxn_addr,
+ u32 phase);
+static int get_node_props(struct dcd_manager *hdcd_mgr,
+ struct node_object *hnode,
+ const struct dsp_uuid *node_uuid,
+ struct dcd_genericobj *dcd_prop);
+static int get_proc_props(struct node_mgr *hnode_mgr,
+ struct dev_object *hdev_obj);
+static int get_rms_fxns(struct node_mgr *hnode_mgr);
+static u32 ovly(void *priv_ref, u32 dsp_run_addr, u32 dsp_load_addr,
+ u32 ul_num_bytes, u32 mem_space);
+static u32 mem_write(void *priv_ref, u32 dsp_add, void *pbuf,
+ u32 ul_num_bytes, u32 mem_space);
+
+static u32 refs; /* module reference count */
+
+/* Dynamic loader functions. */
+static struct node_ldr_fxns nldr_fxns = {
+ nldr_allocate,
+ nldr_create,
+ nldr_delete,
+ nldr_exit,
+ nldr_get_fxn_addr,
+ nldr_init,
+ nldr_load,
+ nldr_unload,
+};
+
+enum node_state node_get_state(void *hnode)
+{
+ struct node_object *pnode = (struct node_object *)hnode;
+ if (!pnode)
+ return -1;
+ else
+ return pnode->node_state;
+}
+
+/*
+ * ======== node_allocate ========
+ * Purpose:
+ * Allocate GPP resources to manage a node on the DSP.
+ */
+int node_allocate(struct proc_object *hprocessor,
+ const struct dsp_uuid *node_uuid,
+ const struct dsp_cbdata *pargs,
+ const struct dsp_nodeattrin *attr_in,
+ struct node_res_object **noderes,
+ struct process_context *pr_ctxt)
+{
+ struct node_mgr *hnode_mgr;
+ struct dev_object *hdev_obj;
+ struct node_object *pnode = NULL;
+ enum node_type node_type = NODE_TASK;
+ struct node_msgargs *pmsg_args;
+ struct node_taskargs *ptask_args;
+ u32 num_streams;
+ struct bridge_drv_interface *intf_fxns;
+ int status = 0;
+ struct cmm_object *hcmm_mgr = NULL; /* Shared memory manager hndl */
+ u32 proc_id;
+ u32 pul_value;
+ u32 dynext_base;
+ u32 off_set = 0;
+ u32 ul_stack_seg_addr, ul_stack_seg_val;
+ u32 ul_gpp_mem_base;
+ struct cfg_hostres *host_res;
+ struct bridge_dev_context *pbridge_context;
+ u32 mapped_addr = 0;
+ u32 map_attrs = 0x0;
+ struct dsp_processorstate proc_state;
+#ifdef DSP_DMM_DEBUG
+ struct dmm_object *dmm_mgr;
+ struct proc_object *p_proc_object = (struct proc_object *)hprocessor;
+#endif
+
+ void *node_res;
+
+ DBC_REQUIRE(refs > 0);
+ DBC_REQUIRE(hprocessor != NULL);
+ DBC_REQUIRE(noderes != NULL);
+ DBC_REQUIRE(node_uuid != NULL);
+
+ *noderes = NULL;
+
+ status = proc_get_processor_id(hprocessor, &proc_id);
+
+ if (proc_id != DSP_UNIT)
+ goto func_end;
+
+ status = proc_get_dev_object(hprocessor, &hdev_obj);
+ if (!status) {
+ status = dev_get_node_manager(hdev_obj, &hnode_mgr);
+ if (hnode_mgr == NULL)
+ status = -EPERM;
+
+ }
+
+ if (status)
+ goto func_end;
+
+ status = dev_get_bridge_context(hdev_obj, &pbridge_context);
+ if (!pbridge_context) {
+ status = -EFAULT;
+ goto func_end;
+ }
+
+ status = proc_get_state(hprocessor, &proc_state,
+ sizeof(struct dsp_processorstate));
+ if (status)
+ goto func_end;
+ /* If processor is in error state then don't attempt
+ to send the message */
+ if (proc_state.proc_state == PROC_ERROR) {
+ status = -EPERM;
+ goto func_end;
+ }
+
+ /* Assuming that 0 is not a valid function address */
+ if (hnode_mgr->ul_fxn_addrs[0] == 0) {
+ /* No RMS on target - we currently can't handle this */
+ pr_err("%s: Failed, no RMS in base image\n", __func__);
+ status = -EPERM;
+ } else {
+ /* Validate attr_in fields, if non-NULL */
+ if (attr_in) {
+ /* Check if attr_in->prio is within range */
+ if (attr_in->prio < hnode_mgr->min_pri ||
+ attr_in->prio > hnode_mgr->max_pri)
+ status = -EDOM;
+ }
+ }
+ /* Allocate node object and fill in */
+ if (status)
+ goto func_end;
+
+ pnode = kzalloc(sizeof(struct node_object), GFP_KERNEL);
+ if (pnode == NULL) {
+ status = -ENOMEM;
+ goto func_end;
+ }
+ pnode->hnode_mgr = hnode_mgr;
+ /* This critical section protects get_node_props */
+ mutex_lock(&hnode_mgr->node_mgr_lock);
+
+ /* Get dsp_ndbprops from node database */
+ status = get_node_props(hnode_mgr->hdcd_mgr, pnode, node_uuid,
+ &(pnode->dcd_props));
+ if (status)
+ goto func_cont;
+
+ pnode->node_uuid = *node_uuid;
+ pnode->hprocessor = hprocessor;
+ pnode->ntype = pnode->dcd_props.obj_data.node_obj.ndb_props.ntype;
+ pnode->utimeout = pnode->dcd_props.obj_data.node_obj.ndb_props.utimeout;
+ pnode->prio = pnode->dcd_props.obj_data.node_obj.ndb_props.prio;
+
+ /* Currently only C64 DSP builds support Node Dynamic * heaps */
+ /* Allocate memory for node heap */
+ pnode->create_args.asa.task_arg_obj.heap_size = 0;
+ pnode->create_args.asa.task_arg_obj.udsp_heap_addr = 0;
+ pnode->create_args.asa.task_arg_obj.udsp_heap_res_addr = 0;
+ pnode->create_args.asa.task_arg_obj.ugpp_heap_addr = 0;
+ if (!attr_in)
+ goto func_cont;
+
+ /* Check if we have a user allocated node heap */
+ if (!(attr_in->pgpp_virt_addr))
+ goto func_cont;
+
+ /* check for page aligned Heap size */
+ if (((attr_in->heap_size) & (PG_SIZE4K - 1))) {
+ pr_err("%s: node heap size not aligned to 4K, size = 0x%x \n",
+ __func__, attr_in->heap_size);
+ status = -EINVAL;
+ } else {
+ pnode->create_args.asa.task_arg_obj.heap_size =
+ attr_in->heap_size;
+ pnode->create_args.asa.task_arg_obj.ugpp_heap_addr =
+ (u32) attr_in->pgpp_virt_addr;
+ }
+ if (status)
+ goto func_cont;
+
+ status = proc_reserve_memory(hprocessor,
+ pnode->create_args.asa.task_arg_obj.
+ heap_size + PAGE_SIZE,
+ (void **)&(pnode->create_args.asa.
+ task_arg_obj.udsp_heap_res_addr),
+ pr_ctxt);
+ if (status) {
+ pr_err("%s: Failed to reserve memory for heap: 0x%x\n",
+ __func__, status);
+ goto func_cont;
+ }
+#ifdef DSP_DMM_DEBUG
+ status = dmm_get_handle(p_proc_object, &dmm_mgr);
+ if (!dmm_mgr) {
+ status = DSP_EHANDLE;
+ goto func_cont;
+ }
+
+ dmm_mem_map_dump(dmm_mgr);
+#endif
+
+ map_attrs |= DSP_MAPLITTLEENDIAN;
+ map_attrs |= DSP_MAPELEMSIZE32;
+ map_attrs |= DSP_MAPVIRTUALADDR;
+ status = proc_map(hprocessor, (void *)attr_in->pgpp_virt_addr,
+ pnode->create_args.asa.task_arg_obj.heap_size,
+ (void *)pnode->create_args.asa.task_arg_obj.
+ udsp_heap_res_addr, (void **)&mapped_addr, map_attrs,
+ pr_ctxt);
+ if (status)
+ pr_err("%s: Failed to map memory for Heap: 0x%x\n",
+ __func__, status);
+ else
+ pnode->create_args.asa.task_arg_obj.udsp_heap_addr =
+ (u32) mapped_addr;
+
+func_cont:
+ mutex_unlock(&hnode_mgr->node_mgr_lock);
+ if (attr_in != NULL) {
+ /* Overrides of NBD properties */
+ pnode->utimeout = attr_in->utimeout;
+ pnode->prio = attr_in->prio;
+ }
+ /* Create object to manage notifications */
+ if (!status) {
+ pnode->ntfy_obj = kmalloc(sizeof(struct ntfy_object),
+ GFP_KERNEL);
+ if (pnode->ntfy_obj)
+ ntfy_init(pnode->ntfy_obj);
+ else
+ status = -ENOMEM;
+ }
+
+ if (!status) {
+ node_type = node_get_type(pnode);
+ /* Allocate dsp_streamconnect array for device, task, and
+ * dais socket nodes. */
+ if (node_type != NODE_MESSAGE) {
+ num_streams = MAX_INPUTS(pnode) + MAX_OUTPUTS(pnode);
+ pnode->stream_connect = kzalloc(num_streams *
+ sizeof(struct dsp_streamconnect),
+ GFP_KERNEL);
+ if (num_streams > 0 && pnode->stream_connect == NULL)
+ status = -ENOMEM;
+
+ }
+ if (!status && (node_type == NODE_TASK ||
+ node_type == NODE_DAISSOCKET)) {
+ /* Allocate arrays for maintainig stream connections */
+ pnode->inputs = kzalloc(MAX_INPUTS(pnode) *
+ sizeof(struct stream_chnl), GFP_KERNEL);
+ pnode->outputs = kzalloc(MAX_OUTPUTS(pnode) *
+ sizeof(struct stream_chnl), GFP_KERNEL);
+ ptask_args = &(pnode->create_args.asa.task_arg_obj);
+ ptask_args->strm_in_def = kzalloc(MAX_INPUTS(pnode) *
+ sizeof(struct node_strmdef),
+ GFP_KERNEL);
+ ptask_args->strm_out_def = kzalloc(MAX_OUTPUTS(pnode) *
+ sizeof(struct node_strmdef),
+ GFP_KERNEL);
+ if ((MAX_INPUTS(pnode) > 0 && (pnode->inputs == NULL ||
+ ptask_args->strm_in_def
+ == NULL))
+ || (MAX_OUTPUTS(pnode) > 0
+ && (pnode->outputs == NULL
+ || ptask_args->strm_out_def == NULL)))
+ status = -ENOMEM;
+ }
+ }
+ if (!status && (node_type != NODE_DEVICE)) {
+ /* Create an event that will be posted when RMS_EXIT is
+ * received. */
+ pnode->sync_done = kzalloc(sizeof(struct sync_object),
+ GFP_KERNEL);
+ if (pnode->sync_done)
+ sync_init_event(pnode->sync_done);
+ else
+ status = -ENOMEM;
+
+ if (!status) {
+ /*Get the shared mem mgr for this nodes dev object */
+ status = cmm_get_handle(hprocessor, &hcmm_mgr);
+ if (!status) {
+ /* Allocate a SM addr translator for this node
+ * w/ deflt attr */
+ status = cmm_xlator_create(&pnode->xlator,
+ hcmm_mgr, NULL);
+ }
+ }
+ if (!status) {
+ /* Fill in message args */
+ if ((pargs != NULL) && (pargs->cb_data > 0)) {
+ pmsg_args =
+ &(pnode->create_args.asa.node_msg_args);
+ pmsg_args->pdata = kzalloc(pargs->cb_data,
+ GFP_KERNEL);
+ if (pmsg_args->pdata == NULL) {
+ status = -ENOMEM;
+ } else {
+ pmsg_args->arg_length = pargs->cb_data;
+ memcpy(pmsg_args->pdata,
+ pargs->node_data,
+ pargs->cb_data);
+ }
+ }
+ }
+ }
+
+ if (!status && node_type != NODE_DEVICE) {
+ /* Create a message queue for this node */
+ intf_fxns = hnode_mgr->intf_fxns;
+ status =
+ (*intf_fxns->pfn_msg_create_queue) (hnode_mgr->msg_mgr_obj,
+ &pnode->msg_queue_obj,
+ 0,
+ pnode->create_args.asa.
+ node_msg_args.max_msgs,
+ pnode);
+ }
+
+ if (!status) {
+ /* Create object for dynamic loading */
+
+ status = hnode_mgr->nldr_fxns.pfn_allocate(hnode_mgr->nldr_obj,
+ (void *)pnode,
+ &pnode->dcd_props.
+ obj_data.node_obj,
+ &pnode->
+ nldr_node_obj,
+ &pnode->phase_split);
+ }
+
+ /* Compare value read from Node Properties and check if it is same as
+ * STACKSEGLABEL, if yes read the Address of STACKSEGLABEL, calculate
+ * GPP Address, Read the value in that address and override the
+ * stack_seg value in task args */
+ if (!status &&
+ (char *)pnode->dcd_props.obj_data.node_obj.ndb_props.
+ stack_seg_name != NULL) {
+ if (strcmp((char *)
+ pnode->dcd_props.obj_data.node_obj.ndb_props.
+ stack_seg_name, STACKSEGLABEL) == 0) {
+ status =
+ hnode_mgr->nldr_fxns.
+ pfn_get_fxn_addr(pnode->nldr_node_obj, "DYNEXT_BEG",
+ &dynext_base);
+ if (status)
+ pr_err("%s: Failed to get addr for DYNEXT_BEG"
+ " status = 0x%x\n", __func__, status);
+
+ status =
+ hnode_mgr->nldr_fxns.
+ pfn_get_fxn_addr(pnode->nldr_node_obj,
+ "L1DSRAM_HEAP", &pul_value);
+
+ if (status)
+ pr_err("%s: Failed to get addr for L1DSRAM_HEAP"
+ " status = 0x%x\n", __func__, status);
+
+ host_res = pbridge_context->resources;
+ if (!host_res)
+ status = -EPERM;
+
+ if (status) {
+ pr_err("%s: Failed to get host resource, status"
+ " = 0x%x\n", __func__, status);
+ goto func_end;
+ }
+
+ ul_gpp_mem_base = (u32) host_res->dw_mem_base[1];
+ off_set = pul_value - dynext_base;
+ ul_stack_seg_addr = ul_gpp_mem_base + off_set;
+ ul_stack_seg_val = readl(ul_stack_seg_addr);
+
+ dev_dbg(bridge, "%s: StackSegVal = 0x%x, StackSegAddr ="
+ " 0x%x\n", __func__, ul_stack_seg_val,
+ ul_stack_seg_addr);
+
+ pnode->create_args.asa.task_arg_obj.stack_seg =
+ ul_stack_seg_val;
+
+ }
+ }
+
+ if (!status) {
+ /* Add the node to the node manager's list of allocated
+ * nodes. */
+ lst_init_elem((struct list_head *)pnode);
+ NODE_SET_STATE(pnode, NODE_ALLOCATED);
+
+ mutex_lock(&hnode_mgr->node_mgr_lock);
+
+ lst_put_tail(hnode_mgr->node_list, (struct list_head *) pnode);
+ ++(hnode_mgr->num_nodes);
+
+ /* Exit critical section */
+ mutex_unlock(&hnode_mgr->node_mgr_lock);
+
+ /* Preset this to assume phases are split
+ * (for overlay and dll) */
+ pnode->phase_split = true;
+
+ /* Notify all clients registered for DSP_NODESTATECHANGE. */
+ proc_notify_all_clients(hprocessor, DSP_NODESTATECHANGE);
+ } else {
+ /* Cleanup */
+ if (pnode)
+ delete_node(pnode, pr_ctxt);
+
+ }
+
+ if (!status) {
+ status = drv_insert_node_res_element(pnode, &node_res, pr_ctxt);
+ if (status) {
+ delete_node(pnode, pr_ctxt);
+ goto func_end;
+ }
+
+ *noderes = (struct node_res_object *)node_res;
+ drv_proc_node_update_heap_status(node_res, true);
+ drv_proc_node_update_status(node_res, true);
+ }
+ DBC_ENSURE((status && *noderes == NULL) || (!status && *noderes));
+func_end:
+ dev_dbg(bridge, "%s: hprocessor: %p pNodeId: %p pargs: %p attr_in: %p "
+ "node_res: %p status: 0x%x\n", __func__, hprocessor,
+ node_uuid, pargs, attr_in, noderes, status);
+ return status;
+}
+
+/*
+ * ======== node_alloc_msg_buf ========
+ * Purpose:
+ * Allocates buffer for zero copy messaging.
+ */
+DBAPI node_alloc_msg_buf(struct node_object *hnode, u32 usize,
+ struct dsp_bufferattr *pattr,
+ u8 **pbuffer)
+{
+ struct node_object *pnode = (struct node_object *)hnode;
+ int status = 0;
+ bool va_flag = false;
+ bool set_info;
+ u32 proc_id;
+
+ DBC_REQUIRE(refs > 0);
+ DBC_REQUIRE(pbuffer != NULL);
+
+ DBC_REQUIRE(usize > 0);
+
+ if (!pnode)
+ status = -EFAULT;
+ else if (node_get_type(pnode) == NODE_DEVICE)
+ status = -EPERM;
+
+ if (status)
+ goto func_end;
+
+ if (pattr == NULL)
+ pattr = &node_dfltbufattrs; /* set defaults */
+
+ status = proc_get_processor_id(pnode->hprocessor, &proc_id);
+ if (proc_id != DSP_UNIT) {
+ DBC_ASSERT(NULL);
+ goto func_end;
+ }
+ /* If segment ID includes MEM_SETVIRTUALSEGID then pbuffer is a
+ * virt address, so set this info in this node's translator
+ * object for future ref. If MEM_GETVIRTUALSEGID then retrieve
+ * virtual address from node's translator. */
+ if ((pattr->segment_id & MEM_SETVIRTUALSEGID) ||
+ (pattr->segment_id & MEM_GETVIRTUALSEGID)) {
+ va_flag = true;
+ set_info = (pattr->segment_id & MEM_SETVIRTUALSEGID) ?
+ true : false;
+ /* Clear mask bits */
+ pattr->segment_id &= ~MEM_MASKVIRTUALSEGID;
+ /* Set/get this node's translators virtual address base/size */
+ status = cmm_xlator_info(pnode->xlator, pbuffer, usize,
+ pattr->segment_id, set_info);
+ }
+ if (!status && (!va_flag)) {
+ if (pattr->segment_id != 1) {
+ /* Node supports single SM segment only. */
+ status = -EBADR;
+ }
+ /* Arbitrary SM buffer alignment not supported for host side
+ * allocs, but guaranteed for the following alignment
+ * values. */
+ switch (pattr->buf_alignment) {
+ case 0:
+ case 1:
+ case 2:
+ case 4:
+ break;
+ default:
+ /* alignment value not suportted */
+ status = -EPERM;
+ break;
+ }
+ if (!status) {
+ /* allocate physical buffer from seg_id in node's
+ * translator */
+ (void)cmm_xlator_alloc_buf(pnode->xlator, pbuffer,
+ usize);
+ if (*pbuffer == NULL) {
+ pr_err("%s: error - Out of shared memory\n",
+ __func__);
+ status = -ENOMEM;
+ }
+ }
+ }
+func_end:
+ return status;
+}
+
+/*
+ * ======== node_change_priority ========
+ * Purpose:
+ * Change the priority of a node in the allocated state, or that is
+ * currently running or paused on the target.
+ */
+int node_change_priority(struct node_object *hnode, s32 prio)
+{
+ struct node_object *pnode = (struct node_object *)hnode;
+ struct node_mgr *hnode_mgr = NULL;
+ enum node_type node_type;
+ enum node_state state;
+ int status = 0;
+ u32 proc_id;
+
+ DBC_REQUIRE(refs > 0);
+
+ if (!hnode || !hnode->hnode_mgr) {
+ status = -EFAULT;
+ } else {
+ hnode_mgr = hnode->hnode_mgr;
+ node_type = node_get_type(hnode);
+ if (node_type != NODE_TASK && node_type != NODE_DAISSOCKET)
+ status = -EPERM;
+ else if (prio < hnode_mgr->min_pri || prio > hnode_mgr->max_pri)
+ status = -EDOM;
+ }
+ if (status)
+ goto func_end;
+
+ /* Enter critical section */
+ mutex_lock(&hnode_mgr->node_mgr_lock);
+
+ state = node_get_state(hnode);
+ if (state == NODE_ALLOCATED || state == NODE_PAUSED) {
+ NODE_SET_PRIORITY(hnode, prio);
+ } else {
+ if (state != NODE_RUNNING) {
+ status = -EBADR;
+ goto func_cont;
+ }
+ status = proc_get_processor_id(pnode->hprocessor, &proc_id);
+ if (proc_id == DSP_UNIT) {
+ status =
+ disp_node_change_priority(hnode_mgr->disp_obj,
+ hnode,
+ hnode_mgr->ul_fxn_addrs
+ [RMSCHANGENODEPRIORITY],
+ hnode->node_env, prio);
+ }
+ if (status >= 0)
+ NODE_SET_PRIORITY(hnode, prio);
+
+ }
+func_cont:
+ /* Leave critical section */
+ mutex_unlock(&hnode_mgr->node_mgr_lock);
+func_end:
+ return status;
+}
+
+/*
+ * ======== node_connect ========
+ * Purpose:
+ * Connect two nodes on the DSP, or a node on the DSP to the GPP.
+ */
+int node_connect(struct node_object *node1, u32 stream1,
+ struct node_object *node2,
+ u32 stream2, struct dsp_strmattr *pattrs,
+ struct dsp_cbdata *conn_param)
+{
+ struct node_mgr *hnode_mgr;
+ char *pstr_dev_name = NULL;
+ enum node_type node1_type = NODE_TASK;
+ enum node_type node2_type = NODE_TASK;
+ struct node_strmdef *pstrm_def;
+ struct node_strmdef *input = NULL;
+ struct node_strmdef *output = NULL;
+ struct node_object *dev_node_obj;
+ struct node_object *hnode;
+ struct stream_chnl *pstream;
+ u32 pipe_id = GB_NOBITS;
+ u32 chnl_id = GB_NOBITS;
+ s8 chnl_mode;
+ u32 dw_length;
+ int status = 0;
+ DBC_REQUIRE(refs > 0);
+
+ if ((node1 != (struct node_object *)DSP_HGPPNODE && !node1) ||
+ (node2 != (struct node_object *)DSP_HGPPNODE && !node2))
+ status = -EFAULT;
+
+ if (!status) {
+ /* The two nodes must be on the same processor */
+ if (node1 != (struct node_object *)DSP_HGPPNODE &&
+ node2 != (struct node_object *)DSP_HGPPNODE &&
+ node1->hnode_mgr != node2->hnode_mgr)
+ status = -EPERM;
+ /* Cannot connect a node to itself */
+ if (node1 == node2)
+ status = -EPERM;
+
+ }
+ if (!status) {
+ /* node_get_type() will return NODE_GPP if hnode =
+ * DSP_HGPPNODE. */
+ node1_type = node_get_type(node1);
+ node2_type = node_get_type(node2);
+ /* Check stream indices ranges */
+ if ((node1_type != NODE_GPP && node1_type != NODE_DEVICE &&
+ stream1 >= MAX_OUTPUTS(node1)) || (node2_type != NODE_GPP
+ && node2_type !=
+ NODE_DEVICE
+ && stream2 >=
+ MAX_INPUTS(node2)))
+ status = -EINVAL;
+ }
+ if (!status) {
+ /*
+ * Only the following types of connections are allowed:
+ * task/dais socket < == > task/dais socket
+ * task/dais socket < == > device
+ * task/dais socket < == > GPP
+ *
+ * ie, no message nodes, and at least one task or dais
+ * socket node.
+ */
+ if (node1_type == NODE_MESSAGE || node2_type == NODE_MESSAGE ||
+ (node1_type != NODE_TASK && node1_type != NODE_DAISSOCKET &&
+ node2_type != NODE_TASK && node2_type != NODE_DAISSOCKET))
+ status = -EPERM;
+ }
+ /*
+ * Check stream mode. Default is STRMMODE_PROCCOPY.
+ */
+ if (!status && pattrs) {
+ if (pattrs->strm_mode != STRMMODE_PROCCOPY)
+ status = -EPERM; /* illegal stream mode */
+
+ }
+ if (status)
+ goto func_end;
+
+ if (node1_type != NODE_GPP) {
+ hnode_mgr = node1->hnode_mgr;
+ } else {
+ DBC_ASSERT(node2 != (struct node_object *)DSP_HGPPNODE);
+ hnode_mgr = node2->hnode_mgr;
+ }
+ /* Enter critical section */
+ mutex_lock(&hnode_mgr->node_mgr_lock);
+
+ /* Nodes must be in the allocated state */
+ if (node1_type != NODE_GPP && node_get_state(node1) != NODE_ALLOCATED)
+ status = -EBADR;
+
+ if (node2_type != NODE_GPP && node_get_state(node2) != NODE_ALLOCATED)
+ status = -EBADR;
+
+ if (!status) {
+ /* Check that stream indices for task and dais socket nodes
+ * are not already be used. (Device nodes checked later) */
+ if (node1_type == NODE_TASK || node1_type == NODE_DAISSOCKET) {
+ output =
+ &(node1->create_args.asa.
+ task_arg_obj.strm_out_def[stream1]);
+ if (output->sz_device != NULL)
+ status = -EISCONN;
+
+ }
+ if (node2_type == NODE_TASK || node2_type == NODE_DAISSOCKET) {
+ input =
+ &(node2->create_args.asa.
+ task_arg_obj.strm_in_def[stream2]);
+ if (input->sz_device != NULL)
+ status = -EISCONN;
+
+ }
+ }
+ /* Connecting two task nodes? */
+ if (!status && ((node1_type == NODE_TASK ||
+ node1_type == NODE_DAISSOCKET)
+ && (node2_type == NODE_TASK
+ || node2_type == NODE_DAISSOCKET))) {
+ /* Find available pipe */
+ pipe_id = gb_findandset(hnode_mgr->pipe_map);
+ if (pipe_id == GB_NOBITS) {
+ status = -ECONNREFUSED;
+ } else {
+ node1->outputs[stream1].type = NODECONNECT;
+ node2->inputs[stream2].type = NODECONNECT;
+ node1->outputs[stream1].dev_id = pipe_id;
+ node2->inputs[stream2].dev_id = pipe_id;
+ output->sz_device = kzalloc(PIPENAMELEN + 1,
+ GFP_KERNEL);
+ input->sz_device = kzalloc(PIPENAMELEN + 1, GFP_KERNEL);
+ if (output->sz_device == NULL ||
+ input->sz_device == NULL) {
+ /* Undo the connection */
+ kfree(output->sz_device);
+
+ kfree(input->sz_device);
+
+ output->sz_device = NULL;
+ input->sz_device = NULL;
+ gb_clear(hnode_mgr->pipe_map, pipe_id);
+ status = -ENOMEM;
+ } else {
+ /* Copy "/dbpipe<pipId>" name to device names */
+ sprintf(output->sz_device, "%s%d",
+ PIPEPREFIX, pipe_id);
+ strcpy(input->sz_device, output->sz_device);
+ }
+ }
+ }
+ /* Connecting task node to host? */
+ if (!status && (node1_type == NODE_GPP ||
+ node2_type == NODE_GPP)) {
+ if (node1_type == NODE_GPP) {
+ chnl_mode = CHNL_MODETODSP;
+ } else {
+ DBC_ASSERT(node2_type == NODE_GPP);
+ chnl_mode = CHNL_MODEFROMDSP;
+ }
+ /* Reserve a channel id. We need to put the name "/host<id>"
+ * in the node's create_args, but the host
+ * side channel will not be opened until DSPStream_Open is
+ * called for this node. */
+ if (pattrs) {
+ if (pattrs->strm_mode == STRMMODE_RDMA) {
+ chnl_id =
+ gb_findandset(hnode_mgr->dma_chnl_map);
+ /* dma chans are 2nd transport chnl set
+ * ids(e.g. 16-31) */
+ (chnl_id != GB_NOBITS) ?
+ (chnl_id =
+ chnl_id +
+ hnode_mgr->ul_num_chnls) : chnl_id;
+ } else if (pattrs->strm_mode == STRMMODE_ZEROCOPY) {
+ chnl_id = gb_findandset(hnode_mgr->zc_chnl_map);
+ /* zero-copy chans are 3nd transport set
+ * (e.g. 32-47) */
+ (chnl_id != GB_NOBITS) ? (chnl_id = chnl_id +
+ (2 *
+ hnode_mgr->
+ ul_num_chnls))
+ : chnl_id;
+ } else { /* must be PROCCOPY */
+ DBC_ASSERT(pattrs->strm_mode ==
+ STRMMODE_PROCCOPY);
+ chnl_id = gb_findandset(hnode_mgr->chnl_map);
+ /* e.g. 0-15 */
+ }
+ } else {
+ /* default to PROCCOPY */
+ chnl_id = gb_findandset(hnode_mgr->chnl_map);
+ }
+ if (chnl_id == GB_NOBITS) {
+ status = -ECONNREFUSED;
+ goto func_cont2;
+ }
+ pstr_dev_name = kzalloc(HOSTNAMELEN + 1, GFP_KERNEL);
+ if (pstr_dev_name != NULL)
+ goto func_cont2;
+
+ if (pattrs) {
+ if (pattrs->strm_mode == STRMMODE_RDMA) {
+ gb_clear(hnode_mgr->dma_chnl_map, chnl_id -
+ hnode_mgr->ul_num_chnls);
+ } else if (pattrs->strm_mode == STRMMODE_ZEROCOPY) {
+ gb_clear(hnode_mgr->zc_chnl_map, chnl_id -
+ (2 * hnode_mgr->ul_num_chnls));
+ } else {
+ DBC_ASSERT(pattrs->strm_mode ==
+ STRMMODE_PROCCOPY);
+ gb_clear(hnode_mgr->chnl_map, chnl_id);
+ }
+ } else {
+ gb_clear(hnode_mgr->chnl_map, chnl_id);
+ }
+ status = -ENOMEM;
+func_cont2:
+ if (!status) {
+ if (node1 == (struct node_object *)DSP_HGPPNODE) {
+ node2->inputs[stream2].type = HOSTCONNECT;
+ node2->inputs[stream2].dev_id = chnl_id;
+ input->sz_device = pstr_dev_name;
+ } else {
+ node1->outputs[stream1].type = HOSTCONNECT;
+ node1->outputs[stream1].dev_id = chnl_id;
+ output->sz_device = pstr_dev_name;
+ }
+ sprintf(pstr_dev_name, "%s%d", HOSTPREFIX, chnl_id);
+ }
+ }
+ /* Connecting task node to device node? */
+ if (!status && ((node1_type == NODE_DEVICE) ||
+ (node2_type == NODE_DEVICE))) {
+ if (node2_type == NODE_DEVICE) {
+ /* node1 == > device */
+ dev_node_obj = node2;
+ hnode = node1;
+ pstream = &(node1->outputs[stream1]);
+ pstrm_def = output;
+ } else {
+ /* device == > node2 */
+ dev_node_obj = node1;
+ hnode = node2;
+ pstream = &(node2->inputs[stream2]);
+ pstrm_def = input;
+ }
+ /* Set up create args */
+ pstream->type = DEVICECONNECT;
+ dw_length = strlen(dev_node_obj->pstr_dev_name);
+ if (conn_param != NULL) {
+ pstrm_def->sz_device = kzalloc(dw_length + 1 +
+ conn_param->cb_data,
+ GFP_KERNEL);
+ } else {
+ pstrm_def->sz_device = kzalloc(dw_length + 1,
+ GFP_KERNEL);
+ }
+ if (pstrm_def->sz_device == NULL) {
+ status = -ENOMEM;
+ } else {
+ /* Copy device name */
+ strncpy(pstrm_def->sz_device,
+ dev_node_obj->pstr_dev_name, dw_length);
+ if (conn_param != NULL) {
+ strncat(pstrm_def->sz_device,
+ (char *)conn_param->node_data,
+ (u32) conn_param->cb_data);
+ }
+ dev_node_obj->device_owner = hnode;
+ }
+ }
+ if (!status) {
+ /* Fill in create args */
+ if (node1_type == NODE_TASK || node1_type == NODE_DAISSOCKET) {
+ node1->create_args.asa.task_arg_obj.num_outputs++;
+ fill_stream_def(node1, output, pattrs);
+ }
+ if (node2_type == NODE_TASK || node2_type == NODE_DAISSOCKET) {
+ node2->create_args.asa.task_arg_obj.num_inputs++;
+ fill_stream_def(node2, input, pattrs);
+ }
+ /* Update node1 and node2 stream_connect */
+ if (node1_type != NODE_GPP && node1_type != NODE_DEVICE) {
+ node1->num_outputs++;
+ if (stream1 > node1->max_output_index)
+ node1->max_output_index = stream1;
+
+ }
+ if (node2_type != NODE_GPP && node2_type != NODE_DEVICE) {
+ node2->num_inputs++;
+ if (stream2 > node2->max_input_index)
+ node2->max_input_index = stream2;
+
+ }
+ fill_stream_connect(node1, node2, stream1, stream2);
+ }
+ /* end of sync_enter_cs */
+ /* Exit critical section */
+ mutex_unlock(&hnode_mgr->node_mgr_lock);
+func_end:
+ dev_dbg(bridge, "%s: node1: %p stream1: %d node2: %p stream2: %d"
+ "pattrs: %p status: 0x%x\n", __func__, node1,
+ stream1, node2, stream2, pattrs, status);
+ return status;
+}
+
+/*
+ * ======== node_create ========
+ * Purpose:
+ * Create a node on the DSP by remotely calling the node's create function.
+ */
+int node_create(struct node_object *hnode)
+{
+ struct node_object *pnode = (struct node_object *)hnode;
+ struct node_mgr *hnode_mgr;
+ struct bridge_drv_interface *intf_fxns;
+ u32 ul_create_fxn;
+ enum node_type node_type;
+ int status = 0;
+ int status1 = 0;
+ struct dsp_cbdata cb_data;
+ u32 proc_id = 255;
+ struct dsp_processorstate proc_state;
+ struct proc_object *hprocessor;
+#if defined(CONFIG_TIDSPBRIDGE_DVFS) && !defined(CONFIG_CPU_FREQ)
+ struct dspbridge_platform_data *pdata =
+ omap_dspbridge_dev->dev.platform_data;
+#endif
+
+ DBC_REQUIRE(refs > 0);
+ if (!pnode) {
+ status = -EFAULT;
+ goto func_end;
+ }
+ hprocessor = hnode->hprocessor;
+ status = proc_get_state(hprocessor, &proc_state,
+ sizeof(struct dsp_processorstate));
+ if (status)
+ goto func_end;
+ /* If processor is in error state then don't attempt to create
+ new node */
+ if (proc_state.proc_state == PROC_ERROR) {
+ status = -EPERM;
+ goto func_end;
+ }
+ /* create struct dsp_cbdata struct for PWR calls */
+ cb_data.cb_data = PWR_TIMEOUT;
+ node_type = node_get_type(hnode);
+ hnode_mgr = hnode->hnode_mgr;
+ intf_fxns = hnode_mgr->intf_fxns;
+ /* Get access to node dispatcher */
+ mutex_lock(&hnode_mgr->node_mgr_lock);
+
+ /* Check node state */
+ if (node_get_state(hnode) != NODE_ALLOCATED)
+ status = -EBADR;
+
+ if (!status)
+ status = proc_get_processor_id(pnode->hprocessor, &proc_id);
+
+ if (status)
+ goto func_cont2;
+
+ if (proc_id != DSP_UNIT)
+ goto func_cont2;
+
+ /* Make sure streams are properly connected */
+ if ((hnode->num_inputs && hnode->max_input_index >
+ hnode->num_inputs - 1) ||
+ (hnode->num_outputs && hnode->max_output_index >
+ hnode->num_outputs - 1))
+ status = -ENOTCONN;
+
+ if (!status) {
+ /* If node's create function is not loaded, load it */
+ /* Boost the OPP level to max level that DSP can be requested */
+#if defined(CONFIG_TIDSPBRIDGE_DVFS) && !defined(CONFIG_CPU_FREQ)
+ if (pdata->cpu_set_freq)
+ (*pdata->cpu_set_freq) (pdata->mpu_speed[VDD1_OPP3]);
+#endif
+ status = hnode_mgr->nldr_fxns.pfn_load(hnode->nldr_node_obj,
+ NLDR_CREATE);
+ /* Get address of node's create function */
+ if (!status) {
+ hnode->loaded = true;
+ if (node_type != NODE_DEVICE) {
+ status = get_fxn_address(hnode, &ul_create_fxn,
+ CREATEPHASE);
+ }
+ } else {
+ pr_err("%s: failed to load create code: 0x%x\n",
+ __func__, status);
+ }
+ /* Request the lowest OPP level */
+#if defined(CONFIG_TIDSPBRIDGE_DVFS) && !defined(CONFIG_CPU_FREQ)
+ if (pdata->cpu_set_freq)
+ (*pdata->cpu_set_freq) (pdata->mpu_speed[VDD1_OPP1]);
+#endif
+ /* Get address of iAlg functions, if socket node */
+ if (!status) {
+ if (node_type == NODE_DAISSOCKET) {
+ status = hnode_mgr->nldr_fxns.pfn_get_fxn_addr
+ (hnode->nldr_node_obj,
+ hnode->dcd_props.obj_data.node_obj.
+ pstr_i_alg_name,
+ &hnode->create_args.asa.
+ task_arg_obj.ul_dais_arg);
+ }
+ }
+ }
+ if (!status) {
+ if (node_type != NODE_DEVICE) {
+ status = disp_node_create(hnode_mgr->disp_obj, hnode,
+ hnode_mgr->ul_fxn_addrs
+ [RMSCREATENODE],
+ ul_create_fxn,
+ &(hnode->create_args),
+ &(hnode->node_env));
+ if (status >= 0) {
+ /* Set the message queue id to the node env
+ * pointer */
+ intf_fxns = hnode_mgr->intf_fxns;
+ (*intf_fxns->pfn_msg_set_queue_id) (hnode->
+ msg_queue_obj,
+ hnode->node_env);
+ }
+ }
+ }
+ /* Phase II/Overlays: Create, execute, delete phases possibly in
+ * different files/sections. */
+ if (hnode->loaded && hnode->phase_split) {
+ /* If create code was dynamically loaded, we can now unload
+ * it. */
+ status1 = hnode_mgr->nldr_fxns.pfn_unload(hnode->nldr_node_obj,
+ NLDR_CREATE);
+ hnode->loaded = false;
+ }
+ if (status1)
+ pr_err("%s: Failed to unload create code: 0x%x\n",
+ __func__, status1);
+func_cont2:
+ /* Update node state and node manager state */
+ if (status >= 0) {
+ NODE_SET_STATE(hnode, NODE_CREATED);
+ hnode_mgr->num_created++;
+ goto func_cont;
+ }
+ if (status != -EBADR) {
+ /* Put back in NODE_ALLOCATED state if error occurred */
+ NODE_SET_STATE(hnode, NODE_ALLOCATED);
+ }
+func_cont:
+ /* Free access to node dispatcher */
+ mutex_unlock(&hnode_mgr->node_mgr_lock);
+func_end:
+ if (status >= 0) {
+ proc_notify_clients(hnode->hprocessor, DSP_NODESTATECHANGE);
+ ntfy_notify(hnode->ntfy_obj, DSP_NODESTATECHANGE);
+ }
+
+ dev_dbg(bridge, "%s: hnode: %p status: 0x%x\n", __func__,
+ hnode, status);
+ return status;
+}
+
+/*
+ * ======== node_create_mgr ========
+ * Purpose:
+ * Create a NODE Manager object.
+ */
+int node_create_mgr(struct node_mgr **node_man,
+ struct dev_object *hdev_obj)
+{
+ u32 i;
+ struct node_mgr *node_mgr_obj = NULL;
+ struct disp_attr disp_attr_obj;
+ char *sz_zl_file = "";
+ struct nldr_attrs nldr_attrs_obj;
+ int status = 0;
+ u8 dev_type;
+ DBC_REQUIRE(refs > 0);
+ DBC_REQUIRE(node_man != NULL);
+ DBC_REQUIRE(hdev_obj != NULL);
+
+ *node_man = NULL;
+ /* Allocate Node manager object */
+ node_mgr_obj = kzalloc(sizeof(struct node_mgr), GFP_KERNEL);
+ if (node_mgr_obj) {
+ node_mgr_obj->hdev_obj = hdev_obj;
+ node_mgr_obj->node_list = kzalloc(sizeof(struct lst_list),
+ GFP_KERNEL);
+ node_mgr_obj->pipe_map = gb_create(MAXPIPES);
+ node_mgr_obj->pipe_done_map = gb_create(MAXPIPES);
+ if (node_mgr_obj->node_list == NULL
+ || node_mgr_obj->pipe_map == NULL
+ || node_mgr_obj->pipe_done_map == NULL) {
+ status = -ENOMEM;
+ } else {
+ INIT_LIST_HEAD(&node_mgr_obj->node_list->head);
+ node_mgr_obj->ntfy_obj = kmalloc(
+ sizeof(struct ntfy_object), GFP_KERNEL);
+ if (node_mgr_obj->ntfy_obj)
+ ntfy_init(node_mgr_obj->ntfy_obj);
+ else
+ status = -ENOMEM;
+ }
+ node_mgr_obj->num_created = 0;
+ } else {
+ status = -ENOMEM;
+ }
+ /* get devNodeType */
+ if (!status)
+ status = dev_get_dev_type(hdev_obj, &dev_type);
+
+ /* Create the DCD Manager */
+ if (!status) {
+ status =
+ dcd_create_manager(sz_zl_file, &node_mgr_obj->hdcd_mgr);
+ if (!status)
+ status = get_proc_props(node_mgr_obj, hdev_obj);
+
+ }
+ /* Create NODE Dispatcher */
+ if (!status) {
+ disp_attr_obj.ul_chnl_offset = node_mgr_obj->ul_chnl_offset;
+ disp_attr_obj.ul_chnl_buf_size = node_mgr_obj->ul_chnl_buf_size;
+ disp_attr_obj.proc_family = node_mgr_obj->proc_family;
+ disp_attr_obj.proc_type = node_mgr_obj->proc_type;
+ status =
+ disp_create(&node_mgr_obj->disp_obj, hdev_obj,
+ &disp_attr_obj);
+ }
+ /* Create a STRM Manager */
+ if (!status)
+ status = strm_create(&node_mgr_obj->strm_mgr_obj, hdev_obj);
+
+ if (!status) {
+ dev_get_intf_fxns(hdev_obj, &node_mgr_obj->intf_fxns);
+ /* Get msg_ctrl queue manager */
+ dev_get_msg_mgr(hdev_obj, &node_mgr_obj->msg_mgr_obj);
+ mutex_init(&node_mgr_obj->node_mgr_lock);
+ node_mgr_obj->chnl_map = gb_create(node_mgr_obj->ul_num_chnls);
+ /* dma chnl map. ul_num_chnls is # per transport */
+ node_mgr_obj->dma_chnl_map =
+ gb_create(node_mgr_obj->ul_num_chnls);
+ node_mgr_obj->zc_chnl_map =
+ gb_create(node_mgr_obj->ul_num_chnls);
+ if ((node_mgr_obj->chnl_map == NULL)
+ || (node_mgr_obj->dma_chnl_map == NULL)
+ || (node_mgr_obj->zc_chnl_map == NULL)) {
+ status = -ENOMEM;
+ } else {
+ /* Block out reserved channels */
+ for (i = 0; i < node_mgr_obj->ul_chnl_offset; i++)
+ gb_set(node_mgr_obj->chnl_map, i);
+
+ /* Block out channels reserved for RMS */
+ gb_set(node_mgr_obj->chnl_map,
+ node_mgr_obj->ul_chnl_offset);
+ gb_set(node_mgr_obj->chnl_map,
+ node_mgr_obj->ul_chnl_offset + 1);
+ }
+ }
+ if (!status) {
+ /* NO RM Server on the IVA */
+ if (dev_type != IVA_UNIT) {
+ /* Get addresses of any RMS functions loaded */
+ status = get_rms_fxns(node_mgr_obj);
+ }
+ }
+
+ /* Get loader functions and create loader */
+ if (!status)
+ node_mgr_obj->nldr_fxns = nldr_fxns; /* Dyn loader funcs */
+
+ if (!status) {
+ nldr_attrs_obj.pfn_ovly = ovly;
+ nldr_attrs_obj.pfn_write = mem_write;
+ nldr_attrs_obj.us_dsp_word_size = node_mgr_obj->udsp_word_size;
+ nldr_attrs_obj.us_dsp_mau_size = node_mgr_obj->udsp_mau_size;
+ node_mgr_obj->loader_init = node_mgr_obj->nldr_fxns.pfn_init();
+ status =
+ node_mgr_obj->nldr_fxns.pfn_create(&node_mgr_obj->nldr_obj,
+ hdev_obj,
+ &nldr_attrs_obj);
+ }
+ if (!status)
+ *node_man = node_mgr_obj;
+ else
+ delete_node_mgr(node_mgr_obj);
+
+ DBC_ENSURE((status && *node_man == NULL) || (!status && *node_man));
+
+ return status;
+}
+
+/*
+ * ======== node_delete ========
+ * Purpose:
+ * Delete a node on the DSP by remotely calling the node's delete function.
+ * Loads the node's delete function if necessary. Free GPP side resources
+ * after node's delete function returns.
+ */
+int node_delete(struct node_res_object *noderes,
+ struct process_context *pr_ctxt)
+{
+ struct node_object *pnode = noderes->hnode;
+ struct node_mgr *hnode_mgr;
+ struct proc_object *hprocessor;
+ struct disp_object *disp_obj;
+ u32 ul_delete_fxn;
+ enum node_type node_type;
+ enum node_state state;
+ int status = 0;
+ int status1 = 0;
+ struct dsp_cbdata cb_data;
+ u32 proc_id;
+ struct bridge_drv_interface *intf_fxns;
+
+ void *node_res = noderes;
+
+ struct dsp_processorstate proc_state;
+ DBC_REQUIRE(refs > 0);
+
+ if (!pnode) {
+ status = -EFAULT;
+ goto func_end;
+ }
+ /* create struct dsp_cbdata struct for PWR call */
+ cb_data.cb_data = PWR_TIMEOUT;
+ hnode_mgr = pnode->hnode_mgr;
+ hprocessor = pnode->hprocessor;
+ disp_obj = hnode_mgr->disp_obj;
+ node_type = node_get_type(pnode);
+ intf_fxns = hnode_mgr->intf_fxns;
+ /* Enter critical section */
+ mutex_lock(&hnode_mgr->node_mgr_lock);
+
+ state = node_get_state(pnode);
+ /* Execute delete phase code for non-device node in all cases
+ * except when the node was only allocated. Delete phase must be
+ * executed even if create phase was executed, but failed.
+ * If the node environment pointer is non-NULL, the delete phase
+ * code must be executed. */
+ if (!(state == NODE_ALLOCATED && pnode->node_env == (u32) NULL) &&
+ node_type != NODE_DEVICE) {
+ status = proc_get_processor_id(pnode->hprocessor, &proc_id);
+ if (status)
+ goto func_cont1;
+
+ if (proc_id == DSP_UNIT || proc_id == IVA_UNIT) {
+ /* If node has terminated, execute phase code will
+ * have already been unloaded in node_on_exit(). If the
+ * node is PAUSED, the execute phase is loaded, and it
+ * is now ok to unload it. If the node is running, we
+ * will unload the execute phase only after deleting
+ * the node. */
+ if (state == NODE_PAUSED && pnode->loaded &&
+ pnode->phase_split) {
+ /* Ok to unload execute code as long as node
+ * is not * running */
+ status1 =
+ hnode_mgr->nldr_fxns.
+ pfn_unload(pnode->nldr_node_obj,
+ NLDR_EXECUTE);
+ pnode->loaded = false;
+ NODE_SET_STATE(pnode, NODE_DONE);
+ }
+ /* Load delete phase code if not loaded or if haven't
+ * * unloaded EXECUTE phase */
+ if ((!(pnode->loaded) || (state == NODE_RUNNING)) &&
+ pnode->phase_split) {
+ status =
+ hnode_mgr->nldr_fxns.
+ pfn_load(pnode->nldr_node_obj, NLDR_DELETE);
+ if (!status)
+ pnode->loaded = true;
+ else
+ pr_err("%s: fail - load delete code:"
+ " 0x%x\n", __func__, status);
+ }
+ }
+func_cont1:
+ if (!status) {
+ /* Unblock a thread trying to terminate the node */
+ (void)sync_set_event(pnode->sync_done);
+ if (proc_id == DSP_UNIT) {
+ /* ul_delete_fxn = address of node's delete
+ * function */
+ status = get_fxn_address(pnode, &ul_delete_fxn,
+ DELETEPHASE);
+ } else if (proc_id == IVA_UNIT)
+ ul_delete_fxn = (u32) pnode->node_env;
+ if (!status) {
+ status = proc_get_state(hprocessor,
+ &proc_state,
+ sizeof(struct
+ dsp_processorstate));
+ if (proc_state.proc_state != PROC_ERROR) {
+ status =
+ disp_node_delete(disp_obj, pnode,
+ hnode_mgr->
+ ul_fxn_addrs
+ [RMSDELETENODE],
+ ul_delete_fxn,
+ pnode->node_env);
+ } else
+ NODE_SET_STATE(pnode, NODE_DONE);
+
+ /* Unload execute, if not unloaded, and delete
+ * function */
+ if (state == NODE_RUNNING &&
+ pnode->phase_split) {
+ status1 =
+ hnode_mgr->nldr_fxns.
+ pfn_unload(pnode->nldr_node_obj,
+ NLDR_EXECUTE);
+ }
+ if (status1)
+ pr_err("%s: fail - unload execute code:"
+ " 0x%x\n", __func__, status1);
+
+ status1 =
+ hnode_mgr->nldr_fxns.pfn_unload(pnode->
+ nldr_node_obj,
+ NLDR_DELETE);
+ pnode->loaded = false;
+ if (status1)
+ pr_err("%s: fail - unload delete code: "
+ "0x%x\n", __func__, status1);
+ }
+ }
+ }
+ /* Free host side resources even if a failure occurred */
+ /* Remove node from hnode_mgr->node_list */
+ lst_remove_elem(hnode_mgr->node_list, (struct list_head *)pnode);
+ hnode_mgr->num_nodes--;
+ /* Decrement count of nodes created on DSP */
+ if ((state != NODE_ALLOCATED) || ((state == NODE_ALLOCATED) &&
+ (pnode->node_env != (u32) NULL)))
+ hnode_mgr->num_created--;
+ /* Free host-side resources allocated by node_create()
+ * delete_node() fails if SM buffers not freed by client! */
+ drv_proc_node_update_status(node_res, false);
+ delete_node(pnode, pr_ctxt);
+
+ /*
+ * Release all Node resources and its context
+ */
+ idr_remove(pr_ctxt->node_id, ((struct node_res_object *)node_res)->id);
+ kfree(node_res);
+
+ /* Exit critical section */
+ mutex_unlock(&hnode_mgr->node_mgr_lock);
+ proc_notify_clients(hprocessor, DSP_NODESTATECHANGE);
+func_end:
+ dev_dbg(bridge, "%s: pnode: %p status 0x%x\n", __func__, pnode, status);
+ return status;
+}
+
+/*
+ * ======== node_delete_mgr ========
+ * Purpose:
+ * Delete the NODE Manager.
+ */
+int node_delete_mgr(struct node_mgr *hnode_mgr)
+{
+ int status = 0;
+
+ DBC_REQUIRE(refs > 0);
+
+ if (hnode_mgr)
+ delete_node_mgr(hnode_mgr);
+ else
+ status = -EFAULT;
+
+ return status;
+}
+
+/*
+ * ======== node_enum_nodes ========
+ * Purpose:
+ * Enumerate currently allocated nodes.
+ */
+int node_enum_nodes(struct node_mgr *hnode_mgr, void **node_tab,
+ u32 node_tab_size, u32 *pu_num_nodes,
+ u32 *pu_allocated)
+{
+ struct node_object *hnode;
+ u32 i;
+ int status = 0;
+ DBC_REQUIRE(refs > 0);
+ DBC_REQUIRE(node_tab != NULL || node_tab_size == 0);
+ DBC_REQUIRE(pu_num_nodes != NULL);
+ DBC_REQUIRE(pu_allocated != NULL);
+
+ if (!hnode_mgr) {
+ status = -EFAULT;
+ goto func_end;
+ }
+ /* Enter critical section */
+ mutex_lock(&hnode_mgr->node_mgr_lock);
+
+ if (hnode_mgr->num_nodes > node_tab_size) {
+ *pu_allocated = hnode_mgr->num_nodes;
+ *pu_num_nodes = 0;
+ status = -EINVAL;
+ } else {
+ hnode = (struct node_object *)lst_first(hnode_mgr->
+ node_list);
+ for (i = 0; i < hnode_mgr->num_nodes; i++) {
+ DBC_ASSERT(hnode);
+ node_tab[i] = hnode;
+ hnode = (struct node_object *)lst_next
+ (hnode_mgr->node_list,
+ (struct list_head *)hnode);
+ }
+ *pu_allocated = *pu_num_nodes = hnode_mgr->num_nodes;
+ }
+ /* end of sync_enter_cs */
+ /* Exit critical section */
+ mutex_unlock(&hnode_mgr->node_mgr_lock);
+func_end:
+ return status;
+}
+
+/*
+ * ======== node_exit ========
+ * Purpose:
+ * Discontinue usage of NODE module.
+ */
+void node_exit(void)
+{
+ DBC_REQUIRE(refs > 0);
+
+ refs--;
+
+ DBC_ENSURE(refs >= 0);
+}
+
+/*
+ * ======== node_free_msg_buf ========
+ * Purpose:
+ * Frees the message buffer.
+ */
+int node_free_msg_buf(struct node_object *hnode, u8 * pbuffer,
+ struct dsp_bufferattr *pattr)
+{
+ struct node_object *pnode = (struct node_object *)hnode;
+ int status = 0;
+ u32 proc_id;
+ DBC_REQUIRE(refs > 0);
+ DBC_REQUIRE(pbuffer != NULL);
+ DBC_REQUIRE(pnode != NULL);
+ DBC_REQUIRE(pnode->xlator != NULL);
+
+ if (!hnode) {
+ status = -EFAULT;
+ goto func_end;
+ }
+ status = proc_get_processor_id(pnode->hprocessor, &proc_id);
+ if (proc_id == DSP_UNIT) {
+ if (!status) {
+ if (pattr == NULL) {
+ /* set defaults */
+ pattr = &node_dfltbufattrs;
+ }
+ /* Node supports single SM segment only */
+ if (pattr->segment_id != 1)
+ status = -EBADR;
+
+ /* pbuffer is clients Va. */
+ status = cmm_xlator_free_buf(pnode->xlator, pbuffer);
+ }
+ } else {
+ DBC_ASSERT(NULL); /* BUG */
+ }
+func_end:
+ return status;
+}
+
+/*
+ * ======== node_get_attr ========
+ * Purpose:
+ * Copy the current attributes of the specified node into a dsp_nodeattr
+ * structure.
+ */
+int node_get_attr(struct node_object *hnode,
+ struct dsp_nodeattr *pattr, u32 attr_size)
+{
+ struct node_mgr *hnode_mgr;
+ int status = 0;
+ DBC_REQUIRE(refs > 0);
+ DBC_REQUIRE(pattr != NULL);
+ DBC_REQUIRE(attr_size >= sizeof(struct dsp_nodeattr));
+
+ if (!hnode) {
+ status = -EFAULT;
+ } else {
+ hnode_mgr = hnode->hnode_mgr;
+ /* Enter hnode_mgr critical section (since we're accessing
+ * data that could be changed by node_change_priority() and
+ * node_connect(). */
+ mutex_lock(&hnode_mgr->node_mgr_lock);
+ pattr->cb_struct = sizeof(struct dsp_nodeattr);
+ /* dsp_nodeattrin */
+ pattr->in_node_attr_in.cb_struct =
+ sizeof(struct dsp_nodeattrin);
+ pattr->in_node_attr_in.prio = hnode->prio;
+ pattr->in_node_attr_in.utimeout = hnode->utimeout;
+ pattr->in_node_attr_in.heap_size =
+ hnode->create_args.asa.task_arg_obj.heap_size;
+ pattr->in_node_attr_in.pgpp_virt_addr = (void *)
+ hnode->create_args.asa.task_arg_obj.ugpp_heap_addr;
+ pattr->node_attr_inputs = hnode->num_gpp_inputs;
+ pattr->node_attr_outputs = hnode->num_gpp_outputs;
+ /* dsp_nodeinfo */
+ get_node_info(hnode, &(pattr->node_info));
+ /* end of sync_enter_cs */
+ /* Exit critical section */
+ mutex_unlock(&hnode_mgr->node_mgr_lock);
+ }
+ return status;
+}
+
+/*
+ * ======== node_get_channel_id ========
+ * Purpose:
+ * Get the channel index reserved for a stream connection between the
+ * host and a node.
+ */
+int node_get_channel_id(struct node_object *hnode, u32 dir, u32 index,
+ u32 *chan_id)
+{
+ enum node_type node_type;
+ int status = -EINVAL;
+ DBC_REQUIRE(refs > 0);
+ DBC_REQUIRE(dir == DSP_TONODE || dir == DSP_FROMNODE);
+ DBC_REQUIRE(chan_id != NULL);
+
+ if (!hnode) {
+ status = -EFAULT;
+ return status;
+ }
+ node_type = node_get_type(hnode);
+ if (node_type != NODE_TASK && node_type != NODE_DAISSOCKET) {
+ status = -EPERM;
+ return status;
+ }
+ if (dir == DSP_TONODE) {
+ if (index < MAX_INPUTS(hnode)) {
+ if (hnode->inputs[index].type == HOSTCONNECT) {
+ *chan_id = hnode->inputs[index].dev_id;
+ status = 0;
+ }
+ }
+ } else {
+ DBC_ASSERT(dir == DSP_FROMNODE);
+ if (index < MAX_OUTPUTS(hnode)) {
+ if (hnode->outputs[index].type == HOSTCONNECT) {
+ *chan_id = hnode->outputs[index].dev_id;
+ status = 0;
+ }
+ }
+ }
+ return status;
+}
+
+/*
+ * ======== node_get_message ========
+ * Purpose:
+ * Retrieve a message from a node on the DSP.
+ */
+int node_get_message(struct node_object *hnode,
+ struct dsp_msg *message, u32 utimeout)
+{
+ struct node_mgr *hnode_mgr;
+ enum node_type node_type;
+ struct bridge_drv_interface *intf_fxns;
+ int status = 0;
+ void *tmp_buf;
+ struct dsp_processorstate proc_state;
+ struct proc_object *hprocessor;
+
+ DBC_REQUIRE(refs > 0);
+ DBC_REQUIRE(message != NULL);
+
+ if (!hnode) {
+ status = -EFAULT;
+ goto func_end;
+ }
+ hprocessor = hnode->hprocessor;
+ status = proc_get_state(hprocessor, &proc_state,
+ sizeof(struct dsp_processorstate));
+ if (status)
+ goto func_end;
+ /* If processor is in error state then don't attempt to get the
+ message */
+ if (proc_state.proc_state == PROC_ERROR) {
+ status = -EPERM;
+ goto func_end;
+ }
+ hnode_mgr = hnode->hnode_mgr;
+ node_type = node_get_type(hnode);
+ if (node_type != NODE_MESSAGE && node_type != NODE_TASK &&
+ node_type != NODE_DAISSOCKET) {
+ status = -EPERM;
+ goto func_end;
+ }
+ /* This function will block unless a message is available. Since
+ * DSPNode_RegisterNotify() allows notification when a message
+ * is available, the system can be designed so that
+ * DSPNode_GetMessage() is only called when a message is
+ * available. */
+ intf_fxns = hnode_mgr->intf_fxns;
+ status =
+ (*intf_fxns->pfn_msg_get) (hnode->msg_queue_obj, message, utimeout);
+ /* Check if message contains SM descriptor */
+ if (status || !(message->dw_cmd & DSP_RMSBUFDESC))
+ goto func_end;
+
+ /* Translate DSP byte addr to GPP Va. */
+ tmp_buf = cmm_xlator_translate(hnode->xlator,
+ (void *)(message->dw_arg1 *
+ hnode->hnode_mgr->
+ udsp_word_size), CMM_DSPPA2PA);
+ if (tmp_buf != NULL) {
+ /* now convert this GPP Pa to Va */
+ tmp_buf = cmm_xlator_translate(hnode->xlator, tmp_buf,
+ CMM_PA2VA);
+ if (tmp_buf != NULL) {
+ /* Adjust SM size in msg */
+ message->dw_arg1 = (u32) tmp_buf;
+ message->dw_arg2 *= hnode->hnode_mgr->udsp_word_size;
+ } else {
+ status = -ESRCH;
+ }
+ } else {
+ status = -ESRCH;
+ }
+func_end:
+ dev_dbg(bridge, "%s: hnode: %p message: %p utimeout: 0x%x\n", __func__,
+ hnode, message, utimeout);
+ return status;
+}
+
+/*
+ * ======== node_get_nldr_obj ========
+ */
+int node_get_nldr_obj(struct node_mgr *hnode_mgr,
+ struct nldr_object **nldr_ovlyobj)
+{
+ int status = 0;
+ struct node_mgr *node_mgr_obj = hnode_mgr;
+ DBC_REQUIRE(nldr_ovlyobj != NULL);
+
+ if (!hnode_mgr)
+ status = -EFAULT;
+ else
+ *nldr_ovlyobj = node_mgr_obj->nldr_obj;
+
+ DBC_ENSURE(!status || (nldr_ovlyobj != NULL && *nldr_ovlyobj == NULL));
+ return status;
+}
+
+/*
+ * ======== node_get_strm_mgr ========
+ * Purpose:
+ * Returns the Stream manager.
+ */
+int node_get_strm_mgr(struct node_object *hnode,
+ struct strm_mgr **strm_man)
+{
+ int status = 0;
+
+ DBC_REQUIRE(refs > 0);
+
+ if (!hnode)
+ status = -EFAULT;
+ else
+ *strm_man = hnode->hnode_mgr->strm_mgr_obj;
+
+ return status;
+}
+
+/*
+ * ======== node_get_load_type ========
+ */
+enum nldr_loadtype node_get_load_type(struct node_object *hnode)
+{
+ DBC_REQUIRE(refs > 0);
+ DBC_REQUIRE(hnode);
+ if (!hnode) {
+ dev_dbg(bridge, "%s: Failed. hnode: %p\n", __func__, hnode);
+ return -1;
+ } else {
+ return hnode->dcd_props.obj_data.node_obj.us_load_type;
+ }
+}
+
+/*
+ * ======== node_get_timeout ========
+ * Purpose:
+ * Returns the timeout value for this node.
+ */
+u32 node_get_timeout(struct node_object *hnode)
+{
+ DBC_REQUIRE(refs > 0);
+ DBC_REQUIRE(hnode);
+ if (!hnode) {
+ dev_dbg(bridge, "%s: failed. hnode: %p\n", __func__, hnode);
+ return 0;
+ } else {
+ return hnode->utimeout;
+ }
+}
+
+/*
+ * ======== node_get_type ========
+ * Purpose:
+ * Returns the node type.
+ */
+enum node_type node_get_type(struct node_object *hnode)
+{
+ enum node_type node_type;
+
+ if (hnode == (struct node_object *)DSP_HGPPNODE)
+ node_type = NODE_GPP;
+ else {
+ if (!hnode)
+ node_type = -1;
+ else
+ node_type = hnode->ntype;
+ }
+ return node_type;
+}
+
+/*
+ * ======== node_init ========
+ * Purpose:
+ * Initialize the NODE module.
+ */
+bool node_init(void)
+{
+ DBC_REQUIRE(refs >= 0);
+
+ refs++;
+
+ return true;
+}
+
+/*
+ * ======== node_on_exit ========
+ * Purpose:
+ * Gets called when RMS_EXIT is received for a node.
+ */
+void node_on_exit(struct node_object *hnode, s32 node_status)
+{
+ if (!hnode)
+ return;
+
+ /* Set node state to done */
+ NODE_SET_STATE(hnode, NODE_DONE);
+ hnode->exit_status = node_status;
+ if (hnode->loaded && hnode->phase_split) {
+ (void)hnode->hnode_mgr->nldr_fxns.pfn_unload(hnode->
+ nldr_node_obj,
+ NLDR_EXECUTE);
+ hnode->loaded = false;
+ }
+ /* Unblock call to node_terminate */
+ (void)sync_set_event(hnode->sync_done);
+ /* Notify clients */
+ proc_notify_clients(hnode->hprocessor, DSP_NODESTATECHANGE);
+ ntfy_notify(hnode->ntfy_obj, DSP_NODESTATECHANGE);
+}
+
+/*
+ * ======== node_pause ========
+ * Purpose:
+ * Suspend execution of a node currently running on the DSP.
+ */
+int node_pause(struct node_object *hnode)
+{
+ struct node_object *pnode = (struct node_object *)hnode;
+ enum node_type node_type;
+ enum node_state state;
+ struct node_mgr *hnode_mgr;
+ int status = 0;
+ u32 proc_id;
+ struct dsp_processorstate proc_state;
+ struct proc_object *hprocessor;
+
+ DBC_REQUIRE(refs > 0);
+
+ if (!hnode) {
+ status = -EFAULT;
+ } else {
+ node_type = node_get_type(hnode);
+ if (node_type != NODE_TASK && node_type != NODE_DAISSOCKET)
+ status = -EPERM;
+ }
+ if (status)
+ goto func_end;
+
+ status = proc_get_processor_id(pnode->hprocessor, &proc_id);
+
+ if (proc_id == IVA_UNIT)
+ status = -ENOSYS;
+
+ if (!status) {
+ hnode_mgr = hnode->hnode_mgr;
+
+ /* Enter critical section */
+ mutex_lock(&hnode_mgr->node_mgr_lock);
+ state = node_get_state(hnode);
+ /* Check node state */
+ if (state != NODE_RUNNING)
+ status = -EBADR;
+
+ if (status)
+ goto func_cont;
+ hprocessor = hnode->hprocessor;
+ status = proc_get_state(hprocessor, &proc_state,
+ sizeof(struct dsp_processorstate));
+ if (status)
+ goto func_cont;
+ /* If processor is in error state then don't attempt
+ to send the message */
+ if (proc_state.proc_state == PROC_ERROR) {
+ status = -EPERM;
+ goto func_cont;
+ }
+
+ status = disp_node_change_priority(hnode_mgr->disp_obj, hnode,
+ hnode_mgr->ul_fxn_addrs[RMSCHANGENODEPRIORITY],
+ hnode->node_env, NODE_SUSPENDEDPRI);
+
+ /* Update state */
+ if (status >= 0)
+ NODE_SET_STATE(hnode, NODE_PAUSED);
+
+func_cont:
+ /* End of sync_enter_cs */
+ /* Leave critical section */
+ mutex_unlock(&hnode_mgr->node_mgr_lock);
+ if (status >= 0) {
+ proc_notify_clients(hnode->hprocessor,
+ DSP_NODESTATECHANGE);
+ ntfy_notify(hnode->ntfy_obj, DSP_NODESTATECHANGE);
+ }
+ }
+func_end:
+ dev_dbg(bridge, "%s: hnode: %p status 0x%x\n", __func__, hnode, status);
+ return status;
+}
+
+/*
+ * ======== node_put_message ========
+ * Purpose:
+ * Send a message to a message node, task node, or XDAIS socket node. This
+ * function will block until the message stream can accommodate the
+ * message, or a timeout occurs.
+ */
+int node_put_message(struct node_object *hnode,
+ const struct dsp_msg *pmsg, u32 utimeout)
+{
+ struct node_mgr *hnode_mgr = NULL;
+ enum node_type node_type;
+ struct bridge_drv_interface *intf_fxns;
+ enum node_state state;
+ int status = 0;
+ void *tmp_buf;
+ struct dsp_msg new_msg;
+ struct dsp_processorstate proc_state;
+ struct proc_object *hprocessor;
+
+ DBC_REQUIRE(refs > 0);
+ DBC_REQUIRE(pmsg != NULL);
+
+ if (!hnode) {
+ status = -EFAULT;
+ goto func_end;
+ }
+ hprocessor = hnode->hprocessor;
+ status = proc_get_state(hprocessor, &proc_state,
+ sizeof(struct dsp_processorstate));
+ if (status)
+ goto func_end;
+ /* If processor is in bad state then don't attempt sending the
+ message */
+ if (proc_state.proc_state == PROC_ERROR) {
+ status = -EPERM;
+ goto func_end;
+ }
+ hnode_mgr = hnode->hnode_mgr;
+ node_type = node_get_type(hnode);
+ if (node_type != NODE_MESSAGE && node_type != NODE_TASK &&
+ node_type != NODE_DAISSOCKET)
+ status = -EPERM;
+
+ if (!status) {
+ /* Check node state. Can't send messages to a node after
+ * we've sent the RMS_EXIT command. There is still the
+ * possibility that node_terminate can be called after we've
+ * checked the state. Could add another SYNC object to
+ * prevent this (can't use node_mgr_lock, since we don't
+ * want to block other NODE functions). However, the node may
+ * still exit on its own, before this message is sent. */
+ mutex_lock(&hnode_mgr->node_mgr_lock);
+ state = node_get_state(hnode);
+ if (state == NODE_TERMINATING || state == NODE_DONE)
+ status = -EBADR;
+
+ /* end of sync_enter_cs */
+ mutex_unlock(&hnode_mgr->node_mgr_lock);
+ }
+ if (status)
+ goto func_end;
+
+ /* assign pmsg values to new msg */
+ new_msg = *pmsg;
+ /* Now, check if message contains a SM buffer descriptor */
+ if (pmsg->dw_cmd & DSP_RMSBUFDESC) {
+ /* Translate GPP Va to DSP physical buf Ptr. */
+ tmp_buf = cmm_xlator_translate(hnode->xlator,
+ (void *)new_msg.dw_arg1,
+ CMM_VA2DSPPA);
+ if (tmp_buf != NULL) {
+ /* got translation, convert to MAUs in msg */
+ if (hnode->hnode_mgr->udsp_word_size != 0) {
+ new_msg.dw_arg1 =
+ (u32) tmp_buf /
+ hnode->hnode_mgr->udsp_word_size;
+ /* MAUs */
+ new_msg.dw_arg2 /= hnode->hnode_mgr->
+ udsp_word_size;
+ } else {
+ pr_err("%s: udsp_word_size is zero!\n",
+ __func__);
+ status = -EPERM; /* bad DSPWordSize */
+ }
+ } else { /* failed to translate buffer address */
+ status = -ESRCH;
+ }
+ }
+ if (!status) {
+ intf_fxns = hnode_mgr->intf_fxns;
+ status = (*intf_fxns->pfn_msg_put) (hnode->msg_queue_obj,
+ &new_msg, utimeout);
+ }
+func_end:
+ dev_dbg(bridge, "%s: hnode: %p pmsg: %p utimeout: 0x%x, "
+ "status 0x%x\n", __func__, hnode, pmsg, utimeout, status);
+ return status;
+}
+
+/*
+ * ======== node_register_notify ========
+ * Purpose:
+ * Register to be notified on specific events for this node.
+ */
+int node_register_notify(struct node_object *hnode, u32 event_mask,
+ u32 notify_type,
+ struct dsp_notification *hnotification)
+{
+ struct bridge_drv_interface *intf_fxns;
+ int status = 0;
+
+ DBC_REQUIRE(refs > 0);
+ DBC_REQUIRE(hnotification != NULL);
+
+ if (!hnode) {
+ status = -EFAULT;
+ } else {
+ /* Check if event mask is a valid node related event */
+ if (event_mask & ~(DSP_NODESTATECHANGE | DSP_NODEMESSAGEREADY))
+ status = -EINVAL;
+
+ /* Check if notify type is valid */
+ if (notify_type != DSP_SIGNALEVENT)
+ status = -EINVAL;
+
+ /* Only one Notification can be registered at a
+ * time - Limitation */
+ if (event_mask == (DSP_NODESTATECHANGE | DSP_NODEMESSAGEREADY))
+ status = -EINVAL;
+ }
+ if (!status) {
+ if (event_mask == DSP_NODESTATECHANGE) {
+ status = ntfy_register(hnode->ntfy_obj, hnotification,
+ event_mask & DSP_NODESTATECHANGE,
+ notify_type);
+ } else {
+ /* Send Message part of event mask to msg_ctrl */
+ intf_fxns = hnode->hnode_mgr->intf_fxns;
+ status = (*intf_fxns->pfn_msg_register_notify)
+ (hnode->msg_queue_obj,
+ event_mask & DSP_NODEMESSAGEREADY, notify_type,
+ hnotification);
+ }
+
+ }
+ dev_dbg(bridge, "%s: hnode: %p event_mask: 0x%x notify_type: 0x%x "
+ "hnotification: %p status 0x%x\n", __func__, hnode,
+ event_mask, notify_type, hnotification, status);
+ return status;
+}
+
+/*
+ * ======== node_run ========
+ * Purpose:
+ * Start execution of a node's execute phase, or resume execution of a node
+ * that has been suspended (via NODE_NodePause()) on the DSP. Load the
+ * node's execute function if necessary.
+ */
+int node_run(struct node_object *hnode)
+{
+ struct node_object *pnode = (struct node_object *)hnode;
+ struct node_mgr *hnode_mgr;
+ enum node_type node_type;
+ enum node_state state;
+ u32 ul_execute_fxn;
+ u32 ul_fxn_addr;
+ int status = 0;
+ u32 proc_id;
+ struct bridge_drv_interface *intf_fxns;
+ struct dsp_processorstate proc_state;
+ struct proc_object *hprocessor;
+
+ DBC_REQUIRE(refs > 0);
+
+ if (!hnode) {
+ status = -EFAULT;
+ goto func_end;
+ }
+ hprocessor = hnode->hprocessor;
+ status = proc_get_state(hprocessor, &proc_state,
+ sizeof(struct dsp_processorstate));
+ if (status)
+ goto func_end;
+ /* If processor is in error state then don't attempt to run the node */
+ if (proc_state.proc_state == PROC_ERROR) {
+ status = -EPERM;
+ goto func_end;
+ }
+ node_type = node_get_type(hnode);
+ if (node_type == NODE_DEVICE)
+ status = -EPERM;
+ if (status)
+ goto func_end;
+
+ hnode_mgr = hnode->hnode_mgr;
+ if (!hnode_mgr) {
+ status = -EFAULT;
+ goto func_end;
+ }
+ intf_fxns = hnode_mgr->intf_fxns;
+ /* Enter critical section */
+ mutex_lock(&hnode_mgr->node_mgr_lock);
+
+ state = node_get_state(hnode);
+ if (state != NODE_CREATED && state != NODE_PAUSED)
+ status = -EBADR;
+
+ if (!status)
+ status = proc_get_processor_id(pnode->hprocessor, &proc_id);
+
+ if (status)
+ goto func_cont1;
+
+ if ((proc_id != DSP_UNIT) && (proc_id != IVA_UNIT))
+ goto func_cont1;
+
+ if (state == NODE_CREATED) {
+ /* If node's execute function is not loaded, load it */
+ if (!(hnode->loaded) && hnode->phase_split) {
+ status =
+ hnode_mgr->nldr_fxns.pfn_load(hnode->nldr_node_obj,
+ NLDR_EXECUTE);
+ if (!status) {
+ hnode->loaded = true;
+ } else {
+ pr_err("%s: fail - load execute code: 0x%x\n",
+ __func__, status);
+ }
+ }
+ if (!status) {
+ /* Get address of node's execute function */
+ if (proc_id == IVA_UNIT)
+ ul_execute_fxn = (u32) hnode->node_env;
+ else {
+ status = get_fxn_address(hnode, &ul_execute_fxn,
+ EXECUTEPHASE);
+ }
+ }
+ if (!status) {
+ ul_fxn_addr = hnode_mgr->ul_fxn_addrs[RMSEXECUTENODE];
+ status =
+ disp_node_run(hnode_mgr->disp_obj, hnode,
+ ul_fxn_addr, ul_execute_fxn,
+ hnode->node_env);
+ }
+ } else if (state == NODE_PAUSED) {
+ ul_fxn_addr = hnode_mgr->ul_fxn_addrs[RMSCHANGENODEPRIORITY];
+ status = disp_node_change_priority(hnode_mgr->disp_obj, hnode,
+ ul_fxn_addr, hnode->node_env,
+ NODE_GET_PRIORITY(hnode));
+ } else {
+ /* We should never get here */
+ DBC_ASSERT(false);
+ }
+func_cont1:
+ /* Update node state. */
+ if (status >= 0)
+ NODE_SET_STATE(hnode, NODE_RUNNING);
+ else /* Set state back to previous value */
+ NODE_SET_STATE(hnode, state);
+ /*End of sync_enter_cs */
+ /* Exit critical section */
+ mutex_unlock(&hnode_mgr->node_mgr_lock);
+ if (status >= 0) {
+ proc_notify_clients(hnode->hprocessor, DSP_NODESTATECHANGE);
+ ntfy_notify(hnode->ntfy_obj, DSP_NODESTATECHANGE);
+ }
+func_end:
+ dev_dbg(bridge, "%s: hnode: %p status 0x%x\n", __func__, hnode, status);
+ return status;
+}
+
+/*
+ * ======== node_terminate ========
+ * Purpose:
+ * Signal a node running on the DSP that it should exit its execute phase
+ * function.
+ */
+int node_terminate(struct node_object *hnode, int *pstatus)
+{
+ struct node_object *pnode = (struct node_object *)hnode;
+ struct node_mgr *hnode_mgr = NULL;
+ enum node_type node_type;
+ struct bridge_drv_interface *intf_fxns;
+ enum node_state state;
+ struct dsp_msg msg, killmsg;
+ int status = 0;
+ u32 proc_id, kill_time_out;
+ struct deh_mgr *hdeh_mgr;
+ struct dsp_processorstate proc_state;
+
+ DBC_REQUIRE(refs > 0);
+ DBC_REQUIRE(pstatus != NULL);
+
+ if (!hnode || !hnode->hnode_mgr) {
+ status = -EFAULT;
+ goto func_end;
+ }
+ if (pnode->hprocessor == NULL) {
+ status = -EFAULT;
+ goto func_end;
+ }
+ status = proc_get_processor_id(pnode->hprocessor, &proc_id);
+
+ if (!status) {
+ hnode_mgr = hnode->hnode_mgr;
+ node_type = node_get_type(hnode);
+ if (node_type != NODE_TASK && node_type != NODE_DAISSOCKET)
+ status = -EPERM;
+ }
+ if (!status) {
+ /* Check node state */
+ mutex_lock(&hnode_mgr->node_mgr_lock);
+ state = node_get_state(hnode);
+ if (state != NODE_RUNNING) {
+ status = -EBADR;
+ /* Set the exit status if node terminated on
+ * its own. */
+ if (state == NODE_DONE)
+ *pstatus = hnode->exit_status;
+
+ } else {
+ NODE_SET_STATE(hnode, NODE_TERMINATING);
+ }
+ /* end of sync_enter_cs */
+ mutex_unlock(&hnode_mgr->node_mgr_lock);
+ }
+ if (!status) {
+ /*
+ * Send exit message. Do not change state to NODE_DONE
+ * here. That will be done in callback.
+ */
+ status = proc_get_state(pnode->hprocessor, &proc_state,
+ sizeof(struct dsp_processorstate));
+ if (status)
+ goto func_cont;
+ /* If processor is in error state then don't attempt to send
+ * A kill task command */
+ if (proc_state.proc_state == PROC_ERROR) {
+ status = -EPERM;
+ goto func_cont;
+ }
+
+ msg.dw_cmd = RMS_EXIT;
+ msg.dw_arg1 = hnode->node_env;
+ killmsg.dw_cmd = RMS_KILLTASK;
+ killmsg.dw_arg1 = hnode->node_env;
+ intf_fxns = hnode_mgr->intf_fxns;
+
+ if (hnode->utimeout > MAXTIMEOUT)
+ kill_time_out = MAXTIMEOUT;
+ else
+ kill_time_out = (hnode->utimeout) * 2;
+
+ status = (*intf_fxns->pfn_msg_put) (hnode->msg_queue_obj, &msg,
+ hnode->utimeout);
+ if (status)
+ goto func_cont;
+
+ /*
+ * Wait on synchronization object that will be
+ * posted in the callback on receiving RMS_EXIT
+ * message, or by node_delete. Check for valid hnode,
+ * in case posted by node_delete().
+ */
+ status = sync_wait_on_event(hnode->sync_done,
+ kill_time_out / 2);
+ if (status != ETIME)
+ goto func_cont;
+
+ status = (*intf_fxns->pfn_msg_put)(hnode->msg_queue_obj,
+ &killmsg, hnode->utimeout);
+ if (status)
+ goto func_cont;
+ status = sync_wait_on_event(hnode->sync_done,
+ kill_time_out / 2);
+ if (status) {
+ /*
+ * Here it goes the part of the simulation of
+ * the DSP exception.
+ */
+ dev_get_deh_mgr(hnode_mgr->hdev_obj, &hdeh_mgr);
+ if (!hdeh_mgr)
+ goto func_cont;
+
+ bridge_deh_notify(hdeh_mgr, DSP_SYSERROR, DSP_EXCEPTIONABORT);
+ }
+ }
+func_cont:
+ if (!status) {
+ /* Enter CS before getting exit status, in case node was
+ * deleted. */
+ mutex_lock(&hnode_mgr->node_mgr_lock);
+ /* Make sure node wasn't deleted while we blocked */
+ if (!hnode) {
+ status = -EPERM;
+ } else {
+ *pstatus = hnode->exit_status;
+ dev_dbg(bridge, "%s: hnode: %p env 0x%x status 0x%x\n",
+ __func__, hnode, hnode->node_env, status);
+ }
+ mutex_unlock(&hnode_mgr->node_mgr_lock);
+ } /*End of sync_enter_cs */
+func_end:
+ return status;
+}
+
+/*
+ * ======== delete_node ========
+ * Purpose:
+ * Free GPP resources allocated in node_allocate() or node_connect().
+ */
+static void delete_node(struct node_object *hnode,
+ struct process_context *pr_ctxt)
+{
+ struct node_mgr *hnode_mgr;
+ struct cmm_xlatorobject *xlator;
+ struct bridge_drv_interface *intf_fxns;
+ u32 i;
+ enum node_type node_type;
+ struct stream_chnl stream;
+ struct node_msgargs node_msg_args;
+ struct node_taskargs task_arg_obj;
+#ifdef DSP_DMM_DEBUG
+ struct dmm_object *dmm_mgr;
+ struct proc_object *p_proc_object =
+ (struct proc_object *)hnode->hprocessor;
+#endif
+ int status;
+ if (!hnode)
+ goto func_end;
+ hnode_mgr = hnode->hnode_mgr;
+ if (!hnode_mgr)
+ goto func_end;
+ xlator = hnode->xlator;
+ node_type = node_get_type(hnode);
+ if (node_type != NODE_DEVICE) {
+ node_msg_args = hnode->create_args.asa.node_msg_args;
+ kfree(node_msg_args.pdata);
+
+ /* Free msg_ctrl queue */
+ if (hnode->msg_queue_obj) {
+ intf_fxns = hnode_mgr->intf_fxns;
+ (*intf_fxns->pfn_msg_delete_queue) (hnode->
+ msg_queue_obj);
+ hnode->msg_queue_obj = NULL;
+ }
+
+ kfree(hnode->sync_done);
+
+ /* Free all stream info */
+ if (hnode->inputs) {
+ for (i = 0; i < MAX_INPUTS(hnode); i++) {
+ stream = hnode->inputs[i];
+ free_stream(hnode_mgr, stream);
+ }
+ kfree(hnode->inputs);
+ hnode->inputs = NULL;
+ }
+ if (hnode->outputs) {
+ for (i = 0; i < MAX_OUTPUTS(hnode); i++) {
+ stream = hnode->outputs[i];
+ free_stream(hnode_mgr, stream);
+ }
+ kfree(hnode->outputs);
+ hnode->outputs = NULL;
+ }
+ task_arg_obj = hnode->create_args.asa.task_arg_obj;
+ if (task_arg_obj.strm_in_def) {
+ for (i = 0; i < MAX_INPUTS(hnode); i++) {
+ kfree(task_arg_obj.strm_in_def[i].sz_device);
+ task_arg_obj.strm_in_def[i].sz_device = NULL;
+ }
+ kfree(task_arg_obj.strm_in_def);
+ task_arg_obj.strm_in_def = NULL;
+ }
+ if (task_arg_obj.strm_out_def) {
+ for (i = 0; i < MAX_OUTPUTS(hnode); i++) {
+ kfree(task_arg_obj.strm_out_def[i].sz_device);
+ task_arg_obj.strm_out_def[i].sz_device = NULL;
+ }
+ kfree(task_arg_obj.strm_out_def);
+ task_arg_obj.strm_out_def = NULL;
+ }
+ if (task_arg_obj.udsp_heap_res_addr) {
+ status = proc_un_map(hnode->hprocessor, (void *)
+ task_arg_obj.udsp_heap_addr,
+ pr_ctxt);
+
+ status = proc_un_reserve_memory(hnode->hprocessor,
+ (void *)
+ task_arg_obj.
+ udsp_heap_res_addr,
+ pr_ctxt);
+#ifdef DSP_DMM_DEBUG
+ status = dmm_get_handle(p_proc_object, &dmm_mgr);
+ if (dmm_mgr)
+ dmm_mem_map_dump(dmm_mgr);
+ else
+ status = DSP_EHANDLE;
+#endif
+ }
+ }
+ if (node_type != NODE_MESSAGE) {
+ kfree(hnode->stream_connect);
+ hnode->stream_connect = NULL;
+ }
+ kfree(hnode->pstr_dev_name);
+ hnode->pstr_dev_name = NULL;
+
+ if (hnode->ntfy_obj) {
+ ntfy_delete(hnode->ntfy_obj);
+ kfree(hnode->ntfy_obj);
+ hnode->ntfy_obj = NULL;
+ }
+
+ /* These were allocated in dcd_get_object_def (via node_allocate) */
+ kfree(hnode->dcd_props.obj_data.node_obj.pstr_create_phase_fxn);
+ hnode->dcd_props.obj_data.node_obj.pstr_create_phase_fxn = NULL;
+
+ kfree(hnode->dcd_props.obj_data.node_obj.pstr_execute_phase_fxn);
+ hnode->dcd_props.obj_data.node_obj.pstr_execute_phase_fxn = NULL;
+
+ kfree(hnode->dcd_props.obj_data.node_obj.pstr_delete_phase_fxn);
+ hnode->dcd_props.obj_data.node_obj.pstr_delete_phase_fxn = NULL;
+
+ kfree(hnode->dcd_props.obj_data.node_obj.pstr_i_alg_name);
+ hnode->dcd_props.obj_data.node_obj.pstr_i_alg_name = NULL;
+
+ /* Free all SM address translator resources */
+ if (xlator) {
+ (void)cmm_xlator_delete(xlator, true); /* force free */
+ xlator = NULL;
+ }
+
+ kfree(hnode->nldr_node_obj);
+ hnode->nldr_node_obj = NULL;
+ hnode->hnode_mgr = NULL;
+ kfree(hnode);
+ hnode = NULL;
+func_end:
+ return;
+}
+
+/*
+ * ======== delete_node_mgr ========
+ * Purpose:
+ * Frees the node manager.
+ */
+static void delete_node_mgr(struct node_mgr *hnode_mgr)
+{
+ struct node_object *hnode;
+
+ if (hnode_mgr) {
+ /* Free resources */
+ if (hnode_mgr->hdcd_mgr)
+ dcd_destroy_manager(hnode_mgr->hdcd_mgr);
+
+ /* Remove any elements remaining in lists */
+ if (hnode_mgr->node_list) {
+ while ((hnode = (struct node_object *)
+ lst_get_head(hnode_mgr->node_list)))
+ delete_node(hnode, NULL);
+
+ DBC_ASSERT(LST_IS_EMPTY(hnode_mgr->node_list));
+ kfree(hnode_mgr->node_list);
+ }
+ mutex_destroy(&hnode_mgr->node_mgr_lock);
+ if (hnode_mgr->ntfy_obj) {
+ ntfy_delete(hnode_mgr->ntfy_obj);
+ kfree(hnode_mgr->ntfy_obj);
+ }
+
+ if (hnode_mgr->pipe_map)
+ gb_delete(hnode_mgr->pipe_map);
+
+ if (hnode_mgr->pipe_done_map)
+ gb_delete(hnode_mgr->pipe_done_map);
+
+ if (hnode_mgr->chnl_map)
+ gb_delete(hnode_mgr->chnl_map);
+
+ if (hnode_mgr->dma_chnl_map)
+ gb_delete(hnode_mgr->dma_chnl_map);
+
+ if (hnode_mgr->zc_chnl_map)
+ gb_delete(hnode_mgr->zc_chnl_map);
+
+ if (hnode_mgr->disp_obj)
+ disp_delete(hnode_mgr->disp_obj);
+
+ if (hnode_mgr->strm_mgr_obj)
+ strm_delete(hnode_mgr->strm_mgr_obj);
+
+ /* Delete the loader */
+ if (hnode_mgr->nldr_obj)
+ hnode_mgr->nldr_fxns.pfn_delete(hnode_mgr->nldr_obj);
+
+ if (hnode_mgr->loader_init)
+ hnode_mgr->nldr_fxns.pfn_exit();
+
+ kfree(hnode_mgr);
+ }
+}
+
+/*
+ * ======== fill_stream_connect ========
+ * Purpose:
+ * Fills stream information.
+ */
+static void fill_stream_connect(struct node_object *node1,
+ struct node_object *node2,
+ u32 stream1, u32 stream2)
+{
+ u32 strm_index;
+ struct dsp_streamconnect *strm1 = NULL;
+ struct dsp_streamconnect *strm2 = NULL;
+ enum node_type node1_type = NODE_TASK;
+ enum node_type node2_type = NODE_TASK;
+
+ node1_type = node_get_type(node1);
+ node2_type = node_get_type(node2);
+ if (node1 != (struct node_object *)DSP_HGPPNODE) {
+
+ if (node1_type != NODE_DEVICE) {
+ strm_index = node1->num_inputs +
+ node1->num_outputs - 1;
+ strm1 = &(node1->stream_connect[strm_index]);
+ strm1->cb_struct = sizeof(struct dsp_streamconnect);
+ strm1->this_node_stream_index = stream1;
+ }
+
+ if (node2 != (struct node_object *)DSP_HGPPNODE) {
+ /* NODE == > NODE */
+ if (node1_type != NODE_DEVICE) {
+ strm1->connected_node = node2;
+ strm1->ui_connected_node_id = node2->node_uuid;
+ strm1->connected_node_stream_index = stream2;
+ strm1->connect_type = CONNECTTYPE_NODEOUTPUT;
+ }
+ if (node2_type != NODE_DEVICE) {
+ strm_index = node2->num_inputs +
+ node2->num_outputs - 1;
+ strm2 = &(node2->stream_connect[strm_index]);
+ strm2->cb_struct =
+ sizeof(struct dsp_streamconnect);
+ strm2->this_node_stream_index = stream2;
+ strm2->connected_node = node1;
+ strm2->ui_connected_node_id = node1->node_uuid;
+ strm2->connected_node_stream_index = stream1;
+ strm2->connect_type = CONNECTTYPE_NODEINPUT;
+ }
+ } else if (node1_type != NODE_DEVICE)
+ strm1->connect_type = CONNECTTYPE_GPPOUTPUT;
+ } else {
+ /* GPP == > NODE */
+ DBC_ASSERT(node2 != (struct node_object *)DSP_HGPPNODE);
+ strm_index = node2->num_inputs + node2->num_outputs - 1;
+ strm2 = &(node2->stream_connect[strm_index]);
+ strm2->cb_struct = sizeof(struct dsp_streamconnect);
+ strm2->this_node_stream_index = stream2;
+ strm2->connect_type = CONNECTTYPE_GPPINPUT;
+ }
+}
+
+/*
+ * ======== fill_stream_def ========
+ * Purpose:
+ * Fills Stream attributes.
+ */
+static void fill_stream_def(struct node_object *hnode,
+ struct node_strmdef *pstrm_def,
+ struct dsp_strmattr *pattrs)
+{
+ struct node_mgr *hnode_mgr = hnode->hnode_mgr;
+
+ if (pattrs != NULL) {
+ pstrm_def->num_bufs = pattrs->num_bufs;
+ pstrm_def->buf_size =
+ pattrs->buf_size / hnode_mgr->udsp_data_mau_size;
+ pstrm_def->seg_id = pattrs->seg_id;
+ pstrm_def->buf_alignment = pattrs->buf_alignment;
+ pstrm_def->utimeout = pattrs->utimeout;
+ } else {
+ pstrm_def->num_bufs = DEFAULTNBUFS;
+ pstrm_def->buf_size =
+ DEFAULTBUFSIZE / hnode_mgr->udsp_data_mau_size;
+ pstrm_def->seg_id = DEFAULTSEGID;
+ pstrm_def->buf_alignment = DEFAULTALIGNMENT;
+ pstrm_def->utimeout = DEFAULTTIMEOUT;
+ }
+}
+
+/*
+ * ======== free_stream ========
+ * Purpose:
+ * Updates the channel mask and frees the pipe id.
+ */
+static void free_stream(struct node_mgr *hnode_mgr, struct stream_chnl stream)
+{
+ /* Free up the pipe id unless other node has not yet been deleted. */
+ if (stream.type == NODECONNECT) {
+ if (gb_test(hnode_mgr->pipe_done_map, stream.dev_id)) {
+ /* The other node has already been deleted */
+ gb_clear(hnode_mgr->pipe_done_map, stream.dev_id);
+ gb_clear(hnode_mgr->pipe_map, stream.dev_id);
+ } else {
+ /* The other node has not been deleted yet */
+ gb_set(hnode_mgr->pipe_done_map, stream.dev_id);
+ }
+ } else if (stream.type == HOSTCONNECT) {
+ if (stream.dev_id < hnode_mgr->ul_num_chnls) {
+ gb_clear(hnode_mgr->chnl_map, stream.dev_id);
+ } else if (stream.dev_id < (2 * hnode_mgr->ul_num_chnls)) {
+ /* dsp-dma */
+ gb_clear(hnode_mgr->dma_chnl_map, stream.dev_id -
+ (1 * hnode_mgr->ul_num_chnls));
+ } else if (stream.dev_id < (3 * hnode_mgr->ul_num_chnls)) {
+ /* zero-copy */
+ gb_clear(hnode_mgr->zc_chnl_map, stream.dev_id -
+ (2 * hnode_mgr->ul_num_chnls));
+ }
+ }
+}
+
+/*
+ * ======== get_fxn_address ========
+ * Purpose:
+ * Retrieves the address for create, execute or delete phase for a node.
+ */
+static int get_fxn_address(struct node_object *hnode, u32 * fxn_addr,
+ u32 phase)
+{
+ char *pstr_fxn_name = NULL;
+ struct node_mgr *hnode_mgr = hnode->hnode_mgr;
+ int status = 0;
+ DBC_REQUIRE(node_get_type(hnode) == NODE_TASK ||
+ node_get_type(hnode) == NODE_DAISSOCKET ||
+ node_get_type(hnode) == NODE_MESSAGE);
+
+ switch (phase) {
+ case CREATEPHASE:
+ pstr_fxn_name =
+ hnode->dcd_props.obj_data.node_obj.pstr_create_phase_fxn;
+ break;
+ case EXECUTEPHASE:
+ pstr_fxn_name =
+ hnode->dcd_props.obj_data.node_obj.pstr_execute_phase_fxn;
+ break;
+ case DELETEPHASE:
+ pstr_fxn_name =
+ hnode->dcd_props.obj_data.node_obj.pstr_delete_phase_fxn;
+ break;
+ default:
+ /* Should never get here */
+ DBC_ASSERT(false);
+ break;
+ }
+
+ status =
+ hnode_mgr->nldr_fxns.pfn_get_fxn_addr(hnode->nldr_node_obj,
+ pstr_fxn_name, fxn_addr);
+
+ return status;
+}
+
+/*
+ * ======== get_node_info ========
+ * Purpose:
+ * Retrieves the node information.
+ */
+void get_node_info(struct node_object *hnode, struct dsp_nodeinfo *node_info)
+{
+ u32 i;
+
+ DBC_REQUIRE(hnode);
+ DBC_REQUIRE(node_info != NULL);
+
+ node_info->cb_struct = sizeof(struct dsp_nodeinfo);
+ node_info->nb_node_database_props =
+ hnode->dcd_props.obj_data.node_obj.ndb_props;
+ node_info->execution_priority = hnode->prio;
+ node_info->device_owner = hnode->device_owner;
+ node_info->number_streams = hnode->num_inputs + hnode->num_outputs;
+ node_info->node_env = hnode->node_env;
+
+ node_info->ns_execution_state = node_get_state(hnode);
+
+ /* Copy stream connect data */
+ for (i = 0; i < hnode->num_inputs + hnode->num_outputs; i++)
+ node_info->sc_stream_connection[i] = hnode->stream_connect[i];
+
+}
+
+/*
+ * ======== get_node_props ========
+ * Purpose:
+ * Retrieve node properties.
+ */
+static int get_node_props(struct dcd_manager *hdcd_mgr,
+ struct node_object *hnode,
+ const struct dsp_uuid *node_uuid,
+ struct dcd_genericobj *dcd_prop)
+{
+ u32 len;
+ struct node_msgargs *pmsg_args;
+ struct node_taskargs *task_arg_obj;
+ enum node_type node_type = NODE_TASK;
+ struct dsp_ndbprops *pndb_props =
+ &(dcd_prop->obj_data.node_obj.ndb_props);
+ int status = 0;
+ char sz_uuid[MAXUUIDLEN];
+
+ status = dcd_get_object_def(hdcd_mgr, (struct dsp_uuid *)node_uuid,
+ DSP_DCDNODETYPE, dcd_prop);
+
+ if (!status) {
+ hnode->ntype = node_type = pndb_props->ntype;
+
+ /* Create UUID value to set in registry. */
+ uuid_uuid_to_string((struct dsp_uuid *)node_uuid, sz_uuid,
+ MAXUUIDLEN);
+ dev_dbg(bridge, "(node) UUID: %s\n", sz_uuid);
+
+ /* Fill in message args that come from NDB */
+ if (node_type != NODE_DEVICE) {
+ pmsg_args = &(hnode->create_args.asa.node_msg_args);
+ pmsg_args->seg_id =
+ dcd_prop->obj_data.node_obj.msg_segid;
+ pmsg_args->notify_type =
+ dcd_prop->obj_data.node_obj.msg_notify_type;
+ pmsg_args->max_msgs = pndb_props->message_depth;
+ dev_dbg(bridge, "(node) Max Number of Messages: 0x%x\n",
+ pmsg_args->max_msgs);
+ } else {
+ /* Copy device name */
+ DBC_REQUIRE(pndb_props->ac_name);
+ len = strlen(pndb_props->ac_name);
+ DBC_ASSERT(len < MAXDEVNAMELEN);
+ hnode->pstr_dev_name = kzalloc(len + 1, GFP_KERNEL);
+ if (hnode->pstr_dev_name == NULL) {
+ status = -ENOMEM;
+ } else {
+ strncpy(hnode->pstr_dev_name,
+ pndb_props->ac_name, len);
+ }
+ }
+ }
+ if (!status) {
+ /* Fill in create args that come from NDB */
+ if (node_type == NODE_TASK || node_type == NODE_DAISSOCKET) {
+ task_arg_obj = &(hnode->create_args.asa.task_arg_obj);
+ task_arg_obj->prio = pndb_props->prio;
+ task_arg_obj->stack_size = pndb_props->stack_size;
+ task_arg_obj->sys_stack_size =
+ pndb_props->sys_stack_size;
+ task_arg_obj->stack_seg = pndb_props->stack_seg;
+ dev_dbg(bridge, "(node) Priority: 0x%x Stack Size: "
+ "0x%x words System Stack Size: 0x%x words "
+ "Stack Segment: 0x%x profile count : 0x%x\n",
+ task_arg_obj->prio, task_arg_obj->stack_size,
+ task_arg_obj->sys_stack_size,
+ task_arg_obj->stack_seg,
+ pndb_props->count_profiles);
+ }
+ }
+
+ return status;
+}
+
+/*
+ * ======== get_proc_props ========
+ * Purpose:
+ * Retrieve the processor properties.
+ */
+static int get_proc_props(struct node_mgr *hnode_mgr,
+ struct dev_object *hdev_obj)
+{
+ struct cfg_hostres *host_res;
+ struct bridge_dev_context *pbridge_context;
+ int status = 0;
+
+ status = dev_get_bridge_context(hdev_obj, &pbridge_context);
+ if (!pbridge_context)
+ status = -EFAULT;
+
+ if (!status) {
+ host_res = pbridge_context->resources;
+ if (!host_res)
+ return -EPERM;
+ hnode_mgr->ul_chnl_offset = host_res->dw_chnl_offset;
+ hnode_mgr->ul_chnl_buf_size = host_res->dw_chnl_buf_size;
+ hnode_mgr->ul_num_chnls = host_res->dw_num_chnls;
+
+ /*
+ * PROC will add an API to get dsp_processorinfo.
+ * Fill in default values for now.
+ */
+ /* TODO -- Instead of hard coding, take from registry */
+ hnode_mgr->proc_family = 6000;
+ hnode_mgr->proc_type = 6410;
+ hnode_mgr->min_pri = DSP_NODE_MIN_PRIORITY;
+ hnode_mgr->max_pri = DSP_NODE_MAX_PRIORITY;
+ hnode_mgr->udsp_word_size = DSPWORDSIZE;
+ hnode_mgr->udsp_data_mau_size = DSPWORDSIZE;
+ hnode_mgr->udsp_mau_size = 1;
+
+ }
+ return status;
+}
+
+/*
+ * ======== node_get_uuid_props ========
+ * Purpose:
+ * Fetch Node UUID properties from DCD/DOF file.
+ */
+int node_get_uuid_props(void *hprocessor,
+ const struct dsp_uuid *node_uuid,
+ struct dsp_ndbprops *node_props)
+{
+ struct node_mgr *hnode_mgr = NULL;
+ struct dev_object *hdev_obj;
+ int status = 0;
+ struct dcd_nodeprops dcd_node_props;
+ struct dsp_processorstate proc_state;
+
+ DBC_REQUIRE(refs > 0);
+ DBC_REQUIRE(hprocessor != NULL);
+ DBC_REQUIRE(node_uuid != NULL);
+
+ if (hprocessor == NULL || node_uuid == NULL) {
+ status = -EFAULT;
+ goto func_end;
+ }
+ status = proc_get_state(hprocessor, &proc_state,
+ sizeof(struct dsp_processorstate));
+ if (status)
+ goto func_end;
+ /* If processor is in error state then don't attempt
+ to send the message */
+ if (proc_state.proc_state == PROC_ERROR) {
+ status = -EPERM;
+ goto func_end;
+ }
+
+ status = proc_get_dev_object(hprocessor, &hdev_obj);
+ if (hdev_obj) {
+ status = dev_get_node_manager(hdev_obj, &hnode_mgr);
+ if (hnode_mgr == NULL) {
+ status = -EFAULT;
+ goto func_end;
+ }
+ }
+
+ /*
+ * Enter the critical section. This is needed because
+ * dcd_get_object_def will ultimately end up calling dbll_open/close,
+ * which needs to be protected in order to not corrupt the zlib manager
+ * (COD).
+ */
+ mutex_lock(&hnode_mgr->node_mgr_lock);
+
+ dcd_node_props.pstr_create_phase_fxn = NULL;
+ dcd_node_props.pstr_execute_phase_fxn = NULL;
+ dcd_node_props.pstr_delete_phase_fxn = NULL;
+ dcd_node_props.pstr_i_alg_name = NULL;
+
+ status = dcd_get_object_def(hnode_mgr->hdcd_mgr,
+ (struct dsp_uuid *)node_uuid, DSP_DCDNODETYPE,
+ (struct dcd_genericobj *)&dcd_node_props);
+
+ if (!status) {
+ *node_props = dcd_node_props.ndb_props;
+ kfree(dcd_node_props.pstr_create_phase_fxn);
+
+ kfree(dcd_node_props.pstr_execute_phase_fxn);
+
+ kfree(dcd_node_props.pstr_delete_phase_fxn);
+
+ kfree(dcd_node_props.pstr_i_alg_name);
+ }
+ /* Leave the critical section, we're done. */
+ mutex_unlock(&hnode_mgr->node_mgr_lock);
+func_end:
+ return status;
+}
+
+/*
+ * ======== get_rms_fxns ========
+ * Purpose:
+ * Retrieve the RMS functions.
+ */
+static int get_rms_fxns(struct node_mgr *hnode_mgr)
+{
+ s32 i;
+ struct dev_object *dev_obj = hnode_mgr->hdev_obj;
+ int status = 0;
+
+ static char *psz_fxns[NUMRMSFXNS] = {
+ "RMS_queryServer", /* RMSQUERYSERVER */
+ "RMS_configureServer", /* RMSCONFIGURESERVER */
+ "RMS_createNode", /* RMSCREATENODE */
+ "RMS_executeNode", /* RMSEXECUTENODE */
+ "RMS_deleteNode", /* RMSDELETENODE */
+ "RMS_changeNodePriority", /* RMSCHANGENODEPRIORITY */
+ "RMS_readMemory", /* RMSREADMEMORY */
+ "RMS_writeMemory", /* RMSWRITEMEMORY */
+ "RMS_copy", /* RMSCOPY */
+ };
+
+ for (i = 0; i < NUMRMSFXNS; i++) {
+ status = dev_get_symbol(dev_obj, psz_fxns[i],
+ &(hnode_mgr->ul_fxn_addrs[i]));
+ if (status) {
+ if (status == -ESPIPE) {
+ /*
+ * May be loaded dynamically (in the future),
+ * but return an error for now.
+ */
+ dev_dbg(bridge, "%s: RMS function: %s currently"
+ " not loaded\n", __func__, psz_fxns[i]);
+ } else {
+ dev_dbg(bridge, "%s: Symbol not found: %s "
+ "status = 0x%x\n", __func__,
+ psz_fxns[i], status);
+ break;
+ }
+ }
+ }
+
+ return status;
+}
+
+/*
+ * ======== ovly ========
+ * Purpose:
+ * Called during overlay.Sends command to RMS to copy a block of data.
+ */
+static u32 ovly(void *priv_ref, u32 dsp_run_addr, u32 dsp_load_addr,
+ u32 ul_num_bytes, u32 mem_space)
+{
+ struct node_object *hnode = (struct node_object *)priv_ref;
+ struct node_mgr *hnode_mgr;
+ u32 ul_bytes = 0;
+ u32 ul_size;
+ u32 ul_timeout;
+ int status = 0;
+ struct bridge_dev_context *hbridge_context;
+ /* Function interface to Bridge driver*/
+ struct bridge_drv_interface *intf_fxns;
+
+ DBC_REQUIRE(hnode);
+
+ hnode_mgr = hnode->hnode_mgr;
+
+ ul_size = ul_num_bytes / hnode_mgr->udsp_word_size;
+ ul_timeout = hnode->utimeout;
+
+ /* Call new MemCopy function */
+ intf_fxns = hnode_mgr->intf_fxns;
+ status = dev_get_bridge_context(hnode_mgr->hdev_obj, &hbridge_context);
+ if (!status) {
+ status =
+ (*intf_fxns->pfn_brd_mem_copy) (hbridge_context,
+ dsp_run_addr, dsp_load_addr,
+ ul_num_bytes, (u32) mem_space);
+ if (!status)
+ ul_bytes = ul_num_bytes;
+ else
+ pr_debug("%s: failed to copy brd memory, status 0x%x\n",
+ __func__, status);
+ } else {
+ pr_debug("%s: failed to get Bridge context, status 0x%x\n",
+ __func__, status);
+ }
+
+ return ul_bytes;
+}
+
+/*
+ * ======== mem_write ========
+ */
+static u32 mem_write(void *priv_ref, u32 dsp_add, void *pbuf,
+ u32 ul_num_bytes, u32 mem_space)
+{
+ struct node_object *hnode = (struct node_object *)priv_ref;
+ struct node_mgr *hnode_mgr;
+ u16 mem_sect_type;
+ u32 ul_timeout;
+ int status = 0;
+ struct bridge_dev_context *hbridge_context;
+ /* Function interface to Bridge driver */
+ struct bridge_drv_interface *intf_fxns;
+
+ DBC_REQUIRE(hnode);
+ DBC_REQUIRE(mem_space & DBLL_CODE || mem_space & DBLL_DATA);
+
+ hnode_mgr = hnode->hnode_mgr;
+
+ ul_timeout = hnode->utimeout;
+ mem_sect_type = (mem_space & DBLL_CODE) ? RMS_CODE : RMS_DATA;
+
+ /* Call new MemWrite function */
+ intf_fxns = hnode_mgr->intf_fxns;
+ status = dev_get_bridge_context(hnode_mgr->hdev_obj, &hbridge_context);
+ status = (*intf_fxns->pfn_brd_mem_write) (hbridge_context, pbuf,
+ dsp_add, ul_num_bytes, mem_sect_type);
+
+ return ul_num_bytes;
+}
+
+#ifdef CONFIG_TIDSPBRIDGE_BACKTRACE
+/*
+ * ======== node_find_addr ========
+ */
+int node_find_addr(struct node_mgr *node_mgr, u32 sym_addr,
+ u32 offset_range, void *sym_addr_output, char *sym_name)
+{
+ struct node_object *node_obj;
+ int status = -ENOENT;
+ u32 n;
+
+ pr_debug("%s(0x%x, 0x%x, 0x%x, 0x%x, %s)\n", __func__,
+ (unsigned int) node_mgr,
+ sym_addr, offset_range,
+ (unsigned int) sym_addr_output, sym_name);
+
+ node_obj = (struct node_object *)(node_mgr->node_list->head.next);
+
+ for (n = 0; n < node_mgr->num_nodes; n++) {
+ status = nldr_find_addr(node_obj->nldr_node_obj, sym_addr,
+ offset_range, sym_addr_output, sym_name);
+
+ if (!status)
+ break;
+
+ node_obj = (struct node_object *) (node_obj->list_elem.next);
+ }
+
+ return status;
+}
+#endif
diff --git a/drivers/staging/tidspbridge/rmgr/proc.c b/drivers/staging/tidspbridge/rmgr/proc.c
new file mode 100644
index 00000000000..44c26e11fc4
--- /dev/null
+++ b/drivers/staging/tidspbridge/rmgr/proc.c
@@ -0,0 +1,1936 @@
+/*
+ * proc.c
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * Processor interface at the driver level.
+ *
+ * Copyright (C) 2005-2006 Texas Instruments, Inc.
+ *
+ * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include <linux/types.h>
+/* ------------------------------------ Host OS */
+#include <linux/dma-mapping.h>
+#include <linux/scatterlist.h>
+#include <dspbridge/host_os.h>
+
+/* ----------------------------------- DSP/BIOS Bridge */
+#include <dspbridge/dbdefs.h>
+
+/* ----------------------------------- Trace & Debug */
+#include <dspbridge/dbc.h>
+
+/* ----------------------------------- OS Adaptation Layer */
+#include <dspbridge/cfg.h>
+#include <dspbridge/list.h>
+#include <dspbridge/ntfy.h>
+#include <dspbridge/sync.h>
+/* ----------------------------------- Bridge Driver */
+#include <dspbridge/dspdefs.h>
+#include <dspbridge/dspdeh.h>
+/* ----------------------------------- Platform Manager */
+#include <dspbridge/cod.h>
+#include <dspbridge/dev.h>
+#include <dspbridge/procpriv.h>
+#include <dspbridge/dmm.h>
+
+/* ----------------------------------- Resource Manager */
+#include <dspbridge/mgr.h>
+#include <dspbridge/node.h>
+#include <dspbridge/nldr.h>
+#include <dspbridge/rmm.h>
+
+/* ----------------------------------- Others */
+#include <dspbridge/dbdcd.h>
+#include <dspbridge/msg.h>
+#include <dspbridge/dspioctl.h>
+#include <dspbridge/drv.h>
+
+/* ----------------------------------- This */
+#include <dspbridge/proc.h>
+#include <dspbridge/pwr.h>
+
+#include <dspbridge/resourcecleanup.h>
+/* ----------------------------------- Defines, Data Structures, Typedefs */
+#define MAXCMDLINELEN 255
+#define PROC_ENVPROCID "PROC_ID=%d"
+#define MAXPROCIDLEN (8 + 5)
+#define PROC_DFLT_TIMEOUT 10000 /* Time out in milliseconds */
+#define PWR_TIMEOUT 500 /* Sleep/wake timout in msec */
+#define EXTEND "_EXT_END" /* Extmem end addr in DSP binary */
+
+#define DSP_CACHE_LINE 128
+
+#define BUFMODE_MASK (3 << 14)
+
+/* Buffer modes from DSP perspective */
+#define RBUF 0x4000 /* Input buffer */
+#define WBUF 0x8000 /* Output Buffer */
+
+extern struct device *bridge;
+
+/* ----------------------------------- Globals */
+
+/* The proc_object structure. */
+struct proc_object {
+ struct list_head link; /* Link to next proc_object */
+ struct dev_object *hdev_obj; /* Device this PROC represents */
+ u32 process; /* Process owning this Processor */
+ struct mgr_object *hmgr_obj; /* Manager Object Handle */
+ u32 attach_count; /* Processor attach count */
+ u32 processor_id; /* Processor number */
+ u32 utimeout; /* Time out count */
+ enum dsp_procstate proc_state; /* Processor state */
+ u32 ul_unit; /* DDSP unit number */
+ bool is_already_attached; /*
+ * True if the Device below has
+ * GPP Client attached
+ */
+ struct ntfy_object *ntfy_obj; /* Manages notifications */
+ /* Bridge Context Handle */
+ struct bridge_dev_context *hbridge_context;
+ /* Function interface to Bridge driver */
+ struct bridge_drv_interface *intf_fxns;
+ char *psz_last_coff;
+ struct list_head proc_list;
+};
+
+static u32 refs;
+
+DEFINE_MUTEX(proc_lock); /* For critical sections */
+
+/* ----------------------------------- Function Prototypes */
+static int proc_monitor(struct proc_object *proc_obj);
+static s32 get_envp_count(char **envp);
+static char **prepend_envp(char **new_envp, char **envp, s32 envp_elems,
+ s32 cnew_envp, char *sz_var);
+
+/* remember mapping information */
+static struct dmm_map_object *add_mapping_info(struct process_context *pr_ctxt,
+ u32 mpu_addr, u32 dsp_addr, u32 size)
+{
+ struct dmm_map_object *map_obj;
+
+ u32 num_usr_pgs = size / PG_SIZE4K;
+
+ pr_debug("%s: adding map info: mpu_addr 0x%x virt 0x%x size 0x%x\n",
+ __func__, mpu_addr,
+ dsp_addr, size);
+
+ map_obj = kzalloc(sizeof(struct dmm_map_object), GFP_KERNEL);
+ if (!map_obj) {
+ pr_err("%s: kzalloc failed\n", __func__);
+ return NULL;
+ }
+ INIT_LIST_HEAD(&map_obj->link);
+
+ map_obj->pages = kcalloc(num_usr_pgs, sizeof(struct page *),
+ GFP_KERNEL);
+ if (!map_obj->pages) {
+ pr_err("%s: kzalloc failed\n", __func__);
+ kfree(map_obj);
+ return NULL;
+ }
+
+ map_obj->mpu_addr = mpu_addr;
+ map_obj->dsp_addr = dsp_addr;
+ map_obj->size = size;
+ map_obj->num_usr_pgs = num_usr_pgs;
+
+ spin_lock(&pr_ctxt->dmm_map_lock);
+ list_add(&map_obj->link, &pr_ctxt->dmm_map_list);
+ spin_unlock(&pr_ctxt->dmm_map_lock);
+
+ return map_obj;
+}
+
+static int match_exact_map_obj(struct dmm_map_object *map_obj,
+ u32 dsp_addr, u32 size)
+{
+ if (map_obj->dsp_addr == dsp_addr && map_obj->size != size)
+ pr_err("%s: addr match (0x%x), size don't (0x%x != 0x%x)\n",
+ __func__, dsp_addr, map_obj->size, size);
+
+ return map_obj->dsp_addr == dsp_addr &&
+ map_obj->size == size;
+}
+
+static void remove_mapping_information(struct process_context *pr_ctxt,
+ u32 dsp_addr, u32 size)
+{
+ struct dmm_map_object *map_obj;
+
+ pr_debug("%s: looking for virt 0x%x size 0x%x\n", __func__,
+ dsp_addr, size);
+
+ spin_lock(&pr_ctxt->dmm_map_lock);
+ list_for_each_entry(map_obj, &pr_ctxt->dmm_map_list, link) {
+ pr_debug("%s: candidate: mpu_addr 0x%x virt 0x%x size 0x%x\n",
+ __func__,
+ map_obj->mpu_addr,
+ map_obj->dsp_addr,
+ map_obj->size);
+
+ if (match_exact_map_obj(map_obj, dsp_addr, size)) {
+ pr_debug("%s: match, deleting map info\n", __func__);
+ list_del(&map_obj->link);
+ kfree(map_obj->dma_info.sg);
+ kfree(map_obj->pages);
+ kfree(map_obj);
+ goto out;
+ }
+ pr_debug("%s: candidate didn't match\n", __func__);
+ }
+
+ pr_err("%s: failed to find given map info\n", __func__);
+out:
+ spin_unlock(&pr_ctxt->dmm_map_lock);
+}
+
+static int match_containing_map_obj(struct dmm_map_object *map_obj,
+ u32 mpu_addr, u32 size)
+{
+ u32 map_obj_end = map_obj->mpu_addr + map_obj->size;
+
+ return mpu_addr >= map_obj->mpu_addr &&
+ mpu_addr + size <= map_obj_end;
+}
+
+static struct dmm_map_object *find_containing_mapping(
+ struct process_context *pr_ctxt,
+ u32 mpu_addr, u32 size)
+{
+ struct dmm_map_object *map_obj;
+ pr_debug("%s: looking for mpu_addr 0x%x size 0x%x\n", __func__,
+ mpu_addr, size);
+
+ spin_lock(&pr_ctxt->dmm_map_lock);
+ list_for_each_entry(map_obj, &pr_ctxt->dmm_map_list, link) {
+ pr_debug("%s: candidate: mpu_addr 0x%x virt 0x%x size 0x%x\n",
+ __func__,
+ map_obj->mpu_addr,
+ map_obj->dsp_addr,
+ map_obj->size);
+ if (match_containing_map_obj(map_obj, mpu_addr, size)) {
+ pr_debug("%s: match!\n", __func__);
+ goto out;
+ }
+
+ pr_debug("%s: no match!\n", __func__);
+ }
+
+ map_obj = NULL;
+out:
+ spin_unlock(&pr_ctxt->dmm_map_lock);
+ return map_obj;
+}
+
+static int find_first_page_in_cache(struct dmm_map_object *map_obj,
+ unsigned long mpu_addr)
+{
+ u32 mapped_base_page = map_obj->mpu_addr >> PAGE_SHIFT;
+ u32 requested_base_page = mpu_addr >> PAGE_SHIFT;
+ int pg_index = requested_base_page - mapped_base_page;
+
+ if (pg_index < 0 || pg_index >= map_obj->num_usr_pgs) {
+ pr_err("%s: failed (got %d)\n", __func__, pg_index);
+ return -1;
+ }
+
+ pr_debug("%s: first page is %d\n", __func__, pg_index);
+ return pg_index;
+}
+
+static inline struct page *get_mapping_page(struct dmm_map_object *map_obj,
+ int pg_i)
+{
+ pr_debug("%s: looking for pg_i %d, num_usr_pgs: %d\n", __func__,
+ pg_i, map_obj->num_usr_pgs);
+
+ if (pg_i < 0 || pg_i >= map_obj->num_usr_pgs) {
+ pr_err("%s: requested pg_i %d is out of mapped range\n",
+ __func__, pg_i);
+ return NULL;
+ }
+
+ return map_obj->pages[pg_i];
+}
+
+/*
+ * ======== proc_attach ========
+ * Purpose:
+ * Prepare for communication with a particular DSP processor, and return
+ * a handle to the processor object.
+ */
+int
+proc_attach(u32 processor_id,
+ const struct dsp_processorattrin *attr_in,
+ void **ph_processor, struct process_context *pr_ctxt)
+{
+ int status = 0;
+ struct dev_object *hdev_obj;
+ struct proc_object *p_proc_object = NULL;
+ struct mgr_object *hmgr_obj = NULL;
+ struct drv_object *hdrv_obj = NULL;
+ u8 dev_type;
+
+ DBC_REQUIRE(refs > 0);
+ DBC_REQUIRE(ph_processor != NULL);
+
+ if (pr_ctxt->hprocessor) {
+ *ph_processor = pr_ctxt->hprocessor;
+ return status;
+ }
+
+ /* Get the Driver and Manager Object Handles */
+ status = cfg_get_object((u32 *) &hdrv_obj, REG_DRV_OBJECT);
+ if (!status)
+ status = cfg_get_object((u32 *) &hmgr_obj, REG_MGR_OBJECT);
+
+ if (!status) {
+ /* Get the Device Object */
+ status = drv_get_dev_object(processor_id, hdrv_obj, &hdev_obj);
+ }
+ if (!status)
+ status = dev_get_dev_type(hdev_obj, &dev_type);
+
+ if (status)
+ goto func_end;
+
+ /* If we made it this far, create the Proceesor object: */
+ p_proc_object = kzalloc(sizeof(struct proc_object), GFP_KERNEL);
+ /* Fill out the Processor Object: */
+ if (p_proc_object == NULL) {
+ status = -ENOMEM;
+ goto func_end;
+ }
+ p_proc_object->hdev_obj = hdev_obj;
+ p_proc_object->hmgr_obj = hmgr_obj;
+ p_proc_object->processor_id = dev_type;
+ /* Store TGID instead of process handle */
+ p_proc_object->process = current->tgid;
+
+ INIT_LIST_HEAD(&p_proc_object->proc_list);
+
+ if (attr_in)
+ p_proc_object->utimeout = attr_in->utimeout;
+ else
+ p_proc_object->utimeout = PROC_DFLT_TIMEOUT;
+
+ status = dev_get_intf_fxns(hdev_obj, &p_proc_object->intf_fxns);
+ if (!status) {
+ status = dev_get_bridge_context(hdev_obj,
+ &p_proc_object->hbridge_context);
+ if (status)
+ kfree(p_proc_object);
+ } else
+ kfree(p_proc_object);
+
+ if (status)
+ goto func_end;
+
+ /* Create the Notification Object */
+ /* This is created with no event mask, no notify mask
+ * and no valid handle to the notification. They all get
+ * filled up when proc_register_notify is called */
+ p_proc_object->ntfy_obj = kmalloc(sizeof(struct ntfy_object),
+ GFP_KERNEL);
+ if (p_proc_object->ntfy_obj)
+ ntfy_init(p_proc_object->ntfy_obj);
+ else
+ status = -ENOMEM;
+
+ if (!status) {
+ /* Insert the Processor Object into the DEV List.
+ * Return handle to this Processor Object:
+ * Find out if the Device is already attached to a
+ * Processor. If so, return AlreadyAttached status */
+ lst_init_elem(&p_proc_object->link);
+ status = dev_insert_proc_object(p_proc_object->hdev_obj,
+ (u32) p_proc_object,
+ &p_proc_object->
+ is_already_attached);
+ if (!status) {
+ if (p_proc_object->is_already_attached)
+ status = 0;
+ } else {
+ if (p_proc_object->ntfy_obj) {
+ ntfy_delete(p_proc_object->ntfy_obj);
+ kfree(p_proc_object->ntfy_obj);
+ }
+
+ kfree(p_proc_object);
+ }
+ if (!status) {
+ *ph_processor = (void *)p_proc_object;
+ pr_ctxt->hprocessor = *ph_processor;
+ (void)proc_notify_clients(p_proc_object,
+ DSP_PROCESSORATTACH);
+ }
+ } else {
+ /* Don't leak memory if status is failed */
+ kfree(p_proc_object);
+ }
+func_end:
+ DBC_ENSURE((status == -EPERM && *ph_processor == NULL) ||
+ (!status && p_proc_object) ||
+ (status == 0 && p_proc_object));
+
+ return status;
+}
+
+static int get_exec_file(struct cfg_devnode *dev_node_obj,
+ struct dev_object *hdev_obj,
+ u32 size, char *exec_file)
+{
+ u8 dev_type;
+ s32 len;
+
+ dev_get_dev_type(hdev_obj, (u8 *) &dev_type);
+ if (dev_type == DSP_UNIT) {
+ return cfg_get_exec_file(dev_node_obj, size, exec_file);
+ } else if (dev_type == IVA_UNIT) {
+ if (iva_img) {
+ len = strlen(iva_img);
+ strncpy(exec_file, iva_img, len + 1);
+ return 0;
+ }
+ }
+ return -ENOENT;
+}
+
+/*
+ * ======== proc_auto_start ======== =
+ * Purpose:
+ * A Particular device gets loaded with the default image
+ * if the AutoStart flag is set.
+ * Parameters:
+ * hdev_obj: Handle to the Device
+ * Returns:
+ * 0: On Successful Loading
+ * -EPERM General Failure
+ * Requires:
+ * hdev_obj != NULL
+ * Ensures:
+ */
+int proc_auto_start(struct cfg_devnode *dev_node_obj,
+ struct dev_object *hdev_obj)
+{
+ int status = -EPERM;
+ struct proc_object *p_proc_object;
+ char sz_exec_file[MAXCMDLINELEN];
+ char *argv[2];
+ struct mgr_object *hmgr_obj = NULL;
+ u8 dev_type;
+
+ DBC_REQUIRE(refs > 0);
+ DBC_REQUIRE(dev_node_obj != NULL);
+ DBC_REQUIRE(hdev_obj != NULL);
+
+ /* Create a Dummy PROC Object */
+ status = cfg_get_object((u32 *) &hmgr_obj, REG_MGR_OBJECT);
+ if (status)
+ goto func_end;
+
+ p_proc_object = kzalloc(sizeof(struct proc_object), GFP_KERNEL);
+ if (p_proc_object == NULL) {
+ status = -ENOMEM;
+ goto func_end;
+ }
+ p_proc_object->hdev_obj = hdev_obj;
+ p_proc_object->hmgr_obj = hmgr_obj;
+ status = dev_get_intf_fxns(hdev_obj, &p_proc_object->intf_fxns);
+ if (!status)
+ status = dev_get_bridge_context(hdev_obj,
+ &p_proc_object->hbridge_context);
+ if (status)
+ goto func_cont;
+
+ /* Stop the Device, put it into standby mode */
+ status = proc_stop(p_proc_object);
+
+ if (status)
+ goto func_cont;
+
+ /* Get the default executable for this board... */
+ dev_get_dev_type(hdev_obj, (u8 *) &dev_type);
+ p_proc_object->processor_id = dev_type;
+ status = get_exec_file(dev_node_obj, hdev_obj, sizeof(sz_exec_file),
+ sz_exec_file);
+ if (!status) {
+ argv[0] = sz_exec_file;
+ argv[1] = NULL;
+ /* ...and try to load it: */
+ status = proc_load(p_proc_object, 1, (const char **)argv, NULL);
+ if (!status)
+ status = proc_start(p_proc_object);
+ }
+ kfree(p_proc_object->psz_last_coff);
+ p_proc_object->psz_last_coff = NULL;
+func_cont:
+ kfree(p_proc_object);
+func_end:
+ return status;
+}
+
+/*
+ * ======== proc_ctrl ========
+ * Purpose:
+ * Pass control information to the GPP device driver managing the
+ * DSP processor.
+ *
+ * This will be an OEM-only function, and not part of the DSP/BIOS Bridge
+ * application developer's API.
+ * Call the bridge_dev_ctrl fxn with the Argument. This is a Synchronous
+ * Operation. arg can be null.
+ */
+int proc_ctrl(void *hprocessor, u32 dw_cmd, struct dsp_cbdata * arg)
+{
+ int status = 0;
+ struct proc_object *p_proc_object = hprocessor;
+ u32 timeout = 0;
+
+ DBC_REQUIRE(refs > 0);
+
+ if (p_proc_object) {
+ /* intercept PWR deep sleep command */
+ if (dw_cmd == BRDIOCTL_DEEPSLEEP) {
+ timeout = arg->cb_data;
+ status = pwr_sleep_dsp(PWR_DEEPSLEEP, timeout);
+ }
+ /* intercept PWR emergency sleep command */
+ else if (dw_cmd == BRDIOCTL_EMERGENCYSLEEP) {
+ timeout = arg->cb_data;
+ status = pwr_sleep_dsp(PWR_EMERGENCYDEEPSLEEP, timeout);
+ } else if (dw_cmd == PWR_DEEPSLEEP) {
+ /* timeout = arg->cb_data; */
+ status = pwr_sleep_dsp(PWR_DEEPSLEEP, timeout);
+ }
+ /* intercept PWR wake commands */
+ else if (dw_cmd == BRDIOCTL_WAKEUP) {
+ timeout = arg->cb_data;
+ status = pwr_wake_dsp(timeout);
+ } else if (dw_cmd == PWR_WAKEUP) {
+ /* timeout = arg->cb_data; */
+ status = pwr_wake_dsp(timeout);
+ } else
+ if (!((*p_proc_object->intf_fxns->pfn_dev_cntrl)
+ (p_proc_object->hbridge_context, dw_cmd,
+ arg))) {
+ status = 0;
+ } else {
+ status = -EPERM;
+ }
+ } else {
+ status = -EFAULT;
+ }
+
+ return status;
+}
+
+/*
+ * ======== proc_detach ========
+ * Purpose:
+ * Destroys the Processor Object. Removes the notification from the Dev
+ * List.
+ */
+int proc_detach(struct process_context *pr_ctxt)
+{
+ int status = 0;
+ struct proc_object *p_proc_object = NULL;
+
+ DBC_REQUIRE(refs > 0);
+
+ p_proc_object = (struct proc_object *)pr_ctxt->hprocessor;
+
+ if (p_proc_object) {
+ /* Notify the Client */
+ ntfy_notify(p_proc_object->ntfy_obj, DSP_PROCESSORDETACH);
+ /* Remove the notification memory */
+ if (p_proc_object->ntfy_obj) {
+ ntfy_delete(p_proc_object->ntfy_obj);
+ kfree(p_proc_object->ntfy_obj);
+ }
+
+ kfree(p_proc_object->psz_last_coff);
+ p_proc_object->psz_last_coff = NULL;
+ /* Remove the Proc from the DEV List */
+ (void)dev_remove_proc_object(p_proc_object->hdev_obj,
+ (u32) p_proc_object);
+ /* Free the Processor Object */
+ kfree(p_proc_object);
+ pr_ctxt->hprocessor = NULL;
+ } else {
+ status = -EFAULT;
+ }
+
+ return status;
+}
+
+/*
+ * ======== proc_enum_nodes ========
+ * Purpose:
+ * Enumerate and get configuration information about nodes allocated
+ * on a DSP processor.
+ */
+int proc_enum_nodes(void *hprocessor, void **node_tab,
+ u32 node_tab_size, u32 *pu_num_nodes,
+ u32 *pu_allocated)
+{
+ int status = -EPERM;
+ struct proc_object *p_proc_object = (struct proc_object *)hprocessor;
+ struct node_mgr *hnode_mgr = NULL;
+
+ DBC_REQUIRE(refs > 0);
+ DBC_REQUIRE(node_tab != NULL || node_tab_size == 0);
+ DBC_REQUIRE(pu_num_nodes != NULL);
+ DBC_REQUIRE(pu_allocated != NULL);
+
+ if (p_proc_object) {
+ if (!(dev_get_node_manager(p_proc_object->hdev_obj,
+ &hnode_mgr))) {
+ if (hnode_mgr) {
+ status = node_enum_nodes(hnode_mgr, node_tab,
+ node_tab_size,
+ pu_num_nodes,
+ pu_allocated);
+ }
+ }
+ } else {
+ status = -EFAULT;
+ }
+
+ return status;
+}
+
+/* Cache operation against kernel address instead of users */
+static int build_dma_sg(struct dmm_map_object *map_obj, unsigned long start,
+ ssize_t len, int pg_i)
+{
+ struct page *page;
+ unsigned long offset;
+ ssize_t rest;
+ int ret = 0, i = 0;
+ struct scatterlist *sg = map_obj->dma_info.sg;
+
+ while (len) {
+ page = get_mapping_page(map_obj, pg_i);
+ if (!page) {
+ pr_err("%s: no page for %08lx\n", __func__, start);
+ ret = -EINVAL;
+ goto out;
+ } else if (IS_ERR(page)) {
+ pr_err("%s: err page for %08lx(%lu)\n", __func__, start,
+ PTR_ERR(page));
+ ret = PTR_ERR(page);
+ goto out;
+ }
+
+ offset = start & ~PAGE_MASK;
+ rest = min_t(ssize_t, PAGE_SIZE - offset, len);
+
+ sg_set_page(&sg[i], page, rest, offset);
+
+ len -= rest;
+ start += rest;
+ pg_i++, i++;
+ }
+
+ if (i != map_obj->dma_info.num_pages) {
+ pr_err("%s: bad number of sg iterations\n", __func__);
+ ret = -EFAULT;
+ goto out;
+ }
+
+out:
+ return ret;
+}
+
+static int memory_regain_ownership(struct dmm_map_object *map_obj,
+ unsigned long start, ssize_t len, enum dma_data_direction dir)
+{
+ int ret = 0;
+ unsigned long first_data_page = start >> PAGE_SHIFT;
+ unsigned long last_data_page = ((u32)(start + len - 1) >> PAGE_SHIFT);
+ /* calculating the number of pages this area spans */
+ unsigned long num_pages = last_data_page - first_data_page + 1;
+ struct bridge_dma_map_info *dma_info = &map_obj->dma_info;
+
+ if (!dma_info->sg)
+ goto out;
+
+ if (dma_info->dir != dir || dma_info->num_pages != num_pages) {
+ pr_err("%s: dma info doesn't match given params\n", __func__);
+ return -EINVAL;
+ }
+
+ dma_unmap_sg(bridge, dma_info->sg, num_pages, dma_info->dir);
+
+ pr_debug("%s: dma_map_sg unmapped\n", __func__);
+
+ kfree(dma_info->sg);
+
+ map_obj->dma_info.sg = NULL;
+
+out:
+ return ret;
+}
+
+/* Cache operation against kernel address instead of users */
+static int memory_give_ownership(struct dmm_map_object *map_obj,
+ unsigned long start, ssize_t len, enum dma_data_direction dir)
+{
+ int pg_i, ret, sg_num;
+ struct scatterlist *sg;
+ unsigned long first_data_page = start >> PAGE_SHIFT;
+ unsigned long last_data_page = ((u32)(start + len - 1) >> PAGE_SHIFT);
+ /* calculating the number of pages this area spans */
+ unsigned long num_pages = last_data_page - first_data_page + 1;
+
+ pg_i = find_first_page_in_cache(map_obj, start);
+ if (pg_i < 0) {
+ pr_err("%s: failed to find first page in cache\n", __func__);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ sg = kcalloc(num_pages, sizeof(*sg), GFP_KERNEL);
+ if (!sg) {
+ pr_err("%s: kcalloc failed\n", __func__);
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ sg_init_table(sg, num_pages);
+
+ /* cleanup a previous sg allocation */
+ /* this may happen if application doesn't signal for e/o DMA */
+ kfree(map_obj->dma_info.sg);
+
+ map_obj->dma_info.sg = sg;
+ map_obj->dma_info.dir = dir;
+ map_obj->dma_info.num_pages = num_pages;
+
+ ret = build_dma_sg(map_obj, start, len, pg_i);
+ if (ret)
+ goto kfree_sg;
+
+ sg_num = dma_map_sg(bridge, sg, num_pages, dir);
+ if (sg_num < 1) {
+ pr_err("%s: dma_map_sg failed: %d\n", __func__, sg_num);
+ ret = -EFAULT;
+ goto kfree_sg;
+ }
+
+ pr_debug("%s: dma_map_sg mapped %d elements\n", __func__, sg_num);
+ map_obj->dma_info.sg_num = sg_num;
+
+ return 0;
+
+kfree_sg:
+ kfree(sg);
+ map_obj->dma_info.sg = NULL;
+out:
+ return ret;
+}
+
+int proc_begin_dma(void *hprocessor, void *pmpu_addr, u32 ul_size,
+ enum dma_data_direction dir)
+{
+ /* Keep STATUS here for future additions to this function */
+ int status = 0;
+ struct process_context *pr_ctxt = (struct process_context *) hprocessor;
+ struct dmm_map_object *map_obj;
+
+ DBC_REQUIRE(refs > 0);
+
+ if (!pr_ctxt) {
+ status = -EFAULT;
+ goto err_out;
+ }
+
+ pr_debug("%s: addr 0x%x, size 0x%x, type %d\n", __func__,
+ (u32)pmpu_addr,
+ ul_size, dir);
+
+ /* find requested memory are in cached mapping information */
+ map_obj = find_containing_mapping(pr_ctxt, (u32) pmpu_addr, ul_size);
+ if (!map_obj) {
+ pr_err("%s: find_containing_mapping failed\n", __func__);
+ status = -EFAULT;
+ goto err_out;
+ }
+
+ if (memory_give_ownership(map_obj, (u32) pmpu_addr, ul_size, dir)) {
+ pr_err("%s: InValid address parameters %p %x\n",
+ __func__, pmpu_addr, ul_size);
+ status = -EFAULT;
+ }
+
+err_out:
+
+ return status;
+}
+
+int proc_end_dma(void *hprocessor, void *pmpu_addr, u32 ul_size,
+ enum dma_data_direction dir)
+{
+ /* Keep STATUS here for future additions to this function */
+ int status = 0;
+ struct process_context *pr_ctxt = (struct process_context *) hprocessor;
+ struct dmm_map_object *map_obj;
+
+ DBC_REQUIRE(refs > 0);
+
+ if (!pr_ctxt) {
+ status = -EFAULT;
+ goto err_out;
+ }
+
+ pr_debug("%s: addr 0x%x, size 0x%x, type %d\n", __func__,
+ (u32)pmpu_addr,
+ ul_size, dir);
+
+ /* find requested memory are in cached mapping information */
+ map_obj = find_containing_mapping(pr_ctxt, (u32) pmpu_addr, ul_size);
+ if (!map_obj) {
+ pr_err("%s: find_containing_mapping failed\n", __func__);
+ status = -EFAULT;
+ goto err_out;
+ }
+
+ if (memory_regain_ownership(map_obj, (u32) pmpu_addr, ul_size, dir)) {
+ pr_err("%s: InValid address parameters %p %x\n",
+ __func__, pmpu_addr, ul_size);
+ status = -EFAULT;
+ goto err_out;
+ }
+
+err_out:
+ return status;
+}
+
+/*
+ * ======== proc_flush_memory ========
+ * Purpose:
+ * Flush cache
+ */
+int proc_flush_memory(void *hprocessor, void *pmpu_addr,
+ u32 ul_size, u32 ul_flags)
+{
+ enum dma_data_direction dir = DMA_BIDIRECTIONAL;
+
+ return proc_begin_dma(hprocessor, pmpu_addr, ul_size, dir);
+}
+
+/*
+ * ======== proc_invalidate_memory ========
+ * Purpose:
+ * Invalidates the memory specified
+ */
+int proc_invalidate_memory(void *hprocessor, void *pmpu_addr, u32 size)
+{
+ enum dma_data_direction dir = DMA_FROM_DEVICE;
+
+ return proc_begin_dma(hprocessor, pmpu_addr, size, dir);
+}
+
+/*
+ * ======== proc_get_resource_info ========
+ * Purpose:
+ * Enumerate the resources currently available on a processor.
+ */
+int proc_get_resource_info(void *hprocessor, u32 resource_type,
+ struct dsp_resourceinfo *resource_info,
+ u32 resource_info_size)
+{
+ int status = -EPERM;
+ struct proc_object *p_proc_object = (struct proc_object *)hprocessor;
+ struct node_mgr *hnode_mgr = NULL;
+ struct nldr_object *nldr_obj = NULL;
+ struct rmm_target_obj *rmm = NULL;
+ struct io_mgr *hio_mgr = NULL; /* IO manager handle */
+
+ DBC_REQUIRE(refs > 0);
+ DBC_REQUIRE(resource_info != NULL);
+ DBC_REQUIRE(resource_info_size >= sizeof(struct dsp_resourceinfo));
+
+ if (!p_proc_object) {
+ status = -EFAULT;
+ goto func_end;
+ }
+ switch (resource_type) {
+ case DSP_RESOURCE_DYNDARAM:
+ case DSP_RESOURCE_DYNSARAM:
+ case DSP_RESOURCE_DYNEXTERNAL:
+ case DSP_RESOURCE_DYNSRAM:
+ status = dev_get_node_manager(p_proc_object->hdev_obj,
+ &hnode_mgr);
+ if (!hnode_mgr) {
+ status = -EFAULT;
+ goto func_end;
+ }
+
+ status = node_get_nldr_obj(hnode_mgr, &nldr_obj);
+ if (!status) {
+ status = nldr_get_rmm_manager(nldr_obj, &rmm);
+ if (rmm) {
+ if (!rmm_stat(rmm,
+ (enum dsp_memtype)resource_type,
+ (struct dsp_memstat *)
+ &(resource_info->result.
+ mem_stat)))
+ status = -EINVAL;
+ } else {
+ status = -EFAULT;
+ }
+ }
+ break;
+ case DSP_RESOURCE_PROCLOAD:
+ status = dev_get_io_mgr(p_proc_object->hdev_obj, &hio_mgr);
+ if (hio_mgr)
+ status =
+ p_proc_object->intf_fxns->
+ pfn_io_get_proc_load(hio_mgr,
+ (struct dsp_procloadstat *)
+ &(resource_info->result.
+ proc_load_stat));
+ else
+ status = -EFAULT;
+ break;
+ default:
+ status = -EPERM;
+ break;
+ }
+func_end:
+ return status;
+}
+
+/*
+ * ======== proc_exit ========
+ * Purpose:
+ * Decrement reference count, and free resources when reference count is
+ * 0.
+ */
+void proc_exit(void)
+{
+ DBC_REQUIRE(refs > 0);
+
+ refs--;
+
+ DBC_ENSURE(refs >= 0);
+}
+
+/*
+ * ======== proc_get_dev_object ========
+ * Purpose:
+ * Return the Dev Object handle for a given Processor.
+ *
+ */
+int proc_get_dev_object(void *hprocessor,
+ struct dev_object **device_obj)
+{
+ int status = -EPERM;
+ struct proc_object *p_proc_object = (struct proc_object *)hprocessor;
+
+ DBC_REQUIRE(refs > 0);
+ DBC_REQUIRE(device_obj != NULL);
+
+ if (p_proc_object) {
+ *device_obj = p_proc_object->hdev_obj;
+ status = 0;
+ } else {
+ *device_obj = NULL;
+ status = -EFAULT;
+ }
+
+ DBC_ENSURE((!status && *device_obj != NULL) ||
+ (status && *device_obj == NULL));
+
+ return status;
+}
+
+/*
+ * ======== proc_get_state ========
+ * Purpose:
+ * Report the state of the specified DSP processor.
+ */
+int proc_get_state(void *hprocessor,
+ struct dsp_processorstate *proc_state_obj,
+ u32 state_info_size)
+{
+ int status = 0;
+ struct proc_object *p_proc_object = (struct proc_object *)hprocessor;
+ int brd_status;
+
+ DBC_REQUIRE(refs > 0);
+ DBC_REQUIRE(proc_state_obj != NULL);
+ DBC_REQUIRE(state_info_size >= sizeof(struct dsp_processorstate));
+
+ if (p_proc_object) {
+ /* First, retrieve BRD state information */
+ status = (*p_proc_object->intf_fxns->pfn_brd_status)
+ (p_proc_object->hbridge_context, &brd_status);
+ if (!status) {
+ switch (brd_status) {
+ case BRD_STOPPED:
+ proc_state_obj->proc_state = PROC_STOPPED;
+ break;
+ case BRD_SLEEP_TRANSITION:
+ case BRD_DSP_HIBERNATION:
+ /* Fall through */
+ case BRD_RUNNING:
+ proc_state_obj->proc_state = PROC_RUNNING;
+ break;
+ case BRD_LOADED:
+ proc_state_obj->proc_state = PROC_LOADED;
+ break;
+ case BRD_ERROR:
+ proc_state_obj->proc_state = PROC_ERROR;
+ break;
+ default:
+ proc_state_obj->proc_state = 0xFF;
+ status = -EPERM;
+ break;
+ }
+ }
+ } else {
+ status = -EFAULT;
+ }
+ dev_dbg(bridge, "%s, results: status: 0x%x proc_state_obj: 0x%x\n",
+ __func__, status, proc_state_obj->proc_state);
+ return status;
+}
+
+/*
+ * ======== proc_get_trace ========
+ * Purpose:
+ * Retrieve the current contents of the trace buffer, located on the
+ * Processor. Predefined symbols for the trace buffer must have been
+ * configured into the DSP executable.
+ * Details:
+ * We support using the symbols SYS_PUTCBEG and SYS_PUTCEND to define a
+ * trace buffer, only. Treat it as an undocumented feature.
+ * This call is destructive, meaning the processor is placed in the monitor
+ * state as a result of this function.
+ */
+int proc_get_trace(void *hprocessor, u8 * pbuf, u32 max_size)
+{
+ int status;
+ status = -ENOSYS;
+ return status;
+}
+
+/*
+ * ======== proc_init ========
+ * Purpose:
+ * Initialize PROC's private state, keeping a reference count on each call
+ */
+bool proc_init(void)
+{
+ bool ret = true;
+
+ DBC_REQUIRE(refs >= 0);
+
+ if (ret)
+ refs++;
+
+ DBC_ENSURE((ret && (refs > 0)) || (!ret && (refs >= 0)));
+
+ return ret;
+}
+
+/*
+ * ======== proc_load ========
+ * Purpose:
+ * Reset a processor and load a new base program image.
+ * This will be an OEM-only function, and not part of the DSP/BIOS Bridge
+ * application developer's API.
+ */
+int proc_load(void *hprocessor, const s32 argc_index,
+ const char **user_args, const char **user_envp)
+{
+ int status = 0;
+ struct proc_object *p_proc_object = (struct proc_object *)hprocessor;
+ struct io_mgr *hio_mgr; /* IO manager handle */
+ struct msg_mgr *hmsg_mgr;
+ struct cod_manager *cod_mgr; /* Code manager handle */
+ char *pargv0; /* temp argv[0] ptr */
+ char **new_envp; /* Updated envp[] array. */
+ char sz_proc_id[MAXPROCIDLEN]; /* Size of "PROC_ID=<n>" */
+ s32 envp_elems; /* Num elements in envp[]. */
+ s32 cnew_envp; /* " " in new_envp[] */
+ s32 nproc_id = 0; /* Anticipate MP version. */
+ struct dcd_manager *hdcd_handle;
+ struct dmm_object *dmm_mgr;
+ u32 dw_ext_end;
+ u32 proc_id;
+ int brd_state;
+ struct drv_data *drv_datap = dev_get_drvdata(bridge);
+
+#ifdef OPT_LOAD_TIME_INSTRUMENTATION
+ struct timeval tv1;
+ struct timeval tv2;
+#endif
+
+#if defined(CONFIG_TIDSPBRIDGE_DVFS) && !defined(CONFIG_CPU_FREQ)
+ struct dspbridge_platform_data *pdata =
+ omap_dspbridge_dev->dev.platform_data;
+#endif
+
+ DBC_REQUIRE(refs > 0);
+ DBC_REQUIRE(argc_index > 0);
+ DBC_REQUIRE(user_args != NULL);
+
+#ifdef OPT_LOAD_TIME_INSTRUMENTATION
+ do_gettimeofday(&tv1);
+#endif
+ if (!p_proc_object) {
+ status = -EFAULT;
+ goto func_end;
+ }
+ dev_get_cod_mgr(p_proc_object->hdev_obj, &cod_mgr);
+ if (!cod_mgr) {
+ status = -EPERM;
+ goto func_end;
+ }
+ status = proc_stop(hprocessor);
+ if (status)
+ goto func_end;
+
+ /* Place the board in the monitor state. */
+ status = proc_monitor(hprocessor);
+ if (status)
+ goto func_end;
+
+ /* Save ptr to original argv[0]. */
+ pargv0 = (char *)user_args[0];
+ /*Prepend "PROC_ID=<nproc_id>"to envp array for target. */
+ envp_elems = get_envp_count((char **)user_envp);
+ cnew_envp = (envp_elems ? (envp_elems + 1) : (envp_elems + 2));
+ new_envp = kzalloc(cnew_envp * sizeof(char **), GFP_KERNEL);
+ if (new_envp) {
+ status = snprintf(sz_proc_id, MAXPROCIDLEN, PROC_ENVPROCID,
+ nproc_id);
+ if (status == -1) {
+ dev_dbg(bridge, "%s: Proc ID string overflow\n",
+ __func__);
+ status = -EPERM;
+ } else {
+ new_envp =
+ prepend_envp(new_envp, (char **)user_envp,
+ envp_elems, cnew_envp, sz_proc_id);
+ /* Get the DCD Handle */
+ status = mgr_get_dcd_handle(p_proc_object->hmgr_obj,
+ (u32 *) &hdcd_handle);
+ if (!status) {
+ /* Before proceeding with new load,
+ * check if a previously registered COFF
+ * exists.
+ * If yes, unregister nodes in previously
+ * registered COFF. If any error occurred,
+ * set previously registered COFF to NULL. */
+ if (p_proc_object->psz_last_coff != NULL) {
+ status =
+ dcd_auto_unregister(hdcd_handle,
+ p_proc_object->
+ psz_last_coff);
+ /* Regardless of auto unregister status,
+ * free previously allocated
+ * memory. */
+ kfree(p_proc_object->psz_last_coff);
+ p_proc_object->psz_last_coff = NULL;
+ }
+ }
+ /* On success, do cod_open_base() */
+ status = cod_open_base(cod_mgr, (char *)user_args[0],
+ COD_SYMB);
+ }
+ } else {
+ status = -ENOMEM;
+ }
+ if (!status) {
+ /* Auto-register data base */
+ /* Get the DCD Handle */
+ status = mgr_get_dcd_handle(p_proc_object->hmgr_obj,
+ (u32 *) &hdcd_handle);
+ if (!status) {
+ /* Auto register nodes in specified COFF
+ * file. If registration did not fail,
+ * (status = 0 or -EACCES)
+ * save the name of the COFF file for
+ * de-registration in the future. */
+ status =
+ dcd_auto_register(hdcd_handle,
+ (char *)user_args[0]);
+ if (status == -EACCES)
+ status = 0;
+
+ if (status) {
+ status = -EPERM;
+ } else {
+ DBC_ASSERT(p_proc_object->psz_last_coff ==
+ NULL);
+ /* Allocate memory for pszLastCoff */
+ p_proc_object->psz_last_coff =
+ kzalloc((strlen(user_args[0]) +
+ 1), GFP_KERNEL);
+ /* If memory allocated, save COFF file name */
+ if (p_proc_object->psz_last_coff) {
+ strncpy(p_proc_object->psz_last_coff,
+ (char *)user_args[0],
+ (strlen((char *)user_args[0]) +
+ 1));
+ }
+ }
+ }
+ }
+ /* Update shared memory address and size */
+ if (!status) {
+ /* Create the message manager. This must be done
+ * before calling the IOOnLoaded function. */
+ dev_get_msg_mgr(p_proc_object->hdev_obj, &hmsg_mgr);
+ if (!hmsg_mgr) {
+ status = msg_create(&hmsg_mgr, p_proc_object->hdev_obj,
+ (msg_onexit) node_on_exit);
+ DBC_ASSERT(!status);
+ dev_set_msg_mgr(p_proc_object->hdev_obj, hmsg_mgr);
+ }
+ }
+ if (!status) {
+ /* Set the Device object's message manager */
+ status = dev_get_io_mgr(p_proc_object->hdev_obj, &hio_mgr);
+ if (hio_mgr)
+ status = (*p_proc_object->intf_fxns->pfn_io_on_loaded)
+ (hio_mgr);
+ else
+ status = -EFAULT;
+ }
+ if (!status) {
+ /* Now, attempt to load an exec: */
+
+ /* Boost the OPP level to Maximum level supported by baseport */
+#if defined(CONFIG_TIDSPBRIDGE_DVFS) && !defined(CONFIG_CPU_FREQ)
+ if (pdata->cpu_set_freq)
+ (*pdata->cpu_set_freq) (pdata->mpu_speed[VDD1_OPP5]);
+#endif
+ status = cod_load_base(cod_mgr, argc_index, (char **)user_args,
+ dev_brd_write_fxn,
+ p_proc_object->hdev_obj, NULL);
+ if (status) {
+ if (status == -EBADF) {
+ dev_dbg(bridge, "%s: Failure to Load the EXE\n",
+ __func__);
+ }
+ if (status == -ESPIPE) {
+ pr_err("%s: Couldn't parse the file\n",
+ __func__);
+ }
+ }
+ /* Requesting the lowest opp supported */
+#if defined(CONFIG_TIDSPBRIDGE_DVFS) && !defined(CONFIG_CPU_FREQ)
+ if (pdata->cpu_set_freq)
+ (*pdata->cpu_set_freq) (pdata->mpu_speed[VDD1_OPP1]);
+#endif
+
+ }
+ if (!status) {
+ /* Update the Processor status to loaded */
+ status = (*p_proc_object->intf_fxns->pfn_brd_set_state)
+ (p_proc_object->hbridge_context, BRD_LOADED);
+ if (!status) {
+ p_proc_object->proc_state = PROC_LOADED;
+ if (p_proc_object->ntfy_obj)
+ proc_notify_clients(p_proc_object,
+ DSP_PROCESSORSTATECHANGE);
+ }
+ }
+ if (!status) {
+ status = proc_get_processor_id(hprocessor, &proc_id);
+ if (proc_id == DSP_UNIT) {
+ /* Use all available DSP address space after EXTMEM
+ * for DMM */
+ if (!status)
+ status = cod_get_sym_value(cod_mgr, EXTEND,
+ &dw_ext_end);
+
+ /* Reset DMM structs and add an initial free chunk */
+ if (!status) {
+ status =
+ dev_get_dmm_mgr(p_proc_object->hdev_obj,
+ &dmm_mgr);
+ if (dmm_mgr) {
+ /* Set dw_ext_end to DMM START u8
+ * address */
+ dw_ext_end =
+ (dw_ext_end + 1) * DSPWORDSIZE;
+ /* DMM memory is from EXT_END */
+ status = dmm_create_tables(dmm_mgr,
+ dw_ext_end,
+ DMMPOOLSIZE);
+ } else {
+ status = -EFAULT;
+ }
+ }
+ }
+ }
+ /* Restore the original argv[0] */
+ kfree(new_envp);
+ user_args[0] = pargv0;
+ if (!status) {
+ if (!((*p_proc_object->intf_fxns->pfn_brd_status)
+ (p_proc_object->hbridge_context, &brd_state))) {
+ pr_info("%s: Processor Loaded %s\n", __func__, pargv0);
+ kfree(drv_datap->base_img);
+ drv_datap->base_img = kmalloc(strlen(pargv0) + 1,
+ GFP_KERNEL);
+ if (drv_datap->base_img)
+ strncpy(drv_datap->base_img, pargv0,
+ strlen(pargv0) + 1);
+ else
+ status = -ENOMEM;
+ DBC_ASSERT(brd_state == BRD_LOADED);
+ }
+ }
+
+func_end:
+ if (status) {
+ pr_err("%s: Processor failed to load\n", __func__);
+ proc_stop(p_proc_object);
+ }
+ DBC_ENSURE((!status
+ && p_proc_object->proc_state == PROC_LOADED)
+ || status);
+#ifdef OPT_LOAD_TIME_INSTRUMENTATION
+ do_gettimeofday(&tv2);
+ if (tv2.tv_usec < tv1.tv_usec) {
+ tv2.tv_usec += 1000000;
+ tv2.tv_sec--;
+ }
+ dev_dbg(bridge, "%s: time to load %d sec and %d usec\n", __func__,
+ tv2.tv_sec - tv1.tv_sec, tv2.tv_usec - tv1.tv_usec);
+#endif
+ return status;
+}
+
+/*
+ * ======== proc_map ========
+ * Purpose:
+ * Maps a MPU buffer to DSP address space.
+ */
+int proc_map(void *hprocessor, void *pmpu_addr, u32 ul_size,
+ void *req_addr, void **pp_map_addr, u32 ul_map_attr,
+ struct process_context *pr_ctxt)
+{
+ u32 va_align;
+ u32 pa_align;
+ struct dmm_object *dmm_mgr;
+ u32 size_align;
+ int status = 0;
+ struct proc_object *p_proc_object = (struct proc_object *)hprocessor;
+ struct dmm_map_object *map_obj;
+ u32 tmp_addr = 0;
+
+#ifdef CONFIG_TIDSPBRIDGE_CACHE_LINE_CHECK
+ if ((ul_map_attr & BUFMODE_MASK) != RBUF) {
+ if (!IS_ALIGNED((u32)pmpu_addr, DSP_CACHE_LINE) ||
+ !IS_ALIGNED(ul_size, DSP_CACHE_LINE)) {
+ pr_err("%s: not aligned: 0x%x (%d)\n", __func__,
+ (u32)pmpu_addr, ul_size);
+ return -EFAULT;
+ }
+ }
+#endif
+
+ /* Calculate the page-aligned PA, VA and size */
+ va_align = PG_ALIGN_LOW((u32) req_addr, PG_SIZE4K);
+ pa_align = PG_ALIGN_LOW((u32) pmpu_addr, PG_SIZE4K);
+ size_align = PG_ALIGN_HIGH(ul_size + (u32) pmpu_addr - pa_align,
+ PG_SIZE4K);
+
+ if (!p_proc_object) {
+ status = -EFAULT;
+ goto func_end;
+ }
+ /* Critical section */
+ mutex_lock(&proc_lock);
+ dmm_get_handle(p_proc_object, &dmm_mgr);
+ if (dmm_mgr)
+ status = dmm_map_memory(dmm_mgr, va_align, size_align);
+ else
+ status = -EFAULT;
+
+ /* Add mapping to the page tables. */
+ if (!status) {
+
+ /* Mapped address = MSB of VA | LSB of PA */
+ tmp_addr = (va_align | ((u32) pmpu_addr & (PG_SIZE4K - 1)));
+ /* mapped memory resource tracking */
+ map_obj = add_mapping_info(pr_ctxt, pa_align, tmp_addr,
+ size_align);
+ if (!map_obj)
+ status = -ENOMEM;
+ else
+ status = (*p_proc_object->intf_fxns->pfn_brd_mem_map)
+ (p_proc_object->hbridge_context, pa_align, va_align,
+ size_align, ul_map_attr, map_obj->pages);
+ }
+ if (!status) {
+ /* Mapped address = MSB of VA | LSB of PA */
+ *pp_map_addr = (void *) tmp_addr;
+ } else {
+ remove_mapping_information(pr_ctxt, tmp_addr, size_align);
+ dmm_un_map_memory(dmm_mgr, va_align, &size_align);
+ }
+ mutex_unlock(&proc_lock);
+
+ if (status)
+ goto func_end;
+
+func_end:
+ dev_dbg(bridge, "%s: hprocessor %p, pmpu_addr %p, ul_size %x, "
+ "req_addr %p, ul_map_attr %x, pp_map_addr %p, va_align %x, "
+ "pa_align %x, size_align %x status 0x%x\n", __func__,
+ hprocessor, pmpu_addr, ul_size, req_addr, ul_map_attr,
+ pp_map_addr, va_align, pa_align, size_align, status);
+
+ return status;
+}
+
+/*
+ * ======== proc_register_notify ========
+ * Purpose:
+ * Register to be notified of specific processor events.
+ */
+int proc_register_notify(void *hprocessor, u32 event_mask,
+ u32 notify_type, struct dsp_notification
+ * hnotification)
+{
+ int status = 0;
+ struct proc_object *p_proc_object = (struct proc_object *)hprocessor;
+ struct deh_mgr *hdeh_mgr;
+
+ DBC_REQUIRE(hnotification != NULL);
+ DBC_REQUIRE(refs > 0);
+
+ /* Check processor handle */
+ if (!p_proc_object) {
+ status = -EFAULT;
+ goto func_end;
+ }
+ /* Check if event mask is a valid processor related event */
+ if (event_mask & ~(DSP_PROCESSORSTATECHANGE | DSP_PROCESSORATTACH |
+ DSP_PROCESSORDETACH | DSP_PROCESSORRESTART |
+ DSP_MMUFAULT | DSP_SYSERROR | DSP_PWRERROR |
+ DSP_WDTOVERFLOW))
+ status = -EINVAL;
+
+ /* Check if notify type is valid */
+ if (notify_type != DSP_SIGNALEVENT)
+ status = -EINVAL;
+
+ if (!status) {
+ /* If event mask is not DSP_SYSERROR, DSP_MMUFAULT,
+ * or DSP_PWRERROR then register event immediately. */
+ if (event_mask &
+ ~(DSP_SYSERROR | DSP_MMUFAULT | DSP_PWRERROR |
+ DSP_WDTOVERFLOW)) {
+ status = ntfy_register(p_proc_object->ntfy_obj,
+ hnotification, event_mask,
+ notify_type);
+ /* Special case alert, special case alert!
+ * If we're trying to *deregister* (i.e. event_mask
+ * is 0), a DSP_SYSERROR or DSP_MMUFAULT notification,
+ * we have to deregister with the DEH manager.
+ * There's no way to know, based on event_mask which
+ * manager the notification event was registered with,
+ * so if we're trying to deregister and ntfy_register
+ * failed, we'll give the deh manager a shot.
+ */
+ if ((event_mask == 0) && status) {
+ status =
+ dev_get_deh_mgr(p_proc_object->hdev_obj,
+ &hdeh_mgr);
+ status =
+ bridge_deh_register_notify(hdeh_mgr,
+ event_mask,
+ notify_type,
+ hnotification);
+ }
+ } else {
+ status = dev_get_deh_mgr(p_proc_object->hdev_obj,
+ &hdeh_mgr);
+ status =
+ bridge_deh_register_notify(hdeh_mgr,
+ event_mask,
+ notify_type,
+ hnotification);
+
+ }
+ }
+func_end:
+ return status;
+}
+
+/*
+ * ======== proc_reserve_memory ========
+ * Purpose:
+ * Reserve a virtually contiguous region of DSP address space.
+ */
+int proc_reserve_memory(void *hprocessor, u32 ul_size,
+ void **pp_rsv_addr,
+ struct process_context *pr_ctxt)
+{
+ struct dmm_object *dmm_mgr;
+ int status = 0;
+ struct proc_object *p_proc_object = (struct proc_object *)hprocessor;
+ struct dmm_rsv_object *rsv_obj;
+
+ if (!p_proc_object) {
+ status = -EFAULT;
+ goto func_end;
+ }
+
+ status = dmm_get_handle(p_proc_object, &dmm_mgr);
+ if (!dmm_mgr) {
+ status = -EFAULT;
+ goto func_end;
+ }
+
+ status = dmm_reserve_memory(dmm_mgr, ul_size, (u32 *) pp_rsv_addr);
+ if (status != 0)
+ goto func_end;
+
+ /*
+ * A successful reserve should be followed by insertion of rsv_obj
+ * into dmm_rsv_list, so that reserved memory resource tracking
+ * remains uptodate
+ */
+ rsv_obj = kmalloc(sizeof(struct dmm_rsv_object), GFP_KERNEL);
+ if (rsv_obj) {
+ rsv_obj->dsp_reserved_addr = (u32) *pp_rsv_addr;
+ spin_lock(&pr_ctxt->dmm_rsv_lock);
+ list_add(&rsv_obj->link, &pr_ctxt->dmm_rsv_list);
+ spin_unlock(&pr_ctxt->dmm_rsv_lock);
+ }
+
+func_end:
+ dev_dbg(bridge, "%s: hprocessor: 0x%p ul_size: 0x%x pp_rsv_addr: 0x%p "
+ "status 0x%x\n", __func__, hprocessor,
+ ul_size, pp_rsv_addr, status);
+ return status;
+}
+
+/*
+ * ======== proc_start ========
+ * Purpose:
+ * Start a processor running.
+ */
+int proc_start(void *hprocessor)
+{
+ int status = 0;
+ struct proc_object *p_proc_object = (struct proc_object *)hprocessor;
+ struct cod_manager *cod_mgr; /* Code manager handle */
+ u32 dw_dsp_addr; /* Loaded code's entry point. */
+ int brd_state;
+
+ DBC_REQUIRE(refs > 0);
+ if (!p_proc_object) {
+ status = -EFAULT;
+ goto func_end;
+ }
+ /* Call the bridge_brd_start */
+ if (p_proc_object->proc_state != PROC_LOADED) {
+ status = -EBADR;
+ goto func_end;
+ }
+ status = dev_get_cod_mgr(p_proc_object->hdev_obj, &cod_mgr);
+ if (!cod_mgr) {
+ status = -EFAULT;
+ goto func_cont;
+ }
+
+ status = cod_get_entry(cod_mgr, &dw_dsp_addr);
+ if (status)
+ goto func_cont;
+
+ status = (*p_proc_object->intf_fxns->pfn_brd_start)
+ (p_proc_object->hbridge_context, dw_dsp_addr);
+ if (status)
+ goto func_cont;
+
+ /* Call dev_create2 */
+ status = dev_create2(p_proc_object->hdev_obj);
+ if (!status) {
+ p_proc_object->proc_state = PROC_RUNNING;
+ /* Deep sleep switces off the peripheral clocks.
+ * we just put the DSP CPU in idle in the idle loop.
+ * so there is no need to send a command to DSP */
+
+ if (p_proc_object->ntfy_obj) {
+ proc_notify_clients(p_proc_object,
+ DSP_PROCESSORSTATECHANGE);
+ }
+ } else {
+ /* Failed to Create Node Manager and DISP Object
+ * Stop the Processor from running. Put it in STOPPED State */
+ (void)(*p_proc_object->intf_fxns->
+ pfn_brd_stop) (p_proc_object->hbridge_context);
+ p_proc_object->proc_state = PROC_STOPPED;
+ }
+func_cont:
+ if (!status) {
+ if (!((*p_proc_object->intf_fxns->pfn_brd_status)
+ (p_proc_object->hbridge_context, &brd_state))) {
+ pr_info("%s: dsp in running state\n", __func__);
+ DBC_ASSERT(brd_state != BRD_HIBERNATION);
+ }
+ } else {
+ pr_err("%s: Failed to start the dsp\n", __func__);
+ proc_stop(p_proc_object);
+ }
+
+func_end:
+ DBC_ENSURE((!status && p_proc_object->proc_state ==
+ PROC_RUNNING) || status);
+ return status;
+}
+
+/*
+ * ======== proc_stop ========
+ * Purpose:
+ * Stop a processor running.
+ */
+int proc_stop(void *hprocessor)
+{
+ int status = 0;
+ struct proc_object *p_proc_object = (struct proc_object *)hprocessor;
+ struct msg_mgr *hmsg_mgr;
+ struct node_mgr *hnode_mgr;
+ void *hnode;
+ u32 node_tab_size = 1;
+ u32 num_nodes = 0;
+ u32 nodes_allocated = 0;
+ int brd_state;
+
+ DBC_REQUIRE(refs > 0);
+ if (!p_proc_object) {
+ status = -EFAULT;
+ goto func_end;
+ }
+ /* check if there are any running nodes */
+ status = dev_get_node_manager(p_proc_object->hdev_obj, &hnode_mgr);
+ if (!status && hnode_mgr) {
+ status = node_enum_nodes(hnode_mgr, &hnode, node_tab_size,
+ &num_nodes, &nodes_allocated);
+ if ((status == -EINVAL) || (nodes_allocated > 0)) {
+ pr_err("%s: Can't stop device, active nodes = %d \n",
+ __func__, nodes_allocated);
+ return -EBADR;
+ }
+ }
+ /* Call the bridge_brd_stop */
+ /* It is OK to stop a device that does n't have nodes OR not started */
+ status =
+ (*p_proc_object->intf_fxns->
+ pfn_brd_stop) (p_proc_object->hbridge_context);
+ if (!status) {
+ dev_dbg(bridge, "%s: processor in standby mode\n", __func__);
+ p_proc_object->proc_state = PROC_STOPPED;
+ /* Destory the Node Manager, msg_ctrl Manager */
+ if (!(dev_destroy2(p_proc_object->hdev_obj))) {
+ /* Destroy the msg_ctrl by calling msg_delete */
+ dev_get_msg_mgr(p_proc_object->hdev_obj, &hmsg_mgr);
+ if (hmsg_mgr) {
+ msg_delete(hmsg_mgr);
+ dev_set_msg_mgr(p_proc_object->hdev_obj, NULL);
+ }
+ if (!((*p_proc_object->
+ intf_fxns->pfn_brd_status) (p_proc_object->
+ hbridge_context,
+ &brd_state)))
+ DBC_ASSERT(brd_state == BRD_STOPPED);
+ }
+ } else {
+ pr_err("%s: Failed to stop the processor\n", __func__);
+ }
+func_end:
+
+ return status;
+}
+
+/*
+ * ======== proc_un_map ========
+ * Purpose:
+ * Removes a MPU buffer mapping from the DSP address space.
+ */
+int proc_un_map(void *hprocessor, void *map_addr,
+ struct process_context *pr_ctxt)
+{
+ int status = 0;
+ struct proc_object *p_proc_object = (struct proc_object *)hprocessor;
+ struct dmm_object *dmm_mgr;
+ u32 va_align;
+ u32 size_align;
+
+ va_align = PG_ALIGN_LOW((u32) map_addr, PG_SIZE4K);
+ if (!p_proc_object) {
+ status = -EFAULT;
+ goto func_end;
+ }
+
+ status = dmm_get_handle(hprocessor, &dmm_mgr);
+ if (!dmm_mgr) {
+ status = -EFAULT;
+ goto func_end;
+ }
+
+ /* Critical section */
+ mutex_lock(&proc_lock);
+ /*
+ * Update DMM structures. Get the size to unmap.
+ * This function returns error if the VA is not mapped
+ */
+ status = dmm_un_map_memory(dmm_mgr, (u32) va_align, &size_align);
+ /* Remove mapping from the page tables. */
+ if (!status) {
+ status = (*p_proc_object->intf_fxns->pfn_brd_mem_un_map)
+ (p_proc_object->hbridge_context, va_align, size_align);
+ }
+
+ mutex_unlock(&proc_lock);
+ if (status)
+ goto func_end;
+
+ /*
+ * A successful unmap should be followed by removal of map_obj
+ * from dmm_map_list, so that mapped memory resource tracking
+ * remains uptodate
+ */
+ remove_mapping_information(pr_ctxt, (u32) map_addr, size_align);
+
+func_end:
+ dev_dbg(bridge, "%s: hprocessor: 0x%p map_addr: 0x%p status: 0x%x\n",
+ __func__, hprocessor, map_addr, status);
+ return status;
+}
+
+/*
+ * ======== proc_un_reserve_memory ========
+ * Purpose:
+ * Frees a previously reserved region of DSP address space.
+ */
+int proc_un_reserve_memory(void *hprocessor, void *prsv_addr,
+ struct process_context *pr_ctxt)
+{
+ struct dmm_object *dmm_mgr;
+ int status = 0;
+ struct proc_object *p_proc_object = (struct proc_object *)hprocessor;
+ struct dmm_rsv_object *rsv_obj;
+
+ if (!p_proc_object) {
+ status = -EFAULT;
+ goto func_end;
+ }
+
+ status = dmm_get_handle(p_proc_object, &dmm_mgr);
+ if (!dmm_mgr) {
+ status = -EFAULT;
+ goto func_end;
+ }
+
+ status = dmm_un_reserve_memory(dmm_mgr, (u32) prsv_addr);
+ if (status != 0)
+ goto func_end;
+
+ /*
+ * A successful unreserve should be followed by removal of rsv_obj
+ * from dmm_rsv_list, so that reserved memory resource tracking
+ * remains uptodate
+ */
+ spin_lock(&pr_ctxt->dmm_rsv_lock);
+ list_for_each_entry(rsv_obj, &pr_ctxt->dmm_rsv_list, link) {
+ if (rsv_obj->dsp_reserved_addr == (u32) prsv_addr) {
+ list_del(&rsv_obj->link);
+ kfree(rsv_obj);
+ break;
+ }
+ }
+ spin_unlock(&pr_ctxt->dmm_rsv_lock);
+
+func_end:
+ dev_dbg(bridge, "%s: hprocessor: 0x%p prsv_addr: 0x%p status: 0x%x\n",
+ __func__, hprocessor, prsv_addr, status);
+ return status;
+}
+
+/*
+ * ======== = proc_monitor ======== ==
+ * Purpose:
+ * Place the Processor in Monitor State. This is an internal
+ * function and a requirement before Processor is loaded.
+ * This does a bridge_brd_stop, dev_destroy2 and bridge_brd_monitor.
+ * In dev_destroy2 we delete the node manager.
+ * Parameters:
+ * p_proc_object: Pointer to Processor Object
+ * Returns:
+ * 0: Processor placed in monitor mode.
+ * !0: Failed to place processor in monitor mode.
+ * Requires:
+ * Valid Processor Handle
+ * Ensures:
+ * Success: ProcObject state is PROC_IDLE
+ */
+static int proc_monitor(struct proc_object *proc_obj)
+{
+ int status = -EPERM;
+ struct msg_mgr *hmsg_mgr;
+ int brd_state;
+
+ DBC_REQUIRE(refs > 0);
+ DBC_REQUIRE(proc_obj);
+
+ /* This is needed only when Device is loaded when it is
+ * already 'ACTIVE' */
+ /* Destory the Node Manager, msg_ctrl Manager */
+ if (!dev_destroy2(proc_obj->hdev_obj)) {
+ /* Destroy the msg_ctrl by calling msg_delete */
+ dev_get_msg_mgr(proc_obj->hdev_obj, &hmsg_mgr);
+ if (hmsg_mgr) {
+ msg_delete(hmsg_mgr);
+ dev_set_msg_mgr(proc_obj->hdev_obj, NULL);
+ }
+ }
+ /* Place the Board in the Monitor State */
+ if (!((*proc_obj->intf_fxns->pfn_brd_monitor)
+ (proc_obj->hbridge_context))) {
+ status = 0;
+ if (!((*proc_obj->intf_fxns->pfn_brd_status)
+ (proc_obj->hbridge_context, &brd_state)))
+ DBC_ASSERT(brd_state == BRD_IDLE);
+ }
+
+ DBC_ENSURE((!status && brd_state == BRD_IDLE) ||
+ status);
+ return status;
+}
+
+/*
+ * ======== get_envp_count ========
+ * Purpose:
+ * Return the number of elements in the envp array, including the
+ * terminating NULL element.
+ */
+static s32 get_envp_count(char **envp)
+{
+ s32 ret = 0;
+ if (envp) {
+ while (*envp++)
+ ret++;
+
+ ret += 1; /* Include the terminating NULL in the count. */
+ }
+
+ return ret;
+}
+
+/*
+ * ======== prepend_envp ========
+ * Purpose:
+ * Prepend an environment variable=value pair to the new envp array, and
+ * copy in the existing var=value pairs in the old envp array.
+ */
+static char **prepend_envp(char **new_envp, char **envp, s32 envp_elems,
+ s32 cnew_envp, char *sz_var)
+{
+ char **pp_envp = new_envp;
+
+ DBC_REQUIRE(new_envp);
+
+ /* Prepend new environ var=value string */
+ *new_envp++ = sz_var;
+
+ /* Copy user's environment into our own. */
+ while (envp_elems--)
+ *new_envp++ = *envp++;
+
+ /* Ensure NULL terminates the new environment strings array. */
+ if (envp_elems == 0)
+ *new_envp = NULL;
+
+ return pp_envp;
+}
+
+/*
+ * ======== proc_notify_clients ========
+ * Purpose:
+ * Notify the processor the events.
+ */
+int proc_notify_clients(void *proc, u32 events)
+{
+ int status = 0;
+ struct proc_object *p_proc_object = (struct proc_object *)proc;
+
+ DBC_REQUIRE(p_proc_object);
+ DBC_REQUIRE(is_valid_proc_event(events));
+ DBC_REQUIRE(refs > 0);
+ if (!p_proc_object) {
+ status = -EFAULT;
+ goto func_end;
+ }
+
+ ntfy_notify(p_proc_object->ntfy_obj, events);
+func_end:
+ return status;
+}
+
+/*
+ * ======== proc_notify_all_clients ========
+ * Purpose:
+ * Notify the processor the events. This includes notifying all clients
+ * attached to a particulat DSP.
+ */
+int proc_notify_all_clients(void *proc, u32 events)
+{
+ int status = 0;
+ struct proc_object *p_proc_object = (struct proc_object *)proc;
+
+ DBC_REQUIRE(is_valid_proc_event(events));
+ DBC_REQUIRE(refs > 0);
+
+ if (!p_proc_object) {
+ status = -EFAULT;
+ goto func_end;
+ }
+
+ dev_notify_clients(p_proc_object->hdev_obj, events);
+
+func_end:
+ return status;
+}
+
+/*
+ * ======== proc_get_processor_id ========
+ * Purpose:
+ * Retrieves the processor ID.
+ */
+int proc_get_processor_id(void *proc, u32 * proc_id)
+{
+ int status = 0;
+ struct proc_object *p_proc_object = (struct proc_object *)proc;
+
+ if (p_proc_object)
+ *proc_id = p_proc_object->processor_id;
+ else
+ status = -EFAULT;
+
+ return status;
+}
diff --git a/drivers/staging/tidspbridge/rmgr/pwr.c b/drivers/staging/tidspbridge/rmgr/pwr.c
new file mode 100644
index 00000000000..85cb1a2bc0b
--- /dev/null
+++ b/drivers/staging/tidspbridge/rmgr/pwr.c
@@ -0,0 +1,176 @@
+/*
+ * pwr.c
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * PWR API for controlling DSP power states.
+ *
+ * Copyright (C) 2005-2006 Texas Instruments, Inc.
+ *
+ * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+/* ----------------------------------- Host OS */
+#include <dspbridge/host_os.h>
+
+/* ----------------------------------- This */
+#include <dspbridge/pwr.h>
+
+/* ----------------------------------- Resource Manager */
+#include <dspbridge/devdefs.h>
+#include <dspbridge/drv.h>
+
+/* ----------------------------------- Platform Manager */
+#include <dspbridge/dev.h>
+
+/* ----------------------------------- Link Driver */
+#include <dspbridge/dspioctl.h>
+
+/*
+ * ======== pwr_sleep_dsp ========
+ * Send command to DSP to enter sleep state.
+ */
+int pwr_sleep_dsp(const u32 sleep_code, const u32 timeout)
+{
+ struct bridge_drv_interface *intf_fxns;
+ struct bridge_dev_context *dw_context;
+ int status = -EPERM;
+ struct dev_object *hdev_obj = NULL;
+ u32 ioctlcode = 0;
+ u32 arg = timeout;
+
+ for (hdev_obj = (struct dev_object *)drv_get_first_dev_object();
+ hdev_obj != NULL;
+ hdev_obj =
+ (struct dev_object *)drv_get_next_dev_object((u32) hdev_obj)) {
+ if (dev_get_bridge_context(hdev_obj,
+ (struct bridge_dev_context **)
+ &dw_context)) {
+ continue;
+ }
+ if (dev_get_intf_fxns(hdev_obj,
+ (struct bridge_drv_interface **)
+ &intf_fxns)) {
+ continue;
+ }
+ if (sleep_code == PWR_DEEPSLEEP)
+ ioctlcode = BRDIOCTL_DEEPSLEEP;
+ else if (sleep_code == PWR_EMERGENCYDEEPSLEEP)
+ ioctlcode = BRDIOCTL_EMERGENCYSLEEP;
+ else
+ status = -EINVAL;
+
+ if (status != -EINVAL) {
+ status = (*intf_fxns->pfn_dev_cntrl) (dw_context,
+ ioctlcode,
+ (void *)&arg);
+ }
+ }
+ return status;
+}
+
+/*
+ * ======== pwr_wake_dsp ========
+ * Send command to DSP to wake it from sleep.
+ */
+int pwr_wake_dsp(const u32 timeout)
+{
+ struct bridge_drv_interface *intf_fxns;
+ struct bridge_dev_context *dw_context;
+ int status = -EPERM;
+ struct dev_object *hdev_obj = NULL;
+ u32 arg = timeout;
+
+ for (hdev_obj = (struct dev_object *)drv_get_first_dev_object();
+ hdev_obj != NULL;
+ hdev_obj = (struct dev_object *)drv_get_next_dev_object
+ ((u32) hdev_obj)) {
+ if (!(dev_get_bridge_context(hdev_obj,
+ (struct bridge_dev_context
+ **)&dw_context))) {
+ if (!(dev_get_intf_fxns(hdev_obj,
+ (struct bridge_drv_interface **)&intf_fxns))) {
+ status =
+ (*intf_fxns->pfn_dev_cntrl) (dw_context,
+ BRDIOCTL_WAKEUP,
+ (void *)&arg);
+ }
+ }
+ }
+ return status;
+}
+
+/*
+ * ======== pwr_pm_pre_scale========
+ * Sends pre-notification message to DSP.
+ */
+int pwr_pm_pre_scale(u16 voltage_domain, u32 level)
+{
+ struct bridge_drv_interface *intf_fxns;
+ struct bridge_dev_context *dw_context;
+ int status = -EPERM;
+ struct dev_object *hdev_obj = NULL;
+ u32 arg[2];
+
+ arg[0] = voltage_domain;
+ arg[1] = level;
+
+ for (hdev_obj = (struct dev_object *)drv_get_first_dev_object();
+ hdev_obj != NULL;
+ hdev_obj = (struct dev_object *)drv_get_next_dev_object
+ ((u32) hdev_obj)) {
+ if (!(dev_get_bridge_context(hdev_obj,
+ (struct bridge_dev_context
+ **)&dw_context))) {
+ if (!(dev_get_intf_fxns(hdev_obj,
+ (struct bridge_drv_interface **)&intf_fxns))) {
+ status =
+ (*intf_fxns->pfn_dev_cntrl) (dw_context,
+ BRDIOCTL_PRESCALE_NOTIFY,
+ (void *)&arg);
+ }
+ }
+ }
+ return status;
+}
+
+/*
+ * ======== pwr_pm_post_scale========
+ * Sends post-notification message to DSP.
+ */
+int pwr_pm_post_scale(u16 voltage_domain, u32 level)
+{
+ struct bridge_drv_interface *intf_fxns;
+ struct bridge_dev_context *dw_context;
+ int status = -EPERM;
+ struct dev_object *hdev_obj = NULL;
+ u32 arg[2];
+
+ arg[0] = voltage_domain;
+ arg[1] = level;
+
+ for (hdev_obj = (struct dev_object *)drv_get_first_dev_object();
+ hdev_obj != NULL;
+ hdev_obj = (struct dev_object *)drv_get_next_dev_object
+ ((u32) hdev_obj)) {
+ if (!(dev_get_bridge_context(hdev_obj,
+ (struct bridge_dev_context
+ **)&dw_context))) {
+ if (!(dev_get_intf_fxns(hdev_obj,
+ (struct bridge_drv_interface **)&intf_fxns))) {
+ status =
+ (*intf_fxns->pfn_dev_cntrl) (dw_context,
+ BRDIOCTL_POSTSCALE_NOTIFY,
+ (void *)&arg);
+ }
+ }
+ }
+ return status;
+
+}
diff --git a/drivers/staging/tidspbridge/rmgr/rmm.c b/drivers/staging/tidspbridge/rmgr/rmm.c
new file mode 100644
index 00000000000..761e8f4fa46
--- /dev/null
+++ b/drivers/staging/tidspbridge/rmgr/rmm.c
@@ -0,0 +1,537 @@
+/*
+ * rmm.c
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * Copyright (C) 2005-2006 Texas Instruments, Inc.
+ *
+ * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+/*
+ * This memory manager provides general heap management and arbitrary
+ * alignment for any number of memory segments.
+ *
+ * Notes:
+ *
+ * Memory blocks are allocated from the end of the first free memory
+ * block large enough to satisfy the request. Alignment requirements
+ * are satisfied by "sliding" the block forward until its base satisfies
+ * the alignment specification; if this is not possible then the next
+ * free block large enough to hold the request is tried.
+ *
+ * Since alignment can cause the creation of a new free block - the
+ * unused memory formed between the start of the original free block
+ * and the start of the allocated block - the memory manager must free
+ * this memory to prevent a memory leak.
+ *
+ * Overlay memory is managed by reserving through rmm_alloc, and freeing
+ * it through rmm_free. The memory manager prevents DSP code/data that is
+ * overlayed from being overwritten as long as the memory it runs at has
+ * been allocated, and not yet freed.
+ */
+
+#include <linux/types.h>
+
+/* ----------------------------------- DSP/BIOS Bridge */
+#include <dspbridge/dbdefs.h>
+
+/* ----------------------------------- Trace & Debug */
+#include <dspbridge/dbc.h>
+
+/* ----------------------------------- OS Adaptation Layer */
+#include <dspbridge/list.h>
+
+/* ----------------------------------- This */
+#include <dspbridge/rmm.h>
+
+/*
+ * ======== rmm_header ========
+ * This header is used to maintain a list of free memory blocks.
+ */
+struct rmm_header {
+ struct rmm_header *next; /* form a free memory link list */
+ u32 size; /* size of the free memory */
+ u32 addr; /* DSP address of memory block */
+};
+
+/*
+ * ======== rmm_ovly_sect ========
+ * Keeps track of memory occupied by overlay section.
+ */
+struct rmm_ovly_sect {
+ struct list_head list_elem;
+ u32 addr; /* Start of memory section */
+ u32 size; /* Length (target MAUs) of section */
+ s32 page; /* Memory page */
+};
+
+/*
+ * ======== rmm_target_obj ========
+ */
+struct rmm_target_obj {
+ struct rmm_segment *seg_tab;
+ struct rmm_header **free_list;
+ u32 num_segs;
+ struct lst_list *ovly_list; /* List of overlay memory in use */
+};
+
+static u32 refs; /* module reference count */
+
+static bool alloc_block(struct rmm_target_obj *target, u32 segid, u32 size,
+ u32 align, u32 *dsp_address);
+static bool free_block(struct rmm_target_obj *target, u32 segid, u32 addr,
+ u32 size);
+
+/*
+ * ======== rmm_alloc ========
+ */
+int rmm_alloc(struct rmm_target_obj *target, u32 segid, u32 size,
+ u32 align, u32 *dsp_address, bool reserve)
+{
+ struct rmm_ovly_sect *sect;
+ struct rmm_ovly_sect *prev_sect = NULL;
+ struct rmm_ovly_sect *new_sect;
+ u32 addr;
+ int status = 0;
+
+ DBC_REQUIRE(target);
+ DBC_REQUIRE(dsp_address != NULL);
+ DBC_REQUIRE(size > 0);
+ DBC_REQUIRE(reserve || (target->num_segs > 0));
+ DBC_REQUIRE(refs > 0);
+
+ if (!reserve) {
+ if (!alloc_block(target, segid, size, align, dsp_address)) {
+ status = -ENOMEM;
+ } else {
+ /* Increment the number of allocated blocks in this
+ * segment */
+ target->seg_tab[segid].number++;
+ }
+ goto func_end;
+ }
+ /* An overlay section - See if block is already in use. If not,
+ * insert into the list in ascending address size. */
+ addr = *dsp_address;
+ sect = (struct rmm_ovly_sect *)lst_first(target->ovly_list);
+ /* Find place to insert new list element. List is sorted from
+ * smallest to largest address. */
+ while (sect != NULL) {
+ if (addr <= sect->addr) {
+ /* Check for overlap with sect */
+ if ((addr + size > sect->addr) || (prev_sect &&
+ (prev_sect->addr +
+ prev_sect->size >
+ addr))) {
+ status = -ENXIO;
+ }
+ break;
+ }
+ prev_sect = sect;
+ sect = (struct rmm_ovly_sect *)lst_next(target->ovly_list,
+ (struct list_head *)
+ sect);
+ }
+ if (!status) {
+ /* No overlap - allocate list element for new section. */
+ new_sect = kzalloc(sizeof(struct rmm_ovly_sect), GFP_KERNEL);
+ if (new_sect == NULL) {
+ status = -ENOMEM;
+ } else {
+ lst_init_elem((struct list_head *)new_sect);
+ new_sect->addr = addr;
+ new_sect->size = size;
+ new_sect->page = segid;
+ if (sect == NULL) {
+ /* Put new section at the end of the list */
+ lst_put_tail(target->ovly_list,
+ (struct list_head *)new_sect);
+ } else {
+ /* Put new section just before sect */
+ lst_insert_before(target->ovly_list,
+ (struct list_head *)new_sect,
+ (struct list_head *)sect);
+ }
+ }
+ }
+func_end:
+ return status;
+}
+
+/*
+ * ======== rmm_create ========
+ */
+int rmm_create(struct rmm_target_obj **target_obj,
+ struct rmm_segment seg_tab[], u32 num_segs)
+{
+ struct rmm_header *hptr;
+ struct rmm_segment *sptr, *tmp;
+ struct rmm_target_obj *target;
+ s32 i;
+ int status = 0;
+
+ DBC_REQUIRE(target_obj != NULL);
+ DBC_REQUIRE(num_segs == 0 || seg_tab != NULL);
+
+ /* Allocate DBL target object */
+ target = kzalloc(sizeof(struct rmm_target_obj), GFP_KERNEL);
+
+ if (target == NULL)
+ status = -ENOMEM;
+
+ if (status)
+ goto func_cont;
+
+ target->num_segs = num_segs;
+ if (!(num_segs > 0))
+ goto func_cont;
+
+ /* Allocate the memory for freelist from host's memory */
+ target->free_list = kzalloc(num_segs * sizeof(struct rmm_header *),
+ GFP_KERNEL);
+ if (target->free_list == NULL) {
+ status = -ENOMEM;
+ } else {
+ /* Allocate headers for each element on the free list */
+ for (i = 0; i < (s32) num_segs; i++) {
+ target->free_list[i] =
+ kzalloc(sizeof(struct rmm_header), GFP_KERNEL);
+ if (target->free_list[i] == NULL) {
+ status = -ENOMEM;
+ break;
+ }
+ }
+ /* Allocate memory for initial segment table */
+ target->seg_tab = kzalloc(num_segs * sizeof(struct rmm_segment),
+ GFP_KERNEL);
+ if (target->seg_tab == NULL) {
+ status = -ENOMEM;
+ } else {
+ /* Initialize segment table and free list */
+ sptr = target->seg_tab;
+ for (i = 0, tmp = seg_tab; num_segs > 0;
+ num_segs--, i++) {
+ *sptr = *tmp;
+ hptr = target->free_list[i];
+ hptr->addr = tmp->base;
+ hptr->size = tmp->length;
+ hptr->next = NULL;
+ tmp++;
+ sptr++;
+ }
+ }
+ }
+func_cont:
+ /* Initialize overlay memory list */
+ if (!status) {
+ target->ovly_list = kzalloc(sizeof(struct lst_list),
+ GFP_KERNEL);
+ if (target->ovly_list == NULL)
+ status = -ENOMEM;
+ else
+ INIT_LIST_HEAD(&target->ovly_list->head);
+ }
+
+ if (!status) {
+ *target_obj = target;
+ } else {
+ *target_obj = NULL;
+ if (target)
+ rmm_delete(target);
+
+ }
+
+ DBC_ENSURE((!status && *target_obj)
+ || (status && *target_obj == NULL));
+
+ return status;
+}
+
+/*
+ * ======== rmm_delete ========
+ */
+void rmm_delete(struct rmm_target_obj *target)
+{
+ struct rmm_ovly_sect *ovly_section;
+ struct rmm_header *hptr;
+ struct rmm_header *next;
+ u32 i;
+
+ DBC_REQUIRE(target);
+
+ kfree(target->seg_tab);
+
+ if (target->ovly_list) {
+ while ((ovly_section = (struct rmm_ovly_sect *)lst_get_head
+ (target->ovly_list))) {
+ kfree(ovly_section);
+ }
+ DBC_ASSERT(LST_IS_EMPTY(target->ovly_list));
+ kfree(target->ovly_list);
+ }
+
+ if (target->free_list != NULL) {
+ /* Free elements on freelist */
+ for (i = 0; i < target->num_segs; i++) {
+ hptr = next = target->free_list[i];
+ while (next) {
+ hptr = next;
+ next = hptr->next;
+ kfree(hptr);
+ }
+ }
+ kfree(target->free_list);
+ }
+
+ kfree(target);
+}
+
+/*
+ * ======== rmm_exit ========
+ */
+void rmm_exit(void)
+{
+ DBC_REQUIRE(refs > 0);
+
+ refs--;
+
+ DBC_ENSURE(refs >= 0);
+}
+
+/*
+ * ======== rmm_free ========
+ */
+bool rmm_free(struct rmm_target_obj *target, u32 segid, u32 dsp_addr, u32 size,
+ bool reserved)
+{
+ struct rmm_ovly_sect *sect;
+ bool ret = true;
+
+ DBC_REQUIRE(target);
+
+ DBC_REQUIRE(reserved || segid < target->num_segs);
+ DBC_REQUIRE(reserved || (dsp_addr >= target->seg_tab[segid].base &&
+ (dsp_addr + size) <= (target->seg_tab[segid].
+ base +
+ target->seg_tab[segid].
+ length)));
+
+ /*
+ * Free or unreserve memory.
+ */
+ if (!reserved) {
+ ret = free_block(target, segid, dsp_addr, size);
+ if (ret)
+ target->seg_tab[segid].number--;
+
+ } else {
+ /* Unreserve memory */
+ sect = (struct rmm_ovly_sect *)lst_first(target->ovly_list);
+ while (sect != NULL) {
+ if (dsp_addr == sect->addr) {
+ DBC_ASSERT(size == sect->size);
+ /* Remove from list */
+ lst_remove_elem(target->ovly_list,
+ (struct list_head *)sect);
+ kfree(sect);
+ break;
+ }
+ sect =
+ (struct rmm_ovly_sect *)lst_next(target->ovly_list,
+ (struct list_head
+ *)sect);
+ }
+ if (sect == NULL)
+ ret = false;
+
+ }
+ return ret;
+}
+
+/*
+ * ======== rmm_init ========
+ */
+bool rmm_init(void)
+{
+ DBC_REQUIRE(refs >= 0);
+
+ refs++;
+
+ return true;
+}
+
+/*
+ * ======== rmm_stat ========
+ */
+bool rmm_stat(struct rmm_target_obj *target, enum dsp_memtype segid,
+ struct dsp_memstat *mem_stat_buf)
+{
+ struct rmm_header *head;
+ bool ret = false;
+ u32 max_free_size = 0;
+ u32 total_free_size = 0;
+ u32 free_blocks = 0;
+
+ DBC_REQUIRE(mem_stat_buf != NULL);
+ DBC_ASSERT(target != NULL);
+
+ if ((u32) segid < target->num_segs) {
+ head = target->free_list[segid];
+
+ /* Collect data from free_list */
+ while (head != NULL) {
+ max_free_size = max(max_free_size, head->size);
+ total_free_size += head->size;
+ free_blocks++;
+ head = head->next;
+ }
+
+ /* ul_size */
+ mem_stat_buf->ul_size = target->seg_tab[segid].length;
+
+ /* ul_num_free_blocks */
+ mem_stat_buf->ul_num_free_blocks = free_blocks;
+
+ /* ul_total_free_size */
+ mem_stat_buf->ul_total_free_size = total_free_size;
+
+ /* ul_len_max_free_block */
+ mem_stat_buf->ul_len_max_free_block = max_free_size;
+
+ /* ul_num_alloc_blocks */
+ mem_stat_buf->ul_num_alloc_blocks =
+ target->seg_tab[segid].number;
+
+ ret = true;
+ }
+
+ return ret;
+}
+
+/*
+ * ======== balloc ========
+ * This allocation function allocates memory from the lowest addresses
+ * first.
+ */
+static bool alloc_block(struct rmm_target_obj *target, u32 segid, u32 size,
+ u32 align, u32 *dsp_address)
+{
+ struct rmm_header *head;
+ struct rmm_header *prevhead = NULL;
+ struct rmm_header *next;
+ u32 tmpalign;
+ u32 alignbytes;
+ u32 hsize;
+ u32 allocsize;
+ u32 addr;
+
+ alignbytes = (align == 0) ? 1 : align;
+ prevhead = NULL;
+ head = target->free_list[segid];
+
+ do {
+ hsize = head->size;
+ next = head->next;
+
+ addr = head->addr; /* alloc from the bottom */
+
+ /* align allocation */
+ (tmpalign = (u32) addr % alignbytes);
+ if (tmpalign != 0)
+ tmpalign = alignbytes - tmpalign;
+
+ allocsize = size + tmpalign;
+
+ if (hsize >= allocsize) { /* big enough */
+ if (hsize == allocsize && prevhead != NULL) {
+ prevhead->next = next;
+ kfree(head);
+ } else {
+ head->size = hsize - allocsize;
+ head->addr += allocsize;
+ }
+
+ /* free up any hole created by alignment */
+ if (tmpalign)
+ free_block(target, segid, addr, tmpalign);
+
+ *dsp_address = addr + tmpalign;
+ return true;
+ }
+
+ prevhead = head;
+ head = next;
+
+ } while (head != NULL);
+
+ return false;
+}
+
+/*
+ * ======== free_block ========
+ * TO DO: free_block() allocates memory, which could result in failure.
+ * Could allocate an rmm_header in rmm_alloc(), to be kept in a pool.
+ * free_block() could use an rmm_header from the pool, freeing as blocks
+ * are coalesced.
+ */
+static bool free_block(struct rmm_target_obj *target, u32 segid, u32 addr,
+ u32 size)
+{
+ struct rmm_header *head;
+ struct rmm_header *thead;
+ struct rmm_header *rhead;
+ bool ret = true;
+
+ /* Create a memory header to hold the newly free'd block. */
+ rhead = kzalloc(sizeof(struct rmm_header), GFP_KERNEL);
+ if (rhead == NULL) {
+ ret = false;
+ } else {
+ /* search down the free list to find the right place for addr */
+ head = target->free_list[segid];
+
+ if (addr >= head->addr) {
+ while (head->next != NULL && addr > head->next->addr)
+ head = head->next;
+
+ thead = head->next;
+
+ head->next = rhead;
+ rhead->next = thead;
+ rhead->addr = addr;
+ rhead->size = size;
+ } else {
+ *rhead = *head;
+ head->next = rhead;
+ head->addr = addr;
+ head->size = size;
+ thead = rhead->next;
+ }
+
+ /* join with upper block, if possible */
+ if (thead != NULL && (rhead->addr + rhead->size) ==
+ thead->addr) {
+ head->next = rhead->next;
+ thead->size = size + thead->size;
+ thead->addr = addr;
+ kfree(rhead);
+ rhead = thead;
+ }
+
+ /* join with the lower block, if possible */
+ if ((head->addr + head->size) == rhead->addr) {
+ head->next = rhead->next;
+ head->size = head->size + rhead->size;
+ kfree(rhead);
+ }
+ }
+
+ return ret;
+}
diff --git a/drivers/staging/tidspbridge/rmgr/strm.c b/drivers/staging/tidspbridge/rmgr/strm.c
new file mode 100644
index 00000000000..ef2ec9497b1
--- /dev/null
+++ b/drivers/staging/tidspbridge/rmgr/strm.c
@@ -0,0 +1,853 @@
+/*
+ * strm.c
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * DSP/BIOS Bridge Stream Manager.
+ *
+ * Copyright (C) 2005-2006 Texas Instruments, Inc.
+ *
+ * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include <linux/types.h>
+
+/* ----------------------------------- Host OS */
+#include <dspbridge/host_os.h>
+
+/* ----------------------------------- DSP/BIOS Bridge */
+#include <dspbridge/dbdefs.h>
+
+/* ----------------------------------- Trace & Debug */
+#include <dspbridge/dbc.h>
+
+/* ----------------------------------- OS Adaptation Layer */
+#include <dspbridge/sync.h>
+
+/* ----------------------------------- Bridge Driver */
+#include <dspbridge/dspdefs.h>
+
+/* ----------------------------------- Resource Manager */
+#include <dspbridge/nodepriv.h>
+
+/* ----------------------------------- Others */
+#include <dspbridge/cmm.h>
+
+/* ----------------------------------- This */
+#include <dspbridge/strm.h>
+
+#include <dspbridge/cfg.h>
+#include <dspbridge/resourcecleanup.h>
+
+/* ----------------------------------- Defines, Data Structures, Typedefs */
+#define DEFAULTTIMEOUT 10000
+#define DEFAULTNUMBUFS 2
+
+/*
+ * ======== strm_mgr ========
+ * The strm_mgr contains device information needed to open the underlying
+ * channels of a stream.
+ */
+struct strm_mgr {
+ struct dev_object *dev_obj; /* Device for this processor */
+ struct chnl_mgr *hchnl_mgr; /* Channel manager */
+ /* Function interface to Bridge driver */
+ struct bridge_drv_interface *intf_fxns;
+};
+
+/*
+ * ======== strm_object ========
+ * This object is allocated in strm_open().
+ */
+struct strm_object {
+ struct strm_mgr *strm_mgr_obj;
+ struct chnl_object *chnl_obj;
+ u32 dir; /* DSP_TONODE or DSP_FROMNODE */
+ u32 utimeout;
+ u32 num_bufs; /* Max # of bufs allowed in stream */
+ u32 un_bufs_in_strm; /* Current # of bufs in stream */
+ u32 ul_n_bytes; /* bytes transferred since idled */
+ /* STREAM_IDLE, STREAM_READY, ... */
+ enum dsp_streamstate strm_state;
+ void *user_event; /* Saved for strm_get_info() */
+ enum dsp_strmmode strm_mode; /* STRMMODE_[PROCCOPY][ZEROCOPY]... */
+ u32 udma_chnl_id; /* DMA chnl id */
+ u32 udma_priority; /* DMA priority:DMAPRI_[LOW][HIGH] */
+ u32 segment_id; /* >0 is SM segment.=0 is local heap */
+ u32 buf_alignment; /* Alignment for stream bufs */
+ /* Stream's SM address translator */
+ struct cmm_xlatorobject *xlator;
+};
+
+/* ----------------------------------- Globals */
+static u32 refs; /* module reference count */
+
+/* ----------------------------------- Function Prototypes */
+static int delete_strm(struct strm_object *stream_obj);
+
+/*
+ * ======== strm_allocate_buffer ========
+ * Purpose:
+ * Allocates buffers for a stream.
+ */
+int strm_allocate_buffer(struct strm_res_object *strmres, u32 usize,
+ u8 **ap_buffer, u32 num_bufs,
+ struct process_context *pr_ctxt)
+{
+ int status = 0;
+ u32 alloc_cnt = 0;
+ u32 i;
+ struct strm_object *stream_obj = strmres->hstream;
+
+ DBC_REQUIRE(refs > 0);
+ DBC_REQUIRE(ap_buffer != NULL);
+
+ if (stream_obj) {
+ /*
+ * Allocate from segment specified at time of stream open.
+ */
+ if (usize == 0)
+ status = -EINVAL;
+
+ } else {
+ status = -EFAULT;
+ }
+
+ if (status)
+ goto func_end;
+
+ for (i = 0; i < num_bufs; i++) {
+ DBC_ASSERT(stream_obj->xlator != NULL);
+ (void)cmm_xlator_alloc_buf(stream_obj->xlator, &ap_buffer[i],
+ usize);
+ if (ap_buffer[i] == NULL) {
+ status = -ENOMEM;
+ alloc_cnt = i;
+ break;
+ }
+ }
+ if (status)
+ strm_free_buffer(strmres, ap_buffer, alloc_cnt, pr_ctxt);
+
+ if (status)
+ goto func_end;
+
+ drv_proc_update_strm_res(num_bufs, strmres);
+
+func_end:
+ return status;
+}
+
+/*
+ * ======== strm_close ========
+ * Purpose:
+ * Close a stream opened with strm_open().
+ */
+int strm_close(struct strm_res_object *strmres,
+ struct process_context *pr_ctxt)
+{
+ struct bridge_drv_interface *intf_fxns;
+ struct chnl_info chnl_info_obj;
+ int status = 0;
+ struct strm_object *stream_obj = strmres->hstream;
+
+ DBC_REQUIRE(refs > 0);
+
+ if (!stream_obj) {
+ status = -EFAULT;
+ } else {
+ /* Have all buffers been reclaimed? If not, return
+ * -EPIPE */
+ intf_fxns = stream_obj->strm_mgr_obj->intf_fxns;
+ status =
+ (*intf_fxns->pfn_chnl_get_info) (stream_obj->chnl_obj,
+ &chnl_info_obj);
+ DBC_ASSERT(!status);
+
+ if (chnl_info_obj.cio_cs > 0 || chnl_info_obj.cio_reqs > 0)
+ status = -EPIPE;
+ else
+ status = delete_strm(stream_obj);
+ }
+
+ if (status)
+ goto func_end;
+
+ idr_remove(pr_ctxt->stream_id, strmres->id);
+func_end:
+ DBC_ENSURE(status == 0 || status == -EFAULT ||
+ status == -EPIPE || status == -EPERM);
+
+ dev_dbg(bridge, "%s: stream_obj: %p, status 0x%x\n", __func__,
+ stream_obj, status);
+ return status;
+}
+
+/*
+ * ======== strm_create ========
+ * Purpose:
+ * Create a STRM manager object.
+ */
+int strm_create(struct strm_mgr **strm_man,
+ struct dev_object *dev_obj)
+{
+ struct strm_mgr *strm_mgr_obj;
+ int status = 0;
+
+ DBC_REQUIRE(refs > 0);
+ DBC_REQUIRE(strm_man != NULL);
+ DBC_REQUIRE(dev_obj != NULL);
+
+ *strm_man = NULL;
+ /* Allocate STRM manager object */
+ strm_mgr_obj = kzalloc(sizeof(struct strm_mgr), GFP_KERNEL);
+ if (strm_mgr_obj == NULL)
+ status = -ENOMEM;
+ else
+ strm_mgr_obj->dev_obj = dev_obj;
+
+ /* Get Channel manager and Bridge function interface */
+ if (!status) {
+ status = dev_get_chnl_mgr(dev_obj, &(strm_mgr_obj->hchnl_mgr));
+ if (!status) {
+ (void)dev_get_intf_fxns(dev_obj,
+ &(strm_mgr_obj->intf_fxns));
+ DBC_ASSERT(strm_mgr_obj->intf_fxns != NULL);
+ }
+ }
+
+ if (!status)
+ *strm_man = strm_mgr_obj;
+ else
+ kfree(strm_mgr_obj);
+
+ DBC_ENSURE((!status && *strm_man) || (status && *strm_man == NULL));
+
+ return status;
+}
+
+/*
+ * ======== strm_delete ========
+ * Purpose:
+ * Delete the STRM Manager Object.
+ */
+void strm_delete(struct strm_mgr *strm_mgr_obj)
+{
+ DBC_REQUIRE(refs > 0);
+ DBC_REQUIRE(strm_mgr_obj);
+
+ kfree(strm_mgr_obj);
+}
+
+/*
+ * ======== strm_exit ========
+ * Purpose:
+ * Discontinue usage of STRM module.
+ */
+void strm_exit(void)
+{
+ DBC_REQUIRE(refs > 0);
+
+ refs--;
+
+ DBC_ENSURE(refs >= 0);
+}
+
+/*
+ * ======== strm_free_buffer ========
+ * Purpose:
+ * Frees the buffers allocated for a stream.
+ */
+int strm_free_buffer(struct strm_res_object *strmres, u8 ** ap_buffer,
+ u32 num_bufs, struct process_context *pr_ctxt)
+{
+ int status = 0;
+ u32 i = 0;
+ struct strm_object *stream_obj = strmres->hstream;
+
+ DBC_REQUIRE(refs > 0);
+ DBC_REQUIRE(ap_buffer != NULL);
+
+ if (!stream_obj)
+ status = -EFAULT;
+
+ if (!status) {
+ for (i = 0; i < num_bufs; i++) {
+ DBC_ASSERT(stream_obj->xlator != NULL);
+ status =
+ cmm_xlator_free_buf(stream_obj->xlator,
+ ap_buffer[i]);
+ if (status)
+ break;
+ ap_buffer[i] = NULL;
+ }
+ }
+ drv_proc_update_strm_res(num_bufs - i, strmres);
+
+ return status;
+}
+
+/*
+ * ======== strm_get_info ========
+ * Purpose:
+ * Retrieves information about a stream.
+ */
+int strm_get_info(struct strm_object *stream_obj,
+ struct stream_info *stream_info,
+ u32 stream_info_size)
+{
+ struct bridge_drv_interface *intf_fxns;
+ struct chnl_info chnl_info_obj;
+ int status = 0;
+ void *virt_base = NULL; /* NULL if no SM used */
+
+ DBC_REQUIRE(refs > 0);
+ DBC_REQUIRE(stream_info != NULL);
+ DBC_REQUIRE(stream_info_size >= sizeof(struct stream_info));
+
+ if (!stream_obj) {
+ status = -EFAULT;
+ } else {
+ if (stream_info_size < sizeof(struct stream_info)) {
+ /* size of users info */
+ status = -EINVAL;
+ }
+ }
+ if (status)
+ goto func_end;
+
+ intf_fxns = stream_obj->strm_mgr_obj->intf_fxns;
+ status =
+ (*intf_fxns->pfn_chnl_get_info) (stream_obj->chnl_obj,
+ &chnl_info_obj);
+ if (status)
+ goto func_end;
+
+ if (stream_obj->xlator) {
+ /* We have a translator */
+ DBC_ASSERT(stream_obj->segment_id > 0);
+ cmm_xlator_info(stream_obj->xlator, (u8 **) &virt_base, 0,
+ stream_obj->segment_id, false);
+ }
+ stream_info->segment_id = stream_obj->segment_id;
+ stream_info->strm_mode = stream_obj->strm_mode;
+ stream_info->virt_base = virt_base;
+ stream_info->user_strm->number_bufs_allowed = stream_obj->num_bufs;
+ stream_info->user_strm->number_bufs_in_stream = chnl_info_obj.cio_cs +
+ chnl_info_obj.cio_reqs;
+ /* # of bytes transferred since last call to DSPStream_Idle() */
+ stream_info->user_strm->ul_number_bytes = chnl_info_obj.bytes_tx;
+ stream_info->user_strm->sync_object_handle = chnl_info_obj.event_obj;
+ /* Determine stream state based on channel state and info */
+ if (chnl_info_obj.dw_state & CHNL_STATEEOS) {
+ stream_info->user_strm->ss_stream_state = STREAM_DONE;
+ } else {
+ if (chnl_info_obj.cio_cs > 0)
+ stream_info->user_strm->ss_stream_state = STREAM_READY;
+ else if (chnl_info_obj.cio_reqs > 0)
+ stream_info->user_strm->ss_stream_state =
+ STREAM_PENDING;
+ else
+ stream_info->user_strm->ss_stream_state = STREAM_IDLE;
+
+ }
+func_end:
+ return status;
+}
+
+/*
+ * ======== strm_idle ========
+ * Purpose:
+ * Idles a particular stream.
+ */
+int strm_idle(struct strm_object *stream_obj, bool flush_data)
+{
+ struct bridge_drv_interface *intf_fxns;
+ int status = 0;
+
+ DBC_REQUIRE(refs > 0);
+
+ if (!stream_obj) {
+ status = -EFAULT;
+ } else {
+ intf_fxns = stream_obj->strm_mgr_obj->intf_fxns;
+
+ status = (*intf_fxns->pfn_chnl_idle) (stream_obj->chnl_obj,
+ stream_obj->utimeout,
+ flush_data);
+ }
+
+ dev_dbg(bridge, "%s: stream_obj: %p flush_data: 0x%x status: 0x%x\n",
+ __func__, stream_obj, flush_data, status);
+ return status;
+}
+
+/*
+ * ======== strm_init ========
+ * Purpose:
+ * Initialize the STRM module.
+ */
+bool strm_init(void)
+{
+ bool ret = true;
+
+ DBC_REQUIRE(refs >= 0);
+
+ if (ret)
+ refs++;
+
+ DBC_ENSURE((ret && (refs > 0)) || (!ret && (refs >= 0)));
+
+ return ret;
+}
+
+/*
+ * ======== strm_issue ========
+ * Purpose:
+ * Issues a buffer on a stream
+ */
+int strm_issue(struct strm_object *stream_obj, u8 *pbuf, u32 ul_bytes,
+ u32 ul_buf_size, u32 dw_arg)
+{
+ struct bridge_drv_interface *intf_fxns;
+ int status = 0;
+ void *tmp_buf = NULL;
+
+ DBC_REQUIRE(refs > 0);
+ DBC_REQUIRE(pbuf != NULL);
+
+ if (!stream_obj) {
+ status = -EFAULT;
+ } else {
+ intf_fxns = stream_obj->strm_mgr_obj->intf_fxns;
+
+ if (stream_obj->segment_id != 0) {
+ tmp_buf = cmm_xlator_translate(stream_obj->xlator,
+ (void *)pbuf,
+ CMM_VA2DSPPA);
+ if (tmp_buf == NULL)
+ status = -ESRCH;
+
+ }
+ if (!status) {
+ status = (*intf_fxns->pfn_chnl_add_io_req)
+ (stream_obj->chnl_obj, pbuf, ul_bytes, ul_buf_size,
+ (u32) tmp_buf, dw_arg);
+ }
+ if (status == -EIO)
+ status = -ENOSR;
+ }
+
+ dev_dbg(bridge, "%s: stream_obj: %p pbuf: %p ul_bytes: 0x%x dw_arg:"
+ " 0x%x status: 0x%x\n", __func__, stream_obj, pbuf,
+ ul_bytes, dw_arg, status);
+ return status;
+}
+
+/*
+ * ======== strm_open ========
+ * Purpose:
+ * Open a stream for sending/receiving data buffers to/from a task or
+ * XDAIS socket node on the DSP.
+ */
+int strm_open(struct node_object *hnode, u32 dir, u32 index,
+ struct strm_attr *pattr,
+ struct strm_res_object **strmres,
+ struct process_context *pr_ctxt)
+{
+ struct strm_mgr *strm_mgr_obj;
+ struct bridge_drv_interface *intf_fxns;
+ u32 ul_chnl_id;
+ struct strm_object *strm_obj = NULL;
+ s8 chnl_mode;
+ struct chnl_attr chnl_attr_obj;
+ int status = 0;
+ struct cmm_object *hcmm_mgr = NULL; /* Shared memory manager hndl */
+
+ void *stream_res;
+
+ DBC_REQUIRE(refs > 0);
+ DBC_REQUIRE(strmres != NULL);
+ DBC_REQUIRE(pattr != NULL);
+ *strmres = NULL;
+ if (dir != DSP_TONODE && dir != DSP_FROMNODE) {
+ status = -EPERM;
+ } else {
+ /* Get the channel id from the node (set in node_connect()) */
+ status = node_get_channel_id(hnode, dir, index, &ul_chnl_id);
+ }
+ if (!status)
+ status = node_get_strm_mgr(hnode, &strm_mgr_obj);
+
+ if (!status) {
+ strm_obj = kzalloc(sizeof(struct strm_object), GFP_KERNEL);
+ if (strm_obj == NULL) {
+ status = -ENOMEM;
+ } else {
+ strm_obj->strm_mgr_obj = strm_mgr_obj;
+ strm_obj->dir = dir;
+ strm_obj->strm_state = STREAM_IDLE;
+ strm_obj->user_event = pattr->user_event;
+ if (pattr->stream_attr_in != NULL) {
+ strm_obj->utimeout =
+ pattr->stream_attr_in->utimeout;
+ strm_obj->num_bufs =
+ pattr->stream_attr_in->num_bufs;
+ strm_obj->strm_mode =
+ pattr->stream_attr_in->strm_mode;
+ strm_obj->segment_id =
+ pattr->stream_attr_in->segment_id;
+ strm_obj->buf_alignment =
+ pattr->stream_attr_in->buf_alignment;
+ strm_obj->udma_chnl_id =
+ pattr->stream_attr_in->udma_chnl_id;
+ strm_obj->udma_priority =
+ pattr->stream_attr_in->udma_priority;
+ chnl_attr_obj.uio_reqs =
+ pattr->stream_attr_in->num_bufs;
+ } else {
+ strm_obj->utimeout = DEFAULTTIMEOUT;
+ strm_obj->num_bufs = DEFAULTNUMBUFS;
+ strm_obj->strm_mode = STRMMODE_PROCCOPY;
+ strm_obj->segment_id = 0; /* local mem */
+ strm_obj->buf_alignment = 0;
+ strm_obj->udma_chnl_id = 0;
+ strm_obj->udma_priority = 0;
+ chnl_attr_obj.uio_reqs = DEFAULTNUMBUFS;
+ }
+ chnl_attr_obj.reserved1 = NULL;
+ /* DMA chnl flush timeout */
+ chnl_attr_obj.reserved2 = strm_obj->utimeout;
+ chnl_attr_obj.event_obj = NULL;
+ if (pattr->user_event != NULL)
+ chnl_attr_obj.event_obj = pattr->user_event;
+
+ }
+ }
+ if (status)
+ goto func_cont;
+
+ if ((pattr->virt_base == NULL) || !(pattr->ul_virt_size > 0))
+ goto func_cont;
+
+ /* No System DMA */
+ DBC_ASSERT(strm_obj->strm_mode != STRMMODE_LDMA);
+ /* Get the shared mem mgr for this streams dev object */
+ status = dev_get_cmm_mgr(strm_mgr_obj->dev_obj, &hcmm_mgr);
+ if (!status) {
+ /*Allocate a SM addr translator for this strm. */
+ status = cmm_xlator_create(&strm_obj->xlator, hcmm_mgr, NULL);
+ if (!status) {
+ DBC_ASSERT(strm_obj->segment_id > 0);
+ /* Set translators Virt Addr attributes */
+ status = cmm_xlator_info(strm_obj->xlator,
+ (u8 **) &pattr->virt_base,
+ pattr->ul_virt_size,
+ strm_obj->segment_id, true);
+ }
+ }
+func_cont:
+ if (!status) {
+ /* Open channel */
+ chnl_mode = (dir == DSP_TONODE) ?
+ CHNL_MODETODSP : CHNL_MODEFROMDSP;
+ intf_fxns = strm_mgr_obj->intf_fxns;
+ status = (*intf_fxns->pfn_chnl_open) (&(strm_obj->chnl_obj),
+ strm_mgr_obj->hchnl_mgr,
+ chnl_mode, ul_chnl_id,
+ &chnl_attr_obj);
+ if (status) {
+ /*
+ * over-ride non-returnable status codes so we return
+ * something documented
+ */
+ if (status != -ENOMEM && status !=
+ -EINVAL && status != -EPERM) {
+ /*
+ * We got a status that's not return-able.
+ * Assert that we got something we were
+ * expecting (-EFAULT isn't acceptable,
+ * strm_mgr_obj->hchnl_mgr better be valid or we
+ * assert here), and then return -EPERM.
+ */
+ DBC_ASSERT(status == -ENOSR ||
+ status == -ECHRNG ||
+ status == -EALREADY ||
+ status == -EIO);
+ status = -EPERM;
+ }
+ }
+ }
+ if (!status) {
+ status = drv_proc_insert_strm_res_element(strm_obj,
+ &stream_res, pr_ctxt);
+ if (status)
+ delete_strm(strm_obj);
+ else
+ *strmres = (struct strm_res_object *)stream_res;
+ } else {
+ (void)delete_strm(strm_obj);
+ }
+
+ /* ensure we return a documented error code */
+ DBC_ENSURE((!status && strm_obj) ||
+ (*strmres == NULL && (status == -EFAULT ||
+ status == -EPERM
+ || status == -EINVAL)));
+
+ dev_dbg(bridge, "%s: hnode: %p dir: 0x%x index: 0x%x pattr: %p "
+ "strmres: %p status: 0x%x\n", __func__,
+ hnode, dir, index, pattr, strmres, status);
+ return status;
+}
+
+/*
+ * ======== strm_reclaim ========
+ * Purpose:
+ * Relcaims a buffer from a stream.
+ */
+int strm_reclaim(struct strm_object *stream_obj, u8 ** buf_ptr,
+ u32 *nbytes, u32 *buff_size, u32 *pdw_arg)
+{
+ struct bridge_drv_interface *intf_fxns;
+ struct chnl_ioc chnl_ioc_obj;
+ int status = 0;
+ void *tmp_buf = NULL;
+
+ DBC_REQUIRE(refs > 0);
+ DBC_REQUIRE(buf_ptr != NULL);
+ DBC_REQUIRE(nbytes != NULL);
+ DBC_REQUIRE(pdw_arg != NULL);
+
+ if (!stream_obj) {
+ status = -EFAULT;
+ goto func_end;
+ }
+ intf_fxns = stream_obj->strm_mgr_obj->intf_fxns;
+
+ status =
+ (*intf_fxns->pfn_chnl_get_ioc) (stream_obj->chnl_obj,
+ stream_obj->utimeout,
+ &chnl_ioc_obj);
+ if (!status) {
+ *nbytes = chnl_ioc_obj.byte_size;
+ if (buff_size)
+ *buff_size = chnl_ioc_obj.buf_size;
+
+ *pdw_arg = chnl_ioc_obj.dw_arg;
+ if (!CHNL_IS_IO_COMPLETE(chnl_ioc_obj)) {
+ if (CHNL_IS_TIMED_OUT(chnl_ioc_obj)) {
+ status = -ETIME;
+ } else {
+ /* Allow reclaims after idle to succeed */
+ if (!CHNL_IS_IO_CANCELLED(chnl_ioc_obj))
+ status = -EPERM;
+
+ }
+ }
+ /* Translate zerocopy buffer if channel not canceled. */
+ if (!status
+ && (!CHNL_IS_IO_CANCELLED(chnl_ioc_obj))
+ && (stream_obj->strm_mode == STRMMODE_ZEROCOPY)) {
+ /*
+ * This is a zero-copy channel so chnl_ioc_obj.pbuf
+ * contains the DSP address of SM. We need to
+ * translate it to a virtual address for the user
+ * thread to access.
+ * Note: Could add CMM_DSPPA2VA to CMM in the future.
+ */
+ tmp_buf = cmm_xlator_translate(stream_obj->xlator,
+ chnl_ioc_obj.pbuf,
+ CMM_DSPPA2PA);
+ if (tmp_buf != NULL) {
+ /* now convert this GPP Pa to Va */
+ tmp_buf = cmm_xlator_translate(stream_obj->
+ xlator,
+ tmp_buf,
+ CMM_PA2VA);
+ }
+ if (tmp_buf == NULL)
+ status = -ESRCH;
+
+ chnl_ioc_obj.pbuf = tmp_buf;
+ }
+ *buf_ptr = chnl_ioc_obj.pbuf;
+ }
+func_end:
+ /* ensure we return a documented return code */
+ DBC_ENSURE(!status || status == -EFAULT ||
+ status == -ETIME || status == -ESRCH ||
+ status == -EPERM);
+
+ dev_dbg(bridge, "%s: stream_obj: %p buf_ptr: %p nbytes: %p "
+ "pdw_arg: %p status 0x%x\n", __func__, stream_obj,
+ buf_ptr, nbytes, pdw_arg, status);
+ return status;
+}
+
+/*
+ * ======== strm_register_notify ========
+ * Purpose:
+ * Register to be notified on specific events for this stream.
+ */
+int strm_register_notify(struct strm_object *stream_obj, u32 event_mask,
+ u32 notify_type, struct dsp_notification
+ * hnotification)
+{
+ struct bridge_drv_interface *intf_fxns;
+ int status = 0;
+
+ DBC_REQUIRE(refs > 0);
+ DBC_REQUIRE(hnotification != NULL);
+
+ if (!stream_obj) {
+ status = -EFAULT;
+ } else if ((event_mask & ~((DSP_STREAMIOCOMPLETION) |
+ DSP_STREAMDONE)) != 0) {
+ status = -EINVAL;
+ } else {
+ if (notify_type != DSP_SIGNALEVENT)
+ status = -ENOSYS;
+
+ }
+ if (!status) {
+ intf_fxns = stream_obj->strm_mgr_obj->intf_fxns;
+
+ status =
+ (*intf_fxns->pfn_chnl_register_notify) (stream_obj->
+ chnl_obj,
+ event_mask,
+ notify_type,
+ hnotification);
+ }
+ /* ensure we return a documented return code */
+ DBC_ENSURE(!status || status == -EFAULT ||
+ status == -ETIME || status == -ESRCH ||
+ status == -ENOSYS || status == -EPERM);
+ return status;
+}
+
+/*
+ * ======== strm_select ========
+ * Purpose:
+ * Selects a ready stream.
+ */
+int strm_select(struct strm_object **strm_tab, u32 strms,
+ u32 *pmask, u32 utimeout)
+{
+ u32 index;
+ struct chnl_info chnl_info_obj;
+ struct bridge_drv_interface *intf_fxns;
+ struct sync_object **sync_events = NULL;
+ u32 i;
+ int status = 0;
+
+ DBC_REQUIRE(refs > 0);
+ DBC_REQUIRE(strm_tab != NULL);
+ DBC_REQUIRE(pmask != NULL);
+ DBC_REQUIRE(strms > 0);
+
+ *pmask = 0;
+ for (i = 0; i < strms; i++) {
+ if (!strm_tab[i]) {
+ status = -EFAULT;
+ break;
+ }
+ }
+ if (status)
+ goto func_end;
+
+ /* Determine which channels have IO ready */
+ for (i = 0; i < strms; i++) {
+ intf_fxns = strm_tab[i]->strm_mgr_obj->intf_fxns;
+ status = (*intf_fxns->pfn_chnl_get_info) (strm_tab[i]->chnl_obj,
+ &chnl_info_obj);
+ if (status) {
+ break;
+ } else {
+ if (chnl_info_obj.cio_cs > 0)
+ *pmask |= (1 << i);
+
+ }
+ }
+ if (!status && utimeout > 0 && *pmask == 0) {
+ /* Non-zero timeout */
+ sync_events = kmalloc(strms * sizeof(struct sync_object *),
+ GFP_KERNEL);
+
+ if (sync_events == NULL) {
+ status = -ENOMEM;
+ } else {
+ for (i = 0; i < strms; i++) {
+ intf_fxns =
+ strm_tab[i]->strm_mgr_obj->intf_fxns;
+ status = (*intf_fxns->pfn_chnl_get_info)
+ (strm_tab[i]->chnl_obj, &chnl_info_obj);
+ if (status)
+ break;
+ else
+ sync_events[i] =
+ chnl_info_obj.sync_event;
+
+ }
+ }
+ if (!status) {
+ status =
+ sync_wait_on_multiple_events(sync_events, strms,
+ utimeout, &index);
+ if (!status) {
+ /* Since we waited on the event, we have to
+ * reset it */
+ sync_set_event(sync_events[index]);
+ *pmask = 1 << index;
+ }
+ }
+ }
+func_end:
+ kfree(sync_events);
+
+ DBC_ENSURE((!status && (*pmask != 0 || utimeout == 0)) ||
+ (status && *pmask == 0));
+
+ return status;
+}
+
+/*
+ * ======== delete_strm ========
+ * Purpose:
+ * Frees the resources allocated for a stream.
+ */
+static int delete_strm(struct strm_object *stream_obj)
+{
+ struct bridge_drv_interface *intf_fxns;
+ int status = 0;
+
+ if (stream_obj) {
+ if (stream_obj->chnl_obj) {
+ intf_fxns = stream_obj->strm_mgr_obj->intf_fxns;
+ /* Channel close can fail only if the channel handle
+ * is invalid. */
+ status = (*intf_fxns->pfn_chnl_close)
+ (stream_obj->chnl_obj);
+ /* Free all SM address translator resources */
+ if (!status) {
+ if (stream_obj->xlator) {
+ /* force free */
+ (void)cmm_xlator_delete(stream_obj->
+ xlator,
+ true);
+ }
+ }
+ }
+ kfree(stream_obj);
+ } else {
+ status = -EFAULT;
+ }
+ return status;
+}
diff --git a/drivers/staging/tidspbridge/services/cfg.c b/drivers/staging/tidspbridge/services/cfg.c
new file mode 100644
index 00000000000..a7af74f482d
--- /dev/null
+++ b/drivers/staging/tidspbridge/services/cfg.c
@@ -0,0 +1,253 @@
+/*
+ * cfg.c
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * Implementation of platform specific config services.
+ *
+ * Copyright (C) 2005-2006 Texas Instruments, Inc.
+ *
+ * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include <linux/types.h>
+
+/* ----------------------------------- DSP/BIOS Bridge */
+#include <dspbridge/dbdefs.h>
+
+/* ----------------------------------- Trace & Debug */
+#include <dspbridge/dbc.h>
+
+/* ----------------------------------- OS Adaptation Layer */
+
+/* ----------------------------------- This */
+#include <dspbridge/cfg.h>
+#include <dspbridge/drv.h>
+
+struct drv_ext {
+ struct list_head link;
+ char sz_string[MAXREGPATHLENGTH];
+};
+
+/*
+ * ======== cfg_exit ========
+ * Purpose:
+ * Discontinue usage of the CFG module.
+ */
+void cfg_exit(void)
+{
+ /* Do nothing */
+}
+
+/*
+ * ======== cfg_get_auto_start ========
+ * Purpose:
+ * Retreive the autostart mask, if any, for this board.
+ */
+int cfg_get_auto_start(struct cfg_devnode *dev_node_obj,
+ u32 *auto_start)
+{
+ int status = 0;
+ u32 dw_buf_size;
+ struct drv_data *drv_datap = dev_get_drvdata(bridge);
+
+ dw_buf_size = sizeof(*auto_start);
+ if (!dev_node_obj)
+ status = -EFAULT;
+ if (!auto_start || !drv_datap)
+ status = -EFAULT;
+ if (!status)
+ *auto_start = (drv_datap->base_img) ? 1 : 0;
+
+ DBC_ENSURE((status == 0 &&
+ (*auto_start == 0 || *auto_start == 1))
+ || status != 0);
+ return status;
+}
+
+/*
+ * ======== cfg_get_dev_object ========
+ * Purpose:
+ * Retrieve the Device Object handle for a given devnode.
+ */
+int cfg_get_dev_object(struct cfg_devnode *dev_node_obj,
+ u32 *value)
+{
+ int status = 0;
+ u32 dw_buf_size;
+ struct drv_data *drv_datap = dev_get_drvdata(bridge);
+
+ if (!drv_datap)
+ status = -EPERM;
+
+ if (!dev_node_obj)
+ status = -EFAULT;
+
+ if (!value)
+ status = -EFAULT;
+
+ dw_buf_size = sizeof(value);
+ if (!status) {
+
+ /* check the device string and then store dev object */
+ if (!
+ (strcmp
+ ((char *)((struct drv_ext *)dev_node_obj)->sz_string,
+ "TIOMAP1510")))
+ *value = (u32)drv_datap->dev_object;
+ }
+ if (status)
+ pr_err("%s: Failed, status 0x%x\n", __func__, status);
+ return status;
+}
+
+/*
+ * ======== cfg_get_exec_file ========
+ * Purpose:
+ * Retreive the default executable, if any, for this board.
+ */
+int cfg_get_exec_file(struct cfg_devnode *dev_node_obj, u32 buf_size,
+ char *str_exec_file)
+{
+ int status = 0;
+ struct drv_data *drv_datap = dev_get_drvdata(bridge);
+
+ if (!dev_node_obj)
+ status = -EFAULT;
+
+ else if (!str_exec_file || !drv_datap)
+ status = -EFAULT;
+
+ if (strlen(drv_datap->base_img) > buf_size)
+ status = -EINVAL;
+
+ if (!status && drv_datap->base_img)
+ strcpy(str_exec_file, drv_datap->base_img);
+
+ if (status)
+ pr_err("%s: Failed, status 0x%x\n", __func__, status);
+ DBC_ENSURE(((status == 0) &&
+ (strlen(str_exec_file) <= buf_size))
+ || (status != 0));
+ return status;
+}
+
+/*
+ * ======== cfg_get_object ========
+ * Purpose:
+ * Retrieve the Object handle from the Registry
+ */
+int cfg_get_object(u32 *value, u8 dw_type)
+{
+ int status = -EINVAL;
+ struct drv_data *drv_datap = dev_get_drvdata(bridge);
+
+ DBC_REQUIRE(value != NULL);
+
+ if (!drv_datap)
+ return -EPERM;
+
+ switch (dw_type) {
+ case (REG_DRV_OBJECT):
+ if (drv_datap->drv_object) {
+ *value = (u32)drv_datap->drv_object;
+ status = 0;
+ } else {
+ status = -ENODATA;
+ }
+ break;
+ case (REG_MGR_OBJECT):
+ if (drv_datap->mgr_object) {
+ *value = (u32)drv_datap->mgr_object;
+ status = 0;
+ } else {
+ status = -ENODATA;
+ }
+ break;
+
+ default:
+ break;
+ }
+ if (status) {
+ *value = 0;
+ pr_err("%s: Failed, status 0x%x\n", __func__, status);
+ }
+ DBC_ENSURE((!status && *value != 0) || (status && *value == 0));
+ return status;
+}
+
+/*
+ * ======== cfg_init ========
+ * Purpose:
+ * Initialize the CFG module's private state.
+ */
+bool cfg_init(void)
+{
+ return true;
+}
+
+/*
+ * ======== cfg_set_dev_object ========
+ * Purpose:
+ * Store the Device Object handle and dev_node pointer for a given devnode.
+ */
+int cfg_set_dev_object(struct cfg_devnode *dev_node_obj, u32 value)
+{
+ int status = 0;
+ struct drv_data *drv_datap = dev_get_drvdata(bridge);
+
+ if (!drv_datap) {
+ pr_err("%s: Failed, status 0x%x\n", __func__, status);
+ return -EPERM;
+ }
+
+ if (!dev_node_obj)
+ status = -EFAULT;
+
+ if (!status) {
+ /* Store the Bridge device object in the Registry */
+
+ if (!(strcmp((char *)dev_node_obj, "TIOMAP1510")))
+ drv_datap->dev_object = (void *) value;
+ }
+ if (status)
+ pr_err("%s: Failed, status 0x%x\n", __func__, status);
+
+ return status;
+}
+
+/*
+ * ======== cfg_set_object ========
+ * Purpose:
+ * Store the Driver Object handle
+ */
+int cfg_set_object(u32 value, u8 dw_type)
+{
+ int status = -EINVAL;
+ struct drv_data *drv_datap = dev_get_drvdata(bridge);
+
+ if (!drv_datap)
+ return -EPERM;
+
+ switch (dw_type) {
+ case (REG_DRV_OBJECT):
+ drv_datap->drv_object = (void *)value;
+ status = 0;
+ break;
+ case (REG_MGR_OBJECT):
+ drv_datap->mgr_object = (void *)value;
+ status = 0;
+ break;
+ default:
+ break;
+ }
+ if (status)
+ pr_err("%s: Failed, status 0x%x\n", __func__, status);
+ return status;
+}
diff --git a/drivers/staging/tidspbridge/services/ntfy.c b/drivers/staging/tidspbridge/services/ntfy.c
new file mode 100644
index 00000000000..a2ea698be24
--- /dev/null
+++ b/drivers/staging/tidspbridge/services/ntfy.c
@@ -0,0 +1,31 @@
+/*
+ * ntfy.c
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * Manage lists of notification events.
+ *
+ * Copyright (C) 2005-2006 Texas Instruments, Inc.
+ *
+ * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+/* ----------------------------------- This */
+#include <dspbridge/ntfy.h>
+
+int dsp_notifier_event(struct notifier_block *this, unsigned long event,
+ void *data)
+{
+ struct ntfy_event *ne = container_of(this, struct ntfy_event,
+ noti_block);
+ if (ne->event & event)
+ sync_set_event(&ne->sync_obj);
+ return NOTIFY_OK;
+}
+
diff --git a/drivers/staging/tidspbridge/services/services.c b/drivers/staging/tidspbridge/services/services.c
new file mode 100644
index 00000000000..6a7dd6f3ecb
--- /dev/null
+++ b/drivers/staging/tidspbridge/services/services.c
@@ -0,0 +1,70 @@
+/*
+ * services.c
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * Provide SERVICES loading.
+ *
+ * Copyright (C) 2005-2006 Texas Instruments, Inc.
+ *
+ * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include <linux/types.h>
+
+#include <dspbridge/host_os.h>
+
+/* ----------------------------------- DSP/BIOS Bridge */
+#include <dspbridge/dbdefs.h>
+
+/* ----------------------------------- Trace & Debug */
+#include <dspbridge/dbc.h>
+
+/* ----------------------------------- OS Adaptation Layer */
+#include <dspbridge/cfg.h>
+#include <dspbridge/ntfy.h>
+#include <dspbridge/sync.h>
+#include <dspbridge/clk.h>
+
+/* ----------------------------------- This */
+#include <dspbridge/services.h>
+
+/*
+ * ======== services_exit ========
+ * Purpose:
+ * Discontinue usage of module; free resources when reference count
+ * reaches 0.
+ */
+void services_exit(void)
+{
+ cfg_exit();
+}
+
+/*
+ * ======== services_init ========
+ * Purpose:
+ * Initializes SERVICES modules.
+ */
+bool services_init(void)
+{
+ bool ret = true;
+ bool fcfg;
+
+ /* Perform required initialization of SERVICES modules. */
+ fcfg = cfg_init();
+
+ ret = fcfg;
+
+ if (!ret) {
+ if (fcfg)
+ cfg_exit();
+ }
+
+ return ret;
+}
diff --git a/drivers/staging/tidspbridge/services/sync.c b/drivers/staging/tidspbridge/services/sync.c
new file mode 100644
index 00000000000..9010b37bf5b
--- /dev/null
+++ b/drivers/staging/tidspbridge/services/sync.c
@@ -0,0 +1,104 @@
+/*
+ * sync.c
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * Synchronization services.
+ *
+ * Copyright (C) 2005-2006 Texas Instruments, Inc.
+ *
+ * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+/* ----------------------------------- Host OS */
+#include <dspbridge/host_os.h>
+
+/* ----------------------------------- This */
+#include <dspbridge/sync.h>
+
+DEFINE_SPINLOCK(sync_lock);
+
+/**
+ * sync_set_event() - set or signal and specified event
+ * @event: Event to be set..
+ *
+ * set the @event, if there is an thread waiting for the event
+ * it will be waken up, this function only wakes one thread.
+ */
+
+void sync_set_event(struct sync_object *event)
+{
+ spin_lock_bh(&sync_lock);
+ complete(&event->comp);
+ if (event->multi_comp)
+ complete(event->multi_comp);
+ spin_unlock_bh(&sync_lock);
+}
+
+/**
+ * sync_wait_on_multiple_events() - waits for multiple events to be set.
+ * @events: Array of events to wait for them.
+ * @count: number of elements of the array.
+ * @timeout timeout on waiting for the evetns.
+ * @pu_index index of the event set.
+ *
+ * This functios will wait until any of the array element is set or until
+ * timeout. In case of success the function will return 0 and
+ * @pu_index will store the index of the array element set or in case
+ * of timeout the function will return -ETIME or in case of
+ * interrupting by a signal it will return -EPERM.
+ */
+
+int sync_wait_on_multiple_events(struct sync_object **events,
+ unsigned count, unsigned timeout,
+ unsigned *index)
+{
+ unsigned i;
+ int status = -EPERM;
+ struct completion m_comp;
+
+ init_completion(&m_comp);
+
+ if (SYNC_INFINITE == timeout)
+ timeout = MAX_SCHEDULE_TIMEOUT;
+
+ spin_lock_bh(&sync_lock);
+ for (i = 0; i < count; i++) {
+ if (completion_done(&events[i]->comp)) {
+ INIT_COMPLETION(events[i]->comp);
+ *index = i;
+ spin_unlock_bh(&sync_lock);
+ status = 0;
+ goto func_end;
+ }
+ }
+
+ for (i = 0; i < count; i++)
+ events[i]->multi_comp = &m_comp;
+
+ spin_unlock_bh(&sync_lock);
+
+ if (!wait_for_completion_interruptible_timeout(&m_comp,
+ msecs_to_jiffies(timeout)))
+ status = -ETIME;
+
+ spin_lock_bh(&sync_lock);
+ for (i = 0; i < count; i++) {
+ if (completion_done(&events[i]->comp)) {
+ INIT_COMPLETION(events[i]->comp);
+ *index = i;
+ status = 0;
+ }
+ events[i]->multi_comp = NULL;
+ }
+ spin_unlock_bh(&sync_lock);
+func_end:
+ return status;
+}
+
diff --git a/drivers/staging/tm6000/Kconfig b/drivers/staging/tm6000/Kconfig
index 3657e33e881..c725356cc34 100644
--- a/drivers/staging/tm6000/Kconfig
+++ b/drivers/staging/tm6000/Kconfig
@@ -26,8 +26,8 @@ config VIDEO_TM6000_ALSA
module will be called tm6000-alsa.
config VIDEO_TM6000_DVB
- bool "DVB Support for tm6000 based TV cards"
- depends on VIDEO_TM6000 && DVB_CORE && EXPERIMENTAL
+ tristate "DVB Support for tm6000 based TV cards"
+ depends on VIDEO_TM6000 && DVB_CORE && USB && EXPERIMENTAL
select DVB_ZL10353
---help---
This adds support for DVB cards based on the tm5600/tm6000 chip.
diff --git a/drivers/staging/tm6000/Makefile b/drivers/staging/tm6000/Makefile
index 93370fccc07..77e06bfd2c4 100644
--- a/drivers/staging/tm6000/Makefile
+++ b/drivers/staging/tm6000/Makefile
@@ -2,14 +2,12 @@ tm6000-objs := tm6000-cards.o \
tm6000-core.o \
tm6000-i2c.o \
tm6000-video.o \
- tm6000-stds.o
-
-ifeq ($(CONFIG_VIDEO_TM6000_DVB),y)
-tm6000-objs += tm6000-dvb.o
-endif
+ tm6000-stds.o \
+ tm6000-input.o
obj-$(CONFIG_VIDEO_TM6000) += tm6000.o
obj-$(CONFIG_VIDEO_TM6000_ALSA) += tm6000-alsa.o
+obj-$(CONFIG_VIDEO_TM6000_DVB) += tm6000-dvb.o
EXTRA_CFLAGS = -Idrivers/media/video
EXTRA_CFLAGS += -Idrivers/media/common/tuners
diff --git a/drivers/staging/tm6000/tm6000-alsa.c b/drivers/staging/tm6000/tm6000-alsa.c
index 273e26ede65..087137d9164 100644
--- a/drivers/staging/tm6000/tm6000-alsa.c
+++ b/drivers/staging/tm6000/tm6000-alsa.c
@@ -16,6 +16,7 @@
#include <linux/interrupt.h>
#include <linux/usb.h>
#include <linux/slab.h>
+#include <linux/vmalloc.h>
#include <asm/delay.h>
#include <sound/core.h>
@@ -36,34 +37,11 @@
} while (0)
/****************************************************************************
- Data type declarations - Can be moded to a header file later
- ****************************************************************************/
-
-struct snd_tm6000_card {
- struct snd_card *card;
-
- spinlock_t reg_lock;
-
- atomic_t count;
-
- unsigned int period_size;
- unsigned int num_periods;
-
- struct tm6000_core *core;
- struct tm6000_buffer *buf;
-
- int bufsize;
-
- struct snd_pcm_substream *substream;
-};
-
-
-/****************************************************************************
Module global static vars
****************************************************************************/
static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */
-static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */
+
static int enable[SNDRV_CARDS] = {1, [1 ... (SNDRV_CARDS - 1)] = 1};
module_param_array(enable, bool, NULL, 0444);
@@ -100,11 +78,15 @@ static int _tm6000_start_audio_dma(struct snd_tm6000_card *chip)
struct tm6000_core *core = chip->core;
int val;
+ dprintk(1, "Starting audio DMA\n");
+
/* Enables audio */
val = tm6000_get_reg(core, TM6010_REQ07_RCC_ACTIVE_VIDEO_IF, 0x0);
val |= 0x20;
tm6000_set_reg(core, TM6010_REQ07_RCC_ACTIVE_VIDEO_IF, val);
+ tm6000_set_audio_bitrate(core, 48000);
+
tm6000_set_reg(core, TM6010_REQ08_R01_A_INIT, 0x80);
return 0;
@@ -129,19 +111,39 @@ static int _tm6000_stop_audio_dma(struct snd_tm6000_card *chip)
return 0;
}
-static int dsp_buffer_free(struct snd_tm6000_card *chip)
+static void dsp_buffer_free(struct snd_pcm_substream *substream)
{
- BUG_ON(!chip->bufsize);
+ struct snd_tm6000_card *chip = snd_pcm_substream_chip(substream);
dprintk(2, "Freeing buffer\n");
- /* FIXME: Frees buffer */
+ vfree(substream->runtime->dma_area);
+ substream->runtime->dma_area = NULL;
+ substream->runtime->dma_bytes = 0;
+}
- chip->bufsize = 0;
+static int dsp_buffer_alloc(struct snd_pcm_substream *substream, int size)
+{
+ struct snd_tm6000_card *chip = snd_pcm_substream_chip(substream);
+
+ dprintk(2, "Allocating buffer\n");
+
+ if (substream->runtime->dma_area) {
+ if (substream->runtime->dma_bytes > size)
+ return 0;
+ dsp_buffer_free(substream);
+ }
- return 0;
+ substream->runtime->dma_area = vmalloc(size);
+ if (!substream->runtime->dma_area)
+ return -ENOMEM;
+
+ substream->runtime->dma_bytes = size;
+
+ return 0;
}
+
/****************************************************************************
ALSA PCM Interface
****************************************************************************/
@@ -158,16 +160,16 @@ static struct snd_pcm_hardware snd_tm6000_digital_hw = {
SNDRV_PCM_INFO_MMAP_VALID,
.formats = SNDRV_PCM_FMTBIT_S16_LE,
- .rates = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000,
- .rate_min = 44100,
+ .rates = SNDRV_PCM_RATE_48000,
+ .rate_min = 48000,
.rate_max = 48000,
.channels_min = 2,
.channels_max = 2,
- .period_bytes_min = DEFAULT_FIFO_SIZE/4,
- .period_bytes_max = DEFAULT_FIFO_SIZE/4,
+ .period_bytes_min = 62720,
+ .period_bytes_max = 62720,
.periods_min = 1,
.periods_max = 1024,
- .buffer_bytes_max = (1024*1024),
+ .buffer_bytes_max = 62720 * 8,
};
/*
@@ -202,29 +204,64 @@ static int snd_tm6000_close(struct snd_pcm_substream *substream)
return 0;
}
+static int tm6000_fillbuf(struct tm6000_core *core, char *buf, int size)
+{
+ struct snd_tm6000_card *chip = core->adev;
+ struct snd_pcm_substream *substream = chip->substream;
+ struct snd_pcm_runtime *runtime;
+ int period_elapsed = 0;
+ unsigned int stride, buf_pos;
+
+ if (!size || !substream)
+ return -EINVAL;
+
+ runtime = substream->runtime;
+ if (!runtime || !runtime->dma_area)
+ return -EINVAL;
+
+ buf_pos = chip->buf_pos;
+ stride = runtime->frame_bits >> 3;
+
+ dprintk(1, "Copying %d bytes at %p[%d] - buf size=%d x %d\n", size,
+ runtime->dma_area, buf_pos,
+ (unsigned int)runtime->buffer_size, stride);
+
+ if (buf_pos + size >= runtime->buffer_size * stride) {
+ unsigned int cnt = runtime->buffer_size * stride - buf_pos;
+ memcpy(runtime->dma_area + buf_pos, buf, cnt);
+ memcpy(runtime->dma_area, buf + cnt, size - cnt);
+ } else
+ memcpy(runtime->dma_area + buf_pos, buf, size);
+
+ chip->buf_pos += size;
+ if (chip->buf_pos >= runtime->buffer_size * stride)
+ chip->buf_pos -= runtime->buffer_size * stride;
+
+ chip->period_pos += size;
+ if (chip->period_pos >= runtime->period_size) {
+ chip->period_pos -= runtime->period_size;
+ period_elapsed = 1;
+ }
+
+ if (period_elapsed)
+ snd_pcm_period_elapsed(substream);
+
+ return 0;
+}
+
/*
* hw_params callback
*/
static int snd_tm6000_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *hw_params)
{
- struct snd_tm6000_card *chip = snd_pcm_substream_chip(substream);
-
- if (substream->runtime->dma_area) {
- dsp_buffer_free(chip);
- substream->runtime->dma_area = NULL;
- }
-
- chip->period_size = params_period_bytes(hw_params);
- chip->num_periods = params_periods(hw_params);
- chip->bufsize = chip->period_size * params_periods(hw_params);
-
- BUG_ON(!chip->bufsize);
+ int size, rc;
- dprintk(1, "Setting buffer\n");
-
- /* FIXME: Allocate buffer for audio */
+ size = params_period_bytes(hw_params) * params_periods(hw_params);
+ rc = dsp_buffer_alloc(substream, size);
+ if (rc < 0)
+ return rc;
return 0;
}
@@ -234,13 +271,9 @@ static int snd_tm6000_hw_params(struct snd_pcm_substream *substream,
*/
static int snd_tm6000_hw_free(struct snd_pcm_substream *substream)
{
-
struct snd_tm6000_card *chip = snd_pcm_substream_chip(substream);
- if (substream->runtime->dma_area) {
- dsp_buffer_free(chip);
- substream->runtime->dma_area = NULL;
- }
+ _tm6000_stop_audio_dma(chip);
return 0;
}
@@ -250,6 +283,11 @@ static int snd_tm6000_hw_free(struct snd_pcm_substream *substream)
*/
static int snd_tm6000_prepare(struct snd_pcm_substream *substream)
{
+ struct snd_tm6000_card *chip = snd_pcm_substream_chip(substream);
+
+ chip->buf_pos = 0;
+ chip->period_pos = 0;
+
return 0;
}
@@ -287,12 +325,8 @@ static int snd_tm6000_card_trigger(struct snd_pcm_substream *substream, int cmd)
static snd_pcm_uframes_t snd_tm6000_pointer(struct snd_pcm_substream *substream)
{
struct snd_tm6000_card *chip = snd_pcm_substream_chip(substream);
- struct snd_pcm_runtime *runtime = substream->runtime;
- u16 count;
-
- count = atomic_read(&chip->count);
- return runtime->period_size * (count & (runtime->periods-1));
+ return chip->buf_pos;
}
/*
@@ -312,21 +346,6 @@ static struct snd_pcm_ops snd_tm6000_pcm_ops = {
/*
* create a PCM device
*/
-static int __devinit snd_tm6000_pcm(struct snd_tm6000_card *chip,
- int device, char *name)
-{
- int err;
- struct snd_pcm *pcm;
-
- err = snd_pcm_new(chip->card, name, device, 0, 1, &pcm);
- if (err < 0)
- return err;
- pcm->private_data = chip;
- strcpy(pcm->name, name);
- snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_tm6000_pcm_ops);
-
- return 0;
-}
/* FIXME: Control interface - How to control volume/mute? */
@@ -337,27 +356,41 @@ static int __devinit snd_tm6000_pcm(struct snd_tm6000_card *chip,
/*
* Alsa Constructor - Component probe
*/
-
-int tm6000_audio_init(struct tm6000_core *dev, int idx)
+int tm6000_audio_init(struct tm6000_core *dev)
{
- struct snd_card *card;
- struct snd_tm6000_card *chip;
- int rc, len;
- char component[14];
+ struct snd_card *card;
+ struct snd_tm6000_card *chip;
+ int rc;
+ static int devnr;
+ char component[14];
+ struct snd_pcm *pcm;
+
+ if (!dev)
+ return 0;
- if (idx >= SNDRV_CARDS)
+ if (devnr >= SNDRV_CARDS)
return -ENODEV;
- if (!enable[idx])
+ if (!enable[devnr])
return -ENOENT;
- rc = snd_card_create(index[idx], id[idx], THIS_MODULE, 0, &card);
+ rc = snd_card_create(index[devnr], "tm6000", THIS_MODULE, 0, &card);
if (rc < 0) {
- snd_printk(KERN_ERR "cannot create card instance %d\n", idx);
+ snd_printk(KERN_ERR "cannot create card instance %d\n", devnr);
return rc;
}
+ strcpy(card->driver, "tm6000-alsa");
+ strcpy(card->shortname, "TM5600/60x0");
+ sprintf(card->longname, "TM5600/60x0 Audio at bus %d device %d",
+ dev->udev->bus->busnum, dev->udev->devnum);
+
+ sprintf(component, "USB%04x:%04x",
+ le16_to_cpu(dev->udev->descriptor.idVendor),
+ le16_to_cpu(dev->udev->descriptor.idProduct));
+ snd_component_add(card, component);
+ snd_card_set_dev(card, &dev->udev->dev);
- chip = kzalloc(sizeof(*chip), GFP_KERNEL);
+ chip = kzalloc(sizeof(struct snd_tm6000_card), GFP_KERNEL);
if (!chip) {
rc = -ENOMEM;
goto error;
@@ -365,45 +398,24 @@ int tm6000_audio_init(struct tm6000_core *dev, int idx)
chip->core = dev;
chip->card = card;
+ dev->adev = chip;
+ spin_lock_init(&chip->reg_lock);
- strcpy(card->driver, "tm6000-alsa");
- sprintf(component, "USB%04x:%04x",
- le16_to_cpu(dev->udev->descriptor.idVendor),
- le16_to_cpu(dev->udev->descriptor.idProduct));
- snd_component_add(card, component);
-
- if (dev->udev->descriptor.iManufacturer)
- len = usb_string(dev->udev,
- dev->udev->descriptor.iManufacturer,
- card->longname, sizeof(card->longname));
- else
- len = 0;
-
- if (len > 0)
- strlcat(card->longname, " ", sizeof(card->longname));
-
- strlcat(card->longname, card->shortname, sizeof(card->longname));
-
- len = strlcat(card->longname, " at ", sizeof(card->longname));
-
- if (len < sizeof(card->longname))
- usb_make_path(dev->udev, card->longname + len,
- sizeof(card->longname) - len);
-
- strlcat(card->longname,
- dev->udev->speed == USB_SPEED_LOW ? ", low speed" :
- dev->udev->speed == USB_SPEED_FULL ? ", full speed" :
- ", high speed",
- sizeof(card->longname));
-
- rc = snd_tm6000_pcm(chip, 0, "tm6000 Digital");
+ rc = snd_pcm_new(card, "TM6000 Audio", 0, 0, 1, &pcm);
if (rc < 0)
goto error;
+ pcm->info_flags = 0;
+ pcm->private_data = chip;
+ strcpy(pcm->name, "Trident TM5600/60x0");
+
+ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_tm6000_pcm_ops);
+
rc = snd_card_register(card);
if (rc < 0)
goto error;
+ dprintk(1,"Registered audio driver for %s\n", card->longname);
return 0;
@@ -414,14 +426,31 @@ error:
static int tm6000_audio_fini(struct tm6000_core *dev)
{
+ struct snd_tm6000_card *chip = dev->adev;
+
+ if (!dev)
+ return 0;
+
+ if (!chip)
+ return 0;
+
+ if (!chip->card)
+ return 0;
+
+ snd_card_free(chip->card);
+ chip->card = NULL;
+ kfree(chip);
+ dev->adev = NULL;
+
return 0;
}
struct tm6000_ops audio_ops = {
- .id = TM6000_AUDIO,
+ .type = TM6000_AUDIO,
.name = "TM6000 Audio Extension",
.init = tm6000_audio_init,
.fini = tm6000_audio_fini,
+ .fillbuf = tm6000_fillbuf,
};
static int __init tm6000_alsa_register(void)
diff --git a/drivers/staging/tm6000/tm6000-cards.c b/drivers/staging/tm6000/tm6000-cards.c
index 6a9ae40c7c6..9d091c34991 100644
--- a/drivers/staging/tm6000/tm6000-cards.c
+++ b/drivers/staging/tm6000/tm6000-cards.c
@@ -29,6 +29,7 @@
#include <media/tuner.h>
#include <media/tvaudio.h>
#include <media/i2c-addr.h>
+#include <media/rc-map.h>
#include "tm6000.h"
#include "tm6000-regs.h"
@@ -69,6 +70,8 @@ struct tm6000_board {
int demod_addr; /* demodulator address */
struct tm6000_gpio gpio;
+
+ char *ir_codes;
};
struct tm6000_board tm6000_boards[] = {
@@ -276,6 +279,7 @@ struct tm6000_board tm6000_boards[] = {
.dvb_led = TM6010_GPIO_5,
.ir = TM6010_GPIO_0,
},
+ .ir_codes = RC_MAP_NEC_TERRATEC_CINERGY_XS,
},
[TM6010_BOARD_TWINHAN_TU501] = {
.name = "Twinhan TU501(704D1)",
@@ -347,7 +351,7 @@ int tm6000_xc5000_callback(void *ptr, int component, int command, int arg)
}
return (rc);
}
-
+EXPORT_SYMBOL_GPL(tm6000_xc5000_callback);
/* Tuner callback to provide the proper gpio changes needed for xc2028 */
@@ -361,6 +365,8 @@ int tm6000_tuner_callback(void *ptr, int component, int command, int arg)
switch (command) {
case XC2028_RESET_CLK:
+ tm6000_ir_wait(dev, 0);
+
tm6000_set_reg(dev, REQ_04_EN_DISABLE_MCU_INT,
0x02, arg);
msleep(10);
@@ -410,13 +416,14 @@ int tm6000_tuner_callback(void *ptr, int component, int command, int arg)
msleep(130);
break;
}
+
+ tm6000_ir_wait(dev, 1);
break;
case 1:
tm6000_set_reg(dev, REQ_04_EN_DISABLE_MCU_INT,
0x02, 0x01);
msleep(10);
break;
-
case 2:
rc = tm6000_i2c_reset(dev, 100);
break;
@@ -424,6 +431,7 @@ int tm6000_tuner_callback(void *ptr, int component, int command, int arg)
}
return rc;
}
+EXPORT_SYMBOL_GPL(tm6000_tuner_callback);
int tm6000_cards_setup(struct tm6000_core *dev)
{
@@ -635,6 +643,8 @@ static int tm6000_init_dev(struct tm6000_core *dev)
dev->gpio = tm6000_boards[dev->model].gpio;
+ dev->ir_codes = tm6000_boards[dev->model].ir_codes;
+
dev->demod_addr = tm6000_boards[dev->model].demod_addr;
dev->caps = tm6000_boards[dev->model].caps;
@@ -681,31 +691,13 @@ static int tm6000_init_dev(struct tm6000_core *dev)
goto err;
tm6000_add_into_devlist(dev);
-
tm6000_init_extension(dev);
- if (dev->caps.has_dvb) {
- dev->dvb = kzalloc(sizeof(*(dev->dvb)), GFP_KERNEL);
- if (!dev->dvb) {
- rc = -ENOMEM;
- goto err2;
- }
+ tm6000_ir_init(dev);
-#ifdef CONFIG_VIDEO_TM6000_DVB
- rc = tm6000_dvb_register(dev);
- if (rc < 0) {
- kfree(dev->dvb);
- dev->dvb = NULL;
- goto err2;
- }
-#endif
- }
mutex_unlock(&dev->lock);
return 0;
-err2:
- v4l2_device_unregister(&dev->v4l2_dev);
-
err:
mutex_unlock(&dev->lock);
return rc;
@@ -724,7 +716,7 @@ static void get_max_endpoint(struct usb_device *udev,
unsigned int size = tmp & 0x7ff;
if (udev->speed == USB_SPEED_HIGH)
- size = size * hb_mult (tmp);
+ size = size * hb_mult(tmp);
if (size > tm_ep->maxsize) {
tm_ep->endp = curr_e;
@@ -848,6 +840,19 @@ static int tm6000_usb_probe(struct usb_interface *interface,
&dev->isoc_out);
}
break;
+ case USB_ENDPOINT_XFER_INT:
+ if (!dir_out) {
+ get_max_endpoint(usbdev,
+ &interface->altsetting[i],
+ "INT IN", e,
+ &dev->int_in);
+ } else {
+ get_max_endpoint(usbdev,
+ &interface->altsetting[i],
+ "INT OUT", e,
+ &dev->int_out);
+ }
+ break;
}
}
}
@@ -906,12 +911,7 @@ static void tm6000_usb_disconnect(struct usb_interface *interface)
mutex_lock(&dev->lock);
-#ifdef CONFIG_VIDEO_TM6000_DVB
- if (dev->dvb) {
- tm6000_dvb_unregister(dev);
- kfree(dev->dvb);
- }
-#endif
+ tm6000_ir_fini(dev);
if (dev->gpio.power_led) {
switch (dev->model) {
@@ -942,8 +942,8 @@ static void tm6000_usb_disconnect(struct usb_interface *interface)
usb_put_dev(dev->udev);
- tm6000_remove_from_devlist(dev);
tm6000_close_extension(dev);
+ tm6000_remove_from_devlist(dev);
mutex_unlock(&dev->lock);
kfree(dev);
diff --git a/drivers/staging/tm6000/tm6000-core.c b/drivers/staging/tm6000/tm6000-core.c
index c3690e3580d..cded411d8bb 100644
--- a/drivers/staging/tm6000/tm6000-core.c
+++ b/drivers/staging/tm6000/tm6000-core.c
@@ -32,66 +32,64 @@
#define USB_TIMEOUT 5*HZ /* ms */
-int tm6000_read_write_usb (struct tm6000_core *dev, u8 req_type, u8 req,
- u16 value, u16 index, u8 *buf, u16 len)
+int tm6000_read_write_usb(struct tm6000_core *dev, u8 req_type, u8 req,
+ u16 value, u16 index, u8 *buf, u16 len)
{
int ret, i;
unsigned int pipe;
- static int ini=0, last=0, n=0;
- u8 *data=NULL;
+ static int ini = 0, last = 0, n = 0;
+ u8 *data = NULL;
if (len)
data = kzalloc(len, GFP_KERNEL);
if (req_type & USB_DIR_IN)
- pipe=usb_rcvctrlpipe(dev->udev, 0);
+ pipe = usb_rcvctrlpipe(dev->udev, 0);
else {
- pipe=usb_sndctrlpipe(dev->udev, 0);
+ pipe = usb_sndctrlpipe(dev->udev, 0);
memcpy(data, buf, len);
}
if (tm6000_debug & V4L2_DEBUG_I2C) {
if (!ini)
- last=ini=jiffies;
+ last = ini = jiffies;
printk("%06i (dev %p, pipe %08x): ", n, dev->udev, pipe);
- printk( "%s: %06u ms %06u ms %02x %02x %02x %02x %02x %02x %02x %02x ",
- (req_type & USB_DIR_IN)?" IN":"OUT",
+ printk("%s: %06u ms %06u ms %02x %02x %02x %02x %02x %02x %02x %02x ",
+ (req_type & USB_DIR_IN) ? " IN" : "OUT",
jiffies_to_msecs(jiffies-last),
jiffies_to_msecs(jiffies-ini),
- req_type, req,value&0xff,value>>8, index&0xff, index>>8,
- len&0xff, len>>8);
- last=jiffies;
+ req_type, req, value&0xff, value>>8, index&0xff,
+ index>>8, len&0xff, len>>8);
+ last = jiffies;
n++;
- if ( !(req_type & USB_DIR_IN) ) {
+ if (!(req_type & USB_DIR_IN)) {
printk(">>> ");
- for (i=0;i<len;i++) {
- printk(" %02x",buf[i]);
- }
+ for (i = 0; i < len; i++)
+ printk(" %02x", buf[i]);
printk("\n");
}
}
- ret = usb_control_msg(dev->udev, pipe, req, req_type, value, index, data,
- len, USB_TIMEOUT);
+ ret = usb_control_msg(dev->udev, pipe, req, req_type, value, index,
+ data, len, USB_TIMEOUT);
if (req_type & USB_DIR_IN)
memcpy(buf, data, len);
if (tm6000_debug & V4L2_DEBUG_I2C) {
- if (ret<0) {
+ if (ret < 0) {
if (req_type & USB_DIR_IN)
- printk("<<< (len=%d)\n",len);
+ printk("<<< (len=%d)\n", len);
printk("%s: Error #%d\n", __FUNCTION__, ret);
} else if (req_type & USB_DIR_IN) {
printk("<<< ");
- for (i=0;i<len;i++) {
- printk(" %02x",buf[i]);
- }
+ for (i = 0; i < len; i++)
+ printk(" %02x", buf[i]);
printk("\n");
}
}
@@ -103,52 +101,52 @@ int tm6000_read_write_usb (struct tm6000_core *dev, u8 req_type, u8 req,
return ret;
}
-int tm6000_set_reg (struct tm6000_core *dev, u8 req, u16 value, u16 index)
+int tm6000_set_reg(struct tm6000_core *dev, u8 req, u16 value, u16 index)
{
return
- tm6000_read_write_usb (dev, USB_DIR_OUT | USB_TYPE_VENDOR,
- req, value, index, NULL, 0);
+ tm6000_read_write_usb(dev, USB_DIR_OUT | USB_TYPE_VENDOR,
+ req, value, index, NULL, 0);
}
EXPORT_SYMBOL_GPL(tm6000_set_reg);
-int tm6000_get_reg (struct tm6000_core *dev, u8 req, u16 value, u16 index)
+int tm6000_get_reg(struct tm6000_core *dev, u8 req, u16 value, u16 index)
{
int rc;
u8 buf[1];
- rc=tm6000_read_write_usb (dev, USB_DIR_IN | USB_TYPE_VENDOR, req,
- value, index, buf, 1);
+ rc = tm6000_read_write_usb(dev, USB_DIR_IN | USB_TYPE_VENDOR, req,
+ value, index, buf, 1);
- if (rc<0)
+ if (rc < 0)
return rc;
return *buf;
}
EXPORT_SYMBOL_GPL(tm6000_get_reg);
-int tm6000_get_reg16 (struct tm6000_core *dev, u8 req, u16 value, u16 index)
+int tm6000_get_reg16(struct tm6000_core *dev, u8 req, u16 value, u16 index)
{
int rc;
u8 buf[2];
- rc=tm6000_read_write_usb (dev, USB_DIR_IN | USB_TYPE_VENDOR, req,
- value, index, buf, 2);
+ rc = tm6000_read_write_usb(dev, USB_DIR_IN | USB_TYPE_VENDOR, req,
+ value, index, buf, 2);
- if (rc<0)
+ if (rc < 0)
return rc;
return buf[1]|buf[0]<<8;
}
-int tm6000_get_reg32 (struct tm6000_core *dev, u8 req, u16 value, u16 index)
+int tm6000_get_reg32(struct tm6000_core *dev, u8 req, u16 value, u16 index)
{
int rc;
u8 buf[4];
- rc=tm6000_read_write_usb (dev, USB_DIR_IN | USB_TYPE_VENDOR, req,
- value, index, buf, 4);
+ rc = tm6000_read_write_usb(dev, USB_DIR_IN | USB_TYPE_VENDOR, req,
+ value, index, buf, 4);
- if (rc<0)
+ if (rc < 0)
return rc;
return buf[3] | buf[2] << 8 | buf[1] << 16 | buf[0] << 24;
@@ -188,7 +186,7 @@ void tm6000_set_fourcc_format(struct tm6000_core *dev)
}
}
-int tm6000_init_analog_mode (struct tm6000_core *dev)
+int tm6000_init_analog_mode(struct tm6000_core *dev)
{
if (dev->dev_type == TM6010) {
int val;
@@ -294,12 +292,10 @@ int tm6000_init_analog_mode (struct tm6000_core *dev)
/* Enables soft reset */
tm6000_set_reg(dev, TM6010_REQ07_R3F_RESET, 0x01);
- if (dev->scaler) {
+ if (dev->scaler)
tm6000_set_reg(dev, TM6010_REQ07_RC0_ACTIVE_VIDEO_SOURCE, 0x20);
- } else {
- /* Enable Hfilter and disable TS Drop err */
+ else /* Enable Hfilter and disable TS Drop err */
tm6000_set_reg(dev, TM6010_REQ07_RC0_ACTIVE_VIDEO_SOURCE, 0x80);
- }
tm6000_set_reg(dev, TM6010_REQ07_RC3_HSTART1, 0x88);
tm6000_set_reg(dev, TM6010_REQ07_RD8_IR_WAKEUP_SEL, 0x23);
@@ -332,13 +328,13 @@ int tm6000_init_analog_mode (struct tm6000_core *dev)
/*FIXME: Hack!!! */
struct v4l2_frequency f;
mutex_lock(&dev->lock);
- f.frequency=dev->freq;
+ f.frequency = dev->freq;
v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_frequency, &f);
mutex_unlock(&dev->lock);
msleep(100);
- tm6000_set_standard (dev, &dev->norm);
- tm6000_set_audio_bitrate (dev,48000);
+ tm6000_set_standard(dev, &dev->norm);
+ tm6000_set_audio_bitrate(dev, 48000);
/* switch dvb led off */
if (dev->gpio.dvb_led) {
@@ -349,7 +345,7 @@ int tm6000_init_analog_mode (struct tm6000_core *dev)
return 0;
}
-int tm6000_init_digital_mode (struct tm6000_core *dev)
+int tm6000_init_digital_mode(struct tm6000_core *dev)
{
if (dev->dev_type == TM6010) {
int val;
@@ -366,10 +362,8 @@ int tm6000_init_digital_mode (struct tm6000_core *dev)
tm6000_set_reg(dev, TM6010_REQ08_RE2_POWER_DOWN_CTRL1, 0xfc);
tm6000_set_reg(dev, TM6010_REQ08_RE6_POWER_DOWN_CTRL2, 0xff);
tm6000_set_reg(dev, TM6010_REQ08_RF1_AADC_POWER_DOWN, 0xfe);
- tm6000_read_write_usb (dev, 0xc0, 0x0e, 0x00c2, 0x0008, buf, 2);
- printk (KERN_INFO "buf %#x %#x \n", buf[0], buf[1]);
-
-
+ tm6000_read_write_usb(dev, 0xc0, 0x0e, 0x00c2, 0x0008, buf, 2);
+ printk(KERN_INFO"buf %#x %#x\n", buf[0], buf[1]);
} else {
tm6000_set_reg(dev, TM6010_REQ07_RFF_SOFT_RESET, 0x08);
tm6000_set_reg(dev, TM6010_REQ07_RFF_SOFT_RESET, 0x00);
@@ -377,7 +371,7 @@ int tm6000_init_digital_mode (struct tm6000_core *dev)
tm6000_set_reg(dev, TM6010_REQ07_RD8_IR_PULSE_CNT0, 0x08);
tm6000_set_reg(dev, TM6010_REQ07_RE2_OUT_SEL2, 0x0c);
tm6000_set_reg(dev, TM6010_REQ07_RE8_TYPESEL_MOS_I2S, 0xff);
- tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x00eb, 0xd8);
+ tm6000_set_reg(dev, REQ_07_SET_GET_AVREG, 0x00eb, 0xd8);
tm6000_set_reg(dev, TM6010_REQ07_RC0_ACTIVE_VIDEO_SOURCE, 0x40);
tm6000_set_reg(dev, TM6010_REQ07_RC1_TRESHOLD, 0xd0);
tm6000_set_reg(dev, TM6010_REQ07_RC3_HSTART1, 0x09);
@@ -388,14 +382,14 @@ int tm6000_init_digital_mode (struct tm6000_core *dev)
tm6000_set_reg(dev, TM6010_REQ07_RE2_OUT_SEL2, 0x0c);
tm6000_set_reg(dev, TM6010_REQ07_RE8_TYPESEL_MOS_I2S, 0xff);
- tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x00eb, 0x08);
+ tm6000_set_reg(dev, REQ_07_SET_GET_AVREG, 0x00eb, 0x08);
msleep(50);
- tm6000_set_reg (dev, REQ_04_EN_DISABLE_MCU_INT, 0x0020, 0x00);
+ tm6000_set_reg(dev, REQ_04_EN_DISABLE_MCU_INT, 0x0020, 0x00);
msleep(50);
- tm6000_set_reg (dev, REQ_04_EN_DISABLE_MCU_INT, 0x0020, 0x01);
+ tm6000_set_reg(dev, REQ_04_EN_DISABLE_MCU_INT, 0x0020, 0x01);
msleep(50);
- tm6000_set_reg (dev, REQ_04_EN_DISABLE_MCU_INT, 0x0020, 0x00);
+ tm6000_set_reg(dev, REQ_04_EN_DISABLE_MCU_INT, 0x0020, 0x00);
msleep(100);
}
@@ -407,6 +401,7 @@ int tm6000_init_digital_mode (struct tm6000_core *dev)
return 0;
}
+EXPORT_SYMBOL(tm6000_init_digital_mode);
struct reg_init {
u8 req;
@@ -566,9 +561,9 @@ struct reg_init tm6010_init_tab[] = {
{ TM6010_REQ07_RD8_IR_WAKEUP_SEL, 0xff },
};
-int tm6000_init (struct tm6000_core *dev)
+int tm6000_init(struct tm6000_core *dev)
{
- int board, rc=0, i, size;
+ int board, rc = 0, i, size;
struct reg_init *tab;
if (dev->dev_type == TM6010) {
@@ -580,12 +575,12 @@ int tm6000_init (struct tm6000_core *dev)
}
/* Load board's initialization table */
- for (i=0; i< size; i++) {
- rc= tm6000_set_reg (dev, tab[i].req, tab[i].reg, tab[i].val);
- if (rc<0) {
- printk (KERN_ERR "Error %i while setting req %d, "
- "reg %d to value %d\n", rc,
- tab[i].req,tab[i].reg, tab[i].val);
+ for (i = 0; i < size; i++) {
+ rc = tm6000_set_reg(dev, tab[i].req, tab[i].reg, tab[i].val);
+ if (rc < 0) {
+ printk(KERN_ERR "Error %i while setting req %d, "
+ "reg %d to value %d\n", rc,
+ tab[i].req, tab[i].reg, tab[i].val);
return rc;
}
}
@@ -593,12 +588,11 @@ int tm6000_init (struct tm6000_core *dev)
msleep(5); /* Just to be conservative */
/* Check board version - maybe 10Moons specific */
- board=tm6000_get_reg32 (dev, REQ_40_GET_VERSION, 0, 0);
- if (board >=0) {
- printk (KERN_INFO "Board version = 0x%08x\n",board);
- } else {
- printk (KERN_ERR "Error %i while retrieving board version\n",board);
- }
+ board = tm6000_get_reg32(dev, REQ_40_GET_VERSION, 0, 0);
+ if (board >= 0)
+ printk(KERN_INFO "Board version = 0x%08x\n", board);
+ else
+ printk(KERN_ERR "Error %i while retrieving board version\n", board);
rc = tm6000_cards_setup(dev);
@@ -609,23 +603,32 @@ int tm6000_set_audio_bitrate(struct tm6000_core *dev, int bitrate)
{
int val;
- val=tm6000_get_reg (dev, REQ_07_SET_GET_AVREG, 0xeb, 0x0);
-printk("Original value=%d\n",val);
- if (val<0)
+ if (dev->dev_type == TM6010) {
+ val = tm6000_get_reg(dev, TM6010_REQ08_R0A_A_I2S_MOD, 0);
+ if (val < 0)
+ return val;
+ val = (val & 0xf0) | 0x1; /* 48 kHz, not muted */
+ val = tm6000_set_reg(dev, TM6010_REQ08_R0A_A_I2S_MOD, val);
+ if (val < 0)
+ return val;
+ }
+
+ val = tm6000_get_reg(dev, REQ_07_SET_GET_AVREG, 0xeb, 0x0);
+ if (val < 0)
return val;
val &= 0x0f; /* Preserve the audio input control bits */
switch (bitrate) {
case 44100:
- val|=0xd0;
- dev->audio_bitrate=bitrate;
+ val |= 0xd0;
+ dev->audio_bitrate = bitrate;
break;
case 48000:
- val|=0x60;
- dev->audio_bitrate=bitrate;
+ val |= 0x60;
+ dev->audio_bitrate = bitrate;
break;
}
- val=tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0xeb, val);
+ val = tm6000_set_reg(dev, REQ_07_SET_GET_AVREG, 0xeb, val);
return val;
}
@@ -659,6 +662,23 @@ void tm6000_add_into_devlist(struct tm6000_core *dev)
static LIST_HEAD(tm6000_extension_devlist);
static DEFINE_MUTEX(tm6000_extension_devlist_lock);
+int tm6000_call_fillbuf(struct tm6000_core *dev, enum tm6000_ops_type type,
+ char *buf, int size)
+{
+ struct tm6000_ops *ops = NULL;
+
+ /* FIXME: tm6000_extension_devlist_lock should be a spinlock */
+
+ if (!list_empty(&tm6000_extension_devlist)) {
+ list_for_each_entry(ops, &tm6000_extension_devlist, next) {
+ if (ops->fillbuf && ops->type == type)
+ ops->fillbuf(dev, buf, size);
+ }
+ }
+
+ return 0;
+}
+
int tm6000_register_extension(struct tm6000_ops *ops)
{
struct tm6000_core *dev = NULL;
@@ -667,10 +687,10 @@ int tm6000_register_extension(struct tm6000_ops *ops)
mutex_lock(&tm6000_extension_devlist_lock);
list_add_tail(&ops->next, &tm6000_extension_devlist);
list_for_each_entry(dev, &tm6000_devlist, devlist) {
- if (dev)
- ops->init(dev);
+ ops->init(dev);
+ printk(KERN_INFO "%s: Initialized (%s) extension\n",
+ dev->name, ops->name);
}
- printk(KERN_INFO "tm6000: Initialized (%s) extension\n", ops->name);
mutex_unlock(&tm6000_extension_devlist_lock);
mutex_unlock(&tm6000_devlist_mutex);
return 0;
diff --git a/drivers/staging/tm6000/tm6000-dvb.c b/drivers/staging/tm6000/tm6000-dvb.c
index 86c1c8b5f25..f501edccf9c 100644
--- a/drivers/staging/tm6000/tm6000-dvb.c
+++ b/drivers/staging/tm6000/tm6000-dvb.c
@@ -31,12 +31,25 @@
#include "tuner-xc2028.h"
#include "xc5000.h"
-static void inline print_err_status (struct tm6000_core *dev,
- int packet, int status)
+MODULE_DESCRIPTION("DVB driver extension module for tm5600/6000/6010 based TV cards");
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
+MODULE_LICENSE("GPL");
+
+MODULE_SUPPORTED_DEVICE("{{Trident, tm5600},"
+ "{{Trident, tm6000},"
+ "{{Trident, tm6010}");
+
+static int debug;
+
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "enable debug message");
+
+static inline void print_err_status(struct tm6000_core *dev,
+ int packet, int status)
{
char *errmsg = "Unknown";
- switch(status) {
+ switch (status) {
case -ENOENT:
errmsg = "unlinked synchronuously";
break;
@@ -62,7 +75,7 @@ static void inline print_err_status (struct tm6000_core *dev,
errmsg = "Device does not respond";
break;
}
- if (packet<0) {
+ if (packet < 0) {
dprintk(dev, 1, "URB status %d [%s].\n",
status, errmsg);
} else {
@@ -74,19 +87,17 @@ static void inline print_err_status (struct tm6000_core *dev,
static void tm6000_urb_received(struct urb *urb)
{
int ret;
- struct tm6000_core* dev = urb->context;
+ struct tm6000_core *dev = urb->context;
- if(urb->status != 0) {
- print_err_status (dev,0,urb->status);
- }
- else if(urb->actual_length>0){
+ if (urb->status != 0)
+ print_err_status(dev, 0, urb->status);
+ else if (urb->actual_length > 0)
dvb_dmx_swfilter(&dev->dvb->demux, urb->transfer_buffer,
urb->actual_length);
- }
- if(dev->dvb->streams > 0) {
+ if (dev->dvb->streams > 0) {
ret = usb_submit_urb(urb, GFP_ATOMIC);
- if(ret < 0) {
+ if (ret < 0) {
printk(KERN_ERR "tm6000: error %s\n", __FUNCTION__);
kfree(urb->transfer_buffer);
usb_free_urb(urb);
@@ -100,7 +111,7 @@ int tm6000_start_stream(struct tm6000_core *dev)
unsigned int pipe, size;
struct tm6000_dvb *dvb = dev->dvb;
- printk(KERN_INFO "tm6000: got start stream request %s\n",__FUNCTION__);
+ printk(KERN_INFO "tm6000: got start stream request %s\n", __FUNCTION__);
if (dev->mode != TM6000_MODE_DIGITAL) {
tm6000_init_digital_mode(dev);
@@ -108,7 +119,7 @@ int tm6000_start_stream(struct tm6000_core *dev)
}
dvb->bulk_urb = usb_alloc_urb(0, GFP_KERNEL);
- if(dvb->bulk_urb == NULL) {
+ if (dvb->bulk_urb == NULL) {
printk(KERN_ERR "tm6000: couldn't allocate urb\n");
return -ENOMEM;
}
@@ -120,7 +131,7 @@ int tm6000_start_stream(struct tm6000_core *dev)
size = size * 15; /* 512 x 8 or 12 or 15 */
dvb->bulk_urb->transfer_buffer = kzalloc(size, GFP_KERNEL);
- if(dvb->bulk_urb->transfer_buffer == NULL) {
+ if (dvb->bulk_urb->transfer_buffer == NULL) {
usb_free_urb(dvb->bulk_urb);
printk(KERN_ERR "tm6000: couldn't allocate transfer buffer!\n");
return -ENOMEM;
@@ -132,20 +143,20 @@ int tm6000_start_stream(struct tm6000_core *dev)
tm6000_urb_received, dev);
ret = usb_clear_halt(dev->udev, pipe);
- if(ret < 0) {
- printk(KERN_ERR "tm6000: error %i in %s during pipe reset\n",ret,__FUNCTION__);
+ if (ret < 0) {
+ printk(KERN_ERR "tm6000: error %i in %s during pipe reset\n",
+ ret, __FUNCTION__);
return ret;
- }
- else {
+ } else
printk(KERN_ERR "tm6000: pipe resetted\n");
- }
/* mutex_lock(&tm6000_driver.open_close_mutex); */
ret = usb_submit_urb(dvb->bulk_urb, GFP_KERNEL);
/* mutex_unlock(&tm6000_driver.open_close_mutex); */
if (ret) {
- printk(KERN_ERR "tm6000: submit of urb failed (error=%i)\n",ret);
+ printk(KERN_ERR "tm6000: submit of urb failed (error=%i)\n",
+ ret);
kfree(dvb->bulk_urb->transfer_buffer);
usb_free_urb(dvb->bulk_urb);
@@ -159,10 +170,10 @@ void tm6000_stop_stream(struct tm6000_core *dev)
{
struct tm6000_dvb *dvb = dev->dvb;
- if(dvb->bulk_urb) {
- printk (KERN_INFO "urb killing\n");
+ if (dvb->bulk_urb) {
+ printk(KERN_INFO "urb killing\n");
usb_kill_urb(dvb->bulk_urb);
- printk (KERN_INFO "urb buffer free\n");
+ printk(KERN_INFO "urb buffer free\n");
kfree(dvb->bulk_urb->transfer_buffer);
usb_free_urb(dvb->bulk_urb);
dvb->bulk_urb = NULL;
@@ -174,35 +185,34 @@ int tm6000_start_feed(struct dvb_demux_feed *feed)
struct dvb_demux *demux = feed->demux;
struct tm6000_core *dev = demux->priv;
struct tm6000_dvb *dvb = dev->dvb;
- printk(KERN_INFO "tm6000: got start feed request %s\n",__FUNCTION__);
+ printk(KERN_INFO "tm6000: got start feed request %s\n", __FUNCTION__);
mutex_lock(&dvb->mutex);
- if(dvb->streams == 0) {
+ if (dvb->streams == 0) {
dvb->streams = 1;
/* mutex_init(&tm6000_dev->streming_mutex); */
tm6000_start_stream(dev);
- }
- else {
+ } else
++(dvb->streams);
- }
mutex_unlock(&dvb->mutex);
return 0;
}
-int tm6000_stop_feed(struct dvb_demux_feed *feed) {
+int tm6000_stop_feed(struct dvb_demux_feed *feed)
+{
struct dvb_demux *demux = feed->demux;
struct tm6000_core *dev = demux->priv;
struct tm6000_dvb *dvb = dev->dvb;
- printk(KERN_INFO "tm6000: got stop feed request %s\n",__FUNCTION__);
+ printk(KERN_INFO "tm6000: got stop feed request %s\n", __FUNCTION__);
mutex_lock(&dvb->mutex);
- printk (KERN_INFO "stream %#x\n", dvb->streams);
+ printk(KERN_INFO "stream %#x\n", dvb->streams);
--(dvb->streams);
- if(dvb->streams == 0) {
- printk (KERN_INFO "stop stream\n");
+ if (dvb->streams == 0) {
+ printk(KERN_INFO "stop stream\n");
tm6000_stop_stream(dev);
/* mutex_destroy(&tm6000_dev->streaming_mutex); */
}
@@ -216,9 +226,9 @@ int tm6000_dvb_attach_frontend(struct tm6000_core *dev)
{
struct tm6000_dvb *dvb = dev->dvb;
- if(dev->caps.has_zl10353) {
- struct zl10353_config config =
- {.demod_address = dev->demod_addr,
+ if (dev->caps.has_zl10353) {
+ struct zl10353_config config = {
+ .demod_address = dev->demod_addr,
.no_tuner = 1,
.parallel_ts = 1,
.if2 = 45700,
@@ -227,8 +237,7 @@ int tm6000_dvb_attach_frontend(struct tm6000_core *dev)
dvb->frontend = dvb_attach(zl10353_attach, &config,
&dev->i2c_adap);
- }
- else {
+ } else {
printk(KERN_ERR "tm6000: no frontend defined for the device!\n");
return -1;
}
@@ -238,7 +247,7 @@ int tm6000_dvb_attach_frontend(struct tm6000_core *dev)
DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
-int tm6000_dvb_register(struct tm6000_core *dev)
+int register_dvb(struct tm6000_core *dev)
{
int ret = -1;
struct tm6000_dvb *dvb = dev->dvb;
@@ -249,13 +258,13 @@ int tm6000_dvb_register(struct tm6000_core *dev)
/* attach the frontend */
ret = tm6000_dvb_attach_frontend(dev);
- if(ret < 0) {
+ if (ret < 0) {
printk(KERN_ERR "tm6000: couldn't attach the frontend!\n");
goto err;
}
ret = dvb_register_adapter(&dvb->adapter, "Trident TVMaster 6000 DVB-T",
- THIS_MODULE, &dev->udev->dev, adapter_nr);
+ THIS_MODULE, &dev->udev->dev, adapter_nr);
dvb->adapter.priv = dev;
if (dvb->frontend) {
@@ -308,9 +317,8 @@ int tm6000_dvb_register(struct tm6000_core *dev)
break;
}
}
- } else {
+ } else
printk(KERN_ERR "tm6000: no frontend found\n");
- }
dvb->demux.dmx.capabilities = DMX_TS_FILTERING | DMX_SECTION_FILTERING
| DMX_MEMORY_BASED_FILTERING;
@@ -321,7 +329,7 @@ int tm6000_dvb_register(struct tm6000_core *dev)
dvb->demux.stop_feed = tm6000_stop_feed;
dvb->demux.write_to_decoder = NULL;
ret = dvb_dmx_init(&dvb->demux);
- if(ret < 0) {
+ if (ret < 0) {
printk("tm6000: dvb_dmx_init failed (errno = %d)\n", ret);
goto frontend_err;
}
@@ -331,7 +339,7 @@ int tm6000_dvb_register(struct tm6000_core *dev)
dvb->dmxdev.capabilities = 0;
ret = dvb_dmxdev_init(&dvb->dmxdev, &dvb->adapter);
- if(ret < 0) {
+ if (ret < 0) {
printk("tm6000: dvb_dmxdev_init failed (errno = %d)\n", ret);
goto dvb_dmx_err;
}
@@ -341,7 +349,7 @@ int tm6000_dvb_register(struct tm6000_core *dev)
dvb_dmx_err:
dvb_dmx_release(&dvb->demux);
frontend_err:
- if(dvb->frontend) {
+ if (dvb->frontend) {
dvb_frontend_detach(dvb->frontend);
dvb_unregister_frontend(dvb->frontend);
}
@@ -351,11 +359,11 @@ err:
return ret;
}
-void tm6000_dvb_unregister(struct tm6000_core *dev)
+void unregister_dvb(struct tm6000_core *dev)
{
struct tm6000_dvb *dvb = dev->dvb;
- if(dvb->bulk_urb != NULL) {
+ if (dvb->bulk_urb != NULL) {
struct urb *bulk_urb = dvb->bulk_urb;
kfree(bulk_urb->transfer_buffer);
@@ -365,7 +373,7 @@ void tm6000_dvb_unregister(struct tm6000_core *dev)
}
/* mutex_lock(&tm6000_driver.open_close_mutex); */
- if(dvb->frontend) {
+ if (dvb->frontend) {
dvb_frontend_detach(dvb->frontend);
dvb_unregister_frontend(dvb->frontend);
}
@@ -375,5 +383,70 @@ void tm6000_dvb_unregister(struct tm6000_core *dev)
dvb_unregister_adapter(&dvb->adapter);
mutex_destroy(&dvb->mutex);
/* mutex_unlock(&tm6000_driver.open_close_mutex); */
+}
+static int dvb_init(struct tm6000_core *dev)
+{
+ struct tm6000_dvb *dvb;
+ int rc;
+
+ if (!dev)
+ return 0;
+
+ if (!dev->caps.has_dvb)
+ return 0;
+
+ dvb = kzalloc(sizeof(struct tm6000_dvb), GFP_KERNEL);
+ if (!dvb) {
+ printk(KERN_INFO "Cannot allocate memory\n");
+ return -ENOMEM;
+ }
+
+ dev->dvb = dvb;
+
+ rc = register_dvb(dev);
+ if (rc < 0) {
+ kfree(dvb);
+ dev->dvb = NULL;
+ return 0;
+ }
+
+ return 0;
+}
+
+static int dvb_fini(struct tm6000_core *dev)
+{
+ if (!dev)
+ return 0;
+
+ if (!dev->caps.has_dvb)
+ return 0;
+
+ if (dev->dvb) {
+ unregister_dvb(dev);
+ kfree(dev->dvb);
+ dev->dvb = NULL;
+ }
+
+ return 0;
}
+
+static struct tm6000_ops dvb_ops = {
+ .type = TM6000_DVB,
+ .name = "TM6000 dvb Extension",
+ .init = dvb_init,
+ .fini = dvb_fini,
+};
+
+static int __init tm6000_dvb_register(void)
+{
+ return tm6000_register_extension(&dvb_ops);
+}
+
+static void __exit tm6000_dvb_unregister(void)
+{
+ tm6000_unregister_extension(&dvb_ops);
+}
+
+module_init(tm6000_dvb_register);
+module_exit(tm6000_dvb_unregister);
diff --git a/drivers/staging/tm6000/tm6000-i2c.c b/drivers/staging/tm6000/tm6000-i2c.c
index 94ff489a1bb..79bc67f0311 100644
--- a/drivers/staging/tm6000/tm6000-i2c.c
+++ b/drivers/staging/tm6000/tm6000-i2c.c
@@ -40,7 +40,7 @@ static unsigned int i2c_debug = 0;
module_param(i2c_debug, int, 0644);
MODULE_PARM_DESC(i2c_debug, "enable debug messages [i2c]");
-#define i2c_dprintk(lvl,fmt, args...) if (i2c_debug>=lvl) do{ \
+#define i2c_dprintk(lvl, fmt, args...) if (i2c_debug >= lvl) do { \
printk(KERN_DEBUG "%s at %s: " fmt, \
dev->name, __FUNCTION__ , ##args); } while (0)
@@ -171,7 +171,7 @@ static int tm6000_i2c_xfer(struct i2c_adapter *i2c_adap,
return 0;
for (i = 0; i < num; i++) {
addr = (msgs[i].addr << 1) & 0xff;
- i2c_dprintk(2,"%s %s addr=0x%x len=%d:",
+ i2c_dprintk(2, "%s %s addr=0x%x len=%d:",
(msgs[i].flags & I2C_M_RD) ? "read" : "write",
i == num - 1 ? "stop" : "nonstop", addr, msgs[i].len);
if (msgs[i].flags & I2C_M_RD) {
@@ -235,7 +235,7 @@ static int tm6000_i2c_xfer(struct i2c_adapter *i2c_adap,
return num;
err:
- i2c_dprintk(2," ERROR: %i\n", rc);
+ i2c_dprintk(2, " ERROR: %i\n", rc);
return rc;
}
@@ -266,11 +266,10 @@ static int tm6000_i2c_eeprom(struct tm6000_core *dev,
if (0 == (i % 16))
printk(KERN_INFO "%s: i2c eeprom %02x:", dev->name, i);
printk(" %02x", eedata[i]);
- if ((eedata[i] >= ' ') && (eedata[i] <= 'z')) {
+ if ((eedata[i] >= ' ') && (eedata[i] <= 'z'))
bytes[i%16] = eedata[i];
- } else {
- bytes[i%16]='.';
- }
+ else
+ bytes[i%16] = '.';
i++;
@@ -305,15 +304,15 @@ static u32 functionality(struct i2c_adapter *adap)
}
#define mass_write(addr, reg, data...) \
- { const static u8 _val[] = data; \
- rc=tm6000_read_write_usb(dev,USB_DIR_OUT | USB_TYPE_VENDOR, \
- REQ_16_SET_GET_I2C_WR1_RDN,(reg<<8)+addr, 0x00, (u8 *) _val, \
+ { static const u8 _val[] = data; \
+ rc = tm6000_read_write_usb(dev, USB_DIR_OUT | USB_TYPE_VENDOR, \
+ REQ_16_SET_GET_I2C_WR1_RDN, (reg<<8)+addr, 0x00, (u8 *) _val, \
ARRAY_SIZE(_val)); \
- if (rc<0) { \
- printk(KERN_ERR "Error on line %d: %d\n",__LINE__,rc); \
+ if (rc < 0) { \
+ printk(KERN_ERR "Error on line %d: %d\n", __LINE__, rc); \
return rc; \
} \
- msleep (10); \
+ msleep(10); \
}
static struct i2c_algorithm tm6000_algo = {
diff --git a/drivers/staging/tm6000/tm6000-input.c b/drivers/staging/tm6000/tm6000-input.c
new file mode 100644
index 00000000000..32f7a0af693
--- /dev/null
+++ b/drivers/staging/tm6000/tm6000-input.c
@@ -0,0 +1,364 @@
+/*
+ tm6000-input.c - driver for TM5600/TM6000/TM6010 USB video capture devices
+
+ Copyright (C) 2010 Stefan Ringel <stefan.ringel@arcor.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 version 2
+
+ 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/delay.h>
+
+#include <linux/input.h>
+#include <linux/usb.h>
+
+#include <media/ir-core.h>
+#include <media/ir-common.h>
+
+#include "tm6000.h"
+#include "tm6000-regs.h"
+
+static unsigned int ir_debug;
+module_param(ir_debug, int, 0644);
+MODULE_PARM_DESC(ir_debug, "enable debug message [IR]");
+
+static unsigned int enable_ir = 1;
+module_param(enable_ir, int, 0644);
+MODULE_PARM_DESC(enable_ir, "enable ir (default is enable");
+
+#undef dprintk
+
+#define dprintk(fmt, arg...) \
+ if (ir_debug) { \
+ printk(KERN_DEBUG "%s/ir: " fmt, ir->name , ## arg); \
+ }
+
+struct tm6000_ir_poll_result {
+ u8 rc_data[4];
+};
+
+struct tm6000_IR {
+ struct tm6000_core *dev;
+ struct ir_input_dev *input;
+ struct ir_input_state ir;
+ char name[32];
+ char phys[32];
+
+ /* poll expernal decoder */
+ int polling;
+ struct delayed_work work;
+ u8 wait:1;
+ struct urb *int_urb;
+ u8 *urb_data;
+ u8 key:1;
+
+ int (*get_key) (struct tm6000_IR *, struct tm6000_ir_poll_result *);
+
+ /* IR device properties */
+ struct ir_dev_props props;
+};
+
+
+void tm6000_ir_wait(struct tm6000_core *dev, u8 state)
+{
+ struct tm6000_IR *ir = dev->ir;
+
+ if (!dev->ir)
+ return;
+
+ if (state)
+ ir->wait = 1;
+ else
+ ir->wait = 0;
+}
+
+
+static int tm6000_ir_config(struct tm6000_IR *ir)
+{
+ struct tm6000_core *dev = ir->dev;
+ u8 buf[10];
+ int rc;
+
+ /* hack */
+ buf[0] = 0xff;
+ buf[1] = 0xff;
+ buf[2] = 0xf2;
+ buf[3] = 0x2b;
+ buf[4] = 0x20;
+ buf[5] = 0x35;
+ buf[6] = 0x60;
+ buf[7] = 0x04;
+ buf[8] = 0xc0;
+ buf[9] = 0x08;
+
+ rc = tm6000_read_write_usb(dev, USB_DIR_OUT | USB_TYPE_VENDOR |
+ USB_RECIP_DEVICE, REQ_00_SET_IR_VALUE, 0, 0, buf, 0x0a);
+ msleep(100);
+
+ if (rc < 0) {
+ printk(KERN_INFO "IR configuration failed");
+ return rc;
+ }
+ return 0;
+}
+
+static void tm6000_ir_urb_received(struct urb *urb)
+{
+ struct tm6000_core *dev = urb->context;
+ struct tm6000_IR *ir = dev->ir;
+ int rc;
+
+ if (urb->status != 0)
+ printk(KERN_INFO "not ready\n");
+ else if (urb->actual_length > 0)
+ memcpy(ir->urb_data, urb->transfer_buffer, urb->actual_length);
+
+ dprintk("data %02x %02x %02x %02x\n", ir->urb_data[0],
+ ir->urb_data[1], ir->urb_data[2], ir->urb_data[3]);
+
+ ir->key = 1;
+
+ rc = usb_submit_urb(urb, GFP_ATOMIC);
+}
+
+static int default_polling_getkey(struct tm6000_IR *ir,
+ struct tm6000_ir_poll_result *poll_result)
+{
+ struct tm6000_core *dev = ir->dev;
+ int rc;
+ u8 buf[2];
+
+ if (ir->wait && !&dev->int_in) {
+ poll_result->rc_data[0] = 0xff;
+ return 0;
+ }
+
+ if (&dev->int_in) {
+ poll_result->rc_data[0] = ir->urb_data[0];
+ poll_result->rc_data[1] = ir->urb_data[1];
+ } else {
+ tm6000_set_reg(dev, REQ_04_EN_DISABLE_MCU_INT, 2, 0);
+ msleep(10);
+ tm6000_set_reg(dev, REQ_04_EN_DISABLE_MCU_INT, 2, 1);
+ msleep(10);
+
+ rc = tm6000_read_write_usb(dev, USB_DIR_IN | USB_TYPE_VENDOR |
+ USB_RECIP_DEVICE, REQ_02_GET_IR_CODE, 0, 0, buf, 1);
+
+ msleep(10);
+
+ dprintk("read data=%02x\n", buf[0]);
+ if (rc < 0)
+ return rc;
+
+ poll_result->rc_data[0] = buf[0];
+ }
+ return 0;
+}
+
+static void tm6000_ir_handle_key(struct tm6000_IR *ir)
+{
+ int result;
+ struct tm6000_ir_poll_result poll_result;
+
+ /* read the registers containing the IR status */
+ result = ir->get_key(ir, &poll_result);
+ if (result < 0) {
+ printk(KERN_INFO "ir->get_key() failed %d\n", result);
+ return;
+ }
+
+ dprintk("ir->get_key result data=%02x %02x\n",
+ poll_result.rc_data[0], poll_result.rc_data[1]);
+
+ if (poll_result.rc_data[0] != 0xff && ir->key == 1) {
+ ir_input_keydown(ir->input->input_dev, &ir->ir,
+ poll_result.rc_data[0] | poll_result.rc_data[1] << 8);
+
+ ir_input_nokey(ir->input->input_dev, &ir->ir);
+ ir->key = 0;
+ }
+ return;
+}
+
+static void tm6000_ir_work(struct work_struct *work)
+{
+ struct tm6000_IR *ir = container_of(work, struct tm6000_IR, work.work);
+
+ tm6000_ir_handle_key(ir);
+ schedule_delayed_work(&ir->work, msecs_to_jiffies(ir->polling));
+}
+
+static int tm6000_ir_start(void *priv)
+{
+ struct tm6000_IR *ir = priv;
+
+ INIT_DELAYED_WORK(&ir->work, tm6000_ir_work);
+ schedule_delayed_work(&ir->work, 0);
+
+ return 0;
+}
+
+static void tm6000_ir_stop(void *priv)
+{
+ struct tm6000_IR *ir = priv;
+
+ cancel_delayed_work_sync(&ir->work);
+}
+
+int tm6000_ir_change_protocol(void *priv, u64 ir_type)
+{
+ struct tm6000_IR *ir = priv;
+
+ ir->get_key = default_polling_getkey;
+
+ tm6000_ir_config(ir);
+ /* TODO */
+ return 0;
+}
+
+int tm6000_ir_init(struct tm6000_core *dev)
+{
+ struct tm6000_IR *ir;
+ struct ir_input_dev *ir_input_dev;
+ int err = -ENOMEM;
+ int pipe, size, rc;
+
+ if (!enable_ir)
+ return -ENODEV;
+
+ if (!dev->caps.has_remote)
+ return 0;
+
+ if (!dev->ir_codes)
+ return 0;
+
+ ir = kzalloc(sizeof(*ir), GFP_KERNEL);
+ ir_input_dev = kzalloc(sizeof(*ir_input_dev), GFP_KERNEL);
+ ir_input_dev->input_dev = input_allocate_device();
+ if (!ir || !ir_input_dev || !ir_input_dev->input_dev)
+ goto err_out_free;
+
+ /* record handles to ourself */
+ ir->dev = dev;
+ dev->ir = ir;
+
+ ir->input = ir_input_dev;
+
+ /* input einrichten */
+ ir->props.allowed_protos = IR_TYPE_RC5 | IR_TYPE_NEC;
+ ir->props.priv = ir;
+ ir->props.change_protocol = tm6000_ir_change_protocol;
+ ir->props.open = tm6000_ir_start;
+ ir->props.close = tm6000_ir_stop;
+ ir->props.driver_type = RC_DRIVER_SCANCODE;
+
+ ir->polling = 50;
+
+ snprintf(ir->name, sizeof(ir->name), "tm5600/60x0 IR (%s)",
+ dev->name);
+
+ usb_make_path(dev->udev, ir->phys, sizeof(ir->phys));
+ strlcat(ir->phys, "/input0", sizeof(ir->phys));
+
+ tm6000_ir_change_protocol(ir, IR_TYPE_UNKNOWN);
+ err = ir_input_init(ir_input_dev->input_dev, &ir->ir, IR_TYPE_OTHER);
+ if (err < 0)
+ goto err_out_free;
+
+ ir_input_dev->input_dev->name = ir->name;
+ ir_input_dev->input_dev->phys = ir->phys;
+ ir_input_dev->input_dev->id.bustype = BUS_USB;
+ ir_input_dev->input_dev->id.version = 1;
+ ir_input_dev->input_dev->id.vendor = le16_to_cpu(dev->udev->descriptor.idVendor);
+ ir_input_dev->input_dev->id.product = le16_to_cpu(dev->udev->descriptor.idProduct);
+
+ ir_input_dev->input_dev->dev.parent = &dev->udev->dev;
+
+ if (&dev->int_in) {
+ dprintk("IR over int\n");
+
+ ir->int_urb = usb_alloc_urb(0, GFP_KERNEL);
+
+ pipe = usb_rcvintpipe(dev->udev,
+ dev->int_in.endp->desc.bEndpointAddress
+ & USB_ENDPOINT_NUMBER_MASK);
+
+ size = usb_maxpacket(dev->udev, pipe, usb_pipeout(pipe));
+ dprintk("IR max size: %d\n", size);
+
+ ir->int_urb->transfer_buffer = kzalloc(size, GFP_KERNEL);
+ if (ir->int_urb->transfer_buffer == NULL) {
+ usb_free_urb(ir->int_urb);
+ goto err_out_stop;
+ }
+ dprintk("int interval: %d\n", dev->int_in.endp->desc.bInterval);
+ usb_fill_int_urb(ir->int_urb, dev->udev, pipe,
+ ir->int_urb->transfer_buffer, size,
+ tm6000_ir_urb_received, dev,
+ dev->int_in.endp->desc.bInterval);
+ rc = usb_submit_urb(ir->int_urb, GFP_KERNEL);
+ if (rc) {
+ kfree(ir->int_urb->transfer_buffer);
+ usb_free_urb(ir->int_urb);
+ err = rc;
+ goto err_out_stop;
+ }
+ ir->urb_data = kzalloc(size, GFP_KERNEL);
+ }
+
+ /* ir register */
+ err = ir_input_register(ir->input->input_dev, dev->ir_codes,
+ &ir->props, "tm6000");
+ if (err)
+ goto err_out_stop;
+
+ return 0;
+
+err_out_stop:
+ dev->ir = NULL;
+err_out_free:
+ kfree(ir_input_dev);
+ kfree(ir);
+ return err;
+}
+
+int tm6000_ir_fini(struct tm6000_core *dev)
+{
+ struct tm6000_IR *ir = dev->ir;
+
+ /* skip detach on non attached board */
+
+ if (!ir)
+ return 0;
+
+ ir_input_unregister(ir->input->input_dev);
+
+ if (ir->int_urb) {
+ usb_kill_urb(ir->int_urb);
+ kfree(ir->int_urb->transfer_buffer);
+ usb_free_urb(ir->int_urb);
+ ir->int_urb = NULL;
+ kfree(ir->urb_data);
+ ir->urb_data = NULL;
+ }
+
+ kfree(ir->input);
+ ir->input = NULL;
+ kfree(ir);
+ dev->ir = NULL;
+
+ return 0;
+}
diff --git a/drivers/staging/tm6000/tm6000-stds.c b/drivers/staging/tm6000/tm6000-stds.c
index b3564f611e5..6bf4a73b320 100644
--- a/drivers/staging/tm6000/tm6000-stds.c
+++ b/drivers/staging/tm6000/tm6000-stds.c
@@ -77,7 +77,7 @@ static struct tm6000_std_tv_settings tv_stds[] = {
{TM6010_REQ07_R01_VIDEO_CONTROL1, 0x0e},
{TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f},
{TM6010_REQ07_R03_YC_SEP_CONTROL, 0x00},
- {TM6010_REQ07_R07_OUTPUT_CONTROL, 0x01},
+ {TM6010_REQ07_R07_OUTPUT_CONTROL, 0x31},
{TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x1e},
{TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0x83},
{TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0x0a},
@@ -135,7 +135,7 @@ static struct tm6000_std_tv_settings tv_stds[] = {
{TM6010_REQ07_R01_VIDEO_CONTROL1, 0x0e},
{TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f},
{TM6010_REQ07_R03_YC_SEP_CONTROL, 0x02},
- {TM6010_REQ07_R07_OUTPUT_CONTROL, 0x01},
+ {TM6010_REQ07_R07_OUTPUT_CONTROL, 0x31},
{TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x1e},
{TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0x91},
{TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0x1f},
@@ -193,7 +193,7 @@ static struct tm6000_std_tv_settings tv_stds[] = {
{TM6010_REQ07_R01_VIDEO_CONTROL1, 0x0e},
{TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f},
{TM6010_REQ07_R03_YC_SEP_CONTROL, 0x02},
- {TM6010_REQ07_R07_OUTPUT_CONTROL, 0x01},
+ {TM6010_REQ07_R07_OUTPUT_CONTROL, 0x31},
{TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x25},
{TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0xd5},
{TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0x63},
@@ -251,7 +251,7 @@ static struct tm6000_std_tv_settings tv_stds[] = {
{TM6010_REQ07_R01_VIDEO_CONTROL1, 0x0e},
{TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f},
{TM6010_REQ07_R03_YC_SEP_CONTROL, 0x02},
- {TM6010_REQ07_R07_OUTPUT_CONTROL, 0x01},
+ {TM6010_REQ07_R07_OUTPUT_CONTROL, 0x31},
{TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x24},
{TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0x92},
{TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0xe8},
@@ -308,7 +308,7 @@ static struct tm6000_std_tv_settings tv_stds[] = {
{TM6010_REQ07_R01_VIDEO_CONTROL1, 0x0f},
{TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f},
{TM6010_REQ07_R03_YC_SEP_CONTROL, 0x00},
- {TM6010_REQ07_R07_OUTPUT_CONTROL, 0x01},
+ {TM6010_REQ07_R07_OUTPUT_CONTROL, 0x31},
{TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x1e},
{TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0x8b},
{TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0xa2},
@@ -354,7 +354,7 @@ static struct tm6000_std_settings composite_stds[] = {
{TM6010_REQ07_R01_VIDEO_CONTROL1, 0x0e},
{TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f},
{TM6010_REQ07_R03_YC_SEP_CONTROL, 0x00},
- {TM6010_REQ07_R07_OUTPUT_CONTROL, 0x01},
+ {TM6010_REQ07_R07_OUTPUT_CONTROL, 0x31},
{TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x1e},
{TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0x83},
{TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0x0a},
@@ -396,7 +396,7 @@ static struct tm6000_std_settings composite_stds[] = {
{TM6010_REQ07_R01_VIDEO_CONTROL1, 0x0e},
{TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f},
{TM6010_REQ07_R03_YC_SEP_CONTROL, 0x02},
- {TM6010_REQ07_R07_OUTPUT_CONTROL, 0x01},
+ {TM6010_REQ07_R07_OUTPUT_CONTROL, 0x31},
{TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x1e},
{TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0x91},
{TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0x1f},
@@ -438,7 +438,7 @@ static struct tm6000_std_settings composite_stds[] = {
{TM6010_REQ07_R01_VIDEO_CONTROL1, 0x0e},
{TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f},
{TM6010_REQ07_R03_YC_SEP_CONTROL, 0x02},
- {TM6010_REQ07_R07_OUTPUT_CONTROL, 0x01},
+ {TM6010_REQ07_R07_OUTPUT_CONTROL, 0x31},
{TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x25},
{TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0xd5},
{TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0x63},
@@ -480,7 +480,7 @@ static struct tm6000_std_settings composite_stds[] = {
{TM6010_REQ07_R01_VIDEO_CONTROL1, 0x0e},
{TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f},
{TM6010_REQ07_R03_YC_SEP_CONTROL, 0x02},
- {TM6010_REQ07_R07_OUTPUT_CONTROL, 0x01},
+ {TM6010_REQ07_R07_OUTPUT_CONTROL, 0x31},
{TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x24},
{TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0x92},
{TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0xe8},
@@ -521,7 +521,7 @@ static struct tm6000_std_settings composite_stds[] = {
{TM6010_REQ07_R01_VIDEO_CONTROL1, 0x0f},
{TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f},
{TM6010_REQ07_R03_YC_SEP_CONTROL, 0x00},
- {TM6010_REQ07_R07_OUTPUT_CONTROL, 0x01},
+ {TM6010_REQ07_R07_OUTPUT_CONTROL, 0x31},
{TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x1e},
{TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0x8b},
{TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0xa2},
@@ -567,7 +567,7 @@ static struct tm6000_std_settings svideo_stds[] = {
{TM6010_REQ07_R01_VIDEO_CONTROL1, 0x0e},
{TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f},
{TM6010_REQ07_R03_YC_SEP_CONTROL, 0x04},
- {TM6010_REQ07_R07_OUTPUT_CONTROL, 0x01},
+ {TM6010_REQ07_R07_OUTPUT_CONTROL, 0x31},
{TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x1e},
{TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0x83},
{TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0x0a},
@@ -609,7 +609,7 @@ static struct tm6000_std_settings svideo_stds[] = {
{TM6010_REQ07_R01_VIDEO_CONTROL1, 0x0e},
{TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f},
{TM6010_REQ07_R03_YC_SEP_CONTROL, 0x04},
- {TM6010_REQ07_R07_OUTPUT_CONTROL, 0x01},
+ {TM6010_REQ07_R07_OUTPUT_CONTROL, 0x31},
{TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x1e},
{TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0x91},
{TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0x1f},
@@ -651,7 +651,7 @@ static struct tm6000_std_settings svideo_stds[] = {
{TM6010_REQ07_R01_VIDEO_CONTROL1, 0x0e},
{TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f},
{TM6010_REQ07_R03_YC_SEP_CONTROL, 0x04},
- {TM6010_REQ07_R07_OUTPUT_CONTROL, 0x00},
+ {TM6010_REQ07_R07_OUTPUT_CONTROL, 0x30},
{TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x25},
{TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0xd5},
{TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0x63},
@@ -693,7 +693,7 @@ static struct tm6000_std_settings svideo_stds[] = {
{TM6010_REQ07_R01_VIDEO_CONTROL1, 0x0e},
{TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f},
{TM6010_REQ07_R03_YC_SEP_CONTROL, 0x03},
- {TM6010_REQ07_R07_OUTPUT_CONTROL, 0x01},
+ {TM6010_REQ07_R07_OUTPUT_CONTROL, 0x31},
{TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x24},
{TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0x92},
{TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0xe8},
@@ -734,7 +734,7 @@ static struct tm6000_std_settings svideo_stds[] = {
{TM6010_REQ07_R01_VIDEO_CONTROL1, 0x0f},
{TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f},
{TM6010_REQ07_R03_YC_SEP_CONTROL, 0x03},
- {TM6010_REQ07_R07_OUTPUT_CONTROL, 0x00},
+ {TM6010_REQ07_R07_OUTPUT_CONTROL, 0x30},
{TM6010_REQ07_R17_HLOOP_MAXSTATE, 0x8b},
{TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x1e},
{TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0x8b},
@@ -763,11 +763,11 @@ static struct tm6000_std_settings svideo_stds[] = {
void tm6000_get_std_res(struct tm6000_core *dev)
{
/* Currently, those are the only supported resoltions */
- if (dev->norm & V4L2_STD_525_60) {
+ if (dev->norm & V4L2_STD_525_60)
dev->height = 480;
- } else {
+ else
dev->height = 576;
- }
+
dev->width = 720;
}
diff --git a/drivers/staging/tm6000/tm6000-usb-isoc.h b/drivers/staging/tm6000/tm6000-usb-isoc.h
index 5a5049acd4e..138716a8f05 100644
--- a/drivers/staging/tm6000/tm6000-usb-isoc.h
+++ b/drivers/staging/tm6000/tm6000-usb-isoc.h
@@ -39,7 +39,7 @@ struct usb_isoc_ctl {
int pos, size, pktsize;
/* Last field: ODD or EVEN? */
- int field;
+ int vfield;
/* Stores incomplete commands */
u32 tmp_buf;
@@ -47,7 +47,4 @@ struct usb_isoc_ctl {
/* Stores already requested buffers */
struct tm6000_buffer *buf;
-
- /* Stores the number of received fields */
- int nfields;
};
diff --git a/drivers/staging/tm6000/tm6000-video.c b/drivers/staging/tm6000/tm6000-video.c
index 56fa371e08c..ce0a089a077 100644
--- a/drivers/staging/tm6000/tm6000-video.c
+++ b/drivers/staging/tm6000/tm6000-video.c
@@ -56,6 +56,7 @@ static int video_nr = -1; /* /dev/videoN, -1 for autodetect */
/* Debug level */
int tm6000_debug;
+EXPORT_SYMBOL_GPL(tm6000_debug);
/* supported controls */
static struct v4l2_queryctrl tm6000_qctrl[] = {
@@ -149,8 +150,6 @@ static inline void get_next_buf(struct tm6000_dmaqueue *dma_q,
/* Cleans up buffer - Usefull for testing for frame/URB loss */
outp = videobuf_to_vmalloc(&(*buf)->vb);
-// if (outp)
-// memset(outp, 0, (*buf)->vb.size);
return;
}
@@ -186,236 +185,152 @@ const char *tm6000_msg_type[] = {
/*
* Identify the tm5600/6000 buffer header type and properly handles
*/
-static int copy_packet(struct urb *urb, u32 header, u8 **ptr, u8 *endp,
- u8 *out_p, struct tm6000_buffer **buf)
-{
- struct tm6000_dmaqueue *dma_q = urb->context;
- struct tm6000_core *dev = container_of(dma_q, struct tm6000_core, vidq);
- u8 c;
- unsigned int cmd, cpysize, pktsize, size, field, block, line, pos = 0;
- int rc = 0;
- /* FIXME: move to tm6000-isoc */
- static int last_line = -2, start_line = -2, last_field = -2;
-
- /* FIXME: this is the hardcoded window size
- */
- unsigned int linewidth = (*buf)->vb.width << 1;
-
- if (!dev->isoc_ctl.cmd) {
- c = (header >> 24) & 0xff;
-
- /* split the header fields */
- size = ((header & 0x7e) << 1);
-
- if (size > 0)
- size -= 4;
-
- block = (header >> 7) & 0xf;
- field = (header >> 11) & 0x1;
- line = (header >> 12) & 0x1ff;
- cmd = (header >> 21) & 0x7;
-
- /* Validates header fields */
- if(size > TM6000_URB_MSG_LEN)
- size = TM6000_URB_MSG_LEN;
-
- if (cmd == TM6000_URB_MSG_VIDEO) {
- if ((block+1)*TM6000_URB_MSG_LEN>linewidth)
- cmd = TM6000_URB_MSG_ERR;
-
- /* FIXME: Mounts the image as field0+field1
- * It should, instead, check if the user selected
- * entrelaced or non-entrelaced mode
- */
- pos = ((line << 1) - field - 1) * linewidth +
- block * TM6000_URB_MSG_LEN;
-
- /* Don't allow to write out of the buffer */
- if (pos+TM6000_URB_MSG_LEN > (*buf)->vb.size) {
- dprintk(dev, V4L2_DEBUG_ISOC,
- "ERR: size=%d, num=%d, line=%d, "
- "field=%d\n",
- size, block, line, field);
-
- cmd = TM6000_URB_MSG_ERR;
- }
- } else {
- pos=0;
- }
-
- /* Prints debug info */
- dprintk(dev, V4L2_DEBUG_ISOC, "size=%d, num=%d, "
- " line=%d, field=%d\n",
- size, block, line, field);
-
- if ((last_line!=line)&&(last_line+1!=line) &&
- (cmd != TM6000_URB_MSG_ERR) ) {
- if (cmd != TM6000_URB_MSG_VIDEO) {
- dprintk(dev, V4L2_DEBUG_ISOC, "cmd=%d, "
- "size=%d, num=%d, line=%d, field=%d\n",
- cmd, size, block, line, field);
- }
- if (start_line<0)
- start_line=last_line;
- /* Prints debug info */
- dprintk(dev, V4L2_DEBUG_ISOC, "lines= %d-%d, "
- "field=%d\n",
- start_line, last_line, field);
-
- if ((start_line<6 && last_line>200) &&
- (last_field != field) ) {
-
- dev->isoc_ctl.nfields++;
- if (dev->isoc_ctl.nfields>=2) {
- dev->isoc_ctl.nfields=0;
-
- /* Announces that a new buffer were filled */
- buffer_filled (dev, dma_q, *buf);
- dprintk(dev, V4L2_DEBUG_ISOC,
- "new buffer filled\n");
- get_next_buf (dma_q, buf);
- if (!*buf)
- return rc;
- out_p = videobuf_to_vmalloc(&((*buf)->vb));
- if (!out_p)
- return rc;
-
- pos = dev->isoc_ctl.pos = 0;
- }
- }
-
- start_line=line;
- last_field=field;
- }
- if (cmd == TM6000_URB_MSG_VIDEO)
- last_line = line;
-
- pktsize = TM6000_URB_MSG_LEN;
- } else {
- /* Continue the last copy */
- cmd = dev->isoc_ctl.cmd;
- size= dev->isoc_ctl.size;
- pos = dev->isoc_ctl.pos;
- pktsize = dev->isoc_ctl.pktsize;
- }
-
- cpysize = (endp-(*ptr) > size) ? size : endp - *ptr;
-
- if (cpysize) {
- /* handles each different URB message */
- switch(cmd) {
- case TM6000_URB_MSG_VIDEO:
- /* Fills video buffer */
- memcpy(&out_p[pos], *ptr, cpysize);
- break;
- case TM6000_URB_MSG_PTS:
- break;
- case TM6000_URB_MSG_AUDIO:
- /* Need some code to process audio */
- printk ("%ld: cmd=%s, size=%d\n", jiffies,
- tm6000_msg_type[cmd],size);
- break;
- case TM6000_URB_MSG_VBI:
- break;
- default:
- dprintk (dev, V4L2_DEBUG_ISOC, "cmd=%s, size=%d\n",
- tm6000_msg_type[cmd],size);
- }
- }
- if (cpysize<size) {
- /* End of URB packet, but cmd processing is not
- * complete. Preserve the state for a next packet
- */
- dev->isoc_ctl.pos = pos+cpysize;
- dev->isoc_ctl.size= size-cpysize;
- dev->isoc_ctl.cmd = cmd;
- dev->isoc_ctl.pktsize = pktsize-cpysize;
- (*ptr)+=cpysize;
- } else {
- dev->isoc_ctl.cmd = 0;
- (*ptr)+=pktsize;
- }
-
- return rc;
-}
-
static int copy_streams(u8 *data, unsigned long len,
struct urb *urb)
{
struct tm6000_dmaqueue *dma_q = urb->context;
struct tm6000_core *dev= container_of(dma_q,struct tm6000_core,vidq);
- u8 *ptr=data, *endp=data+len;
+ u8 *ptr=data, *endp=data+len, c;
unsigned long header=0;
int rc=0;
- struct tm6000_buffer *buf;
- char *outp = NULL;
-
- get_next_buf(dma_q, &buf);
- if (buf)
- outp = videobuf_to_vmalloc(&buf->vb);
+ unsigned int cmd, cpysize, pktsize, size, field, block, line, pos = 0;
+ struct tm6000_buffer *vbuf;
+ char *voutp = NULL;
+ unsigned int linewidth;
- if (!outp)
+ /* get video buffer */
+ get_next_buf (dma_q, &vbuf);
+ if (!vbuf)
+ return rc;
+ voutp = videobuf_to_vmalloc(&vbuf->vb);
+ if (!voutp)
return 0;
- for (ptr=data; ptr<endp;) {
+ for (ptr = data; ptr < endp;) {
if (!dev->isoc_ctl.cmd) {
- u8 *p=(u8 *)&dev->isoc_ctl.tmp_buf;
- /* FIXME: This seems very complex
- * It just recovers up to 3 bytes of the header that
- * might be at the previous packet
- */
- if (dev->isoc_ctl.tmp_buf_len) {
- while (dev->isoc_ctl.tmp_buf_len) {
- if ( *(ptr+3-dev->isoc_ctl.tmp_buf_len) == 0x47) {
- break;
- }
- p++;
- dev->isoc_ctl.tmp_buf_len--;
- }
- if (dev->isoc_ctl.tmp_buf_len) {
- memcpy(&header, p,
- dev->isoc_ctl.tmp_buf_len);
- memcpy((u8 *)&header +
+ /* Header */
+ if (dev->isoc_ctl.tmp_buf_len > 0) {
+ /* from last urb or packet */
+ header = dev->isoc_ctl.tmp_buf;
+ if (4 - dev->isoc_ctl.tmp_buf_len > 0) {
+ memcpy ((u8 *)&header +
dev->isoc_ctl.tmp_buf_len,
ptr,
4 - dev->isoc_ctl.tmp_buf_len);
ptr += 4 - dev->isoc_ctl.tmp_buf_len;
- goto HEADER;
}
- }
- /* Seek for sync */
- for (;ptr<endp-3;ptr++) {
- if (*(ptr+3)==0x47)
- break;
+ dev->isoc_ctl.tmp_buf_len = 0;
+ } else {
+ if (ptr + 3 >= endp) {
+ /* have incomplete header */
+ dev->isoc_ctl.tmp_buf_len = endp - ptr;
+ memcpy (&dev->isoc_ctl.tmp_buf, ptr,
+ dev->isoc_ctl.tmp_buf_len);
+ return rc;
+ }
+ /* Seek for sync */
+ for (; ptr < endp - 3; ptr++) {
+ if (*(ptr + 3) == 0x47)
+ break;
+ }
+ /* Get message header */
+ header = *(unsigned long *)ptr;
+ ptr += 4;
}
- if (ptr+3>=endp) {
- dev->isoc_ctl.tmp_buf_len=endp-ptr;
- memcpy (&dev->isoc_ctl.tmp_buf,ptr,
- dev->isoc_ctl.tmp_buf_len);
- dev->isoc_ctl.cmd=0;
- return rc;
+ /* split the header fields */
+ c = (header >> 24) & 0xff;
+ size = ((header & 0x7e) << 1);
+ if (size > 0)
+ size -= 4;
+ block = (header >> 7) & 0xf;
+ field = (header >> 11) & 0x1;
+ line = (header >> 12) & 0x1ff;
+ cmd = (header >> 21) & 0x7;
+ /* Validates haeder fields */
+ if (size > TM6000_URB_MSG_LEN)
+ size = TM6000_URB_MSG_LEN;
+ pktsize = TM6000_URB_MSG_LEN;
+ /* calculate position in buffer
+ * and change the buffer
+ */
+ switch (cmd) {
+ case TM6000_URB_MSG_VIDEO:
+ if ((dev->isoc_ctl.vfield != field) &&
+ (field == 1)) {
+ /* Announces that a new buffer
+ * were filled
+ */
+ buffer_filled (dev, dma_q, vbuf);
+ dprintk (dev, V4L2_DEBUG_ISOC,
+ "new buffer filled\n");
+ get_next_buf (dma_q, &vbuf);
+ if (!vbuf)
+ return rc;
+ voutp = videobuf_to_vmalloc (&vbuf->vb);
+ if (!voutp)
+ return rc;
+ memset(voutp, 0, vbuf->vb.size);
+ }
+ linewidth = vbuf->vb.width << 1;
+ pos = ((line << 1) - field - 1) * linewidth +
+ block * TM6000_URB_MSG_LEN;
+ /* Don't allow to write out of the buffer */
+ if (pos + size > vbuf->vb.size)
+ cmd = TM6000_URB_MSG_ERR;
+ dev->isoc_ctl.vfield = field;
+ break;
+ case TM6000_URB_MSG_VBI:
+ break;
+ case TM6000_URB_MSG_AUDIO:
+ case TM6000_URB_MSG_PTS:
+ size = pktsize; /* Size is always 180 bytes */
+ break;
}
-
- /* Get message header */
- header=*(unsigned long *)ptr;
- ptr+=4;
+ } else {
+ /* Continue the last copy */
+ cmd = dev->isoc_ctl.cmd;
+ size = dev->isoc_ctl.size;
+ pos = dev->isoc_ctl.pos;
+ pktsize = dev->isoc_ctl.pktsize;
}
-HEADER:
- /* Copy or continue last copy */
- rc=copy_packet(urb,header,&ptr,endp,outp,&buf);
- if (rc<0) {
- buf=NULL;
- printk(KERN_ERR "tm6000: buffer underrun at %ld\n",
- jiffies);
- return rc;
+ cpysize = (endp - ptr > size) ? size : endp - ptr;
+ if (cpysize) {
+ /* copy data in different buffers */
+ switch (cmd) {
+ case TM6000_URB_MSG_VIDEO:
+ /* Fills video buffer */
+ if (vbuf)
+ memcpy (&voutp[pos], ptr, cpysize);
+ break;
+ case TM6000_URB_MSG_AUDIO:
+ tm6000_call_fillbuf(dev, TM6000_AUDIO, ptr, cpysize);
+ break;
+ case TM6000_URB_MSG_VBI:
+ /* Need some code to copy vbi buffer */
+ break;
+ case TM6000_URB_MSG_PTS:
+ /* Need some code to copy pts */
+ break;
+ }
+ }
+ if (ptr + pktsize > endp) {
+ /* End of URB packet, but cmd processing is not
+ * complete. Preserve the state for a next packet
+ */
+ dev->isoc_ctl.pos = pos + cpysize;
+ dev->isoc_ctl.size = size - cpysize;
+ dev->isoc_ctl.cmd = cmd;
+ dev->isoc_ctl.pktsize = pktsize - (endp - ptr);
+ ptr += endp - ptr;
+ } else {
+ dev->isoc_ctl.cmd = 0;
+ ptr += pktsize;
}
- if (!buf)
- return 0;
}
-
return 0;
}
+
/*
* Identify the tm5600/6000 buffer header type and properly handles
*/
@@ -510,7 +425,6 @@ static inline int tm6000_isoc_copy(struct urb *urb)
{
struct tm6000_dmaqueue *dma_q = urb->context;
struct tm6000_core *dev= container_of(dma_q,struct tm6000_core,vidq);
- struct tm6000_buffer *buf;
int i, len=0, rc=1, status;
char *p;
@@ -585,7 +499,6 @@ static void tm6000_uninit_isoc(struct tm6000_core *dev)
struct urb *urb;
int i;
- dev->isoc_ctl.nfields = -1;
dev->isoc_ctl.buf = NULL;
for (i = 0; i < dev->isoc_ctl.num_bufs; i++) {
urb=dev->isoc_ctl.urb[i];
@@ -610,8 +523,6 @@ static void tm6000_uninit_isoc(struct tm6000_core *dev)
dev->isoc_ctl.urb=NULL;
dev->isoc_ctl.transfer_buffer=NULL;
dev->isoc_ctl.num_bufs = 0;
-
- dev->isoc_ctl.num_bufs=0;
}
/*
diff --git a/drivers/staging/tm6000/tm6000.h b/drivers/staging/tm6000/tm6000.h
index 7bbaf26dea1..1ec1bff9b29 100644
--- a/drivers/staging/tm6000/tm6000.h
+++ b/drivers/staging/tm6000/tm6000.h
@@ -20,8 +20,8 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-// Use the tm6000-hack, instead of the proper initialization code
-//#define HACK 1
+/* Use the tm6000-hack, instead of the proper initialization code i*/
+/* #define HACK 1 */
#include <linux/videodev2.h>
#include <media/v4l2-common.h>
@@ -98,7 +98,7 @@ enum tm6000_io_method {
};
enum tm6000_mode {
- TM6000_MODE_UNKNOWN=0,
+ TM6000_MODE_UNKNOWN = 0,
TM6000_MODE_ANALOG,
TM6000_MODE_DIGITAL,
};
@@ -128,10 +128,21 @@ struct tm6000_dvb {
struct dvb_frontend *frontend;
struct dmxdev dmxdev;
unsigned int streams;
- struct urb *bulk_urb;
+ struct urb *bulk_urb;
struct mutex mutex;
};
+struct snd_tm6000_card {
+ struct snd_card *card;
+ spinlock_t reg_lock;
+ struct tm6000_core *core;
+ struct snd_pcm_substream *substream;
+
+ /* temporary data for buffer fill processing */
+ unsigned buf_pos;
+ unsigned period_pos;
+};
+
struct tm6000_endpoint {
struct usb_host_endpoint *endp;
__u8 bInterfaceNumber;
@@ -147,7 +158,7 @@ struct tm6000_core {
enum tm6000_devtype dev_type; /* type of device */
v4l2_std_id norm; /* Current norm */
- int width,height; /* Selected resolution */
+ int width, height; /* Selected resolution */
enum tm6000_core_state state;
@@ -160,6 +171,8 @@ struct tm6000_core {
struct tm6000_gpio gpio;
+ char *ir_codes;
+
/* Demodulator configuration */
int demod_addr; /* demodulator address */
@@ -190,6 +203,11 @@ struct tm6000_core {
/* DVB-T support */
struct tm6000_dvb *dvb;
+ /* audio support */
+ struct snd_tm6000_card *adev;
+
+ struct tm6000_IR *ir;
+
/* locks */
struct mutex lock;
@@ -197,6 +215,7 @@ struct tm6000_core {
struct usb_device *udev; /* the usb device */
struct tm6000_endpoint bulk_in, bulk_out, isoc_in, isoc_out;
+ struct tm6000_endpoint int_in, int_out;
/* scaler!=0 if scaler is active*/
int scaler;
@@ -207,14 +226,18 @@ struct tm6000_core {
spinlock_t slock;
};
-#define TM6000_AUDIO 0x10
+enum tm6000_ops_type {
+ TM6000_AUDIO = 0x10,
+ TM6000_DVB = 0x20,
+};
struct tm6000_ops {
struct list_head next;
char *name;
- int id;
+ enum tm6000_ops_type type;
int (*init)(struct tm6000_core *);
int (*fini)(struct tm6000_core *);
+ int (*fillbuf)(struct tm6000_core *, char *buf, int size);
};
struct tm6000_fh {
@@ -222,7 +245,7 @@ struct tm6000_fh {
/* video capture */
struct tm6000_fmt *fmt;
- unsigned int width,height;
+ unsigned int width, height;
struct videobuf_queue vb_vidq;
enum v4l2_buf_type type;
@@ -234,28 +257,24 @@ struct tm6000_fh {
/* In tm6000-cards.c */
-int tm6000_tuner_callback (void *ptr, int component, int command, int arg);
-int tm6000_xc5000_callback (void *ptr, int component, int command, int arg);
+int tm6000_tuner_callback(void *ptr, int component, int command, int arg);
+int tm6000_xc5000_callback(void *ptr, int component, int command, int arg);
int tm6000_cards_setup(struct tm6000_core *dev);
/* In tm6000-core.c */
-int tm6000_read_write_usb (struct tm6000_core *dev, u8 reqtype, u8 req,
+int tm6000_read_write_usb(struct tm6000_core *dev, u8 reqtype, u8 req,
u16 value, u16 index, u8 *buf, u16 len);
-int tm6000_get_reg (struct tm6000_core *dev, u8 req, u16 value, u16 index);
+int tm6000_get_reg(struct tm6000_core *dev, u8 req, u16 value, u16 index);
int tm6000_get_reg16(struct tm6000_core *dev, u8 req, u16 value, u16 index);
int tm6000_get_reg32(struct tm6000_core *dev, u8 req, u16 value, u16 index);
-int tm6000_set_reg (struct tm6000_core *dev, u8 req, u16 value, u16 index);
+int tm6000_set_reg(struct tm6000_core *dev, u8 req, u16 value, u16 index);
int tm6000_i2c_reset(struct tm6000_core *dev, u16 tsleep);
+int tm6000_init(struct tm6000_core *dev);
-int tm6000_init (struct tm6000_core *dev);
-
-int tm6000_init_analog_mode (struct tm6000_core *dev);
-int tm6000_init_digital_mode (struct tm6000_core *dev);
-int tm6000_set_audio_bitrate (struct tm6000_core *dev, int bitrate);
-
-int tm6000_dvb_register(struct tm6000_core *dev);
-void tm6000_dvb_unregister(struct tm6000_core *dev);
+int tm6000_init_analog_mode(struct tm6000_core *dev);
+int tm6000_init_digital_mode(struct tm6000_core *dev);
+int tm6000_set_audio_bitrate(struct tm6000_core *dev, int bitrate);
int tm6000_v4l2_register(struct tm6000_core *dev);
int tm6000_v4l2_unregister(struct tm6000_core *dev);
@@ -268,10 +287,13 @@ int tm6000_register_extension(struct tm6000_ops *ops);
void tm6000_unregister_extension(struct tm6000_ops *ops);
void tm6000_init_extension(struct tm6000_core *dev);
void tm6000_close_extension(struct tm6000_core *dev);
+int tm6000_call_fillbuf(struct tm6000_core *dev, enum tm6000_ops_type type,
+ char *buf, int size);
+
/* In tm6000-stds.c */
void tm6000_get_std_res(struct tm6000_core *dev);
-int tm6000_set_standard (struct tm6000_core *dev, v4l2_std_id *norm);
+int tm6000_set_standard(struct tm6000_core *dev, v4l2_std_id *norm);
/* In tm6000-i2c.c */
int tm6000_i2c_register(struct tm6000_core *dev);
@@ -285,14 +307,14 @@ int tm6000_vidioc_streamon(struct file *file, void *priv,
enum v4l2_buf_type i);
int tm6000_vidioc_streamoff(struct file *file, void *priv,
enum v4l2_buf_type i);
-int tm6000_vidioc_reqbufs (struct file *file, void *priv,
- struct v4l2_requestbuffers *rb);
-int tm6000_vidioc_querybuf (struct file *file, void *priv,
- struct v4l2_buffer *b);
-int tm6000_vidioc_qbuf (struct file *file, void *priv, struct v4l2_buffer *b);
-int tm6000_vidioc_dqbuf (struct file *file, void *priv, struct v4l2_buffer *b);
+int tm6000_vidioc_reqbufs(struct file *file, void *priv,
+ struct v4l2_requestbuffers *rb);
+int tm6000_vidioc_querybuf(struct file *file, void *priv,
+ struct v4l2_buffer *b);
+int tm6000_vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *b);
+int tm6000_vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b);
ssize_t tm6000_v4l2_read(struct file *filp, char __user * buf, size_t count,
- loff_t * f_pos);
+ loff_t *f_pos);
unsigned int tm6000_v4l2_poll(struct file *file,
struct poll_table_struct *wait);
int tm6000_queue_init(struct tm6000_core *dev);
@@ -300,6 +322,10 @@ int tm6000_queue_init(struct tm6000_core *dev);
/* In tm6000-alsa.c */
/*int tm6000_audio_init(struct tm6000_core *dev, int idx);*/
+/* In tm6000-input.c */
+int tm6000_ir_init(struct tm6000_core *dev);
+int tm6000_ir_fini(struct tm6000_core *dev);
+void tm6000_ir_wait(struct tm6000_core *dev, u8 state);
/* Debug stuff */
@@ -307,7 +333,7 @@ extern int tm6000_debug;
#define dprintk(dev, level, fmt, arg...) do {\
if (tm6000_debug & level) \
- printk(KERN_INFO "(%lu) %s %s :"fmt, jiffies, \
+ printk(KERN_INFO "(%lu) %s %s :"fmt, jiffies, \
dev->name, __FUNCTION__ , ##arg); } while (0)
#define V4L2_DEBUG_REG 0x0004
@@ -320,5 +346,3 @@ extern int tm6000_debug;
#define tm6000_err(fmt, arg...) do {\
printk(KERN_ERR "tm6000 %s :"fmt, \
__FUNCTION__ , ##arg); } while (0)
-
-
diff --git a/drivers/staging/usbip/stub.h b/drivers/staging/usbip/stub.h
index 022d0649ac5..30dbfb6d16f 100644
--- a/drivers/staging/usbip/stub.h
+++ b/drivers/staging/usbip/stub.h
@@ -25,6 +25,11 @@
#include <linux/module.h>
#include <linux/net.h>
+#define STUB_BUSID_OTHER 0
+#define STUB_BUSID_REMOV 1
+#define STUB_BUSID_ADDED 2
+#define STUB_BUSID_ALLOC 3
+
struct stub_device {
struct usb_interface *interface;
struct list_head list;
@@ -72,6 +77,14 @@ struct stub_unlink {
__u32 status;
};
+#define BUSID_SIZE 20
+struct bus_id_priv {
+ char name[BUSID_SIZE];
+ char status;
+ int interf_count;
+ struct stub_device *sdev;
+ char shutdown_busid;
+};
extern struct kmem_cache *stub_priv_cache;
@@ -91,5 +104,7 @@ void stub_rx_loop(struct usbip_task *);
void stub_enqueue_ret_unlink(struct stub_device *, __u32, __u32);
/* stub_main.c */
-int match_busid(const char *busid);
+struct bus_id_priv *get_busid_priv(const char *busid);
+int del_match_busid(char *busid);
+
void stub_device_cleanup_urbs(struct stub_device *sdev);
diff --git a/drivers/staging/usbip/stub_dev.c b/drivers/staging/usbip/stub_dev.c
index 3f95605427a..b6b753a4934 100644
--- a/drivers/staging/usbip/stub_dev.c
+++ b/drivers/staging/usbip/stub_dev.c
@@ -393,11 +393,14 @@ static int stub_probe(struct usb_interface *interface,
struct stub_device *sdev = NULL;
const char *udev_busid = dev_name(interface->dev.parent);
int err = 0;
+ struct bus_id_priv *busid_priv;
dev_dbg(&interface->dev, "Enter\n");
/* check we should claim or not by busid_table */
- if (match_busid(udev_busid)) {
+ busid_priv = get_busid_priv(udev_busid);
+ if (!busid_priv || (busid_priv->status == STUB_BUSID_REMOV) ||
+ (busid_priv->status == STUB_BUSID_OTHER)) {
dev_info(&interface->dev,
"this device %s is not in match_busid table. skip!\n",
udev_busid);
@@ -422,28 +425,80 @@ static int stub_probe(struct usb_interface *interface,
return -ENODEV;
}
+
+ if (busid_priv->status == STUB_BUSID_ALLOC) {
+ busid_priv->interf_count++;
+ sdev = busid_priv->sdev;
+ if (!sdev)
+ return -ENODEV;
+
+ dev_info(&interface->dev,
+ "USB/IP Stub: register a new interface "
+ "(bus %u dev %u ifn %u)\n", udev->bus->busnum, udev->devnum,
+ interface->cur_altsetting->desc.bInterfaceNumber);
+
+ /* set private data to usb_interface */
+ usb_set_intfdata(interface, sdev);
+
+ err = stub_add_files(&interface->dev);
+ if (err) {
+ dev_err(&interface->dev, "create sysfs files for %s\n",
+ udev_busid);
+ usb_set_intfdata(interface, NULL);
+ busid_priv->interf_count--;
+
+ return err;
+ }
+
+ return 0;
+ }
+
/* ok. this is my device. */
sdev = stub_device_alloc(interface);
if (!sdev)
return -ENOMEM;
- dev_info(&interface->dev, "USB/IP Stub: register a new interface "
+ dev_info(&interface->dev, "USB/IP Stub: register a new device "
"(bus %u dev %u ifn %u)\n", udev->bus->busnum, udev->devnum,
interface->cur_altsetting->desc.bInterfaceNumber);
+ busid_priv->interf_count = 0;
+ busid_priv->shutdown_busid = 0;
+
/* set private data to usb_interface */
usb_set_intfdata(interface, sdev);
+ busid_priv->interf_count++;
+
+ busid_priv->sdev = sdev;
err = stub_add_files(&interface->dev);
if (err) {
dev_err(&interface->dev, "create sysfs files for %s\n",
udev_busid);
+ usb_set_intfdata(interface, NULL);
+ busid_priv->interf_count = 0;
+
+ busid_priv->sdev = NULL;
+ stub_device_free(sdev);
return err;
}
+ busid_priv->status = STUB_BUSID_ALLOC;
return 0;
}
+static void shutdown_busid(struct bus_id_priv *busid_priv)
+{
+ if (busid_priv->sdev && !busid_priv->shutdown_busid) {
+ busid_priv->shutdown_busid = 1;
+ usbip_event_add(&busid_priv->sdev->ud, SDEV_EVENT_REMOVED);
+
+ /* 2. wait for the stop of the event handler */
+ usbip_stop_eh(&busid_priv->sdev->ud);
+ }
+
+}
+
/*
* called in usb_disconnect() or usb_deregister()
@@ -451,10 +506,21 @@ static int stub_probe(struct usb_interface *interface,
*/
static void stub_disconnect(struct usb_interface *interface)
{
- struct stub_device *sdev = usb_get_intfdata(interface);
+ struct stub_device *sdev;
+ const char *udev_busid = dev_name(interface->dev.parent);
+ struct bus_id_priv *busid_priv;
+
+ busid_priv = get_busid_priv(udev_busid);
usbip_udbg("Enter\n");
+ if (!busid_priv) {
+ BUG();
+ return;
+ }
+
+ sdev = usb_get_intfdata(interface);
+
/* get stub_device */
if (!sdev) {
err(" could not get device from inteface data");
@@ -464,22 +530,39 @@ static void stub_disconnect(struct usb_interface *interface)
usb_set_intfdata(interface, NULL);
-
/*
* NOTE:
* rx/tx threads are invoked for each usb_device.
*/
stub_remove_files(&interface->dev);
- /* 1. shutdown the current connection */
- usbip_event_add(&sdev->ud, SDEV_EVENT_REMOVED);
+ /*If usb reset called from event handler*/
+ if (busid_priv->sdev->ud.eh.thread == current) {
+ busid_priv->interf_count--;
+ return;
+ }
+
+ if (busid_priv->interf_count > 1) {
+ busid_priv->interf_count--;
+ shutdown_busid(busid_priv);
+ return;
+ }
+
+ busid_priv->interf_count = 0;
- /* 2. wait for the stop of the event handler */
- usbip_stop_eh(&sdev->ud);
+
+ /* 1. shutdown the current connection */
+ shutdown_busid(busid_priv);
/* 3. free sdev */
+ busid_priv->sdev = NULL;
stub_device_free(sdev);
-
+ if (busid_priv->status == STUB_BUSID_ALLOC) {
+ busid_priv->status = STUB_BUSID_ADDED;
+ } else {
+ busid_priv->status = STUB_BUSID_OTHER;
+ del_match_busid((char *)udev_busid);
+ }
usbip_udbg("bye\n");
}
diff --git a/drivers/staging/usbip/stub_main.c b/drivers/staging/usbip/stub_main.c
index 6665cefe573..f3a40968aae 100644
--- a/drivers/staging/usbip/stub_main.c
+++ b/drivers/staging/usbip/stub_main.c
@@ -41,8 +41,7 @@ struct kmem_cache *stub_priv_cache;
* remote host.
*/
#define MAX_BUSID 16
-#define BUSID_SIZE 20
-static char busid_table[MAX_BUSID][BUSID_SIZE];
+static struct bus_id_priv busid_table[MAX_BUSID];
static spinlock_t busid_table_lock;
@@ -53,8 +52,8 @@ int match_busid(const char *busid)
spin_lock(&busid_table_lock);
for (i = 0; i < MAX_BUSID; i++)
- if (busid_table[i][0])
- if (!strncmp(busid_table[i], busid, BUSID_SIZE)) {
+ if (busid_table[i].name[0])
+ if (!strncmp(busid_table[i].name, busid, BUSID_SIZE)) {
/* already registerd */
spin_unlock(&busid_table_lock);
return 0;
@@ -65,6 +64,25 @@ int match_busid(const char *busid)
return 1;
}
+struct bus_id_priv *get_busid_priv(const char *busid)
+{
+ int i;
+
+ spin_lock(&busid_table_lock);
+
+ for (i = 0; i < MAX_BUSID; i++)
+ if (busid_table[i].name[0])
+ if (!strncmp(busid_table[i].name, busid, BUSID_SIZE)) {
+ /* already registerd */
+ spin_unlock(&busid_table_lock);
+ return &(busid_table[i]);
+ }
+
+ spin_unlock(&busid_table_lock);
+
+ return NULL;
+}
+
static ssize_t show_match_busid(struct device_driver *drv, char *buf)
{
int i;
@@ -73,8 +91,8 @@ static ssize_t show_match_busid(struct device_driver *drv, char *buf)
spin_lock(&busid_table_lock);
for (i = 0; i < MAX_BUSID; i++)
- if (busid_table[i][0])
- out += sprintf(out, "%s ", busid_table[i]);
+ if (busid_table[i].name[0])
+ out += sprintf(out, "%s ", busid_table[i].name);
spin_unlock(&busid_table_lock);
@@ -93,8 +111,11 @@ static int add_match_busid(char *busid)
spin_lock(&busid_table_lock);
for (i = 0; i < MAX_BUSID; i++)
- if (!busid_table[i][0]) {
- strncpy(busid_table[i], busid, BUSID_SIZE);
+ if (!busid_table[i].name[0]) {
+ strncpy(busid_table[i].name, busid, BUSID_SIZE);
+ if ((busid_table[i].status != STUB_BUSID_ALLOC) &&
+ (busid_table[i].status != STUB_BUSID_REMOV))
+ busid_table[i].status = STUB_BUSID_ADDED;
spin_unlock(&busid_table_lock);
return 0;
}
@@ -104,16 +125,21 @@ static int add_match_busid(char *busid)
return -1;
}
-static int del_match_busid(char *busid)
+int del_match_busid(char *busid)
{
int i;
spin_lock(&busid_table_lock);
for (i = 0; i < MAX_BUSID; i++)
- if (!strncmp(busid_table[i], busid, BUSID_SIZE)) {
+ if (!strncmp(busid_table[i].name, busid, BUSID_SIZE)) {
/* found */
- memset(busid_table[i], 0, BUSID_SIZE);
+ if (busid_table[i].status == STUB_BUSID_OTHER)
+ memset(busid_table[i].name, 0, BUSID_SIZE);
+ if ((busid_table[i].status != STUB_BUSID_OTHER) &&
+ (busid_table[i].status != STUB_BUSID_ADDED)) {
+ busid_table[i].status = STUB_BUSID_REMOV;
+ }
spin_unlock(&busid_table_lock);
return 0;
}
@@ -122,6 +148,20 @@ static int del_match_busid(char *busid)
return -1;
}
+static void init_busid_table(void)
+{
+ int i;
+
+
+ for (i = 0; i < MAX_BUSID; i++) {
+ memset(busid_table[i].name, 0, BUSID_SIZE);
+ busid_table[i].status = STUB_BUSID_OTHER;
+ busid_table[i].interf_count = 0;
+ busid_table[i].sdev = NULL;
+ busid_table[i].shutdown_busid = 0;
+ }
+ spin_lock_init(&busid_table_lock);
+}
static ssize_t store_match_busid(struct device_driver *dev, const char *buf,
size_t count)
@@ -261,8 +301,7 @@ static int __init usb_stub_init(void)
printk(KERN_INFO KBUILD_MODNAME ":"
DRIVER_DESC ":" DRIVER_VERSION "\n");
- memset(busid_table, 0, sizeof(busid_table));
- spin_lock_init(&busid_table_lock);
+ init_busid_table();
ret = driver_create_file(&stub_driver.drvwrap.driver,
&driver_attr_match_busid);
diff --git a/drivers/staging/usbip/stub_rx.c b/drivers/staging/usbip/stub_rx.c
index 5972ae70e38..3de6fd2539d 100644
--- a/drivers/staging/usbip/stub_rx.c
+++ b/drivers/staging/usbip/stub_rx.c
@@ -362,54 +362,16 @@ static struct stub_priv *stub_priv_alloc(struct stub_device *sdev,
return priv;
}
-
-static struct usb_host_endpoint *get_ep_from_epnum(struct usb_device *udev,
- int epnum0)
-{
- struct usb_host_config *config;
- int i = 0, j = 0;
- struct usb_host_endpoint *ep = NULL;
- int epnum;
- int found = 0;
-
- if (epnum0 == 0)
- return &udev->ep0;
-
- config = udev->actconfig;
- if (!config)
- return NULL;
-
- for (i = 0; i < config->desc.bNumInterfaces; i++) {
- struct usb_host_interface *setting;
-
- setting = config->interface[i]->cur_altsetting;
-
- for (j = 0; j < setting->desc.bNumEndpoints; j++) {
- ep = &setting->endpoint[j];
- epnum = (ep->desc.bEndpointAddress & 0x7f);
-
- if (epnum == epnum0) {
- /* usbip_uinfo("found epnum %d\n", epnum0);*/
- found = 1;
- break;
- }
- }
- }
-
- if (found)
- return ep;
- else
- return NULL;
-}
-
-
static int get_pipe(struct stub_device *sdev, int epnum, int dir)
{
struct usb_device *udev = interface_to_usbdev(sdev->interface);
struct usb_host_endpoint *ep;
struct usb_endpoint_descriptor *epd = NULL;
- ep = get_ep_from_epnum(udev, epnum);
+ if (dir == USBIP_DIR_IN)
+ ep = udev->ep_in[epnum & 0x7f];
+ else
+ ep = udev->ep_out[epnum & 0x7f];
if (!ep) {
dev_err(&sdev->interface->dev, "no such endpoint?, %d\n",
epnum);
@@ -462,6 +424,60 @@ static int get_pipe(struct stub_device *sdev, int epnum, int dir)
return 0;
}
+static void masking_bogus_flags(struct urb *urb)
+{
+ int xfertype;
+ struct usb_device *dev;
+ struct usb_host_endpoint *ep;
+ int is_out;
+ unsigned int allowed;
+
+ if (!urb || urb->hcpriv || !urb->complete)
+ return;
+ dev = urb->dev;
+ if ((!dev) || (dev->state < USB_STATE_UNAUTHENTICATED))
+ return;
+
+ ep = (usb_pipein(urb->pipe) ? dev->ep_in : dev->ep_out)
+ [usb_pipeendpoint(urb->pipe)];
+ if (!ep)
+ return;
+
+ xfertype = usb_endpoint_type(&ep->desc);
+ if (xfertype == USB_ENDPOINT_XFER_CONTROL) {
+ struct usb_ctrlrequest *setup =
+ (struct usb_ctrlrequest *) urb->setup_packet;
+
+ if (!setup)
+ return;
+ is_out = !(setup->bRequestType & USB_DIR_IN) ||
+ !setup->wLength;
+ } else {
+ is_out = usb_endpoint_dir_out(&ep->desc);
+ }
+
+ /* enforce simple/standard policy */
+ allowed = (URB_NO_TRANSFER_DMA_MAP | URB_NO_INTERRUPT |
+ URB_DIR_MASK | URB_FREE_BUFFER);
+ switch (xfertype) {
+ case USB_ENDPOINT_XFER_BULK:
+ if (is_out)
+ allowed |= URB_ZERO_PACKET;
+ /* FALLTHROUGH */
+ case USB_ENDPOINT_XFER_CONTROL:
+ allowed |= URB_NO_FSBR; /* only affects UHCI */
+ /* FALLTHROUGH */
+ default: /* all non-iso endpoints */
+ if (!is_out)
+ allowed |= URB_SHORT_NOT_OK;
+ break;
+ case USB_ENDPOINT_XFER_ISOC:
+ allowed |= URB_ISO_ASAP;
+ break;
+ }
+ urb->transfer_flags &= allowed;
+}
+
static void stub_recv_cmd_submit(struct stub_device *sdev,
struct usbip_header *pdu)
{
@@ -528,6 +544,7 @@ static void stub_recv_cmd_submit(struct stub_device *sdev,
/* no need to submit an intercepted request, but harmless? */
tweak_special_requests(priv->urb);
+ masking_bogus_flags(priv->urb);
/* urb is now ready to submit */
ret = usb_submit_urb(priv->urb, GFP_KERNEL);
diff --git a/drivers/staging/usbip/usbip_common.h b/drivers/staging/usbip/usbip_common.h
index e1bbd1287e2..d280e234e06 100644
--- a/drivers/staging/usbip/usbip_common.h
+++ b/drivers/staging/usbip/usbip_common.h
@@ -172,7 +172,7 @@ struct usbip_header_basic {
#define USBIP_RET_UNLINK 0x0004
__u32 command;
- /* sequencial number which identifies requests.
+ /* sequential number which identifies requests.
* incremented per connections */
__u32 seqnum;
diff --git a/drivers/staging/vme/bridges/vme_ca91cx42.c b/drivers/staging/vme/bridges/vme_ca91cx42.c
index 0f9ea58ff71..06bd793c52b 100644
--- a/drivers/staging/vme/bridges/vme_ca91cx42.c
+++ b/drivers/staging/vme/bridges/vme_ca91cx42.c
@@ -900,7 +900,8 @@ unsigned int ca91cx42_master_rmw(struct vme_master_resource *image,
/* Address must be 4-byte aligned */
if (pci_addr & 0x3) {
dev_err(dev, "RMW Address not 4-byte aligned\n");
- return -EINVAL;
+ result = -EINVAL;
+ goto out;
}
/* Ensure RMW Disabled whilst configuring */
@@ -921,6 +922,7 @@ unsigned int ca91cx42_master_rmw(struct vme_master_resource *image,
/* Disable RMW */
iowrite32(0, bridge->base + SCYC_CTL);
+out:
spin_unlock(&(image->lock));
mutex_unlock(&(bridge->vme_rmw));
@@ -961,11 +963,11 @@ int ca91cx42_dma_list_add(struct vme_dma_list *list, struct vme_dma_attr *src,
if (dest->type == VME_DMA_VME) {
entry->descriptor.dctl |= CA91CX42_DCTL_L2V;
- vme_attr = (struct vme_dma_vme *)dest->private;
- pci_attr = (struct vme_dma_pci *)src->private;
+ vme_attr = dest->private;
+ pci_attr = src->private;
} else {
- vme_attr = (struct vme_dma_vme *)src->private;
- pci_attr = (struct vme_dma_pci *)dest->private;
+ vme_attr = src->private;
+ pci_attr = dest->private;
}
/* Check we can do fullfill required attributes */
diff --git a/drivers/staging/vme/bridges/vme_tsi148.c b/drivers/staging/vme/bridges/vme_tsi148.c
index f09cac16313..492ddb2d510 100644
--- a/drivers/staging/vme/bridges/vme_tsi148.c
+++ b/drivers/staging/vme/bridges/vme_tsi148.c
@@ -1649,7 +1649,7 @@ int tsi148_dma_list_add(struct vme_dma_list *list, struct vme_dma_attr *src,
/* Fill out source part */
switch (src->type) {
case VME_DMA_PATTERN:
- pattern_attr = (struct vme_dma_pattern *)src->private;
+ pattern_attr = src->private;
entry->descriptor.dsal = pattern_attr->pattern;
entry->descriptor.dsat = TSI148_LCSR_DSAT_TYP_PAT;
@@ -1663,7 +1663,7 @@ int tsi148_dma_list_add(struct vme_dma_list *list, struct vme_dma_attr *src,
break;
case VME_DMA_PCI:
- pci_attr = (struct vme_dma_pci *)src->private;
+ pci_attr = src->private;
reg_split((unsigned long long)pci_attr->address, &address_high,
&address_low);
@@ -1672,7 +1672,7 @@ int tsi148_dma_list_add(struct vme_dma_list *list, struct vme_dma_attr *src,
entry->descriptor.dsat = TSI148_LCSR_DSAT_TYP_PCI;
break;
case VME_DMA_VME:
- vme_attr = (struct vme_dma_vme *)src->private;
+ vme_attr = src->private;
reg_split((unsigned long long)vme_attr->address, &address_high,
&address_low);
@@ -1701,7 +1701,7 @@ int tsi148_dma_list_add(struct vme_dma_list *list, struct vme_dma_attr *src,
/* Fill out destination part */
switch (dest->type) {
case VME_DMA_PCI:
- pci_attr = (struct vme_dma_pci *)dest->private;
+ pci_attr = dest->private;
reg_split((unsigned long long)pci_attr->address, &address_high,
&address_low);
@@ -1710,7 +1710,7 @@ int tsi148_dma_list_add(struct vme_dma_list *list, struct vme_dma_attr *src,
entry->descriptor.ddat = TSI148_LCSR_DDAT_TYP_PCI;
break;
case VME_DMA_VME:
- vme_attr = (struct vme_dma_vme *)dest->private;
+ vme_attr = dest->private;
reg_split((unsigned long long)vme_attr->address, &address_high,
&address_low);
diff --git a/drivers/staging/vme/devices/vme_user.c b/drivers/staging/vme/devices/vme_user.c
index bc16fc070fd..8f77bd24630 100644
--- a/drivers/staging/vme/devices/vme_user.c
+++ b/drivers/staging/vme/devices/vme_user.c
@@ -31,15 +31,16 @@
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/syscalls.h>
-#include <linux/smp_lock.h>
+#include <linux/mutex.h>
#include <linux/types.h>
-#include <asm/io.h>
-#include <asm/uaccess.h>
+#include <linux/io.h>
+#include <linux/uaccess.h>
#include "../vme.h"
#include "vme_user.h"
+static DEFINE_MUTEX(vme_user_mutex);
static char driver_name[] = "vme_user";
static int bus[USER_BUS_MAX];
@@ -48,19 +49,19 @@ static int bus_num;
/* Currently Documentation/devices.txt defines the following for VME:
*
* 221 char VME bus
- * 0 = /dev/bus/vme/m0 First master image
- * 1 = /dev/bus/vme/m1 Second master image
- * 2 = /dev/bus/vme/m2 Third master image
- * 3 = /dev/bus/vme/m3 Fourth master image
- * 4 = /dev/bus/vme/s0 First slave image
- * 5 = /dev/bus/vme/s1 Second slave image
- * 6 = /dev/bus/vme/s2 Third slave image
- * 7 = /dev/bus/vme/s3 Fourth slave image
- * 8 = /dev/bus/vme/ctl Control
+ * 0 = /dev/bus/vme/m0 First master image
+ * 1 = /dev/bus/vme/m1 Second master image
+ * 2 = /dev/bus/vme/m2 Third master image
+ * 3 = /dev/bus/vme/m3 Fourth master image
+ * 4 = /dev/bus/vme/s0 First slave image
+ * 5 = /dev/bus/vme/s1 Second slave image
+ * 6 = /dev/bus/vme/s2 Third slave image
+ * 7 = /dev/bus/vme/s3 Fourth slave image
+ * 8 = /dev/bus/vme/ctl Control
*
- * It is expected that all VME bus drivers will use the
- * same interface. For interface documentation see
- * http://www.vmelinux.org/.
+ * It is expected that all VME bus drivers will use the
+ * same interface. For interface documentation see
+ * http://www.vmelinux.org/.
*
* However the VME driver at http://www.vmelinux.org/ is rather old and doesn't
* even support the tsi148 chipset (which has 8 master and 8 slave windows).
@@ -137,12 +138,12 @@ static int __init vme_user_probe(struct device *, int, int);
static int __exit vme_user_remove(struct device *, int, int);
static struct file_operations vme_user_fops = {
- .open = vme_user_open,
- .release = vme_user_release,
- .read = vme_user_read,
- .write = vme_user_write,
- .llseek = vme_user_llseek,
- .unlocked_ioctl = vme_user_unlocked_ioctl,
+ .open = vme_user_open,
+ .release = vme_user_release,
+ .read = vme_user_read,
+ .write = vme_user_write,
+ .llseek = vme_user_llseek,
+ .unlocked_ioctl = vme_user_unlocked_ioctl,
};
@@ -151,13 +152,13 @@ static struct file_operations vme_user_fops = {
*/
static void reset_counters(void)
{
- statistics.reads = 0;
- statistics.writes = 0;
- statistics.ioctls = 0;
- statistics.irqs = 0;
- statistics.berrs = 0;
- statistics.dmaErrors = 0;
- statistics.timeouts = 0;
+ statistics.reads = 0;
+ statistics.writes = 0;
+ statistics.ioctls = 0;
+ statistics.irqs = 0;
+ statistics.berrs = 0;
+ statistics.dmaErrors = 0;
+ statistics.timeouts = 0;
}
static int vme_user_open(struct inode *inode, struct file *file)
@@ -216,21 +217,20 @@ static ssize_t resource_to_user(int minor, char __user *buf, size_t count,
/* We copy to kernel buffer */
copied = vme_master_read(image[minor].resource,
image[minor].kern_buf, count, *ppos);
- if (copied < 0) {
+ if (copied < 0)
return (int)copied;
- }
retval = __copy_to_user(buf, image[minor].kern_buf,
(unsigned long)copied);
if (retval != 0) {
copied = (copied - retval);
- printk("User copy failed\n");
+ printk(KERN_INFO "User copy failed\n");
return -EINVAL;
}
} else {
/* XXX Need to write this */
- printk("Currently don't support large transfers\n");
+ printk(KERN_INFO "Currently don't support large transfers\n");
/* Map in pages from userspace */
/* Call vme_master_read to do the transfer */
@@ -264,7 +264,7 @@ static ssize_t resource_from_user(unsigned int minor, const char *buf,
image[minor].kern_buf, copied, *ppos);
} else {
/* XXX Need to write this */
- printk("Currently don't support large transfers\n");
+ printk(KERN_INFO "Currently don't support large transfers\n");
/* Map in pages from userspace */
/* Call vme_master_write to do the transfer */
@@ -313,7 +313,7 @@ static ssize_t buffer_from_user(unsigned int minor, const char *buf,
}
static ssize_t vme_user_read(struct file *file, char *buf, size_t count,
- loff_t * ppos)
+ loff_t *ppos)
{
unsigned int minor = MINOR(file->f_dentry->d_inode->i_rdev);
ssize_t retval;
@@ -337,7 +337,7 @@ static ssize_t vme_user_read(struct file *file, char *buf, size_t count,
else
okcount = count;
- switch (type[minor]){
+ switch (type[minor]) {
case MASTER_MINOR:
retval = resource_to_user(minor, buf, okcount, ppos);
break;
@@ -380,7 +380,7 @@ static ssize_t vme_user_write(struct file *file, const char *buf, size_t count,
else
okcount = count;
- switch (type[minor]){
+ switch (type[minor]) {
case MASTER_MINOR:
retval = resource_from_user(minor, buf, okcount, ppos);
break;
@@ -560,9 +560,9 @@ vme_user_unlocked_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
int ret;
- lock_kernel();
+ mutex_lock(&vme_user_mutex);
ret = vme_user_ioctl(file->f_path.dentry->d_inode, file, cmd, arg);
- unlock_kernel();
+ mutex_unlock(&vme_user_mutex);
return ret;
}
@@ -571,7 +571,7 @@ vme_user_unlocked_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
/*
* Unallocate a previously allocated buffer
*/
-static void buf_unalloc (int num)
+static void buf_unalloc(int num)
{
if (image[num].kern_buf) {
#ifdef VME_DEBUG
@@ -594,8 +594,8 @@ static void buf_unalloc (int num)
}
static struct vme_driver vme_user_driver = {
- .name = driver_name,
- .probe = vme_user_probe,
+ .name = driver_name,
+ .probe = vme_user_probe,
.remove = vme_user_remove,
};
@@ -770,16 +770,16 @@ static int __init vme_user_probe(struct device *dev, int cur_bus, int cur_slot)
}
/* Add sysfs Entries */
- for (i=0; i<VME_DEVS; i++) {
+ for (i = 0; i < VME_DEVS; i++) {
switch (type[i]) {
case MASTER_MINOR:
- sprintf(name,"bus/vme/m%%d");
+ sprintf(name, "bus/vme/m%%d");
break;
case CONTROL_MINOR:
- sprintf(name,"bus/vme/ctl");
+ sprintf(name, "bus/vme/ctl");
break;
case SLAVE_MINOR:
- sprintf(name,"bus/vme/s%%d");
+ sprintf(name, "bus/vme/s%%d");
break;
default:
err = -EINVAL;
@@ -790,9 +790,9 @@ static int __init vme_user_probe(struct device *dev, int cur_bus, int cur_slot)
image[i].device =
device_create(vme_user_sysfs_class, NULL,
MKDEV(VME_MAJOR, i), NULL, name,
- (type[i] == SLAVE_MINOR)? i - (MASTER_MAX + 1) : i);
+ (type[i] == SLAVE_MINOR) ? i - (MASTER_MAX + 1) : i);
if (IS_ERR(image[i].device)) {
- printk("%s: Error creating sysfs device\n",
+ printk(KERN_INFO "%s: Error creating sysfs device\n",
driver_name);
err = PTR_ERR(image[i].device);
goto err_sysfs;
@@ -804,7 +804,7 @@ static int __init vme_user_probe(struct device *dev, int cur_bus, int cur_slot)
/* Ensure counter set correcty to destroy all sysfs devices */
i = VME_DEVS;
err_sysfs:
- while (i > 0){
+ while (i > 0) {
i--;
device_destroy(vme_user_sysfs_class, MKDEV(VME_MAJOR, i));
}
@@ -845,9 +845,8 @@ static int __exit vme_user_remove(struct device *dev, int cur_bus, int cur_slot)
int i;
/* Remove sysfs Entries */
- for(i=0; i<VME_DEVS; i++) {
+ for (i = 0; i < VME_DEVS; i++)
device_destroy(vme_user_sysfs_class, MKDEV(VME_MAJOR, i));
- }
class_destroy(vme_user_sysfs_class);
for (i = MASTER_MINOR; i < (MASTER_MAX + 1); i++)
diff --git a/drivers/staging/vt6655/80211hdr.h b/drivers/staging/vt6655/80211hdr.h
index b7b170e19aa..f55283b8641 100644
--- a/drivers/staging/vt6655/80211hdr.h
+++ b/drivers/staging/vt6655/80211hdr.h
@@ -161,21 +161,21 @@
#ifdef __BIG_ENDIAN
/* GET & SET Frame Control bit */
-#define WLAN_GET_FC_PRVER(n) ((((WORD)(n) >> 8) & (BIT0 | BIT1))
-#define WLAN_GET_FC_FTYPE(n) ((((WORD)(n) >> 8) & (BIT2 | BIT3)) >> 2)
-#define WLAN_GET_FC_FSTYPE(n) ((((WORD)(n) >> 8) & (BIT4|BIT5|BIT6|BIT7)) >> 4)
-#define WLAN_GET_FC_TODS(n) ((((WORD)(n) << 8) & (BIT8)) >> 8)
-#define WLAN_GET_FC_FROMDS(n) ((((WORD)(n) << 8) & (BIT9)) >> 9)
-#define WLAN_GET_FC_MOREFRAG(n) ((((WORD)(n) << 8) & (BIT10)) >> 10)
-#define WLAN_GET_FC_RETRY(n) ((((WORD)(n) << 8) & (BIT11)) >> 11)
-#define WLAN_GET_FC_PWRMGT(n) ((((WORD)(n) << 8) & (BIT12)) >> 12)
-#define WLAN_GET_FC_MOREDATA(n) ((((WORD)(n) << 8) & (BIT13)) >> 13)
-#define WLAN_GET_FC_ISWEP(n) ((((WORD)(n) << 8) & (BIT14)) >> 14)
-#define WLAN_GET_FC_ORDER(n) ((((WORD)(n) << 8) & (BIT15)) >> 15)
+#define WLAN_GET_FC_PRVER(n) ((((unsigned short)(n) >> 8) & (BIT0 | BIT1))
+#define WLAN_GET_FC_FTYPE(n) ((((unsigned short)(n) >> 8) & (BIT2 | BIT3)) >> 2)
+#define WLAN_GET_FC_FSTYPE(n) ((((unsigned short)(n) >> 8) & (BIT4|BIT5|BIT6|BIT7)) >> 4)
+#define WLAN_GET_FC_TODS(n) ((((unsigned short)(n) << 8) & (BIT8)) >> 8)
+#define WLAN_GET_FC_FROMDS(n) ((((unsigned short)(n) << 8) & (BIT9)) >> 9)
+#define WLAN_GET_FC_MOREFRAG(n) ((((unsigned short)(n) << 8) & (BIT10)) >> 10)
+#define WLAN_GET_FC_RETRY(n) ((((unsigned short)(n) << 8) & (BIT11)) >> 11)
+#define WLAN_GET_FC_PWRMGT(n) ((((unsigned short)(n) << 8) & (BIT12)) >> 12)
+#define WLAN_GET_FC_MOREDATA(n) ((((unsigned short)(n) << 8) & (BIT13)) >> 13)
+#define WLAN_GET_FC_ISWEP(n) ((((unsigned short)(n) << 8) & (BIT14)) >> 14)
+#define WLAN_GET_FC_ORDER(n) ((((unsigned short)(n) << 8) & (BIT15)) >> 15)
/* Sequence Field bit */
-#define WLAN_GET_SEQ_FRGNUM(n) (((WORD)(n) >> 8) & (BIT0|BIT1|BIT2|BIT3))
-#define WLAN_GET_SEQ_SEQNUM(n) ((((WORD)(n) >> 8) & (~(BIT0|BIT1|BIT2|BIT3))) >> 4)
+#define WLAN_GET_SEQ_FRGNUM(n) (((unsigned short)(n) >> 8) & (BIT0|BIT1|BIT2|BIT3))
+#define WLAN_GET_SEQ_SEQNUM(n) ((((unsigned short)(n) >> 8) & (~(BIT0|BIT1|BIT2|BIT3))) >> 4)
/* Capability Field bit */
@@ -196,22 +196,22 @@
#else
/* GET & SET Frame Control bit */
-#define WLAN_GET_FC_PRVER(n) (((WORD)(n)) & (BIT0 | BIT1))
-#define WLAN_GET_FC_FTYPE(n) ((((WORD)(n)) & (BIT2 | BIT3)) >> 2)
-#define WLAN_GET_FC_FSTYPE(n) ((((WORD)(n)) & (BIT4|BIT5|BIT6|BIT7)) >> 4)
-#define WLAN_GET_FC_TODS(n) ((((WORD)(n)) & (BIT8)) >> 8)
-#define WLAN_GET_FC_FROMDS(n) ((((WORD)(n)) & (BIT9)) >> 9)
-#define WLAN_GET_FC_MOREFRAG(n) ((((WORD)(n)) & (BIT10)) >> 10)
-#define WLAN_GET_FC_RETRY(n) ((((WORD)(n)) & (BIT11)) >> 11)
-#define WLAN_GET_FC_PWRMGT(n) ((((WORD)(n)) & (BIT12)) >> 12)
-#define WLAN_GET_FC_MOREDATA(n) ((((WORD)(n)) & (BIT13)) >> 13)
-#define WLAN_GET_FC_ISWEP(n) ((((WORD)(n)) & (BIT14)) >> 14)
-#define WLAN_GET_FC_ORDER(n) ((((WORD)(n)) & (BIT15)) >> 15)
+#define WLAN_GET_FC_PRVER(n) (((unsigned short)(n)) & (BIT0 | BIT1))
+#define WLAN_GET_FC_FTYPE(n) ((((unsigned short)(n)) & (BIT2 | BIT3)) >> 2)
+#define WLAN_GET_FC_FSTYPE(n) ((((unsigned short)(n)) & (BIT4|BIT5|BIT6|BIT7)) >> 4)
+#define WLAN_GET_FC_TODS(n) ((((unsigned short)(n)) & (BIT8)) >> 8)
+#define WLAN_GET_FC_FROMDS(n) ((((unsigned short)(n)) & (BIT9)) >> 9)
+#define WLAN_GET_FC_MOREFRAG(n) ((((unsigned short)(n)) & (BIT10)) >> 10)
+#define WLAN_GET_FC_RETRY(n) ((((unsigned short)(n)) & (BIT11)) >> 11)
+#define WLAN_GET_FC_PWRMGT(n) ((((unsigned short)(n)) & (BIT12)) >> 12)
+#define WLAN_GET_FC_MOREDATA(n) ((((unsigned short)(n)) & (BIT13)) >> 13)
+#define WLAN_GET_FC_ISWEP(n) ((((unsigned short)(n)) & (BIT14)) >> 14)
+#define WLAN_GET_FC_ORDER(n) ((((unsigned short)(n)) & (BIT15)) >> 15)
/* Sequence Field bit */
-#define WLAN_GET_SEQ_FRGNUM(n) (((WORD)(n)) & (BIT0|BIT1|BIT2|BIT3))
-#define WLAN_GET_SEQ_SEQNUM(n) ((((WORD)(n)) & (~(BIT0|BIT1|BIT2|BIT3))) >> 4)
+#define WLAN_GET_SEQ_FRGNUM(n) (((unsigned short)(n)) & (BIT0|BIT1|BIT2|BIT3))
+#define WLAN_GET_SEQ_SEQNUM(n) ((((unsigned short)(n)) & (~(BIT0|BIT1|BIT2|BIT3))) >> 4)
/* Capability Field bit */
@@ -246,20 +246,20 @@
#define WLAN_SET_CAP_INFO_GRPACK(n) ((n) << 14)
-#define WLAN_SET_FC_PRVER(n) ((WORD)(n))
-#define WLAN_SET_FC_FTYPE(n) (((WORD)(n)) << 2)
-#define WLAN_SET_FC_FSTYPE(n) (((WORD)(n)) << 4)
-#define WLAN_SET_FC_TODS(n) (((WORD)(n)) << 8)
-#define WLAN_SET_FC_FROMDS(n) (((WORD)(n)) << 9)
-#define WLAN_SET_FC_MOREFRAG(n) (((WORD)(n)) << 10)
-#define WLAN_SET_FC_RETRY(n) (((WORD)(n)) << 11)
-#define WLAN_SET_FC_PWRMGT(n) (((WORD)(n)) << 12)
-#define WLAN_SET_FC_MOREDATA(n) (((WORD)(n)) << 13)
-#define WLAN_SET_FC_ISWEP(n) (((WORD)(n)) << 14)
-#define WLAN_SET_FC_ORDER(n) (((WORD)(n)) << 15)
+#define WLAN_SET_FC_PRVER(n) ((unsigned short)(n))
+#define WLAN_SET_FC_FTYPE(n) (((unsigned short)(n)) << 2)
+#define WLAN_SET_FC_FSTYPE(n) (((unsigned short)(n)) << 4)
+#define WLAN_SET_FC_TODS(n) (((unsigned short)(n)) << 8)
+#define WLAN_SET_FC_FROMDS(n) (((unsigned short)(n)) << 9)
+#define WLAN_SET_FC_MOREFRAG(n) (((unsigned short)(n)) << 10)
+#define WLAN_SET_FC_RETRY(n) (((unsigned short)(n)) << 11)
+#define WLAN_SET_FC_PWRMGT(n) (((unsigned short)(n)) << 12)
+#define WLAN_SET_FC_MOREDATA(n) (((unsigned short)(n)) << 13)
+#define WLAN_SET_FC_ISWEP(n) (((unsigned short)(n)) << 14)
+#define WLAN_SET_FC_ORDER(n) (((unsigned short)(n)) << 15)
-#define WLAN_SET_SEQ_FRGNUM(n) ((WORD)(n))
-#define WLAN_SET_SEQ_SEQNUM(n) (((WORD)(n)) << 4)
+#define WLAN_SET_SEQ_FRGNUM(n) ((unsigned short)(n))
+#define WLAN_SET_SEQ_SEQNUM(n) (((unsigned short)(n)) << 4)
/* ERP Field bit */
@@ -282,50 +282,50 @@
#define WLAN_MGMT_GET_TIM_OFFSET(b) (((b) & ~BIT0) >> 1)
/* 3-Addr & 4-Addr */
-#define WLAN_HDR_A3_DATA_PTR(p) (((PBYTE)(p)) + WLAN_HDR_ADDR3_LEN)
-#define WLAN_HDR_A4_DATA_PTR(p) (((PBYTE)(p)) + WLAN_HDR_ADDR4_LEN)
+#define WLAN_HDR_A3_DATA_PTR(p) (((unsigned char *)(p)) + WLAN_HDR_ADDR3_LEN)
+#define WLAN_HDR_A4_DATA_PTR(p) (((unsigned char *)(p)) + WLAN_HDR_ADDR4_LEN)
/* IEEE ADDR */
#define IEEE_ADDR_UNIVERSAL 0x02
#define IEEE_ADDR_GROUP 0x01
typedef struct {
- BYTE abyAddr[6];
+ unsigned char abyAddr[6];
} IEEE_ADDR, *PIEEE_ADDR;
/* 802.11 Header Format */
typedef struct tagWLAN_80211HDR_A2 {
- WORD wFrameCtl;
- WORD wDurationID;
- BYTE abyAddr1[WLAN_ADDR_LEN];
- BYTE abyAddr2[WLAN_ADDR_LEN];
+ unsigned short wFrameCtl;
+ unsigned short wDurationID;
+ unsigned char abyAddr1[WLAN_ADDR_LEN];
+ unsigned char abyAddr2[WLAN_ADDR_LEN];
} __attribute__ ((__packed__))
WLAN_80211HDR_A2, *PWLAN_80211HDR_A2;
typedef struct tagWLAN_80211HDR_A3 {
- WORD wFrameCtl;
- WORD wDurationID;
- BYTE abyAddr1[WLAN_ADDR_LEN];
- BYTE abyAddr2[WLAN_ADDR_LEN];
- BYTE abyAddr3[WLAN_ADDR_LEN];
- WORD wSeqCtl;
+ unsigned short wFrameCtl;
+ unsigned short wDurationID;
+ unsigned char abyAddr1[WLAN_ADDR_LEN];
+ unsigned char abyAddr2[WLAN_ADDR_LEN];
+ unsigned char abyAddr3[WLAN_ADDR_LEN];
+ unsigned short wSeqCtl;
}__attribute__ ((__packed__))
WLAN_80211HDR_A3, *PWLAN_80211HDR_A3;
typedef struct tagWLAN_80211HDR_A4 {
- WORD wFrameCtl;
- WORD wDurationID;
- BYTE abyAddr1[WLAN_ADDR_LEN];
- BYTE abyAddr2[WLAN_ADDR_LEN];
- BYTE abyAddr3[WLAN_ADDR_LEN];
- WORD wSeqCtl;
- BYTE abyAddr4[WLAN_ADDR_LEN];
+ unsigned short wFrameCtl;
+ unsigned short wDurationID;
+ unsigned char abyAddr1[WLAN_ADDR_LEN];
+ unsigned char abyAddr2[WLAN_ADDR_LEN];
+ unsigned char abyAddr3[WLAN_ADDR_LEN];
+ unsigned short wSeqCtl;
+ unsigned char abyAddr4[WLAN_ADDR_LEN];
} __attribute__ ((__packed__))
WLAN_80211HDR_A4, *PWLAN_80211HDR_A4;
diff --git a/drivers/staging/vt6655/80211mgr.c b/drivers/staging/vt6655/80211mgr.c
index 38697c86248..1ed0f260b16 100644
--- a/drivers/staging/vt6655/80211mgr.c
+++ b/drivers/staging/vt6655/80211mgr.c
@@ -99,9 +99,9 @@ vMgrEncodeBeacon(
// Fixed Fields
pFrame->pqwTimestamp = (PQWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ WLAN_BEACON_OFF_TS);
- pFrame->pwBeaconInterval = (PWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ pFrame->pwBeaconInterval = (unsigned short *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ WLAN_BEACON_OFF_BCN_INT);
- pFrame->pwCapInfo = (PWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ pFrame->pwCapInfo = (unsigned short *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ WLAN_BEACON_OFF_CAPINFO);
pFrame->len = WLAN_HDR_ADDR3_LEN + WLAN_BEACON_OFF_SSID;
@@ -133,15 +133,15 @@ vMgrDecodeBeacon(
// Fixed Fields
pFrame->pqwTimestamp = (PQWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ WLAN_BEACON_OFF_TS);
- pFrame->pwBeaconInterval = (PWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ pFrame->pwBeaconInterval = (unsigned short *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ WLAN_BEACON_OFF_BCN_INT);
- pFrame->pwCapInfo = (PWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ pFrame->pwCapInfo = (unsigned short *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ WLAN_BEACON_OFF_CAPINFO);
// Information elements
- pItem = (PWLAN_IE)((PBYTE)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3)))
+ pItem = (PWLAN_IE)((unsigned char *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3)))
+ WLAN_BEACON_OFF_SSID);
- while( ((PBYTE)pItem) < (pFrame->pBuf + pFrame->len) ){
+ while( ((unsigned char *)pItem) < (pFrame->pBuf + pFrame->len) ){
switch (pItem->byElementID) {
case WLAN_EID_SSID:
@@ -179,7 +179,7 @@ vMgrDecodeBeacon(
break;
case WLAN_EID_RSN_WPA:
if (pFrame->pRSNWPA == NULL) {
- if (WPAb_Is_RSN((PWLAN_IE_RSN_EXT)pItem) == TRUE)
+ if (WPAb_Is_RSN((PWLAN_IE_RSN_EXT)pItem) == true)
pFrame->pRSNWPA = (PWLAN_IE_RSN_EXT)pItem;
}
break;
@@ -223,7 +223,7 @@ vMgrDecodeBeacon(
break;
}
- pItem = (PWLAN_IE)(((PBYTE)pItem) + 2 + pItem->len);
+ pItem = (PWLAN_IE)(((unsigned char *)pItem) + 2 + pItem->len);
}
return;
@@ -296,7 +296,7 @@ vMgrEncodeDisassociation(
// Fixed Fields
- pFrame->pwReason = (PWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ pFrame->pwReason = (unsigned short *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ WLAN_DISASSOC_OFF_REASON);
pFrame->len = WLAN_HDR_ADDR3_LEN + WLAN_DISASSOC_OFF_REASON + sizeof(*(pFrame->pwReason));
@@ -323,7 +323,7 @@ vMgrDecodeDisassociation(
pFrame->pHdr = (PUWLAN_80211HDR)pFrame->pBuf;
// Fixed Fields
- pFrame->pwReason = (PWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ pFrame->pwReason = (unsigned short *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ WLAN_DISASSOC_OFF_REASON);
return;
@@ -348,9 +348,9 @@ vMgrEncodeAssocRequest(
{
pFrame->pHdr = (PUWLAN_80211HDR)pFrame->pBuf;
// Fixed Fields
- pFrame->pwCapInfo = (PWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ pFrame->pwCapInfo = (unsigned short *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ WLAN_ASSOCREQ_OFF_CAP_INFO);
- pFrame->pwListenInterval = (PWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ pFrame->pwListenInterval = (unsigned short *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ WLAN_ASSOCREQ_OFF_LISTEN_INT);
pFrame->len = WLAN_HDR_ADDR3_LEN + WLAN_ASSOCREQ_OFF_LISTEN_INT + sizeof(*(pFrame->pwListenInterval));
return;
@@ -377,16 +377,16 @@ vMgrDecodeAssocRequest(
pFrame->pHdr = (PUWLAN_80211HDR)pFrame->pBuf;
// Fixed Fields
- pFrame->pwCapInfo = (PWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ pFrame->pwCapInfo = (unsigned short *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ WLAN_ASSOCREQ_OFF_CAP_INFO);
- pFrame->pwListenInterval = (PWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ pFrame->pwListenInterval = (unsigned short *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ WLAN_ASSOCREQ_OFF_LISTEN_INT);
// Information elements
pItem = (PWLAN_IE)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ WLAN_ASSOCREQ_OFF_SSID);
- while (((PBYTE)pItem) < (pFrame->pBuf + pFrame->len)) {
+ while (((unsigned char *)pItem) < (pFrame->pBuf + pFrame->len)) {
switch (pItem->byElementID){
case WLAN_EID_SSID:
if (pFrame->pSSID == NULL)
@@ -404,7 +404,7 @@ vMgrDecodeAssocRequest(
break;
case WLAN_EID_RSN_WPA:
if (pFrame->pRSNWPA == NULL) {
- if (WPAb_Is_RSN((PWLAN_IE_RSN_EXT)pItem) == TRUE)
+ if (WPAb_Is_RSN((PWLAN_IE_RSN_EXT)pItem) == true)
pFrame->pRSNWPA = (PWLAN_IE_RSN_EXT)pItem;
}
break;
@@ -418,7 +418,7 @@ vMgrDecodeAssocRequest(
pItem->byElementID);
break;
}
- pItem = (PWLAN_IE)(((PBYTE)pItem) + 2 + pItem->len);
+ pItem = (PWLAN_IE)(((unsigned char *)pItem) + 2 + pItem->len);
}
return;
}
@@ -442,11 +442,11 @@ vMgrEncodeAssocResponse(
pFrame->pHdr = (PUWLAN_80211HDR)pFrame->pBuf;
// Fixed Fields
- pFrame->pwCapInfo = (PWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ pFrame->pwCapInfo = (unsigned short *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ WLAN_ASSOCRESP_OFF_CAP_INFO);
- pFrame->pwStatus = (PWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ pFrame->pwStatus = (unsigned short *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ WLAN_ASSOCRESP_OFF_STATUS);
- pFrame->pwAid = (PWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ pFrame->pwAid = (unsigned short *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ WLAN_ASSOCRESP_OFF_AID);
pFrame->len = WLAN_HDR_ADDR3_LEN + WLAN_ASSOCRESP_OFF_AID
+ sizeof(*(pFrame->pwAid));
@@ -476,11 +476,11 @@ vMgrDecodeAssocResponse(
pFrame->pHdr = (PUWLAN_80211HDR)pFrame->pBuf;
// Fixed Fields
- pFrame->pwCapInfo = (PWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ pFrame->pwCapInfo = (unsigned short *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ WLAN_ASSOCRESP_OFF_CAP_INFO);
- pFrame->pwStatus = (PWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ pFrame->pwStatus = (unsigned short *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ WLAN_ASSOCRESP_OFF_STATUS);
- pFrame->pwAid = (PWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ pFrame->pwAid = (unsigned short *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ WLAN_ASSOCRESP_OFF_AID);
// Information elements
@@ -488,9 +488,10 @@ vMgrDecodeAssocResponse(
+ WLAN_ASSOCRESP_OFF_SUPP_RATES);
pItem = (PWLAN_IE)(pFrame->pSuppRates);
- pItem = (PWLAN_IE)(((PBYTE)pItem) + 2 + pItem->len);
+ pItem = (PWLAN_IE)(((unsigned char *)pItem) + 2 + pItem->len);
- if ((((PBYTE)pItem) < (pFrame->pBuf + pFrame->len)) && (pItem->byElementID == WLAN_EID_EXTSUPP_RATES)) {
+ if ((((unsigned char *)pItem) < (pFrame->pBuf + pFrame->len)) &&
+ (pItem->byElementID == WLAN_EID_EXTSUPP_RATES)) {
pFrame->pExtSuppRates = (PWLAN_IE_SUPP_RATES)pItem;
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "pFrame->pExtSuppRates=[%p].\n", pItem);
}
@@ -520,9 +521,9 @@ vMgrEncodeReassocRequest(
pFrame->pHdr = (PUWLAN_80211HDR)pFrame->pBuf;
// Fixed Fields
- pFrame->pwCapInfo = (PWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ pFrame->pwCapInfo = (unsigned short *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ WLAN_REASSOCREQ_OFF_CAP_INFO);
- pFrame->pwListenInterval = (PWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ pFrame->pwListenInterval = (unsigned short *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ WLAN_REASSOCREQ_OFF_LISTEN_INT);
pFrame->pAddrCurrAP = (PIEEE_ADDR)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ WLAN_REASSOCREQ_OFF_CURR_AP);
@@ -553,9 +554,9 @@ vMgrDecodeReassocRequest(
pFrame->pHdr = (PUWLAN_80211HDR)pFrame->pBuf;
// Fixed Fields
- pFrame->pwCapInfo = (PWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ pFrame->pwCapInfo = (unsigned short *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ WLAN_REASSOCREQ_OFF_CAP_INFO);
- pFrame->pwListenInterval = (PWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ pFrame->pwListenInterval = (unsigned short *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ WLAN_REASSOCREQ_OFF_LISTEN_INT);
pFrame->pAddrCurrAP = (PIEEE_ADDR)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ WLAN_REASSOCREQ_OFF_CURR_AP);
@@ -564,7 +565,7 @@ vMgrDecodeReassocRequest(
pItem = (PWLAN_IE)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ WLAN_REASSOCREQ_OFF_SSID);
- while(((PBYTE)pItem) < (pFrame->pBuf + pFrame->len)) {
+ while(((unsigned char *)pItem) < (pFrame->pBuf + pFrame->len)) {
switch (pItem->byElementID){
case WLAN_EID_SSID:
@@ -583,7 +584,7 @@ vMgrDecodeReassocRequest(
break;
case WLAN_EID_RSN_WPA:
if (pFrame->pRSNWPA == NULL) {
- if (WPAb_Is_RSN((PWLAN_IE_RSN_EXT)pItem) == TRUE)
+ if (WPAb_Is_RSN((PWLAN_IE_RSN_EXT)pItem) == true)
pFrame->pRSNWPA = (PWLAN_IE_RSN_EXT)pItem;
}
break;
@@ -597,7 +598,7 @@ vMgrDecodeReassocRequest(
pItem->byElementID);
break;
}
- pItem = (PWLAN_IE)(((PBYTE)pItem) + 2 + pItem->len);
+ pItem = (PWLAN_IE)(((unsigned char *)pItem) + 2 + pItem->len);
}
return;
}
@@ -649,7 +650,7 @@ vMgrDecodeProbeRequest(
// Information elements
pItem = (PWLAN_IE)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3)));
- while( ((PBYTE)pItem) < (pFrame->pBuf + pFrame->len) ) {
+ while( ((unsigned char *)pItem) < (pFrame->pBuf + pFrame->len) ) {
switch (pItem->byElementID) {
case WLAN_EID_SSID:
@@ -672,7 +673,7 @@ vMgrDecodeProbeRequest(
break;
}
- pItem = (PWLAN_IE)(((PBYTE)pItem) + 2 + pItem->len);
+ pItem = (PWLAN_IE)(((unsigned char *)pItem) + 2 + pItem->len);
}
return;
}
@@ -700,9 +701,9 @@ vMgrEncodeProbeResponse(
// Fixed Fields
pFrame->pqwTimestamp = (PQWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ WLAN_PROBERESP_OFF_TS);
- pFrame->pwBeaconInterval = (PWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ pFrame->pwBeaconInterval = (unsigned short *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ WLAN_PROBERESP_OFF_BCN_INT);
- pFrame->pwCapInfo = (PWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ pFrame->pwCapInfo = (unsigned short *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ WLAN_PROBERESP_OFF_CAP_INFO);
pFrame->len = WLAN_HDR_ADDR3_LEN + WLAN_PROBERESP_OFF_CAP_INFO +
@@ -737,16 +738,16 @@ vMgrDecodeProbeResponse(
// Fixed Fields
pFrame->pqwTimestamp = (PQWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ WLAN_PROBERESP_OFF_TS);
- pFrame->pwBeaconInterval = (PWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ pFrame->pwBeaconInterval = (unsigned short *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ WLAN_PROBERESP_OFF_BCN_INT);
- pFrame->pwCapInfo = (PWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ pFrame->pwCapInfo = (unsigned short *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ WLAN_PROBERESP_OFF_CAP_INFO);
// Information elements
pItem = (PWLAN_IE)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ WLAN_PROBERESP_OFF_SSID);
- while( ((PBYTE)pItem) < (pFrame->pBuf + pFrame->len) ) {
+ while( ((unsigned char *)pItem) < (pFrame->pBuf + pFrame->len) ) {
switch (pItem->byElementID) {
case WLAN_EID_SSID:
if (pFrame->pSSID == NULL)
@@ -778,7 +779,7 @@ vMgrDecodeProbeResponse(
break;
case WLAN_EID_RSN_WPA:
if (pFrame->pRSNWPA == NULL) {
- if (WPAb_Is_RSN((PWLAN_IE_RSN_EXT)pItem) == TRUE)
+ if (WPAb_Is_RSN((PWLAN_IE_RSN_EXT)pItem) == true)
pFrame->pRSNWPA = (PWLAN_IE_RSN_EXT)pItem;
}
break;
@@ -821,7 +822,7 @@ vMgrDecodeProbeResponse(
break;
}
- pItem = (PWLAN_IE)(((PBYTE)pItem) + 2 + pItem->len);
+ pItem = (PWLAN_IE)(((unsigned char *)pItem) + 2 + pItem->len);
}
return;
}
@@ -846,11 +847,11 @@ vMgrEncodeAuthen(
pFrame->pHdr = (PUWLAN_80211HDR)pFrame->pBuf;
// Fixed Fields
- pFrame->pwAuthAlgorithm = (PWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ pFrame->pwAuthAlgorithm = (unsigned short *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ WLAN_AUTHEN_OFF_AUTH_ALG);
- pFrame->pwAuthSequence = (PWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ pFrame->pwAuthSequence = (unsigned short *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ WLAN_AUTHEN_OFF_AUTH_SEQ);
- pFrame->pwStatus = (PWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ pFrame->pwStatus = (unsigned short *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ WLAN_AUTHEN_OFF_STATUS);
pFrame->len = WLAN_HDR_ADDR3_LEN + WLAN_AUTHEN_OFF_STATUS + sizeof(*(pFrame->pwStatus));
@@ -879,18 +880,18 @@ vMgrDecodeAuthen(
pFrame->pHdr = (PUWLAN_80211HDR)pFrame->pBuf;
// Fixed Fields
- pFrame->pwAuthAlgorithm = (PWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ pFrame->pwAuthAlgorithm = (unsigned short *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ WLAN_AUTHEN_OFF_AUTH_ALG);
- pFrame->pwAuthSequence = (PWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ pFrame->pwAuthSequence = (unsigned short *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ WLAN_AUTHEN_OFF_AUTH_SEQ);
- pFrame->pwStatus = (PWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ pFrame->pwStatus = (unsigned short *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ WLAN_AUTHEN_OFF_STATUS);
// Information elements
pItem = (PWLAN_IE)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ WLAN_AUTHEN_OFF_CHALLENGE);
- if ((((PBYTE)pItem) < (pFrame->pBuf + pFrame->len)) && (pItem->byElementID == WLAN_EID_CHALLENGE)) {
+ if ((((unsigned char *)pItem) < (pFrame->pBuf + pFrame->len)) && (pItem->byElementID == WLAN_EID_CHALLENGE)) {
pFrame->pChallenge = (PWLAN_IE_CHALLENGE)pItem;
}
@@ -917,7 +918,7 @@ vMgrEncodeDeauthen(
pFrame->pHdr = (PUWLAN_80211HDR)pFrame->pBuf;
// Fixed Fields
- pFrame->pwReason = (PWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ pFrame->pwReason = (unsigned short *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ WLAN_DEAUTHEN_OFF_REASON);
pFrame->len = WLAN_HDR_ADDR3_LEN + WLAN_DEAUTHEN_OFF_REASON + sizeof(*(pFrame->pwReason));
@@ -944,7 +945,7 @@ vMgrDecodeDeauthen(
pFrame->pHdr = (PUWLAN_80211HDR)pFrame->pBuf;
// Fixed Fields
- pFrame->pwReason = (PWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ pFrame->pwReason = (unsigned short *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ WLAN_DEAUTHEN_OFF_REASON);
return;
@@ -970,11 +971,11 @@ vMgrEncodeReassocResponse(
pFrame->pHdr = (PUWLAN_80211HDR)pFrame->pBuf;
// Fixed Fields
- pFrame->pwCapInfo = (PWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ pFrame->pwCapInfo = (unsigned short *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ WLAN_REASSOCRESP_OFF_CAP_INFO);
- pFrame->pwStatus = (PWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ pFrame->pwStatus = (unsigned short *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ WLAN_REASSOCRESP_OFF_STATUS);
- pFrame->pwAid = (PWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ pFrame->pwAid = (unsigned short *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ WLAN_REASSOCRESP_OFF_AID);
pFrame->len = WLAN_HDR_ADDR3_LEN + WLAN_REASSOCRESP_OFF_AID + sizeof(*(pFrame->pwAid));
@@ -1005,11 +1006,11 @@ vMgrDecodeReassocResponse(
pFrame->pHdr = (PUWLAN_80211HDR)pFrame->pBuf;
// Fixed Fields
- pFrame->pwCapInfo = (PWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ pFrame->pwCapInfo = (unsigned short *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ WLAN_REASSOCRESP_OFF_CAP_INFO);
- pFrame->pwStatus = (PWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ pFrame->pwStatus = (unsigned short *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ WLAN_REASSOCRESP_OFF_STATUS);
- pFrame->pwAid = (PWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ pFrame->pwAid = (unsigned short *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ WLAN_REASSOCRESP_OFF_AID);
//Information elements
@@ -1017,9 +1018,10 @@ vMgrDecodeReassocResponse(
+ WLAN_REASSOCRESP_OFF_SUPP_RATES);
pItem = (PWLAN_IE)(pFrame->pSuppRates);
- pItem = (PWLAN_IE)(((PBYTE)pItem) + 2 + pItem->len);
+ pItem = (PWLAN_IE)(((unsigned char *)pItem) + 2 + pItem->len);
- if ((((PBYTE)pItem) < (pFrame->pBuf + pFrame->len)) && (pItem->byElementID == WLAN_EID_EXTSUPP_RATES)) {
+ if ((((unsigned char *)pItem) < (pFrame->pBuf + pFrame->len)) &&
+ (pItem->byElementID == WLAN_EID_EXTSUPP_RATES)) {
pFrame->pExtSuppRates = (PWLAN_IE_SUPP_RATES)pItem;
}
return;
diff --git a/drivers/staging/vt6655/80211mgr.h b/drivers/staging/vt6655/80211mgr.h
index 658fe144f89..3bdab3f56f1 100644
--- a/drivers/staging/vt6655/80211mgr.h
+++ b/drivers/staging/vt6655/80211mgr.h
@@ -19,7 +19,7 @@
*
* File: 80211mgr.h
*
- * Purpose: 802.11 managment frames pre-defines.
+ * Purpose: 802.11 management frames pre-defines.
*
*
* Author: Lyndon Chen
@@ -230,8 +230,8 @@
#pragma pack(1)
typedef struct tagWLAN_IE {
- BYTE byElementID;
- BYTE len;
+ unsigned char byElementID;
+ unsigned char len;
}__attribute__ ((__packed__))
WLAN_IE, *PWLAN_IE;
@@ -239,9 +239,9 @@ WLAN_IE, *PWLAN_IE;
// Service Set Identity (SSID)
#pragma pack(1)
typedef struct tagWLAN_IE_SSID {
- BYTE byElementID;
- BYTE len;
- BYTE abySSID[1];
+ unsigned char byElementID;
+ unsigned char len;
+ unsigned char abySSID[1];
}__attribute__ ((__packed__))
WLAN_IE_SSID, *PWLAN_IE_SSID;
@@ -249,9 +249,9 @@ WLAN_IE_SSID, *PWLAN_IE_SSID;
// Supported Rates
#pragma pack(1)
typedef struct tagWLAN_IE_SUPP_RATES {
- BYTE byElementID;
- BYTE len;
- BYTE abyRates[1];
+ unsigned char byElementID;
+ unsigned char len;
+ unsigned char abyRates[1];
}__attribute__ ((__packed__))
WLAN_IE_SUPP_RATES, *PWLAN_IE_SUPP_RATES;
@@ -260,20 +260,20 @@ WLAN_IE_SUPP_RATES, *PWLAN_IE_SUPP_RATES;
// FH Parameter Set
#pragma pack(1)
typedef struct _WLAN_IE_FH_PARMS {
- BYTE byElementID;
- BYTE len;
- WORD wDwellTime;
- BYTE byHopSet;
- BYTE byHopPattern;
- BYTE byHopIndex;
+ unsigned char byElementID;
+ unsigned char len;
+ unsigned short wDwellTime;
+ unsigned char byHopSet;
+ unsigned char byHopPattern;
+ unsigned char byHopIndex;
} WLAN_IE_FH_PARMS, *PWLAN_IE_FH_PARMS;
// DS Parameter Set
#pragma pack(1)
typedef struct tagWLAN_IE_DS_PARMS {
- BYTE byElementID;
- BYTE len;
- BYTE byCurrChannel;
+ unsigned char byElementID;
+ unsigned char len;
+ unsigned char byCurrChannel;
}__attribute__ ((__packed__))
WLAN_IE_DS_PARMS, *PWLAN_IE_DS_PARMS;
@@ -281,12 +281,12 @@ WLAN_IE_DS_PARMS, *PWLAN_IE_DS_PARMS;
// CF Parameter Set
#pragma pack(1)
typedef struct tagWLAN_IE_CF_PARMS {
- BYTE byElementID;
- BYTE len;
- BYTE byCFPCount;
- BYTE byCFPPeriod;
- WORD wCFPMaxDuration;
- WORD wCFPDurRemaining;
+ unsigned char byElementID;
+ unsigned char len;
+ unsigned char byCFPCount;
+ unsigned char byCFPPeriod;
+ unsigned short wCFPMaxDuration;
+ unsigned short wCFPDurRemaining;
}__attribute__ ((__packed__))
WLAN_IE_CF_PARMS, *PWLAN_IE_CF_PARMS;
@@ -294,12 +294,12 @@ WLAN_IE_CF_PARMS, *PWLAN_IE_CF_PARMS;
// TIM
#pragma pack(1)
typedef struct tagWLAN_IE_TIM {
- BYTE byElementID;
- BYTE len;
- BYTE byDTIMCount;
- BYTE byDTIMPeriod;
- BYTE byBitMapCtl;
- BYTE byVirtBitMap[1];
+ unsigned char byElementID;
+ unsigned char len;
+ unsigned char byDTIMCount;
+ unsigned char byDTIMPeriod;
+ unsigned char byBitMapCtl;
+ unsigned char byVirtBitMap[1];
}__attribute__ ((__packed__))
WLAN_IE_TIM, *PWLAN_IE_TIM;
@@ -307,9 +307,9 @@ WLAN_IE_TIM, *PWLAN_IE_TIM;
// IBSS Parameter Set
#pragma pack(1)
typedef struct tagWLAN_IE_IBSS_PARMS {
- BYTE byElementID;
- BYTE len;
- WORD wATIMWindow;
+ unsigned char byElementID;
+ unsigned char len;
+ unsigned short wATIMWindow;
}__attribute__ ((__packed__))
WLAN_IE_IBSS_PARMS, *PWLAN_IE_IBSS_PARMS;
@@ -317,84 +317,84 @@ WLAN_IE_IBSS_PARMS, *PWLAN_IE_IBSS_PARMS;
// Challenge Text
#pragma pack(1)
typedef struct tagWLAN_IE_CHALLENGE {
- BYTE byElementID;
- BYTE len;
- BYTE abyChallenge[1];
+ unsigned char byElementID;
+ unsigned char len;
+ unsigned char abyChallenge[1];
}__attribute__ ((__packed__))
WLAN_IE_CHALLENGE, *PWLAN_IE_CHALLENGE;
#pragma pack(1)
typedef struct tagWLAN_IE_RSN_EXT {
- BYTE byElementID;
- BYTE len;
- BYTE abyOUI[4];
- WORD wVersion;
- BYTE abyMulticast[4];
- WORD wPKCount;
+ unsigned char byElementID;
+ unsigned char len;
+ unsigned char abyOUI[4];
+ unsigned short wVersion;
+ unsigned char abyMulticast[4];
+ unsigned short wPKCount;
struct {
- BYTE abyOUI[4];
+ unsigned char abyOUI[4];
} PKSList[1]; // the rest is variable so need to
// overlay ieauth structure
} WLAN_IE_RSN_EXT, *PWLAN_IE_RSN_EXT;
#pragma pack(1)
typedef struct tagWLAN_IE_RSN_AUTH {
- WORD wAuthCount;
+ unsigned short wAuthCount;
struct {
- BYTE abyOUI[4];
+ unsigned char abyOUI[4];
} AuthKSList[1];
} WLAN_IE_RSN_AUTH, *PWLAN_IE_RSN_AUTH;
// RSN Identity
#pragma pack(1)
typedef struct tagWLAN_IE_RSN {
- BYTE byElementID;
- BYTE len;
- WORD wVersion;
- BYTE abyRSN[WLAN_MIN_ARRAY];
+ unsigned char byElementID;
+ unsigned char len;
+ unsigned short wVersion;
+ unsigned char abyRSN[WLAN_MIN_ARRAY];
} WLAN_IE_RSN, *PWLAN_IE_RSN;
// ERP
#pragma pack(1)
typedef struct tagWLAN_IE_ERP {
- BYTE byElementID;
- BYTE len;
- BYTE byContext;
+ unsigned char byElementID;
+ unsigned char len;
+ unsigned char byContext;
}__attribute__ ((__packed__))
WLAN_IE_ERP, *PWLAN_IE_ERP;
#pragma pack(1)
typedef struct _MEASEURE_REQ {
- BYTE byChannel;
- BYTE abyStartTime[8];
- BYTE abyDuration[2];
+ unsigned char byChannel;
+ unsigned char abyStartTime[8];
+ unsigned char abyDuration[2];
} MEASEURE_REQ, *PMEASEURE_REQ,
MEASEURE_REQ_BASIC, *PMEASEURE_REQ_BASIC,
MEASEURE_REQ_CCA, *PMEASEURE_REQ_CCA,
MEASEURE_REQ_RPI, *PMEASEURE_REQ_RPI;
typedef struct _MEASEURE_REP_BASIC {
- BYTE byChannel;
- BYTE abyStartTime[8];
- BYTE abyDuration[2];
- BYTE byMap;
+ unsigned char byChannel;
+ unsigned char abyStartTime[8];
+ unsigned char abyDuration[2];
+ unsigned char byMap;
} MEASEURE_REP_BASIC, *PMEASEURE_REP_BASIC;
typedef struct _MEASEURE_REP_CCA {
- BYTE byChannel;
- BYTE abyStartTime[8];
- BYTE abyDuration[2];
- BYTE byCCABusyFraction;
+ unsigned char byChannel;
+ unsigned char abyStartTime[8];
+ unsigned char abyDuration[2];
+ unsigned char byCCABusyFraction;
} MEASEURE_REP_CCA, *PMEASEURE_REP_CCA;
typedef struct _MEASEURE_REP_RPI {
- BYTE byChannel;
- BYTE abyStartTime[8];
- BYTE abyDuration[2];
- BYTE abyRPIdensity[8];
+ unsigned char byChannel;
+ unsigned char abyStartTime[8];
+ unsigned char abyDuration[2];
+ unsigned char abyRPIdensity[8];
} MEASEURE_REP_RPI, *PMEASEURE_REP_RPI;
typedef union _MEASEURE_REP {
@@ -406,85 +406,85 @@ typedef union _MEASEURE_REP {
} MEASEURE_REP, *PMEASEURE_REP;
typedef struct _WLAN_IE_MEASURE_REQ {
- BYTE byElementID;
- BYTE len;
- BYTE byToken;
- BYTE byMode;
- BYTE byType;
+ unsigned char byElementID;
+ unsigned char len;
+ unsigned char byToken;
+ unsigned char byMode;
+ unsigned char byType;
MEASEURE_REQ sReq;
} WLAN_IE_MEASURE_REQ, *PWLAN_IE_MEASURE_REQ;
typedef struct _WLAN_IE_MEASURE_REP {
- BYTE byElementID;
- BYTE len;
- BYTE byToken;
- BYTE byMode;
- BYTE byType;
+ unsigned char byElementID;
+ unsigned char len;
+ unsigned char byToken;
+ unsigned char byMode;
+ unsigned char byType;
MEASEURE_REP sRep;
} WLAN_IE_MEASURE_REP, *PWLAN_IE_MEASURE_REP;
typedef struct _WLAN_IE_CH_SW {
- BYTE byElementID;
- BYTE len;
- BYTE byMode;
- BYTE byChannel;
- BYTE byCount;
+ unsigned char byElementID;
+ unsigned char len;
+ unsigned char byMode;
+ unsigned char byChannel;
+ unsigned char byCount;
} WLAN_IE_CH_SW, *PWLAN_IE_CH_SW;
typedef struct _WLAN_IE_QUIET {
- BYTE byElementID;
- BYTE len;
- BYTE byQuietCount;
- BYTE byQuietPeriod;
- BYTE abyQuietDuration[2];
- BYTE abyQuietOffset[2];
+ unsigned char byElementID;
+ unsigned char len;
+ unsigned char byQuietCount;
+ unsigned char byQuietPeriod;
+ unsigned char abyQuietDuration[2];
+ unsigned char abyQuietOffset[2];
} WLAN_IE_QUIET, *PWLAN_IE_QUIET;
typedef struct _WLAN_IE_COUNTRY {
- BYTE byElementID;
- BYTE len;
- BYTE abyCountryString[3];
- BYTE abyCountryInfo[3];
+ unsigned char byElementID;
+ unsigned char len;
+ unsigned char abyCountryString[3];
+ unsigned char abyCountryInfo[3];
} WLAN_IE_COUNTRY, *PWLAN_IE_COUNTRY;
typedef struct _WLAN_IE_PW_CONST {
- BYTE byElementID;
- BYTE len;
- BYTE byPower;
+ unsigned char byElementID;
+ unsigned char len;
+ unsigned char byPower;
} WLAN_IE_PW_CONST, *PWLAN_IE_PW_CONST;
typedef struct _WLAN_IE_PW_CAP {
- BYTE byElementID;
- BYTE len;
- BYTE byMinPower;
- BYTE byMaxPower;
+ unsigned char byElementID;
+ unsigned char len;
+ unsigned char byMinPower;
+ unsigned char byMaxPower;
} WLAN_IE_PW_CAP, *PWLAN_IE_PW_CAP;
typedef struct _WLAN_IE_SUPP_CH {
- BYTE byElementID;
- BYTE len;
- BYTE abyChannelTuple[2];
+ unsigned char byElementID;
+ unsigned char len;
+ unsigned char abyChannelTuple[2];
} WLAN_IE_SUPP_CH, *PWLAN_IE_SUPP_CH;
typedef struct _WLAN_IE_TPC_REQ {
- BYTE byElementID;
- BYTE len;
+ unsigned char byElementID;
+ unsigned char len;
} WLAN_IE_TPC_REQ, *PWLAN_IE_TPC_REQ;
typedef struct _WLAN_IE_TPC_REP {
- BYTE byElementID;
- BYTE len;
- BYTE byTxPower;
- BYTE byLinkMargin;
+ unsigned char byElementID;
+ unsigned char len;
+ unsigned char byTxPower;
+ unsigned char byLinkMargin;
} WLAN_IE_TPC_REP, *PWLAN_IE_TPC_REP;
typedef struct _WLAN_IE_IBSS_DFS {
- BYTE byElementID;
- BYTE len;
- BYTE abyDFSOwner[6];
- BYTE byDFSRecovery;
- BYTE abyChannelMap[2];
+ unsigned char byElementID;
+ unsigned char len;
+ unsigned char abyDFSOwner[6];
+ unsigned char byDFSRecovery;
+ unsigned char abyChannelMap[2];
} WLAN_IE_IBSS_DFS, *PWLAN_IE_IBSS_DFS;
#pragma pack()
@@ -495,9 +495,9 @@ typedef struct _WLAN_IE_IBSS_DFS {
// prototype structure, all mgmt frame types will start with these members
typedef struct tagWLAN_FR_MGMT {
- UINT uType;
- UINT len;
- PBYTE pBuf;
+ unsigned int uType;
+ unsigned int len;
+ unsigned char *pBuf;
PUWLAN_80211HDR pHdr;
} WLAN_FR_MGMT, *PWLAN_FR_MGMT;
@@ -505,14 +505,14 @@ typedef struct tagWLAN_FR_MGMT {
// Beacon frame
typedef struct tagWLAN_FR_BEACON {
- UINT uType;
- UINT len;
- PBYTE pBuf;
+ unsigned int uType;
+ unsigned int len;
+ unsigned char *pBuf;
PUWLAN_80211HDR pHdr;
// fixed fields
PQWORD pqwTimestamp;
- PWORD pwBeaconInterval;
- PWORD pwCapInfo;
+ unsigned short *pwBeaconInterval;
+ unsigned short *pwCapInfo;
/*-- info elements ----------*/
PWLAN_IE_SSID pSSID;
PWLAN_IE_SUPP_RATES pSuppRates;
@@ -537,9 +537,9 @@ typedef struct tagWLAN_FR_BEACON {
// IBSS ATIM frame
typedef struct tagWLAN_FR_IBSSATIM {
- UINT uType;
- UINT len;
- PBYTE pBuf;
+ unsigned int uType;
+ unsigned int len;
+ unsigned char *pBuf;
PUWLAN_80211HDR pHdr;
// fixed fields
@@ -551,12 +551,12 @@ typedef struct tagWLAN_FR_IBSSATIM {
// Disassociation
typedef struct tagWLAN_FR_DISASSOC {
- UINT uType;
- UINT len;
- PBYTE pBuf;
+ unsigned int uType;
+ unsigned int len;
+ unsigned char *pBuf;
PUWLAN_80211HDR pHdr;
/*-- fixed fields -----------*/
- PWORD pwReason;
+ unsigned short *pwReason;
/*-- info elements ----------*/
} WLAN_FR_DISASSOC, *PWLAN_FR_DISASSOC;
@@ -564,13 +564,13 @@ typedef struct tagWLAN_FR_DISASSOC {
// Association Request
typedef struct tagWLAN_FR_ASSOCREQ {
- UINT uType;
- UINT len;
- PBYTE pBuf;
+ unsigned int uType;
+ unsigned int len;
+ unsigned char *pBuf;
PUWLAN_80211HDR pHdr;
/*-- fixed fields -----------*/
- PWORD pwCapInfo;
- PWORD pwListenInterval;
+ unsigned short *pwCapInfo;
+ unsigned short *pwListenInterval;
/*-- info elements ----------*/
PWLAN_IE_SSID pSSID;
PWLAN_IE_SUPP_RATES pSuppRates;
@@ -585,14 +585,14 @@ typedef struct tagWLAN_FR_ASSOCREQ {
// Association Response
typedef struct tagWLAN_FR_ASSOCRESP {
- UINT uType;
- UINT len;
- PBYTE pBuf;
+ unsigned int uType;
+ unsigned int len;
+ unsigned char *pBuf;
PUWLAN_80211HDR pHdr;
/*-- fixed fields -----------*/
- PWORD pwCapInfo;
- PWORD pwStatus;
- PWORD pwAid;
+ unsigned short *pwCapInfo;
+ unsigned short *pwStatus;
+ unsigned short *pwAid;
/*-- info elements ----------*/
PWLAN_IE_SUPP_RATES pSuppRates;
PWLAN_IE_SUPP_RATES pExtSuppRates;
@@ -602,14 +602,14 @@ typedef struct tagWLAN_FR_ASSOCRESP {
// Reassociation Request
typedef struct tagWLAN_FR_REASSOCREQ {
- UINT uType;
- UINT len;
- PBYTE pBuf;
+ unsigned int uType;
+ unsigned int len;
+ unsigned char *pBuf;
PUWLAN_80211HDR pHdr;
/*-- fixed fields -----------*/
- PWORD pwCapInfo;
- PWORD pwListenInterval;
+ unsigned short *pwCapInfo;
+ unsigned short *pwListenInterval;
PIEEE_ADDR pAddrCurrAP;
/*-- info elements ----------*/
@@ -624,14 +624,14 @@ typedef struct tagWLAN_FR_REASSOCREQ {
// Reassociation Response
typedef struct tagWLAN_FR_REASSOCRESP {
- UINT uType;
- UINT len;
- PBYTE pBuf;
+ unsigned int uType;
+ unsigned int len;
+ unsigned char *pBuf;
PUWLAN_80211HDR pHdr;
/*-- fixed fields -----------*/
- PWORD pwCapInfo;
- PWORD pwStatus;
- PWORD pwAid;
+ unsigned short *pwCapInfo;
+ unsigned short *pwStatus;
+ unsigned short *pwAid;
/*-- info elements ----------*/
PWLAN_IE_SUPP_RATES pSuppRates;
PWLAN_IE_SUPP_RATES pExtSuppRates;
@@ -641,9 +641,9 @@ typedef struct tagWLAN_FR_REASSOCRESP {
// Probe Request
typedef struct tagWLAN_FR_PROBEREQ {
- UINT uType;
- UINT len;
- PBYTE pBuf;
+ unsigned int uType;
+ unsigned int len;
+ unsigned char *pBuf;
PUWLAN_80211HDR pHdr;
/*-- fixed fields -----------*/
/*-- info elements ----------*/
@@ -656,14 +656,14 @@ typedef struct tagWLAN_FR_PROBEREQ {
// Probe Response
typedef struct tagWLAN_FR_PROBERESP {
- UINT uType;
- UINT len;
- PBYTE pBuf;
+ unsigned int uType;
+ unsigned int len;
+ unsigned char *pBuf;
PUWLAN_80211HDR pHdr;
/*-- fixed fields -----------*/
PQWORD pqwTimestamp;
- PWORD pwBeaconInterval;
- PWORD pwCapInfo;
+ unsigned short *pwBeaconInterval;
+ unsigned short *pwCapInfo;
/*-- info elements ----------*/
PWLAN_IE_SSID pSSID;
PWLAN_IE_SUPP_RATES pSuppRates;
@@ -685,14 +685,14 @@ typedef struct tagWLAN_FR_PROBERESP {
// Authentication
typedef struct tagWLAN_FR_AUTHEN {
- UINT uType;
- UINT len;
- PBYTE pBuf;
+ unsigned int uType;
+ unsigned int len;
+ unsigned char *pBuf;
PUWLAN_80211HDR pHdr;
/*-- fixed fields -----------*/
- PWORD pwAuthAlgorithm;
- PWORD pwAuthSequence;
- PWORD pwStatus;
+ unsigned short *pwAuthAlgorithm;
+ unsigned short *pwAuthSequence;
+ unsigned short *pwStatus;
/*-- info elements ----------*/
PWLAN_IE_CHALLENGE pChallenge;
@@ -701,12 +701,12 @@ typedef struct tagWLAN_FR_AUTHEN {
// Deauthenication
typedef struct tagWLAN_FR_DEAUTHEN {
- UINT uType;
- UINT len;
- PBYTE pBuf;
+ unsigned int uType;
+ unsigned int len;
+ unsigned char *pBuf;
PUWLAN_80211HDR pHdr;
/*-- fixed fields -----------*/
- PWORD pwReason;
+ unsigned short *pwReason;
/*-- info elements ----------*/
diff --git a/drivers/staging/vt6655/IEEE11h.c b/drivers/staging/vt6655/IEEE11h.c
index 22f12f5ef90..e07ebd578d4 100644
--- a/drivers/staging/vt6655/IEEE11h.c
+++ b/drivers/staging/vt6655/IEEE11h.c
@@ -38,6 +38,7 @@
#include "device.h"
#include "wmgr.h"
#include "rxtx.h"
+#include "channel.h"
/*--------------------- Static Definitions -------------------------*/
static int msglevel =MSG_LEVEL_INFO;
@@ -46,40 +47,40 @@ static int msglevel =MSG_LEVEL_INFO;
typedef struct _WLAN_FRAME_ACTION {
WLAN_80211HDR_A3 Header;
- BYTE byCategory;
- BYTE byAction;
- BYTE abyVars[1];
+ unsigned char byCategory;
+ unsigned char byAction;
+ unsigned char abyVars[1];
} WLAN_FRAME_ACTION, *PWLAN_FRAME_ACTION;
typedef struct _WLAN_FRAME_MSRREQ {
WLAN_80211HDR_A3 Header;
- BYTE byCategory;
- BYTE byAction;
- BYTE byDialogToken;
+ unsigned char byCategory;
+ unsigned char byAction;
+ unsigned char byDialogToken;
WLAN_IE_MEASURE_REQ sMSRReqEIDs[1];
} WLAN_FRAME_MSRREQ, *PWLAN_FRAME_MSRREQ;
typedef struct _WLAN_FRAME_MSRREP {
WLAN_80211HDR_A3 Header;
- BYTE byCategory;
- BYTE byAction;
- BYTE byDialogToken;
+ unsigned char byCategory;
+ unsigned char byAction;
+ unsigned char byDialogToken;
WLAN_IE_MEASURE_REP sMSRRepEIDs[1];
} WLAN_FRAME_MSRREP, *PWLAN_FRAME_MSRREP;
typedef struct _WLAN_FRAME_TPCREQ {
WLAN_80211HDR_A3 Header;
- BYTE byCategory;
- BYTE byAction;
- BYTE byDialogToken;
+ unsigned char byCategory;
+ unsigned char byAction;
+ unsigned char byDialogToken;
WLAN_IE_TPC_REQ sTPCReqEIDs;
} WLAN_FRAME_TPCREQ, *PWLAN_FRAME_TPCREQ;
typedef struct _WLAN_FRAME_TPCREP {
WLAN_80211HDR_A3 Header;
- BYTE byCategory;
- BYTE byAction;
- BYTE byDialogToken;
+ unsigned char byCategory;
+ unsigned char byAction;
+ unsigned char byDialogToken;
WLAN_IE_TPC_REP sTPCRepEIDs;
} WLAN_FRAME_TPCREP, *PWLAN_FRAME_TPCREP;
@@ -97,10 +98,11 @@ typedef struct _WLAN_FRAME_TPCREP {
/*--------------------- Static Variables --------------------------*/
/*--------------------- Static Functions --------------------------*/
-static BOOL s_bRxMSRReq(PSMgmtObject pMgmt, PWLAN_FRAME_MSRREQ pMSRReq, UINT uLength)
+static bool s_bRxMSRReq(PSMgmtObject pMgmt, PWLAN_FRAME_MSRREQ pMSRReq,
+ unsigned int uLength)
{
size_t uNumOfEIDs = 0;
- BOOL bResult = TRUE;
+ bool bResult = true;
if (uLength <= WLAN_A3FR_MAXLEN) {
memcpy(pMgmt->abyCurrentMSRReq, pMSRReq, uLength);
@@ -116,7 +118,7 @@ static BOOL s_bRxMSRReq(PSMgmtObject pMgmt, PWLAN_FRAME_MSRREQ pMSRReq, UINT uLe
}
-static BOOL s_bRxTPCReq(PSMgmtObject pMgmt, PWLAN_FRAME_TPCREQ pTPCReq, BYTE byRate, BYTE byRSSI)
+static bool s_bRxTPCReq(PSMgmtObject pMgmt, PWLAN_FRAME_TPCREQ pTPCReq, unsigned char byRate, unsigned char byRSSI)
{
PWLAN_FRAME_TPCREP pFrame;
PSTxMgmtPacket pTxPacket = NULL;
@@ -124,9 +126,9 @@ static BOOL s_bRxTPCReq(PSMgmtObject pMgmt, PWLAN_FRAME_TPCREQ pTPCReq, BYTE byR
pTxPacket = (PSTxMgmtPacket)pMgmt->pbyMgmtPacketPool;
memset(pTxPacket, 0, sizeof(STxMgmtPacket) + WLAN_A3FR_MAXLEN);
- pTxPacket->p80211Header = (PUWLAN_80211HDR)((PBYTE)pTxPacket + sizeof(STxMgmtPacket));
+ pTxPacket->p80211Header = (PUWLAN_80211HDR)((unsigned char *)pTxPacket + sizeof(STxMgmtPacket));
- pFrame = (PWLAN_FRAME_TPCREP)((PBYTE)pTxPacket + sizeof(STxMgmtPacket));
+ pFrame = (PWLAN_FRAME_TPCREP)((unsigned char *)pTxPacket + sizeof(STxMgmtPacket));
pFrame->Header.wFrameCtl = ( WLAN_SET_FC_FTYPE(WLAN_FTYPE_MGMT) |
WLAN_SET_FC_FSTYPE(WLAN_FSTYPE_ACTION)
@@ -174,8 +176,8 @@ static BOOL s_bRxTPCReq(PSMgmtObject pMgmt, PWLAN_FRAME_TPCREQ pTPCReq, BYTE byR
pTxPacket->cbMPDULen = sizeof(WLAN_FRAME_TPCREP);
pTxPacket->cbPayloadLen = sizeof(WLAN_FRAME_TPCREP) - WLAN_HDR_ADDR3_LEN;
if (csMgmt_xmit(pMgmt->pAdapter, pTxPacket) != CMD_STATUS_PENDING)
- return (FALSE);
- return (TRUE);
+ return (false);
+ return (true);
// return (CARDbSendPacket(pMgmt->pAdapter, pFrame, PKT_TYPE_802_11_MNG, sizeof(WLAN_FRAME_TPCREP)));
}
@@ -201,7 +203,7 @@ static BOOL s_bRxTPCReq(PSMgmtObject pMgmt, PWLAN_FRAME_TPCREQ pTPCReq, BYTE byR
* Return Value: None.
*
-*/
-BOOL
+bool
IEEE11hbMgrRxAction (
void *pMgmtHandle,
void *pRxPacket
@@ -209,14 +211,14 @@ IEEE11hbMgrRxAction (
{
PSMgmtObject pMgmt = (PSMgmtObject) pMgmtHandle;
PWLAN_FRAME_ACTION pAction = NULL;
- UINT uLength = 0;
+ unsigned int uLength = 0;
PWLAN_IE_CH_SW pChannelSwitch = NULL;
// decode the frame
uLength = ((PSRxMgmtPacket)pRxPacket)->cbMPDULen;
if (uLength > WLAN_A3FR_MAXLEN) {
- return (FALSE);
+ return (false);
}
@@ -233,7 +235,7 @@ IEEE11hbMgrRxAction (
return (s_bRxTPCReq(pMgmt,
(PWLAN_FRAME_TPCREQ) pAction,
((PSRxMgmtPacket)pRxPacket)->byRxRate,
- (BYTE) ((PSRxMgmtPacket)pRxPacket)->uRSSI));
+ (unsigned char) ((PSRxMgmtPacket)pRxPacket)->uRSSI));
break;
case ACTION_TPCREP:
break;
@@ -244,7 +246,7 @@ IEEE11hbMgrRxAction (
// valid element id
CARDbChannelSwitch( pMgmt->pAdapter,
pChannelSwitch->byMode,
- CARDbyGetChannelMapping(pMgmt->pAdapter, pChannelSwitch->byChannel, pMgmt->eCurrentPHYMode),
+ get_channel_mapping(pMgmt->pAdapter, pChannelSwitch->byChannel, pMgmt->eCurrentPHYMode),
pChannelSwitch->byCount
);
}
@@ -258,13 +260,13 @@ IEEE11hbMgrRxAction (
pAction->byCategory |= 0x80;
//return (CARDbSendPacket(pMgmt->pAdapter, pAction, PKT_TYPE_802_11_MNG, uLength));
- return (TRUE);
+ return (true);
}
- return (TRUE);
+ return (true);
}
-BOOL IEEE11hbMSRRepTx (
+bool IEEE11hbMSRRepTx (
void *pMgmtHandle
)
{
@@ -275,7 +277,7 @@ BOOL IEEE11hbMSRRepTx (
pTxPacket = (PSTxMgmtPacket)pMgmt->abyCurrentMSRRep;
memset(pTxPacket, 0, sizeof(STxMgmtPacket) + WLAN_A3FR_MAXLEN);
- pTxPacket->p80211Header = (PUWLAN_80211HDR)((PBYTE)pTxPacket + sizeof(STxMgmtPacket));
+ pTxPacket->p80211Header = (PUWLAN_80211HDR)((unsigned char *)pTxPacket + sizeof(STxMgmtPacket));
pMSRRep->Header.wFrameCtl = ( WLAN_SET_FC_FTYPE(WLAN_FTYPE_MGMT) |
@@ -295,8 +297,8 @@ BOOL IEEE11hbMSRRepTx (
pTxPacket->cbMPDULen = uLength;
pTxPacket->cbPayloadLen = uLength - WLAN_HDR_ADDR3_LEN;
if (csMgmt_xmit(pMgmt->pAdapter, pTxPacket) != CMD_STATUS_PENDING)
- return (FALSE);
- return (TRUE);
+ return (false);
+ return (true);
// return (CARDbSendPacket(pMgmt->pAdapter, pMSRRep, PKT_TYPE_802_11_MNG, uLength));
}
diff --git a/drivers/staging/vt6655/IEEE11h.h b/drivers/staging/vt6655/IEEE11h.h
index ae32498a511..542340b96e3 100644
--- a/drivers/staging/vt6655/IEEE11h.h
+++ b/drivers/staging/vt6655/IEEE11h.h
@@ -45,7 +45,7 @@
/*--------------------- Export Functions --------------------------*/
-BOOL IEEE11hbMSRRepTx (
+bool IEEE11hbMSRRepTx (
void *pMgmtHandle
);
diff --git a/drivers/staging/vt6655/Makefile b/drivers/staging/vt6655/Makefile
index 931deb109ee..824c9718787 100644
--- a/drivers/staging/vt6655/Makefile
+++ b/drivers/staging/vt6655/Makefile
@@ -4,6 +4,7 @@ EXTRA_CFLAGS += -DHOSTAP
vt6655_stage-y += device_main.o \
card.o \
+ channel.o \
mac.o \
baseband.o \
wctl.o \
diff --git a/drivers/staging/vt6655/TODO b/drivers/staging/vt6655/TODO
index cb04aaafc46..63607ef9c97 100644
--- a/drivers/staging/vt6655/TODO
+++ b/drivers/staging/vt6655/TODO
@@ -3,7 +3,6 @@ TODO:
- prepare for merge with vt6656 driver:
- rename DEVICE_PRT() to DBG_PRT() -- done
- share 80211*.h includes
- - move code for channel mapping from card.c to channel.c
- split rf.c
- remove dead code
- abstract VT3253 chipset specific code
@@ -11,6 +10,8 @@ TODO:
- kill ttype.h
- switch to use LIB80211
- switch to use MAC80211
+- verify unsigned long usage for x86-64 arch
+- reduce .data footprint
- use kernel coding style
- checkpatch.pl fixes
- sparse fixes
diff --git a/drivers/staging/vt6655/aes_ccmp.c b/drivers/staging/vt6655/aes_ccmp.c
index fef1b91c292..e30168f2da2 100644
--- a/drivers/staging/vt6655/aes_ccmp.c
+++ b/drivers/staging/vt6655/aes_ccmp.c
@@ -46,7 +46,7 @@
* SBOX Table
*/
-BYTE sbox_table[256] =
+unsigned char sbox_table[256] =
{
0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76,
0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0,
@@ -66,7 +66,7 @@ BYTE sbox_table[256] =
0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16
};
-BYTE dot2_table[256] = {
+unsigned char dot2_table[256] = {
0x00, 0x02, 0x04, 0x06, 0x08, 0x0a, 0x0c, 0x0e, 0x10, 0x12, 0x14, 0x16, 0x18, 0x1a, 0x1c, 0x1e,
0x20, 0x22, 0x24, 0x26, 0x28, 0x2a, 0x2c, 0x2e, 0x30, 0x32, 0x34, 0x36, 0x38, 0x3a, 0x3c, 0x3e,
0x40, 0x42, 0x44, 0x46, 0x48, 0x4a, 0x4c, 0x4e, 0x50, 0x52, 0x54, 0x56, 0x58, 0x5a, 0x5c, 0x5e,
@@ -85,7 +85,7 @@ BYTE dot2_table[256] = {
0xfb, 0xf9, 0xff, 0xfd, 0xf3, 0xf1, 0xf7, 0xf5, 0xeb, 0xe9, 0xef, 0xed, 0xe3, 0xe1, 0xe7, 0xe5
};
-BYTE dot3_table[256] = {
+unsigned char dot3_table[256] = {
0x00, 0x03, 0x06, 0x05, 0x0c, 0x0f, 0x0a, 0x09, 0x18, 0x1b, 0x1e, 0x1d, 0x14, 0x17, 0x12, 0x11,
0x30, 0x33, 0x36, 0x35, 0x3c, 0x3f, 0x3a, 0x39, 0x28, 0x2b, 0x2e, 0x2d, 0x24, 0x27, 0x22, 0x21,
0x60, 0x63, 0x66, 0x65, 0x6c, 0x6f, 0x6a, 0x69, 0x78, 0x7b, 0x7e, 0x7d, 0x74, 0x77, 0x72, 0x71,
@@ -110,11 +110,11 @@ BYTE dot3_table[256] = {
/*--------------------- Export Functions --------------------------*/
-void xor_128(BYTE *a, BYTE *b, BYTE *out)
+void xor_128(unsigned char *a, unsigned char *b, unsigned char *out)
{
-PDWORD dwPtrA = (PDWORD) a;
-PDWORD dwPtrB = (PDWORD) b;
-PDWORD dwPtrOut =(PDWORD) out;
+unsigned long *dwPtrA = (unsigned long *) a;
+unsigned long *dwPtrB = (unsigned long *) b;
+unsigned long *dwPtrOut =(unsigned long *) out;
(*dwPtrOut++) = (*dwPtrA++) ^ (*dwPtrB++);
(*dwPtrOut++) = (*dwPtrA++) ^ (*dwPtrB++);
@@ -123,19 +123,19 @@ PDWORD dwPtrOut =(PDWORD) out;
}
-void xor_32(BYTE *a, BYTE *b, BYTE *out)
+void xor_32(unsigned char *a, unsigned char *b, unsigned char *out)
{
-PDWORD dwPtrA = (PDWORD) a;
-PDWORD dwPtrB = (PDWORD) b;
-PDWORD dwPtrOut =(PDWORD) out;
+unsigned long *dwPtrA = (unsigned long *) a;
+unsigned long *dwPtrB = (unsigned long *) b;
+unsigned long *dwPtrOut =(unsigned long *) out;
(*dwPtrOut++) = (*dwPtrA++) ^ (*dwPtrB++);
}
-void AddRoundKey(BYTE *key, int round)
+void AddRoundKey(unsigned char *key, int round)
{
-BYTE sbox_key[4];
-BYTE rcon_table[10] = { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36};
+unsigned char sbox_key[4];
+unsigned char rcon_table[10] = { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36};
sbox_key[0] = sbox_table[key[13]];
sbox_key[1] = sbox_table[key[14]];
@@ -150,7 +150,7 @@ BYTE rcon_table[10] = { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x
xor_32(&key[12], &key[8], &key[12]);
}
-void SubBytes(BYTE *in, BYTE *out)
+void SubBytes(unsigned char *in, unsigned char *out)
{
int i;
@@ -160,7 +160,7 @@ int i;
}
}
-void ShiftRows(BYTE *in, BYTE *out)
+void ShiftRows(unsigned char *in, unsigned char *out)
{
out[0] = in[0];
out[1] = in[5];
@@ -180,7 +180,7 @@ void ShiftRows(BYTE *in, BYTE *out)
out[15] = in[11];
}
-void MixColumns(BYTE *in, BYTE *out)
+void MixColumns(unsigned char *in, unsigned char *out)
{
out[0] = dot2_table[in[0]] ^ dot3_table[in[1]] ^ in[2] ^ in[3];
@@ -190,13 +190,13 @@ void MixColumns(BYTE *in, BYTE *out)
}
-void AESv128(BYTE *key, BYTE *data, BYTE *ciphertext)
+void AESv128(unsigned char *key, unsigned char *data, unsigned char *ciphertext)
{
int i;
int round;
-BYTE TmpdataA[16];
-BYTE TmpdataB[16];
-BYTE abyRoundKey[16];
+unsigned char TmpdataA[16];
+unsigned char TmpdataB[16];
+unsigned char abyRoundKey[16];
for(i=0; i<16; i++)
abyRoundKey[i] = key[i];
@@ -243,33 +243,33 @@ BYTE abyRoundKey[16];
* Return Value: MIC compare result
*
*/
-BOOL AESbGenCCMP(PBYTE pbyRxKey, PBYTE pbyFrame, WORD wFrameSize)
+bool AESbGenCCMP(unsigned char *pbyRxKey, unsigned char *pbyFrame, unsigned short wFrameSize)
{
-BYTE abyNonce[13];
-BYTE MIC_IV[16];
-BYTE MIC_HDR1[16];
-BYTE MIC_HDR2[16];
-BYTE abyMIC[16];
-BYTE abyCTRPLD[16];
-BYTE abyTmp[16];
-BYTE abyPlainText[16];
-BYTE abyLastCipher[16];
+unsigned char abyNonce[13];
+unsigned char MIC_IV[16];
+unsigned char MIC_HDR1[16];
+unsigned char MIC_HDR2[16];
+unsigned char abyMIC[16];
+unsigned char abyCTRPLD[16];
+unsigned char abyTmp[16];
+unsigned char abyPlainText[16];
+unsigned char abyLastCipher[16];
PS802_11Header pMACHeader = (PS802_11Header) pbyFrame;
-PBYTE pbyIV;
-PBYTE pbyPayload;
-WORD wHLen = 22;
-WORD wPayloadSize = wFrameSize - 8 - 8 - 4 - WLAN_HDR_ADDR3_LEN;//8 is IV, 8 is MIC, 4 is CRC
-BOOL bA4 = FALSE;
-BYTE byTmp;
-WORD wCnt;
+unsigned char *pbyIV;
+unsigned char *pbyPayload;
+unsigned short wHLen = 22;
+unsigned short wPayloadSize = wFrameSize - 8 - 8 - 4 - WLAN_HDR_ADDR3_LEN;//8 is IV, 8 is MIC, 4 is CRC
+bool bA4 = false;
+unsigned char byTmp;
+unsigned short wCnt;
int ii,jj,kk;
pbyIV = pbyFrame + WLAN_HDR_ADDR3_LEN;
- if ( WLAN_GET_FC_TODS(*(PWORD)pbyFrame) &&
- WLAN_GET_FC_FROMDS(*(PWORD)pbyFrame) ) {
- bA4 = TRUE;
+ if ( WLAN_GET_FC_TODS(*(unsigned short *)pbyFrame) &&
+ WLAN_GET_FC_FROMDS(*(unsigned short *)pbyFrame) ) {
+ bA4 = true;
pbyIV += 6; // 6 is 802.11 address4
wHLen += 6;
wPayloadSize -= 6;
@@ -288,15 +288,15 @@ int ii,jj,kk;
//MIC_IV
MIC_IV[0] = 0x59;
memcpy(&(MIC_IV[1]), &(abyNonce[0]), 13);
- MIC_IV[14] = (BYTE)(wPayloadSize >> 8);
- MIC_IV[15] = (BYTE)(wPayloadSize & 0xff);
+ MIC_IV[14] = (unsigned char)(wPayloadSize >> 8);
+ MIC_IV[15] = (unsigned char)(wPayloadSize & 0xff);
//MIC_HDR1
- MIC_HDR1[0] = (BYTE)(wHLen >> 8);
- MIC_HDR1[1] = (BYTE)(wHLen & 0xff);
- byTmp = (BYTE)(pMACHeader->wFrameCtl & 0xff);
+ MIC_HDR1[0] = (unsigned char)(wHLen >> 8);
+ MIC_HDR1[1] = (unsigned char)(wHLen & 0xff);
+ byTmp = (unsigned char)(pMACHeader->wFrameCtl & 0xff);
MIC_HDR1[2] = byTmp & 0x8f;
- byTmp = (BYTE)(pMACHeader->wFrameCtl >> 8);
+ byTmp = (unsigned char)(pMACHeader->wFrameCtl >> 8);
byTmp &= 0x87;
MIC_HDR1[3] = byTmp | 0x40;
memcpy(&(MIC_HDR1[4]), pMACHeader->abyAddr1, ETH_ALEN);
@@ -304,7 +304,7 @@ int ii,jj,kk;
//MIC_HDR2
memcpy(&(MIC_HDR2[0]), pMACHeader->abyAddr3, ETH_ALEN);
- byTmp = (BYTE)(pMACHeader->wSeqCtl & 0xff);
+ byTmp = (unsigned char)(pMACHeader->wSeqCtl & 0xff);
MIC_HDR2[6] = byTmp & 0x0f;
MIC_HDR2[7] = 0;
if ( bA4 ) {
@@ -337,8 +337,8 @@ int ii,jj,kk;
for(jj=wPayloadSize; jj>16; jj=jj-16) {
- abyCTRPLD[14] = (BYTE) (wCnt >> 8);
- abyCTRPLD[15] = (BYTE) (wCnt & 0xff);
+ abyCTRPLD[14] = (unsigned char) (wCnt >> 8);
+ abyCTRPLD[15] = (unsigned char) (wCnt & 0xff);
AESv128(pbyRxKey,abyCTRPLD,abyTmp);
@@ -361,8 +361,8 @@ int ii,jj,kk;
abyLastCipher[ii] = 0x00;
}
- abyCTRPLD[14] = (BYTE) (wCnt >> 8);
- abyCTRPLD[15] = (BYTE) (wCnt & 0xff);
+ abyCTRPLD[14] = (unsigned char) (wCnt >> 8);
+ abyCTRPLD[15] = (unsigned char) (wCnt & 0xff);
AESv128(pbyRxKey,abyCTRPLD,abyTmp);
for ( kk=0; kk<16; kk++ ) {
@@ -384,8 +384,8 @@ int ii,jj,kk;
//--------------------------------------------
wCnt = 0;
- abyCTRPLD[14] = (BYTE) (wCnt >> 8);
- abyCTRPLD[15] = (BYTE) (wCnt & 0xff);
+ abyCTRPLD[14] = (unsigned char) (wCnt >> 8);
+ abyCTRPLD[15] = (unsigned char) (wCnt & 0xff);
AESv128(pbyRxKey,abyCTRPLD,abyTmp);
for ( kk=0; kk<8; kk++ ) {
abyTmp[kk] = abyTmp[kk] ^ pbyPayload[kk];
@@ -394,9 +394,9 @@ int ii,jj,kk;
//--------------------------------------------
if ( !memcmp(abyMIC,abyTmp,8) ) {
- return TRUE;
+ return true;
} else {
- return FALSE;
+ return false;
}
}
diff --git a/drivers/staging/vt6655/aes_ccmp.h b/drivers/staging/vt6655/aes_ccmp.h
index f2ba1d5aa1e..c8b28b0e9bd 100644
--- a/drivers/staging/vt6655/aes_ccmp.h
+++ b/drivers/staging/vt6655/aes_ccmp.h
@@ -41,6 +41,6 @@
/*--------------------- Export Variables --------------------------*/
/*--------------------- Export Functions --------------------------*/
-BOOL AESbGenCCMP(PBYTE pbyRxKey, PBYTE pbyFrame, WORD wFrameSize);
+bool AESbGenCCMP(unsigned char *pbyRxKey, unsigned char *pbyFrame, unsigned short wFrameSize);
#endif //__AES_H__
diff --git a/drivers/staging/vt6655/baseband.c b/drivers/staging/vt6655/baseband.c
index 5414c6c6c05..1e1c6e34f78 100644
--- a/drivers/staging/vt6655/baseband.c
+++ b/drivers/staging/vt6655/baseband.c
@@ -79,7 +79,7 @@ static int msglevel =MSG_LEVEL_INFO;
#define CB_VT3253_INIT_FOR_RFMD 446
-BYTE byVT3253InitTab_RFMD[CB_VT3253_INIT_FOR_RFMD][2] = {
+unsigned char byVT3253InitTab_RFMD[CB_VT3253_INIT_FOR_RFMD][2] = {
{0x00, 0x30},
{0x01, 0x00},
{0x02, 0x00},
@@ -529,7 +529,7 @@ BYTE byVT3253InitTab_RFMD[CB_VT3253_INIT_FOR_RFMD][2] = {
};
#define CB_VT3253B0_INIT_FOR_RFMD 256
-BYTE byVT3253B0_RFMD[CB_VT3253B0_INIT_FOR_RFMD][2] = {
+unsigned char byVT3253B0_RFMD[CB_VT3253B0_INIT_FOR_RFMD][2] = {
{0x00, 0x31},
{0x01, 0x00},
{0x02, 0x00},
@@ -790,7 +790,7 @@ BYTE byVT3253B0_RFMD[CB_VT3253B0_INIT_FOR_RFMD][2] = {
#define CB_VT3253B0_AGC_FOR_RFMD2959 195
// For RFMD2959
-BYTE byVT3253B0_AGC4_RFMD2959[CB_VT3253B0_AGC_FOR_RFMD2959][2] = {
+unsigned char byVT3253B0_AGC4_RFMD2959[CB_VT3253B0_AGC_FOR_RFMD2959][2] = {
{0xF0, 0x00},
{0xF1, 0x3E},
{0xF0, 0x80},
@@ -990,7 +990,7 @@ BYTE byVT3253B0_AGC4_RFMD2959[CB_VT3253B0_AGC_FOR_RFMD2959][2] = {
#define CB_VT3253B0_INIT_FOR_AIROHA2230 256
// For AIROHA
-BYTE byVT3253B0_AIROHA2230[CB_VT3253B0_INIT_FOR_AIROHA2230][2] = {
+unsigned char byVT3253B0_AIROHA2230[CB_VT3253B0_INIT_FOR_AIROHA2230][2] = {
{0x00, 0x31},
{0x01, 0x00},
{0x02, 0x00},
@@ -1254,7 +1254,7 @@ BYTE byVT3253B0_AIROHA2230[CB_VT3253B0_INIT_FOR_AIROHA2230][2] = {
#define CB_VT3253B0_INIT_FOR_UW2451 256
//For UW2451
-BYTE byVT3253B0_UW2451[CB_VT3253B0_INIT_FOR_UW2451][2] = {
+unsigned char byVT3253B0_UW2451[CB_VT3253B0_INIT_FOR_UW2451][2] = {
{0x00, 0x31},
{0x01, 0x00},
{0x02, 0x00},
@@ -1516,7 +1516,7 @@ BYTE byVT3253B0_UW2451[CB_VT3253B0_INIT_FOR_UW2451][2] = {
#define CB_VT3253B0_AGC 193
// For AIROHA
-BYTE byVT3253B0_AGC[CB_VT3253B0_AGC][2] = {
+unsigned char byVT3253B0_AGC[CB_VT3253B0_AGC][2] = {
{0xF0, 0x00},
{0xF1, 0x00},
{0xF0, 0x80},
@@ -1712,14 +1712,14 @@ BYTE byVT3253B0_AGC[CB_VT3253B0_AGC][2] = {
{0xF0, 0x00},
};
-const WORD awcFrameTime[MAX_RATE] =
+const unsigned short awcFrameTime[MAX_RATE] =
{10, 20, 55, 110, 24, 36, 48, 72, 96, 144, 192, 216};
/*--------------------- Static Functions --------------------------*/
static
-ULONG
+unsigned long
s_ulGetRatio(PSDevice pDevice);
static
@@ -1740,13 +1740,13 @@ s_vChangeAntenna (
#endif
if ( pDevice->dwRxAntennaSel == 0) {
pDevice->dwRxAntennaSel=1;
- if (pDevice->bTxRxAntInv == TRUE)
+ if (pDevice->bTxRxAntInv == true)
BBvSetRxAntennaMode(pDevice->PortOffset, ANT_A);
else
BBvSetRxAntennaMode(pDevice->PortOffset, ANT_B);
} else {
pDevice->dwRxAntennaSel=0;
- if (pDevice->bTxRxAntInv == TRUE)
+ if (pDevice->bTxRxAntInv == true)
BBvSetRxAntennaMode(pDevice->PortOffset, ANT_B);
else
BBvSetRxAntennaMode(pDevice->PortOffset, ANT_A);
@@ -1776,19 +1776,19 @@ s_vChangeAntenna (
* Return Value: FrameTime
*
*/
-UINT
+unsigned int
BBuGetFrameTime (
- BYTE byPreambleType,
- BYTE byPktType,
- UINT cbFrameLength,
- WORD wRate
+ unsigned char byPreambleType,
+ unsigned char byPktType,
+ unsigned int cbFrameLength,
+ unsigned short wRate
)
{
- UINT uFrameTime;
- UINT uPreamble;
- UINT uTmp;
- UINT uRateIdx = (UINT)wRate;
- UINT uRate = 0;
+ unsigned int uFrameTime;
+ unsigned int uPreamble;
+ unsigned int uTmp;
+ unsigned int uRateIdx = (unsigned int) wRate;
+ unsigned int uRate = 0;
if (uRateIdx > RATE_54M) {
@@ -1796,7 +1796,7 @@ BBuGetFrameTime (
return 0;
}
- uRate = (UINT)awcFrameTime[uRateIdx];
+ uRate = (unsigned int) awcFrameTime[uRateIdx];
if (uRateIdx <= 3) { //CCK mode
@@ -1846,23 +1846,23 @@ BBuGetFrameTime (
void
BBvCaculateParameter (
PSDevice pDevice,
- UINT cbFrameLength,
- WORD wRate,
- BYTE byPacketType,
- PWORD pwPhyLen,
- PBYTE pbyPhySrv,
- PBYTE pbyPhySgn
+ unsigned int cbFrameLength,
+ unsigned short wRate,
+ unsigned char byPacketType,
+ unsigned short *pwPhyLen,
+ unsigned char *pbyPhySrv,
+ unsigned char *pbyPhySgn
)
{
- UINT cbBitCount;
- UINT cbUsCount = 0;
- UINT cbTmp;
- BOOL bExtBit;
- BYTE byPreambleType = pDevice->byPreambleType;
- BOOL bCCK = pDevice->bCCK;
+ unsigned int cbBitCount;
+ unsigned int cbUsCount = 0;
+ unsigned int cbTmp;
+ bool bExtBit;
+ unsigned char byPreambleType = pDevice->byPreambleType;
+ bool bCCK = pDevice->bCCK;
cbBitCount = cbFrameLength * 8;
- bExtBit = FALSE;
+ bExtBit = false;
switch (wRate) {
case RATE_1M :
@@ -1879,7 +1879,7 @@ BBvCaculateParameter (
break;
case RATE_5M :
- if (bCCK == FALSE)
+ if (bCCK == false)
cbBitCount ++;
cbUsCount = (cbBitCount * 10) / 55;
cbTmp = (cbUsCount * 55) / 10;
@@ -1893,14 +1893,14 @@ BBvCaculateParameter (
case RATE_11M :
- if (bCCK == FALSE)
+ if (bCCK == false)
cbBitCount ++;
cbUsCount = cbBitCount / 11;
cbTmp = cbUsCount * 11;
if (cbTmp != cbBitCount) {
cbUsCount ++;
if ((cbBitCount - cbTmp) <= 3)
- bExtBit = TRUE;
+ bExtBit = true;
}
if (byPreambleType == 1)
*pbyPhySgn = 0x0b;
@@ -1994,11 +1994,11 @@ BBvCaculateParameter (
*pbyPhySrv = 0x00;
if (bExtBit)
*pbyPhySrv = *pbyPhySrv | 0x80;
- *pwPhyLen = (WORD)cbUsCount;
+ *pwPhyLen = (unsigned short)cbUsCount;
}
else {
*pbyPhySrv = 0x00;
- *pwPhyLen = (WORD)cbFrameLength;
+ *pwPhyLen = (unsigned short)cbFrameLength;
}
}
@@ -2012,13 +2012,13 @@ BBvCaculateParameter (
* Out:
* pbyData - data read
*
- * Return Value: TRUE if succeeded; FALSE if failed.
+ * Return Value: true if succeeded; false if failed.
*
*/
-BOOL BBbReadEmbeded (DWORD_PTR dwIoBase, BYTE byBBAddr, PBYTE pbyData)
+bool BBbReadEmbeded (unsigned long dwIoBase, unsigned char byBBAddr, unsigned char *pbyData)
{
- WORD ww;
- BYTE byValue;
+ unsigned short ww;
+ unsigned char byValue;
// BB reg offset
VNSvOutPortB(dwIoBase + MAC_REG_BBREGADR, byBBAddr);
@@ -2038,9 +2038,9 @@ BOOL BBbReadEmbeded (DWORD_PTR dwIoBase, BYTE byBBAddr, PBYTE pbyData)
if (ww == W_MAX_TIMEOUT) {
DBG_PORT80(0x30);
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO" DBG_PORT80(0x30)\n");
- return FALSE;
+ return false;
}
- return TRUE;
+ return true;
}
@@ -2055,13 +2055,13 @@ BOOL BBbReadEmbeded (DWORD_PTR dwIoBase, BYTE byBBAddr, PBYTE pbyData)
* Out:
* none
*
- * Return Value: TRUE if succeeded; FALSE if failed.
+ * Return Value: true if succeeded; false if failed.
*
*/
-BOOL BBbWriteEmbeded (DWORD_PTR dwIoBase, BYTE byBBAddr, BYTE byData)
+bool BBbWriteEmbeded (unsigned long dwIoBase, unsigned char byBBAddr, unsigned char byData)
{
- WORD ww;
- BYTE byValue;
+ unsigned short ww;
+ unsigned char byValue;
// BB reg offset
VNSvOutPortB(dwIoBase + MAC_REG_BBREGADR, byBBAddr);
@@ -2080,9 +2080,9 @@ BOOL BBbWriteEmbeded (DWORD_PTR dwIoBase, BYTE byBBAddr, BYTE byData)
if (ww == W_MAX_TIMEOUT) {
DBG_PORT80(0x31);
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO" DBG_PORT80(0x31)\n");
- return FALSE;
+ return false;
}
- return TRUE;
+ return true;
}
@@ -2097,12 +2097,12 @@ BOOL BBbWriteEmbeded (DWORD_PTR dwIoBase, BYTE byBBAddr, BYTE byData)
* Out:
* none
*
- * Return Value: TRUE if all TestBits are set; FALSE otherwise.
+ * Return Value: true if all TestBits are set; false otherwise.
*
*/
-BOOL BBbIsRegBitsOn (DWORD_PTR dwIoBase, BYTE byBBAddr, BYTE byTestBits)
+bool BBbIsRegBitsOn (unsigned long dwIoBase, unsigned char byBBAddr, unsigned char byTestBits)
{
- BYTE byOrgData;
+ unsigned char byOrgData;
BBbReadEmbeded(dwIoBase, byBBAddr, &byOrgData);
return (byOrgData & byTestBits) == byTestBits;
@@ -2120,12 +2120,12 @@ BOOL BBbIsRegBitsOn (DWORD_PTR dwIoBase, BYTE byBBAddr, BYTE byTestBits)
* Out:
* none
*
- * Return Value: TRUE if all TestBits are clear; FALSE otherwise.
+ * Return Value: true if all TestBits are clear; false otherwise.
*
*/
-BOOL BBbIsRegBitsOff (DWORD_PTR dwIoBase, BYTE byBBAddr, BYTE byTestBits)
+bool BBbIsRegBitsOff (unsigned long dwIoBase, unsigned char byBBAddr, unsigned char byTestBits)
{
- BYTE byOrgData;
+ unsigned char byOrgData;
BBbReadEmbeded(dwIoBase, byBBAddr, &byOrgData);
return (byOrgData & byTestBits) == 0;
@@ -2142,17 +2142,17 @@ BOOL BBbIsRegBitsOff (DWORD_PTR dwIoBase, BYTE byBBAddr, BYTE byTestBits)
* Out:
* none
*
- * Return Value: TRUE if succeeded; FALSE if failed.
+ * Return Value: true if succeeded; false if failed.
*
*/
-BOOL BBbVT3253Init (PSDevice pDevice)
+bool BBbVT3253Init (PSDevice pDevice)
{
- BOOL bResult = TRUE;
+ bool bResult = true;
int ii;
- DWORD_PTR dwIoBase = pDevice->PortOffset;
- BYTE byRFType = pDevice->byRFType;
- BYTE byLocalID = pDevice->byLocalID;
+ unsigned long dwIoBase = pDevice->PortOffset;
+ unsigned char byRFType = pDevice->byRFType;
+ unsigned char byLocalID = pDevice->byLocalID;
if (byRFType == RF_RFMD2959) {
if (byLocalID <= REV_ID_VT3253_A1) {
@@ -2294,7 +2294,7 @@ BOOL BBbVT3253Init (PSDevice pDevice)
//}} RobertYu
} else {
// No VGA Table now
- pDevice->bUpdateBBVGA = FALSE;
+ pDevice->bUpdateBBVGA = false;
pDevice->abyBBVGA[0] = 0x1C;
}
@@ -2321,12 +2321,12 @@ BOOL BBbVT3253Init (PSDevice pDevice)
* Return Value: none
*
*/
-void BBvReadAllRegs (DWORD_PTR dwIoBase, PBYTE pbyBBRegs)
+void BBvReadAllRegs (unsigned long dwIoBase, unsigned char *pbyBBRegs)
{
int ii;
- BYTE byBase = 1;
+ unsigned char byBase = 1;
for (ii = 0; ii < BB_MAX_CONTEXT_SIZE; ii++) {
- BBbReadEmbeded(dwIoBase, (BYTE)(ii*byBase), pbyBBRegs);
+ BBbReadEmbeded(dwIoBase, (unsigned char)(ii*byBase), pbyBBRegs);
pbyBBRegs += byBase;
}
}
@@ -2348,8 +2348,8 @@ void BBvReadAllRegs (DWORD_PTR dwIoBase, PBYTE pbyBBRegs)
void BBvLoopbackOn (PSDevice pDevice)
{
- BYTE byData;
- DWORD_PTR dwIoBase = pDevice->PortOffset;
+ unsigned char byData;
+ unsigned long dwIoBase = pDevice->PortOffset;
//CR C9 = 0x00
BBbReadEmbeded(dwIoBase, 0xC9, &pDevice->byBBCRc9);//CR201
@@ -2363,7 +2363,7 @@ void BBvLoopbackOn (PSDevice pDevice)
if (pDevice->uConnectionRate <= RATE_11M) { //CCK
// Enable internal digital loopback: CR33 |= 0000 0001
BBbReadEmbeded(dwIoBase, 0x21, &byData);//CR33
- BBbWriteEmbeded(dwIoBase, 0x21, (BYTE)(byData | 0x01));//CR33
+ BBbWriteEmbeded(dwIoBase, 0x21, (unsigned char)(byData | 0x01));//CR33
// CR154 = 0x00
BBbWriteEmbeded(dwIoBase, 0x9A, 0); //CR154
@@ -2372,7 +2372,7 @@ void BBvLoopbackOn (PSDevice pDevice)
else { //OFDM
// Enable internal digital loopback:CR154 |= 0000 0001
BBbReadEmbeded(dwIoBase, 0x9A, &byData);//CR154
- BBbWriteEmbeded(dwIoBase, 0x9A, (BYTE)(byData | 0x01));//CR154
+ BBbWriteEmbeded(dwIoBase, 0x9A, (unsigned char)(byData | 0x01));//CR154
// CR33 = 0x00
BBbWriteEmbeded(dwIoBase, 0x21, 0); //CR33
@@ -2384,7 +2384,7 @@ void BBvLoopbackOn (PSDevice pDevice)
// Disable TX_IQUN
BBbReadEmbeded(pDevice->PortOffset, 0x09, &pDevice->byBBCR09);
- BBbWriteEmbeded(pDevice->PortOffset, 0x09, (BYTE)(pDevice->byBBCR09 & 0xDE));
+ BBbWriteEmbeded(pDevice->PortOffset, 0x09, (unsigned char)(pDevice->byBBCR09 & 0xDE));
}
/*
@@ -2402,8 +2402,8 @@ void BBvLoopbackOn (PSDevice pDevice)
*/
void BBvLoopbackOff (PSDevice pDevice)
{
- BYTE byData;
- DWORD_PTR dwIoBase = pDevice->PortOffset;
+ unsigned char byData;
+ unsigned long dwIoBase = pDevice->PortOffset;
BBbWriteEmbeded(dwIoBase, 0xC9, pDevice->byBBCRc9);//CR201
BBbWriteEmbeded(dwIoBase, 0x88, pDevice->byBBCR88);//CR136
@@ -2413,14 +2413,14 @@ void BBvLoopbackOff (PSDevice pDevice)
if (pDevice->uConnectionRate <= RATE_11M) { // CCK
// Set the CR33 Bit2 to disable internal Loopback.
BBbReadEmbeded(dwIoBase, 0x21, &byData);//CR33
- BBbWriteEmbeded(dwIoBase, 0x21, (BYTE)(byData & 0xFE));//CR33
+ BBbWriteEmbeded(dwIoBase, 0x21, (unsigned char)(byData & 0xFE));//CR33
}
else { // OFDM
BBbReadEmbeded(dwIoBase, 0x9A, &byData);//CR154
- BBbWriteEmbeded(dwIoBase, 0x9A, (BYTE)(byData & 0xFE));//CR154
+ BBbWriteEmbeded(dwIoBase, 0x9A, (unsigned char)(byData & 0xFE));//CR154
}
BBbReadEmbeded(dwIoBase, 0x0E, &byData);//CR14
- BBbWriteEmbeded(dwIoBase, 0x0E, (BYTE)(byData | 0x80));//CR14
+ BBbWriteEmbeded(dwIoBase, 0x0E, (unsigned char)(byData | 0x80));//CR14
}
@@ -2441,8 +2441,8 @@ void BBvLoopbackOff (PSDevice pDevice)
void
BBvSetShortSlotTime (PSDevice pDevice)
{
- BYTE byBBRxConf=0;
- BYTE byBBVGA=0;
+ unsigned char byBBRxConf=0;
+ unsigned char byBBVGA=0;
BBbReadEmbeded(pDevice->PortOffset, 0x0A, &byBBRxConf);//CR10
@@ -2462,9 +2462,9 @@ BBvSetShortSlotTime (PSDevice pDevice)
}
-void BBvSetVGAGainOffset(PSDevice pDevice, BYTE byData)
+void BBvSetVGAGainOffset(PSDevice pDevice, unsigned char byData)
{
- BYTE byBBRxConf=0;
+ unsigned char byBBRxConf=0;
BBbWriteEmbeded(pDevice->PortOffset, 0xE7, byData);
@@ -2495,7 +2495,7 @@ void BBvSetVGAGainOffset(PSDevice pDevice, BYTE byData)
*
*/
void
-BBvSoftwareReset (DWORD_PTR dwIoBase)
+BBvSoftwareReset (unsigned long dwIoBase)
{
BBbWriteEmbeded(dwIoBase, 0x50, 0x40);
BBbWriteEmbeded(dwIoBase, 0x50, 0);
@@ -2516,9 +2516,9 @@ BBvSoftwareReset (DWORD_PTR dwIoBase)
*
*/
void
-BBvPowerSaveModeON (DWORD_PTR dwIoBase)
+BBvPowerSaveModeON (unsigned long dwIoBase)
{
- BYTE byOrgData;
+ unsigned char byOrgData;
BBbReadEmbeded(dwIoBase, 0x0D, &byOrgData);
byOrgData |= BIT0;
@@ -2538,9 +2538,9 @@ BBvPowerSaveModeON (DWORD_PTR dwIoBase)
*
*/
void
-BBvPowerSaveModeOFF (DWORD_PTR dwIoBase)
+BBvPowerSaveModeOFF (unsigned long dwIoBase)
{
- BYTE byOrgData;
+ unsigned char byOrgData;
BBbReadEmbeded(dwIoBase, 0x0D, &byOrgData);
byOrgData &= ~(BIT0);
@@ -2562,9 +2562,9 @@ BBvPowerSaveModeOFF (DWORD_PTR dwIoBase)
*/
void
-BBvSetTxAntennaMode (DWORD_PTR dwIoBase, BYTE byAntennaMode)
+BBvSetTxAntennaMode (unsigned long dwIoBase, unsigned char byAntennaMode)
{
- BYTE byBBTxConf;
+ unsigned char byBBTxConf;
#ifdef PLICE_DEBUG
//printk("Enter BBvSetTxAntennaMode\n");
@@ -2604,9 +2604,9 @@ BBvSetTxAntennaMode (DWORD_PTR dwIoBase, BYTE byAntennaMode)
*/
void
-BBvSetRxAntennaMode (DWORD_PTR dwIoBase, BYTE byAntennaMode)
+BBvSetRxAntennaMode (unsigned long dwIoBase, unsigned char byAntennaMode)
{
- BYTE byBBRxConf;
+ unsigned char byBBRxConf;
BBbReadEmbeded(dwIoBase, 0x0A, &byBBRxConf);//CR10
if (byAntennaMode == ANT_DIVERSITY) {
@@ -2635,14 +2635,14 @@ BBvSetRxAntennaMode (DWORD_PTR dwIoBase, BYTE byAntennaMode)
*
*/
void
-BBvSetDeepSleep (DWORD_PTR dwIoBase, BYTE byLocalID)
+BBvSetDeepSleep (unsigned long dwIoBase, unsigned char byLocalID)
{
BBbWriteEmbeded(dwIoBase, 0x0C, 0x17);//CR12
BBbWriteEmbeded(dwIoBase, 0x0D, 0xB9);//CR13
}
void
-BBvExitDeepSleep (DWORD_PTR dwIoBase, BYTE byLocalID)
+BBvExitDeepSleep (unsigned long dwIoBase, unsigned char byLocalID)
{
BBbWriteEmbeded(dwIoBase, 0x0C, 0x00);//CR12
BBbWriteEmbeded(dwIoBase, 0x0D, 0x01);//CR13
@@ -2651,12 +2651,12 @@ BBvExitDeepSleep (DWORD_PTR dwIoBase, BYTE byLocalID)
static
-ULONG
+unsigned long
s_ulGetRatio (PSDevice pDevice)
{
-ULONG ulRatio = 0;
-ULONG ulMaxPacket;
-ULONG ulPacketNum;
+unsigned long ulRatio = 0;
+unsigned long ulMaxPacket;
+unsigned long ulPacketNum;
//This is a thousand-ratio
ulMaxPacket = pDevice->uNumSQ3[RATE_54M];
@@ -2762,7 +2762,7 @@ ULONG ulPacketNum;
void
BBvClearAntDivSQ3Value (PSDevice pDevice)
{
- UINT ii;
+ unsigned int ii;
pDevice->uDiversityCnt = 0;
for (ii = 0; ii < MAX_RATE; ii++) {
@@ -2787,7 +2787,7 @@ BBvClearAntDivSQ3Value (PSDevice pDevice)
*/
void
-BBvAntennaDiversity (PSDevice pDevice, BYTE byRxRate, BYTE bySQ3)
+BBvAntennaDiversity (PSDevice pDevice, unsigned char byRxRate, unsigned char bySQ3)
{
if ((byRxRate >= MAX_RATE) || (pDevice->wAntDiversityMaxRate >= MAX_RATE)) {
diff --git a/drivers/staging/vt6655/baseband.h b/drivers/staging/vt6655/baseband.h
index b236ff4139a..8294bdbb7b5 100644
--- a/drivers/staging/vt6655/baseband.h
+++ b/drivers/staging/vt6655/baseband.h
@@ -118,45 +118,45 @@
/*--------------------- Export Functions --------------------------*/
-UINT
+unsigned int
BBuGetFrameTime(
- BYTE byPreambleType,
- BYTE byPktType,
- UINT cbFrameLength,
- WORD wRate
+ unsigned char byPreambleType,
+ unsigned char byPktType,
+ unsigned int cbFrameLength,
+ unsigned short wRate
);
void
BBvCaculateParameter (
PSDevice pDevice,
- UINT cbFrameLength,
- WORD wRate,
- BYTE byPacketType,
- PWORD pwPhyLen,
- PBYTE pbyPhySrv,
- PBYTE pbyPhySgn
+ unsigned int cbFrameLength,
+ unsigned short wRate,
+ unsigned char byPacketType,
+ unsigned short *pwPhyLen,
+ unsigned char *pbyPhySrv,
+ unsigned char *pbyPhySgn
);
-BOOL BBbReadEmbeded(DWORD_PTR dwIoBase, BYTE byBBAddr, PBYTE pbyData);
-BOOL BBbWriteEmbeded(DWORD_PTR dwIoBase, BYTE byBBAddr, BYTE byData);
+bool BBbReadEmbeded(unsigned long dwIoBase, unsigned char byBBAddr, unsigned char *pbyData);
+bool BBbWriteEmbeded(unsigned long dwIoBase, unsigned char byBBAddr, unsigned char byData);
-void BBvReadAllRegs(DWORD_PTR dwIoBase, PBYTE pbyBBRegs);
+void BBvReadAllRegs(unsigned long dwIoBase, unsigned char *pbyBBRegs);
void BBvLoopbackOn(PSDevice pDevice);
void BBvLoopbackOff(PSDevice pDevice);
void BBvSetShortSlotTime(PSDevice pDevice);
-BOOL BBbIsRegBitsOn(DWORD_PTR dwIoBase, BYTE byBBAddr, BYTE byTestBits);
-BOOL BBbIsRegBitsOff(DWORD_PTR dwIoBase, BYTE byBBAddr, BYTE byTestBits);
-void BBvSetVGAGainOffset(PSDevice pDevice, BYTE byData);
+bool BBbIsRegBitsOn(unsigned long dwIoBase, unsigned char byBBAddr, unsigned char byTestBits);
+bool BBbIsRegBitsOff(unsigned long dwIoBase, unsigned char byBBAddr, unsigned char byTestBits);
+void BBvSetVGAGainOffset(PSDevice pDevice, unsigned char byData);
// VT3253 Baseband
-BOOL BBbVT3253Init(PSDevice pDevice);
-void BBvSoftwareReset(DWORD_PTR dwIoBase);
-void BBvPowerSaveModeON(DWORD_PTR dwIoBase);
-void BBvPowerSaveModeOFF(DWORD_PTR dwIoBase);
-void BBvSetTxAntennaMode(DWORD_PTR dwIoBase, BYTE byAntennaMode);
-void BBvSetRxAntennaMode(DWORD_PTR dwIoBase, BYTE byAntennaMode);
-void BBvSetDeepSleep(DWORD_PTR dwIoBase, BYTE byLocalID);
-void BBvExitDeepSleep(DWORD_PTR dwIoBase, BYTE byLocalID);
+bool BBbVT3253Init(PSDevice pDevice);
+void BBvSoftwareReset(unsigned long dwIoBase);
+void BBvPowerSaveModeON(unsigned long dwIoBase);
+void BBvPowerSaveModeOFF(unsigned long dwIoBase);
+void BBvSetTxAntennaMode(unsigned long dwIoBase, unsigned char byAntennaMode);
+void BBvSetRxAntennaMode(unsigned long dwIoBase, unsigned char byAntennaMode);
+void BBvSetDeepSleep(unsigned long dwIoBase, unsigned char byLocalID);
+void BBvExitDeepSleep(unsigned long dwIoBase, unsigned char byLocalID);
// timer for antenna diversity
@@ -170,7 +170,7 @@ TimerState1CallBack(
void *hDeviceContext
);
-void BBvAntennaDiversity(PSDevice pDevice, BYTE byRxRate, BYTE bySQ3);
+void BBvAntennaDiversity(PSDevice pDevice, unsigned char byRxRate, unsigned char bySQ3);
void
BBvClearAntDivSQ3Value (PSDevice pDevice);
diff --git a/drivers/staging/vt6655/bssdb.c b/drivers/staging/vt6655/bssdb.c
index 6312a55dab1..57c1cc90afc 100644
--- a/drivers/staging/vt6655/bssdb.c
+++ b/drivers/staging/vt6655/bssdb.c
@@ -53,6 +53,7 @@
#include "baseband.h"
#include "rf.h"
#include "card.h"
+#include "channel.h"
#include "mac.h"
#include "wpa2.h"
#include "iowpa.h"
@@ -71,14 +72,14 @@ static int msglevel =MSG_LEVEL_INFO;
-const WORD awHWRetry0[5][5] = {
+const unsigned short awHWRetry0[5][5] = {
{RATE_18M, RATE_18M, RATE_12M, RATE_12M, RATE_12M},
{RATE_24M, RATE_24M, RATE_18M, RATE_12M, RATE_12M},
{RATE_36M, RATE_36M, RATE_24M, RATE_18M, RATE_18M},
{RATE_48M, RATE_48M, RATE_36M, RATE_24M, RATE_24M},
{RATE_54M, RATE_54M, RATE_48M, RATE_36M, RATE_36M}
};
-const WORD awHWRetry1[5][5] = {
+const unsigned short awHWRetry1[5][5] = {
{RATE_18M, RATE_18M, RATE_12M, RATE_6M, RATE_6M},
{RATE_24M, RATE_24M, RATE_18M, RATE_6M, RATE_6M},
{RATE_36M, RATE_36M, RATE_24M, RATE_12M, RATE_12M},
@@ -126,25 +127,25 @@ void s_vCheckPreEDThreshold(
PKnownBSS
BSSpSearchBSSList(
void *hDeviceContext,
- PBYTE pbyDesireBSSID,
- PBYTE pbyDesireSSID,
+ unsigned char *pbyDesireBSSID,
+ unsigned char *pbyDesireSSID,
CARD_PHY_TYPE ePhyType
)
{
PSDevice pDevice = (PSDevice)hDeviceContext;
PSMgmtObject pMgmt = pDevice->pMgmt;
- PBYTE pbyBSSID = NULL;
+ unsigned char *pbyBSSID = NULL;
PWLAN_IE_SSID pSSID = NULL;
PKnownBSS pCurrBSS = NULL;
PKnownBSS pSelect = NULL;
-BYTE ZeroBSSID[WLAN_BSSID_LEN]={0x00,0x00,0x00,0x00,0x00,0x00};
- UINT ii = 0;
-// UINT jj = 0; //DavidWang
+ unsigned char ZeroBSSID[WLAN_BSSID_LEN]={0x00,0x00,0x00,0x00,0x00,0x00};
+ unsigned int ii = 0;
+
if (pbyDesireBSSID != NULL) {
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"BSSpSearchBSSList BSSID[%02X %02X %02X-%02X %02X %02X]\n",
*pbyDesireBSSID,*(pbyDesireBSSID+1),*(pbyDesireBSSID+2),
*(pbyDesireBSSID+3),*(pbyDesireBSSID+4),*(pbyDesireBSSID+5));
- if ((!IS_BROADCAST_ADDRESS(pbyDesireBSSID)) &&
+ if ((!is_broadcast_ether_addr(pbyDesireBSSID)) &&
(memcmp(pbyDesireBSSID, ZeroBSSID, 6)!= 0)){
pbyBSSID = pbyDesireBSSID;
}
@@ -159,10 +160,10 @@ BYTE ZeroBSSID[WLAN_BSSID_LEN]={0x00,0x00,0x00,0x00,0x00,0x00};
// match BSSID first
for (ii = 0; ii <MAX_BSS_NUM; ii++) {
pCurrBSS = &(pMgmt->sBSSList[ii]);
-if(pDevice->bLinkPass==FALSE) pCurrBSS->bSelected = FALSE;
+if(pDevice->bLinkPass==false) pCurrBSS->bSelected = false;
if ((pCurrBSS->bActive) &&
- (pCurrBSS->bSelected == FALSE)) {
- if (IS_ETH_ADDRESS_EQUAL(pCurrBSS->abyBSSID, pbyBSSID)) {
+ (pCurrBSS->bSelected == false)) {
+ if (!compare_ether_addr(pCurrBSS->abyBSSID, pbyBSSID)) {
if (pSSID != NULL) {
// compare ssid
if ( !memcmp(pSSID->abySSID,
@@ -172,7 +173,7 @@ if(pDevice->bLinkPass==FALSE) pCurrBSS->bSelected = FALSE;
((pMgmt->eConfigMode == WMAC_CONFIG_IBSS_STA) && WLAN_GET_CAP_INFO_IBSS(pCurrBSS->wCapInfo)) ||
((pMgmt->eConfigMode == WMAC_CONFIG_ESS_STA) && WLAN_GET_CAP_INFO_ESS(pCurrBSS->wCapInfo))
) {
- pCurrBSS->bSelected = TRUE;
+ pCurrBSS->bSelected = true;
return(pCurrBSS);
}
}
@@ -181,7 +182,7 @@ if(pDevice->bLinkPass==FALSE) pCurrBSS->bSelected = FALSE;
((pMgmt->eConfigMode == WMAC_CONFIG_IBSS_STA) && WLAN_GET_CAP_INFO_IBSS(pCurrBSS->wCapInfo)) ||
((pMgmt->eConfigMode == WMAC_CONFIG_ESS_STA) && WLAN_GET_CAP_INFO_ESS(pCurrBSS->wCapInfo))
) {
- pCurrBSS->bSelected = TRUE;
+ pCurrBSS->bSelected = true;
return(pCurrBSS);
}
}
@@ -193,7 +194,7 @@ if(pDevice->bLinkPass==FALSE) pCurrBSS->bSelected = FALSE;
for (ii = 0; ii <MAX_BSS_NUM; ii++) {
pCurrBSS = &(pMgmt->sBSSList[ii]);
//2007-0721-01<Add>by MikeLiu
- pCurrBSS->bSelected = FALSE;
+ pCurrBSS->bSelected = false;
if (pCurrBSS->bActive) {
if (pSSID != NULL) {
@@ -224,19 +225,19 @@ if(pDevice->bLinkPass==FALSE) pCurrBSS->bSelected = FALSE;
}
/*
if (pMgmt->eAuthenMode < WMAC_AUTH_WPA) {
- if (pCurrBSS->bWPAValid == TRUE) {
+ if (pCurrBSS->bWPAValid == true) {
// WPA AP will reject connection of station without WPA enable.
continue;
}
} else if ((pMgmt->eAuthenMode == WMAC_AUTH_WPA) ||
(pMgmt->eAuthenMode == WMAC_AUTH_WPAPSK)) {
- if (pCurrBSS->bWPAValid == FALSE) {
+ if (pCurrBSS->bWPAValid == false) {
// station with WPA enable can't join NonWPA AP.
continue;
}
} else if ((pMgmt->eAuthenMode == WMAC_AUTH_WPA2) ||
(pMgmt->eAuthenMode == WMAC_AUTH_WPA2PSK)) {
- if (pCurrBSS->bWPA2Valid == FALSE) {
+ if (pCurrBSS->bWPA2Valid == false) {
// station with WPA2 enable can't join NonWPA2 AP.
continue;
}
@@ -253,9 +254,9 @@ if(pDevice->bLinkPass==FALSE) pCurrBSS->bSelected = FALSE;
}
}
if (pSelect != NULL) {
- pSelect->bSelected = TRUE;
+ pSelect->bSelected = true;
/*
- if (pDevice->bRoaming == FALSE) {
+ if (pDevice->bRoaming == false) {
// Einsn Add @20070907
memset(pbyDesireSSID, 0, WLAN_IEHDR_LEN + WLAN_SSID_MAXLEN + 1);
memcpy(pbyDesireSSID,pCurrBSS->abySSID,WLAN_IEHDR_LEN + WLAN_SSID_MAXLEN + 1) ;
@@ -283,18 +284,18 @@ if(pDevice->bLinkPass==FALSE) pCurrBSS->bSelected = FALSE;
void
BSSvClearBSSList(
void *hDeviceContext,
- BOOL bKeepCurrBSSID
+ bool bKeepCurrBSSID
)
{
PSDevice pDevice = (PSDevice)hDeviceContext;
PSMgmtObject pMgmt = pDevice->pMgmt;
- UINT ii;
+ unsigned int ii;
for (ii = 0; ii < MAX_BSS_NUM; ii++) {
if (bKeepCurrBSSID) {
if (pMgmt->sBSSList[ii].bActive &&
- IS_ETH_ADDRESS_EQUAL(pMgmt->sBSSList[ii].abyBSSID, pMgmt->abyCurrBSSID)) {
- // bKeepCurrBSSID = FALSE;
+ !compare_ether_addr(pMgmt->sBSSList[ii].abyBSSID, pMgmt->abyCurrBSSID)) {
+ // bKeepCurrBSSID = false;
continue;
}
}
@@ -304,7 +305,7 @@ BSSvClearBSSList(
continue;
}
- pMgmt->sBSSList[ii].bActive = FALSE;
+ pMgmt->sBSSList[ii].bActive = false;
memset(&pMgmt->sBSSList[ii], 0, sizeof(KnownBSS));
}
BSSvClearAnyBSSJoinRecord(pDevice);
@@ -320,25 +321,25 @@ BSSvClearBSSList(
* search BSS list by BSSID & SSID if matched
*
* Return Value:
- * TRUE if found.
+ * true if found.
*
-*/
PKnownBSS
BSSpAddrIsInBSSList(
void *hDeviceContext,
- PBYTE abyBSSID,
+ unsigned char *abyBSSID,
PWLAN_IE_SSID pSSID
)
{
PSDevice pDevice = (PSDevice)hDeviceContext;
PSMgmtObject pMgmt = pDevice->pMgmt;
PKnownBSS pBSSList = NULL;
- UINT ii;
+ unsigned int ii;
for (ii = 0; ii < MAX_BSS_NUM; ii++) {
pBSSList = &(pMgmt->sBSSList[ii]);
if (pBSSList->bActive) {
- if (IS_ETH_ADDRESS_EQUAL(pBSSList->abyBSSID, abyBSSID)) {
+ if (!compare_ether_addr(pBSSList->abyBSSID, abyBSSID)) {
// if (pSSID == NULL)
// return pBSSList;
if (pSSID->len == ((PWLAN_IE_SSID)pBSSList->abySSID)->len){
@@ -362,18 +363,18 @@ BSSpAddrIsInBSSList(
* Insert a BSS set into known BSS list
*
* Return Value:
- * TRUE if success.
+ * true if success.
*
-*/
-BOOL
+bool
BSSbInsertToBSSList (
void *hDeviceContext,
- PBYTE abyBSSIDAddr,
+ unsigned char *abyBSSIDAddr,
QWORD qwTimestamp,
- WORD wBeaconInterval,
- WORD wCapInfo,
- BYTE byCurrChannel,
+ unsigned short wBeaconInterval,
+ unsigned short wCapInfo,
+ unsigned char byCurrChannel,
PWLAN_IE_SSID pSSID,
PWLAN_IE_SUPP_RATES pSuppRates,
PWLAN_IE_SUPP_RATES pExtSuppRates,
@@ -382,8 +383,8 @@ BSSbInsertToBSSList (
PWLAN_IE_RSN_EXT pRSNWPA,
PWLAN_IE_COUNTRY pIE_Country,
PWLAN_IE_QUIET pIE_Quiet,
- UINT uIELength,
- PBYTE pbyIEs,
+ unsigned int uIELength,
+ unsigned char *pbyIEs,
void *pRxPacketContext
)
{
@@ -392,8 +393,8 @@ BSSbInsertToBSSList (
PSMgmtObject pMgmt = pDevice->pMgmt;
PSRxMgmtPacket pRxPacket = (PSRxMgmtPacket)pRxPacketContext;
PKnownBSS pBSSList = NULL;
- UINT ii;
- BOOL bParsingQuiet = FALSE;
+ unsigned int ii;
+ bool bParsingQuiet = false;
PWLAN_IE_QUIET pQuiet = NULL;
@@ -408,10 +409,10 @@ BSSbInsertToBSSList (
if (ii == MAX_BSS_NUM){
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Get free KnowBSS node failed.\n");
- return FALSE;
+ return false;
}
// save the BSS info
- pBSSList->bActive = TRUE;
+ pBSSList->bActive = true;
memcpy( pBSSList->abyBSSID, abyBSSIDAddr, WLAN_BSSID_LEN);
HIDWORD(pBSSList->qwBSSTimestamp) = cpu_to_le32(HIDWORD(qwTimestamp));
LODWORD(pBSSList->qwBSSTimestamp) = cpu_to_le32(LODWORD(qwTimestamp));
@@ -445,7 +446,7 @@ BSSbInsertToBSSList (
if (pBSSList->uChannel > CB_MAX_CHANNEL_24G) {
pBSSList->eNetworkTypeInUse = PHY_TYPE_11A;
} else {
- if (pBSSList->sERP.bERPExist == TRUE) {
+ if (pBSSList->sERP.bERPExist == true) {
pBSSList->eNetworkTypeInUse = PHY_TYPE_11G;
} else {
pBSSList->eNetworkTypeInUse = PHY_TYPE_11B;
@@ -461,16 +462,16 @@ BSSbInsertToBSSList (
(pMgmt->eCurrState == WMAC_STATE_ASSOC)) {
// assoc with BSS
if (pBSSList == pMgmt->pCurrBSS) {
- bParsingQuiet = TRUE;
+ bParsingQuiet = true;
}
}
WPA_ClearRSN(pBSSList);
if (pRSNWPA != NULL) {
- UINT uLen = pRSNWPA->len + 2;
+ unsigned int uLen = pRSNWPA->len + 2;
- if (uLen <= (uIELength - (UINT)(ULONG_PTR)((PBYTE)pRSNWPA - pbyIEs))) {
+ if (uLen <= (uIELength - (unsigned int)((unsigned char *)pRSNWPA - pbyIEs))) {
pBSSList->wWPALen = uLen;
memcpy(pBSSList->byWPAIE, pRSNWPA, uLen);
WPA_ParseRSN(pBSSList, pRSNWPA);
@@ -480,33 +481,33 @@ BSSbInsertToBSSList (
WPA2_ClearRSN(pBSSList);
if (pRSN != NULL) {
- UINT uLen = pRSN->len + 2;
- if (uLen <= (uIELength - (UINT)(ULONG_PTR)((PBYTE)pRSN - pbyIEs))) {
+ unsigned int uLen = pRSN->len + 2;
+ if (uLen <= (uIELength - (unsigned int)((unsigned char *)pRSN - pbyIEs))) {
pBSSList->wRSNLen = uLen;
memcpy(pBSSList->byRSNIE, pRSN, uLen);
WPA2vParseRSN(pBSSList, pRSN);
}
}
- if ((pMgmt->eAuthenMode == WMAC_AUTH_WPA2) || (pBSSList->bWPA2Valid == TRUE)) {
+ if ((pMgmt->eAuthenMode == WMAC_AUTH_WPA2) || (pBSSList->bWPA2Valid == true)) {
PSKeyItem pTransmitKey = NULL;
- BOOL bIs802_1x = FALSE;
+ bool bIs802_1x = false;
for (ii = 0; ii < pBSSList->wAKMSSAuthCount; ii ++) {
if (pBSSList->abyAKMSSAuthType[ii] == WLAN_11i_AKMSS_802_1X) {
- bIs802_1x = TRUE;
+ bIs802_1x = true;
break;
}
}
- if ((bIs802_1x == TRUE) && (pSSID->len == ((PWLAN_IE_SSID)pMgmt->abyDesireSSID)->len) &&
+ if ((bIs802_1x == true) && (pSSID->len == ((PWLAN_IE_SSID)pMgmt->abyDesireSSID)->len) &&
( !memcmp(pSSID->abySSID, ((PWLAN_IE_SSID)pMgmt->abyDesireSSID)->abySSID, pSSID->len))) {
bAdd_PMKID_Candidate((void *)pDevice, pBSSList->abyBSSID, &pBSSList->sRSNCapObj);
- if ((pDevice->bLinkPass == TRUE) && (pMgmt->eCurrState == WMAC_STATE_ASSOC)) {
- if ((KeybGetTransmitKey(&(pDevice->sKey), pDevice->abyBSSID, PAIRWISE_KEY, &pTransmitKey) == TRUE) ||
- (KeybGetTransmitKey(&(pDevice->sKey), pDevice->abyBSSID, GROUP_KEY, &pTransmitKey) == TRUE)) {
+ if ((pDevice->bLinkPass == true) && (pMgmt->eCurrState == WMAC_STATE_ASSOC)) {
+ if ((KeybGetTransmitKey(&(pDevice->sKey), pDevice->abyBSSID, PAIRWISE_KEY, &pTransmitKey) == true) ||
+ (KeybGetTransmitKey(&(pDevice->sKey), pDevice->abyBSSID, GROUP_KEY, &pTransmitKey) == true)) {
pDevice->gsPMKIDCandidate.StatusType = Ndis802_11StatusType_PMKID_CandidateList;
pDevice->gsPMKIDCandidate.Version = 1;
@@ -519,46 +520,45 @@ BSSbInsertToBSSList (
if (pDevice->bUpdateBBVGA) {
// Moniter if RSSI is too strong.
pBSSList->byRSSIStatCnt = 0;
- RFvRSSITodBm(pDevice, (BYTE)(pRxPacket->uRSSI), &pBSSList->ldBmMAX);
+ RFvRSSITodBm(pDevice, (unsigned char)(pRxPacket->uRSSI), &pBSSList->ldBmMAX);
pBSSList->ldBmAverage[0] = pBSSList->ldBmMAX;
for (ii = 1; ii < RSSI_STAT_COUNT; ii++)
pBSSList->ldBmAverage[ii] = 0;
}
if ((pIE_Country != NULL) &&
- (pMgmt->b11hEnable == TRUE)) {
- CARDvSetCountryInfo(pMgmt->pAdapter,
- pBSSList->eNetworkTypeInUse,
+ (pMgmt->b11hEnable == true)) {
+ set_country_info(pMgmt->pAdapter, pBSSList->eNetworkTypeInUse,
pIE_Country);
}
- if ((bParsingQuiet == TRUE) && (pIE_Quiet != NULL)) {
+ if ((bParsingQuiet == true) && (pIE_Quiet != NULL)) {
if ((((PWLAN_IE_QUIET)pIE_Quiet)->len == 8) &&
(((PWLAN_IE_QUIET)pIE_Quiet)->byQuietCount != 0)) {
// valid EID
if (pQuiet == NULL) {
pQuiet = (PWLAN_IE_QUIET)pIE_Quiet;
CARDbSetQuiet( pMgmt->pAdapter,
- TRUE,
+ true,
pQuiet->byQuietCount,
pQuiet->byQuietPeriod,
- *((PWORD)pQuiet->abyQuietDuration),
- *((PWORD)pQuiet->abyQuietOffset)
+ *((unsigned short *)pQuiet->abyQuietDuration),
+ *((unsigned short *)pQuiet->abyQuietOffset)
);
} else {
pQuiet = (PWLAN_IE_QUIET)pIE_Quiet;
CARDbSetQuiet( pMgmt->pAdapter,
- FALSE,
+ false,
pQuiet->byQuietCount,
pQuiet->byQuietPeriod,
- *((PWORD)pQuiet->abyQuietDuration),
- *((PWORD)pQuiet->abyQuietOffset)
+ *((unsigned short *)pQuiet->abyQuietDuration),
+ *((unsigned short *)pQuiet->abyQuietOffset)
);
}
}
}
- if ((bParsingQuiet == TRUE) &&
+ if ((bParsingQuiet == true) &&
(pQuiet != NULL)) {
CARDbStartQuiet(pMgmt->pAdapter);
}
@@ -568,7 +568,7 @@ BSSbInsertToBSSList (
pBSSList->uIELength = WLAN_BEACON_FR_MAXLEN;
memcpy(pBSSList->abyIEs, pbyIEs, pBSSList->uIELength);
- return TRUE;
+ return true;
}
@@ -578,19 +578,19 @@ BSSbInsertToBSSList (
* Update BSS set in known BSS list
*
* Return Value:
- * TRUE if success.
+ * true if success.
*
-*/
// TODO: input structure modify
-BOOL
+bool
BSSbUpdateToBSSList (
void *hDeviceContext,
QWORD qwTimestamp,
- WORD wBeaconInterval,
- WORD wCapInfo,
- BYTE byCurrChannel,
- BOOL bChannelHit,
+ unsigned short wBeaconInterval,
+ unsigned short wCapInfo,
+ unsigned char byCurrChannel,
+ bool bChannelHit,
PWLAN_IE_SSID pSSID,
PWLAN_IE_SUPP_RATES pSuppRates,
PWLAN_IE_SUPP_RATES pExtSuppRates,
@@ -600,8 +600,8 @@ BSSbUpdateToBSSList (
PWLAN_IE_COUNTRY pIE_Country,
PWLAN_IE_QUIET pIE_Quiet,
PKnownBSS pBSSList,
- UINT uIELength,
- PBYTE pbyIEs,
+ unsigned int uIELength,
+ unsigned char *pbyIEs,
void *pRxPacketContext
)
{
@@ -609,14 +609,14 @@ BSSbUpdateToBSSList (
PSDevice pDevice = (PSDevice)hDeviceContext;
PSMgmtObject pMgmt = pDevice->pMgmt;
PSRxMgmtPacket pRxPacket = (PSRxMgmtPacket)pRxPacketContext;
- LONG ldBm;
- BOOL bParsingQuiet = FALSE;
+ long ldBm;
+ bool bParsingQuiet = false;
PWLAN_IE_QUIET pQuiet = NULL;
if (pBSSList == NULL)
- return FALSE;
+ return false;
HIDWORD(pBSSList->qwBSSTimestamp) = cpu_to_le32(HIDWORD(qwTimestamp));
@@ -646,7 +646,7 @@ BSSbUpdateToBSSList (
if (pBSSList->uChannel > CB_MAX_CHANNEL_24G) {
pBSSList->eNetworkTypeInUse = PHY_TYPE_11A;
} else {
- if (pBSSList->sERP.bERPExist == TRUE) {
+ if (pBSSList->sERP.bERPExist == true) {
pBSSList->eNetworkTypeInUse = PHY_TYPE_11G;
} else {
pBSSList->eNetworkTypeInUse = PHY_TYPE_11B;
@@ -663,15 +663,15 @@ BSSbUpdateToBSSList (
(pMgmt->eCurrState == WMAC_STATE_ASSOC)) {
// assoc with BSS
if (pBSSList == pMgmt->pCurrBSS) {
- bParsingQuiet = TRUE;
+ bParsingQuiet = true;
}
}
WPA_ClearRSN(pBSSList); //mike update
if (pRSNWPA != NULL) {
- UINT uLen = pRSNWPA->len + 2;
- if (uLen <= (uIELength - (UINT)(ULONG_PTR)((PBYTE)pRSNWPA - pbyIEs))) {
+ unsigned int uLen = pRSNWPA->len + 2;
+ if (uLen <= (uIELength - (unsigned int)((unsigned char *)pRSNWPA - pbyIEs))) {
pBSSList->wWPALen = uLen;
memcpy(pBSSList->byWPAIE, pRSNWPA, uLen);
WPA_ParseRSN(pBSSList, pRSNWPA);
@@ -681,8 +681,8 @@ BSSbUpdateToBSSList (
WPA2_ClearRSN(pBSSList); //mike update
if (pRSN != NULL) {
- UINT uLen = pRSN->len + 2;
- if (uLen <= (uIELength - (UINT)(ULONG_PTR)((PBYTE)pRSN - pbyIEs))) {
+ unsigned int uLen = pRSN->len + 2;
+ if (uLen <= (uIELength - (unsigned int)((unsigned char *)pRSN - pbyIEs))) {
pBSSList->wRSNLen = uLen;
memcpy(pBSSList->byRSNIE, pRSN, uLen);
WPA2vParseRSN(pBSSList, pRSN);
@@ -690,7 +690,7 @@ BSSbUpdateToBSSList (
}
if (pRxPacket->uRSSI != 0) {
- RFvRSSITodBm(pDevice, (BYTE)(pRxPacket->uRSSI), &ldBm);
+ RFvRSSITodBm(pDevice, (unsigned char)(pRxPacket->uRSSI), &ldBm);
// Moniter if RSSI is too strong.
pBSSList->byRSSIStatCnt++;
pBSSList->byRSSIStatCnt %= RSSI_STAT_COUNT;
@@ -703,39 +703,38 @@ BSSbUpdateToBSSList (
}
if ((pIE_Country != NULL) &&
- (pMgmt->b11hEnable == TRUE)) {
- CARDvSetCountryInfo(pMgmt->pAdapter,
- pBSSList->eNetworkTypeInUse,
+ (pMgmt->b11hEnable == true)) {
+ set_country_info(pMgmt->pAdapter, pBSSList->eNetworkTypeInUse,
pIE_Country);
}
- if ((bParsingQuiet == TRUE) && (pIE_Quiet != NULL)) {
+ if ((bParsingQuiet == true) && (pIE_Quiet != NULL)) {
if ((((PWLAN_IE_QUIET)pIE_Quiet)->len == 8) &&
(((PWLAN_IE_QUIET)pIE_Quiet)->byQuietCount != 0)) {
// valid EID
if (pQuiet == NULL) {
pQuiet = (PWLAN_IE_QUIET)pIE_Quiet;
CARDbSetQuiet( pMgmt->pAdapter,
- TRUE,
+ true,
pQuiet->byQuietCount,
pQuiet->byQuietPeriod,
- *((PWORD)pQuiet->abyQuietDuration),
- *((PWORD)pQuiet->abyQuietOffset)
+ *((unsigned short *)pQuiet->abyQuietDuration),
+ *((unsigned short *)pQuiet->abyQuietOffset)
);
} else {
pQuiet = (PWLAN_IE_QUIET)pIE_Quiet;
CARDbSetQuiet( pMgmt->pAdapter,
- FALSE,
+ false,
pQuiet->byQuietCount,
pQuiet->byQuietPeriod,
- *((PWORD)pQuiet->abyQuietDuration),
- *((PWORD)pQuiet->abyQuietOffset)
+ *((unsigned short *)pQuiet->abyQuietDuration),
+ *((unsigned short *)pQuiet->abyQuietOffset)
);
}
}
}
- if ((bParsingQuiet == TRUE) &&
+ if ((bParsingQuiet == true) &&
(pQuiet != NULL)) {
CARDbStartQuiet(pMgmt->pAdapter);
}
@@ -745,7 +744,7 @@ BSSbUpdateToBSSList (
pBSSList->uIELength = WLAN_BEACON_FR_MAXLEN;
memcpy(pBSSList->abyIEs, pbyIEs, pBSSList->uIELength);
- return TRUE;
+ return true;
}
@@ -762,27 +761,24 @@ BSSbUpdateToBSSList (
*
-*/
-BOOL
-BSSDBbIsSTAInNodeDB(
- void *pMgmtObject,
- PBYTE abyDstAddr,
- PUINT puNodeIndex
- )
+bool
+BSSDBbIsSTAInNodeDB(void *pMgmtObject, unsigned char *abyDstAddr,
+ unsigned int *puNodeIndex)
{
PSMgmtObject pMgmt = (PSMgmtObject) pMgmtObject;
- UINT ii;
+ unsigned int ii;
// Index = 0 reserved for AP Node
for (ii = 1; ii < (MAX_NODE_NUM + 1); ii++) {
if (pMgmt->sNodeDBTable[ii].bActive) {
- if (IS_ETH_ADDRESS_EQUAL(abyDstAddr, pMgmt->sNodeDBTable[ii].abyMACAddr)) {
+ if (!compare_ether_addr(abyDstAddr, pMgmt->sNodeDBTable[ii].abyMACAddr)) {
*puNodeIndex = ii;
- return TRUE;
+ return true;
}
}
}
- return FALSE;
+ return false;
};
@@ -798,17 +794,14 @@ BSSDBbIsSTAInNodeDB(
*
-*/
void
-BSSvCreateOneNode(
- void *hDeviceContext,
- PUINT puNodeIndex
- )
+BSSvCreateOneNode(void *hDeviceContext, unsigned int *puNodeIndex)
{
PSDevice pDevice = (PSDevice)hDeviceContext;
PSMgmtObject pMgmt = pDevice->pMgmt;
- UINT ii;
- UINT BigestCount = 0;
- UINT SelectIndex;
+ unsigned int ii;
+ unsigned int BigestCount = 0;
+ unsigned int SelectIndex;
struct sk_buff *skb;
// Index = 0 reserved for AP Node (In STA mode)
// Index = 0 reserved for Broadcast/MultiCast (In AP mode)
@@ -840,7 +833,7 @@ BSSvCreateOneNode(
}
memset(&pMgmt->sNodeDBTable[*puNodeIndex], 0, sizeof(KnownNodeDB));
- pMgmt->sNodeDBTable[*puNodeIndex].bActive = TRUE;
+ pMgmt->sNodeDBTable[*puNodeIndex].bActive = true;
pMgmt->sNodeDBTable[*puNodeIndex].uRatePollTimeout = FALLBACK_POLL_SECOND;
// for AP mode PS queue
skb_queue_head_init(&pMgmt->sNodeDBTable[*puNodeIndex].sTxPSQueue);
@@ -865,13 +858,13 @@ BSSvCreateOneNode(
void
BSSvRemoveOneNode(
void *hDeviceContext,
- UINT uNodeIndex
+ unsigned int uNodeIndex
)
{
PSDevice pDevice = (PSDevice)hDeviceContext;
PSMgmtObject pMgmt = pDevice->pMgmt;
- BYTE byMask[8] = {1, 2, 4, 8, 0x10, 0x20, 0x40, 0x80};
+ unsigned char byMask[8] = {1, 2, 4, 8, 0x10, 0x20, 0x40, 0x80};
struct sk_buff *skb;
@@ -898,18 +891,18 @@ BSSvRemoveOneNode(
void
BSSvUpdateAPNode(
void *hDeviceContext,
- PWORD pwCapInfo,
+ unsigned short *pwCapInfo,
PWLAN_IE_SUPP_RATES pSuppRates,
PWLAN_IE_SUPP_RATES pExtSuppRates
)
{
PSDevice pDevice = (PSDevice)hDeviceContext;
PSMgmtObject pMgmt = pDevice->pMgmt;
- UINT uRateLen = WLAN_RATES_MAXLEN;
+ unsigned int uRateLen = WLAN_RATES_MAXLEN;
memset(&pMgmt->sNodeDBTable[0], 0, sizeof(KnownNodeDB));
- pMgmt->sNodeDBTable[0].bActive = TRUE;
+ pMgmt->sNodeDBTable[0].bActive = true;
if (pDevice->eCurrentPHYType == PHY_TYPE_11B) {
uRateLen = WLAN_RATES_MAXLEN_11B;
}
@@ -922,7 +915,7 @@ BSSvUpdateAPNode(
RATEvParseMaxRate((void *)pDevice,
(PWLAN_IE_SUPP_RATES)pMgmt->abyCurrSuppRates,
(PWLAN_IE_SUPP_RATES)pMgmt->abyCurrExtSuppRates,
- TRUE,
+ true,
&(pMgmt->sNodeDBTable[0].wMaxBasicRate),
&(pMgmt->sNodeDBTable[0].wMaxSuppRate),
&(pMgmt->sNodeDBTable[0].wSuppRate),
@@ -969,13 +962,13 @@ BSSvAddMulticastNode(
if (!pDevice->bEnableHostWEP)
memset(&pMgmt->sNodeDBTable[0], 0, sizeof(KnownNodeDB));
memset(pMgmt->sNodeDBTable[0].abyMACAddr, 0xff, WLAN_ADDR_LEN);
- pMgmt->sNodeDBTable[0].bActive = TRUE;
- pMgmt->sNodeDBTable[0].bPSEnable = FALSE;
+ pMgmt->sNodeDBTable[0].bActive = true;
+ pMgmt->sNodeDBTable[0].bPSEnable = false;
skb_queue_head_init(&pMgmt->sNodeDBTable[0].sTxPSQueue);
RATEvParseMaxRate((void *)pDevice,
(PWLAN_IE_SUPP_RATES)pMgmt->abyCurrSuppRates,
(PWLAN_IE_SUPP_RATES)pMgmt->abyCurrExtSuppRates,
- TRUE,
+ true,
&(pMgmt->sNodeDBTable[0].wMaxBasicRate),
&(pMgmt->sNodeDBTable[0].wMaxSuppRate),
&(pMgmt->sNodeDBTable[0].wSuppRate),
@@ -1008,8 +1001,8 @@ BSSvAddMulticastNode(
-*/
//2008-4-14 <add> by chester for led issue
#ifdef FOR_LED_ON_NOTEBOOK
-BOOL cc=FALSE;
-UINT status;
+bool cc=false;
+unsigned int status;
#endif
void
BSSvSecondCallBack(
@@ -1018,11 +1011,11 @@ BSSvSecondCallBack(
{
PSDevice pDevice = (PSDevice)hDeviceContext;
PSMgmtObject pMgmt = pDevice->pMgmt;
- UINT ii;
+ unsigned int ii;
PWLAN_IE_SSID pItemSSID, pCurrSSID;
- UINT uSleepySTACnt = 0;
- UINT uNonShortSlotSTACnt = 0;
- UINT uLongPreambleSTACnt = 0;
+ unsigned int uSleepySTACnt = 0;
+ unsigned int uNonShortSlotSTACnt = 0;
+ unsigned int uLongPreambleSTACnt = 0;
viawget_wpa_header* wpahdr; //DavidWang
spin_lock_irq(&pDevice->lock);
@@ -1034,22 +1027,22 @@ BSSvSecondCallBack(
//2008-4-14 <add> by chester for led issue
#ifdef FOR_LED_ON_NOTEBOOK
MACvGPIOIn(pDevice->PortOffset, &pDevice->byGPIO);
-if ((( !(pDevice->byGPIO & GPIO0_DATA)&&(pDevice->bHWRadioOff == FALSE))||((pDevice->byGPIO & GPIO0_DATA)&&(pDevice->bHWRadioOff == TRUE)))&&(cc==FALSE)){
-cc=TRUE;
+if ((( !(pDevice->byGPIO & GPIO0_DATA)&&(pDevice->bHWRadioOff == false))||((pDevice->byGPIO & GPIO0_DATA)&&(pDevice->bHWRadioOff == true)))&&(cc==false)){
+cc=true;
}
-else if(cc==TRUE){
+else if(cc==true){
-if(pDevice->bHWRadioOff == TRUE){
+if(pDevice->bHWRadioOff == true){
if ( !(pDevice->byGPIO & GPIO0_DATA))
//||( !(pDevice->byGPIO & GPIO0_DATA) && (pDevice->byRadioCtl & EEP_RADIOCTL_INV)))
{if(status==1) goto start;
status=1;
CARDbRadioPowerOff(pDevice);
- pMgmt->sNodeDBTable[0].bActive = FALSE;
+ pMgmt->sNodeDBTable[0].bActive = false;
pMgmt->eCurrMode = WMAC_MODE_STANDBY;
pMgmt->eCurrState = WMAC_STATE_IDLE;
//netif_stop_queue(pDevice->dev);
- pDevice->bLinkPass = FALSE;
+ pDevice->bLinkPass = false;
}
if (pDevice->byGPIO &GPIO0_DATA)
@@ -1064,11 +1057,11 @@ else{
{if(status==3) goto start;
status=3;
CARDbRadioPowerOff(pDevice);
- pMgmt->sNodeDBTable[0].bActive = FALSE;
+ pMgmt->sNodeDBTable[0].bActive = false;
pMgmt->eCurrMode = WMAC_MODE_STANDBY;
pMgmt->eCurrState = WMAC_STATE_IDLE;
//netif_stop_queue(pDevice->dev);
- pDevice->bLinkPass = FALSE;
+ pDevice->bLinkPass = false;
}
if ( !(pDevice->byGPIO & GPIO0_DATA))
@@ -1092,11 +1085,11 @@ start:
{
pDevice->byReAssocCount++;
- if((pDevice->byReAssocCount > 10) && (pDevice->bLinkPass != TRUE)) { //10 sec timeout
+ if((pDevice->byReAssocCount > 10) && (pDevice->bLinkPass != true)) { //10 sec timeout
printk("Re-association timeout!!!\n");
pDevice->byReAssocCount = 0;
#ifdef WPA_SUPPLICANT_DRIVER_WEXT_SUPPORT
- // if(pDevice->bWPASuppWextEnabled == TRUE)
+ // if(pDevice->bWPASuppWextEnabled == true)
{
union iwreq_data wrqu;
memset(&wrqu, 0, sizeof (wrqu));
@@ -1106,7 +1099,7 @@ start:
}
#endif
}
- else if(pDevice->bLinkPass == TRUE)
+ else if(pDevice->bLinkPass == true)
pDevice->byReAssocCount = 0;
}
@@ -1200,27 +1193,27 @@ start:
if (WLAN_GET_ERP_USE_PROTECTION(pDevice->byERPFlag)) {
if (!pDevice->bProtectMode) {
MACvEnableProtectMD(pDevice->PortOffset);
- pDevice->bProtectMode = TRUE;
+ pDevice->bProtectMode = true;
}
}
else {
if (pDevice->bProtectMode) {
MACvDisableProtectMD(pDevice->PortOffset);
- pDevice->bProtectMode = FALSE;
+ pDevice->bProtectMode = false;
}
}
// on/off short slot time
if (uNonShortSlotSTACnt > 0) {
if (pDevice->bShortSlotTime) {
- pDevice->bShortSlotTime = FALSE;
+ pDevice->bShortSlotTime = false;
BBvSetShortSlotTime(pDevice);
vUpdateIFS((void *)pDevice);
}
}
else {
if (!pDevice->bShortSlotTime) {
- pDevice->bShortSlotTime = TRUE;
+ pDevice->bShortSlotTime = true;
BBvSetShortSlotTime(pDevice);
vUpdateIFS((void *)pDevice);
}
@@ -1231,13 +1224,13 @@ start:
if (uLongPreambleSTACnt > 0) {
if (!pDevice->bBarkerPreambleMd) {
MACvEnableBarkerPreambleMd(pDevice->PortOffset);
- pDevice->bBarkerPreambleMd = TRUE;
+ pDevice->bBarkerPreambleMd = true;
}
}
else {
if (pDevice->bBarkerPreambleMd) {
MACvDisableBarkerPreambleMd(pDevice->PortOffset);
- pDevice->bBarkerPreambleMd = FALSE;
+ pDevice->bBarkerPreambleMd = false;
}
}
@@ -1247,9 +1240,9 @@ start:
// Check if any STA in PS mode, enable DTIM multicast deliver
if (pMgmt->eCurrMode == WMAC_MODE_ESS_AP) {
if (uSleepySTACnt > 0)
- pMgmt->sNodeDBTable[0].bPSEnable = TRUE;
+ pMgmt->sNodeDBTable[0].bPSEnable = true;
else
- pMgmt->sNodeDBTable[0].bPSEnable = FALSE;
+ pMgmt->sNodeDBTable[0].bPSEnable = false;
}
pItemSSID = (PWLAN_IE_SSID)pMgmt->abyDesireSSID;
@@ -1276,12 +1269,12 @@ start:
}
if (pMgmt->sNodeDBTable[0].uInActiveCount >= LOST_BEACON_COUNT) {
- pMgmt->sNodeDBTable[0].bActive = FALSE;
+ pMgmt->sNodeDBTable[0].bActive = false;
pMgmt->eCurrMode = WMAC_MODE_STANDBY;
pMgmt->eCurrState = WMAC_STATE_IDLE;
netif_stop_queue(pDevice->dev);
- pDevice->bLinkPass = FALSE;
- pDevice->bRoaming = TRUE;
+ pDevice->bLinkPass = false;
+ pDevice->bRoaming = true;
DBG_PRT(MSG_LEVEL_NOTICE, KERN_INFO "Lost AP beacon [%d] sec, disconnected !\n", pMgmt->sNodeDBTable[0].uInActiveCount);
if ((pDevice->bWPADEVUp) && (pDevice->skb != NULL)) {
wpahdr = (viawget_wpa_header *)pDevice->skb->data;
@@ -1298,7 +1291,7 @@ start:
pDevice->skb = dev_alloc_skb((int)pDevice->rx_buf_sz);
};
#ifdef WPA_SUPPLICANT_DRIVER_WEXT_SUPPORT
- // if(pDevice->bWPASuppWextEnabled == TRUE)
+ // if(pDevice->bWPASuppWextEnabled == true)
{
union iwreq_data wrqu;
memset(&wrqu, 0, sizeof (wrqu));
@@ -1314,7 +1307,7 @@ start:
pDevice->uAutoReConnectTime++;
#ifdef WPA_SUPPLICANT_DRIVER_WEXT_SUPPORT
//network manager support need not do Roaming scan???
- if(pDevice->bWPASuppWextEnabled ==TRUE)
+ if(pDevice->bWPASuppWextEnabled ==true)
pDevice->uAutoReConnectTime = 0;
#endif
}
@@ -1358,7 +1351,7 @@ start:
pMgmt->sNodeDBTable[0].uInActiveCount = 0;
pMgmt->eCurrState = WMAC_STATE_STARTED;
netif_stop_queue(pDevice->dev);
- pDevice->bLinkPass = FALSE;
+ pDevice->bLinkPass = false;
}
}
}
@@ -1391,23 +1384,23 @@ start:
void
BSSvUpdateNodeTxCounter(
void *hDeviceContext,
- BYTE byTsr0,
- BYTE byTsr1,
- PBYTE pbyBuffer,
- UINT uFIFOHeaderSize
+ unsigned char byTsr0,
+ unsigned char byTsr1,
+ unsigned char *pbyBuffer,
+ unsigned int uFIFOHeaderSize
)
{
PSDevice pDevice = (PSDevice)hDeviceContext;
PSMgmtObject pMgmt = pDevice->pMgmt;
- UINT uNodeIndex = 0;
- BYTE byTxRetry = (byTsr0 & TSR0_NCR);
+ unsigned int uNodeIndex = 0;
+ unsigned char byTxRetry = (byTsr0 & TSR0_NCR);
PSTxBufHead pTxBufHead;
PS802_11Header pMACHeader;
- WORD wRate;
- WORD wFallBackRate = RATE_1M;
- BYTE byFallBack;
- UINT ii;
-// UINT txRetryTemp;
+ unsigned short wRate;
+ unsigned short wFallBackRate = RATE_1M;
+ unsigned char byFallBack;
+ unsigned int ii;
+// unsigned int txRetryTemp;
//PLICE_DEBUG->
//txRetryTemp = byTxRetry;
//if (txRetryTemp== 8)
@@ -1584,14 +1577,14 @@ BSSvUpdateNodeTxCounter(
void
BSSvClearNodeDBTable(
void *hDeviceContext,
- UINT uStartIndex
+ unsigned int uStartIndex
)
{
PSDevice pDevice = (PSDevice)hDeviceContext;
PSMgmtObject pMgmt = pDevice->pMgmt;
struct sk_buff *skb;
- UINT ii;
+ unsigned int ii;
for (ii = uStartIndex; ii < (MAX_NODE_NUM + 1); ii++) {
if (pMgmt->sNodeDBTable[ii].bActive) {
@@ -1629,8 +1622,8 @@ void s_vCheckSensitivity(
pBSSList = BSSpAddrIsInBSSList(pDevice, pMgmt->abyCurrBSSID, (PWLAN_IE_SSID)pMgmt->abyCurrSSID);
if (pBSSList != NULL) {
// Updata BB Reg if RSSI is too strong.
- LONG LocalldBmAverage = 0;
- LONG uNumofdBm = 0;
+ long LocalldBmAverage = 0;
+ long uNumofdBm = 0;
for (ii = 0; ii < RSSI_STAT_COUNT; ii++) {
if (pBSSList->ldBmAverage[ii] != 0) {
uNumofdBm ++;
@@ -1666,10 +1659,10 @@ BSSvClearAnyBSSJoinRecord (
{
PSDevice pDevice = (PSDevice)hDeviceContext;
PSMgmtObject pMgmt = pDevice->pMgmt;
- UINT ii;
+ unsigned int ii;
for (ii = 0; ii < MAX_BSS_NUM; ii++) {
- pMgmt->sBSSList[ii].bSelected = FALSE;
+ pMgmt->sBSSList[ii].bSelected = false;
}
return;
}
@@ -1680,9 +1673,9 @@ void s_uCalculateLinkQual(
)
{
PSDevice pDevice = (PSDevice)hDeviceContext;
- ULONG TxOkRatio, TxCnt;
- ULONG RxOkRatio,RxCnt;
- ULONG RssiRatio;
+ unsigned long TxOkRatio, TxCnt;
+ unsigned long RxOkRatio,RxCnt;
+ unsigned long RssiRatio;
long ldBm;
TxCnt = pDevice->scStatistic.TxNoRetryOkCount +
@@ -1693,7 +1686,7 @@ RxCnt = pDevice->scStatistic.RxFcsErrCnt +
TxOkRatio = (TxCnt < 6) ? 4000:((pDevice->scStatistic.TxNoRetryOkCount * 4000) / TxCnt);
RxOkRatio = (RxCnt < 6) ? 2000:((pDevice->scStatistic.RxOkCnt * 2000) / RxCnt);
//decide link quality
-if(pDevice->bLinkPass !=TRUE)
+if(pDevice->bLinkPass !=true)
{
// printk("s_uCalculateLinkQual-->Link disconnect and Poor quality**\n");
pDevice->scStatistic.LinkQuality = 0;
@@ -1701,7 +1694,7 @@ if(pDevice->bLinkPass !=TRUE)
}
else
{
- RFvRSSITodBm(pDevice, (BYTE)(pDevice->uCurrRSSI), &ldBm);
+ RFvRSSITodBm(pDevice, (unsigned char)(pDevice->uCurrRSSI), &ldBm);
if(-ldBm < 50) {
RssiRatio = 4000;
}
@@ -1735,8 +1728,8 @@ void s_vCheckPreEDThreshold(
((pMgmt->eCurrMode == WMAC_MODE_IBSS_STA) && (pMgmt->eCurrState == WMAC_STATE_JOINTED))) {
pBSSList = BSSpAddrIsInBSSList(pDevice, pMgmt->abyCurrBSSID, (PWLAN_IE_SSID)pMgmt->abyCurrSSID);
if (pBSSList != NULL) {
- pDevice->byBBPreEDRSSI = (BYTE) (~(pBSSList->ldBmAverRange) + 1);
- //BBvUpdatePreEDThreshold(pDevice, FALSE);
+ pDevice->byBBPreEDRSSI = (unsigned char) (~(pBSSList->ldBmAverRange) + 1);
+ //BBvUpdatePreEDThreshold(pDevice, false);
}
}
return;
diff --git a/drivers/staging/vt6655/bssdb.h b/drivers/staging/vt6655/bssdb.h
index e09ef876297..0af42118612 100644
--- a/drivers/staging/vt6655/bssdb.h
+++ b/drivers/staging/vt6655/bssdb.h
@@ -90,69 +90,69 @@ typedef enum _NDIS_802_11_NETWORK_TYPE
typedef struct tagSERPObject {
- BOOL bERPExist;
- BYTE byERP;
+ bool bERPExist;
+ unsigned char byERP;
}ERPObject, *PERPObject;
typedef struct tagSRSNCapObject {
- BOOL bRSNCapExist;
- WORD wRSNCap;
+ bool bRSNCapExist;
+ unsigned short wRSNCap;
}SRSNCapObject, *PSRSNCapObject;
// BSS info(AP)
#pragma pack(1)
typedef struct tagKnownBSS {
// BSS info
- BOOL bActive;
- BYTE abyBSSID[WLAN_BSSID_LEN];
- UINT uChannel;
- BYTE abySuppRates[WLAN_IEHDR_LEN + WLAN_RATES_MAXLEN + 1];
- BYTE abyExtSuppRates[WLAN_IEHDR_LEN + WLAN_RATES_MAXLEN + 1];
- UINT uRSSI;
- BYTE bySQ;
- WORD wBeaconInterval;
- WORD wCapInfo;
- BYTE abySSID[WLAN_IEHDR_LEN + WLAN_SSID_MAXLEN + 1];
- BYTE byRxRate;
-
-// WORD wATIMWindow;
- BYTE byRSSIStatCnt;
- LONG ldBmMAX;
- LONG ldBmAverage[RSSI_STAT_COUNT];
- LONG ldBmAverRange;
+ bool bActive;
+ unsigned char abyBSSID[WLAN_BSSID_LEN];
+ unsigned int uChannel;
+ unsigned char abySuppRates[WLAN_IEHDR_LEN + WLAN_RATES_MAXLEN + 1];
+ unsigned char abyExtSuppRates[WLAN_IEHDR_LEN + WLAN_RATES_MAXLEN + 1];
+ unsigned int uRSSI;
+ unsigned char bySQ;
+ unsigned short wBeaconInterval;
+ unsigned short wCapInfo;
+ unsigned char abySSID[WLAN_IEHDR_LEN + WLAN_SSID_MAXLEN + 1];
+ unsigned char byRxRate;
+
+// unsigned short wATIMWindow;
+ unsigned char byRSSIStatCnt;
+ long ldBmMAX;
+ long ldBmAverage[RSSI_STAT_COUNT];
+ long ldBmAverRange;
//For any BSSID selection improvment
- BOOL bSelected;
+ bool bSelected;
//++ WPA informations
- BOOL bWPAValid;
- BYTE byGKType;
- BYTE abyPKType[4];
- WORD wPKCount;
- BYTE abyAuthType[4];
- WORD wAuthCount;
- BYTE byDefaultK_as_PK;
- BYTE byReplayIdx;
+ bool bWPAValid;
+ unsigned char byGKType;
+ unsigned char abyPKType[4];
+ unsigned short wPKCount;
+ unsigned char abyAuthType[4];
+ unsigned short wAuthCount;
+ unsigned char byDefaultK_as_PK;
+ unsigned char byReplayIdx;
//--
//++ WPA2 informations
- BOOL bWPA2Valid;
- BYTE byCSSGK;
- WORD wCSSPKCount;
- BYTE abyCSSPK[4];
- WORD wAKMSSAuthCount;
- BYTE abyAKMSSAuthType[4];
+ bool bWPA2Valid;
+ unsigned char byCSSGK;
+ unsigned short wCSSPKCount;
+ unsigned char abyCSSPK[4];
+ unsigned short wAKMSSAuthCount;
+ unsigned char abyAKMSSAuthType[4];
//++ wpactl
- BYTE byWPAIE[MAX_WPA_IE_LEN];
- BYTE byRSNIE[MAX_WPA_IE_LEN];
- WORD wWPALen;
- WORD wRSNLen;
+ unsigned char byWPAIE[MAX_WPA_IE_LEN];
+ unsigned char byRSNIE[MAX_WPA_IE_LEN];
+ unsigned short wWPALen;
+ unsigned short wRSNLen;
// Clear count
- UINT uClearCount;
-// BYTE abyIEs[WLAN_BEACON_FR_MAXLEN];
- UINT uIELength;
+ unsigned int uClearCount;
+// unsigned char abyIEs[WLAN_BEACON_FR_MAXLEN];
+ unsigned int uIELength;
QWORD qwBSSTimestamp;
QWORD qwLocalTSF; // local TSF timer
@@ -161,7 +161,7 @@ typedef struct tagKnownBSS {
ERPObject sERP;
SRSNCapObject sRSNCapObj;
- BYTE abyIEs[1024]; // don't move this field !!
+ unsigned char abyIEs[1024]; // don't move this field !!
}__attribute__ ((__packed__))
KnownBSS , *PKnownBSS;
@@ -181,59 +181,59 @@ typedef enum tagNODE_STATE {
// STA node info
typedef struct tagKnownNodeDB {
// STA info
- BOOL bActive;
- BYTE abyMACAddr[WLAN_ADDR_LEN];
- BYTE abyCurrSuppRates[WLAN_IEHDR_LEN + WLAN_RATES_MAXLEN];
- BYTE abyCurrExtSuppRates[WLAN_IEHDR_LEN + WLAN_RATES_MAXLEN];
- WORD wTxDataRate;
- BOOL bShortPreamble;
- BOOL bERPExist;
- BOOL bShortSlotTime;
- UINT uInActiveCount;
- WORD wMaxBasicRate; //Get from byTopOFDMBasicRate or byTopCCKBasicRate which depends on packetTyp.
- WORD wMaxSuppRate; //Records the highest supported rate getting from SuppRates IE and ExtSuppRates IE in Beacon.
- WORD wSuppRate;
- BYTE byTopOFDMBasicRate;//Records the highest basic rate in OFDM mode
- BYTE byTopCCKBasicRate; //Records the highest basic rate in CCK mode
+ bool bActive;
+ unsigned char abyMACAddr[WLAN_ADDR_LEN];
+ unsigned char abyCurrSuppRates[WLAN_IEHDR_LEN + WLAN_RATES_MAXLEN];
+ unsigned char abyCurrExtSuppRates[WLAN_IEHDR_LEN + WLAN_RATES_MAXLEN];
+ unsigned short wTxDataRate;
+ bool bShortPreamble;
+ bool bERPExist;
+ bool bShortSlotTime;
+ unsigned int uInActiveCount;
+ unsigned short wMaxBasicRate; //Get from byTopOFDMBasicRate or byTopCCKBasicRate which depends on packetTyp.
+ unsigned short wMaxSuppRate; //Records the highest supported rate getting from SuppRates IE and ExtSuppRates IE in Beacon.
+ unsigned short wSuppRate;
+ unsigned char byTopOFDMBasicRate;//Records the highest basic rate in OFDM mode
+ unsigned char byTopCCKBasicRate; //Records the highest basic rate in CCK mode
// For AP mode
struct sk_buff_head sTxPSQueue;
- WORD wCapInfo;
- WORD wListenInterval;
- WORD wAID;
+ unsigned short wCapInfo;
+ unsigned short wListenInterval;
+ unsigned short wAID;
NODE_STATE eNodeState;
- BOOL bPSEnable;
- BOOL bRxPSPoll;
- BYTE byAuthSequence;
- ULONG ulLastRxJiffer;
- BYTE bySuppRate;
- DWORD dwFlags;
- WORD wEnQueueCnt;
-
- BOOL bOnFly;
- ULONGLONG KeyRSC;
- BYTE byKeyIndex;
- DWORD dwKeyIndex;
- BYTE byCipherSuite;
- DWORD dwTSC47_16;
- WORD wTSC15_0;
- UINT uWepKeyLength;
- BYTE abyWepKey[WLAN_WEPMAX_KEYLEN];
+ bool bPSEnable;
+ bool bRxPSPoll;
+ unsigned char byAuthSequence;
+ unsigned long ulLastRxJiffer;
+ unsigned char bySuppRate;
+ unsigned long dwFlags;
+ unsigned short wEnQueueCnt;
+
+ bool bOnFly;
+ unsigned long long KeyRSC;
+ unsigned char byKeyIndex;
+ unsigned long dwKeyIndex;
+ unsigned char byCipherSuite;
+ unsigned long dwTSC47_16;
+ unsigned short wTSC15_0;
+ unsigned int uWepKeyLength;
+ unsigned char abyWepKey[WLAN_WEPMAX_KEYLEN];
//
// Auto rate fallback vars
- BOOL bIsInFallback;
- UINT uAverageRSSI;
- UINT uRateRecoveryTimeout;
- UINT uRatePollTimeout;
- UINT uTxFailures;
- UINT uTxAttempts;
-
- UINT uTxRetry;
- UINT uFailureRatio;
- UINT uRetryRatio;
- UINT uTxOk[MAX_RATE+1];
- UINT uTxFail[MAX_RATE+1];
- UINT uTimeCount;
+ bool bIsInFallback;
+ unsigned int uAverageRSSI;
+ unsigned int uRateRecoveryTimeout;
+ unsigned int uRatePollTimeout;
+ unsigned int uTxFailures;
+ unsigned int uTxAttempts;
+
+ unsigned int uTxRetry;
+ unsigned int uFailureRatio;
+ unsigned int uRetryRatio;
+ unsigned int uTxOk[MAX_RATE+1];
+ unsigned int uTxFail[MAX_RATE+1];
+ unsigned int uTimeCount;
} KnownNodeDB, *PKnownNodeDB;
@@ -245,32 +245,32 @@ typedef struct tagKnownNodeDB {
PKnownBSS
BSSpSearchBSSList(
void *hDeviceContext,
- PBYTE pbyDesireBSSID,
- PBYTE pbyDesireSSID,
+ unsigned char *pbyDesireBSSID,
+ unsigned char *pbyDesireSSID,
CARD_PHY_TYPE ePhyType
);
PKnownBSS
BSSpAddrIsInBSSList(
void *hDeviceContext,
- PBYTE abyBSSID,
+ unsigned char *abyBSSID,
PWLAN_IE_SSID pSSID
);
void
BSSvClearBSSList(
void *hDeviceContext,
- BOOL bKeepCurrBSSID
+ bool bKeepCurrBSSID
);
-BOOL
+bool
BSSbInsertToBSSList(
void *hDeviceContext,
- PBYTE abyBSSIDAddr,
+ unsigned char *abyBSSIDAddr,
QWORD qwTimestamp,
- WORD wBeaconInterval,
- WORD wCapInfo,
- BYTE byCurrChannel,
+ unsigned short wBeaconInterval,
+ unsigned short wCapInfo,
+ unsigned char byCurrChannel,
PWLAN_IE_SSID pSSID,
PWLAN_IE_SUPP_RATES pSuppRates,
PWLAN_IE_SUPP_RATES pExtSuppRates,
@@ -279,20 +279,20 @@ BSSbInsertToBSSList(
PWLAN_IE_RSN_EXT pRSNWPA,
PWLAN_IE_COUNTRY pIE_Country,
PWLAN_IE_QUIET pIE_Quiet,
- UINT uIELength,
- PBYTE pbyIEs,
+ unsigned int uIELength,
+ unsigned char *pbyIEs,
void *pRxPacketContext
);
-BOOL
+bool
BSSbUpdateToBSSList(
void *hDeviceContext,
QWORD qwTimestamp,
- WORD wBeaconInterval,
- WORD wCapInfo,
- BYTE byCurrChannel,
- BOOL bChannelHit,
+ unsigned short wBeaconInterval,
+ unsigned short wCapInfo,
+ unsigned char byCurrChannel,
+ bool bChannelHit,
PWLAN_IE_SSID pSSID,
PWLAN_IE_SUPP_RATES pSuppRates,
PWLAN_IE_SUPP_RATES pExtSuppRates,
@@ -302,29 +302,23 @@ BSSbUpdateToBSSList(
PWLAN_IE_COUNTRY pIE_Country,
PWLAN_IE_QUIET pIE_Quiet,
PKnownBSS pBSSList,
- UINT uIELength,
- PBYTE pbyIEs,
+ unsigned int uIELength,
+ unsigned char *pbyIEs,
void *pRxPacketContext
);
-BOOL
-BSSDBbIsSTAInNodeDB(
- void *hDeviceContext,
- PBYTE abyDstAddr,
- PUINT puNodeIndex
- );
+bool
+BSSDBbIsSTAInNodeDB(void *hDeviceContext, unsigned char *abyDstAddr,
+ unsigned int *puNodeIndex);
void
-BSSvCreateOneNode(
- void *hDeviceContext,
- PUINT puNodeIndex
- );
+BSSvCreateOneNode(void *hDeviceContext, unsigned int *puNodeIndex);
void
BSSvUpdateAPNode(
void *hDeviceContext,
- PWORD pwCapInfo,
+ unsigned short *pwCapInfo,
PWLAN_IE_SUPP_RATES pItemRates,
PWLAN_IE_SUPP_RATES pExtSuppRates
);
@@ -339,16 +333,16 @@ BSSvSecondCallBack(
void
BSSvUpdateNodeTxCounter(
void *hDeviceContext,
- BYTE byTsr0,
- BYTE byTsr1,
- PBYTE pbyBuffer,
- UINT uFIFOHeaderSize
+ unsigned char byTsr0,
+ unsigned char byTsr1,
+ unsigned char *pbyBuffer,
+ unsigned int uFIFOHeaderSize
);
void
BSSvRemoveOneNode(
void *hDeviceContext,
- UINT uNodeIndex
+ unsigned int uNodeIndex
);
void
@@ -360,7 +354,7 @@ BSSvAddMulticastNode(
void
BSSvClearNodeDBTable(
void *hDeviceContext,
- UINT uStartIndex
+ unsigned int uStartIndex
);
void
diff --git a/drivers/staging/vt6655/card.c b/drivers/staging/vt6655/card.c
index 7bc2d7654b0..32d095c4d51 100644
--- a/drivers/staging/vt6655/card.c
+++ b/drivers/staging/vt6655/card.c
@@ -56,6 +56,7 @@
#include "key.h"
#include "rc4.h"
#include "country.h"
+#include "channel.h"
/*--------------------- Static Definitions -------------------------*/
@@ -76,411 +77,39 @@ static int msglevel =MSG_LEVEL_INFO;
#define C_CWMAX 1023 // slot time
-#define CARD_MAX_CHANNEL_TBL 56
-
#define WAIT_BEACON_TX_DOWN_TMO 3 // Times
-typedef struct tagSChannelTblElement {
- BYTE byChannelNumber;
- UINT uFrequency;
- BOOL bValid;
- BYTE byMAP;
-}SChannelTblElement, *PSChannelTblElement;
-
//1M, 2M, 5M, 11M, 18M, 24M, 36M, 54M
-static BYTE abyDefaultSuppRatesG[] = {WLAN_EID_SUPP_RATES, 8, 0x02, 0x04, 0x0B, 0x16, 0x24, 0x30, 0x48, 0x6C};
+static unsigned char abyDefaultSuppRatesG[] = {WLAN_EID_SUPP_RATES, 8, 0x02, 0x04, 0x0B, 0x16, 0x24, 0x30, 0x48, 0x6C};
//6M, 9M, 12M, 48M
-static BYTE abyDefaultExtSuppRatesG[] = {WLAN_EID_EXTSUPP_RATES, 4, 0x0C, 0x12, 0x18, 0x60};
+static unsigned char abyDefaultExtSuppRatesG[] = {WLAN_EID_EXTSUPP_RATES, 4, 0x0C, 0x12, 0x18, 0x60};
//6M, 9M, 12M, 18M, 24M, 36M, 48M, 54M
-static BYTE abyDefaultSuppRatesA[] = {WLAN_EID_SUPP_RATES, 8, 0x0C, 0x12, 0x18, 0x24, 0x30, 0x48, 0x60, 0x6C};
+static unsigned char abyDefaultSuppRatesA[] = {WLAN_EID_SUPP_RATES, 8, 0x0C, 0x12, 0x18, 0x24, 0x30, 0x48, 0x60, 0x6C};
//1M, 2M, 5M, 11M,
-static BYTE abyDefaultSuppRatesB[] = {WLAN_EID_SUPP_RATES, 4, 0x02, 0x04, 0x0B, 0x16};
-
-
+static unsigned char abyDefaultSuppRatesB[] = {WLAN_EID_SUPP_RATES, 4, 0x02, 0x04, 0x0B, 0x16};
-/*--------------------- Static Classes ----------------------------*/
/*--------------------- Static Variables --------------------------*/
-const WORD cwRXBCNTSFOff[MAX_RATE] =
+const unsigned short cwRXBCNTSFOff[MAX_RATE] =
{17, 17, 17, 17, 34, 23, 17, 11, 8, 5, 4, 3};
-static SChannelTblElement sChannelTbl[CARD_MAX_CHANNEL_TBL+1] =
-{
- {0, 0, FALSE, 0},
- {1, 2412, TRUE, 0},
- {2, 2417, TRUE, 0},
- {3, 2422, TRUE, 0},
- {4, 2427, TRUE, 0},
- {5, 2432, TRUE, 0},
- {6, 2437, TRUE, 0},
- {7, 2442, TRUE, 0},
- {8, 2447, TRUE, 0},
- {9, 2452, TRUE, 0},
- {10, 2457, TRUE, 0},
- {11, 2462, TRUE, 0},
- {12, 2467, TRUE, 0},
- {13, 2472, TRUE, 0},
- {14, 2484, TRUE, 0},
- {183, 4915, TRUE, 0},
- {184, 4920, TRUE, 0},
- {185, 4925, TRUE, 0},
- {187, 4935, TRUE, 0},
- {188, 4940, TRUE, 0},
- {189, 4945, TRUE, 0},
- {192, 4960, TRUE, 0},
- {196, 4980, TRUE, 0},
- {7, 5035, TRUE, 0},
- {8, 5040, TRUE, 0},
- {9, 5045, TRUE, 0},
- {11, 5055, TRUE, 0},
- {12, 5060, TRUE, 0},
- {16, 5080, TRUE, 0},
- {34, 5170, TRUE, 0},
- {36, 5180, TRUE, 0},
- {38, 5190, TRUE, 0},
- {40, 5200, TRUE, 0},
- {42, 5210, TRUE, 0},
- {44, 5220, TRUE, 0},
- {46, 5230, TRUE, 0},
- {48, 5240, TRUE, 0},
- {52, 5260, TRUE, 0},
- {56, 5280, TRUE, 0},
- {60, 5300, TRUE, 0},
- {64, 5320, TRUE, 0},
- {100, 5500, TRUE, 0},
- {104, 5520, TRUE, 0},
- {108, 5540, TRUE, 0},
- {112, 5560, TRUE, 0},
- {116, 5580, TRUE, 0},
- {120, 5600, TRUE, 0},
- {124, 5620, TRUE, 0},
- {128, 5640, TRUE, 0},
- {132, 5660, TRUE, 0},
- {136, 5680, TRUE, 0},
- {140, 5700, TRUE, 0},
- {149, 5745, TRUE, 0},
- {153, 5765, TRUE, 0},
- {157, 5785, TRUE, 0},
- {161, 5805, TRUE, 0},
- {165, 5825, TRUE, 0}
-};
-
-
-/************************************************************************
- * The Radar regulation rules for each country
- ************************************************************************/
-SCountryTable ChannelRuleTab[CCODE_MAX+1] =
-{
-/************************************************************************
- * This table is based on Athero driver rules
- ************************************************************************/
-/* Country Available channels, ended with 0 */
-/* 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 */
-{CCODE_FCC, {'U','S'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1}
- , { 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 0, 17, 0, 17, 0, 17, 23, 23, 23, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 30, 30, 30, 30} },
-{CCODE_TELEC, {'J','P'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
- , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 23, 0, 0, 23, 0, 23, 23, 0, 23, 0, 0, 23, 23, 23, 0, 23, 0, 23, 0, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
-{CCODE_ETSI, {'E','U'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0}
- , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 20, 0, 20, 0, 20, 20, 20, 20, 20, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 0, 0, 0, 0, 0} },
-{CCODE_RESV3, {' ',' '}, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
- , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
-{CCODE_RESV4, {' ',' '}, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
- , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
-{CCODE_RESV5, {' ',' '}, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
- , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
-{CCODE_RESV6, {' ',' '}, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
- , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
-{CCODE_RESV7, {' ',' '}, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
- , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
-{CCODE_RESV8, {' ',' '}, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
- , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
-{CCODE_RESV9, {' ',' '}, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
- , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
-{CCODE_RESVa, {' ',' '}, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
- , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
-{CCODE_RESVb, {' ',' '}, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
- , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
-{CCODE_RESVc, {' ',' '}, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
- , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
-{CCODE_RESVd, {' ',' '}, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
- , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
-{CCODE_RESVe, {' ',' '}, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
- , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
-{CCODE_ALLBAND, {' ',' '}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
-{CCODE_ALBANIA, {'A','L'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
- , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
-{CCODE_ALGERIA, {'D','Z'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
- , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
-{CCODE_ARGENTINA, {'A','R'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 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, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0}
- , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 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, 17, 17, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 30, 30, 30, 0} },
-{CCODE_ARMENIA, {'A','M'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
- , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 18, 0, 18, 0, 18, 18, 18, 18, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
-{CCODE_AUSTRALIA, {'A','U'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1}
- , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 23, 0, 23, 0, 23, 0, 23, 23, 23, 23, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 30, 30, 30, 30} },
-{CCODE_AUSTRIA, {'A','T'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
- , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 0, 15, 0, 15, 0, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
-{CCODE_AZERBAIJAN, {'A','Z'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
- , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 18, 0, 18, 0, 18, 18, 18, 18, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
-{CCODE_BAHRAIN, {'B','H'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
- , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
-{CCODE_BELARUS, {'B','Y'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
- , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
-{CCODE_BELGIUM, {'B','E'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
- , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 18, 0, 18, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
-{CCODE_BELIZE, {'B','Z'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 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, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1}
- , { 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 30, 30, 30, 30} },
-{CCODE_BOLIVIA, {'B','O'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 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, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1}
- , { 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 30, 30, 30, 30} },
-{CCODE_BRAZIL, {'B','R'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
- , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
-{CCODE_BRUNEI_DARUSSALAM, {'B','N'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 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, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1}
- , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 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, 30, 30, 30, 30, 30} },
-{CCODE_BULGARIA, {'B','G'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0}
- , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 23, 0, 23, 0, 23, 0, 23, 23, 23, 0, 0, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 0, 0, 0, 0, 0} },
-{CCODE_CANADA, {'C','A'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1}
- , { 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 0, 17, 0, 17, 0, 17, 23, 23, 23, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 30, 30, 30, 30} },
-{CCODE_CHILE, {'C','L'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 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, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1}
- , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 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, 17, 17, 17, 17, 17} },
-{CCODE_CHINA, {'C','N'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 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, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1}
- , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 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, 30, 30, 30, 30, 30} },
-{CCODE_COLOMBIA, {'C','O'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1}
- , { 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 0, 17, 0, 17, 0, 17, 23, 23, 23, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 30, 30, 30, 30} },
-{CCODE_COSTA_RICA, {'C','R'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
- , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
-{CCODE_CROATIA, {'H','R'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
- , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 20, 0, 20, 0, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
-{CCODE_CYPRUS, {'C','Y'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0}
- , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 20, 0, 20, 0, 20, 20, 20, 20, 20, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 0, 0, 0, 0, 0} },
-{CCODE_CZECH, {'C','Z'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
- , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 20, 0, 20, 0, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
-{CCODE_DENMARK, {'D','K'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0}
- , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 20, 0, 20, 0, 20, 20, 20, 20, 20, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 0, 0, 0, 0, 0} },
-{CCODE_DOMINICAN_REPUBLIC, {'D','O'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1}
- , { 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 0, 17, 0, 17, 0, 17, 23, 23, 23, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 30, 30, 30, 30} },
-{CCODE_ECUADOR, {'E','C'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
- , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
-{CCODE_EGYPT, {'E','G'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
- , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
-{CCODE_EL_SALVADOR, {'S','V'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
- , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
-{CCODE_ESTONIA, {'E','E'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0}
- , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 20, 0, 20, 0, 20, 20, 20, 20, 20, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 0, 0, 0, 0, 0} },
-{CCODE_FINLAND, {'F','I'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0}
- , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 20, 0, 20, 0, 20, 20, 20, 20, 20, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 0, 0, 0, 0, 0} },
-{CCODE_FRANCE, {'F','R'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
- , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 20, 0, 20, 0, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
-{CCODE_GERMANY, {'D','E'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0}
- , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 20, 0, 20, 0, 20, 20, 20, 20, 20, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 0, 0, 0, 0, 0} },
-{CCODE_GREECE, {'G','R'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
- , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
-{CCODE_GEORGIA, {'G','E'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
- , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 18, 0, 18, 0, 18, 18, 18, 18, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
-{CCODE_GUATEMALA, {'G','T'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1}
- , { 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 0, 17, 0, 17, 0, 17, 23, 23, 23, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 30, 30, 30, 30} },
-{CCODE_HONDURAS, {'H','N'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
- , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
-{CCODE_HONG_KONG, {'H','K'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1}
- , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 23, 0, 23, 0, 23, 0, 23, 23, 23, 23, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 30, 30, 30, 30} },
-{CCODE_HUNGARY, {'H','U'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
- , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 18, 0, 18, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
-{CCODE_ICELAND, {'I','S'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0}
- , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 20, 0, 20, 0, 20, 20, 20, 20, 20, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 0, 0, 0, 0, 0} },
-{CCODE_INDIA, {'I','N'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
- , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
-{CCODE_INDONESIA, {'I','D'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
- , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
-{CCODE_IRAN, {'I','R'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 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, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1}
- , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 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, 30, 30, 30, 30, 30} },
-{CCODE_IRELAND, {'I','E'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0}
- , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 20, 0, 20, 0, 20, 20, 20, 20, 20, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 0, 0, 0, 0, 0} },
-{CCODE_ITALY, {'I','T'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0}
- , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 20, 0, 20, 0, 20, 20, 20, 20, 20, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 0, 0, 0, 0, 0} },
-{CCODE_ISRAEL, {'I','L'}, { 0, 0, 0, 0, 1, 1, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
- , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
-{CCODE_JAPAN, {'J','P'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
- , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 23, 0, 23, 0, 23, 0, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
-{CCODE_JORDAN, {'J','O'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
- , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
-{CCODE_KAZAKHSTAN, {'K','Z'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
- , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
-{CCODE_KUWAIT, {'K','W'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
- , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
-{CCODE_LATVIA, {'L','V'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
- , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
-{CCODE_LEBANON, {'L','B'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
- , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
-{CCODE_LEICHTENSTEIN, {'L','I'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
- , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 18, 0, 18, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
-{CCODE_LITHUANIA, {'L','T'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0}
- , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 20, 0, 20, 0, 20, 20, 20, 20, 20, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 0, 0, 0, 0, 0} },
-{CCODE_LUXEMBURG, {'L','U'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0}
- , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 20, 0, 20, 0, 20, 20, 20, 20, 20, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 0, 0, 0, 0, 0} },
-{CCODE_MACAU, {'M','O'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1}
- , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 23, 0, 23, 0, 23, 0, 23, 23, 23, 23, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 30, 30, 30, 30} },
-{CCODE_MACEDONIA, {'M','K'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
- , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
-{CCODE_MALTA, {'M','T'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0}
- , { 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 16, 0, 16, 0, 16, 16, 16, 16, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 16, 16, 16, 0} },
-{CCODE_MALAYSIA, {'M','Y'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
- , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
-{CCODE_MEXICO, {'M','X'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1}
- , { 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 0, 17, 0, 17, 0, 17, 23, 23, 23, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 30, 30, 30, 30} },
-{CCODE_MONACO, {'M','C'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
- , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 18, 0, 18, 0, 18, 18, 18, 18, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
-{CCODE_MOROCCO, {'M','A'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
- , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
-{CCODE_NETHERLANDS, {'N','L'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0}
- , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 20, 0, 20, 0, 20, 20, 20, 20, 20, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 0, 0, 0, 0, 0} },
-{CCODE_NEW_ZEALAND, {'N','Z'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1}
- , { 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 23, 0, 23, 0, 23, 0, 23, 23, 23, 23, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 30, 30, 30, 30} },
-{CCODE_NORTH_KOREA, {'K','P'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 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, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0}
- , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 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, 23, 23, 23, 23, 0} },
-{CCODE_NORWAY, {'N','O'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0}
- , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 20, 0, 20, 0, 20, 20, 20, 20, 20, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 0, 0, 0, 0, 0} },
-{CCODE_OMAN, {'O','M'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
- , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
-{CCODE_PAKISTAN, {'P','K'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
- , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
-{CCODE_PANAMA, {'P','A'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1}
- , { 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 0, 17, 0, 17, 0, 17, 23, 23, 23, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 30, 30, 30, 30} },
-{CCODE_PERU, {'P','E'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
- , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
-{CCODE_PHILIPPINES, {'P','H'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1}
- , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 0, 17, 0, 17, 0, 17, 23, 23, 23, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 30, 30, 30, 30} },
-{CCODE_POLAND, {'P','L'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0}
- , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 20, 0, 20, 0, 20, 20, 20, 20, 20, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 0, 0, 0, 0, 0} },
-{CCODE_PORTUGAL, {'P','T'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0}
- , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 20, 0, 20, 0, 20, 20, 20, 20, 20, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 0, 0, 0, 0, 0} },
-{CCODE_PUERTO_RICO, {'P','R'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1}
- , { 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 0, 17, 0, 17, 0, 17, 23, 23, 23, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 30, 30, 30, 30} },
-{CCODE_QATAR, {'Q','A'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
- , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
-{CCODE_ROMANIA, {'R','O'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
- , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
-{CCODE_RUSSIA, {'R','U'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
- , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
-{CCODE_SAUDI_ARABIA, {'S','A'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
- , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
-{CCODE_SINGAPORE, {'S','G'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1}
- , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 20, 0, 20, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 20, 20, 20, 20} },
-{CCODE_SLOVAKIA, {'S','K'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0}
- , { 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 16, 0, 16, 0, 16, 16, 16, 16, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 16, 16, 16, 0} },
-{CCODE_SLOVENIA, {'S','I'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0}
- , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 20, 0, 20, 0, 20, 20, 20, 20, 20, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 0, 0, 0, 0, 0} },
-{CCODE_SOUTH_AFRICA, {'Z','A'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0}
- , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 20, 0, 20, 0, 20, 20, 20, 20, 20, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 0, 0, 0, 0, 0} },
-{CCODE_SOUTH_KOREA, {'K','R'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 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, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0}
- , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 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, 23, 23, 23, 23, 0} },
-{CCODE_SPAIN, {'E','S'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0}
- , { 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 16, 0, 16, 0, 16, 16, 16, 16, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 16, 16, 16, 0} },
-{CCODE_SWEDEN, {'S','E'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0}
- , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 20, 0, 20, 0, 20, 20, 20, 20, 20, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 0, 0, 0, 0, 0} },
-{CCODE_SWITZERLAND, {'C','H'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
- , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 18, 0, 18, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
-{CCODE_SYRIA, {'S','Y'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
- , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
-{CCODE_TAIWAN, {'T','W'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 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, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0}
- , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 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, 17, 17, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 30, 30, 30, 0} },
-{CCODE_THAILAND, {'T','H'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 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, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0}
- , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 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, 23, 23, 23, 23, 0} },
-{CCODE_TRINIDAD_TOBAGO, {'T','T'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
- , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 18, 0, 18, 0, 18, 18, 18, 18, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
-{CCODE_TUNISIA, {'T','N'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
- , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 20, 0, 20, 0, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
-{CCODE_TURKEY, {'T','R'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
- , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 20, 0, 20, 0, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
-{CCODE_UK, {'G','B'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0}
- , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 20, 0, 20, 0, 20, 20, 20, 20, 20, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 0, 0, 0, 0, 0} },
-{CCODE_UKRAINE, {'U','A'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
- , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
-{CCODE_UNITED_ARAB_EMIRATES, {'A','E'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
- , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
-{CCODE_UNITED_STATES, {'U','S'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1}
- , { 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 0, 17, 0, 17, 0, 17, 23, 23, 23, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 30, 30, 30, 30} },
-{CCODE_URUGUAY, {'U','Y'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 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, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0}
- , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 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, 23, 23, 23, 23, 0} },
-{CCODE_UZBEKISTAN, {'U','Z'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
- , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
-{CCODE_VENEZUELA, {'V','E'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 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, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0}
- , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 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, 23, 23, 23, 23, 0} },
-{CCODE_VIETNAM, {'V','N'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
- , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
-{CCODE_YEMEN, {'Y','E'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
- , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
-{CCODE_ZIMBABWE, {'Z','W'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
- , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
-{CCODE_JAPAN_W52_W53, {'J','J'}, { 0, 0, 0, 0, 0, 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, 1, 0, 1, 0, 1, 1, 1, 1, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
-{CCODE_MAX, {'U','N'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }
-/* 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 */
-};
-
/*--------------------- Static Functions --------------------------*/
static
void
s_vCaculateOFDMRParameter(
- BYTE byRate,
+ unsigned char byRate,
CARD_PHY_TYPE ePHYType,
- PBYTE pbyTxRate,
- PBYTE pbyRsvTime
+ unsigned char *pbyTxRate,
+ unsigned char *pbyRsvTime
);
-/*--------------------- Export Variables --------------------------*/
-
/*--------------------- Export Functions --------------------------*/
-
-/*--------------------- Export function -------------------------*/
-/************************************************************************
- * Country Channel Valid
- * Input: CountryCode, ChannelNum
- * ChanneIndex is defined as VT3253 MAC channel:
- * 1 = 2.4G channel 1
- * 2 = 2.4G channel 2
- * ...
- * 14 = 2.4G channel 14
- * 15 = 4.9G channel 183
- * 16 = 4.9G channel 184
- * .....
- * Output: TRUE if the specified 5GHz band is allowed to be used.
- False otherwise.
-// 4.9G => Ch 183, 184, 185, 187, 188, 189, 192, 196 (Value:15 ~ 22)
-
-// 5G => Ch 7, 8, 9, 11, 12, 16, 34, 36, 38, 40, 42, 44, 46, 48, 52, 56, 60, 64,
-// 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140, 149, 153, 157, 161, 165 (Value 23 ~ 56)
- ************************************************************************/
-//2008-8-4 <add> by chester
-BOOL
-ChannelValid(UINT CountryCode, UINT ChannelIndex)
-{
- BOOL bValid;
-
- bValid = FALSE;
- /*
- * If Channel Index is invalid, return invalid
- */
- if ((ChannelIndex > CB_MAX_CHANNEL) ||
- (ChannelIndex == 0))
- {
- bValid = FALSE;
- goto exit;
- }
-
- bValid = sChannelTbl[ChannelIndex].bValid;
-
-exit:
- return (bValid);
-
-} /* end ChannelValid */
-
-
/*
* Description: Caculate TxRate and RsvTime fields for RSPINF in OFDM mode.
*
@@ -498,10 +127,10 @@ exit:
static
void
s_vCaculateOFDMRParameter (
- BYTE byRate,
+ unsigned char byRate,
CARD_PHY_TYPE ePHYType,
- PBYTE pbyTxRate,
- PBYTE pbyRsvTime
+ unsigned char *pbyTxRate,
+ unsigned char *pbyRsvTime
)
{
switch (byRate) {
@@ -614,9 +243,9 @@ static
void
s_vSetRSPINF (PSDevice pDevice, CARD_PHY_TYPE ePHYType, void *pvSupportRateIEs, void *pvExtSupportRateIEs)
{
- BYTE byServ = 0, bySignal = 0; // For CCK
- WORD wLen = 0;
- BYTE byTxRate = 0, byRsvTime = 0; // For OFDM
+ unsigned char byServ = 0, bySignal = 0; // For CCK
+ unsigned short wLen = 0;
+ unsigned char byTxRate = 0, byRsvTime = 0; // For OFDM
//Set to Page1
MACvSelectPage1(pDevice->PortOffset);
@@ -722,120 +351,7 @@ s_vSetRSPINF (PSDevice pDevice, CARD_PHY_TYPE ePHYType, void *pvSupportRateIEs,
MACvSelectPage0(pDevice->PortOffset);
}
-
-
-
-/*--------------------- Export Variables --------------------------*/
-
/*--------------------- Export Functions --------------------------*/
-BYTE CARDbyGetChannelMapping (void *pDeviceHandler, BYTE byChannelNumber, CARD_PHY_TYPE ePhyType)
-{
- UINT ii;
-
- if ((ePhyType == PHY_TYPE_11B) || (ePhyType == PHY_TYPE_11G)) {
- return (byChannelNumber);
- }
-
- for(ii = (CB_MAX_CHANNEL_24G + 1); ii <= CB_MAX_CHANNEL; ) {
- if (sChannelTbl[ii].byChannelNumber == byChannelNumber) {
- return ((BYTE) ii);
- }
- ii++;
- }
- return (0);
-}
-
-
-BYTE CARDbyGetChannelNumber (void *pDeviceHandler, BYTE byChannelIndex)
-{
-// PSDevice pDevice = (PSDevice) pDeviceHandler;
- return(sChannelTbl[byChannelIndex].byChannelNumber);
-}
-
-/*
- * Description: Set NIC media channel
- *
- * Parameters:
- * In:
- * pDeviceHandler - The adapter to be set
- * uConnectionChannel - Channel to be set
- * Out:
- * none
- *
- * Return Value: TRUE if succeeded; FALSE if failed.
- *
- */
-BOOL CARDbSetChannel (void *pDeviceHandler, UINT uConnectionChannel)
-{
- PSDevice pDevice = (PSDevice) pDeviceHandler;
- BOOL bResult = TRUE;
-
-
- if (pDevice->byCurrentCh == uConnectionChannel) {
- return bResult;
- }
-
- if (sChannelTbl[uConnectionChannel].bValid == FALSE) {
- return (FALSE);
- }
-
- if ((uConnectionChannel > CB_MAX_CHANNEL_24G) &&
- (pDevice->eCurrentPHYType != PHY_TYPE_11A)) {
- CARDbSetPhyParameter(pDevice, PHY_TYPE_11A, 0, 0, NULL, NULL);
- } else if ((uConnectionChannel <= CB_MAX_CHANNEL_24G) &&
- (pDevice->eCurrentPHYType == PHY_TYPE_11A)) {
- CARDbSetPhyParameter(pDevice, PHY_TYPE_11G, 0, 0, NULL, NULL);
- }
- // clear NAV
- MACvRegBitsOn(pDevice->PortOffset, MAC_REG_MACCR, MACCR_CLRNAV);
-
- //{{ RobertYu: 20041202
- //// TX_PE will reserve 3 us for MAX2829 A mode only, it is for better TX throughput
-
- if ( pDevice->byRFType == RF_AIROHA7230 )
- {
- RFbAL7230SelectChannelPostProcess(pDevice->PortOffset, pDevice->byCurrentCh, (BYTE)uConnectionChannel);
- }
- //}} RobertYu
-
-
- pDevice->byCurrentCh = (BYTE)uConnectionChannel;
- bResult &= RFbSelectChannel(pDevice->PortOffset, pDevice->byRFType, (BYTE)uConnectionChannel);
-
- // Init Synthesizer Table
- if (pDevice->bEnablePSMode == TRUE)
- RFvWriteWakeProgSyn(pDevice->PortOffset, pDevice->byRFType, uConnectionChannel);
-
-
- //DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"CARDbSetMediaChannel: %d\n", (BYTE)uConnectionChannel);
- BBvSoftwareReset(pDevice->PortOffset);
-
- if (pDevice->byLocalID > REV_ID_VT3253_B1) {
- // set HW default power register
- MACvSelectPage1(pDevice->PortOffset);
- RFbSetPower(pDevice, RATE_1M, pDevice->byCurrentCh);
- VNSvOutPortB(pDevice->PortOffset + MAC_REG_PWRCCK, pDevice->byCurPwr);
- RFbSetPower(pDevice, RATE_6M, pDevice->byCurrentCh);
- VNSvOutPortB(pDevice->PortOffset + MAC_REG_PWROFDM, pDevice->byCurPwr);
- MACvSelectPage0(pDevice->PortOffset);
- }
-
- if (pDevice->eCurrentPHYType == PHY_TYPE_11B) {
-#ifdef PLICE_DEBUG
- //printk("Func:CARDbSetChannel:call RFbSetPower:11B\n");
-#endif
- RFbSetPower(pDevice, RATE_1M, pDevice->byCurrentCh);
- } else {
-#ifdef PLICE_DEBUG
- //printk("Func:CARDbSetChannel:call RFbSetPower\n");
-#endif
- RFbSetPower(pDevice, RATE_6M, pDevice->byCurrentCh);
- }
-
- return(bResult);
-}
-
-
/*
* Description: Card Send packet function
@@ -849,11 +365,11 @@ BOOL CARDbSetChannel (void *pDeviceHandler, UINT uConnectionChannel)
* Out:
* none
*
- * Return Value: TRUE if succeeded; FALSE if failed.
+ * Return Value: true if succeeded; false if failed.
*
*/
/*
-BOOL CARDbSendPacket (void *pDeviceHandler, void *pPacket, CARD_PKT_TYPE ePktType, UINT uLength)
+bool CARDbSendPacket (void *pDeviceHandler, void *pPacket, CARD_PKT_TYPE ePktType, unsigned int uLength)
{
PSDevice pDevice = (PSDevice) pDeviceHandler;
if (ePktType == PKT_TYPE_802_11_MNG) {
@@ -864,7 +380,7 @@ BOOL CARDbSendPacket (void *pDeviceHandler, void *pPacket, CARD_PKT_TYPE ePktTyp
return TXbTD1Send(pDevice, pPacket, uLength);
}
- return (TRUE);
+ return (true);
}
*/
@@ -878,16 +394,16 @@ BOOL CARDbSendPacket (void *pDeviceHandler, void *pPacket, CARD_PKT_TYPE ePktTyp
* Out:
* none
*
- * Return Value: TRUE if short preamble; otherwise FALSE
+ * Return Value: true if short preamble; otherwise false
*
*/
-BOOL CARDbIsShortPreamble (void *pDeviceHandler)
+bool CARDbIsShortPreamble (void *pDeviceHandler)
{
PSDevice pDevice = (PSDevice) pDeviceHandler;
if (pDevice->byPreambleType == 0) {
- return(FALSE);
+ return(false);
}
- return(TRUE);
+ return(true);
}
/*
@@ -899,10 +415,10 @@ BOOL CARDbIsShortPreamble (void *pDeviceHandler)
* Out:
* none
*
- * Return Value: TRUE if short slot time; otherwise FALSE
+ * Return Value: true if short slot time; otherwise false
*
*/
-BOOL CARDbIsShorSlotTime (void *pDeviceHandler)
+bool CARDbIsShorSlotTime (void *pDeviceHandler)
{
PSDevice pDevice = (PSDevice) pDeviceHandler;
return(pDevice->bShortSlotTime);
@@ -921,14 +437,14 @@ BOOL CARDbIsShorSlotTime (void *pDeviceHandler)
* Return Value: None.
*
*/
-BOOL CARDbSetPhyParameter (void *pDeviceHandler, CARD_PHY_TYPE ePHYType, WORD wCapInfo, BYTE byERPField, void *pvSupportRateIEs, void *pvExtSupportRateIEs)
+bool CARDbSetPhyParameter (void *pDeviceHandler, CARD_PHY_TYPE ePHYType, unsigned short wCapInfo, unsigned char byERPField, void *pvSupportRateIEs, void *pvExtSupportRateIEs)
{
PSDevice pDevice = (PSDevice) pDeviceHandler;
- BYTE byCWMaxMin = 0;
- BYTE bySlot = 0;
- BYTE bySIFS = 0;
- BYTE byDIFS = 0;
- BYTE byData;
+ unsigned char byCWMaxMin = 0;
+ unsigned char bySlot = 0;
+ unsigned char bySIFS = 0;
+ unsigned char byDIFS = 0;
+ unsigned char byData;
// PWLAN_IE_SUPP_RATES pRates = NULL;
PWLAN_IE_SUPP_RATES pSupportRates = (PWLAN_IE_SUPP_RATES) pvSupportRateIEs;
PWLAN_IE_SUPP_RATES pExtSupportRates = (PWLAN_IE_SUPP_RATES) pvExtSupportRateIEs;
@@ -1071,9 +587,9 @@ BOOL CARDbSetPhyParameter (void *pDeviceHandler, CARD_PHY_TYPE ePHYType, WORD wC
pDevice->bySlot = bySlot;
VNSvOutPortB(pDevice->PortOffset + MAC_REG_SLOT, pDevice->bySlot);
if (pDevice->bySlot == C_SLOT_SHORT) {
- pDevice->bShortSlotTime = TRUE;
+ pDevice->bShortSlotTime = true;
} else {
- pDevice->bShortSlotTime = FALSE;
+ pDevice->bShortSlotTime = false;
}
BBvSetShortSlotTime(pDevice);
}
@@ -1089,7 +605,7 @@ BOOL CARDbSetPhyParameter (void *pDeviceHandler, CARD_PHY_TYPE ePHYType, WORD wC
s_vSetRSPINF(pDevice, ePHYType, pSupportRates, pExtSupportRates);
pDevice->eCurrentPHYType = ePHYType;
// set for NDIS OID_802_11SUPPORTED_RATES
- return (TRUE);
+ return (true);
}
/*
@@ -1108,7 +624,7 @@ BOOL CARDbSetPhyParameter (void *pDeviceHandler, CARD_PHY_TYPE ePHYType, WORD wC
* Return Value: none
*
*/
-BOOL CARDbUpdateTSF (void *pDeviceHandler, BYTE byRxRate, QWORD qwBSSTimestamp, QWORD qwLocalTSF)
+bool CARDbUpdateTSF (void *pDeviceHandler, unsigned char byRxRate, QWORD qwBSSTimestamp, QWORD qwLocalTSF)
{
PSDevice pDevice = (PSDevice) pDeviceHandler;
QWORD qwTSFOffset;
@@ -1125,7 +641,7 @@ BOOL CARDbUpdateTSF (void *pDeviceHandler, BYTE byRxRate, QWORD qwBSSTimestamp,
VNSvOutPortD(pDevice->PortOffset + MAC_REG_TSFOFST + 4, HIDWORD(qwTSFOffset));
MACvRegBitsOn(pDevice->PortOffset, MAC_REG_TFTCTL, TFTCTL_TSFSYNCEN);
}
- return(TRUE);
+ return(true);
}
@@ -1140,16 +656,16 @@ BOOL CARDbUpdateTSF (void *pDeviceHandler, BYTE byRxRate, QWORD qwBSSTimestamp,
* Out:
* none
*
- * Return Value: TRUE if succeed; otherwise FALSE
+ * Return Value: true if succeed; otherwise false
*
*/
-BOOL CARDbSetBeaconPeriod (void *pDeviceHandler, WORD wBeaconInterval)
+bool CARDbSetBeaconPeriod (void *pDeviceHandler, unsigned short wBeaconInterval)
{
PSDevice pDevice = (PSDevice) pDeviceHandler;
- UINT uBeaconInterval = 0;
- UINT uLowNextTBTT = 0;
- UINT uHighRemain = 0;
- UINT uLowRemain = 0;
+ unsigned int uBeaconInterval = 0;
+ unsigned int uLowNextTBTT = 0;
+ unsigned int uHighRemain = 0;
+ unsigned int uLowRemain = 0;
QWORD qwNextTBTT;
HIDWORD(qwNextTBTT) = 0;
@@ -1179,7 +695,7 @@ BOOL CARDbSetBeaconPeriod (void *pDeviceHandler, WORD wBeaconInterval)
VNSvOutPortD(pDevice->PortOffset + MAC_REG_NEXTTBTT + 4, HIDWORD(qwNextTBTT));
MACvRegBitsOn(pDevice->PortOffset, MAC_REG_TFTCTL, TFTCTL_TBTTSYNCEN);
- return(TRUE);
+ return(true);
}
@@ -1194,51 +710,51 @@ BOOL CARDbSetBeaconPeriod (void *pDeviceHandler, WORD wBeaconInterval)
* Out:
* none
*
- * Return Value: TRUE if all data packet complete; otherwise FALSE.
+ * Return Value: true if all data packet complete; otherwise false.
*
*/
-BOOL CARDbStopTxPacket (void *pDeviceHandler, CARD_PKT_TYPE ePktType)
+bool CARDbStopTxPacket (void *pDeviceHandler, CARD_PKT_TYPE ePktType)
{
PSDevice pDevice = (PSDevice) pDeviceHandler;
if (ePktType == PKT_TYPE_802_11_ALL) {
- pDevice->bStopBeacon = TRUE;
- pDevice->bStopTx0Pkt = TRUE;
- pDevice->bStopDataPkt = TRUE;
+ pDevice->bStopBeacon = true;
+ pDevice->bStopTx0Pkt = true;
+ pDevice->bStopDataPkt = true;
} else if (ePktType == PKT_TYPE_802_11_BCN) {
- pDevice->bStopBeacon = TRUE;
+ pDevice->bStopBeacon = true;
} else if (ePktType == PKT_TYPE_802_11_MNG) {
- pDevice->bStopTx0Pkt = TRUE;
+ pDevice->bStopTx0Pkt = true;
} else if (ePktType == PKT_TYPE_802_11_DATA) {
- pDevice->bStopDataPkt = TRUE;
+ pDevice->bStopDataPkt = true;
}
- if (pDevice->bStopBeacon == TRUE) {
- if (pDevice->bIsBeaconBufReadySet == TRUE) {
+ if (pDevice->bStopBeacon == true) {
+ if (pDevice->bIsBeaconBufReadySet == true) {
if (pDevice->cbBeaconBufReadySetCnt < WAIT_BEACON_TX_DOWN_TMO) {
pDevice->cbBeaconBufReadySetCnt ++;
- return(FALSE);
+ return(false);
}
}
- pDevice->bIsBeaconBufReadySet = FALSE;
+ pDevice->bIsBeaconBufReadySet = false;
pDevice->cbBeaconBufReadySetCnt = 0;
MACvRegBitsOff(pDevice->PortOffset, MAC_REG_TCR, TCR_AUTOBCNTX);
}
// wait all TD0 complete
- if (pDevice->bStopTx0Pkt == TRUE) {
+ if (pDevice->bStopTx0Pkt == true) {
if (pDevice->iTDUsed[TYPE_TXDMA0] != 0){
- return(FALSE);
+ return(false);
}
}
// wait all Data TD complete
- if (pDevice->bStopDataPkt == TRUE) {
+ if (pDevice->bStopDataPkt == true) {
if (pDevice->iTDUsed[TYPE_AC0DMA] != 0){
- return(FALSE);
+ return(false);
}
}
- return(TRUE);
+ return(true);
}
@@ -1252,33 +768,33 @@ BOOL CARDbStopTxPacket (void *pDeviceHandler, CARD_PKT_TYPE ePktType)
* Out:
* none
*
- * Return Value: TRUE if success; FALSE if failed.
+ * Return Value: true if success; false if failed.
*
*/
-BOOL CARDbStartTxPacket (void *pDeviceHandler, CARD_PKT_TYPE ePktType)
+bool CARDbStartTxPacket (void *pDeviceHandler, CARD_PKT_TYPE ePktType)
{
PSDevice pDevice = (PSDevice) pDeviceHandler;
if (ePktType == PKT_TYPE_802_11_ALL) {
- pDevice->bStopBeacon = FALSE;
- pDevice->bStopTx0Pkt = FALSE;
- pDevice->bStopDataPkt = FALSE;
+ pDevice->bStopBeacon = false;
+ pDevice->bStopTx0Pkt = false;
+ pDevice->bStopDataPkt = false;
} else if (ePktType == PKT_TYPE_802_11_BCN) {
- pDevice->bStopBeacon = FALSE;
+ pDevice->bStopBeacon = false;
} else if (ePktType == PKT_TYPE_802_11_MNG) {
- pDevice->bStopTx0Pkt = FALSE;
+ pDevice->bStopTx0Pkt = false;
} else if (ePktType == PKT_TYPE_802_11_DATA) {
- pDevice->bStopDataPkt = FALSE;
+ pDevice->bStopDataPkt = false;
}
- if ((pDevice->bStopBeacon == FALSE) &&
- (pDevice->bBeaconBufReady == TRUE) &&
+ if ((pDevice->bStopBeacon == false) &&
+ (pDevice->bBeaconBufReady == true) &&
(pDevice->eOPMode == OP_MODE_ADHOC)) {
MACvRegBitsOn(pDevice->PortOffset, MAC_REG_TCR, TCR_AUTOBCNTX);
}
- return(TRUE);
+ return(true);
}
@@ -1294,10 +810,10 @@ BOOL CARDbStartTxPacket (void *pDeviceHandler, CARD_PKT_TYPE ePktType)
* Out:
* none
*
- * Return Value: TRUE if success; FALSE if failed.
+ * Return Value: true if success; false if failed.
*
*/
-BOOL CARDbSetBSSID(void *pDeviceHandler, PBYTE pbyBSSID, CARD_OP_MODE eOPMode)
+bool CARDbSetBSSID(void *pDeviceHandler, unsigned char *pbyBSSID, CARD_OP_MODE eOPMode)
{
PSDevice pDevice = (PSDevice) pDeviceHandler;
@@ -1315,20 +831,20 @@ BOOL CARDbSetBSSID(void *pDeviceHandler, PBYTE pbyBSSID, CARD_OP_MODE eOPMode)
}
if (eOPMode == OP_MODE_UNKNOWN) {
MACvRegBitsOff(pDevice->PortOffset, MAC_REG_RCR, RCR_BSSID);
- pDevice->bBSSIDFilter = FALSE;
+ pDevice->bBSSIDFilter = false;
pDevice->byRxMode &= ~RCR_BSSID;
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "wcmd: rx_mode = %x\n", pDevice->byRxMode );
} else {
- if (IS_NULL_ADDRESS(pDevice->abyBSSID) == FALSE) {
+ if (is_zero_ether_addr(pDevice->abyBSSID) == false) {
MACvRegBitsOn(pDevice->PortOffset, MAC_REG_RCR, RCR_BSSID);
- pDevice->bBSSIDFilter = TRUE;
+ pDevice->bBSSIDFilter = true;
pDevice->byRxMode |= RCR_BSSID;
}
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "wmgr: rx_mode = %x\n", pDevice->byRxMode );
}
// Adopt BSS state in Adapter Device Object
pDevice->eOPMode = eOPMode;
- return(TRUE);
+ return(true);
}
@@ -1342,7 +858,7 @@ BOOL CARDbSetBSSID(void *pDeviceHandler, PBYTE pbyBSSID, CARD_OP_MODE eOPMode)
* Out:
* none
*
- * Return Value: TRUE if success; FALSE if failed.
+ * Return Value: true if success; false if failed.
*
*/
@@ -1363,18 +879,18 @@ BOOL CARDbSetBSSID(void *pDeviceHandler, PBYTE pbyBSSID, CARD_OP_MODE eOPMode)
* Out:
* none
*
- * Return Value: TRUE if succeed; otherwise FALSE
+ * Return Value: true if succeed; otherwise false
*
*/
-BOOL CARDbSetTxDataRate(
+bool CARDbSetTxDataRate(
void *pDeviceHandler,
- WORD wDataRate
+ unsigned short wDataRate
)
{
PSDevice pDevice = (PSDevice) pDeviceHandler;
pDevice->wCurrentRate = wDataRate;
- return(TRUE);
+ return(true);
}
/*+
@@ -1388,20 +904,20 @@ BOOL CARDbSetTxDataRate(
* Out:
* none
*
- * Return Value: TRUE if power down success; otherwise FALSE
+ * Return Value: true if power down success; otherwise false
*
-*/
-BOOL
+bool
CARDbPowerDown(
void *pDeviceHandler
)
{
PSDevice pDevice = (PSDevice)pDeviceHandler;
- UINT uIdx;
+ unsigned int uIdx;
// check if already in Doze mode
if (MACbIsRegBitsOn(pDevice->PortOffset, MAC_REG_PSCTL, PSCTL_PS))
- return TRUE;
+ return true;
// Froce PSEN on
MACvRegBitsOn(pDevice->PortOffset, MAC_REG_PSCTL, PSCTL_PSEN);
@@ -1410,12 +926,12 @@ CARDbPowerDown(
for (uIdx = 0; uIdx < TYPE_MAXTD; uIdx ++) {
if (pDevice->iTDUsed[uIdx] != 0)
- return FALSE;
+ return false;
}
MACvRegBitsOn(pDevice->PortOffset, MAC_REG_PSCTL, PSCTL_GO2DOZE);
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Go to Doze ZZZZZZZZZZZZZZZ\n");
- return TRUE;
+ return true;
}
/*
@@ -1427,16 +943,16 @@ CARDbPowerDown(
* Out:
* none
*
- * Return Value: TRUE if success; otherwise FALSE
+ * Return Value: true if success; otherwise false
*
*/
-BOOL CARDbRadioPowerOff (void *pDeviceHandler)
+bool CARDbRadioPowerOff (void *pDeviceHandler)
{
PSDevice pDevice = (PSDevice) pDeviceHandler;
- BOOL bResult = TRUE;
+ bool bResult = true;
- if (pDevice->bRadioOff == TRUE)
- return TRUE;
+ if (pDevice->bRadioOff == true)
+ return true;
switch (pDevice->byRFType) {
@@ -1459,7 +975,7 @@ BOOL CARDbRadioPowerOff (void *pDeviceHandler)
BBvSetDeepSleep(pDevice->PortOffset, pDevice->byLocalID);
- pDevice->bRadioOff = TRUE;
+ pDevice->bRadioOff = true;
//2007-0409-03,<Add> by chester
printk("chester power off\n");
MACvRegBitsOn(pDevice->PortOffset, MAC_REG_GPIOCTL0, LED_ACTSET); //LED issue
@@ -1476,23 +992,23 @@ MACvRegBitsOn(pDevice->PortOffset, MAC_REG_GPIOCTL0, LED_ACTSET); //LED issue
* Out:
* none
*
- * Return Value: TRUE if success; otherwise FALSE
+ * Return Value: true if success; otherwise false
*
*/
-BOOL CARDbRadioPowerOn (void *pDeviceHandler)
+bool CARDbRadioPowerOn (void *pDeviceHandler)
{
PSDevice pDevice = (PSDevice) pDeviceHandler;
- BOOL bResult = TRUE;
+ bool bResult = true;
printk("chester power on\n");
- if (pDevice->bRadioControlOff == TRUE){
-if (pDevice->bHWRadioOff == TRUE) printk("chester bHWRadioOff\n");
-if (pDevice->bRadioControlOff == TRUE) printk("chester bRadioControlOff\n");
- return FALSE;}
+ if (pDevice->bRadioControlOff == true){
+if (pDevice->bHWRadioOff == true) printk("chester bHWRadioOff\n");
+if (pDevice->bRadioControlOff == true) printk("chester bRadioControlOff\n");
+ return false;}
- if (pDevice->bRadioOff == FALSE)
+ if (pDevice->bRadioOff == false)
{
printk("chester pbRadioOff\n");
-return TRUE;}
+return true;}
BBvExitDeepSleep(pDevice->PortOffset, pDevice->byLocalID);
@@ -1514,7 +1030,7 @@ return TRUE;}
}
- pDevice->bRadioOff = FALSE;
+ pDevice->bRadioOff = false;
// 2007-0409-03,<Add> by chester
printk("chester power on\n");
MACvRegBitsOff(pDevice->PortOffset, MAC_REG_GPIOCTL0, LED_ACTSET); //LED issue
@@ -1523,12 +1039,12 @@ MACvRegBitsOff(pDevice->PortOffset, MAC_REG_GPIOCTL0, LED_ACTSET); //LED issue
-BOOL CARDbRemoveKey (void *pDeviceHandler, PBYTE pbyBSSID)
+bool CARDbRemoveKey (void *pDeviceHandler, unsigned char *pbyBSSID)
{
PSDevice pDevice = (PSDevice) pDeviceHandler;
KeybRemoveAllKey(&(pDevice->sKey), pbyBSSID, pDevice->PortOffset);
- return (TRUE);
+ return (true);
}
@@ -1548,17 +1064,17 @@ BOOL CARDbRemoveKey (void *pDeviceHandler, PBYTE pbyBSSID)
* Return Value: none.
*
-*/
-BOOL
+bool
CARDbAdd_PMKID_Candidate (
void *pDeviceHandler,
- PBYTE pbyBSSID,
- BOOL bRSNCapExist,
- WORD wRSNCap
+ unsigned char *pbyBSSID,
+ bool bRSNCapExist,
+ unsigned short wRSNCap
)
{
PSDevice pDevice = (PSDevice) pDeviceHandler;
PPMKID_CANDIDATE pCandidateList;
- UINT ii = 0;
+ unsigned int ii = 0;
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"bAdd_PMKID_Candidate START: (%d)\n", (int)pDevice->gsPMKIDCandidate.NumCandidates);
@@ -1577,18 +1093,18 @@ CARDbAdd_PMKID_Candidate (
for (ii = 0; ii < pDevice->gsPMKIDCandidate.NumCandidates; ii++) {
pCandidateList = &pDevice->gsPMKIDCandidate.CandidateList[ii];
if ( !memcmp(pCandidateList->BSSID, pbyBSSID, ETH_ALEN)) {
- if ((bRSNCapExist == TRUE) && (wRSNCap & BIT0)) {
+ if ((bRSNCapExist == true) && (wRSNCap & BIT0)) {
pCandidateList->Flags |= NDIS_802_11_PMKID_CANDIDATE_PREAUTH_ENABLED;
} else {
pCandidateList->Flags &= ~(NDIS_802_11_PMKID_CANDIDATE_PREAUTH_ENABLED);
}
- return TRUE;
+ return true;
}
}
// New Candidate
pCandidateList = &pDevice->gsPMKIDCandidate.CandidateList[pDevice->gsPMKIDCandidate.NumCandidates];
- if ((bRSNCapExist == TRUE) && (wRSNCap & BIT0)) {
+ if ((bRSNCapExist == true) && (wRSNCap & BIT0)) {
pCandidateList->Flags |= NDIS_802_11_PMKID_CANDIDATE_PREAUTH_ENABLED;
} else {
pCandidateList->Flags &= ~(NDIS_802_11_PMKID_CANDIDATE_PREAUTH_ENABLED);
@@ -1596,7 +1112,7 @@ CARDbAdd_PMKID_Candidate (
memcpy(pCandidateList->BSSID, pbyBSSID, ETH_ALEN);
pDevice->gsPMKIDCandidate.NumCandidates++;
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"NumCandidates:%d\n", (int)pDevice->gsPMKIDCandidate.NumCandidates);
- return TRUE;
+ return true;
}
void *
@@ -1609,89 +1125,6 @@ CARDpGetCurrentAddress (
return (pDevice->abyCurrentNetAddr);
}
-
-
-void CARDvInitChannelTable (void *pDeviceHandler)
-{
- PSDevice pDevice = (PSDevice) pDeviceHandler;
- BOOL bMultiBand = FALSE;
- UINT ii;
-
- for(ii=1;ii<=CARD_MAX_CHANNEL_TBL;ii++) {
- sChannelTbl[ii].bValid = FALSE;
- }
-
- switch (pDevice->byRFType) {
- case RF_RFMD2959 :
- case RF_AIROHA :
- case RF_AL2230S:
- case RF_UW2451 :
- case RF_VT3226 :
- // printk("chester-false\n");
- bMultiBand = FALSE;
- break;
- case RF_AIROHA7230 :
- case RF_UW2452 :
- case RF_NOTHING :
- default :
- bMultiBand = TRUE;
- break;
- }
-
- if ((pDevice->dwDiagRefCount != 0) ||
- (pDevice->b11hEnable == TRUE)) {
- if (bMultiBand == TRUE) {
- for(ii=0;ii<CARD_MAX_CHANNEL_TBL;ii++) {
- sChannelTbl[ii+1].bValid = TRUE;
- pDevice->abyRegPwr[ii+1] = pDevice->abyOFDMDefaultPwr[ii+1];
- pDevice->abyLocalPwr[ii+1] = pDevice->abyOFDMDefaultPwr[ii+1];
- }
- for(ii=0;ii<CHANNEL_MAX_24G;ii++) {
- pDevice->abyRegPwr[ii+1] = pDevice->abyCCKDefaultPwr[ii+1];
- pDevice->abyLocalPwr[ii+1] = pDevice->abyCCKDefaultPwr[ii+1];
- }
- } else {
- for(ii=0;ii<CHANNEL_MAX_24G;ii++) {
-//2008-8-4 <add> by chester
- if (ChannelRuleTab[pDevice->byZoneType].bChannelIdxList[ii] != 0) {
- sChannelTbl[ii+1].bValid = TRUE;
- pDevice->abyRegPwr[ii+1] = pDevice->abyCCKDefaultPwr[ii+1];
- pDevice->abyLocalPwr[ii+1] = pDevice->abyCCKDefaultPwr[ii+1];
- }
- }
- }
- } else if (pDevice->byZoneType <= CCODE_MAX) {
- if (bMultiBand == TRUE) {
- for(ii=0;ii<CARD_MAX_CHANNEL_TBL;ii++) {
- if (ChannelRuleTab[pDevice->byZoneType].bChannelIdxList[ii] != 0) {
- sChannelTbl[ii+1].bValid = TRUE;
- pDevice->abyRegPwr[ii+1] = ChannelRuleTab[pDevice->byZoneType].byPower[ii];
- pDevice->abyLocalPwr[ii+1] = ChannelRuleTab[pDevice->byZoneType].byPower[ii];
- }
- }
- } else {
- for(ii=0;ii<CHANNEL_MAX_24G;ii++) {
- if (ChannelRuleTab[pDevice->byZoneType].bChannelIdxList[ii] != 0) {
- sChannelTbl[ii+1].bValid = TRUE;
- pDevice->abyRegPwr[ii+1] = ChannelRuleTab[pDevice->byZoneType].byPower[ii];
- pDevice->abyLocalPwr[ii+1] = ChannelRuleTab[pDevice->byZoneType].byPower[ii];
- }
- }
- }
- }
- DBG_PRT(MSG_LEVEL_NOTICE, KERN_INFO"Zone=[%d][%c][%c]!!\n",pDevice->byZoneType,ChannelRuleTab[pDevice->byZoneType].chCountryCode[0],ChannelRuleTab[pDevice->byZoneType].chCountryCode[1]);
- for(ii=0;ii<CARD_MAX_CHANNEL_TBL;ii++) {
- if (pDevice->abyRegPwr[ii+1] == 0) {
- pDevice->abyRegPwr[ii+1] = pDevice->abyOFDMDefaultPwr[ii+1];
- }
- if (pDevice->abyLocalPwr[ii+1] == 0) {
- pDevice->abyLocalPwr[ii+1] = pDevice->abyOFDMDefaultPwr[ii+1];
- }
- }
-}
-
-
-
/*
*
* Description:
@@ -1706,27 +1139,27 @@ void CARDvInitChannelTable (void *pDeviceHandler)
* Return Value: none.
*
-*/
-BOOL
+bool
CARDbStartMeasure (
void *pDeviceHandler,
void *pvMeasureEIDs,
- UINT uNumOfMeasureEIDs
+ unsigned int uNumOfMeasureEIDs
)
{
PSDevice pDevice = (PSDevice) pDeviceHandler;
PWLAN_IE_MEASURE_REQ pEID = (PWLAN_IE_MEASURE_REQ) pvMeasureEIDs;
QWORD qwCurrTSF;
QWORD qwStartTSF;
- BOOL bExpired = TRUE;
- WORD wDuration = 0;
+ bool bExpired = true;
+ unsigned short wDuration = 0;
if ((pEID == NULL) ||
(uNumOfMeasureEIDs == 0)) {
- return (TRUE);
+ return (true);
}
CARDbGetCurrentTSF(pDevice->PortOffset, &qwCurrTSF);
- if (pDevice->bMeasureInProgress == TRUE) {
- pDevice->bMeasureInProgress = FALSE;
+ if (pDevice->bMeasureInProgress == true) {
+ pDevice->bMeasureInProgress = false;
VNSvOutPortB(pDevice->PortOffset + MAC_REG_RCR, pDevice->byOrgRCR);
MACvSelectPage1(pDevice->PortOffset);
VNSvOutPortD(pDevice->PortOffset + MAC_REG_MAR0, pDevice->dwOrgMAR0);
@@ -1734,7 +1167,7 @@ CARDbStartMeasure (
// clear measure control
MACvRegBitsOff(pDevice->PortOffset, MAC_REG_MSRCTL, MSRCTL_EN);
MACvSelectPage0(pDevice->PortOffset);
- CARDbSetChannel(pDevice, pDevice->byOrgChannel);
+ set_channel(pDevice, pDevice->byOrgChannel);
MACvSelectPage1(pDevice->PortOffset);
MACvRegBitsOn(pDevice->PortOffset, MAC_REG_MSRCTL+1, MSRCTL1_TXPAUSE);
MACvSelectPage0(pDevice->PortOffset);
@@ -1749,7 +1182,7 @@ CARDbStartMeasure (
if (pDevice->byLocalID > REV_ID_VT3253_B1) {
HIDWORD(qwStartTSF) = HIDWORD(*((PQWORD) (pDevice->pCurrMeasureEID->sReq.abyStartTime)));
LODWORD(qwStartTSF) = LODWORD(*((PQWORD) (pDevice->pCurrMeasureEID->sReq.abyStartTime)));
- wDuration = *((PWORD) (pDevice->pCurrMeasureEID->sReq.abyDuration));
+ wDuration = *((unsigned short *) (pDevice->pCurrMeasureEID->sReq.abyDuration));
wDuration += 1; // 1 TU for channel switching
if ((LODWORD(qwStartTSF) == 0) && (HIDWORD(qwStartTSF) == 0)) {
@@ -1759,7 +1192,7 @@ CARDbStartMeasure (
if (LODWORD(qwCurrTSF) > LODWORD(qwStartTSF)) {
HIDWORD(qwStartTSF)++;
}
- bExpired = FALSE;
+ bExpired = false;
break;
} else {
// start at setting start TSF - 1TU(for channel switching)
@@ -1773,11 +1206,11 @@ CARDbStartMeasure (
((HIDWORD(qwCurrTSF) == HIDWORD(qwStartTSF)) &&
(LODWORD(qwCurrTSF) < LODWORD(qwStartTSF)))
) {
- bExpired = FALSE;
+ bExpired = false;
break;
}
VNTWIFIbMeasureReport( pDevice->pMgmt,
- FALSE,
+ false,
pDevice->pCurrMeasureEID,
MEASURE_MODE_LATE,
pDevice->byBasicMap,
@@ -1787,7 +1220,7 @@ CARDbStartMeasure (
} else {
// hardware do not support measure
VNTWIFIbMeasureReport( pDevice->pMgmt,
- FALSE,
+ false,
pDevice->pCurrMeasureEID,
MEASURE_MODE_INCAPABLE,
pDevice->byBasicMap,
@@ -1797,7 +1230,7 @@ CARDbStartMeasure (
}
} while (pDevice->uNumOfMeasureEIDs != 0);
- if (bExpired == FALSE) {
+ if (bExpired == false) {
MACvSelectPage1(pDevice->PortOffset);
VNSvOutPortD(pDevice->PortOffset + MAC_REG_MSRSTART, LODWORD(qwStartTSF));
VNSvOutPortD(pDevice->PortOffset + MAC_REG_MSRSTART + 4, HIDWORD(qwStartTSF));
@@ -1807,7 +1240,7 @@ CARDbStartMeasure (
} else {
// all measure start time expired we should complete action
VNTWIFIbMeasureReport( pDevice->pMgmt,
- TRUE,
+ true,
NULL,
0,
pDevice->byBasicMap,
@@ -1815,7 +1248,7 @@ CARDbStartMeasure (
pDevice->abyRPIs
);
}
- return (TRUE);
+ return (true);
}
@@ -1833,19 +1266,19 @@ CARDbStartMeasure (
* Return Value: none.
*
-*/
-BOOL
+bool
CARDbChannelSwitch (
void *pDeviceHandler,
- BYTE byMode,
- BYTE byNewChannel,
- BYTE byCount
+ unsigned char byMode,
+ unsigned char byNewChannel,
+ unsigned char byCount
)
{
PSDevice pDevice = (PSDevice) pDeviceHandler;
- BOOL bResult = TRUE;
+ bool bResult = true;
if (byCount == 0) {
- bResult = CARDbSetChannel(pDevice, byNewChannel);
+ bResult = set_channel(pDevice, byNewChannel);
VNTWIFIbChannelSwitch(pDevice->pMgmt, byNewChannel);
MACvSelectPage1(pDevice->PortOffset);
MACvRegBitsOn(pDevice->PortOffset, MAC_REG_MSRCTL+1, MSRCTL1_TXPAUSE);
@@ -1854,7 +1287,7 @@ CARDbChannelSwitch (
}
pDevice->byChannelSwitchCount = byCount;
pDevice->byNewChannel = byNewChannel;
- pDevice->bChannelSwitch = TRUE;
+ pDevice->bChannelSwitch = true;
if (byMode == 1) {
bResult=CARDbStopTxPacket(pDevice, PKT_TYPE_802_11_ALL);
}
@@ -1876,34 +1309,34 @@ CARDbChannelSwitch (
* Return Value: none.
*
-*/
-BOOL
+bool
CARDbSetQuiet (
void *pDeviceHandler,
- BOOL bResetQuiet,
- BYTE byQuietCount,
- BYTE byQuietPeriod,
- WORD wQuietDuration,
- WORD wQuietOffset
+ bool bResetQuiet,
+ unsigned char byQuietCount,
+ unsigned char byQuietPeriod,
+ unsigned short wQuietDuration,
+ unsigned short wQuietOffset
)
{
PSDevice pDevice = (PSDevice) pDeviceHandler;
- UINT ii = 0;
+ unsigned int ii = 0;
- if (bResetQuiet == TRUE) {
+ if (bResetQuiet == true) {
MACvRegBitsOff(pDevice->PortOffset, MAC_REG_MSRCTL, (MSRCTL_QUIETTXCHK | MSRCTL_QUIETEN));
for(ii=0;ii<MAX_QUIET_COUNT;ii++) {
- pDevice->sQuiet[ii].bEnable = FALSE;
+ pDevice->sQuiet[ii].bEnable = false;
}
pDevice->uQuietEnqueue = 0;
- pDevice->bEnableFirstQuiet = FALSE;
- pDevice->bQuietEnable = FALSE;
+ pDevice->bEnableFirstQuiet = false;
+ pDevice->bQuietEnable = false;
pDevice->byQuietStartCount = byQuietCount;
}
- if (pDevice->sQuiet[pDevice->uQuietEnqueue].bEnable == FALSE) {
- pDevice->sQuiet[pDevice->uQuietEnqueue].bEnable = TRUE;
+ if (pDevice->sQuiet[pDevice->uQuietEnqueue].bEnable == false) {
+ pDevice->sQuiet[pDevice->uQuietEnqueue].bEnable = true;
pDevice->sQuiet[pDevice->uQuietEnqueue].byPeriod = byQuietPeriod;
pDevice->sQuiet[pDevice->uQuietEnqueue].wDuration = wQuietDuration;
- pDevice->sQuiet[pDevice->uQuietEnqueue].dwStartTime = (DWORD) byQuietCount;
+ pDevice->sQuiet[pDevice->uQuietEnqueue].dwStartTime = (unsigned long) byQuietCount;
pDevice->sQuiet[pDevice->uQuietEnqueue].dwStartTime *= pDevice->wBeaconInterval;
pDevice->sQuiet[pDevice->uQuietEnqueue].dwStartTime += wQuietOffset;
pDevice->uQuietEnqueue++;
@@ -1914,7 +1347,7 @@ CARDbSetQuiet (
} else {
// we can not handle Quiet EID more
}
- return (TRUE);
+ return (true);
}
@@ -1932,21 +1365,21 @@ CARDbSetQuiet (
* Return Value: none.
*
-*/
-BOOL
+bool
CARDbStartQuiet (
void *pDeviceHandler
)
{
PSDevice pDevice = (PSDevice) pDeviceHandler;
- UINT ii = 0;
- DWORD dwStartTime = 0xFFFFFFFF;
- UINT uCurrentQuietIndex = 0;
- DWORD dwNextTime = 0;
- DWORD dwGap = 0;
- DWORD dwDuration = 0;
+ unsigned int ii = 0;
+ unsigned long dwStartTime = 0xFFFFFFFF;
+ unsigned int uCurrentQuietIndex = 0;
+ unsigned long dwNextTime = 0;
+ unsigned long dwGap = 0;
+ unsigned long dwDuration = 0;
for(ii=0;ii<MAX_QUIET_COUNT;ii++) {
- if ((pDevice->sQuiet[ii].bEnable == TRUE) &&
+ if ((pDevice->sQuiet[ii].bEnable == true) &&
(dwStartTime > pDevice->sQuiet[ii].dwStartTime)) {
dwStartTime = pDevice->sQuiet[ii].dwStartTime;
uCurrentQuietIndex = ii;
@@ -1954,22 +1387,22 @@ CARDbStartQuiet (
}
if (dwStartTime == 0xFFFFFFFF) {
// no more quiet
- pDevice->bQuietEnable = FALSE;
+ pDevice->bQuietEnable = false;
MACvRegBitsOff(pDevice->PortOffset, MAC_REG_MSRCTL, (MSRCTL_QUIETTXCHK | MSRCTL_QUIETEN));
} else {
- if (pDevice->bQuietEnable == FALSE) {
+ if (pDevice->bQuietEnable == false) {
// first quiet
pDevice->byQuietStartCount--;
dwNextTime = pDevice->sQuiet[uCurrentQuietIndex].dwStartTime;
dwNextTime %= pDevice->wBeaconInterval;
MACvSelectPage1(pDevice->PortOffset);
- VNSvOutPortW(pDevice->PortOffset + MAC_REG_QUIETINIT, (WORD) dwNextTime);
- VNSvOutPortW(pDevice->PortOffset + MAC_REG_QUIETDUR, (WORD) pDevice->sQuiet[uCurrentQuietIndex].wDuration);
+ VNSvOutPortW(pDevice->PortOffset + MAC_REG_QUIETINIT, (unsigned short) dwNextTime);
+ VNSvOutPortW(pDevice->PortOffset + MAC_REG_QUIETDUR, (unsigned short) pDevice->sQuiet[uCurrentQuietIndex].wDuration);
if (pDevice->byQuietStartCount == 0) {
- pDevice->bEnableFirstQuiet = FALSE;
+ pDevice->bEnableFirstQuiet = false;
MACvRegBitsOn(pDevice->PortOffset, MAC_REG_MSRCTL, (MSRCTL_QUIETTXCHK | MSRCTL_QUIETEN));
} else {
- pDevice->bEnableFirstQuiet = TRUE;
+ pDevice->bEnableFirstQuiet = true;
}
MACvSelectPage0(pDevice->PortOffset);
} else {
@@ -1977,8 +1410,8 @@ CARDbStartQuiet (
// overlap with previous Quiet
dwGap = pDevice->dwCurrentQuietEndTime - pDevice->sQuiet[uCurrentQuietIndex].dwStartTime;
if (dwGap >= pDevice->sQuiet[uCurrentQuietIndex].wDuration) {
- // return FALSE to indicate next quiet expired, should call this function again
- return (FALSE);
+ // return false to indicate next quiet expired, should call this function again
+ return (false);
}
dwDuration = pDevice->sQuiet[uCurrentQuietIndex].wDuration - dwGap;
dwGap = 0;
@@ -1988,94 +1421,34 @@ CARDbStartQuiet (
}
// set GAP and Next duration
MACvSelectPage1(pDevice->PortOffset);
- VNSvOutPortW(pDevice->PortOffset + MAC_REG_QUIETGAP, (WORD) dwGap);
- VNSvOutPortW(pDevice->PortOffset + MAC_REG_QUIETDUR, (WORD) dwDuration);
+ VNSvOutPortW(pDevice->PortOffset + MAC_REG_QUIETGAP, (unsigned short) dwGap);
+ VNSvOutPortW(pDevice->PortOffset + MAC_REG_QUIETDUR, (unsigned short) dwDuration);
MACvRegBitsOn(pDevice->PortOffset, MAC_REG_MSRCTL, MSRCTL_QUIETRPT);
MACvSelectPage0(pDevice->PortOffset);
}
- pDevice->bQuietEnable = TRUE;
+ pDevice->bQuietEnable = true;
pDevice->dwCurrentQuietEndTime = pDevice->sQuiet[uCurrentQuietIndex].dwStartTime;
pDevice->dwCurrentQuietEndTime += pDevice->sQuiet[uCurrentQuietIndex].wDuration;
if (pDevice->sQuiet[uCurrentQuietIndex].byPeriod == 0) {
// not period disable current quiet element
- pDevice->sQuiet[uCurrentQuietIndex].bEnable = FALSE;
+ pDevice->sQuiet[uCurrentQuietIndex].bEnable = false;
} else {
// set next period start time
- dwNextTime = (DWORD) pDevice->sQuiet[uCurrentQuietIndex].byPeriod;
+ dwNextTime = (unsigned long) pDevice->sQuiet[uCurrentQuietIndex].byPeriod;
dwNextTime *= pDevice->wBeaconInterval;
pDevice->sQuiet[uCurrentQuietIndex].dwStartTime = dwNextTime;
}
if (pDevice->dwCurrentQuietEndTime > 0x80010000) {
// decreament all time to avoid wrap around
for(ii=0;ii<MAX_QUIET_COUNT;ii++) {
- if (pDevice->sQuiet[ii].bEnable == TRUE) {
+ if (pDevice->sQuiet[ii].bEnable == true) {
pDevice->sQuiet[ii].dwStartTime -= 0x80000000;
}
}
pDevice->dwCurrentQuietEndTime -= 0x80000000;
}
}
- return (TRUE);
-}
-
-
-/*
- *
- * Description:
- * Set Channel Info of Country
- *
- * Parameters:
- * In:
- * hDeviceContext - device structure point
- * Out:
- * none
- *
- * Return Value: none.
- *
--*/
-void
-CARDvSetCountryInfo (
- void *pDeviceHandler,
- CARD_PHY_TYPE ePHYType,
- void *pIE
- )
-{
- PSDevice pDevice = (PSDevice) pDeviceHandler;
- UINT ii = 0;
- UINT uu = 0;
- UINT step = 0;
- UINT uNumOfCountryInfo = 0;
- BYTE byCh = 0;
- PWLAN_IE_COUNTRY pIE_Country = (PWLAN_IE_COUNTRY) pIE;
-
-
- uNumOfCountryInfo = (pIE_Country->len - 3);
- uNumOfCountryInfo /= 3;
-
- if (ePHYType == PHY_TYPE_11A) {
- pDevice->bCountryInfo5G = TRUE;
- for(ii=CB_MAX_CHANNEL_24G+1;ii<=CARD_MAX_CHANNEL_TBL;ii++) {
- sChannelTbl[ii].bValid = FALSE;
- }
- step = 4;
- } else {
- pDevice->bCountryInfo24G = TRUE;
- for(ii=1;ii<=CB_MAX_CHANNEL_24G;ii++) {
- sChannelTbl[ii].bValid = FALSE;
- }
- step = 1;
- }
- pDevice->abyCountryCode[0] = pIE_Country->abyCountryString[0];
- pDevice->abyCountryCode[1] = pIE_Country->abyCountryString[1];
- pDevice->abyCountryCode[2] = pIE_Country->abyCountryString[2];
-
- for(ii=0;ii<uNumOfCountryInfo;ii++) {
- for(uu=0;uu<pIE_Country->abyCountryInfo[ii*3+1];uu++) {
- byCh = CARDbyGetChannelMapping(pDevice, (BYTE)(pIE_Country->abyCountryInfo[ii*3]+step*uu), ePHYType);
- sChannelTbl[byCh].bValid = TRUE;
- pDevice->abyRegPwr[byCh] = pIE_Country->abyCountryInfo[ii*3+2];
- }
- }
+ return (true);
}
/*
@@ -2095,18 +1468,18 @@ CARDvSetCountryInfo (
void
CARDvSetPowerConstraint (
void *pDeviceHandler,
- BYTE byChannel,
- I8 byPower
+ unsigned char byChannel,
+ char byPower
)
{
PSDevice pDevice = (PSDevice) pDeviceHandler;
if (byChannel > CB_MAX_CHANNEL_24G) {
- if (pDevice->bCountryInfo5G == TRUE) {
+ if (pDevice->bCountryInfo5G == true) {
pDevice->abyLocalPwr[byChannel] = pDevice->abyRegPwr[byChannel] - byPower;
}
} else {
- if (pDevice->bCountryInfo24G == TRUE) {
+ if (pDevice->bCountryInfo24G == true) {
pDevice->abyLocalPwr[byChannel] = pDevice->abyRegPwr[byChannel] - byPower;
}
}
@@ -2130,12 +1503,12 @@ CARDvSetPowerConstraint (
void
CARDvGetPowerCapability (
void *pDeviceHandler,
- PBYTE pbyMinPower,
- PBYTE pbyMaxPower
+ unsigned char *pbyMinPower,
+ unsigned char *pbyMaxPower
)
{
PSDevice pDevice = (PSDevice) pDeviceHandler;
- BYTE byDec = 0;
+ unsigned char byDec = 0;
*pbyMaxPower = pDevice->abyOFDMDefaultPwr[pDevice->byCurrentCh];
byDec = pDevice->abyOFDMPwrTbl[pDevice->byCurrentCh];
@@ -2148,98 +1521,6 @@ CARDvGetPowerCapability (
*pbyMinPower = pDevice->abyOFDMDefaultPwr[pDevice->byCurrentCh] - byDec;
}
-
-/*
- *
- * Description:
- * Set Support Channels IE defined in 802.11h
- *
- * Parameters:
- * In:
- * hDeviceContext - device structure point
- * Out:
- * none
- *
- * Return Value: none.
- *
--*/
-BYTE
-CARDbySetSupportChannels (
- void *pDeviceHandler,
- PBYTE pbyIEs
- )
-{
- PSDevice pDevice = (PSDevice) pDeviceHandler;
- UINT ii;
- BYTE byCount;
- PWLAN_IE_SUPP_CH pIE = (PWLAN_IE_SUPP_CH) pbyIEs;
- PBYTE pbyChTupple;
- BYTE byLen = 0;
-
-
- pIE->byElementID = WLAN_EID_SUPP_CH;
- pIE->len = 0;
- pbyChTupple = pIE->abyChannelTuple;
- byLen = 2;
- // lower band
- byCount = 0;
- if (ChannelRuleTab[pDevice->byZoneType].bChannelIdxList[28] == TRUE) {
- for (ii=28;ii<36;ii+=2) {
- if (ChannelRuleTab[pDevice->byZoneType].bChannelIdxList[ii] == TRUE) {
- byCount++;
- }
- }
- *pbyChTupple++ = 34;
- *pbyChTupple++ = byCount;
- byLen += 2;
- } else if (ChannelRuleTab[pDevice->byZoneType].bChannelIdxList[29] == TRUE) {
- for (ii=29;ii<36;ii+=2) {
- if (ChannelRuleTab[pDevice->byZoneType].bChannelIdxList[ii] == TRUE) {
- byCount++;
- }
- }
- *pbyChTupple++ = 36;
- *pbyChTupple++ = byCount;
- byLen += 2;
- }
- // middle band
- byCount = 0;
- if (ChannelRuleTab[pDevice->byZoneType].bChannelIdxList[36] == TRUE) {
- for (ii=36;ii<40;ii++) {
- if (ChannelRuleTab[pDevice->byZoneType].bChannelIdxList[ii] == TRUE) {
- byCount++;
- }
- }
- *pbyChTupple++ = 52;
- *pbyChTupple++ = byCount;
- byLen += 2;
- }
- // higher band
- byCount = 0;
- if (ChannelRuleTab[pDevice->byZoneType].bChannelIdxList[40] == TRUE) {
- for (ii=40;ii<51;ii++) {
- if (ChannelRuleTab[pDevice->byZoneType].bChannelIdxList[ii] == TRUE) {
- byCount++;
- }
- }
- *pbyChTupple++ = 100;
- *pbyChTupple++ = byCount;
- byLen += 2;
- } else if (ChannelRuleTab[pDevice->byZoneType].bChannelIdxList[51] == TRUE) {
- for (ii=51;ii<56;ii++) {
- if (ChannelRuleTab[pDevice->byZoneType].bChannelIdxList[ii] == TRUE) {
- byCount++;
- }
- }
- *pbyChTupple++ = 149;
- *pbyChTupple++ = byCount;
- byLen += 2;
- }
- pIE->len += (byLen - 2);
- return (byLen);
-}
-
-
/*
*
* Description:
@@ -2253,8 +1534,8 @@ CARDbySetSupportChannels (
*
* Return Value: none.
*
--*/
-I8
+ */
+char
CARDbyGetTransmitPower (
void *pDeviceHandler
)
@@ -2264,161 +1545,6 @@ CARDbyGetTransmitPower (
return (pDevice->byCurPwrdBm);
}
-
-BOOL
-CARDbChannelGetList (
- UINT uCountryCodeIdx,
- PBYTE pbyChannelTable
- )
-{
- if (uCountryCodeIdx >= CCODE_MAX) {
- return (FALSE);
- }
- memcpy(pbyChannelTable, ChannelRuleTab[uCountryCodeIdx].bChannelIdxList, CB_MAX_CHANNEL);
- return (TRUE);
-}
-
-
-void
-CARDvSetCountryIE(
- void *pDeviceHandler,
- void *pIE
- )
-{
- PSDevice pDevice = (PSDevice) pDeviceHandler;
- UINT ii;
- PWLAN_IE_COUNTRY pIECountry = (PWLAN_IE_COUNTRY) pIE;
-
- pIECountry->byElementID = WLAN_EID_COUNTRY;
- pIECountry->len = 0;
- pIECountry->abyCountryString[0] = ChannelRuleTab[pDevice->byZoneType].chCountryCode[0];
- pIECountry->abyCountryString[1] = ChannelRuleTab[pDevice->byZoneType].chCountryCode[1];
- pIECountry->abyCountryString[2] = ' ';
- for (ii = CB_MAX_CHANNEL_24G; ii < CB_MAX_CHANNEL; ii++ ) {
- if (ChannelRuleTab[pDevice->byZoneType].bChannelIdxList[ii] != 0) {
- pIECountry->abyCountryInfo[pIECountry->len++] = sChannelTbl[ii+1].byChannelNumber;
- pIECountry->abyCountryInfo[pIECountry->len++] = 1;
- pIECountry->abyCountryInfo[pIECountry->len++] = ChannelRuleTab[pDevice->byZoneType].byPower[ii];
- }
- }
- pIECountry->len += 3;
-}
-
-
-BOOL
-CARDbGetChannelMapInfo(
- void *pDeviceHandler,
- UINT uChannelIndex,
- PBYTE pbyChannelNumber,
- PBYTE pbyMap
- )
-{
-// PSDevice pDevice = (PSDevice) pDeviceHandler;
-
- if (uChannelIndex > CB_MAX_CHANNEL) {
- return FALSE;
- }
- *pbyChannelNumber = sChannelTbl[uChannelIndex].byChannelNumber;
- *pbyMap = sChannelTbl[uChannelIndex].byMAP;
- return sChannelTbl[uChannelIndex].bValid;
-}
-
-
-void
-CARDvSetChannelMapInfo(
- void *pDeviceHandler,
- UINT uChannelIndex,
- BYTE byMap
- )
-{
-// PSDevice pDevice = (PSDevice) pDeviceHandler;
-
- if (uChannelIndex > CB_MAX_CHANNEL) {
- return;
- }
- sChannelTbl[uChannelIndex].byMAP |= byMap;
-}
-
-
-void
-CARDvClearChannelMapInfo(
- void *pDeviceHandler
- )
-{
-// PSDevice pDevice = (PSDevice) pDeviceHandler;
- UINT ii = 0;
-
- for (ii = 1; ii <= CB_MAX_CHANNEL; ii++) {
- sChannelTbl[ii].byMAP = 0;
- }
-}
-
-
-BYTE
-CARDbyAutoChannelSelect(
- void *pDeviceHandler,
- CARD_PHY_TYPE ePHYType
- )
-{
-// PSDevice pDevice = (PSDevice) pDeviceHandler;
- UINT ii = 0;
- BYTE byOptionChannel = 0;
- INT aiWeight[CB_MAX_CHANNEL_24G+1] = {-1000,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
-
- if (ePHYType == PHY_TYPE_11A) {
- for(ii=CB_MAX_CHANNEL_24G+1;ii<=CB_MAX_CHANNEL;ii++) {
- if (sChannelTbl[ii].bValid == TRUE) {
- if (byOptionChannel == 0) {
- byOptionChannel = (BYTE) ii;
- }
- if (sChannelTbl[ii].byMAP == 0) {
- return ((BYTE) ii);
- } else if ( !(sChannelTbl[ii].byMAP & 0x08)) {
- byOptionChannel = (BYTE) ii;
- }
- }
- }
- } else {
- byOptionChannel = 0;
- for(ii=1;ii<=CB_MAX_CHANNEL_24G;ii++) {
- if (sChannelTbl[ii].bValid == TRUE) {
- if (sChannelTbl[ii].byMAP == 0) {
- aiWeight[ii] += 100;
- } else if (sChannelTbl[ii].byMAP & 0x01) {
- if (ii > 3) {
- aiWeight[ii-3] -= 10;
- }
- if (ii > 2) {
- aiWeight[ii-2] -= 20;
- }
- if (ii > 1) {
- aiWeight[ii-1] -= 40;
- }
- aiWeight[ii] -= 80;
- if (ii < CB_MAX_CHANNEL_24G) {
- aiWeight[ii+1] -= 40;
- }
- if (ii < (CB_MAX_CHANNEL_24G - 1)) {
- aiWeight[ii+2] -= 20;
- }
- if (ii < (CB_MAX_CHANNEL_24G - 2)) {
- aiWeight[ii+3] -= 10;
- }
- }
- }
- }
- for(ii=1;ii<=CB_MAX_CHANNEL_24G;ii++) {
- if ((sChannelTbl[ii].bValid == TRUE) &&
- (aiWeight[ii] > aiWeight[byOptionChannel])) {
- byOptionChannel = (BYTE) ii;
- }
- }
- }
- return (byOptionChannel);
-}
-
-
-
//xxx
void
CARDvSafeResetTx (
@@ -2426,7 +1552,7 @@ CARDvSafeResetTx (
)
{
PSDevice pDevice = (PSDevice) pDeviceHandler;
- UINT uu;
+ unsigned int uu;
PSTxDesc pCurrTD;
// initialize TD index
@@ -2482,7 +1608,7 @@ CARDvSafeResetRx (
)
{
PSDevice pDevice = (PSDevice) pDeviceHandler;
- UINT uu;
+ unsigned int uu;
PSRxDesc pDesc;
@@ -2494,17 +1620,17 @@ CARDvSafeResetRx (
// init state, all RD is chip's
for (uu = 0; uu < pDevice->sOpts.nRxDescs0; uu++) {
pDesc =&(pDevice->aRD0Ring[uu]);
- pDesc->m_rd0RD0.wResCount = (WORD)(pDevice->rx_buf_sz);
+ pDesc->m_rd0RD0.wResCount = (unsigned short)(pDevice->rx_buf_sz);
pDesc->m_rd0RD0.f1Owner=OWNED_BY_NIC;
- pDesc->m_rd1RD1.wReqCount = (WORD)(pDevice->rx_buf_sz);
+ pDesc->m_rd1RD1.wReqCount = (unsigned short)(pDevice->rx_buf_sz);
}
// init state, all RD is chip's
for (uu = 0; uu < pDevice->sOpts.nRxDescs1; uu++) {
pDesc =&(pDevice->aRD1Ring[uu]);
- pDesc->m_rd0RD0.wResCount = (WORD)(pDevice->rx_buf_sz);
+ pDesc->m_rd0RD0.wResCount = (unsigned short)(pDevice->rx_buf_sz);
pDesc->m_rd0RD0.f1Owner=OWNED_BY_NIC;
- pDesc->m_rd1RD1.wReqCount = (WORD)(pDevice->rx_buf_sz);
+ pDesc->m_rd1RD1.wReqCount = (unsigned short)(pDevice->rx_buf_sz);
}
pDevice->cbDFCB = CB_MAX_RX_FRAG;
@@ -2537,18 +1663,18 @@ CARDvSafeResetRx (
* Return Value: response Control frame rate
*
*/
-WORD CARDwGetCCKControlRate(void *pDeviceHandler, WORD wRateIdx)
+unsigned short CARDwGetCCKControlRate(void *pDeviceHandler, unsigned short wRateIdx)
{
PSDevice pDevice = (PSDevice) pDeviceHandler;
- UINT ui = (UINT)wRateIdx;
+ unsigned int ui = (unsigned int) wRateIdx;
while (ui > RATE_1M) {
- if (pDevice->wBasicRate & ((WORD)1 << ui)) {
- return (WORD)ui;
+ if (pDevice->wBasicRate & ((unsigned short)1 << ui)) {
+ return (unsigned short)ui;
}
ui --;
}
- return (WORD)RATE_1M;
+ return (unsigned short)RATE_1M;
}
/*
@@ -2564,10 +1690,10 @@ WORD CARDwGetCCKControlRate(void *pDeviceHandler, WORD wRateIdx)
* Return Value: response Control frame rate
*
*/
-WORD CARDwGetOFDMControlRate (void *pDeviceHandler, WORD wRateIdx)
+unsigned short CARDwGetOFDMControlRate (void *pDeviceHandler, unsigned short wRateIdx)
{
PSDevice pDevice = (PSDevice) pDeviceHandler;
- UINT ui = (UINT)wRateIdx;
+ unsigned int ui = (unsigned int) wRateIdx;
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"BASIC RATE: %X\n", pDevice->wBasicRate);
@@ -2578,14 +1704,14 @@ WORD CARDwGetOFDMControlRate (void *pDeviceHandler, WORD wRateIdx)
return wRateIdx;
}
while (ui > RATE_11M) {
- if (pDevice->wBasicRate & ((WORD)1 << ui)) {
+ if (pDevice->wBasicRate & ((unsigned short)1 << ui)) {
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"CARDwGetOFDMControlRate : %d\n", ui);
- return (WORD)ui;
+ return (unsigned short)ui;
}
ui --;
}
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"CARDwGetOFDMControlRate: 6M\n");
- return (WORD)RATE_24M;
+ return (unsigned short)RATE_24M;
}
@@ -2604,9 +1730,9 @@ WORD CARDwGetOFDMControlRate (void *pDeviceHandler, WORD wRateIdx)
void CARDvSetRSPINF (void *pDeviceHandler, CARD_PHY_TYPE ePHYType)
{
PSDevice pDevice = (PSDevice) pDeviceHandler;
- BYTE byServ = 0x00, bySignal = 0x00; //For CCK
- WORD wLen = 0x0000;
- BYTE byTxRate, byRsvTime; //For OFDM
+ unsigned char byServ = 0x00, bySignal = 0x00; //For CCK
+ unsigned short wLen = 0x0000;
+ unsigned char byTxRate, byRsvTime; //For OFDM
//Set to Page1
MACvSelectPage1(pDevice->PortOffset);
@@ -2731,7 +1857,7 @@ void vUpdateIFS (void *pDeviceHandler)
//Set SIFS, DIFS, EIFS, SlotTime, CwMin
PSDevice pDevice = (PSDevice) pDeviceHandler;
- BYTE byMaxMin = 0;
+ unsigned char byMaxMin = 0;
if (pDevice->byPacketType==PK_TYPE_11A) {//0000 0000 0000 0000,11a
pDevice->uSlot = C_SLOT_SHORT;
pDevice->uSIFS = C_SIFS_A;
@@ -2768,27 +1894,27 @@ void vUpdateIFS (void *pDeviceHandler)
pDevice->uEIFS = C_EIFS;
if (pDevice->byRFType == RF_RFMD2959) {
// bcs TX_PE will reserve 3 us
- VNSvOutPortB(pDevice->PortOffset + MAC_REG_SIFS, (BYTE)(pDevice->uSIFS - 3));
- VNSvOutPortB(pDevice->PortOffset + MAC_REG_DIFS, (BYTE)(pDevice->uDIFS - 3));
+ VNSvOutPortB(pDevice->PortOffset + MAC_REG_SIFS, (unsigned char)(pDevice->uSIFS - 3));
+ VNSvOutPortB(pDevice->PortOffset + MAC_REG_DIFS, (unsigned char)(pDevice->uDIFS - 3));
} else {
- VNSvOutPortB(pDevice->PortOffset + MAC_REG_SIFS, (BYTE)pDevice->uSIFS);
- VNSvOutPortB(pDevice->PortOffset + MAC_REG_DIFS, (BYTE)pDevice->uDIFS);
+ VNSvOutPortB(pDevice->PortOffset + MAC_REG_SIFS, (unsigned char)pDevice->uSIFS);
+ VNSvOutPortB(pDevice->PortOffset + MAC_REG_DIFS, (unsigned char)pDevice->uDIFS);
}
- VNSvOutPortB(pDevice->PortOffset + MAC_REG_EIFS, (BYTE)pDevice->uEIFS);
- VNSvOutPortB(pDevice->PortOffset + MAC_REG_SLOT, (BYTE)pDevice->uSlot);
+ VNSvOutPortB(pDevice->PortOffset + MAC_REG_EIFS, (unsigned char)pDevice->uEIFS);
+ VNSvOutPortB(pDevice->PortOffset + MAC_REG_SLOT, (unsigned char)pDevice->uSlot);
byMaxMin |= 0xA0;//1010 1111,C_CWMAX = 1023
- VNSvOutPortB(pDevice->PortOffset + MAC_REG_CWMAXMIN0, (BYTE)byMaxMin);
+ VNSvOutPortB(pDevice->PortOffset + MAC_REG_CWMAXMIN0, (unsigned char)byMaxMin);
}
void CARDvUpdateBasicTopRate (void *pDeviceHandler)
{
PSDevice pDevice = (PSDevice) pDeviceHandler;
- BYTE byTopOFDM = RATE_24M, byTopCCK = RATE_1M;
- BYTE ii;
+ unsigned char byTopOFDM = RATE_24M, byTopCCK = RATE_1M;
+ unsigned char ii;
//Determines the highest basic rate.
for (ii = RATE_54M; ii >= RATE_6M; ii --) {
- if ( (pDevice->wBasicRate) & ((WORD)(1<<ii)) ) {
+ if ( (pDevice->wBasicRate) & ((unsigned short)(1<<ii)) ) {
byTopOFDM = ii;
break;
}
@@ -2796,7 +1922,7 @@ void CARDvUpdateBasicTopRate (void *pDeviceHandler)
pDevice->byTopOFDMBasicRate = byTopOFDM;
for (ii = RATE_11M;; ii --) {
- if ( (pDevice->wBasicRate) & ((WORD)(1<<ii)) ) {
+ if ( (pDevice->wBasicRate) & ((unsigned short)(1<<ii)) ) {
byTopCCK = ii;
break;
}
@@ -2817,40 +1943,40 @@ void CARDvUpdateBasicTopRate (void *pDeviceHandler)
* Out:
* none
*
- * Return Value: TRUE if succeeded; FALSE if failed.
+ * Return Value: true if succeeded; false if failed.
*
*/
-BOOL CARDbAddBasicRate (void *pDeviceHandler, WORD wRateIdx)
+bool CARDbAddBasicRate (void *pDeviceHandler, unsigned short wRateIdx)
{
PSDevice pDevice = (PSDevice) pDeviceHandler;
- WORD wRate = (WORD)(1<<wRateIdx);
+ unsigned short wRate = (unsigned short)(1<<wRateIdx);
pDevice->wBasicRate |= wRate;
//Determines the highest basic rate.
CARDvUpdateBasicTopRate((void *)pDevice);
- return(TRUE);
+ return(true);
}
-BOOL CARDbIsOFDMinBasicRate (void *pDeviceHandler)
+bool CARDbIsOFDMinBasicRate (void *pDeviceHandler)
{
PSDevice pDevice = (PSDevice) pDeviceHandler;
int ii;
for (ii = RATE_54M; ii >= RATE_6M; ii --) {
- if ((pDevice->wBasicRate) & ((WORD)(1<<ii)))
- return TRUE;
+ if ((pDevice->wBasicRate) & ((unsigned short)(1<<ii)))
+ return true;
}
- return FALSE;
+ return false;
}
-BYTE CARDbyGetPktType (void *pDeviceHandler)
+unsigned char CARDbyGetPktType (void *pDeviceHandler)
{
PSDevice pDevice = (PSDevice) pDeviceHandler;
if (pDevice->byBBType == BB_TYPE_11A || pDevice->byBBType == BB_TYPE_11B) {
- return (BYTE)pDevice->byBBType;
+ return (unsigned char)pDevice->byBBType;
}
else if (CARDbIsOFDMinBasicRate((void *)pDevice)) {
return PK_TYPE_11GA;
@@ -2873,7 +1999,7 @@ BYTE CARDbyGetPktType (void *pDeviceHandler)
* Return Value: none
*
*/
-void CARDvSetLoopbackMode (DWORD_PTR dwIoBase, WORD wLoopbackMode)
+void CARDvSetLoopbackMode (unsigned long dwIoBase, unsigned short wLoopbackMode)
{
switch(wLoopbackMode) {
case CARD_LB_NONE:
@@ -2881,7 +2007,7 @@ void CARDvSetLoopbackMode (DWORD_PTR dwIoBase, WORD wLoopbackMode)
case CARD_LB_PHY:
break;
default:
- ASSERT(FALSE);
+ ASSERT(false);
break;
}
// set MAC loopback
@@ -2902,15 +2028,15 @@ void CARDvSetLoopbackMode (DWORD_PTR dwIoBase, WORD wLoopbackMode)
* Return Value: none
*
*/
-BOOL CARDbSoftwareReset (void *pDeviceHandler)
+bool CARDbSoftwareReset (void *pDeviceHandler)
{
PSDevice pDevice = (PSDevice) pDeviceHandler;
// reset MAC
if (!MACbSafeSoftwareReset(pDevice->PortOffset))
- return FALSE;
+ return false;
- return TRUE;
+ return true;
}
@@ -2929,16 +2055,16 @@ BOOL CARDbSoftwareReset (void *pDeviceHandler)
* Return Value: TSF Offset value
*
*/
-QWORD CARDqGetTSFOffset (BYTE byRxRate, QWORD qwTSF1, QWORD qwTSF2)
+QWORD CARDqGetTSFOffset (unsigned char byRxRate, QWORD qwTSF1, QWORD qwTSF2)
{
QWORD qwTSFOffset;
- WORD wRxBcnTSFOffst= 0;;
+ unsigned short wRxBcnTSFOffst= 0;;
HIDWORD(qwTSFOffset) = 0;
LODWORD(qwTSFOffset) = 0;
wRxBcnTSFOffst = cwRXBCNTSFOff[byRxRate%MAX_RATE];
- (qwTSF2).u.dwLowDword += (DWORD)(wRxBcnTSFOffst);
- if ((qwTSF2).u.dwLowDword < (DWORD)(wRxBcnTSFOffst)) {
+ (qwTSF2).u.dwLowDword += (unsigned long)(wRxBcnTSFOffst);
+ if ((qwTSF2).u.dwLowDword < (unsigned long)(wRxBcnTSFOffst)) {
(qwTSF2).u.dwHighDword++;
}
LODWORD(qwTSFOffset) = LODWORD(qwTSF1) - LODWORD(qwTSF2);
@@ -2963,13 +2089,13 @@ QWORD CARDqGetTSFOffset (BYTE byRxRate, QWORD qwTSF1, QWORD qwTSF2)
* Out:
* qwCurrTSF - Current TSF counter
*
- * Return Value: TRUE if success; otherwise FALSE
+ * Return Value: true if success; otherwise false
*
*/
-BOOL CARDbGetCurrentTSF (DWORD_PTR dwIoBase, PQWORD pqwCurrTSF)
+bool CARDbGetCurrentTSF (unsigned long dwIoBase, PQWORD pqwCurrTSF)
{
- WORD ww;
- BYTE byData;
+ unsigned short ww;
+ unsigned char byData;
MACvRegBitsOn(dwIoBase, MAC_REG_TFTCTL, TFTCTL_TSFCNTRRD);
for (ww = 0; ww < W_MAX_TIMEOUT; ww++) {
@@ -2978,11 +2104,11 @@ BOOL CARDbGetCurrentTSF (DWORD_PTR dwIoBase, PQWORD pqwCurrTSF)
break;
}
if (ww == W_MAX_TIMEOUT)
- return(FALSE);
+ return(false);
VNSvInPortD(dwIoBase + MAC_REG_TSFCNTR, &LODWORD(*pqwCurrTSF));
VNSvInPortD(dwIoBase + MAC_REG_TSFCNTR + 4, &HIDWORD(*pqwCurrTSF));
- return(TRUE);
+ return(true);
}
@@ -3000,12 +2126,12 @@ BOOL CARDbGetCurrentTSF (DWORD_PTR dwIoBase, PQWORD pqwCurrTSF)
* Return Value: TSF value of next Beacon
*
*/
-QWORD CARDqGetNextTBTT (QWORD qwTSF, WORD wBeaconInterval)
+QWORD CARDqGetNextTBTT (QWORD qwTSF, unsigned short wBeaconInterval)
{
- UINT uLowNextTBTT;
- UINT uHighRemain, uLowRemain;
- UINT uBeaconInterval;
+ unsigned int uLowNextTBTT;
+ unsigned int uHighRemain, uLowRemain;
+ unsigned int uBeaconInterval;
uBeaconInterval = wBeaconInterval * 1024;
// Next TBTT = ((local_current_TSF / beacon_interval) + 1 ) * beacon_interval
@@ -3044,7 +2170,7 @@ QWORD CARDqGetNextTBTT (QWORD qwTSF, WORD wBeaconInterval)
* Return Value: none
*
*/
-void CARDvSetFirstNextTBTT (DWORD_PTR dwIoBase, WORD wBeaconInterval)
+void CARDvSetFirstNextTBTT (unsigned long dwIoBase, unsigned short wBeaconInterval)
{
QWORD qwNextTBTT;
@@ -3077,7 +2203,7 @@ void CARDvSetFirstNextTBTT (DWORD_PTR dwIoBase, WORD wBeaconInterval)
* Return Value: none
*
*/
-void CARDvUpdateNextTBTT (DWORD_PTR dwIoBase, QWORD qwTSF, WORD wBeaconInterval)
+void CARDvUpdateNextTBTT (unsigned long dwIoBase, QWORD qwTSF, unsigned short wBeaconInterval)
{
qwTSF = CARDqGetNextTBTT(qwTSF, wBeaconInterval);
@@ -3085,7 +2211,8 @@ void CARDvUpdateNextTBTT (DWORD_PTR dwIoBase, QWORD qwTSF, WORD wBeaconInterval)
VNSvOutPortD(dwIoBase + MAC_REG_NEXTTBTT, LODWORD(qwTSF));
VNSvOutPortD(dwIoBase + MAC_REG_NEXTTBTT + 4, HIDWORD(qwTSF));
MACvRegBitsOn(dwIoBase, MAC_REG_TFTCTL, TFTCTL_TBTTSYNCEN);
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Card:Update Next TBTT[%8xh:%8xh] \n",(UINT)HIDWORD(qwTSF), (UINT)LODWORD(qwTSF));
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Card:Update Next TBTT[%8xh:%8xh] \n",
+ (unsigned int) HIDWORD(qwTSF), (unsigned int) LODWORD(qwTSF));
return;
}
diff --git a/drivers/staging/vt6655/card.h b/drivers/staging/vt6655/card.h
index 76313462cf7..e0836e1d511 100644
--- a/drivers/staging/vt6655/card.h
+++ b/drivers/staging/vt6655/card.h
@@ -30,6 +30,7 @@
#define __CARD_H__
#include "ttype.h"
+#include <linux/types.h>
/*--------------------- Export Definitions -------------------------*/
//
@@ -86,57 +87,55 @@ typedef enum _CARD_OP_MODE {
/*--------------------- Export Functions --------------------------*/
-BOOL ChannelValid(UINT CountryCode, UINT ChannelIndex);
void CARDvSetRSPINF(void *pDeviceHandler, CARD_PHY_TYPE ePHYType);
void vUpdateIFS(void *pDeviceHandler);
void CARDvUpdateBasicTopRate(void *pDeviceHandler);
-BOOL CARDbAddBasicRate(void *pDeviceHandler, WORD wRateIdx);
-BOOL CARDbIsOFDMinBasicRate(void *pDeviceHandler);
-void CARDvSetLoopbackMode(DWORD_PTR dwIoBase, WORD wLoopbackMode);
-BOOL CARDbSoftwareReset(void *pDeviceHandler);
-void CARDvSetFirstNextTBTT(DWORD_PTR dwIoBase, WORD wBeaconInterval);
-void CARDvUpdateNextTBTT(DWORD_PTR dwIoBase, QWORD qwTSF, WORD wBeaconInterval);
-BOOL CARDbGetCurrentTSF(DWORD_PTR dwIoBase, PQWORD pqwCurrTSF);
-QWORD CARDqGetNextTBTT(QWORD qwTSF, WORD wBeaconInterval);
-QWORD CARDqGetTSFOffset(BYTE byRxRate, QWORD qwTSF1, QWORD qwTSF2);
-BOOL CARDbSetTxPower(void *pDeviceHandler, ULONG ulTxPower);
-BYTE CARDbyGetPktType(void *pDeviceHandler);
+bool CARDbAddBasicRate(void *pDeviceHandler, unsigned short wRateIdx);
+bool CARDbIsOFDMinBasicRate(void *pDeviceHandler);
+void CARDvSetLoopbackMode(unsigned long dwIoBase, unsigned short wLoopbackMode);
+bool CARDbSoftwareReset(void *pDeviceHandler);
+void CARDvSetFirstNextTBTT(unsigned long dwIoBase, unsigned short wBeaconInterval);
+void CARDvUpdateNextTBTT(unsigned long dwIoBase, QWORD qwTSF, unsigned short wBeaconInterval);
+bool CARDbGetCurrentTSF(unsigned long dwIoBase, PQWORD pqwCurrTSF);
+QWORD CARDqGetNextTBTT(QWORD qwTSF, unsigned short wBeaconInterval);
+QWORD CARDqGetTSFOffset(unsigned char byRxRate, QWORD qwTSF1, QWORD qwTSF2);
+bool CARDbSetTxPower(void *pDeviceHandler, unsigned long ulTxPower);
+unsigned char CARDbyGetPktType(void *pDeviceHandler);
void CARDvSafeResetTx(void *pDeviceHandler);
void CARDvSafeResetRx(void *pDeviceHandler);
//xxx
-BOOL CARDbRadioPowerOff(void *pDeviceHandler);
-BOOL CARDbRadioPowerOn(void *pDeviceHandler);
-BOOL CARDbSetChannel(void *pDeviceHandler, UINT uConnectionChannel);
-//BOOL CARDbSendPacket(void *pDeviceHandler, void *pPacket, CARD_PKT_TYPE ePktType, UINT uLength);
-BOOL CARDbIsShortPreamble(void *pDeviceHandler);
-BOOL CARDbIsShorSlotTime(void *pDeviceHandler);
-BOOL CARDbSetPhyParameter(void *pDeviceHandler, CARD_PHY_TYPE ePHYType, WORD wCapInfo, BYTE byERPField, void *pvSupportRateIEs, void *pvExtSupportRateIEs);
-BOOL CARDbUpdateTSF(void *pDeviceHandler, BYTE byRxRate, QWORD qwBSSTimestamp, QWORD qwLocalTSF);
-BOOL CARDbStopTxPacket(void *pDeviceHandler, CARD_PKT_TYPE ePktType);
-BOOL CARDbStartTxPacket(void *pDeviceHandler, CARD_PKT_TYPE ePktType);
-BOOL CARDbSetBeaconPeriod(void *pDeviceHandler, WORD wBeaconInterval);
-BOOL CARDbSetBSSID(void *pDeviceHandler, PBYTE pbyBSSID, CARD_OP_MODE eOPMode);
-
-BOOL
+bool CARDbRadioPowerOff(void *pDeviceHandler);
+bool CARDbRadioPowerOn(void *pDeviceHandler);
+//bool CARDbSendPacket(void *pDeviceHandler, void *pPacket, CARD_PKT_TYPE ePktType, unsigned int uLength);
+bool CARDbIsShortPreamble(void *pDeviceHandler);
+bool CARDbIsShorSlotTime(void *pDeviceHandler);
+bool CARDbSetPhyParameter(void *pDeviceHandler, CARD_PHY_TYPE ePHYType, unsigned short wCapInfo, unsigned char byERPField, void *pvSupportRateIEs, void *pvExtSupportRateIEs);
+bool CARDbUpdateTSF(void *pDeviceHandler, unsigned char byRxRate, QWORD qwBSSTimestamp, QWORD qwLocalTSF);
+bool CARDbStopTxPacket(void *pDeviceHandler, CARD_PKT_TYPE ePktType);
+bool CARDbStartTxPacket(void *pDeviceHandler, CARD_PKT_TYPE ePktType);
+bool CARDbSetBeaconPeriod(void *pDeviceHandler, unsigned short wBeaconInterval);
+bool CARDbSetBSSID(void *pDeviceHandler, unsigned char *pbyBSSID, CARD_OP_MODE eOPMode);
+
+bool
CARDbPowerDown(
void *pDeviceHandler
);
-BOOL CARDbSetTxDataRate(
+bool CARDbSetTxDataRate(
void *pDeviceHandler,
- WORD wDataRate
+ unsigned short wDataRate
);
-BOOL CARDbRemoveKey (void *pDeviceHandler, PBYTE pbyBSSID);
+bool CARDbRemoveKey (void *pDeviceHandler, unsigned char *pbyBSSID);
-BOOL
+bool
CARDbAdd_PMKID_Candidate (
void *pDeviceHandler,
- PBYTE pbyBSSID,
- BOOL bRSNCapExist,
- WORD wRSNCap
+ unsigned char *pbyBSSID,
+ bool bRSNCapExist,
+ unsigned short wRSNCap
);
void *
@@ -144,112 +143,55 @@ CARDpGetCurrentAddress (
void *pDeviceHandler
);
-
-void CARDvInitChannelTable(void *pDeviceHandler);
-BYTE CARDbyGetChannelMapping(void *pDeviceHandler, BYTE byChannelNumber, CARD_PHY_TYPE ePhyType);
-
-BOOL
+bool
CARDbStartMeasure (
void *pDeviceHandler,
void *pvMeasureEIDs,
- UINT uNumOfMeasureEIDs
+ unsigned int uNumOfMeasureEIDs
);
-BOOL
+bool
CARDbChannelSwitch (
void *pDeviceHandler,
- BYTE byMode,
- BYTE byNewChannel,
- BYTE byCount
+ unsigned char byMode,
+ unsigned char byNewChannel,
+ unsigned char byCount
);
-BOOL
+bool
CARDbSetQuiet (
void *pDeviceHandler,
- BOOL bResetQuiet,
- BYTE byQuietCount,
- BYTE byQuietPeriod,
- WORD wQuietDuration,
- WORD wQuietOffset
+ bool bResetQuiet,
+ unsigned char byQuietCount,
+ unsigned char byQuietPeriod,
+ unsigned short wQuietDuration,
+ unsigned short wQuietOffset
);
-BOOL
+bool
CARDbStartQuiet (
void *pDeviceHandler
);
void
-CARDvSetCountryInfo (
- void *pDeviceHandler,
- CARD_PHY_TYPE ePHYType,
- void *pIE
- );
-
-void
CARDvSetPowerConstraint (
void *pDeviceHandler,
- BYTE byChannel,
- I8 byPower
+ unsigned char byChannel,
+ char byPower
);
void
CARDvGetPowerCapability (
void *pDeviceHandler,
- PBYTE pbyMinPower,
- PBYTE pbyMaxPower
+ unsigned char *pbyMinPower,
+ unsigned char *pbyMaxPower
);
-BYTE
-CARDbySetSupportChannels (
- void *pDeviceHandler,
- PBYTE pbyIEs
- );
-
-I8
+char
CARDbyGetTransmitPower (
void *pDeviceHandler
);
-BOOL
-CARDbChannelGetList (
- UINT uCountryCodeIdx,
- PBYTE pbyChannelTable
- );
-
-void
-CARDvSetCountryIE(
- void *pDeviceHandler,
- void *pIE
- );
-
-BOOL
-CARDbGetChannelMapInfo(
- void *pDeviceHandler,
- UINT uChannelIndex,
- PBYTE pbyChannelNumber,
- PBYTE pbyMap
- );
-
-void
-CARDvSetChannelMapInfo(
- void *pDeviceHandler,
- UINT uChannelIndex,
- BYTE byMap
- );
-
-void
-CARDvClearChannelMapInfo(
- void *pDeviceHandler
- );
-
-BYTE
-CARDbyAutoChannelSelect(
- void *pDeviceHandler,
- CARD_PHY_TYPE ePHYType
- );
-
-BYTE CARDbyGetChannelNumber(void *pDeviceHandler, BYTE byChannelIndex);
-
#endif // __CARD_H__
diff --git a/drivers/staging/vt6655/channel.c b/drivers/staging/vt6655/channel.c
new file mode 100644
index 00000000000..47c156bb70a
--- /dev/null
+++ b/drivers/staging/vt6655/channel.c
@@ -0,0 +1,835 @@
+/*
+ * Copyright (c) 1996, 2003 VIA Networking Technologies, 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.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * File: channel.c
+ *
+ */
+
+#include "baseband.h"
+#include "country.h"
+#include "channel.h"
+#include "device.h"
+#include "rf.h"
+
+/*--------------------- Static Definitions -------------------------*/
+
+#define CARD_MAX_CHANNEL_TBL 56
+
+//static int msglevel = MSG_LEVEL_DEBUG;
+static int msglevel = MSG_LEVEL_INFO;
+
+/*--------------------- Static Variables --------------------------*/
+
+static SChannelTblElement sChannelTbl[CARD_MAX_CHANNEL_TBL + 1] =
+{
+ {0, 0, false, 0},
+ {1, 2412, true, 0},
+ {2, 2417, true, 0},
+ {3, 2422, true, 0},
+ {4, 2427, true, 0},
+ {5, 2432, true, 0},
+ {6, 2437, true, 0},
+ {7, 2442, true, 0},
+ {8, 2447, true, 0},
+ {9, 2452, true, 0},
+ {10, 2457, true, 0},
+ {11, 2462, true, 0},
+ {12, 2467, true, 0},
+ {13, 2472, true, 0},
+ {14, 2484, true, 0},
+ {183, 4915, true, 0},
+ {184, 4920, true, 0},
+ {185, 4925, true, 0},
+ {187, 4935, true, 0},
+ {188, 4940, true, 0},
+ {189, 4945, true, 0},
+ {192, 4960, true, 0},
+ {196, 4980, true, 0},
+ {7, 5035, true, 0},
+ {8, 5040, true, 0},
+ {9, 5045, true, 0},
+ {11, 5055, true, 0},
+ {12, 5060, true, 0},
+ {16, 5080, true, 0},
+ {34, 5170, true, 0},
+ {36, 5180, true, 0},
+ {38, 5190, true, 0},
+ {40, 5200, true, 0},
+ {42, 5210, true, 0},
+ {44, 5220, true, 0},
+ {46, 5230, true, 0},
+ {48, 5240, true, 0},
+ {52, 5260, true, 0},
+ {56, 5280, true, 0},
+ {60, 5300, true, 0},
+ {64, 5320, true, 0},
+ {100, 5500, true, 0},
+ {104, 5520, true, 0},
+ {108, 5540, true, 0},
+ {112, 5560, true, 0},
+ {116, 5580, true, 0},
+ {120, 5600, true, 0},
+ {124, 5620, true, 0},
+ {128, 5640, true, 0},
+ {132, 5660, true, 0},
+ {136, 5680, true, 0},
+ {140, 5700, true, 0},
+ {149, 5745, true, 0},
+ {153, 5765, true, 0},
+ {157, 5785, true, 0},
+ {161, 5805, true, 0},
+ {165, 5825, true, 0}
+};
+
+/************************************************************************
+ * The Radar regulation rules for each country
+ ************************************************************************/
+static struct
+{
+ unsigned char byChannelCountryCode; /* The country code */
+ char chCountryCode[2];
+ unsigned char bChannelIdxList[CB_MAX_CHANNEL]; /* Available channels Index */
+ unsigned char byPower[CB_MAX_CHANNEL];
+} ChannelRuleTab[] =
+{
+/************************************************************************
+ * This table is based on Athero driver rules
+ ************************************************************************/
+/* Country Available channels, ended with 0 */
+/* 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 */
+{CCODE_FCC, {'U','S'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1}
+ , { 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 0, 17, 0, 17, 0, 17, 23, 23, 23, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 30, 30, 30, 30} },
+{CCODE_TELEC, {'J','P'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+ , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 23, 0, 0, 23, 0, 23, 23, 0, 23, 0, 0, 23, 23, 23, 0, 23, 0, 23, 0, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+{CCODE_ETSI, {'E','U'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0}
+ , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 20, 0, 20, 0, 20, 20, 20, 20, 20, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 0, 0, 0, 0, 0} },
+{CCODE_RESV3, {' ',' '}, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+ , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+{CCODE_RESV4, {' ',' '}, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+ , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+{CCODE_RESV5, {' ',' '}, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+ , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+{CCODE_RESV6, {' ',' '}, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+ , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+{CCODE_RESV7, {' ',' '}, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+ , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+{CCODE_RESV8, {' ',' '}, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+ , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+{CCODE_RESV9, {' ',' '}, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+ , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+{CCODE_RESVa, {' ',' '}, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+ , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+{CCODE_RESVb, {' ',' '}, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+ , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+{CCODE_RESVc, {' ',' '}, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+ , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+{CCODE_RESVd, {' ',' '}, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+ , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+{CCODE_RESVe, {' ',' '}, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+ , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+{CCODE_ALLBAND, {' ',' '}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+{CCODE_ALBANIA, {'A','L'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+ , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+{CCODE_ALGERIA, {'D','Z'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+ , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+{CCODE_ARGENTINA, {'A','R'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 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, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0}
+ , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 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, 17, 17, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 30, 30, 30, 0} },
+{CCODE_ARMENIA, {'A','M'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+ , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 18, 0, 18, 0, 18, 18, 18, 18, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+{CCODE_AUSTRALIA, {'A','U'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1}
+ , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 23, 0, 23, 0, 23, 0, 23, 23, 23, 23, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 30, 30, 30, 30} },
+{CCODE_AUSTRIA, {'A','T'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+ , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 0, 15, 0, 15, 0, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+{CCODE_AZERBAIJAN, {'A','Z'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+ , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 18, 0, 18, 0, 18, 18, 18, 18, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+{CCODE_BAHRAIN, {'B','H'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+ , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+{CCODE_BELARUS, {'B','Y'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+ , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+{CCODE_BELGIUM, {'B','E'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+ , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 18, 0, 18, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+{CCODE_BELIZE, {'B','Z'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 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, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1}
+ , { 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 30, 30, 30, 30} },
+{CCODE_BOLIVIA, {'B','O'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 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, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1}
+ , { 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 30, 30, 30, 30} },
+{CCODE_BRAZIL, {'B','R'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+ , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+{CCODE_BRUNEI_DARUSSALAM, {'B','N'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 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, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1}
+ , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 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, 30, 30, 30, 30, 30} },
+{CCODE_BULGARIA, {'B','G'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0}
+ , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 23, 0, 23, 0, 23, 0, 23, 23, 23, 0, 0, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 0, 0, 0, 0, 0} },
+{CCODE_CANADA, {'C','A'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1}
+ , { 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 0, 17, 0, 17, 0, 17, 23, 23, 23, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 30, 30, 30, 30} },
+{CCODE_CHILE, {'C','L'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 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, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1}
+ , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 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, 17, 17, 17, 17, 17} },
+{CCODE_CHINA, {'C','N'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 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, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1}
+ , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 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, 30, 30, 30, 30, 30} },
+{CCODE_COLOMBIA, {'C','O'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1}
+ , { 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 0, 17, 0, 17, 0, 17, 23, 23, 23, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 30, 30, 30, 30} },
+{CCODE_COSTA_RICA, {'C','R'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+ , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+{CCODE_CROATIA, {'H','R'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+ , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 20, 0, 20, 0, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+{CCODE_CYPRUS, {'C','Y'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0}
+ , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 20, 0, 20, 0, 20, 20, 20, 20, 20, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 0, 0, 0, 0, 0} },
+{CCODE_CZECH, {'C','Z'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+ , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 20, 0, 20, 0, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+{CCODE_DENMARK, {'D','K'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0}
+ , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 20, 0, 20, 0, 20, 20, 20, 20, 20, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 0, 0, 0, 0, 0} },
+{CCODE_DOMINICAN_REPUBLIC, {'D','O'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1}
+ , { 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 0, 17, 0, 17, 0, 17, 23, 23, 23, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 30, 30, 30, 30} },
+{CCODE_ECUADOR, {'E','C'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+ , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+{CCODE_EGYPT, {'E','G'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+ , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+{CCODE_EL_SALVADOR, {'S','V'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+ , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+{CCODE_ESTONIA, {'E','E'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0}
+ , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 20, 0, 20, 0, 20, 20, 20, 20, 20, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 0, 0, 0, 0, 0} },
+{CCODE_FINLAND, {'F','I'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0}
+ , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 20, 0, 20, 0, 20, 20, 20, 20, 20, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 0, 0, 0, 0, 0} },
+{CCODE_FRANCE, {'F','R'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+ , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 20, 0, 20, 0, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+{CCODE_GERMANY, {'D','E'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0}
+ , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 20, 0, 20, 0, 20, 20, 20, 20, 20, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 0, 0, 0, 0, 0} },
+{CCODE_GREECE, {'G','R'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+ , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+{CCODE_GEORGIA, {'G','E'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+ , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 18, 0, 18, 0, 18, 18, 18, 18, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+{CCODE_GUATEMALA, {'G','T'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1}
+ , { 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 0, 17, 0, 17, 0, 17, 23, 23, 23, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 30, 30, 30, 30} },
+{CCODE_HONDURAS, {'H','N'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+ , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+{CCODE_HONG_KONG, {'H','K'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1}
+ , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 23, 0, 23, 0, 23, 0, 23, 23, 23, 23, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 30, 30, 30, 30} },
+{CCODE_HUNGARY, {'H','U'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+ , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 18, 0, 18, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+{CCODE_ICELAND, {'I','S'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0}
+ , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 20, 0, 20, 0, 20, 20, 20, 20, 20, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 0, 0, 0, 0, 0} },
+{CCODE_INDIA, {'I','N'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+ , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+{CCODE_INDONESIA, {'I','D'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+ , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+{CCODE_IRAN, {'I','R'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 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, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1}
+ , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 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, 30, 30, 30, 30, 30} },
+{CCODE_IRELAND, {'I','E'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0}
+ , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 20, 0, 20, 0, 20, 20, 20, 20, 20, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 0, 0, 0, 0, 0} },
+{CCODE_ITALY, {'I','T'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0}
+ , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 20, 0, 20, 0, 20, 20, 20, 20, 20, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 0, 0, 0, 0, 0} },
+{CCODE_ISRAEL, {'I','L'}, { 0, 0, 0, 0, 1, 1, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+ , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+{CCODE_JAPAN, {'J','P'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+ , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 23, 0, 23, 0, 23, 0, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+{CCODE_JORDAN, {'J','O'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+ , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+{CCODE_KAZAKHSTAN, {'K','Z'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+ , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+{CCODE_KUWAIT, {'K','W'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+ , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+{CCODE_LATVIA, {'L','V'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+ , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+{CCODE_LEBANON, {'L','B'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+ , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+{CCODE_LEICHTENSTEIN, {'L','I'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+ , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 18, 0, 18, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+{CCODE_LITHUANIA, {'L','T'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0}
+ , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 20, 0, 20, 0, 20, 20, 20, 20, 20, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 0, 0, 0, 0, 0} },
+{CCODE_LUXEMBURG, {'L','U'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0}
+ , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 20, 0, 20, 0, 20, 20, 20, 20, 20, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 0, 0, 0, 0, 0} },
+{CCODE_MACAU, {'M','O'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1}
+ , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 23, 0, 23, 0, 23, 0, 23, 23, 23, 23, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 30, 30, 30, 30} },
+{CCODE_MACEDONIA, {'M','K'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+ , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+{CCODE_MALTA, {'M','T'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0}
+ , { 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 16, 0, 16, 0, 16, 16, 16, 16, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 16, 16, 16, 0} },
+{CCODE_MALAYSIA, {'M','Y'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+ , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+{CCODE_MEXICO, {'M','X'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1}
+ , { 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 0, 17, 0, 17, 0, 17, 23, 23, 23, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 30, 30, 30, 30} },
+{CCODE_MONACO, {'M','C'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+ , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 18, 0, 18, 0, 18, 18, 18, 18, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+{CCODE_MOROCCO, {'M','A'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+ , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+{CCODE_NETHERLANDS, {'N','L'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0}
+ , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 20, 0, 20, 0, 20, 20, 20, 20, 20, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 0, 0, 0, 0, 0} },
+{CCODE_NEW_ZEALAND, {'N','Z'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1}
+ , { 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 23, 0, 23, 0, 23, 0, 23, 23, 23, 23, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 30, 30, 30, 30} },
+{CCODE_NORTH_KOREA, {'K','P'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 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, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0}
+ , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 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, 23, 23, 23, 23, 0} },
+{CCODE_NORWAY, {'N','O'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0}
+ , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 20, 0, 20, 0, 20, 20, 20, 20, 20, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 0, 0, 0, 0, 0} },
+{CCODE_OMAN, {'O','M'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+ , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+{CCODE_PAKISTAN, {'P','K'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+ , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+{CCODE_PANAMA, {'P','A'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1}
+ , { 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 0, 17, 0, 17, 0, 17, 23, 23, 23, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 30, 30, 30, 30} },
+{CCODE_PERU, {'P','E'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+ , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+{CCODE_PHILIPPINES, {'P','H'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1}
+ , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 0, 17, 0, 17, 0, 17, 23, 23, 23, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 30, 30, 30, 30} },
+{CCODE_POLAND, {'P','L'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0}
+ , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 20, 0, 20, 0, 20, 20, 20, 20, 20, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 0, 0, 0, 0, 0} },
+{CCODE_PORTUGAL, {'P','T'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0}
+ , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 20, 0, 20, 0, 20, 20, 20, 20, 20, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 0, 0, 0, 0, 0} },
+{CCODE_PUERTO_RICO, {'P','R'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1}
+ , { 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 0, 17, 0, 17, 0, 17, 23, 23, 23, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 30, 30, 30, 30} },
+{CCODE_QATAR, {'Q','A'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+ , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+{CCODE_ROMANIA, {'R','O'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+ , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+{CCODE_RUSSIA, {'R','U'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+ , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+{CCODE_SAUDI_ARABIA, {'S','A'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+ , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+{CCODE_SINGAPORE, {'S','G'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1}
+ , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 20, 0, 20, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 20, 20, 20, 20} },
+{CCODE_SLOVAKIA, {'S','K'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0}
+ , { 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 16, 0, 16, 0, 16, 16, 16, 16, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 16, 16, 16, 0} },
+{CCODE_SLOVENIA, {'S','I'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0}
+ , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 20, 0, 20, 0, 20, 20, 20, 20, 20, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 0, 0, 0, 0, 0} },
+{CCODE_SOUTH_AFRICA, {'Z','A'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0}
+ , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 20, 0, 20, 0, 20, 20, 20, 20, 20, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 0, 0, 0, 0, 0} },
+{CCODE_SOUTH_KOREA, {'K','R'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 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, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0}
+ , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 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, 23, 23, 23, 23, 0} },
+{CCODE_SPAIN, {'E','S'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0}
+ , { 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 16, 0, 16, 0, 16, 16, 16, 16, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 16, 16, 16, 0} },
+{CCODE_SWEDEN, {'S','E'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0}
+ , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 20, 0, 20, 0, 20, 20, 20, 20, 20, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 0, 0, 0, 0, 0} },
+{CCODE_SWITZERLAND, {'C','H'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+ , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 18, 0, 18, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+{CCODE_SYRIA, {'S','Y'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+ , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+{CCODE_TAIWAN, {'T','W'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 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, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0}
+ , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 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, 17, 17, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 30, 30, 30, 0} },
+{CCODE_THAILAND, {'T','H'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 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, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0}
+ , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 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, 23, 23, 23, 23, 0} },
+{CCODE_TRINIDAD_TOBAGO, {'T','T'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+ , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 18, 0, 18, 0, 18, 18, 18, 18, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+{CCODE_TUNISIA, {'T','N'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+ , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 20, 0, 20, 0, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+{CCODE_TURKEY, {'T','R'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+ , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 20, 0, 20, 0, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+{CCODE_UK, {'G','B'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0}
+ , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 20, 0, 20, 0, 20, 20, 20, 20, 20, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 0, 0, 0, 0, 0} },
+{CCODE_UKRAINE, {'U','A'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+ , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+{CCODE_UNITED_ARAB_EMIRATES, {'A','E'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+ , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+{CCODE_UNITED_STATES, {'U','S'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1}
+ , { 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 0, 17, 0, 17, 0, 17, 23, 23, 23, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 30, 30, 30, 30} },
+{CCODE_URUGUAY, {'U','Y'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 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, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0}
+ , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 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, 23, 23, 23, 23, 0} },
+{CCODE_UZBEKISTAN, {'U','Z'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+ , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+{CCODE_VENEZUELA, {'V','E'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 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, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0}
+ , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 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, 23, 23, 23, 23, 0} },
+{CCODE_VIETNAM, {'V','N'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+ , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+{CCODE_YEMEN, {'Y','E'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+ , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+{CCODE_ZIMBABWE, {'Z','W'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+ , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+{CCODE_JAPAN_W52_W53, {'J','J'}, { 0, 0, 0, 0, 0, 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, 1, 0, 1, 0, 1, 1, 1, 1, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+{CCODE_MAX, {'U','N'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }
+/* 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 */
+};
+
+/*--------------------- Export Functions --------------------------*/
+
+/**
+ * is_channel_valid() - Is Country Channel Valid
+ * @ChanneIndex: defined as VT3253 MAC channel:
+ * 1 = 2.4G channel 1
+ * 2 = 2.4G channel 2
+ * ...
+ * 14 = 2.4G channel 14
+ * 15 = 4.9G channel 183
+ * 16 = 4.9G channel 184
+ * .....
+ * Output: true if the specified 5GHz band is allowed to be used,
+ * false otherwise.
+ * 4.9G => Ch 183, 184, 185, 187, 188, 189, 192, 196 (Value:15 ~ 22)
+ *
+ * 5G => Ch 7, 8, 9, 11, 12, 16, 34, 36, 38, 40, 42, 44, 46, 48, 52, 56, 60, 64,
+ * 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140, 149, 153, 157, 161, 165 (Value 23 ~ 56)
+ */
+
+bool is_channel_valid(unsigned int ChannelIndex)
+{
+ bool bValid;
+
+ bValid = false;
+ /*
+ * If Channel Index is invalid, return invalid
+ */
+ if ((ChannelIndex > CB_MAX_CHANNEL) ||
+ (ChannelIndex == 0))
+ {
+ bValid = false;
+ goto exit;
+ }
+
+ bValid = sChannelTbl[ChannelIndex].bValid;
+
+exit:
+ return (bValid);
+
+}
+
+/**
+ * channel_get_list() - Get Available Channel List for a given country
+ * @CountryCode: The country code defined in country.h
+ *
+ * Output:
+ * pbyChannelTable: (QWORD *) correspondent bit mask
+ * of available channels
+ * 0x0000000000000001 means channel 1 is supported
+ * 0x0000000000000003 means channel 1,2 are supported
+ * 0x000000000000000F means channel 1,2,..15 are supported
+ */
+
+bool channel_get_list(unsigned int uCountryCodeIdx, unsigned char *pbyChannelTable)
+{
+ if (uCountryCodeIdx >= CCODE_MAX)
+ return (false);
+
+ memcpy(pbyChannelTable, ChannelRuleTab[uCountryCodeIdx].bChannelIdxList, CB_MAX_CHANNEL);
+
+ return (true);
+}
+
+void init_channel_table(void *pDeviceHandler)
+{
+ PSDevice pDevice = (PSDevice) pDeviceHandler;
+ bool bMultiBand = false;
+ unsigned int ii;
+
+ for(ii = 1 ; ii<=CARD_MAX_CHANNEL_TBL ; ii++) {
+ sChannelTbl[ii].bValid = false;
+ }
+
+ switch (pDevice->byRFType) {
+ case RF_RFMD2959 :
+ case RF_AIROHA :
+ case RF_AL2230S:
+ case RF_UW2451 :
+ case RF_VT3226 :
+ //printk("chester-false\n");
+ bMultiBand = false;
+ break;
+ case RF_AIROHA7230 :
+ case RF_UW2452 :
+ case RF_NOTHING :
+ default :
+ bMultiBand = true;
+ break;
+ }
+
+ if ((pDevice->dwDiagRefCount != 0) || (pDevice->b11hEnable == true)) {
+ if (bMultiBand == true) {
+ for(ii = 0 ; ii<CARD_MAX_CHANNEL_TBL ; ii++) {
+ sChannelTbl[ii+1].bValid = true;
+ pDevice->abyRegPwr[ii+1] = pDevice->abyOFDMDefaultPwr[ii+1];
+ pDevice->abyLocalPwr[ii+1] = pDevice->abyOFDMDefaultPwr[ii+1];
+ }
+ for(ii = 0 ; ii<CHANNEL_MAX_24G ; ii++) {
+ pDevice->abyRegPwr[ii+1] = pDevice->abyCCKDefaultPwr[ii+1];
+ pDevice->abyLocalPwr[ii+1] = pDevice->abyCCKDefaultPwr[ii+1];
+ }
+ } else {
+ for(ii = 0 ; ii<CHANNEL_MAX_24G ; ii++) {
+ //2008-8-4 <add> by chester
+ if (ChannelRuleTab[pDevice->byZoneType].bChannelIdxList[ii] != 0) {
+ sChannelTbl[ii+1].bValid = true;
+ pDevice->abyRegPwr[ii+1] = pDevice->abyCCKDefaultPwr[ii+1];
+ pDevice->abyLocalPwr[ii+1] = pDevice->abyCCKDefaultPwr[ii+1];
+ }
+ }
+ }
+ } else if (pDevice->byZoneType <= CCODE_MAX) {
+ if (bMultiBand == true) {
+ for(ii = 0 ; ii<CARD_MAX_CHANNEL_TBL ; ii++) {
+ if (ChannelRuleTab[pDevice->byZoneType].bChannelIdxList[ii] != 0) {
+ sChannelTbl[ii+1].bValid = true;
+ pDevice->abyRegPwr[ii+1] = ChannelRuleTab[pDevice->byZoneType].byPower[ii];
+ pDevice->abyLocalPwr[ii+1] = ChannelRuleTab[pDevice->byZoneType].byPower[ii];
+ }
+ }
+ } else {
+ for(ii = 0 ; ii<CHANNEL_MAX_24G ; ii++) {
+ if (ChannelRuleTab[pDevice->byZoneType].bChannelIdxList[ii] != 0) {
+ sChannelTbl[ii+1].bValid = true;
+ pDevice->abyRegPwr[ii+1] = ChannelRuleTab[pDevice->byZoneType].byPower[ii];
+ pDevice->abyLocalPwr[ii+1] = ChannelRuleTab[pDevice->byZoneType].byPower[ii];
+ }
+ }
+ }
+ }
+
+ DBG_PRT(MSG_LEVEL_NOTICE, KERN_INFO"Zone=[%d][%c][%c]!!\n",pDevice->byZoneType,ChannelRuleTab[pDevice->byZoneType].chCountryCode[0],ChannelRuleTab[pDevice->byZoneType].chCountryCode[1]);
+
+ for(ii = 0 ; ii<CARD_MAX_CHANNEL_TBL ; ii++) {
+ if (pDevice->abyRegPwr[ii+1] == 0)
+ pDevice->abyRegPwr[ii+1] = pDevice->abyOFDMDefaultPwr[ii+1];
+ if (pDevice->abyLocalPwr[ii+1] == 0)
+ pDevice->abyLocalPwr[ii+1] = pDevice->abyOFDMDefaultPwr[ii+1];
+ }
+}
+
+unsigned char get_channel_mapping(void *pDeviceHandler, unsigned char byChannelNumber, CARD_PHY_TYPE ePhyType)
+{
+ unsigned int ii;
+
+ if ((ePhyType == PHY_TYPE_11B) || (ePhyType == PHY_TYPE_11G))
+ return (byChannelNumber);
+
+ for(ii = (CB_MAX_CHANNEL_24G + 1); ii <= CB_MAX_CHANNEL; ) {
+ if (sChannelTbl[ii].byChannelNumber == byChannelNumber)
+ return ((unsigned char) ii);
+ ii++;
+ }
+ return 0;
+}
+
+unsigned char get_channel_number(void *pDeviceHandler, unsigned char byChannelIndex)
+{
+ //PSDevice pDevice = (PSDevice) pDeviceHandler;
+ return(sChannelTbl[byChannelIndex].byChannelNumber);
+}
+
+/**
+ * set_channel() - Set NIC media channel
+ *
+ * @pDeviceHandler: The adapter to be set
+ * @uConnectionChannel: Channel to be set
+ *
+ * Return Value: true if succeeded; false if failed.
+ *
+ */
+bool set_channel (void *pDeviceHandler, unsigned int uConnectionChannel)
+{
+ PSDevice pDevice = (PSDevice) pDeviceHandler;
+ bool bResult = true;
+
+
+ if (pDevice->byCurrentCh == uConnectionChannel) {
+ return bResult;
+ }
+
+ if (sChannelTbl[uConnectionChannel].bValid == false) {
+ return (false);
+ }
+
+ if ((uConnectionChannel > CB_MAX_CHANNEL_24G) &&
+ (pDevice->eCurrentPHYType != PHY_TYPE_11A)) {
+ CARDbSetPhyParameter(pDevice, PHY_TYPE_11A, 0, 0, NULL, NULL);
+ } else if ((uConnectionChannel <= CB_MAX_CHANNEL_24G) &&
+ (pDevice->eCurrentPHYType == PHY_TYPE_11A)) {
+ CARDbSetPhyParameter(pDevice, PHY_TYPE_11G, 0, 0, NULL, NULL);
+ }
+ // clear NAV
+ MACvRegBitsOn(pDevice->PortOffset, MAC_REG_MACCR, MACCR_CLRNAV);
+
+ //{{ RobertYu: 20041202
+ //// TX_PE will reserve 3 us for MAX2829 A mode only, it is for better TX throughput
+
+ if ( pDevice->byRFType == RF_AIROHA7230 )
+ {
+ RFbAL7230SelectChannelPostProcess(pDevice->PortOffset, pDevice->byCurrentCh, (unsigned char)uConnectionChannel);
+ }
+ //}} RobertYu
+
+
+ pDevice->byCurrentCh = (unsigned char)uConnectionChannel;
+ bResult &= RFbSelectChannel(pDevice->PortOffset, pDevice->byRFType, (unsigned char)uConnectionChannel);
+
+ // Init Synthesizer Table
+ if (pDevice->bEnablePSMode == true)
+ RFvWriteWakeProgSyn(pDevice->PortOffset, pDevice->byRFType, uConnectionChannel);
+
+
+ //DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"CARDbSetMediaChannel: %d\n", (unsigned char)uConnectionChannel);
+ BBvSoftwareReset(pDevice->PortOffset);
+
+ if (pDevice->byLocalID > REV_ID_VT3253_B1) {
+ // set HW default power register
+ MACvSelectPage1(pDevice->PortOffset);
+ RFbSetPower(pDevice, RATE_1M, pDevice->byCurrentCh);
+ VNSvOutPortB(pDevice->PortOffset + MAC_REG_PWRCCK, pDevice->byCurPwr);
+ RFbSetPower(pDevice, RATE_6M, pDevice->byCurrentCh);
+ VNSvOutPortB(pDevice->PortOffset + MAC_REG_PWROFDM, pDevice->byCurPwr);
+ MACvSelectPage0(pDevice->PortOffset);
+ }
+
+ if (pDevice->eCurrentPHYType == PHY_TYPE_11B) {
+#ifdef PLICE_DEBUG
+ //printk("Func:ChbSetChannel:call RFbSetPower:11B\n");
+#endif
+ RFbSetPower(pDevice, RATE_1M, pDevice->byCurrentCh);
+ } else {
+#ifdef PLICE_DEBUG
+ //printk("Func:ChbSetChannel:call RFbSetPower\n");
+#endif
+ RFbSetPower(pDevice, RATE_6M, pDevice->byCurrentCh);
+ }
+
+ return(bResult);
+}
+
+/**
+ * set_country_info() - Set Channel Info of Country
+ *
+ * Return Value: none.
+ *
+ */
+
+void set_country_info(void *pDeviceHandler, CARD_PHY_TYPE ePHYType, void *pIE)
+{
+ PSDevice pDevice = (PSDevice) pDeviceHandler;
+ unsigned int ii = 0;
+ unsigned int uu = 0;
+ unsigned int step = 0;
+ unsigned int uNumOfCountryInfo = 0;
+ unsigned char byCh = 0;
+ PWLAN_IE_COUNTRY pIE_Country = (PWLAN_IE_COUNTRY) pIE;
+
+
+ uNumOfCountryInfo = (pIE_Country->len - 3);
+ uNumOfCountryInfo /= 3;
+
+ if (ePHYType == PHY_TYPE_11A) {
+ pDevice->bCountryInfo5G = true;
+ for(ii = CB_MAX_CHANNEL_24G + 1 ; ii <= CARD_MAX_CHANNEL_TBL ; ii++) {
+ sChannelTbl[ii].bValid = false;
+ }
+ step = 4;
+ } else {
+ pDevice->bCountryInfo24G = true;
+ for(ii = 1 ; ii <= CB_MAX_CHANNEL_24G ; ii++) {
+ sChannelTbl[ii].bValid = false;
+ }
+ step = 1;
+ }
+ pDevice->abyCountryCode[0] = pIE_Country->abyCountryString[0];
+ pDevice->abyCountryCode[1] = pIE_Country->abyCountryString[1];
+ pDevice->abyCountryCode[2] = pIE_Country->abyCountryString[2];
+
+ for(ii = 0 ; ii < uNumOfCountryInfo ; ii++) {
+ for(uu = 0 ; uu < pIE_Country->abyCountryInfo[ii*3+1] ; uu++) {
+ byCh = get_channel_mapping(pDevice, (unsigned char)(pIE_Country->abyCountryInfo[ii*3]+step*uu), ePHYType);
+ sChannelTbl[byCh].bValid = true;
+ pDevice->abyRegPwr[byCh] = pIE_Country->abyCountryInfo[ii*3+2];
+ }
+ }
+}
+
+/**
+ *
+ * set_support_channels() - Set Support Channels IE defined in 802.11h
+ *
+ * @hDeviceContext: device structure point
+ *
+ * Return Value: none.
+ *
+ */
+
+unsigned char set_support_channels(void *pDeviceHandler, unsigned char *pbyIEs)
+{
+ PSDevice pDevice = (PSDevice) pDeviceHandler;
+ unsigned int ii;
+ unsigned char byCount;
+ PWLAN_IE_SUPP_CH pIE = (PWLAN_IE_SUPP_CH) pbyIEs;
+ unsigned char *pbyChTupple;
+ unsigned char byLen = 0;
+
+
+ pIE->byElementID = WLAN_EID_SUPP_CH;
+ pIE->len = 0;
+ pbyChTupple = pIE->abyChannelTuple;
+ byLen = 2;
+ // lower band
+ byCount = 0;
+ if (ChannelRuleTab[pDevice->byZoneType].bChannelIdxList[28] == true) {
+ for (ii = 28 ; ii < 36 ; ii+= 2) {
+ if (ChannelRuleTab[pDevice->byZoneType].bChannelIdxList[ii] == true) {
+ byCount++;
+ }
+ }
+ *pbyChTupple++ = 34;
+ *pbyChTupple++ = byCount;
+ byLen += 2;
+ } else if (ChannelRuleTab[pDevice->byZoneType].bChannelIdxList[29] == true) {
+ for (ii = 29 ; ii < 36 ; ii+= 2) {
+ if (ChannelRuleTab[pDevice->byZoneType].bChannelIdxList[ii] == true) {
+ byCount++;
+ }
+ }
+ *pbyChTupple++ = 36;
+ *pbyChTupple++ = byCount;
+ byLen += 2;
+ }
+ // middle band
+ byCount = 0;
+ if (ChannelRuleTab[pDevice->byZoneType].bChannelIdxList[36] == true) {
+ for (ii = 36 ; ii < 40 ; ii++) {
+ if (ChannelRuleTab[pDevice->byZoneType].bChannelIdxList[ii] == true) {
+ byCount++;
+ }
+ }
+ *pbyChTupple++ = 52;
+ *pbyChTupple++ = byCount;
+ byLen += 2;
+ }
+ // higher band
+ byCount = 0;
+ if (ChannelRuleTab[pDevice->byZoneType].bChannelIdxList[40] == true) {
+ for (ii = 40 ; ii < 51 ; ii++) {
+ if (ChannelRuleTab[pDevice->byZoneType].bChannelIdxList[ii] == true) {
+ byCount++;
+ }
+ }
+ *pbyChTupple++ = 100;
+ *pbyChTupple++ = byCount;
+ byLen += 2;
+ } else if (ChannelRuleTab[pDevice->byZoneType].bChannelIdxList[51] == true) {
+ for (ii = 51 ; ii < 56 ; ii++) {
+ if (ChannelRuleTab[pDevice->byZoneType].bChannelIdxList[ii] == true) {
+ byCount++;
+ }
+ }
+ *pbyChTupple++ = 149;
+ *pbyChTupple++ = byCount;
+ byLen += 2;
+ }
+ pIE->len += (byLen - 2);
+ return (byLen);
+}
+
+void set_country_IE(void *pDeviceHandler, void *pIE)
+{
+ PSDevice pDevice = (PSDevice) pDeviceHandler;
+ unsigned int ii;
+ PWLAN_IE_COUNTRY pIECountry = (PWLAN_IE_COUNTRY) pIE;
+
+ pIECountry->byElementID = WLAN_EID_COUNTRY;
+ pIECountry->len = 0;
+ pIECountry->abyCountryString[0] = ChannelRuleTab[pDevice->byZoneType].chCountryCode[0];
+ pIECountry->abyCountryString[1] = ChannelRuleTab[pDevice->byZoneType].chCountryCode[1];
+ pIECountry->abyCountryString[2] = ' ';
+ for (ii = CB_MAX_CHANNEL_24G; ii < CB_MAX_CHANNEL; ii++ ) {
+ if (ChannelRuleTab[pDevice->byZoneType].bChannelIdxList[ii] != 0) {
+ pIECountry->abyCountryInfo[pIECountry->len++] = sChannelTbl[ii+1].byChannelNumber;
+ pIECountry->abyCountryInfo[pIECountry->len++] = 1;
+ pIECountry->abyCountryInfo[pIECountry->len++] = ChannelRuleTab[pDevice->byZoneType].byPower[ii];
+ }
+ }
+ pIECountry->len += 3;
+}
+
+bool get_channel_map_info(void *pDeviceHandler, unsigned int uChannelIndex,
+ unsigned char *pbyChannelNumber, unsigned char *pbyMap)
+{
+
+ if (uChannelIndex > CB_MAX_CHANNEL) {
+ return false;
+ }
+ *pbyChannelNumber = sChannelTbl[uChannelIndex].byChannelNumber;
+ *pbyMap = sChannelTbl[uChannelIndex].byMAP;
+ return sChannelTbl[uChannelIndex].bValid;
+}
+
+void set_channel_map_info(void *pDeviceHandler, unsigned int uChannelIndex,
+ unsigned char byMap)
+{
+
+ if (uChannelIndex > CB_MAX_CHANNEL) {
+ return;
+ }
+ sChannelTbl[uChannelIndex].byMAP |= byMap;
+}
+
+void clear_channel_map_info(void *pDeviceHandler)
+{
+ unsigned int ii = 0;
+
+ for (ii = 1; ii <= CB_MAX_CHANNEL; ii++) {
+ sChannelTbl[ii].byMAP = 0;
+ }
+}
+
+unsigned char auto_channel_select(void *pDeviceHandler, CARD_PHY_TYPE ePHYType)
+{
+ unsigned int ii = 0;
+ unsigned char byOptionChannel = 0;
+ int aiWeight[CB_MAX_CHANNEL_24G+1] = {-1000,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
+
+ if (ePHYType == PHY_TYPE_11A) {
+ for(ii = CB_MAX_CHANNEL_24G + 1 ; ii <= CB_MAX_CHANNEL ; ii++) {
+ if (sChannelTbl[ii].bValid == true) {
+ if (byOptionChannel == 0) {
+ byOptionChannel = (unsigned char) ii;
+ }
+ if (sChannelTbl[ii].byMAP == 0) {
+ return ((unsigned char) ii);
+ } else if ( !(sChannelTbl[ii].byMAP & 0x08)) {
+ byOptionChannel = (unsigned char) ii;
+ }
+ }
+ }
+ } else {
+ byOptionChannel = 0;
+ for(ii = 1 ; ii <= CB_MAX_CHANNEL_24G ; ii++) {
+ if (sChannelTbl[ii].bValid == true) {
+ if (sChannelTbl[ii].byMAP == 0) {
+ aiWeight[ii] += 100;
+ } else if (sChannelTbl[ii].byMAP & 0x01) {
+ if (ii > 3) {
+ aiWeight[ii-3] -= 10;
+ }
+ if (ii > 2) {
+ aiWeight[ii-2] -= 20;
+ }
+ if (ii > 1) {
+ aiWeight[ii-1] -= 40;
+ }
+ aiWeight[ii] -= 80;
+ if (ii < CB_MAX_CHANNEL_24G) {
+ aiWeight[ii+1] -= 40;
+ }
+ if (ii < (CB_MAX_CHANNEL_24G - 1)) {
+ aiWeight[ii+2] -= 20;
+ }
+ if (ii < (CB_MAX_CHANNEL_24G - 2)) {
+ aiWeight[ii+3] -= 10;
+ }
+ }
+ }
+ }
+ for(ii = 1 ; ii <= CB_MAX_CHANNEL_24G ; ii++) {
+ if ((sChannelTbl[ii].bValid == true) &&
+ (aiWeight[ii] > aiWeight[byOptionChannel])) {
+ byOptionChannel = (unsigned char) ii;
+ }
+ }
+ }
+ return (byOptionChannel);
+}
diff --git a/drivers/staging/vt6655/channel.h b/drivers/staging/vt6655/channel.h
new file mode 100644
index 00000000000..7038f0d3bde
--- /dev/null
+++ b/drivers/staging/vt6655/channel.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 1996, 2003 VIA Networking Technologies, 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.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * File: channel.h
+ *
+ */
+
+#ifndef _CHANNEL_H_
+#define _CHANNEL_H_
+
+#include "ttype.h"
+#include "card.h"
+
+/*--------------------- Export Classes ----------------------------*/
+
+typedef struct tagSChannelTblElement {
+ unsigned char byChannelNumber;
+ unsigned int uFrequency;
+ bool bValid;
+ unsigned char byMAP;
+}SChannelTblElement, *PSChannelTblElement;
+
+
+/*--------------------- Export Functions --------------------------*/
+
+bool is_channel_valid(unsigned int CountryCode);
+void init_channel_table(void *pDeviceHandler);
+unsigned char get_channel_mapping(void *pDeviceHandler, unsigned char byChannelNumber, CARD_PHY_TYPE ePhyType);
+bool channel_get_list(unsigned int uCountryCodeIdx, unsigned char *pbyChannelTable);
+unsigned char get_channel_number(void *pDeviceHandler, unsigned char byChannelIndex);
+bool set_channel(void *pDeviceHandler, unsigned int uConnectionChannel);
+void set_country_info(void *pDeviceHandler, CARD_PHY_TYPE ePHYType, void *pIE);
+unsigned char set_support_channels(void *pDeviceHandler, unsigned char *pbyIEs);
+void set_country_IE(void *pDeviceHandler, void *pIE);
+bool get_channel_map_info(void *pDeviceHandler, unsigned int uChannelIndex,
+ unsigned char *pbyChannelNumber, unsigned char *pbyMap);
+void set_channel_map_info(void *pDeviceHandler, unsigned int uChannelIndex,
+ unsigned char byMap);
+void clear_channel_map_info(void *pDeviceHandler);
+unsigned char auto_channel_select(void *pDeviceHandler, CARD_PHY_TYPE ePHYType);
+
+
+#endif /* _CHANNEL_H_ */
diff --git a/drivers/staging/vt6655/country.h b/drivers/staging/vt6655/country.h
index 2005d276868..05fda410420 100644
--- a/drivers/staging/vt6655/country.h
+++ b/drivers/staging/vt6655/country.h
@@ -159,19 +159,4 @@ typedef enum _COUNTRY_CODE {
CCODE_MAX
} COUNTRY_CODE;
-typedef struct tagSCountryTable
-{
- BYTE byChannelCountryCode; /* The country code */
- CHAR chCountryCode[2];
- BYTE bChannelIdxList[CB_MAX_CHANNEL]; /* Available channels Index */
- BYTE byPower[CB_MAX_CHANNEL];
-} SCountryTable, *PSCountryTable;
-
-/*--------------------- Export Classes ----------------------------*/
-
-/*--------------------- Export Variables --------------------------*/
-extern SCountryTable ChannelRuleTab[CCODE_MAX+1];
-
-/*--------------------- Export Functions --------------------------*/
-
#endif /* __COUNTRY_H__ */
diff --git a/drivers/staging/vt6655/datarate.c b/drivers/staging/vt6655/datarate.c
index 38b09a7fb53..efbb8f45f72 100644
--- a/drivers/staging/vt6655/datarate.c
+++ b/drivers/staging/vt6655/datarate.c
@@ -51,11 +51,11 @@
/*--------------------- Static Classes ----------------------------*/
- extern WORD TxRate_iwconfig; //2008-5-8 <add> by chester
+ extern unsigned short TxRate_iwconfig; //2008-5-8 <add> by chester
/*--------------------- Static Variables --------------------------*/
//static int msglevel =MSG_LEVEL_DEBUG;
static int msglevel =MSG_LEVEL_INFO;
-const BYTE acbyIERate[MAX_RATE] =
+const unsigned char acbyIERate[MAX_RATE] =
{0x02, 0x04, 0x0B, 0x16, 0x0C, 0x12, 0x18, 0x24, 0x30, 0x48, 0x60, 0x6C};
#define AUTORATE_TXOK_CNT 0x0400
@@ -75,7 +75,7 @@ s_vResetCounter (
PKnownNodeDB psNodeDBTable
)
{
- BYTE ii;
+ unsigned char ii;
// clear statistic counter for auto_rate
for(ii=0;ii<=MAX_RATE;ii++) {
@@ -97,19 +97,19 @@ s_vResetCounter (
*
* Parameters:
* In:
- * BYTE - Rate value in SuppRates IE or ExtSuppRates IE
+ * unsigned char - Rate value in SuppRates IE or ExtSuppRates IE
* Out:
* none
*
* Return Value: RateIdx
*
-*/
-BYTE
+unsigned char
DATARATEbyGetRateIdx (
- BYTE byRate
+ unsigned char byRate
)
{
- BYTE ii;
+ unsigned char ii;
//Erase basicRate flag.
byRate = byRate & 0x7F;//0111 1111
@@ -151,19 +151,19 @@ DATARATEbyGetRateIdx (
*
* Parameters:
* In:
- * BYTE - Rate value in SuppRates IE or ExtSuppRates IE
+ * unsigned char - Rate value in SuppRates IE or ExtSuppRates IE
* Out:
* none
*
* Return Value: RateIdx
*
-*/
-WORD
+unsigned short
wGetRateIdx(
- BYTE byRate
+ unsigned char byRate
)
{
- WORD ii;
+ unsigned short ii;
//Erase basicRate flag.
byRate = byRate & 0x7F;//0111 1111
@@ -199,20 +199,20 @@ RATEvParseMaxRate (
void *pDeviceHandler,
PWLAN_IE_SUPP_RATES pItemRates,
PWLAN_IE_SUPP_RATES pItemExtRates,
- BOOL bUpdateBasicRate,
- PWORD pwMaxBasicRate,
- PWORD pwMaxSuppRate,
- PWORD pwSuppRate,
- PBYTE pbyTopCCKRate,
- PBYTE pbyTopOFDMRate
+ bool bUpdateBasicRate,
+ unsigned short *pwMaxBasicRate,
+ unsigned short *pwMaxSuppRate,
+ unsigned short *pwSuppRate,
+ unsigned char *pbyTopCCKRate,
+ unsigned char *pbyTopOFDMRate
)
{
PSDevice pDevice = (PSDevice) pDeviceHandler;
-UINT ii;
-BYTE byHighSuppRate = 0;
-BYTE byRate = 0;
-WORD wOldBasicRate = pDevice->wBasicRate;
-UINT uRateLen;
+unsigned int ii;
+unsigned char byHighSuppRate = 0;
+unsigned char byRate = 0;
+unsigned short wOldBasicRate = pDevice->wBasicRate;
+unsigned int uRateLen;
if (pItemRates == NULL)
@@ -231,14 +231,14 @@ UINT uRateLen;
}
for (ii = 0; ii < uRateLen; ii++) {
- byRate = (BYTE)(pItemRates->abyRates[ii]);
+ byRate = (unsigned char)(pItemRates->abyRates[ii]);
if (WLAN_MGMT_IS_BASICRATE(byRate) &&
- (bUpdateBasicRate == TRUE)) {
+ (bUpdateBasicRate == true)) {
// Add to basic rate set, update pDevice->byTopCCKBasicRate and pDevice->byTopOFDMBasicRate
CARDbAddBasicRate((void *)pDevice, wGetRateIdx(byRate));
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"ParseMaxRate AddBasicRate: %d\n", wGetRateIdx(byRate));
}
- byRate = (BYTE)(pItemRates->abyRates[ii]&0x7F);
+ byRate = (unsigned char)(pItemRates->abyRates[ii]&0x7F);
if (byHighSuppRate == 0)
byHighSuppRate = byRate;
if (byRate > byHighSuppRate)
@@ -248,20 +248,20 @@ UINT uRateLen;
if ((pItemExtRates != NULL) && (pItemExtRates->byElementID == WLAN_EID_EXTSUPP_RATES) &&
(pDevice->eCurrentPHYType != PHY_TYPE_11B)) {
- UINT uExtRateLen = pItemExtRates->len;
+ unsigned int uExtRateLen = pItemExtRates->len;
if (uExtRateLen > WLAN_RATES_MAXLEN)
uExtRateLen = WLAN_RATES_MAXLEN;
for (ii = 0; ii < uExtRateLen ; ii++) {
- byRate = (BYTE)(pItemExtRates->abyRates[ii]);
+ byRate = (unsigned char)(pItemExtRates->abyRates[ii]);
// select highest basic rate
if (WLAN_MGMT_IS_BASICRATE(pItemExtRates->abyRates[ii])) {
// Add to basic rate set, update pDevice->byTopCCKBasicRate and pDevice->byTopOFDMBasicRate
CARDbAddBasicRate((void *)pDevice, wGetRateIdx(byRate));
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"ParseMaxRate AddBasicRate: %d\n", wGetRateIdx(byRate));
}
- byRate = (BYTE)(pItemExtRates->abyRates[ii]&0x7F);
+ byRate = (unsigned char)(pItemExtRates->abyRates[ii]&0x7F);
if (byHighSuppRate == 0)
byHighSuppRate = byRate;
if (byRate > byHighSuppRate)
@@ -314,14 +314,14 @@ RATEvTxRateFallBack (
)
{
PSDevice pDevice = (PSDevice) pDeviceHandler;
-WORD wIdxDownRate = 0;
-UINT ii;
-//DWORD dwRateTable[MAX_RATE] = {1, 2, 5, 11, 6, 9, 12, 18, 24, 36, 48, 54};
-BOOL bAutoRate[MAX_RATE] = {TRUE,TRUE,TRUE,TRUE,FALSE,FALSE,TRUE,TRUE,TRUE,TRUE,TRUE,TRUE};
-DWORD dwThroughputTbl[MAX_RATE] = {10, 20, 55, 110, 60, 90, 120, 180, 240, 360, 480, 540};
-DWORD dwThroughput = 0;
-WORD wIdxUpRate = 0;
-DWORD dwTxDiff = 0;
+unsigned short wIdxDownRate = 0;
+unsigned int ii;
+//unsigned long dwRateTable[MAX_RATE] = {1, 2, 5, 11, 6, 9, 12, 18, 24, 36, 48, 54};
+bool bAutoRate[MAX_RATE] = {true,true,true,true,false,false,true,true,true,true,true,true};
+ unsigned long dwThroughputTbl[MAX_RATE] = {10, 20, 55, 110, 60, 90, 120, 180, 240, 360, 480, 540};
+ unsigned long dwThroughput = 0;
+ unsigned short wIdxUpRate = 0;
+ unsigned long dwTxDiff = 0;
if (pDevice->pMgmt->eScanState != WMAC_NO_SCANNING) {
// Don't do Fallback when scanning Channel
@@ -346,11 +346,11 @@ DWORD dwTxDiff = 0;
for(ii=0;ii<MAX_RATE;ii++) {
if (psNodeDBTable->wSuppRate & (0x0001<<ii)) {
- if (bAutoRate[ii] == TRUE) {
- wIdxUpRate = (WORD) ii;
+ if (bAutoRate[ii] == true) {
+ wIdxUpRate = (unsigned short) ii;
}
} else {
- bAutoRate[ii] = FALSE;
+ bAutoRate[ii] = false;
}
}
@@ -372,9 +372,9 @@ DWORD dwTxDiff = 0;
for(ii = psNodeDBTable->wTxDataRate; ii > 0;) {
ii--;
if ( (dwThroughputTbl[ii] > dwThroughput) &&
- (bAutoRate[ii]==TRUE) ) {
+ (bAutoRate[ii]==true) ) {
dwThroughput = dwThroughputTbl[ii];
- wIdxDownRate = (WORD) ii;
+ wIdxDownRate = (unsigned short) ii;
}
}
psNodeDBTable->wTxDataRate = wIdxDownRate;
@@ -409,14 +409,14 @@ TxRate_iwconfig=psNodeDBTable->wTxDataRate;
* Return Value: None
*
-*/
-BYTE
+unsigned char
RATEuSetIE (
PWLAN_IE_SUPP_RATES pSrcRates,
PWLAN_IE_SUPP_RATES pDstRates,
- UINT uRateLen
+ unsigned int uRateLen
)
{
- UINT ii, uu, uRateCnt = 0;
+ unsigned int ii, uu, uRateCnt = 0;
if ((pSrcRates == NULL) || (pDstRates == NULL))
return 0;
@@ -432,6 +432,6 @@ RATEuSetIE (
}
}
}
- return (BYTE)uRateCnt;
+ return (unsigned char)uRateCnt;
}
diff --git a/drivers/staging/vt6655/datarate.h b/drivers/staging/vt6655/datarate.h
index b8ca792e9c6..4f8ea0b0532 100644
--- a/drivers/staging/vt6655/datarate.h
+++ b/drivers/staging/vt6655/datarate.h
@@ -59,12 +59,12 @@ RATEvParseMaxRate(
void *pDeviceHandler,
PWLAN_IE_SUPP_RATES pItemRates,
PWLAN_IE_SUPP_RATES pItemExtRates,
- BOOL bUpdateBasicRate,
- PWORD pwMaxBasicRate,
- PWORD pwMaxSuppRate,
- PWORD pwSuppRate,
- PBYTE pbyTopCCKRate,
- PBYTE pbyTopOFDMRate
+ bool bUpdateBasicRate,
+ unsigned short *pwMaxBasicRate,
+ unsigned short *pwMaxSuppRate,
+ unsigned short *pwSuppRate,
+ unsigned char *pbyTopCCKRate,
+ unsigned char *pbyTopOFDMRate
);
void
@@ -73,22 +73,22 @@ RATEvTxRateFallBack(
PKnownNodeDB psNodeDBTable
);
-BYTE
+unsigned char
RATEuSetIE(
PWLAN_IE_SUPP_RATES pSrcRates,
PWLAN_IE_SUPP_RATES pDstRates,
- UINT uRateLen
+ unsigned int uRateLen
);
-WORD
+unsigned short
wGetRateIdx(
- BYTE byRate
+ unsigned char byRate
);
-BYTE
+unsigned char
DATARATEbyGetRateIdx(
- BYTE byRate
+ unsigned char byRate
);
diff --git a/drivers/staging/vt6655/desc.h b/drivers/staging/vt6655/desc.h
index cedb1e7df4f..138897a7932 100644
--- a/drivers/staging/vt6655/desc.h
+++ b/drivers/staging/vt6655/desc.h
@@ -244,10 +244,10 @@ static inline PDEVICE_RD_INFO alloc_rd_info(void) {
/*
typedef struct tagRDES0 {
- WORD wResCount;
- WORD wf1Owner ;
-// WORD f15Reserved : 15;
-// WORD f1Owner : 1;
+ unsigned short wResCount;
+ unsigned short wf1Owner ;
+// unsigned short f15Reserved : 15;
+// unsigned short f1Owner : 1;
} __attribute__ ((__packed__))
SRDES0;
*/
@@ -255,13 +255,13 @@ SRDES0;
#ifdef __BIG_ENDIAN
typedef struct tagRDES0 {
- volatile WORD wResCount;
+ volatile unsigned short wResCount;
union {
- volatile U16 f15Reserved;
+ volatile u16 f15Reserved;
struct {
- volatile U8 f8Reserved1;
- volatile U8 f1Owner:1;
- volatile U8 f7Reserved:7;
+ volatile u8 f8Reserved1;
+ volatile u8 f1Owner:1;
+ volatile u8 f7Reserved:7;
} __attribute__ ((__packed__));
} __attribute__ ((__packed__));
} __attribute__ ((__packed__))
@@ -270,9 +270,9 @@ SRDES0, *PSRDES0;
#else
typedef struct tagRDES0 {
- WORD wResCount;
- WORD f15Reserved : 15;
- WORD f1Owner : 1;
+ unsigned short wResCount;
+ unsigned short f15Reserved : 15;
+ unsigned short f1Owner : 1;
} __attribute__ ((__packed__))
SRDES0;
@@ -280,8 +280,8 @@ SRDES0;
#endif
typedef struct tagRDES1 {
- WORD wReqCount;
- WORD wReserved;
+ unsigned short wReqCount;
+ unsigned short wReserved;
} __attribute__ ((__packed__))
SRDES1;
@@ -291,11 +291,11 @@ SRDES1;
typedef struct tagSRxDesc {
volatile SRDES0 m_rd0RD0;
volatile SRDES1 m_rd1RD1;
- volatile U32 buff_addr;
- volatile U32 next_desc;
+ volatile u32 buff_addr;
+ volatile u32 next_desc;
struct tagSRxDesc *next;//4 bytes
volatile PDEVICE_RD_INFO pRDInfo;//4 bytes
- volatile U32 Reserved[2];//8 bytes
+ volatile u32 Reserved[2];//8 bytes
} __attribute__ ((__packed__))
SRxDesc, *PSRxDesc;
typedef const SRxDesc *PCSRxDesc;
@@ -304,24 +304,24 @@ typedef const SRxDesc *PCSRxDesc;
/*
typedef struct tagTDES0 {
- volatile BYTE byTSR0;
- volatile BYTE byTSR1;
- volatile WORD wOwner_Txtime;
-// volatile WORD f15Txtime : 15;
-// volatile WORD f1Owner:1;
+ volatile unsigned char byTSR0;
+ volatile unsigned char byTSR1;
+ volatile unsigned short wOwner_Txtime;
+// volatile unsigned short f15Txtime : 15;
+// volatile unsigned short f1Owner:1;
} __attribute__ ((__packed__))
STDES0;
*/
typedef struct tagTDES0 {
- volatile BYTE byTSR0;
- volatile BYTE byTSR1;
+ volatile unsigned char byTSR0;
+ volatile unsigned char byTSR1;
union {
- volatile U16 f15Txtime;
+ volatile u16 f15Txtime;
struct {
- volatile U8 f8Reserved1;
- volatile U8 f1Owner:1;
- volatile U8 f7Reserved:7;
+ volatile u8 f8Reserved1;
+ volatile u8 f1Owner:1;
+ volatile u8 f7Reserved:7;
} __attribute__ ((__packed__));
} __attribute__ ((__packed__));
} __attribute__ ((__packed__))
@@ -330,10 +330,10 @@ STDES0, PSTDES0;
#else
typedef struct tagTDES0 {
- volatile BYTE byTSR0;
- volatile BYTE byTSR1;
- volatile WORD f15Txtime : 15;
- volatile WORD f1Owner:1;
+ volatile unsigned char byTSR0;
+ volatile unsigned char byTSR1;
+ volatile unsigned short f15Txtime : 15;
+ volatile unsigned short f1Owner:1;
} __attribute__ ((__packed__))
STDES0;
@@ -341,22 +341,22 @@ STDES0;
typedef struct tagTDES1 {
- volatile WORD wReqCount;
- volatile BYTE byTCR;
- volatile BYTE byReserved;
+ volatile unsigned short wReqCount;
+ volatile unsigned char byTCR;
+ volatile unsigned char byReserved;
} __attribute__ ((__packed__))
STDES1;
typedef struct tagDEVICE_TD_INFO{
struct sk_buff* skb;
- PBYTE buf;
+ unsigned char *buf;
dma_addr_t skb_dma;
dma_addr_t buf_dma;
dma_addr_t curr_desc;
- DWORD dwReqCount;
- DWORD dwHeaderLength;
- BYTE byFlags;
+ unsigned long dwReqCount;
+ unsigned long dwHeaderLength;
+ unsigned char byFlags;
} DEVICE_TD_INFO, *PDEVICE_TD_INFO;
/*
@@ -378,11 +378,11 @@ static inline PDEVICE_TD_INFO alloc_td_info(void) {
typedef struct tagSTxDesc {
volatile STDES0 m_td0TD0;
volatile STDES1 m_td1TD1;
- volatile U32 buff_addr;
- volatile U32 next_desc;
+ volatile u32 buff_addr;
+ volatile u32 next_desc;
struct tagSTxDesc* next; //4 bytes
volatile PDEVICE_TD_INFO pTDInfo;//4 bytes
- volatile U32 Reserved[2];//8 bytes
+ volatile u32 Reserved[2];//8 bytes
} __attribute__ ((__packed__))
STxDesc, *PSTxDesc;
typedef const STxDesc *PCSTxDesc;
@@ -391,13 +391,13 @@ typedef const STxDesc *PCSTxDesc;
typedef struct tagSTxSyncDesc {
volatile STDES0 m_td0TD0;
volatile STDES1 m_td1TD1;
- volatile DWORD buff_addr; // pointer to logical buffer
- volatile DWORD next_desc; // pointer to next logical descriptor
- volatile WORD m_wFIFOCtl;
- volatile WORD m_wTimeStamp;
+ volatile u32 buff_addr; // pointer to logical buffer
+ volatile u32 next_desc; // pointer to next logical descriptor
+ volatile unsigned short m_wFIFOCtl;
+ volatile unsigned short m_wTimeStamp;
struct tagSTxSyncDesc* next; //4 bytes
volatile PDEVICE_TD_INFO pTDInfo;//4 bytes
- volatile DWORD m_dwReserved2;
+ volatile u32 m_dwReserved2;
} __attribute__ ((__packed__))
STxSyncDesc, *PSTxSyncDesc;
typedef const STxSyncDesc *PCSTxSyncDesc;
@@ -407,35 +407,35 @@ typedef const STxSyncDesc *PCSTxSyncDesc;
// RsvTime buffer header
//
typedef struct tagSRrvTime_gRTS {
- WORD wRTSTxRrvTime_ba;
- WORD wRTSTxRrvTime_aa;
- WORD wRTSTxRrvTime_bb;
- WORD wReserved;
- WORD wTxRrvTime_b;
- WORD wTxRrvTime_a;
+ unsigned short wRTSTxRrvTime_ba;
+ unsigned short wRTSTxRrvTime_aa;
+ unsigned short wRTSTxRrvTime_bb;
+ unsigned short wReserved;
+ unsigned short wTxRrvTime_b;
+ unsigned short wTxRrvTime_a;
}__attribute__ ((__packed__))
SRrvTime_gRTS, *PSRrvTime_gRTS;
typedef const SRrvTime_gRTS *PCSRrvTime_gRTS;
typedef struct tagSRrvTime_gCTS {
- WORD wCTSTxRrvTime_ba;
- WORD wReserved;
- WORD wTxRrvTime_b;
- WORD wTxRrvTime_a;
+ unsigned short wCTSTxRrvTime_ba;
+ unsigned short wReserved;
+ unsigned short wTxRrvTime_b;
+ unsigned short wTxRrvTime_a;
}__attribute__ ((__packed__))
SRrvTime_gCTS, *PSRrvTime_gCTS;
typedef const SRrvTime_gCTS *PCSRrvTime_gCTS;
typedef struct tagSRrvTime_ab {
- WORD wRTSTxRrvTime;
- WORD wTxRrvTime;
+ unsigned short wRTSTxRrvTime;
+ unsigned short wTxRrvTime;
}__attribute__ ((__packed__))
SRrvTime_ab, *PSRrvTime_ab;
typedef const SRrvTime_ab *PCSRrvTime_ab;
typedef struct tagSRrvTime_atim {
- WORD wCTSTxRrvTime_ba;
- WORD wTxRrvTime_a;
+ unsigned short wCTSTxRrvTime_ba;
+ unsigned short wTxRrvTime_a;
}__attribute__ ((__packed__))
SRrvTime_atim, *PSRrvTime_atim;
typedef const SRrvTime_atim *PCSRrvTime_atim;
@@ -444,25 +444,25 @@ typedef const SRrvTime_atim *PCSRrvTime_atim;
// RTS buffer header
//
typedef struct tagSRTSData {
- WORD wFrameControl;
- WORD wDurationID;
- BYTE abyRA[ETH_ALEN];
- BYTE abyTA[ETH_ALEN];
+ unsigned short wFrameControl;
+ unsigned short wDurationID;
+ unsigned char abyRA[ETH_ALEN];
+ unsigned char abyTA[ETH_ALEN];
}__attribute__ ((__packed__))
SRTSData, *PSRTSData;
typedef const SRTSData *PCSRTSData;
typedef struct tagSRTS_g {
- BYTE bySignalField_b;
- BYTE byServiceField_b;
- WORD wTransmitLength_b;
- BYTE bySignalField_a;
- BYTE byServiceField_a;
- WORD wTransmitLength_a;
- WORD wDuration_ba;
- WORD wDuration_aa;
- WORD wDuration_bb;
- WORD wReserved;
+ unsigned char bySignalField_b;
+ unsigned char byServiceField_b;
+ unsigned short wTransmitLength_b;
+ unsigned char bySignalField_a;
+ unsigned char byServiceField_a;
+ unsigned short wTransmitLength_a;
+ unsigned short wDuration_ba;
+ unsigned short wDuration_aa;
+ unsigned short wDuration_bb;
+ unsigned short wReserved;
SRTSData Data;
}__attribute__ ((__packed__))
SRTS_g, *PSRTS_g;
@@ -470,20 +470,20 @@ typedef const SRTS_g *PCSRTS_g;
typedef struct tagSRTS_g_FB {
- BYTE bySignalField_b;
- BYTE byServiceField_b;
- WORD wTransmitLength_b;
- BYTE bySignalField_a;
- BYTE byServiceField_a;
- WORD wTransmitLength_a;
- WORD wDuration_ba;
- WORD wDuration_aa;
- WORD wDuration_bb;
- WORD wReserved;
- WORD wRTSDuration_ba_f0;
- WORD wRTSDuration_aa_f0;
- WORD wRTSDuration_ba_f1;
- WORD wRTSDuration_aa_f1;
+ unsigned char bySignalField_b;
+ unsigned char byServiceField_b;
+ unsigned short wTransmitLength_b;
+ unsigned char bySignalField_a;
+ unsigned char byServiceField_a;
+ unsigned short wTransmitLength_a;
+ unsigned short wDuration_ba;
+ unsigned short wDuration_aa;
+ unsigned short wDuration_bb;
+ unsigned short wReserved;
+ unsigned short wRTSDuration_ba_f0;
+ unsigned short wRTSDuration_aa_f0;
+ unsigned short wRTSDuration_ba_f1;
+ unsigned short wRTSDuration_aa_f1;
SRTSData Data;
}__attribute__ ((__packed__))
SRTS_g_FB, *PSRTS_g_FB;
@@ -491,11 +491,11 @@ typedef const SRTS_g_FB *PCSRTS_g_FB;
typedef struct tagSRTS_ab {
- BYTE bySignalField;
- BYTE byServiceField;
- WORD wTransmitLength;
- WORD wDuration;
- WORD wReserved;
+ unsigned char bySignalField;
+ unsigned char byServiceField;
+ unsigned short wTransmitLength;
+ unsigned short wDuration;
+ unsigned short wReserved;
SRTSData Data;
}__attribute__ ((__packed__))
SRTS_ab, *PSRTS_ab;
@@ -503,13 +503,13 @@ typedef const SRTS_ab *PCSRTS_ab;
typedef struct tagSRTS_a_FB {
- BYTE bySignalField;
- BYTE byServiceField;
- WORD wTransmitLength;
- WORD wDuration;
- WORD wReserved;
- WORD wRTSDuration_f0;
- WORD wRTSDuration_f1;
+ unsigned char bySignalField;
+ unsigned char byServiceField;
+ unsigned short wTransmitLength;
+ unsigned short wDuration;
+ unsigned short wReserved;
+ unsigned short wRTSDuration_f0;
+ unsigned short wRTSDuration_f1;
SRTSData Data;
}__attribute__ ((__packed__))
SRTS_a_FB, *PSRTS_a_FB;
@@ -520,32 +520,32 @@ typedef const SRTS_a_FB *PCSRTS_a_FB;
// CTS buffer header
//
typedef struct tagSCTSData {
- WORD wFrameControl;
- WORD wDurationID;
- BYTE abyRA[ETH_ALEN];
- WORD wReserved;
+ unsigned short wFrameControl;
+ unsigned short wDurationID;
+ unsigned char abyRA[ETH_ALEN];
+ unsigned short wReserved;
}__attribute__ ((__packed__))
SCTSData, *PSCTSData;
typedef struct tagSCTS {
- BYTE bySignalField_b;
- BYTE byServiceField_b;
- WORD wTransmitLength_b;
- WORD wDuration_ba;
- WORD wReserved;
+ unsigned char bySignalField_b;
+ unsigned char byServiceField_b;
+ unsigned short wTransmitLength_b;
+ unsigned short wDuration_ba;
+ unsigned short wReserved;
SCTSData Data;
}__attribute__ ((__packed__))
SCTS, *PSCTS;
typedef const SCTS *PCSCTS;
typedef struct tagSCTS_FB {
- BYTE bySignalField_b;
- BYTE byServiceField_b;
- WORD wTransmitLength_b;
- WORD wDuration_ba;
- WORD wReserved;
- WORD wCTSDuration_ba_f0;
- WORD wCTSDuration_ba_f1;
+ unsigned char bySignalField_b;
+ unsigned char byServiceField_b;
+ unsigned short wTransmitLength_b;
+ unsigned short wDuration_ba;
+ unsigned short wReserved;
+ unsigned short wCTSDuration_ba_f0;
+ unsigned short wCTSDuration_ba_f1;
SCTSData Data;
}__attribute__ ((__packed__))
SCTS_FB, *PSCTS_FB;
@@ -556,19 +556,19 @@ typedef const SCTS_FB *PCSCTS_FB;
// Tx FIFO header
//
typedef struct tagSTxBufHead {
- DWORD adwTxKey[4];
- WORD wFIFOCtl;
- WORD wTimeStamp;
- WORD wFragCtl;
- BYTE byTxPower;
- BYTE wReserved;
+ u32 adwTxKey[4];
+ unsigned short wFIFOCtl;
+ unsigned short wTimeStamp;
+ unsigned short wFragCtl;
+ unsigned char byTxPower;
+ unsigned char wReserved;
}__attribute__ ((__packed__))
STxBufHead, *PSTxBufHead;
typedef const STxBufHead *PCSTxBufHead;
typedef struct tagSTxShortBufHead {
- WORD wFIFOCtl;
- WORD wTimeStamp;
+ unsigned short wFIFOCtl;
+ unsigned short wTimeStamp;
}__attribute__ ((__packed__))
STxShortBufHead, *PSTxShortBufHead;
typedef const STxShortBufHead *PCSTxShortBufHead;
@@ -577,57 +577,57 @@ typedef const STxShortBufHead *PCSTxShortBufHead;
// Tx data header
//
typedef struct tagSTxDataHead_g {
- BYTE bySignalField_b;
- BYTE byServiceField_b;
- WORD wTransmitLength_b;
- BYTE bySignalField_a;
- BYTE byServiceField_a;
- WORD wTransmitLength_a;
- WORD wDuration_b;
- WORD wDuration_a;
- WORD wTimeStampOff_b;
- WORD wTimeStampOff_a;
+ unsigned char bySignalField_b;
+ unsigned char byServiceField_b;
+ unsigned short wTransmitLength_b;
+ unsigned char bySignalField_a;
+ unsigned char byServiceField_a;
+ unsigned short wTransmitLength_a;
+ unsigned short wDuration_b;
+ unsigned short wDuration_a;
+ unsigned short wTimeStampOff_b;
+ unsigned short wTimeStampOff_a;
}__attribute__ ((__packed__))
STxDataHead_g, *PSTxDataHead_g;
typedef const STxDataHead_g *PCSTxDataHead_g;
typedef struct tagSTxDataHead_g_FB {
- BYTE bySignalField_b;
- BYTE byServiceField_b;
- WORD wTransmitLength_b;
- BYTE bySignalField_a;
- BYTE byServiceField_a;
- WORD wTransmitLength_a;
- WORD wDuration_b;
- WORD wDuration_a;
- WORD wDuration_a_f0;
- WORD wDuration_a_f1;
- WORD wTimeStampOff_b;
- WORD wTimeStampOff_a;
+ unsigned char bySignalField_b;
+ unsigned char byServiceField_b;
+ unsigned short wTransmitLength_b;
+ unsigned char bySignalField_a;
+ unsigned char byServiceField_a;
+ unsigned short wTransmitLength_a;
+ unsigned short wDuration_b;
+ unsigned short wDuration_a;
+ unsigned short wDuration_a_f0;
+ unsigned short wDuration_a_f1;
+ unsigned short wTimeStampOff_b;
+ unsigned short wTimeStampOff_a;
}__attribute__ ((__packed__))
STxDataHead_g_FB, *PSTxDataHead_g_FB;
typedef const STxDataHead_g_FB *PCSTxDataHead_g_FB;
typedef struct tagSTxDataHead_ab {
- BYTE bySignalField;
- BYTE byServiceField;
- WORD wTransmitLength;
- WORD wDuration;
- WORD wTimeStampOff;
+ unsigned char bySignalField;
+ unsigned char byServiceField;
+ unsigned short wTransmitLength;
+ unsigned short wDuration;
+ unsigned short wTimeStampOff;
}__attribute__ ((__packed__))
STxDataHead_ab, *PSTxDataHead_ab;
typedef const STxDataHead_ab *PCSTxDataHead_ab;
typedef struct tagSTxDataHead_a_FB {
- BYTE bySignalField;
- BYTE byServiceField;
- WORD wTransmitLength;
- WORD wDuration;
- WORD wTimeStampOff;
- WORD wDuration_f0;
- WORD wDuration_f1;
+ unsigned char bySignalField;
+ unsigned char byServiceField;
+ unsigned short wTransmitLength;
+ unsigned short wDuration;
+ unsigned short wTimeStampOff;
+ unsigned short wDuration_f0;
+ unsigned short wDuration_f1;
}__attribute__ ((__packed__))
STxDataHead_a_FB, *PSTxDataHead_a_FB;
typedef const STxDataHead_a_FB *PCSTxDataHead_a_FB;
@@ -636,37 +636,37 @@ typedef const STxDataHead_a_FB *PCSTxDataHead_a_FB;
// MICHDR data header
//
typedef struct tagSMICHDRHead {
- DWORD adwHDR0[4];
- DWORD adwHDR1[4];
- DWORD adwHDR2[4];
+ u32 adwHDR0[4];
+ u32 adwHDR1[4];
+ u32 adwHDR2[4];
}__attribute__ ((__packed__))
SMICHDRHead, *PSMICHDRHead;
typedef const SMICHDRHead *PCSMICHDRHead;
typedef struct tagSBEACONCtl {
- DWORD BufReady : 1;
- DWORD TSF : 15;
- DWORD BufLen : 11;
- DWORD Reserved : 5;
+ u32 BufReady : 1;
+ u32 TSF : 15;
+ u32 BufLen : 11;
+ u32 Reserved : 5;
}__attribute__ ((__packed__))
SBEACONCtl;
typedef struct tagSSecretKey {
- DWORD dwLowDword;
- BYTE byHighByte;
+ u32 dwLowDword;
+ unsigned char byHighByte;
}__attribute__ ((__packed__))
SSecretKey;
typedef struct tagSKeyEntry {
- BYTE abyAddrHi[2];
- WORD wKCTL;
- BYTE abyAddrLo[4];
- DWORD dwKey0[4];
- DWORD dwKey1[4];
- DWORD dwKey2[4];
- DWORD dwKey3[4];
- DWORD dwKey4[4];
+ unsigned char abyAddrHi[2];
+ unsigned short wKCTL;
+ unsigned char abyAddrLo[4];
+ u32 dwKey0[4];
+ u32 dwKey1[4];
+ u32 dwKey2[4];
+ u32 dwKey3[4];
+ u32 dwKey4[4];
}__attribute__ ((__packed__))
SKeyEntry;
/*--------------------- Export Macros ------------------------------*/
diff --git a/drivers/staging/vt6655/device.h b/drivers/staging/vt6655/device.h
index 40ee4e14237..2e7c2fd7b7e 100644
--- a/drivers/staging/vt6655/device.h
+++ b/drivers/staging/vt6655/device.h
@@ -48,10 +48,10 @@
#include <linux/wait.h>
#include <linux/if_arp.h>
#include <linux/sched.h>
-#include <asm/io.h>
+#include <linux/io.h>
#include <linux/if.h>
//#include <linux/config.h>
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
#include <linux/proc_fs.h>
#include <linux/inetdevice.h>
#include <linux/reboot.h>
@@ -218,7 +218,7 @@ typedef enum __device_init_type {
#define NDIS_802_11_PMKID_CANDIDATE_PREAUTH_ENABLED 0x01
// PMKID Structures
-typedef UCHAR NDIS_802_11_PMKID_VALUE[16];
+typedef unsigned char NDIS_802_11_PMKID_VALUE[16];
typedef enum _NDIS_802_11_WEP_STATUS
@@ -250,7 +250,7 @@ typedef enum _NDIS_802_11_STATUS_TYPE
//Added new types for PMKID Candidate lists.
typedef struct _PMKID_CANDIDATE {
NDIS_802_11_MAC_ADDRESS BSSID;
- ULONG Flags;
+ unsigned long Flags;
} PMKID_CANDIDATE, *PPMKID_CANDIDATE;
@@ -261,15 +261,15 @@ typedef struct _BSSID_INFO
} BSSID_INFO, *PBSSID_INFO;
typedef struct tagSPMKID {
- ULONG Length;
- ULONG BSSIDInfoCount;
+ unsigned long Length;
+ unsigned long BSSIDInfoCount;
BSSID_INFO BSSIDInfo[MAX_BSSIDINFO_4_PMKID];
} SPMKID, *PSPMKID;
typedef struct tagSPMKIDCandidateEvent {
NDIS_802_11_STATUS_TYPE StatusType;
- ULONG Version; // Version of the structure
- ULONG NumCandidates; // No. of pmkid candidates
+ unsigned long Version; // Version of the structure
+ unsigned long NumCandidates; // No. of pmkid candidates
PMKID_CANDIDATE CandidateList[MAX_PMKIDLIST];
} SPMKIDCandidateEvent, *PSPMKIDCandidateEvent;
@@ -279,10 +279,10 @@ typedef struct tagSPMKIDCandidateEvent {
#define MAX_QUIET_COUNT 8
typedef struct tagSQuietControl {
- BOOL bEnable;
- DWORD dwStartTime;
- BYTE byPeriod;
- WORD wDuration;
+ bool bEnable;
+ unsigned long dwStartTime;
+ unsigned char byPeriod;
+ unsigned short wDuration;
} SQuietControl, *PSQuietControl;
//--
@@ -291,7 +291,7 @@ typedef struct __chip_info_tbl{
char* name;
int io_size;
int nTxQueue;
- U32 flags;
+ u32 flags;
} CHIP_INFO, *PCHIP_INFO;
@@ -303,15 +303,15 @@ typedef enum {
// The receive duplicate detection cache entry
typedef struct tagSCacheEntry{
- WORD wFmSequence;
- BYTE abyAddr2[ETH_ALEN];
+ unsigned short wFmSequence;
+ unsigned char abyAddr2[ETH_ALEN];
} SCacheEntry, *PSCacheEntry;
typedef struct tagSCache{
/* The receive cache is updated circularly. The next entry to be written is
* indexed by the "InPtr".
*/
- UINT uInPtr; // Place to use next
+ unsigned int uInPtr; // Place to use next
SCacheEntry asCacheEntry[DUPLICATE_RX_CACHE_LENGTH];
} SCache, *PSCache;
@@ -319,14 +319,14 @@ typedef struct tagSCache{
// DeFragment Control Block, used for collecting fragments prior to reassembly
typedef struct tagSDeFragControlBlock
{
- WORD wSequence;
- WORD wFragNum;
- BYTE abyAddr2[ETH_ALEN];
- UINT uLifetime;
+ unsigned short wSequence;
+ unsigned short wFragNum;
+ unsigned char abyAddr2[ETH_ALEN];
+ unsigned int uLifetime;
struct sk_buff* skb;
- PBYTE pbyRxBuffer;
- UINT cbFrameLength;
- BOOL bInUse;
+ unsigned char *pbyRxBuffer;
+ unsigned int cbFrameLength;
+ bool bInUse;
} SDeFragControlBlock, *PSDeFragControlBlock;
@@ -386,7 +386,7 @@ typedef struct __device_opt {
int short_retry;
int long_retry;
int bbp_type;
- U32 flags;
+ u32 flags;
} OPTIONS, *POPTIONS;
@@ -417,21 +417,21 @@ typedef struct __device_info {
dma_addr_t tx_bufs_dma1;
dma_addr_t tx_beacon_dma;
- PBYTE tx0_bufs;
- PBYTE tx1_bufs;
- PBYTE tx_beacon_bufs;
+ unsigned char *tx0_bufs;
+ unsigned char *tx1_bufs;
+ unsigned char *tx_beacon_bufs;
CHIP_TYPE chip_id;
- U32 PortOffset;
- DWORD dwIsr;
- U32 memaddr;
- U32 ioaddr;
- U32 io_size;
+ unsigned long PortOffset;
+ unsigned long dwIsr;
+ u32 memaddr;
+ u32 ioaddr;
+ u32 io_size;
- BYTE byRevId;
- WORD SubSystemID;
- WORD SubVendorID;
+ unsigned char byRevId;
+ unsigned short SubSystemID;
+ unsigned short SubVendorID;
int nTxQueues;
volatile int iTDUsed[TYPE_MAXTD];
@@ -448,17 +448,17 @@ typedef struct __device_info {
SCache sDupRxCache;
SDeFragControlBlock sRxDFCB[CB_MAX_RX_FRAG];
- UINT cbDFCB;
- UINT cbFreeDFCB;
- UINT uCurrentDFCBIdx;
+ unsigned int cbDFCB;
+ unsigned int cbFreeDFCB;
+ unsigned int uCurrentDFCBIdx;
OPTIONS sOpts;
- U32 flags;
+ u32 flags;
- U32 rx_buf_sz;
+ u32 rx_buf_sz;
int multicast_limit;
- BYTE byRxMode;
+ unsigned char byRxMode;
spinlock_t lock;
//PLICE_DEBUG->
@@ -472,19 +472,19 @@ typedef struct __device_info {
//PLICE_DEBUG <-
- U32 rx_bytes;
+ u32 rx_bytes;
// Version control
- BYTE byLocalID;
- BYTE byRFType;
+ unsigned char byLocalID;
+ unsigned char byRFType;
- BYTE byMaxPwrLevel;
- BYTE byZoneType;
- BOOL bZoneRegExist;
- BYTE byOriginalZonetype;
- BYTE abyMacContext[MAC_MAX_CONTEXT_REG];
- BOOL bLinkPass; // link status: OK or fail
- BYTE abyCurrentNetAddr[ETH_ALEN];
+ unsigned char byMaxPwrLevel;
+ unsigned char byZoneType;
+ bool bZoneRegExist;
+ unsigned char byOriginalZonetype;
+ unsigned char abyMacContext[MAC_MAX_CONTEXT_REG];
+ bool bLinkPass; // link status: OK or fail
+ unsigned char abyCurrentNetAddr[ETH_ALEN];
// Adapter statistics
SStatCounter scStatistic;
@@ -497,249 +497,249 @@ typedef struct __device_info {
SMgmtObject sMgmtObj;
// 802.11 MAC specific
- UINT uCurrRSSI;
- BYTE byCurrSQ;
-
- DWORD dwTxAntennaSel;
- DWORD dwRxAntennaSel;
- BYTE byAntennaCount;
- BYTE byRxAntennaMode;
- BYTE byTxAntennaMode;
- BOOL bTxRxAntInv;
-
- PBYTE pbyTmpBuff;
- UINT uSIFS; //Current SIFS
- UINT uDIFS; //Current DIFS
- UINT uEIFS; //Current EIFS
- UINT uSlot; //Current SlotTime
- UINT uCwMin; //Current CwMin
- UINT uCwMax; //CwMax is fixed on 1023.
+ unsigned int uCurrRSSI;
+ unsigned char byCurrSQ;
+
+ unsigned long dwTxAntennaSel;
+ unsigned long dwRxAntennaSel;
+ unsigned char byAntennaCount;
+ unsigned char byRxAntennaMode;
+ unsigned char byTxAntennaMode;
+ bool bTxRxAntInv;
+
+ unsigned char *pbyTmpBuff;
+ unsigned int uSIFS; //Current SIFS
+ unsigned int uDIFS; //Current DIFS
+ unsigned int uEIFS; //Current EIFS
+ unsigned int uSlot; //Current SlotTime
+ unsigned int uCwMin; //Current CwMin
+ unsigned int uCwMax; //CwMax is fixed on 1023.
// PHY parameter
- BYTE bySIFS;
- BYTE byDIFS;
- BYTE byEIFS;
- BYTE bySlot;
- BYTE byCWMaxMin;
+ unsigned char bySIFS;
+ unsigned char byDIFS;
+ unsigned char byEIFS;
+ unsigned char bySlot;
+ unsigned char byCWMaxMin;
CARD_PHY_TYPE eCurrentPHYType;
VIA_BB_TYPE byBBType; //0: 11A, 1:11B, 2:11G
VIA_PKT_TYPE byPacketType; //0:11a,1:11b,2:11gb(only CCK in BasicRate),3:11ga(OFDM in Basic Rate)
- WORD wBasicRate;
- BYTE byACKRate;
- BYTE byTopOFDMBasicRate;
- BYTE byTopCCKBasicRate;
-
- BYTE byMinChannel;
- BYTE byMaxChannel;
- UINT uConnectionRate;
-
- BYTE byPreambleType;
- BYTE byShortPreamble;
-
- WORD wCurrentRate;
- WORD wRTSThreshold;
- WORD wFragmentationThreshold;
- BYTE byShortRetryLimit;
- BYTE byLongRetryLimit;
+ unsigned short wBasicRate;
+ unsigned char byACKRate;
+ unsigned char byTopOFDMBasicRate;
+ unsigned char byTopCCKBasicRate;
+
+ unsigned char byMinChannel;
+ unsigned char byMaxChannel;
+ unsigned int uConnectionRate;
+
+ unsigned char byPreambleType;
+ unsigned char byShortPreamble;
+
+ unsigned short wCurrentRate;
+ unsigned short wRTSThreshold;
+ unsigned short wFragmentationThreshold;
+ unsigned char byShortRetryLimit;
+ unsigned char byLongRetryLimit;
CARD_OP_MODE eOPMode;
- BYTE byOpMode;
- BOOL bBSSIDFilter;
- WORD wMaxTransmitMSDULifetime;
- BYTE abyBSSID[ETH_ALEN];
- BYTE abyDesireBSSID[ETH_ALEN];
- WORD wCTSDuration; // update while speed change
- WORD wACKDuration; // update while speed change
- WORD wRTSTransmitLen; // update while speed change
- BYTE byRTSServiceField; // update while speed change
- BYTE byRTSSignalField; // update while speed change
-
- DWORD dwMaxReceiveLifetime; // dot11MaxReceiveLifetime
-
- BOOL bCCK;
- BOOL bEncryptionEnable;
- BOOL bLongHeader;
- BOOL bShortSlotTime;
- BOOL bProtectMode;
- BOOL bNonERPPresent;
- BOOL bBarkerPreambleMd;
-
- BYTE byERPFlag;
- WORD wUseProtectCntDown;
-
- BOOL bRadioControlOff;
- BOOL bRadioOff;
- BOOL bEnablePSMode;
- WORD wListenInterval;
- BOOL bPWBitOn;
+ unsigned char byOpMode;
+ bool bBSSIDFilter;
+ unsigned short wMaxTransmitMSDULifetime;
+ unsigned char abyBSSID[ETH_ALEN];
+ unsigned char abyDesireBSSID[ETH_ALEN];
+ unsigned short wCTSDuration; // update while speed change
+ unsigned short wACKDuration; // update while speed change
+ unsigned short wRTSTransmitLen; // update while speed change
+ unsigned char byRTSServiceField; // update while speed change
+ unsigned char byRTSSignalField; // update while speed change
+
+ unsigned long dwMaxReceiveLifetime; // dot11MaxReceiveLifetime
+
+ bool bCCK;
+ bool bEncryptionEnable;
+ bool bLongHeader;
+ bool bShortSlotTime;
+ bool bProtectMode;
+ bool bNonERPPresent;
+ bool bBarkerPreambleMd;
+
+ unsigned char byERPFlag;
+ unsigned short wUseProtectCntDown;
+
+ bool bRadioControlOff;
+ bool bRadioOff;
+ bool bEnablePSMode;
+ unsigned short wListenInterval;
+ bool bPWBitOn;
WMAC_POWER_MODE ePSMode;
// GPIO Radio Control
- BYTE byRadioCtl;
- BYTE byGPIO;
- BOOL bHWRadioOff;
- BOOL bPrvActive4RadioOFF;
- BOOL bGPIOBlockRead;
+ unsigned char byRadioCtl;
+ unsigned char byGPIO;
+ bool bHWRadioOff;
+ bool bPrvActive4RadioOFF;
+ bool bGPIOBlockRead;
// Beacon releated
- WORD wSeqCounter;
- WORD wBCNBufLen;
- BOOL bBeaconBufReady;
- BOOL bBeaconSent;
- BOOL bIsBeaconBufReadySet;
- UINT cbBeaconBufReadySetCnt;
- BOOL bFixRate;
- BYTE byCurrentCh;
- UINT uScanTime;
+ unsigned short wSeqCounter;
+ unsigned short wBCNBufLen;
+ bool bBeaconBufReady;
+ bool bBeaconSent;
+ bool bIsBeaconBufReadySet;
+ unsigned int cbBeaconBufReadySetCnt;
+ bool bFixRate;
+ unsigned char byCurrentCh;
+ unsigned int uScanTime;
CMD_STATE eCommandState;
CMD_CODE eCommand;
- BOOL bBeaconTx;
+ bool bBeaconTx;
- BOOL bStopBeacon;
- BOOL bStopDataPkt;
- BOOL bStopTx0Pkt;
- UINT uAutoReConnectTime;
+ bool bStopBeacon;
+ bool bStopDataPkt;
+ bool bStopTx0Pkt;
+ unsigned int uAutoReConnectTime;
// 802.11 counter
CMD_ITEM eCmdQueue[CMD_Q_SIZE];
- UINT uCmdDequeueIdx;
- UINT uCmdEnqueueIdx;
- UINT cbFreeCmdQueue;
- BOOL bCmdRunning;
- BOOL bCmdClear;
+ unsigned int uCmdDequeueIdx;
+ unsigned int uCmdEnqueueIdx;
+ unsigned int cbFreeCmdQueue;
+ bool bCmdRunning;
+ bool bCmdClear;
- BOOL bRoaming;
+ bool bRoaming;
//WOW
- BYTE abyIPAddr[4];
+ unsigned char abyIPAddr[4];
- ULONG ulTxPower;
+ unsigned long ulTxPower;
NDIS_802_11_WEP_STATUS eEncryptionStatus;
- BOOL bTransmitKey;
+ bool bTransmitKey;
//2007-0925-01<Add>by MikeLiu
//mike add :save old Encryption
NDIS_802_11_WEP_STATUS eOldEncryptionStatus;
SKeyManagement sKey;
- DWORD dwIVCounter;
+ unsigned long dwIVCounter;
QWORD qwPacketNumber; //For CCMP and TKIP as TSC(6 bytes)
- UINT uCurrentWEPMode;
+ unsigned int uCurrentWEPMode;
RC4Ext SBox;
- BYTE abyPRNG[WLAN_WEPMAX_KEYLEN+3];
- BYTE byKeyIndex;
- UINT uKeyLength;
- BYTE abyKey[WLAN_WEP232_KEYLEN];
+ unsigned char abyPRNG[WLAN_WEPMAX_KEYLEN+3];
+ unsigned char byKeyIndex;
+ unsigned int uKeyLength;
+ unsigned char abyKey[WLAN_WEP232_KEYLEN];
- BOOL bAES;
- BYTE byCntMeasure;
+ bool bAES;
+ unsigned char byCntMeasure;
// for AP mode
- UINT uAssocCount;
- BOOL bMoreData;
+ unsigned int uAssocCount;
+ bool bMoreData;
// QoS
- BOOL bGrpAckPolicy;
+ bool bGrpAckPolicy;
// for OID_802_11_ASSOCIATION_INFORMATION
- BOOL bAssocInfoSet;
+ bool bAssocInfoSet;
- BYTE byAutoFBCtrl;
+ unsigned char byAutoFBCtrl;
- BOOL bTxMICFail;
- BOOL bRxMICFail;
+ bool bTxMICFail;
+ bool bRxMICFail;
- UINT uRATEIdx;
+ unsigned int uRATEIdx;
// For Update BaseBand VGA Gain Offset
- BOOL bUpdateBBVGA;
- UINT uBBVGADiffCount;
- BYTE byBBVGANew;
- BYTE byBBVGACurrent;
- BYTE abyBBVGA[BB_VGA_LEVEL];
- LONG ldBmThreshold[BB_VGA_LEVEL];
+ bool bUpdateBBVGA;
+ unsigned int uBBVGADiffCount;
+ unsigned char byBBVGANew;
+ unsigned char byBBVGACurrent;
+ unsigned char abyBBVGA[BB_VGA_LEVEL];
+ long ldBmThreshold[BB_VGA_LEVEL];
- BYTE byBBPreEDRSSI;
- BYTE byBBPreEDIndex;
+ unsigned char byBBPreEDRSSI;
+ unsigned char byBBPreEDIndex;
- BOOL bRadioCmd;
- DWORD dwDiagRefCount;
+ bool bRadioCmd;
+ unsigned long dwDiagRefCount;
// For FOE Tuning
- BYTE byFOETuning;
+ unsigned char byFOETuning;
// For Auto Power Tunning
- BYTE byAutoPwrTunning;
- SHORT sPSetPointCCK;
- SHORT sPSetPointOFDMG;
- SHORT sPSetPointOFDMA;
- LONG lPFormulaOffset;
- SHORT sPThreshold;
- CHAR cAdjustStep;
- CHAR cMinTxAGC;
+ unsigned char byAutoPwrTunning;
+ short sPSetPointCCK;
+ short sPSetPointOFDMG;
+ short sPSetPointOFDMA;
+ long lPFormulaOffset;
+ short sPThreshold;
+ char cAdjustStep;
+ char cMinTxAGC;
// For RF Power table
- BYTE byCCKPwr;
- BYTE byOFDMPwrG;
- BYTE byCurPwr;
- I8 byCurPwrdBm;
- BYTE abyCCKPwrTbl[CB_MAX_CHANNEL_24G+1];
- BYTE abyOFDMPwrTbl[CB_MAX_CHANNEL+1];
- I8 abyCCKDefaultPwr[CB_MAX_CHANNEL_24G+1];
- I8 abyOFDMDefaultPwr[CB_MAX_CHANNEL+1];
- I8 abyRegPwr[CB_MAX_CHANNEL+1];
- I8 abyLocalPwr[CB_MAX_CHANNEL+1];
+ unsigned char byCCKPwr;
+ unsigned char byOFDMPwrG;
+ unsigned char byCurPwr;
+ char byCurPwrdBm;
+ unsigned char abyCCKPwrTbl[CB_MAX_CHANNEL_24G+1];
+ unsigned char abyOFDMPwrTbl[CB_MAX_CHANNEL+1];
+ char abyCCKDefaultPwr[CB_MAX_CHANNEL_24G+1];
+ char abyOFDMDefaultPwr[CB_MAX_CHANNEL+1];
+ char abyRegPwr[CB_MAX_CHANNEL+1];
+ char abyLocalPwr[CB_MAX_CHANNEL+1];
// BaseBand Loopback Use
- BYTE byBBCR4d;
- BYTE byBBCRc9;
- BYTE byBBCR88;
- BYTE byBBCR09;
+ unsigned char byBBCR4d;
+ unsigned char byBBCRc9;
+ unsigned char byBBCR88;
+ unsigned char byBBCR09;
// command timer
struct timer_list sTimerCommand;
#ifdef TxInSleep
struct timer_list sTimerTxData;
- ULONG nTxDataTimeCout;
- BOOL fTxDataInSleep;
- BOOL IsTxDataTrigger;
+ unsigned long nTxDataTimeCout;
+ bool fTxDataInSleep;
+ bool IsTxDataTrigger;
#endif
#ifdef WPA_SM_Transtatus
- BOOL fWPA_Authened; //is WPA/WPA-PSK or WPA2/WPA2-PSK authen??
+ bool fWPA_Authened; //is WPA/WPA-PSK or WPA2/WPA2-PSK authen??
#endif
- BYTE byReAssocCount; //mike add:re-association retry times!
- BYTE byLinkWaitCount;
+ unsigned char byReAssocCount; //mike add:re-association retry times!
+ unsigned char byLinkWaitCount;
- BYTE abyNodeName[17];
+ unsigned char abyNodeName[17];
- BOOL bDiversityRegCtlON;
- BOOL bDiversityEnable;
- ULONG ulDiversityNValue;
- ULONG ulDiversityMValue;
- BYTE byTMax;
- BYTE byTMax2;
- BYTE byTMax3;
- ULONG ulSQ3TH;
+ bool bDiversityRegCtlON;
+ bool bDiversityEnable;
+ unsigned long ulDiversityNValue;
+ unsigned long ulDiversityMValue;
+ unsigned char byTMax;
+ unsigned char byTMax2;
+ unsigned char byTMax3;
+ unsigned long ulSQ3TH;
// ANT diversity
- ULONG uDiversityCnt;
- BYTE byAntennaState;
- ULONG ulRatio_State0;
- ULONG ulRatio_State1;
+ unsigned long uDiversityCnt;
+ unsigned char byAntennaState;
+ unsigned long ulRatio_State0;
+ unsigned long ulRatio_State1;
//SQ3 functions for antenna diversity
struct timer_list TimerSQ3Tmax1;
@@ -747,80 +747,80 @@ typedef struct __device_info {
struct timer_list TimerSQ3Tmax3;
- ULONG uNumSQ3[MAX_RATE];
- WORD wAntDiversityMaxRate;
+ unsigned long uNumSQ3[MAX_RATE];
+ unsigned short wAntDiversityMaxRate;
SEthernetHeader sTxEthHeader;
SEthernetHeader sRxEthHeader;
- BYTE abyBroadcastAddr[ETH_ALEN];
- BYTE abySNAP_RFC1042[ETH_ALEN];
- BYTE abySNAP_Bridgetunnel[ETH_ALEN];
- BYTE abyEEPROM[EEP_MAX_CONTEXT_SIZE]; //DWORD alignment
+ unsigned char abyBroadcastAddr[ETH_ALEN];
+ unsigned char abySNAP_RFC1042[ETH_ALEN];
+ unsigned char abySNAP_Bridgetunnel[ETH_ALEN];
+ unsigned char abyEEPROM[EEP_MAX_CONTEXT_SIZE]; //unsigned long alignment
// Pre-Authentication & PMK cache
SPMKID gsPMKID;
SPMKIDCandidateEvent gsPMKIDCandidate;
// for 802.11h
- BOOL b11hEnable;
- BYTE abyCountryCode[3];
+ bool b11hEnable;
+ unsigned char abyCountryCode[3];
// for 802.11h DFS
- UINT uNumOfMeasureEIDs;
+ unsigned int uNumOfMeasureEIDs;
PWLAN_IE_MEASURE_REQ pCurrMeasureEID;
- BOOL bMeasureInProgress;
- BYTE byOrgChannel;
- BYTE byOrgRCR;
- DWORD dwOrgMAR0;
- DWORD dwOrgMAR4;
- BYTE byBasicMap;
- BYTE byCCAFraction;
- BYTE abyRPIs[8];
- DWORD dwRPIs[8];
- BOOL bChannelSwitch;
- BYTE byNewChannel;
- BYTE byChannelSwitchCount;
- BOOL bQuietEnable;
- BOOL bEnableFirstQuiet;
- BYTE byQuietStartCount;
- UINT uQuietEnqueue;
- DWORD dwCurrentQuietEndTime;
+ bool bMeasureInProgress;
+ unsigned char byOrgChannel;
+ unsigned char byOrgRCR;
+ unsigned long dwOrgMAR0;
+ unsigned long dwOrgMAR4;
+ unsigned char byBasicMap;
+ unsigned char byCCAFraction;
+ unsigned char abyRPIs[8];
+ unsigned long dwRPIs[8];
+ bool bChannelSwitch;
+ unsigned char byNewChannel;
+ unsigned char byChannelSwitchCount;
+ bool bQuietEnable;
+ bool bEnableFirstQuiet;
+ unsigned char byQuietStartCount;
+ unsigned int uQuietEnqueue;
+ unsigned long dwCurrentQuietEndTime;
SQuietControl sQuiet[MAX_QUIET_COUNT];
// for 802.11h TPC
- BOOL bCountryInfo5G;
- BOOL bCountryInfo24G;
+ bool bCountryInfo5G;
+ bool bCountryInfo24G;
- WORD wBeaconInterval;
+ unsigned short wBeaconInterval;
//WPA supplicant deamon
struct net_device *wpadev;
- BOOL bWPADEVUp;
+ bool bWPADEVUp;
struct sk_buff *skb;
#ifdef WPA_SUPPLICANT_DRIVER_WEXT_SUPPORT
/*
- BOOL bwextstep0;
- BOOL bwextstep1;
- BOOL bwextstep2;
- BOOL bwextstep3;
+ bool bwextstep0;
+ bool bwextstep1;
+ bool bwextstep2;
+ bool bwextstep3;
*/
- UINT bwextcount;
- BOOL bWPASuppWextEnabled;
+ unsigned int bwextcount;
+ bool bWPASuppWextEnabled;
#endif
//--
#ifdef HOSTAP
// user space daemon: hostapd, is used for HOSTAP
- BOOL bEnableHostapd;
- BOOL bEnable8021x;
- BOOL bEnableHostWEP;
+ bool bEnableHostapd;
+ bool bEnable8021x;
+ bool bEnableHostWEP;
struct net_device *apdev;
int (*tx_80211)(struct sk_buff *skb, struct net_device *dev);
#endif
- UINT uChannel;
- BOOL bMACSuspend;
+ unsigned int uChannel;
+ bool bMACSuspend;
struct iw_statistics wstats; // wireless stats
- BOOL bCommit;
+ bool bCommit;
} DEVICE_INFO, *PSDevice;
@@ -880,7 +880,7 @@ void InitRxManagementQueue(PSDevice pDevice);
-inline static BOOL device_get_ip(PSDevice pInfo) {
+inline static bool device_get_ip(PSDevice pInfo) {
struct in_device* in_dev=(struct in_device*) pInfo->dev->ip_ptr;
struct in_ifaddr* ifa;
@@ -888,10 +888,10 @@ inline static BOOL device_get_ip(PSDevice pInfo) {
ifa=(struct in_ifaddr*) in_dev->ifa_list;
if (ifa!=NULL) {
memcpy(pInfo->abyIPAddr,&ifa->ifa_address,4);
- return TRUE;
+ return true;
}
}
- return FALSE;
+ return false;
}
@@ -920,9 +920,9 @@ static inline PDEVICE_TD_INFO alloc_td_info(void) {
/*--------------------- Export Functions --------------------------*/
-BOOL device_dma0_xmit(PSDevice pDevice, struct sk_buff *skb, UINT uNodeIndex);
-BOOL device_alloc_frag_buf(PSDevice pDevice, PSDeFragControlBlock pDeF);
-int Config_FileOperation(PSDevice pDevice,BOOL fwrite,unsigned char *Parameter);
+bool device_dma0_xmit(PSDevice pDevice, struct sk_buff *skb, unsigned int uNodeIndex);
+bool device_alloc_frag_buf(PSDevice pDevice, PSDeFragControlBlock pDeF);
+int Config_FileOperation(PSDevice pDevice, bool fwrite, unsigned char *Parameter);
#endif
diff --git a/drivers/staging/vt6655/device_cfg.h b/drivers/staging/vt6655/device_cfg.h
index d1e9c1930bd..408edc27075 100644
--- a/drivers/staging/vt6655/device_cfg.h
+++ b/drivers/staging/vt6655/device_cfg.h
@@ -39,14 +39,6 @@ struct _version {
unsigned char build;
} version_t, *pversion_t;
-#ifndef FALSE
-#define FALSE (0)
-#endif
-
-#ifndef TRUE
-#define TRUE (!(FALSE))
-#endif
-
#define VID_TABLE_SIZE 64
#define MCAST_TABLE_SIZE 64
#define MCAM_SIZE 32
diff --git a/drivers/staging/vt6655/device_main.c b/drivers/staging/vt6655/device_main.c
index e49bb258b5c..4d6b66a4fd9 100644
--- a/drivers/staging/vt6655/device_main.c
+++ b/drivers/staging/vt6655/device_main.c
@@ -26,9 +26,9 @@
*
* Functions:
*
- * device_found1 - module initial (insmod) driver entry
- * device_remove1 - module remove entry
- * device_init_info - device structure resource allocation function
+ * vt6655_probe - module initial (insmod) driver entry
+ * vt6655_remove - module remove entry
+ * vt6655_init_info - device structure resource allocation function
* device_free_info - device structure resource free function
* device_get_pci_info - get allocated pci io/mem resource
* device_print_info - print out resource
@@ -62,6 +62,7 @@
#include "device.h"
#include "card.h"
+#include "channel.h"
#include "baseband.h"
#include "mac.h"
#include "tether.h"
@@ -133,10 +134,10 @@ DEVICE_PARAM(TxDescriptors1,"Number of transmit descriptors1");
#define IP_ALIG_DEF 0
-/* IP_byte_align[] is used for IP header DWORD byte aligned
- 0: indicate the IP header won't be DWORD byte aligned.(Default) .
- 1: indicate the IP header will be DWORD byte aligned.
- In some enviroment, the IP header should be DWORD byte aligned,
+/* IP_byte_align[] is used for IP header unsigned long byte aligned
+ 0: indicate the IP header won't be unsigned long byte aligned.(Default) .
+ 1: indicate the IP header will be unsigned long byte aligned.
+ In some enviroment, the IP header should be unsigned long byte aligned,
or the packet will be droped when we receive it. (eg: IPVS)
*/
DEVICE_PARAM(IP_byte_align,"Enable IP header dword aligned");
@@ -284,7 +285,7 @@ static CHIP_INFO chip_info_table[]= {
{0,NULL}
};
-DEFINE_PCI_DEVICE_TABLE(device_id_table) = {
+DEFINE_PCI_DEVICE_TABLE(vt6655_pci_id_table) = {
{ PCI_VDEVICE(VIA, 0x3253), (kernel_ulong_t)chip_info_table},
{ 0, }
};
@@ -292,10 +293,10 @@ DEFINE_PCI_DEVICE_TABLE(device_id_table) = {
/*--------------------- Static Functions --------------------------*/
-static int device_found1(struct pci_dev *pcid, const struct pci_device_id *ent);
-static BOOL device_init_info(struct pci_dev* pcid, PSDevice* ppDevice, PCHIP_INFO);
+static int vt6655_probe(struct pci_dev *pcid, const struct pci_device_id *ent);
+static bool vt6655_init_info(struct pci_dev* pcid, PSDevice* ppDevice, PCHIP_INFO);
static void device_free_info(PSDevice pDevice);
-static BOOL device_get_pci_info(PSDevice, struct pci_dev* pcid);
+static bool device_get_pci_info(PSDevice, struct pci_dev* pcid);
static void device_print_info(PSDevice pDevice);
static struct net_device_stats *device_get_stats(struct net_device *dev);
static void device_init_diversity_timer(PSDevice pDevice);
@@ -326,12 +327,12 @@ static void device_init_td1_ring(PSDevice pDevice);
static int device_dma0_tx_80211(struct sk_buff *skb, struct net_device *dev);
//2008-0714<Add>by Mike Liu
-static BOOL device_release_WPADEV(PSDevice pDevice);
+static bool device_release_WPADEV(PSDevice pDevice);
static int ethtool_ioctl(struct net_device *dev, void *useraddr);
-static int device_rx_srv(PSDevice pDevice, UINT uIdx);
-static int device_tx_srv(PSDevice pDevice, UINT uIdx);
-static BOOL device_alloc_rx_buf(PSDevice pDevice, PSRxDesc pDesc);
+static int device_rx_srv(PSDevice pDevice, unsigned int uIdx);
+static int device_tx_srv(PSDevice pDevice, unsigned int uIdx);
+static bool device_alloc_rx_buf(PSDevice pDevice, PSRxDesc pDesc);
static void device_init_registers(PSDevice pDevice, DEVICE_INIT_TYPE InitType);
static void device_free_tx_buf(PSDevice pDevice, PSTxDesc pDesc);
static void device_free_td0_ring(PSDevice pDevice);
@@ -340,7 +341,8 @@ static void device_free_rd0_ring(PSDevice pDevice);
static void device_free_rd1_ring(PSDevice pDevice);
static void device_free_rings(PSDevice pDevice);
static void device_free_frag_buf(PSDevice pDevice);
-static int Config_FileGetParameter(UCHAR *string, UCHAR *dest,UCHAR *source);
+static int Config_FileGetParameter(unsigned char *string,
+ unsigned char *dest, unsigned char *source);
/*--------------------- Export Variables --------------------------*/
@@ -357,7 +359,7 @@ static char* get_chip_name(int chip_id) {
return chip_info_table[i].name;
}
-static void device_remove1(struct pci_dev *pcid)
+static void __devexit vt6655_remove(struct pci_dev *pcid)
{
PSDevice pDevice=pci_get_drvdata(pcid);
@@ -384,7 +386,7 @@ device_set_int_opt(int *opt, int val, int min, int max, int def,char* name,char*
}
static void
-device_set_bool_opt(unsigned int *opt, int val,BOOL def,U32 flag, char* name,char* devname) {
+device_set_bool_opt(unsigned int *opt, int val,bool def,u32 flag, char* name,char* devname) {
(*opt)&=(~flag);
if (val==-1)
*opt|=(def ? flag : 0);
@@ -394,7 +396,7 @@ device_set_bool_opt(unsigned int *opt, int val,BOOL def,U32 flag, char* name,cha
*opt|=(def ? flag : 0);
} else {
DBG_PRT(MSG_LEVEL_INFO, KERN_NOTICE "%s: set parameter %s to %s\n",
- devname,name , val ? "TRUE" : "FALSE");
+ devname,name , val ? "true" : "false");
*opt|=(val ? flag : 0);
}
}
@@ -429,9 +431,9 @@ pOpts->flags|=DEVICE_FLAGS_DiversityANT;
static void
device_set_options(PSDevice pDevice) {
- BYTE abyBroadcastAddr[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
- BYTE abySNAP_RFC1042[ETH_ALEN] = {0xAA, 0xAA, 0x03, 0x00, 0x00, 0x00};
- BYTE abySNAP_Bridgetunnel[ETH_ALEN] = {0xAA, 0xAA, 0x03, 0x00, 0x00, 0xF8};
+ unsigned char abyBroadcastAddr[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+ unsigned char abySNAP_RFC1042[ETH_ALEN] = {0xAA, 0xAA, 0x03, 0x00, 0x00, 0x00};
+ unsigned char abySNAP_Bridgetunnel[ETH_ALEN] = {0xAA, 0xAA, 0x03, 0x00, 0x00, 0xF8};
memcpy(pDevice->abyBroadcastAddr, abyBroadcastAddr, ETH_ALEN);
@@ -450,7 +452,7 @@ device_set_options(PSDevice pDevice) {
pDevice->b11hEnable = (pDevice->sOpts.flags & DEVICE_FLAGS_80211h_MODE) ? 1 : 0;
pDevice->bDiversityRegCtlON = (pDevice->sOpts.flags & DEVICE_FLAGS_DiversityANT) ? 1 : 0;
pDevice->uConnectionRate = pDevice->sOpts.data_rate;
- if (pDevice->uConnectionRate < RATE_AUTO) pDevice->bFixRate = TRUE;
+ if (pDevice->uConnectionRate < RATE_AUTO) pDevice->bFixRate = true;
pDevice->byBBType = pDevice->sOpts.bbp_type;
pDevice->byPacketType = pDevice->byBBType;
@@ -458,45 +460,45 @@ device_set_options(PSDevice pDevice) {
pDevice->byAutoFBCtrl = AUTO_FB_0;
//pDevice->byAutoFBCtrl = AUTO_FB_1;
//PLICE_DEBUG<-
-pDevice->bUpdateBBVGA = TRUE;
+pDevice->bUpdateBBVGA = true;
pDevice->byFOETuning = 0;
pDevice->wCTSDuration = 0;
pDevice->byPreambleType = 0;
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO" uChannel= %d\n",(INT)pDevice->uChannel);
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO" byOpMode= %d\n",(INT)pDevice->byOpMode);
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO" ePSMode= %d\n",(INT)pDevice->ePSMode);
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO" wRTSThreshold= %d\n",(INT)pDevice->wRTSThreshold);
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO" byShortRetryLimit= %d\n",(INT)pDevice->byShortRetryLimit);
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO" byLongRetryLimit= %d\n",(INT)pDevice->byLongRetryLimit);
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO" byPreambleType= %d\n",(INT)pDevice->byPreambleType);
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO" byShortPreamble= %d\n",(INT)pDevice->byShortPreamble);
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO" uConnectionRate= %d\n",(INT)pDevice->uConnectionRate);
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO" byBBType= %d\n",(INT)pDevice->byBBType);
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO" pDevice->b11hEnable= %d\n",(INT)pDevice->b11hEnable);
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO" pDevice->bDiversityRegCtlON= %d\n",(INT)pDevice->bDiversityRegCtlON);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO" uChannel= %d\n",(int)pDevice->uChannel);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO" byOpMode= %d\n",(int)pDevice->byOpMode);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO" ePSMode= %d\n",(int)pDevice->ePSMode);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO" wRTSThreshold= %d\n",(int)pDevice->wRTSThreshold);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO" byShortRetryLimit= %d\n",(int)pDevice->byShortRetryLimit);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO" byLongRetryLimit= %d\n",(int)pDevice->byLongRetryLimit);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO" byPreambleType= %d\n",(int)pDevice->byPreambleType);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO" byShortPreamble= %d\n",(int)pDevice->byShortPreamble);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO" uConnectionRate= %d\n",(int)pDevice->uConnectionRate);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO" byBBType= %d\n",(int)pDevice->byBBType);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO" pDevice->b11hEnable= %d\n",(int)pDevice->b11hEnable);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO" pDevice->bDiversityRegCtlON= %d\n",(int)pDevice->bDiversityRegCtlON);
}
-static void s_vCompleteCurrentMeasure (PSDevice pDevice, BYTE byResult)
+static void s_vCompleteCurrentMeasure (PSDevice pDevice, unsigned char byResult)
{
- UINT ii;
- DWORD dwDuration = 0;
- BYTE byRPI0 = 0;
+ unsigned int ii;
+ unsigned long dwDuration = 0;
+ unsigned char byRPI0 = 0;
for(ii=1;ii<8;ii++) {
pDevice->dwRPIs[ii] *= 255;
- dwDuration |= *((PWORD) (pDevice->pCurrMeasureEID->sReq.abyDuration));
+ dwDuration |= *((unsigned short *) (pDevice->pCurrMeasureEID->sReq.abyDuration));
dwDuration <<= 10;
pDevice->dwRPIs[ii] /= dwDuration;
- pDevice->abyRPIs[ii] = (BYTE) pDevice->dwRPIs[ii];
+ pDevice->abyRPIs[ii] = (unsigned char) pDevice->dwRPIs[ii];
byRPI0 += pDevice->abyRPIs[ii];
}
pDevice->abyRPIs[0] = (0xFF - byRPI0);
if (pDevice->uNumOfMeasureEIDs == 0) {
VNTWIFIbMeasureReport( pDevice->pMgmt,
- TRUE,
+ true,
pDevice->pCurrMeasureEID,
byResult,
pDevice->byBasicMap,
@@ -505,7 +507,7 @@ static void s_vCompleteCurrentMeasure (PSDevice pDevice, BYTE byResult)
);
} else {
VNTWIFIbMeasureReport( pDevice->pMgmt,
- FALSE,
+ false,
pDevice->pCurrMeasureEID,
byResult,
pDevice->byBasicMap,
@@ -525,12 +527,12 @@ static void s_vCompleteCurrentMeasure (PSDevice pDevice, BYTE byResult)
static void device_init_registers(PSDevice pDevice, DEVICE_INIT_TYPE InitType)
{
- UINT ii;
- BYTE byValue;
- BYTE byValue1;
- BYTE byCCKPwrdBm = 0;
- BYTE byOFDMPwrdBm = 0;
- INT zonetype=0;
+ unsigned int ii;
+ unsigned char byValue;
+ unsigned char byValue1;
+ unsigned char byCCKPwrdBm = 0;
+ unsigned char byOFDMPwrdBm = 0;
+ int zonetype=0;
PSMgmtObject pMgmt = &(pDevice->sMgmtObj);
MACbShutdown(pDevice->PortOffset);
BBvSoftwareReset(pDevice->PortOffset);
@@ -540,11 +542,11 @@ static void device_init_registers(PSDevice pDevice, DEVICE_INIT_TYPE InitType)
// Do MACbSoftwareReset in MACvInitialize
MACbSoftwareReset(pDevice->PortOffset);
// force CCK
- pDevice->bCCK = TRUE;
- pDevice->bAES = FALSE;
- pDevice->bProtectMode = FALSE; //Only used in 11g type, sync with ERP IE
- pDevice->bNonERPPresent = FALSE;
- pDevice->bBarkerPreambleMd = FALSE;
+ pDevice->bCCK = true;
+ pDevice->bAES = false;
+ pDevice->bProtectMode = false; //Only used in 11g type, sync with ERP IE
+ pDevice->bNonERPPresent = false;
+ pDevice->bBarkerPreambleMd = false;
pDevice->wCurrentRate = RATE_1M;
pDevice->byTopOFDMBasicRate = RATE_24M;
pDevice->byTopCCKBasicRate = RATE_1M;
@@ -570,9 +572,9 @@ static void device_init_registers(PSDevice pDevice, DEVICE_INIT_TYPE InitType)
// Get Antena
byValue = SROMbyReadEmbedded(pDevice->PortOffset, EEP_OFS_ANTENNA);
if (byValue & EEP_ANTINV)
- pDevice->bTxRxAntInv = TRUE;
+ pDevice->bTxRxAntInv = true;
else
- pDevice->bTxRxAntInv = FALSE;
+ pDevice->bTxRxAntInv = false;
#ifdef PLICE_DEBUG
//printk("init_register:TxRxAntInv is %d,byValue is %d\n",pDevice->bTxRxAntInv,byValue);
#endif
@@ -587,7 +589,7 @@ static void device_init_registers(PSDevice pDevice, DEVICE_INIT_TYPE InitType)
pDevice->ulDiversityMValue = 100*16;//SROMbyReadEmbedded(pDevice->PortOffset, 0x52);
pDevice->byTMax = 1;//SROMbyReadEmbedded(pDevice->PortOffset, 0x53);
pDevice->byTMax2 = 4;//SROMbyReadEmbedded(pDevice->PortOffset, 0x54);
- pDevice->ulSQ3TH = 0;//(ULONG) SROMbyReadEmbedded(pDevice->PortOffset, 0x55);
+ pDevice->ulSQ3TH = 0;//(unsigned long) SROMbyReadEmbedded(pDevice->PortOffset, 0x55);
pDevice->byTMax3 = 64;//SROMbyReadEmbedded(pDevice->PortOffset, 0x56);
if (byValue == (EEP_ANTENNA_AUX | EEP_ANTENNA_MAIN)) {
@@ -595,7 +597,7 @@ static void device_init_registers(PSDevice pDevice, DEVICE_INIT_TYPE InitType)
pDevice->byTxAntennaMode = ANT_B;
pDevice->dwTxAntennaSel = 1;
pDevice->dwRxAntennaSel = 1;
- if (pDevice->bTxRxAntInv == TRUE)
+ if (pDevice->bTxRxAntInv == true)
pDevice->byRxAntennaMode = ANT_A;
else
pDevice->byRxAntennaMode = ANT_B;
@@ -603,26 +605,26 @@ static void device_init_registers(PSDevice pDevice, DEVICE_INIT_TYPE InitType)
byValue1 = SROMbyReadEmbedded(pDevice->PortOffset, EEP_OFS_ANTENNA);
// if (pDevice->bDiversityRegCtlON)
if((byValue1&0x08)==0)
- pDevice->bDiversityEnable = FALSE;//SROMbyReadEmbedded(pDevice->PortOffset, 0x50);
+ pDevice->bDiversityEnable = false;//SROMbyReadEmbedded(pDevice->PortOffset, 0x50);
else
- pDevice->bDiversityEnable = TRUE;
+ pDevice->bDiversityEnable = true;
#ifdef PLICE_DEBUG
//printk("aux |main antenna: RxAntennaMode is %d\n",pDevice->byRxAntennaMode);
#endif
} else {
- pDevice->bDiversityEnable = FALSE;
+ pDevice->bDiversityEnable = false;
pDevice->byAntennaCount = 1;
pDevice->dwTxAntennaSel = 0;
pDevice->dwRxAntennaSel = 0;
if (byValue & EEP_ANTENNA_AUX) {
pDevice->byTxAntennaMode = ANT_A;
- if (pDevice->bTxRxAntInv == TRUE)
+ if (pDevice->bTxRxAntInv == true)
pDevice->byRxAntennaMode = ANT_B;
else
pDevice->byRxAntennaMode = ANT_A;
} else {
pDevice->byTxAntennaMode = ANT_B;
- if (pDevice->bTxRxAntInv == TRUE)
+ if (pDevice->bTxRxAntInv == true)
pDevice->byRxAntennaMode = ANT_A;
else
pDevice->byRxAntennaMode = ANT_B;
@@ -638,7 +640,7 @@ byValue1 = SROMbyReadEmbedded(pDevice->PortOffset, EEP_OFS_ANTENNA);
//2008-8-4 <add> by chester
//zonetype initial
pDevice->byOriginalZonetype = pDevice->abyEEPROM[EEP_OFS_ZONETYPE];
- zonetype = Config_FileOperation(pDevice,FALSE,NULL);
+ zonetype = Config_FileOperation(pDevice,false,NULL);
if (zonetype >= 0) { //read zonetype file ok!
if ((zonetype == 0)&&
(pDevice->abyEEPROM[EEP_OFS_ZONETYPE] !=0x00)){ //for USA
@@ -680,7 +682,7 @@ else
pDevice->byRFType &= RF_MASK;
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "pDevice->byRFType = %x\n", pDevice->byRFType);
- if (pDevice->bZoneRegExist == FALSE) {
+ if (pDevice->bZoneRegExist == false) {
pDevice->byZoneType = pDevice->abyEEPROM[EEP_OFS_ZONETYPE];
}
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "pDevice->byZoneType = %x\n", pDevice->byZoneType);
@@ -700,11 +702,11 @@ else
for (ii=0;ii<CB_MAX_CHANNEL_24G;ii++) {
- pDevice->abyCCKPwrTbl[ii+1] = SROMbyReadEmbedded(pDevice->PortOffset, (BYTE)(ii + EEP_OFS_CCK_PWR_TBL));
+ pDevice->abyCCKPwrTbl[ii+1] = SROMbyReadEmbedded(pDevice->PortOffset, (unsigned char)(ii + EEP_OFS_CCK_PWR_TBL));
if (pDevice->abyCCKPwrTbl[ii+1] == 0) {
pDevice->abyCCKPwrTbl[ii+1] = pDevice->byCCKPwr;
}
- pDevice->abyOFDMPwrTbl[ii+1] = SROMbyReadEmbedded(pDevice->PortOffset, (BYTE)(ii + EEP_OFS_OFDM_PWR_TBL));
+ pDevice->abyOFDMPwrTbl[ii+1] = SROMbyReadEmbedded(pDevice->PortOffset, (unsigned char)(ii + EEP_OFS_OFDM_PWR_TBL));
if (pDevice->abyOFDMPwrTbl[ii+1] == 0) {
pDevice->abyOFDMPwrTbl[ii+1] = pDevice->byOFDMPwrG;
}
@@ -726,10 +728,10 @@ else
// Load OFDM A Power Table
for (ii=0;ii<CB_MAX_CHANNEL_5G;ii++) { //RobertYu:20041224, bug using CB_MAX_CHANNEL
- pDevice->abyOFDMPwrTbl[ii+CB_MAX_CHANNEL_24G+1] = SROMbyReadEmbedded(pDevice->PortOffset, (BYTE)(ii + EEP_OFS_OFDMA_PWR_TBL));
- pDevice->abyOFDMDefaultPwr[ii+CB_MAX_CHANNEL_24G+1] = SROMbyReadEmbedded(pDevice->PortOffset, (BYTE)(ii + EEP_OFS_OFDMA_PWR_dBm));
+ pDevice->abyOFDMPwrTbl[ii+CB_MAX_CHANNEL_24G+1] = SROMbyReadEmbedded(pDevice->PortOffset, (unsigned char)(ii + EEP_OFS_OFDMA_PWR_TBL));
+ pDevice->abyOFDMDefaultPwr[ii+CB_MAX_CHANNEL_24G+1] = SROMbyReadEmbedded(pDevice->PortOffset, (unsigned char)(ii + EEP_OFS_OFDMA_PWR_dBm));
}
- CARDvInitChannelTable((void *)pDevice);
+ init_channel_table((void *)pDevice);
if (pDevice->byLocalID > REV_ID_VT3253_B1) {
@@ -773,38 +775,38 @@ else
if (pDevice->uConnectionRate == RATE_AUTO) {
pDevice->wCurrentRate = RATE_54M;
} else {
- pDevice->wCurrentRate = (WORD)pDevice->uConnectionRate;
+ pDevice->wCurrentRate = (unsigned short)pDevice->uConnectionRate;
}
// default G Mode
VNTWIFIbConfigPhyMode(pDevice->pMgmt, PHY_TYPE_11G);
VNTWIFIbConfigPhyMode(pDevice->pMgmt, PHY_TYPE_AUTO);
- pDevice->bRadioOff = FALSE;
+ pDevice->bRadioOff = false;
pDevice->byRadioCtl = SROMbyReadEmbedded(pDevice->PortOffset, EEP_OFS_RADIOCTL);
- pDevice->bHWRadioOff = FALSE;
+ pDevice->bHWRadioOff = false;
if (pDevice->byRadioCtl & EEP_RADIOCTL_ENABLE) {
// Get GPIO
MACvGPIOIn(pDevice->PortOffset, &pDevice->byGPIO);
//2008-4-14 <add> by chester for led issue
#ifdef FOR_LED_ON_NOTEBOOK
-if (pDevice->byGPIO & GPIO0_DATA){pDevice->bHWRadioOff = TRUE;}
-if ( !(pDevice->byGPIO & GPIO0_DATA)){pDevice->bHWRadioOff = FALSE;}
+if (pDevice->byGPIO & GPIO0_DATA){pDevice->bHWRadioOff = true;}
+if ( !(pDevice->byGPIO & GPIO0_DATA)){pDevice->bHWRadioOff = false;}
}
- if ( (pDevice->bRadioControlOff == TRUE)) {
+ if ( (pDevice->bRadioControlOff == true)) {
CARDbRadioPowerOff(pDevice);
}
else CARDbRadioPowerOn(pDevice);
#else
if (((pDevice->byGPIO & GPIO0_DATA) && !(pDevice->byRadioCtl & EEP_RADIOCTL_INV)) ||
( !(pDevice->byGPIO & GPIO0_DATA) && (pDevice->byRadioCtl & EEP_RADIOCTL_INV))) {
- pDevice->bHWRadioOff = TRUE;
+ pDevice->bHWRadioOff = true;
}
}
- if ((pDevice->bHWRadioOff == TRUE) || (pDevice->bRadioControlOff == TRUE)) {
+ if ((pDevice->bHWRadioOff == true) || (pDevice->bRadioControlOff == true)) {
CARDbRadioPowerOff(pDevice);
}
@@ -850,17 +852,17 @@ else CARDbRadioPowerOn(pDevice);
static void device_init_diversity_timer(PSDevice pDevice) {
init_timer(&pDevice->TimerSQ3Tmax1);
- pDevice->TimerSQ3Tmax1.data = (ULONG)pDevice;
+ pDevice->TimerSQ3Tmax1.data = (unsigned long) pDevice;
pDevice->TimerSQ3Tmax1.function = (TimerFunction)TimerSQ3CallBack;
pDevice->TimerSQ3Tmax1.expires = RUN_AT(HZ);
init_timer(&pDevice->TimerSQ3Tmax2);
- pDevice->TimerSQ3Tmax2.data = (ULONG)pDevice;
+ pDevice->TimerSQ3Tmax2.data = (unsigned long) pDevice;
pDevice->TimerSQ3Tmax2.function = (TimerFunction)TimerSQ3CallBack;
pDevice->TimerSQ3Tmax2.expires = RUN_AT(HZ);
init_timer(&pDevice->TimerSQ3Tmax3);
- pDevice->TimerSQ3Tmax3.data = (ULONG)pDevice;
+ pDevice->TimerSQ3Tmax3.data = (unsigned long) pDevice;
pDevice->TimerSQ3Tmax3.function = (TimerFunction)TimerState1CallBack;
pDevice->TimerSQ3Tmax3.expires = RUN_AT(HZ);
@@ -868,13 +870,13 @@ static void device_init_diversity_timer(PSDevice pDevice) {
}
-static BOOL device_release_WPADEV(PSDevice pDevice)
+static bool device_release_WPADEV(PSDevice pDevice)
{
viawget_wpa_header *wpahdr;
int ii=0;
// wait_queue_head_t Set_wait;
//send device close to wpa_supplicnat layer
- if (pDevice->bWPADEVUp==TRUE) {
+ if (pDevice->bWPADEVUp==true) {
wpahdr = (viawget_wpa_header *)pDevice->skb->data;
wpahdr->type = VIAWGET_DEVICECLOSE_MSG;
wpahdr->resp_ie_len = 0;
@@ -891,7 +893,7 @@ static BOOL device_release_WPADEV(PSDevice pDevice)
//wait release WPADEV
// init_waitqueue_head(&Set_wait);
// wait_event_timeout(Set_wait, ((pDevice->wpadev==NULL)&&(pDevice->skb == NULL)),5*HZ); //1s wait
- while((pDevice->bWPADEVUp==TRUE)) {
+ while((pDevice->bWPADEVUp==true)) {
set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout (HZ/20); //wait 50ms
ii++;
@@ -899,7 +901,7 @@ static BOOL device_release_WPADEV(PSDevice pDevice)
break;
}
};
- return TRUE;
+ return true;
}
@@ -914,10 +916,10 @@ static const struct net_device_ops device_netdev_ops = {
-static int
-device_found1(struct pci_dev *pcid, const struct pci_device_id *ent)
+static int __devinit
+vt6655_probe(struct pci_dev *pcid, const struct pci_device_id *ent)
{
- static BOOL bFirst = TRUE;
+ static bool bFirst = true;
struct net_device* dev = NULL;
PCHIP_INFO pChip_info = (PCHIP_INFO)ent->driver_data;
PSDevice pDevice;
@@ -944,10 +946,10 @@ device_found1(struct pci_dev *pcid, const struct pci_device_id *ent)
if (bFirst) {
printk(KERN_NOTICE "%s Ver. %s\n",DEVICE_FULL_DRV_NAM, DEVICE_VERSION);
printk(KERN_NOTICE "Copyright (c) 2003 VIA Networking Technologies, Inc.\n");
- bFirst=FALSE;
+ bFirst=false;
}
- if (!device_init_info(pcid, &pDevice, pChip_info)) {
+ if (!vt6655_init_info(pcid, &pDevice, pChip_info)) {
return -ENOMEM;
}
pDevice->dev = dev;
@@ -962,7 +964,7 @@ device_found1(struct pci_dev *pcid, const struct pci_device_id *ent)
#ifdef DEBUG
printk("Before get pci_info memaddr is %x\n",pDevice->memaddr);
#endif
- if (device_get_pci_info(pDevice,pcid) == FALSE) {
+ if (device_get_pci_info(pDevice,pcid) == false) {
printk(KERN_ERR DEVICE_NAME ": Failed to find PCI device.\n");
device_free_info(pDevice);
return -ENODEV;
@@ -976,7 +978,7 @@ device_found1(struct pci_dev *pcid, const struct pci_device_id *ent)
printk("after get pci_info memaddr is %x, io addr is %x,io_size is %d\n",pDevice->memaddr,pDevice->ioaddr,pDevice->io_size);
{
int i;
- U32 bar,len;
+ u32 bar,len;
u32 address[] = {
PCI_BASE_ADDRESS_0,
PCI_BASE_ADDRESS_1,
@@ -1020,8 +1022,8 @@ device_found1(struct pci_dev *pcid, const struct pci_device_id *ent)
#ifdef DEBUG
//return 0 ;
#endif
- pDevice->PortOffset = (DWORD)ioremap(pDevice->memaddr & PCI_BASE_ADDRESS_MEM_MASK, pDevice->io_size);
- //pDevice->PortOffset = (DWORD)ioremap(pDevice->ioaddr & PCI_BASE_ADDRESS_IO_MASK, pDevice->io_size);
+ pDevice->PortOffset = (unsigned long)ioremap(pDevice->memaddr & PCI_BASE_ADDRESS_MEM_MASK, pDevice->io_size);
+ //pDevice->PortOffset = (unsigned long)ioremap(pDevice->ioaddr & PCI_BASE_ADDRESS_IO_MASK, pDevice->io_size);
if(pDevice->PortOffset == 0) {
printk(KERN_ERR DEVICE_NAME ": Failed to IO remapping ..\n");
@@ -1041,7 +1043,7 @@ device_found1(struct pci_dev *pcid, const struct pci_device_id *ent)
dev->base_addr = pDevice->ioaddr;
#ifdef PLICE_DEBUG
- BYTE value;
+ unsigned char value;
VNSvInPortB(pDevice->PortOffset+0x4F, &value);
printk("Before write: value is %x\n",value);
@@ -1111,16 +1113,17 @@ static void device_print_info(PSDevice pDevice)
DBG_PRT(MSG_LEVEL_INFO, KERN_INFO "%s: %s\n",dev->name, get_chip_name(pDevice->chip_id));
DBG_PRT(MSG_LEVEL_INFO, KERN_INFO "%s: MAC=%pM", dev->name, dev->dev_addr);
#ifdef IO_MAP
- DBG_PRT(MSG_LEVEL_INFO, KERN_INFO" IO=0x%lx ",(ULONG) pDevice->ioaddr);
+ DBG_PRT(MSG_LEVEL_INFO, KERN_INFO" IO=0x%lx ",(unsigned long) pDevice->ioaddr);
DBG_PRT(MSG_LEVEL_INFO, KERN_INFO" IRQ=%d \n", pDevice->dev->irq);
#else
- DBG_PRT(MSG_LEVEL_INFO, KERN_INFO" IO=0x%lx Mem=0x%lx ",(ULONG) pDevice->ioaddr,(ULONG) pDevice->PortOffset);
+ DBG_PRT(MSG_LEVEL_INFO, KERN_INFO" IO=0x%lx Mem=0x%lx ",
+ (unsigned long) pDevice->ioaddr,(unsigned long) pDevice->PortOffset);
DBG_PRT(MSG_LEVEL_INFO, KERN_INFO" IRQ=%d \n", pDevice->dev->irq);
#endif
}
-static BOOL device_init_info(struct pci_dev* pcid, PSDevice* ppDevice,
+static bool __devinit vt6655_init_info(struct pci_dev* pcid, PSDevice* ppDevice,
PCHIP_INFO pChip_info) {
PSDevice p;
@@ -1145,19 +1148,19 @@ static BOOL device_init_info(struct pci_dev* pcid, PSDevice* ppDevice,
spin_lock_init(&((*ppDevice)->lock));
- return TRUE;
+ return true;
}
-static BOOL device_get_pci_info(PSDevice pDevice, struct pci_dev* pcid) {
+static bool device_get_pci_info(PSDevice pDevice, struct pci_dev* pcid) {
- U16 pci_cmd;
- U8 b;
- UINT cis_addr;
+ u16 pci_cmd;
+ u8 b;
+ unsigned int cis_addr;
#ifdef PLICE_DEBUG
- BYTE pci_config[256];
- BYTE value =0x00;
+ unsigned char pci_config[256];
+ unsigned char value =0x00;
int ii,j;
- U16 max_lat=0x0000;
+ u16 max_lat=0x0000;
memset(pci_config,0x00,256);
#endif
@@ -1211,7 +1214,7 @@ static BOOL device_get_pci_info(PSDevice pDevice, struct pci_dev* pcid) {
}
}
#endif
- return TRUE;
+ return true;
}
static void device_free_info(PSDevice pDevice) {
@@ -1263,7 +1266,7 @@ device_release_WPADEV(pDevice);
}
}
-static BOOL device_init_rings(PSDevice pDevice) {
+static bool device_init_rings(PSDevice pDevice) {
void* vir_pool;
@@ -1277,7 +1280,7 @@ static BOOL device_init_rings(PSDevice pDevice) {
if (vir_pool == NULL) {
DBG_PRT(MSG_LEVEL_ERR,KERN_ERR "%s : allocate desc dma memory failed\n", pDevice->dev->name);
- return FALSE;
+ return false;
}
memset(vir_pool, 0,
@@ -1312,7 +1315,7 @@ static BOOL device_init_rings(PSDevice pDevice) {
pDevice->sOpts.nTxDescs[1] * sizeof(STxDesc),
vir_pool, pDevice->pool_dma
);
- return FALSE;
+ return false;
}
memset(pDevice->tx0_bufs, 0,
@@ -1358,7 +1361,7 @@ static BOOL device_init_rings(PSDevice pDevice) {
pDevice->sOpts.nTxDescs[1] * PKT_BUF_SZ;
- return TRUE;
+ return true;
}
static void device_free_rings(PSDevice pDevice) {
@@ -1593,7 +1596,7 @@ static void device_free_td1_ring(PSDevice pDevice) {
/*-----------------------------------------------------------------*/
-static int device_rx_srv(PSDevice pDevice, UINT uIdx) {
+static int device_rx_srv(PSDevice pDevice, unsigned int uIdx) {
PSRxDesc pRD;
int works = 0;
@@ -1621,7 +1624,7 @@ static int device_rx_srv(PSDevice pDevice, UINT uIdx) {
}
-static BOOL device_alloc_rx_buf(PSDevice pDevice, PSRxDesc pRD) {
+static bool device_alloc_rx_buf(PSDevice pDevice, PSRxDesc pRD) {
PDEVICE_RD_INFO pRDInfo=pRD->pRDInfo;
@@ -1631,7 +1634,7 @@ static BOOL device_alloc_rx_buf(PSDevice pDevice, PSRxDesc pRD) {
//printk("device_alloc_rx_buf:skb is %x\n",pRDInfo->skb);
#endif
if (pRDInfo->skb==NULL)
- return FALSE;
+ return false;
ASSERT(pRDInfo->skb);
pRDInfo->skb->dev = pDevice->dev;
pRDInfo->skb_dma = pci_map_single(pDevice->pcid, skb_tail_pointer(pRDInfo->skb),
@@ -1643,35 +1646,35 @@ static BOOL device_alloc_rx_buf(PSDevice pDevice, PSRxDesc pRD) {
pRD->m_rd1RD1.wReqCount = cpu_to_le16(pDevice->rx_buf_sz);
pRD->buff_addr = cpu_to_le32(pRDInfo->skb_dma);
- return TRUE;
+ return true;
}
-BOOL device_alloc_frag_buf(PSDevice pDevice, PSDeFragControlBlock pDeF) {
+bool device_alloc_frag_buf(PSDevice pDevice, PSDeFragControlBlock pDeF) {
pDeF->skb = dev_alloc_skb((int)pDevice->rx_buf_sz);
if (pDeF->skb == NULL)
- return FALSE;
+ return false;
ASSERT(pDeF->skb);
pDeF->skb->dev = pDevice->dev;
- return TRUE;
+ return true;
}
-static int device_tx_srv(PSDevice pDevice, UINT uIdx) {
+static int device_tx_srv(PSDevice pDevice, unsigned int uIdx) {
PSTxDesc pTD;
- BOOL bFull=FALSE;
+ bool bFull=false;
int works = 0;
- BYTE byTsr0;
- BYTE byTsr1;
- UINT uFrameSize, uFIFOHeaderSize;
+ unsigned char byTsr0;
+ unsigned char byTsr1;
+ unsigned int uFrameSize, uFIFOHeaderSize;
PSTxBufHead pTxBufHead;
struct net_device_stats* pStats = &pDevice->stats;
struct sk_buff* skb;
- UINT uNodeIndex;
+ unsigned int uNodeIndex;
PSMgmtObject pMgmt = pDevice->pMgmt;
@@ -1697,20 +1700,20 @@ static int device_tx_srv(PSDevice pDevice, UINT uIdx) {
STAvUpdateTDStatCounter(&pDevice->scStatistic,
byTsr0, byTsr1,
- (PBYTE)(pTD->pTDInfo->buf + uFIFOHeaderSize),
+ (unsigned char *)(pTD->pTDInfo->buf + uFIFOHeaderSize),
uFrameSize, uIdx);
BSSvUpdateNodeTxCounter(pDevice,
byTsr0, byTsr1,
- (PBYTE)(pTD->pTDInfo->buf),
+ (unsigned char *)(pTD->pTDInfo->buf),
uFIFOHeaderSize
);
if ( !(byTsr1 & TSR1_TERR)) {
if (byTsr0 != 0) {
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO" Tx[%d] OK but has error. tsr1[%02X] tsr0[%02X].\n",
- (INT)uIdx, byTsr1, byTsr0);
+ (int)uIdx, byTsr1, byTsr0);
}
if ((pTxBufHead->wFragCtl & FRAGCTL_ENDFRAG) != FRAGCTL_NONFRAG) {
pDevice->s802_11Counter.TransmittedFragmentCount ++;
@@ -1720,7 +1723,7 @@ static int device_tx_srv(PSDevice pDevice, UINT uIdx) {
}
else {
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO" Tx[%d] dropped & tsr1[%02X] tsr0[%02X].\n",
- (INT)uIdx, byTsr1, byTsr0);
+ (int)uIdx, byTsr1, byTsr0);
pStats->tx_errors++;
pStats->tx_dropped++;
}
@@ -1742,19 +1745,19 @@ static int device_tx_srv(PSDevice pDevice, UINT uIdx) {
if (byTsr1 & TSR1_TERR) {
if ((pTD->pTDInfo->byFlags & TD_FLAGS_PRIV_SKB) != 0) {
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO" Tx[%d] fail has error. tsr1[%02X] tsr0[%02X].\n",
- (INT)uIdx, byTsr1, byTsr0);
+ (int)uIdx, byTsr1, byTsr0);
}
// DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO" Tx[%d] fail has error. tsr1[%02X] tsr0[%02X].\n",
-// (INT)uIdx, byTsr1, byTsr0);
+// (int)uIdx, byTsr1, byTsr0);
if ((pMgmt->eCurrMode == WMAC_MODE_ESS_AP) &&
(pTD->pTDInfo->byFlags & TD_FLAGS_NETIF_SKB)) {
- WORD wAID;
- BYTE byMask[8] = {1, 2, 4, 8, 0x10, 0x20, 0x40, 0x80};
+ unsigned short wAID;
+ unsigned char byMask[8] = {1, 2, 4, 8, 0x10, 0x20, 0x40, 0x80};
skb = pTD->pTDInfo->skb;
- if (BSSDBbIsSTAInNodeDB(pMgmt, (PBYTE)(skb->data), &uNodeIndex)) {
+ if (BSSDBbIsSTAInNodeDB(pMgmt, (unsigned char *)(skb->data), &uNodeIndex)) {
if (pMgmt->sNodeDBTable[uNodeIndex].bPSEnable) {
skb_queue_tail(&pMgmt->sNodeDBTable[uNodeIndex].sTxPSQueue, skb);
pMgmt->sNodeDBTable[uNodeIndex].wEnQueueCnt++;
@@ -1763,7 +1766,7 @@ static int device_tx_srv(PSDevice pDevice, UINT uIdx) {
pMgmt->abyPSTxMap[wAID >> 3] |= byMask[wAID & 7];
pTD->pTDInfo->byFlags &= ~(TD_FLAGS_NETIF_SKB);
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "tx_srv:tx fail re-queue sta index= %d, QueCnt= %d\n"
- ,(INT)uNodeIndex, pMgmt->sNodeDBTable[uNodeIndex].wEnQueueCnt);
+ ,(int)uNodeIndex, pMgmt->sNodeDBTable[uNodeIndex].wEnQueueCnt);
pStats->tx_errors--;
pStats->tx_dropped--;
}
@@ -1780,10 +1783,10 @@ static int device_tx_srv(PSDevice pDevice, UINT uIdx) {
// RESERV_AC0DMA reserved for relay
if (AVAIL_TD(pDevice, uIdx) < RESERV_AC0DMA) {
- bFull = TRUE;
+ bFull = true;
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " AC0DMA is Full = %d\n", pDevice->iTDUsed[uIdx]);
}
- if (netif_queue_stopped(pDevice->dev) && (bFull==FALSE)){
+ if (netif_queue_stopped(pDevice->dev) && (bFull==false)){
netif_wake_queue(pDevice->dev);
}
}
@@ -1795,7 +1798,7 @@ static int device_tx_srv(PSDevice pDevice, UINT uIdx) {
}
-static void device_error(PSDevice pDevice, WORD status) {
+static void device_error(PSDevice pDevice, unsigned short status) {
if (status & ISR_FETALERR) {
DBG_PRT(MSG_LEVEL_ERR, KERN_ERR
@@ -1804,7 +1807,7 @@ static void device_error(PSDevice pDevice, WORD status) {
netif_stop_queue(pDevice->dev);
del_timer(&pDevice->sTimerCommand);
del_timer(&(pDevice->pMgmt->sTimerSecondCallback));
- pDevice->bCmdRunning = FALSE;
+ pDevice->bCmdRunning = false;
MACbShutdown(pDevice->PortOffset);
return;
}
@@ -1844,7 +1847,7 @@ void InitRxManagementQueue(PSDevice pDevice)
//PLICE_DEBUG ->
-INT MlmeThread(
+int MlmeThread(
void * Context)
{
PSDevice pDevice = (PSDevice) Context;
@@ -1914,8 +1917,8 @@ static int device_open(struct net_device *dev) {
wpa_Result.proto = 0;
wpa_Result.key_mgmt = 0;
wpa_Result.eap_type = 0;
- wpa_Result.authenticated = FALSE;
- pDevice->fWPA_Authened = FALSE;
+ wpa_Result.authenticated = false;
+ pDevice->fWPA_Authened = false;
#endif
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "call device init rd0 ring\n");
device_init_rd0_ring(pDevice);
@@ -1980,20 +1983,20 @@ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "call device_init_registers\n");
#ifdef WPA_SUPPLICANT_DRIVER_WEXT_SUPPORT
/*
- pDevice->bwextstep0 = FALSE;
- pDevice->bwextstep1 = FALSE;
- pDevice->bwextstep2 = FALSE;
- pDevice->bwextstep3 = FALSE;
+ pDevice->bwextstep0 = false;
+ pDevice->bwextstep1 = false;
+ pDevice->bwextstep2 = false;
+ pDevice->bwextstep3 = false;
*/
pDevice->bwextcount=0;
- pDevice->bWPASuppWextEnabled = FALSE;
+ pDevice->bWPASuppWextEnabled = false;
#endif
pDevice->byReAssocCount = 0;
- pDevice->bWPADEVUp = FALSE;
+ pDevice->bWPADEVUp = false;
// Patch: if WEP key already set by iwconfig but device not yet open
- if ((pDevice->bEncryptionEnable == TRUE) && (pDevice->bTransmitKey == TRUE)) {
+ if ((pDevice->bEncryptionEnable == true) && (pDevice->bTransmitKey == true)) {
KeybSetDefaultKey(&(pDevice->sKey),
- (DWORD)(pDevice->byKeyIndex | (1 << 31)),
+ (unsigned long)(pDevice->byKeyIndex | (1 << 31)),
pDevice->uKeyLength,
NULL,
pDevice->abyKey,
@@ -2052,12 +2055,12 @@ static int device_close(struct net_device *dev) {
tasklet_kill(&pDevice->RxMngWorkItem);
#endif
netif_stop_queue(dev);
- pDevice->bCmdRunning = FALSE;
+ pDevice->bCmdRunning = false;
MACbShutdown(pDevice->PortOffset);
MACbSoftwareReset(pDevice->PortOffset);
CARDbRadioPowerOff(pDevice);
- pDevice->bLinkPass = FALSE;
+ pDevice->bLinkPass = false;
memset(pMgmt->abyCurrBSSID, 0, 6);
pMgmt->eCurrState = WMAC_STATE_IDLE;
device_free_td0_ring(pDevice);
@@ -2082,8 +2085,8 @@ device_release_WPADEV(pDevice);
static int device_dma0_tx_80211(struct sk_buff *skb, struct net_device *dev) {
PSDevice pDevice=netdev_priv(dev);
- PBYTE pbMPDU;
- UINT cbMPDULen = 0;
+ unsigned char *pbMPDU;
+ unsigned int cbMPDULen = 0;
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "device_dma0_tx_80211\n");
@@ -2096,7 +2099,7 @@ static int device_dma0_tx_80211(struct sk_buff *skb, struct net_device *dev) {
return 0;
}
- if (pDevice->bStopTx0Pkt == TRUE) {
+ if (pDevice->bStopTx0Pkt == true) {
dev_kfree_skb_irq(skb);
spin_unlock_irq(&pDevice->lock);
return 0;
@@ -2115,36 +2118,36 @@ static int device_dma0_tx_80211(struct sk_buff *skb, struct net_device *dev) {
-BOOL device_dma0_xmit(PSDevice pDevice, struct sk_buff *skb, UINT uNodeIndex) {
+bool device_dma0_xmit(PSDevice pDevice, struct sk_buff *skb, unsigned int uNodeIndex) {
PSMgmtObject pMgmt = pDevice->pMgmt;
PSTxDesc pHeadTD, pLastTD;
- UINT cbFrameBodySize;
- UINT uMACfragNum;
- BYTE byPktType;
- BOOL bNeedEncryption = FALSE;
+ unsigned int cbFrameBodySize;
+ unsigned int uMACfragNum;
+ unsigned char byPktType;
+ bool bNeedEncryption = false;
PSKeyItem pTransmitKey = NULL;
- UINT cbHeaderSize;
- UINT ii;
+ unsigned int cbHeaderSize;
+ unsigned int ii;
SKeyItem STempKey;
-// BYTE byKeyIndex = 0;
+// unsigned char byKeyIndex = 0;
- if (pDevice->bStopTx0Pkt == TRUE) {
+ if (pDevice->bStopTx0Pkt == true) {
dev_kfree_skb_irq(skb);
- return FALSE;
+ return false;
};
if (AVAIL_TD(pDevice, TYPE_TXDMA0) <= 0) {
dev_kfree_skb_irq(skb);
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "device_dma0_xmit, td0 <=0\n");
- return FALSE;
+ return false;
}
if (pMgmt->eCurrMode == WMAC_MODE_ESS_AP) {
if (pDevice->uAssocCount == 0) {
dev_kfree_skb_irq(skb);
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "device_dma0_xmit, assocCount = 0\n");
- return FALSE;
+ return false;
}
}
@@ -2152,7 +2155,7 @@ BOOL device_dma0_xmit(PSDevice pDevice, struct sk_buff *skb, UINT uNodeIndex) {
pHeadTD->m_td1TD1.byTCR = (TCR_EDP|TCR_STP);
- memcpy(pDevice->sTxEthHeader.abyDstAddr, (PBYTE)(skb->data), ETH_HLEN);
+ memcpy(pDevice->sTxEthHeader.abyDstAddr, (unsigned char *)(skb->data), ETH_HLEN);
cbFrameBodySize = skb->len - ETH_HLEN;
// 802.1H
@@ -2163,9 +2166,9 @@ BOOL device_dma0_xmit(PSDevice pDevice, struct sk_buff *skb, UINT uNodeIndex) {
if ( uMACfragNum > AVAIL_TD(pDevice, TYPE_TXDMA0)) {
dev_kfree_skb_irq(skb);
- return FALSE;
+ return false;
}
- byPktType = (BYTE)pDevice->byPacketType;
+ byPktType = (unsigned char)pDevice->byPacketType;
if (pDevice->bFixRate) {
@@ -2173,13 +2176,13 @@ BOOL device_dma0_xmit(PSDevice pDevice, struct sk_buff *skb, UINT uNodeIndex) {
if (pDevice->uConnectionRate >= RATE_11M) {
pDevice->wCurrentRate = RATE_11M;
} else {
- pDevice->wCurrentRate = (WORD)pDevice->uConnectionRate;
+ pDevice->wCurrentRate = (unsigned short)pDevice->uConnectionRate;
}
} else {
if (pDevice->uConnectionRate >= RATE_54M)
pDevice->wCurrentRate = RATE_54M;
else
- pDevice->wCurrentRate = (WORD)pDevice->uConnectionRate;
+ pDevice->wCurrentRate = (unsigned short)pDevice->uConnectionRate;
}
}
else {
@@ -2202,15 +2205,15 @@ BOOL device_dma0_xmit(PSDevice pDevice, struct sk_buff *skb, UINT uNodeIndex) {
} else if (pDevice->eCurrentPHYType == PHY_TYPE_11A) {
byPktType = PK_TYPE_11A;
} else {
- if (pDevice->bProtectMode == TRUE) {
+ if (pDevice->bProtectMode == true) {
byPktType = PK_TYPE_11GB;
} else {
byPktType = PK_TYPE_11GA;
}
}
- if (pDevice->bEncryptionEnable == TRUE)
- bNeedEncryption = TRUE;
+ if (pDevice->bEncryptionEnable == true)
+ bNeedEncryption = true;
if (pDevice->bEnableHostWEP) {
pTransmitKey = &STempKey;
@@ -2226,7 +2229,7 @@ BOOL device_dma0_xmit(PSDevice pDevice, struct sk_buff *skb, UINT uNodeIndex) {
}
vGenerateFIFOHeader(pDevice, byPktType, pDevice->pbyTmpBuff, bNeedEncryption,
cbFrameBodySize, TYPE_TXDMA0, pHeadTD,
- &pDevice->sTxEthHeader, (PBYTE)skb->data, pTransmitKey, uNodeIndex,
+ &pDevice->sTxEthHeader, (unsigned char *)skb->data, pTransmitKey, uNodeIndex,
&uMACfragNum,
&cbHeaderSize
);
@@ -2236,7 +2239,7 @@ BOOL device_dma0_xmit(PSDevice pDevice, struct sk_buff *skb, UINT uNodeIndex) {
MACbPSWakeup(pDevice->PortOffset);
}
- pDevice->bPWBitOn = FALSE;
+ pDevice->bPWBitOn = false;
pLastTD = pHeadTD;
for (ii = 0; ii < uMACfragNum; ii++) {
@@ -2260,7 +2263,7 @@ BOOL device_dma0_xmit(PSDevice pDevice, struct sk_buff *skb, UINT uNodeIndex) {
MACvTransmit0(pDevice->PortOffset);
- return TRUE;
+ return true;
}
//TYPE_AC0DMA data tx
@@ -2269,26 +2272,26 @@ static int device_xmit(struct sk_buff *skb, struct net_device *dev) {
PSMgmtObject pMgmt = pDevice->pMgmt;
PSTxDesc pHeadTD, pLastTD;
- UINT uNodeIndex = 0;
- BYTE byMask[8] = {1, 2, 4, 8, 0x10, 0x20, 0x40, 0x80};
- WORD wAID;
- UINT uMACfragNum = 1;
- UINT cbFrameBodySize;
- BYTE byPktType;
- UINT cbHeaderSize;
- BOOL bNeedEncryption = FALSE;
+ unsigned int uNodeIndex = 0;
+ unsigned char byMask[8] = {1, 2, 4, 8, 0x10, 0x20, 0x40, 0x80};
+ unsigned short wAID;
+ unsigned int uMACfragNum = 1;
+ unsigned int cbFrameBodySize;
+ unsigned char byPktType;
+ unsigned int cbHeaderSize;
+ bool bNeedEncryption = false;
PSKeyItem pTransmitKey = NULL;
SKeyItem STempKey;
- UINT ii;
- BOOL bTKIP_UseGTK = FALSE;
- BOOL bNeedDeAuth = FALSE;
- PBYTE pbyBSSID;
- BOOL bNodeExist = FALSE;
+ unsigned int ii;
+ bool bTKIP_UseGTK = false;
+ bool bNeedDeAuth = false;
+ unsigned char *pbyBSSID;
+ bool bNodeExist = false;
spin_lock_irq(&pDevice->lock);
- if (pDevice->bLinkPass == FALSE) {
+ if (pDevice->bLinkPass == false) {
dev_kfree_skb_irq(skb);
spin_unlock_irq(&pDevice->lock);
return 0;
@@ -2307,9 +2310,9 @@ static int device_xmit(struct sk_buff *skb, struct net_device *dev) {
spin_unlock_irq(&pDevice->lock);
return 0;
}
- if (IS_MULTICAST_ADDRESS((PBYTE)(skb->data))) {
+ if (is_multicast_ether_addr((unsigned char *)(skb->data))) {
uNodeIndex = 0;
- bNodeExist = TRUE;
+ bNodeExist = true;
if (pMgmt->sNodeDBTable[0].bPSEnable) {
skb_queue_tail(&(pMgmt->sNodeDBTable[0].sTxPSQueue), skb);
pMgmt->sNodeDBTable[0].wEnQueueCnt++;
@@ -2319,7 +2322,7 @@ static int device_xmit(struct sk_buff *skb, struct net_device *dev) {
return 0;
}
}else {
- if (BSSDBbIsSTAInNodeDB(pMgmt, (PBYTE)(skb->data), &uNodeIndex)) {
+ if (BSSDBbIsSTAInNodeDB(pMgmt, (unsigned char *)(skb->data), &uNodeIndex)) {
if (pMgmt->sNodeDBTable[uNodeIndex].bPSEnable) {
skb_queue_tail(&pMgmt->sNodeDBTable[uNodeIndex].sTxPSQueue, skb);
pMgmt->sNodeDBTable[uNodeIndex].wEnQueueCnt++;
@@ -2338,12 +2341,12 @@ static int device_xmit(struct sk_buff *skb, struct net_device *dev) {
}else {
pDevice->byPreambleType = PREAMBLE_LONG;
}
- bNodeExist = TRUE;
+ bNodeExist = true;
}
}
- if (bNodeExist == FALSE) {
+ if (bNodeExist == false) {
DBG_PRT(MSG_LEVEL_DEBUG, KERN_DEBUG"Unknown STA not found in node DB \n");
dev_kfree_skb_irq(skb);
spin_unlock_irq(&pDevice->lock);
@@ -2356,7 +2359,7 @@ static int device_xmit(struct sk_buff *skb, struct net_device *dev) {
pHeadTD->m_td1TD1.byTCR = (TCR_EDP|TCR_STP);
- memcpy(pDevice->sTxEthHeader.abyDstAddr, (PBYTE)(skb->data), ETH_HLEN);
+ memcpy(pDevice->sTxEthHeader.abyDstAddr, (unsigned char *)(skb->data), ETH_HLEN);
cbFrameBodySize = skb->len - ETH_HLEN;
// 802.1H
if (ntohs(pDevice->sTxEthHeader.wType) > ETH_DATA_LEN) {
@@ -2364,18 +2367,18 @@ static int device_xmit(struct sk_buff *skb, struct net_device *dev) {
}
- if (pDevice->bEncryptionEnable == TRUE) {
- bNeedEncryption = TRUE;
+ if (pDevice->bEncryptionEnable == true) {
+ bNeedEncryption = true;
// get Transmit key
do {
if ((pDevice->pMgmt->eCurrMode == WMAC_MODE_ESS_STA) &&
(pDevice->pMgmt->eCurrState == WMAC_STATE_ASSOC)) {
pbyBSSID = pDevice->abyBSSID;
// get pairwise key
- if (KeybGetTransmitKey(&(pDevice->sKey), pbyBSSID, PAIRWISE_KEY, &pTransmitKey) == FALSE) {
+ if (KeybGetTransmitKey(&(pDevice->sKey), pbyBSSID, PAIRWISE_KEY, &pTransmitKey) == false) {
// get group key
- if(KeybGetTransmitKey(&(pDevice->sKey), pbyBSSID, GROUP_KEY, &pTransmitKey) == TRUE) {
- bTKIP_UseGTK = TRUE;
+ if(KeybGetTransmitKey(&(pDevice->sKey), pbyBSSID, GROUP_KEY, &pTransmitKey) == true) {
+ bTKIP_UseGTK = true;
DBG_PRT(MSG_LEVEL_DEBUG, KERN_DEBUG"Get GTK.\n");
break;
}
@@ -2392,12 +2395,12 @@ static int device_xmit(struct sk_buff *skb, struct net_device *dev) {
DBG_PRT(MSG_LEVEL_DEBUG, KERN_DEBUG"\n");
// get pairwise key
- if(KeybGetTransmitKey(&(pDevice->sKey), pbyBSSID, PAIRWISE_KEY, &pTransmitKey) == TRUE)
+ if(KeybGetTransmitKey(&(pDevice->sKey), pbyBSSID, PAIRWISE_KEY, &pTransmitKey) == true)
break;
}
// get group key
pbyBSSID = pDevice->abyBroadcastAddr;
- if(KeybGetTransmitKey(&(pDevice->sKey), pbyBSSID, GROUP_KEY, &pTransmitKey) == FALSE) {
+ if(KeybGetTransmitKey(&(pDevice->sKey), pbyBSSID, GROUP_KEY, &pTransmitKey) == false) {
pTransmitKey = NULL;
if (pDevice->pMgmt->eCurrMode == WMAC_MODE_IBSS_STA) {
DBG_PRT(MSG_LEVEL_DEBUG, KERN_DEBUG"IBSS and KEY is NULL. [%d]\n", pDevice->pMgmt->eCurrMode);
@@ -2405,15 +2408,15 @@ static int device_xmit(struct sk_buff *skb, struct net_device *dev) {
else
DBG_PRT(MSG_LEVEL_DEBUG, KERN_DEBUG"NOT IBSS and KEY is NULL. [%d]\n", pDevice->pMgmt->eCurrMode);
} else {
- bTKIP_UseGTK = TRUE;
+ bTKIP_UseGTK = true;
DBG_PRT(MSG_LEVEL_DEBUG, KERN_DEBUG"Get GTK.\n");
}
- } while(FALSE);
+ } while(false);
}
if (pDevice->bEnableHostWEP) {
DBG_PRT(MSG_LEVEL_DEBUG, KERN_DEBUG"acdma0: STA index %d\n", uNodeIndex);
- if (pDevice->bEncryptionEnable == TRUE) {
+ if (pDevice->bEncryptionEnable == true) {
pTransmitKey = &STempKey;
pTransmitKey->byCipherSuite = pMgmt->sNodeDBTable[uNodeIndex].byCipherSuite;
pTransmitKey->dwKeyIndex = pMgmt->sNodeDBTable[uNodeIndex].dwKeyIndex;
@@ -2443,7 +2446,7 @@ static int device_xmit(struct sk_buff *skb, struct net_device *dev) {
}
}
- byPktType = (BYTE)pDevice->byPacketType;
+ byPktType = (unsigned char)pDevice->byPacketType;
if (pDevice->bFixRate) {
#ifdef PLICE_DEBUG
@@ -2454,7 +2457,7 @@ static int device_xmit(struct sk_buff *skb, struct net_device *dev) {
if (pDevice->uConnectionRate >= RATE_11M) {
pDevice->wCurrentRate = RATE_11M;
} else {
- pDevice->wCurrentRate = (WORD)pDevice->uConnectionRate;
+ pDevice->wCurrentRate = (unsigned short)pDevice->uConnectionRate;
}
} else {
if ((pDevice->eCurrentPHYType == PHY_TYPE_11A) &&
@@ -2464,11 +2467,11 @@ static int device_xmit(struct sk_buff *skb, struct net_device *dev) {
if (pDevice->uConnectionRate >= RATE_54M)
pDevice->wCurrentRate = RATE_54M;
else
- pDevice->wCurrentRate = (WORD)pDevice->uConnectionRate;
+ pDevice->wCurrentRate = (unsigned short)pDevice->uConnectionRate;
}
}
- pDevice->byACKRate = (BYTE) pDevice->wCurrentRate;
+ pDevice->byACKRate = (unsigned char) pDevice->wCurrentRate;
pDevice->byTopCCKBasicRate = RATE_1M;
pDevice->byTopOFDMBasicRate = RATE_6M;
}
@@ -2521,7 +2524,7 @@ pDevice->byTopCCKBasicRate,pDevice->byTopOFDMBasicRate);
} else if (pDevice->eCurrentPHYType == PHY_TYPE_11A) {
byPktType = PK_TYPE_11A;
} else {
- if (pDevice->bProtectMode == TRUE) {
+ if (pDevice->bProtectMode == true) {
byPktType = PK_TYPE_11GB;
} else {
byPktType = PK_TYPE_11GA;
@@ -2532,28 +2535,28 @@ pDevice->byTopCCKBasicRate,pDevice->byTopOFDMBasicRate);
// printk("FIX RATE:CurrentRate is %d");
//#endif
- if (bNeedEncryption == TRUE) {
+ if (bNeedEncryption == true) {
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"ntohs Pkt Type=%04x\n", ntohs(pDevice->sTxEthHeader.wType));
if ((pDevice->sTxEthHeader.wType) == TYPE_PKT_802_1x) {
- bNeedEncryption = FALSE;
+ bNeedEncryption = false;
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Pkt Type=%04x\n", (pDevice->sTxEthHeader.wType));
if ((pDevice->pMgmt->eCurrMode == WMAC_MODE_ESS_STA) && (pDevice->pMgmt->eCurrState == WMAC_STATE_ASSOC)) {
if (pTransmitKey == NULL) {
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Don't Find TX KEY\n");
}
else {
- if (bTKIP_UseGTK == TRUE) {
+ if (bTKIP_UseGTK == true) {
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"error: KEY is GTK!!~~\n");
}
else {
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Find PTK [%lX]\n", pTransmitKey->dwKeyIndex);
- bNeedEncryption = TRUE;
+ bNeedEncryption = true;
}
}
}
if (pDevice->byCntMeasure == 2) {
- bNeedDeAuth = TRUE;
+ bNeedDeAuth = true;
pDevice->s802_11Counter.TKIPCounterMeasuresInvoked++;
}
@@ -2561,7 +2564,7 @@ pDevice->byTopCCKBasicRate,pDevice->byTopOFDMBasicRate);
if ((uNodeIndex != 0) &&
(pMgmt->sNodeDBTable[uNodeIndex].dwKeyIndex & PAIRWISE_KEY)) {
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Find PTK [%lX]\n", pTransmitKey->dwKeyIndex);
- bNeedEncryption = TRUE;
+ bNeedEncryption = true;
}
}
}
@@ -2584,7 +2587,7 @@ pDevice->byTopCCKBasicRate,pDevice->byTopOFDMBasicRate);
#endif
vGenerateFIFOHeader(pDevice, byPktType, pDevice->pbyTmpBuff, bNeedEncryption,
cbFrameBodySize, TYPE_AC0DMA, pHeadTD,
- &pDevice->sTxEthHeader, (PBYTE)skb->data, pTransmitKey, uNodeIndex,
+ &pDevice->sTxEthHeader, (unsigned char *)skb->data, pTransmitKey, uNodeIndex,
&uMACfragNum,
&cbHeaderSize
);
@@ -2593,7 +2596,7 @@ pDevice->byTopCCKBasicRate,pDevice->byTopOFDMBasicRate);
// Disable PS
MACbPSWakeup(pDevice->PortOffset);
}
- pDevice->bPWBitOn = FALSE;
+ pDevice->bPWBitOn = false;
pLastTD = pHeadTD;
for (ii = 0; ii < uMACfragNum; ii++) {
@@ -2631,11 +2634,11 @@ pDevice->byTopCCKBasicRate,pDevice->byTopOFDMBasicRate);
//#endif
{
- BYTE Protocol_Version; //802.1x Authentication
- BYTE Packet_Type; //802.1x Authentication
- BYTE Descriptor_type;
- WORD Key_info;
-BOOL bTxeapol_key = FALSE;
+ unsigned char Protocol_Version; //802.1x Authentication
+ unsigned char Packet_Type; //802.1x Authentication
+ unsigned char Descriptor_type;
+ unsigned short Key_info;
+bool bTxeapol_key = false;
Protocol_Version = skb->data[ETH_HLEN];
Packet_Type = skb->data[ETH_HLEN+1];
Descriptor_type = skb->data[ETH_HLEN+1+1+2];
@@ -2643,11 +2646,11 @@ BOOL bTxeapol_key = FALSE;
if (pDevice->sTxEthHeader.wType == TYPE_PKT_802_1x) {
if(((Protocol_Version==1) ||(Protocol_Version==2)) &&
(Packet_Type==3)) { //802.1x OR eapol-key challenge frame transfer
- bTxeapol_key = TRUE;
+ bTxeapol_key = true;
if((Descriptor_type==254)||(Descriptor_type==2)) { //WPA or RSN
if(!(Key_info & BIT3) && //group-key challenge
(Key_info & BIT8) && (Key_info & BIT9)) { //send 2/2 key
- pDevice->fWPA_Authened = TRUE;
+ pDevice->fWPA_Authened = true;
if(Descriptor_type==254)
printk("WPA ");
else
@@ -2674,13 +2677,13 @@ static irqreturn_t device_intr(int irq, void *dev_instance) {
PSDevice pDevice=(PSDevice) netdev_priv(dev);
int max_count=0;
- DWORD dwMIBCounter=0;
+ unsigned long dwMIBCounter=0;
PSMgmtObject pMgmt = pDevice->pMgmt;
- BYTE byOrgPageSel=0;
+ unsigned char byOrgPageSel=0;
int handled = 0;
- BYTE byData = 0;
+ unsigned char byData = 0;
int ii= 0;
-// BYTE byRSSI;
+// unsigned char byRSSI;
MACvReadISR(pDevice->PortOffset, &pDevice->dwIsr);
@@ -2697,7 +2700,7 @@ static irqreturn_t device_intr(int irq, void *dev_instance) {
if ((pDevice->dwIsr & ISR_RXDMA0) &&
(pDevice->byLocalID != REV_ID_VT3253_B0) &&
- (pDevice->bBSSIDFilter == TRUE)) {
+ (pDevice->bBSSIDFilter == true)) {
// update RSSI
//BBbReadEmbeded(pDevice->PortOffset, 0x3E, &byRSSI);
//pDevice->uCurrRSSI = byRSSI;
@@ -2746,9 +2749,9 @@ static irqreturn_t device_intr(int irq, void *dev_instance) {
VNSvInPortD(pDevice->PortOffset + MAC_REG_MAR4, &(pDevice->dwOrgMAR4));
MACvSelectPage0(pDevice->PortOffset);
//xxxx
- // WCMDbFlushCommandQueue(pDevice->pMgmt, TRUE);
- if (CARDbSetChannel(pDevice, pDevice->pCurrMeasureEID->sReq.byChannel) == TRUE) {
- pDevice->bMeasureInProgress = TRUE;
+ // WCMDbFlushCommandQueue(pDevice->pMgmt, true);
+ if (set_channel(pDevice, pDevice->pCurrMeasureEID->sReq.byChannel) == true) {
+ pDevice->bMeasureInProgress = true;
MACvSelectPage1(pDevice->PortOffset);
MACvRegBitsOn(pDevice->PortOffset, MAC_REG_MSRCTL, MSRCTL_READY);
MACvSelectPage0(pDevice->PortOffset);
@@ -2770,7 +2773,7 @@ static irqreturn_t device_intr(int irq, void *dev_instance) {
}
if (pDevice->dwIsr & ISR_MEASUREEND) {
// 802.11h measure end
- pDevice->bMeasureInProgress = FALSE;
+ pDevice->bMeasureInProgress = false;
VNSvOutPortB(pDevice->PortOffset + MAC_REG_RCR, pDevice->byOrgRCR);
MACvSelectPage1(pDevice->PortOffset);
VNSvOutPortD(pDevice->PortOffset + MAC_REG_MAR0, pDevice->dwOrgMAR0);
@@ -2782,7 +2785,7 @@ static irqreturn_t device_intr(int irq, void *dev_instance) {
// clear measure control
MACvRegBitsOff(pDevice->PortOffset, MAC_REG_MSRCTL, MSRCTL_EN);
MACvSelectPage0(pDevice->PortOffset);
- CARDbSetChannel(pDevice, pDevice->byOrgChannel);
+ set_channel(pDevice, pDevice->byOrgChannel);
// WCMDbResetCommandQueue(pDevice->pMgmt);
MACvSelectPage1(pDevice->PortOffset);
MACvRegBitsOn(pDevice->PortOffset, MAC_REG_MSRCTL+1, MSRCTL1_TXPAUSE);
@@ -2798,26 +2801,26 @@ static irqreturn_t device_intr(int irq, void *dev_instance) {
if (pDevice->dwIsr & ISR_QUIETSTART) {
do {
;
- } while (CARDbStartQuiet(pDevice) == FALSE);
+ } while (CARDbStartQuiet(pDevice) == false);
}
}
if (pDevice->dwIsr & ISR_TBTT) {
- if (pDevice->bEnableFirstQuiet == TRUE) {
+ if (pDevice->bEnableFirstQuiet == true) {
pDevice->byQuietStartCount--;
if (pDevice->byQuietStartCount == 0) {
- pDevice->bEnableFirstQuiet = FALSE;
+ pDevice->bEnableFirstQuiet = false;
MACvSelectPage1(pDevice->PortOffset);
MACvRegBitsOn(pDevice->PortOffset, MAC_REG_MSRCTL, (MSRCTL_QUIETTXCHK | MSRCTL_QUIETEN));
MACvSelectPage0(pDevice->PortOffset);
}
}
- if ((pDevice->bChannelSwitch == TRUE) &&
+ if ((pDevice->bChannelSwitch == true) &&
(pDevice->eOPMode == OP_MODE_INFRASTRUCTURE)) {
pDevice->byChannelSwitchCount--;
if (pDevice->byChannelSwitchCount == 0) {
- pDevice->bChannelSwitch = FALSE;
- CARDbSetChannel(pDevice, pDevice->byNewChannel);
+ pDevice->bChannelSwitch = false;
+ set_channel(pDevice, pDevice->byNewChannel);
VNTWIFIbChannelSwitch(pDevice->pMgmt, pDevice->byNewChannel);
MACvSelectPage1(pDevice->PortOffset);
MACvRegBitsOn(pDevice->PortOffset, MAC_REG_MSRCTL+1, MSRCTL1_TXPAUSE);
@@ -2827,12 +2830,12 @@ static irqreturn_t device_intr(int irq, void *dev_instance) {
}
}
if (pDevice->eOPMode == OP_MODE_ADHOC) {
- //pDevice->bBeaconSent = FALSE;
+ //pDevice->bBeaconSent = false;
} else {
- if ((pDevice->bUpdateBBVGA) && (pDevice->bLinkPass == TRUE) && (pDevice->uCurrRSSI != 0)) {
- LONG ldBm;
+ if ((pDevice->bUpdateBBVGA) && (pDevice->bLinkPass == true) && (pDevice->uCurrRSSI != 0)) {
+ long ldBm;
- RFvRSSITodBm(pDevice, (BYTE) pDevice->uCurrRSSI, &ldBm);
+ RFvRSSITodBm(pDevice, (unsigned char) pDevice->uCurrRSSI, &ldBm);
for (ii=0;ii<BB_VGA_LEVEL;ii++) {
if (ldBm < pDevice->ldBmThreshold[ii]) {
pDevice->byBBVGANew = pDevice->abyBBVGA[ii];
@@ -2858,7 +2861,7 @@ static irqreturn_t device_intr(int irq, void *dev_instance) {
}
}
- pDevice->bBeaconSent = FALSE;
+ pDevice->bBeaconSent = false;
if (pDevice->bEnablePSMode) {
PSbIsNextTBTTWakeUp((void *)pDevice);
};
@@ -2879,31 +2882,31 @@ static irqreturn_t device_intr(int irq, void *dev_instance) {
if (pDevice->dwIsr & ISR_BNTX) {
if (pDevice->eOPMode == OP_MODE_ADHOC) {
- pDevice->bIsBeaconBufReadySet = FALSE;
+ pDevice->bIsBeaconBufReadySet = false;
pDevice->cbBeaconBufReadySetCnt = 0;
};
if (pDevice->eOPMode == OP_MODE_AP) {
if(pMgmt->byDTIMCount > 0) {
pMgmt->byDTIMCount --;
- pMgmt->sNodeDBTable[0].bRxPSPoll = FALSE;
+ pMgmt->sNodeDBTable[0].bRxPSPoll = false;
}
else {
if(pMgmt->byDTIMCount == 0) {
// check if mutltcast tx bufferring
pMgmt->byDTIMCount = pMgmt->byDTIMPeriod - 1;
- pMgmt->sNodeDBTable[0].bRxPSPoll = TRUE;
+ pMgmt->sNodeDBTable[0].bRxPSPoll = true;
bScheduleCommand((void *)pDevice, WLAN_CMD_RX_PSPOLL, NULL);
}
}
}
- pDevice->bBeaconSent = TRUE;
+ pDevice->bBeaconSent = true;
- if (pDevice->bChannelSwitch == TRUE) {
+ if (pDevice->bChannelSwitch == true) {
pDevice->byChannelSwitchCount--;
if (pDevice->byChannelSwitchCount == 0) {
- pDevice->bChannelSwitch = FALSE;
- CARDbSetChannel(pDevice, pDevice->byNewChannel);
+ pDevice->bChannelSwitch = false;
+ set_channel(pDevice, pDevice->byNewChannel);
VNTWIFIbChannelSwitch(pDevice->pMgmt, pDevice->byNewChannel);
MACvSelectPage1(pDevice->PortOffset);
MACvRegBitsOn(pDevice->PortOffset, MAC_REG_MSRCTL+1, MSRCTL1_TXPAUSE);
@@ -2978,9 +2981,10 @@ static inline u32 ether_crc(int length, unsigned char *data)
}
//2008-8-4 <add> by chester
-static int Config_FileGetParameter(UCHAR *string, UCHAR *dest,UCHAR *source)
+static int Config_FileGetParameter(unsigned char *string,
+ unsigned char *dest, unsigned char *source)
{
- UCHAR buf1[100];
+ unsigned char buf1[100];
int source_len = strlen(source);
memset(buf1,0,100);
@@ -2989,13 +2993,13 @@ static int Config_FileGetParameter(UCHAR *string, UCHAR *dest,UCHAR *source)
source+=strlen(buf1);
memcpy(dest,source,source_len-strlen(buf1));
- return TRUE;
+ return true;
}
-int Config_FileOperation(PSDevice pDevice,BOOL fwrite,unsigned char *Parameter) {
- UCHAR *config_path=CONFIG_PATH;
- UCHAR *buffer=NULL;
- UCHAR tmpbuffer[20];
+int Config_FileOperation(PSDevice pDevice,bool fwrite,unsigned char *Parameter) {
+ unsigned char *config_path = CONFIG_PATH;
+ unsigned char *buffer = NULL;
+ unsigned char tmpbuffer[20];
struct file *filp=NULL;
mm_segment_t old_fs = get_fs();
//int oldfsuid=0,oldfsgid=0;
@@ -3038,7 +3042,7 @@ if(filp->f_op->read(filp, buffer, 1024, &filp->f_pos)<0) {
goto error1;
}
-if(Config_FileGetParameter("ZONETYPE",tmpbuffer,buffer)!=TRUE) {
+if(Config_FileGetParameter("ZONETYPE",tmpbuffer,buffer)!=true) {
printk("get parameter error?\n");
result = -1;
goto error1;
@@ -3555,19 +3559,19 @@ static int device_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) {
else {
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Commit the settings\n");
spin_lock_irq(&pDevice->lock);
- pDevice->bLinkPass = FALSE;
+ pDevice->bLinkPass = false;
memset(pMgmt->abyCurrBSSID, 0, 6);
pMgmt->eCurrState = WMAC_STATE_IDLE;
netif_stop_queue(pDevice->dev);
#ifdef WPA_SUPPLICANT_DRIVER_WEXT_SUPPORT
pMgmt->eScanType = WMAC_SCAN_ACTIVE;
- if(pDevice->bWPASuppWextEnabled !=TRUE)
+ if(pDevice->bWPASuppWextEnabled !=true)
#endif
bScheduleCommand((void *) pDevice, WLAN_CMD_BSSID_SCAN, pMgmt->abyDesireSSID);
bScheduleCommand((void *) pDevice, WLAN_CMD_SSID, NULL);
spin_unlock_irq(&pDevice->lock);
}
- pDevice->bCommit = FALSE;
+ pDevice->bCommit = false;
}
return rc;
@@ -3598,20 +3602,20 @@ static int ethtool_ioctl(struct net_device *dev, void *useraddr)
/*------------------------------------------------------------------*/
-MODULE_DEVICE_TABLE(pci, device_id_table);
+MODULE_DEVICE_TABLE(pci, vt6655_pci_id_table);
static struct pci_driver device_driver = {
name: DEVICE_NAME,
- id_table: device_id_table,
- probe: device_found1,
- remove: device_remove1,
+ id_table: vt6655_pci_id_table,
+ probe: vt6655_probe,
+ remove: vt6655_remove,
#ifdef CONFIG_PM
suspend: viawget_suspend,
resume: viawget_resume,
#endif
};
-static int __init device_init_module(void)
+static int __init vt6655_init_module(void)
{
int ret;
@@ -3627,7 +3631,7 @@ static int __init device_init_module(void)
return ret;
}
-static void __exit device_cleanup_module(void)
+static void __exit vt6655_cleanup_module(void)
{
@@ -3638,8 +3642,8 @@ static void __exit device_cleanup_module(void)
}
-module_init(device_init_module);
-module_exit(device_cleanup_module);
+module_init(vt6655_init_module);
+module_exit(vt6655_cleanup_module);
#ifdef CONFIG_PM
@@ -3651,7 +3655,7 @@ device_notify_reboot(struct notifier_block *nb, unsigned long event, void *p)
case SYS_DOWN:
case SYS_HALT:
case SYS_POWER_OFF:
- while ((pdev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, pdev)) != NULL) {
+ for_each_pci_dev(pdev) {
if(pci_dev_driver(pdev) == &device_driver) {
if (pci_get_drvdata(pdev))
viawget_suspend(pdev, PMSG_HIBERNATE);
@@ -3677,10 +3681,10 @@ viawget_suspend(struct pci_dev *pcid, pm_message_t state)
pDevice->cbFreeCmdQueue = CMD_Q_SIZE;
pDevice->uCmdDequeueIdx = 0;
pDevice->uCmdEnqueueIdx = 0;
- pDevice->bCmdRunning = FALSE;
+ pDevice->bCmdRunning = false;
MACbShutdown(pDevice->PortOffset);
MACvSaveContext(pDevice->PortOffset, pDevice->abyMacContext);
- pDevice->bLinkPass = FALSE;
+ pDevice->bLinkPass = false;
memset(pMgmt->abyCurrBSSID, 0, 6);
pMgmt->eCurrState = WMAC_STATE_IDLE;
pci_disable_device(pcid);
@@ -3704,9 +3708,9 @@ viawget_resume(struct pci_dev *pcid)
spin_lock_irq(&pDevice->lock);
MACvRestoreContext(pDevice->PortOffset, pDevice->abyMacContext);
device_init_registers(pDevice, DEVICE_INIT_DXPL);
- if (pMgmt->sNodeDBTable[0].bActive == TRUE) { // Assoc with BSS
- pMgmt->sNodeDBTable[0].bActive = FALSE;
- pDevice->bLinkPass = FALSE;
+ if (pMgmt->sNodeDBTable[0].bActive == true) { // Assoc with BSS
+ pMgmt->sNodeDBTable[0].bActive = false;
+ pDevice->bLinkPass = false;
if(pMgmt->eCurrMode == WMAC_MODE_IBSS_STA) {
// In Adhoc, BSS state set back to started.
pMgmt->eCurrState = WMAC_STATE_STARTED;
diff --git a/drivers/staging/vt6655/dpc.c b/drivers/staging/vt6655/dpc.c
index 6b758a8c1af..15130733693 100644
--- a/drivers/staging/vt6655/dpc.c
+++ b/drivers/staging/vt6655/dpc.c
@@ -66,7 +66,7 @@
//static int msglevel =MSG_LEVEL_DEBUG;
static int msglevel =MSG_LEVEL_INFO;
-const BYTE acbyRxRate[MAX_RATE] =
+const unsigned char acbyRxRate[MAX_RATE] =
{2, 4, 11, 22, 12, 18, 24, 36, 48, 72, 96, 108};
@@ -76,70 +76,60 @@ const BYTE acbyRxRate[MAX_RATE] =
/*--------------------- Static Functions --------------------------*/
-static BYTE s_byGetRateIdx(BYTE byRate);
+static unsigned char s_byGetRateIdx(unsigned char byRate);
-static
-void
-s_vGetDASA(
- PBYTE pbyRxBufferAddr,
- PUINT pcbHeaderSize,
- PSEthernetHeader psEthHeader
- );
+static void
+s_vGetDASA(unsigned char *pbyRxBufferAddr, unsigned int *pcbHeaderSize,
+ PSEthernetHeader psEthHeader);
-static
-void
-s_vProcessRxMACHeader (
- PSDevice pDevice,
- PBYTE pbyRxBufferAddr,
- UINT cbPacketSize,
- BOOL bIsWEP,
- BOOL bExtIV,
- PUINT pcbHeadSize
- );
+static void
+s_vProcessRxMACHeader(PSDevice pDevice, unsigned char *pbyRxBufferAddr,
+ unsigned int cbPacketSize, bool bIsWEP, bool bExtIV,
+ unsigned int *pcbHeadSize);
-static BOOL s_bAPModeRxCtl(
+static bool s_bAPModeRxCtl(
PSDevice pDevice,
- PBYTE pbyFrame,
- INT iSANodeIndex
+ unsigned char *pbyFrame,
+ int iSANodeIndex
);
-static BOOL s_bAPModeRxData (
+static bool s_bAPModeRxData (
PSDevice pDevice,
struct sk_buff* skb,
- UINT FrameSize,
- UINT cbHeaderOffset,
- INT iSANodeIndex,
- INT iDANodeIndex
+ unsigned int FrameSize,
+ unsigned int cbHeaderOffset,
+ int iSANodeIndex,
+ int iDANodeIndex
);
-static BOOL s_bHandleRxEncryption(
+static bool s_bHandleRxEncryption(
PSDevice pDevice,
- PBYTE pbyFrame,
- UINT FrameSize,
- PBYTE pbyRsr,
- PBYTE pbyNewRsr,
+ unsigned char *pbyFrame,
+ unsigned int FrameSize,
+ unsigned char *pbyRsr,
+ unsigned char *pbyNewRsr,
PSKeyItem *pKeyOut,
- int * pbExtIV,
- PWORD pwRxTSC15_0,
- PDWORD pdwRxTSC47_16
+ bool *pbExtIV,
+ unsigned short *pwRxTSC15_0,
+ unsigned long *pdwRxTSC47_16
);
-static BOOL s_bHostWepRxEncryption(
+static bool s_bHostWepRxEncryption(
PSDevice pDevice,
- PBYTE pbyFrame,
- UINT FrameSize,
- PBYTE pbyRsr,
- BOOL bOnFly,
+ unsigned char *pbyFrame,
+ unsigned int FrameSize,
+ unsigned char *pbyRsr,
+ bool bOnFly,
PSKeyItem pKey,
- PBYTE pbyNewRsr,
- int * pbExtIV,
- PWORD pwRxTSC15_0,
- PDWORD pdwRxTSC47_16
+ unsigned char *pbyNewRsr,
+ bool *pbExtIV,
+ unsigned short *pwRxTSC15_0,
+ unsigned long *pdwRxTSC47_16
);
@@ -162,27 +152,21 @@ static BOOL s_bHostWepRxEncryption(
* Return Value: None
*
-*/
-static
-void
-s_vProcessRxMACHeader (
- PSDevice pDevice,
- PBYTE pbyRxBufferAddr,
- UINT cbPacketSize,
- BOOL bIsWEP,
- BOOL bExtIV,
- PUINT pcbHeadSize
- )
+static void
+s_vProcessRxMACHeader(PSDevice pDevice, unsigned char *pbyRxBufferAddr,
+ unsigned int cbPacketSize, bool bIsWEP, bool bExtIV,
+ unsigned int *pcbHeadSize)
{
- PBYTE pbyRxBuffer;
- UINT cbHeaderSize = 0;
- PWORD pwType;
+ unsigned char *pbyRxBuffer;
+ unsigned int cbHeaderSize = 0;
+ unsigned short *pwType;
PS802_11Header pMACHeader;
int ii;
pMACHeader = (PS802_11Header) (pbyRxBufferAddr + cbHeaderSize);
- s_vGetDASA((PBYTE)pMACHeader, &cbHeaderSize, &pDevice->sRxEthHeader);
+ s_vGetDASA((unsigned char *)pMACHeader, &cbHeaderSize, &pDevice->sRxEthHeader);
if (bIsWEP) {
if (bExtIV) {
@@ -197,18 +181,18 @@ s_vProcessRxMACHeader (
cbHeaderSize += WLAN_HDR_ADDR3_LEN;
};
- pbyRxBuffer = (PBYTE) (pbyRxBufferAddr + cbHeaderSize);
- if (IS_ETH_ADDRESS_EQUAL(pbyRxBuffer, &pDevice->abySNAP_Bridgetunnel[0])) {
+ pbyRxBuffer = (unsigned char *) (pbyRxBufferAddr + cbHeaderSize);
+ if (!compare_ether_addr(pbyRxBuffer, &pDevice->abySNAP_Bridgetunnel[0])) {
cbHeaderSize += 6;
}
- else if (IS_ETH_ADDRESS_EQUAL(pbyRxBuffer, &pDevice->abySNAP_RFC1042[0])) {
+ else if (!compare_ether_addr(pbyRxBuffer, &pDevice->abySNAP_RFC1042[0])) {
cbHeaderSize += 6;
- pwType = (PWORD) (pbyRxBufferAddr + cbHeaderSize);
+ pwType = (unsigned short *) (pbyRxBufferAddr + cbHeaderSize);
if ((*pwType!= TYPE_PKT_IPX) && (*pwType != cpu_to_le16(0xF380))) {
}
else {
cbHeaderSize -= 8;
- pwType = (PWORD) (pbyRxBufferAddr + cbHeaderSize);
+ pwType = (unsigned short *) (pbyRxBufferAddr + cbHeaderSize);
if (bIsWEP) {
if (bExtIV) {
*pwType = htons(cbPacketSize - WLAN_HDR_ADDR3_LEN - 8); // 8 is IV&ExtIV
@@ -223,7 +207,7 @@ s_vProcessRxMACHeader (
}
else {
cbHeaderSize -= 2;
- pwType = (PWORD) (pbyRxBufferAddr + cbHeaderSize);
+ pwType = (unsigned short *) (pbyRxBufferAddr + cbHeaderSize);
if (bIsWEP) {
if (bExtIV) {
*pwType = htons(cbPacketSize - WLAN_HDR_ADDR3_LEN - 8); // 8 is IV&ExtIV
@@ -237,7 +221,7 @@ s_vProcessRxMACHeader (
}
cbHeaderSize -= (ETH_ALEN * 2);
- pbyRxBuffer = (PBYTE) (pbyRxBufferAddr + cbHeaderSize);
+ pbyRxBuffer = (unsigned char *) (pbyRxBufferAddr + cbHeaderSize);
for(ii=0;ii<ETH_ALEN;ii++)
*pbyRxBuffer++ = pDevice->sRxEthHeader.abyDstAddr[ii];
for(ii=0;ii<ETH_ALEN;ii++)
@@ -249,9 +233,9 @@ s_vProcessRxMACHeader (
-static BYTE s_byGetRateIdx (BYTE byRate)
+static unsigned char s_byGetRateIdx (unsigned char byRate)
{
- BYTE byRateIdx;
+ unsigned char byRateIdx;
for (byRateIdx = 0; byRateIdx <MAX_RATE ; byRateIdx++) {
if (acbyRxRate[byRateIdx%MAX_RATE] == byRate)
@@ -261,15 +245,11 @@ static BYTE s_byGetRateIdx (BYTE byRate)
}
-static
-void
-s_vGetDASA (
- PBYTE pbyRxBufferAddr,
- PUINT pcbHeaderSize,
- PSEthernetHeader psEthHeader
- )
+static void
+s_vGetDASA(unsigned char *pbyRxBufferAddr, unsigned int *pcbHeaderSize,
+ PSEthernetHeader psEthHeader)
{
- UINT cbHeaderSize = 0;
+ unsigned int cbHeaderSize = 0;
PS802_11Header pMACHeader;
int ii;
@@ -333,7 +313,7 @@ void MngWorkItem(void *Context)
-BOOL
+bool
device_receive_frame (
PSDevice pDevice,
PSRxDesc pCurrRD
@@ -349,36 +329,36 @@ device_receive_frame (
PSMgmtObject pMgmt = pDevice->pMgmt;
PSRxMgmtPacket pRxPacket = &(pDevice->pMgmt->sRxPacket);
PS802_11Header p802_11Header;
- PBYTE pbyRsr;
- PBYTE pbyNewRsr;
- PBYTE pbyRSSI;
+ unsigned char *pbyRsr;
+ unsigned char *pbyNewRsr;
+ unsigned char *pbyRSSI;
PQWORD pqwTSFTime;
- PWORD pwFrameSize;
- PBYTE pbyFrame;
- BOOL bDeFragRx = FALSE;
- BOOL bIsWEP = FALSE;
- UINT cbHeaderOffset;
- UINT FrameSize;
- WORD wEtherType = 0;
- INT iSANodeIndex = -1;
- INT iDANodeIndex = -1;
- UINT ii;
- UINT cbIVOffset;
- BOOL bExtIV = FALSE;
- PBYTE pbyRxSts;
- PBYTE pbyRxRate;
- PBYTE pbySQ;
- UINT cbHeaderSize;
+ unsigned short *pwFrameSize;
+ unsigned char *pbyFrame;
+ bool bDeFragRx = false;
+ bool bIsWEP = false;
+ unsigned int cbHeaderOffset;
+ unsigned int FrameSize;
+ unsigned short wEtherType = 0;
+ int iSANodeIndex = -1;
+ int iDANodeIndex = -1;
+ unsigned int ii;
+ unsigned int cbIVOffset;
+ bool bExtIV = false;
+ unsigned char *pbyRxSts;
+ unsigned char *pbyRxRate;
+ unsigned char *pbySQ;
+ unsigned int cbHeaderSize;
PSKeyItem pKey = NULL;
- WORD wRxTSC15_0 = 0;
- DWORD dwRxTSC47_16 = 0;
+ unsigned short wRxTSC15_0 = 0;
+ unsigned long dwRxTSC47_16 = 0;
SKeyItem STempKey;
// 802.11h RPI
- DWORD dwDuration = 0;
- LONG ldBm = 0;
- LONG ldBmThreshold = 0;
+ unsigned long dwDuration = 0;
+ long ldBm = 0;
+ long ldBmThreshold = 0;
PS802_11Header pMACHeader;
- BOOL bRxeapol_key = FALSE;
+ bool bRxeapol_key = false;
// DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"---------- device_receive_frame---\n");
@@ -391,7 +371,7 @@ device_receive_frame (
pDevice->rx_buf_sz, PCI_DMA_FROMDEVICE);
#endif
//PLICE_DEBUG<-
- pwFrameSize = (PWORD)(skb->data + 2);
+ pwFrameSize = (unsigned short *)(skb->data + 2);
FrameSize = cpu_to_le16(pCurrRD->m_rd1RD1.wReqCount) - cpu_to_le16(pCurrRD->m_rd0RD0.wResCount);
// Max: 2312Payload + 30HD +4CRC + 2Padding + 4Len + 8TSF + 4RSR
@@ -399,17 +379,17 @@ device_receive_frame (
if ((FrameSize > 2364)||(FrameSize <= 32)) {
// Frame Size error drop this packet.
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"---------- WRONG Length 1 \n");
- return FALSE;
+ return false;
}
- pbyRxSts = (PBYTE) (skb->data);
- pbyRxRate = (PBYTE) (skb->data + 1);
- pbyRsr = (PBYTE) (skb->data + FrameSize - 1);
- pbyRSSI = (PBYTE) (skb->data + FrameSize - 2);
- pbyNewRsr = (PBYTE) (skb->data + FrameSize - 3);
- pbySQ = (PBYTE) (skb->data + FrameSize - 4);
+ pbyRxSts = (unsigned char *) (skb->data);
+ pbyRxRate = (unsigned char *) (skb->data + 1);
+ pbyRsr = (unsigned char *) (skb->data + FrameSize - 1);
+ pbyRSSI = (unsigned char *) (skb->data + FrameSize - 2);
+ pbyNewRsr = (unsigned char *) (skb->data + FrameSize - 3);
+ pbySQ = (unsigned char *) (skb->data + FrameSize - 4);
pqwTSFTime = (PQWORD) (skb->data + FrameSize - 12);
- pbyFrame = (PBYTE)(skb->data + 4);
+ pbyFrame = (unsigned char *)(skb->data + 4);
// get packet size
FrameSize = cpu_to_le16(*pwFrameSize);
@@ -417,7 +397,7 @@ device_receive_frame (
if ((FrameSize > 2346)|(FrameSize < 14)) { // Max: 2312Payload + 30HD +4CRC
// Min: 14 bytes ACK
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"---------- WRONG Length 2 \n");
- return FALSE;
+ return false;
}
//PLICE_DEBUG->
#if 1
@@ -431,9 +411,9 @@ device_receive_frame (
#endif
- pMACHeader=(PS802_11Header)((PBYTE) (skb->data)+8);
+ pMACHeader=(PS802_11Header)((unsigned char *) (skb->data)+8);
//PLICE_DEBUG<-
- if (pDevice->bMeasureInProgress == TRUE) {
+ if (pDevice->bMeasureInProgress == true) {
if ((*pbyRsr & RSR_CRCOK) != 0) {
pDevice->byBasicMap |= 0x01;
}
@@ -460,13 +440,13 @@ device_receive_frame (
ii--;
}
pDevice->dwRPIs[ii] += dwDuration;
- return FALSE;
+ return false;
}
- if (!IS_MULTICAST_ADDRESS(pbyFrame) && !IS_BROADCAST_ADDRESS(pbyFrame)) {
+ if (!is_multicast_ether_addr(pbyFrame)) {
if (WCTLbIsDuplicate(&(pDevice->sDupRxCache), (PS802_11Header) (skb->data + 4))) {
pDevice->s802_11Counter.FrameDuplicateCount++;
- return FALSE;
+ return false;
}
}
@@ -475,14 +455,14 @@ device_receive_frame (
s_vGetDASA(skb->data+4, &cbHeaderSize, &pDevice->sRxEthHeader);
// filter packet send from myself
- if (IS_ETH_ADDRESS_EQUAL((PBYTE)&(pDevice->sRxEthHeader.abySrcAddr[0]), pDevice->abyCurrentNetAddr))
- return FALSE;
+ if (!compare_ether_addr((unsigned char *)&(pDevice->sRxEthHeader.abySrcAddr[0]), pDevice->abyCurrentNetAddr))
+ return false;
if ((pMgmt->eCurrMode == WMAC_MODE_ESS_AP) || (pMgmt->eCurrMode == WMAC_MODE_IBSS_STA)) {
if (IS_CTL_PSPOLL(pbyFrame) || !IS_TYPE_CONTROL(pbyFrame)) {
p802_11Header = (PS802_11Header) (pbyFrame);
// get SA NodeIndex
- if (BSSDBbIsSTAInNodeDB(pMgmt, (PBYTE)(p802_11Header->abyAddr2), &iSANodeIndex)) {
+ if (BSSDBbIsSTAInNodeDB(pMgmt, (unsigned char *)(p802_11Header->abyAddr2), &iSANodeIndex)) {
pMgmt->sNodeDBTable[iSANodeIndex].ulLastRxJiffer = jiffies;
pMgmt->sNodeDBTable[iSANodeIndex].uInActiveCount = 0;
}
@@ -490,17 +470,17 @@ device_receive_frame (
}
if (pMgmt->eCurrMode == WMAC_MODE_ESS_AP) {
- if (s_bAPModeRxCtl(pDevice, pbyFrame, iSANodeIndex) == TRUE) {
- return FALSE;
+ if (s_bAPModeRxCtl(pDevice, pbyFrame, iSANodeIndex) == true) {
+ return false;
}
}
if (IS_FC_WEP(pbyFrame)) {
- BOOL bRxDecryOK = FALSE;
+ bool bRxDecryOK = false;
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"rx WEP pkt\n");
- bIsWEP = TRUE;
+ bIsWEP = true;
if ((pDevice->bEnableHostWEP) && (iSANodeIndex >= 0)) {
pKey = &STempKey;
pKey->byCipherSuite = pMgmt->sNodeDBTable[iSANodeIndex].byCipherSuite;
@@ -552,11 +532,11 @@ device_receive_frame (
// pDevice->s802_11Counter.WEPICVErrorCount.QuadPart++;
}
}
- return FALSE;
+ return false;
}
} else {
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"WEP Func Fail\n");
- return FALSE;
+ return false;
}
if ((pKey != NULL) && (pKey->byCipherSuite == KEY_CTL_CCMP))
FrameSize -= 8; // Message Integrity Code
@@ -584,18 +564,18 @@ device_receive_frame (
}
else {
- return FALSE;
+ return false;
}
}
// Management & Control frame Handle
- if ((IS_TYPE_DATA((skb->data+4))) == FALSE) {
+ if ((IS_TYPE_DATA((skb->data+4))) == false) {
// Handle Control & Manage Frame
if (IS_TYPE_MGMT((skb->data+4))) {
- PBYTE pbyData1;
- PBYTE pbyData2;
+ unsigned char *pbyData1;
+ unsigned char *pbyData2;
pRxPacket->p80211Header = (PUWLAN_80211HDR)(skb->data+4);
pRxPacket->cbMPDULen = FrameSize;
@@ -649,13 +629,13 @@ device_receive_frame (
skb->protocol = htons(ETH_P_802_2);
memset(skb->cb, 0, sizeof(skb->cb));
netif_rx(skb);
- return TRUE;
+ return true;
}
}
else {
// Control Frame
};
- return FALSE;
+ return false;
}
else {
if (pMgmt->eCurrMode == WMAC_MODE_ESS_AP) {
@@ -667,12 +647,12 @@ device_receive_frame (
pDevice->dev->name);
}
}
- return FALSE;
+ return false;
}
}
else {
// discard DATA packet while not associate || BSSID error
- if ((pDevice->bLinkPass == FALSE) ||
+ if ((pDevice->bLinkPass == false) ||
!(*pbyRsr & RSR_BSSIDOK)) {
if (bDeFragRx) {
if (!device_alloc_frag_buf(pDevice, &pDevice->sRxDFCB[pDevice->uCurrentDFCBIdx])) {
@@ -680,12 +660,12 @@ device_receive_frame (
pDevice->dev->name);
}
}
- return FALSE;
+ return false;
}
//mike add:station mode check eapol-key challenge--->
{
- BYTE Protocol_Version; //802.1x Authentication
- BYTE Packet_Type; //802.1x Authentication
+ unsigned char Protocol_Version; //802.1x Authentication
+ unsigned char Packet_Type; //802.1x Authentication
if (bIsWEP)
cbIVOffset = 8;
else
@@ -697,7 +677,7 @@ device_receive_frame (
if (wEtherType == ETH_P_PAE) { //Protocol Type in LLC-Header
if(((Protocol_Version==1) ||(Protocol_Version==2)) &&
(Packet_Type==3)) { //802.1x OR eapol-key challenge frame receive
- bRxeapol_key = TRUE;
+ bRxeapol_key = true;
}
}
}
@@ -716,8 +696,8 @@ device_receive_frame (
}
}
else {
- if (pDevice->pMgmt->bInTIMWake == TRUE) {
- pDevice->pMgmt->bInTIMWake = FALSE;
+ if (pDevice->pMgmt->bInTIMWake == true) {
+ pDevice->pMgmt->bInTIMWake = false;
}
}
};
@@ -725,7 +705,7 @@ device_receive_frame (
// Now it only supports 802.11g Infrastructure Mode, and support rate must up to 54 Mbps
if (pDevice->bDiversityEnable && (FrameSize>50) &&
(pDevice->eOPMode == OP_MODE_INFRASTRUCTURE) &&
- (pDevice->bLinkPass == TRUE)) {
+ (pDevice->bLinkPass == true)) {
//printk("device_receive_frame: RxRate is %d\n",*pbyRxRate);
BBvAntennaDiversity(pDevice, s_byGetRateIdx(*pbyRxRate), 0);
}
@@ -752,8 +732,8 @@ device_receive_frame (
// -----------------------------------------------
- if ((pMgmt->eCurrMode == WMAC_MODE_ESS_AP) && (pDevice->bEnable8021x == TRUE)){
- BYTE abyMacHdr[24];
+ if ((pMgmt->eCurrMode == WMAC_MODE_ESS_AP) && (pDevice->bEnable8021x == true)){
+ unsigned char abyMacHdr[24];
// Only 802.1x packet incoming allowed
if (bIsWEP)
@@ -767,7 +747,7 @@ device_receive_frame (
if (wEtherType == ETH_P_PAE) {
skb->dev = pDevice->apdev;
- if (bIsWEP == TRUE) {
+ if (bIsWEP == true) {
// strip IV header(8)
memcpy(&abyMacHdr[0], (skb->data + 4), 24);
memcpy((skb->data + 4 + cbIVOffset), &abyMacHdr[0], 24);
@@ -781,12 +761,12 @@ device_receive_frame (
skb->protocol = htons(ETH_P_802_2);
memset(skb->cb, 0, sizeof(skb->cb));
netif_rx(skb);
- return TRUE;
+ return true;
}
// check if 802.1x authorized
if (!(pMgmt->sNodeDBTable[iSANodeIndex].dwFlags & WLAN_STA_AUTHORIZED))
- return FALSE;
+ return false;
}
@@ -800,53 +780,53 @@ device_receive_frame (
// Soft MIC
if ((pKey != NULL) && (pKey->byCipherSuite == KEY_CTL_TKIP)) {
if (bIsWEP) {
- PDWORD pdwMIC_L;
- PDWORD pdwMIC_R;
- DWORD dwMIC_Priority;
- DWORD dwMICKey0 = 0, dwMICKey1 = 0;
- DWORD dwLocalMIC_L = 0;
- DWORD dwLocalMIC_R = 0;
+ unsigned long *pdwMIC_L;
+ unsigned long *pdwMIC_R;
+ unsigned long dwMIC_Priority;
+ unsigned long dwMICKey0 = 0, dwMICKey1 = 0;
+ unsigned long dwLocalMIC_L = 0;
+ unsigned long dwLocalMIC_R = 0;
viawget_wpa_header *wpahdr;
if (pMgmt->eCurrMode == WMAC_MODE_ESS_AP) {
- dwMICKey0 = cpu_to_le32(*(PDWORD)(&pKey->abyKey[24]));
- dwMICKey1 = cpu_to_le32(*(PDWORD)(&pKey->abyKey[28]));
+ dwMICKey0 = cpu_to_le32(*(unsigned long *)(&pKey->abyKey[24]));
+ dwMICKey1 = cpu_to_le32(*(unsigned long *)(&pKey->abyKey[28]));
}
else {
if (pDevice->pMgmt->eAuthenMode == WMAC_AUTH_WPANONE) {
- dwMICKey0 = cpu_to_le32(*(PDWORD)(&pKey->abyKey[16]));
- dwMICKey1 = cpu_to_le32(*(PDWORD)(&pKey->abyKey[20]));
+ dwMICKey0 = cpu_to_le32(*(unsigned long *)(&pKey->abyKey[16]));
+ dwMICKey1 = cpu_to_le32(*(unsigned long *)(&pKey->abyKey[20]));
} else if ((pKey->dwKeyIndex & BIT28) == 0) {
- dwMICKey0 = cpu_to_le32(*(PDWORD)(&pKey->abyKey[16]));
- dwMICKey1 = cpu_to_le32(*(PDWORD)(&pKey->abyKey[20]));
+ dwMICKey0 = cpu_to_le32(*(unsigned long *)(&pKey->abyKey[16]));
+ dwMICKey1 = cpu_to_le32(*(unsigned long *)(&pKey->abyKey[20]));
} else {
- dwMICKey0 = cpu_to_le32(*(PDWORD)(&pKey->abyKey[24]));
- dwMICKey1 = cpu_to_le32(*(PDWORD)(&pKey->abyKey[28]));
+ dwMICKey0 = cpu_to_le32(*(unsigned long *)(&pKey->abyKey[24]));
+ dwMICKey1 = cpu_to_le32(*(unsigned long *)(&pKey->abyKey[28]));
}
}
MIC_vInit(dwMICKey0, dwMICKey1);
- MIC_vAppend((PBYTE)&(pDevice->sRxEthHeader.abyDstAddr[0]), 12);
+ MIC_vAppend((unsigned char *)&(pDevice->sRxEthHeader.abyDstAddr[0]), 12);
dwMIC_Priority = 0;
- MIC_vAppend((PBYTE)&dwMIC_Priority, 4);
+ MIC_vAppend((unsigned char *)&dwMIC_Priority, 4);
// 4 is Rcv buffer header, 24 is MAC Header, and 8 is IV and Ext IV.
- MIC_vAppend((PBYTE)(skb->data + 4 + WLAN_HDR_ADDR3_LEN + 8),
+ MIC_vAppend((unsigned char *)(skb->data + 4 + WLAN_HDR_ADDR3_LEN + 8),
FrameSize - WLAN_HDR_ADDR3_LEN - 8);
MIC_vGetMIC(&dwLocalMIC_L, &dwLocalMIC_R);
MIC_vUnInit();
- pdwMIC_L = (PDWORD)(skb->data + 4 + FrameSize);
- pdwMIC_R = (PDWORD)(skb->data + 4 + FrameSize + 4);
+ pdwMIC_L = (unsigned long *)(skb->data + 4 + FrameSize);
+ pdwMIC_R = (unsigned long *)(skb->data + 4 + FrameSize + 4);
//DBG_PRN_GRP12(("RxL: %lx, RxR: %lx\n", *pdwMIC_L, *pdwMIC_R));
//DBG_PRN_GRP12(("LocalL: %lx, LocalR: %lx\n", dwLocalMIC_L, dwLocalMIC_R));
//DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"dwMICKey0= %lx,dwMICKey1= %lx \n", dwMICKey0, dwMICKey1);
if ((cpu_to_le32(*pdwMIC_L) != dwLocalMIC_L) || (cpu_to_le32(*pdwMIC_R) != dwLocalMIC_R) ||
- (pDevice->bRxMICFail == TRUE)) {
+ (pDevice->bRxMICFail == true)) {
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"MIC comparison is fail!\n");
- pDevice->bRxMICFail = FALSE;
+ pDevice->bRxMICFail = false;
//pDevice->s802_11Counter.TKIPLocalMICFailures.QuadPart++;
pDevice->s802_11Counter.TKIPLocalMICFailures++;
if (bDeFragRx) {
@@ -858,7 +838,7 @@ device_receive_frame (
//2008-0409-07, <Add> by Einsn Liu
#ifdef WPA_SUPPLICANT_DRIVER_WEXT_SUPPORT
//send event to wpa_supplicant
- //if(pDevice->bWPADevEnable == TRUE)
+ //if(pDevice->bWPADevEnable == true)
{
union iwreq_data wrqu;
struct iw_michaelmicfailure ev;
@@ -906,7 +886,7 @@ device_receive_frame (
pDevice->skb = dev_alloc_skb((int)pDevice->rx_buf_sz);
};
- return FALSE;
+ return false;
}
}
@@ -917,13 +897,13 @@ device_receive_frame (
if ((pKey != NULL) && ((pKey->byCipherSuite == KEY_CTL_TKIP) ||
(pKey->byCipherSuite == KEY_CTL_CCMP))) {
if (bIsWEP) {
- WORD wLocalTSC15_0 = 0;
- DWORD dwLocalTSC47_16 = 0;
- ULONGLONG RSC = 0;
+ unsigned short wLocalTSC15_0 = 0;
+ unsigned long dwLocalTSC47_16 = 0;
+ unsigned long long RSC = 0;
// endian issues
- RSC = *((ULONGLONG *) &(pKey->KeyRSC));
- wLocalTSC15_0 = (WORD) RSC;
- dwLocalTSC47_16 = (DWORD) (RSC>>16);
+ RSC = *((unsigned long long *) &(pKey->KeyRSC));
+ wLocalTSC15_0 = (unsigned short) RSC;
+ dwLocalTSC47_16 = (unsigned long) (RSC>>16);
RSC = dwRxTSC47_16;
RSC <<= 16;
@@ -950,7 +930,7 @@ device_receive_frame (
pDevice->dev->name);
}
}
- return FALSE;
+ return false;
}
}
}
@@ -963,13 +943,13 @@ device_receive_frame (
}
- s_vProcessRxMACHeader(pDevice, (PBYTE)(skb->data+4), FrameSize, bIsWEP, bExtIV, &cbHeaderOffset);
+ s_vProcessRxMACHeader(pDevice, (unsigned char *)(skb->data+4), FrameSize, bIsWEP, bExtIV, &cbHeaderOffset);
FrameSize -= cbHeaderOffset;
cbHeaderOffset += 4; // 4 is Rcv buffer header
// Null data, framesize = 14
if (FrameSize < 15)
- return FALSE;
+ return false;
if (pMgmt->eCurrMode == WMAC_MODE_ESS_AP) {
if (s_bAPModeRxData(pDevice,
@@ -978,7 +958,7 @@ device_receive_frame (
cbHeaderOffset,
iSANodeIndex,
iDANodeIndex
- ) == FALSE) {
+ ) == false) {
if (bDeFragRx) {
if (!device_alloc_frag_buf(pDevice, &pDevice->sRxDFCB[pDevice->uCurrentDFCBIdx])) {
@@ -986,10 +966,10 @@ device_receive_frame (
pDevice->dev->name);
}
}
- return FALSE;
+ return false;
}
-// if(pDevice->bRxMICFail == FALSE) {
+// if(pDevice->bRxMICFail == false) {
// for (ii =0; ii < 100; ii++)
// printk(" %02x", *(skb->data + ii));
// printk("\n");
@@ -1016,7 +996,7 @@ device_receive_frame (
pDevice->dev->name);
}
}
- return FALSE;
+ return false;
}
}
*/
@@ -1031,17 +1011,17 @@ device_receive_frame (
DBG_PRT(MSG_LEVEL_ERR,KERN_ERR "%s: can not alloc more frag bufs\n",
pDevice->dev->name);
}
- return FALSE;
+ return false;
}
- return TRUE;
+ return true;
}
-static BOOL s_bAPModeRxCtl (
+static bool s_bAPModeRxCtl (
PSDevice pDevice,
- PBYTE pbyFrame,
- INT iSANodeIndex
+ unsigned char *pbyFrame,
+ int iSANodeIndex
)
{
PS802_11Header p802_11Header;
@@ -1063,30 +1043,30 @@ static BOOL s_bAPModeRxCtl (
// reason = (6) class 2 received from nonauth sta
vMgrDeAuthenBeginSta(pDevice,
pMgmt,
- (PBYTE)(p802_11Header->abyAddr2),
+ (unsigned char *)(p802_11Header->abyAddr2),
(WLAN_MGMT_REASON_CLASS2_NONAUTH),
&Status
);
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "dpc: send vMgrDeAuthenBeginSta 1\n");
- return TRUE;
+ return true;
};
if (pMgmt->sNodeDBTable[iSANodeIndex].eNodeState < NODE_ASSOC) {
// send deassoc notification
// reason = (7) class 3 received from nonassoc sta
vMgrDisassocBeginSta(pDevice,
pMgmt,
- (PBYTE)(p802_11Header->abyAddr2),
+ (unsigned char *)(p802_11Header->abyAddr2),
(WLAN_MGMT_REASON_CLASS3_NONASSOC),
&Status
);
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "dpc: send vMgrDisassocBeginSta 2\n");
- return TRUE;
+ return true;
};
if (pMgmt->sNodeDBTable[iSANodeIndex].bPSEnable) {
// delcare received ps-poll event
if (IS_CTL_PSPOLL(pbyFrame)) {
- pMgmt->sNodeDBTable[iSANodeIndex].bRxPSPoll = TRUE;
+ pMgmt->sNodeDBTable[iSANodeIndex].bRxPSPoll = true;
bScheduleCommand((void *)pDevice, WLAN_CMD_RX_PSPOLL, NULL);
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "dpc: WLAN_CMD_RX_PSPOLL 1\n");
}
@@ -1094,8 +1074,8 @@ static BOOL s_bAPModeRxCtl (
// check Data PS state
// if PW bit off, send out all PS bufferring packets.
if (!IS_FC_POWERMGT(pbyFrame)) {
- pMgmt->sNodeDBTable[iSANodeIndex].bPSEnable = FALSE;
- pMgmt->sNodeDBTable[iSANodeIndex].bRxPSPoll = TRUE;
+ pMgmt->sNodeDBTable[iSANodeIndex].bPSEnable = false;
+ pMgmt->sNodeDBTable[iSANodeIndex].bRxPSPoll = true;
bScheduleCommand((void *)pDevice, WLAN_CMD_RX_PSPOLL, NULL);
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "dpc: WLAN_CMD_RX_PSPOLL 2\n");
}
@@ -1103,15 +1083,15 @@ static BOOL s_bAPModeRxCtl (
}
else {
if (IS_FC_POWERMGT(pbyFrame)) {
- pMgmt->sNodeDBTable[iSANodeIndex].bPSEnable = TRUE;
+ pMgmt->sNodeDBTable[iSANodeIndex].bPSEnable = true;
// Once if STA in PS state, enable multicast bufferring
- pMgmt->sNodeDBTable[0].bPSEnable = TRUE;
+ pMgmt->sNodeDBTable[0].bPSEnable = true;
}
else {
// clear all pending PS frame.
if (pMgmt->sNodeDBTable[iSANodeIndex].wEnQueueCnt > 0) {
- pMgmt->sNodeDBTable[iSANodeIndex].bPSEnable = FALSE;
- pMgmt->sNodeDBTable[iSANodeIndex].bRxPSPoll = TRUE;
+ pMgmt->sNodeDBTable[iSANodeIndex].bPSEnable = false;
+ pMgmt->sNodeDBTable[iSANodeIndex].bRxPSPoll = true;
bScheduleCommand((void *)pDevice, WLAN_CMD_RX_PSPOLL, NULL);
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "dpc: WLAN_CMD_RX_PSPOLL 3\n");
@@ -1122,7 +1102,7 @@ static BOOL s_bAPModeRxCtl (
else {
vMgrDeAuthenBeginSta(pDevice,
pMgmt,
- (PBYTE)(p802_11Header->abyAddr2),
+ (unsigned char *)(p802_11Header->abyAddr2),
(WLAN_MGMT_REASON_CLASS2_NONAUTH),
&Status
);
@@ -1154,31 +1134,31 @@ static BOOL s_bAPModeRxCtl (
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "dpc: wFrameCtl= %x\n", p802_11Header->wFrameCtl );
VNSvInPortB(pDevice->PortOffset + MAC_REG_RCR, &(pDevice->byRxMode));
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "dpc:pDevice->byRxMode = %x\n", pDevice->byRxMode );
- return TRUE;
+ return true;
}
}
}
- return FALSE;
+ return false;
}
-static BOOL s_bHandleRxEncryption (
+static bool s_bHandleRxEncryption (
PSDevice pDevice,
- PBYTE pbyFrame,
- UINT FrameSize,
- PBYTE pbyRsr,
- PBYTE pbyNewRsr,
+ unsigned char *pbyFrame,
+ unsigned int FrameSize,
+ unsigned char *pbyRsr,
+ unsigned char *pbyNewRsr,
PSKeyItem *pKeyOut,
- int * pbExtIV,
- PWORD pwRxTSC15_0,
- PDWORD pdwRxTSC47_16
+ bool *pbExtIV,
+ unsigned short *pwRxTSC15_0,
+ unsigned long *pdwRxTSC47_16
)
{
- UINT PayloadLen = FrameSize;
- PBYTE pbyIV;
- BYTE byKeyIdx;
+ unsigned int PayloadLen = FrameSize;
+ unsigned char *pbyIV;
+ unsigned char byKeyIdx;
PSKeyItem pKey = NULL;
- BYTE byDecMode = KEY_CTL_WEP;
+ unsigned char byDecMode = KEY_CTL_WEP;
PSMgmtObject pMgmt = pDevice->pMgmt;
@@ -1186,8 +1166,8 @@ static BOOL s_bHandleRxEncryption (
*pdwRxTSC47_16 = 0;
pbyIV = pbyFrame + WLAN_HDR_ADDR3_LEN;
- if ( WLAN_GET_FC_TODS(*(PWORD)pbyFrame) &&
- WLAN_GET_FC_FROMDS(*(PWORD)pbyFrame) ) {
+ if ( WLAN_GET_FC_TODS(*(unsigned short *)pbyFrame) &&
+ WLAN_GET_FC_FROMDS(*(unsigned short *)pbyFrame) ) {
pbyIV += 6; // 6 is 802.11 address4
PayloadLen -= 6;
}
@@ -1204,7 +1184,7 @@ static BOOL s_bHandleRxEncryption (
(pDevice->pMgmt->byCSSPK != KEY_CTL_NONE)) {
// unicast pkt use pairwise key
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"unicast pkt\n");
- if (KeybGetKey(&(pDevice->sKey), pDevice->abyBSSID, 0xFFFFFFFF, &pKey) == TRUE) {
+ if (KeybGetKey(&(pDevice->sKey), pDevice->abyBSSID, 0xFFFFFFFF, &pKey) == true) {
if (pDevice->pMgmt->byCSSPK == KEY_CTL_TKIP)
byDecMode = KEY_CTL_TKIP;
else if (pDevice->pMgmt->byCSSPK == KEY_CTL_CCMP)
@@ -1238,24 +1218,24 @@ static BOOL s_bHandleRxEncryption (
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"pKey == NULL\n");
if (byDecMode == KEY_CTL_WEP) {
// pDevice->s802_11Counter.WEPUndecryptableCount.QuadPart++;
- } else if (pDevice->bLinkPass == TRUE) {
+ } else if (pDevice->bLinkPass == true) {
// pDevice->s802_11Counter.DecryptFailureCount.QuadPart++;
}
- return FALSE;
+ return false;
}
if (byDecMode != pKey->byCipherSuite) {
if (byDecMode == KEY_CTL_WEP) {
// pDevice->s802_11Counter.WEPUndecryptableCount.QuadPart++;
- } else if (pDevice->bLinkPass == TRUE) {
+ } else if (pDevice->bLinkPass == true) {
// pDevice->s802_11Counter.DecryptFailureCount.QuadPart++;
}
*pKeyOut = NULL;
- return FALSE;
+ return false;
}
if (byDecMode == KEY_CTL_WEP) {
// handle WEP
if ((pDevice->byLocalID <= REV_ID_VT3253_A1) ||
- (((PSKeyTable)(pKey->pvKeyTable))->bSoftWEP == TRUE)) {
+ (((PSKeyTable)(pKey->pvKeyTable))->bSoftWEP == true)) {
// Software WEP
// 1. 3253A
// 2. WEP 256
@@ -1275,12 +1255,12 @@ static BOOL s_bHandleRxEncryption (
// TKIP/AES
PayloadLen -= (WLAN_HDR_ADDR3_LEN + 8 + 4); // 24 is 802.11 header, 8 is IV&ExtIV, 4 is crc
- *pdwRxTSC47_16 = cpu_to_le32(*(PDWORD)(pbyIV + 4));
+ *pdwRxTSC47_16 = cpu_to_le32(*(unsigned long *)(pbyIV + 4));
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"ExtIV: %lx\n",*pdwRxTSC47_16);
if (byDecMode == KEY_CTL_TKIP) {
*pwRxTSC15_0 = cpu_to_le16(MAKEWORD(*(pbyIV+2), *pbyIV));
} else {
- *pwRxTSC15_0 = cpu_to_le16(*(PWORD)pbyIV);
+ *pwRxTSC15_0 = cpu_to_le16(*(unsigned short *)pbyIV);
}
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"TSC0_15: %x\n", *pwRxTSC15_0);
@@ -1303,28 +1283,28 @@ static BOOL s_bHandleRxEncryption (
}// end of TKIP/AES
if ((*(pbyIV+3) & 0x20) != 0)
- *pbExtIV = TRUE;
- return TRUE;
+ *pbExtIV = true;
+ return true;
}
-static BOOL s_bHostWepRxEncryption (
+static bool s_bHostWepRxEncryption (
PSDevice pDevice,
- PBYTE pbyFrame,
- UINT FrameSize,
- PBYTE pbyRsr,
- BOOL bOnFly,
+ unsigned char *pbyFrame,
+ unsigned int FrameSize,
+ unsigned char *pbyRsr,
+ bool bOnFly,
PSKeyItem pKey,
- PBYTE pbyNewRsr,
- int * pbExtIV,
- PWORD pwRxTSC15_0,
- PDWORD pdwRxTSC47_16
+ unsigned char *pbyNewRsr,
+ bool *pbExtIV,
+ unsigned short *pwRxTSC15_0,
+ unsigned long *pdwRxTSC47_16
)
{
- UINT PayloadLen = FrameSize;
- PBYTE pbyIV;
- BYTE byKeyIdx;
- BYTE byDecMode = KEY_CTL_WEP;
+ unsigned int PayloadLen = FrameSize;
+ unsigned char *pbyIV;
+ unsigned char byKeyIdx;
+ unsigned char byDecMode = KEY_CTL_WEP;
PS802_11Header pMACHeader;
@@ -1333,8 +1313,8 @@ static BOOL s_bHostWepRxEncryption (
*pdwRxTSC47_16 = 0;
pbyIV = pbyFrame + WLAN_HDR_ADDR3_LEN;
- if ( WLAN_GET_FC_TODS(*(PWORD)pbyFrame) &&
- WLAN_GET_FC_FROMDS(*(PWORD)pbyFrame) ) {
+ if ( WLAN_GET_FC_TODS(*(unsigned short *)pbyFrame) &&
+ WLAN_GET_FC_FROMDS(*(unsigned short *)pbyFrame) ) {
pbyIV += 6; // 6 is 802.11 address4
PayloadLen -= 6;
}
@@ -1353,18 +1333,18 @@ static BOOL s_bHostWepRxEncryption (
if (byDecMode != pKey->byCipherSuite) {
if (byDecMode == KEY_CTL_WEP) {
// pDevice->s802_11Counter.WEPUndecryptableCount.QuadPart++;
- } else if (pDevice->bLinkPass == TRUE) {
+ } else if (pDevice->bLinkPass == true) {
// pDevice->s802_11Counter.DecryptFailureCount.QuadPart++;
}
- return FALSE;
+ return false;
}
if (byDecMode == KEY_CTL_WEP) {
// handle WEP
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"byDecMode == KEY_CTL_WEP \n");
if ((pDevice->byLocalID <= REV_ID_VT3253_A1) ||
- (((PSKeyTable)(pKey->pvKeyTable))->bSoftWEP == TRUE) ||
- (bOnFly == FALSE)) {
+ (((PSKeyTable)(pKey->pvKeyTable))->bSoftWEP == true) ||
+ (bOnFly == false)) {
// Software WEP
// 1. 3253A
// 2. WEP 256
@@ -1385,19 +1365,19 @@ static BOOL s_bHostWepRxEncryption (
// TKIP/AES
PayloadLen -= (WLAN_HDR_ADDR3_LEN + 8 + 4); // 24 is 802.11 header, 8 is IV&ExtIV, 4 is crc
- *pdwRxTSC47_16 = cpu_to_le32(*(PDWORD)(pbyIV + 4));
+ *pdwRxTSC47_16 = cpu_to_le32(*(unsigned long *)(pbyIV + 4));
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"ExtIV: %lx\n",*pdwRxTSC47_16);
if (byDecMode == KEY_CTL_TKIP) {
*pwRxTSC15_0 = cpu_to_le16(MAKEWORD(*(pbyIV+2), *pbyIV));
} else {
- *pwRxTSC15_0 = cpu_to_le16(*(PWORD)pbyIV);
+ *pwRxTSC15_0 = cpu_to_le16(*(unsigned short *)pbyIV);
}
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"TSC0_15: %x\n", *pwRxTSC15_0);
if (byDecMode == KEY_CTL_TKIP) {
- if ((pDevice->byLocalID <= REV_ID_VT3253_A1) || (bOnFly == FALSE)) {
+ if ((pDevice->byLocalID <= REV_ID_VT3253_A1) || (bOnFly == false)) {
// Software TKIP
// 1. 3253 A
// 2. NotOnFly
@@ -1417,7 +1397,7 @@ static BOOL s_bHostWepRxEncryption (
}
if (byDecMode == KEY_CTL_CCMP) {
- if (bOnFly == FALSE) {
+ if (bOnFly == false) {
// Software CCMP
// NotOnFly
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"soft KEY_CTL_CCMP\n");
@@ -1433,34 +1413,34 @@ static BOOL s_bHostWepRxEncryption (
}// end of TKIP/AES
if ((*(pbyIV+3) & 0x20) != 0)
- *pbExtIV = TRUE;
- return TRUE;
+ *pbExtIV = true;
+ return true;
}
-static BOOL s_bAPModeRxData (
+static bool s_bAPModeRxData (
PSDevice pDevice,
struct sk_buff* skb,
- UINT FrameSize,
- UINT cbHeaderOffset,
- INT iSANodeIndex,
- INT iDANodeIndex
+ unsigned int FrameSize,
+ unsigned int cbHeaderOffset,
+ int iSANodeIndex,
+ int iDANodeIndex
)
{
PSMgmtObject pMgmt = pDevice->pMgmt;
- BOOL bRelayAndForward = FALSE;
- BOOL bRelayOnly = FALSE;
- BYTE byMask[8] = {1, 2, 4, 8, 0x10, 0x20, 0x40, 0x80};
- WORD wAID;
+ bool bRelayAndForward = false;
+ bool bRelayOnly = false;
+ unsigned char byMask[8] = {1, 2, 4, 8, 0x10, 0x20, 0x40, 0x80};
+ unsigned short wAID;
struct sk_buff* skbcpy = NULL;
if (FrameSize > CB_MAX_BUF_SIZE)
- return FALSE;
+ return false;
// check DA
- if(IS_MULTICAST_ADDRESS((PBYTE)(skb->data+cbHeaderOffset))) {
+ if(is_multicast_ether_addr((unsigned char *)(skb->data+cbHeaderOffset))) {
if (pMgmt->sNodeDBTable[0].bPSEnable) {
skbcpy = dev_alloc_skb((int)pDevice->rx_buf_sz);
@@ -1481,12 +1461,12 @@ static BOOL s_bAPModeRxData (
}
}
else {
- bRelayAndForward = TRUE;
+ bRelayAndForward = true;
}
}
else {
// check if relay
- if (BSSDBbIsSTAInNodeDB(pMgmt, (PBYTE)(skb->data+cbHeaderOffset), &iDANodeIndex)) {
+ if (BSSDBbIsSTAInNodeDB(pMgmt, (unsigned char *)(skb->data+cbHeaderOffset), &iDANodeIndex)) {
if (pMgmt->sNodeDBTable[iDANodeIndex].eNodeState >= NODE_ASSOC) {
if (pMgmt->sNodeDBTable[iDANodeIndex].bPSEnable) {
// queue this skb until next PS tx, and then release.
@@ -1500,10 +1480,10 @@ static BOOL s_bAPModeRxData (
pMgmt->abyPSTxMap[wAID >> 3] |= byMask[wAID & 7];
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "relay: index= %d, pMgmt->abyPSTxMap[%d]= %d\n",
iDANodeIndex, (wAID >> 3), pMgmt->abyPSTxMap[wAID >> 3]);
- return TRUE;
+ return true;
}
else {
- bRelayOnly = TRUE;
+ bRelayOnly = true;
}
}
};
@@ -1515,16 +1495,16 @@ static BOOL s_bAPModeRxData (
iDANodeIndex = 0;
if ((pDevice->uAssocCount > 1) && (iDANodeIndex >= 0)) {
- ROUTEbRelay(pDevice, (PBYTE)(skb->data + cbHeaderOffset), FrameSize, (UINT)iDANodeIndex);
+ ROUTEbRelay(pDevice, (unsigned char *)(skb->data + cbHeaderOffset), FrameSize, (unsigned int)iDANodeIndex);
}
if (bRelayOnly)
- return FALSE;
+ return false;
}
// none associate, don't forward
if (pDevice->uAssocCount == 0)
- return FALSE;
+ return false;
- return TRUE;
+ return true;
}
diff --git a/drivers/staging/vt6655/dpc.h b/drivers/staging/vt6655/dpc.h
index e574963fee0..c1b6e76a421 100644
--- a/drivers/staging/vt6655/dpc.h
+++ b/drivers/staging/vt6655/dpc.h
@@ -41,7 +41,7 @@
/*--------------------- Export Functions --------------------------*/
-BOOL
+bool
device_receive_frame (
PSDevice pDevice,
PSRxDesc pCurrRD
diff --git a/drivers/staging/vt6655/hostap.c b/drivers/staging/vt6655/hostap.c
index 195cc36654a..5b83f942cda 100644
--- a/drivers/staging/vt6655/hostap.c
+++ b/drivers/staging/vt6655/hostap.c
@@ -154,9 +154,9 @@ static int hostap_disable_hostapd(PSDevice pDevice, int rtnl_locked)
}
kfree(pDevice->apdev);
pDevice->apdev = NULL;
- pDevice->bEnable8021x = FALSE;
- pDevice->bEnableHostWEP = FALSE;
- pDevice->bEncryptionEnable = FALSE;
+ pDevice->bEnable8021x = false;
+ pDevice->bEnableHostWEP = false;
+ pDevice->bEncryptionEnable = false;
//4.2007-0118-03,<Add> by EinsnLiu
//execute some clear work
@@ -215,7 +215,7 @@ int vt6655_hostap_set_hostapd(PSDevice pDevice, int val, int rtnl_locked)
static int hostap_remove_sta(PSDevice pDevice,
struct viawget_hostapd_param *param)
{
- UINT uNodeIndex;
+ unsigned int uNodeIndex;
if (BSSDBbIsSTAInNodeDB(pDevice->pMgmt, param->sta_addr, &uNodeIndex)) {
@@ -244,7 +244,7 @@ static int hostap_add_sta(PSDevice pDevice,
struct viawget_hostapd_param *param)
{
PSMgmtObject pMgmt = pDevice->pMgmt;
- UINT uNodeIndex;
+ unsigned int uNodeIndex;
if (!BSSDBbIsSTAInNodeDB(pMgmt, param->sta_addr, &uNodeIndex)) {
@@ -255,7 +255,7 @@ static int hostap_add_sta(PSDevice pDevice,
pMgmt->sNodeDBTable[uNodeIndex].wCapInfo = param->u.add_sta.capability;
// TODO listenInterval
// pMgmt->sNodeDBTable[uNodeIndex].wListenInterval = 1;
- pMgmt->sNodeDBTable[uNodeIndex].bPSEnable = FALSE;
+ pMgmt->sNodeDBTable[uNodeIndex].bPSEnable = false;
pMgmt->sNodeDBTable[uNodeIndex].bySuppRate = param->u.add_sta.tx_supp_rates;
// set max tx rate
@@ -267,7 +267,7 @@ static int hostap_add_sta(PSDevice pDevice,
pMgmt->sNodeDBTable[uNodeIndex].bShortPreamble =
WLAN_GET_CAP_INFO_SHORTPREAMBLE(pMgmt->sNodeDBTable[uNodeIndex].wCapInfo);
- pMgmt->sNodeDBTable[uNodeIndex].wAID = (WORD)param->u.add_sta.aid;
+ pMgmt->sNodeDBTable[uNodeIndex].wAID = (unsigned short)param->u.add_sta.aid;
pMgmt->sNodeDBTable[uNodeIndex].ulLastRxJiffer = jiffies;
@@ -304,7 +304,7 @@ static int hostap_get_info_sta(PSDevice pDevice,
struct viawget_hostapd_param *param)
{
PSMgmtObject pMgmt = pDevice->pMgmt;
- UINT uNodeIndex;
+ unsigned int uNodeIndex;
if (BSSDBbIsSTAInNodeDB(pMgmt, param->sta_addr, &uNodeIndex)) {
param->u.get_info_sta.inactive_sec =
@@ -328,7 +328,7 @@ static int hostap_get_info_sta(PSDevice pDevice,
* pDevice -
* param -
* Out:
- * TURE, FALSE
+ * true, false
*
* Return Value:
*
@@ -338,7 +338,7 @@ static int hostap_reset_txexc_sta(PSDevice pDevice,
struct viawget_hostapd_param *param)
{
PSMgmtObject pMgmt = pDevice->pMgmt;
- UINT uNodeIndex;
+ unsigned int uNodeIndex;
if (BSSDBbIsSTAInNodeDB(pMgmt, param->sta_addr, &uNodeIndex)) {
pMgmt->sNodeDBTable[uNodeIndex].uTxAttempts = 0;
@@ -368,13 +368,13 @@ static int hostap_set_flags_sta(PSDevice pDevice,
struct viawget_hostapd_param *param)
{
PSMgmtObject pMgmt = pDevice->pMgmt;
- UINT uNodeIndex;
+ unsigned int uNodeIndex;
if (BSSDBbIsSTAInNodeDB(pMgmt, param->sta_addr, &uNodeIndex)) {
pMgmt->sNodeDBTable[uNodeIndex].dwFlags |= param->u.set_flags_sta.flags_or;
pMgmt->sNodeDBTable[uNodeIndex].dwFlags &= param->u.set_flags_sta.flags_and;
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " dwFlags = %x \n",
- (UINT)pMgmt->sNodeDBTable[uNodeIndex].dwFlags);
+ (unsigned int)pMgmt->sNodeDBTable[uNodeIndex].dwFlags);
}
else {
return -ENOENT;
@@ -471,16 +471,16 @@ static int hostap_set_encryption(PSDevice pDevice,
int param_len)
{
PSMgmtObject pMgmt = pDevice->pMgmt;
- DWORD dwKeyIndex = 0;
- BYTE abyKey[MAX_KEY_LEN];
- BYTE abySeq[MAX_KEY_LEN];
+ unsigned long dwKeyIndex = 0;
+ unsigned char abyKey[MAX_KEY_LEN];
+ unsigned char abySeq[MAX_KEY_LEN];
NDIS_802_11_KEY_RSC KeyRSC;
- BYTE byKeyDecMode = KEY_CTL_WEP;
+ unsigned char byKeyDecMode = KEY_CTL_WEP;
int ret = 0;
int iNodeIndex = -1;
int ii;
- BOOL bKeyTableFull = FALSE;
- WORD wKeyCtl = 0;
+ bool bKeyTableFull = false;
+ unsigned short wKeyCtl = 0;
param->u.crypt.err = 0;
@@ -509,7 +509,7 @@ static int hostap_set_encryption(PSDevice pDevice,
iNodeIndex = 0;
} else {
- if (BSSDBbIsSTAInNodeDB(pMgmt, param->sta_addr, &iNodeIndex) == FALSE) {
+ if (BSSDBbIsSTAInNodeDB(pMgmt, param->sta_addr, &iNodeIndex) == false) {
param->u.crypt.err = HOSTAP_CRYPT_ERR_UNKNOWN_ADDR;
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " HOSTAP_CRYPT_ERR_UNKNOWN_ADDR\n");
return -EINVAL;
@@ -520,14 +520,14 @@ static int hostap_set_encryption(PSDevice pDevice,
if (param->u.crypt.alg == WPA_ALG_NONE) {
- if (pMgmt->sNodeDBTable[iNodeIndex].bOnFly == TRUE) {
+ if (pMgmt->sNodeDBTable[iNodeIndex].bOnFly == true) {
if (KeybRemoveKey(&(pDevice->sKey),
param->sta_addr,
pMgmt->sNodeDBTable[iNodeIndex].dwKeyIndex,
- pDevice->PortOffset) == FALSE) {
+ pDevice->PortOffset) == false) {
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "KeybRemoveKey fail \n");
}
- pMgmt->sNodeDBTable[iNodeIndex].bOnFly = FALSE;
+ pMgmt->sNodeDBTable[iNodeIndex].bOnFly = false;
}
pMgmt->sNodeDBTable[iNodeIndex].byKeyIndex = 0;
pMgmt->sNodeDBTable[iNodeIndex].dwKeyIndex = 0;
@@ -553,16 +553,16 @@ static int hostap_set_encryption(PSDevice pDevice,
param->u.crypt.key_len
);
- dwKeyIndex = (DWORD)(param->u.crypt.idx);
+ dwKeyIndex = (unsigned long)(param->u.crypt.idx);
if (param->u.crypt.flags & HOSTAP_CRYPT_FLAG_SET_TX_KEY) {
- pDevice->byKeyIndex = (BYTE)dwKeyIndex;
- pDevice->bTransmitKey = TRUE;
+ pDevice->byKeyIndex = (unsigned char)dwKeyIndex;
+ pDevice->bTransmitKey = true;
dwKeyIndex |= (1 << 31);
}
if (param->u.crypt.alg == WPA_ALG_WEP) {
- if ((pDevice->bEnable8021x == FALSE) || (iNodeIndex == 0)) {
+ if ((pDevice->bEnable8021x == false) || (iNodeIndex == 0)) {
KeybSetDefaultKey(&(pDevice->sKey),
dwKeyIndex & ~(BIT30 | USE_KEYRSC),
param->u.crypt.key_len,
@@ -580,21 +580,21 @@ static int hostap_set_encryption(PSDevice pDevice,
dwKeyIndex & ~(USE_KEYRSC),
param->u.crypt.key_len,
(PQWORD) &(KeyRSC),
- (PBYTE)abyKey,
+ (unsigned char *)abyKey,
KEY_CTL_WEP,
pDevice->PortOffset,
- pDevice->byLocalID) == TRUE) {
+ pDevice->byLocalID) == true) {
- pMgmt->sNodeDBTable[iNodeIndex].bOnFly = TRUE;
+ pMgmt->sNodeDBTable[iNodeIndex].bOnFly = true;
} else {
// Key Table Full
- pMgmt->sNodeDBTable[iNodeIndex].bOnFly = FALSE;
- bKeyTableFull = TRUE;
+ pMgmt->sNodeDBTable[iNodeIndex].bOnFly = false;
+ bKeyTableFull = true;
}
}
pDevice->eEncryptionStatus = Ndis802_11Encryption1Enabled;
- pDevice->bEncryptionEnable = TRUE;
+ pDevice->bEncryptionEnable = true;
pMgmt->byCSSPK = KEY_CTL_WEP;
pMgmt->byCSSGK = KEY_CTL_WEP;
pMgmt->sNodeDBTable[iNodeIndex].byCipherSuite = KEY_CTL_WEP;
@@ -640,7 +640,7 @@ static int hostap_set_encryption(PSDevice pDevice,
byKeyDecMode,
pDevice->PortOffset,
pDevice->byLocalID);
- pMgmt->sNodeDBTable[iNodeIndex].bOnFly = TRUE;
+ pMgmt->sNodeDBTable[iNodeIndex].bOnFly = true;
} else {
dwKeyIndex |= (1 << 30); // set pairwise key
@@ -649,23 +649,23 @@ static int hostap_set_encryption(PSDevice pDevice,
dwKeyIndex,
param->u.crypt.key_len,
(PQWORD) &(KeyRSC),
- (PBYTE)abyKey,
+ (unsigned char *)abyKey,
byKeyDecMode,
pDevice->PortOffset,
- pDevice->byLocalID) == TRUE) {
+ pDevice->byLocalID) == true) {
- pMgmt->sNodeDBTable[iNodeIndex].bOnFly = TRUE;
+ pMgmt->sNodeDBTable[iNodeIndex].bOnFly = true;
} else {
// Key Table Full
- pMgmt->sNodeDBTable[iNodeIndex].bOnFly = FALSE;
- bKeyTableFull = TRUE;
+ pMgmt->sNodeDBTable[iNodeIndex].bOnFly = false;
+ bKeyTableFull = true;
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " Key Table Full\n");
}
}
- if (bKeyTableFull == TRUE) {
+ if (bKeyTableFull == true) {
wKeyCtl &= 0x7F00; // clear all key control filed
wKeyCtl |= (byKeyDecMode << 4);
wKeyCtl |= (byKeyDecMode);
@@ -686,7 +686,7 @@ static int hostap_set_encryption(PSDevice pDevice,
);
// set wep key
- pDevice->bEncryptionEnable = TRUE;
+ pDevice->bEncryptionEnable = true;
pMgmt->sNodeDBTable[iNodeIndex].byCipherSuite = byKeyDecMode;
pMgmt->sNodeDBTable[iNodeIndex].dwKeyIndex = dwKeyIndex;
pMgmt->sNodeDBTable[iNodeIndex].dwTSC47_16 = 0;
@@ -727,7 +727,7 @@ static int hostap_get_encryption(PSDevice pDevice,
param->sta_addr[4] == 0xff && param->sta_addr[5] == 0xff) {
iNodeIndex = 0;
} else {
- if (BSSDBbIsSTAInNodeDB(pMgmt, param->sta_addr, &iNodeIndex) == FALSE) {
+ if (BSSDBbIsSTAInNodeDB(pMgmt, param->sta_addr, &iNodeIndex) == false) {
param->u.crypt.err = HOSTAP_CRYPT_ERR_UNKNOWN_ADDR;
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "hostap_get_encryption: HOSTAP_CRYPT_ERR_UNKNOWN_ADDR\n");
return -EINVAL;
@@ -736,7 +736,7 @@ static int hostap_get_encryption(PSDevice pDevice,
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "hostap_get_encryption: %d\n", iNodeIndex);
memset(param->u.crypt.seq, 0, 8);
for (ii = 0 ; ii < 8 ; ii++) {
- param->u.crypt.seq[ii] = (BYTE)pMgmt->sNodeDBTable[iNodeIndex].KeyRSC >> (ii * 8);
+ param->u.crypt.seq[ii] = (unsigned char)pMgmt->sNodeDBTable[iNodeIndex].KeyRSC >> (ii * 8);
}
return ret;
diff --git a/drivers/staging/vt6655/iocmd.h b/drivers/staging/vt6655/iocmd.h
index 60c0a362361..53c50c0fc81 100644
--- a/drivers/staging/vt6655/iocmd.h
+++ b/drivers/staging/vt6655/iocmd.h
@@ -37,7 +37,6 @@
#define DEF
#endif
-//typedef int BOOL;
//typedef uint32_t u32;
//typedef uint16_t u16;
//typedef uint8_t u8;
@@ -109,10 +108,10 @@ typedef enum tagWZONETYPE {
//
#pragma pack(1)
typedef struct tagSCmdRequest {
- U8 name[16];
+ u8 name[16];
void *data;
- U16 wResult;
- U16 wCmdCode;
+ u16 wResult;
+ u16 wCmdCode;
} SCmdRequest, *PSCmdRequest;
//
@@ -121,7 +120,7 @@ typedef struct tagSCmdRequest {
typedef struct tagSCmdScan {
- U8 ssid[SSID_MAXLEN + 2];
+ u8 ssid[SSID_MAXLEN + 2];
} SCmdScan, *PSCmdScan;
@@ -132,12 +131,12 @@ typedef struct tagSCmdScan {
typedef struct tagSCmdBSSJoin {
- U16 wBSSType;
- U16 wBBPType;
- U8 ssid[SSID_MAXLEN + 2];
- U32 uChannel;
- BOOL bPSEnable;
- BOOL bShareKeyAuth;
+ u16 wBSSType;
+ u16 wBBPType;
+ u8 ssid[SSID_MAXLEN + 2];
+ u32 uChannel;
+ bool bPSEnable;
+ bool bShareKeyAuth;
} SCmdBSSJoin, *PSCmdBSSJoin;
@@ -147,7 +146,7 @@ typedef struct tagSCmdBSSJoin {
typedef struct tagSCmdZoneTypeSet {
- BOOL bWrite;
+ bool bWrite;
WZONETYPE ZoneType;
} SCmdZoneTypeSet, *PSCmdZoneTypeSet;
@@ -155,33 +154,33 @@ typedef struct tagSCmdZoneTypeSet {
#ifdef WPA_SM_Transtatus
typedef struct tagSWPAResult {
char ifname[100];
- U8 proto;
- U8 key_mgmt;
- U8 eap_type;
- BOOL authenticated;
+ u8 proto;
+ u8 key_mgmt;
+ u8 eap_type;
+ bool authenticated;
} SWPAResult, *PSWPAResult;
#endif
typedef struct tagSCmdStartAP {
- U16 wBSSType;
- U16 wBBPType;
- U8 ssid[SSID_MAXLEN + 2];
- U32 uChannel;
- U32 uBeaconInt;
- BOOL bShareKeyAuth;
- U8 byBasicRate;
+ u16 wBSSType;
+ u16 wBBPType;
+ u8 ssid[SSID_MAXLEN + 2];
+ u32 uChannel;
+ u32 uBeaconInt;
+ bool bShareKeyAuth;
+ u8 byBasicRate;
} SCmdStartAP, *PSCmdStartAP;
typedef struct tagSCmdSetWEP {
- BOOL bEnableWep;
- U8 byKeyIndex;
- U8 abyWepKey[WEP_NKEYS][WEP_KEYMAXLEN];
- BOOL bWepKeyAvailable[WEP_NKEYS];
- U32 auWepKeyLength[WEP_NKEYS];
+ bool bEnableWep;
+ u8 byKeyIndex;
+ u8 abyWepKey[WEP_NKEYS][WEP_KEYMAXLEN];
+ bool bWepKeyAvailable[WEP_NKEYS];
+ u32 auWepKeyLength[WEP_NKEYS];
} SCmdSetWEP, *PSCmdSetWEP;
@@ -189,39 +188,39 @@ typedef struct tagSCmdSetWEP {
typedef struct tagSBSSIDItem {
- U32 uChannel;
- U8 abyBSSID[BSSID_LEN];
- U8 abySSID[SSID_MAXLEN + 1];
+ u32 uChannel;
+ u8 abyBSSID[BSSID_LEN];
+ u8 abySSID[SSID_MAXLEN + 1];
//2006-1116-01,<Modify> by NomadZhao
- //U16 wBeaconInterval;
- //U16 wCapInfo;
- //U8 byNetType;
- U8 byNetType;
- U16 wBeaconInterval;
- U16 wCapInfo; // for address of byNetType at align 4
+ //u16 wBeaconInterval;
+ //u16 wCapInfo;
+ //u8 byNetType;
+ u8 byNetType;
+ u16 wBeaconInterval;
+ u16 wCapInfo; // for address of byNetType at align 4
- BOOL bWEPOn;
- U32 uRSSI;
+ bool bWEPOn;
+ u32 uRSSI;
} SBSSIDItem;
typedef struct tagSBSSIDList {
- U32 uItem;
+ u32 uItem;
SBSSIDItem sBSSIDList[0];
} SBSSIDList, *PSBSSIDList;
typedef struct tagSCmdLinkStatus {
- BOOL bLink;
- U16 wBSSType;
- U8 byState;
- U8 abyBSSID[BSSID_LEN];
- U8 abySSID[SSID_MAXLEN + 2];
- U32 uChannel;
- U32 uLinkRate;
+ bool bLink;
+ u16 wBSSType;
+ u8 byState;
+ u8 abyBSSID[BSSID_LEN];
+ u8 abySSID[SSID_MAXLEN + 2];
+ u32 uChannel;
+ u32 uLinkRate;
} SCmdLinkStatus, *PSCmdLinkStatus;
@@ -229,18 +228,18 @@ typedef struct tagSCmdLinkStatus {
// 802.11 counter
//
typedef struct tagSDot11MIBCount {
- U32 TransmittedFragmentCount;
- U32 MulticastTransmittedFrameCount;
- U32 FailedCount;
- U32 RetryCount;
- U32 MultipleRetryCount;
- U32 RTSSuccessCount;
- U32 RTSFailureCount;
- U32 ACKFailureCount;
- U32 FrameDuplicateCount;
- U32 ReceivedFragmentCount;
- U32 MulticastReceivedFrameCount;
- U32 FCSErrorCount;
+ u32 TransmittedFragmentCount;
+ u32 MulticastTransmittedFrameCount;
+ u32 FailedCount;
+ u32 RetryCount;
+ u32 MultipleRetryCount;
+ u32 RTSSuccessCount;
+ u32 RTSFailureCount;
+ u32 ACKFailureCount;
+ u32 FrameDuplicateCount;
+ u32 ReceivedFragmentCount;
+ u32 MulticastReceivedFrameCount;
+ u32 FCSErrorCount;
} SDot11MIBCount, *PSDot11MIBCount;
@@ -252,129 +251,129 @@ typedef struct tagSStatMIBCount {
//
// ISR status count
//
- U32 dwIsrTx0OK;
- U32 dwIsrTx1OK;
- U32 dwIsrBeaconTxOK;
- U32 dwIsrRxOK;
- U32 dwIsrTBTTInt;
- U32 dwIsrSTIMERInt;
- U32 dwIsrUnrecoverableError;
- U32 dwIsrSoftInterrupt;
- U32 dwIsrRxNoBuf;
+ u32 dwIsrTx0OK;
+ u32 dwIsrTx1OK;
+ u32 dwIsrBeaconTxOK;
+ u32 dwIsrRxOK;
+ u32 dwIsrTBTTInt;
+ u32 dwIsrSTIMERInt;
+ u32 dwIsrUnrecoverableError;
+ u32 dwIsrSoftInterrupt;
+ u32 dwIsrRxNoBuf;
/////////////////////////////////////
- U32 dwIsrUnknown; // unknown interrupt count
+ u32 dwIsrUnknown; // unknown interrupt count
// RSR status count
//
- U32 dwRsrFrmAlgnErr;
- U32 dwRsrErr;
- U32 dwRsrCRCErr;
- U32 dwRsrCRCOk;
- U32 dwRsrBSSIDOk;
- U32 dwRsrADDROk;
- U32 dwRsrICVOk;
- U32 dwNewRsrShortPreamble;
- U32 dwRsrLong;
- U32 dwRsrRunt;
-
- U32 dwRsrRxControl;
- U32 dwRsrRxData;
- U32 dwRsrRxManage;
-
- U32 dwRsrRxPacket;
- U32 dwRsrRxOctet;
- U32 dwRsrBroadcast;
- U32 dwRsrMulticast;
- U32 dwRsrDirected;
+ u32 dwRsrFrmAlgnErr;
+ u32 dwRsrErr;
+ u32 dwRsrCRCErr;
+ u32 dwRsrCRCOk;
+ u32 dwRsrBSSIDOk;
+ u32 dwRsrADDROk;
+ u32 dwRsrICVOk;
+ u32 dwNewRsrShortPreamble;
+ u32 dwRsrLong;
+ u32 dwRsrRunt;
+
+ u32 dwRsrRxControl;
+ u32 dwRsrRxData;
+ u32 dwRsrRxManage;
+
+ u32 dwRsrRxPacket;
+ u32 dwRsrRxOctet;
+ u32 dwRsrBroadcast;
+ u32 dwRsrMulticast;
+ u32 dwRsrDirected;
// 64-bit OID
- U32 ullRsrOK;
+ u32 ullRsrOK;
// for some optional OIDs (64 bits) and DMI support
- U32 ullRxBroadcastBytes;
- U32 ullRxMulticastBytes;
- U32 ullRxDirectedBytes;
- U32 ullRxBroadcastFrames;
- U32 ullRxMulticastFrames;
- U32 ullRxDirectedFrames;
-
- U32 dwRsrRxFragment;
- U32 dwRsrRxFrmLen64;
- U32 dwRsrRxFrmLen65_127;
- U32 dwRsrRxFrmLen128_255;
- U32 dwRsrRxFrmLen256_511;
- U32 dwRsrRxFrmLen512_1023;
- U32 dwRsrRxFrmLen1024_1518;
+ u32 ullRxBroadcastBytes;
+ u32 ullRxMulticastBytes;
+ u32 ullRxDirectedBytes;
+ u32 ullRxBroadcastFrames;
+ u32 ullRxMulticastFrames;
+ u32 ullRxDirectedFrames;
+
+ u32 dwRsrRxFragment;
+ u32 dwRsrRxFrmLen64;
+ u32 dwRsrRxFrmLen65_127;
+ u32 dwRsrRxFrmLen128_255;
+ u32 dwRsrRxFrmLen256_511;
+ u32 dwRsrRxFrmLen512_1023;
+ u32 dwRsrRxFrmLen1024_1518;
// TSR0,1 status count
//
- U32 dwTsrTotalRetry[2]; // total collision retry count
- U32 dwTsrOnceRetry[2]; // this packet only occur one collision
- U32 dwTsrMoreThanOnceRetry[2]; // this packet occur more than one collision
- U32 dwTsrRetry[2]; // this packet has ever occur collision,
+ u32 dwTsrTotalRetry[2]; // total collision retry count
+ u32 dwTsrOnceRetry[2]; // this packet only occur one collision
+ u32 dwTsrMoreThanOnceRetry[2]; // this packet occur more than one collision
+ u32 dwTsrRetry[2]; // this packet has ever occur collision,
// that is (dwTsrOnceCollision0 + dwTsrMoreThanOnceCollision0)
- U32 dwTsrACKData[2];
- U32 dwTsrErr[2];
- U32 dwAllTsrOK[2];
- U32 dwTsrRetryTimeout[2];
- U32 dwTsrTransmitTimeout[2];
-
- U32 dwTsrTxPacket[2];
- U32 dwTsrTxOctet[2];
- U32 dwTsrBroadcast[2];
- U32 dwTsrMulticast[2];
- U32 dwTsrDirected[2];
+ u32 dwTsrACKData[2];
+ u32 dwTsrErr[2];
+ u32 dwAllTsrOK[2];
+ u32 dwTsrRetryTimeout[2];
+ u32 dwTsrTransmitTimeout[2];
+
+ u32 dwTsrTxPacket[2];
+ u32 dwTsrTxOctet[2];
+ u32 dwTsrBroadcast[2];
+ u32 dwTsrMulticast[2];
+ u32 dwTsrDirected[2];
// RD/TD count
- U32 dwCntRxFrmLength;
- U32 dwCntTxBufLength;
+ u32 dwCntRxFrmLength;
+ u32 dwCntTxBufLength;
- U8 abyCntRxPattern[16];
- U8 abyCntTxPattern[16];
+ u8 abyCntRxPattern[16];
+ u8 abyCntTxPattern[16];
// Software check....
- U32 dwCntRxDataErr; // rx buffer data software compare CRC err count
- U32 dwCntDecryptErr; // rx buffer data software compare CRC err count
- U32 dwCntRxICVErr; // rx buffer data software compare CRC err count
- U32 idxRxErrorDesc; // index for rx data error RD
+ u32 dwCntRxDataErr; // rx buffer data software compare CRC err count
+ u32 dwCntDecryptErr; // rx buffer data software compare CRC err count
+ u32 dwCntRxICVErr; // rx buffer data software compare CRC err count
+ u32 idxRxErrorDesc; // index for rx data error RD
// 64-bit OID
- U32 ullTsrOK[2];
+ u32 ullTsrOK[2];
// for some optional OIDs (64 bits) and DMI support
- U32 ullTxBroadcastFrames[2];
- U32 ullTxMulticastFrames[2];
- U32 ullTxDirectedFrames[2];
- U32 ullTxBroadcastBytes[2];
- U32 ullTxMulticastBytes[2];
- U32 ullTxDirectedBytes[2];
+ u32 ullTxBroadcastFrames[2];
+ u32 ullTxMulticastFrames[2];
+ u32 ullTxDirectedFrames[2];
+ u32 ullTxBroadcastBytes[2];
+ u32 ullTxMulticastBytes[2];
+ u32 ullTxDirectedBytes[2];
} SStatMIBCount, *PSStatMIBCount;
typedef struct tagSNodeItem {
// STA info
- U16 wAID;
- U8 abyMACAddr[6];
- U16 wTxDataRate;
- U16 wInActiveCount;
- U16 wEnQueueCnt;
- U16 wFlags;
- BOOL bPWBitOn;
- U8 byKeyIndex;
- U16 wWepKeyLength;
- U8 abyWepKey[WEP_KEYMAXLEN];
+ u16 wAID;
+ u8 abyMACAddr[6];
+ u16 wTxDataRate;
+ u16 wInActiveCount;
+ u16 wEnQueueCnt;
+ u16 wFlags;
+ bool bPWBitOn;
+ u8 byKeyIndex;
+ u16 wWepKeyLength;
+ u8 abyWepKey[WEP_KEYMAXLEN];
// Auto rate fallback vars
- BOOL bIsInFallback;
- U32 uTxFailures;
- U32 uTxAttempts;
- U16 wFailureRatio;
+ bool bIsInFallback;
+ u32 uTxFailures;
+ u32 uTxAttempts;
+ u16 wFailureRatio;
} SNodeItem;
typedef struct tagSNodeList {
- U32 uItem;
+ u32 uItem;
SNodeItem sNodeList[0];
} SNodeList, *PSNodeList;
@@ -383,7 +382,7 @@ typedef struct tagSNodeList {
typedef struct tagSCmdValue {
- U32 dwValue;
+ u32 dwValue;
} SCmdValue, *PSCmdValue;
@@ -418,46 +417,46 @@ enum {
struct viawget_hostapd_param {
- U32 cmd;
- U8 sta_addr[6];
+ u32 cmd;
+ u8 sta_addr[6];
union {
struct {
- U16 aid;
- U16 capability;
- U8 tx_supp_rates;
+ u16 aid;
+ u16 capability;
+ u8 tx_supp_rates;
} add_sta;
struct {
- U32 inactive_sec;
+ u32 inactive_sec;
} get_info_sta;
struct {
- U8 alg;
- U32 flags;
- U32 err;
- U8 idx;
- U8 seq[8];
- U16 key_len;
- U8 key[0];
+ u8 alg;
+ u32 flags;
+ u32 err;
+ u8 idx;
+ u8 seq[8];
+ u16 key_len;
+ u8 key[0];
} crypt;
struct {
- U32 flags_and;
- U32 flags_or;
+ u32 flags_and;
+ u32 flags_or;
} set_flags_sta;
struct {
- U16 rid;
- U16 len;
- U8 data[0];
+ u16 rid;
+ u16 len;
+ u8 data[0];
} rid;
struct {
- U8 len;
- U8 data[0];
+ u8 len;
+ u8 data[0];
} generic_elem;
struct {
- U16 cmd;
- U16 reason_code;
+ u16 cmd;
+ u16 reason_code;
} mlme;
struct {
- U8 ssid_len;
- U8 ssid[32];
+ u8 ssid_len;
+ u8 ssid[32];
} scan_req;
} u;
};
diff --git a/drivers/staging/vt6655/ioctl.c b/drivers/staging/vt6655/ioctl.c
index 404287c6025..5624a41e3d5 100644
--- a/drivers/staging/vt6655/ioctl.c
+++ b/drivers/staging/vt6655/ioctl.c
@@ -70,16 +70,16 @@ int private_ioctl(PSDevice pDevice, struct ifreq *rq) {
SNodeList sNodeList;
PSBSSIDList pList;
PSNodeList pNodeList;
- UINT cbListCount;
+ unsigned int cbListCount;
PKnownBSS pBSS;
PKnownNodeDB pNode;
- UINT ii, jj;
+ unsigned int ii, jj;
SCmdLinkStatus sLinkStatus;
- BYTE abySuppRates[] = {WLAN_EID_SUPP_RATES, 4, 0x02, 0x04, 0x0B, 0x16};
- BYTE abyNullAddr[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
- DWORD dwKeyIndex= 0;
- BYTE abyScanSSID[WLAN_IEHDR_LEN + WLAN_SSID_MAXLEN + 1];
- LONG ldBm;
+ unsigned char abySuppRates[] = {WLAN_EID_SUPP_RATES, 4, 0x02, 0x04, 0x0B, 0x16};
+ unsigned char abyNullAddr[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+ unsigned long dwKeyIndex= 0;
+ unsigned char abyScanSSID[WLAN_IEHDR_LEN + WLAN_SSID_MAXLEN + 1];
+ long ldBm;
pReq->wResult = 0;
@@ -99,17 +99,17 @@ int private_ioctl(PSDevice pDevice, struct ifreq *rq) {
memcpy(abyScanSSID, pItemSSID, pItemSSID->len + WLAN_IEHDR_LEN);
}
- if (pDevice->bMACSuspend == TRUE) {
- if (pDevice->bRadioOff == TRUE)
+ if (pDevice->bMACSuspend == true) {
+ if (pDevice->bRadioOff == true)
CARDbRadioPowerOn(pDevice);
vMgrTimerInit(pDevice);
MACvIntEnable(pDevice->PortOffset, IMR_MASK_VALUE);
add_timer(&pMgmt->sTimerSecondCallback);
- pDevice->bMACSuspend = FALSE;
+ pDevice->bMACSuspend = false;
}
spin_lock_irq(&pDevice->lock);
if (memcmp(pMgmt->abyCurrBSSID, &abyNullAddr[0], 6) == 0)
- BSSvClearBSSList((void *)pDevice, FALSE);
+ BSSvClearBSSList((void *)pDevice, false);
else
BSSvClearBSSList((void *)pDevice, pDevice->bLinkPass);
@@ -130,7 +130,7 @@ int private_ioctl(PSDevice pDevice, struct ifreq *rq) {
break;
};
- if(sZoneTypeCmd.bWrite==TRUE) {
+ if(sZoneTypeCmd.bWrite==true) {
//////write zonetype
if(sZoneTypeCmd.ZoneType == ZoneType_USA) {
//set to USA
@@ -147,7 +147,7 @@ int private_ioctl(PSDevice pDevice, struct ifreq *rq) {
}
else {
///////read zonetype
- BYTE zonetype=0;
+ unsigned char zonetype=0;
if(zonetype == 0x00) { //USA
@@ -174,13 +174,13 @@ int private_ioctl(PSDevice pDevice, struct ifreq *rq) {
case WLAN_CMD_BSS_JOIN:
- if (pDevice->bMACSuspend == TRUE) {
- if (pDevice->bRadioOff == TRUE)
+ if (pDevice->bMACSuspend == true) {
+ if (pDevice->bRadioOff == true)
CARDbRadioPowerOn(pDevice);
vMgrTimerInit(pDevice);
MACvIntEnable(pDevice->PortOffset, IMR_MASK_VALUE);
add_timer(&pMgmt->sTimerSecondCallback);
- pDevice->bMACSuspend = FALSE;
+ pDevice->bMACSuspend = false;
}
if (copy_from_user(&sJoinCmd, pReq->data, sizeof(SCmdBSSJoin))) {
@@ -199,7 +199,7 @@ int private_ioctl(PSDevice pDevice, struct ifreq *rq) {
pMgmt->eConfigMode = WMAC_CONFIG_ESS_STA;
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "ioct set to STA mode\n");
}
- if (sJoinCmd.bPSEnable == TRUE) {
+ if (sJoinCmd.bPSEnable == true) {
pDevice->ePSMode = WMAC_POWER_FAST;
// pDevice->ePSMode = WMAC_POWER_MAX;
pMgmt->wListenInterval = 2;
@@ -211,12 +211,12 @@ int private_ioctl(PSDevice pDevice, struct ifreq *rq) {
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Power Saving Off \n");
}
- if (sJoinCmd.bShareKeyAuth == TRUE){
- pMgmt->bShareKeyAlgorithm = TRUE;
+ if (sJoinCmd.bShareKeyAuth == true){
+ pMgmt->bShareKeyAlgorithm = true;
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Share Key \n");
}
else {
- pMgmt->bShareKeyAlgorithm = FALSE;
+ pMgmt->bShareKeyAlgorithm = false;
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Open System \n");
}
pDevice->uChannel = sJoinCmd.uChannel;
@@ -235,8 +235,8 @@ int private_ioctl(PSDevice pDevice, struct ifreq *rq) {
result = -EFAULT;
break;
};
- if (sWEPCmd.bEnableWep != TRUE) {
- pDevice->bEncryptionEnable = FALSE;
+ if (sWEPCmd.bEnableWep != true) {
+ pDevice->bEncryptionEnable = false;
pDevice->eEncryptionStatus = Ndis802_11EncryptionDisabled;
MACvDisableDefaultKey(pDevice->PortOffset);
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "WEP function disable. \n");
@@ -257,15 +257,15 @@ int private_ioctl(PSDevice pDevice, struct ifreq *rq) {
dwKeyIndex,
sWEPCmd.auWepKeyLength[ii],
NULL,
- (PBYTE)&sWEPCmd.abyWepKey[ii][0],
+ (unsigned char *)&sWEPCmd.abyWepKey[ii][0],
KEY_CTL_WEP,
pDevice->PortOffset,
pDevice->byLocalID);
}
}
pDevice->byKeyIndex = sWEPCmd.byKeyIndex;
- pDevice->bTransmitKey = TRUE;
- pDevice->bEncryptionEnable = TRUE;
+ pDevice->bTransmitKey = true;
+ pDevice->bEncryptionEnable = true;
pDevice->eEncryptionStatus = Ndis802_11Encryption1Enabled;
break;
@@ -286,8 +286,8 @@ int private_ioctl(PSDevice pDevice, struct ifreq *rq) {
sLinkStatus.byState = ADHOC_STARTED;
sLinkStatus.uChannel = pMgmt->uCurrChannel;
- if (pDevice->bLinkPass == TRUE) {
- sLinkStatus.bLink = TRUE;
+ if (pDevice->bLinkPass == true) {
+ sLinkStatus.bLink = true;
pItemSSID = (PWLAN_IE_SSID)pMgmt->abyCurrSSID;
memcpy(sLinkStatus.abySSID, pItemSSID->abySSID, pItemSSID->len);
memcpy(sLinkStatus.abyBSSID, pMgmt->abyCurrBSSID, WLAN_BSSID_LEN);
@@ -295,7 +295,7 @@ int private_ioctl(PSDevice pDevice, struct ifreq *rq) {
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO" Link Success ! \n");
}
else {
- sLinkStatus.bLink = FALSE;
+ sLinkStatus.bLink = false;
}
if (copy_to_user(pReq->data, &sLinkStatus, sizeof(SCmdLinkStatus))) {
result = -EFAULT;
@@ -340,8 +340,8 @@ int private_ioctl(PSDevice pDevice, struct ifreq *rq) {
pList->sBSSIDList[ii].wBeaconInterval = pBSS->wBeaconInterval;
pList->sBSSIDList[ii].wCapInfo = pBSS->wCapInfo;
// pList->sBSSIDList[ii].uRSSI = pBSS->uRSSI;
- RFvRSSITodBm(pDevice, (BYTE)(pBSS->uRSSI), &ldBm);
- pList->sBSSIDList[ii].uRSSI = (UINT)ldBm;
+ RFvRSSITodBm(pDevice, (unsigned char)(pBSS->uRSSI), &ldBm);
+ pList->sBSSIDList[ii].uRSSI = (unsigned int)ldBm;
memcpy(pList->sBSSIDList[ii].abyBSSID, pBSS->abyBSSID, WLAN_BSSID_LEN);
pItemSSID = (PWLAN_IE_SSID)pBSS->abySSID;
memset(pList->sBSSIDList[ii].abySSID, 0, WLAN_SSID_MAXLEN + 1);
@@ -353,10 +353,10 @@ int private_ioctl(PSDevice pDevice, struct ifreq *rq) {
pList->sBSSIDList[ii].byNetType = ADHOC;
}
if (WLAN_GET_CAP_INFO_PRIVACY(pBSS->wCapInfo)) {
- pList->sBSSIDList[ii].bWEPOn = TRUE;
+ pList->sBSSIDList[ii].bWEPOn = true;
}
else {
- pList->sBSSIDList[ii].bWEPOn = FALSE;
+ pList->sBSSIDList[ii].bWEPOn = false;
}
ii ++;
if (ii >= pList->uItem)
@@ -391,16 +391,16 @@ int private_ioctl(PSDevice pDevice, struct ifreq *rq) {
netif_stop_queue(pDevice->dev);
spin_lock_irq(&pDevice->lock);
- if (pDevice->bRadioOff == FALSE) {
+ if (pDevice->bRadioOff == false) {
CARDbRadioPowerOff(pDevice);
}
- pDevice->bLinkPass = FALSE;
+ pDevice->bLinkPass = false;
memset(pMgmt->abyCurrBSSID, 0, 6);
pMgmt->eCurrState = WMAC_STATE_IDLE;
del_timer(&pDevice->sTimerCommand);
del_timer(&pMgmt->sTimerSecondCallback);
- pDevice->bCmdRunning = FALSE;
- pDevice->bMACSuspend = TRUE;
+ pDevice->bCmdRunning = false;
+ pDevice->bMACSuspend = true;
MACvIntDisable(pDevice->PortOffset);
spin_unlock_irq(&pDevice->lock);
@@ -410,13 +410,13 @@ int private_ioctl(PSDevice pDevice, struct ifreq *rq) {
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "WLAN_CMD_START_MAC\n");
- if (pDevice->bMACSuspend == TRUE) {
- if (pDevice->bRadioOff == TRUE)
+ if (pDevice->bMACSuspend == true) {
+ if (pDevice->bRadioOff == true)
CARDbRadioPowerOn(pDevice);
vMgrTimerInit(pDevice);
MACvIntEnable(pDevice->PortOffset, IMR_MASK_VALUE);
add_timer(&pMgmt->sTimerSecondCallback);
- pDevice->bMACSuspend = FALSE;
+ pDevice->bMACSuspend = false;
}
break;
@@ -458,11 +458,11 @@ int private_ioctl(PSDevice pDevice, struct ifreq *rq) {
};
if (sValue.dwValue == 1) {
- pDevice->bEnable8021x = TRUE;
+ pDevice->bEnable8021x = true;
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Enable 802.1x\n");
}
else {
- pDevice->bEnable8021x = FALSE;
+ pDevice->bEnable8021x = false;
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Disable 802.1x\n");
}
@@ -478,11 +478,11 @@ int private_ioctl(PSDevice pDevice, struct ifreq *rq) {
};
if (sValue.dwValue == 1) {
- pDevice->bEnableHostWEP = TRUE;
+ pDevice->bEnableHostWEP = true;
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Enable HostWEP\n");
}
else {
- pDevice->bEnableHostWEP = FALSE;
+ pDevice->bEnableHostWEP = false;
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Disable HostWEP\n");
}
@@ -498,11 +498,11 @@ int private_ioctl(PSDevice pDevice, struct ifreq *rq) {
if (sValue.dwValue == 1) {
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "up wpadev\n");
memcpy(pDevice->wpadev->dev_addr, pDevice->dev->dev_addr, ETH_ALEN);
- pDevice->bWPADEVUp = TRUE;
+ pDevice->bWPADEVUp = true;
}
else {
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "close wpadev\n");
- pDevice->bWPADEVUp = FALSE;
+ pDevice->bWPADEVUp = false;
}
break;
@@ -510,7 +510,7 @@ int private_ioctl(PSDevice pDevice, struct ifreq *rq) {
case WLAN_CMD_AP_START:
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "WLAN_CMD_AP_START\n");
- if (pDevice->bRadioOff == TRUE) {
+ if (pDevice->bRadioOff == true) {
CARDbRadioPowerOn(pDevice);
vMgrTimerInit(pDevice);
MACvIntEnable(pDevice->PortOffset, IMR_MASK_VALUE);
@@ -554,12 +554,12 @@ int private_ioctl(PSDevice pDevice, struct ifreq *rq) {
else
pMgmt->wIBSSBeaconPeriod = 100;
- if (sStartAPCmd.bShareKeyAuth == TRUE){
- pMgmt->bShareKeyAlgorithm = TRUE;
+ if (sStartAPCmd.bShareKeyAuth == true){
+ pMgmt->bShareKeyAlgorithm = true;
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Share Key \n");
}
else {
- pMgmt->bShareKeyAlgorithm = FALSE;
+ pMgmt->bShareKeyAlgorithm = false;
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Open System \n");
}
memcpy(pMgmt->abyIBSSSuppRates, abySuppRates, 6);
@@ -635,9 +635,9 @@ int private_ioctl(PSDevice pDevice, struct ifreq *rq) {
pNodeList->sNodeList[jj].wAID = pNode->wAID;
memcpy(pNodeList->sNodeList[jj].abyMACAddr, pNode->abyMACAddr, WLAN_ADDR_LEN);
pNodeList->sNodeList[jj].wTxDataRate = pNode->wTxDataRate;
- pNodeList->sNodeList[jj].wInActiveCount = (WORD)pNode->uInActiveCount;
- pNodeList->sNodeList[jj].wEnQueueCnt = (WORD)pNode->wEnQueueCnt;
- pNodeList->sNodeList[jj].wFlags = (WORD)pNode->dwFlags;
+ pNodeList->sNodeList[jj].wInActiveCount = (unsigned short)pNode->uInActiveCount;
+ pNodeList->sNodeList[jj].wEnQueueCnt = (unsigned short)pNode->wEnQueueCnt;
+ pNodeList->sNodeList[jj].wFlags = (unsigned short)pNode->dwFlags;
pNodeList->sNodeList[jj].bPWBitOn = pNode->bPSEnable;
pNodeList->sNodeList[jj].byKeyIndex = pNode->byKeyIndex;
pNodeList->sNodeList[jj].wWepKeyLength = pNode->uWepKeyLength;
@@ -652,7 +652,7 @@ int private_ioctl(PSDevice pDevice, struct ifreq *rq) {
pNodeList->sNodeList[jj].bIsInFallback = pNode->bIsInFallback;
pNodeList->sNodeList[jj].uTxFailures = pNode->uTxFailures;
pNodeList->sNodeList[jj].uTxAttempts = pNode->uTxAttempts;
- pNodeList->sNodeList[jj].wFailureRatio = (WORD)pNode->uFailureRatio;
+ pNodeList->sNodeList[jj].wFailureRatio = (unsigned short)pNode->uFailureRatio;
jj ++;
if (jj >= pNodeList->uItem)
break;
@@ -672,14 +672,14 @@ int private_ioctl(PSDevice pDevice, struct ifreq *rq) {
wpa_Result.proto = 0;
wpa_Result.key_mgmt = 0;
wpa_Result.eap_type = 0;
- wpa_Result.authenticated = FALSE;
- pDevice->fWPA_Authened = FALSE;
+ wpa_Result.authenticated = false;
+ pDevice->fWPA_Authened = false;
if (copy_from_user(&wpa_Result, pReq->data, sizeof(wpa_Result))) {
result = -EFAULT;
break;
}
-if(wpa_Result.authenticated==TRUE) {
+if(wpa_Result.authenticated==true) {
#ifdef SndEvt_ToAPI
{
union iwreq_data wrqu;
@@ -692,7 +692,7 @@ if(wpa_Result.authenticated==TRUE) {
wireless_send_event(pDevice->dev, IWEVCUSTOM, &wrqu, pItemSSID->abySSID);
}
#endif
- pDevice->fWPA_Authened = TRUE; //is successful peer to wpa_Result.authenticated?
+ pDevice->fWPA_Authened = true; //is successful peer to wpa_Result.authenticated?
}
//printk("get private wpa_supplicant announce WPA SM\n");
@@ -700,7 +700,7 @@ if(wpa_Result.authenticated==TRUE) {
//printk("wpa-->proto=%d\n",wpa_Result.proto);
//printk("wpa-->key-mgmt=%d\n",wpa_Result.key_mgmt);
//printk("wpa-->eap_type=%d\n",wpa_Result.eap_type);
- //printk("wpa-->authenticated is %s\n",(wpa_Result.authenticated==TRUE)?"TRUE":"FALSE");
+ //printk("wpa-->authenticated is %s\n",(wpa_Result.authenticated==true)?"true":"false");
pReq->wResult = 0;
break;
@@ -717,9 +717,9 @@ if(wpa_Result.authenticated==TRUE) {
void
vConfigWEPKey (
PSDevice pDevice,
- DWORD dwKeyIndex,
- PBYTE pbyKey,
- ULONG uKeyLength
+ unsigned long dwKeyIndex,
+ unsigned char *pbyKey,
+ unsigned long uKeyLength
)
{
int ii;
@@ -728,15 +728,15 @@ vConfigWEPKey (
memset(&pDevice->abyWepKey[dwKeyIndex][0], 0, WLAN_WEPMAX_KEYLEN);
memcpy(&pDevice->abyWepKey[dwKeyIndex][0], pbyKey, uKeyLength);
- pDevice->bWepKeyAvailable[dwKeyIndex] = TRUE;
+ pDevice->bWepKeyAvailable[dwKeyIndex] = true;
pDevice->auWepKeyLength[dwKeyIndex] = uKeyLength;
MACvSetDefaultKeyEntry(pDevice->PortOffset, uKeyLength, dwKeyIndex,
- (PDWORD) &(pDevice->abyWepKey[dwKeyIndex][0]), pDevice->byLocalID);
+ (unsigned long *) &(pDevice->abyWepKey[dwKeyIndex][0]), pDevice->byLocalID);
if (pDevice->eEncryptionStatus < Ndis802_11EncryptionNotSupported) {
for(ii=0; ii<MAX_GROUP_KEY; ii++) {
- if ((pDevice->bWepKeyAvailable[ii] == TRUE) &&
+ if ((pDevice->bWepKeyAvailable[ii] == true) &&
(pDevice->auWepKeyLength[ii] == WLAN_WEP232_KEYLEN)) {
pDevice->uCurrentWEPMode = TX_WEP_SW232;
MACvDisableDefaultKey(pDevice->PortOffset);
diff --git a/drivers/staging/vt6655/ioctl.h b/drivers/staging/vt6655/ioctl.h
index 0d10c2a923c..ba85015c11b 100644
--- a/drivers/staging/vt6655/ioctl.h
+++ b/drivers/staging/vt6655/ioctl.h
@@ -45,9 +45,9 @@ int private_ioctl(PSDevice pDevice, struct ifreq *rq);
/*
void vConfigWEPKey (
PSDevice pDevice,
- DWORD dwKeyIndex,
- PBYTE pbyKey,
- ULONG uKeyLength
+ unsigned long dwKeyIndex,
+ unsigned char *pbyKey,
+ unsigned long uKeyLength
);
*/
diff --git a/drivers/staging/vt6655/iwctl.c b/drivers/staging/vt6655/iwctl.c
index cf69034fc0f..43227617aab 100644
--- a/drivers/staging/vt6655/iwctl.c
+++ b/drivers/staging/vt6655/iwctl.c
@@ -45,7 +45,7 @@
#endif
#include <net/iw_handler.h>
-extern WORD TxRate_iwconfig;//2008-5-8 <add> by chester
+extern unsigned short TxRate_iwconfig;//2008-5-8 <add> by chester
/*--------------------- Static Definitions -------------------------*/
@@ -99,16 +99,16 @@ struct iw_statistics *iwctl_get_wireless_stats(struct net_device *dev)
else
pDevice->scStatistic.LinkQuality = (96-pDevice->byCurrSQ)*100/76;
}
- if(pDevice->bLinkPass !=TRUE)
+ if(pDevice->bLinkPass !=true)
pDevice->scStatistic.LinkQuality = 0;
#endif
if(pDevice->scStatistic.LinkQuality > 100)
pDevice->scStatistic.LinkQuality = 100;
- pDevice->wstats.qual.qual =(BYTE) pDevice->scStatistic.LinkQuality;
+ pDevice->wstats.qual.qual =(unsigned char) pDevice->scStatistic.LinkQuality;
#else
pDevice->wstats.qual.qual = pDevice->byCurrSQ;
#endif
- RFvRSSITodBm(pDevice, (BYTE)(pDevice->uCurrRSSI), &ldBm);
+ RFvRSSITodBm(pDevice, (unsigned char)(pDevice->uCurrRSSI), &ldBm);
pDevice->wstats.qual.level = ldBm;
//pDevice->wstats.qual.level = 0x100 - pDevice->uCurrRSSI;
pDevice->wstats.qual.noise = 0;
@@ -116,7 +116,7 @@ struct iw_statistics *iwctl_get_wireless_stats(struct net_device *dev)
pDevice->wstats.discard.nwid = 0;
pDevice->wstats.discard.code = 0;
pDevice->wstats.discard.fragment = 0;
- pDevice->wstats.discard.retries = (U32)pDevice->scStatistic.dwTsrErr;
+ pDevice->wstats.discard.retries = (unsigned long)pDevice->scStatistic.dwTsrErr;
pDevice->wstats.discard.misc = 0;
pDevice->wstats.miss.beacon = 0;
@@ -175,7 +175,7 @@ int iwctl_siwscan(struct net_device *dev,
PSDevice pDevice = (PSDevice)netdev_priv(dev);
PSMgmtObject pMgmt = &(pDevice->sMgmtObj);
struct iw_scan_req *req = (struct iw_scan_req *)extra;
- BYTE abyScanSSID[WLAN_IEHDR_LEN + WLAN_SSID_MAXLEN + 1];
+ unsigned char abyScanSSID[WLAN_IEHDR_LEN + WLAN_SSID_MAXLEN + 1];
PWLAN_IE_SSID pItemSSID=NULL;
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCSIWSCAN \n");
@@ -309,7 +309,7 @@ int iwctl_giwscan(struct net_device *dev,
//ADD quality
memset(&iwe, 0, sizeof(iwe));
iwe.cmd = IWEVQUAL;
- RFvRSSITodBm(pDevice, (BYTE)(pBSS->uRSSI), &ldBm);
+ RFvRSSITodBm(pDevice, (unsigned char)(pBSS->uRSSI), &ldBm);
iwe.u.qual.level = ldBm;
iwe.u.qual.noise = 0;
//2008-0409-01, <Add> by Einsn Liu
@@ -426,7 +426,7 @@ int iwctl_siwfreq(struct net_device *dev,
pDevice->uChannel = channel;
//2007-0207-04,<Add> by EinsnLiu
//Make change effect at once
- pDevice->bCommit = TRUE;
+ pDevice->bCommit = true;
}
}
@@ -489,7 +489,7 @@ int iwctl_siwmode(struct net_device *dev,
if (pMgmt->eConfigMode != WMAC_CONFIG_IBSS_STA) {
pMgmt->eConfigMode = WMAC_CONFIG_IBSS_STA;
if (pDevice->flags & DEVICE_FLAGS_OPENED) {
- pDevice->bCommit = TRUE;
+ pDevice->bCommit = true;
}
}
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "set mode to ad-hoc \n");
@@ -499,7 +499,7 @@ int iwctl_siwmode(struct net_device *dev,
if (pMgmt->eConfigMode != WMAC_CONFIG_ESS_STA) {
pMgmt->eConfigMode = WMAC_CONFIG_ESS_STA;
if (pDevice->flags & DEVICE_FLAGS_OPENED) {
- pDevice->bCommit = TRUE;
+ pDevice->bCommit = true;
}
}
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "set mode to infrastructure \n");
@@ -513,7 +513,7 @@ int iwctl_siwmode(struct net_device *dev,
if (pMgmt->eConfigMode != WMAC_CONFIG_AP) {
pMgmt->eConfigMode = WMAC_CONFIG_AP;
if (pDevice->flags & DEVICE_FLAGS_OPENED) {
- pDevice->bCommit = TRUE;
+ pDevice->bCommit = true;
}
}
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "set mode to Access Point \n");
@@ -577,7 +577,7 @@ int iwctl_giwrange(struct net_device *dev,
{
struct iw_range *range = (struct iw_range *) extra;
int i,k;
- BYTE abySupportedRates[13]= {0x02, 0x04, 0x0B, 0x16, 0x0c, 0x12, 0x18, 0x24, 0x30, 0x48, 0x60, 0x6C, 0x90};
+ unsigned char abySupportedRates[13]= {0x02, 0x04, 0x0B, 0x16, 0x0c, 0x12, 0x18, 0x24, 0x30, 0x48, 0x60, 0x6C, 0x90};
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCGIWRANGE \n");
@@ -688,7 +688,7 @@ int iwctl_siwap(struct net_device *dev,
PSDevice pDevice = (PSDevice)netdev_priv(dev);
PSMgmtObject pMgmt = &(pDevice->sMgmtObj);
int rc = 0;
- BYTE ZeroBSSID[WLAN_BSSID_LEN]={0x00,0x00,0x00,0x00,0x00,0x00};
+ unsigned char ZeroBSSID[WLAN_BSSID_LEN]={0x00,0x00,0x00,0x00,0x00,0x00};
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCSIWAP \n");
if (pMgmt->eScanState == WMAC_IS_SCANNING) {
@@ -701,12 +701,12 @@ if (pMgmt->eScanState == WMAC_IS_SCANNING) {
else {
memcpy(pMgmt->abyDesireBSSID, wrq->sa_data, 6);
//2008-0409-05, <Add> by Einsn Liu
- if((pDevice->bLinkPass == TRUE) &&
+ if((pDevice->bLinkPass == true) &&
(memcmp(pMgmt->abyDesireBSSID, pMgmt->abyCurrBSSID, 6)== 0)){
return rc;
}
//mike :add
- if ((IS_BROADCAST_ADDRESS(pMgmt->abyDesireBSSID)) ||
+ if ((is_broadcast_ether_addr(pMgmt->abyDesireBSSID)) ||
(memcmp(pMgmt->abyDesireBSSID, ZeroBSSID, 6) == 0)){
PRINT_K("SIOCSIWAP:invalid desired BSSID return!\n");
return rc;
@@ -714,10 +714,10 @@ if (pMgmt->eScanState == WMAC_IS_SCANNING) {
//mike add: if desired AP is hidden ssid(there are two same BSSID in list),
// then ignore,because you don't known which one to be connect with??
{
- UINT ii , uSameBssidNum=0;
+ unsigned int ii , uSameBssidNum=0;
for (ii = 0; ii < MAX_BSS_NUM; ii++) {
if (pMgmt->sBSSList[ii].bActive &&
- IS_ETH_ADDRESS_EQUAL(pMgmt->sBSSList[ii].abyBSSID,pMgmt->abyDesireBSSID)) {
+ !compare_ether_addr(pMgmt->sBSSList[ii].abyBSSID, pMgmt->abyDesireBSSID)) {
uSameBssidNum++;
}
}
@@ -728,7 +728,7 @@ if (pMgmt->eScanState == WMAC_IS_SCANNING) {
}
if (pDevice->flags & DEVICE_FLAGS_OPENED) {
- pDevice->bCommit = TRUE;
+ pDevice->bCommit = true;
}
}
return rc;
@@ -751,7 +751,7 @@ int iwctl_giwap(struct net_device *dev,
memcpy(wrq->sa_data, pMgmt->abyCurrBSSID, 6);
//2008-0410,<Modify> by Einsn Liu
- if ((pDevice->bLinkPass == FALSE) && (pMgmt->eCurrMode != WMAC_MODE_ESS_AP))
+ if ((pDevice->bLinkPass == false) && (pMgmt->eCurrMode != WMAC_MODE_ESS_AP))
memset(wrq->sa_data, 0, 6);
if (pMgmt->eCurrMode == WMAC_MODE_ESS_AP) {
@@ -830,11 +830,11 @@ int iwctl_siwessid(struct net_device *dev,
PSMgmtObject pMgmt = &(pDevice->sMgmtObj);
PWLAN_IE_SSID pItemSSID;
//2008-0409-05, <Add> by Einsn Liu
- BYTE len;
+ unsigned char len;
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCSIWESSID \n");
- pDevice->fWPA_Authened = FALSE;
+ pDevice->fWPA_Authened = false;
if (pMgmt->eScanState == WMAC_IS_SCANNING) {
// In scanning..
printk("SIOCSIWESSID(??)-->In scanning...\n");
@@ -848,7 +848,7 @@ if (pMgmt->eScanState == WMAC_IS_SCANNING) {
PRINT_K("set essid to 'any' \n");
#ifdef WPA_SUPPLICANT_DRIVER_WEXT_SUPPORT
//Unknown desired AP,so here need not associate??
- //if(pDevice->bWPASuppWextEnabled == TRUE) {
+ //if(pDevice->bWPASuppWextEnabled == true) {
return 0;
// }
#endif
@@ -868,7 +868,7 @@ if (pMgmt->eScanState == WMAC_IS_SCANNING) {
printk("set essid to %s \n",pItemSSID->abySSID);
//2008-0409-05, <Add> by Einsn Liu
len=(pItemSSID->len > ((PWLAN_IE_SSID)pMgmt->abyCurrSSID)->len)?pItemSSID->len:((PWLAN_IE_SSID)pMgmt->abyCurrSSID)->len;
- if((pDevice->bLinkPass == TRUE) &&
+ if((pDevice->bLinkPass == true) &&
(memcmp(pItemSSID->abySSID,((PWLAN_IE_SSID)pMgmt->abyCurrSSID)->abySSID,len)==0))
return 0;
@@ -881,12 +881,12 @@ if (pMgmt->eScanState == WMAC_IS_SCANNING) {
#ifdef WPA_SUPPLICANT_DRIVER_WEXT_SUPPORT
//Wext wil order another command of siwap to link with desired AP,
//so here need not associate??
- if(pDevice->bWPASuppWextEnabled == TRUE) {
+ if(pDevice->bWPASuppWextEnabled == true) {
/*******search if in hidden ssid mode ****/
{
PKnownBSS pCurr = NULL;
- BYTE abyTmpDesireSSID[WLAN_IEHDR_LEN + WLAN_SSID_MAXLEN + 1];
- UINT ii , uSameBssidNum=0;
+ unsigned char abyTmpDesireSSID[WLAN_IEHDR_LEN + WLAN_SSID_MAXLEN + 1];
+ unsigned int ii , uSameBssidNum=0;
memcpy(abyTmpDesireSSID,pMgmt->abyDesireSSID,sizeof(abyTmpDesireSSID));
pCurr = BSSpSearchBSSList(pDevice,
@@ -906,7 +906,7 @@ if (pMgmt->eScanState == WMAC_IS_SCANNING) {
// by means of judging if there are two same BSSID exist in list ?
for (ii = 0; ii < MAX_BSS_NUM; ii++) {
if (pMgmt->sBSSList[ii].bActive &&
- IS_ETH_ADDRESS_EQUAL(pMgmt->sBSSList[ii].abyBSSID, pCurr->abyBSSID)) {
+ !compare_ether_addr(pMgmt->sBSSList[ii].abyBSSID, pCurr->abyBSSID)) {
uSameBssidNum++;
}
}
@@ -927,7 +927,7 @@ if (pMgmt->eScanState == WMAC_IS_SCANNING) {
}
if (pDevice->flags & DEVICE_FLAGS_OPENED) {
- pDevice->bCommit = TRUE;
+ pDevice->bCommit = true;
}
@@ -981,7 +981,7 @@ int iwctl_siwrate(struct net_device *dev,
int rc = 0;
u8 brate = 0;
int i;
- BYTE abySupportedRates[13]= {0x02, 0x04, 0x0B, 0x16, 0x0c, 0x12, 0x18, 0x24, 0x30, 0x48, 0x60, 0x6C, 0x90};
+ unsigned char abySupportedRates[13]= {0x02, 0x04, 0x0B, 0x16, 0x0c, 0x12, 0x18, 0x24, 0x30, 0x48, 0x60, 0x6C, 0x90};
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCSIWRATE \n");
@@ -1033,7 +1033,7 @@ int iwctl_siwrate(struct net_device *dev,
// Fixed mode
// One rate, fixed
printk("Rate Fix\n");
- pDevice->bFixRate = TRUE;
+ pDevice->bFixRate = true;
if ((pDevice->byBBType == BB_TYPE_11B)&& (brate > 3)) {
pDevice->uConnectionRate = 3;
}
@@ -1044,7 +1044,7 @@ int iwctl_siwrate(struct net_device *dev,
}
else {
- pDevice->bFixRate = FALSE;
+ pDevice->bFixRate = false;
pDevice->uConnectionRate = 13;
printk("auto rate:connection_rate is 13\n");
}
@@ -1068,11 +1068,11 @@ int iwctl_giwrate(struct net_device *dev,
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCGIWRATE \n");
{
- BYTE abySupportedRates[13]= {0x02, 0x04, 0x0B, 0x16, 0x0c, 0x12, 0x18, 0x24, 0x30, 0x48, 0x60, 0x6C, 0x90};
+ unsigned char abySupportedRates[13]= {0x02, 0x04, 0x0B, 0x16, 0x0c, 0x12, 0x18, 0x24, 0x30, 0x48, 0x60, 0x6C, 0x90};
int brate = 0;
//2008-5-8 <modify> by chester
if(pDevice->bLinkPass){
-if(pDevice->bFixRate == TRUE){
+if(pDevice->bFixRate == true){
if (pDevice->uConnectionRate < 13) {
brate = abySupportedRates[pDevice->uConnectionRate];
}else {
@@ -1108,8 +1108,8 @@ else brate =0;
// brate = abySupportedRates[pDevice->wCurrentRate];
wrq->value = brate * 500000;
// If more than one rate, set auto
- if (pDevice->bFixRate == TRUE)
- wrq->fixed = TRUE;
+ if (pDevice->bFixRate == true)
+ wrq->fixed = true;
}
@@ -1294,7 +1294,7 @@ int iwctl_siwencode(struct net_device *dev,
{
PSDevice pDevice = (PSDevice)netdev_priv(dev);
PSMgmtObject pMgmt = &(pDevice->sMgmtObj);
- DWORD dwKeyIndex = (DWORD)(wrq->flags & IW_ENCODE_INDEX);
+ unsigned long dwKeyIndex = (unsigned long)(wrq->flags & IW_ENCODE_INDEX);
int ii,uu, rc = 0;
int index = (wrq->flags & IW_ENCODE_INDEX);
@@ -1358,7 +1358,7 @@ if((wrq->flags & IW_ENCODE_DISABLED)==0){
if (pDevice->flags & DEVICE_FLAGS_OPENED) {
spin_lock_irq(&pDevice->lock);
KeybSetDefaultKey(&(pDevice->sKey),
- (DWORD)(dwKeyIndex | (1 << 31)),
+ (unsigned long)(dwKeyIndex | (1 << 31)),
wrq->length,
NULL,
pDevice->abyKey,
@@ -1368,38 +1368,38 @@ if((wrq->flags & IW_ENCODE_DISABLED)==0){
);
spin_unlock_irq(&pDevice->lock);
}
- pDevice->byKeyIndex = (BYTE)dwKeyIndex;
+ pDevice->byKeyIndex = (unsigned char)dwKeyIndex;
pDevice->uKeyLength = wrq->length;
- pDevice->bTransmitKey = TRUE;
- pDevice->bEncryptionEnable = TRUE;
+ pDevice->bTransmitKey = true;
+ pDevice->bEncryptionEnable = true;
pDevice->eEncryptionStatus = Ndis802_11Encryption1Enabled;
}else if(index>0){
//when the length is 0 the request only changes the default transmit key index
//check the new key has a non zero lenget
- if(pDevice->bEncryptionEnable==FALSE)
+ if(pDevice->bEncryptionEnable==false)
{
rc = -EINVAL;
return rc;
}
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Just set Default key Index:\n");
pkeytab=&(pDevice->sKey.KeyTable[MAX_KEY_TABLE-1]);
- if(pkeytab->GroupKey[(BYTE)dwKeyIndex].uKeyLength==0){
+ if(pkeytab->GroupKey[(unsigned char)dwKeyIndex].uKeyLength==0){
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Default key len is 0\n");
rc = -EINVAL;
return rc;
}
- pDevice->byKeyIndex =(BYTE)dwKeyIndex;
+ pDevice->byKeyIndex =(unsigned char)dwKeyIndex;
pkeytab->dwGTKeyIndex =dwKeyIndex | (1 << 31);
- pkeytab->GroupKey[(BYTE)dwKeyIndex].dwKeyIndex=dwKeyIndex | (1 << 31);
+ pkeytab->GroupKey[(unsigned char)dwKeyIndex].dwKeyIndex=dwKeyIndex | (1 << 31);
}
}else {//disable the key
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Disable WEP function\n");
- if(pDevice->bEncryptionEnable==FALSE)
+ if(pDevice->bEncryptionEnable==false)
return 0;
- pMgmt->bShareKeyAlgorithm = FALSE;
- pDevice->bEncryptionEnable = FALSE;
+ pMgmt->bShareKeyAlgorithm = false;
+ pDevice->bEncryptionEnable = false;
pDevice->eEncryptionStatus = Ndis802_11EncryptionDisabled;
if (pDevice->flags & DEVICE_FLAGS_OPENED) {
spin_lock_irq(&pDevice->lock);
@@ -1450,7 +1450,7 @@ if((wrq->flags & IW_ENCODE_DISABLED)==0){
if (pDevice->flags & DEVICE_FLAGS_OPENED) {
spin_lock_irq(&pDevice->lock);
KeybSetDefaultKey(&(pDevice->sKey),
- (DWORD)(pDevice->byKeyIndex | (1 << 31)),
+ (unsigned long)(pDevice->byKeyIndex | (1 << 31)),
pDevice->uKeyLength,
NULL,
pDevice->abyKey,
@@ -1460,10 +1460,10 @@ if((wrq->flags & IW_ENCODE_DISABLED)==0){
);
spin_unlock_irq(&pDevice->lock);
}
- pDevice->byKeyIndex = (BYTE)dwKeyIndex;
+ pDevice->byKeyIndex = (unsigned char)dwKeyIndex;
pDevice->uKeyLength = wrq->length;
- pDevice->bTransmitKey = TRUE;
- pDevice->bEncryptionEnable = TRUE;
+ pDevice->bTransmitKey = true;
+ pDevice->bEncryptionEnable = true;
pDevice->eEncryptionStatus = Ndis802_11Encryption1Enabled;
// Do we want to just set the transmit key index ?
@@ -1479,8 +1479,8 @@ if((wrq->flags & IW_ENCODE_DISABLED)==0){
if(wrq->flags & IW_ENCODE_DISABLED){
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Disable WEP function\n");
- pMgmt->bShareKeyAlgorithm = FALSE;
- pDevice->bEncryptionEnable = FALSE;
+ pMgmt->bShareKeyAlgorithm = false;
+ pDevice->bEncryptionEnable = false;
pDevice->eEncryptionStatus = Ndis802_11EncryptionDisabled;
if (pDevice->flags & DEVICE_FLAGS_OPENED) {
spin_lock_irq(&pDevice->lock);
@@ -1493,11 +1493,11 @@ if((wrq->flags & IW_ENCODE_DISABLED)==0){
if(wrq->flags & IW_ENCODE_RESTRICTED) {
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Enable WEP & ShareKey System\n");
- pMgmt->bShareKeyAlgorithm = TRUE;
+ pMgmt->bShareKeyAlgorithm = true;
}
if(wrq->flags & IW_ENCODE_OPEN) {
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Enable WEP & Open System\n");
- pMgmt->bShareKeyAlgorithm = FALSE;
+ pMgmt->bShareKeyAlgorithm = false;
}
return rc;
}
@@ -1515,7 +1515,7 @@ int iwctl_giwencode(struct net_device *dev,
PSMgmtObject pMgmt = &(pDevice->sMgmtObj);
int rc = 0;
char abyKey[WLAN_WEP232_KEYLEN];
- UINT index = (UINT)(wrq->flags & IW_ENCODE_INDEX);
+ unsigned int index = (unsigned int)(wrq->flags & IW_ENCODE_INDEX);
PSKeyItem pKey = NULL;
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCGIWENCODE\n");
@@ -1549,7 +1549,7 @@ int iwctl_giwencode(struct net_device *dev,
else
wrq->flags |= IW_ENCODE_OPEN;
- if (KeybGetKey(&(pDevice->sKey), pDevice->abyBroadcastAddr, (BYTE)index , &pKey)){
+ if (KeybGetKey(&(pDevice->sKey), pDevice->abyBroadcastAddr, (unsigned char)index , &pKey)){
wrq->length = pKey->uKeyLength;
memcpy(abyKey, pKey->abyKey, pKey->uKeyLength);
//2007-0207-06,<Modify> by EinsnLiu
@@ -1584,7 +1584,7 @@ int iwctl_giwencode(struct net_device *dev,
PSMgmtObject pMgmt = &(pDevice->sMgmtObj);
char abyKey[WLAN_WEP232_KEYLEN];
- UINT index = (UINT)(wrq->flags & IW_ENCODE_INDEX);
+ unsigned int index = (unsigned int)(wrq->flags & IW_ENCODE_INDEX);
PSKeyItem pKey = NULL;
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCGIWENCODE\n");
@@ -1622,7 +1622,7 @@ int iwctl_giwencode(struct net_device *dev,
memcpy(abyKey, pKey->abyKey, pKey->uKeyLength);
memcpy(extra, abyKey, WLAN_WEP232_KEYLEN);
}
- }else if (KeybGetKey(&(pDevice->sKey), pDevice->abyBroadcastAddr, (BYTE)index , &pKey)){
+ }else if (KeybGetKey(&(pDevice->sKey), pDevice->abyBroadcastAddr, (unsigned char)index , &pKey)){
wrq->length = pKey->uKeyLength;
memcpy(abyKey, pKey->abyKey, pKey->uKeyLength);
memcpy(extra, abyKey, WLAN_WEP232_KEYLEN);
@@ -1729,8 +1729,8 @@ int iwctl_giwsens(struct net_device *dev,
long ldBm;
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCGIWSENS \n");
- if (pDevice->bLinkPass == TRUE) {
- RFvRSSITodBm(pDevice, (BYTE)(pDevice->uCurrRSSI), &ldBm);
+ if (pDevice->bLinkPass == true) {
+ RFvRSSITodBm(pDevice, (unsigned char)(pDevice->uCurrRSSI), &ldBm);
wrq->value = ldBm;
}
else {
@@ -1763,7 +1763,7 @@ int iwctl_siwauth(struct net_device *dev,
wpa_version = wrq->value;
if(wrq->value == IW_AUTH_WPA_VERSION_DISABLED) {
PRINT_K("iwctl_siwauth:set WPADEV to disable at 1??????\n");
- //pDevice->bWPADevEnable = FALSE;
+ //pDevice->bWPADevEnable = false;
}
else if(wrq->value == IW_AUTH_WPA_VERSION_WPA) {
PRINT_K("iwctl_siwauth:set WPADEV to WPA1******\n");
@@ -1771,7 +1771,7 @@ int iwctl_siwauth(struct net_device *dev,
else {
PRINT_K("iwctl_siwauth:set WPADEV to WPA2******\n");
}
- //pDevice->bWPASuppWextEnabled =TRUE;
+ //pDevice->bWPASuppWextEnabled =true;
break;
case IW_AUTH_CIPHER_PAIRWISE:
pairwise = wrq->value;
@@ -1818,9 +1818,9 @@ int iwctl_siwauth(struct net_device *dev,
break;
case IW_AUTH_80211_AUTH_ALG:
if(wrq->value==IW_AUTH_ALG_OPEN_SYSTEM){
- pMgmt->bShareKeyAlgorithm=FALSE;
+ pMgmt->bShareKeyAlgorithm=false;
}else if(wrq->value==IW_AUTH_ALG_SHARED_KEY){
- pMgmt->bShareKeyAlgorithm=TRUE;
+ pMgmt->bShareKeyAlgorithm=true;
}
break;
case IW_AUTH_WPA_ENABLED:
@@ -1833,13 +1833,13 @@ int iwctl_siwauth(struct net_device *dev,
break;
case IW_AUTH_PRIVACY_INVOKED:
pDevice->bEncryptionEnable = !!wrq->value;
- if(pDevice->bEncryptionEnable == FALSE){
+ if(pDevice->bEncryptionEnable == false){
wpa_version = 0;
pairwise = 0;
pDevice->eEncryptionStatus = Ndis802_11EncryptionDisabled;
- pMgmt->bShareKeyAlgorithm = FALSE;
- pMgmt->eAuthenMode = FALSE;
- //pDevice->bWPADevEnable = FALSE;
+ pMgmt->bShareKeyAlgorithm = false;
+ pMgmt->eAuthenMode = false;
+ //pDevice->bWPADevEnable = false;
}
break;
@@ -1852,9 +1852,9 @@ int iwctl_siwauth(struct net_device *dev,
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "pairwise = %d\n",pairwise);
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "pDevice->eEncryptionStatus = %d\n",pDevice->eEncryptionStatus);
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "pMgmt->eAuthenMode = %d\n",pMgmt->eAuthenMode);
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "pMgmt->bShareKeyAlgorithm = %s\n",pMgmt->bShareKeyAlgorithm?"TRUE":"FALSE");
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "pDevice->bEncryptionEnable = %s\n",pDevice->bEncryptionEnable?"TRUE":"FALSE");
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "pDevice->bWPADevEnable = %s\n",pDevice->bWPADevEnable?"TRUE":"FALSE");
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "pMgmt->bShareKeyAlgorithm = %s\n",pMgmt->bShareKeyAlgorithm?"true":"false");
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "pDevice->bEncryptionEnable = %s\n",pDevice->bEncryptionEnable?"true":"false");
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "pDevice->bWPADevEnable = %s\n",pDevice->bWPADevEnable?"true":"false");
*/
return ret;
}
@@ -2055,12 +2055,12 @@ if(param->u.wpa_key.alg_name == WPA_ALG_NONE) {
if( pDevice->bwextcount == 4) {
printk("SIOCSIWENCODEEXT:Enable WPA WEXT SUPPORT!!!!!\n");
pDevice->bwextcount=0;
- pDevice->bWPASuppWextEnabled = TRUE;
+ pDevice->bWPASuppWextEnabled = true;
}
//******
spin_lock_irq(&pDevice->lock);
- ret = wpa_set_keys(pDevice, param, TRUE);
+ ret = wpa_set_keys(pDevice, param, true);
spin_unlock_irq(&pDevice->lock);
error:
@@ -2096,10 +2096,10 @@ int iwctl_siwmlme(struct net_device *dev,
switch(mlme->cmd){
case IW_MLME_DEAUTH:
//this command seems to be not complete,please test it --einsnliu
- //bScheduleCommand((void *) pDevice, WLAN_CMD_DEAUTH, (PBYTE)&reason);
+ //bScheduleCommand((void *) pDevice, WLAN_CMD_DEAUTH, (unsigned char *)&reason);
break;
case IW_MLME_DISASSOC:
- if(pDevice->bLinkPass == TRUE){
+ if(pDevice->bLinkPass == true){
printk("iwctl_siwmlme--->send DISASSOCIATE\n");
//clear related flags
memset(pMgmt->abyDesireBSSID, 0xFF,6);
diff --git a/drivers/staging/vt6655/key.c b/drivers/staging/vt6655/key.c
index bfc5c509d90..0ff8d7bbf2a 100644
--- a/drivers/staging/vt6655/key.c
+++ b/drivers/staging/vt6655/key.c
@@ -59,22 +59,22 @@ static int msglevel =MSG_LEVEL_INFO;
/*--------------------- Static Functions --------------------------*/
static void
-s_vCheckKeyTableValid (PSKeyManagement pTable, DWORD_PTR dwIoBase)
+s_vCheckKeyTableValid (PSKeyManagement pTable, unsigned long dwIoBase)
{
int i;
for (i=0;i<MAX_KEY_TABLE;i++) {
- if ((pTable->KeyTable[i].bInUse == TRUE) &&
- (pTable->KeyTable[i].PairwiseKey.bKeyValid == FALSE) &&
- (pTable->KeyTable[i].GroupKey[0].bKeyValid == FALSE) &&
- (pTable->KeyTable[i].GroupKey[1].bKeyValid == FALSE) &&
- (pTable->KeyTable[i].GroupKey[2].bKeyValid == FALSE) &&
- (pTable->KeyTable[i].GroupKey[3].bKeyValid == FALSE)
+ if ((pTable->KeyTable[i].bInUse == true) &&
+ (pTable->KeyTable[i].PairwiseKey.bKeyValid == false) &&
+ (pTable->KeyTable[i].GroupKey[0].bKeyValid == false) &&
+ (pTable->KeyTable[i].GroupKey[1].bKeyValid == false) &&
+ (pTable->KeyTable[i].GroupKey[2].bKeyValid == false) &&
+ (pTable->KeyTable[i].GroupKey[3].bKeyValid == false)
) {
- pTable->KeyTable[i].bInUse = FALSE;
+ pTable->KeyTable[i].bInUse = false;
pTable->KeyTable[i].wKeyCtl = 0;
- pTable->KeyTable[i].bSoftWEP = FALSE;
+ pTable->KeyTable[i].bSoftWEP = false;
MACvDisableKeyEntry(dwIoBase, i);
}
}
@@ -96,22 +96,22 @@ s_vCheckKeyTableValid (PSKeyManagement pTable, DWORD_PTR dwIoBase)
* Return Value: none
*
*/
-void KeyvInitTable (PSKeyManagement pTable, DWORD_PTR dwIoBase)
+void KeyvInitTable (PSKeyManagement pTable, unsigned long dwIoBase)
{
int i;
int jj;
for (i=0;i<MAX_KEY_TABLE;i++) {
- pTable->KeyTable[i].bInUse = FALSE;
- pTable->KeyTable[i].PairwiseKey.bKeyValid = FALSE;
+ pTable->KeyTable[i].bInUse = false;
+ pTable->KeyTable[i].PairwiseKey.bKeyValid = false;
pTable->KeyTable[i].PairwiseKey.pvKeyTable = (void *)&pTable->KeyTable[i];
for (jj=0; jj < MAX_GROUP_KEY; jj++) {
- pTable->KeyTable[i].GroupKey[jj].bKeyValid = FALSE;
+ pTable->KeyTable[i].GroupKey[jj].bKeyValid = false;
pTable->KeyTable[i].GroupKey[jj].pvKeyTable = (void *)&pTable->KeyTable[i];
}
pTable->KeyTable[i].wKeyCtl = 0;
pTable->KeyTable[i].dwGTKeyIndex = 0;
- pTable->KeyTable[i].bSoftWEP = FALSE;
+ pTable->KeyTable[i].bSoftWEP = false;
MACvDisableKeyEntry(dwIoBase, i);
}
}
@@ -128,13 +128,13 @@ void KeyvInitTable (PSKeyManagement pTable, DWORD_PTR dwIoBase)
* Out:
* pKey - Key return
*
- * Return Value: TRUE if found otherwise FALSE
+ * Return Value: true if found otherwise false
*
*/
-BOOL KeybGetKey (
+bool KeybGetKey (
PSKeyManagement pTable,
- PBYTE pbyBSSID,
- DWORD dwKeyIndex,
+ unsigned char *pbyBSSID,
+ unsigned long dwKeyIndex,
PSKeyItem *pKey
)
{
@@ -144,31 +144,31 @@ BOOL KeybGetKey (
*pKey = NULL;
for (i=0;i<MAX_KEY_TABLE;i++) {
- if ((pTable->KeyTable[i].bInUse == TRUE) &&
- IS_ETH_ADDRESS_EQUAL(pTable->KeyTable[i].abyBSSID,pbyBSSID)) {
+ if ((pTable->KeyTable[i].bInUse == true) &&
+ !compare_ether_addr(pTable->KeyTable[i].abyBSSID, pbyBSSID)) {
if (dwKeyIndex == 0xFFFFFFFF) {
- if (pTable->KeyTable[i].PairwiseKey.bKeyValid == TRUE) {
+ if (pTable->KeyTable[i].PairwiseKey.bKeyValid == true) {
*pKey = &(pTable->KeyTable[i].PairwiseKey);
- return (TRUE);
+ return (true);
}
else {
- return (FALSE);
+ return (false);
}
} else if (dwKeyIndex < MAX_GROUP_KEY) {
- if (pTable->KeyTable[i].GroupKey[dwKeyIndex].bKeyValid == TRUE) {
+ if (pTable->KeyTable[i].GroupKey[dwKeyIndex].bKeyValid == true) {
*pKey = &(pTable->KeyTable[i].GroupKey[dwKeyIndex]);
- return (TRUE);
+ return (true);
}
else {
- return (FALSE);
+ return (false);
}
}
else {
- return (FALSE);
+ return (false);
}
}
}
- return (FALSE);
+ return (false);
}
@@ -186,37 +186,37 @@ BOOL KeybGetKey (
* Out:
* none
*
- * Return Value: TRUE if success otherwise FALSE
+ * Return Value: true if success otherwise false
*
*/
-BOOL KeybSetKey (
+bool KeybSetKey (
PSKeyManagement pTable,
- PBYTE pbyBSSID,
- DWORD dwKeyIndex,
- ULONG uKeyLength,
+ unsigned char *pbyBSSID,
+ unsigned long dwKeyIndex,
+ unsigned long uKeyLength,
PQWORD pKeyRSC,
- PBYTE pbyKey,
- BYTE byKeyDecMode,
- DWORD_PTR dwIoBase,
- BYTE byLocalID
+ unsigned char *pbyKey,
+ unsigned char byKeyDecMode,
+ unsigned long dwIoBase,
+ unsigned char byLocalID
)
{
int i,j;
- UINT ii;
+ unsigned int ii;
PSKeyItem pKey;
- UINT uKeyIdx;
+ unsigned int uKeyIdx;
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Enter KeybSetKey: %lX\n", dwKeyIndex);
j = (MAX_KEY_TABLE-1);
for (i=0;i<(MAX_KEY_TABLE-1);i++) {
- if ((pTable->KeyTable[i].bInUse == FALSE) &&
+ if ((pTable->KeyTable[i].bInUse == false) &&
(j == (MAX_KEY_TABLE-1))) {
// found empty table
j = i;
}
- if ((pTable->KeyTable[i].bInUse == TRUE) &&
- IS_ETH_ADDRESS_EQUAL(pTable->KeyTable[i].abyBSSID,pbyBSSID)) {
+ if ((pTable->KeyTable[i].bInUse == true) &&
+ !compare_ether_addr(pTable->KeyTable[i].abyBSSID, pbyBSSID)) {
// found table already exist
if ((dwKeyIndex & PAIRWISE_KEY) != 0) {
// Pairwise key
@@ -227,7 +227,7 @@ BOOL KeybSetKey (
} else {
// Group key
if ((dwKeyIndex & 0x000000FF) >= MAX_GROUP_KEY)
- return (FALSE);
+ return (false);
pKey = &(pTable->KeyTable[i].GroupKey[dwKeyIndex & 0x000000FF]);
if ((dwKeyIndex & TRANSMIT_KEY) != 0) {
// Group transmit key
@@ -241,7 +241,7 @@ BOOL KeybSetKey (
}
pTable->KeyTable[i].wKeyCtl |= 0x8000; // enable on-fly
- pKey->bKeyValid = TRUE;
+ pKey->bKeyValid = true;
pKey->uKeyLength = uKeyLength;
pKey->dwKeyIndex = dwKeyIndex;
pKey->byCipherSuite = byKeyDecMode;
@@ -252,7 +252,7 @@ BOOL KeybSetKey (
if (uKeyLength == WLAN_WEP104_KEYLEN)
pKey->abyKey[15] |= 0x80;
}
- MACvSetKeyEntry(dwIoBase, pTable->KeyTable[i].wKeyCtl, i, uKeyIdx, pbyBSSID, (PDWORD)pKey->abyKey, byLocalID);
+ MACvSetKeyEntry(dwIoBase, pTable->KeyTable[i].wKeyCtl, i, uKeyIdx, pbyBSSID, (unsigned long *)pKey->abyKey, byLocalID);
if ((dwKeyIndex & USE_KEYRSC) == 0) {
// RSC set by NIC
@@ -277,12 +277,12 @@ BOOL KeybSetKey (
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"pKey->wTSC15_0: %x\n ", pKey->wTSC15_0);
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"pKey->dwKeyIndex: %lx\n ", pKey->dwKeyIndex);
- return (TRUE);
+ return (true);
}
}
if (j < (MAX_KEY_TABLE-1)) {
memcpy(pTable->KeyTable[j].abyBSSID,pbyBSSID,ETH_ALEN);
- pTable->KeyTable[j].bInUse = TRUE;
+ pTable->KeyTable[j].bInUse = true;
if ((dwKeyIndex & PAIRWISE_KEY) != 0) {
// Pairwise key
pKey = &(pTable->KeyTable[j].PairwiseKey);
@@ -292,7 +292,7 @@ BOOL KeybSetKey (
} else {
// Group key
if ((dwKeyIndex & 0x000000FF) >= MAX_GROUP_KEY)
- return (FALSE);
+ return (false);
pKey = &(pTable->KeyTable[j].GroupKey[dwKeyIndex & 0x000000FF]);
if ((dwKeyIndex & TRANSMIT_KEY) != 0) {
// Group transmit key
@@ -306,7 +306,7 @@ BOOL KeybSetKey (
}
pTable->KeyTable[j].wKeyCtl |= 0x8000; // enable on-fly
- pKey->bKeyValid = TRUE;
+ pKey->bKeyValid = true;
pKey->uKeyLength = uKeyLength;
pKey->dwKeyIndex = dwKeyIndex;
pKey->byCipherSuite = byKeyDecMode;
@@ -317,7 +317,7 @@ BOOL KeybSetKey (
if (uKeyLength == WLAN_WEP104_KEYLEN)
pKey->abyKey[15] |= 0x80;
}
- MACvSetKeyEntry(dwIoBase, pTable->KeyTable[j].wKeyCtl, j, uKeyIdx, pbyBSSID, (PDWORD)pKey->abyKey, byLocalID);
+ MACvSetKeyEntry(dwIoBase, pTable->KeyTable[j].wKeyCtl, j, uKeyIdx, pbyBSSID, (unsigned long *)pKey->abyKey, byLocalID);
if ((dwKeyIndex & USE_KEYRSC) == 0) {
// RSC set by NIC
@@ -342,9 +342,9 @@ BOOL KeybSetKey (
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"pKey->wTSC15_0: %x\n ", pKey->wTSC15_0);
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"pKey->dwKeyIndex: %lx\n ", pKey->dwKeyIndex);
- return (TRUE);
+ return (true);
}
- return (FALSE);
+ return (false);
}
@@ -359,66 +359,66 @@ BOOL KeybSetKey (
* Out:
* none
*
- * Return Value: TRUE if success otherwise FALSE
+ * Return Value: true if success otherwise false
*
*/
-BOOL KeybRemoveKey (
+bool KeybRemoveKey (
PSKeyManagement pTable,
- PBYTE pbyBSSID,
- DWORD dwKeyIndex,
- DWORD_PTR dwIoBase
+ unsigned char *pbyBSSID,
+ unsigned long dwKeyIndex,
+ unsigned long dwIoBase
)
{
int i;
- if (IS_BROADCAST_ADDRESS(pbyBSSID)) {
+ if (is_broadcast_ether_addr(pbyBSSID)) {
// dealte all key
if ((dwKeyIndex & PAIRWISE_KEY) != 0) {
for (i=0;i<MAX_KEY_TABLE;i++) {
- pTable->KeyTable[i].PairwiseKey.bKeyValid = FALSE;
+ pTable->KeyTable[i].PairwiseKey.bKeyValid = false;
}
s_vCheckKeyTableValid(pTable, dwIoBase);
- return TRUE;
+ return true;
}
else if ((dwKeyIndex & 0x000000FF) < MAX_GROUP_KEY) {
for (i=0;i<MAX_KEY_TABLE;i++) {
- pTable->KeyTable[i].GroupKey[dwKeyIndex & 0x000000FF].bKeyValid = FALSE;
+ pTable->KeyTable[i].GroupKey[dwKeyIndex & 0x000000FF].bKeyValid = false;
if ((dwKeyIndex & 0x7FFFFFFF) == (pTable->KeyTable[i].dwGTKeyIndex & 0x7FFFFFFF)) {
// remove Group transmit key
pTable->KeyTable[i].dwGTKeyIndex = 0;
}
}
s_vCheckKeyTableValid(pTable, dwIoBase);
- return TRUE;
+ return true;
}
else {
- return FALSE;
+ return false;
}
}
for (i=0;i<MAX_KEY_TABLE;i++) {
- if ((pTable->KeyTable[i].bInUse == TRUE) &&
- IS_ETH_ADDRESS_EQUAL(pTable->KeyTable[i].abyBSSID,pbyBSSID)) {
+ if ((pTable->KeyTable[i].bInUse == true) &&
+ !compare_ether_addr(pTable->KeyTable[i].abyBSSID, pbyBSSID)) {
if ((dwKeyIndex & PAIRWISE_KEY) != 0) {
- pTable->KeyTable[i].PairwiseKey.bKeyValid = FALSE;
+ pTable->KeyTable[i].PairwiseKey.bKeyValid = false;
s_vCheckKeyTableValid(pTable, dwIoBase);
- return (TRUE);
+ return (true);
}
else if ((dwKeyIndex & 0x000000FF) < MAX_GROUP_KEY) {
- pTable->KeyTable[i].GroupKey[dwKeyIndex & 0x000000FF].bKeyValid = FALSE;
+ pTable->KeyTable[i].GroupKey[dwKeyIndex & 0x000000FF].bKeyValid = false;
if ((dwKeyIndex & 0x7FFFFFFF) == (pTable->KeyTable[i].dwGTKeyIndex & 0x7FFFFFFF)) {
// remove Group transmit key
pTable->KeyTable[i].dwGTKeyIndex = 0;
}
s_vCheckKeyTableValid(pTable, dwIoBase);
- return (TRUE);
+ return (true);
}
else {
- return (FALSE);
+ return (false);
}
}
}
- return (FALSE);
+ return (false);
}
@@ -432,30 +432,30 @@ BOOL KeybRemoveKey (
* Out:
* none
*
- * Return Value: TRUE if success otherwise FALSE
+ * Return Value: true if success otherwise false
*
*/
-BOOL KeybRemoveAllKey (
+bool KeybRemoveAllKey (
PSKeyManagement pTable,
- PBYTE pbyBSSID,
- DWORD_PTR dwIoBase
+ unsigned char *pbyBSSID,
+ unsigned long dwIoBase
)
{
int i,u;
for (i=0;i<MAX_KEY_TABLE;i++) {
- if ((pTable->KeyTable[i].bInUse == TRUE) &&
- IS_ETH_ADDRESS_EQUAL(pTable->KeyTable[i].abyBSSID,pbyBSSID)) {
- pTable->KeyTable[i].PairwiseKey.bKeyValid = FALSE;
+ if ((pTable->KeyTable[i].bInUse == true) &&
+ !compare_ether_addr(pTable->KeyTable[i].abyBSSID, pbyBSSID)) {
+ pTable->KeyTable[i].PairwiseKey.bKeyValid = false;
for(u=0;u<MAX_GROUP_KEY;u++) {
- pTable->KeyTable[i].GroupKey[u].bKeyValid = FALSE;
+ pTable->KeyTable[i].GroupKey[u].bKeyValid = false;
}
pTable->KeyTable[i].dwGTKeyIndex = 0;
s_vCheckKeyTableValid(pTable, dwIoBase);
- return (TRUE);
+ return (true);
}
}
- return (FALSE);
+ return (false);
}
/*
@@ -467,20 +467,20 @@ BOOL KeybRemoveAllKey (
* Out:
* none
*
- * Return Value: TRUE if success otherwise FALSE
+ * Return Value: true if success otherwise false
*
*/
void KeyvRemoveWEPKey (
PSKeyManagement pTable,
- DWORD dwKeyIndex,
- DWORD_PTR dwIoBase
+ unsigned long dwKeyIndex,
+ unsigned long dwIoBase
)
{
if ((dwKeyIndex & 0x000000FF) < MAX_GROUP_KEY) {
- if (pTable->KeyTable[MAX_KEY_TABLE-1].bInUse == TRUE) {
+ if (pTable->KeyTable[MAX_KEY_TABLE-1].bInUse == true) {
if (pTable->KeyTable[MAX_KEY_TABLE-1].GroupKey[dwKeyIndex & 0x000000FF].byCipherSuite == KEY_CTL_WEP) {
- pTable->KeyTable[MAX_KEY_TABLE-1].GroupKey[dwKeyIndex & 0x000000FF].bKeyValid = FALSE;
+ pTable->KeyTable[MAX_KEY_TABLE-1].GroupKey[dwKeyIndex & 0x000000FF].bKeyValid = false;
if ((dwKeyIndex & 0x7FFFFFFF) == (pTable->KeyTable[MAX_KEY_TABLE-1].dwGTKeyIndex & 0x7FFFFFFF)) {
// remove Group transmit key
pTable->KeyTable[MAX_KEY_TABLE-1].dwGTKeyIndex = 0;
@@ -494,7 +494,7 @@ void KeyvRemoveWEPKey (
void KeyvRemoveAllWEPKey (
PSKeyManagement pTable,
- DWORD_PTR dwIoBase
+ unsigned long dwIoBase
)
{
int i;
@@ -514,13 +514,13 @@ void KeyvRemoveAllWEPKey (
* Out:
* pKey - Key return
*
- * Return Value: TRUE if found otherwise FALSE
+ * Return Value: true if found otherwise false
*
*/
-BOOL KeybGetTransmitKey (
+bool KeybGetTransmitKey (
PSKeyManagement pTable,
- PBYTE pbyBSSID,
- DWORD dwKeyType,
+ unsigned char *pbyBSSID,
+ unsigned long dwKeyType,
PSKeyItem *pKey
)
{
@@ -528,12 +528,12 @@ BOOL KeybGetTransmitKey (
*pKey = NULL;
for (i=0;i<MAX_KEY_TABLE;i++) {
- if ((pTable->KeyTable[i].bInUse == TRUE) &&
- IS_ETH_ADDRESS_EQUAL(pTable->KeyTable[i].abyBSSID,pbyBSSID)) {
+ if ((pTable->KeyTable[i].bInUse == true) &&
+ !compare_ether_addr(pTable->KeyTable[i].abyBSSID, pbyBSSID)) {
if (dwKeyType == PAIRWISE_KEY) {
- if (pTable->KeyTable[i].PairwiseKey.bKeyValid == TRUE) {
+ if (pTable->KeyTable[i].PairwiseKey.bKeyValid == true) {
*pKey = &(pTable->KeyTable[i].PairwiseKey);
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"KeybGetTransmitKey:");
@@ -544,19 +544,19 @@ BOOL KeybGetTransmitKey (
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"\n");
- return (TRUE);
+ return (true);
}
else {
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"PairwiseKey.bKeyValid == FALSE\n");
- return (FALSE);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"PairwiseKey.bKeyValid == false\n");
+ return (false);
}
} // End of Type == PAIRWISE
else {
if (pTable->KeyTable[i].dwGTKeyIndex == 0) {
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"ERROR: dwGTKeyIndex == 0 !!!\n");
- return FALSE;
+ return false;
}
- if (pTable->KeyTable[i].GroupKey[(pTable->KeyTable[i].dwGTKeyIndex&0x000000FF)].bKeyValid == TRUE) {
+ if (pTable->KeyTable[i].GroupKey[(pTable->KeyTable[i].dwGTKeyIndex&0x000000FF)].bKeyValid == true) {
*pKey = &(pTable->KeyTable[i].GroupKey[(pTable->KeyTable[i].dwGTKeyIndex&0x000000FF)]);
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"KeybGetTransmitKey:");
@@ -567,11 +567,11 @@ BOOL KeybGetTransmitKey (
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"\n");
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"dwGTKeyIndex: %lX\n", pTable->KeyTable[i].dwGTKeyIndex);
- return (TRUE);
+ return (true);
}
else {
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"GroupKey.bKeyValid == FALSE\n");
- return (FALSE);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"GroupKey.bKeyValid == false\n");
+ return (false);
}
} // End of Type = GROUP
} // BSSID match
@@ -581,7 +581,7 @@ BOOL KeybGetTransmitKey (
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"%02x ", *(pbyBSSID+ii));
}
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"\n");
- return (FALSE);
+ return (false);
}
@@ -594,10 +594,10 @@ BOOL KeybGetTransmitKey (
* Out:
* none
*
- * Return Value: TRUE if found otherwise FALSE
+ * Return Value: true if found otherwise false
*
*/
-BOOL KeybCheckPairewiseKey (
+bool KeybCheckPairewiseKey (
PSKeyManagement pTable,
PSKeyItem *pKey
)
@@ -606,13 +606,13 @@ BOOL KeybCheckPairewiseKey (
*pKey = NULL;
for (i=0;i<MAX_KEY_TABLE;i++) {
- if ((pTable->KeyTable[i].bInUse == TRUE) &&
- (pTable->KeyTable[i].PairwiseKey.bKeyValid == TRUE)) {
+ if ((pTable->KeyTable[i].bInUse == true) &&
+ (pTable->KeyTable[i].PairwiseKey.bKeyValid == true)) {
*pKey = &(pTable->KeyTable[i].PairwiseKey);
- return (TRUE);
+ return (true);
}
}
- return (FALSE);
+ return (false);
}
/*
@@ -628,34 +628,34 @@ BOOL KeybCheckPairewiseKey (
* Out:
* none
*
- * Return Value: TRUE if success otherwise FALSE
+ * Return Value: true if success otherwise false
*
*/
-BOOL KeybSetDefaultKey (
+bool KeybSetDefaultKey (
PSKeyManagement pTable,
- DWORD dwKeyIndex,
- ULONG uKeyLength,
+ unsigned long dwKeyIndex,
+ unsigned long uKeyLength,
PQWORD pKeyRSC,
- PBYTE pbyKey,
- BYTE byKeyDecMode,
- DWORD_PTR dwIoBase,
- BYTE byLocalID
+ unsigned char *pbyKey,
+ unsigned char byKeyDecMode,
+ unsigned long dwIoBase,
+ unsigned char byLocalID
)
{
- UINT ii;
+ unsigned int ii;
PSKeyItem pKey;
- UINT uKeyIdx;
+ unsigned int uKeyIdx;
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Enter KeybSetDefaultKey: %1x, %d \n", (int)dwKeyIndex, (int)uKeyLength);
if ((dwKeyIndex & PAIRWISE_KEY) != 0) { // Pairwise key
- return (FALSE);
+ return (false);
} else if ((dwKeyIndex & 0x000000FF) >= MAX_GROUP_KEY) {
- return (FALSE);
+ return (false);
}
- pTable->KeyTable[MAX_KEY_TABLE-1].bInUse = TRUE;
+ pTable->KeyTable[MAX_KEY_TABLE-1].bInUse = true;
for(ii=0;ii<ETH_ALEN;ii++)
pTable->KeyTable[MAX_KEY_TABLE-1].abyBSSID[ii] = 0xFF;
@@ -676,13 +676,13 @@ BOOL KeybSetDefaultKey (
if ((uKeyLength == WLAN_WEP232_KEYLEN) &&
(byKeyDecMode == KEY_CTL_WEP)) {
pTable->KeyTable[MAX_KEY_TABLE-1].wKeyCtl |= 0x4000; // disable on-fly disable address match
- pTable->KeyTable[MAX_KEY_TABLE-1].bSoftWEP = TRUE;
+ pTable->KeyTable[MAX_KEY_TABLE-1].bSoftWEP = true;
} else {
- if (pTable->KeyTable[MAX_KEY_TABLE-1].bSoftWEP == FALSE)
+ if (pTable->KeyTable[MAX_KEY_TABLE-1].bSoftWEP == false)
pTable->KeyTable[MAX_KEY_TABLE-1].wKeyCtl |= 0xC000; // enable on-fly disable address match
}
- pKey->bKeyValid = TRUE;
+ pKey->bKeyValid = true;
pKey->uKeyLength = uKeyLength;
pKey->dwKeyIndex = dwKeyIndex;
pKey->byCipherSuite = byKeyDecMode;
@@ -693,7 +693,7 @@ BOOL KeybSetDefaultKey (
if (uKeyLength == WLAN_WEP104_KEYLEN)
pKey->abyKey[15] |= 0x80;
}
- MACvSetKeyEntry(dwIoBase, pTable->KeyTable[MAX_KEY_TABLE-1].wKeyCtl, MAX_KEY_TABLE-1, uKeyIdx, pTable->KeyTable[MAX_KEY_TABLE-1].abyBSSID, (PDWORD)pKey->abyKey, byLocalID);
+ MACvSetKeyEntry(dwIoBase, pTable->KeyTable[MAX_KEY_TABLE-1].wKeyCtl, MAX_KEY_TABLE-1, uKeyIdx, pTable->KeyTable[MAX_KEY_TABLE-1].abyBSSID, (unsigned long *)pKey->abyKey, byLocalID);
if ((dwKeyIndex & USE_KEYRSC) == 0) {
// RSC set by NIC
@@ -718,7 +718,7 @@ BOOL KeybSetDefaultKey (
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"pKey->wTSC15_0: %x\n", pKey->wTSC15_0);
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"pKey->dwKeyIndex: %lx\n", pKey->dwKeyIndex);
- return (TRUE);
+ return (true);
}
@@ -735,36 +735,36 @@ BOOL KeybSetDefaultKey (
* Out:
* none
*
- * Return Value: TRUE if success otherwise FALSE
+ * Return Value: true if success otherwise false
*
*/
-BOOL KeybSetAllGroupKey (
+bool KeybSetAllGroupKey (
PSKeyManagement pTable,
- DWORD dwKeyIndex,
- ULONG uKeyLength,
+ unsigned long dwKeyIndex,
+ unsigned long uKeyLength,
PQWORD pKeyRSC,
- PBYTE pbyKey,
- BYTE byKeyDecMode,
- DWORD_PTR dwIoBase,
- BYTE byLocalID
+ unsigned char *pbyKey,
+ unsigned char byKeyDecMode,
+ unsigned long dwIoBase,
+ unsigned char byLocalID
)
{
int i;
- UINT ii;
+ unsigned int ii;
PSKeyItem pKey;
- UINT uKeyIdx;
+ unsigned int uKeyIdx;
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Enter KeybSetAllGroupKey: %lX\n", dwKeyIndex);
if ((dwKeyIndex & PAIRWISE_KEY) != 0) { // Pairwise key
- return (FALSE);
+ return (false);
} else if ((dwKeyIndex & 0x000000FF) >= MAX_GROUP_KEY) {
- return (FALSE);
+ return (false);
}
for (i=0; i < MAX_KEY_TABLE-1; i++) {
- if (pTable->KeyTable[i].bInUse == TRUE) {
+ if (pTable->KeyTable[i].bInUse == true) {
// found table already exist
// Group key
pKey = &(pTable->KeyTable[i].GroupKey[dwKeyIndex & 0x000000FF]);
@@ -781,7 +781,7 @@ BOOL KeybSetAllGroupKey (
pTable->KeyTable[i].wKeyCtl |= 0x8000; // enable on-fly
- pKey->bKeyValid = TRUE;
+ pKey->bKeyValid = true;
pKey->uKeyLength = uKeyLength;
pKey->dwKeyIndex = dwKeyIndex;
pKey->byCipherSuite = byKeyDecMode;
@@ -792,7 +792,7 @@ BOOL KeybSetAllGroupKey (
if (uKeyLength == WLAN_WEP104_KEYLEN)
pKey->abyKey[15] |= 0x80;
}
- MACvSetKeyEntry(dwIoBase, pTable->KeyTable[i].wKeyCtl, i, uKeyIdx, pTable->KeyTable[i].abyBSSID, (PDWORD)pKey->abyKey, byLocalID);
+ MACvSetKeyEntry(dwIoBase, pTable->KeyTable[i].wKeyCtl, i, uKeyIdx, pTable->KeyTable[i].abyBSSID, (unsigned long *)pKey->abyKey, byLocalID);
if ((dwKeyIndex & USE_KEYRSC) == 0) {
// RSC set by NIC
@@ -817,7 +817,7 @@ BOOL KeybSetAllGroupKey (
//DBG_PRN_GRP12(("pKey->wTSC15_0: %X\n ", pKey->wTSC15_0));
//DBG_PRN_GRP12(("pKey->dwKeyIndex: %lX\n ", pKey->dwKeyIndex));
- } // (pTable->KeyTable[i].bInUse == TRUE)
+ } // (pTable->KeyTable[i].bInUse == true)
}
- return (TRUE);
+ return (true);
}
diff --git a/drivers/staging/vt6655/key.h b/drivers/staging/vt6655/key.h
index 39403d93aeb..6b2dad331a5 100644
--- a/drivers/staging/vt6655/key.h
+++ b/drivers/staging/vt6655/key.h
@@ -57,33 +57,33 @@
typedef struct tagSKeyItem
{
- BOOL bKeyValid;
- ULONG uKeyLength;
- BYTE abyKey[MAX_KEY_LEN];
+ bool bKeyValid;
+ unsigned long uKeyLength;
+ unsigned char abyKey[MAX_KEY_LEN];
QWORD KeyRSC;
- DWORD dwTSC47_16;
- WORD wTSC15_0;
- BYTE byCipherSuite;
- BYTE byReserved0;
- DWORD dwKeyIndex;
+ unsigned long dwTSC47_16;
+ unsigned short wTSC15_0;
+ unsigned char byCipherSuite;
+ unsigned char byReserved0;
+ unsigned long dwKeyIndex;
void *pvKeyTable;
} SKeyItem, *PSKeyItem; //64
typedef struct tagSKeyTable
{
- BYTE abyBSSID[ETH_ALEN]; //6
- BYTE byReserved0[2]; //8
+ unsigned char abyBSSID[ETH_ALEN]; //6
+ unsigned char byReserved0[2]; //8
SKeyItem PairwiseKey;
SKeyItem GroupKey[MAX_GROUP_KEY]; //64*5 = 320, 320+8=328
- DWORD dwGTKeyIndex; // GroupTransmitKey Index
- BOOL bInUse;
+ unsigned long dwGTKeyIndex; // GroupTransmitKey Index
+ bool bInUse;
//2006-1116-01,<Modify> by NomadZhao
- //WORD wKeyCtl;
- //BOOL bSoftWEP;
- BOOL bSoftWEP;
- WORD wKeyCtl; // for address of wKeyCtl at align 4
+ //unsigned short wKeyCtl;
+ //bool bSoftWEP;
+ bool bSoftWEP;
+ unsigned short wKeyCtl; // for address of wKeyCtl at align 4
- BYTE byReserved1[6];
+ unsigned char byReserved1[6];
} SKeyTable, *PSKeyTable; //348
typedef struct tagSKeyManagement
@@ -101,83 +101,83 @@ typedef struct tagSKeyManagement
/*--------------------- Export Functions --------------------------*/
-void KeyvInitTable(PSKeyManagement pTable, DWORD_PTR dwIoBase);
+void KeyvInitTable(PSKeyManagement pTable, unsigned long dwIoBase);
-BOOL KeybGetKey(
+bool KeybGetKey(
PSKeyManagement pTable,
- PBYTE pbyBSSID,
- DWORD dwKeyIndex,
+ unsigned char *pbyBSSID,
+ unsigned long dwKeyIndex,
PSKeyItem *pKey
);
-BOOL KeybSetKey(
+bool KeybSetKey(
PSKeyManagement pTable,
- PBYTE pbyBSSID,
- DWORD dwKeyIndex,
- ULONG uKeyLength,
+ unsigned char *pbyBSSID,
+ unsigned long dwKeyIndex,
+ unsigned long uKeyLength,
PQWORD pKeyRSC,
- PBYTE pbyKey,
- BYTE byKeyDecMode,
- DWORD_PTR dwIoBase,
- BYTE byLocalID
+ unsigned char *pbyKey,
+ unsigned char byKeyDecMode,
+ unsigned long dwIoBase,
+ unsigned char byLocalID
);
-BOOL KeybSetDefaultKey(
+bool KeybSetDefaultKey(
PSKeyManagement pTable,
- DWORD dwKeyIndex,
- ULONG uKeyLength,
+ unsigned long dwKeyIndex,
+ unsigned long uKeyLength,
PQWORD pKeyRSC,
- PBYTE pbyKey,
- BYTE byKeyDecMode,
- DWORD_PTR dwIoBase,
- BYTE byLocalID
+ unsigned char *pbyKey,
+ unsigned char byKeyDecMode,
+ unsigned long dwIoBase,
+ unsigned char byLocalID
);
-BOOL KeybRemoveKey(
+bool KeybRemoveKey(
PSKeyManagement pTable,
- PBYTE pbyBSSID,
- DWORD dwKeyIndex,
- DWORD_PTR dwIoBase
+ unsigned char *pbyBSSID,
+ unsigned long dwKeyIndex,
+ unsigned long dwIoBase
);
-BOOL KeybGetTransmitKey(
+bool KeybGetTransmitKey(
PSKeyManagement pTable,
- PBYTE pbyBSSID,
- DWORD dwKeyType,
+ unsigned char *pbyBSSID,
+ unsigned long dwKeyType,
PSKeyItem *pKey
);
-BOOL KeybCheckPairewiseKey(
+bool KeybCheckPairewiseKey(
PSKeyManagement pTable,
PSKeyItem *pKey
);
-BOOL KeybRemoveAllKey(
+bool KeybRemoveAllKey(
PSKeyManagement pTable,
- PBYTE pbyBSSID,
- DWORD_PTR dwIoBase
+ unsigned char *pbyBSSID,
+ unsigned long dwIoBase
);
void KeyvRemoveWEPKey(
PSKeyManagement pTable,
- DWORD dwKeyIndex,
- DWORD_PTR dwIoBase
+ unsigned long dwKeyIndex,
+ unsigned long dwIoBase
);
void KeyvRemoveAllWEPKey(
PSKeyManagement pTable,
- DWORD_PTR dwIoBase
+ unsigned long dwIoBase
);
-BOOL KeybSetAllGroupKey (
+bool KeybSetAllGroupKey (
PSKeyManagement pTable,
- DWORD dwKeyIndex,
- ULONG uKeyLength,
+ unsigned long dwKeyIndex,
+ unsigned long uKeyLength,
PQWORD pKeyRSC,
- PBYTE pbyKey,
- BYTE byKeyDecMode,
- DWORD_PTR dwIoBase,
- BYTE byLocalID
+ unsigned char *pbyKey,
+ unsigned char byKeyDecMode,
+ unsigned long dwIoBase,
+ unsigned char byLocalID
);
#endif // __KEY_H__
diff --git a/drivers/staging/vt6655/mac.c b/drivers/staging/vt6655/mac.c
index f1ef7da75c2..f8d1651341f 100644
--- a/drivers/staging/vt6655/mac.c
+++ b/drivers/staging/vt6655/mac.c
@@ -72,7 +72,7 @@
#include "tether.h"
#include "mac.h"
-WORD TxRate_iwconfig;//2008-5-8 <add> by chester
+unsigned short TxRate_iwconfig;//2008-5-8 <add> by chester
/*--------------------- Static Definitions -------------------------*/
//static int msglevel =MSG_LEVEL_DEBUG;
static int msglevel =MSG_LEVEL_INFO;
@@ -103,7 +103,7 @@ static int msglevel =MSG_LEVEL_INFO;
* Return Value: none
*
*/
-void MACvReadAllRegs (DWORD_PTR dwIoBase, PBYTE pbyMacRegs)
+void MACvReadAllRegs (unsigned long dwIoBase, unsigned char *pbyMacRegs)
{
int ii;
@@ -137,12 +137,12 @@ void MACvReadAllRegs (DWORD_PTR dwIoBase, PBYTE pbyMacRegs)
* Out:
* none
*
- * Return Value: TRUE if all test bits On; otherwise FALSE
+ * Return Value: true if all test bits On; otherwise false
*
*/
-BOOL MACbIsRegBitsOn (DWORD_PTR dwIoBase, BYTE byRegOfs, BYTE byTestBits)
+bool MACbIsRegBitsOn (unsigned long dwIoBase, unsigned char byRegOfs, unsigned char byTestBits)
{
- BYTE byData;
+ unsigned char byData;
VNSvInPortB(dwIoBase + byRegOfs, &byData);
return (byData & byTestBits) == byTestBits;
@@ -160,12 +160,12 @@ BOOL MACbIsRegBitsOn (DWORD_PTR dwIoBase, BYTE byRegOfs, BYTE byTestBits)
* Out:
* none
*
- * Return Value: TRUE if all test bits Off; otherwise FALSE
+ * Return Value: true if all test bits Off; otherwise false
*
*/
-BOOL MACbIsRegBitsOff (DWORD_PTR dwIoBase, BYTE byRegOfs, BYTE byTestBits)
+bool MACbIsRegBitsOff (unsigned long dwIoBase, unsigned char byRegOfs, unsigned char byTestBits)
{
- BYTE byData;
+ unsigned char byData;
VNSvInPortB(dwIoBase + byRegOfs, &byData);
return !(byData & byTestBits);
@@ -181,18 +181,18 @@ BOOL MACbIsRegBitsOff (DWORD_PTR dwIoBase, BYTE byRegOfs, BYTE byTestBits)
* Out:
* none
*
- * Return Value: TRUE if interrupt is disable; otherwise FALSE
+ * Return Value: true if interrupt is disable; otherwise false
*
*/
-BOOL MACbIsIntDisable (DWORD_PTR dwIoBase)
+bool MACbIsIntDisable (unsigned long dwIoBase)
{
- DWORD dwData;
+ unsigned long dwData;
VNSvInPortD(dwIoBase + MAC_REG_IMR, &dwData);
if (dwData != 0)
- return FALSE;
+ return false;
- return TRUE;
+ return true;
}
/*
@@ -209,9 +209,9 @@ BOOL MACbIsIntDisable (DWORD_PTR dwIoBase)
* Return Value: Mask Value read
*
*/
-BYTE MACbyReadMultiAddr (DWORD_PTR dwIoBase, UINT uByteIdx)
+unsigned char MACbyReadMultiAddr (unsigned long dwIoBase, unsigned int uByteIdx)
{
- BYTE byData;
+ unsigned char byData;
MACvSelectPage1(dwIoBase);
VNSvInPortB(dwIoBase + MAC_REG_MAR0 + uByteIdx, &byData);
@@ -234,7 +234,7 @@ BYTE MACbyReadMultiAddr (DWORD_PTR dwIoBase, UINT uByteIdx)
* Return Value: none
*
*/
-void MACvWriteMultiAddr (DWORD_PTR dwIoBase, UINT uByteIdx, BYTE byData)
+void MACvWriteMultiAddr (unsigned long dwIoBase, unsigned int uByteIdx, unsigned char byData)
{
MACvSelectPage1(dwIoBase);
VNSvOutPortB(dwIoBase + MAC_REG_MAR0 + uByteIdx, byData);
@@ -255,11 +255,11 @@ void MACvWriteMultiAddr (DWORD_PTR dwIoBase, UINT uByteIdx, BYTE byData)
* Return Value: none
*
*/
-void MACvSetMultiAddrByHash (DWORD_PTR dwIoBase, BYTE byHashIdx)
+void MACvSetMultiAddrByHash (unsigned long dwIoBase, unsigned char byHashIdx)
{
- UINT uByteIdx;
- BYTE byBitMask;
- BYTE byOrgValue;
+ unsigned int uByteIdx;
+ unsigned char byBitMask;
+ unsigned char byOrgValue;
// calculate byte position
uByteIdx = byHashIdx / 8;
@@ -269,7 +269,7 @@ void MACvSetMultiAddrByHash (DWORD_PTR dwIoBase, BYTE byHashIdx)
byBitMask <<= (byHashIdx % 8);
// turn on the bit
byOrgValue = MACbyReadMultiAddr(dwIoBase, uByteIdx);
- MACvWriteMultiAddr(dwIoBase, uByteIdx, (BYTE)(byOrgValue | byBitMask));
+ MACvWriteMultiAddr(dwIoBase, uByteIdx, (unsigned char)(byOrgValue | byBitMask));
}
/*
@@ -286,11 +286,11 @@ void MACvSetMultiAddrByHash (DWORD_PTR dwIoBase, BYTE byHashIdx)
* Return Value: none
*
*/
-void MACvResetMultiAddrByHash (DWORD_PTR dwIoBase, BYTE byHashIdx)
+void MACvResetMultiAddrByHash (unsigned long dwIoBase, unsigned char byHashIdx)
{
- UINT uByteIdx;
- BYTE byBitMask;
- BYTE byOrgValue;
+ unsigned int uByteIdx;
+ unsigned char byBitMask;
+ unsigned char byOrgValue;
// calculate byte position
uByteIdx = byHashIdx / 8;
@@ -300,7 +300,7 @@ void MACvResetMultiAddrByHash (DWORD_PTR dwIoBase, BYTE byHashIdx)
byBitMask <<= (byHashIdx % 8);
// turn off the bit
byOrgValue = MACbyReadMultiAddr(dwIoBase, uByteIdx);
- MACvWriteMultiAddr(dwIoBase, uByteIdx, (BYTE)(byOrgValue & (~byBitMask)));
+ MACvWriteMultiAddr(dwIoBase, uByteIdx, (unsigned char)(byOrgValue & (~byBitMask)));
}
/*
@@ -317,9 +317,9 @@ void MACvResetMultiAddrByHash (DWORD_PTR dwIoBase, BYTE byHashIdx)
* Return Value: none
*
*/
-void MACvSetRxThreshold (DWORD_PTR dwIoBase, BYTE byThreshold)
+void MACvSetRxThreshold (unsigned long dwIoBase, unsigned char byThreshold)
{
- BYTE byOrgValue;
+ unsigned char byOrgValue;
ASSERT(byThreshold < 4);
@@ -342,7 +342,7 @@ void MACvSetRxThreshold (DWORD_PTR dwIoBase, BYTE byThreshold)
* Return Value: none
*
*/
-void MACvGetRxThreshold (DWORD_PTR dwIoBase, PBYTE pbyThreshold)
+void MACvGetRxThreshold (unsigned long dwIoBase, unsigned char *pbyThreshold)
{
// get FCR0
VNSvInPortB(dwIoBase + MAC_REG_FCR0, pbyThreshold);
@@ -363,9 +363,9 @@ void MACvGetRxThreshold (DWORD_PTR dwIoBase, PBYTE pbyThreshold)
* Return Value: none
*
*/
-void MACvSetTxThreshold (DWORD_PTR dwIoBase, BYTE byThreshold)
+void MACvSetTxThreshold (unsigned long dwIoBase, unsigned char byThreshold)
{
- BYTE byOrgValue;
+ unsigned char byOrgValue;
ASSERT(byThreshold < 4);
@@ -388,7 +388,7 @@ void MACvSetTxThreshold (DWORD_PTR dwIoBase, BYTE byThreshold)
* Return Value: none
*
*/
-void MACvGetTxThreshold (DWORD_PTR dwIoBase, PBYTE pbyThreshold)
+void MACvGetTxThreshold (unsigned long dwIoBase, unsigned char *pbyThreshold)
{
// get FCR0
VNSvInPortB(dwIoBase + MAC_REG_FCR0, pbyThreshold);
@@ -409,9 +409,9 @@ void MACvGetTxThreshold (DWORD_PTR dwIoBase, PBYTE pbyThreshold)
* Return Value: none
*
*/
-void MACvSetDmaLength (DWORD_PTR dwIoBase, BYTE byDmaLength)
+void MACvSetDmaLength (unsigned long dwIoBase, unsigned char byDmaLength)
{
- BYTE byOrgValue;
+ unsigned char byOrgValue;
ASSERT(byDmaLength < 4);
@@ -434,7 +434,7 @@ void MACvSetDmaLength (DWORD_PTR dwIoBase, BYTE byDmaLength)
* Return Value: none
*
*/
-void MACvGetDmaLength (DWORD_PTR dwIoBase, PBYTE pbyDmaLength)
+void MACvGetDmaLength (unsigned long dwIoBase, unsigned char *pbyDmaLength)
{
// get FCR0
VNSvInPortB(dwIoBase + MAC_REG_FCR0, pbyDmaLength);
@@ -455,7 +455,7 @@ void MACvGetDmaLength (DWORD_PTR dwIoBase, PBYTE pbyDmaLength)
* Return Value: none
*
*/
-void MACvSetShortRetryLimit (DWORD_PTR dwIoBase, BYTE byRetryLimit)
+void MACvSetShortRetryLimit (unsigned long dwIoBase, unsigned char byRetryLimit)
{
// set SRT
VNSvOutPortB(dwIoBase + MAC_REG_SRT, byRetryLimit);
@@ -474,7 +474,7 @@ void MACvSetShortRetryLimit (DWORD_PTR dwIoBase, BYTE byRetryLimit)
* Return Value: none
*
*/
-void MACvGetShortRetryLimit (DWORD_PTR dwIoBase, PBYTE pbyRetryLimit)
+void MACvGetShortRetryLimit (unsigned long dwIoBase, unsigned char *pbyRetryLimit)
{
// get SRT
VNSvInPortB(dwIoBase + MAC_REG_SRT, pbyRetryLimit);
@@ -494,7 +494,7 @@ void MACvGetShortRetryLimit (DWORD_PTR dwIoBase, PBYTE pbyRetryLimit)
* Return Value: none
*
*/
-void MACvSetLongRetryLimit (DWORD_PTR dwIoBase, BYTE byRetryLimit)
+void MACvSetLongRetryLimit (unsigned long dwIoBase, unsigned char byRetryLimit)
{
// set LRT
VNSvOutPortB(dwIoBase + MAC_REG_LRT, byRetryLimit);
@@ -513,7 +513,7 @@ void MACvSetLongRetryLimit (DWORD_PTR dwIoBase, BYTE byRetryLimit)
* Return Value: none
*
*/
-void MACvGetLongRetryLimit (DWORD_PTR dwIoBase, PBYTE pbyRetryLimit)
+void MACvGetLongRetryLimit (unsigned long dwIoBase, unsigned char *pbyRetryLimit)
{
// get LRT
VNSvInPortB(dwIoBase + MAC_REG_LRT, pbyRetryLimit);
@@ -533,9 +533,9 @@ void MACvGetLongRetryLimit (DWORD_PTR dwIoBase, PBYTE pbyRetryLimit)
* Return Value: none
*
*/
-void MACvSetLoopbackMode (DWORD_PTR dwIoBase, BYTE byLoopbackMode)
+void MACvSetLoopbackMode (unsigned long dwIoBase, unsigned char byLoopbackMode)
{
- BYTE byOrgValue;
+ unsigned char byOrgValue;
ASSERT(byLoopbackMode < 3);
byLoopbackMode <<= 6;
@@ -556,17 +556,17 @@ void MACvSetLoopbackMode (DWORD_PTR dwIoBase, BYTE byLoopbackMode)
* Out:
* none
*
- * Return Value: TRUE if in Loopback mode; otherwise FALSE
+ * Return Value: true if in Loopback mode; otherwise false
*
*/
-BOOL MACbIsInLoopbackMode (DWORD_PTR dwIoBase)
+bool MACbIsInLoopbackMode (unsigned long dwIoBase)
{
- BYTE byOrgValue;
+ unsigned char byOrgValue;
VNSvInPortB(dwIoBase + MAC_REG_TEST, &byOrgValue);
if (byOrgValue & (TEST_LBINT | TEST_LBEXT))
- return TRUE;
- return FALSE;
+ return true;
+ return false;
}
/*
@@ -583,10 +583,10 @@ BOOL MACbIsInLoopbackMode (DWORD_PTR dwIoBase)
* Return Value: none
*
*/
-void MACvSetPacketFilter (DWORD_PTR dwIoBase, WORD wFilterType)
+void MACvSetPacketFilter (unsigned long dwIoBase, unsigned short wFilterType)
{
- BYTE byOldRCR;
- BYTE byNewRCR = 0;
+ unsigned char byOldRCR;
+ unsigned char byNewRCR = 0;
// if only in DIRECTED mode, multicast-address will set to zero,
// but if other mode exist (e.g. PROMISCUOUS), multicast-address
@@ -595,7 +595,7 @@ void MACvSetPacketFilter (DWORD_PTR dwIoBase, WORD wFilterType)
// set multicast address to accept none
MACvSelectPage1(dwIoBase);
VNSvOutPortD(dwIoBase + MAC_REG_MAR0, 0L);
- VNSvOutPortD(dwIoBase + MAC_REG_MAR0 + sizeof(DWORD), 0L);
+ VNSvOutPortD(dwIoBase + MAC_REG_MAR0 + sizeof(unsigned long), 0L);
MACvSelectPage0(dwIoBase);
}
@@ -603,7 +603,7 @@ void MACvSetPacketFilter (DWORD_PTR dwIoBase, WORD wFilterType)
// set multicast address to accept all
MACvSelectPage1(dwIoBase);
VNSvOutPortD(dwIoBase + MAC_REG_MAR0, 0xFFFFFFFFL);
- VNSvOutPortD(dwIoBase + MAC_REG_MAR0 + sizeof(DWORD), 0xFFFFFFFFL);
+ VNSvOutPortD(dwIoBase + MAC_REG_MAR0 + sizeof(unsigned long), 0xFFFFFFFFL);
MACvSelectPage0(dwIoBase);
}
@@ -643,7 +643,7 @@ void MACvSetPacketFilter (DWORD_PTR dwIoBase, WORD wFilterType)
* Return Value: none
*
*/
-void MACvSaveContext (DWORD_PTR dwIoBase, PBYTE pbyCxtBuf)
+void MACvSaveContext (unsigned long dwIoBase, unsigned char *pbyCxtBuf)
{
int ii;
@@ -676,7 +676,7 @@ void MACvSaveContext (DWORD_PTR dwIoBase, PBYTE pbyCxtBuf)
* Return Value: none
*
*/
-void MACvRestoreContext (DWORD_PTR dwIoBase, PBYTE pbyCxtBuf)
+void MACvRestoreContext (unsigned long dwIoBase, unsigned char *pbyCxtBuf)
{
int ii;
@@ -703,14 +703,14 @@ void MACvRestoreContext (DWORD_PTR dwIoBase, PBYTE pbyCxtBuf)
}
// restore CURR_RX_DESC_ADDR, CURR_TX_DESC_ADDR
- VNSvOutPortD(dwIoBase + MAC_REG_TXDMAPTR0, *(PDWORD)(pbyCxtBuf + MAC_REG_TXDMAPTR0));
- VNSvOutPortD(dwIoBase + MAC_REG_AC0DMAPTR, *(PDWORD)(pbyCxtBuf + MAC_REG_AC0DMAPTR));
- VNSvOutPortD(dwIoBase + MAC_REG_BCNDMAPTR, *(PDWORD)(pbyCxtBuf + MAC_REG_BCNDMAPTR));
+ VNSvOutPortD(dwIoBase + MAC_REG_TXDMAPTR0, *(unsigned long *)(pbyCxtBuf + MAC_REG_TXDMAPTR0));
+ VNSvOutPortD(dwIoBase + MAC_REG_AC0DMAPTR, *(unsigned long *)(pbyCxtBuf + MAC_REG_AC0DMAPTR));
+ VNSvOutPortD(dwIoBase + MAC_REG_BCNDMAPTR, *(unsigned long *)(pbyCxtBuf + MAC_REG_BCNDMAPTR));
- VNSvOutPortD(dwIoBase + MAC_REG_RXDMAPTR0, *(PDWORD)(pbyCxtBuf + MAC_REG_RXDMAPTR0));
+ VNSvOutPortD(dwIoBase + MAC_REG_RXDMAPTR0, *(unsigned long *)(pbyCxtBuf + MAC_REG_RXDMAPTR0));
- VNSvOutPortD(dwIoBase + MAC_REG_RXDMAPTR1, *(PDWORD)(pbyCxtBuf + MAC_REG_RXDMAPTR1));
+ VNSvOutPortD(dwIoBase + MAC_REG_RXDMAPTR1, *(unsigned long *)(pbyCxtBuf + MAC_REG_RXDMAPTR1));
}
@@ -725,39 +725,39 @@ void MACvRestoreContext (DWORD_PTR dwIoBase, PBYTE pbyCxtBuf)
* Out:
* none
*
- * Return Value: TRUE if all values are the same; otherwise FALSE
+ * Return Value: true if all values are the same; otherwise false
*
*/
-BOOL MACbCompareContext (DWORD_PTR dwIoBase, PBYTE pbyCxtBuf)
+bool MACbCompareContext (unsigned long dwIoBase, unsigned char *pbyCxtBuf)
{
- DWORD dwData;
+ unsigned long dwData;
// compare MAC context to determine if this is a power lost init,
- // return TRUE for power remaining init, return FALSE for power lost init
+ // return true for power remaining init, return false for power lost init
// compare CURR_RX_DESC_ADDR, CURR_TX_DESC_ADDR
VNSvInPortD(dwIoBase + MAC_REG_TXDMAPTR0, &dwData);
- if (dwData != *(PDWORD)(pbyCxtBuf + MAC_REG_TXDMAPTR0)) {
- return FALSE;
+ if (dwData != *(unsigned long *)(pbyCxtBuf + MAC_REG_TXDMAPTR0)) {
+ return false;
}
VNSvInPortD(dwIoBase + MAC_REG_AC0DMAPTR, &dwData);
- if (dwData != *(PDWORD)(pbyCxtBuf + MAC_REG_AC0DMAPTR)) {
- return FALSE;
+ if (dwData != *(unsigned long *)(pbyCxtBuf + MAC_REG_AC0DMAPTR)) {
+ return false;
}
VNSvInPortD(dwIoBase + MAC_REG_RXDMAPTR0, &dwData);
- if (dwData != *(PDWORD)(pbyCxtBuf + MAC_REG_RXDMAPTR0)) {
- return FALSE;
+ if (dwData != *(unsigned long *)(pbyCxtBuf + MAC_REG_RXDMAPTR0)) {
+ return false;
}
VNSvInPortD(dwIoBase + MAC_REG_RXDMAPTR1, &dwData);
- if (dwData != *(PDWORD)(pbyCxtBuf + MAC_REG_RXDMAPTR1)) {
- return FALSE;
+ if (dwData != *(unsigned long *)(pbyCxtBuf + MAC_REG_RXDMAPTR1)) {
+ return false;
}
- return TRUE;
+ return true;
}
/*
@@ -770,13 +770,13 @@ BOOL MACbCompareContext (DWORD_PTR dwIoBase, PBYTE pbyCxtBuf)
* Out:
* none
*
- * Return Value: TRUE if Reset Success; otherwise FALSE
+ * Return Value: true if Reset Success; otherwise false
*
*/
-BOOL MACbSoftwareReset (DWORD_PTR dwIoBase)
+bool MACbSoftwareReset (unsigned long dwIoBase)
{
- BYTE byData;
- WORD ww;
+ unsigned char byData;
+ unsigned short ww;
// turn on HOSTCR_SOFTRST, just write 0x01 to reset
//MACvRegBitsOn(dwIoBase, MAC_REG_HOSTCR, HOSTCR_SOFTRST);
@@ -788,8 +788,8 @@ BOOL MACbSoftwareReset (DWORD_PTR dwIoBase)
break;
}
if (ww == W_MAX_TIMEOUT)
- return FALSE;
- return TRUE;
+ return false;
+ return true;
}
@@ -803,13 +803,13 @@ BOOL MACbSoftwareReset (DWORD_PTR dwIoBase)
* Out:
* none
*
- * Return Value: TRUE if success; otherwise FALSE
+ * Return Value: true if success; otherwise false
*
*/
-BOOL MACbSafeSoftwareReset (DWORD_PTR dwIoBase)
+bool MACbSafeSoftwareReset (unsigned long dwIoBase)
{
- BYTE abyTmpRegData[MAC_MAX_CONTEXT_SIZE_PAGE0+MAC_MAX_CONTEXT_SIZE_PAGE1];
- BOOL bRetVal;
+ unsigned char abyTmpRegData[MAC_MAX_CONTEXT_SIZE_PAGE0+MAC_MAX_CONTEXT_SIZE_PAGE1];
+ bool bRetVal;
// PATCH....
// save some important register's value, then do
@@ -836,14 +836,14 @@ BOOL MACbSafeSoftwareReset (DWORD_PTR dwIoBase)
* Out:
* none
*
- * Return Value: TRUE if success; otherwise FALSE
+ * Return Value: true if success; otherwise false
*
*/
-BOOL MACbSafeRxOff (DWORD_PTR dwIoBase)
+bool MACbSafeRxOff (unsigned long dwIoBase)
{
- WORD ww;
- DWORD dwData;
- BYTE byData;
+ unsigned short ww;
+ unsigned long dwData;
+ unsigned char byData;
// turn off wow temp for turn off Rx safely
@@ -858,7 +858,7 @@ BOOL MACbSafeRxOff (DWORD_PTR dwIoBase)
if (ww == W_MAX_TIMEOUT) {
DBG_PORT80(0x10);
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO" DBG_PORT80(0x10)\n");
- return(FALSE);
+ return(false);
}
for (ww = 0; ww < W_MAX_TIMEOUT; ww++) {
VNSvInPortD(dwIoBase + MAC_REG_RXDMACTL1, &dwData);
@@ -868,7 +868,7 @@ BOOL MACbSafeRxOff (DWORD_PTR dwIoBase)
if (ww == W_MAX_TIMEOUT) {
DBG_PORT80(0x11);
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO" DBG_PORT80(0x11)\n");
- return(FALSE);
+ return(false);
}
// try to safe shutdown RX
@@ -882,9 +882,9 @@ BOOL MACbSafeRxOff (DWORD_PTR dwIoBase)
if (ww == W_MAX_TIMEOUT) {
DBG_PORT80(0x12);
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO" DBG_PORT80(0x12)\n");
- return(FALSE);
+ return(false);
}
- return TRUE;
+ return true;
}
/*
@@ -897,14 +897,14 @@ BOOL MACbSafeRxOff (DWORD_PTR dwIoBase)
* Out:
* none
*
- * Return Value: TRUE if success; otherwise FALSE
+ * Return Value: true if success; otherwise false
*
*/
-BOOL MACbSafeTxOff (DWORD_PTR dwIoBase)
+bool MACbSafeTxOff (unsigned long dwIoBase)
{
- WORD ww;
- DWORD dwData;
- BYTE byData;
+ unsigned short ww;
+ unsigned long dwData;
+ unsigned char byData;
// Clear TX DMA
//Tx0
@@ -921,7 +921,7 @@ BOOL MACbSafeTxOff (DWORD_PTR dwIoBase)
if (ww == W_MAX_TIMEOUT) {
DBG_PORT80(0x20);
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO" DBG_PORT80(0x20)\n");
- return(FALSE);
+ return(false);
}
for (ww = 0; ww < W_MAX_TIMEOUT; ww++) {
VNSvInPortD(dwIoBase + MAC_REG_AC0DMACTL, &dwData);
@@ -931,7 +931,7 @@ BOOL MACbSafeTxOff (DWORD_PTR dwIoBase)
if (ww == W_MAX_TIMEOUT) {
DBG_PORT80(0x21);
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO" DBG_PORT80(0x21)\n");
- return(FALSE);
+ return(false);
}
// try to safe shutdown TX
@@ -946,9 +946,9 @@ BOOL MACbSafeTxOff (DWORD_PTR dwIoBase)
if (ww == W_MAX_TIMEOUT) {
DBG_PORT80(0x24);
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO" DBG_PORT80(0x24)\n");
- return(FALSE);
+ return(false);
}
- return TRUE;
+ return true;
}
/*
@@ -961,29 +961,29 @@ BOOL MACbSafeTxOff (DWORD_PTR dwIoBase)
* Out:
* none
*
- * Return Value: TRUE if success; otherwise FALSE
+ * Return Value: true if success; otherwise false
*
*/
-BOOL MACbSafeStop (DWORD_PTR dwIoBase)
+bool MACbSafeStop (unsigned long dwIoBase)
{
MACvRegBitsOff(dwIoBase, MAC_REG_TCR, TCR_AUTOBCNTX);
- if (MACbSafeRxOff(dwIoBase) == FALSE) {
+ if (MACbSafeRxOff(dwIoBase) == false) {
DBG_PORT80(0xA1);
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO" MACbSafeRxOff == FALSE)\n");
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO" MACbSafeRxOff == false)\n");
MACbSafeSoftwareReset(dwIoBase);
- return FALSE;
+ return false;
}
- if (MACbSafeTxOff(dwIoBase) == FALSE) {
+ if (MACbSafeTxOff(dwIoBase) == false) {
DBG_PORT80(0xA2);
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO" MACbSafeTxOff == FALSE)\n");
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO" MACbSafeTxOff == false)\n");
MACbSafeSoftwareReset(dwIoBase);
- return FALSE;
+ return false;
}
MACvRegBitsOff(dwIoBase, MAC_REG_HOSTCR, HOSTCR_MACEN);
- return TRUE;
+ return true;
}
/*
@@ -996,10 +996,10 @@ BOOL MACbSafeStop (DWORD_PTR dwIoBase)
* Out:
* none
*
- * Return Value: TRUE if success; otherwise FALSE
+ * Return Value: true if success; otherwise false
*
*/
-BOOL MACbShutdown (DWORD_PTR dwIoBase)
+bool MACbShutdown (unsigned long dwIoBase)
{
// disable MAC IMR
MACvIntDisable(dwIoBase);
@@ -1007,10 +1007,10 @@ BOOL MACbShutdown (DWORD_PTR dwIoBase)
// stop the adapter
if (!MACbSafeStop(dwIoBase)) {
MACvSetLoopbackMode(dwIoBase, MAC_LB_NONE);
- return FALSE;
+ return false;
}
MACvSetLoopbackMode(dwIoBase, MAC_LB_NONE);
- return TRUE;
+ return true;
}
/*
@@ -1026,7 +1026,7 @@ BOOL MACbShutdown (DWORD_PTR dwIoBase)
* Return Value: none
*
*/
-void MACvInitialize (DWORD_PTR dwIoBase)
+void MACvInitialize (unsigned long dwIoBase)
{
// clear sticky bits
MACvClearStckDS(dwIoBase);
@@ -1045,8 +1045,8 @@ void MACvInitialize (DWORD_PTR dwIoBase)
// issue AUTOLD in EECSR to reload eeprom
//MACvRegBitsOn(dwIoBase, MAC_REG_I2MCSR, I2MCSR_AUTOLD);
// wait until EEPROM loading complete
- //while (TRUE) {
- // U8 u8Data;
+ //while (true) {
+ // u8 u8Data;
// VNSvInPortB(dwIoBase + MAC_REG_I2MCSR, &u8Data);
// if ( !(u8Data & I2MCSR_AUTOLD))
// break;
@@ -1079,11 +1079,11 @@ void MACvInitialize (DWORD_PTR dwIoBase)
* Return Value: none
*
*/
-void MACvSetCurrRx0DescAddr (DWORD_PTR dwIoBase, DWORD dwCurrDescAddr)
+void MACvSetCurrRx0DescAddr (unsigned long dwIoBase, unsigned long dwCurrDescAddr)
{
-WORD ww;
-BYTE byData;
-BYTE byOrgDMACtl;
+unsigned short ww;
+unsigned char byData;
+unsigned char byOrgDMACtl;
VNSvInPortB(dwIoBase + MAC_REG_RXDMACTL0, &byOrgDMACtl);
if (byOrgDMACtl & DMACTL_RUN) {
@@ -1117,11 +1117,11 @@ BYTE byOrgDMACtl;
* Return Value: none
*
*/
-void MACvSetCurrRx1DescAddr (DWORD_PTR dwIoBase, DWORD dwCurrDescAddr)
+void MACvSetCurrRx1DescAddr (unsigned long dwIoBase, unsigned long dwCurrDescAddr)
{
-WORD ww;
-BYTE byData;
-BYTE byOrgDMACtl;
+unsigned short ww;
+unsigned char byData;
+unsigned char byOrgDMACtl;
VNSvInPortB(dwIoBase + MAC_REG_RXDMACTL1, &byOrgDMACtl);
if (byOrgDMACtl & DMACTL_RUN) {
@@ -1155,11 +1155,11 @@ BYTE byOrgDMACtl;
* Return Value: none
*
*/
-void MACvSetCurrTx0DescAddrEx (DWORD_PTR dwIoBase, DWORD dwCurrDescAddr)
+void MACvSetCurrTx0DescAddrEx (unsigned long dwIoBase, unsigned long dwCurrDescAddr)
{
-WORD ww;
-BYTE byData;
-BYTE byOrgDMACtl;
+unsigned short ww;
+unsigned char byData;
+unsigned char byOrgDMACtl;
VNSvInPortB(dwIoBase + MAC_REG_TXDMACTL0, &byOrgDMACtl);
if (byOrgDMACtl & DMACTL_RUN) {
@@ -1194,11 +1194,11 @@ BYTE byOrgDMACtl;
*
*/
//TxDMA1 = AC0DMA
-void MACvSetCurrAC0DescAddrEx (DWORD_PTR dwIoBase, DWORD dwCurrDescAddr)
+void MACvSetCurrAC0DescAddrEx (unsigned long dwIoBase, unsigned long dwCurrDescAddr)
{
-WORD ww;
-BYTE byData;
-BYTE byOrgDMACtl;
+unsigned short ww;
+unsigned char byData;
+unsigned char byOrgDMACtl;
VNSvInPortB(dwIoBase + MAC_REG_AC0DMACTL, &byOrgDMACtl);
if (byOrgDMACtl & DMACTL_RUN) {
@@ -1221,7 +1221,7 @@ BYTE byOrgDMACtl;
-void MACvSetCurrTXDescAddr (int iTxType, DWORD_PTR dwIoBase, DWORD dwCurrDescAddr)
+void MACvSetCurrTXDescAddr (int iTxType, unsigned long dwIoBase, unsigned long dwCurrDescAddr)
{
if(iTxType == TYPE_AC0DMA){
MACvSetCurrAC0DescAddrEx(dwIoBase, dwCurrDescAddr);
@@ -1244,10 +1244,10 @@ void MACvSetCurrTXDescAddr (int iTxType, DWORD_PTR dwIoBase, DWORD dwCurrDescAdd
* Return Value: none
*
*/
-void MACvTimer0MicroSDelay (DWORD_PTR dwIoBase, UINT uDelay)
+void MACvTimer0MicroSDelay (unsigned long dwIoBase, unsigned int uDelay)
{
-BYTE byValue;
-UINT uu,ii;
+unsigned char byValue;
+unsigned int uu,ii;
VNSvOutPortB(dwIoBase + MAC_REG_TMCTL0, 0);
VNSvOutPortD(dwIoBase + MAC_REG_TMDATA0, uDelay);
@@ -1280,7 +1280,7 @@ UINT uu,ii;
* Return Value: none
*
*/
-void MACvOneShotTimer0MicroSec (DWORD_PTR dwIoBase, UINT uDelayTime)
+void MACvOneShotTimer0MicroSec (unsigned long dwIoBase, unsigned int uDelayTime)
{
VNSvOutPortB(dwIoBase + MAC_REG_TMCTL0, 0);
VNSvOutPortD(dwIoBase + MAC_REG_TMDATA0, uDelayTime);
@@ -1301,7 +1301,7 @@ void MACvOneShotTimer0MicroSec (DWORD_PTR dwIoBase, UINT uDelayTime)
* Return Value: none
*
*/
-void MACvOneShotTimer1MicroSec (DWORD_PTR dwIoBase, UINT uDelayTime)
+void MACvOneShotTimer1MicroSec (unsigned long dwIoBase, unsigned int uDelayTime)
{
VNSvOutPortB(dwIoBase + MAC_REG_TMCTL1, 0);
VNSvOutPortD(dwIoBase + MAC_REG_TMDATA1, uDelayTime);
@@ -1309,7 +1309,7 @@ void MACvOneShotTimer1MicroSec (DWORD_PTR dwIoBase, UINT uDelayTime)
}
-void MACvSetMISCFifo (DWORD_PTR dwIoBase, WORD wOffset, DWORD dwData)
+void MACvSetMISCFifo (unsigned long dwIoBase, unsigned short wOffset, unsigned long dwData)
{
if (wOffset > 273)
return;
@@ -1319,10 +1319,10 @@ void MACvSetMISCFifo (DWORD_PTR dwIoBase, WORD wOffset, DWORD dwData)
}
-BOOL MACbTxDMAOff (DWORD_PTR dwIoBase, UINT idx)
+bool MACbTxDMAOff (unsigned long dwIoBase, unsigned int idx)
{
-BYTE byData;
-UINT ww = 0;
+unsigned char byData;
+unsigned int ww = 0;
if (idx == TYPE_TXDMA0) {
VNSvOutPortB(dwIoBase + MAC_REG_TXDMACTL0+2, DMACTL_RUN);
@@ -1342,15 +1342,15 @@ UINT ww = 0;
if (ww == W_MAX_TIMEOUT) {
DBG_PORT80(0x29);
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO" DBG_PORT80(0x29)\n");
- return FALSE;
+ return false;
}
- return TRUE;
+ return true;
}
-void MACvClearBusSusInd (DWORD_PTR dwIoBase)
+void MACvClearBusSusInd (unsigned long dwIoBase)
{
- DWORD dwOrgValue;
- UINT ww;
+ unsigned long dwOrgValue;
+ unsigned int ww;
// check if BcnSusInd enabled
VNSvInPortD(dwIoBase + MAC_REG_ENCFG , &dwOrgValue);
if( !(dwOrgValue & EnCFG_BcnSusInd))
@@ -1369,11 +1369,11 @@ void MACvClearBusSusInd (DWORD_PTR dwIoBase)
}
}
-void MACvEnableBusSusEn (DWORD_PTR dwIoBase)
+void MACvEnableBusSusEn (unsigned long dwIoBase)
{
- BYTE byOrgValue;
- DWORD dwOrgValue;
- UINT ww;
+ unsigned char byOrgValue;
+ unsigned long dwOrgValue;
+ unsigned int ww;
// check if BcnSusInd enabled
VNSvInPortB(dwIoBase + MAC_REG_CFG , &byOrgValue);
@@ -1391,10 +1391,10 @@ void MACvEnableBusSusEn (DWORD_PTR dwIoBase)
}
}
-BOOL MACbFlushSYNCFifo (DWORD_PTR dwIoBase)
+bool MACbFlushSYNCFifo (unsigned long dwIoBase)
{
- BYTE byOrgValue;
- UINT ww;
+ unsigned char byOrgValue;
+ unsigned int ww;
// Read MACCR
VNSvInPortB(dwIoBase + MAC_REG_MACCR , &byOrgValue);
@@ -1412,16 +1412,16 @@ BOOL MACbFlushSYNCFifo (DWORD_PTR dwIoBase)
DBG_PORT80(0x35);
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO" DBG_PORT80(0x33)\n");
}
- return TRUE;
+ return true;
}
-BOOL MACbPSWakeup (DWORD_PTR dwIoBase)
+bool MACbPSWakeup (unsigned long dwIoBase)
{
- BYTE byOrgValue;
- UINT ww;
+ unsigned char byOrgValue;
+ unsigned int ww;
// Read PSCTL
if (MACbIsRegBitsOff(dwIoBase, MAC_REG_PSCTL, PSCTL_PS)) {
- return TRUE;
+ return true;
}
// Disable PS
MACvRegBitsOff(dwIoBase, MAC_REG_PSCTL, PSCTL_PSEN);
@@ -1435,9 +1435,9 @@ BOOL MACbPSWakeup (DWORD_PTR dwIoBase)
if (ww == W_MAX_TIMEOUT) {
DBG_PORT80(0x36);
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO" DBG_PORT80(0x33)\n");
- return FALSE;
+ return false;
}
- return TRUE;
+ return true;
}
/*
@@ -1455,10 +1455,11 @@ BOOL MACbPSWakeup (DWORD_PTR dwIoBase)
*
*/
-void MACvSetKeyEntry (DWORD_PTR dwIoBase, WORD wKeyCtl, UINT uEntryIdx, UINT uKeyIdx, PBYTE pbyAddr, PDWORD pdwKey, BYTE byLocalID)
+void MACvSetKeyEntry (unsigned long dwIoBase, unsigned short wKeyCtl, unsigned int uEntryIdx,
+ unsigned int uKeyIdx, unsigned char *pbyAddr, unsigned long *pdwKey, unsigned char byLocalID)
{
-WORD wOffset;
-DWORD dwData;
+unsigned short wOffset;
+unsigned long dwData;
int ii;
if (byLocalID <= 1)
@@ -1521,9 +1522,9 @@ int ii;
* Return Value: none
*
*/
-void MACvDisableKeyEntry (DWORD_PTR dwIoBase, UINT uEntryIdx)
+void MACvDisableKeyEntry (unsigned long dwIoBase, unsigned int uEntryIdx)
{
-WORD wOffset;
+unsigned short wOffset;
wOffset = MISCFIFO_KEYETRY0;
wOffset += (uEntryIdx * MISCFIFO_KEYENTRYSIZE);
@@ -1549,10 +1550,11 @@ WORD wOffset;
*
*/
-void MACvSetDefaultKeyEntry (DWORD_PTR dwIoBase, UINT uKeyLen, UINT uKeyIdx, PDWORD pdwKey, BYTE byLocalID)
+void MACvSetDefaultKeyEntry (unsigned long dwIoBase, unsigned int uKeyLen,
+ unsigned int uKeyIdx, unsigned long *pdwKey, unsigned char byLocalID)
{
-WORD wOffset;
-DWORD dwData;
+unsigned short wOffset;
+unsigned long dwData;
int ii;
if (byLocalID <= 1)
@@ -1599,10 +1601,10 @@ int ii;
*
*/
/*
-void MACvEnableDefaultKey (DWORD_PTR dwIoBase, BYTE byLocalID)
+void MACvEnableDefaultKey (unsigned long dwIoBase, unsigned char byLocalID)
{
-WORD wOffset;
-DWORD dwData;
+unsigned short wOffset;
+unsigned long dwData;
if (byLocalID <= 1)
@@ -1634,10 +1636,10 @@ DWORD dwData;
* Return Value: none
*
*/
-void MACvDisableDefaultKey (DWORD_PTR dwIoBase)
+void MACvDisableDefaultKey (unsigned long dwIoBase)
{
-WORD wOffset;
-DWORD dwData;
+unsigned short wOffset;
+unsigned long dwData;
wOffset = MISCFIFO_KEYETRY0;
@@ -1664,10 +1666,11 @@ DWORD dwData;
* Return Value: none
*
*/
-void MACvSetDefaultTKIPKeyEntry (DWORD_PTR dwIoBase, UINT uKeyLen, UINT uKeyIdx, PDWORD pdwKey, BYTE byLocalID)
+void MACvSetDefaultTKIPKeyEntry (unsigned long dwIoBase, unsigned int uKeyLen,
+ unsigned int uKeyIdx, unsigned long *pdwKey, unsigned char byLocalID)
{
-WORD wOffset;
-DWORD dwData;
+unsigned short wOffset;
+unsigned long dwData;
int ii;
if (byLocalID <= 1)
@@ -1720,10 +1723,10 @@ int ii;
*
*/
-void MACvSetDefaultKeyCtl (DWORD_PTR dwIoBase, WORD wKeyCtl, UINT uEntryIdx, BYTE byLocalID)
+void MACvSetDefaultKeyCtl (unsigned long dwIoBase, unsigned short wKeyCtl, unsigned int uEntryIdx, unsigned char byLocalID)
{
-WORD wOffset;
-DWORD dwData;
+unsigned short wOffset;
+unsigned long dwData;
if (byLocalID <= 1)
return;
diff --git a/drivers/staging/vt6655/mac.h b/drivers/staging/vt6655/mac.h
index 5eb7f57f718..b96d27ee254 100644
--- a/drivers/staging/vt6655/mac.h
+++ b/drivers/staging/vt6655/mac.h
@@ -663,28 +663,28 @@
#define MACvRegBitsOn(dwIoBase, byRegOfs, byBits) \
{ \
- BYTE byData; \
+ unsigned char byData; \
VNSvInPortB(dwIoBase + byRegOfs, &byData); \
VNSvOutPortB(dwIoBase + byRegOfs, byData | (byBits)); \
}
#define MACvWordRegBitsOn(dwIoBase, byRegOfs, wBits) \
{ \
- WORD wData; \
+ unsigned short wData; \
VNSvInPortW(dwIoBase + byRegOfs, &wData); \
VNSvOutPortW(dwIoBase + byRegOfs, wData | (wBits)); \
}
#define MACvDWordRegBitsOn(dwIoBase, byRegOfs, dwBits) \
{ \
- DWORD dwData; \
+ unsigned long dwData; \
VNSvInPortD(dwIoBase + byRegOfs, &dwData); \
VNSvOutPortD(dwIoBase + byRegOfs, dwData | (dwBits)); \
}
#define MACvRegBitsOnEx(dwIoBase, byRegOfs, byMask, byBits) \
{ \
- BYTE byData; \
+ unsigned char byData; \
VNSvInPortB(dwIoBase + byRegOfs, &byData); \
byData &= byMask; \
VNSvOutPortB(dwIoBase + byRegOfs, byData | (byBits)); \
@@ -692,21 +692,21 @@
#define MACvRegBitsOff(dwIoBase, byRegOfs, byBits) \
{ \
- BYTE byData; \
+ unsigned char byData; \
VNSvInPortB(dwIoBase + byRegOfs, &byData); \
VNSvOutPortB(dwIoBase + byRegOfs, byData & ~(byBits)); \
}
#define MACvWordRegBitsOff(dwIoBase, byRegOfs, wBits) \
{ \
- WORD wData; \
+ unsigned short wData; \
VNSvInPortW(dwIoBase + byRegOfs, &wData); \
VNSvOutPortW(dwIoBase + byRegOfs, wData & ~(wBits)); \
}
#define MACvDWordRegBitsOff(dwIoBase, byRegOfs, dwBits) \
{ \
- DWORD dwData; \
+ unsigned long dwData; \
VNSvInPortD(dwIoBase + byRegOfs, &dwData); \
VNSvOutPortD(dwIoBase + byRegOfs, dwData & ~(dwBits)); \
}
@@ -714,37 +714,37 @@
#define MACvGetCurrRx0DescAddr(dwIoBase, pdwCurrDescAddr) \
{ \
VNSvInPortD(dwIoBase + MAC_REG_RXDMAPTR0, \
- (PDWORD)pdwCurrDescAddr); \
+ (unsigned long *)pdwCurrDescAddr); \
}
#define MACvGetCurrRx1DescAddr(dwIoBase, pdwCurrDescAddr) \
{ \
VNSvInPortD(dwIoBase + MAC_REG_RXDMAPTR1, \
- (PDWORD)pdwCurrDescAddr); \
+ (unsigned long *)pdwCurrDescAddr); \
}
#define MACvGetCurrTx0DescAddr(dwIoBase, pdwCurrDescAddr) \
{ \
VNSvInPortD(dwIoBase + MAC_REG_TXDMAPTR0, \
- (PDWORD)pdwCurrDescAddr); \
+ (unsigned long *)pdwCurrDescAddr); \
}
#define MACvGetCurrAC0DescAddr(dwIoBase, pdwCurrDescAddr) \
{ \
VNSvInPortD(dwIoBase + MAC_REG_AC0DMAPTR, \
- (PDWORD)pdwCurrDescAddr); \
+ (unsigned long *)pdwCurrDescAddr); \
}
#define MACvGetCurrSyncDescAddr(dwIoBase, pdwCurrDescAddr) \
{ \
VNSvInPortD(dwIoBase + MAC_REG_SYNCDMAPTR, \
- (PDWORD)pdwCurrDescAddr); \
+ (unsigned long *)pdwCurrDescAddr); \
}
#define MACvGetCurrATIMDescAddr(dwIoBase, pdwCurrDescAddr) \
{ \
VNSvInPortD(dwIoBase + MAC_REG_ATIMDMAPTR, \
- (PDWORD)pdwCurrDescAddr); \
+ (unsigned long *)pdwCurrDescAddr); \
} \
// set the chip with current BCN tx descriptor address
@@ -765,7 +765,7 @@
{ \
VNSvOutPortB(dwIoBase + MAC_REG_PAGE1SEL, 1); \
VNSvInPortB(dwIoBase + MAC_REG_BSSID0, \
- (PBYTE)pbyEtherAddr); \
+ (unsigned char *)pbyEtherAddr); \
VNSvInPortB(dwIoBase + MAC_REG_BSSID0 + 1, \
pbyEtherAddr + 1); \
VNSvInPortB(dwIoBase + MAC_REG_BSSID0 + 2, \
@@ -801,7 +801,7 @@
{ \
VNSvOutPortB(dwIoBase + MAC_REG_PAGE1SEL, 1); \
VNSvInPortB(dwIoBase + MAC_REG_PAR0, \
- (PBYTE)pbyEtherAddr); \
+ (unsigned char *)pbyEtherAddr); \
VNSvInPortB(dwIoBase + MAC_REG_PAR0 + 1, \
pbyEtherAddr + 1); \
VNSvInPortB(dwIoBase + MAC_REG_PAR0 + 2, \
@@ -873,7 +873,7 @@
#define MACvReceive0(dwIoBase) \
{ \
- DWORD dwData; \
+ unsigned long dwData; \
VNSvInPortD(dwIoBase + MAC_REG_RXDMACTL0, &dwData); \
if (dwData & DMACTL_RUN) { \
VNSvOutPortD(dwIoBase + MAC_REG_RXDMACTL0, DMACTL_WAKE);\
@@ -885,7 +885,7 @@
#define MACvReceive1(dwIoBase) \
{ \
- DWORD dwData; \
+ unsigned long dwData; \
VNSvInPortD(dwIoBase + MAC_REG_RXDMACTL1, &dwData); \
if (dwData & DMACTL_RUN) { \
VNSvOutPortD(dwIoBase + MAC_REG_RXDMACTL1, DMACTL_WAKE);\
@@ -902,7 +902,7 @@
#define MACvTransmit0(dwIoBase) \
{ \
- DWORD dwData; \
+ unsigned long dwData; \
VNSvInPortD(dwIoBase + MAC_REG_TXDMACTL0, &dwData); \
if (dwData & DMACTL_RUN) { \
VNSvOutPortD(dwIoBase + MAC_REG_TXDMACTL0, DMACTL_WAKE);\
@@ -914,7 +914,7 @@
#define MACvTransmitAC0(dwIoBase) \
{ \
- DWORD dwData; \
+ unsigned long dwData; \
VNSvInPortD(dwIoBase + MAC_REG_AC0DMACTL, &dwData); \
if (dwData & DMACTL_RUN) { \
VNSvOutPortD(dwIoBase + MAC_REG_AC0DMACTL, DMACTL_WAKE);\
@@ -926,7 +926,7 @@
#define MACvTransmitSYNC(dwIoBase) \
{ \
- DWORD dwData; \
+ unsigned long dwData; \
VNSvInPortD(dwIoBase + MAC_REG_SYNCDMACTL, &dwData); \
if (dwData & DMACTL_RUN) { \
VNSvOutPortD(dwIoBase + MAC_REG_SYNCDMACTL, DMACTL_WAKE);\
@@ -938,7 +938,7 @@
#define MACvTransmitATIM(dwIoBase) \
{ \
- DWORD dwData; \
+ unsigned long dwData; \
VNSvInPortD(dwIoBase + MAC_REG_ATIMDMACTL, &dwData); \
if (dwData & DMACTL_RUN) { \
VNSvOutPortD(dwIoBase + MAC_REG_ATIMDMACTL, DMACTL_WAKE);\
@@ -955,7 +955,7 @@
#define MACvClearStckDS(dwIoBase) \
{ \
- BYTE byOrgValue; \
+ unsigned char byOrgValue; \
VNSvInPortB(dwIoBase + MAC_REG_STICKHW, &byOrgValue); \
byOrgValue = byOrgValue & 0xFC; \
VNSvOutPortB(dwIoBase + MAC_REG_STICKHW, byOrgValue); \
@@ -1002,7 +1002,7 @@
#define MACvEnableProtectMD(dwIoBase) \
{ \
- DWORD dwOrgValue; \
+ unsigned long dwOrgValue; \
VNSvInPortD(dwIoBase + MAC_REG_ENCFG , &dwOrgValue); \
dwOrgValue = dwOrgValue | EnCFG_ProtectMd; \
VNSvOutPortD(dwIoBase + MAC_REG_ENCFG, dwOrgValue); \
@@ -1010,7 +1010,7 @@
#define MACvDisableProtectMD(dwIoBase) \
{ \
- DWORD dwOrgValue; \
+ unsigned long dwOrgValue; \
VNSvInPortD(dwIoBase + MAC_REG_ENCFG , &dwOrgValue); \
dwOrgValue = dwOrgValue & ~EnCFG_ProtectMd; \
VNSvOutPortD(dwIoBase + MAC_REG_ENCFG, dwOrgValue); \
@@ -1018,7 +1018,7 @@
#define MACvEnableBarkerPreambleMd(dwIoBase) \
{ \
- DWORD dwOrgValue; \
+ unsigned long dwOrgValue; \
VNSvInPortD(dwIoBase + MAC_REG_ENCFG , &dwOrgValue); \
dwOrgValue = dwOrgValue | EnCFG_BarkerPream; \
VNSvOutPortD(dwIoBase + MAC_REG_ENCFG, dwOrgValue); \
@@ -1026,7 +1026,7 @@
#define MACvDisableBarkerPreambleMd(dwIoBase) \
{ \
- DWORD dwOrgValue; \
+ unsigned long dwOrgValue; \
VNSvInPortD(dwIoBase + MAC_REG_ENCFG , &dwOrgValue); \
dwOrgValue = dwOrgValue & ~EnCFG_BarkerPream; \
VNSvOutPortD(dwIoBase + MAC_REG_ENCFG, dwOrgValue); \
@@ -1034,10 +1034,10 @@
#define MACvSetBBType(dwIoBase, byTyp) \
{ \
- DWORD dwOrgValue; \
+ unsigned long dwOrgValue; \
VNSvInPortD(dwIoBase + MAC_REG_ENCFG , &dwOrgValue); \
dwOrgValue = dwOrgValue & ~EnCFG_BBType_MASK; \
- dwOrgValue = dwOrgValue | (DWORD) byTyp; \
+ dwOrgValue = dwOrgValue | (unsigned long) byTyp; \
VNSvOutPortD(dwIoBase + MAC_REG_ENCFG, dwOrgValue); \
}
@@ -1074,78 +1074,81 @@
/*--------------------- Export Functions --------------------------*/
-extern WORD TxRate_iwconfig;//2008-5-8 <add> by chester
-void MACvReadAllRegs(DWORD_PTR dwIoBase, PBYTE pbyMacRegs);
-
-BOOL MACbIsRegBitsOn(DWORD_PTR dwIoBase, BYTE byRegOfs, BYTE byTestBits);
-BOOL MACbIsRegBitsOff(DWORD_PTR dwIoBase, BYTE byRegOfs, BYTE byTestBits);
-
-BOOL MACbIsIntDisable(DWORD_PTR dwIoBase);
-
-BYTE MACbyReadMultiAddr(DWORD_PTR dwIoBase, UINT uByteIdx);
-void MACvWriteMultiAddr(DWORD_PTR dwIoBase, UINT uByteIdx, BYTE byData);
-void MACvSetMultiAddrByHash(DWORD_PTR dwIoBase, BYTE byHashIdx);
-void MACvResetMultiAddrByHash(DWORD_PTR dwIoBase, BYTE byHashIdx);
-
-void MACvSetRxThreshold(DWORD_PTR dwIoBase, BYTE byThreshold);
-void MACvGetRxThreshold(DWORD_PTR dwIoBase, PBYTE pbyThreshold);
-
-void MACvSetTxThreshold(DWORD_PTR dwIoBase, BYTE byThreshold);
-void MACvGetTxThreshold(DWORD_PTR dwIoBase, PBYTE pbyThreshold);
-
-void MACvSetDmaLength(DWORD_PTR dwIoBase, BYTE byDmaLength);
-void MACvGetDmaLength(DWORD_PTR dwIoBase, PBYTE pbyDmaLength);
-
-void MACvSetShortRetryLimit(DWORD_PTR dwIoBase, BYTE byRetryLimit);
-void MACvGetShortRetryLimit(DWORD_PTR dwIoBase, PBYTE pbyRetryLimit);
-
-void MACvSetLongRetryLimit(DWORD_PTR dwIoBase, BYTE byRetryLimit);
-void MACvGetLongRetryLimit(DWORD_PTR dwIoBase, PBYTE pbyRetryLimit);
-
-void MACvSetLoopbackMode(DWORD_PTR dwIoBase, BYTE byLoopbackMode);
-BOOL MACbIsInLoopbackMode(DWORD_PTR dwIoBase);
-
-void MACvSetPacketFilter(DWORD_PTR dwIoBase, WORD wFilterType);
-
-void MACvSaveContext(DWORD_PTR dwIoBase, PBYTE pbyCxtBuf);
-void MACvRestoreContext(DWORD_PTR dwIoBase, PBYTE pbyCxtBuf);
-BOOL MACbCompareContext(DWORD_PTR dwIoBase, PBYTE pbyCxtBuf);
-
-BOOL MACbSoftwareReset(DWORD_PTR dwIoBase);
-BOOL MACbSafeSoftwareReset(DWORD_PTR dwIoBase);
-BOOL MACbSafeRxOff(DWORD_PTR dwIoBase);
-BOOL MACbSafeTxOff(DWORD_PTR dwIoBase);
-BOOL MACbSafeStop(DWORD_PTR dwIoBase);
-BOOL MACbShutdown(DWORD_PTR dwIoBase);
-void MACvInitialize(DWORD_PTR dwIoBase);
-void MACvSetCurrRx0DescAddr(DWORD_PTR dwIoBase, DWORD dwCurrDescAddr);
-void MACvSetCurrRx1DescAddr(DWORD_PTR dwIoBase, DWORD dwCurrDescAddr);
-void MACvSetCurrTXDescAddr(int iTxType, DWORD_PTR dwIoBase, DWORD dwCurrDescAddr);
-void MACvSetCurrTx0DescAddrEx(DWORD_PTR dwIoBase, DWORD dwCurrDescAddr);
-void MACvSetCurrAC0DescAddrEx(DWORD_PTR dwIoBase, DWORD dwCurrDescAddr);
-void MACvSetCurrSyncDescAddrEx(DWORD_PTR dwIoBase, DWORD dwCurrDescAddr);
-void MACvSetCurrATIMDescAddrEx(DWORD_PTR dwIoBase, DWORD dwCurrDescAddr);
-void MACvTimer0MicroSDelay(DWORD_PTR dwIoBase, UINT uDelay);
-void MACvOneShotTimer0MicroSec(DWORD_PTR dwIoBase, UINT uDelayTime);
-void MACvOneShotTimer1MicroSec(DWORD_PTR dwIoBase, UINT uDelayTime);
-
-void MACvSetMISCFifo(DWORD_PTR dwIoBase, WORD wOffset, DWORD dwData);
-
-BOOL MACbTxDMAOff (DWORD_PTR dwIoBase, UINT idx);
-
-void MACvClearBusSusInd(DWORD_PTR dwIoBase);
-void MACvEnableBusSusEn(DWORD_PTR dwIoBase);
-
-BOOL MACbFlushSYNCFifo(DWORD_PTR dwIoBase);
-BOOL MACbPSWakeup(DWORD_PTR dwIoBase);
-
-void MACvSetKeyEntry(DWORD_PTR dwIoBase, WORD wKeyCtl, UINT uEntryIdx, UINT uKeyIdx, PBYTE pbyAddr, PDWORD pdwKey, BYTE byLocalID);
-void MACvDisableKeyEntry(DWORD_PTR dwIoBase, UINT uEntryIdx);
-void MACvSetDefaultKeyEntry(DWORD_PTR dwIoBase, UINT uKeyLen, UINT uKeyIdx, PDWORD pdwKey, BYTE byLocalID);
-//void MACvEnableDefaultKey(DWORD_PTR dwIoBase, BYTE byLocalID);
-void MACvDisableDefaultKey(DWORD_PTR dwIoBase);
-void MACvSetDefaultTKIPKeyEntry(DWORD_PTR dwIoBase, UINT uKeyLen, UINT uKeyIdx, PDWORD pdwKey, BYTE byLocalID);
-void MACvSetDefaultKeyCtl(DWORD_PTR dwIoBase, WORD wKeyCtl, UINT uEntryIdx, BYTE byLocalID);
+extern unsigned short TxRate_iwconfig;//2008-5-8 <add> by chester
+void MACvReadAllRegs(unsigned long dwIoBase, unsigned char *pbyMacRegs);
+
+bool MACbIsRegBitsOn(unsigned long dwIoBase, unsigned char byRegOfs, unsigned char byTestBits);
+bool MACbIsRegBitsOff(unsigned long dwIoBase, unsigned char byRegOfs, unsigned char byTestBits);
+
+bool MACbIsIntDisable(unsigned long dwIoBase);
+
+unsigned char MACbyReadMultiAddr(unsigned long dwIoBase, unsigned int uByteIdx);
+void MACvWriteMultiAddr(unsigned long dwIoBase, unsigned int uByteIdx, unsigned char byData);
+void MACvSetMultiAddrByHash(unsigned long dwIoBase, unsigned char byHashIdx);
+void MACvResetMultiAddrByHash(unsigned long dwIoBase, unsigned char byHashIdx);
+
+void MACvSetRxThreshold(unsigned long dwIoBase, unsigned char byThreshold);
+void MACvGetRxThreshold(unsigned long dwIoBase, unsigned char *pbyThreshold);
+
+void MACvSetTxThreshold(unsigned long dwIoBase, unsigned char byThreshold);
+void MACvGetTxThreshold(unsigned long dwIoBase, unsigned char *pbyThreshold);
+
+void MACvSetDmaLength(unsigned long dwIoBase, unsigned char byDmaLength);
+void MACvGetDmaLength(unsigned long dwIoBase, unsigned char *pbyDmaLength);
+
+void MACvSetShortRetryLimit(unsigned long dwIoBase, unsigned char byRetryLimit);
+void MACvGetShortRetryLimit(unsigned long dwIoBase, unsigned char *pbyRetryLimit);
+
+void MACvSetLongRetryLimit(unsigned long dwIoBase, unsigned char byRetryLimit);
+void MACvGetLongRetryLimit(unsigned long dwIoBase, unsigned char *pbyRetryLimit);
+
+void MACvSetLoopbackMode(unsigned long dwIoBase, unsigned char byLoopbackMode);
+bool MACbIsInLoopbackMode(unsigned long dwIoBase);
+
+void MACvSetPacketFilter(unsigned long dwIoBase, unsigned short wFilterType);
+
+void MACvSaveContext(unsigned long dwIoBase, unsigned char *pbyCxtBuf);
+void MACvRestoreContext(unsigned long dwIoBase, unsigned char *pbyCxtBuf);
+bool MACbCompareContext(unsigned long dwIoBase, unsigned char *pbyCxtBuf);
+
+bool MACbSoftwareReset(unsigned long dwIoBase);
+bool MACbSafeSoftwareReset(unsigned long dwIoBase);
+bool MACbSafeRxOff(unsigned long dwIoBase);
+bool MACbSafeTxOff(unsigned long dwIoBase);
+bool MACbSafeStop(unsigned long dwIoBase);
+bool MACbShutdown(unsigned long dwIoBase);
+void MACvInitialize(unsigned long dwIoBase);
+void MACvSetCurrRx0DescAddr(unsigned long dwIoBase, unsigned long dwCurrDescAddr);
+void MACvSetCurrRx1DescAddr(unsigned long dwIoBase, unsigned long dwCurrDescAddr);
+void MACvSetCurrTXDescAddr(int iTxType, unsigned long dwIoBase, unsigned long dwCurrDescAddr);
+void MACvSetCurrTx0DescAddrEx(unsigned long dwIoBase, unsigned long dwCurrDescAddr);
+void MACvSetCurrAC0DescAddrEx(unsigned long dwIoBase, unsigned long dwCurrDescAddr);
+void MACvSetCurrSyncDescAddrEx(unsigned long dwIoBase, unsigned long dwCurrDescAddr);
+void MACvSetCurrATIMDescAddrEx(unsigned long dwIoBase, unsigned long dwCurrDescAddr);
+void MACvTimer0MicroSDelay(unsigned long dwIoBase, unsigned int uDelay);
+void MACvOneShotTimer0MicroSec(unsigned long dwIoBase, unsigned int uDelayTime);
+void MACvOneShotTimer1MicroSec(unsigned long dwIoBase, unsigned int uDelayTime);
+
+void MACvSetMISCFifo(unsigned long dwIoBase, unsigned short wOffset, unsigned long dwData);
+
+bool MACbTxDMAOff (unsigned long dwIoBase, unsigned int idx);
+
+void MACvClearBusSusInd(unsigned long dwIoBase);
+void MACvEnableBusSusEn(unsigned long dwIoBase);
+
+bool MACbFlushSYNCFifo(unsigned long dwIoBase);
+bool MACbPSWakeup(unsigned long dwIoBase);
+
+void MACvSetKeyEntry(unsigned long dwIoBase, unsigned short wKeyCtl, unsigned int uEntryIdx,
+ unsigned int uKeyIdx, unsigned char *pbyAddr, unsigned long *pdwKey, unsigned char byLocalID);
+void MACvDisableKeyEntry(unsigned long dwIoBase, unsigned int uEntryIdx);
+void MACvSetDefaultKeyEntry(unsigned long dwIoBase, unsigned int uKeyLen,
+ unsigned int uKeyIdx, unsigned long *pdwKey, unsigned char byLocalID);
+//void MACvEnableDefaultKey(unsigned long dwIoBase, unsigned char byLocalID);
+void MACvDisableDefaultKey(unsigned long dwIoBase);
+void MACvSetDefaultTKIPKeyEntry(unsigned long dwIoBase, unsigned int uKeyLen,
+ unsigned int uKeyIdx, unsigned long *pdwKey, unsigned char byLocalID);
+void MACvSetDefaultKeyCtl(unsigned long dwIoBase, unsigned short wKeyCtl, unsigned int uEntryIdx, unsigned char byLocalID);
#endif // __MAC_H__
diff --git a/drivers/staging/vt6655/mib.c b/drivers/staging/vt6655/mib.c
index 4ca7877075b..1b91a837095 100644
--- a/drivers/staging/vt6655/mib.c
+++ b/drivers/staging/vt6655/mib.c
@@ -90,7 +90,7 @@ void STAvClearAllCounter (PSStatCounter pStatistic)
* Return Value: none
*
*/
-void STAvUpdateIsrStatCounter (PSStatCounter pStatistic, DWORD dwIsr)
+void STAvUpdateIsrStatCounter (PSStatCounter pStatistic, unsigned long dwIsr)
{
/**********************/
/* ABNORMAL interrupt */
@@ -177,8 +177,8 @@ void STAvUpdateIsrStatCounter (PSStatCounter pStatistic, DWORD dwIsr)
*
*/
void STAvUpdateRDStatCounter (PSStatCounter pStatistic,
- BYTE byRSR, BYTE byNewRSR, BYTE byRxRate,
- PBYTE pbyBuffer, UINT cbFrameLength)
+ unsigned char byRSR, unsigned char byNewRSR, unsigned char byRxRate,
+ unsigned char *pbyBuffer, unsigned int cbFrameLength)
{
//need change
PS802_11Header pHeader = (PS802_11Header)pbyBuffer;
@@ -194,15 +194,15 @@ void STAvUpdateRDStatCounter (PSStatCounter pStatistic,
// update counters in case that successful transmit
if (byRSR & RSR_ADDRBROAD) {
pStatistic->ullRxBroadcastFrames++;
- pStatistic->ullRxBroadcastBytes += (ULONGLONG)cbFrameLength;
+ pStatistic->ullRxBroadcastBytes += (unsigned long long) cbFrameLength;
}
else if (byRSR & RSR_ADDRMULTI) {
pStatistic->ullRxMulticastFrames++;
- pStatistic->ullRxMulticastBytes += (ULONGLONG)cbFrameLength;
+ pStatistic->ullRxMulticastBytes += (unsigned long long) cbFrameLength;
}
else {
pStatistic->ullRxDirectedFrames++;
- pStatistic->ullRxDirectedBytes += (ULONGLONG)cbFrameLength;
+ pStatistic->ullRxDirectedBytes += (unsigned long long) cbFrameLength;
}
}
}
@@ -212,87 +212,87 @@ void STAvUpdateRDStatCounter (PSStatCounter pStatistic,
if(byRSR & RSR_CRCOK) {
pStatistic->CustomStat.ullRsr11MCRCOk++;
}
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"11M: ALL[%d], OK[%d]:[%02x]\n", (INT)pStatistic->CustomStat.ullRsr11M, (INT)pStatistic->CustomStat.ullRsr11MCRCOk, byRSR);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"11M: ALL[%d], OK[%d]:[%02x]\n", (int)pStatistic->CustomStat.ullRsr11M, (int)pStatistic->CustomStat.ullRsr11MCRCOk, byRSR);
}
else if(byRxRate==11) {
pStatistic->CustomStat.ullRsr5M++;
if(byRSR & RSR_CRCOK) {
pStatistic->CustomStat.ullRsr5MCRCOk++;
}
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO" 5M: ALL[%d], OK[%d]:[%02x]\n", (INT)pStatistic->CustomStat.ullRsr5M, (INT)pStatistic->CustomStat.ullRsr5MCRCOk, byRSR);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO" 5M: ALL[%d], OK[%d]:[%02x]\n", (int)pStatistic->CustomStat.ullRsr5M, (int)pStatistic->CustomStat.ullRsr5MCRCOk, byRSR);
}
else if(byRxRate==4) {
pStatistic->CustomStat.ullRsr2M++;
if(byRSR & RSR_CRCOK) {
pStatistic->CustomStat.ullRsr2MCRCOk++;
}
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO" 2M: ALL[%d], OK[%d]:[%02x]\n", (INT)pStatistic->CustomStat.ullRsr2M, (INT)pStatistic->CustomStat.ullRsr2MCRCOk, byRSR);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO" 2M: ALL[%d], OK[%d]:[%02x]\n", (int)pStatistic->CustomStat.ullRsr2M, (int)pStatistic->CustomStat.ullRsr2MCRCOk, byRSR);
}
else if(byRxRate==2){
pStatistic->CustomStat.ullRsr1M++;
if(byRSR & RSR_CRCOK) {
pStatistic->CustomStat.ullRsr1MCRCOk++;
}
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO" 1M: ALL[%d], OK[%d]:[%02x]\n", (INT)pStatistic->CustomStat.ullRsr1M, (INT)pStatistic->CustomStat.ullRsr1MCRCOk, byRSR);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO" 1M: ALL[%d], OK[%d]:[%02x]\n", (int)pStatistic->CustomStat.ullRsr1M, (int)pStatistic->CustomStat.ullRsr1MCRCOk, byRSR);
}
else if(byRxRate==12){
pStatistic->CustomStat.ullRsr6M++;
if(byRSR & RSR_CRCOK) {
pStatistic->CustomStat.ullRsr6MCRCOk++;
}
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO" 6M: ALL[%d], OK[%d]\n", (INT)pStatistic->CustomStat.ullRsr6M, (INT)pStatistic->CustomStat.ullRsr6MCRCOk);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO" 6M: ALL[%d], OK[%d]\n", (int)pStatistic->CustomStat.ullRsr6M, (int)pStatistic->CustomStat.ullRsr6MCRCOk);
}
else if(byRxRate==18){
pStatistic->CustomStat.ullRsr9M++;
if(byRSR & RSR_CRCOK) {
pStatistic->CustomStat.ullRsr9MCRCOk++;
}
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO" 9M: ALL[%d], OK[%d]\n", (INT)pStatistic->CustomStat.ullRsr9M, (INT)pStatistic->CustomStat.ullRsr9MCRCOk);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO" 9M: ALL[%d], OK[%d]\n", (int)pStatistic->CustomStat.ullRsr9M, (int)pStatistic->CustomStat.ullRsr9MCRCOk);
}
else if(byRxRate==24){
pStatistic->CustomStat.ullRsr12M++;
if(byRSR & RSR_CRCOK) {
pStatistic->CustomStat.ullRsr12MCRCOk++;
}
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"12M: ALL[%d], OK[%d]\n", (INT)pStatistic->CustomStat.ullRsr12M, (INT)pStatistic->CustomStat.ullRsr12MCRCOk);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"12M: ALL[%d], OK[%d]\n", (int)pStatistic->CustomStat.ullRsr12M, (int)pStatistic->CustomStat.ullRsr12MCRCOk);
}
else if(byRxRate==36){
pStatistic->CustomStat.ullRsr18M++;
if(byRSR & RSR_CRCOK) {
pStatistic->CustomStat.ullRsr18MCRCOk++;
}
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"18M: ALL[%d], OK[%d]\n", (INT)pStatistic->CustomStat.ullRsr18M, (INT)pStatistic->CustomStat.ullRsr18MCRCOk);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"18M: ALL[%d], OK[%d]\n", (int)pStatistic->CustomStat.ullRsr18M, (int)pStatistic->CustomStat.ullRsr18MCRCOk);
}
else if(byRxRate==48){
pStatistic->CustomStat.ullRsr24M++;
if(byRSR & RSR_CRCOK) {
pStatistic->CustomStat.ullRsr24MCRCOk++;
}
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"24M: ALL[%d], OK[%d]\n", (INT)pStatistic->CustomStat.ullRsr24M, (INT)pStatistic->CustomStat.ullRsr24MCRCOk);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"24M: ALL[%d], OK[%d]\n", (int)pStatistic->CustomStat.ullRsr24M, (int)pStatistic->CustomStat.ullRsr24MCRCOk);
}
else if(byRxRate==72){
pStatistic->CustomStat.ullRsr36M++;
if(byRSR & RSR_CRCOK) {
pStatistic->CustomStat.ullRsr36MCRCOk++;
}
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"36M: ALL[%d], OK[%d]\n", (INT)pStatistic->CustomStat.ullRsr36M, (INT)pStatistic->CustomStat.ullRsr36MCRCOk);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"36M: ALL[%d], OK[%d]\n", (int)pStatistic->CustomStat.ullRsr36M, (int)pStatistic->CustomStat.ullRsr36MCRCOk);
}
else if(byRxRate==96){
pStatistic->CustomStat.ullRsr48M++;
if(byRSR & RSR_CRCOK) {
pStatistic->CustomStat.ullRsr48MCRCOk++;
}
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"48M: ALL[%d], OK[%d]\n", (INT)pStatistic->CustomStat.ullRsr48M, (INT)pStatistic->CustomStat.ullRsr48MCRCOk);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"48M: ALL[%d], OK[%d]\n", (int)pStatistic->CustomStat.ullRsr48M, (int)pStatistic->CustomStat.ullRsr48MCRCOk);
}
else if(byRxRate==108){
pStatistic->CustomStat.ullRsr54M++;
if(byRSR & RSR_CRCOK) {
pStatistic->CustomStat.ullRsr54MCRCOk++;
}
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"54M: ALL[%d], OK[%d]\n", (INT)pStatistic->CustomStat.ullRsr54M, (INT)pStatistic->CustomStat.ullRsr54MCRCOk);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"54M: ALL[%d], OK[%d]\n", (int)pStatistic->CustomStat.ullRsr54M, (int)pStatistic->CustomStat.ullRsr54MCRCOk);
}
else {
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Unknown: Total[%d], CRCOK[%d]\n", (INT)pStatistic->dwRsrRxPacket+1, (INT)pStatistic->dwRsrCRCOk);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Unknown: Total[%d], CRCOK[%d]\n", (int)pStatistic->dwRsrRxPacket+1, (int)pStatistic->dwRsrCRCOk);
}
if (byRSR & RSR_BSSIDOK)
@@ -341,10 +341,10 @@ void STAvUpdateRDStatCounter (PSStatCounter pStatistic,
if (WLAN_GET_FC_MOREFRAG(pHeader->wFrameCtl))
pStatistic->dwRsrRxFragment++;
- if (cbFrameLength < MIN_PACKET_LEN + 4) {
+ if (cbFrameLength < ETH_ZLEN + 4) {
pStatistic->dwRsrRunt++;
}
- else if (cbFrameLength == MIN_PACKET_LEN + 4) {
+ else if (cbFrameLength == ETH_ZLEN + 4) {
pStatistic->dwRsrRxFrmLen64++;
}
else if ((65 <= cbFrameLength) && (cbFrameLength <= 127)) {
@@ -389,11 +389,11 @@ void STAvUpdateRDStatCounter (PSStatCounter pStatistic,
void
STAvUpdateRDStatCounterEx (
PSStatCounter pStatistic,
- BYTE byRSR,
- BYTE byNewRSR,
- BYTE byRxRate,
- PBYTE pbyBuffer,
- UINT cbFrameLength
+ unsigned char byRSR,
+ unsigned char byNewRSR,
+ unsigned char byRxRate,
+ unsigned char *pbyBuffer,
+ unsigned int cbFrameLength
)
{
STAvUpdateRDStatCounter(
@@ -408,7 +408,7 @@ STAvUpdateRDStatCounterEx (
// rx length
pStatistic->dwCntRxFrmLength = cbFrameLength;
// rx pattern, we just see 10 bytes for sample
- memcpy(pStatistic->abyCntRxPattern, (PBYTE)pbyBuffer, 10);
+ memcpy(pStatistic->abyCntRxPattern, (unsigned char *)pbyBuffer, 10);
}
@@ -432,16 +432,16 @@ STAvUpdateRDStatCounterEx (
void
STAvUpdateTDStatCounter (
PSStatCounter pStatistic,
- BYTE byTSR0,
- BYTE byTSR1,
- PBYTE pbyBuffer,
- UINT cbFrameLength,
- UINT uIdx
+ unsigned char byTSR0,
+ unsigned char byTSR1,
+ unsigned char *pbyBuffer,
+ unsigned int cbFrameLength,
+ unsigned int uIdx
)
{
PWLAN_80211HDR_A4 pHeader;
- PBYTE pbyDestAddr;
- BYTE byTSR0_NCR = byTSR0 & TSR0_NCR;
+ unsigned char *pbyDestAddr;
+ unsigned char byTSR0_NCR = byTSR0 & TSR0_NCR;
@@ -471,17 +471,17 @@ STAvUpdateTDStatCounter (
pStatistic->CustomStat.ullTsrAllOK =
(pStatistic->ullTsrOK[TYPE_AC0DMA] + pStatistic->ullTsrOK[TYPE_TXDMA0]);
// update counters in case that successful transmit
- if (IS_BROADCAST_ADDRESS(pbyDestAddr)) {
+ if (is_broadcast_ether_addr(pbyDestAddr)) {
pStatistic->ullTxBroadcastFrames[uIdx]++;
- pStatistic->ullTxBroadcastBytes[uIdx] += (ULONGLONG)cbFrameLength;
+ pStatistic->ullTxBroadcastBytes[uIdx] += (unsigned long long) cbFrameLength;
}
- else if (IS_MULTICAST_ADDRESS(pbyDestAddr)) {
+ else if (is_multicast_ether_addr(pbyDestAddr)) {
pStatistic->ullTxMulticastFrames[uIdx]++;
- pStatistic->ullTxMulticastBytes[uIdx] += (ULONGLONG)cbFrameLength;
+ pStatistic->ullTxMulticastBytes[uIdx] += (unsigned long long) cbFrameLength;
}
else {
pStatistic->ullTxDirectedFrames[uIdx]++;
- pStatistic->ullTxDirectedBytes[uIdx] += (ULONGLONG)cbFrameLength;
+ pStatistic->ullTxDirectedBytes[uIdx] += (unsigned long long) cbFrameLength;
}
}
else {
@@ -495,9 +495,9 @@ STAvUpdateTDStatCounter (
pStatistic->dwTsrACKData[uIdx]++;
}
- if (IS_BROADCAST_ADDRESS(pbyDestAddr))
+ if (is_broadcast_ether_addr(pbyDestAddr))
pStatistic->dwTsrBroadcast[uIdx]++;
- else if (IS_MULTICAST_ADDRESS(pbyDestAddr))
+ else if (is_multicast_ether_addr(pbyDestAddr))
pStatistic->dwTsrMulticast[uIdx]++;
else
pStatistic->dwTsrDirected[uIdx]++;
@@ -522,13 +522,13 @@ STAvUpdateTDStatCounter (
void
STAvUpdateTDStatCounterEx (
PSStatCounter pStatistic,
- PBYTE pbyBuffer,
- DWORD cbFrameLength
+ unsigned char *pbyBuffer,
+ unsigned long cbFrameLength
)
{
- UINT uPktLength;
+ unsigned int uPktLength;
- uPktLength = (UINT)cbFrameLength;
+ uPktLength = (unsigned int)cbFrameLength;
// tx length
pStatistic->dwCntTxBufLength = uPktLength;
@@ -555,25 +555,25 @@ void
STAvUpdate802_11Counter(
PSDot11Counters p802_11Counter,
PSStatCounter pStatistic,
- DWORD dwCounter
+ unsigned long dwCounter
)
{
//p802_11Counter->TransmittedFragmentCount
- p802_11Counter->MulticastTransmittedFrameCount = (ULONGLONG) (pStatistic->dwTsrBroadcast[TYPE_AC0DMA] +
+ p802_11Counter->MulticastTransmittedFrameCount = (unsigned long long) (pStatistic->dwTsrBroadcast[TYPE_AC0DMA] +
pStatistic->dwTsrBroadcast[TYPE_TXDMA0] +
pStatistic->dwTsrMulticast[TYPE_AC0DMA] +
pStatistic->dwTsrMulticast[TYPE_TXDMA0]);
- p802_11Counter->FailedCount = (ULONGLONG) (pStatistic->dwTsrErr[TYPE_AC0DMA] + pStatistic->dwTsrErr[TYPE_TXDMA0]);
- p802_11Counter->RetryCount = (ULONGLONG) (pStatistic->dwTsrRetry[TYPE_AC0DMA] + pStatistic->dwTsrRetry[TYPE_TXDMA0]);
- p802_11Counter->MultipleRetryCount = (ULONGLONG) (pStatistic->dwTsrMoreThanOnceRetry[TYPE_AC0DMA] +
+ p802_11Counter->FailedCount = (unsigned long long) (pStatistic->dwTsrErr[TYPE_AC0DMA] + pStatistic->dwTsrErr[TYPE_TXDMA0]);
+ p802_11Counter->RetryCount = (unsigned long long) (pStatistic->dwTsrRetry[TYPE_AC0DMA] + pStatistic->dwTsrRetry[TYPE_TXDMA0]);
+ p802_11Counter->MultipleRetryCount = (unsigned long long) (pStatistic->dwTsrMoreThanOnceRetry[TYPE_AC0DMA] +
pStatistic->dwTsrMoreThanOnceRetry[TYPE_TXDMA0]);
//p802_11Counter->FrameDuplicateCount
- p802_11Counter->RTSSuccessCount += (ULONGLONG) (dwCounter & 0x000000ff);
- p802_11Counter->RTSFailureCount += (ULONGLONG) ((dwCounter & 0x0000ff00) >> 8);
- p802_11Counter->ACKFailureCount += (ULONGLONG) ((dwCounter & 0x00ff0000) >> 16);
- p802_11Counter->FCSErrorCount += (ULONGLONG) ((dwCounter & 0xff000000) >> 24);
+ p802_11Counter->RTSSuccessCount += (unsigned long long) (dwCounter & 0x000000ff);
+ p802_11Counter->RTSFailureCount += (unsigned long long) ((dwCounter & 0x0000ff00) >> 8);
+ p802_11Counter->ACKFailureCount += (unsigned long long) ((dwCounter & 0x00ff0000) >> 16);
+ p802_11Counter->FCSErrorCount += (unsigned long long) ((dwCounter & 0xff000000) >> 24);
//p802_11Counter->ReceivedFragmentCount
- p802_11Counter->MulticastReceivedFrameCount = (ULONGLONG) (pStatistic->dwRsrBroadcast +
+ p802_11Counter->MulticastReceivedFrameCount = (unsigned long long) (pStatistic->dwRsrBroadcast +
pStatistic->dwRsrMulticast);
}
diff --git a/drivers/staging/vt6655/mib.h b/drivers/staging/vt6655/mib.h
index 2308319a405..009f3a4d29f 100644
--- a/drivers/staging/vt6655/mib.h
+++ b/drivers/staging/vt6655/mib.h
@@ -39,32 +39,32 @@
//
typedef struct tagSDot11Counters {
- ULONG Length; // Length of structure
- ULONGLONG TransmittedFragmentCount;
- ULONGLONG MulticastTransmittedFrameCount;
- ULONGLONG FailedCount;
- ULONGLONG RetryCount;
- ULONGLONG MultipleRetryCount;
- ULONGLONG RTSSuccessCount;
- ULONGLONG RTSFailureCount;
- ULONGLONG ACKFailureCount;
- ULONGLONG FrameDuplicateCount;
- ULONGLONG ReceivedFragmentCount;
- ULONGLONG MulticastReceivedFrameCount;
- ULONGLONG FCSErrorCount;
- ULONGLONG TKIPLocalMICFailures;
- ULONGLONG TKIPRemoteMICFailures;
- ULONGLONG TKIPICVErrors;
- ULONGLONG TKIPCounterMeasuresInvoked;
- ULONGLONG TKIPReplays;
- ULONGLONG CCMPFormatErrors;
- ULONGLONG CCMPReplays;
- ULONGLONG CCMPDecryptErrors;
- ULONGLONG FourWayHandshakeFailures;
-// ULONGLONG WEPUndecryptableCount;
-// ULONGLONG WEPICVErrorCount;
-// ULONGLONG DecryptSuccessCount;
-// ULONGLONG DecryptFailureCount;
+ unsigned long Length; // Length of structure
+ unsigned long long TransmittedFragmentCount;
+ unsigned long long MulticastTransmittedFrameCount;
+ unsigned long long FailedCount;
+ unsigned long long RetryCount;
+ unsigned long long MultipleRetryCount;
+ unsigned long long RTSSuccessCount;
+ unsigned long long RTSFailureCount;
+ unsigned long long ACKFailureCount;
+ unsigned long long FrameDuplicateCount;
+ unsigned long long ReceivedFragmentCount;
+ unsigned long long MulticastReceivedFrameCount;
+ unsigned long long FCSErrorCount;
+ unsigned long long TKIPLocalMICFailures;
+ unsigned long long TKIPRemoteMICFailures;
+ unsigned long long TKIPICVErrors;
+ unsigned long long TKIPCounterMeasuresInvoked;
+ unsigned long long TKIPReplays;
+ unsigned long long CCMPFormatErrors;
+ unsigned long long CCMPReplays;
+ unsigned long long CCMPDecryptErrors;
+ unsigned long long FourWayHandshakeFailures;
+// unsigned long long WEPUndecryptableCount;
+// unsigned long long WEPICVErrorCount;
+// unsigned long long DecryptSuccessCount;
+// unsigned long long DecryptFailureCount;
} SDot11Counters, *PSDot11Counters;
@@ -72,29 +72,29 @@ typedef struct tagSDot11Counters {
// MIB2 counter
//
typedef struct tagSMib2Counter {
- LONG ifIndex;
+ long ifIndex;
char ifDescr[256]; // max size 255 plus zero ending
// e.g. "interface 1"
- LONG ifType;
- LONG ifMtu;
- DWORD ifSpeed;
- BYTE ifPhysAddress[ETH_ALEN];
- LONG ifAdminStatus;
- LONG ifOperStatus;
- DWORD ifLastChange;
- DWORD ifInOctets;
- DWORD ifInUcastPkts;
- DWORD ifInNUcastPkts;
- DWORD ifInDiscards;
- DWORD ifInErrors;
- DWORD ifInUnknownProtos;
- DWORD ifOutOctets;
- DWORD ifOutUcastPkts;
- DWORD ifOutNUcastPkts;
- DWORD ifOutDiscards;
- DWORD ifOutErrors;
- DWORD ifOutQLen;
- DWORD ifSpecific;
+ long ifType;
+ long ifMtu;
+ unsigned long ifSpeed;
+ unsigned char ifPhysAddress[ETH_ALEN];
+ long ifAdminStatus;
+ long ifOperStatus;
+ unsigned long ifLastChange;
+ unsigned long ifInOctets;
+ unsigned long ifInUcastPkts;
+ unsigned long ifInNUcastPkts;
+ unsigned long ifInDiscards;
+ unsigned long ifInErrors;
+ unsigned long ifInUnknownProtos;
+ unsigned long ifOutOctets;
+ unsigned long ifOutUcastPkts;
+ unsigned long ifOutNUcastPkts;
+ unsigned long ifOutDiscards;
+ unsigned long ifOutErrors;
+ unsigned long ifOutQLen;
+ unsigned long ifSpecific;
} SMib2Counter, *PSMib2Counter;
// Value in the ifType entry
@@ -111,64 +111,64 @@ typedef struct tagSMib2Counter {
// RMON counter
//
typedef struct tagSRmonCounter {
- LONG etherStatsIndex;
- DWORD etherStatsDataSource;
- DWORD etherStatsDropEvents;
- DWORD etherStatsOctets;
- DWORD etherStatsPkts;
- DWORD etherStatsBroadcastPkts;
- DWORD etherStatsMulticastPkts;
- DWORD etherStatsCRCAlignErrors;
- DWORD etherStatsUndersizePkts;
- DWORD etherStatsOversizePkts;
- DWORD etherStatsFragments;
- DWORD etherStatsJabbers;
- DWORD etherStatsCollisions;
- DWORD etherStatsPkt64Octets;
- DWORD etherStatsPkt65to127Octets;
- DWORD etherStatsPkt128to255Octets;
- DWORD etherStatsPkt256to511Octets;
- DWORD etherStatsPkt512to1023Octets;
- DWORD etherStatsPkt1024to1518Octets;
- DWORD etherStatsOwners;
- DWORD etherStatsStatus;
+ long etherStatsIndex;
+ unsigned long etherStatsDataSource;
+ unsigned long etherStatsDropEvents;
+ unsigned long etherStatsOctets;
+ unsigned long etherStatsPkts;
+ unsigned long etherStatsBroadcastPkts;
+ unsigned long etherStatsMulticastPkts;
+ unsigned long etherStatsCRCAlignErrors;
+ unsigned long etherStatsUndersizePkts;
+ unsigned long etherStatsOversizePkts;
+ unsigned long etherStatsFragments;
+ unsigned long etherStatsJabbers;
+ unsigned long etherStatsCollisions;
+ unsigned long etherStatsPkt64Octets;
+ unsigned long etherStatsPkt65to127Octets;
+ unsigned long etherStatsPkt128to255Octets;
+ unsigned long etherStatsPkt256to511Octets;
+ unsigned long etherStatsPkt512to1023Octets;
+ unsigned long etherStatsPkt1024to1518Octets;
+ unsigned long etherStatsOwners;
+ unsigned long etherStatsStatus;
} SRmonCounter, *PSRmonCounter;
//
// Custom counter
//
typedef struct tagSCustomCounters {
- ULONG Length;
-
- ULONGLONG ullTsrAllOK;
-
- ULONGLONG ullRsr11M;
- ULONGLONG ullRsr5M;
- ULONGLONG ullRsr2M;
- ULONGLONG ullRsr1M;
-
- ULONGLONG ullRsr11MCRCOk;
- ULONGLONG ullRsr5MCRCOk;
- ULONGLONG ullRsr2MCRCOk;
- ULONGLONG ullRsr1MCRCOk;
-
- ULONGLONG ullRsr54M;
- ULONGLONG ullRsr48M;
- ULONGLONG ullRsr36M;
- ULONGLONG ullRsr24M;
- ULONGLONG ullRsr18M;
- ULONGLONG ullRsr12M;
- ULONGLONG ullRsr9M;
- ULONGLONG ullRsr6M;
-
- ULONGLONG ullRsr54MCRCOk;
- ULONGLONG ullRsr48MCRCOk;
- ULONGLONG ullRsr36MCRCOk;
- ULONGLONG ullRsr24MCRCOk;
- ULONGLONG ullRsr18MCRCOk;
- ULONGLONG ullRsr12MCRCOk;
- ULONGLONG ullRsr9MCRCOk;
- ULONGLONG ullRsr6MCRCOk;
+ unsigned long Length;
+
+ unsigned long long ullTsrAllOK;
+
+ unsigned long long ullRsr11M;
+ unsigned long long ullRsr5M;
+ unsigned long long ullRsr2M;
+ unsigned long long ullRsr1M;
+
+ unsigned long long ullRsr11MCRCOk;
+ unsigned long long ullRsr5MCRCOk;
+ unsigned long long ullRsr2MCRCOk;
+ unsigned long long ullRsr1MCRCOk;
+
+ unsigned long long ullRsr54M;
+ unsigned long long ullRsr48M;
+ unsigned long long ullRsr36M;
+ unsigned long long ullRsr24M;
+ unsigned long long ullRsr18M;
+ unsigned long long ullRsr12M;
+ unsigned long long ullRsr9M;
+ unsigned long long ullRsr6M;
+
+ unsigned long long ullRsr54MCRCOk;
+ unsigned long long ullRsr48MCRCOk;
+ unsigned long long ullRsr36MCRCOk;
+ unsigned long long ullRsr24MCRCOk;
+ unsigned long long ullRsr18MCRCOk;
+ unsigned long long ullRsr12MCRCOk;
+ unsigned long long ullRsr9MCRCOk;
+ unsigned long long ullRsr6MCRCOk;
} SCustomCounters, *PSCustomCounters;
@@ -177,29 +177,29 @@ typedef struct tagSCustomCounters {
// Custom counter
//
typedef struct tagSISRCounters {
- ULONG Length;
-
- DWORD dwIsrTx0OK;
- DWORD dwIsrAC0TxOK;
- DWORD dwIsrBeaconTxOK;
- DWORD dwIsrRx0OK;
- DWORD dwIsrTBTTInt;
- DWORD dwIsrSTIMERInt;
- DWORD dwIsrWatchDog;
- DWORD dwIsrUnrecoverableError;
- DWORD dwIsrSoftInterrupt;
- DWORD dwIsrMIBNearfull;
- DWORD dwIsrRxNoBuf;
-
- DWORD dwIsrUnknown; // unknown interrupt count
-
- DWORD dwIsrRx1OK;
- DWORD dwIsrATIMTxOK;
- DWORD dwIsrSYNCTxOK;
- DWORD dwIsrCFPEnd;
- DWORD dwIsrATIMEnd;
- DWORD dwIsrSYNCFlushOK;
- DWORD dwIsrSTIMER1Int;
+ unsigned long Length;
+
+ unsigned long dwIsrTx0OK;
+ unsigned long dwIsrAC0TxOK;
+ unsigned long dwIsrBeaconTxOK;
+ unsigned long dwIsrRx0OK;
+ unsigned long dwIsrTBTTInt;
+ unsigned long dwIsrSTIMERInt;
+ unsigned long dwIsrWatchDog;
+ unsigned long dwIsrUnrecoverableError;
+ unsigned long dwIsrSoftInterrupt;
+ unsigned long dwIsrMIBNearfull;
+ unsigned long dwIsrRxNoBuf;
+
+ unsigned long dwIsrUnknown; // unknown interrupt count
+
+ unsigned long dwIsrRx1OK;
+ unsigned long dwIsrATIMTxOK;
+ unsigned long dwIsrSYNCTxOK;
+ unsigned long dwIsrCFPEnd;
+ unsigned long dwIsrATIMEnd;
+ unsigned long dwIsrSYNCFlushOK;
+ unsigned long dwIsrSTIMER1Int;
/////////////////////////////////////
} SISRCounters, *PSISRCounters;
@@ -222,99 +222,99 @@ typedef struct tagSStatCounter {
// RSR status count
//
- DWORD dwRsrFrmAlgnErr;
- DWORD dwRsrErr;
- DWORD dwRsrCRCErr;
- DWORD dwRsrCRCOk;
- DWORD dwRsrBSSIDOk;
- DWORD dwRsrADDROk;
- DWORD dwRsrBCNSSIDOk;
- DWORD dwRsrLENErr;
- DWORD dwRsrTYPErr;
-
- DWORD dwNewRsrDECRYPTOK;
- DWORD dwNewRsrCFP;
- DWORD dwNewRsrUTSF;
- DWORD dwNewRsrHITAID;
- DWORD dwNewRsrHITAID0;
-
- DWORD dwRsrLong;
- DWORD dwRsrRunt;
-
- DWORD dwRsrRxControl;
- DWORD dwRsrRxData;
- DWORD dwRsrRxManage;
-
- DWORD dwRsrRxPacket;
- DWORD dwRsrRxOctet;
- DWORD dwRsrBroadcast;
- DWORD dwRsrMulticast;
- DWORD dwRsrDirected;
+ unsigned long dwRsrFrmAlgnErr;
+ unsigned long dwRsrErr;
+ unsigned long dwRsrCRCErr;
+ unsigned long dwRsrCRCOk;
+ unsigned long dwRsrBSSIDOk;
+ unsigned long dwRsrADDROk;
+ unsigned long dwRsrBCNSSIDOk;
+ unsigned long dwRsrLENErr;
+ unsigned long dwRsrTYPErr;
+
+ unsigned long dwNewRsrDECRYPTOK;
+ unsigned long dwNewRsrCFP;
+ unsigned long dwNewRsrUTSF;
+ unsigned long dwNewRsrHITAID;
+ unsigned long dwNewRsrHITAID0;
+
+ unsigned long dwRsrLong;
+ unsigned long dwRsrRunt;
+
+ unsigned long dwRsrRxControl;
+ unsigned long dwRsrRxData;
+ unsigned long dwRsrRxManage;
+
+ unsigned long dwRsrRxPacket;
+ unsigned long dwRsrRxOctet;
+ unsigned long dwRsrBroadcast;
+ unsigned long dwRsrMulticast;
+ unsigned long dwRsrDirected;
// 64-bit OID
- ULONGLONG ullRsrOK;
+ unsigned long long ullRsrOK;
// for some optional OIDs (64 bits) and DMI support
- ULONGLONG ullRxBroadcastBytes;
- ULONGLONG ullRxMulticastBytes;
- ULONGLONG ullRxDirectedBytes;
- ULONGLONG ullRxBroadcastFrames;
- ULONGLONG ullRxMulticastFrames;
- ULONGLONG ullRxDirectedFrames;
-
- DWORD dwRsrRxFragment;
- DWORD dwRsrRxFrmLen64;
- DWORD dwRsrRxFrmLen65_127;
- DWORD dwRsrRxFrmLen128_255;
- DWORD dwRsrRxFrmLen256_511;
- DWORD dwRsrRxFrmLen512_1023;
- DWORD dwRsrRxFrmLen1024_1518;
+ unsigned long long ullRxBroadcastBytes;
+ unsigned long long ullRxMulticastBytes;
+ unsigned long long ullRxDirectedBytes;
+ unsigned long long ullRxBroadcastFrames;
+ unsigned long long ullRxMulticastFrames;
+ unsigned long long ullRxDirectedFrames;
+
+ unsigned long dwRsrRxFragment;
+ unsigned long dwRsrRxFrmLen64;
+ unsigned long dwRsrRxFrmLen65_127;
+ unsigned long dwRsrRxFrmLen128_255;
+ unsigned long dwRsrRxFrmLen256_511;
+ unsigned long dwRsrRxFrmLen512_1023;
+ unsigned long dwRsrRxFrmLen1024_1518;
// TSR status count
//
- DWORD dwTsrTotalRetry[TYPE_MAXTD]; // total collision retry count
- DWORD dwTsrOnceRetry[TYPE_MAXTD]; // this packet only occur one collision
- DWORD dwTsrMoreThanOnceRetry[TYPE_MAXTD]; // this packet occur more than one collision
- DWORD dwTsrRetry[TYPE_MAXTD]; // this packet has ever occur collision,
+ unsigned long dwTsrTotalRetry[TYPE_MAXTD]; // total collision retry count
+ unsigned long dwTsrOnceRetry[TYPE_MAXTD]; // this packet only occur one collision
+ unsigned long dwTsrMoreThanOnceRetry[TYPE_MAXTD]; // this packet occur more than one collision
+ unsigned long dwTsrRetry[TYPE_MAXTD]; // this packet has ever occur collision,
// that is (dwTsrOnceCollision0 + dwTsrMoreThanOnceCollision0)
- DWORD dwTsrACKData[TYPE_MAXTD];
- DWORD dwTsrErr[TYPE_MAXTD];
- DWORD dwAllTsrOK[TYPE_MAXTD];
- DWORD dwTsrRetryTimeout[TYPE_MAXTD];
- DWORD dwTsrTransmitTimeout[TYPE_MAXTD];
-
- DWORD dwTsrTxPacket[TYPE_MAXTD];
- DWORD dwTsrTxOctet[TYPE_MAXTD];
- DWORD dwTsrBroadcast[TYPE_MAXTD];
- DWORD dwTsrMulticast[TYPE_MAXTD];
- DWORD dwTsrDirected[TYPE_MAXTD];
+ unsigned long dwTsrACKData[TYPE_MAXTD];
+ unsigned long dwTsrErr[TYPE_MAXTD];
+ unsigned long dwAllTsrOK[TYPE_MAXTD];
+ unsigned long dwTsrRetryTimeout[TYPE_MAXTD];
+ unsigned long dwTsrTransmitTimeout[TYPE_MAXTD];
+
+ unsigned long dwTsrTxPacket[TYPE_MAXTD];
+ unsigned long dwTsrTxOctet[TYPE_MAXTD];
+ unsigned long dwTsrBroadcast[TYPE_MAXTD];
+ unsigned long dwTsrMulticast[TYPE_MAXTD];
+ unsigned long dwTsrDirected[TYPE_MAXTD];
// RD/TD count
- DWORD dwCntRxFrmLength;
- DWORD dwCntTxBufLength;
+ unsigned long dwCntRxFrmLength;
+ unsigned long dwCntTxBufLength;
- BYTE abyCntRxPattern[16];
- BYTE abyCntTxPattern[16];
+ unsigned char abyCntRxPattern[16];
+ unsigned char abyCntTxPattern[16];
// Software check....
- DWORD dwCntRxDataErr; // rx buffer data software compare CRC err count
- DWORD dwCntDecryptErr; // rx buffer data software compare CRC err count
- DWORD dwCntRxICVErr; // rx buffer data software compare CRC err count
- UINT idxRxErrorDesc[TYPE_MAXRD]; // index for rx data error RD
+ unsigned long dwCntRxDataErr; // rx buffer data software compare CRC err count
+ unsigned long dwCntDecryptErr; // rx buffer data software compare CRC err count
+ unsigned long dwCntRxICVErr; // rx buffer data software compare CRC err count
+ unsigned int idxRxErrorDesc[TYPE_MAXRD]; // index for rx data error RD
// 64-bit OID
- ULONGLONG ullTsrOK[TYPE_MAXTD];
+ unsigned long long ullTsrOK[TYPE_MAXTD];
// for some optional OIDs (64 bits) and DMI support
- ULONGLONG ullTxBroadcastFrames[TYPE_MAXTD];
- ULONGLONG ullTxMulticastFrames[TYPE_MAXTD];
- ULONGLONG ullTxDirectedFrames[TYPE_MAXTD];
- ULONGLONG ullTxBroadcastBytes[TYPE_MAXTD];
- ULONGLONG ullTxMulticastBytes[TYPE_MAXTD];
- ULONGLONG ullTxDirectedBytes[TYPE_MAXTD];
-
-// DWORD dwTxRetryCount[8];
+ unsigned long long ullTxBroadcastFrames[TYPE_MAXTD];
+ unsigned long long ullTxMulticastFrames[TYPE_MAXTD];
+ unsigned long long ullTxDirectedFrames[TYPE_MAXTD];
+ unsigned long long ullTxBroadcastBytes[TYPE_MAXTD];
+ unsigned long long ullTxMulticastBytes[TYPE_MAXTD];
+ unsigned long long ullTxDirectedBytes[TYPE_MAXTD];
+
+// unsigned long dwTxRetryCount[8];
//
// ISR status count
//
@@ -324,15 +324,15 @@ typedef struct tagSStatCounter {
#ifdef Calcu_LinkQual
//Tx count:
- ULONG TxNoRetryOkCount; //success tx no retry !
- ULONG TxRetryOkCount; //success tx but retry !
- ULONG TxFailCount; //fail tx ?
+ unsigned long TxNoRetryOkCount; //success tx no retry !
+ unsigned long TxRetryOkCount; //success tx but retry !
+ unsigned long TxFailCount; //fail tx ?
//Rx count:
- ULONG RxOkCnt; //success rx !
- ULONG RxFcsErrCnt; //fail rx ?
+ unsigned long RxOkCnt; //success rx !
+ unsigned long RxFcsErrCnt; //fail rx ?
//statistic
- ULONG SignalStren;
- ULONG LinkQuality;
+ unsigned long SignalStren;
+ unsigned long LinkQuality;
#endif
} SStatCounter, *PSStatCounter;
@@ -344,30 +344,29 @@ typedef struct tagSStatCounter {
void STAvClearAllCounter(PSStatCounter pStatistic);
-void STAvUpdateIsrStatCounter(PSStatCounter pStatistic, DWORD dwIsr);
+void STAvUpdateIsrStatCounter(PSStatCounter pStatistic, unsigned long dwIsr);
void STAvUpdateRDStatCounter(PSStatCounter pStatistic,
- BYTE byRSR, BYTE byNewRSR, BYTE byRxRate,
- PBYTE pbyBuffer, UINT cbFrameLength);
+ unsigned char byRSR, unsigned char byNewRSR, unsigned char byRxRate,
+ unsigned char *pbyBuffer, unsigned int cbFrameLength);
void STAvUpdateRDStatCounterEx(PSStatCounter pStatistic,
- BYTE byRSR, BYTE byNewRsr, BYTE byRxRate,
- PBYTE pbyBuffer, UINT cbFrameLength);
+ unsigned char byRSR, unsigned char byNewRsr, unsigned char byRxRate,
+ unsigned char *pbyBuffer, unsigned int cbFrameLength);
-void STAvUpdateTDStatCounter(PSStatCounter pStatistic,
- BYTE byTSR0, BYTE byTSR1,
- PBYTE pbyBuffer, UINT cbFrameLength, UINT uIdx );
+void STAvUpdateTDStatCounter(PSStatCounter pStatistic, unsigned char byTSR0, unsigned char byTSR1,
+ unsigned char *pbyBuffer, unsigned int cbFrameLength, unsigned int uIdx);
void STAvUpdateTDStatCounterEx(
PSStatCounter pStatistic,
- PBYTE pbyBuffer,
- DWORD cbFrameLength
+ unsigned char *pbyBuffer,
+ unsigned long cbFrameLength
);
void STAvUpdate802_11Counter(
PSDot11Counters p802_11Counter,
PSStatCounter pStatistic,
- DWORD dwCounter
+ unsigned long dwCounter
);
void STAvClear802_11Counter(PSDot11Counters p802_11Counter);
diff --git a/drivers/staging/vt6655/michael.c b/drivers/staging/vt6655/michael.c
index 0bf57efdede..67618f069d0 100644
--- a/drivers/staging/vt6655/michael.c
+++ b/drivers/staging/vt6655/michael.c
@@ -26,8 +26,8 @@
* Date: Sep 4, 2002
*
* Functions:
- * s_dwGetUINT32 - Convert from BYTE[] to DWORD in a portable way
- * s_vPutUINT32 - Convert from DWORD to BYTE[] in a portable way
+ * s_dwGetUINT32 - Convert from unsigned char [] to unsigned long in a portable way
+ * s_vPutUINT32 - Convert from unsigned long to unsigned char [] in a portable way
* s_vClear - Reset the state to the empty message.
* s_vSetKey - Set the key.
* MIC_vInit - Set the key.
@@ -48,29 +48,29 @@
/*--------------------- Static Functions --------------------------*/
/*
-static DWORD s_dwGetUINT32(BYTE * p); // Get DWORD from 4 bytes LSByte first
-static void s_vPutUINT32(BYTE* p, DWORD val); // Put DWORD into 4 bytes LSByte first
+static unsigned long s_dwGetUINT32(unsigned char *p); // Get unsigned long from 4 bytes LSByte first
+static void s_vPutUINT32(unsigned char *p, unsigned long val); // Put unsigned long into 4 bytes LSByte first
*/
static void s_vClear(void); // Clear the internal message,
// resets the object to the state just after construction.
-static void s_vSetKey(DWORD dwK0, DWORD dwK1);
-static void s_vAppendByte(BYTE b); // Add a single byte to the internal message
+static void s_vSetKey(unsigned long dwK0, unsigned long dwK1);
+static void s_vAppendByte(unsigned char b); // Add a single byte to the internal message
/*--------------------- Export Variables --------------------------*/
-static DWORD L, R; // Current state
+static unsigned long L, R; // Current state
-static DWORD K0, K1; // Key
-static DWORD M; // Message accumulator (single word)
-static UINT nBytesInM; // # bytes in M
+static unsigned long K0, K1; // Key
+static unsigned long M; // Message accumulator (single word)
+static unsigned int nBytesInM; // # bytes in M
/*--------------------- Export Functions --------------------------*/
/*
-static DWORD s_dwGetUINT32 (BYTE * p)
-// Convert from BYTE[] to DWORD in a portable way
+static unsigned long s_dwGetUINT32 (unsigned char *p)
+// Convert from unsigned char [] to unsigned long in a portable way
{
- DWORD res = 0;
- UINT i;
+ unsigned long res = 0;
+ unsigned int i;
for(i=0; i<4; i++ )
{
res |= (*p++) << (8*i);
@@ -78,13 +78,13 @@ static DWORD s_dwGetUINT32 (BYTE * p)
return res;
}
-static void s_vPutUINT32 (BYTE* p, DWORD val)
-// Convert from DWORD to BYTE[] in a portable way
+static void s_vPutUINT32 (unsigned char *p, unsigned long val)
+// Convert from unsigned long to unsigned char [] in a portable way
{
- UINT i;
+ unsigned int i;
for(i=0; i<4; i++ )
{
- *p++ = (BYTE) (val & 0xff);
+ *p++ = (unsigned char) (val & 0xff);
val >>= 8;
}
}
@@ -99,7 +99,7 @@ static void s_vClear (void)
M = 0;
}
-static void s_vSetKey (DWORD dwK0, DWORD dwK1)
+static void s_vSetKey (unsigned long dwK0, unsigned long dwK1)
{
// Set the key
K0 = dwK0;
@@ -108,7 +108,7 @@ static void s_vSetKey (DWORD dwK0, DWORD dwK1)
s_vClear();
}
-static void s_vAppendByte (BYTE b)
+static void s_vAppendByte (unsigned char b)
{
// Append the byte to our word-sized buffer
M |= b << (8*nBytesInM);
@@ -131,7 +131,7 @@ static void s_vAppendByte (BYTE b)
}
}
-void MIC_vInit (DWORD dwK0, DWORD dwK1)
+void MIC_vInit (unsigned long dwK0, unsigned long dwK1)
{
// Set the key
s_vSetKey(dwK0, dwK1);
@@ -149,7 +149,7 @@ void MIC_vUnInit (void)
s_vClear();
}
-void MIC_vAppend (PBYTE src, UINT nBytes)
+void MIC_vAppend (unsigned char *src, unsigned int nBytes)
{
// This is simple
while (nBytes > 0)
@@ -159,7 +159,7 @@ void MIC_vAppend (PBYTE src, UINT nBytes)
}
}
-void MIC_vGetMIC (PDWORD pdwL, PDWORD pdwR)
+void MIC_vGetMIC (unsigned long *pdwL, unsigned long *pdwR)
{
// Append the minimum padding
s_vAppendByte(0x5a);
diff --git a/drivers/staging/vt6655/michael.h b/drivers/staging/vt6655/michael.h
index 97de77b4da2..3131b161d6a 100644
--- a/drivers/staging/vt6655/michael.h
+++ b/drivers/staging/vt6655/michael.h
@@ -35,16 +35,16 @@
/*--------------------- Export Types ------------------------------*/
-void MIC_vInit(DWORD dwK0, DWORD dwK1);
+void MIC_vInit(unsigned long dwK0, unsigned long dwK1);
void MIC_vUnInit(void);
// Append bytes to the message to be MICed
-void MIC_vAppend(PBYTE src, UINT nBytes);
+void MIC_vAppend(unsigned char *src, unsigned int nBytes);
// Get the MIC result. Destination should accept 8 bytes of result.
// This also resets the message to empty.
-void MIC_vGetMIC(PDWORD pdwL, PDWORD pdwR);
+void MIC_vGetMIC(unsigned long *pdwL, unsigned long *pdwR);
/*--------------------- Export Macros ------------------------------*/
diff --git a/drivers/staging/vt6655/power.c b/drivers/staging/vt6655/power.c
index 64c22c3e4bb..7207aca1301 100644
--- a/drivers/staging/vt6655/power.c
+++ b/drivers/staging/vt6655/power.c
@@ -77,12 +77,12 @@ static int msglevel =MSG_LEVEL_INFO;
void
PSvEnablePowerSaving(
void *hDeviceContext,
- WORD wListenInterval
+ unsigned short wListenInterval
)
{
PSDevice pDevice = (PSDevice)hDeviceContext;
PSMgmtObject pMgmt = pDevice->pMgmt;
- WORD wAID = pMgmt->wCurrAID | BIT14 | BIT15;
+ unsigned short wAID = pMgmt->wCurrAID | BIT14 | BIT15;
// set period of power up before TBTT
VNSvOutPortW(pDevice->PortOffset + MAC_REG_PWBT, C_PWBT);
@@ -115,7 +115,7 @@ PSvEnablePowerSaving(
// enable power saving hw function
MACvRegBitsOn(pDevice->PortOffset, MAC_REG_PSCTL, PSCTL_PSEN);
- pDevice->bEnablePSMode = TRUE;
+ pDevice->bEnablePSMode = true;
if (pDevice->eOPMode == OP_MODE_ADHOC) {
// bMgrPrepareBeaconToSend((void *)pDevice, pMgmt);
@@ -124,7 +124,7 @@ PSvEnablePowerSaving(
else if (pDevice->eOPMode == OP_MODE_INFRASTRUCTURE) {
PSbSendNullPacket(pDevice);
}
- pDevice->bPWBitOn = TRUE;
+ pDevice->bPWBitOn = true;
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "PS:Power Saving Mode Enable... \n");
return;
}
@@ -161,12 +161,12 @@ PSvDisablePowerSaving(
// set always listen beacon
MACvRegBitsOn(pDevice->PortOffset, MAC_REG_PSCTL, PSCTL_ALBCN);
- pDevice->bEnablePSMode = FALSE;
+ pDevice->bEnablePSMode = false;
if (pDevice->eOPMode == OP_MODE_INFRASTRUCTURE) {
PSbSendNullPacket(pDevice);
}
- pDevice->bPWBitOn = FALSE;
+ pDevice->bPWBitOn = false;
return;
}
@@ -177,35 +177,35 @@ PSvDisablePowerSaving(
* Consider to power down when no more packets to tx or rx.
*
* Return Value:
- * TRUE, if power down success
- * FALSE, if fail
+ * true, if power down success
+ * false, if fail
-*/
-BOOL
+bool
PSbConsiderPowerDown(
void *hDeviceContext,
- BOOL bCheckRxDMA,
- BOOL bCheckCountToWakeUp
+ bool bCheckRxDMA,
+ bool bCheckCountToWakeUp
)
{
PSDevice pDevice = (PSDevice)hDeviceContext;
PSMgmtObject pMgmt = pDevice->pMgmt;
- UINT uIdx;
+ unsigned int uIdx;
// check if already in Doze mode
if (MACbIsRegBitsOn(pDevice->PortOffset, MAC_REG_PSCTL, PSCTL_PS))
- return TRUE;
+ return true;
if (pMgmt->eCurrMode != WMAC_MODE_IBSS_STA) {
// check if in TIM wake period
if (pMgmt->bInTIMWake)
- return FALSE;
+ return false;
}
// check scan state
if (pDevice->bCmdRunning)
- return FALSE;
+ return false;
// Froce PSEN on
MACvRegBitsOn(pDevice->PortOffset, MAC_REG_PSCTL, PSCTL_PSEN);
@@ -213,27 +213,27 @@ PSbConsiderPowerDown(
// check if all TD are empty,
for (uIdx = 0; uIdx < TYPE_MAXTD; uIdx ++) {
if (pDevice->iTDUsed[uIdx] != 0)
- return FALSE;
+ return false;
}
// check if rx isr is clear
if (bCheckRxDMA &&
((pDevice->dwIsr& ISR_RXDMA0) != 0) &&
((pDevice->dwIsr & ISR_RXDMA1) != 0)){
- return FALSE;
+ return false;
};
if (pMgmt->eCurrMode != WMAC_MODE_IBSS_STA) {
if (bCheckCountToWakeUp &&
(pMgmt->wCountToWakeUp == 0 || pMgmt->wCountToWakeUp == 1)) {
- return FALSE;
+ return false;
}
}
// no Tx, no Rx isr, now go to Doze
MACvRegBitsOn(pDevice->PortOffset, MAC_REG_PSCTL, PSCTL_GO2DOZE);
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Go to Doze ZZZZZZZZZZZZZZZ\n");
- return TRUE;
+ return true;
}
@@ -262,7 +262,7 @@ PSvSendPSPOLL(
memset(pMgmt->pbyPSPacketPool, 0, sizeof(STxMgmtPacket) + WLAN_HDR_ADDR2_LEN);
pTxPacket = (PSTxMgmtPacket)pMgmt->pbyPSPacketPool;
- pTxPacket->p80211Header = (PUWLAN_80211HDR)((PBYTE)pTxPacket + sizeof(STxMgmtPacket));
+ pTxPacket->p80211Header = (PUWLAN_80211HDR)((unsigned char *)pTxPacket + sizeof(STxMgmtPacket));
pTxPacket->p80211Header->sA2.wFrameCtl = cpu_to_le16(
(
WLAN_SET_FC_FTYPE(WLAN_TYPE_CTL) |
@@ -296,7 +296,7 @@ PSvSendPSPOLL(
* None.
*
-*/
-BOOL
+bool
PSbSendNullPacket(
void *hDeviceContext
)
@@ -304,32 +304,32 @@ PSbSendNullPacket(
PSDevice pDevice = (PSDevice)hDeviceContext;
PSTxMgmtPacket pTxPacket = NULL;
PSMgmtObject pMgmt = pDevice->pMgmt;
- UINT uIdx;
+ unsigned int uIdx;
- if (pDevice->bLinkPass == FALSE) {
- return FALSE;
+ if (pDevice->bLinkPass == false) {
+ return false;
}
#ifdef TxInSleep
- if ((pDevice->bEnablePSMode == FALSE) &&
- (pDevice->fTxDataInSleep == FALSE)){
- return FALSE;
+ if ((pDevice->bEnablePSMode == false) &&
+ (pDevice->fTxDataInSleep == false)){
+ return false;
}
#else
- if (pDevice->bEnablePSMode == FALSE) {
- return FALSE;
+ if (pDevice->bEnablePSMode == false) {
+ return false;
}
#endif
if (pDevice->bEnablePSMode) {
for (uIdx = 0; uIdx < TYPE_MAXTD; uIdx ++) {
if (pDevice->iTDUsed[uIdx] != 0)
- return FALSE;
+ return false;
}
}
memset(pMgmt->pbyPSPacketPool, 0, sizeof(STxMgmtPacket) + WLAN_NULLDATA_FR_MAXLEN);
pTxPacket = (PSTxMgmtPacket)pMgmt->pbyPSPacketPool;
- pTxPacket->p80211Header = (PUWLAN_80211HDR)((PBYTE)pTxPacket + sizeof(STxMgmtPacket));
+ pTxPacket->p80211Header = (PUWLAN_80211HDR)((unsigned char *)pTxPacket + sizeof(STxMgmtPacket));
if (pDevice->bEnablePSMode) {
@@ -350,7 +350,7 @@ PSbSendNullPacket(
}
if(pMgmt->eCurrMode != WMAC_MODE_IBSS_STA) {
- pTxPacket->p80211Header->sA3.wFrameCtl |= cpu_to_le16((WORD)WLAN_SET_FC_TODS(1));
+ pTxPacket->p80211Header->sA3.wFrameCtl |= cpu_to_le16((unsigned short)WLAN_SET_FC_TODS(1));
}
memcpy(pTxPacket->p80211Header->sA3.abyAddr1, pMgmt->abyCurrBSSID, WLAN_ADDR_LEN);
@@ -361,7 +361,7 @@ PSbSendNullPacket(
// send the frame
if (csMgmt_xmit(pDevice, pTxPacket) != CMD_STATUS_PENDING) {
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Send Null Packet failed !\n");
- return FALSE;
+ return false;
}
else {
@@ -369,7 +369,7 @@ PSbSendNullPacket(
}
- return TRUE ;
+ return true ;
}
/*+
@@ -382,7 +382,7 @@ PSbSendNullPacket(
*
-*/
-BOOL
+bool
PSbIsNextTBTTWakeUp(
void *hDeviceContext
)
@@ -390,7 +390,7 @@ PSbIsNextTBTTWakeUp(
PSDevice pDevice = (PSDevice)hDeviceContext;
PSMgmtObject pMgmt = pDevice->pMgmt;
- BOOL bWakeUp = FALSE;
+ bool bWakeUp = false;
if (pMgmt->wListenInterval >= 2) {
if (pMgmt->wCountToWakeUp == 0) {
@@ -402,7 +402,7 @@ PSbIsNextTBTTWakeUp(
if (pMgmt->wCountToWakeUp == 1) {
// Turn on wake up to listen next beacon
MACvRegBitsOn(pDevice->PortOffset, MAC_REG_PSCTL, PSCTL_LNBCN);
- bWakeUp = TRUE;
+ bWakeUp = true;
}
}
diff --git a/drivers/staging/vt6655/power.h b/drivers/staging/vt6655/power.h
index c0dbe216e97..01013b59228 100644
--- a/drivers/staging/vt6655/power.h
+++ b/drivers/staging/vt6655/power.h
@@ -48,11 +48,11 @@
// PSDevice pDevice
// PSDevice hDeviceContext
-BOOL
+bool
PSbConsiderPowerDown(
void *hDeviceContext,
- BOOL bCheckRxDMA,
- BOOL bCheckCountToWakeUp
+ bool bCheckRxDMA,
+ bool bCheckCountToWakeUp
);
void
@@ -63,7 +63,7 @@ PSvDisablePowerSaving(
void
PSvEnablePowerSaving(
void *hDeviceContext,
- WORD wListenInterval
+ unsigned short wListenInterval
);
void
@@ -71,12 +71,12 @@ PSvSendPSPOLL(
void *hDeviceContext
);
-BOOL
+bool
PSbSendNullPacket(
void *hDeviceContext
);
-BOOL
+bool
PSbIsNextTBTTWakeUp(
void *hDeviceContext
);
diff --git a/drivers/staging/vt6655/rc4.c b/drivers/staging/vt6655/rc4.c
index 4a53f159cb3..9856c08b3d7 100644
--- a/drivers/staging/vt6655/rc4.c
+++ b/drivers/staging/vt6655/rc4.c
@@ -32,38 +32,38 @@
#include "rc4.h"
-void rc4_init(PRC4Ext pRC4, PBYTE pbyKey, UINT cbKey_len)
+void rc4_init(PRC4Ext pRC4, unsigned char *pbyKey, unsigned int cbKey_len)
{
- UINT ust1, ust2;
- UINT keyindex;
- UINT stateindex;
- PBYTE pbyst;
- UINT idx;
+ unsigned int ust1, ust2;
+ unsigned int keyindex;
+ unsigned int stateindex;
+ unsigned char *pbyst;
+ unsigned int idx;
pbyst = pRC4->abystate;
pRC4->ux = 0;
pRC4->uy = 0;
for (idx = 0; idx < 256; idx++)
- pbyst[idx] = (BYTE)idx;
+ pbyst[idx] = (unsigned char)idx;
keyindex = 0;
stateindex = 0;
for (idx = 0; idx < 256; idx++) {
ust1 = pbyst[idx];
stateindex = (stateindex + pbyKey[keyindex] + ust1) & 0xff;
ust2 = pbyst[stateindex];
- pbyst[stateindex] = (BYTE)ust1;
- pbyst[idx] = (BYTE)ust2;
+ pbyst[stateindex] = (unsigned char)ust1;
+ pbyst[idx] = (unsigned char)ust2;
if (++keyindex >= cbKey_len)
keyindex = 0;
}
}
-UINT rc4_byte(PRC4Ext pRC4)
+unsigned int rc4_byte(PRC4Ext pRC4)
{
- UINT ux;
- UINT uy;
- UINT ustx, usty;
- PBYTE pbyst;
+ unsigned int ux;
+ unsigned int uy;
+ unsigned int ustx, usty;
+ unsigned char *pbyst;
pbyst = pRC4->abystate;
ux = (pRC4->ux + 1) & 0xff;
@@ -72,16 +72,16 @@ UINT rc4_byte(PRC4Ext pRC4)
usty = pbyst[uy];
pRC4->ux = ux;
pRC4->uy = uy;
- pbyst[uy] = (BYTE)ustx;
- pbyst[ux] = (BYTE)usty;
+ pbyst[uy] = (unsigned char)ustx;
+ pbyst[ux] = (unsigned char)usty;
return pbyst[(ustx + usty) & 0xff];
}
-void rc4_encrypt(PRC4Ext pRC4, PBYTE pbyDest,
- PBYTE pbySrc, UINT cbData_len)
+void rc4_encrypt(PRC4Ext pRC4, unsigned char *pbyDest,
+ unsigned char *pbySrc, unsigned int cbData_len)
{
- UINT ii;
+ unsigned int ii;
for (ii = 0; ii < cbData_len; ii++)
- pbyDest[ii] = (BYTE)(pbySrc[ii] ^ rc4_byte(pRC4));
+ pbyDest[ii] = (unsigned char)(pbySrc[ii] ^ rc4_byte(pRC4));
}
diff --git a/drivers/staging/vt6655/rc4.h b/drivers/staging/vt6655/rc4.h
index e65cae69efa..ad04e351365 100644
--- a/drivers/staging/vt6655/rc4.h
+++ b/drivers/staging/vt6655/rc4.h
@@ -35,13 +35,13 @@
/*--------------------- Export Definitions -------------------------*/
/*--------------------- Export Types ------------------------------*/
typedef struct {
- UINT ux;
- UINT uy;
- BYTE abystate[256];
+ unsigned int ux;
+ unsigned int uy;
+ unsigned char abystate[256];
} RC4Ext, *PRC4Ext;
-void rc4_init(PRC4Ext pRC4, PBYTE pbyKey, UINT cbKey_len);
-UINT rc4_byte(PRC4Ext pRC4);
-void rc4_encrypt(PRC4Ext pRC4, PBYTE pbyDest, PBYTE pbySrc, UINT cbData_len);
+void rc4_init(PRC4Ext pRC4, unsigned char *pbyKey, unsigned int cbKey_len);
+unsigned int rc4_byte(PRC4Ext pRC4);
+void rc4_encrypt(PRC4Ext pRC4, unsigned char *pbyDest, unsigned char *pbySrc, unsigned int cbData_len);
#endif //__RC4_H__
diff --git a/drivers/staging/vt6655/rf.c b/drivers/staging/vt6655/rf.c
index 7cb86fe2eeb..b8ec783e55e 100644
--- a/drivers/staging/vt6655/rf.c
+++ b/drivers/staging/vt6655/rf.c
@@ -94,7 +94,7 @@
-const DWORD dwAL2230InitTable[CB_AL2230_INIT_SEQ] = {
+const unsigned long dwAL2230InitTable[CB_AL2230_INIT_SEQ] = {
0x03F79000+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, //
0x03333100+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, //
0x01A00200+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, //
@@ -112,7 +112,7 @@ const DWORD dwAL2230InitTable[CB_AL2230_INIT_SEQ] = {
0x00580F00+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW
};
-const DWORD dwAL2230ChannelTable0[CB_MAX_CHANNEL] = {
+const unsigned long dwAL2230ChannelTable0[CB_MAX_CHANNEL] = {
0x03F79000+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 1, Tf = 2412MHz
0x03F79000+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 2, Tf = 2417MHz
0x03E79000+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 3, Tf = 2422MHz
@@ -129,7 +129,7 @@ const DWORD dwAL2230ChannelTable0[CB_MAX_CHANNEL] = {
0x03E7C000+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW // channel = 14, Tf = 2412M
};
-const DWORD dwAL2230ChannelTable1[CB_MAX_CHANNEL] = {
+const unsigned long dwAL2230ChannelTable1[CB_MAX_CHANNEL] = {
0x03333100+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 1, Tf = 2412MHz
0x0B333100+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 2, Tf = 2417MHz
0x03333100+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 3, Tf = 2422MHz
@@ -146,7 +146,7 @@ const DWORD dwAL2230ChannelTable1[CB_MAX_CHANNEL] = {
0x06666100+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW // channel = 14, Tf = 2412M
};
-DWORD dwAL2230PowerTable[AL2230_PWR_IDX_LEN] = {
+unsigned long dwAL2230PowerTable[AL2230_PWR_IDX_LEN] = {
0x04040900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW,
0x04041900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW,
0x04042900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW,
@@ -216,7 +216,7 @@ DWORD dwAL2230PowerTable[AL2230_PWR_IDX_LEN] = {
//{{ RobertYu:20050104
// 40MHz reference frequency
// Need to Pull PLLON(PE3) low when writing channel registers through 3-wire.
-const DWORD dwAL7230InitTable[CB_AL7230_INIT_SEQ] = {
+const unsigned long dwAL7230InitTable[CB_AL7230_INIT_SEQ] = {
0x00379000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // Channel1 // Need modify for 11a
0x13333100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // Channel1 // Need modify for 11a
0x841FF200+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // Need modify for 11a: 451FE2
@@ -239,7 +239,7 @@ const DWORD dwAL7230InitTable[CB_AL7230_INIT_SEQ] = {
0x1ABA8F00+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW // Need modify for 11a: 12BACF
};
-const DWORD dwAL7230InitTableAMode[CB_AL7230_INIT_SEQ] = {
+const unsigned long dwAL7230InitTableAMode[CB_AL7230_INIT_SEQ] = {
0x0FF52000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // Channel184 // Need modify for 11b/g
0x00000100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // Channel184 // Need modify for 11b/g
0x451FE200+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // Need modify for 11b/g
@@ -259,7 +259,7 @@ const DWORD dwAL7230InitTableAMode[CB_AL7230_INIT_SEQ] = {
};
-const DWORD dwAL7230ChannelTable0[CB_MAX_CHANNEL] = {
+const unsigned long dwAL7230ChannelTable0[CB_MAX_CHANNEL] = {
0x00379000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 1, Tf = 2412MHz
0x00379000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 2, Tf = 2417MHz
0x00379000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 3, Tf = 2422MHz
@@ -325,7 +325,7 @@ const DWORD dwAL7230ChannelTable0[CB_MAX_CHANNEL] = {
0x0FF61000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW // channel = 165, Tf = 5825MHz (56)
};
-const DWORD dwAL7230ChannelTable1[CB_MAX_CHANNEL] = {
+const unsigned long dwAL7230ChannelTable1[CB_MAX_CHANNEL] = {
0x13333100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 1, Tf = 2412MHz
0x1B333100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 2, Tf = 2417MHz
0x03333100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 3, Tf = 2422MHz
@@ -389,7 +389,7 @@ const DWORD dwAL7230ChannelTable1[CB_MAX_CHANNEL] = {
0x02AAA100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW // channel = 165, Tf = 5825MHz (56)
};
-const DWORD dwAL7230ChannelTable2[CB_MAX_CHANNEL] = {
+const unsigned long dwAL7230ChannelTable2[CB_MAX_CHANNEL] = {
0x7FD78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 1, Tf = 2412MHz
0x7FD78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 2, Tf = 2417MHz
0x7FD78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 3, Tf = 2422MHz
@@ -471,15 +471,15 @@ const DWORD dwAL7230ChannelTable2[CB_MAX_CHANNEL] = {
* Out:
* none
*
- * Return Value: TRUE if succeeded; FALSE if failed.
+ * Return Value: true if succeeded; false if failed.
*
*/
-BOOL s_bAL7230Init (DWORD_PTR dwIoBase)
+bool s_bAL7230Init (unsigned long dwIoBase)
{
int ii;
- BOOL bResult;
+ bool bResult;
- bResult = TRUE;
+ bResult = true;
//3-wire control for normal mode
VNSvOutPortB(dwIoBase + MAC_REG_SOFTPWRCTL, 0);
@@ -517,11 +517,11 @@ BOOL s_bAL7230Init (DWORD_PTR dwIoBase)
}
// Need to Pull PLLON low when writing channel registers through 3-wire interface
-BOOL s_bAL7230SelectChannel (DWORD_PTR dwIoBase, BYTE byChannel)
+bool s_bAL7230SelectChannel (unsigned long dwIoBase, unsigned char byChannel)
{
- BOOL bResult;
+ bool bResult;
- bResult = TRUE;
+ bResult = true;
// PLLON Off
MACvWordRegBitsOff(dwIoBase, MAC_REG_SOFTPWRCTL, SOFTPWRCTL_SWPE3);
@@ -552,7 +552,7 @@ BOOL s_bAL7230SelectChannel (DWORD_PTR dwIoBase, BYTE byChannel)
* Out:
* none
*
- * Return Value: TRUE if succeeded; FALSE if failed.
+ * Return Value: true if succeeded; false if failed.
*
*/
@@ -567,7 +567,7 @@ BOOL s_bAL7230SelectChannel (DWORD_PTR dwIoBase, BYTE byChannel)
* Out:
* none
*
- * Return Value: TRUE if succeeded; FALSE if failed.
+ * Return Value: true if succeeded; false if failed.
*
*/
@@ -585,7 +585,7 @@ BOOL s_bAL7230SelectChannel (DWORD_PTR dwIoBase, BYTE byChannel)
* Out:
* none
*
- * Return Value: TRUE if succeeded; FALSE if failed.
+ * Return Value: true if succeeded; false if failed.
*
*/
@@ -599,7 +599,7 @@ BOOL s_bAL7230SelectChannel (DWORD_PTR dwIoBase, BYTE byChannel)
* Out:
* none
*
- * Return Value: TRUE if succeeded; FALSE if failed.
+ * Return Value: true if succeeded; false if failed.
*
*/
@@ -619,13 +619,13 @@ BOOL s_bAL7230SelectChannel (DWORD_PTR dwIoBase, BYTE byChannel)
* Out:
* none
*
- * Return Value: TRUE if succeeded; FALSE if failed.
+ * Return Value: true if succeeded; false if failed.
*
*/
-BOOL IFRFbWriteEmbeded (DWORD_PTR dwIoBase, DWORD dwData)
+bool IFRFbWriteEmbeded (unsigned long dwIoBase, unsigned long dwData)
{
- WORD ww;
- DWORD dwValue;
+ unsigned short ww;
+ unsigned long dwValue;
VNSvOutPortD(dwIoBase + MAC_REG_IFREGCTL, dwData);
@@ -638,9 +638,9 @@ BOOL IFRFbWriteEmbeded (DWORD_PTR dwIoBase, DWORD dwData)
if (ww == W_MAX_TIMEOUT) {
// DBG_PORT80_ALWAYS(0x32);
- return FALSE;
+ return false;
}
- return TRUE;
+ return true;
}
@@ -654,7 +654,7 @@ BOOL IFRFbWriteEmbeded (DWORD_PTR dwIoBase, DWORD dwData)
* Out:
* none
*
- * Return Value: TRUE if succeeded; FALSE if failed.
+ * Return Value: true if succeeded; false if failed.
*
*/
@@ -668,7 +668,7 @@ BOOL IFRFbWriteEmbeded (DWORD_PTR dwIoBase, DWORD dwData)
* Out:
* none
*
- * Return Value: TRUE if succeeded; FALSE if failed.
+ * Return Value: true if succeeded; false if failed.
*
*/
@@ -681,15 +681,15 @@ BOOL IFRFbWriteEmbeded (DWORD_PTR dwIoBase, DWORD dwData)
* Out:
* none
*
- * Return Value: TRUE if succeeded; FALSE if failed.
+ * Return Value: true if succeeded; false if failed.
*
*/
-BOOL RFbAL2230Init (DWORD_PTR dwIoBase)
+bool RFbAL2230Init (unsigned long dwIoBase)
{
int ii;
- BOOL bResult;
+ bool bResult;
- bResult = TRUE;
+ bResult = true;
//3-wire control for normal mode
VNSvOutPortB(dwIoBase + MAC_REG_SOFTPWRCTL, 0);
@@ -734,11 +734,11 @@ MACvTimer0MicroSDelay(dwIoBase, 30); //delay 30 us
return bResult;
}
-BOOL RFbAL2230SelectChannel (DWORD_PTR dwIoBase, BYTE byChannel)
+bool RFbAL2230SelectChannel (unsigned long dwIoBase, unsigned char byChannel)
{
- BOOL bResult;
+ bool bResult;
- bResult = TRUE;
+ bResult = true;
bResult &= IFRFbWriteEmbeded (dwIoBase, dwAL2230ChannelTable0[byChannel-1]);
bResult &= IFRFbWriteEmbeded (dwIoBase, dwAL2230ChannelTable1[byChannel-1]);
@@ -761,7 +761,7 @@ BOOL RFbAL2230SelectChannel (DWORD_PTR dwIoBase, BYTE byChannel)
* Out:
* none
*
- * Return Value: TRUE if succeeded; FALSE if failed.
+ * Return Value: true if succeeded; false if failed.
*
*/
@@ -776,7 +776,7 @@ BOOL RFbAL2230SelectChannel (DWORD_PTR dwIoBase, BYTE byChannel)
* Out:
* none
*
- * Return Value: TRUE if succeeded; FALSE if failed.
+ * Return Value: true if succeeded; false if failed.
*
*/
@@ -790,7 +790,7 @@ BOOL RFbAL2230SelectChannel (DWORD_PTR dwIoBase, BYTE byChannel)
* Out:
* none
*
- * Return Value: TRUE if succeeded; FALSE if failed.
+ * Return Value: true if succeeded; false if failed.
*
*/
@@ -804,14 +804,14 @@ BOOL RFbAL2230SelectChannel (DWORD_PTR dwIoBase, BYTE byChannel)
* Out:
* none
*
- * Return Value: TRUE if succeeded; FALSE if failed.
+ * Return Value: true if succeeded; false if failed.
*
*/
-BOOL RFbInit (
+bool RFbInit (
PSDevice pDevice
)
{
-BOOL bResult = TRUE;
+bool bResult = true;
switch (pDevice->byRFType) {
case RF_AIROHA :
case RF_AL2230S:
@@ -823,10 +823,10 @@ BOOL bResult = TRUE;
bResult = s_bAL7230Init(pDevice->PortOffset);
break;
case RF_NOTHING :
- bResult = TRUE;
+ bResult = true;
break;
default :
- bResult = FALSE;
+ bResult = false;
break;
}
return bResult;
@@ -842,21 +842,21 @@ BOOL bResult = TRUE;
* Out:
* none
*
- * Return Value: TRUE if succeeded; FALSE if failed.
+ * Return Value: true if succeeded; false if failed.
*
*/
-BOOL RFbShutDown (
+bool RFbShutDown (
PSDevice pDevice
)
{
-BOOL bResult = TRUE;
+bool bResult = true;
switch (pDevice->byRFType) {
case RF_AIROHA7230 :
bResult = IFRFbWriteEmbeded (pDevice->PortOffset, 0x1ABAEF00+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW);
break;
default :
- bResult = TRUE;
+ bResult = true;
break;
}
return bResult;
@@ -872,12 +872,12 @@ BOOL bResult = TRUE;
* Out:
* none
*
- * Return Value: TRUE if succeeded; FALSE if failed.
+ * Return Value: true if succeeded; false if failed.
*
*/
-BOOL RFbSelectChannel (DWORD_PTR dwIoBase, BYTE byRFType, BYTE byChannel)
+bool RFbSelectChannel (unsigned long dwIoBase, unsigned char byRFType, unsigned char byChannel)
{
-BOOL bResult = TRUE;
+bool bResult = true;
switch (byRFType) {
case RF_AIROHA :
@@ -890,10 +890,10 @@ BOOL bResult = TRUE;
break;
//}} RobertYu
case RF_NOTHING :
- bResult = TRUE;
+ bResult = true;
break;
default:
- bResult = FALSE;
+ bResult = false;
break;
}
return bResult;
@@ -911,11 +911,11 @@ BOOL bResult = TRUE;
* Return Value: None.
*
*/
-BOOL RFvWriteWakeProgSyn (DWORD_PTR dwIoBase, BYTE byRFType, UINT uChannel)
+bool RFvWriteWakeProgSyn (unsigned long dwIoBase, unsigned char byRFType, unsigned int uChannel)
{
int ii;
- BYTE byInitCount = 0;
- BYTE bySleepCount = 0;
+ unsigned char byInitCount = 0;
+ unsigned char bySleepCount = 0;
VNSvOutPortW(dwIoBase + MAC_REG_MISCFFNDEX, 0);
switch (byRFType) {
@@ -923,20 +923,20 @@ BOOL RFvWriteWakeProgSyn (DWORD_PTR dwIoBase, BYTE byRFType, UINT uChannel)
case RF_AL2230S:
if (uChannel > CB_MAX_CHANNEL_24G)
- return FALSE;
+ return false;
byInitCount = CB_AL2230_INIT_SEQ + 2; // Init Reg + Channel Reg (2)
bySleepCount = 0;
if (byInitCount > (MISCFIFO_SYNDATASIZE - bySleepCount)) {
- return FALSE;
+ return false;
}
for (ii = 0; ii < CB_AL2230_INIT_SEQ; ii++ ) {
- MACvSetMISCFifo(dwIoBase, (WORD)(MISCFIFO_SYNDATA_IDX + ii), dwAL2230InitTable[ii]);
+ MACvSetMISCFifo(dwIoBase, (unsigned short)(MISCFIFO_SYNDATA_IDX + ii), dwAL2230InitTable[ii]);
}
- MACvSetMISCFifo(dwIoBase, (WORD)(MISCFIFO_SYNDATA_IDX + ii), dwAL2230ChannelTable0[uChannel-1]);
+ MACvSetMISCFifo(dwIoBase, (unsigned short)(MISCFIFO_SYNDATA_IDX + ii), dwAL2230ChannelTable0[uChannel-1]);
ii ++;
- MACvSetMISCFifo(dwIoBase, (WORD)(MISCFIFO_SYNDATA_IDX + ii), dwAL2230ChannelTable1[uChannel-1]);
+ MACvSetMISCFifo(dwIoBase, (unsigned short)(MISCFIFO_SYNDATA_IDX + ii), dwAL2230ChannelTable1[uChannel-1]);
break;
//{{ RobertYu: 20050104
@@ -945,42 +945,42 @@ BOOL RFvWriteWakeProgSyn (DWORD_PTR dwIoBase, BYTE byRFType, UINT uChannel)
byInitCount = CB_AL7230_INIT_SEQ + 3; // Init Reg + Channel Reg (3)
bySleepCount = 0;
if (byInitCount > (MISCFIFO_SYNDATASIZE - bySleepCount)) {
- return FALSE;
+ return false;
}
if (uChannel <= CB_MAX_CHANNEL_24G)
{
for (ii = 0; ii < CB_AL7230_INIT_SEQ; ii++ ) {
- MACvSetMISCFifo(dwIoBase, (WORD)(MISCFIFO_SYNDATA_IDX + ii), dwAL7230InitTable[ii]);
+ MACvSetMISCFifo(dwIoBase, (unsigned short)(MISCFIFO_SYNDATA_IDX + ii), dwAL7230InitTable[ii]);
}
}
else
{
for (ii = 0; ii < CB_AL7230_INIT_SEQ; ii++ ) {
- MACvSetMISCFifo(dwIoBase, (WORD)(MISCFIFO_SYNDATA_IDX + ii), dwAL7230InitTableAMode[ii]);
+ MACvSetMISCFifo(dwIoBase, (unsigned short)(MISCFIFO_SYNDATA_IDX + ii), dwAL7230InitTableAMode[ii]);
}
}
- MACvSetMISCFifo(dwIoBase, (WORD)(MISCFIFO_SYNDATA_IDX + ii), dwAL7230ChannelTable0[uChannel-1]);
+ MACvSetMISCFifo(dwIoBase, (unsigned short)(MISCFIFO_SYNDATA_IDX + ii), dwAL7230ChannelTable0[uChannel-1]);
ii ++;
- MACvSetMISCFifo(dwIoBase, (WORD)(MISCFIFO_SYNDATA_IDX + ii), dwAL7230ChannelTable1[uChannel-1]);
+ MACvSetMISCFifo(dwIoBase, (unsigned short)(MISCFIFO_SYNDATA_IDX + ii), dwAL7230ChannelTable1[uChannel-1]);
ii ++;
- MACvSetMISCFifo(dwIoBase, (WORD)(MISCFIFO_SYNDATA_IDX + ii), dwAL7230ChannelTable2[uChannel-1]);
+ MACvSetMISCFifo(dwIoBase, (unsigned short)(MISCFIFO_SYNDATA_IDX + ii), dwAL7230ChannelTable2[uChannel-1]);
break;
//}} RobertYu
case RF_NOTHING :
- return TRUE;
+ return true;
break;
default:
- return FALSE;
+ return false;
break;
}
- MACvSetMISCFifo(dwIoBase, MISCFIFO_SYNINFO_IDX, (DWORD)MAKEWORD(bySleepCount, byInitCount));
+ MACvSetMISCFifo(dwIoBase, MISCFIFO_SYNINFO_IDX, (unsigned long )MAKEWORD(bySleepCount, byInitCount));
- return TRUE;
+ return true;
}
/*
@@ -993,25 +993,25 @@ BOOL RFvWriteWakeProgSyn (DWORD_PTR dwIoBase, BYTE byRFType, UINT uChannel)
* Out:
* none
*
- * Return Value: TRUE if succeeded; FALSE if failed.
+ * Return Value: true if succeeded; false if failed.
*
*/
-BOOL RFbSetPower (
+bool RFbSetPower (
PSDevice pDevice,
- UINT uRATE,
- UINT uCH
+ unsigned int uRATE,
+ unsigned int uCH
)
{
-BOOL bResult = TRUE;
-BYTE byPwr = 0;
-BYTE byDec = 0;
-BYTE byPwrdBm = 0;
+bool bResult = true;
+unsigned char byPwr = 0;
+unsigned char byDec = 0;
+unsigned char byPwrdBm = 0;
if (pDevice->dwDiagRefCount != 0) {
- return TRUE;
+ return true;
}
if ((uCH < 1) || (uCH > CB_MAX_CHANNEL)) {
- return FALSE;
+ return false;
}
switch (uRATE) {
@@ -1070,7 +1070,7 @@ BYTE byPwrdBm = 0;
#if 0
// 802.11h TPC
- if (pDevice->bLinkPass == TRUE) {
+ if (pDevice->bLinkPass == true) {
// do not over local constraint
if (byPwrdBm > pDevice->abyLocalPwr[uCH]) {
pDevice->byCurPwrdBm = pDevice->abyLocalPwr[uCH];
@@ -1111,11 +1111,11 @@ BYTE byPwrdBm = 0;
// if (pDevice->byLocalID <= REV_ID_VT3253_B1) {
if (pDevice->byCurPwr == byPwr) {
- return TRUE;
+ return true;
}
bResult = RFbRawSetPower(pDevice, byPwr, uRATE);
// }
- if (bResult == TRUE) {
+ if (bResult == true) {
pDevice->byCurPwr = byPwr;
}
return bResult;
@@ -1131,21 +1131,21 @@ BYTE byPwrdBm = 0;
* Out:
* none
*
- * Return Value: TRUE if succeeded; FALSE if failed.
+ * Return Value: true if succeeded; false if failed.
*
*/
-BOOL RFbRawSetPower (
+bool RFbRawSetPower (
PSDevice pDevice,
- BYTE byPwr,
- UINT uRATE
+ unsigned char byPwr,
+ unsigned int uRATE
)
{
-BOOL bResult = TRUE;
-DWORD dwMax7230Pwr = 0;
+bool bResult = true;
+unsigned long dwMax7230Pwr = 0;
if (byPwr >= pDevice->byMaxPwrLevel) {
- return (FALSE);
+ return (false);
}
switch (pDevice->byRFType) {
@@ -1204,14 +1204,14 @@ DWORD dwMax7230Pwr = 0;
void
RFvRSSITodBm (
PSDevice pDevice,
- BYTE byCurrRSSI,
+ unsigned char byCurrRSSI,
long * pldBm
)
{
- BYTE byIdx = (((byCurrRSSI & 0xC0) >> 6) & 0x03);
- LONG b = (byCurrRSSI & 0x3F);
- LONG a = 0;
- BYTE abyAIROHARF[4] = {0, 18, 0, 40};
+ unsigned char byIdx = (((byCurrRSSI & 0xC0) >> 6) & 0x03);
+ long b = (byCurrRSSI & 0x3F);
+ long a = 0;
+ unsigned char abyAIROHARF[4] = {0, 18, 0, 40};
switch (pDevice->byRFType) {
case RF_AIROHA:
@@ -1232,11 +1232,11 @@ RFvRSSITodBm (
// Post processing for the 11b/g and 11a.
// for save time on changing Reg2,3,5,7,10,12,15
-BOOL RFbAL7230SelectChannelPostProcess (DWORD_PTR dwIoBase, BYTE byOldChannel, BYTE byNewChannel)
+bool RFbAL7230SelectChannelPostProcess (unsigned long dwIoBase, unsigned char byOldChannel, unsigned char byNewChannel)
{
- BOOL bResult;
+ bool bResult;
- bResult = TRUE;
+ bResult = true;
// if change between 11 b/g and 11a need to update the following register
// Channel Index 1~14
diff --git a/drivers/staging/vt6655/rf.h b/drivers/staging/vt6655/rf.h
index 25dfc7942f6..1f8d82e1304 100644
--- a/drivers/staging/vt6655/rf.h
+++ b/drivers/staging/vt6655/rf.h
@@ -76,28 +76,28 @@
/*--------------------- Export Functions --------------------------*/
-BOOL IFRFbWriteEmbeded(DWORD_PTR dwIoBase, DWORD dwData);
-BOOL RFbSelectChannel(DWORD_PTR dwIoBase, BYTE byRFType, BYTE byChannel);
-BOOL RFbInit (
+bool IFRFbWriteEmbeded(unsigned long dwIoBase, unsigned long dwData);
+bool RFbSelectChannel(unsigned long dwIoBase, unsigned char byRFType, unsigned char byChannel);
+bool RFbInit (
PSDevice pDevice
);
-BOOL RFvWriteWakeProgSyn(DWORD_PTR dwIoBase, BYTE byRFType, UINT uChannel);
-BOOL RFbSetPower(PSDevice pDevice, UINT uRATE, UINT uCH);
-BOOL RFbRawSetPower(
+bool RFvWriteWakeProgSyn(unsigned long dwIoBase, unsigned char byRFType, unsigned int uChannel);
+bool RFbSetPower(PSDevice pDevice, unsigned int uRATE, unsigned int uCH);
+bool RFbRawSetPower(
PSDevice pDevice,
- BYTE byPwr,
- UINT uRATE
+ unsigned char byPwr,
+ unsigned int uRATE
);
void
RFvRSSITodBm(
PSDevice pDevice,
- BYTE byCurrRSSI,
+ unsigned char byCurrRSSI,
long *pldBm
);
//{{ RobertYu: 20050104
-BOOL RFbAL7230SelectChannelPostProcess(DWORD_PTR dwIoBase, BYTE byOldChannel, BYTE byNewChannel);
+bool RFbAL7230SelectChannelPostProcess(unsigned long dwIoBase, unsigned char byOldChannel, unsigned char byNewChannel);
//}} RobertYu
#endif // __RF_H__
diff --git a/drivers/staging/vt6655/rxtx.c b/drivers/staging/vt6655/rxtx.c
index a0445c3427e..c920cf69405 100644
--- a/drivers/staging/vt6655/rxtx.c
+++ b/drivers/staging/vt6655/rxtx.c
@@ -80,16 +80,16 @@ static int msglevel =MSG_LEVEL_INFO;
#define CRITICAL_PACKET_LEN 256 // if packet size < 256 -> in-direct send
// packet size >= 256 -> direct send
-const WORD wTimeStampOff[2][MAX_RATE] = {
+const unsigned short wTimeStampOff[2][MAX_RATE] = {
{384, 288, 226, 209, 54, 43, 37, 31, 28, 25, 24, 23}, // Long Preamble
{384, 192, 130, 113, 54, 43, 37, 31, 28, 25, 24, 23}, // Short Preamble
};
-const WORD wFB_Opt0[2][5] = {
+const unsigned short wFB_Opt0[2][5] = {
{RATE_12M, RATE_18M, RATE_24M, RATE_36M, RATE_48M}, // fallback_rate0
{RATE_12M, RATE_12M, RATE_18M, RATE_24M, RATE_36M}, // fallback_rate1
};
-const WORD wFB_Opt1[2][5] = {
+const unsigned short wFB_Opt1[2][5] = {
{RATE_12M, RATE_18M, RATE_24M, RATE_24M, RATE_36M}, // fallback_rate0
{RATE_6M , RATE_6M, RATE_12M, RATE_12M, RATE_18M}, // fallback_rate1
};
@@ -118,12 +118,12 @@ static
void
s_vFillTxKey(
PSDevice pDevice,
- PBYTE pbyBuf,
- PBYTE pbyIVHead,
+ unsigned char *pbyBuf,
+ unsigned char *pbyIVHead,
PSKeyItem pTransmitKey,
- PBYTE pbyHdrBuf,
- WORD wPayloadLen,
- PBYTE pMICHDR
+ unsigned char *pbyHdrBuf,
+ unsigned short wPayloadLen,
+ unsigned char *pMICHDR
);
@@ -132,76 +132,65 @@ static
void
s_vFillRTSHead(
PSDevice pDevice,
- BYTE byPktType,
+ unsigned char byPktType,
void * pvRTS,
- UINT cbFrameLength,
- BOOL bNeedAck,
- BOOL bDisCRC,
+ unsigned int cbFrameLength,
+ bool bNeedAck,
+ bool bDisCRC,
PSEthernetHeader psEthHeader,
- WORD wCurrentRate,
- BYTE byFBOption
+ unsigned short wCurrentRate,
+ unsigned char byFBOption
);
static
void
s_vGenerateTxParameter(
PSDevice pDevice,
- BYTE byPktType,
+ unsigned char byPktType,
void * pTxBufHead,
void * pvRrvTime,
void * pvRTS,
void * pvCTS,
- UINT cbFrameSize,
- BOOL bNeedACK,
- UINT uDMAIdx,
+ unsigned int cbFrameSize,
+ bool bNeedACK,
+ unsigned int uDMAIdx,
PSEthernetHeader psEthHeader,
- WORD wCurrentRate
+ unsigned short wCurrentRate
);
static void s_vFillFragParameter(
PSDevice pDevice,
- PBYTE pbyBuffer,
- UINT uTxType,
+ unsigned char *pbyBuffer,
+ unsigned int uTxType,
void * pvtdCurr,
- WORD wFragType,
- UINT cbReqCount
+ unsigned short wFragType,
+ unsigned int cbReqCount
);
-static
-UINT
-s_cbFillTxBufHead (
- PSDevice pDevice,
- BYTE byPktType,
- PBYTE pbyTxBufferAddr,
- UINT cbFrameBodySize,
- UINT uDMAIdx,
- PSTxDesc pHeadTD,
- PSEthernetHeader psEthHeader,
- PBYTE pPacket,
- BOOL bNeedEncrypt,
- PSKeyItem pTransmitKey,
- UINT uNodeIndex,
- PUINT puMACfragNum
- );
+static unsigned int
+s_cbFillTxBufHead(PSDevice pDevice, unsigned char byPktType, unsigned char *pbyTxBufferAddr,
+ unsigned int cbFrameBodySize, unsigned int uDMAIdx, PSTxDesc pHeadTD,
+ PSEthernetHeader psEthHeader, unsigned char *pPacket, bool bNeedEncrypt,
+ PSKeyItem pTransmitKey, unsigned int uNodeIndex, unsigned int *puMACfragNum);
static
-UINT
+unsigned int
s_uFillDataHead (
PSDevice pDevice,
- BYTE byPktType,
+ unsigned char byPktType,
void * pTxDataHead,
- UINT cbFrameLength,
- UINT uDMAIdx,
- BOOL bNeedAck,
- UINT uFragIdx,
- UINT cbLastFragmentSize,
- UINT uMACfragNum,
- BYTE byFBOption,
- WORD wCurrentRate
+ unsigned int cbFrameLength,
+ unsigned int uDMAIdx,
+ bool bNeedAck,
+ unsigned int uFragIdx,
+ unsigned int cbLastFragmentSize,
+ unsigned int uMACfragNum,
+ unsigned char byFBOption,
+ unsigned short wCurrentRate
);
@@ -213,20 +202,20 @@ static
void
s_vFillTxKey (
PSDevice pDevice,
- PBYTE pbyBuf,
- PBYTE pbyIVHead,
+ unsigned char *pbyBuf,
+ unsigned char *pbyIVHead,
PSKeyItem pTransmitKey,
- PBYTE pbyHdrBuf,
- WORD wPayloadLen,
- PBYTE pMICHDR
+ unsigned char *pbyHdrBuf,
+ unsigned short wPayloadLen,
+ unsigned char *pMICHDR
)
{
- PDWORD pdwIV = (PDWORD) pbyIVHead;
- PDWORD pdwExtIV = (PDWORD) ((PBYTE)pbyIVHead+4);
- WORD wValue;
+ unsigned long *pdwIV = (unsigned long *) pbyIVHead;
+ unsigned long *pdwExtIV = (unsigned long *) ((unsigned char *)pbyIVHead+4);
+ unsigned short wValue;
PS802_11Header pMACHeader = (PS802_11Header)pbyHdrBuf;
- DWORD dwRevIVCounter;
- BYTE byKeyIndex = 0;
+ unsigned long dwRevIVCounter;
+ unsigned char byKeyIndex = 0;
@@ -240,13 +229,13 @@ s_vFillTxKey (
if (pTransmitKey->byCipherSuite == KEY_CTL_WEP) {
if (pTransmitKey->uKeyLength == WLAN_WEP232_KEYLEN ){
- memcpy(pDevice->abyPRNG, (PBYTE)&(dwRevIVCounter), 3);
+ memcpy(pDevice->abyPRNG, (unsigned char *)&(dwRevIVCounter), 3);
memcpy(pDevice->abyPRNG+3, pTransmitKey->abyKey, pTransmitKey->uKeyLength);
} else {
- memcpy(pbyBuf, (PBYTE)&(dwRevIVCounter), 3);
+ memcpy(pbyBuf, (unsigned char *)&(dwRevIVCounter), 3);
memcpy(pbyBuf+3, pTransmitKey->abyKey, pTransmitKey->uKeyLength);
if(pTransmitKey->uKeyLength == WLAN_WEP40_KEYLEN) {
- memcpy(pbyBuf+8, (PBYTE)&(dwRevIVCounter), 3);
+ memcpy(pbyBuf+8, (unsigned char *)&(dwRevIVCounter), 3);
memcpy(pbyBuf+11, pTransmitKey->abyKey, pTransmitKey->uKeyLength);
}
memcpy(pDevice->abyPRNG, pbyBuf, 16);
@@ -270,7 +259,7 @@ s_vFillTxKey (
// Make IV
memcpy(pdwIV, pDevice->abyPRNG, 3);
- *(pbyIVHead+3) = (BYTE)(((byKeyIndex << 6) & 0xc0) | 0x20); // 0x20 is ExtIV
+ *(pbyIVHead+3) = (unsigned char)(((byKeyIndex << 6) & 0xc0) | 0x20); // 0x20 is ExtIV
// Append IV&ExtIV after Mac Header
*pdwExtIV = cpu_to_le32(pTransmitKey->dwTSC47_16);
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"vFillTxKey()---- pdwExtIV: %lx\n", *pdwExtIV);
@@ -284,33 +273,33 @@ s_vFillTxKey (
// Make IV
*pdwIV = 0;
- *(pbyIVHead+3) = (BYTE)(((byKeyIndex << 6) & 0xc0) | 0x20); // 0x20 is ExtIV
- *pdwIV |= cpu_to_le16((WORD)(pTransmitKey->wTSC15_0));
+ *(pbyIVHead+3) = (unsigned char)(((byKeyIndex << 6) & 0xc0) | 0x20); // 0x20 is ExtIV
+ *pdwIV |= cpu_to_le16((unsigned short)(pTransmitKey->wTSC15_0));
//Append IV&ExtIV after Mac Header
*pdwExtIV = cpu_to_le32(pTransmitKey->dwTSC47_16);
//Fill MICHDR0
*pMICHDR = 0x59;
- *((PBYTE)(pMICHDR+1)) = 0; // TxPriority
+ *((unsigned char *)(pMICHDR+1)) = 0; // TxPriority
memcpy(pMICHDR+2, &(pMACHeader->abyAddr2[0]), 6);
- *((PBYTE)(pMICHDR+8)) = HIBYTE(HIWORD(pTransmitKey->dwTSC47_16));
- *((PBYTE)(pMICHDR+9)) = LOBYTE(HIWORD(pTransmitKey->dwTSC47_16));
- *((PBYTE)(pMICHDR+10)) = HIBYTE(LOWORD(pTransmitKey->dwTSC47_16));
- *((PBYTE)(pMICHDR+11)) = LOBYTE(LOWORD(pTransmitKey->dwTSC47_16));
- *((PBYTE)(pMICHDR+12)) = HIBYTE(pTransmitKey->wTSC15_0);
- *((PBYTE)(pMICHDR+13)) = LOBYTE(pTransmitKey->wTSC15_0);
- *((PBYTE)(pMICHDR+14)) = HIBYTE(wPayloadLen);
- *((PBYTE)(pMICHDR+15)) = LOBYTE(wPayloadLen);
+ *((unsigned char *)(pMICHDR+8)) = HIBYTE(HIWORD(pTransmitKey->dwTSC47_16));
+ *((unsigned char *)(pMICHDR+9)) = LOBYTE(HIWORD(pTransmitKey->dwTSC47_16));
+ *((unsigned char *)(pMICHDR+10)) = HIBYTE(LOWORD(pTransmitKey->dwTSC47_16));
+ *((unsigned char *)(pMICHDR+11)) = LOBYTE(LOWORD(pTransmitKey->dwTSC47_16));
+ *((unsigned char *)(pMICHDR+12)) = HIBYTE(pTransmitKey->wTSC15_0);
+ *((unsigned char *)(pMICHDR+13)) = LOBYTE(pTransmitKey->wTSC15_0);
+ *((unsigned char *)(pMICHDR+14)) = HIBYTE(wPayloadLen);
+ *((unsigned char *)(pMICHDR+15)) = LOBYTE(wPayloadLen);
//Fill MICHDR1
- *((PBYTE)(pMICHDR+16)) = 0; // HLEN[15:8]
+ *((unsigned char *)(pMICHDR+16)) = 0; // HLEN[15:8]
if (pDevice->bLongHeader) {
- *((PBYTE)(pMICHDR+17)) = 28; // HLEN[7:0]
+ *((unsigned char *)(pMICHDR+17)) = 28; // HLEN[7:0]
} else {
- *((PBYTE)(pMICHDR+17)) = 22; // HLEN[7:0]
+ *((unsigned char *)(pMICHDR+17)) = 22; // HLEN[7:0]
}
wValue = cpu_to_le16(pMACHeader->wFrameCtl & 0xC78F);
- memcpy(pMICHDR+18, (PBYTE)&wValue, 2); // MSKFRACTL
+ memcpy(pMICHDR+18, (unsigned char *)&wValue, 2); // MSKFRACTL
memcpy(pMICHDR+20, &(pMACHeader->abyAddr1[0]), 6);
memcpy(pMICHDR+26, &(pMACHeader->abyAddr2[0]), 6);
@@ -319,7 +308,7 @@ s_vFillTxKey (
wValue = pMACHeader->wSeqCtl;
wValue &= 0x000F;
wValue = cpu_to_le16(wValue);
- memcpy(pMICHDR+38, (PBYTE)&wValue, 2); // MSKSEQCTL
+ memcpy(pMICHDR+38, (unsigned char *)&wValue, 2); // MSKSEQCTL
if (pDevice->bLongHeader) {
memcpy(pMICHDR+40, &(pMACHeader->abyAddr4[0]), 6);
}
@@ -332,13 +321,13 @@ void
s_vSWencryption (
PSDevice pDevice,
PSKeyItem pTransmitKey,
- PBYTE pbyPayloadHead,
- WORD wPayloadSize
+ unsigned char *pbyPayloadHead,
+ unsigned short wPayloadSize
)
{
- UINT cbICVlen = 4;
- DWORD dwICV = 0xFFFFFFFFL;
- PDWORD pdwICV;
+ unsigned int cbICVlen = 4;
+ unsigned long dwICV = 0xFFFFFFFFL;
+ unsigned long *pdwICV;
if (pTransmitKey == NULL)
return;
@@ -347,7 +336,7 @@ s_vSWencryption (
//=======================================================================
// Append ICV after payload
dwICV = CRCdwGetCrc32Ex(pbyPayloadHead, wPayloadSize, dwICV);//ICV(Payload)
- pdwICV = (PDWORD)(pbyPayloadHead + wPayloadSize);
+ pdwICV = (unsigned long *)(pbyPayloadHead + wPayloadSize);
// finally, we must invert dwCRC to get the correct answer
*pdwICV = cpu_to_le32(~dwICV);
// RC4 encryption
@@ -358,7 +347,7 @@ s_vSWencryption (
//=======================================================================
//Append ICV after payload
dwICV = CRCdwGetCrc32Ex(pbyPayloadHead, wPayloadSize, dwICV);//ICV(Payload)
- pdwICV = (PDWORD)(pbyPayloadHead + wPayloadSize);
+ pdwICV = (unsigned long *)(pbyPayloadHead + wPayloadSize);
// finally, we must invert dwCRC to get the correct answer
*pdwICV = cpu_to_le32(~dwICV);
// RC4 encryption
@@ -377,25 +366,25 @@ s_vSWencryption (
PK_TYPE_11GA 3
*/
static
-UINT
+unsigned int
s_uGetTxRsvTime (
PSDevice pDevice,
- BYTE byPktType,
- UINT cbFrameLength,
- WORD wRate,
- BOOL bNeedAck
+ unsigned char byPktType,
+ unsigned int cbFrameLength,
+ unsigned short wRate,
+ bool bNeedAck
)
{
- UINT uDataTime, uAckTime;
+ unsigned int uDataTime, uAckTime;
uDataTime = BBuGetFrameTime(pDevice->byPreambleType, byPktType, cbFrameLength, wRate);
#ifdef PLICE_DEBUG
//printk("s_uGetTxRsvTime is %d\n",uDataTime);
#endif
if (byPktType == PK_TYPE_11B) {//llb,CCK mode
- uAckTime = BBuGetFrameTime(pDevice->byPreambleType, byPktType, 14, (WORD)pDevice->byTopCCKBasicRate);
+ uAckTime = BBuGetFrameTime(pDevice->byPreambleType, byPktType, 14, (unsigned short)pDevice->byTopCCKBasicRate);
} else {//11g 2.4G OFDM mode & 11a 5G OFDM mode
- uAckTime = BBuGetFrameTime(pDevice->byPreambleType, byPktType, 14, (WORD)pDevice->byTopOFDMBasicRate);
+ uAckTime = BBuGetFrameTime(pDevice->byPreambleType, byPktType, 14, (unsigned short)pDevice->byTopOFDMBasicRate);
}
if (bNeedAck) {
@@ -408,16 +397,16 @@ s_uGetTxRsvTime (
//byFreqType: 0=>5GHZ 1=>2.4GHZ
static
-UINT
+unsigned int
s_uGetRTSCTSRsvTime (
PSDevice pDevice,
- BYTE byRTSRsvType,
- BYTE byPktType,
- UINT cbFrameLength,
- WORD wCurrentRate
+ unsigned char byRTSRsvType,
+ unsigned char byPktType,
+ unsigned int cbFrameLength,
+ unsigned short wCurrentRate
)
{
- UINT uRrvTime , uRTSTime, uCTSTime, uAckTime, uDataTime;
+ unsigned int uRrvTime , uRTSTime, uCTSTime, uAckTime, uDataTime;
uRrvTime = uRTSTime = uCTSTime = uAckTime = uDataTime = 0;
@@ -450,22 +439,22 @@ s_uGetRTSCTSRsvTime (
//byFreqType 0: 5GHz, 1:2.4Ghz
static
-UINT
+unsigned int
s_uGetDataDuration (
PSDevice pDevice,
- BYTE byDurType,
- UINT cbFrameLength,
- BYTE byPktType,
- WORD wRate,
- BOOL bNeedAck,
- UINT uFragIdx,
- UINT cbLastFragmentSize,
- UINT uMACfragNum,
- BYTE byFBOption
+ unsigned char byDurType,
+ unsigned int cbFrameLength,
+ unsigned char byPktType,
+ unsigned short wRate,
+ bool bNeedAck,
+ unsigned int uFragIdx,
+ unsigned int cbLastFragmentSize,
+ unsigned int uMACfragNum,
+ unsigned char byFBOption
)
{
- BOOL bLastFrag = 0;
- UINT uAckTime =0, uNextPktTime = 0;
+ bool bLastFrag = 0;
+ unsigned int uAckTime =0, uNextPktTime = 0;
@@ -614,25 +603,25 @@ s_uGetDataDuration (
break;
}
- ASSERT(FALSE);
+ ASSERT(false);
return 0;
}
//byFreqType: 0=>5GHZ 1=>2.4GHZ
static
-UINT
+unsigned int
s_uGetRTSCTSDuration (
PSDevice pDevice,
- BYTE byDurType,
- UINT cbFrameLength,
- BYTE byPktType,
- WORD wRate,
- BOOL bNeedAck,
- BYTE byFBOption
+ unsigned char byDurType,
+ unsigned int cbFrameLength,
+ unsigned char byPktType,
+ unsigned short wRate,
+ bool bNeedAck,
+ unsigned char byFBOption
)
{
- UINT uCTSTime = 0, uDurTime = 0;
+ unsigned int uCTSTime = 0, uDurTime = 0;
switch (byDurType) {
@@ -719,22 +708,22 @@ s_uGetRTSCTSDuration (
static
-UINT
+unsigned int
s_uFillDataHead (
PSDevice pDevice,
- BYTE byPktType,
+ unsigned char byPktType,
void * pTxDataHead,
- UINT cbFrameLength,
- UINT uDMAIdx,
- BOOL bNeedAck,
- UINT uFragIdx,
- UINT cbLastFragmentSize,
- UINT uMACfragNum,
- BYTE byFBOption,
- WORD wCurrentRate
+ unsigned int cbFrameLength,
+ unsigned int uDMAIdx,
+ bool bNeedAck,
+ unsigned int uFragIdx,
+ unsigned int cbLastFragmentSize,
+ unsigned int uMACfragNum,
+ unsigned char byFBOption,
+ unsigned short wCurrentRate
)
{
- WORD wLen = 0x0000;
+ unsigned short wLen = 0x0000;
if (pTxDataHead == NULL) {
return 0;
@@ -745,19 +734,19 @@ s_uFillDataHead (
PSTxDataHead_g pBuf = (PSTxDataHead_g)pTxDataHead;
//Get SignalField,ServiceField,Length
BBvCaculateParameter(pDevice, cbFrameLength, wCurrentRate, byPktType,
- (PWORD)&(wLen), (PBYTE)&(pBuf->byServiceField_a), (PBYTE)&(pBuf->bySignalField_a)
+ (unsigned short *)&(wLen), (unsigned char *)&(pBuf->byServiceField_a), (unsigned char *)&(pBuf->bySignalField_a)
);
pBuf->wTransmitLength_a = cpu_to_le16(wLen);
BBvCaculateParameter(pDevice, cbFrameLength, pDevice->byTopCCKBasicRate, PK_TYPE_11B,
- (PWORD)&(wLen), (PBYTE)&(pBuf->byServiceField_b), (PBYTE)&(pBuf->bySignalField_b)
+ (unsigned short *)&(wLen), (unsigned char *)&(pBuf->byServiceField_b), (unsigned char *)&(pBuf->bySignalField_b)
);
pBuf->wTransmitLength_b = cpu_to_le16(wLen);
//Get Duration and TimeStamp
- pBuf->wDuration_a = cpu_to_le16((WORD)s_uGetDataDuration(pDevice, DATADUR_A, cbFrameLength,
+ pBuf->wDuration_a = cpu_to_le16((unsigned short)s_uGetDataDuration(pDevice, DATADUR_A, cbFrameLength,
byPktType, wCurrentRate, bNeedAck, uFragIdx,
cbLastFragmentSize, uMACfragNum,
byFBOption)); //1: 2.4GHz
- pBuf->wDuration_b = cpu_to_le16((WORD)s_uGetDataDuration(pDevice, DATADUR_B, cbFrameLength,
+ pBuf->wDuration_b = cpu_to_le16((unsigned short)s_uGetDataDuration(pDevice, DATADUR_B, cbFrameLength,
PK_TYPE_11B, pDevice->byTopCCKBasicRate,
bNeedAck, uFragIdx, cbLastFragmentSize,
uMACfragNum, byFBOption)); //1: 2.4
@@ -771,21 +760,21 @@ s_uFillDataHead (
PSTxDataHead_g_FB pBuf = (PSTxDataHead_g_FB)pTxDataHead;
//Get SignalField,ServiceField,Length
BBvCaculateParameter(pDevice, cbFrameLength, wCurrentRate, byPktType,
- (PWORD)&(wLen), (PBYTE)&(pBuf->byServiceField_a), (PBYTE)&(pBuf->bySignalField_a)
+ (unsigned short *)&(wLen), (unsigned char *)&(pBuf->byServiceField_a), (unsigned char *)&(pBuf->bySignalField_a)
);
pBuf->wTransmitLength_a = cpu_to_le16(wLen);
BBvCaculateParameter(pDevice, cbFrameLength, pDevice->byTopCCKBasicRate, PK_TYPE_11B,
- (PWORD)&(wLen), (PBYTE)&(pBuf->byServiceField_b), (PBYTE)&(pBuf->bySignalField_b)
+ (unsigned short *)&(wLen), (unsigned char *)&(pBuf->byServiceField_b), (unsigned char *)&(pBuf->bySignalField_b)
);
pBuf->wTransmitLength_b = cpu_to_le16(wLen);
//Get Duration and TimeStamp
- pBuf->wDuration_a = cpu_to_le16((WORD)s_uGetDataDuration(pDevice, DATADUR_A, cbFrameLength, byPktType,
+ pBuf->wDuration_a = cpu_to_le16((unsigned short)s_uGetDataDuration(pDevice, DATADUR_A, cbFrameLength, byPktType,
wCurrentRate, bNeedAck, uFragIdx, cbLastFragmentSize, uMACfragNum, byFBOption)); //1: 2.4GHz
- pBuf->wDuration_b = cpu_to_le16((WORD)s_uGetDataDuration(pDevice, DATADUR_B, cbFrameLength, PK_TYPE_11B,
+ pBuf->wDuration_b = cpu_to_le16((unsigned short)s_uGetDataDuration(pDevice, DATADUR_B, cbFrameLength, PK_TYPE_11B,
pDevice->byTopCCKBasicRate, bNeedAck, uFragIdx, cbLastFragmentSize, uMACfragNum, byFBOption)); //1: 2.4GHz
- pBuf->wDuration_a_f0 = cpu_to_le16((WORD)s_uGetDataDuration(pDevice, DATADUR_A_F0, cbFrameLength, byPktType,
+ pBuf->wDuration_a_f0 = cpu_to_le16((unsigned short)s_uGetDataDuration(pDevice, DATADUR_A_F0, cbFrameLength, byPktType,
wCurrentRate, bNeedAck, uFragIdx, cbLastFragmentSize, uMACfragNum, byFBOption)); //1: 2.4GHz
- pBuf->wDuration_a_f1 = cpu_to_le16((WORD)s_uGetDataDuration(pDevice, DATADUR_A_F1, cbFrameLength, byPktType,
+ pBuf->wDuration_a_f1 = cpu_to_le16((unsigned short)s_uGetDataDuration(pDevice, DATADUR_A_F1, cbFrameLength, byPktType,
wCurrentRate, bNeedAck, uFragIdx, cbLastFragmentSize, uMACfragNum, byFBOption)); //1: 2.4GHz
pBuf->wTimeStampOff_a = cpu_to_le16(wTimeStampOff[pDevice->byPreambleType%2][wCurrentRate%MAX_RATE]);
@@ -800,16 +789,16 @@ s_uFillDataHead (
PSTxDataHead_a_FB pBuf = (PSTxDataHead_a_FB)pTxDataHead;
//Get SignalField,ServiceField,Length
BBvCaculateParameter(pDevice, cbFrameLength, wCurrentRate, byPktType,
- (PWORD)&(wLen), (PBYTE)&(pBuf->byServiceField), (PBYTE)&(pBuf->bySignalField)
+ (unsigned short *)&(wLen), (unsigned char *)&(pBuf->byServiceField), (unsigned char *)&(pBuf->bySignalField)
);
pBuf->wTransmitLength = cpu_to_le16(wLen);
//Get Duration and TimeStampOff
- pBuf->wDuration = cpu_to_le16((WORD)s_uGetDataDuration(pDevice, DATADUR_A, cbFrameLength, byPktType,
+ pBuf->wDuration = cpu_to_le16((unsigned short)s_uGetDataDuration(pDevice, DATADUR_A, cbFrameLength, byPktType,
wCurrentRate, bNeedAck, uFragIdx, cbLastFragmentSize, uMACfragNum, byFBOption)); //0: 5GHz
- pBuf->wDuration_f0 = cpu_to_le16((WORD)s_uGetDataDuration(pDevice, DATADUR_A_F0, cbFrameLength, byPktType,
+ pBuf->wDuration_f0 = cpu_to_le16((unsigned short)s_uGetDataDuration(pDevice, DATADUR_A_F0, cbFrameLength, byPktType,
wCurrentRate, bNeedAck, uFragIdx, cbLastFragmentSize, uMACfragNum, byFBOption)); //0: 5GHz
- pBuf->wDuration_f1 = cpu_to_le16((WORD)s_uGetDataDuration(pDevice, DATADUR_A_F1, cbFrameLength, byPktType,
+ pBuf->wDuration_f1 = cpu_to_le16((unsigned short)s_uGetDataDuration(pDevice, DATADUR_A_F1, cbFrameLength, byPktType,
wCurrentRate, bNeedAck, uFragIdx, cbLastFragmentSize, uMACfragNum, byFBOption)); //0: 5GHz
pBuf->wTimeStampOff = cpu_to_le16(wTimeStampOff[pDevice->byPreambleType%2][wCurrentRate%MAX_RATE]);
return (pBuf->wDuration);
@@ -817,12 +806,12 @@ s_uFillDataHead (
PSTxDataHead_ab pBuf = (PSTxDataHead_ab)pTxDataHead;
//Get SignalField,ServiceField,Length
BBvCaculateParameter(pDevice, cbFrameLength, wCurrentRate, byPktType,
- (PWORD)&(wLen), (PBYTE)&(pBuf->byServiceField), (PBYTE)&(pBuf->bySignalField)
+ (unsigned short *)&(wLen), (unsigned char *)&(pBuf->byServiceField), (unsigned char *)&(pBuf->bySignalField)
);
pBuf->wTransmitLength = cpu_to_le16(wLen);
//Get Duration and TimeStampOff
- pBuf->wDuration = cpu_to_le16((WORD)s_uGetDataDuration(pDevice, DATADUR_A, cbFrameLength, byPktType,
+ pBuf->wDuration = cpu_to_le16((unsigned short)s_uGetDataDuration(pDevice, DATADUR_A, cbFrameLength, byPktType,
wCurrentRate, bNeedAck, uFragIdx,
cbLastFragmentSize, uMACfragNum,
byFBOption));
@@ -835,11 +824,11 @@ s_uFillDataHead (
PSTxDataHead_ab pBuf = (PSTxDataHead_ab)pTxDataHead;
//Get SignalField,ServiceField,Length
BBvCaculateParameter(pDevice, cbFrameLength, wCurrentRate, byPktType,
- (PWORD)&(wLen), (PBYTE)&(pBuf->byServiceField), (PBYTE)&(pBuf->bySignalField)
+ (unsigned short *)&(wLen), (unsigned char *)&(pBuf->byServiceField), (unsigned char *)&(pBuf->bySignalField)
);
pBuf->wTransmitLength = cpu_to_le16(wLen);
//Get Duration and TimeStampOff
- pBuf->wDuration = cpu_to_le16((WORD)s_uGetDataDuration(pDevice, DATADUR_B, cbFrameLength, byPktType,
+ pBuf->wDuration = cpu_to_le16((unsigned short)s_uGetDataDuration(pDevice, DATADUR_B, cbFrameLength, byPktType,
wCurrentRate, bNeedAck, uFragIdx,
cbLastFragmentSize, uMACfragNum,
byFBOption));
@@ -854,18 +843,18 @@ static
void
s_vFillRTSHead (
PSDevice pDevice,
- BYTE byPktType,
+ unsigned char byPktType,
void * pvRTS,
- UINT cbFrameLength,
- BOOL bNeedAck,
- BOOL bDisCRC,
+ unsigned int cbFrameLength,
+ bool bNeedAck,
+ bool bDisCRC,
PSEthernetHeader psEthHeader,
- WORD wCurrentRate,
- BYTE byFBOption
+ unsigned short wCurrentRate,
+ unsigned char byFBOption
)
{
- UINT uRTSFrameLen = 20;
- WORD wLen = 0x0000;
+ unsigned int uRTSFrameLen = 20;
+ unsigned short wLen = 0x0000;
if (pvRTS == NULL)
return;
@@ -883,17 +872,17 @@ s_vFillRTSHead (
PSRTS_g pBuf = (PSRTS_g)pvRTS;
//Get SignalField,ServiceField,Length
BBvCaculateParameter(pDevice, uRTSFrameLen, pDevice->byTopCCKBasicRate, PK_TYPE_11B,
- (PWORD)&(wLen), (PBYTE)&(pBuf->byServiceField_b), (PBYTE)&(pBuf->bySignalField_b)
+ (unsigned short *)&(wLen), (unsigned char *)&(pBuf->byServiceField_b), (unsigned char *)&(pBuf->bySignalField_b)
);
pBuf->wTransmitLength_b = cpu_to_le16(wLen);
BBvCaculateParameter(pDevice, uRTSFrameLen, pDevice->byTopOFDMBasicRate, byPktType,
- (PWORD)&(wLen), (PBYTE)&(pBuf->byServiceField_a), (PBYTE)&(pBuf->bySignalField_a)
+ (unsigned short *)&(wLen), (unsigned char *)&(pBuf->byServiceField_a), (unsigned char *)&(pBuf->bySignalField_a)
);
pBuf->wTransmitLength_a = cpu_to_le16(wLen);
//Get Duration
- pBuf->wDuration_bb = cpu_to_le16((WORD)s_uGetRTSCTSDuration(pDevice, RTSDUR_BB, cbFrameLength, PK_TYPE_11B, pDevice->byTopCCKBasicRate, bNeedAck, byFBOption)); //0:RTSDuration_bb, 1:2.4G, 1:CCKData
- pBuf->wDuration_aa = cpu_to_le16((WORD)s_uGetRTSCTSDuration(pDevice, RTSDUR_AA, cbFrameLength, byPktType, wCurrentRate, bNeedAck, byFBOption)); //2:RTSDuration_aa, 1:2.4G, 2,3: 2.4G OFDMData
- pBuf->wDuration_ba = cpu_to_le16((WORD)s_uGetRTSCTSDuration(pDevice, RTSDUR_BA, cbFrameLength, byPktType, wCurrentRate, bNeedAck, byFBOption)); //1:RTSDuration_ba, 1:2.4G, 2,3:2.4G OFDM Data
+ pBuf->wDuration_bb = cpu_to_le16((unsigned short)s_uGetRTSCTSDuration(pDevice, RTSDUR_BB, cbFrameLength, PK_TYPE_11B, pDevice->byTopCCKBasicRate, bNeedAck, byFBOption)); //0:RTSDuration_bb, 1:2.4G, 1:CCKData
+ pBuf->wDuration_aa = cpu_to_le16((unsigned short)s_uGetRTSCTSDuration(pDevice, RTSDUR_AA, cbFrameLength, byPktType, wCurrentRate, bNeedAck, byFBOption)); //2:RTSDuration_aa, 1:2.4G, 2,3: 2.4G OFDMData
+ pBuf->wDuration_ba = cpu_to_le16((unsigned short)s_uGetRTSCTSDuration(pDevice, RTSDUR_BA, cbFrameLength, byPktType, wCurrentRate, bNeedAck, byFBOption)); //1:RTSDuration_ba, 1:2.4G, 2,3:2.4G OFDM Data
pBuf->Data.wDurationID = pBuf->wDuration_aa;
//Get RTS Frame body
@@ -916,22 +905,22 @@ s_vFillRTSHead (
PSRTS_g_FB pBuf = (PSRTS_g_FB)pvRTS;
//Get SignalField,ServiceField,Length
BBvCaculateParameter(pDevice, uRTSFrameLen, pDevice->byTopCCKBasicRate, PK_TYPE_11B,
- (PWORD)&(wLen), (PBYTE)&(pBuf->byServiceField_b), (PBYTE)&(pBuf->bySignalField_b)
+ (unsigned short *)&(wLen), (unsigned char *)&(pBuf->byServiceField_b), (unsigned char *)&(pBuf->bySignalField_b)
);
pBuf->wTransmitLength_b = cpu_to_le16(wLen);
BBvCaculateParameter(pDevice, uRTSFrameLen, pDevice->byTopOFDMBasicRate, byPktType,
- (PWORD)&(wLen), (PBYTE)&(pBuf->byServiceField_a), (PBYTE)&(pBuf->bySignalField_a)
+ (unsigned short *)&(wLen), (unsigned char *)&(pBuf->byServiceField_a), (unsigned char *)&(pBuf->bySignalField_a)
);
pBuf->wTransmitLength_a = cpu_to_le16(wLen);
//Get Duration
- pBuf->wDuration_bb = cpu_to_le16((WORD)s_uGetRTSCTSDuration(pDevice, RTSDUR_BB, cbFrameLength, PK_TYPE_11B, pDevice->byTopCCKBasicRate, bNeedAck, byFBOption)); //0:RTSDuration_bb, 1:2.4G, 1:CCKData
- pBuf->wDuration_aa = cpu_to_le16((WORD)s_uGetRTSCTSDuration(pDevice, RTSDUR_AA, cbFrameLength, byPktType, wCurrentRate, bNeedAck, byFBOption)); //2:RTSDuration_aa, 1:2.4G, 2,3:2.4G OFDMData
- pBuf->wDuration_ba = cpu_to_le16((WORD)s_uGetRTSCTSDuration(pDevice, RTSDUR_BA, cbFrameLength, byPktType, wCurrentRate, bNeedAck, byFBOption)); //1:RTSDuration_ba, 1:2.4G, 2,3:2.4G OFDMData
- pBuf->wRTSDuration_ba_f0 = cpu_to_le16((WORD)s_uGetRTSCTSDuration(pDevice, RTSDUR_BA_F0, cbFrameLength, byPktType, wCurrentRate, bNeedAck, byFBOption)); //4:wRTSDuration_ba_f0, 1:2.4G, 1:CCKData
- pBuf->wRTSDuration_aa_f0 = cpu_to_le16((WORD)s_uGetRTSCTSDuration(pDevice, RTSDUR_AA_F0, cbFrameLength, byPktType, wCurrentRate, bNeedAck, byFBOption)); //5:wRTSDuration_aa_f0, 1:2.4G, 1:CCKData
- pBuf->wRTSDuration_ba_f1 = cpu_to_le16((WORD)s_uGetRTSCTSDuration(pDevice, RTSDUR_BA_F1, cbFrameLength, byPktType, wCurrentRate, bNeedAck, byFBOption)); //6:wRTSDuration_ba_f1, 1:2.4G, 1:CCKData
- pBuf->wRTSDuration_aa_f1 = cpu_to_le16((WORD)s_uGetRTSCTSDuration(pDevice, RTSDUR_AA_F1, cbFrameLength, byPktType, wCurrentRate, bNeedAck, byFBOption)); //7:wRTSDuration_aa_f1, 1:2.4G, 1:CCKData
+ pBuf->wDuration_bb = cpu_to_le16((unsigned short)s_uGetRTSCTSDuration(pDevice, RTSDUR_BB, cbFrameLength, PK_TYPE_11B, pDevice->byTopCCKBasicRate, bNeedAck, byFBOption)); //0:RTSDuration_bb, 1:2.4G, 1:CCKData
+ pBuf->wDuration_aa = cpu_to_le16((unsigned short)s_uGetRTSCTSDuration(pDevice, RTSDUR_AA, cbFrameLength, byPktType, wCurrentRate, bNeedAck, byFBOption)); //2:RTSDuration_aa, 1:2.4G, 2,3:2.4G OFDMData
+ pBuf->wDuration_ba = cpu_to_le16((unsigned short)s_uGetRTSCTSDuration(pDevice, RTSDUR_BA, cbFrameLength, byPktType, wCurrentRate, bNeedAck, byFBOption)); //1:RTSDuration_ba, 1:2.4G, 2,3:2.4G OFDMData
+ pBuf->wRTSDuration_ba_f0 = cpu_to_le16((unsigned short)s_uGetRTSCTSDuration(pDevice, RTSDUR_BA_F0, cbFrameLength, byPktType, wCurrentRate, bNeedAck, byFBOption)); //4:wRTSDuration_ba_f0, 1:2.4G, 1:CCKData
+ pBuf->wRTSDuration_aa_f0 = cpu_to_le16((unsigned short)s_uGetRTSCTSDuration(pDevice, RTSDUR_AA_F0, cbFrameLength, byPktType, wCurrentRate, bNeedAck, byFBOption)); //5:wRTSDuration_aa_f0, 1:2.4G, 1:CCKData
+ pBuf->wRTSDuration_ba_f1 = cpu_to_le16((unsigned short)s_uGetRTSCTSDuration(pDevice, RTSDUR_BA_F1, cbFrameLength, byPktType, wCurrentRate, bNeedAck, byFBOption)); //6:wRTSDuration_ba_f1, 1:2.4G, 1:CCKData
+ pBuf->wRTSDuration_aa_f1 = cpu_to_le16((unsigned short)s_uGetRTSCTSDuration(pDevice, RTSDUR_AA_F1, cbFrameLength, byPktType, wCurrentRate, bNeedAck, byFBOption)); //7:wRTSDuration_aa_f1, 1:2.4G, 1:CCKData
pBuf->Data.wDurationID = pBuf->wDuration_aa;
//Get RTS Frame body
pBuf->Data.wFrameControl = TYPE_CTL_RTS;//0x00B4
@@ -958,11 +947,11 @@ s_vFillRTSHead (
PSRTS_ab pBuf = (PSRTS_ab)pvRTS;
//Get SignalField,ServiceField,Length
BBvCaculateParameter(pDevice, uRTSFrameLen, pDevice->byTopOFDMBasicRate, byPktType,
- (PWORD)&(wLen), (PBYTE)&(pBuf->byServiceField), (PBYTE)&(pBuf->bySignalField)
+ (unsigned short *)&(wLen), (unsigned char *)&(pBuf->byServiceField), (unsigned char *)&(pBuf->bySignalField)
);
pBuf->wTransmitLength = cpu_to_le16(wLen);
//Get Duration
- pBuf->wDuration = cpu_to_le16((WORD)s_uGetRTSCTSDuration(pDevice, RTSDUR_AA, cbFrameLength, byPktType, wCurrentRate, bNeedAck, byFBOption)); //0:RTSDuration_aa, 0:5G, 0: 5G OFDMData
+ pBuf->wDuration = cpu_to_le16((unsigned short)s_uGetRTSCTSDuration(pDevice, RTSDUR_AA, cbFrameLength, byPktType, wCurrentRate, bNeedAck, byFBOption)); //0:RTSDuration_aa, 0:5G, 0: 5G OFDMData
pBuf->Data.wDurationID = pBuf->wDuration;
//Get RTS Frame body
pBuf->Data.wFrameControl = TYPE_CTL_RTS;//0x00B4
@@ -987,13 +976,13 @@ s_vFillRTSHead (
PSRTS_a_FB pBuf = (PSRTS_a_FB)pvRTS;
//Get SignalField,ServiceField,Length
BBvCaculateParameter(pDevice, uRTSFrameLen, pDevice->byTopOFDMBasicRate, byPktType,
- (PWORD)&(wLen), (PBYTE)&(pBuf->byServiceField), (PBYTE)&(pBuf->bySignalField)
+ (unsigned short *)&(wLen), (unsigned char *)&(pBuf->byServiceField), (unsigned char *)&(pBuf->bySignalField)
);
pBuf->wTransmitLength = cpu_to_le16(wLen);
//Get Duration
- pBuf->wDuration = cpu_to_le16((WORD)s_uGetRTSCTSDuration(pDevice, RTSDUR_AA, cbFrameLength, byPktType, wCurrentRate, bNeedAck, byFBOption)); //0:RTSDuration_aa, 0:5G, 0: 5G OFDMData
- pBuf->wRTSDuration_f0 = cpu_to_le16((WORD)s_uGetRTSCTSDuration(pDevice, RTSDUR_AA_F0, cbFrameLength, byPktType, wCurrentRate, bNeedAck, byFBOption)); //5:RTSDuration_aa_f0, 0:5G, 0: 5G OFDMData
- pBuf->wRTSDuration_f1 = cpu_to_le16((WORD)s_uGetRTSCTSDuration(pDevice, RTSDUR_AA_F1, cbFrameLength, byPktType, wCurrentRate, bNeedAck, byFBOption)); //7:RTSDuration_aa_f1, 0:5G, 0:
+ pBuf->wDuration = cpu_to_le16((unsigned short)s_uGetRTSCTSDuration(pDevice, RTSDUR_AA, cbFrameLength, byPktType, wCurrentRate, bNeedAck, byFBOption)); //0:RTSDuration_aa, 0:5G, 0: 5G OFDMData
+ pBuf->wRTSDuration_f0 = cpu_to_le16((unsigned short)s_uGetRTSCTSDuration(pDevice, RTSDUR_AA_F0, cbFrameLength, byPktType, wCurrentRate, bNeedAck, byFBOption)); //5:RTSDuration_aa_f0, 0:5G, 0: 5G OFDMData
+ pBuf->wRTSDuration_f1 = cpu_to_le16((unsigned short)s_uGetRTSCTSDuration(pDevice, RTSDUR_AA_F1, cbFrameLength, byPktType, wCurrentRate, bNeedAck, byFBOption)); //7:RTSDuration_aa_f1, 0:5G, 0:
pBuf->Data.wDurationID = pBuf->wDuration;
//Get RTS Frame body
pBuf->Data.wFrameControl = TYPE_CTL_RTS;//0x00B4
@@ -1017,11 +1006,11 @@ s_vFillRTSHead (
PSRTS_ab pBuf = (PSRTS_ab)pvRTS;
//Get SignalField,ServiceField,Length
BBvCaculateParameter(pDevice, uRTSFrameLen, pDevice->byTopCCKBasicRate, PK_TYPE_11B,
- (PWORD)&(wLen), (PBYTE)&(pBuf->byServiceField), (PBYTE)&(pBuf->bySignalField)
+ (unsigned short *)&(wLen), (unsigned char *)&(pBuf->byServiceField), (unsigned char *)&(pBuf->bySignalField)
);
pBuf->wTransmitLength = cpu_to_le16(wLen);
//Get Duration
- pBuf->wDuration = cpu_to_le16((WORD)s_uGetRTSCTSDuration(pDevice, RTSDUR_BB, cbFrameLength, byPktType, wCurrentRate, bNeedAck, byFBOption)); //0:RTSDuration_bb, 1:2.4G, 1:CCKData
+ pBuf->wDuration = cpu_to_le16((unsigned short)s_uGetRTSCTSDuration(pDevice, RTSDUR_BB, cbFrameLength, byPktType, wCurrentRate, bNeedAck, byFBOption)); //0:RTSDuration_bb, 1:2.4G, 1:CCKData
pBuf->Data.wDurationID = pBuf->wDuration;
//Get RTS Frame body
pBuf->Data.wFrameControl = TYPE_CTL_RTS;//0x00B4
@@ -1048,18 +1037,18 @@ static
void
s_vFillCTSHead (
PSDevice pDevice,
- UINT uDMAIdx,
- BYTE byPktType,
+ unsigned int uDMAIdx,
+ unsigned char byPktType,
void * pvCTS,
- UINT cbFrameLength,
- BOOL bNeedAck,
- BOOL bDisCRC,
- WORD wCurrentRate,
- BYTE byFBOption
+ unsigned int cbFrameLength,
+ bool bNeedAck,
+ bool bDisCRC,
+ unsigned short wCurrentRate,
+ unsigned char byFBOption
)
{
- UINT uCTSFrameLen = 14;
- WORD wLen = 0x0000;
+ unsigned int uCTSFrameLen = 14;
+ unsigned short wLen = 0x0000;
if (pvCTS == NULL) {
return;
@@ -1077,21 +1066,21 @@ s_vFillCTSHead (
PSCTS_FB pBuf = (PSCTS_FB)pvCTS;
//Get SignalField,ServiceField,Length
BBvCaculateParameter(pDevice, uCTSFrameLen, pDevice->byTopCCKBasicRate, PK_TYPE_11B,
- (PWORD)&(wLen), (PBYTE)&(pBuf->byServiceField_b), (PBYTE)&(pBuf->bySignalField_b)
+ (unsigned short *)&(wLen), (unsigned char *)&(pBuf->byServiceField_b), (unsigned char *)&(pBuf->bySignalField_b)
);
pBuf->wTransmitLength_b = cpu_to_le16(wLen);
- pBuf->wDuration_ba = (WORD)s_uGetRTSCTSDuration(pDevice, CTSDUR_BA, cbFrameLength, byPktType, wCurrentRate, bNeedAck, byFBOption); //3:CTSDuration_ba, 1:2.4G, 2,3:2.4G OFDM Data
+ pBuf->wDuration_ba = (unsigned short)s_uGetRTSCTSDuration(pDevice, CTSDUR_BA, cbFrameLength, byPktType, wCurrentRate, bNeedAck, byFBOption); //3:CTSDuration_ba, 1:2.4G, 2,3:2.4G OFDM Data
pBuf->wDuration_ba += pDevice->wCTSDuration;
pBuf->wDuration_ba = cpu_to_le16(pBuf->wDuration_ba);
//Get CTSDuration_ba_f0
- pBuf->wCTSDuration_ba_f0 = (WORD)s_uGetRTSCTSDuration(pDevice, CTSDUR_BA_F0, cbFrameLength, byPktType, wCurrentRate, bNeedAck, byFBOption); //8:CTSDuration_ba_f0, 1:2.4G, 2,3:2.4G OFDM Data
+ pBuf->wCTSDuration_ba_f0 = (unsigned short)s_uGetRTSCTSDuration(pDevice, CTSDUR_BA_F0, cbFrameLength, byPktType, wCurrentRate, bNeedAck, byFBOption); //8:CTSDuration_ba_f0, 1:2.4G, 2,3:2.4G OFDM Data
pBuf->wCTSDuration_ba_f0 += pDevice->wCTSDuration;
pBuf->wCTSDuration_ba_f0 = cpu_to_le16(pBuf->wCTSDuration_ba_f0);
//Get CTSDuration_ba_f1
- pBuf->wCTSDuration_ba_f1 = (WORD)s_uGetRTSCTSDuration(pDevice, CTSDUR_BA_F1, cbFrameLength, byPktType, wCurrentRate, bNeedAck, byFBOption); //9:CTSDuration_ba_f1, 1:2.4G, 2,3:2.4G OFDM Data
+ pBuf->wCTSDuration_ba_f1 = (unsigned short)s_uGetRTSCTSDuration(pDevice, CTSDUR_BA_F1, cbFrameLength, byPktType, wCurrentRate, bNeedAck, byFBOption); //9:CTSDuration_ba_f1, 1:2.4G, 2,3:2.4G OFDM Data
pBuf->wCTSDuration_ba_f1 += pDevice->wCTSDuration;
pBuf->wCTSDuration_ba_f1 = cpu_to_le16(pBuf->wCTSDuration_ba_f1);
//Get CTS Frame body
@@ -1104,11 +1093,11 @@ s_vFillCTSHead (
PSCTS pBuf = (PSCTS)pvCTS;
//Get SignalField,ServiceField,Length
BBvCaculateParameter(pDevice, uCTSFrameLen, pDevice->byTopCCKBasicRate, PK_TYPE_11B,
- (PWORD)&(wLen), (PBYTE)&(pBuf->byServiceField_b), (PBYTE)&(pBuf->bySignalField_b)
+ (unsigned short *)&(wLen), (unsigned char *)&(pBuf->byServiceField_b), (unsigned char *)&(pBuf->bySignalField_b)
);
pBuf->wTransmitLength_b = cpu_to_le16(wLen);
//Get CTSDuration_ba
- pBuf->wDuration_ba = cpu_to_le16((WORD)s_uGetRTSCTSDuration(pDevice, CTSDUR_BA, cbFrameLength, byPktType, wCurrentRate, bNeedAck, byFBOption)); //3:CTSDuration_ba, 1:2.4G, 2,3:2.4G OFDM Data
+ pBuf->wDuration_ba = cpu_to_le16((unsigned short)s_uGetRTSCTSDuration(pDevice, CTSDUR_BA, cbFrameLength, byPktType, wCurrentRate, bNeedAck, byFBOption)); //3:CTSDuration_ba, 1:2.4G, 2,3:2.4G OFDM Data
pBuf->wDuration_ba += pDevice->wCTSDuration;
pBuf->wDuration_ba = cpu_to_le16(pBuf->wDuration_ba);
@@ -1148,28 +1137,28 @@ s_vFillCTSHead (
* Return Value: none
*
-*/
-// UINT cbFrameSize,//Hdr+Payload+FCS
+// unsigned int cbFrameSize,//Hdr+Payload+FCS
static
void
s_vGenerateTxParameter (
PSDevice pDevice,
- BYTE byPktType,
+ unsigned char byPktType,
void * pTxBufHead,
void * pvRrvTime,
void * pvRTS,
void * pvCTS,
- UINT cbFrameSize,
- BOOL bNeedACK,
- UINT uDMAIdx,
+ unsigned int cbFrameSize,
+ bool bNeedACK,
+ unsigned int uDMAIdx,
PSEthernetHeader psEthHeader,
- WORD wCurrentRate
+ unsigned short wCurrentRate
)
{
- UINT cbMACHdLen = WLAN_HDR_ADDR3_LEN; //24
- WORD wFifoCtl;
- BOOL bDisCRC = FALSE;
- BYTE byFBOption = AUTO_FB_NONE;
-// WORD wCurrentRate = pDevice->wCurrentRate;
+ unsigned int cbMACHdLen = WLAN_HDR_ADDR3_LEN; //24
+ unsigned short wFifoCtl;
+ bool bDisCRC = false;
+ unsigned char byFBOption = AUTO_FB_NONE;
+// unsigned short wCurrentRate = pDevice->wCurrentRate;
//DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"s_vGenerateTxParameter...\n");
PSTxBufHead pFifoHead = (PSTxBufHead)pTxBufHead;
@@ -1177,7 +1166,7 @@ s_vGenerateTxParameter (
wFifoCtl = pFifoHead->wFIFOCtl;
if (wFifoCtl & FIFOCTL_CRCDIS) {
- bDisCRC = TRUE;
+ bDisCRC = true;
}
if (wFifoCtl & FIFOCTL_AUTO_FB_0) {
@@ -1196,11 +1185,11 @@ s_vGenerateTxParameter (
//Fill RsvTime
if (pvRrvTime) {
PSRrvTime_gRTS pBuf = (PSRrvTime_gRTS)pvRrvTime;
- pBuf->wRTSTxRrvTime_aa = cpu_to_le16((WORD)s_uGetRTSCTSRsvTime(pDevice, 2, byPktType, cbFrameSize, wCurrentRate));//2:RTSTxRrvTime_aa, 1:2.4GHz
- pBuf->wRTSTxRrvTime_ba = cpu_to_le16((WORD)s_uGetRTSCTSRsvTime(pDevice, 1, byPktType, cbFrameSize, wCurrentRate));//1:RTSTxRrvTime_ba, 1:2.4GHz
- pBuf->wRTSTxRrvTime_bb = cpu_to_le16((WORD)s_uGetRTSCTSRsvTime(pDevice, 0, byPktType, cbFrameSize, wCurrentRate));//0:RTSTxRrvTime_bb, 1:2.4GHz
- pBuf->wTxRrvTime_a = cpu_to_le16((WORD) s_uGetTxRsvTime(pDevice, byPktType, cbFrameSize, wCurrentRate, bNeedACK));//2.4G OFDM
- pBuf->wTxRrvTime_b = cpu_to_le16((WORD) s_uGetTxRsvTime(pDevice, PK_TYPE_11B, cbFrameSize, pDevice->byTopCCKBasicRate, bNeedACK));//1:CCK
+ pBuf->wRTSTxRrvTime_aa = cpu_to_le16((unsigned short)s_uGetRTSCTSRsvTime(pDevice, 2, byPktType, cbFrameSize, wCurrentRate));//2:RTSTxRrvTime_aa, 1:2.4GHz
+ pBuf->wRTSTxRrvTime_ba = cpu_to_le16((unsigned short)s_uGetRTSCTSRsvTime(pDevice, 1, byPktType, cbFrameSize, wCurrentRate));//1:RTSTxRrvTime_ba, 1:2.4GHz
+ pBuf->wRTSTxRrvTime_bb = cpu_to_le16((unsigned short)s_uGetRTSCTSRsvTime(pDevice, 0, byPktType, cbFrameSize, wCurrentRate));//0:RTSTxRrvTime_bb, 1:2.4GHz
+ pBuf->wTxRrvTime_a = cpu_to_le16((unsigned short) s_uGetTxRsvTime(pDevice, byPktType, cbFrameSize, wCurrentRate, bNeedACK));//2.4G OFDM
+ pBuf->wTxRrvTime_b = cpu_to_le16((unsigned short) s_uGetTxRsvTime(pDevice, PK_TYPE_11B, cbFrameSize, pDevice->byTopCCKBasicRate, bNeedACK));//1:CCK
}
//Fill RTS
s_vFillRTSHead(pDevice, byPktType, pvRTS, cbFrameSize, bNeedACK, bDisCRC, psEthHeader, wCurrentRate, byFBOption);
@@ -1210,9 +1199,9 @@ s_vGenerateTxParameter (
//Fill RsvTime
if (pvRrvTime) {
PSRrvTime_gCTS pBuf = (PSRrvTime_gCTS)pvRrvTime;
- pBuf->wTxRrvTime_a = cpu_to_le16((WORD)s_uGetTxRsvTime(pDevice, byPktType, cbFrameSize, wCurrentRate, bNeedACK));//2.4G OFDM
- pBuf->wTxRrvTime_b = cpu_to_le16((WORD)s_uGetTxRsvTime(pDevice, PK_TYPE_11B, cbFrameSize, pDevice->byTopCCKBasicRate, bNeedACK));//1:CCK
- pBuf->wCTSTxRrvTime_ba = cpu_to_le16((WORD)s_uGetRTSCTSRsvTime(pDevice, 3, byPktType, cbFrameSize, wCurrentRate));//3:CTSTxRrvTime_Ba, 1:2.4GHz
+ pBuf->wTxRrvTime_a = cpu_to_le16((unsigned short)s_uGetTxRsvTime(pDevice, byPktType, cbFrameSize, wCurrentRate, bNeedACK));//2.4G OFDM
+ pBuf->wTxRrvTime_b = cpu_to_le16((unsigned short)s_uGetTxRsvTime(pDevice, PK_TYPE_11B, cbFrameSize, pDevice->byTopCCKBasicRate, bNeedACK));//1:CCK
+ pBuf->wCTSTxRrvTime_ba = cpu_to_le16((unsigned short)s_uGetRTSCTSRsvTime(pDevice, 3, byPktType, cbFrameSize, wCurrentRate));//3:CTSTxRrvTime_Ba, 1:2.4GHz
}
@@ -1226,8 +1215,8 @@ s_vGenerateTxParameter (
//Fill RsvTime
if (pvRrvTime) {
PSRrvTime_ab pBuf = (PSRrvTime_ab)pvRrvTime;
- pBuf->wRTSTxRrvTime = cpu_to_le16((WORD)s_uGetRTSCTSRsvTime(pDevice, 2, byPktType, cbFrameSize, wCurrentRate));//2:RTSTxRrvTime_aa, 0:5GHz
- pBuf->wTxRrvTime = cpu_to_le16((WORD)s_uGetTxRsvTime(pDevice, byPktType, cbFrameSize, wCurrentRate, bNeedACK));//0:OFDM
+ pBuf->wRTSTxRrvTime = cpu_to_le16((unsigned short)s_uGetRTSCTSRsvTime(pDevice, 2, byPktType, cbFrameSize, wCurrentRate));//2:RTSTxRrvTime_aa, 0:5GHz
+ pBuf->wTxRrvTime = cpu_to_le16((unsigned short)s_uGetTxRsvTime(pDevice, byPktType, cbFrameSize, wCurrentRate, bNeedACK));//0:OFDM
}
//Fill RTS
s_vFillRTSHead(pDevice, byPktType, pvRTS, cbFrameSize, bNeedACK, bDisCRC, psEthHeader, wCurrentRate, byFBOption);
@@ -1236,7 +1225,7 @@ s_vGenerateTxParameter (
//Fill RsvTime
if (pvRrvTime) {
PSRrvTime_ab pBuf = (PSRrvTime_ab)pvRrvTime;
- pBuf->wTxRrvTime = cpu_to_le16((WORD)s_uGetTxRsvTime(pDevice, PK_TYPE_11A, cbFrameSize, wCurrentRate, bNeedACK)); //0:OFDM
+ pBuf->wTxRrvTime = cpu_to_le16((unsigned short)s_uGetTxRsvTime(pDevice, PK_TYPE_11A, cbFrameSize, wCurrentRate, bNeedACK)); //0:OFDM
}
}
}
@@ -1246,8 +1235,8 @@ s_vGenerateTxParameter (
//Fill RsvTime
if (pvRrvTime) {
PSRrvTime_ab pBuf = (PSRrvTime_ab)pvRrvTime;
- pBuf->wRTSTxRrvTime = cpu_to_le16((WORD)s_uGetRTSCTSRsvTime(pDevice, 0, byPktType, cbFrameSize, wCurrentRate));//0:RTSTxRrvTime_bb, 1:2.4GHz
- pBuf->wTxRrvTime = cpu_to_le16((WORD)s_uGetTxRsvTime(pDevice, PK_TYPE_11B, cbFrameSize, wCurrentRate, bNeedACK));//1:CCK
+ pBuf->wRTSTxRrvTime = cpu_to_le16((unsigned short)s_uGetRTSCTSRsvTime(pDevice, 0, byPktType, cbFrameSize, wCurrentRate));//0:RTSTxRrvTime_bb, 1:2.4GHz
+ pBuf->wTxRrvTime = cpu_to_le16((unsigned short)s_uGetTxRsvTime(pDevice, PK_TYPE_11B, cbFrameSize, wCurrentRate, bNeedACK));//1:CCK
}
//Fill RTS
s_vFillRTSHead(pDevice, byPktType, pvRTS, cbFrameSize, bNeedACK, bDisCRC, psEthHeader, wCurrentRate, byFBOption);
@@ -1256,26 +1245,26 @@ s_vGenerateTxParameter (
//Fill RsvTime
if (pvRrvTime) {
PSRrvTime_ab pBuf = (PSRrvTime_ab)pvRrvTime;
- pBuf->wTxRrvTime = cpu_to_le16((WORD)s_uGetTxRsvTime(pDevice, PK_TYPE_11B, cbFrameSize, wCurrentRate, bNeedACK)); //1:CCK
+ pBuf->wTxRrvTime = cpu_to_le16((unsigned short)s_uGetTxRsvTime(pDevice, PK_TYPE_11B, cbFrameSize, wCurrentRate, bNeedACK)); //1:CCK
}
}
}
//DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"s_vGenerateTxParameter END.\n");
}
/*
- PBYTE pbyBuffer,//point to pTxBufHead
- WORD wFragType,//00:Non-Frag, 01:Start, 02:Mid, 03:Last
- UINT cbFragmentSize,//Hdr+payoad+FCS
+ unsigned char *pbyBuffer,//point to pTxBufHead
+ unsigned short wFragType,//00:Non-Frag, 01:Start, 02:Mid, 03:Last
+ unsigned int cbFragmentSize,//Hdr+payoad+FCS
*/
static
void
s_vFillFragParameter(
PSDevice pDevice,
- PBYTE pbyBuffer,
- UINT uTxType,
+ unsigned char *pbyBuffer,
+ unsigned int uTxType,
void * pvtdCurr,
- WORD wFragType,
- UINT cbReqCount
+ unsigned short wFragType,
+ unsigned int cbReqCount
)
{
PSTxBufHead pTxBufHead = (PSTxBufHead) pbyBuffer;
@@ -1289,7 +1278,7 @@ s_vFillFragParameter(
ptdCurr->m_wFIFOCtl = pTxBufHead->wFIFOCtl;
ptdCurr->m_wTimeStamp = pTxBufHead->wTimeStamp;
//Set TSR1 & ReqCount in TxDescHead
- ptdCurr->m_td1TD1.wReqCount = cpu_to_le16((WORD)(cbReqCount));
+ ptdCurr->m_td1TD1.wReqCount = cpu_to_le16((unsigned short)(cbReqCount));
if (wFragType == FRAGCTL_ENDFRAG) { //Last Fragmentation
ptdCurr->m_td1TD1.byTCR |= (TCR_STP | TCR_EDP | EDMSDU);
}
@@ -1301,7 +1290,7 @@ s_vFillFragParameter(
//PSTxDesc ptdCurr = (PSTxDesc)s_pvGetTxDescHead(pDevice, uTxType, uCurIdx);
PSTxDesc ptdCurr = (PSTxDesc)pvtdCurr;
//Set TSR1 & ReqCount in TxDescHead
- ptdCurr->m_td1TD1.wReqCount = cpu_to_le16((WORD)(cbReqCount));
+ ptdCurr->m_td1TD1.wReqCount = cpu_to_le16((unsigned short)(cbReqCount));
if (wFragType == FRAGCTL_ENDFRAG) { //Last Fragmentation
ptdCurr->m_td1TD1.byTCR |= (TCR_STP | TCR_EDP | EDMSDU);
}
@@ -1310,81 +1299,70 @@ s_vFillFragParameter(
}
}
- pTxBufHead->wFragCtl |= (WORD)wFragType;//0x0001; //0000 0000 0000 0001
+ pTxBufHead->wFragCtl |= (unsigned short)wFragType;//0x0001; //0000 0000 0000 0001
//DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"s_vFillFragParameter END\n");
}
-static
-UINT
-s_cbFillTxBufHead (
- PSDevice pDevice,
- BYTE byPktType,
- PBYTE pbyTxBufferAddr,
- UINT cbFrameBodySize,
- UINT uDMAIdx,
- PSTxDesc pHeadTD,
- PSEthernetHeader psEthHeader,
- PBYTE pPacket,
- BOOL bNeedEncrypt,
- PSKeyItem pTransmitKey,
- UINT uNodeIndex,
- PUINT puMACfragNum
- )
+static unsigned int
+s_cbFillTxBufHead(PSDevice pDevice, unsigned char byPktType, unsigned char *pbyTxBufferAddr,
+ unsigned int cbFrameBodySize, unsigned int uDMAIdx, PSTxDesc pHeadTD,
+ PSEthernetHeader psEthHeader, unsigned char *pPacket, bool bNeedEncrypt,
+ PSKeyItem pTransmitKey, unsigned int uNodeIndex, unsigned int *puMACfragNum)
{
- UINT cbMACHdLen;
- UINT cbFrameSize;
- UINT cbFragmentSize; //Hdr+(IV)+payoad+(MIC)+(ICV)+FCS
- UINT cbFragPayloadSize;
- UINT cbLastFragmentSize; //Hdr+(IV)+payoad+(MIC)+(ICV)+FCS
- UINT cbLastFragPayloadSize;
- UINT uFragIdx;
- PBYTE pbyPayloadHead;
- PBYTE pbyIVHead;
- PBYTE pbyMacHdr;
- WORD wFragType; //00:Non-Frag, 01:Start, 10:Mid, 11:Last
- UINT uDuration;
- PBYTE pbyBuffer;
-// UINT uKeyEntryIdx = NUM_KEY_ENTRY+1;
-// BYTE byKeySel = 0xFF;
- UINT cbIVlen = 0;
- UINT cbICVlen = 0;
- UINT cbMIClen = 0;
- UINT cbFCSlen = 4;
- UINT cb802_1_H_len = 0;
- UINT uLength = 0;
- UINT uTmpLen = 0;
-// BYTE abyTmp[8];
-// DWORD dwCRC;
- UINT cbMICHDR = 0;
- DWORD dwMICKey0, dwMICKey1;
- DWORD dwMIC_Priority;
- PDWORD pdwMIC_L;
- PDWORD pdwMIC_R;
- DWORD dwSafeMIC_L, dwSafeMIC_R; //Fix "Last Frag Size" < "MIC length".
- BOOL bMIC2Frag = FALSE;
- UINT uMICFragLen = 0;
- UINT uMACfragNum = 1;
- UINT uPadding = 0;
- UINT cbReqCount = 0;
-
- BOOL bNeedACK;
- BOOL bRTS;
- BOOL bIsAdhoc;
- PBYTE pbyType;
+ unsigned int cbMACHdLen;
+ unsigned int cbFrameSize;
+ unsigned int cbFragmentSize; //Hdr+(IV)+payoad+(MIC)+(ICV)+FCS
+ unsigned int cbFragPayloadSize;
+ unsigned int cbLastFragmentSize; //Hdr+(IV)+payoad+(MIC)+(ICV)+FCS
+ unsigned int cbLastFragPayloadSize;
+ unsigned int uFragIdx;
+ unsigned char *pbyPayloadHead;
+ unsigned char *pbyIVHead;
+ unsigned char *pbyMacHdr;
+ unsigned short wFragType; //00:Non-Frag, 01:Start, 10:Mid, 11:Last
+ unsigned int uDuration;
+ unsigned char *pbyBuffer;
+// unsigned int uKeyEntryIdx = NUM_KEY_ENTRY+1;
+// unsigned char byKeySel = 0xFF;
+ unsigned int cbIVlen = 0;
+ unsigned int cbICVlen = 0;
+ unsigned int cbMIClen = 0;
+ unsigned int cbFCSlen = 4;
+ unsigned int cb802_1_H_len = 0;
+ unsigned int uLength = 0;
+ unsigned int uTmpLen = 0;
+// unsigned char abyTmp[8];
+// unsigned long dwCRC;
+ unsigned int cbMICHDR = 0;
+ unsigned long dwMICKey0, dwMICKey1;
+ unsigned long dwMIC_Priority;
+ unsigned long *pdwMIC_L;
+ unsigned long *pdwMIC_R;
+ unsigned long dwSafeMIC_L, dwSafeMIC_R; //Fix "Last Frag Size" < "MIC length".
+ bool bMIC2Frag = false;
+ unsigned int uMICFragLen = 0;
+ unsigned int uMACfragNum = 1;
+ unsigned int uPadding = 0;
+ unsigned int cbReqCount = 0;
+
+ bool bNeedACK;
+ bool bRTS;
+ bool bIsAdhoc;
+ unsigned char *pbyType;
PSTxDesc ptdCurr;
PSTxBufHead psTxBufHd = (PSTxBufHead) pbyTxBufferAddr;
-// UINT tmpDescIdx;
- UINT cbHeaderLength = 0;
+// unsigned int tmpDescIdx;
+ unsigned int cbHeaderLength = 0;
void * pvRrvTime;
PSMICHDRHead pMICHDR;
void * pvRTS;
void * pvCTS;
void * pvTxDataHd;
- WORD wTxBufSize; // FFinfo size
- UINT uTotalCopyLength = 0;
- BYTE byFBOption = AUTO_FB_NONE;
- BOOL bIsWEP256 = FALSE;
+ unsigned short wTxBufSize; // FFinfo size
+ unsigned int uTotalCopyLength = 0;
+ unsigned char byFBOption = AUTO_FB_NONE;
+ bool bIsWEP256 = false;
PSMgmtObject pMgmt = pDevice->pMgmt;
@@ -1394,19 +1372,16 @@ s_cbFillTxBufHead (
if ((pDevice->eOPMode == OP_MODE_ADHOC) ||
(pDevice->eOPMode == OP_MODE_AP)) {
- if (IS_MULTICAST_ADDRESS(&(psEthHeader->abyDstAddr[0])) ||
- IS_BROADCAST_ADDRESS(&(psEthHeader->abyDstAddr[0]))) {
- bNeedACK = FALSE;
- }
- else {
- bNeedACK = TRUE;
- }
- bIsAdhoc = TRUE;
+ if (is_multicast_ether_addr(&(psEthHeader->abyDstAddr[0])))
+ bNeedACK = false;
+ else
+ bNeedACK = true;
+ bIsAdhoc = true;
}
else {
// MSDUs in Infra mode always need ACK
- bNeedACK = TRUE;
- bIsAdhoc = FALSE;
+ bNeedACK = true;
+ bIsAdhoc = false;
}
if (pDevice->bLongHeader)
@@ -1415,12 +1390,12 @@ s_cbFillTxBufHead (
cbMACHdLen = WLAN_HDR_ADDR3_LEN;
- if ((bNeedEncrypt == TRUE) && (pTransmitKey != NULL)) {
+ if ((bNeedEncrypt == true) && (pTransmitKey != NULL)) {
if (pTransmitKey->byCipherSuite == KEY_CTL_WEP) {
cbIVlen = 4;
cbICVlen = 4;
if (pTransmitKey->uKeyLength == WLAN_WEP232_KEYLEN) {
- bIsWEP256 = TRUE;
+ bIsWEP256 = true;
}
}
if (pTransmitKey->byCipherSuite == KEY_CTL_TKIP) {
@@ -1443,14 +1418,14 @@ s_cbFillTxBufHead (
cbFrameSize = cbMACHdLen + cbIVlen + (cbFrameBodySize + cbMIClen) + cbICVlen + cbFCSlen;
- if ((bNeedACK == FALSE) ||
+ if ((bNeedACK == false) ||
(cbFrameSize < pDevice->wRTSThreshold) ||
((cbFrameSize >= pDevice->wFragmentationThreshold) && (pDevice->wFragmentationThreshold <= pDevice->wRTSThreshold))
) {
- bRTS = FALSE;
+ bRTS = false;
}
else {
- bRTS = TRUE;
+ bRTS = true;
psTxBufHd->wFIFOCtl |= (FIFOCTL_RTS | FIFOCTL_LRETRY);
}
//
@@ -1469,7 +1444,7 @@ s_cbFillTxBufHead (
if (byPktType == PK_TYPE_11GB || byPktType == PK_TYPE_11GA) {//802.11g packet
if (byFBOption == AUTO_FB_NONE) {
- if (bRTS == TRUE) {//RTS_need
+ if (bRTS == true) {//RTS_need
pvRrvTime = (PSRrvTime_gRTS) (pbyTxBufferAddr + wTxBufSize);
pMICHDR = (PSMICHDRHead) (pbyTxBufferAddr + wTxBufSize + sizeof(SRrvTime_gRTS));
pvRTS = (PSRTS_g) (pbyTxBufferAddr + wTxBufSize + sizeof(SRrvTime_gRTS) + cbMICHDR);
@@ -1487,7 +1462,7 @@ s_cbFillTxBufHead (
}
} else {
// Auto Fall Back
- if (bRTS == TRUE) {//RTS_need
+ if (bRTS == true) {//RTS_need
pvRrvTime = (PSRrvTime_gRTS) (pbyTxBufferAddr + wTxBufSize);
pMICHDR = (PSMICHDRHead) (pbyTxBufferAddr + wTxBufSize + sizeof(SRrvTime_gRTS));
pvRTS = (PSRTS_g_FB) (pbyTxBufferAddr + wTxBufSize + sizeof(SRrvTime_gRTS) + cbMICHDR);
@@ -1508,7 +1483,7 @@ s_cbFillTxBufHead (
else {//802.11a/b packet
if (byFBOption == AUTO_FB_NONE) {
- if (bRTS == TRUE) {
+ if (bRTS == true) {
pvRrvTime = (PSRrvTime_ab) (pbyTxBufferAddr + wTxBufSize);
pMICHDR = (PSMICHDRHead) (pbyTxBufferAddr + wTxBufSize + sizeof(SRrvTime_ab));
pvRTS = (PSRTS_ab) (pbyTxBufferAddr + wTxBufSize + sizeof(SRrvTime_ab) + cbMICHDR);
@@ -1526,7 +1501,7 @@ s_cbFillTxBufHead (
}
} else {
// Auto Fall Back
- if (bRTS == TRUE) {//RTS_need
+ if (bRTS == true) {//RTS_need
pvRrvTime = (PSRrvTime_ab) (pbyTxBufferAddr + wTxBufSize);
pMICHDR = (PSMICHDRHead) (pbyTxBufferAddr + wTxBufSize + sizeof(SRrvTime_ab));
pvRTS = (PSRTS_a_FB) (pbyTxBufferAddr + wTxBufSize + sizeof(SRrvTime_ab) + cbMICHDR);
@@ -1547,40 +1522,40 @@ s_cbFillTxBufHead (
memset((void *)(pbyTxBufferAddr + wTxBufSize), 0, (cbHeaderLength - wTxBufSize));
//////////////////////////////////////////////////////////////////
- if ((bNeedEncrypt == TRUE) && (pTransmitKey != NULL) && (pTransmitKey->byCipherSuite == KEY_CTL_TKIP)) {
+ if ((bNeedEncrypt == true) && (pTransmitKey != NULL) && (pTransmitKey->byCipherSuite == KEY_CTL_TKIP)) {
if (pDevice->pMgmt->eAuthenMode == WMAC_AUTH_WPANONE) {
- dwMICKey0 = *(PDWORD)(&pTransmitKey->abyKey[16]);
- dwMICKey1 = *(PDWORD)(&pTransmitKey->abyKey[20]);
+ dwMICKey0 = *(unsigned long *)(&pTransmitKey->abyKey[16]);
+ dwMICKey1 = *(unsigned long *)(&pTransmitKey->abyKey[20]);
}
else if ((pTransmitKey->dwKeyIndex & AUTHENTICATOR_KEY) != 0) {
- dwMICKey0 = *(PDWORD)(&pTransmitKey->abyKey[16]);
- dwMICKey1 = *(PDWORD)(&pTransmitKey->abyKey[20]);
+ dwMICKey0 = *(unsigned long *)(&pTransmitKey->abyKey[16]);
+ dwMICKey1 = *(unsigned long *)(&pTransmitKey->abyKey[20]);
}
else {
- dwMICKey0 = *(PDWORD)(&pTransmitKey->abyKey[24]);
- dwMICKey1 = *(PDWORD)(&pTransmitKey->abyKey[28]);
+ dwMICKey0 = *(unsigned long *)(&pTransmitKey->abyKey[24]);
+ dwMICKey1 = *(unsigned long *)(&pTransmitKey->abyKey[28]);
}
// DO Software Michael
MIC_vInit(dwMICKey0, dwMICKey1);
- MIC_vAppend((PBYTE)&(psEthHeader->abyDstAddr[0]), 12);
+ MIC_vAppend((unsigned char *)&(psEthHeader->abyDstAddr[0]), 12);
dwMIC_Priority = 0;
- MIC_vAppend((PBYTE)&dwMIC_Priority, 4);
+ MIC_vAppend((unsigned char *)&dwMIC_Priority, 4);
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"MIC KEY: %lX, %lX\n", dwMICKey0, dwMICKey1);
}
///////////////////////////////////////////////////////////////////
- pbyMacHdr = (PBYTE)(pbyTxBufferAddr + cbHeaderLength);
- pbyPayloadHead = (PBYTE)(pbyMacHdr + cbMACHdLen + uPadding + cbIVlen);
- pbyIVHead = (PBYTE)(pbyMacHdr + cbMACHdLen + uPadding);
+ pbyMacHdr = (unsigned char *)(pbyTxBufferAddr + cbHeaderLength);
+ pbyPayloadHead = (unsigned char *)(pbyMacHdr + cbMACHdLen + uPadding + cbIVlen);
+ pbyIVHead = (unsigned char *)(pbyMacHdr + cbMACHdLen + uPadding);
- if ((cbFrameSize > pDevice->wFragmentationThreshold) && (bNeedACK == TRUE) && (bIsWEP256 == FALSE)) {
+ if ((cbFrameSize > pDevice->wFragmentationThreshold) && (bNeedACK == true) && (bIsWEP256 == false)) {
// Fragmentation
// FragThreshold = Fragment size(Hdr+(IV)+fragment payload+(MIC)+(ICV)+FCS)
cbFragmentSize = pDevice->wFragmentationThreshold;
cbFragPayloadSize = cbFragmentSize - cbMACHdLen - cbIVlen - cbICVlen - cbFCSlen;
//FragNum = (FrameSize-(Hdr+FCS))/(Fragment Size -(Hrd+FCS)))
- uMACfragNum = (WORD) ((cbFrameBodySize + cbMIClen) / cbFragPayloadSize);
+ uMACfragNum = (unsigned short) ((cbFrameBodySize + cbMIClen) / cbFragPayloadSize);
cbLastFragPayloadSize = (cbFrameBodySize + cbMIClen) % cbFragPayloadSize;
if (cbLastFragPayloadSize == 0) {
cbLastFragPayloadSize = cbFragPayloadSize;
@@ -1606,13 +1581,13 @@ s_cbFillTxBufHead (
uDuration = s_uFillDataHead(pDevice, byPktType, pvTxDataHd, cbFragmentSize, uDMAIdx, bNeedACK,
uFragIdx, cbLastFragmentSize, uMACfragNum, byFBOption, pDevice->wCurrentRate);
// Generate TX MAC Header
- vGenerateMACHeader(pDevice, pbyMacHdr, (WORD)uDuration, psEthHeader, bNeedEncrypt,
+ vGenerateMACHeader(pDevice, pbyMacHdr, (unsigned short)uDuration, psEthHeader, bNeedEncrypt,
wFragType, uDMAIdx, uFragIdx);
- if (bNeedEncrypt == TRUE) {
+ if (bNeedEncrypt == true) {
//Fill TXKEY
- s_vFillTxKey(pDevice, (PBYTE)(psTxBufHd->adwTxKey), pbyIVHead, pTransmitKey,
- pbyMacHdr, (WORD)cbFragPayloadSize, (PBYTE)pMICHDR);
+ s_vFillTxKey(pDevice, (unsigned char *)(psTxBufHd->adwTxKey), pbyIVHead, pTransmitKey,
+ pbyMacHdr, (unsigned short)cbFragPayloadSize, (unsigned char *)pMICHDR);
//Fill IV(ExtIV,RSNHDR)
if (pDevice->bEnableHostWEP) {
pMgmt->sNodeDBTable[uNodeIndex].dwTSC47_16 = pTransmitKey->dwTSC47_16;
@@ -1625,13 +1600,13 @@ s_cbFillTxBufHead (
if (ntohs(psEthHeader->wType) > ETH_DATA_LEN) {
if ((psEthHeader->wType == TYPE_PKT_IPX) ||
(psEthHeader->wType == cpu_to_le16(0xF380))) {
- memcpy((PBYTE) (pbyPayloadHead), &pDevice->abySNAP_Bridgetunnel[0], 6);
+ memcpy((unsigned char *) (pbyPayloadHead), &pDevice->abySNAP_Bridgetunnel[0], 6);
}
else {
- memcpy((PBYTE) (pbyPayloadHead), &pDevice->abySNAP_RFC1042[0], 6);
+ memcpy((unsigned char *) (pbyPayloadHead), &pDevice->abySNAP_RFC1042[0], 6);
}
- pbyType = (PBYTE) (pbyPayloadHead + 6);
- memcpy(pbyType, &(psEthHeader->wType), sizeof(WORD));
+ pbyType = (unsigned char *) (pbyPayloadHead + 6);
+ memcpy(pbyType, &(psEthHeader->wType), sizeof(unsigned short));
cb802_1_H_len = 8;
}
@@ -1641,15 +1616,15 @@ s_cbFillTxBufHead (
//---------------------------
//Fill MICHDR
//if (pDevice->bAES) {
- // s_vFillMICHDR(pDevice, (PBYTE)pMICHDR, pbyMacHdr, (WORD)cbFragPayloadSize);
+ // s_vFillMICHDR(pDevice, (unsigned char *)pMICHDR, pbyMacHdr, (unsigned short)cbFragPayloadSize);
//}
//cbReqCount += s_uDoEncryption(pDevice, psEthHeader, (void *)psTxBufHd, byKeySel,
- // pbyPayloadHead, (WORD)cbFragPayloadSize, uDMAIdx);
+ // pbyPayloadHead, (unsigned short)cbFragPayloadSize, uDMAIdx);
- //pbyBuffer = (PBYTE)pDevice->aamTxBuf[uDMAIdx][uDescIdx].pbyVAddr;
- pbyBuffer = (PBYTE)pHeadTD->pTDInfo->buf;
+ //pbyBuffer = (unsigned char *)pDevice->aamTxBuf[uDMAIdx][uDescIdx].pbyVAddr;
+ pbyBuffer = (unsigned char *)pHeadTD->pTDInfo->buf;
uLength = cbHeaderLength + cbMACHdLen + uPadding + cbIVlen + cb802_1_H_len;
//copy TxBufferHeader + MacHeader to desc
@@ -1661,7 +1636,7 @@ s_cbFillTxBufHead (
uTotalCopyLength += cbFragPayloadSize - cb802_1_H_len;
- if ((bNeedEncrypt == TRUE) && (pTransmitKey != NULL) && (pTransmitKey->byCipherSuite == KEY_CTL_TKIP)) {
+ if ((bNeedEncrypt == true) && (pTransmitKey != NULL) && (pTransmitKey->byCipherSuite == KEY_CTL_TKIP)) {
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Start MIC: %d\n", cbFragPayloadSize);
MIC_vAppend((pbyBuffer + uLength - cb802_1_H_len), cbFragPayloadSize);
@@ -1672,7 +1647,7 @@ s_cbFillTxBufHead (
//---------------------------
if ((pDevice->byLocalID <= REV_ID_VT3253_A1)) {
if (bNeedEncrypt) {
- s_vSWencryption(pDevice, pTransmitKey, (pbyBuffer + uLength - cb802_1_H_len), (WORD)cbFragPayloadSize);
+ s_vSWencryption(pDevice, pTransmitKey, (pbyBuffer + uLength - cb802_1_H_len), (unsigned short)cbFragPayloadSize);
cbReqCount += cbICVlen;
}
}
@@ -1711,13 +1686,13 @@ s_cbFillTxBufHead (
uFragIdx, cbLastFragmentSize, uMACfragNum, byFBOption, pDevice->wCurrentRate);
// Generate TX MAC Header
- vGenerateMACHeader(pDevice, pbyMacHdr, (WORD)uDuration, psEthHeader, bNeedEncrypt,
+ vGenerateMACHeader(pDevice, pbyMacHdr, (unsigned short)uDuration, psEthHeader, bNeedEncrypt,
wFragType, uDMAIdx, uFragIdx);
- if (bNeedEncrypt == TRUE) {
+ if (bNeedEncrypt == true) {
//Fill TXKEY
- s_vFillTxKey(pDevice, (PBYTE)(psTxBufHd->adwTxKey), pbyIVHead, pTransmitKey,
- pbyMacHdr, (WORD)cbLastFragPayloadSize, (PBYTE)pMICHDR);
+ s_vFillTxKey(pDevice, (unsigned char *)(psTxBufHd->adwTxKey), pbyIVHead, pTransmitKey,
+ pbyMacHdr, (unsigned short)cbLastFragPayloadSize, (unsigned char *)pMICHDR);
if (pDevice->bEnableHostWEP) {
pMgmt->sNodeDBTable[uNodeIndex].dwTSC47_16 = pTransmitKey->dwTSC47_16;
@@ -1734,8 +1709,8 @@ s_cbFillTxBufHead (
- pbyBuffer = (PBYTE)pHeadTD->pTDInfo->buf;
- //pbyBuffer = (PBYTE)pDevice->aamTxBuf[uDMAIdx][tmpDescIdx].pbyVAddr;
+ pbyBuffer = (unsigned char *)pHeadTD->pTDInfo->buf;
+ //pbyBuffer = (unsigned char *)pDevice->aamTxBuf[uDMAIdx][tmpDescIdx].pbyVAddr;
uLength = cbHeaderLength + cbMACHdLen + uPadding + cbIVlen;
@@ -1743,7 +1718,7 @@ s_cbFillTxBufHead (
memcpy(pbyBuffer, (void *)psTxBufHd, uLength);
// Copy the Packet into a tx Buffer
- if (bMIC2Frag == FALSE) {
+ if (bMIC2Frag == false) {
memcpy((pbyBuffer + uLength),
(pPacket + 14 + uTotalCopyLength),
@@ -1753,36 +1728,36 @@ s_cbFillTxBufHead (
uTmpLen = cbLastFragPayloadSize - cbMIClen;
}
- if ((bNeedEncrypt == TRUE) && (pTransmitKey != NULL) && (pTransmitKey->byCipherSuite == KEY_CTL_TKIP)) {
+ if ((bNeedEncrypt == true) && (pTransmitKey != NULL) && (pTransmitKey->byCipherSuite == KEY_CTL_TKIP)) {
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"LAST: uMICFragLen:%d, cbLastFragPayloadSize:%d, uTmpLen:%d\n",
uMICFragLen, cbLastFragPayloadSize, uTmpLen);
- if (bMIC2Frag == FALSE) {
+ if (bMIC2Frag == false) {
if (uTmpLen != 0)
MIC_vAppend((pbyBuffer + uLength), uTmpLen);
- pdwMIC_L = (PDWORD)(pbyBuffer + uLength + uTmpLen);
- pdwMIC_R = (PDWORD)(pbyBuffer + uLength + uTmpLen + 4);
+ pdwMIC_L = (unsigned long *)(pbyBuffer + uLength + uTmpLen);
+ pdwMIC_R = (unsigned long *)(pbyBuffer + uLength + uTmpLen + 4);
MIC_vGetMIC(pdwMIC_L, pdwMIC_R);
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Last MIC:%lX, %lX\n", *pdwMIC_L, *pdwMIC_R);
} else {
if (uMICFragLen >= 4) {
- memcpy((pbyBuffer + uLength), ((PBYTE)&dwSafeMIC_R + (uMICFragLen - 4)),
+ memcpy((pbyBuffer + uLength), ((unsigned char *)&dwSafeMIC_R + (uMICFragLen - 4)),
(cbMIClen - uMICFragLen));
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"LAST: uMICFragLen >= 4: %X, %d\n",
- *(PBYTE)((PBYTE)&dwSafeMIC_R + (uMICFragLen - 4)),
+ *(unsigned char *)((unsigned char *)&dwSafeMIC_R + (uMICFragLen - 4)),
(cbMIClen - uMICFragLen));
} else {
- memcpy((pbyBuffer + uLength), ((PBYTE)&dwSafeMIC_L + uMICFragLen),
+ memcpy((pbyBuffer + uLength), ((unsigned char *)&dwSafeMIC_L + uMICFragLen),
(4 - uMICFragLen));
memcpy((pbyBuffer + uLength + (4 - uMICFragLen)), &dwSafeMIC_R, 4);
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"LAST: uMICFragLen < 4: %X, %d\n",
- *(PBYTE)((PBYTE)&dwSafeMIC_R + uMICFragLen - 4),
+ *(unsigned char *)((unsigned char *)&dwSafeMIC_R + uMICFragLen - 4),
(cbMIClen - uMICFragLen));
}
/*
for (ii = 0; ii < cbLastFragPayloadSize + 8 + 24; ii++) {
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"%02x ", *((PBYTE)((pbyBuffer + uLength) + ii - 8 - 24)));
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"%02x ", *((unsigned char *)((pbyBuffer + uLength) + ii - 8 - 24)));
}
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"\n\n");
*/
@@ -1798,7 +1773,7 @@ s_cbFillTxBufHead (
//---------------------------
if ((pDevice->byLocalID <= REV_ID_VT3253_A1)) {
if (bNeedEncrypt) {
- s_vSWencryption(pDevice, pTransmitKey, (pbyBuffer + uLength), (WORD)cbLastFragPayloadSize);
+ s_vSWencryption(pDevice, pTransmitKey, (pbyBuffer + uLength), (unsigned short)cbLastFragPayloadSize);
cbReqCount += cbICVlen;
}
}
@@ -1841,14 +1816,14 @@ s_cbFillTxBufHead (
uFragIdx, cbLastFragmentSize, uMACfragNum, byFBOption, pDevice->wCurrentRate);
// Generate TX MAC Header
- vGenerateMACHeader(pDevice, pbyMacHdr, (WORD)uDuration, psEthHeader, bNeedEncrypt,
+ vGenerateMACHeader(pDevice, pbyMacHdr, (unsigned short)uDuration, psEthHeader, bNeedEncrypt,
wFragType, uDMAIdx, uFragIdx);
- if (bNeedEncrypt == TRUE) {
+ if (bNeedEncrypt == true) {
//Fill TXKEY
- s_vFillTxKey(pDevice, (PBYTE)(psTxBufHd->adwTxKey), pbyIVHead, pTransmitKey,
- pbyMacHdr, (WORD)cbFragPayloadSize, (PBYTE)pMICHDR);
+ s_vFillTxKey(pDevice, (unsigned char *)(psTxBufHd->adwTxKey), pbyIVHead, pTransmitKey,
+ pbyMacHdr, (unsigned short)cbFragPayloadSize, (unsigned char *)pMICHDR);
if (pDevice->bEnableHostWEP) {
pMgmt->sNodeDBTable[uNodeIndex].dwTSC47_16 = pTransmitKey->dwTSC47_16;
@@ -1862,14 +1837,14 @@ s_cbFillTxBufHead (
//---------------------------
//Fill MICHDR
//if (pDevice->bAES) {
- // s_vFillMICHDR(pDevice, (PBYTE)pMICHDR, pbyMacHdr, (WORD)cbFragPayloadSize);
+ // s_vFillMICHDR(pDevice, (unsigned char *)pMICHDR, pbyMacHdr, (unsigned short)cbFragPayloadSize);
//}
//cbReqCount += s_uDoEncryption(pDevice, psEthHeader, (void *)psTxBufHd, byKeySel,
- // pbyPayloadHead, (WORD)cbFragPayloadSize, uDMAIdx);
+ // pbyPayloadHead, (unsigned short)cbFragPayloadSize, uDMAIdx);
- pbyBuffer = (PBYTE)pHeadTD->pTDInfo->buf;
- //pbyBuffer = (PBYTE)pDevice->aamTxBuf[uDMAIdx][tmpDescIdx].pbyVAddr;
+ pbyBuffer = (unsigned char *)pHeadTD->pTDInfo->buf;
+ //pbyBuffer = (unsigned char *)pDevice->aamTxBuf[uDMAIdx][tmpDescIdx].pbyVAddr;
uLength = cbHeaderLength + cbMACHdLen + uPadding + cbIVlen;
@@ -1886,17 +1861,17 @@ s_cbFillTxBufHead (
uTotalCopyLength += uTmpLen;
- if ((bNeedEncrypt == TRUE) && (pTransmitKey != NULL) && (pTransmitKey->byCipherSuite == KEY_CTL_TKIP)) {
+ if ((bNeedEncrypt == true) && (pTransmitKey != NULL) && (pTransmitKey->byCipherSuite == KEY_CTL_TKIP)) {
MIC_vAppend((pbyBuffer + uLength), uTmpLen);
if (uTmpLen < cbFragPayloadSize) {
- bMIC2Frag = TRUE;
+ bMIC2Frag = true;
uMICFragLen = cbFragPayloadSize - uTmpLen;
ASSERT(uMICFragLen < cbMIClen);
- pdwMIC_L = (PDWORD)(pbyBuffer + uLength + uTmpLen);
- pdwMIC_R = (PDWORD)(pbyBuffer + uLength + uTmpLen + 4);
+ pdwMIC_L = (unsigned long *)(pbyBuffer + uLength + uTmpLen);
+ pdwMIC_R = (unsigned long *)(pbyBuffer + uLength + uTmpLen + 4);
MIC_vGetMIC(pdwMIC_L, pdwMIC_R);
dwSafeMIC_L = *pdwMIC_L;
dwSafeMIC_R = *pdwMIC_R;
@@ -1906,7 +1881,7 @@ s_cbFillTxBufHead (
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Fill MIC in Middle frag [%d]\n", uMICFragLen);
/*
for (ii = 0; ii < uMICFragLen; ii++) {
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"%02x ", *((PBYTE)((pbyBuffer + uLength + uTmpLen) + ii)));
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"%02x ", *((unsigned char *)((pbyBuffer + uLength + uTmpLen) + ii)));
}
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"\n");
*/
@@ -1915,7 +1890,7 @@ s_cbFillTxBufHead (
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Middle frag len: %d\n", uTmpLen);
/*
for (ii = 0; ii < uTmpLen; ii++) {
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"%02x ", *((PBYTE)((pbyBuffer + uLength) + ii)));
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"%02x ", *((unsigned char *)((pbyBuffer + uLength) + ii)));
}
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"\n\n");
*/
@@ -1926,7 +1901,7 @@ s_cbFillTxBufHead (
if ((pDevice->byLocalID <= REV_ID_VT3253_A1)) {
if (bNeedEncrypt) {
- s_vSWencryption(pDevice, pTransmitKey, (pbyBuffer + uLength), (WORD)cbFragPayloadSize);
+ s_vSWencryption(pDevice, pTransmitKey, (pbyBuffer + uLength), (unsigned short)cbFragPayloadSize);
cbReqCount += cbICVlen;
}
}
@@ -1961,7 +1936,7 @@ s_cbFillTxBufHead (
wFragType = FRAGCTL_NONFRAG;
//Set FragCtl in TxBufferHead
- psTxBufHd->wFragCtl |= (WORD)wFragType;
+ psTxBufHd->wFragCtl |= (unsigned short)wFragType;
//Fill FIFO,RrvTime,RTS,and CTS
s_vGenerateTxParameter(pDevice, byPktType, (void *)psTxBufHd, pvRrvTime, pvRTS, pvCTS,
@@ -1971,13 +1946,13 @@ s_cbFillTxBufHead (
0, 0, uMACfragNum, byFBOption, pDevice->wCurrentRate);
// Generate TX MAC Header
- vGenerateMACHeader(pDevice, pbyMacHdr, (WORD)uDuration, psEthHeader, bNeedEncrypt,
+ vGenerateMACHeader(pDevice, pbyMacHdr, (unsigned short)uDuration, psEthHeader, bNeedEncrypt,
wFragType, uDMAIdx, 0);
- if (bNeedEncrypt == TRUE) {
+ if (bNeedEncrypt == true) {
//Fill TXKEY
- s_vFillTxKey(pDevice, (PBYTE)(psTxBufHd->adwTxKey), pbyIVHead, pTransmitKey,
- pbyMacHdr, (WORD)cbFrameBodySize, (PBYTE)pMICHDR);
+ s_vFillTxKey(pDevice, (unsigned char *)(psTxBufHd->adwTxKey), pbyIVHead, pTransmitKey,
+ pbyMacHdr, (unsigned short)cbFrameBodySize, (unsigned char *)pMICHDR);
if (pDevice->bEnableHostWEP) {
pMgmt->sNodeDBTable[uNodeIndex].dwTSC47_16 = pTransmitKey->dwTSC47_16;
@@ -1989,13 +1964,13 @@ s_cbFillTxBufHead (
if (ntohs(psEthHeader->wType) > ETH_DATA_LEN) {
if ((psEthHeader->wType == TYPE_PKT_IPX) ||
(psEthHeader->wType == cpu_to_le16(0xF380))) {
- memcpy((PBYTE) (pbyPayloadHead), &pDevice->abySNAP_Bridgetunnel[0], 6);
+ memcpy((unsigned char *) (pbyPayloadHead), &pDevice->abySNAP_Bridgetunnel[0], 6);
}
else {
- memcpy((PBYTE) (pbyPayloadHead), &pDevice->abySNAP_RFC1042[0], 6);
+ memcpy((unsigned char *) (pbyPayloadHead), &pDevice->abySNAP_RFC1042[0], 6);
}
- pbyType = (PBYTE) (pbyPayloadHead + 6);
- memcpy(pbyType, &(psEthHeader->wType), sizeof(WORD));
+ pbyType = (unsigned char *) (pbyPayloadHead + 6);
+ memcpy(pbyType, &(psEthHeader->wType), sizeof(unsigned short));
cb802_1_H_len = 8;
}
@@ -2006,11 +1981,11 @@ s_cbFillTxBufHead (
//Fill MICHDR
//if (pDevice->bAES) {
// DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Fill MICHDR...\n");
- // s_vFillMICHDR(pDevice, (PBYTE)pMICHDR, pbyMacHdr, (WORD)cbFrameBodySize);
+ // s_vFillMICHDR(pDevice, (unsigned char *)pMICHDR, pbyMacHdr, (unsigned short)cbFrameBodySize);
//}
- pbyBuffer = (PBYTE)pHeadTD->pTDInfo->buf;
- //pbyBuffer = (PBYTE)pDevice->aamTxBuf[uDMAIdx][uDescIdx].pbyVAddr;
+ pbyBuffer = (unsigned char *)pHeadTD->pTDInfo->buf;
+ //pbyBuffer = (unsigned char *)pDevice->aamTxBuf[uDMAIdx][uDescIdx].pbyVAddr;
uLength = cbHeaderLength + cbMACHdLen + uPadding + cbIVlen + cb802_1_H_len;
@@ -2023,29 +1998,29 @@ s_cbFillTxBufHead (
cbFrameBodySize - cb802_1_H_len
);
- if ((bNeedEncrypt == TRUE) && (pTransmitKey != NULL) && (pTransmitKey->byCipherSuite == KEY_CTL_TKIP)){
+ if ((bNeedEncrypt == true) && (pTransmitKey != NULL) && (pTransmitKey->byCipherSuite == KEY_CTL_TKIP)){
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Length:%d, %d\n", cbFrameBodySize - cb802_1_H_len, uLength);
/*
for (ii = 0; ii < (cbFrameBodySize - cb802_1_H_len); ii++) {
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"%02x ", *((PBYTE)((pbyBuffer + uLength) + ii)));
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"%02x ", *((unsigned char *)((pbyBuffer + uLength) + ii)));
}
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"\n");
*/
MIC_vAppend((pbyBuffer + uLength - cb802_1_H_len), cbFrameBodySize);
- pdwMIC_L = (PDWORD)(pbyBuffer + uLength - cb802_1_H_len + cbFrameBodySize);
- pdwMIC_R = (PDWORD)(pbyBuffer + uLength - cb802_1_H_len + cbFrameBodySize + 4);
+ pdwMIC_L = (unsigned long *)(pbyBuffer + uLength - cb802_1_H_len + cbFrameBodySize);
+ pdwMIC_R = (unsigned long *)(pbyBuffer + uLength - cb802_1_H_len + cbFrameBodySize + 4);
MIC_vGetMIC(pdwMIC_L, pdwMIC_R);
MIC_vUnInit();
- if (pDevice->bTxMICFail == TRUE) {
+ if (pDevice->bTxMICFail == true) {
*pdwMIC_L = 0;
*pdwMIC_R = 0;
- pDevice->bTxMICFail = FALSE;
+ pDevice->bTxMICFail = false;
}
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"uLength: %d, %d\n", uLength, cbFrameBodySize);
@@ -2053,7 +2028,7 @@ s_cbFillTxBufHead (
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"MIC:%lx, %lx\n", *pdwMIC_L, *pdwMIC_R);
/*
for (ii = 0; ii < 8; ii++) {
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"%02x ", *(((PBYTE)(pdwMIC_L) + ii)));
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"%02x ", *(((unsigned char *)(pdwMIC_L) + ii)));
}
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"\n");
*/
@@ -2064,7 +2039,7 @@ s_cbFillTxBufHead (
if ((pDevice->byLocalID <= REV_ID_VT3253_A1)){
if (bNeedEncrypt) {
s_vSWencryption(pDevice, pTransmitKey, (pbyBuffer + uLength - cb802_1_H_len),
- (WORD)(cbFrameBodySize + cbMIClen));
+ (unsigned short)(cbFrameBodySize + cbMIClen));
cbReqCount += cbICVlen;
}
}
@@ -2078,7 +2053,7 @@ s_cbFillTxBufHead (
ptdCurr->buff_addr = cpu_to_le32(ptdCurr->pTDInfo->skb_dma);
//Set TSR1 & ReqCount in TxDescHead
ptdCurr->m_td1TD1.byTCR |= (TCR_STP | TCR_EDP | EDMSDU);
- ptdCurr->m_td1TD1.wReqCount = cpu_to_le16((WORD)(cbReqCount));
+ ptdCurr->m_td1TD1.wReqCount = cpu_to_le16((unsigned short)(cbReqCount));
pDevice->iTDUsed[uDMAIdx]++;
@@ -2094,26 +2069,16 @@ s_cbFillTxBufHead (
void
-vGenerateFIFOHeader (
- PSDevice pDevice,
- BYTE byPktType,
- PBYTE pbyTxBufferAddr,
- BOOL bNeedEncrypt,
- UINT cbPayloadSize,
- UINT uDMAIdx,
- PSTxDesc pHeadTD,
- PSEthernetHeader psEthHeader,
- PBYTE pPacket,
- PSKeyItem pTransmitKey,
- UINT uNodeIndex,
- PUINT puMACfragNum,
- PUINT pcbHeaderSize
- )
+vGenerateFIFOHeader(PSDevice pDevice, unsigned char byPktType, unsigned char *pbyTxBufferAddr,
+ bool bNeedEncrypt, unsigned int cbPayloadSize, unsigned int uDMAIdx,
+ PSTxDesc pHeadTD, PSEthernetHeader psEthHeader, unsigned char *pPacket,
+ PSKeyItem pTransmitKey, unsigned int uNodeIndex, unsigned int *puMACfragNum,
+ unsigned int *pcbHeaderSize)
{
- UINT wTxBufSize; // FFinfo size
- BOOL bNeedACK;
- BOOL bIsAdhoc;
- WORD cbMacHdLen;
+ unsigned int wTxBufSize; // FFinfo size
+ bool bNeedACK;
+ bool bIsAdhoc;
+ unsigned short cbMacHdLen;
PSTxBufHead pTxBufHead = (PSTxBufHead) pbyTxBufferAddr;
wTxBufSize = sizeof(STxBufHead);
@@ -2123,22 +2088,21 @@ vGenerateFIFOHeader (
if ((pDevice->eOPMode == OP_MODE_ADHOC) ||
(pDevice->eOPMode == OP_MODE_AP)) {
- if (IS_MULTICAST_ADDRESS(&(psEthHeader->abyDstAddr[0])) ||
- IS_BROADCAST_ADDRESS(&(psEthHeader->abyDstAddr[0]))) {
- bNeedACK = FALSE;
+ if (is_multicast_ether_addr(&(psEthHeader->abyDstAddr[0]))) {
+ bNeedACK = false;
pTxBufHead->wFIFOCtl = pTxBufHead->wFIFOCtl & (~FIFOCTL_NEEDACK);
}
else {
- bNeedACK = TRUE;
+ bNeedACK = true;
pTxBufHead->wFIFOCtl |= FIFOCTL_NEEDACK;
}
- bIsAdhoc = TRUE;
+ bIsAdhoc = true;
}
else {
// MSDUs in Infra mode always need ACK
- bNeedACK = TRUE;
+ bNeedACK = true;
pTxBufHead->wFIFOCtl |= FIFOCTL_NEEDACK;
- bIsAdhoc = FALSE;
+ bIsAdhoc = false;
}
@@ -2165,7 +2129,7 @@ vGenerateFIFOHeader (
} else {
cbMacHdLen = WLAN_HDR_ADDR3_LEN;
}
- pTxBufHead->wFragCtl |= cpu_to_le16((WORD)(cbMacHdLen << 10));
+ pTxBufHead->wFragCtl |= cpu_to_le16((unsigned short)(cbMacHdLen << 10));
//Set packet type
if (byPktType == PK_TYPE_11A) {//0000 0000 0000 0000
@@ -2181,7 +2145,7 @@ vGenerateFIFOHeader (
pTxBufHead->wFIFOCtl |= FIFOCTL_11GA;
}
//Set FIFOCTL_GrpAckPolicy
- if (pDevice->bGrpAckPolicy == TRUE) {//0000 0100 0000 0000
+ if (pDevice->bGrpAckPolicy == true) {//0000 0100 0000 0000
pTxBufHead->wFIFOCtl |= FIFOCTL_GRPACK;
}
@@ -2195,7 +2159,7 @@ vGenerateFIFOHeader (
}
//Set FRAGCTL_WEPTYP
- pDevice->bAES = FALSE;
+ pDevice->bAES = false;
//Set FRAGCTL_WEPTYP
if (pDevice->byLocalID > REV_ID_VT3253_A1) {
@@ -2267,13 +2231,13 @@ vGenerateFIFOHeader (
void
vGenerateMACHeader (
PSDevice pDevice,
- PBYTE pbyBufferAddr,
- WORD wDuration,
+ unsigned char *pbyBufferAddr,
+ unsigned short wDuration,
PSEthernetHeader psEthHeader,
- BOOL bNeedEncrypt,
- WORD wFragType,
- UINT uDMAIdx,
- UINT uFragIdx
+ bool bNeedEncrypt,
+ unsigned short wFragType,
+ unsigned int uDMAIdx,
+ unsigned int uFragIdx
)
{
PS802_11Header pMACHeader = (PS802_11Header)pbyBufferAddr;
@@ -2307,7 +2271,7 @@ vGenerateMACHeader (
}
if (bNeedEncrypt)
- pMACHeader->wFrameCtl |= cpu_to_le16((WORD)WLAN_SET_FC_ISWEP(1));
+ pMACHeader->wFrameCtl |= cpu_to_le16((unsigned short)WLAN_SET_FC_ISWEP(1));
pMACHeader->wDurationID = cpu_to_le16(wDuration);
@@ -2319,7 +2283,7 @@ vGenerateMACHeader (
pMACHeader->wSeqCtl = cpu_to_le16(pDevice->wSeqCounter << 4);
//Set FragNumber in Sequence Control
- pMACHeader->wSeqCtl |= cpu_to_le16((WORD)uFragIdx);
+ pMACHeader->wSeqCtl |= cpu_to_le16((unsigned short)uFragIdx);
if ((wFragType == FRAGCTL_ENDFRAG) || (wFragType == FRAGCTL_NONFRAG)) {
pDevice->wSeqCounter++;
@@ -2340,32 +2304,32 @@ vGenerateMACHeader (
CMD_STATUS csMgmt_xmit(PSDevice pDevice, PSTxMgmtPacket pPacket) {
PSTxDesc pFrstTD;
- BYTE byPktType;
- PBYTE pbyTxBufferAddr;
+ unsigned char byPktType;
+ unsigned char *pbyTxBufferAddr;
void * pvRTS;
PSCTS pCTS;
void * pvTxDataHd;
- UINT uDuration;
- UINT cbReqCount;
+ unsigned int uDuration;
+ unsigned int cbReqCount;
PS802_11Header pMACHeader;
- UINT cbHeaderSize;
- UINT cbFrameBodySize;
- BOOL bNeedACK;
- BOOL bIsPSPOLL = FALSE;
+ unsigned int cbHeaderSize;
+ unsigned int cbFrameBodySize;
+ bool bNeedACK;
+ bool bIsPSPOLL = false;
PSTxBufHead pTxBufHead;
- UINT cbFrameSize;
- UINT cbIVlen = 0;
- UINT cbICVlen = 0;
- UINT cbMIClen = 0;
- UINT cbFCSlen = 4;
- UINT uPadding = 0;
- WORD wTxBufSize;
- UINT cbMacHdLen;
+ unsigned int cbFrameSize;
+ unsigned int cbIVlen = 0;
+ unsigned int cbICVlen = 0;
+ unsigned int cbMIClen = 0;
+ unsigned int cbFCSlen = 4;
+ unsigned int uPadding = 0;
+ unsigned short wTxBufSize;
+ unsigned int cbMacHdLen;
SEthernetHeader sEthHeader;
void * pvRrvTime;
void * pMICHDR;
PSMgmtObject pMgmt = pDevice->pMgmt;
- WORD wCurrentRate = RATE_1M;
+ unsigned short wCurrentRate = RATE_1M;
if (AVAIL_TD(pDevice, TYPE_TXDMA0) <= 0) {
@@ -2373,7 +2337,7 @@ CMD_STATUS csMgmt_xmit(PSDevice pDevice, PSTxMgmtPacket pPacket) {
}
pFrstTD = pDevice->apCurrTD[TYPE_TXDMA0];
- pbyTxBufferAddr = (PBYTE)pFrstTD->pTDInfo->buf;
+ pbyTxBufferAddr = (unsigned char *)pFrstTD->pTDInfo->buf;
cbFrameBodySize = pPacket->cbPayloadLen;
pTxBufHead = (PSTxBufHead) pbyTxBufferAddr;
wTxBufSize = sizeof(STxBufHead);
@@ -2424,12 +2388,10 @@ CMD_STATUS csMgmt_xmit(PSDevice pDevice, PSTxMgmtPacket pPacket) {
pTxBufHead->wTimeStamp = cpu_to_le16(DEFAULT_MGN_LIFETIME_RES_64us);
- if (IS_MULTICAST_ADDRESS(&(pPacket->p80211Header->sA3.abyAddr1[0])) ||
- IS_BROADCAST_ADDRESS(&(pPacket->p80211Header->sA3.abyAddr1[0]))) {
- bNeedACK = FALSE;
- }
+ if (is_multicast_ether_addr(&(pPacket->p80211Header->sA3.abyAddr1[0])))
+ bNeedACK = false;
else {
- bNeedACK = TRUE;
+ bNeedACK = true;
pTxBufHead->wFIFOCtl |= FIFOCTL_NEEDACK;
};
@@ -2441,7 +2403,7 @@ CMD_STATUS csMgmt_xmit(PSDevice pDevice, PSTxMgmtPacket pPacket) {
//pDevice->byPreambleType = PREAMBLE_LONG;
// probe-response don't retry
//if ((pPacket->p80211Header->sA4.wFrameCtl & TYPE_SUBTYPE_MASK) == TYPE_MGMT_PROBE_RSP) {
- // bNeedACK = FALSE;
+ // bNeedACK = false;
// pTxBufHead->wFIFOCtl &= (~FIFOCTL_NEEDACK);
//}
}
@@ -2449,19 +2411,19 @@ CMD_STATUS csMgmt_xmit(PSDevice pDevice, PSTxMgmtPacket pPacket) {
pTxBufHead->wFIFOCtl |= (FIFOCTL_GENINT | FIFOCTL_ISDMA0);
if ((pPacket->p80211Header->sA4.wFrameCtl & TYPE_SUBTYPE_MASK) == TYPE_CTL_PSPOLL) {
- bIsPSPOLL = TRUE;
+ bIsPSPOLL = true;
cbMacHdLen = WLAN_HDR_ADDR2_LEN;
} else {
cbMacHdLen = WLAN_HDR_ADDR3_LEN;
}
//Set FRAGCTL_MACHDCNT
- pTxBufHead->wFragCtl |= cpu_to_le16((WORD)(cbMacHdLen << 10));
+ pTxBufHead->wFragCtl |= cpu_to_le16((unsigned short)(cbMacHdLen << 10));
// Notes:
// Although spec says MMPDU can be fragmented; In most case,
// no one will send a MMPDU under fragmentation. With RTS may occur.
- pDevice->bAES = FALSE; //Set FRAGCTL_WEPTYP
+ pDevice->bAES = false; //Set FRAGCTL_WEPTYP
if (WLAN_GET_FC_ISWEP(pPacket->p80211Header->sA4.wFrameCtl) != 0) {
if (pDevice->eEncryptionStatus == Ndis802_11Encryption1Enabled) {
@@ -2482,7 +2444,7 @@ CMD_STATUS csMgmt_xmit(PSDevice pDevice, PSTxMgmtPacket pPacket) {
cbIVlen = 8;//RSN Header
cbICVlen = 8;//MIC
pTxBufHead->wFragCtl |= FRAGCTL_AES;
- pDevice->bAES = TRUE;
+ pDevice->bAES = true;
}
//MAC Header should be padding 0 to DW alignment.
uPadding = 4 - (cbMacHdLen%4);
@@ -2492,7 +2454,7 @@ CMD_STATUS csMgmt_xmit(PSDevice pDevice, PSTxMgmtPacket pPacket) {
cbFrameSize = cbMacHdLen + cbFrameBodySize + cbIVlen + cbMIClen + cbICVlen + cbFCSlen;
//Set FIFOCTL_GrpAckPolicy
- if (pDevice->bGrpAckPolicy == TRUE) {//0000 0100 0000 0000
+ if (pDevice->bGrpAckPolicy == true) {//0000 0100 0000 0000
pTxBufHead->wFIFOCtl |= FIFOCTL_GRPACK;
}
//the rest of pTxBufHead->wFragCtl:FragTyp will be set later in s_vFillFragParameter()
@@ -2523,7 +2485,7 @@ CMD_STATUS csMgmt_xmit(PSDevice pDevice, PSTxMgmtPacket pPacket) {
//=========================
// No Fragmentation
//=========================
- pTxBufHead->wFragCtl |= (WORD)FRAGCTL_NONFRAG;
+ pTxBufHead->wFragCtl |= (unsigned short)FRAGCTL_NONFRAG;
//Fill FIFO,RrvTime,RTS,and CTS
@@ -2539,17 +2501,17 @@ CMD_STATUS csMgmt_xmit(PSDevice pDevice, PSTxMgmtPacket pPacket) {
cbReqCount = cbHeaderSize + cbMacHdLen + uPadding + cbIVlen + cbFrameBodySize;
if (WLAN_GET_FC_ISWEP(pPacket->p80211Header->sA4.wFrameCtl) != 0) {
- PBYTE pbyIVHead;
- PBYTE pbyPayloadHead;
- PBYTE pbyBSSID;
+ unsigned char *pbyIVHead;
+ unsigned char *pbyPayloadHead;
+ unsigned char *pbyBSSID;
PSKeyItem pTransmitKey = NULL;
- pbyIVHead = (PBYTE)(pbyTxBufferAddr + cbHeaderSize + cbMacHdLen + uPadding);
- pbyPayloadHead = (PBYTE)(pbyTxBufferAddr + cbHeaderSize + cbMacHdLen + uPadding + cbIVlen);
+ pbyIVHead = (unsigned char *)(pbyTxBufferAddr + cbHeaderSize + cbMacHdLen + uPadding);
+ pbyPayloadHead = (unsigned char *)(pbyTxBufferAddr + cbHeaderSize + cbMacHdLen + uPadding + cbIVlen);
//Fill TXKEY
//Kyle: Need fix: TKIP and AES did't encryt Mnt Packet.
- //s_vFillTxKey(pDevice, (PBYTE)pTxBufHead->adwTxKey, NULL);
+ //s_vFillTxKey(pDevice, (unsigned char *)pTxBufHead->adwTxKey, NULL);
//Fill IV(ExtIV,RSNHDR)
//s_vFillPrePayload(pDevice, pbyIVHead, NULL);
@@ -2558,16 +2520,16 @@ CMD_STATUS csMgmt_xmit(PSDevice pDevice, PSTxMgmtPacket pPacket) {
//---------------------------
//Fill MICHDR
//if (pDevice->bAES) {
- // s_vFillMICHDR(pDevice, (PBYTE)pMICHDR, (PBYTE)pMACHeader, (WORD)cbFrameBodySize);
+ // s_vFillMICHDR(pDevice, (unsigned char *)pMICHDR, (unsigned char *)pMACHeader, (unsigned short)cbFrameBodySize);
//}
do {
if ((pDevice->eOPMode == OP_MODE_INFRASTRUCTURE) &&
- (pDevice->bLinkPass == TRUE)) {
+ (pDevice->bLinkPass == true)) {
pbyBSSID = pDevice->abyBSSID;
// get pairwise key
- if (KeybGetTransmitKey(&(pDevice->sKey), pbyBSSID, PAIRWISE_KEY, &pTransmitKey) == FALSE) {
+ if (KeybGetTransmitKey(&(pDevice->sKey), pbyBSSID, PAIRWISE_KEY, &pTransmitKey) == false) {
// get group key
- if(KeybGetTransmitKey(&(pDevice->sKey), pbyBSSID, GROUP_KEY, &pTransmitKey) == TRUE) {
+ if(KeybGetTransmitKey(&(pDevice->sKey), pbyBSSID, GROUP_KEY, &pTransmitKey) == true) {
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Get GTK.\n");
break;
}
@@ -2578,19 +2540,19 @@ CMD_STATUS csMgmt_xmit(PSDevice pDevice, PSTxMgmtPacket pPacket) {
}
// get group key
pbyBSSID = pDevice->abyBroadcastAddr;
- if(KeybGetTransmitKey(&(pDevice->sKey), pbyBSSID, GROUP_KEY, &pTransmitKey) == FALSE) {
+ if(KeybGetTransmitKey(&(pDevice->sKey), pbyBSSID, GROUP_KEY, &pTransmitKey) == false) {
pTransmitKey = NULL;
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"KEY is NULL. OP Mode[%d]\n", pDevice->eOPMode);
} else {
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Get GTK.\n");
}
- } while(FALSE);
+ } while(false);
//Fill TXKEY
- s_vFillTxKey(pDevice, (PBYTE)(pTxBufHead->adwTxKey), pbyIVHead, pTransmitKey,
- (PBYTE)pMACHeader, (WORD)cbFrameBodySize, NULL);
+ s_vFillTxKey(pDevice, (unsigned char *)(pTxBufHead->adwTxKey), pbyIVHead, pTransmitKey,
+ (unsigned char *)pMACHeader, (unsigned short)cbFrameBodySize, NULL);
memcpy(pMACHeader, pPacket->p80211Header, cbMacHdLen);
- memcpy(pbyPayloadHead, ((PBYTE)(pPacket->p80211Header) + cbMacHdLen),
+ memcpy(pbyPayloadHead, ((unsigned char *)(pPacket->p80211Header) + cbMacHdLen),
cbFrameBodySize);
}
else {
@@ -2622,7 +2584,7 @@ CMD_STATUS csMgmt_xmit(PSDevice pDevice, PSTxMgmtPacket pPacket) {
//Set TSR1 & ReqCount in TxDescHead
pFrstTD->m_td1TD1.byTCR = (TCR_STP | TCR_EDP | EDMSDU);
pFrstTD->pTDInfo->skb_dma = pFrstTD->pTDInfo->buf_dma;
- pFrstTD->m_td1TD1.wReqCount = cpu_to_le16((WORD)(cbReqCount));
+ pFrstTD->m_td1TD1.wReqCount = cpu_to_le16((unsigned short)(cbReqCount));
pFrstTD->buff_addr = cpu_to_le32(pFrstTD->pTDInfo->skb_dma);
pFrstTD->pTDInfo->byFlags = 0;
@@ -2630,7 +2592,7 @@ CMD_STATUS csMgmt_xmit(PSDevice pDevice, PSTxMgmtPacket pPacket) {
// Disable PS
MACbPSWakeup(pDevice->PortOffset);
}
- pDevice->bPWBitOn = FALSE;
+ pDevice->bPWBitOn = false;
wmb();
pFrstTD->m_td0TD0.f1Owner = OWNED_BY_NIC;
@@ -2661,16 +2623,16 @@ CMD_STATUS csMgmt_xmit(PSDevice pDevice, PSTxMgmtPacket pPacket) {
CMD_STATUS csBeacon_xmit(PSDevice pDevice, PSTxMgmtPacket pPacket) {
- BYTE byPktType;
- PBYTE pbyBuffer = (PBYTE)pDevice->tx_beacon_bufs;
- UINT cbFrameSize = pPacket->cbMPDULen + WLAN_FCS_LEN;
- UINT cbHeaderSize = 0;
- WORD wTxBufSize = sizeof(STxShortBufHead);
+ unsigned char byPktType;
+ unsigned char *pbyBuffer = (unsigned char *)pDevice->tx_beacon_bufs;
+ unsigned int cbFrameSize = pPacket->cbMPDULen + WLAN_FCS_LEN;
+ unsigned int cbHeaderSize = 0;
+ unsigned short wTxBufSize = sizeof(STxShortBufHead);
PSTxShortBufHead pTxBufHead = (PSTxShortBufHead) pbyBuffer;
PSTxDataHead_ab pTxDataHead = (PSTxDataHead_ab) (pbyBuffer + wTxBufSize);
PS802_11Header pMACHeader;
- WORD wCurrentRate;
- WORD wLen = 0x0000;
+ unsigned short wCurrentRate;
+ unsigned short wLen = 0x0000;
memset(pTxBufHead, 0, wTxBufSize);
@@ -2693,17 +2655,17 @@ CMD_STATUS csBeacon_xmit(PSDevice pDevice, PSTxMgmtPacket pPacket) {
//Set packet type & Get Duration
if (byPktType == PK_TYPE_11A) {//0000 0000 0000 0000
- pTxDataHead->wDuration = cpu_to_le16((WORD)s_uGetDataDuration(pDevice, DATADUR_A, cbFrameSize, byPktType,
- wCurrentRate, FALSE, 0, 0, 1, AUTO_FB_NONE));
+ pTxDataHead->wDuration = cpu_to_le16((unsigned short)s_uGetDataDuration(pDevice, DATADUR_A, cbFrameSize, byPktType,
+ wCurrentRate, false, 0, 0, 1, AUTO_FB_NONE));
}
else if (byPktType == PK_TYPE_11B) {//0000 0001 0000 0000
pTxBufHead->wFIFOCtl |= FIFOCTL_11B;
- pTxDataHead->wDuration = cpu_to_le16((WORD)s_uGetDataDuration(pDevice, DATADUR_B, cbFrameSize, byPktType,
- wCurrentRate, FALSE, 0, 0, 1, AUTO_FB_NONE));
+ pTxDataHead->wDuration = cpu_to_le16((unsigned short)s_uGetDataDuration(pDevice, DATADUR_B, cbFrameSize, byPktType,
+ wCurrentRate, false, 0, 0, 1, AUTO_FB_NONE));
}
BBvCaculateParameter(pDevice, cbFrameSize, wCurrentRate, byPktType,
- (PWORD)&(wLen), (PBYTE)&(pTxDataHead->byServiceField), (PBYTE)&(pTxDataHead->bySignalField)
+ (unsigned short *)&(wLen), (unsigned char *)&(pTxDataHead->byServiceField), (unsigned char *)&(pTxDataHead->bySignalField)
);
pTxDataHead->wTransmitLength = cpu_to_le16(wLen);
//Get TimeStampOff
@@ -2736,41 +2698,38 @@ CMD_STATUS csBeacon_xmit(PSDevice pDevice, PSTxMgmtPacket pPacket) {
-UINT
+unsigned int
cbGetFragCount (
PSDevice pDevice,
PSKeyItem pTransmitKey,
- UINT cbFrameBodySize,
+ unsigned int cbFrameBodySize,
PSEthernetHeader psEthHeader
)
{
- UINT cbMACHdLen;
- UINT cbFrameSize;
- UINT cbFragmentSize; //Hdr+(IV)+payoad+(MIC)+(ICV)+FCS
- UINT cbFragPayloadSize;
- UINT cbLastFragPayloadSize;
- UINT cbIVlen = 0;
- UINT cbICVlen = 0;
- UINT cbMIClen = 0;
- UINT cbFCSlen = 4;
- UINT uMACfragNum = 1;
- BOOL bNeedACK;
+ unsigned int cbMACHdLen;
+ unsigned int cbFrameSize;
+ unsigned int cbFragmentSize; //Hdr+(IV)+payoad+(MIC)+(ICV)+FCS
+ unsigned int cbFragPayloadSize;
+ unsigned int cbLastFragPayloadSize;
+ unsigned int cbIVlen = 0;
+ unsigned int cbICVlen = 0;
+ unsigned int cbMIClen = 0;
+ unsigned int cbFCSlen = 4;
+ unsigned int uMACfragNum = 1;
+ bool bNeedACK;
if ((pDevice->eOPMode == OP_MODE_ADHOC) ||
(pDevice->eOPMode == OP_MODE_AP)) {
- if (IS_MULTICAST_ADDRESS(&(psEthHeader->abyDstAddr[0])) ||
- IS_BROADCAST_ADDRESS(&(psEthHeader->abyDstAddr[0]))) {
- bNeedACK = FALSE;
- }
- else {
- bNeedACK = TRUE;
- }
+ if (is_multicast_ether_addr(&(psEthHeader->abyDstAddr[0])))
+ bNeedACK = false;
+ else
+ bNeedACK = true;
}
else {
// MSDUs in Infra mode always need ACK
- bNeedACK = TRUE;
+ bNeedACK = true;
}
if (pDevice->bLongHeader)
@@ -2779,7 +2738,7 @@ cbGetFragCount (
cbMACHdLen = WLAN_HDR_ADDR3_LEN;
- if (pDevice->bEncryptionEnable == TRUE) {
+ if (pDevice->bEncryptionEnable == true) {
if (pTransmitKey == NULL) {
if ((pDevice->eEncryptionStatus == Ndis802_11Encryption1Enabled) ||
@@ -2809,11 +2768,11 @@ cbGetFragCount (
cbFrameSize = cbMACHdLen + cbIVlen + (cbFrameBodySize + cbMIClen) + cbICVlen + cbFCSlen;
- if ((cbFrameSize > pDevice->wFragmentationThreshold) && (bNeedACK == TRUE)) {
+ if ((cbFrameSize > pDevice->wFragmentationThreshold) && (bNeedACK == true)) {
// Fragmentation
cbFragmentSize = pDevice->wFragmentationThreshold;
cbFragPayloadSize = cbFragmentSize - cbMACHdLen - cbIVlen - cbICVlen - cbFCSlen;
- uMACfragNum = (WORD) ((cbFrameBodySize + cbMIClen) / cbFragPayloadSize);
+ uMACfragNum = (unsigned short) ((cbFrameBodySize + cbMIClen) / cbFragPayloadSize);
cbLastFragPayloadSize = (cbFrameBodySize + cbMIClen) % cbFragPayloadSize;
if (cbLastFragPayloadSize == 0) {
cbLastFragPayloadSize = cbFragPayloadSize;
@@ -2826,51 +2785,51 @@ cbGetFragCount (
void
-vDMA0_tx_80211(PSDevice pDevice, struct sk_buff *skb, PBYTE pbMPDU, UINT cbMPDULen) {
+vDMA0_tx_80211(PSDevice pDevice, struct sk_buff *skb, unsigned char *pbMPDU, unsigned int cbMPDULen) {
PSTxDesc pFrstTD;
- BYTE byPktType;
- PBYTE pbyTxBufferAddr;
+ unsigned char byPktType;
+ unsigned char *pbyTxBufferAddr;
void * pvRTS;
void * pvCTS;
void * pvTxDataHd;
- UINT uDuration;
- UINT cbReqCount;
+ unsigned int uDuration;
+ unsigned int cbReqCount;
PS802_11Header pMACHeader;
- UINT cbHeaderSize;
- UINT cbFrameBodySize;
- BOOL bNeedACK;
- BOOL bIsPSPOLL = FALSE;
+ unsigned int cbHeaderSize;
+ unsigned int cbFrameBodySize;
+ bool bNeedACK;
+ bool bIsPSPOLL = false;
PSTxBufHead pTxBufHead;
- UINT cbFrameSize;
- UINT cbIVlen = 0;
- UINT cbICVlen = 0;
- UINT cbMIClen = 0;
- UINT cbFCSlen = 4;
- UINT uPadding = 0;
- UINT cbMICHDR = 0;
- UINT uLength = 0;
- DWORD dwMICKey0, dwMICKey1;
- DWORD dwMIC_Priority;
- PDWORD pdwMIC_L;
- PDWORD pdwMIC_R;
- WORD wTxBufSize;
- UINT cbMacHdLen;
+ unsigned int cbFrameSize;
+ unsigned int cbIVlen = 0;
+ unsigned int cbICVlen = 0;
+ unsigned int cbMIClen = 0;
+ unsigned int cbFCSlen = 4;
+ unsigned int uPadding = 0;
+ unsigned int cbMICHDR = 0;
+ unsigned int uLength = 0;
+ unsigned long dwMICKey0, dwMICKey1;
+ unsigned long dwMIC_Priority;
+ unsigned long *pdwMIC_L;
+ unsigned long *pdwMIC_R;
+ unsigned short wTxBufSize;
+ unsigned int cbMacHdLen;
SEthernetHeader sEthHeader;
void * pvRrvTime;
void * pMICHDR;
PSMgmtObject pMgmt = pDevice->pMgmt;
- WORD wCurrentRate = RATE_1M;
+ unsigned short wCurrentRate = RATE_1M;
PUWLAN_80211HDR p80211Header;
- UINT uNodeIndex = 0;
- BOOL bNodeExist = FALSE;
+ unsigned int uNodeIndex = 0;
+ bool bNodeExist = false;
SKeyItem STempKey;
PSKeyItem pTransmitKey = NULL;
- PBYTE pbyIVHead;
- PBYTE pbyPayloadHead;
- PBYTE pbyMacHdr;
+ unsigned char *pbyIVHead;
+ unsigned char *pbyPayloadHead;
+ unsigned char *pbyMacHdr;
- UINT cbExtSuppRate = 0;
+ unsigned int cbExtSuppRate = 0;
// PWLAN_IE pItem;
@@ -2886,7 +2845,7 @@ vDMA0_tx_80211(PSDevice pDevice, struct sk_buff *skb, PBYTE pbMPDU, UINT cbMPDU
pFrstTD = pDevice->apCurrTD[TYPE_TXDMA0];
- pbyTxBufferAddr = (PBYTE)pFrstTD->pTDInfo->buf;
+ pbyTxBufferAddr = (unsigned char *)pFrstTD->pTDInfo->buf;
pTxBufHead = (PSTxBufHead) pbyTxBufferAddr;
wTxBufSize = sizeof(STxBufHead);
memset(pTxBufHead, 0, wTxBufSize);
@@ -2938,20 +2897,19 @@ vDMA0_tx_80211(PSDevice pDevice, struct sk_buff *skb, PBYTE pbMPDU, UINT cbMPDU
pTxBufHead->wTimeStamp = cpu_to_le16(DEFAULT_MGN_LIFETIME_RES_64us);
- if (IS_MULTICAST_ADDRESS(&(p80211Header->sA3.abyAddr1[0])) ||
- IS_BROADCAST_ADDRESS(&(p80211Header->sA3.abyAddr1[0]))) {
- bNeedACK = FALSE;
+ if (is_multicast_ether_addr(&(p80211Header->sA3.abyAddr1[0]))) {
+ bNeedACK = false;
if (pDevice->bEnableHostWEP) {
uNodeIndex = 0;
- bNodeExist = TRUE;
+ bNodeExist = true;
};
}
else {
if (pDevice->bEnableHostWEP) {
- if (BSSDBbIsSTAInNodeDB(pDevice->pMgmt, (PBYTE)(p80211Header->sA3.abyAddr1), &uNodeIndex))
- bNodeExist = TRUE;
+ if (BSSDBbIsSTAInNodeDB(pDevice->pMgmt, (unsigned char *)(p80211Header->sA3.abyAddr1), &uNodeIndex))
+ bNodeExist = true;
};
- bNeedACK = TRUE;
+ bNeedACK = true;
pTxBufHead->wFIFOCtl |= FIFOCTL_NEEDACK;
};
@@ -2964,7 +2922,7 @@ vDMA0_tx_80211(PSDevice pDevice, struct sk_buff *skb, PBYTE pbMPDU, UINT cbMPDU
// probe-response don't retry
//if ((p80211Header->sA4.wFrameCtl & TYPE_SUBTYPE_MASK) == TYPE_MGMT_PROBE_RSP) {
- // bNeedACK = FALSE;
+ // bNeedACK = false;
// pTxBufHead->wFIFOCtl &= (~FIFOCTL_NEEDACK);
//}
}
@@ -2972,7 +2930,7 @@ vDMA0_tx_80211(PSDevice pDevice, struct sk_buff *skb, PBYTE pbMPDU, UINT cbMPDU
pTxBufHead->wFIFOCtl |= (FIFOCTL_GENINT | FIFOCTL_ISDMA0);
if ((p80211Header->sA4.wFrameCtl & TYPE_SUBTYPE_MASK) == TYPE_CTL_PSPOLL) {
- bIsPSPOLL = TRUE;
+ bIsPSPOLL = true;
cbMacHdLen = WLAN_HDR_ADDR2_LEN;
} else {
cbMacHdLen = WLAN_HDR_ADDR3_LEN;
@@ -2996,12 +2954,12 @@ vDMA0_tx_80211(PSDevice pDevice, struct sk_buff *skb, PBYTE pbMPDU, UINT cbMPDU
//Set FRAGCTL_MACHDCNT
- pTxBufHead->wFragCtl |= cpu_to_le16((WORD)cbMacHdLen << 10);
+ pTxBufHead->wFragCtl |= cpu_to_le16((unsigned short)cbMacHdLen << 10);
// Notes:
// Although spec says MMPDU can be fragmented; In most case,
// no one will send a MMPDU under fragmentation. With RTS may occur.
- pDevice->bAES = FALSE; //Set FRAGCTL_WEPTYP
+ pDevice->bAES = false; //Set FRAGCTL_WEPTYP
if (WLAN_GET_FC_ISWEP(p80211Header->sA4.wFrameCtl) != 0) {
@@ -3024,7 +2982,7 @@ vDMA0_tx_80211(PSDevice pDevice, struct sk_buff *skb, PBYTE pbMPDU, UINT cbMPDU
cbICVlen = 8;//MIC
cbMICHDR = sizeof(SMICHDRHead);
pTxBufHead->wFragCtl |= FRAGCTL_AES;
- pDevice->bAES = TRUE;
+ pDevice->bAES = true;
}
//MAC Header should be padding 0 to DW alignment.
uPadding = 4 - (cbMacHdLen%4);
@@ -3034,7 +2992,7 @@ vDMA0_tx_80211(PSDevice pDevice, struct sk_buff *skb, PBYTE pbMPDU, UINT cbMPDU
cbFrameSize = cbMacHdLen + cbFrameBodySize + cbIVlen + cbMIClen + cbICVlen + cbFCSlen + cbExtSuppRate;
//Set FIFOCTL_GrpAckPolicy
- if (pDevice->bGrpAckPolicy == TRUE) {//0000 0100 0000 0000
+ if (pDevice->bGrpAckPolicy == true) {//0000 0100 0000 0000
pTxBufHead->wFIFOCtl |= FIFOCTL_GRPACK;
}
//the rest of pTxBufHead->wFragCtl:FragTyp will be set later in s_vFillFragParameter()
@@ -3067,7 +3025,7 @@ vDMA0_tx_80211(PSDevice pDevice, struct sk_buff *skb, PBYTE pbMPDU, UINT cbMPDU
//=========================
// No Fragmentation
//=========================
- pTxBufHead->wFragCtl |= (WORD)FRAGCTL_NONFRAG;
+ pTxBufHead->wFragCtl |= (unsigned short)FRAGCTL_NONFRAG;
//Fill FIFO,RrvTime,RTS,and CTS
@@ -3082,9 +3040,9 @@ vDMA0_tx_80211(PSDevice pDevice, struct sk_buff *skb, PBYTE pbMPDU, UINT cbMPDU
cbReqCount = cbHeaderSize + cbMacHdLen + uPadding + cbIVlen + (cbFrameBodySize + cbMIClen) + cbExtSuppRate;
- pbyMacHdr = (PBYTE)(pbyTxBufferAddr + cbHeaderSize);
- pbyPayloadHead = (PBYTE)(pbyMacHdr + cbMacHdLen + uPadding + cbIVlen);
- pbyIVHead = (PBYTE)(pbyMacHdr + cbMacHdLen + uPadding);
+ pbyMacHdr = (unsigned char *)(pbyTxBufferAddr + cbHeaderSize);
+ pbyPayloadHead = (unsigned char *)(pbyMacHdr + cbMacHdLen + uPadding + cbIVlen);
+ pbyIVHead = (unsigned char *)(pbyMacHdr + cbMacHdLen + uPadding);
// Copy the Packet into a tx Buffer
memcpy(pbyMacHdr, pbMPDU, cbMacHdLen);
@@ -3127,30 +3085,30 @@ vDMA0_tx_80211(PSDevice pDevice, struct sk_buff *skb, PBYTE pbMPDU, UINT cbMPDU
if ((pTransmitKey != NULL) && (pTransmitKey->byCipherSuite == KEY_CTL_TKIP)) {
- dwMICKey0 = *(PDWORD)(&pTransmitKey->abyKey[16]);
- dwMICKey1 = *(PDWORD)(&pTransmitKey->abyKey[20]);
+ dwMICKey0 = *(unsigned long *)(&pTransmitKey->abyKey[16]);
+ dwMICKey1 = *(unsigned long *)(&pTransmitKey->abyKey[20]);
// DO Software Michael
MIC_vInit(dwMICKey0, dwMICKey1);
- MIC_vAppend((PBYTE)&(sEthHeader.abyDstAddr[0]), 12);
+ MIC_vAppend((unsigned char *)&(sEthHeader.abyDstAddr[0]), 12);
dwMIC_Priority = 0;
- MIC_vAppend((PBYTE)&dwMIC_Priority, 4);
+ MIC_vAppend((unsigned char *)&dwMIC_Priority, 4);
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"DMA0_tx_8021:MIC KEY: %lX, %lX\n", dwMICKey0, dwMICKey1);
uLength = cbHeaderSize + cbMacHdLen + uPadding + cbIVlen;
MIC_vAppend((pbyTxBufferAddr + uLength), cbFrameBodySize);
- pdwMIC_L = (PDWORD)(pbyTxBufferAddr + uLength + cbFrameBodySize);
- pdwMIC_R = (PDWORD)(pbyTxBufferAddr + uLength + cbFrameBodySize + 4);
+ pdwMIC_L = (unsigned long *)(pbyTxBufferAddr + uLength + cbFrameBodySize);
+ pdwMIC_R = (unsigned long *)(pbyTxBufferAddr + uLength + cbFrameBodySize + 4);
MIC_vGetMIC(pdwMIC_L, pdwMIC_R);
MIC_vUnInit();
- if (pDevice->bTxMICFail == TRUE) {
+ if (pDevice->bTxMICFail == true) {
*pdwMIC_L = 0;
*pdwMIC_R = 0;
- pDevice->bTxMICFail = FALSE;
+ pDevice->bTxMICFail = false;
}
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"uLength: %d, %d\n", uLength, cbFrameBodySize);
@@ -3160,8 +3118,8 @@ vDMA0_tx_80211(PSDevice pDevice, struct sk_buff *skb, PBYTE pbMPDU, UINT cbMPDU
}
- s_vFillTxKey(pDevice, (PBYTE)(pTxBufHead->adwTxKey), pbyIVHead, pTransmitKey,
- pbyMacHdr, (WORD)cbFrameBodySize, (PBYTE)pMICHDR);
+ s_vFillTxKey(pDevice, (unsigned char *)(pTxBufHead->adwTxKey), pbyIVHead, pTransmitKey,
+ pbyMacHdr, (unsigned short)cbFrameBodySize, (unsigned char *)pMICHDR);
if (pDevice->bEnableHostWEP) {
pMgmt->sNodeDBTable[uNodeIndex].dwTSC47_16 = pTransmitKey->dwTSC47_16;
@@ -3169,7 +3127,7 @@ vDMA0_tx_80211(PSDevice pDevice, struct sk_buff *skb, PBYTE pbMPDU, UINT cbMPDU
}
if ((pDevice->byLocalID <= REV_ID_VT3253_A1)) {
- s_vSWencryption(pDevice, pTransmitKey, pbyPayloadHead, (WORD)(cbFrameBodySize + cbMIClen));
+ s_vSWencryption(pDevice, pTransmitKey, pbyPayloadHead, (unsigned short)(cbFrameBodySize + cbMIClen));
}
}
@@ -3208,7 +3166,7 @@ vDMA0_tx_80211(PSDevice pDevice, struct sk_buff *skb, PBYTE pbMPDU, UINT cbMPDU
// Disable PS
MACbPSWakeup(pDevice->PortOffset);
}
- pDevice->bPWBitOn = FALSE;
+ pDevice->bPWBitOn = false;
wmb();
pFrstTD->m_td0TD0.f1Owner = OWNED_BY_NIC;
diff --git a/drivers/staging/vt6655/rxtx.h b/drivers/staging/vt6655/rxtx.h
index b008fc23adb..fa827b828a3 100644
--- a/drivers/staging/vt6655/rxtx.h
+++ b/drivers/staging/vt6655/rxtx.h
@@ -40,67 +40,47 @@
/*--------------------- Export Functions --------------------------*/
/*
-void vGenerateMACHeader(
- PSDevice pDevice,
- DWORD dwTxBufferAddr,
- PBYTE pbySkbData,
- UINT cbPacketSize,
- BOOL bDMA0Used,
- PUINT pcbHeadSize,
- PUINT pcbAppendPayload
- );
-
-void vProcessRxMACHeader (
- PSDevice pDevice,
- DWORD dwRxBufferAddr,
- UINT cbPacketSize,
- BOOL bIsWEP,
- PUINT pcbHeadSize
- );
+void
+vGenerateMACHeader(PSDevice pDevice, unsigned long dwTxBufferAddr, unsigned char *pbySkbData,
+ unsigned int cbPacketSize, bool bDMA0Used, unsigned int *pcbHeadSize,
+ unsigned int *pcbAppendPayload);
+
+void
+vProcessRxMACHeader(PSDevice pDevice, unsigned long dwRxBufferAddr, unsigned int cbPacketSize,
+ bool bIsWEP, unsigned int *pcbHeadSize);
*/
void
vGenerateMACHeader (
PSDevice pDevice,
- PBYTE pbyBufferAddr,
- WORD wDuration,
+ unsigned char *pbyBufferAddr,
+ unsigned short wDuration,
PSEthernetHeader psEthHeader,
- BOOL bNeedEncrypt,
- WORD wFragType,
- UINT uDMAIdx,
- UINT uFragIdx
+ bool bNeedEncrypt,
+ unsigned short wFragType,
+ unsigned int uDMAIdx,
+ unsigned int uFragIdx
);
-UINT
+unsigned int
cbGetFragCount(
PSDevice pDevice,
PSKeyItem pTransmitKey,
- UINT cbFrameBodySize,
+ unsigned int cbFrameBodySize,
PSEthernetHeader psEthHeader
);
void
-vGenerateFIFOHeader (
- PSDevice pDevice,
- BYTE byPktTyp,
- PBYTE pbyTxBufferAddr,
- BOOL bNeedEncrypt,
- UINT cbPayloadSize,
- UINT uDMAIdx,
- PSTxDesc pHeadTD,
- PSEthernetHeader psEthHeader,
- PBYTE pPacket,
- PSKeyItem pTransmitKey,
- UINT uNodeIndex,
- PUINT puMACfragNum,
- PUINT pcbHeaderSize
- );
+vGenerateFIFOHeader(PSDevice pDevice, unsigned char byPktTyp, unsigned char *pbyTxBufferAddr,
+ bool bNeedEncrypt, unsigned int cbPayloadSize, unsigned int uDMAIdx, PSTxDesc pHeadTD,
+ PSEthernetHeader psEthHeader, unsigned char *pPacket, PSKeyItem pTransmitKey,
+ unsigned int uNodeIndex, unsigned int *puMACfragNum, unsigned int *pcbHeaderSize);
-void vDMA0_tx_80211(PSDevice pDevice, struct sk_buff *skb, PBYTE pbMPDU, UINT cbMPDULen);
+void vDMA0_tx_80211(PSDevice pDevice, struct sk_buff *skb, unsigned char *pbMPDU, unsigned int cbMPDULen);
CMD_STATUS csMgmt_xmit(PSDevice pDevice, PSTxMgmtPacket pPacket);
CMD_STATUS csBeacon_xmit(PSDevice pDevice, PSTxMgmtPacket pPacket);
diff --git a/drivers/staging/vt6655/srom.c b/drivers/staging/vt6655/srom.c
index 418575fdc2c..6a0a232d1a0 100644
--- a/drivers/staging/vt6655/srom.c
+++ b/drivers/staging/vt6655/srom.c
@@ -76,12 +76,12 @@
* Return Value: data read
*
*/
-BYTE SROMbyReadEmbedded(DWORD_PTR dwIoBase, BYTE byContntOffset)
+unsigned char SROMbyReadEmbedded(unsigned long dwIoBase, unsigned char byContntOffset)
{
- WORD wDelay, wNoACK;
- BYTE byWait;
- BYTE byData;
- BYTE byOrg;
+ unsigned short wDelay, wNoACK;
+ unsigned char byWait;
+ unsigned char byData;
+ unsigned char byOrg;
byData = 0xFF;
VNSvInPortB(dwIoBase + MAC_REG_I2MCFG, &byOrg);
@@ -122,15 +122,15 @@ BYTE SROMbyReadEmbedded(DWORD_PTR dwIoBase, BYTE byContntOffset)
* Out:
* none
*
- * Return Value: TRUE if succeeded; FALSE if failed.
+ * Return Value: true if succeeded; false if failed.
*
*/
-BOOL SROMbWriteEmbedded(DWORD_PTR dwIoBase, BYTE byContntOffset, BYTE byData)
+bool SROMbWriteEmbedded(unsigned long dwIoBase, unsigned char byContntOffset, unsigned char byData)
{
- WORD wDelay, wNoACK;
- BYTE byWait;
+ unsigned short wDelay, wNoACK;
+ unsigned char byWait;
- BYTE byOrg;
+ unsigned char byOrg;
VNSvInPortB(dwIoBase + MAC_REG_I2MCFG, &byOrg);
/* turn off hardware retry for getting NACK */
@@ -157,10 +157,10 @@ BOOL SROMbWriteEmbedded(DWORD_PTR dwIoBase, BYTE byContntOffset, BYTE byData)
}
if (wNoACK == W_MAX_I2CRETRY) {
VNSvOutPortB(dwIoBase + MAC_REG_I2MCFG, byOrg);
- return FALSE;
+ return false;
}
VNSvOutPortB(dwIoBase + MAC_REG_I2MCFG, byOrg);
- return TRUE;
+ return true;
}
@@ -178,12 +178,12 @@ BOOL SROMbWriteEmbedded(DWORD_PTR dwIoBase, BYTE byContntOffset, BYTE byData)
* Return Value: none
*
*/
-void SROMvRegBitsOn(DWORD_PTR dwIoBase, BYTE byContntOffset, BYTE byBits)
+void SROMvRegBitsOn(unsigned long dwIoBase, unsigned char byContntOffset, unsigned char byBits)
{
- BYTE byOrgData;
+ unsigned char byOrgData;
byOrgData = SROMbyReadEmbedded(dwIoBase, byContntOffset);
- SROMbWriteEmbedded(dwIoBase, byContntOffset,(BYTE)(byOrgData | byBits));
+ SROMbWriteEmbedded(dwIoBase, byContntOffset,(unsigned char)(byOrgData | byBits));
}
@@ -199,12 +199,12 @@ void SROMvRegBitsOn(DWORD_PTR dwIoBase, BYTE byContntOffset, BYTE byBits)
* none
*
*/
-void SROMvRegBitsOff(DWORD_PTR dwIoBase, BYTE byContntOffset, BYTE byBits)
+void SROMvRegBitsOff(unsigned long dwIoBase, unsigned char byContntOffset, unsigned char byBits)
{
- BYTE byOrgData;
+ unsigned char byOrgData;
byOrgData = SROMbyReadEmbedded(dwIoBase, byContntOffset);
- SROMbWriteEmbedded(dwIoBase, byContntOffset,(BYTE)(byOrgData & (~byBits)));
+ SROMbWriteEmbedded(dwIoBase, byContntOffset,(unsigned char)(byOrgData & (~byBits)));
}
@@ -219,12 +219,12 @@ void SROMvRegBitsOff(DWORD_PTR dwIoBase, BYTE byContntOffset, BYTE byBits)
* Out:
* none
*
- * Return Value: TRUE if all test bits on; otherwise FALSE
+ * Return Value: true if all test bits on; otherwise false
*
*/
-BOOL SROMbIsRegBitsOn(DWORD_PTR dwIoBase, BYTE byContntOffset, BYTE byTestBits)
+bool SROMbIsRegBitsOn(unsigned long dwIoBase, unsigned char byContntOffset, unsigned char byTestBits)
{
- BYTE byOrgData;
+ unsigned char byOrgData;
byOrgData = SROMbyReadEmbedded(dwIoBase, byContntOffset);
return (byOrgData & byTestBits) == byTestBits;
@@ -242,12 +242,12 @@ BOOL SROMbIsRegBitsOn(DWORD_PTR dwIoBase, BYTE byContntOffset, BYTE byTestBits)
* Out:
* none
*
- * Return Value: TRUE if all test bits off; otherwise FALSE
+ * Return Value: true if all test bits off; otherwise false
*
*/
-BOOL SROMbIsRegBitsOff(DWORD_PTR dwIoBase, BYTE byContntOffset, BYTE byTestBits)
+bool SROMbIsRegBitsOff(unsigned long dwIoBase, unsigned char byContntOffset, unsigned char byTestBits)
{
- BYTE byOrgData;
+ unsigned char byOrgData;
byOrgData = SROMbyReadEmbedded(dwIoBase, byContntOffset);
return !(byOrgData & byTestBits);
@@ -266,13 +266,13 @@ BOOL SROMbIsRegBitsOff(DWORD_PTR dwIoBase, BYTE byContntOffset, BYTE byTestBits)
* Return Value: none
*
*/
-void SROMvReadAllContents(DWORD_PTR dwIoBase, PBYTE pbyEepromRegs)
+void SROMvReadAllContents(unsigned long dwIoBase, unsigned char *pbyEepromRegs)
{
int ii;
/* ii = Rom Address */
for (ii = 0; ii < EEP_MAX_CONTEXT_SIZE; ii++) {
- *pbyEepromRegs = SROMbyReadEmbedded(dwIoBase,(BYTE) ii);
+ *pbyEepromRegs = SROMbyReadEmbedded(dwIoBase,(unsigned char) ii);
pbyEepromRegs++;
}
}
@@ -291,13 +291,13 @@ void SROMvReadAllContents(DWORD_PTR dwIoBase, PBYTE pbyEepromRegs)
* Return Value: none
*
*/
-void SROMvWriteAllContents(DWORD_PTR dwIoBase, PBYTE pbyEepromRegs)
+void SROMvWriteAllContents(unsigned long dwIoBase, unsigned char *pbyEepromRegs)
{
int ii;
/* ii = Rom Address */
for (ii = 0; ii < EEP_MAX_CONTEXT_SIZE; ii++) {
- SROMbWriteEmbedded(dwIoBase,(BYTE) ii, *pbyEepromRegs);
+ SROMbWriteEmbedded(dwIoBase,(unsigned char) ii, *pbyEepromRegs);
pbyEepromRegs++;
}
}
@@ -315,9 +315,9 @@ void SROMvWriteAllContents(DWORD_PTR dwIoBase, PBYTE pbyEepromRegs)
* Return Value: none
*
*/
-void SROMvReadEtherAddress(DWORD_PTR dwIoBase, PBYTE pbyEtherAddress)
+void SROMvReadEtherAddress(unsigned long dwIoBase, unsigned char *pbyEtherAddress)
{
- BYTE ii;
+ unsigned char ii;
/* ii = Rom Address */
for (ii = 0; ii < ETH_ALEN; ii++) {
@@ -340,9 +340,9 @@ void SROMvReadEtherAddress(DWORD_PTR dwIoBase, PBYTE pbyEtherAddress)
* Return Value: none
*
*/
-void SROMvWriteEtherAddress(DWORD_PTR dwIoBase, PBYTE pbyEtherAddress)
+void SROMvWriteEtherAddress(unsigned long dwIoBase, unsigned char *pbyEtherAddress)
{
- BYTE ii;
+ unsigned char ii;
/* ii = Rom Address */
for (ii = 0; ii < ETH_ALEN; ii++) {
@@ -364,11 +364,11 @@ void SROMvWriteEtherAddress(DWORD_PTR dwIoBase, PBYTE pbyEtherAddress)
* Return Value: none
*
*/
-void SROMvReadSubSysVenId(DWORD_PTR dwIoBase, PDWORD pdwSubSysVenId)
+void SROMvReadSubSysVenId(unsigned long dwIoBase, unsigned long *pdwSubSysVenId)
{
- PBYTE pbyData;
+ unsigned char *pbyData;
- pbyData = (PBYTE)pdwSubSysVenId;
+ pbyData = (unsigned char *)pdwSubSysVenId;
/* sub vendor */
*pbyData = SROMbyReadEmbedded(dwIoBase, 6);
*(pbyData+1) = SROMbyReadEmbedded(dwIoBase, 7);
@@ -386,15 +386,15 @@ void SROMvReadSubSysVenId(DWORD_PTR dwIoBase, PDWORD pdwSubSysVenId)
* Out:
* none
*
- * Return Value: TRUE if success; otherwise FALSE
+ * Return Value: true if success; otherwise false
*
*/
-BOOL SROMbAutoLoad(DWORD_PTR dwIoBase)
+bool SROMbAutoLoad(unsigned long dwIoBase)
{
- BYTE byWait;
+ unsigned char byWait;
int ii;
- BYTE byOrg;
+ unsigned char byOrg;
VNSvInPortB(dwIoBase + MAC_REG_I2MCFG, &byOrg);
/* turn on hardware retry */
@@ -413,8 +413,8 @@ BOOL SROMbAutoLoad(DWORD_PTR dwIoBase)
VNSvOutPortB(dwIoBase + MAC_REG_I2MCFG, byOrg);
if (ii == EEP_MAX_CONTEXT_SIZE)
- return FALSE;
- return TRUE;
+ return false;
+ return true;
}
diff --git a/drivers/staging/vt6655/srom.h b/drivers/staging/vt6655/srom.h
index dbb3f5efe97..4c261dac01b 100644
--- a/drivers/staging/vt6655/srom.h
+++ b/drivers/staging/vt6655/srom.h
@@ -97,34 +97,34 @@
// 2048 bits = 256 bytes = 128 words
//
typedef struct tagSSromReg {
- BYTE abyPAR[6]; // 0x00 (WORD)
-
- WORD wSUB_VID; // 0x03 (WORD)
- WORD wSUB_SID;
-
- BYTE byBCFG0; // 0x05 (WORD)
- BYTE byBCFG1;
-
- BYTE byFCR0; // 0x06 (WORD)
- BYTE byFCR1;
- BYTE byPMC0; // 0x07 (WORD)
- BYTE byPMC1;
- BYTE byMAXLAT; // 0x08 (WORD)
- BYTE byMINGNT;
- BYTE byCFG0; // 0x09 (WORD)
- BYTE byCFG1;
- WORD wCISPTR; // 0x0A (WORD)
- WORD wRsv0; // 0x0B (WORD)
- WORD wRsv1; // 0x0C (WORD)
- BYTE byBBPAIR; // 0x0D (WORD)
- BYTE byRFTYPE;
- BYTE byMinChannel; // 0x0E (WORD)
- BYTE byMaxChannel;
- BYTE bySignature; // 0x0F (WORD)
- BYTE byCheckSum;
-
- BYTE abyReserved0[96]; // 0x10 (WORD)
- BYTE abyCIS[128]; // 0x80 (WORD)
+ unsigned char abyPAR[6]; // 0x00 (unsigned short)
+
+ unsigned short wSUB_VID; // 0x03 (unsigned short)
+ unsigned short wSUB_SID;
+
+ unsigned char byBCFG0; // 0x05 (unsigned short)
+ unsigned char byBCFG1;
+
+ unsigned char byFCR0; // 0x06 (unsigned short)
+ unsigned char byFCR1;
+ unsigned char byPMC0; // 0x07 (unsigned short)
+ unsigned char byPMC1;
+ unsigned char byMAXLAT; // 0x08 (unsigned short)
+ unsigned char byMINGNT;
+ unsigned char byCFG0; // 0x09 (unsigned short)
+ unsigned char byCFG1;
+ unsigned short wCISPTR; // 0x0A (unsigned short)
+ unsigned short wRsv0; // 0x0B (unsigned short)
+ unsigned short wRsv1; // 0x0C (unsigned short)
+ unsigned char byBBPAIR; // 0x0D (unsigned short)
+ unsigned char byRFTYPE;
+ unsigned char byMinChannel; // 0x0E (unsigned short)
+ unsigned char byMaxChannel;
+ unsigned char bySignature; // 0x0F (unsigned short)
+ unsigned char byCheckSum;
+
+ unsigned char abyReserved0[96]; // 0x10 (unsigned short)
+ unsigned char abyCIS[128]; // 0x80 (unsigned short)
} SSromReg, *PSSromReg;
/*--------------------- Export Macros ------------------------------*/
@@ -135,23 +135,23 @@ typedef struct tagSSromReg {
/*--------------------- Export Functions --------------------------*/
-BYTE SROMbyReadEmbedded(DWORD_PTR dwIoBase, BYTE byContntOffset);
-BOOL SROMbWriteEmbedded(DWORD_PTR dwIoBase, BYTE byContntOffset, BYTE byData);
+unsigned char SROMbyReadEmbedded(unsigned long dwIoBase, unsigned char byContntOffset);
+bool SROMbWriteEmbedded(unsigned long dwIoBase, unsigned char byContntOffset, unsigned char byData);
-void SROMvRegBitsOn(DWORD_PTR dwIoBase, BYTE byContntOffset, BYTE byBits);
-void SROMvRegBitsOff(DWORD_PTR dwIoBase, BYTE byContntOffset, BYTE byBits);
+void SROMvRegBitsOn(unsigned long dwIoBase, unsigned char byContntOffset, unsigned char byBits);
+void SROMvRegBitsOff(unsigned long dwIoBase, unsigned char byContntOffset, unsigned char byBits);
-BOOL SROMbIsRegBitsOn(DWORD_PTR dwIoBase, BYTE byContntOffset, BYTE byTestBits);
-BOOL SROMbIsRegBitsOff(DWORD_PTR dwIoBase, BYTE byContntOffset, BYTE byTestBits);
+bool SROMbIsRegBitsOn(unsigned long dwIoBase, unsigned char byContntOffset, unsigned char byTestBits);
+bool SROMbIsRegBitsOff(unsigned long dwIoBase, unsigned char byContntOffset, unsigned char byTestBits);
-void SROMvReadAllContents(DWORD_PTR dwIoBase, PBYTE pbyEepromRegs);
-void SROMvWriteAllContents(DWORD_PTR dwIoBase, PBYTE pbyEepromRegs);
+void SROMvReadAllContents(unsigned long dwIoBase, unsigned char *pbyEepromRegs);
+void SROMvWriteAllContents(unsigned long dwIoBase, unsigned char *pbyEepromRegs);
-void SROMvReadEtherAddress(DWORD_PTR dwIoBase, PBYTE pbyEtherAddress);
-void SROMvWriteEtherAddress(DWORD_PTR dwIoBase, PBYTE pbyEtherAddress);
+void SROMvReadEtherAddress(unsigned long dwIoBase, unsigned char *pbyEtherAddress);
+void SROMvWriteEtherAddress(unsigned long dwIoBase, unsigned char *pbyEtherAddress);
-void SROMvReadSubSysVenId(DWORD_PTR dwIoBase, PDWORD pdwSubSysVenId);
+void SROMvReadSubSysVenId(unsigned long dwIoBase, unsigned long *pdwSubSysVenId);
-BOOL SROMbAutoLoad (DWORD_PTR dwIoBase);
+bool SROMbAutoLoad (unsigned long dwIoBase);
#endif // __EEPROM_H__
diff --git a/drivers/staging/vt6655/tcrc.c b/drivers/staging/vt6655/tcrc.c
index 5f0c74763f8..f9c28bf8a6a 100644
--- a/drivers/staging/vt6655/tcrc.c
+++ b/drivers/staging/vt6655/tcrc.c
@@ -42,7 +42,7 @@
/*--------------------- Static Variables --------------------------*/
// 32-bit CRC table
-static const DWORD s_adwCrc32Table[256] = {
+static const unsigned long s_adwCrc32Table[256] = {
0x00000000L, 0x77073096L, 0xEE0E612CL, 0x990951BAL,
0x076DC419L, 0x706AF48FL, 0xE963A535L, 0x9E6495A3L,
0x0EDB8832L, 0x79DCB8A4L, 0xE0D5E91EL, 0x97D2D988L,
@@ -132,13 +132,13 @@ static const DWORD s_adwCrc32Table[256] = {
* Return Value: CRC-32
*
-*/
-DWORD CRCdwCrc32 (PBYTE pbyData, UINT cbByte, DWORD dwCrcSeed)
+unsigned long CRCdwCrc32 (unsigned char *pbyData, unsigned int cbByte, unsigned long dwCrcSeed)
{
- DWORD dwCrc;
+ unsigned long dwCrc;
dwCrc = dwCrcSeed;
while (cbByte--) {
- dwCrc = s_adwCrc32Table[(BYTE)((dwCrc ^ (*pbyData)) & 0xFF)] ^ (dwCrc >> 8);
+ dwCrc = s_adwCrc32Table[(unsigned char)((dwCrc ^ (*pbyData)) & 0xFF)] ^ (dwCrc >> 8);
pbyData++;
}
@@ -164,7 +164,7 @@ DWORD CRCdwCrc32 (PBYTE pbyData, UINT cbByte, DWORD dwCrcSeed)
* Return Value: CRC-32
*
-*/
-DWORD CRCdwGetCrc32 (PBYTE pbyData, UINT cbByte)
+unsigned long CRCdwGetCrc32 (unsigned char *pbyData, unsigned int cbByte)
{
return ~CRCdwCrc32(pbyData, cbByte, 0xFFFFFFFFL);
}
@@ -190,7 +190,7 @@ DWORD CRCdwGetCrc32 (PBYTE pbyData, UINT cbByte)
* Return Value: CRC-32
*
-*/
-DWORD CRCdwGetCrc32Ex(PBYTE pbyData, UINT cbByte, DWORD dwPreCRC)
+unsigned long CRCdwGetCrc32Ex(unsigned char *pbyData, unsigned int cbByte, unsigned long dwPreCRC)
{
return CRCdwCrc32(pbyData, cbByte, dwPreCRC);
}
diff --git a/drivers/staging/vt6655/tcrc.h b/drivers/staging/vt6655/tcrc.h
index 5faa48b0a74..d0449855beb 100644
--- a/drivers/staging/vt6655/tcrc.h
+++ b/drivers/staging/vt6655/tcrc.h
@@ -43,9 +43,9 @@
/*--------------------- Export Functions --------------------------*/
-DWORD CRCdwCrc32(PBYTE pbyData, UINT cbByte, DWORD dwCrcSeed);
-DWORD CRCdwGetCrc32(PBYTE pbyData, UINT cbByte);
-DWORD CRCdwGetCrc32Ex(PBYTE pbyData, UINT cbByte, DWORD dwPreCRC);
+unsigned long CRCdwCrc32(unsigned char *pbyData, unsigned int cbByte, unsigned long dwCrcSeed);
+unsigned long CRCdwGetCrc32(unsigned char *pbyData, unsigned int cbByte);
+unsigned long CRCdwGetCrc32Ex(unsigned char *pbyData, unsigned int cbByte, unsigned long dwPreCRC);
#endif // __TCRC_H__
diff --git a/drivers/staging/vt6655/tether.c b/drivers/staging/vt6655/tether.c
index d8ba67395cb..1cf8508e407 100644
--- a/drivers/staging/vt6655/tether.c
+++ b/drivers/staging/vt6655/tether.c
@@ -61,14 +61,14 @@
* Return Value: Hash value
*
*/
-BYTE ETHbyGetHashIndexByCrc32 (PBYTE pbyMultiAddr)
+unsigned char ETHbyGetHashIndexByCrc32 (unsigned char *pbyMultiAddr)
{
int ii;
- BYTE byTmpHash;
- BYTE byHash = 0;
+ unsigned char byTmpHash;
+ unsigned char byHash = 0;
// get the least 6-bits from CRC generator
- byTmpHash = (BYTE)(CRCdwCrc32(pbyMultiAddr, ETH_ALEN,
+ byTmpHash = (unsigned char)(CRCdwCrc32(pbyMultiAddr, ETH_ALEN,
0xFFFFFFFFL) & 0x3F);
// reverse most bit to least bit
for (ii = 0; ii < (sizeof(byTmpHash) * 8); ii++) {
@@ -93,17 +93,17 @@ BYTE ETHbyGetHashIndexByCrc32 (PBYTE pbyMultiAddr)
* Out:
* none
*
- * Return Value: TRUE if ok; FALSE if error.
+ * Return Value: true if ok; false if error.
*
*/
-BOOL ETHbIsBufferCrc32Ok (PBYTE pbyBuffer, UINT cbFrameLength)
+bool ETHbIsBufferCrc32Ok (unsigned char *pbyBuffer, unsigned int cbFrameLength)
{
- DWORD dwCRC;
+ unsigned long dwCRC;
dwCRC = CRCdwGetCrc32(pbyBuffer, cbFrameLength - 4);
- if (cpu_to_le32(*((PDWORD)(pbyBuffer + cbFrameLength - 4))) != dwCRC) {
- return FALSE;
+ if (cpu_to_le32(*((unsigned long *)(pbyBuffer + cbFrameLength - 4))) != dwCRC) {
+ return false;
}
- return TRUE;
+ return true;
}
diff --git a/drivers/staging/vt6655/tether.h b/drivers/staging/vt6655/tether.h
index 3c9acd7903a..787d885deee 100644
--- a/drivers/staging/vt6655/tether.h
+++ b/drivers/staging/vt6655/tether.h
@@ -29,7 +29,7 @@
#ifndef __TETHER_H__
#define __TETHER_H__
-#include <linux/if_ether.h>
+#include <linux/etherdevice.h>
#include "ttype.h"
/*--------------------- Export Definitions -------------------------*/
@@ -39,12 +39,6 @@
#define U_ETHER_ADDR_STR_LEN (ETH_ALEN * 2 + 1)
// Ethernet address string length
-#define MIN_DATA_LEN 46 // min data length
-
-#define MIN_PACKET_LEN (MIN_DATA_LEN + ETH_HLEN)
- // 60
- // min total packet length (tx)
-
#define MAX_LOOKAHEAD_SIZE ETH_FRAME_LEN
#define U_MULTI_ADDR_LEN 8 // multicast address length
@@ -160,9 +154,9 @@
// Ethernet packet
//
typedef struct tagSEthernetHeader {
- BYTE abyDstAddr[ETH_ALEN];
- BYTE abySrcAddr[ETH_ALEN];
- WORD wType;
+ unsigned char abyDstAddr[ETH_ALEN];
+ unsigned char abySrcAddr[ETH_ALEN];
+ unsigned short wType;
}__attribute__ ((__packed__))
SEthernetHeader, *PSEthernetHeader;
@@ -171,9 +165,9 @@ SEthernetHeader, *PSEthernetHeader;
// 802_3 packet
//
typedef struct tagS802_3Header {
- BYTE abyDstAddr[ETH_ALEN];
- BYTE abySrcAddr[ETH_ALEN];
- WORD wLen;
+ unsigned char abyDstAddr[ETH_ALEN];
+ unsigned char abySrcAddr[ETH_ALEN];
+ unsigned short wLen;
}__attribute__ ((__packed__))
S802_3Header, *PS802_3Header;
@@ -181,37 +175,17 @@ S802_3Header, *PS802_3Header;
// 802_11 packet
//
typedef struct tagS802_11Header {
- WORD wFrameCtl;
- WORD wDurationID;
- BYTE abyAddr1[ETH_ALEN];
- BYTE abyAddr2[ETH_ALEN];
- BYTE abyAddr3[ETH_ALEN];
- WORD wSeqCtl;
- BYTE abyAddr4[ETH_ALEN];
+ unsigned short wFrameCtl;
+ unsigned short wDurationID;
+ unsigned char abyAddr1[ETH_ALEN];
+ unsigned char abyAddr2[ETH_ALEN];
+ unsigned char abyAddr3[ETH_ALEN];
+ unsigned short wSeqCtl;
+ unsigned char abyAddr4[ETH_ALEN];
}__attribute__ ((__packed__))
S802_11Header, *PS802_11Header;
/*--------------------- Export Macros ------------------------------*/
-// Frame type macro
-
-#define IS_MULTICAST_ADDRESS(pbyEtherAddr) \
- ((*(PBYTE)(pbyEtherAddr) & 0x01) == 1)
-
-#define IS_BROADCAST_ADDRESS(pbyEtherAddr) ( \
- (*(PDWORD)(pbyEtherAddr) == 0xFFFFFFFFL) && \
- (*(PWORD)((PBYTE)(pbyEtherAddr) + 4) == 0xFFFF) \
-)
-
-#define IS_NULL_ADDRESS(pbyEtherAddr) ( \
- (*(PDWORD)(pbyEtherAddr) == 0L) && \
- (*(PWORD)((PBYTE)(pbyEtherAddr) + 4) == 0) \
-)
-
-#define IS_ETH_ADDRESS_EQUAL(pbyAddr1, pbyAddr2) ( \
- (*(PDWORD)(pbyAddr1) == *(PDWORD)(pbyAddr2)) && \
- (*(PWORD)((PBYTE)(pbyAddr1) + 4) == \
- *(PWORD)((PBYTE)(pbyAddr2) + 4)) \
-)
/*--------------------- Export Classes ----------------------------*/
@@ -219,9 +193,9 @@ S802_11Header, *PS802_11Header;
/*--------------------- Export Functions --------------------------*/
-BYTE ETHbyGetHashIndexByCrc32(PBYTE pbyMultiAddr);
-//BYTE ETHbyGetHashIndexByCrc(PBYTE pbyMultiAddr);
-BOOL ETHbIsBufferCrc32Ok(PBYTE pbyBuffer, UINT cbFrameLength);
+unsigned char ETHbyGetHashIndexByCrc32(unsigned char *pbyMultiAddr);
+//unsigned char ETHbyGetHashIndexByCrc(unsigned char *pbyMultiAddr);
+bool ETHbIsBufferCrc32Ok(unsigned char *pbyBuffer, unsigned int cbFrameLength);
#endif // __TETHER_H__
diff --git a/drivers/staging/vt6655/tkip.c b/drivers/staging/vt6655/tkip.c
index f83af5913aa..ed3eac17ae8 100644
--- a/drivers/staging/vt6655/tkip.c
+++ b/drivers/staging/vt6655/tkip.c
@@ -55,7 +55,7 @@
/* The 2nd table is the same as the 1st but with the upper and lower */
/* bytes swapped. To allow an endian tolerant implementation, the byte */
/* halves have been expressed independently here. */
-const BYTE TKIP_Sbox_Lower[256] = {
+const unsigned char TKIP_Sbox_Lower[256] = {
0xA5,0x84,0x99,0x8D,0x0D,0xBD,0xB1,0x54,
0x50,0x03,0xA9,0x7D,0x19,0x62,0xE6,0x9A,
0x45,0x9D,0x40,0x87,0x15,0xEB,0xC9,0x0B,
@@ -90,7 +90,7 @@ const BYTE TKIP_Sbox_Lower[256] = {
0xC3,0xB0,0x77,0x11,0xCB,0xFC,0xD6,0x3A
};
-const BYTE TKIP_Sbox_Upper[256] = {
+const unsigned char TKIP_Sbox_Upper[256] = {
0xC6,0xF8,0xEE,0xF6,0xFF,0xD6,0xDE,0x91,
0x60,0x02,0xCE,0x56,0xE7,0xB5,0x4D,0xEC,
0x8F,0x1F,0x89,0xFA,0xEF,0xB2,0x8E,0xFB,
@@ -184,11 +184,11 @@ unsigned int rotr1(unsigned int a)
*
*/
void TKIPvMixKey(
- PBYTE pbyTKey,
- PBYTE pbyTA,
- WORD wTSC15_0,
- DWORD dwTSC47_16,
- PBYTE pbyRC4Key
+ unsigned char *pbyTKey,
+ unsigned char *pbyTA,
+ unsigned short wTSC15_0,
+ unsigned long dwTSC47_16,
+ unsigned char *pbyRC4Key
)
{
unsigned int p1k[5];
diff --git a/drivers/staging/vt6655/tkip.h b/drivers/staging/vt6655/tkip.h
index 3dfa7f5ee7e..eb5951d726e 100644
--- a/drivers/staging/vt6655/tkip.h
+++ b/drivers/staging/vt6655/tkip.h
@@ -47,11 +47,11 @@
/*--------------------- Export Functions --------------------------*/
void TKIPvMixKey(
- PBYTE pbyTKey,
- PBYTE pbyTA,
- WORD wTSC15_0,
- DWORD dwTSC47_16,
- PBYTE pbyRC4Key
+ unsigned char *pbyTKey,
+ unsigned char *pbyTA,
+ unsigned short wTSC15_0,
+ unsigned long dwTSC47_16,
+ unsigned char *pbyRC4Key
);
#endif // __TKIP_H__
diff --git a/drivers/staging/vt6655/tmacro.h b/drivers/staging/vt6655/tmacro.h
index e96c140de05..e8b177d4128 100644
--- a/drivers/staging/vt6655/tmacro.h
+++ b/drivers/staging/vt6655/tmacro.h
@@ -34,27 +34,27 @@
/****** Common helper macros ***********************************************/
#if !defined(LOBYTE)
-#define LOBYTE(w) ((BYTE)(w))
+#define LOBYTE(w) ((unsigned char)(w))
#endif
#if !defined(HIBYTE)
-#define HIBYTE(w) ((BYTE)(((WORD)(w) >> 8) & 0xFF))
+#define HIBYTE(w) ((unsigned char)(((unsigned short)(w) >> 8) & 0xFF))
#endif
#if !defined(LOWORD)
-#define LOWORD(d) ((WORD)(d))
+#define LOWORD(d) ((unsigned short)(d))
#endif
#if !defined(HIWORD)
-#define HIWORD(d) ((WORD)((((DWORD)(d)) >> 16) & 0xFFFF))
+#define HIWORD(d) ((unsigned short)((((unsigned long)(d)) >> 16) & 0xFFFF))
#endif
#define LODWORD(q) ((q).u.dwLowDword)
#define HIDWORD(q) ((q).u.dwHighDword)
#if !defined(MAKEWORD)
-#define MAKEWORD(lb, hb) ((WORD)(((BYTE)(lb)) | (((WORD)((BYTE)(hb))) << 8)))
+#define MAKEWORD(lb, hb) ((unsigned short)(((unsigned char)(lb)) | (((unsigned short)((unsigned char)(hb))) << 8)))
#endif
#if !defined(MAKEDWORD)
-#define MAKEDWORD(lw, hw) ((DWORD)(((WORD)(lw)) | (((DWORD)((WORD)(hw))) << 16)))
+#define MAKEDWORD(lw, hw) ((unsigned long)(((unsigned short)(lw)) | (((unsigned long)((unsigned short)(hw))) << 16)))
#endif
#endif // __TMACRO_H__
diff --git a/drivers/staging/vt6655/ttype.h b/drivers/staging/vt6655/ttype.h
index 2921083a9f2..37c8fba1fd1 100644
--- a/drivers/staging/vt6655/ttype.h
+++ b/drivers/staging/vt6655/ttype.h
@@ -33,23 +33,10 @@
/******* Common definitions and typedefs ***********************************/
-#ifndef OUT
-#define OUT
-#endif
-
#ifndef TxInSleep
#define TxInSleep
#endif
-typedef int BOOL;
-
-#if !defined(TRUE)
-#define TRUE 1
-#endif
-#if !defined(FALSE)
-#define FALSE 0
-#endif
-
//2007-0809-01<Add>by MikeLiu
#ifndef update_BssList
#define update_BssList
@@ -65,10 +52,6 @@ typedef int BOOL;
#define Calcu_LinkQual
#endif
-#ifndef Calcu_LinkQual
-#define Calcu_LinkQual
-#endif
-
/****** Simple typedefs ***************************************************/
/* These lines assume that your compiler's longs are 32 bits and
@@ -76,37 +59,13 @@ typedef int BOOL;
* but it doesn't matter if they're signed or unsigned.
*/
-typedef signed char I8; /* 8-bit signed integer */
-
-typedef unsigned char U8; /* 8-bit unsigned integer */
-typedef unsigned short U16; /* 16-bit unsigned integer */
-typedef unsigned long U32; /* 32-bit unsigned integer */
-
-
-typedef char CHAR;
-typedef signed short SHORT;
-typedef signed int INT;
-typedef signed long LONG;
-
-typedef unsigned char UCHAR;
-typedef unsigned short USHORT;
-typedef unsigned int UINT;
-typedef unsigned long ULONG;
-typedef unsigned long long ULONGLONG; //64 bit
-
-
-
-typedef unsigned char BYTE; // 8-bit
-typedef unsigned short WORD; // 16-bit
-typedef unsigned long DWORD; // 32-bit
-
// QWORD is for those situation that we want
// an 8-byte-aligned 8 byte long structure
// which is NOT really a floating point number.
typedef union tagUQuadWord {
struct {
- DWORD dwLowDword;
- DWORD dwHighDword;
+ unsigned int dwLowDword;
+ unsigned int dwHighDword;
} u;
double DoNotUseThisField;
} UQuadWord;
@@ -114,18 +73,6 @@ typedef UQuadWord QWORD; // 64-bit
/****** Common pointer types ***********************************************/
-typedef unsigned long ULONG_PTR; // 32-bit
-typedef unsigned long DWORD_PTR; // 32-bit
-
-// boolean pointer
-typedef unsigned int * PUINT;
-
-typedef BYTE * PBYTE;
-
-typedef WORD * PWORD;
-
-typedef DWORD * PDWORD;
-
typedef QWORD * PQWORD;
#endif // __TTYPE_H__
diff --git a/drivers/staging/vt6655/upc.h b/drivers/staging/vt6655/upc.h
index acd1b661490..9596fdef0e3 100644
--- a/drivers/staging/vt6655/upc.h
+++ b/drivers/staging/vt6655/upc.h
@@ -76,36 +76,36 @@
#define VNSvInPortB(dwIOAddress, pbyData) { \
- volatile BYTE* pbyAddr = ((PBYTE)(dwIOAddress)); \
+ volatile unsigned char * pbyAddr = ((unsigned char *)(dwIOAddress)); \
*(pbyData) = readb(pbyAddr); \
}
#define VNSvInPortW(dwIOAddress, pwData) { \
- volatile WORD* pwAddr = ((PWORD)(dwIOAddress)); \
+ volatile unsigned short *pwAddr = ((unsigned short *)(dwIOAddress)); \
*(pwData) = readw(pwAddr); \
}
#define VNSvInPortD(dwIOAddress, pdwData) { \
- volatile DWORD* pdwAddr = ((PDWORD)(dwIOAddress)); \
+ volatile unsigned long *pdwAddr = ((unsigned long *)(dwIOAddress)); \
*(pdwData) = readl(pdwAddr); \
}
#define VNSvOutPortB(dwIOAddress, byData) { \
- volatile BYTE* pbyAddr = ((PBYTE)(dwIOAddress)); \
- writeb((BYTE)byData, pbyAddr); \
+ volatile unsigned char * pbyAddr = ((unsigned char *)(dwIOAddress)); \
+ writeb((unsigned char)byData, pbyAddr); \
}
#define VNSvOutPortW(dwIOAddress, wData) { \
- volatile WORD* pwAddr = ((PWORD)(dwIOAddress)); \
- writew((WORD)wData, pwAddr); \
+ volatile unsigned short *pwAddr = ((unsigned short *)(dwIOAddress)); \
+ writew((unsigned short)wData, pwAddr); \
}
#define VNSvOutPortD(dwIOAddress, dwData) { \
- volatile DWORD* pdwAddr = ((PDWORD)(dwIOAddress)); \
- writel((DWORD)dwData, pdwAddr); \
+ volatile unsigned long *pdwAddr = ((unsigned long *)(dwIOAddress)); \
+ writel((unsigned long)dwData, pdwAddr); \
}
#endif
@@ -140,8 +140,8 @@
#define PCAvDelayByIO(uDelayUnit) { \
- BYTE byData; \
- ULONG ii; \
+ unsigned char byData; \
+ unsigned long ii; \
\
if (uDelayUnit <= 50) { \
udelay(uDelayUnit); \
diff --git a/drivers/staging/vt6655/vntwifi.c b/drivers/staging/vt6655/vntwifi.c
index b527a019188..fcf26ab920d 100644
--- a/drivers/staging/vt6655/vntwifi.c
+++ b/drivers/staging/vt6655/vntwifi.c
@@ -101,9 +101,9 @@ VNTWIFIvSetOPMode (
void
VNTWIFIvSetIBSSParameter (
void *pMgmtHandle,
- WORD wBeaconPeriod,
- WORD wATIMWindow,
- UINT uChannel
+ unsigned short wBeaconPeriod,
+ unsigned short wATIMWindow,
+ unsigned int uChannel
)
{
PSMgmtObject pMgmt = (PSMgmtObject)pMgmtHandle;
@@ -150,7 +150,7 @@ VNTWIFIpGetCurrentSSID (
* Return Value: current Channel.
*
-*/
-UINT
+unsigned int
VNTWIFIpGetCurrentChannel (
void *pMgmtHandle
)
@@ -176,7 +176,7 @@ VNTWIFIpGetCurrentChannel (
* Return Value: current Assoc ID
*
-*/
-WORD
+unsigned short
VNTWIFIwGetAssocID (
void *pMgmtHandle
)
@@ -202,15 +202,15 @@ VNTWIFIwGetAssocID (
* Return Value: max support rate
*
-*/
-BYTE
+unsigned char
VNTWIFIbyGetMaxSupportRate (
PWLAN_IE_SUPP_RATES pSupportRateIEs,
PWLAN_IE_SUPP_RATES pExtSupportRateIEs
)
{
- BYTE byMaxSupportRate = RATE_1M;
- BYTE bySupportRate = RATE_1M;
- UINT ii = 0;
+ unsigned char byMaxSupportRate = RATE_1M;
+ unsigned char bySupportRate = RATE_1M;
+ unsigned int ii = 0;
if (pSupportRateIEs) {
for (ii = 0; ii < pSupportRateIEs->len; ii++) {
@@ -248,16 +248,16 @@ VNTWIFIbyGetMaxSupportRate (
* Return Value: max support rate
*
-*/
-BYTE
+unsigned char
VNTWIFIbyGetACKTxRate (
- BYTE byRxDataRate,
+ unsigned char byRxDataRate,
PWLAN_IE_SUPP_RATES pSupportRateIEs,
PWLAN_IE_SUPP_RATES pExtSupportRateIEs
)
{
- BYTE byMaxAckRate;
- BYTE byBasicRate;
- UINT ii;
+ unsigned char byMaxAckRate;
+ unsigned char byBasicRate;
+ unsigned int ii;
if (byRxDataRate <= RATE_11M) {
byMaxAckRate = RATE_1M;
@@ -317,9 +317,9 @@ VNTWIFIvSetAuthenticationMode (
pMgmt->eAuthenMode = eAuthMode;
if ((eAuthMode == WMAC_AUTH_SHAREKEY) ||
(eAuthMode == WMAC_AUTH_AUTO)) {
- pMgmt->bShareKeyAlgorithm = TRUE;
+ pMgmt->bShareKeyAlgorithm = true;
} else {
- pMgmt->bShareKeyAlgorithm = FALSE;
+ pMgmt->bShareKeyAlgorithm = false;
}
}
@@ -350,15 +350,15 @@ VNTWIFIvSetEncryptionMode (
if ((eEncryptionMode == WMAC_ENCRYPTION_WEPEnabled) ||
(eEncryptionMode == WMAC_ENCRYPTION_TKIPEnabled) ||
(eEncryptionMode == WMAC_ENCRYPTION_AESEnabled) ) {
- pMgmt->bPrivacyInvoked = TRUE;
+ pMgmt->bPrivacyInvoked = true;
} else {
- pMgmt->bPrivacyInvoked = FALSE;
+ pMgmt->bPrivacyInvoked = false;
}
}
-BOOL
+bool
VNTWIFIbConfigPhyMode (
void *pMgmtHandle,
CARD_PHY_TYPE ePhyType
@@ -368,14 +368,14 @@ VNTWIFIbConfigPhyMode (
if ((ePhyType != PHY_TYPE_AUTO) &&
(ePhyType != pMgmt->eCurrentPHYMode)) {
- if (CARDbSetPhyParameter(pMgmt->pAdapter, ePhyType, 0, 0, NULL, NULL)==TRUE) {
+ if (CARDbSetPhyParameter(pMgmt->pAdapter, ePhyType, 0, 0, NULL, NULL)==true) {
pMgmt->eCurrentPHYMode = ePhyType;
} else {
- return(FALSE);
+ return(false);
}
}
pMgmt->eConfigPHYMode = ePhyType;
- return(TRUE);
+ return(true);
}
@@ -425,16 +425,12 @@ VNTWIFIbGetConfigPhyMode (
-*/
void
-VNTWIFIvQueryBSSList (
- void *pMgmtHandle,
- PUINT puBSSCount,
- void **pvFirstBSS
- )
+VNTWIFIvQueryBSSList(void *pMgmtHandle, unsigned int *puBSSCount, void **pvFirstBSS)
{
- UINT ii = 0;
+ unsigned int ii = 0;
PSMgmtObject pMgmt = (PSMgmtObject)pMgmtHandle;
PKnownBSS pBSS = NULL;
- UINT uCount = 0;
+ unsigned int uCount = 0;
*pvFirstBSS = NULL;
@@ -471,7 +467,7 @@ VNTWIFIvGetNextBSS (
if (pBSS > &(pMgmt->sBSSList[MAX_BSS_NUM])) {
return;
}
- if (pBSS->bActive == TRUE) {
+ if (pBSS->bActive == true) {
*pvNextBSS = pBSS;
return;
}
@@ -497,24 +493,24 @@ VNTWIFIvGetNextBSS (
void
VNTWIFIvUpdateNodeTxCounter(
void *pMgmtHandle,
- PBYTE pbyDestAddress,
- BOOL bTxOk,
- WORD wRate,
- PBYTE pbyTxFailCount
+ unsigned char *pbyDestAddress,
+ bool bTxOk,
+ unsigned short wRate,
+ unsigned char *pbyTxFailCount
)
{
PSMgmtObject pMgmt = (PSMgmtObject)pMgmtHandle;
- UINT uNodeIndex = 0;
- UINT ii;
+ unsigned int uNodeIndex = 0;
+ unsigned int ii;
if ((pMgmt->eCurrMode == WMAC_MODE_IBSS_STA) ||
(pMgmt->eCurrMode == WMAC_MODE_ESS_AP)) {
- if (BSSDBbIsSTAInNodeDB(pMgmt, pbyDestAddress, &uNodeIndex) == FALSE) {
+ if (BSSDBbIsSTAInNodeDB(pMgmt, pbyDestAddress, &uNodeIndex) == false) {
return;
}
}
pMgmt->sNodeDBTable[uNodeIndex].uTxAttempts++;
- if (bTxOk == TRUE) {
+ if (bTxOk == true) {
// transmit success, TxAttempts at least plus one
pMgmt->sNodeDBTable[uNodeIndex].uTxOk[MAX_RATE]++;
pMgmt->sNodeDBTable[uNodeIndex].uTxOk[wRate]++;
@@ -532,19 +528,19 @@ VNTWIFIvUpdateNodeTxCounter(
void
VNTWIFIvGetTxRate(
void *pMgmtHandle,
- PBYTE pbyDestAddress,
- PWORD pwTxDataRate,
- PBYTE pbyACKRate,
- PBYTE pbyCCKBasicRate,
- PBYTE pbyOFDMBasicRate
+ unsigned char *pbyDestAddress,
+ unsigned short *pwTxDataRate,
+ unsigned char *pbyACKRate,
+ unsigned char *pbyCCKBasicRate,
+ unsigned char *pbyOFDMBasicRate
)
{
PSMgmtObject pMgmt = (PSMgmtObject)pMgmtHandle;
- UINT uNodeIndex = 0;
- WORD wTxDataRate = RATE_1M;
- BYTE byACKRate = RATE_1M;
- BYTE byCCKBasicRate = RATE_1M;
- BYTE byOFDMBasicRate = RATE_24M;
+ unsigned int uNodeIndex = 0;
+ unsigned short wTxDataRate = RATE_1M;
+ unsigned char byACKRate = RATE_1M;
+ unsigned char byCCKBasicRate = RATE_1M;
+ unsigned char byOFDMBasicRate = RATE_24M;
PWLAN_IE_SUPP_RATES pSupportRateIEs = NULL;
PWLAN_IE_SUPP_RATES pExtSupportRateIEs = NULL;
@@ -579,12 +575,12 @@ VNTWIFIvGetTxRate(
pSupportRateIEs = (PWLAN_IE_SUPP_RATES) pMgmt->abyCurrSuppRates;
pExtSupportRateIEs = (PWLAN_IE_SUPP_RATES) pMgmt->abyCurrExtSuppRates;
}
- byACKRate = VNTWIFIbyGetACKTxRate( (BYTE) wTxDataRate,
+ byACKRate = VNTWIFIbyGetACKTxRate( (unsigned char) wTxDataRate,
pSupportRateIEs,
pExtSupportRateIEs
);
- if (byACKRate > (BYTE) wTxDataRate) {
- byACKRate = (BYTE) wTxDataRate;
+ if (byACKRate > (unsigned char) wTxDataRate) {
+ byACKRate = (unsigned char) wTxDataRate;
}
byCCKBasicRate = VNTWIFIbyGetACKTxRate( RATE_11M,
pSupportRateIEs,
@@ -601,15 +597,15 @@ VNTWIFIvGetTxRate(
return;
}
-BYTE
+unsigned char
VNTWIFIbyGetKeyCypher(
void *pMgmtHandle,
- BOOL bGroupKey
+ bool bGroupKey
)
{
PSMgmtObject pMgmt = (PSMgmtObject)pMgmtHandle;
- if (bGroupKey == TRUE) {
+ if (bGroupKey == true) {
return (pMgmt->byCSSGK);
} else {
return (pMgmt->byCSSPK);
@@ -618,7 +614,7 @@ VNTWIFIbyGetKeyCypher(
/*
-BOOL
+bool
VNTWIFIbInit(
void *pAdapterHandler,
void **pMgmtHandler
@@ -626,13 +622,13 @@ VNTWIFIbInit(
{
PSMgmtObject pMgmt = NULL;
- UINT ii;
+ unsigned int ii;
pMgmt = (PSMgmtObject)kmalloc(sizeof(SMgmtObject), (int)GFP_ATOMIC);
if (pMgmt == NULL) {
*pMgmtHandler = NULL;
- return FALSE;
+ return false;
}
memset(pMgmt, 0, sizeof(SMgmtObject));
@@ -652,41 +648,41 @@ VNTWIFIbInit(
pMgmt->uCmdDequeueIdx = 0;
pMgmt->uCmdEnqueueIdx = 0;
pMgmt->eCommandState = WLAN_CMD_STATE_IDLE;
- pMgmt->bCmdStop = FALSE;
- pMgmt->bCmdRunning = FALSE;
+ pMgmt->bCmdStop = false;
+ pMgmt->bCmdRunning = false;
*pMgmtHandler = pMgmt;
- return TRUE;
+ return true;
}
*/
-BOOL
+bool
VNTWIFIbSetPMKIDCache (
void *pMgmtObject,
- ULONG ulCount,
+ unsigned long ulCount,
void *pPMKIDInfo
)
{
PSMgmtObject pMgmt = (PSMgmtObject) pMgmtObject;
if (ulCount > MAX_PMKID_CACHE) {
- return (FALSE);
+ return (false);
}
pMgmt->gsPMKIDCache.BSSIDInfoCount = ulCount;
memcpy(pMgmt->gsPMKIDCache.BSSIDInfo, pPMKIDInfo, (ulCount*sizeof(PMKIDInfo)));
- return (TRUE);
+ return (true);
}
-WORD
+unsigned short
VNTWIFIwGetMaxSupportRate(
void *pMgmtObject
)
{
- WORD wRate = RATE_54M;
+ unsigned short wRate = RATE_54M;
PSMgmtObject pMgmt = (PSMgmtObject) pMgmtObject;
for(wRate = RATE_54M; wRate > RATE_1M; wRate--) {
@@ -705,7 +701,7 @@ VNTWIFIwGetMaxSupportRate(
void
VNTWIFIvSet11h (
void *pMgmtObject,
- BOOL b11hEnable
+ bool b11hEnable
)
{
PSMgmtObject pMgmt = (PSMgmtObject) pMgmtObject;
@@ -713,19 +709,19 @@ VNTWIFIvSet11h (
pMgmt->b11hEnable = b11hEnable;
}
-BOOL
+bool
VNTWIFIbMeasureReport(
void *pMgmtObject,
- BOOL bEndOfReport,
+ bool bEndOfReport,
void *pvMeasureEID,
- BYTE byReportMode,
- BYTE byBasicMap,
- BYTE byCCAFraction,
- PBYTE pbyRPIs
+ unsigned char byReportMode,
+ unsigned char byBasicMap,
+ unsigned char byCCAFraction,
+ unsigned char *pbyRPIs
)
{
PSMgmtObject pMgmt = (PSMgmtObject) pMgmtObject;
- PBYTE pbyCurrentEID = (PBYTE) (pMgmt->pCurrMeasureEIDRep);
+ unsigned char *pbyCurrentEID = (unsigned char *) (pMgmt->pCurrMeasureEIDRep);
//spin_lock_irq(&pDevice->lock);
if ((pvMeasureEID != NULL) &&
@@ -765,49 +761,49 @@ VNTWIFIbMeasureReport(
pMgmt->uLengthOfRepEIDs += (2 + pMgmt->pCurrMeasureEIDRep->len);
pMgmt->pCurrMeasureEIDRep = (PWLAN_IE_MEASURE_REP) pbyCurrentEID;
}
- if (bEndOfReport == TRUE) {
+ if (bEndOfReport == true) {
IEEE11hbMSRRepTx(pMgmt);
}
//spin_unlock_irq(&pDevice->lock);
- return (TRUE);
+ return (true);
}
-BOOL
+bool
VNTWIFIbChannelSwitch(
void *pMgmtObject,
- BYTE byNewChannel
+ unsigned char byNewChannel
)
{
PSMgmtObject pMgmt = (PSMgmtObject) pMgmtObject;
//spin_lock_irq(&pDevice->lock);
pMgmt->uCurrChannel = byNewChannel;
- pMgmt->bSwitchChannel = FALSE;
+ pMgmt->bSwitchChannel = false;
//spin_unlock_irq(&pDevice->lock);
- return TRUE;
+ return true;
}
/*
-BOOL
+bool
VNTWIFIbRadarPresent(
void *pMgmtObject,
- BYTE byChannel
+ unsigned char byChannel
)
{
PSMgmtObject pMgmt = (PSMgmtObject) pMgmtObject;
if ((pMgmt->eCurrMode == WMAC_MODE_IBSS_STA) &&
- (byChannel == (BYTE) pMgmt->uCurrChannel) &&
- (pMgmt->bSwitchChannel != TRUE) &&
- (pMgmt->b11hEnable == TRUE)) {
- if (IS_ETH_ADDRESS_EQUAL(pMgmt->abyIBSSDFSOwner, CARDpGetCurrentAddress(pMgmt->pAdapter))) {
- pMgmt->byNewChannel = CARDbyAutoChannelSelect(pMgmt->pAdapter,(BYTE) pMgmt->uCurrChannel);
- pMgmt->bSwitchChannel = TRUE;
+ (byChannel == (unsigned char) pMgmt->uCurrChannel) &&
+ (pMgmt->bSwitchChannel != true) &&
+ (pMgmt->b11hEnable == true)) {
+ if (!compare_ether_addr(pMgmt->abyIBSSDFSOwner, CARDpGetCurrentAddress(pMgmt->pAdapter))) {
+ pMgmt->byNewChannel = CARDbyAutoChannelSelect(pMgmt->pAdapter,(unsigned char) pMgmt->uCurrChannel);
+ pMgmt->bSwitchChannel = true;
}
BEACONbSendBeacon(pMgmt);
CARDbChannelSwitch(pMgmt->pAdapter, 0, pMgmt->byNewChannel, 10);
}
- return TRUE;
+ return true;
}
*/
diff --git a/drivers/staging/vt6655/vntwifi.h b/drivers/staging/vt6655/vntwifi.h
index c91dfd79adc..f4327abaa77 100644
--- a/drivers/staging/vt6655/vntwifi.h
+++ b/drivers/staging/vt6655/vntwifi.h
@@ -143,9 +143,9 @@ typedef enum tagWMAC_POWER_MODE {
void
VNTWIFIvSetIBSSParameter (
void *pMgmtHandle,
- WORD wBeaconPeriod,
- WORD wATIMWindow,
- UINT uChannel
+ unsigned short wBeaconPeriod,
+ unsigned short wATIMWindow,
+ unsigned int uChannel
);
void
@@ -159,25 +159,25 @@ VNTWIFIpGetCurrentSSID(
void *pMgmtHandle
);
-UINT
+unsigned int
VNTWIFIpGetCurrentChannel(
void *pMgmtHandle
);
-WORD
+unsigned short
VNTWIFIwGetAssocID (
void *pMgmtHandle
);
-BYTE
+unsigned char
VNTWIFIbyGetMaxSupportRate (
PWLAN_IE_SUPP_RATES pSupportRateIEs,
PWLAN_IE_SUPP_RATES pExtSupportRateIEs
);
-BYTE
+unsigned char
VNTWIFIbyGetACKTxRate (
- BYTE byRxDataRate,
+ unsigned char byRxDataRate,
PWLAN_IE_SUPP_RATES pSupportRateIEs,
PWLAN_IE_SUPP_RATES pExtSupportRateIEs
);
@@ -195,7 +195,7 @@ VNTWIFIvSetEncryptionMode (
);
-BOOL
+bool
VNTWIFIbConfigPhyMode(
void *pMgmtHandle,
CARD_PHY_TYPE ePhyType
@@ -208,14 +208,8 @@ VNTWIFIbGetConfigPhyMode(
);
void
-VNTWIFIvQueryBSSList(
- void *pMgmtHandle,
- PUINT puBSSCount,
- void **pvFirstBSS
- );
-
-
-
+VNTWIFIvQueryBSSList(void *pMgmtHandle, unsigned int *puBSSCount,
+ void **pvFirstBSS);
void
VNTWIFIvGetNextBSS (
@@ -229,52 +223,52 @@ VNTWIFIvGetNextBSS (
void
VNTWIFIvUpdateNodeTxCounter(
void *pMgmtHandle,
- PBYTE pbyDestAddress,
- BOOL bTxOk,
- WORD wRate,
- PBYTE pbyTxFailCount
+ unsigned char *pbyDestAddress,
+ bool bTxOk,
+ unsigned short wRate,
+ unsigned char *pbyTxFailCount
);
void
VNTWIFIvGetTxRate(
void *pMgmtHandle,
- PBYTE pbyDestAddress,
- PWORD pwTxDataRate,
- PBYTE pbyACKRate,
- PBYTE pbyCCKBasicRate,
- PBYTE pbyOFDMBasicRate
+ unsigned char *pbyDestAddress,
+ unsigned short *pwTxDataRate,
+ unsigned char *pbyACKRate,
+ unsigned char *pbyCCKBasicRate,
+ unsigned char *pbyOFDMBasicRate
);
/*
-BOOL
+bool
VNTWIFIbInit(
void *pAdapterHandler,
void **pMgmtHandler
);
*/
-BYTE
+unsigned char
VNTWIFIbyGetKeyCypher(
void *pMgmtHandle,
- BOOL bGroupKey
+ bool bGroupKey
);
-BOOL
+bool
VNTWIFIbSetPMKIDCache (
void *pMgmtObject,
- ULONG ulCount,
+ unsigned long ulCount,
void *pPMKIDInfo
);
-BOOL
+bool
VNTWIFIbCommandRunning (
void *pMgmtObject
);
-WORD
+unsigned short
VNTWIFIwGetMaxSupportRate(
void *pMgmtObject
);
@@ -283,30 +277,30 @@ VNTWIFIwGetMaxSupportRate(
void
VNTWIFIvSet11h (
void *pMgmtObject,
- BOOL b11hEnable
+ bool b11hEnable
);
-BOOL
+bool
VNTWIFIbMeasureReport(
void *pMgmtObject,
- BOOL bEndOfReport,
+ bool bEndOfReport,
void *pvMeasureEID,
- BYTE byReportMode,
- BYTE byBasicMap,
- BYTE byCCAFraction,
- PBYTE pbyRPIs
+ unsigned char byReportMode,
+ unsigned char byBasicMap,
+ unsigned char byCCAFraction,
+ unsigned char *pbyRPIs
);
-BOOL
+bool
VNTWIFIbChannelSwitch(
void *pMgmtObject,
- BYTE byNewChannel
+ unsigned char byNewChannel
);
/*
-BOOL
+bool
VNTWIFIbRadarPresent(
void *pMgmtObject,
- BYTE byChannel
+ unsigned char byChannel
);
*/
diff --git a/drivers/staging/vt6655/wcmd.c b/drivers/staging/vt6655/wcmd.c
index 28665d870f5..abd6745bc3f 100644
--- a/drivers/staging/vt6655/wcmd.c
+++ b/drivers/staging/vt6655/wcmd.c
@@ -52,6 +52,7 @@
#include "rxtx.h"
#include "rf.h"
#include "iowpa.h"
+#include "channel.h"
/*--------------------- Static Definitions -------------------------*/
@@ -77,7 +78,7 @@ PSTxMgmtPacket
s_MgrMakeProbeRequest(
PSDevice pDevice,
PSMgmtObject pMgmt,
- PBYTE pScanBSSID,
+ unsigned char *pScanBSSID,
PWLAN_IE_SSID pSSID,
PWLAN_IE_SUPP_RATES pCurrRates,
PWLAN_IE_SUPP_RATES pCurrExtSuppRates
@@ -85,7 +86,7 @@ s_MgrMakeProbeRequest(
static
-BOOL
+bool
s_bCommandComplete (
PSDevice pDevice
);
@@ -116,7 +117,7 @@ vAdHocBeaconStop(PSDevice pDevice)
{
PSMgmtObject pMgmt = &(pDevice->sMgmtObj);
- BOOL bStop;
+ bool bStop;
/*
* temporarily stop Beacon packet for AdHoc Server
@@ -129,18 +130,18 @@ vAdHocBeaconStop(PSDevice pDevice)
* or
* (3.2) AdHoc channel is in A mode
*/
- bStop = FALSE;
+ bStop = false;
if ((pMgmt->eCurrMode == WMAC_MODE_IBSS_STA) &&
(pMgmt->eCurrState >= WMAC_STATE_STARTED))
{
if ((pMgmt->uIBSSChannel <= CB_MAX_CHANNEL_24G) &&
(pMgmt->uScanChannel > CB_MAX_CHANNEL_24G))
{
- bStop = TRUE;
+ bStop = true;
}
if (pMgmt->uIBSSChannel > CB_MAX_CHANNEL_24G)
{
- bStop = TRUE;
+ bStop = true;
}
}
@@ -208,15 +209,15 @@ s_vProbeChannel(
)
{
//1M, 2M, 5M, 11M, 18M, 24M, 36M, 54M
- BYTE abyCurrSuppRatesG[] = {WLAN_EID_SUPP_RATES, 8, 0x02, 0x04, 0x0B, 0x16, 0x24, 0x30, 0x48, 0x6C};
- BYTE abyCurrExtSuppRatesG[] = {WLAN_EID_EXTSUPP_RATES, 4, 0x0C, 0x12, 0x18, 0x60};
+ unsigned char abyCurrSuppRatesG[] = {WLAN_EID_SUPP_RATES, 8, 0x02, 0x04, 0x0B, 0x16, 0x24, 0x30, 0x48, 0x6C};
+ unsigned char abyCurrExtSuppRatesG[] = {WLAN_EID_EXTSUPP_RATES, 4, 0x0C, 0x12, 0x18, 0x60};
//6M, 9M, 12M, 48M
- BYTE abyCurrSuppRatesA[] = {WLAN_EID_SUPP_RATES, 8, 0x0C, 0x12, 0x18, 0x24, 0x30, 0x48, 0x60, 0x6C};
- BYTE abyCurrSuppRatesB[] = {WLAN_EID_SUPP_RATES, 4, 0x02, 0x04, 0x0B, 0x16};
- PBYTE pbyRate;
+ unsigned char abyCurrSuppRatesA[] = {WLAN_EID_SUPP_RATES, 8, 0x0C, 0x12, 0x18, 0x24, 0x30, 0x48, 0x60, 0x6C};
+ unsigned char abyCurrSuppRatesB[] = {WLAN_EID_SUPP_RATES, 4, 0x02, 0x04, 0x0B, 0x16};
+ unsigned char *pbyRate;
PSTxMgmtPacket pTxPacket;
PSMgmtObject pMgmt = pDevice->pMgmt;
- UINT ii;
+ unsigned int ii;
if (pDevice->eCurrentPHYType == PHY_TYPE_11A) {
@@ -269,7 +270,7 @@ PSTxMgmtPacket
s_MgrMakeProbeRequest(
PSDevice pDevice,
PSMgmtObject pMgmt,
- PBYTE pScanBSSID,
+ unsigned char *pScanBSSID,
PWLAN_IE_SSID pSSID,
PWLAN_IE_SUPP_RATES pCurrRates,
PWLAN_IE_SUPP_RATES pCurrExtSuppRates
@@ -282,8 +283,8 @@ s_MgrMakeProbeRequest(
pTxPacket = (PSTxMgmtPacket)pMgmt->pbyMgmtPacketPool;
memset(pTxPacket, 0, sizeof(STxMgmtPacket) + WLAN_PROBEREQ_FR_MAXLEN);
- pTxPacket->p80211Header = (PUWLAN_80211HDR)((PBYTE)pTxPacket + sizeof(STxMgmtPacket));
- sFrame.pBuf = (PBYTE)pTxPacket->p80211Header;
+ pTxPacket->p80211Header = (PUWLAN_80211HDR)((unsigned char *)pTxPacket + sizeof(STxMgmtPacket));
+ sFrame.pBuf = (unsigned char *)pTxPacket->p80211Header;
sFrame.len = WLAN_PROBEREQ_FR_MAXLEN;
vMgrEncodeProbeRequest(&sFrame);
sFrame.pHdr->sA3.wFrameCtl = cpu_to_le16(
@@ -320,16 +321,16 @@ s_MgrMakeProbeRequest(
void
vCommandTimerWait(
void *hDeviceContext,
- UINT MSecond
+ unsigned int MSecond
)
{
PSDevice pDevice = (PSDevice)hDeviceContext;
init_timer(&pDevice->sTimerCommand);
- pDevice->sTimerCommand.data = (ULONG)pDevice;
+ pDevice->sTimerCommand.data = (unsigned long) pDevice;
pDevice->sTimerCommand.function = (TimerFunction)vCommandTimer;
// RUN_AT :1 msec ~= (HZ/1024)
- pDevice->sTimerCommand.expires = (UINT)RUN_AT((MSecond * HZ) >> 10);
+ pDevice->sTimerCommand.expires = (unsigned int)RUN_AT((MSecond * HZ) >> 10);
add_timer(&pDevice->sTimerCommand);
return;
}
@@ -347,14 +348,14 @@ vCommandTimer (
PWLAN_IE_SSID pItemSSID;
PWLAN_IE_SSID pItemSSIDCurr;
CMD_STATUS Status;
- UINT ii;
- BYTE byMask[8] = {1, 2, 4, 8, 0x10, 0x20, 0x40, 0x80};
+ unsigned int ii;
+ unsigned char byMask[8] = {1, 2, 4, 8, 0x10, 0x20, 0x40, 0x80};
struct sk_buff *skb;
if (pDevice->dwDiagRefCount != 0)
return;
- if (pDevice->bCmdRunning != TRUE)
+ if (pDevice->bCmdRunning != true)
return;
spin_lock_irq(&pDevice->lock);
@@ -364,7 +365,7 @@ vCommandTimer (
case WLAN_CMD_SCAN_START:
pDevice->byReAssocCount = 0;
- if (pDevice->bRadioOff == TRUE) {
+ if (pDevice->bRadioOff == true) {
s_bCommandComplete(pDevice);
spin_unlock_irq(&pDevice->lock);
return;
@@ -396,7 +397,7 @@ vCommandTimer (
// Set Baseband's sensitivity back.
// Set channel back
- CARDbSetChannel(pMgmt->pAdapter, pMgmt->uCurrChannel);
+ set_channel(pMgmt->pAdapter, pMgmt->uCurrChannel);
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Scanning, set back to channel: [%d]\n", pMgmt->uCurrChannel);
if (pMgmt->eCurrMode == WMAC_MODE_IBSS_STA) {
CARDbSetBSSID(pMgmt->pAdapter, pMgmt->abyCurrBSSID, OP_MODE_ADHOC);
@@ -408,7 +409,7 @@ vCommandTimer (
} else {
//2008-8-4 <add> by chester
- if (!ChannelValid(pDevice->byZoneType, pMgmt->uScanChannel)) {
+ if (!is_channel_valid(pMgmt->uScanChannel)) {
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Invalid channel pMgmt->uScanChannel = %d \n",pMgmt->uScanChannel);
s_bCommandComplete(pDevice);
return;
@@ -431,7 +432,7 @@ vCommandTimer (
vAdHocBeaconStop(pDevice);
- if (CARDbSetChannel(pMgmt->pAdapter, pMgmt->uScanChannel) == TRUE) {
+ if (set_channel(pMgmt->pAdapter, pMgmt->uScanChannel) == true) {
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"SCAN Channel: %d\n", pMgmt->uScanChannel);
} else {
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"SET SCAN Channel Fail: %d\n", pMgmt->uScanChannel);
@@ -441,7 +442,7 @@ vCommandTimer (
// printk("chester-ch=%d\n",pMgmt->uScanChannel);
pMgmt->uScanChannel++;
//2008-8-4 <modify> by chester
- if (!ChannelValid(pDevice->byZoneType, pMgmt->uScanChannel) &&
+ if (!is_channel_valid(pMgmt->uScanChannel) &&
pMgmt->uScanChannel <= pDevice->byMaxChannel ){
pMgmt->uScanChannel=pDevice->byMaxChannel+1;
pMgmt->eCommandState = WLAN_CMD_SCAN_END;
@@ -449,7 +450,7 @@ vCommandTimer (
}
- if ((pMgmt->b11hEnable == FALSE) ||
+ if ((pMgmt->b11hEnable == false) ||
(pMgmt->uScanChannel < CB_MAX_CHANNEL_24G)) {
s_vProbeChannel(pDevice);
spin_unlock_irq(&pDevice->lock);
@@ -469,7 +470,7 @@ vCommandTimer (
// Set Baseband's sensitivity back.
// Set channel back
- CARDbSetChannel(pMgmt->pAdapter, pMgmt->uCurrChannel);
+ set_channel(pMgmt->pAdapter, pMgmt->uCurrChannel);
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Scanning, set back to channel: [%d]\n", pMgmt->uCurrChannel);
if (pMgmt->eCurrMode == WMAC_MODE_IBSS_STA) {
CARDbSetBSSID(pMgmt->pAdapter, pMgmt->abyCurrBSSID, OP_MODE_ADHOC);
@@ -502,14 +503,14 @@ vCommandTimer (
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Send Disassociation Packet..\n");
// reason = 8 : disassoc because sta has left
vMgrDisassocBeginSta((void *)pDevice, pMgmt, pMgmt->abyCurrBSSID, (8), &Status);
- pDevice->bLinkPass = FALSE;
+ pDevice->bLinkPass = false;
// unlock command busy
pItemSSID = (PWLAN_IE_SSID)pMgmt->abyCurrSSID;
pItemSSID->len = 0;
memset(pItemSSID->abySSID, 0, WLAN_SSID_MAXLEN);
pMgmt->eCurrState = WMAC_STATE_IDLE;
- pMgmt->sNodeDBTable[0].bActive = FALSE;
-// pDevice->bBeaconBufReady = FALSE;
+ pMgmt->sNodeDBTable[0].bActive = false;
+// pDevice->bBeaconBufReady = false;
}
netif_stop_queue(pDevice->dev);
pDevice->eCommandState = WLAN_DISASSOCIATE_WAIT;
@@ -539,7 +540,7 @@ vCommandTimer (
case WLAN_CMD_SSID_START:
pDevice->byReAssocCount = 0;
- if (pDevice->bRadioOff == TRUE) {
+ if (pDevice->bRadioOff == true) {
s_bCommandComplete(pDevice);
spin_unlock_irq(&pDevice->lock);
return;
@@ -573,7 +574,7 @@ printk("chester-abyDesireSSID=%s\n",((PWLAN_IE_SSID)pMgmt->abyDesireSSID)->abySS
}
netif_stop_queue(pDevice->dev);
- pDevice->bLinkPass = FALSE;
+ pDevice->bLinkPass = false;
}
// set initial state
pMgmt->eCurrState = WMAC_STATE_IDLE;
@@ -607,9 +608,9 @@ printk("chester-abyDesireSSID=%s\n",((PWLAN_IE_SSID)pMgmt->abyDesireSSID)->abySS
if (netif_queue_stopped(pDevice->dev)){
netif_wake_queue(pDevice->dev);
}
- pDevice->bLinkPass = TRUE;
+ pDevice->bLinkPass = true;
- pMgmt->sNodeDBTable[0].bActive = TRUE;
+ pMgmt->sNodeDBTable[0].bActive = true;
pMgmt->sNodeDBTable[0].uInActiveCount = 0;
bClearBSSID_SCAN(pDevice);
}
@@ -635,12 +636,12 @@ printk("chester-abyDesireSSID=%s\n",((PWLAN_IE_SSID)pMgmt->abyDesireSSID)->abySS
if (netif_queue_stopped(pDevice->dev)){
netif_wake_queue(pDevice->dev);
}
- pDevice->bLinkPass = TRUE;
+ pDevice->bLinkPass = true;
}
else {
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Disconnect SSID none\n");
#ifdef WPA_SUPPLICANT_DRIVER_WEXT_SUPPORT
- // if(pDevice->bWPASuppWextEnabled == TRUE)
+ // if(pDevice->bWPASuppWextEnabled == true)
{
union iwreq_data wrqu;
memset(&wrqu, 0, sizeof (wrqu));
@@ -685,7 +686,7 @@ printk("chester-abyDesireSSID=%s\n",((PWLAN_IE_SSID)pMgmt->abyDesireSSID)->abySS
pDevice->byLinkWaitCount = 0;
#if 0
#ifdef WPA_SUPPLICANT_DRIVER_WEXT_SUPPORT
- // if(pDevice->bWPASuppWextEnabled == TRUE)
+ // if(pDevice->bWPASuppWextEnabled == true)
{
union iwreq_data wrqu;
memset(&wrqu, 0, sizeof (wrqu));
@@ -707,7 +708,7 @@ printk("chester-abyDesireSSID=%s\n",((PWLAN_IE_SSID)pMgmt->abyDesireSSID)->abySS
if (pMgmt->eAuthenMode >= WMAC_AUTH_WPA) {
KeybRemoveAllKey(&(pDevice->sKey), pDevice->abyBSSID, pDevice->PortOffset);
}
- pDevice->bLinkPass = TRUE;
+ pDevice->bLinkPass = true;
pDevice->byLinkWaitCount = 0;
pDevice->byReAssocCount = 0;
bClearBSSID_SCAN(pDevice);
@@ -719,20 +720,20 @@ printk("chester-abyDesireSSID=%s\n",((PWLAN_IE_SSID)pMgmt->abyDesireSSID)->abySS
netif_wake_queue(pDevice->dev);
}
#ifdef TxInSleep
- if(pDevice->IsTxDataTrigger != FALSE) { //TxDataTimer is not triggered at the first time
+ if(pDevice->IsTxDataTrigger != false) { //TxDataTimer is not triggered at the first time
// printk("Re-initial TxDataTimer****\n");
del_timer(&pDevice->sTimerTxData);
init_timer(&pDevice->sTimerTxData);
- pDevice->sTimerTxData.data = (ULONG)pDevice;
+ pDevice->sTimerTxData.data = (unsigned long) pDevice;
pDevice->sTimerTxData.function = (TimerFunction)BSSvSecondTxData;
pDevice->sTimerTxData.expires = RUN_AT(10*HZ); //10s callback
- pDevice->fTxDataInSleep = FALSE;
+ pDevice->fTxDataInSleep = false;
pDevice->nTxDataTimeCout = 0;
}
else {
// printk("mike:-->First time triger TimerTxData InSleep\n");
}
- pDevice->IsTxDataTrigger = TRUE;
+ pDevice->IsTxDataTrigger = true;
add_timer(&pDevice->sTimerTxData);
#endif
}
@@ -749,7 +750,7 @@ printk("chester-abyDesireSSID=%s\n",((PWLAN_IE_SSID)pMgmt->abyDesireSSID)->abySS
pDevice->byLinkWaitCount = 0;
#if 0
#ifdef WPA_SUPPLICANT_DRIVER_WEXT_SUPPORT
- // if(pDevice->bWPASuppWextEnabled == TRUE)
+ // if(pDevice->bWPASuppWextEnabled == true)
{
union iwreq_data wrqu;
memset(&wrqu, 0, sizeof (wrqu));
@@ -770,14 +771,14 @@ printk("chester-abyDesireSSID=%s\n",((PWLAN_IE_SSID)pMgmt->abyDesireSSID)->abySS
del_timer(&pMgmt->sTimerSecondCallback);
pMgmt->eCurrState = WMAC_STATE_IDLE;
pMgmt->eCurrMode = WMAC_MODE_STANDBY;
- pDevice->bLinkPass = FALSE;
- if (pDevice->bEnableHostWEP == TRUE)
+ pDevice->bLinkPass = false;
+ if (pDevice->bEnableHostWEP == true)
BSSvClearNodeDBTable(pDevice, 1);
else
BSSvClearNodeDBTable(pDevice, 0);
pDevice->uAssocCount = 0;
pMgmt->eCurrState = WMAC_STATE_IDLE;
- pDevice->bFixRate = FALSE;
+ pDevice->bFixRate = false;
vMgrCreateOwnIBSS((void *)pDevice, &Status);
if (Status != CMD_STATUS_SUCCESS){
@@ -791,7 +792,7 @@ printk("chester-abyDesireSSID=%s\n",((PWLAN_IE_SSID)pMgmt->abyDesireSSID)->abySS
if (netif_queue_stopped(pDevice->dev)){
netif_wake_queue(pDevice->dev);
}
- pDevice->bLinkPass = TRUE;
+ pDevice->bLinkPass = true;
add_timer(&pMgmt->sTimerSecondCallback);
}
s_bCommandComplete(pDevice);
@@ -803,10 +804,10 @@ printk("chester-abyDesireSSID=%s\n",((PWLAN_IE_SSID)pMgmt->abyDesireSSID)->abySS
while ((skb = skb_dequeue(&pMgmt->sNodeDBTable[0].sTxPSQueue)) != NULL) {
if (skb_queue_empty(&pMgmt->sNodeDBTable[0].sTxPSQueue)) {
pMgmt->abyPSTxMap[0] &= ~byMask[0];
- pDevice->bMoreData = FALSE;
+ pDevice->bMoreData = false;
}
else {
- pDevice->bMoreData = TRUE;
+ pDevice->bMoreData = true;
}
if (!device_dma0_xmit(pDevice, skb, 0)) {
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Multicast ps tx fail \n");
@@ -826,10 +827,10 @@ printk("chester-abyDesireSSID=%s\n",((PWLAN_IE_SSID)pMgmt->abyDesireSSID)->abySS
// clear tx map
pMgmt->abyPSTxMap[pMgmt->sNodeDBTable[ii].wAID >> 3] &=
~byMask[pMgmt->sNodeDBTable[ii].wAID & 7];
- pDevice->bMoreData = FALSE;
+ pDevice->bMoreData = false;
}
else {
- pDevice->bMoreData = TRUE;
+ pDevice->bMoreData = true;
}
if (!device_dma0_xmit(pDevice, skb, ii)) {
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "sta ps tx fail \n");
@@ -846,7 +847,7 @@ printk("chester-abyDesireSSID=%s\n",((PWLAN_IE_SSID)pMgmt->abyDesireSSID)->abySS
~byMask[pMgmt->sNodeDBTable[ii].wAID & 7];
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Index=%d PS queue clear \n", ii);
}
- pMgmt->sNodeDBTable[ii].bRxPSPoll = FALSE;
+ pMgmt->sNodeDBTable[ii].bRxPSPoll = false;
}
}
@@ -856,7 +857,7 @@ printk("chester-abyDesireSSID=%s\n",((PWLAN_IE_SSID)pMgmt->abyDesireSSID)->abySS
case WLAN_CMD_RADIO_START :
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"eCommandState == WLAN_CMD_RADIO_START\n");
- if (pDevice->bRadioCmd == TRUE)
+ if (pDevice->bRadioCmd == true)
CARDbRadioPowerOn(pDevice);
else
CARDbRadioPowerOff(pDevice);
@@ -896,23 +897,23 @@ printk("chester-abyDesireSSID=%s\n",((PWLAN_IE_SSID)pMgmt->abyDesireSSID)->abySS
static
-BOOL
+bool
s_bCommandComplete (
PSDevice pDevice
)
{
PWLAN_IE_SSID pSSID;
- BOOL bRadioCmd = FALSE;
- //WORD wDeAuthenReason = 0;
- BOOL bForceSCAN = TRUE;
+ bool bRadioCmd = false;
+ //unsigned short wDeAuthenReason = 0;
+ bool bForceSCAN = true;
PSMgmtObject pMgmt = pDevice->pMgmt;
pDevice->eCommandState = WLAN_CMD_IDLE;
if (pDevice->cbFreeCmdQueue == CMD_Q_SIZE) {
//Command Queue Empty
- pDevice->bCmdRunning = FALSE;
- return TRUE;
+ pDevice->bCmdRunning = false;
+ return true;
}
else {
pDevice->eCommand = pDevice->eCmdQueue[pDevice->uCmdDequeueIdx].eCmd;
@@ -921,7 +922,7 @@ s_bCommandComplete (
bForceSCAN = pDevice->eCmdQueue[pDevice->uCmdDequeueIdx].bForceSCAN;
ADD_ONE_WITH_WRAP_AROUND(pDevice->uCmdDequeueIdx, CMD_Q_SIZE);
pDevice->cbFreeCmdQueue++;
- pDevice->bCmdRunning = TRUE;
+ pDevice->bCmdRunning = true;
switch ( pDevice->eCommand ) {
case WLAN_CMD_BSSID_SCAN:
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"eCommandState= WLAN_CMD_BSSID_SCAN\n");
@@ -933,7 +934,7 @@ s_bCommandComplete (
memset(pMgmt->abyScanSSID, 0, WLAN_IEHDR_LEN + WLAN_SSID_MAXLEN + 1);
}
/*
- if ((bForceSCAN == FALSE) && (pDevice->bLinkPass == TRUE)) {
+ if ((bForceSCAN == false) && (pDevice->bLinkPass == true)) {
if ((pSSID->len == ((PWLAN_IE_SSID)pMgmt->abyCurrSSID)->len) &&
( !memcmp(pSSID->abySSID, ((PWLAN_IE_SSID)pMgmt->abyCurrSSID)->abySSID, pSSID->len))) {
pDevice->eCommandState = WLAN_CMD_IDLE;
@@ -974,25 +975,25 @@ s_bCommandComplete (
vCommandTimerWait((void *)pDevice, 0);
}
- return TRUE;
+ return true;
}
-BOOL bScheduleCommand (
+bool bScheduleCommand (
void *hDeviceContext,
CMD_CODE eCommand,
- PBYTE pbyItem0
+ unsigned char *pbyItem0
)
{
PSDevice pDevice = (PSDevice)hDeviceContext;
if (pDevice->cbFreeCmdQueue == 0) {
- return (FALSE);
+ return (false);
}
pDevice->eCmdQueue[pDevice->uCmdEnqueueIdx].eCmd = eCommand;
- pDevice->eCmdQueue[pDevice->uCmdEnqueueIdx].bForceSCAN = TRUE;
+ pDevice->eCmdQueue[pDevice->uCmdEnqueueIdx].bForceSCAN = true;
memset(pDevice->eCmdQueue[pDevice->uCmdEnqueueIdx].abyCmdDesireSSID, 0 , WLAN_IEHDR_LEN + WLAN_SSID_MAXLEN + 1);
if (pbyItem0 != NULL) {
@@ -1001,7 +1002,7 @@ BOOL bScheduleCommand (
case WLAN_CMD_BSSID_SCAN:
memcpy(pDevice->eCmdQueue[pDevice->uCmdEnqueueIdx].abyCmdDesireSSID,
pbyItem0, WLAN_IEHDR_LEN + WLAN_SSID_MAXLEN + 1);
- pDevice->eCmdQueue[pDevice->uCmdEnqueueIdx].bForceSCAN = FALSE;
+ pDevice->eCmdQueue[pDevice->uCmdEnqueueIdx].bForceSCAN = false;
break;
case WLAN_CMD_SSID:
@@ -1014,7 +1015,7 @@ BOOL bScheduleCommand (
break;
/*
case WLAN_CMD_DEAUTH:
- pDevice->eCmdQueue[pDevice->uCmdEnqueueIdx].wDeAuthenReason = *((PWORD)pbyItem0);
+ pDevice->eCmdQueue[pDevice->uCmdEnqueueIdx].wDeAuthenReason = *((unsigned short *)pbyItem0);
break;
*/
@@ -1037,12 +1038,12 @@ BOOL bScheduleCommand (
ADD_ONE_WITH_WRAP_AROUND(pDevice->uCmdEnqueueIdx, CMD_Q_SIZE);
pDevice->cbFreeCmdQueue--;
- if (pDevice->bCmdRunning == FALSE) {
+ if (pDevice->bCmdRunning == false) {
s_bCommandComplete(pDevice);
}
else {
}
- return (TRUE);
+ return (true);
}
@@ -1057,16 +1058,16 @@ BOOL bScheduleCommand (
* Out:
* none
*
- * Return Value: TRUE if success; otherwise FALSE
+ * Return Value: true if success; otherwise false
*
*/
-BOOL bClearBSSID_SCAN (
+bool bClearBSSID_SCAN (
void *hDeviceContext
)
{
PSDevice pDevice = (PSDevice)hDeviceContext;
- UINT uCmdDequeueIdx = pDevice->uCmdDequeueIdx;
- UINT ii;
+ unsigned int uCmdDequeueIdx = pDevice->uCmdDequeueIdx;
+ unsigned int ii;
if ((pDevice->cbFreeCmdQueue < CMD_Q_SIZE) && (uCmdDequeueIdx != pDevice->uCmdEnqueueIdx)) {
for (ii = 0; ii < (CMD_Q_SIZE - pDevice->cbFreeCmdQueue); ii ++) {
@@ -1077,7 +1078,7 @@ BOOL bClearBSSID_SCAN (
break;
}
}
- return TRUE;
+ return true;
}
//mike add:reset command timer
@@ -1092,15 +1093,15 @@ vResetCommandTimer(
del_timer(&pDevice->sTimerCommand);
//init timer
init_timer(&pDevice->sTimerCommand);
- pDevice->sTimerCommand.data = (ULONG)pDevice;
+ pDevice->sTimerCommand.data = (unsigned long) pDevice;
pDevice->sTimerCommand.function = (TimerFunction)vCommandTimer;
pDevice->sTimerCommand.expires = RUN_AT(HZ);
pDevice->cbFreeCmdQueue = CMD_Q_SIZE;
pDevice->uCmdDequeueIdx = 0;
pDevice->uCmdEnqueueIdx = 0;
pDevice->eCommandState = WLAN_CMD_IDLE;
- pDevice->bCmdRunning = FALSE;
- pDevice->bCmdClear = FALSE;
+ pDevice->bCmdRunning = false;
+ pDevice->bCmdClear = false;
}
@@ -1125,16 +1126,16 @@ BSSvSecondTxData(
spin_lock_irq(&pDevice->lock);
#if 1
- if(((pDevice->bLinkPass ==TRUE)&&(pMgmt->eAuthenMode < WMAC_AUTH_WPA)) || //open && sharekey linking
- (pDevice->fWPA_Authened == TRUE)) { //wpa linking
+ if(((pDevice->bLinkPass ==true)&&(pMgmt->eAuthenMode < WMAC_AUTH_WPA)) || //open && sharekey linking
+ (pDevice->fWPA_Authened == true)) { //wpa linking
#else
- if(pDevice->bLinkPass ==TRUE) {
+ if(pDevice->bLinkPass ==true) {
#endif
// printk("mike:%s-->InSleep Tx Data Procedure\n",__FUNCTION__);
- pDevice->fTxDataInSleep = TRUE;
+ pDevice->fTxDataInSleep = true;
PSbSendNullPacket(pDevice); //send null packet
- pDevice->fTxDataInSleep = FALSE;
+ pDevice->fTxDataInSleep = false;
}
spin_unlock_irq(&pDevice->lock);
diff --git a/drivers/staging/vt6655/wcmd.h b/drivers/staging/vt6655/wcmd.h
index c3c41808951..69d4fc55b84 100644
--- a/drivers/staging/vt6655/wcmd.h
+++ b/drivers/staging/vt6655/wcmd.h
@@ -75,11 +75,11 @@ typedef enum tagCMD_STATUS {
typedef struct tagCMD_ITEM {
CMD_CODE eCmd;
- BYTE abyCmdDesireSSID[WLAN_IEHDR_LEN + WLAN_SSID_MAXLEN + 1];
- BOOL bNeedRadioOFF;
- WORD wDeAuthenReason;
- BOOL bRadioCmd;
- BOOL bForceSCAN;
+ unsigned char abyCmdDesireSSID[WLAN_IEHDR_LEN + WLAN_SSID_MAXLEN + 1];
+ bool bNeedRadioOFF;
+ unsigned short wDeAuthenReason;
+ bool bRadioCmd;
+ bool bForceSCAN;
} CMD_ITEM, *PCMD_ITEM;
// Command state
@@ -119,21 +119,21 @@ vCommandTimer (
void *hDeviceContext
);
-BOOL bClearBSSID_SCAN(
+bool bClearBSSID_SCAN(
void *hDeviceContext
);
-BOOL
+bool
bScheduleCommand(
void *hDeviceContext,
CMD_CODE eCommand,
- PBYTE pbyItem0
+ unsigned char *pbyItem0
);
void
vCommandTimerWait(
void *hDeviceContext,
- UINT MSecond
+ unsigned int MSecond
);
#ifdef TxInSleep
void
diff --git a/drivers/staging/vt6655/wctl.c b/drivers/staging/vt6655/wctl.c
index 64a66b2f1fc..c096583a772 100644
--- a/drivers/staging/vt6655/wctl.c
+++ b/drivers/staging/vt6655/wctl.c
@@ -52,8 +52,8 @@
/*
* Description:
- * Scan Rx cache. Return TRUE if packet is duplicate, else
- * inserts in receive cache and returns FALSE.
+ * Scan Rx cache. Return true if packet is duplicate, else
+ * inserts in receive cache and returns false.
*
* Parameters:
* In:
@@ -62,14 +62,14 @@
* Out:
* none
*
- * Return Value: TRUE if packet duplicate; otherwise FALSE
+ * Return Value: true if packet duplicate; otherwise false
*
*/
-BOOL WCTLbIsDuplicate (PSCache pCache, PS802_11Header pMACHeader)
+bool WCTLbIsDuplicate (PSCache pCache, PS802_11Header pMACHeader)
{
- UINT uIndex;
- UINT ii;
+ unsigned int uIndex;
+ unsigned int ii;
PSCacheEntry pCacheEntry;
if (IS_FC_RETRY(pMACHeader)) {
@@ -78,10 +78,10 @@ BOOL WCTLbIsDuplicate (PSCache pCache, PS802_11Header pMACHeader)
for (ii = 0; ii < DUPLICATE_RX_CACHE_LENGTH; ii++) {
pCacheEntry = &(pCache->asCacheEntry[uIndex]);
if ((pCacheEntry->wFmSequence == pMACHeader->wSeqCtl) &&
- (IS_ETH_ADDRESS_EQUAL (&(pCacheEntry->abyAddr2[0]), &(pMACHeader->abyAddr2[0])))
+ (!compare_ether_addr(&(pCacheEntry->abyAddr2[0]), &(pMACHeader->abyAddr2[0])))
) {
/* Duplicate match */
- return TRUE;
+ return true;
}
ADD_ONE_WITH_WRAP_AROUND(uIndex, DUPLICATE_RX_CACHE_LENGTH);
}
@@ -91,7 +91,7 @@ BOOL WCTLbIsDuplicate (PSCache pCache, PS802_11Header pMACHeader)
pCacheEntry->wFmSequence = pMACHeader->wSeqCtl;
memcpy(&(pCacheEntry->abyAddr2[0]), &(pMACHeader->abyAddr2[0]), ETH_ALEN);
ADD_ONE_WITH_WRAP_AROUND(pCache->uInPtr, DUPLICATE_RX_CACHE_LENGTH);
- return FALSE;
+ return false;
}
/*
@@ -108,13 +108,13 @@ BOOL WCTLbIsDuplicate (PSCache pCache, PS802_11Header pMACHeader)
* Return Value: index number in Defragment Database
*
*/
-UINT WCTLuSearchDFCB (PSDevice pDevice, PS802_11Header pMACHeader)
+unsigned int WCTLuSearchDFCB (PSDevice pDevice, PS802_11Header pMACHeader)
{
-UINT ii;
+unsigned int ii;
for(ii=0;ii<pDevice->cbDFCB;ii++) {
- if ((pDevice->sRxDFCB[ii].bInUse == TRUE) &&
- (IS_ETH_ADDRESS_EQUAL (&(pDevice->sRxDFCB[ii].abyAddr2[0]), &(pMACHeader->abyAddr2[0])))
+ if ((pDevice->sRxDFCB[ii].bInUse == true) &&
+ (!compare_ether_addr(&(pDevice->sRxDFCB[ii].abyAddr2[0]), &(pMACHeader->abyAddr2[0])))
) {
//
return(ii);
@@ -138,17 +138,17 @@ UINT ii;
* Return Value: index number in Defragment Database
*
*/
-UINT WCTLuInsertDFCB (PSDevice pDevice, PS802_11Header pMACHeader)
+unsigned int WCTLuInsertDFCB (PSDevice pDevice, PS802_11Header pMACHeader)
{
-UINT ii;
+unsigned int ii;
if (pDevice->cbFreeDFCB == 0)
return(pDevice->cbDFCB);
for(ii=0;ii<pDevice->cbDFCB;ii++) {
- if (pDevice->sRxDFCB[ii].bInUse == FALSE) {
+ if (pDevice->sRxDFCB[ii].bInUse == false) {
pDevice->cbFreeDFCB--;
pDevice->sRxDFCB[ii].uLifetime = pDevice->dwMaxReceiveLifetime;
- pDevice->sRxDFCB[ii].bInUse = TRUE;
+ pDevice->sRxDFCB[ii].bInUse = true;
pDevice->sRxDFCB[ii].wSequence = (pMACHeader->wSeqCtl >> 4);
pDevice->sRxDFCB[ii].wFragNum = (pMACHeader->wSeqCtl & 0x000F);
memcpy(&(pDevice->sRxDFCB[ii].abyAddr2[0]), &(pMACHeader->abyAddr2[0]), ETH_ALEN);
@@ -172,15 +172,15 @@ UINT ii;
* Out:
* none
*
- * Return Value: TRUE if it is valid fragment packet and we have resource to defragment; otherwise FALSE
+ * Return Value: true if it is valid fragment packet and we have resource to defragment; otherwise false
*
*/
-BOOL WCTLbHandleFragment (PSDevice pDevice, PS802_11Header pMACHeader, UINT cbFrameLength, BOOL bWEP, BOOL bExtIV)
+bool WCTLbHandleFragment (PSDevice pDevice, PS802_11Header pMACHeader, unsigned int cbFrameLength, bool bWEP, bool bExtIV)
{
-UINT uHeaderSize;
+unsigned int uHeaderSize;
- if (bWEP == TRUE) {
+ if (bWEP == true) {
uHeaderSize = 28;
if (bExtIV)
// ExtIV
@@ -201,17 +201,17 @@ UINT uHeaderSize;
else {
pDevice->uCurrentDFCBIdx = WCTLuInsertDFCB(pDevice, pMACHeader);
if (pDevice->uCurrentDFCBIdx == pDevice->cbDFCB) {
- return(FALSE);
+ return(false);
}
}
// reserve 4 byte to match MAC RX Buffer
- pDevice->sRxDFCB[pDevice->uCurrentDFCBIdx].pbyRxBuffer = (PBYTE) (pDevice->sRxDFCB[pDevice->uCurrentDFCBIdx].skb->data + 4);
+ pDevice->sRxDFCB[pDevice->uCurrentDFCBIdx].pbyRxBuffer = (unsigned char *) (pDevice->sRxDFCB[pDevice->uCurrentDFCBIdx].skb->data + 4);
memcpy(pDevice->sRxDFCB[pDevice->uCurrentDFCBIdx].pbyRxBuffer, pMACHeader, cbFrameLength);
pDevice->sRxDFCB[pDevice->uCurrentDFCBIdx].cbFrameLength = cbFrameLength;
pDevice->sRxDFCB[pDevice->uCurrentDFCBIdx].pbyRxBuffer += cbFrameLength;
pDevice->sRxDFCB[pDevice->uCurrentDFCBIdx].wFragNum++;
//DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "First pDevice->uCurrentDFCBIdx= %d\n", pDevice->uCurrentDFCBIdx);
- return(FALSE);
+ return(false);
}
else {
pDevice->uCurrentDFCBIdx = WCTLuSearchDFCB(pDevice, pMACHeader);
@@ -220,7 +220,7 @@ UINT uHeaderSize;
(pDevice->sRxDFCB[pDevice->uCurrentDFCBIdx].wFragNum == (pMACHeader->wSeqCtl & 0x000F)) &&
((pDevice->sRxDFCB[pDevice->uCurrentDFCBIdx].cbFrameLength + cbFrameLength - uHeaderSize) < 2346)) {
- memcpy(pDevice->sRxDFCB[pDevice->uCurrentDFCBIdx].pbyRxBuffer, ((PBYTE) (pMACHeader) + uHeaderSize), (cbFrameLength - uHeaderSize));
+ memcpy(pDevice->sRxDFCB[pDevice->uCurrentDFCBIdx].pbyRxBuffer, ((unsigned char *) (pMACHeader) + uHeaderSize), (cbFrameLength - uHeaderSize));
pDevice->sRxDFCB[pDevice->uCurrentDFCBIdx].cbFrameLength += (cbFrameLength - uHeaderSize);
pDevice->sRxDFCB[pDevice->uCurrentDFCBIdx].pbyRxBuffer += (cbFrameLength - uHeaderSize);
pDevice->sRxDFCB[pDevice->uCurrentDFCBIdx].wFragNum++;
@@ -229,21 +229,21 @@ UINT uHeaderSize;
else {
// seq error or frag # error flush DFCB
pDevice->cbFreeDFCB++;
- pDevice->sRxDFCB[pDevice->uCurrentDFCBIdx].bInUse = FALSE;
- return(FALSE);
+ pDevice->sRxDFCB[pDevice->uCurrentDFCBIdx].bInUse = false;
+ return(false);
}
}
else {
- return(FALSE);
+ return(false);
}
if (IS_LAST_FRAGMENT_PKT(pMACHeader)) {
//enq defragcontrolblock
pDevice->cbFreeDFCB++;
- pDevice->sRxDFCB[pDevice->uCurrentDFCBIdx].bInUse = FALSE;
+ pDevice->sRxDFCB[pDevice->uCurrentDFCBIdx].bInUse = false;
//DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Last pDevice->uCurrentDFCBIdx= %d\n", pDevice->uCurrentDFCBIdx);
- return(TRUE);
+ return(true);
}
- return(FALSE);
+ return(false);
}
}
diff --git a/drivers/staging/vt6655/wctl.h b/drivers/staging/vt6655/wctl.h
index a1ac4791bfd..a92bb6d2b3f 100644
--- a/drivers/staging/vt6655/wctl.h
+++ b/drivers/staging/vt6655/wctl.h
@@ -97,10 +97,11 @@
/*--------------------- Export Functions --------------------------*/
-BOOL WCTLbIsDuplicate(PSCache pCache, PS802_11Header pMACHeader);
-BOOL WCTLbHandleFragment(PSDevice pDevice, PS802_11Header pMACHeader, UINT cbFrameLength, BOOL bWEP, BOOL bExtIV);
-UINT WCTLuSearchDFCB(PSDevice pDevice, PS802_11Header pMACHeader);
-UINT WCTLuInsertDFCB(PSDevice pDevice, PS802_11Header pMACHeader);
+bool WCTLbIsDuplicate(PSCache pCache, PS802_11Header pMACHeader);
+bool WCTLbHandleFragment(PSDevice pDevice, PS802_11Header pMACHeader,
+ unsigned int cbFrameLength, bool bWEP, bool bExtIV);
+unsigned int WCTLuSearchDFCB(PSDevice pDevice, PS802_11Header pMACHeader);
+unsigned int WCTLuInsertDFCB(PSDevice pDevice, PS802_11Header pMACHeader);
#endif // __WCTL_H__
diff --git a/drivers/staging/vt6655/wmgr.c b/drivers/staging/vt6655/wmgr.c
index 8af356fd139..e540110a430 100644
--- a/drivers/staging/vt6655/wmgr.c
+++ b/drivers/staging/vt6655/wmgr.c
@@ -65,6 +65,7 @@
#include "desc.h"
#include "device.h"
#include "card.h"
+#include "channel.h"
#include "80211hdr.h"
#include "80211mgr.h"
#include "wmgr.h"
@@ -93,9 +94,9 @@ static int msglevel =MSG_LEVEL_INFO;
/*--------------------- Static Functions --------------------------*/
//2008-8-4 <add> by chester
-static BOOL ChannelExceedZoneType(
+static bool ChannelExceedZoneType(
PSDevice pDevice,
- BYTE byCurrChannel
+ unsigned char byCurrChannel
);
// Association/diassociation functions
@@ -104,9 +105,9 @@ PSTxMgmtPacket
s_MgrMakeAssocRequest(
PSDevice pDevice,
PSMgmtObject pMgmt,
- PBYTE pDAddr,
- WORD wCurrCapInfo,
- WORD wListenInterval,
+ unsigned char *pDAddr,
+ unsigned short wCurrCapInfo,
+ unsigned short wListenInterval,
PWLAN_IE_SSID pCurrSSID,
PWLAN_IE_SUPP_RATES pCurrRates,
PWLAN_IE_SUPP_RATES pCurrExtSuppRates
@@ -118,7 +119,7 @@ s_vMgrRxAssocRequest(
PSDevice pDevice,
PSMgmtObject pMgmt,
PSRxMgmtPacket pRxPacket,
- UINT uNodeIndex
+ unsigned int uNodeIndex
);
static
@@ -126,9 +127,9 @@ PSTxMgmtPacket
s_MgrMakeReAssocRequest(
PSDevice pDevice,
PSMgmtObject pMgmt,
- PBYTE pDAddr,
- WORD wCurrCapInfo,
- WORD wListenInterval,
+ unsigned char *pDAddr,
+ unsigned short wCurrCapInfo,
+ unsigned short wListenInterval,
PWLAN_IE_SSID pCurrSSID,
PWLAN_IE_SUPP_RATES pCurrRates,
PWLAN_IE_SUPP_RATES pCurrExtSuppRates
@@ -140,7 +141,7 @@ s_vMgrRxAssocResponse(
PSDevice pDevice,
PSMgmtObject pMgmt,
PSRxMgmtPacket pRxPacket,
- BOOL bReAssocType
+ bool bReAssocType
);
static
@@ -225,7 +226,7 @@ s_vMgrRxBeacon(
PSDevice pDevice,
PSMgmtObject pMgmt,
PSRxMgmtPacket pRxPacket,
- BOOL bInScan
+ bool bInScan
);
static
@@ -240,12 +241,12 @@ PSTxMgmtPacket
s_MgrMakeBeacon(
PSDevice pDevice,
PSMgmtObject pMgmt,
- WORD wCurrCapInfo,
- WORD wCurrBeaconPeriod,
- UINT uCurrChannel,
- WORD wCurrATIMWinodw,
+ unsigned short wCurrCapInfo,
+ unsigned short wCurrBeaconPeriod,
+ unsigned int uCurrChannel,
+ unsigned short wCurrATIMWinodw,
PWLAN_IE_SSID pCurrSSID,
- PBYTE pCurrBSSID,
+ unsigned char *pCurrBSSID,
PWLAN_IE_SUPP_RATES pCurrSuppRates,
PWLAN_IE_SUPP_RATES pCurrExtSuppRates
);
@@ -257,10 +258,10 @@ PSTxMgmtPacket
s_MgrMakeAssocResponse(
PSDevice pDevice,
PSMgmtObject pMgmt,
- WORD wCurrCapInfo,
- WORD wAssocStatus,
- WORD wAssocAID,
- PBYTE pDstAddr,
+ unsigned short wCurrCapInfo,
+ unsigned short wAssocStatus,
+ unsigned short wAssocAID,
+ unsigned char *pDstAddr,
PWLAN_IE_SUPP_RATES pCurrSuppRates,
PWLAN_IE_SUPP_RATES pCurrExtSuppRates
);
@@ -271,10 +272,10 @@ PSTxMgmtPacket
s_MgrMakeReAssocResponse(
PSDevice pDevice,
PSMgmtObject pMgmt,
- WORD wCurrCapInfo,
- WORD wAssocStatus,
- WORD wAssocAID,
- PBYTE pDstAddr,
+ unsigned short wCurrCapInfo,
+ unsigned short wAssocStatus,
+ unsigned short wAssocAID,
+ unsigned char *pDstAddr,
PWLAN_IE_SUPP_RATES pCurrSuppRates,
PWLAN_IE_SUPP_RATES pCurrExtSuppRates
);
@@ -285,16 +286,16 @@ PSTxMgmtPacket
s_MgrMakeProbeResponse(
PSDevice pDevice,
PSMgmtObject pMgmt,
- WORD wCurrCapInfo,
- WORD wCurrBeaconPeriod,
- UINT uCurrChannel,
- WORD wCurrATIMWinodw,
- PBYTE pDstAddr,
+ unsigned short wCurrCapInfo,
+ unsigned short wCurrBeaconPeriod,
+ unsigned int uCurrChannel,
+ unsigned short wCurrATIMWinodw,
+ unsigned char *pDstAddr,
PWLAN_IE_SSID pCurrSSID,
- PBYTE pCurrBSSID,
+ unsigned char *pCurrBSSID,
PWLAN_IE_SUPP_RATES pCurrSuppRates,
PWLAN_IE_SUPP_RATES pCurrExtSuppRates,
- BYTE byPHYType
+ unsigned char byPHYType
);
// received status
@@ -302,7 +303,7 @@ static
void
s_vMgrLogStatus(
PSMgmtObject pMgmt,
- WORD wStatus
+ unsigned short wStatus
);
@@ -310,18 +311,18 @@ static
void
s_vMgrSynchBSS (
PSDevice pDevice,
- UINT uBSSMode,
+ unsigned int uBSSMode,
PKnownBSS pCurr,
PCMD_STATUS pStatus
);
-static BOOL
+static bool
s_bCipherMatch (
PKnownBSS pBSSNode,
NDIS_802_11_ENCRYPTION_STATUS EncStatus,
- PBYTE pbyCCSPK,
- PBYTE pbyCCSGK
+ unsigned char *pbyCCSPK,
+ unsigned char *pbyCCSGK
);
static void Encyption_Rebuild(
@@ -368,7 +369,7 @@ vMgrObjectInit(
pMgmt->byCSSPK = KEY_CTL_NONE;
pMgmt->byCSSGK = KEY_CTL_NONE;
pMgmt->wIBSSBeaconPeriod = DEFAULT_IBSS_BI;
- BSSvClearBSSList((void *)pDevice, FALSE);
+ BSSvClearBSSList((void *)pDevice, false);
return;
}
@@ -393,22 +394,22 @@ vMgrTimerInit(
init_timer(&pMgmt->sTimerSecondCallback);
- pMgmt->sTimerSecondCallback.data = (ULONG)pDevice;
+ pMgmt->sTimerSecondCallback.data = (unsigned long) pDevice;
pMgmt->sTimerSecondCallback.function = (TimerFunction)BSSvSecondCallBack;
pMgmt->sTimerSecondCallback.expires = RUN_AT(HZ);
init_timer(&pDevice->sTimerCommand);
- pDevice->sTimerCommand.data = (ULONG)pDevice;
+ pDevice->sTimerCommand.data = (unsigned long) pDevice;
pDevice->sTimerCommand.function = (TimerFunction)vCommandTimer;
pDevice->sTimerCommand.expires = RUN_AT(HZ);
#ifdef TxInSleep
init_timer(&pDevice->sTimerTxData);
- pDevice->sTimerTxData.data = (ULONG)pDevice;
+ pDevice->sTimerTxData.data = (unsigned long) pDevice;
pDevice->sTimerTxData.function = (TimerFunction)BSSvSecondTxData;
pDevice->sTimerTxData.expires = RUN_AT(10*HZ); //10s callback
- pDevice->fTxDataInSleep = FALSE;
- pDevice->IsTxDataTrigger = FALSE;
+ pDevice->fTxDataInSleep = false;
+ pDevice->IsTxDataTrigger = false;
pDevice->nTxDataTimeCout = 0;
#endif
@@ -441,7 +442,7 @@ vMgrObjectReset(
pMgmt->eCurrMode = WMAC_MODE_STANDBY;
pMgmt->eCurrState = WMAC_STATE_IDLE;
- pDevice->bEnablePSMode = FALSE;
+ pDevice->bEnablePSMode = false;
// TODO: timer
return;
@@ -487,15 +488,15 @@ vMgrAssocBeginSta(
// ERP Phy (802.11g) should support short preamble.
if (pMgmt->eCurrentPHYMode == PHY_TYPE_11G) {
pMgmt->wCurrCapInfo |= WLAN_SET_CAP_INFO_SHORTPREAMBLE(1);
- if (CARDbIsShorSlotTime(pMgmt->pAdapter) == TRUE) {
+ if (CARDbIsShorSlotTime(pMgmt->pAdapter) == true) {
pMgmt->wCurrCapInfo |= WLAN_SET_CAP_INFO_SHORTSLOTTIME(1);
}
} else if (pMgmt->eCurrentPHYMode == PHY_TYPE_11B) {
- if (CARDbIsShortPreamble(pMgmt->pAdapter) == TRUE) {
+ if (CARDbIsShortPreamble(pMgmt->pAdapter) == true) {
pMgmt->wCurrCapInfo |= WLAN_SET_CAP_INFO_SHORTPREAMBLE(1);
}
}
- if (pMgmt->b11hEnable == TRUE)
+ if (pMgmt->b11hEnable == true)
pMgmt->wCurrCapInfo |= WLAN_SET_CAP_INFO_SPECTRUMMNG(1);
/* build an assocreq frame and send it */
@@ -566,15 +567,15 @@ vMgrReAssocBeginSta(
// ERP Phy (802.11g) should support short preamble.
if (pMgmt->eCurrentPHYMode == PHY_TYPE_11G) {
pMgmt->wCurrCapInfo |= WLAN_SET_CAP_INFO_SHORTPREAMBLE(1);
- if (CARDbIsShorSlotTime(pMgmt->pAdapter) == TRUE) {
+ if (CARDbIsShorSlotTime(pMgmt->pAdapter) == true) {
pMgmt->wCurrCapInfo |= WLAN_SET_CAP_INFO_SHORTSLOTTIME(1);
}
} else if (pMgmt->eCurrentPHYMode == PHY_TYPE_11B) {
- if (CARDbIsShortPreamble(pMgmt->pAdapter) == TRUE) {
+ if (CARDbIsShortPreamble(pMgmt->pAdapter) == true) {
pMgmt->wCurrCapInfo |= WLAN_SET_CAP_INFO_SHORTPREAMBLE(1);
}
}
- if (pMgmt->b11hEnable == TRUE)
+ if (pMgmt->b11hEnable == true)
pMgmt->wCurrCapInfo |= WLAN_SET_CAP_INFO_SPECTRUMMNG(1);
@@ -619,8 +620,8 @@ void
vMgrDisassocBeginSta(
void *hDeviceContext,
PSMgmtObject pMgmt,
- PBYTE abyDestAddress,
- WORD wReason,
+ unsigned char *abyDestAddress,
+ unsigned short wReason,
PCMD_STATUS pStatus
)
{
@@ -630,10 +631,10 @@ vMgrDisassocBeginSta(
pTxPacket = (PSTxMgmtPacket)pMgmt->pbyMgmtPacketPool;
memset(pTxPacket, 0, sizeof(STxMgmtPacket) + WLAN_DISASSOC_FR_MAXLEN);
- pTxPacket->p80211Header = (PUWLAN_80211HDR)((PBYTE)pTxPacket + sizeof(STxMgmtPacket));
+ pTxPacket->p80211Header = (PUWLAN_80211HDR)((unsigned char *)pTxPacket + sizeof(STxMgmtPacket));
// Setup the sFrame structure
- sFrame.pBuf = (PBYTE)pTxPacket->p80211Header;
+ sFrame.pBuf = (unsigned char *)pTxPacket->p80211Header;
sFrame.len = WLAN_DISASSOC_FR_MAXLEN;
// format fixed field frame structure
@@ -683,17 +684,17 @@ s_vMgrRxAssocRequest(
PSDevice pDevice,
PSMgmtObject pMgmt,
PSRxMgmtPacket pRxPacket,
- UINT uNodeIndex
+ unsigned int uNodeIndex
)
{
WLAN_FR_ASSOCREQ sFrame;
CMD_STATUS Status;
PSTxMgmtPacket pTxPacket;
- WORD wAssocStatus = 0;
- WORD wAssocAID = 0;
- UINT uRateLen = WLAN_RATES_MAXLEN;
- BYTE abyCurrSuppRates[WLAN_IEHDR_LEN + WLAN_RATES_MAXLEN + 1];
- BYTE abyCurrExtSuppRates[WLAN_IEHDR_LEN + WLAN_RATES_MAXLEN + 1];
+ unsigned short wAssocStatus = 0;
+ unsigned short wAssocAID = 0;
+ unsigned int uRateLen = WLAN_RATES_MAXLEN;
+ unsigned char abyCurrSuppRates[WLAN_IEHDR_LEN + WLAN_RATES_MAXLEN + 1];
+ unsigned char abyCurrExtSuppRates[WLAN_IEHDR_LEN + WLAN_RATES_MAXLEN + 1];
if (pMgmt->eCurrMode != WMAC_MODE_ESS_AP)
@@ -708,7 +709,7 @@ s_vMgrRxAssocRequest(
memset(abyCurrSuppRates, 0, WLAN_IEHDR_LEN + WLAN_RATES_MAXLEN + 1);
memset(abyCurrExtSuppRates, 0, WLAN_IEHDR_LEN + WLAN_RATES_MAXLEN + 1);
sFrame.len = pRxPacket->cbMPDULen;
- sFrame.pBuf = (PBYTE)pRxPacket->p80211Header;
+ sFrame.pBuf = (unsigned char *)pRxPacket->p80211Header;
vMgrDecodeAssocRequest(&sFrame);
@@ -717,7 +718,7 @@ s_vMgrRxAssocRequest(
pMgmt->sNodeDBTable[uNodeIndex].wCapInfo = cpu_to_le16(*sFrame.pwCapInfo);
pMgmt->sNodeDBTable[uNodeIndex].wListenInterval = cpu_to_le16(*sFrame.pwListenInterval);
pMgmt->sNodeDBTable[uNodeIndex].bPSEnable =
- WLAN_GET_FC_PWRMGT(sFrame.pHdr->sA3.wFrameCtl) ? TRUE : FALSE;
+ WLAN_GET_FC_PWRMGT(sFrame.pHdr->sA3.wFrameCtl) ? true : false;
// Todo: check sta basic rate, if ap can't support, set status code
if (pDevice->eCurrentPHYType == PHY_TYPE_11B) {
uRateLen = WLAN_RATES_MAXLEN_11B;
@@ -739,7 +740,7 @@ s_vMgrRxAssocRequest(
RATEvParseMaxRate((void *)pDevice,
(PWLAN_IE_SUPP_RATES)abyCurrSuppRates,
(PWLAN_IE_SUPP_RATES)abyCurrExtSuppRates,
- FALSE, // do not change our basic rate
+ false, // do not change our basic rate
&(pMgmt->sNodeDBTable[uNodeIndex].wMaxBasicRate),
&(pMgmt->sNodeDBTable[uNodeIndex].wMaxSuppRate),
&(pMgmt->sNodeDBTable[uNodeIndex].wSuppRate),
@@ -758,20 +759,20 @@ s_vMgrRxAssocRequest(
WLAN_GET_CAP_INFO_SHORTPREAMBLE(*sFrame.pwCapInfo);
pMgmt->sNodeDBTable[uNodeIndex].bShortSlotTime =
WLAN_GET_CAP_INFO_SHORTSLOTTIME(*sFrame.pwCapInfo);
- pMgmt->sNodeDBTable[uNodeIndex].wAID = (WORD)uNodeIndex;
+ pMgmt->sNodeDBTable[uNodeIndex].wAID = (unsigned short)uNodeIndex;
wAssocStatus = WLAN_MGMT_STATUS_SUCCESS;
- wAssocAID = (WORD)uNodeIndex;
+ wAssocAID = (unsigned short)uNodeIndex;
// check if ERP support
if(pMgmt->sNodeDBTable[uNodeIndex].wMaxSuppRate > RATE_11M)
- pMgmt->sNodeDBTable[uNodeIndex].bERPExist = TRUE;
+ pMgmt->sNodeDBTable[uNodeIndex].bERPExist = true;
if (pMgmt->sNodeDBTable[uNodeIndex].wMaxSuppRate <= RATE_11M) {
// B only STA join
- pDevice->bProtectMode = TRUE;
- pDevice->bNonERPPresent = TRUE;
+ pDevice->bProtectMode = true;
+ pDevice->bNonERPPresent = true;
}
- if (pMgmt->sNodeDBTable[uNodeIndex].bShortPreamble == FALSE) {
- pDevice->bBarkerPreambleMd = TRUE;
+ if (pMgmt->sNodeDBTable[uNodeIndex].bShortPreamble == false) {
+ pDevice->bBarkerPreambleMd = true;
}
DBG_PRT(MSG_LEVEL_INFO, KERN_INFO "Associate AID= %d \n", wAssocAID);
@@ -845,17 +846,17 @@ s_vMgrRxReAssocRequest(
PSDevice pDevice,
PSMgmtObject pMgmt,
PSRxMgmtPacket pRxPacket,
- UINT uNodeIndex
+ unsigned int uNodeIndex
)
{
WLAN_FR_REASSOCREQ sFrame;
CMD_STATUS Status;
PSTxMgmtPacket pTxPacket;
- WORD wAssocStatus = 0;
- WORD wAssocAID = 0;
- UINT uRateLen = WLAN_RATES_MAXLEN;
- BYTE abyCurrSuppRates[WLAN_IEHDR_LEN + WLAN_RATES_MAXLEN + 1];
- BYTE abyCurrExtSuppRates[WLAN_IEHDR_LEN + WLAN_RATES_MAXLEN + 1];
+ unsigned short wAssocStatus = 0;
+ unsigned short wAssocAID = 0;
+ unsigned int uRateLen = WLAN_RATES_MAXLEN;
+ unsigned char abyCurrSuppRates[WLAN_IEHDR_LEN + WLAN_RATES_MAXLEN + 1];
+ unsigned char abyCurrExtSuppRates[WLAN_IEHDR_LEN + WLAN_RATES_MAXLEN + 1];
if (pMgmt->eCurrMode != WMAC_MODE_ESS_AP)
return;
@@ -866,7 +867,7 @@ s_vMgrRxReAssocRequest(
//decode the frame
memset(&sFrame, 0, sizeof(WLAN_FR_REASSOCREQ));
sFrame.len = pRxPacket->cbMPDULen;
- sFrame.pBuf = (PBYTE)pRxPacket->p80211Header;
+ sFrame.pBuf = (unsigned char *)pRxPacket->p80211Header;
vMgrDecodeReassocRequest(&sFrame);
if (pMgmt->sNodeDBTable[uNodeIndex].eNodeState >= NODE_AUTH) {
@@ -874,7 +875,7 @@ s_vMgrRxReAssocRequest(
pMgmt->sNodeDBTable[uNodeIndex].wCapInfo = cpu_to_le16(*sFrame.pwCapInfo);
pMgmt->sNodeDBTable[uNodeIndex].wListenInterval = cpu_to_le16(*sFrame.pwListenInterval);
pMgmt->sNodeDBTable[uNodeIndex].bPSEnable =
- WLAN_GET_FC_PWRMGT(sFrame.pHdr->sA3.wFrameCtl) ? TRUE : FALSE;
+ WLAN_GET_FC_PWRMGT(sFrame.pHdr->sA3.wFrameCtl) ? true : false;
// Todo: check sta basic rate, if ap can't support, set status code
if (pDevice->eCurrentPHYType == PHY_TYPE_11B) {
@@ -898,7 +899,7 @@ s_vMgrRxReAssocRequest(
RATEvParseMaxRate((void *)pDevice,
(PWLAN_IE_SUPP_RATES)abyCurrSuppRates,
(PWLAN_IE_SUPP_RATES)abyCurrExtSuppRates,
- FALSE, // do not change our basic rate
+ false, // do not change our basic rate
&(pMgmt->sNodeDBTable[uNodeIndex].wMaxBasicRate),
&(pMgmt->sNodeDBTable[uNodeIndex].wMaxSuppRate),
&(pMgmt->sNodeDBTable[uNodeIndex].wSuppRate),
@@ -917,21 +918,21 @@ s_vMgrRxReAssocRequest(
WLAN_GET_CAP_INFO_SHORTPREAMBLE(*sFrame.pwCapInfo);
pMgmt->sNodeDBTable[uNodeIndex].bShortSlotTime =
WLAN_GET_CAP_INFO_SHORTSLOTTIME(*sFrame.pwCapInfo);
- pMgmt->sNodeDBTable[uNodeIndex].wAID = (WORD)uNodeIndex;
+ pMgmt->sNodeDBTable[uNodeIndex].wAID = (unsigned short)uNodeIndex;
wAssocStatus = WLAN_MGMT_STATUS_SUCCESS;
- wAssocAID = (WORD)uNodeIndex;
+ wAssocAID = (unsigned short)uNodeIndex;
// if suppurt ERP
if(pMgmt->sNodeDBTable[uNodeIndex].wMaxSuppRate > RATE_11M)
- pMgmt->sNodeDBTable[uNodeIndex].bERPExist = TRUE;
+ pMgmt->sNodeDBTable[uNodeIndex].bERPExist = true;
if (pMgmt->sNodeDBTable[uNodeIndex].wMaxSuppRate <= RATE_11M) {
// B only STA join
- pDevice->bProtectMode = TRUE;
- pDevice->bNonERPPresent = TRUE;
+ pDevice->bProtectMode = true;
+ pDevice->bNonERPPresent = true;
}
- if (pMgmt->sNodeDBTable[uNodeIndex].bShortPreamble == FALSE) {
- pDevice->bBarkerPreambleMd = TRUE;
+ if (pMgmt->sNodeDBTable[uNodeIndex].bShortPreamble == false) {
+ pDevice->bBarkerPreambleMd = true;
}
DBG_PRT(MSG_LEVEL_INFO, KERN_INFO "Rx ReAssociate AID= %d \n", wAssocAID);
@@ -995,12 +996,12 @@ s_vMgrRxAssocResponse(
PSDevice pDevice,
PSMgmtObject pMgmt,
PSRxMgmtPacket pRxPacket,
- BOOL bReAssocType
+ bool bReAssocType
)
{
WLAN_FR_ASSOCRESP sFrame;
PWLAN_IE_SSID pItemSSID;
- PBYTE pbyIEs;
+ unsigned char *pbyIEs;
viawget_wpa_header *wpahdr;
@@ -1009,7 +1010,7 @@ s_vMgrRxAssocResponse(
pMgmt->eCurrState == WMAC_STATE_ASSOC) {
sFrame.len = pRxPacket->cbMPDULen;
- sFrame.pBuf = (PBYTE)pRxPacket->p80211Header;
+ sFrame.pBuf = (unsigned char *)pRxPacket->p80211Header;
// decode the frame
vMgrDecodeAssocResponse(&sFrame);
if ((sFrame.pwCapInfo == 0) ||
@@ -1044,7 +1045,7 @@ s_vMgrRxAssocResponse(
BSSvUpdateAPNode((void *)pDevice, sFrame.pwCapInfo, sFrame.pSuppRates, sFrame.pExtSuppRates);
pItemSSID = (PWLAN_IE_SSID)pMgmt->abyCurrSSID;
DBG_PRT(MSG_LEVEL_INFO, KERN_INFO "Link with AP(SSID): %s\n", pItemSSID->abySSID);
- pDevice->bLinkPass = TRUE;
+ pDevice->bLinkPass = true;
pDevice->uBBVGADiffCount = 0;
if ((pDevice->bWPADEVUp) && (pDevice->skb != NULL)) {
if(skb_tailroom(pDevice->skb) <(sizeof(viawget_wpa_header)+pMgmt->sAssocInfo.AssocInfo.ResponseIELength+
@@ -1073,9 +1074,9 @@ s_vMgrRxAssocResponse(
//2008-0409-07, <Add> by Einsn Liu
#ifdef WPA_SUPPLICANT_DRIVER_WEXT_SUPPORT
- //if(pDevice->bWPADevEnable == TRUE)
+ //if(pDevice->bWPADevEnable == true)
{
- BYTE buf[512];
+ unsigned char buf[512];
size_t len;
union iwreq_data wrqu;
int we_event;
@@ -1128,7 +1129,7 @@ s_vMgrRxAssocResponse(
//need clear flags related to Networkmanager
pDevice->bwextcount = 0;
- pDevice->bWPASuppWextEnabled = FALSE;
+ pDevice->bWPASuppWextEnabled = false;
#endif
@@ -1163,8 +1164,8 @@ vMgrAuthenBeginSta(
pTxPacket = (PSTxMgmtPacket)pMgmt->pbyMgmtPacketPool;
memset(pTxPacket, 0, sizeof(STxMgmtPacket) + WLAN_AUTHEN_FR_MAXLEN);
- pTxPacket->p80211Header = (PUWLAN_80211HDR)((PBYTE)pTxPacket + sizeof(STxMgmtPacket));
- sFrame.pBuf = (PBYTE)pTxPacket->p80211Header;
+ pTxPacket->p80211Header = (PUWLAN_80211HDR)((unsigned char *)pTxPacket + sizeof(STxMgmtPacket));
+ sFrame.pBuf = (unsigned char *)pTxPacket->p80211Header;
sFrame.len = WLAN_AUTHEN_FR_MAXLEN;
vMgrEncodeAuthen(&sFrame);
/* insert values */
@@ -1212,8 +1213,8 @@ void
vMgrDeAuthenBeginSta(
void *hDeviceContext,
PSMgmtObject pMgmt,
- PBYTE abyDestAddress,
- WORD wReason,
+ unsigned char *abyDestAddress,
+ unsigned short wReason,
PCMD_STATUS pStatus
)
{
@@ -1224,8 +1225,8 @@ vMgrDeAuthenBeginSta(
pTxPacket = (PSTxMgmtPacket)pMgmt->pbyMgmtPacketPool;
memset(pTxPacket, 0, sizeof(STxMgmtPacket) + WLAN_DEAUTHEN_FR_MAXLEN);
- pTxPacket->p80211Header = (PUWLAN_80211HDR)((PBYTE)pTxPacket + sizeof(STxMgmtPacket));
- sFrame.pBuf = (PBYTE)pTxPacket->p80211Header;
+ pTxPacket->p80211Header = (PUWLAN_80211HDR)((unsigned char *)pTxPacket + sizeof(STxMgmtPacket));
+ sFrame.pBuf = (unsigned char *)pTxPacket->p80211Header;
sFrame.len = WLAN_DEAUTHEN_FR_MAXLEN;
vMgrEncodeDeauthen(&sFrame);
/* insert values */
@@ -1282,7 +1283,7 @@ s_vMgrRxAuthentication(
// decode the frame
sFrame.len = pRxPacket->cbMPDULen;
- sFrame.pBuf = (PBYTE)pRxPacket->p80211Header;
+ sFrame.pBuf = (unsigned char *)pRxPacket->p80211Header;
vMgrDecodeAuthen(&sFrame);
switch (cpu_to_le16((*(sFrame.pwAuthSequence )))){
case 1:
@@ -1331,7 +1332,7 @@ s_vMgrRxAuthenSequence_1(
)
{
PSTxMgmtPacket pTxPacket = NULL;
- UINT uNodeIndex;
+ unsigned int uNodeIndex;
WLAN_FR_AUTHEN sFrame;
PSKeyItem pTransmitKey;
@@ -1353,8 +1354,8 @@ s_vMgrRxAuthenSequence_1(
// send auth reply
pTxPacket = (PSTxMgmtPacket)pMgmt->pbyMgmtPacketPool;
memset(pTxPacket, 0, sizeof(STxMgmtPacket) + WLAN_AUTHEN_FR_MAXLEN);
- pTxPacket->p80211Header = (PUWLAN_80211HDR)((PBYTE)pTxPacket + sizeof(STxMgmtPacket));
- sFrame.pBuf = (PBYTE)pTxPacket->p80211Header;
+ pTxPacket->p80211Header = (PUWLAN_80211HDR)((unsigned char *)pTxPacket + sizeof(STxMgmtPacket));
+ sFrame.pBuf = (unsigned char *)pTxPacket->p80211Header;
sFrame.len = WLAN_AUTHEN_FR_MAXLEN;
// format buffer structure
vMgrEncodeAuthen(&sFrame);
@@ -1393,7 +1394,7 @@ s_vMgrRxAuthenSequence_1(
sFrame.pChallenge->len = WLAN_CHALLENGE_LEN;
memset(pMgmt->abyChallenge, 0, WLAN_CHALLENGE_LEN);
// get group key
- if(KeybGetTransmitKey(&(pDevice->sKey), pDevice->abyBroadcastAddr, GROUP_KEY, &pTransmitKey) == TRUE) {
+ if(KeybGetTransmitKey(&(pDevice->sKey), pDevice->abyBroadcastAddr, GROUP_KEY, &pTransmitKey) == true) {
rc4_init(&pDevice->SBox, pDevice->abyPRNG, pTransmitKey->uKeyLength+3);
rc4_encrypt(&pDevice->SBox, pMgmt->abyChallenge, pMgmt->abyChallenge, WLAN_CHALLENGE_LEN);
}
@@ -1466,8 +1467,8 @@ s_vMgrRxAuthenSequence_2(
if (cpu_to_le16((*(pFrame->pwStatus))) == WLAN_MGMT_STATUS_SUCCESS) {
pTxPacket = (PSTxMgmtPacket)pMgmt->pbyMgmtPacketPool;
memset(pTxPacket, 0, sizeof(STxMgmtPacket) + WLAN_AUTHEN_FR_MAXLEN);
- pTxPacket->p80211Header = (PUWLAN_80211HDR)((PBYTE)pTxPacket + sizeof(STxMgmtPacket));
- sFrame.pBuf = (PBYTE)pTxPacket->p80211Header;
+ pTxPacket->p80211Header = (PUWLAN_80211HDR)((unsigned char *)pTxPacket + sizeof(STxMgmtPacket));
+ sFrame.pBuf = (unsigned char *)pTxPacket->p80211Header;
sFrame.len = WLAN_AUTHEN_FR_MAXLEN;
// format buffer structure
vMgrEncodeAuthen(&sFrame);
@@ -1539,8 +1540,8 @@ s_vMgrRxAuthenSequence_3(
)
{
PSTxMgmtPacket pTxPacket = NULL;
- UINT uStatusCode = 0 ;
- UINT uNodeIndex = 0;
+ unsigned int uStatusCode = 0 ;
+ unsigned int uNodeIndex = 0;
WLAN_FR_AUTHEN sFrame;
if (!WLAN_GET_FC_ISWEP(pFrame->pHdr->sA3.wFrameCtl)) {
@@ -1573,8 +1574,8 @@ reply:
// send auth reply
pTxPacket = (PSTxMgmtPacket)pMgmt->pbyMgmtPacketPool;
memset(pTxPacket, 0, sizeof(STxMgmtPacket) + WLAN_AUTHEN_FR_MAXLEN);
- pTxPacket->p80211Header = (PUWLAN_80211HDR)((PBYTE)pTxPacket + sizeof(STxMgmtPacket));
- sFrame.pBuf = (PBYTE)pTxPacket->p80211Header;
+ pTxPacket->p80211Header = (PUWLAN_80211HDR)((unsigned char *)pTxPacket + sizeof(STxMgmtPacket));
+ sFrame.pBuf = (unsigned char *)pTxPacket->p80211Header;
sFrame.len = WLAN_AUTHEN_FR_MAXLEN;
// format buffer structure
vMgrEncodeAuthen(&sFrame);
@@ -1666,7 +1667,7 @@ s_vMgrRxDisassociation(
)
{
WLAN_FR_DISASSOC sFrame;
- UINT uNodeIndex = 0;
+ unsigned int uNodeIndex = 0;
// CMD_STATUS CmdStatus;
viawget_wpa_header *wpahdr;
@@ -1674,7 +1675,7 @@ s_vMgrRxDisassociation(
// if is acting an AP..
// a STA is leaving this BSS..
sFrame.len = pRxPacket->cbMPDULen;
- sFrame.pBuf = (PBYTE)pRxPacket->p80211Header;
+ sFrame.pBuf = (unsigned char *)pRxPacket->p80211Header;
if (BSSDBbIsSTAInNodeDB(pMgmt, pRxPacket->p80211Header->sA3.abyAddr2, &uNodeIndex)) {
BSSvRemoveOneNode(pDevice, uNodeIndex);
}
@@ -1684,7 +1685,7 @@ s_vMgrRxDisassociation(
}
else if (pMgmt->eCurrMode == WMAC_MODE_ESS_STA ){
sFrame.len = pRxPacket->cbMPDULen;
- sFrame.pBuf = (PBYTE)pRxPacket->p80211Header;
+ sFrame.pBuf = (unsigned char *)pRxPacket->p80211Header;
vMgrDecodeDisassociation(&sFrame);
DBG_PRT(MSG_LEVEL_NOTICE, KERN_INFO "AP disassociated me, reason=%d.\n", cpu_to_le16(*(sFrame.pwReason)));
//TODO: do something let upper layer know or
@@ -1709,7 +1710,7 @@ s_vMgrRxDisassociation(
};
#ifdef WPA_SUPPLICANT_DRIVER_WEXT_SUPPORT
- // if(pDevice->bWPASuppWextEnabled == TRUE)
+ // if(pDevice->bWPASuppWextEnabled == true)
{
union iwreq_data wrqu;
memset(&wrqu, 0, sizeof (wrqu));
@@ -1745,7 +1746,7 @@ s_vMgrRxDeauthentication(
)
{
WLAN_FR_DEAUTHEN sFrame;
- UINT uNodeIndex = 0;
+ unsigned int uNodeIndex = 0;
viawget_wpa_header *wpahdr;
@@ -1754,7 +1755,7 @@ s_vMgrRxDeauthentication(
// if is acting an AP..
// a STA is leaving this BSS..
sFrame.len = pRxPacket->cbMPDULen;
- sFrame.pBuf = (PBYTE)pRxPacket->p80211Header;
+ sFrame.pBuf = (unsigned char *)pRxPacket->p80211Header;
if (BSSDBbIsSTAInNodeDB(pMgmt, pRxPacket->p80211Header->sA3.abyAddr2, &uNodeIndex)) {
BSSvRemoveOneNode(pDevice, uNodeIndex);
}
@@ -1765,17 +1766,17 @@ s_vMgrRxDeauthentication(
else {
if (pMgmt->eCurrMode == WMAC_MODE_ESS_STA ) {
sFrame.len = pRxPacket->cbMPDULen;
- sFrame.pBuf = (PBYTE)pRxPacket->p80211Header;
+ sFrame.pBuf = (unsigned char *)pRxPacket->p80211Header;
vMgrDecodeDeauthen(&sFrame);
DBG_PRT(MSG_LEVEL_NOTICE, KERN_INFO "AP deauthed me, reason=%d.\n", cpu_to_le16((*(sFrame.pwReason))));
// TODO: update BSS list for specific BSSID if pre-authentication case
- if (IS_ETH_ADDRESS_EQUAL(sFrame.pHdr->sA3.abyAddr3, pMgmt->abyCurrBSSID)) {
+ if (!compare_ether_addr(sFrame.pHdr->sA3.abyAddr3, pMgmt->abyCurrBSSID)) {
if (pMgmt->eCurrState >= WMAC_STATE_AUTHPENDING) {
- pMgmt->sNodeDBTable[0].bActive = FALSE;
+ pMgmt->sNodeDBTable[0].bActive = false;
pMgmt->eCurrMode = WMAC_MODE_STANDBY;
pMgmt->eCurrState = WMAC_STATE_IDLE;
netif_stop_queue(pDevice->dev);
- pDevice->bLinkPass = FALSE;
+ pDevice->bLinkPass = false;
}
};
@@ -1795,7 +1796,7 @@ s_vMgrRxDeauthentication(
};
#ifdef WPA_SUPPLICANT_DRIVER_WEXT_SUPPORT
- // if(pDevice->bWPASuppWextEnabled == TRUE)
+ // if(pDevice->bWPASuppWextEnabled == true)
{
union iwreq_data wrqu;
memset(&wrqu, 0, sizeof (wrqu));
@@ -1825,23 +1826,23 @@ s_vMgrRxDeauthentication(
* True:exceed;
* False:normal case
-*/
-static BOOL
+static bool
ChannelExceedZoneType(
PSDevice pDevice,
- BYTE byCurrChannel
+ unsigned char byCurrChannel
)
{
- BOOL exceed=FALSE;
+ bool exceed=false;
switch(pDevice->byZoneType) {
case 0x00: //USA:1~11
if((byCurrChannel<1) ||(byCurrChannel>11))
- exceed = TRUE;
+ exceed = true;
break;
case 0x01: //Japan:1~13
case 0x02: //Europe:1~13
if((byCurrChannel<1) ||(byCurrChannel>13))
- exceed = TRUE;
+ exceed = true;
break;
default: //reserve for other zonetype
break;
@@ -1868,39 +1869,39 @@ s_vMgrRxBeacon(
PSDevice pDevice,
PSMgmtObject pMgmt,
PSRxMgmtPacket pRxPacket,
- BOOL bInScan
+ bool bInScan
)
{
PKnownBSS pBSSList;
WLAN_FR_BEACON sFrame;
QWORD qwTSFOffset;
- BOOL bIsBSSIDEqual = FALSE;
- BOOL bIsSSIDEqual = FALSE;
- BOOL bTSFLargeDiff = FALSE;
- BOOL bTSFOffsetPostive = FALSE;
- BOOL bUpdateTSF = FALSE;
- BOOL bIsAPBeacon = FALSE;
- BOOL bIsChannelEqual = FALSE;
- UINT uLocateByteIndex;
- BYTE byTIMBitOn = 0;
- WORD wAIDNumber = 0;
- UINT uNodeIndex;
+ bool bIsBSSIDEqual = false;
+ bool bIsSSIDEqual = false;
+ bool bTSFLargeDiff = false;
+ bool bTSFOffsetPostive = false;
+ bool bUpdateTSF = false;
+ bool bIsAPBeacon = false;
+ bool bIsChannelEqual = false;
+ unsigned int uLocateByteIndex;
+ unsigned char byTIMBitOn = 0;
+ unsigned short wAIDNumber = 0;
+ unsigned int uNodeIndex;
QWORD qwTimestamp, qwLocalTSF;
QWORD qwCurrTSF;
- WORD wStartIndex = 0;
- WORD wAIDIndex = 0;
- BYTE byCurrChannel = pRxPacket->byRxChannel;
+ unsigned short wStartIndex = 0;
+ unsigned short wAIDIndex = 0;
+ unsigned char byCurrChannel = pRxPacket->byRxChannel;
ERPObject sERP;
- UINT uRateLen = WLAN_RATES_MAXLEN;
- BOOL bChannelHit = FALSE;
- BOOL bUpdatePhyParameter = FALSE;
- BYTE byIEChannel = 0;
+ unsigned int uRateLen = WLAN_RATES_MAXLEN;
+ bool bChannelHit = false;
+ bool bUpdatePhyParameter = false;
+ unsigned char byIEChannel = 0;
memset(&sFrame, 0, sizeof(WLAN_FR_BEACON));
sFrame.len = pRxPacket->cbMPDULen;
- sFrame.pBuf = (PBYTE)pRxPacket->p80211Header;
+ sFrame.pBuf = (unsigned char *)pRxPacket->p80211Header;
// decode the beacon frame
vMgrDecodeBeacon(&sFrame);
@@ -1917,29 +1918,29 @@ s_vMgrRxBeacon(
if (sFrame.pDSParms != NULL) {
if (byCurrChannel > CB_MAX_CHANNEL_24G) {
// channel remapping to
- byIEChannel = CARDbyGetChannelMapping(pDevice, sFrame.pDSParms->byCurrChannel, PHY_TYPE_11A);
+ byIEChannel = get_channel_mapping(pDevice, sFrame.pDSParms->byCurrChannel, PHY_TYPE_11A);
} else {
byIEChannel = sFrame.pDSParms->byCurrChannel;
}
if (byCurrChannel != byIEChannel) {
// adjust channel info. bcs we rcv adjcent channel pakckets
- bChannelHit = FALSE;
+ bChannelHit = false;
byCurrChannel = byIEChannel;
}
} else {
// no DS channel info
- bChannelHit = TRUE;
+ bChannelHit = true;
}
//2008-0730-01<Add>by MikeLiu
-if(ChannelExceedZoneType(pDevice,byCurrChannel)==TRUE)
+if(ChannelExceedZoneType(pDevice,byCurrChannel)==true)
return;
if (sFrame.pERP != NULL) {
sERP.byERP = sFrame.pERP->byContext;
- sERP.bERPExist = TRUE;
+ sERP.bERPExist = true;
} else {
- sERP.bERPExist = FALSE;
+ sERP.bERPExist = false;
sERP.byERP = 0;
}
@@ -1993,8 +1994,8 @@ if(ChannelExceedZoneType(pDevice,byCurrChannel)==TRUE)
return;
}
- if(byCurrChannel == (BYTE)pMgmt->uCurrChannel)
- bIsChannelEqual = TRUE;
+ if(byCurrChannel == (unsigned char)pMgmt->uCurrChannel)
+ bIsChannelEqual = true;
if (bIsChannelEqual && (pMgmt->eCurrMode == WMAC_MODE_ESS_AP)) {
@@ -2021,7 +2022,7 @@ if(ChannelExceedZoneType(pDevice,byCurrChannel)==TRUE)
if (WLAN_GET_ERP_USE_PROTECTION(pDevice->byERPFlag)){
if (!pDevice->bProtectMode) {
MACvEnableProtectMD(pDevice->PortOffset);
- pDevice->bProtectMode = TRUE;
+ pDevice->bProtectMode = true;
}
}
}
@@ -2035,7 +2036,7 @@ if(ChannelExceedZoneType(pDevice,byCurrChannel)==TRUE)
pMgmt->abyCurrBSSID,
WLAN_BSSID_LEN) == 0) {
- bIsBSSIDEqual = TRUE;
+ bIsBSSIDEqual = true;
// 2008-05-21 <add> by Richardtai
pDevice->uCurrRSSI = pRxPacket->uRSSI;
@@ -2052,30 +2053,30 @@ if(ChannelExceedZoneType(pDevice,byCurrChannel)==TRUE)
((PWLAN_IE_SSID)pMgmt->abyCurrSSID)->abySSID,
sFrame.pSSID->len
) == 0) {
- bIsSSIDEqual = TRUE;
+ bIsSSIDEqual = true;
};
}
- if ((WLAN_GET_CAP_INFO_ESS(*sFrame.pwCapInfo)== TRUE) &&
- (bIsBSSIDEqual == TRUE) &&
- (bIsSSIDEqual == TRUE) &&
+ if ((WLAN_GET_CAP_INFO_ESS(*sFrame.pwCapInfo)== true) &&
+ (bIsBSSIDEqual == true) &&
+ (bIsSSIDEqual == true) &&
(pMgmt->eCurrMode == WMAC_MODE_ESS_STA) &&
(pMgmt->eCurrState == WMAC_STATE_ASSOC)) {
// add state check to prevent reconnect fail since we'll receive Beacon
- bIsAPBeacon = TRUE;
+ bIsAPBeacon = true;
if (pBSSList != NULL) {
// Compare PHY paramater setting
if (pMgmt->wCurrCapInfo != pBSSList->wCapInfo) {
- bUpdatePhyParameter = TRUE;
+ bUpdatePhyParameter = true;
pMgmt->wCurrCapInfo = pBSSList->wCapInfo;
}
if (sFrame.pERP != NULL) {
if ((sFrame.pERP->byElementID == WLAN_EID_ERP) &&
(pMgmt->byERPContext != sFrame.pERP->byContext)) {
- bUpdatePhyParameter = TRUE;
+ bUpdatePhyParameter = true;
pMgmt->byERPContext = sFrame.pERP->byContext;
}
}
@@ -2094,7 +2095,7 @@ if(ChannelExceedZoneType(pDevice,byCurrChannel)==TRUE)
RATEvParseMaxRate( (void *)pDevice,
(PWLAN_IE_SUPP_RATES)pMgmt->abyCurrSuppRates,
(PWLAN_IE_SUPP_RATES)pMgmt->abyCurrExtSuppRates,
- TRUE,
+ true,
&(pMgmt->sNodeDBTable[0].wMaxBasicRate),
&(pMgmt->sNodeDBTable[0].wMaxSuppRate),
&(pMgmt->sNodeDBTable[0].wSuppRate),
@@ -2104,7 +2105,7 @@ if(ChannelExceedZoneType(pDevice,byCurrChannel)==TRUE)
#ifdef PLICE_DEBUG
//printk("RxBeacon:MaxSuppRate is %d\n",pMgmt->sNodeDBTable[0].wMaxSuppRate);
#endif
- if (bUpdatePhyParameter == TRUE) {
+ if (bUpdatePhyParameter == true) {
CARDbSetPhyParameter( pMgmt->pAdapter,
pMgmt->eCurrentPHYMode,
pMgmt->wCurrCapInfo,
@@ -2115,19 +2116,19 @@ if(ChannelExceedZoneType(pDevice,byCurrChannel)==TRUE)
}
if (sFrame.pIE_PowerConstraint != NULL) {
CARDvSetPowerConstraint(pMgmt->pAdapter,
- (BYTE) pBSSList->uChannel,
+ (unsigned char) pBSSList->uChannel,
sFrame.pIE_PowerConstraint->byPower
);
}
if (sFrame.pIE_CHSW != NULL) {
CARDbChannelSwitch( pMgmt->pAdapter,
sFrame.pIE_CHSW->byMode,
- CARDbyGetChannelMapping(pMgmt->pAdapter, sFrame.pIE_CHSW->byMode, pMgmt->eCurrentPHYMode),
+ get_channel_mapping(pMgmt->pAdapter, sFrame.pIE_CHSW->byMode, pMgmt->eCurrentPHYMode),
sFrame.pIE_CHSW->byCount
);
- } else if (bIsChannelEqual == FALSE) {
- CARDbSetChannel(pMgmt->pAdapter, pBSSList->uChannel);
+ } else if (bIsChannelEqual == false) {
+ set_channel(pMgmt->pAdapter, pBSSList->uChannel);
}
}
}
@@ -2148,17 +2149,17 @@ if(ChannelExceedZoneType(pDevice,byCurrChannel)==TRUE)
// check if beacon TSF larger or small than our local TSF
if (HIDWORD(qwTimestamp) == HIDWORD(qwLocalTSF)) {
if (LODWORD(qwTimestamp) >= LODWORD(qwLocalTSF)) {
- bTSFOffsetPostive = TRUE;
+ bTSFOffsetPostive = true;
}
else {
- bTSFOffsetPostive = FALSE;
+ bTSFOffsetPostive = false;
}
}
else if (HIDWORD(qwTimestamp) > HIDWORD(qwLocalTSF)) {
- bTSFOffsetPostive = TRUE;
+ bTSFOffsetPostive = true;
}
else if (HIDWORD(qwTimestamp) < HIDWORD(qwLocalTSF)) {
- bTSFOffsetPostive = FALSE;
+ bTSFOffsetPostive = false;
};
if (bTSFOffsetPostive) {
@@ -2170,21 +2171,21 @@ if(ChannelExceedZoneType(pDevice,byCurrChannel)==TRUE)
if (HIDWORD(qwTSFOffset) != 0 ||
(LODWORD(qwTSFOffset) > TRIVIAL_SYNC_DIFFERENCE )) {
- bTSFLargeDiff = TRUE;
+ bTSFLargeDiff = true;
}
// if infra mode
- if (bIsAPBeacon == TRUE) {
+ if (bIsAPBeacon == true) {
// Infra mode: Local TSF always follow AP's TSF if Difference huge.
if (bTSFLargeDiff)
- bUpdateTSF = TRUE;
+ bUpdateTSF = true;
- if ((pDevice->bEnablePSMode == TRUE) &&(sFrame.pTIM != 0)) {
+ if ((pDevice->bEnablePSMode == true) &&(sFrame.pTIM != 0)) {
// deal with DTIM, analysis TIM
- pMgmt->bMulticastTIM = WLAN_MGMT_IS_MULTICAST_TIM(sFrame.pTIM->byBitMapCtl) ? TRUE : FALSE ;
+ pMgmt->bMulticastTIM = WLAN_MGMT_IS_MULTICAST_TIM(sFrame.pTIM->byBitMapCtl) ? true : false ;
pMgmt->byDTIMCount = sFrame.pTIM->byDTIMCount;
pMgmt->byDTIMPeriod = sFrame.pTIM->byDTIMPeriod;
wAIDNumber = pMgmt->wCurrAID & ~(BIT14|BIT15);
@@ -2199,19 +2200,19 @@ if(ChannelExceedZoneType(pDevice,byCurrChannel)==TRUE)
// len = byDTIMCount + byDTIMPeriod + byDTIMPeriod + byVirtBitMap[0~250]
if (sFrame.pTIM->len >= (uLocateByteIndex + 4)) {
byTIMBitOn = (0x01) << ((wAIDNumber) % 8);
- pMgmt->bInTIM = sFrame.pTIM->byVirtBitMap[uLocateByteIndex] & byTIMBitOn ? TRUE : FALSE;
+ pMgmt->bInTIM = sFrame.pTIM->byVirtBitMap[uLocateByteIndex] & byTIMBitOn ? true : false;
}
else {
- pMgmt->bInTIM = FALSE;
+ pMgmt->bInTIM = false;
};
}
else {
- pMgmt->bInTIM = FALSE;
+ pMgmt->bInTIM = false;
};
if (pMgmt->bInTIM ||
(pMgmt->bMulticastTIM && (pMgmt->byDTIMCount == 0))) {
- pMgmt->bInTIMWake = TRUE;
+ pMgmt->bInTIMWake = true;
// send out ps-poll packet
// DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "BCN:In TIM\n");
if (pMgmt->bInTIM) {
@@ -2221,14 +2222,14 @@ if(ChannelExceedZoneType(pDevice,byCurrChannel)==TRUE)
}
else {
- pMgmt->bInTIMWake = FALSE;
+ pMgmt->bInTIMWake = false;
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "BCN: Not In TIM..\n");
- if (pDevice->bPWBitOn == FALSE) {
+ if (pDevice->bPWBitOn == false) {
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "BCN: Send Null Packet\n");
if (PSbSendNullPacket(pDevice))
- pDevice->bPWBitOn = TRUE;
+ pDevice->bPWBitOn = true;
}
- if(PSbConsiderPowerDown(pDevice, FALSE, FALSE)) {
+ if(PSbConsiderPowerDown(pDevice, false, false)) {
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "BCN: Power down now...\n");
};
}
@@ -2246,7 +2247,7 @@ if(ChannelExceedZoneType(pDevice,byCurrChannel)==TRUE)
// adhoc mode:TSF updated only when beacon larger then local TSF
if (bTSFLargeDiff && bTSFOffsetPostive &&
(pMgmt->eCurrState == WMAC_STATE_JOINTED))
- bUpdateTSF = TRUE;
+ bUpdateTSF = true;
// During dpc, already in spinlocked.
if (BSSDBbIsSTAInNodeDB(pMgmt, sFrame.pHdr->sA3.abyAddr2, &uNodeIndex)) {
@@ -2259,7 +2260,7 @@ if(ChannelExceedZoneType(pDevice,byCurrChannel)==TRUE)
RATEvParseMaxRate( (void *)pDevice,
(PWLAN_IE_SUPP_RATES)pMgmt->abyCurrSuppRates,
NULL,
- TRUE,
+ true,
&(pMgmt->sNodeDBTable[uNodeIndex].wMaxBasicRate),
&(pMgmt->sNodeDBTable[uNodeIndex].wMaxSuppRate),
&(pMgmt->sNodeDBTable[uNodeIndex].wSuppRate),
@@ -2280,7 +2281,7 @@ if(ChannelExceedZoneType(pDevice,byCurrChannel)==TRUE)
RATEvParseMaxRate( (void *)pDevice,
(PWLAN_IE_SUPP_RATES)pMgmt->abyCurrSuppRates,
NULL,
- TRUE,
+ true,
&(pMgmt->sNodeDBTable[uNodeIndex].wMaxBasicRate),
&(pMgmt->sNodeDBTable[uNodeIndex].wMaxSuppRate),
&(pMgmt->sNodeDBTable[uNodeIndex].wSuppRate),
@@ -2300,7 +2301,7 @@ if(ChannelExceedZoneType(pDevice,byCurrChannel)==TRUE)
/*
pMgmt->sNodeDBTable[uNodeIndex].bShortSlotTime = WLAN_GET_CAP_INFO_SHORTSLOTTIME(*sFrame.pwCapInfo);
if(pMgmt->sNodeDBTable[uNodeIndex].wMaxSuppRate > RATE_11M)
- pMgmt->sNodeDBTable[uNodeIndex].bERPExist = TRUE;
+ pMgmt->sNodeDBTable[uNodeIndex].bERPExist = true;
*/
}
@@ -2308,11 +2309,11 @@ if(ChannelExceedZoneType(pDevice,byCurrChannel)==TRUE)
if (pMgmt->eCurrState == WMAC_STATE_STARTED) {
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Current IBSS State: [Started]........to: [Jointed] \n");
pMgmt->eCurrState = WMAC_STATE_JOINTED;
- pDevice->bLinkPass = TRUE;
+ pDevice->bLinkPass = true;
if (netif_queue_stopped(pDevice->dev)){
netif_wake_queue(pDevice->dev);
}
- pMgmt->sNodeDBTable[0].bActive = TRUE;
+ pMgmt->sNodeDBTable[0].bActive = true;
pMgmt->sNodeDBTable[0].uInActiveCount = 0;
};
@@ -2392,16 +2393,16 @@ vMgrCreateOwnIBSS(
{
PSDevice pDevice = (PSDevice)hDeviceContext;
PSMgmtObject pMgmt = pDevice->pMgmt;
- WORD wMaxBasicRate;
- WORD wMaxSuppRate;
- BYTE byTopCCKBasicRate;
- BYTE byTopOFDMBasicRate;
+ unsigned short wMaxBasicRate;
+ unsigned short wMaxSuppRate;
+ unsigned char byTopCCKBasicRate;
+ unsigned char byTopOFDMBasicRate;
QWORD qwCurrTSF;
- UINT ii;
- BYTE abyRATE[] = {0x82, 0x84, 0x8B, 0x96, 0x24, 0x30, 0x48, 0x6C, 0x0C, 0x12, 0x18, 0x60};
- BYTE abyCCK_RATE[] = {0x82, 0x84, 0x8B, 0x96};
- BYTE abyOFDM_RATE[] = {0x0C, 0x12, 0x18, 0x24, 0x30, 0x48, 0x60, 0x6C};
- WORD wSuppRate;
+ unsigned int ii;
+ unsigned char abyRATE[] = {0x82, 0x84, 0x8B, 0x96, 0x24, 0x30, 0x48, 0x6C, 0x0C, 0x12, 0x18, 0x60};
+ unsigned char abyCCK_RATE[] = {0x82, 0x84, 0x8B, 0x96};
+ unsigned char abyOFDM_RATE[] = {0x0C, 0x12, 0x18, 0x24, 0x30, 0x48, 0x60, 0x6C};
+ unsigned short wSuppRate;
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Create Basic Service Set .......\n");
@@ -2486,7 +2487,7 @@ vMgrCreateOwnIBSS(
// set basic rate
RATEvParseMaxRate((void *)pDevice, (PWLAN_IE_SUPP_RATES)pMgmt->abyCurrSuppRates,
- (PWLAN_IE_SUPP_RATES)pMgmt->abyCurrExtSuppRates, TRUE,
+ (PWLAN_IE_SUPP_RATES)pMgmt->abyCurrExtSuppRates, true,
&wMaxBasicRate, &wMaxSuppRate, &wSuppRate,
&byTopCCKBasicRate, &byTopOFDMBasicRate);
@@ -2533,12 +2534,12 @@ vMgrCreateOwnIBSS(
if (pMgmt->eCurrMode == WMAC_MODE_IBSS_STA) {
// BSSID selected must be randomized as spec 11.1.3
- pMgmt->abyCurrBSSID[5] = (BYTE) (LODWORD(qwCurrTSF)& 0x000000ff);
- pMgmt->abyCurrBSSID[4] = (BYTE)((LODWORD(qwCurrTSF)& 0x0000ff00) >> 8);
- pMgmt->abyCurrBSSID[3] = (BYTE)((LODWORD(qwCurrTSF)& 0x00ff0000) >> 16);
- pMgmt->abyCurrBSSID[2] = (BYTE)((LODWORD(qwCurrTSF)& 0x00000ff0) >> 4);
- pMgmt->abyCurrBSSID[1] = (BYTE)((LODWORD(qwCurrTSF)& 0x000ff000) >> 12);
- pMgmt->abyCurrBSSID[0] = (BYTE)((LODWORD(qwCurrTSF)& 0x0ff00000) >> 20);
+ pMgmt->abyCurrBSSID[5] = (unsigned char) (LODWORD(qwCurrTSF)& 0x000000ff);
+ pMgmt->abyCurrBSSID[4] = (unsigned char)((LODWORD(qwCurrTSF)& 0x0000ff00) >> 8);
+ pMgmt->abyCurrBSSID[3] = (unsigned char)((LODWORD(qwCurrTSF)& 0x00ff0000) >> 16);
+ pMgmt->abyCurrBSSID[2] = (unsigned char)((LODWORD(qwCurrTSF)& 0x00000ff0) >> 4);
+ pMgmt->abyCurrBSSID[1] = (unsigned char)((LODWORD(qwCurrTSF)& 0x000ff000) >> 12);
+ pMgmt->abyCurrBSSID[0] = (unsigned char)((LODWORD(qwCurrTSF)& 0x0ff00000) >> 20);
pMgmt->abyCurrBSSID[5] ^= pMgmt->abyMACAddr[0];
pMgmt->abyCurrBSSID[4] ^= pMgmt->abyMACAddr[1];
pMgmt->abyCurrBSSID[3] ^= pMgmt->abyMACAddr[2];
@@ -2611,7 +2612,7 @@ vMgrCreateOwnIBSS(
CARDbSetBeaconPeriod(pMgmt->pAdapter, pMgmt->wIBSSBeaconPeriod);
// set channel and clear NAV
- CARDbSetChannel(pMgmt->pAdapter, pMgmt->uIBSSChannel);
+ set_channel(pMgmt->pAdapter, pMgmt->uIBSSChannel);
pMgmt->uCurrChannel = pMgmt->uIBSSChannel;
if (CARDbIsShortPreamble(pMgmt->pAdapter)) {
@@ -2620,7 +2621,7 @@ vMgrCreateOwnIBSS(
pMgmt->wCurrCapInfo &= (~WLAN_SET_CAP_INFO_SHORTPREAMBLE(1));
}
- if ((pMgmt->b11hEnable == TRUE) &&
+ if ((pMgmt->b11hEnable == true) &&
(pMgmt->eCurrentPHYMode == PHY_TYPE_11A)) {
pMgmt->wCurrCapInfo |= WLAN_SET_CAP_INFO_SPECTRUMMNG(1);
} else {
@@ -2661,20 +2662,20 @@ vMgrJoinBSSBegin(
PSDevice pDevice = (PSDevice)hDeviceContext;
PSMgmtObject pMgmt = pDevice->pMgmt;
PKnownBSS pCurr = NULL;
- UINT ii, uu;
+ unsigned int ii, uu;
PWLAN_IE_SUPP_RATES pItemRates = NULL;
PWLAN_IE_SUPP_RATES pItemExtRates = NULL;
PWLAN_IE_SSID pItemSSID;
- UINT uRateLen = WLAN_RATES_MAXLEN;
- WORD wMaxBasicRate = RATE_1M;
- WORD wMaxSuppRate = RATE_1M;
- WORD wSuppRate;
- BYTE byTopCCKBasicRate = RATE_1M;
- BYTE byTopOFDMBasicRate = RATE_1M;
+ unsigned int uRateLen = WLAN_RATES_MAXLEN;
+ unsigned short wMaxBasicRate = RATE_1M;
+ unsigned short wMaxSuppRate = RATE_1M;
+ unsigned short wSuppRate;
+ unsigned char byTopCCKBasicRate = RATE_1M;
+ unsigned char byTopOFDMBasicRate = RATE_1M;
for (ii = 0; ii < MAX_BSS_NUM; ii++) {
- if (pMgmt->sBSSList[ii].bActive == TRUE)
+ if (pMgmt->sBSSList[ii].bActive == true)
break;
}
@@ -2708,14 +2709,14 @@ vMgrJoinBSSBegin(
// patch for CISCO migration mode
/*
if (pDevice->eEncryptionStatus == Ndis802_11Encryption2Enabled) {
- if (WPA_SearchRSN(0, WPA_TKIP, pCurr) == FALSE) {
+ if (WPA_SearchRSN(0, WPA_TKIP, pCurr) == false) {
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"No match RSN info. ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n");
// encryption mode error
pMgmt->eCurrState = WMAC_STATE_IDLE;
return;
}
} else if (pDevice->eEncryptionStatus == Ndis802_11Encryption3Enabled) {
- if (WPA_SearchRSN(0, WPA_AESCCMP, pCurr) == FALSE) {
+ if (WPA_SearchRSN(0, WPA_AESCCMP, pCurr) == false) {
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"No match RSN info. ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n");
// encryption mode error
pMgmt->eCurrState = WMAC_STATE_IDLE;
@@ -2726,7 +2727,7 @@ vMgrJoinBSSBegin(
}
#ifdef WPA_SUPPLICANT_DRIVER_WEXT_SUPPORT
- //if(pDevice->bWPASuppWextEnabled == TRUE)
+ //if(pDevice->bWPASuppWextEnabled == true)
Encyption_Rebuild(pDevice, pCurr);
#endif
// Infrastructure BSS
@@ -2764,15 +2765,15 @@ vMgrJoinBSSBegin(
uRateLen);
// Stuffing Rate IE
if ((pItemExtRates->len > 0) && (pItemRates->len < 8)) {
- for (ii = 0; ii < (UINT)(8 - pItemRates->len); ) {
+ for (ii = 0; ii < (unsigned int)(8 - pItemRates->len); ) {
pItemRates->abyRates[pItemRates->len + ii] = pItemExtRates->abyRates[ii];
ii ++;
if (pItemExtRates->len <= ii)
break;
}
- pItemRates->len += (BYTE)ii;
+ pItemRates->len += (unsigned char)ii;
if (pItemExtRates->len - ii > 0) {
- pItemExtRates->len -= (BYTE)ii;
+ pItemExtRates->len -= (unsigned char)ii;
for (uu = 0; uu < pItemExtRates->len; uu ++) {
pItemExtRates->abyRates[uu] = pItemExtRates->abyRates[uu + ii];
}
@@ -2781,7 +2782,7 @@ vMgrJoinBSSBegin(
}
}
- RATEvParseMaxRate((void *)pDevice, pItemRates, pItemExtRates, TRUE,
+ RATEvParseMaxRate((void *)pDevice, pItemRates, pItemExtRates, true,
&wMaxBasicRate, &wMaxSuppRate, &wSuppRate,
&byTopCCKBasicRate, &byTopOFDMBasicRate);
@@ -2802,9 +2803,9 @@ vMgrJoinBSSBegin(
// Add current BSS to Candidate list
// This should only works for WPA2 BSS, and WPA2 BSS check must be done before.
if (pMgmt->eAuthenMode == WMAC_AUTH_WPA2) {
- BOOL bResult = bAdd_PMKID_Candidate((void *)pDevice, pMgmt->abyCurrBSSID, &pCurr->sRSNCapObj);
+ bool bResult = bAdd_PMKID_Candidate((void *)pDevice, pMgmt->abyCurrBSSID, &pCurr->sRSNCapObj);
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"bAdd_PMKID_Candidate: 1(%d)\n", bResult);
- if (bResult == FALSE) {
+ if (bResult == false) {
vFlush_PMKID_Candidate((void *)pDevice);
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"vFlush_PMKID_Candidate: 4\n");
bAdd_PMKID_Candidate((void *)pDevice, pMgmt->abyCurrBSSID, &pCurr->sRSNCapObj);
@@ -2831,13 +2832,13 @@ vMgrJoinBSSBegin(
if (pMgmt->eAuthenMode == WMAC_AUTH_WPANONE) {
if (pDevice->eEncryptionStatus == Ndis802_11Encryption2Enabled) {
- if (WPA_SearchRSN(0, WPA_TKIP, pCurr) == FALSE) {
+ if (WPA_SearchRSN(0, WPA_TKIP, pCurr) == false) {
// encryption mode error
pMgmt->eCurrState = WMAC_STATE_IDLE;
return;
}
} else if (pDevice->eEncryptionStatus == Ndis802_11Encryption3Enabled) {
- if (WPA_SearchRSN(0, WPA_AESCCMP, pCurr) == FALSE) {
+ if (WPA_SearchRSN(0, WPA_AESCCMP, pCurr) == false) {
// encryption mode error
pMgmt->eCurrState = WMAC_STATE_IDLE;
return;
@@ -2868,7 +2869,7 @@ vMgrJoinBSSBegin(
WLAN_RATES_MAXLEN_11B);
// set basic rate
RATEvParseMaxRate((void *)pDevice, (PWLAN_IE_SUPP_RATES)pMgmt->abyCurrSuppRates,
- NULL, TRUE, &wMaxBasicRate, &wMaxSuppRate, &wSuppRate,
+ NULL, true, &wMaxBasicRate, &wMaxSuppRate, &wSuppRate,
&byTopCCKBasicRate, &byTopOFDMBasicRate);
pMgmt->wCurrCapInfo = pCurr->wCapInfo;
@@ -2883,7 +2884,7 @@ vMgrJoinBSSBegin(
pMgmt->eCurrState = WMAC_STATE_STARTED;
// Adopt BSS state in Adapter Device Object
//pDevice->byOpMode = OP_MODE_ADHOC;
-// pDevice->bLinkPass = TRUE;
+// pDevice->bLinkPass = true;
// memcpy(pDevice->abyBSSID, pCurr->abyBSSID, WLAN_BSSID_LEN);
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Join IBSS ok:%02x-%02x-%02x-%02x-%02x-%02x \n",
@@ -2923,7 +2924,7 @@ static
void
s_vMgrSynchBSS (
PSDevice pDevice,
- UINT uBSSMode,
+ unsigned int uBSSMode,
PKnownBSS pCurr,
PCMD_STATUS pStatus
)
@@ -2932,11 +2933,11 @@ s_vMgrSynchBSS (
PSMgmtObject pMgmt = pDevice->pMgmt;
// int ii;
//1M, 2M, 5M, 11M, 18M, 24M, 36M, 54M
- BYTE abyCurrSuppRatesG[] = {WLAN_EID_SUPP_RATES, 8, 0x02, 0x04, 0x0B, 0x16, 0x24, 0x30, 0x48, 0x6C};
- BYTE abyCurrExtSuppRatesG[] = {WLAN_EID_EXTSUPP_RATES, 4, 0x0C, 0x12, 0x18, 0x60};
+ unsigned char abyCurrSuppRatesG[] = {WLAN_EID_SUPP_RATES, 8, 0x02, 0x04, 0x0B, 0x16, 0x24, 0x30, 0x48, 0x6C};
+ unsigned char abyCurrExtSuppRatesG[] = {WLAN_EID_EXTSUPP_RATES, 4, 0x0C, 0x12, 0x18, 0x60};
//6M, 9M, 12M, 48M
- BYTE abyCurrSuppRatesA[] = {WLAN_EID_SUPP_RATES, 8, 0x0C, 0x12, 0x18, 0x24, 0x30, 0x48, 0x60, 0x6C};
- BYTE abyCurrSuppRatesB[] = {WLAN_EID_SUPP_RATES, 4, 0x02, 0x04, 0x0B, 0x16};
+ unsigned char abyCurrSuppRatesA[] = {WLAN_EID_SUPP_RATES, 8, 0x0C, 0x12, 0x18, 0x24, 0x30, 0x48, 0x60, 0x6C};
+ unsigned char abyCurrSuppRatesB[] = {WLAN_EID_SUPP_RATES, 4, 0x02, 0x04, 0x0B, 0x16};
*pStatus = CMD_STATUS_FAILURE;
@@ -2944,7 +2945,7 @@ s_vMgrSynchBSS (
if (s_bCipherMatch(pCurr,
pDevice->eEncryptionStatus,
&(pMgmt->byCSSPK),
- &(pMgmt->byCSSGK)) == FALSE) {
+ &(pMgmt->byCSSGK)) == false) {
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "s_bCipherMatch Fail .......\n");
return;
}
@@ -2958,12 +2959,12 @@ s_vMgrSynchBSS (
}
// Init the BSS informations
- pDevice->bCCK = TRUE;
- pDevice->bProtectMode = FALSE;
+ pDevice->bCCK = true;
+ pDevice->bProtectMode = false;
MACvDisableProtectMD(pDevice->PortOffset);
- pDevice->bBarkerPreambleMd = FALSE;
+ pDevice->bBarkerPreambleMd = false;
MACvDisableBarkerPreambleMd(pDevice->PortOffset);
- pDevice->bNonERPPresent = FALSE;
+ pDevice->bNonERPPresent = false;
pDevice->byPreambleType = 0;
pDevice->wBasicRate = 0;
// Set Basic Rate
@@ -3046,12 +3047,12 @@ s_vMgrSynchBSS (
pCurr->sERP.byERP,
pMgmt->abyCurrSuppRates,
pMgmt->abyCurrExtSuppRates
- ) != TRUE) {
+ ) != true) {
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "<----s_bSynchBSS Set Phy Mode Fail [%d]\n", ePhyType);
return;
}
// set channel and clear NAV
- if (CARDbSetChannel(pMgmt->pAdapter, pCurr->uChannel) == FALSE) {
+ if (set_channel(pMgmt->pAdapter, pCurr->uChannel) == false) {
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "<----s_bSynchBSS Set Channel [%d]\n", pCurr->uChannel);
return;
}
@@ -3077,7 +3078,7 @@ s_vMgrSynchBSS (
pMgmt->uCurrChannel = pCurr->uChannel;
pMgmt->eCurrentPHYMode = ePhyType;
pMgmt->byERPContext = pCurr->sERP.byERP;
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Sync:Set to channel = [%d]\n", (INT)pCurr->uChannel);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Sync:Set to channel = [%d]\n", (int)pCurr->uChannel);
*pStatus = CMD_STATUS_SUCCESS;
@@ -3094,18 +3095,18 @@ s_vMgrSynchBSS (
)
{
PSMgmtObject pMgmt = &(pDevice->sMgmtObj);
- // UINT ii , uSameBssidNum=0;
+ // unsigned int ii , uSameBssidNum=0;
// for (ii = 0; ii < MAX_BSS_NUM; ii++) {
// if (pMgmt->sBSSList[ii].bActive &&
- // IS_ETH_ADDRESS_EQUAL(pMgmt->sBSSList[ii].abyBSSID, pCurr->abyBSSID)) {
+ // !compare_ether_addr(pMgmt->sBSSList[ii].abyBSSID, pCurr->abyBSSID)) {
// uSameBssidNum++;
// }
// }
// if( uSameBssidNum>=2) { //we only check AP in hidden sssid mode
if ((pMgmt->eAuthenMode == WMAC_AUTH_WPAPSK) || //networkmanager 0.7.0 does not give the pairwise-key selsection,
(pMgmt->eAuthenMode == WMAC_AUTH_WPA2PSK)) { // so we need re-selsect it according to real pairwise-key info.
- if(pCurr->bWPAValid == TRUE) { //WPA-PSK
+ if(pCurr->bWPAValid == true) { //WPA-PSK
pMgmt->eAuthenMode = WMAC_AUTH_WPAPSK;
if(pCurr->abyPKType[0] == WPA_TKIP) {
pDevice->eEncryptionStatus = Ndis802_11Encryption2Enabled; //TKIP
@@ -3116,7 +3117,7 @@ s_vMgrSynchBSS (
PRINT_K("Encyption_Rebuild--->ssid reset config to [WPAPSK-AES]\n");
}
}
- else if(pCurr->bWPA2Valid == TRUE) { //WPA2-PSK
+ else if(pCurr->bWPA2Valid == true) { //WPA2-PSK
pMgmt->eAuthenMode = WMAC_AUTH_WPA2PSK;
if(pCurr->abyCSSPK[0] == WLAN_11i_CSS_TKIP) {
pDevice->eEncryptionStatus = Ndis802_11Encryption2Enabled; //TKIP
@@ -3151,13 +3152,13 @@ s_vMgrFormatTIM(
PWLAN_IE_TIM pTIM
)
{
- BYTE byMask[8] = {1, 2, 4, 8, 0x10, 0x20, 0x40, 0x80};
- BYTE byMap;
- UINT ii, jj;
- BOOL bStartFound = FALSE;
- BOOL bMulticast = FALSE;
- WORD wStartIndex = 0;
- WORD wEndIndex = 0;
+ unsigned char byMask[8] = {1, 2, 4, 8, 0x10, 0x20, 0x40, 0x80};
+ unsigned char byMap;
+ unsigned int ii, jj;
+ bool bStartFound = false;
+ bool bMulticast = false;
+ unsigned short wStartIndex = 0;
+ unsigned short wEndIndex = 0;
// Find size of partial virtual bitmap
@@ -3167,13 +3168,13 @@ s_vMgrFormatTIM(
// Mask out the broadcast bit which is indicated separately.
bMulticast = (byMap & byMask[0]) != 0;
if(bMulticast) {
- pMgmt->sNodeDBTable[0].bRxPSPoll = TRUE;
+ pMgmt->sNodeDBTable[0].bRxPSPoll = true;
}
byMap = 0;
}
if (byMap) {
if (!bStartFound) {
- bStartFound = TRUE;
+ bStartFound = true;
wStartIndex = ii;
}
wEndIndex = ii;
@@ -3224,30 +3225,30 @@ PSTxMgmtPacket
s_MgrMakeBeacon(
PSDevice pDevice,
PSMgmtObject pMgmt,
- WORD wCurrCapInfo,
- WORD wCurrBeaconPeriod,
- UINT uCurrChannel,
- WORD wCurrATIMWinodw,
+ unsigned short wCurrCapInfo,
+ unsigned short wCurrBeaconPeriod,
+ unsigned int uCurrChannel,
+ unsigned short wCurrATIMWinodw,
PWLAN_IE_SSID pCurrSSID,
- PBYTE pCurrBSSID,
+ unsigned char *pCurrBSSID,
PWLAN_IE_SUPP_RATES pCurrSuppRates,
PWLAN_IE_SUPP_RATES pCurrExtSuppRates
)
{
PSTxMgmtPacket pTxPacket = NULL;
WLAN_FR_BEACON sFrame;
- BYTE abyBroadcastAddr[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
- PBYTE pbyBuffer;
- UINT uLength = 0;
+ unsigned char abyBroadcastAddr[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+ unsigned char *pbyBuffer;
+ unsigned int uLength = 0;
PWLAN_IE_IBSS_DFS pIBSSDFS = NULL;
- UINT ii;
+ unsigned int ii;
// prepare beacon frame
pTxPacket = (PSTxMgmtPacket)pMgmt->pbyMgmtPacketPool;
memset(pTxPacket, 0, sizeof(STxMgmtPacket) + WLAN_BEACON_FR_MAXLEN);
- pTxPacket->p80211Header = (PUWLAN_80211HDR)((PBYTE)pTxPacket + sizeof(STxMgmtPacket));
+ pTxPacket->p80211Header = (PUWLAN_80211HDR)((unsigned char *)pTxPacket + sizeof(STxMgmtPacket));
// Setup the sFrame structure.
- sFrame.pBuf = (PBYTE)pTxPacket->p80211Header;
+ sFrame.pBuf = (unsigned char *)pTxPacket->p80211Header;
sFrame.len = WLAN_BEACON_FR_MAXLEN;
vMgrEncodeBeacon(&sFrame);
// Setup the header
@@ -3258,7 +3259,7 @@ s_MgrMakeBeacon(
));
if (pDevice->bEnablePSMode) {
- sFrame.pHdr->sA3.wFrameCtl |= cpu_to_le16((WORD)WLAN_SET_FC_PWRMGT(1));
+ sFrame.pHdr->sA3.wFrameCtl |= cpu_to_le16((unsigned short)WLAN_SET_FC_PWRMGT(1));
}
memcpy( sFrame.pHdr->sA3.abyAddr1, abyBroadcastAddr, WLAN_ADDR_LEN);
@@ -3286,7 +3287,7 @@ s_MgrMakeBeacon(
sFrame.len += (1) + WLAN_IEHDR_LEN;
sFrame.pDSParms->byElementID = WLAN_EID_DS_PARMS;
sFrame.pDSParms->len = 1;
- sFrame.pDSParms->byCurrChannel = (BYTE)uCurrChannel;
+ sFrame.pDSParms->byCurrChannel = (unsigned char)uCurrChannel;
}
// TIM field
if (pMgmt->eCurrMode == WMAC_MODE_ESS_AP) {
@@ -3329,22 +3330,22 @@ s_MgrMakeBeacon(
// Pairwise Key Cipher Suite
sFrame.pRSNWPA->wPKCount = 0;
// Auth Key Management Suite
- *((PWORD)(sFrame.pBuf + sFrame.len + sFrame.pRSNWPA->len))=0;
+ *((unsigned short *)(sFrame.pBuf + sFrame.len + sFrame.pRSNWPA->len))=0;
sFrame.pRSNWPA->len +=2;
// RSN Capabilites
- *((PWORD)(sFrame.pBuf + sFrame.len + sFrame.pRSNWPA->len))=0;
+ *((unsigned short *)(sFrame.pBuf + sFrame.len + sFrame.pRSNWPA->len))=0;
sFrame.pRSNWPA->len +=2;
sFrame.len += sFrame.pRSNWPA->len + WLAN_IEHDR_LEN;
}
}
- if ((pMgmt->b11hEnable == TRUE) &&
+ if ((pMgmt->b11hEnable == true) &&
(pMgmt->eCurrentPHYMode == PHY_TYPE_11A)) {
// Country IE
- pbyBuffer = (PBYTE)(sFrame.pBuf + sFrame.len);
- CARDvSetCountryIE(pMgmt->pAdapter, pbyBuffer);
- CARDvSetCountryInfo(pMgmt->pAdapter, PHY_TYPE_11A, pbyBuffer);
+ pbyBuffer = (unsigned char *)(sFrame.pBuf + sFrame.len);
+ set_country_IE(pMgmt->pAdapter, pbyBuffer);
+ set_country_info(pMgmt->pAdapter, PHY_TYPE_11A, pbyBuffer);
uLength += ((PWLAN_IE_COUNTRY) pbyBuffer)->len + WLAN_IEHDR_LEN;
pbyBuffer += (((PWLAN_IE_COUNTRY) pbyBuffer)->len + WLAN_IEHDR_LEN);
// Power Constrain IE
@@ -3353,12 +3354,12 @@ s_MgrMakeBeacon(
((PWLAN_IE_PW_CONST) pbyBuffer)->byPower = 0;
pbyBuffer += (1) + WLAN_IEHDR_LEN;
uLength += (1) + WLAN_IEHDR_LEN;
- if (pMgmt->bSwitchChannel == TRUE) {
+ if (pMgmt->bSwitchChannel == true) {
// Channel Switch IE
((PWLAN_IE_CH_SW) pbyBuffer)->byElementID = WLAN_EID_CH_SWITCH;
((PWLAN_IE_CH_SW) pbyBuffer)->len = 3;
((PWLAN_IE_CH_SW) pbyBuffer)->byMode = 1;
- ((PWLAN_IE_CH_SW) pbyBuffer)->byChannel = CARDbyGetChannelNumber(pMgmt->pAdapter, pMgmt->byNewChannel);
+ ((PWLAN_IE_CH_SW) pbyBuffer)->byChannel = get_channel_number(pMgmt->pAdapter, pMgmt->byNewChannel);
((PWLAN_IE_CH_SW) pbyBuffer)->byCount = 0;
pbyBuffer += (3) + WLAN_IEHDR_LEN;
uLength += (3) + WLAN_IEHDR_LEN;
@@ -3382,7 +3383,7 @@ s_MgrMakeBeacon(
pbyBuffer += (7) + WLAN_IEHDR_LEN;
uLength += (7) + WLAN_IEHDR_LEN;
for(ii=CB_MAX_CHANNEL_24G+1; ii<=CB_MAX_CHANNEL; ii++ ) {
- if (CARDbGetChannelMapInfo(pMgmt->pAdapter, ii, pbyBuffer, pbyBuffer+1) == TRUE) {
+ if (get_channel_map_info(pMgmt->pAdapter, ii, pbyBuffer, pbyBuffer+1) == true) {
pbyBuffer += 2;
uLength += 2;
pIBSSDFS->len += 2;
@@ -3398,11 +3399,11 @@ s_MgrMakeBeacon(
sFrame.pERP->byElementID = WLAN_EID_ERP;
sFrame.pERP->len = 1;
sFrame.pERP->byContext = 0;
- if (pDevice->bProtectMode == TRUE)
+ if (pDevice->bProtectMode == true)
sFrame.pERP->byContext |= WLAN_EID_ERP_USE_PROTECTION;
- if (pDevice->bNonERPPresent == TRUE)
+ if (pDevice->bNonERPPresent == true)
sFrame.pERP->byContext |= WLAN_EID_ERP_NONERP_PRESENT;
- if (pDevice->bBarkerPreambleMd == TRUE)
+ if (pDevice->bBarkerPreambleMd == true)
sFrame.pERP->byContext |= WLAN_EID_ERP_BARKER_MODE;
}
if (((PWLAN_IE_SUPP_RATES)pCurrExtSuppRates)->len != 0) {
@@ -3414,7 +3415,7 @@ s_MgrMakeBeacon(
);
}
// hostapd wpa/wpa2 IE
- if ((pMgmt->eCurrMode == WMAC_MODE_ESS_AP) && (pDevice->bEnableHostapd == TRUE)) {
+ if ((pMgmt->eCurrMode == WMAC_MODE_ESS_AP) && (pDevice->bEnableHostapd == true)) {
if (pMgmt->eAuthenMode == WMAC_AUTH_WPANONE) {
if (pMgmt->wWPAIELen != 0) {
sFrame.pRSN = (PWLAN_IE_RSN)(sFrame.pBuf + sFrame.len);
@@ -3453,31 +3454,31 @@ PSTxMgmtPacket
s_MgrMakeProbeResponse(
PSDevice pDevice,
PSMgmtObject pMgmt,
- WORD wCurrCapInfo,
- WORD wCurrBeaconPeriod,
- UINT uCurrChannel,
- WORD wCurrATIMWinodw,
- PBYTE pDstAddr,
+ unsigned short wCurrCapInfo,
+ unsigned short wCurrBeaconPeriod,
+ unsigned int uCurrChannel,
+ unsigned short wCurrATIMWinodw,
+ unsigned char *pDstAddr,
PWLAN_IE_SSID pCurrSSID,
- PBYTE pCurrBSSID,
+ unsigned char *pCurrBSSID,
PWLAN_IE_SUPP_RATES pCurrSuppRates,
PWLAN_IE_SUPP_RATES pCurrExtSuppRates,
- BYTE byPHYType
+ unsigned char byPHYType
)
{
PSTxMgmtPacket pTxPacket = NULL;
WLAN_FR_PROBERESP sFrame;
- PBYTE pbyBuffer;
- UINT uLength = 0;
+ unsigned char *pbyBuffer;
+ unsigned int uLength = 0;
PWLAN_IE_IBSS_DFS pIBSSDFS = NULL;
- UINT ii;
+ unsigned int ii;
pTxPacket = (PSTxMgmtPacket)pMgmt->pbyMgmtPacketPool;
memset(pTxPacket, 0, sizeof(STxMgmtPacket) + WLAN_PROBERESP_FR_MAXLEN);
- pTxPacket->p80211Header = (PUWLAN_80211HDR)((PBYTE)pTxPacket + sizeof(STxMgmtPacket));
+ pTxPacket->p80211Header = (PUWLAN_80211HDR)((unsigned char *)pTxPacket + sizeof(STxMgmtPacket));
// Setup the sFrame structure.
- sFrame.pBuf = (PBYTE)pTxPacket->p80211Header;
+ sFrame.pBuf = (unsigned char *)pTxPacket->p80211Header;
sFrame.len = WLAN_PROBERESP_FR_MAXLEN;
vMgrEncodeProbeResponse(&sFrame);
// Setup the header
@@ -3493,7 +3494,7 @@ s_MgrMakeProbeResponse(
*sFrame.pwCapInfo = cpu_to_le16(wCurrCapInfo);
if (byPHYType == BB_TYPE_11B) {
- *sFrame.pwCapInfo &= cpu_to_le16((WORD)~(WLAN_SET_CAP_INFO_SHORTSLOTTIME(1)));
+ *sFrame.pwCapInfo &= cpu_to_le16((unsigned short)~(WLAN_SET_CAP_INFO_SHORTSLOTTIME(1)));
}
// Copy SSID
@@ -3518,7 +3519,7 @@ s_MgrMakeProbeResponse(
sFrame.len += (1) + WLAN_IEHDR_LEN;
sFrame.pDSParms->byElementID = WLAN_EID_DS_PARMS;
sFrame.pDSParms->len = 1;
- sFrame.pDSParms->byCurrChannel = (BYTE)uCurrChannel;
+ sFrame.pDSParms->byCurrChannel = (unsigned char)uCurrChannel;
}
if (pMgmt->eCurrMode != WMAC_MODE_ESS_AP) {
@@ -3535,20 +3536,20 @@ s_MgrMakeProbeResponse(
sFrame.pERP->byElementID = WLAN_EID_ERP;
sFrame.pERP->len = 1;
sFrame.pERP->byContext = 0;
- if (pDevice->bProtectMode == TRUE)
+ if (pDevice->bProtectMode == true)
sFrame.pERP->byContext |= WLAN_EID_ERP_USE_PROTECTION;
- if (pDevice->bNonERPPresent == TRUE)
+ if (pDevice->bNonERPPresent == true)
sFrame.pERP->byContext |= WLAN_EID_ERP_NONERP_PRESENT;
- if (pDevice->bBarkerPreambleMd == TRUE)
+ if (pDevice->bBarkerPreambleMd == true)
sFrame.pERP->byContext |= WLAN_EID_ERP_BARKER_MODE;
}
- if ((pMgmt->b11hEnable == TRUE) &&
+ if ((pMgmt->b11hEnable == true) &&
(pMgmt->eCurrentPHYMode == PHY_TYPE_11A)) {
// Country IE
- pbyBuffer = (PBYTE)(sFrame.pBuf + sFrame.len);
- CARDvSetCountryIE(pMgmt->pAdapter, pbyBuffer);
- CARDvSetCountryInfo(pMgmt->pAdapter, PHY_TYPE_11A, pbyBuffer);
+ pbyBuffer = (unsigned char *)(sFrame.pBuf + sFrame.len);
+ set_country_IE(pMgmt->pAdapter, pbyBuffer);
+ set_country_info(pMgmt->pAdapter, PHY_TYPE_11A, pbyBuffer);
uLength += ((PWLAN_IE_COUNTRY) pbyBuffer)->len + WLAN_IEHDR_LEN;
pbyBuffer += (((PWLAN_IE_COUNTRY) pbyBuffer)->len + WLAN_IEHDR_LEN);
// Power Constrain IE
@@ -3557,12 +3558,12 @@ s_MgrMakeProbeResponse(
((PWLAN_IE_PW_CONST) pbyBuffer)->byPower = 0;
pbyBuffer += (1) + WLAN_IEHDR_LEN;
uLength += (1) + WLAN_IEHDR_LEN;
- if (pMgmt->bSwitchChannel == TRUE) {
+ if (pMgmt->bSwitchChannel == true) {
// Channel Switch IE
((PWLAN_IE_CH_SW) pbyBuffer)->byElementID = WLAN_EID_CH_SWITCH;
((PWLAN_IE_CH_SW) pbyBuffer)->len = 3;
((PWLAN_IE_CH_SW) pbyBuffer)->byMode = 1;
- ((PWLAN_IE_CH_SW) pbyBuffer)->byChannel = CARDbyGetChannelNumber(pMgmt->pAdapter, pMgmt->byNewChannel);
+ ((PWLAN_IE_CH_SW) pbyBuffer)->byChannel = get_channel_number(pMgmt->pAdapter, pMgmt->byNewChannel);
((PWLAN_IE_CH_SW) pbyBuffer)->byCount = 0;
pbyBuffer += (3) + WLAN_IEHDR_LEN;
uLength += (3) + WLAN_IEHDR_LEN;
@@ -3586,7 +3587,7 @@ s_MgrMakeProbeResponse(
pbyBuffer += (7) + WLAN_IEHDR_LEN;
uLength += (7) + WLAN_IEHDR_LEN;
for(ii=CB_MAX_CHANNEL_24G+1; ii<=CB_MAX_CHANNEL; ii++ ) {
- if (CARDbGetChannelMapInfo(pMgmt->pAdapter, ii, pbyBuffer, pbyBuffer+1) == TRUE) {
+ if (get_channel_map_info(pMgmt->pAdapter, ii, pbyBuffer, pbyBuffer+1) == true) {
pbyBuffer += 2;
uLength += 2;
pIBSSDFS->len += 2;
@@ -3607,7 +3608,7 @@ s_MgrMakeProbeResponse(
}
// hostapd wpa/wpa2 IE
- if ((pMgmt->eCurrMode == WMAC_MODE_ESS_AP) && (pDevice->bEnableHostapd == TRUE)) {
+ if ((pMgmt->eCurrMode == WMAC_MODE_ESS_AP) && (pDevice->bEnableHostapd == true)) {
if (pMgmt->eAuthenMode == WMAC_AUTH_WPANONE) {
if (pMgmt->wWPAIELen != 0) {
sFrame.pRSN = (PWLAN_IE_RSN)(sFrame.pBuf + sFrame.len);
@@ -3642,9 +3643,9 @@ PSTxMgmtPacket
s_MgrMakeAssocRequest(
PSDevice pDevice,
PSMgmtObject pMgmt,
- PBYTE pDAddr,
- WORD wCurrCapInfo,
- WORD wListenInterval,
+ unsigned char *pDAddr,
+ unsigned short wCurrCapInfo,
+ unsigned short wListenInterval,
PWLAN_IE_SSID pCurrSSID,
PWLAN_IE_SUPP_RATES pCurrRates,
PWLAN_IE_SUPP_RATES pCurrExtSuppRates
@@ -3652,15 +3653,15 @@ s_MgrMakeAssocRequest(
{
PSTxMgmtPacket pTxPacket = NULL;
WLAN_FR_ASSOCREQ sFrame;
- PBYTE pbyIEs;
- PBYTE pbyRSN;
+ unsigned char *pbyIEs;
+ unsigned char *pbyRSN;
pTxPacket = (PSTxMgmtPacket)pMgmt->pbyMgmtPacketPool;
memset(pTxPacket, 0, sizeof(STxMgmtPacket) + WLAN_ASSOCREQ_FR_MAXLEN);
- pTxPacket->p80211Header = (PUWLAN_80211HDR)((PBYTE)pTxPacket + sizeof(STxMgmtPacket));
+ pTxPacket->p80211Header = (PUWLAN_80211HDR)((unsigned char *)pTxPacket + sizeof(STxMgmtPacket));
// Setup the sFrame structure.
- sFrame.pBuf = (PBYTE)pTxPacket->p80211Header;
+ sFrame.pBuf = (unsigned char *)pTxPacket->p80211Header;
sFrame.len = WLAN_ASSOCREQ_FR_MAXLEN;
// format fixed field frame structure
vMgrEncodeAssocRequest(&sFrame);
@@ -3709,7 +3710,7 @@ s_MgrMakeAssocRequest(
pbyIEs += pCurrRates->len + WLAN_IEHDR_LEN;
// for 802.11h
- if (pMgmt->b11hEnable == TRUE) {
+ if (pMgmt->b11hEnable == true) {
if (sFrame.pCurrPowerCap == NULL) {
sFrame.pCurrPowerCap = (PWLAN_IE_PW_CAP)(sFrame.pBuf + sFrame.len);
sFrame.len += (2 + WLAN_IEHDR_LEN);
@@ -3722,7 +3723,7 @@ s_MgrMakeAssocRequest(
}
if (sFrame.pCurrSuppCh == NULL) {
sFrame.pCurrSuppCh = (PWLAN_IE_SUPP_CH)(sFrame.pBuf + sFrame.len);
- sFrame.len += CARDbySetSupportChannels(pMgmt->pAdapter,(PBYTE)sFrame.pCurrSuppCh);
+ sFrame.len += set_support_channels(pMgmt->pAdapter,(unsigned char *)sFrame.pCurrSuppCh);
}
}
@@ -3765,7 +3766,7 @@ s_MgrMakeAssocRequest(
sFrame.pRSNWPA->PKSList[0].abyOUI[3] = WPA_NONE;
}
// Auth Key Management Suite
- pbyRSN = (PBYTE)(sFrame.pBuf + sFrame.len + 2 + sFrame.pRSNWPA->len);
+ pbyRSN = (unsigned char *)(sFrame.pBuf + sFrame.len + 2 + sFrame.pRSNWPA->len);
*pbyRSN++=0x01;
*pbyRSN++=0x00;
*pbyRSN++=0x00;
@@ -3799,8 +3800,8 @@ s_MgrMakeAssocRequest(
} else if (((pMgmt->eAuthenMode == WMAC_AUTH_WPA2) ||
(pMgmt->eAuthenMode == WMAC_AUTH_WPA2PSK)) &&
(pMgmt->pCurrBSS != NULL)) {
- UINT ii;
- PWORD pwPMKID;
+ unsigned int ii;
+ unsigned short *pwPMKID;
// WPA IE
sFrame.pRSN = (PWLAN_IE_RSN)(sFrame.pBuf + sFrame.len);
@@ -3854,7 +3855,7 @@ s_MgrMakeAssocRequest(
sFrame.pRSN->len +=6;
// RSN Capabilites
- if (pMgmt->pCurrBSS->sRSNCapObj.bRSNCapExist == TRUE) {
+ if (pMgmt->pCurrBSS->sRSNCapObj.bRSNCapExist == true) {
memcpy(&sFrame.pRSN->abyRSN[16], &pMgmt->pCurrBSS->sRSNCapObj.wRSNCap, 2);
} else {
sFrame.pRSN->abyRSN[16] = 0;
@@ -3862,10 +3863,10 @@ s_MgrMakeAssocRequest(
}
sFrame.pRSN->len +=2;
- if ((pDevice->gsPMKID.BSSIDInfoCount > 0) && (pDevice->bRoaming == TRUE) && (pMgmt->eAuthenMode == WMAC_AUTH_WPA2)) {
+ if ((pDevice->gsPMKID.BSSIDInfoCount > 0) && (pDevice->bRoaming == true) && (pMgmt->eAuthenMode == WMAC_AUTH_WPA2)) {
// RSN PMKID
pbyRSN = &sFrame.pRSN->abyRSN[18];
- pwPMKID = (PWORD)pbyRSN; // Point to PMKID count
+ pwPMKID = (unsigned short *)pbyRSN; // Point to PMKID count
*pwPMKID = 0; // Initialize PMKID count
pbyRSN += 2; // Point to PMKID list
for (ii = 0; ii < pDevice->gsPMKID.BSSIDInfoCount; ii++) {
@@ -3917,9 +3918,9 @@ PSTxMgmtPacket
s_MgrMakeReAssocRequest(
PSDevice pDevice,
PSMgmtObject pMgmt,
- PBYTE pDAddr,
- WORD wCurrCapInfo,
- WORD wListenInterval,
+ unsigned char *pDAddr,
+ unsigned short wCurrCapInfo,
+ unsigned short wListenInterval,
PWLAN_IE_SSID pCurrSSID,
PWLAN_IE_SUPP_RATES pCurrRates,
PWLAN_IE_SUPP_RATES pCurrExtSuppRates
@@ -3927,15 +3928,15 @@ s_MgrMakeReAssocRequest(
{
PSTxMgmtPacket pTxPacket = NULL;
WLAN_FR_REASSOCREQ sFrame;
- PBYTE pbyIEs;
- PBYTE pbyRSN;
+ unsigned char *pbyIEs;
+ unsigned char *pbyRSN;
pTxPacket = (PSTxMgmtPacket)pMgmt->pbyMgmtPacketPool;
memset( pTxPacket, 0, sizeof(STxMgmtPacket) + WLAN_REASSOCREQ_FR_MAXLEN);
- pTxPacket->p80211Header = (PUWLAN_80211HDR)((PBYTE)pTxPacket + sizeof(STxMgmtPacket));
+ pTxPacket->p80211Header = (PUWLAN_80211HDR)((unsigned char *)pTxPacket + sizeof(STxMgmtPacket));
/* Setup the sFrame structure. */
- sFrame.pBuf = (PBYTE)pTxPacket->p80211Header;
+ sFrame.pBuf = (unsigned char *)pTxPacket->p80211Header;
sFrame.len = WLAN_REASSOCREQ_FR_MAXLEN;
// format fixed field frame structure
@@ -4024,7 +4025,7 @@ s_MgrMakeReAssocRequest(
sFrame.pRSNWPA->PKSList[0].abyOUI[3] = WPA_NONE;
}
// Auth Key Management Suite
- pbyRSN = (PBYTE)(sFrame.pBuf + sFrame.len + 2 + sFrame.pRSNWPA->len);
+ pbyRSN = (unsigned char *)(sFrame.pBuf + sFrame.len + 2 + sFrame.pRSNWPA->len);
*pbyRSN++=0x01;
*pbyRSN++=0x00;
*pbyRSN++=0x00;
@@ -4055,8 +4056,8 @@ s_MgrMakeReAssocRequest(
} else if (((pMgmt->eAuthenMode == WMAC_AUTH_WPA2) ||
(pMgmt->eAuthenMode == WMAC_AUTH_WPA2PSK)) &&
(pMgmt->pCurrBSS != NULL)) {
- UINT ii;
- PWORD pwPMKID;
+ unsigned int ii;
+ unsigned short *pwPMKID;
/* WPA IE */
sFrame.pRSN = (PWLAN_IE_RSN)(sFrame.pBuf + sFrame.len);
@@ -4110,7 +4111,7 @@ s_MgrMakeReAssocRequest(
sFrame.pRSN->len +=6;
// RSN Capabilites
- if (pMgmt->pCurrBSS->sRSNCapObj.bRSNCapExist == TRUE) {
+ if (pMgmt->pCurrBSS->sRSNCapObj.bRSNCapExist == true) {
memcpy(&sFrame.pRSN->abyRSN[16], &pMgmt->pCurrBSS->sRSNCapObj.wRSNCap, 2);
} else {
sFrame.pRSN->abyRSN[16] = 0;
@@ -4118,10 +4119,10 @@ s_MgrMakeReAssocRequest(
}
sFrame.pRSN->len +=2;
- if ((pDevice->gsPMKID.BSSIDInfoCount > 0) && (pDevice->bRoaming == TRUE) && (pMgmt->eAuthenMode == WMAC_AUTH_WPA2)) {
+ if ((pDevice->gsPMKID.BSSIDInfoCount > 0) && (pDevice->bRoaming == true) && (pMgmt->eAuthenMode == WMAC_AUTH_WPA2)) {
// RSN PMKID
pbyRSN = &sFrame.pRSN->abyRSN[18];
- pwPMKID = (PWORD)pbyRSN; // Point to PMKID count
+ pwPMKID = (unsigned short *)pbyRSN; // Point to PMKID count
*pwPMKID = 0; // Initialize PMKID count
pbyRSN += 2; // Point to PMKID list
for (ii = 0; ii < pDevice->gsPMKID.BSSIDInfoCount; ii++) {
@@ -4169,10 +4170,10 @@ PSTxMgmtPacket
s_MgrMakeAssocResponse(
PSDevice pDevice,
PSMgmtObject pMgmt,
- WORD wCurrCapInfo,
- WORD wAssocStatus,
- WORD wAssocAID,
- PBYTE pDstAddr,
+ unsigned short wCurrCapInfo,
+ unsigned short wAssocStatus,
+ unsigned short wAssocAID,
+ unsigned char *pDstAddr,
PWLAN_IE_SUPP_RATES pCurrSuppRates,
PWLAN_IE_SUPP_RATES pCurrExtSuppRates
)
@@ -4183,9 +4184,9 @@ s_MgrMakeAssocResponse(
pTxPacket = (PSTxMgmtPacket)pMgmt->pbyMgmtPacketPool;
memset(pTxPacket, 0, sizeof(STxMgmtPacket) + WLAN_ASSOCREQ_FR_MAXLEN);
- pTxPacket->p80211Header = (PUWLAN_80211HDR)((PBYTE)pTxPacket + sizeof(STxMgmtPacket));
+ pTxPacket->p80211Header = (PUWLAN_80211HDR)((unsigned char *)pTxPacket + sizeof(STxMgmtPacket));
// Setup the sFrame structure
- sFrame.pBuf = (PBYTE)pTxPacket->p80211Header;
+ sFrame.pBuf = (unsigned char *)pTxPacket->p80211Header;
sFrame.len = WLAN_REASSOCRESP_FR_MAXLEN;
vMgrEncodeAssocResponse(&sFrame);
// Setup the header
@@ -4200,7 +4201,7 @@ s_MgrMakeAssocResponse(
*sFrame.pwCapInfo = cpu_to_le16(wCurrCapInfo);
*sFrame.pwStatus = cpu_to_le16(wAssocStatus);
- *sFrame.pwAid = cpu_to_le16((WORD)(wAssocAID | BIT14 | BIT15));
+ *sFrame.pwAid = cpu_to_le16((unsigned short)(wAssocAID | BIT14 | BIT15));
// Copy the rate set
sFrame.pSuppRates = (PWLAN_IE_SUPP_RATES)(sFrame.pBuf + sFrame.len);
@@ -4243,10 +4244,10 @@ PSTxMgmtPacket
s_MgrMakeReAssocResponse(
PSDevice pDevice,
PSMgmtObject pMgmt,
- WORD wCurrCapInfo,
- WORD wAssocStatus,
- WORD wAssocAID,
- PBYTE pDstAddr,
+ unsigned short wCurrCapInfo,
+ unsigned short wAssocStatus,
+ unsigned short wAssocAID,
+ unsigned char *pDstAddr,
PWLAN_IE_SUPP_RATES pCurrSuppRates,
PWLAN_IE_SUPP_RATES pCurrExtSuppRates
)
@@ -4257,9 +4258,9 @@ s_MgrMakeReAssocResponse(
pTxPacket = (PSTxMgmtPacket)pMgmt->pbyMgmtPacketPool;
memset(pTxPacket, 0, sizeof(STxMgmtPacket) + WLAN_ASSOCREQ_FR_MAXLEN);
- pTxPacket->p80211Header = (PUWLAN_80211HDR)((PBYTE)pTxPacket + sizeof(STxMgmtPacket));
+ pTxPacket->p80211Header = (PUWLAN_80211HDR)((unsigned char *)pTxPacket + sizeof(STxMgmtPacket));
// Setup the sFrame structure
- sFrame.pBuf = (PBYTE)pTxPacket->p80211Header;
+ sFrame.pBuf = (unsigned char *)pTxPacket->p80211Header;
sFrame.len = WLAN_REASSOCRESP_FR_MAXLEN;
vMgrEncodeReassocResponse(&sFrame);
// Setup the header
@@ -4274,7 +4275,7 @@ s_MgrMakeReAssocResponse(
*sFrame.pwCapInfo = cpu_to_le16(wCurrCapInfo);
*sFrame.pwStatus = cpu_to_le16(wAssocStatus);
- *sFrame.pwAid = cpu_to_le16((WORD)(wAssocAID | BIT14 | BIT15));
+ *sFrame.pwAid = cpu_to_le16((unsigned short)(wAssocAID | BIT14 | BIT15));
// Copy the rate set
sFrame.pSuppRates = (PWLAN_IE_SUPP_RATES)(sFrame.pBuf + sFrame.len);
@@ -4322,16 +4323,16 @@ s_vMgrRxProbeResponse(
{
PKnownBSS pBSSList = NULL;
WLAN_FR_PROBERESP sFrame;
- BYTE byCurrChannel = pRxPacket->byRxChannel;
+ unsigned char byCurrChannel = pRxPacket->byRxChannel;
ERPObject sERP;
- BYTE byIEChannel = 0;
- BOOL bChannelHit = TRUE;
+ unsigned char byIEChannel = 0;
+ bool bChannelHit = true;
memset(&sFrame, 0, sizeof(WLAN_FR_PROBERESP));
// decode the frame
sFrame.len = pRxPacket->cbMPDULen;
- sFrame.pBuf = (PBYTE)pRxPacket->p80211Header;
+ sFrame.pBuf = (unsigned char *)pRxPacket->p80211Header;
vMgrDecodeProbeResponse(&sFrame);
if ((sFrame.pqwTimestamp == 0) ||
@@ -4350,29 +4351,29 @@ s_vMgrRxProbeResponse(
if (sFrame.pDSParms != 0) {
if (byCurrChannel > CB_MAX_CHANNEL_24G) {
// channel remapping to
- byIEChannel = CARDbyGetChannelMapping(pMgmt->pAdapter, sFrame.pDSParms->byCurrChannel, PHY_TYPE_11A);
+ byIEChannel = get_channel_mapping(pMgmt->pAdapter, sFrame.pDSParms->byCurrChannel, PHY_TYPE_11A);
} else {
byIEChannel = sFrame.pDSParms->byCurrChannel;
}
if (byCurrChannel != byIEChannel) {
// adjust channel info. bcs we rcv adjcent channel pakckets
- bChannelHit = FALSE;
+ bChannelHit = false;
byCurrChannel = byIEChannel;
}
} else {
// no DS channel info
- bChannelHit = TRUE;
+ bChannelHit = true;
}
//2008-0730-01<Add>by MikeLiu
-if(ChannelExceedZoneType(pDevice,byCurrChannel)==TRUE)
+if(ChannelExceedZoneType(pDevice,byCurrChannel)==true)
return;
if (sFrame.pERP != NULL) {
sERP.byERP = sFrame.pERP->byContext;
- sERP.bERPExist = TRUE;
+ sERP.bERPExist = true;
} else {
- sERP.bERPExist = FALSE;
+ sERP.bERPExist = false;
sERP.byERP = 0;
}
@@ -4448,7 +4449,7 @@ s_vMgrRxProbeRequest(
WLAN_FR_PROBEREQ sFrame;
CMD_STATUS Status;
PSTxMgmtPacket pTxPacket;
- BYTE byPHYType = BB_TYPE_11B;
+ unsigned char byPHYType = BB_TYPE_11B;
// STA in Ad-hoc mode: when latest TBTT beacon transmit success,
// STA have to response this request.
@@ -4458,7 +4459,7 @@ s_vMgrRxProbeRequest(
memset(&sFrame, 0, sizeof(WLAN_FR_PROBEREQ));
// decode the frame
sFrame.len = pRxPacket->cbMPDULen;
- sFrame.pBuf = (PBYTE)pRxPacket->p80211Header;
+ sFrame.pBuf = (unsigned char *)pRxPacket->p80211Header;
vMgrDecodeProbeRequest(&sFrame);
/*
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Probe request rx:MAC addr:%02x-%02x-%02x=%02x-%02x-%02x \n",
@@ -4495,7 +4496,7 @@ s_vMgrRxProbeRequest(
0,
sFrame.pHdr->sA3.abyAddr2,
(PWLAN_IE_SSID)pMgmt->abyCurrSSID,
- (PBYTE)pMgmt->abyCurrBSSID,
+ (unsigned char *)pMgmt->abyCurrBSSID,
(PWLAN_IE_SUPP_RATES)pMgmt->abyCurrSuppRates,
(PWLAN_IE_SUPP_RATES)pMgmt->abyCurrExtSuppRates,
byPHYType
@@ -4542,8 +4543,8 @@ vMgrRxManagePacket(
)
{
PSDevice pDevice = (PSDevice)hDeviceContext;
- BOOL bInScan = FALSE;
- UINT uNodeIndex = 0;
+ bool bInScan = false;
+ unsigned int uNodeIndex = 0;
NODE_STATE eNodeState = 0;
CMD_STATUS Status;
@@ -4577,7 +4578,7 @@ vMgrRxManagePacket(
case WLAN_FSTYPE_ASSOCRESP:
// Frame Clase = 2
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "rx assocresp1\n");
- s_vMgrRxAssocResponse(pDevice, pMgmt, pRxPacket, FALSE);
+ s_vMgrRxAssocResponse(pDevice, pMgmt, pRxPacket, false);
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "rx assocresp2\n");
break;
@@ -4603,7 +4604,7 @@ vMgrRxManagePacket(
case WLAN_FSTYPE_REASSOCRESP:
// Frame Clase = 2
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "rx reassocresp\n");
- s_vMgrRxAssocResponse(pDevice, pMgmt, pRxPacket, TRUE);
+ s_vMgrRxAssocResponse(pDevice, pMgmt, pRxPacket, true);
break;
case WLAN_FSTYPE_PROBEREQ:
@@ -4623,7 +4624,7 @@ vMgrRxManagePacket(
// Frame Clase = 0
//DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "rx beacon\n");
if (pMgmt->eScanState != WMAC_NO_SCANNING) {
- bInScan = TRUE;
+ bInScan = true;
};
s_vMgrRxBeacon(pDevice, pMgmt, pRxPacket, bInScan);
break;
@@ -4680,10 +4681,10 @@ vMgrRxManagePacket(
* Prepare beacon to send
*
* Return Value:
- * TRUE if success; FALSE if failed.
+ * true if success; false if failed.
*
-*/
-BOOL
+bool
bMgrPrepareBeaconToSend(
void *hDeviceContext,
PSMgmtObject pMgmt
@@ -4692,7 +4693,7 @@ bMgrPrepareBeaconToSend(
PSDevice pDevice = (PSDevice)hDeviceContext;
PSTxMgmtPacket pTxPacket;
-// pDevice->bBeaconBufReady = FALSE;
+// pDevice->bBeaconBufReady = false;
if (pDevice->bEncryptionEnable || pDevice->bEnable8021x){
pMgmt->wCurrCapInfo |= WLAN_SET_CAP_INFO_PRIVACY(1);
}
@@ -4708,18 +4709,18 @@ bMgrPrepareBeaconToSend(
pMgmt->uCurrChannel,
pMgmt->wCurrATIMWindow, //0,
(PWLAN_IE_SSID)pMgmt->abyCurrSSID,
- (PBYTE)pMgmt->abyCurrBSSID,
+ (unsigned char *)pMgmt->abyCurrBSSID,
(PWLAN_IE_SUPP_RATES)pMgmt->abyCurrSuppRates,
(PWLAN_IE_SUPP_RATES)pMgmt->abyCurrExtSuppRates
);
if ((pMgmt->eCurrMode == WMAC_MODE_IBSS_STA) &&
(pMgmt->abyCurrBSSID[0] == 0))
- return FALSE;
+ return false;
csBeacon_xmit(pDevice, pTxPacket);
- return TRUE;
+ return true;
}
@@ -4741,7 +4742,7 @@ static
void
s_vMgrLogStatus(
PSMgmtObject pMgmt,
- WORD wStatus
+ unsigned short wStatus
)
{
switch( wStatus ){
@@ -4807,24 +4808,24 @@ s_vMgrLogStatus(
* Return Value: none.
*
-*/
-BOOL
+bool
bAdd_PMKID_Candidate (
void *hDeviceContext,
- PBYTE pbyBSSID,
+ unsigned char *pbyBSSID,
PSRSNCapObject psRSNCapObj
)
{
PSDevice pDevice = (PSDevice)hDeviceContext;
PPMKID_CANDIDATE pCandidateList;
- UINT ii = 0;
+ unsigned int ii = 0;
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"bAdd_PMKID_Candidate START: (%d)\n", (int)pDevice->gsPMKIDCandidate.NumCandidates);
if ((pDevice == NULL) || (pbyBSSID == NULL) || (psRSNCapObj == NULL))
- return FALSE;
+ return false;
if (pDevice->gsPMKIDCandidate.NumCandidates >= MAX_PMKIDLIST)
- return FALSE;
+ return false;
@@ -4832,18 +4833,18 @@ bAdd_PMKID_Candidate (
for (ii = 0; ii < pDevice->gsPMKIDCandidate.NumCandidates; ii++) {
pCandidateList = &pDevice->gsPMKIDCandidate.CandidateList[ii];
if ( !memcmp(pCandidateList->BSSID, pbyBSSID, ETH_ALEN)) {
- if ((psRSNCapObj->bRSNCapExist == TRUE) && (psRSNCapObj->wRSNCap & BIT0)) {
+ if ((psRSNCapObj->bRSNCapExist == true) && (psRSNCapObj->wRSNCap & BIT0)) {
pCandidateList->Flags |= NDIS_802_11_PMKID_CANDIDATE_PREAUTH_ENABLED;
} else {
pCandidateList->Flags &= ~(NDIS_802_11_PMKID_CANDIDATE_PREAUTH_ENABLED);
}
- return TRUE;
+ return true;
}
}
// New Candidate
pCandidateList = &pDevice->gsPMKIDCandidate.CandidateList[pDevice->gsPMKIDCandidate.NumCandidates];
- if ((psRSNCapObj->bRSNCapExist == TRUE) && (psRSNCapObj->wRSNCap & BIT0)) {
+ if ((psRSNCapObj->bRSNCapExist == true) && (psRSNCapObj->wRSNCap & BIT0)) {
pCandidateList->Flags |= NDIS_802_11_PMKID_CANDIDATE_PREAUTH_ENABLED;
} else {
pCandidateList->Flags &= ~(NDIS_802_11_PMKID_CANDIDATE_PREAUTH_ENABLED);
@@ -4851,7 +4852,7 @@ bAdd_PMKID_Candidate (
memcpy(pCandidateList->BSSID, pbyBSSID, ETH_ALEN);
pDevice->gsPMKIDCandidate.NumCandidates++;
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"NumCandidates:%d\n", (int)pDevice->gsPMKIDCandidate.NumCandidates);
- return TRUE;
+ return true;
}
/*
@@ -4881,20 +4882,20 @@ vFlush_PMKID_Candidate (
memset(&pDevice->gsPMKIDCandidate, 0, sizeof(SPMKIDCandidateEvent));
}
-static BOOL
+static bool
s_bCipherMatch (
PKnownBSS pBSSNode,
NDIS_802_11_ENCRYPTION_STATUS EncStatus,
- PBYTE pbyCCSPK,
- PBYTE pbyCCSGK
+ unsigned char *pbyCCSPK,
+ unsigned char *pbyCCSGK
)
{
- BYTE byMulticastCipher = KEY_CTL_INVALID;
- BYTE byCipherMask = 0x00;
+ unsigned char byMulticastCipher = KEY_CTL_INVALID;
+ unsigned char byCipherMask = 0x00;
int i;
if (pBSSNode == NULL)
- return FALSE;
+ return false;
// check cap. of BSS
if ((WLAN_GET_CAP_INFO_PRIVACY(pBSSNode->wCapInfo) != 0) &&
@@ -4904,7 +4905,7 @@ s_bCipherMatch (
}
if ((WLAN_GET_CAP_INFO_PRIVACY(pBSSNode->wCapInfo) != 0) &&
- (pBSSNode->bWPA2Valid == TRUE) &&
+ (pBSSNode->bWPA2Valid == true) &&
//20080123-01,<Add> by Einsn Liu
((EncStatus == Ndis802_11Encryption3Enabled)||(EncStatus == Ndis802_11Encryption2Enabled))) {
//WPA2
@@ -4938,7 +4939,7 @@ s_bCipherMatch (
}
} else if ((WLAN_GET_CAP_INFO_PRIVACY(pBSSNode->wCapInfo) != 0) &&
- (pBSSNode->bWPAValid == TRUE) &&
+ (pBSSNode->bWPAValid == true) &&
((EncStatus == Ndis802_11Encryption3Enabled) || (EncStatus == Ndis802_11Encryption2Enabled))) {
//WPA
// check Group Key Cipher
@@ -4978,9 +4979,9 @@ s_bCipherMatch (
(byCipherMask == 0)) {
*pbyCCSGK = KEY_CTL_WEP;
*pbyCCSPK = KEY_CTL_NONE;
- return TRUE;
+ return true;
} else {
- return FALSE;
+ return false;
}
} else if (EncStatus == Ndis802_11Encryption2Enabled) {
@@ -4988,45 +4989,45 @@ s_bCipherMatch (
(byCipherMask == 0)) {
*pbyCCSGK = KEY_CTL_TKIP;
*pbyCCSPK = KEY_CTL_NONE;
- return TRUE;
+ return true;
} else if ((byMulticastCipher == KEY_CTL_WEP) &&
((byCipherMask & 0x02) != 0)) {
*pbyCCSGK = KEY_CTL_WEP;
*pbyCCSPK = KEY_CTL_TKIP;
- return TRUE;
+ return true;
} else if ((byMulticastCipher == KEY_CTL_TKIP) &&
((byCipherMask & 0x02) != 0)) {
*pbyCCSGK = KEY_CTL_TKIP;
*pbyCCSPK = KEY_CTL_TKIP;
- return TRUE;
+ return true;
} else {
- return FALSE;
+ return false;
}
} else if (EncStatus == Ndis802_11Encryption3Enabled) {
if ((byMulticastCipher == KEY_CTL_CCMP) &&
(byCipherMask == 0)) {
// When CCMP is enable, "Use group cipher suite" shall not be a valid option.
- return FALSE;
+ return false;
} else if ((byMulticastCipher == KEY_CTL_WEP) &&
((byCipherMask & 0x04) != 0)) {
*pbyCCSGK = KEY_CTL_WEP;
*pbyCCSPK = KEY_CTL_CCMP;
- return TRUE;
+ return true;
} else if ((byMulticastCipher == KEY_CTL_TKIP) &&
((byCipherMask & 0x04) != 0)) {
*pbyCCSGK = KEY_CTL_TKIP;
*pbyCCSPK = KEY_CTL_CCMP;
- return TRUE;
+ return true;
} else if ((byMulticastCipher == KEY_CTL_CCMP) &&
((byCipherMask & 0x04) != 0)) {
*pbyCCSGK = KEY_CTL_CCMP;
*pbyCCSPK = KEY_CTL_CCMP;
- return TRUE;
+ return true;
} else {
- return FALSE;
+ return false;
}
}
- return TRUE;
+ return true;
}
diff --git a/drivers/staging/vt6655/wmgr.h b/drivers/staging/vt6655/wmgr.h
index 9ae7e0d55bc..141e80b843a 100644
--- a/drivers/staging/vt6655/wmgr.h
+++ b/drivers/staging/vt6655/wmgr.h
@@ -83,47 +83,47 @@
/*--------------------- Export Types ------------------------------*/
#define timer_expire(timer,next_tick) mod_timer(&timer, RUN_AT(next_tick))
-typedef void (*TimerFunction)(ULONG);
+typedef void (*TimerFunction)(unsigned long);
//+++ NDIS related
-typedef UCHAR NDIS_802_11_MAC_ADDRESS[6];
+typedef unsigned char NDIS_802_11_MAC_ADDRESS[6];
typedef struct _NDIS_802_11_AI_REQFI
{
- USHORT Capabilities;
- USHORT ListenInterval;
+ unsigned short Capabilities;
+ unsigned short ListenInterval;
NDIS_802_11_MAC_ADDRESS CurrentAPAddress;
} NDIS_802_11_AI_REQFI, *PNDIS_802_11_AI_REQFI;
typedef struct _NDIS_802_11_AI_RESFI
{
- USHORT Capabilities;
- USHORT StatusCode;
- USHORT AssociationId;
+ unsigned short Capabilities;
+ unsigned short StatusCode;
+ unsigned short AssociationId;
} NDIS_802_11_AI_RESFI, *PNDIS_802_11_AI_RESFI;
typedef struct _NDIS_802_11_ASSOCIATION_INFORMATION
{
- ULONG Length;
- USHORT AvailableRequestFixedIEs;
+ unsigned long Length;
+ unsigned short AvailableRequestFixedIEs;
NDIS_802_11_AI_REQFI RequestFixedIEs;
- ULONG RequestIELength;
- ULONG OffsetRequestIEs;
- USHORT AvailableResponseFixedIEs;
+ unsigned long RequestIELength;
+ unsigned long OffsetRequestIEs;
+ unsigned short AvailableResponseFixedIEs;
NDIS_802_11_AI_RESFI ResponseFixedIEs;
- ULONG ResponseIELength;
- ULONG OffsetResponseIEs;
+ unsigned long ResponseIELength;
+ unsigned long OffsetResponseIEs;
} NDIS_802_11_ASSOCIATION_INFORMATION, *PNDIS_802_11_ASSOCIATION_INFORMATION;
typedef struct tagSAssocInfo {
NDIS_802_11_ASSOCIATION_INFORMATION AssocInfo;
- BYTE abyIEs[WLAN_BEACON_FR_MAXLEN+WLAN_BEACON_FR_MAXLEN];
+ unsigned char abyIEs[WLAN_BEACON_FR_MAXLEN+WLAN_BEACON_FR_MAXLEN];
// store ReqIEs set by OID_802_11_ASSOCIATION_INFORMATION
- ULONG RequestIELength;
- BYTE abyReqIEs[WLAN_BEACON_FR_MAXLEN];
+ unsigned long RequestIELength;
+ unsigned char abyReqIEs[WLAN_BEACON_FR_MAXLEN];
} SAssocInfo, *PSAssocInfo;
//---
@@ -224,8 +224,8 @@ typedef enum tagWMAC_POWER_MODE {
typedef struct tagSTxMgmtPacket {
PUWLAN_80211HDR p80211Header;
- UINT cbMPDULen;
- UINT cbPayloadLen;
+ unsigned int cbMPDULen;
+ unsigned int cbPayloadLen;
} STxMgmtPacket, *PSTxMgmtPacket;
@@ -235,12 +235,12 @@ typedef struct tagSRxMgmtPacket {
PUWLAN_80211HDR p80211Header;
QWORD qwLocalTSF;
- UINT cbMPDULen;
- UINT cbPayloadLen;
- UINT uRSSI;
- BYTE bySQ;
- BYTE byRxRate;
- BYTE byRxChannel;
+ unsigned int cbMPDULen;
+ unsigned int cbPayloadLen;
+ unsigned int uRSSI;
+ unsigned char bySQ;
+ unsigned char byRxRate;
+ unsigned char byRxChannel;
} SRxMgmtPacket, *PSRxMgmtPacket;
@@ -251,7 +251,7 @@ typedef struct tagSMgmtObject
void * pAdapter;
// MAC address
- BYTE abyMACAddr[WLAN_ADDR_LEN];
+ unsigned char abyMACAddr[WLAN_ADDR_LEN];
// Configuration Mode
WMAC_CONFIG_MODE eConfigMode; // MAC pre-configed mode
@@ -264,86 +264,86 @@ typedef struct tagSMgmtObject
WMAC_BSS_STATE eCurrState; // MAC current BSS state
PKnownBSS pCurrBSS;
- BYTE byCSSGK;
- BYTE byCSSPK;
+ unsigned char byCSSGK;
+ unsigned char byCSSPK;
-// BYTE abyNewSuppRates[WLAN_IEHDR_LEN + WLAN_RATES_MAXLEN];
-// BYTE abyNewExtSuppRates[WLAN_IEHDR_LEN + WLAN_RATES_MAXLEN];
+// unsigned char abyNewSuppRates[WLAN_IEHDR_LEN + WLAN_RATES_MAXLEN];
+// unsigned char abyNewExtSuppRates[WLAN_IEHDR_LEN + WLAN_RATES_MAXLEN];
// Current state vars
- UINT uCurrChannel;
- BYTE abyCurrSuppRates[WLAN_IEHDR_LEN + WLAN_RATES_MAXLEN + 1];
- BYTE abyCurrExtSuppRates[WLAN_IEHDR_LEN + WLAN_RATES_MAXLEN + 1];
- BYTE abyCurrSSID[WLAN_IEHDR_LEN + WLAN_SSID_MAXLEN + 1];
- BYTE abyCurrBSSID[WLAN_BSSID_LEN];
- WORD wCurrCapInfo;
- WORD wCurrAID;
- WORD wCurrATIMWindow;
- WORD wCurrBeaconPeriod;
- BOOL bIsDS;
- BYTE byERPContext;
+ unsigned int uCurrChannel;
+ unsigned char abyCurrSuppRates[WLAN_IEHDR_LEN + WLAN_RATES_MAXLEN + 1];
+ unsigned char abyCurrExtSuppRates[WLAN_IEHDR_LEN + WLAN_RATES_MAXLEN + 1];
+ unsigned char abyCurrSSID[WLAN_IEHDR_LEN + WLAN_SSID_MAXLEN + 1];
+ unsigned char abyCurrBSSID[WLAN_BSSID_LEN];
+ unsigned short wCurrCapInfo;
+ unsigned short wCurrAID;
+ unsigned short wCurrATIMWindow;
+ unsigned short wCurrBeaconPeriod;
+ bool bIsDS;
+ unsigned char byERPContext;
CMD_STATE eCommandState;
- UINT uScanChannel;
+ unsigned int uScanChannel;
// Desire joinning BSS vars
- BYTE abyDesireSSID[WLAN_IEHDR_LEN + WLAN_SSID_MAXLEN + 1];
- BYTE abyDesireBSSID[WLAN_BSSID_LEN];
+ unsigned char abyDesireSSID[WLAN_IEHDR_LEN + WLAN_SSID_MAXLEN + 1];
+ unsigned char abyDesireBSSID[WLAN_BSSID_LEN];
// Adhoc or AP configuration vars
- //BYTE abyAdHocSSID[WLAN_IEHDR_LEN + WLAN_SSID_MAXLEN + 1];
- WORD wIBSSBeaconPeriod;
- WORD wIBSSATIMWindow;
- UINT uIBSSChannel;
- BYTE abyIBSSSuppRates[WLAN_IEHDR_LEN + WLAN_RATES_MAXLEN + 1];
- BYTE byAPBBType;
- BYTE abyWPAIE[MAX_WPA_IE_LEN];
- WORD wWPAIELen;
-
- UINT uAssocCount;
- BOOL bMoreData;
+ //unsigned char abyAdHocSSID[WLAN_IEHDR_LEN + WLAN_SSID_MAXLEN + 1];
+ unsigned short wIBSSBeaconPeriod;
+ unsigned short wIBSSATIMWindow;
+ unsigned int uIBSSChannel;
+ unsigned char abyIBSSSuppRates[WLAN_IEHDR_LEN + WLAN_RATES_MAXLEN + 1];
+ unsigned char byAPBBType;
+ unsigned char abyWPAIE[MAX_WPA_IE_LEN];
+ unsigned short wWPAIELen;
+
+ unsigned int uAssocCount;
+ bool bMoreData;
// Scan state vars
WMAC_SCAN_STATE eScanState;
WMAC_SCAN_TYPE eScanType;
- UINT uScanStartCh;
- UINT uScanEndCh;
- WORD wScanSteps;
- UINT uScanBSSType;
+ unsigned int uScanStartCh;
+ unsigned int uScanEndCh;
+ unsigned short wScanSteps;
+ unsigned int uScanBSSType;
// Desire scannig vars
- BYTE abyScanSSID[WLAN_IEHDR_LEN + WLAN_SSID_MAXLEN + 1];
- BYTE abyScanBSSID[WLAN_BSSID_LEN];
+ unsigned char abyScanSSID[WLAN_IEHDR_LEN + WLAN_SSID_MAXLEN + 1];
+ unsigned char abyScanBSSID[WLAN_BSSID_LEN];
// Privacy
WMAC_AUTHENTICATION_MODE eAuthenMode;
WMAC_ENCRYPTION_MODE eEncryptionMode;
- BOOL bShareKeyAlgorithm;
- BYTE abyChallenge[WLAN_CHALLENGE_LEN];
- BOOL bPrivacyInvoked;
+ bool bShareKeyAlgorithm;
+ unsigned char abyChallenge[WLAN_CHALLENGE_LEN];
+ bool bPrivacyInvoked;
// Received beacon state vars
- BOOL bInTIM;
- BOOL bMulticastTIM;
- BYTE byDTIMCount;
- BYTE byDTIMPeriod;
+ bool bInTIM;
+ bool bMulticastTIM;
+ unsigned char byDTIMCount;
+ unsigned char byDTIMPeriod;
// Power saving state vars
WMAC_POWER_MODE ePSMode;
- WORD wListenInterval;
- WORD wCountToWakeUp;
- BOOL bInTIMWake;
- PBYTE pbyPSPacketPool;
- BYTE byPSPacketPool[sizeof(STxMgmtPacket) + WLAN_NULLDATA_FR_MAXLEN];
- BOOL bRxBeaconInTBTTWake;
- BYTE abyPSTxMap[MAX_NODE_NUM + 1];
+ unsigned short wListenInterval;
+ unsigned short wCountToWakeUp;
+ bool bInTIMWake;
+ unsigned char *pbyPSPacketPool;
+ unsigned char byPSPacketPool[sizeof(STxMgmtPacket) + WLAN_NULLDATA_FR_MAXLEN];
+ bool bRxBeaconInTBTTWake;
+ unsigned char abyPSTxMap[MAX_NODE_NUM + 1];
// management command related
- UINT uCmdBusy;
- UINT uCmdHostAPBusy;
+ unsigned int uCmdBusy;
+ unsigned int uCmdHostAPBusy;
// management packet pool
- PBYTE pbyMgmtPacketPool;
- BYTE byMgmtPacketPool[sizeof(STxMgmtPacket) + WLAN_A3FR_MAXLEN];
+ unsigned char *pbyMgmtPacketPool;
+ unsigned char byMgmtPacketPool[sizeof(STxMgmtPacket) + WLAN_A3FR_MAXLEN];
// One second callback timer
@@ -366,7 +366,7 @@ typedef struct tagSMgmtObject
// WPA2 PMKID Cache
SPMKIDCache gsPMKIDCache;
- BOOL bRoaming;
+ bool bRoaming;
// rate fall back vars
@@ -377,16 +377,16 @@ typedef struct tagSMgmtObject
// for 802.11h
- BOOL b11hEnable;
- BOOL bSwitchChannel;
- BYTE byNewChannel;
+ bool b11hEnable;
+ bool bSwitchChannel;
+ unsigned char byNewChannel;
PWLAN_IE_MEASURE_REP pCurrMeasureEIDRep;
- UINT uLengthOfRepEIDs;
- BYTE abyCurrentMSRReq[sizeof(STxMgmtPacket) + WLAN_A3FR_MAXLEN];
- BYTE abyCurrentMSRRep[sizeof(STxMgmtPacket) + WLAN_A3FR_MAXLEN];
- BYTE abyIECountry[WLAN_A3FR_MAXLEN];
- BYTE abyIBSSDFSOwner[6];
- BYTE byIBSSDFSRecovery;
+ unsigned int uLengthOfRepEIDs;
+ unsigned char abyCurrentMSRReq[sizeof(STxMgmtPacket) + WLAN_A3FR_MAXLEN];
+ unsigned char abyCurrentMSRRep[sizeof(STxMgmtPacket) + WLAN_A3FR_MAXLEN];
+ unsigned char abyIECountry[WLAN_A3FR_MAXLEN];
+ unsigned char abyIBSSDFSOwner[6];
+ unsigned char byIBSSDFSRecovery;
struct sk_buff skb;
@@ -432,8 +432,8 @@ void
vMgrDisassocBeginSta(
void *hDeviceContext,
PSMgmtObject pMgmt,
- PBYTE abyDestAddress,
- WORD wReason,
+ unsigned char *abyDestAddress,
+ unsigned short wReason,
PCMD_STATUS pStatus
);
@@ -475,22 +475,22 @@ void
vMgrDeAuthenBeginSta(
void *hDeviceContext,
PSMgmtObject pMgmt,
- PBYTE abyDestAddress,
- WORD wReason,
+ unsigned char *abyDestAddress,
+ unsigned short wReason,
PCMD_STATUS pStatus
);
-BOOL
+bool
bMgrPrepareBeaconToSend(
void *hDeviceContext,
PSMgmtObject pMgmt
);
-BOOL
+bool
bAdd_PMKID_Candidate (
void *hDeviceContext,
- PBYTE pbyBSSID,
+ unsigned char *pbyBSSID,
PSRSNCapObject psRSNCapObj
);
diff --git a/drivers/staging/vt6655/wpa.c b/drivers/staging/vt6655/wpa.c
index da5c814e200..61ac46fa505 100644
--- a/drivers/staging/vt6655/wpa.c
+++ b/drivers/staging/vt6655/wpa.c
@@ -45,12 +45,12 @@
/*--------------------- Static Variables --------------------------*/
static int msglevel =MSG_LEVEL_INFO;
-const BYTE abyOUI00[4] = { 0x00, 0x50, 0xf2, 0x00 };
-const BYTE abyOUI01[4] = { 0x00, 0x50, 0xf2, 0x01 };
-const BYTE abyOUI02[4] = { 0x00, 0x50, 0xf2, 0x02 };
-const BYTE abyOUI03[4] = { 0x00, 0x50, 0xf2, 0x03 };
-const BYTE abyOUI04[4] = { 0x00, 0x50, 0xf2, 0x04 };
-const BYTE abyOUI05[4] = { 0x00, 0x50, 0xf2, 0x05 };
+const unsigned char abyOUI00[4] = { 0x00, 0x50, 0xf2, 0x00 };
+const unsigned char abyOUI01[4] = { 0x00, 0x50, 0xf2, 0x01 };
+const unsigned char abyOUI02[4] = { 0x00, 0x50, 0xf2, 0x02 };
+const unsigned char abyOUI03[4] = { 0x00, 0x50, 0xf2, 0x03 };
+const unsigned char abyOUI04[4] = { 0x00, 0x50, 0xf2, 0x04 };
+const unsigned char abyOUI05[4] = { 0x00, 0x50, 0xf2, 0x05 };
/*+
@@ -83,9 +83,9 @@ WPA_ClearRSN (
pBSSList->wAuthCount = 0;
pBSSList->byDefaultK_as_PK = 0;
pBSSList->byReplayIdx = 0;
- pBSSList->sRSNCapObj.bRSNCapExist = FALSE;
+ pBSSList->sRSNCapObj.bRSNCapExist = false;
pBSSList->sRSNCapObj.wRSNCap = 0;
- pBSSList->bWPAValid = FALSE;
+ pBSSList->bWPAValid = false;
}
@@ -112,7 +112,7 @@ WPA_ParseRSN (
{
PWLAN_IE_RSN_AUTH pIE_RSN_Auth = NULL;
int i, j, m, n = 0;
- PBYTE pbyCaps;
+ unsigned char *pbyCaps;
WPA_ClearRSN(pBSSList);
@@ -148,7 +148,7 @@ WPA_ParseRSN (
{
j = 0;
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"wPKCount: %d, sizeof(pBSSList->abyPKType): %zu\n", pRSN->wPKCount, sizeof(pBSSList->abyPKType));
- for(i = 0; (i < pRSN->wPKCount) && (j < sizeof(pBSSList->abyPKType)/sizeof(BYTE)); i++) {
+ for(i = 0; (i < pRSN->wPKCount) && (j < sizeof(pBSSList->abyPKType)/sizeof(unsigned char)); i++) {
if(pRSN->len >= 12+i*4+4) { //oui1(4)+ver(2)+GKS(4)+PKSCnt(2)+PKS(4*i)
if ( !memcmp(pRSN->PKSList[i].abyOUI, abyOUI00, 4))
pBSSList->abyPKType[j++] = WPA_NONE;
@@ -166,7 +166,7 @@ WPA_ParseRSN (
break;
//DBG_PRN_GRP14(("abyPKType[%d]: %X\n", j-1, pBSSList->abyPKType[j-1]));
} //for
- pBSSList->wPKCount = (WORD)j;
+ pBSSList->wPKCount = (unsigned short)j;
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"wPKCount: %d\n", pBSSList->wPKCount);
}
@@ -180,7 +180,7 @@ WPA_ParseRSN (
j = 0;
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"wAuthCount: %d, sizeof(pBSSList->abyAuthType): %zu\n",
pIE_RSN_Auth->wAuthCount, sizeof(pBSSList->abyAuthType));
- for(i = 0; (i < pIE_RSN_Auth->wAuthCount) && (j < sizeof(pBSSList->abyAuthType)/sizeof(BYTE)); i++) {
+ for(i = 0; (i < pIE_RSN_Auth->wAuthCount) && (j < sizeof(pBSSList->abyAuthType)/sizeof(unsigned char)); i++) {
if(pRSN->len >= 14+4+(m+i)*4) { //oui1(4)+ver(2)+GKS(4)+PKSCnt(2)+PKS(4*m)+AKC(2)+AKS(4*i)
if ( !memcmp(pIE_RSN_Auth->AuthKSList[i].abyOUI, abyOUI01, 4))
pBSSList->abyAuthType[j++] = WPA_AUTH_IEEE802_1X;
@@ -195,7 +195,7 @@ WPA_ParseRSN (
//DBG_PRN_GRP14(("abyAuthType[%d]: %X\n", j-1, pBSSList->abyAuthType[j-1]));
}
if(j > 0)
- pBSSList->wAuthCount = (WORD)j;
+ pBSSList->wAuthCount = (unsigned short)j;
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"wAuthCount: %d\n", pBSSList->wAuthCount);
}
@@ -207,17 +207,17 @@ WPA_ParseRSN (
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"14+4+(m+n)*4: %d\n", 14+4+(m+n)*4);
if(pRSN->len+2 >= 14+4+(m+n)*4) { //oui1(4)+ver(2)+GKS(4)+PKSCnt(2)+PKS(4*m)+AKC(2)+AKS(4*n)+Cap(2)
- pbyCaps = (PBYTE)pIE_RSN_Auth->AuthKSList[n].abyOUI;
+ pbyCaps = (unsigned char *)pIE_RSN_Auth->AuthKSList[n].abyOUI;
pBSSList->byDefaultK_as_PK = (*pbyCaps) & WPA_GROUPFLAG;
pBSSList->byReplayIdx = 2 << ((*pbyCaps >> WPA_REPLAYBITSSHIFT) & WPA_REPLAYBITS);
- pBSSList->sRSNCapObj.bRSNCapExist = TRUE;
- pBSSList->sRSNCapObj.wRSNCap = *(PWORD)pbyCaps;
+ pBSSList->sRSNCapObj.bRSNCapExist = true;
+ pBSSList->sRSNCapObj.wRSNCap = *(unsigned short *)pbyCaps;
//DBG_PRN_GRP14(("pbyCaps: %X\n", *pbyCaps));
//DBG_PRN_GRP14(("byDefaultK_as_PK: %X\n", pBSSList->byDefaultK_as_PK));
//DBG_PRN_GRP14(("byReplayIdx: %X\n", pBSSList->byReplayIdx));
}
}
- pBSSList->bWPAValid = TRUE;
+ pBSSList->bWPAValid = true;
}
}
@@ -237,24 +237,24 @@ WPA_ParseRSN (
* Return Value: none.
*
-*/
-BOOL
+bool
WPA_SearchRSN (
- BYTE byCmd,
- BYTE byEncrypt,
+ unsigned char byCmd,
+ unsigned char byEncrypt,
PKnownBSS pBSSList
)
{
int ii;
- BYTE byPKType = WPA_NONE;
+ unsigned char byPKType = WPA_NONE;
- if (pBSSList->bWPAValid == FALSE)
- return FALSE;
+ if (pBSSList->bWPAValid == false)
+ return false;
switch(byCmd) {
case 0:
if (byEncrypt != pBSSList->byGKType)
- return FALSE;
+ return false;
if (pBSSList->wPKCount > 0) {
for (ii = 0; ii < pBSSList->wPKCount; ii ++) {
@@ -268,9 +268,9 @@ WPA_SearchRSN (
byPKType = WPA_WEP104;
}
if (byEncrypt != byPKType)
- return FALSE;
+ return false;
}
- return TRUE;
+ return true;
// if (pBSSList->wAuthCount > 0)
// for (ii=0; ii < pBSSList->wAuthCount; ii ++)
// if (byAuth == pBSSList->abyAuthType[ii])
@@ -280,7 +280,7 @@ WPA_SearchRSN (
default:
break;
}
- return FALSE;
+ return false;
}
/*+
@@ -297,20 +297,20 @@ WPA_SearchRSN (
* Return Value: none.
*
-*/
-BOOL
+bool
WPAb_Is_RSN (
PWLAN_IE_RSN_EXT pRSN
)
{
if (pRSN == NULL)
- return FALSE;
+ return false;
if ((pRSN->len >= 6) && // oui1(4)+ver(2)
(pRSN->byElementID == WLAN_EID_RSN_WPA) && !memcmp(pRSN->abyOUI, abyOUI01, 4) &&
(pRSN->wVersion == 1)) {
- return TRUE;
+ return true;
}
else
- return FALSE;
+ return false;
}
diff --git a/drivers/staging/vt6655/wpa.h b/drivers/staging/vt6655/wpa.h
index 80d990b09d2..921fd7ae9d3 100644
--- a/drivers/staging/vt6655/wpa.h
+++ b/drivers/staging/vt6655/wpa.h
@@ -69,14 +69,14 @@ WPA_ParseRSN(
PWLAN_IE_RSN_EXT pRSN
);
-BOOL
+bool
WPA_SearchRSN(
- BYTE byCmd,
- BYTE byEncrypt,
+ unsigned char byCmd,
+ unsigned char byEncrypt,
PKnownBSS pBSSList
);
-BOOL
+bool
WPAb_Is_RSN(
PWLAN_IE_RSN_EXT pRSN
);
diff --git a/drivers/staging/vt6655/wpa2.c b/drivers/staging/vt6655/wpa2.c
index 7a42a0aad7d..805164bed7e 100644
--- a/drivers/staging/vt6655/wpa2.c
+++ b/drivers/staging/vt6655/wpa2.c
@@ -42,14 +42,14 @@ static int msglevel =MSG_LEVEL_INFO;
/*--------------------- Static Variables --------------------------*/
-const BYTE abyOUIGK[4] = { 0x00, 0x0F, 0xAC, 0x00 };
-const BYTE abyOUIWEP40[4] = { 0x00, 0x0F, 0xAC, 0x01 };
-const BYTE abyOUIWEP104[4] = { 0x00, 0x0F, 0xAC, 0x05 };
-const BYTE abyOUITKIP[4] = { 0x00, 0x0F, 0xAC, 0x02 };
-const BYTE abyOUICCMP[4] = { 0x00, 0x0F, 0xAC, 0x04 };
+const unsigned char abyOUIGK[4] = { 0x00, 0x0F, 0xAC, 0x00 };
+const unsigned char abyOUIWEP40[4] = { 0x00, 0x0F, 0xAC, 0x01 };
+const unsigned char abyOUIWEP104[4] = { 0x00, 0x0F, 0xAC, 0x05 };
+const unsigned char abyOUITKIP[4] = { 0x00, 0x0F, 0xAC, 0x02 };
+const unsigned char abyOUICCMP[4] = { 0x00, 0x0F, 0xAC, 0x04 };
-const BYTE abyOUI8021X[4] = { 0x00, 0x0F, 0xAC, 0x01 };
-const BYTE abyOUIPSK[4] = { 0x00, 0x0F, 0xAC, 0x02 };
+const unsigned char abyOUI8021X[4] = { 0x00, 0x0F, 0xAC, 0x01 };
+const unsigned char abyOUIPSK[4] = { 0x00, 0x0F, 0xAC, 0x02 };
/*--------------------- Static Functions --------------------------*/
@@ -79,7 +79,7 @@ WPA2_ClearRSN (
{
int ii;
- pBSSNode->bWPA2Valid = FALSE;
+ pBSSNode->bWPA2Valid = false;
pBSSNode->byCSSGK = WLAN_11i_CSS_CCMP;
for (ii=0; ii < 4; ii ++)
@@ -88,7 +88,7 @@ WPA2_ClearRSN (
for (ii=0; ii < 4; ii ++)
pBSSNode->abyAKMSSAuthType[ii] = WLAN_11i_AKMSS_802_1X;
pBSSNode->wAKMSSAuthCount = 1;
- pBSSNode->sRSNCapObj.bRSNCapExist = FALSE;
+ pBSSNode->sRSNCapObj.bRSNCapExist = false;
pBSSNode->sRSNCapObj.wRSNCap = 0;
}
@@ -114,9 +114,9 @@ WPA2vParseRSN (
)
{
int i, j;
- WORD m = 0, n = 0;
- PBYTE pbyOUI;
- BOOL bUseGK = FALSE;
+ unsigned short m = 0, n = 0;
+ unsigned char *pbyOUI;
+ bool bUseGK = false;
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"WPA2_ParseRSN: [%d]\n", pRSN->len);
@@ -124,7 +124,7 @@ WPA2vParseRSN (
if (pRSN->len == 2) { // ver(2)
if ((pRSN->byElementID == WLAN_EID_RSN) && (pRSN->wVersion == 1)) {
- pBSSNode->bWPA2Valid = TRUE;
+ pBSSNode->bWPA2Valid = true;
}
return;
}
@@ -159,21 +159,21 @@ WPA2vParseRSN (
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"802.11i CSS: %X\n", pBSSNode->byCSSGK);
if (pRSN->len == 6) {
- pBSSNode->bWPA2Valid = TRUE;
+ pBSSNode->bWPA2Valid = true;
return;
}
if (pRSN->len >= 8) { // ver(2) + GK(4) + PK count(2)
- pBSSNode->wCSSPKCount = *((PWORD) &(pRSN->abyRSN[4]));
+ pBSSNode->wCSSPKCount = *((unsigned short *) &(pRSN->abyRSN[4]));
j = 0;
pbyOUI = &(pRSN->abyRSN[6]);
- for (i = 0; (i < pBSSNode->wCSSPKCount) && (j < sizeof(pBSSNode->abyCSSPK)/sizeof(BYTE)); i++) {
+ for (i = 0; (i < pBSSNode->wCSSPKCount) && (j < sizeof(pBSSNode->abyCSSPK)/sizeof(unsigned char)); i++) {
if (pRSN->len >= 8+i*4+4) { // ver(2)+GK(4)+PKCnt(2)+PKS(4*i)
if ( !memcmp(pbyOUI, abyOUIGK, 4)) {
pBSSNode->abyCSSPK[j++] = WLAN_11i_CSS_USE_GROUP;
- bUseGK = TRUE;
+ bUseGK = true;
} else if ( !memcmp(pbyOUI, abyOUIWEP40, 4)) {
// Invialid CSS, continue to parsing
} else if ( !memcmp(pbyOUI, abyOUITKIP, 4)) {
@@ -195,7 +195,7 @@ WPA2vParseRSN (
break;
} //for
- if (bUseGK == TRUE) {
+ if (bUseGK == true) {
if (j != 1) {
// invalid CSS, This should be only PK CSS.
return;
@@ -209,17 +209,17 @@ WPA2vParseRSN (
// invalid CSS, No valid PK.
return;
}
- pBSSNode->wCSSPKCount = (WORD)j;
+ pBSSNode->wCSSPKCount = (unsigned short)j;
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"wCSSPKCount: %d\n", pBSSNode->wCSSPKCount);
}
- m = *((PWORD) &(pRSN->abyRSN[4]));
+ m = *((unsigned short *) &(pRSN->abyRSN[4]));
if (pRSN->len >= 10+m*4) { // ver(2) + GK(4) + PK count(2) + PKS(4*m) + AKMSS count(2)
- pBSSNode->wAKMSSAuthCount = *((PWORD) &(pRSN->abyRSN[6+4*m]));;
+ pBSSNode->wAKMSSAuthCount = *((unsigned short *) &(pRSN->abyRSN[6+4*m]));;
j = 0;
pbyOUI = &(pRSN->abyRSN[8+4*m]);
- for (i = 0; (i < pBSSNode->wAKMSSAuthCount) && (j < sizeof(pBSSNode->abyAKMSSAuthType)/sizeof(BYTE)); i++) {
+ for (i = 0; (i < pBSSNode->wAKMSSAuthCount) && (j < sizeof(pBSSNode->abyAKMSSAuthType)/sizeof(unsigned char)); i++) {
if (pRSN->len >= 10+(m+i)*4+4) { // ver(2)+GK(4)+PKCnt(2)+PKS(4*m)+AKMSS(2)+AKS(4*i)
if ( !memcmp(pbyOUI, abyOUI8021X, 4))
pBSSNode->abyAKMSSAuthType[j++] = WLAN_11i_AKMSS_802_1X;
@@ -232,17 +232,17 @@ WPA2vParseRSN (
} else
break;
}
- pBSSNode->wAKMSSAuthCount = (WORD)j;
+ pBSSNode->wAKMSSAuthCount = (unsigned short)j;
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"wAKMSSAuthCount: %d\n", pBSSNode->wAKMSSAuthCount);
- n = *((PWORD) &(pRSN->abyRSN[6+4*m]));;
+ n = *((unsigned short *) &(pRSN->abyRSN[6+4*m]));;
if (pRSN->len >= 12+4*m+4*n) { // ver(2)+GK(4)+PKCnt(2)+PKS(4*m)+AKMSSCnt(2)+AKMSS(4*n)+Cap(2)
- pBSSNode->sRSNCapObj.bRSNCapExist = TRUE;
- pBSSNode->sRSNCapObj.wRSNCap = *((PWORD) &(pRSN->abyRSN[8+4*m+4*n]));
+ pBSSNode->sRSNCapObj.bRSNCapExist = true;
+ pBSSNode->sRSNCapObj.wRSNCap = *((unsigned short *) &(pRSN->abyRSN[8+4*m+4*n]));
}
}
//ignore PMKID lists bcs only (Re)Assocrequest has this field
- pBSSNode->bWPA2Valid = TRUE;
+ pBSSNode->bWPA2Valid = true;
}
}
@@ -261,16 +261,16 @@ WPA2vParseRSN (
* Return Value: length of IEs.
*
-*/
-UINT
+unsigned int
WPA2uSetIEs(
void *pMgmtHandle,
PWLAN_IE_RSN pRSNIEs
)
{
PSMgmtObject pMgmt = (PSMgmtObject) pMgmtHandle;
- PBYTE pbyBuffer = NULL;
- UINT ii = 0;
- PWORD pwPMKID = NULL;
+ unsigned char *pbyBuffer = NULL;
+ unsigned int ii = 0;
+ unsigned short *pwPMKID = NULL;
if (pRSNIEs == NULL) {
return(0);
@@ -279,7 +279,7 @@ WPA2uSetIEs(
(pMgmt->eAuthenMode == WMAC_AUTH_WPA2PSK)) &&
(pMgmt->pCurrBSS != NULL)) {
/* WPA2 IE */
- pbyBuffer = (PBYTE) pRSNIEs;
+ pbyBuffer = (unsigned char *) pRSNIEs;
pRSNIEs->byElementID = WLAN_EID_RSN;
pRSNIEs->len = 6; //Version(2)+GK(4)
pRSNIEs->wVersion = 1;
@@ -330,7 +330,7 @@ WPA2uSetIEs(
pRSNIEs->len +=6;
// RSN Capabilites
- if (pMgmt->pCurrBSS->sRSNCapObj.bRSNCapExist == TRUE) {
+ if (pMgmt->pCurrBSS->sRSNCapObj.bRSNCapExist == true) {
memcpy(&pRSNIEs->abyRSN[16], &pMgmt->pCurrBSS->sRSNCapObj.wRSNCap, 2);
} else {
pRSNIEs->abyRSN[16] = 0;
@@ -339,10 +339,10 @@ WPA2uSetIEs(
pRSNIEs->len +=2;
if ((pMgmt->gsPMKIDCache.BSSIDInfoCount > 0) &&
- (pMgmt->bRoaming == TRUE) &&
+ (pMgmt->bRoaming == true) &&
(pMgmt->eAuthenMode == WMAC_AUTH_WPA2)) {
// RSN PMKID
- pwPMKID = (PWORD)(&pRSNIEs->abyRSN[18]); // Point to PMKID count
+ pwPMKID = (unsigned short *)(&pRSNIEs->abyRSN[18]); // Point to PMKID count
*pwPMKID = 0; // Initialize PMKID count
pbyBuffer = &pRSNIEs->abyRSN[20]; // Point to PMKID list
for (ii = 0; ii < pMgmt->gsPMKIDCache.BSSIDInfoCount; ii++) {
diff --git a/drivers/staging/vt6655/wpa2.h b/drivers/staging/vt6655/wpa2.h
index 7200db37f43..718208beb72 100644
--- a/drivers/staging/vt6655/wpa2.h
+++ b/drivers/staging/vt6655/wpa2.h
@@ -40,12 +40,12 @@
#define MAX_PMKID_CACHE 16
typedef struct tagsPMKIDInfo {
- BYTE abyBSSID[6];
- BYTE abyPMKID[16];
+ unsigned char abyBSSID[6];
+ unsigned char abyPMKID[16];
} PMKIDInfo, *PPMKIDInfo;
typedef struct tagSPMKIDCache {
- ULONG BSSIDInfoCount;
+ unsigned long BSSIDInfoCount;
PMKIDInfo BSSIDInfo[MAX_PMKID_CACHE];
} SPMKIDCache, *PSPMKIDCache;
@@ -69,7 +69,7 @@ WPA2vParseRSN (
PWLAN_IE_RSN pRSN
);
-UINT
+unsigned int
WPA2uSetIEs(
void *pMgmtHandle,
PWLAN_IE_RSN pRSNIEs
diff --git a/drivers/staging/vt6655/wpactl.c b/drivers/staging/vt6655/wpactl.c
index 22c2fab3f32..0142338bcaf 100644
--- a/drivers/staging/vt6655/wpactl.c
+++ b/drivers/staging/vt6655/wpactl.c
@@ -199,16 +199,16 @@ int wpa_set_wpadev(PSDevice pDevice, int val)
*
*/
- int wpa_set_keys(PSDevice pDevice, void *ctx, BOOL fcpfkernel)
+ int wpa_set_keys(PSDevice pDevice, void *ctx, bool fcpfkernel)
{
struct viawget_wpa_param *param=ctx;
PSMgmtObject pMgmt = pDevice->pMgmt;
- DWORD dwKeyIndex = 0;
- BYTE abyKey[MAX_KEY_LEN];
- BYTE abySeq[MAX_KEY_LEN];
+ unsigned long dwKeyIndex = 0;
+ unsigned char abyKey[MAX_KEY_LEN];
+ unsigned char abySeq[MAX_KEY_LEN];
QWORD KeyRSC;
// NDIS_802_11_KEY_RSC KeyRSC;
- BYTE byKeyDecMode = KEY_CTL_WEP;
+ unsigned char byKeyDecMode = KEY_CTL_WEP;
int ret = 0;
int uu, ii;
@@ -219,9 +219,9 @@ int wpa_set_wpadev(PSDevice pDevice, int val)
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "param->u.wpa_key.alg_name = %d \n", param->u.wpa_key.alg_name);
if (param->u.wpa_key.alg_name == WPA_ALG_NONE) {
pDevice->eEncryptionStatus = Ndis802_11EncryptionDisabled;
- pDevice->bEncryptionEnable = FALSE;
+ pDevice->bEncryptionEnable = false;
pDevice->byKeyIndex = 0;
- pDevice->bTransmitKey = FALSE;
+ pDevice->bTransmitKey = false;
KeyvRemoveAllWEPKey(&(pDevice->sKey), pDevice->PortOffset);
for (uu=0; uu<MAX_KEY_TABLE; uu++) {
MACvDisableKeyEntry(pDevice->PortOffset, uu);
@@ -243,7 +243,7 @@ int wpa_set_wpadev(PSDevice pDevice, int val)
spin_lock_irq(&pDevice->lock);
}
- dwKeyIndex = (DWORD)(param->u.wpa_key.key_index);
+ dwKeyIndex = (unsigned long)(param->u.wpa_key.key_index);
if (param->u.wpa_key.alg_name == WPA_ALG_WEP) {
if (dwKeyIndex > 3) {
@@ -251,8 +251,8 @@ spin_lock_irq(&pDevice->lock);
}
else {
if (param->u.wpa_key.set_tx) {
- pDevice->byKeyIndex = (BYTE)dwKeyIndex;
- pDevice->bTransmitKey = TRUE;
+ pDevice->byKeyIndex = (unsigned char)dwKeyIndex;
+ pDevice->bTransmitKey = true;
dwKeyIndex |= (1 << 31);
}
KeybSetDefaultKey(&(pDevice->sKey),
@@ -266,7 +266,7 @@ spin_lock_irq(&pDevice->lock);
}
pDevice->eEncryptionStatus = Ndis802_11Encryption1Enabled;
- pDevice->bEncryptionEnable = TRUE;
+ pDevice->bEncryptionEnable = true;
return ret;
}
@@ -351,26 +351,26 @@ spin_lock_irq(&pDevice->lock);
}
// spin_lock_irq(&pDevice->lock);
- if (IS_BROADCAST_ADDRESS(&param->addr[0]) || (param->addr == NULL)) {
- // If IS_BROADCAST_ADDRESS, set the key as every key entry's group key.
+ if (is_broadcast_ether_addr(&param->addr[0]) || (param->addr == NULL)) {
+ // If is_broadcast_ether_addr, set the key as every key entry's group key.
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Groupe Key Assign.\n");
if ((KeybSetAllGroupKey(&(pDevice->sKey),
dwKeyIndex,
param->u.wpa_key.key_len,
(PQWORD) &(KeyRSC),
- (PBYTE)abyKey,
+ (unsigned char *)abyKey,
byKeyDecMode,
pDevice->PortOffset,
- pDevice->byLocalID) == TRUE) &&
+ pDevice->byLocalID) == true) &&
(KeybSetDefaultKey(&(pDevice->sKey),
dwKeyIndex,
param->u.wpa_key.key_len,
(PQWORD) &(KeyRSC),
- (PBYTE)abyKey,
+ (unsigned char *)abyKey,
byKeyDecMode,
pDevice->PortOffset,
- pDevice->byLocalID) == TRUE) ) {
+ pDevice->byLocalID) == true) ) {
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "GROUP Key Assign.\n");
} else {
@@ -400,15 +400,15 @@ spin_lock_irq(&pDevice->lock);
dwKeyIndex,
param->u.wpa_key.key_len,
(PQWORD) &(KeyRSC),
- (PBYTE)abyKey,
+ (unsigned char *)abyKey,
byKeyDecMode,
pDevice->PortOffset,
- pDevice->byLocalID) == TRUE) {
+ pDevice->byLocalID) == true) {
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Pairwise Key Set\n");
} else {
// Key Table Full
- if (IS_ETH_ADDRESS_EQUAL(&param->addr[0], pDevice->abyBSSID)) {
+ if (!compare_ether_addr(&param->addr[0], pDevice->abyBSSID)) {
//DBG_PRN_WLAN03(("return NDIS_STATUS_INVALID_DATA -Key Table Full.2\n"));
//spin_unlock_irq(&pDevice->lock);
return -EINVAL;
@@ -422,10 +422,10 @@ spin_lock_irq(&pDevice->lock);
}
} // BSSID not 0xffffffffffff
if ((ret == 0) && ((param->u.wpa_key.set_tx) != 0)) {
- pDevice->byKeyIndex = (BYTE)param->u.wpa_key.key_index;
- pDevice->bTransmitKey = TRUE;
+ pDevice->byKeyIndex = (unsigned char)param->u.wpa_key.key_index;
+ pDevice->bTransmitKey = true;
}
- pDevice->bEncryptionEnable = TRUE;
+ pDevice->bEncryptionEnable = true;
//spin_unlock_irq(&pDevice->lock);
/*
@@ -465,7 +465,7 @@ static int wpa_set_wpa(PSDevice pDevice,
int ret = 0;
pMgmt->eAuthenMode = WMAC_AUTH_OPEN;
- pMgmt->bShareKeyAlgorithm = FALSE;
+ pMgmt->bShareKeyAlgorithm = false;
return ret;
}
@@ -613,13 +613,13 @@ static int wpa_get_scan(PSDevice pDevice,
PSMgmtObject pMgmt = pDevice->pMgmt;
PWLAN_IE_SSID pItemSSID;
PKnownBSS pBSS;
- PBYTE pBuf;
+ unsigned char *pBuf;
int ret = 0;
u16 count = 0;
u16 ii, jj;
#if 1
- PBYTE ptempBSS;
+ unsigned char *ptempBSS;
@@ -639,9 +639,9 @@ static int wpa_get_scan(PSDevice pDevice,
for(jj=0;jj<MAX_BSS_NUM-ii-1;jj++) {
- if((pMgmt->sBSSList[jj].bActive!=TRUE) ||
+ if((pMgmt->sBSSList[jj].bActive!=true) ||
- ((pMgmt->sBSSList[jj].uRSSI>pMgmt->sBSSList[jj+1].uRSSI) &&(pMgmt->sBSSList[jj+1].bActive!=FALSE))) {
+ ((pMgmt->sBSSList[jj].uRSSI>pMgmt->sBSSList[jj+1].uRSSI) &&(pMgmt->sBSSList[jj+1].bActive!=false))) {
memcpy(ptempBSS,&pMgmt->sBSSList[jj],sizeof(KnownBSS));
@@ -713,7 +713,7 @@ static int wpa_get_scan(PSDevice pDevice,
scan_buf->rsn_ie_len = pBSS->wRSNLen;
memcpy(scan_buf->rsn_ie, pBSS->byRSNIE, pBSS->wRSNLen);
}
- scan_buf = (struct viawget_scan_result *)((PBYTE)scan_buf + sizeof(struct viawget_scan_result));
+ scan_buf = (struct viawget_scan_result *)((unsigned char *)scan_buf + sizeof(struct viawget_scan_result));
jj ++;
}
}
@@ -752,10 +752,10 @@ static int wpa_set_associate(PSDevice pDevice,
{
PSMgmtObject pMgmt = pDevice->pMgmt;
PWLAN_IE_SSID pItemSSID;
- BYTE abyNullAddr[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
- BYTE abyWPAIE[64];
+ unsigned char abyNullAddr[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+ unsigned char abyWPAIE[64];
int ret = 0;
- BOOL bWepEnabled=FALSE;
+ bool bWepEnabled=false;
// set key type & algorithm
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "pairwise_suite = %d\n", param->u.wpa_associate.pairwise_suite);
@@ -817,7 +817,7 @@ else
case CIPHER_WEP40:
case CIPHER_WEP104:
pDevice->eEncryptionStatus = Ndis802_11Encryption1Enabled;
- bWepEnabled=TRUE;
+ bWepEnabled=true;
break;
case CIPHER_NONE:
if (param->u.wpa_associate.group_suite == CIPHER_CCMP)
@@ -834,26 +834,26 @@ else
if (pMgmt->eAuthenMode == WMAC_AUTH_SHAREKEY) {
pDevice->eEncryptionStatus = Ndis802_11Encryption1Enabled;
//pMgmt->eAuthenMode = WMAC_AUTH_SHAREKEY;
- pMgmt->bShareKeyAlgorithm = TRUE;
+ pMgmt->bShareKeyAlgorithm = true;
}
else if (pMgmt->eAuthenMode == WMAC_AUTH_OPEN) {
if(!bWepEnabled) pDevice->eEncryptionStatus = Ndis802_11EncryptionDisabled;
else pDevice->eEncryptionStatus = Ndis802_11Encryption1Enabled;
//pMgmt->eAuthenMode = WMAC_AUTH_OPEN;
- //pMgmt->bShareKeyAlgorithm = FALSE; //20080717-06,<Modify> by chester//Fix Open mode, WEP encrytion
+ //pMgmt->bShareKeyAlgorithm = false; //20080717-06,<Modify> by chester//Fix Open mode, WEP encrytion
}
//mike save old encryption status
pDevice->eOldEncryptionStatus = pDevice->eEncryptionStatus;
if (pDevice->eEncryptionStatus != Ndis802_11EncryptionDisabled)
- pDevice->bEncryptionEnable = TRUE;
+ pDevice->bEncryptionEnable = true;
else
- pDevice->bEncryptionEnable = FALSE;
+ pDevice->bEncryptionEnable = false;
if (!((pMgmt->eAuthenMode == WMAC_AUTH_SHAREKEY) ||
- ((pMgmt->eAuthenMode == WMAC_AUTH_OPEN) && (bWepEnabled==TRUE))) ) //DavidWang //20080717-06,<Modify> by chester//Not to initial WEP
+ ((pMgmt->eAuthenMode == WMAC_AUTH_OPEN) && (bWepEnabled==true))) ) //DavidWang //20080717-06,<Modify> by chester//Not to initial WEP
KeyvInitTable(&pDevice->sKey, pDevice->PortOffset);
spin_lock_irq(&pDevice->lock);
- pDevice->bLinkPass = FALSE;
+ pDevice->bLinkPass = false;
memset(pMgmt->abyCurrBSSID, 0, 6);
pMgmt->eCurrState = WMAC_STATE_IDLE;
netif_stop_queue(pDevice->dev);
@@ -922,7 +922,7 @@ int wpa_ioctl(PSDevice pDevice, struct iw_point *p)
case VIAWGET_SET_KEY:
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "VIAWGET_SET_KEY \n");
spin_lock_irq(&pDevice->lock);
- ret = wpa_set_keys(pDevice, param, FALSE);
+ ret = wpa_set_keys(pDevice, param, false);
spin_unlock_irq(&pDevice->lock);
break;
diff --git a/drivers/staging/vt6655/wpactl.h b/drivers/staging/vt6655/wpactl.h
index b0d92d51a2a..dbe8e861d99 100644
--- a/drivers/staging/vt6655/wpactl.h
+++ b/drivers/staging/vt6655/wpactl.h
@@ -54,7 +54,7 @@ typedef enum { KEY_MGMT_802_1X, KEY_MGMT_CCKM,KEY_MGMT_PSK, KEY_MGMT_NONE,
-typedef ULONGLONG NDIS_802_11_KEY_RSC;
+typedef unsigned long long NDIS_802_11_KEY_RSC;
/*--------------------- Export Classes ----------------------------*/
@@ -64,7 +64,7 @@ typedef ULONGLONG NDIS_802_11_KEY_RSC;
int wpa_set_wpadev(PSDevice pDevice, int val);
int wpa_ioctl(PSDevice pDevice, struct iw_point *p);
-int wpa_set_keys(PSDevice pDevice, void *ctx, BOOL fcpfkernel);
+int wpa_set_keys(PSDevice pDevice, void *ctx, bool fcpfkernel);
#endif // __WPACL_H__
diff --git a/drivers/staging/vt6655/wroute.c b/drivers/staging/vt6655/wroute.c
index bf92fb9908f..66e2eeae628 100644
--- a/drivers/staging/vt6655/wroute.c
+++ b/drivers/staging/vt6655/wroute.c
@@ -53,45 +53,45 @@ static int msglevel =MSG_LEVEL_INFO;
/*
* Description:
- * Relay packet. Return TRUE if packet is copy to DMA1
+ * Relay packet. Return true if packet is copy to DMA1
*
* Parameters:
* In:
* pDevice -
* pbySkbData - rx packet skb data
* Out:
- * TURE, FALSE
+ * true, false
*
- * Return Value: TRUE if packet duplicate; otherwise FALSE
+ * Return Value: true if packet duplicate; otherwise false
*
*/
-BOOL ROUTEbRelay (PSDevice pDevice, PBYTE pbySkbData, UINT uDataLen, UINT uNodeIndex)
+bool ROUTEbRelay (PSDevice pDevice, unsigned char *pbySkbData, unsigned int uDataLen, unsigned int uNodeIndex)
{
PSMgmtObject pMgmt = pDevice->pMgmt;
PSTxDesc pHeadTD, pLastTD;
- UINT cbFrameBodySize;
- UINT uMACfragNum;
- BYTE byPktType;
- BOOL bNeedEncryption = FALSE;
+ unsigned int cbFrameBodySize;
+ unsigned int uMACfragNum;
+ unsigned char byPktType;
+ bool bNeedEncryption = false;
SKeyItem STempKey;
PSKeyItem pTransmitKey = NULL;
- UINT cbHeaderSize;
- UINT ii;
- PBYTE pbyBSSID;
+ unsigned int cbHeaderSize;
+ unsigned int ii;
+ unsigned char *pbyBSSID;
if (AVAIL_TD(pDevice, TYPE_AC0DMA)<=0) {
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Relay can't allocate TD1..\n");
- return FALSE;
+ return false;
}
pHeadTD = pDevice->apCurrTD[TYPE_AC0DMA];
pHeadTD->m_td1TD1.byTCR = (TCR_EDP|TCR_STP);
- memcpy(pDevice->sTxEthHeader.abyDstAddr, (PBYTE)pbySkbData, ETH_HLEN);
+ memcpy(pDevice->sTxEthHeader.abyDstAddr, (unsigned char *)pbySkbData, ETH_HLEN);
cbFrameBodySize = uDataLen - ETH_HLEN;
@@ -99,12 +99,12 @@ BOOL ROUTEbRelay (PSDevice pDevice, PBYTE pbySkbData, UINT uDataLen, UINT uNodeI
cbFrameBodySize += 8;
}
- if (pDevice->bEncryptionEnable == TRUE) {
- bNeedEncryption = TRUE;
+ if (pDevice->bEncryptionEnable == true) {
+ bNeedEncryption = true;
// get group key
pbyBSSID = pDevice->abyBroadcastAddr;
- if(KeybGetTransmitKey(&(pDevice->sKey), pbyBSSID, GROUP_KEY, &pTransmitKey) == FALSE) {
+ if(KeybGetTransmitKey(&(pDevice->sKey), pbyBSSID, GROUP_KEY, &pTransmitKey) == false) {
pTransmitKey = NULL;
DBG_PRT(MSG_LEVEL_DEBUG, KERN_DEBUG"KEY is NULL. [%d]\n", pDevice->pMgmt->eCurrMode);
} else {
@@ -130,16 +130,16 @@ BOOL ROUTEbRelay (PSDevice pDevice, PBYTE pbySkbData, UINT uDataLen, UINT uNodeI
uMACfragNum = cbGetFragCount(pDevice, pTransmitKey, cbFrameBodySize, &pDevice->sTxEthHeader);
if (uMACfragNum > AVAIL_TD(pDevice,TYPE_AC0DMA)) {
- return FALSE;
+ return false;
}
- byPktType = (BYTE)pDevice->byPacketType;
+ byPktType = (unsigned char)pDevice->byPacketType;
if (pDevice->bFixRate) {
if (pDevice->eCurrentPHYType == PHY_TYPE_11B) {
if (pDevice->uConnectionRate >= RATE_11M) {
pDevice->wCurrentRate = RATE_11M;
} else {
- pDevice->wCurrentRate = (WORD)pDevice->uConnectionRate;
+ pDevice->wCurrentRate = (unsigned short)pDevice->uConnectionRate;
}
} else {
if ((pDevice->eCurrentPHYType == PHY_TYPE_11A) &&
@@ -149,7 +149,7 @@ BOOL ROUTEbRelay (PSDevice pDevice, PBYTE pbySkbData, UINT uDataLen, UINT uNodeI
if (pDevice->uConnectionRate >= RATE_54M)
pDevice->wCurrentRate = RATE_54M;
else
- pDevice->wCurrentRate = (WORD)pDevice->uConnectionRate;
+ pDevice->wCurrentRate = (unsigned short)pDevice->uConnectionRate;
}
}
}
@@ -172,7 +172,7 @@ BOOL ROUTEbRelay (PSDevice pDevice, PBYTE pbySkbData, UINT uDataLen, UINT uNodeI
MACbPSWakeup(pDevice->PortOffset);
}
- pDevice->bPWBitOn = FALSE;
+ pDevice->bPWBitOn = false;
pLastTD = pHeadTD;
for (ii = 0; ii < uMACfragNum; ii++) {
@@ -192,7 +192,7 @@ BOOL ROUTEbRelay (PSDevice pDevice, PBYTE pbySkbData, UINT uDataLen, UINT uNodeI
MACvTransmitAC0(pDevice->PortOffset);
- return TRUE;
+ return true;
}
diff --git a/drivers/staging/vt6655/wroute.h b/drivers/staging/vt6655/wroute.h
index 295cdc5b8e9..34f9e43a6cc 100644
--- a/drivers/staging/vt6655/wroute.h
+++ b/drivers/staging/vt6655/wroute.h
@@ -39,7 +39,7 @@
/*--------------------- Export Functions --------------------------*/
-BOOL ROUTEbRelay (PSDevice pDevice, PBYTE pbySkbData, UINT uDataLen, UINT uNodeIndex);
+bool ROUTEbRelay (PSDevice pDevice, unsigned char *pbySkbData, unsigned int uDataLen, unsigned int uNodeIndex);
#endif // __WROUTE_H__
diff --git a/drivers/staging/vt6656/80211mgr.c b/drivers/staging/vt6656/80211mgr.c
index f24dc55e68f..fceec4999c3 100644
--- a/drivers/staging/vt6656/80211mgr.c
+++ b/drivers/staging/vt6656/80211mgr.c
@@ -18,7 +18,7 @@
*
* File: 80211mgr.c
*
- * Purpose: Handles the 802.11 managment support functions
+ * Purpose: Handles the 802.11 management support functions
*
* Author: Lyndon Chen
*
@@ -67,8 +67,8 @@
/*--------------------- Static Variables --------------------------*/
-static int msglevel =MSG_LEVEL_INFO;
-//static int msglevel =MSG_LEVEL_DEBUG;
+static int msglevel = MSG_LEVEL_INFO;
+/*static int msglevel =MSG_LEVEL_DEBUG;*/
/*--------------------- Static Functions --------------------------*/
@@ -96,7 +96,7 @@ vMgrEncodeBeacon(
{
pFrame->pHdr = (PUWLAN_80211HDR)pFrame->pBuf;
- // Fixed Fields
+ /* Fixed Fields */
pFrame->pqwTimestamp = (PQWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ WLAN_BEACON_OFF_TS);
pFrame->pwBeaconInterval = (PWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
@@ -130,7 +130,7 @@ vMgrDecodeBeacon(
pFrame->pHdr = (PUWLAN_80211HDR)pFrame->pBuf;
- // Fixed Fields
+ /* Fixed Fields */
pFrame->pqwTimestamp = (PQWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ WLAN_BEACON_OFF_TS);
pFrame->pwBeaconInterval = (PWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
@@ -138,88 +138,87 @@ vMgrDecodeBeacon(
pFrame->pwCapInfo = (PWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ WLAN_BEACON_OFF_CAPINFO);
- // Information elements
+ /* Information elements */
pItem = (PWLAN_IE)((PBYTE)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3)))
+ WLAN_BEACON_OFF_SSID);
- while( ((PBYTE)pItem) < (pFrame->pBuf + pFrame->len) ){
+ while (((PBYTE)pItem) < (pFrame->pBuf + pFrame->len)) {
switch (pItem->byElementID) {
- case WLAN_EID_SSID:
- if (pFrame->pSSID == NULL)
- pFrame->pSSID = (PWLAN_IE_SSID)pItem;
- break;
- case WLAN_EID_SUPP_RATES:
- if (pFrame->pSuppRates == NULL)
- pFrame->pSuppRates = (PWLAN_IE_SUPP_RATES)pItem;
- break;
- case WLAN_EID_FH_PARMS:
- //pFrame->pFHParms = (PWLAN_IE_FH_PARMS)pItem;
- break;
- case WLAN_EID_DS_PARMS:
- if (pFrame->pDSParms == NULL)
- pFrame->pDSParms = (PWLAN_IE_DS_PARMS)pItem;
- break;
- case WLAN_EID_CF_PARMS:
- if (pFrame->pCFParms == NULL)
- pFrame->pCFParms = (PWLAN_IE_CF_PARMS)pItem;
- break;
- case WLAN_EID_IBSS_PARMS:
- if (pFrame->pIBSSParms == NULL)
- pFrame->pIBSSParms = (PWLAN_IE_IBSS_PARMS)pItem;
- break;
- case WLAN_EID_TIM:
- if (pFrame->pTIM == NULL)
- pFrame->pTIM = (PWLAN_IE_TIM)pItem;
- break;
-
- case WLAN_EID_RSN:
- if (pFrame->pRSN == NULL) {
- pFrame->pRSN = (PWLAN_IE_RSN)pItem;
- }
- break;
- case WLAN_EID_RSN_WPA:
- if (pFrame->pRSNWPA == NULL) {
- if (WPAb_Is_RSN((PWLAN_IE_RSN_EXT)pItem) == TRUE)
- pFrame->pRSNWPA = (PWLAN_IE_RSN_EXT)pItem;
- }
- break;
-
- case WLAN_EID_ERP:
- if (pFrame->pERP == NULL)
- pFrame->pERP = (PWLAN_IE_ERP)pItem;
- break;
- case WLAN_EID_EXTSUPP_RATES:
- if (pFrame->pExtSuppRates == NULL)
- pFrame->pExtSuppRates = (PWLAN_IE_SUPP_RATES)pItem;
- break;
-
- case WLAN_EID_COUNTRY: //7
- if (pFrame->pIE_Country == NULL)
- pFrame->pIE_Country = (PWLAN_IE_COUNTRY)pItem;
- break;
-
- case WLAN_EID_PWR_CONSTRAINT: //32
- if (pFrame->pIE_PowerConstraint == NULL)
- pFrame->pIE_PowerConstraint = (PWLAN_IE_PW_CONST)pItem;
- break;
-
- case WLAN_EID_CH_SWITCH: //37
- if (pFrame->pIE_CHSW == NULL)
- pFrame->pIE_CHSW = (PWLAN_IE_CH_SW)pItem;
- break;
-
- case WLAN_EID_QUIET: //40
- if (pFrame->pIE_Quiet == NULL)
- pFrame->pIE_Quiet = (PWLAN_IE_QUIET)pItem;
- break;
-
- case WLAN_EID_IBSS_DFS:
- if (pFrame->pIE_IBSSDFS == NULL)
- pFrame->pIE_IBSSDFS = (PWLAN_IE_IBSS_DFS)pItem;
- break;
-
- default:
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Unrecognized EID=%dd in beacon decode.\n", pItem->byElementID);
+ case WLAN_EID_SSID:
+ if (pFrame->pSSID == NULL)
+ pFrame->pSSID = (PWLAN_IE_SSID)pItem;
+ break;
+ case WLAN_EID_SUPP_RATES:
+ if (pFrame->pSuppRates == NULL)
+ pFrame->pSuppRates = (PWLAN_IE_SUPP_RATES)pItem;
+ break;
+ case WLAN_EID_FH_PARMS:
+ /* pFrame->pFHParms = (PWLAN_IE_FH_PARMS)pItem; */
+ break;
+ case WLAN_EID_DS_PARMS:
+ if (pFrame->pDSParms == NULL)
+ pFrame->pDSParms = (PWLAN_IE_DS_PARMS)pItem;
+ break;
+ case WLAN_EID_CF_PARMS:
+ if (pFrame->pCFParms == NULL)
+ pFrame->pCFParms = (PWLAN_IE_CF_PARMS)pItem;
+ break;
+ case WLAN_EID_IBSS_PARMS:
+ if (pFrame->pIBSSParms == NULL)
+ pFrame->pIBSSParms = (PWLAN_IE_IBSS_PARMS)pItem;
+ break;
+ case WLAN_EID_TIM:
+ if (pFrame->pTIM == NULL)
+ pFrame->pTIM = (PWLAN_IE_TIM)pItem;
+ break;
+
+ case WLAN_EID_RSN:
+ if (pFrame->pRSN == NULL)
+ pFrame->pRSN = (PWLAN_IE_RSN)pItem;
+ break;
+ case WLAN_EID_RSN_WPA:
+ if (pFrame->pRSNWPA == NULL) {
+ if (WPAb_Is_RSN((PWLAN_IE_RSN_EXT)pItem) == TRUE)
+ pFrame->pRSNWPA = (PWLAN_IE_RSN_EXT)pItem;
+ }
+ break;
+
+ case WLAN_EID_ERP:
+ if (pFrame->pERP == NULL)
+ pFrame->pERP = (PWLAN_IE_ERP)pItem;
+ break;
+ case WLAN_EID_EXTSUPP_RATES:
+ if (pFrame->pExtSuppRates == NULL)
+ pFrame->pExtSuppRates = (PWLAN_IE_SUPP_RATES)pItem;
+ break;
+
+ case WLAN_EID_COUNTRY: /* 7 */
+ if (pFrame->pIE_Country == NULL)
+ pFrame->pIE_Country = (PWLAN_IE_COUNTRY)pItem;
+ break;
+
+ case WLAN_EID_PWR_CONSTRAINT: /* 32 */
+ if (pFrame->pIE_PowerConstraint == NULL)
+ pFrame->pIE_PowerConstraint = (PWLAN_IE_PW_CONST)pItem;
+ break;
+
+ case WLAN_EID_CH_SWITCH: /* 37 */
+ if (pFrame->pIE_CHSW == NULL)
+ pFrame->pIE_CHSW = (PWLAN_IE_CH_SW)pItem;
+ break;
+
+ case WLAN_EID_QUIET: /* 40 */
+ if (pFrame->pIE_Quiet == NULL)
+ pFrame->pIE_Quiet = (PWLAN_IE_QUIET)pItem;
+ break;
+
+ case WLAN_EID_IBSS_DFS:
+ if (pFrame->pIE_IBSSDFS == NULL)
+ pFrame->pIE_IBSSDFS = (PWLAN_IE_IBSS_DFS)pItem;
+ break;
+
+ default:
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Unrecognized EID=%dd in beacon decode.\n", pItem->byElementID);
break;
}
@@ -295,7 +294,7 @@ vMgrEncodeDisassociation(
pFrame->pHdr = (PUWLAN_80211HDR)pFrame->pBuf;
- // Fixed Fields
+ /* Fixed Fields */
pFrame->pwReason = (PWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ WLAN_DISASSOC_OFF_REASON);
pFrame->len = WLAN_HDR_ADDR3_LEN + WLAN_DISASSOC_OFF_REASON + sizeof(*(pFrame->pwReason));
@@ -322,7 +321,7 @@ vMgrDecodeDisassociation(
{
pFrame->pHdr = (PUWLAN_80211HDR)pFrame->pBuf;
- // Fixed Fields
+ /* Fixed Fields */
pFrame->pwReason = (PWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ WLAN_DISASSOC_OFF_REASON);
@@ -347,7 +346,7 @@ vMgrEncodeAssocRequest(
)
{
pFrame->pHdr = (PUWLAN_80211HDR)pFrame->pBuf;
- // Fixed Fields
+ /* Fixed Fields */
pFrame->pwCapInfo = (PWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ WLAN_ASSOCREQ_OFF_CAP_INFO);
pFrame->pwListenInterval = (PWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
@@ -376,47 +375,46 @@ vMgrDecodeAssocRequest(
PWLAN_IE pItem;
pFrame->pHdr = (PUWLAN_80211HDR)pFrame->pBuf;
- // Fixed Fields
+ /* Fixed Fields */
pFrame->pwCapInfo = (PWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ WLAN_ASSOCREQ_OFF_CAP_INFO);
pFrame->pwListenInterval = (PWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ WLAN_ASSOCREQ_OFF_LISTEN_INT);
- // Information elements
+ /* Information elements */
pItem = (PWLAN_IE)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ WLAN_ASSOCREQ_OFF_SSID);
while (((PBYTE)pItem) < (pFrame->pBuf + pFrame->len)) {
- switch (pItem->byElementID){
- case WLAN_EID_SSID:
- if (pFrame->pSSID == NULL)
- pFrame->pSSID = (PWLAN_IE_SSID)pItem;
- break;
- case WLAN_EID_SUPP_RATES:
- if (pFrame->pSuppRates == NULL)
- pFrame->pSuppRates = (PWLAN_IE_SUPP_RATES)pItem;
- break;
-
- case WLAN_EID_RSN:
- if (pFrame->pRSN == NULL) {
- pFrame->pRSN = (PWLAN_IE_RSN)pItem;
- }
- break;
- case WLAN_EID_RSN_WPA:
- if (pFrame->pRSNWPA == NULL) {
- if (WPAb_Is_RSN((PWLAN_IE_RSN_EXT)pItem) == TRUE)
- pFrame->pRSNWPA = (PWLAN_IE_RSN_EXT)pItem;
- }
- break;
- case WLAN_EID_EXTSUPP_RATES:
- if (pFrame->pExtSuppRates == NULL)
- pFrame->pExtSuppRates = (PWLAN_IE_SUPP_RATES)pItem;
- break;
-
- default:
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Unrecognized EID=%dd in assocreq decode.\n",
- pItem->byElementID);
- break;
+ switch (pItem->byElementID) {
+ case WLAN_EID_SSID:
+ if (pFrame->pSSID == NULL)
+ pFrame->pSSID = (PWLAN_IE_SSID)pItem;
+ break;
+ case WLAN_EID_SUPP_RATES:
+ if (pFrame->pSuppRates == NULL)
+ pFrame->pSuppRates = (PWLAN_IE_SUPP_RATES)pItem;
+ break;
+
+ case WLAN_EID_RSN:
+ if (pFrame->pRSN == NULL)
+ pFrame->pRSN = (PWLAN_IE_RSN)pItem;
+ break;
+ case WLAN_EID_RSN_WPA:
+ if (pFrame->pRSNWPA == NULL) {
+ if (WPAb_Is_RSN((PWLAN_IE_RSN_EXT)pItem) == TRUE)
+ pFrame->pRSNWPA = (PWLAN_IE_RSN_EXT)pItem;
+ }
+ break;
+ case WLAN_EID_EXTSUPP_RATES:
+ if (pFrame->pExtSuppRates == NULL)
+ pFrame->pExtSuppRates = (PWLAN_IE_SUPP_RATES)pItem;
+ break;
+
+ default:
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Unrecognized EID=%dd in assocreq decode.\n",
+ pItem->byElementID);
+ break;
}
pItem = (PWLAN_IE)(((PBYTE)pItem) + 2 + pItem->len);
}
@@ -441,7 +439,7 @@ vMgrEncodeAssocResponse(
{
pFrame->pHdr = (PUWLAN_80211HDR)pFrame->pBuf;
- // Fixed Fields
+ /* Fixed Fields */
pFrame->pwCapInfo = (PWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ WLAN_ASSOCRESP_OFF_CAP_INFO);
pFrame->pwStatus = (PWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
@@ -475,7 +473,7 @@ vMgrDecodeAssocResponse(
pFrame->pHdr = (PUWLAN_80211HDR)pFrame->pBuf;
- // Fixed Fields
+ /* Fixed Fields */
pFrame->pwCapInfo = (PWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ WLAN_ASSOCRESP_OFF_CAP_INFO);
pFrame->pwStatus = (PWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
@@ -483,7 +481,7 @@ vMgrDecodeAssocResponse(
pFrame->pwAid = (PWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ WLAN_ASSOCRESP_OFF_AID);
- // Information elements
+ /* Information elements */
pFrame->pSuppRates = (PWLAN_IE_SUPP_RATES)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ WLAN_ASSOCRESP_OFF_SUPP_RATES);
@@ -493,8 +491,7 @@ vMgrDecodeAssocResponse(
if ((((PBYTE)pItem) < (pFrame->pBuf + pFrame->len)) && (pItem->byElementID == WLAN_EID_EXTSUPP_RATES)) {
pFrame->pExtSuppRates = (PWLAN_IE_SUPP_RATES)pItem;
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "pFrame->pExtSuppRates=[%p].\n", pItem);
- }
- else {
+ } else {
pFrame->pExtSuppRates = NULL;
}
return;
@@ -519,7 +516,7 @@ vMgrEncodeReassocRequest(
{
pFrame->pHdr = (PUWLAN_80211HDR)pFrame->pBuf;
- // Fixed Fields
+ /* Fixed Fields */
pFrame->pwCapInfo = (PWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ WLAN_REASSOCREQ_OFF_CAP_INFO);
pFrame->pwListenInterval = (PWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
@@ -552,7 +549,7 @@ vMgrDecodeReassocRequest(
PWLAN_IE pItem;
pFrame->pHdr = (PUWLAN_80211HDR)pFrame->pBuf;
- // Fixed Fields
+ /* Fixed Fields */
pFrame->pwCapInfo = (PWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ WLAN_REASSOCREQ_OFF_CAP_INFO);
pFrame->pwListenInterval = (PWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
@@ -560,42 +557,41 @@ vMgrDecodeReassocRequest(
pFrame->pAddrCurrAP = (PIEEE_ADDR)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ WLAN_REASSOCREQ_OFF_CURR_AP);
- // Information elements
+ /* Information elements */
pItem = (PWLAN_IE)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ WLAN_REASSOCREQ_OFF_SSID);
- while(((PBYTE)pItem) < (pFrame->pBuf + pFrame->len)) {
-
- switch (pItem->byElementID){
- case WLAN_EID_SSID:
- if (pFrame->pSSID == NULL)
- pFrame->pSSID = (PWLAN_IE_SSID)pItem;
- break;
- case WLAN_EID_SUPP_RATES:
- if (pFrame->pSuppRates == NULL)
- pFrame->pSuppRates = (PWLAN_IE_SUPP_RATES)pItem;
- break;
-
- case WLAN_EID_RSN:
- if (pFrame->pRSN == NULL) {
- pFrame->pRSN = (PWLAN_IE_RSN)pItem;
- }
- break;
- case WLAN_EID_RSN_WPA:
- if (pFrame->pRSNWPA == NULL) {
- if (WPAb_Is_RSN((PWLAN_IE_RSN_EXT)pItem) == TRUE)
- pFrame->pRSNWPA = (PWLAN_IE_RSN_EXT)pItem;
- }
- break;
+ while (((PBYTE)pItem) < (pFrame->pBuf + pFrame->len)) {
- case WLAN_EID_EXTSUPP_RATES:
- if (pFrame->pExtSuppRates == NULL)
- pFrame->pExtSuppRates = (PWLAN_IE_SUPP_RATES)pItem;
- break;
- default:
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Unrecognized EID=%dd in reassocreq decode.\n",
- pItem->byElementID);
- break;
+ switch (pItem->byElementID) {
+ case WLAN_EID_SSID:
+ if (pFrame->pSSID == NULL)
+ pFrame->pSSID = (PWLAN_IE_SSID)pItem;
+ break;
+ case WLAN_EID_SUPP_RATES:
+ if (pFrame->pSuppRates == NULL)
+ pFrame->pSuppRates = (PWLAN_IE_SUPP_RATES)pItem;
+ break;
+
+ case WLAN_EID_RSN:
+ if (pFrame->pRSN == NULL)
+ pFrame->pRSN = (PWLAN_IE_RSN)pItem;
+ break;
+ case WLAN_EID_RSN_WPA:
+ if (pFrame->pRSNWPA == NULL) {
+ if (WPAb_Is_RSN((PWLAN_IE_RSN_EXT)pItem) == TRUE)
+ pFrame->pRSNWPA = (PWLAN_IE_RSN_EXT)pItem;
+ }
+ break;
+
+ case WLAN_EID_EXTSUPP_RATES:
+ if (pFrame->pExtSuppRates == NULL)
+ pFrame->pExtSuppRates = (PWLAN_IE_SUPP_RATES)pItem;
+ break;
+ default:
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Unrecognized EID=%dd in reassocreq decode.\n",
+ pItem->byElementID);
+ break;
}
pItem = (PWLAN_IE)(((PBYTE)pItem) + 2 + pItem->len);
}
@@ -646,30 +642,30 @@ vMgrDecodeProbeRequest(
pFrame->pHdr = (PUWLAN_80211HDR)pFrame->pBuf;
- // Information elements
+ /* Information elements */
pItem = (PWLAN_IE)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3)));
- while( ((PBYTE)pItem) < (pFrame->pBuf + pFrame->len) ) {
+ while (((PBYTE)pItem) < (pFrame->pBuf + pFrame->len)) {
switch (pItem->byElementID) {
- case WLAN_EID_SSID:
- if (pFrame->pSSID == NULL)
- pFrame->pSSID = (PWLAN_IE_SSID)pItem;
- break;
+ case WLAN_EID_SSID:
+ if (pFrame->pSSID == NULL)
+ pFrame->pSSID = (PWLAN_IE_SSID)pItem;
+ break;
- case WLAN_EID_SUPP_RATES:
- if (pFrame->pSuppRates == NULL)
- pFrame->pSuppRates = (PWLAN_IE_SUPP_RATES)pItem;
- break;
+ case WLAN_EID_SUPP_RATES:
+ if (pFrame->pSuppRates == NULL)
+ pFrame->pSuppRates = (PWLAN_IE_SUPP_RATES)pItem;
+ break;
- case WLAN_EID_EXTSUPP_RATES:
- if (pFrame->pExtSuppRates == NULL)
- pFrame->pExtSuppRates = (PWLAN_IE_SUPP_RATES)pItem;
- break;
+ case WLAN_EID_EXTSUPP_RATES:
+ if (pFrame->pExtSuppRates == NULL)
+ pFrame->pExtSuppRates = (PWLAN_IE_SUPP_RATES)pItem;
+ break;
- default:
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Bad EID=%dd in probereq\n", pItem->byElementID);
- break;
+ default:
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Bad EID=%dd in probereq\n", pItem->byElementID);
+ break;
}
pItem = (PWLAN_IE)(((PBYTE)pItem) + 2 + pItem->len);
@@ -697,7 +693,7 @@ vMgrEncodeProbeResponse(
{
pFrame->pHdr = (PUWLAN_80211HDR)pFrame->pBuf;
- // Fixed Fields
+ /* Fixed Fields */
pFrame->pqwTimestamp = (PQWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ WLAN_PROBERESP_OFF_TS);
pFrame->pwBeaconInterval = (PWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
@@ -734,7 +730,7 @@ vMgrDecodeProbeResponse(
pFrame->pHdr = (PUWLAN_80211HDR)pFrame->pBuf;
- // Fixed Fields
+ /* Fixed Fields */
pFrame->pqwTimestamp = (PQWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ WLAN_PROBERESP_OFF_TS);
pFrame->pwBeaconInterval = (PWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
@@ -742,83 +738,82 @@ vMgrDecodeProbeResponse(
pFrame->pwCapInfo = (PWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ WLAN_PROBERESP_OFF_CAP_INFO);
- // Information elements
+ /* Information elements */
pItem = (PWLAN_IE)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ WLAN_PROBERESP_OFF_SSID);
- while( ((PBYTE)pItem) < (pFrame->pBuf + pFrame->len) ) {
+ while (((PBYTE)pItem) < (pFrame->pBuf + pFrame->len)) {
switch (pItem->byElementID) {
- case WLAN_EID_SSID:
- if (pFrame->pSSID == NULL)
+ case WLAN_EID_SSID:
+ if (pFrame->pSSID == NULL)
pFrame->pSSID = (PWLAN_IE_SSID)pItem;
- break;
- case WLAN_EID_SUPP_RATES:
- if (pFrame->pSuppRates == NULL)
+ break;
+ case WLAN_EID_SUPP_RATES:
+ if (pFrame->pSuppRates == NULL)
pFrame->pSuppRates = (PWLAN_IE_SUPP_RATES)pItem;
- break;
- case WLAN_EID_FH_PARMS:
- break;
- case WLAN_EID_DS_PARMS:
- if (pFrame->pDSParms == NULL)
- pFrame->pDSParms = (PWLAN_IE_DS_PARMS)pItem;
- break;
- case WLAN_EID_CF_PARMS:
- if (pFrame->pCFParms == NULL)
- pFrame->pCFParms = (PWLAN_IE_CF_PARMS)pItem;
- break;
- case WLAN_EID_IBSS_PARMS:
- if (pFrame->pIBSSParms == NULL)
- pFrame->pIBSSParms = (PWLAN_IE_IBSS_PARMS)pItem;
- break;
-
- case WLAN_EID_RSN:
- if (pFrame->pRSN == NULL) {
- pFrame->pRSN = (PWLAN_IE_RSN)pItem;
- }
- break;
- case WLAN_EID_RSN_WPA:
- if (pFrame->pRSNWPA == NULL) {
- if (WPAb_Is_RSN((PWLAN_IE_RSN_EXT)pItem) == TRUE)
- pFrame->pRSNWPA = (PWLAN_IE_RSN_EXT)pItem;
- }
- break;
- case WLAN_EID_ERP:
- if (pFrame->pERP == NULL)
- pFrame->pERP = (PWLAN_IE_ERP)pItem;
- break;
- case WLAN_EID_EXTSUPP_RATES:
- if (pFrame->pExtSuppRates == NULL)
- pFrame->pExtSuppRates = (PWLAN_IE_SUPP_RATES)pItem;
- break;
-
- case WLAN_EID_COUNTRY: //7
- if (pFrame->pIE_Country == NULL)
- pFrame->pIE_Country = (PWLAN_IE_COUNTRY)pItem;
- break;
-
- case WLAN_EID_PWR_CONSTRAINT: //32
- if (pFrame->pIE_PowerConstraint == NULL)
- pFrame->pIE_PowerConstraint = (PWLAN_IE_PW_CONST)pItem;
- break;
-
- case WLAN_EID_CH_SWITCH: //37
- if (pFrame->pIE_CHSW == NULL)
- pFrame->pIE_CHSW = (PWLAN_IE_CH_SW)pItem;
- break;
-
- case WLAN_EID_QUIET: //40
- if (pFrame->pIE_Quiet == NULL)
- pFrame->pIE_Quiet = (PWLAN_IE_QUIET)pItem;
- break;
-
- case WLAN_EID_IBSS_DFS:
- if (pFrame->pIE_IBSSDFS == NULL)
- pFrame->pIE_IBSSDFS = (PWLAN_IE_IBSS_DFS)pItem;
- break;
-
- default:
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Bad EID=%dd in proberesp\n", pItem->byElementID);
- break;
+ break;
+ case WLAN_EID_FH_PARMS:
+ break;
+ case WLAN_EID_DS_PARMS:
+ if (pFrame->pDSParms == NULL)
+ pFrame->pDSParms = (PWLAN_IE_DS_PARMS)pItem;
+ break;
+ case WLAN_EID_CF_PARMS:
+ if (pFrame->pCFParms == NULL)
+ pFrame->pCFParms = (PWLAN_IE_CF_PARMS)pItem;
+ break;
+ case WLAN_EID_IBSS_PARMS:
+ if (pFrame->pIBSSParms == NULL)
+ pFrame->pIBSSParms = (PWLAN_IE_IBSS_PARMS)pItem;
+ break;
+
+ case WLAN_EID_RSN:
+ if (pFrame->pRSN == NULL)
+ pFrame->pRSN = (PWLAN_IE_RSN)pItem;
+ break;
+ case WLAN_EID_RSN_WPA:
+ if (pFrame->pRSNWPA == NULL) {
+ if (WPAb_Is_RSN((PWLAN_IE_RSN_EXT)pItem) == TRUE)
+ pFrame->pRSNWPA = (PWLAN_IE_RSN_EXT)pItem;
+ }
+ break;
+ case WLAN_EID_ERP:
+ if (pFrame->pERP == NULL)
+ pFrame->pERP = (PWLAN_IE_ERP)pItem;
+ break;
+ case WLAN_EID_EXTSUPP_RATES:
+ if (pFrame->pExtSuppRates == NULL)
+ pFrame->pExtSuppRates = (PWLAN_IE_SUPP_RATES)pItem;
+ break;
+
+ case WLAN_EID_COUNTRY: /* 7 */
+ if (pFrame->pIE_Country == NULL)
+ pFrame->pIE_Country = (PWLAN_IE_COUNTRY)pItem;
+ break;
+
+ case WLAN_EID_PWR_CONSTRAINT: /* 32 */
+ if (pFrame->pIE_PowerConstraint == NULL)
+ pFrame->pIE_PowerConstraint = (PWLAN_IE_PW_CONST)pItem;
+ break;
+
+ case WLAN_EID_CH_SWITCH: /* 37 */
+ if (pFrame->pIE_CHSW == NULL)
+ pFrame->pIE_CHSW = (PWLAN_IE_CH_SW)pItem;
+ break;
+
+ case WLAN_EID_QUIET: /* 40 */
+ if (pFrame->pIE_Quiet == NULL)
+ pFrame->pIE_Quiet = (PWLAN_IE_QUIET)pItem;
+ break;
+
+ case WLAN_EID_IBSS_DFS:
+ if (pFrame->pIE_IBSSDFS == NULL)
+ pFrame->pIE_IBSSDFS = (PWLAN_IE_IBSS_DFS)pItem;
+ break;
+
+ default:
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Bad EID=%dd in proberesp\n", pItem->byElementID);
+ break;
}
pItem = (PWLAN_IE)(((PBYTE)pItem) + 2 + pItem->len);
@@ -845,7 +840,7 @@ vMgrEncodeAuthen(
{
pFrame->pHdr = (PUWLAN_80211HDR)pFrame->pBuf;
- // Fixed Fields
+ /* Fixed Fields */
pFrame->pwAuthAlgorithm = (PWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ WLAN_AUTHEN_OFF_AUTH_ALG);
pFrame->pwAuthSequence = (PWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
@@ -853,7 +848,6 @@ vMgrEncodeAuthen(
pFrame->pwStatus = (PWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ WLAN_AUTHEN_OFF_STATUS);
pFrame->len = WLAN_HDR_ADDR3_LEN + WLAN_AUTHEN_OFF_STATUS + sizeof(*(pFrame->pwStatus));
-
return;
}
@@ -878,7 +872,7 @@ vMgrDecodeAuthen(
pFrame->pHdr = (PUWLAN_80211HDR)pFrame->pBuf;
- // Fixed Fields
+ /* Fixed Fields */
pFrame->pwAuthAlgorithm = (PWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ WLAN_AUTHEN_OFF_AUTH_ALG);
pFrame->pwAuthSequence = (PWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
@@ -886,14 +880,12 @@ vMgrDecodeAuthen(
pFrame->pwStatus = (PWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ WLAN_AUTHEN_OFF_STATUS);
- // Information elements
+ /* Information elements */
pItem = (PWLAN_IE)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ WLAN_AUTHEN_OFF_CHALLENGE);
- if ((((PBYTE)pItem) < (pFrame->pBuf + pFrame->len)) && (pItem->byElementID == WLAN_EID_CHALLENGE)) {
+ if ((((PBYTE)pItem) < (pFrame->pBuf + pFrame->len)) && (pItem->byElementID == WLAN_EID_CHALLENGE))
pFrame->pChallenge = (PWLAN_IE_CHALLENGE)pItem;
- }
-
return;
}
@@ -916,11 +908,10 @@ vMgrEncodeDeauthen(
{
pFrame->pHdr = (PUWLAN_80211HDR)pFrame->pBuf;
- // Fixed Fields
+ /* Fixed Fields */
pFrame->pwReason = (PWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ WLAN_DEAUTHEN_OFF_REASON);
pFrame->len = WLAN_HDR_ADDR3_LEN + WLAN_DEAUTHEN_OFF_REASON + sizeof(*(pFrame->pwReason));
-
return;
}
@@ -943,10 +934,9 @@ vMgrDecodeDeauthen(
{
pFrame->pHdr = (PUWLAN_80211HDR)pFrame->pBuf;
- // Fixed Fields
+ /* Fixed Fields */
pFrame->pwReason = (PWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ WLAN_DEAUTHEN_OFF_REASON);
-
return;
}
@@ -969,7 +959,7 @@ vMgrEncodeReassocResponse(
{
pFrame->pHdr = (PUWLAN_80211HDR)pFrame->pBuf;
- // Fixed Fields
+ /* Fixed Fields */
pFrame->pwCapInfo = (PWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ WLAN_REASSOCRESP_OFF_CAP_INFO);
pFrame->pwStatus = (PWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
@@ -978,7 +968,6 @@ vMgrEncodeReassocResponse(
+ WLAN_REASSOCRESP_OFF_AID);
pFrame->len = WLAN_HDR_ADDR3_LEN + WLAN_REASSOCRESP_OFF_AID + sizeof(*(pFrame->pwAid));
-
return;
}
@@ -1004,7 +993,7 @@ vMgrDecodeReassocResponse(
pFrame->pHdr = (PUWLAN_80211HDR)pFrame->pBuf;
- // Fixed Fields
+ /* Fixed Fields */
pFrame->pwCapInfo = (PWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ WLAN_REASSOCRESP_OFF_CAP_INFO);
pFrame->pwStatus = (PWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
@@ -1012,15 +1001,14 @@ vMgrDecodeReassocResponse(
pFrame->pwAid = (PWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ WLAN_REASSOCRESP_OFF_AID);
- //Information elements
+ /* Information elements */
pFrame->pSuppRates = (PWLAN_IE_SUPP_RATES)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ WLAN_REASSOCRESP_OFF_SUPP_RATES);
pItem = (PWLAN_IE)(pFrame->pSuppRates);
pItem = (PWLAN_IE)(((PBYTE)pItem) + 2 + pItem->len);
- if ((((PBYTE)pItem) < (pFrame->pBuf + pFrame->len)) && (pItem->byElementID == WLAN_EID_EXTSUPP_RATES)) {
+ if ((((PBYTE)pItem) < (pFrame->pBuf + pFrame->len)) && (pItem->byElementID == WLAN_EID_EXTSUPP_RATES))
pFrame->pExtSuppRates = (PWLAN_IE_SUPP_RATES)pItem;
- }
return;
}
diff --git a/drivers/staging/vt6656/80211mgr.h b/drivers/staging/vt6656/80211mgr.h
index c140a957d9d..3d57f793986 100644
--- a/drivers/staging/vt6656/80211mgr.h
+++ b/drivers/staging/vt6656/80211mgr.h
@@ -19,7 +19,7 @@
*
* File: 80211mgr.h
*
- * Purpose: 802.11 managment frames pre-defines.
+ * Purpose: 802.11 management frames pre-defines.
*
*
* Author: Lyndon Chen
@@ -222,46 +222,39 @@
#define MEASURE_MODE_INCAPABLE 0x02
#define MEASURE_MODE_REFUSED 0x04
-
-
/*--------------------- Export Classes ----------------------------*/
/*--------------------- Export Variables --------------------------*/
/*--------------------- Export Types ------------------------------*/
-
// Information Element Types
#pragma pack(1)
typedef struct tagWLAN_IE {
BYTE byElementID;
BYTE len;
-}__attribute__ ((__packed__))
+} __attribute__ ((__packed__))
WLAN_IE, *PWLAN_IE;
-
// Service Set Identity (SSID)
#pragma pack(1)
typedef struct tagWLAN_IE_SSID {
BYTE byElementID;
BYTE len;
BYTE abySSID[1];
-}__attribute__ ((__packed__))
+} __attribute__ ((__packed__))
WLAN_IE_SSID, *PWLAN_IE_SSID;
-
// Supported Rates
#pragma pack(1)
typedef struct tagWLAN_IE_SUPP_RATES {
BYTE byElementID;
BYTE len;
BYTE abyRates[1];
-}__attribute__ ((__packed__))
+} __attribute__ ((__packed__))
WLAN_IE_SUPP_RATES, *PWLAN_IE_SUPP_RATES;
-
-
// FH Parameter Set
#pragma pack(1)
typedef struct _WLAN_IE_FH_PARMS {
@@ -279,10 +272,9 @@ typedef struct tagWLAN_IE_DS_PARMS {
BYTE byElementID;
BYTE len;
BYTE byCurrChannel;
-}__attribute__ ((__packed__))
+} __attribute__ ((__packed__))
WLAN_IE_DS_PARMS, *PWLAN_IE_DS_PARMS;
-
// CF Parameter Set
#pragma pack(1)
typedef struct tagWLAN_IE_CF_PARMS {
@@ -292,10 +284,9 @@ typedef struct tagWLAN_IE_CF_PARMS {
BYTE byCFPPeriod;
WORD wCFPMaxDuration;
WORD wCFPDurRemaining;
-}__attribute__ ((__packed__))
+} __attribute__ ((__packed__))
WLAN_IE_CF_PARMS, *PWLAN_IE_CF_PARMS;
-
// TIM
#pragma pack(1)
typedef struct tagWLAN_IE_TIM {
@@ -305,30 +296,27 @@ typedef struct tagWLAN_IE_TIM {
BYTE byDTIMPeriod;
BYTE byBitMapCtl;
BYTE byVirtBitMap[1];
-}__attribute__ ((__packed__))
+} __attribute__ ((__packed__))
WLAN_IE_TIM, *PWLAN_IE_TIM;
-
// IBSS Parameter Set
#pragma pack(1)
typedef struct tagWLAN_IE_IBSS_PARMS {
BYTE byElementID;
BYTE len;
WORD wATIMWindow;
-}__attribute__ ((__packed__))
+} __attribute__ ((__packed__))
WLAN_IE_IBSS_PARMS, *PWLAN_IE_IBSS_PARMS;
-
// Challenge Text
#pragma pack(1)
typedef struct tagWLAN_IE_CHALLENGE {
BYTE byElementID;
BYTE len;
BYTE abyChallenge[1];
-}__attribute__ ((__packed__))
+} __attribute__ ((__packed__))
WLAN_IE_CHALLENGE, *PWLAN_IE_CHALLENGE;
-
#pragma pack(1)
typedef struct tagWLAN_IE_RSN_EXT {
BYTE byElementID;
@@ -391,10 +379,9 @@ typedef struct tagWLAN_IE_ERP {
BYTE byElementID;
BYTE len;
BYTE byContext;
-}__attribute__ ((__packed__))
+} __attribute__ ((__packed__))
WLAN_IE_ERP, *PWLAN_IE_ERP;
-
#pragma pack(1)
typedef struct _MEASEURE_REQ {
BYTE byChannel;
diff --git a/drivers/staging/vt6656/aes_ccmp.c b/drivers/staging/vt6656/aes_ccmp.c
index b3d367b9bdc..f7a3b8f8da7 100644
--- a/drivers/staging/vt6656/aes_ccmp.c
+++ b/drivers/staging/vt6656/aes_ccmp.c
@@ -106,7 +106,7 @@ BYTE dot3_table[256] = {
/*--------------------- Export Functions --------------------------*/
-void xor_128(BYTE *a, BYTE *b, BYTE *out)
+static void xor_128(BYTE *a, BYTE *b, BYTE *out)
{
PDWORD dwPtrA = (PDWORD) a;
PDWORD dwPtrB = (PDWORD) b;
@@ -119,7 +119,7 @@ void xor_128(BYTE *a, BYTE *b, BYTE *out)
}
-void xor_32(BYTE *a, BYTE *b, BYTE *out)
+static void xor_32(BYTE *a, BYTE *b, BYTE *out)
{
PDWORD dwPtrA = (PDWORD) a;
PDWORD dwPtrB = (PDWORD) b;
diff --git a/drivers/staging/vt6656/baseband.c b/drivers/staging/vt6656/baseband.c
index d3de94f36c6..29902492975 100644
--- a/drivers/staging/vt6656/baseband.c
+++ b/drivers/staging/vt6656/baseband.c
@@ -989,10 +989,10 @@ BBvSetAntennaMode (PSDevice pDevice, BYTE byAntennaMode)
* Return Value: none
*
*/
-BOOL
-BBbVT3184Init (PSDevice pDevice)
+
+BOOL BBbVT3184Init(PSDevice pDevice)
{
- NTSTATUS ntStatus;
+ int ntStatus;
WORD wLength;
PBYTE pbyAddr;
PBYTE pbyAgc;
diff --git a/drivers/staging/vt6656/baseband.h b/drivers/staging/vt6656/baseband.h
index bc4633d5fea..8db8cd07d5f 100644
--- a/drivers/staging/vt6656/baseband.h
+++ b/drivers/staging/vt6656/baseband.h
@@ -104,16 +104,13 @@ BBuGetFrameTime(
WORD wRate
);
-void
-BBvCaculateParameter (
- PSDevice pDevice,
- unsigned int cbFrameLength,
- WORD wRate,
- BYTE byPacketType,
- PWORD pwPhyLen,
- PBYTE pbyPhySrv,
- PBYTE pbyPhySgn
- );
+void BBvCaculateParameter(PSDevice pDevice,
+ unsigned int cbFrameLength,
+ WORD wRate,
+ BYTE byPacketType,
+ PWORD pwPhyLen,
+ PBYTE pbyPhySrv,
+ PBYTE pbyPhySgn);
// timer for antenna diversity
@@ -128,7 +125,7 @@ void BBvSoftwareReset(PSDevice pDevice);
void BBvSetShortSlotTime(PSDevice pDevice);
void BBvSetVGAGainOffset(PSDevice pDevice, BYTE byData);
void BBvSetAntennaMode(PSDevice pDevice, BYTE byAntennaMode);
-BOOL BBbVT3184Init (PSDevice pDevice);
+BOOL BBbVT3184Init(PSDevice pDevice);
void BBvSetDeepSleep(PSDevice pDevice);
void BBvExitDeepSleep(PSDevice pDevice);
void BBvUpdatePreEDThreshold(
diff --git a/drivers/staging/vt6656/bssdb.c b/drivers/staging/vt6656/bssdb.c
index 36ed61b595c..a9f68bd5afa 100644
--- a/drivers/staging/vt6656/bssdb.c
+++ b/drivers/staging/vt6656/bssdb.c
@@ -93,10 +93,7 @@ const WORD awHWRetry1[5][5] = {
void s_vCheckSensitivity(void *hDeviceContext);
void s_vCheckPreEDThreshold(void *hDeviceContext);
-
-#ifdef Calcu_LinkQual
void s_uCalculateLinkQual(void *hDeviceContext);
-#endif
/*--------------------- Export Variables --------------------------*/
@@ -135,7 +132,7 @@ PKnownBSS BSSpSearchBSSList(void *hDeviceContext,
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"BSSpSearchBSSList BSSID[%02X %02X %02X-%02X %02X %02X]\n",
*pbyDesireBSSID,*(pbyDesireBSSID+1),*(pbyDesireBSSID+2),
*(pbyDesireBSSID+3),*(pbyDesireBSSID+4),*(pbyDesireBSSID+5));
- if ((!IS_BROADCAST_ADDRESS(pbyDesireBSSID)) &&
+ if ((!is_broadcast_ether_addr(pbyDesireBSSID)) &&
(memcmp(pbyDesireBSSID, ZeroBSSID, 6)!= 0)){
pbyBSSID = pbyDesireBSSID;
}
@@ -156,7 +153,7 @@ PKnownBSS BSSpSearchBSSList(void *hDeviceContext,
if ((pCurrBSS->bActive) &&
(pCurrBSS->bSelected == FALSE)) {
- if (IS_ETH_ADDRESS_EQUAL(pCurrBSS->abyBSSID, pbyBSSID)) {
+ if (!compare_ether_addr(pCurrBSS->abyBSSID, pbyBSSID)) {
if (pSSID != NULL) {
// compare ssid
if ( !memcmp(pSSID->abySSID,
@@ -296,7 +293,8 @@ void BSSvClearBSSList(void *hDeviceContext, BOOL bKeepCurrBSSID)
for (ii = 0; ii < MAX_BSS_NUM; ii++) {
if (bKeepCurrBSSID) {
if (pMgmt->sBSSList[ii].bActive &&
- IS_ETH_ADDRESS_EQUAL(pMgmt->sBSSList[ii].abyBSSID, pMgmt->abyCurrBSSID)) {
+ !compare_ether_addr(pMgmt->sBSSList[ii].abyBSSID,
+ pMgmt->abyCurrBSSID)) {
//mike mark: there are two same BSSID in list if that AP is in hidden ssid mode,one 's SSID is null,
// but other's is obvious, so if it acssociate with your STA exactly,you must keep two
// of them!!!!!!!!!
@@ -341,7 +339,7 @@ PKnownBSS BSSpAddrIsInBSSList(void *hDeviceContext,
for (ii = 0; ii < MAX_BSS_NUM; ii++) {
pBSSList = &(pMgmt->sBSSList[ii]);
if (pBSSList->bActive) {
- if (IS_ETH_ADDRESS_EQUAL(pBSSList->abyBSSID, abyBSSID)) {
+ if (!compare_ether_addr(pBSSList->abyBSSID, abyBSSID)) {
if (pSSID->len == ((PWLAN_IE_SSID)pBSSList->abySSID)->len){
if (memcmp(pSSID->abySSID,
((PWLAN_IE_SSID)pBSSList->abySSID)->abySSID,
@@ -699,12 +697,14 @@ BOOL BSSbUpdateToBSSList(void *hDeviceContext,
pBSSList->byRSSIStatCnt %= RSSI_STAT_COUNT;
pBSSList->ldBmAverage[pBSSList->byRSSIStatCnt] = ldBm;
ldBmSum = 0;
- for(ii=0, jj=0;ii<RSSI_STAT_COUNT;ii++) {
- if (pBSSList->ldBmAverage[ii] != 0) {
- pBSSList->ldBmMAX = max(pBSSList->ldBmAverage[ii], ldBm);
- ldBmSum += pBSSList->ldBmAverage[ii];
- jj++;
- }
+ for (ii = 0, jj = 0; ii < RSSI_STAT_COUNT; ii++) {
+ if (pBSSList->ldBmAverage[ii] != 0) {
+ pBSSList->ldBmMAX =
+ max(pBSSList->ldBmAverage[ii], ldBm);
+ ldBmSum +=
+ pBSSList->ldBmAverage[ii];
+ jj++;
+ }
}
pBSSList->ldBmAverRange = ldBmSum /jj;
}
@@ -714,28 +714,6 @@ BOOL BSSbUpdateToBSSList(void *hDeviceContext,
pBSSList->uIELength = WLAN_BEACON_FR_MAXLEN;
memcpy(pBSSList->abyIEs, pbyIEs, pBSSList->uIELength);
-//mike add: if the AP in this pBSSList is hidden ssid and we can find two of them,
-// you need upgrade the other related pBSSList of which ssid is obvious,
-// for these two AP is the same one!!!!
-/********judge by:BSSID is the same,but ssid is different!*****************/
-#if 0
- for (ii = 0; ii < MAX_BSS_NUM; ii++) {
- if (IS_ETH_ADDRESS_EQUAL(pMgmt->sBSSList[ii].abyBSSID, pBSSList->abyBSSID)) { //BSSID is the same!
- if (memcmp(((PWLAN_IE_SSID)pMgmt->sBSSList[ii].abySSID)->abySSID, //ssid is different??
- ((PWLAN_IE_SSID)pBSSList->abySSID)->abySSID,
- ((PWLAN_IE_SSID)pBSSList->abySSID)->len) != 0) {
- //reserve temp
- memset(abyTmpSSID,0,sizeof(abyTmpSSID));
- memcpy(abyTmpSSID,pMgmt->sBSSList[ii].abySSID,sizeof(abyTmpSSID));
- //upgrade the other one pBSSList
- memcpy(&(pMgmt->sBSSList[ii]),pBSSList,sizeof(KnownBSS));
- //recover ssid info
- memcpy(pMgmt->sBSSList[ii].abySSID,abyTmpSSID,sizeof(abyTmpSSID));
- }
- }
- }
-#endif
-
return TRUE;
}
@@ -755,7 +733,7 @@ BOOL BSSbUpdateToBSSList(void *hDeviceContext,
BOOL BSSbIsSTAInNodeDB(void *hDeviceContext,
PBYTE abyDstAddr,
- PUINT puNodeIndex)
+ unsigned int *puNodeIndex)
{
PSDevice pDevice = (PSDevice)hDeviceContext;
PSMgmtObject pMgmt = &(pDevice->sMgmtObj);
@@ -764,7 +742,8 @@ BOOL BSSbIsSTAInNodeDB(void *hDeviceContext,
// Index = 0 reserved for AP Node
for (ii = 1; ii < (MAX_NODE_NUM + 1); ii++) {
if (pMgmt->sNodeDBTable[ii].bActive) {
- if (IS_ETH_ADDRESS_EQUAL(abyDstAddr, pMgmt->sNodeDBTable[ii].abyMACAddr)) {
+ if (!compare_ether_addr(abyDstAddr,
+ pMgmt->sNodeDBTable[ii].abyMACAddr)) {
*puNodeIndex = ii;
return TRUE;
}
@@ -786,7 +765,7 @@ BOOL BSSbIsSTAInNodeDB(void *hDeviceContext,
* None
*
-*/
-void BSSvCreateOneNode(void *hDeviceContext, PUINT puNodeIndex)
+void BSSvCreateOneNode(void *hDeviceContext, unsigned int *puNodeIndex)
{
PSDevice pDevice = (PSDevice)hDeviceContext;
@@ -1023,7 +1002,6 @@ if(pDevice->byReAssocCount > 0) {
pDevice->byReAssocCount = 0;
}
-#ifdef SndEvt_ToAPI
if((pMgmt->eCurrState!=WMAC_STATE_ASSOC) &&
(pMgmt->eLastState==WMAC_STATE_ASSOC))
{
@@ -1033,11 +1011,8 @@ if((pMgmt->eCurrState!=WMAC_STATE_ASSOC) &&
wireless_send_event(pDevice->dev, IWEVCUSTOM, &wrqu, NULL);
}
pMgmt->eLastState = pMgmt->eCurrState ;
-#endif
-#ifdef Calcu_LinkQual
s_uCalculateLinkQual((void *)pDevice);
-#endif
for (ii = 0; ii < (MAX_NODE_NUM + 1); ii++) {
@@ -1422,21 +1397,25 @@ void BSSvUpdateNodeTxCounter(void *hDeviceContext,
(wRate < RATE_18M) ) {
pMgmt->sNodeDBTable[0].uTxFail[wRate]+=byTxRetry;
} else if (byFallBack == AUTO_FB_0) {
- for(ii=0;ii<byTxRetry;ii++) {
- if (ii < 5)
- wFallBackRate = awHWRetry0[wRate-RATE_18M][ii];
- else
- wFallBackRate = awHWRetry0[wRate-RATE_18M][4];
- pMgmt->sNodeDBTable[0].uTxFail[wFallBackRate]++;
- }
+ for (ii = 0; ii < byTxRetry; ii++) {
+ if (ii < 5)
+ wFallBackRate =
+ awHWRetry0[wRate-RATE_18M][ii];
+ else
+ wFallBackRate =
+ awHWRetry0[wRate-RATE_18M][4];
+ pMgmt->sNodeDBTable[0].uTxFail[wFallBackRate]++;
+ }
} else if (byFallBack == AUTO_FB_1) {
- for(ii=0;ii<byTxRetry;ii++) {
- if (ii < 5)
- wFallBackRate = awHWRetry1[wRate-RATE_18M][ii];
- else
- wFallBackRate = awHWRetry1[wRate-RATE_18M][4];
- pMgmt->sNodeDBTable[0].uTxFail[wFallBackRate]++;
- }
+ for (ii = 0; ii < byTxRetry; ii++) {
+ if (ii < 5)
+ wFallBackRate =
+ awHWRetry1[wRate-RATE_18M][ii];
+ else
+ wFallBackRate =
+ awHWRetry1[wRate-RATE_18M][4];
+ pMgmt->sNodeDBTable[0].uTxFail[wFallBackRate]++;
+ }
}
}
};
@@ -1476,21 +1455,23 @@ void BSSvUpdateNodeTxCounter(void *hDeviceContext,
(wRate < RATE_18M) ) {
pMgmt->sNodeDBTable[uNodeIndex].uTxFail[wRate]+=byTxRetry;
} else if (byFallBack == AUTO_FB_0) {
- for(ii=0;ii<byTxRetry;ii++) {
- if (ii < 5)
- wFallBackRate = awHWRetry0[wRate-RATE_18M][ii];
- else
- wFallBackRate = awHWRetry0[wRate-RATE_18M][4];
- pMgmt->sNodeDBTable[uNodeIndex].uTxFail[wFallBackRate]++;
+ for (ii = 0; ii < byTxRetry; ii++) {
+ if (ii < 5)
+ wFallBackRate =
+ awHWRetry0[wRate-RATE_18M][ii];
+ else
+ wFallBackRate =
+ awHWRetry0[wRate-RATE_18M][4];
+ pMgmt->sNodeDBTable[uNodeIndex].uTxFail[wFallBackRate]++;
}
} else if (byFallBack == AUTO_FB_1) {
- for(ii=0;ii<byTxRetry;ii++) {
- if (ii < 5)
+ for (ii = 0; ii < byTxRetry; ii++) {
+ if (ii < 5)
wFallBackRate = awHWRetry1[wRate-RATE_18M][ii];
- else
+ else
wFallBackRate = awHWRetry1[wRate-RATE_18M][4];
- pMgmt->sNodeDBTable[uNodeIndex].uTxFail[wFallBackRate]++;
- }
+ pMgmt->sNodeDBTable[uNodeIndex].uTxFail[wFallBackRate]++;
+ }
}
}
};
@@ -1587,7 +1568,6 @@ void s_vCheckSensitivity(void *hDeviceContext)
}
}
-#ifdef Calcu_LinkQual
void s_uCalculateLinkQual(void *hDeviceContext)
{
PSDevice pDevice = (PSDevice)hDeviceContext;
@@ -1632,7 +1612,6 @@ else
pDevice->scStatistic.TxRetryOkCount = 0;
return;
}
-#endif
void BSSvClearAnyBSSJoinRecord(void *hDeviceContext)
{
diff --git a/drivers/staging/vt6656/bssdb.h b/drivers/staging/vt6656/bssdb.h
index 9686d8600d6..a8f97ebb659 100644
--- a/drivers/staging/vt6656/bssdb.h
+++ b/drivers/staging/vt6656/bssdb.h
@@ -40,7 +40,7 @@
#define MAX_NODE_NUM 64
#define MAX_BSS_NUM 42
-#define LOST_BEACON_COUNT 10 // 10 sec, XP defined
+#define LOST_BEACON_COUNT 10 /* 10 sec, XP defined */
#define MAX_PS_TX_BUF 32 // sta max power saving tx buf
#define ADHOC_LOST_BEACON_COUNT 30 // 30 sec, beacon lost for adhoc only
#define MAX_INACTIVE_COUNT 300 // 300 sec, inactive STA node refresh
@@ -83,13 +83,13 @@
typedef struct tagSERPObject {
BOOL bERPExist;
BYTE byERP;
-}ERPObject, *PERPObject;
+} ERPObject, *PERPObject;
typedef struct tagSRSNCapObject {
BOOL bRSNCapExist;
WORD wRSNCap;
-}SRSNCapObject, *PSRSNCapObject;
+} SRSNCapObject, *PSRSNCapObject;
// BSS info(AP)
#pragma pack(1)
@@ -153,7 +153,7 @@ typedef struct tagKnownBSS {
SRSNCapObject sRSNCapObj;
BYTE abyIEs[1024]; // don't move this field !!
-}__attribute__ ((__packed__))
+} __attribute__ ((__packed__))
KnownBSS , *PKnownBSS;
@@ -278,9 +278,9 @@ BOOL BSSbUpdateToBSSList(void *hDeviceContext,
BOOL BSSbIsSTAInNodeDB(void *hDeviceContext,
PBYTE abyDstAddr,
- PUINT puNodeIndex);
+ unsigned int *puNodeIndex);
-void BSSvCreateOneNode(void *hDeviceContext, PUINT puNodeIndex);
+void BSSvCreateOneNode(void *hDeviceContext, unsigned int *puNodeIndex);
void BSSvUpdateAPNode(void *hDeviceContext,
PWORD pwCapInfo,
diff --git a/drivers/staging/vt6656/card.c b/drivers/staging/vt6656/card.c
index fe4ec913ffe..35bf4fda330 100644
--- a/drivers/staging/vt6656/card.c
+++ b/drivers/staging/vt6656/card.c
@@ -457,12 +457,11 @@ void CARDvSetRSPINF(void *pDeviceHandler, BYTE byBBType)
abyData[14] = abySignal[3];
abyData[15] = abyServ[3];
- for(i=0;i<9;i++) {
- abyData[16+i*2] = abyTxRate[i];
- abyData[16+i*2+1] = abyRsvTime[i];
+ for (i = 0; i < 9; i++) {
+ abyData[16+i*2] = abyTxRate[i];
+ abyData[16+i*2+1] = abyRsvTime[i];
}
-
CONTROLnsRequestOut(pDevice,
MESSAGE_TYPE_WRITE,
MAC_REG_RSPINF_B_1,
diff --git a/drivers/staging/vt6656/channel.c b/drivers/staging/vt6656/channel.c
index f49b6e13339..6ad03e492ed 100644
--- a/drivers/staging/vt6656/channel.c
+++ b/drivers/staging/vt6656/channel.c
@@ -441,11 +441,10 @@ void CHvInitChannelTable(void *pDeviceHandler)
{
PSDevice pDevice = (PSDevice) pDeviceHandler;
BOOL bMultiBand = FALSE;
- unsigned int ii;
+ unsigned int ii;
- for(ii=1;ii<=CB_MAX_CHANNEL;ii++) {
- sChannelTbl[ii].bValid = FALSE;
- }
+ for (ii = 1; ii <= CB_MAX_CHANNEL; ii++)
+ sChannelTbl[ii].bValid = FALSE;
switch (pDevice->byRFType) {
case RF_AL2230:
@@ -464,43 +463,43 @@ void CHvInitChannelTable(void *pDeviceHandler)
if ((pDevice->dwDiagRefCount != 0) ||
(pDevice->b11hEable == TRUE)) {
if (bMultiBand == TRUE) {
- for(ii=0;ii<CB_MAX_CHANNEL;ii++) {
- sChannelTbl[ii+1].bValid = TRUE;
+ for (ii = 0; ii < CB_MAX_CHANNEL; ii++) {
+ sChannelTbl[ii+1].bValid = TRUE;
//pDevice->abyRegPwr[ii+1] = pDevice->abyOFDMDefaultPwr[ii+1];
//pDevice->abyLocalPwr[ii+1] = pDevice->abyOFDMDefaultPwr[ii+1];
- }
- for(ii=0;ii<CB_MAX_CHANNEL_24G;ii++) {
+ }
+ for (ii = 0; ii < CB_MAX_CHANNEL_24G; ii++) {
//pDevice->abyRegPwr[ii+1] = pDevice->abyCCKDefaultPwr[ii+1];
//pDevice->abyLocalPwr[ii+1] = pDevice->abyCCKDefaultPwr[ii+1];
- }
+ }
} else {
- for(ii=0;ii<CB_MAX_CHANNEL_24G;ii++) {
- sChannelTbl[ii+1].bValid = TRUE;
+ for (ii = 0; ii < CB_MAX_CHANNEL_24G; ii++) {
+ sChannelTbl[ii+1].bValid = TRUE;
//pDevice->abyRegPwr[ii+1] = pDevice->abyCCKDefaultPwr[ii+1];
//pDevice->abyLocalPwr[ii+1] = pDevice->abyCCKDefaultPwr[ii+1];
- }
+ }
}
} else if (pDevice->byZoneType <= CCODE_MAX) {
if (bMultiBand == TRUE) {
- for(ii=0;ii<CB_MAX_CHANNEL;ii++) {
- if (ChannelRuleTab[pDevice->byZoneType].bChannelIdxList[ii] != 0) {
- sChannelTbl[ii+1].bValid = TRUE;
+ for (ii = 0; ii < CB_MAX_CHANNEL; ii++) {
+ if (ChannelRuleTab[pDevice->byZoneType].bChannelIdxList[ii] != 0) {
+ sChannelTbl[ii+1].bValid = TRUE;
//pDevice->abyRegPwr[ii+1] = ChannelRuleTab[pDevice->byZoneType].byPower[ii];
//pDevice->abyLocalPwr[ii+1] = ChannelRuleTab[pDevice->byZoneType].byPower[ii];
- }
- }
+ }
+ }
} else {
- for(ii=0;ii<CB_MAX_CHANNEL_24G;ii++) {
- if (ChannelRuleTab[pDevice->byZoneType].bChannelIdxList[ii] != 0) {
- sChannelTbl[ii+1].bValid = TRUE;
+ for (ii = 0; ii < CB_MAX_CHANNEL_24G; ii++) {
+ if (ChannelRuleTab[pDevice->byZoneType].bChannelIdxList[ii] != 0) {
+ sChannelTbl[ii+1].bValid = TRUE;
//pDevice->abyRegPwr[ii+1] = ChannelRuleTab[pDevice->byZoneType].byPower[ii];
//pDevice->abyLocalPwr[ii+1] = ChannelRuleTab[pDevice->byZoneType].byPower[ii];
- }
- }
+ }
+ }
}
}
DBG_PRT(MSG_LEVEL_NOTICE, KERN_INFO"Zone=[%d][%c][%c]!!\n",pDevice->byZoneType,ChannelRuleTab[pDevice->byZoneType].chCountryCode[0],ChannelRuleTab[pDevice->byZoneType].chCountryCode[1]);
- for(ii=0;ii<CB_MAX_CHANNEL;ii++) {
+ for (ii = 0; ii < CB_MAX_CHANNEL; ii++) {
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Channel[%d] is [%d]\n",sChannelTbl[ii].byChannelNumber,sChannelTbl[ii+1].bValid);
/*if (pDevice->abyRegPwr[ii+1] == 0) {
pDevice->abyRegPwr[ii+1] = pDevice->abyOFDMDefaultPwr[ii+1];
diff --git a/drivers/staging/vt6656/channel.h b/drivers/staging/vt6656/channel.h
index 91c2ffc6f1f..e7b3c123182 100644
--- a/drivers/staging/vt6656/channel.h
+++ b/drivers/staging/vt6656/channel.h
@@ -35,23 +35,21 @@
/*--------------------- Export Definitions -------------------------*/
/*--------------------- Export Classes ----------------------------*/
+
typedef struct tagSChannelTblElement {
BYTE byChannelNumber;
unsigned int uFrequency;
BOOL bValid;
-}SChannelTblElement, *PSChannelTblElement;
+} SChannelTblElement, *PSChannelTblElement;
/*--------------------- Export Variables --------------------------*/
/*--------------------- Export Functions --------------------------*/
+
BOOL ChannelValid(unsigned int CountryCode, unsigned int ChannelNum);
void CHvInitChannelTable(void *pDeviceHandler);
BYTE CHbyGetChannelMapping(BYTE byChannelNumber);
-BOOL
-CHvChannelGetList (
- unsigned int uCountryCodeIdx,
- PBYTE pbyChannelTable
- );
+BOOL CHvChannelGetList(unsigned int uCountryCodeIdx, PBYTE pbyChannelTable);
-#endif /* _REGULATE_H_ */
+#endif /* _CHANNEL_H_ */
diff --git a/drivers/staging/vt6656/control.c b/drivers/staging/vt6656/control.c
index 8aab6718ff4..5d8c5719419 100644
--- a/drivers/staging/vt6656/control.c
+++ b/drivers/staging/vt6656/control.c
@@ -72,7 +72,7 @@ void ControlvWriteByte(PSDevice pDevice, BYTE byRegType, BYTE byRegOfs,
void ControlvReadByte(PSDevice pDevice, BYTE byRegType, BYTE byRegOfs,
PBYTE pbyData)
{
- NTSTATUS ntStatus;
+ int ntStatus;
BYTE byData1;
ntStatus = CONTROLnsRequestIn(pDevice,
MESSAGE_TYPE_READ,
diff --git a/drivers/staging/vt6656/control.h b/drivers/staging/vt6656/control.h
index 146b450e13d..bbe610fd8b5 100644
--- a/drivers/staging/vt6656/control.h
+++ b/drivers/staging/vt6656/control.h
@@ -36,16 +36,14 @@
/*--------------------- Export Definitions -------------------------*/
+#define CONTROLnsRequestOut(Device, Request, Value, Index, Length, Buffer) \
+ PIPEnsControlOut(Device, Request, Value, Index, Length, Buffer)
-#define CONTROLnsRequestOut( Device,Request,Value,Index,Length,Buffer) \
- PIPEnsControlOut( Device,Request,Value,Index,Length,Buffer)
-
-#define CONTROLnsRequestOutAsyn( Device,Request,Value,Index,Length,Buffer) \
- PIPEnsControlOutAsyn( Device,Request,Value,Index,Length,Buffer)
-
-#define CONTROLnsRequestIn( Device,Request,Value,Index,Length,Buffer) \
- PIPEnsControlIn( Device,Request,Value,Index,Length,Buffer)
+#define CONTROLnsRequestOutAsyn(Device, Request, Value, Index, Length, Buffer) \
+ PIPEnsControlOutAsyn(Device, Request, Value, Index, Length, Buffer)
+#define CONTROLnsRequestIn(Device, Request, Value, Index, Length, Buffer) \
+ PIPEnsControlIn(Device, Request, Value, Index, Length, Buffer)
/*--------------------- Export Classes ----------------------------*/
diff --git a/drivers/staging/vt6656/datarate.c b/drivers/staging/vt6656/datarate.c
index 2e183ddbfd0..5c2719fa72f 100644
--- a/drivers/staging/vt6656/datarate.c
+++ b/drivers/staging/vt6656/datarate.c
@@ -72,7 +72,7 @@ void s_vResetCounter(PKnownNodeDB psNodeDBTable)
BYTE ii;
// clear statistic counter for auto_rate
- for(ii=0;ii<=MAX_RATE;ii++) {
+ for (ii = 0; ii <= MAX_RATE; ii++) {
psNodeDBTable->uTxOk[ii] = 0;
psNodeDBTable->uTxFail[ii] = 0;
}
@@ -309,7 +309,6 @@ RATEvTxRateFallBack(
{
PSDevice pDevice = (PSDevice) pDeviceHandler;
PSMgmtObject pMgmt = &(pDevice->sMgmtObj);
-#if 1 //mike fixed old: use packet lose ratio algorithm to control rate
WORD wIdxDownRate = 0;
unsigned int ii;
BOOL bAutoRate[MAX_RATE] = {TRUE,TRUE,TRUE,TRUE,FALSE,FALSE,TRUE,TRUE,TRUE,TRUE,TRUE,TRUE};
@@ -337,7 +336,7 @@ DWORD dwTxDiff = 0;
psNodeDBTable->uTimeCount = 0;
}
- for(ii=0;ii<MAX_RATE;ii++) {
+ for (ii = 0; ii < MAX_RATE; ii++) {
if (psNodeDBTable->wSuppRate & (0x0001<<ii)) {
if (bAutoRate[ii] == TRUE) {
wIdxUpRate = (WORD) ii;
@@ -347,7 +346,7 @@ DWORD dwTxDiff = 0;
}
}
- for(ii=0;ii<=psNodeDBTable->wTxDataRate;ii++) {
+ for (ii = 0; ii <= psNodeDBTable->wTxDataRate; ii++) {
if ( (psNodeDBTable->uTxOk[ii] != 0) ||
(psNodeDBTable->uTxFail[ii] != 0) ) {
dwThroughputTbl[ii] *= psNodeDBTable->uTxOk[ii];
@@ -362,7 +361,7 @@ DWORD dwTxDiff = 0;
dwThroughput = dwThroughputTbl[psNodeDBTable->wTxDataRate];
wIdxDownRate = psNodeDBTable->wTxDataRate;
- for(ii = psNodeDBTable->wTxDataRate; ii > 0;) {
+ for (ii = psNodeDBTable->wTxDataRate; ii > 0;) {
ii--;
if ( (dwThroughputTbl[ii] > dwThroughput) &&
(bAutoRate[ii]==TRUE) ) {
@@ -389,66 +388,6 @@ DWORD dwTxDiff = 0;
s_vResetCounter(psNodeDBTable);
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Rate: %d, U:%d, D:%d\n", (int)psNodeDBTable->wTxDataRate, (int)wIdxUpRate, (int)wIdxDownRate);
return;
-#else //mike fixed new: use differ-signal strength to control rate
-WORD wIdxUpRate = 0;
-BOOL bAutoRate[MAX_RATE] = {TRUE,TRUE,TRUE,TRUE,FALSE,FALSE,TRUE,TRUE,TRUE,TRUE,TRUE,TRUE};
-unsigned int ii;
-long ldBm;
-
- if (pMgmt->eScanState != WMAC_NO_SCANNING) {
- // Don't do Fallback when scanning Channel
- return;
- }
-
- for(ii=0;ii<MAX_RATE;ii++) {
- if (psNodeDBTable->wSuppRate & (0x0001<<ii)) {
- if (bAutoRate[ii] == TRUE) {
- wIdxUpRate = (WORD) ii;
- }
- } else {
- bAutoRate[ii] = FALSE;
- }
- }
-
- RFvRSSITodBm(pDevice, (BYTE)(pDevice->uCurrRSSI), &ldBm);
-
- if (ldBm > -55) {
- if ( psNodeDBTable->wSuppRate & (0x0001<<RATE_54M) ) //11a/g
- {
- psNodeDBTable->wTxDataRate = RATE_54M;
- }
- else{ //11b
- psNodeDBTable->wTxDataRate = RATE_11M;
- }
- }
-
-if (wIdxUpRate == RATE_54M ) { //11a/g
- if (ldBm > -56 )
- psNodeDBTable->wTxDataRate = RATE_54M;
- else if (ldBm > -61 )
- psNodeDBTable->wTxDataRate = RATE_48M;
- else if (ldBm > -66 )
- psNodeDBTable->wTxDataRate = RATE_36M;
- else if (ldBm > -72 )
- psNodeDBTable->wTxDataRate = RATE_24M;
- else if (ldBm > -80 )
- psNodeDBTable->wTxDataRate = RATE_5M;
- else {
- psNodeDBTable->wTxDataRate = RATE_1M;
- //increasingVGA = TRUE;
- }
- }
- else { //11b
- if (ldBm > -65 )
- psNodeDBTable->wTxDataRate = RATE_11M;
- else if (ldBm > -75 )
- psNodeDBTable->wTxDataRate = RATE_5M;
- else
- psNodeDBTable->wTxDataRate = RATE_1M;
- }
-
- return;
-#endif
}
/*+
diff --git a/drivers/staging/vt6656/desc.h b/drivers/staging/vt6656/desc.h
index 07f794ec6db..767112b3c4a 100644
--- a/drivers/staging/vt6656/desc.h
+++ b/drivers/staging/vt6656/desc.h
@@ -51,7 +51,6 @@
#define MAX_INTERRUPT_SIZE 32
-
#define RX_BLOCKS 64 // form 0x60 to 0xA0
#define TX_BLOCKS 32 // from 0xA0 to 0xC0
@@ -63,8 +62,6 @@
#define CB_RD_NUM 64 // default # of RD
#define CB_TD_NUM 64 // default # of TD
-
-
//
// Bits in the RSR register
//
@@ -87,7 +84,6 @@
#define NEWRSR_BCNHITAID 0x02 // 0000 0010
#define NEWRSR_BCNHITAID0 0x01 // 0000 0001
-
//
// Bits in the TSR register
//
@@ -96,17 +92,13 @@
#define TSR_ACKDATA 0x02 // 0000 0010
#define TSR_VALID 0x01 // 0000 0001
-
#define CB_PROTOCOL_RESERVED_SECTION 16
-
-
// if retrys excess 15 times , tx will abort, and
// if tx fifo underflow, tx will fail
// we should try to resend it
#define CB_MAX_TX_ABORT_RETRY 3
-
#define FIFOCTL_AUTO_FB_1 0x1000 // 0001 0000 0000 0000
#define FIFOCTL_AUTO_FB_0 0x0800 // 0000 1000 0000 0000
#define FIFOCTL_GRPACK 0x0400 // 0000 0100 0000 0000
@@ -137,7 +129,6 @@
#define FRAGCTL_STAFRAG 0x0001 // 0000 0000 0000 0001
#define FRAGCTL_NONFRAG 0x0000 // 0000 0000 0000 0000
-
//#define TYPE_AC0DMA 0
//#define TYPE_TXDMA0 1
#define TYPE_TXDMA0 0
@@ -152,8 +143,6 @@
#define TYPE_RXDMA1 1
#define TYPE_MAXRD 2
-
-
// TD_INFO flags control bit
#define TD_FLAGS_NETIF_SKB 0x01 // check if need release skb
#define TD_FLAGS_PRIV_SKB 0x02 // check if called from private skb(hostap)
@@ -162,7 +151,6 @@
/*--------------------- Export Types ------------------------------*/
-
//
// RsvTime buffer header
//
@@ -173,8 +161,9 @@ typedef struct tagSRrvTime_gRTS {
WORD wReserved;
WORD wTxRrvTime_b;
WORD wTxRrvTime_a;
-}__attribute__ ((__packed__))
+} __attribute__ ((__packed__))
SRrvTime_gRTS, *PSRrvTime_gRTS;
+
typedef const SRrvTime_gRTS *PCSRrvTime_gRTS;
typedef struct tagSRrvTime_gCTS {
@@ -182,22 +171,25 @@ typedef struct tagSRrvTime_gCTS {
WORD wReserved;
WORD wTxRrvTime_b;
WORD wTxRrvTime_a;
-}__attribute__ ((__packed__))
+} __attribute__ ((__packed__))
SRrvTime_gCTS, *PSRrvTime_gCTS;
+
typedef const SRrvTime_gCTS *PCSRrvTime_gCTS;
typedef struct tagSRrvTime_ab {
WORD wRTSTxRrvTime;
WORD wTxRrvTime;
-}__attribute__ ((__packed__))
+} __attribute__ ((__packed__))
SRrvTime_ab, *PSRrvTime_ab;
+
typedef const SRrvTime_ab *PCSRrvTime_ab;
typedef struct tagSRrvTime_atim {
WORD wCTSTxRrvTime_ba;
WORD wTxRrvTime_a;
-}__attribute__ ((__packed__))
+} __attribute__ ((__packed__))
SRrvTime_atim, *PSRrvTime_atim;
+
typedef const SRrvTime_atim *PCSRrvTime_atim;
//
@@ -208,8 +200,9 @@ typedef struct tagSRTSData {
WORD wDurationID;
BYTE abyRA[ETH_ALEN];
BYTE abyTA[ETH_ALEN];
-}__attribute__ ((__packed__))
+} __attribute__ ((__packed__))
SRTSData, *PSRTSData;
+
typedef const SRTSData *PCSRTSData;
typedef struct tagSRTS_g {
@@ -224,11 +217,10 @@ typedef struct tagSRTS_g {
WORD wDuration_bb;
WORD wReserved;
SRTSData Data;
-}__attribute__ ((__packed__))
+} __attribute__ ((__packed__))
SRTS_g, *PSRTS_g;
typedef const SRTS_g *PCSRTS_g;
-
typedef struct tagSRTS_g_FB {
BYTE bySignalField_b;
BYTE byServiceField_b;
@@ -245,10 +237,10 @@ typedef struct tagSRTS_g_FB {
WORD wRTSDuration_ba_f1;
WORD wRTSDuration_aa_f1;
SRTSData Data;
-}__attribute__ ((__packed__))
+} __attribute__ ((__packed__))
SRTS_g_FB, *PSRTS_g_FB;
-typedef const SRTS_g_FB *PCSRTS_g_FB;
+typedef const SRTS_g_FB *PCSRTS_g_FB;
typedef struct tagSRTS_ab {
BYTE bySignalField;
@@ -257,10 +249,10 @@ typedef struct tagSRTS_ab {
WORD wDuration;
WORD wReserved;
SRTSData Data;
-}__attribute__ ((__packed__))
+} __attribute__ ((__packed__))
SRTS_ab, *PSRTS_ab;
-typedef const SRTS_ab *PCSRTS_ab;
+typedef const SRTS_ab *PCSRTS_ab;
typedef struct tagSRTS_a_FB {
BYTE bySignalField;
@@ -271,8 +263,9 @@ typedef struct tagSRTS_a_FB {
WORD wRTSDuration_f0;
WORD wRTSDuration_f1;
SRTSData Data;
-}__attribute__ ((__packed__))
+} __attribute__ ((__packed__))
SRTS_a_FB, *PSRTS_a_FB;
+
typedef const SRTS_a_FB *PCSRTS_a_FB;
@@ -284,7 +277,7 @@ typedef struct tagSCTSData {
WORD wDurationID;
BYTE abyRA[ETH_ALEN];
WORD wReserved;
-}__attribute__ ((__packed__))
+} __attribute__ ((__packed__))
SCTSData, *PSCTSData;
typedef struct tagSCTS {
@@ -294,8 +287,9 @@ typedef struct tagSCTS {
WORD wDuration_ba;
WORD wReserved;
SCTSData Data;
-}__attribute__ ((__packed__))
+} __attribute__ ((__packed__))
SCTS, *PSCTS;
+
typedef const SCTS *PCSCTS;
typedef struct tagSCTS_FB {
@@ -307,10 +301,10 @@ typedef struct tagSCTS_FB {
WORD wCTSDuration_ba_f0;
WORD wCTSDuration_ba_f1;
SCTSData Data;
-}__attribute__ ((__packed__))
+} __attribute__ ((__packed__))
SCTS_FB, *PSCTS_FB;
-typedef const SCTS_FB *PCSCTS_FB;
+typedef const SCTS_FB *PCSCTS_FB;
//
// Tx FIFO header
@@ -321,14 +315,14 @@ typedef struct tagSTxBufHead {
WORD wTimeStamp;
WORD wFragCtl;
WORD wReserved;
-}__attribute__ ((__packed__))
+} __attribute__ ((__packed__))
STxBufHead, *PSTxBufHead;
typedef const STxBufHead *PCSTxBufHead;
typedef struct tagSTxShortBufHead {
WORD wFIFOCtl;
WORD wTimeStamp;
-}__attribute__ ((__packed__))
+} __attribute__ ((__packed__))
STxShortBufHead, *PSTxShortBufHead;
typedef const STxShortBufHead *PCSTxShortBufHead;
@@ -346,8 +340,9 @@ typedef struct tagSTxDataHead_g {
WORD wDuration_a;
WORD wTimeStampOff_b;
WORD wTimeStampOff_a;
-}__attribute__ ((__packed__))
+} __attribute__ ((__packed__))
STxDataHead_g, *PSTxDataHead_g;
+
typedef const STxDataHead_g *PCSTxDataHead_g;
typedef struct tagSTxDataHead_g_FB {
@@ -363,22 +358,20 @@ typedef struct tagSTxDataHead_g_FB {
WORD wDuration_a_f1;
WORD wTimeStampOff_b;
WORD wTimeStampOff_a;
-}__attribute__ ((__packed__))
+} __attribute__ ((__packed__))
STxDataHead_g_FB, *PSTxDataHead_g_FB;
typedef const STxDataHead_g_FB *PCSTxDataHead_g_FB;
-
typedef struct tagSTxDataHead_ab {
BYTE bySignalField;
BYTE byServiceField;
WORD wTransmitLength;
WORD wDuration;
WORD wTimeStampOff;
-}__attribute__ ((__packed__))
+} __attribute__ ((__packed__))
STxDataHead_ab, *PSTxDataHead_ab;
typedef const STxDataHead_ab *PCSTxDataHead_ab;
-
typedef struct tagSTxDataHead_a_FB {
BYTE bySignalField;
BYTE byServiceField;
@@ -387,7 +380,7 @@ typedef struct tagSTxDataHead_a_FB {
WORD wTimeStampOff;
WORD wDuration_f0;
WORD wDuration_f1;
-}__attribute__ ((__packed__))
+} __attribute__ ((__packed__))
STxDataHead_a_FB, *PSTxDataHead_a_FB;
typedef const STxDataHead_a_FB *PCSTxDataHead_a_FB;
@@ -398,23 +391,23 @@ typedef struct tagSMICHDRHead {
DWORD adwHDR0[4];
DWORD adwHDR1[4];
DWORD adwHDR2[4];
-}__attribute__ ((__packed__))
+} __attribute__ ((__packed__))
SMICHDRHead, *PSMICHDRHead;
+
typedef const SMICHDRHead *PCSMICHDRHead;
typedef struct tagSBEACONCtl {
DWORD BufReady : 1;
- DWORD TSF : 15;
- DWORD BufLen : 11;
+ DWORD TSF : 15;
+ DWORD BufLen : 11;
DWORD Reserved : 5;
-}__attribute__ ((__packed__))
+} __attribute__ ((__packed__))
SBEACONCtl;
-
typedef struct tagSSecretKey {
DWORD dwLowDword;
BYTE byHighByte;
-}__attribute__ ((__packed__))
+} __attribute__ ((__packed__))
SSecretKey;
typedef struct tagSKeyEntry {
@@ -426,7 +419,7 @@ typedef struct tagSKeyEntry {
DWORD dwKey2[4];
DWORD dwKey3[4];
DWORD dwKey4[4];
-}__attribute__ ((__packed__))
+} __attribute__ ((__packed__))
SKeyEntry;
/*--------------------- Export Macros ------------------------------*/
diff --git a/drivers/staging/vt6656/device.h b/drivers/staging/vt6656/device.h
index ef9fd97d3ca..b9852aa22c0 100644
--- a/drivers/staging/vt6656/device.h
+++ b/drivers/staging/vt6656/device.h
@@ -71,9 +71,6 @@
#define WPA_SUPPLICANT_DRIVER_WEXT_SUPPORT
#endif
-//2007-0920-01<Add>by MikeLiu
-#ifndef SndEvt_ToAPI
-#define SndEvt_ToAPI
//please copy below macro to driver_event.c for API
#define RT_INSMOD_EVENT_FLAG 0x0101
#define RT_UPDEV_EVENT_FLAG 0x0102
@@ -81,7 +78,6 @@
#define RT_WPACONNECTED_EVENT_FLAG 0x0104
#define RT_DOWNDEV_EVENT_FLAG 0x0105
#define RT_RMMOD_EVENT_FLAG 0x0106
-#endif
//
// device specific
@@ -109,7 +105,6 @@
#define MAX_MULTICAST_ADDRESS_NUM 32
#define MULTICAST_ADDRESS_LIST_SIZE (MAX_MULTICAST_ADDRESS_NUM * ETH_ALEN)
-
//#define OP_MODE_INFRASTRUCTURE 0
//#define OP_MODE_ADHOC 1
//#define OP_MODE_AP 2
@@ -130,8 +125,6 @@
#define KEYSEL_TKIP 2
#define KEYSEL_CCMP 3
-
-
#define AUTO_FB_NONE 0
#define AUTO_FB_0 1
#define AUTO_FB_1 2
@@ -162,8 +155,6 @@
#define BB_VGA_LEVEL 4
#define BB_VGA_CHANGE_THRESHOLD 3
-
-
#ifndef RUN_AT
#define RUN_AT(x) (jiffies+(x))
#endif
@@ -175,24 +166,23 @@
/*--------------------- Export Types ------------------------------*/
-#define DBG_PRT(l, p, args...) {if (l<=msglevel) printk( p ,##args);}
-#define PRINT_K(p, args...) {if (PRIVATE_Message) printk( p ,##args);}
+#define DBG_PRT(l, p, args...) { if (l <= msglevel) printk(p, ##args); }
+#define PRINT_K(p, args...) { if (PRIVATE_Message) printk(p, ##args); }
typedef enum __device_msg_level {
- MSG_LEVEL_ERR=0, //Errors that will cause abnormal operation.
- MSG_LEVEL_NOTICE=1, //Some errors need users to be notified.
- MSG_LEVEL_INFO=2, //Normal message.
- MSG_LEVEL_VERBOSE=3, //Will report all trival errors.
- MSG_LEVEL_DEBUG=4 //Only for debug purpose.
+ MSG_LEVEL_ERR = 0, /* Errors causing abnormal operation */
+ MSG_LEVEL_NOTICE = 1, /* Errors needing user notification */
+ MSG_LEVEL_INFO = 2, /* Normal message. */
+ MSG_LEVEL_VERBOSE = 3, /* Will report all trival errors. */
+ MSG_LEVEL_DEBUG = 4 /* Only for debug purpose. */
} DEVICE_MSG_LEVEL, *PDEVICE_MSG_LEVEL;
typedef enum __device_init_type {
- DEVICE_INIT_COLD=0, // cold init
- DEVICE_INIT_RESET, // reset init or Dx to D0 power remain init
- DEVICE_INIT_DXPL // Dx to D0 power lost init
+ DEVICE_INIT_COLD = 0, /* cold init */
+ DEVICE_INIT_RESET, /* reset init or Dx to D0 power remain */
+ DEVICE_INIT_DXPL /* Dx to D0 power lost init */
} DEVICE_INIT_TYPE, *PDEVICE_INIT_TYPE;
-
//USB
//
@@ -203,9 +193,6 @@ typedef enum _CONTEXT_TYPE {
CONTEXT_MGMT_PACKET
} CONTEXT_TYPE;
-
-
-
// RCB (Receive Control Block)
typedef struct _RCB
{
@@ -219,7 +206,6 @@ typedef struct _RCB
} RCB, *PRCB;
-
// used to track bulk out irps
typedef struct _USB_SEND_CONTEXT {
void *pDevice;
@@ -233,7 +219,6 @@ typedef struct _USB_SEND_CONTEXT {
unsigned char Data[MAX_TOTAL_SIZE_WITH_ALL_HEADERS];
} USB_SEND_CONTEXT, *PUSB_SEND_CONTEXT;
-
/* structure got from configuration file as user-desired default settings */
typedef struct _DEFAULT_CONFIG {
signed int ZoneType;
@@ -254,12 +239,10 @@ typedef struct {
BOOL bInUse;
} INT_BUFFER, *PINT_BUFFER;
-
-
//0:11A 1:11B 2:11G
typedef enum _VIA_BB_TYPE
{
- BB_TYPE_11A=0,
+ BB_TYPE_11A = 0,
BB_TYPE_11B,
BB_TYPE_11G
} VIA_BB_TYPE, *PVIA_BB_TYPE;
@@ -267,22 +250,18 @@ typedef enum _VIA_BB_TYPE
//0:11a,1:11b,2:11gb(only CCK in BasicRate),3:11ga(OFDM in Basic Rate)
typedef enum _VIA_PKT_TYPE
{
- PK_TYPE_11A=0,
+ PK_TYPE_11A = 0,
PK_TYPE_11B,
PK_TYPE_11GB,
PK_TYPE_11GA
} VIA_PKT_TYPE, *PVIA_PKT_TYPE;
-
-
-
//++ NDIS related
#define NDIS_STATUS int
-#define NTSTATUS int
typedef enum __DEVICE_NDIS_STATUS {
- STATUS_SUCCESS=0,
+ STATUS_SUCCESS = 0,
STATUS_FAILURE,
STATUS_RESOURCES,
STATUS_PENDING,
@@ -810,17 +789,12 @@ typedef struct __device_info {
// command timer
struct timer_list sTimerCommand;
-//2007-0115-01<Add>by MikeLiu
-#ifdef TxInSleep
struct timer_list sTimerTxData;
unsigned long nTxDataTimeCout;
BOOL fTxDataInSleep;
BOOL IsTxDataTrigger;
-#endif
-#ifdef WPA_SM_Transtatus
BOOL fWPA_Authened; //is WPA/WPA-PSK or WPA2/WPA2-PSK authen??
-#endif
BYTE byReAssocCount; //mike add:re-association retry times!
BYTE byLinkWaitCount;
diff --git a/drivers/staging/vt6656/device_cfg.h b/drivers/staging/vt6656/device_cfg.h
index c816901882a..a0b82169dad 100644
--- a/drivers/staging/vt6656/device_cfg.h
+++ b/drivers/staging/vt6656/device_cfg.h
@@ -77,25 +77,20 @@ struct _version {
//Max: 2378=2312Payload + 30HD +4CRC + 2Padding + 4Len + 8TSF + 4RSR
#define PKT_BUF_SZ 2390
-
#define MAX_UINTS 8
#define OPTION_DEFAULT { [0 ... MAX_UINTS-1] = -1}
-
-
-typedef enum _chip_type{
- VT3184=1
+typedef enum _chip_type {
+ VT3184 = 1
} CHIP_TYPE, *PCHIP_TYPE;
-
-
#ifdef VIAWET_DEBUG
#define ASSERT(x) { \
if (!(x)) { \
- printk(KERN_ERR "assertion %s failed: file %s line %d\n", #x,\
+ printk(KERN_ERR "assertion %s failed: file %s line %d\n", #x, \
__FUNCTION__, __LINE__);\
- *(int*) 0=0;\
- }\
+ *(int *) 0 = 0; \
+ } \
}
#define DBG_PORT80(value) outb(value, 0x80)
#else
@@ -103,5 +98,4 @@ typedef enum _chip_type{
#define DBG_PORT80(value)
#endif
-
#endif
diff --git a/drivers/staging/vt6656/dpc.c b/drivers/staging/vt6656/dpc.c
index 9afe76cacef..5e88349d3b9 100644
--- a/drivers/staging/vt6656/dpc.c
+++ b/drivers/staging/vt6656/dpc.c
@@ -80,7 +80,7 @@ static
void
s_vGetDASA(
PBYTE pbyRxBufferAddr,
- PUINT pcbHeaderSize,
+ unsigned int *pcbHeaderSize,
PSEthernetHeader psEthHeader
);
@@ -92,7 +92,7 @@ s_vProcessRxMACHeader (
unsigned int cbPacketSize,
BOOL bIsWEP,
BOOL bExtIV,
- PUINT pcbHeadSize
+ unsigned int *pcbHeadSize
);
static BOOL s_bAPModeRxCtl(
@@ -167,7 +167,7 @@ s_vProcessRxMACHeader (
unsigned int cbPacketSize,
BOOL bIsWEP,
BOOL bExtIV,
- PUINT pcbHeadSize
+ unsigned int *pcbHeadSize
)
{
PBYTE pbyRxBuffer;
@@ -195,10 +195,9 @@ s_vProcessRxMACHeader (
};
pbyRxBuffer = (PBYTE) (pbyRxBufferAddr + cbHeaderSize);
- if (IS_ETH_ADDRESS_EQUAL(pbyRxBuffer, &pDevice->abySNAP_Bridgetunnel[0])) {
+ if (!compare_ether_addr(pbyRxBuffer, &pDevice->abySNAP_Bridgetunnel[0])) {
cbHeaderSize += 6;
- }
- else if (IS_ETH_ADDRESS_EQUAL(pbyRxBuffer, &pDevice->abySNAP_RFC1042[0])) {
+ } else if (!compare_ether_addr(pbyRxBuffer, &pDevice->abySNAP_RFC1042[0])) {
cbHeaderSize += 6;
pwType = (PWORD) (pbyRxBufferAddr + cbHeaderSize);
if ((*pwType!= TYPE_PKT_IPX) && (*pwType != cpu_to_le16(0xF380))) {
@@ -262,7 +261,7 @@ static
void
s_vGetDASA (
PBYTE pbyRxBufferAddr,
- PUINT pcbHeaderSize,
+ unsigned int *pcbHeaderSize,
PSEthernetHeader psEthHeader
)
{
@@ -343,9 +342,7 @@ RXbBulkInProcessData (
PBYTE pbyRxSts;
PBYTE pbyRxRate;
PBYTE pbySQ;
-#ifdef Calcu_LinkQual
PBYTE pby3SQ;
-#endif
unsigned int cbHeaderSize;
PSKeyItem pKey = NULL;
WORD wRxTSC15_0 = 0;
@@ -416,7 +413,6 @@ RXbBulkInProcessData (
wPLCPwithPadding = ( (*pwPLCP_Length / 4) + ( (*pwPLCP_Length % 4) ? 1:0 ) ) *4;
pqwTSFTime = (PQWORD) (pbyDAddress + 8 + wPLCPwithPadding);
-#ifdef Calcu_LinkQual
if(pDevice->byBBType == BB_TYPE_11G) {
pby3SQ = pbyDAddress + 8 + wPLCPwithPadding + 12;
pbySQ = pby3SQ;
@@ -425,9 +421,6 @@ RXbBulkInProcessData (
pbySQ = pbyDAddress + 8 + wPLCPwithPadding + 8;
pby3SQ = pbySQ;
}
-#else
- pbySQ = pbyDAddress + 8 + wPLCPwithPadding + 8;
-#endif
pbyNewRsr = pbyDAddress + 8 + wPLCPwithPadding + 9;
pbyRSSI = pbyDAddress + 8 + wPLCPwithPadding + 10;
pbyRsr = pbyDAddress + 8 + wPLCPwithPadding + 11;
@@ -453,21 +446,22 @@ RXbBulkInProcessData (
if ((pMgmt->eCurrMode == WMAC_MODE_STANDBY) ||
(pMgmt->eCurrMode == WMAC_MODE_ESS_STA)) {
if (pMgmt->sNodeDBTable[0].bActive) {
- if(IS_ETH_ADDRESS_EQUAL (pMgmt->abyCurrBSSID, pMACHeader->abyAddr2) ) {
+ if (!compare_ether_addr(pMgmt->abyCurrBSSID, pMACHeader->abyAddr2)) {
if (pMgmt->sNodeDBTable[0].uInActiveCount != 0)
pMgmt->sNodeDBTable[0].uInActiveCount = 0;
}
}
}
- if (!IS_MULTICAST_ADDRESS(pMACHeader->abyAddr1) && !IS_BROADCAST_ADDRESS(pMACHeader->abyAddr1)) {
+ if (!is_multicast_ether_addr(pMACHeader->abyAddr1) && !is_broadcast_ether_addr(pMACHeader->abyAddr1)) {
if ( WCTLbIsDuplicate(&(pDevice->sDupRxCache), (PS802_11Header) pbyFrame) ) {
pDevice->s802_11Counter.FrameDuplicateCount++;
return FALSE;
}
- if ( !IS_ETH_ADDRESS_EQUAL (pDevice->abyCurrentNetAddr, pMACHeader->abyAddr1) ) {
- return FALSE;
+ if (compare_ether_addr(pDevice->abyCurrentNetAddr,
+ pMACHeader->abyAddr1)) {
+ return FALSE;
}
}
@@ -475,7 +469,8 @@ RXbBulkInProcessData (
// Use for TKIP MIC
s_vGetDASA(pbyFrame, &cbHeaderSize, &pDevice->sRxEthHeader);
- if (IS_ETH_ADDRESS_EQUAL((PBYTE)&(pDevice->sRxEthHeader.abySrcAddr[0]), pDevice->abyCurrentNetAddr))
+ if (!compare_ether_addr((PBYTE)&(pDevice->sRxEthHeader.abySrcAddr[0]),
+ pDevice->abyCurrentNetAddr))
return FALSE;
if ((pMgmt->eCurrMode == WMAC_MODE_ESS_AP) || (pMgmt->eCurrMode == WMAC_MODE_IBSS_STA)) {
@@ -568,8 +563,8 @@ RXbBulkInProcessData (
//
// RX OK
//
- //remove the CRC length
- FrameSize -= U_CRC_LEN;
+ /* remove the FCS/CRC length */
+ FrameSize -= ETH_FCS_LEN;
if ( !(*pbyRsr & (RSR_ADDRBROAD | RSR_ADDRMULTI)) && // unicast address
(IS_FRAGMENT_PKT((pbyFrame)))
@@ -758,10 +753,11 @@ RXbBulkInProcessData (
pMgmt->pCurrBSS->byRSSIStatCnt++;
pMgmt->pCurrBSS->byRSSIStatCnt %= RSSI_STAT_COUNT;
pMgmt->pCurrBSS->ldBmAverage[pMgmt->pCurrBSS->byRSSIStatCnt] = ldBm;
- for(ii=0;ii<RSSI_STAT_COUNT;ii++) {
- if (pMgmt->pCurrBSS->ldBmAverage[ii] != 0) {
- pMgmt->pCurrBSS->ldBmMAX = max(pMgmt->pCurrBSS->ldBmAverage[ii], ldBm);
- }
+ for (ii = 0; ii < RSSI_STAT_COUNT; ii++) {
+ if (pMgmt->pCurrBSS->ldBmAverage[ii] != 0) {
+ pMgmt->pCurrBSS->ldBmMAX =
+ max(pMgmt->pCurrBSS->ldBmAverage[ii], ldBm);
+ }
}
}
*/
@@ -1448,7 +1444,7 @@ static BOOL s_bAPModeRxData (
if (FrameSize > CB_MAX_BUF_SIZE)
return FALSE;
// check DA
- if(IS_MULTICAST_ADDRESS((PBYTE)(skb->data+cbHeaderOffset))) {
+ if (is_multicast_ether_addr((PBYTE)(skb->data+cbHeaderOffset))) {
if (pMgmt->sNodeDBTable[0].bPSEnable) {
skbcpy = dev_alloc_skb((int)pDevice->rx_buf_sz);
@@ -1523,7 +1519,7 @@ static BOOL s_bAPModeRxData (
void RXvWorkItem(void *Context)
{
PSDevice pDevice = (PSDevice) Context;
- NTSTATUS ntStatus;
+ int ntStatus;
PRCB pRCB=NULL;
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"---->Rx Polling Thread\n");
diff --git a/drivers/staging/vt6656/firmware.c b/drivers/staging/vt6656/firmware.c
index e1f96d7086f..ebb9c99df70 100644
--- a/drivers/staging/vt6656/firmware.c
+++ b/drivers/staging/vt6656/firmware.c
@@ -848,7 +848,7 @@ FIRMWAREbCheckVersion(
PSDevice pDevice
)
{
- NTSTATUS ntStatus;
+ int ntStatus;
ntStatus = CONTROLnsRequestIn(pDevice,
MESSAGE_TYPE_READ,
diff --git a/drivers/staging/vt6656/int.c b/drivers/staging/vt6656/int.c
index 89f5b18bdf1..c95833ac58e 100644
--- a/drivers/staging/vt6656/int.c
+++ b/drivers/staging/vt6656/int.c
@@ -82,7 +82,7 @@ static int msglevel = MSG_LEVEL_INFO;
void INTvWorkItem(void *Context)
{
PSDevice pDevice = (PSDevice) Context;
- NTSTATUS ntStatus;
+ int ntStatus;
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"---->Interrupt Polling Thread\n");
@@ -92,10 +92,9 @@ void INTvWorkItem(void *Context)
spin_unlock_irq(&pDevice->lock);
}
-NTSTATUS
-INTnsProcessData(PSDevice pDevice)
+int INTnsProcessData(PSDevice pDevice)
{
- NTSTATUS status = STATUS_SUCCESS;
+ int status = STATUS_SUCCESS;
PSINTData pINTData;
PSMgmtObject pMgmt = &(pDevice->sMgmtObj);
struct net_device_stats *pStats = &pDevice->stats;
diff --git a/drivers/staging/vt6656/int.h b/drivers/staging/vt6656/int.h
index cdf355130de..3176c8d08d6 100644
--- a/drivers/staging/vt6656/int.h
+++ b/drivers/staging/vt6656/int.h
@@ -57,7 +57,7 @@ typedef struct tagSINTData {
BYTE byACKFail;
BYTE byFCSErr;
BYTE abySW[2];
-}__attribute__ ((__packed__))
+} __attribute__ ((__packed__))
SINTData, *PSINTData;
@@ -68,10 +68,6 @@ SINTData, *PSINTData;
/*--------------------- Export Functions --------------------------*/
void INTvWorkItem(void *Context);
-
-NTSTATUS
-INTnsProcessData(
- PSDevice pDevice
- );
+int INTnsProcessData(PSDevice pDevice);
#endif /* __INT_H__ */
diff --git a/drivers/staging/vt6656/iocmd.h b/drivers/staging/vt6656/iocmd.h
index fbba1d53e49..1ce39a4ba2f 100644
--- a/drivers/staging/vt6656/iocmd.h
+++ b/drivers/staging/vt6656/iocmd.h
@@ -70,10 +70,10 @@ typedef enum tagWMAC_CMD {
} WMAC_CMD, *PWMAC_CMD;
typedef enum tagWZONETYPE {
- ZoneType_USA=0,
- ZoneType_Japan=1,
- ZoneType_Europe=2
-}WZONETYPE;
+ ZoneType_USA = 0,
+ ZoneType_Japan = 1,
+ ZoneType_Europe = 2
+} WZONETYPE;
#define ADHOC 0
#define INFRA 1
@@ -83,9 +83,9 @@ typedef enum tagWZONETYPE {
#define ADHOC_STARTED 1
#define ADHOC_JOINTED 2
-#define PHY80211a 0
-#define PHY80211b 1
-#define PHY80211g 2
+#define PHY80211a 0
+#define PHY80211b 1
+#define PHY80211g 2
#define SSID_ID 0
#define SSID_MAXLEN 32
@@ -143,7 +143,6 @@ typedef struct tagSCmdZoneTypeSet {
} SCmdZoneTypeSet, *PSCmdZoneTypeSet;
-#ifdef WPA_SM_Transtatus
typedef struct tagSWPAResult {
char ifname[100];
u8 proto;
@@ -151,7 +150,6 @@ typedef struct tagSWPAResult {
u8 eap_type;
BOOL authenticated;
} SWPAResult, *PSWPAResult;
-#endif
typedef struct tagSCmdStartAP {
diff --git a/drivers/staging/vt6656/ioctl.c b/drivers/staging/vt6656/ioctl.c
index 19a84b66b09..d532618639b 100644
--- a/drivers/staging/vt6656/ioctl.c
+++ b/drivers/staging/vt6656/ioctl.c
@@ -48,9 +48,7 @@
//static int msglevel =MSG_LEVEL_DEBUG;
static int msglevel =MSG_LEVEL_INFO;
-#ifdef WPA_SM_Transtatus
SWPAResult wpa_Result;
-#endif
/*--------------------- Static Functions --------------------------*/
@@ -232,10 +230,10 @@ int private_ioctl(PSDevice pDevice, struct ifreq *rq) {
pDevice->bEncryptionEnable = FALSE;
pDevice->eEncryptionStatus = Ndis802_11EncryptionDisabled;
spin_lock_irq(&pDevice->lock);
- for(uu=0;uu<MAX_KEY_TABLE;uu++)
- MACvDisableKeyEntry(pDevice,uu);
+ for (uu = 0; uu < MAX_KEY_TABLE; uu++)
+ MACvDisableKeyEntry(pDevice, uu);
spin_unlock_irq(&pDevice->lock);
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "WEP function disable. \n");
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "WEP function disable.\n");
break;
}
@@ -656,7 +654,6 @@ int private_ioctl(PSDevice pDevice, struct ifreq *rq) {
pReq->wResult = 0;
break;
-#ifdef WPA_SM_Transtatus
case 0xFF:
memset(wpa_Result.ifname,0,sizeof(wpa_Result.ifname));
wpa_Result.proto = 0;
@@ -676,7 +673,6 @@ int private_ioctl(PSDevice pDevice, struct ifreq *rq) {
//DavidWang
if(wpa_Result.authenticated==TRUE) {
- #ifdef SndEvt_ToAPI
{
union iwreq_data wrqu;
@@ -687,7 +683,6 @@ if(wpa_Result.authenticated==TRUE) {
wrqu.data.length =pItemSSID->len;
wireless_send_event(pDevice->dev, IWEVCUSTOM, &wrqu, pItemSSID->abySSID);
}
- #endif
pDevice->fWPA_Authened = TRUE; //is successful peer to wpa_Result.authenticated?
}
@@ -700,7 +695,6 @@ if(wpa_Result.authenticated==TRUE) {
pReq->wResult = 0;
break;
-#endif
default:
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Private command not support..\n");
diff --git a/drivers/staging/vt6656/iowpa.h b/drivers/staging/vt6656/iowpa.h
index da03edcbacb..959c8868f6e 100644
--- a/drivers/staging/vt6656/iowpa.h
+++ b/drivers/staging/vt6656/iowpa.h
@@ -31,10 +31,8 @@
/*--------------------- Export Definitions -------------------------*/
-
#define WPA_IE_LEN 64
-
//WPA related
/*
typedef enum { WPA_ALG_NONE, WPA_ALG_WEP, WPA_ALG_TKIP, WPA_ALG_CCMP } wpa_alg;
@@ -54,7 +52,7 @@ enum {
VIAWGET_SET_DROP_UNENCRYPT = 7,
VIAWGET_SET_DEAUTHENTICATE = 8,
VIAWGET_SET_ASSOCIATE = 9,
- VIAWGET_SET_DISASSOCIATE= 10
+ VIAWGET_SET_DISASSOCIATE = 10
};
@@ -76,8 +74,6 @@ typedef struct viawget_wpa_header {
u16 resp_ie_len;
} viawget_wpa_header;
-
-
struct viawget_wpa_param {
u32 cmd;
u8 addr[6];
@@ -86,43 +82,37 @@ struct viawget_wpa_param {
u8 len;
u8 data[0];
} generic_elem;
-
struct {
- u8 bssid[6];
+ u8 bssid[6];
u8 ssid[32];
u8 ssid_len;
- u8 *wpa_ie;
- u16 wpa_ie_len;
- int pairwise_suite;
- int group_suite;
- int key_mgmt_suite;
- int auth_alg;
- int mode;
- u8 roam_dbm; //DavidWang
+ u8 *wpa_ie;
+ u16 wpa_ie_len;
+ int pairwise_suite;
+ int group_suite;
+ int key_mgmt_suite;
+ int auth_alg;
+ int mode;
+ u8 roam_dbm;
} wpa_associate;
-
struct {
- int alg_name;
- u16 key_index;
- u16 set_tx;
- u8 *seq;
- u16 seq_len;
- u8 *key;
- u16 key_len;
+ int alg_name;
+ u16 key_index;
+ u16 set_tx;
+ u8 *seq;
+ u16 seq_len;
+ u8 *key;
+ u16 key_len;
} wpa_key;
-
struct {
u8 ssid_len;
u8 ssid[32];
} scan_req;
-
struct {
u16 scan_count;
u8 *buf;
} scan_results;
-
} u;
-
};
#pragma pack(1)
@@ -142,15 +132,12 @@ struct viawget_scan_result {
int maxrate;
};
-
/*--------------------- Export Classes ----------------------------*/
/*--------------------- Export Variables --------------------------*/
-
/*--------------------- Export Types ------------------------------*/
-
/*--------------------- Export Functions --------------------------*/
#endif /* __IOWPA_H__ */
diff --git a/drivers/staging/vt6656/iwctl.c b/drivers/staging/vt6656/iwctl.c
index fa40522d4a9..016b8e7766f 100644
--- a/drivers/staging/vt6656/iwctl.c
+++ b/drivers/staging/vt6656/iwctl.c
@@ -83,31 +83,9 @@ struct iw_statistics *iwctl_get_wireless_stats(struct net_device *dev)
long ldBm;
pDevice->wstats.status = pDevice->eOPMode;
- #ifdef Calcu_LinkQual
- #if 0
- if(pDevice->byBBType == BB_TYPE_11B) {
- if(pDevice->byCurrSQ > 120)
- pDevice->scStatistic.LinkQuality = 100;
- else
- pDevice->scStatistic.LinkQuality = pDevice->byCurrSQ*100/120;
- }
- else if(pDevice->byBBType == BB_TYPE_11G) {
- if(pDevice->byCurrSQ < 20)
- pDevice->scStatistic.LinkQuality = 100;
- else if(pDevice->byCurrSQ >96)
- pDevice->scStatistic.LinkQuality = 0;
- else
- pDevice->scStatistic.LinkQuality = (96-pDevice->byCurrSQ)*100/76;
- }
- if(pDevice->bLinkPass !=TRUE)
- pDevice->scStatistic.LinkQuality = 0;
- #endif
if(pDevice->scStatistic.LinkQuality > 100)
pDevice->scStatistic.LinkQuality = 100;
pDevice->wstats.qual.qual =(BYTE) pDevice->scStatistic.LinkQuality;
- #else
- pDevice->wstats.qual.qual = pDevice->byCurrSQ;
- #endif
RFvRSSITodBm(pDevice, (BYTE)(pDevice->uCurrRSSI), &ldBm);
pDevice->wstats.qual.level = ldBm;
//pDevice->wstats.qual.level = 0x100 - pDevice->uCurrRSSI;
@@ -133,18 +111,9 @@ static int iwctl_commit(struct net_device *dev,
void *wrq,
char *extra)
{
-//2008-0409-02, <Mark> by Einsn Liu
-/*
-#ifdef Safe_Close
- PSDevice pDevice = (PSDevice)netdev_priv(dev);
- if (!(pDevice->flags & DEVICE_FLAGS_OPENED))
- return -EINVAL;
-#endif
-*/
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCSIWCOMMIT \n");
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCSIWCOMMIT\n");
return 0;
-
}
/*
@@ -209,9 +178,7 @@ if(pDevice->byReAssocCount > 0) { //reject scan when re-associating!
spin_lock_irq(&pDevice->lock);
-#ifdef update_BssList
BSSvClearBSSList((void *) pDevice, pDevice->bLinkPass);
-#endif
//mike add: active scan OR passive scan OR desire_ssid scan
if(wrq->length == sizeof(struct iw_scan_req)) {
@@ -273,14 +240,7 @@ int iwctl_giwscan(struct net_device *dev,
long ldBm;
char buf[MAX_WPA_IE_LEN * 2 + 30];
-//2008-0409-02, <Mark> by Einsn Liu
-/*
-#ifdef Safe_Close
- if (!(pDevice->flags & DEVICE_FLAGS_OPENED))
- return -EINVAL;
-#endif
-*/
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCGIWSCAN \n");
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCGIWSCAN\n");
if (pMgmt->eScanState == WMAC_IS_SCANNING) {
// In scanning..
@@ -349,39 +309,6 @@ int iwctl_giwscan(struct net_device *dev,
}
iwe.u.qual.updated=7;
-//2008-0409-01, <Mark> by Einsn Liu
-/*
-//2008-0220-03, <Modify> by Einsn Liu
- if(pDevice->bLinkPass== TRUE && IS_ETH_ADDRESS_EQUAL(pBSS->abyBSSID, pMgmt->abyCurrBSSID)){
- #ifdef Calcu_LinkQual
- #if 0
- if(pDevice->byBBType == BB_TYPE_11B) {
- if(pDevice->byCurrSQ > 120)
- pDevice->scStatistic.LinkQuality = 100;
- else
- pDevice->scStatistic.LinkQuality = pDevice->byCurrSQ*100/120;
- }
- else if(pDevice->byBBType == BB_TYPE_11G) {
- if(pDevice->byCurrSQ < 20)
- pDevice->scStatistic.LinkQuality = 100;
- else if(pDevice->byCurrSQ >96)
- pDevice->scStatistic.LinkQuality = 0;
- else
- pDevice->scStatistic.LinkQuality = (96-pDevice->byCurrSQ)*100/76;
- }
- if(pDevice->bLinkPass !=TRUE)
- pDevice->scStatistic.LinkQuality = 0;
- #endif
- if(pDevice->scStatistic.LinkQuality > 100)
- pDevice->scStatistic.LinkQuality = 100;
- iwe.u.qual.qual =(BYTE) pDevice->scStatistic.LinkQuality;
- #else
- iwe.u.qual.qual = pDevice->byCurrSQ;
- #endif
- }else {
- iwe.u.qual.qual = 0;
- }
-*/
current_ev = iwe_stream_add_event(info,current_ev, end_buf, &iwe, IW_EV_QUAL_LEN);
//ADD encryption
memset(&iwe, 0, sizeof(iwe));
@@ -634,16 +561,8 @@ int iwctl_giwrange(struct net_device *dev,
struct iw_range *range = (struct iw_range *) extra;
int i,k;
BYTE abySupportedRates[13]= {0x02, 0x04, 0x0B, 0x16, 0x0c, 0x12, 0x18, 0x24, 0x30, 0x48, 0x60, 0x6C, 0x90};
-//2008-0409-02, <Mark> by Einsn Liu
-/*
- #ifdef Safe_Close
- PSDevice pDevice = (PSDevice)netdev_priv(dev);
- if (!(pDevice->flags & DEVICE_FLAGS_OPENED))
- return -EINVAL;
-#endif
- */
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCGIWRANGE \n");
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCGIWRANGE\n");
if (wrq->pointer) {
wrq->length = sizeof(struct iw_range);
memset(range, 0, sizeof(struct iw_range));
@@ -653,23 +572,19 @@ int iwctl_giwrange(struct net_device *dev,
// Should be based on cap_rid.country to give only
// what the current card support
k = 0;
- for(i = 0; i < 14; i++) {
+ for (i = 0; i < 14; i++) {
range->freq[k].i = i + 1; // List index
range->freq[k].m = frequency_list[i] * 100000;
range->freq[k++].e = 1; // Values in table in MHz -> * 10^5 * 10
}
range->num_frequency = k;
// Hum... Should put the right values there
- #ifdef Calcu_LinkQual
range->max_qual.qual = 100;
- #else
- range->max_qual.qual = 255;
- #endif
range->max_qual.level = 0;
range->max_qual.noise = 0;
range->sensitivity = 255;
- for(i = 0 ; i < 13 ; i++) {
+ for (i = 0 ; i < 13 ; i++) {
range->bitrate[i] = abySupportedRates[i] * 500000;
if(range->bitrate[i] == 0)
break;
@@ -761,7 +676,7 @@ int iwctl_siwap(struct net_device *dev,
memcpy(pMgmt->abyDesireBSSID, wrq->sa_data, 6);
//mike :add
- if ((IS_BROADCAST_ADDRESS(pMgmt->abyDesireBSSID)) ||
+ if ((is_broadcast_ether_addr(pMgmt->abyDesireBSSID)) ||
(memcmp(pMgmt->abyDesireBSSID, ZeroBSSID, 6) == 0)){
PRINT_K("SIOCSIWAP:invalid desired BSSID return!\n");
return rc;
@@ -772,7 +687,8 @@ int iwctl_siwap(struct net_device *dev,
unsigned int ii, uSameBssidNum = 0;
for (ii = 0; ii < MAX_BSS_NUM; ii++) {
if (pMgmt->sBSSList[ii].bActive &&
- IS_ETH_ADDRESS_EQUAL(pMgmt->sBSSList[ii].abyBSSID,pMgmt->abyDesireBSSID)) {
+ !compare_ether_addr(pMgmt->sBSSList[ii].abyBSSID,
+ pMgmt->abyDesireBSSID)) {
uSameBssidNum++;
}
}
@@ -957,7 +873,8 @@ int iwctl_siwessid(struct net_device *dev,
// by means of judging if there are two same BSSID exist in list ?
for (ii = 0; ii < MAX_BSS_NUM; ii++) {
if (pMgmt->sBSSList[ii].bActive &&
- IS_ETH_ADDRESS_EQUAL(pMgmt->sBSSList[ii].abyBSSID, pCurr->abyBSSID)) {
+ !compare_ether_addr(pMgmt->sBSSList[ii].abyBSSID,
+ pCurr->abyBSSID)) {
uSameBssidNum++;
}
}
@@ -1057,7 +974,7 @@ int iwctl_siwrate(struct net_device *dev,
u8 normvalue = (u8) (wrq->value/500000);
// Check if rate is valid
- for(i = 0 ; i < 13 ; i++) {
+ for (i = 0 ; i < 13 ; i++) {
if(normvalue == abySupportedRates[i]) {
brate = i;
break;
@@ -1067,7 +984,7 @@ int iwctl_siwrate(struct net_device *dev,
// -1 designed the max rate (mostly auto mode)
if(wrq->value == -1) {
// Get the highest available rate
- for(i = 0 ; i < 13 ; i++) {
+ for (i = 0 ; i < 13 ; i++) {
if(abySupportedRates[i] == 0)
break;
}
@@ -1405,8 +1322,8 @@ int iwctl_siwencode(struct net_device *dev,
pDevice->eEncryptionStatus = Ndis802_11EncryptionDisabled;
if (pDevice->flags & DEVICE_FLAGS_OPENED) {
spin_lock_irq(&pDevice->lock);
- for(uu=0;uu<MAX_KEY_TABLE;uu++)
- MACvDisableKeyEntry(pDevice,uu);
+ for (uu = 0; uu < MAX_KEY_TABLE; uu++)
+ MACvDisableKeyEntry(pDevice, uu);
spin_unlock_irq(&pDevice->lock);
}
}
@@ -1926,26 +1843,6 @@ param->u.wpa_key.key = (u8 *)key_array;
param->u.wpa_key.seq = (u8 *)seq;
param->u.wpa_key.seq_len = seq_len;
-#if 0
-printk("param->u.wpa_key.alg_name =%d\n",param->u.wpa_key.alg_name);
-printk("param->addr=%02x:%02x:%02x:%02x:%02x:%02x\n",
- param->addr[0],param->addr[1],param->addr[2],
- param->addr[3],param->addr[4],param->addr[5]);
-printk("param->u.wpa_key.set_tx =%d\n",param->u.wpa_key.set_tx);
-printk("param->u.wpa_key.key_index =%d\n",param->u.wpa_key.key_index);
-printk("param->u.wpa_key.key_len =%d\n",param->u.wpa_key.key_len);
-printk("param->u.wpa_key.key =");
-for(ii=0;ii<param->u.wpa_key.key_len;ii++)
- printk("%02x:",param->u.wpa_key.key[ii]);
- printk("\n");
-printk("param->u.wpa_key.seq_len =%d\n",param->u.wpa_key.seq_len);
-printk("param->u.wpa_key.seq =");
-for(ii=0;ii<param->u.wpa_key.seq_len;ii++)
- printk("%02x:",param->u.wpa_key.seq[ii]);
- printk("\n");
-
-printk("...........\n");
-#endif
//****set if current action is Network Manager count??
//****this method is so foolish,but there is no other way???
if(param->u.wpa_key.alg_name == WPA_ALG_NONE) {
diff --git a/drivers/staging/vt6656/iwctl.h b/drivers/staging/vt6656/iwctl.h
index df9a4cf3baa..d601e922021 100644
--- a/drivers/staging/vt6656/iwctl.h
+++ b/drivers/staging/vt6656/iwctl.h
@@ -33,15 +33,13 @@
/*--------------------- Export Definitions -------------------------*/
-
/*--------------------- Export Classes ----------------------------*/
/*--------------------- Export Variables --------------------------*/
/*--------------------- Export Functions --------------------------*/
-struct iw_statistics *iwctl_get_wireless_stats (struct net_device *dev);
-
+struct iw_statistics *iwctl_get_wireless_stats(struct net_device *dev);
int iwctl_siwap(struct net_device *dev,
struct iw_request_info *info,
diff --git a/drivers/staging/vt6656/key.c b/drivers/staging/vt6656/key.c
index b0890c181e7..d181a2f6626 100644
--- a/drivers/staging/vt6656/key.c
+++ b/drivers/staging/vt6656/key.c
@@ -174,7 +174,7 @@ BOOL KeybGetKey(PSKeyManagement pTable, PBYTE pbyBSSID, DWORD dwKeyIndex,
*pKey = NULL;
for (i=0;i<MAX_KEY_TABLE;i++) {
if ((pTable->KeyTable[i].bInUse == TRUE) &&
- IS_ETH_ADDRESS_EQUAL(pTable->KeyTable[i].abyBSSID,pbyBSSID)) {
+ !compare_ether_addr(pTable->KeyTable[i].abyBSSID, pbyBSSID)) {
if (dwKeyIndex == 0xFFFFFFFF) {
if (pTable->KeyTable[i].PairwiseKey.bKeyValid == TRUE) {
*pKey = &(pTable->KeyTable[i].PairwiseKey);
@@ -245,7 +245,7 @@ BOOL KeybSetKey(
j = i;
}
if ((pTable->KeyTable[i].bInUse == TRUE) &&
- IS_ETH_ADDRESS_EQUAL(pTable->KeyTable[i].abyBSSID,pbyBSSID)) {
+ !compare_ether_addr(pTable->KeyTable[i].abyBSSID, pbyBSSID)) {
// found table already exist
if ((dwKeyIndex & PAIRWISE_KEY) != 0) {
// Pairwise key
@@ -402,7 +402,7 @@ BOOL KeybRemoveKey(
int i;
BOOL bReturnValue = FALSE;
- if (IS_BROADCAST_ADDRESS(pbyBSSID)) {
+ if (is_broadcast_ether_addr(pbyBSSID)) {
// dealte all key
if ((dwKeyIndex & PAIRWISE_KEY) != 0) {
for (i=0;i<MAX_KEY_TABLE;i++) {
@@ -427,7 +427,7 @@ BOOL KeybRemoveKey(
} else {
for (i=0;i<MAX_KEY_TABLE;i++) {
if ( (pTable->KeyTable[i].bInUse == TRUE) &&
- IS_ETH_ADDRESS_EQUAL(pTable->KeyTable[i].abyBSSID,pbyBSSID)) {
+ !compare_ether_addr(pTable->KeyTable[i].abyBSSID, pbyBSSID)) {
if ((dwKeyIndex & PAIRWISE_KEY) != 0) {
pTable->KeyTable[i].PairwiseKey.bKeyValid = FALSE;
@@ -483,11 +483,11 @@ BOOL KeybRemoveAllKey(
for (i=0;i<MAX_KEY_TABLE;i++) {
if ((pTable->KeyTable[i].bInUse == TRUE) &&
- IS_ETH_ADDRESS_EQUAL(pTable->KeyTable[i].abyBSSID,pbyBSSID)) {
+ !compare_ether_addr(pTable->KeyTable[i].abyBSSID, pbyBSSID)) {
pTable->KeyTable[i].PairwiseKey.bKeyValid = FALSE;
- for(u=0;u<MAX_GROUP_KEY;u++) {
- pTable->KeyTable[i].GroupKey[u].bKeyValid = FALSE;
- }
+ for (u = 0; u < MAX_GROUP_KEY; u++)
+ pTable->KeyTable[i].GroupKey[u].bKeyValid = FALSE;
+
pTable->KeyTable[i].dwGTKeyIndex = 0;
s_vCheckKeyTableValid(pDevice, pTable);
return (TRUE);
@@ -531,19 +531,13 @@ void KeyvRemoveWEPKey(
return;
}
-void KeyvRemoveAllWEPKey(
- void *pDeviceHandler,
- PSKeyManagement pTable
- )
+void KeyvRemoveAllWEPKey(void *pDeviceHandler, PSKeyManagement pTable)
{
- PSDevice pDevice = (PSDevice) pDeviceHandler;
-
- int i;
-
- for(i=0;i<MAX_GROUP_KEY;i++) {
- KeyvRemoveWEPKey(pDevice,pTable, i);
- }
+ PSDevice pDevice = (PSDevice) pDeviceHandler;
+ int i;
+ for (i = 0; i < MAX_GROUP_KEY; i++)
+ KeyvRemoveWEPKey(pDevice, pTable, i);
}
/*
@@ -567,7 +561,7 @@ BOOL KeybGetTransmitKey(PSKeyManagement pTable, PBYTE pbyBSSID, DWORD dwKeyType,
*pKey = NULL;
for (i=0;i<MAX_KEY_TABLE;i++) {
if ((pTable->KeyTable[i].bInUse == TRUE) &&
- IS_ETH_ADDRESS_EQUAL(pTable->KeyTable[i].abyBSSID,pbyBSSID)) {
+ !compare_ether_addr(pTable->KeyTable[i].abyBSSID, pbyBSSID)) {
if (dwKeyType == PAIRWISE_KEY) {
diff --git a/drivers/staging/vt6656/mac.c b/drivers/staging/vt6656/mac.c
index 0ab3db025f3..33698edde4f 100644
--- a/drivers/staging/vt6656/mac.c
+++ b/drivers/staging/vt6656/mac.c
@@ -306,8 +306,8 @@ BYTE pbyData[24];
pbyData[5] = (BYTE)(dwData2>>8);
pbyData[6] = (BYTE)(dwData2>>16);
pbyData[7] = (BYTE)(dwData2>>24);
- for(ii=8;ii<24;ii++)
- pbyData[ii] = *pbyKey++;
+ for (ii = 8; ii < 24; ii++)
+ pbyData[ii] = *pbyKey++;
CONTROLnsRequestOut(pDevice,
MESSAGE_TYPE_SETKEY,
diff --git a/drivers/staging/vt6656/mac.h b/drivers/staging/vt6656/mac.h
index 775c70928ec..491ff5ecd04 100644
--- a/drivers/staging/vt6656/mac.h
+++ b/drivers/staging/vt6656/mac.h
@@ -420,11 +420,11 @@
/*--------------------- Export Functions --------------------------*/
-void MACvSetMultiAddrByHash (PSDevice pDevice, BYTE byHashIdx);
+void MACvSetMultiAddrByHash(PSDevice pDevice, BYTE byHashIdx);
void MACvWriteMultiAddr(PSDevice pDevice, unsigned int uByteIdx, BYTE byData);
-BOOL MACbShutdown(PSDevice pDevice);;
-void MACvSetBBType(PSDevice pDevice,BYTE byType);
-void MACvSetMISCFifo (PSDevice pDevice, WORD wOffset, DWORD dwData);
+BOOL MACbShutdown(PSDevice pDevice);
+void MACvSetBBType(PSDevice pDevice, BYTE byType);
+void MACvSetMISCFifo(PSDevice pDevice, WORD wOffset, DWORD dwData);
void MACvDisableKeyEntry(PSDevice pDevice, unsigned int uEntryIdx);
void MACvSetKeyEntry(PSDevice pDevice, WORD wKeyCtl, unsigned int uEntryIdx,
unsigned int uKeyIdx, PBYTE pbyAddr, PDWORD pdwKey);
diff --git a/drivers/staging/vt6656/main_usb.c b/drivers/staging/vt6656/main_usb.c
index 098b0455e32..c528ef0f8ed 100644
--- a/drivers/staging/vt6656/main_usb.c
+++ b/drivers/staging/vt6656/main_usb.c
@@ -366,7 +366,7 @@ static BOOL device_init_registers(PSDevice pDevice, DEVICE_INIT_TYPE InitType)
BYTE byAntenna;
unsigned int ii;
CMD_CARD_INIT sInitCmd;
- NTSTATUS ntStatus = STATUS_SUCCESS;
+ int ntStatus = STATUS_SUCCESS;
RSP_CARD_INIT sInitRsp;
PSMgmtObject pMgmt = &(pDevice->sMgmtObj);
BYTE byTmp;
@@ -407,8 +407,8 @@ static BOOL device_init_registers(PSDevice pDevice, DEVICE_INIT_TYPE InitType)
sInitCmd.byInitClass = (BYTE)InitType;
sInitCmd.bExistSWNetAddr = (BYTE) pDevice->bExistSWNetAddr;
- for(ii=0;ii<6;ii++)
- sInitCmd.bySWNetAddr[ii] = pDevice->abyCurrentNetAddr[ii];
+ for (ii = 0; ii < 6; ii++)
+ sInitCmd.bySWNetAddr[ii] = pDevice->abyCurrentNetAddr[ii];
sInitCmd.byShortRetryLimit = pDevice->byShortRetryLimit;
sInitCmd.byLongRetryLimit = pDevice->byLongRetryLimit;
@@ -487,10 +487,10 @@ static BOOL device_init_registers(PSDevice pDevice, DEVICE_INIT_TYPE InitType)
if(((pDevice->abyEEPROM[EEP_OFS_ZONETYPE] == ZoneType_Japan) ||
(pDevice->abyEEPROM[EEP_OFS_ZONETYPE] == ZoneType_Europe))&&
(pDevice->byOriginalZonetype == ZoneType_USA)) {
- for(ii=11;ii<14;ii++) {
- pDevice->abyCCKPwrTbl[ii] = pDevice->abyCCKPwrTbl[10];
- pDevice->abyOFDMPwrTbl[ii] = pDevice->abyOFDMPwrTbl[10];
- }
+ for (ii = 11; ii < 14; ii++) {
+ pDevice->abyCCKPwrTbl[ii] = pDevice->abyCCKPwrTbl[10];
+ pDevice->abyOFDMPwrTbl[ii] = pDevice->abyOFDMPwrTbl[10];
+ }
}
//{{ RobertYu: 20041124
@@ -718,33 +718,32 @@ static BOOL device_release_WPADEV(PSDevice pDevice)
static int vt6656_suspend(struct usb_interface *intf, pm_message_t message)
{
- PSDevice pDevice = usb_get_intfdata(intf);
- struct net_device *dev = pDevice->dev;
+ PSDevice device = usb_get_intfdata(intf);
- printk("VNTWUSB Suspend Start======>\n");
-if(dev != NULL) {
- if(pDevice->flags & DEVICE_FLAGS_OPENED)
- device_close(dev);
-}
+ if (!device || !device->dev)
+ return -ENODEV;
- usb_put_dev(interface_to_usbdev(intf));
- return 0;
+ if (device->flags & DEVICE_FLAGS_OPENED)
+ device_close(device->dev);
+
+ usb_put_dev(interface_to_usbdev(intf));
+
+ return 0;
}
static int vt6656_resume(struct usb_interface *intf)
{
- PSDevice pDevice = usb_get_intfdata(intf);
- struct net_device *dev = pDevice->dev;
-
- printk("VNTWUSB Resume Start======>\n");
- if(dev != NULL) {
- usb_get_dev(interface_to_usbdev(intf));
- if(!(pDevice->flags & DEVICE_FLAGS_OPENED)) {
- if(device_open(dev)!=0)
- printk("VNTWUSB Resume Start======>open fail\n");
- }
- }
- return 0;
+ PSDevice device = usb_get_intfdata(intf);
+
+ if (!device || !device->dev)
+ return -ENODEV;
+
+ usb_get_dev(interface_to_usbdev(intf));
+
+ if (!(device->flags & DEVICE_FLAGS_OPENED))
+ device_open(device->dev);
+
+ return 0;
}
#endif /* CONFIG_PM */
@@ -758,93 +757,75 @@ static const struct net_device_ops device_netdev_ops = {
.ndo_set_multicast_list = device_set_multi,
};
-
static int __devinit
vt6656_probe(struct usb_interface *intf, const struct usb_device_id *id)
{
u8 fake_mac[ETH_ALEN] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x01};
struct usb_device *udev = interface_to_usbdev(intf);
- int rc = 0;
- struct net_device *netdev = NULL;
- PSDevice pDevice = NULL;
-
+ int rc = 0;
+ struct net_device *netdev = NULL;
+ PSDevice pDevice = NULL;
- printk(KERN_NOTICE "%s Ver. %s\n",DEVICE_FULL_DRV_NAM, DEVICE_VERSION);
- printk(KERN_NOTICE "Copyright (c) 2004 VIA Networking Technologies, Inc.\n");
+ printk(KERN_NOTICE "%s Ver. %s\n", DEVICE_FULL_DRV_NAM, DEVICE_VERSION);
+ printk(KERN_NOTICE "Copyright (c) 2004 VIA Networking Technologies, Inc.\n");
- udev = usb_get_dev(udev);
-
- netdev = alloc_etherdev(sizeof(DEVICE_INFO));
-
- if (netdev == NULL) {
- printk(KERN_ERR DEVICE_NAME ": allocate net device failed \n");
- kfree(pDevice);
- goto err_nomem;
- }
+ udev = usb_get_dev(udev);
+ netdev = alloc_etherdev(sizeof(DEVICE_INFO));
- pDevice = netdev_priv(netdev);
- memset(pDevice, 0, sizeof(DEVICE_INFO));
+ if (!netdev) {
+ printk(KERN_ERR DEVICE_NAME ": allocate net device failed\n");
+ kfree(pDevice);
+ goto err_nomem;
+ }
- pDevice->dev = netdev;
- pDevice->usb = udev;
+ pDevice = netdev_priv(netdev);
+ memset(pDevice, 0, sizeof(DEVICE_INFO));
- // Set initial settings
- device_set_options(pDevice);
- spin_lock_init(&pDevice->lock);
+ pDevice->dev = netdev;
+ pDevice->usb = udev;
- pDevice->tx_80211 = device_dma0_tx_80211;
- pDevice->sMgmtObj.pAdapter = (void *)pDevice;
+ device_set_options(pDevice);
+ spin_lock_init(&pDevice->lock);
- netdev->netdev_ops = &device_netdev_ops;
+ pDevice->tx_80211 = device_dma0_tx_80211;
+ pDevice->sMgmtObj.pAdapter = (void *) pDevice;
- netdev->wireless_handlers = (struct iw_handler_def *)&iwctl_handler_def;
+ netdev->netdev_ops = &device_netdev_ops;
+ netdev->wireless_handlers =
+ (struct iw_handler_def *) &iwctl_handler_def;
- //2008-0623-01<Remark>by MikeLiu
- //2007-0821-01<Add>by MikeLiu
- usb_set_intfdata(intf, pDevice);
+ usb_set_intfdata(intf, pDevice);
SET_NETDEV_DEV(netdev, &intf->dev);
- memcpy(pDevice->dev->dev_addr, fake_mac, ETH_ALEN);
- rc = register_netdev(netdev);
- if (rc != 0) {
- printk(KERN_ERR DEVICE_NAME " Failed to register netdev\n");
+ memcpy(pDevice->dev->dev_addr, fake_mac, ETH_ALEN);
+ rc = register_netdev(netdev);
+ if (rc) {
+ printk(KERN_ERR DEVICE_NAME " Failed to register netdev\n");
free_netdev(netdev);
- kfree(pDevice);
- return -ENODEV;
- }
-
-//2008-07-21-01<Add>by MikeLiu
-//register wpadev
-#if 0
- if(wpa_set_wpadev(pDevice, 1)!=0) {
- printk("Fail to Register WPADEV?\n");
- unregister_netdev(pDevice->dev);
- free_netdev(netdev);
- kfree(pDevice);
- }
-#endif
- usb_device_reset(pDevice);
+ kfree(pDevice);
+ return -ENODEV;
+ }
-#ifdef SndEvt_ToAPI
-{
- union iwreq_data wrqu;
- memset(&wrqu, 0, sizeof(wrqu));
- wrqu.data.flags = RT_INSMOD_EVENT_FLAG;
- wrqu.data.length =IFNAMSIZ;
- wireless_send_event(pDevice->dev, IWEVCUSTOM, &wrqu, pDevice->dev->name);
-}
-#endif
+ usb_device_reset(pDevice);
+
+ {
+ union iwreq_data wrqu;
+ memset(&wrqu, 0, sizeof(wrqu));
+ wrqu.data.flags = RT_INSMOD_EVENT_FLAG;
+ wrqu.data.length = IFNAMSIZ;
+ wireless_send_event(pDevice->dev,
+ IWEVCUSTOM,
+ &wrqu,
+ pDevice->dev->name);
+ }
return 0;
-
err_nomem:
- //2008-0922-01<Add>by MikeLiu, decrease usb counter.
- usb_put_dev(udev);
+ usb_put_dev(udev);
- return -ENOMEM;
+ return -ENOMEM;
}
-
static void device_free_tx_bufs(PSDevice pDevice)
{
PUSB_SEND_CONTEXT pTxContext;
@@ -1065,7 +1046,6 @@ BOOL device_alloc_frag_buf(PSDevice pDevice, PSDeFragControlBlock pDeF) {
static int device_open(struct net_device *dev) {
PSDevice pDevice=(PSDevice) netdev_priv(dev);
-#ifdef WPA_SM_Transtatus
extern SWPAResult wpa_Result;
memset(wpa_Result.ifname,0,sizeof(wpa_Result.ifname));
wpa_Result.proto = 0;
@@ -1073,7 +1053,6 @@ static int device_open(struct net_device *dev) {
wpa_Result.eap_type = 0;
wpa_Result.authenticated = FALSE;
pDevice->fWPA_Authened = FALSE;
-#endif
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " device_open...\n");
@@ -1172,14 +1151,12 @@ static int device_open(struct net_device *dev) {
netif_stop_queue(pDevice->dev);
pDevice->flags |= DEVICE_FLAGS_OPENED;
-#ifdef SndEvt_ToAPI
{
union iwreq_data wrqu;
memset(&wrqu, 0, sizeof(wrqu));
wrqu.data.flags = RT_UPDEV_EVENT_FLAG;
wireless_send_event(pDevice->dev, IWEVCUSTOM, &wrqu, NULL);
}
-#endif
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "device_open success.. \n");
return 0;
@@ -1211,14 +1188,12 @@ static int device_close(struct net_device *dev) {
if (pDevice == NULL)
return -ENODEV;
-#ifdef SndEvt_ToAPI
{
union iwreq_data wrqu;
memset(&wrqu, 0, sizeof(wrqu));
wrqu.data.flags = RT_DOWNDEV_EVENT_FLAG;
wireless_send_event(pDevice->dev, IWEVCUSTOM, &wrqu, NULL);
}
-#endif
//2007-1121-02<Add>by EinsnLiu
if (pDevice->bLinkPass) {
@@ -1234,10 +1209,10 @@ device_release_WPADEV(pDevice);
pMgmt->bShareKeyAlgorithm = FALSE;
pDevice->bEncryptionEnable = FALSE;
pDevice->eEncryptionStatus = Ndis802_11EncryptionDisabled;
- spin_lock_irq(&pDevice->lock);
- for(uu=0;uu<MAX_KEY_TABLE;uu++)
+ spin_lock_irq(&pDevice->lock);
+ for (uu = 0; uu < MAX_KEY_TABLE; uu++)
MACvDisableKeyEntry(pDevice,uu);
- spin_unlock_irq(&pDevice->lock);
+ spin_unlock_irq(&pDevice->lock);
if ((pDevice->flags & DEVICE_FLAGS_UNPLUG) == FALSE) {
MACbShutdown(pDevice);
@@ -1250,10 +1225,7 @@ device_release_WPADEV(pDevice);
del_timer(&pDevice->sTimerCommand);
del_timer(&pMgmt->sTimerSecondCallback);
-//2007-0115-02<Add>by MikeLiu
-#ifdef TxInSleep
del_timer(&pDevice->sTimerTxData);
-#endif
if (pDevice->bDiversityRegCtlON) {
del_timer(&pDevice->TimerSQ3Tmax1);
@@ -1290,112 +1262,81 @@ device_release_WPADEV(pDevice);
return 0;
}
-
static void __devexit vt6656_disconnect(struct usb_interface *intf)
{
+ PSDevice device = usb_get_intfdata(intf);
- PSDevice pDevice = usb_get_intfdata(intf);
+ if (!device)
+ return;
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "device_disconnect1.. \n");
- if (pDevice == NULL)
- return;
-
-#ifdef SndEvt_ToAPI
-{
- union iwreq_data wrqu;
- memset(&wrqu, 0, sizeof(wrqu));
- wrqu.data.flags = RT_RMMOD_EVENT_FLAG;
- wireless_send_event(pDevice->dev, IWEVCUSTOM, &wrqu, NULL);
-}
-#endif
+ {
+ union iwreq_data req;
+ memset(&req, 0, sizeof(req));
+ req.data.flags = RT_RMMOD_EVENT_FLAG;
+ wireless_send_event(device->dev, IWEVCUSTOM, &req, NULL);
+ }
-//2008-0714-01<Add>by MikeLiu
-device_release_WPADEV(pDevice);
+ device_release_WPADEV(device);
usb_set_intfdata(intf, NULL);
-//2008-0922-01<Add>by MikeLiu, decrease usb counter.
- usb_put_dev(interface_to_usbdev(intf));
+ usb_put_dev(interface_to_usbdev(intf));
- pDevice->flags |= DEVICE_FLAGS_UNPLUG;
- if (pDevice->dev != NULL) {
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "unregister_netdev..\n");
- unregister_netdev(pDevice->dev);
+ device->flags |= DEVICE_FLAGS_UNPLUG;
-//2008-07-21-01<Add>by MikeLiu
-//unregister wpadev
- if(wpa_set_wpadev(pDevice, 0)!=0)
- printk("unregister wpadev fail?\n");
-
- free_netdev(pDevice->dev);
- }
-
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "device_disconnect3.. \n");
+ if (device->dev) {
+ unregister_netdev(device->dev);
+ wpa_set_wpadev(device, 0);
+ free_netdev(device->dev);
+ }
}
+static int device_dma0_tx_80211(struct sk_buff *skb, struct net_device *dev)
+{
+ PSDevice pDevice = netdev_priv(dev);
+ spin_lock_irq(&pDevice->lock);
+ if (unlikely(pDevice->bStopTx0Pkt))
+ dev_kfree_skb_irq(skb);
+ else
+ vDMA0_tx_80211(pDevice, skb);
-static int device_dma0_tx_80211(struct sk_buff *skb, struct net_device *dev) {
- PSDevice pDevice=netdev_priv(dev);
- PBYTE pbMPDU;
- unsigned int cbMPDULen = 0;
-
-
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "device_dma0_tx_80211\n");
- spin_lock_irq(&pDevice->lock);
-
- if (pDevice->bStopTx0Pkt == TRUE) {
- dev_kfree_skb_irq(skb);
- spin_unlock_irq(&pDevice->lock);
- return 0;
- };
-
-
- cbMPDULen = skb->len;
- pbMPDU = skb->data;
-
- vDMA0_tx_80211(pDevice, skb);
-
- spin_unlock_irq(&pDevice->lock);
-
- return 0;
+ spin_unlock_irq(&pDevice->lock);
+ return NETDEV_TX_OK;
}
+static int device_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+ PSDevice pDevice = netdev_priv(dev);
+ struct net_device_stats *stats = &pDevice->stats;
-static int device_xmit(struct sk_buff *skb, struct net_device *dev) {
- PSDevice pDevice=netdev_priv(dev);
- struct net_device_stats* pStats = &pDevice->stats;
-
+ spin_lock_irq(&pDevice->lock);
- spin_lock_irq(&pDevice->lock);
+ netif_stop_queue(dev);
- netif_stop_queue(pDevice->dev);
+ if (!pDevice->bLinkPass) {
+ dev_kfree_skb_irq(skb);
+ goto out;
+ }
- if (pDevice->bLinkPass == FALSE) {
- dev_kfree_skb_irq(skb);
- spin_unlock_irq(&pDevice->lock);
- return 0;
- }
- if (pDevice->bStopDataPkt == TRUE) {
- dev_kfree_skb_irq(skb);
- pStats->tx_dropped++;
- spin_unlock_irq(&pDevice->lock);
- return 0;
- }
+ if (pDevice->bStopDataPkt) {
+ dev_kfree_skb_irq(skb);
+ stats->tx_dropped++;
+ goto out;
+ }
- if(nsDMA_tx_packet(pDevice, TYPE_AC0DMA, skb) !=0) { //mike add:xmit fail!
- if (netif_queue_stopped(pDevice->dev))
- netif_wake_queue(pDevice->dev);
- }
+ if (nsDMA_tx_packet(pDevice, TYPE_AC0DMA, skb)) {
+ if (netif_queue_stopped(dev))
+ netif_wake_queue(dev);
+ }
- spin_unlock_irq(&pDevice->lock);
+out:
+ spin_unlock_irq(&pDevice->lock);
- return 0;
+ return NETDEV_TX_OK;
}
-
-
static unsigned const ethernet_polynomial = 0x04c11db7U;
static inline u32 ether_crc(int length, unsigned char *data)
{
@@ -1447,12 +1388,12 @@ static int Config_FileGetParameter(unsigned char *string,
return FALSE;
//check if current config line is marked by "#" ??
-for(ii=1;;ii++) {
- if(memcmp(start_p-ii,"\n",1)==0)
- break;
- if(memcmp(start_p-ii,"#",1)==0)
- return FALSE;
-}
+ for (ii = 1; ; ii++) {
+ if (memcmp(start_p - ii, "\n", 1) == 0)
+ break;
+ if (memcmp(start_p - ii, "#", 1) == 0)
+ return FALSE;
+ }
//find target string end point
end_p = kstrstr(start_p,"\n");
@@ -1585,7 +1526,6 @@ static int Read_config_file(PSDevice pDevice) {
}
}
-#if 1
//get other parameter
{
memset(tmpbuffer,0,sizeof(tmpbuffer));
@@ -1598,7 +1538,6 @@ static int Read_config_file(PSDevice pDevice) {
pDevice->config_file.eEncryptionStatus= (int) simple_strtol(tmpbuffer, NULL, 10);
}
}
-#endif
kfree(buffer);
return result;
diff --git a/drivers/staging/vt6656/mib.c b/drivers/staging/vt6656/mib.c
index b694fc86d74..8a6ee72f440 100644
--- a/drivers/staging/vt6656/mib.c
+++ b/drivers/staging/vt6656/mib.c
@@ -347,10 +347,9 @@ void STAvUpdateRDStatCounter(PSStatCounter pStatistic,
if (WLAN_GET_FC_MOREFRAG(pHeader->wFrameCtl))
pStatistic->dwRsrRxFragment++;
- if (cbFrameLength < MIN_PACKET_LEN + 4) {
+ if (cbFrameLength < ETH_ZLEN + 4) {
pStatistic->dwRsrRunt++;
- }
- else if (cbFrameLength == MIN_PACKET_LEN + 4) {
+ } else if (cbFrameLength == ETH_ZLEN + 4) {
pStatistic->dwRsrRxFrmLen64++;
}
else if ((65 <= cbFrameLength) && (cbFrameLength <= 127)) {
@@ -364,17 +363,14 @@ void STAvUpdateRDStatCounter(PSStatCounter pStatistic,
}
else if ((512 <= cbFrameLength) && (cbFrameLength <= 1023)) {
pStatistic->dwRsrRxFrmLen512_1023++;
- }
- else if ((1024 <= cbFrameLength) && (cbFrameLength <= MAX_PACKET_LEN + 4)) {
+ } else if ((1024 <= cbFrameLength) &&
+ (cbFrameLength <= ETH_FRAME_LEN + 4)) {
pStatistic->dwRsrRxFrmLen1024_1518++;
- } else if (cbFrameLength > MAX_PACKET_LEN + 4) {
+ } else if (cbFrameLength > ETH_FRAME_LEN + 4) {
pStatistic->dwRsrLong++;
}
-
}
-
-
/*
* Description: Update Rx Statistic Counter and copy Rx buffer
*
@@ -467,12 +463,10 @@ STAvUpdateTDStatCounter (
}
if ( !(byTSR & (TSR_TMO | TSR_RETRYTMO))) {
-#ifdef Calcu_LinkQual
if (byRetyCnt < 2)
pStatistic->TxNoRetryOkCount ++;
else
pStatistic->TxRetryOkCount ++;
-#endif
pStatistic->ullTsrOK++;
pStatistic->CustomStat.ullTsrAllOK++;
@@ -493,9 +487,7 @@ STAvUpdateTDStatCounter (
}
else {
-#ifdef Calcu_LinkQual
pStatistic->TxFailCount ++;
-#endif
pStatistic->dwTsrErr++;
if (byTSR & TSR_RETRYTMO)
@@ -591,10 +583,7 @@ STAvClear802_11Counter(PSDot11Counters p802_11Counter)
*
*/
-void
-STAvUpdateUSBCounter(PSUSBCounter pUsbCounter,
- NTSTATUS ntStatus
- )
+void STAvUpdateUSBCounter(PSUSBCounter pUsbCounter, int ntStatus)
{
// if ( ntStatus == USBD_STATUS_CRC ) {
@@ -602,5 +591,3 @@ STAvUpdateUSBCounter(PSUSBCounter pUsbCounter,
// }
}
-
-
diff --git a/drivers/staging/vt6656/mib.h b/drivers/staging/vt6656/mib.h
index 0455ec9d327..a89cca0c5ec 100644
--- a/drivers/staging/vt6656/mib.h
+++ b/drivers/staging/vt6656/mib.h
@@ -356,7 +356,6 @@ typedef struct tagSStatCounter {
SCustomCounters CustomStat;
- #ifdef Calcu_LinkQual
//Tx count:
unsigned long TxNoRetryOkCount; /* success tx no retry ! */
unsigned long TxRetryOkCount; /* success tx but retry ! */
@@ -367,12 +366,9 @@ typedef struct tagSStatCounter {
//statistic
unsigned long SignalStren;
unsigned long LinkQuality;
- #endif
} SStatCounter, *PSStatCounter;
-#define NTSTATUS int
-
/*--------------------- Export Classes ----------------------------*/
/*--------------------- Export Variables --------------------------*/
@@ -381,7 +377,9 @@ typedef struct tagSStatCounter {
void STAvClearAllCounter(PSStatCounter pStatistic);
-void STAvUpdateIsrStatCounter (PSStatCounter pStatistic, BYTE byIsr0, BYTE byIsr1);
+void STAvUpdateIsrStatCounter(PSStatCounter pStatistic,
+ BYTE byIsr0,
+ BYTE byIsr1);
void STAvUpdateRDStatCounter(PSStatCounter pStatistic,
BYTE byRSR, BYTE byNewRSR, BYTE byRxSts,
@@ -393,14 +391,8 @@ void STAvUpdateRDStatCounterEx(PSStatCounter pStatistic,
BYTE byRxRate, PBYTE pbyBuffer,
unsigned int cbFrameLength);
-void
-STAvUpdateTDStatCounter (
- PSStatCounter pStatistic,
- BYTE byPktNum,
- BYTE byRate,
- BYTE byTSR
- );
-
+void STAvUpdateTDStatCounter(PSStatCounter pStatistic, BYTE byPktNum,
+ BYTE byRate, BYTE byTSR);
void
STAvUpdate802_11Counter(
@@ -413,11 +405,6 @@ STAvUpdate802_11Counter(
);
void STAvClear802_11Counter(PSDot11Counters p802_11Counter);
-
-void
-STAvUpdateUSBCounter(
- PSUSBCounter pUsbCounter,
- NTSTATUS ntStatus
- );
+void STAvUpdateUSBCounter(PSUSBCounter pUsbCounter, int ntStatus);
#endif /* __MIB_H__ */
diff --git a/drivers/staging/vt6656/michael.c b/drivers/staging/vt6656/michael.c
index 671a8cf33e2..4d419814f27 100644
--- a/drivers/staging/vt6656/michael.c
+++ b/drivers/staging/vt6656/michael.c
@@ -74,7 +74,7 @@ static DWORD s_dwGetUINT32 (BYTE * p)
{
DWORD res = 0;
unsigned int i;
- for(i=0; i<4; i++ )
+ for (i = 0; i < 4; i++)
res |= (*p++) << (8*i);
return res;
}
@@ -83,7 +83,7 @@ static void s_vPutUINT32(BYTE *p, DWORD val)
// Convert from DWORD to BYTE[] in a portable way
{
unsigned int i;
- for(i=0; i<4; i++ ) {
+ for (i = 0; i < 4; i++) {
*p++ = (BYTE) (val & 0xff);
val >>= 8;
}
diff --git a/drivers/staging/vt6656/michael.h b/drivers/staging/vt6656/michael.h
index 3ab60928ef3..81351f50623 100644
--- a/drivers/staging/vt6656/michael.h
+++ b/drivers/staging/vt6656/michael.h
@@ -49,8 +49,8 @@ void MIC_vGetMIC(PDWORD pdwL, PDWORD pdwR);
/*--------------------- Export Macros ------------------------------*/
// Rotation functions on 32 bit values
-#define ROL32( A, n ) \
- ( ((A) << (n)) | ( ((A)>>(32-(n))) & ( (1UL << (n)) - 1 ) ) )
-#define ROR32( A, n ) ROL32( (A), 32-(n) )
+#define ROL32(A, n) \
+ (((A) << (n)) | (((A)>>(32-(n))) & ((1UL << (n)) - 1)))
+#define ROR32(A, n) ROL32((A), 32-(n))
#endif /* __MICHAEL_H__ */
diff --git a/drivers/staging/vt6656/power.c b/drivers/staging/vt6656/power.c
index 766c5be6fd2..4d7d4e014d0 100644
--- a/drivers/staging/vt6656/power.c
+++ b/drivers/staging/vt6656/power.c
@@ -19,7 +19,7 @@
*
* File: power.c
*
- * Purpose: Handles 802.11 power managment functions
+ * Purpose: Handles 802.11 power management functions
*
* Author: Lyndon Chen
*
@@ -290,17 +290,11 @@ BOOL PSbSendNullPacket(void *hDeviceContext)
return FALSE;
}
-//2007-0115-03<Add>by MikeLiu
-#ifdef TxInSleep
if ((pDevice->bEnablePSMode == FALSE) &&
(pDevice->fTxDataInSleep == FALSE)){
return FALSE;
}
-#else
- if (pDevice->bEnablePSMode == FALSE) {
- return FALSE;
- }
-#endif
+
memset(pMgmt->pbyPSPacketPool, 0, sizeof(STxMgmtPacket) + WLAN_NULLDATA_FR_MAXLEN);
pTxPacket = (PSTxMgmtPacket)pMgmt->pbyPSPacketPool;
pTxPacket->p80211Header = (PUWLAN_80211HDR)((PBYTE)pTxPacket + sizeof(STxMgmtPacket));
diff --git a/drivers/staging/vt6656/power.h b/drivers/staging/vt6656/power.h
index 50792bb8c97..41bffe528b4 100644
--- a/drivers/staging/vt6656/power.h
+++ b/drivers/staging/vt6656/power.h
@@ -18,7 +18,7 @@
*
* File: power.h
*
- * Purpose: Handles 802.11 power managment functions
+ * Purpose: Handles 802.11 power management functions
*
* Author: Lyndon Chen
*
diff --git a/drivers/staging/vt6656/rf.h b/drivers/staging/vt6656/rf.h
index d4f8b94132b..f5ba8fd7f81 100644
--- a/drivers/staging/vt6656/rf.h
+++ b/drivers/staging/vt6656/rf.h
@@ -64,11 +64,7 @@ extern const BYTE RFaby11aChannelIndex[200];
/*--------------------- Export Functions --------------------------*/
BOOL IFRFbWriteEmbeded(PSDevice pDevice, DWORD dwData);
-BOOL RFbSetPower (
- PSDevice pDevice,
- unsigned int uRATE,
- unsigned int uCH
- );
+BOOL RFbSetPower(PSDevice pDevice, unsigned int uRATE, unsigned int uCH);
BOOL RFbRawSetPower(
PSDevice pDevice,
@@ -76,17 +72,8 @@ BOOL RFbRawSetPower(
unsigned int uRATE
);
-void
-RFvRSSITodBm (
- PSDevice pDevice,
- BYTE byCurrRSSI,
- long * pldBm
- );
-
-void
-RFbRFTableDownload (
- PSDevice pDevice
- );
+void RFvRSSITodBm(PSDevice pDevice, BYTE byCurrRSSI, long *pldBm);
+void RFbRFTableDownload(PSDevice pDevice);
BOOL s_bVT3226D0_11bLoCurrentAdjust(
PSDevice pDevice,
diff --git a/drivers/staging/vt6656/rndis.h b/drivers/staging/vt6656/rndis.h
index ac842dd13a6..fccf7e98eb6 100644
--- a/drivers/staging/vt6656/rndis.h
+++ b/drivers/staging/vt6656/rndis.h
@@ -152,7 +152,7 @@ typedef struct _CMD_CHANGE_BBTYPE
/*--------------------- Export Macros -------------------------*/
-#define EXCH_WORD(w) ( (WORD)((WORD)(w)<<8) | (WORD)((WORD)(w)>>8) )
+#define EXCH_WORD(w) ((WORD)((WORD)(w)<<8) | (WORD)((WORD)(w)>>8))
/*--------------------- Export Variables --------------------------*/
diff --git a/drivers/staging/vt6656/rxtx.c b/drivers/staging/vt6656/rxtx.c
index 3e7e56649a5..deca2137d92 100644
--- a/drivers/staging/vt6656/rxtx.c
+++ b/drivers/staging/vt6656/rxtx.c
@@ -61,10 +61,7 @@
#include "rf.h"
#include "datarate.h"
#include "usbpipe.h"
-
-#ifdef WPA_SM_Transtatus
#include "iocmd.h"
-#endif
/*--------------------- Static Definitions -------------------------*/
@@ -304,10 +301,9 @@ s_vSaveTxPktInfo(PSDevice pDevice, BYTE byPktNum, PBYTE pbyDestAddr, WORD wPktLe
{
PSStatCounter pStatistic=&(pDevice->scStatistic);
-
- if (IS_BROADCAST_ADDRESS(pbyDestAddr))
+ if (is_broadcast_ether_addr(pbyDestAddr))
pStatistic->abyTxPktInfo[byPktNum].byBroadMultiUni = TX_PKT_BROAD;
- else if (IS_MULTICAST_ADDRESS(pbyDestAddr))
+ else if (is_multicast_ether_addr(pbyDestAddr))
pStatistic->abyTxPktInfo[byPktNum].byBroadMultiUni = TX_PKT_MULTI;
else
pStatistic->abyTxPktInfo[byPktNum].byBroadMultiUni = TX_PKT_UNI;
@@ -319,9 +315,6 @@ s_vSaveTxPktInfo(PSDevice pDevice, BYTE byPktNum, PBYTE pbyDestAddr, WORD wPktLe
ETH_ALEN);
}
-
-
-
static
void
s_vFillTxKey (
@@ -1473,7 +1466,7 @@ s_bPacketToWirelessUsb(
memset(pTxBufHead, 0, sizeof(TX_BUFFER));
// Get pkt type
- if (ntohs(psEthHeader->wType) > MAX_DATA_LEN) {
+ if (ntohs(psEthHeader->wType) > ETH_DATA_LEN) {
if (pDevice->dwDiagRefCount == 0) {
cb802_1_H_len = 8;
} else {
@@ -1492,17 +1485,16 @@ s_bPacketToWirelessUsb(
bNeedACK = FALSE;
pTxBufHead->wFIFOCtl = pTxBufHead->wFIFOCtl & (~FIFOCTL_NEEDACK);
} else { //if (pDevice->dwDiagRefCount != 0) {
- if ((pDevice->eOPMode == OP_MODE_ADHOC) ||
- (pDevice->eOPMode == OP_MODE_AP)) {
- if (IS_MULTICAST_ADDRESS(&(psEthHeader->abyDstAddr[0])) ||
- IS_BROADCAST_ADDRESS(&(psEthHeader->abyDstAddr[0]))) {
- bNeedACK = FALSE;
- pTxBufHead->wFIFOCtl = pTxBufHead->wFIFOCtl & (~FIFOCTL_NEEDACK);
- }
- else {
- bNeedACK = TRUE;
- pTxBufHead->wFIFOCtl |= FIFOCTL_NEEDACK;
- }
+ if ((pDevice->eOPMode == OP_MODE_ADHOC) ||
+ (pDevice->eOPMode == OP_MODE_AP)) {
+ if (is_multicast_ether_addr(psEthHeader->abyDstAddr)) {
+ bNeedACK = FALSE;
+ pTxBufHead->wFIFOCtl =
+ pTxBufHead->wFIFOCtl & (~FIFOCTL_NEEDACK);
+ } else {
+ bNeedACK = TRUE;
+ pTxBufHead->wFIFOCtl |= FIFOCTL_NEEDACK;
+ }
}
else {
// MSDUs in Infra mode always need ACK
@@ -1708,7 +1700,7 @@ s_bPacketToWirelessUsb(
}
// 802.1H
- if (ntohs(psEthHeader->wType) > MAX_DATA_LEN) {
+ if (ntohs(psEthHeader->wType) > ETH_DATA_LEN) {
if (pDevice->dwDiagRefCount == 0) {
if ( (psEthHeader->wType == TYPE_PKT_IPX) ||
(psEthHeader->wType == cpu_to_le16(0xF380))) {
@@ -2037,9 +2029,7 @@ CMD_STATUS csMgmt_xmit(
pTxBufHead->wFIFOCtl |= FIFOCTL_TMOEN;
pTxBufHead->wTimeStamp = cpu_to_le16(DEFAULT_MGN_LIFETIME_RES_64us);
-
- if (IS_MULTICAST_ADDRESS(&(pPacket->p80211Header->sA3.abyAddr1[0])) ||
- IS_BROADCAST_ADDRESS(&(pPacket->p80211Header->sA3.abyAddr1[0]))) {
+ if (is_multicast_ether_addr(pPacket->p80211Header->sA3.abyAddr1)) {
bNeedACK = FALSE;
}
else {
@@ -2446,9 +2436,7 @@ vDMA0_tx_80211(PSDevice pDevice, struct sk_buff *skb) {
pTxBufHead->wFIFOCtl |= FIFOCTL_TMOEN;
pTxBufHead->wTimeStamp = cpu_to_le16(DEFAULT_MGN_LIFETIME_RES_64us);
-
- if (IS_MULTICAST_ADDRESS(&(p80211Header->sA3.abyAddr1[0])) ||
- IS_BROADCAST_ADDRESS(&(p80211Header->sA3.abyAddr1[0]))) {
+ if (is_multicast_ether_addr(p80211Header->sA3.abyAddr1)) {
bNeedACK = FALSE;
if (pDevice->bEnableHostWEP) {
uNodeIndex = 0;
@@ -2741,14 +2729,7 @@ vDMA0_tx_80211(PSDevice pDevice, struct sk_buff *skb) {
* Return Value: NULL
*/
-
-
-NTSTATUS
-nsDMA_tx_packet(
- PSDevice pDevice,
- unsigned int uDMAIdx,
- struct sk_buff *skb
- )
+int nsDMA_tx_packet(PSDevice pDevice, unsigned int uDMAIdx, struct sk_buff *skb)
{
PSMgmtObject pMgmt = &(pDevice->sMgmtObj);
unsigned int BytesToWrite = 0, uHeaderLen = 0;
@@ -2770,9 +2751,6 @@ nsDMA_tx_packet(
unsigned int status;
WORD wKeepRate = pDevice->wCurrentRate;
struct net_device_stats* pStats = &pDevice->stats;
-//#ifdef WPA_SM_Transtatus
- // extern SWPAResult wpa_Result;
-//#endif
BOOL bTxeapol_key = FALSE;
@@ -2783,7 +2761,7 @@ nsDMA_tx_packet(
return 0;
}
- if (IS_MULTICAST_ADDRESS((PBYTE)(skb->data))) {
+ if (is_multicast_ether_addr((PBYTE)(skb->data))) {
uNodeIndex = 0;
bNodeExist = TRUE;
if (pMgmt->sNodeDBTable[0].bPSEnable) {
@@ -2975,7 +2953,7 @@ nsDMA_tx_packet(
else {
if (pDevice->eOPMode == OP_MODE_ADHOC) {
// Adhoc Tx rate decided from node DB
- if (IS_MULTICAST_ADDRESS(&(pDevice->sTxEthHeader.abyDstAddr[0]))) {
+ if (is_multicast_ether_addr(pDevice->sTxEthHeader.abyDstAddr)) {
// Multicast use highest data rate
pDevice->wCurrentRate = pMgmt->sNodeDBTable[0].wTxDataRate;
// preamble type
@@ -3071,28 +3049,12 @@ nsDMA_tx_packet(
}
else {
-#if 0
- if((pDevice->fWPA_Authened == FALSE) &&
- ((pMgmt->eAuthenMode == WMAC_AUTH_WPAPSK)||(pMgmt->eAuthenMode = WMAC_AUTH_WPA2PSK))){
- dev_kfree_skb_irq(skb);
- pStats->tx_dropped++;
- return STATUS_FAILURE;
- }
- else if (pTransmitKey == NULL) {
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"return no tx key\n");
- dev_kfree_skb_irq(skb);
- pStats->tx_dropped++;
- return STATUS_FAILURE;
- }
-#else
if (pTransmitKey == NULL) {
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"return no tx key\n");
dev_kfree_skb_irq(skb);
pStats->tx_dropped++;
return STATUS_FAILURE;
}
-#endif
-
}
}
@@ -3261,7 +3223,8 @@ bRelayPacketSend (
if (pDevice->wCurrentRate <= RATE_11M)
byPktType = PK_TYPE_11B;
- BytesToWrite = uDataLen + U_CRC_LEN;
+ BytesToWrite = uDataLen + ETH_FCS_LEN;
+
// Convert the packet to an usb frame and copy into our buffer
// and send the irp.
diff --git a/drivers/staging/vt6656/rxtx.h b/drivers/staging/vt6656/rxtx.h
index f90de42d7ab..f99acf1d8eb 100644
--- a/drivers/staging/vt6656/rxtx.h
+++ b/drivers/staging/vt6656/rxtx.h
@@ -683,9 +683,9 @@ bPacketToWirelessUsb(
);
void vDMA0_tx_80211(PSDevice pDevice, struct sk_buff *skb);
-NTSTATUS nsDMA_tx_packet(PSDevice pDevice,
- unsigned int uDMAIdx,
- struct sk_buff *skb);
+int nsDMA_tx_packet(PSDevice pDevice,
+ unsigned int uDMAIdx,
+ struct sk_buff *skb);
CMD_STATUS csMgmt_xmit(PSDevice pDevice, PSTxMgmtPacket pPacket);
CMD_STATUS csBeacon_xmit(PSDevice pDevice, PSTxMgmtPacket pPacket);
BOOL bRelayPacketSend(PSDevice pDevice, PBYTE pbySkbData,
diff --git a/drivers/staging/vt6656/tether.h b/drivers/staging/vt6656/tether.h
index d63586d5cdb..be87020d532 100644
--- a/drivers/staging/vt6656/tether.h
+++ b/drivers/staging/vt6656/tether.h
@@ -36,25 +36,10 @@
//
// constants
//
-#define U_CRC_LEN 4 //
#define U_ETHER_ADDR_STR_LEN (ETH_ALEN * 2 + 1)
// Ethernet address string length
-
-#define MIN_DATA_LEN 46 // min data length
-#define MAX_DATA_LEN 1500 // max data length
-
-#define MIN_PACKET_LEN (MIN_DATA_LEN + ETH_HLEN)
- // 60
- // min total packet length (tx)
-#define MAX_PACKET_LEN (MAX_DATA_LEN + ETH_HLEN)
- // 1514
- // max total packet length (tx)
-
-#define MAX_LOOKAHEAD_SIZE MAX_PACKET_LEN
-
#define U_MULTI_ADDR_LEN 8 // multicast address length
-
#ifdef __BIG_ENDIAN
#define TYPE_PKT_IP 0x0800 //
@@ -168,7 +153,7 @@ typedef struct tagSEthernetHeader {
BYTE abyDstAddr[ETH_ALEN];
BYTE abySrcAddr[ETH_ALEN];
WORD wType;
-}__attribute__ ((__packed__))
+} __attribute__ ((__packed__))
SEthernetHeader, *PSEthernetHeader;
@@ -179,7 +164,7 @@ typedef struct tagS802_3Header {
BYTE abyDstAddr[ETH_ALEN];
BYTE abySrcAddr[ETH_ALEN];
WORD wLen;
-}__attribute__ ((__packed__))
+} __attribute__ ((__packed__))
S802_3Header, *PS802_3Header;
//
@@ -193,30 +178,10 @@ typedef struct tagS802_11Header {
BYTE abyAddr3[ETH_ALEN];
WORD wSeqCtl;
BYTE abyAddr4[ETH_ALEN];
-}__attribute__ ((__packed__))
+} __attribute__ ((__packed__))
S802_11Header, *PS802_11Header;
/*--------------------- Export Macros ------------------------------*/
-// Frame type macro
-
-#define IS_MULTICAST_ADDRESS(pbyEtherAddr) \
- ((*(PBYTE)(pbyEtherAddr) & 0x01) == 1)
-
-#define IS_BROADCAST_ADDRESS(pbyEtherAddr) ( \
- (*(PDWORD)(pbyEtherAddr) == 0xFFFFFFFFL) && \
- (*(PWORD)((PBYTE)(pbyEtherAddr) + 4) == 0xFFFF) \
-)
-
-#define IS_NULL_ADDRESS(pbyEtherAddr) ( \
- (*(PDWORD)(pbyEtherAddr) == 0L) && \
- (*(PWORD)((PBYTE)(pbyEtherAddr) + 4) == 0) \
-)
-
-#define IS_ETH_ADDRESS_EQUAL(pbyAddr1, pbyAddr2) ( \
- (*(PDWORD)(pbyAddr1) == *(PDWORD)(pbyAddr2)) && \
- (*(PWORD)((PBYTE)(pbyAddr1) + 4) == \
- *(PWORD)((PBYTE)(pbyAddr2) + 4)) \
-)
/*--------------------- Export Classes ----------------------------*/
diff --git a/drivers/staging/vt6656/tkip.c b/drivers/staging/vt6656/tkip.c
index f83af5913aa..a6bd533f957 100644
--- a/drivers/staging/vt6656/tkip.c
+++ b/drivers/staging/vt6656/tkip.c
@@ -129,8 +129,6 @@ const BYTE TKIP_Sbox_Upper[256] = {
//STKIPKeyManagement sTKIPKeyTable[MAX_TKIP_KEY];
/*--------------------- Static Functions --------------------------*/
-unsigned int tkip_sbox(unsigned int index);
-unsigned int rotr1(unsigned int a);
/*--------------------- Export Variables --------------------------*/
@@ -139,7 +137,7 @@ unsigned int rotr1(unsigned int a);
/* Returns a 16 bit value from a 64K entry table. The Table */
/* is synthesized from two 256 entry byte wide tables. */
/************************************************************/
-unsigned int tkip_sbox(unsigned int index)
+static unsigned int tkip_sbox(unsigned int index)
{
unsigned int index_low;
unsigned int index_high;
@@ -155,7 +153,7 @@ unsigned int tkip_sbox(unsigned int index)
};
-unsigned int rotr1(unsigned int a)
+static unsigned int rotr1(unsigned int a)
{
unsigned int b;
diff --git a/drivers/staging/vt6656/ttype.h b/drivers/staging/vt6656/ttype.h
index c27f9858e2e..8e9450ef399 100644
--- a/drivers/staging/vt6656/ttype.h
+++ b/drivers/staging/vt6656/ttype.h
@@ -31,23 +31,6 @@
/******* Common definitions and typedefs ***********************************/
-//2007-0115-05<Add>by MikeLiu
-#ifndef TxInSleep
-#define TxInSleep
-#endif
-
-//DavidWang
-
-//2007-0814-01<Add>by MikeLiu
-#ifndef Safe_Close
-#define Safe_Close
-#endif
-
-//2008-0131-02<Add>by MikeLiu
-#ifndef Adhoc_STA
-#define Adhoc_STA
-#endif
-
typedef int BOOL;
#if !defined(TRUE)
@@ -57,19 +40,6 @@ typedef int BOOL;
#define FALSE 0
#endif
-//2007-0809-01<Add>by MikeLiu
-#ifndef update_BssList
-#define update_BssList
-#endif
-
-#ifndef WPA_SM_Transtatus
-#define WPA_SM_Transtatus
-#endif
-
-#ifndef Calcu_LinkQual
-#define Calcu_LinkQual
-#endif
-
/****** Simple typedefs ***************************************************/
typedef unsigned char BYTE; // 8-bit
@@ -94,7 +64,6 @@ typedef unsigned long ULONG_PTR; // 32-bit
typedef unsigned long DWORD_PTR; // 32-bit
// boolean pointer
-typedef unsigned int * PUINT;
typedef BYTE * PBYTE;
diff --git a/drivers/staging/vt6656/usbpipe.c b/drivers/staging/vt6656/usbpipe.c
index fd2355e34fb..a32785cb9d1 100644
--- a/drivers/staging/vt6656/usbpipe.c
+++ b/drivers/staging/vt6656/usbpipe.c
@@ -107,10 +107,7 @@ s_nsControlInUsbIoCompleteWrite(
/*--------------------- Export Functions --------------------------*/
-
-
-NTSTATUS
-PIPEnsControlOutAsyn(
+int PIPEnsControlOutAsyn(
PSDevice pDevice,
BYTE byRequest,
WORD wValue,
@@ -119,8 +116,7 @@ PIPEnsControlOutAsyn(
PBYTE pbyBuffer
)
{
- NTSTATUS ntStatus;
-
+ int ntStatus;
if (MP_TEST_FLAG(pDevice, fMP_DISCONNECTED))
return STATUS_FAILURE;
@@ -156,12 +152,7 @@ PIPEnsControlOutAsyn(
return ntStatus;
}
-
-
-
-
-NTSTATUS
-PIPEnsControlOut(
+int PIPEnsControlOut(
PSDevice pDevice,
BYTE byRequest,
WORD wValue,
@@ -170,10 +161,9 @@ PIPEnsControlOut(
PBYTE pbyBuffer
)
{
- NTSTATUS ntStatus = 0;
+ int ntStatus = 0;
int ii;
-
if (MP_TEST_FLAG(pDevice, fMP_DISCONNECTED))
return STATUS_FAILURE;
@@ -219,11 +209,7 @@ PIPEnsControlOut(
return STATUS_SUCCESS;
}
-
-
-
-NTSTATUS
-PIPEnsControlIn(
+int PIPEnsControlIn(
PSDevice pDevice,
BYTE byRequest,
WORD wValue,
@@ -232,7 +218,7 @@ PIPEnsControlIn(
PBYTE pbyBuffer
)
{
- NTSTATUS ntStatus = 0;
+ int ntStatus = 0;
int ii;
if (MP_TEST_FLAG(pDevice, fMP_DISCONNECTED))
@@ -360,13 +346,9 @@ s_nsControlInUsbIoCompleteRead(
* Return Value: STATUS_INSUFFICIENT_RESOURCES or result of IoCallDriver
*
*/
-NTSTATUS
-PIPEnsInterruptRead(
- PSDevice pDevice
- )
+int PIPEnsInterruptRead(PSDevice pDevice)
{
- NTSTATUS ntStatus = STATUS_FAILURE;
-
+ int ntStatus = STATUS_FAILURE;
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"---->s_nsStartInterruptUsbRead()\n");
@@ -381,29 +363,6 @@ PIPEnsInterruptRead(
// Now that we have created the urb, we will send a
// request to the USB device object.
//
-#if 0 //reserve int URB submit
- usb_fill_int_urb(pDevice->pInterruptURB,
- pDevice->usb,
- usb_rcvintpipe(pDevice->usb, 1),
- (void *) pDevice->intBuf.pDataBuf,
- MAX_INTERRUPT_SIZE,
- s_nsInterruptUsbIoCompleteRead,
- pDevice,
- pDevice->int_interval
- );
-#else //replace int URB submit by bulk transfer
-#ifndef Safe_Close
- usb_fill_int_urb(pDevice->pInterruptURB,
- pDevice->usb,
- usb_rcvintpipe(pDevice->usb, 1),
- (void *) pDevice->intBuf.pDataBuf,
- MAX_INTERRUPT_SIZE,
- s_nsInterruptUsbIoCompleteRead,
- pDevice,
- pDevice->int_interval
- );
-#else
-
pDevice->pInterruptURB->interval = pDevice->int_interval;
usb_fill_bulk_urb(pDevice->pInterruptURB,
@@ -413,8 +372,6 @@ usb_fill_bulk_urb(pDevice->pInterruptURB,
MAX_INTERRUPT_SIZE,
s_nsInterruptUsbIoCompleteRead,
pDevice);
-#endif
-#endif
ntStatus = usb_submit_urb(pDevice->pInterruptURB, GFP_ATOMIC);
if (ntStatus != 0) {
@@ -448,8 +405,7 @@ s_nsInterruptUsbIoCompleteRead(
{
PSDevice pDevice;
- NTSTATUS ntStatus;
-
+ int ntStatus;
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"---->s_nsInterruptUsbIoCompleteRead\n");
//
@@ -495,13 +451,6 @@ s_nsInterruptUsbIoCompleteRead(
if (pDevice->fKillEventPollingThread != TRUE) {
- #if 0 //reserve int URB submit
- ntStatus = usb_submit_urb(urb, GFP_ATOMIC);
- if (ntStatus != 0) {
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Re-Submit int URB failed %d\n", ntStatus);
- }
- #else //replace int URB submit by bulk transfer
- #ifdef Safe_Close
usb_fill_bulk_urb(pDevice->pInterruptURB,
pDevice->usb,
usb_rcvbulkpipe(pDevice->usb, 1),
@@ -514,11 +463,6 @@ s_nsInterruptUsbIoCompleteRead(
if (ntStatus != 0) {
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Submit int URB failed %d\n", ntStatus);
}
-
- #else
- tasklet_schedule(&pDevice->EventWorkItem);
- #endif
-#endif
}
//
// We return STATUS_MORE_PROCESSING_REQUIRED so that the completion
@@ -540,13 +484,9 @@ s_nsInterruptUsbIoCompleteRead(
* Return Value: STATUS_INSUFFICIENT_RESOURCES or result of IoCallDriver
*
*/
-NTSTATUS
-PIPEnsBulkInUsbRead(
- PSDevice pDevice,
- PRCB pRCB
- )
+int PIPEnsBulkInUsbRead(PSDevice pDevice, PRCB pRCB)
{
- NTSTATUS ntStatus= 0;
+ int ntStatus = 0;
struct urb *pUrb;
@@ -616,9 +556,7 @@ s_nsBulkInUsbIoCompleteRead(
unsigned long bytesRead;
BOOL bIndicateReceive = FALSE;
BOOL bReAllocSkb = FALSE;
- NTSTATUS status;
-
-
+ int status;
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"---->s_nsBulkInUsbIoCompleteRead\n");
status = urb->status;
@@ -628,9 +566,7 @@ s_nsBulkInUsbIoCompleteRead(
pDevice->ulBulkInError++;
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"BULK In failed %d\n", status);
- #ifdef Calcu_LinkQual
pDevice->scStatistic.RxFcsErrCnt ++;
- #endif
//todo...xxxxxx
// if (status == USBD_STATUS_CRC) {
// pDevice->ulBulkInContCRCError++;
@@ -644,9 +580,7 @@ s_nsBulkInUsbIoCompleteRead(
pDevice->ulBulkInContCRCError = 0;
pDevice->ulBulkInBytesRead += bytesRead;
- #ifdef Calcu_LinkQual
pDevice->scStatistic.RxOkCnt ++;
- #endif
}
@@ -690,7 +624,7 @@ PIPEnsSendBulkOut(
PUSB_SEND_CONTEXT pContext
)
{
- NTSTATUS status;
+ int status;
struct urb *pUrb;
@@ -771,7 +705,7 @@ s_nsBulkOutIoCompleteWrite(
)
{
PSDevice pDevice;
- NTSTATUS status;
+ int status;
CONTEXT_TYPE ContextType;
unsigned long ulBufLen;
PUSB_SEND_CONTEXT pContext;
@@ -803,10 +737,7 @@ s_nsBulkOutIoCompleteWrite(
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Write %d bytes\n",(int)ulBufLen);
pDevice->ulBulkOutBytesWrite += ulBufLen;
pDevice->ulBulkOutContCRCError = 0;
- //2007-0115-06<Add>by MikeLiu
- #ifdef TxInSleep
- pDevice->nTxDataTimeCout = 0;
- #endif
+ pDevice->nTxDataTimeCout = 0;
} else {
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"BULK Out failed %d\n", status);
diff --git a/drivers/staging/vt6656/usbpipe.h b/drivers/staging/vt6656/usbpipe.h
index f852b39027a..b3673474a9e 100644
--- a/drivers/staging/vt6656/usbpipe.h
+++ b/drivers/staging/vt6656/usbpipe.h
@@ -41,8 +41,7 @@
/*--------------------- Export Functions --------------------------*/
-NTSTATUS
-PIPEnsControlOut(
+int PIPEnsControlOut(
PSDevice pDevice,
BYTE byRequest,
WORD wValue,
@@ -51,10 +50,7 @@ PIPEnsControlOut(
PBYTE pbyBuffer
);
-
-
-NTSTATUS
-PIPEnsControlOutAsyn(
+int PIPEnsControlOutAsyn(
PSDevice pDevice,
BYTE byRequest,
WORD wValue,
@@ -63,8 +59,7 @@ PIPEnsControlOutAsyn(
PBYTE pbyBuffer
);
-NTSTATUS
-PIPEnsControlIn(
+int PIPEnsControlIn(
PSDevice pDevice,
BYTE byRequest,
WORD wValue,
@@ -73,24 +68,8 @@ PIPEnsControlIn(
PBYTE pbyBuffer
);
-
-
-
-NTSTATUS
-PIPEnsInterruptRead(
- PSDevice pDevice
- );
-
-NTSTATUS
-PIPEnsBulkInUsbRead(
- PSDevice pDevice,
- PRCB pRCB
- );
-
-NTSTATUS
-PIPEnsSendBulkOut(
- PSDevice pDevice,
- PUSB_SEND_CONTEXT pContext
- );
+int PIPEnsInterruptRead(PSDevice pDevice);
+int PIPEnsBulkInUsbRead(PSDevice pDevice, PRCB pRCB);
+int PIPEnsSendBulkOut(PSDevice pDevice, PUSB_SEND_CONTEXT pContext);
#endif /* __USBPIPE_H__ */
diff --git a/drivers/staging/vt6656/wcmd.c b/drivers/staging/vt6656/wcmd.c
index 72e21b6f0e8..686747a0929 100644
--- a/drivers/staging/vt6656/wcmd.c
+++ b/drivers/staging/vt6656/wcmd.c
@@ -565,11 +565,9 @@ void vRunCommand(void *hDeviceContext)
return;
}
-//20080131-03,<Add> by Mike Liu
- #ifdef Adhoc_STA
memcpy(pMgmt->abyAdHocSSID,pMgmt->abyDesireSSID,
((PWLAN_IE_SSID)pMgmt->abyDesireSSID)->len + WLAN_IEHDR_LEN);
- #endif
+
pItemSSID = (PWLAN_IE_SSID)pMgmt->abyDesireSSID;
pItemSSIDCurr = (PWLAN_IE_SSID)pMgmt->abyCurrSSID;
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO" cmd: desire ssid = %s\n", pItemSSID->abySSID);
@@ -716,18 +714,6 @@ void vRunCommand(void *hDeviceContext)
return;
}
pDevice->byLinkWaitCount = 0;
- #if 0
- #ifdef WPA_SUPPLICANT_DRIVER_WEXT_SUPPORT
- // if(pDevice->bWPASuppWextEnabled == TRUE)
- {
- union iwreq_data wrqu;
- memset(&wrqu, 0, sizeof (wrqu));
- wrqu.ap_addr.sa_family = ARPHRD_ETHER;
- printk("wireless_send_event--->SIOCGIWAP(disassociated:AUTHENTICATE_WAIT_timeout)\n");
- wireless_send_event(pDevice->dev, SIOCGIWAP, &wrqu, NULL);
- }
- #endif
- #endif
s_bCommandComplete(pDevice);
break;
@@ -754,8 +740,6 @@ void vRunCommand(void *hDeviceContext)
netif_wake_queue(pDevice->dev);
}
- //2007-0115-07<Add>by MikeLiu
- #ifdef TxInSleep
if(pDevice->IsTxDataTrigger != FALSE) { //TxDataTimer is not triggered at the first time
// printk("Re-initial TxDataTimer****\n");
del_timer(&pDevice->sTimerTxData);
@@ -771,7 +755,6 @@ void vRunCommand(void *hDeviceContext)
}
pDevice->IsTxDataTrigger = TRUE;
add_timer(&pDevice->sTimerTxData);
- #endif
}
else if(pMgmt->eCurrState < WMAC_STATE_ASSOCPENDING) {
@@ -785,18 +768,6 @@ void vRunCommand(void *hDeviceContext)
return;
}
pDevice->byLinkWaitCount = 0;
- #if 0
- #ifdef WPA_SUPPLICANT_DRIVER_WEXT_SUPPORT
- // if(pDevice->bWPASuppWextEnabled == TRUE)
- {
- union iwreq_data wrqu;
- memset(&wrqu, 0, sizeof (wrqu));
- wrqu.ap_addr.sa_family = ARPHRD_ETHER;
- printk("wireless_send_event--->SIOCGIWAP(disassociated:ASSOCIATE_WAIT_timeout)\n");
- wireless_send_event(pDevice->dev, SIOCGIWAP, &wrqu, NULL);
- }
- #endif
- #endif
s_bCommandComplete(pDevice);
break;
@@ -907,7 +878,7 @@ void vRunCommand(void *hDeviceContext)
// CARDbRadioPowerOff(pDevice);
//2008-09-09<Add> BY Mike:Hot Key for Radio On/Off
{
- NTSTATUS ntStatus = STATUS_SUCCESS;
+ int ntStatus = STATUS_SUCCESS;
BYTE byTmp;
ntStatus = CONTROLnsRequestIn(pDevice,
@@ -1300,8 +1271,6 @@ void vResetCommandTimer(void *hDeviceContext)
pDevice->bCmdClear = FALSE;
}
-//2007-0115-08<Add>by MikeLiu
-#ifdef TxInSleep
void BSSvSecondTxData(void *hDeviceContext)
{
PSDevice pDevice = (PSDevice)hDeviceContext;
@@ -1320,12 +1289,8 @@ void BSSvSecondTxData(void *hDeviceContext)
spin_lock_irq(&pDevice->lock);
//is wap_supplicant running successful OR only open && sharekey mode!
- #if 1
if(((pDevice->bLinkPass ==TRUE)&&(pMgmt->eAuthenMode < WMAC_AUTH_WPA)) || //open && sharekey linking
(pDevice->fWPA_Authened == TRUE)) { //wpa linking
- #else
- if(pDevice->bLinkPass ==TRUE) {
- #endif
// printk("mike:%s-->InSleep Tx Data Procedure\n",__FUNCTION__);
pDevice->fTxDataInSleep = TRUE;
PSbSendNullPacket(pDevice); //send null packet
@@ -1337,5 +1302,3 @@ void BSSvSecondTxData(void *hDeviceContext)
add_timer(&pDevice->sTimerTxData);
return;
}
-#endif
-
diff --git a/drivers/staging/vt6656/wcmd.h b/drivers/staging/vt6656/wcmd.h
index 09c4411c689..d24a79dce61 100644
--- a/drivers/staging/vt6656/wcmd.h
+++ b/drivers/staging/vt6656/wcmd.h
@@ -128,9 +128,6 @@ WCMDvCommandThread(
);
*/
-//2007-0115-09<Add>by MikeLiu
-#ifdef TxInSleep
void BSSvSecondTxData(void *hDeviceContext);
-#endif
#endif /* __WCMD_H__ */
diff --git a/drivers/staging/vt6656/wctl.c b/drivers/staging/vt6656/wctl.c
index 857ce0bc00a..c231ae7176f 100644
--- a/drivers/staging/vt6656/wctl.c
+++ b/drivers/staging/vt6656/wctl.c
@@ -79,7 +79,8 @@ BOOL WCTLbIsDuplicate (PSCache pCache, PS802_11Header pMACHeader)
for (ii = 0; ii < DUPLICATE_RX_CACHE_LENGTH; ii++) {
pCacheEntry = &(pCache->asCacheEntry[uIndex]);
if ((pCacheEntry->wFmSequence == pMACHeader->wSeqCtl) &&
- (IS_ETH_ADDRESS_EQUAL (&(pCacheEntry->abyAddr2[0]), &(pMACHeader->abyAddr2[0]))) &&
+ (!compare_ether_addr(&(pCacheEntry->abyAddr2[0]),
+ &(pMACHeader->abyAddr2[0]))) &&
(LOBYTE(pCacheEntry->wFrameCtl) == LOBYTE(pMACHeader->wFrameCtl))
) {
/* Duplicate match */
@@ -111,22 +112,21 @@ BOOL WCTLbIsDuplicate (PSCache pCache, PS802_11Header pMACHeader)
* Return Value: index number in Defragment Database
*
*/
+
unsigned int WCTLuSearchDFCB(PSDevice pDevice, PS802_11Header pMACHeader)
{
unsigned int ii;
- for(ii=0;ii<pDevice->cbDFCB;ii++) {
- if ((pDevice->sRxDFCB[ii].bInUse == TRUE) &&
- (IS_ETH_ADDRESS_EQUAL (&(pDevice->sRxDFCB[ii].abyAddr2[0]), &(pMACHeader->abyAddr2[0])))
- ) {
- //
- return(ii);
- }
- }
- return(pDevice->cbDFCB);
+ for (ii = 0; ii < pDevice->cbDFCB; ii++) {
+ if ((pDevice->sRxDFCB[ii].bInUse == TRUE) &&
+ (!compare_ether_addr(&(pDevice->sRxDFCB[ii].abyAddr2[0]),
+ &(pMACHeader->abyAddr2[0])))) {
+ return ii;
+ }
+ }
+ return pDevice->cbDFCB;
}
-
/*
* Description:
* Insert received fragment packet in Defragment Database
@@ -147,7 +147,7 @@ unsigned int WCTLuInsertDFCB(PSDevice pDevice, PS802_11Header pMACHeader)
if (pDevice->cbFreeDFCB == 0)
return(pDevice->cbDFCB);
- for(ii=0;ii<pDevice->cbDFCB;ii++) {
+ for (ii = 0; ii < pDevice->cbDFCB; ii++) {
if (pDevice->sRxDFCB[ii].bInUse == FALSE) {
pDevice->cbFreeDFCB--;
pDevice->sRxDFCB[ii].uLifetime = pDevice->dwMaxReceiveLifetime;
diff --git a/drivers/staging/vt6656/wmgr.c b/drivers/staging/vt6656/wmgr.c
index 93c15f0580f..e4eca9b060b 100644
--- a/drivers/staging/vt6656/wmgr.c
+++ b/drivers/staging/vt6656/wmgr.c
@@ -353,9 +353,9 @@ void vMgrObjectInit(void *hDeviceContext)
pMgmt->pbyPSPacketPool = &pMgmt->byPSPacketPool[0];
pMgmt->pbyMgmtPacketPool = &pMgmt->byMgmtPacketPool[0];
pMgmt->uCurrChannel = pDevice->uChannel;
- for(ii=0;ii<WLAN_BSSID_LEN;ii++) {
- pMgmt->abyDesireBSSID[ii] = 0xFF;
- }
+ for (ii = 0; ii < WLAN_BSSID_LEN; ii++)
+ pMgmt->abyDesireBSSID[ii] = 0xFF;
+
pMgmt->sAssocInfo.AssocInfo.Length = sizeof(NDIS_802_11_ASSOCIATION_INFORMATION);
//memset(pMgmt->abyDesireSSID, 0, WLAN_IEHDR_LEN + WLAN_SSID_MAXLEN +1);
pMgmt->byCSSPK = KEY_CTL_NONE;
@@ -373,8 +373,6 @@ void vMgrObjectInit(void *hDeviceContext)
pDevice->sTimerCommand.function = (TimerFunction)vRunCommand;
pDevice->sTimerCommand.expires = RUN_AT(HZ);
-//2007-0115-10<Add>by MikeLiu
- #ifdef TxInSleep
init_timer(&pDevice->sTimerTxData);
pDevice->sTimerTxData.data = (unsigned long)pDevice;
pDevice->sTimerTxData.function = (TimerFunction)BSSvSecondTxData;
@@ -382,7 +380,6 @@ void vMgrObjectInit(void *hDeviceContext)
pDevice->fTxDataInSleep = FALSE;
pDevice->IsTxDataTrigger = FALSE;
pDevice->nTxDataTimeCout = 0;
- #endif
pDevice->cbFreeCmdQueue = CMD_Q_SIZE;
pDevice->uCmdDequeueIdx = 0;
@@ -1056,7 +1053,6 @@ s_vMgrRxAssocResponse(
}
-#if 1
#ifdef WPA_SUPPLICANT_DRIVER_WEXT_SUPPORT
//need clear flags related to Networkmanager
pDevice->bwextstep0 = FALSE;
@@ -1065,7 +1061,6 @@ s_vMgrRxAssocResponse(
pDevice->bwextstep3 = FALSE;
pDevice->bWPASuppWextEnabled = FALSE;
#endif
-#endif
if(pMgmt->eCurrState == WMAC_STATE_ASSOC)
timer_expire(pDevice->sTimerCommand, 0);
@@ -1705,7 +1700,8 @@ s_vMgrRxDeauthentication(
pDevice->fWPA_Authened = FALSE;
DBG_PRT(MSG_LEVEL_NOTICE, KERN_INFO "AP deauthed me, reason=%d.\n", cpu_to_le16((*(sFrame.pwReason))));
// TODO: update BSS list for specific BSSID if pre-authentication case
- if (IS_ETH_ADDRESS_EQUAL(sFrame.pHdr->sA3.abyAddr3, pMgmt->abyCurrBSSID)) {
+ if (!compare_ether_addr(sFrame.pHdr->sA3.abyAddr3,
+ pMgmt->abyCurrBSSID)) {
if (pMgmt->eCurrState >= WMAC_STATE_AUTHPENDING) {
pMgmt->sNodeDBTable[0].bActive = FALSE;
pMgmt->eCurrMode = WMAC_MODE_STANDBY;
@@ -2471,11 +2467,8 @@ void vMgrCreateOwnIBSS(void *hDeviceContext,
pDevice->uCurrRSSI = 0;
pDevice->byCurrSQ = 0;
-//20080131-04,<Add> by Mike Liu
-#ifdef Adhoc_STA
memcpy(pMgmt->abyDesireSSID,pMgmt->abyAdHocSSID,
((PWLAN_IE_SSID)pMgmt->abyAdHocSSID)->len + WLAN_IEHDR_LEN);
-#endif
memset(pMgmt->abyCurrSSID, 0, WLAN_IEHDR_LEN + WLAN_SSID_MAXLEN + 1);
memcpy(pMgmt->abyCurrSSID,
@@ -3099,12 +3092,6 @@ s_vMgrSynchBSS (
PSMgmtObject pMgmt = &(pDevice->sMgmtObj);
/* unsigned int ii, uSameBssidNum=0; */
- // for (ii = 0; ii < MAX_BSS_NUM; ii++) {
- // if (pMgmt->sBSSList[ii].bActive &&
- // IS_ETH_ADDRESS_EQUAL(pMgmt->sBSSList[ii].abyBSSID, pCurr->abyBSSID)) {
- // uSameBssidNum++;
- // }
- // }
// if( uSameBssidNum>=2) { //we only check AP in hidden sssid mode
if ((pMgmt->eAuthenMode == WMAC_AUTH_WPAPSK) || //networkmanager 0.7.0 does not give the pairwise-key selsection,
(pMgmt->eAuthenMode == WMAC_AUTH_WPA2PSK)) { // so we need re-selsect it according to real pairwise-key info.
@@ -4795,21 +4782,21 @@ s_bCipherMatch (
byMulticastCipher = KEY_CTL_INVALID;
}
- // check Pairwise Key Cipher
- for(i=0;i<pBSSNode->wCSSPKCount;i++) {
- if ((pBSSNode->abyCSSPK[i] == WLAN_11i_CSS_WEP40) ||
- (pBSSNode->abyCSSPK[i] == WLAN_11i_CSS_WEP104)) {
- // this should not happen as defined 802.11i
- byCipherMask |= 0x01;
- } else if (pBSSNode->abyCSSPK[i] == WLAN_11i_CSS_TKIP) {
- byCipherMask |= 0x02;
- } else if (pBSSNode->abyCSSPK[i] == WLAN_11i_CSS_CCMP) {
- byCipherMask |= 0x04;
- } else if (pBSSNode->abyCSSPK[i] == WLAN_11i_CSS_USE_GROUP) {
- // use group key only ignore all others
- byCipherMask = 0;
- i = pBSSNode->wCSSPKCount;
- }
+ /* check Pairwise Key Cipher */
+ for (i = 0; i < pBSSNode->wCSSPKCount; i++) {
+ if ((pBSSNode->abyCSSPK[i] == WLAN_11i_CSS_WEP40) ||
+ (pBSSNode->abyCSSPK[i] == WLAN_11i_CSS_WEP104)) {
+ /* this should not happen as defined 802.11i */
+ byCipherMask |= 0x01;
+ } else if (pBSSNode->abyCSSPK[i] == WLAN_11i_CSS_TKIP) {
+ byCipherMask |= 0x02;
+ } else if (pBSSNode->abyCSSPK[i] == WLAN_11i_CSS_CCMP) {
+ byCipherMask |= 0x04;
+ } else if (pBSSNode->abyCSSPK[i] == WLAN_11i_CSS_USE_GROUP) {
+ /* use group key only ignore all others */
+ byCipherMask = 0;
+ i = pBSSNode->wCSSPKCount;
+ }
}
} else if ((WLAN_GET_CAP_INFO_PRIVACY(pBSSNode->wCapInfo) != 0) &&
@@ -4828,17 +4815,17 @@ s_bCipherMatch (
byMulticastCipher = KEY_CTL_INVALID;
}
- // check Pairwise Key Cipher
- for(i=0;i<pBSSNode->wPKCount;i++) {
- if (pBSSNode->abyPKType[i] == WPA_TKIP) {
- byCipherMask |= 0x02;
- } else if (pBSSNode->abyPKType[i] == WPA_AESCCMP) {
- byCipherMask |= 0x04;
- } else if (pBSSNode->abyPKType[i] == WPA_NONE) {
- // use group key only ignore all others
- byCipherMask = 0;
- i = pBSSNode->wPKCount;
- }
+ /* check Pairwise Key Cipher */
+ for (i = 0; i < pBSSNode->wPKCount; i++) {
+ if (pBSSNode->abyPKType[i] == WPA_TKIP) {
+ byCipherMask |= 0x02;
+ } else if (pBSSNode->abyPKType[i] == WPA_AESCCMP) {
+ byCipherMask |= 0x04;
+ } else if (pBSSNode->abyPKType[i] == WPA_NONE) {
+ /* use group key only ignore all others */
+ byCipherMask = 0;
+ i = pBSSNode->wPKCount;
+ }
}
}
diff --git a/drivers/staging/vt6656/wmgr.h b/drivers/staging/vt6656/wmgr.h
index 1e5b916aea1..683840c0ac4 100644
--- a/drivers/staging/vt6656/wmgr.h
+++ b/drivers/staging/vt6656/wmgr.h
@@ -82,7 +82,7 @@
/*--------------------- Export Types ------------------------------*/
//mike define: make timer to expire after desired times
-#define timer_expire(timer,next_tick) mod_timer(&timer, RUN_AT(next_tick))
+#define timer_expire(timer, next_tick) mod_timer(&timer, RUN_AT(next_tick))
typedef void (*TimerFunction)(unsigned long);
@@ -259,9 +259,7 @@ typedef struct tagSMgmtObject
// Operation state variables
WMAC_CURRENT_MODE eCurrMode; // MAC current connection mode
WMAC_BSS_STATE eCurrState; // MAC current BSS state
- #ifdef SndEvt_ToAPI
WMAC_BSS_STATE eLastState; // MAC last BSS state
- #endif
PKnownBSS pCurrBSS;
BYTE byCSSGK;
@@ -293,10 +291,7 @@ typedef struct tagSMgmtObject
BYTE abyDesireBSSID[WLAN_BSSID_LEN];
//restore BSS info for Ad-Hoc mode
-//20080131-05,<Add> by Mike Liu
-#ifdef Adhoc_STA
BYTE abyAdHocSSID[WLAN_IEHDR_LEN + WLAN_SSID_MAXLEN + 1];
-#endif
// Adhoc or AP configuration vars
WORD wIBSSBeaconPeriod;
@@ -343,11 +338,11 @@ typedef struct tagSMgmtObject
BOOL bRxBeaconInTBTTWake;
BYTE abyPSTxMap[MAX_NODE_NUM + 1];
- // managment command related
+ // management command related
unsigned int uCmdBusy;
unsigned int uCmdHostAPBusy;
- // managment packet pool
+ // management packet pool
PBYTE pbyMgmtPacketPool;
BYTE byMgmtPacketPool[sizeof(STxMgmtPacket) + WLAN_A3FR_MAXLEN];
diff --git a/drivers/staging/vt6656/wpa.c b/drivers/staging/vt6656/wpa.c
index 1fa6c9b88ed..f492778ee8b 100644
--- a/drivers/staging/vt6656/wpa.c
+++ b/drivers/staging/vt6656/wpa.c
@@ -148,7 +148,8 @@ WPA_ParseRSN (
{
j = 0;
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"wPKCount: %d, sizeof(pBSSList->abyPKType): %zu\n", pRSN->wPKCount, sizeof(pBSSList->abyPKType));
- for(i = 0; (i < pRSN->wPKCount) && (j < sizeof(pBSSList->abyPKType)/sizeof(BYTE)); i++) {
+ for (i = 0; (i < pRSN->wPKCount) &&
+ (j < sizeof(pBSSList->abyPKType)/sizeof(BYTE)); i++) {
if(pRSN->len >= 12+i*4+4) { //oui1(4)+ver(2)+GKS(4)+PKSCnt(2)+PKS(4*i)
if ( !memcmp(pRSN->PKSList[i].abyOUI, abyOUI00, 4))
pBSSList->abyPKType[j++] = WPA_NONE;
@@ -180,7 +181,8 @@ WPA_ParseRSN (
j = 0;
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"wAuthCount: %d, sizeof(pBSSList->abyAuthType): %zu\n",
pIE_RSN_Auth->wAuthCount, sizeof(pBSSList->abyAuthType));
- for(i = 0; (i < pIE_RSN_Auth->wAuthCount) && (j < sizeof(pBSSList->abyAuthType)/sizeof(BYTE)); i++) {
+ for (i = 0; (i < pIE_RSN_Auth->wAuthCount) &&
+ (j < sizeof(pBSSList->abyAuthType)/sizeof(BYTE)); i++) {
if(pRSN->len >= 14+4+(m+i)*4) { //oui1(4)+ver(2)+GKS(4)+PKSCnt(2)+PKS(4*m)+AKC(2)+AKS(4*i)
if ( !memcmp(pIE_RSN_Auth->AuthKSList[i].abyOUI, abyOUI01, 4))
pBSSList->abyAuthType[j++] = WPA_AUTH_IEEE802_1X;
diff --git a/drivers/staging/vt6656/wpa2.h b/drivers/staging/vt6656/wpa2.h
index 429a910a5c5..46c295905b4 100644
--- a/drivers/staging/vt6656/wpa2.h
+++ b/drivers/staging/vt6656/wpa2.h
@@ -58,21 +58,9 @@ typedef struct tagSPMKIDCache {
/*--------------------- Export Functions --------------------------*/
-void
-WPA2_ClearRSN (
- PKnownBSS pBSSNode
- );
+void WPA2_ClearRSN(PKnownBSS pBSSNode);
+void WPA2vParseRSN(PKnownBSS pBSSNode, PWLAN_IE_RSN pRSN);
-void
-WPA2vParseRSN (
- PKnownBSS pBSSNode,
- PWLAN_IE_RSN pRSN
- );
-
-unsigned int
-WPA2uSetIEs(
- void *pMgmtHandle,
- PWLAN_IE_RSN pRSNIEs
- );
+unsigned int WPA2uSetIEs(void *pMgmtHandle, PWLAN_IE_RSN pRSNIEs);
#endif /* __WPA2_H__ */
diff --git a/drivers/staging/vt6656/wpactl.c b/drivers/staging/vt6656/wpactl.c
index 961f583368a..b407ae536bf 100644
--- a/drivers/staging/vt6656/wpactl.c
+++ b/drivers/staging/vt6656/wpactl.c
@@ -186,7 +186,6 @@ int wpa_set_wpadev(PSDevice pDevice, int val)
return wpa_release_wpadev(pDevice);
}
-
/*
* Description:
* Set WPA algorithm & keys
@@ -349,9 +348,8 @@ int wpa_set_wpadev(PSDevice pDevice, int val)
return -EINVAL;
}
-
- if (IS_BROADCAST_ADDRESS(&param->addr[0]) || (param->addr == NULL)) {
- // If IS_BROADCAST_ADDRESS, set the key as every key entry's group key.
+ if (is_broadcast_ether_addr(&param->addr[0]) || (param->addr == NULL)) {
+ /* if broadcast, set the key as every key entry's group key */
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Groupe Key Assign.\n");
if ((KeybSetAllGroupKey(pDevice,
@@ -404,7 +402,7 @@ int wpa_set_wpadev(PSDevice pDevice, int val)
} else {
// Key Table Full
- if (IS_ETH_ADDRESS_EQUAL(&param->addr[0], pDevice->abyBSSID)) {
+ if (!compare_ether_addr(&param->addr[0], pDevice->abyBSSID)) {
//DBG_PRN_WLAN03(("return NDIS_STATUS_INVALID_DATA -Key Table Full.2\n"));
return -EINVAL;
@@ -647,9 +645,9 @@ static int wpa_get_scan(PSDevice pDevice,
for (ii = 0; ii < MAX_BSS_NUM; ii++) {
- for(jj=0;jj<MAX_BSS_NUM-ii-1;jj++) {
+ for (jj = 0; jj < MAX_BSS_NUM - ii - 1; jj++) {
- if((pMgmt->sBSSList[jj].bActive!=TRUE) ||
+ if ((pMgmt->sBSSList[jj].bActive != TRUE) ||
((pMgmt->sBSSList[jj].uRSSI>pMgmt->sBSSList[jj+1].uRSSI) &&(pMgmt->sBSSList[jj+1].bActive!=FALSE))) {
diff --git a/drivers/staging/winbond/mac_structures.h b/drivers/staging/winbond/mac_structures.h
index 7441015cb18..415256f69c3 100644
--- a/drivers/staging/winbond/mac_structures.h
+++ b/drivers/staging/winbond/mac_structures.h
@@ -41,8 +41,10 @@
#define DOT_11_MAC_HEADER_SIZE 24
#define DOT_11_SNAP_SIZE 6
#define DOT_11_DURATION_OFFSET 2
-#define DOT_11_SEQUENCE_OFFSET 22 /* Sequence control offset */
-#define DOT_11_TYPE_OFFSET 30 /* The start offset of 802.11 Frame// */
+/* Sequence control offset */
+#define DOT_11_SEQUENCE_OFFSET 22
+/* The start offset of 802.11 Frame// */
+#define DOT_11_TYPE_OFFSET 30
#define DOT_11_DATA_OFFSET 24
#define DOT_11_DA_OFFSET 4
#define DOT_3_TYPE_ARP 0x80F3
@@ -98,28 +100,28 @@
#define ELEMENT_ID_CF_PARAMETER_SET 4
#define ELEMENT_ID_TIM 5
#define ELEMENT_ID_IBSS_PARAMETER_SET 6
-// 7~15 reserverd
+/* 7~15 reserverd */
#define ELEMENT_ID_CHALLENGE_TEXT 16
-// 17~31 reserved for challenge text extension
-// 32~255 reserved
-//-- 11G --
+/* 17~31 reserved for challenge text extension */
+/* 32~255 reserved */
+/*-- 11G -- */
#define ELEMENT_ID_ERP_INFORMATION 42
#define ELEMENT_ID_EXTENDED_SUPPORTED_RATES 50
-//-- WPA --
+/* -- WPA -- */
#define ELEMENT_ID_RSN_WPA 221
#ifdef _WPA2_
#define ELEMENT_ID_RSN_WPA2 48
-#endif //endif WPA2
+#endif /* endif WPA2 */
#define WLAN_MAX_PAIRWISE_CIPHER_SUITE_COUNT ((u16) 6)
#define WLAN_MAX_AUTH_KEY_MGT_SUITE_LIST_COUNT ((u16) 2)
-//===================================================================
-// Reason Code (Table 18): indicate the reason of DisAssoc, DeAuthen
-// length of ReasonCode is 2 Octs.
-//===================================================================
+/* ===================================================================
+* Reason Code (Table 18): indicate the reason of DisAssoc, DeAuthen
+* length of ReasonCode is 2 Octs.
+* =================================================================== */
#define REASON_REASERED 0
#define REASON_UNSPECIDIED 1
#define REASON_PREAUTH_INVALID 2
@@ -385,9 +387,11 @@ struct Extended_Supported_Rates_Element {
#ifdef _WPA2_
#define VERSION_WPA2 1
#endif /* end def _WPA2_ */
-#define OUI_WPA 0x00F25000 /* WPA2.0 OUI=00:50:F2, the MSB is reserved for suite type */
+/* WPA2.0 OUI=00:50:F2, the MSB is reserved for suite type */
+#define OUI_WPA 0x00F25000
#ifdef _WPA2_
-#define OUI_WPA2 0x00AC0F00 /* for wpa2 change to 0x00ACOF04 by Ws 26/04/04 */
+/* for wpa2 change to 0x00ACOF04 by Ws 26/04/04 */
+#define OUI_WPA2 0x00AC0F00
#endif /* end def _WPA2_ */
#define OUI_WPA_ADDITIONAL 0x01
@@ -400,8 +404,8 @@ struct Extended_Supported_Rates_Element {
#define WPA_OUI_BIG ((u32) 0x01F25000)/* added by ws 09/23/04 */
#define WPA_OUI_LITTLE ((u32) 0x01F25001)/* added by ws 09/23/04 */
-
-#define WPA_WPS_OUI cpu_to_le32(0x04F25000) /* 20061108 For WPS. It's little endian. Big endian is 0x0050F204 */
+/* 20061108 For WPS. It's little endian. Big endian is 0x0050F204 */
+#define WPA_WPS_OUI cpu_to_le32(0x04F25000)
/* -----WPA2----- */
#ifdef _WPA2_
@@ -420,75 +424,65 @@ struct Extended_Supported_Rates_Element {
#define OUI_CIPHER_CCMP 0x04
#define OUI_CIPHER_WEP_104 0x05
-struct suite_selector
-{
- union
- {
+struct suite_selector{
+ union{
u8 Value[4];
- struct _SUIT_
- {
+ struct _SUIT_ {
u8 OUI[3];
u8 Type;
- }SuitSelector;
+ } SuitSelector;
};
};
-//-- WPA --
-struct RSN_Information_Element
-{
+/* -- WPA -- */
+struct RSN_Information_Element{
u8 Element_ID;
u8 Length;
- struct suite_selector OuiWPAAdditional; /* WPA version 2.0 additional field, and should be 00:50:F2:01 */
+ /* WPA version 2.0 additional field, and should be 00:50:F2:01 */
+ struct suite_selector OuiWPAAdditional;
u16 Version;
struct suite_selector GroupKeySuite;
u16 PairwiseKeySuiteCount;
struct suite_selector PairwiseKeySuite[1];
-}__attribute__ ((packed));
-struct RSN_Auth_Sub_Information_Element
-{
+} __attribute__ ((packed));
+struct RSN_Auth_Sub_Information_Element {
u16 AuthKeyMngtSuiteCount;
struct suite_selector AuthKeyMngtSuite[1];
-}__attribute__ ((packed));
+} __attribute__ ((packed));
/* -- WPA2 -- */
-struct RSN_Capability_Element
-{
- union
- {
+struct RSN_Capability_Element {
+ union {
u16 __attribute__ ((packed)) wValue;
#ifdef _BIG_ENDIAN_ /* 20060927 add by anson's endian */
- struct _RSN_Capability
- {
- u16 __attribute__ ((packed)) Reserved2 : 8; /* 20051201 */
- u16 __attribute__ ((packed)) Reserved1 : 2;
- u16 __attribute__ ((packed)) GTK_Replay_Counter : 2;
- u16 __attribute__ ((packed)) PTK_Replay_Counter : 2;
- u16 __attribute__ ((packed)) No_Pairwise : 1;
- u16 __attribute__ ((packed)) Pre_Auth : 1;
- }__attribute__ ((packed)) RSN_Capability;
+ struct _RSN_Capability {
+ u16 __attribute__ ((packed)) Reserved2:8; /* 20051201 */
+ u16 __attribute__ ((packed)) Reserved1:2;
+ u16 __attribute__ ((packed)) GTK_Replay_Counter:2;
+ u16 __attribute__ ((packed)) PTK_Replay_Counter:2;
+ u16 __attribute__ ((packed)) No_Pairwise:1;
+ u16 __attribute__ ((packed)) Pre_Auth:1;
+ } __attribute__ ((packed)) RSN_Capability;
#else
- struct _RSN_Capability
- {
- u16 __attribute__ ((packed)) Pre_Auth : 1;
- u16 __attribute__ ((packed)) No_Pairwise : 1;
- u16 __attribute__ ((packed)) PTK_Replay_Counter : 2;
- u16 __attribute__ ((packed)) GTK_Replay_Counter : 2;
- u16 __attribute__ ((packed)) Reserved1 : 2;
- u16 __attribute__ ((packed)) Reserved2 : 8; /* 20051201 */
- }__attribute__ ((packed)) RSN_Capability;
+ struct _RSN_Capability {
+ u16 __attribute__ ((packed)) Pre_Auth:1;
+ u16 __attribute__ ((packed)) No_Pairwise:1;
+ u16 __attribute__ ((packed)) PTK_Replay_Counter:2;
+ u16 __attribute__ ((packed)) GTK_Replay_Counter:2;
+ u16 __attribute__ ((packed)) Reserved1:2;
+ u16 __attribute__ ((packed)) Reserved2:8; /* 20051201 */
+ } __attribute__ ((packed)) RSN_Capability;
#endif
- }__attribute__ ((packed)) ;
-}__attribute__ ((packed)) ;
+ } __attribute__ ((packed)) ;
+} __attribute__ ((packed)) ;
#ifdef _WPA2_
-struct pmkid
-{
+struct pmkid {
u8 pValue[16];
};
-struct WPA2_RSN_Information_Element
-{
+struct WPA2_RSN_Information_Element {
u8 Element_ID;
u8 Length;
u16 Version;
@@ -496,29 +490,28 @@ struct WPA2_RSN_Information_Element
u16 PairwiseKeySuiteCount;
struct suite_selector PairwiseKeySuite[1];
-}__attribute__ ((packed));
+} __attribute__ ((packed));
-struct WPA2_RSN_Auth_Sub_Information_Element
-{
+struct WPA2_RSN_Auth_Sub_Information_Element {
u16 AuthKeyMngtSuiteCount;
struct suite_selector AuthKeyMngtSuite[1];
-}__attribute__ ((packed));
+} __attribute__ ((packed));
-struct PMKID_Information_Element
-{
+struct PMKID_Information_Element {
u16 PMKID_Count;
struct pmkid pmkid[16];
-}__attribute__ ((packed));
+} __attribute__ ((packed));
#endif /* enddef _WPA2_ */
/*============================================================
// MAC Frame structure (different type) and subfield structure
//============================================================*/
-struct MAC_frame_control
-{
- u8 mac_frame_info; /* a combination of the [Protocol Version, Control Type, Control Subtype]*/
- #ifdef _BIG_ENDIAN_ /* 20060927 add by anson's endian */
+struct MAC_frame_control {
+/* a combination of the [Protocol Version, Control Type, Control Subtype]*/
+ u8 mac_frame_info;
+/* 20060927 add by anson's endian */
+ #ifdef _BIG_ENDIAN_
u8 order:1;
u8 WEP:1;
u8 more_data:1;
@@ -540,7 +533,8 @@ struct MAC_frame_control
} __attribute__ ((packed));
struct Management_Frame {
- struct MAC_frame_control frame_control; /* 2B, ToDS,FromDS,MoreFrag,MoreData,Order=0 */
+/* 2B, ToDS,FromDS,MoreFrag,MoreData,Order=0 */
+ struct MAC_frame_control frame_control;
u16 duration;
u8 DA[MAC_ADDR_LENGTH]; /* Addr1 */
u8 SA[MAC_ADDR_LENGTH]; /* Addr2 */
@@ -552,7 +546,8 @@ struct Management_Frame {
/* SW-MAC don't Tx/Rx Control-Frame, HW-MAC do it. */
struct Control_Frame {
- struct MAC_frame_control frame_control; /* ToDS,FromDS,MoreFrag,Retry,MoreData,WEP,Order=0 */
+/* ToDS,FromDS,MoreFrag,Retry,MoreData,WEP,Order=0 */
+ struct MAC_frame_control frame_control;
u16 duration;
u8 RA[MAC_ADDR_LENGTH];
u8 TA[MAC_ADDR_LENGTH];
@@ -627,8 +622,9 @@ struct Authentication_Frame_Body {
u16 algorithmNumber;
u16 sequenceNumber;
u16 statusCode;
- /* NB: don't include ChallengeText in this structure
- // struct Challenge_Text_Element sChallengeTextElement; // wkchen added */
+ /* NB: don't include ChallengeText in this structure
+ // struct Challenge_Text_Element sChallengeTextElement;
+ // wkchen added */
} __attribute__ ((packed));
diff --git a/drivers/staging/winbond/phy_calibration.c b/drivers/staging/winbond/phy_calibration.c
index 78935865df1..5c1f05392db 100644
--- a/drivers/staging/winbond/phy_calibration.c
+++ b/drivers/staging/winbond/phy_calibration.c
@@ -19,23 +19,25 @@
/****************** LOCAL CONSTANT AND MACRO SECTION ************************/
#define LOOP_TIMES 20
-#define US 1000//MICROSECOND
+#define US 1000/* MICROSECOND*/
#define AG_CONST 0.6072529350
#define FIXED(X) ((s32)((X) * 32768.0))
#define DEG2RAD(X) 0.017453 * (X)
-static const s32 Angles[] =
-{
- FIXED(DEG2RAD(45.0)), FIXED(DEG2RAD(26.565)), FIXED(DEG2RAD(14.0362)),
- FIXED(DEG2RAD(7.12502)), FIXED(DEG2RAD(3.57633)), FIXED(DEG2RAD(1.78991)),
- FIXED(DEG2RAD(0.895174)),FIXED(DEG2RAD(0.447614)),FIXED(DEG2RAD(0.223811)),
- FIXED(DEG2RAD(0.111906)),FIXED(DEG2RAD(0.055953)),FIXED(DEG2RAD(0.027977))
+static const s32 Angles[] = {
+ FIXED(DEG2RAD(45.0)), FIXED(DEG2RAD(26.565)), FIXED(DEG2RAD(14.0362)),
+ FIXED(DEG2RAD(7.12502)), FIXED(DEG2RAD(3.57633)), FIXED(DEG2RAD(1.78991)),
+ FIXED(DEG2RAD(0.895174)), FIXED(DEG2RAD(0.447614)), FIXED(DEG2RAD(0.223811)),
+ FIXED(DEG2RAD(0.111906)), FIXED(DEG2RAD(0.055953)), FIXED(DEG2RAD(0.027977))
};
/****************** LOCAL FUNCTION DECLARATION SECTION **********************/
-//void _phy_rf_write_delay(struct hw_data *phw_data);
-//void phy_init_rf(struct hw_data *phw_data);
+
+/*
+ * void _phy_rf_write_delay(struct hw_data *phw_data);
+ * void phy_init_rf(struct hw_data *phw_data);
+ */
/****************** FUNCTION DEFINITION SECTION *****************************/
@@ -46,9 +48,7 @@ s32 _s13_to_s32(u32 data)
val = (data & 0x0FFF);
if ((data & BIT(12)) != 0)
- {
val |= 0xFFFFF000;
- }
return ((s32) val);
}
@@ -58,13 +58,9 @@ u32 _s32_to_s13(s32 data)
u32 val;
if (data > 4095)
- {
data = 4095;
- }
else if (data < -4096)
- {
data = -4096;
- }
val = data & 0x1FFF;
@@ -79,9 +75,7 @@ s32 _s4_to_s32(u32 data)
val = (data & 0x0007);
if ((data & BIT(3)) != 0)
- {
val |= 0xFFFFFFF8;
- }
return val;
}
@@ -91,13 +85,9 @@ u32 _s32_to_s4(s32 data)
u32 val;
if (data > 7)
- {
data = 7;
- }
else if (data < -8)
- {
data = -8;
- }
val = data & 0x000F;
@@ -112,9 +102,7 @@ s32 _s5_to_s32(u32 data)
val = (data & 0x000F);
if ((data & BIT(4)) != 0)
- {
val |= 0xFFFFFFF0;
- }
return val;
}
@@ -124,13 +112,9 @@ u32 _s32_to_s5(s32 data)
u32 val;
if (data > 15)
- {
data = 15;
- }
else if (data < -16)
- {
data = -16;
- }
val = data & 0x001F;
@@ -145,9 +129,7 @@ s32 _s6_to_s32(u32 data)
val = (data & 0x001F);
if ((data & BIT(5)) != 0)
- {
val |= 0xFFFFFFE0;
- }
return val;
}
@@ -157,13 +139,9 @@ u32 _s32_to_s6(s32 data)
u32 val;
if (data > 31)
- {
data = 31;
- }
else if (data < -32)
- {
data = -32;
- }
val = data & 0x003F;
@@ -178,9 +156,7 @@ s32 _s9_to_s32(u32 data)
val = data & 0x00FF;
if ((data & BIT(8)) != 0)
- {
val |= 0xFFFFFF00;
- }
return val;
}
@@ -190,13 +166,9 @@ u32 _s32_to_s9(s32 data)
u32 val;
if (data > 255)
- {
data = 255;
- }
else if (data < -256)
- {
data = -256;
- }
val = data & 0x01FF;
@@ -207,21 +179,19 @@ u32 _s32_to_s9(s32 data)
s32 _floor(s32 n)
{
if (n > 0)
- {
- n += 5;
- }
+ n += 5;
else
- {
n -= 5;
- }
return (n/10);
}
/****************************************************************************/
-// The following code is sqare-root function.
-// sqsum is the input and the output is sq_rt;
-// The maximum of sqsum = 2^27 -1;
+/*
+ * The following code is sqare-root function.
+ * sqsum is the input and the output is sq_rt;
+ * The maximum of sqsum = 2^27 -1;
+ */
u32 _sqrt(u32 sqsum)
{
u32 sq_rt;
@@ -232,18 +202,17 @@ u32 _sqrt(u32 sqsum)
int step;
g4 = sqsum / 100000000;
- g3 = (sqsum - g4*100000000) /1000000;
- g2 = (sqsum - g4*100000000 - g3*1000000) /10000;
- g1 = (sqsum - g4*100000000 - g3*1000000 - g2*10000) /100;
+ g3 = (sqsum - g4*100000000) / 1000000;
+ g2 = (sqsum - g4*100000000 - g3*1000000) / 10000;
+ g1 = (sqsum - g4*100000000 - g3*1000000 - g2*10000) / 100;
g0 = (sqsum - g4*100000000 - g3*1000000 - g2*10000 - g1*100);
next = g4;
step = 0;
seed = 0;
- while (((seed+1)*(step+1)) <= next)
- {
- step++;
- seed++;
+ while (((seed+1)*(step+1)) <= next) {
+ step++;
+ seed++;
}
sq_rt = seed * 10000;
@@ -251,20 +220,18 @@ u32 _sqrt(u32 sqsum)
step = 0;
seed = 2 * seed * 10;
- while (((seed+1)*(step+1)) <= next)
- {
+ while (((seed+1)*(step+1)) <= next) {
step++;
- seed++;
+ seed++;
}
sq_rt = sq_rt + step * 1000;
next = (next - seed * step) * 100 + g2;
seed = (seed + step) * 10;
step = 0;
- while (((seed+1)*(step+1)) <= next)
- {
+ while (((seed+1)*(step+1)) <= next) {
step++;
- seed++;
+ seed++;
}
sq_rt = sq_rt + step * 100;
@@ -272,21 +239,19 @@ u32 _sqrt(u32 sqsum)
seed = (seed + step) * 10;
step = 0;
- while (((seed+1)*(step+1)) <= next)
- {
+ while (((seed+1)*(step+1)) <= next) {
step++;
- seed++;
+ seed++;
}
sq_rt = sq_rt + step * 10;
- next = (next - seed* step) * 100 + g0;
+ next = (next - seed * step) * 100 + g0;
seed = (seed + step) * 10;
step = 0;
- while (((seed+1)*(step+1)) <= next)
- {
+ while (((seed+1)*(step+1)) <= next) {
step++;
- seed++;
+ seed++;
}
sq_rt = sq_rt + step;
@@ -300,38 +265,31 @@ void _sin_cos(s32 angle, s32 *sin, s32 *cos)
s32 X, Y, TargetAngle, CurrAngle;
unsigned Step;
- X=FIXED(AG_CONST); // AG_CONST * cos(0)
- Y=0; // AG_CONST * sin(0)
- TargetAngle=abs(angle);
- CurrAngle=0;
+ X = FIXED(AG_CONST); /* AG_CONST * cos(0) */
+ Y = 0; /* AG_CONST * sin(0) */
+ TargetAngle = abs(angle);
+ CurrAngle = 0;
- for (Step=0; Step < 12; Step++)
- {
+ for (Step = 0; Step < 12; Step++) {
s32 NewX;
- if(TargetAngle > CurrAngle)
- {
- NewX=X - (Y >> Step);
- Y=(X >> Step) + Y;
- X=NewX;
+ if (TargetAngle > CurrAngle) {
+ NewX = X - (Y >> Step);
+ Y = (X >> Step) + Y;
+ X = NewX;
CurrAngle += Angles[Step];
- }
- else
- {
- NewX=X + (Y >> Step);
- Y=-(X >> Step) + Y;
- X=NewX;
+ } else {
+ NewX = X + (Y >> Step);
+ Y = -(X >> Step) + Y;
+ X = NewX;
CurrAngle -= Angles[Step];
}
}
- if (angle > 0)
- {
+ if (angle > 0) {
*cos = X;
*sin = Y;
- }
- else
- {
+ } else {
*cos = X;
*sin = -Y;
}
@@ -343,7 +301,7 @@ static unsigned char hal_get_dxx_reg(struct hw_data *pHwData, u16 number, u32 *
number += 0x1000;
return Wb35Reg_ReadSync(pHwData, number, pValue);
}
-#define hw_get_dxx_reg( _A, _B, _C ) hal_get_dxx_reg( _A, _B, (u32 *)_C )
+#define hw_get_dxx_reg(_A, _B, _C) hal_get_dxx_reg(_A, _B, (u32 *)_C)
static unsigned char hal_set_dxx_reg(struct hw_data *pHwData, u16 number, u32 value)
{
@@ -354,7 +312,7 @@ static unsigned char hal_set_dxx_reg(struct hw_data *pHwData, u16 number, u32 va
ret = Wb35Reg_WriteSync(pHwData, number, value);
return ret;
}
-#define hw_set_dxx_reg( _A, _B, _C ) hal_set_dxx_reg( _A, _B, (u32)_C )
+#define hw_set_dxx_reg(_A, _B, _C) hal_set_dxx_reg(_A, _B, (u32)_C)
void _reset_rx_cal(struct hw_data *phw_data)
@@ -363,25 +321,20 @@ void _reset_rx_cal(struct hw_data *phw_data)
hw_get_dxx_reg(phw_data, 0x54, &val);
- if (phw_data->revision == 0x2002) // 1st-cut
- {
+ if (phw_data->revision == 0x2002) /* 1st-cut */
val &= 0xFFFF0000;
- }
- else // 2nd-cut
- {
+ else /* 2nd-cut */
val &= 0x000003FF;
- }
hw_set_dxx_reg(phw_data, 0x54, val);
}
-// ************for winbond calibration*********
-//
+/**************for winbond calibration*********/
+
+
-//
-//
-// *********************************************
+/**********************************************/
void _rxadc_dc_offset_cancellation_winbond(struct hw_data *phw_data, u32 frequency)
{
u32 reg_agc_ctrl3;
@@ -392,35 +345,31 @@ void _rxadc_dc_offset_cancellation_winbond(struct hw_data *phw_data, u32 frequen
PHY_DEBUG(("[CAL] -> [1]_rxadc_dc_offset_cancellation()\n"));
phy_init_rf(phw_data);
- // set calibration channel
- if( (RF_WB_242 == phw_data->phy_type) ||
- (RF_WB_242_1 == phw_data->phy_type) ) // 20060619.5 Add
- {
- if ((frequency >= 2412) && (frequency <= 2484))
- {
- // w89rf242 change frequency to 2390Mhz
+ /* set calibration channel */
+ if ((RF_WB_242 == phw_data->phy_type) ||
+ (RF_WB_242_1 == phw_data->phy_type)) /* 20060619.5 Add */{
+ if ((frequency >= 2412) && (frequency <= 2484)) {
+ /* w89rf242 change frequency to 2390Mhz */
PHY_DEBUG(("[CAL] W89RF242/11G/Channel=2390Mhz\n"));
phy_set_rf_data(phw_data, 3, (3<<24)|0x025586);
}
- }
- else
- {
+ } else {
}
- // reset cancel_dc_i[9:5] and cancel_dc_q[4:0] in register DC_Cancel
+ /* reset cancel_dc_i[9:5] and cancel_dc_q[4:0] in register DC_Cancel */
hw_get_dxx_reg(phw_data, 0x5C, &val);
val &= ~(0x03FF);
hw_set_dxx_reg(phw_data, 0x5C, val);
- // reset the TX and RX IQ calibration data
+ /* reset the TX and RX IQ calibration data */
hw_set_dxx_reg(phw_data, 0x3C, 0);
hw_set_dxx_reg(phw_data, 0x54, 0);
- hw_set_dxx_reg(phw_data, 0x58, 0x30303030); // IQ_Alpha Changed
+ hw_set_dxx_reg(phw_data, 0x58, 0x30303030); /* IQ_Alpha Changed */
- // a. Disable AGC
+ /* a. Disable AGC */
hw_get_dxx_reg(phw_data, REG_AGC_CTRL3, &reg_agc_ctrl3);
reg_agc_ctrl3 &= ~BIT(2);
reg_agc_ctrl3 |= (MASK_LNA_FIX_GAIN|MASK_AGC_FIX);
@@ -430,7 +379,7 @@ void _rxadc_dc_offset_cancellation_winbond(struct hw_data *phw_data, u32 frequen
val |= MASK_AGC_FIX_GAIN;
hw_set_dxx_reg(phw_data, REG_AGC_CTRL5, val);
- // b. Turn off BB RX
+ /* b. Turn off BB RX */
hw_get_dxx_reg(phw_data, REG_A_ACQ_CTRL, &reg_a_acq_ctrl);
reg_a_acq_ctrl |= MASK_AMER_OFF_REG;
hw_set_dxx_reg(phw_data, REG_A_ACQ_CTRL, reg_a_acq_ctrl);
@@ -439,9 +388,9 @@ void _rxadc_dc_offset_cancellation_winbond(struct hw_data *phw_data, u32 frequen
reg_b_acq_ctrl |= MASK_BMER_OFF_REG;
hw_set_dxx_reg(phw_data, REG_B_ACQ_CTRL, reg_b_acq_ctrl);
- // c. Make sure MAC is in receiving mode
- // d. Turn ON ADC calibration
- // - ADC calibrator is triggered by this signal rising from 0 to 1
+ /* c. Make sure MAC is in receiving mode
+ * d. Turn ON ADC calibration
+ * - ADC calibrator is triggered by this signal rising from 0 to 1 */
hw_get_dxx_reg(phw_data, REG_MODE_CTRL, &val);
val &= ~MASK_ADC_DC_CAL_STR;
hw_set_dxx_reg(phw_data, REG_MODE_CTRL, val);
@@ -449,7 +398,7 @@ void _rxadc_dc_offset_cancellation_winbond(struct hw_data *phw_data, u32 frequen
val |= MASK_ADC_DC_CAL_STR;
hw_set_dxx_reg(phw_data, REG_MODE_CTRL, val);
- // e. The result are shown in "adc_dc_cal_i[8:0] and adc_dc_cal_q[8:0]"
+ /* e. The result are shown in "adc_dc_cal_i[8:0] and adc_dc_cal_q[8:0]" */
#ifdef _DEBUG
hw_get_dxx_reg(phw_data, REG_OFFSET_READ, &val);
PHY_DEBUG(("[CAL] REG_OFFSET_READ = 0x%08X\n", val));
@@ -464,23 +413,23 @@ void _rxadc_dc_offset_cancellation_winbond(struct hw_data *phw_data, u32 frequen
val &= ~MASK_ADC_DC_CAL_STR;
hw_set_dxx_reg(phw_data, REG_MODE_CTRL, val);
- // f. Turn on BB RX
- //hw_get_dxx_reg(phw_data, REG_A_ACQ_CTRL, &reg_a_acq_ctrl);
+ /* f. Turn on BB RX */
+ /* hw_get_dxx_reg(phw_data, REG_A_ACQ_CTRL, &reg_a_acq_ctrl); */
reg_a_acq_ctrl &= ~MASK_AMER_OFF_REG;
hw_set_dxx_reg(phw_data, REG_A_ACQ_CTRL, reg_a_acq_ctrl);
- //hw_get_dxx_reg(phw_data, REG_B_ACQ_CTRL, &reg_b_acq_ctrl);
+ /* hw_get_dxx_reg(phw_data, REG_B_ACQ_CTRL, &reg_b_acq_ctrl); */
reg_b_acq_ctrl &= ~MASK_BMER_OFF_REG;
hw_set_dxx_reg(phw_data, REG_B_ACQ_CTRL, reg_b_acq_ctrl);
- // g. Enable AGC
- //hw_get_dxx_reg(phw_data, REG_AGC_CTRL3, &val);
+ /* g. Enable AGC */
+ /* hw_get_dxx_reg(phw_data, REG_AGC_CTRL3, &val); */
reg_agc_ctrl3 |= BIT(2);
reg_agc_ctrl3 &= ~(MASK_LNA_FIX_GAIN|MASK_AGC_FIX);
hw_set_dxx_reg(phw_data, REG_AGC_CTRL3, reg_agc_ctrl3);
}
-////////////////////////////////////////////////////////
+/****************************************************************/
void _txidac_dc_offset_cancellation_winbond(struct hw_data *phw_data)
{
u32 reg_agc_ctrl3;
@@ -497,22 +446,22 @@ void _txidac_dc_offset_cancellation_winbond(struct hw_data *phw_data)
PHY_DEBUG(("[CAL] -> [2]_txidac_dc_offset_cancellation()\n"));
- // a. Set to "TX calibration mode"
+ /* a. Set to "TX calibration mode" */
- //0x01 0xEE3FC2 ; 3B8FF ; Calibration (6a). enable TX IQ calibration loop circuits
+ /* 0x01 0xEE3FC2 ; 3B8FF ; Calibration (6a). enable TX IQ calibration loop circuits */
phy_set_rf_data(phw_data, 1, (1<<24)|0xEE3FC2);
- //0x0B 0x1905D6 ; 06417 ; Calibration (6b). enable TX I/Q cal loop squaring circuit
+ /* 0x0B 0x1905D6 ; 06417 ; Calibration (6b). enable TX I/Q cal loop squaring circuit */
phy_set_rf_data(phw_data, 11, (11<<24)|0x1901D6);
- //0x05 0x24C60A ; 09318 ; Calibration (6c). setting TX-VGA gain: TXGCH=2 & GPK=110 --> to be optimized
+ /* 0x05 0x24C60A ; 09318 ; Calibration (6c). setting TX-VGA gain: TXGCH=2 & GPK=110 --> to be optimized */
phy_set_rf_data(phw_data, 5, (5<<24)|0x24C48A);
- //0x06 0x06880C ; 01A20 ; Calibration (6d). RXGCH=00; RXGCL=100 000 (RXVGA=32) --> to be optimized
+ /* 0x06 0x06880C ; 01A20 ; Calibration (6d). RXGCH=00; RXGCL=100 000 (RXVGA=32) --> to be optimized */
phy_set_rf_data(phw_data, 6, (6<<24)|0x06890C);
- //0x00 0xFDF1C0 ; 3F7C7 ; Calibration (6e). turn on IQ imbalance/Test mode
+ /* 0x00 0xFDF1C0 ; 3F7C7 ; Calibration (6e). turn on IQ imbalance/Test mode */
phy_set_rf_data(phw_data, 0, (0<<24)|0xFDF1C0);
- hw_set_dxx_reg(phw_data, 0x58, 0x30303030); // IQ_Alpha Changed
+ hw_set_dxx_reg(phw_data, 0x58, 0x30303030); /* IQ_Alpha Changed */
- // a. Disable AGC
+ /* a. Disable AGC */
hw_get_dxx_reg(phw_data, REG_AGC_CTRL3, &reg_agc_ctrl3);
reg_agc_ctrl3 &= ~BIT(2);
reg_agc_ctrl3 |= (MASK_LNA_FIX_GAIN|MASK_AGC_FIX);
@@ -522,19 +471,19 @@ void _txidac_dc_offset_cancellation_winbond(struct hw_data *phw_data)
val |= MASK_AGC_FIX_GAIN;
hw_set_dxx_reg(phw_data, REG_AGC_CTRL5, val);
- // b. set iqcal_mode[1:0] to 0x2 and set iqcal_tone[3:2] to 0
+ /* b. set iqcal_mode[1:0] to 0x2 and set iqcal_tone[3:2] to 0 */
hw_get_dxx_reg(phw_data, REG_MODE_CTRL, &reg_mode_ctrl);
PHY_DEBUG(("[CAL] MODE_CTRL (read) = 0x%08X\n", reg_mode_ctrl));
reg_mode_ctrl &= ~(MASK_IQCAL_TONE_SEL|MASK_IQCAL_MODE);
- // mode=2, tone=0
- //reg_mode_ctrl |= (MASK_CALIB_START|2);
+ /* mode=2, tone=0 */
+ /* reg_mode_ctrl |= (MASK_CALIB_START|2); */
- // mode=2, tone=1
- //reg_mode_ctrl |= (MASK_CALIB_START|2|(1<<2));
+ /* mode=2, tone=1 */
+ /* reg_mode_ctrl |= (MASK_CALIB_START|2|(1<<2)); */
- // mode=2, tone=2
+ /* mode=2, tone=2 */
reg_mode_ctrl |= (MASK_CALIB_START|2|(2<<2));
hw_set_dxx_reg(phw_data, REG_MODE_CTRL, reg_mode_ctrl);
PHY_DEBUG(("[CAL] MODE_CTRL (write) = 0x%08X\n", reg_mode_ctrl));
@@ -542,12 +491,10 @@ void _txidac_dc_offset_cancellation_winbond(struct hw_data *phw_data)
hw_get_dxx_reg(phw_data, 0x5C, &reg_dc_cancel);
PHY_DEBUG(("[CAL] DC_CANCEL (read) = 0x%08X\n", reg_dc_cancel));
- for (loop = 0; loop < LOOP_TIMES; loop++)
- {
+ for (loop = 0; loop < LOOP_TIMES; loop++) {
PHY_DEBUG(("[CAL] [%d.] ==================================\n", loop));
- // c.
- // reset cancel_dc_i[9:5] and cancel_dc_q[4:0] in register DC_Cancel
+ /* c. reset cancel_dc_i[9:5] and cancel_dc_q[4:0] in register DC_Cancel */
reg_dc_cancel &= ~(0x03FF);
PHY_DEBUG(("[CAL] DC_CANCEL (write) = 0x%08X\n", reg_dc_cancel));
hw_set_dxx_reg(phw_data, 0x5C, reg_dc_cancel);
@@ -562,7 +509,7 @@ void _txidac_dc_offset_cancellation_winbond(struct hw_data *phw_data)
PHY_DEBUG(("[CAL] mag_0=%d (iqcal_image_i=%d, iqcal_image_q=%d)\n",
mag_0, iqcal_image_i, iqcal_image_q));
- // d.
+ /* d. */
reg_dc_cancel |= (1 << CANCEL_DC_I_SHIFT);
PHY_DEBUG(("[CAL] DC_CANCEL (write) = 0x%08X\n", reg_dc_cancel));
hw_set_dxx_reg(phw_data, 0x5C, reg_dc_cancel);
@@ -577,18 +524,12 @@ void _txidac_dc_offset_cancellation_winbond(struct hw_data *phw_data)
PHY_DEBUG(("[CAL] mag_1=%d (iqcal_image_i=%d, iqcal_image_q=%d)\n",
mag_1, iqcal_image_i, iqcal_image_q));
- // e. Calculate the correct DC offset cancellation value for I
+ /* e. Calculate the correct DC offset cancellation value for I */
if (mag_0 != mag_1)
- {
fix_cancel_dc_i = (mag_0*10000) / (mag_0*10000 - mag_1*10000);
- }
- else
- {
+ else {
if (mag_0 == mag_1)
- {
PHY_DEBUG(("[CAL] ***** mag_0 = mag_1 !!\n"));
- }
-
fix_cancel_dc_i = 0;
}
@@ -596,12 +537,10 @@ void _txidac_dc_offset_cancellation_winbond(struct hw_data *phw_data)
fix_cancel_dc_i, _s32_to_s5(fix_cancel_dc_i)));
if ((abs(mag_1-mag_0)*6) > mag_0)
- {
break;
- }
}
- if ( loop >= 19 )
+ if (loop >= 19)
fix_cancel_dc_i = 0;
reg_dc_cancel &= ~(0x03FF);
@@ -609,13 +548,13 @@ void _txidac_dc_offset_cancellation_winbond(struct hw_data *phw_data)
hw_set_dxx_reg(phw_data, 0x5C, reg_dc_cancel);
PHY_DEBUG(("[CAL] DC_CANCEL (write) = 0x%08X\n", reg_dc_cancel));
- // g.
+ /* g. */
reg_mode_ctrl &= ~MASK_CALIB_START;
hw_set_dxx_reg(phw_data, REG_MODE_CTRL, reg_mode_ctrl);
PHY_DEBUG(("[CAL] MODE_CTRL (write) = 0x%08X\n", reg_mode_ctrl));
}
-///////////////////////////////////////////////////////
+/*****************************************************/
void _txqdac_dc_offset_cacellation_winbond(struct hw_data *phw_data)
{
u32 reg_agc_ctrl3;
@@ -631,20 +570,20 @@ void _txqdac_dc_offset_cacellation_winbond(struct hw_data *phw_data)
int loop;
PHY_DEBUG(("[CAL] -> [3]_txqdac_dc_offset_cacellation()\n"));
- //0x01 0xEE3FC2 ; 3B8FF ; Calibration (6a). enable TX IQ calibration loop circuits
+ /*0x01 0xEE3FC2 ; 3B8FF ; Calibration (6a). enable TX IQ calibration loop circuits */
phy_set_rf_data(phw_data, 1, (1<<24)|0xEE3FC2);
- //0x0B 0x1905D6 ; 06417 ; Calibration (6b). enable TX I/Q cal loop squaring circuit
+ /* 0x0B 0x1905D6 ; 06417 ; Calibration (6b). enable TX I/Q cal loop squaring circuit */
phy_set_rf_data(phw_data, 11, (11<<24)|0x1901D6);
- //0x05 0x24C60A ; 09318 ; Calibration (6c). setting TX-VGA gain: TXGCH=2 & GPK=110 --> to be optimized
+ /* 0x05 0x24C60A ; 09318 ; Calibration (6c). setting TX-VGA gain: TXGCH=2 & GPK=110 --> to be optimized */
phy_set_rf_data(phw_data, 5, (5<<24)|0x24C48A);
- //0x06 0x06880C ; 01A20 ; Calibration (6d). RXGCH=00; RXGCL=100 000 (RXVGA=32) --> to be optimized
+ /* 0x06 0x06880C ; 01A20 ; Calibration (6d). RXGCH=00; RXGCL=100 000 (RXVGA=32) --> to be optimized */
phy_set_rf_data(phw_data, 6, (6<<24)|0x06890C);
- //0x00 0xFDF1C0 ; 3F7C7 ; Calibration (6e). turn on IQ imbalance/Test mode
+ /* 0x00 0xFDF1C0 ; 3F7C7 ; Calibration (6e). turn on IQ imbalance/Test mode */
phy_set_rf_data(phw_data, 0, (0<<24)|0xFDF1C0);
- hw_set_dxx_reg(phw_data, 0x58, 0x30303030); // IQ_Alpha Changed
+ hw_set_dxx_reg(phw_data, 0x58, 0x30303030); /* IQ_Alpha Changed */
- // a. Disable AGC
+ /* a. Disable AGC */
hw_get_dxx_reg(phw_data, REG_AGC_CTRL3, &reg_agc_ctrl3);
reg_agc_ctrl3 &= ~BIT(2);
reg_agc_ctrl3 |= (MASK_LNA_FIX_GAIN|MASK_AGC_FIX);
@@ -654,11 +593,11 @@ void _txqdac_dc_offset_cacellation_winbond(struct hw_data *phw_data)
val |= MASK_AGC_FIX_GAIN;
hw_set_dxx_reg(phw_data, REG_AGC_CTRL5, val);
- // a. set iqcal_mode[1:0] to 0x3 and set iqcal_tone[3:2] to 0
+ /* a. set iqcal_mode[1:0] to 0x3 and set iqcal_tone[3:2] to 0 */
hw_get_dxx_reg(phw_data, REG_MODE_CTRL, &reg_mode_ctrl);
PHY_DEBUG(("[CAL] MODE_CTRL (read) = 0x%08X\n", reg_mode_ctrl));
- //reg_mode_ctrl &= ~(MASK_IQCAL_TONE_SEL|MASK_IQCAL_MODE);
+ /* reg_mode_ctrl &= ~(MASK_IQCAL_TONE_SEL|MASK_IQCAL_MODE); */
reg_mode_ctrl &= ~(MASK_IQCAL_MODE);
reg_mode_ctrl |= (MASK_CALIB_START|3);
hw_set_dxx_reg(phw_data, REG_MODE_CTRL, reg_mode_ctrl);
@@ -667,12 +606,10 @@ void _txqdac_dc_offset_cacellation_winbond(struct hw_data *phw_data)
hw_get_dxx_reg(phw_data, 0x5C, &reg_dc_cancel);
PHY_DEBUG(("[CAL] DC_CANCEL (read) = 0x%08X\n", reg_dc_cancel));
- for (loop = 0; loop < LOOP_TIMES; loop++)
- {
+ for (loop = 0; loop < LOOP_TIMES; loop++) {
PHY_DEBUG(("[CAL] [%d.] ==================================\n", loop));
- // b.
- // reset cancel_dc_q[4:0] in register DC_Cancel
+ /* b. reset cancel_dc_q[4:0] in register DC_Cancel */
reg_dc_cancel &= ~(0x001F);
PHY_DEBUG(("[CAL] DC_CANCEL (write) = 0x%08X\n", reg_dc_cancel));
hw_set_dxx_reg(phw_data, 0x5C, reg_dc_cancel);
@@ -687,7 +624,7 @@ void _txqdac_dc_offset_cacellation_winbond(struct hw_data *phw_data)
PHY_DEBUG(("[CAL] mag_0=%d (iqcal_image_i=%d, iqcal_image_q=%d)\n",
mag_0, iqcal_image_i, iqcal_image_q));
- // c.
+ /* c. */
reg_dc_cancel |= (1 << CANCEL_DC_Q_SHIFT);
PHY_DEBUG(("[CAL] DC_CANCEL (write) = 0x%08X\n", reg_dc_cancel));
hw_set_dxx_reg(phw_data, 0x5C, reg_dc_cancel);
@@ -702,18 +639,12 @@ void _txqdac_dc_offset_cacellation_winbond(struct hw_data *phw_data)
PHY_DEBUG(("[CAL] mag_1=%d (iqcal_image_i=%d, iqcal_image_q=%d)\n",
mag_1, iqcal_image_i, iqcal_image_q));
- // d. Calculate the correct DC offset cancellation value for I
+ /* d. Calculate the correct DC offset cancellation value for I */
if (mag_0 != mag_1)
- {
fix_cancel_dc_q = (mag_0*10000) / (mag_0*10000 - mag_1*10000);
- }
- else
- {
+ else {
if (mag_0 == mag_1)
- {
PHY_DEBUG(("[CAL] ***** mag_0 = mag_1 !!\n"));
- }
-
fix_cancel_dc_q = 0;
}
@@ -721,12 +652,10 @@ void _txqdac_dc_offset_cacellation_winbond(struct hw_data *phw_data)
fix_cancel_dc_q, _s32_to_s5(fix_cancel_dc_q)));
if ((abs(mag_1-mag_0)*6) > mag_0)
- {
break;
- }
}
- if ( loop >= 19 )
+ if (loop >= 19)
fix_cancel_dc_q = 0;
reg_dc_cancel &= ~(0x001F);
@@ -735,13 +664,13 @@ void _txqdac_dc_offset_cacellation_winbond(struct hw_data *phw_data)
PHY_DEBUG(("[CAL] DC_CANCEL (write) = 0x%08X\n", reg_dc_cancel));
- // f.
+ /* f. */
reg_mode_ctrl &= ~MASK_CALIB_START;
hw_set_dxx_reg(phw_data, REG_MODE_CTRL, reg_mode_ctrl);
PHY_DEBUG(("[CAL] MODE_CTRL (write) = 0x%08X\n", reg_mode_ctrl));
}
-//20060612.1.a 20060718.1 Modify
+/* 20060612.1.a 20060718.1 Modify */
u8 _tx_iq_calibration_loop_winbond(struct hw_data *phw_data,
s32 a_2_threshold,
s32 b_2_threshold)
@@ -765,7 +694,7 @@ u8 _tx_iq_calibration_loop_winbond(struct hw_data *phw_data,
s32 temp1, temp2;
u32 val;
u16 loop;
- s32 iqcal_tone_i_avg,iqcal_tone_q_avg;
+ s32 iqcal_tone_i_avg, iqcal_tone_q_avg;
u8 verify_count;
int capture_time;
@@ -780,18 +709,18 @@ u8 _tx_iq_calibration_loop_winbond(struct hw_data *phw_data,
loop = LOOP_TIMES;
- while (loop > 0)
- {
+ while (loop > 0) {
PHY_DEBUG(("[CAL] [%d.] <_tx_iq_calibration_loop>\n", (LOOP_TIMES-loop+1)));
- iqcal_tone_i_avg=0;
- iqcal_tone_q_avg=0;
- if( !hw_set_dxx_reg(phw_data, 0x3C, 0x00) ) // 20060718.1 modify
+ iqcal_tone_i_avg = 0;
+ iqcal_tone_q_avg = 0;
+ if (!hw_set_dxx_reg(phw_data, 0x3C, 0x00)) /* 20060718.1 modify */
return 0;
- for(capture_time=0;capture_time<10;capture_time++)
- {
- // a. Set iqcal_mode[1:0] to 0x2 and set "calib_start" to 0x1 to
- // enable "IQ alibration Mode II"
+ for (capture_time = 0; capture_time < 10; capture_time++) {
+ /*
+ * a. Set iqcal_mode[1:0] to 0x2 and set "calib_start" to 0x1 to
+ * enable "IQ alibration Mode II"
+ */
reg_mode_ctrl &= ~(MASK_IQCAL_TONE_SEL|MASK_IQCAL_MODE);
reg_mode_ctrl &= ~MASK_IQCAL_MODE;
reg_mode_ctrl |= (MASK_CALIB_START|0x02);
@@ -799,7 +728,7 @@ u8 _tx_iq_calibration_loop_winbond(struct hw_data *phw_data,
hw_set_dxx_reg(phw_data, REG_MODE_CTRL, reg_mode_ctrl);
PHY_DEBUG(("[CAL] MODE_CTRL (write) = 0x%08X\n", reg_mode_ctrl));
- // b.
+ /* b. */
hw_get_dxx_reg(phw_data, REG_CALIB_READ1, &val);
PHY_DEBUG(("[CAL] CALIB_READ1 = 0x%08X\n", val));
@@ -813,21 +742,23 @@ u8 _tx_iq_calibration_loop_winbond(struct hw_data *phw_data,
iq_mag_0_tx = (s32) _sqrt(sqsum);
PHY_DEBUG(("[CAL] ** iq_mag_0_tx=%d\n", iq_mag_0_tx));
- // c. Set "calib_start" to 0x0
+ /* c. Set "calib_start" to 0x0 */
reg_mode_ctrl &= ~MASK_CALIB_START;
hw_set_dxx_reg(phw_data, REG_MODE_CTRL, reg_mode_ctrl);
PHY_DEBUG(("[CAL] MODE_CTRL (write) = 0x%08X\n", reg_mode_ctrl));
- // d. Set iqcal_mode[1:0] to 0x3 and set "calib_start" to 0x1 to
- // enable "IQ alibration Mode II"
- //hw_get_dxx_reg(phw_data, REG_MODE_CTRL, &val);
+ /*
+ * d. Set iqcal_mode[1:0] to 0x3 and set "calib_start" to 0x1 to
+ * enable "IQ alibration Mode II"
+ */
+ /* hw_get_dxx_reg(phw_data, REG_MODE_CTRL, &val); */
hw_get_dxx_reg(phw_data, REG_MODE_CTRL, &reg_mode_ctrl);
reg_mode_ctrl &= ~MASK_IQCAL_MODE;
reg_mode_ctrl |= (MASK_CALIB_START|0x03);
hw_set_dxx_reg(phw_data, REG_MODE_CTRL, reg_mode_ctrl);
PHY_DEBUG(("[CAL] MODE_CTRL (write) = 0x%08X\n", reg_mode_ctrl));
- // e.
+ /* e. */
hw_get_dxx_reg(phw_data, REG_CALIB_READ1, &val);
PHY_DEBUG(("[CAL] CALIB_READ1 = 0x%08X\n", val));
@@ -835,14 +766,11 @@ u8 _tx_iq_calibration_loop_winbond(struct hw_data *phw_data,
iqcal_tone_q = _s13_to_s32((val & 0x03FFE000) >> 13);
PHY_DEBUG(("[CAL] ** iqcal_tone_i = %d, iqcal_tone_q = %d\n",
iqcal_tone_i, iqcal_tone_q));
- if( capture_time == 0)
- {
+ if (capture_time == 0)
continue;
- }
- else
- {
- iqcal_tone_i_avg=( iqcal_tone_i_avg*(capture_time-1) +iqcal_tone_i)/capture_time;
- iqcal_tone_q_avg=( iqcal_tone_q_avg*(capture_time-1) +iqcal_tone_q)/capture_time;
+ else {
+ iqcal_tone_i_avg = (iqcal_tone_i_avg*(capture_time-1) + iqcal_tone_i)/capture_time;
+ iqcal_tone_q_avg = (iqcal_tone_q_avg*(capture_time-1) + iqcal_tone_q)/capture_time;
}
}
@@ -857,11 +785,10 @@ u8 _tx_iq_calibration_loop_winbond(struct hw_data *phw_data,
PHY_DEBUG(("[CAL] ** rot_i_b = %d, rot_q_b = %d\n",
rot_i_b, rot_q_b));
- // f.
+ /* f. */
divisor = ((iq_mag_0_tx * iq_mag_0_tx * 2)/1024 - rot_i_b) * 2;
- if (divisor == 0)
- {
+ if (divisor == 0) {
PHY_DEBUG(("[CAL] ** <_tx_iq_calibration_loop> ERROR *******\n"));
PHY_DEBUG(("[CAL] ** divisor=0 to calculate EPS and THETA !!\n"));
PHY_DEBUG(("[CAL] ******************************************\n"));
@@ -876,18 +803,16 @@ u8 _tx_iq_calibration_loop_winbond(struct hw_data *phw_data,
phw_data->iq_rsdl_gain_tx_d2 = a_2;
phw_data->iq_rsdl_phase_tx_d2 = b_2;
- //if ((abs(a_2) < 150) && (abs(b_2) < 100))
- //if ((abs(a_2) < 200) && (abs(b_2) < 200))
- if ((abs(a_2) < a_2_threshold) && (abs(b_2) < b_2_threshold))
- {
+ /* if ((abs(a_2) < 150) && (abs(b_2) < 100)) */
+ /* if ((abs(a_2) < 200) && (abs(b_2) < 200)) */
+ if ((abs(a_2) < a_2_threshold) && (abs(b_2) < b_2_threshold)) {
verify_count++;
PHY_DEBUG(("[CAL] ** <_tx_iq_calibration_loop> *************\n"));
PHY_DEBUG(("[CAL] ** VERIFY OK # %d !!\n", verify_count));
PHY_DEBUG(("[CAL] ******************************************\n"));
- if (verify_count > 2)
- {
+ if (verify_count > 2) {
PHY_DEBUG(("[CAL] ** <_tx_iq_calibration_loop> *********\n"));
PHY_DEBUG(("[CAL] ** TX_IQ_CALIBRATION (EPS,THETA) OK !!\n"));
PHY_DEBUG(("[CAL] **************************************\n"));
@@ -895,37 +820,29 @@ u8 _tx_iq_calibration_loop_winbond(struct hw_data *phw_data,
}
continue;
- }
- else
- {
+ } else
verify_count = 0;
- }
_sin_cos(b_2, &sin_b, &cos_b);
_sin_cos(b_2*2, &sin_2b, &cos_2b);
PHY_DEBUG(("[CAL] ** sin(b/2)=%d, cos(b/2)=%d\n", sin_b, cos_b));
PHY_DEBUG(("[CAL] ** sin(b)=%d, cos(b)=%d\n", sin_2b, cos_2b));
- if (cos_2b == 0)
- {
+ if (cos_2b == 0) {
PHY_DEBUG(("[CAL] ** <_tx_iq_calibration_loop> ERROR *******\n"));
PHY_DEBUG(("[CAL] ** cos(b)=0 !!\n"));
PHY_DEBUG(("[CAL] ******************************************\n"));
break;
}
- // 1280 * 32768 = 41943040
+ /* 1280 * 32768 = 41943040 */
temp1 = (41943040/cos_2b)*cos_b;
- //temp2 = (41943040/cos_2b)*sin_b*(-1);
- if (phw_data->revision == 0x2002) // 1st-cut
- {
+ /* temp2 = (41943040/cos_2b)*sin_b*(-1); */
+ if (phw_data->revision == 0x2002) /* 1st-cut */
temp2 = (41943040/cos_2b)*sin_b*(-1);
- }
- else // 2nd-cut
- {
+ else /* 2nd-cut */
temp2 = (41943040*4/cos_2b)*sin_b*(-1);
- }
tx_cal_flt_b[0] = _floor(temp1/(32768+a_2));
tx_cal_flt_b[1] = _floor(temp2/(32768+a_2));
@@ -937,37 +854,34 @@ u8 _tx_iq_calibration_loop_winbond(struct hw_data *phw_data,
PHY_DEBUG(("[CAL] tx_cal_flt_b[3] = %d\n", tx_cal_flt_b[3]));
tx_cal[2] = tx_cal_flt_b[2];
- tx_cal[2] = tx_cal[2] +3;
+ tx_cal[2] = tx_cal[2] + 3;
tx_cal[1] = tx_cal[2];
tx_cal[3] = tx_cal_flt_b[3] - 128;
- tx_cal[0] = -tx_cal[3]+1;
+ tx_cal[0] = -tx_cal[3] + 1;
PHY_DEBUG(("[CAL] tx_cal[0] = %d\n", tx_cal[0]));
PHY_DEBUG(("[CAL] tx_cal[1] = %d\n", tx_cal[1]));
PHY_DEBUG(("[CAL] tx_cal[2] = %d\n", tx_cal[2]));
PHY_DEBUG(("[CAL] tx_cal[3] = %d\n", tx_cal[3]));
- //if ((tx_cal[0] == 0) && (tx_cal[1] == 0) &&
- // (tx_cal[2] == 0) && (tx_cal[3] == 0))
- //{
- // PHY_DEBUG(("[CAL] ** <_tx_iq_calibration_loop> *************\n"));
- // PHY_DEBUG(("[CAL] ** TX_IQ_CALIBRATION COMPLETE !!\n"));
- // PHY_DEBUG(("[CAL] ******************************************\n"));
- // return 0;
- //}
-
- // g.
- if (phw_data->revision == 0x2002) // 1st-cut
- {
+ /* if ((tx_cal[0] == 0) && (tx_cal[1] == 0) &&
+ (tx_cal[2] == 0) && (tx_cal[3] == 0))
+ { */
+ /* PHY_DEBUG(("[CAL] ** <_tx_iq_calibration_loop> *************\n"));
+ * PHY_DEBUG(("[CAL] ** TX_IQ_CALIBRATION COMPLETE !!\n"));
+ * PHY_DEBUG(("[CAL] ******************************************\n"));
+ * return 0;
+ } */
+
+ /* g. */
+ if (phw_data->revision == 0x2002) /* 1st-cut */{
hw_get_dxx_reg(phw_data, 0x54, &val);
PHY_DEBUG(("[CAL] ** 0x54 = 0x%08X\n", val));
tx_cal_reg[0] = _s4_to_s32((val & 0xF0000000) >> 28);
tx_cal_reg[1] = _s4_to_s32((val & 0x0F000000) >> 24);
tx_cal_reg[2] = _s4_to_s32((val & 0x00F00000) >> 20);
tx_cal_reg[3] = _s4_to_s32((val & 0x000F0000) >> 16);
- }
- else // 2nd-cut
- {
+ } else /* 2nd-cut */{
hw_get_dxx_reg(phw_data, 0x3C, &val);
PHY_DEBUG(("[CAL] ** 0x3C = 0x%08X\n", val));
tx_cal_reg[0] = _s5_to_s32((val & 0xF8000000) >> 27);
@@ -982,22 +896,17 @@ u8 _tx_iq_calibration_loop_winbond(struct hw_data *phw_data,
PHY_DEBUG(("[CAL] tx_cal_reg[2] = %d\n", tx_cal_reg[2]));
PHY_DEBUG(("[CAL] tx_cal_reg[3] = %d\n", tx_cal_reg[3]));
- if (phw_data->revision == 0x2002) // 1st-cut
- {
- if (((tx_cal_reg[0]==7) || (tx_cal_reg[0]==(-8))) &&
- ((tx_cal_reg[3]==7) || (tx_cal_reg[3]==(-8))))
- {
+ if (phw_data->revision == 0x2002) /* 1st-cut */{
+ if (((tx_cal_reg[0] == 7) || (tx_cal_reg[0] == (-8))) &&
+ ((tx_cal_reg[3] == 7) || (tx_cal_reg[3] == (-8)))) {
PHY_DEBUG(("[CAL] ** <_tx_iq_calibration_loop> *********\n"));
PHY_DEBUG(("[CAL] ** TX_IQ_CALIBRATION SATUATION !!\n"));
PHY_DEBUG(("[CAL] **************************************\n"));
break;
}
- }
- else // 2nd-cut
- {
- if (((tx_cal_reg[0]==31) || (tx_cal_reg[0]==(-32))) &&
- ((tx_cal_reg[3]==31) || (tx_cal_reg[3]==(-32))))
- {
+ } else /* 2nd-cut */{
+ if (((tx_cal_reg[0] == 31) || (tx_cal_reg[0] == (-32))) &&
+ ((tx_cal_reg[3] == 31) || (tx_cal_reg[3] == (-32)))) {
PHY_DEBUG(("[CAL] ** <_tx_iq_calibration_loop> *********\n"));
PHY_DEBUG(("[CAL] ** TX_IQ_CALIBRATION SATUATION !!\n"));
PHY_DEBUG(("[CAL] **************************************\n"));
@@ -1014,8 +923,7 @@ u8 _tx_iq_calibration_loop_winbond(struct hw_data *phw_data,
PHY_DEBUG(("[CAL] apply tx_cal[2] = %d\n", tx_cal[2]));
PHY_DEBUG(("[CAL] apply tx_cal[3] = %d\n", tx_cal[3]));
- if (phw_data->revision == 0x2002) // 1st-cut
- {
+ if (phw_data->revision == 0x2002) /* 1st-cut */{
val &= 0x0000FFFF;
val |= ((_s32_to_s4(tx_cal[0]) << 28)|
(_s32_to_s4(tx_cal[1]) << 24)|
@@ -1024,9 +932,7 @@ u8 _tx_iq_calibration_loop_winbond(struct hw_data *phw_data,
hw_set_dxx_reg(phw_data, 0x54, val);
PHY_DEBUG(("[CAL] ** CALIB_DATA = 0x%08X\n", val));
return 0;
- }
- else // 2nd-cut
- {
+ } else /* 2nd-cut */{
val &= 0x000003FF;
val |= ((_s32_to_s5(tx_cal[0]) << 27)|
(_s32_to_s6(tx_cal[1]) << 21)|
@@ -1037,7 +943,7 @@ u8 _tx_iq_calibration_loop_winbond(struct hw_data *phw_data,
return 0;
}
- // i. Set "calib_start" to 0x0
+ /* i. Set "calib_start" to 0x0 */
reg_mode_ctrl &= ~MASK_CALIB_START;
hw_set_dxx_reg(phw_data, REG_MODE_CTRL, reg_mode_ctrl);
PHY_DEBUG(("[CAL] MODE_CTRL (write) = 0x%08X\n", reg_mode_ctrl));
@@ -1061,26 +967,26 @@ void _tx_iq_calibration_winbond(struct hw_data *phw_data)
PHY_DEBUG(("[CAL] -> [4]_tx_iq_calibration()\n"));
- //0x01 0xEE3FC2 ; 3B8FF ; Calibration (6a). enable TX IQ calibration loop circuits
+ /* 0x01 0xEE3FC2 ; 3B8FF ; Calibration (6a). enable TX IQ calibration loop circuits */
phy_set_rf_data(phw_data, 1, (1<<24)|0xEE3FC2);
- //0x0B 0x1905D6 ; 06417 ; Calibration (6b). enable TX I/Q cal loop squaring circuit
- phy_set_rf_data(phw_data, 11, (11<<24)|0x19BDD6); // 20060612.1.a 0x1905D6);
- //0x05 0x24C60A ; 09318 ; Calibration (6c). setting TX-VGA gain: TXGCH=2 & GPK=110 --> to be optimized
- phy_set_rf_data(phw_data, 5, (5<<24)|0x24C60A); //0x24C60A (high temperature)
- //0x06 0x06880C ; 01A20 ; Calibration (6d). RXGCH=00; RXGCL=100 000 (RXVGA=32) --> to be optimized
- phy_set_rf_data(phw_data, 6, (6<<24)|0x34880C); // 20060612.1.a 0x06890C);
- //0x00 0xFDF1C0 ; 3F7C7 ; Calibration (6e). turn on IQ imbalance/Test mode
+ /* 0x0B 0x1905D6 ; 06417 ; Calibration (6b). enable TX I/Q cal loop squaring circuit */
+ phy_set_rf_data(phw_data, 11, (11<<24)|0x19BDD6); /* 20060612.1.a 0x1905D6); */
+ /* 0x05 0x24C60A ; 09318 ; Calibration (6c). setting TX-VGA gain: TXGCH=2 & GPK=110 --> to be optimized */
+ phy_set_rf_data(phw_data, 5, (5<<24)|0x24C60A); /* 0x24C60A (high temperature) */
+ /* 0x06 0x06880C ; 01A20 ; Calibration (6d). RXGCH=00; RXGCL=100 000 (RXVGA=32) --> to be optimized */
+ phy_set_rf_data(phw_data, 6, (6<<24)|0x34880C); /* 20060612.1.a 0x06890C); */
+ /* 0x00 0xFDF1C0 ; 3F7C7 ; Calibration (6e). turn on IQ imbalance/Test mode */
phy_set_rf_data(phw_data, 0, (0<<24)|0xFDF1C0);
- //; [BB-chip]: Calibration (6f).Send test pattern
- //; [BB-chip]: Calibration (6g). Search RXGCL optimal value
- //; [BB-chip]: Calibration (6h). Caculate TX-path IQ imbalance and setting TX path IQ compensation table
- //phy_set_rf_data(phw_data, 3, (3<<24)|0x025586);
+ /* ; [BB-chip]: Calibration (6f).Send test pattern */
+ /* ; [BB-chip]: Calibration (6g). Search RXGCL optimal value */
+ /* ; [BB-chip]: Calibration (6h). Caculate TX-path IQ imbalance and setting TX path IQ compensation table */
+ /* phy_set_rf_data(phw_data, 3, (3<<24)|0x025586); */
- msleep(30); // 20060612.1.a 30ms delay. Add the follow 2 lines
- //To adjust TXVGA to fit iq_mag_0 range from 1250 ~ 1750
- adjust_TXVGA_for_iq_mag( phw_data );
+ msleep(30); /* 20060612.1.a 30ms delay. Add the follow 2 lines */
+ /* To adjust TXVGA to fit iq_mag_0 range from 1250 ~ 1750 */
+ adjust_TXVGA_for_iq_mag(phw_data);
- // a. Disable AGC
+ /* a. Disable AGC */
hw_get_dxx_reg(phw_data, REG_AGC_CTRL3, &reg_agc_ctrl3);
reg_agc_ctrl3 &= ~BIT(2);
reg_agc_ctrl3 |= (MASK_LNA_FIX_GAIN|MASK_AGC_FIX);
@@ -1092,16 +998,12 @@ void _tx_iq_calibration_winbond(struct hw_data *phw_data)
result = _tx_iq_calibration_loop_winbond(phw_data, 150, 100);
- if (result > 0)
- {
- if (phw_data->revision == 0x2002) // 1st-cut
- {
+ if (result > 0) {
+ if (phw_data->revision == 0x2002) /* 1st-cut */{
hw_get_dxx_reg(phw_data, 0x54, &val);
val &= 0x0000FFFF;
hw_set_dxx_reg(phw_data, 0x54, val);
- }
- else // 2nd-cut
- {
+ } else /* 2nd-cut*/{
hw_get_dxx_reg(phw_data, 0x3C, &val);
val &= 0x000003FF;
hw_set_dxx_reg(phw_data, 0x3C, val);
@@ -1109,32 +1011,24 @@ void _tx_iq_calibration_winbond(struct hw_data *phw_data)
result = _tx_iq_calibration_loop_winbond(phw_data, 300, 200);
- if (result > 0)
- {
- if (phw_data->revision == 0x2002) // 1st-cut
- {
+ if (result > 0) {
+ if (phw_data->revision == 0x2002) /* 1st-cut */{
hw_get_dxx_reg(phw_data, 0x54, &val);
val &= 0x0000FFFF;
hw_set_dxx_reg(phw_data, 0x54, val);
- }
- else // 2nd-cut
- {
+ } else /* 2nd-cut*/{
hw_get_dxx_reg(phw_data, 0x3C, &val);
val &= 0x000003FF;
hw_set_dxx_reg(phw_data, 0x3C, val);
}
result = _tx_iq_calibration_loop_winbond(phw_data, 500, 400);
- if (result > 0)
- {
- if (phw_data->revision == 0x2002) // 1st-cut
- {
+ if (result > 0) {
+ if (phw_data->revision == 0x2002) /* 1st-cut */{
hw_get_dxx_reg(phw_data, 0x54, &val);
val &= 0x0000FFFF;
hw_set_dxx_reg(phw_data, 0x54, val);
- }
- else // 2nd-cut
- {
+ } else /* 2nd-cut */{
hw_get_dxx_reg(phw_data, 0x3C, &val);
val &= 0x000003FF;
hw_set_dxx_reg(phw_data, 0x3C, val);
@@ -1143,20 +1037,16 @@ void _tx_iq_calibration_winbond(struct hw_data *phw_data)
result = _tx_iq_calibration_loop_winbond(phw_data, 700, 500);
- if (result > 0)
- {
+ if (result > 0) {
PHY_DEBUG(("[CAL] ** <_tx_iq_calibration> **************\n"));
PHY_DEBUG(("[CAL] ** TX_IQ_CALIBRATION FAILURE !!\n"));
PHY_DEBUG(("[CAL] **************************************\n"));
- if (phw_data->revision == 0x2002) // 1st-cut
- {
+ if (phw_data->revision == 0x2002) /* 1st-cut */{
hw_get_dxx_reg(phw_data, 0x54, &val);
val &= 0x0000FFFF;
hw_set_dxx_reg(phw_data, 0x54, val);
- }
- else // 2nd-cut
- {
+ } else /* 2nd-cut */{
hw_get_dxx_reg(phw_data, 0x3C, &val);
val &= 0x000003FF;
hw_set_dxx_reg(phw_data, 0x3C, val);
@@ -1166,30 +1056,27 @@ void _tx_iq_calibration_winbond(struct hw_data *phw_data)
}
}
- // i. Set "calib_start" to 0x0
+ /* i. Set "calib_start" to 0x0 */
hw_get_dxx_reg(phw_data, REG_MODE_CTRL, &reg_mode_ctrl);
reg_mode_ctrl &= ~MASK_CALIB_START;
hw_set_dxx_reg(phw_data, REG_MODE_CTRL, reg_mode_ctrl);
PHY_DEBUG(("[CAL] MODE_CTRL (write) = 0x%08X\n", reg_mode_ctrl));
- // g. Enable AGC
- //hw_get_dxx_reg(phw_data, REG_AGC_CTRL3, &val);
+ /* g. Enable AGC */
+ /* hw_get_dxx_reg(phw_data, REG_AGC_CTRL3, &val); */
reg_agc_ctrl3 |= BIT(2);
reg_agc_ctrl3 &= ~(MASK_LNA_FIX_GAIN|MASK_AGC_FIX);
hw_set_dxx_reg(phw_data, REG_AGC_CTRL3, reg_agc_ctrl3);
#ifdef _DEBUG
- if (phw_data->revision == 0x2002) // 1st-cut
- {
+ if (phw_data->revision == 0x2002) /* 1st-cut */{
hw_get_dxx_reg(phw_data, 0x54, &val);
PHY_DEBUG(("[CAL] ** 0x54 = 0x%08X\n", val));
tx_cal_reg[0] = _s4_to_s32((val & 0xF0000000) >> 28);
tx_cal_reg[1] = _s4_to_s32((val & 0x0F000000) >> 24);
tx_cal_reg[2] = _s4_to_s32((val & 0x00F00000) >> 20);
tx_cal_reg[3] = _s4_to_s32((val & 0x000F0000) >> 16);
- }
- else // 2nd-cut
- {
+ } else /* 2nd-cut */ {
hw_get_dxx_reg(phw_data, 0x3C, &val);
PHY_DEBUG(("[CAL] ** 0x3C = 0x%08X\n", val));
tx_cal_reg[0] = _s5_to_s32((val & 0xF8000000) >> 27);
@@ -1206,11 +1093,13 @@ void _tx_iq_calibration_winbond(struct hw_data *phw_data)
#endif
- // for test - BEN
- // RF Control Override
+ /*
+ * for test - BEN
+ * RF Control Override
+ */
}
-/////////////////////////////////////////////////////////////////////////////////////////
+/*****************************************************/
u8 _rx_iq_calibration_loop_winbond(struct hw_data *phw_data, u16 factor, u32 frequency)
{
u32 reg_mode_ctrl;
@@ -1236,51 +1125,49 @@ u8 _rx_iq_calibration_loop_winbond(struct hw_data *phw_data, u16 factor, u32 fre
u32 pwr_image;
u8 verify_count;
- s32 iqcal_tone_i_avg,iqcal_tone_q_avg;
- s32 iqcal_image_i_avg,iqcal_image_q_avg;
- u16 capture_time;
+ s32 iqcal_tone_i_avg, iqcal_tone_q_avg;
+ s32 iqcal_image_i_avg, iqcal_image_q_avg;
+ u16 capture_time;
PHY_DEBUG(("[CAL] -> [5]_rx_iq_calibration_loop()\n"));
PHY_DEBUG(("[CAL] ** factor = %d\n", factor));
-// RF Control Override
+/* RF Control Override */
hw_get_cxx_reg(phw_data, 0x80, &val);
val |= BIT(19);
hw_set_cxx_reg(phw_data, 0x80, val);
-// RF_Ctrl
+/* RF_Ctrl */
hw_get_cxx_reg(phw_data, 0xE4, &val);
val |= BIT(0);
hw_set_cxx_reg(phw_data, 0xE4, val);
PHY_DEBUG(("[CAL] ** RF_CTRL(0xE4) = 0x%08X", val));
- hw_set_dxx_reg(phw_data, 0x58, 0x44444444); // IQ_Alpha
+ hw_set_dxx_reg(phw_data, 0x58, 0x44444444); /* IQ_Alpha */
- // b.
+ /* b. */
hw_get_dxx_reg(phw_data, REG_MODE_CTRL, &reg_mode_ctrl);
PHY_DEBUG(("[CAL] MODE_CTRL (read) = 0x%08X\n", reg_mode_ctrl));
verify_count = 0;
- //for (loop = 0; loop < 1; loop++)
- //for (loop = 0; loop < LOOP_TIMES; loop++)
+ /* for (loop = 0; loop < 1; loop++) */
+ /* for (loop = 0; loop < LOOP_TIMES; loop++) */
loop = LOOP_TIMES;
- while (loop > 0)
- {
+ while (loop > 0) {
PHY_DEBUG(("[CAL] [%d.] <_rx_iq_calibration_loop>\n", (LOOP_TIMES-loop+1)));
- iqcal_tone_i_avg=0;
- iqcal_tone_q_avg=0;
- iqcal_image_i_avg=0;
- iqcal_image_q_avg=0;
- capture_time=0;
-
- for(capture_time=0; capture_time<10; capture_time++)
- {
- // i. Set "calib_start" to 0x0
+ iqcal_tone_i_avg = 0;
+ iqcal_tone_q_avg = 0;
+ iqcal_image_i_avg = 0;
+ iqcal_image_q_avg = 0;
+ capture_time = 0;
+
+ for (capture_time = 0; capture_time < 10; capture_time++) {
+ /* i. Set "calib_start" to 0x0 */
reg_mode_ctrl &= ~MASK_CALIB_START;
- if( !hw_set_dxx_reg(phw_data, REG_MODE_CTRL, reg_mode_ctrl) )//20060718.1 modify
+ if (!hw_set_dxx_reg(phw_data, REG_MODE_CTRL, reg_mode_ctrl))/*20060718.1 modify */
return 0;
PHY_DEBUG(("[CAL] MODE_CTRL (write) = 0x%08X\n", reg_mode_ctrl));
@@ -1289,7 +1176,7 @@ u8 _rx_iq_calibration_loop_winbond(struct hw_data *phw_data, u16 factor, u32 fre
hw_set_dxx_reg(phw_data, REG_MODE_CTRL, reg_mode_ctrl);
PHY_DEBUG(("[CAL] MODE_CTRL (write) = 0x%08X\n", reg_mode_ctrl));
- // c.
+ /* c. */
hw_get_dxx_reg(phw_data, REG_CALIB_READ1, &val);
PHY_DEBUG(("[CAL] CALIB_READ1 = 0x%08X\n", val));
@@ -1305,16 +1192,13 @@ u8 _rx_iq_calibration_loop_winbond(struct hw_data *phw_data, u16 factor, u32 fre
iqcal_image_q = _s13_to_s32((val & 0x03FFE000) >> 13);
PHY_DEBUG(("[CAL] ** iqcal_image_i = %d, iqcal_image_q = %d\n",
iqcal_image_i, iqcal_image_q));
- if( capture_time == 0)
- {
+ if (capture_time == 0)
continue;
- }
- else
- {
- iqcal_image_i_avg=( iqcal_image_i_avg*(capture_time-1) +iqcal_image_i)/capture_time;
- iqcal_image_q_avg=( iqcal_image_q_avg*(capture_time-1) +iqcal_image_q)/capture_time;
- iqcal_tone_i_avg=( iqcal_tone_i_avg*(capture_time-1) +iqcal_tone_i)/capture_time;
- iqcal_tone_q_avg=( iqcal_tone_q_avg*(capture_time-1) +iqcal_tone_q)/capture_time;
+ else {
+ iqcal_image_i_avg = (iqcal_image_i_avg*(capture_time-1) + iqcal_image_i)/capture_time;
+ iqcal_image_q_avg = (iqcal_image_q_avg*(capture_time-1) + iqcal_image_q)/capture_time;
+ iqcal_tone_i_avg = (iqcal_tone_i_avg*(capture_time-1) + iqcal_tone_i)/capture_time;
+ iqcal_tone_q_avg = (iqcal_tone_q_avg*(capture_time-1) + iqcal_tone_q)/capture_time;
}
}
@@ -1324,7 +1208,7 @@ u8 _rx_iq_calibration_loop_winbond(struct hw_data *phw_data, u16 factor, u32 fre
iqcal_tone_i = iqcal_tone_i_avg;
iqcal_tone_q = iqcal_tone_q_avg;
- // d.
+ /* d. */
rot_tone_i_b = (iqcal_tone_i * iqcal_tone_i +
iqcal_tone_q * iqcal_tone_q) / 1024;
rot_tone_q_b = (iqcal_tone_i * iqcal_tone_q * (-1) +
@@ -1339,9 +1223,8 @@ u8 _rx_iq_calibration_loop_winbond(struct hw_data *phw_data, u16 factor, u32 fre
PHY_DEBUG(("[CAL] ** rot_image_i_b = %d\n", rot_image_i_b));
PHY_DEBUG(("[CAL] ** rot_image_q_b = %d\n", rot_image_q_b));
- // f.
- if (rot_tone_i_b == 0)
- {
+ /* f. */
+ if (rot_tone_i_b == 0) {
PHY_DEBUG(("[CAL] ** <_rx_iq_calibration_loop> ERROR *******\n"));
PHY_DEBUG(("[CAL] ** rot_tone_i_b=0 to calculate EPS and THETA !!\n"));
PHY_DEBUG(("[CAL] ******************************************\n"));
@@ -1363,26 +1246,21 @@ u8 _rx_iq_calibration_loop_winbond(struct hw_data *phw_data, u16 factor, u32 fre
PHY_DEBUG(("[CAL] ** sin(b/2)=%d, cos(b/2)=%d\n", sin_b, cos_b));
PHY_DEBUG(("[CAL] ** sin(b)=%d, cos(b)=%d\n", sin_2b, cos_2b));
- if (cos_2b == 0)
- {
+ if (cos_2b == 0) {
PHY_DEBUG(("[CAL] ** <_rx_iq_calibration_loop> ERROR *******\n"));
PHY_DEBUG(("[CAL] ** cos(b)=0 !!\n"));
PHY_DEBUG(("[CAL] ******************************************\n"));
break;
}
- // 1280 * 32768 = 41943040
+ /* 1280 * 32768 = 41943040 */
temp1 = (41943040/cos_2b)*cos_b;
- //temp2 = (41943040/cos_2b)*sin_b*(-1);
- if (phw_data->revision == 0x2002) // 1st-cut
- {
+ /* temp2 = (41943040/cos_2b)*sin_b*(-1); */
+ if (phw_data->revision == 0x2002)/* 1st-cut */
temp2 = (41943040/cos_2b)*sin_b*(-1);
- }
- else // 2nd-cut
- {
+ else/* 2nd-cut */
temp2 = (41943040*4/cos_2b)*sin_b*(-1);
- }
rx_cal_flt_b[0] = _floor(temp1/(32768+a_2));
rx_cal_flt_b[1] = _floor(temp2/(32768-a_2));
@@ -1403,23 +1281,21 @@ u8 _rx_iq_calibration_loop_winbond(struct hw_data *phw_data, u16 factor, u32 fre
PHY_DEBUG(("[CAL] rx_cal[2] = %d\n", rx_cal[2]));
PHY_DEBUG(("[CAL] rx_cal[3] = %d\n", rx_cal[3]));
- // e.
+ /* e. */
pwr_tone = (iqcal_tone_i*iqcal_tone_i + iqcal_tone_q*iqcal_tone_q);
pwr_image = (iqcal_image_i*iqcal_image_i + iqcal_image_q*iqcal_image_q)*factor;
PHY_DEBUG(("[CAL] ** pwr_tone = %d\n", pwr_tone));
PHY_DEBUG(("[CAL] ** pwr_image = %d\n", pwr_image));
- if (pwr_tone > pwr_image)
- {
+ if (pwr_tone > pwr_image) {
verify_count++;
PHY_DEBUG(("[CAL] ** <_rx_iq_calibration_loop> *************\n"));
PHY_DEBUG(("[CAL] ** VERIFY OK # %d !!\n", verify_count));
PHY_DEBUG(("[CAL] ******************************************\n"));
- if (verify_count > 2)
- {
+ if (verify_count > 2) {
PHY_DEBUG(("[CAL] ** <_rx_iq_calibration_loop> *********\n"));
PHY_DEBUG(("[CAL] ** RX_IQ_CALIBRATION OK !!\n"));
PHY_DEBUG(("[CAL] **************************************\n"));
@@ -1428,19 +1304,16 @@ u8 _rx_iq_calibration_loop_winbond(struct hw_data *phw_data, u16 factor, u32 fre
continue;
}
- // g.
+ /* g. */
hw_get_dxx_reg(phw_data, 0x54, &val);
PHY_DEBUG(("[CAL] ** 0x54 = 0x%08X\n", val));
- if (phw_data->revision == 0x2002) // 1st-cut
- {
+ if (phw_data->revision == 0x2002) /* 1st-cut */{
rx_cal_reg[0] = _s4_to_s32((val & 0x0000F000) >> 12);
rx_cal_reg[1] = _s4_to_s32((val & 0x00000F00) >> 8);
rx_cal_reg[2] = _s4_to_s32((val & 0x000000F0) >> 4);
rx_cal_reg[3] = _s4_to_s32((val & 0x0000000F));
- }
- else // 2nd-cut
- {
+ } else /* 2nd-cut */{
rx_cal_reg[0] = _s5_to_s32((val & 0xF8000000) >> 27);
rx_cal_reg[1] = _s6_to_s32((val & 0x07E00000) >> 21);
rx_cal_reg[2] = _s6_to_s32((val & 0x001F8000) >> 15);
@@ -1452,22 +1325,17 @@ u8 _rx_iq_calibration_loop_winbond(struct hw_data *phw_data, u16 factor, u32 fre
PHY_DEBUG(("[CAL] rx_cal_reg[2] = %d\n", rx_cal_reg[2]));
PHY_DEBUG(("[CAL] rx_cal_reg[3] = %d\n", rx_cal_reg[3]));
- if (phw_data->revision == 0x2002) // 1st-cut
- {
- if (((rx_cal_reg[0]==7) || (rx_cal_reg[0]==(-8))) &&
- ((rx_cal_reg[3]==7) || (rx_cal_reg[3]==(-8))))
- {
+ if (phw_data->revision == 0x2002) /* 1st-cut */{
+ if (((rx_cal_reg[0] == 7) || (rx_cal_reg[0] == (-8))) &&
+ ((rx_cal_reg[3] == 7) || (rx_cal_reg[3] == (-8)))) {
PHY_DEBUG(("[CAL] ** <_rx_iq_calibration_loop> *********\n"));
PHY_DEBUG(("[CAL] ** RX_IQ_CALIBRATION SATUATION !!\n"));
PHY_DEBUG(("[CAL] **************************************\n"));
break;
}
- }
- else // 2nd-cut
- {
- if (((rx_cal_reg[0]==31) || (rx_cal_reg[0]==(-32))) &&
- ((rx_cal_reg[3]==31) || (rx_cal_reg[3]==(-32))))
- {
+ } else /* 2nd-cut */{
+ if (((rx_cal_reg[0] == 31) || (rx_cal_reg[0] == (-32))) &&
+ ((rx_cal_reg[3] == 31) || (rx_cal_reg[3] == (-32)))) {
PHY_DEBUG(("[CAL] ** <_rx_iq_calibration_loop> *********\n"));
PHY_DEBUG(("[CAL] ** RX_IQ_CALIBRATION SATUATION !!\n"));
PHY_DEBUG(("[CAL] **************************************\n"));
@@ -1485,17 +1353,14 @@ u8 _rx_iq_calibration_loop_winbond(struct hw_data *phw_data, u16 factor, u32 fre
PHY_DEBUG(("[CAL] apply rx_cal[3] = %d\n", rx_cal[3]));
hw_get_dxx_reg(phw_data, 0x54, &val);
- if (phw_data->revision == 0x2002) // 1st-cut
- {
+ if (phw_data->revision == 0x2002) /* 1st-cut */{
val &= 0x0000FFFF;
val |= ((_s32_to_s4(rx_cal[0]) << 12)|
(_s32_to_s4(rx_cal[1]) << 8)|
(_s32_to_s4(rx_cal[2]) << 4)|
(_s32_to_s4(rx_cal[3])));
hw_set_dxx_reg(phw_data, 0x54, val);
- }
- else // 2nd-cut
- {
+ } else /* 2nd-cut */{
val &= 0x000003FF;
val |= ((_s32_to_s5(rx_cal[0]) << 27)|
(_s32_to_s6(rx_cal[1]) << 21)|
@@ -1503,7 +1368,7 @@ u8 _rx_iq_calibration_loop_winbond(struct hw_data *phw_data, u16 factor, u32 fre
(_s32_to_s5(rx_cal[3]) << 10));
hw_set_dxx_reg(phw_data, 0x54, val);
- if( loop == 3 )
+ if (loop == 3)
return 0;
}
PHY_DEBUG(("[CAL] ** CALIB_DATA = 0x%08X\n", val));
@@ -1514,12 +1379,12 @@ u8 _rx_iq_calibration_loop_winbond(struct hw_data *phw_data, u16 factor, u32 fre
return 1;
}
-//////////////////////////////////////////////////////////
+/*************************************************/
-//////////////////////////////////////////////////////////////////////////
+/***************************************************************/
void _rx_iq_calibration_winbond(struct hw_data *phw_data, u32 frequency)
{
-// figo 20050523 marked thsi flag for can't compile for relesase
+/* figo 20050523 marked this flag for can't compile for relesase */
#ifdef _DEBUG
s32 rx_cal_reg[4];
u32 val;
@@ -1528,37 +1393,34 @@ void _rx_iq_calibration_winbond(struct hw_data *phw_data, u32 frequency)
u8 result;
PHY_DEBUG(("[CAL] -> [5]_rx_iq_calibration()\n"));
-// a. Set RFIC to "RX calibration mode"
- //; ----- Calibration (7). RX path IQ imbalance calibration loop
- // 0x01 0xFFBFC2 ; 3FEFF ; Calibration (7a). enable RX IQ calibration loop circuits
+/* a. Set RFIC to "RX calibration mode" */
+ /* ; ----- Calibration (7). RX path IQ imbalance calibration loop */
+ /* 0x01 0xFFBFC2 ; 3FEFF ; Calibration (7a). enable RX IQ calibration loop circuits */
phy_set_rf_data(phw_data, 1, (1<<24)|0xEFBFC2);
- // 0x0B 0x1A01D6 ; 06817 ; Calibration (7b). enable RX I/Q cal loop SW1 circuit
+ /* 0x0B 0x1A01D6 ; 06817 ; Calibration (7b). enable RX I/Q cal loop SW1 circuits */
phy_set_rf_data(phw_data, 11, (11<<24)|0x1A05D6);
- //0x05 0x24848A ; 09212 ; Calibration (7c). setting TX-VGA gain (TXGCH) to 2 --> to be optimized
- phy_set_rf_data(phw_data, 5, (5<<24)| phw_data->txvga_setting_for_cal);
- //0x06 0x06840C ; 01A10 ; Calibration (7d). RXGCH=00; RXGCL=010 000 (RXVGA) --> to be optimized
+ /* 0x05 0x24848A ; 09212 ; Calibration (7c). setting TX-VGA gain (TXGCH) to 2 --> to be optimized */
+ phy_set_rf_data(phw_data, 5, (5<<24) | phw_data->txvga_setting_for_cal);
+ /* 0x06 0x06840C ; 01A10 ; Calibration (7d). RXGCH=00; RXGCL=010 000 (RXVGA) --> to be optimized */
phy_set_rf_data(phw_data, 6, (6<<24)|0x06834C);
- //0x00 0xFFF1C0 ; 3F7C7 ; Calibration (7e). turn on IQ imbalance/Test mode
+ /* 0x00 0xFFF1C0 ; 3F7C7 ; Calibration (7e). turn on IQ imbalance/Test mode */
phy_set_rf_data(phw_data, 0, (0<<24)|0xFFF1C0);
- // ; [BB-chip]: Calibration (7f). Send test pattern
- // ; [BB-chip]: Calibration (7g). Search RXGCL optimal value
- // ; [BB-chip]: Calibration (7h). Caculate RX-path IQ imbalance and setting RX path IQ compensation table
+ /* ; [BB-chip]: Calibration (7f). Send test pattern */
+ /* ; [BB-chip]: Calibration (7g). Search RXGCL optimal value */
+ /* ; [BB-chip]: Calibration (7h). Caculate RX-path IQ imbalance and setting RX path IQ compensation table */
result = _rx_iq_calibration_loop_winbond(phw_data, 12589, frequency);
- if (result > 0)
- {
+ if (result > 0) {
_reset_rx_cal(phw_data);
result = _rx_iq_calibration_loop_winbond(phw_data, 7943, frequency);
- if (result > 0)
- {
+ if (result > 0) {
_reset_rx_cal(phw_data);
result = _rx_iq_calibration_loop_winbond(phw_data, 5011, frequency);
- if (result > 0)
- {
+ if (result > 0) {
PHY_DEBUG(("[CAL] ** <_rx_iq_calibration> **************\n"));
PHY_DEBUG(("[CAL] ** RX_IQ_CALIBRATION FAILURE !!\n"));
PHY_DEBUG(("[CAL] **************************************\n"));
@@ -1571,15 +1433,12 @@ void _rx_iq_calibration_winbond(struct hw_data *phw_data, u32 frequency)
hw_get_dxx_reg(phw_data, 0x54, &val);
PHY_DEBUG(("[CAL] ** 0x54 = 0x%08X\n", val));
- if (phw_data->revision == 0x2002) // 1st-cut
- {
+ if (phw_data->revision == 0x2002) /* 1st-cut */{
rx_cal_reg[0] = _s4_to_s32((val & 0x0000F000) >> 12);
rx_cal_reg[1] = _s4_to_s32((val & 0x00000F00) >> 8);
rx_cal_reg[2] = _s4_to_s32((val & 0x000000F0) >> 4);
rx_cal_reg[3] = _s4_to_s32((val & 0x0000000F));
- }
- else // 2nd-cut
- {
+ } else /* 2nd-cut */{
rx_cal_reg[0] = _s5_to_s32((val & 0xF8000000) >> 27);
rx_cal_reg[1] = _s6_to_s32((val & 0x07E00000) >> 21);
rx_cal_reg[2] = _s6_to_s32((val & 0x001F8000) >> 15);
@@ -1594,7 +1453,7 @@ void _rx_iq_calibration_winbond(struct hw_data *phw_data, u32 frequency)
}
-////////////////////////////////////////////////////////////////////////
+/*******************************************************/
void phy_calibration_winbond(struct hw_data *phw_data, u32 frequency)
{
u32 reg_mode_ctrl;
@@ -1602,7 +1461,7 @@ void phy_calibration_winbond(struct hw_data *phw_data, u32 frequency)
PHY_DEBUG(("[CAL] -> phy_calibration_winbond()\n"));
- // 20040701 1.1.25.1000 kevin
+ /* 20040701 1.1.25.1000 kevin */
hw_get_cxx_reg(phw_data, 0x80, &mac_ctrl);
hw_get_cxx_reg(phw_data, 0xE4, &rf_ctrl);
hw_get_dxx_reg(phw_data, 0x58, &iq_alpha);
@@ -1610,72 +1469,71 @@ void phy_calibration_winbond(struct hw_data *phw_data, u32 frequency)
_rxadc_dc_offset_cancellation_winbond(phw_data, frequency);
- //_txidac_dc_offset_cancellation_winbond(phw_data);
- //_txqdac_dc_offset_cacellation_winbond(phw_data);
+ /* _txidac_dc_offset_cancellation_winbond(phw_data); */
+ /* _txqdac_dc_offset_cacellation_winbond(phw_data); */
_tx_iq_calibration_winbond(phw_data);
_rx_iq_calibration_winbond(phw_data, frequency);
- //------------------------------------------------------------------------
+ /*********************************************************************/
hw_get_dxx_reg(phw_data, REG_MODE_CTRL, &reg_mode_ctrl);
- reg_mode_ctrl &= ~(MASK_IQCAL_TONE_SEL|MASK_IQCAL_MODE|MASK_CALIB_START); // set when finish
+ reg_mode_ctrl &= ~(MASK_IQCAL_TONE_SEL|MASK_IQCAL_MODE|MASK_CALIB_START); /* set when finish */
hw_set_dxx_reg(phw_data, REG_MODE_CTRL, reg_mode_ctrl);
PHY_DEBUG(("[CAL] MODE_CTRL (write) = 0x%08X\n", reg_mode_ctrl));
- // i. Set RFIC to "Normal mode"
+ /* i. Set RFIC to "Normal mode" */
hw_set_cxx_reg(phw_data, 0x80, mac_ctrl);
hw_set_cxx_reg(phw_data, 0xE4, rf_ctrl);
hw_set_dxx_reg(phw_data, 0x58, iq_alpha);
- //------------------------------------------------------------------------
+ /*********************************************************************/
phy_init_rf(phw_data);
}
-//===========================
-void phy_set_rf_data( struct hw_data * pHwData, u32 index, u32 value )
+/******************/
+void phy_set_rf_data(struct hw_data *pHwData, u32 index, u32 value)
{
- u32 ltmp=0;
-
- switch( pHwData->phy_type )
- {
- case RF_MAXIM_2825:
- case RF_MAXIM_V1: // 11g Winbond 2nd BB(with Phy board (v1) + Maxim 331)
- ltmp = (1 << 31) | (0 << 30) | (18 << 24) | BitReverse( value, 18 );
- break;
-
- case RF_MAXIM_2827:
- ltmp = (1 << 31) | (0 << 30) | (18 << 24) | BitReverse( value, 18 );
- break;
-
- case RF_MAXIM_2828:
- ltmp = (1 << 31) | (0 << 30) | (18 << 24) | BitReverse( value, 18 );
- break;
-
- case RF_MAXIM_2829:
- ltmp = (1 << 31) | (0 << 30) | (18 << 24) | BitReverse( value, 18 );
- break;
-
- case RF_AIROHA_2230:
- case RF_AIROHA_2230S: // 20060420 Add this
- ltmp = (1 << 31) | (0 << 30) | (20 << 24) | BitReverse( value, 20 );
- break;
-
- case RF_AIROHA_7230:
- ltmp = (1 << 31) | (0 << 30) | (24 << 24) | (value&0xffffff);
- break;
-
- case RF_WB_242:
- case RF_WB_242_1: // 20060619.5 Add
- ltmp = (1 << 31) | (0 << 30) | (24 << 24) | BitReverse( value, 24 );
- break;
- }
+ u32 ltmp = 0;
+
+ switch (pHwData->phy_type) {
+ case RF_MAXIM_2825:
+ case RF_MAXIM_V1: /* 11g Winbond 2nd BB(with Phy board (v1) + Maxim 331) */
+ ltmp = (1 << 31) | (0 << 30) | (18 << 24) | BitReverse(value, 18);
+ break;
+
+ case RF_MAXIM_2827:
+ ltmp = (1 << 31) | (0 << 30) | (18 << 24) | BitReverse(value, 18);
+ break;
+
+ case RF_MAXIM_2828:
+ ltmp = (1 << 31) | (0 << 30) | (18 << 24) | BitReverse(value, 18);
+ break;
+
+ case RF_MAXIM_2829:
+ ltmp = (1 << 31) | (0 << 30) | (18 << 24) | BitReverse(value, 18);
+ break;
+
+ case RF_AIROHA_2230:
+ case RF_AIROHA_2230S: /* 20060420 Add this */
+ ltmp = (1 << 31) | (0 << 30) | (20 << 24) | BitReverse(value, 20);
+ break;
+
+ case RF_AIROHA_7230:
+ ltmp = (1 << 31) | (0 << 30) | (24 << 24) | (value&0xffffff);
+ break;
+
+ case RF_WB_242:
+ case RF_WB_242_1:/* 20060619.5 Add */
+ ltmp = (1 << 31) | (0 << 30) | (24 << 24) | BitReverse(value, 24);
+ break;
+ }
- Wb35Reg_WriteSync( pHwData, 0x0864, ltmp );
+ Wb35Reg_WriteSync(pHwData, 0x0864, ltmp);
}
-// 20060717 modify as Bruce's mail
+/* 20060717 modify as Bruce's mail */
unsigned char adjust_TXVGA_for_iq_mag(struct hw_data *phw_data)
{
int init_txvga = 0;
@@ -1685,26 +1543,27 @@ unsigned char adjust_TXVGA_for_iq_mag(struct hw_data *phw_data)
s32 iqcal_tone_q0;
u32 sqsum;
s32 iq_mag_0_tx;
- u8 reg_state;
- int current_txvga;
+ u8 reg_state;
+ int current_txvga;
reg_state = 0;
- for( init_txvga=0; init_txvga<10; init_txvga++)
- {
- current_txvga = ( 0x24C40A|(init_txvga<<6) );
- phy_set_rf_data(phw_data, 5, ((5<<24)|current_txvga) );
+ for (init_txvga = 0; init_txvga < 10; init_txvga++) {
+ current_txvga = (0x24C40A|(init_txvga<<6));
+ phy_set_rf_data(phw_data, 5, ((5<<24)|current_txvga));
phw_data->txvga_setting_for_cal = current_txvga;
- msleep(30); // 20060612.1.a
+ msleep(30);/* 20060612.1.a */
- if( !hw_get_dxx_reg(phw_data, REG_MODE_CTRL, &reg_mode_ctrl) ) // 20060718.1 modify
+ if (!hw_get_dxx_reg(phw_data, REG_MODE_CTRL, &reg_mode_ctrl))/* 20060718.1 modify */
return false;
PHY_DEBUG(("[CAL] MODE_CTRL (read) = 0x%08X\n", reg_mode_ctrl));
- // a. Set iqcal_mode[1:0] to 0x2 and set "calib_start" to 0x1 to
- // enable "IQ alibration Mode II"
+ /*
+ * a. Set iqcal_mode[1:0] to 0x2 and set "calib_start" to 0x1 to
+ * enable "IQ alibration Mode II"
+ */
reg_mode_ctrl &= ~(MASK_IQCAL_TONE_SEL|MASK_IQCAL_MODE);
reg_mode_ctrl &= ~MASK_IQCAL_MODE;
reg_mode_ctrl |= (MASK_CALIB_START|0x02);
@@ -1712,15 +1571,15 @@ unsigned char adjust_TXVGA_for_iq_mag(struct hw_data *phw_data)
hw_set_dxx_reg(phw_data, REG_MODE_CTRL, reg_mode_ctrl);
PHY_DEBUG(("[CAL] MODE_CTRL (write) = 0x%08X\n", reg_mode_ctrl));
- udelay(1); // 20060612.1.a
+ udelay(1);/* 20060612.1.a */
- udelay(300); // 20060612.1.a
+ udelay(300);/* 20060612.1.a */
- // b.
+ /* b. */
hw_get_dxx_reg(phw_data, REG_CALIB_READ1, &val);
PHY_DEBUG(("[CAL] CALIB_READ1 = 0x%08X\n", val));
- udelay(300); // 20060612.1.a
+ udelay(300);/* 20060612.1.a */
iqcal_tone_i0 = _s13_to_s32(val & 0x00001FFF);
iqcal_tone_q0 = _s13_to_s32((val & 0x03FFE000) >> 13);
@@ -1731,23 +1590,18 @@ unsigned char adjust_TXVGA_for_iq_mag(struct hw_data *phw_data)
iq_mag_0_tx = (s32) _sqrt(sqsum);
PHY_DEBUG(("[CAL] ** auto_adjust_txvga_for_iq_mag_0_tx=%d\n", iq_mag_0_tx));
- if( iq_mag_0_tx>=700 && iq_mag_0_tx<=1750 )
+ if (iq_mag_0_tx >= 700 && iq_mag_0_tx <= 1750)
break;
- else if(iq_mag_0_tx > 1750)
- {
- init_txvga=-2;
+ else if (iq_mag_0_tx > 1750) {
+ init_txvga = -2;
continue;
- }
- else
+ } else
continue;
}
- if( iq_mag_0_tx>=700 && iq_mag_0_tx<=1750 )
+ if (iq_mag_0_tx >= 700 && iq_mag_0_tx <= 1750)
return true;
else
return false;
}
-
-
-
diff --git a/drivers/staging/winbond/reg.c b/drivers/staging/winbond/reg.c
index d9a8128b21f..990f9d4bdbb 100644
--- a/drivers/staging/winbond/reg.c
+++ b/drivers/staging/winbond/reg.c
@@ -966,42 +966,42 @@ void RFSynthesizer_initial(struct hw_data *pHwData)
switch (pHwData->phy_type) {
case RF_MAXIM_2825:
case RF_MAXIM_V1: /* 11g Winbond 2nd BB(with Phy board (v1) + Maxim 331) */
- number = sizeof(max2825_rf_data) / sizeof(max2825_rf_data[0]);
+ number = ARRAY_SIZE(max2825_rf_data);
for (i = 0; i < number; i++) {
pHwData->phy_para[i] = max2825_rf_data[i]; /* Backup Rf parameter */
pltmp[i] = (1 << 31) | (0 << 30) | (18 << 24) | BitReverse(max2825_rf_data[i], 18);
}
break;
case RF_MAXIM_2827:
- number = sizeof(max2827_rf_data) / sizeof(max2827_rf_data[0]);
+ number = ARRAY_SIZE(max2827_rf_data);
for (i = 0; i < number; i++) {
pHwData->phy_para[i] = max2827_rf_data[i];
pltmp[i] = (1 << 31) | (0 << 30) | (18 << 24) | BitReverse(max2827_rf_data[i], 18);
}
break;
case RF_MAXIM_2828:
- number = sizeof(max2828_rf_data) / sizeof(max2828_rf_data[0]);
+ number = ARRAY_SIZE(max2828_rf_data);
for (i = 0; i < number; i++) {
pHwData->phy_para[i] = max2828_rf_data[i];
pltmp[i] = (1 << 31) | (0 << 30) | (18 << 24) | BitReverse(max2828_rf_data[i], 18);
}
break;
case RF_MAXIM_2829:
- number = sizeof(max2829_rf_data) / sizeof(max2829_rf_data[0]);
+ number = ARRAY_SIZE(max2829_rf_data);
for (i = 0; i < number; i++) {
pHwData->phy_para[i] = max2829_rf_data[i];
pltmp[i] = (1 << 31) | (0 << 30) | (18 << 24) | BitReverse(max2829_rf_data[i], 18);
}
break;
case RF_AIROHA_2230:
- number = sizeof(al2230_rf_data) / sizeof(al2230_rf_data[0]);
+ number = ARRAY_SIZE(al2230_rf_data);
for (i = 0; i < number; i++) {
pHwData->phy_para[i] = al2230_rf_data[i];
pltmp[i] = (1 << 31) | (0 << 30) | (20 << 24) | BitReverse(al2230_rf_data[i], 20);
}
break;
case RF_AIROHA_2230S:
- number = sizeof(al2230s_rf_data) / sizeof(al2230s_rf_data[0]);
+ number = ARRAY_SIZE(al2230s_rf_data);
for (i = 0; i < number; i++) {
pHwData->phy_para[i] = al2230s_rf_data[i];
pltmp[i] = (1 << 31) | (0 << 30) | (20 << 24) | BitReverse(al2230s_rf_data[i], 20);
@@ -1013,12 +1013,12 @@ void RFSynthesizer_initial(struct hw_data *pHwData)
#ifdef _PE_STATE_DUMP_
printk("* PLL_ON low\n");
#endif
- number = sizeof(al7230_rf_data_24) / sizeof(al7230_rf_data_24[0]);
+ number = ARRAY_SIZE(al7230_rf_data_24);
Set_ChanIndep_RfData_al7230_24(pHwData, pltmp, number);
break;
case RF_WB_242:
case RF_WB_242_1:
- number = sizeof(w89rf242_rf_data) / sizeof(w89rf242_rf_data[0]);
+ number = ARRAY_SIZE(w89rf242_rf_data);
for (i = 0; i < number; i++) {
ltmp = w89rf242_rf_data[i];
if (i == 4) { /* Update the VCO trim from EEPROM */
@@ -1119,7 +1119,7 @@ void RFSynthesizer_initial(struct hw_data *pHwData)
printk("* PLL_ON low\n");
#endif
- number = sizeof(al7230_rf_data_50) / sizeof(al7230_rf_data_50[0]);
+ number = ARRAY_SIZE(al7230_rf_data_50);
Set_ChanIndep_RfData_al7230_50(pHwData, pltmp, number);
/* Write to register. number must less and equal than 16 */
for (i = 0; i < number; i++)
@@ -1747,7 +1747,7 @@ void RFSynthesizer_SwitchingChannel(struct hw_data *pHwData, struct chan_info C
pltmp[i] = (1 << 31) | (0 << 30) | (18 << 24) | BitReverse(max2829_channel_data_24[Channel.ChanNo-1][i], 18);
Wb35Reg_BurstWrite(pHwData, 0x0864, pltmp, 3, NO_INCREMENT);
} else if (Channel.band == BAND_TYPE_OFDM_5) {
- count = sizeof(max2829_channel_data_50) / sizeof(max2829_channel_data_50[0]);
+ count = ARRAY_SIZE(max2829_channel_data_50);
for (i = 0; i < count; i++) {
if (max2829_channel_data_50[i][0] == Channel.ChanNo) {
@@ -1783,13 +1783,13 @@ void RFSynthesizer_SwitchingChannel(struct hw_data *pHwData, struct chan_info C
/* Update BB register */
BBProcessor_AL7230_2400(pHwData);
- number = sizeof(al7230_rf_data_24) / sizeof(al7230_rf_data_24[0]);
+ number = ARRAY_SIZE(al7230_rf_data_24);
Set_ChanIndep_RfData_al7230_24(pHwData, pltmp, number);
} else {
/* Update BB register */
BBProcessor_AL7230_5000(pHwData);
- number = sizeof(al7230_rf_data_50) / sizeof(al7230_rf_data_50[0]);
+ number = ARRAY_SIZE(al7230_rf_data_50);
Set_ChanIndep_RfData_al7230_50(pHwData, pltmp, number);
}
@@ -1814,7 +1814,7 @@ void RFSynthesizer_SwitchingChannel(struct hw_data *pHwData, struct chan_info C
Wb35Reg_Write(pHwData, 0x0864, ltmp);
}
- count = sizeof(al7230_channel_data_5) / sizeof(al7230_channel_data_5[0]);
+ count = ARRAY_SIZE(al7230_channel_data_5);
for (i = 0; i < count; i++) {
if (al7230_channel_data_5[i][0] == Channel.ChanNo) {
@@ -1978,7 +1978,7 @@ u8 RFSynthesizer_SetAiroha2230Power(struct hw_data *pHwData, u8 index)
u32 PowerData;
u8 i, count;
- count = sizeof(al2230_txvga_data) / sizeof(al2230_txvga_data[0]);
+ count = ARRAY_SIZE(al2230_txvga_data);
for (i = 0; i < count; i++) {
if (al2230_txvga_data[i][1] >= index)
break;
@@ -1996,7 +1996,7 @@ u8 RFSynthesizer_SetAiroha7230Power(struct hw_data *pHwData, u8 index)
u32 PowerData;
u8 i, count;
- count = sizeof(al7230_txvga_data) / sizeof(al7230_txvga_data[0]);
+ count = ARRAY_SIZE(al7230_txvga_data);
for (i = 0; i < count; i++) {
if (al7230_txvga_data[i][1] >= index)
break;
@@ -2013,7 +2013,7 @@ u8 RFSynthesizer_SetWinbond242Power(struct hw_data *pHwData, u8 index)
u32 PowerData;
u8 i, count;
- count = sizeof(w89rf242_txvga_data) / sizeof(w89rf242_txvga_data[0]);
+ count = ARRAY_SIZE(w89rf242_txvga_data);
for (i = 0; i < count; i++) {
if (w89rf242_txvga_data[i][1] >= index)
break;
@@ -2184,14 +2184,14 @@ void GetTxVgaFromEEPROM(struct hw_data *pHwData)
/* Adjust WB_242 to WB_242_1 TxVga scale */
if (pHwData->phy_type == RF_WB_242) {
for (i = 0; i < 4; i++) { /* Only 2412 2437 2462 2484 case must be modified */
- for (j = 0; j < (sizeof(w89rf242_txvga_old_mapping) / sizeof(w89rf242_txvga_old_mapping[0])); j++) {
+ for (j = 0; j < ARRAY_SIZE(w89rf242_txvga_old_mapping); j++) {
if (pctmp[i] < (u8) w89rf242_txvga_old_mapping[j][1]) {
pctmp[i] = (u8) w89rf242_txvga_old_mapping[j][0];
break;
}
}
- if (j == (sizeof(w89rf242_txvga_old_mapping) / sizeof(w89rf242_txvga_old_mapping[0])))
+ if (j == ARRAY_SIZE(w89rf242_txvga_old_mapping))
pctmp[i] = (u8)w89rf242_txvga_old_mapping[j-1][0];
}
}
diff --git a/drivers/staging/winbond/wbusb.c b/drivers/staging/winbond/wbusb.c
index 681419d6856..abaa05a630f 100644
--- a/drivers/staging/winbond/wbusb.c
+++ b/drivers/staging/winbond/wbusb.c
@@ -1,5 +1,5 @@
/*
- * Copyright 2008 Pavel Machek <pavel@suse.cz>
+ * Copyright 2008 Pavel Machek <pavel@ucw.cz>
*
* Distribute under GPLv2.
*
@@ -700,7 +700,7 @@ static int wb35_hw_init(struct ieee80211_hw *hw)
Mds_initial(priv);
/*
- * If no user-defined address in the registry, use the addresss
+ * If no user-defined address in the registry, use the address
* "burned" on the NIC instead.
*/
pMacAddr = priv->sLocalPara.ThisMacAddress;
diff --git a/drivers/staging/wlags49_h2/hcf.c b/drivers/staging/wlags49_h2/hcf.c
index 390628c6c1e..c4fe0ec9507 100644
--- a/drivers/staging/wlags49_h2/hcf.c
+++ b/drivers/staging/wlags49_h2/hcf.c
@@ -502,7 +502,7 @@ HCF_STATIC hcf_16* BASED xxxx[ ] = {
#endif // MSF_COMPONENT_ID
NULL //endsentinel
};
-#define xxxx_PRI_IDENTITY_OFFSET (sizeof(xxxx)/sizeof(xxxx[0]) - 3)
+#define xxxx_PRI_IDENTITY_OFFSET (ARRAY_SIZE(xxxx) - 3)
#endif // MSF_COMPONENT_ID / HCF_EXT_MB
diff --git a/drivers/staging/wlags49_h2/mdd.h b/drivers/staging/wlags49_h2/mdd.h
index b45c7ddd92e..b50b7b0a5ca 100644
--- a/drivers/staging/wlags49_h2/mdd.h
+++ b/drivers/staging/wlags49_h2/mdd.h
@@ -727,10 +727,10 @@ XX1( CFG_SCAN, SCAN_RS_STRCT, scan_result[32] ) /*Scan results *
#define CFG_FCBE 0xFCBE //FW codes ahead of available documentation, so ???????
#define CFG_FCBF 0xFCBF //FW codes ahead of available documentation, so ???????
-#define CFG_HANDOVER_ADDR 0xFCC0 //[AP] Station MAC Adrress re-associated with other AP
+#define CFG_HANDOVER_ADDR 0xFCC0 //[AP] Station MAC Address re-associated with other AP
#define CFG_SCAN_CHANNEL 0xFCC2 //Channel set for host requested scan
//;?#define CFG_SCAN_CHANNEL_MASK 0xFCC2 // contains
-#define CFG_DISASSOCIATE_ADDR 0xFCC4 //[AP] Station MAC Adrress to be disassociated
+#define CFG_DISASSOCIATE_ADDR 0xFCC4 //[AP] Station MAC Address to be disassociated
#define CFG_PROBE_DATA_RATE 0xFCC5 //WARP connection control
#define CFG_FRAME_BURST_LIMIT 0xFCC6 //
#define CFG_COEXISTENSE_BEHAVIOUR 0xFCC7 //[AP]
diff --git a/drivers/staging/wlags49_h2/wl_cs.c b/drivers/staging/wlags49_h2/wl_cs.c
index 10abd406b09..19c33545865 100644
--- a/drivers/staging/wlags49_h2/wl_cs.c
+++ b/drivers/staging/wlags49_h2/wl_cs.c
@@ -23,7 +23,7 @@
* software indicates your acceptance of these terms and conditions. If you do
* not agree with these terms and conditions, do not use the software.
*
- * Copyright © 2003 Agere Systems Inc.
+ * Copyright (c) 2003 Agere Systems Inc.
* All rights reserved.
*
* Redistribution and use in source or binary forms, with or without
@@ -44,7 +44,7 @@
*
* Disclaimer
*
- * THIS SOFTWARE IS PROVIDED “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, INFRINGEMENT AND THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ANY
* USE, MODIFICATION OR DISTRIBUTION OF THIS SOFTWARE IS SOLELY AT THE USERS OWN
@@ -83,7 +83,6 @@
#include <linux/if_arp.h>
#include <linux/ioport.h>
-#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/cistpl.h>
#include <pcmcia/cisreg.h>
@@ -133,36 +132,35 @@ extern dbg_info_t *DbgInfo;
******************************************************************************/
static int wl_adapter_attach(struct pcmcia_device *link)
{
- struct net_device *dev;
- struct wl_private *lp;
- /*------------------------------------------------------------------------*/
-
- DBG_FUNC( "wl_adapter_attach" );
- DBG_ENTER( DbgInfo );
-
- dev = wl_device_alloc();
- if(dev == NULL) {
- DBG_ERROR( DbgInfo, "wl_device_alloc returned NULL\n");
- return -ENOMEM;
- }
-
- link->io.NumPorts1 = HCF_NUM_IO_PORTS;
- link->io.Attributes1 = IO_DATA_PATH_WIDTH_16;
- link->io.IOAddrLines = 6;
- link->conf.Attributes = CONF_ENABLE_IRQ;
- link->conf.IntType = INT_MEMORY_AND_IO;
- link->conf.ConfigIndex = 5;
- link->conf.Present = PRESENT_OPTION;
-
- link->priv = dev;
- lp = wl_priv(dev);
- lp->link = link;
-
- wl_adapter_insert(link);
-
- DBG_LEAVE( DbgInfo );
- return 0;
-} // wl_adapter_attach
+ struct net_device *dev;
+ struct wl_private *lp;
+ /*--------------------------------------------------------------------*/
+
+ DBG_FUNC("wl_adapter_attach");
+ DBG_ENTER(DbgInfo);
+
+ dev = wl_device_alloc();
+ if (dev == NULL) {
+ DBG_ERROR(DbgInfo, "wl_device_alloc returned NULL\n");
+ return -ENOMEM;
+ }
+
+ link->resource[0]->end = HCF_NUM_IO_PORTS;
+ link->resource[0]->flags= IO_DATA_PATH_WIDTH_16;
+ link->conf.Attributes = CONF_ENABLE_IRQ;
+ link->conf.IntType = INT_MEMORY_AND_IO;
+ link->conf.ConfigIndex = 5;
+ link->conf.Present = PRESENT_OPTION;
+
+ link->priv = dev;
+ lp = wl_priv(dev);
+ lp->link = link;
+
+ wl_adapter_insert(link);
+
+ DBG_LEAVE(DbgInfo);
+ return 0;
+} /* wl_adapter_attach */
/*============================================================================*/
@@ -190,25 +188,24 @@ static int wl_adapter_attach(struct pcmcia_device *link)
******************************************************************************/
static void wl_adapter_detach(struct pcmcia_device *link)
{
- struct net_device *dev = link->priv;
- /*------------------------------------------------------------------------*/
-
+ struct net_device *dev = link->priv;
+ /*--------------------------------------------------------------------*/
- DBG_FUNC( "wl_adapter_detach" );
- DBG_ENTER( DbgInfo );
- DBG_PARAM( DbgInfo, "link", "0x%p", link );
+ DBG_FUNC("wl_adapter_detach");
+ DBG_ENTER(DbgInfo);
+ DBG_PARAM(DbgInfo, "link", "0x%p", link);
- wl_adapter_release(link);
+ wl_adapter_release(link);
- if (dev) {
- unregister_wlags_sysfs(dev);
- unregister_netdev(dev);
- }
+ if (dev) {
+ unregister_wlags_sysfs(dev);
+ unregister_netdev(dev);
+ }
- wl_device_dealloc(dev);
+ wl_device_dealloc(dev);
- DBG_LEAVE( DbgInfo );
-} // wl_adapter_detach
+ DBG_LEAVE(DbgInfo);
+} /* wl_adapter_detach */
/*============================================================================*/
@@ -232,33 +229,33 @@ static void wl_adapter_detach(struct pcmcia_device *link)
* N/A
*
******************************************************************************/
-void wl_adapter_release( struct pcmcia_device *link )
+void wl_adapter_release(struct pcmcia_device *link)
{
- DBG_FUNC( "wl_adapter_release" );
- DBG_ENTER( DbgInfo );
- DBG_PARAM( DbgInfo, "link", "0x%p", link);
+ DBG_FUNC("wl_adapter_release");
+ DBG_ENTER(DbgInfo);
+ DBG_PARAM(DbgInfo, "link", "0x%p", link);
- /* Stop hardware */
- wl_remove(link->priv);
+ /* Stop hardware */
+ wl_remove(link->priv);
- pcmcia_disable_device(link);
+ pcmcia_disable_device(link);
- DBG_LEAVE( DbgInfo );
-} // wl_adapter_release
+ DBG_LEAVE(DbgInfo);
+} /* wl_adapter_release */
/*============================================================================*/
static int wl_adapter_suspend(struct pcmcia_device *link)
{
- struct net_device *dev = link->priv;
+ struct net_device *dev = link->priv;
- //if (link->open) {
+ /* if (link->open) { */
netif_device_detach(dev);
wl_suspend(dev);
-//// CHECK! pcmcia_release_configuration(link->handle);
- //}
+ /* CHECK! pcmcia_release_configuration(link->handle); */
+ /* } */
- return 0;
-} // wl_adapter_suspend
+ return 0;
+} /* wl_adapter_suspend */
static int wl_adapter_resume(struct pcmcia_device *link)
{
@@ -266,10 +263,10 @@ static int wl_adapter_resume(struct pcmcia_device *link)
wl_resume(dev);
- netif_device_attach( dev );
+ netif_device_attach(dev);
return 0;
-} // wl_adapter_resume
+} /* wl_adapter_resume */
/*******************************************************************************
* wl_adapter_insert()
@@ -291,60 +288,60 @@ static int wl_adapter_resume(struct pcmcia_device *link)
* N/A
*
******************************************************************************/
-void wl_adapter_insert( struct pcmcia_device *link )
+void wl_adapter_insert(struct pcmcia_device *link)
{
- struct net_device *dev;
- int i;
- int ret;
- /*------------------------------------------------------------------------*/
+ struct net_device *dev;
+ int i;
+ int ret;
+ /*--------------------------------------------------------------------*/
- DBG_FUNC( "wl_adapter_insert" );
- DBG_ENTER( DbgInfo );
- DBG_PARAM( DbgInfo, "link", "0x%p", link );
+ DBG_FUNC("wl_adapter_insert");
+ DBG_ENTER(DbgInfo);
+ DBG_PARAM(DbgInfo, "link", "0x%p", link);
- dev = link->priv;
+ dev = link->priv;
- /* Do we need to allocate an interrupt? */
- link->conf.Attributes |= CONF_ENABLE_IRQ;
+ /* Do we need to allocate an interrupt? */
+ link->conf.Attributes |= CONF_ENABLE_IRQ;
+ link->io_lines = 6;
- ret = pcmcia_request_io(link, &link->io);
- if (ret != 0)
- goto failed;
+ ret = pcmcia_request_io(link);
+ if (ret != 0)
+ goto failed;
- ret = pcmcia_request_irq(link, (void *) wl_isr);
- if (ret != 0)
- goto failed;
+ ret = pcmcia_request_irq(link, (void *) wl_isr);
+ if (ret != 0)
+ goto failed;
- ret = pcmcia_request_configuration(link, &link->conf);
- if (ret != 0)
- goto failed;
+ ret = pcmcia_request_configuration(link, &link->conf);
+ if (ret != 0)
+ goto failed;
- dev->irq = link->irq;
- dev->base_addr = link->io.BasePort1;
+ dev->irq = link->irq;
+ dev->base_addr = link->resource[0]->start;
- SET_NETDEV_DEV(dev, &link->dev);
- if (register_netdev(dev) != 0) {
- printk("%s: register_netdev() failed\n", MODULE_NAME);
- goto failed;
- }
+ SET_NETDEV_DEV(dev, &link->dev);
+ if (register_netdev(dev) != 0) {
+ printk("%s: register_netdev() failed\n", MODULE_NAME);
+ goto failed;
+ }
- register_wlags_sysfs(dev);
+ register_wlags_sysfs(dev);
- printk(KERN_INFO "%s: Wireless, io_addr %#03lx, irq %d, ""mac_address ",
- dev->name, dev->base_addr, dev->irq);
- for( i = 0; i < ETH_ALEN; i++ ) {
- printk("%02X%c", dev->dev_addr[i], ((i < (ETH_ALEN-1)) ? ':' : '\n'));
- }
+ printk(KERN_INFO "%s: Wireless, io_addr %#03lx, irq %d, ""mac_address ",
+ dev->name, dev->base_addr, dev->irq);
+ for (i = 0; i < ETH_ALEN; i++)
+ printk("%02X%c", dev->dev_addr[i], ((i < (ETH_ALEN-1)) ? ':' : '\n'));
- DBG_LEAVE( DbgInfo );
- return;
+ DBG_LEAVE(DbgInfo);
+ return;
failed:
- wl_adapter_release( link );
+ wl_adapter_release(link);
- DBG_LEAVE(DbgInfo);
- return;
-} // wl_adapter_insert
+ DBG_LEAVE(DbgInfo);
+ return;
+} /* wl_adapter_insert */
/*============================================================================*/
@@ -367,38 +364,36 @@ failed:
* errno value otherwise
*
******************************************************************************/
-int wl_adapter_open( struct net_device *dev )
+int wl_adapter_open(struct net_device *dev)
{
- struct wl_private *lp = wl_priv(dev);
- struct pcmcia_device *link = lp->link;
- int result = 0;
- int hcf_status = HCF_SUCCESS;
- /*------------------------------------------------------------------------*/
-
-
- DBG_FUNC( "wl_adapter_open" );
- DBG_ENTER( DbgInfo );
- DBG_PRINT( "%s\n", VERSION_INFO );
- DBG_PARAM( DbgInfo, "dev", "%s (0x%p)", dev->name, dev );
-
- if(!pcmcia_dev_present(link))
- {
- DBG_LEAVE( DbgInfo );
- return -ENODEV;
- }
-
- link->open++;
-
- hcf_status = wl_open( dev );
-
- if( hcf_status != HCF_SUCCESS ) {
- link->open--;
- result = -ENODEV;
- }
-
- DBG_LEAVE( DbgInfo );
- return result;
-} // wl_adapter_open
+ struct wl_private *lp = wl_priv(dev);
+ struct pcmcia_device *link = lp->link;
+ int result = 0;
+ int hcf_status = HCF_SUCCESS;
+ /*--------------------------------------------------------------------*/
+
+ DBG_FUNC("wl_adapter_open");
+ DBG_ENTER(DbgInfo);
+ DBG_PRINT("%s\n", VERSION_INFO);
+ DBG_PARAM(DbgInfo, "dev", "%s (0x%p)", dev->name, dev);
+
+ if (!pcmcia_dev_present(link)) {
+ DBG_LEAVE(DbgInfo);
+ return -ENODEV;
+ }
+
+ link->open++;
+
+ hcf_status = wl_open(dev);
+
+ if (hcf_status != HCF_SUCCESS) {
+ link->open--;
+ result = -ENODEV;
+ }
+
+ DBG_LEAVE(DbgInfo);
+ return result;
+} /* wl_adapter_open */
/*============================================================================*/
@@ -421,56 +416,55 @@ int wl_adapter_open( struct net_device *dev )
* errno value otherwise
*
******************************************************************************/
-int wl_adapter_close( struct net_device *dev )
+int wl_adapter_close(struct net_device *dev)
{
- struct wl_private *lp = wl_priv(dev);
- struct pcmcia_device *link = lp->link;
- /*------------------------------------------------------------------------*/
+ struct wl_private *lp = wl_priv(dev);
+ struct pcmcia_device *link = lp->link;
+ /*--------------------------------------------------------------------*/
+ DBG_FUNC("wl_adapter_close");
+ DBG_ENTER(DbgInfo);
+ DBG_PARAM(DbgInfo, "dev", "%s (0x%p)", dev->name, dev);
- DBG_FUNC( "wl_adapter_close" );
- DBG_ENTER( DbgInfo );
- DBG_PARAM( DbgInfo, "dev", "%s (0x%p)", dev->name, dev );
+ if (link == NULL) {
+ DBG_LEAVE(DbgInfo);
+ return -ENODEV;
+ }
- if( link == NULL ) {
- DBG_LEAVE( DbgInfo );
- return -ENODEV;
- }
+ DBG_TRACE(DbgInfo, "%s: Shutting down adapter.\n", dev->name);
+ wl_close(dev);
- DBG_TRACE( DbgInfo, "%s: Shutting down adapter.\n", dev->name );
- wl_close( dev );
+ link->open--;
- link->open--;
-
- DBG_LEAVE( DbgInfo );
- return 0;
-} // wl_adapter_close
+ DBG_LEAVE(DbgInfo);
+ return 0;
+} /* wl_adapter_close */
/*============================================================================*/
static struct pcmcia_device_id wl_adapter_ids[] = {
-#if ! ((HCF_TYPE) & HCF_TYPE_HII5)
+#if !((HCF_TYPE) & HCF_TYPE_HII5)
PCMCIA_DEVICE_MANF_CARD(0x0156, 0x0003),
PCMCIA_DEVICE_PROD_ID12("Agere Systems", "Wireless PC Card Model 0110",
- 0x33103a9b, 0xe175b0dd),
+ 0x33103a9b, 0xe175b0dd),
#else
PCMCIA_DEVICE_MANF_CARD(0x0156, 0x0004),
PCMCIA_DEVICE_PROD_ID12("Linksys", "WCF54G_Wireless-G_CompactFlash_Card",
- 0x0733cc81, 0x98a599e1),
-#endif // (HCF_TYPE) & HCF_TYPE_HII5
+ 0x0733cc81, 0x98a599e1),
+#endif /* (HCF_TYPE) & HCF_TYPE_HII5 */
PCMCIA_DEVICE_NULL,
- };
+};
MODULE_DEVICE_TABLE(pcmcia, wl_adapter_ids);
static struct pcmcia_driver wlags49_driver = {
- .owner = THIS_MODULE,
- .drv = {
- .name = DRIVER_NAME,
- },
- .probe = wl_adapter_attach,
- .remove = wl_adapter_detach,
- .id_table = wl_adapter_ids,
- .suspend = wl_adapter_suspend,
- .resume = wl_adapter_resume,
+ .owner = THIS_MODULE,
+ .drv = {
+ .name = DRIVER_NAME,
+ },
+ .probe = wl_adapter_attach,
+ .remove = wl_adapter_detach,
+ .id_table = wl_adapter_ids,
+ .suspend = wl_adapter_suspend,
+ .resume = wl_adapter_resume,
};
@@ -493,21 +487,20 @@ static struct pcmcia_driver wlags49_driver = {
* -1 on error
*
******************************************************************************/
-int wl_adapter_init_module( void )
+int wl_adapter_init_module(void)
{
- int ret;
- /*------------------------------------------------------------------------*/
+ int ret;
+ /*--------------------------------------------------------------------*/
+ DBG_FUNC("wl_adapter_init_module");
+ DBG_ENTER(DbgInfo);
+ DBG_TRACE(DbgInfo, "wl_adapter_init_module() -- PCMCIA\n");
- DBG_FUNC( "wl_adapter_init_module" );
- DBG_ENTER( DbgInfo );
- DBG_TRACE( DbgInfo, "wl_adapter_init_module() -- PCMCIA\n" );
+ ret = pcmcia_register_driver(&wlags49_driver);
- ret = pcmcia_register_driver(&wlags49_driver);
-
- DBG_LEAVE( DbgInfo );
- return ret;
-} // wl_adapter_init_module
+ DBG_LEAVE(DbgInfo);
+ return ret;
+} /* wl_adapter_init_module */
/*============================================================================*/
@@ -528,18 +521,18 @@ int wl_adapter_init_module( void )
* N/A
*
******************************************************************************/
-void wl_adapter_cleanup_module( void )
+void wl_adapter_cleanup_module(void)
{
- DBG_FUNC( "wl_adapter_cleanup_module" );
- DBG_ENTER( DbgInfo );
- DBG_TRACE( DbgInfo, "wl_adapter_cleanup_module() -- PCMCIA\n" );
+ DBG_FUNC("wl_adapter_cleanup_module");
+ DBG_ENTER(DbgInfo);
+ DBG_TRACE(DbgInfo, "wl_adapter_cleanup_module() -- PCMCIA\n");
- pcmcia_unregister_driver(&wlags49_driver);
+ pcmcia_unregister_driver(&wlags49_driver);
- DBG_LEAVE( DbgInfo );
- return;
-} // wl_adapter_cleanup_module
+ DBG_LEAVE(DbgInfo);
+ return;
+} /* wl_adapter_cleanup_module */
/*============================================================================*/
@@ -562,17 +555,16 @@ void wl_adapter_cleanup_module( void )
* 0 otherwise
*
******************************************************************************/
-int wl_adapter_is_open( struct net_device *dev )
+int wl_adapter_is_open(struct net_device *dev)
{
- struct wl_private *lp = wl_priv(dev);
- struct pcmcia_device *link = lp->link;
+ struct wl_private *lp = wl_priv(dev);
+ struct pcmcia_device *link = lp->link;
- if(!pcmcia_dev_present(link)) {
- return 0;
- }
+ if (!pcmcia_dev_present(link))
+ return 0;
- return( link->open );
-} // wl_adapter_is_open
+ return link->open;
+} /* wl_adapter_is_open */
/*============================================================================*/
@@ -596,97 +588,95 @@ int wl_adapter_is_open( struct net_device *dev )
* a pointer to a string describing the error(s)
*
******************************************************************************/
-const char* DbgEvent( int mask )
+const char *DbgEvent(int mask)
{
- static char DbgBuffer[256];
- char *pBuf;
- /*------------------------------------------------------------------------*/
-
+ static char DbgBuffer[256];
+ char *pBuf;
+ /*--------------------------------------------------------------------*/
- pBuf = DbgBuffer;
- *pBuf = '\0';
+ pBuf = DbgBuffer;
+ *pBuf = '\0';
- if( mask & CS_EVENT_WRITE_PROTECT )
- strcat( pBuf, "WRITE_PROTECT " );
+ if (mask & CS_EVENT_WRITE_PROTECT)
+ strcat(pBuf, "WRITE_PROTECT ");
- if(mask & CS_EVENT_CARD_LOCK)
- strcat( pBuf, "CARD_LOCK " );
+ if (mask & CS_EVENT_CARD_LOCK)
+ strcat(pBuf, "CARD_LOCK ");
- if(mask & CS_EVENT_CARD_INSERTION)
- strcat( pBuf, "CARD_INSERTION " );
+ if (mask & CS_EVENT_CARD_INSERTION)
+ strcat(pBuf, "CARD_INSERTION ");
- if(mask & CS_EVENT_CARD_REMOVAL)
- strcat( pBuf, "CARD_REMOVAL " );
+ if (mask & CS_EVENT_CARD_REMOVAL)
+ strcat(pBuf, "CARD_REMOVAL ");
- if(mask & CS_EVENT_BATTERY_DEAD)
- strcat( pBuf, "BATTERY_DEAD " );
+ if (mask & CS_EVENT_BATTERY_DEAD)
+ strcat(pBuf, "BATTERY_DEAD ");
- if(mask & CS_EVENT_BATTERY_LOW)
- strcat( pBuf, "BATTERY_LOW " );
+ if (mask & CS_EVENT_BATTERY_LOW)
+ strcat(pBuf, "BATTERY_LOW ");
- if(mask & CS_EVENT_READY_CHANGE)
- strcat( pBuf, "READY_CHANGE " );
+ if (mask & CS_EVENT_READY_CHANGE)
+ strcat(pBuf, "READY_CHANGE ");
- if(mask & CS_EVENT_CARD_DETECT)
- strcat( pBuf, "CARD_DETECT " );
+ if (mask & CS_EVENT_CARD_DETECT)
+ strcat(pBuf, "CARD_DETECT ");
- if(mask & CS_EVENT_RESET_REQUEST)
- strcat( pBuf, "RESET_REQUEST " );
+ if (mask & CS_EVENT_RESET_REQUEST)
+ strcat(pBuf, "RESET_REQUEST ");
- if(mask & CS_EVENT_RESET_PHYSICAL)
- strcat( pBuf, "RESET_PHYSICAL " );
+ if (mask & CS_EVENT_RESET_PHYSICAL)
+ strcat(pBuf, "RESET_PHYSICAL ");
- if(mask & CS_EVENT_CARD_RESET)
- strcat( pBuf, "CARD_RESET " );
+ if (mask & CS_EVENT_CARD_RESET)
+ strcat(pBuf, "CARD_RESET ");
- if(mask & CS_EVENT_REGISTRATION_COMPLETE)
- strcat( pBuf, "REGISTRATION_COMPLETE " );
+ if (mask & CS_EVENT_REGISTRATION_COMPLETE)
+ strcat(pBuf, "REGISTRATION_COMPLETE ");
- // if(mask & CS_EVENT_RESET_COMPLETE)
- // strcat( pBuf, "RESET_COMPLETE " );
+ /* if (mask & CS_EVENT_RESET_COMPLETE)
+ strcat(pBuf, "RESET_COMPLETE "); */
- if(mask & CS_EVENT_PM_SUSPEND)
- strcat( pBuf, "PM_SUSPEND " );
+ if (mask & CS_EVENT_PM_SUSPEND)
+ strcat(pBuf, "PM_SUSPEND ");
- if(mask & CS_EVENT_PM_RESUME)
- strcat( pBuf, "PM_RESUME " );
+ if (mask & CS_EVENT_PM_RESUME)
+ strcat(pBuf, "PM_RESUME ");
- if(mask & CS_EVENT_INSERTION_REQUEST)
- strcat( pBuf, "INSERTION_REQUEST " );
+ if (mask & CS_EVENT_INSERTION_REQUEST)
+ strcat(pBuf, "INSERTION_REQUEST ");
- if(mask & CS_EVENT_EJECTION_REQUEST)
- strcat( pBuf, "EJECTION_REQUEST " );
+ if (mask & CS_EVENT_EJECTION_REQUEST)
+ strcat(pBuf, "EJECTION_REQUEST ");
- if(mask & CS_EVENT_MTD_REQUEST)
- strcat( pBuf, "MTD_REQUEST " );
+ if (mask & CS_EVENT_MTD_REQUEST)
+ strcat(pBuf, "MTD_REQUEST ");
- if(mask & CS_EVENT_ERASE_COMPLETE)
- strcat( pBuf, "ERASE_COMPLETE " );
+ if (mask & CS_EVENT_ERASE_COMPLETE)
+ strcat(pBuf, "ERASE_COMPLETE ");
- if(mask & CS_EVENT_REQUEST_ATTENTION)
- strcat( pBuf, "REQUEST_ATTENTION " );
+ if (mask & CS_EVENT_REQUEST_ATTENTION)
+ strcat(pBuf, "REQUEST_ATTENTION ");
- if(mask & CS_EVENT_CB_DETECT)
- strcat( pBuf, "CB_DETECT " );
+ if (mask & CS_EVENT_CB_DETECT)
+ strcat(pBuf, "CB_DETECT ");
- if(mask & CS_EVENT_3VCARD)
- strcat( pBuf, "3VCARD " );
+ if (mask & CS_EVENT_3VCARD)
+ strcat(pBuf, "3VCARD ");
- if(mask & CS_EVENT_XVCARD)
- strcat( pBuf, "XVCARD " );
+ if (mask & CS_EVENT_XVCARD)
+ strcat(pBuf, "XVCARD ");
- if( *pBuf ) {
- pBuf[strlen(pBuf) - 1] = '\0';
- } else {
- if( mask != 0x0 ) {
- sprintf( pBuf, "<<0x%08x>>", mask );
- }
- }
+ if (*pBuf) {
+ pBuf[strlen(pBuf) - 1] = '\0';
+ } else {
+ if (mask != 0x0)
+ sprintf(pBuf, "<<0x%08x>>", mask);
+ }
- return pBuf;
-} // DbgEvent
+ return pBuf;
+} /* DbgEvent */
/*============================================================================*/
#endif /* DBG */
diff --git a/drivers/staging/wlags49_h2/wl_cs.h b/drivers/staging/wlags49_h2/wl_cs.h
index a9b8828a1a2..21f17be4f02 100644
--- a/drivers/staging/wlags49_h2/wl_cs.h
+++ b/drivers/staging/wlags49_h2/wl_cs.h
@@ -72,8 +72,6 @@ void wl_adapter_insert(struct pcmcia_device *link);
void wl_adapter_release(struct pcmcia_device *link);
-int wl_adapter_event(event_t event, int priority, event_callback_args_t *args );
-
int wl_adapter_init_module( void );
void wl_adapter_cleanup_module( void );
diff --git a/drivers/staging/wlags49_h2/wl_internal.h b/drivers/staging/wlags49_h2/wl_internal.h
index d9a0ad039c1..02f0a20e178 100644
--- a/drivers/staging/wlags49_h2/wl_internal.h
+++ b/drivers/staging/wlags49_h2/wl_internal.h
@@ -69,7 +69,6 @@
******************************************************************************/
#include <linux/version.h>
#ifdef BUS_PCMCIA
-#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/cistpl.h>
#include <pcmcia/cisreg.h>
diff --git a/drivers/staging/wlags49_h2/wl_netdev.c b/drivers/staging/wlags49_h2/wl_netdev.c
index 1aa61dbdb79..e2a7ad05e54 100644
--- a/drivers/staging/wlags49_h2/wl_netdev.c
+++ b/drivers/staging/wlags49_h2/wl_netdev.c
@@ -1905,8 +1905,8 @@ int wl_rx_dma( struct net_device *dev )
DBG_FUNC("wl_rx")
DBG_PARAM(DbgInfo, "dev", "%s (0x%p)", dev->name, dev);
- if((( lp = (struct wl_private *)dev->priv ) != NULL ) &&
- !( lp->flags & WVLAN2_UIL_BUSY )) {
+ if((( lp = dev->priv ) != NULL ) &&
+ !( lp->flags & WVLAN2_UIL_BUSY )) {
#ifdef USE_RTS
if( lp->useRTS == 1 ) {
diff --git a/drivers/staging/wlags49_h2/wl_pci.c b/drivers/staging/wlags49_h2/wl_pci.c
index 6751b4bad2e..020b17adee2 100644
--- a/drivers/staging/wlags49_h2/wl_pci.c
+++ b/drivers/staging/wlags49_h2/wl_pci.c
@@ -117,9 +117,13 @@ enum hermes_pci_versions {
};
static struct pci_device_id wl_pci_tbl[] __devinitdata = {
- { WL_LKM_PCI_VENDOR_ID, WL_LKM_PCI_DEVICE_ID_0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_Agere_Systems_Mini_PCI_V1 },
- { WL_LKM_PCI_VENDOR_ID, WL_LKM_PCI_DEVICE_ID_1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_Agere_Systems_Mini_PCI_V1 },
- { WL_LKM_PCI_VENDOR_ID, WL_LKM_PCI_DEVICE_ID_2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_Agere_Systems_Mini_PCI_V1 },
+ { PCI_VENDOR_ID_WL_LKM, PCI_DEVICE_ID_WL_LKM_0,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_Agere_Systems_Mini_PCI_V1 },
+ { PCI_VENDOR_ID_WL_LKM, PCI_DEVICE_ID_WL_LKM_1,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_Agere_Systems_Mini_PCI_V1 },
+ { PCI_VENDOR_ID_WL_LKM, PCI_DEVICE_ID_WL_LKM_2,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_Agere_Systems_Mini_PCI_V1 },
+
{ } /* Terminating entry */
};
@@ -465,7 +469,7 @@ void __devexit wl_pci_remove(struct pci_dev *pdev)
free_irq( dev->irq, dev );
#ifdef ENABLE_DMA
- wl_pci_dma_free( pdev, (struct wl_private *)dev->priv );
+ wl_pci_dma_free( pdev, dev->priv );
#endif
wl_device_dealloc( dev );
@@ -534,7 +538,7 @@ int wl_pci_setup( struct pci_dev *pdev )
#ifdef ENABLE_DMA
/* Allocate DMA Descriptors */
- if( wl_pci_dma_alloc( pdev, (struct wl_private *)dev->priv ) < 0 ) {
+ if( wl_pci_dma_alloc( pdev, dev->priv ) < 0 ) {
DBG_ERROR( DbgInfo, "Could not allocate DMA descriptor memory!!!\n" );
DBG_LEAVE( DbgInfo );
return -ENOMEM;
@@ -570,7 +574,7 @@ int wl_pci_setup( struct pci_dev *pdev )
}
/* Make sure interrupts are enabled properly for CardBus */
- lp = (struct wl_private *)dev->priv;
+ lp = dev->priv;
if( lp->hcfCtx.IFB_BusType == CFG_NIC_BUS_TYPE_CARDBUS ||
lp->hcfCtx.IFB_BusType == CFG_NIC_BUS_TYPE_PCI ) {
diff --git a/drivers/staging/wlags49_h2/wl_pci.h b/drivers/staging/wlags49_h2/wl_pci.h
index 18d7b514ea6..cea04c44ec4 100644
--- a/drivers/staging/wlags49_h2/wl_pci.h
+++ b/drivers/staging/wlags49_h2/wl_pci.h
@@ -67,10 +67,10 @@
/*******************************************************************************
* constant definitions
******************************************************************************/
-#define WL_LKM_PCI_VENDOR_ID 0x11C1 // Lucent Microelectronics
-#define WL_LKM_PCI_DEVICE_ID_0 0xAB30 // Mini PCI
-#define WL_LKM_PCI_DEVICE_ID_1 0xAB34 // Mini PCI
-#define WL_LKM_PCI_DEVICE_ID_2 0xAB11 // WARP CardBus
+#define PCI_VENDOR_IDWL_LKM 0x11C1 /* Lucent Microelectronics */
+#define PCI_DEVICE_ID_WL_LKM_0 0xAB30 /* Mini PCI */
+#define PCI_DEVICE_ID_WL_LKM_1 0xAB34 /* Mini PCI */
+#define PCI_DEVICE_ID_WL_LKM_2 0xAB11 /* WARP CardBus */
diff --git a/drivers/staging/wlags49_h2/wl_profile.c b/drivers/staging/wlags49_h2/wl_profile.c
index 292d5792dd7..7a1337db7aa 100644
--- a/drivers/staging/wlags49_h2/wl_profile.c
+++ b/drivers/staging/wlags49_h2/wl_profile.c
@@ -169,7 +169,7 @@ void parse_config(struct net_device *dev)
DBG_ENTER(DbgInfo);
/* Get the wavelan specific info for this device */
- wvlan_config = (struct wl_private *)dev->priv;
+ wvlan_config = dev->priv;
if (wvlan_config == NULL) {
DBG_ERROR(DbgInfo, "Wavelan specific info struct not present?\n");
return;
diff --git a/drivers/staging/wlags49_h2/wl_util.c b/drivers/staging/wlags49_h2/wl_util.c
index bbdb9973d1e..ce8ed410a7e 100644
--- a/drivers/staging/wlags49_h2/wl_util.c
+++ b/drivers/staging/wlags49_h2/wl_util.c
@@ -259,41 +259,6 @@ int is_valid_key_string( char *s )
/*******************************************************************************
- * hexdigit2int()
- *******************************************************************************
- *
- * DESCRIPTION:
- *
- * Converts a hexadecimal digit character to an integer
- *
- * PARAMETERS:
- *
- * c - the hexadecimal digit character
- *
- * RETURNS:
- *
- * the converted integer
- *
- ******************************************************************************/
-int hexdigit2int( char c )
-{
- if( c >= '0' && c <= '9' )
- return c - '0';
-
- if( c >= 'A' && c <= 'F' )
- return c - 'A' + 10;
-
- if( c >= 'a' && c <= 'f' )
- return c - 'a' + 10;
-
- return 0;
-} // hexdigit2int
-/*============================================================================*/
-
-
-
-
-/*******************************************************************************
* key_string2key()
*******************************************************************************
*
@@ -328,7 +293,7 @@ void key_string2key( char *ks, KEY_STRCT *key )
p = (char *)key->key;
for( i = 2; i < l; i+=2 ) {
- *p++ = ( hexdigit2int( ks[i] ) << 4 ) + hexdigit2int (ks[i+1] );
+ *p++ = (hex_to_bin(ks[i]) << 4) + hex_to_bin(ks[i+1]);
n++;
}
diff --git a/drivers/staging/wlags49_h2/wl_util.h b/drivers/staging/wlags49_h2/wl_util.h
index 561e85b5c9b..ba537a60059 100644
--- a/drivers/staging/wlags49_h2/wl_util.h
+++ b/drivers/staging/wlags49_h2/wl_util.h
@@ -71,8 +71,6 @@ int is_valid_key_string( char *s );
void key_string2key( char *ks, KEY_STRCT *key );
-int hexdigit2int( char c );
-
void wl_hcf_error( struct net_device *dev, int hcfStatus );
void wl_endian_translate_event( ltv_t *pLtv );
diff --git a/drivers/staging/wlan-ng/Kconfig b/drivers/staging/wlan-ng/Kconfig
index 82fcc1665e9..426d4efbabc 100644
--- a/drivers/staging/wlan-ng/Kconfig
+++ b/drivers/staging/wlan-ng/Kconfig
@@ -1,6 +1,6 @@
config PRISM2_USB
tristate "Prism2.5/3 USB driver"
- depends on WLAN && USB
+ depends on WLAN && USB && CFG80211
select WIRELESS_EXT
select WEXT_PRIV
default n
diff --git a/drivers/staging/wlan-ng/Makefile b/drivers/staging/wlan-ng/Makefile
index 5edac5c8d4e..db5d597563f 100644
--- a/drivers/staging/wlan-ng/Makefile
+++ b/drivers/staging/wlan-ng/Makefile
@@ -4,5 +4,4 @@ prism2_usb-objs := prism2usb.o \
p80211conv.o \
p80211req.o \
p80211wep.o \
- p80211wext.o \
p80211netdev.o
diff --git a/drivers/staging/wlan-ng/cfg80211.c b/drivers/staging/wlan-ng/cfg80211.c
new file mode 100644
index 00000000000..368c30a9d5f
--- /dev/null
+++ b/drivers/staging/wlan-ng/cfg80211.c
@@ -0,0 +1,760 @@
+/* cfg80211 Interface for prism2_usb module */
+
+
+/* Prism2 channell/frequency/bitrate declarations */
+static const struct ieee80211_channel prism2_channels[] = {
+ { .center_freq = 2412 },
+ { .center_freq = 2417 },
+ { .center_freq = 2422 },
+ { .center_freq = 2427 },
+ { .center_freq = 2432 },
+ { .center_freq = 2437 },
+ { .center_freq = 2442 },
+ { .center_freq = 2447 },
+ { .center_freq = 2452 },
+ { .center_freq = 2457 },
+ { .center_freq = 2462 },
+ { .center_freq = 2467 },
+ { .center_freq = 2472 },
+ { .center_freq = 2484 },
+};
+
+static const struct ieee80211_rate prism2_rates[] = {
+ { .bitrate = 10 },
+ { .bitrate = 20 },
+ { .bitrate = 55 },
+ { .bitrate = 110 }
+};
+
+#define PRISM2_NUM_CIPHER_SUITES 2
+static const u32 prism2_cipher_suites[PRISM2_NUM_CIPHER_SUITES] = {
+ WLAN_CIPHER_SUITE_WEP40,
+ WLAN_CIPHER_SUITE_WEP104
+};
+
+
+/* prism2 device private data */
+struct prism2_wiphy_private {
+ wlandevice_t *wlandev;
+
+ struct ieee80211_supported_band band;
+ struct ieee80211_channel channels[ARRAY_SIZE(prism2_channels)];
+ struct ieee80211_rate rates[ARRAY_SIZE(prism2_rates)];
+
+ struct cfg80211_scan_request *scan_request;
+};
+
+static const void * const prism2_wiphy_privid = &prism2_wiphy_privid;
+
+
+/* Helper Functions */
+static int prism2_result2err(int prism2_result)
+{
+ int err = 0;
+
+ switch (prism2_result) {
+ case P80211ENUM_resultcode_invalid_parameters:
+ err = -EINVAL;
+ break;
+ case P80211ENUM_resultcode_implementation_failure:
+ err = -EIO;
+ break;
+ case P80211ENUM_resultcode_not_supported:
+ err = -EOPNOTSUPP;
+ break;
+ default:
+ err = 0;
+ break;
+ }
+
+ return err;
+}
+
+static int prism2_domibset_uint32(wlandevice_t *wlandev, u32 did, u32 data)
+{
+ struct p80211msg_dot11req_mibset msg;
+ p80211item_uint32_t *mibitem = (p80211item_uint32_t *) &msg.mibattribute.data;
+
+ msg.msgcode = DIDmsg_dot11req_mibset;
+ mibitem->did = did;
+ mibitem->data = data;
+
+ return p80211req_dorequest(wlandev, (u8 *) &msg);
+}
+
+static int prism2_domibset_pstr32(wlandevice_t *wlandev,
+ u32 did, u8 len, u8 *data)
+{
+ struct p80211msg_dot11req_mibset msg;
+ p80211item_pstr32_t *mibitem = (p80211item_pstr32_t *) &msg.mibattribute.data;
+
+ msg.msgcode = DIDmsg_dot11req_mibset;
+ mibitem->did = did;
+ mibitem->data.len = len;
+ memcpy(mibitem->data.data, data, len);
+
+ return p80211req_dorequest(wlandev, (u8 *) &msg);
+}
+
+
+/* The interface functions, called by the cfg80211 layer */
+int prism2_change_virtual_intf(struct wiphy *wiphy,
+ struct net_device *dev,
+ enum nl80211_iftype type, u32 *flags,
+ struct vif_params *params)
+{
+ wlandevice_t *wlandev = dev->ml_priv;
+ u32 data;
+ int result;
+ int err = 0;
+
+ switch (type) {
+ case NL80211_IFTYPE_ADHOC:
+ if (wlandev->macmode == WLAN_MACMODE_IBSS_STA)
+ goto exit;
+ wlandev->macmode = WLAN_MACMODE_IBSS_STA;
+ data = 0;
+ break;
+ case NL80211_IFTYPE_STATION:
+ if (wlandev->macmode == WLAN_MACMODE_ESS_STA)
+ goto exit;
+ wlandev->macmode = WLAN_MACMODE_ESS_STA;
+ data = 1;
+ break;
+ default:
+ printk(KERN_WARNING "Operation mode: %d not support\n", type);
+ return -EOPNOTSUPP;
+ }
+
+ /* Set Operation mode to the PORT TYPE RID */
+ result = prism2_domibset_uint32(wlandev, DIDmib_p2_p2Static_p2CnfPortType, data);
+
+ if (result)
+ err = -EFAULT;
+
+ dev->ieee80211_ptr->iftype = type;
+
+exit:
+ return err;
+}
+
+int prism2_add_key(struct wiphy *wiphy, struct net_device *dev,
+ u8 key_index, const u8 *mac_addr,
+ struct key_params *params)
+{
+ wlandevice_t *wlandev = dev->ml_priv;
+ u32 did;
+
+ int err = 0;
+ int result = 0;
+
+ switch (params->cipher) {
+ case WLAN_CIPHER_SUITE_WEP40:
+ case WLAN_CIPHER_SUITE_WEP104:
+ result = prism2_domibset_uint32(wlandev,
+ DIDmib_dot11smt_dot11PrivacyTable_dot11WEPDefaultKeyID,
+ key_index);
+ if (result)
+ goto exit;
+
+ /* send key to driver */
+ switch (key_index) {
+ case 0:
+ did = DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey0;
+ break;
+
+ case 1:
+ did = DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey1;
+ break;
+
+ case 2:
+ did = DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey2;
+ break;
+
+ case 3:
+ did = DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey3;
+ break;
+
+ default:
+ err = -EINVAL;
+ goto exit;
+ }
+
+ result = prism2_domibset_pstr32(wlandev, did, params->key_len, params->key);
+ if (result)
+ goto exit;
+ break;
+
+ default:
+ pr_debug("Unsupported cipher suite\n");
+ result = 1;
+ }
+
+exit:
+ if (result)
+ err = -EFAULT;
+
+ return err;
+}
+
+int prism2_get_key(struct wiphy *wiphy, struct net_device *dev,
+ u8 key_index, const u8 *mac_addr, void *cookie,
+ void (*callback)(void *cookie, struct key_params*))
+{
+ wlandevice_t *wlandev = dev->ml_priv;
+ struct key_params params;
+ int len;
+
+ if (key_index >= NUM_WEPKEYS)
+ return -EINVAL;
+
+ len = wlandev->wep_keylens[key_index];
+ memset(&params, 0, sizeof(params));
+
+ if (len == 13)
+ params.cipher = WLAN_CIPHER_SUITE_WEP104;
+ else if (len == 5)
+ params.cipher = WLAN_CIPHER_SUITE_WEP104;
+ else
+ return -ENOENT;
+ params.key_len = len;
+ params.key = wlandev->wep_keys[key_index];
+
+ callback(cookie, &params);
+
+ return 0;
+}
+
+int prism2_del_key(struct wiphy *wiphy, struct net_device *dev,
+ u8 key_index, const u8 *mac_addr)
+{
+ wlandevice_t *wlandev = dev->ml_priv;
+ u32 did;
+ int err = 0;
+ int result = 0;
+
+ /* There is no direct way in the hardware (AFAIK) of removing
+ a key, so we will cheat by setting the key to a bogus value */
+ /* send key to driver */
+ switch (key_index) {
+ case 0:
+ did =
+ DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey0;
+ break;
+
+ case 1:
+ did =
+ DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey1;
+ break;
+
+ case 2:
+ did =
+ DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey2;
+ break;
+
+ case 3:
+ did =
+ DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey3;
+ break;
+
+ default:
+ err = -EINVAL;
+ goto exit;
+ }
+
+ result = prism2_domibset_pstr32(wlandev, did, 13, "0000000000000");
+
+exit:
+ if (result)
+ err = -EFAULT;
+
+ return err;
+}
+
+int prism2_set_default_key(struct wiphy *wiphy, struct net_device *dev,
+ u8 key_index)
+{
+ wlandevice_t *wlandev = dev->ml_priv;
+
+ int err = 0;
+ int result = 0;
+
+ result = prism2_domibset_uint32(wlandev,
+ DIDmib_dot11smt_dot11PrivacyTable_dot11WEPDefaultKeyID,
+ key_index);
+
+ if (result)
+ err = -EFAULT;
+
+ return err;
+}
+
+
+int prism2_get_station(struct wiphy *wiphy, struct net_device *dev,
+ u8 *mac, struct station_info *sinfo)
+{
+ wlandevice_t *wlandev = dev->ml_priv;
+ struct p80211msg_lnxreq_commsquality quality;
+ int result;
+
+ memset(sinfo, 0, sizeof(*sinfo));
+
+ if ((wlandev == NULL) || (wlandev->msdstate != WLAN_MSD_RUNNING))
+ return -EOPNOTSUPP;
+
+ /* build request message */
+ quality.msgcode = DIDmsg_lnxreq_commsquality;
+ quality.dbm.data = P80211ENUM_truth_true;
+ quality.dbm.status = P80211ENUM_msgitem_status_data_ok;
+
+ /* send message to nsd */
+ if (wlandev->mlmerequest == NULL)
+ return -EOPNOTSUPP;
+
+ result = wlandev->mlmerequest(wlandev, (struct p80211msg *) &quality);
+
+
+ if (result == 0) {
+ sinfo->txrate.legacy = quality.txrate.data;
+ sinfo->filled |= STATION_INFO_TX_BITRATE;
+ sinfo->signal = quality.level.data;
+ sinfo->filled |= STATION_INFO_SIGNAL;
+ }
+
+ return result;
+}
+
+int prism2_scan(struct wiphy *wiphy, struct net_device *dev,
+ struct cfg80211_scan_request *request)
+{
+ struct prism2_wiphy_private *priv = wiphy_priv(wiphy);
+ wlandevice_t *wlandev = dev->ml_priv;
+ struct p80211msg_dot11req_scan msg1;
+ struct p80211msg_dot11req_scan_results msg2;
+ int result;
+ int err = 0;
+ int numbss = 0;
+ int i = 0;
+ u8 ie_buf[46];
+ int ie_len;
+
+ if (!request)
+ return -EINVAL;
+
+ if (priv->scan_request && priv->scan_request != request)
+ return -EBUSY;
+
+ if (wlandev->macmode == WLAN_MACMODE_ESS_AP) {
+ printk(KERN_ERR "Can't scan in AP mode\n");
+ return -EOPNOTSUPP;
+ }
+
+ priv->scan_request = request;
+
+ memset(&msg1, 0x00, sizeof(struct p80211msg_dot11req_scan));
+ msg1.msgcode = DIDmsg_dot11req_scan;
+ msg1.bsstype.data = P80211ENUM_bsstype_any;
+
+ memset(&(msg1.bssid.data), 0xFF, sizeof(p80211item_pstr6_t));
+ msg1.bssid.data.len = 6;
+
+ if (request->n_ssids > 0) {
+ msg1.scantype.data = P80211ENUM_scantype_active;
+ msg1.ssid.data.len = request->ssids->ssid_len;
+ memcpy(msg1.ssid.data.data, request->ssids->ssid, request->ssids->ssid_len);
+ } else {
+ msg1.scantype.data = 0;
+ }
+ msg1.probedelay.data = 0;
+
+ for (i = 0;
+ (i < request->n_channels) && i < ARRAY_SIZE(prism2_channels);
+ i++)
+ msg1.channellist.data.data[i] =
+ ieee80211_frequency_to_channel(request->channels[i]->center_freq);
+ msg1.channellist.data.len = request->n_channels;
+
+ msg1.maxchanneltime.data = 250;
+ msg1.minchanneltime.data = 200;
+
+ result = p80211req_dorequest(wlandev, (u8 *) &msg1);
+ if (result) {
+ err = prism2_result2err(msg1.resultcode.data);
+ goto exit;
+ }
+ /* Now retrieve scan results */
+ numbss = msg1.numbss.data;
+
+ for (i = 0; i < numbss; i++) {
+ memset(&msg2, 0, sizeof(msg2));
+ msg2.msgcode = DIDmsg_dot11req_scan_results;
+ msg2.bssindex.data = i;
+
+ result = p80211req_dorequest(wlandev, (u8 *) &msg2);
+ if ((result != 0) ||
+ (msg2.resultcode.data != P80211ENUM_resultcode_success)) {
+ break;
+ }
+
+ ie_buf[0] = WLAN_EID_SSID;
+ ie_buf[1] = msg2.ssid.data.len;
+ ie_len = ie_buf[1] + 2;
+ memcpy(&ie_buf[2], &(msg2.ssid.data.data), msg2.ssid.data.len);
+ cfg80211_inform_bss(wiphy,
+ ieee80211_get_channel(wiphy, ieee80211_dsss_chan_to_freq(msg2.dschannel.data)),
+ (const u8 *) &(msg2.bssid.data.data),
+ msg2.timestamp.data, msg2.capinfo.data,
+ msg2.beaconperiod.data,
+ ie_buf,
+ ie_len,
+ (msg2.signal.data - 65536) * 100, /* Conversion to signed type */
+ GFP_KERNEL
+ );
+ }
+
+ if (result)
+ err = prism2_result2err(msg2.resultcode.data);
+
+exit:
+ cfg80211_scan_done(request, err ? 1 : 0);
+ priv->scan_request = NULL;
+ return err;
+}
+
+int prism2_set_wiphy_params(struct wiphy *wiphy, u32 changed)
+{
+ struct prism2_wiphy_private *priv = wiphy_priv(wiphy);
+ wlandevice_t *wlandev = priv->wlandev;
+ u32 data;
+ int result;
+ int err = 0;
+
+ if (changed & WIPHY_PARAM_RTS_THRESHOLD) {
+ if (wiphy->rts_threshold == -1)
+ data = 2347;
+ else
+ data = wiphy->rts_threshold;
+
+ result = prism2_domibset_uint32(wlandev,
+ DIDmib_dot11mac_dot11OperationTable_dot11RTSThreshold,
+ data);
+ if (result) {
+ err = -EFAULT;
+ goto exit;
+ }
+ }
+
+ if (changed & WIPHY_PARAM_FRAG_THRESHOLD) {
+ if (wiphy->frag_threshold == -1)
+ data = 2346;
+ else
+ data = wiphy->frag_threshold;
+
+ result = prism2_domibset_uint32(wlandev,
+ DIDmib_dot11mac_dot11OperationTable_dot11FragmentationThreshold,
+ data);
+ if (result) {
+ err = -EFAULT;
+ goto exit;
+ }
+ }
+
+exit:
+ return err;
+}
+
+int prism2_connect(struct wiphy *wiphy, struct net_device *dev,
+ struct cfg80211_connect_params *sme)
+{
+ wlandevice_t *wlandev = dev->ml_priv;
+ struct ieee80211_channel *channel = sme->channel;
+ struct p80211msg_lnxreq_autojoin msg_join;
+ u32 did;
+ int length = sme->ssid_len;
+ int chan = -1;
+ int is_wep = (sme->crypto.cipher_group == WLAN_CIPHER_SUITE_WEP40) ||
+ (sme->crypto.cipher_group == WLAN_CIPHER_SUITE_WEP104);
+ int result;
+ int err = 0;
+
+ /* Set the channel */
+ if (channel) {
+ chan = ieee80211_frequency_to_channel(channel->center_freq);
+ result = prism2_domibset_uint32(wlandev,
+ DIDmib_dot11phy_dot11PhyDSSSTable_dot11CurrentChannel,
+ chan);
+ if (result)
+ goto exit;
+ }
+
+ /* Set the authorisation */
+ if ((sme->auth_type == NL80211_AUTHTYPE_OPEN_SYSTEM) ||
+ ((sme->auth_type == NL80211_AUTHTYPE_AUTOMATIC) && !is_wep))
+ msg_join.authtype.data = P80211ENUM_authalg_opensystem;
+ else if ((sme->auth_type == NL80211_AUTHTYPE_SHARED_KEY) ||
+ ((sme->auth_type == NL80211_AUTHTYPE_AUTOMATIC) && is_wep))
+ msg_join.authtype.data = P80211ENUM_authalg_sharedkey;
+ else
+ printk(KERN_WARNING
+ "Unhandled authorisation type for connect (%d)\n",
+ sme->auth_type);
+
+ /* Set the encryption - we only support wep */
+ if (is_wep) {
+ if (sme->key) {
+ result = prism2_domibset_uint32(wlandev,
+ DIDmib_dot11smt_dot11PrivacyTable_dot11WEPDefaultKeyID,
+ sme->key_idx);
+ if (result)
+ goto exit;
+
+ /* send key to driver */
+ switch (sme->key_idx) {
+ case 0:
+ did = DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey0;
+ break;
+
+ case 1:
+ did = DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey1;
+ break;
+
+ case 2:
+ did = DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey2;
+ break;
+
+ case 3:
+ did = DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey3;
+ break;
+
+ default:
+ err = -EINVAL;
+ goto exit;
+ }
+
+ result = prism2_domibset_pstr32(wlandev, did, sme->key_len, (u8 *) sme->key);
+ if (result)
+ goto exit;
+
+ }
+
+ /* Assume we should set privacy invoked and exclude unencrypted
+ We could possibly use sme->privacy here, but the assumption
+ seems reasonable anyway */
+ result = prism2_domibset_uint32(wlandev,
+ DIDmib_dot11smt_dot11PrivacyTable_dot11PrivacyInvoked,
+ P80211ENUM_truth_true);
+ if (result)
+ goto exit;
+
+ result = prism2_domibset_uint32(wlandev,
+ DIDmib_dot11smt_dot11PrivacyTable_dot11ExcludeUnencrypted,
+ P80211ENUM_truth_true);
+ if (result)
+ goto exit;
+
+ } else {
+ /* Assume we should unset privacy invoked
+ and exclude unencrypted */
+ result = prism2_domibset_uint32(wlandev,
+ DIDmib_dot11smt_dot11PrivacyTable_dot11PrivacyInvoked,
+ P80211ENUM_truth_false);
+ if (result)
+ goto exit;
+
+ result = prism2_domibset_uint32(wlandev,
+ DIDmib_dot11smt_dot11PrivacyTable_dot11ExcludeUnencrypted,
+ P80211ENUM_truth_false);
+ if (result)
+ goto exit;
+
+ }
+
+ /* Now do the actual join. Note there is no way that I can
+ see to request a specific bssid */
+ msg_join.msgcode = DIDmsg_lnxreq_autojoin;
+
+ memcpy(msg_join.ssid.data.data, sme->ssid, length);
+ msg_join.ssid.data.len = length;
+
+ result = p80211req_dorequest(wlandev, (u8 *) &msg_join);
+
+exit:
+ if (result)
+ err = -EFAULT;
+
+ return err;
+}
+
+int prism2_disconnect(struct wiphy *wiphy, struct net_device *dev,
+ u16 reason_code)
+{
+ wlandevice_t *wlandev = dev->ml_priv;
+ struct p80211msg_lnxreq_autojoin msg_join;
+ int result;
+ int err = 0;
+
+
+ /* Do a join, with a bogus ssid. Thats the only way I can think of */
+ msg_join.msgcode = DIDmsg_lnxreq_autojoin;
+
+ memcpy(msg_join.ssid.data.data, "---", 3);
+ msg_join.ssid.data.len = 3;
+
+ result = p80211req_dorequest(wlandev, (u8 *) &msg_join);
+
+ if (result)
+ err = -EFAULT;
+
+ return err;
+}
+
+
+int prism2_join_ibss(struct wiphy *wiphy, struct net_device *dev,
+ struct cfg80211_ibss_params *params)
+{
+ return -EOPNOTSUPP;
+}
+
+int prism2_leave_ibss(struct wiphy *wiphy, struct net_device *dev)
+{
+ return -EOPNOTSUPP;
+}
+
+
+int prism2_set_tx_power(struct wiphy *wiphy, enum nl80211_tx_power_setting type,
+ int mbm)
+{
+ struct prism2_wiphy_private *priv = wiphy_priv(wiphy);
+ wlandevice_t *wlandev = priv->wlandev;
+ u32 data;
+ int result;
+ int err = 0;
+
+ if (type == NL80211_TX_POWER_AUTOMATIC)
+ data = 30;
+ else
+ data = MBM_TO_DBM(mbm);
+
+ result = prism2_domibset_uint32(wlandev,
+ DIDmib_dot11phy_dot11PhyTxPowerTable_dot11CurrentTxPowerLevel,
+ data);
+
+ if (result) {
+ err = -EFAULT;
+ goto exit;
+ }
+
+exit:
+ return err;
+}
+
+int prism2_get_tx_power(struct wiphy *wiphy, int *dbm)
+{
+ struct prism2_wiphy_private *priv = wiphy_priv(wiphy);
+ wlandevice_t *wlandev = priv->wlandev;
+ struct p80211msg_dot11req_mibget msg;
+ p80211item_uint32_t *mibitem = (p80211item_uint32_t *) &msg.mibattribute.data;
+ int result;
+ int err = 0;
+
+ msg.msgcode = DIDmsg_dot11req_mibget;
+ mibitem->did =
+ DIDmib_dot11phy_dot11PhyTxPowerTable_dot11CurrentTxPowerLevel;
+
+ result = p80211req_dorequest(wlandev, (u8 *) &msg);
+
+ if (result) {
+ err = -EFAULT;
+ goto exit;
+ }
+
+ *dbm = mibitem->data;
+
+exit:
+ return err;
+}
+
+
+
+
+/* Interface callback functions, passing data back up to the cfg80211 layer */
+void prism2_connect_result(wlandevice_t *wlandev, u8 failed)
+{
+ u16 status = failed ? WLAN_STATUS_UNSPECIFIED_FAILURE : WLAN_STATUS_SUCCESS;
+
+ cfg80211_connect_result(wlandev->netdev, wlandev->bssid,
+ NULL, 0, NULL, 0, status, GFP_KERNEL);
+}
+
+void prism2_disconnected(wlandevice_t *wlandev)
+{
+ cfg80211_disconnected(wlandev->netdev, 0, NULL,
+ 0, GFP_KERNEL);
+}
+
+void prism2_roamed(wlandevice_t *wlandev)
+{
+ cfg80211_roamed(wlandev->netdev, wlandev->bssid,
+ NULL, 0, NULL, 0, GFP_KERNEL);
+}
+
+
+/* Structures for declaring wiphy interface */
+static const struct cfg80211_ops prism2_usb_cfg_ops = {
+ .change_virtual_intf = prism2_change_virtual_intf,
+ .add_key = prism2_add_key,
+ .get_key = prism2_get_key,
+ .del_key = prism2_del_key,
+ .set_default_key = prism2_set_default_key,
+ .get_station = prism2_get_station,
+ .scan = prism2_scan,
+ .set_wiphy_params = prism2_set_wiphy_params,
+ .connect = prism2_connect,
+ .disconnect = prism2_disconnect,
+ .join_ibss = prism2_join_ibss,
+ .leave_ibss = prism2_leave_ibss,
+ .set_tx_power = prism2_set_tx_power,
+ .get_tx_power = prism2_get_tx_power,
+};
+
+
+/* Functions to create/free wiphy interface */
+struct wiphy *wlan_create_wiphy(struct device *dev, wlandevice_t *wlandev)
+{
+ struct wiphy *wiphy;
+ struct prism2_wiphy_private *priv;
+ wiphy = wiphy_new(&prism2_usb_cfg_ops, sizeof(struct prism2_wiphy_private));
+ if (!wiphy)
+ return NULL;
+
+ priv = wiphy_priv(wiphy);
+ priv->wlandev = wlandev;
+ memcpy(priv->channels, prism2_channels, sizeof(prism2_channels));
+ memcpy(priv->rates, prism2_rates, sizeof(prism2_rates));
+ priv->band.channels = priv->channels;
+ priv->band.n_channels = ARRAY_SIZE(prism2_channels);
+ priv->band.bitrates = priv->rates;
+ priv->band.n_bitrates = ARRAY_SIZE(prism2_rates);
+ wiphy->bands[IEEE80211_BAND_2GHZ] = &priv->band;
+
+ set_wiphy_dev(wiphy, dev);
+ wiphy->privid = prism2_wiphy_privid;
+ wiphy->max_scan_ssids = 1;
+ wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION)
+ | BIT(NL80211_IFTYPE_ADHOC);
+ wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
+ wiphy->n_cipher_suites = PRISM2_NUM_CIPHER_SUITES;
+ wiphy->cipher_suites = prism2_cipher_suites;
+
+ if (wiphy_register(wiphy) < 0)
+ return NULL;
+
+ return wiphy;
+}
+
+
+void wlan_free_wiphy(struct wiphy *wiphy)
+{
+ wiphy_unregister(wiphy);
+ wiphy_free(wiphy);
+}
diff --git a/drivers/staging/wlan-ng/hfa384x.h b/drivers/staging/wlan-ng/hfa384x.h
index 1fa42e01e8c..fa94a7cc86c 100644
--- a/drivers/staging/wlan-ng/hfa384x.h
+++ b/drivers/staging/wlan-ng/hfa384x.h
@@ -1284,6 +1284,8 @@ typedef struct hfa384x {
u16 link_status_new;
struct sk_buff_head authq;
+ u32 txrate;
+
/* And here we have stuff that used to be in priv */
/* State variables */
@@ -1407,7 +1409,7 @@ int hfa384x_drvr_start(hfa384x_t *hw);
int hfa384x_drvr_stop(hfa384x_t *hw);
int
hfa384x_drvr_txframe(hfa384x_t *hw, struct sk_buff *skb,
- p80211_hdr_t *p80211_hdr, p80211_metawep_t *p80211_wep);
+ union p80211_hdr *p80211_hdr, struct p80211_metawep *p80211_wep);
void hfa384x_tx_timeout(wlandevice_t *wlandev);
int hfa384x_cmd_initialize(hfa384x_t *hw);
diff --git a/drivers/staging/wlan-ng/hfa384x_usb.c b/drivers/staging/wlan-ng/hfa384x_usb.c
index a41db5dc8c7..ea81cb547bb 100644
--- a/drivers/staging/wlan-ng/hfa384x_usb.c
+++ b/drivers/staging/wlan-ng/hfa384x_usb.c
@@ -2706,8 +2706,8 @@ int hfa384x_drvr_stop(hfa384x_t *hw)
* interrupt
----------------------------------------------------------------*/
int hfa384x_drvr_txframe(hfa384x_t *hw, struct sk_buff *skb,
- p80211_hdr_t *p80211_hdr,
- p80211_metawep_t *p80211_wep)
+ union p80211_hdr *p80211_hdr,
+ struct p80211_metawep *p80211_wep)
{
int usbpktlen = sizeof(hfa384x_tx_frame_t);
int result;
@@ -2752,7 +2752,7 @@ int hfa384x_drvr_txframe(hfa384x_t *hw, struct sk_buff *skb,
/* copy the header over to the txdesc */
memcpy(&(hw->txbuff.txfrm.desc.frame_control), p80211_hdr,
- sizeof(p80211_hdr_t));
+ sizeof(union p80211_hdr));
/* if we're using host WEP, increase size by IV+ICV */
if (p80211_wep->data) {
@@ -2805,11 +2805,13 @@ void hfa384x_tx_timeout(wlandevice_t *wlandev)
spin_lock_irqsave(&hw->ctlxq.lock, flags);
- if (!hw->wlandev->hwremoved &&
- /* Note the bitwise OR, not the logical OR. */
- (!test_and_set_bit(WORK_TX_HALT, &hw->usb_flags) |
- !test_and_set_bit(WORK_RX_HALT, &hw->usb_flags))) {
- schedule_work(&hw->usb_work);
+ if (!hw->wlandev->hwremoved) {
+ int sched;
+
+ sched = !test_and_set_bit(WORK_TX_HALT, &hw->usb_flags);
+ sched |= !test_and_set_bit(WORK_RX_HALT, &hw->usb_flags);
+ if (sched)
+ schedule_work(&hw->usb_work);
}
spin_unlock_irqrestore(&hw->ctlxq.lock, flags);
@@ -3471,7 +3473,7 @@ static void hfa384x_usbin_rx(wlandevice_t *wlandev, struct sk_buff *skb)
hfa384x_usbin_t *usbin = (hfa384x_usbin_t *) skb->data;
hfa384x_t *hw = wlandev->priv;
int hdrlen;
- p80211_rxmeta_t *rxmeta;
+ struct p80211_rxmeta *rxmeta;
u16 data_len;
u16 fc;
@@ -3588,14 +3590,14 @@ static void hfa384x_int_rxmonitor(wlandevice_t *wlandev,
datalen = le16_to_cpu(rxdesc->data_len);
/* Allocate an ind message+framesize skb */
- skblen = sizeof(p80211_caphdr_t) + hdrlen + datalen + WLAN_CRC_LEN;
+ skblen = sizeof(struct p80211_caphdr) + hdrlen + datalen + WLAN_CRC_LEN;
/* sanity check the length */
if (skblen >
- (sizeof(p80211_caphdr_t) +
+ (sizeof(struct p80211_caphdr) +
WLAN_HDR_A4_LEN + WLAN_DATA_MAXLEN + WLAN_CRC_LEN)) {
pr_debug("overlen frm: len=%zd\n",
- skblen - sizeof(p80211_caphdr_t));
+ skblen - sizeof(struct p80211_caphdr));
}
skb = dev_alloc_skb(skblen);
@@ -3609,13 +3611,13 @@ static void hfa384x_int_rxmonitor(wlandevice_t *wlandev,
/* only prepend the prism header if in the right mode */
if ((wlandev->netdev->type == ARPHRD_IEEE80211_PRISM) &&
(hw->sniffhdr != 0)) {
- p80211_caphdr_t *caphdr;
+ struct p80211_caphdr *caphdr;
/* The NEW header format! */
- datap = skb_put(skb, sizeof(p80211_caphdr_t));
- caphdr = (p80211_caphdr_t *) datap;
+ datap = skb_put(skb, sizeof(struct p80211_caphdr));
+ caphdr = (struct p80211_caphdr *) datap;
caphdr->version = htonl(P80211CAPTURE_VERSION);
- caphdr->length = htonl(sizeof(p80211_caphdr_t));
+ caphdr->length = htonl(sizeof(struct p80211_caphdr));
caphdr->mactime = __cpu_to_be64(rxdesc->time) * 1000;
caphdr->hosttime = __cpu_to_be64(jiffies);
caphdr->phytype = htonl(4); /* dss_dot11_b */
diff --git a/drivers/staging/wlan-ng/p80211conv.c b/drivers/staging/wlan-ng/p80211conv.c
index 059e15055b7..83879f9a0b7 100644
--- a/drivers/staging/wlan-ng/p80211conv.c
+++ b/drivers/staging/wlan-ng/p80211conv.c
@@ -103,15 +103,15 @@ static u8 oui_8021h[] = { 0x00, 0x00, 0xf8 };
* May be called in interrupt or non-interrupt context
----------------------------------------------------------------*/
int skb_ether_to_p80211(wlandevice_t *wlandev, u32 ethconv,
- struct sk_buff *skb, p80211_hdr_t *p80211_hdr,
- p80211_metawep_t *p80211_wep)
+ struct sk_buff *skb, union p80211_hdr *p80211_hdr,
+ struct p80211_metawep *p80211_wep)
{
u16 fc;
u16 proto;
- wlan_ethhdr_t e_hdr;
- wlan_llc_t *e_llc;
- wlan_snap_t *e_snap;
+ struct wlan_ethhdr e_hdr;
+ struct wlan_llc *e_llc;
+ struct wlan_snap *e_snap;
int foo;
memcpy(&e_hdr, skb->data, sizeof(e_hdr));
@@ -148,7 +148,7 @@ int skb_ether_to_p80211(wlandevice_t *wlandev, u32 ethconv,
/* tack on SNAP */
e_snap =
- (wlan_snap_t *) skb_push(skb, sizeof(wlan_snap_t));
+ (struct wlan_snap *) skb_push(skb, sizeof(struct wlan_snap));
e_snap->type = htons(proto);
if (ethconv == WLAN_ETHCONV_8021h
&& p80211_stt_findproto(proto)) {
@@ -161,7 +161,7 @@ int skb_ether_to_p80211(wlandevice_t *wlandev, u32 ethconv,
/* tack on llc */
e_llc =
- (wlan_llc_t *) skb_push(skb, sizeof(wlan_llc_t));
+ (struct wlan_llc *) skb_push(skb, sizeof(struct wlan_llc));
e_llc->dsap = 0xAA; /* SNAP, see IEEE 802 */
e_llc->ssap = 0xAA;
e_llc->ctl = 0x03;
@@ -230,7 +230,7 @@ int skb_ether_to_p80211(wlandevice_t *wlandev, u32 ethconv,
/* jkriegl: from orinoco, modified */
static void orinoco_spy_gather(wlandevice_t *wlandev, char *mac,
- p80211_rxmeta_t *rxmeta)
+ struct p80211_rxmeta *rxmeta)
{
int i;
@@ -280,17 +280,17 @@ int skb_p80211_to_ether(wlandevice_t *wlandev, u32 ethconv,
unsigned int payload_offset;
u8 daddr[WLAN_ETHADDR_LEN];
u8 saddr[WLAN_ETHADDR_LEN];
- p80211_hdr_t *w_hdr;
- wlan_ethhdr_t *e_hdr;
- wlan_llc_t *e_llc;
- wlan_snap_t *e_snap;
+ union p80211_hdr *w_hdr;
+ struct wlan_ethhdr *e_hdr;
+ struct wlan_llc *e_llc;
+ struct wlan_snap *e_snap;
int foo;
payload_length = skb->len - WLAN_HDR_A3_LEN - WLAN_CRC_LEN;
payload_offset = WLAN_HDR_A3_LEN;
- w_hdr = (p80211_hdr_t *) skb->data;
+ w_hdr = (union p80211_hdr *) skb->data;
/* setup some vars for convenience */
fc = le16_to_cpu(w_hdr->a3.fc);
@@ -345,14 +345,14 @@ int skb_p80211_to_ether(wlandevice_t *wlandev, u32 ethconv,
wlandev->rx.decrypt++;
}
- e_hdr = (wlan_ethhdr_t *) (skb->data + payload_offset);
+ e_hdr = (struct wlan_ethhdr *) (skb->data + payload_offset);
- e_llc = (wlan_llc_t *) (skb->data + payload_offset);
+ e_llc = (struct wlan_llc *) (skb->data + payload_offset);
e_snap =
- (wlan_snap_t *) (skb->data + payload_offset + sizeof(wlan_llc_t));
+ (struct wlan_snap *) (skb->data + payload_offset + sizeof(struct wlan_llc));
/* Test for the various encodings */
- if ((payload_length >= sizeof(wlan_ethhdr_t)) &&
+ if ((payload_length >= sizeof(struct wlan_ethhdr)) &&
(e_llc->dsap != 0xaa || e_llc->ssap != 0xaa) &&
((memcmp(daddr, e_hdr->daddr, WLAN_ETHADDR_LEN) == 0) ||
(memcmp(saddr, e_hdr->saddr, WLAN_ETHADDR_LEN) == 0))) {
@@ -372,7 +372,7 @@ int skb_p80211_to_ether(wlandevice_t *wlandev, u32 ethconv,
/* chop off the 802.11 CRC */
skb_trim(skb, skb->len - WLAN_CRC_LEN);
- } else if ((payload_length >= sizeof(wlan_llc_t) + sizeof(wlan_snap_t))
+ } else if ((payload_length >= sizeof(struct wlan_llc) + sizeof(struct wlan_snap))
&& (e_llc->dsap == 0xaa) && (e_llc->ssap == 0xaa)
&& (e_llc->ctl == 0x03)
&&
@@ -398,7 +398,7 @@ int skb_p80211_to_ether(wlandevice_t *wlandev, u32 ethconv,
skb_pull(skb, payload_offset);
/* create 802.3 header at beginning of skb. */
- e_hdr = (wlan_ethhdr_t *) skb_push(skb, WLAN_ETHHDR_LEN);
+ e_hdr = (struct wlan_ethhdr *) skb_push(skb, WLAN_ETHHDR_LEN);
memcpy(e_hdr->daddr, daddr, WLAN_ETHADDR_LEN);
memcpy(e_hdr->saddr, saddr, WLAN_ETHADDR_LEN);
e_hdr->type = htons(payload_length);
@@ -406,7 +406,7 @@ int skb_p80211_to_ether(wlandevice_t *wlandev, u32 ethconv,
/* chop off the 802.11 CRC */
skb_trim(skb, skb->len - WLAN_CRC_LEN);
- } else if ((payload_length >= sizeof(wlan_llc_t) + sizeof(wlan_snap_t))
+ } else if ((payload_length >= sizeof(struct wlan_llc) + sizeof(struct wlan_snap))
&& (e_llc->dsap == 0xaa) && (e_llc->ssap == 0xaa)
&& (e_llc->ctl == 0x03)) {
pr_debug("802.1h/RFC1042 len: %d\n", payload_length);
@@ -414,13 +414,13 @@ int skb_p80211_to_ether(wlandevice_t *wlandev, u32 ethconv,
/* build a DIXII + RFC894 */
/* Test for an overlength frame */
- if ((payload_length - sizeof(wlan_llc_t) - sizeof(wlan_snap_t))
+ if ((payload_length - sizeof(struct wlan_llc) - sizeof(struct wlan_snap))
> netdev->mtu) {
/* A bogus length ethfrm has been sent. */
/* Is someone trying an oflow attack? */
printk(KERN_ERR "DIXII frame too large (%ld > %d)\n",
- (long int)(payload_length - sizeof(wlan_llc_t) -
- sizeof(wlan_snap_t)), netdev->mtu);
+ (long int)(payload_length - sizeof(struct wlan_llc) -
+ sizeof(struct wlan_snap)), netdev->mtu);
return 1;
}
@@ -428,13 +428,13 @@ int skb_p80211_to_ether(wlandevice_t *wlandev, u32 ethconv,
skb_pull(skb, payload_offset);
/* chop llc header from skb. */
- skb_pull(skb, sizeof(wlan_llc_t));
+ skb_pull(skb, sizeof(struct wlan_llc));
/* chop snap header from skb. */
- skb_pull(skb, sizeof(wlan_snap_t));
+ skb_pull(skb, sizeof(struct wlan_snap));
/* create 802.3 header at beginning of skb. */
- e_hdr = (wlan_ethhdr_t *) skb_push(skb, WLAN_ETHHDR_LEN);
+ e_hdr = (struct wlan_ethhdr *) skb_push(skb, WLAN_ETHHDR_LEN);
e_hdr->type = e_snap->type;
memcpy(e_hdr->daddr, daddr, WLAN_ETHADDR_LEN);
memcpy(e_hdr->saddr, saddr, WLAN_ETHADDR_LEN);
@@ -461,7 +461,7 @@ int skb_p80211_to_ether(wlandevice_t *wlandev, u32 ethconv,
skb_pull(skb, payload_offset);
/* create 802.3 header at beginning of skb. */
- e_hdr = (wlan_ethhdr_t *) skb_push(skb, WLAN_ETHHDR_LEN);
+ e_hdr = (struct wlan_ethhdr *) skb_push(skb, WLAN_ETHHDR_LEN);
memcpy(e_hdr->daddr, daddr, WLAN_ETHADDR_LEN);
memcpy(e_hdr->saddr, saddr, WLAN_ETHADDR_LEN);
e_hdr->type = htons(payload_length);
@@ -542,8 +542,8 @@ int p80211_stt_findproto(u16 proto)
----------------------------------------------------------------*/
void p80211skb_rxmeta_detach(struct sk_buff *skb)
{
- p80211_rxmeta_t *rxmeta;
- p80211_frmmeta_t *frmmeta;
+ struct p80211_rxmeta *rxmeta;
+ struct p80211_frmmeta *frmmeta;
/* Sanity checks */
if (skb == NULL) { /* bad skb */
@@ -589,8 +589,8 @@ exit:
int p80211skb_rxmeta_attach(struct wlandevice *wlandev, struct sk_buff *skb)
{
int result = 0;
- p80211_rxmeta_t *rxmeta;
- p80211_frmmeta_t *frmmeta;
+ struct p80211_rxmeta *rxmeta;
+ struct p80211_frmmeta *frmmeta;
/* If these already have metadata, we error out! */
if (P80211SKB_RXMETA(skb) != NULL) {
@@ -601,7 +601,7 @@ int p80211skb_rxmeta_attach(struct wlandevice *wlandev, struct sk_buff *skb)
}
/* Allocate the rxmeta */
- rxmeta = kzalloc(sizeof(p80211_rxmeta_t), GFP_ATOMIC);
+ rxmeta = kzalloc(sizeof(struct p80211_rxmeta), GFP_ATOMIC);
if (rxmeta == NULL) {
printk(KERN_ERR "%s: Failed to allocate rxmeta.\n",
@@ -615,8 +615,8 @@ int p80211skb_rxmeta_attach(struct wlandevice *wlandev, struct sk_buff *skb)
rxmeta->hosttime = jiffies;
/* Overlay a frmmeta_t onto skb->cb */
- memset(skb->cb, 0, sizeof(p80211_frmmeta_t));
- frmmeta = (p80211_frmmeta_t *) (skb->cb);
+ memset(skb->cb, 0, sizeof(struct p80211_frmmeta));
+ frmmeta = (struct p80211_frmmeta *) (skb->cb);
frmmeta->magic = P80211_FRMMETA_MAGIC;
frmmeta->rx = rxmeta;
exit:
@@ -641,7 +641,7 @@ exit:
----------------------------------------------------------------*/
void p80211skb_free(struct wlandevice *wlandev, struct sk_buff *skb)
{
- p80211_frmmeta_t *meta;
+ struct p80211_frmmeta *meta;
meta = P80211SKB_FRMMETA(skb);
if (meta && meta->rx)
diff --git a/drivers/staging/wlan-ng/p80211conv.h b/drivers/staging/wlan-ng/p80211conv.h
index 6fe163be24f..eca0391c676 100644
--- a/drivers/staging/wlan-ng/p80211conv.h
+++ b/drivers/staging/wlan-ng/p80211conv.h
@@ -63,17 +63,17 @@
#define P80211CAPTURE_VERSION 0x80211001
-#define P80211_FRMMETA_MAGIC 0x802110
+#define P80211_FRMMETA_MAGIC 0x802110
#define P80211SKB_FRMMETA(s) \
- (((((p80211_frmmeta_t *)((s)->cb))->magic) == P80211_FRMMETA_MAGIC) ? \
- ((p80211_frmmeta_t *)((s)->cb)) : \
+ (((((struct p80211_frmmeta *)((s)->cb))->magic) == P80211_FRMMETA_MAGIC) ? \
+ ((struct p80211_frmmeta *)((s)->cb)) : \
(NULL))
#define P80211SKB_RXMETA(s) \
- (P80211SKB_FRMMETA((s)) ? P80211SKB_FRMMETA((s))->rx : ((p80211_rxmeta_t *)(NULL)))
+ (P80211SKB_FRMMETA((s)) ? P80211SKB_FRMMETA((s))->rx : ((struct p80211_rxmeta *)(NULL)))
-typedef struct p80211_rxmeta {
+struct p80211_rxmeta {
struct wlandevice *wlandev;
u64 mactime; /* Hi-rez MAC-supplied time value */
@@ -87,12 +87,12 @@ typedef struct p80211_rxmeta {
unsigned int preamble; /* P80211ENUM_preambletype_* */
unsigned int encoding; /* P80211ENUM_encoding_* */
-} p80211_rxmeta_t;
+};
-typedef struct p80211_frmmeta {
+struct p80211_frmmeta {
unsigned int magic;
- p80211_rxmeta_t *rx;
-} p80211_frmmeta_t;
+ struct p80211_rxmeta *rx;
+};
void p80211skb_free(struct wlandevice *wlandev, struct sk_buff *skb);
int p80211skb_rxmeta_attach(struct wlandevice *wlandev, struct sk_buff *skb);
@@ -101,7 +101,7 @@ void p80211skb_rxmeta_detach(struct sk_buff *skb);
/*
* Frame capture header. (See doc/capturefrm.txt)
*/
-typedef struct p80211_caphdr {
+struct p80211_caphdr {
u32 version;
u32 length;
u64 mactime;
@@ -116,36 +116,36 @@ typedef struct p80211_caphdr {
s32 ssi_noise;
u32 preamble;
u32 encoding;
-} p80211_caphdr_t;
+};
/* buffer free method pointer type */
typedef void (*freebuf_method_t) (void *buf, int size);
-typedef struct p80211_metawep {
+struct p80211_metawep {
void *data;
u8 iv[4];
u8 icv[4];
-} p80211_metawep_t;
+};
/* local ether header type */
-typedef struct wlan_ethhdr {
+struct wlan_ethhdr {
u8 daddr[WLAN_ETHADDR_LEN];
u8 saddr[WLAN_ETHADDR_LEN];
u16 type;
-} __attribute__ ((packed)) wlan_ethhdr_t;
+} __attribute__ ((packed));
/* local llc header type */
-typedef struct wlan_llc {
+struct wlan_llc {
u8 dsap;
u8 ssap;
u8 ctl;
-} __attribute__ ((packed)) wlan_llc_t;
+} __attribute__ ((packed));
/* local snap header type */
-typedef struct wlan_snap {
+struct wlan_snap {
u8 oui[WLAN_IEEE_OUI_LEN];
u16 type;
-} __attribute__ ((packed)) wlan_snap_t;
+} __attribute__ ((packed));
/* Circular include trick */
struct wlandevice;
@@ -153,8 +153,8 @@ struct wlandevice;
int skb_p80211_to_ether(struct wlandevice *wlandev, u32 ethconv,
struct sk_buff *skb);
int skb_ether_to_p80211(struct wlandevice *wlandev, u32 ethconv,
- struct sk_buff *skb, p80211_hdr_t *p80211_hdr,
- p80211_metawep_t *p80211_wep);
+ struct sk_buff *skb, union p80211_hdr *p80211_hdr,
+ struct p80211_metawep *p80211_wep);
int p80211_stt_findproto(u16 proto);
diff --git a/drivers/staging/wlan-ng/p80211hdr.h b/drivers/staging/wlan-ng/p80211hdr.h
index 419de4dee56..1f6e4ebc6eb 100644
--- a/drivers/staging/wlan-ng/p80211hdr.h
+++ b/drivers/staging/wlan-ng/p80211hdr.h
@@ -94,7 +94,7 @@
/* Control */
#define WLAN_FSTYPE_BLOCKACKREQ 0x8
-#define WLAN_FSTYPE_BLOCKACK 0x9
+#define WLAN_FSTYPE_BLOCKACK 0x9
#define WLAN_FSTYPE_PSPOLL 0x0a
#define WLAN_FSTYPE_RTS 0x0b
#define WLAN_FSTYPE_CTS 0x0c
@@ -133,13 +133,13 @@
#define WLAN_GET_FC_FTYPE(n) ((((u16)(n)) & (BIT(2) | BIT(3))) >> 2)
#define WLAN_GET_FC_FSTYPE(n) ((((u16)(n)) & (BIT(4)|BIT(5)|BIT(6)|BIT(7))) >> 4)
-#define WLAN_GET_FC_TODS(n) ((((u16)(n)) & (BIT(8))) >> 8)
+#define WLAN_GET_FC_TODS(n) ((((u16)(n)) & (BIT(8))) >> 8)
#define WLAN_GET_FC_FROMDS(n) ((((u16)(n)) & (BIT(9))) >> 9)
#define WLAN_GET_FC_ISWEP(n) ((((u16)(n)) & (BIT(14))) >> 14)
#define WLAN_SET_FC_FTYPE(n) (((u16)(n)) << 2)
#define WLAN_SET_FC_FSTYPE(n) (((u16)(n)) << 4)
-#define WLAN_SET_FC_TODS(n) (((u16)(n)) << 8)
+#define WLAN_SET_FC_TODS(n) (((u16)(n)) << 8)
#define WLAN_SET_FC_FROMDS(n) (((u16)(n)) << 9)
#define WLAN_SET_FC_ISWEP(n) (((u16)(n)) << 14)
@@ -147,16 +147,16 @@
/* Generic 802.11 Header types */
-typedef struct p80211_hdr_a3 {
+struct p80211_hdr_a3 {
u16 fc;
u16 dur;
u8 a1[ETH_ALEN];
u8 a2[ETH_ALEN];
u8 a3[ETH_ALEN];
u16 seq;
-} __attribute__ ((packed)) p80211_hdr_a3_t;
+} __attribute__ ((packed));
-typedef struct p80211_hdr_a4 {
+struct p80211_hdr_a4 {
u16 fc;
u16 dur;
u8 a1[ETH_ALEN];
@@ -164,18 +164,18 @@ typedef struct p80211_hdr_a4 {
u8 a3[ETH_ALEN];
u16 seq;
u8 a4[ETH_ALEN];
-} __attribute__ ((packed)) p80211_hdr_a4_t;
+} __attribute__ ((packed));
-typedef union p80211_hdr {
- p80211_hdr_a3_t a3;
- p80211_hdr_a4_t a4;
-} __attribute__ ((packed)) p80211_hdr_t;
+union p80211_hdr {
+ struct p80211_hdr_a3 a3;
+ struct p80211_hdr_a4 a4;
+} __attribute__ ((packed));
/* Frame and header length macros */
#define WLAN_CTL_FRAMELEN(fstype) (\
(fstype) == WLAN_FSTYPE_BLOCKACKREQ ? 24 : \
- (fstype) == WLAN_FSTYPE_BLOCKACK ? 152 : \
+ (fstype) == WLAN_FSTYPE_BLOCKACK ? 152 : \
(fstype) == WLAN_FSTYPE_PSPOLL ? 20 : \
(fstype) == WLAN_FSTYPE_RTS ? 20 : \
(fstype) == WLAN_FSTYPE_CTS ? 14 : \
diff --git a/drivers/staging/wlan-ng/p80211ioctl.h b/drivers/staging/wlan-ng/p80211ioctl.h
index 64ca7f95262..0d47765452e 100644
--- a/drivers/staging/wlan-ng/p80211ioctl.h
+++ b/drivers/staging/wlan-ng/p80211ioctl.h
@@ -78,12 +78,12 @@
/* argument to the ioctl system call when issuing a request to */
/* the p80211 module. */
-typedef struct p80211ioctl_req {
+struct p80211ioctl_req {
char name[WLAN_DEVNAMELEN_MAX];
caddr_t data;
u32 magic;
u16 len;
u32 result;
-} __attribute__ ((packed)) p80211ioctl_req_t;
+} __attribute__ ((packed));
#endif /* _P80211IOCTL_H */
diff --git a/drivers/staging/wlan-ng/p80211meta.h b/drivers/staging/wlan-ng/p80211meta.h
index b9badcff681..c5f1a63add9 100644
--- a/drivers/staging/wlan-ng/p80211meta.h
+++ b/drivers/staging/wlan-ng/p80211meta.h
@@ -62,7 +62,7 @@
/* representation of category list metadata, group list metadata, */
/* and data item metadata for both Mib and Messages. */
-typedef struct p80211meta {
+struct p80211meta {
char *name; /* data item name */
u32 did; /* partial did */
u32 flags; /* set of various flag bits */
@@ -75,16 +75,16 @@ typedef struct p80211meta {
p80211_totext_t totextptr; /* ptr to totext conversion function */
p80211_fromtext_t fromtextptr; /* ptr to totext conversion function */
p80211_valid_t validfunptr; /* ptr to totext conversion function */
-} p80211meta_t;
+};
-typedef struct grplistitem {
+struct grplistitem {
char *name;
- p80211meta_t *itemlist;
-} grplistitem_t;
+ struct p80211meta *itemlist;
+};
-typedef struct catlistitem {
+struct catlistitem {
char *name;
- grplistitem_t *grplist;
-} catlistitem_t;
+ struct grplistitem *grplist;
+};
#endif /* _P80211META_H */
diff --git a/drivers/staging/wlan-ng/p80211metastruct.h b/drivers/staging/wlan-ng/p80211metastruct.h
index db12713eeaa..a8a4e3b5ffe 100644
--- a/drivers/staging/wlan-ng/p80211metastruct.h
+++ b/drivers/staging/wlan-ng/p80211metastruct.h
@@ -47,23 +47,23 @@
#ifndef _P80211MKMETASTRUCT_H
#define _P80211MKMETASTRUCT_H
-typedef struct p80211msg_dot11req_mibget {
+struct p80211msg_dot11req_mibget {
u32 msgcode;
u32 msglen;
u8 devname[WLAN_DEVNAMELEN_MAX];
p80211item_unk392_t mibattribute;
p80211item_uint32_t resultcode;
-} __attribute__ ((packed)) p80211msg_dot11req_mibget_t;
+} __attribute__ ((packed));
-typedef struct p80211msg_dot11req_mibset {
+struct p80211msg_dot11req_mibset {
u32 msgcode;
u32 msglen;
u8 devname[WLAN_DEVNAMELEN_MAX];
p80211item_unk392_t mibattribute;
p80211item_uint32_t resultcode;
-} __attribute__ ((packed)) p80211msg_dot11req_mibset_t;
+} __attribute__ ((packed));
-typedef struct p80211msg_dot11req_scan {
+struct p80211msg_dot11req_scan {
u32 msgcode;
u32 msglen;
u8 devname[WLAN_DEVNAMELEN_MAX];
@@ -81,9 +81,9 @@ typedef struct p80211msg_dot11req_scan {
p80211item_uint32_t resultcode;
p80211item_uint32_t numbss;
p80211item_uint32_t append;
-} __attribute__ ((packed)) p80211msg_dot11req_scan_t;
+} __attribute__ ((packed));
-typedef struct p80211msg_dot11req_scan_results {
+struct p80211msg_dot11req_scan_results {
u32 msgcode;
u32 msglen;
u8 devname[WLAN_DEVNAMELEN_MAX];
@@ -113,6 +113,7 @@ typedef struct p80211msg_dot11req_scan_results {
p80211item_uint32_t cfpollable;
p80211item_uint32_t cfpollreq;
p80211item_uint32_t privacy;
+ p80211item_uint32_t capinfo;
p80211item_uint32_t basicrate1;
p80211item_uint32_t basicrate2;
p80211item_uint32_t basicrate3;
@@ -129,9 +130,9 @@ typedef struct p80211msg_dot11req_scan_results {
p80211item_uint32_t supprate6;
p80211item_uint32_t supprate7;
p80211item_uint32_t supprate8;
-} __attribute__ ((packed)) p80211msg_dot11req_scan_results_t;
+} __attribute__ ((packed));
-typedef struct p80211msg_dot11req_start {
+struct p80211msg_dot11req_start {
u32 msgcode;
u32 msglen;
u8 devname[WLAN_DEVNAMELEN_MAX];
@@ -167,17 +168,17 @@ typedef struct p80211msg_dot11req_start {
p80211item_uint32_t operationalrate7;
p80211item_uint32_t operationalrate8;
p80211item_uint32_t resultcode;
-} __attribute__ ((packed)) p80211msg_dot11req_start_t;
+} __attribute__ ((packed));
-typedef struct p80211msg_lnxreq_ifstate {
+struct p80211msg_lnxreq_ifstate {
u32 msgcode;
u32 msglen;
u8 devname[WLAN_DEVNAMELEN_MAX];
p80211item_uint32_t ifstate;
p80211item_uint32_t resultcode;
-} __attribute__ ((packed)) p80211msg_lnxreq_ifstate_t;
+} __attribute__ ((packed));
-typedef struct p80211msg_lnxreq_wlansniff {
+struct p80211msg_lnxreq_wlansniff {
u32 msgcode;
u32 msglen;
u8 devname[WLAN_DEVNAMELEN_MAX];
@@ -189,18 +190,18 @@ typedef struct p80211msg_lnxreq_wlansniff {
p80211item_uint32_t stripfcs;
p80211item_uint32_t packet_trunc;
p80211item_uint32_t resultcode;
-} __attribute__ ((packed)) p80211msg_lnxreq_wlansniff_t;
+} __attribute__ ((packed));
-typedef struct p80211msg_lnxreq_hostwep {
+struct p80211msg_lnxreq_hostwep {
u32 msgcode;
u32 msglen;
u8 devname[WLAN_DEVNAMELEN_MAX];
p80211item_uint32_t resultcode;
p80211item_uint32_t decrypt;
p80211item_uint32_t encrypt;
-} __attribute__ ((packed)) p80211msg_lnxreq_hostwep_t;
+} __attribute__ ((packed));
-typedef struct p80211msg_lnxreq_commsquality {
+struct p80211msg_lnxreq_commsquality {
u32 msgcode;
u32 msglen;
u8 devname[WLAN_DEVNAMELEN_MAX];
@@ -209,9 +210,10 @@ typedef struct p80211msg_lnxreq_commsquality {
p80211item_uint32_t link;
p80211item_uint32_t level;
p80211item_uint32_t noise;
-} __attribute__ ((packed)) p80211msg_lnxreq_commsquality_t;
+ p80211item_uint32_t txrate;
+} __attribute__ ((packed));
-typedef struct p80211msg_lnxreq_autojoin {
+struct p80211msg_lnxreq_autojoin {
u32 msgcode;
u32 msglen;
u8 devname[WLAN_DEVNAMELEN_MAX];
@@ -219,26 +221,26 @@ typedef struct p80211msg_lnxreq_autojoin {
u8 pad_19D[3];
p80211item_uint32_t authtype;
p80211item_uint32_t resultcode;
-} __attribute__ ((packed)) p80211msg_lnxreq_autojoin_t;
+} __attribute__ ((packed));
-typedef struct p80211msg_p2req_readpda {
+struct p80211msg_p2req_readpda {
u32 msgcode;
u32 msglen;
u8 devname[WLAN_DEVNAMELEN_MAX];
p80211item_unk1024_t pda;
p80211item_uint32_t resultcode;
-} __attribute__ ((packed)) p80211msg_p2req_readpda_t;
+} __attribute__ ((packed));
-typedef struct p80211msg_p2req_ramdl_state {
+struct p80211msg_p2req_ramdl_state {
u32 msgcode;
u32 msglen;
u8 devname[WLAN_DEVNAMELEN_MAX];
p80211item_uint32_t enable;
p80211item_uint32_t exeaddr;
p80211item_uint32_t resultcode;
-} __attribute__ ((packed)) p80211msg_p2req_ramdl_state_t;
+} __attribute__ ((packed));
-typedef struct p80211msg_p2req_ramdl_write {
+struct p80211msg_p2req_ramdl_write {
u32 msgcode;
u32 msglen;
u8 devname[WLAN_DEVNAMELEN_MAX];
@@ -246,17 +248,17 @@ typedef struct p80211msg_p2req_ramdl_write {
p80211item_uint32_t len;
p80211item_unk4096_t data;
p80211item_uint32_t resultcode;
-} __attribute__ ((packed)) p80211msg_p2req_ramdl_write_t;
+} __attribute__ ((packed));
-typedef struct p80211msg_p2req_flashdl_state {
+struct p80211msg_p2req_flashdl_state {
u32 msgcode;
u32 msglen;
u8 devname[WLAN_DEVNAMELEN_MAX];
p80211item_uint32_t enable;
p80211item_uint32_t resultcode;
-} __attribute__ ((packed)) p80211msg_p2req_flashdl_state_t;
+} __attribute__ ((packed));
-typedef struct p80211msg_p2req_flashdl_write {
+struct p80211msg_p2req_flashdl_write {
u32 msgcode;
u32 msglen;
u8 devname[WLAN_DEVNAMELEN_MAX];
@@ -264,6 +266,6 @@ typedef struct p80211msg_p2req_flashdl_write {
p80211item_uint32_t len;
p80211item_unk4096_t data;
p80211item_uint32_t resultcode;
-} __attribute__ ((packed)) p80211msg_p2req_flashdl_write_t;
+} __attribute__ ((packed));
#endif
diff --git a/drivers/staging/wlan-ng/p80211mgmt.h b/drivers/staging/wlan-ng/p80211mgmt.h
index deb52f5fd78..3b5e8113ad1 100644
--- a/drivers/staging/wlan-ng/p80211mgmt.h
+++ b/drivers/staging/wlan-ng/p80211mgmt.h
@@ -298,7 +298,7 @@ typedef struct wlan_fr_mgmt {
u16 type;
u16 len; /* DOES NOT include CRC !!!! */
u8 *buf;
- p80211_hdr_t *hdr;
+ union p80211_hdr *hdr;
/* used for target specific data, skb in Linux */
void *priv;
/*-- fixed fields -----------*/
@@ -310,7 +310,7 @@ typedef struct wlan_fr_beacon {
u16 type;
u16 len;
u8 *buf;
- p80211_hdr_t *hdr;
+ union p80211_hdr *hdr;
/* used for target specific data, skb in Linux */
void *priv;
/*-- fixed fields -----------*/
@@ -333,7 +333,7 @@ typedef struct wlan_fr_ibssatim {
u16 type;
u16 len;
u8 *buf;
- p80211_hdr_t *hdr;
+ union p80211_hdr *hdr;
/* used for target specific data, skb in Linux */
void *priv;
@@ -349,7 +349,7 @@ typedef struct wlan_fr_disassoc {
u16 type;
u16 len;
u8 *buf;
- p80211_hdr_t *hdr;
+ union p80211_hdr *hdr;
/* used for target specific data, skb in Linux */
void *priv;
/*-- fixed fields -----------*/
@@ -364,7 +364,7 @@ typedef struct wlan_fr_assocreq {
u16 type;
u16 len;
u8 *buf;
- p80211_hdr_t *hdr;
+ union p80211_hdr *hdr;
/* used for target specific data, skb in Linux */
void *priv;
/*-- fixed fields -----------*/
@@ -381,7 +381,7 @@ typedef struct wlan_fr_assocresp {
u16 type;
u16 len;
u8 *buf;
- p80211_hdr_t *hdr;
+ union p80211_hdr *hdr;
/* used for target specific data, skb in Linux */
void *priv;
/*-- fixed fields -----------*/
@@ -398,7 +398,7 @@ typedef struct wlan_fr_reassocreq {
u16 type;
u16 len;
u8 *buf;
- p80211_hdr_t *hdr;
+ union p80211_hdr *hdr;
/* used for target specific data, skb in Linux */
void *priv;
/*-- fixed fields -----------*/
@@ -416,7 +416,7 @@ typedef struct wlan_fr_reassocresp {
u16 type;
u16 len;
u8 *buf;
- p80211_hdr_t *hdr;
+ union p80211_hdr *hdr;
/* used for target specific data, skb in Linux */
void *priv;
/*-- fixed fields -----------*/
@@ -433,7 +433,7 @@ typedef struct wlan_fr_probereq {
u16 type;
u16 len;
u8 *buf;
- p80211_hdr_t *hdr;
+ union p80211_hdr *hdr;
/* used for target specific data, skb in Linux */
void *priv;
/*-- fixed fields -----------*/
@@ -448,7 +448,7 @@ typedef struct wlan_fr_proberesp {
u16 type;
u16 len;
u8 *buf;
- p80211_hdr_t *hdr;
+ union p80211_hdr *hdr;
/* used for target specific data, skb in Linux */
void *priv;
/*-- fixed fields -----------*/
@@ -469,7 +469,7 @@ typedef struct wlan_fr_authen {
u16 type;
u16 len;
u8 *buf;
- p80211_hdr_t *hdr;
+ union p80211_hdr *hdr;
/* used for target specific data, skb in Linux */
void *priv;
/*-- fixed fields -----------*/
@@ -486,7 +486,7 @@ typedef struct wlan_fr_deauthen {
u16 type;
u16 len;
u8 *buf;
- p80211_hdr_t *hdr;
+ union p80211_hdr *hdr;
/* used for target specific data, skb in Linux */
void *priv;
/*-- fixed fields -----------*/
diff --git a/drivers/staging/wlan-ng/p80211msg.h b/drivers/staging/wlan-ng/p80211msg.h
index c691d3eeb9d..8e0f9a0cd74 100644
--- a/drivers/staging/wlan-ng/p80211msg.h
+++ b/drivers/staging/wlan-ng/p80211msg.h
@@ -50,10 +50,10 @@
#define WLAN_DEVNAMELEN_MAX 16
-typedef struct p80211msg {
+struct p80211msg {
u32 msgcode;
u32 msglen;
u8 devname[WLAN_DEVNAMELEN_MAX];
-} __attribute__ ((packed)) p80211msg_t;
+} __attribute__ ((packed));
#endif /* _P80211MSG_H */
diff --git a/drivers/staging/wlan-ng/p80211netdev.c b/drivers/staging/wlan-ng/p80211netdev.c
index 763ab1187a1..aa1792c8429 100644
--- a/drivers/staging/wlan-ng/p80211netdev.c
+++ b/drivers/staging/wlan-ng/p80211netdev.c
@@ -75,6 +75,7 @@
#include <net/iw_handler.h>
#include <net/net_namespace.h>
+#include <net/cfg80211.h>
#include "p80211types.h"
#include "p80211hdr.h"
@@ -87,6 +88,8 @@
#include "p80211metastruct.h"
#include "p80211metadef.h"
+#include "cfg80211.c"
+
/* Support functions */
static void p80211netdev_rx_bh(unsigned long arg);
@@ -261,7 +264,7 @@ static void p80211netdev_rx_bh(unsigned long arg)
wlandevice_t *wlandev = (wlandevice_t *) arg;
struct sk_buff *skb = NULL;
netdevice_t *dev = wlandev->netdev;
- p80211_hdr_a3_t *hdr;
+ struct p80211_hdr_a3 *hdr;
u16 fc;
/* Let's empty our our queue */
@@ -285,7 +288,7 @@ static void p80211netdev_rx_bh(unsigned long arg)
netif_rx_ni(skb);
continue;
} else {
- hdr = (p80211_hdr_a3_t *) skb->data;
+ hdr = (struct p80211_hdr_a3 *) skb->data;
fc = le16_to_cpu(hdr->fc);
if (p80211_rx_typedrop(wlandev, fc)) {
dev_kfree_skb(skb);
@@ -347,8 +350,8 @@ static int p80211knetdev_hard_start_xmit(struct sk_buff *skb,
int result = 0;
int txresult = -1;
wlandevice_t *wlandev = netdev->ml_priv;
- p80211_hdr_t p80211_hdr;
- p80211_metawep_t p80211_wep;
+ union p80211_hdr p80211_hdr;
+ struct p80211_metawep p80211_wep;
if (skb == NULL)
return NETDEV_TX_OK;
@@ -358,8 +361,8 @@ static int p80211knetdev_hard_start_xmit(struct sk_buff *skb,
goto failed;
}
- memset(&p80211_hdr, 0, sizeof(p80211_hdr_t));
- memset(&p80211_wep, 0, sizeof(p80211_metawep_t));
+ memset(&p80211_hdr, 0, sizeof(union p80211_hdr));
+ memset(&p80211_wep, 0, sizeof(struct p80211_metawep));
if (netif_queue_stopped(netdev)) {
pr_debug("called when queue stopped.\n");
@@ -398,8 +401,8 @@ static int p80211knetdev_hard_start_xmit(struct sk_buff *skb,
goto failed;
}
/* move the header over */
- memcpy(&p80211_hdr, skb->data, sizeof(p80211_hdr_t));
- skb_pull(skb, sizeof(p80211_hdr_t));
+ memcpy(&p80211_hdr, skb->data, sizeof(union p80211_hdr));
+ skb_pull(skb, sizeof(union p80211_hdr));
} else {
if (skb_ether_to_p80211
(wlandev, wlandev->ethconv, skb, &p80211_hdr,
@@ -557,7 +560,7 @@ static int p80211netdev_ethtool(wlandevice_t *wlandev, void __user *useraddr)
static int p80211knetdev_do_ioctl(netdevice_t *dev, struct ifreq *ifr, int cmd)
{
int result = 0;
- p80211ioctl_req_t *req = (p80211ioctl_req_t *) ifr;
+ struct p80211ioctl_req *req = (struct p80211ioctl_req *) ifr;
wlandevice_t *wlandev = dev->ml_priv;
u8 *msgbuf;
@@ -604,7 +607,8 @@ static int p80211knetdev_do_ioctl(netdevice_t *dev, struct ifreq *ifr, int cmd)
result = -ENOMEM;
}
bail:
- return result; /* If allocate,copyfrom or copyto fails, return errno */
+ /* If allocate,copyfrom or copyto fails, return errno */
+ return result;
}
/*----------------------------------------------------------------
@@ -635,7 +639,7 @@ bail:
static int p80211knetdev_set_mac_address(netdevice_t *dev, void *addr)
{
struct sockaddr *new_addr = addr;
- p80211msg_dot11req_mibset_t dot11req;
+ struct p80211msg_dot11req_mibset dot11req;
p80211item_unk392_t *mibattr;
p80211item_pstr6_t *macaddr;
p80211item_uint32_t *resultcode;
@@ -651,9 +655,9 @@ static int p80211knetdev_set_mac_address(netdevice_t *dev, void *addr)
resultcode = &dot11req.resultcode;
/* Set up a dot11req_mibset */
- memset(&dot11req, 0, sizeof(p80211msg_dot11req_mibset_t));
+ memset(&dot11req, 0, sizeof(struct p80211msg_dot11req_mibset));
dot11req.msgcode = DIDmsg_dot11req_mibset;
- dot11req.msglen = sizeof(p80211msg_dot11req_mibset_t);
+ dot11req.msglen = sizeof(struct p80211msg_dot11req_mibset);
memcpy(dot11req.devname,
((wlandevice_t *) dev->ml_priv)->name, WLAN_DEVNAMELEN_MAX - 1);
@@ -732,6 +736,7 @@ static const struct net_device_ops p80211_netdev_ops = {
* Arguments:
* wlandev ptr to the wlandev structure for the
* interface.
+* physdev ptr to usb device
* Returns:
* zero on success, non-zero otherwise.
* Call Context:
@@ -740,10 +745,12 @@ static const struct net_device_ops p80211_netdev_ops = {
* compiled drivers, this function will be called in the
* context of the kernel startup code.
----------------------------------------------------------------*/
-int wlan_setup(wlandevice_t *wlandev)
+int wlan_setup(wlandevice_t *wlandev, struct device *physdev)
{
int result = 0;
- netdevice_t *dev;
+ netdevice_t *netdev;
+ struct wiphy *wiphy;
+ struct wireless_dev *wdev;
/* Set up the wlandev */
wlandev->state = WLAN_DEVICE_CLOSED;
@@ -755,20 +762,30 @@ int wlan_setup(wlandevice_t *wlandev)
tasklet_init(&wlandev->rx_bh,
p80211netdev_rx_bh, (unsigned long)wlandev);
+ /* Allocate and initialize the wiphy struct */
+ wiphy = wlan_create_wiphy(physdev, wlandev);
+ if (wiphy == NULL) {
+ printk(KERN_ERR "Failed to alloc wiphy.\n");
+ return 1;
+ }
+
/* Allocate and initialize the struct device */
- dev = alloc_netdev(0, "wlan%d", ether_setup);
- if (dev == NULL) {
+ netdev = alloc_netdev(sizeof(struct wireless_dev), "wlan%d", ether_setup);
+ if (netdev == NULL) {
printk(KERN_ERR "Failed to alloc netdev.\n");
+ wlan_free_wiphy(wiphy);
result = 1;
} else {
- wlandev->netdev = dev;
- dev->ml_priv = wlandev;
- dev->netdev_ops = &p80211_netdev_ops;
-
- dev->wireless_handlers = &p80211wext_handler_def;
-
- netif_stop_queue(dev);
- netif_carrier_off(dev);
+ wlandev->netdev = netdev;
+ netdev->ml_priv = wlandev;
+ netdev->netdev_ops = &p80211_netdev_ops;
+ wdev = netdev_priv(netdev);
+ wdev->wiphy = wiphy;
+ wdev->iftype = NL80211_IFTYPE_STATION;
+ netdev->ieee80211_ptr = wdev;
+
+ netif_stop_queue(netdev);
+ netif_carrier_off(netdev);
}
return result;
@@ -797,14 +814,14 @@ int wlan_setup(wlandevice_t *wlandev)
----------------------------------------------------------------*/
int wlan_unsetup(wlandevice_t *wlandev)
{
- int result = 0;
+ struct wireless_dev *wdev;
tasklet_kill(&wlandev->rx_bh);
- if (wlandev->netdev == NULL) {
- printk(KERN_ERR "called without wlandev->netdev set.\n");
- result = 1;
- } else {
+ if (wlandev->netdev) {
+ wdev = netdev_priv(wlandev->netdev);
+ if (wdev->wiphy)
+ wlan_free_wiphy(wdev->wiphy);
free_netdev(wlandev->netdev);
wlandev->netdev = NULL;
}
diff --git a/drivers/staging/wlan-ng/p80211netdev.h b/drivers/staging/wlan-ng/p80211netdev.h
index 3c8c6480056..1ec33740f10 100644
--- a/drivers/staging/wlan-ng/p80211netdev.h
+++ b/drivers/staging/wlan-ng/p80211netdev.h
@@ -148,6 +148,7 @@ int p80211wext_event_associated(struct wlandevice *wlandev, int assoc);
#define MAX_KEYLEN 32
#define HOSTWEP_DEFAULTKEY_MASK (BIT(1)|BIT(0))
+#define HOSTWEP_SHAREDKEY BIT(3)
#define HOSTWEP_DECRYPT BIT(4)
#define HOSTWEP_ENCRYPT BIT(5)
#define HOSTWEP_PRIVACYINVOKED BIT(6)
@@ -183,9 +184,9 @@ typedef struct wlandevice {
int (*close) (struct wlandevice *wlandev);
void (*reset) (struct wlandevice *wlandev);
int (*txframe) (struct wlandevice *wlandev, struct sk_buff *skb,
- p80211_hdr_t *p80211_hdr,
- p80211_metawep_t *p80211_wep);
- int (*mlmerequest) (struct wlandevice *wlandev, p80211msg_t *msg);
+ union p80211_hdr *p80211_hdr,
+ struct p80211_metawep *p80211_wep);
+ int (*mlmerequest) (struct wlandevice *wlandev, struct p80211msg *msg);
int (*set_multicast_list) (struct wlandevice *wlandev,
netdevice_t *dev);
void (*tx_timeout) (struct wlandevice *wlandev);
@@ -233,7 +234,7 @@ int wep_decrypt(wlandevice_t *wlandev, u8 *buf, u32 len, int key_override,
int wep_encrypt(wlandevice_t *wlandev, u8 *buf, u8 *dst, u32 len, int keynum,
u8 *iv, u8 *icv);
-int wlan_setup(wlandevice_t *wlandev);
+int wlan_setup(wlandevice_t *wlandev, struct device *physdev);
int wlan_unsetup(wlandevice_t *wlandev);
int register_wlandev(wlandevice_t *wlandev);
int unregister_wlandev(wlandevice_t *wlandev);
diff --git a/drivers/staging/wlan-ng/p80211req.c b/drivers/staging/wlan-ng/p80211req.c
index 207f080cfc9..179194e7d2a 100644
--- a/drivers/staging/wlan-ng/p80211req.c
+++ b/drivers/staging/wlan-ng/p80211req.c
@@ -72,9 +72,9 @@
#include "p80211metastruct.h"
#include "p80211req.h"
-static void p80211req_handlemsg(wlandevice_t *wlandev, p80211msg_t *msg);
+static void p80211req_handlemsg(wlandevice_t *wlandev, struct p80211msg *msg);
static int p80211req_mibset_mibget(wlandevice_t *wlandev,
- p80211msg_dot11req_mibget_t *mib_msg,
+ struct p80211msg_dot11req_mibget *mib_msg,
int isget);
/*----------------------------------------------------------------
@@ -96,7 +96,7 @@ static int p80211req_mibset_mibget(wlandevice_t *wlandev,
int p80211req_dorequest(wlandevice_t *wlandev, u8 *msgbuf)
{
int result = 0;
- p80211msg_t *msg = (p80211msg_t *) msgbuf;
+ struct p80211msg *msg = (struct p80211msg *) msgbuf;
/* Check to make sure the MSD is running */
if (!((wlandev->msdstate == WLAN_MSD_HWPRESENT &&
@@ -150,13 +150,13 @@ int p80211req_dorequest(wlandevice_t *wlandev, u8 *msgbuf)
* Call context:
* Process thread
----------------------------------------------------------------*/
-static void p80211req_handlemsg(wlandevice_t *wlandev, p80211msg_t *msg)
+static void p80211req_handlemsg(wlandevice_t *wlandev, struct p80211msg *msg)
{
switch (msg->msgcode) {
case DIDmsg_lnxreq_hostwep:{
- p80211msg_lnxreq_hostwep_t *req =
- (p80211msg_lnxreq_hostwep_t *) msg;
+ struct p80211msg_lnxreq_hostwep *req =
+ (struct p80211msg_lnxreq_hostwep *) msg;
wlandev->hostwep &=
~(HOSTWEP_DECRYPT | HOSTWEP_ENCRYPT);
if (req->decrypt.data == P80211ENUM_truth_true)
@@ -169,8 +169,8 @@ static void p80211req_handlemsg(wlandevice_t *wlandev, p80211msg_t *msg)
case DIDmsg_dot11req_mibget:
case DIDmsg_dot11req_mibset:{
int isget = (msg->msgcode == DIDmsg_dot11req_mibget);
- p80211msg_dot11req_mibget_t *mib_msg =
- (p80211msg_dot11req_mibget_t *) msg;
+ struct p80211msg_dot11req_mibget *mib_msg =
+ (struct p80211msg_dot11req_mibget *) msg;
p80211req_mibset_mibget(wlandev, mib_msg, isget);
}
default:
@@ -181,7 +181,7 @@ static void p80211req_handlemsg(wlandevice_t *wlandev, p80211msg_t *msg)
}
static int p80211req_mibset_mibget(wlandevice_t *wlandev,
- p80211msg_dot11req_mibget_t *mib_msg,
+ struct p80211msg_dot11req_mibget *mib_msg,
int isget)
{
p80211itemd_t *mibitem = (p80211itemd_t *) mib_msg->mibattribute.data;
diff --git a/drivers/staging/wlan-ng/p80211wext.c b/drivers/staging/wlan-ng/p80211wext.c
deleted file mode 100644
index 387194d4a6e..00000000000
--- a/drivers/staging/wlan-ng/p80211wext.c
+++ /dev/null
@@ -1,1690 +0,0 @@
-/* src/p80211/p80211wext.c
-*
-* Glue code to make linux-wlan-ng a happy wireless extension camper.
-*
-* original author: Reyk Floeter <reyk@synack.de>
-* Completely re-written by Solomon Peachy <solomon@linux-wlan.com>
-*
-* Copyright (C) 2002 AbsoluteValue Systems, Inc. All Rights Reserved.
-* --------------------------------------------------------------------
-*
-* linux-wlan
-*
-* The contents of this file are subject to the Mozilla Public
-* License Version 1.1 (the "License"); you may not use this file
-* except in compliance with the License. You may obtain a copy of
-* the License at http://www.mozilla.org/MPL/
-*
-* Software distributed under the License is distributed on an "AS
-* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
-* implied. See the License for the specific language governing
-* rights and limitations under the License.
-*
-* Alternatively, the contents of this file may be used under the
-* terms of the GNU Public License version 2 (the "GPL"), in which
-* case the provisions of the GPL are applicable instead of the
-* above. If you wish to allow the use of your version of this file
-* only under the terms of the GPL and not to allow others to use
-* your version of this file under the MPL, indicate your decision
-* by deleting the provisions above and replace them with the notice
-* and other provisions required by the GPL. If you do not delete
-* the provisions above, a recipient may use your version of this
-* file under either the MPL or the GPL.
-*
-* --------------------------------------------------------------------
-*/
-
-/*================================================================*/
-/* System Includes */
-
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/types.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/wireless.h>
-#include <net/iw_handler.h>
-#include <linux/if_arp.h>
-#include <linux/bitops.h>
-#include <linux/uaccess.h>
-#include <asm/byteorder.h>
-#include <linux/if_ether.h>
-
-#include "p80211types.h"
-#include "p80211hdr.h"
-#include "p80211conv.h"
-#include "p80211mgmt.h"
-#include "p80211msg.h"
-#include "p80211metastruct.h"
-#include "p80211metadef.h"
-#include "p80211netdev.h"
-#include "p80211ioctl.h"
-#include "p80211req.h"
-
-static int p80211wext_giwrate(netdevice_t *dev,
- struct iw_request_info *info,
- struct iw_param *rrq, char *extra);
-static int p80211wext_giwessid(netdevice_t *dev,
- struct iw_request_info *info,
- struct iw_point *data, char *essid);
-
-static u8 p80211_mhz_to_channel(u16 mhz)
-{
- if (mhz >= 5000)
- return (mhz - 5000) / 5;
-
- if (mhz == 2484)
- return 14;
-
- if (mhz >= 2407)
- return (mhz - 2407) / 5;
-
- return 0;
-}
-
-static u16 p80211_channel_to_mhz(u8 ch, int dot11a)
-{
-
- if (ch == 0)
- return 0;
- if (ch > 200)
- return 0;
-
- /* 5G */
- if (dot11a)
- return 5000 + (5 * ch);
-
- /* 2.4G */
- if (ch == 14)
- return 2484;
-
- if ((ch < 14) && (ch > 0))
- return 2407 + (5 * ch);
-
- return 0;
-}
-
-/* taken from orinoco.c ;-) */
-static const long p80211wext_channel_freq[] = {
- 2412, 2417, 2422, 2427, 2432, 2437, 2442,
- 2447, 2452, 2457, 2462, 2467, 2472, 2484
-};
-
-#define NUM_CHANNELS ARRAY_SIZE(p80211wext_channel_freq)
-
-/* steal a spare bit to store the shared/opensystems state.
- should default to open if not set */
-#define HOSTWEP_SHAREDKEY BIT(3)
-
-static int qual_as_percent(int snr)
-{
- if (snr <= 0)
- return 0;
- if (snr <= 40)
- return snr * 5 / 2;
- return 100;
-}
-
-static int p80211wext_setmib(wlandevice_t *wlandev, u32 did, u32 data)
-{
- p80211msg_dot11req_mibset_t msg;
- p80211item_uint32_t *mibitem =
- (p80211item_uint32_t *)&msg.mibattribute.data;
- int result;
-
- msg.msgcode = DIDmsg_dot11req_mibset;
- memset(mibitem, 0, sizeof(*mibitem));
- mibitem->did = did;
- mibitem->data = data;
- result = p80211req_dorequest(wlandev, (u8 *) &msg);
-
- return result;
-}
-
-/*
- * get a 32 bit mib value
- */
-static int p80211wext_getmib(wlandevice_t *wlandev, u32 did, u32 *data)
-{
- p80211msg_dot11req_mibset_t msg;
- p80211item_uint32_t *mibitem =
- (p80211item_uint32_t *)&msg.mibattribute.data;
- int result;
-
- msg.msgcode = DIDmsg_dot11req_mibget;
- memset(mibitem, 0, sizeof(*mibitem));
- mibitem->did = did;
- result = p80211req_dorequest(wlandev, (u8 *) &msg);
- if (!result)
- *data = mibitem->data;
-
- return result;
-}
-
-static int p80211wext_autojoin(wlandevice_t *wlandev)
-{
- p80211msg_lnxreq_autojoin_t msg;
- struct iw_point data;
- char ssid[IW_ESSID_MAX_SIZE];
-
- int result;
- int err = 0;
-
- /* Get ESSID */
- result = p80211wext_giwessid(wlandev->netdev, NULL, &data, ssid);
-
- if (result) {
- err = -EFAULT;
- goto exit;
- }
-
- if (wlandev->hostwep & HOSTWEP_SHAREDKEY)
- msg.authtype.data = P80211ENUM_authalg_sharedkey;
- else
- msg.authtype.data = P80211ENUM_authalg_opensystem;
-
- msg.msgcode = DIDmsg_lnxreq_autojoin;
-
- /* Trim the last '\0' to fit the SSID format */
-
- if (data.length && ssid[data.length - 1] == '\0')
- data.length = data.length - 1;
-
- memcpy(msg.ssid.data.data, ssid, data.length);
- msg.ssid.data.len = data.length;
-
- result = p80211req_dorequest(wlandev, (u8 *) &msg);
-
- if (result) {
- err = -EFAULT;
- goto exit;
- }
-
-exit:
-
- return err;
-
-}
-
-/* called by /proc/net/wireless */
-struct iw_statistics *p80211wext_get_wireless_stats(netdevice_t *dev)
-{
- p80211msg_lnxreq_commsquality_t quality;
- wlandevice_t *wlandev = dev->ml_priv;
- struct iw_statistics *wstats = &wlandev->wstats;
- int retval;
-
- /* Check */
- if ((wlandev == NULL) || (wlandev->msdstate != WLAN_MSD_RUNNING))
- return NULL;
-
- /* XXX Only valid in station mode */
- wstats->status = 0;
-
- /* build request message */
- quality.msgcode = DIDmsg_lnxreq_commsquality;
- quality.dbm.data = P80211ENUM_truth_true;
- quality.dbm.status = P80211ENUM_msgitem_status_data_ok;
-
- /* send message to nsd */
- if (wlandev->mlmerequest == NULL)
- return NULL;
-
- retval = wlandev->mlmerequest(wlandev, (p80211msg_t *) &quality);
-
- wstats->qual.qual = qual_as_percent(quality.link.data); /* overall link quality */
- wstats->qual.level = quality.level.data; /* instant signal level */
- wstats->qual.noise = quality.noise.data; /* instant noise level */
-
- wstats->qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM;
- wstats->discard.code = wlandev->rx.decrypt_err;
- wstats->discard.nwid = 0;
- wstats->discard.misc = 0;
-
- wstats->discard.fragment = 0; /* incomplete fragments */
- wstats->discard.retries = 0; /* tx retries. */
- wstats->miss.beacon = 0;
-
- return wstats;
-}
-
-static int p80211wext_giwname(netdevice_t *dev,
- struct iw_request_info *info,
- char *name, char *extra)
-{
- struct iw_param rate;
- int result;
- int err = 0;
-
- result = p80211wext_giwrate(dev, NULL, &rate, NULL);
-
- if (result) {
- err = -EFAULT;
- goto exit;
- }
-
- switch (rate.value) {
- case 1000000:
- case 2000000:
- strcpy(name, "IEEE 802.11-DS");
- break;
- case 5500000:
- case 11000000:
- strcpy(name, "IEEE 802.11-b");
- break;
- }
-exit:
- return err;
-}
-
-static int p80211wext_giwfreq(netdevice_t *dev,
- struct iw_request_info *info,
- struct iw_freq *freq, char *extra)
-{
- wlandevice_t *wlandev = dev->ml_priv;
- int result;
- int err = 0;
- unsigned int value;
-
- result = p80211wext_getmib(wlandev,
- DIDmib_dot11phy_dot11PhyDSSSTable_dot11CurrentChannel,
- &value);
- if (result) {
- err = -EFAULT;
- goto exit;
- }
-
- if (value > NUM_CHANNELS) {
- err = -EFAULT;
- goto exit;
- }
-
- /* convert into frequency instead of a channel */
- freq->e = 1;
- freq->m = p80211_channel_to_mhz(value, 0) * 100000;
-
-exit:
- return err;
-}
-
-static int p80211wext_siwfreq(netdevice_t *dev,
- struct iw_request_info *info,
- struct iw_freq *freq, char *extra)
-{
- wlandevice_t *wlandev = dev->ml_priv;
- int result;
- int err = 0;
- unsigned int value;
-
- if (!wlan_wext_write) {
- err = -EOPNOTSUPP;
- goto exit;
- }
-
- if ((freq->e == 0) && (freq->m <= 1000))
- value = freq->m;
- else
- value = p80211_mhz_to_channel(freq->m);
-
- result = p80211wext_setmib(wlandev,
- DIDmib_dot11phy_dot11PhyDSSSTable_dot11CurrentChannel,
- value);
-
- if (result) {
- err = -EFAULT;
- goto exit;
- }
-
-exit:
- return err;
-}
-
-static int p80211wext_giwmode(netdevice_t *dev,
- struct iw_request_info *info,
- __u32 *mode, char *extra)
-{
- wlandevice_t *wlandev = dev->ml_priv;
-
- switch (wlandev->macmode) {
- case WLAN_MACMODE_IBSS_STA:
- *mode = IW_MODE_ADHOC;
- break;
- case WLAN_MACMODE_ESS_STA:
- *mode = IW_MODE_INFRA;
- break;
- case WLAN_MACMODE_ESS_AP:
- *mode = IW_MODE_MASTER;
- break;
- default:
- /* Not set yet. */
- *mode = IW_MODE_AUTO;
- }
-
- return 0;
-}
-
-static int p80211wext_siwmode(netdevice_t *dev,
- struct iw_request_info *info,
- __u32 *mode, char *extra)
-{
- wlandevice_t *wlandev = dev->ml_priv;
- int result;
- int err = 0;
-
- if (!wlan_wext_write) {
- err = -EOPNOTSUPP;
- goto exit;
- }
-
- if (*mode != IW_MODE_ADHOC && *mode != IW_MODE_INFRA &&
- *mode != IW_MODE_MASTER) {
- err = (-EOPNOTSUPP);
- goto exit;
- }
-
- /* Operation mode is the same with current mode */
- if (*mode == wlandev->macmode)
- goto exit;
-
- switch (*mode) {
- case IW_MODE_ADHOC:
- wlandev->macmode = WLAN_MACMODE_IBSS_STA;
- break;
- case IW_MODE_INFRA:
- wlandev->macmode = WLAN_MACMODE_ESS_STA;
- break;
- case IW_MODE_MASTER:
- wlandev->macmode = WLAN_MACMODE_ESS_AP;
- break;
- default:
- /* Not set yet. */
- printk(KERN_INFO "Operation mode: %d not support\n", *mode);
- return -EOPNOTSUPP;
- }
-
- /* Set Operation mode to the PORT TYPE RID */
- result = p80211wext_setmib(wlandev,
- DIDmib_p2_p2Static_p2CnfPortType,
- (*mode == IW_MODE_ADHOC) ? 0 : 1);
- if (result)
- err = -EFAULT;
-exit:
- return err;
-}
-
-static int p80211wext_giwrange(netdevice_t *dev,
- struct iw_request_info *info,
- struct iw_point *data, char *extra)
-{
- struct iw_range *range = (struct iw_range *)extra;
- int i, val;
-
- /* for backward compatability set size and zero everything we don't understand */
- data->length = sizeof(*range);
- memset(range, 0, sizeof(*range));
-
- range->txpower_capa = IW_TXPOW_DBM;
- /* XXX what about min/max_pmp, min/max_pmt, etc. */
-
- range->we_version_compiled = WIRELESS_EXT;
- range->we_version_source = 13;
-
- range->retry_capa = IW_RETRY_LIMIT;
- range->retry_flags = IW_RETRY_LIMIT;
- range->min_retry = 0;
- range->max_retry = 255;
-
- range->event_capa[0] = (IW_EVENT_CAPA_K_0 | /* mode/freq/ssid */
- IW_EVENT_CAPA_MASK(SIOCGIWAP) |
- IW_EVENT_CAPA_MASK(SIOCGIWSCAN));
- range->event_capa[1] = IW_EVENT_CAPA_K_1; /* encode */
- range->event_capa[4] = (IW_EVENT_CAPA_MASK(IWEVQUAL) |
- IW_EVENT_CAPA_MASK(IWEVCUSTOM));
-
- range->num_channels = NUM_CHANNELS;
-
- /* XXX need to filter against the regulatory domain &| active set */
- val = 0;
- for (i = 0; i < NUM_CHANNELS; i++) {
- range->freq[val].i = i + 1;
- range->freq[val].m = p80211wext_channel_freq[i] * 100000;
- range->freq[val].e = 1;
- val++;
- }
-
- range->num_frequency = val;
-
- /* Max of /proc/net/wireless */
- range->max_qual.qual = 100;
- range->max_qual.level = 0;
- range->max_qual.noise = 0;
- range->sensitivity = 3;
- /* XXX these need to be nsd-specific! */
-
- range->min_rts = 0;
- range->max_rts = 2347;
- range->min_frag = 256;
- range->max_frag = 2346;
-
- range->max_encoding_tokens = NUM_WEPKEYS;
- range->num_encoding_sizes = 2;
- range->encoding_size[0] = 5;
- range->encoding_size[1] = 13;
-
- /* XXX what about num_bitrates/throughput? */
- range->num_bitrates = 0;
-
- /* estimated max throughput */
- /* XXX need to cap it if we're running at ~2Mbps.. */
- range->throughput = 5500000;
-
- return 0;
-}
-
-static int p80211wext_giwap(netdevice_t *dev,
- struct iw_request_info *info,
- struct sockaddr *ap_addr, char *extra)
-{
-
- wlandevice_t *wlandev = dev->ml_priv;
-
- memcpy(ap_addr->sa_data, wlandev->bssid, WLAN_BSSID_LEN);
- ap_addr->sa_family = ARPHRD_ETHER;
-
- return 0;
-}
-
-static int p80211wext_giwencode(netdevice_t *dev,
- struct iw_request_info *info,
- struct iw_point *erq, char *key)
-{
- wlandevice_t *wlandev = dev->ml_priv;
- int err = 0;
- int i;
-
- i = (erq->flags & IW_ENCODE_INDEX) - 1;
- erq->flags = 0;
-
- if (wlandev->hostwep & HOSTWEP_PRIVACYINVOKED)
- erq->flags |= IW_ENCODE_ENABLED;
- else
- erq->flags |= IW_ENCODE_DISABLED;
-
- if (wlandev->hostwep & HOSTWEP_EXCLUDEUNENCRYPTED)
- erq->flags |= IW_ENCODE_RESTRICTED;
- else
- erq->flags |= IW_ENCODE_OPEN;
-
- i = (erq->flags & IW_ENCODE_INDEX) - 1;
-
- if (i == -1)
- i = wlandev->hostwep & HOSTWEP_DEFAULTKEY_MASK;
-
- if ((i < 0) || (i >= NUM_WEPKEYS)) {
- err = -EINVAL;
- goto exit;
- }
-
- erq->flags |= i + 1;
-
- /* copy the key from the driver cache as the keys are read-only MIBs */
- erq->length = wlandev->wep_keylens[i];
- memcpy(key, wlandev->wep_keys[i], erq->length);
-
-exit:
- return err;
-}
-
-static int p80211wext_siwencode(netdevice_t *dev,
- struct iw_request_info *info,
- struct iw_point *erq, char *key)
-{
- wlandevice_t *wlandev = dev->ml_priv;
- p80211msg_dot11req_mibset_t msg;
- p80211item_pstr32_t pstr;
-
- int err = 0;
- int result = 0;
- int i;
-
- if (!wlan_wext_write) {
- err = (-EOPNOTSUPP);
- goto exit;
- }
-
- /* Check the Key index first. */
- i = (erq->flags & IW_ENCODE_INDEX);
- if (i) {
- if ((i < 1) || (i > NUM_WEPKEYS)) {
- err = -EINVAL;
- goto exit;
- } else {
- i--;
- }
- /* Set current key number only if no keys are given */
- if (erq->flags & IW_ENCODE_NOKEY) {
- result =
- p80211wext_setmib(wlandev,
- DIDmib_dot11smt_dot11PrivacyTable_dot11WEPDefaultKeyID,
- i);
-
- if (result) {
- err = -EFAULT;
- goto exit;
- }
- }
-
- } else {
- /* Use defaultkey if no Key Index */
- i = wlandev->hostwep & HOSTWEP_DEFAULTKEY_MASK;
- }
-
- /* Check if there is no key information in the iwconfig request */
- if ((erq->flags & IW_ENCODE_NOKEY) == 0) {
-
- /*------------------------------------------------------------
- * If there is WEP Key for setting, check the Key Information
- * and then set it to the firmware.
- -------------------------------------------------------------*/
-
- if (erq->length > 0) {
- /* copy the key from the driver cache as the keys are read-only MIBs */
- wlandev->wep_keylens[i] = erq->length;
- memcpy(wlandev->wep_keys[i], key, erq->length);
-
- /* Prepare data struture for p80211req_dorequest. */
- memcpy(pstr.data.data, key, erq->length);
- pstr.data.len = erq->length;
-
- switch (i) {
- case 0:
- pstr.did =
- DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey0;
- break;
-
- case 1:
- pstr.did =
- DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey1;
- break;
-
- case 2:
- pstr.did =
- DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey2;
- break;
-
- case 3:
- pstr.did =
- DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey3;
- break;
-
- default:
- err = -EINVAL;
- goto exit;
- }
-
- msg.msgcode = DIDmsg_dot11req_mibset;
- memcpy(&msg.mibattribute.data, &pstr, sizeof(pstr));
- result = p80211req_dorequest(wlandev, (u8 *) &msg);
-
- if (result) {
- err = -EFAULT;
- goto exit;
- }
- }
-
- }
-
- /* Check the PrivacyInvoked flag */
- if (erq->flags & IW_ENCODE_DISABLED) {
- result =
- p80211wext_setmib(wlandev,
- DIDmib_dot11smt_dot11PrivacyTable_dot11PrivacyInvoked,
- P80211ENUM_truth_false);
- } else {
- result =
- p80211wext_setmib(wlandev,
- DIDmib_dot11smt_dot11PrivacyTable_dot11PrivacyInvoked,
- P80211ENUM_truth_true);
- }
-
- if (result) {
- err = -EFAULT;
- goto exit;
- }
-
- /* The security mode may be open or restricted, and its meaning
- depends on the card used. With most cards, in open mode no
- authentication is used and the card may also accept non-
- encrypted sessions, whereas in restricted mode only encrypted
- sessions are accepted and the card will use authentication if
- available.
- */
- if (erq->flags & IW_ENCODE_RESTRICTED) {
- result =
- p80211wext_setmib(wlandev,
- DIDmib_dot11smt_dot11PrivacyTable_dot11ExcludeUnencrypted,
- P80211ENUM_truth_true);
- } else if (erq->flags & IW_ENCODE_OPEN) {
- result =
- p80211wext_setmib(wlandev,
- DIDmib_dot11smt_dot11PrivacyTable_dot11ExcludeUnencrypted,
- P80211ENUM_truth_false);
- }
-
- if (result) {
- err = -EFAULT;
- goto exit;
- }
-
-exit:
-
- return err;
-}
-
-static int p80211wext_giwessid(netdevice_t *dev,
- struct iw_request_info *info,
- struct iw_point *data, char *essid)
-{
- wlandevice_t *wlandev = dev->ml_priv;
-
- if (wlandev->ssid.len) {
- data->length = wlandev->ssid.len;
- data->flags = 1;
- memcpy(essid, wlandev->ssid.data, data->length);
- essid[data->length] = 0;
- } else {
- memset(essid, 0, sizeof(wlandev->ssid.data));
- data->length = 0;
- data->flags = 0;
- }
-
- return 0;
-}
-
-static int p80211wext_siwessid(netdevice_t *dev,
- struct iw_request_info *info,
- struct iw_point *data, char *essid)
-{
- wlandevice_t *wlandev = dev->ml_priv;
- p80211msg_lnxreq_autojoin_t msg;
-
- int result;
- int err = 0;
- int length = data->length;
-
- if (!wlan_wext_write) {
- err = (-EOPNOTSUPP);
- goto exit;
- }
-
- if (wlandev->hostwep & HOSTWEP_SHAREDKEY)
- msg.authtype.data = P80211ENUM_authalg_sharedkey;
- else
- msg.authtype.data = P80211ENUM_authalg_opensystem;
-
- msg.msgcode = DIDmsg_lnxreq_autojoin;
-
- /* Trim the last '\0' to fit the SSID format */
- if (length && essid[length - 1] == '\0')
- length--;
-
- memcpy(msg.ssid.data.data, essid, length);
- msg.ssid.data.len = length;
-
- pr_debug("autojoin_ssid for %s \n", essid);
- result = p80211req_dorequest(wlandev, (u8 *) &msg);
- pr_debug("autojoin_ssid %d\n", result);
-
- if (result) {
- err = -EFAULT;
- goto exit;
- }
-
-exit:
- return err;
-}
-
-static int p80211wext_siwcommit(netdevice_t *dev,
- struct iw_request_info *info,
- struct iw_point *data, char *essid)
-{
- wlandevice_t *wlandev = dev->ml_priv;
- int err = 0;
-
- if (!wlan_wext_write) {
- err = (-EOPNOTSUPP);
- goto exit;
- }
-
- /* Auto Join */
- err = p80211wext_autojoin(wlandev);
-
-exit:
- return err;
-}
-
-static int p80211wext_giwrate(netdevice_t *dev,
- struct iw_request_info *info,
- struct iw_param *rrq, char *extra)
-{
- wlandevice_t *wlandev = dev->ml_priv;
- int result;
- int err = 0;
- unsigned int value;
-
- result = p80211wext_getmib(wlandev, DIDmib_p2_p2MAC_p2CurrentTxRate, &value);
- if (result) {
- err = -EFAULT;
- goto exit;
- }
-
- rrq->fixed = 0; /* can it change? */
- rrq->disabled = 0;
- rrq->value = 0;
-
-#define HFA384x_RATEBIT_1 ((u16)1)
-#define HFA384x_RATEBIT_2 ((u16)2)
-#define HFA384x_RATEBIT_5dot5 ((u16)4)
-#define HFA384x_RATEBIT_11 ((u16)8)
-
- switch (value) {
- case HFA384x_RATEBIT_1:
- rrq->value = 1000000;
- break;
- case HFA384x_RATEBIT_2:
- rrq->value = 2000000;
- break;
- case HFA384x_RATEBIT_5dot5:
- rrq->value = 5500000;
- break;
- case HFA384x_RATEBIT_11:
- rrq->value = 11000000;
- break;
- default:
- err = -EINVAL;
- }
-exit:
- return err;
-}
-
-static int p80211wext_giwrts(netdevice_t *dev,
- struct iw_request_info *info,
- struct iw_param *rts, char *extra)
-{
- wlandevice_t *wlandev = dev->ml_priv;
- int result;
- int err = 0;
- unsigned int value;
-
- result = p80211wext_getmib(wlandev,
- DIDmib_dot11mac_dot11OperationTable_dot11RTSThreshold,
- &value);
- if (result) {
- err = -EFAULT;
- goto exit;
- }
-
- rts->value = value;
- rts->disabled = (rts->value == 2347);
- rts->fixed = 1;
-
-exit:
- return err;
-}
-
-static int p80211wext_siwrts(netdevice_t *dev,
- struct iw_request_info *info,
- struct iw_param *rts, char *extra)
-{
- wlandevice_t *wlandev = dev->ml_priv;
- int result;
- int err = 0;
- unsigned int value;
-
- if (!wlan_wext_write) {
- err = -EOPNOTSUPP;
- goto exit;
- }
-
- if (rts->disabled)
- value = 2347;
- else
- value = rts->value;
-
- result = p80211wext_setmib(wlandev,
- DIDmib_dot11mac_dot11OperationTable_dot11RTSThreshold,
- value);
- if (result) {
- err = -EFAULT;
- goto exit;
- }
-
-exit:
- return err;
-}
-
-static int p80211wext_giwfrag(netdevice_t *dev,
- struct iw_request_info *info,
- struct iw_param *frag, char *extra)
-{
- wlandevice_t *wlandev = dev->ml_priv;
- int result;
- int err = 0;
- unsigned int value;
-
- result = p80211wext_getmib(wlandev,
- DIDmib_dot11mac_dot11OperationTable_dot11FragmentationThreshold,
- &value);
- if (result) {
- err = -EFAULT;
- goto exit;
- }
-
- frag->value = value;
- frag->disabled = (frag->value == 2346);
- frag->fixed = 1;
-
-exit:
- return err;
-}
-
-static int p80211wext_siwfrag(netdevice_t *dev,
- struct iw_request_info *info,
- struct iw_param *frag, char *extra)
-{
- wlandevice_t *wlandev = dev->ml_priv;
- int result;
- int err = 0;
- int value;
-
- if (!wlan_wext_write) {
- err = (-EOPNOTSUPP);
- goto exit;
- }
-
- if (frag->disabled)
- value = 2346;
- else
- value = frag->value;
-
- result = p80211wext_setmib(wlandev,
- DIDmib_dot11mac_dot11OperationTable_dot11FragmentationThreshold,
- value);
-
- if (result) {
- err = -EFAULT;
- goto exit;
- }
-
-exit:
- return err;
-}
-
-#ifndef IW_RETRY_LONG
-#define IW_RETRY_LONG IW_RETRY_MAX
-#endif
-
-#ifndef IW_RETRY_SHORT
-#define IW_RETRY_SHORT IW_RETRY_MIN
-#endif
-
-static int p80211wext_giwretry(netdevice_t *dev,
- struct iw_request_info *info,
- struct iw_param *rrq, char *extra)
-{
- wlandevice_t *wlandev = dev->ml_priv;
- int result;
- int err = 0;
- u16 shortretry, longretry, lifetime;
- unsigned int value;
-
- result = p80211wext_getmib(wlandev,
- DIDmib_dot11mac_dot11OperationTable_dot11ShortRetryLimit,
- &value);
- if (result) {
- err = -EFAULT;
- goto exit;
- }
-
- shortretry = value;
-
- result = p80211wext_getmib(wlandev,
- DIDmib_dot11mac_dot11OperationTable_dot11LongRetryLimit,
- &value);
- if (result) {
- err = -EFAULT;
- goto exit;
- }
-
- longretry = value;
-
- result = p80211wext_getmib(wlandev,
- DIDmib_dot11mac_dot11OperationTable_dot11MaxTransmitMSDULifetime,
- &value);
- if (result) {
- err = -EFAULT;
- goto exit;
- }
-
- lifetime = value;
-
- rrq->disabled = 0;
-
- if ((rrq->flags & IW_RETRY_TYPE) == IW_RETRY_LIFETIME) {
- rrq->flags = IW_RETRY_LIFETIME;
- rrq->value = lifetime * 1024;
- } else {
- if (rrq->flags & IW_RETRY_LONG) {
- rrq->flags = IW_RETRY_LIMIT | IW_RETRY_LONG;
- rrq->value = longretry;
- } else {
- rrq->flags = IW_RETRY_LIMIT;
- rrq->value = shortretry;
- if (shortretry != longretry)
- rrq->flags |= IW_RETRY_SHORT;
- }
- }
-
-exit:
- return err;
-
-}
-
-static int p80211wext_siwretry(netdevice_t *dev,
- struct iw_request_info *info,
- struct iw_param *rrq, char *extra)
-{
- wlandevice_t *wlandev = dev->ml_priv;
- p80211item_uint32_t mibitem;
- p80211msg_dot11req_mibset_t msg;
- int result;
- int err = 0;
- unsigned int value;
-
- if (!wlan_wext_write) {
- err = (-EOPNOTSUPP);
- goto exit;
- }
-
- if (rrq->disabled) {
- err = -EINVAL;
- goto exit;
- }
-
- msg.msgcode = DIDmsg_dot11req_mibset;
-
- if ((rrq->flags & IW_RETRY_TYPE) == IW_RETRY_LIFETIME) {
-
- value = rrq->value /= 1024;
- result = p80211wext_setmib(wlandev,
- DIDmib_dot11mac_dot11OperationTable_dot11MaxTransmitMSDULifetime,
- value);
- if (result) {
- err = -EFAULT;
- goto exit;
- }
- } else {
- if (rrq->flags & IW_RETRY_LONG) {
- result = p80211wext_setmib(wlandev,
- DIDmib_dot11mac_dot11OperationTable_dot11LongRetryLimit,
- rrq->value);
-
- if (result) {
- err = -EFAULT;
- goto exit;
- }
- }
-
- if (rrq->flags & IW_RETRY_SHORT) {
- result = p80211wext_setmib(wlandev,
- DIDmib_dot11mac_dot11OperationTable_dot11ShortRetryLimit,
- rrq->value);
-
- if (result) {
- err = -EFAULT;
- goto exit;
- }
- }
- }
-
-exit:
- return err;
-
-}
-
-static int p80211wext_siwtxpow(netdevice_t *dev,
- struct iw_request_info *info,
- struct iw_param *rrq, char *extra)
-{
- wlandevice_t *wlandev = dev->ml_priv;
- p80211item_uint32_t mibitem;
- p80211msg_dot11req_mibset_t msg;
- int result;
- int err = 0;
- unsigned int value;
-
- if (!wlan_wext_write) {
- err = (-EOPNOTSUPP);
- goto exit;
- }
-
- if (rrq->fixed == 0)
- value = 30;
- else
- value = rrq->value;
- result = p80211wext_setmib(wlandev,
- DIDmib_dot11phy_dot11PhyTxPowerTable_dot11CurrentTxPowerLevel,
- value);
-
- if (result) {
- err = -EFAULT;
- goto exit;
- }
-
-exit:
- return err;
-}
-
-static int p80211wext_giwtxpow(netdevice_t *dev,
- struct iw_request_info *info,
- struct iw_param *rrq, char *extra)
-{
- wlandevice_t *wlandev = dev->ml_priv;
- int result;
- int err = 0;
- unsigned int value;
-
- result = p80211wext_getmib(wlandev,
- DIDmib_dot11phy_dot11PhyTxPowerTable_dot11CurrentTxPowerLevel,
- &value);
-
- if (result) {
- err = -EFAULT;
- goto exit;
- }
-
- /* XXX handle OFF by setting disabled = 1; */
-
- rrq->flags = 0; /* IW_TXPOW_DBM; */
- rrq->disabled = 0;
- rrq->fixed = 0;
- rrq->value = value;
-
-exit:
- return err;
-}
-
-static int p80211wext_siwspy(netdevice_t *dev,
- struct iw_request_info *info,
- struct iw_point *srq, char *extra)
-{
- wlandevice_t *wlandev = dev->ml_priv;
- struct sockaddr address[IW_MAX_SPY];
- int number = srq->length;
- int i;
-
- /* Copy the data from the input buffer */
- memcpy(address, extra, sizeof(struct sockaddr) * number);
-
- wlandev->spy_number = 0;
-
- if (number > 0) {
-
- /* extract the addresses */
- for (i = 0; i < number; i++) {
-
- memcpy(wlandev->spy_address[i], address[i].sa_data,
- ETH_ALEN);
- }
-
- /* reset stats */
- memset(wlandev->spy_stat, 0,
- sizeof(struct iw_quality) * IW_MAX_SPY);
-
- /* set number of addresses */
- wlandev->spy_number = number;
- }
-
- return 0;
-}
-
-/* jkriegl: from orinoco, modified */
-static int p80211wext_giwspy(netdevice_t *dev,
- struct iw_request_info *info,
- struct iw_point *srq, char *extra)
-{
- wlandevice_t *wlandev = dev->ml_priv;
-
- struct sockaddr address[IW_MAX_SPY];
- struct iw_quality spy_stat[IW_MAX_SPY];
- int number;
- int i;
-
- number = wlandev->spy_number;
-
- if (number > 0) {
-
- /* populate address and spy struct's */
- for (i = 0; i < number; i++) {
- memcpy(address[i].sa_data, wlandev->spy_address[i],
- ETH_ALEN);
- address[i].sa_family = AF_UNIX;
- memcpy(&spy_stat[i], &wlandev->spy_stat[i],
- sizeof(struct iw_quality));
- }
-
- /* reset update flag */
- for (i = 0; i < number; i++)
- wlandev->spy_stat[i].updated = 0;
- }
-
- /* push stuff to user space */
- srq->length = number;
- memcpy(extra, address, sizeof(struct sockaddr) * number);
- memcpy(extra + sizeof(struct sockaddr) * number, spy_stat,
- sizeof(struct iw_quality) * number);
-
- return 0;
-}
-
-static int prism2_result2err(int prism2_result)
-{
- int err = 0;
-
- switch (prism2_result) {
- case P80211ENUM_resultcode_invalid_parameters:
- err = -EINVAL;
- break;
- case P80211ENUM_resultcode_implementation_failure:
- err = -EIO;
- break;
- case P80211ENUM_resultcode_not_supported:
- err = -EOPNOTSUPP;
- break;
- default:
- err = 0;
- break;
- }
-
- return err;
-}
-
-static int p80211wext_siwscan(netdevice_t *dev,
- struct iw_request_info *info,
- struct iw_point *srq, char *extra)
-{
- wlandevice_t *wlandev = dev->ml_priv;
- p80211msg_dot11req_scan_t msg;
- int result;
- int err = 0;
- int i = 0;
-
- if (wlandev->macmode == WLAN_MACMODE_ESS_AP) {
- printk(KERN_ERR "Can't scan in AP mode\n");
- err = (-EOPNOTSUPP);
- goto exit;
- }
-
- memset(&msg, 0x00, sizeof(p80211msg_dot11req_scan_t));
- msg.msgcode = DIDmsg_dot11req_scan;
- msg.bsstype.data = P80211ENUM_bsstype_any;
-
- memset(&(msg.bssid.data), 0xFF, sizeof(p80211item_pstr6_t));
- msg.bssid.data.len = 6;
-
- msg.scantype.data = P80211ENUM_scantype_active;
- msg.probedelay.data = 0;
-
- for (i = 1; i <= 14; i++)
- msg.channellist.data.data[i - 1] = i;
- msg.channellist.data.len = 14;
-
- msg.maxchanneltime.data = 250;
- msg.minchanneltime.data = 200;
-
- result = p80211req_dorequest(wlandev, (u8 *) &msg);
- if (result)
- err = prism2_result2err(msg.resultcode.data);
-
-exit:
- return err;
-}
-
-/* Helper to translate scan into Wireless Extensions scan results.
- * Inspired by the prism54 code, which was in turn inspired by the
- * airo driver code.
- */
-static char *wext_translate_bss(struct iw_request_info *info, char *current_ev,
- char *end_buf,
- p80211msg_dot11req_scan_results_t *bss)
-{
- struct iw_event iwe; /* Temporary buffer */
-
- /* The first entry must be the MAC address */
- memcpy(iwe.u.ap_addr.sa_data, bss->bssid.data.data, WLAN_BSSID_LEN);
- iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
- iwe.cmd = SIOCGIWAP;
- current_ev =
- iwe_stream_add_event(info, current_ev, end_buf, &iwe,
- IW_EV_ADDR_LEN);
-
- /* The following entries will be displayed in the same order we give them */
-
- /* The ESSID. */
- if (bss->ssid.data.len > 0) {
- char essid[IW_ESSID_MAX_SIZE + 1];
- int size;
-
- size =
- min_t(unsigned short, IW_ESSID_MAX_SIZE,
- bss->ssid.data.len);
- memset(&essid, 0, sizeof(essid));
- memcpy(&essid, bss->ssid.data.data, size);
- pr_debug(" essid size = %d\n", size);
- iwe.u.data.length = size;
- iwe.u.data.flags = 1;
- iwe.cmd = SIOCGIWESSID;
- current_ev =
- iwe_stream_add_point(info, current_ev, end_buf, &iwe,
- &essid[0]);
- pr_debug(" essid size OK.\n");
- }
-
- switch (bss->bsstype.data) {
- case P80211ENUM_bsstype_infrastructure:
- iwe.u.mode = IW_MODE_MASTER;
- break;
-
- case P80211ENUM_bsstype_independent:
- iwe.u.mode = IW_MODE_ADHOC;
- break;
-
- default:
- iwe.u.mode = 0;
- break;
- }
- iwe.cmd = SIOCGIWMODE;
- if (iwe.u.mode)
- current_ev =
- iwe_stream_add_event(info, current_ev, end_buf, &iwe,
- IW_EV_UINT_LEN);
-
- /* Encryption capability */
- if (bss->privacy.data == P80211ENUM_truth_true)
- iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
- else
- iwe.u.data.flags = IW_ENCODE_DISABLED;
- iwe.u.data.length = 0;
- iwe.cmd = SIOCGIWENCODE;
- current_ev =
- iwe_stream_add_point(info, current_ev, end_buf, &iwe, NULL);
-
- /* Add frequency. (short) bss->channel is the frequency in MHz */
- iwe.u.freq.m = bss->dschannel.data;
- iwe.u.freq.e = 0;
- iwe.cmd = SIOCGIWFREQ;
- current_ev =
- iwe_stream_add_event(info, current_ev, end_buf, &iwe,
- IW_EV_FREQ_LEN);
-
- /* Add quality statistics */
- iwe.u.qual.level = bss->signal.data;
- iwe.u.qual.noise = bss->noise.data;
- /* do a simple SNR for quality */
- iwe.u.qual.qual = qual_as_percent(bss->signal.data - bss->noise.data);
- iwe.cmd = IWEVQUAL;
- current_ev =
- iwe_stream_add_event(info, current_ev, end_buf, &iwe,
- IW_EV_QUAL_LEN);
-
- return current_ev;
-}
-
-static int p80211wext_giwscan(netdevice_t *dev,
- struct iw_request_info *info,
- struct iw_point *srq, char *extra)
-{
- wlandevice_t *wlandev = dev->ml_priv;
- p80211msg_dot11req_scan_results_t msg;
- int result = 0;
- int err = 0;
- int i = 0;
- int scan_good = 0;
- char *current_ev = extra;
-
- /* Since wireless tools doesn't really have a way of passing how
- * many scan results results there were back here, keep grabbing them
- * until we fail.
- */
- do {
- memset(&msg, 0, sizeof(msg));
- msg.msgcode = DIDmsg_dot11req_scan_results;
- msg.bssindex.data = i;
-
- result = p80211req_dorequest(wlandev, (u8 *) &msg);
- if ((result != 0) ||
- (msg.resultcode.data != P80211ENUM_resultcode_success)) {
- break;
- }
-
- current_ev =
- wext_translate_bss(info, current_ev,
- extra + IW_SCAN_MAX_DATA, &msg);
- scan_good = 1;
- i++;
- } while (i < IW_MAX_AP);
-
- srq->length = (current_ev - extra);
- srq->flags = 0; /* todo */
-
- if (result && !scan_good)
- err = prism2_result2err(msg.resultcode.data);
-
- return err;
-}
-
-/* extra wireless extensions stuff to support NetworkManager (I hope) */
-
-/* SIOCSIWENCODEEXT */
-static int p80211wext_set_encodeext(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- wlandevice_t *wlandev = dev->ml_priv;
- struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
- p80211msg_dot11req_mibset_t msg;
- p80211item_pstr32_t *pstr;
-
- int result = 0;
- struct iw_point *encoding = &wrqu->encoding;
- int idx = encoding->flags & IW_ENCODE_INDEX;
-
- pr_debug("set_encode_ext flags[%d] alg[%d] keylen[%d]\n",
- ext->ext_flags, (int)ext->alg, (int)ext->key_len);
-
- if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) {
- /* set default key ? I'm not sure if this the the correct thing to do here */
-
- if (idx) {
- if (idx < 1 || idx > NUM_WEPKEYS)
- return -EINVAL;
- else
- idx--;
- }
- pr_debug("setting default key (%d)\n", idx);
- result =
- p80211wext_setmib(wlandev,
- DIDmib_dot11smt_dot11PrivacyTable_dot11WEPDefaultKeyID,
- idx);
- if (result)
- return -EFAULT;
- }
-
- if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) {
- if (ext->alg != IW_ENCODE_ALG_WEP) {
- pr_debug("asked to set a non wep key :(\n");
- return -EINVAL;
- }
- if (idx) {
- if (idx < 1 || idx > NUM_WEPKEYS)
- return -EINVAL;
- else
- idx--;
- }
- pr_debug("Set WEP key (%d)\n", idx);
- wlandev->wep_keylens[idx] = ext->key_len;
- memcpy(wlandev->wep_keys[idx], ext->key, ext->key_len);
-
- memset(&msg, 0, sizeof(msg));
- pstr = (p80211item_pstr32_t *) &msg.mibattribute.data;
- memcpy(pstr->data.data, ext->key, ext->key_len);
- pstr->data.len = ext->key_len;
- switch (idx) {
- case 0:
- pstr->did =
- DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey0;
- break;
- case 1:
- pstr->did =
- DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey1;
- break;
- case 2:
- pstr->did =
- DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey2;
- break;
- case 3:
- pstr->did =
- DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey3;
- break;
- default:
- break;
- }
- msg.msgcode = DIDmsg_dot11req_mibset;
- result = p80211req_dorequest(wlandev, (u8 *) &msg);
- pr_debug("result (%d)\n", result);
- }
- return result;
-}
-
-/* SIOCGIWENCODEEXT */
-static int p80211wext_get_encodeext(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- wlandevice_t *wlandev = dev->ml_priv;
- struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
-
- struct iw_point *encoding = &wrqu->encoding;
- int result = 0;
- int max_len;
- int idx;
-
- pr_debug("get_encode_ext flags[%d] alg[%d] keylen[%d]\n",
- ext->ext_flags, (int)ext->alg, (int)ext->key_len);
-
- max_len = encoding->length - sizeof(*ext);
- if (max_len <= 0) {
- pr_debug("get_encodeext max_len [%d] invalid\n", max_len);
- result = -EINVAL;
- goto exit;
- }
- idx = encoding->flags & IW_ENCODE_INDEX;
-
- pr_debug("get_encode_ext index [%d]\n", idx);
-
- if (idx) {
- if (idx < 1 || idx > NUM_WEPKEYS) {
- pr_debug("get_encode_ext invalid key index [%d]\n",
- idx);
- result = -EINVAL;
- goto exit;
- }
- idx--;
- } else {
- /* default key ? not sure what to do */
- /* will just use key[0] for now ! FIX ME */
- }
-
- encoding->flags = idx + 1;
- memset(ext, 0, sizeof(*ext));
-
- ext->alg = IW_ENCODE_ALG_WEP;
- ext->key_len = wlandev->wep_keylens[idx];
- memcpy(ext->key, wlandev->wep_keys[idx], ext->key_len);
-
- encoding->flags |= IW_ENCODE_ENABLED;
-exit:
- return result;
-}
-
-/* SIOCSIWAUTH */
-static int p80211_wext_set_iwauth(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- wlandevice_t *wlandev = dev->ml_priv;
- struct iw_param *param = &wrqu->param;
- int result = 0;
-
- pr_debug("set_iwauth flags[%d]\n", (int)param->flags & IW_AUTH_INDEX);
-
- switch (param->flags & IW_AUTH_INDEX) {
- case IW_AUTH_DROP_UNENCRYPTED:
- pr_debug("drop_unencrypted %d\n", param->value);
- if (param->value)
- result =
- p80211wext_setmib(wlandev,
- DIDmib_dot11smt_dot11PrivacyTable_dot11ExcludeUnencrypted,
- P80211ENUM_truth_true);
- else
- result =
- p80211wext_setmib(wlandev,
- DIDmib_dot11smt_dot11PrivacyTable_dot11ExcludeUnencrypted,
- P80211ENUM_truth_false);
- break;
-
- case IW_AUTH_PRIVACY_INVOKED:
- pr_debug("privacy invoked %d\n", param->value);
- if (param->value)
- result =
- p80211wext_setmib(wlandev,
- DIDmib_dot11smt_dot11PrivacyTable_dot11PrivacyInvoked,
- P80211ENUM_truth_true);
- else
- result =
- p80211wext_setmib(wlandev,
- DIDmib_dot11smt_dot11PrivacyTable_dot11PrivacyInvoked,
- P80211ENUM_truth_false);
-
- break;
-
- case IW_AUTH_80211_AUTH_ALG:
- if (param->value & IW_AUTH_ALG_OPEN_SYSTEM) {
- pr_debug("set open_system\n");
- wlandev->hostwep &= ~HOSTWEP_SHAREDKEY;
- } else if (param->value & IW_AUTH_ALG_SHARED_KEY) {
- pr_debug("set shared key\n");
- wlandev->hostwep |= HOSTWEP_SHAREDKEY;
- } else {
- /* don't know what to do know */
- pr_debug("unknown AUTH_ALG (%d)\n", param->value);
- result = -EINVAL;
- }
- break;
-
- default:
- break;
- }
-
- return result;
-}
-
-/* SIOCSIWAUTH */
-static int p80211_wext_get_iwauth(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- wlandevice_t *wlandev = dev->ml_priv;
- struct iw_param *param = &wrqu->param;
- int result = 0;
-
- pr_debug("get_iwauth flags[%d]\n", (int)param->flags & IW_AUTH_INDEX);
-
- switch (param->flags & IW_AUTH_INDEX) {
- case IW_AUTH_DROP_UNENCRYPTED:
- param->value =
- wlandev->hostwep & HOSTWEP_EXCLUDEUNENCRYPTED ? 1 : 0;
- break;
-
- case IW_AUTH_PRIVACY_INVOKED:
- param->value =
- wlandev->hostwep & HOSTWEP_PRIVACYINVOKED ? 1 : 0;
- break;
-
- case IW_AUTH_80211_AUTH_ALG:
- param->value =
- wlandev->hostwep & HOSTWEP_SHAREDKEY ?
- IW_AUTH_ALG_SHARED_KEY : IW_AUTH_ALG_OPEN_SYSTEM;
- break;
-
- default:
- break;
- }
-
- return result;
-}
-
-#define IW_IOCTL(x) [(x)-SIOCSIWCOMMIT]
-
-static iw_handler p80211wext_handlers[] = {
- IW_IOCTL(SIOCSIWCOMMIT) = (iw_handler) p80211wext_siwcommit,
- IW_IOCTL(SIOCGIWNAME) = (iw_handler) p80211wext_giwname,
-/* SIOCSIWNWID,SIOCGIWNWID */
- IW_IOCTL(SIOCSIWFREQ) = (iw_handler) p80211wext_siwfreq,
- IW_IOCTL(SIOCGIWFREQ) = (iw_handler) p80211wext_giwfreq,
- IW_IOCTL(SIOCSIWMODE) = (iw_handler) p80211wext_siwmode,
- IW_IOCTL(SIOCGIWMODE) = (iw_handler) p80211wext_giwmode,
-/* SIOCSIWSENS,SIOCGIWSENS,SIOCSIWRANGE */
- IW_IOCTL(SIOCGIWRANGE) = (iw_handler) p80211wext_giwrange,
-/* SIOCSIWPRIV,SIOCGIWPRIV,SIOCSIWSTATS,SIOCGIWSTATS */
- IW_IOCTL(SIOCSIWSPY) = (iw_handler) p80211wext_siwspy,
- IW_IOCTL(SIOCGIWSPY) = (iw_handler) p80211wext_giwspy,
-/* SIOCSIWAP */
- IW_IOCTL(SIOCGIWAP) = (iw_handler) p80211wext_giwap,
-/* SIOCGIWAPLIST */
- IW_IOCTL(SIOCSIWSCAN) = (iw_handler) p80211wext_siwscan,
- IW_IOCTL(SIOCGIWSCAN) = (iw_handler) p80211wext_giwscan,
- IW_IOCTL(SIOCSIWESSID) = (iw_handler) p80211wext_siwessid,
- IW_IOCTL(SIOCGIWESSID) = (iw_handler) p80211wext_giwessid,
-/* SIOCSIWNICKN */
- IW_IOCTL(SIOCGIWNICKN) = (iw_handler) p80211wext_giwessid,
-/* SIOCSIWRATE */
- IW_IOCTL(SIOCGIWRATE) = (iw_handler) p80211wext_giwrate,
- IW_IOCTL(SIOCSIWRTS) = (iw_handler) p80211wext_siwrts,
- IW_IOCTL(SIOCGIWRTS) = (iw_handler) p80211wext_giwrts,
- IW_IOCTL(SIOCSIWFRAG) = (iw_handler) p80211wext_siwfrag,
- IW_IOCTL(SIOCGIWFRAG) = (iw_handler) p80211wext_giwfrag,
- IW_IOCTL(SIOCSIWTXPOW) = (iw_handler) p80211wext_siwtxpow,
- IW_IOCTL(SIOCGIWTXPOW) = (iw_handler) p80211wext_giwtxpow,
- IW_IOCTL(SIOCSIWRETRY) = (iw_handler) p80211wext_siwretry,
- IW_IOCTL(SIOCGIWRETRY) = (iw_handler) p80211wext_giwretry,
- IW_IOCTL(SIOCSIWENCODE) = (iw_handler) p80211wext_siwencode,
- IW_IOCTL(SIOCGIWENCODE) = (iw_handler) p80211wext_giwencode,
-/* SIOCSIWPOWER,SIOCGIWPOWER */
-/* WPA operations */
-/* SIOCSIWGENIE,SIOCGIWGENIE generic IE */
- IW_IOCTL(SIOCSIWAUTH) = (iw_handler) p80211_wext_set_iwauth, /*set authentication mode params */
- IW_IOCTL(SIOCGIWAUTH) = (iw_handler) p80211_wext_get_iwauth, /*get authentication mode params */
- IW_IOCTL(SIOCSIWENCODEEXT) = (iw_handler) p80211wext_set_encodeext, /*set encoding token & mode */
- IW_IOCTL(SIOCGIWENCODEEXT) = (iw_handler) p80211wext_get_encodeext, /*get encoding token & mode */
-/* SIOCSIWPMKSA PMKSA cache operation */
-};
-
-struct iw_handler_def p80211wext_handler_def = {
- .num_standard = ARRAY_SIZE(p80211wext_handlers),
- .standard = p80211wext_handlers,
- .get_wireless_stats = p80211wext_get_wireless_stats
-};
-
-int p80211wext_event_associated(wlandevice_t *wlandev, int assoc)
-{
- union iwreq_data data;
-
- /* Send the association state first */
- data.ap_addr.sa_family = ARPHRD_ETHER;
- if (assoc)
- memcpy(data.ap_addr.sa_data, wlandev->bssid, ETH_ALEN);
- else
- memset(data.ap_addr.sa_data, 0, ETH_ALEN);
-
- if (wlan_wext_write)
- wireless_send_event(wlandev->netdev, SIOCGIWAP, &data, NULL);
-
- if (!assoc)
- goto done;
-
- /* XXX send association data, like IEs, etc etc. */
-
-done:
- return 0;
-}
diff --git a/drivers/staging/wlan-ng/prism2fw.c b/drivers/staging/wlan-ng/prism2fw.c
index d20c8797bcc..fd5ddb29436 100644
--- a/drivers/staging/wlan-ng/prism2fw.c
+++ b/drivers/staging/wlan-ng/prism2fw.c
@@ -73,26 +73,26 @@ MODULE_FIRMWARE(PRISM2_USB_FWFILE);
/*================================================================*/
/* Local Types */
-typedef struct s3datarec {
+struct s3datarec {
u32 len;
u32 addr;
u8 checksum;
u8 *data;
-} s3datarec_t;
+};
-typedef struct s3plugrec {
+struct s3plugrec {
u32 itemcode;
u32 addr;
u32 len;
-} s3plugrec_t;
+};
-typedef struct s3crcrec {
+struct s3crcrec {
u32 addr;
u32 len;
unsigned int dowrite;
-} s3crcrec_t;
+};
-typedef struct s3inforec {
+struct s3inforec {
u16 len;
u16 type;
union {
@@ -101,20 +101,20 @@ typedef struct s3inforec {
u16 buildseq;
hfa384x_compident_t platform;
} info;
-} s3inforec_t;
+};
-typedef struct pda {
+struct pda {
u8 buf[HFA384x_PDA_LEN_MAX];
hfa384x_pdrec_t *rec[HFA384x_PDA_RECS_MAX];
unsigned int nrec;
-} pda_t;
+};
-typedef struct imgchunk {
+struct imgchunk {
u32 addr; /* start address */
u32 len; /* in bytes */
u16 crc; /* CRC value (if it falls at a chunk boundary) */
u8 *data;
-} imgchunk_t;
+};
/*================================================================*/
/* Local Static Definitions */
@@ -124,26 +124,26 @@ typedef struct imgchunk {
/* Data records */
unsigned int ns3data;
-s3datarec_t s3data[S3DATA_MAX];
+struct s3datarec s3data[S3DATA_MAX];
/* Plug records */
unsigned int ns3plug;
-s3plugrec_t s3plug[S3PLUG_MAX];
+struct s3plugrec s3plug[S3PLUG_MAX];
/* CRC records */
unsigned int ns3crc;
-s3crcrec_t s3crc[S3CRC_MAX];
+struct s3crcrec s3crc[S3CRC_MAX];
/* Info records */
unsigned int ns3info;
-s3inforec_t s3info[S3INFO_MAX];
+struct s3inforec s3info[S3INFO_MAX];
/* S7 record (there _better_ be only one) */
u32 startaddr;
/* Load image chunks */
unsigned int nfchunks;
-imgchunk_t fchunk[CHUNKS_MAX];
+struct imgchunk fchunk[CHUNKS_MAX];
/* Note that for the following pdrec_t arrays, the len and code */
/* fields are stored in HOST byte order. The mkpdrlist() function */
@@ -151,7 +151,7 @@ imgchunk_t fchunk[CHUNKS_MAX];
/*----------------------------------------------------------------*/
/* PDA, built from [card|newfile]+[addfile1+addfile2...] */
-pda_t pda;
+struct pda pda;
hfa384x_compident_t nicid;
hfa384x_caplevel_t rfid;
hfa384x_caplevel_t macid;
@@ -165,21 +165,21 @@ wlandevice_t *wlandev);
static int read_fwfile(const struct ihex_binrec *rfptr);
-static int mkimage(imgchunk_t *clist, unsigned int *ccnt);
+static int mkimage(struct imgchunk *clist, unsigned int *ccnt);
-static int read_cardpda(pda_t *pda, wlandevice_t *wlandev);
+static int read_cardpda(struct pda *pda, wlandevice_t *wlandev);
-static int mkpdrlist(pda_t *pda);
+static int mkpdrlist(struct pda *pda);
-static int plugimage(imgchunk_t *fchunk, unsigned int nfchunks,
- s3plugrec_t *s3plug, unsigned int ns3plug, pda_t * pda);
+static int plugimage(struct imgchunk *fchunk, unsigned int nfchunks,
+ struct s3plugrec *s3plug, unsigned int ns3plug, struct pda * pda);
-static int crcimage(imgchunk_t *fchunk, unsigned int nfchunks,
- s3crcrec_t *s3crc, unsigned int ns3crc);
+static int crcimage(struct imgchunk *fchunk, unsigned int nfchunks,
+ struct s3crcrec *s3crc, unsigned int ns3crc);
-static int writeimage(wlandevice_t *wlandev, imgchunk_t *fchunk,
+static int writeimage(wlandevice_t *wlandev, struct imgchunk *fchunk,
unsigned int nfchunks);
-static void free_chunks(imgchunk_t *fchunk, unsigned int *nfchunks);
+static void free_chunks(struct imgchunk *fchunk, unsigned int *nfchunks);
static void free_srecs(void);
@@ -239,7 +239,7 @@ int prism2_fwtry(struct usb_device *udev, wlandevice_t *wlandev)
int prism2_fwapply(const struct ihex_binrec *rfptr, wlandevice_t *wlandev)
{
signed int result = 0;
- p80211msg_dot11req_mibget_t getmsg;
+ struct p80211msg_dot11req_mibget getmsg;
p80211itemd_t *item;
u32 *data;
@@ -375,8 +375,8 @@ int prism2_fwapply(const struct ihex_binrec *rfptr, wlandevice_t *wlandev)
* 0 success
* ~0 failure
----------------------------------------------------------------*/
-int crcimage(imgchunk_t *fchunk, unsigned int nfchunks, s3crcrec_t *s3crc,
- unsigned int ns3crc)
+int crcimage(struct imgchunk *fchunk, unsigned int nfchunks,
+ struct s3crcrec *s3crc, unsigned int ns3crc)
{
int result = 0;
int i;
@@ -397,15 +397,14 @@ int crcimage(imgchunk_t *fchunk, unsigned int nfchunks, s3crcrec_t *s3crc,
for (c = 0; c < nfchunks; c++) {
cstart = fchunk[c].addr;
cend = fchunk[c].addr + fchunk[c].len;
- /* the line below does an address & len match search */
- /* unfortunately, I've found that the len fields of */
- /* some crc records don't match with the length of */
- /* the actual data, so we're not checking right */
- /* now */
- /* if ( crcstart-2 >= cstart && crcend <= cend ) break; */
+ /* the line below does an address & len match search */
+ /* unfortunately, I've found that the len fields of */
+ /* some crc records don't match with the length of */
+ /* the actual data, so we're not checking right now */
+ /* if (crcstart-2 >= cstart && crcend <= cend) break; */
/* note the -2 below, it's to make sure the chunk has */
- /* space for the CRC value */
+ /* space for the CRC value */
if (crcstart - 2 >= cstart && crcstart < cend)
break;
}
@@ -440,7 +439,7 @@ int crcimage(imgchunk_t *fchunk, unsigned int nfchunks, s3crcrec_t *s3crc,
* Returns:
* nothing
----------------------------------------------------------------*/
-void free_chunks(imgchunk_t *fchunk, unsigned int *nfchunks)
+void free_chunks(struct imgchunk *fchunk, unsigned int *nfchunks)
{
int i;
for (i = 0; i < *nfchunks; i++) {
@@ -490,7 +489,7 @@ void free_srecs(void)
* 0 - success
* ~0 - failure (probably an errno)
----------------------------------------------------------------*/
-int mkimage(imgchunk_t *clist, unsigned int *ccnt)
+int mkimage(struct imgchunk *clist, unsigned int *ccnt)
{
int result = 0;
int i;
@@ -583,7 +582,7 @@ int mkimage(imgchunk_t *clist, unsigned int *ccnt)
* 0 - success
* ~0 - failure (probably an errno)
----------------------------------------------------------------*/
-int mkpdrlist(pda_t *pda)
+int mkpdrlist(struct pda *pda)
{
int result = 0;
u16 *pda16 = (u16 *) pda->buf;
@@ -656,8 +655,8 @@ int mkpdrlist(pda_t *pda)
* 0 success
* ~0 failure
----------------------------------------------------------------*/
-int plugimage(imgchunk_t *fchunk, unsigned int nfchunks,
- s3plugrec_t *s3plug, unsigned int ns3plug, pda_t * pda)
+int plugimage(struct imgchunk *fchunk, unsigned int nfchunks,
+ struct s3plugrec *s3plug, unsigned int ns3plug, struct pda * pda)
{
int result = 0;
int i; /* plug index */
@@ -675,7 +674,7 @@ int plugimage(imgchunk_t *fchunk, unsigned int nfchunks,
pstart = s3plug[i].addr;
pend = s3plug[i].addr + s3plug[i].len;
/* find the matching PDR (or filename) */
- if (s3plug[i].itemcode != 0xffffffffUL) { /* not filename */
+ if (s3plug[i].itemcode != 0xffffffffUL) { /* not filename */
for (j = 0; j < pda->nrec; j++) {
if (s3plug[i].itemcode ==
le16_to_cpu(pda->rec[j]->code))
@@ -684,7 +683,7 @@ int plugimage(imgchunk_t *fchunk, unsigned int nfchunks,
} else {
j = -1;
}
- if (j >= pda->nrec && j != -1) { /* if no matching PDR, fail */
+ if (j >= pda->nrec && j != -1) { /* if no matching PDR, fail */
printk(KERN_WARNING
"warning: Failed to find PDR for "
"plugrec 0x%04x.\n", s3plug[i].itemcode);
@@ -764,10 +763,10 @@ int plugimage(imgchunk_t *fchunk, unsigned int nfchunks,
* 0 - success
* ~0 - failure (probably an errno)
----------------------------------------------------------------*/
-int read_cardpda(pda_t *pda, wlandevice_t *wlandev)
+int read_cardpda(struct pda *pda, wlandevice_t *wlandev)
{
int result = 0;
- p80211msg_p2req_readpda_t msg;
+ struct p80211msg_p2req_readpda msg;
/* set up the msg */
msg.msgcode = DIDmsg_p2req_readpda;
@@ -839,7 +838,7 @@ int read_cardpda(pda_t *pda, wlandevice_t *wlandev)
* ssssttttdd..dd
* s - Size in words (little endian)
* t - Info type (little endian), see #defines and
-* s3inforec_t for details about types.
+* struct s3inforec for details about types.
* d - (s - 1) little endian words giving the contents of
* the given info type.
*
@@ -978,13 +977,13 @@ int read_fwfile(const struct ihex_binrec *record)
* 0 success
* ~0 failure
----------------------------------------------------------------*/
-int writeimage(wlandevice_t *wlandev, imgchunk_t *fchunk,
+int writeimage(wlandevice_t *wlandev, struct imgchunk *fchunk,
unsigned int nfchunks)
{
int result = 0;
- p80211msg_p2req_ramdl_state_t rstatemsg;
- p80211msg_p2req_ramdl_write_t rwritemsg;
- p80211msg_t *msgp;
+ struct p80211msg_p2req_ramdl_state rstatemsg;
+ struct p80211msg_p2req_ramdl_write rwritemsg;
+ struct p80211msg *msgp;
u32 resultcode;
int i;
int j;
@@ -1030,7 +1029,7 @@ int writeimage(wlandevice_t *wlandev, imgchunk_t *fchunk,
rstatemsg.enable.data = P80211ENUM_truth_true;
rstatemsg.exeaddr.data = startaddr;
- msgp = (p80211msg_t *) &rstatemsg;
+ msgp = (struct p80211msg *) &rstatemsg;
result = prism2mgmt_ramdl_state(wlandev, msgp);
if (result) {
printk(KERN_ERR
@@ -1052,11 +1051,12 @@ int writeimage(wlandevice_t *wlandev, imgchunk_t *fchunk,
nwrites += (fchunk[i].len % WRITESIZE_MAX) ? 1 : 0;
curroff = 0;
for (j = 0; j < nwrites; j++) {
- currlen =
- (fchunk[i].len - (WRITESIZE_MAX * j)) >
- WRITESIZE_MAX ? WRITESIZE_MAX : (fchunk[i].len -
- (WRITESIZE_MAX *
- j));
+ /* TODO Move this to a separate function */
+ int lenleft = fchunk[i].len - (WRITESIZE_MAX * j);
+ if (fchunk[i].len > WRITESIZE_MAX)
+ currlen = WRITESIZE_MAX;
+ else
+ currlen = lenleft;
curroff = j * WRITESIZE_MAX;
currdaddr = fchunk[i].addr + curroff;
/* Setup the message */
@@ -1070,7 +1070,7 @@ int writeimage(wlandevice_t *wlandev, imgchunk_t *fchunk,
("Sending xxxdl_write message addr=%06x len=%d.\n",
currdaddr, currlen);
- msgp = (p80211msg_t *) &rwritemsg;
+ msgp = (struct p80211msg *) &rwritemsg;
result = prism2mgmt_ramdl_write(wlandev, msgp);
/* Check the results */
@@ -1097,7 +1097,7 @@ int writeimage(wlandevice_t *wlandev, imgchunk_t *fchunk,
rstatemsg.enable.data = P80211ENUM_truth_false;
rstatemsg.exeaddr.data = 0;
- msgp = (p80211msg_t *) &rstatemsg;
+ msgp = (struct p80211msg *) &rstatemsg;
result = prism2mgmt_ramdl_state(wlandev, msgp);
if (result) {
printk(KERN_ERR
diff --git a/drivers/staging/wlan-ng/prism2mgmt.c b/drivers/staging/wlan-ng/prism2mgmt.c
index 4d1cdfc3542..04514a85d10 100644
--- a/drivers/staging/wlan-ng/prism2mgmt.c
+++ b/drivers/staging/wlan-ng/prism2mgmt.c
@@ -117,7 +117,7 @@ int prism2mgmt_scan(wlandevice_t *wlandev, void *msgp)
{
int result = 0;
hfa384x_t *hw = wlandev->priv;
- p80211msg_dot11req_scan_t *msg = msgp;
+ struct p80211msg_dot11req_scan *msg = msgp;
u16 roamingmode, word;
int i, timeout;
int istmpenable = 0;
@@ -361,13 +361,13 @@ exit:
int prism2mgmt_scan_results(wlandevice_t *wlandev, void *msgp)
{
int result = 0;
- p80211msg_dot11req_scan_results_t *req;
+ struct p80211msg_dot11req_scan_results *req;
hfa384x_t *hw = wlandev->priv;
hfa384x_HScanResultSub_t *item = NULL;
int count;
- req = (p80211msg_dot11req_scan_results_t *) msgp;
+ req = (struct p80211msg_dot11req_scan_results *) msgp;
req->resultcode.status = P80211ENUM_msgitem_status_data_ok;
@@ -463,6 +463,8 @@ int prism2mgmt_scan_results(wlandevice_t *wlandev, void *msgp)
/* capinfo bits */
count = le16_to_cpu(item->capinfo);
+ req->capinfo.status = P80211ENUM_msgitem_status_data_ok;
+ req->capinfo.data = count;
/* privacy flag */
req->privacy.status = P80211ENUM_msgitem_status_data_ok;
@@ -511,7 +513,7 @@ int prism2mgmt_start(wlandevice_t *wlandev, void *msgp)
{
int result = 0;
hfa384x_t *hw = wlandev->priv;
- p80211msg_dot11req_start_t *msg = msgp;
+ struct p80211msg_dot11req_start *msg = msgp;
p80211pstrd_t *pstr;
u8 bytebuf[80];
@@ -687,7 +689,7 @@ done:
int prism2mgmt_readpda(wlandevice_t *wlandev, void *msgp)
{
hfa384x_t *hw = wlandev->priv;
- p80211msg_p2req_readpda_t *msg = msgp;
+ struct p80211msg_p2req_readpda *msg = msgp;
int result;
/* We only support collecting the PDA when in the FWLOAD
@@ -753,7 +755,7 @@ int prism2mgmt_readpda(wlandevice_t *wlandev, void *msgp)
int prism2mgmt_ramdl_state(wlandevice_t *wlandev, void *msgp)
{
hfa384x_t *hw = wlandev->priv;
- p80211msg_p2req_ramdl_state_t *msg = msgp;
+ struct p80211msg_p2req_ramdl_state *msg = msgp;
if (wlandev->msdstate != WLAN_MSD_FWLOAD) {
printk(KERN_ERR
@@ -809,7 +811,7 @@ int prism2mgmt_ramdl_state(wlandevice_t *wlandev, void *msgp)
int prism2mgmt_ramdl_write(wlandevice_t *wlandev, void *msgp)
{
hfa384x_t *hw = wlandev->priv;
- p80211msg_p2req_ramdl_write_t *msg = msgp;
+ struct p80211msg_p2req_ramdl_write *msg = msgp;
u32 addr;
u32 len;
u8 *buf;
@@ -872,7 +874,7 @@ int prism2mgmt_flashdl_state(wlandevice_t *wlandev, void *msgp)
{
int result = 0;
hfa384x_t *hw = wlandev->priv;
- p80211msg_p2req_flashdl_state_t *msg = msgp;
+ struct p80211msg_p2req_flashdl_state *msg = msgp;
if (wlandev->msdstate != WLAN_MSD_FWLOAD) {
printk(KERN_ERR
@@ -942,7 +944,7 @@ int prism2mgmt_flashdl_state(wlandevice_t *wlandev, void *msgp)
int prism2mgmt_flashdl_write(wlandevice_t *wlandev, void *msgp)
{
hfa384x_t *hw = wlandev->priv;
- p80211msg_p2req_flashdl_write_t *msg = msgp;
+ struct p80211msg_p2req_flashdl_write *msg = msgp;
u32 addr;
u32 len;
u8 *buf;
@@ -1006,7 +1008,7 @@ int prism2mgmt_autojoin(wlandevice_t *wlandev, void *msgp)
int result = 0;
u16 reg;
u16 port_type;
- p80211msg_lnxreq_autojoin_t *msg = msgp;
+ struct p80211msg_lnxreq_autojoin *msg = msgp;
p80211pstrd_t *pstr;
u8 bytebuf[256];
hfa384x_bytestr_t *p2bytestr = (hfa384x_bytestr_t *) bytebuf;
@@ -1074,7 +1076,7 @@ int prism2mgmt_autojoin(wlandevice_t *wlandev, void *msgp)
int prism2mgmt_wlansniff(wlandevice_t *wlandev, void *msgp)
{
int result = 0;
- p80211msg_lnxreq_wlansniff_t *msg = msgp;
+ struct p80211msg_lnxreq_wlansniff *msg = msgp;
hfa384x_t *hw = wlandev->priv;
u16 word;
diff --git a/drivers/staging/wlan-ng/prism2mib.c b/drivers/staging/wlan-ng/prism2mib.c
index 0b0ec9c59a5..d3a06fa0b4f 100644
--- a/drivers/staging/wlan-ng/prism2mib.c
+++ b/drivers/staging/wlan-ng/prism2mib.c
@@ -79,7 +79,7 @@
#define F_READ 0x2 /* MIB may be read. */
#define F_WRITE 0x4 /* MIB may be written. */
-typedef struct mibrec {
+struct mibrec {
u32 did;
u16 flag;
u16 parm1;
@@ -89,63 +89,63 @@ typedef struct mibrec {
int isget,
wlandevice_t *wlandev,
hfa384x_t *hw,
- p80211msg_dot11req_mibset_t *msg, void *data);
-} mibrec_t;
+ struct p80211msg_dot11req_mibset *msg, void *data);
+};
-static int prism2mib_bytearea2pstr(mibrec_t *mib,
+static int prism2mib_bytearea2pstr(struct mibrec *mib,
int isget,
wlandevice_t *wlandev,
hfa384x_t *hw,
- p80211msg_dot11req_mibset_t *msg,
+ struct p80211msg_dot11req_mibset *msg,
void *data);
-static int prism2mib_uint32(mibrec_t *mib,
+static int prism2mib_uint32(struct mibrec *mib,
int isget,
wlandevice_t *wlandev,
hfa384x_t *hw,
- p80211msg_dot11req_mibset_t *msg, void *data);
+ struct p80211msg_dot11req_mibset *msg, void *data);
-static int prism2mib_flag(mibrec_t *mib,
+static int prism2mib_flag(struct mibrec *mib,
int isget,
wlandevice_t *wlandev,
hfa384x_t *hw,
- p80211msg_dot11req_mibset_t *msg, void *data);
+ struct p80211msg_dot11req_mibset *msg, void *data);
-static int prism2mib_wepdefaultkey(mibrec_t *mib,
+static int prism2mib_wepdefaultkey(struct mibrec *mib,
int isget,
wlandevice_t *wlandev,
hfa384x_t *hw,
- p80211msg_dot11req_mibset_t *msg,
+ struct p80211msg_dot11req_mibset *msg,
void *data);
-static int prism2mib_privacyinvoked(mibrec_t *mib,
+static int prism2mib_privacyinvoked(struct mibrec *mib,
int isget,
wlandevice_t *wlandev,
hfa384x_t *hw,
- p80211msg_dot11req_mibset_t *msg,
+ struct p80211msg_dot11req_mibset *msg,
void *data);
-static int prism2mib_excludeunencrypted(mibrec_t *mib,
+static int prism2mib_excludeunencrypted(struct mibrec *mib,
int isget,
wlandevice_t *wlandev,
hfa384x_t *hw,
- p80211msg_dot11req_mibset_t *msg,
+ struct p80211msg_dot11req_mibset *msg,
void *data);
-static int prism2mib_fragmentationthreshold(mibrec_t *mib,
+static int prism2mib_fragmentationthreshold(struct mibrec *mib,
int isget,
wlandevice_t *wlandev,
hfa384x_t *hw,
- p80211msg_dot11req_mibset_t *msg,
+ struct p80211msg_dot11req_mibset *msg,
void *data);
-static int prism2mib_priv(mibrec_t *mib,
+static int prism2mib_priv(struct mibrec *mib,
int isget,
wlandevice_t *wlandev,
hfa384x_t *hw,
- p80211msg_dot11req_mibset_t *msg, void *data);
+ struct p80211msg_dot11req_mibset *msg, void *data);
-static mibrec_t mibtab[] = {
+static struct mibrec mibtab[] = {
/* dot11smt MIB's */
{DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey0,
@@ -261,11 +261,11 @@ int prism2mgmt_mibset_mibget(wlandevice_t *wlandev, void *msgp)
{
hfa384x_t *hw = wlandev->priv;
int result, isget;
- mibrec_t *mib;
+ struct mibrec *mib;
u16 which;
- p80211msg_dot11req_mibset_t *msg = msgp;
+ struct p80211msg_dot11req_mibset *msg = msgp;
p80211itemd_t *mibitem;
msg->resultcode.status = P80211ENUM_msgitem_status_data_ok;
@@ -371,11 +371,11 @@ done:
*
----------------------------------------------------------------*/
-static int prism2mib_bytearea2pstr(mibrec_t *mib,
+static int prism2mib_bytearea2pstr(struct mibrec *mib,
int isget,
wlandevice_t *wlandev,
hfa384x_t *hw,
- p80211msg_dot11req_mibset_t *msg,
+ struct p80211msg_dot11req_mibset *msg,
void *data)
{
int result;
@@ -421,11 +421,11 @@ static int prism2mib_bytearea2pstr(mibrec_t *mib,
*
----------------------------------------------------------------*/
-static int prism2mib_uint32(mibrec_t *mib,
+static int prism2mib_uint32(struct mibrec *mib,
int isget,
wlandevice_t *wlandev,
hfa384x_t *hw,
- p80211msg_dot11req_mibset_t *msg, void *data)
+ struct p80211msg_dot11req_mibset *msg, void *data)
{
int result;
u32 *uint32 = (u32 *) data;
@@ -468,11 +468,11 @@ static int prism2mib_uint32(mibrec_t *mib,
*
----------------------------------------------------------------*/
-static int prism2mib_flag(mibrec_t *mib,
+static int prism2mib_flag(struct mibrec *mib,
int isget,
wlandevice_t *wlandev,
hfa384x_t *hw,
- p80211msg_dot11req_mibset_t *msg, void *data)
+ struct p80211msg_dot11req_mibset *msg, void *data)
{
int result;
u32 *uint32 = (u32 *) data;
@@ -525,11 +525,11 @@ static int prism2mib_flag(mibrec_t *mib,
*
----------------------------------------------------------------*/
-static int prism2mib_wepdefaultkey(mibrec_t *mib,
+static int prism2mib_wepdefaultkey(struct mibrec *mib,
int isget,
wlandevice_t *wlandev,
hfa384x_t *hw,
- p80211msg_dot11req_mibset_t *msg,
+ struct p80211msg_dot11req_mibset *msg,
void *data)
{
int result;
@@ -575,11 +575,11 @@ static int prism2mib_wepdefaultkey(mibrec_t *mib,
*
----------------------------------------------------------------*/
-static int prism2mib_privacyinvoked(mibrec_t *mib,
+static int prism2mib_privacyinvoked(struct mibrec *mib,
int isget,
wlandevice_t *wlandev,
hfa384x_t *hw,
- p80211msg_dot11req_mibset_t *msg,
+ struct p80211msg_dot11req_mibset *msg,
void *data)
{
int result;
@@ -621,11 +621,11 @@ static int prism2mib_privacyinvoked(mibrec_t *mib,
*
----------------------------------------------------------------*/
-static int prism2mib_excludeunencrypted(mibrec_t *mib,
+static int prism2mib_excludeunencrypted(struct mibrec *mib,
int isget,
wlandevice_t *wlandev,
hfa384x_t *hw,
- p80211msg_dot11req_mibset_t *msg,
+ struct p80211msg_dot11req_mibset *msg,
void *data)
{
int result;
@@ -660,11 +660,11 @@ static int prism2mib_excludeunencrypted(mibrec_t *mib,
*
----------------------------------------------------------------*/
-static int prism2mib_fragmentationthreshold(mibrec_t *mib,
+static int prism2mib_fragmentationthreshold(struct mibrec *mib,
int isget,
wlandevice_t *wlandev,
hfa384x_t *hw,
- p80211msg_dot11req_mibset_t *msg,
+ struct p80211msg_dot11req_mibset *msg,
void *data)
{
int result;
@@ -709,11 +709,11 @@ static int prism2mib_fragmentationthreshold(mibrec_t *mib,
*
----------------------------------------------------------------*/
-static int prism2mib_priv(mibrec_t *mib,
+static int prism2mib_priv(struct mibrec *mib,
int isget,
wlandevice_t *wlandev,
hfa384x_t *hw,
- p80211msg_dot11req_mibset_t *msg, void *data)
+ struct p80211msg_dot11req_mibset *msg, void *data)
{
p80211pstrd_t *pstr = (p80211pstrd_t *) data;
diff --git a/drivers/staging/wlan-ng/prism2sta.c b/drivers/staging/wlan-ng/prism2sta.c
index 6cd09352f89..ed751f418db 100644
--- a/drivers/staging/wlan-ng/prism2sta.c
+++ b/drivers/staging/wlan-ng/prism2sta.c
@@ -83,8 +83,6 @@
#include "hfa384x.h"
#include "prism2mgmt.h"
-#define wlan_hexchar(x) (((x) < 0x0a) ? ('0' + (x)) : ('a' + ((x) - 0x0a)))
-
/* Create a string of printable chars from something that might not be */
/* It's recommended that the str be 4*len + 1 bytes long */
#define wlan_mkprintstr(buf, buflen, str, strlen) \
@@ -99,8 +97,8 @@
} else { \
(str)[j] = '\\'; \
(str)[j+1] = 'x'; \
- (str)[j+2] = wlan_hexchar(((buf)[i] & 0xf0) >> 4); \
- (str)[j+3] = wlan_hexchar(((buf)[i] & 0x0f)); \
+ (str)[j+2] = hex_asc_hi((buf)[i]); \
+ (str)[j+3] = hex_asc_lo((buf)[i]); \
j += 4; \
} \
} \
@@ -124,13 +122,17 @@ MODULE_PARM_DESC(prism2_reset_settletime, "reset settle time in ms");
MODULE_LICENSE("Dual MPL/GPL");
+void prism2_connect_result(wlandevice_t *wlandev, u8 failed);
+void prism2_disconnected(wlandevice_t *wlandev);
+void prism2_roamed(wlandevice_t *wlandev);
+
static int prism2sta_open(wlandevice_t *wlandev);
static int prism2sta_close(wlandevice_t *wlandev);
static void prism2sta_reset(wlandevice_t *wlandev);
static int prism2sta_txframe(wlandevice_t *wlandev, struct sk_buff *skb,
- p80211_hdr_t *p80211_hdr,
- p80211_metawep_t *p80211_wep);
-static int prism2sta_mlmerequest(wlandevice_t *wlandev, p80211msg_t *msg);
+ union p80211_hdr *p80211_hdr,
+ struct p80211_metawep *p80211_wep);
+static int prism2sta_mlmerequest(wlandevice_t *wlandev, struct p80211msg *msg);
static int prism2sta_getcardinfo(wlandevice_t *wlandev);
static int prism2sta_globalsetup(wlandevice_t *wlandev);
static int prism2sta_setmulticast(wlandevice_t *wlandev, netdevice_t *dev);
@@ -266,8 +268,8 @@ static void prism2sta_reset(wlandevice_t *wlandev)
* process thread
----------------------------------------------------------------*/
static int prism2sta_txframe(wlandevice_t *wlandev, struct sk_buff *skb,
- p80211_hdr_t *p80211_hdr,
- p80211_metawep_t *p80211_wep)
+ union p80211_hdr *p80211_hdr,
+ struct p80211_metawep *p80211_wep)
{
hfa384x_t *hw = (hfa384x_t *) wlandev->priv;
int result;
@@ -307,7 +309,7 @@ static int prism2sta_txframe(wlandevice_t *wlandev, struct sk_buff *skb,
* Call context:
* process thread
----------------------------------------------------------------*/
-static int prism2sta_mlmerequest(wlandevice_t *wlandev, p80211msg_t *msg)
+static int prism2sta_mlmerequest(wlandevice_t *wlandev, struct p80211msg *msg)
{
hfa384x_t *hw = (hfa384x_t *) wlandev->priv;
@@ -364,9 +366,9 @@ static int prism2sta_mlmerequest(wlandevice_t *wlandev, p80211msg_t *msg)
break; /* ignore me. */
case DIDmsg_lnxreq_ifstate:
{
- p80211msg_lnxreq_ifstate_t *ifstatemsg;
+ struct p80211msg_lnxreq_ifstate *ifstatemsg;
pr_debug("Received mlme ifstate request\n");
- ifstatemsg = (p80211msg_lnxreq_ifstate_t *) msg;
+ ifstatemsg = (struct p80211msg_lnxreq_ifstate *) msg;
result =
prism2sta_ifstate(wlandev,
ifstatemsg->ifstate.data);
@@ -385,11 +387,11 @@ static int prism2sta_mlmerequest(wlandevice_t *wlandev, p80211msg_t *msg)
result = prism2mgmt_autojoin(wlandev, msg);
break;
case DIDmsg_lnxreq_commsquality:{
- p80211msg_lnxreq_commsquality_t *qualmsg;
+ struct p80211msg_lnxreq_commsquality *qualmsg;
pr_debug("Received commsquality request\n");
- qualmsg = (p80211msg_lnxreq_commsquality_t *) msg;
+ qualmsg = (struct p80211msg_lnxreq_commsquality *) msg;
qualmsg->link.status =
P80211ENUM_msgitem_status_data_ok;
@@ -401,6 +403,7 @@ static int prism2sta_mlmerequest(wlandevice_t *wlandev, p80211msg_t *msg)
qualmsg->link.data = le16_to_cpu(hw->qual.CQ_currBSS);
qualmsg->level.data = le16_to_cpu(hw->qual.ASL_currBSS);
qualmsg->noise.data = le16_to_cpu(hw->qual.ANL_currFC);
+ qualmsg->txrate.data = hw->txrate;
break;
}
@@ -1300,6 +1303,9 @@ void prism2sta_processing_defer(struct work_struct *data)
(portstatus == HFA384x_PSTATUS_CONN_IBSS) ?
WLAN_MACMODE_IBSS_STA : WLAN_MACMODE_ESS_STA;
+ /* signal back up to cfg80211 layer */
+ prism2_connect_result(wlandev, P80211ENUM_truth_false);
+
/* Get the ball rolling on the comms quality stuff */
prism2sta_commsqual_defer(&hw->commsqual_bh);
}
@@ -1315,25 +1321,16 @@ void prism2sta_processing_defer(struct work_struct *data)
* Indicate Deauthentication
* Block Transmits, Ignore receives of data frames
*/
- if (hw->join_ap == 2) {
- hfa384x_JoinRequest_data_t joinreq;
- joinreq = hw->joinreq;
- /* Send the join request */
- hfa384x_drvr_setconfig(hw,
- HFA384x_RID_JOINREQUEST,
- &joinreq,
- HFA384x_RID_JOINREQUEST_LEN);
+ if (wlandev->netdev->type == ARPHRD_ETHER)
printk(KERN_INFO
- "linkstatus=DISCONNECTED (re-submitting join)\n");
- } else {
- if (wlandev->netdev->type == ARPHRD_ETHER)
- printk(KERN_INFO
- "linkstatus=DISCONNECTED (unhandled)\n");
- }
+ "linkstatus=DISCONNECTED (unhandled)\n");
wlandev->macmode = WLAN_MACMODE_NONE;
netif_carrier_off(wlandev->netdev);
+ /* signal back up to cfg80211 layer */
+ prism2_disconnected(wlandev);
+
break;
case HFA384x_LINK_AP_CHANGE:
@@ -1376,6 +1373,9 @@ void prism2sta_processing_defer(struct work_struct *data)
hw->link_status = HFA384x_LINK_CONNECTED;
netif_carrier_on(wlandev->netdev);
+ /* signal back up to cfg80211 layer */
+ prism2_roamed(wlandev);
+
break;
case HFA384x_LINK_AP_OUTOFRANGE:
@@ -1435,6 +1435,9 @@ void prism2sta_processing_defer(struct work_struct *data)
netif_carrier_off(wlandev->netdev);
+ /* signal back up to cfg80211 layer */
+ prism2_connect_result(wlandev, P80211ENUM_truth_true);
+
break;
default:
@@ -1446,7 +1449,6 @@ void prism2sta_processing_defer(struct work_struct *data)
}
wlandev->linkstatus = (hw->link_status == HFA384x_LINK_CONNECTED);
- p80211wext_event_associated(wlandev, wlandev->linkstatus);
failed:
return;
@@ -1985,6 +1987,9 @@ void prism2sta_commsqual_defer(struct work_struct *data)
hfa384x_t *hw = container_of(data, struct hfa384x, commsqual_bh);
wlandevice_t *wlandev = hw->wlandev;
hfa384x_bytestr32_t ssid;
+ struct p80211msg_dot11req_mibget msg;
+ p80211item_uint32_t *mibitem = (p80211item_uint32_t *)
+ &msg.mibattribute.data;
int result = 0;
if (hw->wlandev->hwremoved)
@@ -2013,6 +2018,34 @@ void prism2sta_commsqual_defer(struct work_struct *data)
le16_to_cpu(hw->qual.ANL_currFC));
}
+ /* Get the signal rate */
+ msg.msgcode = DIDmsg_dot11req_mibget;
+ mibitem->did = DIDmib_p2_p2MAC_p2CurrentTxRate;
+ result = p80211req_dorequest(wlandev, (u8 *) &msg);
+
+ if (result) {
+ pr_debug("get signal rate failed, result = %d\n",
+ result);
+ goto done;
+ }
+
+ switch (mibitem->data) {
+ case HFA384x_RATEBIT_1:
+ hw->txrate = 10;
+ break;
+ case HFA384x_RATEBIT_2:
+ hw->txrate = 20;
+ break;
+ case HFA384x_RATEBIT_5dot5:
+ hw->txrate = 55;
+ break;
+ case HFA384x_RATEBIT_11:
+ hw->txrate = 110;
+ break;
+ default:
+ pr_debug("Bad ratebit (%d)\n", mibitem->data);
+ }
+
/* Lastly, we need to make sure the BSSID didn't change on us */
result = hfa384x_drvr_getconfig(hw,
HFA384x_RID_CURRENTBSSID,
diff --git a/drivers/staging/wlan-ng/prism2usb.c b/drivers/staging/wlan-ng/prism2usb.c
index f5cff751db2..4efa027a81e 100644
--- a/drivers/staging/wlan-ng/prism2usb.c
+++ b/drivers/staging/wlan-ng/prism2usb.c
@@ -119,7 +119,7 @@ static int prism2sta_probe_usb(struct usb_interface *interface,
}
hw = wlandev->priv;
- if (wlan_setup(wlandev) != 0) {
+ if (wlan_setup(wlandev, &(interface->dev)) != 0) {
printk(KERN_ERR "%s: wlan_setup() failed.\n", dev_info);
result = -EIO;
goto failed;
diff --git a/drivers/staging/xgifb/XGI.h b/drivers/staging/xgifb/XGI.h
deleted file mode 100644
index 87803dd032d..00000000000
--- a/drivers/staging/xgifb/XGI.h
+++ /dev/null
@@ -1,10 +0,0 @@
-#ifndef _XGI_H
-#define _XGI_H
-
-#if 1
-#define TWDEBUG(x)
-#else
-#define TWDEBUG(x) printk(KERN_INFO x "\n");
-#endif
-
-#endif
diff --git a/drivers/staging/xgifb/XGI_accel.c b/drivers/staging/xgifb/XGI_accel.c
index 86ec3421942..79549742cff 100644
--- a/drivers/staging/xgifb/XGI_accel.c
+++ b/drivers/staging/xgifb/XGI_accel.c
@@ -37,37 +37,17 @@
#include <linux/agp_backend.h>
#include <linux/types.h>
-/*
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-#include <linux/XGIfb.h>
-#else
-#include <video/XGIfb.h>
-#endif
-*/
#include <asm/io.h>
#ifdef CONFIG_MTRR
#include <asm/mtrr.h>
#endif
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-#include <video/fbcon.h>
-#include <video/fbcon-cfb8.h>
-#include <video/fbcon-cfb16.h>
-#include <video/fbcon-cfb24.h>
-#include <video/fbcon-cfb32.h>
-#endif
-
-#include "osdef.h"
#include "vgatypes.h"
#include "vb_struct.h"
#include "XGIfb.h"
#include "XGI_accel.h"
-
-extern struct video_info xgi_video_info;
-extern int XGIfb_accel;
-
static const int XGIALUConv[] =
{
0x00, /* dest = 0; 0, GXclear, 0 */
@@ -108,109 +88,17 @@ static const int XGIPatALUConv[] =
0xFF, /* dest = 0xFF; 1, GXset, 0xF */
};
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,34)
static const unsigned char myrops[] = {
3, 10, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3
};
-#endif
/* 300 series */
-#if 0
-static void
-XGI300Sync(void)
-{
- XGI300Idle
-}
-#endif
static void
XGI310Sync(void)
{
XGI310Idle
}
-#if 0
-static void
-XGI300SetupForScreenToScreenCopy(int xdir, int ydir, int rop,
- unsigned int planemask, int trans_color)
-{
- XGI300SetupDSTColorDepth(xgi_video_info.DstColor);
- XGI300SetupSRCPitch(xgi_video_info.video_linelength)
- XGI300SetupDSTRect(xgi_video_info.video_linelength, 0xFFF)
-
- if(trans_color != -1) {
- XGI300SetupROP(0x0A)
- XGI300SetupSRCTrans(trans_color)
- XGI300SetupCMDFlag(TRANSPARENT_BITBLT)
- } else {
- XGI300SetupROP(XGIALUConv[rop])
- }
- if(xdir > 0) {
- XGI300SetupCMDFlag(X_INC)
- }
- if(ydir > 0) {
- XGI300SetupCMDFlag(Y_INC)
- }
-}
-
-static void
-XGI300SubsequentScreenToScreenCopy(int src_x, int src_y, int dst_x, int dst_y,
- int width, int height)
-{
- long srcbase, dstbase;
-
- srcbase = dstbase = 0;
- if (src_y >= 2048) {
- srcbase = xgi_video_info.video_linelength * src_y;
- src_y = 0;
- }
- if (dst_y >= 2048) {
- dstbase = xgi_video_info.video_linelength * dst_y;
- dst_y = 0;
- }
-
- XGI300SetupSRCBase(srcbase);
- XGI300SetupDSTBase(dstbase);
-
- if(!(xgi_video_info.CommandReg & X_INC)) {
- src_x += width-1;
- dst_x += width-1;
- }
- if(!(xgi_video_info.CommandReg & Y_INC)) {
- src_y += height-1;
- dst_y += height-1;
- }
- XGI300SetupRect(width, height)
- XGI300SetupSRCXY(src_x, src_y)
- XGI300SetupDSTXY(dst_x, dst_y)
- XGI300DoCMD
-}
-
-static void
-XGI300SetupForSolidFill(int color, int rop, unsigned int planemask)
-{
- XGI300SetupPATFG(color)
- XGI300SetupDSTRect(xgi_video_info.video_linelength, 0xFFF)
- XGI300SetupDSTColorDepth(xgi_video_info.DstColor);
- XGI300SetupROP(XGIPatALUConv[rop])
- XGI300SetupCMDFlag(PATFG)
-}
-static void
-XGI300SubsequentSolidFillRect(int x, int y, int w, int h)
-{
- long dstbase;
-
- dstbase = 0;
- if(y >= 2048) {
- dstbase = xgi_video_info.video_linelength * y;
- y = 0;
- }
- XGI300SetupDSTBase(dstbase)
- XGI300SetupDSTXY(x,y)
- XGI300SetupRect(w,h)
- XGI300SetupCMDFlag(X_INC | Y_INC | BITBLT)
- XGI300DoCMD
-}
-#endif
/* 310/325 series ------------------------------------------------ */
static void
@@ -326,8 +214,6 @@ void XGIfb_syncaccel(void)
}
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,34) /* --- KERNEL 2.5.34 and later --- */
-
int fbcon_XGI_sync(struct fb_info *info)
{
if(!XGIfb_accel) return 0;
@@ -399,198 +285,5 @@ void fbcon_XGI_copyarea(struct fb_info *info, const struct fb_copyarea *area)
}
-#endif
-
-#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,33) /* ------ KERNEL <2.5.34 ------ */
-
-void fbcon_XGI_bmove(struct display *p, int srcy, int srcx,
- int dsty, int dstx, int height, int width)
-{
- int xdir, ydir;
- CRITFLAGS
-
- if(!xgi_video_info.accel) {
- switch(xgi_video_info.video_bpp) {
- case 8:
-#ifdef FBCON_HAS_CFB8
- fbcon_cfb8_bmove(p, srcy, srcx, dsty, dstx, height, width);
-#endif
- break;
- case 16:
-#ifdef FBCON_HAS_CFB16
- fbcon_cfb16_bmove(p, srcy, srcx, dsty, dstx, height, width);
-#endif
- break;
- case 32:
-#ifdef FBCON_HAS_CFB32
- fbcon_cfb32_bmove(p, srcy, srcx, dsty, dstx, height, width);
-#endif
- break;
- }
- return;
- }
-
- srcx *= fontwidth(p);
- srcy *= fontheight(p);
- dstx *= fontwidth(p);
- dsty *= fontheight(p);
- width *= fontwidth(p);
- height *= fontheight(p);
-
- if(srcx < dstx) xdir = 0;
- else xdir = 1;
- if(srcy < dsty) ydir = 0;
- else ydir = 1;
-
-
- CRITBEGIN
- XGI310SetupForScreenToScreenCopy(xdir, ydir, 3, 0, -1);
- XGI310SubsequentScreenToScreenCopy(srcx, srcy, dstx, dsty, width, height);
- CRITEND
- XGI310Sync();
-#if 0
- printk(KERN_INFO "XGI_bmove sx %d sy %d dx %d dy %d w %d h %d\n",
- srcx, srcy, dstx, dsty, width, height);
-#endif
-
-}
-
-
-static void fbcon_XGI_clear(struct vc_data *conp, struct display *p,
- int srcy, int srcx, int height, int width, int color)
-{
- CRITFLAGS
-
- srcx *= fontwidth(p);
- srcy *= fontheight(p);
- width *= fontwidth(p);
- height *= fontheight(p);
-
-
- CRITBEGIN
- XGI310SetupForSolidFill(color, 3, 0);
- XGI310SubsequentSolidFillRect(srcx, srcy, width, height);
- CRITEND
- XGI310Sync();
-
-}
-
-void fbcon_XGI_clear8(struct vc_data *conp, struct display *p,
- int srcy, int srcx, int height, int width)
-{
- u32 bgx;
-
- if(!xgi_video_info.accel) {
-#ifdef FBCON_HAS_CFB8
- fbcon_cfb8_clear(conp, p, srcy, srcx, height, width);
-#endif
- return;
- }
-
- bgx = attr_bgcol_ec(p, conp);
- fbcon_XGI_clear(conp, p, srcy, srcx, height, width, bgx);
-}
-
-void fbcon_XGI_clear16(struct vc_data *conp, struct display *p,
- int srcy, int srcx, int height, int width)
-{
- u32 bgx;
- if(!xgi_video_info.accel) {
-#ifdef FBCON_HAS_CFB16
- fbcon_cfb16_clear(conp, p, srcy, srcx, height, width);
-#endif
- return;
- }
-
- bgx = ((u_int16_t*)p->dispsw_data)[attr_bgcol_ec(p, conp)];
- fbcon_XGI_clear(conp, p, srcy, srcx, height, width, bgx);
-}
-
-void fbcon_XGI_clear32(struct vc_data *conp, struct display *p,
- int srcy, int srcx, int height, int width)
-{
- u32 bgx;
-
- if(!xgi_video_info.accel) {
-#ifdef FBCON_HAS_CFB32
- fbcon_cfb32_clear(conp, p, srcy, srcx, height, width);
-#endif
- return;
- }
-
- bgx = ((u_int32_t*)p->dispsw_data)[attr_bgcol_ec(p, conp)];
- fbcon_XGI_clear(conp, p, srcy, srcx, height, width, bgx);
-}
-
-void fbcon_XGI_revc(struct display *p, int srcx, int srcy)
-{
- CRITFLAGS
-
- if(!xgi_video_info.accel) {
- switch(xgi_video_info.video_bpp) {
- case 16:
-#ifdef FBCON_HAS_CFB16
- fbcon_cfb16_revc(p, srcx, srcy);
-#endif
- break;
- case 32:
-#ifdef FBCON_HAS_CFB32
- fbcon_cfb32_revc(p, srcx, srcy);
-#endif
- break;
- }
- return;
- }
-
- srcx *= fontwidth(p);
- srcy *= fontheight(p);
-
-
- CRITBEGIN
- XGI310SetupForSolidFill(0, 0x0a, 0);
- XGI310SubsequentSolidFillRect(srcx, srcy, fontwidth(p), fontheight(p));
- CRITEND
- XGI310Sync();
-
-}
-
-#ifdef FBCON_HAS_CFB8
-struct display_switch fbcon_XGI8 = {
- setup: fbcon_cfb8_setup,
- bmove: fbcon_XGI_bmove,
- clear: fbcon_XGI_clear8,
- putc: fbcon_cfb8_putc,
- putcs: fbcon_cfb8_putcs,
- revc: fbcon_cfb8_revc,
- clear_margins: fbcon_cfb8_clear_margins,
- fontwidthmask: FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16)
-};
-#endif
-#ifdef FBCON_HAS_CFB16
-struct display_switch fbcon_XGI16 = {
- setup: fbcon_cfb16_setup,
- bmove: fbcon_XGI_bmove,
- clear: fbcon_XGI_clear16,
- putc: fbcon_cfb16_putc,
- putcs: fbcon_cfb16_putcs,
- revc: fbcon_XGI_revc,
- clear_margins: fbcon_cfb16_clear_margins,
- fontwidthmask: FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16)
-};
-#endif
-#ifdef FBCON_HAS_CFB32
-struct display_switch fbcon_XGI32 = {
- setup: fbcon_cfb32_setup,
- bmove: fbcon_XGI_bmove,
- clear: fbcon_XGI_clear32,
- putc: fbcon_cfb32_putc,
- putcs: fbcon_cfb32_putcs,
- revc: fbcon_XGI_revc,
- clear_margins: fbcon_cfb32_clear_margins,
- fontwidthmask: FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16)
-};
-#endif
-
-#endif /* KERNEL VERSION */
diff --git a/drivers/staging/xgifb/XGI_accel.h b/drivers/staging/xgifb/XGI_accel.h
index 04e126772bb..28c057994b3 100644
--- a/drivers/staging/xgifb/XGI_accel.h
+++ b/drivers/staging/xgifb/XGI_accel.h
@@ -491,21 +491,9 @@ void XGIfb_syncaccel(void);
extern struct video_info xgi_video_info;
-#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,33)
-void fbcon_XGI_bmove(struct display *p, int srcy, int srcx, int dsty,
- int dstx, int height, int width);
-void fbcon_XGI_revc(struct display *p, int srcy, int srcx);
-void fbcon_XGI_clear8(struct vc_data *conp, struct display *p, int srcy,
- int srcx, int height, int width);
-void fbcon_XGI_clear16(struct vc_data *conp, struct display *p, int srcy,
- int srcx, int height, int width);
-void fbcon_XGI_clear32(struct vc_data *conp, struct display *p, int srcy,
- int srcx, int height, int width);
-#endif
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,34)
extern int XGIfb_accel;
void fbcon_XGI_fillrect(struct fb_info *info, const struct fb_fillrect *rect);
void fbcon_XGI_copyarea(struct fb_info *info, const struct fb_copyarea *area);
-#endif
+
#endif
diff --git a/drivers/staging/xgifb/XGI_main.h b/drivers/staging/xgifb/XGI_main.h
index 4f4171e8a68..fd1152eb2c9 100644
--- a/drivers/staging/xgifb/XGI_main.h
+++ b/drivers/staging/xgifb/XGI_main.h
@@ -42,17 +42,10 @@
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,8)
#define XGI_IOTYPE1 void __iomem
#define XGI_IOTYPE2 __iomem
#define XGIINITSTATIC static
-#else
-#define XGI_IOTYPE1 unsigned char
-#define XGI_IOTYPE2
-#define XGIINITSTATIC
-#endif
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
static struct pci_device_id __devinitdata xgifb_pci_table[] = {
{ PCI_VENDOR_ID_XG, PCI_DEVICE_ID_XG_20, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
@@ -63,7 +56,7 @@ static struct pci_device_id __devinitdata xgifb_pci_table[] = {
};
MODULE_DEVICE_TABLE(pci, xgifb_pci_table);
-#endif
+
/* To be included in fb.h */
#ifndef FB_ACCEL_XGI_GLAMOUR_2
#define FB_ACCEL_XGI_GLAMOUR_2 40 /* XGI 315, 650, 740 */
@@ -255,9 +248,6 @@ MODULE_DEVICE_TABLE(pci, xgifb_pci_table);
#define BRI_DRAM_SIZE_32MB 0x04
#define BRI_DRAM_SIZE_64MB 0x05
-#define HW_DEVICE_EXTENSION XGI_HW_DEVICE_INFO
-#define PHW_DEVICE_EXTENSION PXGI_HW_DEVICE_INFO
-
#define SR_BUFFER_SIZE 5
#define CR_BUFFER_SIZE 5
@@ -300,11 +290,7 @@ MODULE_DEVICE_TABLE(pci, xgifb_pci_table);
/* ------------------- Global Variables ----------------------------- */
/* Fbcon variables */
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
static struct fb_info* fb_info;
-#else
-static struct fb_info XGI_fb_info;
-#endif
static int video_type = FB_TYPE_PACKED_PIXELS;
@@ -336,12 +322,8 @@ static struct fb_var_screeninfo default_var = {
.vsync_len = 0,
.sync = 0,
.vmode = FB_VMODE_NONINTERLACED,
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
- .reserved = {0, 0, 0, 0, 0, 0}
-#endif
};
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
static struct fb_fix_screeninfo XGIfb_fix = {
.id = "XGI",
.type = FB_TYPE_PACKED_PIXELS,
@@ -350,28 +332,7 @@ static struct fb_fix_screeninfo XGIfb_fix = {
};
static char myid[20];
static u32 pseudo_palette[17];
-#endif
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-static struct display XGI_disp;
-
-static struct display_switch XGIfb_sw;
-
-static struct {
- u16 blue, green, red, pad;
-} XGI_palette[256];
-
-static union {
-#ifdef FBCON_HAS_CFB16
- u16 cfb16[16];
-#endif
-#ifdef FBCON_HAS_CFB32
- u32 cfb32[16];
-#endif
-} XGI_fbcon_cmap;
-
-static int XGIfb_inverse = 0;
-#endif
/* display status */
static int XGIfb_off = 0;
@@ -380,9 +341,6 @@ static int XGIfb_forcecrt1 = -1;
static int XGIvga_enabled = 0;
static int XGIfb_userom = 0;
//static int XGIfb_useoem = -1;
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-static int currcon = 0;
-#endif
/* global flags */
static int XGIfb_registered;
@@ -415,10 +373,10 @@ unsigned char XGIfb_detectedlcda = 0xff;
/* XGIfb_info XGIfbinfo; */
/* TW: Hardware extension; contains data on hardware */
-HW_DEVICE_EXTENSION XGIhw_ext;
+struct xgi_hw_device_info XGIhw_ext;
/* TW: XGI private structure */
-VB_DEVICE_INFO XGI_Pr;
+struct vb_device_info XGI_Pr;
/* card parameters */
static unsigned long XGIfb_mmio_size = 0;
@@ -530,29 +488,21 @@ struct _XGIbios_mode {
/* mode-related variables */
#ifdef MODULE
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
static int xgifb_mode_idx = 1;
#else
-static int XGIfb_mode_idx = MODE_INDEX_NONE; /* Don't use a mode by default if we are a module */
-#endif
-#else
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
static int xgifb_mode_idx = -1; /* Use a default mode if we are inside the kernel */
-#else
-static int XGIfb_mode_idx = -1;
-#endif
#endif
u8 XGIfb_mode_no = 0;
u8 XGIfb_rate_idx = 0;
/* TW: CR36 evaluation */
-const USHORT XGI300paneltype[] =
+const unsigned short XGI300paneltype[] =
{ LCD_UNKNOWN, LCD_800x600, LCD_1024x768, LCD_1280x1024,
LCD_1280x960, LCD_640x480, LCD_1024x600, LCD_1152x768,
LCD_1024x768, LCD_1024x768, LCD_1024x768,
LCD_1024x768, LCD_1024x768, LCD_1024x768, LCD_1024x768 };
-const USHORT XGI310paneltype[] =
+const unsigned short XGI310paneltype[] =
{ LCD_UNKNOWN, LCD_800x600, LCD_1024x768, LCD_1280x1024,
LCD_640x480, LCD_1024x600, LCD_1152x864, LCD_1280x960,
LCD_1152x768, LCD_1400x1050,LCD_1280x768, LCD_1600x1200,
@@ -648,17 +598,6 @@ static const struct _chswtable {
{ 0, 0, "" , "" }
};
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-/* Offscreen layout */
-typedef struct _XGI_GLYINFO {
- unsigned char ch;
- int fontwidth;
- int fontheight;
- u8 gmask[72];
- int ngmask;
-} XGI_GLYINFO;
-#endif
-
typedef struct _XGI_OH {
struct _XGI_OH *poh_next;
struct _XGI_OH *poh_prev;
@@ -852,50 +791,6 @@ XGIINITSTATIC int __init XGIfb_setup(char *options);
/* fbdev routines */
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
- int XGIfb_init(void);
-static int XGIfb_get_fix(struct fb_fix_screeninfo *fix,
- int con,
- struct fb_info *info);
-static int XGIfb_get_var(struct fb_var_screeninfo *var,
- int con,
- struct fb_info *info);
-static int XGIfb_set_var(struct fb_var_screeninfo *var,
- int con,
- struct fb_info *info);
-static void XGIfb_crtc_to_var(struct fb_var_screeninfo *var);
-static int XGIfb_get_cmap(struct fb_cmap *cmap,
- int kspc,
- int con,
- struct fb_info *info);
-static int XGIfb_set_cmap(struct fb_cmap *cmap,
- int kspc,
- int con,
- struct fb_info *info);
-static int XGIfb_update_var(int con,
- struct fb_info *info);
-static int XGIfb_switch(int con,
- struct fb_info *info);
-static void XGIfb_blank(int blank,
- struct fb_info *info);
-static void XGIfb_set_disp(int con,
- struct fb_var_screeninfo *var,
- struct fb_info *info);
-static int XGI_getcolreg(unsigned regno, unsigned *red, unsigned *green,
- unsigned *blue, unsigned *transp,
- struct fb_info *fb_info);
-static void XGIfb_do_install_cmap(int con,
- struct fb_info *info);
-static void XGI_get_glyph(struct fb_info *info,
- XGI_GLYINFO *gly);
-static int XGIfb_mmap(struct fb_info *info, struct file *file,
- struct vm_area_struct *vma);
-static int XGIfb_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg, int con,
- struct fb_info *info);
-#endif
-
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
XGIINITSTATIC int __init xgifb_init(void);
static int XGIfb_set_par(struct fb_info *info);
static int XGIfb_blank(int blank,
@@ -907,36 +802,25 @@ extern void fbcon_XGI_fillrect(struct fb_info *info,
const struct fb_fillrect *rect);
extern void fbcon_XGI_copyarea(struct fb_info *info,
const struct fb_copyarea *area);
-#if 0
-extern void cfb_imageblit(struct fb_info *info,
- const struct fb_image *image);
-#endif
extern int fbcon_XGI_sync(struct fb_info *info);
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,15)
static int XGIfb_ioctl(struct fb_info *info, unsigned int cmd,
unsigned long arg);
-#else
-static int XGIfb_ioctl(struct inode *inode,
- struct file *file,
- unsigned int cmd,
- unsigned long arg,
- struct fb_info *info);
-#endif
/*
extern int XGIfb_mode_rate_to_dclock(VB_DEVICE_INFO *XGI_Pr,
- PXGI_HW_DEVICE_INFO HwDeviceExtension,
+ struct xgi_hw_device_info *HwDeviceExtension,
unsigned char modeno, unsigned char rateindex);
-extern int XGIfb_mode_rate_to_ddata(VB_DEVICE_INFO *XGI_Pr, PXGI_HW_DEVICE_INFO HwDeviceExtension,
+extern int XGIfb_mode_rate_to_ddata(VB_DEVICE_INFO *XGI_Pr, struct xgi_hw_device_info *HwDeviceExtension,
unsigned char modeno, unsigned char rateindex,
unsigned int *left_margin, unsigned int *right_margin,
unsigned int *upper_margin, unsigned int *lower_margin,
unsigned int *hsync_len, unsigned int *vsync_len,
unsigned int *sync, unsigned int *vmode);
*/
-#endif
- extern BOOLEAN XGI_SearchModeID( USHORT ModeNo,USHORT *ModeIdIndex, PVB_DEVICE_INFO );
+extern unsigned char XGI_SearchModeID(unsigned short ModeNo,
+ unsigned short *ModeIdIndex,
+ struct vb_device_info *);
static int XGIfb_get_fix(struct fb_fix_screeninfo *fix, int con,
struct fb_info *info);
@@ -956,10 +840,10 @@ static int XGIfb_do_set_var(struct fb_var_screeninfo *var, int isactive,
static void XGIfb_pre_setmode(void);
static void XGIfb_post_setmode(void);
-static BOOLEAN XGIfb_CheckVBRetrace(void);
-static BOOLEAN XGIfbcheckvretracecrt2(void);
-static BOOLEAN XGIfbcheckvretracecrt1(void);
-static BOOLEAN XGIfb_bridgeisslave(void);
+static unsigned char XGIfb_CheckVBRetrace(void);
+static unsigned char XGIfbcheckvretracecrt2(void);
+static unsigned char XGIfbcheckvretracecrt1(void);
+static unsigned char XGIfb_bridgeisslave(void);
struct XGI_memreq {
unsigned long offset;
@@ -994,30 +878,40 @@ static XGI_OH *XGIfb_poh_free(unsigned long base);
static void XGIfb_free_node(XGI_OH *poh);
/* Internal routines to access PCI configuration space */
-BOOLEAN XGIfb_query_VGA_config_space(PXGI_HW_DEVICE_INFO pXGIhw_ext,
- unsigned long offset, unsigned long set, unsigned long *value);
+unsigned char XGIfb_query_VGA_config_space(struct xgi_hw_device_info *pXGIhw_ext,
+ unsigned long offset,
+ unsigned long set,
+ unsigned long *value);
//BOOLEAN XGIfb_query_north_bridge_space(PXGI_HW_DEVICE_INFO pXGIhw_ext,
// unsigned long offset, unsigned long set, unsigned long *value);
/* Routines from init.c/init301.c */
-extern void InitTo330Pointer(UCHAR,PVB_DEVICE_INFO pVBInfo);
-extern BOOLEAN XGIInitNew(PXGI_HW_DEVICE_INFO HwDeviceExtension);
-extern BOOLEAN XGISetModeNew(PXGI_HW_DEVICE_INFO HwDeviceExtension, USHORT ModeNo);
+extern void InitTo330Pointer(unsigned char, struct vb_device_info *pVBInfo);
+extern unsigned char XGIInitNew(struct xgi_hw_device_info *HwDeviceExtension);
+extern unsigned char XGISetModeNew(struct xgi_hw_device_info *HwDeviceExtension,
+ unsigned short ModeNo);
//extern void XGI_SetEnableDstn(VB_DEVICE_INFO *XGI_Pr);
-extern void XGI_LongWait(VB_DEVICE_INFO *XGI_Pr);
-extern USHORT XGI_GetRatePtrCRT2( PXGI_HW_DEVICE_INFO pXGIHWDE, USHORT ModeNo,USHORT ModeIdIndex,PVB_DEVICE_INFO pVBInfo );
+extern void XGI_LongWait(struct vb_device_info *XGI_Pr);
+extern unsigned short XGI_GetRatePtrCRT2(struct xgi_hw_device_info *pXGIHWDE,
+ unsigned short ModeNo,
+ unsigned short ModeIdIndex,
+ struct vb_device_info *pVBInfo);
/* TW: Chrontel TV functions */
-extern USHORT XGI_GetCH700x(VB_DEVICE_INFO *XGI_Pr, USHORT tempbx);
-extern void XGI_SetCH700x(VB_DEVICE_INFO *XGI_Pr, USHORT tempbx);
-extern USHORT XGI_GetCH701x(VB_DEVICE_INFO *XGI_Pr, USHORT tempbx);
-extern void XGI_SetCH701x(VB_DEVICE_INFO *XGI_Pr, USHORT tempbx);
-extern void XGI_SetCH70xxANDOR(VB_DEVICE_INFO *XGI_Pr, USHORT tempax,USHORT tempbh);
-extern void XGI_DDC2Delay(VB_DEVICE_INFO *XGI_Pr, USHORT delaytime);
+extern unsigned short XGI_GetCH700x(struct vb_device_info *XGI_Pr,
+ unsigned short tempbx);
+extern void XGI_SetCH700x(struct vb_device_info *XGI_Pr, unsigned short tempbx);
+extern unsigned short XGI_GetCH701x(struct vb_device_info *XGI_Pr,
+ unsigned short tempbx);
+extern void XGI_SetCH701x(struct vb_device_info *XGI_Pr, unsigned short tempbx);
+extern void XGI_SetCH70xxANDOR(struct vb_device_info *XGI_Pr,
+ unsigned short tempax,
+ unsigned short tempbh);
+extern void XGI_DDC2Delay(struct vb_device_info *XGI_Pr, unsigned short delaytime);
/* TW: Sensing routines */
void XGI_Sense30x(void);
int XGIDoSense(int tempbl, int tempbh, int tempcl, int tempch);
-extern XGI21_LVDSCapStruct XGI21_LCDCapList[13];
+extern struct XGI21_LVDSCapStruct XGI21_LCDCapList[13];
#endif
diff --git a/drivers/staging/xgifb/XGI_main_26.c b/drivers/staging/xgifb/XGI_main_26.c
index 867012b48a0..976c39bb286 100644
--- a/drivers/staging/xgifb/XGI_main_26.c
+++ b/drivers/staging/xgifb/XGI_main_26.c
@@ -28,9 +28,6 @@
#include <linux/fs.h>
#include <linux/types.h>
#include <linux/proc_fs.h>
-#include <linux/kernel.h>
-
-#include "osdef.h"
#ifndef XGIFB_PAN
@@ -164,16 +161,15 @@ struct video_info xgi_video_info;
/* --------------- Hardware Access Routines -------------------------- */
-#ifdef LINUX_KERNEL
int
-XGIfb_mode_rate_to_dclock(VB_DEVICE_INFO *XGI_Pr, PXGI_HW_DEVICE_INFO HwDeviceExtension,
+XGIfb_mode_rate_to_dclock(struct vb_device_info *XGI_Pr, struct xgi_hw_device_info *HwDeviceExtension,
unsigned char modeno, unsigned char rateindex)
{
- USHORT ModeNo = modeno;
- USHORT ModeIdIndex = 0, ClockIndex = 0;
- USHORT RefreshRateTableIndex = 0;
+ unsigned short ModeNo = modeno;
+ unsigned short ModeIdIndex = 0, ClockIndex = 0;
+ unsigned short RefreshRateTableIndex = 0;
- /*ULONG temp = 0;*/
+ /*unsigned long temp = 0;*/
int Clock;
XGI_Pr->ROMAddr = HwDeviceExtension->pjVirtualRomBase;
InitTo330Pointer( HwDeviceExtension->jChipType, XGI_Pr ) ;
@@ -201,16 +197,16 @@ XGIfb_mode_rate_to_dclock(VB_DEVICE_INFO *XGI_Pr, PXGI_HW_DEVICE_INFO HwDeviceEx
}
int
-XGIfb_mode_rate_to_ddata(VB_DEVICE_INFO *XGI_Pr, PXGI_HW_DEVICE_INFO HwDeviceExtension,
+XGIfb_mode_rate_to_ddata(struct vb_device_info *XGI_Pr, struct xgi_hw_device_info *HwDeviceExtension,
unsigned char modeno, unsigned char rateindex,
u32 *left_margin, u32 *right_margin,
u32 *upper_margin, u32 *lower_margin,
u32 *hsync_len, u32 *vsync_len,
u32 *sync, u32 *vmode)
{
- USHORT ModeNo = modeno;
- USHORT ModeIdIndex = 0, index = 0;
- USHORT RefreshRateTableIndex = 0;
+ unsigned short ModeNo = modeno;
+ unsigned short ModeIdIndex = 0, index = 0;
+ unsigned short RefreshRateTableIndex = 0;
unsigned short VRE, VBE, VRS, VBS, VDE, VT;
unsigned short HRE, HBE, HRS, HBS, HDE, HT;
@@ -375,26 +371,13 @@ XGIfb_mode_rate_to_ddata(VB_DEVICE_INFO *XGI_Pr, PXGI_HW_DEVICE_INFO HwDeviceExt
}
}
-#if 0 /* That's bullshit, only the resolution needs to be shifted */
- if((*vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
- *upper_margin <<= 1;
- *lower_margin <<= 1;
- *vsync_len <<= 1;
- } else if((*vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
- *upper_margin >>= 1;
- *lower_margin >>= 1;
- *vsync_len >>= 1;
- }
-#endif
-
return 1;
}
-#endif
-void XGIRegInit(VB_DEVICE_INFO *XGI_Pr, ULONG BaseAddr)
+void XGIRegInit(struct vb_device_info *XGI_Pr, unsigned long BaseAddr)
{
XGI_Pr->RelIO = BaseAddr;
XGI_Pr->P3c4 = BaseAddr + 0x14;
@@ -432,8 +415,8 @@ u32 XGIfb_get_reg3(u16 port)
/* ------------ Interface for init & mode switching code ------------- */
-BOOLEAN
-XGIfb_query_VGA_config_space(PXGI_HW_DEVICE_INFO pXGIhw_ext,
+unsigned char
+XGIfb_query_VGA_config_space(struct xgi_hw_device_info *pXGIhw_ext,
unsigned long offset, unsigned long set, unsigned long *value)
{
static struct pci_dev *pdev = NULL;
@@ -445,10 +428,10 @@ XGIfb_query_VGA_config_space(PXGI_HW_DEVICE_INFO pXGIhw_ext,
DPRINTK("XGIfb: Set offset 0x%lx to 0x%lx\n", offset, *value);
if (!init) {
- init = TRUE;
+ init = 1;
pdev = pci_get_device(PCI_VENDOR_ID_XG, xgi_video_info.chip_id, pdev);
if (pdev) {
- valid_pdev = TRUE;
+ valid_pdev = 1;
pci_dev_put(pdev);
}
}
@@ -456,7 +439,7 @@ XGIfb_query_VGA_config_space(PXGI_HW_DEVICE_INFO pXGIhw_ext,
if (!valid_pdev) {
printk(KERN_DEBUG "XGIfb: Can't find XGI %d VGA device.\n",
xgi_video_info.chip_id);
- return FALSE;
+ return 0;
}
if (set == 0)
@@ -464,10 +447,10 @@ XGIfb_query_VGA_config_space(PXGI_HW_DEVICE_INFO pXGIhw_ext,
else
pci_write_config_dword(pdev, offset, (u32)(*value));
- return TRUE;
+ return 1;
}
-/*BOOLEAN XGIfb_query_north_bridge_space(PXGI_HW_DEVICE_INFO pXGIhw_ext,
+/*unsigned char XGIfb_query_north_bridge_space(struct xgi_hw_device_info *pXGIhw_ext,
unsigned long offset, unsigned long set, unsigned long *value)
{
static struct pci_dev *pdev = NULL;
@@ -475,7 +458,7 @@ XGIfb_query_VGA_config_space(PXGI_HW_DEVICE_INFO pXGIhw_ext,
u16 nbridge_id = 0;
if (!init) {
- init = TRUE;
+ init = 1;
switch (xgi_video_info.chip) {
case XGI_540:
nbridge_id = PCI_DEVICE_ID_XG_540;
@@ -502,13 +485,13 @@ XGIfb_query_VGA_config_space(PXGI_HW_DEVICE_INFO pXGIhw_ext,
pdev = pci_find_device(PCI_VENDOR_ID_SI, nbridge_id, pdev);
if (pdev)
- valid_pdev = TRUE;
+ valid_pdev = 1;
}
if (!valid_pdev) {
printk(KERN_DEBUG "XGIfb: Can't find XGI %d North Bridge device.\n",
nbridge_id);
- return FALSE;
+ return 0;
}
if (set == 0)
@@ -516,7 +499,7 @@ XGIfb_query_VGA_config_space(PXGI_HW_DEVICE_INFO pXGIhw_ext,
else
pci_write_config_dword(pdev, offset, (u32)(*value));
- return TRUE;
+ return 1;
}
*/
/* ------------------ Internal helper routines ----------------- */
@@ -627,7 +610,8 @@ int XGIfb_GetXG21LVDSData(void)
i += 25;
j--;
k++;
- } while ( (j>0) && ( k < (sizeof(XGI21_LCDCapList)/sizeof(XGI21_LVDSCapStruct)) ) );
+ } while ((j > 0) &&
+ (k < (sizeof(XGI21_LCDCapList)/sizeof(struct XGI21_LVDSCapStruct))));
return 1;
}
return 0;
@@ -954,46 +938,52 @@ static void XGIfb_search_tvstd(const char *name)
}
}
-static BOOLEAN XGIfb_bridgeisslave(void)
+static unsigned char XGIfb_bridgeisslave(void)
{
unsigned char usScratchP1_00;
- if(xgi_video_info.hasVB == HASVB_NONE) return FALSE;
+ if (xgi_video_info.hasVB == HASVB_NONE)
+ return 0;
inXGIIDXREG(XGIPART1,0x00,usScratchP1_00);
- if( (usScratchP1_00 & 0x50) == 0x10) {
- return TRUE;
- } else {
- return FALSE;
- }
+ if ((usScratchP1_00 & 0x50) == 0x10)
+ return 1;
+ else
+ return 0;
}
-static BOOLEAN XGIfbcheckvretracecrt1(void)
+static unsigned char XGIfbcheckvretracecrt1(void)
{
unsigned char temp;
inXGIIDXREG(XGICR,0x17,temp);
- if(!(temp & 0x80)) return FALSE;
+ if (!(temp & 0x80))
+ return 0;
inXGIIDXREG(XGISR,0x1f,temp);
- if(temp & 0xc0) return FALSE;
+ if (temp & 0xc0)
+ return 0;
-
- if(inXGIREG(XGIINPSTAT) & 0x08) return TRUE;
- else return FALSE;
+ if (inXGIREG(XGIINPSTAT) & 0x08)
+ return 1;
+ else
+ return 0;
}
-static BOOLEAN XGIfbcheckvretracecrt2(void)
+static unsigned char XGIfbcheckvretracecrt2(void)
{
unsigned char temp;
- if(xgi_video_info.hasVB == HASVB_NONE) return FALSE;
+ if (xgi_video_info.hasVB == HASVB_NONE)
+ return 0;
inXGIIDXREG(XGIPART1, 0x30, temp);
- if(temp & 0x02) return FALSE;
- else return TRUE;
+ if (temp & 0x02)
+ return 0;
+ else
+ return 1;
}
-static BOOLEAN XGIfb_CheckVBRetrace(void)
+static unsigned char XGIfb_CheckVBRetrace(void)
{
if(xgi_video_info.disp_state & DISPTYPE_DISP2) {
if(XGIfb_bridgeisslave()) {
@@ -1350,11 +1340,7 @@ static int XGIfb_set_par(struct fb_info *info)
// printk("XGIfb: inside set_par\n");
if((err = XGIfb_do_set_var(&info->var, 1, info)))
return err;
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10)
- XGIfb_get_fix(&info->fix, info->currcon, info);
-#else
XGIfb_get_fix(&info->fix, -1, info);
-#endif
// printk("XGIfb:end of set_par\n");
return 0;
}
@@ -1540,58 +1526,7 @@ static int XGIfb_pan_display( struct fb_var_screeninfo *var,
}
#endif
-#if 0
-static int XGIfb_mmap(struct fb_info *info, struct file *file,
- struct vm_area_struct *vma)
-{
- unsigned long start;
- unsigned long off;
- u32 len, mmio_off;
-
- DEBUGPRN("inside mmap");
- if(vma->vm_pgoff > (~0UL >> PAGE_SHIFT)) return -EINVAL;
-
- off = vma->vm_pgoff << PAGE_SHIFT;
-
- start = (unsigned long) xgi_video_info.video_base;
- len = PAGE_ALIGN((start & ~PAGE_MASK) + xgi_video_info.video_size);
- start &= PAGE_MASK;
-#if 0
- if (off >= len) {
- off -= len;
-#endif
- /* By Jake Page: Treat mmap request with offset beyond heapstart
- * as request for mapping the mmio area
- */
- #if 1
- mmio_off = PAGE_ALIGN((start & ~PAGE_MASK) + xgi_video_info.heapstart);
- if(off >= mmio_off) {
- off -= mmio_off;
- if(info->var.accel_flags) return -EINVAL;
-
- start = (unsigned long) xgi_video_info.mmio_base;
- len = PAGE_ALIGN((start & ~PAGE_MASK) + XGIfb_mmio_size);
- }
- start &= PAGE_MASK;
- #endif
- if((vma->vm_end - vma->vm_start + off) > len) return -EINVAL;
-
- off += start;
- vma->vm_pgoff = off >> PAGE_SHIFT;
- vma->vm_flags |= VM_IO; /* by Jake Page; is that really needed? */
-
-#if defined(__i386__) || defined(__x86_64__)
- if (boot_cpu_data.x86 > 3)
- pgprot_val(vma->vm_page_prot) |= _PAGE_PCD;
-#endif
- if (io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT, vma->vm_end - vma->vm_start,
- vma->vm_page_prot))
- return -EAGAIN;
- DEBUGPRN("end of mmap");
- return 0;
-}
-#endif
static int XGIfb_blank(int blank, struct fb_info *info)
{
u8 reg;
@@ -1610,15 +1545,8 @@ static int XGIfb_blank(int blank, struct fb_info *info)
}
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,15)
static int XGIfb_ioctl(struct fb_info *info, unsigned int cmd,
unsigned long arg)
-#else
-static int XGIfb_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg,
- struct fb_info *info)
-#endif
-
{
DEBUGPRN("inside ioctl");
switch (cmd) {
@@ -1687,7 +1615,7 @@ static int XGIfb_ioctl(struct inode *inode, struct file *file,
break;
case XGIFB_GET_INFO: /* TW: New for communication with X driver */
{
- XGIfb_info *x = (XGIfb_info *)arg;
+ struct XGIfb_info *x = (struct XGIfb_info *)arg;
//x->XGIfb_id = XGIFB_ID;
x->XGIfb_version = VER_MAJOR;
@@ -1786,9 +1714,6 @@ static struct fb_ops XGIfb_ops = {
.fb_fillrect = fbcon_XGI_fillrect,
.fb_copyarea = fbcon_XGI_copyarea,
.fb_imageblit = cfb_imageblit,
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15)
- .fb_cursor = soft_cursor,
-#endif
.fb_sync = fbcon_XGI_sync,
.fb_ioctl = XGIfb_ioctl,
// .fb_mmap = XGIfb_mmap,
@@ -2008,9 +1933,9 @@ static int XGIfb_has_VB(void)
break;
default:
xgi_video_info.hasVB = HASVB_NONE;
- return FALSE;
+ return 0;
}
- return TRUE;
+ return 1;
}
@@ -2664,13 +2589,7 @@ static void XGIfb_pre_setmode(void)
static void XGIfb_post_setmode(void)
{
u8 reg;
- BOOLEAN doit = TRUE;
-#if 0 /* TW: Wrong: Is not in MMIO space, but in RAM */
- /* Backup mode number to MMIO space */
- if(xgi_video_info.mmio_vbase) {
- *(volatile u8 *)(((u8*)xgi_video_info.mmio_vbase) + 0x449) = (unsigned char)XGIfb_mode_no;
- }
-#endif
+ unsigned char doit = 1;
/* outXGIIDXREG(XGISR,IND_XGI_PASSWORD,XGI_PASSWORD);
outXGIIDXREG(XGICR,0x13,0x00);
setXGIIDXREG(XGISR,0x0E,0xF0,0x01);
@@ -2678,11 +2597,11 @@ static void XGIfb_post_setmode(void)
if (xgi_video_info.video_bpp == 8) {
/* TW: We can't switch off CRT1 on LVDS/Chrontel in 8bpp Modes */
if ((xgi_video_info.hasVB == HASVB_LVDS) || (xgi_video_info.hasVB == HASVB_LVDS_CHRONTEL)) {
- doit = FALSE;
+ doit = 0;
}
/* TW: We can't switch off CRT1 on 301B-DH in 8bpp Modes if using LCD */
if (xgi_video_info.disp_state & DISPTYPE_LCD) {
- doit = FALSE;
+ doit = 0;
}
}
@@ -2691,14 +2610,15 @@ static void XGIfb_post_setmode(void)
inXGIIDXREG(XGIPART1, 0x00, reg);
- if((reg & 0x50) == 0x10) {
- doit = FALSE;
- }
+ if ((reg & 0x50) == 0x10)
+ doit = 0;
- } else XGIfb_crt1off = 0;
+
+ } else
+ XGIfb_crt1off = 0;
inXGIIDXREG(XGICR, 0x17, reg);
- if((XGIfb_crt1off) && (doit))
+ if ((XGIfb_crt1off) && (doit))
reg &= ~0x80;
else
reg |= 0x80;
@@ -2907,7 +2827,7 @@ XGIINITSTATIC int __init XGIfb_setup(char *options)
static unsigned char VBIOS_BUF[65535];
-unsigned char* attempt_map_rom(struct pci_dev *dev,void *copy_address)
+unsigned char *attempt_map_rom(struct pci_dev *dev, void *copy_address)
{
u32 rom_size = 0;
u32 rom_address = 0;
@@ -2962,15 +2882,9 @@ int __devinit xgifb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
XGIfb_registered = 0;
- memset(&XGIhw_ext, 0, sizeof(HW_DEVICE_EXTENSION));
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,3))
+ memset(&XGIhw_ext, 0, sizeof(struct xgi_hw_device_info));
fb_info = framebuffer_alloc(sizeof(struct fb_info), &pdev->dev);
if(!fb_info) return -ENOMEM;
-#else
- XGI_fb_info = kmalloc( sizeof(struct fb_info), GFP_KERNEL);
- if(!XGI_fb_info) return -ENOMEM;
- memset(XGI_fb_info, 0, sizeof(struct fb_info));
-#endif
xgi_video_info.chip_id = pdev->device;
pci_read_config_byte(pdev, PCI_REVISION_ID,&xgi_video_info.revision_id);
@@ -2988,14 +2902,15 @@ int __devinit xgifb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
xgi_video_info.mmio_base = pci_resource_start(pdev, 1);
XGIfb_mmio_size = pci_resource_len(pdev, 1);
xgi_video_info.vga_base = pci_resource_start(pdev, 2) + 0x30;
- XGIhw_ext.pjIOAddress = (PUCHAR)xgi_video_info.vga_base;
+ XGIhw_ext.pjIOAddress = (unsigned char *)xgi_video_info.vga_base;
//XGI_Pr.RelIO = ioremap(pci_resource_start(pdev, 2), 128) + 0x30;
- printk("XGIfb: Relocate IO address: %lx [%08lx] \n", (unsigned long)pci_resource_start(pdev, 2), XGI_Pr.RelIO);
+ printk("XGIfb: Relocate IO address: %lx [%08lx]\n",
+ (unsigned long)pci_resource_start(pdev, 2), XGI_Pr.RelIO);
if (pci_enable_device(pdev))
return -EIO;
- XGIRegInit(&XGI_Pr, (ULONG)XGIhw_ext.pjIOAddress);
+ XGIRegInit(&XGI_Pr, (unsigned long)XGIhw_ext.pjIOAddress);
outXGIIDXREG(XGISR, IND_XGI_PASSWORD, XGI_PASSWORD);
inXGIIDXREG(XGISR, IND_XGI_PASSWORD, reg1);
@@ -3052,7 +2967,7 @@ int __devinit xgifb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
case XG20:
case XG21:
case XG27:
- XGIhw_ext.bIntegratedMMEnabled = TRUE;
+ XGIhw_ext.bIntegratedMMEnabled = 1;
break;
default:
@@ -3080,7 +2995,7 @@ int __devinit xgifb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
strcpy(XGIhw_ext.szVBIOSVer, "0.84");
- XGIhw_ext.pSR = vmalloc(sizeof(XGI_DSReg) * SR_BUFFER_SIZE);
+ XGIhw_ext.pSR = vmalloc(sizeof(struct XGI_DSReg) * SR_BUFFER_SIZE);
if (XGIhw_ext.pSR == NULL)
{
printk(KERN_ERR "XGIfb: Fatal error: Allocating SRReg space failed.\n");
@@ -3088,7 +3003,7 @@ int __devinit xgifb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
}
XGIhw_ext.pSR[0].jIdx = XGIhw_ext.pSR[0].jVal = 0xFF;
- XGIhw_ext.pCR = vmalloc(sizeof(XGI_DSReg) * CR_BUFFER_SIZE);
+ XGIhw_ext.pCR = vmalloc(sizeof(struct XGI_DSReg) * CR_BUFFER_SIZE);
if (XGIhw_ext.pCR == NULL)
{
vfree(XGIhw_ext.pSR);
@@ -3218,7 +3133,7 @@ int __devinit xgifb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
xgi_video_info.disp_state = DISPTYPE_LCD;
if (!XGIfb_GetXG21LVDSData()) {
int m;
- for (m=0; m < sizeof(XGI21_LCDCapList)/sizeof(XGI21_LVDSCapStruct); m++) {
+ for (m = 0; m < sizeof(XGI21_LCDCapList)/sizeof(struct XGI21_LVDSCapStruct); m++) {
if ((XGI21_LCDCapList[m].LVDSHDE == XGIbios_mode[xgifb_mode_idx].xres) &&
(XGI21_LCDCapList[m].LVDSVDE == XGIbios_mode[xgifb_mode_idx].yres)) {
XGINew_SetReg1( XGI_Pr.P3d4 , 0x36, m) ;
@@ -3341,14 +3256,14 @@ int __devinit xgifb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
inXGIIDXREG(XGICR,0x38,tmp);
if((tmp & 0x03) == 0x03)
{
-// XGI_Pr.XGI_UseLCDA = TRUE;
+/* XGI_Pr.XGI_UseLCDA = 1; */
}else
{
// Currently on LCDA? (Some newer BIOSes set D0 in CR35)
inXGIIDXREG(XGICR,0x35,tmp);
if(tmp & 0x01)
{
-// XGI_Pr.XGI_UseLCDA = TRUE;
+/* XGI_Pr.XGI_UseLCDA = 1; */
}else
{
inXGIIDXREG(XGICR,0x30,tmp);
@@ -3357,7 +3272,7 @@ int __devinit xgifb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
inXGIIDXREG(XGIPART1,0x13,tmp);
if(tmp & 0x04)
{
-// XGI_Pr.XGI_UseLCDA = TRUE;
+/* XGI_Pr.XGI_UseLCDA = 1; */
}
}
}
@@ -3462,20 +3377,6 @@ int __devinit xgifb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
}
-
-#if 0
-#ifdef XGIFB_PAN
- if(XGIfb_ypan) {
- default_var.yres_virtual =
- xgi_video_info.heapstart / (default_var.xres * (default_var.bits_per_pixel >> 3));
- if(default_var.yres_virtual <= default_var.yres) {
- default_var.yres_virtual = default_var.yres;
- }
- }
-#endif
-#endif
-
-
xgi_video_info.accel = 0;
if(XGIfb_accel) {
xgi_video_info.accel = -1;
@@ -3511,7 +3412,8 @@ int __devinit xgifb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
XGIfb_registered = 1;
- printk(KERN_INFO "XGIfb: Installed XGIFB_GET_INFO ioctl (%x)\n", XGIFB_GET_INFO);
+ printk(KERN_INFO "XGIfb: Installed XGIFB_GET_INFO ioctl (%lx)\n",
+ XGIFB_GET_INFO);
/* printk(KERN_INFO "XGIfb: 2D acceleration is %s, scrolling mode %s\n",
XGIfb_accel ? "enabled" : "disabled",
@@ -3538,11 +3440,7 @@ static void __devexit xgifb_remove(struct pci_dev *pdev)
/* Unregister the framebuffer */
// if(xgi_video_info.registered) {
unregister_framebuffer(fb_info);
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,3))
framebuffer_release(fb_info);
-#else
- kfree(fb_info);
-#endif
// }
pci_set_drvdata(pdev, NULL);
@@ -3558,7 +3456,6 @@ static struct pci_driver xgifb_driver = {
XGIINITSTATIC int __init xgifb_init(void)
{
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,8)
#ifndef MODULE
char *option = NULL;
@@ -3566,15 +3463,13 @@ XGIINITSTATIC int __init xgifb_init(void)
return -ENODEV;
XGIfb_setup(option);
#endif
-#endif
return(pci_register_driver(&xgifb_driver));
}
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,8)
+
#ifndef MODULE
module_init(xgifb_init);
#endif
-#endif
/*****************************************************/
/* MODULE */
diff --git a/drivers/staging/xgifb/XGIfb.h b/drivers/staging/xgifb/XGIfb.h
index 41bf163d4e6..ef86a64d699 100644
--- a/drivers/staging/xgifb/XGIfb.h
+++ b/drivers/staging/xgifb/XGIfb.h
@@ -27,7 +27,7 @@
#define XGIFB_ID 0x53495346 /* Identify myself with 'XGIF' */
#endif
-typedef enum _XGI_CHIP_TYPE {
+enum XGI_CHIP_TYPE {
XGI_VGALegacy = 0,
XGI_300,
XGI_630,
@@ -53,9 +53,9 @@ typedef enum _XGI_CHIP_TYPE {
XG21,
XG27,
MAX_XGI_CHIP
-} XGI_CHIP_TYPE;
+};
-typedef enum _TVTYPE {
+enum xgi_tvtype {
TVMODE_NTSC = 0,
TVMODE_PAL,
TVMODE_HIVISION,
@@ -63,13 +63,11 @@ typedef enum _TVTYPE {
TVTYPE_PALN, // vicki@030226
TVTYPE_NTSCJ, // vicki@030226
TVMODE_TOTAL
-} XGI_TV_TYPE;
-
+};
-typedef struct _XGIFB_INFO XGIfb_info;
-struct _XGIFB_INFO {
-unsigned long XGIfb_id;
+struct XGIfb_info {
+ unsigned long XGIfb_id;
int chip_id; /* PCI ID of detected chip */
int memory; /* video memory in KB which XGIfb manages */
int heapstart; /* heap start (= XGIfb "mem" argument) in KB */
@@ -97,7 +95,7 @@ unsigned long XGIfb_id;
-typedef enum _TVPLUGTYPE { // vicki@030226
+enum xgi_tv_plug { /* vicki@030226 */
// TVPLUG_Legacy = 0,
// TVPLUG_COMPOSITE,
// TVPLUG_SVIDEO,
@@ -113,7 +111,7 @@ typedef enum _TVPLUGTYPE { // vicki@030226
TVPLUG_YPBPR_750P = 7,
TVPLUG_YPBPR_1080i = 8,
TVPLUG_TOTAL
-} XGI_TV_PLUG;
+};
struct mode_info {
@@ -132,10 +130,10 @@ struct ap_data {
unsigned long iobase;
unsigned int mem_size;
unsigned long disp_state;
- XGI_CHIP_TYPE chip;
+ enum XGI_CHIP_TYPE chip;
unsigned char hasVB;
- XGI_TV_TYPE TV_type;
- XGI_TV_PLUG TV_plug;
+ enum xgi_tvtype TV_type;
+ enum xgi_tv_plug TV_plug;
unsigned long version;
char reserved[256];
};
@@ -184,7 +182,7 @@ struct video_info{
unsigned char TV_type;
unsigned char TV_plug;
- XGI_CHIP_TYPE chip;
+ enum XGI_CHIP_TYPE chip;
unsigned char revision_id;
unsigned short DstColor;
@@ -207,9 +205,4 @@ struct video_info{
extern struct video_info xgi_video_info;
-#ifdef __KERNEL__
-//extern void xgi_malloc(struct xgi_memreq *req);
-extern void xgi_free(unsigned long base);
-extern void xgi_dispinfo(struct ap_data *rec);
-#endif
#endif
diff --git a/drivers/staging/xgifb/osdef.h b/drivers/staging/xgifb/osdef.h
deleted file mode 100644
index 4bc7d3a7440..00000000000
--- a/drivers/staging/xgifb/osdef.h
+++ /dev/null
@@ -1,153 +0,0 @@
-#ifndef _OSDEF_H_
-#define _OSDEF_H_
-
-/* #define WINCE_HEADER*/
-/*#define WIN2000*/
-/* #define TC */
-#define LINUX_KERNEL
-/* #define LINUX_XF86 */
-
-/**********************************************************************/
-#ifdef LINUX_KERNEL
-//#include <linux/config.h>
-#endif
-
-
-/**********************************************************************/
-#ifdef TC
-#endif
-#ifdef WIN2000
-#endif
-#ifdef WINCE_HEADER
-#endif
-#ifdef LINUX_XF86
-#define LINUX
-#endif
-#ifdef LINUX_KERNEL
-#define LINUX
-#endif
-
-/**********************************************************************/
-#ifdef TC
-#define XGI_SetMemory(MemoryAddress,MemorySize,value) memset(MemoryAddress, value, MemorySize);
-#endif
-#ifdef WIN2000
-#define XGI_SetMemory(MemoryAddress,MemorySize,value) MemFill((PVOID) MemoryAddress,(ULONG) MemorySize,(UCHAR) value);
-#endif
-#ifdef WINCE_HEADER
-#define XGI_SetMemory(MemoryAddress,MemorySize,value) memset(MemoryAddress, value, MemorySize);
-#endif
-#ifdef LINUX_XF86
-#define XGI_SetMemory(MemoryAddress,MemorySize,value) memset(MemoryAddress, value, MemorySize)
-#endif
-#ifdef LINUX_KERNEL
-#define XGI_SetMemory(MemoryAddress,MemorySize,value) memset(MemoryAddress, value, MemorySize)
-#endif
-/**********************************************************************/
-
-/**********************************************************************/
-
-#ifdef TC
-#define XGI_MemoryCopy(Destination,Soruce,Length) memmove(Destination, Soruce, Length);
-#endif
-#ifdef WIN2000
-#define XGI_MemoryCopy(Destination,Soruce,Length) /*VideoPortMoveMemory((PUCHAR)Destination , Soruce,length);*/
-#endif
-#ifdef WINCE_HEADER
-#define XGI_MemoryCopy(Destination,Soruce,Length) memmove(Destination, Soruce, Length);
-#endif
-#ifdef LINUX_XF86
-#define XGI_MemoryCopy(Destination,Soruce,Length) memcpy(Destination,Soruce,Length)
-#endif
-#ifdef LINUX_KERNEL
-#define XGI_MemoryCopy(Destination,Soruce,Length) memcpy(Destination,Soruce,Length)
-#endif
-
-/**********************************************************************/
-
-#ifdef OutPortByte
-#undef OutPortByte
-#endif /* OutPortByte */
-
-#ifdef OutPortWord
-#undef OutPortWord
-#endif /* OutPortWord */
-
-#ifdef OutPortLong
-#undef OutPortLong
-#endif /* OutPortLong */
-
-#ifdef InPortByte
-#undef InPortByte
-#endif /* InPortByte */
-
-#ifdef InPortWord
-#undef InPortWord
-#endif /* InPortWord */
-
-#ifdef InPortLong
-#undef InPortLong
-#endif /* InPortLong */
-
-/**********************************************************************/
-/* TC */
-/**********************************************************************/
-
-#ifdef TC
-#define OutPortByte(p,v) outp((unsigned short)(p),(unsigned char)(v))
-#define OutPortWord(p,v) outp((unsigned short)(p),(unsigned short)(v))
-#define OutPortLong(p,v) outp((unsigned short)(p),(unsigned long)(v))
-#define InPortByte(p) inp((unsigned short)(p))
-#define InPortWord(p) inp((unsigned short)(p))
-#define InPortLong(p) ((inp((unsigned short)(p+2))<<16) | inp((unsigned short)(p)))
-#endif
-
-/**********************************************************************/
-/* LINUX XF86 */
-/**********************************************************************/
-
-#ifdef LINUX_XF86
-#define OutPortByte(p,v) outb((CARD16)(p),(CARD8)(v))
-#define OutPortWord(p,v) outw((CARD16)(p),(CARD16)(v))
-#define OutPortLong(p,v) outl((CARD16)(p),(CARD32)(v))
-#define InPortByte(p) inb((CARD16)(p))
-#define InPortWord(p) inw((CARD16)(p))
-#define InPortLong(p) inl((CARD16)(p))
-#endif
-
-#ifdef LINUX_KERNEL
-#define OutPortByte(p,v) outb((u8)(v),(p))
-#define OutPortWord(p,v) outw((u16)(v),(p))
-#define OutPortLong(p,v) outl((u32)(v),(p))
-#define InPortByte(p) inb(p)
-#define InPortWord(p) inw(p)
-#define InPortLong(p) inl(p)
-#endif
-
-/**********************************************************************/
-/* WIN 2000 */
-/**********************************************************************/
-
-#ifdef WIN2000
-#define OutPortByte(p,v) VideoPortWritePortUchar ((PUCHAR) (p), (UCHAR) (v))
-#define OutPortWord(p,v) VideoPortWritePortUshort((PUSHORT) (p), (USHORT) (v))
-#define OutPortLong(p,v) VideoPortWritePortUlong ((PULONG) (p), (ULONG) (v))
-#define InPortByte(p) VideoPortReadPortUchar ((PUCHAR) (p))
-#define InPortWord(p) VideoPortReadPortUshort ((PUSHORT) (p))
-#define InPortLong(p) VideoPortReadPortUlong ((PULONG) (p))
-#endif
-
-
-/**********************************************************************/
-/* WIN CE */
-/**********************************************************************/
-
-#ifdef WINCE_HEADER
-#define OutPortByte(p,v) WRITE_PORT_UCHAR ((PUCHAR) (p), (UCHAR) (v))
-#define OutPortWord(p,v) WRITE_PORT_USHORT((PUSHORT) (p), (USHORT) (v))
-#define OutPortLong(p,v) WRITE_PORT_ULONG ((PULONG) (p), (ULONG) (v))
-#define InPortByte(p) READ_PORT_UCHAR ((PUCHAR) (p))
-#define InPortWord(p) READ_PORT_USHORT ((PUSHORT) (p))
-#define InPortLong(p) READ_PORT_ULONG ((PULONG) (p))
-#endif
-#endif // _OSDEF_H_
diff --git a/drivers/staging/xgifb/vb_def.h b/drivers/staging/xgifb/vb_def.h
index 17a7ada4926..4de182b23d4 100644
--- a/drivers/staging/xgifb/vb_def.h
+++ b/drivers/staging/xgifb/vb_def.h
@@ -6,7 +6,7 @@
#define NewScratch
#endif
/* shampoo */
-#ifdef LINUX_KERNEL
+
#define SEQ_ADDRESS_PORT 0x0014
#define SEQ_DATA_PORT 0x0015
#define MISC_OUTPUT_REG_READ_PORT 0x001C
@@ -17,7 +17,7 @@
#define CRTC_ADDRESS_PORT_COLOR 0x0024
#define VIDEO_SUBSYSTEM_ENABLE_PORT 0x0013
#define PCI_COMMAND 0x04
-#endif
+
/* ~shampoo */
diff --git a/drivers/staging/xgifb/vb_ext.c b/drivers/staging/xgifb/vb_ext.c
index 49b39ee93a8..1ecf9e3e85f 100644
--- a/drivers/staging/xgifb/vb_ext.c
+++ b/drivers/staging/xgifb/vb_ext.c
@@ -1,40 +1,7 @@
-#include "osdef.h"
-
-
-
-
-#ifdef WIN2000
-
-#include <dderror.h>
-#include <devioctl.h>
-#include <miniport.h>
-#include <ntddvdeo.h>
-#include <video.h>
-#include "xgiv.h"
-#include "dd_i2c.h"
-#include "tools.h"
-#endif /* WIN2000 */
-
-#ifdef LINUX_XF86
-#include "xf86.h"
-#include "xf86PciInfo.h"
-#include "xgi.h"
-#include "xgi_regs.h"
-#endif
-
-#ifdef LINUX_KERNEL
#include <linux/version.h>
#include <asm/io.h>
#include <linux/types.h>
#include "XGIfb.h"
-/*#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
-#include <video/XGIfb.h>
-#else
-#include <linux/XGIfb.h>
-#endif*/
-#endif
-
-
#include "vb_def.h"
#include "vgatypes.h"
@@ -42,43 +9,33 @@
#include "vb_util.h"
#include "vb_setmode.h"
#include "vb_ext.h"
-extern UCHAR XGI330_SoftSetting;
-extern UCHAR XGI330_OutputSelect;
-extern USHORT XGI330_RGBSenseData2;
-extern USHORT XGI330_YCSenseData2;
-extern USHORT XGI330_VideoSenseData2;
-#ifdef WIN2000
-extern UCHAR SenseCHTV(PHW_DEVICE_EXTENSION pHWDE); /* 2007/05/17 Billy */
-#endif
-void XGI_GetSenseStatus( PXGI_HW_DEVICE_INFO HwDeviceExtension , PVB_DEVICE_INFO pVBInfo );
-BOOLEAN XGINew_GetPanelID(PVB_DEVICE_INFO pVBInfo);
-USHORT XGINew_SenseLCD(PXGI_HW_DEVICE_INFO,PVB_DEVICE_INFO pVBInfo);
-BOOLEAN XGINew_GetLCDDDCInfo(PXGI_HW_DEVICE_INFO HwDeviceExtension,PVB_DEVICE_INFO pVBInfo);
-void XGISetDPMS( PXGI_HW_DEVICE_INFO pXGIHWDE , ULONG VESA_POWER_STATE ) ;
-BOOLEAN XGINew_BridgeIsEnable(PXGI_HW_DEVICE_INFO,PVB_DEVICE_INFO pVBInfo );
-BOOLEAN XGINew_Sense(USHORT tempbx,USHORT tempcx, PVB_DEVICE_INFO pVBInfo);
-BOOLEAN XGINew_SenseHiTV( PXGI_HW_DEVICE_INFO HwDeviceExtension , PVB_DEVICE_INFO pVBInfo ) ;
+extern unsigned char XGI330_SoftSetting;
+extern unsigned char XGI330_OutputSelect;
+extern unsigned short XGI330_RGBSenseData2;
+extern unsigned short XGI330_YCSenseData2;
+extern unsigned short XGI330_VideoSenseData2;
+void XGI_GetSenseStatus(struct xgi_hw_device_info *HwDeviceExtension, struct vb_device_info *pVBInfo);
+unsigned char XGINew_GetPanelID(struct vb_device_info *pVBInfo);
+unsigned short XGINew_SenseLCD(struct xgi_hw_device_info *,
+ struct vb_device_info *pVBInfo);
+unsigned char XGINew_GetLCDDDCInfo(struct xgi_hw_device_info *HwDeviceExtension,
+ struct vb_device_info *pVBInfo);
+void XGISetDPMS(struct xgi_hw_device_info *pXGIHWDE,
+ unsigned long VESA_POWER_STATE);
+unsigned char XGINew_BridgeIsEnable(struct xgi_hw_device_info *, struct vb_device_info *pVBInfo);
+unsigned char XGINew_Sense(unsigned short tempbx, unsigned short tempcx,
+ struct vb_device_info *pVBInfo);
+unsigned char XGINew_SenseHiTV(struct xgi_hw_device_info *HwDeviceExtension,
+ struct vb_device_info *pVBInfo);
/**************************************************************
Dynamic Sense
*************************************************************/
void XGI_WaitDisplay(void);
-BOOLEAN XGI_Is301C(PVB_DEVICE_INFO);
-BOOLEAN XGI_Is301LV(PVB_DEVICE_INFO);
-
-#ifdef WIN2000
-UCHAR XGI_SenseLCD(PHW_DEVICE_EXTENSION, PVB_DEVICE_INFO);
-UCHAR XGI_GetLCDDDCInfo(PHW_DEVICE_EXTENSION,PVB_DEVICE_INFO);
+unsigned char XGI_Is301C(struct vb_device_info *);
+unsigned char XGI_Is301LV(struct vb_device_info *);
-extern BOOL bGetDdcInfo(
-PHW_DEVICE_EXTENSION pHWDE,
-ULONG ulWhichOne,
-PUCHAR pjQueryBuffer,
-ULONG ulBufferSize
- );
-
-#endif
/* --------------------------------------------------------------------- */
@@ -87,9 +44,9 @@ ULONG ulBufferSize
/* Output : */
/* Description : */
/* --------------------------------------------------------------------- */
-BOOLEAN XGINew_Is301B( PVB_DEVICE_INFO pVBInfo )
+unsigned char XGINew_Is301B(struct vb_device_info *pVBInfo)
{
- USHORT flag ;
+ unsigned short flag ;
flag = XGINew_GetReg1( pVBInfo->Part4Port , 0x01 ) ;
@@ -105,7 +62,7 @@ BOOLEAN XGINew_Is301B( PVB_DEVICE_INFO pVBInfo )
/* Output : */
/* Description : */
/* --------------------------------------------------------------------- */
-BOOLEAN XGI_Is301C( PVB_DEVICE_INFO pVBInfo )
+unsigned char XGI_Is301C(struct vb_device_info *pVBInfo)
{
if ( ( XGINew_GetReg1( pVBInfo->Part4Port , 0x01 ) & 0xF0 ) == 0xC0 )
return( 1 ) ;
@@ -126,7 +83,7 @@ BOOLEAN XGI_Is301C( PVB_DEVICE_INFO pVBInfo )
/* Output : */
/* Description : */
/* --------------------------------------------------------------------- */
-BOOLEAN XGI_Is301LV( PVB_DEVICE_INFO pVBInfo )
+unsigned char XGI_Is301LV(struct vb_device_info *pVBInfo)
{
if ( XGINew_GetReg1( pVBInfo->Part4Port , 0x01 ) >= 0xD0 )
{
@@ -145,9 +102,11 @@ BOOLEAN XGI_Is301LV( PVB_DEVICE_INFO pVBInfo )
/* Output : */
/* Description : */
/* --------------------------------------------------------------------- */
-BOOLEAN XGINew_Sense( USHORT tempbx , USHORT tempcx, PVB_DEVICE_INFO pVBInfo )
+unsigned char XGINew_Sense(unsigned short tempbx,
+ unsigned short tempcx,
+ struct vb_device_info *pVBInfo)
{
- USHORT temp , i , tempch ;
+ unsigned short temp, i, tempch;
temp = tempbx & 0xFF ;
XGINew_SetReg1( pVBInfo->Part4Port , 0x11 , temp ) ;
@@ -169,284 +128,6 @@ BOOLEAN XGINew_Sense( USHORT tempbx , USHORT tempcx, PVB_DEVICE_INFO pVBInfo )
return( 0 ) ;
}
-#ifdef WIN2000
-/* --------------------------------------------------------------------- */
-/* Function : XGI_SenseLCD */
-/* Input : */
-/* Output : */
-/* Description : */
-/* --------------------------------------------------------------------- */
-UCHAR XGI_SenseLCD( PHW_DEVICE_EXTENSION pHWDE, PVB_DEVICE_INFO pVBInfo)
-{
- USHORT tempax , tempbx , tempcx ;
- UCHAR SoftSetting = XGI330_SoftSetting ;
-
- if ( pVBInfo->VBType & ( VB_XGI301LV | VB_XGI302LV ) )
- return( 1 ) ;
-
-
- if ( SoftSetting & HotPlugFunction ) /* Hot Plug Detection */
- {
- XGINew_SetRegAND( pVBInfo->Part4Port , 0x0F , 0x3F ) ;
- tempbx = 0 ;
- tempcx = 0x9010 ;
- if ( XGINew_Sense( tempbx , tempcx, pVBInfo ) )
- return( 1 ) ;
-
- return( 0 ) ;
- }
- else /* Get LCD Info from EDID */
- return(XGI_GetLCDDDCInfo(pHWDE, pVBInfo));
-}
-
-
-/* --------------------------------------------------------------------- */
-/* Function : XGI_GetLCDDDCInfo */
-/* Input : */
-/* Output : */
-/* Description : */
-/* --------------------------------------------------------------------- */
-UCHAR XGI_GetLCDDDCInfo( PHW_DEVICE_EXTENSION pHWDE , PVB_DEVICE_INFO pVBInfo)
-{
- UCHAR tempah , tempbl , tempbh ;
- USHORT tempbx , temp ;
- UCHAR pjEDIDBuf[ 256 ] ;
- ULONG ulBufferSize = 256 ;
- UCHAR bMASK_OUTPUTSTATE_CRT2LCD = 2 ; /* 0423 shampoo */
-
- bGetDdcInfo( pHWDE , MASK_OUTPUTSTATE_CRT2LCD , pjEDIDBuf , ulBufferSize ) ;
- if ( ( *( ( PULONG )pjEDIDBuf ) == 0xFFFFFF00 ) && ( *( ( PULONG )( pjEDIDBuf + 4 ) ) == 0x00FFFFFF ) )
- {
- tempah = Panel1024x768 ;
- tempbl=( *( pjEDIDBuf + 0x3A ) ) & 0xf0 ;
-
- if ( tempbl != 0x40 )
- {
- tempah = Panel1600x1200 ;
- if ( tempbl != 0x60 )
- {
- tempah = Panel1280x1024 ;
- tempbh = ( *( pjEDIDBuf + 0x3B ) ) ;
- if ( tempbh != 0x00 )
- {
- tempah = Panel1280x960 ;
- if ( tempbh != 0x0C0 )
- {
- tempbx = ( ( *( pjEDIDBuf + 0x24 ) ) << 8 ) | ( *( pjEDIDBuf + 0x23 ) ) ;
- tempah = Panel1280x1024 ;
- if ( !( tempbx & 0x0100 ) )
- {
- tempah = Panel1024x768 ;
- if ( !( tempbx & 0x0E00 ) )
- {
- tempah = Panel1280x1024 ;
- }
- }
- }
-
- if ( tempbx & 0x00FF )
- {
- temp = ScalingLCD ;
- XGINew_SetRegOR( pVBInfo->P3d4 , 0x37 , temp ) ;
- }
- }
- }
- }
- XGINew_SetRegANDOR( pVBInfo->P3d4 , 0x36 , ( ~0x07 ) , tempah ) ;
- tempah = ( ( *( pjEDIDBuf + 0x47 ) ) & 0x06 ) ; /* Polarity */
- tempah = ( tempah ^ 0x06 ) << 4 ;
- tempah |= LCDSync ;
- XGINew_SetRegANDOR( pVBInfo->P3d4 , 0x37 , ( ~LCDSyncBit ) , tempah ) ;
- tempbh= XGINew_GetReg1( pVBInfo->P3d4 , 0x36 ) ;
- tempbh &= 0x07 ;
- if ( tempbh == Panel1280x960 )
- XGINew_SetRegAND( pVBInfo->P3d4 , 0x37 , 0x0E ) ;
- }
- else if ( *pjEDIDBuf == 0x20 )
- {
- tempah = Panel1024x768 ;
- XGINew_SetRegANDOR( pVBInfo->P3d4 , 0x36 , ( ~0x07 ) , tempah ) ;
- }
- else
- {
- return( 0 ) ;
- }
-
- return( 1 ) ;
-}
-
-
-/* --------------------------------------------------------------------- */
-/* Function : XGI_DySense */
-/* Input : */
-/* Output : */
-/* Description : */
-/* --------------------------------------------------------------------- */
-BOOLEAN XGI_DySense( PHW_DEVICE_EXTENSION pHWDE , PUCHAR ujConnectStatus)
-{
- UCHAR pre_CRD,pre_SR1E , pre_Part2_0 , pre_Part4_D ;
- USHORT tempax , tempbx , tempcx , pushax , temp ;
- VB_DEVICE_INFO VBINF;
- PVB_DEVICE_INFO pVBInfo = &VBINF;
- UCHAR OutputSelect = XGI330_OutputSelect ;
- PXGI_HW_DEVICE_INFO HwDeviceExtension= pHWDE->pXGIHWDE ;
- UCHAR bConnectStatus = 0 ;
- pVBInfo->BaseAddr = HwDeviceExtension->pjIOAddress ;
- pVBInfo->ROMAddr = pHWDE->pjVirtualRomBase ;
-
- pVBInfo->P3c2 = pVBInfo->BaseAddr + 0x12 ;
- pVBInfo->P3c4 = pVBInfo->BaseAddr + 0x14 ;
- pVBInfo->P3d4 = pVBInfo->BaseAddr + 0x24 ;
- pVBInfo->Part2Port = pVBInfo->BaseAddr + XGI_CRT2_PORT_10 ;
- pVBInfo->Part4Port = pVBInfo->BaseAddr + XGI_CRT2_PORT_14 ;
- pushax = XGINew_GetReg1( pVBInfo->P3d4 , 0x17 ) ; /* 0512 Fix Dysense hanged */
- temp = ( pushax & 0x00FF ) | 0x80 ;
- XGINew_SetRegOR( pVBInfo->P3d4 , 0x17 , temp ) ;
- XGINew_SetReg1( pVBInfo->P3c4 , 0x05 , 0x86 ) ;
- /* beginning of dynamic sense CRT1 */
-
- pVBInfo->IF_DEF_CH7007 = 0;
- if (pHWDE->bCH7007)
- {
- InitTo330Pointer( pHWDE->pXGIHWDE->jChipType, pVBInfo ) ;
- HwDeviceExtension->pDevice = (PVOID)pHWDE;
- pVBInfo->IF_DEF_CH7007 = 1;
- /* [Billy] 2007/05/14 For CH7007 */
- if ( pVBInfo->IF_DEF_CH7007 == 1 )
- {
- bConnectStatus = SenseCHTV(HwDeviceExtension->pDevice) ; /* 07/05/28 */
- XGINew_SetRegANDOR( pVBInfo->P3d4 , 0x32 , ~0x03 , (UCHAR)bConnectStatus ) ;
- }
- }
- if(( pHWDE->jChipID >= XG40 ) || ( pHWDE->jChipID >= XG20 ))
- {
-
- if ( pHWDE->jChipID >= XG40 )
- XGINew_SetReg1( pVBInfo->P3d4 , 0x57 , 0x4A ) ; /* write sense pattern 30->4a */
- else
- XGINew_SetReg1( pVBInfo->P3d4 , 0x57 , 0x5F ) ; /* write sense pattern */
-
- XGINew_SetRegANDOR( pVBInfo->P3d4 , 0x53 , 0xFF , 0x02 ) ; /* enable sense DAC */
- XGI_WaitDisply(pVBInfo) ;
-
- if(XGINew_GetReg2( pVBInfo->P3c2 ) & 0x10 )
- bConnectStatus |= Monitor1Sense ;
-
- XGINew_SetRegAND( pVBInfo->P3d4 , 0x53 , 0xFD ) ; /* disable sense DAC */
- XGINew_SetRegAND( pVBInfo->P3d4 , 0x57 , 0x00 ) ; /* clear sense pattern */
-
-
- /* ---------- End of dynamic sense CRT1 ----------- */
-
- /* ---------- beginning of dynamic sense VB ------------ */
- pre_SR1E = XGINew_GetReg1( pVBInfo->P3c4 , 0x1E ) ;
- XGINew_SetRegOR( pVBInfo->P3c4 , 0x1E , 0x20 ) ; /* Enable CRT2,work-a-round for 301B/301LV/302LV */
- pre_Part2_0 = XGINew_GetReg1( pVBInfo->Part2Port , 0x00 ) ;
- pre_Part4_D = XGINew_GetReg1( pVBInfo->Part4Port , 0x0D ) ;
-
- if ( XGI_Is301C( pVBInfo ) ) /* 301C only */
- XGINew_SetRegANDOR( pVBInfo->Part4Port , 0x0D , ~0x07 , 0x01 ) ; /* Set Part4 0x0D D[2:0] to 001b */
-
- /* tempax = 0 ; */
- if ( !XGI_Is301LV( pVBInfo ) )
- {
- tempbx = XGI330_RGBSenseData2 ;
- tempcx = 0x0E08 ;
- if(XGINew_Sense( tempbx , tempcx, pVBInfo ) )
- {
- bConnectStatus |= Monitor2Sense ;
- if ( OutputSelect & SetSCARTOutput )
- {
- bConnectStatus ^= ( Monitor2Sense | SCARTSense ) ;
- }
- }
- }
- if ( XGI_Is301C( pVBInfo ) ) /* 301C only */
- XGINew_SetRegOR( pVBInfo->Part4Port , 0x0D , 0x04 ) ; /* Set Part4 0x0D D[2]=1 for dynamic sense */
-
- if ( ( XGINew_Is301B( pVBInfo ) ) )
- XGINew_SetRegOR( pVBInfo->Part2Port , 0x00 , 0x0C ) ; /* ????????? */
-
- if ( XGINew_SenseHiTV( HwDeviceExtension , pVBInfo) ) /* add by kuku for Dysense HiTV //start */
- {
- bConnectStatus|= YPbPrSense ;
- }
- else
- {
- tempbx = XGI330_YCSenseData2 ; /* Y/C Sense Data Ptr */
- tempcx = 0x0604 ;
- if ( XGINew_Sense( tempbx , tempcx , pVBInfo) )
- bConnectStatus |= SVIDEOSense ;
-
- if ( OutputSelect & BoardTVType )
- {
- tempbx = XGI330_VideoSenseData2 ;
- tempcx = 0x0804 ;
- if ( XGINew_Sense(tempbx , tempcx, pVBInfo) )
- bConnectStatus|= AVIDEOSense ;
- }
- else
- {
- if ( !( bConnectStatus & SVIDEOSense ) )
- {
- tempbx = XGI330_VideoSenseData2 ;
- tempcx = 0x0804 ;
- if ( XGINew_Sense( tempbx , tempcx, pVBInfo ) )
- bConnectStatus |= AVIDEOSense ;
- }
- }
- } /* end */
- /* DySenseVBCnt */
-
- tempbx = 0 ;
- tempcx = 0 ;
- XGINew_Sense(tempbx , tempcx, pVBInfo ) ;
-
- if ( !( bConnectStatus & Monitor2Sense ) )
- {
- if ( XGI_SenseLCD( pHWDE , pVBInfo ) )
- bConnectStatus |= LCDSense ;
- }
-
- XGINew_SetRegANDOR( pVBInfo->P3d4 , 0x32 , ~( AVIDEOSense | SVIDEOSense | LCDSense | Monitor2Sense | Monitor1Sense ) , bConnectStatus ) ;
-
- XGINew_SetReg1( pVBInfo->Part4Port , 0x0D , pre_Part4_D ) ;
- XGINew_SetReg1( pVBInfo->Part2Port , 0x00 , pre_Part2_0 ) ;
- XGINew_SetReg1( pVBInfo->P3c4 , 0x1E , pre_SR1E ) ;
-
- if ( XGI_Is301C( pVBInfo ) ) /* 301C only */
- {
- tempax = XGINew_GetReg1( pVBInfo->Part2Port , 0x00 ) ;
- if ( tempax & 0x20 )
- {
- /* Reset VBPro */
- for( tempcx = 2 ; tempcx > 0 ; tempcx-- )
- {
- tempax ^= 0x20 ;
- XGINew_SetReg1( pVBInfo->Part2Port , 0x00 , tempax ) ;
- }
- }
- }
- /* End of dynamic sense VB */
- }
- else
- {
- XGI_SenseCRT1(pVBInfo) ;
- XGI_GetSenseStatus( HwDeviceExtension, pVBInfo ) ; /* sense CRT2 */
- bConnectStatus = XGINew_GetReg1( pVBInfo->P3d4 , 0x32 ) ;
- }
- temp = pushax & 0x00FF ; /* 0512 Fix Dysense hanged */
- XGINew_SetReg1( pVBInfo->P3d4 , 0x17 , temp ) ;
- if ( bConnectStatus )
- {
- *ujConnectStatus = bConnectStatus ;
- return( 1 ) ;
- }
- else
- return( 0 ) ;
-}
-
-#endif /* WIN2000 */
/* --------------------------------------------------------------------- */
/* Function : XGISetDPMS */
@@ -454,13 +135,14 @@ BOOLEAN XGI_DySense( PHW_DEVICE_EXTENSION pHWDE , PUCHAR ujConnectStatus)
/* Output : */
/* Description : */
/* --------------------------------------------------------------------- */
-VOID XGISetDPMS( PXGI_HW_DEVICE_INFO pXGIHWDE , ULONG VESA_POWER_STATE )
+void XGISetDPMS(struct xgi_hw_device_info *pXGIHWDE,
+ unsigned long VESA_POWER_STATE)
{
- USHORT ModeNo, ModeIdIndex ;
- UCHAR temp ;
- VB_DEVICE_INFO VBINF;
- PVB_DEVICE_INFO pVBInfo = &VBINF;
- pVBInfo->BaseAddr = (ULONG)pXGIHWDE->pjIOAddress ;
+ unsigned short ModeNo, ModeIdIndex;
+ unsigned char temp;
+ struct vb_device_info VBINF;
+ struct vb_device_info *pVBInfo = &VBINF;
+ pVBInfo->BaseAddr = (unsigned long)pXGIHWDE->pjIOAddress ;
pVBInfo->ROMAddr = pXGIHWDE->pjVirtualRomBase ;
@@ -527,18 +209,18 @@ VOID XGISetDPMS( PXGI_HW_DEVICE_INFO pXGIHWDE , ULONG VESA_POWER_STATE )
}
if ( VESA_POWER_STATE == 0x00000400 )
- XGINew_SetReg1( pVBInfo->Part4Port , 0x31 , ( UCHAR )( XGINew_GetReg1( pVBInfo->Part4Port , 0x31 ) & 0xFE ) ) ;
+ XGINew_SetReg1(pVBInfo->Part4Port, 0x31, (unsigned char)(XGINew_GetReg1(pVBInfo->Part4Port, 0x31) & 0xFE));
else
- XGINew_SetReg1( pVBInfo->Part4Port , 0x31 , ( UCHAR )( XGINew_GetReg1( pVBInfo->Part4Port , 0x31 ) | 0x01 ) ) ;
+ XGINew_SetReg1(pVBInfo->Part4Port, 0x31, (unsigned char)(XGINew_GetReg1(pVBInfo->Part4Port, 0x31) | 0x01));
- temp = ( UCHAR )XGINew_GetReg1( pVBInfo->P3c4 , 0x1f ) ;
+ temp = (unsigned char)XGINew_GetReg1(pVBInfo->P3c4, 0x1f);
temp &= 0x3f ;
switch ( VESA_POWER_STATE )
{
case 0x00000000: /* on */
if ( ( pXGIHWDE->ujVBChipID == VB_CHIP_301 ) || ( pXGIHWDE->ujVBChipID == VB_CHIP_302 ) )
{
- XGINew_SetReg1( pVBInfo->P3c4 , 0x1f , ( UCHAR )( temp | 0x00 ) ) ;
+ XGINew_SetReg1(pVBInfo->P3c4, 0x1f, (unsigned char)(temp | 0x00));
XGI_EnableBridge( pXGIHWDE, pVBInfo ) ;
}
else
@@ -596,7 +278,7 @@ VOID XGISetDPMS( PXGI_HW_DEVICE_INFO pXGIHWDE , ULONG VESA_POWER_STATE )
XGI_DisplayOff( pXGIHWDE, pVBInfo );
}
- XGINew_SetReg1( pVBInfo->P3c4 , 0x1f , ( UCHAR )( temp | 0x40 ) ) ;
+ XGINew_SetReg1(pVBInfo->P3c4, 0x1f, (unsigned char)(temp | 0x40));
break ;
case 0x00000200: /* suspend */
if ( pXGIHWDE->jChipType == XG21 )
@@ -609,12 +291,12 @@ VOID XGISetDPMS( PXGI_HW_DEVICE_INFO pXGIHWDE , ULONG VESA_POWER_STATE )
XGI_DisplayOff( pXGIHWDE, pVBInfo );
XGI_XG27BLSignalVDD( 0x20 , 0x00, pVBInfo ) ; /* LVDS signal off */
}
- XGINew_SetReg1( pVBInfo->P3c4 , 0x1f , ( UCHAR )( temp | 0x80 ) ) ;
+ XGINew_SetReg1(pVBInfo->P3c4, 0x1f, (unsigned char)(temp | 0x80));
break ;
case 0x00000400: /* off */
if ( (pXGIHWDE->ujVBChipID == VB_CHIP_301 ) || ( pXGIHWDE->ujVBChipID == VB_CHIP_302 ) )
{
- XGINew_SetReg1( pVBInfo->P3c4 , 0x1f , ( UCHAR )( temp | 0xc0 ) ) ;
+ XGINew_SetReg1(pVBInfo->P3c4, 0x1f, (unsigned char)(temp | 0xc0));
XGI_DisableBridge( pXGIHWDE, pVBInfo ) ;
}
else
@@ -677,12 +359,12 @@ VOID XGISetDPMS( PXGI_HW_DEVICE_INFO pXGIHWDE , ULONG VESA_POWER_STATE )
/* Output : */
/* Description : */
/* --------------------------------------------------------------------- */
-void XGI_GetSenseStatus( PXGI_HW_DEVICE_INFO HwDeviceExtension , PVB_DEVICE_INFO pVBInfo)
+void XGI_GetSenseStatus(struct xgi_hw_device_info *HwDeviceExtension, struct vb_device_info *pVBInfo)
{
- USHORT tempax = 0 , tempbx , tempcx , temp ,
+ unsigned short tempax = 0 , tempbx , tempcx , temp ,
P2reg0 = 0 , SenseModeNo = 0 , OutputSelect = *pVBInfo->pOutputSelect ,
ModeIdIndex , i ;
- pVBInfo->BaseAddr = (ULONG)HwDeviceExtension->pjIOAddress ;
+ pVBInfo->BaseAddr = (unsigned long)HwDeviceExtension->pjIOAddress ;
if ( pVBInfo->IF_DEF_LVDS == 1 )
{
@@ -876,10 +558,11 @@ void XGI_GetSenseStatus( PXGI_HW_DEVICE_INFO HwDeviceExtension , PVB_DEVICE_INFO
/* Output : */
/* Description : */
/* --------------------------------------------------------------------- */
-USHORT XGINew_SenseLCD( PXGI_HW_DEVICE_INFO HwDeviceExtension ,PVB_DEVICE_INFO pVBInfo)
+unsigned short XGINew_SenseLCD(struct xgi_hw_device_info *HwDeviceExtension,
+ struct vb_device_info *pVBInfo)
{
- /* USHORT SoftSetting ; */
- USHORT temp ;
+ /* unsigned short SoftSetting ; */
+ unsigned short temp ;
if ( ( HwDeviceExtension->jChipType >= XG20 ) || ( HwDeviceExtension->jChipType >= XG40 ) )
temp = 0 ;
@@ -899,9 +582,9 @@ USHORT XGINew_SenseLCD( PXGI_HW_DEVICE_INFO HwDeviceExtension ,PVB_DEVICE_INFO p
/* Output : */
/* Description : */
/* --------------------------------------------------------------------- */
-BOOLEAN XGINew_GetLCDDDCInfo( PXGI_HW_DEVICE_INFO HwDeviceExtension,PVB_DEVICE_INFO pVBInfo)
+unsigned char XGINew_GetLCDDDCInfo(struct xgi_hw_device_info *HwDeviceExtension, struct vb_device_info *pVBInfo)
{
- USHORT temp ;
+ unsigned short temp ;
/* add lcd sense */
if ( HwDeviceExtension->ulCRT2LCDType == LCD_UNKNOWN )
@@ -910,7 +593,7 @@ BOOLEAN XGINew_GetLCDDDCInfo( PXGI_HW_DEVICE_INFO HwDeviceExtension,PVB_DEVICE_I
}
else
{
- temp = ( USHORT )HwDeviceExtension->ulCRT2LCDType ;
+ temp = (unsigned short)HwDeviceExtension->ulCRT2LCDType ;
switch( HwDeviceExtension->ulCRT2LCDType )
{
case LCD_INVALID:
@@ -952,26 +635,27 @@ BOOLEAN XGINew_GetLCDDDCInfo( PXGI_HW_DEVICE_INFO HwDeviceExtension,PVB_DEVICE_I
/* Output : */
/* Description : */
/* --------------------------------------------------------------------- */
-BOOLEAN XGINew_GetPanelID(PVB_DEVICE_INFO pVBInfo )
+unsigned char XGINew_GetPanelID(struct vb_device_info *pVBInfo)
{
- USHORT PanelTypeTable[ 16 ] = { SyncNN | PanelRGB18Bit | Panel800x600 | _PanelType00 ,
- SyncNN | PanelRGB18Bit | Panel1024x768 | _PanelType01 ,
- SyncNN | PanelRGB18Bit | Panel800x600 | _PanelType02 ,
- SyncNN | PanelRGB18Bit | Panel640x480 | _PanelType03 ,
- SyncNN | PanelRGB18Bit | Panel1024x768 | _PanelType04 ,
- SyncNN | PanelRGB18Bit | Panel1024x768 | _PanelType05 ,
- SyncNN | PanelRGB18Bit | Panel1024x768 | _PanelType06 ,
- SyncNN | PanelRGB24Bit | Panel1024x768 | _PanelType07 ,
- SyncNN | PanelRGB18Bit | Panel800x600 | _PanelType08 ,
- SyncNN | PanelRGB18Bit | Panel1024x768 | _PanelType09 ,
- SyncNN | PanelRGB18Bit | Panel800x600 | _PanelType0A ,
- SyncNN | PanelRGB18Bit | Panel1024x768 | _PanelType0B ,
- SyncNN | PanelRGB18Bit | Panel1024x768 | _PanelType0C ,
- SyncNN | PanelRGB24Bit | Panel1024x768 | _PanelType0D ,
- SyncNN | PanelRGB18Bit | Panel1024x768 | _PanelType0E ,
- SyncNN | PanelRGB18Bit | Panel1024x768 | _PanelType0F } ;
- USHORT tempax , tempbx , temp ;
- /* USHORT return_flag ; */
+ unsigned short PanelTypeTable[16] = {
+ SyncNN | PanelRGB18Bit | Panel800x600 | _PanelType00,
+ SyncNN | PanelRGB18Bit | Panel1024x768 | _PanelType01,
+ SyncNN | PanelRGB18Bit | Panel800x600 | _PanelType02,
+ SyncNN | PanelRGB18Bit | Panel640x480 | _PanelType03,
+ SyncNN | PanelRGB18Bit | Panel1024x768 | _PanelType04,
+ SyncNN | PanelRGB18Bit | Panel1024x768 | _PanelType05,
+ SyncNN | PanelRGB18Bit | Panel1024x768 | _PanelType06,
+ SyncNN | PanelRGB24Bit | Panel1024x768 | _PanelType07,
+ SyncNN | PanelRGB18Bit | Panel800x600 | _PanelType08,
+ SyncNN | PanelRGB18Bit | Panel1024x768 | _PanelType09,
+ SyncNN | PanelRGB18Bit | Panel800x600 | _PanelType0A,
+ SyncNN | PanelRGB18Bit | Panel1024x768 | _PanelType0B,
+ SyncNN | PanelRGB18Bit | Panel1024x768 | _PanelType0C,
+ SyncNN | PanelRGB24Bit | Panel1024x768 | _PanelType0D,
+ SyncNN | PanelRGB18Bit | Panel1024x768 | _PanelType0E,
+ SyncNN | PanelRGB18Bit | Panel1024x768 | _PanelType0F };
+ unsigned short tempax , tempbx, temp;
+ /* unsigned short return_flag ; */
tempax = XGINew_GetReg1( pVBInfo->P3c4 , 0x1A ) ;
tempbx = tempax & 0x1E ;
@@ -1024,9 +708,9 @@ BOOLEAN XGINew_GetPanelID(PVB_DEVICE_INFO pVBInfo )
/* Output : */
/* Description : */
/* --------------------------------------------------------------------- */
-BOOLEAN XGINew_BridgeIsEnable( PXGI_HW_DEVICE_INFO HwDeviceExtension ,PVB_DEVICE_INFO pVBInfo)
+unsigned char XGINew_BridgeIsEnable(struct xgi_hw_device_info *HwDeviceExtension, struct vb_device_info *pVBInfo)
{
- USHORT flag ;
+ unsigned short flag ;
if ( XGI_BridgeIsOn( pVBInfo ) == 0 )
{
@@ -1051,9 +735,9 @@ BOOLEAN XGINew_BridgeIsEnable( PXGI_HW_DEVICE_INFO HwDeviceExtension ,PVB_DEVICE
/* Output : */
/* Description : */
/* ------------------------------------------------------ */
-BOOLEAN XGINew_SenseHiTV( PXGI_HW_DEVICE_INFO HwDeviceExtension , PVB_DEVICE_INFO pVBInfo )
+unsigned char XGINew_SenseHiTV(struct xgi_hw_device_info *HwDeviceExtension, struct vb_device_info *pVBInfo)
{
- USHORT tempbx , tempcx , temp , i , tempch;
+ unsigned short tempbx , tempcx , temp , i , tempch;
tempbx = *pVBInfo->pYCSenseData2 ;
@@ -1132,14 +816,14 @@ BOOLEAN XGINew_SenseHiTV( PXGI_HW_DEVICE_INFO HwDeviceExtension , PVB_DEVICE_INF
; DX: PAnel V. resolution
;-----------------------------------------------------------------------------
*/
-void XGI_XG21Fun14Sub70( PVB_DEVICE_INFO pVBInfo , PX86_REGS pBiosArguments )
+void XGI_XG21Fun14Sub70(struct vb_device_info *pVBInfo, PX86_REGS pBiosArguments)
{
- USHORT ModeIdIndex;
- USHORT ModeNo;
+ unsigned short ModeIdIndex;
+ unsigned short ModeNo;
- USHORT EModeCount;
- USHORT lvdstableindex;
+ unsigned short EModeCount;
+ unsigned short lvdstableindex;
lvdstableindex = XGI_GetLVDSOEMTableIndex( pVBInfo );
pBiosArguments->h.bl = 0x81;
@@ -1153,7 +837,7 @@ void XGI_XG21Fun14Sub70( PVB_DEVICE_INFO pVBInfo , PX86_REGS pBiosArguments )
ModeNo = pVBInfo->EModeIDTable[ ModeIdIndex ].Ext_ModeID;
if ( pVBInfo->EModeIDTable[ ModeIdIndex ].Ext_ModeID == 0xFF )
{
- pBiosArguments->h.bh = (UCHAR) EModeCount;
+ pBiosArguments->h.bh = (unsigned char) EModeCount;
return;
}
if ( !XGI_XG21CheckLVDSMode( ModeNo , ModeIdIndex, pVBInfo) )
@@ -1175,13 +859,13 @@ void XGI_XG21Fun14Sub70( PVB_DEVICE_INFO pVBInfo , PX86_REGS pBiosArguments )
;
;-----------------------------------------------------------------------------
*/
-void XGI_XG21Fun14Sub71( PVB_DEVICE_INFO pVBInfo , PX86_REGS pBiosArguments )
+void XGI_XG21Fun14Sub71(struct vb_device_info *pVBInfo, PX86_REGS pBiosArguments)
{
- USHORT EModeCount;
- USHORT ModeIdIndex,resindex;
- USHORT ModeNo;
- USHORT EModeIndex = pBiosArguments->h.bh;
+ unsigned short EModeCount;
+ unsigned short ModeIdIndex, resindex;
+ unsigned short ModeNo;
+ unsigned short EModeIndex = pBiosArguments->h.bh;
EModeCount = 0;
for( ModeIdIndex = 0 ; ; ModeIdIndex ++ )
@@ -1199,7 +883,7 @@ void XGI_XG21Fun14Sub71( PVB_DEVICE_INFO pVBInfo , PX86_REGS pBiosArguments )
if (EModeCount == EModeIndex)
{
resindex = XGI_GetResInfo( ModeNo , ModeIdIndex, pVBInfo ) ;
- pBiosArguments->h.bl = (UCHAR) ModeNo;
+ pBiosArguments->h.bl = (unsigned char) ModeNo;
pBiosArguments->x.cx = pVBInfo->ModeResInfo[ resindex ].HTotal ; /* xres->ax */
pBiosArguments->x.dx = pVBInfo->ModeResInfo[ resindex ].VTotal ; /* yres->bx */
pBiosArguments->x.ax = 0x0014;
@@ -1221,10 +905,10 @@ void XGI_XG21Fun14Sub71( PVB_DEVICE_INFO pVBInfo , PX86_REGS pBiosArguments )
;
;-----------------------------------------------------------------------------
*/
-void XGI_XG21Fun14Sub72( PVB_DEVICE_INFO pVBInfo , PX86_REGS pBiosArguments )
+void XGI_XG21Fun14Sub72(struct vb_device_info *pVBInfo, PX86_REGS pBiosArguments)
{
- USHORT ModeIdIndex,resindex;
- USHORT ModeNo;
+ unsigned short ModeIdIndex, resindex;
+ unsigned short ModeNo;
ModeNo = pBiosArguments->h.bl ;
@@ -1280,11 +964,11 @@ void XGI_XG21Fun14Sub72( PVB_DEVICE_INFO pVBInfo , PX86_REGS pBiosArguments )
; BX[6]: *Value1 D[6] Panel H. Polarity
;-----------------------------------------------------------------------------
*/
-void XGI_XG21Fun14Sub73( PVB_DEVICE_INFO pVBInfo , PX86_REGS pBiosArguments )
+void XGI_XG21Fun14Sub73(struct vb_device_info *pVBInfo, PX86_REGS pBiosArguments)
{
- UCHAR Select;
+ unsigned char Select;
- USHORT lvdstableindex;
+ unsigned short lvdstableindex;
lvdstableindex = XGI_GetLVDSOEMTableIndex( pVBInfo );
Select = pBiosArguments->h.bl;
@@ -1314,10 +998,10 @@ void XGI_XG21Fun14Sub73( PVB_DEVICE_INFO pVBInfo , PX86_REGS pBiosArguments )
}
-void XGI_XG21Fun14( PXGI_HW_DEVICE_INFO pXGIHWDE, PX86_REGS pBiosArguments)
+void XGI_XG21Fun14(struct xgi_hw_device_info *pXGIHWDE, PX86_REGS pBiosArguments)
{
- VB_DEVICE_INFO VBINF;
- PVB_DEVICE_INFO pVBInfo = &VBINF;
+ struct vb_device_info VBINF;
+ struct vb_device_info *pVBInfo = &VBINF;
pVBInfo->IF_DEF_LVDS = 0 ;
pVBInfo->IF_DEF_CH7005 = 0 ;
diff --git a/drivers/staging/xgifb/vb_ext.h b/drivers/staging/xgifb/vb_ext.h
index 9a72f5ecb71..5cc4d12c225 100644
--- a/drivers/staging/xgifb/vb_ext.h
+++ b/drivers/staging/xgifb/vb_ext.h
@@ -2,15 +2,17 @@
#define _VBEXT_
struct DWORDREGS {
- ULONG Eax, Ebx, Ecx, Edx, Esi, Edi, Ebp;
+ unsigned long Eax, Ebx, Ecx, Edx, Esi, Edi, Ebp;
};
struct WORDREGS {
- USHORT ax, hi_ax, bx, hi_bx, cx, hi_cx, dx, hi_dx, si, hi_si, di ,hi_di, bp, hi_bp;
+ unsigned short ax, hi_ax, bx, hi_bx, cx, hi_cx, dx, hi_dx, si,
+ hi_si, di, hi_di, bp, hi_bp;
};
struct BYTEREGS {
- UCHAR al, ah, hi_al, hi_ah, bl, bh, hi_bl, hi_bh, cl, ch, hi_cl, hi_ch, dl, dh, hi_dl, hi_dh;
+ unsigned char al, ah, hi_al, hi_ah, bl, bh, hi_bl, hi_bh, cl, ch,
+ hi_cl, hi_ch, dl, dh, hi_dl, hi_dh;
};
typedef union _X86_REGS {
@@ -19,14 +21,14 @@ typedef union _X86_REGS {
struct BYTEREGS h;
} X86_REGS, *PX86_REGS;
-extern void XGI_XG21Fun14( PXGI_HW_DEVICE_INFO pXGIHWDE, PX86_REGS pBiosArguments);
-extern void XGISetDPMS( PXGI_HW_DEVICE_INFO pXGIHWDE , ULONG VESA_POWER_STATE ) ;
-extern void XGI_GetSenseStatus( PXGI_HW_DEVICE_INFO HwDeviceExtension , PVB_DEVICE_INFO pVBInfo );
-extern void XGINew_SetModeScratch ( PXGI_HW_DEVICE_INFO HwDeviceExtension , PVB_DEVICE_INFO pVBInfo ) ;
-extern void ReadVBIOSTablData( UCHAR ChipType , PVB_DEVICE_INFO pVBInfo);
-extern USHORT XGINew_SenseLCD(PXGI_HW_DEVICE_INFO,PVB_DEVICE_INFO pVBInfo);
-#ifdef WIN2000
-extern BOOLEAN XGI_DySense( PHW_DEVICE_EXTENSION pHWDE , PUCHAR ujConnectStatus );
-#endif /* WIN2000 */
+extern void XGI_XG21Fun14(struct xgi_hw_device_info *pXGIHWDE, PX86_REGS pBiosArguments);
+extern void XGISetDPMS(struct xgi_hw_device_info *pXGIHWDE,
+ unsigned long VESA_POWER_STATE);
+extern void XGI_GetSenseStatus(struct xgi_hw_device_info *HwDeviceExtension, struct vb_device_info *pVBInfo);
+extern void XGINew_SetModeScratch(struct xgi_hw_device_info *HwDeviceExtension, struct vb_device_info *pVBInfo) ;
+extern void ReadVBIOSTablData(unsigned char ChipType,
+ struct vb_device_info *pVBInfo);
+extern unsigned short XGINew_SenseLCD(struct xgi_hw_device_info *,
+ struct vb_device_info *pVBInfo);
#endif
diff --git a/drivers/staging/xgifb/vb_init.c b/drivers/staging/xgifb/vb_init.c
index b85ca9ba807..e02722d05f6 100644
--- a/drivers/staging/xgifb/vb_init.c
+++ b/drivers/staging/xgifb/vb_init.c
@@ -1,29 +1,9 @@
-#include "osdef.h"
#include "vgatypes.h"
-
-#ifdef LINUX_KERNEL
#include <linux/version.h>
#include <linux/types.h>
#include <linux/delay.h> /* udelay */
#include "XGIfb.h"
-/*#if LINUX_VERSxION_CODE >= KERNEL_VERSION(2,5,0)
-#include <video/XGIfb.h>
-#else
-#include <linux/XGIfb.h>
-#endif */
-#endif
-
-#ifdef WIN2000
-#include <dderror.h>
-#include <devioctl.h>
-#include <miniport.h>
-#include <ntddvdeo.h>
-#include <video.h>
-#include "xgiv.h"
-#include "dd_i2c.h"
-#include "tools.h"
-#endif
#include "vb_def.h"
#include "vb_struct.h"
@@ -32,123 +12,105 @@
#include "vb_init.h"
#include "vb_ext.h"
-#ifdef LINUX_XF86
-#include "xf86.h"
-#include "xf86PciInfo.h"
-#include "xgi.h"
-#include "xgi_regs.h"
-#endif
-#ifdef LINUX_KERNEL
#include <asm/io.h>
-#include <linux/types.h>
-#endif
-UCHAR XGINew_ChannelAB,XGINew_DataBusWidth;
-
-USHORT XGINew_DRAMType[17][5]={{0x0C,0x0A,0x02,0x40,0x39},{0x0D,0x0A,0x01,0x40,0x48},
- {0x0C,0x09,0x02,0x20,0x35},{0x0D,0x09,0x01,0x20,0x44},
- {0x0C,0x08,0x02,0x10,0x31},{0x0D,0x08,0x01,0x10,0x40},
- {0x0C,0x0A,0x01,0x20,0x34},{0x0C,0x09,0x01,0x08,0x32},
- {0x0B,0x08,0x02,0x08,0x21},{0x0C,0x08,0x01,0x08,0x30},
- {0x0A,0x08,0x02,0x04,0x11},{0x0B,0x0A,0x01,0x10,0x28},
- {0x09,0x08,0x02,0x02,0x01},{0x0B,0x09,0x01,0x08,0x24},
- {0x0B,0x08,0x01,0x04,0x20},{0x0A,0x08,0x01,0x02,0x10},
- {0x09,0x08,0x01,0x01,0x00}};
-
-USHORT XGINew_SDRDRAM_TYPE[13][5]=
-{
-{ 2,12, 9,64,0x35},
-{ 1,13, 9,64,0x44},
-{ 2,12, 8,32,0x31},
-{ 2,11, 9,32,0x25},
-{ 1,12, 9,32,0x34},
-{ 1,13, 8,32,0x40},
-{ 2,11, 8,16,0x21},
-{ 1,12, 8,16,0x30},
-{ 1,11, 9,16,0x24},
-{ 1,11, 8, 8,0x20},
-{ 2, 9, 8, 4,0x01},
-{ 1,10, 8, 4,0x10},
-{ 1, 9, 8, 2,0x00}
-};
-
-USHORT XGINew_DDRDRAM_TYPE[4][5]=
-{
-{ 2,12, 9,64,0x35},
-{ 2,12, 8,32,0x31},
-{ 2,11, 8,16,0x21},
-{ 2, 9, 8, 4,0x01}
-};
-USHORT XGINew_DDRDRAM_TYPE340[4][5]=
-{
-{ 2,13, 9,64,0x45},
-{ 2,12, 9,32,0x35},
-{ 2,12, 8,16,0x31},
-{ 2,11, 8, 8,0x21}
-};
-USHORT XGINew_DDRDRAM_TYPE20[12][5]=
-{
-{ 2,14,11,128,0x5D},
-{ 2,14,10,64,0x59},
-{ 2,13,11,64,0x4D},
-{ 2,14, 9,32,0x55},
-{ 2,13,10,32,0x49},
-{ 2,12,11,32,0x3D},
-{ 2,14, 8,16,0x51},
-{ 2,13, 9,16,0x45},
-{ 2,12,10,16,0x39},
-{ 2,13, 8, 8,0x41},
-{ 2,12, 9, 8,0x35},
-{ 2,12, 8, 4,0x31}
-};
-
-void XGINew_SetDRAMSize_340(PXGI_HW_DEVICE_INFO, PVB_DEVICE_INFO);
-void XGINew_SetDRAMSize_310(PXGI_HW_DEVICE_INFO, PVB_DEVICE_INFO);
-void XGINew_SetMemoryClock(PXGI_HW_DEVICE_INFO HwDeviceExtension, PVB_DEVICE_INFO );
-void XGINew_SetDRAMModeRegister(PVB_DEVICE_INFO );
-void XGINew_SetDRAMModeRegister340( PXGI_HW_DEVICE_INFO HwDeviceExtension );
-void XGINew_SetDRAMDefaultRegister340(PXGI_HW_DEVICE_INFO HwDeviceExtension, ULONG, PVB_DEVICE_INFO );
-UCHAR XGINew_GetXG20DRAMType( PXGI_HW_DEVICE_INFO HwDeviceExtension , PVB_DEVICE_INFO pVBInfo);
-BOOLEAN XGIInitNew( PXGI_HW_DEVICE_INFO HwDeviceExtension) ;
-
-int XGINew_DDRSizing340( PXGI_HW_DEVICE_INFO, PVB_DEVICE_INFO );
-void XGINew_DisableRefresh( PXGI_HW_DEVICE_INFO ,PVB_DEVICE_INFO) ;
-void XGINew_CheckBusWidth_310( PVB_DEVICE_INFO) ;
-int XGINew_SDRSizing(PVB_DEVICE_INFO);
-int XGINew_DDRSizing( PVB_DEVICE_INFO );
-void XGINew_EnableRefresh( PXGI_HW_DEVICE_INFO, PVB_DEVICE_INFO);
+unsigned char XGINew_ChannelAB, XGINew_DataBusWidth;
+
+unsigned short XGINew_DRAMType[17][5] = {
+ {0x0C, 0x0A, 0x02, 0x40, 0x39}, {0x0D, 0x0A, 0x01, 0x40, 0x48},
+ {0x0C, 0x09, 0x02, 0x20, 0x35}, {0x0D, 0x09, 0x01, 0x20, 0x44},
+ {0x0C, 0x08, 0x02, 0x10, 0x31}, {0x0D, 0x08, 0x01, 0x10, 0x40},
+ {0x0C, 0x0A, 0x01, 0x20, 0x34}, {0x0C, 0x09, 0x01, 0x08, 0x32},
+ {0x0B, 0x08, 0x02, 0x08, 0x21}, {0x0C, 0x08, 0x01, 0x08, 0x30},
+ {0x0A, 0x08, 0x02, 0x04, 0x11}, {0x0B, 0x0A, 0x01, 0x10, 0x28},
+ {0x09, 0x08, 0x02, 0x02, 0x01}, {0x0B, 0x09, 0x01, 0x08, 0x24},
+ {0x0B, 0x08, 0x01, 0x04, 0x20}, {0x0A, 0x08, 0x01, 0x02, 0x10},
+ {0x09, 0x08, 0x01, 0x01, 0x00} };
+
+unsigned short XGINew_SDRDRAM_TYPE[13][5] = {
+ { 2, 12, 9, 64, 0x35},
+ { 1, 13, 9, 64, 0x44},
+ { 2, 12, 8, 32, 0x31},
+ { 2, 11, 9, 32, 0x25},
+ { 1, 12, 9, 32, 0x34},
+ { 1, 13, 8, 32, 0x40},
+ { 2, 11, 8, 16, 0x21},
+ { 1, 12, 8, 16, 0x30},
+ { 1, 11, 9, 16, 0x24},
+ { 1, 11, 8, 8, 0x20},
+ { 2, 9, 8, 4, 0x01},
+ { 1, 10, 8, 4, 0x10},
+ { 1, 9, 8, 2, 0x00} };
+
+unsigned short XGINew_DDRDRAM_TYPE[4][5] = {
+ { 2, 12, 9, 64, 0x35},
+ { 2, 12, 8, 32, 0x31},
+ { 2, 11, 8, 16, 0x21},
+ { 2, 9, 8, 4, 0x01} };
+
+unsigned short XGINew_DDRDRAM_TYPE340[4][5] = {
+ { 2, 13, 9, 64, 0x45},
+ { 2, 12, 9, 32, 0x35},
+ { 2, 12, 8, 16, 0x31},
+ { 2, 11, 8, 8, 0x21} };
+
+unsigned short XGINew_DDRDRAM_TYPE20[12][5] = {
+ { 2, 14, 11, 128, 0x5D},
+ { 2, 14, 10, 64, 0x59},
+ { 2, 13, 11, 64, 0x4D},
+ { 2, 14, 9, 32, 0x55},
+ { 2, 13, 10, 32, 0x49},
+ { 2, 12, 11, 32, 0x3D},
+ { 2, 14, 8, 16, 0x51},
+ { 2, 13, 9, 16, 0x45},
+ { 2, 12, 10, 16, 0x39},
+ { 2, 13, 8, 8, 0x41},
+ { 2, 12, 9, 8, 0x35},
+ { 2, 12, 8, 4, 0x31} };
+
+void XGINew_SetDRAMSize_340(struct xgi_hw_device_info *, struct vb_device_info *);
+void XGINew_SetDRAMSize_310(struct xgi_hw_device_info *, struct vb_device_info *);
+void XGINew_SetMemoryClock(struct xgi_hw_device_info *HwDeviceExtension, struct vb_device_info *);
+void XGINew_SetDRAMModeRegister(struct vb_device_info *);
+void XGINew_SetDRAMModeRegister340(struct xgi_hw_device_info *HwDeviceExtension);
+void XGINew_SetDRAMDefaultRegister340(struct xgi_hw_device_info *HwDeviceExtension,
+ unsigned long, struct vb_device_info *);
+unsigned char XGINew_GetXG20DRAMType(struct xgi_hw_device_info *HwDeviceExtension,
+ struct vb_device_info *pVBInfo);
+unsigned char XGIInitNew(struct xgi_hw_device_info *HwDeviceExtension);
+
+int XGINew_DDRSizing340(struct xgi_hw_device_info *, struct vb_device_info *);
+void XGINew_DisableRefresh(struct xgi_hw_device_info *, struct vb_device_info *) ;
+void XGINew_CheckBusWidth_310(struct vb_device_info *) ;
+int XGINew_SDRSizing(struct vb_device_info *);
+int XGINew_DDRSizing(struct vb_device_info *);
+void XGINew_EnableRefresh(struct xgi_hw_device_info *, struct vb_device_info *);
int XGINew_RAMType; /*int ModeIDOffset,StandTable,CRT1Table,ScreenOffset,REFIndex;*/
-ULONG UNIROM; /* UNIROM */
-BOOLEAN ChkLFB( PVB_DEVICE_INFO );
-void XGINew_Delay15us(ULONG);
-void SetPowerConsume (PXGI_HW_DEVICE_INFO HwDeviceExtension,ULONG XGI_P3d4Port);
-void ReadVBIOSTablData( UCHAR ChipType , PVB_DEVICE_INFO pVBInfo);
-void XGINew_DDR1x_MRS_XG20( ULONG P3c4 , PVB_DEVICE_INFO pVBInfo);
-void XGINew_SetDRAMModeRegister_XG20( PXGI_HW_DEVICE_INFO HwDeviceExtension );
-void XGINew_SetDRAMModeRegister_XG27( PXGI_HW_DEVICE_INFO HwDeviceExtension );
-void XGINew_ChkSenseStatus ( PXGI_HW_DEVICE_INFO HwDeviceExtension , PVB_DEVICE_INFO pVBInfo ) ;
-void XGINew_SetModeScratch ( PXGI_HW_DEVICE_INFO HwDeviceExtension , PVB_DEVICE_INFO pVBInfo ) ;
-void XGINew_GetXG21Sense(PXGI_HW_DEVICE_INFO HwDeviceExtension, PVB_DEVICE_INFO pVBInfo) ;
-UCHAR GetXG21FPBits(PVB_DEVICE_INFO pVBInfo);
-void XGINew_GetXG27Sense(PXGI_HW_DEVICE_INFO HwDeviceExtension, PVB_DEVICE_INFO pVBInfo) ;
-UCHAR GetXG27FPBits(PVB_DEVICE_INFO pVBInfo);
-
-#ifdef WIN2000
-/* [Billy] 2007/05/20 For CH7007 */
-extern UCHAR CH7007TVReg_UNTSC[][8],CH7007TVReg_ONTSC[][8],CH7007TVReg_UPAL[][8],CH7007TVReg_OPAL[][8];
-extern UCHAR XGI7007_CHTVVCLKUNTSC[],XGI7007_CHTVVCLKONTSC[],XGI7007_CHTVVCLKUPAL[],XGI7007_CHTVVCLKOPAL[];
-#endif
-
-#ifdef LINUX_KERNEL
-void DelayUS(ULONG MicroSeconds)
+unsigned long UNIROM; /* UNIROM */
+unsigned char ChkLFB(struct vb_device_info *);
+void XGINew_Delay15us(unsigned long);
+void SetPowerConsume(struct xgi_hw_device_info *HwDeviceExtension,
+ unsigned long XGI_P3d4Port);
+void ReadVBIOSTablData(unsigned char ChipType, struct vb_device_info *pVBInfo);
+void XGINew_DDR1x_MRS_XG20(unsigned long P3c4, struct vb_device_info *pVBInfo);
+void XGINew_SetDRAMModeRegister_XG20(struct xgi_hw_device_info *HwDeviceExtension);
+void XGINew_SetDRAMModeRegister_XG27(struct xgi_hw_device_info *HwDeviceExtension);
+void XGINew_ChkSenseStatus(struct xgi_hw_device_info *HwDeviceExtension, struct vb_device_info *pVBInfo) ;
+void XGINew_SetModeScratch(struct xgi_hw_device_info *HwDeviceExtension, struct vb_device_info *pVBInfo) ;
+void XGINew_GetXG21Sense(struct xgi_hw_device_info *HwDeviceExtension, struct vb_device_info *pVBInfo) ;
+unsigned char GetXG21FPBits(struct vb_device_info *pVBInfo);
+void XGINew_GetXG27Sense(struct xgi_hw_device_info *HwDeviceExtension, struct vb_device_info *pVBInfo) ;
+unsigned char GetXG27FPBits(struct vb_device_info *pVBInfo);
+
+void DelayUS(unsigned long MicroSeconds)
{
udelay(MicroSeconds);
}
-#endif
+
/* --------------------------------------------------------------------- */
/* Function : XGIInitNew */
@@ -156,46 +118,44 @@ void DelayUS(ULONG MicroSeconds)
/* Output : */
/* Description : */
/* --------------------------------------------------------------------- */
-BOOLEAN XGIInitNew( PXGI_HW_DEVICE_INFO HwDeviceExtension )
+unsigned char XGIInitNew(struct xgi_hw_device_info *HwDeviceExtension)
{
- VB_DEVICE_INFO VBINF;
- PVB_DEVICE_INFO pVBInfo = &VBINF;
- UCHAR i , temp = 0 , temp1 ;
+ struct vb_device_info VBINF;
+ struct vb_device_info *pVBInfo = &VBINF;
+ unsigned char i, temp = 0, temp1 ;
// VBIOSVersion[ 5 ] ;
- PUCHAR volatile pVideoMemory;
+ volatile unsigned char *pVideoMemory;
- /* ULONG j, k ; */
+ /* unsigned long j, k ; */
- PXGI_DSReg pSR ;
+ struct XGI_DSReg *pSR ;
- ULONG Temp ;
+ unsigned long Temp ;
pVBInfo->ROMAddr = HwDeviceExtension->pjVirtualRomBase ;
pVBInfo->FBAddr = HwDeviceExtension->pjVideoMemoryAddress ;
- pVBInfo->BaseAddr = (ULONG)HwDeviceExtension->pjIOAddress ;
+ pVBInfo->BaseAddr = (unsigned long)HwDeviceExtension->pjIOAddress ;
- pVideoMemory = ( PUCHAR )pVBInfo->ROMAddr;
+ pVideoMemory = (unsigned char *)pVBInfo->ROMAddr;
// Newdebugcode( 0x99 ) ;
/* if ( pVBInfo->ROMAddr == 0 ) */
- /* return( FALSE ) ; */
+ /* return( 0 ) ; */
- if ( pVBInfo->FBAddr == 0 )
-{
+ if (pVBInfo->FBAddr == 0) {
printk("\n pVBInfo->FBAddr == 0 ");
- return( FALSE ) ;
-}
+ return 0;
+ }
printk("1");
- if ( pVBInfo->BaseAddr == 0 )
-{
- printk("\npVBInfo->BaseAddr == 0 ");
- return( FALSE ) ;
+if (pVBInfo->BaseAddr == 0) {
+ printk("\npVBInfo->BaseAddr == 0 ");
+ return 0;
}
printk("2");
@@ -205,12 +165,9 @@ printk("2");
printk("3");
if ( !HwDeviceExtension->bIntegratedMMEnabled )
-{
- return( FALSE ) ; /* alan */
-}
-printk("4");
+ return 0; /* alan */
-// XGI_MemoryCopy( VBIOSVersion , HwDeviceExtension->szVBIOSVer , 4 ) ;
+printk("4");
// VBIOSVersion[ 4 ] = 0x0 ;
@@ -407,8 +364,8 @@ printk("15");
XGI_UnLockCRT2( HwDeviceExtension, pVBInfo) ;
XGINew_SetRegANDOR( pVBInfo->Part0Port , 0x3F , 0xEF , 0x00 ) ; /* alan, disable VideoCapture */
XGINew_SetReg1( pVBInfo->Part1Port , 0x00 , 0x00 ) ;
- temp1 = ( UCHAR )XGINew_GetReg1( pVBInfo->P3d4 , 0x7B ) ; /* chk if BCLK>=100MHz */
- temp = ( UCHAR )( ( temp1 >> 4 ) & 0x0F ) ;
+ temp1 = (unsigned char)XGINew_GetReg1(pVBInfo->P3d4, 0x7B); /* chk if BCLK>=100MHz */
+ temp = (unsigned char)((temp1 >> 4) & 0x0F);
XGINew_SetReg1( pVBInfo->Part1Port , 0x02 , ( *pVBInfo->pCRT2Data_1_2 ) ) ;
@@ -460,15 +417,14 @@ printk("18");
XGINew_SetReg1( pVBInfo->P3d4 , 0x83 , 0x00 ) ;
printk("181");
- if ( HwDeviceExtension->bSkipSense == FALSE )
- {
-printk("182");
+if (HwDeviceExtension->bSkipSense == 0) {
+ printk("182");
XGI_SenseCRT1(pVBInfo) ;
-printk("183");
+ printk("183");
/* XGINew_DetectMonitor( HwDeviceExtension ) ; */
-pVBInfo->IF_DEF_CH7007 = 0;
+ pVBInfo->IF_DEF_CH7007 = 0;
if ( ( HwDeviceExtension->jChipType == XG21 ) && (pVBInfo->IF_DEF_CH7007) )
{
printk("184");
@@ -504,8 +460,7 @@ printk("19");
XGINew_SetDRAMDefaultRegister340( HwDeviceExtension , pVBInfo->P3d4, pVBInfo ) ;
- if ( HwDeviceExtension->bSkipDramSizing == TRUE )
- {
+ if (HwDeviceExtension->bSkipDramSizing == 1) {
pSR = HwDeviceExtension->pSR ;
if ( pSR!=NULL )
{
@@ -519,15 +474,6 @@ printk("19");
} /* SkipDramSizing */
else
{
-#if 0
- if ( HwDeviceExtension->jChipType == XG20 )
- {
- XGINew_SetReg1( pVBInfo->P3c4 , 0x13 , pVBInfo->SR15[0][XGINew_RAMType] ) ;
- XGINew_SetReg1( pVBInfo->P3c4 , 0x14 , pVBInfo->SR15[1][XGINew_RAMType] ) ;
- XGINew_SetReg1( pVBInfo->P3c4 , 0x20 , 0x20 ) ;
- }
- else
-#endif
{
printk("20");
@@ -544,7 +490,7 @@ printk("22");
/* SetDefExt2Regs begin */
/*
AGP = 1 ;
- temp =( UCHAR )XGINew_GetReg1( pVBInfo->P3c4 , 0x3A ) ;
+ temp =(unsigned char)XGINew_GetReg1(pVBInfo->P3c4, 0x3A) ;
temp &= 0x30 ;
if ( temp == 0x30 )
AGP = 0 ;
@@ -563,7 +509,7 @@ printk("22");
// Temp = ( InPortLong( 0xcfc ) & 0xFFFF ) ;
// if ( Temp == 0x1039 )
// {
- XGINew_SetReg1( pVBInfo->P3c4 , 0x22 , ( UCHAR )( ( *pVBInfo->pSR22 ) & 0xFE ) ) ;
+ XGINew_SetReg1(pVBInfo->P3c4, 0x22, (unsigned char)((*pVBInfo->pSR22) & 0xFE));
// }
// else
// {
@@ -585,7 +531,7 @@ XGINew_SetReg1( pVBInfo->P3d4 , 0x8c , 0x87);
XGINew_SetReg1( pVBInfo->P3c4 , 0x14 , 0x31);
printk("25");
- return( TRUE ) ;
+return 1;
} /* end of init */
@@ -600,9 +546,10 @@ printk("25");
/* Output : */
/* Description : */
/* --------------------------------------------------------------------- */
-UCHAR XGINew_GetXG20DRAMType( PXGI_HW_DEVICE_INFO HwDeviceExtension , PVB_DEVICE_INFO pVBInfo)
+unsigned char XGINew_GetXG20DRAMType(struct xgi_hw_device_info *HwDeviceExtension,
+ struct vb_device_info *pVBInfo)
{
- UCHAR data, temp ;
+ unsigned char data, temp;
if ( HwDeviceExtension->jChipType < XG20 )
{
@@ -670,9 +617,9 @@ UCHAR XGINew_GetXG20DRAMType( PXGI_HW_DEVICE_INFO HwDeviceExtension , PVB_DEVICE
/* Output : */
/* Description : */
/* --------------------------------------------------------------------- */
-UCHAR XGINew_Get310DRAMType(PVB_DEVICE_INFO pVBInfo)
+unsigned char XGINew_Get310DRAMType(struct vb_device_info *pVBInfo)
{
- UCHAR data ;
+ unsigned char data ;
/* index = XGINew_GetReg1( pVBInfo->P3c4 , 0x1A ) ; */
/* index &= 07 ; */
@@ -694,7 +641,7 @@ UCHAR XGINew_Get310DRAMType(PVB_DEVICE_INFO pVBInfo)
/* Description : */
/* --------------------------------------------------------------------- */
/*
-void XGINew_Delay15us(ULONG ulMicrsoSec)
+void XGINew_Delay15us(unsigned long ulMicrsoSec)
{
}
*/
@@ -706,9 +653,9 @@ void XGINew_Delay15us(ULONG ulMicrsoSec)
/* Output : */
/* Description : */
/* --------------------------------------------------------------------- */
-void XGINew_SDR_MRS( PVB_DEVICE_INFO pVBInfo )
+void XGINew_SDR_MRS(struct vb_device_info *pVBInfo)
{
- USHORT data ;
+ unsigned short data ;
data = XGINew_GetReg1( pVBInfo->P3c4 , 0x16 ) ;
data &= 0x3F ; /* SR16 D7=0,D6=0 */
@@ -726,7 +673,7 @@ void XGINew_SDR_MRS( PVB_DEVICE_INFO pVBInfo )
/* Output : */
/* Description : */
/* --------------------------------------------------------------------- */
-void XGINew_DDR1x_MRS_340( ULONG P3c4 , PVB_DEVICE_INFO pVBInfo)
+void XGINew_DDR1x_MRS_340(unsigned long P3c4, struct vb_device_info *pVBInfo)
{
XGINew_SetReg1( P3c4 , 0x18 , 0x01 ) ;
XGINew_SetReg1( P3c4 , 0x19 , 0x20 ) ;
@@ -764,7 +711,7 @@ void XGINew_DDR1x_MRS_340( ULONG P3c4 , PVB_DEVICE_INFO pVBInfo)
/* Output : */
/* Description : */
/* --------------------------------------------------------------------- */
-void XGINew_DDR2x_MRS_340( ULONG P3c4 , PVB_DEVICE_INFO pVBInfo)
+void XGINew_DDR2x_MRS_340(unsigned long P3c4, struct vb_device_info *pVBInfo)
{
XGINew_SetReg1( P3c4 , 0x18 , 0x00 ) ;
XGINew_SetReg1( P3c4 , 0x19 , 0x20 ) ;
@@ -793,9 +740,10 @@ void XGINew_DDR2x_MRS_340( ULONG P3c4 , PVB_DEVICE_INFO pVBInfo)
/* Output : */
/* Description : */
/* --------------------------------------------------------------------- */
-void XGINew_DDRII_Bootup_XG27( PXGI_HW_DEVICE_INFO HwDeviceExtension , ULONG P3c4 , PVB_DEVICE_INFO pVBInfo)
+void XGINew_DDRII_Bootup_XG27(struct xgi_hw_device_info *HwDeviceExtension,
+ unsigned long P3c4, struct vb_device_info *pVBInfo)
{
- ULONG P3d4 = P3c4 + 0x10 ;
+ unsigned long P3d4 = P3c4 + 0x10 ;
XGINew_RAMType = ( int )XGINew_GetXG20DRAMType( HwDeviceExtension , pVBInfo ) ;
XGINew_SetMemoryClock( HwDeviceExtension , pVBInfo ) ;
@@ -871,9 +819,10 @@ void XGINew_DDRII_Bootup_XG27( PXGI_HW_DEVICE_INFO HwDeviceExtension , ULONG P3
/* Output : */
/* Description : */
/* --------------------------------------------------------------------- */
-void XGINew_DDR2_MRS_XG20( PXGI_HW_DEVICE_INFO HwDeviceExtension , ULONG P3c4 , PVB_DEVICE_INFO pVBInfo)
+void XGINew_DDR2_MRS_XG20(struct xgi_hw_device_info *HwDeviceExtension,
+ unsigned long P3c4, struct vb_device_info *pVBInfo)
{
- ULONG P3d4 = P3c4 + 0x10 ;
+ unsigned long P3d4 = P3c4 + 0x10 ;
XGINew_RAMType = ( int )XGINew_GetXG20DRAMType( HwDeviceExtension , pVBInfo ) ;
XGINew_SetMemoryClock( HwDeviceExtension , pVBInfo ) ;
@@ -923,9 +872,10 @@ void XGINew_DDR2_MRS_XG20( PXGI_HW_DEVICE_INFO HwDeviceExtension , ULONG P3c4 ,
/* Output : */
/* Description : */
/* --------------------------------------------------------------------- */
-void XGINew_DDR2_MRS_XG27( PXGI_HW_DEVICE_INFO HwDeviceExtension , ULONG P3c4 , PVB_DEVICE_INFO pVBInfo)
+void XGINew_DDR2_MRS_XG27(struct xgi_hw_device_info *HwDeviceExtension,
+ unsigned long P3c4, struct vb_device_info *pVBInfo)
{
- ULONG P3d4 = P3c4 + 0x10 ;
+ unsigned long P3d4 = P3c4 + 0x10 ;
XGINew_RAMType = ( int )XGINew_GetXG20DRAMType( HwDeviceExtension , pVBInfo ) ;
XGINew_SetMemoryClock( HwDeviceExtension , pVBInfo ) ;
@@ -1001,9 +951,10 @@ void XGINew_DDR2_MRS_XG27( PXGI_HW_DEVICE_INFO HwDeviceExtension , ULONG P3c4 ,
/* Output : */
/* Description : */
/* --------------------------------------------------------------------- */
-void XGINew_DDR1x_DefaultRegister( PXGI_HW_DEVICE_INFO HwDeviceExtension , ULONG Port , PVB_DEVICE_INFO pVBInfo)
+void XGINew_DDR1x_DefaultRegister(struct xgi_hw_device_info *HwDeviceExtension,
+ unsigned long Port, struct vb_device_info *pVBInfo)
{
- ULONG P3d4 = Port ,
+ unsigned long P3d4 = Port ,
P3c4 = Port - 0x10 ;
if ( HwDeviceExtension->jChipType >= XG20 )
@@ -1061,9 +1012,10 @@ void XGINew_DDR1x_DefaultRegister( PXGI_HW_DEVICE_INFO HwDeviceExtension , ULON
/* Output : */
/* Description : */
/* --------------------------------------------------------------------- */
-void XGINew_DDR2x_DefaultRegister( PXGI_HW_DEVICE_INFO HwDeviceExtension , ULONG Port ,PVB_DEVICE_INFO pVBInfo)
+void XGINew_DDR2x_DefaultRegister(struct xgi_hw_device_info *HwDeviceExtension,
+ unsigned long Port, struct vb_device_info *pVBInfo)
{
- ULONG P3d4 = Port ,
+ unsigned long P3d4 = Port ,
P3c4 = Port - 0x10 ;
XGINew_SetMemoryClock( HwDeviceExtension , pVBInfo ) ;
@@ -1112,9 +1064,10 @@ void XGINew_DDR2x_DefaultRegister( PXGI_HW_DEVICE_INFO HwDeviceExtension , ULON
/* Output : */
/* Description : */
/* --------------------------------------------------------------------- */
-void XGINew_DDR2_DefaultRegister( PXGI_HW_DEVICE_INFO HwDeviceExtension, ULONG Port , PVB_DEVICE_INFO pVBInfo)
+void XGINew_DDR2_DefaultRegister(struct xgi_hw_device_info *HwDeviceExtension,
+ unsigned long Port, struct vb_device_info *pVBInfo)
{
- ULONG P3d4 = Port ,
+ unsigned long P3d4 = Port ,
P3c4 = Port - 0x10 ;
/* keep following setting sequence, each setting in the same reg insert idle */
@@ -1150,12 +1103,13 @@ void XGINew_DDR2_DefaultRegister( PXGI_HW_DEVICE_INFO HwDeviceExtension, ULONG P
/* Output : */
/* Description : */
/* --------------------------------------------------------------------- */
-void XGINew_SetDRAMDefaultRegister340( PXGI_HW_DEVICE_INFO HwDeviceExtension , ULONG Port , PVB_DEVICE_INFO pVBInfo)
+void XGINew_SetDRAMDefaultRegister340(struct xgi_hw_device_info *HwDeviceExtension,
+ unsigned long Port, struct vb_device_info *pVBInfo)
{
- UCHAR temp , temp1 , temp2 , temp3 ,
+ unsigned char temp, temp1, temp2, temp3 ,
i , j , k ;
- ULONG P3d4 = Port ,
+ unsigned long P3d4 = Port ,
P3c4 = Port - 0x10 ;
XGINew_SetReg1( P3d4 , 0x6D , pVBInfo->CR40[ 8 ][ XGINew_RAMType ] ) ;
@@ -1293,11 +1247,11 @@ void XGINew_SetDRAMDefaultRegister340( PXGI_HW_DEVICE_INFO HwDeviceExtension ,
/* Output : */
/* Description : */
/* --------------------------------------------------------------------- */
-void XGINew_DDR_MRS(PVB_DEVICE_INFO pVBInfo)
+void XGINew_DDR_MRS(struct vb_device_info *pVBInfo)
{
- USHORT data ;
+ unsigned short data ;
- PUCHAR volatile pVideoMemory = ( PUCHAR )pVBInfo->ROMAddr ;
+ volatile unsigned char *pVideoMemory = (unsigned char *)pVBInfo->ROMAddr;
/* SR16 <- 1F,DF,2F,AF */
/* yriver modified SR16 <- 0F,DF,0F,AF */
@@ -1361,11 +1315,11 @@ void XGINew_DDR_MRS(PVB_DEVICE_INFO pVBInfo)
/* Output : */
/* Description : */
/* --------------------------------------------------------------------- */
-void XGINew_VerifyMclk( PXGI_HW_DEVICE_INFO HwDeviceExtension , PVB_DEVICE_INFO pVBInfo)
+void XGINew_VerifyMclk(struct xgi_hw_device_info *HwDeviceExtension, struct vb_device_info *pVBInfo)
{
- PUCHAR pVideoMemory = pVBInfo->FBAddr ;
- UCHAR i , j ;
- USHORT Temp , SR21 ;
+ unsigned char *pVideoMemory = pVBInfo->FBAddr ;
+ unsigned char i, j ;
+ unsigned short Temp , SR21 ;
pVideoMemory[ 0 ] = 0xaa ; /* alan */
pVideoMemory[ 16 ] = 0x55 ; /* note: PCI read cache is off */
@@ -1407,9 +1361,9 @@ void XGINew_VerifyMclk( PXGI_HW_DEVICE_INFO HwDeviceExtension , PVB_DEVICE_INFO
/* Output : */
/* Description : */
/* --------------------------------------------------------------------- */
-void XGINew_SetDRAMSize_340( PXGI_HW_DEVICE_INFO HwDeviceExtension , PVB_DEVICE_INFO pVBInfo)
+void XGINew_SetDRAMSize_340(struct xgi_hw_device_info *HwDeviceExtension, struct vb_device_info *pVBInfo)
{
- USHORT data ;
+ unsigned short data ;
pVBInfo->ROMAddr = HwDeviceExtension->pjVirtualRomBase ;
pVBInfo->FBAddr = HwDeviceExtension->pjVideoMemoryAddress ;
@@ -1418,7 +1372,7 @@ void XGINew_SetDRAMSize_340( PXGI_HW_DEVICE_INFO HwDeviceExtension , PVB_DEVICE_
data = XGINew_GetReg1( pVBInfo->P3c4 , 0x21 ) ;
- XGINew_SetReg1( pVBInfo->P3c4 , 0x21 , ( USHORT )( data & 0xDF ) ) ; /* disable read cache */
+ XGINew_SetReg1(pVBInfo->P3c4, 0x21, (unsigned short)(data & 0xDF)); /* disable read cache */
XGI_DisplayOff( HwDeviceExtension, pVBInfo );
/*data = XGINew_GetReg1( pVBInfo->P3c4 , 0x1 ) ;*/
@@ -1426,8 +1380,7 @@ void XGINew_SetDRAMSize_340( PXGI_HW_DEVICE_INFO HwDeviceExtension , PVB_DEVICE_
/*XGINew_SetReg1( pVBInfo->P3c4 , 0x01 , data ) ;*/ /* Turn OFF Display */
XGINew_DDRSizing340( HwDeviceExtension, pVBInfo ) ;
data=XGINew_GetReg1( pVBInfo->P3c4 , 0x21 ) ;
- XGINew_SetReg1( pVBInfo->P3c4 , 0x21 , ( USHORT )( data | 0x20 ) ) ; /* enable read cache */
-
+ XGINew_SetReg1(pVBInfo->P3c4, 0x21, (unsigned short)(data | 0x20)); /* enable read cache */
}
@@ -1437,9 +1390,9 @@ void XGINew_SetDRAMSize_340( PXGI_HW_DEVICE_INFO HwDeviceExtension , PVB_DEVICE_
/* Output : */
/* Description : */
/* --------------------------------------------------------------------- */
-void XGINew_SetDRAMSize_310( PXGI_HW_DEVICE_INFO HwDeviceExtension , PVB_DEVICE_INFO pVBInfo)
+void XGINew_SetDRAMSize_310(struct xgi_hw_device_info *HwDeviceExtension, struct vb_device_info *pVBInfo)
{
- USHORT data ;
+ unsigned short data ;
pVBInfo->ROMAddr = HwDeviceExtension->pjVirtualRomBase ,
pVBInfo->FBAddr = HwDeviceExtension->pjVideoMemoryAddress ;
#ifdef XGI301
@@ -1455,7 +1408,7 @@ void XGINew_SetDRAMSize_310( PXGI_HW_DEVICE_INFO HwDeviceExtension , PVB_DEVICE_
XGISetModeNew( HwDeviceExtension , 0x2e ) ;
data = XGINew_GetReg1( pVBInfo->P3c4 , 0x21 ) ;
- XGINew_SetReg1( pVBInfo->P3c4 , 0x21 , ( USHORT )( data & 0xDF ) ) ; /* disable read cache */
+ XGINew_SetReg1(pVBInfo->P3c4, 0x21, (unsigned short)(data & 0xDF)); /* disable read cache */
data = XGINew_GetReg1( pVBInfo->P3c4 , 0x1 ) ;
data |= 0x20 ;
@@ -1464,7 +1417,7 @@ void XGINew_SetDRAMSize_310( PXGI_HW_DEVICE_INFO HwDeviceExtension , PVB_DEVICE_
data = XGINew_GetReg1( pVBInfo->P3c4 , 0x16 ) ;
- XGINew_SetReg1( pVBInfo->P3c4 , 0x16 , ( USHORT )( data | 0x0F ) ) ; /* assume lowest speed DRAM */
+ XGINew_SetReg1(pVBInfo->P3c4, 0x16, (unsigned short)(data | 0x0F)); /* assume lowest speed DRAM */
XGINew_SetDRAMModeRegister( pVBInfo ) ;
XGINew_DisableRefresh( HwDeviceExtension, pVBInfo ) ;
@@ -1485,11 +1438,11 @@ void XGINew_SetDRAMSize_310( PXGI_HW_DEVICE_INFO HwDeviceExtension , PVB_DEVICE_
- XGINew_SetReg1( pVBInfo->P3c4 , 0x16 , pVBInfo->SR15[ 1 ][ XGINew_RAMType ] ) ; /* restore SR16 */
+ XGINew_SetReg1(pVBInfo->P3c4, 0x16, pVBInfo->SR15[1][XGINew_RAMType]); /* restore SR16 */
XGINew_EnableRefresh( HwDeviceExtension, pVBInfo ) ;
data=XGINew_GetReg1( pVBInfo->P3c4 ,0x21 ) ;
- XGINew_SetReg1( pVBInfo->P3c4 , 0x21 , ( USHORT )( data | 0x20 ) ) ; /* enable read cache */
+ XGINew_SetReg1(pVBInfo->P3c4, 0x21, (unsigned short)(data | 0x20)); /* enable read cache */
}
@@ -1501,14 +1454,14 @@ void XGINew_SetDRAMSize_310( PXGI_HW_DEVICE_INFO HwDeviceExtension , PVB_DEVICE_
/* Description : */
/* --------------------------------------------------------------------- */
-void XGINew_SetDRAMModeRegister340( PXGI_HW_DEVICE_INFO HwDeviceExtension )
+void XGINew_SetDRAMModeRegister340(struct xgi_hw_device_info *HwDeviceExtension)
{
- UCHAR data ;
- VB_DEVICE_INFO VBINF;
- PVB_DEVICE_INFO pVBInfo = &VBINF;
+ unsigned char data ;
+ struct vb_device_info VBINF;
+ struct vb_device_info *pVBInfo = &VBINF;
pVBInfo->ROMAddr = HwDeviceExtension->pjVirtualRomBase ;
pVBInfo->FBAddr = HwDeviceExtension->pjVideoMemoryAddress ;
- pVBInfo->BaseAddr = (ULONG)HwDeviceExtension->pjIOAddress ;
+ pVBInfo->BaseAddr = (unsigned long)HwDeviceExtension->pjIOAddress ;
pVBInfo->ISXPDOS = 0 ;
pVBInfo->P3c4 = pVBInfo->BaseAddr + 0x14 ;
@@ -1555,7 +1508,7 @@ void XGINew_SetDRAMModeRegister340( PXGI_HW_DEVICE_INFO HwDeviceExtension )
/* Output : */
/* Description : */
/* --------------------------------------------------------------------- */
-void XGINew_SetDRAMModeRegister( PVB_DEVICE_INFO pVBInfo)
+void XGINew_SetDRAMModeRegister(struct vb_device_info *pVBInfo)
{
if ( XGINew_Get310DRAMType( pVBInfo ) < 2 )
{
@@ -1575,9 +1528,9 @@ void XGINew_SetDRAMModeRegister( PVB_DEVICE_INFO pVBInfo)
/* Output : */
/* Description : */
/* --------------------------------------------------------------------- */
-void XGINew_DisableRefresh( PXGI_HW_DEVICE_INFO HwDeviceExtension , PVB_DEVICE_INFO pVBInfo)
+void XGINew_DisableRefresh(struct xgi_hw_device_info *HwDeviceExtension, struct vb_device_info *pVBInfo)
{
- USHORT data ;
+ unsigned short data ;
data = XGINew_GetReg1( pVBInfo->P3c4 , 0x1B ) ;
@@ -1593,7 +1546,7 @@ void XGINew_DisableRefresh( PXGI_HW_DEVICE_INFO HwDeviceExtension , PVB_DEVICE_I
/* Output : */
/* Description : */
/* --------------------------------------------------------------------- */
-void XGINew_EnableRefresh( PXGI_HW_DEVICE_INFO HwDeviceExtension , PVB_DEVICE_INFO pVBInfo)
+void XGINew_EnableRefresh(struct xgi_hw_device_info *HwDeviceExtension, struct vb_device_info *pVBInfo)
{
XGINew_SetReg1( pVBInfo->P3c4 , 0x1B , pVBInfo->SR15[ 3 ][ XGINew_RAMType ] ) ; /* SR1B */
@@ -1608,9 +1561,11 @@ void XGINew_EnableRefresh( PXGI_HW_DEVICE_INFO HwDeviceExtension , PVB_DEVICE_IN
/* Output : */
/* Description : */
/* --------------------------------------------------------------------- */
-void XGINew_DisableChannelInterleaving( int index , USHORT XGINew_DDRDRAM_TYPE[][ 5 ] , PVB_DEVICE_INFO pVBInfo)
+void XGINew_DisableChannelInterleaving(int index,
+ unsigned short XGINew_DDRDRAM_TYPE[][5],
+ struct vb_device_info *pVBInfo)
{
- USHORT data ;
+ unsigned short data ;
data = XGINew_GetReg1( pVBInfo->P3c4 , 0x15 ) ;
data &= 0x1F ;
@@ -1642,9 +1597,11 @@ void XGINew_DisableChannelInterleaving( int index , USHORT XGINew_DDRDRAM_TYPE[]
/* Output : */
/* Description : */
/* --------------------------------------------------------------------- */
-void XGINew_SetDRAMSizingType( int index , USHORT DRAMTYPE_TABLE[][ 5 ] ,PVB_DEVICE_INFO pVBInfo)
+void XGINew_SetDRAMSizingType(int index,
+ unsigned short DRAMTYPE_TABLE[][5],
+ struct vb_device_info *pVBInfo)
{
- USHORT data ;
+ unsigned short data;
data = DRAMTYPE_TABLE[ index ][ 4 ] ;
XGINew_SetRegANDOR( pVBInfo->P3c4 , 0x13 , 0x80 , data ) ;
@@ -1659,12 +1616,12 @@ void XGINew_SetDRAMSizingType( int index , USHORT DRAMTYPE_TABLE[][ 5 ] ,PVB_DEV
/* Output : */
/* Description : */
/* --------------------------------------------------------------------- */
-void XGINew_CheckBusWidth_310( PVB_DEVICE_INFO pVBInfo)
+void XGINew_CheckBusWidth_310(struct vb_device_info *pVBInfo)
{
- USHORT data ;
- PULONG volatile pVideoMemory ;
+ unsigned short data ;
+ volatile unsigned long *pVideoMemory ;
- pVideoMemory = (PULONG) pVBInfo->FBAddr;
+ pVideoMemory = (unsigned long *) pVBInfo->FBAddr;
if ( XGINew_Get310DRAMType( pVBInfo ) < 2 )
{
@@ -1690,7 +1647,7 @@ void XGINew_CheckBusWidth_310( PVB_DEVICE_INFO pVBInfo)
XGINew_DataBusWidth = 64 ;
XGINew_ChannelAB = 0 ;
data=XGINew_GetReg1( pVBInfo->P3c4 , 0x14 ) ;
- XGINew_SetReg1( pVBInfo->P3c4 , 0x14 , ( USHORT )( data & 0xFD ) ) ;
+ XGINew_SetReg1(pVBInfo->P3c4, 0x14, (unsigned short)(data & 0xFD));
}
if ( ( pVideoMemory[ 1 ] != 0x456789ABL ) || ( pVideoMemory[ 0 ] != 0x01234567L ) )
@@ -1699,7 +1656,8 @@ void XGINew_CheckBusWidth_310( PVB_DEVICE_INFO pVBInfo)
XGINew_DataBusWidth = 64 ;
XGINew_ChannelAB = 1 ;
data=XGINew_GetReg1( pVBInfo->P3c4 , 0x14 ) ;
- XGINew_SetReg1( pVBInfo->P3c4 , 0x14 , ( USHORT )( ( data & 0xFD ) | 0x01 ) ) ;
+ XGINew_SetReg1(pVBInfo->P3c4, 0x14,
+ (unsigned short)((data & 0xFD) | 0x01));
}
return ;
@@ -1792,9 +1750,13 @@ void XGINew_CheckBusWidth_310( PVB_DEVICE_INFO pVBInfo)
/* Output : */
/* Description : */
/* --------------------------------------------------------------------- */
-int XGINew_SetRank( int index , UCHAR RankNo , UCHAR XGINew_ChannelAB , USHORT DRAMTYPE_TABLE[][ 5 ] , PVB_DEVICE_INFO pVBInfo)
+int XGINew_SetRank(int index,
+ unsigned char RankNo,
+ unsigned char XGINew_ChannelAB,
+ unsigned short DRAMTYPE_TABLE[][5],
+ struct vb_device_info *pVBInfo)
{
- USHORT data ;
+ unsigned short data;
int RankSize ;
if ( ( RankNo == 2 ) && ( DRAMTYPE_TABLE[ index ][ 0 ] == 2 ) )
@@ -1829,9 +1791,13 @@ int XGINew_SetRank( int index , UCHAR RankNo , UCHAR XGINew_ChannelAB , USHORT D
/* Output : */
/* Description : */
/* --------------------------------------------------------------------- */
-int XGINew_SetDDRChannel( int index , UCHAR ChannelNo , UCHAR XGINew_ChannelAB , USHORT DRAMTYPE_TABLE[][ 5 ] , PVB_DEVICE_INFO pVBInfo)
+int XGINew_SetDDRChannel(int index,
+ unsigned char ChannelNo,
+ unsigned char XGINew_ChannelAB,
+ unsigned short DRAMTYPE_TABLE[][5],
+ struct vb_device_info *pVBInfo)
{
- USHORT data ;
+ unsigned short data;
int RankSize ;
RankSize = DRAMTYPE_TABLE[index][3]/2 * XGINew_DataBusWidth/32;
@@ -1865,30 +1831,29 @@ int XGINew_SetDDRChannel( int index , UCHAR ChannelNo , UCHAR XGINew_ChannelAB ,
/* Output : */
/* Description : */
/* --------------------------------------------------------------------- */
-int XGINew_CheckColumn( int index , USHORT DRAMTYPE_TABLE[][ 5 ], PVB_DEVICE_INFO pVBInfo)
+int XGINew_CheckColumn(int index,
+ unsigned short DRAMTYPE_TABLE[][5],
+ struct vb_device_info *pVBInfo)
{
int i ;
- ULONG Increment , Position ;
+ unsigned long Increment , Position ;
/* Increment = 1 << ( DRAMTYPE_TABLE[ index ][ 2 ] + XGINew_DataBusWidth / 64 + 1 ) ; */
Increment = 1 << ( 10 + XGINew_DataBusWidth / 64 ) ;
for( i = 0 , Position = 0 ; i < 2 ; i++ )
{
- *( ( PULONG )( pVBInfo->FBAddr + Position ) ) = Position ;
- Position += Increment ;
+ *((unsigned long *)(pVBInfo->FBAddr + Position)) = Position;
+ Position += Increment ;
}
-#ifdef WIN2000 /* chiawen for linux solution */
- DelayUS( 100 ) ;
-#endif
for( i = 0 , Position = 0 ; i < 2 ; i++ )
{
/* if ( pVBInfo->FBAddr[ Position ] != Position ) */
- if ( ( *( PULONG )( pVBInfo->FBAddr + Position ) ) != Position )
- return( 0 ) ;
- Position += Increment ;
+ if ((*(unsigned long *)(pVBInfo->FBAddr + Position)) != Position)
+ return 0;
+ Position += Increment;
}
return( 1 ) ;
}
@@ -1900,26 +1865,28 @@ int XGINew_CheckColumn( int index , USHORT DRAMTYPE_TABLE[][ 5 ], PVB_DEVICE_INF
/* Output : */
/* Description : */
/* --------------------------------------------------------------------- */
-int XGINew_CheckBanks( int index , USHORT DRAMTYPE_TABLE[][ 5 ], PVB_DEVICE_INFO pVBInfo)
+int XGINew_CheckBanks(int index,
+ unsigned short DRAMTYPE_TABLE[][5],
+ struct vb_device_info *pVBInfo)
{
int i ;
- ULONG Increment , Position ;
+ unsigned long Increment , Position ;
Increment = 1 << ( DRAMTYPE_TABLE[ index ][ 2 ] + XGINew_DataBusWidth / 64 + 2 ) ;
for( i = 0 , Position = 0 ; i < 4 ; i++ )
{
/* pVBInfo->FBAddr[ Position ] = Position ; */
- *( ( PULONG )( pVBInfo->FBAddr + Position ) ) = Position ;
- Position += Increment ;
+ *((unsigned long *)(pVBInfo->FBAddr + Position)) = Position;
+ Position += Increment ;
}
for( i = 0 , Position = 0 ; i < 4 ; i++ )
{
/* if (pVBInfo->FBAddr[ Position ] != Position ) */
- if ( ( *( PULONG )( pVBInfo->FBAddr + Position ) ) != Position )
- return( 0 ) ;
- Position += Increment ;
+ if ((*(unsigned long *)(pVBInfo->FBAddr + Position)) != Position)
+ return 0;
+ Position += Increment;
}
return( 1 ) ;
}
@@ -1931,10 +1898,12 @@ int XGINew_CheckBanks( int index , USHORT DRAMTYPE_TABLE[][ 5 ], PVB_DEVICE_INFO
/* Output : */
/* Description : */
/* --------------------------------------------------------------------- */
-int XGINew_CheckRank( int RankNo , int index , USHORT DRAMTYPE_TABLE[][ 5 ], PVB_DEVICE_INFO pVBInfo)
+int XGINew_CheckRank(int RankNo, int index,
+ unsigned short DRAMTYPE_TABLE[][5],
+ struct vb_device_info *pVBInfo)
{
int i ;
- ULONG Increment , Position ;
+ unsigned long Increment , Position ;
Increment = 1 << ( DRAMTYPE_TABLE[ index ][ 2 ] + DRAMTYPE_TABLE[ index ][ 1 ] +
DRAMTYPE_TABLE[ index ][ 0 ] + XGINew_DataBusWidth / 64 + RankNo ) ;
@@ -1942,18 +1911,18 @@ int XGINew_CheckRank( int RankNo , int index , USHORT DRAMTYPE_TABLE[][ 5 ], PVB
for( i = 0 , Position = 0 ; i < 2 ; i++ )
{
/* pVBInfo->FBAddr[ Position ] = Position ; */
- /* *( ( PULONG )( pVBInfo->FBAddr ) ) = Position ; */
- *( ( PULONG )( pVBInfo->FBAddr + Position ) ) = Position ;
- Position += Increment ;
+ /* *( (unsigned long *)( pVBInfo->FBAddr ) ) = Position ; */
+ *((unsigned long *)(pVBInfo->FBAddr + Position)) = Position;
+ Position += Increment;
}
for( i = 0 , Position = 0 ; i < 2 ; i++ )
{
/* if ( pVBInfo->FBAddr[ Position ] != Position ) */
- /* if ( ( *( PULONG )( pVBInfo->FBAddr ) ) != Position ) */
- if ( ( *( PULONG )( pVBInfo->FBAddr + Position ) ) != Position )
- return( 0 ) ;
- Position += Increment ;
+ /* if ( ( *(unsigned long *)( pVBInfo->FBAddr ) ) != Position ) */
+ if ((*(unsigned long *)(pVBInfo->FBAddr + Position)) != Position)
+ return 0;
+ Position += Increment;
}
return( 1 );
}
@@ -1965,10 +1934,12 @@ int XGINew_CheckRank( int RankNo , int index , USHORT DRAMTYPE_TABLE[][ 5 ], PVB
/* Output : */
/* Description : */
/* --------------------------------------------------------------------- */
-int XGINew_CheckDDRRank( int RankNo , int index , USHORT DRAMTYPE_TABLE[][ 5 ], PVB_DEVICE_INFO pVBInfo)
+int XGINew_CheckDDRRank(int RankNo, int index,
+ unsigned short DRAMTYPE_TABLE[][5],
+ struct vb_device_info *pVBInfo)
{
- ULONG Increment , Position ;
- USHORT data ;
+ unsigned long Increment , Position ;
+ unsigned short data ;
Increment = 1 << ( DRAMTYPE_TABLE[ index ][ 2 ] + DRAMTYPE_TABLE[ index ][ 1 ] +
DRAMTYPE_TABLE[ index ][ 0 ] + XGINew_DataBusWidth / 64 + RankNo ) ;
@@ -1976,18 +1947,18 @@ int XGINew_CheckDDRRank( int RankNo , int index , USHORT DRAMTYPE_TABLE[][ 5 ],
Increment += Increment / 2 ;
Position = 0;
- *( ( PULONG )( pVBInfo->FBAddr + Position + 0 ) ) = 0x01234567 ;
- *( ( PULONG )( pVBInfo->FBAddr + Position + 1 ) ) = 0x456789AB ;
- *( ( PULONG )( pVBInfo->FBAddr + Position + 2 ) ) = 0x55555555 ;
- *( ( PULONG )( pVBInfo->FBAddr + Position + 3 ) ) = 0x55555555 ;
- *( ( PULONG )( pVBInfo->FBAddr + Position + 4 ) ) = 0xAAAAAAAA ;
- *( ( PULONG )( pVBInfo->FBAddr + Position + 5 ) ) = 0xAAAAAAAA ;
-
- if ( ( *( PULONG )( pVBInfo->FBAddr + 1 ) ) == 0x456789AB )
- return( 1 ) ;
+ *((unsigned long *)(pVBInfo->FBAddr + Position + 0)) = 0x01234567;
+ *((unsigned long *)(pVBInfo->FBAddr + Position + 1)) = 0x456789AB;
+ *((unsigned long *)(pVBInfo->FBAddr + Position + 2)) = 0x55555555;
+ *((unsigned long *)(pVBInfo->FBAddr + Position + 3)) = 0x55555555;
+ *((unsigned long *)(pVBInfo->FBAddr + Position + 4)) = 0xAAAAAAAA;
+ *((unsigned long *)(pVBInfo->FBAddr + Position + 5)) = 0xAAAAAAAA;
- if ( ( *( PULONG )( pVBInfo->FBAddr + 0 ) ) == 0x01234567 )
- return( 0 ) ;
+ if ((*(unsigned long *)(pVBInfo->FBAddr + 1)) == 0x456789AB)
+ return 1;
+
+ if ((*(unsigned long *)(pVBInfo->FBAddr + 0)) == 0x01234567)
+ return 0;
data = XGINew_GetReg1( pVBInfo->P3c4 , 0x14 ) ;
data &= 0xF3 ;
@@ -2007,7 +1978,9 @@ int XGINew_CheckDDRRank( int RankNo , int index , USHORT DRAMTYPE_TABLE[][ 5 ],
/* Output : */
/* Description : */
/* --------------------------------------------------------------------- */
-int XGINew_CheckRanks( int RankNo , int index , USHORT DRAMTYPE_TABLE[][ 5 ], PVB_DEVICE_INFO pVBInfo)
+int XGINew_CheckRanks(int RankNo, int index,
+ unsigned short DRAMTYPE_TABLE[][5],
+ struct vb_device_info *pVBInfo)
{
int r ;
@@ -2033,7 +2006,9 @@ int XGINew_CheckRanks( int RankNo , int index , USHORT DRAMTYPE_TABLE[][ 5 ], PV
/* Output : */
/* Description : */
/* --------------------------------------------------------------------- */
-int XGINew_CheckDDRRanks( int RankNo , int index , USHORT DRAMTYPE_TABLE[][ 5 ], PVB_DEVICE_INFO pVBInfo)
+int XGINew_CheckDDRRanks(int RankNo, int index,
+ unsigned short DRAMTYPE_TABLE[][5],
+ struct vb_device_info *pVBInfo)
{
int r ;
@@ -2059,10 +2034,10 @@ int XGINew_CheckDDRRanks( int RankNo , int index , USHORT DRAMTYPE_TABLE[][ 5 ],
/* Output : */
/* Description : */
/* --------------------------------------------------------------------- */
-int XGINew_SDRSizing(PVB_DEVICE_INFO pVBInfo)
+int XGINew_SDRSizing(struct vb_device_info *pVBInfo)
{
int i ;
- UCHAR j ;
+ unsigned char j ;
for( i = 0 ; i < 13 ; i++ )
{
@@ -2070,7 +2045,8 @@ int XGINew_SDRSizing(PVB_DEVICE_INFO pVBInfo)
for( j = 2 ; j > 0 ; j-- )
{
- if ( !XGINew_SetRank( i , ( UCHAR )j , XGINew_ChannelAB , XGINew_SDRDRAM_TYPE , pVBInfo) )
+ if (!XGINew_SetRank(i, (unsigned char)j, XGINew_ChannelAB,
+ XGINew_SDRDRAM_TYPE, pVBInfo))
continue ;
else
{
@@ -2089,11 +2065,13 @@ int XGINew_SDRSizing(PVB_DEVICE_INFO pVBInfo)
/* Output : */
/* Description : */
/* --------------------------------------------------------------------- */
-USHORT XGINew_SetDRAMSizeReg( int index , USHORT DRAMTYPE_TABLE[][ 5 ], PVB_DEVICE_INFO pVBInfo)
+unsigned short XGINew_SetDRAMSizeReg(int index,
+ unsigned short DRAMTYPE_TABLE[][5],
+ struct vb_device_info *pVBInfo)
{
- USHORT data = 0 , memsize = 0 ;
+ unsigned short data = 0 , memsize = 0;
int RankSize ;
- UCHAR ChannelNo ;
+ unsigned char ChannelNo ;
RankSize = DRAMTYPE_TABLE[ index ][ 3 ] * XGINew_DataBusWidth / 32 ;
data = XGINew_GetReg1( pVBInfo->P3c4 , 0x13 ) ;
@@ -2138,11 +2116,13 @@ USHORT XGINew_SetDRAMSizeReg( int index , USHORT DRAMTYPE_TABLE[][ 5 ], PVB_DEVI
/* Output : */
/* Description : */
/* --------------------------------------------------------------------- */
-USHORT XGINew_SetDRAMSize20Reg( int index , USHORT DRAMTYPE_TABLE[][ 5 ], PVB_DEVICE_INFO pVBInfo)
+unsigned short XGINew_SetDRAMSize20Reg(int index,
+ unsigned short DRAMTYPE_TABLE[][5],
+ struct vb_device_info *pVBInfo)
{
- USHORT data = 0 , memsize = 0 ;
+ unsigned short data = 0 , memsize = 0;
int RankSize ;
- UCHAR ChannelNo ;
+ unsigned char ChannelNo ;
RankSize = DRAMTYPE_TABLE[ index ][ 3 ] * XGINew_DataBusWidth / 8 ;
data = XGINew_GetReg1( pVBInfo->P3c4 , 0x13 ) ;
@@ -2188,31 +2168,32 @@ USHORT XGINew_SetDRAMSize20Reg( int index , USHORT DRAMTYPE_TABLE[][ 5 ], PVB_DE
/* Output : */
/* Description : */
/* --------------------------------------------------------------------- */
-int XGINew_ReadWriteRest( USHORT StopAddr , USHORT StartAddr, PVB_DEVICE_INFO pVBInfo)
+int XGINew_ReadWriteRest(unsigned short StopAddr, unsigned short StartAddr,
+ struct vb_device_info *pVBInfo)
{
int i ;
- ULONG Position = 0 ;
+ unsigned long Position = 0 ;
- *( ( PULONG )( pVBInfo->FBAddr + Position ) ) = Position ;
+ *((unsigned long *)(pVBInfo->FBAddr + Position)) = Position;
for( i = StartAddr ; i <= StopAddr ; i++ )
{
Position = 1 << i ;
- *( ( PULONG )( pVBInfo->FBAddr + Position ) ) = Position ;
+ *((unsigned long *)(pVBInfo->FBAddr + Position)) = Position;
}
DelayUS( 500 ) ; /* [Vicent] 2004/04/16. Fix #1759 Memory Size error in Multi-Adapter. */
Position = 0 ;
- if ( ( *( PULONG )( pVBInfo->FBAddr + Position ) ) != Position )
- return( 0 ) ;
+ if ((*(unsigned long *)(pVBInfo->FBAddr + Position)) != Position)
+ return 0;
for( i = StartAddr ; i <= StopAddr ; i++ )
{
Position = 1 << i ;
- if ( ( *( PULONG )( pVBInfo->FBAddr + Position ) ) != Position )
- return( 0 ) ;
+ if ((*(unsigned long *)(pVBInfo->FBAddr + Position)) != Position)
+ return 0;
}
return( 1 ) ;
}
@@ -2224,9 +2205,9 @@ int XGINew_ReadWriteRest( USHORT StopAddr , USHORT StartAddr, PVB_DEVICE_INFO pV
/* Output : */
/* Description : */
/* --------------------------------------------------------------------- */
-UCHAR XGINew_CheckFrequence( PVB_DEVICE_INFO pVBInfo )
+unsigned char XGINew_CheckFrequence(struct vb_device_info *pVBInfo)
{
- UCHAR data ;
+ unsigned char data ;
data = XGINew_GetReg1( pVBInfo->P3d4 , 0x97 ) ;
@@ -2247,9 +2228,9 @@ UCHAR XGINew_CheckFrequence( PVB_DEVICE_INFO pVBInfo )
/* Output : */
/* Description : */
/* --------------------------------------------------------------------- */
-void XGINew_CheckChannel( PXGI_HW_DEVICE_INFO HwDeviceExtension, PVB_DEVICE_INFO pVBInfo)
+void XGINew_CheckChannel(struct xgi_hw_device_info *HwDeviceExtension, struct vb_device_info *pVBInfo)
{
- UCHAR data;
+ unsigned char data;
switch( HwDeviceExtension->jChipType )
{
@@ -2528,10 +2509,10 @@ void XGINew_CheckChannel( PXGI_HW_DEVICE_INFO HwDeviceExtension, PVB_DEVICE_INFO
/* Output : */
/* Description : */
/* --------------------------------------------------------------------- */
-int XGINew_DDRSizing340( PXGI_HW_DEVICE_INFO HwDeviceExtension, PVB_DEVICE_INFO pVBInfo)
+int XGINew_DDRSizing340(struct xgi_hw_device_info *HwDeviceExtension, struct vb_device_info *pVBInfo)
{
int i ;
- USHORT memsize , addr ;
+ unsigned short memsize , addr ;
XGINew_SetReg1( pVBInfo->P3c4 , 0x15 , 0x00 ) ; /* noninterleaving */
XGINew_SetReg1( pVBInfo->P3c4 , 0x1C , 0x00 ) ; /* nontiling */
@@ -2548,7 +2529,7 @@ int XGINew_DDRSizing340( PXGI_HW_DEVICE_INFO HwDeviceExtension, PVB_DEVICE_INFO
continue ;
addr = memsize + ( XGINew_ChannelAB - 2 ) + 20 ;
- if ( ( HwDeviceExtension->ulVideoMemorySize - 1 ) < ( ULONG )( 1 << addr ) )
+ if ((HwDeviceExtension->ulVideoMemorySize - 1) < (unsigned long)(1 << addr))
continue ;
if ( XGINew_ReadWriteRest( addr , 5, pVBInfo ) == 1 )
@@ -2566,7 +2547,7 @@ int XGINew_DDRSizing340( PXGI_HW_DEVICE_INFO HwDeviceExtension, PVB_DEVICE_INFO
continue ;
addr = memsize + ( XGINew_ChannelAB - 2 ) + 20 ;
- if ( ( HwDeviceExtension->ulVideoMemorySize - 1 ) < ( ULONG )( 1 << addr ) )
+ if ((HwDeviceExtension->ulVideoMemorySize - 1) < (unsigned long)(1 << addr))
continue ;
if ( XGINew_ReadWriteRest( addr , 9, pVBInfo ) == 1 )
@@ -2583,10 +2564,10 @@ int XGINew_DDRSizing340( PXGI_HW_DEVICE_INFO HwDeviceExtension, PVB_DEVICE_INFO
/* Output : */
/* Description : */
/* --------------------------------------------------------------------- */
-int XGINew_DDRSizing(PVB_DEVICE_INFO pVBInfo)
+int XGINew_DDRSizing(struct vb_device_info *pVBInfo)
{
int i ;
- UCHAR j ;
+ unsigned char j ;
for( i = 0 ; i < 4 ; i++ )
{
@@ -2595,7 +2576,8 @@ int XGINew_DDRSizing(PVB_DEVICE_INFO pVBInfo)
for( j = 2 ; j > 0 ; j-- )
{
XGINew_SetDDRChannel( i , j , XGINew_ChannelAB , XGINew_DDRDRAM_TYPE , pVBInfo ) ;
- if ( !XGINew_SetRank( i , ( UCHAR )j , XGINew_ChannelAB , XGINew_DDRDRAM_TYPE, pVBInfo ) )
+ if (!XGINew_SetRank(i, (unsigned char)j, XGINew_ChannelAB,
+ XGINew_DDRDRAM_TYPE, pVBInfo))
continue ;
else
{
@@ -2613,7 +2595,7 @@ int XGINew_DDRSizing(PVB_DEVICE_INFO pVBInfo)
/* Output : */
/* Description : */
/* --------------------------------------------------------------------- */
-void XGINew_SetMemoryClock( PXGI_HW_DEVICE_INFO HwDeviceExtension, PVB_DEVICE_INFO pVBInfo)
+void XGINew_SetMemoryClock(struct xgi_hw_device_info *HwDeviceExtension, struct vb_device_info *pVBInfo)
{
@@ -2634,9 +2616,7 @@ void XGINew_SetMemoryClock( PXGI_HW_DEVICE_INFO HwDeviceExtension, PVB_DEVICE_IN
if ( ( pVBInfo->MCLKData[ XGINew_RAMType ].SR28 == 0x1C ) && ( pVBInfo->MCLKData[ XGINew_RAMType ].SR29 == 0x01 )
&& ( ( ( pVBInfo->ECLKData[ XGINew_RAMType ].SR2E == 0x1C ) && ( pVBInfo->ECLKData[ XGINew_RAMType ].SR2F == 0x01 ) )
|| ( ( pVBInfo->ECLKData[ XGINew_RAMType ].SR2E == 0x22 ) && ( pVBInfo->ECLKData[ XGINew_RAMType ].SR2F == 0x01 ) ) ) )
- {
- XGINew_SetReg1( pVBInfo->P3c4 , 0x32 , ( ( UCHAR )XGINew_GetReg1( pVBInfo->P3c4 , 0x32 ) & 0xFC ) | 0x02 ) ;
- }
+ XGINew_SetReg1(pVBInfo->P3c4, 0x32, ((unsigned char)XGINew_GetReg1(pVBInfo->P3c4, 0x32) & 0xFC) | 0x02);
}
}
@@ -2647,12 +2627,12 @@ void XGINew_SetMemoryClock( PXGI_HW_DEVICE_INFO HwDeviceExtension, PVB_DEVICE_IN
/* Output : */
/* Description : */
/* --------------------------------------------------------------------- */
-BOOLEAN ChkLFB( PVB_DEVICE_INFO pVBInfo )
+unsigned char ChkLFB(struct vb_device_info *pVBInfo)
{
- if ( LFBDRAMTrap & XGINew_GetReg1( pVBInfo->P3d4 , 0x78 ) )
- return( TRUE ) ;
- else
- return( FALSE );
+ if (LFBDRAMTrap & XGINew_GetReg1(pVBInfo->P3d4 , 0x78))
+ return 1;
+ else
+ return 0;
}
@@ -2664,17 +2644,18 @@ BOOLEAN ChkLFB( PVB_DEVICE_INFO pVBInfo )
/* in second chip, assume CR A1 D[6]="1" in this case */
/* output : none */
/* --------------------------------------------------------------------- */
-void SetPowerConsume ( PXGI_HW_DEVICE_INFO HwDeviceExtension , ULONG XGI_P3d4Port )
+void SetPowerConsume(struct xgi_hw_device_info *HwDeviceExtension,
+ unsigned long XGI_P3d4Port)
{
- ULONG lTemp ;
- UCHAR bTemp;
+ unsigned long lTemp ;
+ unsigned char bTemp;
HwDeviceExtension->pQueryVGAConfigSpace( HwDeviceExtension , 0x08 , 0 , &lTemp ) ; /* Get */
if ((lTemp&0xFF)==0)
{
/* set CR58 D[5]=0 D[3]=0 */
XGINew_SetRegAND( XGI_P3d4Port , 0x58 , 0xD7 ) ;
- bTemp = (UCHAR) XGINew_GetReg1( XGI_P3d4Port , 0xCB ) ;
+ bTemp = (unsigned char) XGINew_GetReg1(XGI_P3d4Port, 0xCB);
if (bTemp&0x20)
{
if (!(bTemp&0x10))
@@ -2692,15 +2673,13 @@ void SetPowerConsume ( PXGI_HW_DEVICE_INFO HwDeviceExtension , ULONG XGI_P3d4Por
}
-
-#if defined(LINUX_XF86)||defined(LINUX_KERNEL)
-void XGINew_InitVBIOSData(PXGI_HW_DEVICE_INFO HwDeviceExtension, PVB_DEVICE_INFO pVBInfo)
+void XGINew_InitVBIOSData(struct xgi_hw_device_info *HwDeviceExtension, struct vb_device_info *pVBInfo)
{
- /* ULONG ROMAddr = (ULONG)HwDeviceExtension->pjVirtualRomBase; */
+ /* unsigned long ROMAddr = (unsigned long)HwDeviceExtension->pjVirtualRomBase; */
pVBInfo->ROMAddr = HwDeviceExtension->pjVirtualRomBase ;
pVBInfo->FBAddr = HwDeviceExtension->pjVideoMemoryAddress ;
- pVBInfo->BaseAddr = (ULONG)HwDeviceExtension->pjIOAddress ;
+ pVBInfo->BaseAddr = (unsigned long)HwDeviceExtension->pjIOAddress ;
pVBInfo->ISXPDOS = 0 ;
pVBInfo->P3c4 = pVBInfo->BaseAddr + 0x14 ;
@@ -2736,7 +2715,6 @@ void XGINew_InitVBIOSData(PXGI_HW_DEVICE_INFO HwDeviceExtension, PVB_DEVICE_INFO
}
}
-#endif /* For Linux */
/* --------------------------------------------------------------------- */
/* Function : ReadVBIOSTablData */
@@ -2744,200 +2722,11 @@ void XGINew_InitVBIOSData(PXGI_HW_DEVICE_INFO HwDeviceExtension, PVB_DEVICE_INFO
/* Output : */
/* Description : */
/* --------------------------------------------------------------------- */
-void ReadVBIOSTablData( UCHAR ChipType , PVB_DEVICE_INFO pVBInfo)
+void ReadVBIOSTablData(unsigned char ChipType, struct vb_device_info *pVBInfo)
{
- PUCHAR volatile pVideoMemory = ( PUCHAR )pVBInfo->ROMAddr ;
- ULONG i ;
- UCHAR j , k ;
-#if 0
- ULONG ii , jj ;
- i = pVideoMemory[ 0x1CF ] | ( pVideoMemory[ 0x1D0 ] << 8 ) ; /* UniROM */
- if ( i != 0 )
- UNIROM = 1 ;
-
- ii = 0x90 ;
- for( jj = 0x00 ; jj < 0x08 ; jj++ )
- {
- pVBInfo->MCLKData[ jj ].SR28 = pVideoMemory[ ii ] ;
- pVBInfo->MCLKData[ jj ].SR29 = pVideoMemory[ ii + 1] ;
- pVBInfo->MCLKData[ jj ].SR2A = pVideoMemory[ ii + 2] ;
- pVBInfo->MCLKData[ jj ].CLOCK = pVideoMemory[ ii + 3 ] | ( pVideoMemory[ ii + 4 ] << 8 ) ;
- ii += 0x05 ;
- }
-
- ii = 0xB8 ;
- for( jj = 0x00 ; jj < 0x08 ; jj++ )
- {
- pVBInfo->ECLKData[ jj ].SR2E = pVideoMemory[ ii ] ;
- pVBInfo->ECLKData[ jj ].SR2F=pVideoMemory[ ii + 1 ] ;
- pVBInfo->ECLKData[ jj ].SR30= pVideoMemory[ ii + 2 ] ;
- pVBInfo->ECLKData[ jj ].CLOCK= pVideoMemory[ ii + 3 ] | ( pVideoMemory[ ii + 4 ] << 8 ) ;
- ii += 0x05 ;
- }
-
- /* Volari customize data area start */
- /* if ( ChipType == XG40 ) */
- if ( ChipType >= XG40 )
- {
- ii = 0xE0 ;
- for( jj = 0x00 ; jj < 0x03 ; jj++ )
- {
- pVBInfo->SR15[ jj ][ 0 ] = pVideoMemory[ ii ] ; /* SR13, SR14, and SR18 */
- pVBInfo->SR15[ jj ][ 1 ] = pVideoMemory[ ii + 1 ] ;
- pVBInfo->SR15[ jj ][ 2 ] = pVideoMemory[ ii + 2 ] ;
- pVBInfo->SR15[ jj ][ 3 ] = pVideoMemory[ ii + 3 ] ;
- pVBInfo->SR15[ jj ][ 4 ] = pVideoMemory[ ii + 4 ] ;
- pVBInfo->SR15[ jj ][ 5 ] = pVideoMemory[ ii + 5 ] ;
- pVBInfo->SR15[ jj ][ 6 ] = pVideoMemory[ ii + 6 ] ;
- pVBInfo->SR15[ jj ][ 7 ] = pVideoMemory[ ii + 7 ] ;
- ii += 0x08 ;
- }
- ii = 0x110 ;
- jj = 0x03 ;
- pVBInfo->SR15[ jj ][ 0 ] = pVideoMemory[ ii ] ; /* SR1B */
- pVBInfo->SR15[ jj ][ 1 ] = pVideoMemory[ ii + 1 ] ;
- pVBInfo->SR15[ jj ][ 2 ] = pVideoMemory[ ii + 2 ] ;
- pVBInfo->SR15[ jj ][ 3 ] = pVideoMemory[ ii + 3 ] ;
- pVBInfo->SR15[ jj ][ 4 ] = pVideoMemory[ ii + 4 ] ;
- pVBInfo->SR15[ jj ][ 5 ] = pVideoMemory[ ii + 5 ] ;
- pVBInfo->SR15[ jj ][ 6 ] = pVideoMemory[ ii + 6 ] ;
- pVBInfo->SR15[ jj ][ 7 ] = pVideoMemory[ ii + 7 ] ;
-
- *pVBInfo->pSR07 = pVideoMemory[ 0x74 ] ;
- *pVBInfo->pSR1F = pVideoMemory[ 0x75 ] ;
- *pVBInfo->pSR21 = pVideoMemory[ 0x76 ] ;
- *pVBInfo->pSR22 = pVideoMemory[ 0x77 ] ;
- *pVBInfo->pSR23 = pVideoMemory[ 0x78 ] ;
- *pVBInfo->pSR24 = pVideoMemory[ 0x79 ] ;
- pVBInfo->SR25[ 0 ] = pVideoMemory[ 0x7A ] ;
- *pVBInfo->pSR31 = pVideoMemory[ 0x7B ] ;
- *pVBInfo->pSR32 = pVideoMemory[ 0x7C ] ;
- *pVBInfo->pSR33 = pVideoMemory[ 0x7D ] ;
- ii = 0xF8 ;
-
- for( jj = 0 ; jj < 3 ; jj++ )
- {
- pVBInfo->CR40[ jj ][ 0 ] = pVideoMemory[ ii ] ;
- pVBInfo->CR40[ jj ][ 1 ] = pVideoMemory[ ii + 1 ] ;
- pVBInfo->CR40[ jj ][ 2 ] = pVideoMemory[ ii + 2 ] ;
- pVBInfo->CR40[ jj ][ 3 ] = pVideoMemory[ ii + 3 ] ;
- pVBInfo->CR40[ jj ][ 4 ] = pVideoMemory[ ii + 4 ] ;
- pVBInfo->CR40[ jj ][ 5 ] = pVideoMemory[ ii + 5 ] ;
- pVBInfo->CR40[ jj ][ 6 ] = pVideoMemory[ ii + 6 ] ;
- pVBInfo->CR40[ jj ][ 7 ] = pVideoMemory[ ii + 7 ] ;
- ii += 0x08 ;
- }
-
- ii = 0x118 ;
- for( j = 3 ; j < 24 ; j++ )
- {
- pVBInfo->CR40[ j ][ 0 ] = pVideoMemory[ ii ] ;
- pVBInfo->CR40[ j ][ 1 ] = pVideoMemory[ ii + 1 ] ;
- pVBInfo->CR40[ j ][ 2 ] = pVideoMemory[ ii + 2 ] ;
- pVBInfo->CR40[ j ][ 3 ] = pVideoMemory[ ii + 3 ] ;
- pVBInfo->CR40[ j ][ 4 ] = pVideoMemory[ ii + 4 ] ;
- pVBInfo->CR40[ j ][ 5 ] = pVideoMemory[ ii + 5 ] ;
- pVBInfo->CR40[ j ][ 6 ] = pVideoMemory[ ii + 6 ] ;
- pVBInfo->CR40[ j ][ 7 ] = pVideoMemory[ ii + 7 ] ;
- ii += 0x08 ;
- }
-
- i = pVideoMemory[ 0x1C0 ] | ( pVideoMemory[ 0x1C1 ] << 8 ) ;
-
- for( j = 0 ; j < 8 ; j++ )
- {
- for( k = 0 ; k < 4 ; k++ )
- pVBInfo->CR6B[ j ][ k ] = pVideoMemory[ i + 4 * j + k ] ;
- }
-
- i = pVideoMemory[ 0x1C2 ] | ( pVideoMemory[ 0x1C3 ] << 8 ) ;
-
- for( j = 0 ; j < 8 ; j++ )
- {
- for( k = 0 ; k < 4 ; k++ )
- pVBInfo->CR6E[ j ][ k ] = pVideoMemory[ i + 4 * j + k ] ;
- }
-
- i = pVideoMemory[ 0x1C4 ] | ( pVideoMemory[ 0x1C5 ] << 8 ) ;
- for( j = 0 ; j < 8 ; j++ )
- {
- for( k = 0 ; k < 32 ; k++ )
- pVBInfo->CR6F[ j ][ k ] = pVideoMemory[ i + 32 * j + k ] ;
- }
-
- i = pVideoMemory[ 0x1C6 ] | ( pVideoMemory[ 0x1C7 ] << 8 ) ;
-
- for( j = 0 ; j < 8 ; j++ )
- {
- for( k = 0 ; k < 2 ; k++ )
- pVBInfo->CR89[ j ][ k ] = pVideoMemory[ i + 2 * j + k ] ;
- }
-
- i = pVideoMemory[ 0x1C8 ] | ( pVideoMemory[ 0x1C9 ] << 8 ) ;
- for( j = 0 ; j < 12 ; j++ )
- pVBInfo->AGPReg[ j ] = pVideoMemory[ i + j ] ;
-
- i = pVideoMemory[ 0x1CF ] | ( pVideoMemory[ 0x1D0 ] << 8 ) ;
- for( j = 0 ; j < 4 ; j++ )
- pVBInfo->SR16[ j ] = pVideoMemory[ i + j ] ;
-
- if ( ChipType == XG21 )
- {
- if (pVideoMemory[ 0x67 ] & 0x80)
- {
- *pVBInfo->pDVOSetting = pVideoMemory[ 0x67 ];
- }
- if ( (pVideoMemory[ 0x67 ] & 0xC0) == 0xC0 )
- {
- *pVBInfo->pCR2E = pVideoMemory[ i + 4 ] ;
- *pVBInfo->pCR2F = pVideoMemory[ i + 5 ] ;
- *pVBInfo->pCR46 = pVideoMemory[ i + 6 ] ;
- *pVBInfo->pCR47 = pVideoMemory[ i + 7 ] ;
- }
- }
-
- if ( ChipType == XG27 )
- {
- jj = i+j;
- for( i = 0 ; i <= 0xB ; i++,jj++ )
- pVBInfo->pCRD0[i] = pVideoMemory[ jj ] ;
- for( i = 0x0 ; i <= 0x1 ; i++,jj++ )
- pVBInfo->pCRDE[i] = pVideoMemory[ jj ] ;
-
- *pVBInfo->pSR40 = pVideoMemory[ jj ] ;
- jj++;
- *pVBInfo->pSR41 = pVideoMemory[ jj ] ;
-
- if (pVideoMemory[ 0x67 ] & 0x80)
- {
- *pVBInfo->pDVOSetting = pVideoMemory[ 0x67 ];
- }
- if ( (pVideoMemory[ 0x67 ] & 0xC0) == 0xC0 )
- {
- jj++;
- *pVBInfo->pCR2E = pVideoMemory[ jj ] ;
- *pVBInfo->pCR2F = pVideoMemory[ jj + 1 ] ;
- *pVBInfo->pCR46 = pVideoMemory[ jj + 2 ] ;
- *pVBInfo->pCR47 = pVideoMemory[ jj + 3 ] ;
- }
-
- }
-
- *pVBInfo->pCRCF = pVideoMemory[ 0x1CA ] ;
- *pVBInfo->pXGINew_DRAMTypeDefinition = pVideoMemory[ 0x1CB ] ;
- *pVBInfo->pXGINew_I2CDefinition = pVideoMemory[ 0x1D1 ] ;
- if ( ChipType >= XG20 )
- {
- *pVBInfo->pXGINew_CR97 = pVideoMemory[ 0x1D2 ] ;
- if ( ChipType == XG27 )
- {
- *pVBInfo->pSR36 = pVideoMemory[ 0x1D3 ] ;
- *pVBInfo->pCR8F = pVideoMemory[ 0x1D5 ] ;
- }
- }
-
- }
-#endif
+ volatile unsigned char *pVideoMemory = (unsigned char *)pVBInfo->ROMAddr;
+ unsigned long i ;
+ unsigned char j, k ;
/* Volari customize data area end */
if ( ChipType == XG21 )
@@ -2972,7 +2761,8 @@ void ReadVBIOSTablData( UCHAR ChipType , PVB_DEVICE_INFO pVBInfo)
i += 25;
j--;
k++;
- } while ( (j>0) && ( k < (sizeof(XGI21_LCDCapList)/sizeof(XGI21_LVDSCapStruct)) ) );
+ } while ((j > 0) &&
+ (k < (sizeof(XGI21_LCDCapList)/sizeof(struct XGI21_LVDSCapStruct))));
}
else
{
@@ -3003,7 +2793,7 @@ void ReadVBIOSTablData( UCHAR ChipType , PVB_DEVICE_INFO pVBInfo)
/* Output : */
/* Description : */
/* --------------------------------------------------------------------- */
-void XGINew_DDR1x_MRS_XG20( ULONG P3c4 , PVB_DEVICE_INFO pVBInfo)
+void XGINew_DDR1x_MRS_XG20(unsigned long P3c4, struct vb_device_info *pVBInfo)
{
XGINew_SetReg1( P3c4 , 0x18 , 0x01 ) ;
@@ -3039,13 +2829,13 @@ void XGINew_DDR1x_MRS_XG20( ULONG P3c4 , PVB_DEVICE_INFO pVBInfo)
/* Output : */
/* Description : */
/* --------------------------------------------------------------------- */
-void XGINew_SetDRAMModeRegister_XG20( PXGI_HW_DEVICE_INFO HwDeviceExtension )
+void XGINew_SetDRAMModeRegister_XG20(struct xgi_hw_device_info *HwDeviceExtension)
{
- VB_DEVICE_INFO VBINF;
- PVB_DEVICE_INFO pVBInfo = &VBINF;
+ struct vb_device_info VBINF;
+ struct vb_device_info *pVBInfo = &VBINF;
pVBInfo->ROMAddr = HwDeviceExtension->pjVirtualRomBase ;
pVBInfo->FBAddr = HwDeviceExtension->pjVideoMemoryAddress ;
- pVBInfo->BaseAddr = (ULONG)HwDeviceExtension->pjIOAddress ;
+ pVBInfo->BaseAddr = (unsigned long)HwDeviceExtension->pjIOAddress ;
pVBInfo->ISXPDOS = 0 ;
pVBInfo->P3c4 = pVBInfo->BaseAddr + 0x14 ;
@@ -3078,13 +2868,13 @@ void XGINew_SetDRAMModeRegister_XG20( PXGI_HW_DEVICE_INFO HwDeviceExtension )
XGINew_SetReg1( pVBInfo->P3c4 , 0x1B , 0x03 ) ;
}
-void XGINew_SetDRAMModeRegister_XG27( PXGI_HW_DEVICE_INFO HwDeviceExtension )
+void XGINew_SetDRAMModeRegister_XG27(struct xgi_hw_device_info *HwDeviceExtension)
{
- VB_DEVICE_INFO VBINF;
- PVB_DEVICE_INFO pVBInfo = &VBINF;
+ struct vb_device_info VBINF;
+ struct vb_device_info *pVBInfo = &VBINF;
pVBInfo->ROMAddr = HwDeviceExtension->pjVirtualRomBase ;
pVBInfo->FBAddr = HwDeviceExtension->pjVideoMemoryAddress ;
- pVBInfo->BaseAddr = (ULONG)HwDeviceExtension->pjIOAddress ;
+ pVBInfo->BaseAddr = (unsigned long)HwDeviceExtension->pjIOAddress ;
pVBInfo->ISXPDOS = 0 ;
pVBInfo->P3c4 = pVBInfo->BaseAddr + 0x14 ;
@@ -3120,13 +2910,12 @@ void XGINew_SetDRAMModeRegister_XG27( PXGI_HW_DEVICE_INFO HwDeviceExtension )
}
/*
-void XGINew_SetDRAMModeRegister_XG27( PXGI_HW_DEVICE_INFO HwDeviceExtension )
+void XGINew_SetDRAMModeRegister_XG27(struct xgi_hw_device_info *HwDeviceExtension)
{
-#ifndef LINUX_XF86
- UCHAR data ;
-#endif
- VB_DEVICE_INFO VBINF;
- PVB_DEVICE_INFO pVBInfo = &VBINF;
+
+ unsigned char data ;
+ struct vb_device_info VBINF;
+ struct vb_device_info *pVBInfo = &VBINF;
pVBInfo->ROMAddr = HwDeviceExtension->pjVirtualRomBase ;
pVBInfo->FBAddr = HwDeviceExtension->pjVideoMemoryAddress ;
pVBInfo->BaseAddr = HwDeviceExtension->pjIOAddress ;
@@ -3168,9 +2957,9 @@ void XGINew_SetDRAMModeRegister_XG27( PXGI_HW_DEVICE_INFO HwDeviceExtension )
/* Output : */
/* Description : */
/* -------------------------------------------------------- */
-void XGINew_ChkSenseStatus ( PXGI_HW_DEVICE_INFO HwDeviceExtension , PVB_DEVICE_INFO pVBInfo)
+void XGINew_ChkSenseStatus(struct xgi_hw_device_info *HwDeviceExtension, struct vb_device_info *pVBInfo)
{
- USHORT tempbx=0 , temp , tempcx , CR3CData;
+ unsigned short tempbx = 0, temp, tempcx, CR3CData;
temp = XGINew_GetReg1( pVBInfo->P3d4 , 0x32 ) ;
@@ -3229,9 +3018,9 @@ void XGINew_ChkSenseStatus ( PXGI_HW_DEVICE_INFO HwDeviceExtension , PVB_DEVICE_
/* Output : */
/* Description : */
/* -------------------------------------------------------- */
-void XGINew_SetModeScratch ( PXGI_HW_DEVICE_INFO HwDeviceExtension , PVB_DEVICE_INFO pVBInfo )
+void XGINew_SetModeScratch(struct xgi_hw_device_info *HwDeviceExtension, struct vb_device_info *pVBInfo)
{
- USHORT temp , tempcl = 0 , tempch = 0 , CR31Data , CR38Data;
+ unsigned short temp , tempcl = 0 , tempch = 0 , CR31Data , CR38Data;
temp = XGINew_GetReg1( pVBInfo->P3d4 , 0x3d ) ;
temp |= XGINew_GetReg1( pVBInfo->P3d4 , 0x3e ) << 8 ;
@@ -3326,23 +3115,13 @@ void XGINew_SetModeScratch ( PXGI_HW_DEVICE_INFO HwDeviceExtension , PVB_DEVICE_
/* Output : */
/* Description : */
/* -------------------------------------------------------- */
-void XGINew_GetXG21Sense(PXGI_HW_DEVICE_INFO HwDeviceExtension, PVB_DEVICE_INFO pVBInfo)
+void XGINew_GetXG21Sense(struct xgi_hw_device_info *HwDeviceExtension, struct vb_device_info *pVBInfo)
{
- UCHAR Temp;
- PUCHAR volatile pVideoMemory = ( PUCHAR )pVBInfo->ROMAddr ;
+ unsigned char Temp;
+ volatile unsigned char *pVideoMemory = (unsigned char *)pVBInfo->ROMAddr;
pVBInfo->IF_DEF_LVDS = 0 ;
-#ifdef WIN2000
- pVBInfo->IF_DEF_CH7007 = 0 ;
- if ( ( pVideoMemory[ 0x65 ] & 0x02 ) ) /* For XG21 CH7007 */
- {
- /* VideoDebugPrint((0, "ReadVBIOSTablData: pVideoMemory[ 0x65 ] =%x\n",pVideoMemory[ 0x65 ])); */
- pVBInfo->IF_DEF_CH7007 = 1 ; /* [Billy] 07/05/03 */
- XGINew_SetRegANDOR( pVBInfo->P3d4 , 0x38 , ~0xE0 , 0x60 ) ; /* CH7007 on chip */
- }
- else
-#endif
#if 1
if (( pVideoMemory[ 0x65 ] & 0x01 ) ) /* For XG21 LVDS */
{
@@ -3378,9 +3157,9 @@ void XGINew_GetXG21Sense(PXGI_HW_DEVICE_INFO HwDeviceExtension, PVB_DEVICE_INFO
/* Output : */
/* Description : */
/* -------------------------------------------------------- */
-void XGINew_GetXG27Sense(PXGI_HW_DEVICE_INFO HwDeviceExtension, PVB_DEVICE_INFO pVBInfo)
+void XGINew_GetXG27Sense(struct xgi_hw_device_info *HwDeviceExtension, struct vb_device_info *pVBInfo)
{
- UCHAR Temp,bCR4A;
+ unsigned char Temp, bCR4A;
pVBInfo->IF_DEF_LVDS = 0 ;
bCR4A = XGINew_GetReg1( pVBInfo->P3d4 , 0x4A ) ;
@@ -3402,9 +3181,9 @@ void XGINew_GetXG27Sense(PXGI_HW_DEVICE_INFO HwDeviceExtension, PVB_DEVICE_INFO
}
-UCHAR GetXG21FPBits(PVB_DEVICE_INFO pVBInfo)
+unsigned char GetXG21FPBits(struct vb_device_info *pVBInfo)
{
- UCHAR CR38,CR4A,temp;
+ unsigned char CR38, CR4A, temp;
CR4A = XGINew_GetReg1( pVBInfo->P3d4 , 0x4A ) ;
XGINew_SetRegANDOR( pVBInfo->P3d4 , 0x4A , ~0x10 , 0x10 ) ; /* enable GPIOE read */
@@ -3422,9 +3201,9 @@ UCHAR GetXG21FPBits(PVB_DEVICE_INFO pVBInfo)
return temp;
}
-UCHAR GetXG27FPBits(PVB_DEVICE_INFO pVBInfo)
+unsigned char GetXG27FPBits(struct vb_device_info *pVBInfo)
{
- UCHAR CR4A,temp;
+ unsigned char CR4A, temp;
CR4A = XGINew_GetReg1( pVBInfo->P3d4 , 0x4A ) ;
XGINew_SetRegANDOR( pVBInfo->P3d4 , 0x4A , ~0x03 , 0x03 ) ; /* enable GPIOA/B/C read */
diff --git a/drivers/staging/xgifb/vb_init.h b/drivers/staging/xgifb/vb_init.h
index 1f39d9c74cd..b47352b8e34 100644
--- a/drivers/staging/xgifb/vb_init.h
+++ b/drivers/staging/xgifb/vb_init.h
@@ -1,7 +1,7 @@
#ifndef _VBINIT_
#define _VBINIT_
-extern BOOLEAN XGIInitNew( PXGI_HW_DEVICE_INFO HwDeviceExtension ) ;
-extern XGI21_LVDSCapStruct XGI21_LCDCapList[13];
+extern unsigned char XGIInitNew(struct xgi_hw_device_info *HwDeviceExtension) ;
+extern struct XGI21_LVDSCapStruct XGI21_LCDCapList[13];
#endif
diff --git a/drivers/staging/xgifb/vb_setmode.c b/drivers/staging/xgifb/vb_setmode.c
index bd7f7389864..d90bf06bf62 100644
--- a/drivers/staging/xgifb/vb_setmode.c
+++ b/drivers/staging/xgifb/vb_setmode.c
@@ -1,43 +1,9 @@
-#include "osdef.h"
-#ifdef TC
-#include <stdio.h>
-#include <string.h>
-#include <conio.h>
-#include <dos.h>
-#endif
-
-
-#ifdef LINUX_XF86
-#include "xf86.h"
-#include "xf86PciInfo.h"
-#include "xgi.h"
-#include "xgi_regs.h"
-#endif
-
-#ifdef LINUX_KERNEL
#include <asm/io.h>
#include <linux/types.h>
#include <linux/version.h>
#include "XGIfb.h"
-/*#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
-#include <video/XGIfb.h>
-#else
-#include <linux/XGIfb.h>
-#endif*/
-#endif
-
-#ifdef WIN2000
-#include <dderror.h>
-#include <devioctl.h>
-#include <miniport.h>
-#include <ntddvdeo.h>
-#include <video.h>
-#include "xgiv.h"
-#include "dd_i2c.h"
-#include "tools.h"
-#endif
#include "vb_def.h"
#include "vgatypes.h"
@@ -54,194 +20,218 @@
-BOOLEAN XGI_IsLCDDualLink(PVB_DEVICE_INFO pVBInfo);
-BOOLEAN XGI_SetCRT2Group301(USHORT ModeNo, PXGI_HW_DEVICE_INFO HwDeviceExtension,PVB_DEVICE_INFO pVBInfo);
-BOOLEAN XGI_BacklightByDrv(PVB_DEVICE_INFO pVBInfo);
-
-BOOLEAN XGI_IsLCDON(PVB_DEVICE_INFO pVBInfo);
-BOOLEAN XGI_DisableChISLCD(PVB_DEVICE_INFO pVBInfo);
-BOOLEAN XGI_EnableChISLCD(PVB_DEVICE_INFO pVBInfo);
-BOOLEAN XGI_AjustCRT2Rate(USHORT ModeNo,USHORT ModeIdIndex,USHORT RefreshRateTableIndex,USHORT *i, PVB_DEVICE_INFO pVBInfo);
-BOOLEAN XGI_SearchModeID( USHORT ModeNo,USHORT *ModeIdIndex, PVB_DEVICE_INFO pVBInfo);
-BOOLEAN XGI_GetLCDInfo(USHORT ModeNo,USHORT ModeIdIndex, PVB_DEVICE_INFO pVBInfo);
-BOOLEAN XGISetModeNew( PXGI_HW_DEVICE_INFO HwDeviceExtension , USHORT ModeNo ) ;
-BOOLEAN XGI_BridgeIsOn(PVB_DEVICE_INFO pVBInfo);
-UCHAR XGI_GetModePtr( USHORT ModeNo,USHORT ModeIdIndex,PVB_DEVICE_INFO pVBInfo);
-USHORT XGI_GetOffset(USHORT ModeNo,USHORT ModeIdIndex,USHORT RefreshRateTableIndex,PXGI_HW_DEVICE_INFO HwDeviceExtension,PVB_DEVICE_INFO pVBInfo);
-USHORT XGI_GetRatePtrCRT2( PXGI_HW_DEVICE_INFO pXGIHWDE, USHORT ModeNo,USHORT ModeIdIndex,PVB_DEVICE_INFO pVBInfo );
-USHORT XGI_GetResInfo(USHORT ModeNo,USHORT ModeIdIndex, PVB_DEVICE_INFO pVBInfo);
-USHORT XGI_GetColorDepth(USHORT ModeNo,USHORT ModeIdIndex,PVB_DEVICE_INFO pVBInfo);
-USHORT XGI_GetVGAHT2(PVB_DEVICE_INFO pVBInfo);
-USHORT XGI_GetVCLK2Ptr(USHORT ModeNo,USHORT ModeIdIndex,USHORT RefreshRateTableIndex,PXGI_HW_DEVICE_INFO HwDeviceExtension,PVB_DEVICE_INFO pVBInfo);
-void XGI_VBLongWait(PVB_DEVICE_INFO pVBInfo);
-void XGI_SaveCRT2Info(USHORT ModeNo, PVB_DEVICE_INFO pVBInfo);
-void XGI_GetCRT2Data(USHORT ModeNo,USHORT ModeIdIndex,USHORT RefreshRateTableIndex, PVB_DEVICE_INFO pVBInfo);
-void XGI_GetCRT2ResInfo(USHORT ModeNo,USHORT ModeIdIndex, PVB_DEVICE_INFO pVBInfo);
-void XGI_PreSetGroup1(USHORT ModeNo,USHORT ModeIdIndex, PXGI_HW_DEVICE_INFO HwDeviceExtension,USHORT RefreshRateTableIndex, PVB_DEVICE_INFO pVBInfo);
-void XGI_SetGroup1(USHORT ModeNo,USHORT ModeIdIndex, PXGI_HW_DEVICE_INFO HwDeviceExtension,USHORT RefreshRateTableIndex, PVB_DEVICE_INFO pVBInfo);
-void XGI_SetLockRegs(USHORT ModeNo,USHORT ModeIdIndex, PXGI_HW_DEVICE_INFO HwDeviceExtension,USHORT RefreshRateTableIndex, PVB_DEVICE_INFO pVBInfo);
-void XGI_SetLCDRegs(USHORT ModeNo,USHORT ModeIdIndex, PXGI_HW_DEVICE_INFO HwDeviceExtension,USHORT RefreshRateTableIndex, PVB_DEVICE_INFO pVBInfo);
-void XGI_SetGroup2(USHORT ModeNo,USHORT ModeIdIndex,USHORT RefreshRateTableIndex,PXGI_HW_DEVICE_INFO HwDeviceExtension, PVB_DEVICE_INFO pVBInfo);
-void XGI_SetGroup3(USHORT ModeNo,USHORT ModeIdIndex, PVB_DEVICE_INFO pVBInfo);
-void XGI_SetGroup4(USHORT ModeNo,USHORT ModeIdIndex,USHORT RefreshRateTableIndex,PXGI_HW_DEVICE_INFO HwDeviceExtension, PVB_DEVICE_INFO pVBInfo);
-void XGI_SetGroup5(USHORT ModeNo,USHORT ModeIdIndex, PVB_DEVICE_INFO pVBInfo);
-void* XGI_GetLcdPtr(USHORT BX, USHORT ModeNo, USHORT ModeIdIndex, USHORT RefreshRateTableIndex, PVB_DEVICE_INFO pVBInfo);
-void* XGI_GetTVPtr(USHORT BX, USHORT ModeNo,USHORT ModeIdIndex,USHORT RefreshRateTableIndex, PVB_DEVICE_INFO pVBInfo);
-void XGI_FirePWDEnable(PVB_DEVICE_INFO pVBInfo);
-void XGI_EnableGatingCRT(PXGI_HW_DEVICE_INFO HwDeviceExtension, PVB_DEVICE_INFO pVBInfo);
-void XGI_DisableGatingCRT(PXGI_HW_DEVICE_INFO HwDeviceExtension, PVB_DEVICE_INFO pVBInfo);
-void XGI_SetPanelDelay(USHORT tempbl, PVB_DEVICE_INFO pVBInfo);
-void XGI_SetPanelPower(USHORT tempah,USHORT tempbl, PVB_DEVICE_INFO pVBInfo);
-void XGI_EnablePWD( PVB_DEVICE_INFO pVBInfo);
-void XGI_DisablePWD( PVB_DEVICE_INFO pVBInfo);
-void XGI_AutoThreshold( PVB_DEVICE_INFO pVBInfo);
-void XGI_SetTap4Regs( PVB_DEVICE_INFO pVBInfo);
-
-void XGI_DisplayOn(PXGI_HW_DEVICE_INFO, PVB_DEVICE_INFO pVBInfo);
-void XGI_DisplayOff( PXGI_HW_DEVICE_INFO, PVB_DEVICE_INFO pVBInfo );
-void XGI_SetCRT1Group(PXGI_HW_DEVICE_INFO HwDeviceExtension,USHORT ModeNo,USHORT ModeIdIndex,PVB_DEVICE_INFO pVBInfo);
-void XGI_SetXG21CRTC(USHORT ModeNo, USHORT ModeIdIndex, USHORT RefreshRateTableIndex, PVB_DEVICE_INFO pVBInfo);
-void XGI_SetXG21LCD(PVB_DEVICE_INFO pVBInfo,USHORT RefreshRateTableIndex,USHORT ModeNo);
-void XGI_SetXG27CRTC(USHORT ModeNo, USHORT ModeIdIndex, USHORT RefreshRateTableIndex, PVB_DEVICE_INFO pVBInfo);
-void XGI_SetXG27LCD(PVB_DEVICE_INFO pVBInfo,USHORT RefreshRateTableIndex,USHORT ModeNo);
-void XGI_UpdateXG21CRTC(USHORT ModeNo, PVB_DEVICE_INFO pVBInfo, USHORT RefreshRateTableIndex);
-void XGI_WaitDisply(PVB_DEVICE_INFO pVBInfo);
-void XGI_SenseCRT1(PVB_DEVICE_INFO pVBInfo);
-void XGI_SetSeqRegs(USHORT ModeNo,USHORT StandTableIndex,USHORT ModeIdIndex,PVB_DEVICE_INFO pVBInfo);
-void XGI_SetMiscRegs(USHORT StandTableIndex, PVB_DEVICE_INFO pVBInfo);
-void XGI_SetCRTCRegs(PXGI_HW_DEVICE_INFO HwDeviceExtension,USHORT StandTableIndex, PVB_DEVICE_INFO pVBInfo);
-void XGI_SetATTRegs(USHORT ModeNo,USHORT StandTableIndex,USHORT ModeIdIndex,PVB_DEVICE_INFO pVBInfo );
-void XGI_SetGRCRegs(USHORT StandTableIndex, PVB_DEVICE_INFO pVBInfo);
-void XGI_ClearExt1Regs(PVB_DEVICE_INFO pVBInfo);
-
-void XGI_SetSync(USHORT RefreshRateTableIndex,PVB_DEVICE_INFO pVBInfo);
-void XGI_SetCRT1CRTC(USHORT ModeNo,USHORT ModeIdIndex,USHORT RefreshRateTableIndex,PVB_DEVICE_INFO pVBInfo,PXGI_HW_DEVICE_INFO HwDeviceExtension);
-void XGI_SetCRT1Timing_H(PVB_DEVICE_INFO pVBInfo,PXGI_HW_DEVICE_INFO HwDeviceExtension);
-void XGI_SetCRT1Timing_V(USHORT ModeIdIndex,USHORT ModeNo,PVB_DEVICE_INFO pVBInfo);
-void XGI_SetCRT1DE(PXGI_HW_DEVICE_INFO HwDeviceExtension,USHORT ModeNo,USHORT ModeIdIndex,USHORT RefreshRateTableIndex,PVB_DEVICE_INFO pVBInfo);
-void XGI_SetCRT1VCLK(USHORT ModeNo,USHORT ModeIdIndex,PXGI_HW_DEVICE_INFO HwDeviceExtension,USHORT RefreshRateTableIndex, PVB_DEVICE_INFO pVBInfo);
-void XGI_SetCRT1FIFO(USHORT ModeNo,PXGI_HW_DEVICE_INFO HwDeviceExtension, PVB_DEVICE_INFO pVBInfo);
-void XGI_SetCRT1ModeRegs(PXGI_HW_DEVICE_INFO HwDeviceExtension,USHORT ModeNo,USHORT ModeIdIndex,USHORT RefreshRateTableIndex,PVB_DEVICE_INFO pVBInfo);
-void XGI_SetVCLKState(PXGI_HW_DEVICE_INFO HwDeviceExtension,USHORT ModeNo,USHORT RefreshRateTableIndex,PVB_DEVICE_INFO pVBInfo);
-
-void XGI_LoadDAC(USHORT ModeNo,USHORT ModeIdIndex,PVB_DEVICE_INFO pVBInfo);
-void XGI_WriteDAC(USHORT dl, USHORT ah, USHORT al, USHORT dh, PVB_DEVICE_INFO pVBInfo);
-/*void XGI_ClearBuffer(PXGI_HW_DEVICE_INFO HwDeviceExtension,USHORT ModeNo,PVB_DEVICE_INFO pVBInfo);*/
-void XGI_SetLCDAGroup(USHORT ModeNo,USHORT ModeIdIndex,PXGI_HW_DEVICE_INFO HwDeviceExtension,PVB_DEVICE_INFO pVBInfo);
-void XGI_GetLVDSResInfo( USHORT ModeNo,USHORT ModeIdIndex,PVB_DEVICE_INFO pVBInfo);
-void XGI_GetLVDSData(USHORT ModeNo,USHORT ModeIdIndex,USHORT RefreshRateTableIndex,PVB_DEVICE_INFO pVBInfo);
-void XGI_ModCRT1Regs(USHORT ModeNo,USHORT ModeIdIndex,USHORT RefreshRateTableIndex,PXGI_HW_DEVICE_INFO HwDeviceExtension,PVB_DEVICE_INFO pVBInfo);
-void XGI_SetLVDSRegs(USHORT ModeNo,USHORT ModeIdIndex,USHORT RefreshRateTableIndex,PVB_DEVICE_INFO pVBInfo);
-void XGI_UpdateModeInfo(PXGI_HW_DEVICE_INFO HwDeviceExtension,PVB_DEVICE_INFO pVBInfo);
-void XGI_GetVGAType(PXGI_HW_DEVICE_INFO HwDeviceExtension,PVB_DEVICE_INFO pVBInfo);
-void XGI_GetVBType(PVB_DEVICE_INFO pVBInfo);
-void XGI_GetVBInfo(USHORT ModeNo,USHORT ModeIdIndex,PXGI_HW_DEVICE_INFO HwDeviceExtension,PVB_DEVICE_INFO pVBInfo);
-void XGI_GetTVInfo(USHORT ModeNo,USHORT ModeIdIndex,PVB_DEVICE_INFO pVBInfo);
-void XGI_SetCRT2ECLK( USHORT ModeNo,USHORT ModeIdIndex,USHORT RefreshRateTableIndex,PVB_DEVICE_INFO pVBInfo);
-void InitTo330Pointer(UCHAR,PVB_DEVICE_INFO pVBInfo);
-void XGI_GetLCDSync(USHORT* HSyncWidth, USHORT* VSyncWidth, PVB_DEVICE_INFO pVBInfo);
-void XGI_DisableBridge(PXGI_HW_DEVICE_INFO HwDeviceExtension, PVB_DEVICE_INFO pVBInfo);
-void XGI_EnableBridge(PXGI_HW_DEVICE_INFO HwDeviceExtension, PVB_DEVICE_INFO pVBInfo);
-void XGI_SetCRT2VCLK(USHORT ModeNo,USHORT ModeIdIndex,USHORT RefreshRateTableIndex, PVB_DEVICE_INFO pVBInfo);
-void XGI_OEM310Setting(USHORT ModeNo,USHORT ModeIdIndex, PVB_DEVICE_INFO pVBInfo);
-void XGI_SetDelayComp(PVB_DEVICE_INFO pVBInfo);
-void XGI_SetLCDCap(PVB_DEVICE_INFO pVBInfo);
-void XGI_SetLCDCap_A(USHORT tempcx,PVB_DEVICE_INFO pVBInfo);
-void XGI_SetLCDCap_B(USHORT tempcx,PVB_DEVICE_INFO pVBInfo);
-void SetSpectrum(PVB_DEVICE_INFO pVBInfo);
-void XGI_SetAntiFlicker(USHORT ModeNo,USHORT ModeIdIndex, PVB_DEVICE_INFO pVBInfo);
-void XGI_SetEdgeEnhance(USHORT ModeNo,USHORT ModeIdIndex, PVB_DEVICE_INFO pVBInfo);
-void XGI_SetPhaseIncr(PVB_DEVICE_INFO pVBInfo);
-void XGI_SetYFilter(USHORT ModeNo,USHORT ModeIdIndex, PVB_DEVICE_INFO pVBInfo);
-void XGI_GetTVPtrIndex2(USHORT* tempbx,UCHAR* tempcl,UCHAR* tempch, PVB_DEVICE_INFO pVBInfo);
-USHORT XGI_GetTVPtrIndex( PVB_DEVICE_INFO pVBInfo );
-void XGI_SetCRT2ModeRegs(USHORT ModeNo,PXGI_HW_DEVICE_INFO, PVB_DEVICE_INFO pVBInfo );
-void XGI_CloseCRTC(PXGI_HW_DEVICE_INFO, PVB_DEVICE_INFO pVBInfo);
-void XGI_OpenCRTC(PXGI_HW_DEVICE_INFO, PVB_DEVICE_INFO pVBInfo);
-void XGI_GetRAMDAC2DATA(USHORT ModeNo,USHORT ModeIdIndex,USHORT RefreshRateTableIndex, PVB_DEVICE_INFO pVBInfo);
-void XGI_UnLockCRT2(PXGI_HW_DEVICE_INFO, PVB_DEVICE_INFO pVBInfo);
-void XGI_LockCRT2(PXGI_HW_DEVICE_INFO, PVB_DEVICE_INFO pVBInfo);
-void XGINew_EnableCRT2(PVB_DEVICE_INFO pVBInfo);
-void XGINew_LCD_Wait_Time(UCHAR DelayTime, PVB_DEVICE_INFO pVBInfo);
-void XGI_LongWait(PVB_DEVICE_INFO pVBInfo);
-void XGI_SetCRT1Offset( USHORT ModeNo , USHORT ModeIdIndex , USHORT RefreshRateTableIndex , PXGI_HW_DEVICE_INFO HwDeviceExtension,PVB_DEVICE_INFO pVBInfo );
-void XGI_GetLCDVCLKPtr(UCHAR* di_0,UCHAR *di_1, PVB_DEVICE_INFO pVBInfo);
-UCHAR XGI_GetVCLKPtr(USHORT RefreshRateTableIndex,USHORT ModeNo,USHORT ModeIdIndex, PVB_DEVICE_INFO pVBInfo);
-void XGI_GetVCLKLen(UCHAR tempal,UCHAR* di_0,UCHAR* di_1, PVB_DEVICE_INFO pVBInfo);
-USHORT XGI_GetLCDCapPtr(PVB_DEVICE_INFO pVBInfo);
-USHORT XGI_GetLCDCapPtr1(PVB_DEVICE_INFO pVBInfo);
-XGI301C_Tap4TimingStruct* XGI_GetTap4Ptr(USHORT tempcx, PVB_DEVICE_INFO pVBInfo);
-void XGI_SetXG21FPBits(PVB_DEVICE_INFO pVBInfo);
-void XGI_SetXG27FPBits(PVB_DEVICE_INFO pVBInfo);
-UCHAR XGI_XG21GetPSCValue(PVB_DEVICE_INFO pVBInfo);
-UCHAR XGI_XG27GetPSCValue(PVB_DEVICE_INFO pVBInfo);
-void XGI_XG21BLSignalVDD(USHORT tempbh,USHORT tempbl, PVB_DEVICE_INFO pVBInfo);
-void XGI_XG27BLSignalVDD(USHORT tempbh,USHORT tempbl, PVB_DEVICE_INFO pVBInfo);
-void XGI_XG21SetPanelDelay(USHORT tempbl, PVB_DEVICE_INFO pVBInfo);
-BOOLEAN XGI_XG21CheckLVDSMode(USHORT ModeNo,USHORT ModeIdIndex, PVB_DEVICE_INFO pVBInfo );
-void XGI_SetXG21LVDSPara(USHORT ModeNo,USHORT ModeIdIndex, PVB_DEVICE_INFO pVBInfo );
-void XGI_SetXG27LVDSPara(USHORT ModeNo,USHORT ModeIdIndex, PVB_DEVICE_INFO pVBInfo );
-UCHAR XGI_SetDefaultVCLK( PVB_DEVICE_INFO pVBInfo );
-
-extern void ReadVBIOSTablData( UCHAR ChipType , PVB_DEVICE_INFO pVBInfo);
-#ifdef WIN2000
-/* [Billy] 2007/05/17 For CH7007 */
-extern UCHAR CH7007TVReg_UNTSC[][8],CH7007TVReg_ONTSC[][8],CH7007TVReg_UPAL[][8],CH7007TVReg_OPAL[][8];
-extern UCHAR CH7007TVCRT1UNTSC_H[][10],CH7007TVCRT1ONTSC_H[][10],CH7007TVCRT1UPAL_H[][10],CH7007TVCRT1OPAL_H[][10] ;
-extern UCHAR CH7007TVCRT1UNTSC_V[][10],CH7007TVCRT1ONTSC_V[][10],CH7007TVCRT1UPAL_V[][10],CH7007TVCRT1OPAL_V[][10] ;
-extern UCHAR XGI7007_CHTVVCLKUNTSC[],XGI7007_CHTVVCLKONTSC[],XGI7007_CHTVVCLKUPAL[],XGI7007_CHTVVCLKOPAL[];
-
-extern BOOLEAN XGI_XG21CheckCH7007TVMode(USHORT ModeNo,USHORT ModeIdIndex, PVB_DEVICE_INFO pVBInfo ) ;
-extern void SetCH7007Regs(PXGI_HW_DEVICE_INFO HwDeviceExtension, USHORT ModeNo, USHORT ModeIdIndex, USHORT RefreshRateTableIndex, PVB_DEVICE_INFO pVBInfo ) ;
-extern VP_STATUS TurnOnCH7007(PHW_DEVICE_EXTENSION pHWDE) ;
-extern VP_STATUS TurnOffCH7007(PHW_DEVICE_EXTENSION pHWDE) ;
-extern BOOLEAN IsCH7007TVMode(PVB_DEVICE_INFO pVBInfo) ;
-#endif
-
-/* USHORT XGINew_flag_clearbuffer; 0: no clear frame buffer 1:clear frame buffer */
-
-
-
-
-
-USHORT XGINew_MDA_DAC[]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15,
- 0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15,
- 0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15,
- 0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15,
- 0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F};
-
-USHORT XGINew_CGA_DAC[]={0x00,0x10,0x04,0x14,0x01,0x11,0x09,0x15,
- 0x00,0x10,0x04,0x14,0x01,0x11,0x09,0x15,
- 0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F,
- 0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F,
- 0x00,0x10,0x04,0x14,0x01,0x11,0x09,0x15,
- 0x00,0x10,0x04,0x14,0x01,0x11,0x09,0x15,
- 0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F,
- 0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F};
-
-USHORT XGINew_EGA_DAC[]={0x00,0x10,0x04,0x14,0x01,0x11,0x05,0x15,
- 0x20,0x30,0x24,0x34,0x21,0x31,0x25,0x35,
- 0x08,0x18,0x0C,0x1C,0x09,0x19,0x0D,0x1D,
- 0x28,0x38,0x2C,0x3C,0x29,0x39,0x2D,0x3D,
- 0x02,0x12,0x06,0x16,0x03,0x13,0x07,0x17,
- 0x22,0x32,0x26,0x36,0x23,0x33,0x27,0x37,
- 0x0A,0x1A,0x0E,0x1E,0x0B,0x1B,0x0F,0x1F,
- 0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F};
-
-USHORT XGINew_VGA_DAC[]={0x00,0x10,0x04,0x14,0x01,0x11,0x09,0x15,
- 0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F,
- 0x00,0x05,0x08,0x0B,0x0E,0x11,0x14,0x18,
- 0x1C,0x20,0x24,0x28,0x2D,0x32,0x38,0x3F,
-
- 0x00,0x10,0x1F,0x2F,0x3F,0x1F,0x27,0x2F,
- 0x37,0x3F,0x2D,0x31,0x36,0x3A,0x3F,0x00,
- 0x07,0x0E,0x15,0x1C,0x0E,0x11,0x15,0x18,
- 0x1C,0x14,0x16,0x18,0x1A,0x1C,0x00,0x04,
- 0x08,0x0C,0x10,0x08,0x0A,0x0C,0x0E,0x10,
- 0x0B,0x0C,0x0D,0x0F,0x10};
+unsigned char XGI_IsLCDDualLink(struct vb_device_info *pVBInfo);
+unsigned char XGI_SetCRT2Group301(unsigned short ModeNo,
+ struct xgi_hw_device_info *HwDeviceExtension,
+ struct vb_device_info *pVBInfo);
+unsigned char XGI_BacklightByDrv(struct vb_device_info *pVBInfo);
+
+unsigned char XGI_IsLCDON(struct vb_device_info *pVBInfo);
+unsigned char XGI_DisableChISLCD(struct vb_device_info *pVBInfo);
+unsigned char XGI_EnableChISLCD(struct vb_device_info *pVBInfo);
+unsigned char XGI_AjustCRT2Rate(unsigned short ModeNo,
+ unsigned short ModeIdIndex,
+ unsigned short RefreshRateTableIndex,
+ unsigned short *i, struct vb_device_info *pVBInfo);
+unsigned char XGI_SearchModeID(unsigned short ModeNo,
+ unsigned short *ModeIdIndex,
+ struct vb_device_info *pVBInfo);
+unsigned char XGI_GetLCDInfo(unsigned short ModeNo,
+ unsigned short ModeIdIndex,
+ struct vb_device_info *pVBInfo);
+unsigned char XGISetModeNew(struct xgi_hw_device_info *HwDeviceExtension,
+ unsigned short ModeNo);
+unsigned char XGI_BridgeIsOn(struct vb_device_info *pVBInfo);
+unsigned char XGI_GetModePtr(unsigned short ModeNo,
+ unsigned short ModeIdIndex,
+ struct vb_device_info *pVBInfo);
+unsigned short XGI_GetOffset(unsigned short ModeNo,
+ unsigned short ModeIdIndex,
+ unsigned short RefreshRateTableIndex,
+ struct xgi_hw_device_info *HwDeviceExtension,
+ struct vb_device_info *pVBInfo);
+unsigned short XGI_GetRatePtrCRT2(struct xgi_hw_device_info *pXGIHWDE,
+ unsigned short ModeNo,
+ unsigned short ModeIdIndex,
+ struct vb_device_info *pVBInfo);
+unsigned short XGI_GetResInfo(unsigned short ModeNo,
+ unsigned short ModeIdIndex,
+ struct vb_device_info *pVBInfo);
+unsigned short XGI_GetColorDepth(unsigned short ModeNo,
+ unsigned short ModeIdIndex,
+ struct vb_device_info *pVBInfo);
+unsigned short XGI_GetVGAHT2(struct vb_device_info *pVBInfo);
+unsigned short XGI_GetVCLK2Ptr(unsigned short ModeNo,
+ unsigned short ModeIdIndex,
+ unsigned short RefreshRateTableIndex,
+ struct xgi_hw_device_info *HwDeviceExtension,
+ struct vb_device_info *pVBInfo);
+void XGI_VBLongWait(struct vb_device_info *pVBInfo);
+void XGI_SaveCRT2Info(unsigned short ModeNo, struct vb_device_info *pVBInfo);
+void XGI_GetCRT2Data(unsigned short ModeNo, unsigned short ModeIdIndex, unsigned short RefreshRateTableIndex, struct vb_device_info *pVBInfo);
+void XGI_GetCRT2ResInfo(unsigned short ModeNo, unsigned short ModeIdIndex, struct vb_device_info *pVBInfo);
+void XGI_PreSetGroup1(unsigned short ModeNo, unsigned short ModeIdIndex, struct xgi_hw_device_info *HwDeviceExtension, unsigned short RefreshRateTableIndex, struct vb_device_info *pVBInfo);
+void XGI_SetGroup1(unsigned short ModeNo, unsigned short ModeIdIndex, struct xgi_hw_device_info *HwDeviceExtension, unsigned short RefreshRateTableIndex, struct vb_device_info *pVBInfo);
+void XGI_SetLockRegs(unsigned short ModeNo, unsigned short ModeIdIndex, struct xgi_hw_device_info *HwDeviceExtension, unsigned short RefreshRateTableIndex, struct vb_device_info *pVBInfo);
+void XGI_SetLCDRegs(unsigned short ModeNo, unsigned short ModeIdIndex, struct xgi_hw_device_info *HwDeviceExtension, unsigned short RefreshRateTableIndex, struct vb_device_info *pVBInfo);
+void XGI_SetGroup2(unsigned short ModeNo, unsigned short ModeIdIndex, unsigned short RefreshRateTableIndex, struct xgi_hw_device_info *HwDeviceExtension, struct vb_device_info *pVBInfo);
+void XGI_SetGroup3(unsigned short ModeNo, unsigned short ModeIdIndex, struct vb_device_info *pVBInfo);
+void XGI_SetGroup4(unsigned short ModeNo, unsigned short ModeIdIndex, unsigned short RefreshRateTableIndex, struct xgi_hw_device_info *HwDeviceExtension, struct vb_device_info *pVBInfo);
+void XGI_SetGroup5(unsigned short ModeNo, unsigned short ModeIdIndex, struct vb_device_info *pVBInfo);
+void *XGI_GetLcdPtr(unsigned short BX, unsigned short ModeNo, unsigned short ModeIdIndex, unsigned short RefreshRateTableIndex, struct vb_device_info *pVBInfo);
+void *XGI_GetTVPtr(unsigned short BX, unsigned short ModeNo, unsigned short ModeIdIndex, unsigned short RefreshRateTableIndex, struct vb_device_info *pVBInfo);
+void XGI_FirePWDEnable(struct vb_device_info *pVBInfo);
+void XGI_EnableGatingCRT(struct xgi_hw_device_info *HwDeviceExtension, struct vb_device_info *pVBInfo);
+void XGI_DisableGatingCRT(struct xgi_hw_device_info *HwDeviceExtension, struct vb_device_info *pVBInfo);
+void XGI_SetPanelDelay(unsigned short tempbl, struct vb_device_info *pVBInfo);
+void XGI_SetPanelPower(unsigned short tempah, unsigned short tempbl, struct vb_device_info *pVBInfo);
+void XGI_EnablePWD(struct vb_device_info *pVBInfo);
+void XGI_DisablePWD(struct vb_device_info *pVBInfo);
+void XGI_AutoThreshold(struct vb_device_info *pVBInfo);
+void XGI_SetTap4Regs(struct vb_device_info *pVBInfo);
+
+void XGI_DisplayOn(struct xgi_hw_device_info *, struct vb_device_info *pVBInfo);
+void XGI_DisplayOff(struct xgi_hw_device_info *, struct vb_device_info *pVBInfo);
+void XGI_SetCRT1Group(struct xgi_hw_device_info *HwDeviceExtension, unsigned short ModeNo, unsigned short ModeIdIndex, struct vb_device_info *pVBInfo);
+void XGI_SetXG21CRTC(unsigned short ModeNo, unsigned short ModeIdIndex, unsigned short RefreshRateTableIndex, struct vb_device_info *pVBInfo);
+void XGI_SetXG21LCD(struct vb_device_info *pVBInfo, unsigned short RefreshRateTableIndex, unsigned short ModeNo);
+void XGI_SetXG27CRTC(unsigned short ModeNo, unsigned short ModeIdIndex, unsigned short RefreshRateTableIndex, struct vb_device_info *pVBInfo);
+void XGI_SetXG27LCD(struct vb_device_info *pVBInfo, unsigned short RefreshRateTableIndex, unsigned short ModeNo);
+void XGI_UpdateXG21CRTC(unsigned short ModeNo, struct vb_device_info *pVBInfo, unsigned short RefreshRateTableIndex);
+void XGI_WaitDisply(struct vb_device_info *pVBInfo);
+void XGI_SenseCRT1(struct vb_device_info *pVBInfo);
+void XGI_SetSeqRegs(unsigned short ModeNo, unsigned short StandTableIndex, unsigned short ModeIdIndex, struct vb_device_info *pVBInfo);
+void XGI_SetMiscRegs(unsigned short StandTableIndex, struct vb_device_info *pVBInfo);
+void XGI_SetCRTCRegs(struct xgi_hw_device_info *HwDeviceExtension, unsigned short StandTableIndex, struct vb_device_info *pVBInfo);
+void XGI_SetATTRegs(unsigned short ModeNo, unsigned short StandTableIndex, unsigned short ModeIdIndex, struct vb_device_info *pVBInfo);
+void XGI_SetGRCRegs(unsigned short StandTableIndex, struct vb_device_info *pVBInfo);
+void XGI_ClearExt1Regs(struct vb_device_info *pVBInfo);
+
+void XGI_SetSync(unsigned short RefreshRateTableIndex, struct vb_device_info *pVBInfo);
+void XGI_SetCRT1CRTC(unsigned short ModeNo, unsigned short ModeIdIndex, unsigned short RefreshRateTableIndex, struct vb_device_info *pVBInfo, struct xgi_hw_device_info *HwDeviceExtension);
+void XGI_SetCRT1Timing_H(struct vb_device_info *pVBInfo, struct xgi_hw_device_info *HwDeviceExtension);
+void XGI_SetCRT1Timing_V(unsigned short ModeIdIndex, unsigned short ModeNo, struct vb_device_info *pVBInfo);
+void XGI_SetCRT1DE(struct xgi_hw_device_info *HwDeviceExtension, unsigned short ModeNo, unsigned short ModeIdIndex, unsigned short RefreshRateTableIndex, struct vb_device_info *pVBInfo);
+void XGI_SetCRT1VCLK(unsigned short ModeNo, unsigned short ModeIdIndex, struct xgi_hw_device_info *HwDeviceExtension, unsigned short RefreshRateTableIndex, struct vb_device_info *pVBInfo);
+void XGI_SetCRT1FIFO(unsigned short ModeNo, struct xgi_hw_device_info *HwDeviceExtension, struct vb_device_info *pVBInfo);
+void XGI_SetCRT1ModeRegs(struct xgi_hw_device_info *HwDeviceExtension, unsigned short ModeNo, unsigned short ModeIdIndex, unsigned short RefreshRateTableIndex, struct vb_device_info *pVBInfo);
+void XGI_SetVCLKState(struct xgi_hw_device_info *HwDeviceExtension, unsigned short ModeNo, unsigned short RefreshRateTableIndex, struct vb_device_info *pVBInfo);
+
+void XGI_LoadDAC(unsigned short ModeNo, unsigned short ModeIdIndex, struct vb_device_info *pVBInfo);
+void XGI_WriteDAC(unsigned short dl, unsigned short ah, unsigned short al, unsigned short dh, struct vb_device_info *pVBInfo);
+/*void XGI_ClearBuffer(struct xgi_hw_device_info *HwDeviceExtension, unsigned short ModeNo, struct vb_device_info *pVBInfo);*/
+void XGI_SetLCDAGroup(unsigned short ModeNo, unsigned short ModeIdIndex, struct xgi_hw_device_info *HwDeviceExtension, struct vb_device_info *pVBInfo);
+void XGI_GetLVDSResInfo(unsigned short ModeNo, unsigned short ModeIdIndex,
+ struct vb_device_info *pVBInfo);
+void XGI_GetLVDSData(unsigned short ModeNo, unsigned short ModeIdIndex, unsigned short RefreshRateTableIndex, struct vb_device_info *pVBInfo);
+void XGI_ModCRT1Regs(unsigned short ModeNo, unsigned short ModeIdIndex,
+ unsigned short RefreshRateTableIndex,
+ struct xgi_hw_device_info *HwDeviceExtension,
+ struct vb_device_info *pVBInfo);
+void XGI_SetLVDSRegs(unsigned short ModeNo, unsigned short ModeIdIndex, unsigned short RefreshRateTableIndex, struct vb_device_info *pVBInfo);
+void XGI_UpdateModeInfo(struct xgi_hw_device_info *HwDeviceExtension, struct vb_device_info *pVBInfo);
+void XGI_GetVGAType(struct xgi_hw_device_info *HwDeviceExtension, struct vb_device_info *pVBInfo);
+void XGI_GetVBType(struct vb_device_info *pVBInfo);
+void XGI_GetVBInfo(unsigned short ModeNo, unsigned short ModeIdIndex, struct xgi_hw_device_info *HwDeviceExtension, struct vb_device_info *pVBInfo);
+void XGI_GetTVInfo(unsigned short ModeNo, unsigned short ModeIdIndex, struct vb_device_info *pVBInfo);
+void XGI_SetCRT2ECLK(unsigned short ModeNo, unsigned short ModeIdIndex, unsigned short RefreshRateTableIndex, struct vb_device_info *pVBInfo);
+void InitTo330Pointer(unsigned char, struct vb_device_info *pVBInfo);
+void XGI_GetLCDSync(unsigned short *HSyncWidth, unsigned short *VSyncWidth, struct vb_device_info *pVBInfo);
+void XGI_DisableBridge(struct xgi_hw_device_info *HwDeviceExtension, struct vb_device_info *pVBInfo);
+void XGI_EnableBridge(struct xgi_hw_device_info *HwDeviceExtension, struct vb_device_info *pVBInfo);
+void XGI_SetCRT2VCLK(unsigned short ModeNo, unsigned short ModeIdIndex, unsigned short RefreshRateTableIndex, struct vb_device_info *pVBInfo);
+void XGI_OEM310Setting(unsigned short ModeNo, unsigned short ModeIdIndex, struct vb_device_info *pVBInfo);
+void XGI_SetDelayComp(struct vb_device_info *pVBInfo);
+void XGI_SetLCDCap(struct vb_device_info *pVBInfo);
+void XGI_SetLCDCap_A(unsigned short tempcx, struct vb_device_info *pVBInfo);
+void XGI_SetLCDCap_B(unsigned short tempcx, struct vb_device_info *pVBInfo);
+void SetSpectrum(struct vb_device_info *pVBInfo);
+void XGI_SetAntiFlicker(unsigned short ModeNo, unsigned short ModeIdIndex, struct vb_device_info *pVBInfo);
+void XGI_SetEdgeEnhance(unsigned short ModeNo, unsigned short ModeIdIndex, struct vb_device_info *pVBInfo);
+void XGI_SetPhaseIncr(struct vb_device_info *pVBInfo);
+void XGI_SetYFilter(unsigned short ModeNo, unsigned short ModeIdIndex, struct vb_device_info *pVBInfo);
+void XGI_GetTVPtrIndex2(unsigned short *tempbx, unsigned char* tempcl,
+ unsigned char *tempch, struct vb_device_info *pVBInfo);
+unsigned short XGI_GetTVPtrIndex(struct vb_device_info *pVBInfo);
+void XGI_SetCRT2ModeRegs(unsigned short ModeNo, struct xgi_hw_device_info *, struct vb_device_info *pVBInfo);
+void XGI_CloseCRTC(struct xgi_hw_device_info *, struct vb_device_info *pVBInfo);
+void XGI_OpenCRTC(struct xgi_hw_device_info *, struct vb_device_info *pVBInfo);
+void XGI_GetRAMDAC2DATA(unsigned short ModeNo, unsigned short ModeIdIndex, unsigned short RefreshRateTableIndex, struct vb_device_info *pVBInfo);
+void XGI_UnLockCRT2(struct xgi_hw_device_info *, struct vb_device_info *pVBInfo);
+void XGI_LockCRT2(struct xgi_hw_device_info *, struct vb_device_info *pVBInfo);
+void XGINew_EnableCRT2(struct vb_device_info *pVBInfo);
+void XGINew_LCD_Wait_Time(unsigned char DelayTime, struct vb_device_info *pVBInfo);
+void XGI_LongWait(struct vb_device_info *pVBInfo);
+void XGI_SetCRT1Offset(unsigned short ModeNo, unsigned short ModeIdIndex, unsigned short RefreshRateTableIndex, struct xgi_hw_device_info *HwDeviceExtension, struct vb_device_info *pVBInfo);
+void XGI_GetLCDVCLKPtr(unsigned char *di_0, unsigned char *di_1,
+ struct vb_device_info *pVBInfo);
+unsigned char XGI_GetVCLKPtr(unsigned short RefreshRateTableIndex,
+ unsigned short ModeNo,
+ unsigned short ModeIdIndex,
+ struct vb_device_info *pVBInfo);
+void XGI_GetVCLKLen(unsigned char tempal, unsigned char *di_0,
+ unsigned char *di_1, struct vb_device_info *pVBInfo);
+unsigned short XGI_GetLCDCapPtr(struct vb_device_info *pVBInfo);
+unsigned short XGI_GetLCDCapPtr1(struct vb_device_info *pVBInfo);
+struct XGI301C_Tap4TimingStruct *XGI_GetTap4Ptr(unsigned short tempcx, struct vb_device_info *pVBInfo);
+void XGI_SetXG21FPBits(struct vb_device_info *pVBInfo);
+void XGI_SetXG27FPBits(struct vb_device_info *pVBInfo);
+unsigned char XGI_XG21GetPSCValue(struct vb_device_info *pVBInfo);
+unsigned char XGI_XG27GetPSCValue(struct vb_device_info *pVBInfo);
+void XGI_XG21BLSignalVDD(unsigned short tempbh, unsigned short tempbl, struct vb_device_info *pVBInfo);
+void XGI_XG27BLSignalVDD(unsigned short tempbh, unsigned short tempbl, struct vb_device_info *pVBInfo);
+void XGI_XG21SetPanelDelay(unsigned short tempbl, struct vb_device_info *pVBInfo);
+unsigned char XGI_XG21CheckLVDSMode(unsigned short ModeNo, unsigned short ModeIdIndex, struct vb_device_info *pVBInfo);
+void XGI_SetXG21LVDSPara(unsigned short ModeNo, unsigned short ModeIdIndex, struct vb_device_info *pVBInfo);
+void XGI_SetXG27LVDSPara(unsigned short ModeNo, unsigned short ModeIdIndex, struct vb_device_info *pVBInfo);
+unsigned char XGI_SetDefaultVCLK(struct vb_device_info *pVBInfo);
+
+extern void ReadVBIOSTablData(unsigned char ChipType, struct vb_device_info *pVBInfo);
+
+/* unsigned short XGINew_flag_clearbuffer; 0: no clear frame buffer 1:clear frame buffer */
+
+
+unsigned short XGINew_MDA_DAC[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15,
+ 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15,
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15,
+ 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15,
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F};
+
+unsigned short XGINew_CGA_DAC[] = {
+ 0x00, 0x10, 0x04, 0x14, 0x01, 0x11, 0x09, 0x15,
+ 0x00, 0x10, 0x04, 0x14, 0x01, 0x11, 0x09, 0x15,
+ 0x2A, 0x3A, 0x2E, 0x3E, 0x2B, 0x3B, 0x2F, 0x3F,
+ 0x2A, 0x3A, 0x2E, 0x3E, 0x2B, 0x3B, 0x2F, 0x3F,
+ 0x00, 0x10, 0x04, 0x14, 0x01, 0x11, 0x09, 0x15,
+ 0x00, 0x10, 0x04, 0x14, 0x01, 0x11, 0x09, 0x15,
+ 0x2A, 0x3A, 0x2E, 0x3E, 0x2B, 0x3B, 0x2F, 0x3F,
+ 0x2A, 0x3A, 0x2E, 0x3E, 0x2B, 0x3B, 0x2F, 0x3F};
+
+unsigned short XGINew_EGA_DAC[] = {
+ 0x00, 0x10, 0x04, 0x14, 0x01, 0x11, 0x05, 0x15,
+ 0x20, 0x30, 0x24, 0x34, 0x21, 0x31, 0x25, 0x35,
+ 0x08, 0x18, 0x0C, 0x1C, 0x09, 0x19, 0x0D, 0x1D,
+ 0x28, 0x38, 0x2C, 0x3C, 0x29, 0x39, 0x2D, 0x3D,
+ 0x02, 0x12, 0x06, 0x16, 0x03, 0x13, 0x07, 0x17,
+ 0x22, 0x32, 0x26, 0x36, 0x23, 0x33, 0x27, 0x37,
+ 0x0A, 0x1A, 0x0E, 0x1E, 0x0B, 0x1B, 0x0F, 0x1F,
+ 0x2A, 0x3A, 0x2E, 0x3E, 0x2B, 0x3B, 0x2F, 0x3F};
+
+unsigned short XGINew_VGA_DAC[] = {
+ 0x00, 0x10, 0x04, 0x14, 0x01, 0x11, 0x09, 0x15,
+ 0x2A, 0x3A, 0x2E, 0x3E, 0x2B, 0x3B, 0x2F, 0x3F,
+ 0x00, 0x05, 0x08, 0x0B, 0x0E, 0x11, 0x14, 0x18,
+ 0x1C, 0x20, 0x24, 0x28, 0x2D, 0x32, 0x38, 0x3F,
+ 0x00, 0x10, 0x1F, 0x2F, 0x3F, 0x1F, 0x27, 0x2F,
+ 0x37, 0x3F, 0x2D, 0x31, 0x36, 0x3A, 0x3F, 0x00,
+ 0x07, 0x0E, 0x15, 0x1C, 0x0E, 0x11, 0x15, 0x18,
+ 0x1C, 0x14, 0x16, 0x18, 0x1A, 0x1C, 0x00, 0x04,
+ 0x08, 0x0C, 0x10, 0x08, 0x0A, 0x0C, 0x0E, 0x10,
+ 0x0B, 0x0C, 0x0D, 0x0F, 0x10};
/* --------------------------------------------------------------------- */
@@ -250,35 +240,35 @@ USHORT XGINew_VGA_DAC[]={0x00,0x10,0x04,0x14,0x01,0x11,0x09,0x15,
/* Output : */
/* Description : */
/* --------------------------------------------------------------------- */
-void InitTo330Pointer( UCHAR ChipType ,PVB_DEVICE_INFO pVBInfo)
+void InitTo330Pointer(unsigned char ChipType, struct vb_device_info *pVBInfo)
{
- pVBInfo->SModeIDTable = (XGI_StStruct *) XGI330_SModeIDTable ;
- pVBInfo->StandTable = (XGI_StandTableStruct *) XGI330_StandTable ;
- pVBInfo->EModeIDTable = (XGI_ExtStruct *) XGI330_EModeIDTable ;
- pVBInfo->RefIndex = (XGI_Ext2Struct *) XGI330_RefIndex ;
- pVBInfo->XGINEWUB_CRT1Table = (XGI_CRT1TableStruct *) XGI_CRT1Table ;
+ pVBInfo->SModeIDTable = (struct XGI_StStruct *) XGI330_SModeIDTable ;
+ pVBInfo->StandTable = (struct XGI_StandTableStruct *) XGI330_StandTable ;
+ pVBInfo->EModeIDTable = (struct XGI_ExtStruct *) XGI330_EModeIDTable ;
+ pVBInfo->RefIndex = (struct XGI_Ext2Struct *) XGI330_RefIndex ;
+ pVBInfo->XGINEWUB_CRT1Table = (struct XGI_CRT1TableStruct *) XGI_CRT1Table ;
/* add for new UNIVGABIOS */
- /* XGINew_UBLCDDataTable = (XGI_LCDDataTablStruct *) XGI_LCDDataTable ; */
+ /* XGINew_UBLCDDataTable = (struct XGI_LCDDataTablStruct *) XGI_LCDDataTable ; */
/* XGINew_UBTVDataTable = (XGI_TVDataTablStruct *) XGI_TVDataTable ; */
if ( ChipType >= XG40 )
{
- pVBInfo->MCLKData = (XGI_MCLKDataStruct *) XGI340New_MCLKData ;
- pVBInfo->ECLKData = (XGI_ECLKDataStruct *) XGI340_ECLKData ;
+ pVBInfo->MCLKData = (struct XGI_MCLKDataStruct *) XGI340New_MCLKData;
+ pVBInfo->ECLKData = (struct XGI_ECLKDataStruct *) XGI340_ECLKData;
}
else
{
- pVBInfo->MCLKData = (XGI_MCLKDataStruct *) XGI330New_MCLKData ;
- pVBInfo->ECLKData = (XGI_ECLKDataStruct *) XGI330_ECLKData ;
+ pVBInfo->MCLKData = (struct XGI_MCLKDataStruct *) XGI330New_MCLKData;
+ pVBInfo->ECLKData = (struct XGI_ECLKDataStruct *) XGI330_ECLKData;
}
- pVBInfo->VCLKData = (XGI_VCLKDataStruct *) XGI_VCLKData ;
- pVBInfo->VBVCLKData = (XGI_VBVCLKDataStruct *) XGI_VBVCLKData ;
+ pVBInfo->VCLKData = (struct XGI_VCLKDataStruct *) XGI_VCLKData ;
+ pVBInfo->VBVCLKData = (struct XGI_VBVCLKDataStruct *) XGI_VBVCLKData ;
pVBInfo->ScreenOffset = XGI330_ScreenOffset ;
- pVBInfo->StResInfo = (XGI_StResInfoStruct *) XGI330_StResInfo ;
- pVBInfo->ModeResInfo = (XGI_ModeResInfoStruct *) XGI330_ModeResInfo ;
+ pVBInfo->StResInfo = (struct XGI_StResInfoStruct *) XGI330_StResInfo ;
+ pVBInfo->ModeResInfo = (struct XGI_ModeResInfoStruct *) XGI330_ModeResInfo ;
pVBInfo->pOutputSelect = &XGI330_OutputSelect ;
pVBInfo->pSoftSetting = &XGI330_SoftSetting ;
@@ -342,9 +332,9 @@ void InitTo330Pointer( UCHAR ChipType ,PVB_DEVICE_INFO pVBInfo)
pVBInfo->Ren750pGroup3 = XGI330_Ren750pGroup3 ;
- pVBInfo->TimingH = (XGI_TimingHStruct *) XGI_TimingH ;
- pVBInfo->TimingV = (XGI_TimingVStruct *) XGI_TimingV ;
- pVBInfo->UpdateCRT1 = (XGI_XG21CRT1Struct *) XGI_UpdateCRT1Table ;
+ pVBInfo->TimingH = (struct XGI_TimingHStruct *) XGI_TimingH ;
+ pVBInfo->TimingV = (struct XGI_TimingVStruct *) XGI_TimingV ;
+ pVBInfo->UpdateCRT1 = (struct XGI_XG21CRT1Struct *) XGI_UpdateCRT1Table ;
pVBInfo->CHTVVCLKUNTSC = XGI330_CHTVVCLKUNTSC ;
pVBInfo->CHTVVCLKONTSC = XGI330_CHTVVCLKONTSC ;
@@ -371,7 +361,7 @@ void InitTo330Pointer( UCHAR ChipType ,PVB_DEVICE_INFO pVBInfo)
if ( ChipType == XG27 )
{
- pVBInfo->MCLKData = (XGI_MCLKDataStruct *) XGI27New_MCLKData ;
+ pVBInfo->MCLKData = (struct XGI_MCLKDataStruct *) XGI27New_MCLKData;
pVBInfo->CR40 = XGI27_cr41 ;
pVBInfo->pXGINew_CR97 = &XG27_CR97 ;
pVBInfo->pSR36 = &XG27_SR36 ;
@@ -405,14 +395,15 @@ void InitTo330Pointer( UCHAR ChipType ,PVB_DEVICE_INFO pVBInfo)
/* Output : */
/* Description : */
/* --------------------------------------------------------------------- */
-BOOLEAN XGISetModeNew( PXGI_HW_DEVICE_INFO HwDeviceExtension , USHORT ModeNo )
+unsigned char XGISetModeNew(struct xgi_hw_device_info *HwDeviceExtension,
+ unsigned short ModeNo)
{
- USHORT ModeIdIndex ;
- /* PUCHAR pVBInfo->FBAddr = HwDeviceExtension->pjVideoMemoryAddress ; */
- VB_DEVICE_INFO VBINF;
- PVB_DEVICE_INFO pVBInfo = &VBINF;
+ unsigned short ModeIdIndex ;
+ /* unsigned char *pVBInfo->FBAddr = HwDeviceExtension->pjVideoMemoryAddress ; */
+ struct vb_device_info VBINF;
+ struct vb_device_info *pVBInfo = &VBINF;
pVBInfo->ROMAddr = HwDeviceExtension->pjVirtualRomBase ;
- pVBInfo->BaseAddr = (ULONG)HwDeviceExtension->pjIOAddress ;
+ pVBInfo->BaseAddr = (unsigned long)HwDeviceExtension->pjIOAddress ;
pVBInfo->IF_DEF_LVDS = 0 ;
pVBInfo->IF_DEF_CH7005 = 0 ;
pVBInfo->IF_DEF_LCDA = 1 ;
@@ -485,9 +476,6 @@ BOOLEAN XGISetModeNew( PXGI_HW_DEVICE_INFO HwDeviceExtension , USHORT ModeNo )
XGI_GetVBType( pVBInfo ) ;
InitTo330Pointer( HwDeviceExtension->jChipType, pVBInfo ) ;
-#ifdef WIN2000
- ReadVBIOSTablData( HwDeviceExtension->jChipType , pVBInfo) ;
-#endif
if ( ModeNo & 0x80 )
{
ModeNo = ModeNo & 0x7F ;
@@ -560,30 +548,9 @@ BOOLEAN XGISetModeNew( PXGI_HW_DEVICE_INFO HwDeviceExtension , USHORT ModeNo )
} /* !XG20 */
else
{
-#ifdef WIN2000
- if ( pVBInfo->IF_DEF_CH7007 == 1 )
- {
-
- VideoDebugPrint((0, "XGISetModeNew: pVBIfo->IF_DEF_CH7007==1\n"));
- pVBInfo->VBType = VB_CH7007 ;
- XGI_GetVBInfo(ModeNo , ModeIdIndex , HwDeviceExtension, pVBInfo ) ;
- XGI_GetTVInfo(ModeNo , ModeIdIndex, pVBInfo ) ;
- XGI_GetLCDInfo(ModeNo , ModeIdIndex, pVBInfo ) ;
- if( !(XGI_XG21CheckCH7007TVMode(ModeNo, ModeIdIndex, pVBInfo )) )
- {
- return FALSE;
- }
- }
-#endif
-
-
- if ( pVBInfo->IF_DEF_LVDS == 1 )
- {
- if ( !XGI_XG21CheckLVDSMode(ModeNo , ModeIdIndex, pVBInfo) )
- {
- return FALSE;
- }
- }
+ if (pVBInfo->IF_DEF_LVDS == 1)
+ if (!XGI_XG21CheckLVDSMode(ModeNo , ModeIdIndex, pVBInfo))
+ return 0;
if ( ModeNo <= 0x13 )
{
@@ -642,7 +609,7 @@ BOOLEAN XGISetModeNew( PXGI_HW_DEVICE_INFO HwDeviceExtension , USHORT ModeNo )
XGI_LockCRT2( HwDeviceExtension, pVBInfo ) ;
}
- return( TRUE ) ;
+ return 1;
}
@@ -652,14 +619,16 @@ BOOLEAN XGISetModeNew( PXGI_HW_DEVICE_INFO HwDeviceExtension , USHORT ModeNo )
/* Output : */
/* Description : */
/* --------------------------------------------------------------------- */
-void XGI_SetCRT1Group( PXGI_HW_DEVICE_INFO HwDeviceExtension , USHORT ModeNo , USHORT ModeIdIndex, PVB_DEVICE_INFO pVBInfo )
+void XGI_SetCRT1Group(struct xgi_hw_device_info *HwDeviceExtension,
+ unsigned short ModeNo,
+ unsigned short ModeIdIndex, struct vb_device_info *pVBInfo)
{
- USHORT StandTableIndex ,
+ unsigned short StandTableIndex ,
RefreshRateTableIndex ,
b3CC ,
temp ;
- USHORT XGINew_P3cc = pVBInfo->P3cc;
+ unsigned short XGINew_P3cc = pVBInfo->P3cc;
/* XGINew_CRT1Mode = ModeNo ; // SaveModeID */
StandTableIndex = XGI_GetModePtr( ModeNo , ModeIdIndex, pVBInfo ) ;
@@ -710,14 +679,14 @@ void XGI_SetCRT1Group( PXGI_HW_DEVICE_INFO HwDeviceExtension , USHORT ModeNo , U
{
XGINew_SetReg1( pVBInfo->P3c4 , 0x2B , 0x4E) ;
XGINew_SetReg1( pVBInfo->P3c4 , 0x2C , 0xE9) ;
- b3CC =(UCHAR) XGINew_GetReg2(XGINew_P3cc) ;
+ b3CC = (unsigned char) XGINew_GetReg2(XGINew_P3cc) ;
XGINew_SetReg3(XGINew_P3cc , (b3CC |= 0x0C) ) ;
}
else if ( ( ModeNo == 0x04) | ( ModeNo == 0x05) | ( ModeNo == 0x0D) )
{
XGINew_SetReg1( pVBInfo->P3c4 , 0x2B , 0x1B) ;
XGINew_SetReg1( pVBInfo->P3c4 , 0x2C , 0xE3) ;
- b3CC = (UCHAR)XGINew_GetReg2(XGINew_P3cc) ;
+ b3CC = (unsigned char)XGINew_GetReg2(XGINew_P3cc) ;
XGINew_SetReg3(XGINew_P3cc , (b3CC |= 0x0C) ) ;
}
}
@@ -763,13 +732,6 @@ void XGI_SetCRT1Group( PXGI_HW_DEVICE_INFO HwDeviceExtension , USHORT ModeNo , U
XGI_LoadDAC( ModeNo , ModeIdIndex, pVBInfo ) ;
/* XGI_ClearBuffer( HwDeviceExtension , ModeNo, pVBInfo ) ; */
-#ifdef WIN2000
- if ( pVBInfo->IF_DEF_CH7007 == 1 ) /* [Billy] 2007/05/14 */
- {
- VideoDebugPrint((0, "XGI_SetCRT1Group: VBInfo->IF_DEF_CH7007==1\n"));
- SetCH7007Regs(HwDeviceExtension, ModeNo, ModeIdIndex, RefreshRateTableIndex, pVBInfo ) ; /* 07/05/28 */
- }
-#endif
}
@@ -779,9 +741,10 @@ void XGI_SetCRT1Group( PXGI_HW_DEVICE_INFO HwDeviceExtension , USHORT ModeNo , U
/* Output : */
/* Description : */
/* --------------------------------------------------------------------- */
-UCHAR XGI_GetModePtr( USHORT ModeNo , USHORT ModeIdIndex, PVB_DEVICE_INFO pVBInfo )
+unsigned char XGI_GetModePtr(unsigned short ModeNo, unsigned short ModeIdIndex,
+ struct vb_device_info *pVBInfo)
{
- UCHAR index ;
+ unsigned char index ;
if ( ModeNo <= 0x13 )
index = pVBInfo->SModeIDTable[ ModeIdIndex ].St_StTableIndex ;
@@ -802,7 +765,7 @@ UCHAR XGI_GetModePtr( USHORT ModeNo , USHORT ModeIdIndex, PVB_DEVICE_INFO pVBInf
/* Output : */
/* Description : */
/* --------------------------------------------------------------------- */
-/*UCHAR XGI_SetBIOSData( USHORT ModeNo , USHORT ModeIdIndex )
+/*unsigned char XGI_SetBIOSData(unsigned short ModeNo, unsigned short ModeIdIndex)
{
return( 0 ) ;
}
@@ -814,7 +777,7 @@ UCHAR XGI_GetModePtr( USHORT ModeNo , USHORT ModeIdIndex, PVB_DEVICE_INFO pVBInf
/* Output : */
/* Description : */
/* --------------------------------------------------------------------- */
-/*UCHAR XGI_ClearBankRegs( USHORT ModeNo , USHORT ModeIdIndex )
+/*unsigned char XGI_ClearBankRegs(unsigned short ModeNo, unsigned short ModeIdIndex)
{
return( 0 ) ;
}
@@ -826,12 +789,13 @@ UCHAR XGI_GetModePtr( USHORT ModeNo , USHORT ModeIdIndex, PVB_DEVICE_INFO pVBInf
/* Output : */
/* Description : */
/* --------------------------------------------------------------------- */
-void XGI_SetSeqRegs( USHORT ModeNo , USHORT StandTableIndex , USHORT ModeIdIndex, PVB_DEVICE_INFO pVBInfo )
+void XGI_SetSeqRegs(unsigned short ModeNo, unsigned short StandTableIndex,
+ unsigned short ModeIdIndex, struct vb_device_info *pVBInfo)
{
- UCHAR tempah ,
+ unsigned char tempah ,
SRdata ;
- USHORT i ,
+ unsigned short i ,
modeflag ;
if ( ModeNo <= 0x13 )
@@ -873,9 +837,9 @@ void XGI_SetSeqRegs( USHORT ModeNo , USHORT StandTableIndex , USHORT ModeIdInde
/* Output : */
/* Description : */
/* --------------------------------------------------------------------- */
-void XGI_SetMiscRegs( USHORT StandTableIndex, PVB_DEVICE_INFO pVBInfo )
+void XGI_SetMiscRegs(unsigned short StandTableIndex, struct vb_device_info *pVBInfo)
{
- UCHAR Miscdata ;
+ unsigned char Miscdata ;
Miscdata = pVBInfo->StandTable[ StandTableIndex ].MISC ; /* Get Misc from file */
/*
@@ -898,12 +862,13 @@ void XGI_SetMiscRegs( USHORT StandTableIndex, PVB_DEVICE_INFO pVBInfo )
/* Output : */
/* Description : */
/* --------------------------------------------------------------------- */
-void XGI_SetCRTCRegs( PXGI_HW_DEVICE_INFO HwDeviceExtension , USHORT StandTableIndex, PVB_DEVICE_INFO pVBInfo )
+void XGI_SetCRTCRegs(struct xgi_hw_device_info *HwDeviceExtension,
+ unsigned short StandTableIndex, struct vb_device_info *pVBInfo)
{
- UCHAR CRTCdata ;
- USHORT i ;
+ unsigned char CRTCdata ;
+ unsigned short i ;
- CRTCdata = ( UCHAR )XGINew_GetReg1( pVBInfo->P3d4 , 0x11 ) ;
+ CRTCdata = (unsigned char)XGINew_GetReg1(pVBInfo->P3d4, 0x11);
CRTCdata &= 0x7f ;
XGINew_SetReg1( pVBInfo->P3d4 , 0x11 , CRTCdata ) ; /* Unlock CRTC */
@@ -933,11 +898,11 @@ void XGI_SetCRTCRegs( PXGI_HW_DEVICE_INFO HwDeviceExtension , USHORT StandTableI
/* Output : */
/* Description : */
/* --------------------------------------------------------------------- */
-void XGI_SetATTRegs( USHORT ModeNo , USHORT StandTableIndex , USHORT ModeIdIndex, PVB_DEVICE_INFO pVBInfo )
+void XGI_SetATTRegs(unsigned short ModeNo, unsigned short StandTableIndex,
+ unsigned short ModeIdIndex, struct vb_device_info *pVBInfo)
{
- UCHAR ARdata ;
- USHORT i ,
- modeflag ;
+ unsigned char ARdata ;
+ unsigned short i, modeflag;
if ( ModeNo <= 0x13 )
modeflag = pVBInfo->SModeIDTable[ ModeIdIndex ].St_ModeFlag ;
@@ -983,10 +948,10 @@ void XGI_SetATTRegs( USHORT ModeNo , USHORT StandTableIndex , USHORT ModeIdIndex
/* Output : */
/* Description : */
/* --------------------------------------------------------------------- */
-void XGI_SetGRCRegs( USHORT StandTableIndex, PVB_DEVICE_INFO pVBInfo )
+void XGI_SetGRCRegs(unsigned short StandTableIndex, struct vb_device_info *pVBInfo)
{
- UCHAR GRdata ;
- USHORT i ;
+ unsigned char GRdata ;
+ unsigned short i ;
for( i = 0 ; i <= 0x08 ; i++ )
{
@@ -996,7 +961,7 @@ void XGI_SetGRCRegs( USHORT StandTableIndex, PVB_DEVICE_INFO pVBInfo )
if ( pVBInfo->ModeType > ModeVGA )
{
- GRdata = ( UCHAR )XGINew_GetReg1( pVBInfo->P3ce , 0x05 ) ;
+ GRdata = (unsigned char)XGINew_GetReg1(pVBInfo->P3ce, 0x05);
GRdata &= 0xBF ; /* 256 color disable */
XGINew_SetReg1( pVBInfo->P3ce , 0x05 , GRdata ) ;
}
@@ -1009,9 +974,9 @@ void XGI_SetGRCRegs( USHORT StandTableIndex, PVB_DEVICE_INFO pVBInfo )
/* Output : */
/* Description : */
/* --------------------------------------------------------------------- */
-void XGI_ClearExt1Regs(PVB_DEVICE_INFO pVBInfo)
+void XGI_ClearExt1Regs(struct vb_device_info *pVBInfo)
{
- USHORT i ;
+ unsigned short i ;
for( i = 0x0A ; i <= 0x0E ; i++ )
XGINew_SetReg1( pVBInfo->P3c4 , i , 0x00 ) ; /* Clear SR0A-SR0E */
@@ -1024,7 +989,7 @@ void XGI_ClearExt1Regs(PVB_DEVICE_INFO pVBInfo)
/* Output : */
/* Description : */
/* --------------------------------------------------------------------- */
-UCHAR XGI_SetDefaultVCLK( PVB_DEVICE_INFO pVBInfo )
+unsigned char XGI_SetDefaultVCLK(struct vb_device_info *pVBInfo)
{
XGINew_SetRegANDOR( pVBInfo->P3c4 , 0x31 , ~0x30 , 0x20 ) ;
@@ -1046,13 +1011,15 @@ UCHAR XGI_SetDefaultVCLK( PVB_DEVICE_INFO pVBInfo )
/* Output : */
/* Description : */
/* --------------------------------------------------------------------- */
-USHORT XGI_GetRatePtrCRT2( PXGI_HW_DEVICE_INFO pXGIHWDE, USHORT ModeNo , USHORT ModeIdIndex, PVB_DEVICE_INFO pVBInfo )
+unsigned short XGI_GetRatePtrCRT2(struct xgi_hw_device_info *pXGIHWDE,
+ unsigned short ModeNo,
+ unsigned short ModeIdIndex,
+ struct vb_device_info *pVBInfo)
{
- SHORT LCDRefreshIndex[] = { 0x00 , 0x00 , 0x03 , 0x01 } ,
+ short LCDRefreshIndex[] = { 0x00 , 0x00 , 0x03 , 0x01 } ,
LCDARefreshIndex[] = { 0x00 , 0x00 , 0x03 , 0x01 , 0x01 , 0x01 , 0x01 } ;
- USHORT RefreshRateTableIndex , i ,
- modeflag , index , temp ;
+ unsigned short RefreshRateTableIndex, i, modeflag, index, temp;
if ( ModeNo <= 0x13 )
{
@@ -1183,13 +1150,11 @@ USHORT XGI_GetRatePtrCRT2( PXGI_HW_DEVICE_INFO pXGIHWDE, USHORT ModeNo , USHORT
/* Output : */
/* Description : */
/* --------------------------------------------------------------------- */
-BOOLEAN XGI_AjustCRT2Rate( USHORT ModeNo , USHORT ModeIdIndex , USHORT RefreshRateTableIndex , USHORT *i, PVB_DEVICE_INFO pVBInfo )
+unsigned char XGI_AjustCRT2Rate(unsigned short ModeNo, unsigned short ModeIdIndex,
+ unsigned short RefreshRateTableIndex,
+ unsigned short *i, struct vb_device_info *pVBInfo)
{
- USHORT tempax ,
- tempbx ,
- resinfo ,
- modeflag ,
- infoflag ;
+ unsigned short tempax, tempbx, resinfo, modeflag, infoflag;
if ( ModeNo <= 0x13 )
{
@@ -1359,9 +1324,9 @@ BOOLEAN XGI_AjustCRT2Rate( USHORT ModeNo , USHORT ModeIdIndex , USHORT RefreshRa
/* Output : */
/* Description : */
/* --------------------------------------------------------------------- */
-void XGI_SetSync(USHORT RefreshRateTableIndex, PVB_DEVICE_INFO pVBInfo )
+void XGI_SetSync(unsigned short RefreshRateTableIndex, struct vb_device_info *pVBInfo)
{
- USHORT sync ,
+ unsigned short sync ,
temp ;
sync = pVBInfo->RefIndex[ RefreshRateTableIndex ].Ext_InfoFlag >> 8 ; /* di+0x00 */
@@ -1378,17 +1343,18 @@ void XGI_SetSync(USHORT RefreshRateTableIndex, PVB_DEVICE_INFO pVBInfo )
/* Output : */
/* Description : */
/* --------------------------------------------------------------------- */
-void XGI_SetCRT1CRTC( USHORT ModeNo , USHORT ModeIdIndex , USHORT RefreshRateTableIndex,PVB_DEVICE_INFO pVBInfo, PXGI_HW_DEVICE_INFO HwDeviceExtension )
+void XGI_SetCRT1CRTC(unsigned short ModeNo, unsigned short ModeIdIndex,
+ unsigned short RefreshRateTableIndex,
+ struct vb_device_info *pVBInfo,
+ struct xgi_hw_device_info *HwDeviceExtension)
{
- UCHAR index ,
- data ;
-
- USHORT i ;
+ unsigned char index, data;
+ unsigned short i;
index = pVBInfo->RefIndex[ RefreshRateTableIndex ].Ext_CRT1CRTC ; /* Get index */
index = index&IndexMask ;
- data =( UCHAR )XGINew_GetReg1( pVBInfo->P3d4 , 0x11 ) ;
+ data = (unsigned char)XGINew_GetReg1(pVBInfo->P3d4, 0x11);
data &= 0x7F ;
XGINew_SetReg1(pVBInfo->P3d4,0x11,data); /* Unlock CRTC */
@@ -1416,16 +1382,16 @@ void XGI_SetCRT1CRTC( USHORT ModeNo , USHORT ModeIdIndex , USHORT RefreshRateTab
/* Output : */
/* Description : */
/* --------------------------------------------------------------------- */
-void XGI_SetCRT1Timing_H( PVB_DEVICE_INFO pVBInfo, PXGI_HW_DEVICE_INFO HwDeviceExtension )
+void XGI_SetCRT1Timing_H(struct vb_device_info *pVBInfo, struct xgi_hw_device_info *HwDeviceExtension)
{
- UCHAR data , data1, pushax;
- USHORT i , j ;
+ unsigned char data, data1, pushax;
+ unsigned short i, j;
/* XGINew_SetReg1( pVBInfo->P3d4 , 0x51 , 0 ) ; */
/* XGINew_SetReg1( pVBInfo->P3d4 , 0x56 , 0 ) ; */
/* XGINew_SetRegANDOR( pVBInfo->P3d4 ,0x11 , 0x7f , 0x00 ) ; */
- data = ( UCHAR )XGINew_GetReg1( pVBInfo->P3d4 , 0x11 ) ; /* unlock cr0-7 */
+ data = (unsigned char)XGINew_GetReg1(pVBInfo->P3d4, 0x11); /* unlock cr0-7 */
data &= 0x7F ;
XGINew_SetReg1( pVBInfo->P3d4 , 0x11 , data ) ;
@@ -1435,16 +1401,16 @@ void XGI_SetCRT1Timing_H( PVB_DEVICE_INFO pVBInfo, PXGI_HW_DEVICE_INFO HwDeviceE
for( i = 0x01 ; i <= 0x04 ; i++ )
{
data = pVBInfo->TimingH[ 0 ].data[ i ] ;
- XGINew_SetReg1( pVBInfo->P3d4 , ( USHORT )( i + 1 ) , data ) ;
+ XGINew_SetReg1( pVBInfo->P3d4, (unsigned short)(i + 1), data);
}
for( i = 0x05 ; i <= 0x06 ; i++ )
{
data = pVBInfo->TimingH[ 0 ].data[ i ];
- XGINew_SetReg1( pVBInfo->P3c4 ,( USHORT )( i + 6 ) , data ) ;
+ XGINew_SetReg1(pVBInfo->P3c4, (unsigned short)(i + 6), data);
}
- j = ( UCHAR )XGINew_GetReg1( pVBInfo->P3c4 , 0x0e ) ;
+ j = (unsigned char)XGINew_GetReg1(pVBInfo->P3c4, 0x0e);
j &= 0x1F ;
data = pVBInfo->TimingH[ 0 ].data[ 7 ] ;
data &= 0xE0 ;
@@ -1453,17 +1419,17 @@ void XGI_SetCRT1Timing_H( PVB_DEVICE_INFO pVBInfo, PXGI_HW_DEVICE_INFO HwDeviceE
if ( HwDeviceExtension->jChipType >= XG20 )
{
- data = ( UCHAR )XGINew_GetReg1( pVBInfo->P3d4 , 0x04 ) ;
+ data = (unsigned char)XGINew_GetReg1(pVBInfo->P3d4, 0x04);
data = data - 1 ;
XGINew_SetReg1( pVBInfo->P3d4 , 0x04 , data ) ;
- data = ( UCHAR )XGINew_GetReg1( pVBInfo->P3d4 , 0x05 ) ;
+ data = (unsigned char)XGINew_GetReg1(pVBInfo->P3d4, 0x05);
data1 = data ;
data1 &= 0xE0 ;
data &= 0x1F ;
if ( data == 0 )
{
pushax = data ;
- data = ( UCHAR )XGINew_GetReg1( pVBInfo->P3c4 , 0x0c ) ;
+ data = (unsigned char)XGINew_GetReg1(pVBInfo->P3c4, 0x0c);
data &= 0xFB ;
XGINew_SetReg1( pVBInfo->P3c4 , 0x0c , data ) ;
data = pushax ;
@@ -1471,7 +1437,7 @@ void XGI_SetCRT1Timing_H( PVB_DEVICE_INFO pVBInfo, PXGI_HW_DEVICE_INFO HwDeviceE
data = data - 1 ;
data |= data1 ;
XGINew_SetReg1( pVBInfo->P3d4 , 0x05 , data ) ;
- data = ( UCHAR )XGINew_GetReg1( pVBInfo->P3c4 , 0x0e ) ;
+ data = (unsigned char)XGINew_GetReg1(pVBInfo->P3c4, 0x0e);
data = data >> 5 ;
data = data + 3 ;
if ( data > 7 )
@@ -1488,10 +1454,12 @@ void XGI_SetCRT1Timing_H( PVB_DEVICE_INFO pVBInfo, PXGI_HW_DEVICE_INFO HwDeviceE
/* Output : */
/* Description : */
/* --------------------------------------------------------------------- */
-void XGI_SetCRT1Timing_V( USHORT ModeIdIndex , USHORT ModeNo,PVB_DEVICE_INFO pVBInfo )
+void XGI_SetCRT1Timing_V(unsigned short ModeIdIndex,
+ unsigned short ModeNo,
+ struct vb_device_info *pVBInfo)
{
- UCHAR data ;
- USHORT i , j ;
+ unsigned char data;
+ unsigned short i, j;
/* XGINew_SetReg1( pVBInfo->P3d4 , 0x51 , 0 ) ; */
/* XGINew_SetReg1( pVBInfo->P3d4 , 0x56 , 0 ) ; */
@@ -1500,22 +1468,22 @@ void XGI_SetCRT1Timing_V( USHORT ModeIdIndex , USHORT ModeNo,PVB_DEVICE_INFO pVB
for( i = 0x00 ; i <= 0x01 ; i++ )
{
data = pVBInfo->TimingV[ 0 ].data[ i ] ;
- XGINew_SetReg1( pVBInfo->P3d4 , ( USHORT )( i + 6 ) , data ) ;
+ XGINew_SetReg1(pVBInfo->P3d4, (unsigned short)(i + 6), data);
}
for( i = 0x02 ; i <= 0x03 ; i++ )
{
data = pVBInfo->TimingV[ 0 ].data[ i ] ;
- XGINew_SetReg1( pVBInfo->P3d4 , ( USHORT )( i + 0x0e ) , data ) ;
+ XGINew_SetReg1(pVBInfo->P3d4, (unsigned short)(i + 0x0e), data);
}
for( i = 0x04 ; i <= 0x05 ; i++ )
{
data = pVBInfo->TimingV[ 0 ].data[ i ] ;
- XGINew_SetReg1( pVBInfo->P3d4 , ( USHORT )( i + 0x11 ) , data ) ;
+ XGINew_SetReg1(pVBInfo->P3d4, (unsigned short)(i + 0x11), data);
}
- j = ( UCHAR )XGINew_GetReg1( pVBInfo->P3c4 , 0x0a ) ;
+ j = (unsigned char)XGINew_GetReg1(pVBInfo->P3c4, 0x0a);
j &= 0xC0 ;
data = pVBInfo->TimingV[ 0 ].data[ 6 ] ;
data &= 0x3F ;
@@ -1535,7 +1503,7 @@ void XGI_SetCRT1Timing_V( USHORT ModeIdIndex , USHORT ModeNo,PVB_DEVICE_INFO pVB
if ( i )
data |= 0x80 ;
- j = ( UCHAR )XGINew_GetReg1( pVBInfo->P3d4 , 0x09 ) ;
+ j = (unsigned char)XGINew_GetReg1(pVBInfo->P3d4, 0x09);
j &= 0x5F ;
data |= j ;
XGINew_SetReg1( pVBInfo->P3d4 , 0x09 , data ) ;
@@ -1548,10 +1516,12 @@ void XGI_SetCRT1Timing_V( USHORT ModeIdIndex , USHORT ModeNo,PVB_DEVICE_INFO pVB
/* Output : Fill CRT Hsync/Vsync to SR2E/SR2F/SR30/SR33/SR34/SR3F */
/* Description : Set LCD timing */
/* --------------------------------------------------------------------- */
-void XGI_SetXG21CRTC(USHORT ModeNo, USHORT ModeIdIndex, USHORT RefreshRateTableIndex, PVB_DEVICE_INFO pVBInfo)
+void XGI_SetXG21CRTC(unsigned short ModeNo, unsigned short ModeIdIndex,
+ unsigned short RefreshRateTableIndex,
+ struct vb_device_info *pVBInfo)
{
- UCHAR StandTableIndex, index, Tempax, Tempbx, Tempcx, Tempdx ;
- USHORT Temp1, Temp2, Temp3 ;
+ unsigned char StandTableIndex, index, Tempax, Tempbx, Tempcx, Tempdx;
+ unsigned short Temp1, Temp2, Temp3;
if ( ModeNo <= 0x13 )
{
@@ -1580,7 +1550,7 @@ void XGI_SetXG21CRTC(USHORT ModeNo, USHORT ModeIdIndex, USHORT RefreshRateTableI
Tempdx |= Tempcx ; /* Tempdx: VRS[8:1] */
XGINew_SetReg1( pVBInfo->P3c4 , 0x34 , Tempdx ) ; /* SR34[7:0]: VRS[8:1] */
- Temp1 = Tempcx << 1 ; /* Temp1[8]: VRS[8] UCHAR -> USHORT */
+ Temp1 = Tempcx << 1 ; /* Temp1[8]: VRS[8] unsigned char -> unsigned short */
Temp1 |= Tempbx ; /* Temp1[8:0]: VRS[8:0] */
Tempax &= 0x80 ; /* Tempax[7]: CR7[7] */
Temp2 = Tempax << 2 ; /* Temp2[9]: VRS[9] */
@@ -1594,11 +1564,11 @@ void XGI_SetXG21CRTC(USHORT ModeNo, USHORT ModeIdIndex, USHORT RefreshRateTableI
if ( Tempax < Temp3 ) /* VRE[3:0]<VRS[3:0] */
Temp2 |= 0x10 ; /* Temp2: VRE + 0x10 */
Temp2 &= 0xFF ; /* Temp2[7:0]: VRE[7:0] */
- Tempax = (UCHAR)Temp2 ; /* Tempax[7:0]: VRE[7:0] */
+ Tempax = (unsigned char)Temp2; /* Tempax[7:0]: VRE[7:0] */
Tempax <<= 2 ; /* Tempax << 2: VRE[5:0] */
Temp1 &= 0x600 ; /* Temp1[10:9]: VRS[10:9] */
Temp1 >>= 9 ; /* [10:9]->[1:0] */
- Tempbx = (UCHAR)Temp1 ; /* Tempbx[1:0]: VRS[10:9] */
+ Tempbx = (unsigned char)Temp1; /* Tempbx[1:0]: VRS[10:9] */
Tempax |= Tempbx ; /* VRE[5:0]VRS[10:9] */
Tempax &= 0x7F ;
XGINew_SetReg1( pVBInfo->P3c4 , 0x3F , Tempax ) ; /* SR3F D[7:2]->VRE D[1:0]->VRS */
@@ -1632,7 +1602,7 @@ void XGI_SetXG21CRTC(USHORT ModeNo, USHORT ModeIdIndex, USHORT RefreshRateTableI
Temp2 |= 0x40 ; /* Temp2 + 0x40 */
Temp2 &= 0xFF ;
- Tempax = (UCHAR)Temp2 ; /* Tempax: HRE[7:0] */
+ Tempax = (unsigned char)Temp2; /* Tempax: HRE[7:0] */
Tempax <<= 2 ; /* Tempax[7:2]: HRE[5:0] */
Tempdx >>= 6 ; /* Tempdx[7:6]->[1:0] HRS[9:8] */
Tempax |= Tempdx ; /* HRE[5:0]HRS[9:8] */
@@ -1676,20 +1646,22 @@ void XGI_SetXG21CRTC(USHORT ModeNo, USHORT ModeIdIndex, USHORT RefreshRateTableI
Temp2 |= 0x20 ; /* VRE + 0x20 */
Temp2 &= 0xFF ;
- Tempax = (UCHAR)Temp2 ; /* Tempax: VRE[7:0] */
+ Tempax = (unsigned char)Temp2; /* Tempax: VRE[7:0] */
Tempax <<= 2 ; /* Tempax[7:0]; VRE[5:0]00 */
Temp1 &= 0x600 ; /* Temp1[10:9]: VRS[10:9] */
Temp1 >>= 9 ; /* Temp1[1:0]: VRS[10:9] */
- Tempbx = (UCHAR)Temp1 ;
+ Tempbx = (unsigned char)Temp1;
Tempax |= Tempbx ; /* Tempax[7:0]: VRE[5:0]VRS[10:9] */
Tempax &= 0x7F ;
XGINew_SetReg1( pVBInfo->P3c4 , 0x3F , Tempax ) ; /* SR3F D[7:2]->VRE D[1:0]->VRS */
}
}
-void XGI_SetXG27CRTC(USHORT ModeNo, USHORT ModeIdIndex, USHORT RefreshRateTableIndex, PVB_DEVICE_INFO pVBInfo)
+void XGI_SetXG27CRTC(unsigned short ModeNo, unsigned short ModeIdIndex,
+ unsigned short RefreshRateTableIndex,
+ struct vb_device_info *pVBInfo)
{
- USHORT StandTableIndex, index, Tempax, Tempbx, Tempcx, Tempdx ;
+ unsigned short StandTableIndex, index, Tempax, Tempbx, Tempcx, Tempdx;
if ( ModeNo <= 0x13 )
{
@@ -1726,7 +1698,7 @@ void XGI_SetXG27CRTC(USHORT ModeNo, USHORT ModeIdIndex, USHORT RefreshRateTableI
Tempbx |= Tempax ; /* Tempbx[9:0]: VRE[9:0] */
if ( Tempax <= (Tempcx & 0x0F) ) /* VRE[3:0]<=VRS[3:0] */
Tempbx |= 0x10 ; /* Tempbx: VRE + 0x10 */
- Tempax = (UCHAR)Tempbx & 0xFF; /* Tempax[7:0]: VRE[7:0] */
+ Tempax = (unsigned char)Tempbx & 0xFF; /* Tempax[7:0]: VRE[7:0] */
Tempax <<= 2 ; /* Tempax << 2: VRE[5:0] */
Tempcx = (Tempcx&0x600)>>8; /* Tempcx VRS[10:9] */
XGINew_SetRegANDOR( pVBInfo->P3c4 , 0x3F , ~0xFC, Tempax ) ; /* SR3F D[7:2]->VRE D[5:0] */
@@ -1810,10 +1782,12 @@ void XGI_SetXG27CRTC(USHORT ModeNo, USHORT ModeIdIndex, USHORT RefreshRateTableI
/* Output : FCLK duty cycle, FCLK delay compensation */
/* Description : All values set zero */
/* --------------------------------------------------------------------- */
-void XGI_SetXG21LCD(PVB_DEVICE_INFO pVBInfo,USHORT RefreshRateTableIndex,USHORT ModeNo)
+void XGI_SetXG21LCD(struct vb_device_info *pVBInfo,
+ unsigned short RefreshRateTableIndex,
+ unsigned short ModeNo)
{
- USHORT Data , Temp , b3CC ;
- USHORT XGI_P3cc ;
+ unsigned short Data, Temp, b3CC;
+ unsigned short XGI_P3cc;
XGI_P3cc = pVBInfo->P3cc ;
@@ -1844,7 +1818,7 @@ void XGI_SetXG21LCD(PVB_DEVICE_INFO pVBInfo,USHORT RefreshRateTableIndex,USHORT
if ( ModeNo <= 0x13 )
{
- b3CC = (UCHAR) XGINew_GetReg2( XGI_P3cc ) ;
+ b3CC = (unsigned char) XGINew_GetReg2(XGI_P3cc);
if ( b3CC & 0x40 )
XGINew_SetRegOR( pVBInfo->P3c4 , 0x30 , 0x20 ) ; /* Hsync polarity */
if ( b3CC & 0x80 )
@@ -1860,10 +1834,12 @@ void XGI_SetXG21LCD(PVB_DEVICE_INFO pVBInfo,USHORT RefreshRateTableIndex,USHORT
}
}
-void XGI_SetXG27LCD(PVB_DEVICE_INFO pVBInfo,USHORT RefreshRateTableIndex,USHORT ModeNo)
+void XGI_SetXG27LCD(struct vb_device_info *pVBInfo,
+ unsigned short RefreshRateTableIndex,
+ unsigned short ModeNo)
{
- USHORT Data , Temp , b3CC ;
- USHORT XGI_P3cc ;
+ unsigned short Data , Temp , b3CC ;
+ unsigned short XGI_P3cc ;
XGI_P3cc = pVBInfo->P3cc ;
@@ -1896,7 +1872,7 @@ void XGI_SetXG27LCD(PVB_DEVICE_INFO pVBInfo,USHORT RefreshRateTableIndex,USHORT
if ( ModeNo <= 0x13 )
{
- b3CC = (UCHAR) XGINew_GetReg2( XGI_P3cc ) ;
+ b3CC = (unsigned char) XGINew_GetReg2(XGI_P3cc);
if ( b3CC & 0x40 )
XGINew_SetRegOR( pVBInfo->P3c4 , 0x30 , 0x20 ) ; /* Hsync polarity */
if ( b3CC & 0x80 )
@@ -1918,7 +1894,9 @@ void XGI_SetXG27LCD(PVB_DEVICE_INFO pVBInfo,USHORT RefreshRateTableIndex,USHORT
/* Output : CRT1 CRTC */
/* Description : Modify CRT1 Hsync/Vsync to fix LCD mode timing */
/* --------------------------------------------------------------------- */
-void XGI_UpdateXG21CRTC( USHORT ModeNo , PVB_DEVICE_INFO pVBInfo , USHORT RefreshRateTableIndex )
+void XGI_UpdateXG21CRTC(unsigned short ModeNo,
+ struct vb_device_info *pVBInfo,
+ unsigned short RefreshRateTableIndex)
{
int i , index = -1;
@@ -1961,16 +1939,15 @@ void XGI_UpdateXG21CRTC( USHORT ModeNo , PVB_DEVICE_INFO pVBInfo , USHORT Refres
/* Output : */
/* Description : */
/* --------------------------------------------------------------------- */
-void XGI_SetCRT1DE( PXGI_HW_DEVICE_INFO HwDeviceExtension , USHORT ModeNo,USHORT ModeIdIndex , USHORT RefreshRateTableIndex, PVB_DEVICE_INFO pVBInfo )
+void XGI_SetCRT1DE(struct xgi_hw_device_info *HwDeviceExtension,
+ unsigned short ModeNo,
+ unsigned short ModeIdIndex,
+ unsigned short RefreshRateTableIndex,
+ struct vb_device_info *pVBInfo)
{
- USHORT resindex ,
- tempax ,
- tempbx ,
- tempcx ,
- temp ,
- modeflag ;
+ unsigned short resindex, tempax, tempbx, tempcx, temp, modeflag;
- UCHAR data ;
+ unsigned char data;
resindex = XGI_GetResInfo( ModeNo , ModeIdIndex, pVBInfo ) ;
@@ -2013,13 +1990,13 @@ void XGI_SetCRT1DE( PXGI_HW_DEVICE_INFO HwDeviceExtension , USHORT ModeNo,USHORT
tempax -= 1 ;
tempbx -= 1 ;
tempcx = tempax ;
- temp = ( UCHAR )XGINew_GetReg1( pVBInfo->P3d4 , 0x11 ) ;
- data = ( UCHAR )XGINew_GetReg1( pVBInfo->P3d4 , 0x11 ) ;
+ temp = (unsigned char)XGINew_GetReg1(pVBInfo->P3d4, 0x11);
+ data = (unsigned char)XGINew_GetReg1(pVBInfo->P3d4, 0x11);
data &= 0x7F ;
XGINew_SetReg1( pVBInfo->P3d4 , 0x11 , data ) ; /* Unlock CRTC */
- XGINew_SetReg1( pVBInfo->P3d4 , 0x01 , ( USHORT )( tempcx & 0xff ) ) ;
- XGINew_SetRegANDOR( pVBInfo->P3d4 , 0x0b , ~0x0c , ( USHORT )( ( tempcx & 0x0ff00 ) >> 10 ) ) ;
- XGINew_SetReg1( pVBInfo->P3d4 , 0x12 , ( USHORT )( tempbx & 0xff ) ) ;
+ XGINew_SetReg1(pVBInfo->P3d4, 0x01, (unsigned short)(tempcx & 0xff));
+ XGINew_SetRegANDOR(pVBInfo->P3d4, 0x0b, ~0x0c, (unsigned short)((tempcx & 0x0ff00) >> 10));
+ XGINew_SetReg1(pVBInfo->P3d4, 0x12, (unsigned short)(tempbx & 0xff));
tempax = 0 ;
tempbx = tempbx >> 8 ;
@@ -2030,7 +2007,7 @@ void XGI_SetCRT1DE( PXGI_HW_DEVICE_INFO HwDeviceExtension , USHORT ModeNo,USHORT
tempax |= 0x40 ;
XGINew_SetRegANDOR( pVBInfo->P3d4 , 0x07 , ~0x42 , tempax ) ;
- data =( UCHAR )XGINew_GetReg1( pVBInfo->P3d4 , 0x07 ) ;
+ data = (unsigned char)XGINew_GetReg1(pVBInfo->P3d4, 0x07);
data &= 0xFF ;
tempax = 0 ;
@@ -2048,9 +2025,11 @@ void XGI_SetCRT1DE( PXGI_HW_DEVICE_INFO HwDeviceExtension , USHORT ModeNo,USHORT
/* Output : */
/* Description : */
/* --------------------------------------------------------------------- */
-USHORT XGI_GetResInfo(USHORT ModeNo , USHORT ModeIdIndex, PVB_DEVICE_INFO pVBInfo )
+unsigned short XGI_GetResInfo(unsigned short ModeNo,
+ unsigned short ModeIdIndex,
+ struct vb_device_info *pVBInfo)
{
- USHORT resindex ;
+ unsigned short resindex;
if ( ModeNo <= 0x13 )
{
@@ -2070,9 +2049,13 @@ USHORT XGI_GetResInfo(USHORT ModeNo , USHORT ModeIdIndex, PVB_DEVICE_INFO pVBIn
/* Output : */
/* Description : */
/* --------------------------------------------------------------------- */
-void XGI_SetCRT1Offset( USHORT ModeNo , USHORT ModeIdIndex , USHORT RefreshRateTableIndex , PXGI_HW_DEVICE_INFO HwDeviceExtension, PVB_DEVICE_INFO pVBInfo )
+void XGI_SetCRT1Offset(unsigned short ModeNo,
+ unsigned short ModeIdIndex,
+ unsigned short RefreshRateTableIndex,
+ struct xgi_hw_device_info *HwDeviceExtension,
+ struct vb_device_info *pVBInfo)
{
- USHORT temp ,
+ unsigned short temp ,
ah ,
al ,
temp2 ,
@@ -2131,7 +2114,7 @@ void XGI_SetCRT1Offset( USHORT ModeNo , USHORT ModeIdIndex , USHORT RefreshRate
i |= temp ;
XGINew_SetReg1( pVBInfo->P3c4 , 0x0E , i ) ;
- temp =( UCHAR )temp2 ;
+ temp = (unsigned char)temp2;
temp &= 0xFF ; /* al */
XGINew_SetReg1( pVBInfo->P3d4 , 0x13 , temp ) ;
@@ -2163,11 +2146,13 @@ void XGI_SetCRT1Offset( USHORT ModeNo , USHORT ModeIdIndex , USHORT RefreshRate
/* Output : */
/* Description : */
/* --------------------------------------------------------------------- */
-void XGI_SetCRT1VCLK( USHORT ModeNo , USHORT ModeIdIndex ,
- PXGI_HW_DEVICE_INFO HwDeviceExtension , USHORT RefreshRateTableIndex, PVB_DEVICE_INFO pVBInfo )
+void XGI_SetCRT1VCLK(unsigned short ModeNo, unsigned short ModeIdIndex,
+ struct xgi_hw_device_info *HwDeviceExtension,
+ unsigned short RefreshRateTableIndex,
+ struct vb_device_info *pVBInfo)
{
- UCHAR index , data ;
- USHORT vclkindex ;
+ unsigned char index, data;
+ unsigned short vclkindex ;
if ( pVBInfo->IF_DEF_LVDS == 1 )
{
@@ -2224,9 +2209,11 @@ void XGI_SetCRT1VCLK( USHORT ModeNo , USHORT ModeIdIndex ,
/* Output : */
/* Description : */
/* --------------------------------------------------------------------- */
-void XGI_SetCRT1FIFO( USHORT ModeNo , PXGI_HW_DEVICE_INFO HwDeviceExtension,PVB_DEVICE_INFO pVBInfo )
+void XGI_SetCRT1FIFO(unsigned short ModeNo,
+ struct xgi_hw_device_info *HwDeviceExtension,
+ struct vb_device_info *pVBInfo)
{
- USHORT data ;
+ unsigned short data ;
data = XGINew_GetReg1( pVBInfo->P3c4 , 0x3D ) ;
data &= 0xfe ;
@@ -2273,10 +2260,12 @@ void XGI_SetCRT1FIFO( USHORT ModeNo , PXGI_HW_DEVICE_INFO HwDeviceExtension,PVB_
/* Output : */
/* Description : */
/* --------------------------------------------------------------------- */
-void XGI_SetCRT1ModeRegs( PXGI_HW_DEVICE_INFO HwDeviceExtension ,
- USHORT ModeNo , USHORT ModeIdIndex , USHORT RefreshRateTableIndex,PVB_DEVICE_INFO pVBInfo )
+void XGI_SetCRT1ModeRegs(struct xgi_hw_device_info *HwDeviceExtension,
+ unsigned short ModeNo, unsigned short ModeIdIndex,
+ unsigned short RefreshRateTableIndex,
+ struct vb_device_info *pVBInfo)
{
- USHORT data ,
+ unsigned short data ,
data2 ,
data3 ,
infoflag = 0 ,
@@ -2411,13 +2400,16 @@ void XGI_SetCRT1ModeRegs( PXGI_HW_DEVICE_INFO HwDeviceExtension ,
/* Output : */
/* Description : */
/* --------------------------------------------------------------------- */
-void XGI_SetVCLKState( PXGI_HW_DEVICE_INFO HwDeviceExtension , USHORT ModeNo , USHORT RefreshRateTableIndex,PVB_DEVICE_INFO pVBInfo )
+void XGI_SetVCLKState(struct xgi_hw_device_info *HwDeviceExtension,
+ unsigned short ModeNo,
+ unsigned short RefreshRateTableIndex,
+ struct vb_device_info *pVBInfo)
{
- USHORT data ,
+ unsigned short data ,
data2 = 0 ;
- SHORT VCLK ;
+ short VCLK ;
- UCHAR index ;
+ unsigned char index;
if ( ModeNo <= 0x13 )
VCLK = 0 ;
@@ -2475,9 +2467,9 @@ void XGI_SetVCLKState( PXGI_HW_DEVICE_INFO HwDeviceExtension , USHORT ModeNo ,
/* Output : */
/* Description : */
/* --------------------------------------------------------------------- */
-/*void XGI_VesaLowResolution( USHORT ModeNo , USHORT ModeIdIndex ,PVB_DEVICE_INFO pVBInfo)
+/*void XGI_VesaLowResolution(unsigned short ModeNo, unsigned short ModeIdIndex, struct vb_device_info *pVBInfo)
{
- USHORT modeflag;
+ unsigned short modeflag;
if ( ModeNo > 0x13 )
modeflag = pVBInfo->EModeIDTable[ ModeIdIndex ].Ext_ModeFlag ;
@@ -2518,9 +2510,11 @@ void XGI_SetVCLKState( PXGI_HW_DEVICE_INFO HwDeviceExtension , USHORT ModeNo ,
/* Output : */
/* Description : */
/* --------------------------------------------------------------------- */
-void XGI_LoadDAC( USHORT ModeNo , USHORT ModeIdIndex,PVB_DEVICE_INFO pVBInfo )
+void XGI_LoadDAC(unsigned short ModeNo,
+ unsigned short ModeIdIndex,
+ struct vb_device_info *pVBInfo)
{
- USHORT data , data2 , time ,
+ unsigned short data , data2 , time ,
i , j , k , m , n , o ,
si , di , bx , dl , al , ah , dh ,
*table = NULL ;
@@ -2627,9 +2621,11 @@ void XGI_LoadDAC( USHORT ModeNo , USHORT ModeIdIndex,PVB_DEVICE_INFO pVBInfo )
/* Output : */
/* Description : */
/* --------------------------------------------------------------------- */
-void XGI_WriteDAC( USHORT dl , USHORT ah , USHORT al , USHORT dh,PVB_DEVICE_INFO pVBInfo )
+void XGI_WriteDAC(unsigned short dl, unsigned short ah,
+ unsigned short al, unsigned short dh,
+ struct vb_device_info *pVBInfo)
{
- USHORT temp , bh , bl ;
+ unsigned short temp , bh , bl ;
bh = ah ;
bl = al ;
@@ -2652,70 +2648,24 @@ void XGI_WriteDAC( USHORT dl , USHORT ah , USHORT al , USHORT dh,PVB_DEVICE_INFO
bh = temp ;
}
}
- XGINew_SetReg3( pVBInfo->P3c9 , ( USHORT )dh ) ;
- XGINew_SetReg3( pVBInfo->P3c9 , ( USHORT )bh ) ;
- XGINew_SetReg3( pVBInfo->P3c9 , ( USHORT )bl ) ;
+ XGINew_SetReg3(pVBInfo->P3c9, (unsigned short)dh);
+ XGINew_SetReg3(pVBInfo->P3c9, (unsigned short)bh);
+ XGINew_SetReg3(pVBInfo->P3c9, (unsigned short)bl);
}
-#if 0
-/* --------------------------------------------------------------------- */
-/* Function : XGI_ClearBuffer */
-/* Input : */
-/* Output : */
-/* Description : */
-/* --------------------------------------------------------------------- */
-void XGI_ClearBuffer( PXGI_HW_DEVICE_INFO HwDeviceExtension , USHORT ModeNo, PVB_DEVICE_INFO pVBInfo)
-{
- PVOID VideoMemoryAddress = ( PVOID )HwDeviceExtension->pjVideoMemoryAddress ;
- ULONG AdapterMemorySize = ( ULONG )HwDeviceExtension->ulVideoMemorySize ;
- PUSHORT pBuffer ;
-#ifndef LINUX_XF86
- int i ;
-#endif
-
- if ( pVBInfo->ModeType >= ModeEGA )
- {
- if ( ModeNo > 0x13 )
- {
- AdapterMemorySize = 0x40000 ; /* clear 256k */
- /* GetDRAMSize( HwDeviceExtension ) ; */
- XGI_SetMemory( VideoMemoryAddress , AdapterMemorySize , 0 ) ;
- }
- else
- {
-/*
- pBuffer = VideoMemoryAddress ;
- for( i = 0 ; i < 0x4000 ; i++ )
- pBuffer[ i ] = 0x0000 ;
-*/
- }
- }
- else
- {
- pBuffer = VideoMemoryAddress ;
- if ( pVBInfo->ModeType < ModeCGA )
- {
-/*
- for ( i = 0 ; i < 0x4000 ; i++ )
- pBuffer[ i ] = 0x0720 ;
-*/
- }
- else
- XGI_SetMemory( VideoMemoryAddress , 0x8000 , 0 ) ;
- }
-}
-
-#endif
/* --------------------------------------------------------------------- */
/* Function : XGI_SetLCDAGroup */
/* Input : */
/* Output : */
/* Description : */
/* --------------------------------------------------------------------- */
-void XGI_SetLCDAGroup( USHORT ModeNo , USHORT ModeIdIndex , PXGI_HW_DEVICE_INFO HwDeviceExtension, PVB_DEVICE_INFO pVBInfo )
+void XGI_SetLCDAGroup(unsigned short ModeNo,
+ unsigned short ModeIdIndex,
+ struct xgi_hw_device_info *HwDeviceExtension,
+ struct vb_device_info *pVBInfo)
{
- USHORT RefreshRateTableIndex ;
- /* USHORT temp ; */
+ unsigned short RefreshRateTableIndex ;
+ /* unsigned short temp ; */
/* pVBInfo->SelectCRT2Rate = 0 ; */
@@ -2735,9 +2685,11 @@ void XGI_SetLCDAGroup( USHORT ModeNo , USHORT ModeIdIndex , PXGI_HW_DEVICE_INFO
/* Output : */
/* Description : */
/* --------------------------------------------------------------------- */
-void XGI_GetLVDSResInfo( USHORT ModeNo , USHORT ModeIdIndex,PVB_DEVICE_INFO pVBInfo )
+void XGI_GetLVDSResInfo(unsigned short ModeNo,
+ unsigned short ModeIdIndex,
+ struct vb_device_info *pVBInfo)
{
- USHORT resindex , xres , yres , modeflag ;
+ unsigned short resindex , xres , yres , modeflag ;
if ( ModeNo <= 0x13 )
{
@@ -2803,17 +2755,20 @@ void XGI_GetLVDSResInfo( USHORT ModeNo , USHORT ModeIdIndex,PVB_DEVICE_INFO pVB
/* Output : */
/* Description : */
/* --------------------------------------------------------------------- */
-void XGI_GetLVDSData( USHORT ModeNo , USHORT ModeIdIndex , USHORT RefreshRateTableIndex, PVB_DEVICE_INFO pVBInfo )
+void XGI_GetLVDSData(unsigned short ModeNo,
+ unsigned short ModeIdIndex,
+ unsigned short RefreshRateTableIndex,
+ struct vb_device_info *pVBInfo)
{
- USHORT tempbx ;
- XGI330_LVDSDataStruct *LCDPtr = NULL ;
- XGI330_CHTVDataStruct *TVPtr = NULL ;
+ unsigned short tempbx ;
+ struct XGI330_LVDSDataStruct *LCDPtr = NULL ;
+ struct XGI330_CHTVDataStruct *TVPtr = NULL ;
tempbx = 2 ;
if ( pVBInfo->VBInfo & ( SetCRT2ToLCD | SetCRT2ToLCDA ) )
{
- LCDPtr = ( XGI330_LVDSDataStruct * )XGI_GetLcdPtr( tempbx, ModeNo , ModeIdIndex , RefreshRateTableIndex, pVBInfo) ;
+ LCDPtr = (struct XGI330_LVDSDataStruct *)XGI_GetLcdPtr(tempbx, ModeNo, ModeIdIndex, RefreshRateTableIndex, pVBInfo);
pVBInfo->VGAHT = LCDPtr->VGAHT ;
pVBInfo->VGAVT = LCDPtr->VGAVT ;
pVBInfo->HT = LCDPtr->LCDHT ;
@@ -2823,7 +2778,7 @@ void XGI_GetLVDSData( USHORT ModeNo , USHORT ModeIdIndex , USHORT RefreshRateTa
{
if ( pVBInfo->VBInfo & SetCRT2ToTV )
{
- TVPtr = ( XGI330_CHTVDataStruct * )XGI_GetTVPtr( tempbx , ModeNo , ModeIdIndex , RefreshRateTableIndex, pVBInfo ) ;
+ TVPtr = (struct XGI330_CHTVDataStruct *)XGI_GetTVPtr(tempbx, ModeNo, ModeIdIndex, RefreshRateTableIndex, pVBInfo);
pVBInfo->VGAHT = TVPtr->VGAHT ;
pVBInfo->VGAVT = TVPtr->VGAVT ;
pVBInfo->HT = TVPtr->LCDHT ;
@@ -2866,16 +2821,18 @@ void XGI_GetLVDSData( USHORT ModeNo , USHORT ModeIdIndex , USHORT RefreshRateTa
/* Output : */
/* Description : */
/* --------------------------------------------------------------------- */
-void XGI_ModCRT1Regs( USHORT ModeNo , USHORT ModeIdIndex ,
- USHORT RefreshRateTableIndex , PXGI_HW_DEVICE_INFO HwDeviceExtension,PVB_DEVICE_INFO pVBInfo )
+void XGI_ModCRT1Regs(unsigned short ModeNo, unsigned short ModeIdIndex,
+ unsigned short RefreshRateTableIndex,
+ struct xgi_hw_device_info *HwDeviceExtension,
+ struct vb_device_info *pVBInfo)
{
- UCHAR index ;
- USHORT tempbx , i ;
- XGI_LVDSCRT1HDataStruct *LCDPtr = NULL ;
- XGI_LVDSCRT1VDataStruct *LCDPtr1 =NULL ;
- /* XGI330_CHTVDataStruct *TVPtr = NULL ; */
- XGI_CH7007TV_TimingHStruct *CH7007TV_TimingHPtr = NULL;
- XGI_CH7007TV_TimingVStruct *CH7007TV_TimingVPtr = NULL;
+ unsigned char index;
+ unsigned short tempbx , i ;
+ struct XGI_LVDSCRT1HDataStruct *LCDPtr = NULL;
+ struct XGI_LVDSCRT1VDataStruct *LCDPtr1 = NULL;
+ /* struct XGI330_CHTVDataStruct *TVPtr = NULL ; */
+ struct XGI_CH7007TV_TimingHStruct *CH7007TV_TimingHPtr = NULL;
+ struct XGI_CH7007TV_TimingVStruct *CH7007TV_TimingVPtr = NULL;
if( ModeNo <= 0x13 )
index = pVBInfo->SModeIDTable[ ModeIdIndex ].St_CRT2CRTC ;
@@ -2890,7 +2847,7 @@ void XGI_ModCRT1Regs( USHORT ModeNo , USHORT ModeIdIndex ,
if ( pVBInfo->VBInfo & ( SetCRT2ToLCD | SetCRT2ToLCDA ) )
{
- LCDPtr = ( XGI_LVDSCRT1HDataStruct * )XGI_GetLcdPtr( tempbx , ModeNo , ModeIdIndex , RefreshRateTableIndex, pVBInfo ) ;
+ LCDPtr = (struct XGI_LVDSCRT1HDataStruct *)XGI_GetLcdPtr(tempbx, ModeNo, ModeIdIndex, RefreshRateTableIndex, pVBInfo);
for( i = 0 ; i < 8 ; i++ )
pVBInfo->TimingH[ 0 ].data[ i ] = LCDPtr[ 0 ].Reg[ i ] ;
@@ -2900,7 +2857,7 @@ void XGI_ModCRT1Regs( USHORT ModeNo , USHORT ModeIdIndex ,
{
if ( pVBInfo->VBInfo & SetCRT2ToTV )
{
- CH7007TV_TimingHPtr = ( XGI_CH7007TV_TimingHStruct *)XGI_GetTVPtr( tempbx , ModeNo , ModeIdIndex , RefreshRateTableIndex, pVBInfo ) ;
+ CH7007TV_TimingHPtr = (struct XGI_CH7007TV_TimingHStruct *)XGI_GetTVPtr(tempbx, ModeNo, ModeIdIndex, RefreshRateTableIndex, pVBInfo);
for( i = 0 ; i < 8 ; i++ )
pVBInfo->TimingH[ 0 ].data[ i ] = CH7007TV_TimingHPtr[ 0 ].data[ i ] ;
@@ -2910,7 +2867,7 @@ void XGI_ModCRT1Regs( USHORT ModeNo , USHORT ModeIdIndex ,
/* if ( pVBInfo->IF_DEF_CH7017 == 1 )
{
if ( pVBInfo->VBInfo & SetCRT2ToTV )
- TVPtr = ( XGI330_CHTVDataStruct *)XGI_GetTVPtr( tempbx , ModeNo , ModeIdIndex , RefreshRateTableIndex, pVBInfo ) ;
+ TVPtr = ( struct XGI330_CHTVDataStruct *)XGI_GetTVPtr( tempbx , ModeNo , ModeIdIndex , RefreshRateTableIndex, pVBInfo ) ;
} */
XGI_SetCRT1Timing_H(pVBInfo,HwDeviceExtension) ;
@@ -2925,7 +2882,7 @@ void XGI_ModCRT1Regs( USHORT ModeNo , USHORT ModeIdIndex ,
if ( pVBInfo->VBInfo & ( SetCRT2ToLCD | SetCRT2ToLCDA ) )
{
- LCDPtr1 = ( XGI_LVDSCRT1VDataStruct * )XGI_GetLcdPtr( tempbx , ModeNo , ModeIdIndex , RefreshRateTableIndex, pVBInfo ) ;
+ LCDPtr1 = (struct XGI_LVDSCRT1VDataStruct *)XGI_GetLcdPtr(tempbx, ModeNo, ModeIdIndex, RefreshRateTableIndex, pVBInfo);
for( i = 0 ; i < 7 ; i++ )
pVBInfo->TimingV[ 0 ].data[ i ] = LCDPtr1[ 0 ].Reg[ i ] ;
}
@@ -2934,7 +2891,7 @@ void XGI_ModCRT1Regs( USHORT ModeNo , USHORT ModeIdIndex ,
{
if ( pVBInfo->VBInfo & SetCRT2ToTV )
{
- CH7007TV_TimingVPtr = ( XGI_CH7007TV_TimingVStruct *)XGI_GetTVPtr( tempbx , ModeNo , ModeIdIndex , RefreshRateTableIndex, pVBInfo ) ;
+ CH7007TV_TimingVPtr = (struct XGI_CH7007TV_TimingVStruct *)XGI_GetTVPtr(tempbx, ModeNo, ModeIdIndex, RefreshRateTableIndex, pVBInfo);
for( i = 0 ; i < 7 ; i++ )
pVBInfo->TimingV[ 0 ].data[ i ] = CH7007TV_TimingVPtr[ 0 ].data[ i ] ;
@@ -2943,7 +2900,7 @@ void XGI_ModCRT1Regs( USHORT ModeNo , USHORT ModeIdIndex ,
/* if ( pVBInfo->IF_DEF_CH7017 == 1 )
{
if ( pVBInfo->VBInfo & SetCRT2ToTV )
- TVPtr = ( XGI330_CHTVDataStruct *)XGI_GetTVPtr( tempbx , ModeNo , ModeIdIndex , RefreshRateTableIndex, pVBInfo ) ;
+ TVPtr = ( struct XGI330_CHTVDataStruct *)XGI_GetTVPtr( tempbx , ModeNo , ModeIdIndex , RefreshRateTableIndex, pVBInfo ) ;
} */
XGI_SetCRT1Timing_V( ModeIdIndex , ModeNo , pVBInfo) ;
@@ -2966,12 +2923,14 @@ void XGI_ModCRT1Regs( USHORT ModeNo , USHORT ModeIdIndex ,
/* Output : */
/* Description : */
/* --------------------------------------------------------------------- */
-void XGI_SetLVDSRegs( USHORT ModeNo , USHORT ModeIdIndex , USHORT RefreshRateTableIndex, PVB_DEVICE_INFO pVBInfo )
+void XGI_SetLVDSRegs(unsigned short ModeNo, unsigned short ModeIdIndex,
+ unsigned short RefreshRateTableIndex,
+ struct vb_device_info *pVBInfo)
{
- USHORT tempbx , tempax , tempcx , tempdx , push1 , push2 , modeflag ;
+ unsigned short tempbx , tempax , tempcx , tempdx , push1 , push2 , modeflag ;
unsigned long temp , temp1 , temp2 , temp3 , push3 ;
- XGI330_LCDDataDesStruct *LCDPtr = NULL ;
- XGI330_LCDDataDesStruct2 *LCDPtr1 = NULL ;
+ struct XGI330_LCDDataDesStruct *LCDPtr = NULL ;
+ struct XGI330_LCDDataDesStruct2 *LCDPtr1 = NULL ;
if ( ModeNo > 0x13 )
modeflag = pVBInfo->EModeIDTable[ ModeIdIndex ].Ext_ModeFlag ;
@@ -2985,16 +2944,16 @@ void XGI_SetLVDSRegs( USHORT ModeNo , USHORT ModeIdIndex , USHORT RefreshRateTab
if ( pVBInfo->IF_DEF_OEMUtil == 1 )
{
tempbx = 8 ;
- LCDPtr = ( XGI330_LCDDataDesStruct * )XGI_GetLcdPtr( tempbx , ModeNo , ModeIdIndex , RefreshRateTableIndex, pVBInfo ) ;
+ LCDPtr = (struct XGI330_LCDDataDesStruct *)XGI_GetLcdPtr(tempbx, ModeNo, ModeIdIndex, RefreshRateTableIndex, pVBInfo);
}
if ( ( pVBInfo->IF_DEF_OEMUtil == 0 ) || ( LCDPtr == 0 ) )
{
tempbx = 3 ;
if ( pVBInfo->LCDInfo & EnableScalingLCD )
- LCDPtr1 = ( XGI330_LCDDataDesStruct2 * )XGI_GetLcdPtr( tempbx , ModeNo , ModeIdIndex , RefreshRateTableIndex, pVBInfo ) ;
+ LCDPtr1 = (struct XGI330_LCDDataDesStruct2 *)XGI_GetLcdPtr(tempbx, ModeNo, ModeIdIndex, RefreshRateTableIndex, pVBInfo);
else
- LCDPtr = ( XGI330_LCDDataDesStruct * )XGI_GetLcdPtr( tempbx , ModeNo , ModeIdIndex , RefreshRateTableIndex, pVBInfo ) ;
+ LCDPtr = (struct XGI330_LCDDataDesStruct *)XGI_GetLcdPtr(tempbx, ModeNo, ModeIdIndex, RefreshRateTableIndex, pVBInfo);
}
XGI_GetLCDSync( &tempax , &tempbx ,pVBInfo) ;
@@ -3056,8 +3015,8 @@ void XGI_SetLVDSRegs( USHORT ModeNo , USHORT ModeIdIndex , USHORT RefreshRateTab
tempcx = tempcx >> 3 ;
tempbx = tempbx >> 3 ;
- XGINew_SetReg1( pVBInfo->Part1Port , 0x16 , ( USHORT )( tempbx & 0xff ) ) ;
- XGINew_SetReg1( pVBInfo->Part1Port , 0x17 , ( USHORT )( tempcx & 0xff ) ) ;
+ XGINew_SetReg1(pVBInfo->Part1Port, 0x16, (unsigned short)(tempbx & 0xff));
+ XGINew_SetReg1(pVBInfo->Part1Port, 0x17, (unsigned short)(tempcx & 0xff));
tempax = pVBInfo->HT ;
@@ -3085,7 +3044,7 @@ void XGI_SetLVDSRegs( USHORT ModeNo , USHORT ModeIdIndex , USHORT RefreshRateTab
tempax |= tempcx ;
XGINew_SetReg1( pVBInfo->Part1Port , 0x15 , tempax ) ;
- XGINew_SetReg1( pVBInfo->Part1Port , 0x14 , ( USHORT )( tempbx & 0xff ) ) ;
+ XGINew_SetReg1(pVBInfo->Part1Port, 0x14, (unsigned short)(tempbx & 0xff));
tempax = pVBInfo->VT ;
if ( pVBInfo->LCDInfo & EnableScalingLCD )
@@ -3099,13 +3058,13 @@ void XGI_SetLVDSRegs( USHORT ModeNo , USHORT ModeIdIndex , USHORT RefreshRateTab
if ( tempcx >= tempax )
tempcx -= tempax ;
- XGINew_SetReg1( pVBInfo->Part1Port , 0x1b , ( USHORT )( tempbx & 0xff ) ) ;
- XGINew_SetReg1( pVBInfo->Part1Port , 0x1c , ( USHORT )( tempcx & 0xff ) ) ;
+ XGINew_SetReg1(pVBInfo->Part1Port, 0x1b, (unsigned short)(tempbx & 0xff));
+ XGINew_SetReg1(pVBInfo->Part1Port, 0x1c, (unsigned short)(tempcx & 0xff));
tempbx = ( tempbx >> 8 ) & 0x07 ;
tempcx = ( tempcx >> 8 ) & 0x07 ;
- XGINew_SetReg1( pVBInfo->Part1Port , 0x1d , ( USHORT )( ( tempcx << 3 ) | tempbx ) ) ;
+ XGINew_SetReg1(pVBInfo->Part1Port, 0x1d, (unsigned short)((tempcx << 3) | tempbx));
tempax = pVBInfo->VT ;
if ( pVBInfo->LCDInfo & EnableScalingLCD )
@@ -3123,8 +3082,8 @@ void XGI_SetLVDSRegs( USHORT ModeNo , USHORT ModeIdIndex , USHORT RefreshRateTab
if ( tempcx >= tempax )
tempcx -= tempax ;
- XGINew_SetReg1( pVBInfo->Part1Port , 0x18 , ( USHORT )( tempbx & 0xff ) ) ;
- XGINew_SetRegANDOR( pVBInfo->Part1Port , 0x19 , ~0x0f , ( USHORT )( tempcx & 0x0f ) ) ;
+ XGINew_SetReg1(pVBInfo->Part1Port, 0x18, (unsigned short)(tempbx & 0xff));
+ XGINew_SetRegANDOR(pVBInfo->Part1Port, 0x19, ~0x0f, (unsigned short)(tempcx & 0x0f));
tempax = ( ( tempbx >> 8 ) & 0x07 ) << 3 ;
@@ -3145,7 +3104,7 @@ void XGI_SetLVDSRegs( USHORT ModeNo , USHORT ModeIdIndex , USHORT RefreshRateTab
temp = tempax ; /* 0430 ylshieh */
temp1 = ( temp << 18 ) / tempbx ;
- tempdx = ( USHORT )( ( temp << 18 ) % tempbx ) ;
+ tempdx = (unsigned short)((temp << 18) % tempbx);
if ( tempdx != 0 )
temp1 += 1 ;
@@ -3153,10 +3112,10 @@ void XGI_SetLVDSRegs( USHORT ModeNo , USHORT ModeIdIndex , USHORT RefreshRateTab
temp2 = temp1 ;
push3 = temp2 ;
- XGINew_SetReg1( pVBInfo->Part1Port , 0x37 , ( USHORT )( temp2 & 0xff ) ) ;
- XGINew_SetReg1( pVBInfo->Part1Port , 0x36 , ( USHORT )( ( temp2 >> 8 ) & 0xff ) ) ;
+ XGINew_SetReg1(pVBInfo->Part1Port, 0x37, (unsigned short)(temp2 & 0xff));
+ XGINew_SetReg1(pVBInfo->Part1Port, 0x36, (unsigned short)((temp2 >> 8) & 0xff));
- tempbx = ( USHORT )( temp2 >> 16 ) ;
+ tempbx = (unsigned short)(temp2 >> 16);
tempax = tempbx & 0x03 ;
tempbx = pVBInfo->VGAVDE ;
@@ -3168,10 +3127,10 @@ void XGI_SetLVDSRegs( USHORT ModeNo , USHORT ModeIdIndex , USHORT RefreshRateTab
if ( pVBInfo->VBType & VB_XGI301C )
{
temp2 = push3 ;
- XGINew_SetReg1( pVBInfo->Part4Port , 0x3c , ( USHORT )( temp2 & 0xff ) ) ;
- XGINew_SetReg1( pVBInfo->Part4Port , 0x3b , ( USHORT )( ( temp2 >> 8 ) & 0xff ) ) ;
- tempbx = ( USHORT )( temp2 >> 16 ) ;
- XGINew_SetRegANDOR( pVBInfo->Part4Port , 0x3a , ~0xc0 , ( USHORT )( ( tempbx & 0xff ) << 6 ) ) ;
+ XGINew_SetReg1(pVBInfo->Part4Port, 0x3c, (unsigned short)(temp2 & 0xff));
+ XGINew_SetReg1(pVBInfo->Part4Port, 0x3b, (unsigned short)((temp2 >> 8) & 0xff));
+ tempbx = (unsigned short)(temp2 >> 16);
+ XGINew_SetRegANDOR(pVBInfo->Part4Port, 0x3a, ~0xc0, (unsigned short)((tempbx & 0xff) << 6));
tempcx = pVBInfo->VGAVDE ;
if ( tempcx == pVBInfo->VDE )
@@ -3185,7 +3144,7 @@ void XGI_SetLVDSRegs( USHORT ModeNo , USHORT ModeIdIndex , USHORT RefreshRateTab
temp1 = tempcx << 16 ;
- tempax = ( USHORT )( temp1 / tempbx ) ;
+ tempax = (unsigned short)(temp1 / tempbx);
if ( ( tempbx & 0xffff ) == ( tempcx & 0xffff ) )
tempax = 65535 ;
@@ -3199,28 +3158,28 @@ void XGI_SetLVDSRegs( USHORT ModeNo , USHORT ModeIdIndex , USHORT RefreshRateTab
temp3 = ( temp3 & 0xffff0000 ) + ( temp1 & 0xffff ) ;
- tempax = ( USHORT )( temp3 & 0xff ) ;
+ tempax = (unsigned short)(temp3 & 0xff);
XGINew_SetReg1( pVBInfo->Part1Port , 0x1f , tempax ) ;
temp1 = pVBInfo->VGAVDE << 18 ;
temp1 = temp1 / push3 ;
- tempbx = ( USHORT )( temp1 & 0xffff ) ;
+ tempbx = (unsigned short)(temp1 & 0xffff);
if ( pVBInfo->LCDResInfo == Panel1024x768 )
tempbx -= 1 ;
tempax = ( ( tempbx >> 8 ) & 0xff ) << 3 ;
- tempax |= ( USHORT )( ( temp3 >> 8 ) & 0x07 ) ;
- XGINew_SetReg1( pVBInfo->Part1Port , 0x20 , ( USHORT )( tempax & 0xff ) ) ;
- XGINew_SetReg1( pVBInfo->Part1Port , 0x21 , ( USHORT )( tempbx & 0xff ) ) ;
+ tempax |= (unsigned short)((temp3 >> 8) & 0x07);
+ XGINew_SetReg1(pVBInfo->Part1Port, 0x20, (unsigned short)(tempax & 0xff));
+ XGINew_SetReg1(pVBInfo->Part1Port, 0x21, (unsigned short)(tempbx & 0xff));
temp3 = temp3 >> 16 ;
if ( modeflag & HalfDCLK )
temp3 = temp3 >> 1 ;
- XGINew_SetReg1(pVBInfo->Part1Port , 0x22 , ( USHORT )( ( temp3 >> 8 ) & 0xff ) ) ;
- XGINew_SetReg1(pVBInfo->Part1Port , 0x23 , ( USHORT )( temp3 & 0xff ) ) ;
+ XGINew_SetReg1(pVBInfo->Part1Port , 0x22, (unsigned short)((temp3 >> 8) & 0xff));
+ XGINew_SetReg1(pVBInfo->Part1Port , 0x23, (unsigned short)(temp3 & 0xff));
}
}
}
@@ -3232,9 +3191,9 @@ void XGI_SetLVDSRegs( USHORT ModeNo , USHORT ModeIdIndex , USHORT RefreshRateTab
/* Output : */
/* Description : */
/* --------------------------------------------------------------------- */
-void XGI_SetCRT2ECLK( USHORT ModeNo , USHORT ModeIdIndex , USHORT RefreshRateTableIndex, PVB_DEVICE_INFO pVBInfo )
+void XGI_SetCRT2ECLK(unsigned short ModeNo, unsigned short ModeIdIndex, unsigned short RefreshRateTableIndex, struct vb_device_info *pVBInfo)
{
- UCHAR di_0 , di_1 , tempal ;
+ unsigned char di_0, di_1, tempal;
int i ;
tempal = XGI_GetVCLKPtr( RefreshRateTableIndex , ModeNo , ModeIdIndex, pVBInfo ) ;
@@ -3243,7 +3202,7 @@ void XGI_SetCRT2ECLK( USHORT ModeNo , USHORT ModeIdIndex , USHORT RefreshRateTab
for( i = 0 ; i < 4 ; i++ )
{
- XGINew_SetRegANDOR( pVBInfo->P3d4 , 0x31 , ~0x30 , ( USHORT )( 0x10 * i ) ) ;
+ XGINew_SetRegANDOR(pVBInfo->P3d4, 0x31, ~0x30, (unsigned short)(0x10 * i));
if ( pVBInfo->IF_DEF_CH7007 == 1 )
{
XGINew_SetReg1( pVBInfo->P3c4 , 0x2b , di_0 ) ;
@@ -3269,9 +3228,9 @@ void XGI_SetCRT2ECLK( USHORT ModeNo , USHORT ModeIdIndex , USHORT RefreshRateTab
/* Output : */
/* Description : */
/* --------------------------------------------------------------------- */
-void XGI_UpdateModeInfo( PXGI_HW_DEVICE_INFO HwDeviceExtension,PVB_DEVICE_INFO pVBInfo )
+void XGI_UpdateModeInfo(struct xgi_hw_device_info *HwDeviceExtension, struct vb_device_info *pVBInfo)
{
- USHORT tempcl ,
+ unsigned short tempcl ,
tempch ,
temp ,
tempbl ,
@@ -3377,7 +3336,7 @@ void XGI_UpdateModeInfo( PXGI_HW_DEVICE_INFO HwDeviceExtension,PVB_DEVICE_INFO
/* Output : */
/* Description : */
/* --------------------------------------------------------------------- */
-void XGI_GetVGAType( PXGI_HW_DEVICE_INFO HwDeviceExtension, PVB_DEVICE_INFO pVBInfo)
+void XGI_GetVGAType(struct xgi_hw_device_info *HwDeviceExtension, struct vb_device_info *pVBInfo)
{
/*
if ( HwDeviceExtension->jChipType >= XG20 )
@@ -3399,9 +3358,9 @@ void XGI_GetVGAType( PXGI_HW_DEVICE_INFO HwDeviceExtension, PVB_DEVICE_INFO pVB
/* Output : */
/* Description : */
/* --------------------------------------------------------------------- */
-void XGI_GetVBType(PVB_DEVICE_INFO pVBInfo)
+void XGI_GetVBType(struct vb_device_info *pVBInfo)
{
- USHORT flag , tempbx , tempah ;
+ unsigned short flag , tempbx , tempah ;
if ( pVBInfo->IF_DEF_CH7007 == 1 )
{
@@ -3462,9 +3421,9 @@ void XGI_GetVBType(PVB_DEVICE_INFO pVBInfo)
/* Output : */
/* Description : */
/* --------------------------------------------------------------------- */
-void XGI_GetVBInfo( USHORT ModeNo , USHORT ModeIdIndex , PXGI_HW_DEVICE_INFO HwDeviceExtension, PVB_DEVICE_INFO pVBInfo )
+void XGI_GetVBInfo(unsigned short ModeNo, unsigned short ModeIdIndex, struct xgi_hw_device_info *HwDeviceExtension, struct vb_device_info *pVBInfo)
{
- USHORT tempax ,
+ unsigned short tempax ,
push ,
tempbx ,
temp ,
@@ -3703,9 +3662,9 @@ void XGI_GetVBInfo( USHORT ModeNo , USHORT ModeIdIndex , PXGI_HW_DEVICE_INFO HwD
/* Output : */
/* Description : */
/* --------------------------------------------------------------------- */
-void XGI_GetTVInfo( USHORT ModeNo , USHORT ModeIdIndex ,PVB_DEVICE_INFO pVBInfo )
+void XGI_GetTVInfo(unsigned short ModeNo, unsigned short ModeIdIndex, struct vb_device_info *pVBInfo)
{
- USHORT temp ,
+ unsigned short temp ,
tempbx = 0 ,
resinfo = 0 ,
modeflag ,
@@ -3838,9 +3797,10 @@ void XGI_GetTVInfo( USHORT ModeNo , USHORT ModeIdIndex ,PVB_DEVICE_INFO pVBInfo
/* Output : */
/* Description : */
/* --------------------------------------------------------------------- */
-BOOLEAN XGI_GetLCDInfo( USHORT ModeNo , USHORT ModeIdIndex, PVB_DEVICE_INFO pVBInfo)
+unsigned char XGI_GetLCDInfo(unsigned short ModeNo, unsigned short ModeIdIndex,
+ struct vb_device_info *pVBInfo)
{
- USHORT temp ,
+ unsigned short temp ,
tempax ,
tempbx ,
modeflag ,
@@ -4047,96 +4007,12 @@ BOOLEAN XGI_GetLCDInfo( USHORT ModeNo , USHORT ModeIdIndex, PVB_DEVICE_INFO pVBI
/* Output : */
/* Description : */
/* --------------------------------------------------------------------- */
-BOOLEAN XGI_SearchModeID( USHORT ModeNo , USHORT *ModeIdIndex, PVB_DEVICE_INFO pVBInfo )
+unsigned char XGI_SearchModeID(unsigned short ModeNo,
+ unsigned short *ModeIdIndex,
+ struct vb_device_info *pVBInfo)
{
-#ifdef TC
-
- if ( ModeNo <= 5 )
- ModeNo |= 1 ;
-
- if ( ModeNo <= 0x13 )
- {
- /* for (*ModeIdIndex=0;*ModeIdIndex<sizeof(pVBInfo->SModeIDTable)/sizeof(XGI_StStruct);(*ModeIdIndex)++) */
- for( *ModeIdIndex = 0 ; ; ( *ModeIdIndex )++ )
- {
- if ( pVBInfo->SModeIDTable[ *ModeIdIndex ].St_ModeID == ModeNo )
- break ;
- if ( pVBInfo->SModeIDTable[ *ModeIdIndex ].St_ModeID == 0xFF )
- return( FALSE ) ;
- }
-
- VGA_INFO = ( PUCHAR )MK_FP( 0 , 0x489 ) ;
-
- if ( ModeNo == 0x07 )
- {
- if ( ( *VGA_INFO & 0x10 ) != 0 )
- ( *ModeIdIndex )++ ; /* 400 lines */
- /* else 350 lines */
- }
-
- if ( ModeNo <= 3 )
- {
- if ( ( *VGA_INFO & 0x80 ) == 0 )
- {
- ( *ModeIdIndex )++ ;
- if ( ( *VGA_INFO & 0x10 ) != 0 )
- ( *ModeIdIndex )++ ; /* 400 lines */
- /* else 350 lines */
- }
- /* else 200 lines */
- }
- }
- else
- {
- /* for (*ModeIdIndex=0;*ModeIdIndex<sizeof(pVBInfo->EModeIDTable)/sizeof(XGI_ExtStruct);(*ModeIdIndex)++) */
- for( *ModeIdIndex = 0 ; ; ( *ModeIdIndex )++ )
- {
- if ( pVBInfo->EModeIDTable[ *ModeIdIndex ].Ext_ModeID == ModeNo )
- break ;
- if ( pVBInfo->EModeIDTable[ *ModeIdIndex ].Ext_ModeID == 0xFF )
- return( FALSE ) ;
- }
- }
-
-
-#endif
-
-#ifdef WIN2000
-
- if ( ModeNo <= 5 )
- ModeNo |= 1 ;
- if ( ModeNo <= 0x13 )
- {
- /* for (*ModeIdIndex=0;*ModeIdIndex<sizeof(pVBInfo->SModeIDTable)/sizeof(XGI_StStruct);(*ModeIdIndex)++) */
- for( *ModeIdIndex = 0 ; ; ( *ModeIdIndex )++ )
- {
- if ( pVBInfo->SModeIDTable[ *ModeIdIndex ].St_ModeID == ModeNo )
- break ;
- if ( pVBInfo->SModeIDTable[ *ModeIdIndex ].St_ModeID == 0xFF )
- return( FALSE ) ;
- }
-
- if ( ModeNo == 0x07 )
- ( *ModeIdIndex )++ ; /* 400 lines */
-
- if ( ModeNo <=3 )
- ( *ModeIdIndex ) += 2 ; /* 400 lines */
- /* else 350 lines */
- }
- else
- {
- /* for (*ModeIdIndex=0;*ModeIdIndex<sizeof(pVBInfo->EModeIDTable)/sizeof(XGI_ExtStruct);(*ModeIdIndex)++) */
- for( *ModeIdIndex = 0 ; ; ( *ModeIdIndex )++ )
- {
- if ( pVBInfo->EModeIDTable[ *ModeIdIndex ].Ext_ModeID == ModeNo )
- break ;
- if ( pVBInfo->EModeIDTable[ *ModeIdIndex ].Ext_ModeID == 0xFF )
- return( FALSE ) ;
- }
- }
-#endif
#ifdef LINUX /* chiawen for linux solution */
@@ -4144,13 +4020,13 @@ BOOLEAN XGI_SearchModeID( USHORT ModeNo , USHORT *ModeIdIndex, PVB_DEVICE_INFO p
ModeNo |= 1 ;
if ( ModeNo <= 0x13 )
{
- /* for (*ModeIdIndex=0;*ModeIdIndex<sizeof(pVBInfo->SModeIDTable)/sizeof(XGI_StStruct);(*ModeIdIndex)++) */
+ /* for (*ModeIdIndex=0;*ModeIdIndex<sizeof(pVBInfo->SModeIDTable)/sizeof(struct XGI_StStruct);(*ModeIdIndex)++) */
for( *ModeIdIndex = 0 ; ; ( *ModeIdIndex )++ )
{
- if ( pVBInfo->SModeIDTable[ *ModeIdIndex ].St_ModeID == ModeNo )
- break ;
- if ( pVBInfo->SModeIDTable[ *ModeIdIndex ].St_ModeID == 0xFF )
- return( FALSE ) ;
+ if (pVBInfo->SModeIDTable[*ModeIdIndex].St_ModeID == ModeNo)
+ break;
+ if (pVBInfo->SModeIDTable[*ModeIdIndex].St_ModeID == 0xFF)
+ return 0;
}
if ( ModeNo == 0x07 )
@@ -4162,19 +4038,19 @@ BOOLEAN XGI_SearchModeID( USHORT ModeNo , USHORT *ModeIdIndex, PVB_DEVICE_INFO p
}
else
{
- /* for (*ModeIdIndex=0;*ModeIdIndex<sizeof(pVBInfo->EModeIDTable)/sizeof(XGI_ExtStruct);(*ModeIdIndex)++) */
+ /* for (*ModeIdIndex=0;*ModeIdIndex<sizeof(pVBInfo->EModeIDTable)/sizeof(struct XGI_ExtStruct);(*ModeIdIndex)++) */
for( *ModeIdIndex = 0 ; ; ( *ModeIdIndex )++ )
{
- if ( pVBInfo->EModeIDTable[ *ModeIdIndex ].Ext_ModeID == ModeNo )
- break ;
- if ( pVBInfo->EModeIDTable[ *ModeIdIndex ].Ext_ModeID == 0xFF )
- return( FALSE ) ;
+ if (pVBInfo->EModeIDTable[*ModeIdIndex].Ext_ModeID == ModeNo)
+ break;
+ if (pVBInfo->EModeIDTable[*ModeIdIndex].Ext_ModeID == 0xFF)
+ return 0;
}
}
#endif
- return( TRUE ) ;
+ return 1;
}
@@ -4188,9 +4064,12 @@ BOOLEAN XGI_SearchModeID( USHORT ModeNo , USHORT *ModeIdIndex, PVB_DEVICE_INFO p
/* Output : */
/* Description : */
/* --------------------------------------------------------------------- */
-BOOLEAN XGINew_CheckMemorySize(PXGI_HW_DEVICE_INFO HwDeviceExtension,USHORT ModeNo,USHORT ModeIdIndex,PVB_DEVICE_INFO pVBInfo)
+unsigned char XGINew_CheckMemorySize(struct xgi_hw_device_info *HwDeviceExtension,
+ unsigned short ModeNo,
+ unsigned short ModeIdIndex,
+ struct vb_device_info *pVBInfo)
{
- USHORT memorysize ,
+ unsigned short memorysize ,
modeflag ,
temp ,
temp1 ,
@@ -4199,7 +4078,7 @@ BOOLEAN XGINew_CheckMemorySize(PXGI_HW_DEVICE_INFO HwDeviceExtension,USHORT Mode
/* if ( ( HwDeviceExtension->jChipType == XGI_650 ) ||
( HwDeviceExtension->jChipType == XGI_650M ) )
{
- return( TRUE ) ;
+ return 1;
} */
if ( ModeNo <= 0x13 )
@@ -4257,10 +4136,10 @@ BOOLEAN XGINew_CheckMemorySize(PXGI_HW_DEVICE_INFO HwDeviceExtension,USHORT Mode
temp <<= 1 ;
}
}
- if ( temp < memorysize )
- return( FALSE ) ;
+ if (temp < memorysize)
+ return 0;
else
- return( TRUE ) ;
+ return 1;
}
@@ -4270,10 +4149,10 @@ BOOLEAN XGINew_CheckMemorySize(PXGI_HW_DEVICE_INFO HwDeviceExtension,USHORT Mode
/* Output : */
/* Description : */
/* --------------------------------------------------------------------- */
-/*void XGINew_IsLowResolution( USHORT ModeNo , USHORT ModeIdIndex, BOOLEAN XGINew_CheckMemorySize(PXGI_HW_DEVICE_INFO HwDeviceExtension,USHORT ModeNo,USHORT ModeIdIndex,PVB_DEVICE_INFO pVBInfo)
+/*void XGINew_IsLowResolution(unsigned short ModeNo, unsigned short ModeIdIndex, unsigned char XGINew_CheckMemorySize(struct xgi_hw_device_info *HwDeviceExtension, unsigned short ModeNo, unsigned short ModeIdIndex, struct vb_device_info *pVBInfo)
{
- USHORT data ;
- USHORT ModeFlag ;
+ unsigned short data ;
+ unsigned short ModeFlag ;
data = XGINew_GetReg1( pVBInfo->P3c4 , 0x0F ) ;
data &= 0x7F ;
@@ -4302,7 +4181,7 @@ BOOLEAN XGINew_CheckMemorySize(PXGI_HW_DEVICE_INFO HwDeviceExtension,USHORT Mode
/* Output : */
/* Description : */
/* --------------------------------------------------------------------- */
-void XGI_DisplayOn( PXGI_HW_DEVICE_INFO pXGIHWDE , PVB_DEVICE_INFO pVBInfo )
+void XGI_DisplayOn(struct xgi_hw_device_info *pXGIHWDE, struct vb_device_info *pVBInfo)
{
XGINew_SetRegANDOR(pVBInfo->P3c4,0x01,0xDF,0x00);
@@ -4331,12 +4210,6 @@ void XGI_DisplayOn( PXGI_HW_DEVICE_INFO pXGIHWDE , PVB_DEVICE_INFO pVBInfo )
if (pVBInfo->IF_DEF_CH7007 == 1) /* [Billy] 07/05/23 For CH7007 */
{
-#ifdef WIN2000
- if ( IsCH7007TVMode( pVBInfo ) )
- {
- TurnOnCH7007(pXGIHWDE->pDevice) ; /* 07/05/28 */
- }
-#endif
}
@@ -4372,7 +4245,7 @@ void XGI_DisplayOn( PXGI_HW_DEVICE_INFO pXGIHWDE , PVB_DEVICE_INFO pVBInfo )
/* Output : */
/* Description : */
/* --------------------------------------------------------------------- */
-void XGI_DisplayOff( PXGI_HW_DEVICE_INFO pXGIHWDE , PVB_DEVICE_INFO pVBInfo )
+void XGI_DisplayOff(struct xgi_hw_device_info *pXGIHWDE, struct vb_device_info *pVBInfo)
{
if ( pXGIHWDE->jChipType == XG21 )
@@ -4392,9 +4265,6 @@ void XGI_DisplayOff( PXGI_HW_DEVICE_INFO pXGIHWDE , PVB_DEVICE_INFO pVBInfo )
{
/* if( IsCH7007TVMode( pVBInfo ) == 0 ) */
{
-#ifdef WIN2000
- TurnOffCH7007(pXGIHWDE->pDevice) ; /* 07/05/28 */
-#endif
}
}
@@ -4423,7 +4293,7 @@ void XGI_DisplayOff( PXGI_HW_DEVICE_INFO pXGIHWDE , PVB_DEVICE_INFO pVBInfo )
/* Output : */
/* Description : chiawen for sensecrt1 */
/* --------------------------------------------------------------------- */
-void XGI_WaitDisply( PVB_DEVICE_INFO pVBInfo )
+void XGI_WaitDisply(struct vb_device_info *pVBInfo)
{
while( ( XGINew_GetReg2( pVBInfo->P3da ) & 0x01 ) )
break ;
@@ -4439,58 +4309,59 @@ void XGI_WaitDisply( PVB_DEVICE_INFO pVBInfo )
/* Description : */
/* --------------------------------------------------------------------- */
-void XGI_SenseCRT1( PVB_DEVICE_INFO pVBInfo )
+void XGI_SenseCRT1(struct vb_device_info *pVBInfo)
{
- UCHAR CRTCData[ 17 ] = { 0x5F , 0x4F , 0x50 , 0x82 , 0x55 , 0x81 ,
- 0x0B , 0x3E , 0xE9 , 0x0B , 0xDF , 0xE7 ,
- 0x04 , 0x00 , 0x00 , 0x05 , 0x00 } ;
+ unsigned char CRTCData[17] = {
+ 0x5F , 0x4F , 0x50 , 0x82 , 0x55 , 0x81 ,
+ 0x0B , 0x3E , 0xE9 , 0x0B , 0xDF , 0xE7 ,
+ 0x04 , 0x00 , 0x00 , 0x05 , 0x00 };
- UCHAR SR01 = 0 , SR1F = 0 , SR07 = 0 , SR06 = 0 ;
+ unsigned char SR01 = 0, SR1F = 0, SR07 = 0, SR06 = 0;
- UCHAR CR17 , CR63 , SR31 ;
- USHORT temp ;
- UCHAR DAC_TEST_PARMS[ 3 ] = { 0x0F , 0x0F , 0x0F } ;
+ unsigned char CR17, CR63, SR31;
+ unsigned short temp ;
+ unsigned char DAC_TEST_PARMS[3] = { 0x0F, 0x0F, 0x0F } ;
int i ;
XGINew_SetReg1( pVBInfo->P3c4 , 0x05 , 0x86 ) ;
/* [2004/05/06] Vicent to fix XG42 single LCD sense to CRT+LCD */
XGINew_SetReg1( pVBInfo->P3d4 , 0x57 , 0x4A ) ;
- XGINew_SetReg1( pVBInfo->P3d4 , 0x53 , ( UCHAR )( XGINew_GetReg1( pVBInfo->P3d4 , 0x53 ) | 0x02 ) ) ;
+ XGINew_SetReg1(pVBInfo->P3d4, 0x53, (unsigned char)(XGINew_GetReg1(pVBInfo->P3d4, 0x53) | 0x02));
- SR31 = ( UCHAR )XGINew_GetReg1( pVBInfo->P3c4 , 0x31 ) ;
- CR63 = ( UCHAR )XGINew_GetReg1( pVBInfo->P3d4 , 0x63 ) ;
- SR01 = ( UCHAR )XGINew_GetReg1( pVBInfo->P3c4 , 0x01 ) ;
+ SR31 = (unsigned char)XGINew_GetReg1(pVBInfo->P3c4, 0x31);
+ CR63 = (unsigned char)XGINew_GetReg1(pVBInfo->P3d4, 0x63);
+ SR01 = (unsigned char)XGINew_GetReg1(pVBInfo->P3c4, 0x01);
- XGINew_SetReg1( pVBInfo->P3c4 , 0x01 , ( UCHAR )( SR01 & 0xDF ) ) ;
- XGINew_SetReg1( pVBInfo->P3d4 , 0x63 , ( UCHAR )( CR63 & 0xBF ) ) ;
+ XGINew_SetReg1(pVBInfo->P3c4, 0x01, (unsigned char)(SR01 & 0xDF));
+ XGINew_SetReg1(pVBInfo->P3d4, 0x63, (unsigned char)(CR63 & 0xBF));
- CR17 = ( UCHAR )XGINew_GetReg1( pVBInfo->P3d4 , 0x17 ) ;
- XGINew_SetReg1( pVBInfo->P3d4 , 0x17 , ( UCHAR )( CR17 | 0x80 ) ) ;
+ CR17 = (unsigned char)XGINew_GetReg1(pVBInfo->P3d4, 0x17);
+ XGINew_SetReg1(pVBInfo->P3d4, 0x17, (unsigned char)(CR17 | 0x80)) ;
- SR1F = ( UCHAR )XGINew_GetReg1( pVBInfo->P3c4 , 0x1F ) ;
- XGINew_SetReg1( pVBInfo->P3c4 , 0x1F , ( UCHAR )( SR1F | 0x04 ) ) ;
+ SR1F = (unsigned char)XGINew_GetReg1(pVBInfo->P3c4, 0x1F);
+ XGINew_SetReg1(pVBInfo->P3c4, 0x1F, (unsigned char)(SR1F | 0x04));
- SR07 = ( UCHAR )XGINew_GetReg1( pVBInfo->P3c4 , 0x07 ) ;
- XGINew_SetReg1( pVBInfo->P3c4 , 0x07 , ( UCHAR )( SR07 & 0xFB ) ) ;
- SR06 = ( UCHAR )XGINew_GetReg1( pVBInfo->P3c4 , 0x06 ) ;
- XGINew_SetReg1( pVBInfo->P3c4 , 0x06 , ( UCHAR )( SR06 & 0xC3 ) ) ;
+ SR07 = (unsigned char)XGINew_GetReg1(pVBInfo->P3c4, 0x07);
+ XGINew_SetReg1(pVBInfo->P3c4, 0x07, (unsigned char)(SR07 & 0xFB));
+ SR06 = (unsigned char)XGINew_GetReg1(pVBInfo->P3c4, 0x06);
+ XGINew_SetReg1(pVBInfo->P3c4, 0x06, (unsigned char)(SR06 & 0xC3));
XGINew_SetReg1( pVBInfo->P3d4 , 0x11 , 0x00 ) ;
for( i = 0 ; i < 8 ; i++ )
- XGINew_SetReg1( pVBInfo->P3d4 , ( USHORT )i , CRTCData[ i ] ) ;
+ XGINew_SetReg1(pVBInfo->P3d4, (unsigned short)i, CRTCData[i]);
for( i = 8 ; i < 11 ; i++ )
- XGINew_SetReg1( pVBInfo->P3d4 , ( USHORT )( i + 8 ) , CRTCData[ i ] ) ;
+ XGINew_SetReg1(pVBInfo->P3d4, (unsigned short)(i + 8), CRTCData[i]);
for( i = 11 ; i < 13 ; i++ )
- XGINew_SetReg1( pVBInfo->P3d4 , ( USHORT )( i + 4 ) , CRTCData[ i ] ) ;
+ XGINew_SetReg1(pVBInfo->P3d4, (unsigned short)(i + 4), CRTCData[i]);
for( i = 13 ; i < 16 ; i++ )
- XGINew_SetReg1( pVBInfo->P3c4 , ( USHORT )( i - 3 ) , CRTCData[ i ] ) ;
+ XGINew_SetReg1(pVBInfo->P3c4, (unsigned short)(i - 3), CRTCData[i]);
- XGINew_SetReg1( pVBInfo->P3c4 , 0x0E , ( UCHAR )( CRTCData[ 16 ] & 0xE0 ) ) ;
+ XGINew_SetReg1(pVBInfo->P3c4, 0x0E, (unsigned char)(CRTCData[16] & 0xE0));
XGINew_SetReg1( pVBInfo->P3c4 , 0x31 , 0x00 ) ;
XGINew_SetReg1( pVBInfo->P3c4 , 0x2B , 0x1B ) ;
@@ -4500,9 +4371,9 @@ void XGI_SenseCRT1( PVB_DEVICE_INFO pVBInfo )
for( i = 0 ; i < 256 ; i++ )
{
- XGINew_SetReg3( ( pVBInfo->P3c8 + 1 ) , ( UCHAR )DAC_TEST_PARMS[ 0 ] ) ;
- XGINew_SetReg3( ( pVBInfo->P3c8 + 1 ) , ( UCHAR )DAC_TEST_PARMS[ 1 ] ) ;
- XGINew_SetReg3( ( pVBInfo->P3c8 + 1 ) , ( UCHAR )DAC_TEST_PARMS[ 2 ] ) ;
+ XGINew_SetReg3((pVBInfo->P3c8 + 1), (unsigned char)DAC_TEST_PARMS[0]);
+ XGINew_SetReg3((pVBInfo->P3c8 + 1), (unsigned char)DAC_TEST_PARMS[1]);
+ XGINew_SetReg3((pVBInfo->P3c8 + 1), (unsigned char)DAC_TEST_PARMS[2]);
}
XGI_VBLongWait( pVBInfo ) ;
@@ -4538,148 +4409,18 @@ void XGI_SenseCRT1( PVB_DEVICE_INFO pVBInfo )
XGINew_SetReg1( pVBInfo->P3c4 , 0x31 , SR31 ) ;
/* [2004/05/11] Vicent */
- XGINew_SetReg1( pVBInfo->P3d4 , 0x53 , ( UCHAR )( XGINew_GetReg1( pVBInfo->P3d4 , 0x53 ) & 0xFD ) ) ;
- XGINew_SetReg1( pVBInfo->P3c4 , 0x1F , ( UCHAR ) SR1F ) ;
+ XGINew_SetReg1(pVBInfo->P3d4, 0x53,
+ (unsigned char)(XGINew_GetReg1(pVBInfo->P3d4, 0x53) & 0xFD));
+ XGINew_SetReg1(pVBInfo->P3c4, 0x1F, (unsigned char)SR1F);
}
-#ifdef TC
-/* --------------------------------------------------------------------- */
-/* Function : INT1AReturnCode */
-/* Input : */
-/* Output : */
-/* Description : */
-/* --------------------------------------------------------------------- */
-int INT1AReturnCode( union REGS regs )
-{
- if ( regs.x.cflag )
- {
- /* printf( "Error to find pci device!\n" ) ; */
- return( 1 ) ;
- }
- switch(regs.h.ah)
- {
- case 0: return 0;
- break ;
- case 0x81:
- printf( "Function not support\n" ) ;
- break ;
- case 0x83:
- printf( "bad vendor id\n" ) ;
- break ;
- case 0x86:
- printf( "device not found\n" ) ;
- break ;
- case 0x87:
- printf( "bad register number\n" ) ;
- break ;
- case 0x88:
- printf( "set failed\n" ) ;
- break ;
- case 0x89:
- printf( "buffer too small" ) ;
- break ;
- default:
- break ;
- }
- return( 1 ) ;
-}
-/* --------------------------------------------------------------------- */
-/* Function : FindPCIIOBase */
-/* Input : */
-/* Output : */
-/* Description : */
-/* --------------------------------------------------------------------- */
-unsigned FindPCIIOBase( unsigned index , unsigned deviceid )
-{
- union REGS regs ;
-
- regs.h.ah = 0xb1 ; /* PCI_FUNCTION_ID */
- regs.h.al = 0x02 ; /* FIND_PCI_DEVICE */
- regs.x.cx = deviceid ;
- regs.x.dx = 0x1039 ;
- regs.x.si = index ; /* find n-th device */
-
- int86( 0x1A , &regs , &regs ) ;
-
- if ( INT1AReturnCode( regs ) != 0 )
- return( 0 ) ;
-
- /* regs.h.bh bus number */
- /* regs.h.bl device number */
- regs.h.ah = 0xb1 ; /* PCI_FUNCTION_ID */
- regs.h.al = 0x09 ; /* READ_CONFIG_WORD */
- regs.x.cx = deviceid ;
- regs.x.dx = 0x1039 ;
- regs.x.di = 0x18 ; /* register number */
- int86( 0x1A , &regs , &regs ) ;
-
- if ( INT1AReturnCode( regs ) != 0 )
- return( 0 ) ;
-
- return( regs.x.cx ) ;
-}
-
-#endif
-
-
-
-#ifdef TC
-/* --------------------------------------------------------------------- */
-/* Function : main */
-/* Input : */
-/* Output : */
-/* Description : */
-/* --------------------------------------------------------------------- */
-void main(int argc, char *argv[])
-{
- XGI_HW_DEVICE_INFO HwDeviceExtension ;
- USHORT temp ;
- USHORT ModeNo ;
-
- /* HwDeviceExtension.pjVirtualRomBase =(PUCHAR) MK_FP(0xC000,0); */
- /* HwDeviceExtension.pjVideoMemoryAddress = (PUCHAR)MK_FP(0xA000,0); */
-
-
- HwDeviceExtension.pjIOAddress = ( FindPCIIOBase( 0 ,0x6300 ) & 0xFF80 ) + 0x30 ;
- HwDeviceExtension.jChipType = XGI_340 ;
-
-
-
- /* HwDeviceExtension.pjIOAddress = ( FindPCIIOBase( 0 , 0x5315 ) & 0xFF80 ) + 0x30 ; */
-
- HwDeviceExtension.pjIOAddress = ( FindPCIIOBase( 0 , 0x330 ) & 0xFF80 ) + 0x30 ;
- HwDeviceExtension.jChipType = XGI_340 ;
-
-
- HwDeviceExtension.ujVBChipID = VB_CHIP_301 ;
- StrCpy(HwDeviceExtension.szVBIOSVer , "0.84" ) ;
- HwDeviceExtension.bSkipDramSizing = FALSE ;
- HwDeviceExtension.ulVideoMemorySize = 0 ;
-
- if ( argc == 2 )
- {
- ModeNo = atoi( argv[ 1 ] ) ;
- }
- else
- {
- ModeNo = 0x2e ;
- /* ModeNo = 0x37 ; 1024x768x 4bpp */
- /* ModeNo = 0x38 ; 1024x768x 8bpp */
- /* ModeNo = 0x4A ; 1024x768x 16bpp */
- /* ModeNo = 0x47 ; 800x600x 16bpp */
- }
-
- /* XGIInitNew( &HwDeviceExtension ) ; */
- XGISetModeNew( &HwDeviceExtension , ModeNo ) ;
-}
-#endif
/* --------------------------------------------------------------------- */
@@ -4688,7 +4429,7 @@ void main(int argc, char *argv[])
/* Output : */
/* Description : */
/* --------------------------------------------------------------------- */
-void XGI_WaitDisplay( PVB_DEVICE_INFO pVBInfo )
+void XGI_WaitDisplay(struct vb_device_info *pVBInfo)
{
while( !( XGINew_GetReg2( pVBInfo->P3da ) & 0x01 ) ) ;
@@ -4704,9 +4445,11 @@ void XGI_WaitDisplay( PVB_DEVICE_INFO pVBInfo )
/* Output : */
/* Description : */
/* --------------------------------------------------------------------- */
-BOOLEAN XGI_SetCRT2Group301( USHORT ModeNo , PXGI_HW_DEVICE_INFO HwDeviceExtension, PVB_DEVICE_INFO pVBInfo )
+unsigned char XGI_SetCRT2Group301(unsigned short ModeNo,
+ struct xgi_hw_device_info *HwDeviceExtension,
+ struct vb_device_info *pVBInfo)
{
- USHORT tempbx ,
+ unsigned short tempbx ,
ModeIdIndex ,
RefreshRateTableIndex ;
@@ -4739,7 +4482,7 @@ BOOLEAN XGI_SetCRT2Group301( USHORT ModeNo , PXGI_HW_DEVICE_INFO HwDeviceExtensi
/* Output : */
/* Description : */
/* --------------------------------------------------------------------- */
-void XGI_AutoThreshold( PVB_DEVICE_INFO pVBInfo )
+void XGI_AutoThreshold(struct vb_device_info *pVBInfo)
{
if ( !( pVBInfo->SetFlag & Win9xDOSMode ) )
XGINew_SetRegOR( pVBInfo->Part1Port , 0x01 , 0x40 ) ;
@@ -4752,9 +4495,9 @@ void XGI_AutoThreshold( PVB_DEVICE_INFO pVBInfo )
/* Output : */
/* Description : */
/* --------------------------------------------------------------------- */
-void XGI_SaveCRT2Info( USHORT ModeNo , PVB_DEVICE_INFO pVBInfo)
+void XGI_SaveCRT2Info(unsigned short ModeNo, struct vb_device_info *pVBInfo)
{
- USHORT temp1 ,
+ unsigned short temp1 ,
temp2 ;
XGINew_SetReg1( pVBInfo->P3d4 , 0x34 , ModeNo ) ; /* reserve CR34 for CRT1 Mode No */
@@ -4770,9 +4513,11 @@ void XGI_SaveCRT2Info( USHORT ModeNo , PVB_DEVICE_INFO pVBInfo)
/* Output : */
/* Description : */
/* --------------------------------------------------------------------- */
-void XGI_GetCRT2ResInfo( USHORT ModeNo , USHORT ModeIdIndex, PVB_DEVICE_INFO pVBInfo )
+void XGI_GetCRT2ResInfo(unsigned short ModeNo,
+ unsigned short ModeIdIndex,
+ struct vb_device_info *pVBInfo)
{
- USHORT xres ,
+ unsigned short xres ,
yres ,
modeflag ,
resindex ;
@@ -4867,7 +4612,7 @@ void XGI_GetCRT2ResInfo( USHORT ModeNo , USHORT ModeIdIndex, PVB_DEVICE_INFO pVB
/* Output : */
/* Description : */
/* --------------------------------------------------------------------- */
-BOOLEAN XGI_IsLCDDualLink( PVB_DEVICE_INFO pVBInfo )
+unsigned char XGI_IsLCDDualLink(struct vb_device_info *pVBInfo)
{
if ( ( ( ( pVBInfo->VBInfo & SetCRT2ToLCD ) | SetCRT2ToLCDA ) ) && ( pVBInfo->LCDInfo & SetLCDDualLink ) ) /* shampoo0129 */
@@ -4883,15 +4628,15 @@ BOOLEAN XGI_IsLCDDualLink( PVB_DEVICE_INFO pVBInfo )
/* Output : */
/* Description : */
/* --------------------------------------------------------------------- */
-void XGI_GetCRT2Data( USHORT ModeNo , USHORT ModeIdIndex , USHORT RefreshRateTableIndex, PVB_DEVICE_INFO pVBInfo )
+void XGI_GetCRT2Data(unsigned short ModeNo, unsigned short ModeIdIndex, unsigned short RefreshRateTableIndex, struct vb_device_info *pVBInfo)
{
- USHORT tempax = 0,
+ unsigned short tempax = 0,
tempbx ,
modeflag ,
resinfo ;
- XGI_LCDDataStruct *LCDPtr = NULL ;
- XGI_TVDataStruct *TVPtr = NULL ;
+ struct XGI_LCDDataStruct *LCDPtr = NULL ;
+ struct XGI_TVDataStruct *TVPtr = NULL ;
if ( ModeNo <= 0x13 )
{
@@ -4917,7 +4662,7 @@ void XGI_GetCRT2Data( USHORT ModeNo , USHORT ModeIdIndex , USHORT RefreshRateTa
if ( pVBInfo->VBInfo & ( SetCRT2ToLCD | SetCRT2ToLCDA ) )
{
- LCDPtr = (XGI_LCDDataStruct* )XGI_GetLcdPtr( tempbx, ModeNo , ModeIdIndex , RefreshRateTableIndex, pVBInfo ) ;
+ LCDPtr = (struct XGI_LCDDataStruct *)XGI_GetLcdPtr(tempbx, ModeNo, ModeIdIndex, RefreshRateTableIndex, pVBInfo);
pVBInfo->RVBHCMAX = LCDPtr->RVBHCMAX ;
pVBInfo->RVBHCFACT = LCDPtr->RVBHCFACT ;
@@ -5021,7 +4766,7 @@ void XGI_GetCRT2Data( USHORT ModeNo , USHORT ModeIdIndex , USHORT RefreshRateTa
if ( pVBInfo->VBInfo & ( SetCRT2ToTV ) )
{
tempbx = 4 ;
- TVPtr = ( XGI_TVDataStruct * )XGI_GetTVPtr( tempbx , ModeNo , ModeIdIndex , RefreshRateTableIndex, pVBInfo ) ;
+ TVPtr = (struct XGI_TVDataStruct *)XGI_GetTVPtr(tempbx, ModeNo, ModeIdIndex, RefreshRateTableIndex, pVBInfo);
pVBInfo->RVBHCMAX = TVPtr->RVBHCMAX ;
pVBInfo->RVBHCFACT = TVPtr->RVBHCFACT ;
@@ -5109,11 +4854,9 @@ void XGI_GetCRT2Data( USHORT ModeNo , USHORT ModeIdIndex , USHORT RefreshRateTa
/* Output : */
/* Description : */
/* --------------------------------------------------------------------- */
-void XGI_SetCRT2VCLK( USHORT ModeNo , USHORT ModeIdIndex , USHORT RefreshRateTableIndex, PVB_DEVICE_INFO pVBInfo )
+void XGI_SetCRT2VCLK(unsigned short ModeNo, unsigned short ModeIdIndex, unsigned short RefreshRateTableIndex, struct vb_device_info *pVBInfo)
{
- UCHAR di_0 ,
- di_1 ,
- tempal ;
+ unsigned char di_0, di_1, tempal;
tempal = XGI_GetVCLKPtr( RefreshRateTableIndex , ModeNo , ModeIdIndex, pVBInfo ) ;
XGI_GetVCLKLen( tempal, &di_0 , &di_1, pVBInfo ) ;
@@ -5146,9 +4889,10 @@ void XGI_SetCRT2VCLK( USHORT ModeNo , USHORT ModeIdIndex , USHORT RefreshRateTab
/* Output : al -> VCLK Index */
/* Description : */
/* --------------------------------------------------------------------- */
-void XGI_GetLCDVCLKPtr( UCHAR* di_0 , UCHAR *di_1, PVB_DEVICE_INFO pVBInfo )
+void XGI_GetLCDVCLKPtr(unsigned char *di_0, unsigned char *di_1,
+ struct vb_device_info *pVBInfo)
{
- USHORT index ;
+ unsigned short index ;
if ( pVBInfo->VBInfo & ( SetCRT2ToLCD | SetCRT2ToLCDA ) )
{
@@ -5182,17 +4926,16 @@ void XGI_GetLCDVCLKPtr( UCHAR* di_0 , UCHAR *di_1, PVB_DEVICE_INFO pVBInfo )
/* Output : */
/* Description : */
/* --------------------------------------------------------------------- */
-UCHAR XGI_GetVCLKPtr(USHORT RefreshRateTableIndex,USHORT ModeNo,USHORT ModeIdIndex, PVB_DEVICE_INFO pVBInfo)
+unsigned char XGI_GetVCLKPtr(unsigned short RefreshRateTableIndex,
+ unsigned short ModeNo, unsigned short ModeIdIndex,
+ struct vb_device_info *pVBInfo)
{
- USHORT index ,
+ unsigned short index ,
modeflag ;
-#ifndef LINUX_XF86
- USHORT tempbx ;
-#endif
-
- UCHAR tempal ;
- UCHAR *CHTVVCLKPtr = NULL ;
+ unsigned short tempbx ;
+ unsigned char tempal;
+ unsigned char *CHTVVCLKPtr = NULL;
if ( ModeNo <= 0x13 )
modeflag = pVBInfo->SModeIDTable[ ModeIdIndex ].St_ModeFlag ; /* si+St_ResInfo */
@@ -5344,7 +5087,7 @@ UCHAR XGI_GetVCLKPtr(USHORT RefreshRateTableIndex,USHORT ModeNo,USHORT ModeIdInd
}
- tempal = ( UCHAR )XGINew_GetReg2( ( pVBInfo->P3ca + 0x02 ) ) ;
+ tempal = (unsigned char)XGINew_GetReg2((pVBInfo->P3ca + 0x02));
tempal = tempal >> 2 ;
tempal &= 0x03 ;
@@ -5365,19 +5108,20 @@ UCHAR XGI_GetVCLKPtr(USHORT RefreshRateTableIndex,USHORT ModeNo,USHORT ModeIdInd
/* Output : */
/* Description : */
/* --------------------------------------------------------------------- */
-void XGI_GetVCLKLen(UCHAR tempal,UCHAR* di_0,UCHAR* di_1, PVB_DEVICE_INFO pVBInfo)
+void XGI_GetVCLKLen(unsigned char tempal, unsigned char *di_0,
+ unsigned char *di_1, struct vb_device_info *pVBInfo)
{
if ( pVBInfo->IF_DEF_CH7007 == 1 ) /* [Billy] 2007/05/16 */
{
/* VideoDebugPrint((0, "XGI_GetVCLKLen: pVBInfo->IF_DEF_CH7007==1\n")); */
- *di_0 = ( UCHAR )XGI_CH7007VCLKData[ tempal ].SR2B ;
- *di_1 = ( UCHAR )XGI_CH7007VCLKData[ tempal ].SR2C ;
+ *di_0 = (unsigned char)XGI_CH7007VCLKData[tempal].SR2B;
+ *di_1 = (unsigned char)XGI_CH7007VCLKData[tempal].SR2C;
}
else if ( pVBInfo->VBType & ( VB_XGI301 | VB_XGI301B | VB_XGI302B | VB_XGI301LV | VB_XGI302LV | VB_XGI301C ) )
{
if ( ( !( pVBInfo->VBInfo & SetCRT2ToLCDA ) ) && ( pVBInfo->SetFlag & ProgrammingCRT2 ) )
{
- *di_0 = ( UCHAR )XGI_VBVCLKData[ tempal ].SR2B ;
+ *di_0 = (unsigned char)XGI_VBVCLKData[tempal].SR2B;
*di_1 = XGI_VBVCLKData[ tempal ].SR2C ;
}
}
@@ -5395,11 +5139,14 @@ void XGI_GetVCLKLen(UCHAR tempal,UCHAR* di_0,UCHAR* di_1, PVB_DEVICE_INFO pVBInf
/* Output : */
/* Description : */
/* --------------------------------------------------------------------- */
-void XGI_SetCRT2Offset( USHORT ModeNo ,
- USHORT ModeIdIndex , USHORT RefreshRateTableIndex , PXGI_HW_DEVICE_INFO HwDeviceExtension, PVB_DEVICE_INFO pVBInfo )
+void XGI_SetCRT2Offset(unsigned short ModeNo,
+ unsigned short ModeIdIndex,
+ unsigned short RefreshRateTableIndex,
+ struct xgi_hw_device_info *HwDeviceExtension,
+ struct vb_device_info *pVBInfo)
{
- USHORT offset ;
- UCHAR temp ;
+ unsigned short offset ;
+ unsigned char temp;
if ( pVBInfo->VBInfo & SetInSlaveMode )
{
@@ -5407,12 +5154,12 @@ void XGI_SetCRT2Offset( USHORT ModeNo ,
}
offset = XGI_GetOffset( ModeNo , ModeIdIndex , RefreshRateTableIndex , HwDeviceExtension, pVBInfo ) ;
- temp = ( UCHAR )( offset & 0xFF ) ;
+ temp = (unsigned char)(offset & 0xFF);
XGINew_SetReg1( pVBInfo->Part1Port , 0x07 , temp ) ;
- temp =( UCHAR)( ( offset & 0xFF00 ) >> 8 ) ;
- XGINew_SetReg1( pVBInfo->Part1Port , 0x09 , temp ) ;
- temp =( UCHAR )( ( ( offset >> 3 ) & 0xFF ) + 1 ) ;
- XGINew_SetReg1( pVBInfo->Part1Port , 0x03 , temp ) ;
+ temp = (unsigned char)((offset & 0xFF00) >> 8);
+ XGINew_SetReg1(pVBInfo->Part1Port , 0x09 , temp);
+ temp = (unsigned char)(((offset >> 3) & 0xFF) + 1) ;
+ XGINew_SetReg1(pVBInfo->Part1Port, 0x03, temp);
}
@@ -5422,9 +5169,9 @@ void XGI_SetCRT2Offset( USHORT ModeNo ,
/* Output : */
/* Description : */
/* --------------------------------------------------------------------- */
-USHORT XGI_GetOffset(USHORT ModeNo,USHORT ModeIdIndex,USHORT RefreshRateTableIndex,PXGI_HW_DEVICE_INFO HwDeviceExtension,PVB_DEVICE_INFO pVBInfo)
+unsigned short XGI_GetOffset(unsigned short ModeNo, unsigned short ModeIdIndex, unsigned short RefreshRateTableIndex, struct xgi_hw_device_info *HwDeviceExtension, struct vb_device_info *pVBInfo)
{
- USHORT temp ,
+ unsigned short temp ,
colordepth ,
modeinfo ,
index ,
@@ -5471,7 +5218,7 @@ USHORT XGI_GetOffset(USHORT ModeNo,USHORT ModeIdIndex,USHORT RefreshRateTableInd
/* Output : */
/* Description : */
/* --------------------------------------------------------------------- */
-void XGI_SetCRT2FIFO( PVB_DEVICE_INFO pVBInfo)
+void XGI_SetCRT2FIFO(struct vb_device_info *pVBInfo)
{
XGINew_SetReg1( pVBInfo->Part1Port , 0x01 , 0x3B ) ; /* threshold high ,disable auto threshold */
XGINew_SetRegANDOR( pVBInfo->Part1Port , 0x02 , ~( 0x3F ) , 0x04 ) ; /* threshold low default 04h */
@@ -5484,10 +5231,12 @@ void XGI_SetCRT2FIFO( PVB_DEVICE_INFO pVBInfo)
/* Output : */
/* Description : */
/* --------------------------------------------------------------------- */
-void XGI_PreSetGroup1(USHORT ModeNo , USHORT ModeIdIndex ,PXGI_HW_DEVICE_INFO HwDeviceExtension,
- USHORT RefreshRateTableIndex, PVB_DEVICE_INFO pVBInfo )
+void XGI_PreSetGroup1(unsigned short ModeNo, unsigned short ModeIdIndex,
+ struct xgi_hw_device_info *HwDeviceExtension,
+ unsigned short RefreshRateTableIndex,
+ struct vb_device_info *pVBInfo)
{
- USHORT tempcx = 0 ,
+ unsigned short tempcx = 0 ,
CRT1Index = 0 ,
resinfo = 0 ;
@@ -5518,10 +5267,12 @@ void XGI_PreSetGroup1(USHORT ModeNo , USHORT ModeIdIndex ,PXGI_HW_DEVICE_INFO Hw
/* Output : */
/* Description : */
/* --------------------------------------------------------------------- */
-void XGI_SetGroup1( USHORT ModeNo , USHORT ModeIdIndex ,
- PXGI_HW_DEVICE_INFO HwDeviceExtension , USHORT RefreshRateTableIndex, PVB_DEVICE_INFO pVBInfo )
+void XGI_SetGroup1(unsigned short ModeNo, unsigned short ModeIdIndex,
+ struct xgi_hw_device_info *HwDeviceExtension,
+ unsigned short RefreshRateTableIndex,
+ struct vb_device_info *pVBInfo)
{
- USHORT temp = 0 ,
+ unsigned short temp = 0 ,
tempax = 0 ,
tempbx = 0 ,
tempcx = 0 ,
@@ -5694,10 +5445,12 @@ void XGI_SetGroup1( USHORT ModeNo , USHORT ModeIdIndex ,
/* Output : */
/* Description : */
/* --------------------------------------------------------------------- */
-void XGI_SetLockRegs( USHORT ModeNo , USHORT ModeIdIndex ,
- PXGI_HW_DEVICE_INFO HwDeviceExtension , USHORT RefreshRateTableIndex, PVB_DEVICE_INFO pVBInfo )
+void XGI_SetLockRegs(unsigned short ModeNo, unsigned short ModeIdIndex,
+ struct xgi_hw_device_info *HwDeviceExtension,
+ unsigned short RefreshRateTableIndex,
+ struct vb_device_info *pVBInfo)
{
- USHORT push1 ,
+ unsigned short push1 ,
push2 ,
tempax ,
tempbx = 0 ,
@@ -6141,10 +5894,10 @@ void XGI_SetLockRegs( USHORT ModeNo , USHORT ModeIdIndex ,
/* Output : */
/* Description : */
/* --------------------------------------------------------------------- */
-void XGI_SetGroup2( USHORT ModeNo, USHORT ModeIdIndex, USHORT RefreshRateTableIndex,
- PXGI_HW_DEVICE_INFO HwDeviceExtension, PVB_DEVICE_INFO pVBInfo )
+void XGI_SetGroup2(unsigned short ModeNo, unsigned short ModeIdIndex, unsigned short RefreshRateTableIndex,
+ struct xgi_hw_device_info *HwDeviceExtension, struct vb_device_info *pVBInfo)
{
- USHORT i ,
+ unsigned short i ,
j ,
tempax ,
tempbx ,
@@ -6155,9 +5908,9 @@ void XGI_SetGroup2( USHORT ModeNo, USHORT ModeIdIndex, USHORT RefreshRateTableIn
modeflag ,
resinfo ,
crt2crtc ;
- UCHAR *TimingPoint ;
+ unsigned char *TimingPoint ;
- ULONG longtemp ,
+ unsigned long longtemp ,
tempeax ,
tempebx ,
temp2 ,
@@ -6266,7 +6019,7 @@ void XGI_SetGroup2( USHORT ModeNo, USHORT ModeIdIndex, USHORT RefreshRateTableIn
tempax = ( tempax & 0x00FF ) | ( ( tempax & 0x00FF ) << 8 ) ;
push1 = tempax ;
temp = ( tempax & 0xFF00 ) >> 8 ;
- temp += ( USHORT )TimingPoint[ 0 ] ;
+ temp += (unsigned short)TimingPoint[0];
if ( pVBInfo->VBType & ( VB_XGI301B | VB_XGI302B | VB_XGI301LV | VB_XGI302LV | VB_XGI301C ) )
{
@@ -6543,7 +6296,7 @@ void XGI_SetGroup2( USHORT ModeNo, USHORT ModeIdIndex, USHORT RefreshRateTableIn
tempeax += 1 ;
}
- tempax = ( USHORT )tempeax ;
+ tempax = (unsigned short)tempeax;
/* 301b */
if ( pVBInfo->VBType & ( VB_XGI301B | VB_XGI302B | VB_XGI301LV | VB_XGI302LV | VB_XGI301C ) )
@@ -6553,8 +6306,8 @@ void XGI_SetGroup2( USHORT ModeNo, USHORT ModeIdIndex, USHORT RefreshRateTableIn
/* end 301b */
tempbx = push1 ;
- tempbx =( USHORT )( ( ( tempeax & 0x0000FF00 ) & 0x1F00 ) | ( tempbx & 0x00FF ) ) ;
- tempax =( USHORT )( ( ( tempeax & 0x000000FF ) << 8 ) | ( tempax & 0x00FF ) ) ;
+ tempbx = (unsigned short)(((tempeax & 0x0000FF00) & 0x1F00) | (tempbx & 0x00FF));
+ tempax = (unsigned short)(((tempeax & 0x000000FF) << 8) | (tempax & 0x00FF));
temp = ( tempax & 0xFF00 ) >> 8 ;
}
else
@@ -6607,7 +6360,7 @@ void XGI_SetGroup2( USHORT ModeNo, USHORT ModeIdIndex, USHORT RefreshRateTableIn
XGINew_SetReg1( pVBInfo->Part2Port , 0x4d , temp ) ;
temp=XGINew_GetReg1( pVBInfo->Part2Port , 0x43 ) ; /* 301b change */
- XGINew_SetReg1( pVBInfo->Part2Port , 0x43 , ( USHORT )( temp - 3 ) ) ;
+ XGINew_SetReg1( pVBInfo->Part2Port , 0x43, (unsigned short)( temp - 3 ) ) ;
if ( !( pVBInfo->TVInfo & ( SetYPbPrMode525p | SetYPbPrMode750p ) ) )
{
@@ -6631,7 +6384,7 @@ void XGI_SetGroup2( USHORT ModeNo, USHORT ModeIdIndex, USHORT RefreshRateTableIn
if ( pVBInfo->TVInfo & SetPALMTV )
{
- tempax = ( UCHAR )XGINew_GetReg1( pVBInfo->Part2Port , 0x01 ) ;
+ tempax = (unsigned char)XGINew_GetReg1(pVBInfo->Part2Port, 0x01);
tempax-- ;
XGINew_SetRegAND( pVBInfo->Part2Port , 0x01 , tempax ) ;
@@ -6660,9 +6413,9 @@ void XGI_SetGroup2( USHORT ModeNo, USHORT ModeIdIndex, USHORT RefreshRateTableIn
/* Output : */
/* Description : */
/* --------------------------------------------------------------------- */
-void XGI_SetLCDRegs(USHORT ModeNo,USHORT ModeIdIndex, PXGI_HW_DEVICE_INFO HwDeviceExtension,USHORT RefreshRateTableIndex, PVB_DEVICE_INFO pVBInfo)
+void XGI_SetLCDRegs(unsigned short ModeNo, unsigned short ModeIdIndex, struct xgi_hw_device_info *HwDeviceExtension, unsigned short RefreshRateTableIndex, struct vb_device_info *pVBInfo)
{
- USHORT push1 ,
+ unsigned short push1 ,
push2 ,
pushbx ,
tempax ,
@@ -6676,7 +6429,7 @@ void XGI_SetLCDRegs(USHORT ModeNo,USHORT ModeIdIndex, PXGI_HW_DEVICE_INFO HwDev
modeflag ,
CRT1Index ;
- XGI_LCDDesStruct *LCDBDesPtr = NULL ;
+ struct XGI_LCDDesStruct *LCDBDesPtr = NULL ;
if ( ModeNo <= 0x13 )
@@ -6746,7 +6499,7 @@ void XGI_SetLCDRegs(USHORT ModeNo,USHORT ModeIdIndex, PXGI_HW_DEVICE_INFO HwDev
/* Customized LCDB Des no add */
tempbx = 5 ;
- LCDBDesPtr = ( XGI_LCDDesStruct * )XGI_GetLcdPtr( tempbx , ModeNo , ModeIdIndex , RefreshRateTableIndex, pVBInfo ) ;
+ LCDBDesPtr = (struct XGI_LCDDesStruct *)XGI_GetLcdPtr(tempbx, ModeNo, ModeIdIndex, RefreshRateTableIndex, pVBInfo);
tempah = pVBInfo->LCDResInfo ;
tempah &= PanelResInfo ;
@@ -6914,13 +6667,14 @@ void XGI_SetLCDRegs(USHORT ModeNo,USHORT ModeIdIndex, PXGI_HW_DEVICE_INFO HwDev
/* Output : di -> Tap4 Reg. Setting Pointer */
/* Description : */
/* --------------------------------------------------------------------- */
-XGI301C_Tap4TimingStruct* XGI_GetTap4Ptr(USHORT tempcx, PVB_DEVICE_INFO pVBInfo)
+struct XGI301C_Tap4TimingStruct *XGI_GetTap4Ptr(unsigned short tempcx,
+ struct vb_device_info *pVBInfo)
{
- USHORT tempax ,
+ unsigned short tempax ,
tempbx ,
i ;
- XGI301C_Tap4TimingStruct *Tap4TimingPtr ;
+ struct XGI301C_Tap4TimingStruct *Tap4TimingPtr ;
if ( tempcx == 0 )
{
@@ -6974,12 +6728,12 @@ XGI301C_Tap4TimingStruct* XGI_GetTap4Ptr(USHORT tempcx, PVB_DEVICE_INFO pVBInfo)
/* Output : */
/* Description : */
/* --------------------------------------------------------------------- */
-void XGI_SetTap4Regs( PVB_DEVICE_INFO pVBInfo)
+void XGI_SetTap4Regs(struct vb_device_info *pVBInfo)
{
- USHORT i ,
+ unsigned short i ,
j ;
- XGI301C_Tap4TimingStruct *Tap4TimingPtr ;
+ struct XGI301C_Tap4TimingStruct *Tap4TimingPtr ;
if ( !( pVBInfo->VBType & VB_XGI301C ) )
return ;
@@ -7012,11 +6766,11 @@ void XGI_SetTap4Regs( PVB_DEVICE_INFO pVBInfo)
/* Output : */
/* Description : */
/* --------------------------------------------------------------------- */
-void XGI_SetGroup3(USHORT ModeNo,USHORT ModeIdIndex, PVB_DEVICE_INFO pVBInfo)
+void XGI_SetGroup3(unsigned short ModeNo, unsigned short ModeIdIndex, struct vb_device_info *pVBInfo)
{
- USHORT i;
- UCHAR *tempdi;
- USHORT modeflag;
+ unsigned short i;
+ unsigned char *tempdi;
+ unsigned short modeflag;
if(ModeNo<=0x13)
{
@@ -7099,16 +6853,16 @@ void XGI_SetGroup3(USHORT ModeNo,USHORT ModeIdIndex, PVB_DEVICE_INFO pVBInfo)
/* Output : */
/* Description : */
/* --------------------------------------------------------------------- */
-void XGI_SetGroup4(USHORT ModeNo,USHORT ModeIdIndex,USHORT RefreshRateTableIndex,PXGI_HW_DEVICE_INFO HwDeviceExtension, PVB_DEVICE_INFO pVBInfo)
+void XGI_SetGroup4(unsigned short ModeNo, unsigned short ModeIdIndex, unsigned short RefreshRateTableIndex, struct xgi_hw_device_info *HwDeviceExtension, struct vb_device_info *pVBInfo)
{
- USHORT tempax ,
+ unsigned short tempax ,
tempcx ,
tempbx ,
modeflag ,
temp ,
temp2 ;
- ULONG tempebx ,
+ unsigned long tempebx ,
tempeax ,
templong ;
@@ -7230,12 +6984,12 @@ void XGI_SetGroup4(USHORT ModeNo,USHORT ModeIdIndex,USHORT RefreshRateTableIndex
}
- temp = ( USHORT )( tempebx & 0x000000FF ) ;
+ temp = (unsigned short)(tempebx & 0x000000FF);
XGINew_SetReg1( pVBInfo->Part4Port , 0x1B , temp ) ;
- temp = ( USHORT )( ( tempebx & 0x0000FF00 ) >> 8 ) ;
+ temp = (unsigned short)((tempebx & 0x0000FF00) >> 8);
XGINew_SetReg1( pVBInfo->Part4Port , 0x1A , temp ) ;
- tempbx = ( USHORT )( tempebx >> 16 ) ;
+ tempbx = (unsigned short)(tempebx >> 16);
temp = tempbx & 0x00FF ;
temp = temp << 4 ;
temp |= ( ( tempcx & 0xFF00 ) >> 8 ) ;
@@ -7350,9 +7104,9 @@ void XGI_SetGroup4(USHORT ModeNo,USHORT ModeIdIndex,USHORT RefreshRateTableIndex
/* Output : */
/* Description : */
/* --------------------------------------------------------------------- */
-void XGI_SetGroup5( USHORT ModeNo , USHORT ModeIdIndex , PVB_DEVICE_INFO pVBInfo)
+void XGI_SetGroup5(unsigned short ModeNo, unsigned short ModeIdIndex, struct vb_device_info *pVBInfo)
{
- USHORT Pindex ,
+ unsigned short Pindex ,
Pdata ;
Pindex = pVBInfo->Part5Port ;
@@ -7375,9 +7129,13 @@ void XGI_SetGroup5( USHORT ModeNo , USHORT ModeIdIndex , PVB_DEVICE_INFO pVBInfo
/* Output : */
/* Description : */
/* --------------------------------------------------------------------- */
-void* XGI_GetLcdPtr( USHORT BX , USHORT ModeNo , USHORT ModeIdIndex , USHORT RefreshRateTableIndex, PVB_DEVICE_INFO pVBInfo )
+void *XGI_GetLcdPtr(unsigned short BX,
+ unsigned short ModeNo,
+ unsigned short ModeIdIndex,
+ unsigned short RefreshRateTableIndex,
+ struct vb_device_info *pVBInfo)
{
- USHORT i ,
+ unsigned short i ,
tempdx ,
tempcx ,
tempbx ,
@@ -7385,7 +7143,7 @@ void* XGI_GetLcdPtr( USHORT BX , USHORT ModeNo , USHORT ModeIdIndex , USHORT Ref
modeflag ,
table ;
- XGI330_LCDDataTablStruct *tempdi = 0 ;
+ struct XGI330_LCDDataTablStruct *tempdi = 0 ;
tempbx = BX;
@@ -7877,10 +7635,13 @@ void* XGI_GetLcdPtr( USHORT BX , USHORT ModeNo , USHORT ModeIdIndex , USHORT Ref
/* Output : */
/* Description : */
/* --------------------------------------------------------------------- */
-void* XGI_GetTVPtr (USHORT BX,USHORT ModeNo,USHORT ModeIdIndex,USHORT RefreshRateTableIndex, PVB_DEVICE_INFO pVBInfo )
+void *XGI_GetTVPtr(unsigned short BX, unsigned short ModeNo,
+ unsigned short ModeIdIndex,
+ unsigned short RefreshRateTableIndex,
+ struct vb_device_info *pVBInfo)
{
- USHORT i , tempdx , tempbx , tempal , modeflag , table ;
- XGI330_TVDataTablStruct *tempdi = 0 ;
+ unsigned short i , tempdx , tempbx , tempal , modeflag , table ;
+ struct XGI330_TVDataTablStruct *tempdi = 0 ;
tempbx = BX ;
@@ -7955,53 +7716,9 @@ void* XGI_GetTVPtr (USHORT BX,USHORT ModeNo,USHORT ModeIdIndex,USHORT RefreshRat
if ( table == 0x00 ) /* 07/05/22 */
{
-#ifdef WIN2000
- if ( pVBInfo->IF_DEF_CH7007 == 1 )
- {
- switch( tempdi[ i ].DATAPTR )
- {
- case 0:
- return &CH7007TVCRT1UNTSC_H[ tempal ] ;
- break ;
- case 1:
- return &CH7007TVCRT1ONTSC_H[ tempal ] ;
- break ;
- case 2:
- return &CH7007TVCRT1UPAL_H[ tempal ] ;
- break ;
- case 3:
- return &CH7007TVCRT1OPAL_H[ tempal ] ;
- break ;
- default:
- break ;
- }
- }
-#endif
}
else if ( table == 0x01 )
{
-#ifdef WIN2000
- if ( pVBInfo->IF_DEF_CH7007 == 1 )
- {
- switch( tempdi[ i ].DATAPTR )
- {
- case 0:
- return &CH7007TVCRT1UNTSC_V[ tempal ] ;
- break ;
- case 1:
- return &CH7007TVCRT1ONTSC_V[ tempal ] ;
- break ;
- case 2:
- return &CH7007TVCRT1UPAL_V[ tempal ] ;
- break ;
- case 3:
- return &CH7007TVCRT1OPAL_V[ tempal ] ;
- break ;
- default:
- break ;
- }
- }
-#endif
}
else if ( table == 0x04 )
{
@@ -8075,49 +7792,6 @@ void* XGI_GetTVPtr (USHORT BX,USHORT ModeNo,USHORT ModeIdIndex,USHORT RefreshRat
}
else if( table == 0x06 )
{
-#ifdef WIN2000
- if ( pVBInfo->IF_DEF_CH7007 == 1 )
- {
- /* VideoDebugPrint((0, "XGI_GetTVPtr: pVBInfo->IF_DEF_CH7007==1\n")); */
- switch( tempdi[ i ].DATAPTR )
- {
- case 0:
- return &CH7007TVReg_UNTSC[ tempal ] ;
- break ;
- case 1:
- return &CH7007TVReg_ONTSC[ tempal ] ;
- break ;
- case 2:
- return &CH7007TVReg_UPAL[ tempal ] ;
- break ;
- case 3:
- return &CH7007TVReg_OPAL[ tempal ] ;
- break ;
- default:
- break ;
- }
- }
- else
- {
- switch( tempdi[ i ].DATAPTR )
- {
- case 0:
- return &XGI_CHTVRegUNTSC[ tempal ] ;
- break ;
- case 1:
- return &XGI_CHTVRegONTSC[ tempal ] ;
- break ;
- case 2:
- return &XGI_CHTVRegUPAL[ tempal ] ;
- break ;
- case 3:
- return &XGI_CHTVRegOPAL[ tempal ] ;
- break ;
- default:
- break ;
- }
- }
-#endif
}
return( 0 ) ;
}
@@ -8126,18 +7800,18 @@ void* XGI_GetTVPtr (USHORT BX,USHORT ModeNo,USHORT ModeIdIndex,USHORT RefreshRat
/* --------------------------------------------------------------------- */
/* Function : XGI_BacklightByDrv */
/* Input : */
-/* Output : TRUE -> Skip backlight control */
+/* Output : 1 -> Skip backlight control */
/* Description : */
/* --------------------------------------------------------------------- */
-BOOLEAN XGI_BacklightByDrv( PVB_DEVICE_INFO pVBInfo )
+unsigned char XGI_BacklightByDrv(struct vb_device_info *pVBInfo)
{
- UCHAR tempah ;
+ unsigned char tempah ;
- tempah = ( UCHAR )XGINew_GetReg1( pVBInfo->P3d4 , 0x3A ) ;
- if ( tempah & BacklightControlBit )
- return TRUE ;
+ tempah = (unsigned char)XGINew_GetReg1(pVBInfo->P3d4, 0x3A) ;
+ if (tempah & BacklightControlBit)
+ return 1;
else
- return FALSE ;
+ return 0;
}
@@ -8148,7 +7822,7 @@ BOOLEAN XGI_BacklightByDrv( PVB_DEVICE_INFO pVBInfo )
/* Description : Turn off VDD & Backlight : Fire disable procedure */
/* --------------------------------------------------------------------- */
/*
-void XGI_FirePWDDisable( PVB_DEVICE_INFO pVBInfo )
+void XGI_FirePWDDisable(struct vb_device_info *pVBInfo)
{
XGINew_SetRegANDOR( pVBInfo->Part1Port , 0x26 , 0x00 , 0xFC ) ;
}
@@ -8160,7 +7834,7 @@ void XGI_FirePWDDisable( PVB_DEVICE_INFO pVBInfo )
/* Output : */
/* Description : Turn on VDD & Backlight : Fire enable procedure */
/* --------------------------------------------------------------------- */
-void XGI_FirePWDEnable(PVB_DEVICE_INFO pVBInfo )
+void XGI_FirePWDEnable(struct vb_device_info *pVBInfo)
{
XGINew_SetRegANDOR( pVBInfo->Part1Port , 0x26 , 0x03 , 0xFC ) ;
}
@@ -8172,7 +7846,7 @@ void XGI_FirePWDEnable(PVB_DEVICE_INFO pVBInfo )
/* Output : */
/* Description : */
/* --------------------------------------------------------------------- */
-void XGI_EnableGatingCRT(PXGI_HW_DEVICE_INFO HwDeviceExtension, PVB_DEVICE_INFO pVBInfo)
+void XGI_EnableGatingCRT(struct xgi_hw_device_info *HwDeviceExtension, struct vb_device_info *pVBInfo)
{
XGINew_SetRegANDOR( pVBInfo->P3d4 , 0x63 , 0xBF , 0x40 ) ;
}
@@ -8184,7 +7858,7 @@ void XGI_EnableGatingCRT(PXGI_HW_DEVICE_INFO HwDeviceExtension, PVB_DEVICE_INFO
/* Output : */
/* Description : */
/* --------------------------------------------------------------------- */
-void XGI_DisableGatingCRT(PXGI_HW_DEVICE_INFO HwDeviceExtension, PVB_DEVICE_INFO pVBInfo)
+void XGI_DisableGatingCRT(struct xgi_hw_device_info *HwDeviceExtension, struct vb_device_info *pVBInfo)
{
XGINew_SetRegANDOR( pVBInfo->P3d4 , 0x63 , 0xBF , 0x00 ) ;
@@ -8201,9 +7875,9 @@ void XGI_DisableGatingCRT(PXGI_HW_DEVICE_INFO HwDeviceExtension, PVB_DEVICE_INFO
/* : bl : 3 ; T3 : the duration between CPL off and signal off */
/* : bl : 4 ; T4 : the duration signal off and Vdd off */
/* --------------------------------------------------------------------- */
-void XGI_SetPanelDelay(USHORT tempbl, PVB_DEVICE_INFO pVBInfo)
+void XGI_SetPanelDelay(unsigned short tempbl, struct vb_device_info *pVBInfo)
{
- USHORT index ;
+ unsigned short index ;
index = XGI_GetLCDCapPtr(pVBInfo) ;
@@ -8231,7 +7905,7 @@ void XGI_SetPanelDelay(USHORT tempbl, PVB_DEVICE_INFO pVBInfo)
/* = 1011b = 0Bh ; Backlight off, Power on */
/* = 1111b = 0Fh ; Backlight off, Power off */
/* --------------------------------------------------------------------- */
-void XGI_SetPanelPower(USHORT tempah,USHORT tempbl, PVB_DEVICE_INFO pVBInfo)
+void XGI_SetPanelPower(unsigned short tempah, unsigned short tempbl, struct vb_device_info *pVBInfo)
{
if ( pVBInfo->VBType & ( VB_XGI301LV | VB_XGI302LV | VB_XGI301C ) )
XGINew_SetRegANDOR( pVBInfo->Part4Port , 0x26 , tempbl , tempah ) ;
@@ -8239,10 +7913,10 @@ void XGI_SetPanelPower(USHORT tempah,USHORT tempbl, PVB_DEVICE_INFO pVBInfo)
XGINew_SetRegANDOR( pVBInfo->P3c4 , 0x11 , tempbl , tempah ) ;
}
-UCHAR XG21GPIODataTransfer(UCHAR ujDate)
+unsigned char XG21GPIODataTransfer(unsigned char ujDate)
{
- UCHAR ujRet = 0;
- UCHAR i = 0;
+ unsigned char ujRet = 0;
+ unsigned char i = 0;
for (i=0; i<8; i++)
{
@@ -8260,9 +7934,9 @@ UCHAR XG21GPIODataTransfer(UCHAR ujDate)
/* bl[1] : LVDS backlight */
/* bl[0] : LVDS VDD */
/*----------------------------------------------------------------------------*/
-UCHAR XGI_XG21GetPSCValue(PVB_DEVICE_INFO pVBInfo)
+unsigned char XGI_XG21GetPSCValue(struct vb_device_info *pVBInfo)
{
- UCHAR CR4A,temp;
+ unsigned char CR4A, temp;
CR4A = XGINew_GetReg1( pVBInfo->P3d4 , 0x4A ) ;
XGINew_SetRegAND( pVBInfo->P3d4 , 0x4A , ~0x23 ) ; /* enable GPIO write */
@@ -8281,9 +7955,9 @@ UCHAR XGI_XG21GetPSCValue(PVB_DEVICE_INFO pVBInfo)
/* bl[1] : LVDS backlight */
/* bl[0] : LVDS VDD */
/*----------------------------------------------------------------------------*/
-UCHAR XGI_XG27GetPSCValue(PVB_DEVICE_INFO pVBInfo)
+unsigned char XGI_XG27GetPSCValue(struct vb_device_info *pVBInfo)
{
- UCHAR CR4A,CRB4,temp;
+ unsigned char CR4A, CRB4, temp;
CR4A = XGINew_GetReg1( pVBInfo->P3d4 , 0x4A ) ;
XGINew_SetRegAND( pVBInfo->P3d4 , 0x4A , ~0x0C ) ; /* enable GPIO write */
@@ -8306,9 +7980,9 @@ UCHAR XGI_XG27GetPSCValue(PVB_DEVICE_INFO pVBInfo)
/* 000010b : clear bit 1, to set bit1 */
/* 000001b : clear bit 0, to set bit0 */
/*----------------------------------------------------------------------------*/
-void XGI_XG21BLSignalVDD(USHORT tempbh,USHORT tempbl, PVB_DEVICE_INFO pVBInfo)
+void XGI_XG21BLSignalVDD(unsigned short tempbh, unsigned short tempbl, struct vb_device_info *pVBInfo)
{
- UCHAR CR4A,temp;
+ unsigned char CR4A, temp;
CR4A = XGINew_GetReg1( pVBInfo->P3d4 , 0x4A ) ;
tempbh &= 0x23;
@@ -8331,10 +8005,10 @@ void XGI_XG21BLSignalVDD(USHORT tempbh,USHORT tempbl, PVB_DEVICE_INFO pVBInfo)
XGINew_SetReg1( pVBInfo->P3d4 , 0x48 , temp ) ;
}
-void XGI_XG27BLSignalVDD(USHORT tempbh,USHORT tempbl, PVB_DEVICE_INFO pVBInfo)
+void XGI_XG27BLSignalVDD(unsigned short tempbh, unsigned short tempbl, struct vb_device_info *pVBInfo)
{
- UCHAR CR4A,temp;
- USHORT tempbh0,tempbl0;
+ unsigned char CR4A, temp;
+ unsigned short tempbh0, tempbl0;
tempbh0 = tempbh;
tempbl0 = tempbl;
@@ -8362,15 +8036,13 @@ void XGI_XG27BLSignalVDD(USHORT tempbh,USHORT tempbl, PVB_DEVICE_INFO pVBInfo)
}
/* --------------------------------------------------------------------- */
-USHORT XGI_GetLVDSOEMTableIndex(PVB_DEVICE_INFO pVBInfo)
+unsigned short XGI_GetLVDSOEMTableIndex(struct vb_device_info *pVBInfo)
{
- USHORT index ;
+ unsigned short index ;
index = XGINew_GetReg1( pVBInfo->P3d4 , 0x36 ) ;
- if (index<sizeof(XGI21_LCDCapList)/sizeof(XGI21_LVDSCapStruct))
- {
- return index;
- }
+ if (index < sizeof(XGI21_LCDCapList)/sizeof(struct XGI21_LVDSCapStruct))
+ return index;
return 0;
}
@@ -8384,9 +8056,9 @@ USHORT XGI_GetLVDSOEMTableIndex(PVB_DEVICE_INFO pVBInfo)
/* : bl : 3 ; T3 : the duration between CPL off and signal off */
/* : bl : 4 ; T4 : the duration signal off and Vdd off */
/* --------------------------------------------------------------------- */
-void XGI_XG21SetPanelDelay(USHORT tempbl, PVB_DEVICE_INFO pVBInfo)
+void XGI_XG21SetPanelDelay(unsigned short tempbl, struct vb_device_info *pVBInfo)
{
- USHORT index ;
+ unsigned short index ;
index = XGI_GetLVDSOEMTableIndex( pVBInfo );
if ( tempbl == 1 )
@@ -8402,9 +8074,11 @@ void XGI_XG21SetPanelDelay(USHORT tempbl, PVB_DEVICE_INFO pVBInfo)
XGINew_LCD_Wait_Time( pVBInfo->XG21_LVDSCapList[ index ].PSC_S4, pVBInfo ) ;
}
-BOOLEAN XGI_XG21CheckLVDSMode(USHORT ModeNo,USHORT ModeIdIndex, PVB_DEVICE_INFO pVBInfo )
+unsigned char XGI_XG21CheckLVDSMode(unsigned short ModeNo,
+ unsigned short ModeIdIndex,
+ struct vb_device_info *pVBInfo)
{
- USHORT xres ,
+ unsigned short xres ,
yres ,
colordepth ,
modeflag ,
@@ -8445,10 +8119,10 @@ BOOLEAN XGI_XG21CheckLVDSMode(USHORT ModeNo,USHORT ModeIdIndex, PVB_DEVICE_INFO
lvdstableindex = XGI_GetLVDSOEMTableIndex( pVBInfo );
if ( xres > (pVBInfo->XG21_LVDSCapList[lvdstableindex].LVDSHDE) )
- return FALSE;
+ return 0;
if ( yres > (pVBInfo->XG21_LVDSCapList[lvdstableindex].LVDSVDE) )
- return FALSE;
+ return 0;
if ( ModeNo > 0x13 )
{
@@ -8456,18 +8130,17 @@ BOOLEAN XGI_XG21CheckLVDSMode(USHORT ModeNo,USHORT ModeIdIndex, PVB_DEVICE_INFO
( yres != (pVBInfo->XG21_LVDSCapList[lvdstableindex].LVDSVDE)) )
{
colordepth = XGI_GetColorDepth( ModeNo , ModeIdIndex, pVBInfo ) ;
- if ( colordepth > 2 )
- {
- return FALSE;
- }
+ if (colordepth > 2)
+ return 0;
+
}
}
- return TRUE;
+ return 1;
}
-void XGI_SetXG21FPBits(PVB_DEVICE_INFO pVBInfo)
+void XGI_SetXG21FPBits(struct vb_device_info *pVBInfo)
{
- UCHAR temp;
+ unsigned char temp;
temp = XGINew_GetReg1( pVBInfo->P3d4 , 0x37 ) ; /* D[0] 1: 18bit */
temp = ( temp & 1 ) << 6;
@@ -8476,9 +8149,9 @@ void XGI_SetXG21FPBits(PVB_DEVICE_INFO pVBInfo)
}
-void XGI_SetXG27FPBits(PVB_DEVICE_INFO pVBInfo)
+void XGI_SetXG27FPBits(struct vb_device_info *pVBInfo)
{
- UCHAR temp;
+ unsigned char temp;
temp = XGINew_GetReg1( pVBInfo->P3d4 , 0x37 ) ; /* D[1:0] 01: 18bit, 00: dual 12, 10: single 24 */
temp = ( temp & 3 ) << 6;
@@ -8487,27 +8160,28 @@ void XGI_SetXG27FPBits(PVB_DEVICE_INFO pVBInfo)
}
-void XGI_SetXG21LVDSPara(USHORT ModeNo,USHORT ModeIdIndex, PVB_DEVICE_INFO pVBInfo )
+void XGI_SetXG21LVDSPara(unsigned short ModeNo, unsigned short ModeIdIndex,
+ struct vb_device_info *pVBInfo)
{
- UCHAR temp,Miscdata;
- USHORT xres ,
+ unsigned char temp, Miscdata;
+ unsigned short xres ,
yres ,
modeflag ,
resindex ,
lvdstableindex ;
- USHORT LVDSHT,LVDSHBS,LVDSHRS,LVDSHRE,LVDSHBE;
- USHORT LVDSVT,LVDSVBS,LVDSVRS,LVDSVRE,LVDSVBE;
- USHORT value;
+ unsigned short LVDSHT,LVDSHBS,LVDSHRS,LVDSHRE,LVDSHBE;
+ unsigned short LVDSVT,LVDSVBS,LVDSVRS,LVDSVRE,LVDSVBE;
+ unsigned short value;
lvdstableindex = XGI_GetLVDSOEMTableIndex( pVBInfo );
- temp = (UCHAR) ( ( pVBInfo->XG21_LVDSCapList[lvdstableindex].LVDS_Capability & (LCDPolarity << 8 ) ) >> 8 );
+ temp = (unsigned char) ((pVBInfo->XG21_LVDSCapList[lvdstableindex].LVDS_Capability & (LCDPolarity << 8)) >> 8);
temp &= LCDPolarity;
- Miscdata =(UCHAR) XGINew_GetReg2(pVBInfo->P3cc) ;
+ Miscdata = (unsigned char) XGINew_GetReg2(pVBInfo->P3cc) ;
XGINew_SetReg3( pVBInfo->P3c2 , (Miscdata & 0x3F) | temp ) ;
- temp = (UCHAR) ( pVBInfo->XG21_LVDSCapList[lvdstableindex].LVDS_Capability & LCDPolarity ) ;
+ temp = (unsigned char) (pVBInfo->XG21_LVDSCapList[lvdstableindex].LVDS_Capability & LCDPolarity) ;
XGINew_SetRegANDOR( pVBInfo->P3c4 , 0x35 , ~0x80 , temp&0x80 ) ; /* SR35[7] FP VSync polarity */
XGINew_SetRegANDOR( pVBInfo->P3c4 , 0x30 , ~0x20 , (temp&0x40)>>1 ) ; /* SR30[5] FP HSync polarity */
@@ -8563,7 +8237,7 @@ void XGI_SetXG21LVDSPara(USHORT ModeNo,USHORT ModeIdIndex, PVB_DEVICE_INFO pVBIn
LVDSVBE = LVDSVBS + LVDSVT - pVBInfo->XG21_LVDSCapList[lvdstableindex].LVDSVDE ;
- temp = ( UCHAR )XGINew_GetReg1( pVBInfo->P3d4 , 0x11 ) ;
+ temp = (unsigned char)XGINew_GetReg1(pVBInfo->P3d4, 0x11) ;
XGINew_SetReg1( pVBInfo->P3d4 , 0x11 , temp & 0x7f ) ; /* Unlock CRTC */
if (!( modeflag & Charx8Dot ))
@@ -8670,26 +8344,27 @@ void XGI_SetXG21LVDSPara(USHORT ModeNo,USHORT ModeIdIndex, PVB_DEVICE_INFO pVBIn
}
/* no shadow case */
-void XGI_SetXG27LVDSPara(USHORT ModeNo,USHORT ModeIdIndex, PVB_DEVICE_INFO pVBInfo )
+void XGI_SetXG27LVDSPara(unsigned short ModeNo, unsigned short ModeIdIndex,
+ struct vb_device_info *pVBInfo)
{
- UCHAR temp,Miscdata;
- USHORT xres ,
+ unsigned char temp, Miscdata;
+ unsigned short xres ,
yres ,
modeflag ,
resindex ,
lvdstableindex ;
- USHORT LVDSHT,LVDSHBS,LVDSHRS,LVDSHRE,LVDSHBE;
- USHORT LVDSVT,LVDSVBS,LVDSVRS,LVDSVRE,LVDSVBE;
- USHORT value;
+ unsigned short LVDSHT,LVDSHBS,LVDSHRS,LVDSHRE,LVDSHBE;
+ unsigned short LVDSVT,LVDSVBS,LVDSVRS,LVDSVRE,LVDSVBE;
+ unsigned short value;
lvdstableindex = XGI_GetLVDSOEMTableIndex( pVBInfo );
- temp = (UCHAR) ( ( pVBInfo->XG21_LVDSCapList[lvdstableindex].LVDS_Capability & (LCDPolarity << 8 ) ) >> 8 );
+ temp = (unsigned char) ((pVBInfo->XG21_LVDSCapList[lvdstableindex].LVDS_Capability & (LCDPolarity << 8)) >> 8);
temp &= LCDPolarity;
- Miscdata =(UCHAR) XGINew_GetReg2(pVBInfo->P3cc) ;
+ Miscdata = (unsigned char) XGINew_GetReg2(pVBInfo->P3cc);
XGINew_SetReg3( pVBInfo->P3c2 , (Miscdata & 0x3F) | temp ) ;
- temp = (UCHAR) ( pVBInfo->XG21_LVDSCapList[lvdstableindex].LVDS_Capability & LCDPolarity ) ;
+ temp = (unsigned char) (pVBInfo->XG21_LVDSCapList[lvdstableindex].LVDS_Capability & LCDPolarity) ;
XGINew_SetRegANDOR( pVBInfo->P3c4 , 0x35 , ~0x80 , temp&0x80 ) ; /* SR35[7] FP VSync polarity */
XGINew_SetRegANDOR( pVBInfo->P3c4 , 0x30 , ~0x20 , (temp&0x40)>>1 ) ; /* SR30[5] FP HSync polarity */
@@ -8745,7 +8420,7 @@ void XGI_SetXG27LVDSPara(USHORT ModeNo,USHORT ModeIdIndex, PVB_DEVICE_INFO pVBIn
LVDSVBE = LVDSVBS + LVDSVT - pVBInfo->XG21_LVDSCapList[lvdstableindex].LVDSVDE ;
- temp = ( UCHAR )XGINew_GetReg1( pVBInfo->P3d4 , 0x11 ) ;
+ temp = (unsigned char)XGINew_GetReg1(pVBInfo->P3d4, 0x11) ;
XGINew_SetReg1( pVBInfo->P3d4 , 0x11 , temp & 0x7f ) ; /* Unlock CRTC */
if (!( modeflag & Charx8Dot ))
@@ -8853,21 +8528,21 @@ void XGI_SetXG27LVDSPara(USHORT ModeNo,USHORT ModeIdIndex, PVB_DEVICE_INFO pVBIn
/* --------------------------------------------------------------------- */
/* Function : XGI_IsLCDON */
/* Input : */
-/* Output : FALSE : Skip PSC Control */
-/* TRUE: Disable PSC */
+/* Output : 0 : Skip PSC Control */
+/* 1: Disable PSC */
/* Description : */
/* --------------------------------------------------------------------- */
-BOOLEAN XGI_IsLCDON(PVB_DEVICE_INFO pVBInfo)
+unsigned char XGI_IsLCDON(struct vb_device_info *pVBInfo)
{
- USHORT tempax ;
+ unsigned short tempax ;
tempax = pVBInfo->VBInfo ;
if ( tempax & SetCRT2ToDualEdge )
- return FALSE ;
+ return 0;
else if ( tempax & ( DisableCRT2Display | SwitchToCRT2 | SetSimuScanMode ) )
- return TRUE ;
+ return 1;
- return FALSE ;
+ return 0;
}
@@ -8877,9 +8552,9 @@ BOOLEAN XGI_IsLCDON(PVB_DEVICE_INFO pVBInfo)
/* Output : */
/* Description : */
/* --------------------------------------------------------------------- */
-void XGI_EnablePWD( PVB_DEVICE_INFO pVBInfo )
+void XGI_EnablePWD(struct vb_device_info *pVBInfo)
{
- USHORT index ,
+ unsigned short index ,
temp ;
index = XGI_GetLCDCapPtr(pVBInfo) ;
@@ -8899,7 +8574,7 @@ void XGI_EnablePWD( PVB_DEVICE_INFO pVBInfo )
/* Output : */
/* Description : */
/* --------------------------------------------------------------------- */
-void XGI_DisablePWD( PVB_DEVICE_INFO pVBInfo )
+void XGI_DisablePWD(struct vb_device_info *pVBInfo)
{
XGINew_SetRegAND( pVBInfo->Part4Port , 0x27 , 0x7F ) ; /* disable PWD */
}
@@ -8908,30 +8583,30 @@ void XGI_DisablePWD( PVB_DEVICE_INFO pVBInfo )
/* --------------------------------------------------------------------- */
/* Function : XGI_DisableChISLCD */
/* Input : */
-/* Output : FALSE -> Not LCD Mode */
+/* Output : 0 -> Not LCD Mode */
/* Description : */
/* --------------------------------------------------------------------- */
-BOOLEAN XGI_DisableChISLCD(PVB_DEVICE_INFO pVBInfo)
+unsigned char XGI_DisableChISLCD(struct vb_device_info *pVBInfo)
{
- USHORT tempbx ,
+ unsigned short tempbx ,
tempah ;
tempbx = pVBInfo->SetFlag & ( DisableChA | DisableChB ) ;
- tempah = ~( ( USHORT )XGINew_GetReg1( pVBInfo->Part1Port , 0x2E ) ) ;
+ tempah = ~((unsigned short) XGINew_GetReg1(pVBInfo->Part1Port, 0x2E));
if ( tempbx & ( EnableChA | DisableChA ) )
{
if ( !( tempah & 0x08 ) ) /* Chk LCDA Mode */
- return FALSE ;
+ return 0 ;
}
if ( !( tempbx & ( EnableChB | DisableChB ) ) )
- return FALSE ;
+ return 0;
if ( tempah & 0x01 ) /* Chk LCDB Mode */
- return TRUE ;
+ return 1;
- return FALSE ;
+ return 0;
}
@@ -8941,28 +8616,28 @@ BOOLEAN XGI_DisableChISLCD(PVB_DEVICE_INFO pVBInfo)
/* Output : 0 -> Not LCD mode */
/* Description : */
/* --------------------------------------------------------------------- */
-BOOLEAN XGI_EnableChISLCD(PVB_DEVICE_INFO pVBInfo)
+unsigned char XGI_EnableChISLCD(struct vb_device_info *pVBInfo)
{
- USHORT tempbx ,
+ unsigned short tempbx ,
tempah ;
tempbx = pVBInfo->SetFlag & ( EnableChA | EnableChB ) ;
- tempah = ~( ( USHORT )XGINew_GetReg1( pVBInfo->Part1Port , 0x2E ) ) ;
+ tempah = ~( (unsigned short)XGINew_GetReg1( pVBInfo->Part1Port , 0x2E ) ) ;
if ( tempbx & ( EnableChA | DisableChA ) )
{
if ( !( tempah & 0x08 ) ) /* Chk LCDA Mode */
- return FALSE ;
+ return 0;
}
if ( !( tempbx & ( EnableChB | DisableChB ) ) )
- return FALSE ;
+ return 0;
if ( tempah & 0x01 ) /* Chk LCDB Mode */
- return TRUE ;
+ return 1;
- return FALSE ;
+ return 0;
}
@@ -8972,9 +8647,9 @@ BOOLEAN XGI_EnableChISLCD(PVB_DEVICE_INFO pVBInfo)
/* Output : */
/* Description : */
/* --------------------------------------------------------------------- */
-USHORT XGI_GetLCDCapPtr( PVB_DEVICE_INFO pVBInfo )
+unsigned short XGI_GetLCDCapPtr(struct vb_device_info *pVBInfo)
{
- UCHAR tempal ,
+ unsigned char tempal ,
tempah ,
tempbl ,
i ;
@@ -9011,9 +8686,9 @@ USHORT XGI_GetLCDCapPtr( PVB_DEVICE_INFO pVBInfo )
/* Output : */
/* Description : */
/* --------------------------------------------------------------------- */
-USHORT XGI_GetLCDCapPtr1( PVB_DEVICE_INFO pVBInfo )
+unsigned short XGI_GetLCDCapPtr1(struct vb_device_info *pVBInfo)
{
- USHORT tempah ,
+ unsigned short tempah ,
tempal ,
tempbl ,
i ;
@@ -9056,9 +8731,10 @@ USHORT XGI_GetLCDCapPtr1( PVB_DEVICE_INFO pVBInfo )
/* Output : */
/* Description : */
/* --------------------------------------------------------------------- */
-void XGI_GetLCDSync( USHORT* HSyncWidth , USHORT* VSyncWidth, PVB_DEVICE_INFO pVBInfo )
+void XGI_GetLCDSync(unsigned short *HSyncWidth , unsigned short *VSyncWidth,
+ struct vb_device_info *pVBInfo)
{
- USHORT Index ;
+ unsigned short Index ;
Index = XGI_GetLCDCapPtr(pVBInfo) ;
*HSyncWidth = pVBInfo->LCDCapList[ Index ].LCD_HSyncWidth ;
@@ -9075,9 +8751,9 @@ void XGI_GetLCDSync( USHORT* HSyncWidth , USHORT* VSyncWidth, PVB_DEVICE_INFO pV
/* Output : */
/* Description : */
/* --------------------------------------------------------------------- */
-void XGI_EnableBridge( PXGI_HW_DEVICE_INFO HwDeviceExtension , PVB_DEVICE_INFO pVBInfo)
+void XGI_EnableBridge(struct xgi_hw_device_info *HwDeviceExtension, struct vb_device_info *pVBInfo)
{
- USHORT tempbl ,
+ unsigned short tempbl ,
tempah ;
if ( pVBInfo->SetFlag == Win9xDOSMode )
@@ -9146,7 +8822,7 @@ void XGI_EnableBridge( PXGI_HW_DEVICE_INFO HwDeviceExtension , PVB_DEVICE_INFO p
{
if ( ( pVBInfo->SetFlag & EnableChB ) || ( pVBInfo->VBInfo & ( SetCRT2ToLCD | SetCRT2ToTV | SetCRT2ToRAMDAC ) ) )
{
- tempah = ( UCHAR )XGINew_GetReg1( pVBInfo->P3c4 , 0x32 ) ;
+ tempah = (unsigned char)XGINew_GetReg1(pVBInfo->P3c4, 0x32);
tempah &= 0xDF;
if ( pVBInfo->VBInfo & SetInSlaveMode )
{
@@ -9156,8 +8832,7 @@ void XGI_EnableBridge( PXGI_HW_DEVICE_INFO HwDeviceExtension , PVB_DEVICE_INFO p
XGINew_SetReg1( pVBInfo->P3c4 , 0x32 , tempah ) ;
XGINew_SetRegOR( pVBInfo->P3c4 , 0x1E , 0x20 ) ;
-
- tempah = ( UCHAR )XGINew_GetReg1( pVBInfo->Part1Port , 0x2E ) ;
+ tempah = (unsigned char)XGINew_GetReg1(pVBInfo->Part1Port, 0x2E);
if ( !( tempah & 0x80 ) )
XGINew_SetRegOR( pVBInfo->Part1Port , 0x2E , 0x80 ) ; /* BVBDOENABLE = 1 */
@@ -9238,7 +8913,7 @@ void XGI_EnableBridge( PXGI_HW_DEVICE_INFO HwDeviceExtension , PVB_DEVICE_INFO p
- tempah = ( UCHAR )XGINew_GetReg1( pVBInfo->Part1Port , 0x2E ) ;
+ tempah = (unsigned char)XGINew_GetReg1(pVBInfo->Part1Port, 0x2E);
if ( !( tempah & 0x80 ) )
XGINew_SetRegOR( pVBInfo->Part1Port , 0x2E , 0x80 ) ; /* BVBDOENABLE = 1 */
@@ -9289,9 +8964,9 @@ void XGI_EnableBridge( PXGI_HW_DEVICE_INFO HwDeviceExtension , PVB_DEVICE_INFO p
/* Output : */
/* Description : */
/* --------------------------------------------------------------------- */
-void XGI_DisableBridge(PXGI_HW_DEVICE_INFO HwDeviceExtension, PVB_DEVICE_INFO pVBInfo)
+void XGI_DisableBridge(struct xgi_hw_device_info *HwDeviceExtension, struct vb_device_info *pVBInfo)
{
- USHORT tempax ,
+ unsigned short tempax ,
tempbx ,
tempah = 0 ,
tempbl = 0 ;
@@ -9470,9 +9145,9 @@ void XGI_DisableBridge(PXGI_HW_DEVICE_INFO HwDeviceExtension, PVB_DEVICE_INFO pV
/* A : Ext750p */
/* B : St750p */
/* --------------------------------------------------------------------- */
-USHORT XGI_GetTVPtrIndex( PVB_DEVICE_INFO pVBInfo )
+unsigned short XGI_GetTVPtrIndex(struct vb_device_info *pVBInfo)
{
- USHORT tempbx = 0 ;
+ unsigned short tempbx = 0 ;
if ( pVBInfo->TVInfo & SetPALTV )
tempbx = 2 ;
@@ -9497,7 +9172,7 @@ USHORT XGI_GetTVPtrIndex( PVB_DEVICE_INFO pVBInfo )
/* Output : */
/* Description : Customized Param. for 301 */
/* --------------------------------------------------------------------- */
-void XGI_OEM310Setting( USHORT ModeNo , USHORT ModeIdIndex, PVB_DEVICE_INFO pVBInfo)
+void XGI_OEM310Setting(unsigned short ModeNo, unsigned short ModeIdIndex, struct vb_device_info *pVBInfo)
{
if ( pVBInfo->SetFlag & Win9xDOSMode )
return ;
@@ -9527,11 +9202,11 @@ void XGI_OEM310Setting( USHORT ModeNo , USHORT ModeIdIndex, PVB_DEVICE_INFO pVBI
/* Output : */
/* Description : */
/* --------------------------------------------------------------------- */
-void XGI_SetDelayComp( PVB_DEVICE_INFO pVBInfo )
+void XGI_SetDelayComp(struct vb_device_info *pVBInfo)
{
- USHORT index ;
+ unsigned short index ;
- UCHAR tempah ,
+ unsigned char tempah ,
tempbl ,
tempbh ;
@@ -9605,9 +9280,9 @@ void XGI_SetDelayComp( PVB_DEVICE_INFO pVBInfo )
/* Output : */
/* Description : */
/* --------------------------------------------------------------------- */
-void XGI_SetLCDCap( PVB_DEVICE_INFO pVBInfo )
+void XGI_SetLCDCap(struct vb_device_info *pVBInfo)
{
- USHORT tempcx ;
+ unsigned short tempcx ;
tempcx = pVBInfo->LCDCapList[ XGI_GetLCDCapPtr(pVBInfo) ].LCD_Capability ;
@@ -9616,10 +9291,12 @@ void XGI_SetLCDCap( PVB_DEVICE_INFO pVBInfo )
if ( pVBInfo->VBType & ( VB_XGI301LV | VB_XGI302LV | VB_XGI301C ) )
{ /* 301LV/302LV only */
/* Set 301LV Capability */
- XGINew_SetReg1( pVBInfo->Part4Port , 0x24 , ( UCHAR )( tempcx & 0x1F ) ) ;
+ XGINew_SetReg1(pVBInfo->Part4Port, 0x24, (unsigned char)(tempcx & 0x1F));
}
/* VB Driving */
- XGINew_SetRegANDOR( pVBInfo->Part4Port , 0x0D , ~( ( EnableVBCLKDRVLOW | EnablePLLSPLOW ) >> 8 ) , ( USHORT )( ( tempcx & ( EnableVBCLKDRVLOW | EnablePLLSPLOW ) ) >> 8 ) ) ;
+ XGINew_SetRegANDOR(pVBInfo->Part4Port, 0x0D,
+ ~((EnableVBCLKDRVLOW | EnablePLLSPLOW) >> 8),
+ (unsigned short)((tempcx & (EnableVBCLKDRVLOW | EnablePLLSPLOW)) >> 8));
}
if ( pVBInfo->VBType & ( VB_XGI301B | VB_XGI302B | VB_XGI301LV | VB_XGI302LV | VB_XGI301C ) )
@@ -9646,32 +9323,34 @@ void XGI_SetLCDCap( PVB_DEVICE_INFO pVBInfo )
/* Output : */
/* Description : */
/* --------------------------------------------------------------------- */
-void XGI_SetLCDCap_A(USHORT tempcx,PVB_DEVICE_INFO pVBInfo)
+void XGI_SetLCDCap_A(unsigned short tempcx, struct vb_device_info *pVBInfo)
{
- USHORT temp ;
+ unsigned short temp ;
temp = XGINew_GetReg1( pVBInfo->P3d4 , 0x37 ) ;
if ( temp & LCDRGB18Bit )
{
- XGINew_SetRegANDOR( pVBInfo->Part1Port , 0x19 , 0x0F , ( USHORT )( 0x20 | ( tempcx & 0x00C0 ) ) ) ; /* Enable Dither */
+ XGINew_SetRegANDOR(pVBInfo->Part1Port, 0x19, 0x0F,
+ (unsigned short)(0x20 | (tempcx & 0x00C0))); /* Enable Dither */
XGINew_SetRegANDOR( pVBInfo->Part1Port , 0x1A , 0x7F , 0x80 ) ;
}
else
{
- XGINew_SetRegANDOR( pVBInfo->Part1Port , 0x19 , 0x0F , ( USHORT )( 0x30 | ( tempcx & 0x00C0 ) ) ) ;
+ XGINew_SetRegANDOR(pVBInfo->Part1Port, 0x19, 0x0F,
+ (unsigned short)(0x30 | (tempcx & 0x00C0)));
XGINew_SetRegANDOR( pVBInfo->Part1Port , 0x1A , 0x7F , 0x00 ) ;
}
/*
if ( tempcx & EnableLCD24bpp ) // 24bits
{
- XGINew_SetRegANDOR(pVBInfo->Part1Port,0x19, 0x0F,(USHORT)(0x30|(tempcx&0x00C0)) );
+ XGINew_SetRegANDOR(pVBInfo->Part1Port,0x19, 0x0F,(unsigned short)(0x30|(tempcx&0x00C0)) );
XGINew_SetRegANDOR(pVBInfo->Part1Port,0x1A,0x7F,0x00);
}
else
{
- XGINew_SetRegANDOR(pVBInfo->Part1Port,0x19, 0x0F,(USHORT)(0x20|(tempcx&0x00C0)) );//Enable Dither
+ XGINew_SetRegANDOR(pVBInfo->Part1Port,0x19, 0x0F,(unsigned short)(0x20|(tempcx&0x00C0)) ); // Enable Dither
XGINew_SetRegANDOR(pVBInfo->Part1Port,0x1A,0x7F,0x80);
}
*/
@@ -9684,12 +9363,14 @@ void XGI_SetLCDCap_A(USHORT tempcx,PVB_DEVICE_INFO pVBInfo)
/* Output : */
/* Description : */
/* --------------------------------------------------------------------- */
-void XGI_SetLCDCap_B(USHORT tempcx,PVB_DEVICE_INFO pVBInfo)
+void XGI_SetLCDCap_B(unsigned short tempcx, struct vb_device_info *pVBInfo)
{
if ( tempcx & EnableLCD24bpp ) /* 24bits */
- XGINew_SetRegANDOR( pVBInfo->Part2Port , 0x1A , 0xE0 , ( USHORT )( ( ( tempcx & 0x00ff ) >> 6 ) | 0x0c ) ) ;
+ XGINew_SetRegANDOR(pVBInfo->Part2Port, 0x1A, 0xE0,
+ (unsigned short)(((tempcx & 0x00ff) >> 6) | 0x0c));
else
- XGINew_SetRegANDOR( pVBInfo->Part2Port , 0x1A , 0xE0 , ( USHORT )( ( ( tempcx & 0x00ff ) >> 6 ) | 0x18 ) ) ; /* Enable Dither */
+ XGINew_SetRegANDOR(pVBInfo->Part2Port, 0x1A, 0xE0,
+ (unsigned short)(((tempcx & 0x00ff) >> 6) | 0x18)); /* Enable Dither */
}
@@ -9699,9 +9380,9 @@ void XGI_SetLCDCap_B(USHORT tempcx,PVB_DEVICE_INFO pVBInfo)
/* Output : */
/* Description : */
/* --------------------------------------------------------------------- */
-void SetSpectrum( PVB_DEVICE_INFO pVBInfo )
+void SetSpectrum(struct vb_device_info *pVBInfo)
{
- USHORT index ;
+ unsigned short index ;
index = XGI_GetLCDCapPtr(pVBInfo) ;
@@ -9725,12 +9406,13 @@ void SetSpectrum( PVB_DEVICE_INFO pVBInfo )
/* Output : */
/* Description : Set TV Customized Param. */
/* --------------------------------------------------------------------- */
-void XGI_SetAntiFlicker( USHORT ModeNo , USHORT ModeIdIndex, PVB_DEVICE_INFO pVBInfo )
+void XGI_SetAntiFlicker(unsigned short ModeNo, unsigned short ModeIdIndex,
+ struct vb_device_info *pVBInfo)
{
- USHORT tempbx ,
+ unsigned short tempbx ,
index ;
- UCHAR tempah ;
+ unsigned char tempah ;
if (pVBInfo->TVInfo & ( SetYPbPrMode525p | SetYPbPrMode750p ) )
return ;
@@ -9761,12 +9443,12 @@ void XGI_SetAntiFlicker( USHORT ModeNo , USHORT ModeIdIndex, PVB_DEVICE_INFO pVB
/* Output : */
/* Description : */
/* --------------------------------------------------------------------- */
-void XGI_SetEdgeEnhance( USHORT ModeNo , USHORT ModeIdIndex , PVB_DEVICE_INFO pVBInfo)
+void XGI_SetEdgeEnhance(unsigned short ModeNo, unsigned short ModeIdIndex, struct vb_device_info *pVBInfo)
{
- USHORT tempbx ,
+ unsigned short tempbx ,
index ;
- UCHAR tempah ;
+ unsigned char tempah ;
tempbx = XGI_GetTVPtrIndex(pVBInfo ) ;
@@ -9795,22 +9477,26 @@ void XGI_SetEdgeEnhance( USHORT ModeNo , USHORT ModeIdIndex , PVB_DEVICE_INFO pV
/* Output : */
/* Description : */
/* --------------------------------------------------------------------- */
-void XGI_SetPhaseIncr( PVB_DEVICE_INFO pVBInfo )
+void XGI_SetPhaseIncr(struct vb_device_info *pVBInfo)
{
- USHORT tempbx ;
+ unsigned short tempbx ;
- UCHAR tempcl ,
+ unsigned char tempcl ,
tempch ;
- ULONG tempData ;
+ unsigned long tempData ;
XGI_GetTVPtrIndex2( &tempbx , &tempcl , &tempch, pVBInfo ) ; /* bx, cl, ch */
tempData = TVPhaseList[ tempbx ] ;
- XGINew_SetReg1( pVBInfo->Part2Port , 0x31 , ( USHORT )( tempData & 0x000000FF ) ) ;
- XGINew_SetReg1( pVBInfo->Part2Port , 0x32 , ( USHORT )( ( tempData & 0x0000FF00 ) >> 8 ) ) ;
- XGINew_SetReg1( pVBInfo->Part2Port , 0x33 , ( USHORT )( ( tempData & 0x00FF0000 ) >> 16 ) ) ;
- XGINew_SetReg1( pVBInfo->Part2Port , 0x34 , ( USHORT )( ( tempData & 0xFF000000 ) >> 24 ) ) ;
+ XGINew_SetReg1(pVBInfo->Part2Port, 0x31,
+ (unsigned short)(tempData & 0x000000FF));
+ XGINew_SetReg1(pVBInfo->Part2Port, 0x32,
+ (unsigned short)((tempData & 0x0000FF00) >> 8));
+ XGINew_SetReg1(pVBInfo->Part2Port, 0x33,
+ (unsigned short)((tempData & 0x00FF0000) >> 16));
+ XGINew_SetReg1(pVBInfo->Part2Port, 0x34,
+ (unsigned short)((tempData & 0xFF000000) >> 24));
}
@@ -9820,12 +9506,13 @@ void XGI_SetPhaseIncr( PVB_DEVICE_INFO pVBInfo )
/* Output : */
/* Description : */
/* --------------------------------------------------------------------- */
-void XGI_SetYFilter( USHORT ModeNo , USHORT ModeIdIndex, PVB_DEVICE_INFO pVBInfo)
+void XGI_SetYFilter(unsigned short ModeNo, unsigned short ModeIdIndex,
+ struct vb_device_info *pVBInfo)
{
- USHORT tempbx ,
+ unsigned short tempbx ,
index ;
- UCHAR tempcl ,
+ unsigned char tempcl ,
tempch ,
tempal ,
*filterPtr ;
@@ -9924,7 +9611,8 @@ void XGI_SetYFilter( USHORT ModeNo , USHORT ModeIdIndex, PVB_DEVICE_INFO pVBInfo
/* 1 : 301B/302B/301LV/302LV */
/* Description : */
/* --------------------------------------------------------------------- */
-void XGI_GetTVPtrIndex2(USHORT* tempbx,UCHAR* tempcl,UCHAR* tempch, PVB_DEVICE_INFO pVBInfo)
+void XGI_GetTVPtrIndex2(unsigned short *tempbx, unsigned char *tempcl,
+ unsigned char *tempch, struct vb_device_info *pVBInfo)
{
*tempbx = 0 ;
*tempcl = 0 ;
@@ -9966,12 +9654,14 @@ void XGI_GetTVPtrIndex2(USHORT* tempbx,UCHAR* tempcl,UCHAR* tempch, PVB_DEVICE_I
/* Output : */
/* Description : Origin code for crt2group */
/* --------------------------------------------------------------------- */
-void XGI_SetCRT2ModeRegs(USHORT ModeNo,PXGI_HW_DEVICE_INFO HwDeviceExtension, PVB_DEVICE_INFO pVBInfo)
+void XGI_SetCRT2ModeRegs(unsigned short ModeNo,
+ struct xgi_hw_device_info *HwDeviceExtension,
+ struct vb_device_info *pVBInfo)
{
- USHORT tempbl ;
- SHORT tempcl ;
+ unsigned short tempbl ;
+ short tempcl ;
- UCHAR tempah ;
+ unsigned char tempah ;
/* XGINew_SetReg1( pVBInfo->Part1Port , 0x03 , 0x00 ) ; // fix write part1 index 0 BTDRAM bit Bug */
tempah=0;
@@ -10195,9 +9885,9 @@ void XGI_SetCRT2ModeRegs(USHORT ModeNo,PXGI_HW_DEVICE_INFO HwDeviceExtension, PV
/* Output : */
/* Description : */
/* --------------------------------------------------------------------- */
-void XGI_CloseCRTC( PXGI_HW_DEVICE_INFO HwDeviceExtension, PVB_DEVICE_INFO pVBInfo )
+void XGI_CloseCRTC(struct xgi_hw_device_info *HwDeviceExtension, struct vb_device_info *pVBInfo)
{
- USHORT tempbx ;
+ unsigned short tempbx ;
tempbx = 0 ;
@@ -10214,9 +9904,9 @@ void XGI_CloseCRTC( PXGI_HW_DEVICE_INFO HwDeviceExtension, PVB_DEVICE_INFO pVBIn
/* Output : */
/* Description : */
/* --------------------------------------------------------------------- */
-void XGI_OpenCRTC( PXGI_HW_DEVICE_INFO HwDeviceExtension, PVB_DEVICE_INFO pVBInfo )
+void XGI_OpenCRTC(struct xgi_hw_device_info *HwDeviceExtension, struct vb_device_info *pVBInfo)
{
- USHORT tempbx ;
+ unsigned short tempbx ;
tempbx = 0 ;
@@ -10230,9 +9920,9 @@ void XGI_OpenCRTC( PXGI_HW_DEVICE_INFO HwDeviceExtension, PVB_DEVICE_INFO pVBInf
/* Output : */
/* Description : */
/* --------------------------------------------------------------------- */
-void XGI_GetRAMDAC2DATA(USHORT ModeNo , USHORT ModeIdIndex , USHORT RefreshRateTableIndex, PVB_DEVICE_INFO pVBInfo )
+void XGI_GetRAMDAC2DATA(unsigned short ModeNo, unsigned short ModeIdIndex, unsigned short RefreshRateTableIndex, struct vb_device_info *pVBInfo)
{
- USHORT tempax ,
+ unsigned short tempax ,
tempbx ,
temp1 ,
temp2 ,
@@ -10257,15 +9947,15 @@ void XGI_GetRAMDAC2DATA(USHORT ModeNo , USHORT ModeIdIndex , USHORT RefreshRateT
modeflag = pVBInfo->EModeIDTable[ ModeIdIndex ].Ext_ModeFlag ;
CRT1Index = pVBInfo->RefIndex[ RefreshRateTableIndex ].Ext_CRT1CRTC ;
CRT1Index &= IndexMask ;
- temp1 = ( USHORT )pVBInfo->XGINEWUB_CRT1Table[ CRT1Index ].CR[ 0 ] ;
- temp2 = ( USHORT )pVBInfo->XGINEWUB_CRT1Table[ CRT1Index ].CR[ 5 ] ;
+ temp1 = (unsigned short)pVBInfo->XGINEWUB_CRT1Table[CRT1Index].CR[0];
+ temp2 = (unsigned short)pVBInfo->XGINEWUB_CRT1Table[CRT1Index].CR[5];
tempax = ( temp1 & 0xFF ) | ( ( temp2 & 0x03 ) << 8 ) ;
- tempbx = ( USHORT )pVBInfo->XGINEWUB_CRT1Table[ CRT1Index ].CR[ 8 ] ;
- tempcx = ( USHORT )pVBInfo->XGINEWUB_CRT1Table[ CRT1Index ].CR[ 14 ] << 8 ;
+ tempbx = (unsigned short)pVBInfo->XGINEWUB_CRT1Table[CRT1Index].CR[8];
+ tempcx = (unsigned short)pVBInfo->XGINEWUB_CRT1Table[CRT1Index].CR[14] << 8;
tempcx &= 0x0100 ;
tempcx = tempcx << 2 ;
tempbx |= tempcx;
- temp1 = ( USHORT )pVBInfo->XGINEWUB_CRT1Table[ CRT1Index ].CR[ 9 ] ;
+ temp1 = (unsigned short)pVBInfo->XGINEWUB_CRT1Table[CRT1Index].CR[9];
}
if ( temp1 & 0x01 )
@@ -10295,11 +9985,11 @@ void XGI_GetRAMDAC2DATA(USHORT ModeNo , USHORT ModeIdIndex , USHORT RefreshRateT
/* Output : */
/* Description : */
/* --------------------------------------------------------------------- */
-USHORT XGI_GetColorDepth(USHORT ModeNo , USHORT ModeIdIndex, PVB_DEVICE_INFO pVBInfo)
+unsigned short XGI_GetColorDepth(unsigned short ModeNo, unsigned short ModeIdIndex, struct vb_device_info *pVBInfo)
{
- USHORT ColorDepth[ 6 ] = { 1 , 2 , 4 , 4 , 6 , 8 } ;
- SHORT index ;
- USHORT modeflag ;
+ unsigned short ColorDepth[ 6 ] = { 1 , 2 , 4 , 4 , 6 , 8 } ;
+ short index ;
+ unsigned short modeflag ;
if ( ModeNo <= 0x13 )
{
@@ -10326,7 +10016,7 @@ USHORT XGI_GetColorDepth(USHORT ModeNo , USHORT ModeIdIndex, PVB_DEVICE_INFO pVB
/* Output : */
/* Description : */
/* --------------------------------------------------------------------- */
-void XGI_UnLockCRT2( PXGI_HW_DEVICE_INFO HwDeviceExtension, PVB_DEVICE_INFO pVBInfo )
+void XGI_UnLockCRT2(struct xgi_hw_device_info *HwDeviceExtension, struct vb_device_info *pVBInfo)
{
XGINew_SetRegANDOR( pVBInfo->Part1Port , 0x2f , 0xFF , 0x01 ) ;
@@ -10340,7 +10030,7 @@ void XGI_UnLockCRT2( PXGI_HW_DEVICE_INFO HwDeviceExtension, PVB_DEVICE_INFO pVB
/* Output : */
/* Description : */
/* --------------------------------------------------------------------- */
-void XGI_LockCRT2( PXGI_HW_DEVICE_INFO HwDeviceExtension, PVB_DEVICE_INFO pVBInfo )
+void XGI_LockCRT2(struct xgi_hw_device_info *HwDeviceExtension, struct vb_device_info *pVBInfo)
{
XGINew_SetRegANDOR( pVBInfo->Part1Port , 0x2F , 0xFE , 0x00 ) ;
@@ -10355,7 +10045,7 @@ void XGI_LockCRT2( PXGI_HW_DEVICE_INFO HwDeviceExtension, PVB_DEVICE_INFO pVBIn
/* Output : */
/* Description : */
/* --------------------------------------------------------------------- */
-void XGINew_EnableCRT2( PVB_DEVICE_INFO pVBInfo)
+void XGINew_EnableCRT2(struct vb_device_info *pVBInfo)
{
XGINew_SetRegANDOR( pVBInfo->P3c4 , 0x1E , 0xFF , 0x20 ) ;
}
@@ -10368,12 +10058,12 @@ void XGINew_EnableCRT2( PVB_DEVICE_INFO pVBInfo)
/* Output : */
/* Description : */
/* --------------------------------------------------------------------- */
-void XGINew_LCD_Wait_Time(UCHAR DelayTime, PVB_DEVICE_INFO pVBInfo)
+void XGINew_LCD_Wait_Time(unsigned char DelayTime, struct vb_device_info *pVBInfo)
{
- USHORT i ,
+ unsigned short i ,
j ;
- ULONG temp ,
+ unsigned long temp ,
flag ;
flag = 0 ;
@@ -10405,9 +10095,9 @@ void XGINew_LCD_Wait_Time(UCHAR DelayTime, PVB_DEVICE_INFO pVBInfo)
/* Output : */
/* Description : */
/* --------------------------------------------------------------------- */
-BOOLEAN XGI_BridgeIsOn( PVB_DEVICE_INFO pVBInfo )
+unsigned char XGI_BridgeIsOn(struct vb_device_info *pVBInfo)
{
- USHORT flag ;
+ unsigned short flag ;
if ( pVBInfo->IF_DEF_LVDS == 1 )
{
@@ -10431,9 +10121,9 @@ BOOLEAN XGI_BridgeIsOn( PVB_DEVICE_INFO pVBInfo )
/* Output : */
/* Description : */
/* --------------------------------------------------------------------- */
-void XGI_LongWait(PVB_DEVICE_INFO pVBInfo)
+void XGI_LongWait(struct vb_device_info *pVBInfo)
{
- USHORT i ;
+ unsigned short i ;
i = XGINew_GetReg1( pVBInfo->P3c4 , 0x1F ) ;
@@ -10460,9 +10150,9 @@ void XGI_LongWait(PVB_DEVICE_INFO pVBInfo)
/* Output : */
/* Description : */
/* --------------------------------------------------------------------- */
-void XGI_VBLongWait( PVB_DEVICE_INFO pVBInfo )
+void XGI_VBLongWait(struct vb_device_info *pVBInfo)
{
- USHORT tempal ,
+ unsigned short tempal ,
temp ,
i ,
j ;
@@ -10519,16 +10209,16 @@ return ;
/* Output : */
/* Description : */
/* --------------------------------------------------------------------- */
-USHORT XGI_GetVGAHT2( PVB_DEVICE_INFO pVBInfo )
+unsigned short XGI_GetVGAHT2(struct vb_device_info *pVBInfo)
{
- ULONG tempax ,
+ unsigned long tempax ,
tempbx ;
tempbx = ( ( pVBInfo->VGAVT - pVBInfo->VGAVDE ) * pVBInfo->RVBHCMAX ) & 0xFFFF ;
tempax = ( pVBInfo->VT - pVBInfo->VDE ) * pVBInfo->RVBHCFACT ;
tempax = ( tempax * pVBInfo->HT ) /tempbx ;
- return( ( USHORT )tempax ) ;
+ return( (unsigned short)tempax ) ;
}
@@ -10538,19 +10228,23 @@ USHORT XGI_GetVGAHT2( PVB_DEVICE_INFO pVBInfo )
/* Output : */
/* Description : */
/* --------------------------------------------------------------------- */
-USHORT XGI_GetVCLK2Ptr( USHORT ModeNo , USHORT ModeIdIndex , USHORT RefreshRateTableIndex , PXGI_HW_DEVICE_INFO HwDeviceExtension ,PVB_DEVICE_INFO pVBInfo)
+unsigned short XGI_GetVCLK2Ptr(unsigned short ModeNo,
+ unsigned short ModeIdIndex,
+ unsigned short RefreshRateTableIndex,
+ struct xgi_hw_device_info *HwDeviceExtension,
+ struct vb_device_info *pVBInfo)
{
- USHORT tempbx ;
+ unsigned short tempbx ;
- USHORT LCDXlat1VCLK[ 4 ] = { VCLK65 + 2 , VCLK65 + 2 , VCLK65 + 2 , VCLK65 + 2 } ;
- USHORT LCDXlat2VCLK[ 4 ] = { VCLK108_2 + 5 , VCLK108_2 + 5 , VCLK108_2 + 5 , VCLK108_2 + 5 } ;
- USHORT LVDSXlat1VCLK[ 4 ] = { VCLK40 , VCLK40 , VCLK40 , VCLK40 } ;
- USHORT LVDSXlat2VCLK[ 4 ] = { VCLK65 + 2 , VCLK65 + 2 , VCLK65 + 2 , VCLK65 + 2 } ;
- USHORT LVDSXlat3VCLK[ 4 ] = { VCLK65 + 2 , VCLK65 + 2 , VCLK65 + 2 , VCLK65 + 2 } ;
+ unsigned short LCDXlat1VCLK[ 4 ] = { VCLK65 + 2 , VCLK65 + 2 , VCLK65 + 2 , VCLK65 + 2 } ;
+ unsigned short LCDXlat2VCLK[ 4 ] = { VCLK108_2 + 5 , VCLK108_2 + 5 , VCLK108_2 + 5 , VCLK108_2 + 5 } ;
+ unsigned short LVDSXlat1VCLK[ 4 ] = { VCLK40 , VCLK40 , VCLK40 , VCLK40 } ;
+ unsigned short LVDSXlat2VCLK[ 4 ] = { VCLK65 + 2 , VCLK65 + 2 , VCLK65 + 2 , VCLK65 + 2 } ;
+ unsigned short LVDSXlat3VCLK[ 4 ] = { VCLK65 + 2 , VCLK65 + 2 , VCLK65 + 2 , VCLK65 + 2 } ;
- USHORT CRT2Index , VCLKIndex ;
- USHORT modeflag , resinfo ;
- UCHAR *CHTVVCLKPtr = NULL ;
+ unsigned short CRT2Index , VCLKIndex ;
+ unsigned short modeflag , resinfo ;
+ unsigned char *CHTVVCLKPtr = NULL ;
if ( ModeNo <= 0x13 )
{
@@ -10665,7 +10359,7 @@ USHORT XGI_GetVCLK2Ptr( USHORT ModeNo , USHORT ModeIdIndex , USHORT RefreshRateT
}
else
{ /* for CRT2 */
- VCLKIndex = ( UCHAR )XGINew_GetReg2( ( pVBInfo->P3ca + 0x02 ) ) ; /* Port 3cch */
+ VCLKIndex = (unsigned char)XGINew_GetReg2((pVBInfo->P3ca + 0x02)); /* Port 3cch */
VCLKIndex = ( ( VCLKIndex >> 2 ) & 0x03 ) ;
if ( ModeNo > 0x13 )
{
diff --git a/drivers/staging/xgifb/vb_setmode.h b/drivers/staging/xgifb/vb_setmode.h
index 09753d70666..0dcc2979617 100644
--- a/drivers/staging/xgifb/vb_setmode.h
+++ b/drivers/staging/xgifb/vb_setmode.h
@@ -1,40 +1,42 @@
#ifndef _VBSETMODE_
#define _VBSETMODE_
-extern void InitTo330Pointer(UCHAR,PVB_DEVICE_INFO);
-extern void XGI_UnLockCRT2(PXGI_HW_DEVICE_INFO HwDeviceExtension, PVB_DEVICE_INFO );
-extern void XGI_LockCRT2(PXGI_HW_DEVICE_INFO HwDeviceExtension, PVB_DEVICE_INFO );
-extern void XGI_LongWait( PVB_DEVICE_INFO );
-extern void XGI_SetCRT2ModeRegs(USHORT ModeNo,PXGI_HW_DEVICE_INFO, PVB_DEVICE_INFO );
-extern void XGI_DisableBridge(PXGI_HW_DEVICE_INFO HwDeviceExtension, PVB_DEVICE_INFO );
-extern void XGI_EnableBridge(PXGI_HW_DEVICE_INFO HwDeviceExtension, PVB_DEVICE_INFO );
-extern void XGI_DisplayOff( PXGI_HW_DEVICE_INFO, PVB_DEVICE_INFO );
-extern void XGI_DisplayOn( PXGI_HW_DEVICE_INFO, PVB_DEVICE_INFO );
-extern void XGI_GetVBType(PVB_DEVICE_INFO);
-extern void XGI_SenseCRT1(PVB_DEVICE_INFO );
-extern void XGI_GetVGAType(PXGI_HW_DEVICE_INFO HwDeviceExtension, PVB_DEVICE_INFO );
-extern void XGI_GetVBInfo(USHORT ModeNo,USHORT ModeIdIndex,PXGI_HW_DEVICE_INFO HwDeviceExtension, PVB_DEVICE_INFO );
-extern void XGI_GetTVInfo(USHORT ModeNo,USHORT ModeIdIndex, PVB_DEVICE_INFO );
-extern void XGI_SetCRT1Offset(USHORT ModeNo,USHORT ModeIdIndex,USHORT RefreshRateTableIndex,PXGI_HW_DEVICE_INFO HwDeviceExtension, PVB_DEVICE_INFO );
-extern void XGI_SetLCDAGroup(USHORT ModeNo,USHORT ModeIdIndex,PXGI_HW_DEVICE_INFO HwDeviceExtension, PVB_DEVICE_INFO );
-extern void XGI_WaitDisply( PVB_DEVICE_INFO );
-extern USHORT XGI_GetResInfo(USHORT ModeNo,USHORT ModeIdIndex, PVB_DEVICE_INFO pVBInfo);
+extern void InitTo330Pointer(unsigned char, struct vb_device_info *);
+extern void XGI_UnLockCRT2(struct xgi_hw_device_info *HwDeviceExtension, struct vb_device_info *);
+extern void XGI_LockCRT2(struct xgi_hw_device_info *HwDeviceExtension, struct vb_device_info *);
+extern void XGI_LongWait(struct vb_device_info *);
+extern void XGI_SetCRT2ModeRegs(unsigned short ModeNo,
+ struct xgi_hw_device_info *,
+ struct vb_device_info *);
+extern void XGI_DisableBridge(struct xgi_hw_device_info *HwDeviceExtension, struct vb_device_info *);
+extern void XGI_EnableBridge(struct xgi_hw_device_info *HwDeviceExtension, struct vb_device_info *);
+extern void XGI_DisplayOff(struct xgi_hw_device_info *, struct vb_device_info *);
+extern void XGI_DisplayOn(struct xgi_hw_device_info *, struct vb_device_info *);
+extern void XGI_GetVBType(struct vb_device_info *);
+extern void XGI_SenseCRT1(struct vb_device_info *);
+extern void XGI_GetVGAType(struct xgi_hw_device_info *HwDeviceExtension, struct vb_device_info *);
+extern void XGI_GetVBInfo(unsigned short ModeNo, unsigned short ModeIdIndex, struct xgi_hw_device_info *HwDeviceExtension, struct vb_device_info *);
+extern void XGI_GetTVInfo(unsigned short ModeNo, unsigned short ModeIdIndex, struct vb_device_info *);
+extern void XGI_SetCRT1Offset(unsigned short ModeNo, unsigned short ModeIdIndex, unsigned short RefreshRateTableIndex, struct xgi_hw_device_info *HwDeviceExtension, struct vb_device_info *);
+extern void XGI_SetLCDAGroup(unsigned short ModeNo, unsigned short ModeIdIndex, struct xgi_hw_device_info *HwDeviceExtension, struct vb_device_info *);
+extern void XGI_WaitDisply(struct vb_device_info *);
+extern unsigned short XGI_GetResInfo(unsigned short ModeNo, unsigned short ModeIdIndex, struct vb_device_info *pVBInfo);
-extern BOOLEAN XGISetModeNew( PXGI_HW_DEVICE_INFO HwDeviceExtension , USHORT ModeNo ) ;
+extern unsigned char XGISetModeNew(struct xgi_hw_device_info *HwDeviceExtension, unsigned short ModeNo) ;
-extern BOOLEAN XGI_SearchModeID( USHORT ModeNo,USHORT *ModeIdIndex, PVB_DEVICE_INFO );
-extern BOOLEAN XGI_GetLCDInfo(USHORT ModeNo,USHORT ModeIdIndex,PVB_DEVICE_INFO );
-extern BOOLEAN XGI_BridgeIsOn( PVB_DEVICE_INFO );
-extern BOOLEAN XGI_SetCRT2Group301(USHORT ModeNo, PXGI_HW_DEVICE_INFO HwDeviceExtension, PVB_DEVICE_INFO);
-extern USHORT XGI_GetRatePtrCRT2( PXGI_HW_DEVICE_INFO pXGIHWDE, USHORT ModeNo,USHORT ModeIdIndex, PVB_DEVICE_INFO );
+extern unsigned char XGI_SearchModeID(unsigned short ModeNo, unsigned short *ModeIdIndex, struct vb_device_info *);
+extern unsigned char XGI_GetLCDInfo(unsigned short ModeNo, unsigned short ModeIdIndex, struct vb_device_info *);
+extern unsigned char XGI_BridgeIsOn(struct vb_device_info *);
+extern unsigned char XGI_SetCRT2Group301(unsigned short ModeNo, struct xgi_hw_device_info *HwDeviceExtension, struct vb_device_info *);
+extern unsigned short XGI_GetRatePtrCRT2(struct xgi_hw_device_info *pXGIHWDE, unsigned short ModeNo, unsigned short ModeIdIndex, struct vb_device_info *);
-extern void XGI_SetXG21FPBits(PVB_DEVICE_INFO pVBInfo);
-extern void XGI_SetXG27FPBits(PVB_DEVICE_INFO pVBInfo);
-extern void XGI_XG21BLSignalVDD(USHORT tempbh,USHORT tempbl, PVB_DEVICE_INFO pVBInfo);
-extern void XGI_XG27BLSignalVDD(USHORT tempbh,USHORT tempbl, PVB_DEVICE_INFO pVBInfo);
-extern void XGI_XG21SetPanelDelay(USHORT tempbl, PVB_DEVICE_INFO pVBInfo);
-extern BOOLEAN XGI_XG21CheckLVDSMode(USHORT ModeNo,USHORT ModeIdIndex, PVB_DEVICE_INFO pVBInfo );
-extern void XGI_SetXG21LVDSPara(USHORT ModeNo,USHORT ModeIdIndex, PVB_DEVICE_INFO pVBInfo );
-extern USHORT XGI_GetLVDSOEMTableIndex(PVB_DEVICE_INFO pVBInfo);
+extern void XGI_SetXG21FPBits(struct vb_device_info *pVBInfo);
+extern void XGI_SetXG27FPBits(struct vb_device_info *pVBInfo);
+extern void XGI_XG21BLSignalVDD(unsigned short tempbh, unsigned short tempbl, struct vb_device_info *pVBInfo);
+extern void XGI_XG27BLSignalVDD(unsigned short tempbh, unsigned short tempbl, struct vb_device_info *pVBInfo);
+extern void XGI_XG21SetPanelDelay(unsigned short tempbl, struct vb_device_info *pVBInfo);
+extern unsigned char XGI_XG21CheckLVDSMode(unsigned short ModeNo, unsigned short ModeIdIndex, struct vb_device_info *pVBInfo);
+extern void XGI_SetXG21LVDSPara(unsigned short ModeNo, unsigned short ModeIdIndex, struct vb_device_info *pVBInfo);
+extern unsigned short XGI_GetLVDSOEMTableIndex(struct vb_device_info *pVBInfo);
#endif
diff --git a/drivers/staging/xgifb/vb_struct.h b/drivers/staging/xgifb/vb_struct.h
index bb25c0e2785..9c6e0c7ac78 100644
--- a/drivers/staging/xgifb/vb_struct.h
+++ b/drivers/staging/xgifb/vb_struct.h
@@ -10,525 +10,518 @@
-typedef struct _XGI_PanelDelayTblStruct
+struct XGI_PanelDelayTblStruct
{
- UCHAR timer[2];
-} XGI_PanelDelayTblStruct;
+ unsigned char timer[2];
+};
-typedef struct _XGI_LCDDataStruct
+struct XGI_LCDDataStruct
{
- USHORT RVBHCMAX;
- USHORT RVBHCFACT;
- USHORT VGAHT;
- USHORT VGAVT;
- USHORT LCDHT;
- USHORT LCDVT;
-} XGI_LCDDataStruct;
+ unsigned short RVBHCMAX;
+ unsigned short RVBHCFACT;
+ unsigned short VGAHT;
+ unsigned short VGAVT;
+ unsigned short LCDHT;
+ unsigned short LCDVT;
+};
-typedef struct _XGI_LVDSCRT1HDataStruct
+struct XGI_LVDSCRT1HDataStruct
{
- UCHAR Reg[8];
-} XGI_LVDSCRT1HDataStruct;
-typedef struct _XGI_LVDSCRT1VDataStruct
-{
- UCHAR Reg[7];
-} XGI_LVDSCRT1VDataStruct;
-
-
-typedef struct _XGI_TVDataStruct
-{
- USHORT RVBHCMAX;
- USHORT RVBHCFACT;
- USHORT VGAHT;
- USHORT VGAVT;
- USHORT TVHDE;
- USHORT TVVDE;
- USHORT RVBHRS;
- UCHAR FlickerMode;
- USHORT HALFRVBHRS;
- UCHAR RY1COE;
- UCHAR RY2COE;
- UCHAR RY3COE;
- UCHAR RY4COE;
-} XGI_TVDataStruct;
-
-typedef struct _XGI_LVDSDataStruct
-{
- USHORT VGAHT;
- USHORT VGAVT;
- USHORT LCDHT;
- USHORT LCDVT;
-} XGI_LVDSDataStruct;
-
-typedef struct _XGI_LVDSDesStruct
-{
- USHORT LCDHDES;
- USHORT LCDVDES;
-} XGI_LVDSDesStruct;
-
-typedef struct _XGI_LVDSCRT1DataStruct
-{
- UCHAR CR[15];
-} XGI_LVDSCRT1DataStruct;
-
-/*add for LCDA*/
+ unsigned char Reg[8];
+};
-
-typedef struct _XGI_StStruct
-{
- UCHAR St_ModeID;
- USHORT St_ModeFlag;
- UCHAR St_StTableIndex;
- UCHAR St_CRT2CRTC;
- UCHAR St_CRT2CRTC2;
- UCHAR St_ResInfo;
- UCHAR VB_StTVFlickerIndex;
- UCHAR VB_StTVEdgeIndex;
- UCHAR VB_StTVYFilterIndex;
-} XGI_StStruct;
-
-typedef struct _XGI_StandTableStruct
-{
- UCHAR CRT_COLS;
- UCHAR ROWS;
- UCHAR CHAR_HEIGHT;
- USHORT CRT_LEN;
- UCHAR SR[4];
- UCHAR MISC;
- UCHAR CRTC[0x19];
- UCHAR ATTR[0x14];
- UCHAR GRC[9];
-} XGI_StandTableStruct;
-
-typedef struct _XGI_ExtStruct
-{
- UCHAR Ext_ModeID;
- USHORT Ext_ModeFlag;
- USHORT Ext_ModeInfo;
- USHORT Ext_Point;
- USHORT Ext_VESAID;
- UCHAR Ext_VESAMEMSize;
- UCHAR Ext_RESINFO;
- UCHAR VB_ExtTVFlickerIndex;
- UCHAR VB_ExtTVEdgeIndex;
- UCHAR VB_ExtTVYFilterIndex;
- UCHAR REFindex;
-} XGI_ExtStruct;
-
-typedef struct _XGI_Ext2Struct
+struct XGI_LVDSCRT1VDataStruct
{
- USHORT Ext_InfoFlag;
- UCHAR Ext_CRT1CRTC;
- UCHAR Ext_CRTVCLK;
- UCHAR Ext_CRT2CRTC;
- UCHAR Ext_CRT2CRTC2;
- UCHAR ModeID;
- USHORT XRes;
- USHORT YRes;
- /* USHORT ROM_OFFSET; */
-} XGI_Ext2Struct;
-
+ unsigned char Reg[7];
+};
-typedef struct _XGI_MCLKDataStruct
-{
- UCHAR SR28,SR29,SR2A;
- USHORT CLOCK;
-} XGI_MCLKDataStruct;
-typedef struct _XGI_ECLKDataStruct
+struct XGI_TVDataStruct
{
- UCHAR SR2E,SR2F,SR30;
- USHORT CLOCK;
-} XGI_ECLKDataStruct;
+ unsigned short RVBHCMAX;
+ unsigned short RVBHCFACT;
+ unsigned short VGAHT;
+ unsigned short VGAVT;
+ unsigned short TVHDE;
+ unsigned short TVVDE;
+ unsigned short RVBHRS;
+ unsigned char FlickerMode;
+ unsigned short HALFRVBHRS;
+ unsigned char RY1COE;
+ unsigned char RY2COE;
+ unsigned char RY3COE;
+ unsigned char RY4COE;
+};
-typedef struct _XGI_VCLKDataStruct
+struct XGI_LVDSDataStruct
{
- UCHAR SR2B,SR2C;
- USHORT CLOCK;
-} XGI_VCLKDataStruct;
+ unsigned short VGAHT;
+ unsigned short VGAVT;
+ unsigned short LCDHT;
+ unsigned short LCDVT;
+};
-typedef struct _XGI_VBVCLKDataStruct
+struct XGI_LVDSDesStruct
{
- UCHAR Part4_A,Part4_B;
- USHORT CLOCK;
-} XGI_VBVCLKDataStruct;
+ unsigned short LCDHDES;
+ unsigned short LCDVDES;
+};
-typedef struct _XGI_StResInfoStruct
+struct XGI_LVDSCRT1DataStruct
{
- USHORT HTotal;
- USHORT VTotal;
-} XGI_StResInfoStruct;
+ unsigned char CR[15];
+};
-typedef struct _XGI_ModeResInfoStruct
-{
- USHORT HTotal;
- USHORT VTotal;
- UCHAR XChar;
- UCHAR YChar;
-} XGI_ModeResInfoStruct;
+/*add for LCDA*/
-typedef struct _XGI_LCDNBDesStruct
-{
- UCHAR NB[12];
-} XGI_LCDNBDesStruct;
+struct XGI_StStruct
+{
+ unsigned char St_ModeID;
+ unsigned short St_ModeFlag;
+ unsigned char St_StTableIndex;
+ unsigned char St_CRT2CRTC;
+ unsigned char St_CRT2CRTC2;
+ unsigned char St_ResInfo;
+ unsigned char VB_StTVFlickerIndex;
+ unsigned char VB_StTVEdgeIndex;
+ unsigned char VB_StTVYFilterIndex;
+};
+
+struct XGI_StandTableStruct
+{
+ unsigned char CRT_COLS;
+ unsigned char ROWS;
+ unsigned char CHAR_HEIGHT;
+ unsigned short CRT_LEN;
+ unsigned char SR[4];
+ unsigned char MISC;
+ unsigned char CRTC[0x19];
+ unsigned char ATTR[0x14];
+ unsigned char GRC[9];
+};
+
+struct XGI_ExtStruct
+{
+ unsigned char Ext_ModeID;
+ unsigned short Ext_ModeFlag;
+ unsigned short Ext_ModeInfo;
+ unsigned short Ext_Point;
+ unsigned short Ext_VESAID;
+ unsigned char Ext_VESAMEMSize;
+ unsigned char Ext_RESINFO;
+ unsigned char VB_ExtTVFlickerIndex;
+ unsigned char VB_ExtTVEdgeIndex;
+ unsigned char VB_ExtTVYFilterIndex;
+ unsigned char REFindex;
+};
+
+struct XGI_Ext2Struct
+{
+ unsigned short Ext_InfoFlag;
+ unsigned char Ext_CRT1CRTC;
+ unsigned char Ext_CRTVCLK;
+ unsigned char Ext_CRT2CRTC;
+ unsigned char Ext_CRT2CRTC2;
+ unsigned char ModeID;
+ unsigned short XRes;
+ unsigned short YRes;
+ /* unsigned short ROM_OFFSET; */
+};
+
+
+struct XGI_MCLKDataStruct
+{
+ unsigned char SR28, SR29, SR2A;
+ unsigned short CLOCK;
+};
+
+struct XGI_ECLKDataStruct
+{
+ unsigned char SR2E, SR2F, SR30;
+ unsigned short CLOCK;
+};
+
+struct XGI_VCLKDataStruct
+{
+ unsigned char SR2B, SR2C;
+ unsigned short CLOCK;
+};
+
+struct XGI_VBVCLKDataStruct
+{
+ unsigned char Part4_A, Part4_B;
+ unsigned short CLOCK;
+};
+
+struct XGI_StResInfoStruct
+{
+ unsigned short HTotal;
+ unsigned short VTotal;
+};
+
+struct XGI_ModeResInfoStruct
+{
+ unsigned short HTotal;
+ unsigned short VTotal;
+ unsigned char XChar;
+ unsigned char YChar;
+};
+
+struct XGI_LCDNBDesStruct
+{
+ unsigned char NB[12];
+};
/*add for new UNIVGABIOS*/
-typedef struct _XGI_LCDDesStruct
+struct XGI_LCDDesStruct
{
- USHORT LCDHDES;
- USHORT LCDHRS;
- USHORT LCDVDES;
- USHORT LCDVRS;
-} XGI_LCDDesStruct;
+ unsigned short LCDHDES;
+ unsigned short LCDHRS;
+ unsigned short LCDVDES;
+ unsigned short LCDVRS;
+};
-typedef struct _XGI_LCDDataTablStruct
+struct XGI_LCDDataTablStruct
{
- UCHAR PANELID;
- USHORT MASK;
- USHORT CAP;
- USHORT DATAPTR;
-} XGI_LCDDataTablStruct;
+ unsigned char PANELID;
+ unsigned short MASK;
+ unsigned short CAP;
+ unsigned short DATAPTR;
+};
-typedef struct _XGI_TVTablDataStruct
+struct XGI_TVTablDataStruct
{
- USHORT MASK;
- USHORT CAP;
- USHORT DATAPTR;
-} XGI_TVDataTablStruct;
+ unsigned short MASK;
+ unsigned short CAP;
+ unsigned short DATAPTR;
+};
-typedef struct _XGI330_LCDDesDataStruct
+struct XGI330_LCDDataDesStruct
{
- USHORT LCDHDES;
- USHORT LCDHRS;
- USHORT LCDVDES;
- USHORT LCDVRS;
-} XGI330_LCDDataDesStruct;
+ unsigned short LCDHDES;
+ unsigned short LCDHRS;
+ unsigned short LCDVDES;
+ unsigned short LCDVRS;
+};
-typedef struct _XGI330_LVDSDataStruct
+struct XGI330_LVDSDataStruct
{
- USHORT VGAHT;
- USHORT VGAVT;
- USHORT LCDHT;
- USHORT LCDVT;
-} XGI330_LVDSDataStruct;
+ unsigned short VGAHT;
+ unsigned short VGAVT;
+ unsigned short LCDHT;
+ unsigned short LCDVT;
+};
-typedef struct _XGI330_LCDDesDataStruct2
+struct XGI330_LCDDataDesStruct2
{
- USHORT LCDHDES;
- USHORT LCDHRS;
- USHORT LCDVDES;
- USHORT LCDVRS;
- USHORT LCDHSync;
- USHORT LCDVSync;
-} XGI330_LCDDataDesStruct2;
+ unsigned short LCDHDES;
+ unsigned short LCDHRS;
+ unsigned short LCDVDES;
+ unsigned short LCDVRS;
+ unsigned short LCDHSync;
+ unsigned short LCDVSync;
+};
-typedef struct _XGI330_LCDDataStruct
+struct XGI330_LCDDataStruct
{
- USHORT RVBHCMAX;
- USHORT RVBHCFACT;
- USHORT VGAHT;
- USHORT VGAVT;
- USHORT LCDHT;
- USHORT LCDVT;
-} XGI330_LCDDataStruct;
+ unsigned short RVBHCMAX;
+ unsigned short RVBHCFACT;
+ unsigned short VGAHT;
+ unsigned short VGAVT;
+ unsigned short LCDHT;
+ unsigned short LCDVT;
+};
-typedef struct _XGI330_TVDataStruct
+struct XGI330_TVDataStruct
{
- USHORT RVBHCMAX;
- USHORT RVBHCFACT;
- USHORT VGAHT;
- USHORT VGAVT;
- USHORT TVHDE;
- USHORT TVVDE;
- USHORT RVBHRS;
- UCHAR FlickerMode;
- USHORT HALFRVBHRS;
-} XGI330_TVDataStruct;
-
-typedef struct _XGI330_LCDDataTablStruct
-{
- UCHAR PANELID;
- USHORT MASK;
- USHORT CAP;
- USHORT DATAPTR;
-} XGI330_LCDDataTablStruct;
-
-typedef struct _XGI330_TVDataTablStruct
-{
- USHORT MASK;
- USHORT CAP;
- USHORT DATAPTR;
-} XGI330_TVDataTablStruct;
-
-
-typedef struct _XGI330_CHTVDataStruct
-{
- USHORT VGAHT;
- USHORT VGAVT;
- USHORT LCDHT;
- USHORT LCDVT;
-} XGI330_CHTVDataStruct;
+ unsigned short RVBHCMAX;
+ unsigned short RVBHCFACT;
+ unsigned short VGAHT;
+ unsigned short VGAVT;
+ unsigned short TVHDE;
+ unsigned short TVVDE;
+ unsigned short RVBHRS;
+ unsigned char FlickerMode;
+ unsigned short HALFRVBHRS;
+};
+
+struct XGI330_LCDDataTablStruct
+{
+ unsigned char PANELID;
+ unsigned short MASK;
+ unsigned short CAP;
+ unsigned short DATAPTR;
+};
+
+struct XGI330_TVDataTablStruct
+{
+ unsigned short MASK;
+ unsigned short CAP;
+ unsigned short DATAPTR;
+};
+
+
+struct XGI330_CHTVDataStruct
+{
+ unsigned short VGAHT;
+ unsigned short VGAVT;
+ unsigned short LCDHT;
+ unsigned short LCDVT;
+};
-typedef struct _XGI_TimingHStruct
-{
- UCHAR data[8];
-} XGI_TimingHStruct;
-
-typedef struct _XGI_TimingVStruct
-{
- UCHAR data[7];
-} XGI_TimingVStruct;
-
-typedef struct _XGI_CH7007TV_TimingHStruct
-{
- UCHAR data[10];
-} XGI_CH7007TV_TimingHStruct;
-
-typedef struct _XGI_CH7007TV_TimingVStruct
-{
- UCHAR data[10];
-} XGI_CH7007TV_TimingVStruct;
-
-typedef struct _XGI_XG21CRT1Struct
-{
- UCHAR ModeID,CR02,CR03,CR15,CR16;
-} XGI_XG21CRT1Struct;
-
-typedef struct _XGI330_CHTVRegDataStruct
-{
- UCHAR Reg[16];
-} XGI330_CHTVRegDataStruct;
-
-typedef struct _XGI330_LCDCapStruct
-{
- UCHAR LCD_ID;
- USHORT LCD_Capability;
- UCHAR LCD_SetFlag;
- UCHAR LCD_DelayCompensation;
- UCHAR LCD_HSyncWidth;
- UCHAR LCD_VSyncWidth;
- UCHAR LCD_VCLK;
- UCHAR LCDA_VCLKData1;
- UCHAR LCDA_VCLKData2;
- UCHAR LCUCHAR_VCLKData1;
- UCHAR LCUCHAR_VCLKData2;
- UCHAR PSC_S1;
- UCHAR PSC_S2;
- UCHAR PSC_S3;
- UCHAR PSC_S4;
- UCHAR PSC_S5;
- UCHAR PWD_2B;
- UCHAR PWD_2C;
- UCHAR PWD_2D;
- UCHAR PWD_2E;
- UCHAR PWD_2F;
- UCHAR Spectrum_31;
- UCHAR Spectrum_32;
- UCHAR Spectrum_33;
- UCHAR Spectrum_34;
-} XGI330_LCDCapStruct;
-
-typedef struct _XGI21_LVDSCapStruct
-{
- USHORT LVDS_Capability;
- USHORT LVDSHT;
- USHORT LVDSVT;
- USHORT LVDSHDE;
- USHORT LVDSVDE;
- USHORT LVDSHFP;
- USHORT LVDSVFP;
- USHORT LVDSHSYNC;
- USHORT LVDSVSYNC;
- UCHAR VCLKData1;
- UCHAR VCLKData2;
- UCHAR PSC_S1;
- UCHAR PSC_S2;
- UCHAR PSC_S3;
- UCHAR PSC_S4;
- UCHAR PSC_S5;
-} XGI21_LVDSCapStruct;
-
-typedef struct _XGI_CRT1TableStruct
-{
- UCHAR CR[16];
-} XGI_CRT1TableStruct;
-
-
-typedef struct _XGI330_VCLKDataStruct
-{
- UCHAR SR2B,SR2C;
- USHORT CLOCK;
-} XGI330_VCLKDataStruct;
-
-typedef struct _XGI301C_Tap4TimingStruct
-{
- USHORT DE;
- UCHAR Reg[64]; /* C0-FF */
-} XGI301C_Tap4TimingStruct;
-
-typedef struct _XGI_New_StandTableStruct
-{
- UCHAR CRT_COLS;
- UCHAR ROWS;
- UCHAR CHAR_HEIGHT;
- USHORT CRT_LEN;
- UCHAR SR[4];
- UCHAR MISC;
- UCHAR CRTC[0x19];
- UCHAR ATTR[0x14];
- UCHAR GRC[9];
-} XGI_New_StandTableStruct;
-
-typedef UCHAR DRAM8Type[8];
-typedef UCHAR DRAM4Type[4];
-typedef UCHAR DRAM32Type[32];
-typedef UCHAR DRAM2Type[2];
-
-typedef struct _VB_DEVICE_INFO VB_DEVICE_INFO;
-typedef VB_DEVICE_INFO * PVB_DEVICE_INFO;
-
-struct _VB_DEVICE_INFO
-{
- BOOLEAN ISXPDOS;
- ULONG P3c4,P3d4,P3c0,P3ce,P3c2,P3cc;
- ULONG P3ca,P3c6,P3c7,P3c8,P3c9,P3da;
- ULONG Part0Port,Part1Port,Part2Port;
- ULONG Part3Port,Part4Port,Part5Port;
- USHORT RVBHCFACT,RVBHCMAX,RVBHRS;
- USHORT VGAVT,VGAHT,VGAVDE,VGAHDE;
- USHORT VT,HT,VDE,HDE;
- USHORT LCDHRS,LCDVRS,LCDHDES,LCDVDES;
-
- USHORT ModeType;
- USHORT IF_DEF_LVDS,IF_DEF_TRUMPION,IF_DEF_DSTN;/* ,IF_DEF_FSTN; add for dstn */
- USHORT IF_DEF_CRT2Monitor,IF_DEF_VideoCapture;
- USHORT IF_DEF_LCDA,IF_DEF_CH7017,IF_DEF_YPbPr,IF_DEF_ScaleLCD,IF_DEF_OEMUtil,IF_DEF_PWD;
- USHORT IF_DEF_ExpLink;
- USHORT IF_DEF_CH7005,IF_DEF_HiVision;
- USHORT IF_DEF_CH7007; /* Billy 2007/05/03 */
- USHORT LCDResInfo,LCDTypeInfo, VBType;/*301b*/
- USHORT VBInfo,TVInfo,LCDInfo, Set_VGAType;
- USHORT VBExtInfo;/*301lv*/
- USHORT SetFlag;
- USHORT NewFlickerMode;
- USHORT SelectCRT2Rate;
-
- PUCHAR ROMAddr;
- PUCHAR FBAddr;
- ULONG BaseAddr;
- ULONG RelIO;
-
- DRAM4Type *CR6B;
- DRAM4Type *CR6E;
- DRAM32Type *CR6F;
- DRAM2Type *CR89;
-
- DRAM8Type *SR15; /* pointer : point to array */
- DRAM8Type *CR40;
- UCHAR *pSoftSetting;
- UCHAR *pOutputSelect;
-
- USHORT *pRGBSenseData;
- USHORT *pRGBSenseData2; /*301b*/
- USHORT *pVideoSenseData;
- USHORT *pVideoSenseData2;
- USHORT *pYCSenseData;
- USHORT *pYCSenseData2;
-
- UCHAR *pSR07;
- UCHAR *CR49;
- UCHAR *pSR1F;
- UCHAR *AGPReg;
- UCHAR *SR16;
- UCHAR *pSR21;
- UCHAR *pSR22;
- UCHAR *pSR23;
- UCHAR *pSR24;
- UCHAR *SR25;
- UCHAR *pSR31;
- UCHAR *pSR32;
- UCHAR *pSR33;
- UCHAR *pSR36; /* alan 12/07/2006 */
- UCHAR *pCRCF;
- UCHAR *pCRD0; /* alan 12/07/2006 */
- UCHAR *pCRDE; /* alan 12/07/2006 */
- UCHAR *pCR8F; /* alan 12/07/2006 */
- UCHAR *pSR40; /* alan 12/07/2006 */
- UCHAR *pSR41; /* alan 12/07/2006 */
- UCHAR *pDVOSetting;
- UCHAR *pCR2E;
- UCHAR *pCR2F;
- UCHAR *pCR46;
- UCHAR *pCR47;
- UCHAR *pCRT2Data_1_2;
- UCHAR *pCRT2Data_4_D;
- UCHAR *pCRT2Data_4_E;
- UCHAR *pCRT2Data_4_10;
- XGI_MCLKDataStruct *MCLKData;
- XGI_ECLKDataStruct *ECLKData;
-
- UCHAR *XGI_TVDelayList;
- UCHAR *XGI_TVDelayList2;
- UCHAR *CHTVVCLKUNTSC;
- UCHAR *CHTVVCLKONTSC;
- UCHAR *CHTVVCLKUPAL;
- UCHAR *CHTVVCLKOPAL;
- UCHAR *NTSCTiming;
- UCHAR *PALTiming;
- UCHAR *HiTVExtTiming;
- UCHAR *HiTVSt1Timing;
- UCHAR *HiTVSt2Timing;
- UCHAR *HiTVTextTiming;
- UCHAR *YPbPr750pTiming;
- UCHAR *YPbPr525pTiming;
- UCHAR *YPbPr525iTiming;
- UCHAR *HiTVGroup3Data;
- UCHAR *HiTVGroup3Simu;
- UCHAR *HiTVGroup3Text;
- UCHAR *Ren525pGroup3;
- UCHAR *Ren750pGroup3;
- UCHAR *ScreenOffset;
- UCHAR *pXGINew_DRAMTypeDefinition;
- UCHAR *pXGINew_I2CDefinition ;
- UCHAR *pXGINew_CR97 ;
-
- XGI330_LCDCapStruct *LCDCapList;
- XGI21_LVDSCapStruct *XG21_LVDSCapList;
-
- XGI_TimingHStruct *TimingH;
- XGI_TimingVStruct *TimingV;
-
- XGI_StStruct *SModeIDTable;
- XGI_StandTableStruct *StandTable;
- XGI_ExtStruct *EModeIDTable;
- XGI_Ext2Struct *RefIndex;
+struct XGI_TimingHStruct
+{
+ unsigned char data[8];
+};
+
+struct XGI_TimingVStruct
+{
+ unsigned char data[7];
+};
+
+struct XGI_CH7007TV_TimingHStruct
+{
+ unsigned char data[10];
+};
+
+struct XGI_CH7007TV_TimingVStruct
+{
+ unsigned char data[10];
+};
+
+struct XGI_XG21CRT1Struct
+{
+ unsigned char ModeID, CR02, CR03, CR15, CR16;
+};
+
+struct XGI330_CHTVRegDataStruct
+{
+ unsigned char Reg[16];
+};
+
+struct XGI330_LCDCapStruct
+{
+ unsigned char LCD_ID;
+ unsigned short LCD_Capability;
+ unsigned char LCD_SetFlag;
+ unsigned char LCD_DelayCompensation;
+ unsigned char LCD_HSyncWidth;
+ unsigned char LCD_VSyncWidth;
+ unsigned char LCD_VCLK;
+ unsigned char LCDA_VCLKData1;
+ unsigned char LCDA_VCLKData2;
+ unsigned char LCUCHAR_VCLKData1;
+ unsigned char LCUCHAR_VCLKData2;
+ unsigned char PSC_S1;
+ unsigned char PSC_S2;
+ unsigned char PSC_S3;
+ unsigned char PSC_S4;
+ unsigned char PSC_S5;
+ unsigned char PWD_2B;
+ unsigned char PWD_2C;
+ unsigned char PWD_2D;
+ unsigned char PWD_2E;
+ unsigned char PWD_2F;
+ unsigned char Spectrum_31;
+ unsigned char Spectrum_32;
+ unsigned char Spectrum_33;
+ unsigned char Spectrum_34;
+};
+
+struct XGI21_LVDSCapStruct
+{
+ unsigned short LVDS_Capability;
+ unsigned short LVDSHT;
+ unsigned short LVDSVT;
+ unsigned short LVDSHDE;
+ unsigned short LVDSVDE;
+ unsigned short LVDSHFP;
+ unsigned short LVDSVFP;
+ unsigned short LVDSHSYNC;
+ unsigned short LVDSVSYNC;
+ unsigned char VCLKData1;
+ unsigned char VCLKData2;
+ unsigned char PSC_S1;
+ unsigned char PSC_S2;
+ unsigned char PSC_S3;
+ unsigned char PSC_S4;
+ unsigned char PSC_S5;
+};
+
+struct XGI_CRT1TableStruct
+{
+ unsigned char CR[16];
+};
+
+
+struct XGI330_VCLKDataStruct
+{
+ unsigned char SR2B, SR2C;
+ unsigned short CLOCK;
+};
+
+struct XGI301C_Tap4TimingStruct
+{
+ unsigned short DE;
+ unsigned char Reg[64]; /* C0-FF */
+};
+
+struct XGI_New_StandTableStruct
+{
+ unsigned char CRT_COLS;
+ unsigned char ROWS;
+ unsigned char CHAR_HEIGHT;
+ unsigned short CRT_LEN;
+ unsigned char SR[4];
+ unsigned char MISC;
+ unsigned char CRTC[0x19];
+ unsigned char ATTR[0x14];
+ unsigned char GRC[9];
+};
+
+struct vb_device_info
+{
+ unsigned char ISXPDOS;
+ unsigned long P3c4,P3d4,P3c0,P3ce,P3c2,P3cc;
+ unsigned long P3ca,P3c6,P3c7,P3c8,P3c9,P3da;
+ unsigned long Part0Port,Part1Port,Part2Port;
+ unsigned long Part3Port,Part4Port,Part5Port;
+ unsigned short RVBHCFACT,RVBHCMAX,RVBHRS;
+ unsigned short VGAVT,VGAHT,VGAVDE,VGAHDE;
+ unsigned short VT,HT,VDE,HDE;
+ unsigned short LCDHRS,LCDVRS,LCDHDES,LCDVDES;
+
+ unsigned short ModeType;
+ unsigned short IF_DEF_LVDS,IF_DEF_TRUMPION,IF_DEF_DSTN;/* ,IF_DEF_FSTN; add for dstn */
+ unsigned short IF_DEF_CRT2Monitor,IF_DEF_VideoCapture;
+ unsigned short IF_DEF_LCDA,IF_DEF_CH7017,IF_DEF_YPbPr,IF_DEF_ScaleLCD,IF_DEF_OEMUtil,IF_DEF_PWD;
+ unsigned short IF_DEF_ExpLink;
+ unsigned short IF_DEF_CH7005,IF_DEF_HiVision;
+ unsigned short IF_DEF_CH7007; /* Billy 2007/05/03 */
+ unsigned short LCDResInfo,LCDTypeInfo, VBType;/*301b*/
+ unsigned short VBInfo,TVInfo,LCDInfo, Set_VGAType;
+ unsigned short VBExtInfo;/*301lv*/
+ unsigned short SetFlag;
+ unsigned short NewFlickerMode;
+ unsigned short SelectCRT2Rate;
+
+ unsigned char *ROMAddr;
+ unsigned char *FBAddr;
+ unsigned long BaseAddr;
+ unsigned long RelIO;
+
+ unsigned char (*CR6B)[4];
+ unsigned char (*CR6E)[4];
+ unsigned char (*CR6F)[32];
+ unsigned char (*CR89)[2];
+
+ unsigned char (*SR15)[8];
+ unsigned char (*CR40)[8];
+
+ unsigned char *pSoftSetting;
+ unsigned char *pOutputSelect;
+
+ unsigned short *pRGBSenseData;
+ unsigned short *pRGBSenseData2; /*301b*/
+ unsigned short *pVideoSenseData;
+ unsigned short *pVideoSenseData2;
+ unsigned short *pYCSenseData;
+ unsigned short *pYCSenseData2;
+
+ unsigned char *pSR07;
+ unsigned char *CR49;
+ unsigned char *pSR1F;
+ unsigned char *AGPReg;
+ unsigned char *SR16;
+ unsigned char *pSR21;
+ unsigned char *pSR22;
+ unsigned char *pSR23;
+ unsigned char *pSR24;
+ unsigned char *SR25;
+ unsigned char *pSR31;
+ unsigned char *pSR32;
+ unsigned char *pSR33;
+ unsigned char *pSR36; /* alan 12/07/2006 */
+ unsigned char *pCRCF;
+ unsigned char *pCRD0; /* alan 12/07/2006 */
+ unsigned char *pCRDE; /* alan 12/07/2006 */
+ unsigned char *pCR8F; /* alan 12/07/2006 */
+ unsigned char *pSR40; /* alan 12/07/2006 */
+ unsigned char *pSR41; /* alan 12/07/2006 */
+ unsigned char *pDVOSetting;
+ unsigned char *pCR2E;
+ unsigned char *pCR2F;
+ unsigned char *pCR46;
+ unsigned char *pCR47;
+ unsigned char *pCRT2Data_1_2;
+ unsigned char *pCRT2Data_4_D;
+ unsigned char *pCRT2Data_4_E;
+ unsigned char *pCRT2Data_4_10;
+ struct XGI_MCLKDataStruct *MCLKData;
+ struct XGI_ECLKDataStruct *ECLKData;
+
+ unsigned char *XGI_TVDelayList;
+ unsigned char *XGI_TVDelayList2;
+ unsigned char *CHTVVCLKUNTSC;
+ unsigned char *CHTVVCLKONTSC;
+ unsigned char *CHTVVCLKUPAL;
+ unsigned char *CHTVVCLKOPAL;
+ unsigned char *NTSCTiming;
+ unsigned char *PALTiming;
+ unsigned char *HiTVExtTiming;
+ unsigned char *HiTVSt1Timing;
+ unsigned char *HiTVSt2Timing;
+ unsigned char *HiTVTextTiming;
+ unsigned char *YPbPr750pTiming;
+ unsigned char *YPbPr525pTiming;
+ unsigned char *YPbPr525iTiming;
+ unsigned char *HiTVGroup3Data;
+ unsigned char *HiTVGroup3Simu;
+ unsigned char *HiTVGroup3Text;
+ unsigned char *Ren525pGroup3;
+ unsigned char *Ren750pGroup3;
+ unsigned char *ScreenOffset;
+ unsigned char *pXGINew_DRAMTypeDefinition;
+ unsigned char *pXGINew_I2CDefinition ;
+ unsigned char *pXGINew_CR97 ;
+
+ struct XGI330_LCDCapStruct *LCDCapList;
+ struct XGI21_LVDSCapStruct *XG21_LVDSCapList;
+
+ struct XGI_TimingHStruct *TimingH;
+ struct XGI_TimingVStruct *TimingV;
+
+ struct XGI_StStruct *SModeIDTable;
+ struct XGI_StandTableStruct *StandTable;
+ struct XGI_ExtStruct *EModeIDTable;
+ struct XGI_Ext2Struct *RefIndex;
/* XGINew_CRT1TableStruct *CRT1Table; */
- XGI_CRT1TableStruct *XGINEWUB_CRT1Table;
- XGI_VCLKDataStruct *VCLKData;
- XGI_VBVCLKDataStruct *VBVCLKData;
- XGI_StResInfoStruct *StResInfo;
- XGI_ModeResInfoStruct *ModeResInfo;
- XGI_XG21CRT1Struct *UpdateCRT1;
-}; /* _VB_DEVICE_INFO */
-
-
-typedef struct
-{
- USHORT Horizontal_ACTIVE;
- USHORT Horizontal_FP;
- USHORT Horizontal_SYNC;
- USHORT Horizontal_BP;
- USHORT Vertical_ACTIVE;
- USHORT Vertical_FP;
- USHORT Vertical_SYNC;
- USHORT Vertical_BP;
+ struct XGI_CRT1TableStruct *XGINEWUB_CRT1Table;
+ struct XGI_VCLKDataStruct *VCLKData;
+ struct XGI_VBVCLKDataStruct *VBVCLKData;
+ struct XGI_StResInfoStruct *StResInfo;
+ struct XGI_ModeResInfoStruct *ModeResInfo;
+ struct XGI_XG21CRT1Struct *UpdateCRT1;
+}; /* _struct vb_device_info */
+
+
+struct TimingInfo
+{
+ unsigned short Horizontal_ACTIVE;
+ unsigned short Horizontal_FP;
+ unsigned short Horizontal_SYNC;
+ unsigned short Horizontal_BP;
+ unsigned short Vertical_ACTIVE;
+ unsigned short Vertical_FP;
+ unsigned short Vertical_SYNC;
+ unsigned short Vertical_BP;
double DCLK;
- UCHAR FrameRate;
- UCHAR Interlace;
- USHORT Margin;
-} TimingInfo;
+ unsigned char FrameRate;
+ unsigned char Interlace;
+ unsigned short Margin;
+};
#define _VB_STRUCT_
#endif /* _VB_STRUCT_ */
diff --git a/drivers/staging/xgifb/vb_table.h b/drivers/staging/xgifb/vb_table.h
index 781caefc56b..510ef767868 100644
--- a/drivers/staging/xgifb/vb_table.h
+++ b/drivers/staging/xgifb/vb_table.h
@@ -1,7 +1,7 @@
#define Tap4
-XGI_MCLKDataStruct XGI330New_MCLKData[]=
+struct XGI_MCLKDataStruct XGI330New_MCLKData[] =
{
{ 0x5c,0x23,0x01,166},
{ 0x5c,0x23,0x01,166},
@@ -13,7 +13,7 @@ XGI_MCLKDataStruct XGI330New_MCLKData[]=
{ 0x29,0x01,0x81,300}
};
//yilin modify for xgi20
-XGI_MCLKDataStruct XGI340New_MCLKData[]=
+struct XGI_MCLKDataStruct XGI340New_MCLKData[] =
{
{ 0x16,0x01,0x01,166},
{ 0x19,0x02,0x01,124},
@@ -25,7 +25,7 @@ XGI_MCLKDataStruct XGI340New_MCLKData[]=
{ 0x5c,0x23,0x01,166}
};
-XGI_MCLKDataStruct XGI27New_MCLKData[]=
+struct XGI_MCLKDataStruct XGI27New_MCLKData[] =
{
{ 0x5c,0x23,0x01,166},
{ 0x19,0x02,0x01,124},
@@ -37,7 +37,7 @@ XGI_MCLKDataStruct XGI27New_MCLKData[]=
{ 0x5c,0x23,0x01,166}
};
-XGI_ECLKDataStruct XGI330_ECLKData[]=
+struct XGI_ECLKDataStruct XGI330_ECLKData[] =
{
{ 0x7c,0x08,0x01,200},
{ 0x7c,0x08,0x01,200},
@@ -49,7 +49,7 @@ XGI_ECLKDataStruct XGI330_ECLKData[]=
{ 0x29,0x01,0x81,300}
};
//yilin modify for xgi20
-XGI_ECLKDataStruct XGI340_ECLKData[]=
+struct XGI_ECLKDataStruct XGI340_ECLKData[] =
{
{ 0x5c,0x23,0x01,166},
{ 0x55,0x84,0x01,123},
@@ -63,14 +63,14 @@ XGI_ECLKDataStruct XGI340_ECLKData[]=
-UCHAR XGI340_SR13[4][8]={
+unsigned char XGI340_SR13[4][8] = {
{0x35,0x45,0xb1,0x00,0x00,0x00,0x00,0x00},/* SR13 */
{0x41,0x51,0x5c,0x00,0x00,0x00,0x00,0x00},/* SR14 */
{0x31,0x42,0x42,0x00,0x00,0x00,0x00,0x00},/* SR18 */
{0x03,0x03,0x03,0x00,0x00,0x00,0x00,0x00}/* SR1B */
};
-UCHAR XGI340_cr41[24][8]=
+unsigned char XGI340_cr41[24][8] =
{{0x20,0x50,0x60,0x00,0x00,0x00,0x00,0x00},/* 0 CR41 */
{0xc4,0x40,0x84,0x00,0x00,0x00,0x00,0x00},/* 1 CR8A */
{0xc4,0x40,0x84,0x00,0x00,0x00,0x00,0x00},/* 2 CR8B */
@@ -98,7 +98,7 @@ UCHAR XGI340_cr41[24][8]=
};
-UCHAR XGI27_cr41[24][8]=
+unsigned char XGI27_cr41[24][8] =
{
{0x20,0x40,0x60,0x00,0x00,0x00,0x00,0x00},/* 0 CR41 */
{0xC4,0x40,0x84,0x00,0x00,0x00,0x00,0x00},/* 1 CR8A */
@@ -126,37 +126,7 @@ UCHAR XGI27_cr41[24][8]=
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}/* 23 CRC5 */
};
-
-#if 0
-UCHAR XGI27_cr41[24][8]=
-{
-{0x20,0x60,0x60,0x00,0x00,0x00,0x00,0x00},/* 0 CR41 */
-{0x04,0x44,0x84,0x00,0x00,0x00,0x00,0x00},/* 1 CR8A */
-{0x04,0x40,0x84,0x00,0x00,0x00,0x00,0x00},/* 2 CR8B */
-{0xb5,0x03,0xa4,0x00,0x00,0x00,0x00,0x00},/* 3 CR40[7],CR99[2:0],CR45[3:0]*/
-{0xf0,0xf5,0xf0,0x00,0x00,0x00,0x00,0x00},/* 4 CR59 */
-{0xa4,0x1C,0x24,0x00,0x00,0x00,0x00,0x00},/* 5 CR68 */
-{0x77,0x77,0x44,0x00,0x00,0x00,0x00,0x00},/* 6 CR69 */
-{0x77,0x77,0x44,0x00,0x00,0x00,0x00,0x00},/* 7 CR6A */
-{0xff,0xff,0xff,0x00,0x00,0x00,0x00,0x00},/* 8 CR6D */
-{0x55,0x55,0x55,0x00,0x00,0x00,0x00,0x00},/* 9 CR80 */
-{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/* 10 CR81 */
-{0x48,0xa8,0x48,0x00,0x00,0x00,0x00,0x00},/* 11 CR82 */
-{0x77,0x88,0x77,0x00,0x00,0x00,0x00,0x00},/* 12 CR85 */
-{0x88,0x88,0x88,0x00,0x00,0x00,0x00,0x00},/* 13 CR86 */
-{0x44,0x32,0x44,0x00,0x00,0x00,0x00,0x00},/* 14 CR90 */
-{0x44,0x33,0x44,0x00,0x00,0x00,0x00,0x00},/* 15 CR91 */
-{0x07,0x07,0x07,0x00,0x00,0x00,0x00,0x00},/* 16 CR92 */
-{0x44,0x63,0x44,0x00,0x00,0x00,0x00,0x00},/* 17 CR93 */
-{0x0A,0x14,0x0A,0x00,0x00,0x00,0x00,0x00},/* 18 CR94 */
-{0x0C,0x0B,0x0C,0x00,0x00,0x00,0x00,0x00},/* 19 CR95 */
-{0x05,0x22,0x05,0x00,0x00,0x00,0x00,0x00},/* 20 CR96 */
-{0xf0,0xf0,0xf0,0x00,0x00,0x00,0x00,0x00},/* 21 CRC3 */
-{0x03,0x00,0x02,0x00,0x00,0x00,0x00,0x00},/* 22 CRC4 */
-{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}/* 23 CRC5 */
-};
-#endif
-UCHAR XGI340_CR6B[8][4]={
+unsigned char XGI340_CR6B[8][4] = {
{0xaa,0xaa,0xaa,0xaa},
{0xaa,0xaa,0xaa,0xaa},
{0xaa,0xaa,0xaa,0xaa},
@@ -167,7 +137,7 @@ UCHAR XGI340_CR6B[8][4]={
{0x00,0x00,0x00,0x00}
};
-UCHAR XGI340_CR6E[8][4]={
+unsigned char XGI340_CR6E[8][4] = {
{0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00},
@@ -178,7 +148,7 @@ UCHAR XGI340_CR6E[8][4]={
{0x00,0x00,0x00,0x00}
};
-UCHAR XGI340_CR6F[8][32]={
+unsigned char XGI340_CR6F[8][32] = {
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
@@ -189,7 +159,7 @@ UCHAR XGI340_CR6F[8][32]={
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}
};
-UCHAR XGI340_CR89[8][2]={
+unsigned char XGI340_CR89[8][2] = {
{0x00,0x00},
{0x00,0x00},
{0x00,0x00},
@@ -200,11 +170,12 @@ UCHAR XGI340_CR89[8][2]={
{0x00,0x00}
};
/* CR47,CR48,CR49,CR4A,CR4B,CR4C,CR70,CR71,CR74,CR75,CR76,CR77 */
-UCHAR XGI340_AGPReg[12]={0x28,0x23,0x00,0x20,0x00,0x20,0x00,0x05,0xd0,0x10,0x10,0x00};
+unsigned char XGI340_AGPReg[12] = {0x28, 0x23, 0x00, 0x20, 0x00, 0x20, 0x00,
+ 0x05, 0xd0, 0x10, 0x10, 0x00};
-UCHAR XGI340_SR16[4]={0x03,0x83,0x03,0x83};
+unsigned char XGI340_SR16[4] = {0x03, 0x83, 0x03, 0x83};
-UCHAR XGI330_SR15_1[8][8]={
+unsigned char XGI330_SR15_1[8][8] = {
{0x0,0x0,0x00,0x00,0x20,0x20,0x00,0x00},
{0x5,0x15,0x15,0x15,0x15,0x15,0x00,0x00},
{0xba,0xba,0xba,0xba,0xBA,0xBA,0x00,0x00},
@@ -215,7 +186,7 @@ UCHAR XGI330_SR15_1[8][8]={
{0x0,0xa5,0xfb,0xf6,0xF6,0xF6,0x00,0x00}
};
-UCHAR XGI330_cr40_1[15][8]={
+unsigned char XGI330_cr40_1[15][8] = {
{0x66,0x40,0x40,0x28,0x24,0x24,0x00,0x00},
{0x66,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
@@ -233,14 +204,14 @@ UCHAR XGI330_cr40_1[15][8]={
{0x00,0xA2,0x00,0x00,0xA2,0xA2,0x00,0x00},
};
-UCHAR XGI330_sr25[]={0x00,0x0};
-UCHAR XGI330_sr31=0xc0;
-UCHAR XGI330_sr32=0x11;
-UCHAR XGI330_SR33=0x00;
-UCHAR XG40_CRCF=0x13;
-UCHAR XG40_DRAMTypeDefinition=0xFF ;
+unsigned char XGI330_sr25[] = {0x00, 0x0};
+unsigned char XGI330_sr31 = 0xc0;
+unsigned char XGI330_sr32 = 0x11;
+unsigned char XGI330_SR33 = 0x00;
+unsigned char XG40_CRCF = 0x13;
+unsigned char XG40_DRAMTypeDefinition = 0xFF ;
-XGI_StStruct XGI330_SModeIDTable[]=
+struct XGI_StStruct XGI330_SModeIDTable[] =
{
{0x01,0x9208,0x01,0x00,0x10,0x00,0x00,0x01,0x00},
{0x01,0x1210,0x14,0x01,0x00,0x01,0x00,0x01,0x00},
@@ -265,7 +236,7 @@ XGI_StStruct XGI330_SModeIDTable[]=
};
-XGI_ExtStruct XGI330_EModeIDTable[]=
+struct XGI_ExtStruct XGI330_EModeIDTable[] =
{
{0x6a,0x2212,0x0407,0x3a81,0x0102,0x08,0x07,0x00,0x00,0x07,0x0e},
{0x2e,0x0a1b,0x0306,0x3a57,0x0101,0x08,0x06,0x00,0x00,0x05,0x06},
@@ -337,7 +308,7 @@ XGI_ExtStruct XGI330_EModeIDTable[]=
{0xff,0x0000,0x0000,0x0000,0x0000,0x00,0x00,0x00,0x00,0x00,0x00}
};
-XGI_StandTableStruct XGI330_StandTable[]=
+struct XGI_StandTableStruct XGI330_StandTable[] =
{
/* MD_0_200 */
{
@@ -775,13 +746,13 @@ XGI_StandTableStruct XGI330_StandTable[]=
}
};
-XGI_TimingHStruct XGI_TimingH[]=
+struct XGI_TimingHStruct XGI_TimingH[] =
{{{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}}};
-XGI_TimingVStruct XGI_TimingV[]=
+struct XGI_TimingVStruct XGI_TimingV[] =
{{{0x00,0x00,0x00,0x00,0x00,0x00,0x00}}};
-XGI_XG21CRT1Struct XGI_UpdateCRT1Table[]=
+struct XGI_XG21CRT1Struct XGI_UpdateCRT1Table[] =
{
{0x01,0x27,0x91,0x8f,0xc0}, /* 00 */
{0x03,0x4f,0x83,0x8f,0xc0}, /* 01 */
@@ -802,7 +773,7 @@ XGI_XG21CRT1Struct XGI_UpdateCRT1Table[]=
{0x59,0x27,0x91,0x8f,0xc0} /* 16 */
};
-XGI_CRT1TableStruct XGI_CRT1Table[]=
+struct XGI_CRT1TableStruct XGI_CRT1Table[] =
{
{{0x2d,0x28,0x90,0x2c,0x90,0x00,0x04,0x00,
0xbf,0x1f,0x9c,0x8e,0x96,0xb9,0x30}}, /* 0x0 */
@@ -950,7 +921,7 @@ XGI_CRT1TableStruct XGI_CRT1Table[]=
0x03,0xDE,0xC0,0x84,0xBF,0x04,0x90}} /* 0x47 */
};
-XGI330_CHTVRegDataStruct XGI_CHTVRegUNTSC[] = {
+struct XGI330_CHTVRegDataStruct XGI_CHTVRegUNTSC[] = {
/* Index:000h,001h,002h,004h,003h,005h,006h,007h,008h,015h,01Fh,00Ch,00Dh,00Eh,00Fh,010h */
{{ 0x4A,0x77,0xBB,0x94,0x84,0x48,0xFE,0x50,0x04,0x00,0x80,0x00,0x00,0x00,0x00,0x01 }},/* 00 (640x200,640x400) */
{{ 0x4A,0x77,0xBB,0x94,0x84,0x48,0xFE,0x50,0x04,0x00,0x80,0x00,0x00,0x00,0x00,0x01 }},/* 01 (640x350) */
@@ -961,7 +932,7 @@ XGI330_CHTVRegDataStruct XGI_CHTVRegUNTSC[] = {
{{ 0xEE,0x77,0xBB,0x66,0x87,0x32,0x01,0x5A,0x04,0x00,0x80,0x1B,0xD4,0x2F,0x6F,0x00 }}/* 06 (1024x768) ;;5/6/02 */
};
-XGI330_CHTVRegDataStruct XGI_CHTVRegONTSC[]= {
+struct XGI330_CHTVRegDataStruct XGI_CHTVRegONTSC[] = {
/* Index:000h,001h,002h,004h,003h,005h,006h,007h,008h,015h,01Fh,00Ch,00Dh,00Eh,00Fh,010h */
{{ 0x49,0x77,0xBB,0x7B,0x84,0x34,0x00,0x50,0x04,0x00,0x80,0x00,0x00,0x00,0x00,0x01 }},/* 00 (640x200,640x400) */
{{ 0x49,0x77,0xBB,0x7B,0x84,0x34,0x00,0x50,0x04,0x00,0x80,0x00,0x00,0x00,0x00,0x01 }},/* 01 (640x350) */
@@ -972,7 +943,7 @@ XGI330_CHTVRegDataStruct XGI_CHTVRegONTSC[]= {
{{ 0xED,0x77,0xBB,0x66,0x8C,0x21,0x02,0x5A,0x04,0x00,0x80,0x1F,0xA0,0x7E,0x73,0x00 }}/* 06 (1024x768) ;;5/6/02 */
};
-XGI330_CHTVRegDataStruct XGI_CHTVRegUPAL[]= {
+struct XGI330_CHTVRegDataStruct XGI_CHTVRegUPAL[] = {
/* Index:000h,001h,002h,004h,003h,005h,006h,007h,008h,015h,01Fh,00Ch,00Dh,00Eh,00Fh,010h */
{{ 0x41,0x7F,0xB7,0x34,0xAD,0x50,0x34,0x83,0x05,0x00,0x80,0x00,0x00,0x00,0x00,0x01 }},/* ; 00 (640x200,640x400) */
{{ 0x41,0x7F,0xB7,0x80,0x85,0x50,0x00,0x83,0x05,0x00,0x80,0x00,0x00,0x00,0x00,0x01 }},/* ; 01 (640x350) */
@@ -983,7 +954,7 @@ XGI330_CHTVRegDataStruct XGI_CHTVRegUPAL[]= {
{{ 0xE5,0x7F,0xB7,0x1D,0xA7,0x3E,0x04,0x5A,0x05,0x00,0x80,0x20,0x3E,0xE4,0x22,0x00 }}/* ; 06 (1024x768) ;;1/12/02 */
};
-XGI330_CHTVRegDataStruct XGI_CHTVRegOPAL[]={
+struct XGI330_CHTVRegDataStruct XGI_CHTVRegOPAL[] = {
/* Index:000,0x01,0x02,0x04,0x03,0x05,0x06,0x07,0x08,0x15,0x1F,0x0C,0x0D,0x0E,0x0F,0x10h */
{{ 0x41,0x7F,0xB7,0x36,0xAD,0x50,0x34,0x83,0x05,0x00,0x80,0x00,0x00,0x00,0x00,0x01 }},/* 00 (640x200,640x400) */
{{ 0x41,0x7F,0xB7,0x86,0x85,0x50,0x00,0x83,0x05,0x00,0x80,0x00,0x00,0x00,0x00,0x01 }},/* 01 (640x350) */
@@ -994,14 +965,14 @@ XGI330_CHTVRegDataStruct XGI_CHTVRegOPAL[]={
{{ 0xE4,0x7F,0xB7,0x1E,0xAF,0x29,0x37,0x5A,0x05,0x00,0x80,0x25,0x8C,0xB2,0x2A,0x00 }}/* 06 (1024x768) ;;1/12/02 */
};
-UCHAR XGI_CH7017LV1024x768[]={0x60,0x02,0x00,0x07,0x40,0xED,0xA3,
- 0xC8,0xC7,0xAC,0xE0,0x02};
-UCHAR XGI_CH7017LV1400x1050[]={0x60,0x03,0x11,0x00,0x40,0xE3,0xAD,
- 0xDB,0xF6,0xAC,0xE0,0x02};
+unsigned char XGI_CH7017LV1024x768[] = {0x60, 0x02, 0x00, 0x07, 0x40, 0xED, 0xA3,
+ 0xC8, 0xC7, 0xAC, 0xE0, 0x02};
+unsigned char XGI_CH7017LV1400x1050[] = {0x60, 0x03, 0x11, 0x00, 0x40, 0xE3, 0xAD,
+ 0xDB, 0xF6, 0xAC, 0xE0, 0x02};
/*add for new UNIVGABIOS*/
-XGI330_LCDDataStruct XGI_StLCD1024x768Data[]=
+struct XGI330_LCDDataStruct XGI_StLCD1024x768Data[] =
{
{ 62, 25, 800, 546,1344, 806},
{ 32, 15, 930, 546,1344, 806},
@@ -1012,7 +983,7 @@ XGI330_LCDDataStruct XGI_StLCD1024x768Data[]=
{ 1, 1,1344, 806,1344, 806}
};
-XGI330_LCDDataStruct XGI_ExtLCD1024x768Data[]=
+struct XGI330_LCDDataStruct XGI_ExtLCD1024x768Data[] =
{
{ 42, 25,1536, 419,1344, 806}, /* { 12, 5, 896, 512,1344, 806}, // alan 09/12/2003 */
{ 48, 25,1536, 369,1344, 806}, /* { 12, 5, 896, 510,1344, 806}, // alan 09/12/2003 */
@@ -1029,7 +1000,7 @@ XGI330_LCDDataStruct XGI_ExtLCD1024x768Data[]=
{ 1, 1,1344, 806,1344, 806}
};
-/*XGI330_LCDDataStruct XGI_St2LCD1024x768Data[]=
+/*struct XGI330_LCDDataStruct XGI_St2LCD1024x768Data[] =
{
{ 62, 25, 800, 546,1344, 806},
{ 32, 15, 930, 546,1344, 806},
@@ -1040,7 +1011,7 @@ XGI330_LCDDataStruct XGI_ExtLCD1024x768Data[]=
{ 1, 1,1344, 806,1344, 806}
};*/
-XGI330_LCDDataStruct XGI_CetLCD1024x768Data[]=
+struct XGI330_LCDDataStruct XGI_CetLCD1024x768Data[] =
{
{ 1,1,1344,806,1344,806 }, /* ; 00 (320x200,320x400,640x200,640x400) */
{ 1,1,1344,806,1344,806 }, /* 01 (320x350,640x350) */
@@ -1051,7 +1022,7 @@ XGI330_LCDDataStruct XGI_CetLCD1024x768Data[]=
{ 1,1,1344,806,1344,806 } /* 06 (1024x768x60Hz) */
};
-XGI330_LCDDataStruct XGI_StLCD1280x1024Data[]=
+struct XGI330_LCDDataStruct XGI_StLCD1280x1024Data[] =
{
{ 22, 5, 800, 510,1650,1088},
{ 22, 5, 800, 510,1650,1088},
@@ -1063,7 +1034,7 @@ XGI330_LCDDataStruct XGI_StLCD1280x1024Data[]=
{ 1, 1,1688,1066,1688,1066}
};
-XGI330_LCDDataStruct XGI_ExtLCD1280x1024Data[]=
+struct XGI330_LCDDataStruct XGI_ExtLCD1280x1024Data[] =
{
{ 211, 60,1024, 501,1688,1066},
{ 211, 60,1024, 508,1688,1066},
@@ -1075,7 +1046,7 @@ XGI330_LCDDataStruct XGI_ExtLCD1280x1024Data[]=
{ 1, 1,1688,1066,1688,1066}
};
-XGI330_LCDDataStruct XGI_St2LCD1280x1024Data[]=
+struct XGI330_LCDDataStruct XGI_St2LCD1280x1024Data[] =
{
{ 22, 5, 800, 510,1650,1088},
{ 22, 5, 800, 510,1650,1088},
@@ -1087,7 +1058,7 @@ XGI330_LCDDataStruct XGI_St2LCD1280x1024Data[]=
{ 1, 1,1688,1066,1688,1066}
};
-XGI330_LCDDataStruct XGI_CetLCD1280x1024Data[]=
+struct XGI330_LCDDataStruct XGI_CetLCD1280x1024Data[] =
{
{ 1,1,1688,1066,1688,1066 }, /* 00 (320x200,320x400,640x200,640x400) */
{ 1,1,1688,1066,1688,1066 }, /* 01 (320x350,640x350) */
@@ -1100,7 +1071,7 @@ XGI330_LCDDataStruct XGI_CetLCD1280x1024Data[]=
{ 1,1,1688,1066,1688,1066 } /* 08 (1400x1050x60Hz) */
};
-XGI330_LCDDataStruct XGI_StLCD1400x1050Data[]=
+struct XGI330_LCDDataStruct XGI_StLCD1400x1050Data[] =
{
{ 211,100,2100,408,1688,1066 }, /* 00 (320x200,320x400,640x200,640x400) */
{ 211,64,1536,358,1688,1066 }, /* 01 (320x350,640x350) */
@@ -1113,7 +1084,7 @@ XGI330_LCDDataStruct XGI_StLCD1400x1050Data[]=
{ 1,1,1688,1066,1688,1066 } /* 08 (1400x1050x60Hz) */
};
-XGI330_LCDDataStruct XGI_ExtLCD1400x1050Data[]=
+struct XGI330_LCDDataStruct XGI_ExtLCD1400x1050Data[] =
{
{ 211,100,2100,408,1688,1066 }, /* 00 (320x200,320x400,640x200,640x400) */
{ 211,64,1536,358,1688,1066 }, /* 01 (320x350,640x350) */
@@ -1126,7 +1097,7 @@ XGI330_LCDDataStruct XGI_ExtLCD1400x1050Data[]=
{ 1,1,1688,1066,1688,1066 } /* 08 (1400x1050x60Hz) */
};
-XGI330_LCDDataStruct XGI_ExtLCD1600x1200Data[]=
+struct XGI330_LCDDataStruct XGI_ExtLCD1600x1200Data[] =
{
{ 4,1,1620,420,2160,1250 }, /* { 3,1,2160,425,2160,1250 }, // 00 (320x200,320x400,640x200,640x400) // alan 10/14/2003 */
{ 27,7,1920,375,2160,1250 }, /* 01 (320x350,640x350) */
@@ -1140,7 +1111,7 @@ XGI330_LCDDataStruct XGI_ExtLCD1600x1200Data[]=
{ 1,1,2160,1250,2160,1250 } /* 09 (1600x1200x60Hz) ;302lv */
};
-XGI330_LCDDataStruct XGI_StLCD1600x1200Data[]=
+struct XGI330_LCDDataStruct XGI_StLCD1600x1200Data[] =
{
{ 27,4,800,500,2160,1250 },/* 00 (320x200,320x400,640x200,640x400) */
{ 27,4,800,500,2160,1250 },/* 01 (320x350,640x350) */
@@ -1154,7 +1125,7 @@ XGI330_LCDDataStruct XGI_StLCD1600x1200Data[]=
{ 1,1,2160,1250,2160,1250 } /* 09 (1600x1200) */
};
-XGI330_LCDDataStruct XGI_CetLCD1400x1050Data[]=
+struct XGI330_LCDDataStruct XGI_CetLCD1400x1050Data[] =
{
{ 1,1,1688,1066,1688,1066 }, /* 00 (320x200,320x400,640x200,640x400) */
{ 1,1,1688,1066,1688,1066 }, /* 01 (320x350,640x350) */
@@ -1167,7 +1138,7 @@ XGI330_LCDDataStruct XGI_CetLCD1400x1050Data[]=
{ 1,1,1688,1066,1688,1066 } /* 08 (1400x1050x60Hz) */
};
-XGI330_LCDDataStruct XGI_NoScalingData[]=
+struct XGI330_LCDDataStruct XGI_NoScalingData[] =
{
{ 1, 1, 800, 449, 800, 449},
{ 1, 1, 800, 449, 800, 449},
@@ -1179,7 +1150,7 @@ XGI330_LCDDataStruct XGI_NoScalingData[]=
{ 1, 1,1688,1066,1688,1066}
};
-XGI330_LCDDataStruct XGI_ExtLCD1024x768x75Data[]=
+struct XGI330_LCDDataStruct XGI_ExtLCD1024x768x75Data[] =
{
{42,25,1536,419,1344,806 }, /* ; 00 (320x200,320x400,640x200,640x400) */
{48,25,1536,369,1344,806 }, /* ; 01 (320x350,640x350) */
@@ -1190,7 +1161,7 @@ XGI330_LCDDataStruct XGI_ExtLCD1024x768x75Data[]=
{1,1,1312,800,1312,800 } /* ; 06 (1024x768x75Hz) */
};
-XGI330_LCDDataStruct XGI_StLCD1024x768x75Data[]=
+struct XGI330_LCDDataStruct XGI_StLCD1024x768x75Data[] =
{
{42,25,1536,419,1344,806 }, /* ; 00 (320x200,320x400,640x200,640x400) */
{48,25,1536,369,1344,806 }, /* ; 01 (320x350,640x350) */
@@ -1201,7 +1172,7 @@ XGI330_LCDDataStruct XGI_StLCD1024x768x75Data[]=
{1,1,1312,800,1312,800 } /* ; 06 (1024x768x75Hz) */
};
-XGI330_LCDDataStruct XGI_CetLCD1024x768x75Data[]=
+struct XGI330_LCDDataStruct XGI_CetLCD1024x768x75Data[] =
{
{1,1,1312,800,1312,800}, /* ; 00 (320x200,320x400,640x200,640x400) */
{1,1,1312,800,1312,800}, /* ; 01 (320x350,640x350) */
@@ -1212,7 +1183,7 @@ XGI330_LCDDataStruct XGI_CetLCD1024x768x75Data[]=
{1,1,1312,800,1312,800} /* ; 06 (1024x768x75Hz) */
};
-XGI330_LCDDataStruct XGI_ExtLCD1280x1024x75Data[]=
+struct XGI330_LCDDataStruct XGI_ExtLCD1280x1024x75Data[] =
{
{211,60,1024,501,1688,1066 }, /* ; 00 (320x200,320x400,640x200,640x400) */
{211,60,1024,508,1688,1066 }, /* ; 01 (320x350,640x350) */
@@ -1224,7 +1195,7 @@ XGI330_LCDDataStruct XGI_ExtLCD1280x1024x75Data[]=
{1,1,1688,1066,1688,1066 } /* ; 07 (1280x1024x75Hz) */
};
-XGI330_LCDDataStruct XGI_StLCD1280x1024x75Data[]=
+struct XGI330_LCDDataStruct XGI_StLCD1280x1024x75Data[] =
{
{211,60,1024,501,1688,1066 }, /* ; 00 (320x200,320x400,640x200,640x400) */
{211,60,1024,508,1688,1066 }, /* ; 01 (320x350,640x350) */
@@ -1236,7 +1207,7 @@ XGI330_LCDDataStruct XGI_StLCD1280x1024x75Data[]=
{1,1,1688,1066,1688,1066 } /* ; 07 (1280x1024x75Hz) */
};
-XGI330_LCDDataStruct XGI_CetLCD1280x1024x75Data[]=
+struct XGI330_LCDDataStruct XGI_CetLCD1280x1024x75Data[] =
{
{1,1,1688,1066,1688,1066}, /* ; 00 (320x200,320x400,640x200,640x400) */
{1,1,1688,1066,1688,1066}, /* ; 01 (320x350,640x350) */
@@ -1248,7 +1219,7 @@ XGI330_LCDDataStruct XGI_CetLCD1280x1024x75Data[]=
{1,1,1688,1066,1688,1066} /* ; 07 (1280x1024x75Hz) */
};
-XGI330_LCDDataStruct XGI_NoScalingDatax75[]=
+struct XGI330_LCDDataStruct XGI_NoScalingDatax75[] =
{
{1,1,800,449,800,449 }, /* ; 00 (320x200,320x400,640x200,640x400) */
{1,1,800,449,800,449 }, /* ; 01 (320x350,640x350) */
@@ -1263,7 +1234,7 @@ XGI330_LCDDataStruct XGI_NoScalingDatax75[]=
{1,1,1688,806,1688,806 } /* ; 0A (1280x768x75Hz) */
};
-XGI330_LCDDataDesStruct XGI_ExtLCDDes1024x768Data[]=
+struct XGI330_LCDDataDesStruct XGI_ExtLCDDes1024x768Data[] =
{
{ 9,1057,0, 771 }, /* ; 00 (320x200,320x400,640x200,640x400) */
{ 9,1057,0, 771 }, /* ; 01 (320x350,640x350) */
@@ -1274,7 +1245,7 @@ XGI330_LCDDataDesStruct XGI_ExtLCDDes1024x768Data[]=
{ 9,1057,805, 770 } /* ; 06 (1024x768x60Hz) */
};
-XGI330_LCDDataDesStruct XGI_StLCDDes1024x768Data[]=
+struct XGI330_LCDDataDesStruct XGI_StLCDDes1024x768Data[] =
{
{ 9,1057,737,703 }, /* ; 00 (320x200,320x400,640x200,640x400) */
{ 9,1057,686,651 }, /* ; 01 (320x350,640x350) */
@@ -1285,7 +1256,7 @@ XGI330_LCDDataDesStruct XGI_StLCDDes1024x768Data[]=
{ 9,1057,805,770 } /* ; 06 (1024x768x60Hz) */
};
-XGI330_LCDDataDesStruct XGI_CetLCDDes1024x768Data[]=
+struct XGI330_LCDDataDesStruct XGI_CetLCDDes1024x768Data[] =
{
{ 1152,856,622,587 }, /* ; 00 (320x200,320x400,640x200,640x400) */
{ 1152,856,597,562 }, /* ; 01 (320x350,640x350) */
@@ -1296,7 +1267,7 @@ XGI330_LCDDataDesStruct XGI_CetLCDDes1024x768Data[]=
{ 0,1048,805,770 } /* ; 06 (1024x768x60Hz) */
};
-XGI330_LCDDataDesStruct XGI_ExtLCDDLDes1280x1024Data[]=
+struct XGI330_LCDDataDesStruct XGI_ExtLCDDLDes1280x1024Data[] =
{
{ 18,1346,981,940 },/* 00 (320x200,320x400,640x200,640x400) */
{ 18,1346,926,865 },/* 01 (320x350,640x350) */
@@ -1308,7 +1279,7 @@ XGI330_LCDDataDesStruct XGI_ExtLCDDLDes1280x1024Data[]=
{ 18,1346,1065,1024 }/* 07 (1280x1024x60Hz) */
};
-XGI330_LCDDataDesStruct XGI_StLCDDLDes1280x1024Data[]=
+struct XGI330_LCDDataDesStruct XGI_StLCDDLDes1280x1024Data[] =
{
{ 18,1346,970,907 },/* 00 (320x200,320x400,640x200,640x400) */
{ 18,1346,917,854 },/* 01 (320x350,640x350) */
@@ -1320,7 +1291,7 @@ XGI330_LCDDataDesStruct XGI_StLCDDLDes1280x1024Data[]=
{ 18,1346,1065,1024 }/* 07 (1280x1024x60Hz) */
};
-XGI330_LCDDataDesStruct XGI_CetLCDDLDes1280x1024Data[]=
+struct XGI330_LCDDataDesStruct XGI_CetLCDDLDes1280x1024Data[] =
{
{ 1368,1008,752,711 }, /* 00 (320x200,320x400,640x200,640x400) */
{ 1368,1008,729,688 }, /* 01 (320x350,640x350) */
@@ -1332,7 +1303,7 @@ XGI330_LCDDataDesStruct XGI_CetLCDDLDes1280x1024Data[]=
{ 18,1346,1065,1024 } /* 07 (1280x1024x60Hz) */
};
-XGI330_LCDDataDesStruct XGI_ExtLCDDes1280x1024Data[]=
+struct XGI330_LCDDataDesStruct XGI_ExtLCDDes1280x1024Data[] =
{
{ 9,1337,981,940 }, /* ; 00 (320x200,320x400,640x200,640x400) */
{ 9,1337,926,884 }, /* ; 01 (320x350,640x350) alan, 2003/09/30 */
@@ -1344,7 +1315,7 @@ XGI330_LCDDataDesStruct XGI_ExtLCDDes1280x1024Data[]=
{ 9,1337,1065,1024 } /* ; 07 (1280x1024x60Hz) */
};
-XGI330_LCDDataDesStruct XGI_StLCDDes1280x1024Data[]=
+struct XGI330_LCDDataDesStruct XGI_StLCDDes1280x1024Data[] =
{
{ 9,1337,970,907 }, /* ; 00 (320x200,320x400,640x200,640x400) */
{ 9,1337,917,854 }, /* ; 01 (320x350,640x350) */
@@ -1356,7 +1327,7 @@ XGI330_LCDDataDesStruct XGI_StLCDDes1280x1024Data[]=
{ 9,1337,1065,1024 } /* ; 07 (1280x1024x60Hz) */
};
-XGI330_LCDDataDesStruct XGI_CetLCDDes1280x1024Data[]=
+struct XGI330_LCDDataDesStruct XGI_CetLCDDes1280x1024Data[] =
{
{ 1368,1008,752,711 }, /* 00 (320x200,320x400,640x200,640x400) */
{ 1368,1008,729,688 }, /* 01 (320x350,640x350) */
@@ -1368,7 +1339,7 @@ XGI330_LCDDataDesStruct XGI_CetLCDDes1280x1024Data[]=
{ 9,1337,1065,1024 } /* 07 (1280x1024x60Hz) */
};
-XGI330_LCDDataDesStruct XGI_StLCDDLDes1400x1050Data[]=
+struct XGI330_LCDDataDesStruct XGI_StLCDDLDes1400x1050Data[] =
{
{ 18,1464,0,1051 }, /* 00 (320x200,320x400,640x200,640x400) */
{ 18,1464,0,1051 }, /* 01 (320x350,640x350) */
@@ -1381,7 +1352,7 @@ XGI330_LCDDataDesStruct XGI_StLCDDLDes1400x1050Data[]=
{ 18,1464,0,1051 } /* 08 (1400x1050x60Hz) */
};
-XGI330_LCDDataDesStruct XGI_ExtLCDDLDes1400x1050Data[]=
+struct XGI330_LCDDataDesStruct XGI_ExtLCDDLDes1400x1050Data[] =
{
{ 18,1464,0,1051 }, /* 00 (320x200,320x400,640x200,640x400) */
{ 18,1464,0,1051 }, /* 01 (320x350,640x350) */
@@ -1394,7 +1365,7 @@ XGI330_LCDDataDesStruct XGI_ExtLCDDLDes1400x1050Data[]=
{ 18,1464,0,1051 } /* 08 (1400x1050x60Hz) */
};
-XGI330_LCDDataDesStruct XGI_StLCDDes1400x1050Data[]=
+struct XGI330_LCDDataDesStruct XGI_StLCDDes1400x1050Data[] =
{
{ 9,1455,0,1051 },/* 00 (320x200,320x400,640x200,640x400) */
{ 9,1455,0,1051 },/* 01 (320x350,640x350) */
@@ -1407,7 +1378,7 @@ XGI330_LCDDataDesStruct XGI_StLCDDes1400x1050Data[]=
{ 9,1455,0,1051 } /* 08 (1400x1050x60Hz) */
};
-XGI330_LCDDataDesStruct XGI_ExtLCDDes1400x1050Data[]=
+struct XGI330_LCDDataDesStruct XGI_ExtLCDDes1400x1050Data[] =
{
{ 9,1455,0,1051 },/* 00 (320x200,320x400,640x200,640x400) */
{ 9,1455,0,1051 },/* 01 (320x350,640x350) */
@@ -1420,7 +1391,7 @@ XGI330_LCDDataDesStruct XGI_ExtLCDDes1400x1050Data[]=
{ 9,1455,0,1051 } /* 08 (1400x1050x60Hz) */
};
-XGI330_LCDDataDesStruct XGI_CetLCDDes1400x1050Data[]=
+struct XGI330_LCDDataDesStruct XGI_CetLCDDes1400x1050Data[] =
{
{ 1308,1068,781,766 }, /* 00 (320x200,320x400,640x200,640x400) */
{ 1308,1068,781,766 }, /* 01 (320x350,640x350) */
@@ -1433,7 +1404,7 @@ XGI330_LCDDataDesStruct XGI_CetLCDDes1400x1050Data[]=
{ 18,1464,0,1051 } /* 08 (1400x1050x60Hz) */
};
-XGI330_LCDDataDesStruct XGI_CetLCDDes1400x1050Data2[]=
+struct XGI330_LCDDataDesStruct XGI_CetLCDDes1400x1050Data2[] =
{
{ 0,1448,0,1051 }, /* 00 (320x200,320x400,640x200,640x400) */
{ 0,1448,0,1051 }, /* 01 (320x350,640x350) */
@@ -1444,7 +1415,7 @@ XGI330_LCDDataDesStruct XGI_CetLCDDes1400x1050Data2[]=
-XGI330_LCDDataDesStruct XGI_ExtLCDDLDes1600x1200Data[]=
+struct XGI330_LCDDataDesStruct XGI_ExtLCDDLDes1600x1200Data[] =
{
{ 18,1682,0,1201 }, /* 00 (320x200,320x400,640x200,640x400) */
{ 18,1682,0,1201 }, /* 01 (320x350,640x350) */
@@ -1458,7 +1429,7 @@ XGI330_LCDDataDesStruct XGI_ExtLCDDLDes1600x1200Data[]=
{ 18,1682,0,1201 } /* 09 (1600x1200x60Hz) */
};
-XGI330_LCDDataDesStruct XGI_StLCDDLDes1600x1200Data[]=
+struct XGI330_LCDDataDesStruct XGI_StLCDDLDes1600x1200Data[] =
{
{ 18,1682,1150,1101 }, /* 00 (320x200,320x400,640x200,640x400) */
{ 18,1682,1083,1034 }, /* 01 (320x350,640x350) */
@@ -1472,7 +1443,7 @@ XGI330_LCDDataDesStruct XGI_StLCDDLDes1600x1200Data[]=
{ 18,1682,0,1201 } /* 09 (1600x1200x60Hz) */
};
-XGI330_LCDDataDesStruct XGI_ExtLCDDes1600x1200Data[]=
+struct XGI330_LCDDataDesStruct XGI_ExtLCDDes1600x1200Data[] =
{
{ 9,1673,0,1201 },/* 00 (320x200,320x400,640x200,640x400) */
{ 9,1673,0,1201 },/* 01 (320x350,640x350) */
@@ -1486,7 +1457,7 @@ XGI330_LCDDataDesStruct XGI_ExtLCDDes1600x1200Data[]=
{ 9,1673,0,1201 } /* 09 (1600x1200x60Hz) */
};
-XGI330_LCDDataDesStruct XGI_StLCDDes1600x1200Data[]=
+struct XGI330_LCDDataDesStruct XGI_StLCDDes1600x1200Data[] =
{
{ 9,1673,1150,1101 },/* 00 (320x200,320x400,640x200,640x400) */
{ 9,1673,1083,1034 },/* 01 (320x350,640x350) */
@@ -1500,7 +1471,7 @@ XGI330_LCDDataDesStruct XGI_StLCDDes1600x1200Data[]=
{ 9,1673,0,1201 } /* 09 (1600x1200x60Hz) */
};
-XGI330_LCDDataDesStruct2 XGI_NoScalingDesData[]=
+struct XGI330_LCDDataDesStruct2 XGI_NoScalingDesData[] =
{
{ 9,657,448,405,96,2 }, /* 00 (320x200,320x400,640x200,640x400) */
{ 9,657,448,355,96,2 }, /* 01 (320x350,640x350) */
@@ -1515,7 +1486,7 @@ XGI330_LCDDataDesStruct2 XGI_NoScalingDesData[]=
{ 9,1337,0,771,112,6 } /* 0A (1280x768x60Hz) */
};
-XGI330_LCDDataDesStruct XGI_ExtLCDDes1024x768x75Data[]= /* ;;1024x768x75Hz */
+struct XGI330_LCDDataDesStruct XGI_ExtLCDDes1024x768x75Data[] = /* ;;1024x768x75Hz */
{
{9,1049,0,769}, /* ; 00 (320x200,320x400,640x200,640x400) */
{9,1049,0,769}, /* ; 01 (320x350,640x350) */
@@ -1526,7 +1497,7 @@ XGI330_LCDDataDesStruct XGI_ExtLCDDes1024x768x75Data[]= /* ;;1024x768x75Hz */
{9,1049,0,769} /* ; 06 (1024x768x75Hz) */
};
-XGI330_LCDDataDesStruct XGI_StLCDDes1024x768x75Data[]=
+struct XGI330_LCDDataDesStruct XGI_StLCDDes1024x768x75Data[] =
{
{9,1049,0,769}, /* ; 00 (320x200,320x400,640x200,640x400) */
{9,1049,0,769}, /* ; 01 (320x350,640x350) */
@@ -1537,7 +1508,7 @@ XGI330_LCDDataDesStruct XGI_StLCDDes1024x768x75Data[]=
{9,1049,0,769} /* ; 06 (1024x768x75Hz) */
};
-XGI330_LCDDataDesStruct XGI_CetLCDDes1024x768x75Data[]= /* ;;1024x768x75Hz */
+struct XGI330_LCDDataDesStruct XGI_CetLCDDes1024x768x75Data[] = /* ;;1024x768x75Hz */
{
{1152,856,622,587}, /* ; 00 (320x200,320x400,640x200,640x400) */
{1152,856,597,562}, /* ; 01 (320x350,640x350) */
@@ -1548,7 +1519,7 @@ XGI330_LCDDataDesStruct XGI_CetLCDDes1024x768x75Data[]= /* ;;1024x768x75Hz */
{9,1049,0,769} /* ; 06 (1024x768x75Hz) */
};
-XGI330_LCDDataDesStruct XGI_ExtLCDDLDes1280x1024x75Data[]= /* ;;1280x1024x75Hz */
+struct XGI330_LCDDataDesStruct XGI_ExtLCDDLDes1280x1024x75Data[] = /* ;;1280x1024x75Hz */
{
{18,1314,0,1025 },/* ; 00 (320x200,320x400,640x200,640x400) */
{18,1314,0,1025 },/* ; 01 (320x350,640x350) */
@@ -1560,7 +1531,7 @@ XGI330_LCDDataDesStruct XGI_ExtLCDDLDes1280x1024x75Data[]= /* ;;1280x10
{18,1314,0,1025 }/* ; 07 (1280x1024x60Hz) */
};
-XGI330_LCDDataDesStruct XGI_StLCDDLDes1280x1024x75Data[]=
+struct XGI330_LCDDataDesStruct XGI_StLCDDLDes1280x1024x75Data[] =
{
{18,1314,0,1025 },/* ; 00 (320x200,320x400,640x200,640x400) */
{18,1314,0,1025 },/* ; 01 (320x350,640x350) */
@@ -1572,7 +1543,7 @@ XGI330_LCDDataDesStruct XGI_StLCDDLDes1280x1024x75Data[]=
{18,1314,0,1025 }/* ; 07 (1280x1024x60Hz) */
};
-XGI330_LCDDataDesStruct XGI_CetLCDDLDes1280x1024x75Data[]= /* 1280x1024x75Hz */
+struct XGI330_LCDDataDesStruct XGI_CetLCDDLDes1280x1024x75Data[] = /* 1280x1024x75Hz */
{
{1368,1008,752,711}, /* ; 00 (320x200,320x400,640x200,640x400) */
{1368,1008,729,688}, /* ; 01 (320x350,640x350) */
@@ -1584,7 +1555,7 @@ XGI330_LCDDataDesStruct XGI_CetLCDDLDes1280x1024x75Data[]= /* 1280x1024x75Hz */
{18,1314,0,1025} /* ; 07 (1280x1024x75Hz) */
};
-XGI330_LCDDataDesStruct XGI_ExtLCDDes1280x1024x75Data[]= /* ;;1280x1024x75Hz */
+struct XGI330_LCDDataDesStruct XGI_ExtLCDDes1280x1024x75Data[] = /* ;;1280x1024x75Hz */
{
{9,1305,0,1025},/* ; 00 (320x200,320x400,640x200,640x400) */
{9,1305,0,1025},/* ; 01 (320x350,640x350) */
@@ -1596,7 +1567,7 @@ XGI330_LCDDataDesStruct XGI_ExtLCDDes1280x1024x75Data[]= /* ;;1280x1024
{9,1305,0,1025} /* ; 07 (1280x1024x60Hz) */
};
-XGI330_LCDDataDesStruct XGI_StLCDDes1280x1024x75Data[]=
+struct XGI330_LCDDataDesStruct XGI_StLCDDes1280x1024x75Data[] =
{
{9,1305,0,1025},/* ; 00 (320x200,320x400,640x200,640x400) */
{9,1305,0,1025},/* ; 01 (320x350,640x350) */
@@ -1608,7 +1579,7 @@ XGI330_LCDDataDesStruct XGI_StLCDDes1280x1024x75Data[]=
{9,1305,0,1025} /* ; 07 (1280x1024x60Hz) */
};
-XGI330_LCDDataDesStruct XGI_CetLCDDes1280x1024x75Data[]= /* 1280x1024x75Hz */
+struct XGI330_LCDDataDesStruct XGI_CetLCDDes1280x1024x75Data[] = /* 1280x1024x75Hz */
{
{1368,1008,752,711}, /* ; 00 (320x200,320x400,640x200,640x400) */
{1368,1008,729,688}, /* ; 01 (320x350,640x350) */
@@ -1620,7 +1591,7 @@ XGI330_LCDDataDesStruct XGI_CetLCDDes1280x1024x75Data[]= /* 1280x1024x75Hz */
{9,1305,0,1025} /* ; 07 (1280x1024x75Hz) */
};
-XGI330_LCDDataDesStruct2 XGI_NoScalingDesDatax75[]= /* Scaling LCD 75Hz */
+struct XGI330_LCDDataDesStruct2 XGI_NoScalingDesDatax75[] = /* Scaling LCD 75Hz */
{
{9,657,448,405,96,2}, /* ; 00 (320x200,320x400,640x200,640x400) */
{9,657,448,355,96,2}, /* ; 01 (320x350,640x350) */
@@ -1635,7 +1606,7 @@ XGI330_LCDDataDesStruct2 XGI_NoScalingDesDatax75[]= /* Scaling LCD 75Hz */
{9,1337,0,771,112,6} /* ; 0A (1280x768x60Hz) */
};
-XGI330_TVDataStruct XGI_StPALData[]=
+struct XGI330_TVDataStruct XGI_StPALData[] =
{
{ 1, 1, 864, 525,1270, 400, 100, 0, 760},
{ 1, 1, 864, 525,1270, 350, 100, 0, 760},
@@ -1645,7 +1616,7 @@ XGI330_TVDataStruct XGI_StPALData[]=
{ 1, 1, 864, 525,1270, 600, 50, 0, 0}
};
-XGI330_TVDataStruct XGI_ExtPALData[]=
+struct XGI330_TVDataStruct XGI_ExtPALData[] =
{
{ 2, 1,1080, 463,1270, 500, 50, 0, 50},
{ 15, 7,1152, 413,1270, 500, 50, 0, 50},
@@ -1657,7 +1628,7 @@ XGI330_TVDataStruct XGI_ExtPALData[]=
{ 3, 2,1080, 619,1270, 540, 438, 0, 438}
};
-XGI330_TVDataStruct XGI_StNTSCData[]=
+struct XGI330_TVDataStruct XGI_StNTSCData[] =
{
{ 1, 1, 858, 525,1270, 400, 50, 0, 760},
{ 1, 1, 858, 525,1270, 350, 50, 0, 640},
@@ -1666,7 +1637,7 @@ XGI330_TVDataStruct XGI_StNTSCData[]=
{ 1, 1, 858, 525,1270, 480, 0, 0, 760}
};
-XGI330_TVDataStruct XGI_ExtNTSCData[]=
+struct XGI330_TVDataStruct XGI_ExtNTSCData[] =
{
{ 9, 5, 1001, 453,1270, 420, 171, 0, 171},
{ 12, 5, 858, 403,1270, 420, 171, 0, 171},
@@ -1679,7 +1650,7 @@ XGI330_TVDataStruct XGI_ExtNTSCData[]=
{ 3, 2,1001, 533,1270, 420, 0, 0, 0}
};
-XGI330_TVDataStruct XGI_St1HiTVData[]=
+struct XGI330_TVDataStruct XGI_St1HiTVData[] =
{
{ 1,1,892,563,690,800,0,0,0 }, /* 00 (320x200,320x400,640x200,640x400) */
{ 1,1,892,563,690,700,0,0,0 }, /* 01 (320x350,640x350) */
@@ -1689,7 +1660,7 @@ XGI330_TVDataStruct XGI_St1HiTVData[]=
{ 8,5,1050,683,1648,960,0x150,1,0 } /* 05 (400x300,800x600) */
};
-XGI330_TVDataStruct XGI_St2HiTVData[]=
+struct XGI330_TVDataStruct XGI_St2HiTVData[] =
{
{ 3,1,840,483,1648,960,0x032,0,0 }, /* 00 (320x200,320x400,640x200,640x400) */
{ 1,1,892,563,690,700,0,0,0 }, /* 01 (320x350,640x350) */
@@ -1700,7 +1671,7 @@ XGI330_TVDataStruct XGI_St2HiTVData[]=
};
-XGI330_TVDataStruct XGI_ExtHiTVData[]=
+struct XGI330_TVDataStruct XGI_ExtHiTVData[] =
{
{ 6,1,840,563,1632,960,0,0,0 }, /* 00 (320x200,320x400,640x200,640x400) */
{ 3,1,960,563,1632,960,0,0,0 }, /* 01 (320x350,640x350) */
@@ -1716,7 +1687,7 @@ XGI330_TVDataStruct XGI_ExtHiTVData[]=
};
-XGI330_TVDataStruct XGI_ExtYPbPr525iData[]=
+struct XGI330_TVDataStruct XGI_ExtYPbPr525iData[] =
{
{ 9, 5, 1001, 453,1270, 420, 171, 0, 171},
{ 12, 5, 858, 403,1270, 420, 171, 0, 171},
@@ -1729,7 +1700,7 @@ XGI330_TVDataStruct XGI_ExtYPbPr525iData[]=
{ 3, 2,1001, 533,1250, 420, 0, 0, 0}
};
-XGI330_TVDataStruct XGI_StYPbPr525iData[]=
+struct XGI330_TVDataStruct XGI_StYPbPr525iData[] =
{
{ 1, 1, 858, 525,1270, 400, 50, 0, 760},
{ 1, 1, 858, 525,1270, 350, 50, 0, 640},
@@ -1738,7 +1709,7 @@ XGI330_TVDataStruct XGI_StYPbPr525iData[]=
{ 1, 1, 858, 525,1270, 480, 0, 0, 760},
};
-XGI330_TVDataStruct XGI_ExtYPbPr525pData[]=
+struct XGI330_TVDataStruct XGI_ExtYPbPr525pData[] =
{
{ 9, 5, 1001, 453,1270, 420, 171, 0, 171},
{ 12, 5, 858, 403,1270, 420, 171, 0, 171},
@@ -1751,7 +1722,7 @@ XGI330_TVDataStruct XGI_ExtYPbPr525pData[]=
{ 3, 2,1001, 533,1270, 420, 0, 0, 0}
};
-XGI330_TVDataStruct XGI_StYPbPr525pData[]=
+struct XGI330_TVDataStruct XGI_StYPbPr525pData[] =
{
{ 1, 1,1716, 525,1270, 400, 50, 0, 760},
{ 1, 1,1716, 525,1270, 350, 50, 0, 640},
@@ -1760,7 +1731,7 @@ XGI330_TVDataStruct XGI_StYPbPr525pData[]=
{ 1, 1,1716, 525,1270, 480, 0, 0, 760},
};
-XGI330_TVDataStruct XGI_ExtYPbPr750pData[]=
+struct XGI330_TVDataStruct XGI_ExtYPbPr750pData[] =
{
{ 3, 1, 935, 470,1130, 680, 50, 0, 0}, /* 00 (320x200,320x400,640x200,640x400) */
{ 24, 7, 935, 420,1130, 680, 50, 0, 0}, /* 01 (320x350,640x350) */
@@ -1775,7 +1746,7 @@ XGI330_TVDataStruct XGI_ExtYPbPr750pData[]=
{ 10, 9,1320, 830,1130, 640, 50, 0, 0}
};
-XGI330_TVDataStruct XGI_StYPbPr750pData[]=
+struct XGI330_TVDataStruct XGI_StYPbPr750pData[] =
{
{ 1, 1,1650, 750,1280, 400, 50, 0, 760},
{ 1, 1,1650, 750,1280, 350, 50, 0, 640},
@@ -1784,7 +1755,7 @@ XGI330_TVDataStruct XGI_StYPbPr750pData[]=
{ 1, 1,1650, 750,1280, 480, 0, 0, 760},
};
-UCHAR XGI330_NTSCTiming[] = {
+unsigned char XGI330_NTSCTiming[] = {
0x17,0x1d,0x03,0x09,0x05,0x06,0x0c,0x0c,
0x94,0x49,0x01,0x0a,0x06,0x0d,0x04,0x0a,
0x06,0x14,0x0d,0x04,0x0a,0x00,0x85,0x1b,
@@ -1794,7 +1765,7 @@ UCHAR XGI330_NTSCTiming[] = {
0x60,0x80,0x14,0x90,0x8c,0x60,0x14,0x50,
0x00,0x40,0x44,0x00,0xdb,0x02,0x3b,0x00};
-UCHAR XGI330_PALTiming[] = {
+unsigned char XGI330_PALTiming[] = {
0x21,0x5A,0x35,0x6e,0x04,0x38,0x3d,0x70,
0x94,0x49,0x01,0x12,0x06,0x3e,0x35,0x6d,
0x06,0x14,0x3e,0x35,0x6d,0x00,0x45,0x2b,
@@ -1804,7 +1775,7 @@ UCHAR XGI330_PALTiming[] = {
0x60,0x80,0x14,0x90,0x8c,0x60,0x14,0x63,
0x00,0x40,0x3e,0x00,0xe1,0x02,0x28,0x00};
-UCHAR XGI330_HiTVExtTiming[] =
+unsigned char XGI330_HiTVExtTiming[] =
{
0x2D,0x60,0x2C,0x5F,0x08,0x31,0x3A,0x64,
0x28,0x02,0x01,0x3D,0x06,0x3E,0x35,0x6D,
@@ -1818,7 +1789,7 @@ UCHAR XGI330_HiTVExtTiming[] =
};
-UCHAR XGI330_HiTVSt1Timing[] =
+unsigned char XGI330_HiTVSt1Timing[] =
{
0x32,0x65,0x2C,0x5F,0x08,0x31,0x3A,0x65,
0x28,0x02,0x01,0x3D,0x06,0x3E,0x35,0x6D,
@@ -1831,7 +1802,7 @@ UCHAR XGI330_HiTVSt1Timing[] =
0x0E,0x00,0xfc,0xff,0x2d,0x00
};
-UCHAR XGI330_HiTVSt2Timing[] =
+unsigned char XGI330_HiTVSt2Timing[] =
{
0x32,0x65,0x2C,0x5F,0x08,0x31,0x3A,0x64,
0x28,0x02,0x01,0x3D,0x06,0x3E,0x35,0x6D,
@@ -1844,7 +1815,7 @@ UCHAR XGI330_HiTVSt2Timing[] =
0x27,0x00,0xFC,0xff,0x6a,0x00
};
-UCHAR XGI330_HiTVTextTiming[] =
+unsigned char XGI330_HiTVTextTiming[] =
{
0x32,0x65,0x2C,0x5F,0x08,0x31,0x3A,0x65,
0x28,0x02,0x01,0x3D,0x06,0x3E,0x35,0x6D,
@@ -1857,7 +1828,7 @@ UCHAR XGI330_HiTVTextTiming[] =
0x11,0x00,0xFC,0xFF,0x32,0x00
};
-UCHAR XGI330_YPbPr750pTiming[] =
+unsigned char XGI330_YPbPr750pTiming[] =
{
0x30,0x1d,0xe8,0x09,0x09,0xed,0x0c,0x0c,
0x98,0x0a,0x01,0x0c,0x06,0x0d,0x04,0x0a,
@@ -1870,7 +1841,7 @@ UCHAR XGI330_YPbPr750pTiming[] =
0x11,0x00,0xfc,0xff,0x32,0x00
};
-UCHAR XGI330_YPbPr525pTiming[] =
+unsigned char XGI330_YPbPr525pTiming[] =
{
0x3E,0x11,0x06,0x09,0x0b,0x0c,0x0c,0x0c,
0x98,0x0a,0x01,0x0d,0x06,0x0d,0x04,0x0a,
@@ -1883,7 +1854,7 @@ UCHAR XGI330_YPbPr525pTiming[] =
0x11,0x00,0xFC,0xFF,0x32,0x00
};
-UCHAR XGI330_YPbPr525iTiming[] =
+unsigned char XGI330_YPbPr525iTiming[] =
{
0x1B,0x21,0x03,0x09,0x05,0x06,0x0C,0x0C,
0x94,0x49,0x01,0x0A,0x06,0x0D,0x04,0x0A,
@@ -1897,7 +1868,7 @@ UCHAR XGI330_YPbPr525iTiming[] =
};
-UCHAR XGI330_HiTVGroup3Data[] =
+unsigned char XGI330_HiTVGroup3Data[] =
{
0x00,0x1A,0x22,0x63,0x62,0x22,0x08,0x5F,
0x05,0x21,0xB2,0xB2,0x55,0x77,0x2A,0xA6,
@@ -1909,7 +1880,7 @@ UCHAR XGI330_HiTVGroup3Data[] =
0x18,0x05,0x18,0x05,0x4C,0xA8,0x01
};
-UCHAR XGI330_HiTVGroup3Simu[] =
+unsigned char XGI330_HiTVGroup3Simu[] =
{
0x00,0x1A,0x22,0x63,0x62,0x22,0x08,0x95,
0xDB,0x20,0xB8,0xB8,0x55,0x47,0x2A,0xA6,
@@ -1921,7 +1892,7 @@ UCHAR XGI330_HiTVGroup3Simu[] =
0x18,0x05,0x18,0x05,0x4C,0xA8,0x01
};
-UCHAR XGI330_HiTVGroup3Text[] =
+unsigned char XGI330_HiTVGroup3Text[] =
{
0x00,0x1A,0x22,0x63,0x62,0x22,0x08,0xA7,
0xF5,0x20,0xCE,0xCE,0x55,0x47,0x2A,0xA6,
@@ -1933,7 +1904,7 @@ UCHAR XGI330_HiTVGroup3Text[] =
0x18,0x05,0x18,0x05,0x4C,0xA8,0x01
};
-UCHAR XGI330_Ren525pGroup3[] =
+unsigned char XGI330_Ren525pGroup3[] =
{
0x00,0x14,0x15,0x25,0x55,0x15,0x0b,0x13,
0xB1,0x41,0x62,0x62,0xFF,0xF4,0x45,0xa6,
@@ -1945,7 +1916,7 @@ UCHAR XGI330_Ren525pGroup3[] =
0x1a,0x1F,0x25,0x2a,0x4C,0xAA,0x01
};
-UCHAR XGI330_Ren750pGroup3[] =
+unsigned char XGI330_Ren750pGroup3[] =
{
0x00,0x14,0x15,0x25,0x55,0x15,0x0b,0x7a,
0x54,0x41,0xE7,0xE7,0xFF,0xF4,0x45,0xa6,
@@ -1957,7 +1928,7 @@ UCHAR XGI330_Ren750pGroup3[] =
0x18,0x1D,0x23,0x28,0x4C,0xAA,0x01
};
-XGI_PanelDelayTblStruct XGI330_PanelDelayTbl[]=
+struct XGI_PanelDelayTblStruct XGI330_PanelDelayTbl[] =
{
{{0x00,0x00}},
{{0x00,0x00}},
@@ -1977,7 +1948,7 @@ XGI_PanelDelayTblStruct XGI330_PanelDelayTbl[]=
{{0x00,0x00}}
};
-XGI330_LVDSDataStruct XGI330_LVDS320x480Data_1[]=
+struct XGI330_LVDSDataStruct XGI330_LVDS320x480Data_1[] =
{
{848, 433,400,525},
{848, 389,400,525},
@@ -1990,7 +1961,7 @@ XGI330_LVDSDataStruct XGI330_LVDS320x480Data_1[]=
{800, 525,1000, 635}
};
-XGI330_LVDSDataStruct XGI330_LVDS800x600Data_1[]=
+struct XGI330_LVDSDataStruct XGI330_LVDS800x600Data_1[] =
{
{848, 433,1060, 629},
{848, 389,1060, 629},
@@ -2003,7 +1974,7 @@ XGI330_LVDSDataStruct XGI330_LVDS800x600Data_1[]=
{800, 525,1000, 635}
};
-XGI330_LVDSDataStruct XGI330_LVDS800x600Data_2[]=
+struct XGI330_LVDSDataStruct XGI330_LVDS800x600Data_2[] =
{
{1056, 628,1056, 628},
{1056, 628,1056, 628},
@@ -2016,7 +1987,7 @@ XGI330_LVDSDataStruct XGI330_LVDS800x600Data_2[]=
{800, 525,1000, 635}
};
-XGI330_LVDSDataStruct XGI_LVDS1024x768Data_1[]=
+struct XGI330_LVDSDataStruct XGI_LVDS1024x768Data_1[] =
{
{ 960 , 438 , 1344 , 806 } , /* 00 (320x200,320x400,640x200,640x400) */
{ 960 , 388 , 1344 , 806 } , /* 01 (320x350,640x350) */
@@ -2028,7 +1999,7 @@ XGI330_LVDSDataStruct XGI_LVDS1024x768Data_1[]=
};
-XGI330_LVDSDataStruct XGI_LVDS1024x768Data_2[]=
+struct XGI330_LVDSDataStruct XGI_LVDS1024x768Data_2[] =
{
{1344, 806,1344, 806},
{1344, 806,1344, 806},
@@ -2041,7 +2012,7 @@ XGI330_LVDSDataStruct XGI_LVDS1024x768Data_2[]=
{800, 525,1280, 813}
};
-XGI330_LVDSDataStruct XGI_LVDS1280x1024Data_1[]=
+struct XGI330_LVDSDataStruct XGI_LVDS1280x1024Data_1[] =
{
{1048, 442,1688, 1066},
{1048, 392,1688, 1066},
@@ -2053,7 +2024,7 @@ XGI330_LVDSDataStruct XGI_LVDS1280x1024Data_1[]=
{1688, 1066,1688, 1066}
};
-XGI330_LVDSDataStruct XGI_LVDS1280x1024Data_2[]=
+struct XGI330_LVDSDataStruct XGI_LVDS1280x1024Data_2[] =
{
{1344, 806,1344, 806},
{1344, 806,1344, 806},
@@ -2066,7 +2037,7 @@ XGI330_LVDSDataStruct XGI_LVDS1280x1024Data_2[]=
{800, 525,1280, 813}
};
/*
-XGI330_LVDSDataStruct XGI_LVDS1280x768Data_1[]=
+struct XGI330_LVDSDataStruct XGI_LVDS1280x768Data_1[] =
{
{768,438,1408,806},
{768,388,1408,806},
@@ -2079,7 +2050,7 @@ XGI330_LVDSDataStruct XGI_LVDS1280x768Data_1[]=
{1408,806,1408,806}
};
-XGI330_LVDSDataStruct XGI_LVDS1280x768Data_2[]=
+struct XGI330_LVDSDataStruct XGI_LVDS1280x768Data_2[] =
{
{1408, 806,1408, 806},
{1408, 806,1408, 806},
@@ -2092,7 +2063,7 @@ XGI330_LVDSDataStruct XGI_LVDS1280x768Data_2[]=
{1408, 806,1408, 806}
};
-XGI330_LVDSDataStruct XGI_LVDS1280x768NData_1[]=
+struct XGI330_LVDSDataStruct XGI_LVDS1280x768NData_1[] =
{
{704, 438,1344, 806},
{704, 388,1344, 806},
@@ -2105,7 +2076,7 @@ XGI330_LVDSDataStruct XGI_LVDS1280x768NData_1[]=
{1344, 806,1344, 806}
};
-XGI330_LVDSDataStruct XGI_LVDS1280x768NData_2[]=
+struct XGI330_LVDSDataStruct XGI_LVDS1280x768NData_2[] =
{
{1344, 806,1344, 806},
{1344, 806,1344, 806},
@@ -2118,7 +2089,7 @@ XGI330_LVDSDataStruct XGI_LVDS1280x768NData_2[]=
{1344, 806,1344, 806}
};
-XGI330_LVDSDataStruct XGI_LVDS1280x768SData_1[]=
+struct XGI330_LVDSDataStruct XGI_LVDS1280x768SData_1[] =
{
{1048,438,1688,806},
{1048,388,1688,806},
@@ -2131,7 +2102,7 @@ XGI330_LVDSDataStruct XGI_LVDS1280x768SData_1[]=
{1688,806,1688,806}
};
-XGI330_LVDSDataStruct XGI_LVDS1280x768SData_2[]=
+struct XGI330_LVDSDataStruct XGI_LVDS1280x768SData_2[] =
{
{1688,806,1688,806},
{1688,806,1688,806},
@@ -2144,7 +2115,7 @@ XGI330_LVDSDataStruct XGI_LVDS1280x768SData_2[]=
{1688,806,1688,806}
};
*/
-XGI330_LVDSDataStruct XGI_LVDS1400x1050Data_1[]=
+struct XGI330_LVDSDataStruct XGI_LVDS1400x1050Data_1[] =
{
{928,416,1688,1066},
{928,366,1688,1066},
@@ -2157,7 +2128,7 @@ XGI330_LVDSDataStruct XGI_LVDS1400x1050Data_1[]=
{1688,1066,1688,1066}
};
-XGI330_LVDSDataStruct XGI_LVDS1400x1050Data_2[]=
+struct XGI330_LVDSDataStruct XGI_LVDS1400x1050Data_2[] =
{
{1688,1066,1688,1066},
{1688,1066,1688,1066},
@@ -2170,7 +2141,7 @@ XGI330_LVDSDataStruct XGI_LVDS1400x1050Data_2[]=
{1688,1066,1688,1066}
};
-XGI330_LVDSDataStruct XGI_LVDS1600x1200Data_1[]=
+struct XGI330_LVDSDataStruct XGI_LVDS1600x1200Data_1[] =
{ /* ;;[ycchen] 12/05/02 LCDHTxLCDVT=2048x1320 */
{ 1088,520,2048,1320 },/* 00 (320x200,320x400,640x200,640x400) */
{ 1088,470,2048,1320 },/* 01 (320x350,640x350) */
@@ -2184,7 +2155,7 @@ XGI330_LVDSDataStruct XGI_LVDS1600x1200Data_1[]=
{ 2048,1320,2048,1320 } /* 09 (1600x1200) */
};
-XGI330_LVDSDataStruct XGI_LVDSNoScalingData[]=
+struct XGI330_LVDSDataStruct XGI_LVDSNoScalingData[] =
{
{ 800,449,800,449 }, /* 00 (320x200,320x400,640x200,640x400) */
{ 800,449,800,449 }, /* 01 (320x350,640x350) */
@@ -2199,7 +2170,7 @@ XGI330_LVDSDataStruct XGI_LVDSNoScalingData[]=
{ 1688,806,1688,806 } /* 0A (1280x768x60Hz) */
};
-XGI330_LVDSDataStruct XGI_LVDS1024x768Data_1x75[]=
+struct XGI330_LVDSDataStruct XGI_LVDS1024x768Data_1x75[] =
{
{960,438,1312,800 }, /* 00 (320x200,320x400,640x200,640x400) */
{960,388,1312,800 }, /* 01 (320x350,640x350) */
@@ -2211,7 +2182,7 @@ XGI330_LVDSDataStruct XGI_LVDS1024x768Data_1x75[]=
};
-XGI330_LVDSDataStruct XGI_LVDS1024x768Data_2x75[]=
+struct XGI330_LVDSDataStruct XGI_LVDS1024x768Data_2x75[] =
{
{1312,800,1312,800}, /* ; 00 (320x200,320x400,640x200,640x400) */
{1312,800,1312,800}, /* ; 01 (320x350,640x350) */
@@ -2222,7 +2193,7 @@ XGI330_LVDSDataStruct XGI_LVDS1024x768Data_2x75[]=
{1312,800,1312,800}, /* ; 06 (512x384,1024x768) */
};
-XGI330_LVDSDataStruct XGI_LVDS1280x1024Data_1x75[]=
+struct XGI330_LVDSDataStruct XGI_LVDS1280x1024Data_1x75[] =
{
{1048,442,1688,1066 }, /* ; 00 (320x200,320x400,640x200,640x400) */
{1048,392,1688,1066 }, /* ; 01 (320x350,640x350) */
@@ -2234,7 +2205,7 @@ XGI330_LVDSDataStruct XGI_LVDS1280x1024Data_1x75[]=
{1688,1066,1688,1066 }, /* ; 06; 07 (640x512,1280x1024) */
};
-XGI330_LVDSDataStruct XGI_LVDS1280x1024Data_2x75[]=
+struct XGI330_LVDSDataStruct XGI_LVDS1280x1024Data_2x75[] =
{
{1688,1066,1688,1066 }, /* ; 00 (320x200,320x400,640x200,640x400) */
{1688,1066,1688,1066 }, /* ; 01 (320x350,640x350) */
@@ -2246,7 +2217,7 @@ XGI330_LVDSDataStruct XGI_LVDS1280x1024Data_2x75[]=
{1688,1066,1688,1066 }, /* ; 06; 07 (640x512,1280x1024) */
};
-XGI330_LVDSDataStruct XGI_LVDSNoScalingDatax75[]=
+struct XGI330_LVDSDataStruct XGI_LVDSNoScalingDatax75[] =
{
{800,449,800,449 }, /* ; 00 (320x200,320x400,640x200,640x400) */
{800,449,800,449 }, /* ; 01 (320x350,640x350) */
@@ -2261,7 +2232,7 @@ XGI330_LVDSDataStruct XGI_LVDSNoScalingDatax75[]=
{1688,806,1688,806 }, /* ; 0A (1280x768x75Hz) */
};
-XGI330_LVDSDataStruct XGI_LVDS1024x768Des_1[]=
+struct XGI330_LVDSDataStruct XGI_LVDS1024x768Des_1[] =
{
{ 0,1048, 0, 771 }, /* 00 (320x200,320x400,640x200,640x400) */
{ 0,1048, 0, 771 }, /* 01 (320x350,640x350) */
@@ -2272,7 +2243,7 @@ XGI330_LVDSDataStruct XGI_LVDS1024x768Des_1[]=
{ 0,1048, 805, 770 } /* 06 (1024x768x60Hz) */
} ;
-XGI330_LVDSDataStruct XGI_LVDS1024x768Des_2[]=
+struct XGI330_LVDSDataStruct XGI_LVDS1024x768Des_2[] =
{
{ 1142, 856, 622, 587 }, /* 00 (320x200,320x400,640x200,640x400) */
{ 1142, 856, 597, 562 }, /* 01 (320x350,640x350) */
@@ -2283,7 +2254,7 @@ XGI330_LVDSDataStruct XGI_LVDS1024x768Des_2[]=
{ 0,1048, 805, 771 } /* 06 (1024x768x60Hz) */
};
-XGI330_LVDSDataStruct XGI_LVDS1024x768Des_3[]=
+struct XGI330_LVDSDataStruct XGI_LVDS1024x768Des_3[] =
{
{ 320, 24, 622, 587 }, /* 00 (320x200,320x400,640x200,640x400) */
{ 320, 24, 597, 562 }, /* 01 (320x350,640x350) */
@@ -2292,7 +2263,7 @@ XGI330_LVDSDataStruct XGI_LVDS1024x768Des_3[]=
{ 320, 24, 722, 687 } /* 04 (640x480x60Hz) */
};
-XGI330_LVDSDataStruct XGI_LVDS1280x1024Des_1[]=
+struct XGI330_LVDSDataStruct XGI_LVDS1280x1024Des_1[] =
{
{ 0,1328, 0, 1025 }, /* 00 (320x200,320x400,640x200,640x400) */
{ 0,1328, 0, 1025 }, /* 01 (320x350,640x350) */
@@ -2305,7 +2276,7 @@ XGI330_LVDSDataStruct XGI_LVDS1280x1024Des_1[]=
};
/* The Display setting for DE Mode Panel */
-XGI330_LVDSDataStruct XGI_LVDS1280x1024Des_2[]=
+struct XGI330_LVDSDataStruct XGI_LVDS1280x1024Des_2[] =
{
{ 1368,1008,752,711 }, /* 00 (320x200,320x400,640x200,640x400) */
{ 1368,1008,729,688 }, /* 01 (320x350,640x350) */
@@ -2317,7 +2288,7 @@ XGI330_LVDSDataStruct XGI_LVDS1280x1024Des_2[]=
{ 0000,1328,0,1025 } /* 07 (1280x1024x60Hz) */
};
-XGI330_LVDSDataStruct XGI_LVDS1400x1050Des_1[]=
+struct XGI330_LVDSDataStruct XGI_LVDS1400x1050Des_1[] =
{
{ 0,1448,0,1051 }, /* 00 (320x200,320x400,640x200,640x400) */
{ 0,1448,0,1051 }, /* 01 (320x350,640x350) */
@@ -2330,7 +2301,7 @@ XGI330_LVDSDataStruct XGI_LVDS1400x1050Des_1[]=
{ 0,1448,0,1051 } /* 08 (1400x1050x60Hz) */
};
-XGI330_LVDSDataStruct XGI_LVDS1400x1050Des_2[]=
+struct XGI330_LVDSDataStruct XGI_LVDS1400x1050Des_2[] =
{
{ 1308,1068, 781, 766 }, /* 00 (320x200,320x400,640x200,640x400) */
{ 1308,1068, 781, 766 }, /* 01 (320x350,640x350) */
@@ -2343,7 +2314,7 @@ XGI330_LVDSDataStruct XGI_LVDS1400x1050Des_2[]=
{ 0,1448,0,1051 } /* 08 (1400x1050x60Hz) */
};
-XGI330_LVDSDataStruct XGI_LVDS1600x1200Des_1[]=
+struct XGI330_LVDSDataStruct XGI_LVDS1600x1200Des_1[] =
{
{ 0,1664,0,1201 }, /* 00 (320x200,320x400,640x200,640x400) */
{ 0,1664,0,1201 }, /* 01 (320x350,640x350) */
@@ -2359,7 +2330,7 @@ XGI330_LVDSDataStruct XGI_LVDS1600x1200Des_1[]=
-XGI330_LCDDataDesStruct2 XGI_LVDSNoScalingDesData[]=
+struct XGI330_LCDDataDesStruct2 XGI_LVDSNoScalingDesData[] =
{
{ 0, 648, 448, 405, 96, 2 }, /* 00 (320x200,320x400,640x200,640x400) */
{ 0, 648, 448, 355, 96, 2 }, /* 01 (320x350,640x350) */
@@ -2374,7 +2345,7 @@ XGI330_LCDDataDesStruct2 XGI_LVDSNoScalingDesData[]=
{ 0,1328,0,0771, 112, 6 } /* 0A (1280x768x60Hz) */
};
-XGI330_LVDSDataStruct XGI_LVDS1024x768Des_1x75[]= /* ; 1024x768 Full-screen */
+struct XGI330_LVDSDataStruct XGI_LVDS1024x768Des_1x75[] = /* ; 1024x768 Full-screen */
{
{0,1040,0,769}, /* ; 00 (320x200,320x400,640x200,640x400) */
{0,1040,0,769}, /* ; 01 (320x350,640x350) */
@@ -2385,7 +2356,7 @@ XGI330_LVDSDataStruct XGI_LVDS1024x768Des_1x75[]= /* ; 1024x768 Full-screen */
{0,1040,0,769} /* ; 06 (1024x768x75Hz) */
};
-XGI330_LVDSDataStruct XGI_LVDS1024x768Des_2x75[]= /* ; 1024x768 center-screen (Enh. Mode) */
+struct XGI330_LVDSDataStruct XGI_LVDS1024x768Des_2x75[] = /* ; 1024x768 center-screen (Enh. Mode) */
{
{1142, 856,622,587 }, /* 00 (320x200,320x400,640x200,640x400) */
{1142, 856,597,562 }, /* 01 (320x350,640x350) */
@@ -2396,7 +2367,7 @@ XGI330_LVDSDataStruct XGI_LVDS1024x768Des_2x75[]= /* ; 1024x768 center-screen (E
{ 0,1048,805,771 } /* 06 (1024x768x60Hz) */
};
-XGI330_LVDSDataStruct XGI_LVDS1024x768Des_3x75[]= /* ; 1024x768 center-screen (St.Mode) */
+struct XGI330_LVDSDataStruct XGI_LVDS1024x768Des_3x75[] = /* ; 1024x768 center-screen (St.Mode) */
{
{320,24,622,587 }, /* ; 00 (320x200,320x400,640x200,640x400) */
{320,24,597,562 }, /* ; 01 (320x350,640x350) */
@@ -2405,7 +2376,7 @@ XGI330_LVDSDataStruct XGI_LVDS1024x768Des_3x75[]= /* ; 1024x768 center-screen (S
{320,24,722,687 } /* ; 04 (640x480x60Hz) */
};
-XGI330_LVDSDataStruct XGI_LVDS1280x1024Des_1x75[]=
+struct XGI330_LVDSDataStruct XGI_LVDS1280x1024Des_1x75[] =
{
{0,1296,0,1025}, /* ; 00 (320x200,320x400,640x200,640x400) */
{0,1296,0,1025}, /* ; 01 (320x350,640x350) */
@@ -2418,7 +2389,7 @@ XGI330_LVDSDataStruct XGI_LVDS1280x1024Des_1x75[]=
};
/* The Display setting for DE Mode Panel */
-XGI330_LVDSDataStruct XGI_LVDS1280x1024Des_2x75[]= /* [ycchen] 02/18/03 Set DE as default */
+struct XGI330_LVDSDataStruct XGI_LVDS1280x1024Des_2x75[] = /* [ycchen] 02/18/03 Set DE as default */
{
{1368,976,752,711 }, /* ; 00 (320x200,320x400,640x200,640x400) */
{1368,976,729,688 }, /* ; 01 (320x350,640x350) */
@@ -2430,7 +2401,7 @@ XGI330_LVDSDataStruct XGI_LVDS1280x1024Des_2x75[]= /* [ycchen] 02/18/03 Set DE
{0,1296,0,1025 } /* ; 07 (1280x1024x75Hz) */
};
-XGI330_LCDDataDesStruct2 XGI_LVDSNoScalingDesDatax75[]= /* Scaling LCD 75Hz */
+struct XGI330_LCDDataDesStruct2 XGI_LVDSNoScalingDesDatax75[] = /* Scaling LCD 75Hz */
{
{ 0,648,448,405,96,2 }, /* ; 00 (320x200,320x400,640x200,640x400) */
{ 0,648,448,355,96,2 }, /* ; 01 (320x350,640x350) */
@@ -2445,7 +2416,7 @@ XGI330_LCDDataDesStruct2 XGI_LVDSNoScalingDesDatax75[]= /* Scaling LCD 75Hz */
{ 0,1328,0,771,112,6 } /* ; 0A (1280x768x75Hz) */
};
-XGI330_LVDSDataStruct XGI330_LVDS640x480Data_1[]=
+struct XGI330_LVDSDataStruct XGI330_LVDS640x480Data_1[] =
{
{800, 449, 800, 449},
{800, 449, 800, 449},
@@ -2458,7 +2429,7 @@ XGI330_LVDSDataStruct XGI330_LVDS640x480Data_1[]=
{1056, 628,1056, 628}
};
-XGI330_CHTVDataStruct XGI_CHTVUNTSCData[]=
+struct XGI330_CHTVDataStruct XGI_CHTVUNTSCData[] =
{
{840, 600, 840, 600},
{840, 600, 840, 600},
@@ -2468,7 +2439,7 @@ XGI330_CHTVDataStruct XGI_CHTVUNTSCData[]=
{1064, 750,1064, 750}
};
-XGI330_CHTVDataStruct XGI_CHTVONTSCData[]=
+struct XGI330_CHTVDataStruct XGI_CHTVONTSCData[] =
{
{840, 525, 840, 525},
{840, 525, 840, 525},
@@ -2478,7 +2449,7 @@ XGI330_CHTVDataStruct XGI_CHTVONTSCData[]=
{1040, 700,1040, 700}
};
-XGI330_CHTVDataStruct XGI_CHTVUPALData[]=
+struct XGI330_CHTVDataStruct XGI_CHTVUPALData[] =
{
{1008, 625,1008, 625},
{1008, 625,1008, 625},
@@ -2488,7 +2459,7 @@ XGI330_CHTVDataStruct XGI_CHTVUPALData[]=
{936, 836, 936, 836}
};
-XGI330_CHTVDataStruct XGI_CHTVOPALData[]=
+struct XGI330_CHTVDataStruct XGI_CHTVOPALData[] =
{
{1008, 625,1008, 625},
{1008, 625,1008, 625},
@@ -2498,7 +2469,7 @@ XGI330_CHTVDataStruct XGI_CHTVOPALData[]=
{960, 750, 960, 750}
};
-XGI_LVDSCRT1HDataStruct XGI_LVDSCRT11024x768_1_H[]=
+struct XGI_LVDSCRT1HDataStruct XGI_LVDSCRT11024x768_1_H[] =
{
/* CR00,CR02,CR03,CR04,CR05,SR0B,SR0C,SR0E */
{{ 0x4B,0x27,0x8F,0x32,0x1B,0x00,0x45,0x00 }}, /* 00 (320x) */
@@ -2511,7 +2482,7 @@ XGI_LVDSCRT1HDataStruct XGI_LVDSCRT11024x768_1_H[]=
{{ 0xA3,0x7F,0x87,0x86,0x97,0x00,0x02,0x00 }} /* 07 (1024x) */
};
-XGI_LVDSCRT1HDataStruct XGI_LVDSCRT11280x1024_1_H[]=
+struct XGI_LVDSCRT1HDataStruct XGI_LVDSCRT11280x1024_1_H[] =
{
/* CR00,CR02,CR03,CR04,CR05,SR0B,SR0C,SR0E */
{{ 0x56,0x27,0x9A,0x30,0x1E,0x00,0x05,0x00 }}, /* 00 (320x) */
@@ -2525,7 +2496,7 @@ XGI_LVDSCRT1HDataStruct XGI_LVDSCRT11280x1024_1_H[]=
{{ 0xCE,0x9F,0x92,0xA8,0x16,0x00,0x07,0x00 }} /* 08 (1280x) */
};
-XGI_LVDSCRT1HDataStruct XGI_LVDSCRT11024x768_2_H[]=
+struct XGI_LVDSCRT1HDataStruct XGI_LVDSCRT11024x768_2_H[] =
{
/* CR00,CR02,CR03,CR04,CR05,SR0B,SR0C,SR0E */
{{ 0x63,0x27,0x87,0x3B,0x8C,0x00,0x01,0x00 }}, /* 00 (320x) */
@@ -2538,7 +2509,7 @@ XGI_LVDSCRT1HDataStruct XGI_LVDSCRT11024x768_2_H[]=
{{ 0xA3,0x7F,0x87,0x86,0x97,0x00,0x02,0x00 }} /* 07 (1024x) */
};
-XGI_LVDSCRT1HDataStruct XGI_LVDSCRT11280x1024_2_H[]=
+struct XGI_LVDSCRT1HDataStruct XGI_LVDSCRT11280x1024_2_H[] =
{
/* CR00,CR02,CR03,CR04,CR05,SR0B,SR0C,SR0E */
{{ 0x7E,0x3B,0x9A,0x44,0x12,0x00,0x01,0x00 }}, /* 00 (320x) */
@@ -2552,7 +2523,7 @@ XGI_LVDSCRT1HDataStruct XGI_LVDSCRT11280x1024_2_H[]=
{{ 0xCE,0x9F,0x92,0xA8,0x16,0x00,0x07,0x00 }} /* 08 (1280x) */
};
-XGI_LVDSCRT1HDataStruct XGI_LVDSCRT11400x1050_1_H[]=
+struct XGI_LVDSCRT1HDataStruct XGI_LVDSCRT11400x1050_1_H[] =
{ /* CR00,CR02,CR03,CR04,CR05,SR0B,SR0C,SR0E */
{{ 0x47,0x27,0x8B,0x2C,0x1A,0x00,0x05,0x00 }}, /* 00 (320x) */
{{ 0x47,0x27,0x8B,0x30,0x1E,0x00,0x05,0x00 }}, /* 01 (360x) */
@@ -2566,7 +2537,7 @@ XGI_LVDSCRT1HDataStruct XGI_LVDSCRT11400x1050_1_H[]=
{{ 0xCE,0xAE,0x92,0xB3,0x01,0x00,0x03,0x00 }} /* 09 (1400x) */
};
-XGI_LVDSCRT1HDataStruct XGI_LVDSCRT11400x1050_2_H[]=
+struct XGI_LVDSCRT1HDataStruct XGI_LVDSCRT11400x1050_2_H[] =
{ /* CR00,CR02,CR03,CR04,CR05,SR0B,SR0C,SR0E */
{{ 0x76,0x3F,0x83,0x45,0x8C,0x00,0x41,0x00 }}, /* 00 (320x) */
{{ 0x76,0x3F,0x83,0x45,0x8C,0x00,0x41,0x00 }}, /* 01 (360x) */
@@ -2580,7 +2551,7 @@ XGI_LVDSCRT1HDataStruct XGI_LVDSCRT11400x1050_2_H[]=
{{ 0xCE,0xAE,0x92,0xBC,0x0A,0x00,0x03,0x00 }} /* 09 (1400x) */
};
-XGI_LVDSCRT1HDataStruct XGI_LVDSCRT11600x1200_1_H[]=
+struct XGI_LVDSCRT1HDataStruct XGI_LVDSCRT11600x1200_1_H[] =
/* ;302lv channelA [ycchen] 12/05/02 LCDHT=2048 */
{ /* ; CR00,CR02,CR03,CR04,CR05,SR0B,SR0C,SR0E */
{{ 0x5B,0x27,0x9F,0x32,0x0A,0x00,0x01,0x00 }},/* 00 (320x) */
@@ -2596,7 +2567,7 @@ XGI_LVDSCRT1HDataStruct XGI_LVDSCRT11600x1200_1_H[]=
{{ 0xFB,0xC7,0x9F,0xC9,0x81,0x00,0x07,0x00 }} /* 0A (1600x) */
};
-XGI_LVDSCRT1VDataStruct XGI_LVDSCRT11024x768_1_V[]=
+struct XGI_LVDSCRT1VDataStruct XGI_LVDSCRT11024x768_1_V[] =
{ /* CR06,CR07,CR10,CR11,CR15,CR16,SR0A+CR09(5->7) */
{{ 0x97,0x1F,0x60,0x87,0x5D,0x83,0x10 }}, /* 00 (x350) */
{{ 0xB4,0x1F,0x92,0x89,0x8F,0xB5,0x30 }}, /* 01 (x400) */
@@ -2605,7 +2576,7 @@ XGI_LVDSCRT1VDataStruct XGI_LVDSCRT11024x768_1_V[]=
{{ 0x24,0xF5,0x02,0x88,0xFF,0x25,0x90 }} /* 04 (x768) */
};
-XGI_LVDSCRT1VDataStruct XGI_LVDSCRT11024x768_2_V[]=
+struct XGI_LVDSCRT1VDataStruct XGI_LVDSCRT11024x768_2_V[] =
{ /* CR06,CR07,CR10,CR11,CR15,CR16,SR0A */
{{ 0x24,0xBB,0x31,0x87,0x5D,0x25,0x30 }}, /* 00 (x350) */
{{ 0x24,0xBB,0x4A,0x80,0x8F,0x25,0x30 }}, /* 01 (x400) */
@@ -2614,7 +2585,7 @@ XGI_LVDSCRT1VDataStruct XGI_LVDSCRT11024x768_2_V[]=
{{ 0x24,0xF5,0x02,0x88,0xFF,0x25,0x90 }} /* 04 (x768) */
};
-XGI_LVDSCRT1VDataStruct XGI_LVDSCRT11280x1024_1_V[]=
+struct XGI_LVDSCRT1VDataStruct XGI_LVDSCRT11280x1024_1_V[] =
{ /* CR06,CR07,CR10,CR11,CR15,CR16,SR0A */
{{ 0x86,0x1F,0x5E,0x82,0x5D,0x87,0x00 }}, /* 00 (x350) */
{{ 0xB8,0x1F,0x90,0x84,0x8F,0xB9,0x30 }}, /* 01 (x400) */
@@ -2624,7 +2595,7 @@ XGI_LVDSCRT1VDataStruct XGI_LVDSCRT11280x1024_1_V[]=
{{ 0x28,0x5A,0x13,0x87,0xFF,0x29,0xA9 }} /* 05 (x1024) */
};
-XGI_LVDSCRT1VDataStruct XGI_LVDSCRT11280x1024_2_V[]=
+struct XGI_LVDSCRT1VDataStruct XGI_LVDSCRT11280x1024_2_V[] =
{ /* CR06,CR07,CR10,CR11,CR15,CR16,SR0A */
{{ 0x28,0xD2,0xAF,0x83,0xAE,0xD8,0xA1 }}, /* 00 (x350) */
{{ 0x28,0xD2,0xC8,0x8C,0xC7,0xF2,0x81 }}, /* 01 (x400) */
@@ -2634,7 +2605,7 @@ XGI_LVDSCRT1VDataStruct XGI_LVDSCRT11280x1024_2_V[]=
{{ 0x28,0x5A,0x13,0x87,0xFF,0x29,0xA9 }} /* 05 (x1024) */
};
-XGI_LVDSCRT1VDataStruct XGI_LVDSCRT11400x1050_1_V[]=
+struct XGI_LVDSCRT1VDataStruct XGI_LVDSCRT11400x1050_1_V[] =
{ /* CR06,CR07,CR10,CR11,CR15,CR16,SR0A */
{{ 0x6C,0x1F,0x60,0x84,0x5D,0x6D,0x10 }}, /* 00 (x350) */
{{ 0x9E,0x1F,0x93,0x86,0x8F,0x9F,0x30 }}, /* 01 (x400) */
@@ -2645,7 +2616,7 @@ XGI_LVDSCRT1VDataStruct XGI_LVDSCRT11400x1050_1_V[]=
{{ 0x28,0x10,0x1A,0x80,0x19,0x29,0x0F }} /* 06 (x1050) */
};
-XGI_LVDSCRT1VDataStruct XGI_LVDSCRT11400x1050_2_V[]=
+struct XGI_LVDSCRT1VDataStruct XGI_LVDSCRT11400x1050_2_V[] =
{ /* CR06,CR07,CR10,CR11,CR15,CR16,SR0A */
{{ 0x28,0x92,0xB6,0x83,0xB5,0xCF,0x81 }}, /* 00 (x350) */
{{ 0x28,0x92,0xD5,0x82,0xD4,0xEE,0x81 }}, /* 01 (x400) */
@@ -2656,7 +2627,7 @@ XGI_LVDSCRT1VDataStruct XGI_LVDSCRT11400x1050_2_V[]=
{{ 0x28,0x10,0x1A,0x87,0x19,0x29,0x8F }} /* 06 (x1050) */
};
-XGI_LVDSCRT1VDataStruct XGI_LVDSCRT11600x1200_1_V[]=
+struct XGI_LVDSCRT1VDataStruct XGI_LVDSCRT11600x1200_1_V[] =
{
/* CR06,CR07,CR10,CR11,CR15,CR16,SR0A+CR09(5->7) */
{{ 0xd4,0x1F,0x81,0x84,0x5D,0xd5,0x10 }}, /* 00 (x350) */
@@ -2669,7 +2640,7 @@ XGI_LVDSCRT1VDataStruct XGI_LVDSCRT11600x1200_1_V[]=
{{ 0x26,0x11,0xd3,0x86,0xaF,0x27,0x3f }} /* 07 (x1200) */
};
-XGI_LVDSCRT1HDataStruct XGI_LVDSCRT11024x768_1_Hx75[]=
+struct XGI_LVDSCRT1HDataStruct XGI_LVDSCRT11024x768_1_Hx75[] =
{ /* CR00,CR02,CR03,CR04,CR05,SR0B,SR0C,SR0E */
{{ 0x4B,0x27,0x8F,0x32,0x1B,0x00,0x45,0x00 }},/* ; 00 (320x) */
{{ 0x4B,0x27,0x8F,0x2B,0x03,0x00,0x44,0x00 }},/* ; 01 (360x) */
@@ -2681,7 +2652,7 @@ XGI_LVDSCRT1HDataStruct XGI_LVDSCRT11024x768_1_Hx75[]=
{{ 0x9F,0x7F,0x83,0x85,0x91,0x00,0x02,0x00 }} /* ; 07 (1024x) */
};
-XGI_LVDSCRT1VDataStruct XGI_LVDSCRT11024x768_1_Vx75[]=
+struct XGI_LVDSCRT1VDataStruct XGI_LVDSCRT11024x768_1_Vx75[] =
{ /* CR06,CR07,CR10,CR11,CR15,CR16,SR0A+CR09(5->7) */
{{ 0x97,0x1F,0x60,0x87,0x5D,0x83,0x10 }},/* ; 00 (x350) */
{{ 0xB4,0x1F,0x92,0x89,0x8F,0xB5,0x30 }},/* ; 01 (x400) */
@@ -2690,7 +2661,7 @@ XGI_LVDSCRT1VDataStruct XGI_LVDSCRT11024x768_1_Vx75[]=
{{ 0x1E,0xF5,0x00,0x83,0xFF,0x1F,0x90 }} /* ; 04 (x768) */
};
-XGI_LVDSCRT1HDataStruct XGI_LVDSCRT11024x768_2_Hx75[]=
+struct XGI_LVDSCRT1HDataStruct XGI_LVDSCRT11024x768_2_Hx75[] =
{ /* CR00,CR02,CR03,CR04,CR05,SR0B,SR0C,SR0E */
{{ 0x63,0x27,0x87,0x3B,0x8C,0x00,0x01,0x00 }},/* ; 00 (320x) */
{{ 0x63,0x27,0x87,0x3B,0x8C,0x00,0x01,0x00 }},/* ; 01 (360x) */
@@ -2702,7 +2673,7 @@ XGI_LVDSCRT1HDataStruct XGI_LVDSCRT11024x768_2_Hx75[]=
{{ 0xA3,0x7F,0x87,0x86,0x97,0x00,0x02,0x00 }} /* ; 07 (1024x) */
};
-XGI_LVDSCRT1VDataStruct XGI_LVDSCRT11024x768_2_Vx75[]=
+struct XGI_LVDSCRT1VDataStruct XGI_LVDSCRT11024x768_2_Vx75[] =
{ /* CR06,CR07,CR10,CR11,CR15,CR16,SR0A */
{{ 0x24,0xBB,0x31,0x87,0x5D,0x25,0x30 }},/* ; 00 (x350) */
{{ 0x24,0xBB,0x4A,0x80,0x8F,0x25,0x30 }},/* ; 01 (x400) */
@@ -2711,7 +2682,7 @@ XGI_LVDSCRT1VDataStruct XGI_LVDSCRT11024x768_2_Vx75[]=
{{ 0x24,0xF5,0x02,0x88,0xFF,0x25,0x90 }} /* ; 04 (x768) */
};
-XGI_LVDSCRT1HDataStruct XGI_LVDSCRT11280x1024_1_Hx75[]=
+struct XGI_LVDSCRT1HDataStruct XGI_LVDSCRT11280x1024_1_Hx75[] =
{ /* CR00,CR02,CR03,CR04,CR05,SR0B,SR0C,SR0E */
{{ 0x56,0x27,0x9A,0x30,0x1E,0x00,0x05,0x00 }},/* ; 00 (320x) */
{{ 0x56,0x27,0x9A,0x30,0x1E,0x00,0x05,0x00 }},/* ; 01 (360x) */
@@ -2724,7 +2695,7 @@ XGI_LVDSCRT1HDataStruct XGI_LVDSCRT11280x1024_1_Hx75[]=
{{ 0xCE,0x9F,0x92,0xA5,0x17,0x00,0x07,0x00 }} /* ; 08 (1280x) */
};
-XGI_LVDSCRT1VDataStruct XGI_LVDSCRT11280x1024_1_Vx75[]=
+struct XGI_LVDSCRT1VDataStruct XGI_LVDSCRT11280x1024_1_Vx75[] =
{ /* CR06,CR07,CR10,CR11,CR15,CR16,SR0A */
{{ 0x86,0xD1,0xBC,0x80,0xBB,0xE5,0x00 }},/* ; 00 (x350) */
{{ 0xB8,0x1F,0x90,0x84,0x8F,0xB9,0x30 }},/* ; 01 (x400) */
@@ -2734,7 +2705,7 @@ XGI_LVDSCRT1VDataStruct XGI_LVDSCRT11280x1024_1_Vx75[]=
{{ 0x28,0x5A,0x13,0x87,0xFF,0x29,0xA9 }} /* ; 05 (x1024) */
};
-XGI_LVDSCRT1HDataStruct XGI_LVDSCRT11280x1024_2_Hx75[]=
+struct XGI_LVDSCRT1HDataStruct XGI_LVDSCRT11280x1024_2_Hx75[] =
{
/* CR00,CR02,CR03,CR04,CR05,SR0B,SR0C,SR0E */
{{ 0x7E,0x3B,0x9A,0x44,0x12,0x00,0x01,0x00 }},/* ; 00 (320x) */
@@ -2748,7 +2719,7 @@ XGI_LVDSCRT1HDataStruct XGI_LVDSCRT11280x1024_2_Hx75[]=
{{ 0xCE,0x9F,0x92,0xA8,0x16,0x00,0x07,0x00 }} /* ; 08 (1280x) */
};
-XGI_LVDSCRT1VDataStruct XGI_LVDSCRT11280x1024_2_Vx75[]=
+struct XGI_LVDSCRT1VDataStruct XGI_LVDSCRT11280x1024_2_Vx75[] =
{
/* CR06,CR07,CR10,CR11,CR15,CR16,SR0A */
{{ 0x28,0xD2,0xAF,0x83,0xAE,0xD8,0xA1 }},/* ; 00 (x350) */
@@ -2759,7 +2730,7 @@ XGI_LVDSCRT1VDataStruct XGI_LVDSCRT11280x1024_2_Vx75[]=
{{ 0x28,0x5A,0x13,0x87,0xFF,0x29,0xA9 }} /* ; 05 (x1024) */
};
-XGI_LVDSCRT1DataStruct XGI_CHTVCRT1UNTSC[]=
+struct XGI_LVDSCRT1DataStruct XGI_CHTVCRT1UNTSC[] =
{
{{0x64,0x4f,0x88,0x56,0x9f,0x56,0x3e,
0xe8,0x84,0x8f,0x57,0x20,0x00,0x01,0x00 }},
@@ -2775,7 +2746,7 @@ XGI_LVDSCRT1DataStruct XGI_CHTVCRT1UNTSC[]=
0x90,0x8c,0x57,0xed,0x20,0x00,0x06,0x01 }}
};
-XGI_LVDSCRT1DataStruct XGI_CHTVCRT1ONTSC[]=
+struct XGI_LVDSCRT1DataStruct XGI_CHTVCRT1ONTSC[] =
{
{{0x64,0x4f,0x88,0x5a,0x9f,0x0b,0x3e,
0xc0,0x84,0x8f,0x0c,0x20,0x00,0x01,0x00 }},
@@ -2791,7 +2762,7 @@ XGI_LVDSCRT1DataStruct XGI_CHTVCRT1ONTSC[]=
0x7f,0x86,0x57,0xbb,0x00,0x00,0x06,0x01 }}
};
-XGI_LVDSCRT1DataStruct XGI_CHTVCRT1UPAL[]=
+struct XGI_LVDSCRT1DataStruct XGI_CHTVCRT1UPAL[] =
{
{{0x79,0x4f,0x9d,0x5a,0x90,0x6f,0x3e,
0xf8,0x83,0x8f,0x70,0x20,0x00,0x05,0x00 }},
@@ -2807,7 +2778,7 @@ XGI_LVDSCRT1DataStruct XGI_CHTVCRT1UPAL[]=
0xc8,0x8c,0x57,0xe9,0x20,0x00,0x05,0x01 }}
};
-XGI_LVDSCRT1DataStruct XGI_CHTVCRT1OPAL[]=
+struct XGI_LVDSCRT1DataStruct XGI_CHTVCRT1OPAL[] =
{
{{0x79,0x4f,0x9d,0x5a,0x90,0x6f,0x3e,
0xf0,0x83,0x8f,0x70,0x20,0x00,0x05,0x00 }},
@@ -2824,7 +2795,7 @@ XGI_LVDSCRT1DataStruct XGI_CHTVCRT1OPAL[]=
};
/*add for new UNIVGABIOS*/
-XGI330_LCDDataTablStruct XGI_LCDDataTable[]=
+struct XGI330_LCDDataTablStruct XGI_LCDDataTable[] =
{
{Panel1024x768,0x0019,0x0001,0}, /* XGI_ExtLCD1024x768Data */
{Panel1024x768,0x0019,0x0000,1}, /* XGI_StLCD1024x768Data */
@@ -2848,7 +2819,7 @@ XGI330_LCDDataTablStruct XGI_LCDDataTable[]=
{0xFF,0x0000,0x0000,0} /* End of table */
};
-XGI330_LCDDataTablStruct XGI_LCDDesDataTable[]=
+struct XGI330_LCDDataTablStruct XGI_LCDDesDataTable[] =
{
{Panel1024x768,0x0019,0x0001,0}, /* XGI_ExtLCDDes1024x768Data */
{Panel1024x768,0x0019,0x0000,1}, /* XGI_StLCDDes1024x768Data */
@@ -2873,7 +2844,7 @@ XGI330_LCDDataTablStruct XGI_LCDDesDataTable[]=
{0xFF,0x0000,0x0000,0}
};
-XGI330_LCDDataTablStruct XGI_EPLLCDCRT1Ptr_H[]=
+struct XGI330_LCDDataTablStruct XGI_EPLLCDCRT1Ptr_H[] =
{
{Panel1024x768,0x0018,0x0000,0}, /* XGI_LVDSCRT11024x768_1_H */
{Panel1024x768,0x0018,0x0010,1}, /* XGI_LVDSCRT11024x768_2_H */
@@ -2889,7 +2860,7 @@ XGI330_LCDDataTablStruct XGI_EPLLCDCRT1Ptr_H[]=
{0xFF,0x0000,0x0000,0}
};
-XGI330_LCDDataTablStruct XGI_EPLLCDCRT1Ptr_V[]=
+struct XGI330_LCDDataTablStruct XGI_EPLLCDCRT1Ptr_V[] =
{
{Panel1024x768,0x0018,0x0000,0}, /* XGI_LVDSCRT11024x768_1_V */
{Panel1024x768,0x0018,0x0010,1}, /* XGI_LVDSCRT11024x768_2_V */
@@ -2905,7 +2876,7 @@ XGI330_LCDDataTablStruct XGI_EPLLCDCRT1Ptr_V[]=
{0xFF,0x0000,0x0000,0}
};
-XGI330_LCDDataTablStruct XGI_EPLLCDDataPtr[]=
+struct XGI330_LCDDataTablStruct XGI_EPLLCDDataPtr[] =
{
{Panel1024x768,0x0018,0x0000,0}, /* XGI_LVDS1024x768Data_1 */
{Panel1024x768,0x0018,0x0010,1}, /* XGI_LVDS1024x768Data_2 */
@@ -2923,7 +2894,7 @@ XGI330_LCDDataTablStruct XGI_EPLLCDDataPtr[]=
{0xFF,0x0000,0x0000,0}
};
-XGI330_LCDDataTablStruct XGI_EPLLCDDesDataPtr[]=
+struct XGI330_LCDDataTablStruct XGI_EPLLCDDesDataPtr[] =
{
{Panel1024x768,0x0018,0x0000,0}, /* XGI_LVDS1024x768Des_1 */
{Panel1024x768,0x0618,0x0410,1}, /* XGI_LVDS1024x768Des_3 */
@@ -2943,14 +2914,14 @@ XGI330_LCDDataTablStruct XGI_EPLLCDDesDataPtr[]=
{0xFF,0x0000,0x0000,0}
};
-XGI330_LCDDataTablStruct XGI_EPLCHLCDRegPtr[]=
+struct XGI330_LCDDataTablStruct XGI_EPLCHLCDRegPtr[] =
{
{Panel1024x768,0x0000,0x0000,0}, /* XGI_CH7017LV1024x768 */
{Panel1400x1050,0x0000,0x0000,1}, /* XGI_CH7017LV1400x1050 */
{0xFF,0x0000,0x0000,0}
};
-XGI330_TVDataTablStruct XGI_TVDataTable[]=
+struct XGI330_TVDataTablStruct XGI_TVDataTable[] =
{
{0x09E1,0x0001,0}, /* XGI_ExtPALData */
{0x09E1,0x0000,1}, /* XGI_ExtNTSCData */
@@ -2968,7 +2939,7 @@ XGI330_TVDataTablStruct XGI_TVDataTable[]=
{0xffff,0x0000,12} /* END */
};
-USHORT TVLenList[]=
+unsigned short TVLenList[] =
{
LVDSCRT1Len_H,
LVDSCRT1Len_V,
@@ -2981,7 +2952,7 @@ USHORT TVLenList[]=
} ;
/* Chrontel 7017 TV CRT1 Timing List */
-XGI330_TVDataTablStruct XGI_EPLCHTVCRT1Ptr[]=
+struct XGI330_TVDataTablStruct XGI_EPLCHTVCRT1Ptr[] =
{
{0x0011,0x0000,0}, /* XGI_CHTVCRT1UNTSC */
{0x0011,0x0010,1}, /* XGI_CHTVCRT1ONTSC */
@@ -2991,7 +2962,7 @@ XGI330_TVDataTablStruct XGI_EPLCHTVCRT1Ptr[]=
};
/* ;;Chrontel 7017 TV Timing List */
-XGI330_TVDataTablStruct XGI_EPLCHTVDataPtr[]=
+struct XGI330_TVDataTablStruct XGI_EPLCHTVDataPtr[] =
{
{0x0011,0x0000,0}, /* XGI_CHTVUNTSCData */
{0x0011,0x0010,1}, /* XGI_CHTVONTSCData */
@@ -3001,7 +2972,7 @@ XGI330_TVDataTablStruct XGI_EPLCHTVDataPtr[]=
};
/* ;;Chrontel 7017 TV Reg. List */
-XGI330_TVDataTablStruct XGI_EPLCHTVRegPtr[]=
+struct XGI330_TVDataTablStruct XGI_EPLCHTVRegPtr[] =
{
{0x0011,0x0000,0}, /* XGI_CHTVRegUNTSC */
{0x0011,0x0010,1}, /* XGI_CHTVRegONTSC */
@@ -3010,7 +2981,7 @@ XGI330_TVDataTablStruct XGI_EPLCHTVRegPtr[]=
{0xFFFF,0x0000,4}
};
-USHORT LCDLenList[]=
+unsigned short LCDLenList[] =
{
LVDSCRT1Len_H,
LVDSCRT1Len_V,
@@ -3024,7 +2995,7 @@ USHORT LCDLenList[]=
0
} ;
-XGI330_LCDCapStruct XGI660_LCDDLCapList[]= /* 660, Dual link */
+struct XGI330_LCDCapStruct XGI660_LCDDLCapList[] = /* 660, Dual link */
{
/* LCDCap1024x768 */
{Panel1024x768, DefaultLCDCap, 0, 0x014, 0x88, 0x06, VCLK65,
@@ -3056,7 +3027,7 @@ XGI330_LCDCapStruct XGI660_LCDDLCapList[]= /* 660, Dual link */
0x30, 0x10, 0x5A, 0x10, 0x10, 0x0A, 0xC0, 0x28, 0x10}
};
-XGI330_LCDCapStruct XGI_LCDDLCapList[]= /* Dual link only */
+struct XGI330_LCDCapStruct XGI_LCDDLCapList[] = /* Dual link only */
{
/* LCDCap1024x768 */
{Panel1024x768, DefaultLCDCap, 0, 0x012, 0x88, 0x06, VCLK65,
@@ -3088,7 +3059,7 @@ XGI330_LCDCapStruct XGI_LCDDLCapList[]= /* Dual link only */
0x30, 0x10, 0x5A, 0x10, 0x10, 0x0A, 0xC0, 0x28, 0x10}
};
-XGI330_LCDCapStruct XGI660_LCDCapList[]=
+struct XGI330_LCDCapStruct XGI660_LCDCapList[] =
{
/* LCDCap1024x768 */
{Panel1024x768, DefaultLCDCap, 0, 0x014, 0x88, 0x06, VCLK65,
@@ -3120,7 +3091,7 @@ XGI330_LCDCapStruct XGI660_LCDCapList[]=
0x30, 0x10, 0x5A, 0x10, 0x10, 0x0A, 0xC0, 0x28, 0x10}
};
-XGI330_LCDCapStruct XGI_LCDCapList[]=
+struct XGI330_LCDCapStruct XGI_LCDCapList[] =
{
/* LCDCap1024x768 */
{Panel1024x768, DefaultLCDCap, 0, 0x012, 0x88, 0x06, VCLK65,
@@ -3152,7 +3123,7 @@ XGI330_LCDCapStruct XGI_LCDCapList[]=
0x30, 0x10, 0x5A, 0x10, 0x10, 0x0A, 0xC0, 0x28, 0x10}
};
-XGI21_LVDSCapStruct XGI21_LCDCapList[]=
+struct XGI21_LVDSCapStruct XGI21_LCDCapList[] =
{
{DisableLCD24bpp + LCDPolarity,
2160,1250,1600,1200, 64, 1, 192, 3,
@@ -3181,7 +3152,7 @@ XGI21_LVDSCapStruct XGI21_LCDCapList[]=
};
-XGI_Ext2Struct XGI330_RefIndex[]=
+struct XGI_Ext2Struct XGI330_RefIndex[] =
{
{Support32Bpp + SupportAllCRT2 + SyncPN, RES320x200, VCLK25_175, 0x00,0x10,0x59, 320, 200},/* 00 */
{Support32Bpp + SupportAllCRT2 + SyncPN, RES320x200, VCLK25_175, 0x00,0x10,0x00, 320, 400},/* 01 */
@@ -3260,7 +3231,7 @@ XGI_Ext2Struct XGI330_RefIndex[]=
-XGI330_VCLKDataStruct XGI330_VCLKData[]=
+struct XGI330_VCLKDataStruct XGI330_VCLKData[] =
{
{ 0x1b,0xe1, 25}, /* 0x0 */
{ 0x4e,0xe4, 28}, /* 0x1 */
@@ -3344,7 +3315,7 @@ XGI330_VCLKDataStruct XGI330_VCLKData[]=
{ 0x3b,0x61,108} /* 0x4f */
};
-XGI_VBVCLKDataStruct XGI330_VBVCLKData[]=
+struct XGI_VBVCLKDataStruct XGI330_VBVCLKData[] =
{
{ 0x1b,0xe1, 25}, /* 0x0 */
{ 0x4e,0xe4, 28}, /* 0x1 */
@@ -3422,9 +3393,11 @@ XGI_VBVCLKDataStruct XGI330_VBVCLKData[]=
{ 0x70,0x44,108}, /* 0x49 chiawen for 1400x1050*/
};
-UCHAR XGI330_ScreenOffset[]={ 0x14,0x19,0x20,0x28,0x32,0x40,0x50,0x64,0x78,0x80,0x2d,0x35,0x57,0x48 };
+unsigned char XGI330_ScreenOffset[] = { 0x14, 0x19, 0x20, 0x28, 0x32, 0x40,
+ 0x50, 0x64, 0x78, 0x80, 0x2d, 0x35,
+ 0x57, 0x48};
-XGI_StResInfoStruct XGI330_StResInfo[]=
+struct XGI_StResInfoStruct XGI330_StResInfo[] =
{
{ 640,400},
{ 640,350},
@@ -3433,7 +3406,7 @@ XGI_StResInfoStruct XGI330_StResInfo[]=
{ 640,480}
};
-XGI_ModeResInfoStruct XGI330_ModeResInfo[]=
+struct XGI_ModeResInfoStruct XGI330_ModeResInfo[] =
{
{ 320, 200, 8, 8},
{ 320, 240, 8, 8},
@@ -3460,10 +3433,10 @@ XGI_ModeResInfoStruct XGI330_ModeResInfo[]=
{ 1152, 864, 8,16}
};
-UCHAR XGI330_OutputSelect =0x40;
-UCHAR XGI330_SoftSetting = 0x30;
-UCHAR XGI330_SR07=0x18;
-UCHAR XGI330New_SR15[8][8]={
+unsigned char XGI330_OutputSelect = 0x40;
+unsigned char XGI330_SoftSetting = 0x30;
+unsigned char XGI330_SR07 = 0x18;
+unsigned char XGI330New_SR15[8][8] = {
{0x0,0x4,0x60,0x60},
{0xf,0xf,0xf,0xf},
{0xba,0xba,0xba,0xba},
@@ -3474,7 +3447,7 @@ UCHAR XGI330New_SR15[8][8]={
{0x0,0xa5,0xfb,0xf6}
};
-UCHAR XGI330New_CR40[5][8]={
+unsigned char XGI330New_CR40[5][8] = {
{0x77,0x77,0x44,0x44},
{0x77,0x77,0x44,0x44},
{0x0,0x0,0x0,0x0},
@@ -3482,63 +3455,63 @@ UCHAR XGI330New_CR40[5][8]={
{0x0,0x0,0xf0,0xf8}
};
-UCHAR XGI330_CR49[]={0xaa,0x88};
-UCHAR XGI330_SR1F=0x0;
-UCHAR XGI330_SR21=0xa3;
-UCHAR XGI330_650_SR21=0xa7;
-UCHAR XGI330_SR22=0xfb;
-UCHAR XGI330_SR23=0xf6;
-UCHAR XGI330_SR24=0xd;
-
-UCHAR XGI660_SR21=0xa3;/* 2003.0312 */
-UCHAR XGI660_SR22=0xf3;/* 2003.0312 */
-
-UCHAR XGI330_LVDS_SR32=0x00; /* ynlai for 650 LVDS */
-UCHAR XGI330_LVDS_SR33=0x00; /* chiawen for 650 LVDS */
-UCHAR XGI330_650_SR31=0x40;
-UCHAR XGI330_650_SR33=0x04;
-UCHAR XGI330_CRT2Data_1_2 = 0x0;
-UCHAR XGI330_CRT2Data_4_D = 0x0;
-UCHAR XGI330_CRT2Data_4_E = 0x0;
-UCHAR XGI330_CRT2Data_4_10 = 0x80;
-USHORT XGI330_RGBSenseData = 0xd1;
-USHORT XGI330_VideoSenseData = 0xb9;
-USHORT XGI330_YCSenseData = 0xb3;
-USHORT XGI330_RGBSenseData2 = 0x0190; /*301b*/
-USHORT XGI330_VideoSenseData2 = 0x0110;
-USHORT XGI330_YCSenseData2 = 0x016B;
-UCHAR XGI330_NTSCPhase[] = {0x21,0xed,0x8a,0x8};
-UCHAR XGI330_PALPhase[] = {0x2a,0x5,0xd3,0x0};
-UCHAR XGI330_NTSCPhase2[] = {0x21,0xF0,0x7B,0xD6};/*301b*/
-UCHAR XGI330_PALPhase2[] = {0x2a,0x09,0x86,0xe9};
-UCHAR XGI330_PALMPhase[] = {0x21,0xE4,0x2E,0x9B}; /*palmn*/
-UCHAR XGI330_PALNPhase[] = {0x21,0xF4,0x3E,0xBA};
-UCHAR XG40_I2CDefinition = 0x00 ;
-UCHAR XG20_CR97 = 0x10 ;
-
-UCHAR XG21_DVOSetting = 0x00 ;
-UCHAR XG21_CR2E = 0x00 ;
-UCHAR XG21_CR2F = 0x00 ;
-UCHAR XG21_CR46 = 0x00 ;
-UCHAR XG21_CR47 = 0x00 ;
-
-UCHAR XG27_CR97 = 0xC1 ;
-UCHAR XG27_SR36 = 0x30 ;
-UCHAR XG27_CR8F = 0x0C ;
-UCHAR XG27_CRD0[] = {0,0,0,0,0,0,0,0x82,0x00,0x66,0x01,0x00} ;
-UCHAR XG27_CRDE[] = {0,0} ;
-UCHAR XG27_SR40 = 0x04 ;
-UCHAR XG27_SR41 = 0x00 ;
-
-UCHAR XGI330_CHTVVCLKUNTSC[]={0x00 };
-
-UCHAR XGI330_CHTVVCLKONTSC[]={0x00 };
-
-UCHAR XGI330_CHTVVCLKUPAL[]={0x00 };
-
-UCHAR XGI330_CHTVVCLKOPAL[]={0x00 };
-
-UCHAR XGI7007_CHTVVCLKUNTSC[]={CH7007TVVCLK30_2,
+unsigned char XGI330_CR49[] = {0xaa, 0x88};
+unsigned char XGI330_SR1F = 0x0;
+unsigned char XGI330_SR21 = 0xa3;
+unsigned char XGI330_650_SR21 = 0xa7;
+unsigned char XGI330_SR22 = 0xfb;
+unsigned char XGI330_SR23 = 0xf6;
+unsigned char XGI330_SR24 = 0xd;
+
+unsigned char XGI660_SR21 = 0xa3;/* 2003.0312 */
+unsigned char XGI660_SR22 = 0xf3;/* 2003.0312 */
+
+unsigned char XGI330_LVDS_SR32 = 0x00; /* ynlai for 650 LVDS */
+unsigned char XGI330_LVDS_SR33 = 0x00; /* chiawen for 650 LVDS */
+unsigned char XGI330_650_SR31 = 0x40;
+unsigned char XGI330_650_SR33 = 0x04;
+unsigned char XGI330_CRT2Data_1_2 = 0x0;
+unsigned char XGI330_CRT2Data_4_D = 0x0;
+unsigned char XGI330_CRT2Data_4_E = 0x0;
+unsigned char XGI330_CRT2Data_4_10 = 0x80;
+unsigned short XGI330_RGBSenseData = 0xd1;
+unsigned short XGI330_VideoSenseData = 0xb9;
+unsigned short XGI330_YCSenseData = 0xb3;
+unsigned short XGI330_RGBSenseData2 = 0x0190; /*301b*/
+unsigned short XGI330_VideoSenseData2 = 0x0110;
+unsigned short XGI330_YCSenseData2 = 0x016B;
+unsigned char XGI330_NTSCPhase[] = {0x21, 0xed, 0x8a, 0x8};
+unsigned char XGI330_PALPhase[] = {0x2a, 0x5, 0xd3, 0x0};
+unsigned char XGI330_NTSCPhase2[] = {0x21, 0xF0, 0x7B, 0xD6};/*301b*/
+unsigned char XGI330_PALPhase2[] = {0x2a, 0x09, 0x86, 0xe9};
+unsigned char XGI330_PALMPhase[] = {0x21, 0xE4, 0x2E, 0x9B}; /*palmn*/
+unsigned char XGI330_PALNPhase[] = {0x21, 0xF4, 0x3E, 0xBA};
+unsigned char XG40_I2CDefinition = 0x00 ;
+unsigned char XG20_CR97 = 0x10 ;
+
+unsigned char XG21_DVOSetting = 0x00 ;
+unsigned char XG21_CR2E = 0x00 ;
+unsigned char XG21_CR2F = 0x00 ;
+unsigned char XG21_CR46 = 0x00 ;
+unsigned char XG21_CR47 = 0x00 ;
+
+unsigned char XG27_CR97 = 0xC1 ;
+unsigned char XG27_SR36 = 0x30 ;
+unsigned char XG27_CR8F = 0x0C ;
+unsigned char XG27_CRD0[] = {0, 0, 0, 0, 0, 0, 0, 0x82, 0x00, 0x66, 0x01, 0x00};
+unsigned char XG27_CRDE[] = {0, 0};
+unsigned char XG27_SR40 = 0x04 ;
+unsigned char XG27_SR41 = 0x00 ;
+
+unsigned char XGI330_CHTVVCLKUNTSC[] = {0x00};
+
+unsigned char XGI330_CHTVVCLKONTSC[] = {0x00};
+
+unsigned char XGI330_CHTVVCLKUPAL[] = {0x00};
+
+unsigned char XGI330_CHTVVCLKOPAL[] = {0x00};
+
+unsigned char XGI7007_CHTVVCLKUNTSC[] = {CH7007TVVCLK30_2,
CH7007TVVCLK30_2,
CH7007TVVCLK30_2,
CH7007TVVCLK30_2,
@@ -3546,7 +3519,7 @@ UCHAR XGI7007_CHTVVCLKUNTSC[]={CH7007TVVCLK30_2,
CH7007TVVCLK47_8
};
-UCHAR XGI7007_CHTVVCLKONTSC[]={CH7007TVVCLK26_4,
+unsigned char XGI7007_CHTVVCLKONTSC[] = {CH7007TVVCLK26_4,
CH7007TVVCLK26_4,
CH7007TVVCLK26_4,
CH7007TVVCLK26_4,
@@ -3554,7 +3527,7 @@ UCHAR XGI7007_CHTVVCLKONTSC[]={CH7007TVVCLK26_4,
CH7007TVVCLK43_6
};
-UCHAR XGI7007_CHTVVCLKUPAL[]={CH7007TVVCLK31_5,
+unsigned char XGI7007_CHTVVCLKUPAL[] = {CH7007TVVCLK31_5,
CH7007TVVCLK31_5,
CH7007TVVCLK31_5,
CH7007TVVCLK31_5,
@@ -3562,7 +3535,7 @@ UCHAR XGI7007_CHTVVCLKUPAL[]={CH7007TVVCLK31_5,
CH7007TVVCLK39
};
-UCHAR XGI7007_CHTVVCLKOPAL[]={CH7007TVVCLK31_5,
+unsigned char XGI7007_CHTVVCLKOPAL[] = {CH7007TVVCLK31_5,
CH7007TVVCLK31_5,
CH7007TVVCLK31_5,
CH7007TVVCLK31_5,
@@ -3570,7 +3543,7 @@ UCHAR XGI7007_CHTVVCLKOPAL[]={CH7007TVVCLK31_5,
CH7007TVVCLK36
};
-XGI330_VCLKDataStruct XGI_CH7007VCLKData[]=
+struct XGI330_VCLKDataStruct XGI_CH7007VCLKData[] =
{
{ 0x60,0x36,30}, /* 0 30.2 MHZ */
{ 0x40,0x4A,28}, /* 1 28.19 MHZ */
@@ -3585,7 +3558,7 @@ XGI330_VCLKDataStruct XGI_CH7007VCLKData[]=
{ 0xFF,0x00,0 } /* End mark */
};
-XGI330_VCLKDataStruct XGI_VCLKData[]=
+struct XGI330_VCLKDataStruct XGI_VCLKData[] =
{
/* SR2B,SR2C,SR2D */
{ 0x1B,0xE1,25 },/* 00 (25.175MHz) */
@@ -3786,7 +3759,7 @@ XGI330_VCLKDataStruct XGI_VCLKData[]=
{ 0xFF,0x00,0 }/* End mark */
} ;
-XGI330_VCLKDataStruct XGI_VBVCLKData[]=
+struct XGI330_VCLKDataStruct XGI_VBVCLKData[] =
{
{ 0x1B,0xE1,25 },/* 00 (25.175MHz) */
@@ -3987,7 +3960,7 @@ XGI330_VCLKDataStruct XGI_VBVCLKData[]=
{ 0xFF,0x00,0 } /* End mark */
};
-UCHAR XGI660_TVDelayList[]=
+unsigned char XGI660_TVDelayList[] =
{
0x44, /* ; 0 ExtNTSCDelay */
0x44, /* ; 1 StNTSCDelay */
@@ -4003,7 +3976,7 @@ UCHAR XGI660_TVDelayList[]=
0x44 /* ; B StYPbPrDealy(750p) */
};
-UCHAR XGI660_TVDelayList2[]=
+unsigned char XGI660_TVDelayList2[] =
{
0x44, /* ; 0 ExtNTSCDelay */
0x44, /* ; 1 StNTSCDelay */
@@ -4019,7 +3992,7 @@ UCHAR XGI660_TVDelayList2[]=
0x44 /* ; B StYPbPrDealy(750p) */
};
-UCHAR XGI301TVDelayList[]=
+unsigned char XGI301TVDelayList[] =
{
0x22, /* ; 0 ExtNTSCDelay */
0x22, /* ; 1 StNTSCDelay */
@@ -4035,7 +4008,7 @@ UCHAR XGI301TVDelayList[]=
0x22 /* B StYPbPrDealy(750p) */
};
-UCHAR XGI301TVDelayList2[]=
+unsigned char XGI301TVDelayList2[] =
{
0x22, /* ; 0 ExtNTSCDelay */
0x22, /* ; 1 StNTSCDelay */
@@ -4052,7 +4025,7 @@ UCHAR XGI301TVDelayList2[]=
};
-UCHAR TVAntiFlickList[]=
+unsigned char TVAntiFlickList[] =
{/* NTSCAntiFlicker */
0x04, /* ; 0 Adaptive */
0x00, /* ; 1 new anti-flicker ? */
@@ -4065,7 +4038,7 @@ UCHAR TVAntiFlickList[]=
};
-UCHAR TVEdgeList[]=
+unsigned char TVEdgeList[] =
{
0x00, /* ; 0 NTSC No Edge enhance */
0x04, /* ; 1 NTSC Adaptive Edge enhance */
@@ -4075,7 +4048,7 @@ UCHAR TVEdgeList[]=
0x00 /* ; 1 HiTV */
};
-ULONG TVPhaseList[]=
+unsigned long TVPhaseList[] =
{ 0x08BAED21, /* ; 0 NTSC phase */
0x00E3052A, /* ; 1 PAL phase */
0x9B2EE421, /* ; 2 PAL-M phase */
@@ -4092,7 +4065,7 @@ ULONG TVPhaseList[]=
0xE00A831E /* ; D PAL-M 1024x768 */
};
-UCHAR NTSCYFilter1[]=
+unsigned char NTSCYFilter1[] =
{
0x00,0xF4,0x10,0x38 ,/* 0 : 320x text mode */
0x00,0xF4,0x10,0x38 ,/* 1 : 360x text mode */
@@ -4103,7 +4076,7 @@ UCHAR NTSCYFilter1[]=
0xEB,0x15,0x25,0xF6 /* 6 : 800x gra. mode */
};
-UCHAR PALYFilter1[]=
+unsigned char PALYFilter1[] =
{
0x00,0xF4,0x10,0x38, /* 0 : 320x text mode */
0x00,0xF4,0x10,0x38 ,/* 1 : 360x text mode */
@@ -4114,7 +4087,7 @@ UCHAR PALYFilter1[]=
0xFC,0xFB,0x14,0x2A /* 6 : 800x gra. mode */
};
-UCHAR PALMYFilter1[]=
+unsigned char PALMYFilter1[] =
{
0x00,0xF4,0x10,0x38, /* 0 : 320x text mode */
0x00,0xF4,0x10,0x38, /* 1 : 360x text mode */
@@ -4126,7 +4099,7 @@ UCHAR PALMYFilter1[]=
0xFF,0xFF,0xFF,0xFF /* End of Table */
};
-UCHAR PALNYFilter1[]=
+unsigned char PALNYFilter1[] =
{
0x00,0xF4,0x10,0x38, /* 0 : 320x text mode */
0x00,0xF4,0x10,0x38, /* 1 : 360x text mode */
@@ -4138,7 +4111,7 @@ UCHAR PALNYFilter1[]=
0xFF,0xFF,0xFF,0xFF /* End of Table */
};
-UCHAR NTSCYFilter2[]=
+unsigned char NTSCYFilter2[] =
{
0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46, /* 0 : 320x text mode */
0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C, /* 1 : 360x text mode */
@@ -4150,7 +4123,7 @@ UCHAR NTSCYFilter2[]=
0xFF,0xFF,0xFC,0x00,0x0F,0x22,0x28 /* 7 : 1024xgra. mode */
};
-UCHAR PALYFilter2[]=
+unsigned char PALYFilter2[] =
{
0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46, /* 0 : 320x text mode */
0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C, /* 1 : 360x text mode */
@@ -4162,7 +4135,7 @@ UCHAR PALYFilter2[]=
0xFF,0xFF,0xFC,0x00,0x0F,0x22,0x28 /* 7 : 1024xgra. mode */
};
-UCHAR PALMYFilter2[]=
+unsigned char PALMYFilter2[] =
{
0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46, /* 0 : 320x text mode */
0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C, /* 1 : 360x text mode */
@@ -4174,7 +4147,7 @@ UCHAR PALMYFilter2[]=
0xFF,0xFF,0xFC,0x00,0x0F,0x22,0x28 /* 7 : 1024xgra. mode */
};
-UCHAR PALNYFilter2[]=
+unsigned char PALNYFilter2[] =
{
0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46, /* 0 : 320x text mode */
0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C, /* 1 : 360x text mode */
@@ -4186,14 +4159,14 @@ UCHAR PALNYFilter2[]=
0xFF,0xFF,0xFC,0x00,0x0F,0x22,0x28 /* 7 : 1024xgra. mode */
};
-UCHAR XGI_NTSC1024AdjTime[]=
+unsigned char XGI_NTSC1024AdjTime[] =
{
0xa7,0x07,0xf2,0x6e,0x17,0x8b,0x73,0x53,
0x13,0x40,0x34,0xF4,0x63,0xBB,0xCC,0x7A,
0x58,0xe4,0x73,0xd0,0x13
};
-XGI301C_Tap4TimingStruct HiTVTap4Timing[]=
+struct XGI301C_Tap4TimingStruct HiTVTap4Timing[] =
{
{0,{
0x00,0x20,0x00,0x00,0x7F,0x20,0x02,0x7F, /* ; C0-C7 */
@@ -4208,7 +4181,7 @@ XGI301C_Tap4TimingStruct HiTVTap4Timing[]=
}
};
-XGI301C_Tap4TimingStruct EnlargeTap4Timing[]=
+struct XGI301C_Tap4TimingStruct EnlargeTap4Timing[] =
{
{0,{
0x00,0x20,0x00,0x00,0x7F,0x20,0x02,0x7F, /* ; C0-C7 */
@@ -4223,7 +4196,7 @@ XGI301C_Tap4TimingStruct EnlargeTap4Timing[]=
}
};
-XGI301C_Tap4TimingStruct NoScaleTap4Timing[]=
+struct XGI301C_Tap4TimingStruct NoScaleTap4Timing[] =
{
{0,{
0x00,0x20,0x00,0x00,0x7F,0x20,0x02,0x7F, /* ; C0-C7 */
@@ -4238,7 +4211,7 @@ XGI301C_Tap4TimingStruct NoScaleTap4Timing[]=
}
};
-XGI301C_Tap4TimingStruct PALTap4Timing[]=
+struct XGI301C_Tap4TimingStruct PALTap4Timing[] =
{
{600, {
0x05,0x19,0x05,0x7D,0x03,0x19,0x06,0x7E, /* ; C0-C7 */
@@ -4276,7 +4249,7 @@ XGI301C_Tap4TimingStruct PALTap4Timing[]=
}
};
-XGI301C_Tap4TimingStruct NTSCTap4Timing[]=
+struct XGI301C_Tap4TimingStruct NTSCTap4Timing[] =
{
{480, {
0x04,0x1A,0x04,0x7E,0x03,0x1A,0x06,0x7D, /* ; C0-C7 */
@@ -4314,7 +4287,7 @@ XGI301C_Tap4TimingStruct NTSCTap4Timing[]=
}
};
-XGI301C_Tap4TimingStruct YPbPr525pTap4Timing[]=
+struct XGI301C_Tap4TimingStruct YPbPr525pTap4Timing[] =
{
{480, {
0x04,0x1A,0x04,0x7E,0x03,0x1A,0x06,0x7D, /* ; C0-C7 */
@@ -4352,7 +4325,7 @@ XGI301C_Tap4TimingStruct YPbPr525pTap4Timing[]=
}
};
-XGI301C_Tap4TimingStruct YPbPr525iTap4Timing[]=
+struct XGI301C_Tap4TimingStruct YPbPr525iTap4Timing[] =
{
{480, {
0x04,0x1A,0x04,0x7E,0x03,0x1A,0x06,0x7D, /* ; C0-C7 */
@@ -4390,7 +4363,7 @@ XGI301C_Tap4TimingStruct YPbPr525iTap4Timing[]=
}
};
-XGI301C_Tap4TimingStruct YPbPr750pTap4Timing[]=
+struct XGI301C_Tap4TimingStruct YPbPr750pTap4Timing[] =
{ {0xFFFF,
{
0x05,0x19,0x05,0x7D,0x03,0x19,0x06,0x7E, /* ; C0-C7 */
diff --git a/drivers/staging/xgifb/vb_util.c b/drivers/staging/xgifb/vb_util.c
index 87531b49b73..2c40368ceee 100644
--- a/drivers/staging/xgifb/vb_util.c
+++ b/drivers/staging/xgifb/vb_util.c
@@ -1,54 +1,25 @@
-#include "osdef.h"
#include "vb_def.h"
#include "vgatypes.h"
#include "vb_struct.h"
-#ifdef LINUX_KERNEL
#include "XGIfb.h"
#include <asm/io.h>
#include <linux/types.h>
-#endif
-
-#ifdef TC
-#include <stdio.h>
-#include <string.h>
-#include <conio.h>
-#include <dos.h>
-#endif
-
-#ifdef WIN2000
-#include <dderror.h>
-#include <devioctl.h>
-#include <miniport.h>
-#include <ntddvdeo.h>
-#include <video.h>
-
-#include "xgiv.h"
-#include "dd_i2c.h"
-#include "tools.h"
-#endif
-
-#ifdef LINUX_XF86
-#include "xf86.h"
-#include "xf86PciInfo.h"
-#include "xgi.h"
-#include "xgi_regs.h"
-#endif
-
-
-
-
-void XGINew_SetReg1( ULONG , USHORT , USHORT ) ;
-void XGINew_SetReg2( ULONG , USHORT , USHORT ) ;
-void XGINew_SetReg3( ULONG , USHORT ) ;
-void XGINew_SetReg4( ULONG , ULONG ) ;
-UCHAR XGINew_GetReg1( ULONG , USHORT) ;
-UCHAR XGINew_GetReg2( ULONG ) ;
-ULONG XGINew_GetReg3( ULONG ) ;
-void XGINew_ClearDAC( PUCHAR ) ;
-void XGINew_SetRegANDOR(ULONG Port,USHORT Index,USHORT DataAND,USHORT DataOR);
-void XGINew_SetRegOR(ULONG Port,USHORT Index,USHORT DataOR);
-void XGINew_SetRegAND(ULONG Port,USHORT Index,USHORT DataAND);
+
+void XGINew_SetReg1(unsigned long,unsigned short,unsigned short);
+void XGINew_SetReg2(unsigned long,unsigned short,unsigned short);
+void XGINew_SetReg3(unsigned long,unsigned short);
+void XGINew_SetReg4(unsigned long,unsigned long);
+unsigned char XGINew_GetReg1(unsigned long, unsigned short);
+unsigned char XGINew_GetReg2(unsigned long);
+unsigned long XGINew_GetReg3(unsigned long);
+void XGINew_ClearDAC(unsigned char *);
+void XGINew_SetRegANDOR(unsigned long Port,unsigned short Index,
+ unsigned short DataAND,unsigned short DataOR);
+void XGINew_SetRegOR(unsigned long Port,unsigned short Index,
+ unsigned short DataOR);
+void XGINew_SetRegAND(unsigned long Port,unsigned short Index,
+ unsigned short DataAND);
/* --------------------------------------------------------------------- */
@@ -57,15 +28,10 @@ void XGINew_SetRegAND(ULONG Port,USHORT Index,USHORT DataAND);
/* Output : */
/* Description : SR CRTC GR */
/* --------------------------------------------------------------------- */
-void XGINew_SetReg1( ULONG port , USHORT index , USHORT data )
+void XGINew_SetReg1( unsigned long port , unsigned short index , unsigned short data )
{
-#ifdef LINUX_XF86
- OutPortByte( ( PUCHAR )(ULONG)port , index ) ;
- OutPortByte( ( PUCHAR )(ULONG)port + 1 , data ) ;
-#else
- OutPortByte( port , index ) ;
- OutPortByte( port + 1 , data ) ;
-#endif
+ outb(index, port);
+ outb(data, port + 1);
}
@@ -75,9 +41,9 @@ void XGINew_SetReg1( ULONG port , USHORT index , USHORT data )
/* Output : */
/* Description : AR( 3C0 ) */
/* --------------------------------------------------------------------- */
-/*void XGINew_SetReg2( ULONG port , USHORT index , USHORT data )
+/*void XGINew_SetReg2( unsigned long port , unsigned short index , unsigned short data )
{
- InPortByte( ( PUCHAR )port + 0x3da - 0x3c0 ) ;
+ InPortByte((P unsigned char )port + 0x3da - 0x3c0) ;
OutPortByte( XGINew_P3c0 , index ) ;
OutPortByte( XGINew_P3c0 , data ) ;
OutPortByte( XGINew_P3c0 , 0x20 ) ;
@@ -90,9 +56,9 @@ void XGINew_SetReg1( ULONG port , USHORT index , USHORT data )
/* Output : */
/* Description : */
/* --------------------------------------------------------------------- */
-void XGINew_SetReg3( ULONG port , USHORT data )
+void XGINew_SetReg3( unsigned long port , unsigned short data )
{
- OutPortByte( port , data ) ;
+ outb(data, port);
}
@@ -102,9 +68,9 @@ void XGINew_SetReg3( ULONG port , USHORT data )
/* Output : */
/* Description : */
/* --------------------------------------------------------------------- */
-void XGINew_SetReg4( ULONG port , ULONG data )
+void XGINew_SetReg4( unsigned long port , unsigned long data )
{
- OutPortLong( port , data ) ;
+ outl(data, port);
}
@@ -114,18 +80,12 @@ void XGINew_SetReg4( ULONG port , ULONG data )
/* Output : */
/* Description : */
/* --------------------------------------------------------------------- */
-UCHAR XGINew_GetReg1( ULONG port , USHORT index )
+unsigned char XGINew_GetReg1(unsigned long port, unsigned short index)
{
- UCHAR data ;
-
-#ifdef LINUX_XF86
- OutPortByte( ( PUCHAR )(ULONG)port , index ) ;
- data = InPortByte( ( PUCHAR )(ULONG)port + 1 ) ;
-#else
- OutPortByte( port , index ) ;
- data = InPortByte( port + 1 ) ;
-#endif
+ unsigned char data ;
+ outb(index, port);
+ data = inb(port + 1) ;
return( data ) ;
}
@@ -136,11 +96,11 @@ UCHAR XGINew_GetReg1( ULONG port , USHORT index )
/* Output : */
/* Description : */
/* --------------------------------------------------------------------- */
-UCHAR XGINew_GetReg2( ULONG port )
+unsigned char XGINew_GetReg2(unsigned long port)
{
- UCHAR data ;
+ unsigned char data ;
- data = InPortByte( port ) ;
+ data = inb(port) ;
return( data ) ;
}
@@ -152,11 +112,11 @@ UCHAR XGINew_GetReg2( ULONG port )
/* Output : */
/* Description : */
/* --------------------------------------------------------------------- */
-ULONG XGINew_GetReg3( ULONG port )
+unsigned long XGINew_GetReg3( unsigned long port )
{
- ULONG data ;
+ unsigned long data ;
- data = InPortLong( port ) ;
+ data = inl(port) ;
return( data ) ;
}
@@ -169,9 +129,9 @@ ULONG XGINew_GetReg3( ULONG port )
/* Output : */
/* Description : */
/* --------------------------------------------------------------------- */
-void XGINew_SetRegANDOR( ULONG Port , USHORT Index , USHORT DataAND , USHORT DataOR )
+void XGINew_SetRegANDOR( unsigned long Port , unsigned short Index , unsigned short DataAND , unsigned short DataOR )
{
- USHORT temp ;
+ unsigned short temp ;
temp = XGINew_GetReg1( Port , Index ) ; /* XGINew_Part1Port index 02 */
temp = ( temp & ( DataAND ) ) | DataOR ;
@@ -185,9 +145,9 @@ void XGINew_SetRegANDOR( ULONG Port , USHORT Index , USHORT DataAND , USHORT Dat
/* Output : */
/* Description : */
/* --------------------------------------------------------------------- */
-void XGINew_SetRegAND(ULONG Port,USHORT Index,USHORT DataAND)
+void XGINew_SetRegAND(unsigned long Port,unsigned short Index,unsigned short DataAND)
{
- USHORT temp ;
+ unsigned short temp ;
temp = XGINew_GetReg1( Port , Index ) ; /* XGINew_Part1Port index 02 */
temp &= DataAND ;
@@ -201,9 +161,9 @@ void XGINew_SetRegAND(ULONG Port,USHORT Index,USHORT DataAND)
/* Output : */
/* Description : */
/* --------------------------------------------------------------------- */
-void XGINew_SetRegOR( ULONG Port , USHORT Index , USHORT DataOR )
+void XGINew_SetRegOR( unsigned long Port , unsigned short Index , unsigned short DataOR )
{
- USHORT temp ;
+ unsigned short temp ;
temp = XGINew_GetReg1( Port , Index ) ; /* XGINew_Part1Port index 02 */
temp |= DataOR ;
@@ -219,29 +179,14 @@ void XGINew_SetRegOR( ULONG Port , USHORT Index , USHORT DataOR )
/* --------------------------------------------------------------------- */
void NewDelaySeconds( int seconds )
{
-#ifdef WIN2000
- int j ;
-#endif
int i ;
for( i = 0 ; i < seconds ; i++ )
{
-#ifdef TC
- delay( 1000 ) ;
-#endif
-
-#ifdef WIN2000
- for ( j = 0 ; j < 20000 ; j++ )
- VideoPortStallExecution( 50 ) ;
-#endif
-#ifdef WINCE_HEADER
-#endif
-#ifdef LINUX_KERNEL
-#endif
}
}
@@ -252,7 +197,7 @@ void NewDelaySeconds( int seconds )
/* Output : */
/* Description : */
/* --------------------------------------------------------------------- */
-void Newdebugcode( UCHAR code )
+void Newdebugcode(unsigned char code)
{
// OutPortByte ( 0x80 , code ) ;
/* OutPortByte ( 0x300 , code ) ; */
diff --git a/drivers/staging/xgifb/vb_util.h b/drivers/staging/xgifb/vb_util.h
index 91779d8cfdc..156f6445c88 100644
--- a/drivers/staging/xgifb/vb_util.h
+++ b/drivers/staging/xgifb/vb_util.h
@@ -1,15 +1,15 @@
#ifndef _VBUTIL_
#define _VBUTIL_
extern void NewDelaySeconds( int );
-extern void Newdebugcode( UCHAR );
-extern void XGINew_SetReg1(ULONG, USHORT, USHORT);
-extern void XGINew_SetReg3(ULONG, USHORT);
-extern UCHAR XGINew_GetReg1(ULONG, USHORT);
-extern UCHAR XGINew_GetReg2(ULONG);
-extern void XGINew_SetReg4(ULONG, ULONG);
-extern ULONG XGINew_GetReg3(ULONG);
-extern void XGINew_SetRegOR(ULONG Port,USHORT Index,USHORT DataOR);
-extern void XGINew_SetRegAND(ULONG Port,USHORT Index,USHORT DataAND);
-extern void XGINew_SetRegANDOR(ULONG Port,USHORT Index,USHORT DataAND,USHORT DataOR);
+extern void Newdebugcode(unsigned char);
+extern void XGINew_SetReg1(unsigned long, unsigned short, unsigned short);
+extern void XGINew_SetReg3(unsigned long, unsigned short);
+extern unsigned char XGINew_GetReg1(unsigned long, unsigned short);
+extern unsigned char XGINew_GetReg2(unsigned long);
+extern void XGINew_SetReg4(unsigned long, unsigned long);
+extern unsigned long XGINew_GetReg3(unsigned long);
+extern void XGINew_SetRegOR(unsigned long Port,unsigned short Index,unsigned short DataOR);
+extern void XGINew_SetRegAND(unsigned long Port,unsigned short Index,unsigned short DataAND);
+extern void XGINew_SetRegANDOR(unsigned long Port,unsigned short Index,unsigned short DataAND,unsigned short DataOR);
#endif
diff --git a/drivers/staging/xgifb/vgatypes.h b/drivers/staging/xgifb/vgatypes.h
index 295ea860ae4..df839eeb5ef 100644
--- a/drivers/staging/xgifb/vgatypes.h
+++ b/drivers/staging/xgifb/vgatypes.h
@@ -2,136 +2,14 @@
#ifndef _VGATYPES_
#define _VGATYPES_
-#include "osdef.h"
-
-#ifdef LINUX_XF86
-#include "xf86Version.h"
-#include "xf86Pci.h"
-#endif
-
-#ifdef LINUX_KERNEL /* We don't want the X driver to depend on kernel source */
#include <linux/ioctl.h>
-#endif
-
-#ifndef FALSE
-#define FALSE 0
-#endif
-
-#ifndef TRUE
-#define TRUE 1
-#endif
-
-#ifndef NULL
-#define NULL 0
-#endif
-
-#ifndef CHAR
-typedef char CHAR;
-#endif
-
-#ifndef SHORT
-typedef short SHORT;
-#endif
-
-#ifndef LONG
-typedef long LONG;
-#endif
-
-#ifndef UCHAR
-typedef unsigned char UCHAR;
-#endif
-
-#ifndef USHORT
-typedef unsigned short USHORT;
-#endif
-
-#ifndef ULONG
-typedef unsigned long ULONG;
-#endif
-
-#ifndef PUCHAR
-typedef UCHAR *PUCHAR;
-#endif
-
-#ifndef PUSHORT
-typedef USHORT *PUSHORT;
-#endif
-
-#ifndef PLONGU
-typedef ULONG *PULONG;
-#endif
-
-#ifndef VOID
-typedef void VOID;
-#endif
-
-#ifndef PVOID
-typedef void *PVOID;
-#endif
-
-#ifndef BOOLEAN
-typedef UCHAR BOOLEAN;
-#endif
-/*
-#ifndef bool
-typedef UCHAR bool;
-#endif
-*/
-#ifdef LINUX_KERNEL
-typedef unsigned long XGIIOADDRESS;
-#endif
-
-#ifdef LINUX_XF86
-#if XF86_VERSION_CURRENT < XF86_VERSION_NUMERIC(4,2,0,0,0)
-typedef unsigned char IOADDRESS;
-typedef unsigned char XGIIOADDRESS;
-#else
-typedef IOADDRESS XGIIOADDRESS;
-#endif
-#endif
#ifndef VBIOS_VER_MAX_LENGTH
-#define VBIOS_VER_MAX_LENGTH 4
-#endif
-
-#ifndef WIN2000
-
-#ifndef LINUX_KERNEL /* For the linux kernel, this is defined in xgifb.h */
-#ifndef XGI_CHIP_TYPE
-typedef enum _XGI_CHIP_TYPE {
- XGI_VGALegacy = 0,
-#ifdef LINUX_XF86
- XGI_530,
- XGI_OLD,
-#endif
- XGI_300,
- XGI_630,
- XGI_640,
- XGI_315H,
- XGI_315,
- XGI_315PRO,
- XGI_550,
- XGI_650,
- XGI_650M,
- XGI_740,
- XGI_330,
- XGI_661,
- XGI_660,
- XGI_760,
- XG40 = 32,
- XG41,
- XG42,
- XG45,
- XG20 = 48,
- XG21,
- XG27,
- MAX_XGI_CHIP
-} XGI_CHIP_TYPE;
-#endif
+#define VBIOS_VER_MAX_LENGTH 5
#endif
#ifndef XGI_VB_CHIP_TYPE
-typedef enum _XGI_VB_CHIP_TYPE {
+enum XGI_VB_CHIP_TYPE {
VB_CHIP_Legacy = 0,
VB_CHIP_301,
VB_CHIP_301B,
@@ -143,11 +21,11 @@ typedef enum _XGI_VB_CHIP_TYPE {
VB_CHIP_302ELV,
VB_CHIP_UNKNOWN, /* other video bridge or no video bridge */
MAX_VB_CHIP
-} XGI_VB_CHIP_TYPE;
+};
#endif
#ifndef XGI_LCD_TYPE
-typedef enum _XGI_LCD_TYPE {
+enum XGI_LCD_TYPE {
LCD_INVALID = 0,
LCD_320x480, /* FSTN, DSTN */
LCD_640x480,
@@ -171,155 +49,90 @@ typedef enum _XGI_LCD_TYPE {
LCD_2048x1536,
LCD_CUSTOM,
LCD_UNKNOWN
-} XGI_LCD_TYPE;
+};
#endif
-#endif /* not WIN2000 */
-
-#ifndef PXGI_DSReg
-typedef struct _XGI_DSReg
+struct XGI_DSReg
{
- UCHAR jIdx;
- UCHAR jVal;
-} XGI_DSReg, *PXGI_DSReg;
-#endif
-
-#ifndef XGI_HW_DEVICE_INFO
-
-typedef struct _XGI_HW_DEVICE_INFO XGI_HW_DEVICE_INFO, *PXGI_HW_DEVICE_INFO;
-
-typedef BOOLEAN (*PXGI_QUERYSPACE) (PXGI_HW_DEVICE_INFO, ULONG, ULONG, ULONG *);
+ unsigned char jIdx;
+ unsigned char jVal;
+};
-struct _XGI_HW_DEVICE_INFO
+struct xgi_hw_device_info
{
- ULONG ulExternalChip; /* NO VB or other video bridge*/
+ unsigned long ulExternalChip; /* NO VB or other video bridge*/
/* if ujVBChipID = VB_CHIP_UNKNOWN, */
-#ifdef LINUX_XF86
- PCITAG PciTag; /* PCI Tag */
-#endif
- PUCHAR pjVirtualRomBase; /* ROM image */
+ unsigned char *pjVirtualRomBase; /* ROM image */
- BOOLEAN UseROM; /* Use the ROM image if provided */
+ unsigned char UseROM; /* Use the ROM image if provided */
- PVOID pDevice;
+ void *pDevice;
- PUCHAR pjVideoMemoryAddress;/* base virtual memory address */
+ unsigned char *pjVideoMemoryAddress;/* base virtual memory address */
/* of Linear VGA memory */
- ULONG ulVideoMemorySize; /* size, in bytes, of the memory on the board */
+ unsigned long ulVideoMemorySize; /* size, in bytes, of the memory on the board */
- PUCHAR pjIOAddress; /* base I/O address of VGA ports (0x3B0) */
+ unsigned char *pjIOAddress; /* base I/O address of VGA ports (0x3B0) */
- PUCHAR pjCustomizedROMImage;
+ unsigned char *pjCustomizedROMImage;
- PUCHAR pj2ndVideoMemoryAddress;
- ULONG ul2ndVideoMemorySize;
+ unsigned char *pj2ndVideoMemoryAddress;
+ unsigned long ul2ndVideoMemorySize;
- PUCHAR pj2ndIOAddress;
-/*#ifndef WIN2000
- XGIIOADDRESS pjIOAddress; // base I/O address of VGA ports (0x3B0)
-#endif */
- UCHAR jChipType; /* Used to Identify Graphics Chip */
+ unsigned char *pj2ndIOAddress;
+ unsigned char jChipType; /* Used to Identify Graphics Chip */
/* defined in the data structure type */
/* "XGI_CHIP_TYPE" */
- UCHAR jChipRevision; /* Used to Identify Graphics Chip Revision */
+ unsigned char jChipRevision; /* Used to Identify Graphics Chip Revision */
- UCHAR ujVBChipID; /* the ID of video bridge */
+ unsigned char ujVBChipID; /* the ID of video bridge */
/* defined in the data structure type */
/* "XGI_VB_CHIP_TYPE" */
- BOOLEAN bNewScratch;
+ unsigned char bNewScratch;
- ULONG ulCRT2LCDType; /* defined in the data structure type */
+ unsigned long ulCRT2LCDType; /* defined in the data structure type */
- ULONG usExternalChip; /* NO VB or other video bridge (other than */
+ unsigned long usExternalChip; /* NO VB or other video bridge (other than */
/* video bridge) */
- BOOLEAN bIntegratedMMEnabled;/* supporting integration MM enable */
+ unsigned char bIntegratedMMEnabled;/* supporting integration MM enable */
- BOOLEAN bSkipDramSizing; /* True: Skip video memory sizing. */
+ unsigned char bSkipDramSizing; /* True: Skip video memory sizing. */
- BOOLEAN bSkipSense;
+ unsigned char bSkipSense;
- BOOLEAN bIsPowerSaving; /* True: XGIInit() is invoked by power management,
+ unsigned char bIsPowerSaving; /* True: XGIInit() is invoked by power management,
otherwise by 2nd adapter's initialzation */
- PXGI_DSReg pSR; /* restore SR registers in initial function. */
+ struct XGI_DSReg *pSR; /* restore SR registers in initial function. */
/* end data :(idx, val) = (FF, FF). */
/* Note : restore SR registers if */
- /* bSkipDramSizing = TRUE */
+ /* bSkipDramSizing = 1 */
- PXGI_DSReg pCR; /* restore CR registers in initial function. */
+ struct XGI_DSReg *pCR; /* restore CR registers in initial function. */
/* end data :(idx, val) = (FF, FF) */
/* Note : restore cR registers if */
- /* bSkipDramSizing = TRUE */
-/*
-#endif
-*/
+ /* bSkipDramSizing = 1 */
- PXGI_QUERYSPACE pQueryVGAConfigSpace;
+ unsigned char(*pQueryVGAConfigSpace)(struct xgi_hw_device_info *,
+ unsigned long, unsigned long,
+ unsigned long *);
- PXGI_QUERYSPACE pQueryNorthBridgeSpace;
+ unsigned char(*pQueryNorthBridgeSpace)(struct xgi_hw_device_info *,
+ unsigned long, unsigned long,
+ unsigned long *);
- UCHAR szVBIOSVer[VBIOS_VER_MAX_LENGTH];
+ unsigned char szVBIOSVer[VBIOS_VER_MAX_LENGTH];
};
-#endif
/* Addtional IOCTL for communication xgifb <> X driver */
/* If changing this, xgifb.h must also be changed (for xgifb) */
-#ifdef LINUX_XF86 /* We don't want the X driver to depend on the kernel source */
-
-/* ioctl for identifying and giving some info (esp. memory heap start) */
-#define XGIFB_GET_INFO 0x80046ef8 /* Wow, what a terrible hack... */
-
-/* Structure argument for XGIFB_GET_INFO ioctl */
-typedef struct _XGIFB_INFO xgifb_info, *pxgifb_info;
-
-struct _XGIFB_INFO {
- CARD32 xgifb_id; /* for identifying xgifb */
-#ifndef XGIFB_ID
-#define XGIFB_ID 0x53495346 /* Identify myself with 'XGIF' */
-#endif
- CARD32 chip_id; /* PCI ID of detected chip */
- CARD32 memory; /* video memory in KB which xgifb manages */
- CARD32 heapstart; /* heap start (= xgifb "mem" argument) in KB */
- CARD8 fbvidmode; /* current xgifb mode */
-
- CARD8 xgifb_version;
- CARD8 xgifb_revision;
- CARD8 xgifb_patchlevel;
-
- CARD8 xgifb_caps; /* xgifb's capabilities */
-
- CARD32 xgifb_tqlen; /* turbo queue length (in KB) */
-
- CARD32 xgifb_pcibus; /* The card's PCI ID */
- CARD32 xgifb_pcislot;
- CARD32 xgifb_pcifunc;
-
- CARD8 xgifb_lcdpdc;
-
- CARD8 xgifb_lcda;
-
- CARD32 xgifb_vbflags;
- CARD32 xgifb_currentvbflags;
-
- CARD32 xgifb_scalelcd;
- CARD32 xgifb_specialtiming;
-
- CARD8 xgifb_haveemi;
- CARD8 xgifb_emi30,xgifb_emi31,xgifb_emi32,xgifb_emi33;
- CARD8 xgifb_haveemilcd;
-
- CARD8 xgifb_lcdpdca;
-
- CARD8 reserved[212]; /* for future use */
-};
-#endif
#endif
diff --git a/drivers/staging/zram/Kconfig b/drivers/staging/zram/Kconfig
new file mode 100644
index 00000000000..4654ae2eb42
--- /dev/null
+++ b/drivers/staging/zram/Kconfig
@@ -0,0 +1,29 @@
+config ZRAM
+ tristate "Compressed RAM block device support"
+ depends on BLOCK
+ select LZO_COMPRESS
+ select LZO_DECOMPRESS
+ default n
+ help
+ Creates virtual block devices called /dev/zramX (X = 0, 1, ...).
+ Pages written to these disks are compressed and stored in memory
+ itself. These disks allow very fast I/O and compression provides
+ good amounts of memory savings.
+
+ It has several use cases, for example: /tmp storage, use as swap
+ disks and maybe many more.
+
+ See zram.txt for more information.
+ Project home: http://compcache.googlecode.com/
+
+config ZRAM_STATS
+ bool "Enable statistics for compressed RAM disks"
+ depends on ZRAM
+ default y
+ help
+ Enable statistics collection for compressed RAM devices. Statistics
+ are exported through ioctl interface, so you have to use zramconfig
+ program to get them. This adds only a minimal overhead.
+
+ If unsure, say Y.
+
diff --git a/drivers/staging/zram/Makefile b/drivers/staging/zram/Makefile
new file mode 100644
index 00000000000..b2c087aa105
--- /dev/null
+++ b/drivers/staging/zram/Makefile
@@ -0,0 +1,3 @@
+zram-objs := zram_drv.o xvmalloc.o
+
+obj-$(CONFIG_ZRAM) += zram.o
diff --git a/drivers/staging/ramzswap/xvmalloc.c b/drivers/staging/zram/xvmalloc.c
index 3fdbb8ada82..3fdbb8ada82 100644
--- a/drivers/staging/ramzswap/xvmalloc.c
+++ b/drivers/staging/zram/xvmalloc.c
diff --git a/drivers/staging/ramzswap/xvmalloc.h b/drivers/staging/zram/xvmalloc.h
index 5b1a81aa5fa..5b1a81aa5fa 100644
--- a/drivers/staging/ramzswap/xvmalloc.h
+++ b/drivers/staging/zram/xvmalloc.h
diff --git a/drivers/staging/ramzswap/xvmalloc_int.h b/drivers/staging/zram/xvmalloc_int.h
index e23ed5c8b8e..e23ed5c8b8e 100644
--- a/drivers/staging/ramzswap/xvmalloc_int.h
+++ b/drivers/staging/zram/xvmalloc_int.h
diff --git a/drivers/staging/zram/zram.txt b/drivers/staging/zram/zram.txt
new file mode 100644
index 00000000000..520edc1bea7
--- /dev/null
+++ b/drivers/staging/zram/zram.txt
@@ -0,0 +1,62 @@
+zram: Compressed RAM based block devices
+----------------------------------------
+
+Project home: http://compcache.googlecode.com/
+
+* Introduction
+
+The zram module creates RAM based block devices: /dev/ramX (X = 0, 1, ...).
+Pages written to these disks are compressed and stored in memory itself.
+These disks allow very fast I/O and compression provides good amounts of
+memory savings.
+
+See project home for use cases, performance numbers and a lot more.
+
+Individual zram devices are configured and initialized using zramconfig
+userspace utility as shown in examples below. See zramconfig man page for
+more details.
+
+* Usage
+
+Following shows a typical sequence of steps for using zram.
+
+1) Load Modules:
+ modprobe zram num_devices=4
+ This creates 4 (uninitialized) devices: /dev/zram{0,1,2,3}
+ (num_devices parameter is optional. Default: 1)
+
+2) Initialize:
+ Use zramconfig utility to configure and initialize individual
+ zram devices. For example:
+ zramconfig /dev/zram0 --init # uses default value of disksize_kb
+ zramconfig /dev/zram1 --disksize_kb=102400 # 100MB /dev/zram1
+
+ *See zramconfig man page for more details and examples*
+
+3) Activate:
+ mkswap /dev/zram0
+ swapon /dev/zram0
+
+ mkfs.ext4 /dev/zram1
+ mount /dev/zram1 /tmp
+
+4) Stats:
+ zramconfig /dev/zram0 --stats
+ zramconfig /dev/zram1 --stats
+
+5) Deactivate:
+ swapoff /dev/zram0
+ umount /dev/zram1
+
+6) Reset:
+ zramconfig /dev/zram0 --reset
+ zramconfig /dev/zram1 --reset
+ (This frees memory allocated for the given device).
+
+
+Please report any problems at:
+ - Mailing list: linux-mm-cc at laptop dot org
+ - Issue tracker: http://code.google.com/p/compcache/issues/list
+
+Nitin Gupta
+ngupta@vflare.org
diff --git a/drivers/staging/zram/zram_drv.c b/drivers/staging/zram/zram_drv.c
new file mode 100644
index 00000000000..77d4d715a78
--- /dev/null
+++ b/drivers/staging/zram/zram_drv.c
@@ -0,0 +1,805 @@
+/*
+ * Compressed RAM block device
+ *
+ * Copyright (C) 2008, 2009, 2010 Nitin Gupta
+ *
+ * This code is released using a dual license strategy: BSD/GPL
+ * You can choose the licence that better fits your requirements.
+ *
+ * Released under the terms of 3-clause BSD License
+ * Released under the terms of GNU General Public License Version 2.0
+ *
+ * Project home: http://compcache.googlecode.com
+ */
+
+#define KMSG_COMPONENT "zram"
+#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/bio.h>
+#include <linux/bitops.h>
+#include <linux/blkdev.h>
+#include <linux/buffer_head.h>
+#include <linux/device.h>
+#include <linux/genhd.h>
+#include <linux/highmem.h>
+#include <linux/slab.h>
+#include <linux/lzo.h>
+#include <linux/string.h>
+#include <linux/vmalloc.h>
+
+#include "zram_drv.h"
+
+/* Globals */
+static int zram_major;
+static struct zram *devices;
+
+/* Module params (documentation at end) */
+static unsigned int num_devices;
+
+static int zram_test_flag(struct zram *zram, u32 index,
+ enum zram_pageflags flag)
+{
+ return zram->table[index].flags & BIT(flag);
+}
+
+static void zram_set_flag(struct zram *zram, u32 index,
+ enum zram_pageflags flag)
+{
+ zram->table[index].flags |= BIT(flag);
+}
+
+static void zram_clear_flag(struct zram *zram, u32 index,
+ enum zram_pageflags flag)
+{
+ zram->table[index].flags &= ~BIT(flag);
+}
+
+static int page_zero_filled(void *ptr)
+{
+ unsigned int pos;
+ unsigned long *page;
+
+ page = (unsigned long *)ptr;
+
+ for (pos = 0; pos != PAGE_SIZE / sizeof(*page); pos++) {
+ if (page[pos])
+ return 0;
+ }
+
+ return 1;
+}
+
+static void zram_set_disksize(struct zram *zram, size_t totalram_bytes)
+{
+ if (!zram->disksize) {
+ pr_info(
+ "disk size not provided. You can use disksize_kb module "
+ "param to specify size.\nUsing default: (%u%% of RAM).\n",
+ default_disksize_perc_ram
+ );
+ zram->disksize = default_disksize_perc_ram *
+ (totalram_bytes / 100);
+ }
+
+ if (zram->disksize > 2 * (totalram_bytes)) {
+ pr_info(
+ "There is little point creating a zram of greater than "
+ "twice the size of memory since we expect a 2:1 compression "
+ "ratio. Note that zram uses about 0.1%% of the size of "
+ "the disk when not in use so a huge zram is "
+ "wasteful.\n"
+ "\tMemory Size: %zu kB\n"
+ "\tSize you selected: %zu kB\n"
+ "Continuing anyway ...\n",
+ totalram_bytes >> 10, zram->disksize
+ );
+ }
+
+ zram->disksize &= PAGE_MASK;
+}
+
+static void zram_ioctl_get_stats(struct zram *zram,
+ struct zram_ioctl_stats *s)
+{
+ s->disksize = zram->disksize;
+
+#if defined(CONFIG_ZRAM_STATS)
+ {
+ struct zram_stats *rs = &zram->stats;
+ size_t succ_writes, mem_used;
+ unsigned int good_compress_perc = 0, no_compress_perc = 0;
+
+ mem_used = xv_get_total_size_bytes(zram->mem_pool)
+ + (rs->pages_expand << PAGE_SHIFT);
+ succ_writes = zram_stat64_read(zram, &rs->num_writes) -
+ zram_stat64_read(zram, &rs->failed_writes);
+
+ if (succ_writes && rs->pages_stored) {
+ good_compress_perc = rs->good_compress * 100
+ / rs->pages_stored;
+ no_compress_perc = rs->pages_expand * 100
+ / rs->pages_stored;
+ }
+
+ s->num_reads = zram_stat64_read(zram, &rs->num_reads);
+ s->num_writes = zram_stat64_read(zram, &rs->num_writes);
+ s->failed_reads = zram_stat64_read(zram, &rs->failed_reads);
+ s->failed_writes = zram_stat64_read(zram, &rs->failed_writes);
+ s->invalid_io = zram_stat64_read(zram, &rs->invalid_io);
+ s->notify_free = zram_stat64_read(zram, &rs->notify_free);
+ s->pages_zero = rs->pages_zero;
+
+ s->good_compress_pct = good_compress_perc;
+ s->pages_expand_pct = no_compress_perc;
+
+ s->pages_stored = rs->pages_stored;
+ s->pages_used = mem_used >> PAGE_SHIFT;
+ s->orig_data_size = rs->pages_stored << PAGE_SHIFT;
+ s->compr_data_size = rs->compr_size;
+ s->mem_used_total = mem_used;
+ }
+#endif /* CONFIG_ZRAM_STATS */
+}
+
+static void zram_free_page(struct zram *zram, size_t index)
+{
+ u32 clen;
+ void *obj;
+
+ struct page *page = zram->table[index].page;
+ u32 offset = zram->table[index].offset;
+
+ if (unlikely(!page)) {
+ /*
+ * No memory is allocated for zero filled pages.
+ * Simply clear zero page flag.
+ */
+ if (zram_test_flag(zram, index, ZRAM_ZERO)) {
+ zram_clear_flag(zram, index, ZRAM_ZERO);
+ zram_stat_dec(&zram->stats.pages_zero);
+ }
+ return;
+ }
+
+ if (unlikely(zram_test_flag(zram, index, ZRAM_UNCOMPRESSED))) {
+ clen = PAGE_SIZE;
+ __free_page(page);
+ zram_clear_flag(zram, index, ZRAM_UNCOMPRESSED);
+ zram_stat_dec(&zram->stats.pages_expand);
+ goto out;
+ }
+
+ obj = kmap_atomic(page, KM_USER0) + offset;
+ clen = xv_get_object_size(obj) - sizeof(struct zobj_header);
+ kunmap_atomic(obj, KM_USER0);
+
+ xv_free(zram->mem_pool, page, offset);
+ if (clen <= PAGE_SIZE / 2)
+ zram_stat_dec(&zram->stats.good_compress);
+
+out:
+ zram->stats.compr_size -= clen;
+ zram_stat_dec(&zram->stats.pages_stored);
+
+ zram->table[index].page = NULL;
+ zram->table[index].offset = 0;
+}
+
+static void handle_zero_page(struct page *page)
+{
+ void *user_mem;
+
+ user_mem = kmap_atomic(page, KM_USER0);
+ memset(user_mem, 0, PAGE_SIZE);
+ kunmap_atomic(user_mem, KM_USER0);
+
+ flush_dcache_page(page);
+}
+
+static void handle_uncompressed_page(struct zram *zram,
+ struct page *page, u32 index)
+{
+ unsigned char *user_mem, *cmem;
+
+ user_mem = kmap_atomic(page, KM_USER0);
+ cmem = kmap_atomic(zram->table[index].page, KM_USER1) +
+ zram->table[index].offset;
+
+ memcpy(user_mem, cmem, PAGE_SIZE);
+ kunmap_atomic(user_mem, KM_USER0);
+ kunmap_atomic(cmem, KM_USER1);
+
+ flush_dcache_page(page);
+}
+
+static int zram_read(struct zram *zram, struct bio *bio)
+{
+
+ int i;
+ u32 index;
+ struct bio_vec *bvec;
+
+ zram_stat64_inc(zram, &zram->stats.num_reads);
+
+ index = bio->bi_sector >> SECTORS_PER_PAGE_SHIFT;
+ bio_for_each_segment(bvec, bio, i) {
+ int ret;
+ size_t clen;
+ struct page *page;
+ struct zobj_header *zheader;
+ unsigned char *user_mem, *cmem;
+
+ page = bvec->bv_page;
+
+ if (zram_test_flag(zram, index, ZRAM_ZERO)) {
+ handle_zero_page(page);
+ continue;
+ }
+
+ /* Requested page is not present in compressed area */
+ if (unlikely(!zram->table[index].page)) {
+ pr_debug("Read before write: sector=%lu, size=%u",
+ (ulong)(bio->bi_sector), bio->bi_size);
+ /* Do nothing */
+ continue;
+ }
+
+ /* Page is stored uncompressed since it's incompressible */
+ if (unlikely(zram_test_flag(zram, index, ZRAM_UNCOMPRESSED))) {
+ handle_uncompressed_page(zram, page, index);
+ continue;
+ }
+
+ user_mem = kmap_atomic(page, KM_USER0);
+ clen = PAGE_SIZE;
+
+ cmem = kmap_atomic(zram->table[index].page, KM_USER1) +
+ zram->table[index].offset;
+
+ ret = lzo1x_decompress_safe(
+ cmem + sizeof(*zheader),
+ xv_get_object_size(cmem) - sizeof(*zheader),
+ user_mem, &clen);
+
+ kunmap_atomic(user_mem, KM_USER0);
+ kunmap_atomic(cmem, KM_USER1);
+
+ /* Should NEVER happen. Return bio error if it does. */
+ if (unlikely(ret != LZO_E_OK)) {
+ pr_err("Decompression failed! err=%d, page=%u\n",
+ ret, index);
+ zram_stat64_inc(zram, &zram->stats.failed_reads);
+ goto out;
+ }
+
+ flush_dcache_page(page);
+ index++;
+ }
+
+ set_bit(BIO_UPTODATE, &bio->bi_flags);
+ bio_endio(bio, 0);
+ return 0;
+
+out:
+ bio_io_error(bio);
+ return 0;
+}
+
+static int zram_write(struct zram *zram, struct bio *bio)
+{
+ int i;
+ u32 index;
+ struct bio_vec *bvec;
+
+ zram_stat64_inc(zram, &zram->stats.num_writes);
+
+ index = bio->bi_sector >> SECTORS_PER_PAGE_SHIFT;
+
+ bio_for_each_segment(bvec, bio, i) {
+ int ret;
+ u32 offset;
+ size_t clen;
+ struct zobj_header *zheader;
+ struct page *page, *page_store;
+ unsigned char *user_mem, *cmem, *src;
+
+ page = bvec->bv_page;
+ src = zram->compress_buffer;
+
+ /*
+ * System overwrites unused sectors. Free memory associated
+ * with this sector now.
+ */
+ if (zram->table[index].page ||
+ zram_test_flag(zram, index, ZRAM_ZERO))
+ zram_free_page(zram, index);
+
+ mutex_lock(&zram->lock);
+
+ user_mem = kmap_atomic(page, KM_USER0);
+ if (page_zero_filled(user_mem)) {
+ kunmap_atomic(user_mem, KM_USER0);
+ mutex_unlock(&zram->lock);
+ zram_stat_inc(&zram->stats.pages_zero);
+ zram_set_flag(zram, index, ZRAM_ZERO);
+ continue;
+ }
+
+ ret = lzo1x_1_compress(user_mem, PAGE_SIZE, src, &clen,
+ zram->compress_workmem);
+
+ kunmap_atomic(user_mem, KM_USER0);
+
+ if (unlikely(ret != LZO_E_OK)) {
+ mutex_unlock(&zram->lock);
+ pr_err("Compression failed! err=%d\n", ret);
+ zram_stat64_inc(zram, &zram->stats.failed_writes);
+ goto out;
+ }
+
+ /*
+ * Page is incompressible. Store it as-is (uncompressed)
+ * since we do not want to return too many disk write
+ * errors which has side effect of hanging the system.
+ */
+ if (unlikely(clen > max_zpage_size)) {
+ clen = PAGE_SIZE;
+ page_store = alloc_page(GFP_NOIO | __GFP_HIGHMEM);
+ if (unlikely(!page_store)) {
+ mutex_unlock(&zram->lock);
+ pr_info("Error allocating memory for "
+ "incompressible page: %u\n", index);
+ zram_stat64_inc(zram,
+ &zram->stats.failed_writes);
+ goto out;
+ }
+
+ offset = 0;
+ zram_set_flag(zram, index, ZRAM_UNCOMPRESSED);
+ zram_stat_inc(&zram->stats.pages_expand);
+ zram->table[index].page = page_store;
+ src = kmap_atomic(page, KM_USER0);
+ goto memstore;
+ }
+
+ if (xv_malloc(zram->mem_pool, clen + sizeof(*zheader),
+ &zram->table[index].page, &offset,
+ GFP_NOIO | __GFP_HIGHMEM)) {
+ mutex_unlock(&zram->lock);
+ pr_info("Error allocating memory for compressed "
+ "page: %u, size=%zu\n", index, clen);
+ zram_stat64_inc(zram, &zram->stats.failed_writes);
+ goto out;
+ }
+
+memstore:
+ zram->table[index].offset = offset;
+
+ cmem = kmap_atomic(zram->table[index].page, KM_USER1) +
+ zram->table[index].offset;
+
+#if 0
+ /* Back-reference needed for memory defragmentation */
+ if (!zram_test_flag(zram, index, ZRAM_UNCOMPRESSED)) {
+ zheader = (struct zobj_header *)cmem;
+ zheader->table_idx = index;
+ cmem += sizeof(*zheader);
+ }
+#endif
+
+ memcpy(cmem, src, clen);
+
+ kunmap_atomic(cmem, KM_USER1);
+ if (unlikely(zram_test_flag(zram, index, ZRAM_UNCOMPRESSED)))
+ kunmap_atomic(src, KM_USER0);
+
+ /* Update stats */
+ zram->stats.compr_size += clen;
+ zram_stat_inc(&zram->stats.pages_stored);
+ if (clen <= PAGE_SIZE / 2)
+ zram_stat_inc(&zram->stats.good_compress);
+
+ mutex_unlock(&zram->lock);
+ index++;
+ }
+
+ set_bit(BIO_UPTODATE, &bio->bi_flags);
+ bio_endio(bio, 0);
+ return 0;
+
+out:
+ bio_io_error(bio);
+ return 0;
+}
+
+/*
+ * Check if request is within bounds and page aligned.
+ */
+static inline int valid_io_request(struct zram *zram, struct bio *bio)
+{
+ if (unlikely(
+ (bio->bi_sector >= (zram->disksize >> SECTOR_SHIFT)) ||
+ (bio->bi_sector & (SECTORS_PER_PAGE - 1)) ||
+ (bio->bi_size & (PAGE_SIZE - 1)))) {
+
+ return 0;
+ }
+
+ /* I/O request is valid */
+ return 1;
+}
+
+/*
+ * Handler function for all zram I/O requests.
+ */
+static int zram_make_request(struct request_queue *queue, struct bio *bio)
+{
+ int ret = 0;
+ struct zram *zram = queue->queuedata;
+
+ if (unlikely(!zram->init_done)) {
+ bio_io_error(bio);
+ return 0;
+ }
+
+ if (!valid_io_request(zram, bio)) {
+ zram_stat64_inc(zram, &zram->stats.invalid_io);
+ bio_io_error(bio);
+ return 0;
+ }
+
+ switch (bio_data_dir(bio)) {
+ case READ:
+ ret = zram_read(zram, bio);
+ break;
+
+ case WRITE:
+ ret = zram_write(zram, bio);
+ break;
+ }
+
+ return ret;
+}
+
+static void reset_device(struct zram *zram)
+{
+ size_t index;
+
+ /* Do not accept any new I/O request */
+ zram->init_done = 0;
+
+ /* Free various per-device buffers */
+ kfree(zram->compress_workmem);
+ free_pages((unsigned long)zram->compress_buffer, 1);
+
+ zram->compress_workmem = NULL;
+ zram->compress_buffer = NULL;
+
+ /* Free all pages that are still in this zram device */
+ for (index = 0; index < zram->disksize >> PAGE_SHIFT; index++) {
+ struct page *page;
+ u16 offset;
+
+ page = zram->table[index].page;
+ offset = zram->table[index].offset;
+
+ if (!page)
+ continue;
+
+ if (unlikely(zram_test_flag(zram, index, ZRAM_UNCOMPRESSED)))
+ __free_page(page);
+ else
+ xv_free(zram->mem_pool, page, offset);
+ }
+
+ vfree(zram->table);
+ zram->table = NULL;
+
+ xv_destroy_pool(zram->mem_pool);
+ zram->mem_pool = NULL;
+
+ /* Reset stats */
+ memset(&zram->stats, 0, sizeof(zram->stats));
+
+ zram->disksize = 0;
+}
+
+static int zram_ioctl_init_device(struct zram *zram)
+{
+ int ret;
+ size_t num_pages;
+
+ if (zram->init_done) {
+ pr_info("Device already initialized!\n");
+ return -EBUSY;
+ }
+
+ zram_set_disksize(zram, totalram_pages << PAGE_SHIFT);
+
+ zram->compress_workmem = kzalloc(LZO1X_MEM_COMPRESS, GFP_KERNEL);
+ if (!zram->compress_workmem) {
+ pr_err("Error allocating compressor working memory!\n");
+ ret = -ENOMEM;
+ goto fail;
+ }
+
+ zram->compress_buffer = (void *)__get_free_pages(__GFP_ZERO, 1);
+ if (!zram->compress_buffer) {
+ pr_err("Error allocating compressor buffer space\n");
+ ret = -ENOMEM;
+ goto fail;
+ }
+
+ num_pages = zram->disksize >> PAGE_SHIFT;
+ zram->table = vmalloc(num_pages * sizeof(*zram->table));
+ if (!zram->table) {
+ pr_err("Error allocating zram address table\n");
+ /* To prevent accessing table entries during cleanup */
+ zram->disksize = 0;
+ ret = -ENOMEM;
+ goto fail;
+ }
+ memset(zram->table, 0, num_pages * sizeof(*zram->table));
+
+ set_capacity(zram->disk, zram->disksize >> SECTOR_SHIFT);
+
+ /* zram devices sort of resembles non-rotational disks */
+ queue_flag_set_unlocked(QUEUE_FLAG_NONROT, zram->disk->queue);
+
+ zram->mem_pool = xv_create_pool();
+ if (!zram->mem_pool) {
+ pr_err("Error creating memory pool\n");
+ ret = -ENOMEM;
+ goto fail;
+ }
+
+ zram->init_done = 1;
+
+ pr_debug("Initialization done!\n");
+ return 0;
+
+fail:
+ reset_device(zram);
+
+ pr_err("Initialization failed: err=%d\n", ret);
+ return ret;
+}
+
+static int zram_ioctl_reset_device(struct zram *zram)
+{
+ if (zram->init_done)
+ reset_device(zram);
+
+ return 0;
+}
+
+static int zram_ioctl(struct block_device *bdev, fmode_t mode,
+ unsigned int cmd, unsigned long arg)
+{
+ int ret = 0;
+ size_t disksize_kb;
+
+ struct zram *zram = bdev->bd_disk->private_data;
+
+ switch (cmd) {
+ case ZRAMIO_SET_DISKSIZE_KB:
+ if (zram->init_done) {
+ ret = -EBUSY;
+ goto out;
+ }
+ if (copy_from_user(&disksize_kb, (void *)arg,
+ _IOC_SIZE(cmd))) {
+ ret = -EFAULT;
+ goto out;
+ }
+ zram->disksize = disksize_kb << 10;
+ pr_info("Disk size set to %zu kB\n", disksize_kb);
+ break;
+
+ case ZRAMIO_GET_STATS:
+ {
+ struct zram_ioctl_stats *stats;
+ if (!zram->init_done) {
+ ret = -ENOTTY;
+ goto out;
+ }
+ stats = kzalloc(sizeof(*stats), GFP_KERNEL);
+ if (!stats) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ zram_ioctl_get_stats(zram, stats);
+ if (copy_to_user((void *)arg, stats, sizeof(*stats))) {
+ kfree(stats);
+ ret = -EFAULT;
+ goto out;
+ }
+ kfree(stats);
+ break;
+ }
+ case ZRAMIO_INIT:
+ ret = zram_ioctl_init_device(zram);
+ break;
+
+ case ZRAMIO_RESET:
+ /* Do not reset an active device! */
+ if (bdev->bd_holders) {
+ ret = -EBUSY;
+ goto out;
+ }
+
+ /* Make sure all pending I/O is finished */
+ if (bdev)
+ fsync_bdev(bdev);
+
+ ret = zram_ioctl_reset_device(zram);
+ break;
+
+ default:
+ pr_info("Invalid ioctl %u\n", cmd);
+ ret = -ENOTTY;
+ }
+
+out:
+ return ret;
+}
+
+void zram_slot_free_notify(struct block_device *bdev, unsigned long index)
+{
+ struct zram *zram;
+
+ zram = bdev->bd_disk->private_data;
+ zram_free_page(zram, index);
+ zram_stat64_inc(zram, &zram->stats.notify_free);
+}
+
+static const struct block_device_operations zram_devops = {
+ .ioctl = zram_ioctl,
+ .swap_slot_free_notify = zram_slot_free_notify,
+ .owner = THIS_MODULE
+};
+
+static int create_device(struct zram *zram, int device_id)
+{
+ int ret = 0;
+
+ mutex_init(&zram->lock);
+ spin_lock_init(&zram->stat64_lock);
+
+ zram->queue = blk_alloc_queue(GFP_KERNEL);
+ if (!zram->queue) {
+ pr_err("Error allocating disk queue for device %d\n",
+ device_id);
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ blk_queue_make_request(zram->queue, zram_make_request);
+ zram->queue->queuedata = zram;
+
+ /* gendisk structure */
+ zram->disk = alloc_disk(1);
+ if (!zram->disk) {
+ blk_cleanup_queue(zram->queue);
+ pr_warning("Error allocating disk structure for device %d\n",
+ device_id);
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ zram->disk->major = zram_major;
+ zram->disk->first_minor = device_id;
+ zram->disk->fops = &zram_devops;
+ zram->disk->queue = zram->queue;
+ zram->disk->private_data = zram;
+ snprintf(zram->disk->disk_name, 16, "zram%d", device_id);
+
+ /* Actual capacity set using ZRAMIO_SET_DISKSIZE_KB ioctl */
+ set_capacity(zram->disk, 0);
+
+ /*
+ * To ensure that we always get PAGE_SIZE aligned
+ * and n*PAGE_SIZED sized I/O requests.
+ */
+ blk_queue_physical_block_size(zram->disk->queue, PAGE_SIZE);
+ blk_queue_logical_block_size(zram->disk->queue, PAGE_SIZE);
+ blk_queue_io_min(zram->disk->queue, PAGE_SIZE);
+ blk_queue_io_opt(zram->disk->queue, PAGE_SIZE);
+
+ add_disk(zram->disk);
+
+ zram->init_done = 0;
+
+out:
+ return ret;
+}
+
+static void destroy_device(struct zram *zram)
+{
+ if (zram->disk) {
+ del_gendisk(zram->disk);
+ put_disk(zram->disk);
+ }
+
+ if (zram->queue)
+ blk_cleanup_queue(zram->queue);
+}
+
+static int __init zram_init(void)
+{
+ int ret, dev_id;
+
+ if (num_devices > max_num_devices) {
+ pr_warning("Invalid value for num_devices: %u\n",
+ num_devices);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ zram_major = register_blkdev(0, "zram");
+ if (zram_major <= 0) {
+ pr_warning("Unable to get major number\n");
+ ret = -EBUSY;
+ goto out;
+ }
+
+ if (!num_devices) {
+ pr_info("num_devices not specified. Using default: 1\n");
+ num_devices = 1;
+ }
+
+ /* Allocate the device array and initialize each one */
+ pr_info("Creating %u devices ...\n", num_devices);
+ devices = kzalloc(num_devices * sizeof(struct zram), GFP_KERNEL);
+ if (!devices) {
+ ret = -ENOMEM;
+ goto unregister;
+ }
+
+ for (dev_id = 0; dev_id < num_devices; dev_id++) {
+ ret = create_device(&devices[dev_id], dev_id);
+ if (ret)
+ goto free_devices;
+ }
+
+ return 0;
+
+free_devices:
+ while (dev_id)
+ destroy_device(&devices[--dev_id]);
+unregister:
+ unregister_blkdev(zram_major, "zram");
+out:
+ return ret;
+}
+
+static void __exit zram_exit(void)
+{
+ int i;
+ struct zram *zram;
+
+ for (i = 0; i < num_devices; i++) {
+ zram = &devices[i];
+
+ destroy_device(zram);
+ if (zram->init_done)
+ reset_device(zram);
+ }
+
+ unregister_blkdev(zram_major, "zram");
+
+ kfree(devices);
+ pr_debug("Cleanup done!\n");
+}
+
+module_param(num_devices, uint, 0);
+MODULE_PARM_DESC(num_devices, "Number of zram devices");
+
+module_init(zram_init);
+module_exit(zram_exit);
+
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_AUTHOR("Nitin Gupta <ngupta@vflare.org>");
+MODULE_DESCRIPTION("Compressed RAM Block Device");
diff --git a/drivers/staging/ramzswap/ramzswap_drv.h b/drivers/staging/zram/zram_drv.h
index 63c30420df2..945f9740442 100644
--- a/drivers/staging/ramzswap/ramzswap_drv.h
+++ b/drivers/staging/zram/zram_drv.h
@@ -1,5 +1,5 @@
/*
- * Compressed RAM based swap device
+ * Compressed RAM block device
*
* Copyright (C) 2008, 2009, 2010 Nitin Gupta
*
@@ -12,13 +12,13 @@
* Project home: http://compcache.googlecode.com
*/
-#ifndef _RAMZSWAP_DRV_H_
-#define _RAMZSWAP_DRV_H_
+#ifndef _ZRAM_DRV_H_
+#define _ZRAM_DRV_H_
#include <linux/spinlock.h>
#include <linux/mutex.h>
-#include "ramzswap_ioctl.h"
+#include "zram_ioctl.h"
#include "xvmalloc.h"
/*
@@ -41,7 +41,7 @@ struct zobj_header {
/*-- Configurable parameters */
-/* Default ramzswap disk size: 25% of total RAM */
+/* Default zram disk size: 25% of total RAM */
static const unsigned default_disksize_perc_ram = 25;
/*
@@ -63,23 +63,20 @@ static const unsigned max_zpage_size = PAGE_SIZE / 4 * 3;
#define SECTORS_PER_PAGE_SHIFT (PAGE_SHIFT - SECTOR_SHIFT)
#define SECTORS_PER_PAGE (1 << SECTORS_PER_PAGE_SHIFT)
-/* Flags for ramzswap pages (table[page_no].flags) */
-enum rzs_pageflags {
+/* Flags for zram pages (table[page_no].flags) */
+enum zram_pageflags {
/* Page is stored uncompressed */
- RZS_UNCOMPRESSED,
+ ZRAM_UNCOMPRESSED,
/* Page consists entirely of zeros */
- RZS_ZERO,
+ ZRAM_ZERO,
- __NR_RZS_PAGEFLAGS,
+ __NR_ZRAM_PAGEFLAGS,
};
/*-- Data structures */
-/*
- * Allocated for each swap slot, indexed by page no.
- * These table entries must fit exactly in a page.
- */
+/* Allocated for each disk page */
struct table {
struct page *page;
u16 offset;
@@ -87,17 +84,17 @@ struct table {
u8 flags;
} __attribute__((aligned(4)));
-struct ramzswap_stats {
+struct zram_stats {
/* basic stats */
size_t compr_size; /* compressed size of pages stored -
* needed to enforce memlimit */
/* more stats */
-#if defined(CONFIG_RAMZSWAP_STATS)
+#if defined(CONFIG_ZRAM_STATS)
u64 num_reads; /* failed + successful */
u64 num_writes; /* --do-- */
u64 failed_reads; /* should NEVER! happen */
u64 failed_writes; /* can happen when memory is too low */
- u64 invalid_io; /* non-swap I/O requests */
+ u64 invalid_io; /* non-page-aligned I/O requests */
u64 notify_free; /* no. of swap slot free notifications */
u32 pages_zero; /* no. of zero filled pages */
u32 pages_stored; /* no. of pages currently stored */
@@ -106,62 +103,62 @@ struct ramzswap_stats {
#endif
};
-struct ramzswap {
+struct zram {
struct xv_pool *mem_pool;
void *compress_workmem;
void *compress_buffer;
struct table *table;
spinlock_t stat64_lock; /* protect 64-bit stats */
- struct mutex lock;
+ struct mutex lock; /* protect compression buffers against
+ * concurrent writes */
struct request_queue *queue;
struct gendisk *disk;
int init_done;
/*
- * This is limit on amount of *uncompressed* worth of data
- * we can hold. When backing swap device is provided, it is
- * set equal to device size.
+ * This is the limit on amount of *uncompressed* worth of data
+ * we can store in a disk.
*/
size_t disksize; /* bytes */
- struct ramzswap_stats stats;
+ struct zram_stats stats;
};
/*-- */
/* Debugging and Stats */
-#if defined(CONFIG_RAMZSWAP_STATS)
-static void rzs_stat_inc(u32 *v)
+#if defined(CONFIG_ZRAM_STATS)
+static void zram_stat_inc(u32 *v)
{
*v = *v + 1;
}
-static void rzs_stat_dec(u32 *v)
+static void zram_stat_dec(u32 *v)
{
*v = *v - 1;
}
-static void rzs_stat64_inc(struct ramzswap *rzs, u64 *v)
+static void zram_stat64_inc(struct zram *zram, u64 *v)
{
- spin_lock(&rzs->stat64_lock);
+ spin_lock(&zram->stat64_lock);
*v = *v + 1;
- spin_unlock(&rzs->stat64_lock);
+ spin_unlock(&zram->stat64_lock);
}
-static u64 rzs_stat64_read(struct ramzswap *rzs, u64 *v)
+static u64 zram_stat64_read(struct zram *zram, u64 *v)
{
u64 val;
- spin_lock(&rzs->stat64_lock);
+ spin_lock(&zram->stat64_lock);
val = *v;
- spin_unlock(&rzs->stat64_lock);
+ spin_unlock(&zram->stat64_lock);
return val;
}
#else
-#define rzs_stat_inc(v)
-#define rzs_stat_dec(v)
-#define rzs_stat64_inc(r, v)
-#define rzs_stat64_read(r, v)
-#endif /* CONFIG_RAMZSWAP_STATS */
+#define zram_stat_inc(v)
+#define zram_stat_dec(v)
+#define zram_stat64_inc(r, v)
+#define zram_stat64_read(r, v)
+#endif /* CONFIG_ZRAM_STATS */
#endif
diff --git a/drivers/staging/ramzswap/ramzswap_ioctl.h b/drivers/staging/zram/zram_ioctl.h
index db94bcb4296..5c415fa4f17 100644
--- a/drivers/staging/ramzswap/ramzswap_ioctl.h
+++ b/drivers/staging/zram/zram_ioctl.h
@@ -1,5 +1,5 @@
/*
- * Compressed RAM based swap device
+ * Compressed RAM block device
*
* Copyright (C) 2008, 2009, 2010 Nitin Gupta
*
@@ -12,17 +12,16 @@
* Project home: http://compcache.googlecode.com
*/
-#ifndef _RAMZSWAP_IOCTL_H_
-#define _RAMZSWAP_IOCTL_H_
+#ifndef _ZRAM_IOCTL_H_
+#define _ZRAM_IOCTL_H_
-struct ramzswap_ioctl_stats {
- u64 disksize; /* user specified or equal to backing swap
- * size (if present) */
+struct zram_ioctl_stats {
+ u64 disksize; /* disksize in bytes (user specifies in KB) */
u64 num_reads; /* failed + successful */
u64 num_writes; /* --do-- */
u64 failed_reads; /* should NEVER! happen */
u64 failed_writes; /* can happen when memory is too low */
- u64 invalid_io; /* non-swap I/O requests */
+ u64 invalid_io; /* non-page-aligned I/O requests */
u64 notify_free; /* no. of swap slot free notifications */
u32 pages_zero; /* no. of zero filled pages */
u32 good_compress_pct; /* no. of pages with compression ratio<=50% */
@@ -34,9 +33,9 @@ struct ramzswap_ioctl_stats {
u64 mem_used_total;
} __attribute__ ((packed, aligned(4)));
-#define RZSIO_SET_DISKSIZE_KB _IOW('z', 0, size_t)
-#define RZSIO_GET_STATS _IOR('z', 1, struct ramzswap_ioctl_stats)
-#define RZSIO_INIT _IO('z', 2)
-#define RZSIO_RESET _IO('z', 3)
+#define ZRAMIO_SET_DISKSIZE_KB _IOW('z', 0, size_t)
+#define ZRAMIO_GET_STATS _IOR('z', 1, struct zram_ioctl_stats)
+#define ZRAMIO_INIT _IO('z', 2)
+#define ZRAMIO_RESET _IO('z', 3)
#endif
diff --git a/drivers/telephony/ixj_pcmcia.c b/drivers/telephony/ixj_pcmcia.c
index 99cb2246ac7..a1900e50251 100644
--- a/drivers/telephony/ixj_pcmcia.c
+++ b/drivers/telephony/ixj_pcmcia.c
@@ -8,7 +8,6 @@
#include <linux/errno.h> /* error codes */
#include <linux/slab.h>
-#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/cistpl.h>
#include <pcmcia/ds.h>
@@ -33,9 +32,8 @@ static int ixj_probe(struct pcmcia_device *p_dev)
{
dev_dbg(&p_dev->dev, "ixj_attach()\n");
/* Create new ixj device */
- p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
- p_dev->io.Attributes2 = IO_DATA_PATH_WIDTH_8;
- p_dev->io.IOAddrLines = 3;
+ p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_8;
+ p_dev->resource[1]->flags |= IO_DATA_PATH_WIDTH_8;
p_dev->conf.IntType = INT_MEMORY_AND_IO;
p_dev->priv = kzalloc(sizeof(struct ixj_info_t), GFP_KERNEL);
if (!p_dev->priv) {
@@ -121,13 +119,14 @@ static int ixj_config_check(struct pcmcia_device *p_dev,
{
if ((cfg->io.nwin > 0) || (dflt->io.nwin > 0)) {
cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt->io;
- p_dev->io.BasePort1 = io->win[0].base;
- p_dev->io.NumPorts1 = io->win[0].len;
+ p_dev->resource[0]->start = io->win[0].base;
+ p_dev->resource[0]->end = io->win[0].len;
+ p_dev->io_lines = 3;
if (io->nwin == 2) {
- p_dev->io.BasePort2 = io->win[1].base;
- p_dev->io.NumPorts2 = io->win[1].len;
+ p_dev->resource[1]->start = io->win[1].base;
+ p_dev->resource[1]->end = io->win[1].len;
}
- if (!pcmcia_request_io(p_dev, &p_dev->io))
+ if (!pcmcia_request_io(p_dev))
return 0;
}
return -ENODEV;
@@ -151,7 +150,8 @@ static int ixj_config(struct pcmcia_device * link)
/*
* Register the card with the core.
*/
- j = ixj_pcmcia_probe(link->io.BasePort1, link->io.BasePort1 + 0x10);
+ j = ixj_pcmcia_probe(link->resource[0]->start,
+ link->resource[0]->start + 0x10);
info->ndev = 1;
ixj_get_serial(link, j);
diff --git a/drivers/uio/uio_cif.c b/drivers/uio/uio_cif.c
index 371f87f8bc2..a8ea2f19a0c 100644
--- a/drivers/uio/uio_cif.c
+++ b/drivers/uio/uio_cif.c
@@ -79,7 +79,7 @@ static int __devinit hilscher_pci_probe(struct pci_dev *dev,
}
info->version = "0.0.1";
info->irq = dev->irq;
- info->irq_flags = IRQF_DISABLED | IRQF_SHARED;
+ info->irq_flags = IRQF_SHARED;
info->handler = hilscher_handler;
if (uio_register_device(&dev->dev, info))
diff --git a/drivers/uio/uio_pdrv_genirq.c b/drivers/uio/uio_pdrv_genirq.c
index 61e569df2bb..7174d518b8a 100644
--- a/drivers/uio/uio_pdrv_genirq.c
+++ b/drivers/uio/uio_pdrv_genirq.c
@@ -155,7 +155,6 @@ static int uio_pdrv_genirq_probe(struct platform_device *pdev)
* Interrupt sharing is not supported.
*/
- uioinfo->irq_flags |= IRQF_DISABLED;
uioinfo->handler = uio_pdrv_genirq_handler;
uioinfo->irqcontrol = uio_pdrv_genirq_irqcontrol;
uioinfo->open = uio_pdrv_genirq_open;
diff --git a/drivers/uio/uio_sercos3.c b/drivers/uio/uio_sercos3.c
index 3d461cd73e6..a187fa14c5c 100644
--- a/drivers/uio/uio_sercos3.c
+++ b/drivers/uio/uio_sercos3.c
@@ -154,7 +154,7 @@ static int __devinit sercos3_pci_probe(struct pci_dev *dev,
info->name = "Sercos_III_PCI";
info->version = "0.0.1";
info->irq = dev->irq;
- info->irq_flags = IRQF_DISABLED | IRQF_SHARED;
+ info->irq_flags = IRQF_SHARED;
info->handler = sercos3_handler;
info->irqcontrol = sercos3_irqcontrol;
diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig
index 6a58cb1330c..4aa00e6e57a 100644
--- a/drivers/usb/Kconfig
+++ b/drivers/usb/Kconfig
@@ -45,7 +45,8 @@ config USB_ARCH_HAS_OHCI
default y if STB03xxx
default y if PPC_MPC52xx
# MIPS:
- default y if SOC_AU1X00
+ default y if MIPS_ALCHEMY
+ default y if MACH_JZ4740
# SH:
default y if CPU_SUBTYPE_SH7720
default y if CPU_SUBTYPE_SH7721
diff --git a/drivers/usb/atm/cxacru.c b/drivers/usb/atm/cxacru.c
index c89990f5e01..101ffc965ee 100644
--- a/drivers/usb/atm/cxacru.c
+++ b/drivers/usb/atm/cxacru.c
@@ -866,50 +866,50 @@ static void cxacru_poll_status(struct work_struct *work)
instance->line_status = buf[CXINF_LINE_STATUS];
switch (instance->line_status) {
case 0:
- atm_dev->signal = ATM_PHY_SIG_LOST;
+ atm_dev_signal_change(atm_dev, ATM_PHY_SIG_LOST);
atm_info(usbatm, "ADSL line: down\n");
break;
case 1:
- atm_dev->signal = ATM_PHY_SIG_LOST;
+ atm_dev_signal_change(atm_dev, ATM_PHY_SIG_LOST);
atm_info(usbatm, "ADSL line: attempting to activate\n");
break;
case 2:
- atm_dev->signal = ATM_PHY_SIG_LOST;
+ atm_dev_signal_change(atm_dev, ATM_PHY_SIG_LOST);
atm_info(usbatm, "ADSL line: training\n");
break;
case 3:
- atm_dev->signal = ATM_PHY_SIG_LOST;
+ atm_dev_signal_change(atm_dev, ATM_PHY_SIG_LOST);
atm_info(usbatm, "ADSL line: channel analysis\n");
break;
case 4:
- atm_dev->signal = ATM_PHY_SIG_LOST;
+ atm_dev_signal_change(atm_dev, ATM_PHY_SIG_LOST);
atm_info(usbatm, "ADSL line: exchange\n");
break;
case 5:
atm_dev->link_rate = buf[CXINF_DOWNSTREAM_RATE] * 1000 / 424;
- atm_dev->signal = ATM_PHY_SIG_FOUND;
+ atm_dev_signal_change(atm_dev, ATM_PHY_SIG_FOUND);
atm_info(usbatm, "ADSL line: up (%d kb/s down | %d kb/s up)\n",
buf[CXINF_DOWNSTREAM_RATE], buf[CXINF_UPSTREAM_RATE]);
break;
case 6:
- atm_dev->signal = ATM_PHY_SIG_LOST;
+ atm_dev_signal_change(atm_dev, ATM_PHY_SIG_LOST);
atm_info(usbatm, "ADSL line: waiting\n");
break;
case 7:
- atm_dev->signal = ATM_PHY_SIG_LOST;
+ atm_dev_signal_change(atm_dev, ATM_PHY_SIG_LOST);
atm_info(usbatm, "ADSL line: initializing\n");
break;
default:
- atm_dev->signal = ATM_PHY_SIG_UNKNOWN;
+ atm_dev_signal_change(atm_dev, ATM_PHY_SIG_UNKNOWN);
atm_info(usbatm, "Unknown line state %02x\n", instance->line_status);
break;
}
diff --git a/drivers/usb/atm/speedtch.c b/drivers/usb/atm/speedtch.c
index 1335456b4f9..80f9617d3a1 100644
--- a/drivers/usb/atm/speedtch.c
+++ b/drivers/usb/atm/speedtch.c
@@ -525,7 +525,7 @@ static void speedtch_check_status(struct work_struct *work)
switch (status) {
case 0:
- atm_dev->signal = ATM_PHY_SIG_LOST;
+ atm_dev_signal_change(atm_dev, ATM_PHY_SIG_LOST);
if (instance->last_status)
atm_info(usbatm, "ADSL line is down\n");
/* It may never resync again unless we ask it to... */
@@ -533,12 +533,12 @@ static void speedtch_check_status(struct work_struct *work)
break;
case 0x08:
- atm_dev->signal = ATM_PHY_SIG_UNKNOWN;
+ atm_dev_signal_change(atm_dev, ATM_PHY_SIG_UNKNOWN);
atm_info(usbatm, "ADSL line is blocked?\n");
break;
case 0x10:
- atm_dev->signal = ATM_PHY_SIG_LOST;
+ atm_dev_signal_change(atm_dev, ATM_PHY_SIG_LOST);
atm_info(usbatm, "ADSL line is synchronising\n");
break;
@@ -554,7 +554,7 @@ static void speedtch_check_status(struct work_struct *work)
}
atm_dev->link_rate = down_speed * 1000 / 424;
- atm_dev->signal = ATM_PHY_SIG_FOUND;
+ atm_dev_signal_change(atm_dev, ATM_PHY_SIG_FOUND);
atm_info(usbatm,
"ADSL line is up (%d kb/s down | %d kb/s up)\n",
@@ -562,7 +562,7 @@ static void speedtch_check_status(struct work_struct *work)
break;
default:
- atm_dev->signal = ATM_PHY_SIG_UNKNOWN;
+ atm_dev_signal_change(atm_dev, ATM_PHY_SIG_UNKNOWN);
atm_info(usbatm, "unknown line state %02x\n", status);
break;
}
diff --git a/drivers/usb/atm/ueagle-atm.c b/drivers/usb/atm/ueagle-atm.c
index e213d3fa492..ebae9448014 100644
--- a/drivers/usb/atm/ueagle-atm.c
+++ b/drivers/usb/atm/ueagle-atm.c
@@ -575,6 +575,13 @@ MODULE_PARM_DESC(annex,
sc->usbatm->atm_dev->type = val; \
} while (0)
+#define UPDATE_ATM_SIGNAL(val) \
+ do { \
+ if (sc->usbatm->atm_dev) \
+ atm_dev_signal_change(sc->usbatm->atm_dev, val); \
+ } while (0)
+
+
/* Firmware loading */
#define LOAD_INTERNAL 0xA0
#define F8051_USBCS 0x7f92
@@ -1359,7 +1366,7 @@ static int uea_stat_e1(struct uea_softc *sc)
/* always update it as atm layer could not be init when we switch to
* operational state
*/
- UPDATE_ATM_STAT(signal, ATM_PHY_SIG_FOUND);
+ UPDATE_ATM_SIGNAL(ATM_PHY_SIG_FOUND);
/* wake up processes waiting for synchronization */
wake_up(&sc->sync_q);
@@ -1498,7 +1505,7 @@ static int uea_stat_e4(struct uea_softc *sc)
/* always update it as atm layer could not be init when we switch to
* operational state
*/
- UPDATE_ATM_STAT(signal, ATM_PHY_SIG_FOUND);
+ UPDATE_ATM_SIGNAL(ATM_PHY_SIG_FOUND);
/* wake up processes waiting for synchronization */
wake_up(&sc->sync_q);
@@ -1825,7 +1832,7 @@ static int uea_start_reset(struct uea_softc *sc)
* So we will failed to wait Ready CMV.
*/
sc->cmv_ack = 0;
- UPDATE_ATM_STAT(signal, ATM_PHY_SIG_LOST);
+ UPDATE_ATM_SIGNAL(ATM_PHY_SIG_LOST);
/* reset statistics */
memset(&sc->stats, 0, sizeof(struct uea_stats));
diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c
index 162c95a088e..89d260d6b03 100644
--- a/drivers/usb/class/cdc-acm.c
+++ b/drivers/usb/class/cdc-acm.c
@@ -2,7 +2,7 @@
* cdc-acm.c
*
* Copyright (c) 1999 Armin Fuerst <fuerst@in.tum.de>
- * Copyright (c) 1999 Pavel Machek <pavel@suse.cz>
+ * Copyright (c) 1999 Pavel Machek <pavel@ucw.cz>
* Copyright (c) 1999 Johannes Erdfelt <johannes@erdfelt.com>
* Copyright (c) 2000 Vojtech Pavlik <vojtech@suse.cz>
* Copyright (c) 2004 Oliver Neukum <oliver@neukum.name>
diff --git a/drivers/usb/class/usblp.c b/drivers/usb/class/usblp.c
index 2250095db0a..84f9e52327f 100644
--- a/drivers/usb/class/usblp.c
+++ b/drivers/usb/class/usblp.c
@@ -2,7 +2,7 @@
* usblp.c
*
* Copyright (c) 1999 Michael Gee <michael@linuxspecific.com>
- * Copyright (c) 1999 Pavel Machek <pavel@suse.cz>
+ * Copyright (c) 1999 Pavel Machek <pavel@ucw.cz>
* Copyright (c) 2000 Randy Dunlap <rdunlap@xenotime.net>
* Copyright (c) 2000 Vojtech Pavlik <vojtech@suse.cz>
# Copyright (c) 2001 Pete Zaitcev <zaitcev@redhat.com>
diff --git a/drivers/usb/gadget/f_audio.c b/drivers/usb/gadget/f_audio.c
index b91115f84b1..1f48ceb55a7 100644
--- a/drivers/usb/gadget/f_audio.c
+++ b/drivers/usb/gadget/f_audio.c
@@ -61,7 +61,7 @@ DECLARE_UAC_AC_HEADER_DESCRIPTOR(2);
#define UAC_DT_TOTAL_LENGTH (UAC_DT_AC_HEADER_LENGTH + UAC_DT_INPUT_TERMINAL_SIZE \
+ UAC_DT_OUTPUT_TERMINAL_SIZE + UAC_DT_FEATURE_UNIT_SIZE(0))
/* B.3.2 Class-Specific AC Interface Descriptor */
-static struct uac_ac_header_descriptor_v1_2 ac_header_desc = {
+static struct uac1_ac_header_descriptor_2 ac_header_desc = {
.bLength = UAC_DT_AC_HEADER_LENGTH,
.bDescriptorType = USB_DT_CS_INTERFACE,
.bDescriptorSubtype = UAC_HEADER,
@@ -125,7 +125,7 @@ static struct usb_audio_control_selector feature_unit = {
};
#define OUTPUT_TERMINAL_ID 3
-static struct uac_output_terminal_descriptor_v1 output_terminal_desc = {
+static struct uac1_output_terminal_descriptor output_terminal_desc = {
.bLength = UAC_DT_OUTPUT_TERMINAL_SIZE,
.bDescriptorType = USB_DT_CS_INTERFACE,
.bDescriptorSubtype = UAC_OUTPUT_TERMINAL,
@@ -155,7 +155,7 @@ static struct usb_interface_descriptor as_interface_alt_1_desc = {
};
/* B.4.2 Class-Specific AS Interface Descriptor */
-static struct uac_as_header_descriptor_v1 as_header_desc = {
+static struct uac1_as_header_descriptor as_header_desc = {
.bLength = UAC_DT_AS_HEADER_SIZE,
.bDescriptorType = USB_DT_CS_INTERFACE,
.bDescriptorSubtype = UAC_AS_GENERAL,
diff --git a/drivers/usb/gadget/f_uvc.c b/drivers/usb/gadget/f_uvc.c
index dbe6db0184f..be446b7e7ea 100644
--- a/drivers/usb/gadget/f_uvc.c
+++ b/drivers/usb/gadget/f_uvc.c
@@ -61,12 +61,12 @@ static struct usb_gadget_strings *uvc_function_strings[] = {
#define UVC_INTF_VIDEO_STREAMING 1
static struct usb_interface_assoc_descriptor uvc_iad __initdata = {
- .bLength = USB_DT_INTERFACE_ASSOCIATION_SIZE,
+ .bLength = sizeof(uvc_iad),
.bDescriptorType = USB_DT_INTERFACE_ASSOCIATION,
.bFirstInterface = 0,
.bInterfaceCount = 2,
.bFunctionClass = USB_CLASS_VIDEO,
- .bFunctionSubClass = 0x03,
+ .bFunctionSubClass = UVC_SC_VIDEO_INTERFACE_COLLECTION,
.bFunctionProtocol = 0x00,
.iFunction = 0,
};
@@ -78,7 +78,7 @@ static struct usb_interface_descriptor uvc_control_intf __initdata = {
.bAlternateSetting = 0,
.bNumEndpoints = 1,
.bInterfaceClass = USB_CLASS_VIDEO,
- .bInterfaceSubClass = 0x01,
+ .bInterfaceSubClass = UVC_SC_VIDEOCONTROL,
.bInterfaceProtocol = 0x00,
.iInterface = 0,
};
@@ -106,7 +106,7 @@ static struct usb_interface_descriptor uvc_streaming_intf_alt0 __initdata = {
.bAlternateSetting = 0,
.bNumEndpoints = 0,
.bInterfaceClass = USB_CLASS_VIDEO,
- .bInterfaceSubClass = 0x02,
+ .bInterfaceSubClass = UVC_SC_VIDEOSTREAMING,
.bInterfaceProtocol = 0x00,
.iInterface = 0,
};
@@ -118,7 +118,7 @@ static struct usb_interface_descriptor uvc_streaming_intf_alt1 __initdata = {
.bAlternateSetting = 1,
.bNumEndpoints = 1,
.bInterfaceClass = USB_CLASS_VIDEO,
- .bInterfaceSubClass = 0x02,
+ .bInterfaceSubClass = UVC_SC_VIDEOSTREAMING,
.bInterfaceProtocol = 0x00,
.iInterface = 0,
};
@@ -603,15 +603,15 @@ uvc_bind_config(struct usb_configuration *c,
/* Validate the descriptors. */
if (control == NULL || control[0] == NULL ||
- control[0]->bDescriptorSubType != UVC_DT_HEADER)
+ control[0]->bDescriptorSubType != UVC_VC_HEADER)
goto error;
if (fs_streaming == NULL || fs_streaming[0] == NULL ||
- fs_streaming[0]->bDescriptorSubType != UVC_DT_INPUT_HEADER)
+ fs_streaming[0]->bDescriptorSubType != UVC_VS_INPUT_HEADER)
goto error;
if (hs_streaming == NULL || hs_streaming[0] == NULL ||
- hs_streaming[0]->bDescriptorSubType != UVC_DT_INPUT_HEADER)
+ hs_streaming[0]->bDescriptorSubType != UVC_VS_INPUT_HEADER)
goto error;
uvc->desc.control = control;
diff --git a/drivers/usb/gadget/f_uvc.h b/drivers/usb/gadget/f_uvc.h
index 8a5db7c4fe7..e18a6636c28 100644
--- a/drivers/usb/gadget/f_uvc.h
+++ b/drivers/usb/gadget/f_uvc.h
@@ -15,357 +15,7 @@
#define _F_UVC_H_
#include <linux/usb/composite.h>
-
-#define USB_CLASS_VIDEO_CONTROL 1
-#define USB_CLASS_VIDEO_STREAMING 2
-
-struct uvc_descriptor_header {
- __u8 bLength;
- __u8 bDescriptorType;
- __u8 bDescriptorSubType;
-} __attribute__ ((packed));
-
-struct uvc_header_descriptor {
- __u8 bLength;
- __u8 bDescriptorType;
- __u8 bDescriptorSubType;
- __u16 bcdUVC;
- __u16 wTotalLength;
- __u32 dwClockFrequency;
- __u8 bInCollection;
- __u8 baInterfaceNr[];
-} __attribute__((__packed__));
-
-#define UVC_HEADER_DESCRIPTOR(n) uvc_header_descriptor_##n
-
-#define DECLARE_UVC_HEADER_DESCRIPTOR(n) \
-struct UVC_HEADER_DESCRIPTOR(n) { \
- __u8 bLength; \
- __u8 bDescriptorType; \
- __u8 bDescriptorSubType; \
- __u16 bcdUVC; \
- __u16 wTotalLength; \
- __u32 dwClockFrequency; \
- __u8 bInCollection; \
- __u8 baInterfaceNr[n]; \
-} __attribute__ ((packed))
-
-struct uvc_input_terminal_descriptor {
- __u8 bLength;
- __u8 bDescriptorType;
- __u8 bDescriptorSubType;
- __u8 bTerminalID;
- __u16 wTerminalType;
- __u8 bAssocTerminal;
- __u8 iTerminal;
-} __attribute__((__packed__));
-
-struct uvc_output_terminal_descriptor {
- __u8 bLength;
- __u8 bDescriptorType;
- __u8 bDescriptorSubType;
- __u8 bTerminalID;
- __u16 wTerminalType;
- __u8 bAssocTerminal;
- __u8 bSourceID;
- __u8 iTerminal;
-} __attribute__((__packed__));
-
-struct uvc_camera_terminal_descriptor {
- __u8 bLength;
- __u8 bDescriptorType;
- __u8 bDescriptorSubType;
- __u8 bTerminalID;
- __u16 wTerminalType;
- __u8 bAssocTerminal;
- __u8 iTerminal;
- __u16 wObjectiveFocalLengthMin;
- __u16 wObjectiveFocalLengthMax;
- __u16 wOcularFocalLength;
- __u8 bControlSize;
- __u8 bmControls[3];
-} __attribute__((__packed__));
-
-struct uvc_selector_unit_descriptor {
- __u8 bLength;
- __u8 bDescriptorType;
- __u8 bDescriptorSubType;
- __u8 bUnitID;
- __u8 bNrInPins;
- __u8 baSourceID[0];
- __u8 iSelector;
-} __attribute__((__packed__));
-
-#define UVC_SELECTOR_UNIT_DESCRIPTOR(n) \
- uvc_selector_unit_descriptor_##n
-
-#define DECLARE_UVC_SELECTOR_UNIT_DESCRIPTOR(n) \
-struct UVC_SELECTOR_UNIT_DESCRIPTOR(n) { \
- __u8 bLength; \
- __u8 bDescriptorType; \
- __u8 bDescriptorSubType; \
- __u8 bUnitID; \
- __u8 bNrInPins; \
- __u8 baSourceID[n]; \
- __u8 iSelector; \
-} __attribute__ ((packed))
-
-struct uvc_processing_unit_descriptor {
- __u8 bLength;
- __u8 bDescriptorType;
- __u8 bDescriptorSubType;
- __u8 bUnitID;
- __u8 bSourceID;
- __u16 wMaxMultiplier;
- __u8 bControlSize;
- __u8 bmControls[2];
- __u8 iProcessing;
-} __attribute__((__packed__));
-
-struct uvc_extension_unit_descriptor {
- __u8 bLength;
- __u8 bDescriptorType;
- __u8 bDescriptorSubType;
- __u8 bUnitID;
- __u8 guidExtensionCode[16];
- __u8 bNumControls;
- __u8 bNrInPins;
- __u8 baSourceID[0];
- __u8 bControlSize;
- __u8 bmControls[0];
- __u8 iExtension;
-} __attribute__((__packed__));
-
-#define UVC_EXTENSION_UNIT_DESCRIPTOR(p, n) \
- uvc_extension_unit_descriptor_##p_##n
-
-#define DECLARE_UVC_EXTENSION_UNIT_DESCRIPTOR(p, n) \
-struct UVC_EXTENSION_UNIT_DESCRIPTOR(p, n) { \
- __u8 bLength; \
- __u8 bDescriptorType; \
- __u8 bDescriptorSubType; \
- __u8 bUnitID; \
- __u8 guidExtensionCode[16]; \
- __u8 bNumControls; \
- __u8 bNrInPins; \
- __u8 baSourceID[p]; \
- __u8 bControlSize; \
- __u8 bmControls[n]; \
- __u8 iExtension; \
-} __attribute__ ((packed))
-
-struct uvc_control_endpoint_descriptor {
- __u8 bLength;
- __u8 bDescriptorType;
- __u8 bDescriptorSubType;
- __u16 wMaxTransferSize;
-} __attribute__((__packed__));
-
-#define UVC_DT_HEADER 1
-#define UVC_DT_INPUT_TERMINAL 2
-#define UVC_DT_OUTPUT_TERMINAL 3
-#define UVC_DT_SELECTOR_UNIT 4
-#define UVC_DT_PROCESSING_UNIT 5
-#define UVC_DT_EXTENSION_UNIT 6
-
-#define UVC_DT_HEADER_SIZE(n) (12+(n))
-#define UVC_DT_INPUT_TERMINAL_SIZE 8
-#define UVC_DT_OUTPUT_TERMINAL_SIZE 9
-#define UVC_DT_CAMERA_TERMINAL_SIZE(n) (15+(n))
-#define UVC_DT_SELECTOR_UNIT_SIZE(n) (6+(n))
-#define UVC_DT_PROCESSING_UNIT_SIZE(n) (9+(n))
-#define UVC_DT_EXTENSION_UNIT_SIZE(p,n) (24+(p)+(n))
-#define UVC_DT_CONTROL_ENDPOINT_SIZE 5
-
-struct uvc_input_header_descriptor {
- __u8 bLength;
- __u8 bDescriptorType;
- __u8 bDescriptorSubType;
- __u8 bNumFormats;
- __u16 wTotalLength;
- __u8 bEndpointAddress;
- __u8 bmInfo;
- __u8 bTerminalLink;
- __u8 bStillCaptureMethod;
- __u8 bTriggerSupport;
- __u8 bTriggerUsage;
- __u8 bControlSize;
- __u8 bmaControls[];
-} __attribute__((__packed__));
-
-#define UVC_INPUT_HEADER_DESCRIPTOR(n, p) \
- uvc_input_header_descriptor_##n_##p
-
-#define DECLARE_UVC_INPUT_HEADER_DESCRIPTOR(n, p) \
-struct UVC_INPUT_HEADER_DESCRIPTOR(n, p) { \
- __u8 bLength; \
- __u8 bDescriptorType; \
- __u8 bDescriptorSubType; \
- __u8 bNumFormats; \
- __u16 wTotalLength; \
- __u8 bEndpointAddress; \
- __u8 bmInfo; \
- __u8 bTerminalLink; \
- __u8 bStillCaptureMethod; \
- __u8 bTriggerSupport; \
- __u8 bTriggerUsage; \
- __u8 bControlSize; \
- __u8 bmaControls[p][n]; \
-} __attribute__ ((packed))
-
-struct uvc_output_header_descriptor {
- __u8 bLength;
- __u8 bDescriptorType;
- __u8 bDescriptorSubType;
- __u8 bNumFormats;
- __u16 wTotalLength;
- __u8 bEndpointAddress;
- __u8 bTerminalLink;
- __u8 bControlSize;
- __u8 bmaControls[];
-} __attribute__((__packed__));
-
-#define UVC_OUTPUT_HEADER_DESCRIPTOR(n, p) \
- uvc_output_header_descriptor_##n_##p
-
-#define DECLARE_UVC_OUTPUT_HEADER_DESCRIPTOR(n, p) \
-struct UVC_OUTPUT_HEADER_DESCRIPTOR(n, p) { \
- __u8 bLength; \
- __u8 bDescriptorType; \
- __u8 bDescriptorSubType; \
- __u8 bNumFormats; \
- __u16 wTotalLength; \
- __u8 bEndpointAddress; \
- __u8 bTerminalLink; \
- __u8 bControlSize; \
- __u8 bmaControls[p][n]; \
-} __attribute__ ((packed))
-
-struct uvc_format_uncompressed {
- __u8 bLength;
- __u8 bDescriptorType;
- __u8 bDescriptorSubType;
- __u8 bFormatIndex;
- __u8 bNumFrameDescriptors;
- __u8 guidFormat[16];
- __u8 bBitsPerPixel;
- __u8 bDefaultFrameIndex;
- __u8 bAspectRatioX;
- __u8 bAspectRatioY;
- __u8 bmInterfaceFlags;
- __u8 bCopyProtect;
-} __attribute__((__packed__));
-
-struct uvc_frame_uncompressed {
- __u8 bLength;
- __u8 bDescriptorType;
- __u8 bDescriptorSubType;
- __u8 bFrameIndex;
- __u8 bmCapabilities;
- __u16 wWidth;
- __u16 wHeight;
- __u32 dwMinBitRate;
- __u32 dwMaxBitRate;
- __u32 dwMaxVideoFrameBufferSize;
- __u32 dwDefaultFrameInterval;
- __u8 bFrameIntervalType;
- __u32 dwFrameInterval[];
-} __attribute__((__packed__));
-
-#define UVC_FRAME_UNCOMPRESSED(n) \
- uvc_frame_uncompressed_##n
-
-#define DECLARE_UVC_FRAME_UNCOMPRESSED(n) \
-struct UVC_FRAME_UNCOMPRESSED(n) { \
- __u8 bLength; \
- __u8 bDescriptorType; \
- __u8 bDescriptorSubType; \
- __u8 bFrameIndex; \
- __u8 bmCapabilities; \
- __u16 wWidth; \
- __u16 wHeight; \
- __u32 dwMinBitRate; \
- __u32 dwMaxBitRate; \
- __u32 dwMaxVideoFrameBufferSize; \
- __u32 dwDefaultFrameInterval; \
- __u8 bFrameIntervalType; \
- __u32 dwFrameInterval[n]; \
-} __attribute__ ((packed))
-
-struct uvc_format_mjpeg {
- __u8 bLength;
- __u8 bDescriptorType;
- __u8 bDescriptorSubType;
- __u8 bFormatIndex;
- __u8 bNumFrameDescriptors;
- __u8 bmFlags;
- __u8 bDefaultFrameIndex;
- __u8 bAspectRatioX;
- __u8 bAspectRatioY;
- __u8 bmInterfaceFlags;
- __u8 bCopyProtect;
-} __attribute__((__packed__));
-
-struct uvc_frame_mjpeg {
- __u8 bLength;
- __u8 bDescriptorType;
- __u8 bDescriptorSubType;
- __u8 bFrameIndex;
- __u8 bmCapabilities;
- __u16 wWidth;
- __u16 wHeight;
- __u32 dwMinBitRate;
- __u32 dwMaxBitRate;
- __u32 dwMaxVideoFrameBufferSize;
- __u32 dwDefaultFrameInterval;
- __u8 bFrameIntervalType;
- __u32 dwFrameInterval[];
-} __attribute__((__packed__));
-
-#define UVC_FRAME_MJPEG(n) \
- uvc_frame_mjpeg_##n
-
-#define DECLARE_UVC_FRAME_MJPEG(n) \
-struct UVC_FRAME_MJPEG(n) { \
- __u8 bLength; \
- __u8 bDescriptorType; \
- __u8 bDescriptorSubType; \
- __u8 bFrameIndex; \
- __u8 bmCapabilities; \
- __u16 wWidth; \
- __u16 wHeight; \
- __u32 dwMinBitRate; \
- __u32 dwMaxBitRate; \
- __u32 dwMaxVideoFrameBufferSize; \
- __u32 dwDefaultFrameInterval; \
- __u8 bFrameIntervalType; \
- __u32 dwFrameInterval[n]; \
-} __attribute__ ((packed))
-
-struct uvc_color_matching_descriptor {
- __u8 bLength;
- __u8 bDescriptorType;
- __u8 bDescriptorSubType;
- __u8 bColorPrimaries;
- __u8 bTransferCharacteristics;
- __u8 bMatrixCoefficients;
-} __attribute__((__packed__));
-
-#define UVC_DT_INPUT_HEADER 1
-#define UVC_DT_OUTPUT_HEADER 2
-#define UVC_DT_FORMAT_UNCOMPRESSED 4
-#define UVC_DT_FRAME_UNCOMPRESSED 5
-#define UVC_DT_FORMAT_MJPEG 6
-#define UVC_DT_FRAME_MJPEG 7
-#define UVC_DT_COLOR_MATCHING 13
-
-#define UVC_DT_INPUT_HEADER_SIZE(n, p) (13+(n*p))
-#define UVC_DT_OUTPUT_HEADER_SIZE(n, p) (9+(n*p))
-#define UVC_DT_FORMAT_UNCOMPRESSED_SIZE 27
-#define UVC_DT_FRAME_UNCOMPRESSED_SIZE(n) (26+4*(n))
-#define UVC_DT_FORMAT_MJPEG_SIZE 11
-#define UVC_DT_FRAME_MJPEG_SIZE(n) (26+4*(n))
-#define UVC_DT_COLOR_MATCHING_SIZE 6
+#include <linux/usb/video.h>
extern int uvc_bind_config(struct usb_configuration *c,
const struct uvc_descriptor_header * const *control,
diff --git a/drivers/usb/gadget/fsl_qe_udc.c b/drivers/usb/gadget/fsl_qe_udc.c
index 82506ca297d..9648b75f028 100644
--- a/drivers/usb/gadget/fsl_qe_udc.c
+++ b/drivers/usb/gadget/fsl_qe_udc.c
@@ -32,6 +32,7 @@
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/moduleparam.h>
+#include <linux/of_address.h>
#include <linux/of_platform.h>
#include <linux/dma-mapping.h>
#include <linux/usb/ch9.h>
diff --git a/drivers/usb/gadget/gmidi.c b/drivers/usb/gadget/gmidi.c
index 2b56ce62185..b7bf88019b0 100644
--- a/drivers/usb/gadget/gmidi.c
+++ b/drivers/usb/gadget/gmidi.c
@@ -238,7 +238,7 @@ static const struct usb_interface_descriptor ac_interface_desc = {
};
/* B.3.2 Class-Specific AC Interface Descriptor */
-static const struct uac_ac_header_descriptor_v1_1 ac_header_desc = {
+static const struct uac1_ac_header_descriptor_1 ac_header_desc = {
.bLength = UAC_DT_AC_HEADER_SIZE(1),
.bDescriptorType = USB_DT_CS_INTERFACE,
.bDescriptorSubtype = USB_MS_HEADER,
diff --git a/drivers/usb/gadget/rndis.c b/drivers/usb/gadget/rndis.c
index 5c0d06c79a8..020fa5a25fd 100644
--- a/drivers/usb/gadget/rndis.c
+++ b/drivers/usb/gadget/rndis.c
@@ -171,7 +171,8 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
int i, count;
rndis_query_cmplt_type *resp;
struct net_device *net;
- const struct net_device_stats *stats;
+ struct rtnl_link_stats64 temp;
+ const struct rtnl_link_stats64 *stats;
if (!r) return -ENOMEM;
resp = (rndis_query_cmplt_type *) r->buf;
@@ -194,7 +195,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
resp->InformationBufferOffset = cpu_to_le32 (16);
net = rndis_per_dev_params[configNr].dev;
- stats = dev_get_stats(net);
+ stats = dev_get_stats(net, &temp);
switch (OID) {
diff --git a/drivers/usb/gadget/uvc.h b/drivers/usb/gadget/uvc.h
index e92454cddd7..5b7919460fd 100644
--- a/drivers/usb/gadget/uvc.h
+++ b/drivers/usb/gadget/uvc.h
@@ -48,39 +48,6 @@ struct uvc_event
#define UVC_INTF_STREAMING 1
/* ------------------------------------------------------------------------
- * UVC constants & structures
- */
-
-/* Values for bmHeaderInfo (Video and Still Image Payload Headers, 2.4.3.3) */
-#define UVC_STREAM_EOH (1 << 7)
-#define UVC_STREAM_ERR (1 << 6)
-#define UVC_STREAM_STI (1 << 5)
-#define UVC_STREAM_RES (1 << 4)
-#define UVC_STREAM_SCR (1 << 3)
-#define UVC_STREAM_PTS (1 << 2)
-#define UVC_STREAM_EOF (1 << 1)
-#define UVC_STREAM_FID (1 << 0)
-
-struct uvc_streaming_control {
- __u16 bmHint;
- __u8 bFormatIndex;
- __u8 bFrameIndex;
- __u32 dwFrameInterval;
- __u16 wKeyFrameRate;
- __u16 wPFrameRate;
- __u16 wCompQuality;
- __u16 wCompWindowSize;
- __u16 wDelay;
- __u32 dwMaxVideoFrameSize;
- __u32 dwMaxPayloadTransferSize;
- __u32 dwClockFrequency;
- __u8 bmFramingInfo;
- __u8 bPreferedVersion;
- __u8 bMinVersion;
- __u8 bMaxVersion;
-} __attribute__((__packed__));
-
-/* ------------------------------------------------------------------------
* Debugging, printing and logging
*/
@@ -137,9 +104,6 @@ extern unsigned int uvc_gadget_trace_param;
#define UVC_MAX_REQUEST_SIZE 64
#define UVC_MAX_EVENTS 4
-#define USB_DT_INTERFACE_ASSOCIATION_SIZE 8
-#define USB_CLASS_MISC 0xef
-
/* ------------------------------------------------------------------------
* Structures
*/
diff --git a/drivers/usb/gadget/webcam.c b/drivers/usb/gadget/webcam.c
index f5f3030cc41..288d21155ab 100644
--- a/drivers/usb/gadget/webcam.c
+++ b/drivers/usb/gadget/webcam.c
@@ -90,7 +90,7 @@ DECLARE_UVC_HEADER_DESCRIPTOR(1);
static const struct UVC_HEADER_DESCRIPTOR(1) uvc_control_header = {
.bLength = UVC_DT_HEADER_SIZE(1),
.bDescriptorType = USB_DT_CS_INTERFACE,
- .bDescriptorSubType = UVC_DT_HEADER,
+ .bDescriptorSubType = UVC_VC_HEADER,
.bcdUVC = cpu_to_le16(0x0100),
.wTotalLength = 0, /* dynamic */
.dwClockFrequency = cpu_to_le32(48000000),
@@ -101,7 +101,7 @@ static const struct UVC_HEADER_DESCRIPTOR(1) uvc_control_header = {
static const struct uvc_camera_terminal_descriptor uvc_camera_terminal = {
.bLength = UVC_DT_CAMERA_TERMINAL_SIZE(3),
.bDescriptorType = USB_DT_CS_INTERFACE,
- .bDescriptorSubType = UVC_DT_INPUT_TERMINAL,
+ .bDescriptorSubType = UVC_VC_INPUT_TERMINAL,
.bTerminalID = 1,
.wTerminalType = cpu_to_le16(0x0201),
.bAssocTerminal = 0,
@@ -118,7 +118,7 @@ static const struct uvc_camera_terminal_descriptor uvc_camera_terminal = {
static const struct uvc_processing_unit_descriptor uvc_processing = {
.bLength = UVC_DT_PROCESSING_UNIT_SIZE(2),
.bDescriptorType = USB_DT_CS_INTERFACE,
- .bDescriptorSubType = UVC_DT_PROCESSING_UNIT,
+ .bDescriptorSubType = UVC_VC_PROCESSING_UNIT,
.bUnitID = 2,
.bSourceID = 1,
.wMaxMultiplier = cpu_to_le16(16*1024),
@@ -131,7 +131,7 @@ static const struct uvc_processing_unit_descriptor uvc_processing = {
static const struct uvc_output_terminal_descriptor uvc_output_terminal = {
.bLength = UVC_DT_OUTPUT_TERMINAL_SIZE,
.bDescriptorType = USB_DT_CS_INTERFACE,
- .bDescriptorSubType = UVC_DT_OUTPUT_TERMINAL,
+ .bDescriptorSubType = UVC_VC_OUTPUT_TERMINAL,
.bTerminalID = 3,
.wTerminalType = cpu_to_le16(0x0101),
.bAssocTerminal = 0,
@@ -144,7 +144,7 @@ DECLARE_UVC_INPUT_HEADER_DESCRIPTOR(1, 2);
static const struct UVC_INPUT_HEADER_DESCRIPTOR(1, 2) uvc_input_header = {
.bLength = UVC_DT_INPUT_HEADER_SIZE(1, 2),
.bDescriptorType = USB_DT_CS_INTERFACE,
- .bDescriptorSubType = UVC_DT_INPUT_HEADER,
+ .bDescriptorSubType = UVC_VS_INPUT_HEADER,
.bNumFormats = 2,
.wTotalLength = 0, /* dynamic */
.bEndpointAddress = 0, /* dynamic */
@@ -161,7 +161,7 @@ static const struct UVC_INPUT_HEADER_DESCRIPTOR(1, 2) uvc_input_header = {
static const struct uvc_format_uncompressed uvc_format_yuv = {
.bLength = UVC_DT_FORMAT_UNCOMPRESSED_SIZE,
.bDescriptorType = USB_DT_CS_INTERFACE,
- .bDescriptorSubType = UVC_DT_FORMAT_UNCOMPRESSED,
+ .bDescriptorSubType = UVC_VS_FORMAT_UNCOMPRESSED,
.bFormatIndex = 1,
.bNumFrameDescriptors = 2,
.guidFormat =
@@ -181,7 +181,7 @@ DECLARE_UVC_FRAME_UNCOMPRESSED(3);
static const struct UVC_FRAME_UNCOMPRESSED(3) uvc_frame_yuv_360p = {
.bLength = UVC_DT_FRAME_UNCOMPRESSED_SIZE(3),
.bDescriptorType = USB_DT_CS_INTERFACE,
- .bDescriptorSubType = UVC_DT_FRAME_UNCOMPRESSED,
+ .bDescriptorSubType = UVC_VS_FRAME_UNCOMPRESSED,
.bFrameIndex = 1,
.bmCapabilities = 0,
.wWidth = cpu_to_le16(640),
@@ -199,7 +199,7 @@ static const struct UVC_FRAME_UNCOMPRESSED(3) uvc_frame_yuv_360p = {
static const struct UVC_FRAME_UNCOMPRESSED(1) uvc_frame_yuv_720p = {
.bLength = UVC_DT_FRAME_UNCOMPRESSED_SIZE(1),
.bDescriptorType = USB_DT_CS_INTERFACE,
- .bDescriptorSubType = UVC_DT_FRAME_UNCOMPRESSED,
+ .bDescriptorSubType = UVC_VS_FRAME_UNCOMPRESSED,
.bFrameIndex = 2,
.bmCapabilities = 0,
.wWidth = cpu_to_le16(1280),
@@ -215,7 +215,7 @@ static const struct UVC_FRAME_UNCOMPRESSED(1) uvc_frame_yuv_720p = {
static const struct uvc_format_mjpeg uvc_format_mjpg = {
.bLength = UVC_DT_FORMAT_MJPEG_SIZE,
.bDescriptorType = USB_DT_CS_INTERFACE,
- .bDescriptorSubType = UVC_DT_FORMAT_MJPEG,
+ .bDescriptorSubType = UVC_VS_FORMAT_MJPEG,
.bFormatIndex = 2,
.bNumFrameDescriptors = 2,
.bmFlags = 0,
@@ -232,7 +232,7 @@ DECLARE_UVC_FRAME_MJPEG(3);
static const struct UVC_FRAME_MJPEG(3) uvc_frame_mjpg_360p = {
.bLength = UVC_DT_FRAME_MJPEG_SIZE(3),
.bDescriptorType = USB_DT_CS_INTERFACE,
- .bDescriptorSubType = UVC_DT_FRAME_MJPEG,
+ .bDescriptorSubType = UVC_VS_FRAME_MJPEG,
.bFrameIndex = 1,
.bmCapabilities = 0,
.wWidth = cpu_to_le16(640),
@@ -250,7 +250,7 @@ static const struct UVC_FRAME_MJPEG(3) uvc_frame_mjpg_360p = {
static const struct UVC_FRAME_MJPEG(1) uvc_frame_mjpg_720p = {
.bLength = UVC_DT_FRAME_MJPEG_SIZE(1),
.bDescriptorType = USB_DT_CS_INTERFACE,
- .bDescriptorSubType = UVC_DT_FRAME_MJPEG,
+ .bDescriptorSubType = UVC_VS_FRAME_MJPEG,
.bFrameIndex = 2,
.bmCapabilities = 0,
.wWidth = cpu_to_le16(1280),
@@ -266,7 +266,7 @@ static const struct UVC_FRAME_MJPEG(1) uvc_frame_mjpg_720p = {
static const struct uvc_color_matching_descriptor uvc_color_matching = {
.bLength = UVC_DT_COLOR_MATCHING_SIZE,
.bDescriptorType = USB_DT_CS_INTERFACE,
- .bDescriptorSubType = UVC_DT_COLOR_MATCHING,
+ .bDescriptorSubType = UVC_VS_COLORFORMAT,
.bColorPrimaries = 1,
.bTransferCharacteristics = 1,
.bMatrixCoefficients = 4,
diff --git a/drivers/usb/host/fhci-sched.c b/drivers/usb/host/fhci-sched.c
index 4f2cbdcc027..a42ef380e91 100644
--- a/drivers/usb/host/fhci-sched.c
+++ b/drivers/usb/host/fhci-sched.c
@@ -125,7 +125,7 @@ void fhci_transaction_confirm(struct fhci_usb *usb, struct packet *pkt)
/*
* Flush all transmitted packets from BDs
* This routine is called when disabling the USB port to flush all
- * transmissions that are allready scheduled in the BDs
+ * transmissions that are already scheduled in the BDs
*/
void fhci_flush_all_transmissions(struct fhci_usb *usb)
{
diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c
index fc576557d8a..02864a237a2 100644
--- a/drivers/usb/host/ohci-hcd.c
+++ b/drivers/usb/host/ohci-hcd.c
@@ -1031,7 +1031,7 @@ MODULE_LICENSE ("GPL");
#define PLATFORM_DRIVER ohci_hcd_ep93xx_driver
#endif
-#ifdef CONFIG_SOC_AU1X00
+#ifdef CONFIG_MIPS_ALCHEMY
#include "ohci-au1xxx.c"
#define PLATFORM_DRIVER ohci_hcd_au1xxx_driver
#endif
@@ -1095,6 +1095,11 @@ MODULE_LICENSE ("GPL");
#define TMIO_OHCI_DRIVER ohci_hcd_tmio_driver
#endif
+#ifdef CONFIG_MACH_JZ4740
+#include "ohci-jz4740.c"
+#define PLATFORM_DRIVER ohci_hcd_jz4740_driver
+#endif
+
#if !defined(PCI_DRIVER) && \
!defined(PLATFORM_DRIVER) && \
!defined(OMAP1_PLATFORM_DRIVER) && \
diff --git a/drivers/usb/host/ohci-jz4740.c b/drivers/usb/host/ohci-jz4740.c
new file mode 100644
index 00000000000..10e1872f3ab
--- /dev/null
+++ b/drivers/usb/host/ohci-jz4740.c
@@ -0,0 +1,276 @@
+/*
+ * Copyright (C) 2010, Lars-Peter Clausen <lars@metafoo.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.
+ *
+ * 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/platform_device.h>
+#include <linux/clk.h>
+#include <linux/regulator/consumer.h>
+
+struct jz4740_ohci_hcd {
+ struct ohci_hcd ohci_hcd;
+
+ struct regulator *vbus;
+ bool vbus_enabled;
+ struct clk *clk;
+};
+
+static inline struct jz4740_ohci_hcd *hcd_to_jz4740_hcd(struct usb_hcd *hcd)
+{
+ return (struct jz4740_ohci_hcd *)(hcd->hcd_priv);
+}
+
+static inline struct usb_hcd *jz4740_hcd_to_hcd(struct jz4740_ohci_hcd *jz4740_ohci)
+{
+ return container_of((void *)jz4740_ohci, struct usb_hcd, hcd_priv);
+}
+
+static int ohci_jz4740_start(struct usb_hcd *hcd)
+{
+ struct ohci_hcd *ohci = hcd_to_ohci(hcd);
+ int ret;
+
+ ret = ohci_init(ohci);
+ if (ret < 0)
+ return ret;
+
+ ohci->num_ports = 1;
+
+ ret = ohci_run(ohci);
+ if (ret < 0) {
+ dev_err(hcd->self.controller, "Can not start %s",
+ hcd->self.bus_name);
+ ohci_stop(hcd);
+ return ret;
+ }
+ return 0;
+}
+
+static int ohci_jz4740_set_vbus_power(struct jz4740_ohci_hcd *jz4740_ohci,
+ bool enabled)
+{
+ int ret = 0;
+
+ if (!jz4740_ohci->vbus)
+ return 0;
+
+ if (enabled && !jz4740_ohci->vbus_enabled) {
+ ret = regulator_enable(jz4740_ohci->vbus);
+ if (ret)
+ dev_err(jz4740_hcd_to_hcd(jz4740_ohci)->self.controller,
+ "Could not power vbus\n");
+ } else if (!enabled && jz4740_ohci->vbus_enabled) {
+ ret = regulator_disable(jz4740_ohci->vbus);
+ }
+
+ if (ret == 0)
+ jz4740_ohci->vbus_enabled = enabled;
+
+ return ret;
+}
+
+static int ohci_jz4740_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
+ u16 wIndex, char *buf, u16 wLength)
+{
+ struct jz4740_ohci_hcd *jz4740_ohci = hcd_to_jz4740_hcd(hcd);
+ int ret;
+
+ switch (typeReq) {
+ case SetHubFeature:
+ if (wValue == USB_PORT_FEAT_POWER)
+ ret = ohci_jz4740_set_vbus_power(jz4740_ohci, true);
+ break;
+ case ClearHubFeature:
+ if (wValue == USB_PORT_FEAT_POWER)
+ ret = ohci_jz4740_set_vbus_power(jz4740_ohci, false);
+ break;
+ }
+
+ if (ret)
+ return ret;
+
+ return ohci_hub_control(hcd, typeReq, wValue, wIndex, buf, wLength);
+}
+
+
+static const struct hc_driver ohci_jz4740_hc_driver = {
+ .description = hcd_name,
+ .product_desc = "JZ4740 OHCI",
+ .hcd_priv_size = sizeof(struct jz4740_ohci_hcd),
+
+ /*
+ * generic hardware linkage
+ */
+ .irq = ohci_irq,
+ .flags = HCD_USB11 | HCD_MEMORY,
+
+ /*
+ * basic lifecycle operations
+ */
+ .start = ohci_jz4740_start,
+ .stop = ohci_stop,
+ .shutdown = ohci_shutdown,
+
+ /*
+ * managing i/o requests and associated device resources
+ */
+ .urb_enqueue = ohci_urb_enqueue,
+ .urb_dequeue = ohci_urb_dequeue,
+ .endpoint_disable = ohci_endpoint_disable,
+
+ /*
+ * scheduling support
+ */
+ .get_frame_number = ohci_get_frame,
+
+ /*
+ * root hub support
+ */
+ .hub_status_data = ohci_hub_status_data,
+ .hub_control = ohci_jz4740_hub_control,
+#ifdef CONFIG_PM
+ .bus_suspend = ohci_bus_suspend,
+ .bus_resume = ohci_bus_resume,
+#endif
+ .start_port_reset = ohci_start_port_reset,
+};
+
+
+static __devinit int jz4740_ohci_probe(struct platform_device *pdev)
+{
+ int ret;
+ struct usb_hcd *hcd;
+ struct jz4740_ohci_hcd *jz4740_ohci;
+ struct resource *res;
+ int irq;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+ if (!res) {
+ dev_err(&pdev->dev, "Failed to get platform resource\n");
+ return -ENOENT;
+ }
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ dev_err(&pdev->dev, "Failed to get platform irq\n");
+ return irq;
+ }
+
+ hcd = usb_create_hcd(&ohci_jz4740_hc_driver, &pdev->dev, "jz4740");
+ if (!hcd) {
+ dev_err(&pdev->dev, "Failed to create hcd.\n");
+ return -ENOMEM;
+ }
+
+ jz4740_ohci = hcd_to_jz4740_hcd(hcd);
+
+ res = request_mem_region(res->start, resource_size(res), hcd_name);
+ if (!res) {
+ dev_err(&pdev->dev, "Failed to request mem region.\n");
+ ret = -EBUSY;
+ goto err_free;
+ }
+
+ hcd->rsrc_start = res->start;
+ hcd->rsrc_len = resource_size(res);
+ hcd->regs = ioremap(res->start, resource_size(res));
+
+ if (!hcd->regs) {
+ dev_err(&pdev->dev, "Failed to ioremap registers.\n");
+ ret = -EBUSY;
+ goto err_release_mem;
+ }
+
+ jz4740_ohci->clk = clk_get(&pdev->dev, "uhc");
+ if (IS_ERR(jz4740_ohci->clk)) {
+ ret = PTR_ERR(jz4740_ohci->clk);
+ dev_err(&pdev->dev, "Failed to get clock: %d\n", ret);
+ goto err_iounmap;
+ }
+
+ jz4740_ohci->vbus = regulator_get(&pdev->dev, "vbus");
+ if (IS_ERR(jz4740_ohci->vbus))
+ jz4740_ohci->vbus = NULL;
+
+
+ clk_set_rate(jz4740_ohci->clk, 48000000);
+ clk_enable(jz4740_ohci->clk);
+ if (jz4740_ohci->vbus)
+ ohci_jz4740_set_vbus_power(jz4740_ohci, true);
+
+ platform_set_drvdata(pdev, hcd);
+
+ ohci_hcd_init(hcd_to_ohci(hcd));
+
+ ret = usb_add_hcd(hcd, irq, 0);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to add hcd: %d\n", ret);
+ goto err_disable;
+ }
+
+ return 0;
+
+err_disable:
+ platform_set_drvdata(pdev, NULL);
+ if (jz4740_ohci->vbus) {
+ regulator_disable(jz4740_ohci->vbus);
+ regulator_put(jz4740_ohci->vbus);
+ }
+ clk_disable(jz4740_ohci->clk);
+
+ clk_put(jz4740_ohci->clk);
+err_iounmap:
+ iounmap(hcd->regs);
+err_release_mem:
+ release_mem_region(res->start, resource_size(res));
+err_free:
+ usb_put_hcd(hcd);
+
+ return ret;
+}
+
+static __devexit int jz4740_ohci_remove(struct platform_device *pdev)
+{
+ struct usb_hcd *hcd = platform_get_drvdata(pdev);
+ struct jz4740_ohci_hcd *jz4740_ohci = hcd_to_jz4740_hcd(hcd);
+
+ usb_remove_hcd(hcd);
+
+ platform_set_drvdata(pdev, NULL);
+
+ if (jz4740_ohci->vbus) {
+ regulator_disable(jz4740_ohci->vbus);
+ regulator_put(jz4740_ohci->vbus);
+ }
+
+ clk_disable(jz4740_ohci->clk);
+ clk_put(jz4740_ohci->clk);
+
+ iounmap(hcd->regs);
+ release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+
+ usb_put_hcd(hcd);
+
+ return 0;
+}
+
+static struct platform_driver ohci_hcd_jz4740_driver = {
+ .probe = jz4740_ohci_probe,
+ .remove = __devexit_p(jz4740_ohci_remove),
+ .driver = {
+ .name = "jz4740-ohci",
+ .owner = THIS_MODULE,
+ },
+};
+
+MODULE_ALIAS("platfrom:jz4740-ohci");
diff --git a/drivers/usb/host/sl811_cs.c b/drivers/usb/host/sl811_cs.c
index 58cb73c8420..0e13a00eb2e 100644
--- a/drivers/usb/host/sl811_cs.c
+++ b/drivers/usb/host/sl811_cs.c
@@ -20,7 +20,6 @@
#include <linux/ioport.h>
#include <linux/platform_device.h>
-#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/cistpl.h>
#include <pcmcia/cisreg.h>
@@ -43,8 +42,6 @@ MODULE_LICENSE("GPL");
/* VARIABLES */
/*====================================================================*/
-static const char driver_name[DEV_NAME_LEN] = "sl811_cs";
-
typedef struct local_info_t {
struct pcmcia_device *p_dev;
} local_info_t;
@@ -165,16 +162,16 @@ static int sl811_cs_config_check(struct pcmcia_device *p_dev,
p_dev->conf.Attributes |= CONF_ENABLE_IRQ;
/* IO window settings */
- p_dev->io.NumPorts1 = p_dev->io.NumPorts2 = 0;
+ p_dev->resource[0]->end = p_dev->resource[1]->end = 0;
if ((cfg->io.nwin > 0) || (dflt->io.nwin > 0)) {
cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt->io;
+ p_dev->io_lines = io->flags & CISTPL_IO_LINES_MASK;
- p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
- p_dev->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK;
- p_dev->io.BasePort1 = io->win[0].base;
- p_dev->io.NumPorts1 = io->win[0].len;
+ p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_8;
+ p_dev->resource[0]->start = io->win[0].base;
+ p_dev->resource[0]->end = io->win[0].len;
- return pcmcia_request_io(p_dev, &p_dev->io);
+ return pcmcia_request_io(p_dev);
}
pcmcia_disable_device(p_dev);
return -ENODEV;
@@ -192,7 +189,7 @@ static int sl811_cs_config(struct pcmcia_device *link)
goto failed;
/* require an IRQ and two registers */
- if (!link->io.NumPorts1 || link->io.NumPorts1 < 2)
+ if (resource_size(link->resource[0]) < 2)
goto failed;
if (!link->irq)
@@ -207,11 +204,10 @@ static int sl811_cs_config(struct pcmcia_device *link)
if (link->conf.Vpp)
printk(", Vpp %d.%d", link->conf.Vpp/10, link->conf.Vpp%10);
printk(", irq %d", link->irq);
- printk(", io 0x%04x-0x%04x", link->io.BasePort1,
- link->io.BasePort1+link->io.NumPorts1-1);
+ printk(", io %pR", link->resource[0]);
printk("\n");
- if (sl811_hc_init(parent, link->io.BasePort1, link->irq)
+ if (sl811_hc_init(parent, link->resource[0]->start, link->irq)
< 0) {
failed:
printk(KERN_WARNING "sl811_cs_config failed\n");
@@ -246,7 +242,7 @@ MODULE_DEVICE_TABLE(pcmcia, sl811_ids);
static struct pcmcia_driver sl811_cs_driver = {
.owner = THIS_MODULE,
.drv = {
- .name = (char *)driver_name,
+ .name = "sl811_cs",
},
.probe = sl811_cs_probe,
.remove = sl811_cs_detach,
diff --git a/drivers/usb/serial/kl5kusb105.c b/drivers/usb/serial/kl5kusb105.c
index cdbe8bf7f67..e8a65ce45a2 100644
--- a/drivers/usb/serial/kl5kusb105.c
+++ b/drivers/usb/serial/kl5kusb105.c
@@ -261,7 +261,7 @@ static int klsi_105_startup(struct usb_serial *serial)
spin_lock_init(&priv->lock);
- /* priv->termios is left uninitalized until port opening */
+ /* priv->termios is left uninitialized until port opening */
init_waitqueue_head(&serial->port[i]->write_wait);
}
diff --git a/drivers/usb/wusbcore/wusbhc.c b/drivers/usb/wusbcore/wusbhc.c
index eab86e4bc77..2054d4ee977 100644
--- a/drivers/usb/wusbcore/wusbhc.c
+++ b/drivers/usb/wusbcore/wusbhc.c
@@ -26,7 +26,7 @@
* the one that requires (phase B, wusbhc_b_{create,destroy}).
*
* This is so because usb_add_hcd() will start the HC, and thus, all
- * the HC specific stuff has to be already initialiazed (like sysfs
+ * the HC specific stuff has to be already initialized (like sysfs
* thingies).
*/
#include <linux/device.h>
diff --git a/drivers/uwb/wlp/wss-lc.c b/drivers/uwb/wlp/wss-lc.c
index 90accdd54c0..a005d2a03b5 100644
--- a/drivers/uwb/wlp/wss-lc.c
+++ b/drivers/uwb/wlp/wss-lc.c
@@ -180,7 +180,7 @@ error_kobject_register:
* If memory was allocated for the kobject's name then it will
* be freed by the kobject system during this time.
*
- * The EDA cache is removed and reinitilized when the WSS is removed. We
+ * The EDA cache is removed and reinitialized when the WSS is removed. We
* thus loose knowledge of members of this WSS at that time and need not do
* it here.
*/
diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c
index d219070fed3..29e850a7a2f 100644
--- a/drivers/vhost/net.c
+++ b/drivers/vhost/net.c
@@ -74,6 +74,22 @@ static int move_iovec_hdr(struct iovec *from, struct iovec *to,
}
return seg;
}
+/* Copy iovec entries for len bytes from iovec. */
+static void copy_iovec_hdr(const struct iovec *from, struct iovec *to,
+ size_t len, int iovcount)
+{
+ int seg = 0;
+ size_t size;
+ while (len && seg < iovcount) {
+ size = min(from->iov_len, len);
+ to->iov_base = from->iov_base;
+ to->iov_len = size;
+ len -= size;
+ ++from;
+ ++to;
+ ++seg;
+ }
+}
/* Caller must have TX VQ lock */
static void tx_poll_stop(struct vhost_net *net)
@@ -129,7 +145,7 @@ static void handle_tx(struct vhost_net *net)
if (wmem < sock->sk->sk_sndbuf / 2)
tx_poll_stop(net);
- hdr_size = vq->hdr_size;
+ hdr_size = vq->vhost_hlen;
for (;;) {
head = vhost_get_vq_desc(&net->dev, vq, vq->iov,
@@ -172,7 +188,7 @@ static void handle_tx(struct vhost_net *net)
/* TODO: Check specific error and bomb out unless ENOBUFS? */
err = sock->ops->sendmsg(NULL, sock, &msg, len);
if (unlikely(err < 0)) {
- vhost_discard_vq_desc(vq);
+ vhost_discard_vq_desc(vq, 1);
tx_poll_start(net, sock);
break;
}
@@ -191,9 +207,82 @@ static void handle_tx(struct vhost_net *net)
unuse_mm(net->dev.mm);
}
+static int peek_head_len(struct sock *sk)
+{
+ struct sk_buff *head;
+ int len = 0;
+
+ lock_sock(sk);
+ head = skb_peek(&sk->sk_receive_queue);
+ if (head)
+ len = head->len;
+ release_sock(sk);
+ return len;
+}
+
+/* This is a multi-buffer version of vhost_get_desc, that works if
+ * vq has read descriptors only.
+ * @vq - the relevant virtqueue
+ * @datalen - data length we'll be reading
+ * @iovcount - returned count of io vectors we fill
+ * @log - vhost log
+ * @log_num - log offset
+ * returns number of buffer heads allocated, negative on error
+ */
+static int get_rx_bufs(struct vhost_virtqueue *vq,
+ struct vring_used_elem *heads,
+ int datalen,
+ unsigned *iovcount,
+ struct vhost_log *log,
+ unsigned *log_num)
+{
+ unsigned int out, in;
+ int seg = 0;
+ int headcount = 0;
+ unsigned d;
+ int r, nlogs = 0;
+
+ while (datalen > 0) {
+ if (unlikely(headcount >= VHOST_NET_MAX_SG)) {
+ r = -ENOBUFS;
+ goto err;
+ }
+ d = vhost_get_vq_desc(vq->dev, vq, vq->iov + seg,
+ ARRAY_SIZE(vq->iov) - seg, &out,
+ &in, log, log_num);
+ if (d == vq->num) {
+ r = 0;
+ goto err;
+ }
+ if (unlikely(out || in <= 0)) {
+ vq_err(vq, "unexpected descriptor format for RX: "
+ "out %d, in %d\n", out, in);
+ r = -EINVAL;
+ goto err;
+ }
+ if (unlikely(log)) {
+ nlogs += *log_num;
+ log += *log_num;
+ }
+ heads[headcount].id = d;
+ heads[headcount].len = iov_length(vq->iov + seg, in);
+ datalen -= heads[headcount].len;
+ ++headcount;
+ seg += in;
+ }
+ heads[headcount - 1].len += datalen;
+ *iovcount = seg;
+ if (unlikely(log))
+ *log_num = nlogs;
+ return headcount;
+err:
+ vhost_discard_vq_desc(vq, headcount);
+ return r;
+}
+
/* Expects to be always run from workqueue - which acts as
* read-size critical section for our kind of RCU. */
-static void handle_rx(struct vhost_net *net)
+static void handle_rx_big(struct vhost_net *net)
{
struct vhost_virtqueue *vq = &net->dev.vqs[VHOST_NET_VQ_RX];
unsigned out, in, log, s;
@@ -223,7 +312,7 @@ static void handle_rx(struct vhost_net *net)
use_mm(net->dev.mm);
mutex_lock(&vq->mutex);
vhost_disable_notify(vq);
- hdr_size = vq->hdr_size;
+ hdr_size = vq->vhost_hlen;
vq_log = unlikely(vhost_has_feature(&net->dev, VHOST_F_LOG_ALL)) ?
vq->log : NULL;
@@ -270,14 +359,14 @@ static void handle_rx(struct vhost_net *net)
len, MSG_DONTWAIT | MSG_TRUNC);
/* TODO: Check specific error and bomb out unless EAGAIN? */
if (err < 0) {
- vhost_discard_vq_desc(vq);
+ vhost_discard_vq_desc(vq, 1);
break;
}
/* TODO: Should check and handle checksum. */
if (err > len) {
pr_debug("Discarded truncated rx packet: "
" len %d > %zd\n", err, len);
- vhost_discard_vq_desc(vq);
+ vhost_discard_vq_desc(vq, 1);
continue;
}
len = err;
@@ -302,54 +391,175 @@ static void handle_rx(struct vhost_net *net)
unuse_mm(net->dev.mm);
}
-static void handle_tx_kick(struct work_struct *work)
+/* Expects to be always run from workqueue - which acts as
+ * read-size critical section for our kind of RCU. */
+static void handle_rx_mergeable(struct vhost_net *net)
{
- struct vhost_virtqueue *vq;
- struct vhost_net *net;
- vq = container_of(work, struct vhost_virtqueue, poll.work);
- net = container_of(vq->dev, struct vhost_net, dev);
+ struct vhost_virtqueue *vq = &net->dev.vqs[VHOST_NET_VQ_RX];
+ unsigned uninitialized_var(in), log;
+ struct vhost_log *vq_log;
+ struct msghdr msg = {
+ .msg_name = NULL,
+ .msg_namelen = 0,
+ .msg_control = NULL, /* FIXME: get and handle RX aux data. */
+ .msg_controllen = 0,
+ .msg_iov = vq->iov,
+ .msg_flags = MSG_DONTWAIT,
+ };
+
+ struct virtio_net_hdr_mrg_rxbuf hdr = {
+ .hdr.flags = 0,
+ .hdr.gso_type = VIRTIO_NET_HDR_GSO_NONE
+ };
+
+ size_t total_len = 0;
+ int err, headcount;
+ size_t vhost_hlen, sock_hlen;
+ size_t vhost_len, sock_len;
+ struct socket *sock = rcu_dereference(vq->private_data);
+ if (!sock || skb_queue_empty(&sock->sk->sk_receive_queue))
+ return;
+
+ use_mm(net->dev.mm);
+ mutex_lock(&vq->mutex);
+ vhost_disable_notify(vq);
+ vhost_hlen = vq->vhost_hlen;
+ sock_hlen = vq->sock_hlen;
+
+ vq_log = unlikely(vhost_has_feature(&net->dev, VHOST_F_LOG_ALL)) ?
+ vq->log : NULL;
+
+ while ((sock_len = peek_head_len(sock->sk))) {
+ sock_len += sock_hlen;
+ vhost_len = sock_len + vhost_hlen;
+ headcount = get_rx_bufs(vq, vq->heads, vhost_len,
+ &in, vq_log, &log);
+ /* On error, stop handling until the next kick. */
+ if (unlikely(headcount < 0))
+ break;
+ /* OK, now we need to know about added descriptors. */
+ if (!headcount) {
+ if (unlikely(vhost_enable_notify(vq))) {
+ /* They have slipped one in as we were
+ * doing that: check again. */
+ vhost_disable_notify(vq);
+ continue;
+ }
+ /* Nothing new? Wait for eventfd to tell us
+ * they refilled. */
+ break;
+ }
+ /* We don't need to be notified again. */
+ if (unlikely((vhost_hlen)))
+ /* Skip header. TODO: support TSO. */
+ move_iovec_hdr(vq->iov, vq->hdr, vhost_hlen, in);
+ else
+ /* Copy the header for use in VIRTIO_NET_F_MRG_RXBUF:
+ * needed because sendmsg can modify msg_iov. */
+ copy_iovec_hdr(vq->iov, vq->hdr, sock_hlen, in);
+ msg.msg_iovlen = in;
+ err = sock->ops->recvmsg(NULL, sock, &msg,
+ sock_len, MSG_DONTWAIT | MSG_TRUNC);
+ /* Userspace might have consumed the packet meanwhile:
+ * it's not supposed to do this usually, but might be hard
+ * to prevent. Discard data we got (if any) and keep going. */
+ if (unlikely(err != sock_len)) {
+ pr_debug("Discarded rx packet: "
+ " len %d, expected %zd\n", err, sock_len);
+ vhost_discard_vq_desc(vq, headcount);
+ continue;
+ }
+ if (unlikely(vhost_hlen) &&
+ memcpy_toiovecend(vq->hdr, (unsigned char *)&hdr, 0,
+ vhost_hlen)) {
+ vq_err(vq, "Unable to write vnet_hdr at addr %p\n",
+ vq->iov->iov_base);
+ break;
+ }
+ /* TODO: Should check and handle checksum. */
+ if (vhost_has_feature(&net->dev, VIRTIO_NET_F_MRG_RXBUF) &&
+ memcpy_toiovecend(vq->hdr, (unsigned char *)&headcount,
+ offsetof(typeof(hdr), num_buffers),
+ sizeof hdr.num_buffers)) {
+ vq_err(vq, "Failed num_buffers write");
+ vhost_discard_vq_desc(vq, headcount);
+ break;
+ }
+ vhost_add_used_and_signal_n(&net->dev, vq, vq->heads,
+ headcount);
+ if (unlikely(vq_log))
+ vhost_log_write(vq, vq_log, log, vhost_len);
+ total_len += vhost_len;
+ if (unlikely(total_len >= VHOST_NET_WEIGHT)) {
+ vhost_poll_queue(&vq->poll);
+ break;
+ }
+ }
+
+ mutex_unlock(&vq->mutex);
+ unuse_mm(net->dev.mm);
+}
+
+static void handle_rx(struct vhost_net *net)
+{
+ if (vhost_has_feature(&net->dev, VIRTIO_NET_F_MRG_RXBUF))
+ handle_rx_mergeable(net);
+ else
+ handle_rx_big(net);
+}
+
+static void handle_tx_kick(struct vhost_work *work)
+{
+ struct vhost_virtqueue *vq = container_of(work, struct vhost_virtqueue,
+ poll.work);
+ struct vhost_net *net = container_of(vq->dev, struct vhost_net, dev);
+
handle_tx(net);
}
-static void handle_rx_kick(struct work_struct *work)
+static void handle_rx_kick(struct vhost_work *work)
{
- struct vhost_virtqueue *vq;
- struct vhost_net *net;
- vq = container_of(work, struct vhost_virtqueue, poll.work);
- net = container_of(vq->dev, struct vhost_net, dev);
+ struct vhost_virtqueue *vq = container_of(work, struct vhost_virtqueue,
+ poll.work);
+ struct vhost_net *net = container_of(vq->dev, struct vhost_net, dev);
+
handle_rx(net);
}
-static void handle_tx_net(struct work_struct *work)
+static void handle_tx_net(struct vhost_work *work)
{
- struct vhost_net *net;
- net = container_of(work, struct vhost_net, poll[VHOST_NET_VQ_TX].work);
+ struct vhost_net *net = container_of(work, struct vhost_net,
+ poll[VHOST_NET_VQ_TX].work);
handle_tx(net);
}
-static void handle_rx_net(struct work_struct *work)
+static void handle_rx_net(struct vhost_work *work)
{
- struct vhost_net *net;
- net = container_of(work, struct vhost_net, poll[VHOST_NET_VQ_RX].work);
+ struct vhost_net *net = container_of(work, struct vhost_net,
+ poll[VHOST_NET_VQ_RX].work);
handle_rx(net);
}
static int vhost_net_open(struct inode *inode, struct file *f)
{
struct vhost_net *n = kmalloc(sizeof *n, GFP_KERNEL);
+ struct vhost_dev *dev;
int r;
+
if (!n)
return -ENOMEM;
+
+ dev = &n->dev;
n->vqs[VHOST_NET_VQ_TX].handle_kick = handle_tx_kick;
n->vqs[VHOST_NET_VQ_RX].handle_kick = handle_rx_kick;
- r = vhost_dev_init(&n->dev, n->vqs, VHOST_NET_VQ_MAX);
+ r = vhost_dev_init(dev, n->vqs, VHOST_NET_VQ_MAX);
if (r < 0) {
kfree(n);
return r;
}
- vhost_poll_init(n->poll + VHOST_NET_VQ_TX, handle_tx_net, POLLOUT);
- vhost_poll_init(n->poll + VHOST_NET_VQ_RX, handle_rx_net, POLLIN);
+ vhost_poll_init(n->poll + VHOST_NET_VQ_TX, handle_tx_net, POLLOUT, dev);
+ vhost_poll_init(n->poll + VHOST_NET_VQ_RX, handle_rx_net, POLLIN, dev);
n->tx_poll_state = VHOST_NET_POLL_DISABLED;
f->private_data = n;
@@ -527,13 +737,12 @@ static long vhost_net_set_backend(struct vhost_net *n, unsigned index, int fd)
/* start polling new socket */
oldsock = vq->private_data;
- if (sock == oldsock)
- goto done;
+ if (sock != oldsock) {
+ vhost_net_disable_vq(n, vq);
+ rcu_assign_pointer(vq->private_data, sock);
+ vhost_net_enable_vq(n, vq);
+ }
- vhost_net_disable_vq(n, vq);
- rcu_assign_pointer(vq->private_data, sock);
- vhost_net_enable_vq(n, vq);
-done:
mutex_unlock(&vq->mutex);
if (oldsock) {
@@ -574,9 +783,21 @@ done:
static int vhost_net_set_features(struct vhost_net *n, u64 features)
{
- size_t hdr_size = features & (1 << VHOST_NET_F_VIRTIO_NET_HDR) ?
- sizeof(struct virtio_net_hdr) : 0;
+ size_t vhost_hlen, sock_hlen, hdr_len;
int i;
+
+ hdr_len = (features & (1 << VIRTIO_NET_F_MRG_RXBUF)) ?
+ sizeof(struct virtio_net_hdr_mrg_rxbuf) :
+ sizeof(struct virtio_net_hdr);
+ if (features & (1 << VHOST_NET_F_VIRTIO_NET_HDR)) {
+ /* vhost provides vnet_hdr */
+ vhost_hlen = hdr_len;
+ sock_hlen = 0;
+ } else {
+ /* socket provides vnet_hdr */
+ vhost_hlen = 0;
+ sock_hlen = hdr_len;
+ }
mutex_lock(&n->dev.mutex);
if ((features & (1 << VHOST_F_LOG_ALL)) &&
!vhost_log_access_ok(&n->dev)) {
@@ -587,7 +808,8 @@ static int vhost_net_set_features(struct vhost_net *n, u64 features)
smp_wmb();
for (i = 0; i < VHOST_NET_VQ_MAX; ++i) {
mutex_lock(&n->vqs[i].mutex);
- n->vqs[i].hdr_size = hdr_size;
+ n->vqs[i].vhost_hlen = vhost_hlen;
+ n->vqs[i].sock_hlen = sock_hlen;
mutex_unlock(&n->vqs[i].mutex);
}
vhost_net_flush(n);
@@ -639,7 +861,7 @@ static long vhost_net_compat_ioctl(struct file *f, unsigned int ioctl,
}
#endif
-const static struct file_operations vhost_net_fops = {
+static const struct file_operations vhost_net_fops = {
.owner = THIS_MODULE,
.release = vhost_net_release,
.unlocked_ioctl = vhost_net_ioctl,
@@ -657,25 +879,13 @@ static struct miscdevice vhost_net_misc = {
static int vhost_net_init(void)
{
- int r = vhost_init();
- if (r)
- goto err_init;
- r = misc_register(&vhost_net_misc);
- if (r)
- goto err_reg;
- return 0;
-err_reg:
- vhost_cleanup();
-err_init:
- return r;
-
+ return misc_register(&vhost_net_misc);
}
module_init(vhost_net_init);
static void vhost_net_exit(void)
{
misc_deregister(&vhost_net_misc);
- vhost_cleanup();
}
module_exit(vhost_net_exit);
diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c
index 0b99783083f..e05557d5299 100644
--- a/drivers/vhost/vhost.c
+++ b/drivers/vhost/vhost.c
@@ -17,12 +17,13 @@
#include <linux/mm.h>
#include <linux/miscdevice.h>
#include <linux/mutex.h>
-#include <linux/workqueue.h>
#include <linux/rcupdate.h>
#include <linux/poll.h>
#include <linux/file.h>
#include <linux/highmem.h>
#include <linux/slab.h>
+#include <linux/kthread.h>
+#include <linux/cgroup.h>
#include <linux/net.h>
#include <linux/if_packet.h>
@@ -37,8 +38,6 @@ enum {
VHOST_MEMORY_F_LOG = 0x1,
};
-static struct workqueue_struct *vhost_workqueue;
-
static void vhost_poll_func(struct file *file, wait_queue_head_t *wqh,
poll_table *pt)
{
@@ -52,23 +51,31 @@ static void vhost_poll_func(struct file *file, wait_queue_head_t *wqh,
static int vhost_poll_wakeup(wait_queue_t *wait, unsigned mode, int sync,
void *key)
{
- struct vhost_poll *poll;
- poll = container_of(wait, struct vhost_poll, wait);
+ struct vhost_poll *poll = container_of(wait, struct vhost_poll, wait);
+
if (!((unsigned long)key & poll->mask))
return 0;
- queue_work(vhost_workqueue, &poll->work);
+ vhost_poll_queue(poll);
return 0;
}
/* Init poll structure */
-void vhost_poll_init(struct vhost_poll *poll, work_func_t func,
- unsigned long mask)
+void vhost_poll_init(struct vhost_poll *poll, vhost_work_fn_t fn,
+ unsigned long mask, struct vhost_dev *dev)
{
- INIT_WORK(&poll->work, func);
+ struct vhost_work *work = &poll->work;
+
init_waitqueue_func_entry(&poll->wait, vhost_poll_wakeup);
init_poll_funcptr(&poll->table, vhost_poll_func);
poll->mask = mask;
+ poll->dev = dev;
+
+ INIT_LIST_HEAD(&work->node);
+ work->fn = fn;
+ init_waitqueue_head(&work->done);
+ work->flushing = 0;
+ work->queue_seq = work->done_seq = 0;
}
/* Start polling a file. We add ourselves to file's wait queue. The caller must
@@ -92,12 +99,40 @@ void vhost_poll_stop(struct vhost_poll *poll)
* locks that are also used by the callback. */
void vhost_poll_flush(struct vhost_poll *poll)
{
- flush_work(&poll->work);
+ struct vhost_work *work = &poll->work;
+ unsigned seq;
+ int left;
+ int flushing;
+
+ spin_lock_irq(&poll->dev->work_lock);
+ seq = work->queue_seq;
+ work->flushing++;
+ spin_unlock_irq(&poll->dev->work_lock);
+ wait_event(work->done, ({
+ spin_lock_irq(&poll->dev->work_lock);
+ left = seq - work->done_seq <= 0;
+ spin_unlock_irq(&poll->dev->work_lock);
+ left;
+ }));
+ spin_lock_irq(&poll->dev->work_lock);
+ flushing = --work->flushing;
+ spin_unlock_irq(&poll->dev->work_lock);
+ BUG_ON(flushing < 0);
}
void vhost_poll_queue(struct vhost_poll *poll)
{
- queue_work(vhost_workqueue, &poll->work);
+ struct vhost_dev *dev = poll->dev;
+ struct vhost_work *work = &poll->work;
+ unsigned long flags;
+
+ spin_lock_irqsave(&dev->work_lock, flags);
+ if (list_empty(&work->node)) {
+ list_add_tail(&work->node, &dev->work_list);
+ work->queue_seq++;
+ wake_up_process(dev->worker);
+ }
+ spin_unlock_irqrestore(&dev->work_lock, flags);
}
static void vhost_vq_reset(struct vhost_dev *dev,
@@ -114,7 +149,8 @@ static void vhost_vq_reset(struct vhost_dev *dev,
vq->used_flags = 0;
vq->log_used = false;
vq->log_addr = -1ull;
- vq->hdr_size = 0;
+ vq->vhost_hlen = 0;
+ vq->sock_hlen = 0;
vq->private_data = NULL;
vq->log_base = NULL;
vq->error_ctx = NULL;
@@ -125,10 +161,51 @@ static void vhost_vq_reset(struct vhost_dev *dev,
vq->log_ctx = NULL;
}
+static int vhost_worker(void *data)
+{
+ struct vhost_dev *dev = data;
+ struct vhost_work *work = NULL;
+ unsigned uninitialized_var(seq);
+
+ for (;;) {
+ /* mb paired w/ kthread_stop */
+ set_current_state(TASK_INTERRUPTIBLE);
+
+ spin_lock_irq(&dev->work_lock);
+ if (work) {
+ work->done_seq = seq;
+ if (work->flushing)
+ wake_up_all(&work->done);
+ }
+
+ if (kthread_should_stop()) {
+ spin_unlock_irq(&dev->work_lock);
+ __set_current_state(TASK_RUNNING);
+ return 0;
+ }
+ if (!list_empty(&dev->work_list)) {
+ work = list_first_entry(&dev->work_list,
+ struct vhost_work, node);
+ list_del_init(&work->node);
+ seq = work->queue_seq;
+ } else
+ work = NULL;
+ spin_unlock_irq(&dev->work_lock);
+
+ if (work) {
+ __set_current_state(TASK_RUNNING);
+ work->fn(work);
+ } else
+ schedule();
+
+ }
+}
+
long vhost_dev_init(struct vhost_dev *dev,
struct vhost_virtqueue *vqs, int nvqs)
{
int i;
+
dev->vqs = vqs;
dev->nvqs = nvqs;
mutex_init(&dev->mutex);
@@ -136,6 +213,9 @@ long vhost_dev_init(struct vhost_dev *dev,
dev->log_file = NULL;
dev->memory = NULL;
dev->mm = NULL;
+ spin_lock_init(&dev->work_lock);
+ INIT_LIST_HEAD(&dev->work_list);
+ dev->worker = NULL;
for (i = 0; i < dev->nvqs; ++i) {
dev->vqs[i].dev = dev;
@@ -143,9 +223,9 @@ long vhost_dev_init(struct vhost_dev *dev,
vhost_vq_reset(dev, dev->vqs + i);
if (dev->vqs[i].handle_kick)
vhost_poll_init(&dev->vqs[i].poll,
- dev->vqs[i].handle_kick,
- POLLIN);
+ dev->vqs[i].handle_kick, POLLIN, dev);
}
+
return 0;
}
@@ -159,12 +239,36 @@ long vhost_dev_check_owner(struct vhost_dev *dev)
/* Caller should have device mutex */
static long vhost_dev_set_owner(struct vhost_dev *dev)
{
+ struct task_struct *worker;
+ int err;
/* Is there an owner already? */
- if (dev->mm)
- return -EBUSY;
+ if (dev->mm) {
+ err = -EBUSY;
+ goto err_mm;
+ }
/* No owner, become one */
dev->mm = get_task_mm(current);
+ worker = kthread_create(vhost_worker, dev, "vhost-%d", current->pid);
+ if (IS_ERR(worker)) {
+ err = PTR_ERR(worker);
+ goto err_worker;
+ }
+
+ dev->worker = worker;
+ err = cgroup_attach_task_current_cg(worker);
+ if (err)
+ goto err_cgroup;
+ wake_up_process(worker); /* avoid contributing to loadavg */
+
return 0;
+err_cgroup:
+ kthread_stop(worker);
+err_worker:
+ if (dev->mm)
+ mmput(dev->mm);
+ dev->mm = NULL;
+err_mm:
+ return err;
}
/* Caller should have device mutex */
@@ -217,6 +321,9 @@ void vhost_dev_cleanup(struct vhost_dev *dev)
if (dev->mm)
mmput(dev->mm);
dev->mm = NULL;
+
+ WARN_ON(!list_empty(&dev->work_list));
+ kthread_stop(dev->worker);
}
static int log_access_ok(void __user *log_base, u64 addr, unsigned long sz)
@@ -237,8 +344,8 @@ static int vq_memory_access_ok(void __user *log_base, struct vhost_memory *mem,
{
int i;
- if (!mem)
- return 0;
+ if (!mem)
+ return 0;
for (i = 0; i < mem->nregions; ++i) {
struct vhost_memory_region *m = mem->regions + i;
@@ -995,9 +1102,9 @@ int vhost_get_vq_desc(struct vhost_dev *dev, struct vhost_virtqueue *vq,
}
/* Reverse the effect of vhost_get_vq_desc. Useful for error handling. */
-void vhost_discard_vq_desc(struct vhost_virtqueue *vq)
+void vhost_discard_vq_desc(struct vhost_virtqueue *vq, int n)
{
- vq->last_avail_idx--;
+ vq->last_avail_idx -= n;
}
/* After we've used one of their buffers, we tell them about it. We'll then
@@ -1042,6 +1149,67 @@ int vhost_add_used(struct vhost_virtqueue *vq, unsigned int head, int len)
return 0;
}
+static int __vhost_add_used_n(struct vhost_virtqueue *vq,
+ struct vring_used_elem *heads,
+ unsigned count)
+{
+ struct vring_used_elem __user *used;
+ int start;
+
+ start = vq->last_used_idx % vq->num;
+ used = vq->used->ring + start;
+ if (copy_to_user(used, heads, count * sizeof *used)) {
+ vq_err(vq, "Failed to write used");
+ return -EFAULT;
+ }
+ if (unlikely(vq->log_used)) {
+ /* Make sure data is seen before log. */
+ smp_wmb();
+ /* Log used ring entry write. */
+ log_write(vq->log_base,
+ vq->log_addr +
+ ((void __user *)used - (void __user *)vq->used),
+ count * sizeof *used);
+ }
+ vq->last_used_idx += count;
+ return 0;
+}
+
+/* After we've used one of their buffers, we tell them about it. We'll then
+ * want to notify the guest, using eventfd. */
+int vhost_add_used_n(struct vhost_virtqueue *vq, struct vring_used_elem *heads,
+ unsigned count)
+{
+ int start, n, r;
+
+ start = vq->last_used_idx % vq->num;
+ n = vq->num - start;
+ if (n < count) {
+ r = __vhost_add_used_n(vq, heads, n);
+ if (r < 0)
+ return r;
+ heads += n;
+ count -= n;
+ }
+ r = __vhost_add_used_n(vq, heads, count);
+
+ /* Make sure buffer is written before we update index. */
+ smp_wmb();
+ if (put_user(vq->last_used_idx, &vq->used->idx)) {
+ vq_err(vq, "Failed to increment used idx");
+ return -EFAULT;
+ }
+ if (unlikely(vq->log_used)) {
+ /* Log used index update. */
+ log_write(vq->log_base,
+ vq->log_addr + offsetof(struct vring_used, idx),
+ sizeof vq->used->idx);
+ if (vq->log_ctx)
+ eventfd_signal(vq->log_ctx, 1);
+ }
+ return r;
+}
+
/* This actually signals the guest, using eventfd. */
void vhost_signal(struct vhost_dev *dev, struct vhost_virtqueue *vq)
{
@@ -1076,6 +1244,15 @@ void vhost_add_used_and_signal(struct vhost_dev *dev,
vhost_signal(dev, vq);
}
+/* multi-buffer version of vhost_add_used_and_signal */
+void vhost_add_used_and_signal_n(struct vhost_dev *dev,
+ struct vhost_virtqueue *vq,
+ struct vring_used_elem *heads, unsigned count)
+{
+ vhost_add_used_n(vq, heads, count);
+ vhost_signal(dev, vq);
+}
+
/* OK, now we need to know about added descriptors. */
bool vhost_enable_notify(struct vhost_virtqueue *vq)
{
@@ -1100,7 +1277,7 @@ bool vhost_enable_notify(struct vhost_virtqueue *vq)
return false;
}
- return avail_idx != vq->last_avail_idx;
+ return avail_idx != vq->avail_idx;
}
/* We don't need to be notified again. */
@@ -1115,16 +1292,3 @@ void vhost_disable_notify(struct vhost_virtqueue *vq)
vq_err(vq, "Failed to enable notification at %p: %d\n",
&vq->used->flags, r);
}
-
-int vhost_init(void)
-{
- vhost_workqueue = create_singlethread_workqueue("vhost");
- if (!vhost_workqueue)
- return -ENOMEM;
- return 0;
-}
-
-void vhost_cleanup(void)
-{
- destroy_workqueue(vhost_workqueue);
-}
diff --git a/drivers/vhost/vhost.h b/drivers/vhost/vhost.h
index 11ee13dba0f..afd77295971 100644
--- a/drivers/vhost/vhost.h
+++ b/drivers/vhost/vhost.h
@@ -5,13 +5,13 @@
#include <linux/vhost.h>
#include <linux/mm.h>
#include <linux/mutex.h>
-#include <linux/workqueue.h>
#include <linux/poll.h>
#include <linux/file.h>
#include <linux/skbuff.h>
#include <linux/uio.h>
#include <linux/virtio_config.h>
#include <linux/virtio_ring.h>
+#include <asm/atomic.h>
struct vhost_device;
@@ -20,19 +20,31 @@ enum {
VHOST_NET_MAX_SG = MAX_SKB_FRAGS + 2,
};
+struct vhost_work;
+typedef void (*vhost_work_fn_t)(struct vhost_work *work);
+
+struct vhost_work {
+ struct list_head node;
+ vhost_work_fn_t fn;
+ wait_queue_head_t done;
+ int flushing;
+ unsigned queue_seq;
+ unsigned done_seq;
+};
+
/* Poll a file (eventfd or socket) */
/* Note: there's nothing vhost specific about this structure. */
struct vhost_poll {
poll_table table;
wait_queue_head_t *wqh;
wait_queue_t wait;
- /* struct which will handle all actual work. */
- struct work_struct work;
+ struct vhost_work work;
unsigned long mask;
+ struct vhost_dev *dev;
};
-void vhost_poll_init(struct vhost_poll *poll, work_func_t func,
- unsigned long mask);
+void vhost_poll_init(struct vhost_poll *poll, vhost_work_fn_t fn,
+ unsigned long mask, struct vhost_dev *dev);
void vhost_poll_start(struct vhost_poll *poll, struct file *file);
void vhost_poll_stop(struct vhost_poll *poll);
void vhost_poll_flush(struct vhost_poll *poll);
@@ -63,7 +75,7 @@ struct vhost_virtqueue {
struct vhost_poll poll;
/* The routine to call when the Guest pings us, or timeout. */
- work_func_t handle_kick;
+ vhost_work_fn_t handle_kick;
/* Last available index we saw. */
u16 last_avail_idx;
@@ -84,13 +96,15 @@ struct vhost_virtqueue {
struct iovec indirect[VHOST_NET_MAX_SG];
struct iovec iov[VHOST_NET_MAX_SG];
struct iovec hdr[VHOST_NET_MAX_SG];
- size_t hdr_size;
+ size_t vhost_hlen;
+ size_t sock_hlen;
+ struct vring_used_elem heads[VHOST_NET_MAX_SG];
/* We use a kind of RCU to access private pointer.
- * All readers access it from workqueue, which makes it possible to
- * flush the workqueue instead of synchronize_rcu. Therefore readers do
+ * All readers access it from worker, which makes it possible to
+ * flush the vhost_work instead of synchronize_rcu. Therefore readers do
* not need to call rcu_read_lock/rcu_read_unlock: the beginning of
- * work item execution acts instead of rcu_read_lock() and the end of
- * work item execution acts instead of rcu_read_lock().
+ * vhost_work execution acts instead of rcu_read_lock() and the end of
+ * vhost_work execution acts instead of rcu_read_lock().
* Writers use virtqueue mutex. */
void *private_data;
/* Log write descriptors */
@@ -110,6 +124,9 @@ struct vhost_dev {
int nvqs;
struct file *log_file;
struct eventfd_ctx *log_ctx;
+ spinlock_t work_lock;
+ struct list_head work_list;
+ struct task_struct *worker;
};
long vhost_dev_init(struct vhost_dev *, struct vhost_virtqueue *vqs, int nvqs);
@@ -124,21 +141,22 @@ int vhost_get_vq_desc(struct vhost_dev *, struct vhost_virtqueue *,
struct iovec iov[], unsigned int iov_count,
unsigned int *out_num, unsigned int *in_num,
struct vhost_log *log, unsigned int *log_num);
-void vhost_discard_vq_desc(struct vhost_virtqueue *);
+void vhost_discard_vq_desc(struct vhost_virtqueue *, int n);
int vhost_add_used(struct vhost_virtqueue *, unsigned int head, int len);
-void vhost_signal(struct vhost_dev *, struct vhost_virtqueue *);
+int vhost_add_used_n(struct vhost_virtqueue *, struct vring_used_elem *heads,
+ unsigned count);
void vhost_add_used_and_signal(struct vhost_dev *, struct vhost_virtqueue *,
- unsigned int head, int len);
+ unsigned int id, int len);
+void vhost_add_used_and_signal_n(struct vhost_dev *, struct vhost_virtqueue *,
+ struct vring_used_elem *heads, unsigned count);
+void vhost_signal(struct vhost_dev *, struct vhost_virtqueue *);
void vhost_disable_notify(struct vhost_virtqueue *);
bool vhost_enable_notify(struct vhost_virtqueue *);
int vhost_log_write(struct vhost_virtqueue *vq, struct vhost_log *log,
unsigned int log_num, u64 len);
-int vhost_init(void);
-void vhost_cleanup(void);
-
#define vq_err(vq, fmt, ...) do { \
pr_debug(pr_fmt(fmt), ##__VA_ARGS__); \
if ((vq)->error_ctx) \
@@ -149,7 +167,8 @@ enum {
VHOST_FEATURES = (1 << VIRTIO_F_NOTIFY_ON_EMPTY) |
(1 << VIRTIO_RING_F_INDIRECT_DESC) |
(1 << VHOST_F_LOG_ALL) |
- (1 << VHOST_NET_F_VIRTIO_NET_HDR),
+ (1 << VHOST_NET_F_VIRTIO_NET_HDR) |
+ (1 << VIRTIO_NET_F_MRG_RXBUF),
};
static inline int vhost_has_feature(struct vhost_dev *dev, int bit)
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index 3d94a147172..7b11ea68c80 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -1871,6 +1871,7 @@ config FB_MBX_DEBUG
config FB_FSL_DIU
tristate "Freescale DIU framebuffer support"
depends on FB && FSL_SOC
+ select FB_MODE_HELPERS
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
@@ -2229,6 +2230,15 @@ config FB_BROADSHEET
and could also have been called by other names when coupled with
a bridge adapter.
+config FB_JZ4740
+ tristate "JZ4740 LCD framebuffer support"
+ depends on FB && MACH_JZ4740
+ select FB_SYS_FILLRECT
+ select FB_SYS_COPYAREA
+ select FB_SYS_IMAGEBLIT
+ help
+ Framebuffer support for the JZ4740 SoC.
+
source "drivers/video/omap/Kconfig"
source "drivers/video/omap2/Kconfig"
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index ddc2af2ba45..f56a9cae215 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -131,6 +131,7 @@ obj-$(CONFIG_FB_CARMINE) += carminefb.o
obj-$(CONFIG_FB_MB862XX) += mb862xx/
obj-$(CONFIG_FB_MSM) += msm/
obj-$(CONFIG_FB_NUC900) += nuc900fb.o
+obj-$(CONFIG_FB_JZ4740) += jz4740_fb.o
# Platform or fallback drivers go here
obj-$(CONFIG_FB_UVESA) += uvesafb.o
diff --git a/drivers/video/backlight/locomolcd.c b/drivers/video/backlight/locomolcd.c
index 7571bc26071..d2f59015d51 100644
--- a/drivers/video/backlight/locomolcd.c
+++ b/drivers/video/backlight/locomolcd.c
@@ -2,7 +2,7 @@
* Backlight control code for Sharp Zaurus SL-5500
*
* Copyright 2005 John Lenz <lenz@cs.wisc.edu>
- * Maintainer: Pavel Machek <pavel@suse.cz> (unless John wants to :-)
+ * Maintainer: Pavel Machek <pavel@ucw.cz> (unless John wants to :-)
* GPL v2
*
* This driver assumes single CPU. That's okay, because collie is
@@ -246,6 +246,6 @@ static void __exit locomolcd_exit(void)
module_init(locomolcd_init);
module_exit(locomolcd_exit);
-MODULE_AUTHOR("John Lenz <lenz@cs.wisc.edu>, Pavel Machek <pavel@suse.cz>");
+MODULE_AUTHOR("John Lenz <lenz@cs.wisc.edu>, Pavel Machek <pavel@ucw.cz>");
MODULE_DESCRIPTION("Collie LCD driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/video/bw2.c b/drivers/video/bw2.c
index 09f1b9b462f..c7796637baf 100644
--- a/drivers/video/bw2.c
+++ b/drivers/video/bw2.c
@@ -390,12 +390,12 @@ static int __init bw2_init(void)
if (fb_get_options("bw2fb", NULL))
return -ENODEV;
- return of_register_driver(&bw2_driver, &of_bus_type);
+ return of_register_platform_driver(&bw2_driver);
}
static void __exit bw2_exit(void)
{
- of_unregister_driver(&bw2_driver);
+ of_unregister_platform_driver(&bw2_driver);
}
module_init(bw2_init);
diff --git a/drivers/video/carminefb.c b/drivers/video/carminefb.c
index d8345fcc4fe..6b19136aa18 100644
--- a/drivers/video/carminefb.c
+++ b/drivers/video/carminefb.c
@@ -432,7 +432,7 @@ static int init_hardware(struct carmine_hw *hw)
u32 loops;
u32 ret;
- /* Initalize Carmine */
+ /* Initialize Carmine */
/* Sets internal clock */
c_set_hw_reg(hw, CARMINE_CTL_REG + CARMINE_CTL_REG_CLOCK_ENABLE,
CARMINE_DFLT_IP_CLOCK_ENABLE);
diff --git a/drivers/video/cg14.c b/drivers/video/cg14.c
index e5dc2241194..d09fde8beb6 100644
--- a/drivers/video/cg14.c
+++ b/drivers/video/cg14.c
@@ -610,12 +610,12 @@ static int __init cg14_init(void)
if (fb_get_options("cg14fb", NULL))
return -ENODEV;
- return of_register_driver(&cg14_driver, &of_bus_type);
+ return of_register_platform_driver(&cg14_driver);
}
static void __exit cg14_exit(void)
{
- of_unregister_driver(&cg14_driver);
+ of_unregister_platform_driver(&cg14_driver);
}
module_init(cg14_init);
diff --git a/drivers/video/cg3.c b/drivers/video/cg3.c
index 558d73a948a..64aa29809fb 100644
--- a/drivers/video/cg3.c
+++ b/drivers/video/cg3.c
@@ -477,12 +477,12 @@ static int __init cg3_init(void)
if (fb_get_options("cg3fb", NULL))
return -ENODEV;
- return of_register_driver(&cg3_driver, &of_bus_type);
+ return of_register_platform_driver(&cg3_driver);
}
static void __exit cg3_exit(void)
{
- of_unregister_driver(&cg3_driver);
+ of_unregister_platform_driver(&cg3_driver);
}
module_init(cg3_init);
diff --git a/drivers/video/cg6.c b/drivers/video/cg6.c
index 480d761a27a..2389a719dcc 100644
--- a/drivers/video/cg6.c
+++ b/drivers/video/cg6.c
@@ -870,12 +870,12 @@ static int __init cg6_init(void)
if (fb_get_options("cg6fb", NULL))
return -ENODEV;
- return of_register_driver(&cg6_driver, &of_bus_type);
+ return of_register_platform_driver(&cg6_driver);
}
static void __exit cg6_exit(void)
{
- of_unregister_driver(&cg6_driver);
+ of_unregister_platform_driver(&cg6_driver);
}
module_init(cg6_init);
diff --git a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c
index b0a3fa00706..3b3f5749af9 100644
--- a/drivers/video/console/fbcon.c
+++ b/drivers/video/console/fbcon.c
@@ -2342,6 +2342,30 @@ static int fbcon_blank(struct vc_data *vc, int blank, int mode_switch)
return 0;
}
+static int fbcon_debug_enter(struct vc_data *vc)
+{
+ struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
+ struct fbcon_ops *ops = info->fbcon_par;
+
+ ops->save_graphics = ops->graphics;
+ ops->graphics = 0;
+ if (info->fbops->fb_debug_enter)
+ info->fbops->fb_debug_enter(info);
+ fbcon_set_palette(vc, color_table);
+ return 0;
+}
+
+static int fbcon_debug_leave(struct vc_data *vc)
+{
+ struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
+ struct fbcon_ops *ops = info->fbcon_par;
+
+ ops->graphics = ops->save_graphics;
+ if (info->fbops->fb_debug_leave)
+ info->fbops->fb_debug_leave(info);
+ return 0;
+}
+
static int fbcon_get_font(struct vc_data *vc, struct console_font *font)
{
u8 *fontdata = vc->vc_font.data;
@@ -3276,6 +3300,8 @@ static const struct consw fb_con = {
.con_screen_pos = fbcon_screen_pos,
.con_getxy = fbcon_getxy,
.con_resize = fbcon_resize,
+ .con_debug_enter = fbcon_debug_enter,
+ .con_debug_leave = fbcon_debug_leave,
};
static struct notifier_block fbcon_event_notifier = {
diff --git a/drivers/video/console/fbcon.h b/drivers/video/console/fbcon.h
index 89a346880ec..6bd2e0c7f20 100644
--- a/drivers/video/console/fbcon.h
+++ b/drivers/video/console/fbcon.h
@@ -74,6 +74,7 @@ struct fbcon_ops {
int cursor_reset;
int blank_state;
int graphics;
+ int save_graphics; /* for debug enter/leave */
int flags;
int rotate;
int cur_rotate;
diff --git a/drivers/video/controlfb.c b/drivers/video/controlfb.c
index 49fcbe8f18a..c225dcce89e 100644
--- a/drivers/video/controlfb.c
+++ b/drivers/video/controlfb.c
@@ -40,6 +40,8 @@
#include <linux/vmalloc.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
#include <linux/fb.h>
#include <linux/init.h>
#include <linux/pci.h>
diff --git a/drivers/video/ffb.c b/drivers/video/ffb.c
index 95c0227f47f..f6ecfab296d 100644
--- a/drivers/video/ffb.c
+++ b/drivers/video/ffb.c
@@ -1067,12 +1067,12 @@ static int __init ffb_init(void)
if (fb_get_options("ffb", NULL))
return -ENODEV;
- return of_register_driver(&ffb_driver, &of_bus_type);
+ return of_register_platform_driver(&ffb_driver);
}
static void __exit ffb_exit(void)
{
- of_unregister_driver(&ffb_driver);
+ of_unregister_platform_driver(&ffb_driver);
}
module_init(ffb_init);
diff --git a/drivers/video/fsl-diu-fb.c b/drivers/video/fsl-diu-fb.c
index 27455ce298b..e38ad222454 100644
--- a/drivers/video/fsl-diu-fb.c
+++ b/drivers/video/fsl-diu-fb.c
@@ -34,7 +34,8 @@
#include <linux/of_platform.h>
#include <sysdev/fsl_soc.h>
-#include "fsl-diu-fb.h"
+#include <linux/fsl-diu-fb.h>
+#include "edid.h"
/*
* These parameters give default parameters
@@ -217,6 +218,7 @@ struct mfb_info {
int x_aoi_d; /* aoi display x offset to physical screen */
int y_aoi_d; /* aoi display y offset to physical screen */
struct fsl_diu_data *parent;
+ u8 *edid_data;
};
@@ -317,6 +319,17 @@ static void fsl_diu_free(void *virt, size_t size)
free_pages_exact(virt, size);
}
+/*
+ * Workaround for failed writing desc register of planes.
+ * Needed with MPC5121 DIU rev 2.0 silicon.
+ */
+void wr_reg_wa(u32 *reg, u32 val)
+{
+ do {
+ out_be32(reg, val);
+ } while (in_be32(reg) != val);
+}
+
static int fsl_diu_enable_panel(struct fb_info *info)
{
struct mfb_info *pmfbi, *cmfbi, *mfbi = info->par;
@@ -330,7 +343,7 @@ static int fsl_diu_enable_panel(struct fb_info *info)
switch (mfbi->index) {
case 0: /* plane 0 */
if (hw->desc[0] != ad->paddr)
- out_be32(&hw->desc[0], ad->paddr);
+ wr_reg_wa(&hw->desc[0], ad->paddr);
break;
case 1: /* plane 1 AOI 0 */
cmfbi = machine_data->fsl_diu_info[2]->par;
@@ -340,7 +353,7 @@ static int fsl_diu_enable_panel(struct fb_info *info)
cpu_to_le32(cmfbi->ad->paddr);
else
ad->next_ad = 0;
- out_be32(&hw->desc[1], ad->paddr);
+ wr_reg_wa(&hw->desc[1], ad->paddr);
}
break;
case 3: /* plane 2 AOI 0 */
@@ -351,14 +364,14 @@ static int fsl_diu_enable_panel(struct fb_info *info)
cpu_to_le32(cmfbi->ad->paddr);
else
ad->next_ad = 0;
- out_be32(&hw->desc[2], ad->paddr);
+ wr_reg_wa(&hw->desc[2], ad->paddr);
}
break;
case 2: /* plane 1 AOI 1 */
pmfbi = machine_data->fsl_diu_info[1]->par;
ad->next_ad = 0;
if (hw->desc[1] == machine_data->dummy_ad->paddr)
- out_be32(&hw->desc[1], ad->paddr);
+ wr_reg_wa(&hw->desc[1], ad->paddr);
else /* AOI0 open */
pmfbi->ad->next_ad = cpu_to_le32(ad->paddr);
break;
@@ -366,7 +379,7 @@ static int fsl_diu_enable_panel(struct fb_info *info)
pmfbi = machine_data->fsl_diu_info[3]->par;
ad->next_ad = 0;
if (hw->desc[2] == machine_data->dummy_ad->paddr)
- out_be32(&hw->desc[2], ad->paddr);
+ wr_reg_wa(&hw->desc[2], ad->paddr);
else /* AOI0 was open */
pmfbi->ad->next_ad = cpu_to_le32(ad->paddr);
break;
@@ -390,27 +403,24 @@ static int fsl_diu_disable_panel(struct fb_info *info)
switch (mfbi->index) {
case 0: /* plane 0 */
if (hw->desc[0] != machine_data->dummy_ad->paddr)
- out_be32(&hw->desc[0],
- machine_data->dummy_ad->paddr);
+ wr_reg_wa(&hw->desc[0], machine_data->dummy_ad->paddr);
break;
case 1: /* plane 1 AOI 0 */
cmfbi = machine_data->fsl_diu_info[2]->par;
if (cmfbi->count > 0) /* AOI1 is open */
- out_be32(&hw->desc[1], cmfbi->ad->paddr);
+ wr_reg_wa(&hw->desc[1], cmfbi->ad->paddr);
/* move AOI1 to the first */
else /* AOI1 was closed */
- out_be32(&hw->desc[1],
- machine_data->dummy_ad->paddr);
+ wr_reg_wa(&hw->desc[1], machine_data->dummy_ad->paddr);
/* close AOI 0 */
break;
case 3: /* plane 2 AOI 0 */
cmfbi = machine_data->fsl_diu_info[4]->par;
if (cmfbi->count > 0) /* AOI1 is open */
- out_be32(&hw->desc[2], cmfbi->ad->paddr);
+ wr_reg_wa(&hw->desc[2], cmfbi->ad->paddr);
/* move AOI1 to the first */
else /* AOI1 was closed */
- out_be32(&hw->desc[2],
- machine_data->dummy_ad->paddr);
+ wr_reg_wa(&hw->desc[2], machine_data->dummy_ad->paddr);
/* close AOI 0 */
break;
case 2: /* plane 1 AOI 1 */
@@ -421,7 +431,7 @@ static int fsl_diu_disable_panel(struct fb_info *info)
/* AOI0 is open, must be the first */
pmfbi->ad->next_ad = 0;
} else /* AOI1 is the first in the chain */
- out_be32(&hw->desc[1], machine_data->dummy_ad->paddr);
+ wr_reg_wa(&hw->desc[1], machine_data->dummy_ad->paddr);
/* close AOI 1 */
break;
case 4: /* plane 2 AOI 1 */
@@ -432,7 +442,7 @@ static int fsl_diu_disable_panel(struct fb_info *info)
/* AOI0 is open, must be the first */
pmfbi->ad->next_ad = 0;
} else /* AOI1 is the first in the chain */
- out_be32(&hw->desc[2], machine_data->dummy_ad->paddr);
+ wr_reg_wa(&hw->desc[2], machine_data->dummy_ad->paddr);
/* close AOI 1 */
break;
default:
@@ -1100,6 +1110,10 @@ static int fsl_diu_open(struct fb_info *info, int user)
struct mfb_info *mfbi = info->par;
int res = 0;
+ /* free boot splash memory on first /dev/fb0 open */
+ if (!mfbi->index && diu_ops.release_bootmem)
+ diu_ops.release_bootmem();
+
spin_lock(&diu_lock);
mfbi->count++;
if (mfbi->count == 1) {
@@ -1173,18 +1187,30 @@ static int __devinit install_fb(struct fb_info *info)
int rc;
struct mfb_info *mfbi = info->par;
const char *aoi_mode, *init_aoi_mode = "320x240";
+ struct fb_videomode *db = fsl_diu_mode_db;
+ unsigned int dbsize = ARRAY_SIZE(fsl_diu_mode_db);
+ int has_default_mode = 1;
if (init_fbinfo(info))
return -EINVAL;
- if (mfbi->index == 0) /* plane 0 */
+ if (mfbi->index == 0) { /* plane 0 */
+ if (mfbi->edid_data) {
+ /* Now build modedb from EDID */
+ fb_edid_to_monspecs(mfbi->edid_data, &info->monspecs);
+ fb_videomode_to_modelist(info->monspecs.modedb,
+ info->monspecs.modedb_len,
+ &info->modelist);
+ db = info->monspecs.modedb;
+ dbsize = info->monspecs.modedb_len;
+ }
aoi_mode = fb_mode;
- else
+ } else {
aoi_mode = init_aoi_mode;
+ }
pr_debug("mode used = %s\n", aoi_mode);
- rc = fb_find_mode(&info->var, info, aoi_mode, fsl_diu_mode_db,
- ARRAY_SIZE(fsl_diu_mode_db), &fsl_diu_default_mode, default_bpp);
-
+ rc = fb_find_mode(&info->var, info, aoi_mode, db, dbsize,
+ &fsl_diu_default_mode, default_bpp);
switch (rc) {
case 1:
pr_debug("using mode specified in @mode\n");
@@ -1202,10 +1228,50 @@ static int __devinit install_fb(struct fb_info *info)
default:
pr_debug("rc = %d\n", rc);
pr_debug("failed to find mode\n");
- return -EINVAL;
+ /*
+ * For plane 0 we continue and look into
+ * driver's internal modedb.
+ */
+ if (mfbi->index == 0 && mfbi->edid_data)
+ has_default_mode = 0;
+ else
+ return -EINVAL;
break;
}
+ if (!has_default_mode) {
+ rc = fb_find_mode(&info->var, info, aoi_mode, fsl_diu_mode_db,
+ ARRAY_SIZE(fsl_diu_mode_db),
+ &fsl_diu_default_mode,
+ default_bpp);
+ if (rc > 0 && rc < 5)
+ has_default_mode = 1;
+ }
+
+ /* Still not found, use preferred mode from database if any */
+ if (!has_default_mode && info->monspecs.modedb) {
+ struct fb_monspecs *specs = &info->monspecs;
+ struct fb_videomode *modedb = &specs->modedb[0];
+
+ /*
+ * Get preferred timing. If not found,
+ * first mode in database will be used.
+ */
+ if (specs->misc & FB_MISC_1ST_DETAIL) {
+ int i;
+
+ for (i = 0; i < specs->modedb_len; i++) {
+ if (specs->modedb[i].flag & FB_MODE_IS_FIRST) {
+ modedb = &specs->modedb[i];
+ break;
+ }
+ }
+ }
+
+ info->var.bits_per_pixel = default_bpp;
+ fb_videomode_to_var(&info->var, modedb);
+ }
+
pr_debug("xres_virtual %d\n", info->var.xres_virtual);
pr_debug("bits_per_pixel %d\n", info->var.bits_per_pixel);
@@ -1244,6 +1310,9 @@ static void uninstall_fb(struct fb_info *info)
if (!mfbi->registered)
return;
+ if (mfbi->index == 0)
+ kfree(mfbi->edid_data);
+
unregister_framebuffer(info);
unmap_video_memory(info);
if (&info->cmap)
@@ -1427,6 +1496,7 @@ static int __devinit fsl_diu_probe(struct of_device *ofdev,
int ret, i, error = 0;
struct resource res;
struct fsl_diu_data *machine_data;
+ int diu_mode;
machine_data = kzalloc(sizeof(struct fsl_diu_data), GFP_KERNEL);
if (!machine_data)
@@ -1443,6 +1513,17 @@ static int __devinit fsl_diu_probe(struct of_device *ofdev,
mfbi = machine_data->fsl_diu_info[i]->par;
memcpy(mfbi, &mfb_template[i], sizeof(struct mfb_info));
mfbi->parent = machine_data;
+
+ if (mfbi->index == 0) {
+ const u8 *prop;
+ int len;
+
+ /* Get EDID */
+ prop = of_get_property(np, "edid", &len);
+ if (prop && len == EDID_LENGTH)
+ mfbi->edid_data = kmemdup(prop, EDID_LENGTH,
+ GFP_KERNEL);
+ }
}
ret = of_address_to_resource(np, 0, &res);
@@ -1463,7 +1544,9 @@ static int __devinit fsl_diu_probe(struct of_device *ofdev,
goto error2;
}
- out_be32(&dr.diu_reg->diu_mode, 0); /* disable DIU anyway*/
+ diu_mode = in_be32(&dr.diu_reg->diu_mode);
+ if (diu_mode != MFB_MODE1)
+ out_be32(&dr.diu_reg->diu_mode, 0); /* disable DIU */
/* Get the IRQ of the DIU */
machine_data->irq = irq_of_parse_and_map(np, 0);
@@ -1511,7 +1594,13 @@ static int __devinit fsl_diu_probe(struct of_device *ofdev,
machine_data->dummy_ad->offset_xyd = 0;
machine_data->dummy_ad->next_ad = 0;
- out_be32(&dr.diu_reg->desc[0], machine_data->dummy_ad->paddr);
+ /*
+ * Let DIU display splash screen if it was pre-initialized
+ * by the bootloader, set dummy area descriptor otherwise.
+ */
+ if (diu_mode != MFB_MODE1)
+ out_be32(&dr.diu_reg->desc[0], machine_data->dummy_ad->paddr);
+
out_be32(&dr.diu_reg->desc[1], machine_data->dummy_ad->paddr);
out_be32(&dr.diu_reg->desc[2], machine_data->dummy_ad->paddr);
diff --git a/drivers/video/jz4740_fb.c b/drivers/video/jz4740_fb.c
new file mode 100644
index 00000000000..670ecaa0385
--- /dev/null
+++ b/drivers/video/jz4740_fb.c
@@ -0,0 +1,847 @@
+/*
+ * Copyright (C) 2009-2010, Lars-Peter Clausen <lars@metafoo.de>
+ * JZ4740 SoC LCD framebuffer 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.
+ *
+ * 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/mutex.h>
+#include <linux/platform_device.h>
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+
+#include <linux/console.h>
+#include <linux/fb.h>
+
+#include <linux/dma-mapping.h>
+
+#include <asm/mach-jz4740/jz4740_fb.h>
+#include <asm/mach-jz4740/gpio.h>
+
+#define JZ_REG_LCD_CFG 0x00
+#define JZ_REG_LCD_VSYNC 0x04
+#define JZ_REG_LCD_HSYNC 0x08
+#define JZ_REG_LCD_VAT 0x0C
+#define JZ_REG_LCD_DAH 0x10
+#define JZ_REG_LCD_DAV 0x14
+#define JZ_REG_LCD_PS 0x18
+#define JZ_REG_LCD_CLS 0x1C
+#define JZ_REG_LCD_SPL 0x20
+#define JZ_REG_LCD_REV 0x24
+#define JZ_REG_LCD_CTRL 0x30
+#define JZ_REG_LCD_STATE 0x34
+#define JZ_REG_LCD_IID 0x38
+#define JZ_REG_LCD_DA0 0x40
+#define JZ_REG_LCD_SA0 0x44
+#define JZ_REG_LCD_FID0 0x48
+#define JZ_REG_LCD_CMD0 0x4C
+#define JZ_REG_LCD_DA1 0x50
+#define JZ_REG_LCD_SA1 0x54
+#define JZ_REG_LCD_FID1 0x58
+#define JZ_REG_LCD_CMD1 0x5C
+
+#define JZ_LCD_CFG_SLCD BIT(31)
+#define JZ_LCD_CFG_PS_DISABLE BIT(23)
+#define JZ_LCD_CFG_CLS_DISABLE BIT(22)
+#define JZ_LCD_CFG_SPL_DISABLE BIT(21)
+#define JZ_LCD_CFG_REV_DISABLE BIT(20)
+#define JZ_LCD_CFG_HSYNCM BIT(19)
+#define JZ_LCD_CFG_PCLKM BIT(18)
+#define JZ_LCD_CFG_INV BIT(17)
+#define JZ_LCD_CFG_SYNC_DIR BIT(16)
+#define JZ_LCD_CFG_PS_POLARITY BIT(15)
+#define JZ_LCD_CFG_CLS_POLARITY BIT(14)
+#define JZ_LCD_CFG_SPL_POLARITY BIT(13)
+#define JZ_LCD_CFG_REV_POLARITY BIT(12)
+#define JZ_LCD_CFG_HSYNC_ACTIVE_LOW BIT(11)
+#define JZ_LCD_CFG_PCLK_FALLING_EDGE BIT(10)
+#define JZ_LCD_CFG_DE_ACTIVE_LOW BIT(9)
+#define JZ_LCD_CFG_VSYNC_ACTIVE_LOW BIT(8)
+#define JZ_LCD_CFG_18_BIT BIT(7)
+#define JZ_LCD_CFG_PDW (BIT(5) | BIT(4))
+#define JZ_LCD_CFG_MODE_MASK 0xf
+
+#define JZ_LCD_CTRL_BURST_4 (0x0 << 28)
+#define JZ_LCD_CTRL_BURST_8 (0x1 << 28)
+#define JZ_LCD_CTRL_BURST_16 (0x2 << 28)
+#define JZ_LCD_CTRL_RGB555 BIT(27)
+#define JZ_LCD_CTRL_OFUP BIT(26)
+#define JZ_LCD_CTRL_FRC_GRAYSCALE_16 (0x0 << 24)
+#define JZ_LCD_CTRL_FRC_GRAYSCALE_4 (0x1 << 24)
+#define JZ_LCD_CTRL_FRC_GRAYSCALE_2 (0x2 << 24)
+#define JZ_LCD_CTRL_PDD_MASK (0xff << 16)
+#define JZ_LCD_CTRL_EOF_IRQ BIT(13)
+#define JZ_LCD_CTRL_SOF_IRQ BIT(12)
+#define JZ_LCD_CTRL_OFU_IRQ BIT(11)
+#define JZ_LCD_CTRL_IFU0_IRQ BIT(10)
+#define JZ_LCD_CTRL_IFU1_IRQ BIT(9)
+#define JZ_LCD_CTRL_DD_IRQ BIT(8)
+#define JZ_LCD_CTRL_QDD_IRQ BIT(7)
+#define JZ_LCD_CTRL_REVERSE_ENDIAN BIT(6)
+#define JZ_LCD_CTRL_LSB_FISRT BIT(5)
+#define JZ_LCD_CTRL_DISABLE BIT(4)
+#define JZ_LCD_CTRL_ENABLE BIT(3)
+#define JZ_LCD_CTRL_BPP_1 0x0
+#define JZ_LCD_CTRL_BPP_2 0x1
+#define JZ_LCD_CTRL_BPP_4 0x2
+#define JZ_LCD_CTRL_BPP_8 0x3
+#define JZ_LCD_CTRL_BPP_15_16 0x4
+#define JZ_LCD_CTRL_BPP_18_24 0x5
+
+#define JZ_LCD_CMD_SOF_IRQ BIT(15)
+#define JZ_LCD_CMD_EOF_IRQ BIT(16)
+#define JZ_LCD_CMD_ENABLE_PAL BIT(12)
+
+#define JZ_LCD_SYNC_MASK 0x3ff
+
+#define JZ_LCD_STATE_DISABLED BIT(0)
+
+struct jzfb_framedesc {
+ uint32_t next;
+ uint32_t addr;
+ uint32_t id;
+ uint32_t cmd;
+} __packed;
+
+struct jzfb {
+ struct fb_info *fb;
+ struct platform_device *pdev;
+ void __iomem *base;
+ struct resource *mem;
+ struct jz4740_fb_platform_data *pdata;
+
+ size_t vidmem_size;
+ void *vidmem;
+ dma_addr_t vidmem_phys;
+ struct jzfb_framedesc *framedesc;
+ dma_addr_t framedesc_phys;
+
+ struct clk *ldclk;
+ struct clk *lpclk;
+
+ unsigned is_enabled:1;
+ struct mutex lock;
+
+ uint32_t pseudo_palette[16];
+};
+
+static const struct fb_fix_screeninfo jzfb_fix __devinitdata = {
+ .id = "JZ4740 FB",
+ .type = FB_TYPE_PACKED_PIXELS,
+ .visual = FB_VISUAL_TRUECOLOR,
+ .xpanstep = 0,
+ .ypanstep = 0,
+ .ywrapstep = 0,
+ .accel = FB_ACCEL_NONE,
+};
+
+static const struct jz_gpio_bulk_request jz_lcd_ctrl_pins[] = {
+ JZ_GPIO_BULK_PIN(LCD_PCLK),
+ JZ_GPIO_BULK_PIN(LCD_HSYNC),
+ JZ_GPIO_BULK_PIN(LCD_VSYNC),
+ JZ_GPIO_BULK_PIN(LCD_DE),
+ JZ_GPIO_BULK_PIN(LCD_PS),
+ JZ_GPIO_BULK_PIN(LCD_REV),
+ JZ_GPIO_BULK_PIN(LCD_CLS),
+ JZ_GPIO_BULK_PIN(LCD_SPL),
+};
+
+static const struct jz_gpio_bulk_request jz_lcd_data_pins[] = {
+ JZ_GPIO_BULK_PIN(LCD_DATA0),
+ JZ_GPIO_BULK_PIN(LCD_DATA1),
+ JZ_GPIO_BULK_PIN(LCD_DATA2),
+ JZ_GPIO_BULK_PIN(LCD_DATA3),
+ JZ_GPIO_BULK_PIN(LCD_DATA4),
+ JZ_GPIO_BULK_PIN(LCD_DATA5),
+ JZ_GPIO_BULK_PIN(LCD_DATA6),
+ JZ_GPIO_BULK_PIN(LCD_DATA7),
+ JZ_GPIO_BULK_PIN(LCD_DATA8),
+ JZ_GPIO_BULK_PIN(LCD_DATA9),
+ JZ_GPIO_BULK_PIN(LCD_DATA10),
+ JZ_GPIO_BULK_PIN(LCD_DATA11),
+ JZ_GPIO_BULK_PIN(LCD_DATA12),
+ JZ_GPIO_BULK_PIN(LCD_DATA13),
+ JZ_GPIO_BULK_PIN(LCD_DATA14),
+ JZ_GPIO_BULK_PIN(LCD_DATA15),
+ JZ_GPIO_BULK_PIN(LCD_DATA16),
+ JZ_GPIO_BULK_PIN(LCD_DATA17),
+};
+
+static unsigned int jzfb_num_ctrl_pins(struct jzfb *jzfb)
+{
+ unsigned int num;
+
+ switch (jzfb->pdata->lcd_type) {
+ case JZ_LCD_TYPE_GENERIC_16_BIT:
+ num = 4;
+ break;
+ case JZ_LCD_TYPE_GENERIC_18_BIT:
+ num = 4;
+ break;
+ case JZ_LCD_TYPE_8BIT_SERIAL:
+ num = 3;
+ break;
+ case JZ_LCD_TYPE_SPECIAL_TFT_1:
+ case JZ_LCD_TYPE_SPECIAL_TFT_2:
+ case JZ_LCD_TYPE_SPECIAL_TFT_3:
+ num = 8;
+ break;
+ default:
+ num = 0;
+ break;
+ }
+ return num;
+}
+
+static unsigned int jzfb_num_data_pins(struct jzfb *jzfb)
+{
+ unsigned int num;
+
+ switch (jzfb->pdata->lcd_type) {
+ case JZ_LCD_TYPE_GENERIC_16_BIT:
+ num = 16;
+ break;
+ case JZ_LCD_TYPE_GENERIC_18_BIT:
+ num = 18;
+ break;
+ case JZ_LCD_TYPE_8BIT_SERIAL:
+ num = 8;
+ break;
+ case JZ_LCD_TYPE_SPECIAL_TFT_1:
+ case JZ_LCD_TYPE_SPECIAL_TFT_2:
+ case JZ_LCD_TYPE_SPECIAL_TFT_3:
+ if (jzfb->pdata->bpp == 18)
+ num = 18;
+ else
+ num = 16;
+ break;
+ default:
+ num = 0;
+ break;
+ }
+ return num;
+}
+
+/* Based on CNVT_TOHW macro from skeletonfb.c */
+static inline uint32_t jzfb_convert_color_to_hw(unsigned val,
+ struct fb_bitfield *bf)
+{
+ return (((val << bf->length) + 0x7FFF - val) >> 16) << bf->offset;
+}
+
+static int jzfb_setcolreg(unsigned regno, unsigned red, unsigned green,
+ unsigned blue, unsigned transp, struct fb_info *fb)
+{
+ uint32_t color;
+
+ if (regno >= 16)
+ return -EINVAL;
+
+ color = jzfb_convert_color_to_hw(red, &fb->var.red);
+ color |= jzfb_convert_color_to_hw(green, &fb->var.green);
+ color |= jzfb_convert_color_to_hw(blue, &fb->var.blue);
+ color |= jzfb_convert_color_to_hw(transp, &fb->var.transp);
+
+ ((uint32_t *)(fb->pseudo_palette))[regno] = color;
+
+ return 0;
+}
+
+static int jzfb_get_controller_bpp(struct jzfb *jzfb)
+{
+ switch (jzfb->pdata->bpp) {
+ case 18:
+ case 24:
+ return 32;
+ case 15:
+ return 16;
+ default:
+ return jzfb->pdata->bpp;
+ }
+}
+
+static struct fb_videomode *jzfb_get_mode(struct jzfb *jzfb,
+ struct fb_var_screeninfo *var)
+{
+ size_t i;
+ struct fb_videomode *mode = jzfb->pdata->modes;
+
+ for (i = 0; i < jzfb->pdata->num_modes; ++i, ++mode) {
+ if (mode->xres == var->xres && mode->yres == var->yres)
+ return mode;
+ }
+
+ return NULL;
+}
+
+static int jzfb_check_var(struct fb_var_screeninfo *var, struct fb_info *fb)
+{
+ struct jzfb *jzfb = fb->par;
+ struct fb_videomode *mode;
+
+ if (var->bits_per_pixel != jzfb_get_controller_bpp(jzfb) &&
+ var->bits_per_pixel != jzfb->pdata->bpp)
+ return -EINVAL;
+
+ mode = jzfb_get_mode(jzfb, var);
+ if (mode == NULL)
+ return -EINVAL;
+
+ fb_videomode_to_var(var, mode);
+
+ switch (jzfb->pdata->bpp) {
+ case 8:
+ break;
+ case 15:
+ var->red.offset = 10;
+ var->red.length = 5;
+ var->green.offset = 6;
+ var->green.length = 5;
+ var->blue.offset = 0;
+ var->blue.length = 5;
+ break;
+ case 16:
+ var->red.offset = 11;
+ var->red.length = 5;
+ var->green.offset = 5;
+ var->green.length = 6;
+ var->blue.offset = 0;
+ var->blue.length = 5;
+ break;
+ case 18:
+ var->red.offset = 16;
+ var->red.length = 6;
+ var->green.offset = 8;
+ var->green.length = 6;
+ var->blue.offset = 0;
+ var->blue.length = 6;
+ var->bits_per_pixel = 32;
+ break;
+ case 32:
+ case 24:
+ var->transp.offset = 24;
+ var->transp.length = 8;
+ var->red.offset = 16;
+ var->red.length = 8;
+ var->green.offset = 8;
+ var->green.length = 8;
+ var->blue.offset = 0;
+ var->blue.length = 8;
+ var->bits_per_pixel = 32;
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static int jzfb_set_par(struct fb_info *info)
+{
+ struct jzfb *jzfb = info->par;
+ struct jz4740_fb_platform_data *pdata = jzfb->pdata;
+ struct fb_var_screeninfo *var = &info->var;
+ struct fb_videomode *mode;
+ uint16_t hds, vds;
+ uint16_t hde, vde;
+ uint16_t ht, vt;
+ uint32_t ctrl;
+ uint32_t cfg;
+ unsigned long rate;
+
+ mode = jzfb_get_mode(jzfb, var);
+ if (mode == NULL)
+ return -EINVAL;
+
+ if (mode == info->mode)
+ return 0;
+
+ info->mode = mode;
+
+ hds = mode->hsync_len + mode->left_margin;
+ hde = hds + mode->xres;
+ ht = hde + mode->right_margin;
+
+ vds = mode->vsync_len + mode->upper_margin;
+ vde = vds + mode->yres;
+ vt = vde + mode->lower_margin;
+
+ ctrl = JZ_LCD_CTRL_OFUP | JZ_LCD_CTRL_BURST_16;
+
+ switch (pdata->bpp) {
+ case 1:
+ ctrl |= JZ_LCD_CTRL_BPP_1;
+ break;
+ case 2:
+ ctrl |= JZ_LCD_CTRL_BPP_2;
+ break;
+ case 4:
+ ctrl |= JZ_LCD_CTRL_BPP_4;
+ break;
+ case 8:
+ ctrl |= JZ_LCD_CTRL_BPP_8;
+ break;
+ case 15:
+ ctrl |= JZ_LCD_CTRL_RGB555; /* Falltrough */
+ case 16:
+ ctrl |= JZ_LCD_CTRL_BPP_15_16;
+ break;
+ case 18:
+ case 24:
+ case 32:
+ ctrl |= JZ_LCD_CTRL_BPP_18_24;
+ break;
+ default:
+ break;
+ }
+
+ cfg = pdata->lcd_type & 0xf;
+
+ if (!(mode->sync & FB_SYNC_HOR_HIGH_ACT))
+ cfg |= JZ_LCD_CFG_HSYNC_ACTIVE_LOW;
+
+ if (!(mode->sync & FB_SYNC_VERT_HIGH_ACT))
+ cfg |= JZ_LCD_CFG_VSYNC_ACTIVE_LOW;
+
+ if (pdata->pixclk_falling_edge)
+ cfg |= JZ_LCD_CFG_PCLK_FALLING_EDGE;
+
+ if (pdata->date_enable_active_low)
+ cfg |= JZ_LCD_CFG_DE_ACTIVE_LOW;
+
+ if (pdata->lcd_type == JZ_LCD_TYPE_GENERIC_18_BIT)
+ cfg |= JZ_LCD_CFG_18_BIT;
+
+ if (mode->pixclock) {
+ rate = PICOS2KHZ(mode->pixclock) * 1000;
+ mode->refresh = rate / vt / ht;
+ } else {
+ if (pdata->lcd_type == JZ_LCD_TYPE_8BIT_SERIAL)
+ rate = mode->refresh * (vt + 2 * mode->xres) * ht;
+ else
+ rate = mode->refresh * vt * ht;
+
+ mode->pixclock = KHZ2PICOS(rate / 1000);
+ }
+
+ mutex_lock(&jzfb->lock);
+ if (!jzfb->is_enabled)
+ clk_enable(jzfb->ldclk);
+ else
+ ctrl |= JZ_LCD_CTRL_ENABLE;
+
+ switch (pdata->lcd_type) {
+ case JZ_LCD_TYPE_SPECIAL_TFT_1:
+ case JZ_LCD_TYPE_SPECIAL_TFT_2:
+ case JZ_LCD_TYPE_SPECIAL_TFT_3:
+ writel(pdata->special_tft_config.spl, jzfb->base + JZ_REG_LCD_SPL);
+ writel(pdata->special_tft_config.cls, jzfb->base + JZ_REG_LCD_CLS);
+ writel(pdata->special_tft_config.ps, jzfb->base + JZ_REG_LCD_PS);
+ writel(pdata->special_tft_config.ps, jzfb->base + JZ_REG_LCD_REV);
+ break;
+ default:
+ cfg |= JZ_LCD_CFG_PS_DISABLE;
+ cfg |= JZ_LCD_CFG_CLS_DISABLE;
+ cfg |= JZ_LCD_CFG_SPL_DISABLE;
+ cfg |= JZ_LCD_CFG_REV_DISABLE;
+ break;
+ }
+
+ writel(mode->hsync_len, jzfb->base + JZ_REG_LCD_HSYNC);
+ writel(mode->vsync_len, jzfb->base + JZ_REG_LCD_VSYNC);
+
+ writel((ht << 16) | vt, jzfb->base + JZ_REG_LCD_VAT);
+
+ writel((hds << 16) | hde, jzfb->base + JZ_REG_LCD_DAH);
+ writel((vds << 16) | vde, jzfb->base + JZ_REG_LCD_DAV);
+
+ writel(cfg, jzfb->base + JZ_REG_LCD_CFG);
+
+ writel(ctrl, jzfb->base + JZ_REG_LCD_CTRL);
+
+ if (!jzfb->is_enabled)
+ clk_disable(jzfb->ldclk);
+
+ mutex_unlock(&jzfb->lock);
+
+ clk_set_rate(jzfb->lpclk, rate);
+ clk_set_rate(jzfb->ldclk, rate * 3);
+
+ return 0;
+}
+
+static void jzfb_enable(struct jzfb *jzfb)
+{
+ uint32_t ctrl;
+
+ clk_enable(jzfb->ldclk);
+
+ jz_gpio_bulk_resume(jz_lcd_ctrl_pins, jzfb_num_ctrl_pins(jzfb));
+ jz_gpio_bulk_resume(jz_lcd_data_pins, jzfb_num_data_pins(jzfb));
+
+ writel(0, jzfb->base + JZ_REG_LCD_STATE);
+
+ writel(jzfb->framedesc->next, jzfb->base + JZ_REG_LCD_DA0);
+
+ ctrl = readl(jzfb->base + JZ_REG_LCD_CTRL);
+ ctrl |= JZ_LCD_CTRL_ENABLE;
+ ctrl &= ~JZ_LCD_CTRL_DISABLE;
+ writel(ctrl, jzfb->base + JZ_REG_LCD_CTRL);
+}
+
+static void jzfb_disable(struct jzfb *jzfb)
+{
+ uint32_t ctrl;
+
+ ctrl = readl(jzfb->base + JZ_REG_LCD_CTRL);
+ ctrl |= JZ_LCD_CTRL_DISABLE;
+ writel(ctrl, jzfb->base + JZ_REG_LCD_CTRL);
+ do {
+ ctrl = readl(jzfb->base + JZ_REG_LCD_STATE);
+ } while (!(ctrl & JZ_LCD_STATE_DISABLED));
+
+ jz_gpio_bulk_suspend(jz_lcd_ctrl_pins, jzfb_num_ctrl_pins(jzfb));
+ jz_gpio_bulk_suspend(jz_lcd_data_pins, jzfb_num_data_pins(jzfb));
+
+ clk_disable(jzfb->ldclk);
+}
+
+static int jzfb_blank(int blank_mode, struct fb_info *info)
+{
+ struct jzfb *jzfb = info->par;
+
+ switch (blank_mode) {
+ case FB_BLANK_UNBLANK:
+ mutex_lock(&jzfb->lock);
+ if (jzfb->is_enabled) {
+ mutex_unlock(&jzfb->lock);
+ return 0;
+ }
+
+ jzfb_enable(jzfb);
+ jzfb->is_enabled = 1;
+
+ mutex_unlock(&jzfb->lock);
+ break;
+ default:
+ mutex_lock(&jzfb->lock);
+ if (!jzfb->is_enabled) {
+ mutex_unlock(&jzfb->lock);
+ return 0;
+ }
+
+ jzfb_disable(jzfb);
+ jzfb->is_enabled = 0;
+
+ mutex_unlock(&jzfb->lock);
+ break;
+ }
+
+ return 0;
+}
+
+static int jzfb_alloc_devmem(struct jzfb *jzfb)
+{
+ int max_videosize = 0;
+ struct fb_videomode *mode = jzfb->pdata->modes;
+ void *page;
+ int i;
+
+ for (i = 0; i < jzfb->pdata->num_modes; ++mode, ++i) {
+ if (max_videosize < mode->xres * mode->yres)
+ max_videosize = mode->xres * mode->yres;
+ }
+
+ max_videosize *= jzfb_get_controller_bpp(jzfb) >> 3;
+
+ jzfb->framedesc = dma_alloc_coherent(&jzfb->pdev->dev,
+ sizeof(*jzfb->framedesc),
+ &jzfb->framedesc_phys, GFP_KERNEL);
+
+ if (!jzfb->framedesc)
+ return -ENOMEM;
+
+ jzfb->vidmem_size = PAGE_ALIGN(max_videosize);
+ jzfb->vidmem = dma_alloc_coherent(&jzfb->pdev->dev,
+ jzfb->vidmem_size,
+ &jzfb->vidmem_phys, GFP_KERNEL);
+
+ if (!jzfb->vidmem)
+ goto err_free_framedesc;
+
+ for (page = jzfb->vidmem;
+ page < jzfb->vidmem + PAGE_ALIGN(jzfb->vidmem_size);
+ page += PAGE_SIZE) {
+ SetPageReserved(virt_to_page(page));
+ }
+
+ jzfb->framedesc->next = jzfb->framedesc_phys;
+ jzfb->framedesc->addr = jzfb->vidmem_phys;
+ jzfb->framedesc->id = 0xdeafbead;
+ jzfb->framedesc->cmd = 0;
+ jzfb->framedesc->cmd |= max_videosize / 4;
+
+ return 0;
+
+err_free_framedesc:
+ dma_free_coherent(&jzfb->pdev->dev, sizeof(*jzfb->framedesc),
+ jzfb->framedesc, jzfb->framedesc_phys);
+ return -ENOMEM;
+}
+
+static void jzfb_free_devmem(struct jzfb *jzfb)
+{
+ dma_free_coherent(&jzfb->pdev->dev, jzfb->vidmem_size,
+ jzfb->vidmem, jzfb->vidmem_phys);
+ dma_free_coherent(&jzfb->pdev->dev, sizeof(*jzfb->framedesc),
+ jzfb->framedesc, jzfb->framedesc_phys);
+}
+
+static struct fb_ops jzfb_ops = {
+ .owner = THIS_MODULE,
+ .fb_check_var = jzfb_check_var,
+ .fb_set_par = jzfb_set_par,
+ .fb_blank = jzfb_blank,
+ .fb_fillrect = sys_fillrect,
+ .fb_copyarea = sys_copyarea,
+ .fb_imageblit = sys_imageblit,
+ .fb_setcolreg = jzfb_setcolreg,
+};
+
+static int __devinit jzfb_probe(struct platform_device *pdev)
+{
+ int ret;
+ struct jzfb *jzfb;
+ struct fb_info *fb;
+ struct jz4740_fb_platform_data *pdata = pdev->dev.platform_data;
+ struct resource *mem;
+
+ if (!pdata) {
+ dev_err(&pdev->dev, "Missing platform data\n");
+ return -ENXIO;
+ }
+
+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!mem) {
+ dev_err(&pdev->dev, "Failed to get register memory resource\n");
+ return -ENXIO;
+ }
+
+ mem = request_mem_region(mem->start, resource_size(mem), pdev->name);
+ if (!mem) {
+ dev_err(&pdev->dev, "Failed to request register memory region\n");
+ return -EBUSY;
+ }
+
+ fb = framebuffer_alloc(sizeof(struct jzfb), &pdev->dev);
+ if (!fb) {
+ dev_err(&pdev->dev, "Failed to allocate framebuffer device\n");
+ ret = -ENOMEM;
+ goto err_release_mem_region;
+ }
+
+ fb->fbops = &jzfb_ops;
+ fb->flags = FBINFO_DEFAULT;
+
+ jzfb = fb->par;
+ jzfb->pdev = pdev;
+ jzfb->pdata = pdata;
+ jzfb->mem = mem;
+
+ jzfb->ldclk = clk_get(&pdev->dev, "lcd");
+ if (IS_ERR(jzfb->ldclk)) {
+ ret = PTR_ERR(jzfb->ldclk);
+ dev_err(&pdev->dev, "Failed to get lcd clock: %d\n", ret);
+ goto err_framebuffer_release;
+ }
+
+ jzfb->lpclk = clk_get(&pdev->dev, "lcd_pclk");
+ if (IS_ERR(jzfb->lpclk)) {
+ ret = PTR_ERR(jzfb->lpclk);
+ dev_err(&pdev->dev, "Failed to get lcd pixel clock: %d\n", ret);
+ goto err_put_ldclk;
+ }
+
+ jzfb->base = ioremap(mem->start, resource_size(mem));
+ if (!jzfb->base) {
+ dev_err(&pdev->dev, "Failed to ioremap register memory region\n");
+ ret = -EBUSY;
+ goto err_put_lpclk;
+ }
+
+ platform_set_drvdata(pdev, jzfb);
+
+ mutex_init(&jzfb->lock);
+
+ fb_videomode_to_modelist(pdata->modes, pdata->num_modes,
+ &fb->modelist);
+ fb_videomode_to_var(&fb->var, pdata->modes);
+ fb->var.bits_per_pixel = pdata->bpp;
+ jzfb_check_var(&fb->var, fb);
+
+ ret = jzfb_alloc_devmem(jzfb);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to allocate video memory\n");
+ goto err_iounmap;
+ }
+
+ fb->fix = jzfb_fix;
+ fb->fix.line_length = fb->var.bits_per_pixel * fb->var.xres / 8;
+ fb->fix.mmio_start = mem->start;
+ fb->fix.mmio_len = resource_size(mem);
+ fb->fix.smem_start = jzfb->vidmem_phys;
+ fb->fix.smem_len = fb->fix.line_length * fb->var.yres;
+ fb->screen_base = jzfb->vidmem;
+ fb->pseudo_palette = jzfb->pseudo_palette;
+
+ fb_alloc_cmap(&fb->cmap, 256, 0);
+
+ clk_enable(jzfb->ldclk);
+ jzfb->is_enabled = 1;
+
+ writel(jzfb->framedesc->next, jzfb->base + JZ_REG_LCD_DA0);
+
+ fb->mode = NULL;
+ jzfb_set_par(fb);
+
+ jz_gpio_bulk_request(jz_lcd_ctrl_pins, jzfb_num_ctrl_pins(jzfb));
+ jz_gpio_bulk_request(jz_lcd_data_pins, jzfb_num_data_pins(jzfb));
+
+ ret = register_framebuffer(fb);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to register framebuffer: %d\n", ret);
+ goto err_free_devmem;
+ }
+
+ jzfb->fb = fb;
+
+ return 0;
+
+err_free_devmem:
+ jz_gpio_bulk_free(jz_lcd_ctrl_pins, jzfb_num_ctrl_pins(jzfb));
+ jz_gpio_bulk_free(jz_lcd_data_pins, jzfb_num_data_pins(jzfb));
+
+ fb_dealloc_cmap(&fb->cmap);
+ jzfb_free_devmem(jzfb);
+err_iounmap:
+ iounmap(jzfb->base);
+err_put_lpclk:
+ clk_put(jzfb->lpclk);
+err_put_ldclk:
+ clk_put(jzfb->ldclk);
+err_framebuffer_release:
+ framebuffer_release(fb);
+err_release_mem_region:
+ release_mem_region(mem->start, resource_size(mem));
+ return ret;
+}
+
+static int __devexit jzfb_remove(struct platform_device *pdev)
+{
+ struct jzfb *jzfb = platform_get_drvdata(pdev);
+
+ jzfb_blank(FB_BLANK_POWERDOWN, jzfb->fb);
+
+ jz_gpio_bulk_free(jz_lcd_ctrl_pins, jzfb_num_ctrl_pins(jzfb));
+ jz_gpio_bulk_free(jz_lcd_data_pins, jzfb_num_data_pins(jzfb));
+
+ iounmap(jzfb->base);
+ release_mem_region(jzfb->mem->start, resource_size(jzfb->mem));
+
+ fb_dealloc_cmap(&jzfb->fb->cmap);
+ jzfb_free_devmem(jzfb);
+
+ platform_set_drvdata(pdev, NULL);
+
+ clk_put(jzfb->lpclk);
+ clk_put(jzfb->ldclk);
+
+ framebuffer_release(jzfb->fb);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+
+static int jzfb_suspend(struct device *dev)
+{
+ struct jzfb *jzfb = dev_get_drvdata(dev);
+
+ acquire_console_sem();
+ fb_set_suspend(jzfb->fb, 1);
+ release_console_sem();
+
+ mutex_lock(&jzfb->lock);
+ if (jzfb->is_enabled)
+ jzfb_disable(jzfb);
+ mutex_unlock(&jzfb->lock);
+
+ return 0;
+}
+
+static int jzfb_resume(struct device *dev)
+{
+ struct jzfb *jzfb = dev_get_drvdata(dev);
+ clk_enable(jzfb->ldclk);
+
+ mutex_lock(&jzfb->lock);
+ if (jzfb->is_enabled)
+ jzfb_enable(jzfb);
+ mutex_unlock(&jzfb->lock);
+
+ acquire_console_sem();
+ fb_set_suspend(jzfb->fb, 0);
+ release_console_sem();
+
+ return 0;
+}
+
+static const struct dev_pm_ops jzfb_pm_ops = {
+ .suspend = jzfb_suspend,
+ .resume = jzfb_resume,
+ .poweroff = jzfb_suspend,
+ .restore = jzfb_resume,
+};
+
+#define JZFB_PM_OPS (&jzfb_pm_ops)
+
+#else
+#define JZFB_PM_OPS NULL
+#endif
+
+static struct platform_driver jzfb_driver = {
+ .probe = jzfb_probe,
+ .remove = __devexit_p(jzfb_remove),
+ .driver = {
+ .name = "jz4740-fb",
+ .pm = JZFB_PM_OPS,
+ },
+};
+
+static int __init jzfb_init(void)
+{
+ return platform_driver_register(&jzfb_driver);
+}
+module_init(jzfb_init);
+
+static void __exit jzfb_exit(void)
+{
+ platform_driver_unregister(&jzfb_driver);
+}
+module_exit(jzfb_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
+MODULE_DESCRIPTION("JZ4740 SoC LCD framebuffer driver");
+MODULE_ALIAS("platform:jz4740-fb");
diff --git a/drivers/video/leo.c b/drivers/video/leo.c
index 9e8bf7d5e24..ad677637ffb 100644
--- a/drivers/video/leo.c
+++ b/drivers/video/leo.c
@@ -677,12 +677,12 @@ static int __init leo_init(void)
if (fb_get_options("leofb", NULL))
return -ENODEV;
- return of_register_driver(&leo_driver, &of_bus_type);
+ return of_register_platform_driver(&leo_driver);
}
static void __exit leo_exit(void)
{
- of_unregister_driver(&leo_driver);
+ of_unregister_platform_driver(&leo_driver);
}
module_init(leo_init);
diff --git a/drivers/video/offb.c b/drivers/video/offb.c
index 46dda7d8aae..cb163a5397b 100644
--- a/drivers/video/offb.c
+++ b/drivers/video/offb.c
@@ -19,13 +19,14 @@
#include <linux/mm.h>
#include <linux/vmalloc.h>
#include <linux/delay.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
#include <linux/interrupt.h>
#include <linux/fb.h>
#include <linux/init.h>
#include <linux/ioport.h>
#include <linux/pci.h>
#include <asm/io.h>
-#include <asm/prom.h>
#ifdef CONFIG_PPC64
#include <asm/pci-bridge.h>
diff --git a/drivers/video/omap2/displays/panel-acx565akm.c b/drivers/video/omap2/displays/panel-acx565akm.c
index 1f8eb70e293..07fbb8a733b 100644
--- a/drivers/video/omap2/displays/panel-acx565akm.c
+++ b/drivers/video/omap2/displays/panel-acx565akm.c
@@ -592,7 +592,7 @@ static int acx_panel_power_on(struct omap_dss_device *dssdev)
r = omapdss_sdi_display_enable(dssdev);
if (r) {
pr_err("%s sdi enable failed\n", __func__);
- return r;
+ goto fail_unlock;
}
/*FIXME tweak me */
@@ -633,6 +633,8 @@ static int acx_panel_power_on(struct omap_dss_device *dssdev)
return acx565akm_bl_update_status(md->bl_dev);
fail:
omapdss_sdi_display_disable(dssdev);
+fail_unlock:
+ mutex_unlock(&md->mutex);
return r;
}
diff --git a/drivers/video/p9100.c b/drivers/video/p9100.c
index 6552751e81a..688b055abab 100644
--- a/drivers/video/p9100.c
+++ b/drivers/video/p9100.c
@@ -367,12 +367,12 @@ static int __init p9100_init(void)
if (fb_get_options("p9100fb", NULL))
return -ENODEV;
- return of_register_driver(&p9100_driver, &of_bus_type);
+ return of_register_platform_driver(&p9100_driver);
}
static void __exit p9100_exit(void)
{
- of_unregister_driver(&p9100_driver);
+ of_unregister_platform_driver(&p9100_driver);
}
module_init(p9100_init);
diff --git a/drivers/video/sunxvr1000.c b/drivers/video/sunxvr1000.c
index 489b44e8db8..7288934c0d4 100644
--- a/drivers/video/sunxvr1000.c
+++ b/drivers/video/sunxvr1000.c
@@ -213,12 +213,12 @@ static int __init gfb_init(void)
if (fb_get_options("gfb", NULL))
return -ENODEV;
- return of_register_driver(&gfb_driver, &of_bus_type);
+ return of_register_platform_driver(&gfb_driver);
}
static void __exit gfb_exit(void)
{
- of_unregister_driver(&gfb_driver);
+ of_unregister_platform_driver(&gfb_driver);
}
module_init(gfb_init);
diff --git a/drivers/video/tcx.c b/drivers/video/tcx.c
index cc039b33d2d..f375e0db677 100644
--- a/drivers/video/tcx.c
+++ b/drivers/video/tcx.c
@@ -526,12 +526,12 @@ static int __init tcx_init(void)
if (fb_get_options("tcxfb", NULL))
return -ENODEV;
- return of_register_driver(&tcx_driver, &of_bus_type);
+ return of_register_platform_driver(&tcx_driver);
}
static void __exit tcx_exit(void)
{
- of_unregister_driver(&tcx_driver);
+ of_unregister_platform_driver(&tcx_driver);
}
module_init(tcx_init);
diff --git a/drivers/video/tdfxfb.c b/drivers/video/tdfxfb.c
index 98054839004..3ee5e63cfa4 100644
--- a/drivers/video/tdfxfb.c
+++ b/drivers/video/tdfxfb.c
@@ -1571,8 +1571,8 @@ out_err_iobase:
if (default_par->mtrr_handle >= 0)
mtrr_del(default_par->mtrr_handle, info->fix.smem_start,
info->fix.smem_len);
- release_mem_region(pci_resource_start(pdev, 2),
- pci_resource_len(pdev, 2));
+ release_region(pci_resource_start(pdev, 2),
+ pci_resource_len(pdev, 2));
out_err_screenbase:
if (info->screen_base)
iounmap(info->screen_base);
diff --git a/drivers/video/tgafb.c b/drivers/video/tgafb.c
index 1b3b1c718e8..aba7686b1a3 100644
--- a/drivers/video/tgafb.c
+++ b/drivers/video/tgafb.c
@@ -305,7 +305,7 @@ tgafb_set_par(struct fb_info *info)
TGA_WRITE_REG(par, htimings, TGA_HORIZ_REG);
TGA_WRITE_REG(par, vtimings, TGA_VERT_REG);
- /* Initalise RAMDAC. */
+ /* Initialise RAMDAC. */
if (tga_type == TGA_TYPE_8PLANE && tga_bus_pci) {
/* Init BT485 RAMDAC registers. */
diff --git a/drivers/video/xen-fbfront.c b/drivers/video/xen-fbfront.c
index fa97d3e7c21..7c7f42a1279 100644
--- a/drivers/video/xen-fbfront.c
+++ b/drivers/video/xen-fbfront.c
@@ -684,7 +684,7 @@ static struct xenbus_driver xenfb_driver = {
static int __init xenfb_init(void)
{
- if (!xen_domain())
+ if (!xen_pv_domain())
return -ENODEV;
/* Nothing to do if running in dom0. */
diff --git a/drivers/video/xilinxfb.c b/drivers/video/xilinxfb.c
index 574dc54e12d..29b5daacc21 100644
--- a/drivers/video/xilinxfb.c
+++ b/drivers/video/xilinxfb.c
@@ -485,6 +485,8 @@ static int __devexit xilinxfb_of_remove(struct of_device *op)
/* Match table for of_platform binding */
static struct of_device_id xilinxfb_of_match[] __devinitdata = {
{ .compatible = "xlnx,xps-tft-1.00.a", },
+ { .compatible = "xlnx,xps-tft-2.00.a", },
+ { .compatible = "xlnx,xps-tft-2.01.a", },
{ .compatible = "xlnx,plb-tft-cntlr-ref-1.00.a", },
{ .compatible = "xlnx,plb-dvi-cntlr-ref-1.00.c", },
{},
diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
index afcfacc9bbe..b04b1846893 100644
--- a/drivers/watchdog/Kconfig
+++ b/drivers/watchdog/Kconfig
@@ -875,6 +875,24 @@ config TXX9_WDT
help
Hardware driver for the built-in watchdog timer on TXx9 MIPS SoCs.
+config OCTEON_WDT
+ tristate "Cavium OCTEON SOC family Watchdog Timer"
+ depends on CPU_CAVIUM_OCTEON
+ default y
+ select EXPORT_UASM if OCTEON_WDT = m
+ help
+ Hardware driver for OCTEON's on chip watchdog timer.
+ Enables the watchdog for all cores running Linux. It
+ installs a NMI handler and pokes the watchdog based on an
+ interrupt. On first expiration of the watchdog, the
+ interrupt handler pokes it. The second expiration causes an
+ NMI that prints a message. The third expiration causes a
+ global soft reset.
+
+ When userspace has /dev/watchdog open, no poking is done
+ from the first interrupt, it is then only poked when the
+ device is written.
+
# PARISC Architecture
# POWERPC Architecture
diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile
index 72f3e2073f8..e30289a5e36 100644
--- a/drivers/watchdog/Makefile
+++ b/drivers/watchdog/Makefile
@@ -114,6 +114,8 @@ obj-$(CONFIG_PNX833X_WDT) += pnx833x_wdt.o
obj-$(CONFIG_SIBYTE_WDOG) += sb_wdog.o
obj-$(CONFIG_AR7_WDT) += ar7_wdt.o
obj-$(CONFIG_TXX9_WDT) += txx9wdt.o
+obj-$(CONFIG_OCTEON_WDT) += octeon-wdt.o
+octeon-wdt-y := octeon-wdt-main.o octeon-wdt-nmi.o
# PARISC Architecture
diff --git a/drivers/watchdog/cpwd.c b/drivers/watchdog/cpwd.c
index d62b9ce8f77..30a2512fd52 100644
--- a/drivers/watchdog/cpwd.c
+++ b/drivers/watchdog/cpwd.c
@@ -545,7 +545,7 @@ static int __devinit cpwd_probe(struct of_device *op,
goto out;
}
- p->irq = op->irqs[0];
+ p->irq = op->archdata.irqs[0];
spin_lock_init(&p->lock);
@@ -688,12 +688,12 @@ static struct of_platform_driver cpwd_driver = {
static int __init cpwd_init(void)
{
- return of_register_driver(&cpwd_driver, &of_bus_type);
+ return of_register_platform_driver(&cpwd_driver);
}
static void __exit cpwd_exit(void)
{
- of_unregister_driver(&cpwd_driver);
+ of_unregister_platform_driver(&cpwd_driver);
}
module_init(cpwd_init);
diff --git a/drivers/watchdog/octeon-wdt-main.c b/drivers/watchdog/octeon-wdt-main.c
new file mode 100644
index 00000000000..2a410170eca
--- /dev/null
+++ b/drivers/watchdog/octeon-wdt-main.c
@@ -0,0 +1,745 @@
+/*
+ * Octeon Watchdog driver
+ *
+ * Copyright (C) 2007, 2008, 2009, 2010 Cavium Networks
+ *
+ * Some parts derived from wdt.c
+ *
+ * (c) Copyright 1996-1997 Alan Cox <alan@lxorguk.ukuu.org.uk>,
+ * 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.
+ *
+ * Neither Alan Cox nor CymruNet Ltd. admit liability nor provide
+ * warranty for any of this software. This material is provided
+ * "AS-IS" and at no charge.
+ *
+ * (c) Copyright 1995 Alan Cox <alan@lxorguk.ukuu.org.uk>
+ *
+ * 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.
+ *
+ *
+ * The OCTEON watchdog has a maximum timeout of 2^32 * io_clock.
+ * For most systems this is less than 10 seconds, so to allow for
+ * software to request longer watchdog heartbeats, we maintain software
+ * counters to count multiples of the base rate. If the system locks
+ * up in such a manner that we can not run the software counters, the
+ * only result is a watchdog reset sooner than was requested. But
+ * that is OK, because in this case userspace would likely not be able
+ * to do anything anyhow.
+ *
+ * The hardware watchdog interval we call the period. The OCTEON
+ * watchdog goes through several stages, after the first period an
+ * irq is asserted, then if it is not reset, after the next period NMI
+ * is asserted, then after an additional period a chip wide soft reset.
+ * So for the software counters, we reset watchdog after each period
+ * and decrement the counter. But for the last two periods we need to
+ * let the watchdog progress to the NMI stage so we disable the irq
+ * and let it proceed. Once in the NMI, we print the register state
+ * to the serial port and then wait for the reset.
+ *
+ * A watchdog is maintained for each CPU in the system, that way if
+ * one CPU suffers a lockup, we also get a register dump and reset.
+ * The userspace ping resets the watchdog on all CPUs.
+ *
+ * Before userspace opens the watchdog device, we still run the
+ * watchdogs to catch any lockups that may be kernel related.
+ *
+ */
+
+#include <linux/miscdevice.h>
+#include <linux/interrupt.h>
+#include <linux/watchdog.h>
+#include <linux/cpumask.h>
+#include <linux/bitops.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/delay.h>
+#include <linux/cpu.h>
+#include <linux/smp.h>
+#include <linux/fs.h>
+
+#include <asm/mipsregs.h>
+#include <asm/uasm.h>
+
+#include <asm/octeon/octeon.h>
+
+/* The count needed to achieve timeout_sec. */
+static unsigned int timeout_cnt;
+
+/* The maximum period supported. */
+static unsigned int max_timeout_sec;
+
+/* The current period. */
+static unsigned int timeout_sec;
+
+/* Set to non-zero when userspace countdown mode active */
+static int do_coundown;
+static unsigned int countdown_reset;
+static unsigned int per_cpu_countdown[NR_CPUS];
+
+static cpumask_t irq_enabled_cpus;
+
+#define WD_TIMO 60 /* Default heartbeat = 60 seconds */
+
+static int heartbeat = WD_TIMO;
+module_param(heartbeat, int, S_IRUGO);
+MODULE_PARM_DESC(heartbeat,
+ "Watchdog heartbeat in seconds. (0 < heartbeat, default="
+ __MODULE_STRING(WD_TIMO) ")");
+
+static int nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, int, S_IRUGO);
+MODULE_PARM_DESC(nowayout,
+ "Watchdog cannot be stopped once started (default="
+ __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
+
+static unsigned long octeon_wdt_is_open;
+static char expect_close;
+
+static u32 __initdata nmi_stage1_insns[64];
+/* We need one branch and therefore one relocation per target label. */
+static struct uasm_label __initdata labels[5];
+static struct uasm_reloc __initdata relocs[5];
+
+enum lable_id {
+ label_enter_bootloader = 1
+};
+
+/* Some CP0 registers */
+#define K0 26
+#define C0_CVMMEMCTL 11, 7
+#define C0_STATUS 12, 0
+#define C0_EBASE 15, 1
+#define C0_DESAVE 31, 0
+
+void octeon_wdt_nmi_stage2(void);
+
+static void __init octeon_wdt_build_stage1(void)
+{
+ int i;
+ int len;
+ u32 *p = nmi_stage1_insns;
+#ifdef CONFIG_HOTPLUG_CPU
+ struct uasm_label *l = labels;
+ struct uasm_reloc *r = relocs;
+#endif
+
+ /*
+ * For the next few instructions running the debugger may
+ * cause corruption of k0 in the saved registers. Since we're
+ * about to crash, nobody probably cares.
+ *
+ * Save K0 into the debug scratch register
+ */
+ uasm_i_dmtc0(&p, K0, C0_DESAVE);
+
+ uasm_i_mfc0(&p, K0, C0_STATUS);
+#ifdef CONFIG_HOTPLUG_CPU
+ uasm_il_bbit0(&p, &r, K0, ilog2(ST0_NMI), label_enter_bootloader);
+#endif
+ /* Force 64-bit addressing enabled */
+ uasm_i_ori(&p, K0, K0, ST0_UX | ST0_SX | ST0_KX);
+ uasm_i_mtc0(&p, K0, C0_STATUS);
+
+#ifdef CONFIG_HOTPLUG_CPU
+ uasm_i_mfc0(&p, K0, C0_EBASE);
+ /* Coreid number in K0 */
+ uasm_i_andi(&p, K0, K0, 0xf);
+ /* 8 * coreid in bits 16-31 */
+ uasm_i_dsll_safe(&p, K0, K0, 3 + 16);
+ uasm_i_ori(&p, K0, K0, 0x8001);
+ uasm_i_dsll_safe(&p, K0, K0, 16);
+ uasm_i_ori(&p, K0, K0, 0x0700);
+ uasm_i_drotr_safe(&p, K0, K0, 32);
+ /*
+ * Should result in: 0x8001,0700,0000,8*coreid which is
+ * CVMX_CIU_WDOGX(coreid) - 0x0500
+ *
+ * Now ld K0, CVMX_CIU_WDOGX(coreid)
+ */
+ uasm_i_ld(&p, K0, 0x500, K0);
+ /*
+ * If bit one set handle the NMI as a watchdog event.
+ * otherwise transfer control to bootloader.
+ */
+ uasm_il_bbit0(&p, &r, K0, 1, label_enter_bootloader);
+ uasm_i_nop(&p);
+#endif
+
+ /* Clear Dcache so cvmseg works right. */
+ uasm_i_cache(&p, 1, 0, 0);
+
+ /* Use K0 to do a read/modify/write of CVMMEMCTL */
+ uasm_i_dmfc0(&p, K0, C0_CVMMEMCTL);
+ /* Clear out the size of CVMSEG */
+ uasm_i_dins(&p, K0, 0, 0, 6);
+ /* Set CVMSEG to its largest value */
+ uasm_i_ori(&p, K0, K0, 0x1c0 | 54);
+ /* Store the CVMMEMCTL value */
+ uasm_i_dmtc0(&p, K0, C0_CVMMEMCTL);
+
+ /* Load the address of the second stage handler */
+ UASM_i_LA(&p, K0, (long)octeon_wdt_nmi_stage2);
+ uasm_i_jr(&p, K0);
+ uasm_i_dmfc0(&p, K0, C0_DESAVE);
+
+#ifdef CONFIG_HOTPLUG_CPU
+ uasm_build_label(&l, p, label_enter_bootloader);
+ /* Jump to the bootloader and restore K0 */
+ UASM_i_LA(&p, K0, (long)octeon_bootloader_entry_addr);
+ uasm_i_jr(&p, K0);
+ uasm_i_dmfc0(&p, K0, C0_DESAVE);
+#endif
+ uasm_resolve_relocs(relocs, labels);
+
+ len = (int)(p - nmi_stage1_insns);
+ pr_debug("Synthesized NMI stage 1 handler (%d instructions).\n", len);
+
+ pr_debug("\t.set push\n");
+ pr_debug("\t.set noreorder\n");
+ for (i = 0; i < len; i++)
+ pr_debug("\t.word 0x%08x\n", nmi_stage1_insns[i]);
+ pr_debug("\t.set pop\n");
+
+ if (len > 32)
+ panic("NMI stage 1 handler exceeds 32 instructions, was %d\n", len);
+}
+
+static int cpu2core(int cpu)
+{
+#ifdef CONFIG_SMP
+ return cpu_logical_map(cpu);
+#else
+ return cvmx_get_core_num();
+#endif
+}
+
+static int core2cpu(int coreid)
+{
+#ifdef CONFIG_SMP
+ return cpu_number_map(coreid);
+#else
+ return 0;
+#endif
+}
+
+/**
+ * Poke the watchdog when an interrupt is received
+ *
+ * @cpl:
+ * @dev_id:
+ *
+ * Returns
+ */
+static irqreturn_t octeon_wdt_poke_irq(int cpl, void *dev_id)
+{
+ unsigned int core = cvmx_get_core_num();
+ int cpu = core2cpu(core);
+
+ if (do_coundown) {
+ if (per_cpu_countdown[cpu] > 0) {
+ /* We're alive, poke the watchdog */
+ cvmx_write_csr(CVMX_CIU_PP_POKEX(core), 1);
+ per_cpu_countdown[cpu]--;
+ } else {
+ /* Bad news, you are about to reboot. */
+ disable_irq_nosync(cpl);
+ cpumask_clear_cpu(cpu, &irq_enabled_cpus);
+ }
+ } else {
+ /* Not open, just ping away... */
+ cvmx_write_csr(CVMX_CIU_PP_POKEX(core), 1);
+ }
+ return IRQ_HANDLED;
+}
+
+/* From setup.c */
+extern int prom_putchar(char c);
+
+/**
+ * Write a string to the uart
+ *
+ * @str: String to write
+ */
+static void octeon_wdt_write_string(const char *str)
+{
+ /* Just loop writing one byte at a time */
+ while (*str)
+ prom_putchar(*str++);
+}
+
+/**
+ * Write a hex number out of the uart
+ *
+ * @value: Number to display
+ * @digits: Number of digits to print (1 to 16)
+ */
+static void octeon_wdt_write_hex(u64 value, int digits)
+{
+ int d;
+ int v;
+ for (d = 0; d < digits; d++) {
+ v = (value >> ((digits - d - 1) * 4)) & 0xf;
+ if (v >= 10)
+ prom_putchar('a' + v - 10);
+ else
+ prom_putchar('0' + v);
+ }
+}
+
+const char *reg_name[] = {
+ "$0", "at", "v0", "v1", "a0", "a1", "a2", "a3",
+ "a4", "a5", "a6", "a7", "t0", "t1", "t2", "t3",
+ "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
+ "t8", "t9", "k0", "k1", "gp", "sp", "s8", "ra"
+};
+
+/**
+ * NMI stage 3 handler. NMIs are handled in the following manner:
+ * 1) The first NMI handler enables CVMSEG and transfers from
+ * the bootbus region into normal memory. It is careful to not
+ * destroy any registers.
+ * 2) The second stage handler uses CVMSEG to save the registers
+ * and create a stack for C code. It then calls the third level
+ * handler with one argument, a pointer to the register values.
+ * 3) The third, and final, level handler is the following C
+ * function that prints out some useful infomration.
+ *
+ * @reg: Pointer to register state before the NMI
+ */
+void octeon_wdt_nmi_stage3(u64 reg[32])
+{
+ u64 i;
+
+ unsigned int coreid = cvmx_get_core_num();
+ /*
+ * Save status and cause early to get them before any changes
+ * might happen.
+ */
+ u64 cp0_cause = read_c0_cause();
+ u64 cp0_status = read_c0_status();
+ u64 cp0_error_epc = read_c0_errorepc();
+ u64 cp0_epc = read_c0_epc();
+
+ /* Delay so output from all cores output is not jumbled together. */
+ __delay(100000000ull * coreid);
+
+ octeon_wdt_write_string("\r\n*** NMI Watchdog interrupt on Core 0x");
+ octeon_wdt_write_hex(coreid, 1);
+ octeon_wdt_write_string(" ***\r\n");
+ for (i = 0; i < 32; i++) {
+ octeon_wdt_write_string("\t");
+ octeon_wdt_write_string(reg_name[i]);
+ octeon_wdt_write_string("\t0x");
+ octeon_wdt_write_hex(reg[i], 16);
+ if (i & 1)
+ octeon_wdt_write_string("\r\n");
+ }
+ octeon_wdt_write_string("\terr_epc\t0x");
+ octeon_wdt_write_hex(cp0_error_epc, 16);
+
+ octeon_wdt_write_string("\tepc\t0x");
+ octeon_wdt_write_hex(cp0_epc, 16);
+ octeon_wdt_write_string("\r\n");
+
+ octeon_wdt_write_string("\tstatus\t0x");
+ octeon_wdt_write_hex(cp0_status, 16);
+ octeon_wdt_write_string("\tcause\t0x");
+ octeon_wdt_write_hex(cp0_cause, 16);
+ octeon_wdt_write_string("\r\n");
+
+ octeon_wdt_write_string("\tsum0\t0x");
+ octeon_wdt_write_hex(cvmx_read_csr(CVMX_CIU_INTX_SUM0(coreid * 2)), 16);
+ octeon_wdt_write_string("\ten0\t0x");
+ octeon_wdt_write_hex(cvmx_read_csr(CVMX_CIU_INTX_EN0(coreid * 2)), 16);
+ octeon_wdt_write_string("\r\n");
+
+ octeon_wdt_write_string("*** Chip soft reset soon ***\r\n");
+}
+
+static void octeon_wdt_disable_interrupt(int cpu)
+{
+ unsigned int core;
+ unsigned int irq;
+ union cvmx_ciu_wdogx ciu_wdog;
+
+ core = cpu2core(cpu);
+
+ irq = OCTEON_IRQ_WDOG0 + core;
+
+ /* Poke the watchdog to clear out its state */
+ cvmx_write_csr(CVMX_CIU_PP_POKEX(core), 1);
+
+ /* Disable the hardware. */
+ ciu_wdog.u64 = 0;
+ cvmx_write_csr(CVMX_CIU_WDOGX(core), ciu_wdog.u64);
+
+ free_irq(irq, octeon_wdt_poke_irq);
+}
+
+static void octeon_wdt_setup_interrupt(int cpu)
+{
+ unsigned int core;
+ unsigned int irq;
+ union cvmx_ciu_wdogx ciu_wdog;
+
+ core = cpu2core(cpu);
+
+ /* Disable it before doing anything with the interrupts. */
+ ciu_wdog.u64 = 0;
+ cvmx_write_csr(CVMX_CIU_WDOGX(core), ciu_wdog.u64);
+
+ per_cpu_countdown[cpu] = countdown_reset;
+
+ irq = OCTEON_IRQ_WDOG0 + core;
+
+ if (request_irq(irq, octeon_wdt_poke_irq,
+ IRQF_DISABLED, "octeon_wdt", octeon_wdt_poke_irq))
+ panic("octeon_wdt: Couldn't obtain irq %d", irq);
+
+ cpumask_set_cpu(cpu, &irq_enabled_cpus);
+
+ /* Poke the watchdog to clear out its state */
+ cvmx_write_csr(CVMX_CIU_PP_POKEX(core), 1);
+
+ /* Finally enable the watchdog now that all handlers are installed */
+ ciu_wdog.u64 = 0;
+ ciu_wdog.s.len = timeout_cnt;
+ ciu_wdog.s.mode = 3; /* 3 = Interrupt + NMI + Soft-Reset */
+ cvmx_write_csr(CVMX_CIU_WDOGX(core), ciu_wdog.u64);
+}
+
+static int octeon_wdt_cpu_callback(struct notifier_block *nfb,
+ unsigned long action, void *hcpu)
+{
+ unsigned int cpu = (unsigned long)hcpu;
+
+ switch (action) {
+ case CPU_DOWN_PREPARE:
+ octeon_wdt_disable_interrupt(cpu);
+ break;
+ case CPU_ONLINE:
+ case CPU_DOWN_FAILED:
+ octeon_wdt_setup_interrupt(cpu);
+ break;
+ default:
+ break;
+ }
+ return NOTIFY_OK;
+}
+
+static void octeon_wdt_ping(void)
+{
+ int cpu;
+ int coreid;
+
+ for_each_online_cpu(cpu) {
+ coreid = cpu2core(cpu);
+ cvmx_write_csr(CVMX_CIU_PP_POKEX(coreid), 1);
+ per_cpu_countdown[cpu] = countdown_reset;
+ if ((countdown_reset || !do_coundown) &&
+ !cpumask_test_cpu(cpu, &irq_enabled_cpus)) {
+ /* We have to enable the irq */
+ int irq = OCTEON_IRQ_WDOG0 + coreid;
+ enable_irq(irq);
+ cpumask_set_cpu(cpu, &irq_enabled_cpus);
+ }
+ }
+}
+
+static void octeon_wdt_calc_parameters(int t)
+{
+ unsigned int periods;
+
+ timeout_sec = max_timeout_sec;
+
+
+ /*
+ * Find the largest interrupt period, that can evenly divide
+ * the requested heartbeat time.
+ */
+ while ((t % timeout_sec) != 0)
+ timeout_sec--;
+
+ periods = t / timeout_sec;
+
+ /*
+ * The last two periods are after the irq is disabled, and
+ * then to the nmi, so we subtract them off.
+ */
+
+ countdown_reset = periods > 2 ? periods - 2 : 0;
+ heartbeat = t;
+ timeout_cnt = ((octeon_get_clock_rate() >> 8) * timeout_sec) >> 8;
+}
+
+static int octeon_wdt_set_heartbeat(int t)
+{
+ int cpu;
+ int coreid;
+ union cvmx_ciu_wdogx ciu_wdog;
+
+ if (t <= 0)
+ return -1;
+
+ octeon_wdt_calc_parameters(t);
+
+ for_each_online_cpu(cpu) {
+ coreid = cpu2core(cpu);
+ cvmx_write_csr(CVMX_CIU_PP_POKEX(coreid), 1);
+ ciu_wdog.u64 = 0;
+ ciu_wdog.s.len = timeout_cnt;
+ ciu_wdog.s.mode = 3; /* 3 = Interrupt + NMI + Soft-Reset */
+ cvmx_write_csr(CVMX_CIU_WDOGX(coreid), ciu_wdog.u64);
+ cvmx_write_csr(CVMX_CIU_PP_POKEX(coreid), 1);
+ }
+ octeon_wdt_ping(); /* Get the irqs back on. */
+ return 0;
+}
+
+/**
+ * octeon_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 octeon_wdt_write(struct file *file, const char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ if (count) {
+ if (!nowayout) {
+ size_t i;
+
+ /* In case it was set long ago */
+ expect_close = 0;
+
+ for (i = 0; i != count; i++) {
+ char c;
+ if (get_user(c, buf + i))
+ return -EFAULT;
+ if (c == 'V')
+ expect_close = 1;
+ }
+ }
+ octeon_wdt_ping();
+ }
+ return count;
+}
+
+/**
+ * octeon_wdt_ioctl:
+ * @file: file handle to the device
+ * @cmd: watchdog command
+ * @arg: argument pointer
+ *
+ * The watchdog API defines a common set of functions for all
+ * watchdogs according to their available features. We only
+ * actually usefully support querying capabilities and setting
+ * the timeout.
+ */
+
+static long octeon_wdt_ioctl(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ void __user *argp = (void __user *)arg;
+ int __user *p = argp;
+ int new_heartbeat;
+
+ static struct watchdog_info ident = {
+ .options = WDIOF_SETTIMEOUT|
+ WDIOF_MAGICCLOSE|
+ WDIOF_KEEPALIVEPING,
+ .firmware_version = 1,
+ .identity = "OCTEON",
+ };
+
+ switch (cmd) {
+ case WDIOC_GETSUPPORT:
+ return copy_to_user(argp, &ident, sizeof(ident)) ? -EFAULT : 0;
+ case WDIOC_GETSTATUS:
+ case WDIOC_GETBOOTSTATUS:
+ return put_user(0, p);
+ case WDIOC_KEEPALIVE:
+ octeon_wdt_ping();
+ return 0;
+ case WDIOC_SETTIMEOUT:
+ if (get_user(new_heartbeat, p))
+ return -EFAULT;
+ if (octeon_wdt_set_heartbeat(new_heartbeat))
+ return -EINVAL;
+ /* Fall through. */
+ case WDIOC_GETTIMEOUT:
+ return put_user(heartbeat, p);
+ default:
+ return -ENOTTY;
+ }
+}
+
+/**
+ * octeon_wdt_open:
+ * @inode: inode of device
+ * @file: file handle to device
+ *
+ * The watchdog device has been opened. The watchdog device is single
+ * open and on opening we do a ping to reset the counters.
+ */
+
+static int octeon_wdt_open(struct inode *inode, struct file *file)
+{
+ if (test_and_set_bit(0, &octeon_wdt_is_open))
+ return -EBUSY;
+ /*
+ * Activate
+ */
+ octeon_wdt_ping();
+ do_coundown = 1;
+ return nonseekable_open(inode, file);
+}
+
+/**
+ * octeon_wdt_release:
+ * @inode: inode to board
+ * @file: file handle to board
+ *
+ * The watchdog has a configurable API. There is a religious dispute
+ * between people who want their watchdog to be able to shut down and
+ * those who want to be sure if the watchdog manager dies the machine
+ * reboots. In the former case we disable the counters, in the latter
+ * case you have to open it again very soon.
+ */
+
+static int octeon_wdt_release(struct inode *inode, struct file *file)
+{
+ if (expect_close) {
+ do_coundown = 0;
+ octeon_wdt_ping();
+ } else {
+ pr_crit("octeon_wdt: WDT device closed unexpectedly. WDT will not stop!\n");
+ }
+ clear_bit(0, &octeon_wdt_is_open);
+ expect_close = 0;
+ return 0;
+}
+
+static const struct file_operations octeon_wdt_fops = {
+ .owner = THIS_MODULE,
+ .llseek = no_llseek,
+ .write = octeon_wdt_write,
+ .unlocked_ioctl = octeon_wdt_ioctl,
+ .open = octeon_wdt_open,
+ .release = octeon_wdt_release,
+};
+
+static struct miscdevice octeon_wdt_miscdev = {
+ .minor = WATCHDOG_MINOR,
+ .name = "watchdog",
+ .fops = &octeon_wdt_fops,
+};
+
+static struct notifier_block octeon_wdt_cpu_notifier = {
+ .notifier_call = octeon_wdt_cpu_callback,
+};
+
+
+/**
+ * Module/ driver initialization.
+ *
+ * Returns Zero on success
+ */
+static int __init octeon_wdt_init(void)
+{
+ int i;
+ int ret;
+ int cpu;
+ u64 *ptr;
+
+ /*
+ * Watchdog time expiration length = The 16 bits of LEN
+ * represent the most significant bits of a 24 bit decrementer
+ * that decrements every 256 cycles.
+ *
+ * Try for a timeout of 5 sec, if that fails a smaller number
+ * of even seconds,
+ */
+ max_timeout_sec = 6;
+ do {
+ max_timeout_sec--;
+ timeout_cnt = ((octeon_get_clock_rate() >> 8) * max_timeout_sec) >> 8;
+ } while (timeout_cnt > 65535);
+
+ BUG_ON(timeout_cnt == 0);
+
+ octeon_wdt_calc_parameters(heartbeat);
+
+ pr_info("octeon_wdt: Initial granularity %d Sec.\n", timeout_sec);
+
+ ret = misc_register(&octeon_wdt_miscdev);
+ if (ret) {
+ pr_err("octeon_wdt: cannot register miscdev on minor=%d (err=%d)\n",
+ WATCHDOG_MINOR, ret);
+ goto out;
+ }
+
+ /* Build the NMI handler ... */
+ octeon_wdt_build_stage1();
+
+ /* ... and install it. */
+ ptr = (u64 *) nmi_stage1_insns;
+ for (i = 0; i < 16; i++) {
+ cvmx_write_csr(CVMX_MIO_BOOT_LOC_ADR, i * 8);
+ cvmx_write_csr(CVMX_MIO_BOOT_LOC_DAT, ptr[i]);
+ }
+ cvmx_write_csr(CVMX_MIO_BOOT_LOC_CFGX(0), 0x81fc0000);
+
+ cpumask_clear(&irq_enabled_cpus);
+
+ for_each_online_cpu(cpu)
+ octeon_wdt_setup_interrupt(cpu);
+
+ register_hotcpu_notifier(&octeon_wdt_cpu_notifier);
+out:
+ return ret;
+}
+
+/**
+ * Module / driver shutdown
+ */
+static void __exit octeon_wdt_cleanup(void)
+{
+ int cpu;
+
+ misc_deregister(&octeon_wdt_miscdev);
+
+ unregister_hotcpu_notifier(&octeon_wdt_cpu_notifier);
+
+ for_each_online_cpu(cpu) {
+ int core = cpu2core(cpu);
+ /* Disable the watchdog */
+ cvmx_write_csr(CVMX_CIU_WDOGX(core), 0);
+ /* Free the interrupt handler */
+ free_irq(OCTEON_IRQ_WDOG0 + core, octeon_wdt_poke_irq);
+ }
+ /*
+ * Disable the boot-bus memory, the code it points to is soon
+ * to go missing.
+ */
+ cvmx_write_csr(CVMX_MIO_BOOT_LOC_CFGX(0), 0);
+}
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Cavium Networks <support@caviumnetworks.com>");
+MODULE_DESCRIPTION("Cavium Networks Octeon Watchdog driver.");
+module_init(octeon_wdt_init);
+module_exit(octeon_wdt_cleanup);
diff --git a/drivers/watchdog/octeon-wdt-nmi.S b/drivers/watchdog/octeon-wdt-nmi.S
new file mode 100644
index 00000000000..8a900a5e323
--- /dev/null
+++ b/drivers/watchdog/octeon-wdt-nmi.S
@@ -0,0 +1,64 @@
+/*
+ * 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) 2007 Cavium Networks
+ */
+#include <asm/asm.h>
+#include <asm/regdef.h>
+
+#define SAVE_REG(r) sd $r, -32768+6912-(32-r)*8($0)
+
+ NESTED(octeon_wdt_nmi_stage2, 0, sp)
+ .set push
+ .set noreorder
+ .set noat
+ /* Save all registers to the top CVMSEG. This shouldn't
+ * corrupt any state used by the kernel. Also all registers
+ * should have the value right before the NMI. */
+ SAVE_REG(0)
+ SAVE_REG(1)
+ SAVE_REG(2)
+ SAVE_REG(3)
+ SAVE_REG(4)
+ SAVE_REG(5)
+ SAVE_REG(6)
+ SAVE_REG(7)
+ SAVE_REG(8)
+ SAVE_REG(9)
+ SAVE_REG(10)
+ SAVE_REG(11)
+ SAVE_REG(12)
+ SAVE_REG(13)
+ SAVE_REG(14)
+ SAVE_REG(15)
+ SAVE_REG(16)
+ SAVE_REG(17)
+ SAVE_REG(18)
+ SAVE_REG(19)
+ SAVE_REG(20)
+ SAVE_REG(21)
+ SAVE_REG(22)
+ SAVE_REG(23)
+ SAVE_REG(24)
+ SAVE_REG(25)
+ SAVE_REG(26)
+ SAVE_REG(27)
+ SAVE_REG(28)
+ SAVE_REG(29)
+ SAVE_REG(30)
+ SAVE_REG(31)
+ /* Set the stack to begin right below the registers */
+ li sp, -32768+6912-32*8
+ /* Load the address of the third stage handler */
+ dla a0, octeon_wdt_nmi_stage3
+ /* Call the third stage handler */
+ jal a0
+ /* a0 is the address of the saved registers */
+ move a0, sp
+ /* Loop forvever if we get here. */
+1: b 1b
+ nop
+ .set pop
+ END(octeon_wdt_nmi_stage2)
diff --git a/drivers/watchdog/riowd.c b/drivers/watchdog/riowd.c
index 5dceeddc885..4082b4ace1f 100644
--- a/drivers/watchdog/riowd.c
+++ b/drivers/watchdog/riowd.c
@@ -250,12 +250,12 @@ static struct of_platform_driver riowd_driver = {
static int __init riowd_init(void)
{
- return of_register_driver(&riowd_driver, &of_bus_type);
+ return of_register_platform_driver(&riowd_driver);
}
static void __exit riowd_exit(void)
{
- of_unregister_driver(&riowd_driver);
+ of_unregister_platform_driver(&riowd_driver);
}
module_init(riowd_init);
diff --git a/drivers/xen/Kconfig b/drivers/xen/Kconfig
index fad3df2c127..0a882693663 100644
--- a/drivers/xen/Kconfig
+++ b/drivers/xen/Kconfig
@@ -62,4 +62,13 @@ config XEN_SYS_HYPERVISOR
virtual environment, /sys/hypervisor will still be present,
but will have no xen contents.
+config XEN_PLATFORM_PCI
+ tristate "xen platform pci device driver"
+ depends on XEN_PVHVM
+ default m
+ help
+ Driver for the Xen PCI Platform device: it is responsible for
+ initializing xenbus and grant_table when running in a Xen HVM
+ domain. As a consequence this driver is required to run any Xen PV
+ frontend on Xen HVM.
endmenu
diff --git a/drivers/xen/Makefile b/drivers/xen/Makefile
index 7c284342f30..e392fb776af 100644
--- a/drivers/xen/Makefile
+++ b/drivers/xen/Makefile
@@ -9,4 +9,5 @@ obj-$(CONFIG_XEN_XENCOMM) += xencomm.o
obj-$(CONFIG_XEN_BALLOON) += balloon.o
obj-$(CONFIG_XEN_DEV_EVTCHN) += evtchn.o
obj-$(CONFIG_XENFS) += xenfs/
-obj-$(CONFIG_XEN_SYS_HYPERVISOR) += sys-hypervisor.o \ No newline at end of file
+obj-$(CONFIG_XEN_SYS_HYPERVISOR) += sys-hypervisor.o
+obj-$(CONFIG_XEN_PLATFORM_PCI) += platform-pci.o
diff --git a/drivers/xen/events.c b/drivers/xen/events.c
index db8f506817f..72f91bff29c 100644
--- a/drivers/xen/events.c
+++ b/drivers/xen/events.c
@@ -29,6 +29,7 @@
#include <linux/bootmem.h>
#include <linux/slab.h>
+#include <asm/desc.h>
#include <asm/ptrace.h>
#include <asm/irq.h>
#include <asm/idle.h>
@@ -36,10 +37,14 @@
#include <asm/xen/hypercall.h>
#include <asm/xen/hypervisor.h>
+#include <xen/xen.h>
+#include <xen/hvm.h>
#include <xen/xen-ops.h>
#include <xen/events.h>
#include <xen/interface/xen.h>
#include <xen/interface/event_channel.h>
+#include <xen/interface/hvm/hvm_op.h>
+#include <xen/interface/hvm/params.h>
/*
* This lock protects updates to the following mapping and reference-count
@@ -335,9 +340,18 @@ static int find_unbound_irq(void)
int irq;
struct irq_desc *desc;
- for (irq = 0; irq < nr_irqs; irq++)
+ for (irq = 0; irq < nr_irqs; irq++) {
+ desc = irq_to_desc(irq);
+ /* only 0->15 have init'd desc; handle irq > 16 */
+ if (desc == NULL)
+ break;
+ if (desc->chip == &no_irq_chip)
+ break;
+ if (desc->chip != &xen_dynamic_chip)
+ continue;
if (irq_info[irq].type == IRQT_UNBOUND)
break;
+ }
if (irq == nr_irqs)
panic("No available IRQ to bind to: increase nr_irqs!\n");
@@ -346,7 +360,7 @@ static int find_unbound_irq(void)
if (WARN_ON(desc == NULL))
return -1;
- dynamic_irq_init(irq);
+ dynamic_irq_init_keep_chip_data(irq);
return irq;
}
@@ -536,6 +550,7 @@ int bind_ipi_to_irqhandler(enum ipi_vector ipi,
if (irq < 0)
return irq;
+ irqflags |= IRQF_NO_SUSPEND;
retval = request_irq(irq, handler, irqflags, devname, dev_id);
if (retval != 0) {
unbind_from_irq(irq);
@@ -617,17 +632,13 @@ static DEFINE_PER_CPU(unsigned, xed_nesting_count);
* a bitset of words which contain pending event bits. The second
* level is a bitset of pending events themselves.
*/
-void xen_evtchn_do_upcall(struct pt_regs *regs)
+static void __xen_evtchn_do_upcall(void)
{
int cpu = get_cpu();
- struct pt_regs *old_regs = set_irq_regs(regs);
struct shared_info *s = HYPERVISOR_shared_info;
struct vcpu_info *vcpu_info = __get_cpu_var(xen_vcpu);
unsigned count;
- exit_idle();
- irq_enter();
-
do {
unsigned long pending_words;
@@ -664,14 +675,31 @@ void xen_evtchn_do_upcall(struct pt_regs *regs)
count = __get_cpu_var(xed_nesting_count);
__get_cpu_var(xed_nesting_count) = 0;
- } while(count != 1);
+ } while (count != 1 || vcpu_info->evtchn_upcall_pending);
out:
+
+ put_cpu();
+}
+
+void xen_evtchn_do_upcall(struct pt_regs *regs)
+{
+ struct pt_regs *old_regs = set_irq_regs(regs);
+
+ exit_idle();
+ irq_enter();
+
+ __xen_evtchn_do_upcall();
+
irq_exit();
set_irq_regs(old_regs);
+}
- put_cpu();
+void xen_hvm_evtchn_do_upcall(void)
+{
+ __xen_evtchn_do_upcall();
}
+EXPORT_SYMBOL_GPL(xen_hvm_evtchn_do_upcall);
/* Rebind a new event channel to an existing irq. */
void rebind_evtchn_irq(int evtchn, int irq)
@@ -708,7 +736,10 @@ static int rebind_irq_to_cpu(unsigned irq, unsigned tcpu)
struct evtchn_bind_vcpu bind_vcpu;
int evtchn = evtchn_from_irq(irq);
- if (!VALID_EVTCHN(evtchn))
+ /* events delivered via platform PCI interrupts are always
+ * routed to vcpu 0 */
+ if (!VALID_EVTCHN(evtchn) ||
+ (xen_hvm_domain() && !xen_have_vector_callback))
return -1;
/* Send future instances of this interrupt to other vcpu. */
@@ -933,6 +964,44 @@ static struct irq_chip xen_dynamic_chip __read_mostly = {
.retrigger = retrigger_dynirq,
};
+int xen_set_callback_via(uint64_t via)
+{
+ struct xen_hvm_param a;
+ a.domid = DOMID_SELF;
+ a.index = HVM_PARAM_CALLBACK_IRQ;
+ a.value = via;
+ return HYPERVISOR_hvm_op(HVMOP_set_param, &a);
+}
+EXPORT_SYMBOL_GPL(xen_set_callback_via);
+
+#ifdef CONFIG_XEN_PVHVM
+/* Vector callbacks are better than PCI interrupts to receive event
+ * channel notifications because we can receive vector callbacks on any
+ * vcpu and we don't need PCI support or APIC interactions. */
+void xen_callback_vector(void)
+{
+ int rc;
+ uint64_t callback_via;
+ if (xen_have_vector_callback) {
+ callback_via = HVM_CALLBACK_VECTOR(XEN_HVM_EVTCHN_CALLBACK);
+ rc = xen_set_callback_via(callback_via);
+ if (rc) {
+ printk(KERN_ERR "Request for Xen HVM callback vector"
+ " failed.\n");
+ xen_have_vector_callback = 0;
+ return;
+ }
+ printk(KERN_INFO "Xen HVM callback vector for event delivery is "
+ "enabled\n");
+ /* in the restore case the vector has already been allocated */
+ if (!test_bit(XEN_HVM_EVTCHN_CALLBACK, used_vectors))
+ alloc_intr_gate(XEN_HVM_EVTCHN_CALLBACK, xen_hvm_callback_vector);
+ }
+}
+#else
+void xen_callback_vector(void) {}
+#endif
+
void __init xen_init_IRQ(void)
{
int i;
@@ -947,5 +1016,10 @@ void __init xen_init_IRQ(void)
for (i = 0; i < NR_EVENT_CHANNELS; i++)
mask_evtchn(i);
- irq_ctx_init(smp_processor_id());
+ if (xen_hvm_domain()) {
+ xen_callback_vector();
+ native_init_IRQ();
+ } else {
+ irq_ctx_init(smp_processor_id());
+ }
}
diff --git a/drivers/xen/grant-table.c b/drivers/xen/grant-table.c
index f66db3b91d6..6c453181649 100644
--- a/drivers/xen/grant-table.c
+++ b/drivers/xen/grant-table.c
@@ -37,11 +37,13 @@
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/uaccess.h>
+#include <linux/io.h>
#include <xen/xen.h>
#include <xen/interface/xen.h>
#include <xen/page.h>
#include <xen/grant_table.h>
+#include <xen/interface/memory.h>
#include <asm/xen/hypercall.h>
#include <asm/pgtable.h>
@@ -59,6 +61,8 @@ 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);
+unsigned long xen_hvm_resume_frames;
+EXPORT_SYMBOL_GPL(xen_hvm_resume_frames);
static struct grant_entry *shared;
@@ -433,7 +437,7 @@ static unsigned int __max_nr_grant_frames(void)
return query.max_nr_frames;
}
-static inline unsigned int max_nr_grant_frames(void)
+unsigned int gnttab_max_grant_frames(void)
{
unsigned int xen_max = __max_nr_grant_frames();
@@ -441,6 +445,7 @@ static inline unsigned int max_nr_grant_frames(void)
return boot_max_nr_grant_frames;
return xen_max;
}
+EXPORT_SYMBOL_GPL(gnttab_max_grant_frames);
static int gnttab_map(unsigned int start_idx, unsigned int end_idx)
{
@@ -449,6 +454,30 @@ static int gnttab_map(unsigned int start_idx, unsigned int end_idx)
unsigned int nr_gframes = end_idx + 1;
int rc;
+ if (xen_hvm_domain()) {
+ struct xen_add_to_physmap xatp;
+ unsigned int i = end_idx;
+ rc = 0;
+ /*
+ * Loop backwards, so that the first hypercall has the largest
+ * index, ensuring that the table will grow only once.
+ */
+ do {
+ xatp.domid = DOMID_SELF;
+ xatp.idx = i;
+ xatp.space = XENMAPSPACE_grant_table;
+ xatp.gpfn = (xen_hvm_resume_frames >> PAGE_SHIFT) + i;
+ rc = HYPERVISOR_memory_op(XENMEM_add_to_physmap, &xatp);
+ if (rc != 0) {
+ printk(KERN_WARNING
+ "grant table add_to_physmap failed, err=%d\n", rc);
+ break;
+ }
+ } while (i-- > start_idx);
+
+ return rc;
+ }
+
frames = kmalloc(nr_gframes * sizeof(unsigned long), GFP_ATOMIC);
if (!frames)
return -ENOMEM;
@@ -465,7 +494,7 @@ static int gnttab_map(unsigned int start_idx, unsigned int end_idx)
BUG_ON(rc || setup.status);
- rc = arch_gnttab_map_shared(frames, nr_gframes, max_nr_grant_frames(),
+ rc = arch_gnttab_map_shared(frames, nr_gframes, gnttab_max_grant_frames(),
&shared);
BUG_ON(rc);
@@ -476,9 +505,27 @@ static int gnttab_map(unsigned int start_idx, unsigned int end_idx)
int gnttab_resume(void)
{
- if (max_nr_grant_frames() < nr_grant_frames)
+ unsigned int max_nr_gframes;
+
+ max_nr_gframes = gnttab_max_grant_frames();
+ if (max_nr_gframes < nr_grant_frames)
return -ENOSYS;
- return gnttab_map(0, nr_grant_frames - 1);
+
+ if (xen_pv_domain())
+ return gnttab_map(0, nr_grant_frames - 1);
+
+ if (!shared) {
+ shared = ioremap(xen_hvm_resume_frames, PAGE_SIZE * max_nr_gframes);
+ if (shared == NULL) {
+ printk(KERN_WARNING
+ "Failed to ioremap gnttab share frames!");
+ return -ENOMEM;
+ }
+ }
+
+ gnttab_map(0, nr_grant_frames - 1);
+
+ return 0;
}
int gnttab_suspend(void)
@@ -495,7 +542,7 @@ static int gnttab_expand(unsigned int req_entries)
cur = nr_grant_frames;
extra = ((req_entries + (GREFS_PER_GRANT_FRAME-1)) /
GREFS_PER_GRANT_FRAME);
- if (cur + extra > max_nr_grant_frames())
+ if (cur + extra > gnttab_max_grant_frames())
return -ENOSPC;
rc = gnttab_map(cur, cur + extra - 1);
@@ -505,15 +552,12 @@ static int gnttab_expand(unsigned int req_entries)
return rc;
}
-static int __devinit gnttab_init(void)
+int gnttab_init(void)
{
int i;
unsigned int max_nr_glist_frames, nr_glist_frames;
unsigned int nr_init_grefs;
- if (!xen_domain())
- return -ENODEV;
-
nr_grant_frames = 1;
boot_max_nr_grant_frames = __max_nr_grant_frames();
@@ -556,5 +600,18 @@ static int __devinit gnttab_init(void)
kfree(gnttab_list);
return -ENOMEM;
}
+EXPORT_SYMBOL_GPL(gnttab_init);
+
+static int __devinit __gnttab_init(void)
+{
+ /* Delay grant-table initialization in the PV on HVM case */
+ if (xen_hvm_domain())
+ return 0;
+
+ if (!xen_pv_domain())
+ return -ENODEV;
+
+ return gnttab_init();
+}
-core_initcall(gnttab_init);
+core_initcall(__gnttab_init);
diff --git a/drivers/xen/manage.c b/drivers/xen/manage.c
index 07e857b0de1..1799bd89031 100644
--- a/drivers/xen/manage.c
+++ b/drivers/xen/manage.c
@@ -9,6 +9,7 @@
#include <linux/stop_machine.h>
#include <linux/freezer.h>
+#include <xen/xen.h>
#include <xen/xenbus.h>
#include <xen/grant_table.h>
#include <xen/events.h>
@@ -17,6 +18,7 @@
#include <asm/xen/hypercall.h>
#include <asm/xen/page.h>
+#include <asm/xen/hypervisor.h>
enum shutdown_state {
SHUTDOWN_INVALID = -1,
@@ -33,10 +35,30 @@ enum shutdown_state {
static enum shutdown_state shutting_down = SHUTDOWN_INVALID;
#ifdef CONFIG_PM_SLEEP
-static int xen_suspend(void *data)
+static int xen_hvm_suspend(void *data)
{
+ struct sched_shutdown r = { .reason = SHUTDOWN_suspend };
int *cancelled = data;
+
+ BUG_ON(!irqs_disabled());
+
+ *cancelled = HYPERVISOR_sched_op(SCHEDOP_shutdown, &r);
+
+ xen_hvm_post_suspend(*cancelled);
+ gnttab_resume();
+
+ if (!*cancelled) {
+ xen_irq_resume();
+ xen_timer_resume();
+ }
+
+ return 0;
+}
+
+static int xen_suspend(void *data)
+{
int err;
+ int *cancelled = data;
BUG_ON(!irqs_disabled());
@@ -106,7 +128,10 @@ static void do_suspend(void)
goto out_resume;
}
- err = stop_machine(xen_suspend, &cancelled, cpumask_of(0));
+ if (xen_hvm_domain())
+ err = stop_machine(xen_hvm_suspend, &cancelled, cpumask_of(0));
+ else
+ err = stop_machine(xen_suspend, &cancelled, cpumask_of(0));
dpm_resume_noirq(PMSG_RESUME);
@@ -255,7 +280,19 @@ static int shutdown_event(struct notifier_block *notifier,
return NOTIFY_DONE;
}
-static int __init setup_shutdown_event(void)
+static int __init __setup_shutdown_event(void)
+{
+ /* Delay initialization in the PV on HVM case */
+ if (xen_hvm_domain())
+ return 0;
+
+ if (!xen_pv_domain())
+ return -ENODEV;
+
+ return xen_setup_shutdown_event();
+}
+
+int xen_setup_shutdown_event(void)
{
static struct notifier_block xenstore_notifier = {
.notifier_call = shutdown_event
@@ -264,5 +301,6 @@ static int __init setup_shutdown_event(void)
return 0;
}
+EXPORT_SYMBOL_GPL(xen_setup_shutdown_event);
-subsys_initcall(setup_shutdown_event);
+subsys_initcall(__setup_shutdown_event);
diff --git a/drivers/xen/platform-pci.c b/drivers/xen/platform-pci.c
new file mode 100644
index 00000000000..c01b5ddce52
--- /dev/null
+++ b/drivers/xen/platform-pci.c
@@ -0,0 +1,207 @@
+/******************************************************************************
+ * platform-pci.c
+ *
+ * Xen platform PCI device driver
+ * Copyright (c) 2005, Intel Corporation.
+ * Copyright (c) 2007, XenSource Inc.
+ * Copyright (c) 2010, Citrix
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place - Suite 330, Boston, MA 02111-1307 USA.
+ *
+ */
+
+
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+
+#include <xen/platform_pci.h>
+#include <xen/grant_table.h>
+#include <xen/xenbus.h>
+#include <xen/events.h>
+#include <xen/hvm.h>
+#include <xen/xen-ops.h>
+
+#define DRV_NAME "xen-platform-pci"
+
+MODULE_AUTHOR("ssmith@xensource.com and stefano.stabellini@eu.citrix.com");
+MODULE_DESCRIPTION("Xen platform PCI device");
+MODULE_LICENSE("GPL");
+
+static unsigned long platform_mmio;
+static unsigned long platform_mmio_alloc;
+static unsigned long platform_mmiolen;
+static uint64_t callback_via;
+
+unsigned long alloc_xen_mmio(unsigned long len)
+{
+ unsigned long addr;
+
+ addr = platform_mmio + platform_mmio_alloc;
+ platform_mmio_alloc += len;
+ BUG_ON(platform_mmio_alloc > platform_mmiolen);
+
+ return addr;
+}
+
+static uint64_t get_callback_via(struct pci_dev *pdev)
+{
+ u8 pin;
+ int irq;
+
+ irq = pdev->irq;
+ if (irq < 16)
+ return irq; /* ISA IRQ */
+
+ pin = pdev->pin;
+
+ /* We don't know the GSI. Specify the PCI INTx line instead. */
+ return ((uint64_t)0x01 << 56) | /* PCI INTx identifier */
+ ((uint64_t)pci_domain_nr(pdev->bus) << 32) |
+ ((uint64_t)pdev->bus->number << 16) |
+ ((uint64_t)(pdev->devfn & 0xff) << 8) |
+ ((uint64_t)(pin - 1) & 3);
+}
+
+static irqreturn_t do_hvm_evtchn_intr(int irq, void *dev_id)
+{
+ xen_hvm_evtchn_do_upcall();
+ return IRQ_HANDLED;
+}
+
+static int xen_allocate_irq(struct pci_dev *pdev)
+{
+ return request_irq(pdev->irq, do_hvm_evtchn_intr,
+ IRQF_DISABLED | IRQF_NOBALANCING | IRQF_TRIGGER_RISING,
+ "xen-platform-pci", pdev);
+}
+
+static int platform_pci_resume(struct pci_dev *pdev)
+{
+ int err;
+ if (xen_have_vector_callback)
+ return 0;
+ err = xen_set_callback_via(callback_via);
+ if (err) {
+ dev_err(&pdev->dev, "platform_pci_resume failure!\n");
+ return err;
+ }
+ return 0;
+}
+
+static int __devinit platform_pci_init(struct pci_dev *pdev,
+ const struct pci_device_id *ent)
+{
+ int i, ret;
+ long ioaddr, iolen;
+ long mmio_addr, mmio_len;
+ unsigned int max_nr_gframes;
+
+ i = pci_enable_device(pdev);
+ if (i)
+ return i;
+
+ ioaddr = pci_resource_start(pdev, 0);
+ iolen = pci_resource_len(pdev, 0);
+
+ mmio_addr = pci_resource_start(pdev, 1);
+ mmio_len = pci_resource_len(pdev, 1);
+
+ if (mmio_addr == 0 || ioaddr == 0) {
+ dev_err(&pdev->dev, "no resources found\n");
+ ret = -ENOENT;
+ goto pci_out;
+ }
+
+ if (request_mem_region(mmio_addr, mmio_len, DRV_NAME) == NULL) {
+ dev_err(&pdev->dev, "MEM I/O resource 0x%lx @ 0x%lx busy\n",
+ mmio_addr, mmio_len);
+ ret = -EBUSY;
+ goto pci_out;
+ }
+
+ if (request_region(ioaddr, iolen, DRV_NAME) == NULL) {
+ dev_err(&pdev->dev, "I/O resource 0x%lx @ 0x%lx busy\n",
+ iolen, ioaddr);
+ ret = -EBUSY;
+ goto mem_out;
+ }
+
+ platform_mmio = mmio_addr;
+ platform_mmiolen = mmio_len;
+
+ if (!xen_have_vector_callback) {
+ ret = xen_allocate_irq(pdev);
+ if (ret) {
+ dev_warn(&pdev->dev, "request_irq failed err=%d\n", ret);
+ goto out;
+ }
+ callback_via = get_callback_via(pdev);
+ ret = xen_set_callback_via(callback_via);
+ if (ret) {
+ dev_warn(&pdev->dev, "Unable to set the evtchn callback "
+ "err=%d\n", ret);
+ goto out;
+ }
+ }
+
+ max_nr_gframes = gnttab_max_grant_frames();
+ xen_hvm_resume_frames = alloc_xen_mmio(PAGE_SIZE * max_nr_gframes);
+ ret = gnttab_init();
+ if (ret)
+ goto out;
+ xenbus_probe(NULL);
+ ret = xen_setup_shutdown_event();
+ if (ret)
+ goto out;
+ return 0;
+
+out:
+ release_region(ioaddr, iolen);
+mem_out:
+ release_mem_region(mmio_addr, mmio_len);
+pci_out:
+ pci_disable_device(pdev);
+ return ret;
+}
+
+static struct pci_device_id platform_pci_tbl[] __devinitdata = {
+ {PCI_VENDOR_ID_XEN, PCI_DEVICE_ID_XEN_PLATFORM,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ {0,}
+};
+
+MODULE_DEVICE_TABLE(pci, platform_pci_tbl);
+
+static struct pci_driver platform_driver = {
+ .name = DRV_NAME,
+ .probe = platform_pci_init,
+ .id_table = platform_pci_tbl,
+#ifdef CONFIG_PM
+ .resume_early = platform_pci_resume,
+#endif
+};
+
+static int __init platform_pci_module_init(void)
+{
+ /* no unplug has been done, IGNORE hasn't been specified: just
+ * return now */
+ if (!xen_platform_pci_unplug)
+ return -ENODEV;
+
+ return pci_register_driver(&platform_driver);
+}
+
+module_init(platform_pci_module_init);
diff --git a/drivers/xen/xenbus/xenbus_probe.c b/drivers/xen/xenbus/xenbus_probe.c
index 3479332113e..29bac511887 100644
--- a/drivers/xen/xenbus/xenbus_probe.c
+++ b/drivers/xen/xenbus/xenbus_probe.c
@@ -56,6 +56,9 @@
#include <xen/events.h>
#include <xen/page.h>
+#include <xen/platform_pci.h>
+#include <xen/hvm.h>
+
#include "xenbus_comms.h"
#include "xenbus_probe.h"
@@ -752,10 +755,7 @@ 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);
+ blocking_notifier_chain_register(&xenstore_chain, nb);
return ret;
}
@@ -779,8 +779,23 @@ void xenbus_probe(struct work_struct *unused)
/* Notify others that xenstore is up */
blocking_notifier_call_chain(&xenstore_chain, 0, NULL);
}
+EXPORT_SYMBOL_GPL(xenbus_probe);
+
+static int __init xenbus_probe_initcall(void)
+{
+ if (!xen_domain())
+ return -ENODEV;
+
+ if (xen_initial_domain() || xen_hvm_domain())
+ return 0;
+
+ xenbus_probe(NULL);
+ return 0;
+}
+
+device_initcall(xenbus_probe_initcall);
-static int __init xenbus_probe_init(void)
+static int __init xenbus_init(void)
{
int err = 0;
@@ -805,11 +820,24 @@ static int __init xenbus_probe_init(void)
if (xen_initial_domain()) {
/* dom0 not yet supported */
} else {
+ if (xen_hvm_domain()) {
+ uint64_t v = 0;
+ err = hvm_get_parameter(HVM_PARAM_STORE_EVTCHN, &v);
+ if (err)
+ goto out_error;
+ xen_store_evtchn = (int)v;
+ err = hvm_get_parameter(HVM_PARAM_STORE_PFN, &v);
+ if (err)
+ goto out_error;
+ xen_store_mfn = (unsigned long)v;
+ xen_store_interface = ioremap(xen_store_mfn << PAGE_SHIFT, PAGE_SIZE);
+ } else {
+ 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);
+ }
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();
@@ -819,9 +847,6 @@ static int __init xenbus_probe_init(void)
goto out_unreg_back;
}
- if (!xen_initial_domain())
- xenbus_probe(NULL);
-
#ifdef CONFIG_XEN_COMPAT_XENFS
/*
* Create xenfs mountpoint in /proc for compatibility with
@@ -842,7 +867,7 @@ static int __init xenbus_probe_init(void)
return err;
}
-postcore_initcall(xenbus_probe_init);
+postcore_initcall(xenbus_init);
MODULE_LICENSE("GPL");
@@ -950,6 +975,9 @@ static void wait_for_devices(struct xenbus_driver *xendrv)
#ifndef MODULE
static int __init boot_wait_for_devices(void)
{
+ if (xen_hvm_domain() && !xen_platform_pci_unplug)
+ return -ENODEV;
+
ready_to_wait_for_devices = 1;
wait_for_devices(NULL);
return 0;
diff --git a/drivers/xen/xenbus/xenbus_xs.c b/drivers/xen/xenbus/xenbus_xs.c
index 7b547f53f65..5534690075a 100644
--- a/drivers/xen/xenbus/xenbus_xs.c
+++ b/drivers/xen/xenbus/xenbus_xs.c
@@ -76,6 +76,14 @@ struct xs_handle {
/*
* Mutex ordering: transaction_mutex -> watch_mutex -> request_mutex.
* response_mutex is never taken simultaneously with the other three.
+ *
+ * transaction_mutex must be held before incrementing
+ * transaction_count. The mutex is held when a suspend is in
+ * progress to prevent new transactions starting.
+ *
+ * When decrementing transaction_count to zero the wait queue
+ * should be woken up, the suspend code waits for count to
+ * reach zero.
*/
/* One request at a time. */
@@ -85,7 +93,9 @@ struct xs_handle {
struct mutex response_mutex;
/* Protect transactions against save/restore. */
- struct rw_semaphore transaction_mutex;
+ struct mutex transaction_mutex;
+ atomic_t transaction_count;
+ wait_queue_head_t transaction_wq;
/* Protect watch (de)register against save/restore. */
struct rw_semaphore watch_mutex;
@@ -157,6 +167,31 @@ static void *read_reply(enum xsd_sockmsg_type *type, unsigned int *len)
return body;
}
+static void transaction_start(void)
+{
+ mutex_lock(&xs_state.transaction_mutex);
+ atomic_inc(&xs_state.transaction_count);
+ mutex_unlock(&xs_state.transaction_mutex);
+}
+
+static void transaction_end(void)
+{
+ if (atomic_dec_and_test(&xs_state.transaction_count))
+ wake_up(&xs_state.transaction_wq);
+}
+
+static void transaction_suspend(void)
+{
+ mutex_lock(&xs_state.transaction_mutex);
+ wait_event(xs_state.transaction_wq,
+ atomic_read(&xs_state.transaction_count) == 0);
+}
+
+static void transaction_resume(void)
+{
+ mutex_unlock(&xs_state.transaction_mutex);
+}
+
void *xenbus_dev_request_and_reply(struct xsd_sockmsg *msg)
{
void *ret;
@@ -164,7 +199,7 @@ void *xenbus_dev_request_and_reply(struct xsd_sockmsg *msg)
int err;
if (req_msg.type == XS_TRANSACTION_START)
- down_read(&xs_state.transaction_mutex);
+ transaction_start();
mutex_lock(&xs_state.request_mutex);
@@ -180,7 +215,7 @@ void *xenbus_dev_request_and_reply(struct xsd_sockmsg *msg)
if ((msg->type == XS_TRANSACTION_END) ||
((req_msg.type == XS_TRANSACTION_START) &&
(msg->type == XS_ERROR)))
- up_read(&xs_state.transaction_mutex);
+ transaction_end();
return ret;
}
@@ -432,11 +467,11 @@ int xenbus_transaction_start(struct xenbus_transaction *t)
{
char *id_str;
- down_read(&xs_state.transaction_mutex);
+ transaction_start();
id_str = xs_single(XBT_NIL, XS_TRANSACTION_START, "", NULL);
if (IS_ERR(id_str)) {
- up_read(&xs_state.transaction_mutex);
+ transaction_end();
return PTR_ERR(id_str);
}
@@ -461,7 +496,7 @@ int xenbus_transaction_end(struct xenbus_transaction t, int abort)
err = xs_error(xs_single(t, XS_TRANSACTION_END, abortstr, NULL));
- up_read(&xs_state.transaction_mutex);
+ transaction_end();
return err;
}
@@ -662,7 +697,7 @@ EXPORT_SYMBOL_GPL(unregister_xenbus_watch);
void xs_suspend(void)
{
- down_write(&xs_state.transaction_mutex);
+ transaction_suspend();
down_write(&xs_state.watch_mutex);
mutex_lock(&xs_state.request_mutex);
mutex_lock(&xs_state.response_mutex);
@@ -677,7 +712,7 @@ void xs_resume(void)
mutex_unlock(&xs_state.response_mutex);
mutex_unlock(&xs_state.request_mutex);
- up_write(&xs_state.transaction_mutex);
+ transaction_resume();
/* No need for watches_lock: the watch_mutex is sufficient. */
list_for_each_entry(watch, &watches, list) {
@@ -693,7 +728,7 @@ 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);
+ mutex_unlock(&xs_state.transaction_mutex);
}
static int xenwatch_thread(void *unused)
@@ -843,8 +878,10 @@ int xs_init(void)
mutex_init(&xs_state.request_mutex);
mutex_init(&xs_state.response_mutex);
- init_rwsem(&xs_state.transaction_mutex);
+ mutex_init(&xs_state.transaction_mutex);
init_rwsem(&xs_state.watch_mutex);
+ atomic_set(&xs_state.transaction_count, 0);
+ init_waitqueue_head(&xs_state.transaction_wq);
/* Initialize the shared memory rings to talk to xenstored */
err = xb_init_comms();
diff --git a/drivers/xen/xenfs/super.c b/drivers/xen/xenfs/super.c
index 8924d93136f..78bfab0700b 100644
--- a/drivers/xen/xenfs/super.c
+++ b/drivers/xen/xenfs/super.c
@@ -65,7 +65,7 @@ static struct file_system_type xenfs_type = {
static int __init xenfs_init(void)
{
- if (xen_pv_domain())
+ if (xen_domain())
return register_filesystem(&xenfs_type);
printk(KERN_INFO "XENFS: not registering filesystem on non-xen platform\n");
@@ -74,7 +74,7 @@ static int __init xenfs_init(void)
static void __exit xenfs_exit(void)
{
- if (xen_pv_domain())
+ if (xen_domain())
unregister_filesystem(&xenfs_type);
}
diff --git a/drivers/xen/xenfs/xenbus.c b/drivers/xen/xenfs/xenbus.c
index f28ece39736..3b39c3752e2 100644
--- a/drivers/xen/xenfs/xenbus.c
+++ b/drivers/xen/xenfs/xenbus.c
@@ -124,6 +124,9 @@ static ssize_t xenbus_file_read(struct file *filp,
mutex_lock(&u->reply_mutex);
while (list_empty(&u->read_buffers)) {
mutex_unlock(&u->reply_mutex);
+ if (filp->f_flags & O_NONBLOCK)
+ return -EAGAIN;
+
ret = wait_event_interruptible(u->read_waitq,
!list_empty(&u->read_buffers));
if (ret)
diff --git a/firmware/Makefile b/firmware/Makefile
index 020e629a615..b27f09f05d1 100644
--- a/firmware/Makefile
+++ b/firmware/Makefile
@@ -42,7 +42,7 @@ fw-shipped-$(CONFIG_CASSINI) += sun/cassini.bin
fw-shipped-$(CONFIG_COMPUTONE) += intelliport2.bin
fw-shipped-$(CONFIG_CHELSIO_T3) += cxgb3/t3b_psram-1.1.0.bin \
cxgb3/t3c_psram-1.1.0.bin \
- cxgb3/t3fw-7.4.0.bin \
+ cxgb3/t3fw-7.10.0.bin \
cxgb3/ael2005_opt_edc.bin \
cxgb3/ael2005_twx_edc.bin \
cxgb3/ael2020_twx_edc.bin
diff --git a/firmware/cxgb3/t3fw-7.10.0.bin.ihex b/firmware/cxgb3/t3fw-7.10.0.bin.ihex
new file mode 100644
index 00000000000..96399d87bd3
--- /dev/null
+++ b/firmware/cxgb3/t3fw-7.10.0.bin.ihex
@@ -0,0 +1,1935 @@
+:1000000060007400200380002003700000001000D6
+:1000100000002000E100028400070000E1000288E7
+:1000200000010000E0000000E00000A0010000006E
+:1000300044444440E3000183200200002001E0002A
+:100040002001FF101FFFD0001FFFC000E300043C91
+:100050000200000020006C841FFFC2A020006CCCB6
+:100060001FFFC2A420006D0C1FFFC2A820006D80DE
+:100070001FFFC2AC200003C0C00000E43100EA3121
+:1000800000A13100A03103020002ED306E2A05000C
+:10009000ED3100020002160012FFDBC03014FFDA5F
+:1000A000D30FD30FD30F03431F244C107249F0D347
+:1000B0000FD30FD30F12FFD5230A00240A00D30F4A
+:1000C000D30FD30F03431F244C107249F0D30FD327
+:1000D0000FD30F14FFCE03421F14FFCB03421F1296
+:1000E000FFCCC0302D37302D37342D37382D373CED
+:1000F000233D017233ED00020012FFC4C0302F37E0
+:10010000002F37102F37202F3730233D017233ED6A
+:1001100000020012FFBEC0302737002737102737F4
+:1001200020273730233D017233ED03020012FFB95F
+:1001300013FFBA0C0200932012FFB913FFB90C028F
+:1001400000932012FFB8C0319320822012FFB71312
+:10015000FFB7932012FFB715FFB316FFB6C030D715
+:100160002005660160001B00000000000000000088
+:10017000043605000200D30FD30F05330C6E3B1479
+:100180000747140704437631E604360505330C6F40
+:100190003BED00020012FFA615FFA3230A00D720A3
+:1001A000070443043E0505330C0747146F3BF00377
+:1001B000020012FFA1C03014FFA1D30FD30FD30F41
+:1001C0009340B4447249F2D30FD30FD30F14FF9B63
+:1001D000834014FF9B834012FF9B230A0014FF9A65
+:1001E000D30FD30FD30F9340B4447249F2D30FD33C
+:1001F0000FD30F14FF95834012FF95C92F832084DE
+:10020000218522BC22743B0F8650B4559630B433FE
+:100210007433F463FFE60000653FE1655FDE12FFC3
+:100220007C230A0028374028374428374828374C91
+:10023000233D017233ED03020000020012FF7AC079
+:1002400032032E0503020012FF7813FF819320C0B2
+:1002500011014931004831010200C00014FF7E0441
+:10026000D23115FF7D945014FF7D04D33115FF7CEE
+:10027000945014FF7C04D43115FF7C24560014FFE5
+:100280007B04D53115FF7B24560010FF7A03000054
+:10029000000000000000000000000000000000005E
+:1002A000000000000000000000000000000000004E
+:1002B000000000000000000000000000000000003E
+:1002C000000000000000000000000000000000002E
+:1002D000000000000000000000000000000000001E
+:1002E000000000000000000000000000000000000E
+:1002F00000000000000000000000000000000000FE
+:1003000000000000000000000000000000000000ED
+:1003100000000000000000000000000000000000DD
+:1003200000000000000000000000000000000000CD
+:1003300000000000000000000000000000000000BD
+:1003400000000000000000000000000000000000AD
+:10035000000000000000000000000000000000009D
+:10036000000000000000000000000000000000008D
+:10037000000000000000000000000000000000007D
+:10038000000000000000000000000000000000006D
+:10039000000000000000000000000000000000005D
+:1003A000000000000000000000000000000000004D
+:1003B000000000000000000000000000000000003D
+:1003C000000000000000000000000000000000002D
+:1003D000000000000000000000000000000000001D
+:1003E000000000000000000000000000000000000D
+:1003F00000000000000000000000000000000000FD
+:1004000000000000000000000000000000000000EC
+:1004100000000000000000000000000000000000DC
+:1004200063FFFC000000000000000000000000006E
+:100430000000000000000000000000001FFC0000A1
+:100440001FFC0000E30005C81FFC00001FFC0000AB
+:10045000E30005C81FFC00001FFC0000E30005C806
+:100460001FFFC0001FFFC000E30005C81FFFC00042
+:100470001FFFC018E30005C81FFFC0181FFFC018EA
+:10048000E30005E01FFFC0181FFFC294E30005E072
+:100490001FFFC2941FFFC294E300085C1FFFC2A0AD
+:1004A0001FFFC59CE300085C200000002000016ADB
+:1004B000E3000B582000018020000180E3000CC401
+:1004C0002000020020000203E3000CC42000021CF4
+:1004D00020000220E3000CC8200002202000022699
+:1004E000E3000CCC2000023C20000240E3000CD4CE
+:1004F0002000024020000249E3000CD82000024CFA
+:1005000020000250E3000CE42000025020000259B9
+:10051000E3000CE82000025C20000260E3000CF421
+:100520002000026020000269E3000CF82000026C49
+:1005300020000270E3000D04200002702000027908
+:10054000E3000D082000028C2000028CE3000D1453
+:100550002000029020000293E3000D14200002AC62
+:10056000200002B0E3000D18200002D0200002F2AB
+:10057000E3000D1C200003B0200003B0E3000D4099
+:10058000200003B0200003B0E3000D40200003B0C2
+:10059000200003B0E3000D40200003B0200003B0B2
+:1005A000E3000D40200003B020006EA4E3000D40E6
+:1005B00020006EA420006EA4E30078340000000048
+:1005C00000000000000000001FFC00001FFC0000F5
+:1005D0001FFFC5A01FFFC69020006EA820006EA8B8
+:1005E000DEFFFE000000080CDEADBEEF1FFFC2B054
+:1005F0001FFCFE001FFFC0A41FFFC5D0300000007D
+:10060000003FFFFF8040000010000000080FFFFFC8
+:100610001FFFC27D000FFFFF804FFFFF8000000023
+:1006200000000880B000000560500000600000007D
+:1006300040000011350000004100000010000001E2
+:100640002000000000001000400000000500000035
+:10065000800000190400000000000800E100020012
+:1006600010000005806000007000000020000009FC
+:10067000001FF8008000001EA0000000F80000002D
+:1006800007FFFFFF080000001800000001008001C4
+:10069000420000001FFFC22D1FFFC0EC00010080C0
+:1006A000604000001A0000000C0000001000000A6A
+:1006B000000030000001000080000018FC00000075
+:1006C0008000000100004000600008008000001C65
+:1006D0008000001A030000008000040004030403EB
+:1006E00050000003FFFFBFFF1FFFC3E400000FFF28
+:1006F000FFFFF000000016D00000FFF7A50000008B
+:100700001FFFC4C01FFFC4710001000800000B20C0
+:10071000202FFF801FFFC46500002C00FFFEFFF8A4
+:1007200000FFFFFF1FFFC58800002000FFFFDFFF65
+:100730000000FFEF010011001FFFC3E21FFFC5A073
+:10074000FFFFEFFF0000FFFB1FFFC6501FFFBEB003
+:10075000FFFFF7FF1FFFC0740000FFFD1FFFC64033
+:100760000001FBD01FFFC5C01FFFC6801FFFC5A132
+:10077000E0FFFE001FFFC5B0000080001FFFC54C5A
+:100780001FFFC5C41FFFC0781FFFC4E41FFCFFD8B4
+:10079000000100817FFFFFFFE1000600000027103D
+:1007A0001FFCFE301FFCFE701FFFC5481FFFC56009
+:1007B0000003D0901FFFC5742B5063802B507980AD
+:1007C0002B5090802B50A6801FFFC4790100110F81
+:1007D000202FFE0020300080202FFF000000FFFFB0
+:1007E0000001FFF82B50B2002B50B208000100109E
+:1007F0002B50B1802B50B2802B50BA000001001159
+:100800002B50BD282B50BC802B50BDA020300000A9
+:10081000DFFFFE005000000200C0000002000000E8
+:10082000FFFFF7F41FFFC07C000FF800044000003A
+:10083000001000000C4000001C400000E00000A080
+:100840001FFFC5501FFD00081FFFC5641FFFC578AF
+:100850001FFFC58CE1000690E10006EC00000000DF
+:100860000000000000000000000000000100000087
+:100870000000000000000000000000002010004008
+:10088000201000402010004020140080200C0000A8
+:10089000200C0000200C00002010004020140080DC
+:1008A0002014008020140080201800C0201C0100AB
+:1008B000201C0100201C010020200140201800C045
+:1008C000201800C0201800C0201C0100201800C003
+:1008D000201800C0201800C0201C0100202001406A
+:1008E00020200140202001402020094020200940F4
+:1008F000202009402020094020240980FFFFFFFF1D
+:10090000FFFFFFFFFFFFFFFF0000000000000000EF
+:1009100000000000000000000000000020005588DA
+:1009200020005458200055882000558820005394FA
+:100930002000539420005394200051D4200051D41F
+:10094000200051CC2000513820004FE020004DC045
+:1009500020004B94000000000000000020005558CB
+:1009600020005424200054C8200054C82000527C89
+:100970002000527C2000527C2000527C2000527CBF
+:10098000200051C42000527C20004F0020004D70F8
+:1009900020004B40000000000000000020000BF091
+:1009A00020003ADC200004C02000473020000BE883
+:1009B000200041F4200003F0200046F020004B1CF2
+:1009C00020003F0020003E1C20003A58200038E85C
+:1009D00020003658200031B820003C7820002DD06F
+:1009E0002000286420006828200023F0200020D068
+:1009F0002000207C20001D68200018602000158841
+:100A000020000E5420000C3420001134200013204C
+:100A1000200043EC20003EB420000BF8200004C06E
+:100A200000000000000000000000000000000000C6
+:100A300000000000000000000000000000000000B6
+:100A400000000000000000000000000000000000A6
+:100A50000000000000000000000000000000000096
+:100A60000000000000000000000000000000000086
+:100A70000000000000000000000000000000000076
+:100A80000000000000000000000000000000000066
+:100A90000000000000000000000000000000000056
+:100AA0003264000000000000326400006400640052
+:100AB00064006400640064006400640000000000DE
+:100AC0000000000000000000000000000000000026
+:100AD0000000000000000000000000000000000016
+:100AE0000000000000000000000000000000000006
+:100AF00000000000000000000000000000000000F6
+:100B000000000000000010000000000000000000D5
+:100B100000000000000000000000000000001000C5
+:100B200000000000000000000000000000000000C5
+:100B300000432380000000000000000000000000CF
+:100B400000000000000000000000000000000000A5
+:100B50000000000000000000005C94015D94025E53
+:100B600094035F94004300000000000000000000B8
+:100B70000000000000000000000000000000000075
+:100B80000000000000000000000000000000000065
+:100B90000000000000000000005C90015D90025E1B
+:100BA00090035F9000530000000000000000000070
+:100BB0000000000000000000000000000000000035
+:100BC0000000000000000000000000000000000025
+:100BD0000000000000000000009C94001D90019D9A
+:100BE00094029E94039F94040894050994060A9421
+:100BF000070B94004300000000000000000000000C
+:100C000000000000000000000000000000000000E4
+:100C10000000000000000000009C90019D90029EDA
+:100C200090071D90039F90047890057990067A9024
+:100C3000077B90005300000000000000000000004F
+:100C400000000000000000000000000000000000A4
+:100C5000000000000000000000DC94001D9001DD99
+:100C60009402DE9403DF940404940505940606942C
+:100C70000707940808940909940A0A940B0B940036
+:100C80004300000000000000000000000000000021
+:100C9000000000000000000000DC9001DD9002DE9A
+:100CA000900B1D9003DF9004B49005B59006B690AC
+:100CB00007B79008B89009B9900ABA900BBB90009A
+:100CC0005300000063FFFC0020006C6010FFFF0A6F
+:100CD0000000000020006C8400D23110FFFE0A00EA
+:100CE0000000000020006CCC00D33110FFFE0A0091
+:100CF0000000000020006D0C00D43110FFFE0A003F
+:100D00000000000020006D8000D53110FFFE0A00B9
+:100D10000000000063FFFC00E00000A012FFF7826B
+:100D200020028257C82163FFFC12FFF303E830045E
+:100D3000EE3005C03093209421952263FFFC000023
+:100D40001FFFD000000400201FFFC5A01FFFC6909A
+:100D5000200A0011FFFB13FFFB03E631010200161E
+:100D6000FFFA17FFFAD30F776B069060B4667763CC
+:100D7000F85415F3541AA50F140063FFF90000008E
+:100D80006C1004C020D10F006C1004C0C71AEF060D
+:100D9000D830BC2BD72085720D4211837105450BCD
+:100DA000957202330C2376017B3B04233D0893713B
+:100DB000A32D12EEFE19EEFEA2767D632C2E0A0004
+:100DC000088202280A01038E380E0E42C8EE29A6B8
+:100DD0007E6D4A0500208800308C8271D10FC0F0F2
+:100DE000028F387FC0EA63FFE400C0F1C050037E89
+:100DF0000CA2EE0E3D1208820203F538050542CB27
+:100E00005729A67E2FDC100F4F366DFA050020887B
+:100E100000308CBC75C03008E208280A0105833810
+:100E2000030342C93E29A67E0D480CD30F6D8A05E7
+:100E300000208800B08C8271D10FC05008F5387541
+:100E4000C0C163FFBBC06002863876C0DA63FFD4DE
+:100E50006C101216EED8C1F9C1E8C1C72B221E28AA
+:100E6000221DC0D07B81352920060BB702299CFAB0
+:100E7000655008282072288CFF2824726491642A07
+:100E8000B0000CA80C64816F0EA90C6492BB7FA10A
+:100E90003FC1CE7CA13669AC336000370029200603
+:100EA000D7D0299CFACC57282072288CFF2824728E
+:100EB0006491392AD0000CA80C6481680EA90C64D6
+:100EC000931F7FA10BC1CE7CA10268AC06C020D1CC
+:100ED0000F2D25028A32C0900A6E5065E5B529248F
+:100EE00067090F4765F5B12C200C1FEEB30CCE112E
+:100EF000AFEE29E286B44879830260058219EEAF2D
+:100F000009C90A2992A36890078F2009FF0C65F58B
+:100F10006E2FE28564F56865559628221D7B810554
+:100F2000D9B060000200C0908B9417EEA50B881416
+:100F300087740B0B47A87718EEA309BB100877023C
+:100F400097F018EEA117EEA208A8010B8802074738
+:100F5000021BEE9E97F10B880298F22790232B90AC
+:100F60002204781006BB1007471208BB0228902104
+:100F70000777100C88100788020B880217EE968BF3
+:100F80003307BB0187340B880298F3979997F48B4A
+:100F90009587399BF588968B3898F688979BF897B4
+:100FA000F998F717EE8D28E28507C7082D74CF084A
+:100FB000480B28E68565550F2B221E28221D7B89AC
+:100FC000022B0A0064BF052CB00728B000DA200607
+:100FD000880A28824CC0D10B8000DBA065AFE76394
+:100FE000FEEA0000292072659E946004E72A2072C0
+:100FF00065AEBF6004DE00002EB0032C2067D4E095
+:1010000065C1058A328C330AFF500C4554BC5564C7
+:10101000F4EB19EE72882A09A90109880C64821F71
+:10102000C0926000DD2ED0032A2067D4E065A0D8EE
+:101030008A328B330AFC500B4554BC5564C4BE192C
+:10104000EE67882A09A9017989D50BEA5064A4E3DF
+:101050000CEE11C0F02F16132E16168AE78CE82A14
+:1010600016128EE9DFC0AAEA7EAB01B1CF0BA85001
+:101070006583468837DBC0AE89991E789B022BCCEE
+:10108000012B161B29120E2B0A0029161A7FC307E3
+:101090007FC9027EAB01C0B165B49D8B352F0A00BC
+:1010A0002A0A007AC30564C3CB2F0A0165F4892B91
+:1010B00012162B1619005104C0C100CC1A2CCCFFFB
+:1010C0002C16170CFC132C16182B121A2A121BDCC8
+:1010D000505819B6C0D0C0902E5CF42C12172812AC
+:1010E000182F121B2A121A08FF010CAA01883407B4
+:1010F0004C0AAB8B2812192BC6162F86082A860994
+:101100002E74102924672E70038975B1EA2A74039E
+:10111000B09909490C659DB42B20672D250265B354
+:10112000FA2B221E2C221D7BC901C0B064BD9D2C50
+:10113000B00728B000DA2006880A28824CC0D10BFC
+:101140008000DBA065AFE763FD8289BAB199659045
+:101150009788341CEE2398BA8F331EEE1C0F4F5421
+:101160002FB42C8D2A8A320EDD020CAC017DC966AB
+:101170000A49516F92608A3375A65B2CB0130AED51
+:10118000510DCD010D0D410C0C417DC9492EB01200
+:10119000B0EE65E3C6C0D08E378CB88A368FB97C86
+:1011A000A3077AC9027EFB01C0D1CED988350AAD2A
+:1011B000020E8E0878EB022DAC0189B7DAC0AF9B26
+:1011C00079BB01B1CADCB0C0B07DA3077AD9027C7B
+:1011D000EB01C0B164B161C091292467C020D10F77
+:1011E00000008ADAB1AA64A0C02C20672D25026510
+:1011F000C3111DEDF68A321EEDFB0DAD010EDD0CA7
+:1012000065D28A0A4E516FE202600281C0902924A1
+:1012100067090F4765F2F828221D7B89022B0A0017
+:1012200064BCA92CB00728B000DA2006880A2882FE
+:101230004CC0D10B8000DBA065AFE763FC8E0000E3
+:101240000CE9506492ED0CEF11C080281611AFBF6D
+:101250002F16198EF88BF7DAE08FF92B1610ABFBEF
+:101260007FBB01B1EA0CA8506580D68837DCE0AFBF
+:1012700089991C789B022CEC012C161B29120C2C32
+:101280000A0029161A7AE3077AE9027FBB01C0C176
+:1012900065C2A58B352C0A002A0A007AE30564E1B1
+:1012A000CA2C0A0164CE0D60028E88341BEDCD98E5
+:1012B000DA8F331EEDC60F4F542FD42C8C2A8A326E
+:1012C0000ECC020BAB010CBB0C65BF0A0A49516E78
+:1012D000920263FF018A330AAB5064BEF92CD0132B
+:1012E0000AEE510ECE010E0E410C0C410ECC0C65D7
+:1012F000CEE42FD012B0FF65F26EC0B08E378CD81E
+:101300008A362FD2097CA3077AC9027EFB01C0B1BD
+:1013100065BEC38835DBA0AE8E78EB01B1AB89D753
+:10132000DAC0AF9D79DB01B1CAC0C07BA3077AB92F
+:10133000027DEB01C0C165CE9DC090292467C0200D
+:10134000D10F88378C3698140CE90C29161408F83C
+:101350000C981D78FB07281214B088281614891DD4
+:101360009F159B16C0F02B121429161A2B161B8BD7
+:10137000147AE30B7AE90688158E1678EB01C0F132
+:1013800065F1BA29121A2F12118A352E121B9A1AD8
+:10139000AFEE2F1210C0A0AF9F79FB01B1EE9F11ED
+:1013A000881AC0F098107AE30A7EA9052A12017AF9
+:1013B0008B01C0F164F08160018389368B37991706
+:1013C0000BE80C981F09C90C29161578EB07281291
+:1013D00015B088281615D9C09A199E188A1F2E1282
+:1013E000152A161A2E161BDAC0C0E08C177F930B35
+:1013F0007FA90688188F1978FB01C0E165E13E29B5
+:10140000121A2F12138A352E121B9A1BAFEE2F12AF
+:1014100012C0A0AF9F79FB01B1EE9F13881BC0F0F3
+:1014200098127AE30A7EA9052A12037A8B01C0F189
+:1014300065F10A2E12162E16192A121B005104C02D
+:10144000E100EE1AB0EE2E16170EFF132F16180F2E
+:10145000CC01ACAA2F121A0EBC01ACFC7FCB01B19F
+:10146000AA2A161B2C161A63FC5E00007FB30263C7
+:10147000FE3163FE2B7EB30263FC3063FC2A000066
+:101480006450C0DA20DBC058168AC020D10FC0914A
+:1014900063FD7A00C09163FA44DA20DB70C0D12E7C
+:1014A0000A80C09A2924682C7007581575D2A0D1DB
+:1014B0000F03470B18ED4DDB70A8287873022B7DC6
+:1014C000F8D9B063FA6100002A2C74DB40580EEEA4
+:1014D00063FAE4000029221D2D25027B9901C0B08A
+:1014E000C9B62CB00728B000DA2006880A28824C3A
+:1014F000C0D10B8000DBA065AFE7C020D10FC09149
+:1015000063FBFF00022A0258024C0AA202060000F6
+:10151000022A025802490AA202060000DB70DA2001
+:10152000C0D12E0A80C09E2924682C7007581554FB
+:10153000C020D10FC09463FBC9C09663FBC4C096A2
+:1015400063FBBF002A2C74DB30DC405BFE0FDBA0AA
+:10155000C2A02AB4002C200C63FF27008D358CB765
+:101560007DCB0263FDD263FC6D8F358ED77FEB029E
+:1015700063FDC563FC6000006C1004C020D10F0047
+:101580006C1004C020D10F006C10042B221E2822E6
+:101590001DC0A0C0942924062A25027B8901DBA056
+:1015A000C9B913ED04DA2028B0002CB00703880A6B
+:1015B00028824CC0D10B8000DBA065AFE7C020D1F2
+:1015C0000F0000006C10042C20062A210268C805B8
+:1015D00028CCF965812E0A094C6591048F30C1B879
+:1015E0000F8F147FB00528212365812716ECF3297E
+:1015F000629E6F98026000F819ECEF2992266890BD
+:10160000078A2009AA0C65A0E72A629D64A0E12B45
+:10161000200C0CB911A6992D92866FD9026000DBBF
+:101620001DECE70DBD0A2DD2A368D0078E200DEE6C
+:101630000C65E0C7279285C0E06470BF1DECEC68C4
+:10164000434E1CECEB8A2B0CAA029A708920089955
+:10165000110D99029971882A98748F329F752821EB
+:1016600004088811987718ECDC0CBF11A6FF2DF246
+:1016700085A8B82E84CF2DDC282DF685C85A2A2CB3
+:1016800074DB40580E81D2A0D10FC020D10F0000D2
+:101690000029CCF96490B12C20668931B1CC0C0CB6
+:1016A000472C24666EC60260008509F85065807F6D
+:1016B0001CECD18A2B0F08400B881008AA020CAA38
+:1016C000029A7089200899110D99029971883398AE
+:1016D000738C329C728A2A9A748934997563FF7D5F
+:1016E00000CC57DA20DB30DC4058155FC020D10F2A
+:1016F00000DA20C0B65815EE63FFE500DA20581571
+:10170000EC63FFDC00DA20DB30DC40DD5058167A79
+:10171000D2A0D10FC858DA20DB305814C72A2102D2
+:1017200065AFBDC09409A90229250263FFB200007C
+:101730002B21045814731DECADC0E02E24668F30AD
+:101740002B200C0F8F1463FF66292138C088798302
+:101750001F8C310CFC5064CF562B2104C0C0581490
+:10176000681DECA2C0E08F302B200C0F8F1463FF9C
+:101770003E2C20662B2104B1CC0C0C472C2466583F
+:1017800014601DEC9AC0E02E24668F302B200C0FC5
+:101790008F1463FF1A0000006C1004C0B7C0A116BC
+:1017A000EC9615EC88D720D840B822C04005350209
+:1017B0009671957002A438040442C94B1AEC7B1947
+:1017C000EC7C29A67EC140D30F6D4A0500808800BD
+:1017D000208C220A88A272D10FC05008A53875B09B
+:1017E000E363FFD76C10069313941129200665520A
+:1017F00088C0716898052A9CF965A29816EC6F2933
+:1018000021028A1309094C6590CD8AA00A6A512ADF
+:10181000ACFD65A0C2CC5FDB30DA208C115815120C
+:10182000C0519A13C7BF9BA98E132EE20968E060CE
+:101830002F629E1DEC606FF8026000842DD2266836
+:10184000D0052F22007DF9782C629DC79064C0706E
+:101850009C108A132B200C2AA0200CBD11A6DD0A97
+:101860004F14BFA809880129D286AF88288C09792E
+:101870008B591FEC520FBF0A2FF2A368F0052822E4
+:10188000007F894729D285D4906590756000430018
+:10189000002B200C1FEC4A0CBD11A6DD29D2860FAF
+:1018A000BF0A6E96102FF2A368F00488207F890586
+:1018B00029D285659165DA2058157DC95C6001FFE4
+:1018C00000DA20C0B658157A60000C00C09063FFA3
+:1018D000B50000DA205815766551E48D138C11DBC4
+:1018E000D08DD0022A020D6D515813E39A1364A1D2
+:1018F000CEC75F8FA195A9C0510F0F479F1163FEFF
+:10190000FD00C091C0F12820062C2066288CF9A784
+:10191000CC0C0C472C24666FC6098D138DD170DE5C
+:1019200002290A00099D02648159C9D38A102B211A
+:10193000045813F38A13C0B02B24662EA2092AA0E0
+:10194000200E28141CEC298D1315EC1DC1700A778C
+:101950003685562DDC28AC2C9C12DED0A8557CD3C5
+:10196000022EDDF8D3E0DA40055B02DC305BFF8A53
+:10197000D4A028200CB455C0D02B0A882F0A800C84
+:101980008C11A6CC29C285AF3FAB9929C6851CEC2A
+:1019900012DEF0AC882D84CF28120229120378F3CE
+:1019A000022EFDF8289020D3E007880CC1700808AB
+:1019B00047289420087736657FAB891313EC10898C
+:1019C00090C0F47797491BEC0EC1CA2821048513F7
+:1019D000099E4006EE11875304881185520E880235
+:1019E0000C88029BA09FA18F2B9DA598A497A795DB
+:1019F000A603FF029FA22C200C1EEBF7AECE0CCC50
+:101A00001106CC082BC2852DE4CF2BBC202BC6851C
+:101A10002A2C748B11580D9CD2A0D10F28203DC0C8
+:101A2000E07C877F2E24670E0A4765A07B1AEBF5C2
+:101A300088201EEBE38F138EE48FF40888110A8848
+:101A4000020F8F14AFEE1FEBF098910FEE029E90F5
+:101A50001EEBEFC0801AEBE02CD285AABAB8CC28D6
+:101A6000A4CF2CD6852C21022F20720ECC02B1FFE0
+:101A70002F24722C2502C020D10F871387700707EF
+:101A80004763FD6E282138C099798B0263FE9ADD89
+:101A9000F063FE9500DA20DB308C11DD505815968E
+:101AA000D2A0D10FC0E163FF7A8B138C11DD50C03F
+:101AB000AA2E0A802A2468DA205813F1D2A0D10F66
+:101AC000C020D10F6C1006292102C0D07597102AB2
+:101AD00032047FA70A8B357FBF052D25020DD90261
+:101AE000090C4C65C18216EBB41EEBB228629EC095
+:101AF000FA78F30260018829E2266890078A2009B3
+:101B0000AA0C65A17A2A629DDFA064A1772B200C24
+:101B10000CBC11A6CC29C286C08C79830260015707
+:101B200019EBA709B90A2992A368900788200988A8
+:101B30000C65814327C2851CEBA964713A89310980
+:101B40008B140CBB016FB11D2C20669F10B1CC0C07
+:101B50000C472C24666EC60260014009FF5065F1F7
+:101B60003A8A102AAC188934C0C47F973C18EBA974
+:101B70001BEBA88F359C719B708B209D7408BB025A
+:101B80009B72C08298751BEBA40F08409B730F8853
+:101B90001198777FF70B2F2102284A0008FF022FA8
+:101BA0002502C0B4600004000000C0B07E97048F1E
+:101BB000362F25227D970488372825217C9736C02B
+:101BC000F1C0900AF9382F3C200909426490861927
+:101BD000EB7618EB7728967E00F08800A08C00F05A
+:101BE0008800A08C00F08800A08C2A629D2DE4A2C1
+:101BF0002AAC182A669D89307797388F338A321835
+:101C0000EB8007BE0B2C2104B4BB04CC1198E0C0C0
+:101C10008498E1882B9DE59AE69FE71AEB78099F67
+:101C20004006FF110FCC020A880298E2C1FC0FCCDB
+:101C3000022CE604C9B82C200C1EEB670CCA11AEAE
+:101C4000CC06AA0829A2852DC4CF09B90B29A685DF
+:101C5000CF5CC020D10FC081C0900F8938C0877978
+:101C6000880263FF7263FF6600CC57DA20DB30DC4A
+:101C7000405813FDC020D10FDA2058148D63FFE8BF
+:101C8000C0A063FE82DA20C0B658148963FFD90071
+:101C9000DB402A2C74580CFCD2A0D10F8A102B21C7
+:101CA000045813171EEB44C0D02D246663FEB10008
+:101CB0006C1006D62019EB3F1EEB4128610217EB92
+:101CC0003E08084C65805F8A300A6A5169A3572B29
+:101CD000729E6EB83F2A922668A0048C607AC9343E
+:101CE0002A729D2C4CFECAAB2B600CB64F0CBD115A
+:101CF000A7DD28D2860EBE0A78FB269C112EE2A311
+:101D00002C160068E0052F62007EF91522D285CFDF
+:101D10002560000D00DA60C0B6581465C85A60012D
+:101D20000F00DA60581462655106DC40DB308D30FC
+:101D3000DA600D6D515812D0D3A064A0F384A1C015
+:101D40005104044763FF6D00C0B02C60668931B157
+:101D5000CC0C0C472C64666FC60270960A2B61048B
+:101D60005812E7C0B02B64666550B42A3C10C0E737
+:101D7000DC20C0D1C0F002DF380F0F4264F09019B0
+:101D8000EB0A18EB0B28967E8D106DDA0500A08803
+:101D900000C08CC0A089301DEB1A77975388328C15
+:101DA000108F3302CE0BC02492E12261049DE00427
+:101DB00022118D6B9BE59FE798E61FEB1009984079
+:101DC0000688110822020FDD02C18D9DE208220261
+:101DD00092E4B4C22E600C1FEB000CE811A7882C13
+:101DE0008285AFEE0C220B2BE4CF228685D2A0D1C8
+:101DF0000F28600CD2A08C1119EAF80C8D11A9885B
+:101E0000A7DD2ED2852B84CF0ECC0B2CD685D10FFF
+:101E1000C0F00ADF387FE80263FF6C63FF600000F8
+:101E20002A6C74C0B2DC20DD405812C5C0B063FF1C
+:101E300063C020D10F0000006C10042920062A2264
+:101E40001EC0392C221D232468C0307AC107DDA0B2
+:101E5000600004000000C0D06E9738C08F2E0A804A
+:101E60002B2014C0962924060EBB022E21022B24FF
+:101E7000147E8004232502DE307AC10EC8ABDBD08D
+:101E8000DA202C0A00580B062E21020E0F4CC8FE39
+:101E90006000690068956528210208084C65805C2F
+:101EA0001AEAC61EEAC42BA29EC09A7B9B5E2BE256
+:101EB0002668B0048C207BC95329A29D1FEAC16407
+:101EC000904A9390C0C31DEAD52B21049D9608BB70
+:101ED000110CBB029B979B911CEAD2C08523E4A204
+:101EE0002BA29D2824068DFA282102B0DD2BBC30C0
+:101EF0002BA69D9DFA0C8802282502C8D2C020D1AD
+:101F00000F8EF912EAC82E2689C020D10FDA20C020
+:101F1000B65813E7C020D10F6C10062A2006941083
+:101F200068A80528ACF965825029210209094C6589
+:101F3000920ACC5FDB30DA208C1058134BC051D39F
+:101F4000A0C7AF9A3AC0D01CEA9D14EAA31EEA9C2F
+:101F50008F3A16EA99B1FB64B13128629E6F88020C
+:101F60006001ED294C332992266890078A2009AA3E
+:101F70000C65A1DC2A629DC08E64A1D42B200C0CC0
+:101F8000B7110677082972867983026001CD0CB9F2
+:101F90000A2992A36890082C220009CC0C65C1BBC9
+:101FA0002772856471B5282006288CF96481E52C98
+:101FB00020668931B1CC0C0C472C24666EC60260B9
+:101FC00001A109F85065819B2A21048CE488361E02
+:101FD000EA7D088914A9CC08084709881019EA92F3
+:101FE0000ECC029C7099718C2A1EEA9008CC020ECD
+:101FF000CC029C722E302C293013283012049910F8
+:102000000688100CEE109F740EAE0209880208EECE
+:10201000029E738C3704AA119C758938C0F4997696
+:102020008839C0C1987718EA828E359C7B9E780EDD
+:102030008E1408EE029E7A8E301CEA7177E73088A3
+:102040003289339C7C9F7D0E9C4006CC118F2B29BE
+:1020500076132D76112876120CAA0218EA68C1C9E7
+:102060000CAA022A761008FF029F7EC0AA60000117
+:10207000C0A6A4BC0CB911A6992892852DC4CF087E
+:10208000A80B289685655100C020D10F2B200C0C81
+:10209000B7110677082A72860CB90A6FA902600187
+:1020A000182992A36890082A220009AA0C65A109A0
+:1020B0002A728564A1032C203D0C2C4064C08C8CBA
+:1020C000350C8C1464C0848FE57CF37F8C360C8CCB
+:1020D0001464C0777CF374283013C0FC78F86CC0AB
+:1020E00090292467090C4765C0D719EA4718EA45C3
+:1020F0008F208C3508FF110C8C1408FF0288E49F98
+:10210000A1AC8C09CC029CA08C369FA30C8C14AC87
+:102110008809880298A218EA3DA4BC2F72852DC4B4
+:10212000CF2FFC102F76852F210229207208FF0265
+:10213000B2992924722F2502C020D10F00CC57DA82
+:1021400020DB308C105812C8C020D10FC09163FF23
+:102150008FDA20C0B658135663FFE100DA20581317
+:102160005463FFD82B21045811E61EEA152B200CCE
+:10217000C0D02D24668F3A63FE4DDA20DB30DC4080
+:10218000DD505813DDD2A0D10F2A2C748B10580BC0
+:10219000BED2A0D10F292138C08879832E8C310C72
+:1021A000FC5064CE222B2104C0C05811D5C0D01ED3
+:1021B000EA048F3A2B200C63FE0DDA2058133C639F
+:1021C000FF7ADA205BFF1CD2A0D10F002C20662BF7
+:1021D0002104B1CC0C0C472C24665811C91EE9F817
+:1021E0002B200CC0D02D24668F3A63FDDA0000004E
+:1021F0006C10089514C061C1B0D9402A203DC04080
+:102200000BAA010A64382A200629160568A8052C9D
+:10221000ACF965C33F1DE9EA6440052F120464F27E
+:10222000A02621021EE9E606064C6562E615E9E2F3
+:102230006440D98A352930039A130A990C6490CCEA
+:102240002C200C8B139C100CCC11A5CC9C112CC2F7
+:1022500086B4BB7CB3026002D78F100EFE0A2EE25A
+:10226000A368E0098620D30F0E660C6562C2881150
+:102270002882856482BA891364905EDA80D9308CB2
+:10228000201EE9E01FE9E11DE9CE8B138DD4D4B007
+:102290007FB718B88A293C10853608C6110E660229
+:1022A0009681058514A5D50F550295800418146DE7
+:1022B0008927889608CB110888140EBB02A8D82954
+:1022C0009C200F88029BA198A088929BA308881449
+:1022D000A8D80F880298A22AAC1019E9CCC0C08FE8
+:1022E000131EE9BD86118D10286285AEDD08FF0B37
+:1022F0002CD4CF2821022F66858B352A207209889D
+:1023000002ABAA2825022A2472C020D10F29529E8E
+:1023100018E9A96F980260020B28822668800829B4
+:10232000220008990C6591FC2A529DC1CE9A126434
+:10233000A1F22B200C2620060CB8110588082D824E
+:10234000860EBE0A7DC3026002052EE2A368E00885
+:102350002F22000EFF0C65F1F6288285D780DE80E3
+:102360006482009816266CF96462012C206688311C
+:102370002CCC010C0C472C24666EC6026001BC08F4
+:10238000FD5065D1B61DE9AB1CE98F19E9962A21EC
+:10239000048B2D2830102F211D0C88100BFB090AEF
+:1023A00088020988020CBB026441529B709D71989F
+:1023B00072C04D8D35D9E064D06ED730DBD0D830C7
+:1023C0007FD714273C10BCE92632168C3996E69C40
+:1023D000E78A37B4382AE6080B131464304A2A8295
+:1023E0001686799A9696978C778A7D9C982B821779
+:1023F0002C7C209A9A2A9C189B99867BB03B298C2E
+:10240000086DB9218BC996A52692162AAC18B899E1
+:102410009BA196A08BC786CD9BA22B921596A49BC1
+:10242000A386CB2CCC2026A605C0346BD4200D3B34
+:102430000C0DD8090E880A7FB705C0909988BC8812
+:10244000C0900B1A126DAA069988998B288C18C017
+:10245000D01BE97A1CE97916E96EB1FF2A211C2309
+:10246000E6130F0F4F26E6122F251D7FA906C0F099
+:10247000C08028251D05F6111AE9678F202BE61567
+:102480002CE6162DE61726E6180AFA022AE6142983
+:102490002006299CF96490F829200C8D14C0801A1C
+:1024A000E94E0C9C11AA99A5CCDA202BC285289460
+:1024B000CF0B4B0B2BC685C0B08C155811BBD2A0CF
+:1024C000D10F8A356FA546D8308BD56DA90C8A8679
+:1024D0000A8A14CBA77AB335288C10C080282467C9
+:1024E000080B4765B10BDA20DB302C12055811DEE2
+:1024F000D3A0C0C1C0D02DA4039C1463FD22863696
+:102500006461059B709D719872C04D63FEA4C0818B
+:1025100063FFC9008814CC87DA20DB308C15581192
+:10252000D2C020D10FDA20C0B658126163FFE40098
+:1025300000DA208B1058125E63FFD8009E178A12B3
+:102540002B21045810EF8E17C09029246663FE34A7
+:10255000C08063FE06DA20DB308C15DD505812E6B1
+:10256000D2A0D10FDA2058125263FFA7002B2138D6
+:10257000C0A87BAB026001048C310CFC5064CE041B
+:102580008A122B2104C0C098175810DD8E1763FDE6
+:10259000F32D21382DDCFF0D0D4F2D253865DEF78D
+:1025A00028206A7F87050826416460A3C09016E949
+:1025B000141CE9232A200723E61BB1AA0CFD0226DE
+:1025C000E61A2B200A29E61D2DE61E0CBB022BE67F
+:1025D0001C8B260A0A472BE6208B282AE53E2BE691
+:1025E000212924072820062A2064688346B44463EE
+:1025F000FEA5DB30DA208C158D142E0A80C08E28C3
+:10260000246858111FD2A0D10F2E7C4819E8ED2A5A
+:1026100032162B76129D712D761328761489960A20
+:102620002A14AA990C9902997069ED71C14663FD4B
+:102630008100000064AFB51DE8E22C20168DD20A9F
+:10264000CC0C00D10400CC1AACBC9C2963FF9D00CB
+:102650002B21046EB81E2C2066B8CC0C0C472C2401
+:1026600066C9C09E178A125810A68E17C0348F20D4
+:10267000C0D02D2466C06826240663FF2E8A122B44
+:1026800021042C20669817B1CC0C0C472C246658DA
+:10269000109C8E178716C0D02D246663FCE68D35FE
+:1026A000C08064D04AD9E0DC30DBE0DF301AE8E5F6
+:1026B000B188B4FF16E8E584C92D9DFF87C82CCCEE
+:1026C0001027D63006460127D6320A440117E8DF24
+:1026D00024D631A74727D63324F21596B794B68D62
+:1026E000C3BCBB9DB58D35299C107D83C22F211D98
+:1026F000C14663FD330000006C1006292006289CAB
+:10270000F86582BF2921022B200C09094C6590E154
+:1027100016E8AA0CBA11A6AA2DA2862C0A127DC30D
+:102720000260028C19E8A609B90A2992A3689007E9
+:102730008C2009CC0C65C27829A2856492722D6226
+:102740009E1AE89C6FD80260026E2AA22629160102
+:1027500068A0082B22000ABB0C65B25C29629DC1EF
+:102760008C6492542A21200A806099102C203CC746
+:10277000EF000F3E010B3EB1BD0FDB390BBB098FE4
+:10278000260DBD112DDC1C0D0D410EDD038E27B174
+:10279000DD0D0D410FEE0C0DBB0B2BBC1C0BB7025E
+:1027A0007EC71C2C21257BCB162D1AFC0CBA0C0DD8
+:1027B000A16000093E01073EB1780987390B770A0D
+:1027C00077EB0260020A2C2123282121B1CC0C0CCA
+:1027D0004F2C25237C8B29B0CD2D2523C855DA20FD
+:1027E000DB30581095292102CC96C0E80E9E022EAF
+:1027F0002502CC57DA20DB30DC4058111BC020D139
+:102800000F2C20668931B1CC0C0C472C24666EC687
+:10281000026001D309FD5065D1CD2F0A012E301180
+:1028200029221464E01128221B090C4400C1040071
+:10283000FA1A0A880228261B2E3010C0A0C0B094B5
+:102840001295131CE85F88302CC022088D147787FE
+:1028500004C0F10CFA38C041C0F225203CC0840805
+:1028600058010F5F010F4B3805354007BB10C0F012
+:10287000084F3808FF100FBB0228ECFEC0F0084FCD
+:1028800038842B0BA8100AFF102A21200F88020B76
+:10289000880208440218E86E8F1108440228212596
+:1028A0000A2A140828140488110A88022A21049488
+:1028B000F08B2004E41008BB1104BB02C04A04BB27
+:1028C000029BF1842A08AB110BEB0294F40A541119
+:1028D0000B44020555100D1B4094F707BB100B5518
+:1028E00002085502C08195F68433C05094F3B19428
+:1028F0008B3295F898F99BF2C080C1BC24261499BC
+:10290000FA9BF598FB853895FC843A94FD8B3B9BAC
+:10291000FE883998FF853525F6108436851324F610
+:10292000118B3784122BF612C0B064C07E893077C9
+:1029300097438D3288332E30108F111CE83109995E
+:10294000400699112CF614C0C42CF6158C2B2DF6CC
+:102950001A28F61B2BF61904A81109880208EE02A2
+:1029600019E827C18008EE0209C90229F6162EF6D9
+:1029700018C09E600001C09A2F200C18E8170CFEAA
+:1029800011A8FFA6EE2DE2852BF4CF0D9D0B2DE6B1
+:1029900085C87F8A268929A7AA9A260A990C090937
+:1029A00048292525655050C020D10F00C09A63FFEB
+:1029B000C6DA2058113F63FE38DA20C0B658113C01
+:1029C00063FE2E0068973C2B9CFD64BE24C020D182
+:1029D0000FDA20DB705810F8C0C0C0D10ADA390A0B
+:1029E000DC3865CDE063FE098A102B2104580FC442
+:1029F000C0B02B246663FE21DB402A2C745809A248
+:102A0000D2A0D10FDA20580FC963FCF76C1004C0B4
+:102A100020D10F006C1004290A801EE80E1FE80E5A
+:102A20001CE7E60C2B11ACBB2C2CFC2DB2850FCC7B
+:102A3000029ED19CD0C051C07013E80A14E8091856
+:102A4000E8072AB285A82804240A234691A986B853
+:102A5000AA2AB685A98827849F25649FD10F0000E4
+:102A60006C100AD630283010292006288CF9648290
+:102A70009B68980B2A9CF965A1B2022A02580FABF9
+:102A800089371BE7CFC89164520E2A21020A0C4CE9
+:102A900065C2588D3019E7C874D7052E212365E229
+:102AA0009E2F929E1AE7C46FF8026002532AA22654
+:102AB00068A0082C22000ACC0C65C2442A929D64AE
+:102AC000A23E9A151FE7BE8D67C1E6C8DD2B6206E0
+:102AD00018E7BC64B0052880217B8B432B200C18A1
+:102AE000E7B60CBC11A8CC29C28679EB460FBE0A0A
+:102AF0002EE2A368E0052F22007EF9372CC2859CC8
+:102B00001864C2332B212F87660B7B360B790C6F31
+:102B10009D266ED2462C203D7BC740CE5560001EC0
+:102B20002A200CC1B28C205811229A1864A2458D1B
+:102B30006763FFCFC0C063FFC5D7B063FFD300C0DA
+:102B4000E06000022E60030EDB0C6EB20EDC700C37
+:102B5000EA11AA6A2AAC20580199D7A0DA20DB70C2
+:102B6000C1C82D21205810BC8C268B279A160CBB6F
+:102B70000C7AB3348F18896399F3886298F28E6562
+:102B80009EF82D60108A189D1768D729C0D09DA97E
+:102B90002C22182B22139CAB9BAA97A58E667E73C2
+:102BA00002600097CF5860001FDA208B1658108201
+:102BB00065A13863FFBDC081C0908F18C0A29AF98B
+:102BC00099FB98FA97F563FFD2DB30DA20DC4058A6
+:102BD0001026C051D6A0C0C02BA0102CA4039B1758
+:102BE0002C1208022A02066B02DF702D60038E177A
+:102BF0009D149E100CDD11C0E0AD6D2DDC20580140
+:102C0000188C148B16ACAC2C64038A268929ABAAC9
+:102C10000A990C9A26886609094829252507880CEF
+:102C200098662F2218A7FF2F261863FE96DA20DB5E
+:102C300030DC40DD50581130D2A0D10FC0302C20F4
+:102C4000668961B1CC0C0C472C24666EC60260000C
+:102C5000D2C03009FD5065D0CA8E6764E0696470E7
+:102C600066DB608C18DF70DA202D60038E170CDDB8
+:102C7000119E10AD6D2DDC201EE7755800F923263E
+:102C800018DA208B16DC402F2213DD50B1FF2F26DF
+:102C900013580FC5D2A0D10F0028203D0848406529
+:102CA0008DE76F953EDA308DB56D990C8CA80C8C44
+:102CB00014CACF7CD32D2AAC10C090292467090DEB
+:102CC0004764DDC5600092002C1208066B022D6C73
+:102CD00020077F028E17DA209E101EE75C58007DC9
+:102CE00063FF9A00C09163FFD1000000655081DA54
+:102CF00020DB60DC40580FDCC020C0F02FA403D1E3
+:102D00000FDA20C0B658106A63FFE000006F95022A
+:102D100063FD6CDA20DB30DC40DD50C4E0580F5836
+:102D2000D2A0D10F8A152B2104580EF52324662832
+:102D30006010981763FF2100DA2058105D63FFAB25
+:102D4000C858DB30DA20580F3C2A210265AF9CC0FE
+:102D50009409A90229250263FF91DB30DC40DD5094
+:102D6000C0A32E0A802A2468DA20580F45D2A0D1A9
+:102D70000FC020D10FDA202B200C58107263FF6B8C
+:102D80006C1004282006C062288CF8658125C0508C
+:102D9000C7DF2B221BC0E12A206B29212300A104BD
+:102DA000B099292523B1AA00EC1A0BC4010A0A44E0
+:102DB0002A246B04E4390DCC030CBB012B261B64C5
+:102DC000406929200C1BE6FC0C9A110BAA082FA2C3
+:102DD000861BE6FA6FF9026000B60B9B0A2BB2A3C2
+:102DE00068B0082C22000BCC0C65C0A42BA2851D5A
+:102DF000E71E64B09B8C2B2421040DCC029CB08870
+:102E000020C0C50888110C880298B1882A0844118E
+:102E100098B48F3494B79FB5C0401EE6EF2DA285BD
+:102E20000E9E0825E4CF2DDC282DA6852921020938
+:102E3000094C68941A689820C9402A210265A00BA1
+:102E40002A221E2B221D7AB10265A079C020D10F43
+:102E50002C212365CFDE6000082E21212D21237E29
+:102E6000DBD52B221E2F221D2525027BF901C0B0A8
+:102E700064BFC413E6D02CB00728B000DA20038862
+:102E80000A28824CC0D10B8000DBA065AFE763FF4E
+:102E9000A62A2C74C0B02C0A02580E2F1CE6F49CF3
+:102EA000A08B2008BB1106BB029BA1893499A263A9
+:102EB000FF790000262468DA20DB30DC40DD505842
+:102EC000108ED2A0D10FDA202B200C580FF9C02081
+:102ED000D10F00006C1006073D14C080DC30DB40D1
+:102EE000DA20C047C02123BC3003283808084277C5
+:102EF0004001B1DD64815A1EE6AC19E6AD29E67EDB
+:102F0000D30F6DDA0500508800308CC0E0C020255A
+:102F1000A03C14E6ABB6D38FC0C0D00F87142440BA
+:102F2000220F8940941077F704C081048238C0F1E1
+:102F30000B2810C044C02204540104FD3802520181
+:102F400002FE3808DD10821C07EE100E6E020EDD48
+:102F500002242CFEC0E004FE380AEE100E88020D9A
+:102F600088028DAB1EE69B08D8020E880298B0C07E
+:102F7000E80428100E5E0184A025A125084411084C
+:102F80004402052514045511043402C0810E8E3903
+:102F900094B18FAA84109FB475660C26A11FC0F24D
+:102FA000062614600009000026A120C0F20626149F
+:102FB0000565020F770107873905E61007781008C5
+:102FC000660206550295B625A1040AE611085811B5
+:102FD00008280208660296B7C060644056649053A1
+:102FE000067E11C0F489C288C30B340B96459847FE
+:102FF000994618E6829F410459110E99021FE680F6
+:10300000020E4708D80298420E99029F40C1E00E76
+:10301000990299442FA00CB4380CF91114E66F1ED4
+:10302000E666A4FFAE992E928526F4CF0E880B2873
+:103030009685D10F2BA00C1FE6601CE6670CBE1115
+:10304000ACBBAFEE2DE28526B4CF0D3D0B2DE68552
+:10305000D10FC08005283878480263FEA263FE962F
+:103060006C1006C0C06570F18830C03008871477D6
+:103070008712C0B0C0A619E652299022C030CC9762
+:10308000C031600003C0B0C0A6C0E0C091C0D4C0D1
+:103090008225203C0B3F109712831CC070085801FA
+:1030A0000D5D01089738C0800B98380777100488A9
+:1030B00010086802087702C0800D98382D3CFE0881
+:1030C00088100D9E388D2B0AEE1008EE0207EE02D6
+:1030D0000CB8100FDD02053B400EDD029D4089203B
+:1030E000043D100899110D99022D210409A9020827
+:1030F000DD119941872A05B9100D3D020ABB110D5A
+:10310000BB02087702974428212587120828140457
+:103110008811071E4007EE100E99027566092621D8
+:103120001F062614600006002621200626140868C3
+:10313000029B47098802984629200CD2C0C0800C07
+:103140009E111BE6251FE61CAB99AFEE2DE28528EC
+:1031500094CF0DAD0B2DE685D10FDD40C0A6C0B0DC
+:103160008E51CAE0B2AAB1BB2DDC108F500E78365A
+:10317000981008770C9FD898D989538F5299119934
+:10318000DB9FDA7E8309B1CC255C10C97763FFCF62
+:1031900088108D1108E70C9751AD8DD7F078DB01C1
+:1031A000B1F79D5397528830C03008871408884083
+:1031B000648ED565BEC963FEBC0000006C1004D7E8
+:1031C00020B03A8820C0308221CAA0742B1E2972F8
+:1031D000046D080FC980C9918575B133A2527A3B3D
+:1031E0000B742B0863FFE900649FECD10FD240D130
+:1031F0000F0000006C100AD6302E3027D950DA406C
+:1032000015E5F02430269A1529160464E00264932B
+:10321000732920062A9CF865A3CE2A2102270A04D6
+:103220000A0B4C65B3978C3074C7052D212365D4E8
+:10323000A0C0A62B0A032C2200580F3664A3B9178E
+:10324000E5DE8E389A1664E3BA2F6027285021C92C
+:10325000F37E8311C2B08C202A200C580F55D7A0C2
+:10326000CDA16004A200C2B08C202A200C580F29E6
+:10327000D7A064A4862F212E8B680FBF360FB90C00
+:103280006F9D54296027D5B06E920528203D7B8F15
+:103290004CDA20DB50C1C42D211F580EEF8B269A2B
+:1032A000189A1989272AAC380B990C7A9353896399
+:1032B000C08099738F6298789F728E659E798D67B2
+:1032C0009D7B8C6695759C7A8E687E53026000B1FA
+:1032D0008B1465B050600038DBF063FFA5008A14E2
+:1032E000C9A92E60030E9B0C6EB2A5DC500CEA112E
+:1032F000AA6A2AAC285BFFB1D5A063FF93C0E06344
+:10330000FFE2DA208B18580EAC65A2B163FF9E0075
+:1033100000DA20DB308C15580E54D6A0C0C0C0D1C6
+:103320002D16042CA403DC70DA20DB60DF502D6046
+:1033300003C0E09E109D171EE5B90CDD110D6D0850
+:103340002DDC285BFF478E668F678817AF5FA8A8C4
+:1033500028640375FB01B1EE8A189E669F67892673
+:103360008829AA9909880C99268E6808084805EECC
+:103370000C28252515E5939E6865EECC63FEE600D6
+:103380000000C9432F21232B21212FFC010F0F4FB8
+:103390002F25237FBB026003142C20668961B1CCEA
+:1033A0000C0C472C24666EC60260022809FD50658D
+:1033B000D22264E1B62E602764E1B0DC70DF50DA1F
+:1033C00020DB601EE5AB2D6003C08098100CDD1182
+:1033D000AD6D2DDC285BFF22644181C0442B0A00C7
+:1033E0008C202A200C580ECB0AA70265A00FC0B073
+:1033F0002C22002A200C580EC7D7A064AFEFDA2089
+:10340000C1BCC1C82D21208F188E268929AFEE9E00
+:10341000260E990C090948292525580E8FC090C001
+:1034200050C0C288609A191EE566C0A12EE022082D
+:103430008F14778704C0810E8938C0800B93102DBC
+:10344000203C2921200CDC0104DB010929140BA8F4
+:10345000380CA5380D3D401CE57E8B2B08881007E5
+:1034600055100855020533022821250F154003BBCE
+:10347000020CBB0207551005D3100828140ADD11F1
+:103480000488110988020533022921040833029BAC
+:1034900070C0808A201BE57708AA110BAA029A71D6
+:1034A000C0A1852A9376957408931103DD020ADD85
+:1034B000029D778C63C1DC9C738B6298789A799BB0
+:1034C00072232214C0C0B1352526149C7B9D7593B0
+:1034D0007A2B621A9B7C2A621C9A7D28621D987E38
+:1034E00025621B957F2362172376102D62182D7697
+:1034F000112C62192C761264E0B98E6077E73DC01A
+:10350000FE13E53E1DE53FC1818A628B6304951180
+:103510000E9C4006CC110C5502247615085502C0AD
+:10352000802D76148D2B2B761B2A761A287619255A
+:10353000761803DD022D76166000030000C0FA2E17
+:10354000200C19E52518E51CA9E90CEE11A8EEC020
+:10355000802DE2852894CF0DFD0B2DE685DA208B9A
+:10356000198C158D14580D90D2A0D10FDC70DF503E
+:10357000DB602D6C28C0A01EE53E9A10DA205BFEB1
+:103580005563FE53002B203D0B4B4065BC826FE51D
+:1035900027DA308F556DE90C8EAA0E8E14C9E87E9D
+:1035A000F3162AAC10C090292467090F4764FC6009
+:1035B00060015F00C0FA63FF85C09163FFE8881473
+:1035C000658168DA20DB608C15580DA7C020C0909B
+:1035D00029A403D10F8A162B2104580CC9C0A02A94
+:1035E00024668E6863FDCA00002B9CF965B0FDDA85
+:1035F00020580CCE63FC220000DA20C0B6580E2CF6
+:1036000063FFBA002B200C0CBE11A7EE2DE286C181
+:10361000C27DC30260011819E4E909B90A2992A31D
+:103620006890082A220009AA0C65A10326E2856495
+:1036300060FD2C20668931B1CC0C0C472C24666FC0
+:10364000C60270960C8A162B2104580CADC0D02DE2
+:1036500024668E3077E74D1CE4E91BE4E98F32885D
+:1036600033C0A42D21040E994006991104DD1109DF
+:10367000DD029A61C19009DD029B60C0908B2B9D99
+:10368000649F66986799650CBB029B6228200C1AA0
+:10369000E4D2AA8A0C8811A7882F828529A4CF2F6B
+:1036A000FC202F86858A1465A0A6C020D10FB0FC0F
+:1036B0008B142C2523C8B7022A02066B02580CDE95
+:1036C0002A210265AEF7C0D80DAD022D250263FE9A
+:1036D000EC008E14C8E8DA20DB30580CD72A21021F
+:1036E00065AEDA07AF022F250263FED100DA20DBD8
+:1036F000308C158D14580E80D2A0D10FDA202B20DB
+:103700000C580DEB63FEB600DA202B200C580E0D82
+:1037100063FEAADA20DB308C152D12042E0A8028D5
+:103720000A00282468580CD663FAE500C020D10F9F
+:10373000DA20580DDF8914CD92DA20DB308C155851
+:103740000D4ADBA0C020C0A02AB403D10FC020D1F5
+:103750000F2A2C748B1558064CD2A0D10F000000F4
+:103760006C100E28210224160108084C6583A91F3D
+:10377000E49229F29E6F98026003AD1EE48E29E266
+:10378000266890082A220009AA0C65A39B24F29DB2
+:103790006443952A31160A4B412B240BB4BB0B0B07
+:1037A000472B240C0CB611AF66286286C1CC78C3B7
+:1037B0000260037F19E48209B90A2992A36890077D
+:1037C0008C2009CC0C65C36B276285647365293135
+:1037D00009C0D02D24668C3599139C2A88369C14F8
+:1037E000982B8E3798159E169E2C8C38C0E10C5C59
+:1037F000149C179C2D88392925042E251D28251C4D
+:103800002C3028C0822C243C2930290C0C4708C8B5
+:103810000129243D29311598189912090841089960
+:103820000C299CEC29251F7EC725921C8212282A70
+:1038300000082060991B01023E00093EB128098260
+:1038400039891B0E221102990C821C29251F821C0A
+:10385000941D951E24211F15E4880451609A10C1FF
+:10386000802B1610252014961F05054301063E00E7
+:103870000D3EB16B0DB6398B3C2D9CFC08663606AF
+:10388000441C893D2E26132E26142E26152E246B1D
+:1038900025241406D61CC05025261825261B2524B1
+:1038A000672524682832112525232525242525254B
+:1038B00025252C2925222D25202B252124252E26A2
+:1038C000252F14E46F16E46D1BE45298192D211C6A
+:1038D000C08498719B70892095759577957F967CAB
+:1038E000967E98799B7894731BE46714E4680C388F
+:1038F000400288100C064015E464016610947D9B1C
+:1039000074841D1BE444086602957B18E431851E0F
+:103910000B99029972997A0866022B121096768694
+:103920001F6FD2026001C8C0A0991A6D080AB1AA1F
+:1039300000A10400E81A7D8B0263FFEE891AC0E043
+:10394000961F1DE43E2B1610951E941D28203D2920
+:10395000761A297612C040C051C0B22D76130806DF
+:10396000408D170B8801065E380AEE101BE44A08EA
+:103970005438B0A609661188140B44102B761B042A
+:10398000EE028B1614E44308DA1406EE020D8810DA
+:103990002A761E86131AE41C04EE020D66110866D0
+:1039A000022E76160D14141EE41A0D44110BD814B1
+:1039B0000866020A44022E76182E76102476172600
+:1039C000761FC084287619287611C76F0C24400F03
+:1039D00044111CE3FB26761D26761C2676152676DA
+:1039E000148A262676242676252976222E762028E5
+:1039F00076218E1888150DB91016E4278BC70D880F
+:103A0000110E5E39ADBB851904EE022676230988B6
+:103A100002861F89102876260A04480544110505E8
+:103A2000480E551105440204EE02851E841D2E76B3
+:103A3000272820069B2D29246A2E31172B12102EA1
+:103A40002538CC83C0D02D2407C0D7090840648016
+:103A50008E9A290928416480AA64E0B42D2406C006
+:103A60009809E9362D0AA02A628501C404ADAA2D61
+:103A700021042A668508DD11883F8E3E2732100812
+:103A8000EA1800C40408E8180088110ECE5308771D
+:103A900002C08308DD029D4118E401090D4E9840E3
+:103AA00088209A4397449D4517E3FE1DE3CB058884
+:103AB0001108EE02ADBDC08007EE029E4228D4CFB1
+:103AC0002AF29D87CA2AAC18B1772AF69D1AE3B963
+:103AD00097CA28A4A268711C655060C020D10F004D
+:103AE0002D2406C080C09809E9360E893863FF731B
+:103AF000C0A063FE481BE3CB1AE3EB2AB68963FF41
+:103B0000D600000065EF54C098C0D82D240663FF8E
+:103B1000522D2406C09063FF4ACC57DA20DB308C4C
+:103B200011580C51C020D10F00DA20C0B6580CE05B
+:103B300063FFE500DA20580CDE63FFDC2A2C748B6F
+:103B400011580551D2A0D10F6C10062820068A33D7
+:103B50006F8202600161C05013E39729210216E3CE
+:103B600096699204252502D9502C20159A2814E331
+:103B7000948F2627200B0AFE0C0477092B712064F2
+:103B8000E1398E428D436FBC0260016F00E104B0E9
+:103B9000C800881A08A80808D80298272B200668A9
+:103BA000B32ECE972B221E2C221D0111027BC901A0
+:103BB000C0B064B0172CB00728B000DA2003880A20
+:103BC00028824CC0D10B8000DBA065AFE7C020D1BC
+:103BD0000F2D206464DFCA8B29C0F10BAB0C66BFCC
+:103BE000C02B200C0CBC11A6CC28C2862E0A08784B
+:103BF000EB611EE3720EBE0A2EE2A368E0052822E6
+:103C0000007E894F29C2851EE37E6490461FE38CA7
+:103C10009E90C084989128200A95930F88029892CC
+:103C20008E200FEE029E942F200788262F950A984B
+:103C3000969A972E200625240768E3432921022A15
+:103C4000C2851DE3652AAC20ADBD25D4CF2AC6852B
+:103C500063FF4E002E2065CBEDC082282465C9F697
+:103C600005E4310002002A62821BE36D2941020B48
+:103C7000AA022A668209E43129210263FF23000097
+:103C800064DFB88F422E201600F1040DEE0C00EE1A
+:103C90001AAEAE9E2963FFA38A202B3221B1AA9AC5
+:103CA000B0293221283223B4992936217989A92BC8
+:103CB00032222B362163FFA0C020D10F9F2725245D
+:103CC00015ACB82875202B2006C0C12EBCFE64E0C0
+:103CD000AB68B7772DBCFD65DEC72D2064C0F064EE
+:103CE000D0868E290EAE0C66E089C0F128205A28B5
+:103CF0008CFE08CF3865FEE863FF580000E00493AF
+:103D000010C0810AF30C038339C78F08D80308A8B1
+:103D10000108F80C080819A83303C80CA8B82875BE
+:103D200020030B472B24158310CBB700E104B0BC54
+:103D300000CC1AACAC0CDC029C27659E5EC0B20BBA
+:103D4000990209094F29250263FE50002D206A0DB2
+:103D50002D4165DF7EDA20C0B0580CA864AF18C0D2
+:103D6000F163FEEF9F2763FFD02E221F65EE3263C3
+:103D7000FF79000028221F658E2763FF6E25240629
+:103D800029210263FE1B00006C10066571332B4C69
+:103D900018C0C7293C18C0A1C08009A8380808422B
+:103DA0006481101CE3011AE3022AC67E2A5CFDD35B
+:103DB0000F6DAA0500B08800908C8940C0A00988CA
+:103DC000471FE32B080B47094C50090D5304DD1026
+:103DD000B4CC04CC100D5D029D310CBB029B30882D
+:103DE000438E2098350FEE029E328D26D850A6DDE8
+:103DF0009D268E40C0900E5E5064E0971CE3111E1D
+:103E0000E300038B0BC0F49FB19EB02D200A99B341
+:103E10000CDD029DB28F200CFF029FB48E262D2058
+:103E2000079EB68C282DB50A9CB72924072F20069B
+:103E30002B206469F339CBB61DE2E22320168DD224
+:103E40000B330C00D10400331AB48DA3C393292281
+:103E5000200C13E2E11FE2D80C2E11AFEEA32229B1
+:103E600024CF2FE285D2A00FDD0B2DE685D10F00E8
+:103E70002E200CB48C0CEB111FE2D81DE2CFAFEE5C
+:103E8000ADBB22B28529E4CF02C20B22B685D2A0F7
+:103E9000D10F00002E200C1CE2C81FE2CF0CEB114A
+:103EA000AFEEACBB22B28529E4CF02820B22B685ED
+:103EB000D2A0D10FC0D00BAD387DC80263FEEC6339
+:103EC000FEE08E40272C747BEE12DA70C0B32C3CDF
+:103ED00018DD50580A9B8940C08063FEE3066E02DD
+:103EE000022A02DB30DC40DD505800049A10DB501F
+:103EF000DA70580465881063FEF700006C100692B3
+:103F0000121EE2B98C40AE2D0C8C472E3C1804CA10
+:103F10000BD9A07DA30229ADF875C302600084C04F
+:103F2000B0C023C0A09D106D0844B89F0EB80A8D84
+:103F3000900EB70BB8770D6D36ADAA9D800D660C4F
+:103F4000D8F000808800708C879068B124B2227706
+:103F5000D3278891C0D0CB879890279C1000708879
+:103F600000F08C9D91CB6FC08108BB0375CB36638D
+:103F7000FFB4B1222EEC1863FFD485920D770C8626
+:103F8000939790A6D67D6B01B1559693959260005C
+:103F900016B3CC2D9C188810D9D078D3C729DDF85A
+:103FA00063FFC100C0238A421BE2C000CD322D4412
+:103FB000029B3092318942854379A1051EE2BC0EF5
+:103FC000550187121BE2AB897095350B9902993226
+:103FD00088420A880C98428676A6A696768F44AFC9
+:103FE000AF9F44D10F0000006C10089311D63088A9
+:103FF00030C0910863510808470598389812282165
+:1040000002293CFD08084C6581656591628A630A56
+:104010002B5065B18B0A6F142E0AFF7CA60A2C2048
+:104020005ACCC42D0A022D245A7FE0026002158961
+:104030002888261FE29F09880C65820F2E200B0F0F
+:10404000EE0B2DE0FE2EE0FF08DD110EDD021EE27C
+:1040500099AEDD1EE2991CE2990EDD010DCC37C14F
+:1040600080084837B88DB488981089601AE2557B6B
+:1040700096218B622AA0219C147BA3179D132A20D2
+:104080000C8B108C20580BCA8C148D13DBA0CEAC7B
+:104090006001C4002E200C1BE2480CEA110BAA0898
+:1040A0002BA2861FE2467BDB3B0FEF0A2FF2A368B1
+:1040B000F0052822007F892C2BA28564B0AA876294
+:1040C0008826DE700C7936097A0C6FAD1C8F279B21
+:1040D0001508FF0C77F3197E7B729D139C149B15BA
+:1040E000CF56600025C0B063FFD0D79063FFDD00DE
+:1040F000009D139C14DA20DB70580B2F8B158C1449
+:104100008D1365A06A8E6263FFCC00DA208B11DC10
+:1041100040580AD5D6A08B15C051DE70DA20DC607D
+:10412000DD405BFF768D138C14D9A02E200C1BE292
+:10413000221FE2290CEA11AFEFC0E0ABAA2BA28547
+:104140002EF4CF0B990B29A68563FF1D00DA20DC26
+:1041500060DD40DE708912282007DF50A9882824FE
+:10416000075BFF09D2A0D10F00DBE0DA20580B502B
+:104170006550EF2A20140A3A4065A0EBDB60DC4072
+:10418000DD30022A025809BCD6A064A0D584A183E0
+:10419000A00404470305479512036351C05163FE11
+:1041A0005C2C2006D30F28CCFD6480A568C704C012
+:1041B000932924062C2006C0B18D641FE2019D279F
+:1041C0009D289D298FF29D2600F10400BB1A00F066
+:1041D00004B0BE0EDD01C0F0ADBB8D652F24070D10
+:1041E0000E5E01EE11AEBB2E0AFEB0BB0B0B190E1C
+:1041F000BB36C0E20B0B470EBB372B241618E1F978
+:104200000A09450D0B422B240B29240AB4BE2E2487
+:104210000C7D88572920162FCCFDB09D0A5C520DCD
+:10422000CC362C246465FDEC0C0C4764CDE618E11B
+:10423000E48E2888820C9F0C00810400FF1AAFEEE8
+:104240009E2963FDCF1CE21163FE13001CE20B6389
+:10425000FE0C8D6563FFA500DA202B200C580B396E
+:10426000645F0FC020D10F00C020D10FC09329245C
+:1042700016C09363FFA000006C1004C06017E1CD6E
+:104280001DE1D0C3812931012A300829240A78A1EF
+:1042900008C3B27BA172D260D10FC0C16550512654
+:1042A00025022AD0202F200B290AFB2B20142E2098
+:1042B0001526241509BB010DFF0928F1202B241414
+:1042C000A8EE2EF52064A0A92B221E28221D011184
+:1042D000027B8901DB6064B0172CB00728B000DADC
+:1042E0002007880A28824CC0D10B8000DBA065AF74
+:1042F000E7DB30DC40DD50DA205800DE29210209FE
+:104300000B4CCAB2D2A0D10F00CC5A2C30087BC1C2
+:10431000372ED02064E02D022A02033B02DC40DD70
+:10432000505800D4D2A0D10F2B2014B0BB2B241492
+:104330000B0F4164F0797CB7CAC0C10C9C022C25DC
+:1043400002D2A0D10FC020D10F2E200669E2C126D3
+:1043500024062B221E2F221D29200B2820150D9903
+:10436000092A9120262415AA882895207BF14960E6
+:104370000048B0BB2B24140B0A4164A0627CB70236
+:104380002C25022B221E2C221DD30F7BC901C0B06D
+:10439000C9B62CB00728B000DA2007880A28824C5A
+:1043A000C0D10B8000DBA065AFE7C020D10F0000BB
+:1043B000262406D2A0D10F0000DB601DE18164BF7E
+:1043C0004F2CB00728B000DA2007880A28824CC09A
+:1043D000D10B8000DBA065AFE71DE17963FF310001
+:1043E00026240663FF9C00006C1004282006260A81
+:1043F000046F856364502A2920147D9724022A02C1
+:10440000DB30DC40DD50580019292102090A4CC874
+:10441000A2C020D10FC0B10B9B022B2502C020D11E
+:104420000F00022A02033B022C0A015800D1C9AA3C
+:10443000DA20DB30DC40580A0C29A011D3A07E978B
+:10444000082C0AFD0C9C012CA411C0512D2014062F
+:10445000DD022D241463FFA4DA20DB30DC40DD50C4
+:10446000C0E0580987D2A0D10F0000006C100616DA
+:10447000E1521CE152655157C0E117E14E2821027B
+:104480002D220008084C6580932B32000B695129BE
+:104490009CFD6590872A629E6EA84C2A722668A0B1
+:1044A000027AD9432A629DCBAD7CBE502B200C0CE6
+:1044B000BD11A6DD28D2862F4C0478FB160CBF0A4E
+:1044C0002FF2A368F0052822007F89072DD285D31B
+:1044D0000F65D0742A210419E17AD30F7A9B2EDA62
+:1044E00020580883600035002D21041BE1757DBB39
+:1044F00024DA20C0B658087ECA546001030B2B5042
+:104500002B240BB4BB0B0B472B240C63FFA0DA202E
+:10451000580A67600006DA20C0B6580A656550E0A0
+:10452000DC40DB302D3200022A020D6D515808D2DA
+:104530001CE123D3A064A0C8C05184A18EA00404B0
+:10454000470E0E4763FF3500002B2104C08B8931D5
+:10455000C070DF7009F950098F386EB8172C2066CB
+:10456000AECC0C0C472C24667CFB099D105808E44B
+:104570008D1027246694D11EE126B8DC9ED06550AC
+:1045800056C0D7B83AC0B1C0F00CBF380F0F42CBFD
+:10459000F119E10518E10728967EB04BD30F6DBAEB
+:1045A0000500A08800C08C2C200CC0201DE10B0C45
+:1045B000CF11A6FF2EF285ADCC27C4CF0E4E0B2E09
+:1045C000F685D10FC0800AB83878D0CD63FFC1001E
+:1045D0008E300E0E4763FEA12A2C742B0A01044D67
+:1045E000025808D72F200C12E0FC0CF911A699A252
+:1045F000FF27F4CF289285D2A008480B289685D1B2
+:104600000FC020D10F0000006C1004C060CB55DB40
+:1046100030DC40055D02022A025BFF942921020979
+:10462000084CC882D2A0D10F2B2014B0BB2B24146D
+:104630000B0C41CBC57DB7EBC0C10C9C022C2502F5
+:10464000D2A0D10F0000022A02033B02066C02C076
+:10465000D0C7F72E201428310126250228240A0F5E
+:10466000EE012E241458010E63FFA300262406D267
+:10467000A0D10F006C1006282102D62008084C6536
+:10468000809D2B200C12E0CC0CB811A2882A8286C7
+:10469000B5497A930260009719E0C909B90A2992CD
+:1046A000A36890082A620009AA0C65A08228828566
+:1046B0001CE0D46480799C80B887B14B9B819B10AF
+:1046C000655074C0A7D970280A01C0D0078D380D75
+:1046D0000D42CBDE1FE0B51EE0B62EF67ED830D3FD
+:1046E0000F6D4A0500808800908C2E3008C0A00015
+:1046F000EE322E740028600C19E0B80C8D11A2DD8A
+:10470000A988C0202CD2852284CFD2A00CBC0B2C2F
+:10471000D685D10FC0F0038F387FA0C063FFB400EF
+:10472000CC582A6C74DB30DC4058080BC020D10F09
+:10473000DA605809DF63FFE7DD402A6C74C0B0DC43
+:104740007058087F2E30088B1000EE322E7400282F
+:10475000600C19E0A10C8D11A2DDA988C0202CD21B
+:10476000852284CFD2A00CBC0B2CD685D10F0000A3
+:104770006C1004292014282006B19929241468817A
+:1047800024C0AF2C0A012B21022C24067BA004C0DC
+:10479000D02D2502022A02033B02044C02C0D0584D
+:1047A00000C0D2A0D10FC020D10F00006C1004298E
+:1047B0003101C2B429240A2A3011C28378A16C7B4A
+:1047C000A1696450472C2006C0686FC562CA572D86
+:1047D00020147CD722DA20DB30DC40DD505BFFA5E3
+:1047E000292102090E4CC8E2C020D10FC0F10F9F51
+:1047F000022F2502C020D10FDA20DB30C0C05BFFC2
+:10480000DC28201406880228241463FFC7292015F9
+:104810001BE06C2A200BC0C09C240BAA092BA120F2
+:104820002C2415AB9929A52063FF9900C020D10F36
+:10483000DA20DB30DC40DD50C0E0580891D2A0D156
+:104840000F0000006C1004CB5513E06725221F0DEC
+:10485000461106550CA32326221E25261F06440BAF
+:1048600024261E734B1DC852D240D10F280A80C087
+:104870004024261FA82828261E28261DD240D10FF6
+:10488000C020D10F244DF824261E63FFD80000005D
+:104890006C1004D620282006C0706E85026000D4FB
+:1048A0001DE04E19E04612E0442A8CFC64A1302B36
+:1048B0006102B44C0B0B4C65B0A22B600C8A600CEF
+:1048C000B8110288082E828609B90A7EC3026000E8
+:1048D0009A2992A368900509AA0C65A08E28828562
+:1048E000648088B8891BE04A94819B80655155C0DB
+:1048F000B7B8382A0A01C0C009AC380C0C4264C0F1
+:10490000421FE0291EE02B2EF67EB04AD30F6DAA7F
+:104910000500808800908CC0A029600C0C9C11A21E
+:10492000CC2BC285AD990B4B0B2BC6852860062777
+:1049300094CF6881222D6015D2A0C9D2C0E22E6426
+:1049400006D10F00C0F008AF387FB0BD63FFB100E3
+:10495000276406D2A0D10F00D2A0D10F00CC57DA25
+:1049600060DB30DC405808C0C020D10FDA60580945
+:104970005063FFE80028221E29221DD30F789901D9
+:10498000C080C1D6C1C11BE018C122AB6B6480429C
+:1049900078913F2A80000CAE0C64E0BB02AF0C643F
+:1049A000F0B52EACEC64E0AF0DAF0C64F0A92EAC0A
+:1049B000E864E0A32FACE764F09D2EACE664E097DA
+:1049C0002F800708F80BDA807B83022A8DF8D8A0A5
+:1049D00065AFBC28612308D739D97060007B00001F
+:1049E0002B600C0CB811A2882C82862A0A087CAB9A
+:1049F0007E09BA0A2AA2A368A0052C62007AC96FB0
+:104A00002A828564A0691FDFFE276504C0E3C0C455
+:104A10002E64069CA11CE02B9FA02E600A97A30C7D
+:104A2000EE029EA28F600CFF029FA42E60147AEF0C
+:104A30004627A417ADBC2F828527C4CF2FFC202F7B
+:104A4000868563FE692A6C74C0B1DC90DD4058072E
+:104A5000BC1DDFE163FEC100D9A0DA60DB30C2D04B
+:104A6000C1E0DC4009DE39DD50580805D2A0D10F85
+:104A7000DA6058090F63FEE4290A0129A4170DBF63
+:104A8000082E828527F4CF2EEC202E868564500BCD
+:104A90002A6C74DB4058017CD2A0D10FC020D10F0A
+:104AA0006C10062B221E28221D93107B8901C0B09A
+:104AB000C0C9C03BC1F20406401DDFCBC0E2C074D8
+:104AC0000747010E4E01AD2D9E11C0402E0A146401
+:104AD000B06E6D084428221D7B81652AB0007EA13E
+:104AE0003B7FA1477B51207CA14968A91768AA1484
+:104AF00073A111C09F79A10CC18B78A107C1AE2908
+:104B00000A1E29B4007CA12B2AB0070BAB0BDAB02C
+:104B10007DB3022ABDF8DBA0CAA563FFB428B0109C
+:104B200089116987BB649FB863FFDC00647FB4634D
+:104B3000FFD50000646FD0C041C1AE2AB40063FF4E
+:104B4000C62B2102CEBE2A221D2B221E7AB12A8C10
+:104B5000107CB1217AB901C0B0C9B913DF96DA204F
+:104B600028B0002CB00703880A28824CC0D10B80E3
+:104B700000DBA065AFE7D240D10F8910659FD463F9
+:104B8000FFF300006C1008C0D0C8598C30292102F6
+:104B90000C0C4760000C8E300E1E5065E19E2921E2
+:104BA00002C0C116DF85090B4C65B0908A300A6ED1
+:104BB0005168E3026000852F629E1BDF7E6EF85312
+:104BC0002BB22668B0052E22007BE94727629DB7ED
+:104BD00048CB7F97102B200CB04E0CBF11A6FF299D
+:104BE000F2869E12798B4117DF7507B70A2772A3E9
+:104BF000687004882077893029F285DF90D7906526
+:104C000090652A210419DFAE7A9B22DA205806B873
+:104C1000600029002C21041BDFAA7CBB18DA20C00D
+:104C2000B65806B3C95860014CC09063FFCCDA2077
+:104C300058089F600006DA20C0B658089D655135B7
+:104C4000DC40DB308D30DA200D6D5158070BC0D0C1
+:104C5000D3A064A120292102C05184A18CA0040406
+:104C6000470C0C4763FF3E00C09B8831DBD008F83F
+:104C700050089B3828210498116E8823282066ACA0
+:104C80008C0C0C472C24667CBB159F139E148A1039
+:104C90008B1158071B8E148F13C0D02D24668A30B9
+:104CA000C092C1C81BDF5B7FA6099BF099F12CF471
+:104CB0000827FC106550A4B83ADF70C051C08007C7
+:104CC000583808084264806718DF3819DF392986A8
+:104CD0007E6A420AD30F6DE90500A08800F08CC0FF
+:104CE000A08930B4E37F9628C0F207E90B2C940822
+:104CF0009B909F912F200C12DF380CF811A6882969
+:104D00008285A2FF2DF4CFD2A009330B238685D153
+:104D10000F22200C891218DF300C2B11A6BBA82201
+:104D20002D24CF2CB285D2A00C990B29B685D10F9A
+:104D3000C087C0900A593879809663FF8ADB30DAE1
+:104D400020C0C1C0D05BFF56292102C0D02A9CFEE2
+:104D500065AE4D2D2502C09063FE45009E142A2CA1
+:104D600074C0B1DC70DD405806F68E14C0D01BDF75
+:104D700028C1C863FF6AC020D10F00006C1006284C
+:104D8000210217DF0D08084C65824929729E6F9831
+:104D90000260025019DF082A922668A0078B200AB9
+:104DA000BB0C65B23F2A729DC0CB64A2371DDF04E5
+:104DB000C0602B3008C0F164B0712E0AFFB0B86437
+:104DC00081512DBCFE64D0F364505C2A2C74044BDA
+:104DD000025800AD0AA2020600000000001ADF0817
+:104DE0002C20076EBB0260022218DEFE13DF081BB8
+:104DF000DF36C0E229200A9AD09ED1ABCB039902BC
+:104E000099D223B08026B480B13308330293D318EB
+:104E1000DEF20CFD11A7DD2CD285A8F82684CF0C7C
+:104E2000EC0B2CD685655FA2C020D10F2B21048806
+:104E300031DE6008F85008CE386EB8102C2066B10C
+:104E4000CC0C0C472C24667CEB026001AF2E30109A
+:104E50002930112C301300993200CB3264E1452AFD
+:104E600030141EDF1A00AA3278CF050E9C092BC41D
+:104E70007F1CDF1766A0050E98092A8480B4A71846
+:104E8000DF15C76F009104AC9CDBC000AE1A00F3C5
+:104E90001A6EC1048BD00BCB0C1CDF0F08B81C069C
+:104EA0003303AC882A848B2CD03627848C03CC0126
+:104EB0000ECC022CD4365801AD63FF0B2F200C0C06
+:104EC000FB11A7BB2DB286C0987D9302600121190A
+:104ED000DEBB09F90A2992A36890082D220009DD9A
+:104EE0000C65D10C2DB285DE6064D10488312B2194
+:104EF0000408F85008CE386FB80263FEDF2C206635
+:104F0000B1CC0C0C472C24667CE30263FECE9D10D2
+:104F100060013100293108292504283014B0886443
+:104F200080A62B31092B240AC0812B30162FD423C5
+:104F30002B240BB4BC2C240C8D378B36292504DE96
+:104F4000D00D8E39DCB00B8C390ECC0264CE7808D3
+:104F50009C1101C4048F380DBE1800C4040DB8188C
+:104F600000881108FF02C08308CC0218DECC9CA187
+:104F700098A018DECB8C209EA39FA405CC110BCF4C
+:104F800053C1E09EA50CFF0208FF029FA218DE8914
+:104F90002624662C729D2684A22CCC182C769D6328
+:104FA000FE250000002D30121CDECD00DA3278DF45
+:104FB000050C9E0B2AE47F66B0050C9F0B2BF4803A
+:104FC0002A301100AA3263FEEC2E240A2B31099BF1
+:104FD0002B63FF5300CC57DA20DB30DC405807222C
+:104FE000C020D10F00DA20C0B65807B163FFE5003A
+:104FF00000DBF0DA205807AE63FFD9000058064006
+:105000001DDE70C0F126246663FE41008B20280A55
+:10501000FFB1CE23200A2C21040E0E472E24077840
+:1050200031359AD02CD50A96D319DEA62ED416C0C7
+:105030008398D1C0E309B80298D409390299D226DD
+:10504000240763FDC958062E8D102624662B2104E3
+:105050002F200C63FD86000008B81119DE6808EEE9
+:1050600002882B9ED59AD0C0EF09880298D204C935
+:10507000110E990299D4C0E49ED163FFC1000000D3
+:105080006C1004C020D10F006C100485210D381164
+:1050900014DE478622A42408660C962205330B935F
+:1050A00021743B13C862D230D10FC030BC29992182
+:1050B00099209322D230D10F233DF8932163FFE34F
+:1050C0006C100AD620941817DE3CD930B8389819DD
+:1050D0009914655256C0E1D2E02E61021DDE390EF0
+:1050E0000E4C65E1628F308E190F6F512FFCFD65FC
+:1050F000F1558EE129D0230E8F5077E66B8F181E65
+:10510000DE78B0FF0FF4110F1F146590CE18DE7516
+:105110008C60A8CCC0B119DE2728600B09CC0B0D20
+:10512000880929812028811E2A0A0009880C08BACA
+:10513000381BDE6B0CA90A2992947B9B0260008CC1
+:105140002B600C94160CBD11A7DD29D286B84879C6
+:1051500083026000D219DE1909B80A2882A39817C1
+:105160006880026000A36000A51ADE5F84180AEE62
+:1051700001CA981BDE108C192BB0008CC06EB313C3
+:105180001DDE0D0C1C520DCC0B2DC295C0A17EDB7B
+:10519000AE6000380C0C5360000900000018DE51AE
+:1051A0008C60A8CCC0B119DE0328600B09CC0B0DB4
+:1051B000880929812028811E2A0A0009880C08BA3A
+:1051C000380CA90A2992947E930263FF72DA60C0B8
+:1051D000BA58073764507360026A00001ADDF68C13
+:1051E000192AA0008CC06EA31A18DDF20C1C5208FC
+:1051F000CC0B18DE3B2BC295C0A178B30263FF3FF6
+:1052000063FFC9000C0C5363FF0989607899182962
+:10521000D285C9922B729E1DDDE76EB8232DD22652
+:10522000991369D00B60000DDA60580721600017F0
+:105230000088607D890A9A1A29729D9C129915CF5F
+:1052400095DA60C0B658071A6551F98D148C18DBD1
+:10525000D08DD0066A020D6D51580587D3A09A14DF
+:1052600064A1E182A085A1B8AF9F1905054702029C
+:10527000479518C05163FE602B6104C08B8931C013
+:10528000A009F950098A386EB81F2C6066A2CC0CB0
+:105290000C472C64667CAB119F119E1B8A15580528
+:1052A000988E1B8F11C0A02A64669F1164F0E58957
+:1052B0001388190FFD022E0A006DD9172F810300E4
+:1052C000908DAEFE0080889F9200908C008088B800
+:1052D0009900908C65514E8A10851A8B301FDDC85D
+:1052E000881229600708580A2C82942D61040ECC7C
+:1052F0000C2C86946FDB3C1CDDF4AC9C29C0800B2D
+:105300005D50A29909094729C48065D0DA2E600C46
+:10531000C0D01FDDB10CE811AFEEA7882282852D29
+:10532000E4CF02420B228685D2A0D10F8E300E0E22
+:105330004763FDA2A29C0C0C472C64077AB6CD8B68
+:10534000602E600A280AFF08E80C64810E18DDDD73
+:1053500083168213B33902330B2C34162D350AC051
+:105360002392319F30C020923308B20208E80292A3
+:10537000349832C0802864072B600CD2A01CDD96C4
+:105380000CBE11A7EE2DE285ACBB28B4CF0D9D0B52
+:105390002DE685D10F8B1888138D30B88C0D8F4773
+:1053A0000D4950B4990499100D0D5F04DD1009FFEB
+:1053B000029F800DBB029B8165508D851AB83AC053
+:1053C000F1C0800CF83808084264806B1BDD771947
+:1053D000DD7829B67E8D18B0DD6DDA0500A0880075
+:1053E000C08CC0A063FEF30082138B161DDD8828DD
+:1053F000600AC0E02EC4800D880202B20B99239F80
+:1054000020C0D298229D2122600CB2BB0C2D11A786
+:10541000DD28D28508BB0B18DD702BD685A8222E7F
+:1054200024CFD2A0D10F9E1B851A2A6C748B185BD7
+:10543000FF168E1B63FEA300C087C0900AF938795F
+:10544000809263FF86C020D10F9E1B2A6C74C0B16E
+:105450008D1858053B8E1B851A63FE7E886B821360
+:10546000891608BE110ECE0202920B9E25B4991E1B
+:10547000DD639F200E88029822C0EF04D8110E88A9
+:10548000029824C0E49E21C080D2A02B600C286426
+:10549000071CDD510CBE11A7EE2DE285ACBB28B474
+:1054A000CF0D9D0B2DE685D10F0000006C1004C0C0
+:1054B00020D10F006C10048633C071C03060000131
+:1054C000B13300310400741A0462017460F1D10F29
+:1054D0006C1004022A02033B025BFFF61CDD391B41
+:1054E000DD83C79F88B009A903098A019AB0798032
+:1054F0001EC0F00FE4311DDD300002002BD2821EF1
+:10550000DD7C2AC1020EBB022BD6820AE431D10F08
+:1055100028C102C19009880208084F28C50208E482
+:1055200031D10F006C1004C0C00CE43112DD251A1B
+:10553000DD2200020029A28218DD701BDD6E26210B
+:10554000020B990108660129A68226250206E4318C
+:1055500014DD6B15DD66236A9023261685502426FC
+:1055600015252617222C50D10F0000006C1008D6EC
+:10557000102B0A64291AB41ADD0F0D23111CDD103B
+:105580000F2511B81898130E551118DD5DAC55A8EC
+:1055900038AA332C80FF2A80FEA933288D01298068
+:1055A0000108AA112880000CAA02088811098802A3
+:1055B00008AA1C288C0828160458086814DD010A5B
+:1055C000A70224411A2A30802B120407AA2858085F
+:1055D00063B1338B13B4559A6004AC28B4662C566F
+:1055E0002B7B69E016DD3A9412C050C0D017DCF472
+:1055F0009D15D370D4102F60802E60829F169E1749
+:10560000881672891A8D128C402A607F0DCC282B47
+:105610003A200CAA28580851C0B10ABE372E354886
+:105620008F1772F91A8D128C402A60810DCC282BAD
+:105630003A200CAA28580849C0B10ABE372E354A6C
+:10564000B233B444B1556952B6B466C0508F15B880
+:1056500077D370B2FF9F156EF899D10F6C1004C00C
+:1056600021D10F006C1004270A001CDCD31FDCE4DE
+:105670001EDCE71DDCD01ADD141BDD22C02824B09F
+:10568000006D2A75AA48288080C09164806100411D
+:105690000415DCCBC03125503600361A06550105FD
+:1056A00095390C56110C66082962966E974D0D5966
+:1056B0000A29922468900812DD0602420872993B7A
+:1056C00023629512DCC8CB349F300282020E440262
+:1056D000C092993194329233AD52246295C0902495
+:1056E0004C1024669524B0002924A0AA42292480C5
+:1056F000B177B14404044224B400D10FD10FD10FCB
+:105700006C10041ADCAC2AA00058021C5BFFD50206
+:105710002A02033B025BFFD11BDCAAC9A12CB10208
+:10572000C0D40DCC020C0C4F2CB5020CE431D10FBF
+:10573000C0A00AE43118DCA00002002F828219DC2C
+:10574000B32EB10209FF022F86820EE431D10F0081
+:105750006C1004C02002E43114DC9A16DC970002BD
+:1057600000226282234102732F0603E431C020D15C
+:105770000F19DCE61ADCE52841020A2A0109880132
+:105780002A668228450208E43115DCDC12DCE125BA
+:105790004621D10F6C1004292006289CF96480A0B2
+:1057A0002A9CFD65A0968A288D262F0A087AD9049E
+:1057B0002B221FC8BD2C206464C0812E22090EAE8E
+:1057C0000C66E0782B200C1EDC7C0CBC11AECC28C7
+:1057D000C28619DC7A78F3026000AD09B90A299211
+:1057E000A36890082E220009EE0C65E09B29C28573
+:1057F0001FDC846490929F90C0E41FDC919E9128EE
+:10580000200AC0E09E930F8802989288200F880299
+:1058100098942F20079A979D962F950A2E24072853
+:10582000200629206468833328C28512DC6B288C0B
+:1058300020A2B22E24CF28C685C020D10FC020D1EF
+:105840000F2A206A0111020A2A4165AF52DA20C0EC
+:10585000B05805EA64AFE5C021D10F00649FC81FAE
+:10586000DC582D20168FF209DD0C00F10400DD1A42
+:10587000ADAD9D2912DC5928C285A2B22E24CF28B5
+:105880008C2028C685C020D10FC021D10F00000078
+:105890006C1004260A001BDC9F15DC4928206517C4
+:1058A000DC46288CFE6480940C4D110DBD082CD272
+:1058B000F52BD2F42ED2F77CB13DB4BB2BD6F47BC2
+:1058C000E9052BD2F62BD6F47CB92C2AD2F62AD6AF
+:1058D000F52AD6F406E4310002002872822AFAFF83
+:1058E000004104290A012F510200991A0A9903095B
+:1058F00088012876820FE4312624652BD2F48E5C51
+:105900002CD2F5B0EE9E5C7BCB1629D2F62FD2F7C7
+:105910000CB80C09FF0C08FF0C0F2F14C8F960001D
+:10592000320BCA0C0A2A14CEA92B5102C0C20CBBDE
+:10593000020B0B4F2B55020BE431D10F00DB30DA99
+:10594000205BFF941BDC7464AF5D0C4D11ADBD6337
+:10595000FFA8000006E4310002002F728218DC303C
+:105960002E510208FF022F76820EE431D10F000083
+:105970006C1004C03003E43116DC1015DC11000299
+:105980000024628274472118DC64875C084801287F
+:105990006682CD7319DC620C2A11AA99229283299E
+:1059A00092847291038220CC292B51020BE431C0E6
+:1059B00020D10F001FDC5B2E51020FEE012E55028D
+:1059C0000EE431B02DB17C9C5C12DC5608DD112D4B
+:1059D000561DD10F6C10061BDBF71EDBF922B00041
+:1059E0001ADC526F23721DDC39C04818DC511FDCF1
+:1059F0004FDC10D5C083F000808600508A6D4A4F7E
+:105A00000F35110D34092440800B560A296294B1D8
+:105A1000330E55092251480F44110C440A8740099E
+:105A2000A80C02883622514907883608770CA899B5
+:105A30002966949740296295874109A80C02883607
+:105A400007883608770CA899296695974103034281
+:105A5000B13808084298F0D10F1CDC3613DC372728
+:105A6000B0002332B5647057C091C0D016DC351534
+:105A7000DC33C0402AC00003884328C4006D793C51
+:105A8000004104B14400971A7780148E502FB295CC
+:105A90002DB695AFEE2EED2006EE369E5060001826
+:105AA00077A00983509D5023B69560000223B295DC
+:105AB000223D2006223622B695B455B8BBD10F0040
+:105AC00003884328C400D10F6C1004C04004E431A3
+:105AD00015DC1D000200885013DC1CCB815BFFBD70
+:105AE0001CDC1B0C2D11ADCC2BC2822AC28394501E
+:105AF0007BAB142EC28429C2850ABD0C0E990C0DF5
+:105B0000990C0929146000050BA90C092914993076
+:105B100015DBAC2A51020AE4312A2CFC58004B2B2D
+:105B200032000AA2022BBCFF9B30CCB6C8A4D2A084
+:105B3000D10F000004E4311EDBA00002002DE28240
+:105B40002FBAFF2C51020FDD012DE6820CE431D17A
+:105B50000F0000006C1004D10F0000006C1004C096
+:105B600020D10F006C100413DBFAC0D103230923EA
+:105B7000318FC0A06F340260008D19DB8F1BDB906A
+:105B800017DBF30C2811A8772672832572822CFA72
+:105B9000FF76514788502E7285255C0425768275E4
+:105BA000E9052572842576827659292E72842E760F
+:105BB000822E76830AE431000200239282002104BF
+:105BC0002FB10200D61A0C66030633012396820F0A
+:105BD000E43126728325728260000200D8A07659D3
+:105BE000220AE43100020023928200210400D21A2A
+:105BF0002FB1020C22030232012296820FE431D22D
+:105C000080D10F00D280D10FC020D10F6C1004DBE7
+:105C100030862015DB68280A00282502DA2028B003
+:105C2000002CB00705880A28824C2D0A010B800041
+:105C3000DBA065AFE61ADB610A4A0A29A2A3C7BF47
+:105C4000769101D10F2BA6A3D10F00006C1004C0D8
+:105C5000D1C7CF1BDB5B19DB5817DB560C2811A80B
+:105C60007786758574C0A076516288508E77B4555A
+:105C7000957475E903857695747659278F769F75A7
+:105C80009F740AE431000200239282B42E2FB102E5
+:105C900000E10400D61A0C66030633012396820F36
+:105CA000E431867583747639280AE4310002002EC7
+:105CB0009282B42200210424B10200DF1A0CFF03F7
+:105CC0000FEE012E968204E431D280D10FD8A07657
+:105CD00051D6D280D10F00006C1004290A801EDB3F
+:105CE0005D1FDB5D1CDB350C2B11ACBB2C2CFC2DA4
+:105CF000B2850FCC029ED19CD0C051C07013DB592D
+:105D000014DB5818DB562AB285A82804240A234637
+:105D100091A986B8AA2AB685A98827849F25649F59
+:105D2000D10F00006C100419DB8B0C2A11A9A98972
+:105D300090C484798B761BDB79ABAC2AC2832CC2EE
+:105D4000847AC1688AA02BBC30D3A064A05E0B2BE0
+:105D50000A2CB2A319DB4268C0071DDB7FD30F7D7D
+:105D6000C94AA929299D0129901F68913270A6036B
+:105D7000D3A0CA9E689210C7AF2AB6A32A2CFC5B98
+:105D8000FFB3D230D10F000013DB7503A3018C31B8
+:105D90001DDB130C8C140DCC012CB6A363FFDC00AF
+:105DA000C020D10FDA205BFFCCC020D10FC020D1A2
+:105DB0000F0000006C1004DB30C0D019DAFEDA20CE
+:105DC00028300022300708481209880A28824CDC53
+:105DD000200B80001BDAF90C4A11ABAA29A2840916
+:105DE000290B29A684D10F006C1004C04118DAF2E7
+:105DF00017DAF40C2611A727277038A866256286C3
+:105E0000007104A35500441A75414822628415DBD1
+:105E10001502320BC922882117DAF10884140744CD
+:105E200001754905C834C020D10FD10F0809471D9D
+:105E3000DB4AC0B28E201FDADF0E0E43AFEC2BC45C
+:105E4000A00FEE0A2DE6242A6284C0200A990B29AD
+:105E50006684D10FC020D10F6C1004DB30C0D01885
+:105E6000DAD5DA2025300022300708580A28824C7B
+:105E7000DC200B80008931709E121BDACF0C4A1196
+:105E8000ABAA29A28409290B29A684D10F09C952DA
+:105E900068532600910418DACAC0A12F811600AAFF
+:105EA0001A0AFF022F85161EDAC40C4D11AEDD2C26
+:105EB000D2840C2C0B2CD684D10FC0811FDAC1B830
+:105EC0009A0A0A472EF11600A10400881A08EE0269
+:105ED0002EF5161DDAB90C4C11ADCC2BC2840B2B50
+:105EE0000B2BC684D10F00006C1004DB30C0D0191E
+:105EF000DAB1DA2028300022300709880A28824CDB
+:105F0000DC200B80001CDAAC0C4B11ACBB2AB28439
+:105F10000A2A0B2AB684D10F6C1004C04118DAA6E5
+:105F200016DAA80C2711A626266038A87225228624
+:105F3000006104A35500441A7541082222840232EC
+:105F40000BD10F00C020D10F6C100415DB050249E6
+:105F5000142956112452120208430F8811C07300ED
+:105F6000810400361A008104C78F00771A0877036E
+:105F7000074401064402245612D10F006C10066E2D
+:105F800023026000AC6420A7C0A0851013DADD16E0
+:105F9000DAF4C040A6AA2BA2AE0B19416490666841
+:105FA000915D68925268933C2AA2AA283C7F288C73
+:105FB0007F0A0A4D2980012880002AACF208881146
+:105FC0000988027589462B3D0129B0002BB00108D4
+:105FD00099110B99027A9934B8332A2A00B1447284
+:105FE00049B160004A7FBF0715DADF63FFB90000DF
+:105FF000253AE863FFB10000253AE863FFA90000F5
+:10600000250A6463FFA1C05A63FF9C0000705F080B
+:106010002534FF058C142C34FE70AF0B0A8D142E22
+:106020003D012AE4012DE400DA405BFD5063FFA747
+:10603000D10FD10F6C10041ADA6219DA5F1CDACAB8
+:106040001BDACBC080C07160000D00000022A438B4
+:10605000B1AA299C107B915F26928679C2156E6247
+:1060600062C0206D080AB12200210400741A764B28
+:10607000DB63FFEE2292850D6311032514645FCF6D
+:10608000D650032D436DD9039820B4220644146DD5
+:106090004922982098219822982398249825982678
+:1060A000982798289829982A982B982C982D982EDC
+:1060B000982F222C4063FF971EDA4027E68027E6C0
+:1060C00081D10F00C02063FF830000006C1004C06A
+:1060D00062C04112DA3B1ADA3713DA522AA00023DF
+:1060E000322D19DA9F2BACFE2992AE6EA30260000E
+:1060F0008E090E402D1AC2C2CD0EDC392C251A6431
+:10610000B0895BFF9E15DA9A1ADA952B3AE80A3ABB
+:10611000015805922B211A0ABB28D3A09B50580581
+:10612000A92B52000ABB082A0A005805A815DA91C3
+:106130002D21022C3AE80C3C2804DD022D25029C7E
+:10614000505805A08B50AABBC0A15805A01CDA8AE4
+:106150002D21020C3C2806DD0213DA882D25029C35
+:10616000305805988B30AABBC0A25805982A210246
+:10617000C0B40BAA020A0A4F2A25025805ACD10F57
+:10618000242423C3CC2C251A63FF760018DA801C44
+:10619000DA7C19DA7D1BDA7B17DA4F85202E0AFDAF
+:1061A0001FDA7C2D203624F47A24F47E24F4820E27
+:1061B000DD0124F4862E0AF707552806DD02C07596
+:1061C0000EDD01050506AB5BA959C0E8AC5C24C433
+:1061D000AB0EDD0227C4AC2E0ADFA85527B4EC0EA7
+:1061E000DD0124B4EBC2E027942C0EDD0224942BB5
+:1061F0002E0A800D0D4627546C24546B0EDD022DA3
+:10620000243663FEFC0000006C10042A0A302B0ABE
+:10621000035BFF4D12DA53C390292616C3A1C0B306
+:10622000C08A2826175BFF48C03CC3B12B26161A2C
+:10623000D9E42AA02023261764A079C3A2C0B15BA9
+:10624000FF42C3A2C0B15BFF40C3C22C2616C2AF3F
+:10625000C0B12326175BFF3CC28F282616C0FE2F35
+:106260002617C2E22E26162A0AA1C0B1C0D82D26B2
+:10627000175BFF352A0AA12A2616C3A6C0B3C1920E
+:106280002926175BFF31C3C62C2616C1B32A0AA2E2
+:106290002B2617C0B35BFF2C290AA2292616C1851D
+:1062A000282617C2FB2F2616C0E72E26171DDA391F
+:1062B0002D2610D10FC3A2C0B35BFF2363FF820062
+:1062C0006C10041CDA031BD9ED18DA3317DA341614
+:1062D000DA3415DA34C0E0C0D414D9FF1FD9B9C0FC
+:1062E000288FF06D2A36DAC0D9C07C5B020FC90C4A
+:1062F0001CD9F90C9C28A8C3A6C22A36802A25845A
+:10630000A4C2A7CC2D248C2B248A2B24872E248B4B
+:10631000B1BB2E369F2C369E2C369DB1AC1CD9D7E6
+:106320001BDA22C0286D2A33DAC0D9C07C5B020F89
+:10633000C90C1CD9E80C9C28A8C3A6C22A36802BFD
+:106340002584A4C2B1BBA7CC2D248C2E248B2A2457
+:106350008A2E369F2C369E2C369DB1ACC07919D929
+:10636000D81BDA1413DA121ADA1218DA1314D9D97C
+:1063700016DA1304F42812DA1204660C040506A2D5
+:1063800052A858AA5AA3539B3029A50027848AC033
+:1063900091C0A52A848C29848B17DA0B18DA0AA7F6
+:1063A0005726361D26361E2E361F16DA0813DA0833
+:1063B000A65504330C2826C82E75002D54AC2E5437
+:1063C000AB2E54AA2326E62326E52E26E7D10F007E
+:1063D0006C100613D99417D9E224723D2232937FB0
+:1063E0002F0B6D08052832937F8F0263FFF3C0C423
+:1063F000C0B01AD973C051D94004593929A4206EAC
+:1064000044020BB502C3281ED96EDDB025E4220577
+:106410002D392DE421C0501ED9EF19D9DF18D9DF4D
+:1064200016D9E11DD9ED94102A724517D9AB6DA983
+:106430004BD450B3557A5B17DF50756B071FD9608B
+:106440008FF00F5F0C12D9A302F228AE2222D68160
+:10645000D54013D9A0746B0715D95A855005450C42
+:10646000035328B145A73FA832A93322369D2236CF
+:106470009E2436802B369F2BF48B2CF48C14D969F8
+:1064800024424DC030041414C84C6D0806B13304C6
+:106490001414C84263FFF20015D947C44000310408
+:1064A0001AD948C0D193A200DD1AC138B0DD9DA32E
+:1064B00018D95D2B824D29824E29A5202882537A36
+:1064C000871E2C54008E106FE45D12D93D2F2121C0
+:1064D0002321202F251F04330C23252023251ED103
+:1064E0000FC06218D99F88807E87D98910265400F2
+:1064F0006F94191BD9332AB1200A1A1404AA0C2A42
+:10650000B5202AB5212AB51E2AB51FD10F1BD92CBB
+:106510002AB1200A1A1403AA0C2AB5202AB5212A66
+:10652000B51E2AB51FD10F001CD9262BC1212DC1A4
+:10653000202BC51F03DD0C2DC5202DC51ED10F003E
+:106540006C100619D91F14D98612D93615D9A3C7CC
+:106550003FC0E02E56A82E56A92E56AA2E56AB2383
+:10656000262918D946DB101CD99DC0D42A42452DB6
+:1065700016012C160000B0890A880C98905BFF94D5
+:106580002C22E318D90F0C5C149C842B22E48C84FD
+:10659000B1BB0B5B140CBB0C9B852A22E50A5A1479
+:1065A0002A86062922CD0959142986072F22892FE8
+:1065B00086095BFF435BFF1423463BC1B01ED90035
+:1065C0001DD9602AE1022D463A0BAA020A0A4F2A77
+:1065D000E5025804965BFEBD5BFE96C050C0B01647
+:1065E000D8F614D8FE17D96FC0C0C73E93122C2618
+:1065F0002DC0306000440000007F9F0FB155091985
+:1066000014659FF4C0500AA9027FA7EF18D8EADAF0
+:106610005008580A28822C2B0A000B8000005104D5
+:10662000D2A0C091C7AF00991A0A99039912CE3827
+:1066300064206BD3202B20072516032C12022A621C
+:10664000827CA86318D8DC01110208580A28822C21
+:10665000DA500B8000D2A0643FD58A310A8A140434
+:10666000AA01C82A2B22010B8B1404BB017BA9456C
+:10667000DDA07A7B081DD8D22DD2000DAD0CDB3009
+:1066800019D8CD1AD91488130ADA28DC801DD951FB
+:1066900009880A28823C0DAA080B8000652F93D335
+:1066A00020C0B063FF9400007FAF34B155005004A8
+:1066B0000A091963FF42DAB07B7B081AD8C12AA203
+:1066C000000ABA0C1BD9048C310BAB280C8A141CA1
+:1066D000D941ACBB1CD94104AA012BC68163FF8FF1
+:1066E000645F60C050C0B0C7CE9C1263FF5500000D
+:1066F0006C100427221EC08008E4311BD8AF0002B2
+:10670000002AB28219D8AF003104C06100661A298C
+:1067100091020A6A022AB68209E43115D90C0C38B2
+:1067200011A8532832822432842A8CFC7841102903
+:1067300021022A368297A0096902292502D10F0079
+:106740002B21022C32850B6B022CCCFC2C36829731
+:10675000C02B2502D10F00006C1004C0E71DD89299
+:106760001CD8940D4911D7208B228A200B4B0BD2B9
+:10677000A007A80C9B72288CF4C8346F8E026000AE
+:10678000A31FD88AA298AF7B78B334C93DC081C01B
+:10679000F0028F380F0F42C9FA2CD67ED5206D4AF1
+:1067A0000500308800508C887008980878B16DD248
+:1067B000A09870D10FC0F0038F387FE0DE63FFD860
+:1067C000027B0CAFBB0B990C643047D830C0F1C0D2
+:1067D0005002F5380505426450792CD67E0B3612EE
+:1067E0002F6C100F4F366DFA0500808800208C0644
+:1067F000440CC081C05003B208237C0C03853805CB
+:10680000054264505A2CD67ED30F6D4A050020886D
+:1068100000308CD2A0A798BC889870D10FD2A0BCB1
+:10682000799970D10FD2302BAD08C0F1C0500BF563
+:1068300038050542CB542CD67E083F14260A100F8B
+:10684000660C0646366D6A0500208800B08C8270A2
+:1068500063FF2D00C05003F53875E08063FF7A00B8
+:10686000C06002863876E09F63FF9900C05003F550
+:106870003875E0C463FFBE006C1004D62068520F68
+:10688000695324DA20DB30DC405800F7D2A0D10F66
+:10689000DA20DB30DC405800F49A2424240EC02196
+:1068A00022640FC020D10F00B83BB04C2A2C748951
+:1068B000242D200E2E200FA4DDB1EE2E240FB0DDEE
+:1068C0002D240E2890072D9003A488B088B1DD2DCB
+:1068D00094032894075BFFA069511DC0E082242A1D
+:1068E000600F18D8BF2A240329600E8F202924079F
+:1068F00008FF029F209E64D10FC020D10F0000002E
+:106900006C1004942319D8B7C0B3083A110BAA022B
+:10691000992019D8299A2116D827C05028929D2548
+:1069200064A2288C1828969DD10F00006C100428B2
+:106930002066C038232406B788282466D10F0000BB
+:106940006C10060D3C111AD819D820035B0C862256
+:106950000D55118221AA8902320B928105630C9395
+:10696000820C550C792B54CB531CD8111DD80FC059
+:10697000F7A256C031C0A0043A380A0A42769343BF
+:10698000044302C9AB2CD67ED30F6DBA0500208814
+:1069900000308C8281A25272917D92818382C83EA6
+:1069A000D10FC071C06002763876F0DB63FFD5008E
+:1069B000C020BC89998199809282D10F222DF892B2
+:1069C0008163FFA219D7FA02860CA9669611D940F5
+:1069D000063612961006BB0C64A0442CD67E8A1094
+:1069E000D30F6DAA0500208800908CBC828311C053
+:1069F000E0A433240A01034E380E0E42CAEC2CD612
+:106A00007E6DBA0500208800308C821102520CA2E3
+:106A100082BC22928163FF83BC82928163FF7C00EF
+:106A2000C06002363876F0B563FFAF00C070024731
+:106A30003877F0CC63FFC6006C100414D7EBC1525A
+:106A4000A424CA3128221D73811C292102659016B5
+:106A50002A300075A912022A02033B022C3007C01B
+:106A6000D25801D5653FDCD10F2B300703BB0B0B90
+:106A7000BA0274B3022ABDF8D3A063FFC4000000B9
+:106A80006C1004292006C0706E9741292102C08F26
+:106A90002A2014C0B62B240606AA022A24147980C0
+:106AA000022725022A221E2C221D7AC10EC8ABDA2B
+:106AB00020DB302C0A00033D025BF7F96450892D7E
+:106AC00021020D0D4CC9D3C020D10F00002E9CFB1C
+:106AD00064E0962F21020F0F4C65F0A51AD7B71E60
+:106AE000D7B529A29EC08A798B712BE22668B004A3
+:106AF0008C207BC96629A29D1FD7B264905D9790B8
+:106B0000C0C31DD7C62B21049D9608BB110CBB0228
+:106B10009B919B971CD7C3C08527E4A22BA29D28DD
+:106B200024068DFA282102B0DD2BBC302BA69D9DBA
+:106B3000FA0C8802282502C8D2C020D10F8EF91283
+:106B4000D7B92E2689C020D10F283000688938DABD
+:106B500020DB30DC4058004463FF6300022A022B34
+:106B60000A065800D3220A00D10F655010293000C0
+:106B7000689924022A02033B02DC4058003BC020F3
+:106B8000D10FD270D10F00002A2C74033B02044CA9
+:106B9000025BFEF163FF2700DB30DC402A2C745BD4
+:106BA000FEEEC020D10F00006C1004C83F8926887B
+:106BB00029A399992609880C080848282525CC522C
+:106BC000C020D10FDB402A2C745BF92FD2A0D10F4B
+:106BD0006C1004D820D73082220D451105220C926A
+:106BE0008264207407420B13D771D420A3837323CC
+:106BF00002242DF8858074514CBC82C0906D08161B
+:106C000000408800708C773903D720C0918680744B
+:106C10003901D42074610263FFE2CA98C097C04171
+:106C20001BD7F2C0A00B8B0C0B4A380A0A42C9AA28
+:106C30001DD75E1CD75F2CD67EC140D30F6D4A0591
+:106C400000208800308C9780D270D10FBC8FC0E0BC
+:106C50000F4E387E90E263FFD6BC8292819280C054
+:106C6000209282D10F0000006C1006C0D71CD74EB6
+:106C70001BD7500D4911D7202E221F28221D0E4E42
+:106C80000BD280078A0C2E761F2AAC80C8346FAED8
+:106C9000026000CB2F0A801AD754A29EAA7A7EA344
+:106CA0003FC93FC0E1C05002E538050542CA552B37
+:106CB000C67EDB20D30F6D4A0500308800B08C2ED5
+:106CC000721DAE9E0EA50C645086D2802E761DC01D
+:106CD00091298403D10FC05003E53875D0D363FFE9
+:106CE000CD15D741027E0CA5EE643051C0A1250A16
+:106CF0000002A538033A020505426450922BC67E75
+:106D00000E35129510255C10054536D30F6D5A05CA
+:106D100000A08800208CC0A1A3E2C05023FA800309
+:106D2000730C03A538AF730505426450722BC67E01
+:106D3000851005450C6D5A0500208800308CD280E6
+:106D4000C0A10E9B0CAB7BAFBB2B761D2A8403D15D
+:106D50000FD280C0C1AF7D2D761D2C8403D10F00D2
+:106D6000D2302E8D08C0F1C0500EF538050542CB4B
+:106D7000592BC67E0A3F14C1600F660C064636D3F7
+:106D80000F6D6A0500208800E08C22721D63FF03EE
+:106D9000C061C05003653875D80263FF6263FF5C51
+:106DA000C05002A53875D08763FF8100C06003F62C
+:106DB0003876D0BF63FFB9006C10042A2015292053
+:106DC0001614D6FF0A990CCB9D2E200B04ED092B2F
+:106DD000D1208F2809BC36ACAA0CBB0C2BD5200ABD
+:106DE0000A472A2415CAAF8B438942B0A8009104F0
+:106DF00000881AA8FF0FBB029B278F260FB80C78BC
+:106E00003B1AC020D10F0000292102C0A20A99021A
+:106E1000292502C021D10F008B2763FFDC2BD12055
+:106E20000CAA0C0A0A472A2415ACBB2BD520C9AEE4
+:106E30008B438C288F42B0AD00F10400DD1AADCC3D
+:106E40000CBB029B27DA20B7EB580019C021D10FE9
+:106E50009F2763FFEF0000006C100428203C643083
+:106E60004705306000073E01053EB156076539050C
+:106E70004928C77FA933030641076603B1660606A2
+:106E800041A6337E871E222125291AFC732B150269
+:106E9000380C09816000063E01023EB124064239E9
+:106EA00003220AD10FD230D10FC05163FFC00000BE
+:106EB0006C100427221EC08008E4311DD6BF0002DA
+:106EC000002CD2821BD6BF003104C06100661A2B91
+:106ED000B1020C6C022CD6820BE43119D7440C3A67
+:106EE00011AA932832829780253282243284B455A5
+:106EF00025368275410A292102096902292502D114
+:106F00000F2A21022B32830A6A022B36822A25029B
+:106F1000D10F00006C100418D6A80C2711087708B0
+:106F2000267286253C04765B1315D6A405220A2218
+:106F300022A3682002742904227285D10FC020D1B7
+:106F40000F0000006C100419D6A727221EC080096C
+:106F5000770208E4311DD6980002002CD2821BD69D
+:106F600098003104C06100661A2BB1020C6C022C2F
+:106F7000D6820BE43119D71D0C3A11AA932832821C
+:106F80009780253282243284B45525368275410B90
+:106F90002A21020A6A022A2502D10F002B21022C83
+:106FA00032830B6B022C36822B2502D10F0000009E
+:106FB0006C10041BD6810C2A11ABAA29A286B43806
+:106FC000798B221BD67E19D6A50B2B0A2BB2A309CF
+:106FD000290868B00274B90D299D0129901F6E928D
+:106FE0000822A285D10FC020D10FC892C020D10F96
+:106FF000DA205BEE88C020D10F0000006C10041472
+:10700000D66E28429E19D66B6F88026000BA29920C
+:10701000266890078A2009AA0C65A0AC2A429DC068
+:10702000DC64A0A42B200C19D6650CBC11A4CC2EBA
+:10703000C28609B90A7ED30260009A2992A3689099
+:10704000078D2009DD0C65D08C25C2856450862D06
+:107050002104C0306ED80D2C2066B8CC0C0C472C07
+:10706000246665C07B1CD6E218D66B1AD66219D688
+:10707000731DD667C0E49E519D508F209357935542
+:1070800099539A569A5408FF021AD6839F5288261B
+:107090009F5A9E599D58935E9C5D935C9A5B08082D
+:1070A00048058811985FC0D81FD64C0CB911A49917
+:1070B000289285AFBF23F4CF288C402896858E2652
+:1070C0002D24069E29C020D10FCA33DA20C0B65B1A
+:1070D000FF78C72FD10FC93ADA205BFF75C72FD1D0
+:1070E0000FDBD05BFE072324662B200C63FF7500AB
+:1070F000C72FD10FC72FD10F6C1004C85B292006F2
+:1071000068941C689607C020D10FC020D10FDA20E8
+:10711000DB30DC40DD502E0A005BFE59D2A0D10FDF
+:107120002E200C18D6250CEF11A8FF29F286C08856
+:10713000798B791AD6220AEA0A2AA2A368A0048BBC
+:10714000207AB96823F2856430621BD62C290A8024
+:107150002C20682820672D21040B881104DD1108DC
+:10716000DD020DCC02C0842D4A100DCC021DD624A8
+:1071700098319D308A2B99379C340BAA02C0C09C51
+:10718000359C369A322A2C74DB4028F285C0D328ED
+:107190008C2028F6852C25042D24061FD60FDD40D3
+:1071A000AFEE2CE4CF5BFDE6D2A0D10F00DA20DBFE
+:1071B000E05BFF3FC020D10F6C100AD6302A2006BA
+:1071C00024160128ACF86583862B2122C0F22A21DF
+:1071D00024CC572AAC010A0A4F2A25247ABB026024
+:1071E000037F2C21020C0C4C65C3192E22158D3205
+:1071F000C0910EDD0C65D39088381ED5EF64836B8B
+:107200008C37C0B8C0960CB9399914B49A9A120D3B
+:10721000991199138F6718D5EAC9FB2880217F83BC
+:10722000168B142C22002A200C5BFF61D4A064A3CF
+:10723000B38F6760002800002B200C89120CBA1154
+:10724000AEAA2CA2861DD5DD7C9B3E0DBD0A2DD29B
+:10725000A368D00488207D893024A28564436427F4
+:10726000212E07F73607F90C6F9D01D7F0DA20DBE6
+:1072700070C1C42D211F5BFEF889268827DDA00977
+:10728000880C7A8B179A10600006C04063FFCC0010
+:1072900000DA208B105BFEC88D1065A267C0E09EEF
+:1072A000488C649C498B658A669B4A9A4B97458FAC
+:1072B000677F7302600120CD529D10DA20DB302CF5
+:1072C00012015BFE698D10C051D6A08FA7C0C08A85
+:1072D00068974D9A4C8869896A984E994F8E6A8A48
+:1072E00069AE7E77EB01B1AA9E6A9A698B60C0A0F5
+:1072F0000B8E1477B701C0A1C091C08493159D1760
+:107300009516C0D025203CC030085801089338C0DD
+:1073100082083310085B010535400B9D3807DD10EE
+:107320000BAB100E19402A211F07991003DD020D27
+:10733000BB020553100933020A55112921250A2AD7
+:10734000140929140499110A99020933028A2B2974
+:1073500021040BAA021BD6270899110955020855CA
+:10736000020BAA029A408920881408991109880200
+:1073700019D5A61DD62109880298418B2A934695D6
+:107380004783150DBB0285168D179B448A65896658
+:10739000AACAA97C77CB01B1AA07FB0C9C669A65A7
+:1073A00088268E29AD87972607EE0C0E0E482E25CF
+:1073B000259B672B200C87131ED5800CB911AE9925
+:1073C000289285A78828968517D584C090A7BB29C1
+:1073D000B4CF871863FE3C008C60C0E0C091C0F061
+:1073E000C034C0B82A210428203C08AA110B8B0104
+:1073F000038301039F380B9B39C03208FF100388B9
+:1074000001089E380C881407EE100FEE0203880165
+:1074100008983905BF1029211F0ABB1107881008D9
+:10742000FF020BAA0218D57809291403AA022B21FE
+:107430002583200B2B1404BB110833110FBB020B47
+:1074400099028B148F2A0B33020833028B2B647042
+:10745000868868974D984C8769886A9341994697C2
+:107460004E984FC07077C701C0719A4718D5E30B8B
+:107470007C100CEC0208F802984418D5E00CBC0211
+:1074800008CC029C402A200C295CFEC0801FD54AF3
+:107490001CD5520CAE112B2124ACAAAFEEB0BB8F81
+:1074A000132CE28528A4CFAFCC2CE6852A22152BFD
+:1074B0002524B1AA2A26156490DBC9D28F262E2254
+:1074C000090DFF082F26060FEE0C0E0E482E25255F
+:1074D0006550E4C020D10F00C07093419F4499468D
+:1074E0009A4777C70A1CD5362CC022C0810C873832
+:1074F0001CD5C40B781008E80208B8020C88029862
+:107500004063FF8000CC57DA20DB608C115BFDD636
+:10751000292102689806689403C020D10F2B221EEF
+:10752000C0A029221D2A25027B9901C0B064BFE8B2
+:1075300013D5212CB00728B000DA2003880A28824E
+:107540004CC0D10B8000DBA065AFE763FFCA000031
+:1075500068A779DA20DB30DC40DD505BFEE7D2A0A3
+:10756000D10FC16DC19D29252C60000429252CD681
+:10757000902624672F2468DA20DB308C11DD502E12
+:107580000A805BFD3FD2A0D10FC168C1A82A252C7B
+:1075900063FFDD000000C8DF8C268B29ADCC9C2664
+:1075A0000CBB0C0B0B482B25252A2C74DB602C12F2
+:1075B000015BFD87D2A0D10F2A2C748B115BF6B230
+:1075C000D2A0D10FDA205BFE3A63FF3800DA20C088
+:1075D000B15BFE8A64ABF1655F352D2124B1DD2DF1
+:1075E000252463FF1FDA202B200C5BFE5663FF145B
+:1075F00012D5858220028257C82163FFFC12D581F3
+:1076000003E83004EE3005B13093209421952263D5
+:10761000FFFC000010D57D910092019302940311AC
+:10762000D554821001EA30A21101F031C04004E4C7
+:107630001600020011D5768210234A00032202921E
+:107640001011D540C021921004E4318403830282DA
+:1076500001810000D23001230000000010D56D919F
+:107660000092019302940311D543821001EA30A2E3
+:107670001101F131C04004E41600020011D564820A
+:107680001013D4E7032202921004E431840383022E
+:107690008201810000D330013300000010D55E91DB
+:1076A00000810165104981026510448103CF1F925A
+:1076B000019302940311D531821001EA30A2110125
+:1076C000F231C04004E41600020011D550821013BC
+:1076D000D4CF032202921004E43184038302820196
+:1076E000C010910391029101810000D43001430048
+:1076F00012D500C03028374028374428374828376B
+:107700004C233D017233ED03020063FFFC000000D7
+:1077100010D542910092019302940311D54082103A
+:10772000921011D4F28310032202921011D53D124F
+:10773000D5049210C04004E41600020011D5348232
+:107740001013D4EB032202921004E4318403830269
+:107750008201810000D53001530000006C10026EE0
+:10776000322FD620056F04043F04745B2A05440CB5
+:1077700000410400331A220A006D490D73630403AB
+:10778000660CB1220F2211031314736302222C0121
+:10779000D10FC83BD10F000073630CC021D10F0083
+:1077A0000000000044495630C020D10F6C10020088
+:1077B00040046B4C07032318020219D10F0203196E
+:1077C000C020D10F6C100202EA30D10F6C1002CC35
+:1077D0002503F03160000F006F220503F1316000D6
+:1077E000056F230503F231000200D10F6C1002CCAB
+:1077F0002502F030D10F00006F220402F130D10FCA
+:107800006F230402F230D10FC020D10F6C1002227E
+:107810000A20230A006D280E2837402837442837CD
+:107820004828374C233D01030200D10F6C1002029F
+:10783000E431D10F0A0000004368656C73696F2062
+:1078400046572044454255473D3020284275696CD3
+:1078500074204D6F6E204D61722020382031373AF0
+:1078600032383A3135205053542032303130206F85
+:107870006E20636C656F70617472612E61736963F1
+:1078800064657369676E6572732E636F6D3A2F68F6
+:107890006F6D652F66656C69782F772F66775F3718
+:1078A0002E392D6977617270292C205665727369A3
+:1078B0006F6E2054337878203030372E30612E3080
+:1078C00030202D20313030373061303010070A0041
+:0478D0000BDFE8756D
+:00000001FF
diff --git a/firmware/cxgb3/t3fw-7.4.0.bin.ihex b/firmware/cxgb3/t3fw-7.4.0.bin.ihex
deleted file mode 100644
index 38dda94bfa6..00000000000
--- a/firmware/cxgb3/t3fw-7.4.0.bin.ihex
+++ /dev/null
@@ -1,1917 +0,0 @@
-:1000000060007400200380002003700000001000D6
-:1000100000002000E100028400070000E1000288E7
-:1000200000010000E0000000E00000A0010000006E
-:1000300044444440E3000183200200002001E0002A
-:100040002001FF101FFFD0001FFFC000E300043C91
-:100050000200000020006B741FFFC29020006BBCE8
-:100060001FFFC29420006BFC1FFFC29820006C7021
-:100070001FFFC29C200003C0C00000E43100EA3131
-:1000800000A13100A03103020002ED306E2A05000C
-:10009000ED3100020002160012FFDBC03014FFDA5F
-:1000A000D30FD30FD30F03431F244C107249F0D347
-:1000B0000FD30FD30F12FFD5230A00240A00D30F4A
-:1000C000D30FD30F03431F244C107249F0D30FD327
-:1000D0000FD30F14FFCE03421F14FFCB03421F1296
-:1000E000FFCCC0302D37302D37342D37382D373CED
-:1000F000233D017233ED00020012FFC4C0302F37E0
-:10010000002F37102F37202F3730233D017233ED6A
-:1001100000020012FFBEC0302737002737102737F4
-:1001200020273730233D017233ED03020012FFB95F
-:1001300013FFBA0C0200932012FFB913FFB90C028F
-:1001400000932012FFB8C0319320822012FFB71312
-:10015000FFB7932012FFB715FFB316FFB6C030D715
-:100160002005660160001B00000000000000000088
-:10017000043605000200D30FD30F05330C6E3B1479
-:100180000747140704437631E604360505330C6F40
-:100190003BED00020012FFA615FFA3230A00D720A3
-:1001A000070443043E0505330C0747146F3BF00377
-:1001B000020012FFA1C03014FFA1D30FD30FD30F41
-:1001C0009340B4447249F2D30FD30FD30F14FF9B63
-:1001D000834014FF9B834012FF9B230A0014FF9A65
-:1001E000D30FD30FD30F9340B4447249F2D30FD33C
-:1001F0000FD30F14FF95834012FF95C92F832084DE
-:10020000218522BC22743B0F8650B4559630B433FE
-:100210007433F463FFE60000653FE1655FDE12FFC3
-:100220007C230A0028374028374428374828374C91
-:10023000233D017233ED03020000020012FF7AC079
-:1002400032032E0503020012FF7813FF819320C0B2
-:1002500011014931004831010200C00014FF7E0441
-:10026000D23115FF7D945014FF7D04D33115FF7CEE
-:10027000945014FF7C04D43115FF7C24560014FFE5
-:100280007B04D53115FF7B24560010FF7A03000054
-:10029000000000000000000000000000000000005E
-:1002A000000000000000000000000000000000004E
-:1002B000000000000000000000000000000000003E
-:1002C000000000000000000000000000000000002E
-:1002D000000000000000000000000000000000001E
-:1002E000000000000000000000000000000000000E
-:1002F00000000000000000000000000000000000FE
-:1003000000000000000000000000000000000000ED
-:1003100000000000000000000000000000000000DD
-:1003200000000000000000000000000000000000CD
-:1003300000000000000000000000000000000000BD
-:1003400000000000000000000000000000000000AD
-:10035000000000000000000000000000000000009D
-:10036000000000000000000000000000000000008D
-:10037000000000000000000000000000000000007D
-:10038000000000000000000000000000000000006D
-:10039000000000000000000000000000000000005D
-:1003A000000000000000000000000000000000004D
-:1003B000000000000000000000000000000000003D
-:1003C000000000000000000000000000000000002D
-:1003D000000000000000000000000000000000001D
-:1003E000000000000000000000000000000000000D
-:1003F00000000000000000000000000000000000FD
-:1004000000000000000000000000000000000000EC
-:1004100000000000000000000000000000000000DC
-:1004200063FFFC000000000000000000000000006E
-:100430000000000000000000000000001FFC0000A1
-:100440001FFC0000E30005C81FFC00001FFC0000AB
-:10045000E30005C81FFC00001FFC0000E30005C806
-:100460001FFFC0001FFFC000E30005C81FFFC00042
-:100470001FFFC018E30005C81FFFC0181FFFC018EA
-:10048000E30005E01FFFC0181FFFC290E30005E076
-:100490001FFFC2901FFFC290E30008581FFFC290C9
-:1004A0001FFFC58CE3000858200000002000016AEF
-:1004B000E3000B542000018020000180E3000CC009
-:1004C0002000020020000203E3000CC02000021CF8
-:1004D00020000220E3000CC420000220200002269D
-:1004E000E3000CC82000023C20000240E3000CD0D6
-:1004F0002000024020000249E3000CD42000024CFE
-:1005000020000250E3000CE02000025020000259BD
-:10051000E3000CE42000025C20000260E3000CF029
-:100520002000026020000269E3000CF42000026C4D
-:1005300020000270E3000D0020000270200002790C
-:10054000E3000D042000028C2000028CE3000D105B
-:100550002000029020000293E3000D10200002AC66
-:10056000200002B0E3000D14200002D0200002F2AF
-:10057000E3000D18200003B0200003B0E3000D3CA1
-:10058000200003B0200003B0E3000D3C200003B0C6
-:10059000200003B0E3000D3C200003B0200003B0B6
-:1005A000E3000D3C200003B020006D94E3000D3CFF
-:1005B00020006D9420006D94E3007720000000007F
-:1005C00000000000000000001FFC00001FFC0000F5
-:1005D0001FFFC5901FFFC67020006D9820006D980A
-:1005E000DEFFFE000000080CDEADBEEF1FFFC2A064
-:1005F0001FFCFE001FFFC0941FFFC5C0300000009D
-:10060000003FFFFF8040000010000000080FFFFFC8
-:100610001FFFC26D000FFFFF804FFFFF8000000033
-:1006200000000880B000000560500000600000007D
-:1006300040000011350000004100000010000001E2
-:100640002000000000001000400000000500000035
-:1006500080000019040000000000080010000005E0
-:10066000806000007000000020000009001FF800FA
-:100670008000001EA0000000F800000007FFFFFF40
-:100680000800000018000000010080014200000086
-:100690001FFFC21D1FFFC0DC000100806040000082
-:1006A0001A0000000C0000001000000A00003000DA
-:1006B000600008008000001C000100008000001A9B
-:1006C00080000018FC0000008000000100004000D5
-:1006D000030000008000040050000003FFFFBFFF84
-:1006E0001FFFC3D400000FFFFFFFF000000016D073
-:1006F0000000FFF7A50000001FFFC4B01FFFC4618A
-:100700000001000800000B20202FFF801FFFC455B0
-:1007100000002C00FFFEFFF800FFFFFF1FFFC57861
-:1007200000002000FFFFDFFF0000FFEF01001100CD
-:100730001FFFC3D21FFFC590FFFFEFFF0000FFFBAD
-:100740001FFFC6301FFFBEA0FFFFF7FF1FFFC064E3
-:100750000000FFFD1FFFC6200001FBD01FFFC5B03A
-:100760001FFFC6601FFFC591E0FFFE001FFFC5A071
-:10077000000080001FFFC53C1FFFC5B41FFFC068FD
-:100780001FFFC4D01FFCFFD8000100817FFFFFFFC7
-:10079000E1000600000027101FFCFE301FFCFE7069
-:1007A000E10002001FFFC5381FFFC5500003D090B5
-:1007B0001FFFC5642B5063802B5079802B50908095
-:1007C0002B50A6801FFFC4690100110F202FFE00CF
-:1007D00020300080202FFF000000FFFF0001FFF805
-:1007E0002B50B2002B50B208000100102B50B180EA
-:1007F0002B50B2802B50BA00000100112B50BD28A5
-:100800002B50BC802B50BDA020300000DFFFFE002D
-:100810005000000200C0000002000000FFFFF7F4DB
-:100820001FFFC06C000FF800044000000010000023
-:100830000C4000001C400000E00000A01FFFC5406D
-:100840001FFD00081FFFC5541FFFC5681FFFC57CA3
-:10085000E1000690E10006EC00000000000000004E
-:100860000000000000000000010000000000000087
-:100870000000000000000000201000402010004098
-:100880002010004020140080200C0000200C0000EC
-:10089000200C000020100040201400802014008054
-:1008A00020140080201800C0201C0100201C010022
-:1008B000201C010020200140201800C0201800C08A
-:1008C000201800C0201C0100201800C0201800C003
-:1008D000201800C0201C01002020014020200140E1
-:1008E00020200140202009402020094020200940EC
-:1008F0002020094020240980FFFFFFFFFFFFFFFFAA
-:10090000FFFFFFFF000000000000000000000000EB
-:100910000000000000000000200054902000536000
-:1009200020005490200054902000529C2000529CA3
-:100930002000529C200050DC200050DC200050D4CD
-:100940002000504020004EE820004CC820004A9C67
-:100950000000000000000000200054602000532C24
-:10096000200053D0200053D0200051842000518417
-:10097000200051842000518420005184200050CC5C
-:100980002000518420004E0820004C7820004A4866
-:10099000000000000000000020000BE820003A30BA
-:1009A000200004C02000463C20000BE0200041480D
-:1009B000200003F0200045FC20004A2420003E5483
-:1009C00020003D70200039AC2000383C200035ACC0
-:1009D0002000310C20003BCC20002D6C2000280092
-:1009E000200067182000238C2000206C2000201895
-:1009F00020001D04200018182000154820000E2C8F
-:100A000020000C2C2000110C200012F82000434084
-:100A100020003E0820000BF0200004C00000000071
-:100A200000000000000000000000000000000000C6
-:100A300000000000000000000000000000000000B6
-:100A400000000000000000000000000000000000A6
-:100A50000000000000000000000000000000000096
-:100A60000000000000000000000000000000000086
-:100A70000000000000000000000000000000000076
-:100A80000000000000000000000000000000000066
-:100A900000000000000000000000000032640000C0
-:100AA0000000000032640000640064006400640020
-:100AB00064006400640064000000000000000000A6
-:100AC0000000000000000000000000000000000026
-:100AD0000000000000000000000000000000000016
-:100AE0000000000000000000000000000000000006
-:100AF00000000000000000000000000000000000F6
-:100B000000001000000000000000000000000000D5
-:100B100000000000000000000000100000000000C5
-:100B200000000000000000000000000000432380DF
-:100B300000000000000000000000000000000000B5
-:100B400000000000000000000000000000000000A5
-:100B500000000000005C94015D94025E94035F94C9
-:100B60000043000000000000000000000000000042
-:100B70000000000000000000000000000000000075
-:100B80000000000000000000000000000000000065
-:100B900000000000005C90015D90025E90035F9099
-:100BA00000530000000000000000000000000000F2
-:100BB0000000000000000000000000000000000035
-:100BC0000000000000000000000000000000000025
-:100BD00000000000009C94001D90019D94029E94D2
-:100BE000039F94040894050994060A94070B940043
-:100BF00043000000000000000000000000000000B2
-:100C000000000000000000000000000000000000E4
-:100C100000000000009C90019D90029E90071D9096
-:100C2000039F90047890057990067A90077B900056
-:100C30005300000000000000000000000000000061
-:100C400000000000000000000000000000000000A4
-:100C50000000000000DC94001D9001DD9402DE9491
-:100C600003DF94040494050594060694070794088A
-:100C700008940909940A0A940B0B9400430000009D
-:100C80000000000000000000000000000000000064
-:100C90000000000000DC9001DD9002DE900B1D9052
-:100CA00003DF9004B49005B59006B69007B790089E
-:100CB000B89009B9900ABA900BBB9000530000009D
-:100CC00063FFFC0020006B5010FFFF0A00000000D3
-:100CD00020006B7400D23110FFFE0A0000000000FB
-:100CE00020006BBC00D33110FFFE0A0000000000A2
-:100CF00020006BFC00D43110FFFE0A000000000051
-:100D000020006C7000D53110FFFE0A0000000000CA
-:100D100063FFFC00E00000A012FFF7822002825770
-:100D2000C82163FFFC12FFF303E83004EE3005C076
-:100D30003093209421952263FFFC00001FFFD00018
-:100D4000000400201FFFC5901FFFC670200A00117D
-:100D5000FFFB13FFFB03E63101020016FFFA17FF4A
-:100D6000FAD30F776B069060B4667763F85415B5C5
-:100D7000541A610F140063FFF90000006C1004C0E6
-:100D800020D10F006C1004C0C71AEF06D830BC2B5E
-:100D9000D72085720D4211837105450B9572023380
-:100DA0000C2376017B3B04233D089371A32D12EEA7
-:100DB000FE19EEFEA2767D632C2E0A000882022820
-:100DC0000A01038E380E0E42C8EE29A67E6D4A0532
-:100DD00000208800308C8271D10FC0F0028F387FE4
-:100DE000C0EA63FFE400C0F1C050037E0CA2EE0E27
-:100DF0003D1208820203F538050542CB5729A67E2D
-:100E00002FDC100F4F366DFA0500208800308CBCA7
-:100E100075C03008E208280A01058338030342C977
-:100E20003E29A67E0D480CD30F6D8A050020880050
-:100E3000B08C8271D10FC05008F53875C0C163FF06
-:100E4000BBC06002863876C0DA63FFD46C1012161D
-:100E5000EED8C1F9C1E8C1C72B221E28221DC0D07F
-:100E60007B81312920060BB702299CFA655008289E
-:100E70002072288CFF28247264915C2AB0000CA890
-:100E80000C6481670EA90C6492B37FA13769AC2F03
-:100E90006000340000282006D7D0288CFACC572ACE
-:100EA00020722AACFF2A24726481352AD0000CA952
-:100EB0000C6491640EAC0C64C31B7FA10768AC0783
-:100EC000C020D10F002D25028A32C0900A6E5065D5
-:100ED000E5B5292467090F4765F5B12C200C1FEEF5
-:100EE000B50CCE11AFEE29E286B4487983026005D5
-:100EF0008219EEB109C90A2992A36890078F2009C7
-:100F0000FF0C65F56E2FE28564F56865559628221D
-:100F10001D7B8105D9B060000200C0908B9417EE54
-:100F2000A70B881487740B0B47A87718EEA509BB8D
-:100F30001008770297F018EEA317EEA408A8010B8B
-:100F400088020747021BEEA097F10B880298F22750
-:100F500090232B902204781006BB1007471208BB81
-:100F6000022890210777100C88100788020B88024E
-:100F700017EE988B3307BB0187340B880298F397E1
-:100F80009997F48B9587399BF588968B3898F688D6
-:100F90009797F99BF898F717EE8F28E28507C7080F
-:100FA0002D74CF08480B28E68565550F2B221E2887
-:100FB000221D7B89022B0A0064BF042CB00728B0D5
-:100FC00000DA2006880A28824CC0D10B8000DBA002
-:100FD00065AFE763FEE90000292072659E9C60040E
-:100FE000E72A207265AEC36004DE00002EB0032C39
-:100FF0002067D4E065C1058A328C330AFF500C4566
-:1010000054BC5564F4EB19EE74882A09A9010988C7
-:101010000C64821FC0926000DD2ED0032A2067D4AA
-:10102000E065A0D88A328B330AFC500B4554BC557E
-:1010300064C4BE19EE69882A09A9017989D50BEA29
-:101040005064A4E30CEE11C0F02F16132E16168A6E
-:10105000E78CE82A16128EE9DFC0AAEA7EAB01B15E
-:10106000CF0BA8506583468837DBC0AE89991E78C0
-:101070009B022BCC012B161B29120E2B0A002916C2
-:101080001A7FC3077FC9027EAB01C0B165B49D8BD7
-:10109000352F0A002A0A007AC30564C3CB2F0A0140
-:1010A00065F4892B12162B1619005104C0C100CC0F
-:1010B0001A2CCCFF2C16170CFC132C16182B121AFA
-:1010C0002A121BDC50581974C0D0C0902E5CF42C2E
-:1010D00012172812182F121B2A121A08FF010CAA25
-:1010E000018834074C0AAB8B2812192BC6162F86A1
-:1010F000082A86092E74102924672E70038975B179
-:10110000EA2A7403B09909490C659DB32B20672D19
-:10111000250265B3FA2B221E2C221D7BC901C0B00B
-:1011200064BD9C2CB00728B000DA2006880A28820B
-:101130004CC0D10B8000DBA065AFE763FD8189BAAD
-:10114000B19965909788341CEE2598BA8F331EEEBE
-:101150001E0F4F542FB42C8D2A8A320EDD020CAC98
-:10116000017DC9660A49516F92608A3375A65B2C6E
-:10117000B0130AED510DCD010D0D410C0C417DC98F
-:10118000492EB012B0EE65E3C6C0D08E378CB88A57
-:10119000368FB97CA3077AC9027EFB01C0D1CED9B4
-:1011A00088350AAD020E8E0878EB022DAC0189B7A6
-:1011B000DAC0AF9B79BB01B1CADCB0C0B07DA30778
-:1011C0007AD9027CEB01C0B164B161C09129246776
-:1011D000C020D10F00008ADAB1AA64A0C02C206719
-:1011E0002D250265C3111DEDF88A321EEDFD0DADF2
-:1011F000010EDD0C65D28A0A4E516FE20260028157
-:10120000C090292467090F4765F2F828221D7B89C1
-:10121000022B0A0064BCA82CB00728B000DA200614
-:10122000880A28824CC0D10B8000DBA065AFE76341
-:10123000FC8D00000CE9506492ED0CEF11C0802889
-:101240001611AFBF2F16198EF88BF7DAE08FF92B36
-:101250001610ABFB7FBB01B1EA0CA8506580D688A5
-:1012600037DCE0AF89991C789B022CEC012C161B13
-:1012700029120C2C0A0029161A7AE3077AE9027F50
-:10128000BB01C0C165C2A58B352C0A002A0A007AB1
-:10129000E30564E1CA2C0A0164CE0D60028E883435
-:1012A0001BEDCF98DA8F331EEDC80F4F542FD42C7F
-:1012B0008C2A8A320ECC020BAB010CBB0C65BF0A28
-:1012C0000A49516E920263FF018A330AAB5064BE31
-:1012D000F92CD0130AEE510ECE010E0E410C0C412A
-:1012E0000ECC0C65CEE42FD012B0FF65F26EC0B00C
-:1012F0008E378CD88A362FD2097CA3077AC9027E12
-:10130000FB01C0B165BEC38835DBA0AE8E78EB01B2
-:10131000B1AB89D7DAC0AF9D79DB01B1CAC0C07B60
-:10132000A3077AB9027DEB01C0C165CE9DC09029AB
-:101330002467C020D10F88378C3698140CE90C290B
-:10134000161408F80C981D78FB07281214B088288A
-:101350001614891D9F159B16C0F02B121429161AFE
-:101360002B161B8B147AE30B7AE90688158E1678F8
-:10137000EB01C0F165F1BA29121A2F12118A352E2C
-:10138000121B9A1AAFEE2F1210C0A0AF9F79FB016B
-:10139000B1EE9F11881AC0F098107AE30A7EA90571
-:1013A0002A12017A8B01C0F164F0816001838936D1
-:1013B0008B3799170BE80C981F09C90C291615785B
-:1013C000EB07281215B088281615D9C09A199E184F
-:1013D0008A1F2E12152A161A2E161BDAC0C0E08C90
-:1013E000177F930B7FA90688188F1978FB01C0E13E
-:1013F00065E13E29121A2F12138A352E121B9A1BF1
-:10140000AFEE2F1212C0A0AF9F79FB01B1EE9F1378
-:10141000881BC0F098127AE30A7EA9052A12037A83
-:101420008B01C0F165F10A2E12162E16192A121B15
-:10143000005104C0E100EE1AB0EE2E16170EFF1395
-:101440002F16180FCC01ACAA2F121A0EBC01ACFC3F
-:101450007FCB01B1AA2A161B2C161A63FC5E000072
-:101460007FB30263FE3163FE2B7EB30263FC306305
-:10147000FC2A00006450C0DA20DBC0581648C020A7
-:10148000D10FC09163FD7A00C09163FA44DA20DB8A
-:1014900070C0D12E0A80C09A2924682C7007581574
-:1014A00038D2A0D10F03470B18ED4FDB70A8287876
-:1014B00073022B7DF8D9B063FA6100002A2C74DB2B
-:1014C00040580EB363FAE4000029221D2D25027B4B
-:1014D0009901C0B0C9B62CB00728B000DA20068840
-:1014E0000A28824CC0D10B8000DBA065AFE7C0208A
-:1014F000D10FC09163FBFF00022A025802440AA2E6
-:1015000002060000022A025802410AA20206000056
-:10151000DB70DA20C0D12E0A80C09E2924682C708E
-:1015200007581517C020D10FC09463FBC9C096633C
-:10153000FBC4C09663FBBF002A2C74DB30DC405B2D
-:10154000FE11DBA0C2A02AB4002C200C63FF2700F0
-:101550008D358CB77DCB0263FDD263FC6D8F358EEC
-:10156000D77FEB0263FDC563FC6000006C1004C014
-:1015700020D10F006C1004C020D10F006C10042B80
-:10158000221E28221DC0A0C0942924062A25027BE1
-:101590008901DBA0C9B913ED06DA2028B0002CB010
-:1015A0000703880A28824CC0D10B8000DBA065AFFE
-:1015B000E7C020D10F0000006C10042C20062A2167
-:1015C0000268C80528CCF965812E0A094C6591048A
-:1015D0008F30C1B80F8F147FB00528212365812774
-:1015E00016ECF529629E6F98026000F819ECF1295B
-:1015F00092266890078A2009AA0C65A0E72A629DB6
-:1016000064A0E12B200C0CB911A6992D92866FD9FC
-:10161000026000DB1DECE90DBD0A2DD2A368D007E6
-:101620008E200DEE0C65E0C7279285C0E06470BF88
-:101630001DECEE68434E1CECED8A2B0CAA029A704E
-:1016400089200899110D99029971882A98748F320E
-:101650009F75282104088811987718ECDE0CBF11BB
-:10166000A6FF2DF285A8B82E84CF2DDC282DF68577
-:10167000C85A2A2C74DB40580E46D2A0D10FC02085
-:10168000D10F00000029CCF96490B12C206689317B
-:10169000B1CC0C0C472C24666EC60260008509F89C
-:1016A0005065807F1CECD38A2B0F08400B881008F4
-:1016B000AA020CAA029A7089200899110D99029920
-:1016C00071883398738C329C728A2A9A74893499FF
-:1016D0007563FF7D00CC57DA20DB30DC4058151DE8
-:1016E000C020D10F00DA20C0B65815AC63FFE5006A
-:1016F000DA205815AA63FFDC00DA20DB30DC40DD9D
-:1017000050581638D2A0D10FC858DA20DB30581400
-:101710008A2A210265AFBDC09409A9022925026366
-:10172000FFB200002B21045814351DECAFC0E02E91
-:1017300024668F302B200C0F8F1463FF662921380D
-:10174000C08879830263FF5B2C20662B2104B1CC17
-:101750000C0C472C24665814291DECA3C0E02E2441
-:10176000668F302B200C0F8F1463FF376C1004C072
-:10177000B7C0A116ECA015EC92D720D840B822C073
-:10178000400535029671957002A438040442C94B95
-:101790001AEC8519EC8629A67EC140D30F6D4A0547
-:1017A00000808800208C220A88A272D10FC05008C5
-:1017B000A53875B0E363FFD76C1006931394112915
-:1017C0002006655288C0716898052A9CF965A29820
-:1017D00016EC792921028A1309094C6590CD8AA05B
-:1017E0000A6A512AACFD65A0C2CC5FDB30DA208CDE
-:1017F000115814D8C0519A13C7BF9BA98E132EE25B
-:101800000968E0602F629E1DEC6A6FF80260008438
-:101810002DD22668D0052F22007DF9782C629DC735
-:101820009064C0709C108A132B200C2AA0200CBD41
-:1018300011A6DD0A4F14BFA809880129D286AF88F6
-:10184000288C09798B591FEC5C0FBF0A2FF2A36813
-:10185000F0052822007F894729D285D490659075AC
-:1018600060004300002B200C1FEC540CBD11A6DDC2
-:1018700029D2860FBF0A6E96102FF2A368F0048853
-:10188000207F890529D285659165DA20581543C9DD
-:101890005C6001FF00DA20C0B658154060000C0003
-:1018A000C09063FFB50000DA2058153C6551E48D07
-:1018B000138C11DBD08DD0022A020D6D515813AD5F
-:1018C0009A1364A1CEC75F8FA195A9C0510F0F478E
-:1018D0009F1163FEFD00C091C0F12820062C2066F8
-:1018E000288CF9A7CC0C0C472C24666FC6098D13E5
-:1018F0008DD170DE02290A00099D02648159C9D385
-:101900008A102B21045813BD8A13C0B02B24662ED5
-:10191000A2092AA0200E28141CEC338D1315EC27E5
-:10192000C1700A773685562DDC28AC2C9C12DED08F
-:10193000A8557CD3022EDDF8D3E0DA40055B02DC4B
-:10194000305BFF8AD4A028200CB455C0D02B0A8865
-:101950002F0A800C8C11A6CC29C285AF3FAB9929E8
-:10196000C6851CEC1CDEF0AC882D84CF2812022921
-:10197000120378F3022EFDF8289020D3E007880C9C
-:10198000C170080847289420087736657FAB891313
-:1019900013EC1A8990C0F47797491BEC18C1CA2838
-:1019A00021048513099E4006EE1187530488118592
-:1019B000520E88020C88029BA09FA18F2B9DA59898
-:1019C000A497A795A603FF029FA22C200C1EEC0152
-:1019D000AECE0CCC1106CC082BC2852DE4CF2BBC8F
-:1019E000202BC6852A2C748B11580D69D2A0D10FDB
-:1019F00028203DC0E07C877F2E24670E0A4765A023
-:101A00007B1AEBFF88201EEBED8F138EE48FF4081A
-:101A100088110A88020F8F14AFEE1FEBFA98910F0E
-:101A2000EE029E901EEBF9C0801AEBEA2CD285AA3A
-:101A3000BAB8CC28A4CF2CD6852C21022F20720E28
-:101A4000CC02B1FF2F24722C2502C020D10F8713A6
-:101A5000877007074763FD6E282138C099798B028C
-:101A600063FE9ADDF063FE9500DA20DB308C11DD39
-:101A70005058155CD2A0D10FC0E163FF7A8B138C54
-:101A800011DD50C0AA2E0A802A2468DA205813BC1F
-:101A9000D2A0D10FC020D10F6C1006292102C0D0D6
-:101AA0007597102A32047FA70A8B357FBF052D2535
-:101AB000020DD902090C4C65C18216EBBE1EEBBCAF
-:101AC00028629EC0FA78F30260018829E2266890B5
-:101AD000078A2009AA0C65A17A2A629DDFA064A169
-:101AE000772B200C0CBC11A6CC29C286C08C798324
-:101AF0000260015719EBB109B90A2992A36890074E
-:101B0000882009880C65814327C2851CEBB364716A
-:101B10003A8931098B140CBB016FB11D2C20669FD3
-:101B200010B1CC0C0C472C24666EC6026001400933
-:101B3000FF5065F13A8A102AAC188934C0C47F97E7
-:101B40003C18EBB31BEBB28F359C719B708B209DC7
-:101B50007408BB029B72C08298751BEBAE0F0840E5
-:101B60009B730F881198777FF70B2F2102284A006B
-:101B700008FF022F2502C0B4600004000000C0B0BE
-:101B80007E97048F362F25227D97048837282521BC
-:101B90007C9736C0F1C0900AF9382F3C20090942E1
-:101BA00064908619EB8018EB8128967E00F08800FF
-:101BB000A08C00F08800A08C00F08800A08C2A6225
-:101BC0009D2DE4A22AAC182A669D89307797388F1C
-:101BD000338A3218EB8A07BE0B2C2104B4BB04CC29
-:101BE0001198E0C08498E1882B9DE59AE69FE71A5A
-:101BF000EB82099F4006FF110FCC020A880298E28F
-:101C0000C1FC0FCC022CE604C9B82C200C1EEB71D1
-:101C10000CCA11AECC06AA0829A2852DC4CF09B9D9
-:101C20000B29A685CF5CC020D10FC081C0900F8941
-:101C300038C08779880263FF7263FF6600CC57DA89
-:101C400020DB30DC405813C3C020D10FDA205814F9
-:101C50005363FFE8C0A063FE82DA20C0B658144F79
-:101C600063FFD900DB402A2C74580CC9D2A0D10FD5
-:101C70008A102B21045812E11EEB4EC0D02D246691
-:101C800063FEB1006C1006D62019EB491EEB4B2801
-:101C9000610217EB4808084C65805F8A300A6A5178
-:101CA00069A3572B729E6EB83F2A922668A0048CB7
-:101CB000607AC9342A729D2C4CFECAAB2B600CB6DC
-:101CC0004F0CBD11A7DD28D2860EBE0A78FB269CDC
-:101CD000112EE2A32C160068E0052F62007EF91594
-:101CE00022D285CF2560000D00DA60C0B658142BD3
-:101CF000C85A60010F00DA60581428655106DC40AC
-:101D0000DB308D30DA600D6D5158129AD3A064A08B
-:101D1000F384A1C05104044763FF6D00C0B02C6080
-:101D2000668931B1CC0C0C472C64666FC602709684
-:101D30000A2B61045812B1C0B02B64666550B42AF6
-:101D40003C10C0E7DC20C0D1C0F002DF380F0F42EA
-:101D500064F09019EB1418EB1528967E8D106DDA4F
-:101D60000500A08800C08CC0A089301DEB247797A7
-:101D70005388328C108F3302CE0BC02492E1226143
-:101D8000049DE00422118D6B9BE59FE798E61FEB15
-:101D90001A0998400688110822020FDD02C18D9DA4
-:101DA000E208220292E4B4C22E600C1FEB0A0CE897
-:101DB00011A7882C8285AFEE0C220B2BE4CF228654
-:101DC00085D2A0D10F28600CD2A08C1119EB020C87
-:101DD0008D11A988A7DD2ED2852B84CF0ECC0B2C9C
-:101DE000D685D10FC0F00ADF387FE80263FF6C634D
-:101DF000FF6000002A6C74C0B2DC20DD4058128FF6
-:101E0000C0B063FF63C020D10F0000006C10042C31
-:101E1000221D2A221EC049D320293006243468C03E
-:101E2000407AC105DDA060000200C0D06E9738C0C6
-:101E30008F2E0A802B3014C0962934060EBB022E3A
-:101E400031022B34147E8004243502DE407AC10E28
-:101E5000C8ABDBD0DA302C0A00580AE52E31020E6E
-:101E60000F4CC8FEC020D10F6895F8283102080831
-:101E70004C658FEF1AEAD01CEACE2BA29EC09A7B4B
-:101E80009B462BC22668B0048D307BD93B29A29D8E
-:101E9000C0E3CB9394901BEAE02D31049B9608DDC0
-:101EA000110EDD029D979D9112EADDC0E524C4A2CA
-:101EB0002E34062F310228A29D02FF02288C3028E2
-:101EC000A69D2F3502C020D10FDA30C0B65813B30B
-:101ED000C020D10F6C1006292006689805289CF9AF
-:101EE00065825D29210209094C659210CD51DB30D4
-:101EF000DA20044C02581317C051D3A0C7AF2A36BA
-:101F00000AC0E019EAAD1DEAB31FEAAC8A3A16EA44
-:101F1000A9B1AC64C13528629E6F88026001F129C5
-:101F2000DC332992266890078B2009BB0C65B1E051
-:101F300027629DC08E6471D82B200C0CBC11A6CCDE
-:101F400029C2867983026001D219EA9B09B90A295C
-:101F500092A3971068900828220009880C6581BB1D
-:101F600027C2856471B5292006299CF96491EC2C5F
-:101F700020668931B1CC0C0C472C24666EC60260F9
-:101F800001A109F85065819B883689F4088C14AC4E
-:101F9000991CEA8B0C99022C2104997019EAA1086A
-:101FA00008479971892A09881008990218EA9E0839
-:101FB000990299722830132930120488100699105A
-:101FC00008990228302C9A740C881008C8020988D5
-:101FD00002987389379975883898768A39C0819ABA
-:101FE000771AEA918935987B99780989140A9902B8
-:101FF000997A8A30893277A73618EA808F33987CAD
-:10200000C084987D882B2E76112976122F7613198D
-:10201000EA7A0A9F4006FF1104CA110988020FAA32
-:1020200002987EC1F90FAA022A7610C0AA600001A8
-:10203000C0A6ADBF0CBC11A6CC29C2852EF4CF0919
-:10204000A90B29C685655107C020D10F2B200C0C88
-:10205000BC1106CC0828C28609B90A6F8902600142
-:102060002E2992A36890082A220009AA0C65A11FB4
-:102070002AC28564A11928203D08284064808C84E8
-:102080003504841464408485F574537F8436048455
-:1020900014644077745374293013C08C79886CC0F1
-:1020A000902924670908476580ED882089F48435E4
-:1020B0001FEA55048414A4940F440294A014EA5017
-:1020C00008881104880298A1843698A3048414A473
-:1020D000990F990299A219EA4CADB428C2852E44F1
-:1020E000CF288C1028C6852821022F20720988024B
-:1020F000B2FF2F2472282502C020D10F00CC57DA5E
-:1021000020DB30DC40581293C020D10FC09163FF18
-:102110008FDA20C0B658132163FFE100DA2058138C
-:102120001F63FFD88A102B21045811B41DEA2A1FFF
-:10213000EA232B200CC0E02E24668A3A63FE480076
-:1021400000DA20DB30DC40DD505813A6D2A0D10FDE
-:102150002A2C74DB40580B8ED2A0D10F292138C015
-:102160008879830263FE202A12002C20662B21042A
-:102170002CCC010C0C472C24665811A01DEA161F0C
-:10218000EA0F2B200CC0E02E24668A3A63FDF8008B
-:10219000DA2058130263FF64DA205BFF1CD2A0D15F
-:1021A0000F0000006C10089515C061C1B0D9402A1D
-:1021B000203DC0400BAA010A64382A2006291606D1
-:1021C00068A8052CACF965C33B1DE9FC6440052FEC
-:1021D000120564F29C2621021EE9F806064C65628F
-:1021E000E315E9F46440D98A352930039A140A9931
-:1021F0000C6490CC2C200C8B149C110CCC11A5CC15
-:102200009C122CC286B4BB7CB3026002D38F110E29
-:10221000FE0A2EE2A368E0098620D30F0E660C6545
-:1022200062BE88122882856482B6891464905EDA60
-:1022300080D9308C201EE9F21FE9F31DE9E08B14F0
-:102240008DD4D4B07FB718B88A293C10853608C61B
-:10225000110E66029681058514A5D50F550295804D
-:102260000418146D8927889608CB110888140EBBB2
-:1022700002A8D8299C200F88029BA198A088929B35
-:10228000A3088814A8D80F880298A22AAC1019E9CC
-:10229000DEC0C08F141EE9CF86128D11286285AE74
-:1022A000DD08FF0B2CD4CF2821022F66858B352A21
-:1022B0002072098802ABAA2825022A2472C020D1E4
-:1022C0000F29529E18E9BB6F9802600208288226E7
-:1022D00068800829220008990C6591F92A529DC14D
-:1022E000CA9A1364A1EF2B200C2620060CB811A566
-:1022F000882D82860EBE0A7DC3026002022EE2A3F2
-:1023000068E0082F22000EFF0C65F1F3288285DEBD
-:10231000806481FF9810266CF96461FF2C20668828
-:1023200031B1CC0C0C472C24666EC6026001BC088F
-:10233000FD5065D1B617E9BD19E9A21AE9A92C210A
-:10234000048B2D2830102F211D0C88100BFB090C3D
-:1023500088020A880209BB026441528910C04D9B61
-:1023600090979198928D35D9E064D06CD730DBD0BE
-:10237000D8307FD713273C10BCE92632168C39960B
-:10238000E69CE78A37B4389AE80B13146430492A7C
-:10239000821686799A9696978C778A7D9C982B825E
-:1023A000172C7C209A9A2A9C189B99867BB03BB864
-:1023B000896DB9218BC996A52692162AAC18B899B1
-:1023C0009BA196A08BC786CD9BA22B921596A49B12
-:1023D000A386CB2CCC2026A605C0346BD4200D3B85
-:1023E0000C0DD8090E880A7FB705C0909988BC8863
-:1023F000C0900B1A126DAA069988998B288C18C068
-:10240000D01BE98C1CE98B16E981B1FF2A211C2322
-:10241000E6130F0F4F26E6122F251D7FA906C0F0E9
-:10242000C08028251D05F6111AE97A8F202BE615A4
-:102430002CE6162DE61726E6180AFA022AE61429D3
-:102440002006299CF96490FF29200C8D15C0801A64
-:10245000E9610C9C11AA99A5CCDA202BC28528949D
-:10246000CF0B4B0B2BC685C0B08C1658118AD2A04F
-:10247000D10F8A356FA548D8308BD56DA90C8A86C7
-:102480000A8A14CBA97AB337288C10C08028246715
-:10249000080B4765B112DA20DB302C12065811AD5B
-:1024A000D3A0C0C1C0D02DA4039C1563FD268636E1
-:1024B00064610C8910C04D9B909791989263FEA423
-:1024C000C08163FFC78A15CCA7DA20DB308C165891
-:1024D00011A1C020D10FDA20C0B658123063FFE43A
-:1024E00000DA208B1158122D63FFD9009E178A1332
-:1024F0002B21045810C28E17C0B02B246663FE3403
-:10250000C08063FE09DA20DB308C16DD505812B52E
-:10251000D2A0D10FDA2058122163FFA82D2138C094
-:10252000C87DC30263FE0D8A132B21042C206698FC
-:1025300017B1CC0C0C472C24665810B08E17C0D0A5
-:102540002D246663FDEE0000262138B06606064F96
-:10255000262538656EF128206A7F870508294164A1
-:1025600090A5C0D01BE92619E93426200723E61BD5
-:10257000B16609FA022BE61A28200A2DE61D2AE682
-:102580001E09880228E61C882606064728E6202B16
-:10259000220826E53E2BE6212D24072C20062A20A2
-:1025A0006468C347B44463FE9EDB30DA208D15C0F7
-:1025B000CE2E0A802C24688C165810F1D2A0D10F90
-:1025C0008E102A321616E8FD0A2A1486662BE612A9
-:1025D00097E127E61328E614AA6609660296E02E1C
-:1025E000EC4869ED50C14663FD7A000064AFB41950
-:1025F000E8F328201689920A880C00910400881AB2
-:10260000A8B8982963FF9C002B21046EB81E2C20CB
-:1026100066B8CC0C0C472C2466C9C09E178A135888
-:1026200010778E17C0348F20C0D02D2466C0682646
-:10263000240663FF2C008D35C08064D04AD9E0DCCD
-:1026400030DBE0DF301AE8FDB188B4FF17E8FD8623
-:10265000C9249DFF8DC82CCC102D46300767012D55
-:1026600046320A66011DE8F7264631AD6D2D463328
-:1026700026F21597B796B684C3BCBB94B58D3529A1
-:102680009C107D83C22F211DC14663FD4B000000BD
-:102690006C1006292006289CF86582BF2921022B90
-:1026A000200C09094C6590E116E8C30CBA11A6AAE2
-:1026B0002DA2862C0A127DC30260028C19E8BF0984
-:1026C000B90A2992A36890078C2009CC0C65C278BE
-:1026D00029A2856492722D629E1AE8B56FD80260B5
-:1026E000026E2AA22629160168A0082B22000ABB26
-:1026F0000C65B25C29629DC18C6492542A21200A27
-:10270000806099102C203CC7EF000F3E010B3EB1BA
-:10271000BD0FDB390BBB098F260DBD112DDC1C0D48
-:102720000D410EDD038E27B1DD0D0D410FEE0C0DB9
-:10273000BB0B2BBC1C0BB7027EC71C2C21257BCBF3
-:10274000162D1AFC0CBA0C0DA16000093E01073EC3
-:10275000B1780987390B770A77EB0260020A2C21DE
-:1027600023282121B1CC0C0C4F2C25237C8B29B0A4
-:10277000CD2D2523C855DA20DB3058106F292102D2
-:10278000CC96C0E80E9E022E2502CC57DA20DB3014
-:10279000DC405810F0C020D10F2C20668931B1CC1C
-:1027A0000C0C472C24666EC6026001D309FD5065EF
-:1027B000D1CD2F0A012E301129221464E0112822D4
-:1027C0001B090C4400C10400FA1A0A880228261BBF
-:1027D0002E3010C0A0C0B0941295131CE878883039
-:1027E0002CC022088D14778704C0F10CFA38C04140
-:1027F000C0F225203CC0840858010F5F010F4B3800
-:1028000005354007BB10C0F0084F3808FF100FBB5C
-:102810000228ECFEC0F0084F38842B0BA8100AFFEA
-:10282000102A21200F88020B880208440218E8862B
-:102830008F110844022821250A2A14082814048824
-:10284000110A88022A210494F08B2004E41008BBAA
-:102850001104BB02C04A04BB029BF1842A08AB11DD
-:102860000BEB0294F40A54110B44020555100D1B96
-:102870004094F707BB100B5502085502C08195F62E
-:102880008433C05094F3B1948B3295F898F99BF24D
-:10289000C080C1BC24261499FA9BF598FB85389515
-:1028A000FC843A94FD8B3B9BFE883998FF85352547
-:1028B000F6108436851324F6118B3784122BF6120A
-:1028C000C0B064C07E89307797438D3288332E3014
-:1028D000108F111CE84A0999400699112CF614C072
-:1028E000C42CF6158C2B2DF61A28F61B2BF6190482
-:1028F000A81109880208EE0219E840C18008EE021A
-:1029000009C90229F6162EF618C09E600001C09A69
-:102910002F200C18E8300CFE11A8FFA6EE2DE28542
-:102920002BF4CF0D9D0B2DE685C87F8A268929A71C
-:10293000AA9A260A990C090948292525655050C0EC
-:1029400020D10F00C09A63FFC6DA2058111463FE2D
-:1029500038DA20C0B658111163FE2E0068973C2B60
-:102960009CFD64BE24C020D10FDA20DB705810CD4E
-:10297000C0C0C0D10ADA390ADC3865CDE063FE098F
-:102980008A102B2104580F9DC0B02B246663FE21B2
-:10299000DB402A2C7458097ED2A0D10FDA20580FC0
-:1029A000A263FCF76C1004C020D10F006C10042946
-:1029B0000A801EE8261FE8261CE7FF0C2B11ACBB83
-:1029C0002C2CFC2DB2850FCC029ED19CD0C051C0C6
-:1029D0007013E82214E82118E81F2AB285A82804F9
-:1029E000240A234691A986B8AA2AB685A9882784ED
-:1029F0009F25649FD10F00006C100AD6302830103C
-:102A0000292006288CF964829B68980B2A9CF9651A
-:102A1000A1B2022A02580F8489371BE7E8C89164E3
-:102A2000520E2A21020A0C4C65C2588D3019E7E17A
-:102A300074D7052E212365E29E2F929E1AE7DD6F43
-:102A4000F8026002532AA22668A0082C22000ACCB1
-:102A50000C65C2442A929D64A23E9A151FE7D78D49
-:102A600067C1E6C8DD2B620618E7D564B00528808B
-:102A7000217B8B432B200C18E7CF0CBC11A8CC2951
-:102A8000C28679EB460FBE0A2EE2A368E0052F222C
-:102A9000007EF9372CC2859C1864C2332B212F8706
-:102AA000660B7B360B790C6F9D266ED2462C203D33
-:102AB0007BC740CE5560001E2A200CC1B28C205826
-:102AC00010F79A1864A2458D6763FFCFC0C063FFFB
-:102AD000C5D7B063FFD300C0E06000022E60030ED4
-:102AE000DB0C6EB20EDC700CEA11AA6A2AAC20581C
-:102AF0000199D7A0DA20DB70C1C82D212058109190
-:102B00008C268B279A160CBB0C7AB3348F188963EA
-:102B100099F3886298F28E659EF82D60108A189D50
-:102B20001768D729C0D09DA92C22182B22139CAB43
-:102B30009BAA97A58E667E7302600097CF586000AF
-:102B40001FDA208B1658105765A13863FFBDC0816E
-:102B5000C0908F18C0A29AF999FB98FA97F563FF75
-:102B6000D2DB30DA20DC40580FFBC051D6A0C0C009
-:102B70002BA0102CA4039B172C1208022A02066B10
-:102B800002DF702D60038E179D149E100CDD11C0A6
-:102B9000E0AD6D2DDC205801188C148B16ACAC2CDC
-:102BA00064038A268929ABAA0A990C9A26886609A1
-:102BB000094829252507880C98662F2218A7FF2F7A
-:102BC000261863FE96DA20DB30DC40DD5058110514
-:102BD000D2A0D10FC0302C20668961B1CC0C0C473B
-:102BE0002C24666EC6026000D2C03009FD5065D04C
-:102BF000CA8E6764E069647066DB608C18DF70DA27
-:102C0000202D60038E170CDD119E10AD6D2DDC2084
-:102C10001EE78D5800F9232618DA208B16DC402F8A
-:102C20002213DD50B1FF2F2613580F9AD2A0D10FD7
-:102C30000028203D084840658DE76F953EDA308DCD
-:102C4000B56D990C8CA80C8C14CACF7CD32D2AACF2
-:102C500010C090292467090D4764DDC5600092000B
-:102C60002C1208066B022D6C20077F028E17DA20CB
-:102C70009E101EE77458007D63FF9A00C09163FFA9
-:102C8000D1000000655081DA20DB60DC40580FB1D4
-:102C9000C020C0F02FA403D10FDA20C0B658103FD7
-:102CA00063FFE000006F950263FD6CDA20DB30DC2F
-:102CB00040DD50C4E0580F32D2A0D10F8A152B212D
-:102CC00004580ECE232466286010981763FF210055
-:102CD000DA2058103263FFABC858DB30DA20580FC7
-:102CE000162A210265AF9CC09409A9022925026316
-:102CF000FF91DB30DC40DD50C0A32E0A802A24681F
-:102D0000DA20580F1FD2A0D10FC020D10FDA202B0C
-:102D1000200C58104763FF6B6C1004282006C0621B
-:102D2000288CF8658125C050C7DF2B221BC0E12A03
-:102D3000206B29212300A104B099292523B1AA00E1
-:102D4000EC1A0BC4010A0A442A246B04E4390DCCA2
-:102D5000030CBB012B261B64406929200C1BE715C3
-:102D60000C9A110BAA082FA2861BE7136FF90260B9
-:102D700000B60B9B0A2BB2A368B0082C22000BCC28
-:102D80000C65C0A42BA2851DE73664B09B8C2B2458
-:102D900021040DCC029CB08820C0C50888110C8885
-:102DA0000298B1882A08441198B48F3494B79FB51B
-:102DB000C0401EE7082DA2850E9E0825E4CF2DDC1D
-:102DC000282DA68529210209094C68941A689820A3
-:102DD000C9402A210265A00B2A221E2B221D7AB18E
-:102DE0000265A079C020D10F2C212365CFDE6000C1
-:102DF000082E21212D21237EDBD52B221E2F221DE3
-:102E00002525027BF901C0B064BFC413E6E92CB0EC
-:102E10000728B000DA2003880A28824CC0D10B8032
-:102E200000DBA065AFE763FFA62A2C74C0B02C0AB4
-:102E300002580E081CE70C9CA08B2008BB1106BB97
-:102E4000029BA1893499A263FF790000262468DAE5
-:102E500020DB30DC40DD50581063D2A0D10FDA20E7
-:102E60002B200C580FCEC020D10F00006C1006078D
-:102E70003D14C080DC30DB40DA20C047C02123BCD9
-:102E800030032838080842774001B1DD64815A1EBA
-:102E9000E6C519E6C629E67ED30F6DDA050050882F
-:102EA00000308CC0E0C02025A03C14E6C4B6D38F0F
-:102EB000C0C0D00F87142440220F8940941077F7A8
-:102EC00004C081048238C0F10B2810C044C0220421
-:102ED000540104FD3802520102FE3808DD10821C44
-:102EE00007EE100E6E020EDD02242CFEC0E004FE82
-:102EF000380AEE100E88020D88028DAB1EE6B4086B
-:102F0000D8020E880298B0C0E80428100E5E018432
-:102F1000A025A125084411084402052514045511D3
-:102F2000043402C0810E8E3994B18FAA84109FB4EC
-:102F300075660C26A11FC0F2062614600009000069
-:102F400026A120C0F20626140565020F7701078727
-:102F50003905E61007781008660206550295B62571
-:102F6000A1040AE61108581108280208660296B75B
-:102F7000C060644056649053067E11C0F489C288D4
-:102F8000C30B340B96459847994618E69B9F41041E
-:102F900059110E99021FE699020E4708D80298426D
-:102FA0000E99029F40C1E00E990299442FA00CB4E3
-:102FB000380CF91114E6881EE67FA4FFAE992E9214
-:102FC0008526F4CF0E880B289685D10F2BA00C1FD9
-:102FD000E6791CE6800CBE11ACBBAFEE2DE2852677
-:102FE000B4CF0D3D0B2DE685D10FC0800528387874
-:102FF000480263FEA263FE966C1006C0C06570F1C5
-:103000008830C030088714778712C0B0C0A619E690
-:103010006B299022C030CC97C031600003C0B0C093
-:10302000A6C0E0C091C0D4C08225203C0B3F1097C1
-:1030300012831CC0700858010D5D01089738C080CC
-:103040000B9838077710048810086802087702C0C8
-:10305000800D98382D3CFE0888100D9E388D2B0A67
-:10306000EE1008EE0207EE020CB8100FDD02053B71
-:10307000400EDD029D408920043D100899110D99F4
-:10308000022D210409A90208DD119941872A05B9F9
-:10309000100D3D020ABB110DBB02087702974428B0
-:1030A00021258712082814048811071E4007EE10F6
-:1030B0000E990275660926211F0626146000060077
-:1030C0002621200626140868029B47098802984694
-:1030D00029200CD2C0C0800C9E111BE63E1FE63595
-:1030E000AB99AFEE2DE2852894CF0DAD0B2DE68583
-:1030F000D10FDD40C0A6C0B08E51CAE0B2AAB1BBAC
-:103100002DDC108F500E7836981008770C9FD898C9
-:10311000D989538F52991199DB9FDA7E8309B1CCFB
-:10312000255C10C97763FFCF88108D1108E70C97D5
-:1031300051AD8DD7F078DB01B1F79D5397528830B0
-:10314000C030088714088840648ED565BEC963FE08
-:10315000BC0000006C1004D720B03A8820C0308238
-:1031600021CAA0742B1E2972046D080FC980C99151
-:103170008575B133A2527A3B0B742B0863FFE900CB
-:10318000649FECD10FD240D10F0000006C100AD622
-:10319000302E3027D950DA4015E6092430269A150A
-:1031A00029160464E0026493732920062A9CF865BA
-:1031B000A3CE2A2102270A040A0B4C65B3978C3050
-:1031C00074C7052D212365D4A0C0A62B0A032C2289
-:1031D00000580F0B64A3B917E5F78E389A1664E30D
-:1031E000BA2F6027285021C9F37E8311C2B08C20EA
-:1031F0002A200C580F2AD7A0CDA16004A200C2B08B
-:103200008C202A200C580EFED7A064A4862F212ED5
-:103210008B680FBF360FB90C6F9D54296027D5B04E
-:103220006E920528203D7B8F4CDA20DB50C1C42DE7
-:10323000211F580EC48B269A189A1989272AAC3850
-:103240000B990C7A93538963C08099738F62987835
-:103250009F728E659E798D679D7B8C6695759C7A35
-:103260008E687E53026000B18B1465B050600038E8
-:10327000DBF063FFA5008A14C9A92E60030E9B0C26
-:103280006EB2A5DC500CEA11AA6A2AAC285BFFB129
-:10329000D5A063FF93C0E063FFE2DA208B18580EDD
-:1032A0008165A2B163FF9E0000DA20DB308C1558E7
-:1032B0000E29D6A0C0C0C0D12D16042CA403DC70EA
-:1032C000DA20DB60DF502D6003C0E09E109D171EEA
-:1032D000E5D20CDD110D6D082DDC285BFF478E66F5
-:1032E0008F678817AF5FA8A828640375FB01B1EE4C
-:1032F0008A189E669F6789268829AA9909880C9949
-:10330000268E6808084805EE0C28252515E5AC9E94
-:103310006865EECC63FEE6000000C9432F21232B35
-:1033200021212FFC010F0F4F2F25237FBB026003AC
-:10333000142C20668961B1CC0C0C472C24666EC617
-:103340000260022809FD5065D22264E1B62E602792
-:1033500064E1B0DC70DF50DA20DB601EE5C32D6075
-:1033600003C08098100CDD11AD6D2DDC285BFF22B1
-:10337000644181C0442B0A008C202A200C580EA0E6
-:103380000AA70265A00FC0B02C22002A200C580EFC
-:103390009CD7A064AFEFDA20C1BCC1C82D21208F1B
-:1033A000188E268929AFEE9E260E990C0909482908
-:1033B0002525580E64C090C050C0C288609A191E5E
-:1033C000E57FC0A12EE022088F14778704C0810E0C
-:1033D0008938C0800B93102D203C2921200CDC0162
-:1033E00004DB010929140BA8380CA5380D3D401C3D
-:1033F000E5968B2B088810075510085502053302F7
-:103400002821250F154003BB020CBB0207551005F0
-:10341000D3100828140ADD11048811098802053325
-:10342000022921040833029B70C0808A201BE58F8B
-:1034300008AA110BAA029A71C0A1852A93769574E5
-:1034400008931103DD020ADD029D778C63C1DC9CC9
-:10345000738B6298789A799B72232214C0C0B1351D
-:103460002526149C7B9D75937A2B621A9B7C2A627D
-:103470001C9A7D28621D987E25621B957F2362170A
-:103480002376102D62182D76112C62192C76126479
-:10349000E0B98E6077E73DC0FE13E5571DE558C1E2
-:1034A000818A628B630495110E9C4006CC110C55E9
-:1034B00002247615085502C0802D76148D2B2B76AC
-:1034C0001B2A761A28761925761803DD022D761622
-:1034D0006000030000C0FA2E200C19E53E18E53507
-:1034E000A9E90CEE11A8EEC0802DE2852894CF0D3D
-:1034F000FD0B2DE685DA208B198C158D14580D6582
-:10350000D2A0D10FDC70DF50DB602D6C28C0A01E74
-:10351000E5569A10DA205BFE5563FE53002B203DE2
-:103520000B4B4065BC826FE527DA308F556DE90C97
-:103530008EAA0E8E14C9E87EF3162AAC10C090290C
-:103540002467090F4764FC6060015F00C0FA63FFF5
-:1035500085C09163FFE88814658168DA20DB608CA0
-:1035600015580D7CC020C09029A403D10F8A162BBA
-:103570002104580CA2C0A02A24668E6863FDCA00EC
-:10358000002B9CF965B0FDDA20580CA763FC2200E3
-:1035900000DA20C0B6580E0163FFBA002B200C0CD5
-:1035A000BE11A7EE2DE286C1C27DC30260011819CB
-:1035B000E50209B90A2992A36890082A220009AAFB
-:1035C0000C65A10326E2856460FD2C20668931B17B
-:1035D000CC0C0C472C24666FC60270960C8A162BF6
-:1035E0002104580C86C0D02D24668E3077E74D1C00
-:1035F000E5021BE5028F328833C0A42D21040E9909
-:103600004006991104DD1109DD029A61C19009DDBE
-:10361000029B60C0908B2B9D649F66986799650C98
-:10362000BB029B6228200C1AE4EBAA8A0C8811A723
-:10363000882F828529A4CF2FFC202F86858A1465A8
-:10364000A0A6C020D10FB0FC8B142C2523C8B70234
-:103650002A02066B02580CB82A210265AEF7C0D8C0
-:103660000DAD022D250263FEEC008E14C8E8DA20B1
-:10367000DB30580CB12A210265AEDA07AF022F25E4
-:103680000263FED100DA20DB308C158D14580E5504
-:10369000D2A0D10FDA202B200C580DC063FEB6004B
-:1036A000DA202B200C580DE263FEAADA20DB308CE6
-:1036B000152D12042E0A80280A00282468580CB000
-:1036C00063FAE500C020D10FDA20580DB48914CD7B
-:1036D00092DA20DB308C15580D1FDBA0C020C0A073
-:1036E0002AB403D10FC020D10F2A2C748B15580691
-:1036F00028D2A0D10F0000006C100C2821029410D9
-:1037000008084C6583621FE4AB29F29E6F98026043
-:1037100003661DE4A729D2266890082A220009AA78
-:103720000C65A3542CF29D64C34E2B200C0CB611D7
-:10373000AF66286286C1EC78E30260034619E49E16
-:1037400009B90A2992A36890078A2009AA0C65A3DF
-:103750003224628564432CC0E12A3109C0702724D9
-:103760006689359A11992A88369912982B89379843
-:1037700013992C883899140858149815982D89395C
-:103780002A25042E251D29251C283028C0922824EE
-:103790003C2A302908084798160989012A243D2A1D
-:1037A000311599170A094109A90C299CEC29251FF3
-:1037B0007E87192D2A000DA06000083E010A3EB147
-:1037C000AD08DA390EAA110A990C29251F2A211FE2
-:1037D00018E4A80A8160C1D0941A951B01083E0024
-:1037E000053EB184054839843C259CFC0D8836296A
-:1037F000201408AA1C8D3D2726182E26132E2614C9
-:103800002E261527261B2E246B27246727246808BD
-:10381000581C0909432924142932112A252E282548
-:103820002F27252427252527252C27252325252037
-:103830002425212D2522841A2D211C851B6FD202BF
-:10384000600209C0A099186D080AB1AA00A104007D
-:10385000E91A7D9B0263FFEE8918C080C0E1C07049
-:10386000C0D29B1D951B961C9C1E16E4722C203DFD
-:1038700015E4820C0B400DCC010BE7381DE4640A03
-:1038800077100CE8380B8810C0C49C410877029D63
-:1038900040B0A80988118B209C499D48954B9643C0
-:1038A000087702861418E47315E45A08770205BBFA
-:1038B000029B4A9B4297468812871108DA149A4E57
-:1038C0000D88100D77110877021AE44E06D8140DF2
-:1038D0006610087702974FC78F984D984C98458788
-:1038E0001598440715140D55110A5502954715E40E
-:1038F000638A262D46102D46182D46202C46112C65
-:1039000046192C46212B46122B461A2846142846C7
-:10391000152B462288162546242546268B170A0C89
-:1039200048090D4885130EDD1105CC110839400BEF
-:10393000EB390299101EE4520DCC020D5511082DE1
-:10394000400655022E461316E41D0FDD11254616BE
-:10395000080840851B0188100DBB0286671DE449DD
-:103960000988020CBB0219E4191CE4472B46172DE9
-:10397000461BA7661BE446C0702C461C0988028CB7
-:103980001E28461E2B4623C0908B1D29461D294606
-:103990001F18E43F2946272846252931162E2006E0
-:1039A00029246A243117962D242538861CCCE1273A
-:1039B0002407C0D7090E4064E0829A29092841648F
-:1039C000809164409B2D2406C098094936280AA09E
-:1039D00024628501C404A84428210424668508883B
-:1039E000118E3F8A3E2D32100EA41800C4040EAE74
-:1039F0001800EE110ACA530EDD02C0E30E880298C9
-:103A0000C11EE42409084E9EC08E2094C398C59D13
-:103A1000C418E3F01DE42105EE110EAA020DAA025E
-:103A2000A8B82784CF9AC21EE3E224F29D27E4A21D
-:103A3000244C1824F69D655052C020D10F2D240629
-:103A4000C0A0C09809493604A93863FF7FC0A063AD
-:103A5000FE070000654F6DC098C0A82A240663FFCA
-:103A60006B2D2406C09063FF63CC57DA20DB308CCB
-:103A700010580C38C020D10F00DA20C0B6580CC73F
-:103A800063FFE500DA20580CC563FFDC2A2C748B39
-:103A90001058053FD2A0D10F6C10062820068A339B
-:103AA0006F8202600161C05013E3C229210216E354
-:103AB000C1699204252502D9502C20159A2814E3B7
-:103AC000BF8F2627200B0AFE0C0477092B711C647C
-:103AD000E1398E428D436FBC0260016F00E104B09A
-:103AE000C800881A08A80808D80298272B2006685A
-:103AF000B32ECE972B221E2C221D0111027BC90151
-:103B0000C0B064B0172CB00728B000DA2003880AD0
-:103B100028824CC0D10B8000DBA065AFE7C020D16C
-:103B20000F2D206464DFCA8B29C0F10BAB0C66BF7C
-:103B3000C02B200C0CBC11A6CC28C2862E0A0878FB
-:103B4000EB611EE39D0EBE0A2EE2A368E00528226B
-:103B5000007E894F29C2851EE3A96490461FE3B603
-:103B60009E90C084989128200A95930F880298927D
-:103B70008E200FEE029E942F200788262F950A98FC
-:103B8000969A972E200625240768E3432921022AC6
-:103B9000C2851DE3902AAC20ADBD25D4CF2AC685B1
-:103BA00063FF4E002E2065CBEDC082282465C9F648
-:103BB00005E4310002002A62821BE3982941020BCE
-:103BC000AA022A668209E43129210263FF23000048
-:103BD00064DFB88F422E201600F1040DEE0C00EECB
-:103BE0001AAEAE9E2963FFA38A202B3221B1AA9A76
-:103BF000B0293221283223B4992936217989A92B79
-:103C000032222B362163FFA0C020D10F9F2725240D
-:103C100015ACB828751C2B2006C0C12EBCFE64E074
-:103C2000AB68B7772DBCFD65DEC72D2064C0F0649E
-:103C3000D0868E290EAE0C66E089C0F128205A2865
-:103C40008CFE08CF3865FEE863FF580000E004935F
-:103C500010C0810AF30C038339C78F08D80308A862
-:103C60000108F80C080819A83303C80CA8B828756F
-:103C70001C030B472B24158310CBB700E104B0BC09
-:103C800000CC1AACAC0CDC029C27659E5EC0B20B6B
-:103C9000990209094F29250263FE50002D206A0D63
-:103CA0002D4165DF7EDA20C0B0580C8F64AF18C09C
-:103CB000F163FEEF9F2763FFD02E221F65EE326374
-:103CC000FF79000028221F658E2763FF6E252406DA
-:103CD00029210263FE1B00006C10066571332B4C1A
-:103CE00018C0C7293C18C0A1C08009A838080842DC
-:103CF0006481101CE32C1AE32D2AC67E2A5CFDD3B6
-:103D00000F6DAA0500B08800908C8940C0A009887A
-:103D1000471FE355080B47094C50090D5304DD10AC
-:103D2000B4CC04CC100D5D029D310CBB029B3088DD
-:103D3000438E2098350FEE029E328D26D850A6DD98
-:103D40009D268E40C0900E5E5064E0971CE33B1EA3
-:103D5000E32B038B0BC0F49FB19EB02D200A99B3C7
-:103D60000CDD029DB28F200CFF029FB48E262D2009
-:103D7000079EB68C282DB50A9CB72924072F20064C
-:103D80002B206469F339CBB61DE30D2320168DD2A9
-:103D90000B330C00D10400331AB48DA3C393292232
-:103DA000200C13E30C1FE3030C2E11AFEEA322290A
-:103DB00024CF2FE285D2A00FDD0B2DE685D10F0099
-:103DC0002E200CB48C0CEB111FE3031DE2FAAFEEB6
-:103DD000ADBB22B28529E4CF02C20B22B685D2A0A8
-:103DE000D10F00002E200C1CE2F31FE2FA0CEB11A5
-:103DF000AFEEACBB22B28529E4CF02820B22B6859E
-:103E0000D2A0D10FC0D00BAD387DC80263FEEC63E9
-:103E1000FEE08E40272C747BEE12DA70C0B32C3C8F
-:103E200018DD50580A868940C08063FEE3066E02A2
-:103E3000022A02DB30DC40DD505800049A10DB50CF
-:103E4000DA70580453881063FEF700006C10069275
-:103E5000121EE2E48C40AE2D0C8C472E3C1804CA96
-:103E60000BD9A07DA30229ADF875C302600084C000
-:103E7000B0C023C0A09D106D0844B89F0EB80A8D35
-:103E8000900EB70BB8770D6D36ADAA9D800D660C00
-:103E9000D8F000808800708C879068B124B22277B7
-:103EA000D3278891C0D0CB879890279C100070882A
-:103EB00000F08C9D91CB6FC08108BB0375CB36633E
-:103EC000FFB4B1222EEC1863FFD485920D770C86D7
-:103ED000939790A6D67D6B01B1559693959260000D
-:103EE00016B3CC2D9C188810D9D078D3C729DDF80B
-:103EF00063FFC100C0238A421BE2E900CD322D449A
-:103F0000029B3092318942854379A1051EE2E50E7C
-:103F1000550187121BE2D5897095350B99029932AC
-:103F200088420A880C98428676A6A696768F44AF79
-:103F3000AF9F44D10F0000006C10089311D6308859
-:103F400030C0910863510808470598389812282115
-:103F500002293CFD08084C6581656591628A630A07
-:103F60002B5065B18B0A6F142E0AFF7CA60A2C20F9
-:103F70005ACCC42D0A022D245A7FE0026002158912
-:103F80002888261FE2C809880C65820F2E200B0F97
-:103F9000EE0B2DE0FE2EE0FF08DD110EDD021EE22D
-:103FA000C2AEDD1EE2C21CE2C20EDD010DCC37C185
-:103FB00080084837B88DB488981089601AE2807BF1
-:103FC00096218B622AA0219C147BA3179D132A2083
-:103FD0000C8B108C20580BB18C148D13DBA0CEAC45
-:103FE0006001C4002E200C1BE2730CEA110BAA081E
-:103FF0002BA2861FE2717BDB3B0FEF0A2FF2A36837
-:10400000F0052822007F892C2BA28564B0AA876244
-:104010008826DE700C7936097A0C6FAD1C8F279BD1
-:104020001508FF0C77F3197E7B729D139C149B156A
-:10403000CF56600025C0B063FFD0D79063FFDD008E
-:10404000009D139C14DA20DB70580B168B158C1412
-:104050008D1365A06A8E6263FFCC00DA208B11DCC1
-:1040600040580ABCD6A08B15C051DE70DA20DC6047
-:10407000DD405BFF768D138C14D9A02E200C1BE243
-:104080004D1FE2540CEA11AFEFC0E0ABAA2BA285A2
-:104090002EF4CF0B990B29A68563FF1D00DA20DCD7
-:1040A00060DD40DE708912282007DF50A9882824AF
-:1040B000075BFF09D2A0D10F00DBE0DA20580B37F5
-:1040C0006550EF2A20140A3A4065A0EBDB60DC4023
-:1040D000DD30022A025809A7D6A064A0D584A183A6
-:1040E000A00404470305479512036351C05163FEC2
-:1040F0005C2C2006D30F28CCFD6480A568C704C0C3
-:10410000932924062C2006C0B18D641FE22C9D2724
-:104110009D289D298FF29D2600F10400BB1A00F016
-:1041200004B0BE0EDD01C0F0ADBB8D652F24070DC0
-:104130000E5E01EE11AEBB2E0AFEB0BB0B0B190ECC
-:10414000BB36C0E20B0B470EBB372B241618E224FC
-:104150000A09450D0B422B240B29240AB4BE2E2438
-:104160000C7D88572920162FCCFDB09D0A5C520D7E
-:10417000CC362C246465FDEC0C0C4764CDE618E2CB
-:104180000F8E2888820C9F0C00810400FF1AAFEE6E
-:104190009E2963FDCF1CE23E63FE13001CE23563E3
-:1041A000FE0C8D6563FFA500DA202B200C580B2038
-:1041B000645F0FC020D10F00C020D10FC09329240D
-:1041C00016C09363FFA000006C1004C06017E1F8F4
-:1041D0001DE1FBC3812931012A300829240A78A175
-:1041E00008C3B27BA172D260D10FC0C16550512605
-:1041F00025022AD0202F200B290AFB2B20142E2049
-:104200001526241509BB010DFF0928F11C2B2414C8
-:10421000A8EE2EF51C64A0A92B221E28221D011138
-:10422000027B8901DB6064B0172CB00728B000DA8C
-:104230002007880A28824CC0D10B8000DBA065AF24
-:10424000E7DB30DC40DD50DA205800DE29210209AE
-:104250000B4CCAB2D2A0D10F00CC5A2C30087BC173
-:10426000372ED02064E02D022A02033B02DC40DD21
-:10427000505800D4D2A0D10F2B2014B0BB2B241443
-:104280000B0F4164F0797CB7CAC0C10C9C022C258D
-:1042900002D2A0D10FC020D10F2E200669E2C12684
-:1042A00024062B221E2F221D29200B2820150D99B4
-:1042B000092A911C262415AA8828951C7BF149609F
-:1042C0000048B0BB2B24140B0A4164A0627CB702E7
-:1042D0002C25022B221E2C221DD30F7BC901C0B01E
-:1042E000C9B62CB00728B000DA2007880A28824C0B
-:1042F000C0D10B8000DBA065AFE7C020D10F00006C
-:10430000262406D2A0D10F0000DB601DE1AC64BF03
-:104310004F2CB00728B000DA2007880A28824CC04A
-:10432000D10B8000DBA065AFE71DE1A463FF310086
-:1043300026240663FF9C00006C1004282006260A31
-:10434000046F856364502A2920147D9724022A0271
-:10435000DB30DC40DD50580019292102090A4CC825
-:10436000A2C020D10FC0B10B9B022B2502C020D1CF
-:104370000F00022A02033B022C0A015800D1C9AAED
-:10438000DA20DB30DC405809F329A011D3A07E9756
-:10439000082C0AFD0C9C012CA411C0512D201406E0
-:1043A000DD022D241463FFA4DA20DB30DC40DD5075
-:1043B000C0E0580973D2A0D10F0000006C1006169F
-:1043C000E17D1CE17D655157C0E117E179282102AB
-:1043D0002D220008084C6580932B32000B6951296F
-:1043E0009CFD6590872A629E6EA84C2A722668A062
-:1043F000027AD9432A629DCBAD7CBE502B200C0C97
-:10440000BD11A6DD28D2862F4C0478FB160CBF0AFE
-:104410002FF2A368F0052822007F89072DD285D3CB
-:104420000F65D0742A210419E1A3D30F7A9B2EDAE9
-:104430002058086E600035002D21041BE19E7DBBD5
-:1044400024DA20C0B6580869CA546001030B2B5007
-:104450002B240BB4BB0B0B472B240C63FFA0DA20DF
-:10446000580A4E600006DA20C0B6580A4C6550E083
-:10447000DC40DB302D3200022A020D6D515808BDA0
-:104480001CE14ED3A064A0C8C05184A18EA0040436
-:10449000470E0E4763FF3500002B2104C08C893185
-:1044A000C070DF7009F950098F386EB8172C20667C
-:1044B000AECC0C0C472C24667CFB099D105808CF11
-:1044C0008D1027246694D11EE151B8DC9ED0655032
-:1044D00056C0D7B83AC0B1C0F00CBF380F0F42CBAE
-:1044E000F119E13018E13228967EB04BD30F6DBA46
-:1044F0000500A08800C08C2C200CC0201DE1360CCB
-:10450000CF11A6FF2EF285ADCC27C4CF0E4E0B2EB9
-:10451000F685D10FC0800AB83878D0CD63FFC100CE
-:104520008E300E0E4763FEA12A2C742B0A01044D17
-:10453000025808C22F200C12E1270CF911A699A2EB
-:10454000FF27F4CF289285D2A008480B289685D162
-:104550000FC020D10F0000006C1004C060CB55DBF1
-:1045600030DC40055D02022A025BFF94292102092A
-:10457000084CC882D2A0D10F2B2014B0BB2B24141E
-:104580000B0C41CBC57DB7EBC0C10C9C022C2502A6
-:10459000D2A0D10F0000022A02033B02066C02C027
-:1045A000D0C7F72E201428310126250228240A0F0F
-:1045B000EE012E241458010E63FFA300262406D218
-:1045C000A0D10F006C1006282102D62008084C65E7
-:1045D000809D2B200C12E0F70CB811A2882A82864D
-:1045E000B5497A930260009719E0F409B90A299253
-:1045F000A36890082A620009AA0C65A08228828517
-:104600001CE0FF6480799C80B887B14B9B819B1034
-:10461000655074C0A7D970280A01C0D0078D380D25
-:104620000D42CBDE1FE0E01EE0E12EF67ED830D357
-:104630000F6D4A0500808800908C2E3008C0A000C5
-:10464000EE322E740028600C19E0E30C8D11A2DD0F
-:10465000A988C0202CD2852284CFD2A00CBC0B2CE0
-:10466000D685D10FC0F0038F387FA0C063FFB400A0
-:10467000CC582A6C74DB30DC405807F6C020D10FD0
-:10468000DA605809C663FFE7DD402A6C74C0B0DC0D
-:104690007058086A2E30088B1000EE322E740028F5
-:1046A000600C19E0CC0C8D11A2DDA988C0202CD2A1
-:1046B000852284CFD2A00CBC0B2CD685D10F000054
-:1046C0006C1004292014282006B19929241468812B
-:1046D00024C0AF2C0A012B21022C24067BA004C08D
-:1046E000D02D2502022A02033B02044C02C0D058FE
-:1046F00000C0D2A0D10FC020D10F00006C1004293F
-:104700003101C2B429240A2A3011C28378A16C7BFA
-:10471000A1696450472C2006C0686FC562CA572D36
-:1047200020147CD722DA20DB30DC40DD505BFFA593
-:10473000292102090E4CC8E2C020D10FC0F10F9F01
-:10474000022F2502C020D10FDA20DB30C0C05BFF72
-:10475000DC28201406880228241463FFC7292015AA
-:104760001BE0972A200BC0C09C240BAA092BA11C7C
-:104770002C2415AB9929A51C63FF9900C020D10FEB
-:10478000DA20DB30DC40DD50C0E058087DD2A0D11B
-:104790000F0000006C1004CB5513E09225221F0D72
-:1047A000461106550CA32326221E25261F06440B60
-:1047B00024261E734B1DC852D240D10F280A80C038
-:1047C0004024261FA82828261E28261DD240D10FA7
-:1047D000C020D10F244DF824261E63FFD80000000E
-:1047E0006C1004D620282006C0706E85026000D4AC
-:1047F0001DE07919E07112E06F2A8CFC64A1302B66
-:104800006102B44C0B0B4C65B0A22B600C8A600C9F
-:10481000B8110288082E828609B90A7EC302600098
-:104820009A2992A368900509AA0C65A08E28828512
-:10483000648088B8891BE07594819B80655155C060
-:10484000B7B8382A0A01C0C009AC380C0C4264C0A1
-:10485000421FE0541EE0562EF67EB04AD30F6DAADA
-:104860000500808800908CC0A029600C0C9C11A2CF
-:10487000CC2BC285AD990B4B0B2BC6852860062728
-:1048800094CF6881222D6015D2A0C9D2C0E22E64D7
-:1048900006D10F00C0F008AF387FB0BD63FFB10094
-:1048A000276406D2A0D10F00D2A0D10F00CC57DAD6
-:1048B00060DB30DC405808A7C020D10FDA6058090F
-:1048C0003763FFE80028221E29221DD30F789901A3
-:1048D000C080C1D6C1C11BE043C122AB6B64804222
-:1048E00078913F2A80000CAE0C64E0BB02AF0C64F0
-:1048F000F0B52EACEC64E0AF0DAF0C64F0A92EACBB
-:10490000E864E0A32FACE764F09D2EACE664E0978A
-:104910002F800708F80BDA807B83022A8DF8D8A055
-:1049200065AFBC28612308D739D97060007B0000CF
-:104930002B600C0CB811A2882C82862A0A087CAB4A
-:104940007E09BA0A2AA2A368A0052C62007AC96F60
-:104950002A828564A0691FE029276504C0E3C0C4DA
-:104960002E64069CA11CE0549FA02E600A97A30C05
-:10497000EE029EA28F600CFF029FA42E60147AEFBD
-:104980004627A417ADBC2F828527C4CF2FFC202F2C
-:10499000868563FE692A6C74C0B1DC90DD405807DF
-:1049A000A71DE00C63FEC100D9A0DA60DB30C2D0E5
-:1049B000C1E0DC4009DE39DD505807F1D2A0D10F4B
-:1049C000DA605808F663FEE4290A0129A4170DBF2E
-:1049D000082E828527F4CF2EEC202E868564500B7E
-:1049E0002A6C74DB4058016AD2A0D10FC020D10FCD
-:1049F0006C10062B221E28221D93107B8901C0B04B
-:104A0000C0C9C03BC1F20406401DDFF6C0E2C0745D
-:104A10000747010E4E01AD2D9E11C0402E0A1464B1
-:104A2000B06E6D084428221D7B81652AB0007EA1EE
-:104A30003B7FA1477B51207CA14968A91768AA1434
-:104A400073A111C09F79A10CC18B78A107C1AE29B8
-:104A50000A1E29B4007CA12B2AB0070BAB0BDAB0DD
-:104A60007DB3022ABDF8DBA0CAA563FFB428B0104D
-:104A700089116987BB649FB863FFDC00647FB463FE
-:104A8000FFD50000646FD0C041C1AE2AB40063FFFF
-:104A9000C62B2102CEBE2A221D2B221E7AB12A8CC1
-:104AA000107CB1217AB901C0B0C9B913DFC1DA20D5
-:104AB00028B0002CB00703880A28824CC0D10B8094
-:104AC00000DBA065AFE7D240D10F8910659FD463AA
-:104AD000FFF300006C1008C0D0C8598C30292102A7
-:104AE0000C0C4760000C8E300E1E5065E19E292193
-:104AF00002C0C116DFB0090B4C65B0908A300A6E57
-:104B00005168E3026000852F629E1BDFA96EF85397
-:104B10002BB22668B0052E22007BE94727629DB79D
-:104B200048CB7F97102B200CB04E0CBF11A6FF294D
-:104B3000F2869E12798B4117DFA007B70A2772A36E
-:104B4000687004882077893029F285DF90D79065D6
-:104B500090652A210419DFD77A9B22DA205806A310
-:104B6000600029002C21041BDFD37CBB18DA20C095
-:104B7000B658069EC95860014CC09063FFCCDA203D
-:104B8000580886600006DA20C0B65808846551359A
-:104B9000DC40DB308D30DA200D6D515806F6C0D088
-:104BA000D3A064A120292102C05184A18CA00404B7
-:104BB000470C0C4763FF3E00C09C8831DBD008F8EF
-:104BC00050089B3828210498116E8823282066AC51
-:104BD0008C0C0C472C24667CBB159F139E148A10EA
-:104BE0008B115807068E148F13C0D02D24668A307F
-:104BF000C092C1C81BDF867FA6099BF099F12CF4F7
-:104C00000827FC106550A4B83ADF70C051C0800777
-:104C1000583808084264806718DF6319DF64298602
-:104C20007E6A420AD30F6DE90500A08800F08CC0AF
-:104C3000A08930B4E37F9628C0F207E90B2C9408D2
-:104C40009B909F912F200C12DF630CF811A68829EE
-:104C50008285A2FF2DF4CFD2A009330B238685D104
-:104C60000F22200C891218DF5B0C2B11A6BBA82287
-:104C70002D24CF2CB285D2A00C990B29B685D10F4B
-:104C8000C087C0900A593879809663FF8ADB30DA92
-:104C900020C0C1C0D05BFF56292102C0D02A9CFE93
-:104CA00065AE4D2D2502C09063FE45009E142A2C52
-:104CB00074C0B1DC70DD405806E18E14C0D01BDF3B
-:104CC00053C1C863FF6AC020D10F00006C100628D2
-:104CD000210216DF3808084C65821929629E6F98F8
-:104CE0000260022019DF332992266890078A200982
-:104CF000AA0C65A20F27629DC0CC6472072B210409
-:104D00008E31C0A0DDA00EFE500ECD386EB8102C36
-:104D10002066B1CC0C0C472C24667CDB026001EFD2
-:104D2000C0C12930081BDF2564909C2F0AFFC0D327
-:104D3000B09E64E1026892136450882A2C74044B7C
-:104D4000025800930AA20206000000002B200C2744
-:104D500021040CBC11A6CC29C286280A087983023A
-:104D60006001B919DF1509B90A2992A36890082EC4
-:104D7000220009EE0C65E1A42EC28564E19E262086
-:104D80000713DF1E6E7B0260019A17DF151FDF1EFF
-:104D900019DF4BC0D228200A93E09DE1A9690F8852
-:104DA0000298E22F90802A9480B1FF07FF029FE3D0
-:104DB0002EC2851FDF080EDE0BAFBF2AF4CF2EC632
-:104DC00085655F76C020D10F2830102930112E3034
-:104DD0001300993200ED326480EE2A30141FDF3860
-:104DE00000AA3278EF050F9E092DE47F1EDF36669C
-:104DF000A0050F98092A8480B4A718DF33C76F0075
-:104E00009104AE9EDDE000AF1A00C31A6EE1052DDD
-:104E1000B2000DED0C1EDF2D08D81C063303AE8842
-:104E20002A848B2EB02E27848C03EE010FEE022EE7
-:104E3000B42E58018F63FEFF29310829250428303C
-:104E4000142E3109B0886480A32E240AC0812E302C
-:104E5000162CB4232E240BB4EF2F240C8C378B3656
-:104E6000292504DEB0DFC00C8F390B8E390FEE021E
-:104E700064EEC4089F1101C4048D380CB81800C436
-:104E8000040CBE1800EE110EDD02C0E30EFF021E80
-:104E9000DF019F719E701EDF008F2098739D740547
-:104EA000FF110BCD53C18098750FDD020EDD029D01
-:104EB000721EDEBF2A24662F629D2AE4A22FFC18F0
-:104EC0002F669D63FE710000002F30121BDF010072
-:104ED000FA3278FF050B980B2A847F66D0050B9A6F
-:104EE0000B2DA4802A301100AA3263FF442F240A1C
-:104EF0009E2B63FF56CC57DA20DB30DC4058071579
-:104F0000C020D10F00DA20C0B65807A463FFE50027
-:104F1000DA7058063AC0A02A246663FE02DA2058E6
-:104F2000079F63FFCFB16928200A862009094799A6
-:104F30001129240798107F812693E027E50A9AE338
-:104F400088109DE119DEDD8D11096F029FE42DE4CB
-:104F500016098802C0D398E22A240763FE51000094
-:104F60001DDEA60868118F11892B93E008FF02C08F
-:104F70008F9FE50D990299E2047F11C0D49DE1084D
-:104F8000FF029FE463FFD0006C1004C020D10F002B
-:104F90006C100485210D381114DE848622A42408A7
-:104FA000660C962205330B9321743B13C862D230F2
-:104FB000D10FC030BC29992199209322D230D10F32
-:104FC000233DF8932163FFE36C100AD62094181751
-:104FD000DE79D930B83898199914655252C0E1D2A7
-:104FE000E02E61021DDE760E0E4C65E1628F308E82
-:104FF000190F6F512FFCFD65F1558EE129D0230E5D
-:105000008F5077E66B8F181EDEB3B0FF0FF4110FD1
-:105010001F146590CE18DEB08C60A8CCC0B119DE2C
-:105020006428600B09CC0B0D880929811C28811A82
-:105030002A0A0009880C08BA381BDEA60CA90A291E
-:1050400092947B9B0260008C2B600C94160CBD111B
-:10505000A7DD29D286B8487983026000D219DE56CE
-:1050600009B80A2882A398176880026000A360002C
-:10507000A51ADE9A84180AEE01CA981BDE4D8C1917
-:105080002BB0008CC06EB3131DDE4A0C1C520DCC2D
-:105090000B2DC295C0A17EDBAE6000380C0C5360B6
-:1050A000000900000018DE8C8C60A8CCC0B119DEAD
-:1050B0004028600B09CC0B0D880929811C28811A16
-:1050C0002A0A0009880C08BA380CA90A2992947E89
-:1050D000930263FF72DA60C0BA580730645073609D
-:1050E000026600001ADE338C192AA0008CC06EA361
-:1050F0001A18DE2F0C1C5208CC0B18DE762BC2952A
-:10510000C0A178B30263FF3F63FFC9000C0C536377
-:10511000FF09896078991829D285C9922B729E1D42
-:10512000DE246EB8232DD226991369D00B60000DB2
-:10513000DA6058071A6000170088607D890A9A1A99
-:1051400029729D9C129915CF95DA60C0B658071345
-:105150006551F58D148C18DBD08DD0066A020D6D6B
-:1051600051580584D3A09A1464A1DD82A085A1B80A
-:10517000AF9F190505470202479518C05163FE60AD
-:105180002B6104C08C8931C0A009F950098A386E9E
-:10519000B81F2C6066A2CC0C0C472C64667CAB114B
-:1051A0009F119E1B8A155805958E1B8F11C0A02A32
-:1051B00064669F1164F0E12912032812096DF91742
-:1051C0002F810300908DAEFE0080889F9200908C0E
-:1051D000008088B89900908C65514E8A10851A8B92
-:1051E000301FDE06881229600708580A2C82942D89
-:1051F00061040ECC0C2C86946FDB3C1CDE30AC9C26
-:1052000029C0800B5D50A29909094729C48065D047
-:10521000DA2E600CC0D01FDDEF0CE811AFEEA788CE
-:105220002282852DE4CF02420B228685D2A0D10FA7
-:105230008E300E0E4763FDA6A29C0C0C472C640713
-:105240007AB6CD8B602E600A280AFF08E80C6481CC
-:105250000E18DE1983168213B33902330B2C341661
-:105260002D350AC02392319F30C020923308B202FC
-:1052700008E80292349832C0802864072B600CD270
-:10528000A01CDDD40CBE11A7EE2DE285ACBB28B46A
-:10529000CF0D9D0B2DE685D10F8B1888138D30B85F
-:1052A0008C0D8F470D4950B4990499100D0D5F0472
-:1052B000DD1009FF029F800DBB029B8165508D852B
-:1052C0001AB83AC0F1C0800CF83808084264806B04
-:1052D0001BDDB519DDB629B67E8D18B0DD6DDA059A
-:1052E00000A08800C08CC0A063FEF30082138B1660
-:1052F0001DDDC628600AC0E02EC4800D880202B2FF
-:105300000B99239F20C0D298229D2122600CB2BB12
-:105310000C2D11A7DD28D28508BB0B18DDAE2BD6CE
-:1053200085A8222E24CFD2A0D10F9E1B851A2A6CCD
-:10533000748B185BFF178E1B63FEA300C087C090A1
-:105340000AF93879809263FF86C020D10F9E1B2A0C
-:105350006C74C0B18D185805398E1B851A63FE7E9A
-:10536000886B8213891608BE110ECE0202920B9E24
-:1053700025B4991EDDA19F200E88029822C0EF045B
-:10538000D8110E88029824C0E49E21C080D2A02BA0
-:10539000600C2864071CDD8F0CBE11A7EE2DE28582
-:1053A000ACBB28B4CF0D9D0B2DE685D10F000000BE
-:1053B0006C1004C020D10F006C10048633C071C083
-:1053C00030600001B13300310400741A04620174CA
-:1053D00060F1D10F6C1004022A02033B025BFFF65E
-:1053E0001CDD771BDDBFC79F88B009A903098A01AF
-:1053F0009AB079801EC0F00FE4311DDD6E0002000E
-:105400002BD2821EDDB82AC1020EBB022BD6820A25
-:10541000E431D10F28C102C19009880208084F2841
-:10542000C50208E431D10F006C1004C0C00CE43197
-:1054300012DD631ADD6000020029A28218DDAC1BB8
-:10544000DDAA2621020B990108660129A6822625DC
-:105450000206E43114DDA715DDA2236A902326128B
-:105460008550242611252613222C40D10F00000040
-:105470006C1008D6102B0A64291AB41ADD4D0D23BE
-:10548000111CDD4E0F2511B81898130E551118DD9B
-:1054900099AC55A838AA332C80FF2A80FEA933285E
-:1054A0008D0129800108AA112880000CAA02088811
-:1054B0001109880208AA1C288C08281604580862BA
-:1054C00014DD3F0AA7022441162A30802B1204075C
-:1054D000AA2858085DB1338B13B4559A6004AC28E0
-:1054E000B4662C56277B69E016DD769412C050C056
-:1054F000D017DD329D15D370D4102F60802E6082BE
-:105500009F169E17881672891A8D128C402A607F0A
-:105510000DCC282B3A200CAA2858084BC0B10ABE43
-:10552000372E35408F1772F91A8D128C402A608100
-:105530000DCC282B3A200CAA28580843C0B10ABE2B
-:10554000372E3542B233B444B1556952B6B466C051
-:10555000508F15B877D370B2FF9F156EF899D10FA1
-:105560006C1004C021D10F006C1004270A001CDD50
-:10557000111FDD221EDD251DDD0E1ADD501BDD5E37
-:10558000C02824B0006D2A75AA48288080C0916484
-:10559000806100410415DD09C03125502E00361A06
-:1055A0000655010595390C56110C66082962966E50
-:1055B000974D0D590A29922468900812DD42024243
-:1055C0000872993B23629512DD06CB349F3002822C
-:1055D000020E4402C092993194329233AD52246249
-:1055E00095C090244C1024669524B0002924A0AACC
-:1055F00042292480B177B14404044224B400D10F7D
-:10560000D10FD10F6C10041ADCEA2AA00058021C3A
-:105610005BFFD5022A02033B025BFFD11BDCE8C91A
-:10562000A12CB102C0D40DCC020C0C4F2CB5020C35
-:10563000E431D10FC0A00AE43118DCDE0002002FF3
-:10564000828219DCF12EB10209FF022F86820EE45C
-:1056500031D10F006C1004C02002E43114DCD816E4
-:10566000DCD5000200226282234102732F0603E48C
-:1056700031C020D10F19DD221ADD212841020A2A6A
-:10568000010988012A668228450208E43115DD18DF
-:1056900012DD1D25461DD10F6C1004292006289C03
-:1056A000F96480A02A9CFD65A0968A288D262F0A81
-:1056B000087AD9042B221FC8BD2C206464C0812E17
-:1056C00022090EAE0C66E0782B200C1EDCBA0CBC56
-:1056D00011AECC28C28619DCB878F3026000AD099F
-:1056E000B90A2992A36890082E220009EE0C65E001
-:1056F0009B29C2851FDCC26490929F90C0E41FDC8E
-:10570000CE9E9128200AC0E09E930F88029892882E
-:10571000200F880298942F20079A979D962F950A1C
-:105720002E240728200629206468833328C2851286
-:10573000DCA9288C20A2B22E24CF28C685C020D177
-:105740000FC020D10F2A206A0111020A2A4165AF39
-:1057500052DA20C0B05805E464AFE5C021D10F0093
-:10576000649FC81FDC962D20168FF209DD0C00F116
-:105770000400DD1AADAD9D2912DC9728C285A2B2C6
-:105780002E24CF288C2028C685C020D10FC021D13F
-:105790000F0000006C1004260A001BDCDB15DC8700
-:1057A00028206517DC84288CFE6480940C4D110D34
-:1057B000BD082CD2F52BD2F42ED2F77CB13DB4BB70
-:1057C0002BD6F47BE9052BD2F62BD6F47CB92C2A08
-:1057D000D2F62AD6F52AD6F406E431000200287261
-:1057E000822AFAFF004104290A012F510200991A66
-:1057F0000A99030988012876820FE4312624652B53
-:10580000D2F48E5A2CD2F5B0EE9E5A7BCB1629D20A
-:10581000F62FD2F70CB80C09FF0C08FF0C0F2F1451
-:10582000C8F96000320BCA0C0A2A14CEA92B510207
-:10583000C0C20CBB020B0B4F2B55020BE431D10F36
-:1058400000DB30DA205BFF941BDCB064AF5D0C4DF5
-:1058500011ADBD63FFA8000006E4310002002F7205
-:105860008218DC6E2E510208FF022F76820EE43180
-:10587000D10F00006C1004C03003E43116DC4E156B
-:10588000DC4F00020024628274472118DCA0875A92
-:10589000084801286682CD7319DC9E0C2A11AA994A
-:1058A0002292832992847291038220CC292B510267
-:1058B0000BE431C020D10F001FDC972E51020FEEF8
-:1058C000012E55020EE431B02DB17C9C5A12DC92AF
-:1058D00008DD112D5619D10F6C10061BDC351EDCAE
-:1058E0003722B0001ADC8E6F23721DDC75C0481899
-:1058F000DC8D1FDC8BDC10D5C083F000808600506F
-:105900008A6D4A4F0F35110D34092440800B560A19
-:10591000296294B1330E55092251400F44110C44B1
-:105920000A874009A80C02883622514107883608A8
-:10593000770CA8992966949740296295874109A810
-:105940000C02883607883608770CA899296695973F
-:1059500041030342B13808084298F0D10F1CDC72B1
-:1059600013DC7327B0002332B5647057C091C0D0E8
-:1059700016DC7115DC6FC0402AC00003884328C4C0
-:10598000006D793C004104B14400971A7780148E71
-:10599000502FB2952DB695AFEE2EED2006EE369E29
-:1059A0005060001877A00983509D5023B695600081
-:1059B0000223B295223D2006223622B695B455B870
-:1059C000BBD10F0003884328C400D10F6C1004C062
-:1059D0004004E43115DC59000200885013DC58CB38
-:1059E000815BFFBD1CDC570C2D11ADCC2BC2822A74
-:1059F000C28394507BAB142EC28429C2850ABD0C8D
-:105A00000E990C0D990C0929146000050BA90C09BD
-:105A10002914993015DBEA2A51020AE4312A2CFCB8
-:105A200058004B2B32000AA2022BBCFF9B30CCB695
-:105A3000C8A4D2A0D10F000004E4311EDBDE0002B6
-:105A4000002DE2822FBAFF2C51020FDD012DE682DC
-:105A50000CE431D10F0000006C1004D10F000000E5
-:105A60006C1004C020D10F006C100413DC36C0D1C0
-:105A700003230923318DC0A06F340260008D19DB30
-:105A8000CD1BDBCE17DC2F0C2811A87726728325BF
-:105A900072822CFAFF76514788502E7285255C045D
-:105AA00025768275E9052572842576827659292E18
-:105AB00072842E76822E76830AE4310002002392CD
-:105AC000820021042FB10200D61A0C6603063301AE
-:105AD0002396820FE43126728325728260000200D1
-:105AE000D8A07659220AE4310002002392820021D4
-:105AF0000400D21A2FB1020C220302320122968234
-:105B00000FE431D280D10F00D280D10FC020D10F4D
-:105B10006C1004DB30862015DBA6280A002825023D
-:105B2000DA2028B0002CB00705880A28824C2D0AFC
-:105B3000010B8000DBA065AFE61ADB9F0A4A0A2949
-:105B4000A2A3C7BF769101D10F2BA6A3D10F00004E
-:105B50006C1004C0D1C7CF1BDB9919DB9617DB94FF
-:105B60000C2811A87786758574C0A076516288507C
-:105B70008E77B455957475E90385769574765927B3
-:105B80008F769F759F740AE431000200239282B4DD
-:105B90002E2FB10200E10400D61A0C660306330171
-:105BA0002396820FE431867583747639280AE431AE
-:105BB0000002002E9282B42200210424B10200DFF0
-:105BC0001A0CFF030FEE012E968204E431D280D12D
-:105BD0000FD8A07651D6D280D10F00006C100429C6
-:105BE0000A801EDB9A1FDB9A1CDB730C2B11ACBBEB
-:105BF0002C2CFC2DB2850FCC029ED19CD0C051C064
-:105C00007013DB9614DB9518DB932AB285A8280461
-:105C1000240A234691A986B8AA2AB685A98827848A
-:105C20009F25649FD10F00006C100419DBC70C2A5C
-:105C300011A9A98990C484798B761BDBB5ABAC2AFA
-:105C4000C2832CC2847AC1688AA02BBC30D3A064E2
-:105C5000A05E0B2B0A2CB2A319DB7F68C0071DDBEB
-:105C6000BBD30F7DC94AA929299D0129901F68919D
-:105C70003270A603D3A0CA9E689210C7AF2AB6A3FB
-:105C80002A2CFC5BFFB3D230D10F000013DBB10331
-:105C9000A3018C311DDB510C8C140DCC012CB6A34F
-:105CA00063FFDC00C020D10FDA205BFFCCC020D125
-:105CB0000FC020D10F0000006C1004DB30C0D019E1
-:105CC000DB3CDA2028300022300708481209880A15
-:105CD00028824CDC200B80001BDB370C4A11ABAA5E
-:105CE00029A28409290B29A684D10F006C1004C0B5
-:105CF0004118DB3017DB320C2611A727277030A89C
-:105D000066256286007104A35500441A7541482235
-:105D1000628415DB5202320BC922882117DB2F085F
-:105D20008414074401754905C834C020D10FD10F30
-:105D30000809471DDB86C0B28E201FDB1D0E0E43F7
-:105D4000AFEC2BC4A00FEE0A2DE6242A6284C020FB
-:105D50000A990B296684D10FC020D10F6C1004DB87
-:105D600030C0D018DB13DA20253000223007085865
-:105D70000A28824CDC200B80008931709E121BDBCC
-:105D80000D0C4A11ABAA29A28409290B29A684D19A
-:105D90000F09C95268532600910418DB08C0A12FCF
-:105DA000811200AA1A0AFF022F85121EDB020C4D77
-:105DB00011AEDD2CD2840C2C0B2CD684D10FC081DB
-:105DC0001FDAFFB89A0A0A472EF11200A1040088D0
-:105DD0001A08EE022EF5121DDAF70C4C11ADCC2B81
-:105DE000C2840B2B0B2BC684D10F00006C1004DB7C
-:105DF00030C0D019DAEFDA202830002230070988C5
-:105E00000A28824CDC200B80001CDAEA0C4B11AC17
-:105E1000BB2AB2840A2A0B2AB684D10F6C1004C0A4
-:105E20004118DAE416DAE60C2711A626266030A817
-:105E300072252286006104A35500441A7541082288
-:105E4000228402320BD10F00C020D10F6C10041538
-:105E5000DB410249142956112452120208430F88CB
-:105E600011C07300810400361A008104C78F0077C7
-:105E70001A087703074401064402245612D10F0082
-:105E80006C10066E23026000AC6420A7C0A08510D1
-:105E900013DB1916DB30C040A6AA2BA2AE0B1941AA
-:105EA00064906668915D68925268933C2AA2AA2821
-:105EB0003C7F288C7F0A0A4D2980012880002AAC6B
-:105EC000F20888110988027589462B3D0129B00026
-:105ED0002BB0010899110B99027A9934B8332A2A08
-:105EE00000B1447249B160004A7FBF0715DB1B63F4
-:105EF000FFB90000253AE863FFB10000253AE863E6
-:105F0000FFA90000250A6463FFA1C05A63FF9C003B
-:105F100000705F082534FF058C142C34FE70AF0B25
-:105F20000A8D142E3D012AE4012DE400DA405BFDC8
-:105F30005063FFA7D10FD10F6C10041ADAA019DA41
-:105F40009D1CDB061BDB07C080C07160000D0000DC
-:105F50000022A430B1AA299C107B915F26928679F9
-:105F6000C2156E6262C0206D080AB12200210400D1
-:105F7000741A764BDB63FFEE2292850D63110325C5
-:105F800014645FCFD650032D436DD9039820B422FB
-:105F90000644146D49229820982198229823982429
-:105FA00098259826982798289829982A982B982CED
-:105FB000982D982E982F222C4063FF971EDA7E276B
-:105FC000E68027E681D10F00C02063FF8300000038
-:105FD0006C1004C062C04112DA791ADA7513DAE182
-:105FE0002AA00023322D19DADB2BACFE2992AE6EEB
-:105FF000A30260008E090E402D1AC2C2CD0EDC39FC
-:106000002C251664B0895BFF9E15DAD71ADAD12BDE
-:106010003AE80A3A0158058C2B21160ABB28D3A06E
-:106020009B505805A32B52000ABB082A0A005805AA
-:10603000A215DACE2D21022C3AE80C3C2804DD0210
-:106040002D25029C5058059A8B50AABBC0A158051B
-:106050009A1CDAC72D21020C3C2806DD0213DAC592
-:106060002D25029C305805928B30AABBC0A2580542
-:10607000922A2102C0B40BAA020A0A4F2A2502580A
-:1060800005A6D10F242423C3CC2C251663FF76004C
-:1060900018DABD1CDAB919DABA1BDAB817DA8B8547
-:1060A000202E0AFD1FDAB92D202E24F47A24F47E46
-:1060B00024F4820EDD0124F4862E0AF70755280603
-:1060C000DD02C0750EDD01050506AB5BA959C0E810
-:1060D000AC5C24C4AB0EDD0227C4AC2E0ADFA8558D
-:1060E00027B4EC0EDD0124B4EBC2E027942C0EDDC6
-:1060F0000224942B2E0A800D0D4627546C24546BD9
-:106100000EDD022D242E63FEFC0000006C10042A1C
-:106110000A302B0A035BFF4D12DA8FC39029261633
-:10612000C3A1C0B3C08A2826175BFF48C03CC3B1D7
-:106130002B26161ADA222AA02023261764A079C358
-:10614000A2C0B15BFF42C3A2C0B15BFF40C3C22C7F
-:106150002616C2AFC0B12326175BFF3CC28F28268C
-:1061600016C0FE2F2617C2E22E26162A0AA1C0B19B
-:10617000C0D82D26175BFF352A0AA12A2616C3A6EA
-:10618000C0B3C1922926175BFF31C3C62C2616C1A6
-:10619000B32A0AA22B2617C0B35BFF2C290AA22917
-:1061A0002616C185282617C2FB2F2616C0E72E26E5
-:1061B000171DDA762D2610D10FC3A2C0B35BFF23C3
-:1061C00063FF82006C10041CDA3F1BDA2C18DA70B3
-:1061D00017DA7116DA7115DA71C0E0C0D414DA3B3F
-:1061E0001FD9F7C0288FF06D2A36DAC0D9C07C5B82
-:1061F000020FC90C1CDA350C9C28A8C3A6C22A368B
-:10620000802A2584A4C2A7CC2D248C2B248A2B245D
-:10621000872E248BB1BB2E369F2C369E2C369DB1FB
-:10622000AC1CDA161BDA5FC0286D2A33DAC0D9C07D
-:106230007C5B020FC90C1CDA240C9C28A8C3A6C2E4
-:106240002A36802B2584A4C2B1BBA7CC2D248C2E4A
-:10625000248B2A248A2E369F2C369E2C369DB1AC58
-:10626000C07919DA141BDA5113DA4F1ADA4F18DA37
-:106270005014DA1516DA5004F42812DA4F04660CBA
-:10628000040506A252A858AA5AA3539B3029A50078
-:1062900027848AC091C0A52A848C29848B17DA4868
-:1062A00018DA47A75726361D26361E2E361F16DA51
-:1062B0004513DA45A65504330C2826C82E75002D43
-:1062C00054AC2E54AB2E54AA2326E62326E52E26C4
-:1062D000E7D10F006C100613DA2317DA1E24723D83
-:1062E0002232937F2F0B6D08052832937F8F026334
-:1062F000FFF3C0C4C0B01AD9B1C051D94004593954
-:1063000029A4206E44020BB502C3281ED9ACDDB00F
-:1063100025E422052D392DE421C0501EDA2C19DA8E
-:106320001C18DA1C16DA1E1DDA2A94102A72451778
-:10633000D9E76DA94BD450B3557A5B17DF50756B15
-:10634000071FD99E8FF00F5F0C12D9DF02F228AE23
-:106350002222D681D54013D9DC746B0715D99885D4
-:106360005005450C035328B145A73FA832A9332255
-:10637000369D22369E2436802B369F2BF48B2CF4B0
-:106380008C14D9F824424DC030041414C84C6D0844
-:1063900006B133041414C84263FFF20015D985C452
-:1063A000400031041AD986C0D193A200DD1AC13849
-:1063B000B0DD9DA318D9EC2B824D29824E29A51C56
-:1063C0002882537A871E2C54008E106FE45D12D9F8
-:1063D0007B2F211D23211C2F251B04330C23251C5F
-:1063E00023251AD10FC06218D9DB88807E87D9890E
-:1063F000102654006F94191BD9712AB11C0A1A1463
-:1064000004AA0C2AB51C2AB51D2AB51A2AB51BD117
-:106410000F1BD96A2AB11C0A1A1403AA0C2AB51C2C
-:106420002AB51D2AB51A2AB51BD10F001CD9642B19
-:10643000C11D2DC11C2BC51B03DD0C2DC51C2DC57D
-:106440001AD10F006C100619D95D14D9C212D9C522
-:1064500015D9E0C73FC0E02E56A82E56A92E56AA41
-:106460002E56AB23262918D985DB101CD9DAC0D4C7
-:106470002A42452D16019C1000B0890A880C2896E6
-:10648000005BFF942B22E318D94D0B5B149B842AED
-:1064900022E48B84B1AA0A5A140BAA0C9A852922E9
-:1064A000E509591499862F22CD0F5F149F875BFF52
-:1064B000455BFF1623463BC1B01DD9401CD99E2A1F
-:1064C000D1022C463A0BAA020A0A4F2AD5025804D6
-:1064D000925BFEBF5BFE98C050C0B016D93614D98F
-:1064E0003E17D9AEC0C0C73E93122C262DC03060D7
-:1064F00000440000007F9F0FB155091914659FF4F7
-:10650000C0500AA9027FA7EF18D92ADA5008580A02
-:1065100028822C2B0A000B8000005104D2A0C091CD
-:10652000C7AF00991A0A99039912CE3864206BD329
-:10653000202B20072516032C12022A62827CA863D6
-:1065400018D91C01110208580A28822CDA500B8035
-:1065500000D2A0643FD58A310A8A1404AA01C82A4D
-:106560002B22010B8B1404BB017BA945DDA07A7B98
-:10657000081DD9122DD2000DAD0CDB3019D90D1A22
-:10658000D95288130ADA28DC801DD99009880A2894
-:10659000823C0DAA080B8000652F93D320C0B06306
-:1065A000FF9400007FAF34B1550050040A0919630D
-:1065B000FF42DAB07B7B081AD9012AA2000ABA0C82
-:1065C0001BD9428C310BAB280C8A141CD980ACBB74
-:1065D0001CD98004AA012BC68163FF8F645F60C051
-:1065E00050C0B0C7CE9C1263FF5500006C1004274A
-:1065F000221EC08008E4311BD8EF0002002AB282BC
-:1066000019D8EF003104C06100661A2991020A6AA4
-:10661000022AB68209E43115D94A0C3811A8532848
-:1066200032822432842A8CFC7841102921022A36B5
-:106630008297A0096902292502D10F002B21022C83
-:1066400032850B6B022CCCFC2C368297C02B25029A
-:10665000D10F00006C1004C0E71DD8D21CD8D40D97
-:106660004911D7208B228A200B4B0BD2A007A80CF4
-:106670009B72288CF4C8346F8E026000A31FD8CAA6
-:10668000A298AF7B78B334C93DC081C0F0028F3887
-:106690000F0F42C9FA2CD67ED5206D4A05003088EE
-:1066A00000508C887008980878B16DD2A09870D18D
-:1066B0000FC0F0038F387FE0DE63FFD8027B0CAFA2
-:1066C000BB0B990C643047D830C0F1C05002F5388C
-:1066D0000505426450792CD67E0B36122F6C100FB4
-:1066E0004F366DFA0500808800208C06440CC0816E
-:1066F000C05003B208237C0C038538050542645062
-:106700005A2CD67ED30F6D4A0500208800308CD2DB
-:10671000A0A798BC889870D10FD2A0BC799970D1ED
-:106720000FD2302BAD08C0F1C0500BF53805054233
-:10673000CB542CD67E083F14260A100F660C064652
-:10674000366D6A0500208800B08C827063FF2D00D2
-:10675000C05003F53875E08063FF7A00C0600286A0
-:106760003876E09F63FF9900C05003F53875E0C4A8
-:1067700063FFBE006C1004D62068520F695324DA00
-:1067800020DB30DC405800F3D2A0D10FDA20DB3020
-:10679000DC405800F09A2424240EC02122640FC04B
-:1067A00020D10F00B83BB04C2A2C7489242D200E28
-:1067B0002E200FA4DDB1EE2E240FB0DD2D240E28E7
-:1067C00090072D9003A488B088B1DD2D9403289400
-:1067D000075BFFA069511DC0E082242A600F18D812
-:1067E000FE2A240329600E8F2029240708FF029F18
-:1067F000209E64D10FC020D10F0000006C100494C3
-:106800002319D8F6C0B3083A110BAA02992019D857
-:10681000699A2116D867C05028929D2564A2288CB9
-:106820001828969DD10F00006C1004282066C038EF
-:10683000232406B788282466D10F00006C100603B5
-:106840005A0C0D36110D5C11D8208B2282210CBB05
-:106850000C06550F9B8202320B928113D853D9201C
-:10686000A38F6450561CD84FC0D71BD850A256C017
-:10687000E1C09004E93809094276F34F044302CAA3
-:10688000912BC67ED30F6DAA0500208800308C891D
-:1068900081A95909FA0C64A07D99818A8264A00FAC
-:1068A000D290D10FC06002E63876D0D763FFD10016
-:1068B000C020BC89998199809282D10F7F230429BD
-:1068C0002DF8998165BFD863FFE50000028F0CA306
-:1068D000FF0F3312931003AA0CD3406490402BC6D1
-:1068E0007E8610D30F6D6A0500208800308CBC8234
-:1068F000C090A4F3C041034938090942CA9B2BC682
-:106900007E6DAA0500208800308C0F590CA989BC27
-:1069100099998163FF8400BC89998163FF7C00C0E1
-:106920006002E63876D0B963FFB300C07002473822
-:1069300077D0CD63FFC700006C100414D82AC15271
-:10694000A424CA3128221D73811C292102659016B6
-:106950002A300075A912022A02033B022C3007C01C
-:10696000D25801D0653FDCD10F2B300703BB0B0B96
-:10697000BA0274B3022ABDF8D3A063FFC4000000BA
-:106980006C1004292006C0706E9741292102C08F27
-:106990002A2014C0B62B240606AA022A24147980C1
-:1069A000022725022A221E2C221D7AC10EC8ABDA2C
-:1069B00020DB302C0A00033D025BF80D6450742D7F
-:1069C00021020D0D4CC9D3C020D10F00002E9CFB1D
-:1069D00064E0822F21020F0F4C65F0911AD7F61C4C
-:1069E000D7F429A29EC08A798B5D2BC22668B00499
-:1069F0008D207BD95229A29DC0F364904A97901DA7
-:106A0000D8062E21049D9608EE110FEE029E979E49
-:106A10009118D802C0E527C4A22E24062BA29D2FD0
-:106A200021022BBC3008FF022F25022BA69DC0207F
-:106A3000D10F00002F300068F939DA20DB30044C28
-:106A40000258004463FF7700022A022B0A0658000E
-:106A5000D3220A00D10F6550102830006889240223
-:106A60002A02033B02DC4058003BC020D10FD27009
-:106A7000D10F00002A2C74033B02044C025BFEF58C
-:106A800063FF3B00DB30DC402A2C745BFEF2C0204D
-:106A9000D10F00006C1004C83F89268829A399995A
-:106AA0002609880C080848282525CC52C020D10F7B
-:106AB000DB402A2C745BF936D2A0D10F6C1004D8BD
-:106AC00020D73082220D451105220C928264207459
-:106AD00007420B13D7B5D420A383732302242DF8C8
-:106AE000858074514CBC82C0906D081600408800AF
-:106AF000708C773903D720C0918680743901D420F7
-:106B000074610263FFE2CA98C097C0411BD835C0C8
-:106B1000A00B8B0C0B4A380A0A42C9AA1DD7A21C2B
-:106B2000D7A32CD67EC140D30F6D4A050020880024
-:106B3000308C9780D270D10FBC8FC0E00F4E387E62
-:106B400090E263FFD6BC8292819280C0209282D173
-:106B50000F0000006C1006C0D71CD7921BD7940DF5
-:106B60004911D7202E221F28221D0E4E0BD280073E
-:106B70008A0C2E761F2AAC80C8346FAE026000CB20
-:106B80002F0A801AD798A29EAA7A7EA33FC93FC037
-:106B9000E1C05002E538050542CA552BC67EDB2010
-:106BA000D30F6D4A0500308800B08C2E721DAE9E4A
-:106BB0000EA50C645086D2802E761DC091298403C8
-:106BC000D10FC05003E53875D0D363FFCD15D785FD
-:106BD000027E0CA5EE643051C0A1250A0002A53842
-:106BE000033A020505426450922BC67E0E3512957B
-:106BF00010255C10054536D30F6D5A0500A088009E
-:106C0000208CC0A1A3E2C05023FA8003730C03A51B
-:106C100038AF730505426450722BC67E851005455A
-:106C20000C6D5A0500208800308CD280C0A10E9BCC
-:106C30000CAB7BAFBB2B761D2A8403D10FD280C057
-:106C4000C1AF7D2D761D2C8403D10F00D2302E8D47
-:106C500008C0F1C0500EF538050542CB592BC67E51
-:106C60000A3F14C1600F660C064636D30F6D6A05E5
-:106C700000208800E08C22721D63FF03C061C050B9
-:106C800003653875D80263FF6263FF5CC05002A5DC
-:106C90003875D08763FF8100C06003F63876D0BFB7
-:106CA00063FFB9006C10042A201529201614D7435D
-:106CB0000A990CCB9D2E200B04ED092BD11C8F289B
-:106CC00009BC36ACAA0CBB0C2BD51C0A0A472A24DB
-:106CD00015CAAF8B438942B0A800910400881AA856
-:106CE000FF0FBB029B278F260FB80C783B1AC020E2
-:106CF000D10F0000292102C0A20A9902292502C051
-:106D000021D10F008B2763FFDC2BD11C0CAA0C0AAE
-:106D10000A472A2415ACBB2BD51CC9AE8B438C2843
-:106D20008F42B0AD00F10400DD1AADCC0CBB029B6C
-:106D300027DA20B7EB580019C021D10F9F2763FF36
-:106D4000EF0000006C100428203C643047053060E0
-:106D500000073E01053EB156076539054928C77F42
-:106D6000A933030641076603B166060641A6337ED2
-:106D7000871E222125291AFC732B1502380C098144
-:106D80006000063E01023EB12406423903220AD1C8
-:106D90000FD230D10FC05163FFC000006C10042728
-:106DA000221EC08008E4311DD7030002002CD282CD
-:106DB0001BD703003104C06100661A2BB1020C6CB2
-:106DC000022CD6820BE43119D7870C3A11AA9328EA
-:106DD00032829780253282243284B45525368275DA
-:106DE000410A292102096902292502D10F2A21021B
-:106DF0002B32830A6A022B36822A2502D10F000029
-:106E00006C100418D6EC0C2711087708267286251A
-:106E10003C04765B1315D6E805220A2222A36820DB
-:106E200002742904227285D10FC020D10F00000006
-:106E30006C100419D6EB27221EC08009770208E4E3
-:106E4000311DD6DC0002002CD2821BD6DC003104BE
-:106E5000C06100661A2BB1020C6C022CD6820BE4C6
-:106E60003119D7600C3A11AA9328328297802532C3
-:106E700082243284B45525368275410B2A21020AB8
-:106E80006A022A2502D10F002B21022C32830B6BC0
-:106E9000022C36822B2502D10F0000006C10041B3F
-:106EA000D6C50C2A11ABAA29A286B438798B221B2D
-:106EB000D6C219D6E80B2B0A2BB2A309290868B051
-:106EC0000274B90D299D0129901F6E920822A28596
-:106ED000D10FC020D10FC892C020D10FDA205BEEB5
-:106EE000B3C020D10F0000006C100414D6B22842A9
-:106EF0009E19D6AF6F88026000BA29922668900763
-:106F00008A2009AA0C65A0AC2A429DC0DC64A0A41A
-:106F10002B200C19D6A90CBC11A4CC2EC28609B901
-:106F20000A7ED30260009A2992A36890078D2009F7
-:106F3000DD0C65D08C25C2856450862D2104C030BF
-:106F40006ED80D2C2066B8CC0C0C472C246665C07E
-:106F50007B1CD72518D6AF1AD6A619D6B61DD6AB28
-:106F6000C0E49E519D508F209357935599539A5644
-:106F70009A5408FF021AD6C29F5288269F5A9E59D9
-:106F80009D58935E9C5D935C9A5B08084805881148
-:106F9000985FC0D81FD6900CB911A499289285AFDC
-:106FA000BF23F4CF288C402896858E262D24069E5C
-:106FB00029C020D10FCA33DA20C0B65BFF78C72FB3
-:106FC000D10FC93ADA205BFF75C72FD10FDBD05B39
-:106FD000FE0B2324662B200C63FF7500C72FD10FF7
-:106FE000C72FD10F6C1004C85B29200668941C6859
-:106FF0009607C020D10FC020D10FDA20DB30DC4053
-:10700000DD502E0A005BFE5ED2A0D10F2E200C18A0
-:10701000D6690CEF11A8FF29F286C088798B791AFE
-:10702000D6660AEA0A2AA2A368A0048B207AB96865
-:1070300023F2856430621BD670290A802C206828D0
-:1070400020672D21040B881104DD1108DD020DCC11
-:1070500002C0842D4A100DCC021DD66898319D3097
-:107060008A2B99379C340BAA02C0C09C359C369A57
-:10707000322A2C74DB4028F285C0D3288C2028F6D5
-:10708000852C25042D24061FD653DD40AFEE2CE4BD
-:10709000CF5BFDEAD2A0D10F00DA20DBE05BFF3F3F
-:1070A000C020D10F6C100AD6302A200624160128E1
-:1070B000ACF86583862B2122C0F22A2124CC572AE2
-:1070C000AC010A0A4F2A25247ABB0260037F2C21D7
-:1070D000020C0C4C65C3192E22158D32C0910EDDA9
-:1070E0000C65D39088381ED63364836B8C37C0B858
-:1070F000C0960CB9399914B49A9A120D9911991332
-:107100008F6718D62EC9FB2880217F83168B142CFD
-:1071100022002A200C5BFF61D4A064A3B38F6760B8
-:10712000002800002B200C89120CBA11AEAA2CA248
-:10713000861DD6217C9B3E0DBD0A2DD2A368D004AE
-:1071400088207D893024A28564436427212E07F797
-:107150003607F90C6F9D01D7F0DA20DB70C1C42D22
-:10716000211F5BFEF889268827DDA009880C7A8B11
-:10717000179A10600006C04063FFCC0000DA208B35
-:10718000105BFEC88D1065A267C0E09E488C649CB1
-:10719000498B658A669B4A9A4B97458F677F730236
-:1071A000600120CD529D10DA20DB302C12015BFEF5
-:1071B000698D10C051D6A08FA7C0C08A68974D9A1C
-:1071C0004C8869896A984E994F8E6A8A69AE7E7733
-:1071D000EB01B1AA9E6A9A698B60C0A00B8E1477EE
-:1071E000B701C0A1C091C08493159D179516C0D05A
-:1071F00025203CC030085801089338C0820833105D
-:10720000085B010535400B9D3807DD100BAB100EF8
-:1072100019402A211F07991003DD020DBB020553F7
-:10722000100933020A55112921250A2A14092914A3
-:107230000499110A99020933028A2B2921040BAA05
-:10724000021BD66A0899110955020855020BAA02B9
-:107250009A408920881408991109880219D5EA1DD5
-:10726000D66409880298418B2A9346954783150D69
-:10727000BB0285168D179B448A658966AACAA97CBC
-:1072800077CB01B1AA07FB0C9C669A6588268E29EC
-:10729000AD87972607EE0C0E0E482E25259B672BF3
-:1072A000200C87131ED5C40CB911AE99289285A75E
-:1072B0008828968517D5C8C090A7BB29B4CF871852
-:1072C00063FE3C008C60C0E0C091C0F0C034C0B828
-:1072D0002A210428203C08AA110B8B0103830103F7
-:1072E0009F380B9B39C03208FF10038801089E3875
-:1072F0000C881407EE100FEE020388010898390578
-:10730000BF1029211F0ABB1107881008FF020BAA12
-:107310000218D5BC09291403AA022B212583200BAE
-:107320002B1404BB110833110FBB020B99028B14F1
-:107330008F2A0B33020833028B2B64708688689780
-:107340004D984C8769886A93419946974E984FC0EB
-:107350007077C701C0719A4718D6260B7C100CECC9
-:107360000208F802984418D6230CBC0208CC029CF0
-:10737000402A200C295CFEC0801FD58E1CD5960C9F
-:10738000AE112B2124ACAAAFEEB0BB8F132CE2853B
-:1073900028A4CFAFCC2CE6852A22152B2524B1AA10
-:1073A0002A26156490DBC9D28F262E22090DFF08EC
-:1073B0002F26060FEE0C0E0E482E25256550E4C034
-:1073C00020D10F00C07093419F4499469A4777C7D8
-:1073D0000A1CD57A2CC022C0810C87381CD6070B1A
-:1073E000781008E80208B8020C8802984063FF8011
-:1073F00000CC57DA20DB608C115BFDD629210268B6
-:107400009806689403C020D10F2B221EC0A0292209
-:107410001D2A25027B9901C0B064BFE813D5652CF5
-:10742000B00728B000DA2003880A28824CC0D10BAC
-:107430008000DBA065AFE763FFCA000068A779DAC8
-:1074400020DB30DC40DD505BFEE7D2A0D10FC16D08
-:10745000C19D29252C60000429252CD6902624675F
-:107460002F2468DA20DB308C11DD502E0A805BFD82
-:1074700044D2A0D10FC168C1A82A252C63FFDD002A
-:107480000000C8DF8C268B29ADCC9C260CBB0C0BD6
-:107490000B482B25252A2C74DB602C12015BFD8701
-:1074A000D2A0D10F2A2C748B115BF6B9D2A0D10FC8
-:1074B000DA205BFE3A63FF3800DA20C0B15BFE8A57
-:1074C00064ABF1655F352D2124B1DD2D252463FFEB
-:1074D0001FDA202B200C5BFE5663FF1412D5C882E6
-:1074E00020028257C82163FFFC12D5C403E8300490
-:1074F000EE3005B13093209421952263FFFC00000B
-:1075000010D5C0910092019302940311D597821077
-:1075100001EA30A21101F031C04004E4160002007B
-:1075200011D5B98210234A00032202921011D5828C
-:10753000C021921004E4318403830282018100009F
-:10754000D23001230000000010D5B09100920193C9
-:1075500002940311D586821001EA30A21101F131A3
-:10756000C04004E41600020011D5A7821013D52BE9
-:10757000032202921004E431840383028201810019
-:1075800000D330013300000010D5A19100810165C6
-:10759000104981026510448103CF1F920193029428
-:1075A0000311D574821001EA30A21101F231C040FA
-:1075B00004E41600020011D593821013D5130322A0
-:1075C00002921004E431840383028201C01091030B
-:1075D00091029101810000D43001430012D542C0D4
-:1075E0003028374028374428374828374C233D0176
-:1075F0007233ED03020063FFFC00000010D585919B
-:107600000092019302940311D5838210921011D538
-:10761000348310032202921011D58012D5469210A5
-:10762000C04004E41600020011D577821013D52D56
-:10763000032202921004E431840383028201810058
-:1076400000D53001530000006C10026E322FD6209E
-:10765000056F04043F04745B2A05440C00410400D8
-:10766000331A220A006D490D73630403660CB122BC
-:107670000F2211031314736302222C01D10FC83B94
-:10768000D10F000073630CC021D10F000000000077
-:1076900044495630C020D10F6C10020040046B4C9E
-:1076A00007032318020219D10F020319C020D10FBA
-:1076B0006C100202EA30D10F6C1002CC2503F031BD
-:1076C00060000F006F220503F1316000056F230594
-:1076D00003F231000200D10F6C1002CC2502F03011
-:1076E000D10F00006F220402F130D10F6F2304028A
-:1076F000F230D10FC020D10F6C1002220A20230AD1
-:10770000006D280E28374028374428374828374C42
-:10771000233D01030200D10F6C100202E431D10FAE
-:107720000A004368656C73696F20465720444542E0
-:1077300055473D3020284275696C74204672692097
-:107740004D61792020382031363A30373A333620AF
-:107750005044542032303039206F6E20636C656F96
-:1077600070617472612E6173696364657369676EB9
-:107770006572732E636F6D3A2F686F6D652F666546
-:107780006C69782F772F66775F372E31292C20563A
-:10779000657273696F6E2054337878203030372EDD
-:1077A00030342E3030202D203130303730343030EE
-:0877B000100704000071489469
-:00000001FF
diff --git a/fs/9p/Makefile b/fs/9p/Makefile
index 1a940ec7af6..91fba025fcb 100644
--- a/fs/9p/Makefile
+++ b/fs/9p/Makefile
@@ -8,6 +8,8 @@ obj-$(CONFIG_9P_FS) := 9p.o
vfs_dir.o \
vfs_dentry.o \
v9fs.o \
- fid.o
+ fid.o \
+ xattr.o \
+ xattr_user.o
9p-$(CONFIG_9P_FSCACHE) += cache.o
diff --git a/fs/9p/fid.c b/fs/9p/fid.c
index 7317b39b281..35856368906 100644
--- a/fs/9p/fid.c
+++ b/fs/9p/fid.c
@@ -97,6 +97,34 @@ static struct p9_fid *v9fs_fid_find(struct dentry *dentry, u32 uid, int any)
return ret;
}
+/*
+ * We need to hold v9ses->rename_sem as long as we hold references
+ * to returned path array. Array element contain pointers to
+ * dentry names.
+ */
+static int build_path_from_dentry(struct v9fs_session_info *v9ses,
+ struct dentry *dentry, char ***names)
+{
+ int n = 0, i;
+ char **wnames;
+ struct dentry *ds;
+
+ for (ds = dentry; !IS_ROOT(ds); ds = ds->d_parent)
+ n++;
+
+ wnames = kmalloc(sizeof(char *) * n, GFP_KERNEL);
+ if (!wnames)
+ goto err_out;
+
+ for (ds = dentry, i = (n-1); i >= 0; i--, ds = ds->d_parent)
+ wnames[i] = (char *)ds->d_name.name;
+
+ *names = wnames;
+ return n;
+err_out:
+ return -ENOMEM;
+}
+
/**
* v9fs_fid_lookup - lookup for a fid, try to walk if not found
* @dentry: dentry to look for fid in
@@ -112,7 +140,7 @@ struct p9_fid *v9fs_fid_lookup(struct dentry *dentry)
int i, n, l, clone, any, access;
u32 uid;
struct p9_fid *fid, *old_fid = NULL;
- struct dentry *d, *ds;
+ struct dentry *ds;
struct v9fs_session_info *v9ses;
char **wnames, *uname;
@@ -139,49 +167,62 @@ struct p9_fid *v9fs_fid_lookup(struct dentry *dentry)
fid = v9fs_fid_find(dentry, uid, any);
if (fid)
return fid;
-
+ /*
+ * we don't have a matching fid. To do a TWALK we need
+ * parent fid. We need to prevent rename when we want to
+ * look at the parent.
+ */
+ down_read(&v9ses->rename_sem);
ds = dentry->d_parent;
fid = v9fs_fid_find(ds, uid, any);
- if (!fid) { /* walk from the root */
- n = 0;
- for (ds = dentry; !IS_ROOT(ds); ds = ds->d_parent)
- n++;
+ if (fid) {
+ /* Found the parent fid do a lookup with that */
+ fid = p9_client_walk(fid, 1, (char **)&dentry->d_name.name, 1);
+ goto fid_out;
+ }
+ up_read(&v9ses->rename_sem);
- fid = v9fs_fid_find(ds, uid, any);
- if (!fid) { /* the user is not attached to the fs yet */
- if (access == V9FS_ACCESS_SINGLE)
- return ERR_PTR(-EPERM);
+ /* start from the root and try to do a lookup */
+ fid = v9fs_fid_find(dentry->d_sb->s_root, uid, any);
+ if (!fid) {
+ /* the user is not attached to the fs yet */
+ if (access == V9FS_ACCESS_SINGLE)
+ return ERR_PTR(-EPERM);
- if (v9fs_proto_dotu(v9ses))
+ if (v9fs_proto_dotu(v9ses) || v9fs_proto_dotl(v9ses))
uname = NULL;
- else
- uname = v9ses->uname;
+ else
+ uname = v9ses->uname;
- fid = p9_client_attach(v9ses->clnt, NULL, uname, uid,
- v9ses->aname);
-
- if (IS_ERR(fid))
- return fid;
-
- v9fs_fid_add(ds, fid);
- }
- } else /* walk from the parent */
- n = 1;
+ fid = p9_client_attach(v9ses->clnt, NULL, uname, uid,
+ v9ses->aname);
+ if (IS_ERR(fid))
+ return fid;
- if (ds == dentry)
+ v9fs_fid_add(dentry->d_sb->s_root, fid);
+ }
+ /* If we are root ourself just return that */
+ if (dentry->d_sb->s_root == dentry)
return fid;
-
- wnames = kmalloc(sizeof(char *) * n, GFP_KERNEL);
- if (!wnames)
- return ERR_PTR(-ENOMEM);
-
- for (d = dentry, i = (n-1); i >= 0; i--, d = d->d_parent)
- wnames[i] = (char *) d->d_name.name;
-
+ /*
+ * Do a multipath walk with attached root.
+ * When walking parent we need to make sure we
+ * don't have a parallel rename happening
+ */
+ down_read(&v9ses->rename_sem);
+ n = build_path_from_dentry(v9ses, dentry, &wnames);
+ if (n < 0) {
+ fid = ERR_PTR(n);
+ goto err_out;
+ }
clone = 1;
i = 0;
while (i < n) {
l = min(n - i, P9_MAXWELEM);
+ /*
+ * We need to hold rename lock when doing a multipath
+ * walk to ensure none of the patch component change
+ */
fid = p9_client_walk(fid, l, &wnames[i], clone);
if (IS_ERR(fid)) {
if (old_fid) {
@@ -193,15 +234,17 @@ struct p9_fid *v9fs_fid_lookup(struct dentry *dentry)
p9_client_clunk(old_fid);
}
kfree(wnames);
- return fid;
+ goto err_out;
}
old_fid = fid;
i += l;
clone = 0;
}
-
kfree(wnames);
+fid_out:
v9fs_fid_add(dentry, fid);
+err_out:
+ up_read(&v9ses->rename_sem);
return fid;
}
diff --git a/fs/9p/v9fs.c b/fs/9p/v9fs.c
index f8b86e92cd6..38dc0e06759 100644
--- a/fs/9p/v9fs.c
+++ b/fs/9p/v9fs.c
@@ -237,6 +237,7 @@ struct p9_fid *v9fs_session_init(struct v9fs_session_info *v9ses,
__putname(v9ses->uname);
return ERR_PTR(-ENOMEM);
}
+ init_rwsem(&v9ses->rename_sem);
rc = bdi_setup_and_register(&v9ses->bdi, "9p", BDI_CAP_MAP_COPY);
if (rc) {
@@ -278,7 +279,7 @@ struct p9_fid *v9fs_session_init(struct v9fs_session_info *v9ses,
v9ses->maxdata = v9ses->clnt->msize - P9_IOHDRSZ;
/* for legacy mode, fall back to V9FS_ACCESS_ANY */
- if (!v9fs_proto_dotu(v9ses) &&
+ if (!(v9fs_proto_dotu(v9ses) || v9fs_proto_dotl(v9ses)) &&
((v9ses->flags&V9FS_ACCESS_MASK) == V9FS_ACCESS_USER)) {
v9ses->flags &= ~V9FS_ACCESS_MASK;
diff --git a/fs/9p/v9fs.h b/fs/9p/v9fs.h
index bec4d0bcb45..4c963c9fc41 100644
--- a/fs/9p/v9fs.h
+++ b/fs/9p/v9fs.h
@@ -104,6 +104,7 @@ struct v9fs_session_info {
struct p9_client *clnt; /* 9p client */
struct list_head slist; /* list of sessions registered with v9fs */
struct backing_dev_info bdi;
+ struct rw_semaphore rename_sem;
};
struct p9_fid *v9fs_session_init(struct v9fs_session_info *, const char *,
diff --git a/fs/9p/v9fs_vfs.h b/fs/9p/v9fs_vfs.h
index 32ef4009d03..f47c6bbb01b 100644
--- a/fs/9p/v9fs_vfs.h
+++ b/fs/9p/v9fs_vfs.h
@@ -55,6 +55,7 @@ struct inode *v9fs_get_inode(struct super_block *sb, int mode);
void v9fs_clear_inode(struct inode *inode);
ino_t v9fs_qid2ino(struct p9_qid *qid);
void v9fs_stat2inode(struct p9_wstat *, struct inode *, struct super_block *);
+void v9fs_stat2inode_dotl(struct p9_stat_dotl *, struct inode *);
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 p9_wstat *stat);
diff --git a/fs/9p/vfs_dir.c b/fs/9p/vfs_dir.c
index 36d961f342a..16c8a2a98c1 100644
--- a/fs/9p/vfs_dir.c
+++ b/fs/9p/vfs_dir.c
@@ -87,29 +87,19 @@ static void p9stat_init(struct p9_wstat *stbuf)
}
/**
- * v9fs_dir_readdir - read a directory
+ * v9fs_alloc_rdir_buf - Allocate buffer used for read and readdir
* @filp: opened file structure
- * @dirent: directory structure ???
- * @filldir: function to populate directory structure ???
+ * @buflen: Length in bytes of buffer to allocate
*
*/
-static int v9fs_dir_readdir(struct file *filp, void *dirent, filldir_t filldir)
+static int v9fs_alloc_rdir_buf(struct file *filp, int buflen)
{
- int over;
- struct p9_wstat st;
- int err = 0;
- struct p9_fid *fid;
- int buflen;
- int reclen = 0;
struct p9_rdir *rdir;
+ struct p9_fid *fid;
+ int err = 0;
- P9_DPRINTK(P9_DEBUG_VFS, "name %s\n", filp->f_path.dentry->d_name.name);
fid = filp->private_data;
-
- buflen = fid->clnt->msize - P9_IOHDRSZ;
-
- /* allocate rdir on demand */
if (!fid->rdir) {
rdir = kmalloc(sizeof(struct p9_rdir) + buflen, GFP_KERNEL);
@@ -128,6 +118,36 @@ static int v9fs_dir_readdir(struct file *filp, void *dirent, filldir_t filldir)
spin_unlock(&filp->f_dentry->d_lock);
kfree(rdir);
}
+exit:
+ return err;
+}
+
+/**
+ * v9fs_dir_readdir - read a directory
+ * @filp: opened file structure
+ * @dirent: directory structure ???
+ * @filldir: function to populate directory structure ???
+ *
+ */
+
+static int v9fs_dir_readdir(struct file *filp, void *dirent, filldir_t filldir)
+{
+ int over;
+ struct p9_wstat st;
+ int err = 0;
+ struct p9_fid *fid;
+ int buflen;
+ int reclen = 0;
+ struct p9_rdir *rdir;
+
+ P9_DPRINTK(P9_DEBUG_VFS, "name %s\n", filp->f_path.dentry->d_name.name);
+ fid = filp->private_data;
+
+ buflen = fid->clnt->msize - P9_IOHDRSZ;
+
+ err = v9fs_alloc_rdir_buf(filp, buflen);
+ if (err)
+ goto exit;
rdir = (struct p9_rdir *) fid->rdir;
err = mutex_lock_interruptible(&rdir->mutex);
@@ -176,6 +196,88 @@ exit:
return err;
}
+/**
+ * v9fs_dir_readdir_dotl - read a directory
+ * @filp: opened file structure
+ * @dirent: buffer to fill dirent structures
+ * @filldir: function to populate dirent structures
+ *
+ */
+static int v9fs_dir_readdir_dotl(struct file *filp, void *dirent,
+ filldir_t filldir)
+{
+ int over;
+ int err = 0;
+ struct p9_fid *fid;
+ int buflen;
+ struct p9_rdir *rdir;
+ struct p9_dirent curdirent;
+ u64 oldoffset = 0;
+
+ P9_DPRINTK(P9_DEBUG_VFS, "name %s\n", filp->f_path.dentry->d_name.name);
+ fid = filp->private_data;
+
+ buflen = fid->clnt->msize - P9_READDIRHDRSZ;
+
+ err = v9fs_alloc_rdir_buf(filp, buflen);
+ if (err)
+ goto exit;
+ rdir = (struct p9_rdir *) fid->rdir;
+
+ err = mutex_lock_interruptible(&rdir->mutex);
+ if (err)
+ return err;
+
+ while (err == 0) {
+ if (rdir->tail == rdir->head) {
+ err = p9_client_readdir(fid, rdir->buf, buflen,
+ filp->f_pos);
+ if (err <= 0)
+ goto unlock_and_exit;
+
+ rdir->head = 0;
+ rdir->tail = err;
+ }
+
+ while (rdir->head < rdir->tail) {
+
+ err = p9dirent_read(rdir->buf + rdir->head,
+ buflen - rdir->head, &curdirent,
+ fid->clnt->proto_version);
+ if (err < 0) {
+ P9_DPRINTK(P9_DEBUG_VFS, "returned %d\n", err);
+ err = -EIO;
+ goto unlock_and_exit;
+ }
+
+ /* d_off in dirent structure tracks the offset into
+ * the next dirent in the dir. However, filldir()
+ * expects offset into the current dirent. Hence
+ * while calling filldir send the offset from the
+ * previous dirent structure.
+ */
+ over = filldir(dirent, curdirent.d_name,
+ strlen(curdirent.d_name),
+ oldoffset, v9fs_qid2ino(&curdirent.qid),
+ curdirent.d_type);
+ oldoffset = curdirent.d_off;
+
+ if (over) {
+ err = 0;
+ goto unlock_and_exit;
+ }
+
+ filp->f_pos = curdirent.d_off;
+ rdir->head += err;
+ }
+ }
+
+unlock_and_exit:
+ mutex_unlock(&rdir->mutex);
+exit:
+ return err;
+}
+
/**
* v9fs_dir_release - close a directory
@@ -207,7 +309,7 @@ const struct file_operations v9fs_dir_operations = {
const struct file_operations v9fs_dir_operations_dotl = {
.read = generic_read_dir,
.llseek = generic_file_llseek,
- .readdir = v9fs_dir_readdir,
+ .readdir = v9fs_dir_readdir_dotl,
.open = v9fs_file_open,
.release = v9fs_dir_release,
};
diff --git a/fs/9p/vfs_file.c b/fs/9p/vfs_file.c
index 2bedc6c94fc..e97c92bd6f1 100644
--- a/fs/9p/vfs_file.c
+++ b/fs/9p/vfs_file.c
@@ -59,9 +59,13 @@ int v9fs_file_open(struct inode *inode, struct file *file)
struct p9_fid *fid;
int omode;
- P9_DPRINTK(P9_DEBUG_VFS, "inode: %p file: %p \n", inode, file);
+ P9_DPRINTK(P9_DEBUG_VFS, "inode: %p file: %p\n", inode, file);
v9ses = v9fs_inode2v9ses(inode);
- omode = v9fs_uflags2omode(file->f_flags, v9fs_proto_dotu(v9ses));
+ if (v9fs_proto_dotl(v9ses))
+ omode = file->f_flags;
+ else
+ omode = v9fs_uflags2omode(file->f_flags,
+ v9fs_proto_dotu(v9ses));
fid = file->private_data;
if (!fid) {
fid = v9fs_fid_clone(file->f_path.dentry);
@@ -73,11 +77,12 @@ int v9fs_file_open(struct inode *inode, struct file *file)
p9_client_clunk(fid);
return err;
}
- if (omode & P9_OTRUNC) {
+ if (file->f_flags & O_TRUNC) {
i_size_write(inode, 0);
inode->i_blocks = 0;
}
- if ((file->f_flags & O_APPEND) && (!v9fs_proto_dotu(v9ses)))
+ if ((file->f_flags & O_APPEND) &&
+ (!v9fs_proto_dotu(v9ses) && !v9fs_proto_dotl(v9ses)))
generic_file_llseek(file, 0, SEEK_END);
}
@@ -139,7 +144,7 @@ ssize_t
v9fs_file_readn(struct file *filp, char *data, char __user *udata, u32 count,
u64 offset)
{
- int n, total;
+ int n, total, size;
struct p9_fid *fid = filp->private_data;
P9_DPRINTK(P9_DEBUG_VFS, "fid %d offset %llu count %d\n", fid->fid,
@@ -147,6 +152,7 @@ v9fs_file_readn(struct file *filp, char *data, char __user *udata, u32 count,
n = 0;
total = 0;
+ size = fid->iounit ? fid->iounit : fid->clnt->msize - P9_IOHDRSZ;
do {
n = p9_client_read(fid, data, udata, offset, count);
if (n <= 0)
@@ -160,7 +166,7 @@ v9fs_file_readn(struct file *filp, char *data, char __user *udata, u32 count,
offset += n;
count -= n;
total += n;
- } while (count > 0 && n == (fid->clnt->msize - P9_IOHDRSZ));
+ } while (count > 0 && n == size);
if (n < 0)
total = n;
@@ -183,11 +189,13 @@ v9fs_file_read(struct file *filp, char __user *udata, size_t count,
{
int ret;
struct p9_fid *fid;
+ size_t size;
P9_DPRINTK(P9_DEBUG_VFS, "count %zu offset %lld\n", count, *offset);
fid = filp->private_data;
- if (count > (fid->clnt->msize - P9_IOHDRSZ))
+ size = fid->iounit ? fid->iounit : fid->clnt->msize - P9_IOHDRSZ;
+ if (count > size)
ret = v9fs_file_readn(filp, NULL, udata, count, *offset);
else
ret = p9_client_read(fid, NULL, udata, *offset, count);
@@ -224,9 +232,7 @@ v9fs_file_write(struct file *filp, const char __user * data,
fid = filp->private_data;
clnt = fid->clnt;
- rsize = fid->iounit;
- if (!rsize || rsize > clnt->msize-P9_IOHDRSZ)
- rsize = clnt->msize - P9_IOHDRSZ;
+ rsize = fid->iounit ? fid->iounit : clnt->msize - P9_IOHDRSZ;
do {
if (count < rsize)
diff --git a/fs/9p/vfs_inode.c b/fs/9p/vfs_inode.c
index 4331b3b5ee1..6e94f3247ce 100644
--- a/fs/9p/vfs_inode.c
+++ b/fs/9p/vfs_inode.c
@@ -35,6 +35,7 @@
#include <linux/idr.h>
#include <linux/sched.h>
#include <linux/slab.h>
+#include <linux/xattr.h>
#include <net/9p/9p.h>
#include <net/9p/client.h>
@@ -42,6 +43,7 @@
#include "v9fs_vfs.h"
#include "fid.h"
#include "cache.h"
+#include "xattr.h"
static const struct inode_operations v9fs_dir_inode_operations;
static const struct inode_operations v9fs_dir_inode_operations_dotu;
@@ -236,6 +238,41 @@ void v9fs_destroy_inode(struct inode *inode)
#endif
/**
+ * v9fs_get_fsgid_for_create - Helper function to get the gid for creating a
+ * new file system object. This checks the S_ISGID to determine the owning
+ * group of the new file system object.
+ */
+
+static gid_t v9fs_get_fsgid_for_create(struct inode *dir_inode)
+{
+ BUG_ON(dir_inode == NULL);
+
+ if (dir_inode->i_mode & S_ISGID) {
+ /* set_gid bit is set.*/
+ return dir_inode->i_gid;
+ }
+ return current_fsgid();
+}
+
+/**
+ * v9fs_dentry_from_dir_inode - helper function to get the dentry from
+ * dir inode.
+ *
+ */
+
+static struct dentry *v9fs_dentry_from_dir_inode(struct inode *inode)
+{
+ struct dentry *dentry;
+
+ spin_lock(&dcache_lock);
+ /* Directory should have only one entry. */
+ BUG_ON(S_ISDIR(inode->i_mode) && !list_is_singular(&inode->i_dentry));
+ dentry = list_entry(inode->i_dentry.next, struct dentry, d_alias);
+ spin_unlock(&dcache_lock);
+ return dentry;
+}
+
+/**
* v9fs_get_inode - helper function to setup an inode
* @sb: superblock
* @mode: mode to setup inode with
@@ -267,7 +304,13 @@ struct inode *v9fs_get_inode(struct super_block *sb, int mode)
case S_IFBLK:
case S_IFCHR:
case S_IFSOCK:
- if (!v9fs_proto_dotu(v9ses)) {
+ if (v9fs_proto_dotl(v9ses)) {
+ inode->i_op = &v9fs_file_inode_operations_dotl;
+ inode->i_fop = &v9fs_file_operations_dotl;
+ } else if (v9fs_proto_dotu(v9ses)) {
+ inode->i_op = &v9fs_file_inode_operations;
+ inode->i_fop = &v9fs_file_operations;
+ } else {
P9_DPRINTK(P9_DEBUG_ERROR,
"special files without extended mode\n");
err = -EINVAL;
@@ -396,23 +439,14 @@ void v9fs_clear_inode(struct inode *inode)
#endif
}
-/**
- * v9fs_inode_from_fid - populate an inode by issuing a attribute request
- * @v9ses: session information
- * @fid: fid to issue attribute request for
- * @sb: superblock on which to create inode
- *
- */
-
static struct inode *
-v9fs_inode_from_fid(struct v9fs_session_info *v9ses, struct p9_fid *fid,
+v9fs_inode(struct v9fs_session_info *v9ses, struct p9_fid *fid,
struct super_block *sb)
{
int err, umode;
- struct inode *ret;
+ struct inode *ret = NULL;
struct p9_wstat *st;
- ret = NULL;
st = p9_client_stat(fid);
if (IS_ERR(st))
return ERR_CAST(st);
@@ -433,15 +467,62 @@ v9fs_inode_from_fid(struct v9fs_session_info *v9ses, struct p9_fid *fid,
#endif
p9stat_free(st);
kfree(st);
-
return ret;
-
error:
p9stat_free(st);
kfree(st);
return ERR_PTR(err);
}
+static struct inode *
+v9fs_inode_dotl(struct v9fs_session_info *v9ses, struct p9_fid *fid,
+ struct super_block *sb)
+{
+ struct inode *ret = NULL;
+ int err;
+ struct p9_stat_dotl *st;
+
+ st = p9_client_getattr_dotl(fid, P9_STATS_BASIC);
+ if (IS_ERR(st))
+ return ERR_CAST(st);
+
+ ret = v9fs_get_inode(sb, st->st_mode);
+ if (IS_ERR(ret)) {
+ err = PTR_ERR(ret);
+ goto error;
+ }
+
+ v9fs_stat2inode_dotl(st, ret);
+ ret->i_ino = v9fs_qid2ino(&st->qid);
+#ifdef CONFIG_9P_FSCACHE
+ v9fs_vcookie_set_qid(ret, &st->qid);
+ v9fs_cache_inode_get_cookie(ret);
+#endif
+ kfree(st);
+ return ret;
+error:
+ kfree(st);
+ return ERR_PTR(err);
+}
+
+/**
+ * v9fs_inode_from_fid - Helper routine to populate an inode by
+ * issuing a attribute request
+ * @v9ses: session information
+ * @fid: fid to issue attribute request for
+ * @sb: superblock on which to create inode
+ *
+ */
+static inline struct inode *
+v9fs_inode_from_fid(struct v9fs_session_info *v9ses, struct p9_fid *fid,
+ struct super_block *sb)
+{
+ if (v9fs_proto_dotl(v9ses))
+ return v9fs_inode_dotl(v9ses, fid, sb);
+ else
+ return v9fs_inode(v9ses, fid, sb);
+}
+
/**
* v9fs_remove - helper function to remove files and directories
* @dir: directory inode that is being deleted
@@ -563,6 +644,118 @@ error:
}
/**
+ * v9fs_vfs_create_dotl - VFS hook to create files for 9P2000.L protocol.
+ * @dir: directory inode that is being created
+ * @dentry: dentry that is being deleted
+ * @mode: create permissions
+ * @nd: path information
+ *
+ */
+
+static int
+v9fs_vfs_create_dotl(struct inode *dir, struct dentry *dentry, int mode,
+ struct nameidata *nd)
+{
+ int err = 0;
+ char *name = NULL;
+ gid_t gid;
+ int flags;
+ struct v9fs_session_info *v9ses;
+ struct p9_fid *fid = NULL;
+ struct p9_fid *dfid, *ofid;
+ struct file *filp;
+ struct p9_qid qid;
+ struct inode *inode;
+
+ v9ses = v9fs_inode2v9ses(dir);
+ if (nd && nd->flags & LOOKUP_OPEN)
+ flags = nd->intent.open.flags - 1;
+ else
+ flags = O_RDWR;
+
+ name = (char *) dentry->d_name.name;
+ P9_DPRINTK(P9_DEBUG_VFS, "v9fs_vfs_create_dotl: name:%s flags:0x%x "
+ "mode:0x%x\n", name, flags, mode);
+
+ dfid = v9fs_fid_lookup(dentry->d_parent);
+ if (IS_ERR(dfid)) {
+ err = PTR_ERR(dfid);
+ P9_DPRINTK(P9_DEBUG_VFS, "fid lookup failed %d\n", err);
+ return err;
+ }
+
+ /* clone a fid to use for creation */
+ ofid = p9_client_walk(dfid, 0, NULL, 1);
+ if (IS_ERR(ofid)) {
+ err = PTR_ERR(ofid);
+ P9_DPRINTK(P9_DEBUG_VFS, "p9_client_walk failed %d\n", err);
+ return err;
+ }
+
+ gid = v9fs_get_fsgid_for_create(dir);
+ err = p9_client_create_dotl(ofid, name, flags, mode, gid, &qid);
+ if (err < 0) {
+ P9_DPRINTK(P9_DEBUG_VFS,
+ "p9_client_open_dotl failed in creat %d\n",
+ err);
+ goto error;
+ }
+
+ /* No need to populate the inode if we are not opening the file AND
+ * not in cached mode.
+ */
+ if (!v9ses->cache && !(nd && nd->flags & LOOKUP_OPEN)) {
+ /* Not in cached mode. No need to populate inode with stat */
+ dentry->d_op = &v9fs_dentry_operations;
+ p9_client_clunk(ofid);
+ d_instantiate(dentry, NULL);
+ return 0;
+ }
+
+ /* Now walk from the parent so we can get an unopened fid. */
+ fid = p9_client_walk(dfid, 1, &name, 1);
+ if (IS_ERR(fid)) {
+ err = PTR_ERR(fid);
+ P9_DPRINTK(P9_DEBUG_VFS, "p9_client_walk failed %d\n", err);
+ fid = NULL;
+ goto error;
+ }
+
+ /* instantiate inode and assign the unopened fid to dentry */
+ inode = v9fs_inode_from_fid(v9ses, fid, dir->i_sb);
+ if (IS_ERR(inode)) {
+ err = PTR_ERR(inode);
+ P9_DPRINTK(P9_DEBUG_VFS, "inode creation failed %d\n", err);
+ goto error;
+ }
+ dentry->d_op = &v9fs_cached_dentry_operations;
+ d_instantiate(dentry, inode);
+ err = v9fs_fid_add(dentry, fid);
+ if (err < 0)
+ 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)) {
+ p9_client_clunk(ofid);
+ return PTR_ERR(filp);
+ }
+ filp->private_data = ofid;
+ } else
+ p9_client_clunk(ofid);
+
+ return 0;
+
+error:
+ if (ofid)
+ p9_client_clunk(ofid);
+ if (fid)
+ p9_client_clunk(fid);
+ return err;
+}
+
+/**
* v9fs_vfs_create - VFS hook to create files
* @dir: directory inode that is being created
* @dentry: dentry that is being deleted
@@ -652,6 +845,83 @@ static int v9fs_vfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
return err;
}
+
+/**
+ * v9fs_vfs_mkdir_dotl - VFS mkdir hook to create a directory
+ * @dir: inode that is being unlinked
+ * @dentry: dentry that is being unlinked
+ * @mode: mode for new directory
+ *
+ */
+
+static int v9fs_vfs_mkdir_dotl(struct inode *dir, struct dentry *dentry,
+ int mode)
+{
+ int err;
+ struct v9fs_session_info *v9ses;
+ struct p9_fid *fid = NULL, *dfid = NULL;
+ gid_t gid;
+ char *name;
+ struct inode *inode;
+ struct p9_qid qid;
+ struct dentry *dir_dentry;
+
+ P9_DPRINTK(P9_DEBUG_VFS, "name %s\n", dentry->d_name.name);
+ err = 0;
+ v9ses = v9fs_inode2v9ses(dir);
+
+ mode |= S_IFDIR;
+ dir_dentry = v9fs_dentry_from_dir_inode(dir);
+ dfid = v9fs_fid_lookup(dir_dentry);
+ if (IS_ERR(dfid)) {
+ err = PTR_ERR(dfid);
+ P9_DPRINTK(P9_DEBUG_VFS, "fid lookup failed %d\n", err);
+ dfid = NULL;
+ goto error;
+ }
+
+ gid = v9fs_get_fsgid_for_create(dir);
+ if (gid < 0) {
+ P9_DPRINTK(P9_DEBUG_VFS, "v9fs_get_fsgid_for_create failed\n");
+ goto error;
+ }
+
+ name = (char *) dentry->d_name.name;
+ err = p9_client_mkdir_dotl(dfid, name, mode, gid, &qid);
+ if (err < 0)
+ goto error;
+
+ /* instantiate inode and assign the unopened fid to the dentry */
+ if (v9ses->cache == CACHE_LOOSE || v9ses->cache == CACHE_FSCACHE) {
+ fid = p9_client_walk(dfid, 1, &name, 1);
+ if (IS_ERR(fid)) {
+ err = PTR_ERR(fid);
+ P9_DPRINTK(P9_DEBUG_VFS, "p9_client_walk failed %d\n",
+ err);
+ fid = NULL;
+ goto error;
+ }
+
+ inode = v9fs_inode_from_fid(v9ses, fid, dir->i_sb);
+ if (IS_ERR(inode)) {
+ err = PTR_ERR(inode);
+ P9_DPRINTK(P9_DEBUG_VFS, "inode creation failed %d\n",
+ err);
+ goto error;
+ }
+ dentry->d_op = &v9fs_cached_dentry_operations;
+ d_instantiate(dentry, inode);
+ err = v9fs_fid_add(dentry, fid);
+ if (err < 0)
+ goto error;
+ fid = NULL;
+ }
+error:
+ if (fid)
+ p9_client_clunk(fid);
+ return err;
+}
+
/**
* v9fs_vfs_lookup - VFS lookup hook to "walk" to a new inode
* @dir: inode that is being walked from
@@ -678,6 +948,7 @@ static struct dentry *v9fs_vfs_lookup(struct inode *dir, struct dentry *dentry,
sb = dir->i_sb;
v9ses = v9fs_inode2v9ses(dir);
+ /* We can walk d_parent because we hold the dir->i_mutex */
dfid = v9fs_fid_lookup(dentry->d_parent);
if (IS_ERR(dfid))
return ERR_CAST(dfid);
@@ -785,27 +1056,33 @@ v9fs_vfs_rename(struct inode *old_dir, struct dentry *old_dentry,
goto clunk_olddir;
}
+ down_write(&v9ses->rename_sem);
if (v9fs_proto_dotl(v9ses)) {
retval = p9_client_rename(oldfid, newdirfid,
(char *) new_dentry->d_name.name);
if (retval != -ENOSYS)
goto clunk_newdir;
}
+ if (old_dentry->d_parent != new_dentry->d_parent) {
+ /*
+ * 9P .u can only handle file rename in the same directory
+ */
- /* 9P can only handle file rename in the same directory */
- if (memcmp(&olddirfid->qid, &newdirfid->qid, sizeof(newdirfid->qid))) {
P9_DPRINTK(P9_DEBUG_ERROR,
"old dir and new dir are different\n");
retval = -EXDEV;
goto clunk_newdir;
}
-
v9fs_blank_wstat(&wstat);
wstat.muid = v9ses->uname;
wstat.name = (char *) new_dentry->d_name.name;
retval = p9_client_wstat(oldfid, &wstat);
clunk_newdir:
+ if (!retval)
+ /* successful rename */
+ d_move(old_dentry, new_dentry);
+ up_write(&v9ses->rename_sem);
p9_client_clunk(newdirfid);
clunk_olddir:
@@ -853,6 +1130,42 @@ v9fs_vfs_getattr(struct vfsmount *mnt, struct dentry *dentry,
return 0;
}
+static int
+v9fs_vfs_getattr_dotl(struct vfsmount *mnt, struct dentry *dentry,
+ struct kstat *stat)
+{
+ int err;
+ struct v9fs_session_info *v9ses;
+ struct p9_fid *fid;
+ struct p9_stat_dotl *st;
+
+ P9_DPRINTK(P9_DEBUG_VFS, "dentry: %p\n", dentry);
+ err = -EPERM;
+ v9ses = v9fs_inode2v9ses(dentry->d_inode);
+ if (v9ses->cache == CACHE_LOOSE || v9ses->cache == CACHE_FSCACHE)
+ return simple_getattr(mnt, dentry, stat);
+
+ fid = v9fs_fid_lookup(dentry);
+ if (IS_ERR(fid))
+ return PTR_ERR(fid);
+
+ /* Ask for all the fields in stat structure. Server will return
+ * whatever it supports
+ */
+
+ st = p9_client_getattr_dotl(fid, P9_STATS_ALL);
+ if (IS_ERR(st))
+ return PTR_ERR(st);
+
+ v9fs_stat2inode_dotl(st, dentry->d_inode);
+ generic_fillattr(dentry->d_inode, stat);
+ /* Change block size to what the server returned */
+ stat->blksize = st->st_blksize;
+
+ kfree(st);
+ return 0;
+}
+
/**
* v9fs_vfs_setattr - set file metadata
* @dentry: file whose metadata to set
@@ -903,6 +1216,49 @@ static int v9fs_vfs_setattr(struct dentry *dentry, struct iattr *iattr)
}
/**
+ * v9fs_vfs_setattr_dotl - set file metadata
+ * @dentry: file whose metadata to set
+ * @iattr: metadata assignment structure
+ *
+ */
+
+static int v9fs_vfs_setattr_dotl(struct dentry *dentry, struct iattr *iattr)
+{
+ int retval;
+ struct v9fs_session_info *v9ses;
+ struct p9_fid *fid;
+ struct p9_iattr_dotl p9attr;
+
+ P9_DPRINTK(P9_DEBUG_VFS, "\n");
+
+ retval = inode_change_ok(dentry->d_inode, iattr);
+ if (retval)
+ return retval;
+
+ p9attr.valid = iattr->ia_valid;
+ p9attr.mode = iattr->ia_mode;
+ p9attr.uid = iattr->ia_uid;
+ p9attr.gid = iattr->ia_gid;
+ p9attr.size = iattr->ia_size;
+ p9attr.atime_sec = iattr->ia_atime.tv_sec;
+ p9attr.atime_nsec = iattr->ia_atime.tv_nsec;
+ p9attr.mtime_sec = iattr->ia_mtime.tv_sec;
+ p9attr.mtime_nsec = iattr->ia_mtime.tv_nsec;
+
+ retval = -EPERM;
+ v9ses = v9fs_inode2v9ses(dentry->d_inode);
+ fid = v9fs_fid_lookup(dentry);
+ if (IS_ERR(fid))
+ return PTR_ERR(fid);
+
+ retval = p9_client_setattr(fid, &p9attr);
+ if (retval >= 0)
+ retval = inode_setattr(dentry->d_inode, iattr);
+
+ return retval;
+}
+
+/**
* v9fs_stat2inode - populate an inode structure with mistat info
* @stat: Plan 9 metadata (mistat) structure
* @inode: inode to populate
@@ -980,6 +1336,77 @@ v9fs_stat2inode(struct p9_wstat *stat, struct inode *inode,
}
/**
+ * v9fs_stat2inode_dotl - populate an inode structure with stat info
+ * @stat: stat structure
+ * @inode: inode to populate
+ * @sb: superblock of filesystem
+ *
+ */
+
+void
+v9fs_stat2inode_dotl(struct p9_stat_dotl *stat, struct inode *inode)
+{
+
+ if ((stat->st_result_mask & P9_STATS_BASIC) == P9_STATS_BASIC) {
+ inode->i_atime.tv_sec = stat->st_atime_sec;
+ inode->i_atime.tv_nsec = stat->st_atime_nsec;
+ inode->i_mtime.tv_sec = stat->st_mtime_sec;
+ inode->i_mtime.tv_nsec = stat->st_mtime_nsec;
+ inode->i_ctime.tv_sec = stat->st_ctime_sec;
+ inode->i_ctime.tv_nsec = stat->st_ctime_nsec;
+ inode->i_uid = stat->st_uid;
+ inode->i_gid = stat->st_gid;
+ inode->i_nlink = stat->st_nlink;
+ inode->i_mode = stat->st_mode;
+ inode->i_rdev = new_decode_dev(stat->st_rdev);
+
+ if ((S_ISBLK(inode->i_mode)) || (S_ISCHR(inode->i_mode)))
+ init_special_inode(inode, inode->i_mode, inode->i_rdev);
+
+ i_size_write(inode, stat->st_size);
+ inode->i_blocks = stat->st_blocks;
+ } else {
+ if (stat->st_result_mask & P9_STATS_ATIME) {
+ inode->i_atime.tv_sec = stat->st_atime_sec;
+ inode->i_atime.tv_nsec = stat->st_atime_nsec;
+ }
+ if (stat->st_result_mask & P9_STATS_MTIME) {
+ inode->i_mtime.tv_sec = stat->st_mtime_sec;
+ inode->i_mtime.tv_nsec = stat->st_mtime_nsec;
+ }
+ if (stat->st_result_mask & P9_STATS_CTIME) {
+ inode->i_ctime.tv_sec = stat->st_ctime_sec;
+ inode->i_ctime.tv_nsec = stat->st_ctime_nsec;
+ }
+ if (stat->st_result_mask & P9_STATS_UID)
+ inode->i_uid = stat->st_uid;
+ if (stat->st_result_mask & P9_STATS_GID)
+ inode->i_gid = stat->st_gid;
+ if (stat->st_result_mask & P9_STATS_NLINK)
+ inode->i_nlink = stat->st_nlink;
+ if (stat->st_result_mask & P9_STATS_MODE) {
+ inode->i_mode = stat->st_mode;
+ if ((S_ISBLK(inode->i_mode)) ||
+ (S_ISCHR(inode->i_mode)))
+ init_special_inode(inode, inode->i_mode,
+ inode->i_rdev);
+ }
+ if (stat->st_result_mask & P9_STATS_RDEV)
+ inode->i_rdev = new_decode_dev(stat->st_rdev);
+ if (stat->st_result_mask & P9_STATS_SIZE)
+ i_size_write(inode, stat->st_size);
+ if (stat->st_result_mask & P9_STATS_BLOCKS)
+ inode->i_blocks = stat->st_blocks;
+ }
+ if (stat->st_result_mask & P9_STATS_GEN)
+ inode->i_generation = stat->st_gen;
+
+ /* Currently we don't support P9_STATS_BTIME and P9_STATS_DATA_VERSION
+ * because the inode structure does not have fields for them.
+ */
+}
+
+/**
* v9fs_qid2ino - convert qid into inode number
* @qid: qid to hash
*
@@ -1022,7 +1449,7 @@ static int v9fs_readlink(struct dentry *dentry, char *buffer, int buflen)
if (IS_ERR(fid))
return PTR_ERR(fid);
- if (!v9fs_proto_dotu(v9ses))
+ if (!v9fs_proto_dotu(v9ses) && !v9fs_proto_dotl(v9ses))
return -EBADF;
st = p9_client_stat(fid);
@@ -1128,6 +1555,99 @@ static int v9fs_vfs_mkspecial(struct inode *dir, struct dentry *dentry,
}
/**
+ * v9fs_vfs_symlink_dotl - helper function to create symlinks
+ * @dir: directory inode containing symlink
+ * @dentry: dentry for symlink
+ * @symname: symlink data
+ *
+ * See Also: 9P2000.L RFC for more information
+ *
+ */
+
+static int
+v9fs_vfs_symlink_dotl(struct inode *dir, struct dentry *dentry,
+ const char *symname)
+{
+ struct v9fs_session_info *v9ses;
+ struct p9_fid *dfid;
+ struct p9_fid *fid = NULL;
+ struct inode *inode;
+ struct p9_qid qid;
+ char *name;
+ int err;
+ gid_t gid;
+
+ name = (char *) dentry->d_name.name;
+ P9_DPRINTK(P9_DEBUG_VFS, "v9fs_vfs_symlink_dotl : %lu,%s,%s\n",
+ dir->i_ino, name, symname);
+ v9ses = v9fs_inode2v9ses(dir);
+
+ dfid = v9fs_fid_lookup(dentry->d_parent);
+ if (IS_ERR(dfid)) {
+ err = PTR_ERR(dfid);
+ P9_DPRINTK(P9_DEBUG_VFS, "fid lookup failed %d\n", err);
+ return err;
+ }
+
+ gid = v9fs_get_fsgid_for_create(dir);
+
+ if (gid < 0) {
+ P9_DPRINTK(P9_DEBUG_VFS, "v9fs_get_egid failed %d\n", gid);
+ goto error;
+ }
+
+ /* Server doesn't alter fid on TSYMLINK. Hence no need to clone it. */
+ err = p9_client_symlink(dfid, name, (char *)symname, gid, &qid);
+
+ if (err < 0) {
+ P9_DPRINTK(P9_DEBUG_VFS, "p9_client_symlink failed %d\n", err);
+ goto error;
+ }
+
+ if (v9ses->cache) {
+ /* Now walk from the parent so we can get an unopened fid. */
+ fid = p9_client_walk(dfid, 1, &name, 1);
+ if (IS_ERR(fid)) {
+ err = PTR_ERR(fid);
+ P9_DPRINTK(P9_DEBUG_VFS, "p9_client_walk failed %d\n",
+ err);
+ fid = NULL;
+ goto error;
+ }
+
+ /* instantiate inode and assign the unopened fid to dentry */
+ inode = v9fs_inode_from_fid(v9ses, fid, dir->i_sb);
+ if (IS_ERR(inode)) {
+ err = PTR_ERR(inode);
+ P9_DPRINTK(P9_DEBUG_VFS, "inode creation failed %d\n",
+ err);
+ goto error;
+ }
+ dentry->d_op = &v9fs_cached_dentry_operations;
+ d_instantiate(dentry, inode);
+ err = v9fs_fid_add(dentry, fid);
+ if (err < 0)
+ goto error;
+ fid = NULL;
+ } else {
+ /* Not in cached mode. No need to populate inode with stat */
+ inode = v9fs_get_inode(dir->i_sb, S_IFLNK);
+ if (IS_ERR(inode)) {
+ err = PTR_ERR(inode);
+ goto error;
+ }
+ dentry->d_op = &v9fs_dentry_operations;
+ d_instantiate(dentry, inode);
+ }
+
+error:
+ if (fid)
+ p9_client_clunk(fid);
+
+ return err;
+}
+
+/**
* v9fs_vfs_symlink - helper function to create symlinks
* @dir: directory inode containing symlink
* @dentry: dentry for symlink
@@ -1186,6 +1706,76 @@ clunk_fid:
}
/**
+ * v9fs_vfs_link_dotl - create a hardlink for dotl
+ * @old_dentry: dentry for file to link to
+ * @dir: inode destination for new link
+ * @dentry: dentry for link
+ *
+ */
+
+static int
+v9fs_vfs_link_dotl(struct dentry *old_dentry, struct inode *dir,
+ struct dentry *dentry)
+{
+ int err;
+ struct p9_fid *dfid, *oldfid;
+ char *name;
+ struct v9fs_session_info *v9ses;
+ struct dentry *dir_dentry;
+
+ P9_DPRINTK(P9_DEBUG_VFS, "dir ino: %lu, old_name: %s, new_name: %s\n",
+ dir->i_ino, old_dentry->d_name.name,
+ dentry->d_name.name);
+
+ v9ses = v9fs_inode2v9ses(dir);
+ dir_dentry = v9fs_dentry_from_dir_inode(dir);
+ dfid = v9fs_fid_lookup(dir_dentry);
+ if (IS_ERR(dfid))
+ return PTR_ERR(dfid);
+
+ oldfid = v9fs_fid_lookup(old_dentry);
+ if (IS_ERR(oldfid))
+ return PTR_ERR(oldfid);
+
+ name = (char *) dentry->d_name.name;
+
+ err = p9_client_link(dfid, oldfid, (char *)dentry->d_name.name);
+
+ if (err < 0) {
+ P9_DPRINTK(P9_DEBUG_VFS, "p9_client_link failed %d\n", err);
+ return err;
+ }
+
+ if (v9ses->cache == CACHE_LOOSE || v9ses->cache == CACHE_FSCACHE) {
+ /* Get the latest stat info from server. */
+ struct p9_fid *fid;
+ struct p9_stat_dotl *st;
+
+ fid = v9fs_fid_lookup(old_dentry);
+ if (IS_ERR(fid))
+ return PTR_ERR(fid);
+
+ st = p9_client_getattr_dotl(fid, P9_STATS_BASIC);
+ if (IS_ERR(st))
+ return PTR_ERR(st);
+
+ v9fs_stat2inode_dotl(st, old_dentry->d_inode);
+
+ kfree(st);
+ } else {
+ /* Caching disabled. No need to get upto date stat info.
+ * This dentry will be released immediately. So, just i_count++
+ */
+ atomic_inc(&old_dentry->d_inode->i_count);
+ }
+
+ dentry->d_op = old_dentry->d_op;
+ d_instantiate(dentry, old_dentry->d_inode);
+
+ return err;
+}
+
+/**
* v9fs_vfs_mknod - create a special file
* @dir: inode destination for new link
* @dentry: dentry for file
@@ -1230,6 +1820,100 @@ v9fs_vfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t rdev)
return retval;
}
+/**
+ * v9fs_vfs_mknod_dotl - create a special file
+ * @dir: inode destination for new link
+ * @dentry: dentry for file
+ * @mode: mode for creation
+ * @rdev: device associated with special file
+ *
+ */
+static int
+v9fs_vfs_mknod_dotl(struct inode *dir, struct dentry *dentry, int mode,
+ dev_t rdev)
+{
+ int err;
+ char *name;
+ struct v9fs_session_info *v9ses;
+ struct p9_fid *fid = NULL, *dfid = NULL;
+ struct inode *inode;
+ gid_t gid;
+ struct p9_qid qid;
+ struct dentry *dir_dentry;
+
+ 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))
+ return -EINVAL;
+
+ v9ses = v9fs_inode2v9ses(dir);
+ dir_dentry = v9fs_dentry_from_dir_inode(dir);
+ dfid = v9fs_fid_lookup(dir_dentry);
+ if (IS_ERR(dfid)) {
+ err = PTR_ERR(dfid);
+ P9_DPRINTK(P9_DEBUG_VFS, "fid lookup failed %d\n", err);
+ dfid = NULL;
+ goto error;
+ }
+
+ gid = v9fs_get_fsgid_for_create(dir);
+ if (gid < 0) {
+ P9_DPRINTK(P9_DEBUG_VFS, "v9fs_get_fsgid_for_create failed\n");
+ goto error;
+ }
+
+ name = (char *) dentry->d_name.name;
+
+ err = p9_client_mknod_dotl(dfid, name, mode, rdev, gid, &qid);
+ if (err < 0)
+ goto error;
+
+ /* instantiate inode and assign the unopened fid to the dentry */
+ if (v9ses->cache == CACHE_LOOSE || v9ses->cache == CACHE_FSCACHE) {
+ fid = p9_client_walk(dfid, 1, &name, 1);
+ if (IS_ERR(fid)) {
+ err = PTR_ERR(fid);
+ P9_DPRINTK(P9_DEBUG_VFS, "p9_client_walk failed %d\n",
+ err);
+ fid = NULL;
+ goto error;
+ }
+
+ inode = v9fs_inode_from_fid(v9ses, fid, dir->i_sb);
+ if (IS_ERR(inode)) {
+ err = PTR_ERR(inode);
+ P9_DPRINTK(P9_DEBUG_VFS, "inode creation failed %d\n",
+ err);
+ goto error;
+ }
+ dentry->d_op = &v9fs_cached_dentry_operations;
+ d_instantiate(dentry, inode);
+ err = v9fs_fid_add(dentry, fid);
+ if (err < 0)
+ goto error;
+ fid = NULL;
+ } else {
+ /*
+ * Not in cached mode. No need to populate inode with stat.
+ * socket syscall returns a fd, so we need instantiate
+ */
+ inode = v9fs_get_inode(dir->i_sb, mode);
+ if (IS_ERR(inode)) {
+ err = PTR_ERR(inode);
+ goto error;
+ }
+ dentry->d_op = &v9fs_dentry_operations;
+ d_instantiate(dentry, inode);
+ }
+
+error:
+ if (fid)
+ p9_client_clunk(fid);
+ return err;
+}
+
static const struct inode_operations v9fs_dir_inode_operations_dotu = {
.create = v9fs_vfs_create,
.lookup = v9fs_vfs_lookup,
@@ -1238,24 +1922,29 @@ static const struct inode_operations v9fs_dir_inode_operations_dotu = {
.unlink = v9fs_vfs_unlink,
.mkdir = v9fs_vfs_mkdir,
.rmdir = v9fs_vfs_rmdir,
- .mknod = v9fs_vfs_mknod,
+ .mknod = v9fs_vfs_mknod_dotl,
.rename = v9fs_vfs_rename,
.getattr = v9fs_vfs_getattr,
.setattr = v9fs_vfs_setattr,
};
static const struct inode_operations v9fs_dir_inode_operations_dotl = {
- .create = v9fs_vfs_create,
+ .create = v9fs_vfs_create_dotl,
.lookup = v9fs_vfs_lookup,
- .symlink = v9fs_vfs_symlink,
- .link = v9fs_vfs_link,
+ .link = v9fs_vfs_link_dotl,
+ .symlink = v9fs_vfs_symlink_dotl,
.unlink = v9fs_vfs_unlink,
- .mkdir = v9fs_vfs_mkdir,
+ .mkdir = v9fs_vfs_mkdir_dotl,
.rmdir = v9fs_vfs_rmdir,
- .mknod = v9fs_vfs_mknod,
+ .mknod = v9fs_vfs_mknod_dotl,
.rename = v9fs_vfs_rename,
- .getattr = v9fs_vfs_getattr,
- .setattr = v9fs_vfs_setattr,
+ .getattr = v9fs_vfs_getattr_dotl,
+ .setattr = v9fs_vfs_setattr_dotl,
+ .setxattr = generic_setxattr,
+ .getxattr = generic_getxattr,
+ .removexattr = generic_removexattr,
+ .listxattr = v9fs_listxattr,
+
};
static const struct inode_operations v9fs_dir_inode_operations = {
@@ -1276,8 +1965,12 @@ static const struct inode_operations v9fs_file_inode_operations = {
};
static const struct inode_operations v9fs_file_inode_operations_dotl = {
- .getattr = v9fs_vfs_getattr,
- .setattr = v9fs_vfs_setattr,
+ .getattr = v9fs_vfs_getattr_dotl,
+ .setattr = v9fs_vfs_setattr_dotl,
+ .setxattr = generic_setxattr,
+ .getxattr = generic_getxattr,
+ .removexattr = generic_removexattr,
+ .listxattr = v9fs_listxattr,
};
static const struct inode_operations v9fs_symlink_inode_operations = {
@@ -1292,6 +1985,10 @@ static const struct inode_operations v9fs_symlink_inode_operations_dotl = {
.readlink = generic_readlink,
.follow_link = v9fs_vfs_follow_link,
.put_link = v9fs_vfs_put_link,
- .getattr = v9fs_vfs_getattr,
- .setattr = v9fs_vfs_setattr,
+ .getattr = v9fs_vfs_getattr_dotl,
+ .setattr = v9fs_vfs_setattr_dotl,
+ .setxattr = generic_setxattr,
+ .getxattr = generic_getxattr,
+ .removexattr = generic_removexattr,
+ .listxattr = v9fs_listxattr,
};
diff --git a/fs/9p/vfs_super.c b/fs/9p/vfs_super.c
index be74d020436..4b9ede0b41b 100644
--- a/fs/9p/vfs_super.c
+++ b/fs/9p/vfs_super.c
@@ -45,6 +45,7 @@
#include "v9fs.h"
#include "v9fs_vfs.h"
#include "fid.h"
+#include "xattr.h"
static const struct super_operations v9fs_super_ops, v9fs_super_ops_dotl;
@@ -77,9 +78,10 @@ v9fs_fill_super(struct super_block *sb, struct v9fs_session_info *v9ses,
sb->s_blocksize_bits = fls(v9ses->maxdata - 1);
sb->s_blocksize = 1 << sb->s_blocksize_bits;
sb->s_magic = V9FS_MAGIC;
- if (v9fs_proto_dotl(v9ses))
+ if (v9fs_proto_dotl(v9ses)) {
sb->s_op = &v9fs_super_ops_dotl;
- else
+ sb->s_xattr = v9fs_xattr_handlers;
+ } else
sb->s_op = &v9fs_super_ops;
sb->s_bdi = &v9ses->bdi;
@@ -107,7 +109,6 @@ static int v9fs_get_sb(struct file_system_type *fs_type, int flags,
struct inode *inode = NULL;
struct dentry *root = NULL;
struct v9fs_session_info *v9ses = NULL;
- struct p9_wstat *st = NULL;
int mode = S_IRWXUGO | S_ISVTX;
struct p9_fid *fid;
int retval = 0;
@@ -124,16 +125,10 @@ static int v9fs_get_sb(struct file_system_type *fs_type, int flags,
goto close_session;
}
- st = p9_client_stat(fid);
- if (IS_ERR(st)) {
- retval = PTR_ERR(st);
- goto clunk_fid;
- }
-
sb = sget(fs_type, NULL, v9fs_set_super, v9ses);
if (IS_ERR(sb)) {
retval = PTR_ERR(sb);
- goto free_stat;
+ goto clunk_fid;
}
v9fs_fill_super(sb, v9ses, flags, data);
@@ -151,22 +146,38 @@ static int v9fs_get_sb(struct file_system_type *fs_type, int flags,
}
sb->s_root = root;
- root->d_inode->i_ino = v9fs_qid2ino(&st->qid);
- v9fs_stat2inode(st, root->d_inode, sb);
+ if (v9fs_proto_dotl(v9ses)) {
+ struct p9_stat_dotl *st = NULL;
+ st = p9_client_getattr_dotl(fid, P9_STATS_BASIC);
+ if (IS_ERR(st)) {
+ retval = PTR_ERR(st);
+ goto clunk_fid;
+ }
+
+ v9fs_stat2inode_dotl(st, root->d_inode);
+ kfree(st);
+ } else {
+ struct p9_wstat *st = NULL;
+ st = p9_client_stat(fid);
+ if (IS_ERR(st)) {
+ retval = PTR_ERR(st);
+ goto clunk_fid;
+ }
+
+ root->d_inode->i_ino = v9fs_qid2ino(&st->qid);
+ v9fs_stat2inode(st, root->d_inode, sb);
+
+ p9stat_free(st);
+ kfree(st);
+ }
v9fs_fid_add(root, fid);
- p9stat_free(st);
- kfree(st);
P9_DPRINTK(P9_DEBUG_VFS, " simple set mount, return 0\n");
simple_set_mnt(mnt, sb);
return 0;
-free_stat:
- p9stat_free(st);
- kfree(st);
-
clunk_fid:
p9_client_clunk(fid);
@@ -176,8 +187,6 @@ close_session:
return retval;
release_sb:
- p9stat_free(st);
- kfree(st);
deactivate_locked_super(sb);
return retval;
}
@@ -278,4 +287,5 @@ struct file_system_type v9fs_fs_type = {
.get_sb = v9fs_get_sb,
.kill_sb = v9fs_kill_super,
.owner = THIS_MODULE,
+ .fs_flags = FS_RENAME_DOES_D_MOVE,
};
diff --git a/fs/9p/xattr.c b/fs/9p/xattr.c
new file mode 100644
index 00000000000..f88e5c2dc87
--- /dev/null
+++ b/fs/9p/xattr.c
@@ -0,0 +1,160 @@
+/*
+ * Copyright IBM Corporation, 2010
+ * Author Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2.1 of the GNU Lesser 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.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/sched.h>
+#include <net/9p/9p.h>
+#include <net/9p/client.h>
+
+#include "fid.h"
+#include "xattr.h"
+
+/*
+ * v9fs_xattr_get()
+ *
+ * Copy an extended attribute into the buffer
+ * provided, or compute the buffer size required.
+ * Buffer is NULL to compute the size of the buffer required.
+ *
+ * Returns a negative error number on failure, or the number of bytes
+ * used / required on success.
+ */
+ssize_t v9fs_xattr_get(struct dentry *dentry, const char *name,
+ void *buffer, size_t buffer_size)
+{
+ ssize_t retval;
+ int msize, read_count;
+ u64 offset = 0, attr_size;
+ struct p9_fid *fid, *attr_fid;
+
+ P9_DPRINTK(P9_DEBUG_VFS, "%s: name = %s value_len = %zu\n",
+ __func__, name, buffer_size);
+
+ fid = v9fs_fid_lookup(dentry);
+ if (IS_ERR(fid))
+ return PTR_ERR(fid);
+
+ attr_fid = p9_client_xattrwalk(fid, name, &attr_size);
+ if (IS_ERR(attr_fid)) {
+ retval = PTR_ERR(attr_fid);
+ P9_DPRINTK(P9_DEBUG_VFS,
+ "p9_client_attrwalk failed %zd\n", retval);
+ attr_fid = NULL;
+ goto error;
+ }
+ if (!buffer_size) {
+ /* request to get the attr_size */
+ retval = attr_size;
+ goto error;
+ }
+ if (attr_size > buffer_size) {
+ retval = -ERANGE;
+ goto error;
+ }
+ msize = attr_fid->clnt->msize;
+ while (attr_size) {
+ if (attr_size > (msize - P9_IOHDRSZ))
+ read_count = msize - P9_IOHDRSZ;
+ else
+ read_count = attr_size;
+ read_count = p9_client_read(attr_fid, ((char *)buffer)+offset,
+ NULL, offset, read_count);
+ if (read_count < 0) {
+ /* error in xattr read */
+ retval = read_count;
+ goto error;
+ }
+ offset += read_count;
+ attr_size -= read_count;
+ }
+ /* Total read xattr bytes */
+ retval = offset;
+error:
+ if (attr_fid)
+ p9_client_clunk(attr_fid);
+ return retval;
+
+}
+
+/*
+ * v9fs_xattr_set()
+ *
+ * Create, replace or remove an extended attribute for this inode. Buffer
+ * is NULL to remove an existing extended attribute, and non-NULL to
+ * either replace an existing extended attribute, or create a new extended
+ * attribute. The flags XATTR_REPLACE and XATTR_CREATE
+ * specify that an extended attribute must exist and must not exist
+ * previous to the call, respectively.
+ *
+ * Returns 0, or a negative error number on failure.
+ */
+int v9fs_xattr_set(struct dentry *dentry, const char *name,
+ const void *value, size_t value_len, int flags)
+{
+ u64 offset = 0;
+ int retval, msize, write_count;
+ struct p9_fid *fid = NULL;
+
+ P9_DPRINTK(P9_DEBUG_VFS, "%s: name = %s value_len = %zu flags = %d\n",
+ __func__, name, value_len, flags);
+
+ fid = v9fs_fid_clone(dentry);
+ if (IS_ERR(fid)) {
+ retval = PTR_ERR(fid);
+ fid = NULL;
+ goto error;
+ }
+ /*
+ * On success fid points to xattr
+ */
+ retval = p9_client_xattrcreate(fid, name, value_len, flags);
+ if (retval < 0) {
+ P9_DPRINTK(P9_DEBUG_VFS,
+ "p9_client_xattrcreate failed %d\n", retval);
+ goto error;
+ }
+ msize = fid->clnt->msize;;
+ while (value_len) {
+ if (value_len > (msize - P9_IOHDRSZ))
+ write_count = msize - P9_IOHDRSZ;
+ else
+ write_count = value_len;
+ write_count = p9_client_write(fid, ((char *)value)+offset,
+ NULL, offset, write_count);
+ if (write_count < 0) {
+ /* error in xattr write */
+ retval = write_count;
+ goto error;
+ }
+ offset += write_count;
+ value_len -= write_count;
+ }
+ /* Total read xattr bytes */
+ retval = offset;
+error:
+ if (fid)
+ retval = p9_client_clunk(fid);
+ return retval;
+}
+
+ssize_t v9fs_listxattr(struct dentry *dentry, char *buffer, size_t buffer_size)
+{
+ return v9fs_xattr_get(dentry, NULL, buffer, buffer_size);
+}
+
+const struct xattr_handler *v9fs_xattr_handlers[] = {
+ &v9fs_xattr_user_handler,
+ NULL
+};
diff --git a/fs/9p/xattr.h b/fs/9p/xattr.h
new file mode 100644
index 00000000000..9ddf672ae5c
--- /dev/null
+++ b/fs/9p/xattr.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright IBM Corporation, 2010
+ * Author Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2.1 of the GNU Lesser 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.
+ *
+ */
+#ifndef FS_9P_XATTR_H
+#define FS_9P_XATTR_H
+
+#include <linux/xattr.h>
+
+extern const struct xattr_handler *v9fs_xattr_handlers[];
+extern struct xattr_handler v9fs_xattr_user_handler;
+
+extern ssize_t v9fs_xattr_get(struct dentry *, const char *,
+ void *, size_t);
+extern int v9fs_xattr_set(struct dentry *, const char *,
+ const void *, size_t, int);
+extern ssize_t v9fs_listxattr(struct dentry *, char *, size_t);
+#endif /* FS_9P_XATTR_H */
diff --git a/fs/9p/xattr_user.c b/fs/9p/xattr_user.c
new file mode 100644
index 00000000000..d0b701b7208
--- /dev/null
+++ b/fs/9p/xattr_user.c
@@ -0,0 +1,80 @@
+/*
+ * Copyright IBM Corporation, 2010
+ * Author Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2.1 of the GNU Lesser 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.
+ *
+ */
+
+
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/fs.h>
+#include <linux/slab.h>
+#include "xattr.h"
+
+static int v9fs_xattr_user_get(struct dentry *dentry, const char *name,
+ void *buffer, size_t size, int type)
+{
+ int retval;
+ char *full_name;
+ size_t name_len;
+ size_t prefix_len = XATTR_USER_PREFIX_LEN;
+
+ if (name == NULL)
+ return -EINVAL;
+
+ if (strcmp(name, "") == 0)
+ return -EINVAL;
+
+ name_len = strlen(name);
+ full_name = kmalloc(prefix_len + name_len + 1 , GFP_KERNEL);
+ if (!full_name)
+ return -ENOMEM;
+ memcpy(full_name, XATTR_USER_PREFIX, prefix_len);
+ memcpy(full_name+prefix_len, name, name_len);
+ full_name[prefix_len + name_len] = '\0';
+
+ retval = v9fs_xattr_get(dentry, full_name, buffer, size);
+ kfree(full_name);
+ return retval;
+}
+
+static int v9fs_xattr_user_set(struct dentry *dentry, const char *name,
+ const void *value, size_t size, int flags, int type)
+{
+ int retval;
+ char *full_name;
+ size_t name_len;
+ size_t prefix_len = XATTR_USER_PREFIX_LEN;
+
+ if (name == NULL)
+ return -EINVAL;
+
+ if (strcmp(name, "") == 0)
+ return -EINVAL;
+
+ name_len = strlen(name);
+ full_name = kmalloc(prefix_len + name_len + 1 , GFP_KERNEL);
+ if (!full_name)
+ return -ENOMEM;
+ memcpy(full_name, XATTR_USER_PREFIX, prefix_len);
+ memcpy(full_name + prefix_len, name, name_len);
+ full_name[prefix_len + name_len] = '\0';
+
+ retval = v9fs_xattr_set(dentry, full_name, value, size, flags);
+ kfree(full_name);
+ return retval;
+}
+
+struct xattr_handler v9fs_xattr_user_handler = {
+ .prefix = XATTR_USER_PREFIX,
+ .get = v9fs_xattr_user_get,
+ .set = v9fs_xattr_user_set,
+};
diff --git a/fs/Kconfig b/fs/Kconfig
index 5f85b594761..3d185308ec8 100644
--- a/fs/Kconfig
+++ b/fs/Kconfig
@@ -64,7 +64,7 @@ source "fs/autofs4/Kconfig"
source "fs/fuse/Kconfig"
config CUSE
- tristate "Character device in Userpace support"
+ tristate "Character device in Userspace support"
depends on FUSE_FS
help
This FUSE extension allows character devices to be
diff --git a/fs/afs/Kconfig b/fs/afs/Kconfig
index 5c4e61d3c77..8f975f25b48 100644
--- a/fs/afs/Kconfig
+++ b/fs/afs/Kconfig
@@ -2,6 +2,7 @@ config AFS_FS
tristate "Andrew File System support (AFS) (EXPERIMENTAL)"
depends on INET && EXPERIMENTAL
select AF_RXRPC
+ select DNS_RESOLVER
help
If you say Y here, you will get an experimental Andrew File System
driver. It currently only supports unsecured read-only AFS access.
diff --git a/fs/afs/cell.c b/fs/afs/cell.c
index e19c13f059e..ffea35c6387 100644
--- a/fs/afs/cell.c
+++ b/fs/afs/cell.c
@@ -13,6 +13,7 @@
#include <linux/slab.h>
#include <linux/key.h>
#include <linux/ctype.h>
+#include <linux/dns_resolver.h>
#include <linux/sched.h>
#include <keys/rxrpc-type.h>
#include "internal.h"
@@ -36,6 +37,8 @@ static struct afs_cell *afs_cell_alloc(const char *name, char *vllist)
struct key *key;
size_t namelen;
char keyname[4 + AFS_MAXCELLNAME + 1], *cp, *dp, *next;
+ char *dvllist = NULL, *_vllist = NULL;
+ char delimiter = ':';
int ret;
_enter("%s,%s", name, vllist);
@@ -43,8 +46,10 @@ static struct afs_cell *afs_cell_alloc(const char *name, char *vllist)
BUG_ON(!name); /* TODO: want to look up "this cell" in the cache */
namelen = strlen(name);
- if (namelen > AFS_MAXCELLNAME)
+ if (namelen > AFS_MAXCELLNAME) {
+ _leave(" = -ENAMETOOLONG");
return ERR_PTR(-ENAMETOOLONG);
+ }
/* allocate and initialise a cell record */
cell = kzalloc(sizeof(struct afs_cell) + namelen + 1, GFP_KERNEL);
@@ -64,15 +69,31 @@ static struct afs_cell *afs_cell_alloc(const char *name, char *vllist)
INIT_LIST_HEAD(&cell->vl_list);
spin_lock_init(&cell->vl_lock);
+ /* if the ip address is invalid, try dns query */
+ if (!vllist || strlen(vllist) < 7) {
+ ret = dns_query("afsdb", name, namelen, "ipv4", &dvllist, NULL);
+ if (ret < 0) {
+ _leave(" = %d", ret);
+ return ERR_PTR(ret);
+ }
+ _vllist = dvllist;
+
+ /* change the delimiter for user-space reply */
+ delimiter = ',';
+
+ } else {
+ _vllist = vllist;
+ }
+
/* fill in the VL server list from the rest of the string */
do {
unsigned a, b, c, d;
- next = strchr(vllist, ':');
+ next = strchr(_vllist, delimiter);
if (next)
*next++ = 0;
- if (sscanf(vllist, "%u.%u.%u.%u", &a, &b, &c, &d) != 4)
+ if (sscanf(_vllist, "%u.%u.%u.%u", &a, &b, &c, &d) != 4)
goto bad_address;
if (a > 255 || b > 255 || c > 255 || d > 255)
@@ -81,7 +102,7 @@ static struct afs_cell *afs_cell_alloc(const char *name, char *vllist)
cell->vl_addrs[cell->vl_naddrs++].s_addr =
htonl((a << 24) | (b << 16) | (c << 8) | d);
- } while (cell->vl_naddrs < AFS_CELL_MAX_ADDRS && (vllist = next));
+ } while (cell->vl_naddrs < AFS_CELL_MAX_ADDRS && (_vllist = next));
/* create a key to represent an anonymous user */
memcpy(keyname, "afs@", 4);
@@ -110,6 +131,7 @@ bad_address:
ret = -EINVAL;
error:
key_put(cell->anonymous_key);
+ kfree(dvllist);
kfree(cell);
_leave(" = %d", ret);
return ERR_PTR(ret);
@@ -201,14 +223,12 @@ int afs_cell_init(char *rootcell)
}
cp = strchr(rootcell, ':');
- if (!cp) {
- printk(KERN_ERR "kAFS: no VL server IP addresses specified\n");
- _leave(" = -EINVAL");
- return -EINVAL;
- }
+ if (!cp)
+ _debug("kAFS: no VL server IP addresses specified");
+ else
+ *cp++ = 0;
/* allocate a cell record for the root cell */
- *cp++ = 0;
new_root = afs_cell_create(rootcell, cp);
if (IS_ERR(new_root)) {
_leave(" = %ld", PTR_ERR(new_root));
diff --git a/fs/afs/main.c b/fs/afs/main.c
index 66d54d348c5..cfd1cbe25b2 100644
--- a/fs/afs/main.c
+++ b/fs/afs/main.c
@@ -111,6 +111,8 @@ static int __init afs_init(void)
/* initialise the callback update process */
ret = afs_callback_update_init();
+ if (ret < 0)
+ goto error_callback_update_init;
/* create the RxRPC transport */
ret = afs_open_socket();
@@ -127,15 +129,16 @@ static int __init afs_init(void)
error_fs:
afs_close_socket();
error_open_socket:
+ afs_callback_update_kill();
+error_callback_update_init:
+ afs_vlocation_purge();
error_vl_update_init:
+ afs_cell_purge();
error_cell_init:
#ifdef CONFIG_AFS_FSCACHE
fscache_unregister_netfs(&afs_cache_netfs);
error_cache:
#endif
- afs_callback_update_kill();
- afs_vlocation_purge();
- afs_cell_purge();
afs_proc_cleanup();
rcu_barrier();
printk(KERN_ERR "kAFS: failed to register: %d\n", ret);
diff --git a/fs/aio.c b/fs/aio.c
index 1ccf25cef1f..3006b5bc33d 100644
--- a/fs/aio.c
+++ b/fs/aio.c
@@ -1277,7 +1277,7 @@ out:
/* sys_io_destroy:
* Destroy the aio_context specified. May cancel any outstanding
* AIOs and block on completion. Will fail with -ENOSYS if not
- * implemented. May fail with -EFAULT if the context pointed to
+ * implemented. May fail with -EINVAL if the context pointed to
* is invalid.
*/
SYSCALL_DEFINE1(io_destroy, aio_context_t, ctx)
@@ -1795,15 +1795,16 @@ SYSCALL_DEFINE3(io_cancel, aio_context_t, ctx_id, struct iocb __user *, iocb,
/* io_getevents:
* Attempts to read at least min_nr events and up to nr events from
- * the completion queue for the aio_context specified by ctx_id. May
- * fail with -EINVAL if ctx_id is invalid, if min_nr is out of range,
- * if nr is out of range, if when is out of range. May fail with
- * -EFAULT if any of the memory specified to is invalid. May return
- * 0 or < min_nr if no events are available and the timeout specified
- * by when has elapsed, where when == NULL specifies an infinite
- * timeout. Note that the timeout pointed to by when is relative and
- * will be updated if not NULL and the operation blocks. Will fail
- * with -ENOSYS if not implemented.
+ * the completion queue for the aio_context specified by ctx_id. If
+ * it succeeds, the number of read events is returned. May fail with
+ * -EINVAL if ctx_id is invalid, if min_nr is out of range, if nr is
+ * out of range, if timeout is out of range. May fail with -EFAULT
+ * if any of the memory specified is invalid. May return 0 or
+ * < min_nr if the timeout specified by timeout has elapsed
+ * before sufficient events are available, where timeout == NULL
+ * specifies an infinite timeout. Note that the timeout pointed to by
+ * timeout is relative and will be updated if not NULL and the
+ * operation blocks. Will fail with -ENOSYS if not implemented.
*/
SYSCALL_DEFINE5(io_getevents, aio_context_t, ctx_id,
long, min_nr,
diff --git a/fs/befs/linuxvfs.c b/fs/befs/linuxvfs.c
index 34ddda888e6..dc39d282488 100644
--- a/fs/befs/linuxvfs.c
+++ b/fs/befs/linuxvfs.c
@@ -436,7 +436,7 @@ befs_init_inodecache(void)
init_once);
if (befs_inode_cachep == NULL) {
printk(KERN_ERR "befs_init_inodecache: "
- "Couldn't initalize inode slabcache\n");
+ "Couldn't initialize inode slabcache\n");
return -ENOMEM;
}
diff --git a/fs/block_dev.c b/fs/block_dev.c
index 99d6af81174..b3171fb0dc9 100644
--- a/fs/block_dev.c
+++ b/fs/block_dev.c
@@ -681,8 +681,8 @@ retry:
if (!bd_may_claim(bdev, whole, holder))
return -EBUSY;
- /* if someone else is claiming, wait for it to finish */
- if (whole->bd_claiming && whole->bd_claiming != holder) {
+ /* if claiming is already in progress, wait for it to finish */
+ if (whole->bd_claiming) {
wait_queue_head_t *wq = bit_waitqueue(&whole->bd_claiming, 0);
DEFINE_WAIT(wait);
diff --git a/fs/cachefiles/namei.c b/fs/cachefiles/namei.c
index f4a7840bf42..42c7fafc8bf 100644
--- a/fs/cachefiles/namei.c
+++ b/fs/cachefiles/namei.c
@@ -37,9 +37,9 @@ void __cachefiles_printk_object(struct cachefiles_object *object,
printk(KERN_ERR "%sobject: OBJ%x\n",
prefix, object->fscache.debug_id);
- printk(KERN_ERR "%sobjstate=%s fl=%lx swfl=%lx ev=%lx[%lx]\n",
+ printk(KERN_ERR "%sobjstate=%s fl=%lx wbusy=%x ev=%lx[%lx]\n",
prefix, fscache_object_states[object->fscache.state],
- object->fscache.flags, object->fscache.work.flags,
+ object->fscache.flags, work_busy(&object->fscache.work),
object->fscache.events,
object->fscache.event_mask & FSCACHE_OBJECT_EVENTS_MASK);
printk(KERN_ERR "%sops=%u inp=%u exc=%u\n",
@@ -212,7 +212,7 @@ wait_for_old_object:
/* if the object we're waiting for is queued for processing,
* then just put ourselves on the queue behind it */
- if (slow_work_is_queued(&xobject->fscache.work)) {
+ if (work_pending(&xobject->fscache.work)) {
_debug("queue OBJ%x behind OBJ%x immediately",
object->fscache.debug_id,
xobject->fscache.debug_id);
@@ -220,8 +220,7 @@ wait_for_old_object:
}
/* otherwise we sleep until either the object we're waiting for
- * is done, or the slow-work facility wants the thread back to
- * do other work */
+ * is done, or the fscache_object is congested */
wq = bit_waitqueue(&xobject->flags, CACHEFILES_OBJECT_ACTIVE);
init_wait(&wait);
requeue = false;
@@ -229,8 +228,8 @@ wait_for_old_object:
prepare_to_wait(wq, &wait, TASK_UNINTERRUPTIBLE);
if (!test_bit(CACHEFILES_OBJECT_ACTIVE, &xobject->flags))
break;
- requeue = slow_work_sleep_till_thread_needed(
- &object->fscache.work, &timeout);
+
+ requeue = fscache_object_sleep_till_congested(&timeout);
} while (timeout > 0 && !requeue);
finish_wait(wq, &wait);
diff --git a/fs/cachefiles/rdwr.c b/fs/cachefiles/rdwr.c
index 0f0d41fbb03..0e3c0924cc3 100644
--- a/fs/cachefiles/rdwr.c
+++ b/fs/cachefiles/rdwr.c
@@ -422,7 +422,7 @@ int cachefiles_read_or_alloc_page(struct fscache_retrieval *op,
shift = PAGE_SHIFT - inode->i_sb->s_blocksize_bits;
op->op.flags &= FSCACHE_OP_KEEP_FLAGS;
- op->op.flags |= FSCACHE_OP_FAST;
+ op->op.flags |= FSCACHE_OP_ASYNC;
op->op.processor = cachefiles_read_copier;
pagevec_init(&pagevec, 0);
@@ -729,7 +729,7 @@ int cachefiles_read_or_alloc_pages(struct fscache_retrieval *op,
pagevec_init(&pagevec, 0);
op->op.flags &= FSCACHE_OP_KEEP_FLAGS;
- op->op.flags |= FSCACHE_OP_FAST;
+ op->op.flags |= FSCACHE_OP_ASYNC;
op->op.processor = cachefiles_read_copier;
INIT_LIST_HEAD(&backpages);
diff --git a/fs/char_dev.c b/fs/char_dev.c
index d6db933df2b..f80a4f25123 100644
--- a/fs/char_dev.c
+++ b/fs/char_dev.c
@@ -20,6 +20,7 @@
#include <linux/cdev.h>
#include <linux/mutex.h>
#include <linux/backing-dev.h>
+#include <linux/tty.h>
#include "internal.h"
diff --git a/fs/cifs/Kconfig b/fs/cifs/Kconfig
index 80f35259680..917b7d449bb 100644
--- a/fs/cifs/Kconfig
+++ b/fs/cifs/Kconfig
@@ -2,7 +2,6 @@ config CIFS
tristate "CIFS support (advanced network filesystem, SMBFS successor)"
depends on INET
select NLS
- select SLOW_WORK
help
This is the client VFS module for the Common Internet File System
(CIFS) protocol which is the successor to the Server Message Block
@@ -71,14 +70,14 @@ config CIFS_WEAK_PW_HASH
If unsure, say N.
config CIFS_UPCALL
- bool "Kerberos/SPNEGO advanced session setup"
- depends on CIFS && KEYS
- help
- Enables an upcall mechanism for CIFS which accesses
- userspace helper utilities to provide SPNEGO packaged (RFC 4178)
- Kerberos tickets which are needed to mount to certain secure servers
- (for which more secure Kerberos authentication is required). If
- unsure, say N.
+ bool "Kerberos/SPNEGO advanced session setup"
+ depends on CIFS && KEYS
+ select DNS_RESOLVER
+ help
+ Enables an upcall mechanism for CIFS which accesses userspace helper
+ utilities to provide SPNEGO packaged (RFC 4178) Kerberos tickets
+ which are needed to mount to certain secure servers (for which more
+ secure Kerberos authentication is required). If unsure, say N.
config CIFS_XATTR
bool "CIFS extended attributes"
@@ -122,6 +121,7 @@ config CIFS_DEBUG2
config CIFS_DFS_UPCALL
bool "DFS feature support"
depends on CIFS && KEYS
+ select DNS_RESOLVER
help
Distributed File System (DFS) support is used to access shares
transparently in an enterprise name space, even if the share
@@ -131,6 +131,15 @@ config CIFS_DFS_UPCALL
IP addresses) which is needed for implicit mounts of DFS junction
points. If unsure, say N.
+config CIFS_FSCACHE
+ bool "Provide CIFS client caching support (EXPERIMENTAL)"
+ depends on EXPERIMENTAL
+ depends on CIFS=m && FSCACHE || CIFS=y && FSCACHE=y
+ help
+ Makes CIFS FS-Cache capable. Say Y here if you want your CIFS data
+ to be cached locally on disk through the general filesystem cache
+ manager. If unsure, say N.
+
config CIFS_EXPERIMENTAL
bool "CIFS Experimental Features (EXPERIMENTAL)"
depends on CIFS && EXPERIMENTAL
diff --git a/fs/cifs/Makefile b/fs/cifs/Makefile
index 9948c0030e8..adefa60a9bd 100644
--- a/fs/cifs/Makefile
+++ b/fs/cifs/Makefile
@@ -11,3 +11,5 @@ cifs-y := cifsfs.o cifssmb.o cifs_debug.o connect.o dir.o file.o inode.o \
cifs-$(CONFIG_CIFS_UPCALL) += cifs_spnego.o
cifs-$(CONFIG_CIFS_DFS_UPCALL) += dns_resolve.o cifs_dfs_ref.o
+
+cifs-$(CONFIG_CIFS_FSCACHE) += fscache.o cache.o
diff --git a/fs/cifs/README b/fs/cifs/README
index a727b7cb075..a7081eeeb85 100644
--- a/fs/cifs/README
+++ b/fs/cifs/README
@@ -568,8 +568,9 @@ module can be displayed via modinfo.
Misc /proc/fs/cifs Flags and Debug Info
=======================================
Informational pseudo-files:
-DebugData Displays information about active CIFS sessions
- and shares, as well as the cifs.ko version.
+DebugData Displays information about active CIFS sessions and
+ shares, features enabled as well as the cifs.ko
+ version.
Stats Lists summary resource usage information as well as per
share statistics, if CONFIG_CIFS_STATS in enabled
in the kernel configuration.
diff --git a/fs/cifs/cache.c b/fs/cifs/cache.c
new file mode 100644
index 00000000000..224d7bbd1fc
--- /dev/null
+++ b/fs/cifs/cache.c
@@ -0,0 +1,331 @@
+/*
+ * fs/cifs/cache.c - CIFS filesystem cache index structure definitions
+ *
+ * Copyright (c) 2010 Novell, Inc.
+ * Authors(s): Suresh Jayaraman (sjayaraman@suse.de>
+ *
+ * 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
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * 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
+ */
+#include "fscache.h"
+#include "cifs_debug.h"
+
+/*
+ * CIFS filesystem definition for FS-Cache
+ */
+struct fscache_netfs cifs_fscache_netfs = {
+ .name = "cifs",
+ .version = 0,
+};
+
+/*
+ * Register CIFS for caching with FS-Cache
+ */
+int cifs_fscache_register(void)
+{
+ return fscache_register_netfs(&cifs_fscache_netfs);
+}
+
+/*
+ * Unregister CIFS for caching
+ */
+void cifs_fscache_unregister(void)
+{
+ fscache_unregister_netfs(&cifs_fscache_netfs);
+}
+
+/*
+ * Key layout of CIFS server cache index object
+ */
+struct cifs_server_key {
+ uint16_t family; /* address family */
+ uint16_t port; /* IP port */
+ union {
+ struct in_addr ipv4_addr;
+ struct in6_addr ipv6_addr;
+ } addr[0];
+};
+
+/*
+ * Server object keyed by {IPaddress,port,family} tuple
+ */
+static uint16_t cifs_server_get_key(const void *cookie_netfs_data,
+ void *buffer, uint16_t maxbuf)
+{
+ const struct TCP_Server_Info *server = cookie_netfs_data;
+ const struct sockaddr *sa = (struct sockaddr *) &server->addr.sockAddr;
+ struct cifs_server_key *key = buffer;
+ uint16_t key_len = sizeof(struct cifs_server_key);
+
+ memset(key, 0, key_len);
+
+ /*
+ * Should not be a problem as sin_family/sin6_family overlays
+ * sa_family field
+ */
+ switch (sa->sa_family) {
+ case AF_INET:
+ key->family = server->addr.sockAddr.sin_family;
+ key->port = server->addr.sockAddr.sin_port;
+ key->addr[0].ipv4_addr = server->addr.sockAddr.sin_addr;
+ key_len += sizeof(key->addr[0].ipv4_addr);
+ break;
+
+ case AF_INET6:
+ key->family = server->addr.sockAddr6.sin6_family;
+ key->port = server->addr.sockAddr6.sin6_port;
+ key->addr[0].ipv6_addr = server->addr.sockAddr6.sin6_addr;
+ key_len += sizeof(key->addr[0].ipv6_addr);
+ break;
+
+ default:
+ cERROR(1, "CIFS: Unknown network family '%d'", sa->sa_family);
+ key_len = 0;
+ break;
+ }
+
+ return key_len;
+}
+
+/*
+ * Server object for FS-Cache
+ */
+const struct fscache_cookie_def cifs_fscache_server_index_def = {
+ .name = "CIFS.server",
+ .type = FSCACHE_COOKIE_TYPE_INDEX,
+ .get_key = cifs_server_get_key,
+};
+
+/*
+ * Auxiliary data attached to CIFS superblock within the cache
+ */
+struct cifs_fscache_super_auxdata {
+ u64 resource_id; /* unique server resource id */
+};
+
+static char *extract_sharename(const char *treename)
+{
+ const char *src;
+ char *delim, *dst;
+ int len;
+
+ /* skip double chars at the beginning */
+ src = treename + 2;
+
+ /* share name is always preceded by '\\' now */
+ delim = strchr(src, '\\');
+ if (!delim)
+ return ERR_PTR(-EINVAL);
+ delim++;
+ len = strlen(delim);
+
+ /* caller has to free the memory */
+ dst = kstrndup(delim, len, GFP_KERNEL);
+ if (!dst)
+ return ERR_PTR(-ENOMEM);
+
+ return dst;
+}
+
+/*
+ * Superblock object currently keyed by share name
+ */
+static uint16_t cifs_super_get_key(const void *cookie_netfs_data, void *buffer,
+ uint16_t maxbuf)
+{
+ const struct cifsTconInfo *tcon = cookie_netfs_data;
+ char *sharename;
+ uint16_t len;
+
+ sharename = extract_sharename(tcon->treeName);
+ if (IS_ERR(sharename)) {
+ cFYI(1, "CIFS: couldn't extract sharename\n");
+ sharename = NULL;
+ return 0;
+ }
+
+ len = strlen(sharename);
+ if (len > maxbuf)
+ return 0;
+
+ memcpy(buffer, sharename, len);
+
+ kfree(sharename);
+
+ return len;
+}
+
+static uint16_t
+cifs_fscache_super_get_aux(const void *cookie_netfs_data, void *buffer,
+ uint16_t maxbuf)
+{
+ struct cifs_fscache_super_auxdata auxdata;
+ const struct cifsTconInfo *tcon = cookie_netfs_data;
+
+ memset(&auxdata, 0, sizeof(auxdata));
+ auxdata.resource_id = tcon->resource_id;
+
+ if (maxbuf > sizeof(auxdata))
+ maxbuf = sizeof(auxdata);
+
+ memcpy(buffer, &auxdata, maxbuf);
+
+ return maxbuf;
+}
+
+static enum
+fscache_checkaux cifs_fscache_super_check_aux(void *cookie_netfs_data,
+ const void *data,
+ uint16_t datalen)
+{
+ struct cifs_fscache_super_auxdata auxdata;
+ const struct cifsTconInfo *tcon = cookie_netfs_data;
+
+ if (datalen != sizeof(auxdata))
+ return FSCACHE_CHECKAUX_OBSOLETE;
+
+ memset(&auxdata, 0, sizeof(auxdata));
+ auxdata.resource_id = tcon->resource_id;
+
+ if (memcmp(data, &auxdata, datalen) != 0)
+ return FSCACHE_CHECKAUX_OBSOLETE;
+
+ return FSCACHE_CHECKAUX_OKAY;
+}
+
+/*
+ * Superblock object for FS-Cache
+ */
+const struct fscache_cookie_def cifs_fscache_super_index_def = {
+ .name = "CIFS.super",
+ .type = FSCACHE_COOKIE_TYPE_INDEX,
+ .get_key = cifs_super_get_key,
+ .get_aux = cifs_fscache_super_get_aux,
+ .check_aux = cifs_fscache_super_check_aux,
+};
+
+/*
+ * Auxiliary data attached to CIFS inode within the cache
+ */
+struct cifs_fscache_inode_auxdata {
+ struct timespec last_write_time;
+ struct timespec last_change_time;
+ u64 eof;
+};
+
+static uint16_t cifs_fscache_inode_get_key(const void *cookie_netfs_data,
+ void *buffer, uint16_t maxbuf)
+{
+ const struct cifsInodeInfo *cifsi = cookie_netfs_data;
+ uint16_t keylen;
+
+ /* use the UniqueId as the key */
+ keylen = sizeof(cifsi->uniqueid);
+ if (keylen > maxbuf)
+ keylen = 0;
+ else
+ memcpy(buffer, &cifsi->uniqueid, keylen);
+
+ return keylen;
+}
+
+static void
+cifs_fscache_inode_get_attr(const void *cookie_netfs_data, uint64_t *size)
+{
+ const struct cifsInodeInfo *cifsi = cookie_netfs_data;
+
+ *size = cifsi->vfs_inode.i_size;
+}
+
+static uint16_t
+cifs_fscache_inode_get_aux(const void *cookie_netfs_data, void *buffer,
+ uint16_t maxbuf)
+{
+ struct cifs_fscache_inode_auxdata auxdata;
+ const struct cifsInodeInfo *cifsi = cookie_netfs_data;
+
+ memset(&auxdata, 0, sizeof(auxdata));
+ auxdata.eof = cifsi->server_eof;
+ auxdata.last_write_time = cifsi->vfs_inode.i_mtime;
+ auxdata.last_change_time = cifsi->vfs_inode.i_ctime;
+
+ if (maxbuf > sizeof(auxdata))
+ maxbuf = sizeof(auxdata);
+
+ memcpy(buffer, &auxdata, maxbuf);
+
+ return maxbuf;
+}
+
+static enum
+fscache_checkaux cifs_fscache_inode_check_aux(void *cookie_netfs_data,
+ const void *data,
+ uint16_t datalen)
+{
+ struct cifs_fscache_inode_auxdata auxdata;
+ struct cifsInodeInfo *cifsi = cookie_netfs_data;
+
+ if (datalen != sizeof(auxdata))
+ return FSCACHE_CHECKAUX_OBSOLETE;
+
+ memset(&auxdata, 0, sizeof(auxdata));
+ auxdata.eof = cifsi->server_eof;
+ auxdata.last_write_time = cifsi->vfs_inode.i_mtime;
+ auxdata.last_change_time = cifsi->vfs_inode.i_ctime;
+
+ if (memcmp(data, &auxdata, datalen) != 0)
+ return FSCACHE_CHECKAUX_OBSOLETE;
+
+ return FSCACHE_CHECKAUX_OKAY;
+}
+
+static void cifs_fscache_inode_now_uncached(void *cookie_netfs_data)
+{
+ struct cifsInodeInfo *cifsi = cookie_netfs_data;
+ struct pagevec pvec;
+ pgoff_t first;
+ int loop, nr_pages;
+
+ pagevec_init(&pvec, 0);
+ first = 0;
+
+ cFYI(1, "cifs inode 0x%p now uncached", cifsi);
+
+ for (;;) {
+ nr_pages = pagevec_lookup(&pvec,
+ cifsi->vfs_inode.i_mapping, first,
+ PAGEVEC_SIZE - pagevec_count(&pvec));
+ if (!nr_pages)
+ break;
+
+ for (loop = 0; loop < nr_pages; loop++)
+ ClearPageFsCache(pvec.pages[loop]);
+
+ first = pvec.pages[nr_pages - 1]->index + 1;
+
+ pvec.nr = nr_pages;
+ pagevec_release(&pvec);
+ cond_resched();
+ }
+}
+
+const struct fscache_cookie_def cifs_fscache_inode_object_def = {
+ .name = "CIFS.uniqueid",
+ .type = FSCACHE_COOKIE_TYPE_DATAFILE,
+ .get_key = cifs_fscache_inode_get_key,
+ .get_attr = cifs_fscache_inode_get_attr,
+ .get_aux = cifs_fscache_inode_get_aux,
+ .check_aux = cifs_fscache_inode_check_aux,
+ .now_uncached = cifs_fscache_inode_now_uncached,
+};
diff --git a/fs/cifs/cifs_debug.c b/fs/cifs/cifs_debug.c
index 4fce6e61b34..eb1ba493489 100644
--- a/fs/cifs/cifs_debug.c
+++ b/fs/cifs/cifs_debug.c
@@ -119,6 +119,31 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v)
"Display Internal CIFS Data Structures for Debugging\n"
"---------------------------------------------------\n");
seq_printf(m, "CIFS Version %s\n", CIFS_VERSION);
+ seq_printf(m, "Features: ");
+#ifdef CONFIG_CIFS_DFS_UPCALL
+ seq_printf(m, "dfs");
+ seq_putc(m, ' ');
+#endif
+#ifdef CONFIG_CIFS_FSCACHE
+ seq_printf(m, "fscache");
+ seq_putc(m, ' ');
+#endif
+#ifdef CONFIG_CIFS_WEAK_PW_HASH
+ seq_printf(m, "lanman");
+ seq_putc(m, ' ');
+#endif
+#ifdef CONFIG_CIFS_POSIX
+ seq_printf(m, "posix");
+ seq_putc(m, ' ');
+#endif
+#ifdef CONFIG_CIFS_UPCALL
+ seq_printf(m, "spnego");
+ seq_putc(m, ' ');
+#endif
+#ifdef CONFIG_CIFS_XATTR
+ seq_printf(m, "xattr");
+#endif
+ seq_putc(m, '\n');
seq_printf(m, "Active VFS Requests: %d\n", GlobalTotalActiveXid);
seq_printf(m, "Servers:");
diff --git a/fs/cifs/cifs_dfs_ref.c b/fs/cifs/cifs_dfs_ref.c
index ac19a6f3dae..d6ced7aa23c 100644
--- a/fs/cifs/cifs_dfs_ref.c
+++ b/fs/cifs/cifs_dfs_ref.c
@@ -141,7 +141,7 @@ char *cifs_compose_mount_options(const char *sb_mountdata,
}
rc = dns_resolve_server_name_to_ip(*devname, &srvIP);
- if (rc != 0) {
+ if (rc < 0) {
cERROR(1, "%s: Failed to resolve server part of %s to IP: %d",
__func__, *devname, rc);
goto compose_mount_options_err;
@@ -150,8 +150,7 @@ char *cifs_compose_mount_options(const char *sb_mountdata,
* assuming that we have 'unc=' and 'ip=' in
* the original sb_mountdata
*/
- md_len = strlen(sb_mountdata) + strlen(srvIP) +
- strlen(ref->node_name) + 12;
+ md_len = strlen(sb_mountdata) + rc + strlen(ref->node_name) + 12;
mountdata = kzalloc(md_len+1, GFP_KERNEL);
if (mountdata == NULL) {
rc = -ENOMEM;
@@ -230,28 +229,22 @@ compose_mount_options_err:
goto compose_mount_options_out;
}
-
-static struct vfsmount *cifs_dfs_do_refmount(const struct vfsmount *mnt_parent,
- struct dentry *dentry, const struct dfs_info3_param *ref)
+/**
+ * cifs_dfs_do_refmount - mounts specified path using provided refferal
+ * @cifs_sb: parent/root superblock
+ * @fullpath: full path in UNC format
+ * @ref: server's referral
+ */
+static struct vfsmount *cifs_dfs_do_refmount(struct cifs_sb_info *cifs_sb,
+ const char *fullpath, const struct dfs_info3_param *ref)
{
- struct cifs_sb_info *cifs_sb;
struct vfsmount *mnt;
char *mountdata;
char *devname = NULL;
- char *fullpath;
-
- cifs_sb = CIFS_SB(dentry->d_inode->i_sb);
- /*
- * this function gives us a path with a double backslash prefix. We
- * require a single backslash for DFS.
- */
- fullpath = build_path_from_dentry(dentry);
- if (!fullpath)
- return ERR_PTR(-ENOMEM);
+ /* strip first '\' from fullpath */
mountdata = cifs_compose_mount_options(cifs_sb->mountdata,
fullpath + 1, ref, &devname);
- kfree(fullpath);
if (IS_ERR(mountdata))
return (struct vfsmount *)mountdata;
@@ -357,8 +350,8 @@ cifs_dfs_follow_mountpoint(struct dentry *dentry, struct nameidata *nd)
rc = -EINVAL;
goto out_err;
}
- mnt = cifs_dfs_do_refmount(nd->path.mnt,
- nd->path.dentry, referrals + i);
+ mnt = cifs_dfs_do_refmount(cifs_sb,
+ full_path, referrals + i);
cFYI(1, "%s: cifs_dfs_do_refmount:%s , mnt:%p", __func__,
referrals[i].node_name, mnt);
diff --git a/fs/cifs/cifs_fs_sb.h b/fs/cifs/cifs_fs_sb.h
index 246a167cb91..9e771450c3b 100644
--- a/fs/cifs/cifs_fs_sb.h
+++ b/fs/cifs/cifs_fs_sb.h
@@ -35,6 +35,7 @@
#define CIFS_MOUNT_DYNPERM 0x1000 /* allow in-memory only mode setting */
#define CIFS_MOUNT_NOPOSIXBRL 0x2000 /* mandatory not posix byte range lock */
#define CIFS_MOUNT_NOSSYNC 0x4000 /* don't do slow SMBflush on every sync*/
+#define CIFS_MOUNT_FSCACHE 0x8000 /* local caching enabled */
struct cifs_sb_info {
struct cifsTconInfo *tcon; /* primary mount */
diff --git a/fs/cifs/cifs_spnego.c b/fs/cifs/cifs_spnego.c
index 379bd7d9c05..87044906cd1 100644
--- a/fs/cifs/cifs_spnego.c
+++ b/fs/cifs/cifs_spnego.c
@@ -84,6 +84,9 @@ struct key_type cifs_spnego_key_type = {
/* strlen of ";uid=0x" */
#define UID_KEY_LEN 7
+/* strlen of ";creduid=0x" */
+#define CREDUID_KEY_LEN 11
+
/* strlen of ";user=" */
#define USER_KEY_LEN 6
@@ -107,6 +110,7 @@ cifs_get_spnego_key(struct cifsSesInfo *sesInfo)
IP_KEY_LEN + INET6_ADDRSTRLEN +
MAX_MECH_STR_LEN +
UID_KEY_LEN + (sizeof(uid_t) * 2) +
+ CREDUID_KEY_LEN + (sizeof(uid_t) * 2) +
USER_KEY_LEN + strlen(sesInfo->userName) +
PID_KEY_LEN + (sizeof(pid_t) * 2) + 1;
@@ -144,6 +148,9 @@ cifs_get_spnego_key(struct cifsSesInfo *sesInfo)
sprintf(dp, ";uid=0x%x", sesInfo->linux_uid);
dp = description + strlen(description);
+ sprintf(dp, ";creduid=0x%x", sesInfo->cred_uid);
+
+ dp = description + strlen(description);
sprintf(dp, ";user=%s", sesInfo->userName);
dp = description + strlen(description);
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c
index 2cb1a70214d..a5ed10c9afe 100644
--- a/fs/cifs/cifsfs.c
+++ b/fs/cifs/cifsfs.c
@@ -45,8 +45,8 @@
#include "cifs_fs_sb.h"
#include <linux/mm.h>
#include <linux/key-type.h>
-#include "dns_resolve.h"
#include "cifs_spnego.h"
+#include "fscache.h"
#define CIFS_MAGIC_NUMBER 0xFF534D42 /* the first four bytes of SMB PDUs */
int cifsFYI = 0;
@@ -329,6 +329,12 @@ cifs_destroy_inode(struct inode *inode)
}
static void
+cifs_clear_inode(struct inode *inode)
+{
+ cifs_fscache_release_inode_cookie(inode);
+}
+
+static void
cifs_show_address(struct seq_file *s, struct TCP_Server_Info *server)
{
seq_printf(s, ",addr=");
@@ -489,6 +495,7 @@ static const struct super_operations cifs_super_ops = {
.alloc_inode = cifs_alloc_inode,
.destroy_inode = cifs_destroy_inode,
.drop_inode = cifs_drop_inode,
+ .clear_inode = cifs_clear_inode,
/* .delete_inode = cifs_delete_inode, */ /* Do not need above
function unless later we add lazy close of inodes or unless the
kernel forgets to call us with the same number of releases (closes)
@@ -902,6 +909,10 @@ init_cifs(void)
cFYI(1, "cifs_max_pending set to max of 256");
}
+ rc = cifs_fscache_register();
+ if (rc)
+ goto out;
+
rc = cifs_init_inodecache();
if (rc)
goto out_clean_proc;
@@ -922,27 +933,13 @@ init_cifs(void)
if (rc)
goto out_unregister_filesystem;
#endif
-#ifdef CONFIG_CIFS_DFS_UPCALL
- rc = cifs_init_dns_resolver();
- if (rc)
- goto out_unregister_key_type;
-#endif
- rc = slow_work_register_user(THIS_MODULE);
- if (rc)
- goto out_unregister_resolver_key;
return 0;
- out_unregister_resolver_key:
-#ifdef CONFIG_CIFS_DFS_UPCALL
- cifs_exit_dns_resolver();
- out_unregister_key_type:
-#endif
#ifdef CONFIG_CIFS_UPCALL
- unregister_key_type(&cifs_spnego_key_type);
out_unregister_filesystem:
-#endif
unregister_filesystem(&cifs_fs_type);
+#endif
out_destroy_request_bufs:
cifs_destroy_request_bufs();
out_destroy_mids:
@@ -951,6 +948,8 @@ init_cifs(void)
cifs_destroy_inodecache();
out_clean_proc:
cifs_proc_clean();
+ cifs_fscache_unregister();
+ out:
return rc;
}
@@ -959,9 +958,9 @@ exit_cifs(void)
{
cFYI(DBG2, "exit_cifs");
cifs_proc_clean();
+ cifs_fscache_unregister();
#ifdef CONFIG_CIFS_DFS_UPCALL
cifs_dfs_release_automount_timer();
- cifs_exit_dns_resolver();
#endif
#ifdef CONFIG_CIFS_UPCALL
unregister_key_type(&cifs_spnego_key_type);
diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h
index a7eb65c84b1..d82f5fb4761 100644
--- a/fs/cifs/cifsfs.h
+++ b/fs/cifs/cifsfs.h
@@ -114,5 +114,5 @@ extern long cifs_ioctl(struct file *filep, unsigned int cmd, unsigned long arg);
extern const struct export_operations cifs_export_ops;
#endif /* EXPERIMENTAL */
-#define CIFS_VERSION "1.64"
+#define CIFS_VERSION "1.65"
#endif /* _CIFSFS_H */
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index a88479ceaad..0cdfb8c32ac 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -16,10 +16,13 @@
* the GNU Lesser General Public License for more details.
*
*/
+#ifndef _CIFS_GLOB_H
+#define _CIFS_GLOB_H
+
#include <linux/in.h>
#include <linux/in6.h>
#include <linux/slab.h>
-#include <linux/slow-work.h>
+#include <linux/workqueue.h>
#include "cifs_fs_sb.h"
#include "cifsacl.h"
/*
@@ -34,7 +37,7 @@
#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
+#define MAX_PASSWORD_SIZE 512 /* max for windows seems to be 256 wide chars */
#define CIFS_MIN_RCV_POOL 4
@@ -80,8 +83,7 @@ enum statusEnum {
};
enum securityEnum {
- PLAINTXT = 0, /* Legacy with Plaintext passwords */
- LANMAN, /* Legacy LANMAN auth */
+ LANMAN = 0, /* Legacy LANMAN auth */
NTLM, /* Legacy NTLM012 auth with NTLM hash */
NTLMv2, /* Legacy NTLM auth with NTLMv2 hash */
RawNTLMSSP, /* NTLMSSP without SPNEGO, NTLMv2 hash */
@@ -142,7 +144,6 @@ struct TCP_Server_Info {
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;
char versionMajor;
char versionMinor;
@@ -190,19 +191,9 @@ struct TCP_Server_Info {
bool sec_mskerberos; /* supports legacy MS Kerberos */
bool sec_kerberosu2u; /* supports U2U Kerberos */
bool sec_ntlmssp; /* supports NTLMSSP */
-};
-
-/*
- * 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.
- */
-struct cifsUidInfo {
- struct list_head userList;
- struct list_head sessionList; /* SMB sessions for this user */
- uid_t linux_uid;
- char user[MAX_USERNAME_SIZE + 1]; /* ascii name of user */
- /* BB may need ptr or callback for PAM or WinBind info */
+#ifdef CONFIG_CIFS_FSCACHE
+ struct fscache_cookie *fscache; /* client index cache cookie */
+#endif
};
/*
@@ -212,9 +203,6 @@ struct cifsSesInfo {
struct list_head smb_ses_list;
struct list_head tcon_list;
struct mutex session_mutex;
-#if 0
- struct cifsUidInfo *uidInfo; /* pointer to user info */
-#endif
struct TCP_Server_Info *server; /* pointer to server info */
int ses_count; /* reference counter */
enum statusEnum status;
@@ -226,7 +214,8 @@ struct cifsSesInfo {
char *serverNOS; /* name of network operating system of server */
char *serverDomain; /* security realm of server */
int Suid; /* remote smb uid */
- uid_t linux_uid; /* local Linux uid */
+ uid_t linux_uid; /* overriding owner of files on the mount */
+ uid_t cred_uid; /* owner of credentials */
int capabilities;
char serverName[SERVER_NAME_LEN_WITH_NULL * 2]; /* BB make bigger for
TCP names - will ipv6 and sctp addresses fit? */
@@ -311,6 +300,10 @@ struct cifsTconInfo {
bool local_lease:1; /* check leases (only) on local system not remote */
bool broken_posix_open; /* e.g. Samba server versions < 3.3.2, 3.2.9 */
bool need_reconnect:1; /* connection reset, tid now invalid */
+#ifdef CONFIG_CIFS_FSCACHE
+ u64 resource_id; /* server resource id */
+ struct fscache_cookie *fscache; /* cookie for share */
+#endif
/* BB add field for back pointer to sb struct(s)? */
};
@@ -363,7 +356,7 @@ struct cifsFileInfo {
atomic_t count; /* reference count */
struct mutex fh_mutex; /* prevents reopen race after dead ses*/
struct cifs_search_info srch_inf;
- struct slow_work oplock_break; /* slow_work job for oplock breaks */
+ struct work_struct oplock_break; /* work for oplock breaks */
};
/* Take a reference on the file private data */
@@ -398,6 +391,9 @@ struct cifsInodeInfo {
bool invalid_mapping:1; /* pagecache is invalid */
u64 server_eof; /* current file size on server */
u64 uniqueid; /* server inode number */
+#ifdef CONFIG_CIFS_FSCACHE
+ struct fscache_cookie *fscache;
+#endif
struct inode vfs_inode;
};
@@ -732,4 +728,10 @@ GLOBAL_EXTERN unsigned int cifs_min_rcv; /* min size of big ntwrk buf pool */
GLOBAL_EXTERN unsigned int cifs_min_small; /* min size of small buf pool */
GLOBAL_EXTERN unsigned int cifs_max_pending; /* MAX requests at once to server*/
+void cifs_oplock_break(struct work_struct *work);
+void cifs_oplock_break_get(struct cifsFileInfo *cfile);
+void cifs_oplock_break_put(struct cifsFileInfo *cfile);
+
extern const struct slow_work_ops cifs_oplock_break_ops;
+
+#endif /* _CIFS_GLOB_H */
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
index fb6318b8150..1f545081408 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -86,7 +86,9 @@ 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,
struct TCP_Server_Info *server);
-extern int cifs_convert_address(char *src, void *dst);
+extern int cifs_convert_address(struct sockaddr *dst, const char *src, int len);
+extern int cifs_fill_sockaddr(struct sockaddr *dst, const char *src, int len,
+ unsigned short int port);
extern int map_smb_to_linux_error(struct smb_hdr *smb, int logErr);
extern void header_assemble(struct smb_hdr *, char /* command */ ,
const struct cifsTconInfo *, int /* length of
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index 2208f06e4c4..95c2ea67edf 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -48,6 +48,7 @@
#include "nterr.h"
#include "rfc1002pdu.h"
#include "cn_cifs.h"
+#include "fscache.h"
#define CIFS_PORT 445
#define RFC1001_PORT 139
@@ -66,6 +67,7 @@ struct smb_vol {
char *iocharset; /* local code page for mapping to and from Unicode */
char source_rfc1001_name[16]; /* netbios name of client */
char target_rfc1001_name[16]; /* netbios name of server for Win9x/ME */
+ uid_t cred_uid;
uid_t linux_uid;
gid_t linux_gid;
mode_t file_mode;
@@ -97,6 +99,7 @@ struct smb_vol {
bool noblocksnd:1;
bool noautotune:1;
bool nostrictsync:1; /* do not force expensive SMBflush on every sync */
+ bool fsc:1; /* enable fscache */
unsigned int rsize;
unsigned int wsize;
bool sockopt_tcp_nodelay:1;
@@ -830,7 +833,8 @@ cifs_parse_mount_options(char *options, const char *devname,
/* null target name indicates to use *SMBSERVR default called name
if we end up sending RFC1001 session initialize */
vol->target_rfc1001_name[0] = 0;
- vol->linux_uid = current_uid(); /* use current_euid() instead? */
+ vol->cred_uid = current_uid();
+ vol->linux_uid = current_uid();
vol->linux_gid = current_gid();
/* default to only allowing write access to owner of the mount */
@@ -1257,6 +1261,12 @@ cifs_parse_mount_options(char *options, const char *devname,
} else if ((strnicmp(data, "nocase", 6) == 0) ||
(strnicmp(data, "ignorecase", 10) == 0)) {
vol->nocase = 1;
+ } else if (strnicmp(data, "mand", 4) == 0) {
+ /* ignore */
+ } else if (strnicmp(data, "nomand", 6) == 0) {
+ /* ignore */
+ } else if (strnicmp(data, "_netdev", 7) == 0) {
+ /* ignore */
} else if (strnicmp(data, "brl", 3) == 0) {
vol->nobrl = 0;
} else if ((strnicmp(data, "nobrl", 5) == 0) ||
@@ -1331,6 +1341,8 @@ cifs_parse_mount_options(char *options, const char *devname,
printk(KERN_WARNING "CIFS: Mount option noac not "
"supported. Instead set "
"/proc/fs/cifs/LookupCacheEnabled to 0\n");
+ } else if (strnicmp(data, "fsc", 3) == 0) {
+ vol->fsc = true;
} else
printk(KERN_WARNING "CIFS: Unknown mount option %s\n",
data);
@@ -1380,18 +1392,92 @@ cifs_parse_mount_options(char *options, const char *devname,
return 0;
}
+static bool
+match_address(struct TCP_Server_Info *server, struct sockaddr *addr)
+{
+ struct sockaddr_in *addr4 = (struct sockaddr_in *)addr;
+ struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)addr;
+
+ switch (addr->sa_family) {
+ case AF_INET:
+ if (addr4->sin_addr.s_addr !=
+ server->addr.sockAddr.sin_addr.s_addr)
+ return false;
+ if (addr4->sin_port &&
+ addr4->sin_port != server->addr.sockAddr.sin_port)
+ return false;
+ break;
+ case AF_INET6:
+ if (!ipv6_addr_equal(&addr6->sin6_addr,
+ &server->addr.sockAddr6.sin6_addr))
+ return false;
+ if (addr6->sin6_scope_id !=
+ server->addr.sockAddr6.sin6_scope_id)
+ return false;
+ if (addr6->sin6_port &&
+ addr6->sin6_port != server->addr.sockAddr6.sin6_port)
+ return false;
+ break;
+ }
+
+ return true;
+}
+
+static bool
+match_security(struct TCP_Server_Info *server, struct smb_vol *vol)
+{
+ unsigned int secFlags;
+
+ if (vol->secFlg & (~(CIFSSEC_MUST_SIGN | CIFSSEC_MUST_SEAL)))
+ secFlags = vol->secFlg;
+ else
+ secFlags = global_secflags | vol->secFlg;
+
+ switch (server->secType) {
+ case LANMAN:
+ if (!(secFlags & (CIFSSEC_MAY_LANMAN|CIFSSEC_MAY_PLNTXT)))
+ return false;
+ break;
+ case NTLMv2:
+ if (!(secFlags & CIFSSEC_MAY_NTLMV2))
+ return false;
+ break;
+ case NTLM:
+ if (!(secFlags & CIFSSEC_MAY_NTLM))
+ return false;
+ break;
+ case Kerberos:
+ if (!(secFlags & CIFSSEC_MAY_KRB5))
+ return false;
+ break;
+ case RawNTLMSSP:
+ if (!(secFlags & CIFSSEC_MAY_NTLMSSP))
+ return false;
+ break;
+ default:
+ /* shouldn't happen */
+ return false;
+ }
+
+ /* now check if signing mode is acceptible */
+ if ((secFlags & CIFSSEC_MAY_SIGN) == 0 &&
+ (server->secMode & SECMODE_SIGN_REQUIRED))
+ return false;
+ else if (((secFlags & CIFSSEC_MUST_SIGN) == CIFSSEC_MUST_SIGN) &&
+ (server->secMode &
+ (SECMODE_SIGN_ENABLED|SECMODE_SIGN_REQUIRED)) == 0)
+ return false;
+
+ return true;
+}
+
static struct TCP_Server_Info *
-cifs_find_tcp_session(struct sockaddr_storage *addr, unsigned short int port)
+cifs_find_tcp_session(struct sockaddr *addr, struct smb_vol *vol)
{
- struct list_head *tmp;
struct TCP_Server_Info *server;
- struct sockaddr_in *addr4 = (struct sockaddr_in *) addr;
- struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *) addr;
write_lock(&cifs_tcp_ses_lock);
- list_for_each(tmp, &cifs_tcp_ses_list) {
- server = list_entry(tmp, struct TCP_Server_Info,
- tcp_ses_list);
+ list_for_each_entry(server, &cifs_tcp_ses_list, tcp_ses_list) {
/*
* the demux thread can exit on its own while still in CifsNew
* so don't accept any sockets in that state. Since the
@@ -1401,37 +1487,11 @@ cifs_find_tcp_session(struct sockaddr_storage *addr, unsigned short int port)
if (server->tcpStatus == CifsNew)
continue;
- switch (addr->ss_family) {
- case AF_INET:
- if (addr4->sin_addr.s_addr ==
- server->addr.sockAddr.sin_addr.s_addr) {
- addr4->sin_port = htons(port);
- /* user overrode default port? */
- if (addr4->sin_port) {
- if (addr4->sin_port !=
- server->addr.sockAddr.sin_port)
- continue;
- }
- break;
- } else
- continue;
+ if (!match_address(server, addr))
+ continue;
- case AF_INET6:
- if (ipv6_addr_equal(&addr6->sin6_addr,
- &server->addr.sockAddr6.sin6_addr) &&
- (addr6->sin6_scope_id ==
- server->addr.sockAddr6.sin6_scope_id)) {
- addr6->sin6_port = htons(port);
- /* user overrode default port? */
- if (addr6->sin6_port) {
- if (addr6->sin6_port !=
- server->addr.sockAddr6.sin6_port)
- continue;
- }
- break;
- } else
- continue;
- }
+ if (!match_security(server, vol))
+ continue;
++server->srv_count;
write_unlock(&cifs_tcp_ses_lock);
@@ -1460,6 +1520,8 @@ cifs_put_tcp_session(struct TCP_Server_Info *server)
server->tcpStatus = CifsExiting;
spin_unlock(&GlobalMid_Lock);
+ cifs_fscache_release_client_cookie(server);
+
task = xchg(&server->tsk, NULL);
if (task)
force_sig(SIGKILL, task);
@@ -1479,7 +1541,10 @@ cifs_get_tcp_session(struct smb_vol *volume_info)
cFYI(1, "UNC: %s ip: %s", volume_info->UNC, volume_info->UNCip);
if (volume_info->UNCip && volume_info->UNC) {
- rc = cifs_convert_address(volume_info->UNCip, &addr);
+ rc = cifs_fill_sockaddr((struct sockaddr *)&addr,
+ volume_info->UNCip,
+ strlen(volume_info->UNCip),
+ volume_info->port);
if (!rc) {
/* we failed translating address */
rc = -EINVAL;
@@ -1499,7 +1564,7 @@ cifs_get_tcp_session(struct smb_vol *volume_info)
}
/* see if we already have a matching tcp_ses */
- tcp_ses = cifs_find_tcp_session(&addr, volume_info->port);
+ tcp_ses = cifs_find_tcp_session((struct sockaddr *)&addr, volume_info);
if (tcp_ses)
return tcp_ses;
@@ -1543,12 +1608,10 @@ cifs_get_tcp_session(struct smb_vol *volume_info)
cFYI(1, "attempting ipv6 connect");
/* BB should we allow ipv6 on port 139? */
/* other OS never observed in Wild doing 139 with v6 */
- sin_server6->sin6_port = htons(volume_info->port);
memcpy(&tcp_ses->addr.sockAddr6, sin_server6,
sizeof(struct sockaddr_in6));
rc = ipv6_connect(tcp_ses);
} else {
- sin_server->sin_port = htons(volume_info->port);
memcpy(&tcp_ses->addr.sockAddr, sin_server,
sizeof(struct sockaddr_in));
rc = ipv4_connect(tcp_ses);
@@ -1577,6 +1640,8 @@ cifs_get_tcp_session(struct smb_vol *volume_info)
list_add(&tcp_ses->tcp_ses_list, &cifs_tcp_ses_list);
write_unlock(&cifs_tcp_ses_lock);
+ cifs_fscache_get_client_cookie(tcp_ses);
+
return tcp_ses;
out_err:
@@ -1591,17 +1656,27 @@ out_err:
}
static struct cifsSesInfo *
-cifs_find_smb_ses(struct TCP_Server_Info *server, char *username)
+cifs_find_smb_ses(struct TCP_Server_Info *server, struct smb_vol *vol)
{
- struct list_head *tmp;
struct cifsSesInfo *ses;
write_lock(&cifs_tcp_ses_lock);
- list_for_each(tmp, &server->smb_ses_list) {
- ses = list_entry(tmp, struct cifsSesInfo, smb_ses_list);
- if (strncmp(ses->userName, username, MAX_USERNAME_SIZE))
- continue;
-
+ list_for_each_entry(ses, &server->smb_ses_list, smb_ses_list) {
+ switch (server->secType) {
+ case Kerberos:
+ if (vol->cred_uid != ses->cred_uid)
+ continue;
+ break;
+ default:
+ /* anything else takes username/password */
+ if (strncmp(ses->userName, vol->username,
+ MAX_USERNAME_SIZE))
+ continue;
+ if (strlen(vol->username) != 0 &&
+ strncmp(ses->password, vol->password,
+ MAX_PASSWORD_SIZE))
+ continue;
+ }
++ses->ses_count;
write_unlock(&cifs_tcp_ses_lock);
return ses;
@@ -1643,7 +1718,7 @@ cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb_vol *volume_info)
xid = GetXid();
- ses = cifs_find_smb_ses(server, volume_info->username);
+ ses = cifs_find_smb_ses(server, volume_info);
if (ses) {
cFYI(1, "Existing smb sess found (status=%d)", ses->status);
@@ -1706,6 +1781,7 @@ cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb_vol *volume_info)
if (ses->domainName)
strcpy(ses->domainName, volume_info->domainname);
}
+ ses->cred_uid = volume_info->cred_uid;
ses->linux_uid = volume_info->linux_uid;
ses->overrideSecFlg = volume_info->secFlg;
@@ -1773,6 +1849,7 @@ cifs_put_tcon(struct cifsTconInfo *tcon)
CIFSSMBTDis(xid, tcon);
_FreeXid(xid);
+ cifs_fscache_release_super_cookie(tcon);
tconInfoFree(tcon);
cifs_put_smb_ses(ses);
}
@@ -1843,6 +1920,8 @@ cifs_get_tcon(struct cifsSesInfo *ses, struct smb_vol *volume_info)
list_add(&tcon->tcon_list, &ses->tcon_list);
write_unlock(&cifs_tcp_ses_lock);
+ cifs_fscache_get_super_cookie(tcon);
+
return tcon;
out_fail:
@@ -2397,6 +2476,8 @@ static void setup_cifs_sb(struct smb_vol *pvolume_info,
cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_OVERR_GID;
if (pvolume_info->dynperm)
cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DYNPERM;
+ if (pvolume_info->fsc)
+ cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_FSCACHE;
if (pvolume_info->direct_io) {
cFYI(1, "mounting share using direct i/o");
cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DIRECT_IO;
diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c
index e7ae78b66fa..578d88c5b46 100644
--- a/fs/cifs/dir.c
+++ b/fs/cifs/dir.c
@@ -130,12 +130,6 @@ cifs_bp_rename_retry:
return full_path;
}
-/*
- * When called with struct file pointer set to NULL, there is no way we could
- * update file->private_data, but getting it stuck on openFileList provides a
- * way to access it from cifs_fill_filedata and thereby set file->private_data
- * from cifs_open.
- */
struct cifsFileInfo *
cifs_new_fileinfo(struct inode *newinode, __u16 fileHandle,
struct file *file, struct vfsmount *mnt, unsigned int oflags)
@@ -163,7 +157,7 @@ cifs_new_fileinfo(struct inode *newinode, __u16 fileHandle,
mutex_init(&pCifsFile->lock_mutex);
INIT_LIST_HEAD(&pCifsFile->llist);
atomic_set(&pCifsFile->count, 1);
- slow_work_init(&pCifsFile->oplock_break, &cifs_oplock_break_ops);
+ INIT_WORK(&pCifsFile->oplock_break, cifs_oplock_break);
write_lock(&GlobalSMBSeslock);
list_add(&pCifsFile->tlist, &cifs_sb->tcon->openFileList);
diff --git a/fs/cifs/dns_resolve.c b/fs/cifs/dns_resolve.c
index 853a968e82d..0eb87026cad 100644
--- a/fs/cifs/dns_resolve.c
+++ b/fs/cifs/dns_resolve.c
@@ -4,6 +4,8 @@
* Copyright (c) 2007 Igor Mammedov
* Author(s): Igor Mammedov (niallain@gmail.com)
* Steve French (sfrench@us.ibm.com)
+ * Wang Lei (wang840925@gmail.com)
+ * David Howells (dhowells@redhat.com)
*
* Contains the CIFS DFS upcall routines used for hostname to
* IP address translation.
@@ -24,214 +26,73 @@
*/
#include <linux/slab.h>
-#include <linux/keyctl.h>
-#include <linux/key-type.h>
-#include <keys/user-type.h>
+#include <linux/dns_resolver.h>
#include "dns_resolve.h"
#include "cifsglob.h"
#include "cifsproto.h"
#include "cifs_debug.h"
-static const struct cred *dns_resolver_cache;
-
-/* Checks if supplied name is IP address
- * returns:
- * 1 - name is IP
- * 0 - name is not IP
- */
-static int
-is_ip(char *name)
-{
- struct sockaddr_storage ss;
-
- return cifs_convert_address(name, &ss);
-}
-
-static int
-dns_resolver_instantiate(struct key *key, const void *data,
- size_t datalen)
-{
- int rc = 0;
- char *ip;
-
- ip = kmalloc(datalen + 1, GFP_KERNEL);
- if (!ip)
- return -ENOMEM;
-
- memcpy(ip, data, datalen);
- ip[datalen] = '\0';
-
- /* make sure this looks like an address */
- if (!is_ip(ip)) {
- kfree(ip);
- return -EINVAL;
- }
-
- key->type_data.x[0] = datalen;
- key->payload.data = ip;
-
- return rc;
-}
-
-static void
-dns_resolver_destroy(struct key *key)
-{
- kfree(key->payload.data);
-}
-
-struct key_type key_type_dns_resolver = {
- .name = "dns_resolver",
- .def_datalen = sizeof(struct in_addr),
- .describe = user_describe,
- .instantiate = dns_resolver_instantiate,
- .destroy = dns_resolver_destroy,
- .match = user_match,
-};
-
-/* Resolves server name to ip address.
- * input:
- * unc - server UNC
- * output:
- * *ip_addr - pointer to server ip, caller responcible for freeing it.
- * return 0 on success
+/**
+ * dns_resolve_server_name_to_ip - Resolve UNC server name to ip address.
+ * @unc: UNC path specifying the server
+ * @ip_addr: Where to return the IP address.
+ *
+ * The IP address will be returned in string form, and the caller is
+ * responsible for freeing it.
+ *
+ * Returns length of result on success, -ve on error.
*/
int
dns_resolve_server_name_to_ip(const char *unc, char **ip_addr)
{
- const struct cred *saved_cred;
- int rc = -EAGAIN;
- struct key *rkey = ERR_PTR(-EAGAIN);
+ struct sockaddr_storage ss;
+ const char *hostname, *sep;
char *name;
- char *data = NULL;
- int len;
+ int len, rc;
if (!ip_addr || !unc)
return -EINVAL;
- /* search for server name delimiter */
len = strlen(unc);
if (len < 3) {
cFYI(1, "%s: unc is too short: %s", __func__, unc);
return -EINVAL;
}
- len -= 2;
- name = memchr(unc+2, '\\', len);
- if (!name) {
- cFYI(1, "%s: probably server name is whole unc: %s",
- __func__, unc);
- } else {
- len = (name - unc) - 2/* leading // */;
- }
-
- name = kmalloc(len+1, GFP_KERNEL);
- if (!name) {
- rc = -ENOMEM;
- return rc;
- }
- memcpy(name, unc+2, len);
- name[len] = 0;
-
- if (is_ip(name)) {
- cFYI(1, "%s: it is IP, skipping dns upcall: %s",
- __func__, name);
- data = name;
- goto skip_upcall;
- }
- saved_cred = override_creds(dns_resolver_cache);
- rkey = request_key(&key_type_dns_resolver, name, "");
- revert_creds(saved_cred);
- if (!IS_ERR(rkey)) {
- if (!(rkey->perm & KEY_USR_VIEW)) {
- down_read(&rkey->sem);
- rkey->perm |= KEY_USR_VIEW;
- up_read(&rkey->sem);
- }
- len = rkey->type_data.x[0];
- data = rkey->payload.data;
- } else {
- cERROR(1, "%s: unable to resolve: %s", __func__, name);
- goto out;
- }
-
-skip_upcall:
- if (data) {
- *ip_addr = kmalloc(len + 1, GFP_KERNEL);
- if (*ip_addr) {
- memcpy(*ip_addr, data, len + 1);
- if (!IS_ERR(rkey))
- cFYI(1, "%s: resolved: %s to %s", __func__,
- name,
- *ip_addr
- );
- rc = 0;
- } else {
- rc = -ENOMEM;
- }
- if (!IS_ERR(rkey))
- key_put(rkey);
- }
+ /* Discount leading slashes for cifs */
+ len -= 2;
+ hostname = unc + 2;
-out:
- kfree(name);
+ /* Search for server name delimiter */
+ sep = memchr(hostname, '\\', len);
+ if (sep)
+ len = sep - unc;
+ else
+ cFYI(1, "%s: probably server name is whole unc: %s",
+ __func__, unc);
+
+ /* Try to interpret hostname as an IPv4 or IPv6 address */
+ rc = cifs_convert_address((struct sockaddr *)&ss, hostname, len);
+ if (rc > 0)
+ goto name_is_IP_address;
+
+ /* Perform the upcall */
+ rc = dns_query(NULL, hostname, len, NULL, ip_addr, NULL);
+ if (rc < 0)
+ cERROR(1, "%s: unable to resolve: %*.*s",
+ __func__, len, len, hostname);
+ else
+ cFYI(1, "%s: resolved: %*.*s to %s",
+ __func__, len, len, hostname, *ip_addr);
return rc;
-}
-int __init cifs_init_dns_resolver(void)
-{
- struct cred *cred;
- struct key *keyring;
- int ret;
-
- printk(KERN_NOTICE "Registering the %s key type\n",
- key_type_dns_resolver.name);
-
- /* create an override credential set with a special thread keyring in
- * which DNS requests are cached
- *
- * this is used to prevent malicious redirections from being installed
- * with add_key().
- */
- cred = prepare_kernel_cred(NULL);
- if (!cred)
+name_is_IP_address:
+ name = kmalloc(len + 1, GFP_KERNEL);
+ if (!name)
return -ENOMEM;
-
- keyring = key_alloc(&key_type_keyring, ".dns_resolver", 0, 0, cred,
- (KEY_POS_ALL & ~KEY_POS_SETATTR) |
- KEY_USR_VIEW | KEY_USR_READ,
- KEY_ALLOC_NOT_IN_QUOTA);
- if (IS_ERR(keyring)) {
- ret = PTR_ERR(keyring);
- goto failed_put_cred;
- }
-
- ret = key_instantiate_and_link(keyring, NULL, 0, NULL, NULL);
- if (ret < 0)
- goto failed_put_key;
-
- ret = register_key_type(&key_type_dns_resolver);
- if (ret < 0)
- goto failed_put_key;
-
- /* instruct request_key() to use this special keyring as a cache for
- * the results it looks up */
- cred->thread_keyring = keyring;
- cred->jit_keyring = KEY_REQKEY_DEFL_THREAD_KEYRING;
- dns_resolver_cache = cred;
+ memcpy(name, hostname, len);
+ name[len] = 0;
+ cFYI(1, "%s: unc is IP, skipping dns upcall: %s", __func__, name);
+ *ip_addr = name;
return 0;
-
-failed_put_key:
- key_put(keyring);
-failed_put_cred:
- put_cred(cred);
- return ret;
-}
-
-void cifs_exit_dns_resolver(void)
-{
- key_revoke(dns_resolver_cache->thread_keyring);
- unregister_key_type(&key_type_dns_resolver);
- put_cred(dns_resolver_cache);
- printk(KERN_NOTICE "Unregistered %s key type\n",
- key_type_dns_resolver.name);
}
diff --git a/fs/cifs/dns_resolve.h b/fs/cifs/dns_resolve.h
index 5d7f291df16..d3f5d27f4d0 100644
--- a/fs/cifs/dns_resolve.h
+++ b/fs/cifs/dns_resolve.h
@@ -24,8 +24,6 @@
#define _DNS_RESOLVE_H
#ifdef __KERNEL__
-extern int __init cifs_init_dns_resolver(void);
-extern void cifs_exit_dns_resolver(void);
extern int dns_resolve_server_name_to_ip(const char *unc, char **ip_addr);
#endif /* KERNEL */
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index 409e4f523e6..db11fdef0e9 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -40,6 +40,7 @@
#include "cifs_unicode.h"
#include "cifs_debug.h"
#include "cifs_fs_sb.h"
+#include "fscache.h"
static inline int cifs_convert_flags(unsigned int flags)
{
@@ -282,6 +283,9 @@ int cifs_open(struct inode *inode, struct file *file)
CIFSSMBClose(xid, tcon, netfid);
rc = -ENOMEM;
}
+
+ cifs_fscache_set_inode_cookie(inode, file);
+
goto out;
} else if ((rc == -EINVAL) || (rc == -EOPNOTSUPP)) {
if (tcon->ses->serverNOS)
@@ -373,6 +377,8 @@ int cifs_open(struct inode *inode, struct file *file)
goto out;
}
+ cifs_fscache_set_inode_cookie(inode, file);
+
if (oplock & CIFS_CREATE_ACTION) {
/* time to set mode which we can not set earlier due to
problems creating new read-only files */
@@ -427,7 +433,7 @@ static int cifs_reopen_file(struct file *file, bool can_flush)
__u16 netfid;
if (file->private_data)
- pCifsFile = (struct cifsFileInfo *)file->private_data;
+ pCifsFile = file->private_data;
else
return -EBADF;
@@ -565,8 +571,7 @@ int cifs_close(struct inode *inode, struct file *file)
int xid, timeout;
struct cifs_sb_info *cifs_sb;
struct cifsTconInfo *pTcon;
- struct cifsFileInfo *pSMBFile =
- (struct cifsFileInfo *)file->private_data;
+ struct cifsFileInfo *pSMBFile = file->private_data;
xid = GetXid();
@@ -641,8 +646,7 @@ int cifs_closedir(struct inode *inode, struct file *file)
{
int rc = 0;
int xid;
- struct cifsFileInfo *pCFileStruct =
- (struct cifsFileInfo *)file->private_data;
+ struct cifsFileInfo *pCFileStruct = file->private_data;
char *ptmp;
cFYI(1, "Closedir inode = 0x%p", inode);
@@ -863,8 +867,7 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
length, pfLock,
posix_lock_type, wait_flag);
} else {
- struct cifsFileInfo *fid =
- (struct cifsFileInfo *)file->private_data;
+ struct cifsFileInfo *fid = file->private_data;
if (numLock) {
rc = CIFSSMBLock(xid, tcon, netfid, length,
@@ -965,7 +968,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;
+ open_file = file->private_data;
rc = generic_write_checks(file, poffset, &write_size, 0);
if (rc)
@@ -1067,7 +1070,7 @@ static ssize_t cifs_write(struct file *file, const char *write_data,
if (file->private_data == NULL)
return -EBADF;
- open_file = (struct cifsFileInfo *)file->private_data;
+ open_file = file->private_data;
xid = GetXid();
@@ -1651,8 +1654,7 @@ int cifs_fsync(struct file *file, int datasync)
int xid;
int rc = 0;
struct cifsTconInfo *tcon;
- struct cifsFileInfo *smbfile =
- (struct cifsFileInfo *)file->private_data;
+ struct cifsFileInfo *smbfile = file->private_data;
struct inode *inode = file->f_path.dentry->d_inode;
xid = GetXid();
@@ -1756,7 +1758,7 @@ ssize_t cifs_user_read(struct file *file, char __user *read_data,
FreeXid(xid);
return rc;
}
- open_file = (struct cifsFileInfo *)file->private_data;
+ open_file = file->private_data;
if ((file->f_flags & O_ACCMODE) == O_WRONLY)
cFYI(1, "attempting read on write only file instance");
@@ -1837,7 +1839,7 @@ static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size,
FreeXid(xid);
return rc;
}
- open_file = (struct cifsFileInfo *)file->private_data;
+ open_file = file->private_data;
if ((file->f_flags & O_ACCMODE) == O_WRONLY)
cFYI(1, "attempting read on write only file instance");
@@ -1942,6 +1944,9 @@ static void cifs_copy_cache_pages(struct address_space *mapping,
SetPageUptodate(page);
unlock_page(page);
data += PAGE_CACHE_SIZE;
+
+ /* add page to FS-Cache */
+ cifs_readpage_to_fscache(mapping->host, page);
}
return;
}
@@ -1968,10 +1973,19 @@ static int cifs_readpages(struct file *file, struct address_space *mapping,
FreeXid(xid);
return rc;
}
- open_file = (struct cifsFileInfo *)file->private_data;
+ open_file = file->private_data;
cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
pTcon = cifs_sb->tcon;
+ /*
+ * Reads as many pages as possible from fscache. Returns -ENOBUFS
+ * immediately if the cookie is negative
+ */
+ rc = cifs_readpages_from_fscache(mapping->host, mapping, page_list,
+ &num_pages);
+ if (rc == 0)
+ goto read_complete;
+
cFYI(DBG2, "rpages: num pages %d", num_pages);
for (i = 0; i < num_pages; ) {
unsigned contig_pages;
@@ -2082,6 +2096,7 @@ static int cifs_readpages(struct file *file, struct address_space *mapping,
smb_read_data = NULL;
}
+read_complete:
FreeXid(xid);
return rc;
}
@@ -2092,6 +2107,11 @@ static int cifs_readpage_worker(struct file *file, struct page *page,
char *read_data;
int rc;
+ /* Is the page cached? */
+ rc = cifs_readpage_from_fscache(file->f_path.dentry->d_inode, page);
+ if (rc == 0)
+ goto read_complete;
+
page_cache_get(page);
read_data = kmap(page);
/* for reads over a certain size could initiate async read ahead */
@@ -2111,11 +2131,17 @@ static int cifs_readpage_worker(struct file *file, struct page *page,
flush_dcache_page(page);
SetPageUptodate(page);
+
+ /* send this page to the cache */
+ cifs_readpage_to_fscache(file->f_path.dentry->d_inode, page);
+
rc = 0;
io_error:
kunmap(page);
page_cache_release(page);
+
+read_complete:
return rc;
}
@@ -2265,8 +2291,23 @@ out:
return rc;
}
-static void
-cifs_oplock_break(struct slow_work *work)
+static int cifs_release_page(struct page *page, gfp_t gfp)
+{
+ if (PagePrivate(page))
+ return 0;
+
+ return cifs_fscache_release_page(page, gfp);
+}
+
+static void cifs_invalidate_page(struct page *page, unsigned long offset)
+{
+ struct cifsInodeInfo *cifsi = CIFS_I(page->mapping->host);
+
+ if (offset == 0)
+ cifs_fscache_invalidate_page(page, &cifsi->vfs_inode);
+}
+
+void cifs_oplock_break(struct work_struct *work)
{
struct cifsFileInfo *cfile = container_of(work, struct cifsFileInfo,
oplock_break);
@@ -2303,33 +2344,30 @@ cifs_oplock_break(struct slow_work *work)
LOCKING_ANDX_OPLOCK_RELEASE, false);
cFYI(1, "Oplock release rc = %d", rc);
}
+
+ /*
+ * We might have kicked in before is_valid_oplock_break()
+ * finished grabbing reference for us. Make sure it's done by
+ * waiting for GlobalSMSSeslock.
+ */
+ write_lock(&GlobalSMBSeslock);
+ write_unlock(&GlobalSMBSeslock);
+
+ cifs_oplock_break_put(cfile);
}
-static int
-cifs_oplock_break_get(struct slow_work *work)
+void cifs_oplock_break_get(struct cifsFileInfo *cfile)
{
- struct cifsFileInfo *cfile = container_of(work, struct cifsFileInfo,
- oplock_break);
mntget(cfile->mnt);
cifsFileInfo_get(cfile);
- return 0;
}
-static void
-cifs_oplock_break_put(struct slow_work *work)
+void cifs_oplock_break_put(struct cifsFileInfo *cfile)
{
- struct cifsFileInfo *cfile = container_of(work, struct cifsFileInfo,
- oplock_break);
mntput(cfile->mnt);
cifsFileInfo_put(cfile);
}
-const struct slow_work_ops cifs_oplock_break_ops = {
- .get_ref = cifs_oplock_break_get,
- .put_ref = cifs_oplock_break_put,
- .execute = cifs_oplock_break,
-};
-
const struct address_space_operations cifs_addr_ops = {
.readpage = cifs_readpage,
.readpages = cifs_readpages,
@@ -2338,6 +2376,8 @@ const struct address_space_operations cifs_addr_ops = {
.write_begin = cifs_write_begin,
.write_end = cifs_write_end,
.set_page_dirty = __set_page_dirty_nobuffers,
+ .releasepage = cifs_release_page,
+ .invalidatepage = cifs_invalidate_page,
/* .sync_page = cifs_sync_page, */
/* .direct_IO = */
};
@@ -2354,6 +2394,8 @@ const struct address_space_operations cifs_addr_ops_smallbuf = {
.write_begin = cifs_write_begin,
.write_end = cifs_write_end,
.set_page_dirty = __set_page_dirty_nobuffers,
+ .releasepage = cifs_release_page,
+ .invalidatepage = cifs_invalidate_page,
/* .sync_page = cifs_sync_page, */
/* .direct_IO = */
};
diff --git a/fs/cifs/fscache.c b/fs/cifs/fscache.c
new file mode 100644
index 00000000000..9f3f5c4be16
--- /dev/null
+++ b/fs/cifs/fscache.c
@@ -0,0 +1,236 @@
+/*
+ * fs/cifs/fscache.c - CIFS filesystem cache interface
+ *
+ * Copyright (c) 2010 Novell, Inc.
+ * Author(s): Suresh Jayaraman (sjayaraman@suse.de>
+ *
+ * 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
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * 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
+ */
+#include "fscache.h"
+#include "cifsglob.h"
+#include "cifs_debug.h"
+#include "cifs_fs_sb.h"
+
+void cifs_fscache_get_client_cookie(struct TCP_Server_Info *server)
+{
+ server->fscache =
+ fscache_acquire_cookie(cifs_fscache_netfs.primary_index,
+ &cifs_fscache_server_index_def, server);
+ cFYI(1, "CIFS: get client cookie (0x%p/0x%p)", server,
+ server->fscache);
+}
+
+void cifs_fscache_release_client_cookie(struct TCP_Server_Info *server)
+{
+ cFYI(1, "CIFS: release client cookie (0x%p/0x%p)", server,
+ server->fscache);
+ fscache_relinquish_cookie(server->fscache, 0);
+ server->fscache = NULL;
+}
+
+void cifs_fscache_get_super_cookie(struct cifsTconInfo *tcon)
+{
+ struct TCP_Server_Info *server = tcon->ses->server;
+
+ tcon->fscache =
+ fscache_acquire_cookie(server->fscache,
+ &cifs_fscache_super_index_def, tcon);
+ cFYI(1, "CIFS: get superblock cookie (0x%p/0x%p)",
+ server->fscache, tcon->fscache);
+}
+
+void cifs_fscache_release_super_cookie(struct cifsTconInfo *tcon)
+{
+ cFYI(1, "CIFS: releasing superblock cookie (0x%p)", tcon->fscache);
+ fscache_relinquish_cookie(tcon->fscache, 0);
+ tcon->fscache = NULL;
+}
+
+static void cifs_fscache_enable_inode_cookie(struct inode *inode)
+{
+ struct cifsInodeInfo *cifsi = CIFS_I(inode);
+ struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
+
+ if (cifsi->fscache)
+ return;
+
+ cifsi->fscache = fscache_acquire_cookie(cifs_sb->tcon->fscache,
+ &cifs_fscache_inode_object_def,
+ cifsi);
+ cFYI(1, "CIFS: got FH cookie (0x%p/0x%p)",
+ cifs_sb->tcon->fscache, cifsi->fscache);
+}
+
+void cifs_fscache_release_inode_cookie(struct inode *inode)
+{
+ struct cifsInodeInfo *cifsi = CIFS_I(inode);
+
+ if (cifsi->fscache) {
+ cFYI(1, "CIFS releasing inode cookie (0x%p)",
+ cifsi->fscache);
+ fscache_relinquish_cookie(cifsi->fscache, 0);
+ cifsi->fscache = NULL;
+ }
+}
+
+static void cifs_fscache_disable_inode_cookie(struct inode *inode)
+{
+ struct cifsInodeInfo *cifsi = CIFS_I(inode);
+
+ if (cifsi->fscache) {
+ cFYI(1, "CIFS disabling inode cookie (0x%p)",
+ cifsi->fscache);
+ fscache_relinquish_cookie(cifsi->fscache, 1);
+ cifsi->fscache = NULL;
+ }
+}
+
+void cifs_fscache_set_inode_cookie(struct inode *inode, struct file *filp)
+{
+ if ((filp->f_flags & O_ACCMODE) != O_RDONLY)
+ cifs_fscache_disable_inode_cookie(inode);
+ else {
+ cifs_fscache_enable_inode_cookie(inode);
+ cFYI(1, "CIFS: fscache inode cookie set");
+ }
+}
+
+void cifs_fscache_reset_inode_cookie(struct inode *inode)
+{
+ struct cifsInodeInfo *cifsi = CIFS_I(inode);
+ struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
+ struct fscache_cookie *old = cifsi->fscache;
+
+ if (cifsi->fscache) {
+ /* retire the current fscache cache and get a new one */
+ fscache_relinquish_cookie(cifsi->fscache, 1);
+
+ cifsi->fscache = fscache_acquire_cookie(cifs_sb->tcon->fscache,
+ &cifs_fscache_inode_object_def,
+ cifsi);
+ cFYI(1, "CIFS: new cookie 0x%p oldcookie 0x%p",
+ cifsi->fscache, old);
+ }
+}
+
+int cifs_fscache_release_page(struct page *page, gfp_t gfp)
+{
+ if (PageFsCache(page)) {
+ struct inode *inode = page->mapping->host;
+ struct cifsInodeInfo *cifsi = CIFS_I(inode);
+
+ cFYI(1, "CIFS: fscache release page (0x%p/0x%p)",
+ page, cifsi->fscache);
+ if (!fscache_maybe_release_page(cifsi->fscache, page, gfp))
+ return 0;
+ }
+
+ return 1;
+}
+
+static void cifs_readpage_from_fscache_complete(struct page *page, void *ctx,
+ int error)
+{
+ cFYI(1, "CFS: readpage_from_fscache_complete (0x%p/%d)",
+ page, error);
+ if (!error)
+ SetPageUptodate(page);
+ unlock_page(page);
+}
+
+/*
+ * Retrieve a page from FS-Cache
+ */
+int __cifs_readpage_from_fscache(struct inode *inode, struct page *page)
+{
+ int ret;
+
+ cFYI(1, "CIFS: readpage_from_fscache(fsc:%p, p:%p, i:0x%p",
+ CIFS_I(inode)->fscache, page, inode);
+ ret = fscache_read_or_alloc_page(CIFS_I(inode)->fscache, page,
+ cifs_readpage_from_fscache_complete,
+ NULL,
+ GFP_KERNEL);
+ switch (ret) {
+
+ case 0: /* page found in fscache, read submitted */
+ cFYI(1, "CIFS: readpage_from_fscache: submitted");
+ return ret;
+ case -ENOBUFS: /* page won't be cached */
+ case -ENODATA: /* page not in cache */
+ cFYI(1, "CIFS: readpage_from_fscache %d", ret);
+ return 1;
+
+ default:
+ cERROR(1, "unknown error ret = %d", ret);
+ }
+ return ret;
+}
+
+/*
+ * Retrieve a set of pages from FS-Cache
+ */
+int __cifs_readpages_from_fscache(struct inode *inode,
+ struct address_space *mapping,
+ struct list_head *pages,
+ unsigned *nr_pages)
+{
+ int ret;
+
+ cFYI(1, "CIFS: __cifs_readpages_from_fscache (0x%p/%u/0x%p)",
+ CIFS_I(inode)->fscache, *nr_pages, inode);
+ ret = fscache_read_or_alloc_pages(CIFS_I(inode)->fscache, mapping,
+ pages, nr_pages,
+ cifs_readpage_from_fscache_complete,
+ NULL,
+ mapping_gfp_mask(mapping));
+ switch (ret) {
+ case 0: /* read submitted to the cache for all pages */
+ cFYI(1, "CIFS: readpages_from_fscache: submitted");
+ return ret;
+
+ case -ENOBUFS: /* some pages are not cached and can't be */
+ case -ENODATA: /* some pages are not cached */
+ cFYI(1, "CIFS: readpages_from_fscache: no page");
+ return 1;
+
+ default:
+ cFYI(1, "unknown error ret = %d", ret);
+ }
+
+ return ret;
+}
+
+void __cifs_readpage_to_fscache(struct inode *inode, struct page *page)
+{
+ int ret;
+
+ cFYI(1, "CIFS: readpage_to_fscache(fsc: %p, p: %p, i: %p",
+ CIFS_I(inode)->fscache, page, inode);
+ ret = fscache_write_page(CIFS_I(inode)->fscache, page, GFP_KERNEL);
+ if (ret != 0)
+ fscache_uncache_page(CIFS_I(inode)->fscache, page);
+}
+
+void __cifs_fscache_invalidate_page(struct page *page, struct inode *inode)
+{
+ struct cifsInodeInfo *cifsi = CIFS_I(inode);
+ struct fscache_cookie *cookie = cifsi->fscache;
+
+ cFYI(1, "CIFS: fscache invalidatepage (0x%p/0x%p)", page, cookie);
+ fscache_wait_on_page_write(cookie, page);
+ fscache_uncache_page(cookie, page);
+}
+
diff --git a/fs/cifs/fscache.h b/fs/cifs/fscache.h
new file mode 100644
index 00000000000..31b88ec2341
--- /dev/null
+++ b/fs/cifs/fscache.h
@@ -0,0 +1,136 @@
+/*
+ * fs/cifs/fscache.h - CIFS filesystem cache interface definitions
+ *
+ * Copyright (c) 2010 Novell, Inc.
+ * Authors(s): Suresh Jayaraman (sjayaraman@suse.de>
+ *
+ * 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
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * 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
+ */
+#ifndef _CIFS_FSCACHE_H
+#define _CIFS_FSCACHE_H
+
+#include <linux/fscache.h>
+
+#include "cifsglob.h"
+
+#ifdef CONFIG_CIFS_FSCACHE
+
+extern struct fscache_netfs cifs_fscache_netfs;
+extern const struct fscache_cookie_def cifs_fscache_server_index_def;
+extern const struct fscache_cookie_def cifs_fscache_super_index_def;
+extern const struct fscache_cookie_def cifs_fscache_inode_object_def;
+
+extern int cifs_fscache_register(void);
+extern void cifs_fscache_unregister(void);
+
+/*
+ * fscache.c
+ */
+extern void cifs_fscache_get_client_cookie(struct TCP_Server_Info *);
+extern void cifs_fscache_release_client_cookie(struct TCP_Server_Info *);
+extern void cifs_fscache_get_super_cookie(struct cifsTconInfo *);
+extern void cifs_fscache_release_super_cookie(struct cifsTconInfo *);
+
+extern void cifs_fscache_release_inode_cookie(struct inode *);
+extern void cifs_fscache_set_inode_cookie(struct inode *, struct file *);
+extern void cifs_fscache_reset_inode_cookie(struct inode *);
+
+extern void __cifs_fscache_invalidate_page(struct page *, struct inode *);
+extern int cifs_fscache_release_page(struct page *page, gfp_t gfp);
+extern int __cifs_readpage_from_fscache(struct inode *, struct page *);
+extern int __cifs_readpages_from_fscache(struct inode *,
+ struct address_space *,
+ struct list_head *,
+ unsigned *);
+
+extern void __cifs_readpage_to_fscache(struct inode *, struct page *);
+
+static inline void cifs_fscache_invalidate_page(struct page *page,
+ struct inode *inode)
+{
+ if (PageFsCache(page))
+ __cifs_fscache_invalidate_page(page, inode);
+}
+
+static inline int cifs_readpage_from_fscache(struct inode *inode,
+ struct page *page)
+{
+ if (CIFS_I(inode)->fscache)
+ return __cifs_readpage_from_fscache(inode, page);
+
+ return -ENOBUFS;
+}
+
+static inline int cifs_readpages_from_fscache(struct inode *inode,
+ struct address_space *mapping,
+ struct list_head *pages,
+ unsigned *nr_pages)
+{
+ if (CIFS_I(inode)->fscache)
+ return __cifs_readpages_from_fscache(inode, mapping, pages,
+ nr_pages);
+ return -ENOBUFS;
+}
+
+static inline void cifs_readpage_to_fscache(struct inode *inode,
+ struct page *page)
+{
+ if (PageFsCache(page))
+ __cifs_readpage_to_fscache(inode, page);
+}
+
+#else /* CONFIG_CIFS_FSCACHE */
+static inline int cifs_fscache_register(void) { return 0; }
+static inline void cifs_fscache_unregister(void) {}
+
+static inline void
+cifs_fscache_get_client_cookie(struct TCP_Server_Info *server) {}
+static inline void
+cifs_fscache_release_client_cookie(struct TCP_Server_Info *server) {}
+static inline void cifs_fscache_get_super_cookie(struct cifsTconInfo *tcon) {}
+static inline void
+cifs_fscache_release_super_cookie(struct cifsTconInfo *tcon) {}
+
+static inline void cifs_fscache_release_inode_cookie(struct inode *inode) {}
+static inline void cifs_fscache_set_inode_cookie(struct inode *inode,
+ struct file *filp) {}
+static inline void cifs_fscache_reset_inode_cookie(struct inode *inode) {}
+static inline int cifs_fscache_release_page(struct page *page, gfp_t gfp)
+{
+ return 1; /* May release page */
+}
+
+static inline void cifs_fscache_invalidate_page(struct page *page,
+ struct inode *inode) {}
+static inline int
+cifs_readpage_from_fscache(struct inode *inode, struct page *page)
+{
+ return -ENOBUFS;
+}
+
+static inline int cifs_readpages_from_fscache(struct inode *inode,
+ struct address_space *mapping,
+ struct list_head *pages,
+ unsigned *nr_pages)
+{
+ return -ENOBUFS;
+}
+
+static inline void cifs_readpage_to_fscache(struct inode *inode,
+ struct page *page) {}
+
+#endif /* CONFIG_CIFS_FSCACHE */
+
+#endif /* _CIFS_FSCACHE_H */
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
index 6f0683c6895..dc4c47ab958 100644
--- a/fs/cifs/inode.c
+++ b/fs/cifs/inode.c
@@ -29,6 +29,7 @@
#include "cifsproto.h"
#include "cifs_debug.h"
#include "cifs_fs_sb.h"
+#include "fscache.h"
static void cifs_set_ops(struct inode *inode, const bool is_dfs_referral)
@@ -288,7 +289,7 @@ int cifs_get_file_info_unix(struct file *filp)
struct inode *inode = filp->f_path.dentry->d_inode;
struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
struct cifsTconInfo *tcon = cifs_sb->tcon;
- struct cifsFileInfo *cfile = (struct cifsFileInfo *) filp->private_data;
+ struct cifsFileInfo *cfile = filp->private_data;
xid = GetXid();
rc = CIFSSMBUnixQFileInfo(xid, tcon, cfile->netfid, &find_data);
@@ -515,7 +516,7 @@ int cifs_get_file_info(struct file *filp)
struct inode *inode = filp->f_path.dentry->d_inode;
struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
struct cifsTconInfo *tcon = cifs_sb->tcon;
- struct cifsFileInfo *cfile = (struct cifsFileInfo *) filp->private_data;
+ struct cifsFileInfo *cfile = filp->private_data;
xid = GetXid();
rc = CIFSSMBQFileInfo(xid, tcon, cfile->netfid, &find_data);
@@ -723,18 +724,17 @@ cifs_find_inode(struct inode *inode, void *opaque)
{
struct cifs_fattr *fattr = (struct cifs_fattr *) opaque;
+ /* don't match inode with different uniqueid */
if (CIFS_I(inode)->uniqueid != fattr->cf_uniqueid)
return 0;
- /*
- * uh oh -- it's a directory. We can't use it since hardlinked dirs are
- * verboten. Disable serverino and return it as if it were found, the
- * caller can discard it, generate a uniqueid and retry the find
- */
- if (S_ISDIR(inode->i_mode) && !list_empty(&inode->i_dentry)) {
+ /* don't match inode of different type */
+ if ((inode->i_mode & S_IFMT) != (fattr->cf_mode & S_IFMT))
+ return 0;
+
+ /* if it's not a directory or has no dentries, then flag it */
+ if (S_ISDIR(inode->i_mode) && !list_empty(&inode->i_dentry))
fattr->cf_flags |= CIFS_FATTR_INO_COLLISION;
- cifs_autodisable_serverino(CIFS_SB(inode->i_sb));
- }
return 1;
}
@@ -748,6 +748,27 @@ cifs_init_inode(struct inode *inode, void *opaque)
return 0;
}
+/*
+ * walk dentry list for an inode and report whether it has aliases that
+ * are hashed. We use this to determine if a directory inode can actually
+ * be used.
+ */
+static bool
+inode_has_hashed_dentries(struct inode *inode)
+{
+ struct dentry *dentry;
+
+ spin_lock(&dcache_lock);
+ list_for_each_entry(dentry, &inode->i_dentry, d_alias) {
+ if (!d_unhashed(dentry) || IS_ROOT(dentry)) {
+ spin_unlock(&dcache_lock);
+ return true;
+ }
+ }
+ spin_unlock(&dcache_lock);
+ return false;
+}
+
/* Given fattrs, get a corresponding inode */
struct inode *
cifs_iget(struct super_block *sb, struct cifs_fattr *fattr)
@@ -763,12 +784,16 @@ retry_iget5_locked:
inode = iget5_locked(sb, hash, cifs_find_inode, cifs_init_inode, fattr);
if (inode) {
- /* was there a problematic inode number collision? */
+ /* was there a potentially problematic inode collision? */
if (fattr->cf_flags & CIFS_FATTR_INO_COLLISION) {
- iput(inode);
- fattr->cf_uniqueid = iunique(sb, ROOT_I);
fattr->cf_flags &= ~CIFS_FATTR_INO_COLLISION;
- goto retry_iget5_locked;
+
+ if (inode_has_hashed_dentries(inode)) {
+ cifs_autodisable_serverino(CIFS_SB(sb));
+ iput(inode);
+ fattr->cf_uniqueid = iunique(sb, ROOT_I);
+ goto retry_iget5_locked;
+ }
}
cifs_fattr_to_inode(inode, fattr);
@@ -776,6 +801,10 @@ retry_iget5_locked:
inode->i_flags |= S_NOATIME | S_NOCMTIME;
if (inode->i_state & I_NEW) {
inode->i_ino = hash;
+#ifdef CONFIG_CIFS_FSCACHE
+ /* initialize per-inode cache cookie pointer */
+ CIFS_I(inode)->fscache = NULL;
+#endif
unlock_new_inode(inode);
}
}
@@ -807,6 +836,11 @@ struct inode *cifs_root_iget(struct super_block *sb, unsigned long ino)
if (!inode)
return ERR_PTR(-ENOMEM);
+#ifdef CONFIG_CIFS_FSCACHE
+ /* populate tcon->resource_id */
+ cifs_sb->tcon->resource_id = CIFS_I(inode)->uniqueid;
+#endif
+
if (rc && cifs_sb->tcon->ipc) {
cFYI(1, "ipc connection - fake read inode");
inode->i_mode |= S_IFDIR;
@@ -1568,6 +1602,7 @@ cifs_invalidate_mapping(struct inode *inode)
cifs_i->write_behind_rc = rc;
}
invalidate_remote_inode(inode);
+ cifs_fscache_reset_inode_cookie(inode);
}
int cifs_revalidate_file(struct file *filp)
diff --git a/fs/cifs/ioctl.c b/fs/cifs/ioctl.c
index 505926f1ee6..9d38a71c8e1 100644
--- a/fs/cifs/ioctl.c
+++ b/fs/cifs/ioctl.c
@@ -41,8 +41,7 @@ long cifs_ioctl(struct file *filep, unsigned int command, unsigned long arg)
__u64 ExtAttrMask = 0;
__u64 caps;
struct cifsTconInfo *tcon;
- struct cifsFileInfo *pSMBFile =
- (struct cifsFileInfo *)filep->private_data;
+ struct cifsFileInfo *pSMBFile = filep->private_data;
#endif /* CONFIG_CIFS_POSIX */
xid = GetXid();
diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c
index 1394aa37f26..3ccadc1326d 100644
--- a/fs/cifs/misc.c
+++ b/fs/cifs/misc.c
@@ -498,7 +498,6 @@ is_valid_oplock_break(struct smb_hdr *buf, struct TCP_Server_Info *srv)
struct cifsTconInfo *tcon;
struct cifsInodeInfo *pCifsInode;
struct cifsFileInfo *netfile;
- int rc;
cFYI(1, "Checking for oplock break or dnotify response");
if ((pSMB->hdr.Command == SMB_COM_NT_TRANSACT) &&
@@ -583,13 +582,18 @@ is_valid_oplock_break(struct smb_hdr *buf, struct TCP_Server_Info *srv)
pCifsInode->clientCanCacheAll = false;
if (pSMB->OplockLevel == 0)
pCifsInode->clientCanCacheRead = false;
- rc = slow_work_enqueue(&netfile->oplock_break);
- if (rc) {
- cERROR(1, "failed to enqueue oplock "
- "break: %d\n", rc);
- } else {
- netfile->oplock_break_cancelled = false;
- }
+
+ /*
+ * cifs_oplock_break_put() can't be called
+ * from here. Get reference after queueing
+ * succeeded. cifs_oplock_break() will
+ * synchronize using GlobalSMSSeslock.
+ */
+ if (queue_work(system_nrt_wq,
+ &netfile->oplock_break))
+ cifs_oplock_break_get(netfile);
+ netfile->oplock_break_cancelled = false;
+
read_unlock(&GlobalSMBSeslock);
read_unlock(&cifs_tcp_ses_lock);
return true;
diff --git a/fs/cifs/netmisc.c b/fs/cifs/netmisc.c
index d35d52889cb..f97851119e6 100644
--- a/fs/cifs/netmisc.c
+++ b/fs/cifs/netmisc.c
@@ -61,6 +61,7 @@ static const struct smb_to_posix_error mapping_table_ERRDOS[] = {
{ERRremcd, -EACCES},
{ERRdiffdevice, -EXDEV},
{ERRnofiles, -ENOENT},
+ {ERRwriteprot, -EROFS},
{ERRbadshare, -ETXTBSY},
{ERRlock, -EACCES},
{ERRunsup, -EINVAL},
@@ -139,17 +140,18 @@ static const struct smb_to_posix_error mapping_table_ERRHRD[] = {
* Returns 0 on failure.
*/
static int
-cifs_inet_pton(const int address_family, const char *cp, void *dst)
+cifs_inet_pton(const int address_family, const char *cp, int len, void *dst)
{
int ret = 0;
/* calculate length by finding first slash or NULL */
if (address_family == AF_INET)
- ret = in4_pton(cp, -1 /* len */, dst, '\\', NULL);
+ ret = in4_pton(cp, len, dst, '\\', NULL);
else if (address_family == AF_INET6)
- ret = in6_pton(cp, -1 /* len */, dst , '\\', NULL);
+ ret = in6_pton(cp, len, dst , '\\', NULL);
- cFYI(DBG2, "address conversion returned %d for %s", ret, cp);
+ cFYI(DBG2, "address conversion returned %d for %*.*s",
+ ret, len, len, cp);
if (ret > 0)
ret = 1;
return ret;
@@ -164,43 +166,66 @@ cifs_inet_pton(const int address_family, const char *cp, void *dst)
* Returns 0 on failure.
*/
int
-cifs_convert_address(char *src, void *dst)
+cifs_convert_address(struct sockaddr *dst, const char *src, int len)
{
- int rc;
- char *pct, *endp;
+ int rc, alen, slen;
+ const char *pct;
+ char *endp, scope_id[13];
struct sockaddr_in *s4 = (struct sockaddr_in *) dst;
struct sockaddr_in6 *s6 = (struct sockaddr_in6 *) dst;
/* IPv4 address */
- if (cifs_inet_pton(AF_INET, src, &s4->sin_addr.s_addr)) {
+ if (cifs_inet_pton(AF_INET, src, len, &s4->sin_addr.s_addr)) {
s4->sin_family = AF_INET;
return 1;
}
- /* temporarily terminate string */
- pct = strchr(src, '%');
- if (pct)
- *pct = '\0';
-
- rc = cifs_inet_pton(AF_INET6, src, &s6->sin6_addr.s6_addr);
-
- /* repair temp termination (if any) and make pct point to scopeid */
- if (pct)
- *pct++ = '%';
+ /* attempt to exclude the scope ID from the address part */
+ pct = memchr(src, '%', len);
+ alen = pct ? pct - src : len;
+ rc = cifs_inet_pton(AF_INET6, src, alen, &s6->sin6_addr.s6_addr);
if (!rc)
return rc;
s6->sin6_family = AF_INET6;
if (pct) {
+ /* grab the scope ID */
+ slen = len - (alen + 1);
+ if (slen <= 0 || slen > 12)
+ return 0;
+ memcpy(scope_id, pct + 1, slen);
+ scope_id[slen] = '\0';
+
s6->sin6_scope_id = (u32) simple_strtoul(pct, &endp, 0);
- if (!*pct || *endp)
+ if (endp != scope_id + slen)
return 0;
}
return rc;
}
+int
+cifs_fill_sockaddr(struct sockaddr *dst, const char *src, int len,
+ const unsigned short int port)
+{
+ if (!cifs_convert_address(dst, src, len))
+ return 0;
+
+ switch (dst->sa_family) {
+ case AF_INET:
+ ((struct sockaddr_in *)dst)->sin_port = htons(port);
+ break;
+ case AF_INET6:
+ ((struct sockaddr_in6 *)dst)->sin6_port = htons(port);
+ break;
+ default:
+ return 0;
+ }
+
+ return 1;
+}
+
/*****************************************************************************
convert a NT status code to a dos class/code
*****************************************************************************/
diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c
index daf1753af67..d5e591fab47 100644
--- a/fs/cifs/readdir.c
+++ b/fs/cifs/readdir.c
@@ -847,6 +847,11 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
end_of_smb = cifsFile->srch_inf.ntwrk_buf_start + max_len;
tmp_buf = kmalloc(UNICODE_NAME_MAX, GFP_KERNEL);
+ if (tmp_buf == NULL) {
+ rc = -ENOMEM;
+ break;
+ }
+
for (i = 0; (i < num_to_fill) && (rc == 0); i++) {
if (current_entry == NULL) {
/* evaluate whether this case is an error */
diff --git a/fs/cifs/smberr.h b/fs/cifs/smberr.h
index c5084d27db7..7f16cb825fe 100644
--- a/fs/cifs/smberr.h
+++ b/fs/cifs/smberr.h
@@ -76,6 +76,7 @@
#define ERRnofiles 18 /* A File Search command can find no
more files matching the specified
criteria. */
+#define ERRwriteprot 19 /* media is write protected */
#define ERRgeneral 31
#define ERRbadshare 32 /* The sharing mode specified for an
Open conflicts with existing FIDs on
diff --git a/fs/compat.c b/fs/compat.c
index 6490d2134ff..c6fda9aeb86 100644
--- a/fs/compat.c
+++ b/fs/compat.c
@@ -8,7 +8,7 @@
* Copyright (C) 1997-2000 Jakub Jelinek (jakub@redhat.com)
* Copyright (C) 1998 Eddie C. Dost (ecd@skynet.be)
* Copyright (C) 2001,2002 Andi Kleen, SuSE Labs
- * Copyright (C) 2003 Pavel Machek (pavel@suse.cz)
+ * Copyright (C) 2003 Pavel Machek (pavel@ucw.cz)
*
* 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
diff --git a/fs/compat_ioctl.c b/fs/compat_ioctl.c
index 641640dc7ae..63ae8583146 100644
--- a/fs/compat_ioctl.c
+++ b/fs/compat_ioctl.c
@@ -4,7 +4,7 @@
* Copyright (C) 1997-2000 Jakub Jelinek (jakub@redhat.com)
* Copyright (C) 1998 Eddie C. Dost (ecd@skynet.be)
* Copyright (C) 2001,2002 Andi Kleen, SuSE Labs
- * Copyright (C) 2003 Pavel Machek (pavel@suse.cz)
+ * Copyright (C) 2003 Pavel Machek (pavel@ucw.cz)
*
* These routines maintain argument size conversion between 32bit and 64bit
* ioctls.
@@ -601,8 +601,11 @@ static int ioc_settimeout(unsigned int fd, unsigned int cmd,
}
/* Bluetooth ioctls */
-#define HCIUARTSETPROTO _IOW('U', 200, int)
-#define HCIUARTGETPROTO _IOR('U', 201, int)
+#define HCIUARTSETPROTO _IOW('U', 200, int)
+#define HCIUARTGETPROTO _IOR('U', 201, int)
+#define HCIUARTGETDEVICE _IOR('U', 202, int)
+#define HCIUARTSETFLAGS _IOW('U', 203, int)
+#define HCIUARTGETFLAGS _IOR('U', 204, int)
#define BNEPCONNADD _IOW('B', 200, int)
#define BNEPCONNDEL _IOW('B', 201, int)
@@ -1328,6 +1331,8 @@ COMPATIBLE_IOCTL(HCISETLINKPOL)
COMPATIBLE_IOCTL(HCISETLINKMODE)
COMPATIBLE_IOCTL(HCISETACLMTU)
COMPATIBLE_IOCTL(HCISETSCOMTU)
+COMPATIBLE_IOCTL(HCIBLOCKADDR)
+COMPATIBLE_IOCTL(HCIUNBLOCKADDR)
COMPATIBLE_IOCTL(HCIINQUIRY)
COMPATIBLE_IOCTL(HCIUARTSETPROTO)
COMPATIBLE_IOCTL(HCIUARTGETPROTO)
diff --git a/fs/direct-io.c b/fs/direct-io.c
index 7600aacf531..a10cb91cade 100644
--- a/fs/direct-io.c
+++ b/fs/direct-io.c
@@ -218,7 +218,7 @@ static struct page *dio_get_page(struct dio *dio)
* filesystems can use it to hold additional state between get_block calls and
* dio_complete.
*/
-static int dio_complete(struct dio *dio, loff_t offset, int ret)
+static int dio_complete(struct dio *dio, loff_t offset, int ret, bool is_async)
{
ssize_t transferred = 0;
@@ -239,14 +239,6 @@ static int dio_complete(struct dio *dio, loff_t offset, int ret)
transferred = dio->i_size - offset;
}
- if (dio->end_io && dio->result)
- dio->end_io(dio->iocb, offset, transferred,
- dio->map_bh.b_private);
-
- if (dio->flags & DIO_LOCKING)
- /* lockdep: non-owner release */
- up_read_non_owner(&dio->inode->i_alloc_sem);
-
if (ret == 0)
ret = dio->page_errors;
if (ret == 0)
@@ -254,6 +246,17 @@ static int dio_complete(struct dio *dio, loff_t offset, int ret)
if (ret == 0)
ret = transferred;
+ if (dio->end_io && dio->result) {
+ dio->end_io(dio->iocb, offset, transferred,
+ dio->map_bh.b_private, ret, is_async);
+ } else if (is_async) {
+ aio_complete(dio->iocb, ret, 0);
+ }
+
+ if (dio->flags & DIO_LOCKING)
+ /* lockdep: non-owner release */
+ up_read_non_owner(&dio->inode->i_alloc_sem);
+
return ret;
}
@@ -277,8 +280,7 @@ static void dio_bio_end_aio(struct bio *bio, int error)
spin_unlock_irqrestore(&dio->bio_lock, flags);
if (remaining == 0) {
- int ret = dio_complete(dio, dio->iocb->ki_pos, 0);
- aio_complete(dio->iocb, ret, 0);
+ dio_complete(dio, dio->iocb->ki_pos, 0, true);
kfree(dio);
}
}
@@ -1126,7 +1128,7 @@ direct_io_worker(int rw, struct kiocb *iocb, struct inode *inode,
spin_unlock_irqrestore(&dio->bio_lock, flags);
if (ret2 == 0) {
- ret = dio_complete(dio, offset, ret);
+ ret = dio_complete(dio, offset, ret, false);
kfree(dio);
} else
BUG_ON(ret != -EIOCBQUEUED);
diff --git a/fs/dlm/lowcomms.c b/fs/dlm/lowcomms.c
index c0d35c62052..37a34c2c622 100644
--- a/fs/dlm/lowcomms.c
+++ b/fs/dlm/lowcomms.c
@@ -248,7 +248,7 @@ static struct connection *assoc2con(int assoc_id)
for (i = 0 ; i < CONN_HASH_SIZE; i++) {
hlist_for_each_entry(con, h, &connection_hash[i], list) {
- if (con && con->sctp_assoc == assoc_id) {
+ if (con->sctp_assoc == assoc_id) {
mutex_unlock(&connections_lock);
return con;
}
diff --git a/fs/dlm/netlink.c b/fs/dlm/netlink.c
index 2c6ad518100..ef17e0169da 100644
--- a/fs/dlm/netlink.c
+++ b/fs/dlm/netlink.c
@@ -81,24 +81,11 @@ static struct genl_ops dlm_nl_ops = {
int __init dlm_netlink_init(void)
{
- int rv;
-
- rv = genl_register_family(&family);
- if (rv)
- return rv;
-
- rv = genl_register_ops(&family, &dlm_nl_ops);
- if (rv < 0)
- goto err;
- return 0;
- err:
- genl_unregister_family(&family);
- return rv;
+ return genl_register_family_with_ops(&family, &dlm_nl_ops, 1);
}
void dlm_netlink_exit(void)
{
- genl_unregister_ops(&family, &dlm_nl_ops);
genl_unregister_family(&family);
}
diff --git a/fs/ecryptfs/crypto.c b/fs/ecryptfs/crypto.c
index 1cc087635a5..a2e3b562e65 100644
--- a/fs/ecryptfs/crypto.c
+++ b/fs/ecryptfs/crypto.c
@@ -762,7 +762,7 @@ ecryptfs_decrypt_page_offset(struct ecryptfs_crypt_stat *crypt_stat,
/**
* ecryptfs_init_crypt_ctx
- * @crypt_stat: Uninitilized crypt stats structure
+ * @crypt_stat: Uninitialized crypt stats structure
*
* Initialize the crypto context.
*
diff --git a/fs/exec.c b/fs/exec.c
index e19de6a8033..dab85ecad68 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -28,7 +28,6 @@
#include <linux/mm.h>
#include <linux/stat.h>
#include <linux/fcntl.h>
-#include <linux/smp_lock.h>
#include <linux/swap.h>
#include <linux/string.h>
#include <linux/init.h>
@@ -653,6 +652,7 @@ int setup_arg_pages(struct linux_binprm *bprm,
else
stack_base = vma->vm_start - stack_expand;
#endif
+ current->mm->start_stack = bprm->p;
ret = expand_stack(vma, stack_base);
if (ret)
ret = -EFAULT;
@@ -1891,13 +1891,7 @@ void do_coredump(long signr, int exit_code, struct pt_regs *regs)
*/
clear_thread_flag(TIF_SIGPENDING);
- /*
- * lock_kernel() because format_corename() is controlled by sysctl, which
- * uses lock_kernel()
- */
- lock_kernel();
ispipe = format_corename(corename, signr);
- unlock_kernel();
if (ispipe) {
int dump_count;
diff --git a/fs/ext3/Kconfig b/fs/ext3/Kconfig
index 522b15498f4..e8c6ba0e4a3 100644
--- a/fs/ext3/Kconfig
+++ b/fs/ext3/Kconfig
@@ -31,6 +31,7 @@ config EXT3_FS
config EXT3_DEFAULTS_TO_ORDERED
bool "Default to 'data=ordered' in ext3"
depends on EXT3_FS
+ default y
help
The journal mode options for ext3 have different tradeoffs
between when data is guaranteed to be on disk and
diff --git a/fs/ext3/inode.c b/fs/ext3/inode.c
index 735f0190ec2..001eb0e2d48 100644
--- a/fs/ext3/inode.c
+++ b/fs/ext3/inode.c
@@ -1149,9 +1149,25 @@ static int walk_page_buffers( handle_t *handle,
static int do_journal_get_write_access(handle_t *handle,
struct buffer_head *bh)
{
+ int dirty = buffer_dirty(bh);
+ int ret;
+
if (!buffer_mapped(bh) || buffer_freed(bh))
return 0;
- return ext3_journal_get_write_access(handle, bh);
+ /*
+ * __block_prepare_write() could have dirtied some buffers. Clean
+ * the dirty bit as jbd2_journal_get_write_access() could complain
+ * otherwise about fs integrity issues. Setting of the dirty bit
+ * by __block_prepare_write() isn't a real problem here as we clear
+ * the bit before releasing a page lock and thus writeback cannot
+ * ever write the buffer.
+ */
+ if (dirty)
+ clear_buffer_dirty(bh);
+ ret = ext3_journal_get_write_access(handle, bh);
+ if (!ret && dirty)
+ ret = ext3_journal_dirty_metadata(handle, bh);
+ return ret;
}
/*
@@ -1625,10 +1641,7 @@ static int ext3_writeback_writepage(struct page *page,
goto out_fail;
}
- if (test_opt(inode->i_sb, NOBH) && ext3_should_writeback_data(inode))
- ret = nobh_writepage(page, ext3_get_block, wbc);
- else
- ret = block_write_full_page(page, ext3_get_block, wbc);
+ ret = block_write_full_page(page, ext3_get_block, wbc);
err = ext3_journal_stop(handle);
if (!ret)
@@ -1922,17 +1935,6 @@ static int ext3_block_truncate_page(handle_t *handle, struct page *page,
length = blocksize - (offset & (blocksize - 1));
iblock = index << (PAGE_CACHE_SHIFT - inode->i_sb->s_blocksize_bits);
- /*
- * For "nobh" option, we can only work if we don't need to
- * read-in the page - otherwise we create buffers to do the IO.
- */
- if (!page_has_buffers(page) && test_opt(inode->i_sb, NOBH) &&
- ext3_should_writeback_data(inode) && PageUptodate(page)) {
- zero_user(page, offset, length);
- set_page_dirty(page);
- goto unlock;
- }
-
if (!page_has_buffers(page))
create_empty_buffers(page, blocksize, 0);
@@ -2284,27 +2286,6 @@ static void ext3_free_branches(handle_t *handle, struct inode *inode,
depth);
/*
- * We've probably journalled the indirect block several
- * times during the truncate. But it's no longer
- * needed and we now drop it from the transaction via
- * journal_revoke().
- *
- * That's easy if it's exclusively part of this
- * transaction. But if it's part of the committing
- * transaction then journal_forget() will simply
- * brelse() it. That means that if the underlying
- * block is reallocated in ext3_get_block(),
- * unmap_underlying_metadata() will find this block
- * and will try to get rid of it. damn, damn.
- *
- * If this block has already been committed to the
- * journal, a revoke record will be written. And
- * revoke records must be emitted *before* clearing
- * this block's bit in the bitmaps.
- */
- ext3_forget(handle, 1, inode, bh, bh->b_blocknr);
-
- /*
* Everything below this this pointer has been
* released. Now let this top-of-subtree go.
*
@@ -2327,6 +2308,31 @@ static void ext3_free_branches(handle_t *handle, struct inode *inode,
truncate_restart_transaction(handle, inode);
}
+ /*
+ * We've probably journalled the indirect block several
+ * times during the truncate. But it's no longer
+ * needed and we now drop it from the transaction via
+ * journal_revoke().
+ *
+ * That's easy if it's exclusively part of this
+ * transaction. But if it's part of the committing
+ * transaction then journal_forget() will simply
+ * brelse() it. That means that if the underlying
+ * block is reallocated in ext3_get_block(),
+ * unmap_underlying_metadata() will find this block
+ * and will try to get rid of it. damn, damn. Thus
+ * we don't allow a block to be reallocated until
+ * a transaction freeing it has fully committed.
+ *
+ * We also have to make sure journal replay after a
+ * crash does not overwrite non-journaled data blocks
+ * with old metadata when the block got reallocated for
+ * data. Thus we have to store a revoke record for a
+ * block in the same transaction in which we free the
+ * block.
+ */
+ ext3_forget(handle, 1, inode, bh, bh->b_blocknr);
+
ext3_free_blocks(handle, inode, nr, 1);
if (parent_bh) {
diff --git a/fs/ext3/namei.c b/fs/ext3/namei.c
index ee184084ca4..2b35ddb70d6 100644
--- a/fs/ext3/namei.c
+++ b/fs/ext3/namei.c
@@ -1447,7 +1447,6 @@ static int ext3_add_entry (handle_t *handle, struct dentry *dentry,
struct inode *inode)
{
struct inode *dir = dentry->d_parent->d_inode;
- unsigned long offset;
struct buffer_head * bh;
struct ext3_dir_entry_2 *de;
struct super_block * sb;
@@ -1469,7 +1468,7 @@ static int ext3_add_entry (handle_t *handle, struct dentry *dentry,
ext3_mark_inode_dirty(handle, dir);
}
blocks = dir->i_size >> sb->s_blocksize_bits;
- for (block = 0, offset = 0; block < blocks; block++) {
+ for (block = 0; block < blocks; block++) {
bh = ext3_bread(handle, dir, block, 0, &retval);
if(!bh)
return retval;
diff --git a/fs/ext3/resize.c b/fs/ext3/resize.c
index 54351ac7cef..0ccd7b12b73 100644
--- a/fs/ext3/resize.c
+++ b/fs/ext3/resize.c
@@ -964,7 +964,6 @@ int ext3_group_extend(struct super_block *sb, struct ext3_super_block *es,
ext3_fsblk_t n_blocks_count)
{
ext3_fsblk_t o_blocks_count;
- unsigned long o_groups_count;
ext3_grpblk_t last;
ext3_grpblk_t add;
struct buffer_head * bh;
@@ -976,7 +975,6 @@ int ext3_group_extend(struct super_block *sb, struct ext3_super_block *es,
* yet: we're going to revalidate es->s_blocks_count after
* taking the s_resize_lock below. */
o_blocks_count = le32_to_cpu(es->s_blocks_count);
- o_groups_count = EXT3_SB(sb)->s_groups_count;
if (test_opt(sb, DEBUG))
printk(KERN_DEBUG "EXT3-fs: extending last group from "E3FSBLK" uto "E3FSBLK" blocks\n",
diff --git a/fs/ext3/super.c b/fs/ext3/super.c
index 6c953bb255e..9650a956fd0 100644
--- a/fs/ext3/super.c
+++ b/fs/ext3/super.c
@@ -661,9 +661,6 @@ static int ext3_show_options(struct seq_file *seq, struct vfsmount *vfs)
*/
seq_puts(seq, ",barrier=");
seq_puts(seq, test_opt(sb, BARRIER) ? "1" : "0");
- if (test_opt(sb, NOBH))
- seq_puts(seq, ",nobh");
-
seq_printf(seq, ",data=%s", data_mode_string(test_opt(sb, DATA_FLAGS)));
if (test_opt(sb, DATA_ERR_ABORT))
seq_puts(seq, ",data_err=abort");
@@ -1255,10 +1252,12 @@ set_qf_format:
*n_blocks_count = option;
break;
case Opt_nobh:
- set_opt(sbi->s_mount_opt, NOBH);
+ ext3_msg(sb, KERN_WARNING,
+ "warning: ignoring deprecated nobh option");
break;
case Opt_bh:
- clear_opt(sbi->s_mount_opt, NOBH);
+ ext3_msg(sb, KERN_WARNING,
+ "warning: ignoring deprecated bh option");
break;
default:
ext3_msg(sb, KERN_ERR,
@@ -2001,14 +2000,6 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent)
break;
}
- if (test_opt(sb, NOBH)) {
- if (!(test_opt(sb, DATA_FLAGS) == EXT3_MOUNT_WRITEBACK_DATA)) {
- ext3_msg(sb, KERN_WARNING,
- "warning: ignoring nobh option - "
- "it is supported only with writeback mode");
- clear_opt(sbi->s_mount_opt, NOBH);
- }
- }
/*
* The journal_load will have done any necessary log recovery,
* so we can safely mount the rest of the filesystem now.
diff --git a/fs/ext4/acl.c b/fs/ext4/acl.c
index feaf498feaa..5e2ed4504ea 100644
--- a/fs/ext4/acl.c
+++ b/fs/ext4/acl.c
@@ -204,6 +204,7 @@ ext4_set_acl(handle_t *handle, struct inode *inode, int type,
return error;
else {
inode->i_mode = mode;
+ inode->i_ctime = ext4_current_time(inode);
ext4_mark_inode_dirty(handle, inode);
if (error == 0)
acl = NULL;
diff --git a/fs/ext4/balloc.c b/fs/ext4/balloc.c
index 95b7594c76f..bd30799a43e 100644
--- a/fs/ext4/balloc.c
+++ b/fs/ext4/balloc.c
@@ -377,14 +377,11 @@ void ext4_add_groupblocks(handle_t *handle, struct super_block *sb,
ext4_grpblk_t bit;
unsigned int i;
struct ext4_group_desc *desc;
- struct ext4_super_block *es;
- struct ext4_sb_info *sbi;
+ struct ext4_sb_info *sbi = EXT4_SB(sb);
int err = 0, ret, blk_free_count;
ext4_grpblk_t blocks_freed;
struct ext4_group_info *grp;
- sbi = EXT4_SB(sb);
- es = sbi->s_es;
ext4_debug("Adding block(s) %llu-%llu\n", block, block + count - 1);
ext4_get_group_no_and_offset(sb, block, &block_group, &bit);
@@ -477,7 +474,6 @@ void ext4_add_groupblocks(handle_t *handle, struct super_block *sb,
ret = ext4_handle_dirty_metadata(handle, NULL, gd_bh);
if (!err)
err = ret;
- sb->s_dirt = 1;
error_return:
brelse(bitmap_bh);
diff --git a/fs/ext4/block_validity.c b/fs/ext4/block_validity.c
index 5b6973fbf1b..3db5084db9b 100644
--- a/fs/ext4/block_validity.c
+++ b/fs/ext4/block_validity.c
@@ -229,16 +229,20 @@ int ext4_data_block_valid(struct ext4_sb_info *sbi, ext4_fsblk_t start_blk,
if ((start_blk <= le32_to_cpu(sbi->s_es->s_first_data_block)) ||
(start_blk + count < start_blk) ||
- (start_blk + count > ext4_blocks_count(sbi->s_es)))
+ (start_blk + count > ext4_blocks_count(sbi->s_es))) {
+ sbi->s_es->s_last_error_block = cpu_to_le64(start_blk);
return 0;
+ }
while (n) {
entry = rb_entry(n, struct ext4_system_zone, node);
if (start_blk + count - 1 < entry->start_blk)
n = n->rb_left;
else if (start_blk >= (entry->start_blk + entry->count))
n = n->rb_right;
- else
+ else {
+ sbi->s_es->s_last_error_block = cpu_to_le64(start_blk);
return 0;
+ }
}
return 1;
}
diff --git a/fs/ext4/dir.c b/fs/ext4/dir.c
index ea5e6cb7e2a..374510f72ba 100644
--- a/fs/ext4/dir.c
+++ b/fs/ext4/dir.c
@@ -61,10 +61,11 @@ static unsigned char get_dtype(struct super_block *sb, int filetype)
}
-int ext4_check_dir_entry(const char *function, struct inode *dir,
- struct ext4_dir_entry_2 *de,
- struct buffer_head *bh,
- unsigned int offset)
+int __ext4_check_dir_entry(const char *function, unsigned int line,
+ struct inode *dir,
+ struct ext4_dir_entry_2 *de,
+ struct buffer_head *bh,
+ unsigned int offset)
{
const char *error_msg = NULL;
const int rlen = ext4_rec_len_from_disk(de->rec_len,
@@ -83,11 +84,10 @@ int ext4_check_dir_entry(const char *function, struct inode *dir,
error_msg = "inode out of bounds";
if (error_msg != NULL)
- ext4_error_inode(function, dir,
- "bad entry in directory: %s - block=%llu"
+ ext4_error_inode(dir, function, line, bh->b_blocknr,
+ "bad entry in directory: %s - "
"offset=%u(%u), inode=%u, rec_len=%d, name_len=%d",
- error_msg, (unsigned long long) bh->b_blocknr,
- (unsigned) (offset%bh->b_size), offset,
+ error_msg, (unsigned) (offset%bh->b_size), offset,
le32_to_cpu(de->inode),
rlen, de->name_len);
return error_msg == NULL ? 1 : 0;
@@ -121,7 +121,8 @@ static int ext4_readdir(struct file *filp,
* We don't set the inode dirty flag since it's not
* critical that it get flushed back to the disk.
*/
- ext4_clear_inode_flag(filp->f_path.dentry->d_inode, EXT4_INODE_INDEX);
+ ext4_clear_inode_flag(filp->f_path.dentry->d_inode,
+ EXT4_INODE_INDEX);
}
stored = 0;
offset = filp->f_pos & (sb->s_blocksize - 1);
@@ -193,7 +194,7 @@ revalidate:
while (!error && filp->f_pos < inode->i_size
&& offset < sb->s_blocksize) {
de = (struct ext4_dir_entry_2 *) (bh->b_data + offset);
- if (!ext4_check_dir_entry("ext4_readdir", inode, de,
+ if (!ext4_check_dir_entry(inode, de,
bh, offset)) {
/*
* On error, skip the f_pos to the next block
@@ -343,7 +344,7 @@ int ext4_htree_store_dirent(struct file *dir_file, __u32 hash,
struct dir_private_info *info;
int len;
- info = (struct dir_private_info *) dir_file->private_data;
+ info = dir_file->private_data;
p = &info->root.rb_node;
/* Create and allocate the fname structure */
diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
index 19a4de57128..e03841d9f30 100644
--- a/fs/ext4/ext4.h
+++ b/fs/ext4/ext4.h
@@ -57,10 +57,13 @@
#endif
#define EXT4_ERROR_INODE(inode, fmt, a...) \
- ext4_error_inode(__func__, (inode), (fmt), ## a)
+ ext4_error_inode((inode), __func__, __LINE__, 0, (fmt), ## a)
+
+#define EXT4_ERROR_INODE_BLOCK(inode, block, fmt, a...) \
+ ext4_error_inode((inode), __func__, __LINE__, (block), (fmt), ## a)
#define EXT4_ERROR_FILE(file, fmt, a...) \
- ext4_error_file(__func__, (file), (fmt), ## a)
+ ext4_error_file(__func__, __LINE__, (file), (fmt), ## a)
/* data type for block offset of block group */
typedef int ext4_grpblk_t;
@@ -167,13 +170,15 @@ struct mpage_da_data {
};
#define EXT4_IO_UNWRITTEN 0x1
typedef struct ext4_io_end {
- struct list_head list; /* per-file finished AIO list */
+ struct list_head list; /* per-file finished IO list */
struct inode *inode; /* file being written to */
unsigned int flag; /* unwritten or not */
struct page *page; /* page struct for buffer write */
loff_t offset; /* offset in the file */
ssize_t size; /* size of the extent */
struct work_struct work; /* data work queue */
+ struct kiocb *iocb; /* iocb struct for AIO */
+ int result; /* error value for AIO */
} ext4_io_end_t;
/*
@@ -460,7 +465,7 @@ struct ext4_new_group_data {
};
/*
- * Flags used by ext4_get_blocks()
+ * Flags used by ext4_map_blocks()
*/
/* Allocate any needed blocks and/or convert an unitialized
extent to be an initialized ext4 */
@@ -873,7 +878,6 @@ struct ext4_inode_info {
#define EXT4_MOUNT_POSIX_ACL 0x08000 /* POSIX Access Control Lists */
#define EXT4_MOUNT_NO_AUTO_DA_ALLOC 0x10000 /* No auto delalloc mapping */
#define EXT4_MOUNT_BARRIER 0x20000 /* Use block barriers */
-#define EXT4_MOUNT_NOBH 0x40000 /* No bufferheads */
#define EXT4_MOUNT_QUOTA 0x80000 /* Some quota option set */
#define EXT4_MOUNT_USRQUOTA 0x100000 /* "old" user quota */
#define EXT4_MOUNT_GRPQUOTA 0x200000 /* "old" group quota */
@@ -982,7 +986,7 @@ struct ext4_super_block {
__le32 s_last_orphan; /* start of list of inodes to delete */
__le32 s_hash_seed[4]; /* HTREE hash seed */
__u8 s_def_hash_version; /* Default hash version to use */
- __u8 s_reserved_char_pad;
+ __u8 s_jnl_backup_type;
__le16 s_desc_size; /* size of group descriptor */
/*100*/ __le32 s_default_mount_opts;
__le32 s_first_meta_bg; /* First metablock block group */
@@ -1000,12 +1004,34 @@ struct ext4_super_block {
__le64 s_mmp_block; /* Block for multi-mount protection */
__le32 s_raid_stripe_width; /* blocks on all data disks (N*stride)*/
__u8 s_log_groups_per_flex; /* FLEX_BG group size */
- __u8 s_reserved_char_pad2;
+ __u8 s_reserved_char_pad;
__le16 s_reserved_pad;
__le64 s_kbytes_written; /* nr of lifetime kilobytes written */
- __u32 s_reserved[160]; /* Padding to the end of the block */
+ __le32 s_snapshot_inum; /* Inode number of active snapshot */
+ __le32 s_snapshot_id; /* sequential ID of active snapshot */
+ __le64 s_snapshot_r_blocks_count; /* reserved blocks for active
+ snapshot's future use */
+ __le32 s_snapshot_list; /* inode number of the head of the
+ on-disk snapshot list */
+#define EXT4_S_ERR_START offsetof(struct ext4_super_block, s_error_count)
+ __le32 s_error_count; /* number of fs errors */
+ __le32 s_first_error_time; /* first time an error happened */
+ __le32 s_first_error_ino; /* inode involved in first error */
+ __le64 s_first_error_block; /* block involved of first error */
+ __u8 s_first_error_func[32]; /* function where the error happened */
+ __le32 s_first_error_line; /* line number where error happened */
+ __le32 s_last_error_time; /* most recent time of an error */
+ __le32 s_last_error_ino; /* inode involved in last error */
+ __le32 s_last_error_line; /* line number where error happened */
+ __le64 s_last_error_block; /* block involved of last error */
+ __u8 s_last_error_func[32]; /* function where the error happened */
+#define EXT4_S_ERR_END offsetof(struct ext4_super_block, s_mount_opts)
+ __u8 s_mount_opts[64];
+ __le32 s_reserved[112]; /* Padding to the end of the block */
};
+#define EXT4_S_ERR_LEN (EXT4_S_ERR_END - EXT4_S_ERR_START)
+
#ifdef __KERNEL__
/*
@@ -1143,6 +1169,9 @@ struct ext4_sb_info {
/* workqueue for dio unwritten */
struct workqueue_struct *dio_unwritten_wq;
+
+ /* timer for periodic error stats printing */
+ struct timer_list s_err_report;
};
static inline struct ext4_sb_info *EXT4_SB(struct super_block *sb)
@@ -1313,6 +1342,10 @@ EXT4_INODE_BIT_FNS(state, state_flags)
#define EXT4_DEFM_JMODE_DATA 0x0020
#define EXT4_DEFM_JMODE_ORDERED 0x0040
#define EXT4_DEFM_JMODE_WBACK 0x0060
+#define EXT4_DEFM_NOBARRIER 0x0100
+#define EXT4_DEFM_BLOCK_VALIDITY 0x0200
+#define EXT4_DEFM_DISCARD 0x0400
+#define EXT4_DEFM_NODELALLOC 0x0800
/*
* Default journal batch times
@@ -1379,6 +1412,43 @@ struct ext4_dir_entry_2 {
#define EXT4_MAX_REC_LEN ((1<<16)-1)
/*
+ * If we ever get support for fs block sizes > page_size, we'll need
+ * to remove the #if statements in the next two functions...
+ */
+static inline unsigned int
+ext4_rec_len_from_disk(__le16 dlen, unsigned blocksize)
+{
+ unsigned len = le16_to_cpu(dlen);
+
+#if (PAGE_CACHE_SIZE >= 65536)
+ if (len == EXT4_MAX_REC_LEN || len == 0)
+ return blocksize;
+ return (len & 65532) | ((len & 3) << 16);
+#else
+ return len;
+#endif
+}
+
+static inline __le16 ext4_rec_len_to_disk(unsigned len, unsigned blocksize)
+{
+ if ((len > blocksize) || (blocksize > (1 << 18)) || (len & 3))
+ BUG();
+#if (PAGE_CACHE_SIZE >= 65536)
+ if (len < 65536)
+ return cpu_to_le16(len);
+ if (len == blocksize) {
+ if (blocksize == 65536)
+ return cpu_to_le16(EXT4_MAX_REC_LEN);
+ else
+ return cpu_to_le16(0);
+ }
+ return cpu_to_le16((len & 65532) | ((len >> 16) & 3));
+#else
+ return cpu_to_le16(len);
+#endif
+}
+
+/*
* Hash Tree Directory indexing
* (c) Daniel Phillips, 2001
*/
@@ -1510,9 +1580,11 @@ extern unsigned ext4_init_block_bitmap(struct super_block *sb,
ext4_init_block_bitmap(sb, NULL, group, desc)
/* dir.c */
-extern int ext4_check_dir_entry(const char *, struct inode *,
- struct ext4_dir_entry_2 *,
- struct buffer_head *, unsigned int);
+extern int __ext4_check_dir_entry(const char *, unsigned int, struct inode *,
+ struct ext4_dir_entry_2 *,
+ struct buffer_head *, unsigned int);
+#define ext4_check_dir_entry(dir, de, bh, offset) \
+ __ext4_check_dir_entry(__func__, __LINE__, (dir), (de), (bh), (offset))
extern int ext4_htree_store_dirent(struct file *dir_file, __u32 hash,
__u32 minor_hash,
struct ext4_dir_entry_2 *dirent);
@@ -1601,8 +1673,6 @@ extern long ext4_compat_ioctl(struct file *, unsigned int, unsigned long);
extern int ext4_ext_migrate(struct inode *);
/* namei.c */
-extern unsigned int ext4_rec_len_from_disk(__le16 dlen, unsigned blocksize);
-extern __le16 ext4_rec_len_to_disk(unsigned len, unsigned blocksize);
extern int ext4_orphan_add(handle_t *, struct inode *);
extern int ext4_orphan_del(handle_t *, struct inode *);
extern int ext4_htree_fill_tree(struct file *dir_file, __u32 start_hash,
@@ -1616,25 +1686,38 @@ extern int ext4_group_extend(struct super_block *sb,
ext4_fsblk_t n_blocks_count);
/* super.c */
-extern void __ext4_error(struct super_block *, const char *, const char *, ...)
- __attribute__ ((format (printf, 3, 4)));
-#define ext4_error(sb, message...) __ext4_error(sb, __func__, ## message)
-extern void ext4_error_inode(const char *, struct inode *, const char *, ...)
- __attribute__ ((format (printf, 3, 4)));
-extern void ext4_error_file(const char *, struct file *, const char *, ...)
- __attribute__ ((format (printf, 3, 4)));
-extern void __ext4_std_error(struct super_block *, const char *, int);
-extern void ext4_abort(struct super_block *, const char *, const char *, ...)
- __attribute__ ((format (printf, 3, 4)));
-extern void __ext4_warning(struct super_block *, const char *,
+extern void __ext4_error(struct super_block *, const char *, unsigned int,
+ const char *, ...)
+ __attribute__ ((format (printf, 4, 5)));
+#define ext4_error(sb, message...) __ext4_error(sb, __func__, \
+ __LINE__, ## message)
+extern void ext4_error_inode(struct inode *, const char *, unsigned int,
+ ext4_fsblk_t, const char *, ...)
+ __attribute__ ((format (printf, 5, 6)));
+extern void ext4_error_file(struct file *, const char *, unsigned int,
+ const char *, ...)
+ __attribute__ ((format (printf, 4, 5)));
+extern void __ext4_std_error(struct super_block *, const char *,
+ unsigned int, int);
+extern void __ext4_abort(struct super_block *, const char *, unsigned int,
+ const char *, ...)
+ __attribute__ ((format (printf, 4, 5)));
+#define ext4_abort(sb, message...) __ext4_abort(sb, __func__, \
+ __LINE__, ## message)
+extern void __ext4_warning(struct super_block *, const char *, unsigned int,
const char *, ...)
- __attribute__ ((format (printf, 3, 4)));
-#define ext4_warning(sb, message...) __ext4_warning(sb, __func__, ## message)
+ __attribute__ ((format (printf, 4, 5)));
+#define ext4_warning(sb, message...) __ext4_warning(sb, __func__, \
+ __LINE__, ## message)
extern void ext4_msg(struct super_block *, const char *, const char *, ...)
__attribute__ ((format (printf, 3, 4)));
-extern void ext4_grp_locked_error(struct super_block *, ext4_group_t,
- const char *, const char *, ...)
- __attribute__ ((format (printf, 4, 5)));
+extern void __ext4_grp_locked_error(const char *, unsigned int, \
+ struct super_block *, ext4_group_t, \
+ unsigned long, ext4_fsblk_t, \
+ const char *, ...)
+ __attribute__ ((format (printf, 7, 8)));
+#define ext4_grp_locked_error(sb, grp, message...) \
+ __ext4_grp_locked_error(__func__, __LINE__, (sb), (grp), ## message)
extern void ext4_update_dynamic_rev(struct super_block *sb);
extern int ext4_update_compat_feature(handle_t *handle, struct super_block *sb,
__u32 compat);
@@ -1768,7 +1851,7 @@ static inline unsigned int ext4_flex_bg_size(struct ext4_sb_info *sbi)
#define ext4_std_error(sb, errno) \
do { \
if ((errno)) \
- __ext4_std_error((sb), __func__, (errno)); \
+ __ext4_std_error((sb), __func__, __LINE__, (errno)); \
} while (0)
#ifdef CONFIG_SMP
@@ -1860,6 +1943,12 @@ static inline void ext4_unlock_group(struct super_block *sb,
spin_unlock(ext4_group_lock_ptr(sb, group));
}
+static inline void ext4_mark_super_dirty(struct super_block *sb)
+{
+ if (EXT4_SB(sb)->s_journal == NULL)
+ sb->s_dirt =1;
+}
+
/*
* Inodes and files operations
*/
@@ -1905,9 +1994,6 @@ extern int ext4_convert_unwritten_extents(struct inode *inode, loff_t offset,
ssize_t len);
extern int ext4_map_blocks(handle_t *handle, struct inode *inode,
struct ext4_map_blocks *map, int flags);
-extern int ext4_get_blocks(handle_t *handle, struct inode *inode,
- sector_t block, unsigned int max_blocks,
- struct buffer_head *bh, int flags);
extern int ext4_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
__u64 start, __u64 len);
/* move_extent.c */
diff --git a/fs/ext4/ext4_jbd2.c b/fs/ext4/ext4_jbd2.c
index 53d2764d71c..6e272ef6ba9 100644
--- a/fs/ext4/ext4_jbd2.c
+++ b/fs/ext4/ext4_jbd2.c
@@ -6,29 +6,29 @@
#include <trace/events/ext4.h>
-int __ext4_journal_get_undo_access(const char *where, handle_t *handle,
- struct buffer_head *bh)
+int __ext4_journal_get_undo_access(const char *where, unsigned int line,
+ handle_t *handle, struct buffer_head *bh)
{
int err = 0;
if (ext4_handle_valid(handle)) {
err = jbd2_journal_get_undo_access(handle, bh);
if (err)
- ext4_journal_abort_handle(where, __func__, bh,
+ ext4_journal_abort_handle(where, line, __func__, bh,
handle, err);
}
return err;
}
-int __ext4_journal_get_write_access(const char *where, handle_t *handle,
- struct buffer_head *bh)
+int __ext4_journal_get_write_access(const char *where, unsigned int line,
+ handle_t *handle, struct buffer_head *bh)
{
int err = 0;
if (ext4_handle_valid(handle)) {
err = jbd2_journal_get_write_access(handle, bh);
if (err)
- ext4_journal_abort_handle(where, __func__, bh,
+ ext4_journal_abort_handle(where, line, __func__, bh,
handle, err);
}
return err;
@@ -46,9 +46,9 @@ int __ext4_journal_get_write_access(const char *where, handle_t *handle,
* If the handle isn't valid we're not journaling, but we still need to
* call into ext4_journal_revoke() to put the buffer head.
*/
-int __ext4_forget(const char *where, handle_t *handle, int is_metadata,
- struct inode *inode, struct buffer_head *bh,
- ext4_fsblk_t blocknr)
+int __ext4_forget(const char *where, unsigned int line, handle_t *handle,
+ int is_metadata, struct inode *inode,
+ struct buffer_head *bh, ext4_fsblk_t blocknr)
{
int err;
@@ -79,8 +79,8 @@ int __ext4_forget(const char *where, handle_t *handle, int is_metadata,
BUFFER_TRACE(bh, "call jbd2_journal_forget");
err = jbd2_journal_forget(handle, bh);
if (err)
- ext4_journal_abort_handle(where, __func__, bh,
- handle, err);
+ ext4_journal_abort_handle(where, line, __func__,
+ bh, handle, err);
return err;
}
return 0;
@@ -92,15 +92,16 @@ int __ext4_forget(const char *where, handle_t *handle, int is_metadata,
BUFFER_TRACE(bh, "call jbd2_journal_revoke");
err = jbd2_journal_revoke(handle, blocknr, bh);
if (err) {
- ext4_journal_abort_handle(where, __func__, bh, handle, err);
- ext4_abort(inode->i_sb, __func__,
+ ext4_journal_abort_handle(where, line, __func__,
+ bh, handle, err);
+ __ext4_abort(inode->i_sb, where, line,
"error %d when attempting revoke", err);
}
BUFFER_TRACE(bh, "exit");
return err;
}
-int __ext4_journal_get_create_access(const char *where,
+int __ext4_journal_get_create_access(const char *where, unsigned int line,
handle_t *handle, struct buffer_head *bh)
{
int err = 0;
@@ -108,22 +109,23 @@ int __ext4_journal_get_create_access(const char *where,
if (ext4_handle_valid(handle)) {
err = jbd2_journal_get_create_access(handle, bh);
if (err)
- ext4_journal_abort_handle(where, __func__, bh,
- handle, err);
+ ext4_journal_abort_handle(where, line, __func__,
+ bh, handle, err);
}
return err;
}
-int __ext4_handle_dirty_metadata(const char *where, handle_t *handle,
- struct inode *inode, struct buffer_head *bh)
+int __ext4_handle_dirty_metadata(const char *where, unsigned int line,
+ handle_t *handle, struct inode *inode,
+ struct buffer_head *bh)
{
int err = 0;
if (ext4_handle_valid(handle)) {
err = jbd2_journal_dirty_metadata(handle, bh);
if (err)
- ext4_journal_abort_handle(where, __func__, bh,
- handle, err);
+ ext4_journal_abort_handle(where, line, __func__,
+ bh, handle, err);
} else {
if (inode)
mark_buffer_dirty_inode(bh, inode);
@@ -132,14 +134,33 @@ int __ext4_handle_dirty_metadata(const char *where, handle_t *handle,
if (inode && inode_needs_sync(inode)) {
sync_dirty_buffer(bh);
if (buffer_req(bh) && !buffer_uptodate(bh)) {
- ext4_error(inode->i_sb,
- "IO error syncing inode, "
- "inode=%lu, block=%llu",
- inode->i_ino,
- (unsigned long long) bh->b_blocknr);
+ struct ext4_super_block *es;
+
+ es = EXT4_SB(inode->i_sb)->s_es;
+ es->s_last_error_block =
+ cpu_to_le64(bh->b_blocknr);
+ ext4_error_inode(inode, where, line,
+ bh->b_blocknr,
+ "IO error syncing itable block");
err = -EIO;
}
}
}
return err;
}
+
+int __ext4_handle_dirty_super(const char *where, unsigned int line,
+ handle_t *handle, struct super_block *sb)
+{
+ struct buffer_head *bh = EXT4_SB(sb)->s_sbh;
+ int err = 0;
+
+ if (ext4_handle_valid(handle)) {
+ err = jbd2_journal_dirty_metadata(handle, bh);
+ if (err)
+ ext4_journal_abort_handle(where, line, __func__,
+ bh, handle, err);
+ } else
+ sb->s_dirt = 1;
+ return err;
+}
diff --git a/fs/ext4/ext4_jbd2.h b/fs/ext4/ext4_jbd2.h
index dade0c02479..b0bd792c58c 100644
--- a/fs/ext4/ext4_jbd2.h
+++ b/fs/ext4/ext4_jbd2.h
@@ -122,39 +122,47 @@ int ext4_mark_inode_dirty(handle_t *handle, struct inode *inode);
/*
* Wrapper functions with which ext4 calls into JBD.
*/
-void ext4_journal_abort_handle(const char *caller, const char *err_fn,
+void ext4_journal_abort_handle(const char *caller, unsigned int line,
+ const char *err_fn,
struct buffer_head *bh, handle_t *handle, int err);
-int __ext4_journal_get_undo_access(const char *where, handle_t *handle,
- struct buffer_head *bh);
+int __ext4_journal_get_undo_access(const char *where, unsigned int line,
+ handle_t *handle, struct buffer_head *bh);
-int __ext4_journal_get_write_access(const char *where, handle_t *handle,
- struct buffer_head *bh);
+int __ext4_journal_get_write_access(const char *where, unsigned int line,
+ handle_t *handle, struct buffer_head *bh);
-int __ext4_forget(const char *where, handle_t *handle, int is_metadata,
- struct inode *inode, struct buffer_head *bh,
- ext4_fsblk_t blocknr);
+int __ext4_forget(const char *where, unsigned int line, handle_t *handle,
+ int is_metadata, struct inode *inode,
+ struct buffer_head *bh, ext4_fsblk_t blocknr);
-int __ext4_journal_get_create_access(const char *where,
+int __ext4_journal_get_create_access(const char *where, unsigned int line,
handle_t *handle, struct buffer_head *bh);
-int __ext4_handle_dirty_metadata(const char *where, handle_t *handle,
- struct inode *inode, struct buffer_head *bh);
+int __ext4_handle_dirty_metadata(const char *where, unsigned int line,
+ handle_t *handle, struct inode *inode,
+ struct buffer_head *bh);
+
+int __ext4_handle_dirty_super(const char *where, unsigned int line,
+ handle_t *handle, struct super_block *sb);
#define ext4_journal_get_undo_access(handle, bh) \
- __ext4_journal_get_undo_access(__func__, (handle), (bh))
+ __ext4_journal_get_undo_access(__func__, __LINE__, (handle), (bh))
#define ext4_journal_get_write_access(handle, bh) \
- __ext4_journal_get_write_access(__func__, (handle), (bh))
+ __ext4_journal_get_write_access(__func__, __LINE__, (handle), (bh))
#define ext4_forget(handle, is_metadata, inode, bh, block_nr) \
- __ext4_forget(__func__, (handle), (is_metadata), (inode), (bh),\
- (block_nr))
+ __ext4_forget(__func__, __LINE__, (handle), (is_metadata), (inode), \
+ (bh), (block_nr))
#define ext4_journal_get_create_access(handle, bh) \
- __ext4_journal_get_create_access(__func__, (handle), (bh))
+ __ext4_journal_get_create_access(__func__, __LINE__, (handle), (bh))
#define ext4_handle_dirty_metadata(handle, inode, bh) \
- __ext4_handle_dirty_metadata(__func__, (handle), (inode), (bh))
+ __ext4_handle_dirty_metadata(__func__, __LINE__, (handle), (inode), \
+ (bh))
+#define ext4_handle_dirty_super(handle, sb) \
+ __ext4_handle_dirty_super(__func__, __LINE__, (handle), (sb))
handle_t *ext4_journal_start_sb(struct super_block *sb, int nblocks);
-int __ext4_journal_stop(const char *where, handle_t *handle);
+int __ext4_journal_stop(const char *where, unsigned int line, handle_t *handle);
#define EXT4_NOJOURNAL_MAX_REF_COUNT ((unsigned long) 4096)
@@ -207,7 +215,7 @@ static inline handle_t *ext4_journal_start(struct inode *inode, int nblocks)
}
#define ext4_journal_stop(handle) \
- __ext4_journal_stop(__func__, (handle))
+ __ext4_journal_stop(__func__, __LINE__, (handle))
static inline handle_t *ext4_journal_current_handle(void)
{
@@ -308,17 +316,15 @@ static inline int ext4_should_writeback_data(struct inode *inode)
* This function controls whether or not we should try to go down the
* dioread_nolock code paths, which makes it safe to avoid taking
* i_mutex for direct I/O reads. This only works for extent-based
- * files, and it doesn't work for nobh or if data journaling is
- * enabled, since the dioread_nolock code uses b_private to pass
- * information back to the I/O completion handler, and this conflicts
- * with the jbd's use of b_private.
+ * files, and it doesn't work if data journaling is enabled, since the
+ * dioread_nolock code uses b_private to pass information back to the
+ * I/O completion handler, and this conflicts with the jbd's use of
+ * b_private.
*/
static inline int ext4_should_dioread_nolock(struct inode *inode)
{
if (!test_opt(inode->i_sb, DIOREAD_NOLOCK))
return 0;
- if (test_opt(inode->i_sb, NOBH))
- return 0;
if (!S_ISREG(inode->i_mode))
return 0;
if (!(ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS)))
diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c
index 377309c1af6..06328d3e571 100644
--- a/fs/ext4/extents.c
+++ b/fs/ext4/extents.c
@@ -401,9 +401,9 @@ static int ext4_valid_extent_entries(struct inode *inode,
return 1;
}
-static int __ext4_ext_check(const char *function, struct inode *inode,
- struct ext4_extent_header *eh,
- int depth)
+static int __ext4_ext_check(const char *function, unsigned int line,
+ struct inode *inode, struct ext4_extent_header *eh,
+ int depth)
{
const char *error_msg;
int max = 0;
@@ -436,7 +436,7 @@ static int __ext4_ext_check(const char *function, struct inode *inode,
return 0;
corrupted:
- ext4_error_inode(function, inode,
+ ext4_error_inode(inode, function, line, 0,
"bad header/extent: %s - magic %x, "
"entries %u, max %u(%u), depth %u(%u)",
error_msg, le16_to_cpu(eh->eh_magic),
@@ -447,7 +447,7 @@ corrupted:
}
#define ext4_ext_check(inode, eh, depth) \
- __ext4_ext_check(__func__, inode, eh, depth)
+ __ext4_ext_check(__func__, __LINE__, inode, eh, depth)
int ext4_ext_check_inode(struct inode *inode)
{
@@ -1083,7 +1083,6 @@ static int ext4_ext_grow_indepth(handle_t *handle, struct inode *inode,
{
struct ext4_ext_path *curp = path;
struct ext4_extent_header *neh;
- struct ext4_extent_idx *fidx;
struct buffer_head *bh;
ext4_fsblk_t newblock;
int err = 0;
@@ -1144,10 +1143,10 @@ static int ext4_ext_grow_indepth(handle_t *handle, struct inode *inode,
ext4_idx_store_pblock(curp->p_idx, newblock);
neh = ext_inode_hdr(inode);
- fidx = EXT_FIRST_INDEX(neh);
ext_debug("new root: num %d(%d), lblock %d, ptr %llu\n",
le16_to_cpu(neh->eh_entries), le16_to_cpu(neh->eh_max),
- le32_to_cpu(fidx->ei_block), idx_pblock(fidx));
+ le32_to_cpu(EXT_FIRST_INDEX(neh)->ei_block),
+ idx_pblock(EXT_FIRST_INDEX(neh)));
neh->eh_depth = cpu_to_le16(path->p_depth + 1);
err = ext4_ext_dirty(handle, inode, curp);
@@ -2937,7 +2936,7 @@ fix_extent_len:
* One of more index blocks maybe needed if the extent tree grow after
* the unintialized extent split. To prevent ENOSPC occur at the IO
* complete, we need to split the uninitialized extent before DIO submit
- * the IO. The uninitilized extent called at this time will be split
+ * the IO. The uninitialized extent called at this time will be split
* into three uninitialized extent(at most). After IO complete, the part
* being filled will be convert to initialized by the end_io callback function
* via ext4_convert_unwritten_extents().
@@ -2954,7 +2953,6 @@ static int ext4_split_unwritten_extents(handle_t *handle,
struct ext4_extent *ex1 = NULL;
struct ext4_extent *ex2 = NULL;
struct ext4_extent *ex3 = NULL;
- struct ext4_extent_header *eh;
ext4_lblk_t ee_block, eof_block;
unsigned int allocated, ee_len, depth;
ext4_fsblk_t newblock;
@@ -2971,7 +2969,6 @@ static int ext4_split_unwritten_extents(handle_t *handle,
eof_block = map->m_lblk + map->m_len;
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);
@@ -3058,7 +3055,6 @@ static int ext4_split_unwritten_extents(handle_t *handle,
err = PTR_ERR(path);
goto out;
}
- eh = path[depth].p_hdr;
ex = path[depth].p_ext;
if (ex2 != &newex)
ex2 = ex;
diff --git a/fs/ext4/file.c b/fs/ext4/file.c
index 5313ae4cda2..ee92b66d455 100644
--- a/fs/ext4/file.c
+++ b/fs/ext4/file.c
@@ -70,7 +70,8 @@ ext4_file_write(struct kiocb *iocb, const struct iovec *iov,
struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb);
size_t length = iov_length(iov, nr_segs);
- if (pos > sbi->s_bitmap_maxbytes)
+ if ((pos > sbi->s_bitmap_maxbytes ||
+ (pos == sbi->s_bitmap_maxbytes && length > 0)))
return -EFBIG;
if (pos + length > sbi->s_bitmap_maxbytes) {
@@ -123,7 +124,7 @@ static int ext4_file_open(struct inode * inode, struct file * filp)
if (!IS_ERR(cp)) {
memcpy(sbi->s_es->s_last_mounted, cp,
sizeof(sbi->s_es->s_last_mounted));
- sb->s_dirt = 1;
+ ext4_mark_super_dirty(sb);
}
}
return dquot_file_open(inode, filp);
diff --git a/fs/ext4/ialloc.c b/fs/ext4/ialloc.c
index 25c4b3173fd..ac377505ed5 100644
--- a/fs/ext4/ialloc.c
+++ b/fs/ext4/ialloc.c
@@ -279,7 +279,7 @@ out:
err = ext4_handle_dirty_metadata(handle, NULL, bitmap_bh);
if (!fatal)
fatal = err;
- sb->s_dirt = 1;
+ ext4_mark_super_dirty(sb);
} else
ext4_error(sb, "bit already cleared for inode %lu", ino);
@@ -965,7 +965,7 @@ got:
percpu_counter_dec(&sbi->s_freeinodes_counter);
if (S_ISDIR(mode))
percpu_counter_inc(&sbi->s_dirs_counter);
- sb->s_dirt = 1;
+ ext4_mark_super_dirty(sb);
if (sbi->s_log_groups_per_flex) {
flex_group = ext4_flex_group(sbi, group);
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
index 42272d67955..a0ab3754d0d 100644
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@ -221,6 +221,7 @@ void ext4_delete_inode(struct inode *inode)
"couldn't extend journal (err %d)", err);
stop_handle:
ext4_journal_stop(handle);
+ ext4_orphan_del(NULL, inode);
goto no_delete;
}
}
@@ -337,9 +338,11 @@ static int ext4_block_to_path(struct inode *inode,
return n;
}
-static int __ext4_check_blockref(const char *function, struct inode *inode,
+static int __ext4_check_blockref(const char *function, unsigned int line,
+ struct inode *inode,
__le32 *p, unsigned int max)
{
+ struct ext4_super_block *es = EXT4_SB(inode->i_sb)->s_es;
__le32 *bref = p;
unsigned int blk;
@@ -348,8 +351,9 @@ static int __ext4_check_blockref(const char *function, struct inode *inode,
if (blk &&
unlikely(!ext4_data_block_valid(EXT4_SB(inode->i_sb),
blk, 1))) {
- ext4_error_inode(function, inode,
- "invalid block reference %u", blk);
+ es->s_last_error_block = cpu_to_le64(blk);
+ ext4_error_inode(inode, function, line, blk,
+ "invalid block");
return -EIO;
}
}
@@ -358,11 +362,13 @@ static int __ext4_check_blockref(const char *function, struct inode *inode,
#define ext4_check_indirect_blockref(inode, bh) \
- __ext4_check_blockref(__func__, inode, (__le32 *)(bh)->b_data, \
+ __ext4_check_blockref(__func__, __LINE__, inode, \
+ (__le32 *)(bh)->b_data, \
EXT4_ADDR_PER_BLOCK((inode)->i_sb))
#define ext4_check_inode_blockref(inode) \
- __ext4_check_blockref(__func__, inode, EXT4_I(inode)->i_data, \
+ __ext4_check_blockref(__func__, __LINE__, inode, \
+ EXT4_I(inode)->i_data, \
EXT4_NDIR_BLOCKS)
/**
@@ -1128,20 +1134,24 @@ void ext4_da_update_reserve_space(struct inode *inode,
ext4_discard_preallocations(inode);
}
-static int check_block_validity(struct inode *inode, const char *func,
+static int __check_block_validity(struct inode *inode, const char *func,
+ unsigned int line,
struct ext4_map_blocks *map)
{
if (!ext4_data_block_valid(EXT4_SB(inode->i_sb), map->m_pblk,
map->m_len)) {
- ext4_error_inode(func, inode,
- "lblock %lu mapped to illegal pblock %llu "
- "(length %d)", (unsigned long) map->m_lblk,
- map->m_pblk, map->m_len);
+ ext4_error_inode(inode, func, line, map->m_pblk,
+ "lblock %lu mapped to illegal pblock "
+ "(length %d)", (unsigned long) map->m_lblk,
+ map->m_len);
return -EIO;
}
return 0;
}
+#define check_block_validity(inode, map) \
+ __check_block_validity((inode), __func__, __LINE__, (map))
+
/*
* Return the number of contiguous dirty pages in a given inode
* starting at page frame idx.
@@ -1244,7 +1254,7 @@ int ext4_map_blocks(handle_t *handle, struct inode *inode,
up_read((&EXT4_I(inode)->i_data_sem));
if (retval > 0 && map->m_flags & EXT4_MAP_MAPPED) {
- int ret = check_block_validity(inode, __func__, map);
+ int ret = check_block_validity(inode, map);
if (ret != 0)
return ret;
}
@@ -1324,9 +1334,7 @@ int ext4_map_blocks(handle_t *handle, struct inode *inode,
up_write((&EXT4_I(inode)->i_data_sem));
if (retval > 0 && map->m_flags & EXT4_MAP_MAPPED) {
- int ret = check_block_validity(inode,
- "ext4_map_blocks_after_alloc",
- map);
+ int ret = check_block_validity(inode, map);
if (ret != 0)
return ret;
}
@@ -1519,9 +1527,25 @@ static int walk_page_buffers(handle_t *handle,
static int do_journal_get_write_access(handle_t *handle,
struct buffer_head *bh)
{
+ int dirty = buffer_dirty(bh);
+ int ret;
+
if (!buffer_mapped(bh) || buffer_freed(bh))
return 0;
- return ext4_journal_get_write_access(handle, bh);
+ /*
+ * __block_prepare_write() could have dirtied some buffers. Clean
+ * the dirty bit as jbd2_journal_get_write_access() could complain
+ * otherwise about fs integrity issues. Setting of the dirty bit
+ * by __block_prepare_write() isn't a real problem here as we clear
+ * the bit before releasing a page lock and thus writeback cannot
+ * ever write the buffer.
+ */
+ if (dirty)
+ clear_buffer_dirty(bh);
+ ret = ext4_journal_get_write_access(handle, bh);
+ if (!ret && dirty)
+ ret = ext4_handle_dirty_metadata(handle, NULL, bh);
+ return ret;
}
/*
@@ -2194,7 +2218,7 @@ static int mpage_da_map_blocks(struct mpage_da_data *mpd)
BUG_ON(!handle);
/*
- * Call ext4_get_blocks() to allocate any delayed allocation
+ * Call ext4_map_blocks() to allocate any delayed allocation
* blocks, or to convert an uninitialized extent to be
* initialized (in the case where we have written into
* one or more preallocated blocks).
@@ -2203,7 +2227,7 @@ static int mpage_da_map_blocks(struct mpage_da_data *mpd)
* indicate that we are on the delayed allocation path. This
* affects functions in many different parts of the allocation
* call path. This flag exists primarily because we don't
- * want to change *many* call functions, so ext4_get_blocks()
+ * want to change *many* call functions, so ext4_map_blocks()
* will set the magic i_delalloc_reserved_flag once the
* inode's allocation semaphore is taken.
*
@@ -2221,6 +2245,8 @@ static int mpage_da_map_blocks(struct mpage_da_data *mpd)
blks = ext4_map_blocks(handle, mpd->inode, &map, get_blocks_flags);
if (blks < 0) {
+ struct super_block *sb = mpd->inode->i_sb;
+
err = blks;
/*
* If get block returns with error we simply
@@ -2231,7 +2257,7 @@ static int mpage_da_map_blocks(struct mpage_da_data *mpd)
return 0;
if (err == -ENOSPC &&
- ext4_count_free_blocks(mpd->inode->i_sb)) {
+ ext4_count_free_blocks(sb)) {
mpd->retval = err;
return 0;
}
@@ -2243,16 +2269,17 @@ static int mpage_da_map_blocks(struct mpage_da_data *mpd)
* writepage and writepages will again try to write
* the same.
*/
- ext4_msg(mpd->inode->i_sb, KERN_CRIT,
- "delayed block allocation failed for inode %lu at "
- "logical offset %llu with max blocks %zd with "
- "error %d", mpd->inode->i_ino,
- (unsigned long long) next,
- mpd->b_size >> mpd->inode->i_blkbits, err);
- printk(KERN_CRIT "This should not happen!! "
- "Data will be lost\n");
- if (err == -ENOSPC) {
- ext4_print_free_blocks(mpd->inode);
+ if (!(EXT4_SB(sb)->s_mount_flags & EXT4_MF_FS_ABORTED)) {
+ ext4_msg(sb, KERN_CRIT,
+ "delayed block allocation failed for inode %lu "
+ "at logical offset %llu with max blocks %zd "
+ "with error %d", mpd->inode->i_ino,
+ (unsigned long long) next,
+ mpd->b_size >> mpd->inode->i_blkbits, err);
+ ext4_msg(sb, KERN_CRIT,
+ "This should not happen!! Data will be lost\n");
+ if (err == -ENOSPC)
+ ext4_print_free_blocks(mpd->inode);
}
/* invalidate all the pages */
ext4_da_block_invalidatepages(mpd, next,
@@ -2320,7 +2347,7 @@ static void mpage_add_bh_to_extent(struct mpage_da_data *mpd,
* XXX Don't go larger than mballoc is willing to allocate
* This is a stopgap solution. We eventually need to fold
* mpage_da_submit_io() into this function and then call
- * ext4_get_blocks() multiple times in a loop
+ * ext4_map_blocks() multiple times in a loop
*/
if (nrblocks >= 8*1024*1024/mpd->inode->i_sb->s_blocksize)
goto flush_it;
@@ -2553,18 +2580,16 @@ static int ext4_da_get_block_prep(struct inode *inode, sector_t iblock,
/*
* This function is used as a standard get_block_t calback function
* when there is no desire to allocate any blocks. It is used as a
- * callback function for block_prepare_write(), nobh_writepage(), and
- * block_write_full_page(). These functions should only try to map a
- * single block at a time.
+ * callback function for block_prepare_write() and block_write_full_page().
+ * These functions should only try to map a single block at a time.
*
* Since this function doesn't do block allocations even if the caller
* requests it by passing in create=1, it is critically important that
* any caller checks to make sure that any buffer heads are returned
* by this function are either all already mapped or marked for
- * delayed allocation before calling nobh_writepage() or
- * block_write_full_page(). Otherwise, b_blocknr could be left
- * unitialized, and the page write functions will be taken by
- * surprise.
+ * delayed allocation before calling block_write_full_page(). Otherwise,
+ * b_blocknr could be left unitialized, and the page write functions will
+ * be taken by surprise.
*/
static int noalloc_get_block_write(struct inode *inode, sector_t iblock,
struct buffer_head *bh_result, int create)
@@ -2749,9 +2774,7 @@ static int ext4_writepage(struct page *page,
return __ext4_journalled_writepage(page, len);
}
- if (test_opt(inode->i_sb, NOBH) && ext4_should_writeback_data(inode))
- ret = nobh_writepage(page, noalloc_get_block_write, wbc);
- else if (page_bufs && buffer_uninit(page_bufs)) {
+ if (page_bufs && buffer_uninit(page_bufs)) {
ext4_set_bh_endio(page_bufs, inode);
ret = block_write_full_page_endio(page, noalloc_get_block_write,
wbc, ext4_end_io_buffer_write);
@@ -3146,13 +3169,10 @@ static int ext4_da_write_begin(struct file *file, struct address_space *mapping,
int ret, retries = 0;
struct page *page;
pgoff_t index;
- unsigned from, to;
struct inode *inode = mapping->host;
handle_t *handle;
index = pos >> PAGE_CACHE_SHIFT;
- from = pos & (PAGE_CACHE_SIZE - 1);
- to = from + len;
if (ext4_nonda_switch(inode->i_sb)) {
*fsdata = (void *)FALL_BACK_TO_NONDELALLOC;
@@ -3668,6 +3688,8 @@ static int ext4_end_io_nolock(ext4_io_end_t *io)
return ret;
}
+ if (io->iocb)
+ aio_complete(io->iocb, io->result, 0);
/* clear the DIO AIO unwritten flag */
io->flag = 0;
return ret;
@@ -3767,6 +3789,8 @@ static ext4_io_end_t *ext4_init_io_end (struct inode *inode, gfp_t flags)
io->offset = 0;
io->size = 0;
io->page = NULL;
+ io->iocb = NULL;
+ io->result = 0;
INIT_WORK(&io->work, ext4_end_io_work);
INIT_LIST_HEAD(&io->list);
}
@@ -3775,7 +3799,8 @@ static ext4_io_end_t *ext4_init_io_end (struct inode *inode, gfp_t flags)
}
static void ext4_end_io_dio(struct kiocb *iocb, loff_t offset,
- ssize_t size, void *private)
+ ssize_t size, void *private, int ret,
+ bool is_async)
{
ext4_io_end_t *io_end = iocb->private;
struct workqueue_struct *wq;
@@ -3784,7 +3809,7 @@ static void ext4_end_io_dio(struct kiocb *iocb, loff_t offset,
/* if not async direct IO or dio with 0 bytes write, just return */
if (!io_end || !size)
- return;
+ goto out;
ext_debug("ext4_end_io_dio(): io_end 0x%p"
"for inode %lu, iocb 0x%p, offset %llu, size %llu\n",
@@ -3795,12 +3820,18 @@ static void ext4_end_io_dio(struct kiocb *iocb, loff_t offset,
if (io_end->flag != EXT4_IO_UNWRITTEN){
ext4_free_io_end(io_end);
iocb->private = NULL;
+out:
+ if (is_async)
+ aio_complete(iocb, ret, 0);
return;
}
io_end->offset = offset;
io_end->size = size;
- io_end->flag = EXT4_IO_UNWRITTEN;
+ if (is_async) {
+ io_end->iocb = iocb;
+ io_end->result = ret;
+ }
wq = EXT4_SB(io_end->inode->i_sb)->dio_unwritten_wq;
/* queue the work to convert unwritten extents to written */
@@ -3937,7 +3968,7 @@ static ssize_t ext4_ext_direct_IO(int rw, struct kiocb *iocb,
return -ENOMEM;
/*
* we save the io structure for current async
- * direct IO, so that later ext4_get_blocks()
+ * direct IO, so that later ext4_map_blocks()
* could flag the io structure whether there
* is a unwritten extents needs to be converted
* when IO is completed.
@@ -4128,17 +4159,6 @@ int ext4_block_truncate_page(handle_t *handle,
length = blocksize - (offset & (blocksize - 1));
iblock = index << (PAGE_CACHE_SHIFT - inode->i_sb->s_blocksize_bits);
- /*
- * For "nobh" option, we can only work if we don't need to
- * read-in the page - otherwise we create buffers to do the IO.
- */
- if (!page_has_buffers(page) && test_opt(inode->i_sb, NOBH) &&
- ext4_should_writeback_data(inode) && PageUptodate(page)) {
- zero_user(page, offset, length);
- set_page_dirty(page);
- goto unlock;
- }
-
if (!page_has_buffers(page))
create_empty_buffers(page, blocksize, 0);
@@ -4488,9 +4508,8 @@ static void ext4_free_branches(handle_t *handle, struct inode *inode,
* (should be rare).
*/
if (!bh) {
- EXT4_ERROR_INODE(inode,
- "Read failure block=%llu",
- (unsigned long long) nr);
+ EXT4_ERROR_INODE_BLOCK(inode, nr,
+ "Read failure");
continue;
}
@@ -4502,27 +4521,6 @@ static void ext4_free_branches(handle_t *handle, struct inode *inode,
depth);
/*
- * We've probably journalled the indirect block several
- * times during the truncate. But it's no longer
- * needed and we now drop it from the transaction via
- * jbd2_journal_revoke().
- *
- * That's easy if it's exclusively part of this
- * transaction. But if it's part of the committing
- * transaction then jbd2_journal_forget() will simply
- * brelse() it. That means that if the underlying
- * block is reallocated in ext4_get_block(),
- * unmap_underlying_metadata() will find this block
- * and will try to get rid of it. damn, damn.
- *
- * If this block has already been committed to the
- * journal, a revoke record will be written. And
- * revoke records must be emitted *before* clearing
- * this block's bit in the bitmaps.
- */
- ext4_forget(handle, 1, inode, bh, bh->b_blocknr);
-
- /*
* Everything below this this pointer has been
* released. Now let this top-of-subtree go.
*
@@ -4546,8 +4544,20 @@ static void ext4_free_branches(handle_t *handle, struct inode *inode,
blocks_for_truncate(inode));
}
+ /*
+ * The forget flag here is critical because if
+ * we are journaling (and not doing data
+ * journaling), we have to make sure a revoke
+ * record is written to prevent the journal
+ * replay from overwriting the (former)
+ * indirect block if it gets reallocated as a
+ * data block. This must happen in the same
+ * transaction where the data blocks are
+ * actually freed.
+ */
ext4_free_blocks(handle, inode, 0, nr, 1,
- EXT4_FREE_BLOCKS_METADATA);
+ EXT4_FREE_BLOCKS_METADATA|
+ EXT4_FREE_BLOCKS_FORGET);
if (parent_bh) {
/*
@@ -4805,8 +4815,8 @@ static int __ext4_get_inode_loc(struct inode *inode,
bh = sb_getblk(sb, block);
if (!bh) {
- EXT4_ERROR_INODE(inode, "unable to read inode block - "
- "block %llu", block);
+ EXT4_ERROR_INODE_BLOCK(inode, block,
+ "unable to read itable block");
return -EIO;
}
if (!buffer_uptodate(bh)) {
@@ -4904,8 +4914,8 @@ make_io:
submit_bh(READ_META, bh);
wait_on_buffer(bh);
if (!buffer_uptodate(bh)) {
- EXT4_ERROR_INODE(inode, "unable to read inode "
- "block %llu", block);
+ EXT4_ERROR_INODE_BLOCK(inode, block,
+ "unable to read itable block");
brelse(bh);
return -EIO;
}
@@ -4976,7 +4986,7 @@ static blkcnt_t ext4_inode_blocks(struct ext4_inode *raw_inode,
/* we are using combined 48 bit field */
i_blocks = ((u64)le16_to_cpu(raw_inode->i_blocks_high)) << 32 |
le32_to_cpu(raw_inode->i_blocks_lo);
- if (ei->i_flags & EXT4_HUGE_FILE_FL) {
+ if (ext4_test_inode_flag(inode, EXT4_INODE_HUGE_FILE)) {
/* i_blocks represent file system block size */
return i_blocks << (inode->i_blkbits - 9);
} else {
@@ -5072,7 +5082,7 @@ struct inode *ext4_iget(struct super_block *sb, unsigned long ino)
transaction_t *transaction;
tid_t tid;
- spin_lock(&journal->j_state_lock);
+ read_lock(&journal->j_state_lock);
if (journal->j_running_transaction)
transaction = journal->j_running_transaction;
else
@@ -5081,7 +5091,7 @@ struct inode *ext4_iget(struct super_block *sb, unsigned long ino)
tid = transaction->t_tid;
else
tid = journal->j_commit_sequence;
- spin_unlock(&journal->j_state_lock);
+ read_unlock(&journal->j_state_lock);
ei->i_sync_tid = tid;
ei->i_datasync_tid = tid;
}
@@ -5126,7 +5136,7 @@ struct inode *ext4_iget(struct super_block *sb, unsigned long ino)
ei->i_file_acl);
ret = -EIO;
goto bad_inode;
- } else if (ei->i_flags & EXT4_EXTENTS_FL) {
+ } else if (ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS)) {
if (S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
(S_ISLNK(inode->i_mode) &&
!ext4_inode_is_fast_symlink(inode)))
@@ -5406,9 +5416,8 @@ int ext4_write_inode(struct inode *inode, struct writeback_control *wbc)
if (wbc->sync_mode == WB_SYNC_ALL)
sync_dirty_buffer(iloc.bh);
if (buffer_req(iloc.bh) && !buffer_uptodate(iloc.bh)) {
- EXT4_ERROR_INODE(inode,
- "IO error syncing inode (block=%llu)",
- (unsigned long long) iloc.bh->b_blocknr);
+ EXT4_ERROR_INODE_BLOCK(inode, iloc.bh->b_blocknr,
+ "IO error syncing inode");
err = -EIO;
}
brelse(iloc.bh);
@@ -5483,10 +5492,8 @@ int ext4_setattr(struct dentry *dentry, struct iattr *attr)
if (!(ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS))) {
struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb);
- if (attr->ia_size > sbi->s_bitmap_maxbytes) {
- error = -EFBIG;
- goto err_out;
- }
+ if (attr->ia_size > sbi->s_bitmap_maxbytes)
+ return -EFBIG;
}
}
@@ -5688,7 +5695,7 @@ int ext4_writepage_trans_blocks(struct inode *inode)
* Calculate the journal credits for a chunk of data modification.
*
* This is called from DIO, fallocate or whoever calling
- * ext4_get_blocks() to map/allocate a chunk of contiguous disk blocks.
+ * ext4_map_blocks() to map/allocate a chunk of contiguous disk blocks.
*
* journal buffers for data blocks are not included here, as DIO
* and fallocate do no need to journal data buffers.
@@ -5754,7 +5761,6 @@ static int ext4_expand_extra_isize(struct inode *inode,
{
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;
@@ -5762,7 +5768,6 @@ static int ext4_expand_extra_isize(struct inode *inode,
raw_inode = ext4_raw_inode(&iloc);
header = IHDR(inode, raw_inode);
- entry = IFIRST(header);
/* No extended attributes present */
if (!ext4_test_inode_state(inode, EXT4_STATE_XATTR) ||
diff --git a/fs/ext4/mballoc.c b/fs/ext4/mballoc.c
index 12b3bc026a6..4b4ad4b7ce5 100644
--- a/fs/ext4/mballoc.c
+++ b/fs/ext4/mballoc.c
@@ -446,10 +446,11 @@ static void mb_free_blocks_double(struct inode *inode, struct ext4_buddy *e4b,
blocknr = ext4_group_first_block_no(sb, e4b->bd_group);
blocknr += first + i;
ext4_grp_locked_error(sb, e4b->bd_group,
- __func__, "double-free of inode"
- " %lu's block %llu(bit %u in group %u)",
- inode ? inode->i_ino : 0, blocknr,
- first + i, e4b->bd_group);
+ inode ? inode->i_ino : 0,
+ blocknr,
+ "freeing block already freed "
+ "(bit %u)",
+ first + i);
}
mb_clear_bit(first + i, e4b->bd_info->bb_bitmap);
}
@@ -712,9 +713,9 @@ void ext4_mb_generate_buddy(struct super_block *sb,
grp->bb_fragments = fragments;
if (free != grp->bb_free) {
- ext4_grp_locked_error(sb, group, __func__,
- "EXT4-fs: group %u: %u blocks in bitmap, %u in gd",
- group, free, grp->bb_free);
+ ext4_grp_locked_error(sb, group, 0, 0,
+ "%u blocks in bitmap, %u in gd",
+ free, grp->bb_free);
/*
* If we intent to continue, we consider group descritor
* corrupt and update bb_free using bitmap value
@@ -1296,10 +1297,10 @@ static void mb_free_blocks(struct inode *inode, struct ext4_buddy *e4b,
blocknr = ext4_group_first_block_no(sb, e4b->bd_group);
blocknr += block;
ext4_grp_locked_error(sb, e4b->bd_group,
- __func__, "double-free of inode"
- " %lu's block %llu(bit %u in group %u)",
- inode ? inode->i_ino : 0, blocknr, block,
- e4b->bd_group);
+ inode ? inode->i_ino : 0,
+ blocknr,
+ "freeing already freed block "
+ "(bit %u)", block);
}
mb_clear_bit(block, EXT4_MB_BITMAP(e4b));
e4b->bd_info->bb_counters[order]++;
@@ -1788,8 +1789,8 @@ void ext4_mb_complex_scan_group(struct ext4_allocation_context *ac,
* free blocks even though group info says we
* we have free blocks
*/
- ext4_grp_locked_error(sb, e4b->bd_group,
- __func__, "%d free blocks as per "
+ ext4_grp_locked_error(sb, e4b->bd_group, 0, 0,
+ "%d free blocks as per "
"group info. But bitmap says 0",
free);
break;
@@ -1798,8 +1799,8 @@ void ext4_mb_complex_scan_group(struct ext4_allocation_context *ac,
mb_find_extent(e4b, 0, i, ac->ac_g_ex.fe_len, &ex);
BUG_ON(ex.fe_len <= 0);
if (free < ex.fe_len) {
- ext4_grp_locked_error(sb, e4b->bd_group,
- __func__, "%d free blocks as per "
+ ext4_grp_locked_error(sb, e4b->bd_group, 0, 0,
+ "%d free blocks as per "
"group info. But got %d blocks",
free, ex.fe_len);
/*
@@ -1821,8 +1822,7 @@ void ext4_mb_complex_scan_group(struct ext4_allocation_context *ac,
/*
* This is a special case for storages like raid5
- * we try to find stripe-aligned chunks for stripe-size requests
- * XXX should do so at least for multiples of stripe size as well
+ * we try to find stripe-aligned chunks for stripe-size-multiple requests
*/
static noinline_for_stack
void ext4_mb_scan_aligned(struct ext4_allocation_context *ac,
@@ -1999,7 +1999,6 @@ ext4_mb_regular_allocator(struct ext4_allocation_context *ac)
ext4_group_t ngroups, group, i;
int cr;
int err = 0;
- int bsbits;
struct ext4_sb_info *sbi;
struct super_block *sb;
struct ext4_buddy e4b;
@@ -2041,8 +2040,6 @@ ext4_mb_regular_allocator(struct ext4_allocation_context *ac)
ac->ac_2order = i - 1;
}
- bsbits = ac->ac_sb->s_blocksize_bits;
-
/* if stream allocation is enabled, use global goal */
if (ac->ac_flags & EXT4_MB_STREAM_ALLOC) {
/* TBD: may be hot point */
@@ -2094,8 +2091,8 @@ repeat:
ac->ac_groups_scanned++;
if (cr == 0)
ext4_mb_simple_scan_group(ac, &e4b);
- else if (cr == 1 &&
- ac->ac_g_ex.fe_len == sbi->s_stripe)
+ else if (cr == 1 && sbi->s_stripe &&
+ !(ac->ac_g_ex.fe_len % sbi->s_stripe))
ext4_mb_scan_aligned(ac, &e4b);
else
ext4_mb_complex_scan_group(ac, &e4b);
@@ -2221,7 +2218,7 @@ static int ext4_mb_seq_groups_open(struct inode *inode, struct file *file)
rc = seq_open(file, &ext4_mb_seq_groups_ops);
if (rc == 0) {
- struct seq_file *m = (struct seq_file *)file->private_data;
+ struct seq_file *m = file->private_data;
m->private = sb;
}
return rc;
@@ -2560,6 +2557,22 @@ int ext4_mb_release(struct super_block *sb)
return 0;
}
+static inline void ext4_issue_discard(struct super_block *sb,
+ ext4_group_t block_group, ext4_grpblk_t block, int count)
+{
+ int ret;
+ ext4_fsblk_t discard_block;
+
+ discard_block = block + ext4_group_first_block_no(sb, block_group);
+ trace_ext4_discard_blocks(sb,
+ (unsigned long long) discard_block, count);
+ ret = sb_issue_discard(sb, discard_block, count);
+ if (ret == EOPNOTSUPP) {
+ ext4_warning(sb, "discard not supported, disabling");
+ clear_opt(EXT4_SB(sb)->s_mount_opt, DISCARD);
+ }
+}
+
/*
* This function is called by the jbd2 layer once the commit has finished,
* so we know we can free the blocks that were released with that commit.
@@ -2579,22 +2592,9 @@ static void release_blocks_on_commit(journal_t *journal, transaction_t *txn)
mb_debug(1, "gonna free %u blocks in group %u (0x%p):",
entry->count, entry->group, entry);
- if (test_opt(sb, DISCARD)) {
- int ret;
- ext4_fsblk_t discard_block;
-
- discard_block = entry->start_blk +
- ext4_group_first_block_no(sb, entry->group);
- trace_ext4_discard_blocks(sb,
- (unsigned long long)discard_block,
- entry->count);
- ret = sb_issue_discard(sb, discard_block, entry->count);
- if (ret == EOPNOTSUPP) {
- ext4_warning(sb,
- "discard not supported, disabling");
- clear_opt(EXT4_SB(sb)->s_mount_opt, DISCARD);
- }
- }
+ if (test_opt(sb, DISCARD))
+ ext4_issue_discard(sb, entry->group,
+ entry->start_blk, entry->count);
err = ext4_mb_load_buddy(sb, entry->group, &e4b);
/* we expect to find existing buddy because it's pinned */
@@ -2704,7 +2704,7 @@ void exit_ext4_mballoc(void)
/*
- * Check quota and mark choosed space (ac->ac_b_ex) non-free in bitmaps
+ * Check quota and mark chosen space (ac->ac_b_ex) non-free in bitmaps
* Returns 0 if success or error code
*/
static noinline_for_stack int
@@ -2712,7 +2712,6 @@ ext4_mb_mark_diskspace_used(struct ext4_allocation_context *ac,
handle_t *handle, unsigned int reserv_blks)
{
struct buffer_head *bitmap_bh = NULL;
- struct ext4_super_block *es;
struct ext4_group_desc *gdp;
struct buffer_head *gdp_bh;
struct ext4_sb_info *sbi;
@@ -2725,8 +2724,6 @@ ext4_mb_mark_diskspace_used(struct ext4_allocation_context *ac,
sb = ac->ac_sb;
sbi = EXT4_SB(sb);
- es = sbi->s_es;
-
err = -EIO;
bitmap_bh = ext4_read_block_bitmap(sb, ac->ac_b_ex.fe_group);
@@ -2812,7 +2809,7 @@ ext4_mb_mark_diskspace_used(struct ext4_allocation_context *ac,
err = ext4_handle_dirty_metadata(handle, NULL, gdp_bh);
out_err:
- sb->s_dirt = 1;
+ ext4_mark_super_dirty(sb);
brelse(bitmap_bh);
return err;
}
@@ -2850,7 +2847,7 @@ ext4_mb_normalize_request(struct ext4_allocation_context *ac,
int bsbits, max;
ext4_lblk_t end;
loff_t size, orig_size, start_off;
- ext4_lblk_t start, orig_start;
+ ext4_lblk_t start;
struct ext4_inode_info *ei = EXT4_I(ac->ac_inode);
struct ext4_prealloc_space *pa;
@@ -2881,6 +2878,7 @@ ext4_mb_normalize_request(struct ext4_allocation_context *ac,
size = size << bsbits;
if (size < i_size_read(ac->ac_inode))
size = i_size_read(ac->ac_inode);
+ orig_size = size;
/* max size of free chunks */
max = 2 << bsbits;
@@ -2922,8 +2920,8 @@ ext4_mb_normalize_request(struct ext4_allocation_context *ac,
start_off = (loff_t)ac->ac_o_ex.fe_logical << bsbits;
size = ac->ac_o_ex.fe_len << bsbits;
}
- orig_size = size = size >> bsbits;
- orig_start = start = start_off >> bsbits;
+ size = size >> bsbits;
+ start = start_off >> bsbits;
/* don't cover already allocated blocks in selected range */
if (ar->pleft && start <= ar->lleft) {
@@ -3547,7 +3545,6 @@ ext4_mb_release_inode_pa(struct ext4_buddy *e4b, struct buffer_head *bitmap_bh,
ext4_group_t group;
ext4_grpblk_t bit;
unsigned long long grp_blk_start;
- sector_t start;
int err = 0;
int free = 0;
@@ -3567,10 +3564,9 @@ ext4_mb_release_inode_pa(struct ext4_buddy *e4b, struct buffer_head *bitmap_bh,
if (bit >= end)
break;
next = mb_find_next_bit(bitmap_bh->b_data, end, bit);
- start = ext4_group_first_block_no(sb, group) + bit;
mb_debug(1, " free preallocated %u/%u in group %u\n",
- (unsigned) start, (unsigned) next - bit,
- (unsigned) group);
+ (unsigned) ext4_group_first_block_no(sb, group) + bit,
+ (unsigned) next - bit, (unsigned) group);
free += next - bit;
if (ac) {
@@ -3581,7 +3577,7 @@ ext4_mb_release_inode_pa(struct ext4_buddy *e4b, struct buffer_head *bitmap_bh,
trace_ext4_mballoc_discard(ac);
}
- trace_ext4_mb_release_inode_pa(ac, pa, grp_blk_start + bit,
+ trace_ext4_mb_release_inode_pa(sb, ac, pa, grp_blk_start + bit,
next - bit);
mb_free_blocks(pa->pa_inode, e4b, bit, next - bit);
bit = next + 1;
@@ -3591,8 +3587,7 @@ ext4_mb_release_inode_pa(struct ext4_buddy *e4b, struct buffer_head *bitmap_bh,
pa, (unsigned long) pa->pa_lstart,
(unsigned long) pa->pa_pstart,
(unsigned long) pa->pa_len);
- ext4_grp_locked_error(sb, group,
- __func__, "free %u, pa_free %u",
+ ext4_grp_locked_error(sb, group, 0, 0, "free %u, pa_free %u",
free, pa->pa_free);
/*
* pa is already deleted so we use the value obtained
@@ -3613,7 +3608,7 @@ ext4_mb_release_group_pa(struct ext4_buddy *e4b,
ext4_group_t group;
ext4_grpblk_t bit;
- trace_ext4_mb_release_group_pa(ac, pa);
+ trace_ext4_mb_release_group_pa(sb, ac, pa);
BUG_ON(pa->pa_deleted == 0);
ext4_get_group_no_and_offset(sb, pa->pa_pstart, &group, &bit);
BUG_ON(group != e4b->bd_group && pa->pa_len != 0);
@@ -3889,6 +3884,9 @@ static void ext4_mb_show_ac(struct ext4_allocation_context *ac)
struct super_block *sb = ac->ac_sb;
ext4_group_t ngroups, i;
+ if (EXT4_SB(sb)->s_mount_flags & EXT4_MF_FS_ABORTED)
+ return;
+
printk(KERN_ERR "EXT4-fs: Can't allocate:"
" Allocation context details:\n");
printk(KERN_ERR "EXT4-fs: status %d flags %d\n",
@@ -4255,7 +4253,7 @@ static int ext4_mb_discard_preallocations(struct super_block *sb, int needed)
* to usual allocation
*/
ext4_fsblk_t ext4_mb_new_blocks(handle_t *handle,
- struct ext4_allocation_request *ar, int *errp)
+ struct ext4_allocation_request *ar, int *errp)
{
int freed;
struct ext4_allocation_context *ac = NULL;
@@ -4299,7 +4297,7 @@ ext4_fsblk_t ext4_mb_new_blocks(handle_t *handle,
inquota = ar->len;
if (ar->len == 0) {
*errp = -EDQUOT;
- goto out3;
+ goto out;
}
}
@@ -4307,13 +4305,13 @@ ext4_fsblk_t ext4_mb_new_blocks(handle_t *handle,
if (!ac) {
ar->len = 0;
*errp = -ENOMEM;
- goto out1;
+ goto out;
}
*errp = ext4_mb_initialize_context(ac, ar);
if (*errp) {
ar->len = 0;
- goto out2;
+ goto out;
}
ac->ac_op = EXT4_MB_HISTORY_PREALLOC;
@@ -4322,7 +4320,9 @@ ext4_fsblk_t ext4_mb_new_blocks(handle_t *handle,
ext4_mb_normalize_request(ac, ar);
repeat:
/* allocate space in core */
- ext4_mb_regular_allocator(ac);
+ *errp = ext4_mb_regular_allocator(ac);
+ if (*errp)
+ goto errout;
/* as we've just preallocated more space than
* user requested orinally, we store allocated
@@ -4333,7 +4333,7 @@ repeat:
}
if (likely(ac->ac_status == AC_STATUS_FOUND)) {
*errp = ext4_mb_mark_diskspace_used(ac, handle, reserv_blks);
- if (*errp == -EAGAIN) {
+ if (*errp == -EAGAIN) {
/*
* drop the reference that we took
* in ext4_mb_use_best_found
@@ -4344,12 +4344,10 @@ repeat:
ac->ac_b_ex.fe_len = 0;
ac->ac_status = AC_STATUS_CONTINUE;
goto repeat;
- } else if (*errp) {
+ } else if (*errp)
+ errout:
ext4_discard_allocated_blocks(ac);
- ac->ac_b_ex.fe_len = 0;
- ar->len = 0;
- ext4_mb_show_ac(ac);
- } else {
+ else {
block = ext4_grp_offs_to_block(sb, &ac->ac_b_ex);
ar->len = ac->ac_b_ex.fe_len;
}
@@ -4358,19 +4356,19 @@ repeat:
if (freed)
goto repeat;
*errp = -ENOSPC;
+ }
+
+ if (*errp) {
ac->ac_b_ex.fe_len = 0;
ar->len = 0;
ext4_mb_show_ac(ac);
}
-
ext4_mb_release_context(ac);
-
-out2:
- kmem_cache_free(ext4_ac_cachep, ac);
-out1:
+out:
+ if (ac)
+ kmem_cache_free(ext4_ac_cachep, ac);
if (inquota && ar->len < inquota)
dquot_free_block(ar->inode, inquota - ar->len);
-out3:
if (!ar->len) {
if (!EXT4_I(ar->inode)->i_delalloc_reserved_flag)
/* release all the reserved blocks if non delalloc */
@@ -4402,6 +4400,7 @@ static noinline_for_stack int
ext4_mb_free_metadata(handle_t *handle, struct ext4_buddy *e4b,
struct ext4_free_data *new_entry)
{
+ ext4_group_t group = e4b->bd_group;
ext4_grpblk_t block;
struct ext4_free_data *entry;
struct ext4_group_info *db = e4b->bd_info;
@@ -4434,9 +4433,9 @@ ext4_mb_free_metadata(handle_t *handle, struct ext4_buddy *e4b,
else if (block >= (entry->start_blk + entry->count))
n = &(*n)->rb_right;
else {
- ext4_grp_locked_error(sb, e4b->bd_group, __func__,
- "Double free of blocks %d (%d %d)",
- block, entry->start_blk, entry->count);
+ ext4_grp_locked_error(sb, group, 0,
+ ext4_group_first_block_no(sb, group) + block,
+ "Block already on to-be-freed list");
return 0;
}
}
@@ -4494,7 +4493,6 @@ void ext4_free_blocks(handle_t *handle, struct inode *inode,
struct super_block *sb = inode->i_sb;
struct ext4_allocation_context *ac = NULL;
struct ext4_group_desc *gdp;
- struct ext4_super_block *es;
unsigned long freed = 0;
unsigned int overflow;
ext4_grpblk_t bit;
@@ -4513,7 +4511,6 @@ void ext4_free_blocks(handle_t *handle, struct inode *inode,
}
sbi = EXT4_SB(sb);
- es = EXT4_SB(sb)->s_es;
if (!(flags & EXT4_FREE_BLOCKS_VALIDATED) &&
!ext4_data_block_valid(sbi, block, count)) {
ext4_error(sb, "Freeing blocks not in datazone - "
@@ -4647,6 +4644,8 @@ do_more:
mb_clear_bits(bitmap_bh->b_data, bit, count);
mb_free_blocks(inode, &e4b, bit, count);
ext4_mb_return_to_preallocation(inode, &e4b, block, count);
+ if (test_opt(sb, DISCARD))
+ ext4_issue_discard(sb, block_group, bit, count);
}
ret = ext4_free_blks_count(sb, gdp) + count;
@@ -4680,7 +4679,7 @@ do_more:
put_bh(bitmap_bh);
goto do_more;
}
- sb->s_dirt = 1;
+ ext4_mark_super_dirty(sb);
error_return:
if (freed)
dquot_free_block(inode, freed);
diff --git a/fs/ext4/migrate.c b/fs/ext4/migrate.c
index 6f3a27ec30b..1765c2c50a9 100644
--- a/fs/ext4/migrate.c
+++ b/fs/ext4/migrate.c
@@ -376,7 +376,7 @@ static int ext4_ext_swap_inode_data(handle_t *handle, struct inode *inode,
* We have the extent map build with the tmp inode.
* Now copy the i_data across
*/
- ei->i_flags |= EXT4_EXTENTS_FL;
+ ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS);
memcpy(ei->i_data, tmp_ei->i_data, sizeof(ei->i_data));
/*
diff --git a/fs/ext4/move_extent.c b/fs/ext4/move_extent.c
index 52abfa12762..5f1ed9fc913 100644
--- a/fs/ext4/move_extent.c
+++ b/fs/ext4/move_extent.c
@@ -148,17 +148,17 @@ mext_next_extent(struct inode *inode, struct ext4_ext_path *path,
*/
static int
mext_check_null_inode(struct inode *inode1, struct inode *inode2,
- const char *function)
+ const char *function, unsigned int line)
{
int ret = 0;
if (inode1 == NULL) {
- __ext4_error(inode2->i_sb, function,
+ __ext4_error(inode2->i_sb, function, line,
"Both inodes should not be NULL: "
"inode1 NULL inode2 %lu", inode2->i_ino);
ret = -EIO;
} else if (inode2 == NULL) {
- __ext4_error(inode1->i_sb, function,
+ __ext4_error(inode1->i_sb, function, line,
"Both inodes should not be NULL: "
"inode1 %lu inode2 NULL", inode1->i_ino);
ret = -EIO;
@@ -1084,7 +1084,7 @@ mext_inode_double_lock(struct inode *inode1, struct inode *inode2)
BUG_ON(inode1 == NULL && inode2 == NULL);
- ret = mext_check_null_inode(inode1, inode2, __func__);
+ ret = mext_check_null_inode(inode1, inode2, __func__, __LINE__);
if (ret < 0)
goto out;
@@ -1121,7 +1121,7 @@ mext_inode_double_unlock(struct inode *inode1, struct inode *inode2)
BUG_ON(inode1 == NULL && inode2 == NULL);
- ret = mext_check_null_inode(inode1, inode2, __func__);
+ ret = mext_check_null_inode(inode1, inode2, __func__, __LINE__);
if (ret < 0)
goto out;
diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c
index a43e6617b35..314c0d3b3fa 100644
--- a/fs/ext4/namei.c
+++ b/fs/ext4/namei.c
@@ -179,30 +179,6 @@ static struct buffer_head * ext4_dx_find_entry(struct inode *dir,
static int ext4_dx_add_entry(handle_t *handle, struct dentry *dentry,
struct inode *inode);
-unsigned int ext4_rec_len_from_disk(__le16 dlen, unsigned blocksize)
-{
- unsigned len = le16_to_cpu(dlen);
-
- if (len == EXT4_MAX_REC_LEN || len == 0)
- return blocksize;
- return (len & 65532) | ((len & 3) << 16);
-}
-
-__le16 ext4_rec_len_to_disk(unsigned len, unsigned blocksize)
-{
- if ((len > blocksize) || (blocksize > (1 << 18)) || (len & 3))
- BUG();
- if (len < 65536)
- return cpu_to_le16(len);
- if (len == blocksize) {
- if (blocksize == 65536)
- return cpu_to_le16(EXT4_MAX_REC_LEN);
- else
- return cpu_to_le16(0);
- }
- return cpu_to_le16((len & 65532) | ((len >> 16) & 3));
-}
-
/*
* p is at least 6 bytes before the end of page
*/
@@ -605,7 +581,7 @@ static int htree_dirblock_to_tree(struct file *dir_file,
dir->i_sb->s_blocksize -
EXT4_DIR_REC_LEN(0));
for (; de < top; de = ext4_next_entry(de, dir->i_sb->s_blocksize)) {
- if (!ext4_check_dir_entry("htree_dirblock_to_tree", dir, de, bh,
+ if (!ext4_check_dir_entry(dir, de, bh,
(block<<EXT4_BLOCK_SIZE_BITS(dir->i_sb))
+((char *)de - bh->b_data))) {
/* On error, skip the f_pos to the next block. */
@@ -844,8 +820,7 @@ static inline int search_dirblock(struct buffer_head *bh,
if ((char *) de + namelen <= dlimit &&
ext4_match (namelen, name, de)) {
/* found a match - just to be sure, do a full check */
- if (!ext4_check_dir_entry("ext4_find_entry",
- dir, de, bh, offset))
+ if (!ext4_check_dir_entry(dir, de, bh, offset))
return -1;
*res_dir = de;
return 1;
@@ -1019,7 +994,7 @@ static struct buffer_head * ext4_dx_find_entry(struct inode *dir, const struct q
int off = (block << EXT4_BLOCK_SIZE_BITS(sb))
+ ((char *) de - bh->b_data);
- if (!ext4_check_dir_entry(__func__, dir, de, bh, off)) {
+ if (!ext4_check_dir_entry(dir, de, bh, off)) {
brelse(bh);
*err = ERR_BAD_DX_DIR;
goto errout;
@@ -1088,7 +1063,6 @@ static struct dentry *ext4_lookup(struct inode *dir, struct dentry *dentry, stru
struct dentry *ext4_get_parent(struct dentry *child)
{
__u32 ino;
- struct inode *inode;
static const struct qstr dotdot = {
.name = "..",
.len = 2,
@@ -1097,7 +1071,6 @@ struct dentry *ext4_get_parent(struct dentry *child)
struct buffer_head *bh;
bh = ext4_find_entry(child->d_inode, &dotdot, &de);
- inode = NULL;
if (!bh)
return ERR_PTR(-ENOENT);
ino = le32_to_cpu(de->inode);
@@ -1305,8 +1278,7 @@ static int add_dirent_to_buf(handle_t *handle, struct dentry *dentry,
de = (struct ext4_dir_entry_2 *)bh->b_data;
top = bh->b_data + blocksize - reclen;
while ((char *) de <= top) {
- if (!ext4_check_dir_entry("ext4_add_entry", dir, de,
- bh, offset))
+ if (!ext4_check_dir_entry(dir, de, bh, offset))
return -EIO;
if (ext4_match(namelen, name, de))
return -EEXIST;
@@ -1673,7 +1645,7 @@ static int ext4_delete_entry(handle_t *handle,
pde = NULL;
de = (struct ext4_dir_entry_2 *) bh->b_data;
while (i < bh->b_size) {
- if (!ext4_check_dir_entry("ext4_delete_entry", dir, de, bh, i))
+ if (!ext4_check_dir_entry(dir, de, bh, i))
return -EIO;
if (de == de_del) {
BUFFER_TRACE(bh, "get_write_access");
@@ -1956,7 +1928,7 @@ static int empty_dir(struct inode *inode)
}
de = (struct ext4_dir_entry_2 *) bh->b_data;
}
- if (!ext4_check_dir_entry("empty_dir", inode, de, bh, offset)) {
+ if (!ext4_check_dir_entry(inode, de, bh, offset)) {
de = (struct ext4_dir_entry_2 *)(bh->b_data +
sb->s_blocksize);
offset = (offset | (sb->s_blocksize - 1)) + 1;
diff --git a/fs/ext4/resize.c b/fs/ext4/resize.c
index 6df797eb9ae..ca5c8aa00a2 100644
--- a/fs/ext4/resize.c
+++ b/fs/ext4/resize.c
@@ -921,8 +921,7 @@ int ext4_group_add(struct super_block *sb, struct ext4_new_group_data *input)
&sbi->s_flex_groups[flex_group].free_inodes);
}
- ext4_handle_dirty_metadata(handle, NULL, sbi->s_sbh);
- sb->s_dirt = 1;
+ ext4_handle_dirty_super(handle, sb);
exit_journal:
mutex_unlock(&sbi->s_resize_lock);
@@ -953,7 +952,6 @@ int ext4_group_extend(struct super_block *sb, struct ext4_super_block *es,
ext4_fsblk_t n_blocks_count)
{
ext4_fsblk_t o_blocks_count;
- ext4_group_t o_groups_count;
ext4_grpblk_t last;
ext4_grpblk_t add;
struct buffer_head *bh;
@@ -965,7 +963,6 @@ int ext4_group_extend(struct super_block *sb, struct ext4_super_block *es,
* yet: we're going to revalidate es->s_blocks_count after
* taking the s_resize_lock below. */
o_blocks_count = ext4_blocks_count(es);
- o_groups_count = EXT4_SB(sb)->s_groups_count;
if (test_opt(sb, DEBUG))
printk(KERN_DEBUG "EXT4-fs: extending last group from %llu uto %llu blocks\n",
@@ -1045,13 +1042,12 @@ int ext4_group_extend(struct super_block *sb, struct ext4_super_block *es,
goto exit_put;
}
ext4_blocks_count_set(es, o_blocks_count + add);
- ext4_handle_dirty_metadata(handle, NULL, EXT4_SB(sb)->s_sbh);
- sb->s_dirt = 1;
mutex_unlock(&EXT4_SB(sb)->s_resize_lock);
ext4_debug("freeing blocks %llu through %llu\n", o_blocks_count,
o_blocks_count + add);
/* We add the blocks to the bitmap and set the group need init bit */
ext4_add_groupblocks(handle, sb, o_blocks_count, add);
+ ext4_handle_dirty_super(handle, sb);
ext4_debug("freed blocks %llu through %llu\n", o_blocks_count,
o_blocks_count + add);
if ((err = ext4_journal_stop(handle)))
diff --git a/fs/ext4/super.c b/fs/ext4/super.c
index 4e8983a9811..8d65575f8c8 100644
--- a/fs/ext4/super.c
+++ b/fs/ext4/super.c
@@ -241,14 +241,14 @@ handle_t *ext4_journal_start_sb(struct super_block *sb, int nblocks)
if (sb->s_flags & MS_RDONLY)
return ERR_PTR(-EROFS);
- vfs_check_frozen(sb, SB_FREEZE_WRITE);
+ vfs_check_frozen(sb, SB_FREEZE_TRANS);
/* Special case here: if the journal has aborted behind our
* backs (eg. EIO in the commit thread), then we still need to
* take the FS itself readonly cleanly. */
journal = EXT4_SB(sb)->s_journal;
if (journal) {
if (is_journal_aborted(journal)) {
- ext4_abort(sb, __func__, "Detected aborted journal");
+ ext4_abort(sb, "Detected aborted journal");
return ERR_PTR(-EROFS);
}
return jbd2_journal_start(journal, nblocks);
@@ -262,7 +262,7 @@ handle_t *ext4_journal_start_sb(struct super_block *sb, int nblocks)
* that sync() will call the filesystem's write_super callback if
* appropriate.
*/
-int __ext4_journal_stop(const char *where, handle_t *handle)
+int __ext4_journal_stop(const char *where, unsigned int line, handle_t *handle)
{
struct super_block *sb;
int err;
@@ -279,12 +279,13 @@ int __ext4_journal_stop(const char *where, handle_t *handle)
if (!err)
err = rc;
if (err)
- __ext4_std_error(sb, where, err);
+ __ext4_std_error(sb, where, line, err);
return err;
}
-void ext4_journal_abort_handle(const char *caller, const char *err_fn,
- struct buffer_head *bh, handle_t *handle, int err)
+void ext4_journal_abort_handle(const char *caller, unsigned int line,
+ const char *err_fn, struct buffer_head *bh,
+ handle_t *handle, int err)
{
char nbuf[16];
const char *errstr = ext4_decode_error(NULL, err, nbuf);
@@ -300,12 +301,47 @@ void ext4_journal_abort_handle(const char *caller, const char *err_fn,
if (is_handle_aborted(handle))
return;
- printk(KERN_ERR "%s: aborting transaction: %s in %s\n",
- caller, errstr, err_fn);
+ printk(KERN_ERR "%s:%d: aborting transaction: %s in %s\n",
+ caller, line, errstr, err_fn);
jbd2_journal_abort_handle(handle);
}
+static void __save_error_info(struct super_block *sb, const char *func,
+ unsigned int line)
+{
+ struct ext4_super_block *es = EXT4_SB(sb)->s_es;
+
+ EXT4_SB(sb)->s_mount_state |= EXT4_ERROR_FS;
+ es->s_state |= cpu_to_le16(EXT4_ERROR_FS);
+ es->s_last_error_time = cpu_to_le32(get_seconds());
+ strncpy(es->s_last_error_func, func, sizeof(es->s_last_error_func));
+ es->s_last_error_line = cpu_to_le32(line);
+ if (!es->s_first_error_time) {
+ es->s_first_error_time = es->s_last_error_time;
+ strncpy(es->s_first_error_func, func,
+ sizeof(es->s_first_error_func));
+ es->s_first_error_line = cpu_to_le32(line);
+ es->s_first_error_ino = es->s_last_error_ino;
+ es->s_first_error_block = es->s_last_error_block;
+ }
+ /*
+ * Start the daily error reporting function if it hasn't been
+ * started already
+ */
+ if (!es->s_error_count)
+ mod_timer(&EXT4_SB(sb)->s_err_report, jiffies + 24*60*60*HZ);
+ es->s_error_count = cpu_to_le32(le32_to_cpu(es->s_error_count) + 1);
+}
+
+static void save_error_info(struct super_block *sb, const char *func,
+ unsigned int line)
+{
+ __save_error_info(sb, func, line);
+ ext4_commit_super(sb, 1);
+}
+
+
/* Deal with the reporting of failure conditions on a filesystem such as
* inconsistencies detected or read IO failures.
*
@@ -323,11 +359,6 @@ void ext4_journal_abort_handle(const char *caller, const char *err_fn,
static void ext4_handle_error(struct super_block *sb)
{
- struct ext4_super_block *es = EXT4_SB(sb)->s_es;
-
- EXT4_SB(sb)->s_mount_state |= EXT4_ERROR_FS;
- es->s_state |= cpu_to_le16(EXT4_ERROR_FS);
-
if (sb->s_flags & MS_RDONLY)
return;
@@ -342,19 +373,19 @@ static void ext4_handle_error(struct super_block *sb)
ext4_msg(sb, KERN_CRIT, "Remounting filesystem read-only");
sb->s_flags |= MS_RDONLY;
}
- ext4_commit_super(sb, 1);
if (test_opt(sb, ERRORS_PANIC))
panic("EXT4-fs (device %s): panic forced after error\n",
sb->s_id);
}
void __ext4_error(struct super_block *sb, const char *function,
- const char *fmt, ...)
+ unsigned int line, const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
- printk(KERN_CRIT "EXT4-fs error (device %s): %s: ", sb->s_id, function);
+ printk(KERN_CRIT "EXT4-fs error (device %s): %s:%d: comm %s: ",
+ sb->s_id, function, line, current->comm);
vprintk(fmt, args);
printk("\n");
va_end(args);
@@ -362,14 +393,22 @@ void __ext4_error(struct super_block *sb, const char *function,
ext4_handle_error(sb);
}
-void ext4_error_inode(const char *function, struct inode *inode,
+void ext4_error_inode(struct inode *inode, const char *function,
+ unsigned int line, ext4_fsblk_t block,
const char *fmt, ...)
{
va_list args;
+ struct ext4_super_block *es = EXT4_SB(inode->i_sb)->s_es;
+ es->s_last_error_ino = cpu_to_le32(inode->i_ino);
+ es->s_last_error_block = cpu_to_le64(block);
+ save_error_info(inode->i_sb, function, line);
va_start(args, fmt);
- printk(KERN_CRIT "EXT4-fs error (device %s): %s: inode #%lu: (comm %s) ",
- inode->i_sb->s_id, function, inode->i_ino, current->comm);
+ printk(KERN_CRIT "EXT4-fs error (device %s): %s:%d: inode #%lu: ",
+ inode->i_sb->s_id, function, line, inode->i_ino);
+ if (block)
+ printk("block %llu: ", block);
+ printk("comm %s: ", current->comm);
vprintk(fmt, args);
printk("\n");
va_end(args);
@@ -377,20 +416,26 @@ void ext4_error_inode(const char *function, struct inode *inode,
ext4_handle_error(inode->i_sb);
}
-void ext4_error_file(const char *function, struct file *file,
- const char *fmt, ...)
+void ext4_error_file(struct file *file, const char *function,
+ unsigned int line, const char *fmt, ...)
{
va_list args;
+ struct ext4_super_block *es;
struct inode *inode = file->f_dentry->d_inode;
char pathname[80], *path;
+ es = EXT4_SB(inode->i_sb)->s_es;
+ es->s_last_error_ino = cpu_to_le32(inode->i_ino);
+ save_error_info(inode->i_sb, function, line);
va_start(args, fmt);
path = d_path(&(file->f_path), pathname, sizeof(pathname));
if (!path)
path = "(unknown)";
printk(KERN_CRIT
- "EXT4-fs error (device %s): %s: inode #%lu (comm %s path %s): ",
- inode->i_sb->s_id, function, inode->i_ino, current->comm, path);
+ "EXT4-fs error (device %s): %s:%d: inode #%lu "
+ "(comm %s path %s): ",
+ inode->i_sb->s_id, function, line, inode->i_ino,
+ current->comm, path);
vprintk(fmt, args);
printk("\n");
va_end(args);
@@ -435,7 +480,8 @@ static const char *ext4_decode_error(struct super_block *sb, int errno,
/* __ext4_std_error decodes expected errors from journaling functions
* automatically and invokes the appropriate error response. */
-void __ext4_std_error(struct super_block *sb, const char *function, int errno)
+void __ext4_std_error(struct super_block *sb, const char *function,
+ unsigned int line, int errno)
{
char nbuf[16];
const char *errstr;
@@ -448,8 +494,9 @@ void __ext4_std_error(struct super_block *sb, const char *function, int errno)
return;
errstr = ext4_decode_error(sb, errno, nbuf);
- printk(KERN_CRIT "EXT4-fs error (device %s) in %s: %s\n",
- sb->s_id, function, errstr);
+ printk(KERN_CRIT "EXT4-fs error (device %s) in %s:%d: %s\n",
+ sb->s_id, function, line, errstr);
+ save_error_info(sb, function, line);
ext4_handle_error(sb);
}
@@ -464,29 +511,29 @@ void __ext4_std_error(struct super_block *sb, const char *function, int errno)
* case we take the easy way out and panic immediately.
*/
-void ext4_abort(struct super_block *sb, const char *function,
- const char *fmt, ...)
+void __ext4_abort(struct super_block *sb, const char *function,
+ unsigned int line, const char *fmt, ...)
{
va_list args;
+ save_error_info(sb, function, line);
va_start(args, fmt);
- printk(KERN_CRIT "EXT4-fs error (device %s): %s: ", sb->s_id, function);
+ printk(KERN_CRIT "EXT4-fs error (device %s): %s:%d: ", sb->s_id,
+ function, line);
vprintk(fmt, args);
printk("\n");
va_end(args);
+ if ((sb->s_flags & MS_RDONLY) == 0) {
+ ext4_msg(sb, KERN_CRIT, "Remounting filesystem read-only");
+ sb->s_flags |= MS_RDONLY;
+ EXT4_SB(sb)->s_mount_flags |= EXT4_MF_FS_ABORTED;
+ if (EXT4_SB(sb)->s_journal)
+ jbd2_journal_abort(EXT4_SB(sb)->s_journal, -EIO);
+ save_error_info(sb, function, line);
+ }
if (test_opt(sb, ERRORS_PANIC))
panic("EXT4-fs panic from previous error\n");
-
- if (sb->s_flags & MS_RDONLY)
- return;
-
- ext4_msg(sb, KERN_CRIT, "Remounting filesystem read-only");
- EXT4_SB(sb)->s_mount_state |= EXT4_ERROR_FS;
- sb->s_flags |= MS_RDONLY;
- EXT4_SB(sb)->s_mount_flags |= EXT4_MF_FS_ABORTED;
- if (EXT4_SB(sb)->s_journal)
- jbd2_journal_abort(EXT4_SB(sb)->s_journal, -EIO);
}
void ext4_msg (struct super_block * sb, const char *prefix,
@@ -502,38 +549,47 @@ void ext4_msg (struct super_block * sb, const char *prefix,
}
void __ext4_warning(struct super_block *sb, const char *function,
- const char *fmt, ...)
+ unsigned int line, const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
- printk(KERN_WARNING "EXT4-fs warning (device %s): %s: ",
- sb->s_id, function);
+ printk(KERN_WARNING "EXT4-fs warning (device %s): %s:%d: ",
+ sb->s_id, function, line);
vprintk(fmt, args);
printk("\n");
va_end(args);
}
-void ext4_grp_locked_error(struct super_block *sb, ext4_group_t grp,
- const char *function, const char *fmt, ...)
+void __ext4_grp_locked_error(const char *function, unsigned int line,
+ struct super_block *sb, ext4_group_t grp,
+ unsigned long ino, ext4_fsblk_t block,
+ const char *fmt, ...)
__releases(bitlock)
__acquires(bitlock)
{
va_list args;
struct ext4_super_block *es = EXT4_SB(sb)->s_es;
+ es->s_last_error_ino = cpu_to_le32(ino);
+ es->s_last_error_block = cpu_to_le64(block);
+ __save_error_info(sb, function, line);
va_start(args, fmt);
- printk(KERN_CRIT "EXT4-fs error (device %s): %s: ", sb->s_id, function);
+ printk(KERN_CRIT "EXT4-fs error (device %s): %s:%d: group %u",
+ sb->s_id, function, line, grp);
+ if (ino)
+ printk("inode %lu: ", ino);
+ if (block)
+ printk("block %llu:", (unsigned long long) block);
vprintk(fmt, args);
printk("\n");
va_end(args);
if (test_opt(sb, ERRORS_CONT)) {
- EXT4_SB(sb)->s_mount_state |= EXT4_ERROR_FS;
- es->s_state |= cpu_to_le16(EXT4_ERROR_FS);
ext4_commit_super(sb, 0);
return;
}
+
ext4_unlock_group(sb, grp);
ext4_handle_error(sb);
/*
@@ -660,8 +716,7 @@ static void ext4_put_super(struct super_block *sb)
err = jbd2_journal_destroy(sbi->s_journal);
sbi->s_journal = NULL;
if (err < 0)
- ext4_abort(sb, __func__,
- "Couldn't clean up the journal");
+ ext4_abort(sb, "Couldn't clean up the journal");
}
ext4_release_system_zone(sb);
@@ -946,14 +1001,12 @@ static int ext4_show_options(struct seq_file *seq, struct vfsmount *vfs)
seq_puts(seq, ",journal_async_commit");
else if (test_opt(sb, JOURNAL_CHECKSUM))
seq_puts(seq, ",journal_checksum");
- if (test_opt(sb, NOBH))
- seq_puts(seq, ",nobh");
if (test_opt(sb, I_VERSION))
seq_puts(seq, ",i_version");
- if (!test_opt(sb, DELALLOC))
+ if (!test_opt(sb, DELALLOC) &&
+ !(def_mount_opts & EXT4_DEFM_NODELALLOC))
seq_puts(seq, ",nodelalloc");
-
if (sbi->s_stripe)
seq_printf(seq, ",stripe=%lu", sbi->s_stripe);
/*
@@ -977,7 +1030,7 @@ static int ext4_show_options(struct seq_file *seq, struct vfsmount *vfs)
if (test_opt(sb, NO_AUTO_DA_ALLOC))
seq_puts(seq, ",noauto_da_alloc");
- if (test_opt(sb, DISCARD))
+ if (test_opt(sb, DISCARD) && !(def_mount_opts & EXT4_DEFM_DISCARD))
seq_puts(seq, ",discard");
if (test_opt(sb, NOLOAD))
@@ -986,6 +1039,10 @@ static int ext4_show_options(struct seq_file *seq, struct vfsmount *vfs)
if (test_opt(sb, DIOREAD_NOLOCK))
seq_puts(seq, ",dioread_nolock");
+ if (test_opt(sb, BLOCK_VALIDITY) &&
+ !(def_mount_opts & EXT4_DEFM_BLOCK_VALIDITY))
+ seq_puts(seq, ",block_validity");
+
ext4_show_quota_options(seq, sb);
return 0;
@@ -1065,6 +1122,7 @@ static int ext4_mark_dquot_dirty(struct dquot *dquot);
static int ext4_write_info(struct super_block *sb, int type);
static int ext4_quota_on(struct super_block *sb, int type, int format_id,
char *path);
+static int ext4_quota_off(struct super_block *sb, int type);
static int ext4_quota_on_mount(struct super_block *sb, int type);
static ssize_t ext4_quota_read(struct super_block *sb, int type, char *data,
size_t len, loff_t off);
@@ -1086,7 +1144,7 @@ static const struct dquot_operations ext4_quota_operations = {
static const struct quotactl_ops ext4_qctl_operations = {
.quota_on = ext4_quota_on,
- .quota_off = dquot_quota_off,
+ .quota_off = ext4_quota_off,
.quota_sync = dquot_quota_sync,
.get_info = dquot_get_dqinfo,
.set_info = dquot_set_dqinfo,
@@ -1624,10 +1682,12 @@ set_qf_format:
*n_blocks_count = option;
break;
case Opt_nobh:
- set_opt(sbi->s_mount_opt, NOBH);
+ ext4_msg(sb, KERN_WARNING,
+ "Ignoring deprecated nobh option");
break;
case Opt_bh:
- clear_opt(sbi->s_mount_opt, NOBH);
+ ext4_msg(sb, KERN_WARNING,
+ "Ignoring deprecated bh option");
break;
case Opt_i_version:
set_opt(sbi->s_mount_opt, I_VERSION);
@@ -2249,6 +2309,8 @@ static ssize_t session_write_kbytes_show(struct ext4_attr *a,
{
struct super_block *sb = sbi->s_buddy_cache->i_sb;
+ if (!sb->s_bdev->bd_part)
+ return snprintf(buf, PAGE_SIZE, "0\n");
return snprintf(buf, PAGE_SIZE, "%lu\n",
(part_stat_read(sb->s_bdev->bd_part, sectors[1]) -
sbi->s_sectors_written_start) >> 1);
@@ -2259,6 +2321,8 @@ static ssize_t lifetime_write_kbytes_show(struct ext4_attr *a,
{
struct super_block *sb = sbi->s_buddy_cache->i_sb;
+ if (!sb->s_bdev->bd_part)
+ return snprintf(buf, PAGE_SIZE, "0\n");
return snprintf(buf, PAGE_SIZE, "%llu\n",
(unsigned long long)(sbi->s_kbytes_written +
((part_stat_read(sb->s_bdev->bd_part, sectors[1]) -
@@ -2431,6 +2495,53 @@ static int ext4_feature_set_ok(struct super_block *sb, int readonly)
return 1;
}
+/*
+ * This function is called once a day if we have errors logged
+ * on the file system
+ */
+static void print_daily_error_info(unsigned long arg)
+{
+ struct super_block *sb = (struct super_block *) arg;
+ struct ext4_sb_info *sbi;
+ struct ext4_super_block *es;
+
+ sbi = EXT4_SB(sb);
+ es = sbi->s_es;
+
+ if (es->s_error_count)
+ ext4_msg(sb, KERN_NOTICE, "error count: %u",
+ le32_to_cpu(es->s_error_count));
+ if (es->s_first_error_time) {
+ printk(KERN_NOTICE "EXT4-fs (%s): initial error at %u: %.*s:%d",
+ sb->s_id, le32_to_cpu(es->s_first_error_time),
+ (int) sizeof(es->s_first_error_func),
+ es->s_first_error_func,
+ le32_to_cpu(es->s_first_error_line));
+ if (es->s_first_error_ino)
+ printk(": inode %u",
+ le32_to_cpu(es->s_first_error_ino));
+ if (es->s_first_error_block)
+ printk(": block %llu", (unsigned long long)
+ le64_to_cpu(es->s_first_error_block));
+ printk("\n");
+ }
+ if (es->s_last_error_time) {
+ printk(KERN_NOTICE "EXT4-fs (%s): last error at %u: %.*s:%d",
+ sb->s_id, le32_to_cpu(es->s_last_error_time),
+ (int) sizeof(es->s_last_error_func),
+ es->s_last_error_func,
+ le32_to_cpu(es->s_last_error_line));
+ if (es->s_last_error_ino)
+ printk(": inode %u",
+ le32_to_cpu(es->s_last_error_ino));
+ if (es->s_last_error_block)
+ printk(": block %llu", (unsigned long long)
+ le64_to_cpu(es->s_last_error_block));
+ printk("\n");
+ }
+ mod_timer(&sbi->s_err_report, jiffies + 24*60*60*HZ); /* Once a day */
+}
+
static int ext4_fill_super(struct super_block *sb, void *data, int silent)
__releases(kernel_lock)
__acquires(kernel_lock)
@@ -2448,7 +2559,7 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
struct inode *root;
char *cp;
const char *descr;
- int ret = -EINVAL;
+ int ret = -ENOMEM;
int blocksize;
unsigned int db_count;
unsigned int i;
@@ -2459,13 +2570,13 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
sbi = kzalloc(sizeof(*sbi), GFP_KERNEL);
if (!sbi)
- return -ENOMEM;
+ goto out_free_orig;
sbi->s_blockgroup_lock =
kzalloc(sizeof(struct blockgroup_lock), GFP_KERNEL);
if (!sbi->s_blockgroup_lock) {
kfree(sbi);
- return -ENOMEM;
+ goto out_free_orig;
}
sb->s_fs_info = sbi;
sbi->s_mount_opt = 0;
@@ -2473,8 +2584,9 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
sbi->s_resgid = EXT4_DEF_RESGID;
sbi->s_inode_readahead_blks = EXT4_DEF_INODE_READAHEAD_BLKS;
sbi->s_sb_block = sb_block;
- sbi->s_sectors_written_start = part_stat_read(sb->s_bdev->bd_part,
- sectors[1]);
+ if (sb->s_bdev->bd_part)
+ sbi->s_sectors_written_start =
+ part_stat_read(sb->s_bdev->bd_part, sectors[1]);
unlock_kernel();
@@ -2482,6 +2594,7 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
for (cp = sb->s_id; (cp = strchr(cp, '/'));)
*cp = '!';
+ ret = -EINVAL;
blocksize = sb_min_blocksize(sb, EXT4_MIN_BLOCK_SIZE);
if (!blocksize) {
ext4_msg(sb, KERN_ERR, "unable to set blocksize");
@@ -2546,6 +2659,10 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
set_opt(sbi->s_mount_opt, ERRORS_CONT);
else
set_opt(sbi->s_mount_opt, ERRORS_RO);
+ if (def_mount_opts & EXT4_DEFM_BLOCK_VALIDITY)
+ set_opt(sbi->s_mount_opt, BLOCK_VALIDITY);
+ if (def_mount_opts & EXT4_DEFM_DISCARD)
+ set_opt(sbi->s_mount_opt, DISCARD);
sbi->s_resuid = le16_to_cpu(es->s_def_resuid);
sbi->s_resgid = le16_to_cpu(es->s_def_resgid);
@@ -2553,15 +2670,23 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
sbi->s_min_batch_time = EXT4_DEF_MIN_BATCH_TIME;
sbi->s_max_batch_time = EXT4_DEF_MAX_BATCH_TIME;
- set_opt(sbi->s_mount_opt, BARRIER);
+ if ((def_mount_opts & EXT4_DEFM_NOBARRIER) == 0)
+ set_opt(sbi->s_mount_opt, BARRIER);
/*
* enable delayed allocation by default
* Use -o nodelalloc to turn it off
*/
- if (!IS_EXT3_SB(sb))
+ if (!IS_EXT3_SB(sb) &&
+ ((def_mount_opts & EXT4_DEFM_NODELALLOC) == 0))
set_opt(sbi->s_mount_opt, DELALLOC);
+ if (!parse_options((char *) sbi->s_es->s_mount_opts, sb,
+ &journal_devnum, &journal_ioprio, NULL, 0)) {
+ ext4_msg(sb, KERN_WARNING,
+ "failed to parse options in superblock: %s",
+ sbi->s_es->s_mount_opts);
+ }
if (!parse_options((char *) data, sb, &journal_devnum,
&journal_ioprio, NULL, 0))
goto failed_mount;
@@ -2912,18 +3037,7 @@ no_journal:
ext4_msg(sb, KERN_ERR, "insufficient memory");
goto failed_mount_wq;
}
- if (test_opt(sb, NOBH)) {
- if (!(test_opt(sb, DATA_FLAGS) == EXT4_MOUNT_WRITEBACK_DATA)) {
- ext4_msg(sb, KERN_WARNING, "Ignoring nobh option - "
- "its supported only with writeback mode");
- clear_opt(sbi->s_mount_opt, NOBH);
- }
- if (test_opt(sb, DIOREAD_NOLOCK)) {
- ext4_msg(sb, KERN_WARNING, "dioread_nolock option is "
- "not supported with nobh mode");
- goto failed_mount_wq;
- }
- }
+
EXT4_SB(sb)->dio_unwritten_wq = create_workqueue("ext4-dio-unwritten");
if (!EXT4_SB(sb)->dio_unwritten_wq) {
printk(KERN_ERR "EXT4-fs: failed to create DIO workqueue\n");
@@ -3010,7 +3124,7 @@ no_journal:
ext4_ext_init(sb);
err = ext4_mb_init(sb, needs_recovery);
if (err) {
- ext4_msg(sb, KERN_ERR, "failed to initalize mballoc (%d)",
+ ext4_msg(sb, KERN_ERR, "failed to initialize mballoc (%d)",
err);
goto failed_mount4;
}
@@ -3043,7 +3157,14 @@ no_journal:
descr = "out journal";
ext4_msg(sb, KERN_INFO, "mounted filesystem with%s. "
- "Opts: %s", descr, orig_data);
+ "Opts: %s%s%s", descr, sbi->s_es->s_mount_opts,
+ *sbi->s_es->s_mount_opts ? "; " : "", orig_data);
+
+ init_timer(&sbi->s_err_report);
+ sbi->s_err_report.function = print_daily_error_info;
+ sbi->s_err_report.data = (unsigned long) sb;
+ if (es->s_error_count)
+ mod_timer(&sbi->s_err_report, jiffies + 300*HZ); /* 5 minutes */
lock_kernel();
kfree(orig_data);
@@ -3093,6 +3214,7 @@ out_fail:
kfree(sbi->s_blockgroup_lock);
kfree(sbi);
lock_kernel();
+out_free_orig:
kfree(orig_data);
return ret;
}
@@ -3110,7 +3232,7 @@ static void ext4_init_journal_params(struct super_block *sb, journal_t *journal)
journal->j_min_batch_time = sbi->s_min_batch_time;
journal->j_max_batch_time = sbi->s_max_batch_time;
- spin_lock(&journal->j_state_lock);
+ write_lock(&journal->j_state_lock);
if (test_opt(sb, BARRIER))
journal->j_flags |= JBD2_BARRIER;
else
@@ -3119,7 +3241,7 @@ static void ext4_init_journal_params(struct super_block *sb, journal_t *journal)
journal->j_flags |= JBD2_ABORT_ON_SYNCDATA_ERR;
else
journal->j_flags &= ~JBD2_ABORT_ON_SYNCDATA_ERR;
- spin_unlock(&journal->j_state_lock);
+ write_unlock(&journal->j_state_lock);
}
static journal_t *ext4_get_journal(struct super_block *sb,
@@ -3327,8 +3449,17 @@ static int ext4_load_journal(struct super_block *sb,
if (!EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_RECOVER))
err = jbd2_journal_wipe(journal, !really_read_only);
- if (!err)
+ if (!err) {
+ char *save = kmalloc(EXT4_S_ERR_LEN, GFP_KERNEL);
+ if (save)
+ memcpy(save, ((char *) es) +
+ EXT4_S_ERR_START, EXT4_S_ERR_LEN);
err = jbd2_journal_load(journal);
+ if (save)
+ memcpy(((char *) es) + EXT4_S_ERR_START,
+ save, EXT4_S_ERR_LEN);
+ kfree(save);
+ }
if (err) {
ext4_msg(sb, KERN_ERR, "error loading journal");
@@ -3384,10 +3515,14 @@ static int ext4_commit_super(struct super_block *sb, int sync)
*/
if (!(sb->s_flags & MS_RDONLY))
es->s_wtime = cpu_to_le32(get_seconds());
- es->s_kbytes_written =
- cpu_to_le64(EXT4_SB(sb)->s_kbytes_written +
+ if (sb->s_bdev->bd_part)
+ es->s_kbytes_written =
+ cpu_to_le64(EXT4_SB(sb)->s_kbytes_written +
((part_stat_read(sb->s_bdev->bd_part, sectors[1]) -
EXT4_SB(sb)->s_sectors_written_start) >> 1));
+ else
+ es->s_kbytes_written =
+ cpu_to_le64(EXT4_SB(sb)->s_kbytes_written);
ext4_free_blocks_count_set(es, percpu_counter_sum_positive(
&EXT4_SB(sb)->s_freeblocks_counter));
es->s_free_inodes_count = cpu_to_le32(percpu_counter_sum_positive(
@@ -3491,7 +3626,7 @@ int ext4_force_commit(struct super_block *sb)
journal = EXT4_SB(sb)->s_journal;
if (journal) {
- vfs_check_frozen(sb, SB_FREEZE_WRITE);
+ vfs_check_frozen(sb, SB_FREEZE_TRANS);
ret = ext4_journal_force_commit(journal);
}
@@ -3616,7 +3751,7 @@ static int ext4_remount(struct super_block *sb, int *flags, char *data)
}
if (sbi->s_mount_flags & EXT4_MF_FS_ABORTED)
- ext4_abort(sb, __func__, "Abort forced by user");
+ ext4_abort(sb, "Abort forced by user");
sb->s_flags = (sb->s_flags & ~MS_POSIXACL) |
(test_opt(sb, POSIX_ACL) ? MS_POSIXACL : 0);
@@ -3981,6 +4116,18 @@ static int ext4_quota_on(struct super_block *sb, int type, int format_id,
return err;
}
+static int ext4_quota_off(struct super_block *sb, int type)
+{
+ /* Force all delayed allocation blocks to be allocated */
+ if (test_opt(sb, DELALLOC)) {
+ down_read(&sb->s_umount);
+ sync_filesystem(sb);
+ up_read(&sb->s_umount);
+ }
+
+ return dquot_quota_off(sb, type);
+}
+
/* Read data from quotafile - avoid pagecache and such because we cannot afford
* acquiring the locks... As quota files are never truncated and quota code
* itself serializes the operations (and noone else should touch the files)
@@ -4030,7 +4177,6 @@ static ssize_t ext4_quota_write(struct super_block *sb, int type,
ext4_lblk_t blk = off >> EXT4_BLOCK_SIZE_BITS(sb);
int err = 0;
int offset = off & (sb->s_blocksize - 1);
- int journal_quota = EXT4_SB(sb)->s_qf_names[type] != NULL;
struct buffer_head *bh;
handle_t *handle = journal_current_handle();
@@ -4055,24 +4201,16 @@ static ssize_t ext4_quota_write(struct super_block *sb, int type,
bh = ext4_bread(handle, inode, blk, 1, &err);
if (!bh)
goto out;
- if (journal_quota) {
- err = ext4_journal_get_write_access(handle, bh);
- if (err) {
- brelse(bh);
- goto out;
- }
+ err = ext4_journal_get_write_access(handle, bh);
+ if (err) {
+ brelse(bh);
+ goto out;
}
lock_buffer(bh);
memcpy(bh->b_data+offset, data, len);
flush_dcache_page(bh->b_page);
unlock_buffer(bh);
- if (journal_quota)
- err = ext4_handle_dirty_metadata(handle, NULL, bh);
- else {
- /* Always do at least ordered writes for quotas */
- err = ext4_jbd2_file_inode(handle, inode);
- mark_buffer_dirty(bh);
- }
+ err = ext4_handle_dirty_metadata(handle, NULL, bh);
brelse(bh);
out:
if (err) {
diff --git a/fs/ext4/xattr.c b/fs/ext4/xattr.c
index 04338009793..a6f31424957 100644
--- a/fs/ext4/xattr.c
+++ b/fs/ext4/xattr.c
@@ -458,8 +458,7 @@ static void ext4_xattr_update_super_block(handle_t *handle,
if (ext4_journal_get_write_access(handle, EXT4_SB(sb)->s_sbh) == 0) {
EXT4_SET_COMPAT_FEATURE(sb, EXT4_FEATURE_COMPAT_EXT_ATTR);
- sb->s_dirt = 1;
- ext4_handle_dirty_metadata(handle, NULL, EXT4_SB(sb)->s_sbh);
+ ext4_handle_dirty_super(handle, sb);
}
}
diff --git a/fs/file.c b/fs/file.c
index 34bb7f71d99..cccaead962c 100644
--- a/fs/file.c
+++ b/fs/file.c
@@ -178,7 +178,6 @@ static struct fdtable * alloc_fdtable(unsigned int nr)
fdt->open_fds = (fd_set *)data;
data += nr / BITS_PER_BYTE;
fdt->close_on_exec = (fd_set *)data;
- INIT_RCU_HEAD(&fdt->rcu);
fdt->next = NULL;
return fdt;
@@ -312,7 +311,6 @@ struct files_struct *dup_fd(struct files_struct *oldf, int *errorp)
new_fdt->close_on_exec = (fd_set *)&newf->close_on_exec_init;
new_fdt->open_fds = (fd_set *)&newf->open_fds_init;
new_fdt->fd = &newf->fd_array[0];
- INIT_RCU_HEAD(&new_fdt->rcu);
new_fdt->next = NULL;
spin_lock(&oldf->file_lock);
@@ -430,7 +428,6 @@ struct files_struct init_files = {
.fd = &init_files.fd_array[0],
.close_on_exec = (fd_set *)&init_files.close_on_exec_init,
.open_fds = (fd_set *)&init_files.open_fds_init,
- .rcu = RCU_HEAD_INIT,
},
.file_lock = __SPIN_LOCK_UNLOCKED(init_task.file_lock),
};
diff --git a/fs/freevxfs/vxfs_super.c b/fs/freevxfs/vxfs_super.c
index 1e8af939b3e..5132c99b1ca 100644
--- a/fs/freevxfs/vxfs_super.c
+++ b/fs/freevxfs/vxfs_super.c
@@ -135,7 +135,7 @@ static int vxfs_remount(struct super_block *sb, int *flags, char *data)
}
/**
- * vxfs_read_super - read superblock into memory and initalize filesystem
+ * vxfs_read_super - read superblock into memory and initialize filesystem
* @sbp: VFS superblock (to fill)
* @dp: fs private mount data
* @silent: do not complain loudly when sth is wrong
diff --git a/fs/fscache/Kconfig b/fs/fscache/Kconfig
index cc94bb9563f..3f6dfa98988 100644
--- a/fs/fscache/Kconfig
+++ b/fs/fscache/Kconfig
@@ -1,7 +1,6 @@
config FSCACHE
tristate "General filesystem local caching manager"
- select SLOW_WORK
help
This option enables a generic filesystem caching manager that can be
used by various network and other filesystems to cache data locally.
diff --git a/fs/fscache/internal.h b/fs/fscache/internal.h
index edd7434ab6e..6a026441c5a 100644
--- a/fs/fscache/internal.h
+++ b/fs/fscache/internal.h
@@ -82,6 +82,14 @@ extern unsigned fscache_defer_lookup;
extern unsigned fscache_defer_create;
extern unsigned fscache_debug;
extern struct kobject *fscache_root;
+extern struct workqueue_struct *fscache_object_wq;
+extern struct workqueue_struct *fscache_op_wq;
+DECLARE_PER_CPU(wait_queue_head_t, fscache_object_cong_wait);
+
+static inline bool fscache_object_congested(void)
+{
+ return workqueue_congested(WORK_CPU_UNBOUND, fscache_object_wq);
+}
extern int fscache_wait_bit(void *);
extern int fscache_wait_bit_interruptible(void *);
diff --git a/fs/fscache/main.c b/fs/fscache/main.c
index add6bdb53f0..f9d856773f7 100644
--- a/fs/fscache/main.c
+++ b/fs/fscache/main.c
@@ -15,6 +15,7 @@
#include <linux/sched.h>
#include <linux/completion.h>
#include <linux/slab.h>
+#include <linux/seq_file.h>
#include "internal.h"
MODULE_DESCRIPTION("FS Cache Manager");
@@ -40,22 +41,105 @@ MODULE_PARM_DESC(fscache_debug,
"FS-Cache debugging mask");
struct kobject *fscache_root;
+struct workqueue_struct *fscache_object_wq;
+struct workqueue_struct *fscache_op_wq;
+
+DEFINE_PER_CPU(wait_queue_head_t, fscache_object_cong_wait);
+
+/* these values serve as lower bounds, will be adjusted in fscache_init() */
+static unsigned fscache_object_max_active = 4;
+static unsigned fscache_op_max_active = 2;
+
+#ifdef CONFIG_SYSCTL
+static struct ctl_table_header *fscache_sysctl_header;
+
+static int fscache_max_active_sysctl(struct ctl_table *table, int write,
+ void __user *buffer,
+ size_t *lenp, loff_t *ppos)
+{
+ struct workqueue_struct **wqp = table->extra1;
+ unsigned int *datap = table->data;
+ int ret;
+
+ ret = proc_dointvec(table, write, buffer, lenp, ppos);
+ if (ret == 0)
+ workqueue_set_max_active(*wqp, *datap);
+ return ret;
+}
+
+ctl_table fscache_sysctls[] = {
+ {
+ .procname = "object_max_active",
+ .data = &fscache_object_max_active,
+ .maxlen = sizeof(unsigned),
+ .mode = 0644,
+ .proc_handler = fscache_max_active_sysctl,
+ .extra1 = &fscache_object_wq,
+ },
+ {
+ .procname = "operation_max_active",
+ .data = &fscache_op_max_active,
+ .maxlen = sizeof(unsigned),
+ .mode = 0644,
+ .proc_handler = fscache_max_active_sysctl,
+ .extra1 = &fscache_op_wq,
+ },
+ {}
+};
+
+ctl_table fscache_sysctls_root[] = {
+ {
+ .procname = "fscache",
+ .mode = 0555,
+ .child = fscache_sysctls,
+ },
+ {}
+};
+#endif
/*
* initialise the fs caching module
*/
static int __init fscache_init(void)
{
+ unsigned int nr_cpus = num_possible_cpus();
+ unsigned int cpu;
int ret;
- ret = slow_work_register_user(THIS_MODULE);
- if (ret < 0)
- goto error_slow_work;
+ fscache_object_max_active =
+ clamp_val(nr_cpus,
+ fscache_object_max_active, WQ_UNBOUND_MAX_ACTIVE);
+
+ ret = -ENOMEM;
+ fscache_object_wq = alloc_workqueue("fscache_object", WQ_UNBOUND,
+ fscache_object_max_active);
+ if (!fscache_object_wq)
+ goto error_object_wq;
+
+ fscache_op_max_active =
+ clamp_val(fscache_object_max_active / 2,
+ fscache_op_max_active, WQ_UNBOUND_MAX_ACTIVE);
+
+ ret = -ENOMEM;
+ fscache_op_wq = alloc_workqueue("fscache_operation", WQ_UNBOUND,
+ fscache_op_max_active);
+ if (!fscache_op_wq)
+ goto error_op_wq;
+
+ for_each_possible_cpu(cpu)
+ init_waitqueue_head(&per_cpu(fscache_object_cong_wait, cpu));
ret = fscache_proc_init();
if (ret < 0)
goto error_proc;
+#ifdef CONFIG_SYSCTL
+ ret = -ENOMEM;
+ fscache_sysctl_header = register_sysctl_table(fscache_sysctls_root);
+ if (!fscache_sysctl_header)
+ goto error_sysctl;
+#endif
+
fscache_cookie_jar = kmem_cache_create("fscache_cookie_jar",
sizeof(struct fscache_cookie),
0,
@@ -78,10 +162,16 @@ static int __init fscache_init(void)
error_kobj:
kmem_cache_destroy(fscache_cookie_jar);
error_cookie_jar:
+#ifdef CONFIG_SYSCTL
+ unregister_sysctl_table(fscache_sysctl_header);
+error_sysctl:
+#endif
fscache_proc_cleanup();
error_proc:
- slow_work_unregister_user(THIS_MODULE);
-error_slow_work:
+ destroy_workqueue(fscache_op_wq);
+error_op_wq:
+ destroy_workqueue(fscache_object_wq);
+error_object_wq:
return ret;
}
@@ -96,8 +186,12 @@ static void __exit fscache_exit(void)
kobject_put(fscache_root);
kmem_cache_destroy(fscache_cookie_jar);
+#ifdef CONFIG_SYSCTL
+ unregister_sysctl_table(fscache_sysctl_header);
+#endif
fscache_proc_cleanup();
- slow_work_unregister_user(THIS_MODULE);
+ destroy_workqueue(fscache_op_wq);
+ destroy_workqueue(fscache_object_wq);
printk(KERN_NOTICE "FS-Cache: Unloaded\n");
}
diff --git a/fs/fscache/object-list.c b/fs/fscache/object-list.c
index 4a8eb31c533..ebe29c58138 100644
--- a/fs/fscache/object-list.c
+++ b/fs/fscache/object-list.c
@@ -34,8 +34,8 @@ struct fscache_objlist_data {
#define FSCACHE_OBJLIST_CONFIG_NOREADS 0x00000200 /* show objects without active reads */
#define FSCACHE_OBJLIST_CONFIG_EVENTS 0x00000400 /* show objects with events */
#define FSCACHE_OBJLIST_CONFIG_NOEVENTS 0x00000800 /* show objects without no events */
-#define FSCACHE_OBJLIST_CONFIG_WORK 0x00001000 /* show objects with slow work */
-#define FSCACHE_OBJLIST_CONFIG_NOWORK 0x00002000 /* show objects without slow work */
+#define FSCACHE_OBJLIST_CONFIG_WORK 0x00001000 /* show objects with work */
+#define FSCACHE_OBJLIST_CONFIG_NOWORK 0x00002000 /* show objects without work */
u8 buf[512]; /* key and aux data buffer */
};
@@ -231,12 +231,11 @@ static int fscache_objlist_show(struct seq_file *m, void *v)
READS, NOREADS);
FILTER(obj->events & obj->event_mask,
EVENTS, NOEVENTS);
- FILTER(obj->work.flags & ~(1UL << SLOW_WORK_VERY_SLOW),
- WORK, NOWORK);
+ FILTER(work_busy(&obj->work), WORK, NOWORK);
}
seq_printf(m,
- "%8x %8x %s %5u %3u %3u %3u %2u %5u %2lx %2lx %1lx %1lx | ",
+ "%8x %8x %s %5u %3u %3u %3u %2u %5u %2lx %2lx %1lx %1x | ",
obj->debug_id,
obj->parent ? obj->parent->debug_id : -1,
fscache_object_states_short[obj->state],
@@ -249,7 +248,7 @@ static int fscache_objlist_show(struct seq_file *m, void *v)
obj->event_mask & FSCACHE_OBJECT_EVENTS_MASK,
obj->events,
obj->flags,
- obj->work.flags);
+ work_busy(&obj->work));
no_cookie = true;
keylen = auxlen = 0;
diff --git a/fs/fscache/object.c b/fs/fscache/object.c
index 0b589a9b4ff..b6b897c550a 100644
--- a/fs/fscache/object.c
+++ b/fs/fscache/object.c
@@ -14,7 +14,6 @@
#define FSCACHE_DEBUG_LEVEL COOKIE
#include <linux/module.h>
-#include <linux/seq_file.h>
#include "internal.h"
const char *fscache_object_states[FSCACHE_OBJECT__NSTATES] = {
@@ -50,12 +49,8 @@ const char fscache_object_states_short[FSCACHE_OBJECT__NSTATES][5] = {
[FSCACHE_OBJECT_DEAD] = "DEAD",
};
-static void fscache_object_slow_work_put_ref(struct slow_work *);
-static int fscache_object_slow_work_get_ref(struct slow_work *);
-static void fscache_object_slow_work_execute(struct slow_work *);
-#ifdef CONFIG_SLOW_WORK_DEBUG
-static void fscache_object_slow_work_desc(struct slow_work *, struct seq_file *);
-#endif
+static int fscache_get_object(struct fscache_object *);
+static void fscache_put_object(struct fscache_object *);
static void fscache_initialise_object(struct fscache_object *);
static void fscache_lookup_object(struct fscache_object *);
static void fscache_object_available(struct fscache_object *);
@@ -64,17 +59,6 @@ static void fscache_withdraw_object(struct fscache_object *);
static void fscache_enqueue_dependents(struct fscache_object *);
static void fscache_dequeue_object(struct fscache_object *);
-const struct slow_work_ops fscache_object_slow_work_ops = {
- .owner = THIS_MODULE,
- .get_ref = fscache_object_slow_work_get_ref,
- .put_ref = fscache_object_slow_work_put_ref,
- .execute = fscache_object_slow_work_execute,
-#ifdef CONFIG_SLOW_WORK_DEBUG
- .desc = fscache_object_slow_work_desc,
-#endif
-};
-EXPORT_SYMBOL(fscache_object_slow_work_ops);
-
/*
* we need to notify the parent when an op completes that we had outstanding
* upon it
@@ -345,7 +329,7 @@ unsupported_event:
/*
* execute an object
*/
-static void fscache_object_slow_work_execute(struct slow_work *work)
+void fscache_object_work_func(struct work_struct *work)
{
struct fscache_object *object =
container_of(work, struct fscache_object, work);
@@ -359,23 +343,9 @@ static void fscache_object_slow_work_execute(struct slow_work *work)
if (object->events & object->event_mask)
fscache_enqueue_object(object);
clear_bit(FSCACHE_OBJECT_EV_REQUEUE, &object->events);
+ fscache_put_object(object);
}
-
-/*
- * describe an object for slow-work debugging
- */
-#ifdef CONFIG_SLOW_WORK_DEBUG
-static void fscache_object_slow_work_desc(struct slow_work *work,
- struct seq_file *m)
-{
- struct fscache_object *object =
- container_of(work, struct fscache_object, work);
-
- seq_printf(m, "FSC: OBJ%x: %s",
- object->debug_id,
- fscache_object_states_short[object->state]);
-}
-#endif
+EXPORT_SYMBOL(fscache_object_work_func);
/*
* initialise an object
@@ -393,7 +363,6 @@ static void fscache_initialise_object(struct fscache_object *object)
_enter("");
ASSERT(object->cookie != NULL);
ASSERT(object->cookie->parent != NULL);
- ASSERT(list_empty(&object->work.link));
if (object->events & ((1 << FSCACHE_OBJECT_EV_ERROR) |
(1 << FSCACHE_OBJECT_EV_RELEASE) |
@@ -671,10 +640,8 @@ static void fscache_drop_object(struct fscache_object *object)
object->parent = NULL;
}
- /* this just shifts the object release to the slow work processor */
- fscache_stat(&fscache_n_cop_put_object);
- object->cache->ops->put_object(object);
- fscache_stat_d(&fscache_n_cop_put_object);
+ /* this just shifts the object release to the work processor */
+ fscache_put_object(object);
_leave("");
}
@@ -758,12 +725,10 @@ void fscache_withdrawing_object(struct fscache_cache *cache,
}
/*
- * allow the slow work item processor to get a ref on an object
+ * get a ref on an object
*/
-static int fscache_object_slow_work_get_ref(struct slow_work *work)
+static int fscache_get_object(struct fscache_object *object)
{
- struct fscache_object *object =
- container_of(work, struct fscache_object, work);
int ret;
fscache_stat(&fscache_n_cop_grab_object);
@@ -773,13 +738,10 @@ static int fscache_object_slow_work_get_ref(struct slow_work *work)
}
/*
- * allow the slow work item processor to discard a ref on a work item
+ * discard a ref on a work item
*/
-static void fscache_object_slow_work_put_ref(struct slow_work *work)
+static void fscache_put_object(struct fscache_object *object)
{
- struct fscache_object *object =
- container_of(work, struct fscache_object, work);
-
fscache_stat(&fscache_n_cop_put_object);
object->cache->ops->put_object(object);
fscache_stat_d(&fscache_n_cop_put_object);
@@ -792,8 +754,48 @@ void fscache_enqueue_object(struct fscache_object *object)
{
_enter("{OBJ%x}", object->debug_id);
- slow_work_enqueue(&object->work);
+ if (fscache_get_object(object) >= 0) {
+ wait_queue_head_t *cong_wq =
+ &get_cpu_var(fscache_object_cong_wait);
+
+ if (queue_work(fscache_object_wq, &object->work)) {
+ if (fscache_object_congested())
+ wake_up(cong_wq);
+ } else
+ fscache_put_object(object);
+
+ put_cpu_var(fscache_object_cong_wait);
+ }
+}
+
+/**
+ * fscache_object_sleep_till_congested - Sleep until object wq is congested
+ * @timoutp: Scheduler sleep timeout
+ *
+ * Allow an object handler to sleep until the object workqueue is congested.
+ *
+ * The caller must set up a wake up event before calling this and must have set
+ * the appropriate sleep mode (such as TASK_UNINTERRUPTIBLE) and tested its own
+ * condition before calling this function as no test is made here.
+ *
+ * %true is returned if the object wq is congested, %false otherwise.
+ */
+bool fscache_object_sleep_till_congested(signed long *timeoutp)
+{
+ wait_queue_head_t *cong_wq = &__get_cpu_var(fscache_object_cong_wait);
+ DEFINE_WAIT(wait);
+
+ if (fscache_object_congested())
+ return true;
+
+ add_wait_queue_exclusive(cong_wq, &wait);
+ if (!fscache_object_congested())
+ *timeoutp = schedule_timeout(*timeoutp);
+ finish_wait(cong_wq, &wait);
+
+ return fscache_object_congested();
}
+EXPORT_SYMBOL_GPL(fscache_object_sleep_till_congested);
/*
* enqueue the dependents of an object for metadata-type processing
@@ -819,9 +821,7 @@ static void fscache_enqueue_dependents(struct fscache_object *object)
/* sort onto appropriate lists */
fscache_enqueue_object(dep);
- fscache_stat(&fscache_n_cop_put_object);
- dep->cache->ops->put_object(dep);
- fscache_stat_d(&fscache_n_cop_put_object);
+ fscache_put_object(dep);
if (!list_empty(&object->dependents))
cond_resched_lock(&object->lock);
diff --git a/fs/fscache/operation.c b/fs/fscache/operation.c
index f17cecafae4..b9f34eaede0 100644
--- a/fs/fscache/operation.c
+++ b/fs/fscache/operation.c
@@ -42,16 +42,12 @@ void fscache_enqueue_operation(struct fscache_operation *op)
fscache_stat(&fscache_n_op_enqueue);
switch (op->flags & FSCACHE_OP_TYPE) {
- case FSCACHE_OP_FAST:
- _debug("queue fast");
+ case FSCACHE_OP_ASYNC:
+ _debug("queue async");
atomic_inc(&op->usage);
- if (!schedule_work(&op->fast_work))
+ if (!queue_work(fscache_op_wq, &op->work))
fscache_put_operation(op);
break;
- case FSCACHE_OP_SLOW:
- _debug("queue slow");
- slow_work_enqueue(&op->slow_work);
- break;
case FSCACHE_OP_MYTHREAD:
_debug("queue for caller's attention");
break;
@@ -455,36 +451,13 @@ void fscache_operation_gc(struct work_struct *work)
}
/*
- * allow the slow work item processor to get a ref on an operation
- */
-static int fscache_op_get_ref(struct slow_work *work)
-{
- struct fscache_operation *op =
- container_of(work, struct fscache_operation, slow_work);
-
- atomic_inc(&op->usage);
- return 0;
-}
-
-/*
- * allow the slow work item processor to discard a ref on an operation
- */
-static void fscache_op_put_ref(struct slow_work *work)
-{
- struct fscache_operation *op =
- container_of(work, struct fscache_operation, slow_work);
-
- fscache_put_operation(op);
-}
-
-/*
- * execute an operation using the slow thread pool to provide processing context
- * - the caller holds a ref to this object, so we don't need to hold one
+ * execute an operation using fs_op_wq to provide processing context -
+ * the caller holds a ref to this object, so we don't need to hold one
*/
-static void fscache_op_execute(struct slow_work *work)
+void fscache_op_work_func(struct work_struct *work)
{
struct fscache_operation *op =
- container_of(work, struct fscache_operation, slow_work);
+ container_of(work, struct fscache_operation, work);
unsigned long start;
_enter("{OBJ%x OP%x,%d}",
@@ -494,31 +467,7 @@ static void fscache_op_execute(struct slow_work *work)
start = jiffies;
op->processor(op);
fscache_hist(fscache_ops_histogram, start);
+ fscache_put_operation(op);
_leave("");
}
-
-/*
- * describe an operation for slow-work debugging
- */
-#ifdef CONFIG_SLOW_WORK_DEBUG
-static void fscache_op_desc(struct slow_work *work, struct seq_file *m)
-{
- struct fscache_operation *op =
- container_of(work, struct fscache_operation, slow_work);
-
- seq_printf(m, "FSC: OBJ%x OP%x: %s/%s fl=%lx",
- op->object->debug_id, op->debug_id,
- op->name, op->state, op->flags);
-}
-#endif
-
-const struct slow_work_ops fscache_op_slow_work_ops = {
- .owner = THIS_MODULE,
- .get_ref = fscache_op_get_ref,
- .put_ref = fscache_op_put_ref,
- .execute = fscache_op_execute,
-#ifdef CONFIG_SLOW_WORK_DEBUG
- .desc = fscache_op_desc,
-#endif
-};
diff --git a/fs/fscache/page.c b/fs/fscache/page.c
index 723b889fd21..41c441c2058 100644
--- a/fs/fscache/page.c
+++ b/fs/fscache/page.c
@@ -105,7 +105,7 @@ bool __fscache_maybe_release_page(struct fscache_cookie *cookie,
page_busy:
/* we might want to wait here, but that could deadlock the allocator as
- * the slow-work threads writing to the cache may all end up sleeping
+ * the work threads writing to the cache may all end up sleeping
* on memory allocation */
fscache_stat(&fscache_n_store_vmscan_busy);
return false;
@@ -188,9 +188,8 @@ int __fscache_attr_changed(struct fscache_cookie *cookie)
return -ENOMEM;
}
- fscache_operation_init(op, NULL);
- fscache_operation_init_slow(op, fscache_attr_changed_op);
- op->flags = FSCACHE_OP_SLOW | (1 << FSCACHE_OP_EXCLUSIVE);
+ fscache_operation_init(op, fscache_attr_changed_op, NULL);
+ op->flags = FSCACHE_OP_ASYNC | (1 << FSCACHE_OP_EXCLUSIVE);
fscache_set_op_name(op, "Attr");
spin_lock(&cookie->lock);
@@ -218,24 +217,6 @@ nobufs:
EXPORT_SYMBOL(__fscache_attr_changed);
/*
- * handle secondary execution given to a retrieval op on behalf of the
- * cache
- */
-static void fscache_retrieval_work(struct work_struct *work)
-{
- struct fscache_retrieval *op =
- container_of(work, struct fscache_retrieval, op.fast_work);
- unsigned long start;
-
- _enter("{OP%x}", op->op.debug_id);
-
- start = jiffies;
- op->op.processor(&op->op);
- fscache_hist(fscache_ops_histogram, start);
- fscache_put_operation(&op->op);
-}
-
-/*
* release a retrieval op reference
*/
static void fscache_release_retrieval_op(struct fscache_operation *_op)
@@ -269,13 +250,12 @@ static struct fscache_retrieval *fscache_alloc_retrieval(
return NULL;
}
- fscache_operation_init(&op->op, fscache_release_retrieval_op);
+ fscache_operation_init(&op->op, NULL, fscache_release_retrieval_op);
op->op.flags = FSCACHE_OP_MYTHREAD | (1 << FSCACHE_OP_WAITING);
op->mapping = mapping;
op->end_io_func = end_io_func;
op->context = context;
op->start_time = jiffies;
- INIT_WORK(&op->op.fast_work, fscache_retrieval_work);
INIT_LIST_HEAD(&op->to_do);
fscache_set_op_name(&op->op, "Retr");
return op;
@@ -795,9 +775,9 @@ int __fscache_write_page(struct fscache_cookie *cookie,
if (!op)
goto nomem;
- fscache_operation_init(&op->op, fscache_release_write_op);
- fscache_operation_init_slow(&op->op, fscache_write_op);
- op->op.flags = FSCACHE_OP_SLOW | (1 << FSCACHE_OP_WAITING);
+ fscache_operation_init(&op->op, fscache_write_op,
+ fscache_release_write_op);
+ op->op.flags = FSCACHE_OP_ASYNC | (1 << FSCACHE_OP_WAITING);
fscache_set_op_name(&op->op, "Write1");
ret = radix_tree_preload(gfp & ~__GFP_HIGHMEM);
@@ -852,7 +832,7 @@ int __fscache_write_page(struct fscache_cookie *cookie,
fscache_stat(&fscache_n_store_ops);
fscache_stat(&fscache_n_stores_ok);
- /* the slow work queue now carries its own ref on the object */
+ /* the work queue now carries its own ref on the object */
fscache_put_operation(&op->op);
_leave(" = 0");
return 0;
diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c
index 9424796d663..69ad053ffd7 100644
--- a/fs/fuse/dev.c
+++ b/fs/fuse/dev.c
@@ -239,7 +239,6 @@ static u64 fuse_get_unique(struct fuse_conn *fc)
static void queue_request(struct fuse_conn *fc, struct fuse_req *req)
{
- req->in.h.unique = fuse_get_unique(fc);
req->in.h.len = sizeof(struct fuse_in_header) +
len_args(req->in.numargs, (struct fuse_arg *) req->in.args);
list_add_tail(&req->list, &fc->pending);
@@ -261,6 +260,7 @@ static void flush_bg_queue(struct fuse_conn *fc)
req = list_entry(fc->bg_queue.next, struct fuse_req, list);
list_del(&req->list);
fc->active_background++;
+ req->in.h.unique = fuse_get_unique(fc);
queue_request(fc, req);
}
}
@@ -398,6 +398,7 @@ void fuse_request_send(struct fuse_conn *fc, struct fuse_req *req)
else if (fc->conn_error)
req->out.h.error = -ECONNREFUSED;
else {
+ req->in.h.unique = fuse_get_unique(fc);
queue_request(fc, req);
/* acquire extra reference, since request is still needed
after request_end() */
@@ -450,6 +451,23 @@ void fuse_request_send_background(struct fuse_conn *fc, struct fuse_req *req)
}
EXPORT_SYMBOL_GPL(fuse_request_send_background);
+static int fuse_request_send_notify_reply(struct fuse_conn *fc,
+ struct fuse_req *req, u64 unique)
+{
+ int err = -ENODEV;
+
+ req->isreply = 0;
+ req->in.h.unique = unique;
+ spin_lock(&fc->lock);
+ if (fc->connected) {
+ queue_request(fc, req);
+ err = 0;
+ }
+ spin_unlock(&fc->lock);
+
+ return err;
+}
+
/*
* Called under fc->lock
*
@@ -535,13 +553,13 @@ static void fuse_copy_finish(struct fuse_copy_state *cs)
if (!cs->write) {
buf->ops->unmap(cs->pipe, buf, cs->mapaddr);
} else {
- kunmap_atomic(cs->mapaddr, KM_USER0);
+ kunmap(buf->page);
buf->len = PAGE_SIZE - cs->len;
}
cs->currbuf = NULL;
cs->mapaddr = NULL;
} else if (cs->mapaddr) {
- kunmap_atomic(cs->mapaddr, KM_USER0);
+ kunmap(cs->pg);
if (cs->write) {
flush_dcache_page(cs->pg);
set_page_dirty_lock(cs->pg);
@@ -572,7 +590,7 @@ static int fuse_copy_fill(struct fuse_copy_state *cs)
BUG_ON(!cs->nr_segs);
cs->currbuf = buf;
- cs->mapaddr = buf->ops->map(cs->pipe, buf, 1);
+ cs->mapaddr = buf->ops->map(cs->pipe, buf, 0);
cs->len = buf->len;
cs->buf = cs->mapaddr + buf->offset;
cs->pipebufs++;
@@ -592,7 +610,7 @@ static int fuse_copy_fill(struct fuse_copy_state *cs)
buf->len = 0;
cs->currbuf = buf;
- cs->mapaddr = kmap_atomic(page, KM_USER0);
+ cs->mapaddr = kmap(page);
cs->buf = cs->mapaddr;
cs->len = PAGE_SIZE;
cs->pipebufs++;
@@ -611,7 +629,7 @@ static int fuse_copy_fill(struct fuse_copy_state *cs)
return err;
BUG_ON(err != 1);
offset = cs->addr % PAGE_SIZE;
- cs->mapaddr = kmap_atomic(cs->pg, KM_USER0);
+ cs->mapaddr = kmap(cs->pg);
cs->buf = cs->mapaddr + offset;
cs->len = min(PAGE_SIZE - offset, cs->seglen);
cs->seglen -= cs->len;
@@ -1231,6 +1249,199 @@ err:
return err;
}
+static int fuse_notify_store(struct fuse_conn *fc, unsigned int size,
+ struct fuse_copy_state *cs)
+{
+ struct fuse_notify_store_out outarg;
+ struct inode *inode;
+ struct address_space *mapping;
+ u64 nodeid;
+ int err;
+ pgoff_t index;
+ unsigned int offset;
+ unsigned int num;
+ loff_t file_size;
+ loff_t end;
+
+ err = -EINVAL;
+ if (size < sizeof(outarg))
+ goto out_finish;
+
+ err = fuse_copy_one(cs, &outarg, sizeof(outarg));
+ if (err)
+ goto out_finish;
+
+ err = -EINVAL;
+ if (size - sizeof(outarg) != outarg.size)
+ goto out_finish;
+
+ nodeid = outarg.nodeid;
+
+ down_read(&fc->killsb);
+
+ err = -ENOENT;
+ if (!fc->sb)
+ goto out_up_killsb;
+
+ inode = ilookup5(fc->sb, nodeid, fuse_inode_eq, &nodeid);
+ if (!inode)
+ goto out_up_killsb;
+
+ mapping = inode->i_mapping;
+ index = outarg.offset >> PAGE_CACHE_SHIFT;
+ offset = outarg.offset & ~PAGE_CACHE_MASK;
+ file_size = i_size_read(inode);
+ end = outarg.offset + outarg.size;
+ if (end > file_size) {
+ file_size = end;
+ fuse_write_update_size(inode, file_size);
+ }
+
+ num = outarg.size;
+ while (num) {
+ struct page *page;
+ unsigned int this_num;
+
+ err = -ENOMEM;
+ page = find_or_create_page(mapping, index,
+ mapping_gfp_mask(mapping));
+ if (!page)
+ goto out_iput;
+
+ this_num = min_t(unsigned, num, PAGE_CACHE_SIZE - offset);
+ err = fuse_copy_page(cs, &page, offset, this_num, 0);
+ if (!err && offset == 0 && (num != 0 || file_size == end))
+ SetPageUptodate(page);
+ unlock_page(page);
+ page_cache_release(page);
+
+ if (err)
+ goto out_iput;
+
+ num -= this_num;
+ offset = 0;
+ index++;
+ }
+
+ err = 0;
+
+out_iput:
+ iput(inode);
+out_up_killsb:
+ up_read(&fc->killsb);
+out_finish:
+ fuse_copy_finish(cs);
+ return err;
+}
+
+static void fuse_retrieve_end(struct fuse_conn *fc, struct fuse_req *req)
+{
+ int i;
+
+ for (i = 0; i < req->num_pages; i++) {
+ struct page *page = req->pages[i];
+ page_cache_release(page);
+ }
+}
+
+static int fuse_retrieve(struct fuse_conn *fc, struct inode *inode,
+ struct fuse_notify_retrieve_out *outarg)
+{
+ int err;
+ struct address_space *mapping = inode->i_mapping;
+ struct fuse_req *req;
+ pgoff_t index;
+ loff_t file_size;
+ unsigned int num;
+ unsigned int offset;
+ size_t total_len;
+
+ req = fuse_get_req(fc);
+ if (IS_ERR(req))
+ return PTR_ERR(req);
+
+ offset = outarg->offset & ~PAGE_CACHE_MASK;
+
+ req->in.h.opcode = FUSE_NOTIFY_REPLY;
+ req->in.h.nodeid = outarg->nodeid;
+ req->in.numargs = 2;
+ req->in.argpages = 1;
+ req->page_offset = offset;
+ req->end = fuse_retrieve_end;
+
+ index = outarg->offset >> PAGE_CACHE_SHIFT;
+ file_size = i_size_read(inode);
+ num = outarg->size;
+ if (outarg->offset > file_size)
+ num = 0;
+ else if (outarg->offset + num > file_size)
+ num = file_size - outarg->offset;
+
+ while (num) {
+ struct page *page;
+ unsigned int this_num;
+
+ page = find_get_page(mapping, index);
+ if (!page)
+ break;
+
+ this_num = min_t(unsigned, num, PAGE_CACHE_SIZE - offset);
+ req->pages[req->num_pages] = page;
+ req->num_pages++;
+
+ num -= this_num;
+ total_len += this_num;
+ }
+ req->misc.retrieve_in.offset = outarg->offset;
+ req->misc.retrieve_in.size = total_len;
+ req->in.args[0].size = sizeof(req->misc.retrieve_in);
+ req->in.args[0].value = &req->misc.retrieve_in;
+ req->in.args[1].size = total_len;
+
+ err = fuse_request_send_notify_reply(fc, req, outarg->notify_unique);
+ if (err)
+ fuse_retrieve_end(fc, req);
+
+ return err;
+}
+
+static int fuse_notify_retrieve(struct fuse_conn *fc, unsigned int size,
+ struct fuse_copy_state *cs)
+{
+ struct fuse_notify_retrieve_out outarg;
+ struct inode *inode;
+ int err;
+
+ err = -EINVAL;
+ if (size != sizeof(outarg))
+ goto copy_finish;
+
+ err = fuse_copy_one(cs, &outarg, sizeof(outarg));
+ if (err)
+ goto copy_finish;
+
+ fuse_copy_finish(cs);
+
+ down_read(&fc->killsb);
+ err = -ENOENT;
+ if (fc->sb) {
+ u64 nodeid = outarg.nodeid;
+
+ inode = ilookup5(fc->sb, nodeid, fuse_inode_eq, &nodeid);
+ if (inode) {
+ err = fuse_retrieve(fc, inode, &outarg);
+ iput(inode);
+ }
+ }
+ up_read(&fc->killsb);
+
+ return err;
+
+copy_finish:
+ fuse_copy_finish(cs);
+ return err;
+}
+
static int fuse_notify(struct fuse_conn *fc, enum fuse_notify_code code,
unsigned int size, struct fuse_copy_state *cs)
{
@@ -1244,6 +1455,12 @@ static int fuse_notify(struct fuse_conn *fc, enum fuse_notify_code code,
case FUSE_NOTIFY_INVAL_ENTRY:
return fuse_notify_inval_entry(fc, size, cs);
+ case FUSE_NOTIFY_STORE:
+ return fuse_notify_store(fc, size, cs);
+
+ case FUSE_NOTIFY_RETRIEVE:
+ return fuse_notify_retrieve(fc, size, cs);
+
default:
fuse_copy_finish(cs);
return -EINVAL;
diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c
index 3cdc5f78a40..431be0795b6 100644
--- a/fs/fuse/dir.c
+++ b/fs/fuse/dir.c
@@ -1016,7 +1016,7 @@ static int fuse_permission(struct inode *inode, int mask)
exist. So if permissions are revoked this won't be
noticed immediately, only after the attribute
timeout has expired */
- } else if (mask & MAY_ACCESS) {
+ } else if (mask & (MAY_ACCESS | MAY_CHDIR)) {
err = fuse_access(inode, mask);
} else if ((mask & MAY_EXEC) && S_ISREG(inode->i_mode)) {
if (!(inode->i_mode & S_IXUGO)) {
diff --git a/fs/fuse/file.c b/fs/fuse/file.c
index ada0adeb3bb..147c1f71bdb 100644
--- a/fs/fuse/file.c
+++ b/fs/fuse/file.c
@@ -706,7 +706,7 @@ static int fuse_write_begin(struct file *file, struct address_space *mapping,
return 0;
}
-static void fuse_write_update_size(struct inode *inode, loff_t pos)
+void fuse_write_update_size(struct inode *inode, loff_t pos)
{
struct fuse_conn *fc = get_fuse_conn(inode);
struct fuse_inode *fi = get_fuse_inode(inode);
diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h
index 8f309f04064..57d4a3a0f10 100644
--- a/fs/fuse/fuse_i.h
+++ b/fs/fuse/fuse_i.h
@@ -272,6 +272,7 @@ struct fuse_req {
struct fuse_write_in in;
struct fuse_write_out out;
} write;
+ struct fuse_notify_retrieve_in retrieve_in;
struct fuse_lk_in lk_in;
} misc;
@@ -748,4 +749,6 @@ long fuse_do_ioctl(struct file *file, unsigned int cmd, unsigned long arg,
unsigned fuse_file_poll(struct file *file, poll_table *wait);
int fuse_dev_release(struct inode *inode, struct file *file);
+void fuse_write_update_size(struct inode *inode, loff_t pos);
+
#endif /* _FS_FUSE_I_H */
diff --git a/fs/gfs2/Kconfig b/fs/gfs2/Kconfig
index a47b4310711..cc966552214 100644
--- a/fs/gfs2/Kconfig
+++ b/fs/gfs2/Kconfig
@@ -7,7 +7,6 @@ config GFS2_FS
select IP_SCTP if DLM_SCTP
select FS_POSIX_ACL
select CRC32
- select SLOW_WORK
select QUOTACTL
help
A cluster filesystem.
diff --git a/fs/gfs2/aops.c b/fs/gfs2/aops.c
index 9f8b52500d6..5e96cbd8a45 100644
--- a/fs/gfs2/aops.c
+++ b/fs/gfs2/aops.c
@@ -136,10 +136,7 @@ static int gfs2_writeback_writepage(struct page *page,
if (ret <= 0)
return ret;
- ret = mpage_writepage(page, gfs2_get_block_noalloc, wbc);
- if (ret == -EAGAIN)
- ret = block_write_full_page(page, gfs2_get_block_noalloc, wbc);
- return ret;
+ return nobh_writepage(page, gfs2_get_block_noalloc, wbc);
}
/**
@@ -637,9 +634,7 @@ static int gfs2_write_begin(struct file *file, struct address_space *mapping,
}
}
- error = gfs2_write_alloc_required(ip, pos, len, &alloc_required);
- if (error)
- goto out_unlock;
+ alloc_required = gfs2_write_alloc_required(ip, pos, len);
if (alloc_required || gfs2_is_jdata(ip))
gfs2_write_calc_reserv(ip, len, &data_blocks, &ind_blocks);
diff --git a/fs/gfs2/bmap.c b/fs/gfs2/bmap.c
index 84da64b551b..6f482809d1a 100644
--- a/fs/gfs2/bmap.c
+++ b/fs/gfs2/bmap.c
@@ -1040,7 +1040,7 @@ static int trunc_start(struct gfs2_inode *ip, u64 size)
goto out;
if (gfs2_is_stuffed(ip)) {
- u64 dsize = size + sizeof(struct gfs2_inode);
+ u64 dsize = size + sizeof(struct gfs2_dinode);
ip->i_disksize = size;
ip->i_inode.i_mtime = ip->i_inode.i_ctime = CURRENT_TIME;
gfs2_trans_add_bh(ip->i_gl, dibh, 1);
@@ -1244,13 +1244,12 @@ int gfs2_file_dealloc(struct gfs2_inode *ip)
* @ip: the file being written to
* @offset: the offset to write to
* @len: the number of bytes being written
- * @alloc_required: set to 1 if an alloc is required, 0 otherwise
*
- * Returns: errno
+ * Returns: 1 if an alloc is required, 0 otherwise
*/
int gfs2_write_alloc_required(struct gfs2_inode *ip, u64 offset,
- unsigned int len, int *alloc_required)
+ unsigned int len)
{
struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
struct buffer_head bh;
@@ -1258,26 +1257,23 @@ int gfs2_write_alloc_required(struct gfs2_inode *ip, u64 offset,
u64 lblock, lblock_stop, size;
u64 end_of_file;
- *alloc_required = 0;
-
if (!len)
return 0;
if (gfs2_is_stuffed(ip)) {
if (offset + len >
sdp->sd_sb.sb_bsize - sizeof(struct gfs2_dinode))
- *alloc_required = 1;
+ return 1;
return 0;
}
- *alloc_required = 1;
shift = sdp->sd_sb.sb_bsize_shift;
BUG_ON(gfs2_is_dir(ip));
end_of_file = (ip->i_disksize + sdp->sd_sb.sb_bsize - 1) >> shift;
lblock = offset >> shift;
lblock_stop = (offset + len + sdp->sd_sb.sb_bsize - 1) >> shift;
if (lblock_stop > end_of_file)
- return 0;
+ return 1;
size = (lblock_stop - lblock) << shift;
do {
@@ -1285,12 +1281,11 @@ int gfs2_write_alloc_required(struct gfs2_inode *ip, u64 offset,
bh.b_size = size;
gfs2_block_map(&ip->i_inode, lblock, &bh, 0);
if (!buffer_mapped(&bh))
- return 0;
+ return 1;
size -= bh.b_size;
lblock += (bh.b_size >> ip->i_inode.i_blkbits);
} while(size > 0);
- *alloc_required = 0;
return 0;
}
diff --git a/fs/gfs2/bmap.h b/fs/gfs2/bmap.h
index c983177e05a..a20a5213135 100644
--- a/fs/gfs2/bmap.h
+++ b/fs/gfs2/bmap.h
@@ -52,6 +52,6 @@ int gfs2_truncatei(struct gfs2_inode *ip, u64 size);
int gfs2_truncatei_resume(struct gfs2_inode *ip);
int gfs2_file_dealloc(struct gfs2_inode *ip);
int gfs2_write_alloc_required(struct gfs2_inode *ip, u64 offset,
- unsigned int len, int *alloc_required);
+ unsigned int len);
#endif /* __BMAP_DOT_H__ */
diff --git a/fs/gfs2/dir.c b/fs/gfs2/dir.c
index 6b48d7c268b..b9dd88a78dd 100644
--- a/fs/gfs2/dir.c
+++ b/fs/gfs2/dir.c
@@ -955,7 +955,12 @@ static int dir_split_leaf(struct inode *inode, const struct qstr *name)
/* Change the pointers.
Don't bother distinguishing stuffed from non-stuffed.
This code is complicated enough already. */
- lp = kmalloc(half_len * sizeof(__be64), GFP_NOFS | __GFP_NOFAIL);
+ lp = kmalloc(half_len * sizeof(__be64), GFP_NOFS);
+ if (!lp) {
+ error = -ENOMEM;
+ goto fail_brelse;
+ }
+
/* Change the pointers */
for (x = 0; x < half_len; x++)
lp[x] = cpu_to_be64(bn);
@@ -1063,7 +1068,9 @@ static int dir_double_exhash(struct gfs2_inode *dip)
/* Allocate both the "from" and "to" buffers in one big chunk */
- buf = kcalloc(3, sdp->sd_hash_bsize, GFP_NOFS | __GFP_NOFAIL);
+ buf = kcalloc(3, sdp->sd_hash_bsize, GFP_NOFS);
+ if (!buf)
+ return -ENOMEM;
for (block = dip->i_disksize >> sdp->sd_hash_bsize_shift; block--;) {
error = gfs2_dir_read_data(dip, (char *)buf,
diff --git a/fs/gfs2/file.c b/fs/gfs2/file.c
index ed9a94f0ef1..4edd662c823 100644
--- a/fs/gfs2/file.c
+++ b/fs/gfs2/file.c
@@ -351,7 +351,6 @@ static int gfs2_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf)
unsigned long last_index;
u64 pos = page->index << PAGE_CACHE_SHIFT;
unsigned int data_blocks, ind_blocks, rblocks;
- int alloc_required = 0;
struct gfs2_holder gh;
struct gfs2_alloc *al;
int ret;
@@ -364,8 +363,7 @@ static int gfs2_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf)
set_bit(GLF_DIRTY, &ip->i_gl->gl_flags);
set_bit(GIF_SW_PAGED, &ip->i_flags);
- ret = gfs2_write_alloc_required(ip, pos, PAGE_CACHE_SIZE, &alloc_required);
- if (ret || !alloc_required)
+ if (!gfs2_write_alloc_required(ip, pos, PAGE_CACHE_SIZE))
goto out_unlock;
ret = -ENOMEM;
al = gfs2_alloc_get(ip);
diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c
index 0898f3ec821..9adf8f924e0 100644
--- a/fs/gfs2/glock.c
+++ b/fs/gfs2/glock.c
@@ -328,6 +328,30 @@ static void gfs2_holder_wake(struct gfs2_holder *gh)
}
/**
+ * do_error - Something unexpected has happened during a lock request
+ *
+ */
+
+static inline void do_error(struct gfs2_glock *gl, const int ret)
+{
+ struct gfs2_holder *gh, *tmp;
+
+ list_for_each_entry_safe(gh, tmp, &gl->gl_holders, gh_list) {
+ if (test_bit(HIF_HOLDER, &gh->gh_iflags))
+ continue;
+ if (ret & LM_OUT_ERROR)
+ gh->gh_error = -EIO;
+ else if (gh->gh_flags & (LM_FLAG_TRY | LM_FLAG_TRY_1CB))
+ gh->gh_error = GLR_TRYFAILED;
+ else
+ continue;
+ list_del_init(&gh->gh_list);
+ trace_gfs2_glock_queue(gh, 0);
+ gfs2_holder_wake(gh);
+ }
+}
+
+/**
* do_promote - promote as many requests as possible on the current queue
* @gl: The glock
*
@@ -375,36 +399,13 @@ restart:
}
if (gh->gh_list.prev == &gl->gl_holders)
return 1;
+ do_error(gl, 0);
break;
}
return 0;
}
/**
- * do_error - Something unexpected has happened during a lock request
- *
- */
-
-static inline void do_error(struct gfs2_glock *gl, const int ret)
-{
- struct gfs2_holder *gh, *tmp;
-
- list_for_each_entry_safe(gh, tmp, &gl->gl_holders, gh_list) {
- if (test_bit(HIF_HOLDER, &gh->gh_iflags))
- continue;
- if (ret & LM_OUT_ERROR)
- gh->gh_error = -EIO;
- else if (gh->gh_flags & (LM_FLAG_TRY | LM_FLAG_TRY_1CB))
- gh->gh_error = GLR_TRYFAILED;
- else
- continue;
- list_del_init(&gh->gh_list);
- trace_gfs2_glock_queue(gh, 0);
- gfs2_holder_wake(gh);
- }
-}
-
-/**
* find_first_waiter - find the first gh that's waiting for the glock
* @gl: the glock
*/
@@ -706,18 +707,8 @@ static void glock_work_func(struct work_struct *work)
{
unsigned long delay = 0;
struct gfs2_glock *gl = container_of(work, struct gfs2_glock, gl_work.work);
- struct gfs2_holder *gh;
int drop_ref = 0;
- if (unlikely(test_bit(GLF_FROZEN, &gl->gl_flags))) {
- spin_lock(&gl->gl_spin);
- gh = find_first_waiter(gl);
- if (gh && (gh->gh_flags & LM_FLAG_NOEXP) &&
- test_and_clear_bit(GLF_FROZEN, &gl->gl_flags))
- set_bit(GLF_REPLY_PENDING, &gl->gl_flags);
- spin_unlock(&gl->gl_spin);
- }
-
if (test_and_clear_bit(GLF_REPLY_PENDING, &gl->gl_flags)) {
finish_xmote(gl, gl->gl_reply);
drop_ref = 1;
@@ -1072,6 +1063,9 @@ int gfs2_glock_nq(struct gfs2_holder *gh)
spin_lock(&gl->gl_spin);
add_to_queue(gh);
+ if ((LM_FLAG_NOEXP & gh->gh_flags) &&
+ test_and_clear_bit(GLF_FROZEN, &gl->gl_flags))
+ set_bit(GLF_REPLY_PENDING, &gl->gl_flags);
run_queue(gl, 1);
spin_unlock(&gl->gl_spin);
@@ -1329,6 +1323,36 @@ void gfs2_glock_cb(struct gfs2_glock *gl, unsigned int state)
}
/**
+ * gfs2_should_freeze - Figure out if glock should be frozen
+ * @gl: The glock in question
+ *
+ * Glocks are not frozen if (a) the result of the dlm operation is
+ * an error, (b) the locking operation was an unlock operation or
+ * (c) if there is a "noexp" flagged request anywhere in the queue
+ *
+ * Returns: 1 if freezing should occur, 0 otherwise
+ */
+
+static int gfs2_should_freeze(const struct gfs2_glock *gl)
+{
+ const struct gfs2_holder *gh;
+
+ if (gl->gl_reply & ~LM_OUT_ST_MASK)
+ return 0;
+ if (gl->gl_target == LM_ST_UNLOCKED)
+ return 0;
+
+ list_for_each_entry(gh, &gl->gl_holders, gh_list) {
+ if (test_bit(HIF_HOLDER, &gh->gh_iflags))
+ continue;
+ if (LM_FLAG_NOEXP & gh->gh_flags)
+ return 0;
+ }
+
+ return 1;
+}
+
+/**
* gfs2_glock_complete - Callback used by locking
* @gl: Pointer to the glock
* @ret: The return value from the dlm
@@ -1338,18 +1362,17 @@ void gfs2_glock_cb(struct gfs2_glock *gl, unsigned int state)
void gfs2_glock_complete(struct gfs2_glock *gl, int ret)
{
struct lm_lockstruct *ls = &gl->gl_sbd->sd_lockstruct;
+
gl->gl_reply = ret;
+
if (unlikely(test_bit(DFL_BLOCK_LOCKS, &ls->ls_flags))) {
- struct gfs2_holder *gh;
spin_lock(&gl->gl_spin);
- gh = find_first_waiter(gl);
- if ((!(gh && (gh->gh_flags & LM_FLAG_NOEXP)) &&
- (gl->gl_target != LM_ST_UNLOCKED)) ||
- ((ret & ~LM_OUT_ST_MASK) != 0))
+ if (gfs2_should_freeze(gl)) {
set_bit(GLF_FROZEN, &gl->gl_flags);
- spin_unlock(&gl->gl_spin);
- if (test_bit(GLF_FROZEN, &gl->gl_flags))
+ spin_unlock(&gl->gl_spin);
return;
+ }
+ spin_unlock(&gl->gl_spin);
}
set_bit(GLF_REPLY_PENDING, &gl->gl_flags);
gfs2_glock_hold(gl);
diff --git a/fs/gfs2/incore.h b/fs/gfs2/incore.h
index b5d7363b22d..fdbf4b366fa 100644
--- a/fs/gfs2/incore.h
+++ b/fs/gfs2/incore.h
@@ -12,7 +12,6 @@
#include <linux/fs.h>
#include <linux/workqueue.h>
-#include <linux/slow-work.h>
#include <linux/dlm.h>
#include <linux/buffer_head.h>
@@ -383,7 +382,7 @@ struct gfs2_journal_extent {
struct gfs2_jdesc {
struct list_head jd_list;
struct list_head extent_list;
- struct slow_work jd_work;
+ struct work_struct jd_work;
struct inode *jd_inode;
unsigned long jd_flags;
#define JDF_RECOVERY 1
@@ -460,6 +459,7 @@ enum {
SDF_NOBARRIERS = 3,
SDF_NORECOVERY = 4,
SDF_DEMOTE = 5,
+ SDF_NOJOURNALID = 6,
};
#define GFS2_FSNAME_LEN 256
diff --git a/fs/gfs2/main.c b/fs/gfs2/main.c
index fb2a5f93b7c..b1e9630eb46 100644
--- a/fs/gfs2/main.c
+++ b/fs/gfs2/main.c
@@ -15,7 +15,6 @@
#include <linux/init.h>
#include <linux/gfs2_ondisk.h>
#include <asm/atomic.h>
-#include <linux/slow-work.h>
#include "gfs2.h"
#include "incore.h"
@@ -24,6 +23,7 @@
#include "util.h"
#include "glock.h"
#include "quota.h"
+#include "recovery.h"
static struct shrinker qd_shrinker = {
.shrink = gfs2_shrink_qd_memory,
@@ -138,9 +138,11 @@ static int __init init_gfs2_fs(void)
if (error)
goto fail_unregister;
- error = slow_work_register_user(THIS_MODULE);
- if (error)
- goto fail_slow;
+ error = -ENOMEM;
+ gfs_recovery_wq = alloc_workqueue("gfs_recovery",
+ WQ_NON_REENTRANT | WQ_RESCUER, 0);
+ if (!gfs_recovery_wq)
+ goto fail_wq;
gfs2_register_debugfs();
@@ -148,7 +150,7 @@ static int __init init_gfs2_fs(void)
return 0;
-fail_slow:
+fail_wq:
unregister_filesystem(&gfs2meta_fs_type);
fail_unregister:
unregister_filesystem(&gfs2_fs_type);
@@ -190,7 +192,7 @@ static void __exit exit_gfs2_fs(void)
gfs2_unregister_debugfs();
unregister_filesystem(&gfs2_fs_type);
unregister_filesystem(&gfs2meta_fs_type);
- slow_work_unregister_user(THIS_MODULE);
+ destroy_workqueue(gfs_recovery_wq);
kmem_cache_destroy(gfs2_quotad_cachep);
kmem_cache_destroy(gfs2_rgrpd_cachep);
diff --git a/fs/gfs2/ops_fstype.c b/fs/gfs2/ops_fstype.c
index 3593b3a7290..4f44bdeb2f0 100644
--- a/fs/gfs2/ops_fstype.c
+++ b/fs/gfs2/ops_fstype.c
@@ -17,7 +17,6 @@
#include <linux/namei.h>
#include <linux/mount.h>
#include <linux/gfs2_ondisk.h>
-#include <linux/slow-work.h>
#include <linux/quotaops.h>
#include "gfs2.h"
@@ -76,7 +75,7 @@ static struct gfs2_sbd *init_sbd(struct super_block *sb)
sb->s_fs_info = sdp;
sdp->sd_vfs = sb;
-
+ set_bit(SDF_NOJOURNALID, &sdp->sd_flags);
gfs2_tune_init(&sdp->sd_tune);
init_waitqueue_head(&sdp->sd_glock_wait);
@@ -673,7 +672,7 @@ static int gfs2_jindex_hold(struct gfs2_sbd *sdp, struct gfs2_holder *ji_gh)
break;
INIT_LIST_HEAD(&jd->extent_list);
- slow_work_init(&jd->jd_work, &gfs2_recover_ops);
+ INIT_WORK(&jd->jd_work, gfs2_recover_func);
jd->jd_inode = gfs2_lookupi(sdp->sd_jindex, &name, 1);
if (!jd->jd_inode || IS_ERR(jd->jd_inode)) {
if (!jd->jd_inode)
@@ -782,7 +781,8 @@ static int init_journal(struct gfs2_sbd *sdp, int undo)
if (sdp->sd_lockstruct.ls_first) {
unsigned int x;
for (x = 0; x < sdp->sd_journals; x++) {
- error = gfs2_recover_journal(gfs2_jdesc_find(sdp, x));
+ error = gfs2_recover_journal(gfs2_jdesc_find(sdp, x),
+ true);
if (error) {
fs_err(sdp, "error recovering journal %u: %d\n",
x, error);
@@ -792,7 +792,7 @@ static int init_journal(struct gfs2_sbd *sdp, int undo)
gfs2_others_may_mount(sdp);
} else if (!sdp->sd_args.ar_spectator) {
- error = gfs2_recover_journal(sdp->sd_jdesc);
+ error = gfs2_recover_journal(sdp->sd_jdesc, true);
if (error) {
fs_err(sdp, "error recovering my journal: %d\n", error);
goto fail_jinode_gh;
@@ -1050,7 +1050,8 @@ static int gfs2_lm_mount(struct gfs2_sbd *sdp, int silent)
ret = match_int(&tmp[0], &option);
if (ret || option < 0)
goto hostdata_error;
- ls->ls_jid = option;
+ if (test_and_clear_bit(SDF_NOJOURNALID, &sdp->sd_flags))
+ ls->ls_jid = option;
break;
case Opt_id:
/* Obsolete, but left for backward compat purposes */
@@ -1102,6 +1103,24 @@ void gfs2_lm_unmount(struct gfs2_sbd *sdp)
lm->lm_unmount(sdp);
}
+static int gfs2_journalid_wait(void *word)
+{
+ if (signal_pending(current))
+ return -EINTR;
+ schedule();
+ return 0;
+}
+
+static int wait_on_journal(struct gfs2_sbd *sdp)
+{
+ if (sdp->sd_args.ar_spectator)
+ return 0;
+ if (sdp->sd_lockstruct.ls_ops->lm_mount == NULL)
+ return 0;
+
+ return wait_on_bit(&sdp->sd_flags, SDF_NOJOURNALID, gfs2_journalid_wait, TASK_INTERRUPTIBLE);
+}
+
void gfs2_online_uevent(struct gfs2_sbd *sdp)
{
struct super_block *sb = sdp->sd_vfs;
@@ -1194,6 +1213,10 @@ static int fill_super(struct super_block *sb, struct gfs2_args *args, int silent
if (error)
goto fail_locking;
+ error = wait_on_journal(sdp);
+ if (error)
+ goto fail_sb;
+
error = init_inodes(sdp, DO);
if (error)
goto fail_sb;
diff --git a/fs/gfs2/quota.c b/fs/gfs2/quota.c
index 8f02d3db8f4..1bc6b5695e6 100644
--- a/fs/gfs2/quota.c
+++ b/fs/gfs2/quota.c
@@ -787,15 +787,9 @@ static int do_sync(unsigned int num_qd, struct gfs2_quota_data **qda)
goto out;
for (x = 0; x < num_qd; x++) {
- int alloc_required;
-
offset = qd2offset(qda[x]);
- error = gfs2_write_alloc_required(ip, offset,
- sizeof(struct gfs2_quota),
- &alloc_required);
- if (error)
- goto out_gunlock;
- if (alloc_required)
+ if (gfs2_write_alloc_required(ip, offset,
+ sizeof(struct gfs2_quota)))
nalloc++;
}
@@ -1455,10 +1449,10 @@ static int gfs2_quota_get_xstate(struct super_block *sb,
switch (sdp->sd_args.ar_quota) {
case GFS2_QUOTA_ON:
- fqs->qs_flags |= (XFS_QUOTA_UDQ_ENFD | XFS_QUOTA_GDQ_ENFD);
+ fqs->qs_flags |= (FS_QUOTA_UDQ_ENFD | FS_QUOTA_GDQ_ENFD);
/*FALLTHRU*/
case GFS2_QUOTA_ACCOUNT:
- fqs->qs_flags |= (XFS_QUOTA_UDQ_ACCT | XFS_QUOTA_GDQ_ACCT);
+ fqs->qs_flags |= (FS_QUOTA_UDQ_ACCT | FS_QUOTA_GDQ_ACCT);
break;
case GFS2_QUOTA_OFF:
break;
@@ -1504,7 +1498,7 @@ static int gfs2_get_dqblk(struct super_block *sb, int type, qid_t id,
qlvb = (struct gfs2_quota_lvb *)qd->qd_gl->gl_lvb;
fdq->d_version = FS_DQUOT_VERSION;
- fdq->d_flags = (type == QUOTA_USER) ? XFS_USER_QUOTA : XFS_GROUP_QUOTA;
+ fdq->d_flags = (type == QUOTA_USER) ? FS_USER_QUOTA : FS_GROUP_QUOTA;
fdq->d_id = id;
fdq->d_blk_hardlimit = be64_to_cpu(qlvb->qb_limit);
fdq->d_blk_softlimit = be64_to_cpu(qlvb->qb_warn);
@@ -1539,12 +1533,12 @@ static int gfs2_set_dqblk(struct super_block *sb, int type, qid_t id,
switch(type) {
case USRQUOTA:
type = QUOTA_USER;
- if (fdq->d_flags != XFS_USER_QUOTA)
+ if (fdq->d_flags != FS_USER_QUOTA)
return -EINVAL;
break;
case GRPQUOTA:
type = QUOTA_GROUP;
- if (fdq->d_flags != XFS_GROUP_QUOTA)
+ if (fdq->d_flags != FS_GROUP_QUOTA)
return -EINVAL;
break;
default:
@@ -1584,10 +1578,7 @@ static int gfs2_set_dqblk(struct super_block *sb, int type, qid_t id,
goto out_i;
offset = qd2offset(qd);
- error = gfs2_write_alloc_required(ip, offset, sizeof(struct gfs2_quota),
- &alloc_required);
- if (error)
- goto out_i;
+ alloc_required = gfs2_write_alloc_required(ip, offset, sizeof(struct gfs2_quota));
if (alloc_required) {
al = gfs2_alloc_get(ip);
if (al == NULL)
diff --git a/fs/gfs2/recovery.c b/fs/gfs2/recovery.c
index 4b9bece3d43..f7f89a94a5a 100644
--- a/fs/gfs2/recovery.c
+++ b/fs/gfs2/recovery.c
@@ -14,7 +14,6 @@
#include <linux/buffer_head.h>
#include <linux/gfs2_ondisk.h>
#include <linux/crc32.h>
-#include <linux/slow-work.h>
#include "gfs2.h"
#include "incore.h"
@@ -28,6 +27,8 @@
#include "util.h"
#include "dir.h"
+struct workqueue_struct *gfs_recovery_wq;
+
int gfs2_replay_read_block(struct gfs2_jdesc *jd, unsigned int blk,
struct buffer_head **bh)
{
@@ -443,23 +444,7 @@ static void gfs2_recovery_done(struct gfs2_sbd *sdp, unsigned int jid,
kobject_uevent_env(&sdp->sd_kobj, KOBJ_CHANGE, envp);
}
-static int gfs2_recover_get_ref(struct slow_work *work)
-{
- struct gfs2_jdesc *jd = container_of(work, struct gfs2_jdesc, jd_work);
- if (test_and_set_bit(JDF_RECOVERY, &jd->jd_flags))
- return -EBUSY;
- return 0;
-}
-
-static void gfs2_recover_put_ref(struct slow_work *work)
-{
- struct gfs2_jdesc *jd = container_of(work, struct gfs2_jdesc, jd_work);
- clear_bit(JDF_RECOVERY, &jd->jd_flags);
- smp_mb__after_clear_bit();
- wake_up_bit(&jd->jd_flags, JDF_RECOVERY);
-}
-
-static void gfs2_recover_work(struct slow_work *work)
+void gfs2_recover_func(struct work_struct *work)
{
struct gfs2_jdesc *jd = container_of(work, struct gfs2_jdesc, jd_work);
struct gfs2_inode *ip = GFS2_I(jd->jd_inode);
@@ -578,7 +563,7 @@ static void gfs2_recover_work(struct slow_work *work)
gfs2_glock_dq_uninit(&j_gh);
fs_info(sdp, "jid=%u: Done\n", jd->jd_jid);
- return;
+ goto done;
fail_gunlock_tr:
gfs2_glock_dq_uninit(&t_gh);
@@ -590,32 +575,35 @@ fail_gunlock_j:
}
fs_info(sdp, "jid=%u: %s\n", jd->jd_jid, (error) ? "Failed" : "Done");
-
fail:
gfs2_recovery_done(sdp, jd->jd_jid, LM_RD_GAVEUP);
+done:
+ clear_bit(JDF_RECOVERY, &jd->jd_flags);
+ smp_mb__after_clear_bit();
+ wake_up_bit(&jd->jd_flags, JDF_RECOVERY);
}
-struct slow_work_ops gfs2_recover_ops = {
- .owner = THIS_MODULE,
- .get_ref = gfs2_recover_get_ref,
- .put_ref = gfs2_recover_put_ref,
- .execute = gfs2_recover_work,
-};
-
-
static int gfs2_recovery_wait(void *word)
{
schedule();
return 0;
}
-int gfs2_recover_journal(struct gfs2_jdesc *jd)
+int gfs2_recover_journal(struct gfs2_jdesc *jd, bool wait)
{
int rv;
- rv = slow_work_enqueue(&jd->jd_work);
- if (rv)
- return rv;
- wait_on_bit(&jd->jd_flags, JDF_RECOVERY, gfs2_recovery_wait, TASK_UNINTERRUPTIBLE);
+
+ if (test_and_set_bit(JDF_RECOVERY, &jd->jd_flags))
+ return -EBUSY;
+
+ /* we have JDF_RECOVERY, queue should always succeed */
+ rv = queue_work(gfs_recovery_wq, &jd->jd_work);
+ BUG_ON(!rv);
+
+ if (wait)
+ wait_on_bit(&jd->jd_flags, JDF_RECOVERY, gfs2_recovery_wait,
+ TASK_UNINTERRUPTIBLE);
+
return 0;
}
diff --git a/fs/gfs2/recovery.h b/fs/gfs2/recovery.h
index 1616ac22569..2226136c764 100644
--- a/fs/gfs2/recovery.h
+++ b/fs/gfs2/recovery.h
@@ -12,6 +12,8 @@
#include "incore.h"
+extern struct workqueue_struct *gfs_recovery_wq;
+
static inline void gfs2_replay_incr_blk(struct gfs2_sbd *sdp, unsigned int *blk)
{
if (++*blk == sdp->sd_jdesc->jd_blocks)
@@ -27,8 +29,8 @@ extern void gfs2_revoke_clean(struct gfs2_sbd *sdp);
extern int gfs2_find_jhead(struct gfs2_jdesc *jd,
struct gfs2_log_header_host *head);
-extern int gfs2_recover_journal(struct gfs2_jdesc *gfs2_jd);
-extern struct slow_work_ops gfs2_recover_ops;
+extern int gfs2_recover_journal(struct gfs2_jdesc *gfs2_jd, bool wait);
+extern void gfs2_recover_func(struct work_struct *work);
#endif /* __RECOVERY_DOT_H__ */
diff --git a/fs/gfs2/super.c b/fs/gfs2/super.c
index 4d1aad38f1b..4140811a921 100644
--- a/fs/gfs2/super.c
+++ b/fs/gfs2/super.c
@@ -342,8 +342,6 @@ int gfs2_jdesc_check(struct gfs2_jdesc *jd)
{
struct gfs2_inode *ip = GFS2_I(jd->jd_inode);
struct gfs2_sbd *sdp = GFS2_SB(jd->jd_inode);
- int ar;
- int error;
if (ip->i_disksize < (8 << 20) || ip->i_disksize > (1 << 30) ||
(ip->i_disksize & (sdp->sd_sb.sb_bsize - 1))) {
@@ -352,13 +350,12 @@ int gfs2_jdesc_check(struct gfs2_jdesc *jd)
}
jd->jd_blocks = ip->i_disksize >> sdp->sd_sb.sb_bsize_shift;
- error = gfs2_write_alloc_required(ip, 0, ip->i_disksize, &ar);
- if (!error && ar) {
+ if (gfs2_write_alloc_required(ip, 0, ip->i_disksize)) {
gfs2_consist_inode(ip);
- error = -EIO;
+ return -EIO;
}
- return error;
+ return 0;
}
/**
diff --git a/fs/gfs2/sys.c b/fs/gfs2/sys.c
index 37f5393e68e..ccacffd2faa 100644
--- a/fs/gfs2/sys.c
+++ b/fs/gfs2/sys.c
@@ -25,6 +25,7 @@
#include "quota.h"
#include "util.h"
#include "glops.h"
+#include "recovery.h"
struct gfs2_attr {
struct attribute attr;
@@ -325,6 +326,30 @@ static ssize_t lkfirst_show(struct gfs2_sbd *sdp, char *buf)
return sprintf(buf, "%d\n", ls->ls_first);
}
+static ssize_t lkfirst_store(struct gfs2_sbd *sdp, const char *buf, size_t len)
+{
+ unsigned first;
+ int rv;
+
+ rv = sscanf(buf, "%u", &first);
+ if (rv != 1 || first > 1)
+ return -EINVAL;
+ spin_lock(&sdp->sd_jindex_spin);
+ rv = -EBUSY;
+ if (test_bit(SDF_NOJOURNALID, &sdp->sd_flags) == 0)
+ goto out;
+ rv = -EINVAL;
+ if (sdp->sd_args.ar_spectator)
+ goto out;
+ if (sdp->sd_lockstruct.ls_ops->lm_mount == NULL)
+ goto out;
+ sdp->sd_lockstruct.ls_first = first;
+ rv = 0;
+out:
+ spin_unlock(&sdp->sd_jindex_spin);
+ return rv ? rv : len;
+}
+
static ssize_t first_done_show(struct gfs2_sbd *sdp, char *buf)
{
struct lm_lockstruct *ls = &sdp->sd_lockstruct;
@@ -352,7 +377,7 @@ static ssize_t recover_store(struct gfs2_sbd *sdp, const char *buf, size_t len)
list_for_each_entry(jd, &sdp->sd_jindex_list, jd_list) {
if (jd->jd_jid != jid)
continue;
- rv = slow_work_enqueue(&jd->jd_work);
+ rv = gfs2_recover_journal(jd, false);
break;
}
out:
@@ -377,14 +402,41 @@ static ssize_t jid_show(struct gfs2_sbd *sdp, char *buf)
return sprintf(buf, "%u\n", sdp->sd_lockstruct.ls_jid);
}
+static ssize_t jid_store(struct gfs2_sbd *sdp, const char *buf, size_t len)
+{
+ unsigned jid;
+ int rv;
+
+ rv = sscanf(buf, "%u", &jid);
+ if (rv != 1)
+ return -EINVAL;
+
+ spin_lock(&sdp->sd_jindex_spin);
+ rv = -EINVAL;
+ if (sdp->sd_args.ar_spectator)
+ goto out;
+ if (sdp->sd_lockstruct.ls_ops->lm_mount == NULL)
+ goto out;
+ rv = -EBUSY;
+ if (test_and_clear_bit(SDF_NOJOURNALID, &sdp->sd_flags) == 0)
+ goto out;
+ sdp->sd_lockstruct.ls_jid = jid;
+ smp_mb__after_clear_bit();
+ wake_up_bit(&sdp->sd_flags, SDF_NOJOURNALID);
+ rv = 0;
+out:
+ spin_unlock(&sdp->sd_jindex_spin);
+ return rv ? rv : len;
+}
+
#define GDLM_ATTR(_name,_mode,_show,_store) \
static struct gfs2_attr gdlm_attr_##_name = __ATTR(_name,_mode,_show,_store)
GDLM_ATTR(proto_name, 0444, proto_name_show, NULL);
GDLM_ATTR(block, 0644, block_show, block_store);
GDLM_ATTR(withdraw, 0644, withdraw_show, withdraw_store);
-GDLM_ATTR(jid, 0444, jid_show, NULL);
-GDLM_ATTR(first, 0444, lkfirst_show, NULL);
+GDLM_ATTR(jid, 0644, jid_show, jid_store);
+GDLM_ATTR(first, 0644, lkfirst_show, lkfirst_store);
GDLM_ATTR(first_done, 0444, first_done_show, NULL);
GDLM_ATTR(recover, 0600, NULL, recover_store);
GDLM_ATTR(recover_done, 0444, recover_done_show, NULL);
@@ -564,7 +616,7 @@ static int gfs2_uevent(struct kset *kset, struct kobject *kobj,
add_uevent_var(env, "LOCKTABLE=%s", sdp->sd_table_name);
add_uevent_var(env, "LOCKPROTO=%s", sdp->sd_proto_name);
- if (!sdp->sd_args.ar_spectator)
+ if (!test_bit(SDF_NOJOURNALID, &sdp->sd_flags))
add_uevent_var(env, "JOURNALID=%u", sdp->sd_lockstruct.ls_jid);
if (gfs2_uuid_valid(uuid))
add_uevent_var(env, "UUID=%pUB", uuid);
diff --git a/fs/jbd/journal.c b/fs/jbd/journal.c
index 93d1e47647b..f19ce94693d 100644
--- a/fs/jbd/journal.c
+++ b/fs/jbd/journal.c
@@ -1281,13 +1281,9 @@ int journal_check_used_features (journal_t *journal, unsigned long compat,
int journal_check_available_features (journal_t *journal, unsigned long compat,
unsigned long ro, unsigned long incompat)
{
- journal_superblock_t *sb;
-
if (!compat && !ro && !incompat)
return 1;
- sb = journal->j_superblock;
-
/* We can support any known requested features iff the
* superblock is in version 2. Otherwise we fail to support any
* extended sb features. */
@@ -1481,7 +1477,6 @@ int journal_flush(journal_t *journal)
int journal_wipe(journal_t *journal, int write)
{
- journal_superblock_t *sb;
int err = 0;
J_ASSERT (!(journal->j_flags & JFS_LOADED));
@@ -1490,8 +1485,6 @@ int journal_wipe(journal_t *journal, int write)
if (err)
return err;
- sb = journal->j_superblock;
-
if (!journal->j_tail)
goto no_recovery;
diff --git a/fs/jbd/recovery.c b/fs/jbd/recovery.c
index 54c9bc9e1b1..81051dafebf 100644
--- a/fs/jbd/recovery.c
+++ b/fs/jbd/recovery.c
@@ -283,12 +283,9 @@ int journal_recover(journal_t *journal)
int journal_skip_recovery(journal_t *journal)
{
int err;
- journal_superblock_t * sb;
-
struct recovery_info info;
memset (&info, 0, sizeof(info));
- sb = journal->j_superblock;
err = do_one_pass(journal, &info, PASS_SCAN);
@@ -297,7 +294,8 @@ int journal_skip_recovery(journal_t *journal)
++journal->j_transaction_sequence;
} else {
#ifdef CONFIG_JBD_DEBUG
- int dropped = info.end_transaction - be32_to_cpu(sb->s_sequence);
+ int dropped = info.end_transaction -
+ be32_to_cpu(journal->j_superblock->s_sequence);
#endif
jbd_debug(1,
"JBD: ignoring %d transaction%s from the journal.\n",
@@ -321,11 +319,6 @@ static int do_one_pass(journal_t *journal,
unsigned int sequence;
int blocktype;
- /* Precompute the maximum metadata descriptors in a descriptor block */
- int MAX_BLOCKS_PER_DESC;
- MAX_BLOCKS_PER_DESC = ((journal->j_blocksize-sizeof(journal_header_t))
- / sizeof(journal_block_tag_t));
-
/*
* First thing is to establish what we expect to find in the log
* (in terms of transaction IDs), and where (in terms of log
diff --git a/fs/jbd2/checkpoint.c b/fs/jbd2/checkpoint.c
index 076d1cc44f9..1c23a0f4e8a 100644
--- a/fs/jbd2/checkpoint.c
+++ b/fs/jbd2/checkpoint.c
@@ -118,13 +118,13 @@ static int __try_to_free_cp_buf(struct journal_head *jh)
void __jbd2_log_wait_for_space(journal_t *journal)
{
int nblocks, space_left;
- assert_spin_locked(&journal->j_state_lock);
+ /* assert_spin_locked(&journal->j_state_lock); */
nblocks = jbd_space_needed(journal);
while (__jbd2_log_space_left(journal) < nblocks) {
if (journal->j_flags & JBD2_ABORT)
return;
- spin_unlock(&journal->j_state_lock);
+ write_unlock(&journal->j_state_lock);
mutex_lock(&journal->j_checkpoint_mutex);
/*
@@ -138,7 +138,7 @@ void __jbd2_log_wait_for_space(journal_t *journal)
* filesystem, so abort the journal and leave a stack
* trace for forensic evidence.
*/
- spin_lock(&journal->j_state_lock);
+ write_lock(&journal->j_state_lock);
spin_lock(&journal->j_list_lock);
nblocks = jbd_space_needed(journal);
space_left = __jbd2_log_space_left(journal);
@@ -149,7 +149,7 @@ void __jbd2_log_wait_for_space(journal_t *journal)
if (journal->j_committing_transaction)
tid = journal->j_committing_transaction->t_tid;
spin_unlock(&journal->j_list_lock);
- spin_unlock(&journal->j_state_lock);
+ write_unlock(&journal->j_state_lock);
if (chkpt) {
jbd2_log_do_checkpoint(journal);
} else if (jbd2_cleanup_journal_tail(journal) == 0) {
@@ -167,7 +167,7 @@ void __jbd2_log_wait_for_space(journal_t *journal)
WARN_ON(1);
jbd2_journal_abort(journal, 0);
}
- spin_lock(&journal->j_state_lock);
+ write_lock(&journal->j_state_lock);
} else {
spin_unlock(&journal->j_list_lock);
}
@@ -474,7 +474,7 @@ int jbd2_cleanup_journal_tail(journal_t *journal)
* next transaction ID we will write, and where it will
* start. */
- spin_lock(&journal->j_state_lock);
+ write_lock(&journal->j_state_lock);
spin_lock(&journal->j_list_lock);
transaction = journal->j_checkpoint_transactions;
if (transaction) {
@@ -496,7 +496,7 @@ int jbd2_cleanup_journal_tail(journal_t *journal)
/* If the oldest pinned transaction is at the tail of the log
already then there's not much we can do right now. */
if (journal->j_tail_sequence == first_tid) {
- spin_unlock(&journal->j_state_lock);
+ write_unlock(&journal->j_state_lock);
return 1;
}
@@ -516,7 +516,7 @@ int jbd2_cleanup_journal_tail(journal_t *journal)
journal->j_free += freed;
journal->j_tail_sequence = first_tid;
journal->j_tail = blocknr;
- spin_unlock(&journal->j_state_lock);
+ write_unlock(&journal->j_state_lock);
/*
* If there is an external journal, we need to make sure that
@@ -775,7 +775,7 @@ void __jbd2_journal_drop_transaction(journal_t *journal, transaction_t *transact
J_ASSERT(transaction->t_log_list == NULL);
J_ASSERT(transaction->t_checkpoint_list == NULL);
J_ASSERT(transaction->t_checkpoint_io_list == NULL);
- J_ASSERT(transaction->t_updates == 0);
+ J_ASSERT(atomic_read(&transaction->t_updates) == 0);
J_ASSERT(journal->j_committing_transaction != transaction);
J_ASSERT(journal->j_running_transaction != transaction);
diff --git a/fs/jbd2/commit.c b/fs/jbd2/commit.c
index 75716d3d2be..f52e5e8049f 100644
--- a/fs/jbd2/commit.c
+++ b/fs/jbd2/commit.c
@@ -150,11 +150,11 @@ static int journal_submit_commit_record(journal_t *journal,
*/
if (ret == -EOPNOTSUPP && barrier_done) {
printk(KERN_WARNING
- "JBD: barrier-based sync failed on %s - "
- "disabling barriers\n", journal->j_devname);
- spin_lock(&journal->j_state_lock);
+ "JBD2: Disabling barriers on %s, "
+ "not supported by device\n", journal->j_devname);
+ write_lock(&journal->j_state_lock);
journal->j_flags &= ~JBD2_BARRIER;
- spin_unlock(&journal->j_state_lock);
+ write_unlock(&journal->j_state_lock);
/* And try again, without the barrier */
lock_buffer(bh);
@@ -180,11 +180,11 @@ retry:
wait_on_buffer(bh);
if (buffer_eopnotsupp(bh) && (journal->j_flags & JBD2_BARRIER)) {
printk(KERN_WARNING
- "JBD2: wait_on_commit_record: sync failed on %s - "
- "disabling barriers\n", journal->j_devname);
- spin_lock(&journal->j_state_lock);
+ "JBD2: %s: disabling barries on %s - not supported "
+ "by device\n", __func__, journal->j_devname);
+ write_lock(&journal->j_state_lock);
journal->j_flags &= ~JBD2_BARRIER;
- spin_unlock(&journal->j_state_lock);
+ write_unlock(&journal->j_state_lock);
lock_buffer(bh);
clear_buffer_dirty(bh);
@@ -400,7 +400,7 @@ void jbd2_journal_commit_transaction(journal_t *journal)
jbd_debug(1, "JBD: starting commit of transaction %d\n",
commit_transaction->t_tid);
- spin_lock(&journal->j_state_lock);
+ write_lock(&journal->j_state_lock);
commit_transaction->t_state = T_LOCKED;
/*
@@ -417,23 +417,23 @@ void jbd2_journal_commit_transaction(journal_t *journal)
stats.run.rs_locked);
spin_lock(&commit_transaction->t_handle_lock);
- while (commit_transaction->t_updates) {
+ while (atomic_read(&commit_transaction->t_updates)) {
DEFINE_WAIT(wait);
prepare_to_wait(&journal->j_wait_updates, &wait,
TASK_UNINTERRUPTIBLE);
- if (commit_transaction->t_updates) {
+ if (atomic_read(&commit_transaction->t_updates)) {
spin_unlock(&commit_transaction->t_handle_lock);
- spin_unlock(&journal->j_state_lock);
+ write_unlock(&journal->j_state_lock);
schedule();
- spin_lock(&journal->j_state_lock);
+ write_lock(&journal->j_state_lock);
spin_lock(&commit_transaction->t_handle_lock);
}
finish_wait(&journal->j_wait_updates, &wait);
}
spin_unlock(&commit_transaction->t_handle_lock);
- J_ASSERT (commit_transaction->t_outstanding_credits <=
+ J_ASSERT (atomic_read(&commit_transaction->t_outstanding_credits) <=
journal->j_max_transaction_buffers);
/*
@@ -497,7 +497,7 @@ void jbd2_journal_commit_transaction(journal_t *journal)
start_time = ktime_get();
commit_transaction->t_log_start = journal->j_head;
wake_up(&journal->j_wait_transaction_locked);
- spin_unlock(&journal->j_state_lock);
+ write_unlock(&journal->j_state_lock);
jbd_debug (3, "JBD: commit phase 2\n");
@@ -519,19 +519,20 @@ void jbd2_journal_commit_transaction(journal_t *journal)
* transaction! Now comes the tricky part: we need to write out
* metadata. Loop over the transaction's entire buffer list:
*/
- spin_lock(&journal->j_state_lock);
+ write_lock(&journal->j_state_lock);
commit_transaction->t_state = T_COMMIT;
- spin_unlock(&journal->j_state_lock);
+ write_unlock(&journal->j_state_lock);
trace_jbd2_commit_logging(journal, commit_transaction);
stats.run.rs_logging = jiffies;
stats.run.rs_flushing = jbd2_time_diff(stats.run.rs_flushing,
stats.run.rs_logging);
- stats.run.rs_blocks = commit_transaction->t_outstanding_credits;
+ stats.run.rs_blocks =
+ atomic_read(&commit_transaction->t_outstanding_credits);
stats.run.rs_blocks_logged = 0;
J_ASSERT(commit_transaction->t_nr_buffers <=
- commit_transaction->t_outstanding_credits);
+ atomic_read(&commit_transaction->t_outstanding_credits));
err = 0;
descriptor = NULL;
@@ -616,7 +617,7 @@ void jbd2_journal_commit_transaction(journal_t *journal)
* the free space in the log, but this counter is changed
* by jbd2_journal_next_log_block() also.
*/
- commit_transaction->t_outstanding_credits--;
+ atomic_dec(&commit_transaction->t_outstanding_credits);
/* Bump b_count to prevent truncate from stumbling over
the shadowed buffer! @@@ This can go if we ever get
@@ -977,7 +978,7 @@ restart_loop:
* __jbd2_journal_drop_transaction(). Otherwise we could race with
* other checkpointing code processing the transaction...
*/
- spin_lock(&journal->j_state_lock);
+ write_lock(&journal->j_state_lock);
spin_lock(&journal->j_list_lock);
/*
* Now recheck if some buffers did not get attached to the transaction
@@ -985,7 +986,7 @@ restart_loop:
*/
if (commit_transaction->t_forget) {
spin_unlock(&journal->j_list_lock);
- spin_unlock(&journal->j_state_lock);
+ write_unlock(&journal->j_state_lock);
goto restart_loop;
}
@@ -1003,7 +1004,8 @@ restart_loop:
* File the transaction statistics
*/
stats.ts_tid = commit_transaction->t_tid;
- stats.run.rs_handle_count = commit_transaction->t_handle_count;
+ stats.run.rs_handle_count =
+ atomic_read(&commit_transaction->t_handle_count);
trace_jbd2_run_stats(journal->j_fs_dev->bd_dev,
commit_transaction->t_tid, &stats.run);
@@ -1037,7 +1039,7 @@ restart_loop:
journal->j_average_commit_time*3) / 4;
else
journal->j_average_commit_time = commit_time;
- spin_unlock(&journal->j_state_lock);
+ write_unlock(&journal->j_state_lock);
if (commit_transaction->t_checkpoint_list == NULL &&
commit_transaction->t_checkpoint_io_list == NULL) {
diff --git a/fs/jbd2/journal.c b/fs/jbd2/journal.c
index 036880895bf..ad5866aaf0f 100644
--- a/fs/jbd2/journal.c
+++ b/fs/jbd2/journal.c
@@ -41,6 +41,7 @@
#include <linux/hash.h>
#include <linux/log2.h>
#include <linux/vmalloc.h>
+#include <linux/backing-dev.h>
#define CREATE_TRACE_POINTS
#include <trace/events/jbd2.h>
@@ -48,8 +49,6 @@
#include <asm/uaccess.h>
#include <asm/page.h>
-EXPORT_SYMBOL(jbd2_journal_start);
-EXPORT_SYMBOL(jbd2_journal_restart);
EXPORT_SYMBOL(jbd2_journal_extend);
EXPORT_SYMBOL(jbd2_journal_stop);
EXPORT_SYMBOL(jbd2_journal_lock_updates);
@@ -143,7 +142,7 @@ static int kjournald2(void *arg)
/*
* And now, wait forever for commit wakeup events.
*/
- spin_lock(&journal->j_state_lock);
+ write_lock(&journal->j_state_lock);
loop:
if (journal->j_flags & JBD2_UNMOUNT)
@@ -154,10 +153,10 @@ loop:
if (journal->j_commit_sequence != journal->j_commit_request) {
jbd_debug(1, "OK, requests differ\n");
- spin_unlock(&journal->j_state_lock);
+ write_unlock(&journal->j_state_lock);
del_timer_sync(&journal->j_commit_timer);
jbd2_journal_commit_transaction(journal);
- spin_lock(&journal->j_state_lock);
+ write_lock(&journal->j_state_lock);
goto loop;
}
@@ -169,9 +168,9 @@ loop:
* be already stopped.
*/
jbd_debug(1, "Now suspending kjournald2\n");
- spin_unlock(&journal->j_state_lock);
+ write_unlock(&journal->j_state_lock);
refrigerator();
- spin_lock(&journal->j_state_lock);
+ write_lock(&journal->j_state_lock);
} else {
/*
* We assume on resume that commits are already there,
@@ -191,9 +190,9 @@ loop:
if (journal->j_flags & JBD2_UNMOUNT)
should_sleep = 0;
if (should_sleep) {
- spin_unlock(&journal->j_state_lock);
+ write_unlock(&journal->j_state_lock);
schedule();
- spin_lock(&journal->j_state_lock);
+ write_lock(&journal->j_state_lock);
}
finish_wait(&journal->j_wait_commit, &wait);
}
@@ -211,7 +210,7 @@ loop:
goto loop;
end_loop:
- spin_unlock(&journal->j_state_lock);
+ write_unlock(&journal->j_state_lock);
del_timer_sync(&journal->j_commit_timer);
journal->j_task = NULL;
wake_up(&journal->j_wait_done_commit);
@@ -234,16 +233,16 @@ static int jbd2_journal_start_thread(journal_t *journal)
static void journal_kill_thread(journal_t *journal)
{
- spin_lock(&journal->j_state_lock);
+ write_lock(&journal->j_state_lock);
journal->j_flags |= JBD2_UNMOUNT;
while (journal->j_task) {
wake_up(&journal->j_wait_commit);
- spin_unlock(&journal->j_state_lock);
+ write_unlock(&journal->j_state_lock);
wait_event(journal->j_wait_done_commit, journal->j_task == NULL);
- spin_lock(&journal->j_state_lock);
+ write_lock(&journal->j_state_lock);
}
- spin_unlock(&journal->j_state_lock);
+ write_unlock(&journal->j_state_lock);
}
/*
@@ -310,7 +309,17 @@ int jbd2_journal_write_metadata_buffer(transaction_t *transaction,
*/
J_ASSERT_BH(bh_in, buffer_jbddirty(bh_in));
- new_bh = alloc_buffer_head(GFP_NOFS|__GFP_NOFAIL);
+retry_alloc:
+ new_bh = alloc_buffer_head(GFP_NOFS);
+ if (!new_bh) {
+ /*
+ * Failure is not an option, but __GFP_NOFAIL is going
+ * away; so we retry ourselves here.
+ */
+ congestion_wait(BLK_RW_ASYNC, HZ/50);
+ goto retry_alloc;
+ }
+
/* keep subsequent assertions sane */
new_bh->b_state = 0;
init_buffer(new_bh, NULL, NULL);
@@ -442,7 +451,7 @@ int __jbd2_log_space_left(journal_t *journal)
{
int left = journal->j_free;
- assert_spin_locked(&journal->j_state_lock);
+ /* assert_spin_locked(&journal->j_state_lock); */
/*
* Be pessimistic here about the number of those free blocks which
@@ -487,9 +496,9 @@ int jbd2_log_start_commit(journal_t *journal, tid_t tid)
{
int ret;
- spin_lock(&journal->j_state_lock);
+ write_lock(&journal->j_state_lock);
ret = __jbd2_log_start_commit(journal, tid);
- spin_unlock(&journal->j_state_lock);
+ write_unlock(&journal->j_state_lock);
return ret;
}
@@ -508,7 +517,7 @@ int jbd2_journal_force_commit_nested(journal_t *journal)
transaction_t *transaction = NULL;
tid_t tid;
- spin_lock(&journal->j_state_lock);
+ read_lock(&journal->j_state_lock);
if (journal->j_running_transaction && !current->journal_info) {
transaction = journal->j_running_transaction;
__jbd2_log_start_commit(journal, transaction->t_tid);
@@ -516,12 +525,12 @@ int jbd2_journal_force_commit_nested(journal_t *journal)
transaction = journal->j_committing_transaction;
if (!transaction) {
- spin_unlock(&journal->j_state_lock);
+ read_unlock(&journal->j_state_lock);
return 0; /* Nothing to retry */
}
tid = transaction->t_tid;
- spin_unlock(&journal->j_state_lock);
+ read_unlock(&journal->j_state_lock);
jbd2_log_wait_commit(journal, tid);
return 1;
}
@@ -535,7 +544,7 @@ int jbd2_journal_start_commit(journal_t *journal, tid_t *ptid)
{
int ret = 0;
- spin_lock(&journal->j_state_lock);
+ write_lock(&journal->j_state_lock);
if (journal->j_running_transaction) {
tid_t tid = journal->j_running_transaction->t_tid;
@@ -554,7 +563,7 @@ int jbd2_journal_start_commit(journal_t *journal, tid_t *ptid)
*ptid = journal->j_committing_transaction->t_tid;
ret = 1;
}
- spin_unlock(&journal->j_state_lock);
+ write_unlock(&journal->j_state_lock);
return ret;
}
@@ -566,26 +575,24 @@ int jbd2_log_wait_commit(journal_t *journal, tid_t tid)
{
int err = 0;
+ read_lock(&journal->j_state_lock);
#ifdef CONFIG_JBD2_DEBUG
- spin_lock(&journal->j_state_lock);
if (!tid_geq(journal->j_commit_request, tid)) {
printk(KERN_EMERG
"%s: error: j_commit_request=%d, tid=%d\n",
__func__, journal->j_commit_request, tid);
}
- spin_unlock(&journal->j_state_lock);
#endif
- spin_lock(&journal->j_state_lock);
while (tid_gt(tid, journal->j_commit_sequence)) {
jbd_debug(1, "JBD: want %d, j_commit_sequence=%d\n",
tid, journal->j_commit_sequence);
wake_up(&journal->j_wait_commit);
- spin_unlock(&journal->j_state_lock);
+ read_unlock(&journal->j_state_lock);
wait_event(journal->j_wait_done_commit,
!tid_gt(tid, journal->j_commit_sequence));
- spin_lock(&journal->j_state_lock);
+ read_lock(&journal->j_state_lock);
}
- spin_unlock(&journal->j_state_lock);
+ read_unlock(&journal->j_state_lock);
if (unlikely(is_journal_aborted(journal))) {
printk(KERN_EMERG "journal commit I/O error\n");
@@ -602,7 +609,7 @@ int jbd2_journal_next_log_block(journal_t *journal, unsigned long long *retp)
{
unsigned long blocknr;
- spin_lock(&journal->j_state_lock);
+ write_lock(&journal->j_state_lock);
J_ASSERT(journal->j_free > 1);
blocknr = journal->j_head;
@@ -610,7 +617,7 @@ int jbd2_journal_next_log_block(journal_t *journal, unsigned long long *retp)
journal->j_free--;
if (journal->j_head == journal->j_last)
journal->j_head = journal->j_first;
- spin_unlock(&journal->j_state_lock);
+ write_unlock(&journal->j_state_lock);
return jbd2_journal_bmap(journal, blocknr, retp);
}
@@ -830,7 +837,7 @@ static journal_t * journal_init_common (void)
mutex_init(&journal->j_checkpoint_mutex);
spin_lock_init(&journal->j_revoke_lock);
spin_lock_init(&journal->j_list_lock);
- spin_lock_init(&journal->j_state_lock);
+ rwlock_init(&journal->j_state_lock);
journal->j_commit_interval = (HZ * JBD2_DEFAULT_MAX_COMMIT_AGE);
journal->j_min_batch_time = 0;
@@ -1096,14 +1103,14 @@ void jbd2_journal_update_superblock(journal_t *journal, int wait)
set_buffer_uptodate(bh);
}
- spin_lock(&journal->j_state_lock);
+ read_lock(&journal->j_state_lock);
jbd_debug(1,"JBD: updating superblock (start %ld, seq %d, errno %d)\n",
journal->j_tail, journal->j_tail_sequence, journal->j_errno);
sb->s_sequence = cpu_to_be32(journal->j_tail_sequence);
sb->s_start = cpu_to_be32(journal->j_tail);
sb->s_errno = cpu_to_be32(journal->j_errno);
- spin_unlock(&journal->j_state_lock);
+ read_unlock(&journal->j_state_lock);
BUFFER_TRACE(bh, "marking dirty");
mark_buffer_dirty(bh);
@@ -1124,12 +1131,12 @@ out:
* any future commit will have to be careful to update the
* superblock again to re-record the true start of the log. */
- spin_lock(&journal->j_state_lock);
+ write_lock(&journal->j_state_lock);
if (sb->s_start)
journal->j_flags &= ~JBD2_FLUSHED;
else
journal->j_flags |= JBD2_FLUSHED;
- spin_unlock(&journal->j_state_lock);
+ write_unlock(&journal->j_state_lock);
}
/*
@@ -1391,13 +1398,9 @@ int jbd2_journal_check_used_features (journal_t *journal, unsigned long compat,
int jbd2_journal_check_available_features (journal_t *journal, unsigned long compat,
unsigned long ro, unsigned long incompat)
{
- journal_superblock_t *sb;
-
if (!compat && !ro && !incompat)
return 1;
- sb = journal->j_superblock;
-
/* We can support any known requested features iff the
* superblock is in version 2. Otherwise we fail to support any
* extended sb features. */
@@ -1545,7 +1548,7 @@ int jbd2_journal_flush(journal_t *journal)
transaction_t *transaction = NULL;
unsigned long old_tail;
- spin_lock(&journal->j_state_lock);
+ write_lock(&journal->j_state_lock);
/* Force everything buffered to the log... */
if (journal->j_running_transaction) {
@@ -1558,10 +1561,10 @@ int jbd2_journal_flush(journal_t *journal)
if (transaction) {
tid_t tid = transaction->t_tid;
- spin_unlock(&journal->j_state_lock);
+ write_unlock(&journal->j_state_lock);
jbd2_log_wait_commit(journal, tid);
} else {
- spin_unlock(&journal->j_state_lock);
+ write_unlock(&journal->j_state_lock);
}
/* ...and flush everything in the log out to disk. */
@@ -1585,12 +1588,12 @@ int jbd2_journal_flush(journal_t *journal)
* the magic code for a fully-recovered superblock. Any future
* commits of data to the journal will restore the current
* s_start value. */
- spin_lock(&journal->j_state_lock);
+ write_lock(&journal->j_state_lock);
old_tail = journal->j_tail;
journal->j_tail = 0;
- spin_unlock(&journal->j_state_lock);
+ write_unlock(&journal->j_state_lock);
jbd2_journal_update_superblock(journal, 1);
- spin_lock(&journal->j_state_lock);
+ write_lock(&journal->j_state_lock);
journal->j_tail = old_tail;
J_ASSERT(!journal->j_running_transaction);
@@ -1598,7 +1601,7 @@ int jbd2_journal_flush(journal_t *journal)
J_ASSERT(!journal->j_checkpoint_transactions);
J_ASSERT(journal->j_head == journal->j_tail);
J_ASSERT(journal->j_tail_sequence == journal->j_transaction_sequence);
- spin_unlock(&journal->j_state_lock);
+ write_unlock(&journal->j_state_lock);
return 0;
}
@@ -1617,7 +1620,6 @@ int jbd2_journal_flush(journal_t *journal)
int jbd2_journal_wipe(journal_t *journal, int write)
{
- journal_superblock_t *sb;
int err = 0;
J_ASSERT (!(journal->j_flags & JBD2_LOADED));
@@ -1626,8 +1628,6 @@ int jbd2_journal_wipe(journal_t *journal, int write)
if (err)
return err;
- sb = journal->j_superblock;
-
if (!journal->j_tail)
goto no_recovery;
@@ -1665,12 +1665,12 @@ void __jbd2_journal_abort_hard(journal_t *journal)
printk(KERN_ERR "Aborting journal on device %s.\n",
journal->j_devname);
- spin_lock(&journal->j_state_lock);
+ write_lock(&journal->j_state_lock);
journal->j_flags |= JBD2_ABORT;
transaction = journal->j_running_transaction;
if (transaction)
__jbd2_log_start_commit(journal, transaction->t_tid);
- spin_unlock(&journal->j_state_lock);
+ write_unlock(&journal->j_state_lock);
}
/* Soft abort: record the abort error status in the journal superblock,
@@ -1755,12 +1755,12 @@ int jbd2_journal_errno(journal_t *journal)
{
int err;
- spin_lock(&journal->j_state_lock);
+ read_lock(&journal->j_state_lock);
if (journal->j_flags & JBD2_ABORT)
err = -EROFS;
else
err = journal->j_errno;
- spin_unlock(&journal->j_state_lock);
+ read_unlock(&journal->j_state_lock);
return err;
}
@@ -1775,12 +1775,12 @@ int jbd2_journal_clear_err(journal_t *journal)
{
int err = 0;
- spin_lock(&journal->j_state_lock);
+ write_lock(&journal->j_state_lock);
if (journal->j_flags & JBD2_ABORT)
err = -EROFS;
else
journal->j_errno = 0;
- spin_unlock(&journal->j_state_lock);
+ write_unlock(&journal->j_state_lock);
return err;
}
@@ -1793,10 +1793,10 @@ int jbd2_journal_clear_err(journal_t *journal)
*/
void jbd2_journal_ack_err(journal_t *journal)
{
- spin_lock(&journal->j_state_lock);
+ write_lock(&journal->j_state_lock);
if (journal->j_errno)
journal->j_flags |= JBD2_ACK_ERR;
- spin_unlock(&journal->j_state_lock);
+ write_unlock(&journal->j_state_lock);
}
int jbd2_journal_blocks_per_page(struct inode *inode)
@@ -2201,8 +2201,6 @@ void jbd2_journal_init_jbd_inode(struct jbd2_inode *jinode, struct inode *inode)
void jbd2_journal_release_jbd_inode(journal_t *journal,
struct jbd2_inode *jinode)
{
- int writeout = 0;
-
if (!journal)
return;
restart:
@@ -2219,9 +2217,6 @@ restart:
goto restart;
}
- /* Do we need to wait for data writeback? */
- if (journal->j_committing_transaction == jinode->i_transaction)
- writeout = 1;
if (jinode->i_transaction) {
list_del(&jinode->i_list);
jinode->i_transaction = NULL;
diff --git a/fs/jbd2/recovery.c b/fs/jbd2/recovery.c
index 049281b7cb8..2bc4d5f116f 100644
--- a/fs/jbd2/recovery.c
+++ b/fs/jbd2/recovery.c
@@ -285,12 +285,10 @@ int jbd2_journal_recover(journal_t *journal)
int jbd2_journal_skip_recovery(journal_t *journal)
{
int err;
- journal_superblock_t * sb;
struct recovery_info info;
memset (&info, 0, sizeof(info));
- sb = journal->j_superblock;
err = do_one_pass(journal, &info, PASS_SCAN);
@@ -299,7 +297,8 @@ int jbd2_journal_skip_recovery(journal_t *journal)
++journal->j_transaction_sequence;
} else {
#ifdef CONFIG_JBD2_DEBUG
- int dropped = info.end_transaction - be32_to_cpu(sb->s_sequence);
+ int dropped = info.end_transaction -
+ be32_to_cpu(journal->j_superblock->s_sequence);
#endif
jbd_debug(1,
"JBD: ignoring %d transaction%s from the journal.\n",
@@ -365,11 +364,6 @@ static int do_one_pass(journal_t *journal,
int tag_bytes = journal_tag_bytes(journal);
__u32 crc32_sum = ~0; /* Transactional Checksums */
- /* Precompute the maximum metadata descriptors in a descriptor block */
- int MAX_BLOCKS_PER_DESC;
- MAX_BLOCKS_PER_DESC = ((journal->j_blocksize-sizeof(journal_header_t))
- / tag_bytes);
-
/*
* First thing is to establish what we expect to find in the log
* (in terms of transaction IDs), and where (in terms of log
diff --git a/fs/jbd2/transaction.c b/fs/jbd2/transaction.c
index b8e0806681b..d95cc9d0401 100644
--- a/fs/jbd2/transaction.c
+++ b/fs/jbd2/transaction.c
@@ -26,6 +26,8 @@
#include <linux/mm.h>
#include <linux/highmem.h>
#include <linux/hrtimer.h>
+#include <linux/backing-dev.h>
+#include <linux/module.h>
static void __jbd2_journal_temp_unlink_buffer(struct journal_head *jh);
@@ -53,6 +55,9 @@ jbd2_get_transaction(journal_t *journal, transaction_t *transaction)
transaction->t_tid = journal->j_transaction_sequence++;
transaction->t_expires = jiffies + journal->j_commit_interval;
spin_lock_init(&transaction->t_handle_lock);
+ atomic_set(&transaction->t_updates, 0);
+ atomic_set(&transaction->t_outstanding_credits, 0);
+ atomic_set(&transaction->t_handle_count, 0);
INIT_LIST_HEAD(&transaction->t_inode_list);
INIT_LIST_HEAD(&transaction->t_private_list);
@@ -83,65 +88,75 @@ jbd2_get_transaction(journal_t *journal, transaction_t *transaction)
* transaction's buffer credits.
*/
-static int start_this_handle(journal_t *journal, handle_t *handle)
+static int start_this_handle(journal_t *journal, handle_t *handle,
+ int gfp_mask)
{
transaction_t *transaction;
int needed;
int nblocks = handle->h_buffer_credits;
transaction_t *new_transaction = NULL;
- int ret = 0;
unsigned long ts = jiffies;
if (nblocks > journal->j_max_transaction_buffers) {
printk(KERN_ERR "JBD: %s wants too many credits (%d > %d)\n",
current->comm, nblocks,
journal->j_max_transaction_buffers);
- ret = -ENOSPC;
- goto out;
+ return -ENOSPC;
}
alloc_transaction:
if (!journal->j_running_transaction) {
- new_transaction = kzalloc(sizeof(*new_transaction),
- GFP_NOFS|__GFP_NOFAIL);
+ new_transaction = kzalloc(sizeof(*new_transaction), gfp_mask);
if (!new_transaction) {
- ret = -ENOMEM;
- goto out;
+ /*
+ * If __GFP_FS is not present, then we may be
+ * being called from inside the fs writeback
+ * layer, so we MUST NOT fail. Since
+ * __GFP_NOFAIL is going away, we will arrange
+ * to retry the allocation ourselves.
+ */
+ if ((gfp_mask & __GFP_FS) == 0) {
+ congestion_wait(BLK_RW_ASYNC, HZ/50);
+ goto alloc_transaction;
+ }
+ return -ENOMEM;
}
}
jbd_debug(3, "New handle %p going live.\n", handle);
-repeat:
-
/*
* We need to hold j_state_lock until t_updates has been incremented,
* for proper journal barrier handling
*/
- spin_lock(&journal->j_state_lock);
-repeat_locked:
+repeat:
+ read_lock(&journal->j_state_lock);
if (is_journal_aborted(journal) ||
(journal->j_errno != 0 && !(journal->j_flags & JBD2_ACK_ERR))) {
- spin_unlock(&journal->j_state_lock);
- ret = -EROFS;
- goto out;
+ read_unlock(&journal->j_state_lock);
+ kfree(new_transaction);
+ return -EROFS;
}
/* Wait on the journal's transaction barrier if necessary */
if (journal->j_barrier_count) {
- spin_unlock(&journal->j_state_lock);
+ read_unlock(&journal->j_state_lock);
wait_event(journal->j_wait_transaction_locked,
journal->j_barrier_count == 0);
goto repeat;
}
if (!journal->j_running_transaction) {
- if (!new_transaction) {
- spin_unlock(&journal->j_state_lock);
+ read_unlock(&journal->j_state_lock);
+ if (!new_transaction)
goto alloc_transaction;
+ write_lock(&journal->j_state_lock);
+ if (!journal->j_running_transaction) {
+ jbd2_get_transaction(journal, new_transaction);
+ new_transaction = NULL;
}
- jbd2_get_transaction(journal, new_transaction);
- new_transaction = NULL;
+ write_unlock(&journal->j_state_lock);
+ goto repeat;
}
transaction = journal->j_running_transaction;
@@ -155,7 +170,7 @@ repeat_locked:
prepare_to_wait(&journal->j_wait_transaction_locked,
&wait, TASK_UNINTERRUPTIBLE);
- spin_unlock(&journal->j_state_lock);
+ read_unlock(&journal->j_state_lock);
schedule();
finish_wait(&journal->j_wait_transaction_locked, &wait);
goto repeat;
@@ -166,8 +181,8 @@ repeat_locked:
* buffers requested by this operation, we need to stall pending a log
* checkpoint to free some more log space.
*/
- spin_lock(&transaction->t_handle_lock);
- needed = transaction->t_outstanding_credits + nblocks;
+ needed = atomic_add_return(nblocks,
+ &transaction->t_outstanding_credits);
if (needed > journal->j_max_transaction_buffers) {
/*
@@ -178,11 +193,11 @@ repeat_locked:
DEFINE_WAIT(wait);
jbd_debug(2, "Handle %p starting new commit...\n", handle);
- spin_unlock(&transaction->t_handle_lock);
+ atomic_sub(nblocks, &transaction->t_outstanding_credits);
prepare_to_wait(&journal->j_wait_transaction_locked, &wait,
TASK_UNINTERRUPTIBLE);
__jbd2_log_start_commit(journal, transaction->t_tid);
- spin_unlock(&journal->j_state_lock);
+ read_unlock(&journal->j_state_lock);
schedule();
finish_wait(&journal->j_wait_transaction_locked, &wait);
goto repeat;
@@ -215,35 +230,48 @@ repeat_locked:
*/
if (__jbd2_log_space_left(journal) < jbd_space_needed(journal)) {
jbd_debug(2, "Handle %p waiting for checkpoint...\n", handle);
- spin_unlock(&transaction->t_handle_lock);
- __jbd2_log_wait_for_space(journal);
- goto repeat_locked;
+ atomic_sub(nblocks, &transaction->t_outstanding_credits);
+ read_unlock(&journal->j_state_lock);
+ write_lock(&journal->j_state_lock);
+ if (__jbd2_log_space_left(journal) < jbd_space_needed(journal))
+ __jbd2_log_wait_for_space(journal);
+ write_unlock(&journal->j_state_lock);
+ goto repeat;
}
/* OK, account for the buffers that this operation expects to
- * use and add the handle to the running transaction. */
-
- if (time_after(transaction->t_start, ts)) {
+ * use and add the handle to the running transaction.
+ *
+ * In order for t_max_wait to be reliable, it must be
+ * protected by a lock. But doing so will mean that
+ * start_this_handle() can not be run in parallel on SMP
+ * systems, which limits our scalability. So we only enable
+ * it when debugging is enabled. We may want to use a
+ * separate flag, eventually, so we can enable this
+ * independently of debugging.
+ */
+#ifdef CONFIG_JBD2_DEBUG
+ if (jbd2_journal_enable_debug &&
+ time_after(transaction->t_start, ts)) {
ts = jbd2_time_diff(ts, transaction->t_start);
+ spin_lock(&transaction->t_handle_lock);
if (ts > transaction->t_max_wait)
transaction->t_max_wait = ts;
+ spin_unlock(&transaction->t_handle_lock);
}
-
+#endif
handle->h_transaction = transaction;
- transaction->t_outstanding_credits += nblocks;
- transaction->t_updates++;
- transaction->t_handle_count++;
+ atomic_inc(&transaction->t_updates);
+ atomic_inc(&transaction->t_handle_count);
jbd_debug(4, "Handle %p given %d credits (total %d, free %d)\n",
- handle, nblocks, transaction->t_outstanding_credits,
+ handle, nblocks,
+ atomic_read(&transaction->t_outstanding_credits),
__jbd2_log_space_left(journal));
- spin_unlock(&transaction->t_handle_lock);
- spin_unlock(&journal->j_state_lock);
+ read_unlock(&journal->j_state_lock);
lock_map_acquire(&handle->h_lockdep_map);
-out:
- if (unlikely(new_transaction)) /* It's usually NULL */
- kfree(new_transaction);
- return ret;
+ kfree(new_transaction);
+ return 0;
}
static struct lock_class_key jbd2_handle_key;
@@ -278,7 +306,7 @@ static handle_t *new_handle(int nblocks)
*
* Return a pointer to a newly allocated handle, or NULL on failure
*/
-handle_t *jbd2_journal_start(journal_t *journal, int nblocks)
+handle_t *jbd2__journal_start(journal_t *journal, int nblocks, int gfp_mask)
{
handle_t *handle = journal_current_handle();
int err;
@@ -298,7 +326,7 @@ handle_t *jbd2_journal_start(journal_t *journal, int nblocks)
current->journal_info = handle;
- err = start_this_handle(journal, handle);
+ err = start_this_handle(journal, handle, gfp_mask);
if (err < 0) {
jbd2_free_handle(handle);
current->journal_info = NULL;
@@ -308,6 +336,15 @@ handle_t *jbd2_journal_start(journal_t *journal, int nblocks)
out:
return handle;
}
+EXPORT_SYMBOL(jbd2__journal_start);
+
+
+handle_t *jbd2_journal_start(journal_t *journal, int nblocks)
+{
+ return jbd2__journal_start(journal, nblocks, GFP_NOFS);
+}
+EXPORT_SYMBOL(jbd2_journal_start);
+
/**
* int jbd2_journal_extend() - extend buffer credits.
@@ -342,7 +379,7 @@ int jbd2_journal_extend(handle_t *handle, int nblocks)
result = 1;
- spin_lock(&journal->j_state_lock);
+ read_lock(&journal->j_state_lock);
/* Don't extend a locked-down transaction! */
if (handle->h_transaction->t_state != T_RUNNING) {
@@ -352,7 +389,7 @@ int jbd2_journal_extend(handle_t *handle, int nblocks)
}
spin_lock(&transaction->t_handle_lock);
- wanted = transaction->t_outstanding_credits + nblocks;
+ wanted = atomic_read(&transaction->t_outstanding_credits) + nblocks;
if (wanted > journal->j_max_transaction_buffers) {
jbd_debug(3, "denied handle %p %d blocks: "
@@ -367,14 +404,14 @@ int jbd2_journal_extend(handle_t *handle, int nblocks)
}
handle->h_buffer_credits += nblocks;
- transaction->t_outstanding_credits += nblocks;
+ atomic_add(nblocks, &transaction->t_outstanding_credits);
result = 0;
jbd_debug(3, "extended handle %p by %d\n", handle, nblocks);
unlock:
spin_unlock(&transaction->t_handle_lock);
error_out:
- spin_unlock(&journal->j_state_lock);
+ read_unlock(&journal->j_state_lock);
out:
return result;
}
@@ -394,8 +431,7 @@ out:
* transaction capabable of guaranteeing the requested number of
* credits.
*/
-
-int jbd2_journal_restart(handle_t *handle, int nblocks)
+int jbd2__journal_restart(handle_t *handle, int nblocks, int gfp_mask)
{
transaction_t *transaction = handle->h_transaction;
journal_t *journal = transaction->t_journal;
@@ -410,29 +446,35 @@ int jbd2_journal_restart(handle_t *handle, int nblocks)
* First unlink the handle from its current transaction, and start the
* commit on that.
*/
- J_ASSERT(transaction->t_updates > 0);
+ J_ASSERT(atomic_read(&transaction->t_updates) > 0);
J_ASSERT(journal_current_handle() == handle);
- spin_lock(&journal->j_state_lock);
+ read_lock(&journal->j_state_lock);
spin_lock(&transaction->t_handle_lock);
- transaction->t_outstanding_credits -= handle->h_buffer_credits;
- transaction->t_updates--;
-
- if (!transaction->t_updates)
+ atomic_sub(handle->h_buffer_credits,
+ &transaction->t_outstanding_credits);
+ if (atomic_dec_and_test(&transaction->t_updates))
wake_up(&journal->j_wait_updates);
spin_unlock(&transaction->t_handle_lock);
jbd_debug(2, "restarting handle %p\n", handle);
__jbd2_log_start_commit(journal, transaction->t_tid);
- spin_unlock(&journal->j_state_lock);
+ read_unlock(&journal->j_state_lock);
lock_map_release(&handle->h_lockdep_map);
handle->h_buffer_credits = nblocks;
- ret = start_this_handle(journal, handle);
+ ret = start_this_handle(journal, handle, gfp_mask);
return ret;
}
+EXPORT_SYMBOL(jbd2__journal_restart);
+int jbd2_journal_restart(handle_t *handle, int nblocks)
+{
+ return jbd2__journal_restart(handle, nblocks, GFP_NOFS);
+}
+EXPORT_SYMBOL(jbd2_journal_restart);
+
/**
* void jbd2_journal_lock_updates () - establish a transaction barrier.
* @journal: Journal to establish a barrier on.
@@ -447,7 +489,7 @@ void jbd2_journal_lock_updates(journal_t *journal)
{
DEFINE_WAIT(wait);
- spin_lock(&journal->j_state_lock);
+ write_lock(&journal->j_state_lock);
++journal->j_barrier_count;
/* Wait until there are no running updates */
@@ -458,19 +500,19 @@ void jbd2_journal_lock_updates(journal_t *journal)
break;
spin_lock(&transaction->t_handle_lock);
- if (!transaction->t_updates) {
+ if (!atomic_read(&transaction->t_updates)) {
spin_unlock(&transaction->t_handle_lock);
break;
}
prepare_to_wait(&journal->j_wait_updates, &wait,
TASK_UNINTERRUPTIBLE);
spin_unlock(&transaction->t_handle_lock);
- spin_unlock(&journal->j_state_lock);
+ write_unlock(&journal->j_state_lock);
schedule();
finish_wait(&journal->j_wait_updates, &wait);
- spin_lock(&journal->j_state_lock);
+ write_lock(&journal->j_state_lock);
}
- spin_unlock(&journal->j_state_lock);
+ write_unlock(&journal->j_state_lock);
/*
* We have now established a barrier against other normal updates, but
@@ -494,9 +536,9 @@ void jbd2_journal_unlock_updates (journal_t *journal)
J_ASSERT(journal->j_barrier_count != 0);
mutex_unlock(&journal->j_barrier);
- spin_lock(&journal->j_state_lock);
+ write_lock(&journal->j_state_lock);
--journal->j_barrier_count;
- spin_unlock(&journal->j_state_lock);
+ write_unlock(&journal->j_state_lock);
wake_up(&journal->j_wait_transaction_locked);
}
@@ -1238,7 +1280,8 @@ int jbd2_journal_stop(handle_t *handle)
{
transaction_t *transaction = handle->h_transaction;
journal_t *journal = transaction->t_journal;
- int err;
+ int err, wait_for_commit = 0;
+ tid_t tid;
pid_t pid;
J_ASSERT(journal_current_handle() == handle);
@@ -1246,7 +1289,7 @@ int jbd2_journal_stop(handle_t *handle)
if (is_handle_aborted(handle))
err = -EIO;
else {
- J_ASSERT(transaction->t_updates > 0);
+ J_ASSERT(atomic_read(&transaction->t_updates) > 0);
err = 0;
}
@@ -1291,9 +1334,9 @@ int jbd2_journal_stop(handle_t *handle)
journal->j_last_sync_writer = pid;
- spin_lock(&journal->j_state_lock);
+ read_lock(&journal->j_state_lock);
commit_time = journal->j_average_commit_time;
- spin_unlock(&journal->j_state_lock);
+ read_unlock(&journal->j_state_lock);
trans_time = ktime_to_ns(ktime_sub(ktime_get(),
transaction->t_start_time));
@@ -1314,14 +1357,8 @@ int jbd2_journal_stop(handle_t *handle)
if (handle->h_sync)
transaction->t_synchronous_commit = 1;
current->journal_info = NULL;
- spin_lock(&transaction->t_handle_lock);
- transaction->t_outstanding_credits -= handle->h_buffer_credits;
- transaction->t_updates--;
- if (!transaction->t_updates) {
- wake_up(&journal->j_wait_updates);
- if (journal->j_barrier_count)
- wake_up(&journal->j_wait_transaction_locked);
- }
+ atomic_sub(handle->h_buffer_credits,
+ &transaction->t_outstanding_credits);
/*
* If the handle is marked SYNC, we need to set another commit
@@ -1330,15 +1367,13 @@ int jbd2_journal_stop(handle_t *handle)
* transaction is too old now.
*/
if (handle->h_sync ||
- transaction->t_outstanding_credits >
- journal->j_max_transaction_buffers ||
- time_after_eq(jiffies, transaction->t_expires)) {
+ (atomic_read(&transaction->t_outstanding_credits) >
+ journal->j_max_transaction_buffers) ||
+ time_after_eq(jiffies, transaction->t_expires)) {
/* Do this even for aborted journals: an abort still
* completes the commit thread, it just doesn't write
* anything to disk. */
- tid_t tid = transaction->t_tid;
- spin_unlock(&transaction->t_handle_lock);
jbd_debug(2, "transaction too old, requesting commit for "
"handle %p\n", handle);
/* This is non-blocking */
@@ -1349,11 +1384,25 @@ int jbd2_journal_stop(handle_t *handle)
* to wait for the commit to complete.
*/
if (handle->h_sync && !(current->flags & PF_MEMALLOC))
- err = jbd2_log_wait_commit(journal, tid);
- } else {
- spin_unlock(&transaction->t_handle_lock);
+ wait_for_commit = 1;
}
+ /*
+ * Once we drop t_updates, if it goes to zero the transaction
+ * could start commiting on us and eventually disappear. So
+ * once we do this, we must not dereference transaction
+ * pointer again.
+ */
+ tid = transaction->t_tid;
+ if (atomic_dec_and_test(&transaction->t_updates)) {
+ wake_up(&journal->j_wait_updates);
+ if (journal->j_barrier_count)
+ wake_up(&journal->j_wait_transaction_locked);
+ }
+
+ if (wait_for_commit)
+ err = jbd2_log_wait_commit(journal, tid);
+
lock_map_release(&handle->h_lockdep_map);
jbd2_free_handle(handle);
@@ -1719,7 +1768,7 @@ static int journal_unmap_buffer(journal_t *journal, struct buffer_head *bh)
goto zap_buffer_unlocked;
/* OK, we have data buffer in journaled mode */
- spin_lock(&journal->j_state_lock);
+ write_lock(&journal->j_state_lock);
jbd_lock_bh_state(bh);
spin_lock(&journal->j_list_lock);
@@ -1772,7 +1821,7 @@ static int journal_unmap_buffer(journal_t *journal, struct buffer_head *bh)
jbd2_journal_put_journal_head(jh);
spin_unlock(&journal->j_list_lock);
jbd_unlock_bh_state(bh);
- spin_unlock(&journal->j_state_lock);
+ write_unlock(&journal->j_state_lock);
return ret;
} else {
/* There is no currently-running transaction. So the
@@ -1786,7 +1835,7 @@ static int journal_unmap_buffer(journal_t *journal, struct buffer_head *bh)
jbd2_journal_put_journal_head(jh);
spin_unlock(&journal->j_list_lock);
jbd_unlock_bh_state(bh);
- spin_unlock(&journal->j_state_lock);
+ write_unlock(&journal->j_state_lock);
return ret;
} else {
/* The orphan record's transaction has
@@ -1810,7 +1859,7 @@ static int journal_unmap_buffer(journal_t *journal, struct buffer_head *bh)
jbd2_journal_put_journal_head(jh);
spin_unlock(&journal->j_list_lock);
jbd_unlock_bh_state(bh);
- spin_unlock(&journal->j_state_lock);
+ write_unlock(&journal->j_state_lock);
return 0;
} else {
/* Good, the buffer belongs to the running transaction.
@@ -1829,7 +1878,7 @@ zap_buffer:
zap_buffer_no_jh:
spin_unlock(&journal->j_list_lock);
jbd_unlock_bh_state(bh);
- spin_unlock(&journal->j_state_lock);
+ write_unlock(&journal->j_state_lock);
zap_buffer_unlocked:
clear_buffer_dirty(bh);
J_ASSERT_BH(bh, !buffer_jbddirty(bh));
@@ -2136,9 +2185,9 @@ int jbd2_journal_begin_ordered_truncate(journal_t *journal,
/* Locks are here just to force reading of recent values, it is
* enough that the transaction was not committing before we started
* a transaction adding the inode to orphan list */
- spin_lock(&journal->j_state_lock);
+ read_lock(&journal->j_state_lock);
commit_trans = journal->j_committing_transaction;
- spin_unlock(&journal->j_state_lock);
+ read_unlock(&journal->j_state_lock);
spin_lock(&journal->j_list_lock);
inode_trans = jinode->i_transaction;
spin_unlock(&journal->j_list_lock);
diff --git a/fs/namei.c b/fs/namei.c
index 868d0cb9d47..42d2d28fb82 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -282,8 +282,7 @@ int inode_permission(struct inode *inode, int mask)
if (retval)
return retval;
- return security_inode_permission(inode,
- mask & (MAY_READ|MAY_WRITE|MAY_EXEC|MAY_APPEND));
+ return security_inode_permission(inode, mask);
}
/**
@@ -1484,8 +1483,7 @@ static int handle_truncate(struct path *path)
*/
error = locks_verify_locked(inode);
if (!error)
- error = security_path_truncate(path, 0,
- ATTR_MTIME|ATTR_CTIME|ATTR_OPEN);
+ error = security_path_truncate(path);
if (!error) {
error = do_truncate(path->dentry, 0,
ATTR_MTIME|ATTR_CTIME|ATTR_OPEN,
diff --git a/fs/ncpfs/inode.c b/fs/ncpfs/inode.c
index fa338515402..1e634deff94 100644
--- a/fs/ncpfs/inode.c
+++ b/fs/ncpfs/inode.c
@@ -728,8 +728,8 @@ out_fput:
out_bdi:
/* 23/12/1998 Marcin Dalecki <dalecki@cs.net.pl>:
*
- * The previously used put_filp(ncp_filp); was bogous, since
- * it doesn't proper unlocking.
+ * The previously used put_filp(ncp_filp); was bogus, since
+ * it doesn't perform proper unlocking.
*/
fput(ncp_filp);
out:
diff --git a/fs/nfs/Kconfig b/fs/nfs/Kconfig
index a43d07e7b92..cc1bb33b59b 100644
--- a/fs/nfs/Kconfig
+++ b/fs/nfs/Kconfig
@@ -61,8 +61,8 @@ config NFS_V3_ACL
If unsure, say N.
config NFS_V4
- bool "NFS client support for NFS version 4 (EXPERIMENTAL)"
- depends on NFS_FS && EXPERIMENTAL
+ bool "NFS client support for NFS version 4"
+ depends on NFS_FS
select RPCSEC_GSS_KRB5
help
This option enables support for version 4 of the NFS protocol
@@ -72,16 +72,16 @@ config NFS_V4
space programs which can be found in the Linux nfs-utils package,
available from http://linux-nfs.org/.
- If unsure, say N.
+ If unsure, say Y.
config NFS_V4_1
- bool "NFS client support for NFSv4.1 (DEVELOPER ONLY)"
+ bool "NFS client support for NFSv4.1 (EXPERIMENTAL)"
depends on NFS_V4 && EXPERIMENTAL
help
This option enables support for minor version 1 of the NFSv4 protocol
(draft-ietf-nfsv4-minorversion1) in the kernel's NFS client.
- Unless you're an NFS developer, say N.
+ If unsure, say N.
config ROOT_NFS
bool "Root file system on NFS"
diff --git a/fs/nfs/callback_proc.c b/fs/nfs/callback_proc.c
index a08770a7e85..930d10fecda 100644
--- a/fs/nfs/callback_proc.c
+++ b/fs/nfs/callback_proc.c
@@ -37,8 +37,8 @@ __be32 nfs4_callback_getattr(struct cb_getattrargs *args, struct cb_getattrres *
if (inode == NULL)
goto out_putclient;
nfsi = NFS_I(inode);
- down_read(&nfsi->rwsem);
- delegation = nfsi->delegation;
+ rcu_read_lock();
+ delegation = rcu_dereference(nfsi->delegation);
if (delegation == NULL || (delegation->type & FMODE_WRITE) == 0)
goto out_iput;
res->size = i_size_read(inode);
@@ -53,7 +53,7 @@ __be32 nfs4_callback_getattr(struct cb_getattrargs *args, struct cb_getattrres *
args->bitmap[1];
res->status = 0;
out_iput:
- up_read(&nfsi->rwsem);
+ rcu_read_unlock();
iput(inode);
out_putclient:
nfs_put_client(clp);
@@ -62,16 +62,6 @@ out:
return res->status;
}
-static int (*nfs_validate_delegation_stateid(struct nfs_client *clp))(struct nfs_delegation *, const nfs4_stateid *)
-{
-#if defined(CONFIG_NFS_V4_1)
- if (clp->cl_minorversion > 0)
- return nfs41_validate_delegation_stateid;
-#endif
- return nfs4_validate_delegation_stateid;
-}
-
-
__be32 nfs4_callback_recall(struct cb_recallargs *args, void *dummy)
{
struct nfs_client *clp;
@@ -92,8 +82,7 @@ __be32 nfs4_callback_recall(struct cb_recallargs *args, void *dummy)
inode = nfs_delegation_find_inode(clp, &args->fh);
if (inode != NULL) {
/* Set up a helper thread to actually return the delegation */
- switch (nfs_async_inode_return_delegation(inode, &args->stateid,
- nfs_validate_delegation_stateid(clp))) {
+ switch (nfs_async_inode_return_delegation(inode, &args->stateid)) {
case 0:
res = 0;
break;
diff --git a/fs/nfs/client.c b/fs/nfs/client.c
index d25b5257b7a..4e7df2adb21 100644
--- a/fs/nfs/client.c
+++ b/fs/nfs/client.c
@@ -150,6 +150,7 @@ static struct nfs_client *nfs_alloc_client(const struct nfs_client_initdata *cl_
clp->cl_boot_time = CURRENT_TIME;
clp->cl_state = 1 << NFS4CLNT_LEASE_EXPIRED;
clp->cl_minorversion = cl_init->minorversion;
+ clp->cl_mvops = nfs_v4_minor_ops[cl_init->minorversion];
#endif
cred = rpc_lookup_machine_cred();
if (!IS_ERR(cred))
@@ -178,7 +179,7 @@ static void nfs4_clear_client_minor_version(struct nfs_client *clp)
clp->cl_session = NULL;
}
- clp->cl_call_sync = _nfs4_call_sync;
+ clp->cl_mvops = nfs_v4_minor_ops[0];
#endif /* CONFIG_NFS_V4_1 */
}
@@ -188,7 +189,7 @@ static void nfs4_clear_client_minor_version(struct nfs_client *clp)
static void nfs4_destroy_callback(struct nfs_client *clp)
{
if (__test_and_clear_bit(NFS_CS_CALLBACK, &clp->cl_res_state))
- nfs_callback_down(clp->cl_minorversion);
+ nfs_callback_down(clp->cl_mvops->minor_version);
}
static void nfs4_shutdown_client(struct nfs_client *clp)
@@ -1126,7 +1127,7 @@ static int nfs4_init_callback(struct nfs_client *clp)
return error;
}
- error = nfs_callback_up(clp->cl_minorversion,
+ error = nfs_callback_up(clp->cl_mvops->minor_version,
clp->cl_rpcclient->cl_xprt);
if (error < 0) {
dprintk("%s: failed to start callback. Error = %d\n",
@@ -1143,10 +1144,8 @@ static int nfs4_init_callback(struct nfs_client *clp)
*/
static int nfs4_init_client_minor_version(struct nfs_client *clp)
{
- clp->cl_call_sync = _nfs4_call_sync;
-
#if defined(CONFIG_NFS_V4_1)
- if (clp->cl_minorversion) {
+ if (clp->cl_mvops->minor_version) {
struct nfs4_session *session = NULL;
/*
* Create the session and mark it expired.
@@ -1158,7 +1157,13 @@ static int nfs4_init_client_minor_version(struct nfs_client *clp)
return -ENOMEM;
clp->cl_session = session;
- clp->cl_call_sync = _nfs4_call_sync_session;
+ /*
+ * The create session reply races with the server back
+ * channel probe. Mark the client NFS_CS_SESSION_INITING
+ * so that the client back channel can find the
+ * nfs_client struct
+ */
+ clp->cl_cons_state = NFS_CS_SESSION_INITING;
}
#endif /* CONFIG_NFS_V4_1 */
@@ -1454,7 +1459,7 @@ struct nfs_server *nfs4_create_referral_server(struct nfs_clone_mount *data,
data->authflavor,
parent_server->client->cl_xprt->prot,
parent_server->client->cl_timeout,
- parent_client->cl_minorversion);
+ parent_client->cl_mvops->minor_version);
if (error < 0)
goto error;
diff --git a/fs/nfs/delegation.c b/fs/nfs/delegation.c
index 30163454397..b9c3c43cea1 100644
--- a/fs/nfs/delegation.c
+++ b/fs/nfs/delegation.c
@@ -268,14 +268,6 @@ out:
return status;
}
-/* Sync all data to disk upon delegation return */
-static void nfs_msync_inode(struct inode *inode)
-{
- filemap_fdatawrite(inode->i_mapping);
- nfs_wb_all(inode);
- filemap_fdatawait(inode->i_mapping);
-}
-
/*
* Basic procedure for returning a delegation to the server
*/
@@ -367,7 +359,7 @@ int nfs_inode_return_delegation(struct inode *inode)
delegation = nfs_detach_delegation_locked(nfsi, NULL, clp);
spin_unlock(&clp->cl_lock);
if (delegation != NULL) {
- nfs_msync_inode(inode);
+ nfs_wb_all(inode);
err = __nfs_inode_return_delegation(inode, delegation, 1);
}
}
@@ -471,9 +463,7 @@ void nfs_expire_unreferenced_delegations(struct nfs_client *clp)
/*
* Asynchronous delegation recall!
*/
-int nfs_async_inode_return_delegation(struct inode *inode, const nfs4_stateid *stateid,
- int (*validate_stateid)(struct nfs_delegation *delegation,
- const nfs4_stateid *stateid))
+int nfs_async_inode_return_delegation(struct inode *inode, const nfs4_stateid *stateid)
{
struct nfs_client *clp = NFS_SERVER(inode)->nfs_client;
struct nfs_delegation *delegation;
@@ -481,7 +471,7 @@ int nfs_async_inode_return_delegation(struct inode *inode, const nfs4_stateid *s
rcu_read_lock();
delegation = rcu_dereference(NFS_I(inode)->delegation);
- if (!validate_stateid(delegation, stateid)) {
+ if (!clp->cl_mvops->validate_stateid(delegation, stateid)) {
rcu_read_unlock();
return -ENOENT;
}
diff --git a/fs/nfs/delegation.h b/fs/nfs/delegation.h
index 69e7b814012..2026304bda1 100644
--- a/fs/nfs/delegation.h
+++ b/fs/nfs/delegation.h
@@ -34,9 +34,7 @@ enum {
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_async_inode_return_delegation(struct inode *inode, const nfs4_stateid *stateid,
- int (*validate_stateid)(struct nfs_delegation *delegation,
- const nfs4_stateid *stateid));
+int nfs_async_inode_return_delegation(struct inode *inode, const nfs4_stateid *stateid);
void nfs_inode_return_delegation_noreclaim(struct inode *inode);
struct inode *nfs_delegation_find_inode(struct nfs_client *clp, const struct nfs_fh *fhandle);
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c
index e60416d3f81..29539ceeb74 100644
--- a/fs/nfs/dir.c
+++ b/fs/nfs/dir.c
@@ -1652,16 +1652,7 @@ static int nfs_rename(struct inode *old_dir, struct dentry *old_dentry,
}
}
- /*
- * ... prune child dentries and writebacks if needed.
- */
- if (atomic_read(&old_dentry->d_count) > 1) {
- if (S_ISREG(old_inode->i_mode))
- nfs_wb_all(old_inode);
- shrink_dcache_parent(old_dentry);
- }
nfs_inode_return_delegation(old_inode);
-
if (new_inode != NULL)
nfs_inode_return_delegation(new_inode);
@@ -1953,7 +1944,7 @@ int nfs_permission(struct inode *inode, int mask)
if ((mask & (MAY_READ | MAY_WRITE | MAY_EXEC)) == 0)
goto out;
/* Is this sys_access() ? */
- if (mask & MAY_ACCESS)
+ if (mask & (MAY_ACCESS | MAY_CHDIR))
goto force_lookup;
switch (inode->i_mode & S_IFMT) {
diff --git a/fs/nfs/direct.c b/fs/nfs/direct.c
index ad4cd31d605..064a8096167 100644
--- a/fs/nfs/direct.c
+++ b/fs/nfs/direct.c
@@ -69,6 +69,7 @@ struct nfs_direct_req {
/* I/O parameters */
struct nfs_open_context *ctx; /* file open context info */
+ struct nfs_lock_context *l_ctx; /* Lock context info */
struct kiocb * iocb; /* controlling i/o request */
struct inode * inode; /* target file of i/o */
@@ -160,6 +161,7 @@ static inline struct nfs_direct_req *nfs_direct_req_alloc(void)
INIT_LIST_HEAD(&dreq->rewrite_list);
dreq->iocb = NULL;
dreq->ctx = NULL;
+ dreq->l_ctx = NULL;
spin_lock_init(&dreq->lock);
atomic_set(&dreq->io_count, 0);
dreq->count = 0;
@@ -173,6 +175,8 @@ static void nfs_direct_req_free(struct kref *kref)
{
struct nfs_direct_req *dreq = container_of(kref, struct nfs_direct_req, kref);
+ if (dreq->l_ctx != NULL)
+ nfs_put_lock_context(dreq->l_ctx);
if (dreq->ctx != NULL)
put_nfs_open_context(dreq->ctx);
kmem_cache_free(nfs_direct_cachep, dreq);
@@ -336,6 +340,7 @@ static ssize_t nfs_direct_read_schedule_segment(struct nfs_direct_req *dreq,
data->cred = msg.rpc_cred;
data->args.fh = NFS_FH(inode);
data->args.context = ctx;
+ data->args.lock_context = dreq->l_ctx;
data->args.offset = pos;
data->args.pgbase = pgbase;
data->args.pages = data->pagevec;
@@ -416,24 +421,28 @@ static ssize_t nfs_direct_read_schedule_iovec(struct nfs_direct_req *dreq,
static ssize_t nfs_direct_read(struct kiocb *iocb, const struct iovec *iov,
unsigned long nr_segs, loff_t pos)
{
- ssize_t result = 0;
+ ssize_t result = -ENOMEM;
struct inode *inode = iocb->ki_filp->f_mapping->host;
struct nfs_direct_req *dreq;
dreq = nfs_direct_req_alloc();
- if (!dreq)
- return -ENOMEM;
+ if (dreq == NULL)
+ goto out;
dreq->inode = inode;
dreq->ctx = get_nfs_open_context(nfs_file_open_context(iocb->ki_filp));
+ dreq->l_ctx = nfs_get_lock_context(dreq->ctx);
+ if (dreq->l_ctx == NULL)
+ goto out_release;
if (!is_sync_kiocb(iocb))
dreq->iocb = iocb;
result = nfs_direct_read_schedule_iovec(dreq, iov, nr_segs, pos);
if (!result)
result = nfs_direct_wait(dreq);
+out_release:
nfs_direct_req_release(dreq);
-
+out:
return result;
}
@@ -574,6 +583,7 @@ static void nfs_direct_commit_schedule(struct nfs_direct_req *dreq)
data->args.offset = 0;
data->args.count = 0;
data->args.context = dreq->ctx;
+ data->args.lock_context = dreq->l_ctx;
data->res.count = 0;
data->res.fattr = &data->fattr;
data->res.verf = &data->verf;
@@ -761,6 +771,7 @@ static ssize_t nfs_direct_write_schedule_segment(struct nfs_direct_req *dreq,
data->cred = msg.rpc_cred;
data->args.fh = NFS_FH(inode);
data->args.context = ctx;
+ data->args.lock_context = dreq->l_ctx;
data->args.offset = pos;
data->args.pgbase = pgbase;
data->args.pages = data->pagevec;
@@ -845,7 +856,7 @@ static ssize_t nfs_direct_write(struct kiocb *iocb, const struct iovec *iov,
unsigned long nr_segs, loff_t pos,
size_t count)
{
- ssize_t result = 0;
+ ssize_t result = -ENOMEM;
struct inode *inode = iocb->ki_filp->f_mapping->host;
struct nfs_direct_req *dreq;
size_t wsize = NFS_SERVER(inode)->wsize;
@@ -853,7 +864,7 @@ static ssize_t nfs_direct_write(struct kiocb *iocb, const struct iovec *iov,
dreq = nfs_direct_req_alloc();
if (!dreq)
- return -ENOMEM;
+ goto out;
nfs_alloc_commit_data(dreq);
if (dreq->commit_data == NULL || count < wsize)
@@ -861,14 +872,18 @@ static ssize_t nfs_direct_write(struct kiocb *iocb, const struct iovec *iov,
dreq->inode = inode;
dreq->ctx = get_nfs_open_context(nfs_file_open_context(iocb->ki_filp));
+ dreq->l_ctx = nfs_get_lock_context(dreq->ctx);
+ if (dreq->l_ctx != NULL)
+ goto out_release;
if (!is_sync_kiocb(iocb))
dreq->iocb = iocb;
result = nfs_direct_write_schedule_iovec(dreq, iov, nr_segs, pos, sync);
if (!result)
result = nfs_direct_wait(dreq);
+out_release:
nfs_direct_req_release(dreq);
-
+out:
return result;
}
diff --git a/fs/nfs/file.c b/fs/nfs/file.c
index f036153d9f5..2d141a74ae8 100644
--- a/fs/nfs/file.c
+++ b/fs/nfs/file.c
@@ -203,37 +203,11 @@ static loff_t nfs_file_llseek(struct file *filp, loff_t offset, int origin)
}
/*
- * Helper for nfs_file_flush() and nfs_file_fsync()
- *
- * Notice that it clears the NFS_CONTEXT_ERROR_WRITE before synching to
- * disk, but it retrieves and clears ctx->error after synching, despite
- * the two being set at the same time in nfs_context_set_write_error().
- * This is because the former is used to notify the _next_ call to
- * nfs_file_write() that a write error occured, and hence cause it to
- * fall back to doing a synchronous write.
- */
-static int nfs_do_fsync(struct nfs_open_context *ctx, struct inode *inode)
-{
- int have_error, status;
- int ret = 0;
-
- have_error = test_and_clear_bit(NFS_CONTEXT_ERROR_WRITE, &ctx->flags);
- status = nfs_wb_all(inode);
- have_error |= test_bit(NFS_CONTEXT_ERROR_WRITE, &ctx->flags);
- if (have_error)
- ret = xchg(&ctx->error, 0);
- if (!ret)
- ret = status;
- return ret;
-}
-
-/*
* Flush all dirty pages, and check for write errors.
*/
static int
nfs_file_flush(struct file *file, fl_owner_t id)
{
- struct nfs_open_context *ctx = nfs_file_open_context(file);
struct dentry *dentry = file->f_path.dentry;
struct inode *inode = dentry->d_inode;
@@ -246,7 +220,7 @@ nfs_file_flush(struct file *file, fl_owner_t id)
return 0;
/* Flush writes to the server and return any errors */
- return nfs_do_fsync(ctx, inode);
+ return vfs_fsync(file, 0);
}
static ssize_t
@@ -321,6 +295,13 @@ nfs_file_mmap(struct file * file, struct vm_area_struct * vma)
* Flush any dirty pages for this process, and check for write errors.
* The return status from this call provides a reliable indication of
* whether any write errors occurred for this process.
+ *
+ * Notice that it clears the NFS_CONTEXT_ERROR_WRITE before synching to
+ * disk, but it retrieves and clears ctx->error after synching, despite
+ * the two being set at the same time in nfs_context_set_write_error().
+ * This is because the former is used to notify the _next_ call to
+ * nfs_file_write() that a write error occured, and hence cause it to
+ * fall back to doing a synchronous write.
*/
static int
nfs_file_fsync(struct file *file, int datasync)
@@ -328,13 +309,23 @@ nfs_file_fsync(struct file *file, int datasync)
struct dentry *dentry = file->f_path.dentry;
struct nfs_open_context *ctx = nfs_file_open_context(file);
struct inode *inode = dentry->d_inode;
+ int have_error, status;
+ int ret = 0;
+
dprintk("NFS: fsync file(%s/%s) datasync %d\n",
dentry->d_parent->d_name.name, dentry->d_name.name,
datasync);
nfs_inc_stats(inode, NFSIOS_VFSFSYNC);
- return nfs_do_fsync(ctx, inode);
+ have_error = test_and_clear_bit(NFS_CONTEXT_ERROR_WRITE, &ctx->flags);
+ status = nfs_commit_inode(inode, FLUSH_SYNC);
+ have_error |= test_bit(NFS_CONTEXT_ERROR_WRITE, &ctx->flags);
+ if (have_error)
+ ret = xchg(&ctx->error, 0);
+ if (!ret)
+ ret = status;
+ return ret;
}
/*
@@ -648,7 +639,7 @@ static ssize_t nfs_file_write(struct kiocb *iocb, const struct iovec *iov,
/* Return error values for O_DSYNC and IS_SYNC() */
if (result >= 0 && nfs_need_sync_write(iocb->ki_filp, inode)) {
- int err = nfs_do_fsync(nfs_file_open_context(iocb->ki_filp), inode);
+ int err = vfs_fsync(iocb->ki_filp, 0);
if (err < 0)
result = err;
}
@@ -684,7 +675,7 @@ static ssize_t nfs_file_splice_write(struct pipe_inode_info *pipe,
written = ret;
if (ret >= 0 && nfs_need_sync_write(filp, inode)) {
- int err = nfs_do_fsync(nfs_file_open_context(filp), inode);
+ int err = vfs_fsync(filp, 0);
if (err < 0)
ret = err;
}
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
index 099b3518fee..581d8f081e6 100644
--- a/fs/nfs/inode.c
+++ b/fs/nfs/inode.c
@@ -413,10 +413,8 @@ nfs_setattr(struct dentry *dentry, struct iattr *attr)
return 0;
/* Write all dirty data */
- if (S_ISREG(inode->i_mode)) {
- filemap_write_and_wait(inode->i_mapping);
+ if (S_ISREG(inode->i_mode))
nfs_wb_all(inode);
- }
fattr = nfs_alloc_fattr();
if (fattr == NULL)
@@ -530,6 +528,68 @@ out:
return err;
}
+static void nfs_init_lock_context(struct nfs_lock_context *l_ctx)
+{
+ atomic_set(&l_ctx->count, 1);
+ l_ctx->lockowner = current->files;
+ l_ctx->pid = current->tgid;
+ INIT_LIST_HEAD(&l_ctx->list);
+}
+
+static struct nfs_lock_context *__nfs_find_lock_context(struct nfs_open_context *ctx)
+{
+ struct nfs_lock_context *pos;
+
+ list_for_each_entry(pos, &ctx->lock_context.list, list) {
+ if (pos->lockowner != current->files)
+ continue;
+ if (pos->pid != current->tgid)
+ continue;
+ atomic_inc(&pos->count);
+ return pos;
+ }
+ return NULL;
+}
+
+struct nfs_lock_context *nfs_get_lock_context(struct nfs_open_context *ctx)
+{
+ struct nfs_lock_context *res, *new = NULL;
+ struct inode *inode = ctx->path.dentry->d_inode;
+
+ spin_lock(&inode->i_lock);
+ res = __nfs_find_lock_context(ctx);
+ if (res == NULL) {
+ spin_unlock(&inode->i_lock);
+ new = kmalloc(sizeof(*new), GFP_KERNEL);
+ if (new == NULL)
+ return NULL;
+ nfs_init_lock_context(new);
+ spin_lock(&inode->i_lock);
+ res = __nfs_find_lock_context(ctx);
+ if (res == NULL) {
+ list_add_tail(&new->list, &ctx->lock_context.list);
+ new->open_context = ctx;
+ res = new;
+ new = NULL;
+ }
+ }
+ spin_unlock(&inode->i_lock);
+ kfree(new);
+ return res;
+}
+
+void nfs_put_lock_context(struct nfs_lock_context *l_ctx)
+{
+ struct nfs_open_context *ctx = l_ctx->open_context;
+ struct inode *inode = ctx->path.dentry->d_inode;
+
+ if (!atomic_dec_and_lock(&l_ctx->count, &inode->i_lock))
+ return;
+ list_del(&l_ctx->list);
+ spin_unlock(&inode->i_lock);
+ kfree(l_ctx);
+}
+
/**
* nfs_close_context - Common close_context() routine NFSv2/v3
* @ctx: pointer to context
@@ -566,11 +626,11 @@ static struct nfs_open_context *alloc_nfs_open_context(struct path *path, struct
path_get(&ctx->path);
ctx->cred = get_rpccred(cred);
ctx->state = NULL;
- ctx->lockowner = current->files;
ctx->flags = 0;
ctx->error = 0;
ctx->dir_cookie = 0;
- atomic_set(&ctx->count, 1);
+ nfs_init_lock_context(&ctx->lock_context);
+ ctx->lock_context.open_context = ctx;
}
return ctx;
}
@@ -578,7 +638,7 @@ static struct nfs_open_context *alloc_nfs_open_context(struct path *path, struct
struct nfs_open_context *get_nfs_open_context(struct nfs_open_context *ctx)
{
if (ctx != NULL)
- atomic_inc(&ctx->count);
+ atomic_inc(&ctx->lock_context.count);
return ctx;
}
@@ -586,7 +646,7 @@ static void __put_nfs_open_context(struct nfs_open_context *ctx, int is_sync)
{
struct inode *inode = ctx->path.dentry->d_inode;
- if (!atomic_dec_and_lock(&ctx->count, &inode->i_lock))
+ if (!atomic_dec_and_lock(&ctx->lock_context.count, &inode->i_lock))
return;
list_del(&ctx->list);
spin_unlock(&inode->i_lock);
diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h
index e70f44b9b3f..4c2150d8671 100644
--- a/fs/nfs/internal.h
+++ b/fs/nfs/internal.h
@@ -370,10 +370,9 @@ unsigned int nfs_page_array_len(unsigned int base, size_t len)
* Helper for restarting RPC calls in the possible presence of NFSv4.1
* sessions.
*/
-static inline void nfs_restart_rpc(struct rpc_task *task, const struct nfs_client *clp)
+static inline int nfs_restart_rpc(struct rpc_task *task, const struct nfs_client *clp)
{
if (nfs4_has_session(clp))
- rpc_restart_call_prepare(task);
- else
- rpc_restart_call(task);
+ return rpc_restart_call_prepare(task);
+ return rpc_restart_call(task);
}
diff --git a/fs/nfs/nfs2xdr.c b/fs/nfs/nfs2xdr.c
index 81cf1425791..db8846a0e82 100644
--- a/fs/nfs/nfs2xdr.c
+++ b/fs/nfs/nfs2xdr.c
@@ -233,7 +233,7 @@ nfs_xdr_removeargs(struct rpc_rqst *req, __be32 *p, const struct nfs_removeargs
static int
nfs_xdr_readargs(struct rpc_rqst *req, __be32 *p, struct nfs_readargs *args)
{
- struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth;
+ struct rpc_auth *auth = req->rq_cred->cr_auth;
unsigned int replen;
u32 offset = (u32)args->offset;
u32 count = args->count;
@@ -393,8 +393,7 @@ nfs_xdr_symlinkargs(struct rpc_rqst *req, __be32 *p, struct nfs_symlinkargs *arg
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_msg.rpc_cred->cr_auth;
+ struct rpc_auth *auth = req->rq_cred->cr_auth;
unsigned int replen;
u32 count = args->count;
@@ -575,7 +574,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_msg.rpc_cred->cr_auth;
+ struct rpc_auth *auth = req->rq_cred->cr_auth;
unsigned int replen;
p = xdr_encode_fhandle(p, args->fh);
diff --git a/fs/nfs/nfs3xdr.c b/fs/nfs/nfs3xdr.c
index 75dcfc7da36..9769704f8ce 100644
--- a/fs/nfs/nfs3xdr.c
+++ b/fs/nfs/nfs3xdr.c
@@ -330,7 +330,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_msg.rpc_cred->cr_auth;
+ struct rpc_auth *auth = req->rq_cred->cr_auth;
unsigned int replen;
u32 count = args->count;
@@ -471,7 +471,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_msg.rpc_cred->cr_auth;
+ struct rpc_auth *auth = req->rq_cred->cr_auth;
unsigned int replen;
u32 count = args->count;
@@ -675,7 +675,7 @@ static int
nfs3_xdr_getaclargs(struct rpc_rqst *req, __be32 *p,
struct nfs3_getaclargs *args)
{
- struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth;
+ struct rpc_auth *auth = req->rq_cred->cr_auth;
unsigned int replen;
p = xdr_encode_fhandle(p, args->fh);
@@ -802,7 +802,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_msg.rpc_cred->cr_auth;
+ struct rpc_auth *auth = req->rq_cred->cr_auth;
unsigned int replen;
p = xdr_encode_fhandle(p, args->fh);
diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h
index c538c6106e1..311e15cc8af 100644
--- a/fs/nfs/nfs4_fs.h
+++ b/fs/nfs/nfs4_fs.h
@@ -45,10 +45,29 @@ enum nfs4_client_state {
NFS4CLNT_RECLAIM_NOGRACE,
NFS4CLNT_DELEGRETURN,
NFS4CLNT_SESSION_RESET,
- NFS4CLNT_SESSION_DRAINING,
NFS4CLNT_RECALL_SLOT,
};
+enum nfs4_session_state {
+ NFS4_SESSION_INITING,
+ NFS4_SESSION_DRAINING,
+};
+
+struct nfs4_minor_version_ops {
+ u32 minor_version;
+
+ int (*call_sync)(struct nfs_server *server,
+ struct rpc_message *msg,
+ struct nfs4_sequence_args *args,
+ struct nfs4_sequence_res *res,
+ int cache_reply);
+ int (*validate_stateid)(struct nfs_delegation *,
+ const nfs4_stateid *);
+ const struct nfs4_state_recovery_ops *reboot_recovery_ops;
+ const struct nfs4_state_recovery_ops *nograce_recovery_ops;
+ const struct nfs4_state_maintenance_ops *state_renewal_ops;
+};
+
/*
* struct rpc_sequence ensures that RPC calls are sent in the exact
* order that they appear on the list.
@@ -89,7 +108,6 @@ struct nfs_unique_id {
*/
struct nfs4_state_owner {
struct nfs_unique_id so_owner_id;
- struct nfs_client *so_client;
struct nfs_server *so_server;
struct rb_node so_client_node;
@@ -99,7 +117,6 @@ struct nfs4_state_owner {
atomic_t so_count;
unsigned long so_flags;
struct list_head so_states;
- struct list_head so_delegations;
struct nfs_seqid_counter so_seqid;
struct rpc_sequence so_sequence;
};
@@ -125,10 +142,20 @@ enum {
* LOCK: one nfs4_state (LOCK) to hold the lock stateid nfs4_state(OPEN)
*/
+struct nfs4_lock_owner {
+ unsigned int lo_type;
+#define NFS4_ANY_LOCK_TYPE (0U)
+#define NFS4_FLOCK_LOCK_TYPE (1U << 0)
+#define NFS4_POSIX_LOCK_TYPE (1U << 1)
+ union {
+ fl_owner_t posix_owner;
+ pid_t flock_owner;
+ } lo_u;
+};
+
struct nfs4_lock_state {
struct list_head ls_locks; /* Other lock stateids */
struct nfs4_state * ls_state; /* Pointer to open state */
- fl_owner_t ls_owner; /* POSIX lock owner */
#define NFS_LOCK_INITIALIZED 1
int ls_flags;
struct nfs_seqid_counter ls_seqid;
@@ -136,6 +163,7 @@ struct nfs4_lock_state {
struct nfs_unique_id ls_id;
nfs4_stateid ls_stateid;
atomic_t ls_count;
+ struct nfs4_lock_owner ls_owner;
};
/* bits for nfs4_state->flags */
@@ -219,11 +247,15 @@ extern int nfs4_open_revalidate(struct inode *, struct dentry *, int, struct nam
extern int nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *fhandle);
extern int nfs4_proc_fs_locations(struct inode *dir, const struct qstr *name,
struct nfs4_fs_locations *fs_locations, struct page *page);
+extern void nfs4_release_lockowner(const struct nfs4_lock_state *);
-extern struct nfs4_state_recovery_ops *nfs4_reboot_recovery_ops[];
-extern struct nfs4_state_recovery_ops *nfs4_nograce_recovery_ops[];
#if defined(CONFIG_NFS_V4_1)
-extern int nfs4_setup_sequence(struct nfs_client *clp,
+static inline struct nfs4_session *nfs4_get_session(const struct nfs_server *server)
+{
+ return server->nfs_client->cl_session;
+}
+
+extern int nfs4_setup_sequence(const struct nfs_server *server,
struct nfs4_sequence_args *args, struct nfs4_sequence_res *res,
int cache_reply, struct rpc_task *task);
extern void nfs4_destroy_session(struct nfs4_session *session);
@@ -234,7 +266,12 @@ extern int nfs4_init_session(struct nfs_server *server);
extern int nfs4_proc_get_lease_time(struct nfs_client *clp,
struct nfs_fsinfo *fsinfo);
#else /* CONFIG_NFS_v4_1 */
-static inline int nfs4_setup_sequence(struct nfs_client *clp,
+static inline struct nfs4_session *nfs4_get_session(const struct nfs_server *server)
+{
+ return NULL;
+}
+
+static inline int nfs4_setup_sequence(const struct nfs_server *server,
struct nfs4_sequence_args *args, struct nfs4_sequence_res *res,
int cache_reply, struct rpc_task *task)
{
@@ -247,7 +284,7 @@ static inline int nfs4_init_session(struct nfs_server *server)
}
#endif /* CONFIG_NFS_V4_1 */
-extern struct nfs4_state_maintenance_ops *nfs4_state_renewal_ops[];
+extern const struct nfs4_minor_version_ops *nfs_v4_minor_ops[];
extern const u32 nfs4_fattr_bitmap[2];
extern const u32 nfs4_statfs_bitmap[2];
@@ -284,7 +321,7 @@ extern void nfs41_handle_sequence_flag_errors(struct nfs_client *clp, u32 flags)
extern void nfs41_handle_recall_slot(struct nfs_client *clp);
extern void nfs4_put_lock_state(struct nfs4_lock_state *lsp);
extern int nfs4_set_lock_state(struct nfs4_state *state, struct file_lock *fl);
-extern void nfs4_copy_stateid(nfs4_stateid *, struct nfs4_state *, fl_owner_t);
+extern void nfs4_copy_stateid(nfs4_stateid *, struct nfs4_state *, fl_owner_t, pid_t);
extern struct nfs_seqid *nfs_alloc_seqid(struct nfs_seqid_counter *counter, gfp_t gfp_mask);
extern int nfs_wait_on_sequence(struct nfs_seqid *seqid, struct rpc_task *task);
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index 70015dd60a9..7ffbb98ddec 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -303,15 +303,19 @@ do_state_recovery:
}
-static void renew_lease(const struct nfs_server *server, unsigned long timestamp)
+static void do_renew_lease(struct nfs_client *clp, unsigned long timestamp)
{
- struct nfs_client *clp = server->nfs_client;
spin_lock(&clp->cl_lock);
if (time_before(clp->cl_last_renewal,timestamp))
clp->cl_last_renewal = timestamp;
spin_unlock(&clp->cl_lock);
}
+static void renew_lease(const struct nfs_server *server, unsigned long timestamp)
+{
+ do_renew_lease(server->nfs_client, timestamp);
+}
+
#if defined(CONFIG_NFS_V4_1)
/*
@@ -356,7 +360,7 @@ static void nfs41_check_drain_session_complete(struct nfs4_session *ses)
{
struct rpc_task *task;
- if (!test_bit(NFS4CLNT_SESSION_DRAINING, &ses->clp->cl_state)) {
+ if (!test_bit(NFS4_SESSION_DRAINING, &ses->session_state)) {
task = rpc_wake_up_next(&ses->fc_slot_table.slot_tbl_waitq);
if (task)
rpc_task_set_priority(task, RPC_PRIORITY_PRIVILEGED);
@@ -370,12 +374,11 @@ static void nfs41_check_drain_session_complete(struct nfs4_session *ses)
complete(&ses->complete);
}
-static void nfs41_sequence_free_slot(const struct nfs_client *clp,
- struct nfs4_sequence_res *res)
+static void nfs41_sequence_free_slot(struct nfs4_sequence_res *res)
{
struct nfs4_slot_table *tbl;
- tbl = &clp->cl_session->fc_slot_table;
+ tbl = &res->sr_session->fc_slot_table;
if (res->sr_slotid == NFS4_MAX_SLOT_TABLE) {
/* just wake up the next guy waiting since
* we may have not consumed a slot after all */
@@ -385,18 +388,17 @@ static void nfs41_sequence_free_slot(const struct nfs_client *clp,
spin_lock(&tbl->slot_tbl_lock);
nfs4_free_slot(tbl, res->sr_slotid);
- nfs41_check_drain_session_complete(clp->cl_session);
+ nfs41_check_drain_session_complete(res->sr_session);
spin_unlock(&tbl->slot_tbl_lock);
res->sr_slotid = NFS4_MAX_SLOT_TABLE;
}
-static void nfs41_sequence_done(struct nfs_client *clp,
- struct nfs4_sequence_res *res,
- int rpc_status)
+static int nfs41_sequence_done(struct rpc_task *task, struct nfs4_sequence_res *res)
{
unsigned long timestamp;
struct nfs4_slot_table *tbl;
struct nfs4_slot *slot;
+ struct nfs_client *clp;
/*
* sr_status remains 1 if an RPC level error occurred. The server
@@ -411,25 +413,51 @@ static void nfs41_sequence_done(struct nfs_client *clp,
if (res->sr_slotid == NFS4_MAX_SLOT_TABLE)
goto out;
+ tbl = &res->sr_session->fc_slot_table;
+ slot = tbl->slots + res->sr_slotid;
+
/* Check the SEQUENCE operation status */
- if (res->sr_status == 0) {
- tbl = &clp->cl_session->fc_slot_table;
- slot = tbl->slots + res->sr_slotid;
+ switch (res->sr_status) {
+ case 0:
/* Update the slot's sequence and clientid lease timer */
++slot->seq_nr;
timestamp = res->sr_renewal_time;
- spin_lock(&clp->cl_lock);
- if (time_before(clp->cl_last_renewal, timestamp))
- clp->cl_last_renewal = timestamp;
- spin_unlock(&clp->cl_lock);
+ clp = res->sr_session->clp;
+ do_renew_lease(clp, timestamp);
/* Check sequence flags */
if (atomic_read(&clp->cl_count) > 1)
nfs41_handle_sequence_flag_errors(clp, res->sr_status_flags);
+ break;
+ case -NFS4ERR_DELAY:
+ /* The server detected a resend of the RPC call and
+ * returned NFS4ERR_DELAY as per Section 2.10.6.2
+ * of RFC5661.
+ */
+ dprintk("%s: slot=%d seq=%d: Operation in progress\n",
+ __func__, res->sr_slotid, slot->seq_nr);
+ goto out_retry;
+ default:
+ /* Just update the slot sequence no. */
+ ++slot->seq_nr;
}
out:
/* The session may be reset by one of the error handlers. */
dprintk("%s: Error %d free the slot \n", __func__, res->sr_status);
- nfs41_sequence_free_slot(clp, res);
+ nfs41_sequence_free_slot(res);
+ return 1;
+out_retry:
+ if (!rpc_restart_call(task))
+ goto out;
+ rpc_delay(task, NFS4_POLL_RETRY_MAX);
+ return 0;
+}
+
+static int nfs4_sequence_done(struct rpc_task *task,
+ struct nfs4_sequence_res *res)
+{
+ if (res->sr_session == NULL)
+ return 1;
+ return nfs41_sequence_done(task, res);
}
/*
@@ -480,12 +508,11 @@ static int nfs41_setup_sequence(struct nfs4_session *session,
if (res->sr_slotid != NFS4_MAX_SLOT_TABLE)
return 0;
- memset(res, 0, sizeof(*res));
res->sr_slotid = NFS4_MAX_SLOT_TABLE;
tbl = &session->fc_slot_table;
spin_lock(&tbl->slot_tbl_lock);
- if (test_bit(NFS4CLNT_SESSION_DRAINING, &session->clp->cl_state) &&
+ if (test_bit(NFS4_SESSION_DRAINING, &session->session_state) &&
!rpc_task_has_priority(task, RPC_PRIORITY_PRIVILEGED)) {
/*
* The state manager will wait until the slot table is empty.
@@ -525,6 +552,7 @@ static int nfs41_setup_sequence(struct nfs4_session *session,
res->sr_session = session;
res->sr_slotid = slotid;
res->sr_renewal_time = jiffies;
+ res->sr_status_flags = 0;
/*
* sr_status is only set in decode_sequence, and so will remain
* set to 1 if an rpc level failure occurs.
@@ -533,33 +561,33 @@ static int nfs41_setup_sequence(struct nfs4_session *session,
return 0;
}
-int nfs4_setup_sequence(struct nfs_client *clp,
+int nfs4_setup_sequence(const struct nfs_server *server,
struct nfs4_sequence_args *args,
struct nfs4_sequence_res *res,
int cache_reply,
struct rpc_task *task)
{
+ struct nfs4_session *session = nfs4_get_session(server);
int ret = 0;
+ if (session == NULL) {
+ args->sa_session = NULL;
+ res->sr_session = NULL;
+ goto out;
+ }
+
dprintk("--> %s clp %p session %p sr_slotid %d\n",
- __func__, clp, clp->cl_session, res->sr_slotid);
+ __func__, session->clp, session, res->sr_slotid);
- if (!nfs4_has_session(clp))
- goto out;
- ret = nfs41_setup_sequence(clp->cl_session, args, res, cache_reply,
+ ret = nfs41_setup_sequence(session, args, res, cache_reply,
task);
- if (ret && ret != -EAGAIN) {
- /* terminate rpc task */
- task->tk_status = ret;
- task->tk_action = NULL;
- }
out:
dprintk("<-- %s status=%d\n", __func__, ret);
return ret;
}
struct nfs41_call_sync_data {
- struct nfs_client *clp;
+ const struct nfs_server *seq_server;
struct nfs4_sequence_args *seq_args;
struct nfs4_sequence_res *seq_res;
int cache_reply;
@@ -569,9 +597,9 @@ static void nfs41_call_sync_prepare(struct rpc_task *task, void *calldata)
{
struct nfs41_call_sync_data *data = calldata;
- dprintk("--> %s data->clp->cl_session %p\n", __func__,
- data->clp->cl_session);
- if (nfs4_setup_sequence(data->clp, data->seq_args,
+ dprintk("--> %s data->seq_server %p\n", __func__, data->seq_server);
+
+ if (nfs4_setup_sequence(data->seq_server, data->seq_args,
data->seq_res, data->cache_reply, task))
return;
rpc_call_start(task);
@@ -587,7 +615,7 @@ static void nfs41_call_sync_done(struct rpc_task *task, void *calldata)
{
struct nfs41_call_sync_data *data = calldata;
- nfs41_sequence_done(data->clp, data->seq_res, task->tk_status);
+ nfs41_sequence_done(task, data->seq_res);
}
struct rpc_call_ops nfs41_call_sync_ops = {
@@ -600,8 +628,7 @@ struct rpc_call_ops nfs41_call_priv_sync_ops = {
.rpc_call_done = nfs41_call_sync_done,
};
-static int nfs4_call_sync_sequence(struct nfs_client *clp,
- struct rpc_clnt *clnt,
+static int nfs4_call_sync_sequence(struct nfs_server *server,
struct rpc_message *msg,
struct nfs4_sequence_args *args,
struct nfs4_sequence_res *res,
@@ -611,13 +638,13 @@ static int nfs4_call_sync_sequence(struct nfs_client *clp,
int ret;
struct rpc_task *task;
struct nfs41_call_sync_data data = {
- .clp = clp,
+ .seq_server = server,
.seq_args = args,
.seq_res = res,
.cache_reply = cache_reply,
};
struct rpc_task_setup task_setup = {
- .rpc_client = clnt,
+ .rpc_client = server->client,
.rpc_message = msg,
.callback_ops = &nfs41_call_sync_ops,
.callback_data = &data
@@ -642,10 +669,15 @@ int _nfs4_call_sync_session(struct nfs_server *server,
struct nfs4_sequence_res *res,
int cache_reply)
{
- return nfs4_call_sync_sequence(server->nfs_client, server->client,
- msg, args, res, cache_reply, 0);
+ return nfs4_call_sync_sequence(server, msg, args, res, cache_reply, 0);
}
+#else
+static int nfs4_sequence_done(struct rpc_task *task,
+ struct nfs4_sequence_res *res)
+{
+ return 1;
+}
#endif /* CONFIG_NFS_V4_1 */
int _nfs4_call_sync(struct nfs_server *server,
@@ -659,18 +691,9 @@ int _nfs4_call_sync(struct nfs_server *server,
}
#define nfs4_call_sync(server, msg, args, res, cache_reply) \
- (server)->nfs_client->cl_call_sync((server), (msg), &(args)->seq_args, \
+ (server)->nfs_client->cl_mvops->call_sync((server), (msg), &(args)->seq_args, \
&(res)->seq_res, (cache_reply))
-static void nfs4_sequence_done(const struct nfs_server *server,
- struct nfs4_sequence_res *res, int rpc_status)
-{
-#ifdef CONFIG_NFS_V4_1
- if (nfs4_has_session(server->nfs_client))
- nfs41_sequence_done(server->nfs_client, res, rpc_status);
-#endif /* CONFIG_NFS_V4_1 */
-}
-
static void update_changeattr(struct inode *dir, struct nfs4_change_info *cinfo)
{
struct nfs_inode *nfsi = NFS_I(dir);
@@ -745,19 +768,14 @@ static struct nfs4_opendata *nfs4_opendata_alloc(struct path *path,
p->o_arg.server = server;
p->o_arg.bitmask = server->attr_bitmask;
p->o_arg.claim = NFS4_OPEN_CLAIM_NULL;
- if (flags & O_EXCL) {
- if (nfs4_has_persistent_session(server->nfs_client)) {
- /* GUARDED */
- p->o_arg.u.attrs = &p->attrs;
- memcpy(&p->attrs, attrs, sizeof(p->attrs));
- } else { /* EXCLUSIVE4_1 */
- u32 *s = (u32 *) p->o_arg.u.verifier.data;
- s[0] = jiffies;
- s[1] = current->pid;
- }
- } else if (flags & O_CREAT) {
+ if (flags & O_CREAT) {
+ u32 *s;
+
p->o_arg.u.attrs = &p->attrs;
memcpy(&p->attrs, attrs, sizeof(p->attrs));
+ s = (u32 *) p->o_arg.u.verifier.data;
+ s[0] = jiffies;
+ s[1] = current->pid;
}
p->c_arg.fh = &p->o_res.fh;
p->c_arg.stateid = &p->o_res.stateid;
@@ -1255,8 +1273,6 @@ static void nfs4_open_confirm_done(struct rpc_task *task, void *calldata)
struct nfs4_opendata *data = calldata;
data->rpc_status = task->tk_status;
- if (RPC_ASSASSINATED(task))
- return;
if (data->rpc_status == 0) {
memcpy(data->o_res.stateid.data, data->c_res.stateid.data,
sizeof(data->o_res.stateid.data));
@@ -1356,13 +1372,13 @@ static void nfs4_open_prepare(struct rpc_task *task, void *calldata)
}
/* Update sequence id. */
data->o_arg.id = sp->so_owner_id.id;
- data->o_arg.clientid = sp->so_client->cl_clientid;
+ data->o_arg.clientid = sp->so_server->nfs_client->cl_clientid;
if (data->o_arg.claim == NFS4_OPEN_CLAIM_PREVIOUS) {
task->tk_msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN_NOATTR];
nfs_copy_fh(&data->o_res.fh, data->o_arg.fh);
}
data->timestamp = jiffies;
- if (nfs4_setup_sequence(data->o_arg.server->nfs_client,
+ if (nfs4_setup_sequence(data->o_arg.server,
&data->o_arg.seq_args,
&data->o_res.seq_res, 1, task))
return;
@@ -1385,11 +1401,9 @@ static void nfs4_open_done(struct rpc_task *task, void *calldata)
data->rpc_status = task->tk_status;
- nfs4_sequence_done(data->o_arg.server, &data->o_res.seq_res,
- task->tk_status);
-
- if (RPC_ASSASSINATED(task))
+ if (!nfs4_sequence_done(task, &data->o_res.seq_res))
return;
+
if (task->tk_status == 0) {
switch (data->o_res.f_attr->mode & S_IFMT) {
case S_IFREG:
@@ -1773,7 +1787,7 @@ static int _nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred,
if (nfs4_copy_delegation_stateid(&arg.stateid, inode)) {
/* Use that stateid */
} else if (state != NULL) {
- nfs4_copy_stateid(&arg.stateid, state, current->files);
+ nfs4_copy_stateid(&arg.stateid, state, current->files, current->tgid);
} else
memcpy(&arg.stateid, &zero_stateid, sizeof(arg.stateid));
@@ -1838,8 +1852,7 @@ static void nfs4_close_done(struct rpc_task *task, void *data)
struct nfs4_state *state = calldata->state;
struct nfs_server *server = NFS_SERVER(calldata->inode);
- nfs4_sequence_done(server, &calldata->res.seq_res, task->tk_status);
- if (RPC_ASSASSINATED(task))
+ if (!nfs4_sequence_done(task, &calldata->res.seq_res))
return;
/* hmm. we are done with the inode, and in the process of freeing
* the state_owner. we keep this around to process errors
@@ -1903,7 +1916,7 @@ static void nfs4_close_prepare(struct rpc_task *task, void *data)
nfs_fattr_init(calldata->res.fattr);
calldata->timestamp = jiffies;
- if (nfs4_setup_sequence((NFS_SERVER(calldata->inode))->nfs_client,
+ if (nfs4_setup_sequence(NFS_SERVER(calldata->inode),
&calldata->arg.seq_args, &calldata->res.seq_res,
1, task))
return;
@@ -2648,7 +2661,8 @@ static int nfs4_proc_unlink_done(struct rpc_task *task, struct inode *dir)
{
struct nfs_removeres *res = task->tk_msg.rpc_resp;
- nfs4_sequence_done(res->server, &res->seq_res, task->tk_status);
+ if (!nfs4_sequence_done(task, &res->seq_res))
+ return 0;
if (nfs4_async_handle_error(task, res->server, NULL) == -EAGAIN)
return 0;
update_changeattr(dir, &res->cinfo);
@@ -3093,7 +3107,8 @@ static int nfs4_read_done(struct rpc_task *task, struct nfs_read_data *data)
dprintk("--> %s\n", __func__);
- nfs4_sequence_done(server, &data->res.seq_res, task->tk_status);
+ if (!nfs4_sequence_done(task, &data->res.seq_res))
+ return -EAGAIN;
if (nfs4_async_handle_error(task, server, data->args.context->state) == -EAGAIN) {
nfs_restart_rpc(task, server->nfs_client);
@@ -3116,8 +3131,8 @@ static int nfs4_write_done(struct rpc_task *task, struct nfs_write_data *data)
{
struct inode *inode = data->inode;
- nfs4_sequence_done(NFS_SERVER(inode), &data->res.seq_res,
- task->tk_status);
+ if (!nfs4_sequence_done(task, &data->res.seq_res))
+ return -EAGAIN;
if (nfs4_async_handle_error(task, NFS_SERVER(inode), data->args.context->state) == -EAGAIN) {
nfs_restart_rpc(task, NFS_SERVER(inode)->nfs_client);
@@ -3145,8 +3160,9 @@ static int nfs4_commit_done(struct rpc_task *task, struct nfs_write_data *data)
{
struct inode *inode = data->inode;
- nfs4_sequence_done(NFS_SERVER(inode), &data->res.seq_res,
- task->tk_status);
+ if (!nfs4_sequence_done(task, &data->res.seq_res))
+ return -EAGAIN;
+
if (nfs4_async_handle_error(task, NFS_SERVER(inode), NULL) == -EAGAIN) {
nfs_restart_rpc(task, NFS_SERVER(inode)->nfs_client);
return -EAGAIN;
@@ -3196,10 +3212,7 @@ static void nfs4_renew_done(struct rpc_task *task, void *calldata)
nfs4_schedule_state_recovery(clp);
return;
}
- spin_lock(&clp->cl_lock);
- if (time_before(clp->cl_last_renewal,timestamp))
- clp->cl_last_renewal = timestamp;
- spin_unlock(&clp->cl_lock);
+ do_renew_lease(clp, timestamp);
}
static const struct rpc_call_ops nfs4_renew_ops = {
@@ -3240,10 +3253,7 @@ int nfs4_proc_renew(struct nfs_client *clp, struct rpc_cred *cred)
status = rpc_call_sync(clp->cl_rpcclient, &msg, 0);
if (status < 0)
return status;
- spin_lock(&clp->cl_lock);
- if (time_before(clp->cl_last_renewal,now))
- clp->cl_last_renewal = now;
- spin_unlock(&clp->cl_lock);
+ do_renew_lease(clp, now);
return 0;
}
@@ -3464,9 +3474,11 @@ static int nfs4_proc_set_acl(struct inode *inode, const void *buf, size_t buflen
}
static int
-_nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server, struct nfs_client *clp, struct nfs4_state *state)
+nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server, struct nfs4_state *state)
{
- if (!clp || task->tk_status >= 0)
+ struct nfs_client *clp = server->nfs_client;
+
+ if (task->tk_status >= 0)
return 0;
switch(task->tk_status) {
case -NFS4ERR_ADMIN_REVOKED:
@@ -3498,8 +3510,7 @@ _nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server,
return -EAGAIN;
#endif /* CONFIG_NFS_V4_1 */
case -NFS4ERR_DELAY:
- if (server)
- nfs_inc_server_stats(server, NFSIOS_DELAY);
+ nfs_inc_server_stats(server, NFSIOS_DELAY);
case -NFS4ERR_GRACE:
case -EKEYEXPIRED:
rpc_delay(task, NFS4_POLL_RETRY_MAX);
@@ -3520,12 +3531,6 @@ do_state_recovery:
return -EAGAIN;
}
-static int
-nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server, struct nfs4_state *state)
-{
- return _nfs4_async_handle_error(task, server, server->nfs_client, state);
-}
-
int nfs4_proc_setclientid(struct nfs_client *clp, u32 program,
unsigned short port, struct rpc_cred *cred,
struct nfs4_setclientid_res *res)
@@ -3641,8 +3646,8 @@ static void nfs4_delegreturn_done(struct rpc_task *task, void *calldata)
{
struct nfs4_delegreturndata *data = calldata;
- nfs4_sequence_done(data->res.server, &data->res.seq_res,
- task->tk_status);
+ if (!nfs4_sequence_done(task, &data->res.seq_res))
+ return;
switch (task->tk_status) {
case -NFS4ERR_STALE_STATEID:
@@ -3672,7 +3677,7 @@ static void nfs4_delegreturn_prepare(struct rpc_task *task, void *data)
d_data = (struct nfs4_delegreturndata *)data;
- if (nfs4_setup_sequence(d_data->res.server->nfs_client,
+ if (nfs4_setup_sequence(d_data->res.server,
&d_data->args.seq_args,
&d_data->res.seq_res, 1, task))
return;
@@ -3892,9 +3897,7 @@ static void nfs4_locku_done(struct rpc_task *task, void *data)
{
struct nfs4_unlockdata *calldata = data;
- nfs4_sequence_done(calldata->server, &calldata->res.seq_res,
- task->tk_status);
- if (RPC_ASSASSINATED(task))
+ if (!nfs4_sequence_done(task, &calldata->res.seq_res))
return;
switch (task->tk_status) {
case 0:
@@ -3927,7 +3930,7 @@ static void nfs4_locku_prepare(struct rpc_task *task, void *data)
return;
}
calldata->timestamp = jiffies;
- if (nfs4_setup_sequence(calldata->server->nfs_client,
+ if (nfs4_setup_sequence(calldata->server,
&calldata->arg.seq_args,
&calldata->res.seq_res, 1, task))
return;
@@ -4082,7 +4085,8 @@ static void nfs4_lock_prepare(struct rpc_task *task, void *calldata)
} else
data->arg.new_lock_owner = 0;
data->timestamp = jiffies;
- if (nfs4_setup_sequence(data->server->nfs_client, &data->arg.seq_args,
+ if (nfs4_setup_sequence(data->server,
+ &data->arg.seq_args,
&data->res.seq_res, 1, task))
return;
rpc_call_start(task);
@@ -4101,12 +4105,10 @@ static void nfs4_lock_done(struct rpc_task *task, void *calldata)
dprintk("%s: begin!\n", __func__);
- nfs4_sequence_done(data->server, &data->res.seq_res,
- task->tk_status);
+ if (!nfs4_sequence_done(task, &data->res.seq_res))
+ return;
data->rpc_status = task->tk_status;
- if (RPC_ASSASSINATED(task))
- goto out;
if (data->arg.new_lock_owner != 0) {
if (data->rpc_status == 0)
nfs_confirm_seqid(&data->lsp->ls_seqid, 0);
@@ -4424,6 +4426,34 @@ out:
return err;
}
+static void nfs4_release_lockowner_release(void *calldata)
+{
+ kfree(calldata);
+}
+
+const struct rpc_call_ops nfs4_release_lockowner_ops = {
+ .rpc_release = nfs4_release_lockowner_release,
+};
+
+void nfs4_release_lockowner(const struct nfs4_lock_state *lsp)
+{
+ struct nfs_server *server = lsp->ls_state->owner->so_server;
+ struct nfs_release_lockowner_args *args;
+ struct rpc_message msg = {
+ .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_RELEASE_LOCKOWNER],
+ };
+
+ if (server->nfs_client->cl_mvops->minor_version != 0)
+ return;
+ args = kmalloc(sizeof(*args), GFP_NOFS);
+ if (!args)
+ return;
+ args->lock_owner.clientid = server->nfs_client->cl_clientid;
+ args->lock_owner.id = lsp->ls_id.id;
+ msg.rpc_argp = args;
+ rpc_call_async(server->client, &msg, 0, &nfs4_release_lockowner_ops, args);
+}
+
#define XATTR_NAME_NFSV4_ACL "system.nfs4_acl"
int nfs4_setxattr(struct dentry *dentry, const char *key, const void *buf,
@@ -4611,7 +4641,8 @@ static void nfs4_get_lease_time_done(struct rpc_task *task, void *calldata)
(struct nfs4_get_lease_time_data *)calldata;
dprintk("--> %s\n", __func__);
- nfs41_sequence_done(data->clp, &data->res->lr_seq_res, task->tk_status);
+ if (!nfs41_sequence_done(task, &data->res->lr_seq_res))
+ return;
switch (task->tk_status) {
case -NFS4ERR_DELAY:
case -NFS4ERR_GRACE:
@@ -4805,13 +4836,6 @@ struct nfs4_session *nfs4_alloc_session(struct nfs_client *clp)
if (!session)
return NULL;
- /*
- * The create session reply races with the server back
- * channel probe. Mark the client NFS_CS_SESSION_INITING
- * so that the client back channel can find the
- * nfs_client struct
- */
- clp->cl_cons_state = NFS_CS_SESSION_INITING;
init_completion(&session->complete);
tbl = &session->fc_slot_table;
@@ -4824,6 +4848,8 @@ struct nfs4_session *nfs4_alloc_session(struct nfs_client *clp)
spin_lock_init(&tbl->slot_tbl_lock);
rpc_init_wait_queue(&tbl->slot_tbl_waitq, "BackChannel Slot table");
+ session->session_state = 1<<NFS4_SESSION_INITING;
+
session->clp = clp;
return session;
}
@@ -5040,6 +5066,10 @@ int nfs4_init_session(struct nfs_server *server)
if (!nfs4_has_session(clp))
return 0;
+ session = clp->cl_session;
+ if (!test_and_clear_bit(NFS4_SESSION_INITING, &session->session_state))
+ return 0;
+
rsize = server->rsize;
if (rsize == 0)
rsize = NFS_MAX_FILE_IO_SIZE;
@@ -5047,7 +5077,6 @@ int nfs4_init_session(struct nfs_server *server)
if (wsize == 0)
wsize = NFS_MAX_FILE_IO_SIZE;
- session = clp->cl_session;
session->fc_attrs.max_rqst_sz = wsize + nfs41_maxwrite_overhead;
session->fc_attrs.max_resp_sz = rsize + nfs41_maxread_overhead;
@@ -5060,69 +5089,70 @@ int nfs4_init_session(struct nfs_server *server)
/*
* Renew the cl_session lease.
*/
-static int nfs4_proc_sequence(struct nfs_client *clp, struct rpc_cred *cred)
-{
+struct nfs4_sequence_data {
+ struct nfs_client *clp;
struct nfs4_sequence_args args;
struct nfs4_sequence_res res;
-
- struct rpc_message msg = {
- .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SEQUENCE],
- .rpc_argp = &args,
- .rpc_resp = &res,
- .rpc_cred = cred,
- };
-
- args.sa_cache_this = 0;
-
- return nfs4_call_sync_sequence(clp, clp->cl_rpcclient, &msg, &args,
- &res, args.sa_cache_this, 1);
-}
+};
static void nfs41_sequence_release(void *data)
{
- struct nfs_client *clp = (struct nfs_client *)data;
+ struct nfs4_sequence_data *calldata = data;
+ struct nfs_client *clp = calldata->clp;
if (atomic_read(&clp->cl_count) > 1)
nfs4_schedule_state_renewal(clp);
nfs_put_client(clp);
+ kfree(calldata);
+}
+
+static int nfs41_sequence_handle_errors(struct rpc_task *task, struct nfs_client *clp)
+{
+ switch(task->tk_status) {
+ case -NFS4ERR_DELAY:
+ case -EKEYEXPIRED:
+ rpc_delay(task, NFS4_POLL_RETRY_MAX);
+ return -EAGAIN;
+ default:
+ nfs4_schedule_state_recovery(clp);
+ }
+ return 0;
}
static void nfs41_sequence_call_done(struct rpc_task *task, void *data)
{
- struct nfs_client *clp = (struct nfs_client *)data;
+ struct nfs4_sequence_data *calldata = data;
+ struct nfs_client *clp = calldata->clp;
- nfs41_sequence_done(clp, task->tk_msg.rpc_resp, task->tk_status);
+ if (!nfs41_sequence_done(task, task->tk_msg.rpc_resp))
+ return;
if (task->tk_status < 0) {
dprintk("%s ERROR %d\n", __func__, task->tk_status);
if (atomic_read(&clp->cl_count) == 1)
goto out;
- if (_nfs4_async_handle_error(task, NULL, clp, NULL)
- == -EAGAIN) {
- nfs_restart_rpc(task, clp);
+ if (nfs41_sequence_handle_errors(task, clp) == -EAGAIN) {
+ rpc_restart_call_prepare(task);
return;
}
}
dprintk("%s rpc_cred %p\n", __func__, task->tk_msg.rpc_cred);
out:
- kfree(task->tk_msg.rpc_argp);
- kfree(task->tk_msg.rpc_resp);
-
dprintk("<-- %s\n", __func__);
}
static void nfs41_sequence_prepare(struct rpc_task *task, void *data)
{
- struct nfs_client *clp;
+ struct nfs4_sequence_data *calldata = data;
+ struct nfs_client *clp = calldata->clp;
struct nfs4_sequence_args *args;
struct nfs4_sequence_res *res;
- clp = (struct nfs_client *)data;
args = task->tk_msg.rpc_argp;
res = task->tk_msg.rpc_resp;
- if (nfs4_setup_sequence(clp, args, res, 0, task))
+ if (nfs41_setup_sequence(clp->cl_session, args, res, 0, task))
return;
rpc_call_start(task);
}
@@ -5133,32 +5163,67 @@ static const struct rpc_call_ops nfs41_sequence_ops = {
.rpc_release = nfs41_sequence_release,
};
-static int nfs41_proc_async_sequence(struct nfs_client *clp,
- struct rpc_cred *cred)
+static struct rpc_task *_nfs41_proc_sequence(struct nfs_client *clp, struct rpc_cred *cred)
{
- struct nfs4_sequence_args *args;
- struct nfs4_sequence_res *res;
+ struct nfs4_sequence_data *calldata;
struct rpc_message msg = {
.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SEQUENCE],
.rpc_cred = cred,
};
+ struct rpc_task_setup task_setup_data = {
+ .rpc_client = clp->cl_rpcclient,
+ .rpc_message = &msg,
+ .callback_ops = &nfs41_sequence_ops,
+ .flags = RPC_TASK_ASYNC | RPC_TASK_SOFT,
+ };
if (!atomic_inc_not_zero(&clp->cl_count))
- return -EIO;
- args = kzalloc(sizeof(*args), GFP_NOFS);
- res = kzalloc(sizeof(*res), GFP_NOFS);
- if (!args || !res) {
- kfree(args);
- kfree(res);
+ return ERR_PTR(-EIO);
+ calldata = kmalloc(sizeof(*calldata), GFP_NOFS);
+ if (calldata == NULL) {
nfs_put_client(clp);
- return -ENOMEM;
+ return ERR_PTR(-ENOMEM);
}
- res->sr_slotid = NFS4_MAX_SLOT_TABLE;
- msg.rpc_argp = args;
- msg.rpc_resp = res;
+ calldata->res.sr_slotid = NFS4_MAX_SLOT_TABLE;
+ msg.rpc_argp = &calldata->args;
+ msg.rpc_resp = &calldata->res;
+ calldata->clp = clp;
+ task_setup_data.callback_data = calldata;
- return rpc_call_async(clp->cl_rpcclient, &msg, RPC_TASK_SOFT,
- &nfs41_sequence_ops, (void *)clp);
+ return rpc_run_task(&task_setup_data);
+}
+
+static int nfs41_proc_async_sequence(struct nfs_client *clp, struct rpc_cred *cred)
+{
+ struct rpc_task *task;
+ int ret = 0;
+
+ task = _nfs41_proc_sequence(clp, cred);
+ if (IS_ERR(task))
+ ret = PTR_ERR(task);
+ else
+ rpc_put_task(task);
+ dprintk("<-- %s status=%d\n", __func__, ret);
+ return ret;
+}
+
+static int nfs4_proc_sequence(struct nfs_client *clp, struct rpc_cred *cred)
+{
+ struct rpc_task *task;
+ int ret;
+
+ task = _nfs41_proc_sequence(clp, cred);
+ if (IS_ERR(task)) {
+ ret = PTR_ERR(task);
+ goto out;
+ }
+ ret = rpc_wait_for_completion_task(task);
+ if (!ret)
+ ret = task->tk_status;
+ rpc_put_task(task);
+out:
+ dprintk("<-- %s status=%d\n", __func__, ret);
+ return ret;
}
struct nfs4_reclaim_complete_data {
@@ -5172,13 +5237,31 @@ static void nfs4_reclaim_complete_prepare(struct rpc_task *task, void *data)
struct nfs4_reclaim_complete_data *calldata = data;
rpc_task_set_priority(task, RPC_PRIORITY_PRIVILEGED);
- if (nfs4_setup_sequence(calldata->clp, &calldata->arg.seq_args,
+ if (nfs41_setup_sequence(calldata->clp->cl_session,
+ &calldata->arg.seq_args,
&calldata->res.seq_res, 0, task))
return;
rpc_call_start(task);
}
+static int nfs41_reclaim_complete_handle_errors(struct rpc_task *task, struct nfs_client *clp)
+{
+ switch(task->tk_status) {
+ case 0:
+ case -NFS4ERR_COMPLETE_ALREADY:
+ case -NFS4ERR_WRONG_CRED: /* What to do here? */
+ break;
+ case -NFS4ERR_DELAY:
+ case -EKEYEXPIRED:
+ rpc_delay(task, NFS4_POLL_RETRY_MAX);
+ return -EAGAIN;
+ default:
+ nfs4_schedule_state_recovery(clp);
+ }
+ return 0;
+}
+
static void nfs4_reclaim_complete_done(struct rpc_task *task, void *data)
{
struct nfs4_reclaim_complete_data *calldata = data;
@@ -5186,32 +5269,13 @@ static void nfs4_reclaim_complete_done(struct rpc_task *task, void *data)
struct nfs4_sequence_res *res = &calldata->res.seq_res;
dprintk("--> %s\n", __func__);
- nfs41_sequence_done(clp, res, task->tk_status);
- switch (task->tk_status) {
- case 0:
- case -NFS4ERR_COMPLETE_ALREADY:
- break;
- case -NFS4ERR_BADSESSION:
- case -NFS4ERR_DEADSESSION:
- /*
- * Handle the session error, but do not retry the operation, as
- * we have no way of telling whether the clientid had to be
- * reset before we got our reply. If reset, a new wave of
- * reclaim operations will follow, containing their own reclaim
- * complete. We don't want our retry to get on the way of
- * recovery by incorrectly indicating to the server that we're
- * done reclaiming state since the process had to be restarted.
- */
- _nfs4_async_handle_error(task, NULL, clp, NULL);
- break;
- default:
- if (_nfs4_async_handle_error(
- task, NULL, clp, NULL) == -EAGAIN) {
- rpc_restart_call_prepare(task);
- return;
- }
- }
+ if (!nfs41_sequence_done(task, res))
+ return;
+ if (nfs41_reclaim_complete_handle_errors(task, clp) == -EAGAIN) {
+ rpc_restart_call_prepare(task);
+ return;
+ }
dprintk("<-- %s\n", __func__);
}
@@ -5325,28 +5389,30 @@ struct nfs4_state_maintenance_ops nfs41_state_renewal_ops = {
};
#endif
-/*
- * Per minor version reboot and network partition recovery ops
- */
-
-struct nfs4_state_recovery_ops *nfs4_reboot_recovery_ops[] = {
- &nfs40_reboot_recovery_ops,
-#if defined(CONFIG_NFS_V4_1)
- &nfs41_reboot_recovery_ops,
-#endif
+static const struct nfs4_minor_version_ops nfs_v4_0_minor_ops = {
+ .minor_version = 0,
+ .call_sync = _nfs4_call_sync,
+ .validate_stateid = nfs4_validate_delegation_stateid,
+ .reboot_recovery_ops = &nfs40_reboot_recovery_ops,
+ .nograce_recovery_ops = &nfs40_nograce_recovery_ops,
+ .state_renewal_ops = &nfs40_state_renewal_ops,
};
-struct nfs4_state_recovery_ops *nfs4_nograce_recovery_ops[] = {
- &nfs40_nograce_recovery_ops,
#if defined(CONFIG_NFS_V4_1)
- &nfs41_nograce_recovery_ops,
-#endif
+static const struct nfs4_minor_version_ops nfs_v4_1_minor_ops = {
+ .minor_version = 1,
+ .call_sync = _nfs4_call_sync_session,
+ .validate_stateid = nfs41_validate_delegation_stateid,
+ .reboot_recovery_ops = &nfs41_reboot_recovery_ops,
+ .nograce_recovery_ops = &nfs41_nograce_recovery_ops,
+ .state_renewal_ops = &nfs41_state_renewal_ops,
};
+#endif
-struct nfs4_state_maintenance_ops *nfs4_state_renewal_ops[] = {
- &nfs40_state_renewal_ops,
+const struct nfs4_minor_version_ops *nfs_v4_minor_ops[] = {
+ [0] = &nfs_v4_0_minor_ops,
#if defined(CONFIG_NFS_V4_1)
- &nfs41_state_renewal_ops,
+ [1] = &nfs_v4_1_minor_ops,
#endif
};
diff --git a/fs/nfs/nfs4renewd.c b/fs/nfs/nfs4renewd.c
index d87f10327b7..72b6c580af1 100644
--- a/fs/nfs/nfs4renewd.c
+++ b/fs/nfs/nfs4renewd.c
@@ -54,14 +54,14 @@
void
nfs4_renew_state(struct work_struct *work)
{
- struct nfs4_state_maintenance_ops *ops;
+ const struct nfs4_state_maintenance_ops *ops;
struct nfs_client *clp =
container_of(work, struct nfs_client, cl_renewd.work);
struct rpc_cred *cred;
long lease;
unsigned long last, now;
- ops = nfs4_state_renewal_ops[clp->cl_minorversion];
+ ops = clp->cl_mvops->state_renewal_ops;
dprintk("%s: start\n", __func__);
/* Are there any active superblocks? */
if (list_empty(&clp->cl_superblocks))
diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c
index 34acf5926fd..3e2f19b04c0 100644
--- a/fs/nfs/nfs4state.c
+++ b/fs/nfs/nfs4state.c
@@ -145,7 +145,9 @@ static void nfs4_end_drain_session(struct nfs_client *clp)
struct nfs4_session *ses = clp->cl_session;
int max_slots;
- if (test_and_clear_bit(NFS4CLNT_SESSION_DRAINING, &clp->cl_state)) {
+ if (ses == NULL)
+ return;
+ if (test_and_clear_bit(NFS4_SESSION_DRAINING, &ses->session_state)) {
spin_lock(&ses->fc_slot_table.slot_tbl_lock);
max_slots = ses->fc_slot_table.max_slots;
while (max_slots--) {
@@ -167,7 +169,7 @@ static int nfs4_begin_drain_session(struct nfs_client *clp)
struct nfs4_slot_table *tbl = &ses->fc_slot_table;
spin_lock(&tbl->slot_tbl_lock);
- set_bit(NFS4CLNT_SESSION_DRAINING, &clp->cl_state);
+ set_bit(NFS4_SESSION_DRAINING, &ses->session_state);
if (tbl->highest_used_slotid != -1) {
INIT_COMPLETION(ses->complete);
spin_unlock(&tbl->slot_tbl_lock);
@@ -371,7 +373,6 @@ nfs4_alloc_state_owner(void)
return NULL;
spin_lock_init(&sp->so_lock);
INIT_LIST_HEAD(&sp->so_states);
- INIT_LIST_HEAD(&sp->so_delegations);
rpc_init_wait_queue(&sp->so_sequence.wait, "Seqid_waitqueue");
sp->so_seqid.sequence = &sp->so_sequence;
spin_lock_init(&sp->so_sequence.lock);
@@ -384,7 +385,7 @@ static void
nfs4_drop_state_owner(struct nfs4_state_owner *sp)
{
if (!RB_EMPTY_NODE(&sp->so_client_node)) {
- struct nfs_client *clp = sp->so_client;
+ struct nfs_client *clp = sp->so_server->nfs_client;
spin_lock(&clp->cl_lock);
rb_erase(&sp->so_client_node, &clp->cl_state_owners);
@@ -406,7 +407,6 @@ struct nfs4_state_owner *nfs4_get_state_owner(struct nfs_server *server, struct
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);
@@ -423,7 +423,7 @@ struct nfs4_state_owner *nfs4_get_state_owner(struct nfs_server *server, struct
void nfs4_put_state_owner(struct nfs4_state_owner *sp)
{
- struct nfs_client *clp = sp->so_client;
+ struct nfs_client *clp = sp->so_server->nfs_client;
struct rpc_cred *cred = sp->so_cred;
if (!atomic_dec_and_lock(&sp->so_count, &clp->cl_lock))
@@ -602,12 +602,21 @@ void nfs4_close_sync(struct path *path, struct nfs4_state *state, fmode_t fmode)
* that is compatible with current->files
*/
static struct nfs4_lock_state *
-__nfs4_find_lock_state(struct nfs4_state *state, fl_owner_t fl_owner)
+__nfs4_find_lock_state(struct nfs4_state *state, fl_owner_t fl_owner, pid_t fl_pid, unsigned int type)
{
struct nfs4_lock_state *pos;
list_for_each_entry(pos, &state->lock_states, ls_locks) {
- if (pos->ls_owner != fl_owner)
+ if (type != NFS4_ANY_LOCK_TYPE && pos->ls_owner.lo_type != type)
continue;
+ switch (pos->ls_owner.lo_type) {
+ case NFS4_POSIX_LOCK_TYPE:
+ if (pos->ls_owner.lo_u.posix_owner != fl_owner)
+ continue;
+ break;
+ case NFS4_FLOCK_LOCK_TYPE:
+ if (pos->ls_owner.lo_u.flock_owner != fl_pid)
+ continue;
+ }
atomic_inc(&pos->ls_count);
return pos;
}
@@ -619,10 +628,10 @@ __nfs4_find_lock_state(struct nfs4_state *state, fl_owner_t fl_owner)
* exists, return an uninitialized one.
*
*/
-static struct nfs4_lock_state *nfs4_alloc_lock_state(struct nfs4_state *state, fl_owner_t fl_owner)
+static struct nfs4_lock_state *nfs4_alloc_lock_state(struct nfs4_state *state, fl_owner_t fl_owner, pid_t fl_pid, unsigned int type)
{
struct nfs4_lock_state *lsp;
- struct nfs_client *clp = state->owner->so_client;
+ struct nfs_client *clp = state->owner->so_server->nfs_client;
lsp = kzalloc(sizeof(*lsp), GFP_NOFS);
if (lsp == NULL)
@@ -633,7 +642,18 @@ static struct nfs4_lock_state *nfs4_alloc_lock_state(struct nfs4_state *state, f
lsp->ls_seqid.sequence = &lsp->ls_sequence;
atomic_set(&lsp->ls_count, 1);
lsp->ls_state = state;
- lsp->ls_owner = fl_owner;
+ lsp->ls_owner.lo_type = type;
+ switch (lsp->ls_owner.lo_type) {
+ case NFS4_FLOCK_LOCK_TYPE:
+ lsp->ls_owner.lo_u.flock_owner = fl_pid;
+ break;
+ case NFS4_POSIX_LOCK_TYPE:
+ lsp->ls_owner.lo_u.posix_owner = fl_owner;
+ break;
+ default:
+ kfree(lsp);
+ return NULL;
+ }
spin_lock(&clp->cl_lock);
nfs_alloc_unique_id(&clp->cl_lockowner_id, &lsp->ls_id, 1, 64);
spin_unlock(&clp->cl_lock);
@@ -643,7 +663,7 @@ static struct nfs4_lock_state *nfs4_alloc_lock_state(struct nfs4_state *state, f
static void nfs4_free_lock_state(struct nfs4_lock_state *lsp)
{
- struct nfs_client *clp = lsp->ls_state->owner->so_client;
+ struct nfs_client *clp = lsp->ls_state->owner->so_server->nfs_client;
spin_lock(&clp->cl_lock);
nfs_free_unique_id(&clp->cl_lockowner_id, &lsp->ls_id);
@@ -657,13 +677,13 @@ static void nfs4_free_lock_state(struct nfs4_lock_state *lsp)
* exists, return an uninitialized one.
*
*/
-static struct nfs4_lock_state *nfs4_get_lock_state(struct nfs4_state *state, fl_owner_t owner)
+static struct nfs4_lock_state *nfs4_get_lock_state(struct nfs4_state *state, fl_owner_t owner, pid_t pid, unsigned int type)
{
struct nfs4_lock_state *lsp, *new = NULL;
for(;;) {
spin_lock(&state->state_lock);
- lsp = __nfs4_find_lock_state(state, owner);
+ lsp = __nfs4_find_lock_state(state, owner, pid, type);
if (lsp != NULL)
break;
if (new != NULL) {
@@ -674,7 +694,7 @@ static struct nfs4_lock_state *nfs4_get_lock_state(struct nfs4_state *state, fl_
break;
}
spin_unlock(&state->state_lock);
- new = nfs4_alloc_lock_state(state, owner);
+ new = nfs4_alloc_lock_state(state, owner, pid, type);
if (new == NULL)
return NULL;
}
@@ -701,6 +721,8 @@ 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);
+ if (lsp->ls_flags & NFS_LOCK_INITIALIZED)
+ nfs4_release_lockowner(lsp);
nfs4_free_lock_state(lsp);
}
@@ -728,7 +750,12 @@ int nfs4_set_lock_state(struct nfs4_state *state, struct file_lock *fl)
if (fl->fl_ops != NULL)
return 0;
- lsp = nfs4_get_lock_state(state, fl->fl_owner);
+ if (fl->fl_flags & FL_POSIX)
+ lsp = nfs4_get_lock_state(state, fl->fl_owner, 0, NFS4_POSIX_LOCK_TYPE);
+ else if (fl->fl_flags & FL_FLOCK)
+ lsp = nfs4_get_lock_state(state, 0, fl->fl_pid, NFS4_FLOCK_LOCK_TYPE);
+ else
+ return -EINVAL;
if (lsp == NULL)
return -ENOMEM;
fl->fl_u.nfs4_fl.owner = lsp;
@@ -740,7 +767,7 @@ int nfs4_set_lock_state(struct nfs4_state *state, struct file_lock *fl)
* Byte-range lock aware utility to initialize the stateid of read/write
* requests.
*/
-void nfs4_copy_stateid(nfs4_stateid *dst, struct nfs4_state *state, fl_owner_t fl_owner)
+void nfs4_copy_stateid(nfs4_stateid *dst, struct nfs4_state *state, fl_owner_t fl_owner, pid_t fl_pid)
{
struct nfs4_lock_state *lsp;
int seq;
@@ -753,7 +780,7 @@ void nfs4_copy_stateid(nfs4_stateid *dst, struct nfs4_state *state, fl_owner_t f
return;
spin_lock(&state->state_lock);
- lsp = __nfs4_find_lock_state(state, fl_owner);
+ lsp = __nfs4_find_lock_state(state, fl_owner, fl_pid, NFS4_ANY_LOCK_TYPE);
if (lsp != NULL && (lsp->ls_flags & NFS_LOCK_INITIALIZED) != 0)
memcpy(dst, &lsp->ls_stateid, sizeof(*dst));
spin_unlock(&state->state_lock);
@@ -1041,11 +1068,11 @@ restart:
case -NFS4ERR_BAD_STATEID:
case -NFS4ERR_RECLAIM_BAD:
case -NFS4ERR_RECLAIM_CONFLICT:
- nfs4_state_mark_reclaim_nograce(sp->so_client, state);
+ nfs4_state_mark_reclaim_nograce(sp->so_server->nfs_client, state);
break;
case -NFS4ERR_EXPIRED:
case -NFS4ERR_NO_GRACE:
- nfs4_state_mark_reclaim_nograce(sp->so_client, state);
+ nfs4_state_mark_reclaim_nograce(sp->so_server->nfs_client, state);
case -NFS4ERR_STALE_CLIENTID:
case -NFS4ERR_BADSESSION:
case -NFS4ERR_BADSLOT:
@@ -1120,8 +1147,7 @@ static void nfs4_state_end_reclaim_reboot(struct nfs_client *clp)
if (!test_and_clear_bit(NFS4CLNT_RECLAIM_REBOOT, &clp->cl_state))
return;
- nfs4_reclaim_complete(clp,
- nfs4_reboot_recovery_ops[clp->cl_minorversion]);
+ nfs4_reclaim_complete(clp, clp->cl_mvops->reboot_recovery_ops);
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);
@@ -1211,8 +1237,8 @@ restart:
static int nfs4_check_lease(struct nfs_client *clp)
{
struct rpc_cred *cred;
- struct nfs4_state_maintenance_ops *ops =
- nfs4_state_renewal_ops[clp->cl_minorversion];
+ const struct nfs4_state_maintenance_ops *ops =
+ clp->cl_mvops->state_renewal_ops;
int status = -NFS4ERR_EXPIRED;
/* Is the client already known to have an expired lease? */
@@ -1235,8 +1261,8 @@ out:
static int nfs4_reclaim_lease(struct nfs_client *clp)
{
struct rpc_cred *cred;
- struct nfs4_state_recovery_ops *ops =
- nfs4_reboot_recovery_ops[clp->cl_minorversion];
+ const struct nfs4_state_recovery_ops *ops =
+ clp->cl_mvops->reboot_recovery_ops;
int status = -ENOENT;
cred = ops->get_clid_cred(clp);
@@ -1444,7 +1470,7 @@ static void nfs4_state_manager(struct nfs_client *clp)
/* First recover reboot state... */
if (test_bit(NFS4CLNT_RECLAIM_REBOOT, &clp->cl_state)) {
status = nfs4_do_reclaim(clp,
- nfs4_reboot_recovery_ops[clp->cl_minorversion]);
+ clp->cl_mvops->reboot_recovery_ops);
if (test_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state) ||
test_bit(NFS4CLNT_SESSION_RESET, &clp->cl_state))
continue;
@@ -1458,7 +1484,7 @@ static void nfs4_state_manager(struct nfs_client *clp)
/* Now recover expired state... */
if (test_and_clear_bit(NFS4CLNT_RECLAIM_NOGRACE, &clp->cl_state)) {
status = nfs4_do_reclaim(clp,
- nfs4_nograce_recovery_ops[clp->cl_minorversion]);
+ clp->cl_mvops->nograce_recovery_ops);
if (test_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state) ||
test_bit(NFS4CLNT_SESSION_RESET, &clp->cl_state) ||
test_bit(NFS4CLNT_RECLAIM_REBOOT, &clp->cl_state))
diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c
index 65c8dae4b26..08ef9129113 100644
--- a/fs/nfs/nfs4xdr.c
+++ b/fs/nfs/nfs4xdr.c
@@ -202,14 +202,17 @@ 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 + decode_change_info_maxsz)
+#define encode_lockowner_maxsz (7)
#define encode_lock_maxsz (op_encode_hdr_maxsz + \
7 + \
- 1 + encode_stateid_maxsz + 8)
+ 1 + encode_stateid_maxsz + 1 + \
+ encode_lockowner_maxsz)
#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 encode_lockt_maxsz (op_encode_hdr_maxsz + 5 + \
+ encode_lockowner_maxsz)
#define decode_lockt_maxsz (op_decode_hdr_maxsz + \
decode_lock_denied_maxsz)
#define encode_locku_maxsz (op_encode_hdr_maxsz + 3 + \
@@ -217,6 +220,11 @@ static int nfs4_stat_to_errno(int);
4)
#define decode_locku_maxsz (op_decode_hdr_maxsz + \
decode_stateid_maxsz)
+#define encode_release_lockowner_maxsz \
+ (op_encode_hdr_maxsz + \
+ encode_lockowner_maxsz)
+#define decode_release_lockowner_maxsz \
+ (op_decode_hdr_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 + \
@@ -471,6 +479,12 @@ static int nfs4_stat_to_errno(int);
decode_sequence_maxsz + \
decode_putfh_maxsz + \
decode_locku_maxsz)
+#define NFS4_enc_release_lockowner_sz \
+ (compound_encode_hdr_maxsz + \
+ encode_lockowner_maxsz)
+#define NFS4_dec_release_lockowner_sz \
+ (compound_decode_hdr_maxsz + \
+ decode_lockowner_maxsz)
#define NFS4_enc_access_sz (compound_encode_hdr_maxsz + \
encode_sequence_maxsz + \
encode_putfh_maxsz + \
@@ -744,7 +758,7 @@ static void encode_compound_hdr(struct xdr_stream *xdr,
struct compound_hdr *hdr)
{
__be32 *p;
- struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth;
+ struct rpc_auth *auth = req->rq_cred->cr_auth;
/* initialize running count of expected bytes in reply.
* NOTE: the replied tag SHOULD be the same is the one sent,
@@ -1042,6 +1056,17 @@ static inline uint64_t nfs4_lock_length(struct file_lock *fl)
return fl->fl_end - fl->fl_start + 1;
}
+static void encode_lockowner(struct xdr_stream *xdr, const struct nfs_lowner *lowner)
+{
+ __be32 *p;
+
+ p = reserve_space(xdr, 28);
+ p = xdr_encode_hyper(p, lowner->clientid);
+ *p++ = cpu_to_be32(16);
+ p = xdr_encode_opaque_fixed(p, "lock id:", 8);
+ xdr_encode_hyper(p, lowner->id);
+}
+
/*
* opcode,type,reclaim,offset,length,new_lock_owner = 32
* open_seqid,open_stateid,lock_seqid,lock_owner.clientid, lock_owner.id = 40
@@ -1058,14 +1083,11 @@ static void encode_lock(struct xdr_stream *xdr, const struct nfs_lock_args *args
p = xdr_encode_hyper(p, nfs4_lock_length(args->fl));
*p = cpu_to_be32(args->new_lock_owner);
if (args->new_lock_owner){
- p = reserve_space(xdr, 4+NFS4_STATEID_SIZE+32);
+ p = reserve_space(xdr, 4+NFS4_STATEID_SIZE+4);
*p++ = cpu_to_be32(args->open_seqid->sequence->counter);
p = xdr_encode_opaque_fixed(p, args->open_stateid->data, NFS4_STATEID_SIZE);
*p++ = cpu_to_be32(args->lock_seqid->sequence->counter);
- p = xdr_encode_hyper(p, args->lock_owner.clientid);
- *p++ = cpu_to_be32(16);
- p = xdr_encode_opaque_fixed(p, "lock id:", 8);
- xdr_encode_hyper(p, args->lock_owner.id);
+ encode_lockowner(xdr, &args->lock_owner);
}
else {
p = reserve_space(xdr, NFS4_STATEID_SIZE+4);
@@ -1080,15 +1102,12 @@ static void encode_lockt(struct xdr_stream *xdr, const struct nfs_lockt_args *ar
{
__be32 *p;
- p = reserve_space(xdr, 52);
+ p = reserve_space(xdr, 24);
*p++ = cpu_to_be32(OP_LOCKT);
*p++ = cpu_to_be32(nfs4_lock_type(args->fl, 0));
p = xdr_encode_hyper(p, args->fl->fl_start);
p = xdr_encode_hyper(p, nfs4_lock_length(args->fl));
- p = xdr_encode_hyper(p, args->lock_owner.clientid);
- *p++ = cpu_to_be32(16);
- p = xdr_encode_opaque_fixed(p, "lock id:", 8);
- xdr_encode_hyper(p, args->lock_owner.id);
+ encode_lockowner(xdr, &args->lock_owner);
hdr->nops++;
hdr->replen += decode_lockt_maxsz;
}
@@ -1108,6 +1127,17 @@ static void encode_locku(struct xdr_stream *xdr, const struct nfs_locku_args *ar
hdr->replen += decode_locku_maxsz;
}
+static void encode_release_lockowner(struct xdr_stream *xdr, const struct nfs_lowner *lowner, struct compound_hdr *hdr)
+{
+ __be32 *p;
+
+ p = reserve_space(xdr, 4);
+ *p = cpu_to_be32(OP_RELEASE_LOCKOWNER);
+ encode_lockowner(xdr, lowner);
+ hdr->nops++;
+ hdr->replen += decode_release_lockowner_maxsz;
+}
+
static void encode_lookup(struct xdr_stream *xdr, const struct qstr *name, struct compound_hdr *hdr)
{
int len = name->len;
@@ -1172,7 +1202,7 @@ static inline void encode_createmode(struct xdr_stream *xdr, const struct nfs_op
break;
default:
clp = arg->server->nfs_client;
- if (clp->cl_minorversion > 0) {
+ if (clp->cl_mvops->minor_version > 0) {
if (nfs4_has_persistent_session(clp)) {
*p = cpu_to_be32(NFS4_CREATE_GUARDED);
encode_attrs(xdr, arg->u.attrs, arg->server);
@@ -1324,14 +1354,14 @@ static void encode_putrootfh(struct xdr_stream *xdr, struct compound_hdr *hdr)
hdr->replen += decode_putrootfh_maxsz;
}
-static void encode_stateid(struct xdr_stream *xdr, const struct nfs_open_context *ctx)
+static void encode_stateid(struct xdr_stream *xdr, const struct nfs_open_context *ctx, const struct nfs_lock_context *l_ctx)
{
nfs4_stateid stateid;
__be32 *p;
p = reserve_space(xdr, NFS4_STATEID_SIZE);
if (ctx->state != NULL) {
- nfs4_copy_stateid(&stateid, ctx->state, ctx->lockowner);
+ nfs4_copy_stateid(&stateid, ctx->state, l_ctx->lockowner, l_ctx->pid);
xdr_encode_opaque_fixed(p, stateid.data, NFS4_STATEID_SIZE);
} else
xdr_encode_opaque_fixed(p, zero_stateid.data, NFS4_STATEID_SIZE);
@@ -1344,7 +1374,7 @@ static void encode_read(struct xdr_stream *xdr, const struct nfs_readargs *args,
p = reserve_space(xdr, 4);
*p = cpu_to_be32(OP_READ);
- encode_stateid(xdr, args->context);
+ encode_stateid(xdr, args->context, args->lock_context);
p = reserve_space(xdr, 12);
p = xdr_encode_hyper(p, args->offset);
@@ -1523,7 +1553,7 @@ static void encode_write(struct xdr_stream *xdr, const struct nfs_writeargs *arg
p = reserve_space(xdr, 4);
*p = cpu_to_be32(OP_WRITE);
- encode_stateid(xdr, args->context);
+ encode_stateid(xdr, args->context, args->lock_context);
p = reserve_space(xdr, 16);
p = xdr_encode_hyper(p, args->offset);
@@ -1704,7 +1734,7 @@ static u32 nfs4_xdr_minorversion(const struct nfs4_sequence_args *args)
{
#if defined(CONFIG_NFS_V4_1)
if (args->sa_session)
- return args->sa_session->clp->cl_minorversion;
+ return args->sa_session->clp->cl_mvops->minor_version;
#endif /* CONFIG_NFS_V4_1 */
return 0;
}
@@ -2048,6 +2078,20 @@ static int nfs4_xdr_enc_locku(struct rpc_rqst *req, __be32 *p, struct nfs_locku_
return 0;
}
+static int nfs4_xdr_enc_release_lockowner(struct rpc_rqst *req, __be32 *p, struct nfs_release_lockowner_args *args)
+{
+ struct xdr_stream xdr;
+ struct compound_hdr hdr = {
+ .minorversion = 0,
+ };
+
+ xdr_init_encode(&xdr, &req->rq_snd_buf, p);
+ encode_compound_hdr(&xdr, req, &hdr);
+ encode_release_lockowner(&xdr, &args->lock_owner, &hdr);
+ encode_nops(&hdr);
+ return 0;
+}
+
/*
* Encode a READLINK request
*/
@@ -2395,7 +2439,7 @@ static int nfs4_xdr_enc_exchange_id(struct rpc_rqst *req, uint32_t *p,
{
struct xdr_stream xdr;
struct compound_hdr hdr = {
- .minorversion = args->client->cl_minorversion,
+ .minorversion = args->client->cl_mvops->minor_version,
};
xdr_init_encode(&xdr, &req->rq_snd_buf, p);
@@ -2413,7 +2457,7 @@ static int nfs4_xdr_enc_create_session(struct rpc_rqst *req, uint32_t *p,
{
struct xdr_stream xdr;
struct compound_hdr hdr = {
- .minorversion = args->client->cl_minorversion,
+ .minorversion = args->client->cl_mvops->minor_version,
};
xdr_init_encode(&xdr, &req->rq_snd_buf, p);
@@ -2431,7 +2475,7 @@ static int nfs4_xdr_enc_destroy_session(struct rpc_rqst *req, uint32_t *p,
{
struct xdr_stream xdr;
struct compound_hdr hdr = {
- .minorversion = session->clp->cl_minorversion,
+ .minorversion = session->clp->cl_mvops->minor_version,
};
xdr_init_encode(&xdr, &req->rq_snd_buf, p);
@@ -3973,6 +4017,11 @@ static int decode_locku(struct xdr_stream *xdr, struct nfs_locku_res *res)
return status;
}
+static int decode_release_lockowner(struct xdr_stream *xdr)
+{
+ return decode_op_hdr(xdr, OP_RELEASE_LOCKOWNER);
+}
+
static int decode_lookup(struct xdr_stream *xdr)
{
return decode_op_hdr(xdr, OP_LOOKUP);
@@ -5259,6 +5308,19 @@ out:
return status;
}
+static int nfs4_xdr_dec_release_lockowner(struct rpc_rqst *rqstp, __be32 *p, void *dummy)
+{
+ struct xdr_stream xdr;
+ struct compound_hdr hdr;
+ int status;
+
+ xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
+ status = decode_compound_hdr(&xdr, &hdr);
+ if (!status)
+ status = decode_release_lockowner(&xdr);
+ return status;
+}
+
/*
* Decode READLINK response
*/
@@ -5866,6 +5928,7 @@ struct rpc_procinfo nfs4_procedures[] = {
PROC(GETACL, enc_getacl, dec_getacl),
PROC(SETACL, enc_setacl, dec_setacl),
PROC(FS_LOCATIONS, enc_fs_locations, dec_fs_locations),
+ PROC(RELEASE_LOCKOWNER, enc_release_lockowner, dec_release_lockowner),
#if defined(CONFIG_NFS_V4_1)
PROC(EXCHANGE_ID, enc_exchange_id, dec_exchange_id),
PROC(CREATE_SESSION, enc_create_session, dec_create_session),
diff --git a/fs/nfs/pagelist.c b/fs/nfs/pagelist.c
index a3654e57b58..919490232e1 100644
--- a/fs/nfs/pagelist.c
+++ b/fs/nfs/pagelist.c
@@ -79,6 +79,7 @@ nfs_create_request(struct nfs_open_context *ctx, struct inode *inode,
req->wb_pgbase = offset;
req->wb_bytes = count;
req->wb_context = get_nfs_open_context(ctx);
+ req->wb_lock_context = nfs_get_lock_context(ctx);
kref_init(&req->wb_kref);
return req;
}
@@ -141,11 +142,16 @@ void nfs_clear_request(struct nfs_page *req)
{
struct page *page = req->wb_page;
struct nfs_open_context *ctx = req->wb_context;
+ struct nfs_lock_context *l_ctx = req->wb_lock_context;
if (page != NULL) {
page_cache_release(page);
req->wb_page = NULL;
}
+ if (l_ctx != NULL) {
+ nfs_put_lock_context(l_ctx);
+ req->wb_lock_context = NULL;
+ }
if (ctx != NULL) {
put_nfs_open_context(ctx);
req->wb_context = NULL;
@@ -235,7 +241,7 @@ static int nfs_can_coalesce_requests(struct nfs_page *prev,
{
if (req->wb_context->cred != prev->wb_context->cred)
return 0;
- if (req->wb_context->lockowner != prev->wb_context->lockowner)
+ if (req->wb_lock_context->lockowner != prev->wb_lock_context->lockowner)
return 0;
if (req->wb_context->state != prev->wb_context->state)
return 0;
diff --git a/fs/nfs/read.c b/fs/nfs/read.c
index 6e2b06e6ca7..87adc274424 100644
--- a/fs/nfs/read.c
+++ b/fs/nfs/read.c
@@ -190,6 +190,7 @@ static int nfs_read_rpcsetup(struct nfs_page *req, struct nfs_read_data *data,
data->args.pages = data->pagevec;
data->args.count = count;
data->args.context = get_nfs_open_context(req->wb_context);
+ data->args.lock_context = req->wb_lock_context;
data->res.fattr = &data->fattr;
data->res.count = count;
@@ -410,7 +411,7 @@ void nfs_read_prepare(struct rpc_task *task, void *calldata)
{
struct nfs_read_data *data = calldata;
- if (nfs4_setup_sequence(NFS_SERVER(data->inode)->nfs_client,
+ if (nfs4_setup_sequence(NFS_SERVER(data->inode),
&data->args.seq_args, &data->res.seq_res,
0, task))
return;
diff --git a/fs/nfs/super.c b/fs/nfs/super.c
index f9df16de4a5..f1ae39f6cb0 100644
--- a/fs/nfs/super.c
+++ b/fs/nfs/super.c
@@ -546,6 +546,9 @@ static void nfs_show_mountd_options(struct seq_file *m, struct nfs_server *nfss,
{
struct sockaddr *sap = (struct sockaddr *)&nfss->mountd_address;
+ if (nfss->flags & NFS_MOUNT_LEGACY_INTERFACE)
+ return;
+
switch (sap->sa_family) {
case AF_INET: {
struct sockaddr_in *sin = (struct sockaddr_in *)sap;
@@ -1780,6 +1783,7 @@ static int nfs_validate_mount_data(void *options,
* can deal with.
*/
args->flags = data->flags & NFS_MOUNT_FLAGMASK;
+ args->flags |= NFS_MOUNT_LEGACY_INTERFACE;
args->rsize = data->rsize;
args->wsize = data->wsize;
args->timeo = data->timeo;
diff --git a/fs/nfs/unlink.c b/fs/nfs/unlink.c
index a2242af6a17..2f84adaad42 100644
--- a/fs/nfs/unlink.c
+++ b/fs/nfs/unlink.c
@@ -110,7 +110,7 @@ void nfs_unlink_prepare(struct rpc_task *task, void *calldata)
struct nfs_unlinkdata *data = calldata;
struct nfs_server *server = NFS_SERVER(data->dir);
- if (nfs4_setup_sequence(server->nfs_client, &data->args.seq_args,
+ if (nfs4_setup_sequence(server, &data->args.seq_args,
&data->res.seq_res, 1, task))
return;
rpc_call_start(task);
diff --git a/fs/nfs/write.c b/fs/nfs/write.c
index 9f81bdd91c5..874972d9427 100644
--- a/fs/nfs/write.c
+++ b/fs/nfs/write.c
@@ -700,7 +700,9 @@ int nfs_flush_incompatible(struct file *file, struct page *page)
req = nfs_page_find_request(page);
if (req == NULL)
return 0;
- do_flush = req->wb_page != page || req->wb_context != ctx;
+ do_flush = req->wb_page != page || req->wb_context != ctx ||
+ req->wb_lock_context->lockowner != current->files ||
+ req->wb_lock_context->pid != current->tgid;
nfs_release_request(req);
if (!do_flush)
return 0;
@@ -824,6 +826,7 @@ static int nfs_write_rpcsetup(struct nfs_page *req,
data->args.pages = data->pagevec;
data->args.count = count;
data->args.context = get_nfs_open_context(req->wb_context);
+ data->args.lock_context = req->wb_lock_context;
data->args.stable = NFS_UNSTABLE;
if (how & FLUSH_STABLE) {
data->args.stable = NFS_DATA_SYNC;
@@ -1047,9 +1050,9 @@ out:
void nfs_write_prepare(struct rpc_task *task, void *calldata)
{
struct nfs_write_data *data = calldata;
- struct nfs_client *clp = (NFS_SERVER(data->inode))->nfs_client;
- if (nfs4_setup_sequence(clp, &data->args.seq_args,
+ if (nfs4_setup_sequence(NFS_SERVER(data->inode),
+ &data->args.seq_args,
&data->res.seq_res, 1, task))
return;
rpc_call_start(task);
diff --git a/fs/nfsd/nfs3proc.c b/fs/nfsd/nfs3proc.c
index 3d68f45a37b..5b7e3021e06 100644
--- a/fs/nfsd/nfs3proc.c
+++ b/fs/nfsd/nfs3proc.c
@@ -168,7 +168,7 @@ nfsd3_proc_read(struct svc_rqst *rqstp, struct nfsd3_readargs *argp,
svc_reserve_auth(rqstp, ((1 + NFS3_POST_OP_ATTR_WORDS + 3)<<2) + resp->count +4);
fh_copy(&resp->fh, &argp->fh);
- nfserr = nfsd_read(rqstp, &resp->fh, NULL,
+ nfserr = nfsd_read(rqstp, &resp->fh,
argp->offset,
rqstp->rq_vec, argp->vlen,
&resp->count);
@@ -271,7 +271,7 @@ nfsd3_proc_mkdir(struct svc_rqst *rqstp, struct nfsd3_createargs *argp,
fh_init(&resp->fh, NFS3_FHSIZE);
nfserr = nfsd_create(rqstp, &resp->dirfh, argp->name, argp->len,
&argp->attrs, S_IFDIR, 0, &resp->fh);
-
+ fh_unlock(&resp->dirfh);
RETURN_STATUS(nfserr);
}
@@ -327,7 +327,7 @@ nfsd3_proc_mknod(struct svc_rqst *rqstp, struct nfsd3_mknodargs *argp,
type = nfs3_ftypes[argp->ftype];
nfserr = nfsd_create(rqstp, &resp->dirfh, argp->name, argp->len,
&argp->attrs, type, rdev, &resp->fh);
-
+ fh_unlock(&resp->dirfh);
RETURN_STATUS(nfserr);
}
@@ -348,6 +348,7 @@ nfsd3_proc_remove(struct svc_rqst *rqstp, struct nfsd3_diropargs *argp,
/* Unlink. -S_IFDIR means file must not be a directory */
fh_copy(&resp->fh, &argp->fh);
nfserr = nfsd_unlink(rqstp, &resp->fh, -S_IFDIR, argp->name, argp->len);
+ fh_unlock(&resp->fh);
RETURN_STATUS(nfserr);
}
@@ -367,6 +368,7 @@ nfsd3_proc_rmdir(struct svc_rqst *rqstp, struct nfsd3_diropargs *argp,
fh_copy(&resp->fh, &argp->fh);
nfserr = nfsd_unlink(rqstp, &resp->fh, S_IFDIR, argp->name, argp->len);
+ fh_unlock(&resp->fh);
RETURN_STATUS(nfserr);
}
diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c
index eb78e7e2207..988cbb3a19b 100644
--- a/fs/nfsd/nfs4callback.c
+++ b/fs/nfsd/nfs4callback.c
@@ -143,8 +143,6 @@ struct nfs4_cb_compound_hdr {
u32 minorversion;
/* res */
int status;
- u32 taglen;
- char *tag;
};
static struct {
@@ -205,6 +203,16 @@ nfs_cb_stat_to_errno(int stat)
*/
static void
+encode_stateid(struct xdr_stream *xdr, stateid_t *sid)
+{
+ __be32 *p;
+
+ RESERVE_SPACE(sizeof(stateid_t));
+ WRITE32(sid->si_generation);
+ WRITEMEM(&sid->si_opaque, sizeof(stateid_opaque_t));
+}
+
+static void
encode_cb_compound_hdr(struct xdr_stream *xdr, struct nfs4_cb_compound_hdr *hdr)
{
__be32 * p;
@@ -229,10 +237,10 @@ encode_cb_recall(struct xdr_stream *xdr, struct nfs4_delegation *dp,
__be32 *p;
int len = dp->dl_fh.fh_size;
- RESERVE_SPACE(12+sizeof(dp->dl_stateid) + len);
+ RESERVE_SPACE(4);
WRITE32(OP_CB_RECALL);
- WRITE32(dp->dl_stateid.si_generation);
- WRITEMEM(&dp->dl_stateid.si_opaque, sizeof(stateid_opaque_t));
+ encode_stateid(xdr, &dp->dl_stateid);
+ RESERVE_SPACE(8 + (XDR_QUADLEN(len) << 2));
WRITE32(0); /* truncate optimization not implemented */
WRITE32(len);
WRITEMEM(&dp->dl_fh.fh_base, len);
@@ -293,13 +301,14 @@ nfs4_xdr_enc_cb_recall(struct rpc_rqst *req, __be32 *p,
static int
decode_cb_compound_hdr(struct xdr_stream *xdr, struct nfs4_cb_compound_hdr *hdr){
__be32 *p;
+ u32 taglen;
READ_BUF(8);
READ32(hdr->status);
- READ32(hdr->taglen);
- READ_BUF(hdr->taglen + 4);
- hdr->tag = (char *)p;
- p += XDR_QUADLEN(hdr->taglen);
+ /* We've got no use for the tag; ignore it: */
+ READ32(taglen);
+ READ_BUF(taglen + 4);
+ p += XDR_QUADLEN(taglen);
READ32(hdr->nops);
return 0;
}
@@ -667,28 +676,28 @@ static void nfsd4_cb_recall_done(struct rpc_task *task, void *calldata)
}
switch (task->tk_status) {
- case -EIO:
+ case 0:
+ return;
+ case -EBADHANDLE:
+ case -NFS4ERR_BAD_STATEID:
+ /* Race: client probably got cb_recall
+ * before open reply granting delegation */
+ break;
+ default:
/* Network partition? */
atomic_set(&clp->cl_cb_set, 0);
warn_no_callback_path(clp, task->tk_status);
if (current_rpc_client != task->tk_client) {
/* queue a callback on the new connection: */
+ atomic_inc(&dp->dl_count);
nfsd4_cb_recall(dp);
return;
}
- case -EBADHANDLE:
- case -NFS4ERR_BAD_STATEID:
- /* Race: client probably got cb_recall
- * before open reply granting delegation */
- break;
- default:
- /* success, or error we can't handle */
- return;
}
if (dp->dl_retries--) {
rpc_delay(task, 2*HZ);
task->tk_status = 0;
- rpc_restart_call(task);
+ rpc_restart_call_prepare(task);
return;
} else {
atomic_set(&clp->cl_cb_set, 0);
@@ -752,18 +761,16 @@ static void _nfsd4_cb_recall(struct nfs4_delegation *dp)
.rpc_proc = &nfs4_cb_procedures[NFSPROC4_CLNT_CB_RECALL],
.rpc_cred = callback_cred
};
- int status;
- if (clnt == NULL)
+ if (clnt == NULL) {
+ nfs4_put_delegation(dp);
return; /* Client is shutting down; give up. */
+ }
args->args_op = dp;
msg.rpc_argp = args;
dp->dl_retries = 1;
- status = rpc_call_async(clnt, &msg, RPC_TASK_SOFT,
- &nfsd4_cb_recall_ops, dp);
- if (status)
- nfs4_put_delegation(dp);
+ rpc_call_async(clnt, &msg, RPC_TASK_SOFT, &nfsd4_cb_recall_ops, dp);
}
void nfsd4_do_callback_rpc(struct work_struct *w)
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 4a273475877..2e7357104cf 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -51,7 +51,6 @@ static time_t boot_time;
static u32 current_ownerid = 1;
static u32 current_fileid = 1;
static u32 current_delegid = 1;
-static u32 nfs4_init;
static stateid_t zerostateid; /* bits all 0 */
static stateid_t onestateid; /* bits all 1 */
static u64 current_sessionid = 1;
@@ -163,6 +162,46 @@ static struct list_head ownerstr_hashtbl[OWNER_HASH_SIZE];
static struct list_head file_hashtbl[FILE_HASH_SIZE];
static struct list_head stateid_hashtbl[STATEID_HASH_SIZE];
+static void __nfs4_file_get_access(struct nfs4_file *fp, int oflag)
+{
+ BUG_ON(!(fp->fi_fds[oflag] || fp->fi_fds[O_RDWR]));
+ atomic_inc(&fp->fi_access[oflag]);
+}
+
+static void nfs4_file_get_access(struct nfs4_file *fp, int oflag)
+{
+ if (oflag == O_RDWR) {
+ __nfs4_file_get_access(fp, O_RDONLY);
+ __nfs4_file_get_access(fp, O_WRONLY);
+ } else
+ __nfs4_file_get_access(fp, oflag);
+}
+
+static void nfs4_file_put_fd(struct nfs4_file *fp, int oflag)
+{
+ if (fp->fi_fds[oflag]) {
+ fput(fp->fi_fds[oflag]);
+ fp->fi_fds[oflag] = NULL;
+ }
+}
+
+static void __nfs4_file_put_access(struct nfs4_file *fp, int oflag)
+{
+ if (atomic_dec_and_test(&fp->fi_access[oflag])) {
+ nfs4_file_put_fd(fp, O_RDWR);
+ nfs4_file_put_fd(fp, oflag);
+ }
+}
+
+static void nfs4_file_put_access(struct nfs4_file *fp, int oflag)
+{
+ if (oflag == O_RDWR) {
+ __nfs4_file_put_access(fp, O_RDONLY);
+ __nfs4_file_put_access(fp, O_WRONLY);
+ } else
+ __nfs4_file_put_access(fp, oflag);
+}
+
static struct nfs4_delegation *
alloc_init_deleg(struct nfs4_client *clp, struct nfs4_stateid *stp, struct svc_fh *current_fh, u32 type)
{
@@ -171,6 +210,13 @@ alloc_init_deleg(struct nfs4_client *clp, struct nfs4_stateid *stp, struct svc_f
struct nfs4_cb_conn *cb = &stp->st_stateowner->so_client->cl_cb_conn;
dprintk("NFSD alloc_init_deleg\n");
+ /*
+ * Major work on the lease subsystem (for example, to support
+ * calbacks on stat) will be required before we can support
+ * write delegations properly.
+ */
+ if (type != NFS4_OPEN_DELEGATE_READ)
+ return NULL;
if (fp->fi_had_conflict)
return NULL;
if (num_delegations > max_delegations)
@@ -185,9 +231,8 @@ alloc_init_deleg(struct nfs4_client *clp, struct nfs4_stateid *stp, struct svc_f
dp->dl_client = clp;
get_nfs4_file(fp);
dp->dl_file = fp;
+ nfs4_file_get_access(fp, O_RDONLY);
dp->dl_flock = NULL;
- get_file(stp->st_vfs_file);
- dp->dl_vfs_file = stp->st_vfs_file;
dp->dl_type = type;
dp->dl_ident = cb->cb_ident;
dp->dl_stateid.si_boot = boot_time;
@@ -222,15 +267,12 @@ nfs4_put_delegation(struct nfs4_delegation *dp)
static void
nfs4_close_delegation(struct nfs4_delegation *dp)
{
- struct file *filp = dp->dl_vfs_file;
+ struct file *filp = find_readable_file(dp->dl_file);
dprintk("NFSD: close_delegation dp %p\n",dp);
- dp->dl_vfs_file = NULL;
- /* The following nfsd_close may not actually close the file,
- * but we want to remove the lease in any case. */
if (dp->dl_flock)
vfs_setlease(filp, F_UNLCK, &dp->dl_flock);
- nfsd_close(filp);
+ nfs4_file_put_access(dp->dl_file, O_RDONLY);
}
/* Called under the state lock. */
@@ -302,8 +344,12 @@ static void free_generic_stateid(struct nfs4_stateid *stp)
static void release_lock_stateid(struct nfs4_stateid *stp)
{
+ struct file *file;
+
unhash_generic_stateid(stp);
- locks_remove_posix(stp->st_vfs_file, (fl_owner_t)stp->st_stateowner);
+ file = find_any_file(stp->st_file);
+ if (file)
+ locks_remove_posix(file, (fl_owner_t)stp->st_stateowner);
free_generic_stateid(stp);
}
@@ -341,11 +387,85 @@ release_stateid_lockowners(struct nfs4_stateid *open_stp)
}
}
+/*
+ * We store the NONE, READ, WRITE, and BOTH bits separately in the
+ * st_{access,deny}_bmap field of the stateid, in order to track not
+ * only what share bits are currently in force, but also what
+ * combinations of share bits previous opens have used. This allows us
+ * to enforce the recommendation of rfc 3530 14.2.19 that the server
+ * return an error if the client attempt to downgrade to a combination
+ * of share bits not explicable by closing some of its previous opens.
+ *
+ * XXX: This enforcement is actually incomplete, since we don't keep
+ * track of access/deny bit combinations; so, e.g., we allow:
+ *
+ * OPEN allow read, deny write
+ * OPEN allow both, deny none
+ * DOWNGRADE allow read, deny none
+ *
+ * which we should reject.
+ */
+static void
+set_access(unsigned int *access, unsigned long bmap) {
+ int i;
+
+ *access = 0;
+ for (i = 1; i < 4; i++) {
+ if (test_bit(i, &bmap))
+ *access |= i;
+ }
+}
+
+static void
+set_deny(unsigned int *deny, unsigned long bmap) {
+ int i;
+
+ *deny = 0;
+ for (i = 0; i < 4; i++) {
+ if (test_bit(i, &bmap))
+ *deny |= i ;
+ }
+}
+
+static int
+test_share(struct nfs4_stateid *stp, struct nfsd4_open *open) {
+ unsigned int access, deny;
+
+ set_access(&access, stp->st_access_bmap);
+ set_deny(&deny, stp->st_deny_bmap);
+ if ((access & open->op_share_deny) || (deny & open->op_share_access))
+ return 0;
+ return 1;
+}
+
+static int nfs4_access_to_omode(u32 access)
+{
+ switch (access) {
+ case NFS4_SHARE_ACCESS_READ:
+ return O_RDONLY;
+ case NFS4_SHARE_ACCESS_WRITE:
+ return O_WRONLY;
+ case NFS4_SHARE_ACCESS_BOTH:
+ return O_RDWR;
+ }
+ BUG();
+}
+
+static int nfs4_access_bmap_to_omode(struct nfs4_stateid *stp)
+{
+ unsigned int access;
+
+ set_access(&access, stp->st_access_bmap);
+ return nfs4_access_to_omode(access);
+}
+
static void release_open_stateid(struct nfs4_stateid *stp)
{
+ int oflag = nfs4_access_bmap_to_omode(stp);
+
unhash_generic_stateid(stp);
release_stateid_lockowners(stp);
- nfsd_close(stp->st_vfs_file);
+ nfs4_file_put_access(stp->st_file, oflag);
free_generic_stateid(stp);
}
@@ -457,7 +577,7 @@ static int set_forechannel_drc_size(struct nfsd4_channel_attrs *fchan)
spin_unlock(&nfsd_drc_lock);
if (fchan->maxreqs == 0)
- return nfserr_serverfault;
+ return nfserr_jukebox;
fchan->maxresp_cached = size + NFSD_MIN_HDR_SEQ_SZ;
return 0;
@@ -542,7 +662,7 @@ alloc_init_session(struct svc_rqst *rqstp, struct nfs4_client *clp,
BUILD_BUG_ON(NFSD_MAX_SLOTS_PER_SESSION * sizeof(struct nfsd4_slot)
+ sizeof(struct nfsd4_session) > PAGE_SIZE);
- status = nfserr_serverfault;
+ status = nfserr_jukebox;
/* allocate struct nfsd4_session and slot table pointers in one piece */
slotsize = tmp.se_fchannel.maxreqs * sizeof(struct nfsd4_slot *);
new = kzalloc(sizeof(*new) + slotsize, GFP_KERNEL);
@@ -591,10 +711,8 @@ find_in_sessionid_hashtbl(struct nfs4_sessionid *sessionid)
dump_sessionid(__func__, sessionid);
idx = hash_sessionid(sessionid);
- dprintk("%s: idx is %d\n", __func__, idx);
/* Search in the appropriate list */
list_for_each_entry(elem, &sessionid_hashtbl[idx], se_hash) {
- dump_sessionid("list traversal", &elem->se_sessionid);
if (!memcmp(elem->se_sessionid.data, sessionid->data,
NFS4_MAX_SESSIONID_LEN)) {
return elem;
@@ -714,7 +832,6 @@ release_session_client(struct nfsd4_session *session)
} else
renew_client_locked(clp);
spin_unlock(&client_lock);
- nfsd4_put_session(session);
}
/* must be called under the client_lock */
@@ -1220,7 +1337,7 @@ out_new:
/* Normal case */
new = create_client(exid->clname, dname, rqstp, &verf);
if (new == NULL) {
- status = nfserr_serverfault;
+ status = nfserr_jukebox;
goto out;
}
@@ -1760,6 +1877,8 @@ alloc_init_file(struct inode *ino)
fp->fi_inode = igrab(ino);
fp->fi_id = current_fileid++;
fp->fi_had_conflict = false;
+ memset(fp->fi_fds, 0, sizeof(fp->fi_fds));
+ memset(fp->fi_access, 0, sizeof(fp->fi_access));
spin_lock(&recall_lock);
list_add(&fp->fi_hash, &file_hashtbl[hashval]);
spin_unlock(&recall_lock);
@@ -1971,57 +2090,6 @@ static inline int deny_valid(u32 x)
}
/*
- * We store the NONE, READ, WRITE, and BOTH bits separately in the
- * st_{access,deny}_bmap field of the stateid, in order to track not
- * only what share bits are currently in force, but also what
- * combinations of share bits previous opens have used. This allows us
- * to enforce the recommendation of rfc 3530 14.2.19 that the server
- * return an error if the client attempt to downgrade to a combination
- * of share bits not explicable by closing some of its previous opens.
- *
- * XXX: This enforcement is actually incomplete, since we don't keep
- * track of access/deny bit combinations; so, e.g., we allow:
- *
- * OPEN allow read, deny write
- * OPEN allow both, deny none
- * DOWNGRADE allow read, deny none
- *
- * which we should reject.
- */
-static void
-set_access(unsigned int *access, unsigned long bmap) {
- int i;
-
- *access = 0;
- for (i = 1; i < 4; i++) {
- if (test_bit(i, &bmap))
- *access |= i;
- }
-}
-
-static void
-set_deny(unsigned int *deny, unsigned long bmap) {
- int i;
-
- *deny = 0;
- for (i = 0; i < 4; i++) {
- if (test_bit(i, &bmap))
- *deny |= i ;
- }
-}
-
-static int
-test_share(struct nfs4_stateid *stp, struct nfsd4_open *open) {
- unsigned int access, deny;
-
- set_access(&access, stp->st_access_bmap);
- set_deny(&deny, stp->st_deny_bmap);
- if ((access & open->op_share_deny) || (deny & open->op_share_access))
- return 0;
- return 1;
-}
-
-/*
* Called to check deny when READ with all zero stateid or
* WRITE with all zero or all one stateid
*/
@@ -2052,14 +2120,12 @@ out:
}
static inline void
-nfs4_file_downgrade(struct file *filp, unsigned int share_access)
+nfs4_file_downgrade(struct nfs4_file *fp, unsigned int share_access)
{
- if (share_access & NFS4_SHARE_ACCESS_WRITE) {
- drop_file_write_access(filp);
- spin_lock(&filp->f_lock);
- filp->f_mode = (filp->f_mode | FMODE_READ) & ~FMODE_WRITE;
- spin_unlock(&filp->f_lock);
- }
+ if (share_access & NFS4_SHARE_ACCESS_WRITE)
+ nfs4_file_put_access(fp, O_WRONLY);
+ if (share_access & NFS4_SHARE_ACCESS_READ)
+ nfs4_file_put_access(fp, O_RDONLY);
}
/*
@@ -2255,6 +2321,13 @@ find_delegation_file(struct nfs4_file *fp, stateid_t *stid)
return NULL;
}
+int share_access_to_flags(u32 share_access)
+{
+ share_access &= ~NFS4_SHARE_WANT_MASK;
+
+ return share_access == NFS4_SHARE_ACCESS_READ ? RD_STATE : WR_STATE;
+}
+
static __be32
nfs4_check_deleg(struct nfs4_file *fp, struct nfsd4_open *open,
struct nfs4_delegation **dp)
@@ -2265,8 +2338,7 @@ nfs4_check_deleg(struct nfs4_file *fp, struct nfsd4_open *open,
*dp = find_delegation_file(fp, &open->op_delegate_stateid);
if (*dp == NULL)
goto out;
- flags = open->op_share_access == NFS4_SHARE_ACCESS_READ ?
- RD_STATE : WR_STATE;
+ flags = share_access_to_flags(open->op_share_access);
status = nfs4_check_delegmode(*dp, flags);
if (status)
*dp = NULL;
@@ -2308,30 +2380,53 @@ nfs4_alloc_stateid(void)
return kmem_cache_alloc(stateid_slab, GFP_KERNEL);
}
+static inline int nfs4_access_to_access(u32 nfs4_access)
+{
+ int flags = 0;
+
+ if (nfs4_access & NFS4_SHARE_ACCESS_READ)
+ flags |= NFSD_MAY_READ;
+ if (nfs4_access & NFS4_SHARE_ACCESS_WRITE)
+ flags |= NFSD_MAY_WRITE;
+ return flags;
+}
+
+static __be32 nfs4_get_vfs_file(struct svc_rqst *rqstp, struct nfs4_file
+*fp, struct svc_fh *cur_fh, u32 nfs4_access)
+{
+ __be32 status;
+ int oflag = nfs4_access_to_omode(nfs4_access);
+ int access = nfs4_access_to_access(nfs4_access);
+
+ if (!fp->fi_fds[oflag]) {
+ status = nfsd_open(rqstp, cur_fh, S_IFREG, access,
+ &fp->fi_fds[oflag]);
+ if (status == nfserr_dropit)
+ status = nfserr_jukebox;
+ if (status)
+ return status;
+ }
+ nfs4_file_get_access(fp, oflag);
+
+ return nfs_ok;
+}
+
static __be32
nfs4_new_open(struct svc_rqst *rqstp, struct nfs4_stateid **stpp,
- struct nfs4_delegation *dp,
- struct svc_fh *cur_fh, int flags)
+ struct nfs4_file *fp, struct svc_fh *cur_fh,
+ struct nfsd4_open *open)
{
struct nfs4_stateid *stp;
+ __be32 status;
stp = nfs4_alloc_stateid();
if (stp == NULL)
return nfserr_resource;
- if (dp) {
- get_file(dp->dl_vfs_file);
- stp->st_vfs_file = dp->dl_vfs_file;
- } else {
- __be32 status;
- status = nfsd_open(rqstp, cur_fh, S_IFREG, flags,
- &stp->st_vfs_file);
- if (status) {
- if (status == nfserr_dropit)
- status = nfserr_jukebox;
- kmem_cache_free(stateid_slab, stp);
- return status;
- }
+ status = nfs4_get_vfs_file(rqstp, fp, cur_fh, open->op_share_access);
+ if (status) {
+ kmem_cache_free(stateid_slab, stp);
+ return status;
}
*stpp = stp;
return 0;
@@ -2353,35 +2448,30 @@ nfsd4_truncate(struct svc_rqst *rqstp, struct svc_fh *fh,
}
static __be32
-nfs4_upgrade_open(struct svc_rqst *rqstp, struct svc_fh *cur_fh, struct nfs4_stateid *stp, struct nfsd4_open *open)
+nfs4_upgrade_open(struct svc_rqst *rqstp, struct nfs4_file *fp, struct svc_fh *cur_fh, struct nfs4_stateid *stp, struct nfsd4_open *open)
{
- struct file *filp = stp->st_vfs_file;
- struct inode *inode = filp->f_path.dentry->d_inode;
- unsigned int share_access, new_writer;
+ u32 op_share_access, new_access;
__be32 status;
- set_access(&share_access, stp->st_access_bmap);
- new_writer = (~share_access) & open->op_share_access
- & NFS4_SHARE_ACCESS_WRITE;
-
- if (new_writer) {
- int err = get_write_access(inode);
- if (err)
- return nfserrno(err);
- err = mnt_want_write(cur_fh->fh_export->ex_path.mnt);
- if (err)
- return nfserrno(err);
- file_take_write(filp);
+ set_access(&new_access, stp->st_access_bmap);
+ new_access = (~new_access) & open->op_share_access & ~NFS4_SHARE_WANT_MASK;
+
+ if (new_access) {
+ status = nfs4_get_vfs_file(rqstp, fp, cur_fh, new_access);
+ if (status)
+ return status;
}
status = nfsd4_truncate(rqstp, cur_fh, open);
if (status) {
- if (new_writer)
- put_write_access(inode);
+ if (new_access) {
+ int oflag = nfs4_access_to_omode(new_access);
+ nfs4_file_put_access(fp, oflag);
+ }
return status;
}
/* remember the open */
- filp->f_mode |= open->op_share_access;
- __set_bit(open->op_share_access, &stp->st_access_bmap);
+ op_share_access = open->op_share_access & ~NFS4_SHARE_WANT_MASK;
+ __set_bit(op_share_access, &stp->st_access_bmap);
__set_bit(open->op_share_deny, &stp->st_deny_bmap);
return nfs_ok;
@@ -2444,13 +2534,14 @@ nfs4_open_delegation(struct svc_fh *fh, struct nfsd4_open *open, struct nfs4_sta
fl.fl_type = flag == NFS4_OPEN_DELEGATE_READ? F_RDLCK: F_WRLCK;
fl.fl_end = OFFSET_MAX;
fl.fl_owner = (fl_owner_t)dp;
- fl.fl_file = stp->st_vfs_file;
+ fl.fl_file = find_readable_file(stp->st_file);
+ BUG_ON(!fl.fl_file);
fl.fl_pid = current->tgid;
/* vfs_setlease checks to see if delegation should be handed out.
* the lock_manager callbacks fl_mylease and fl_change are used
*/
- if ((status = vfs_setlease(stp->st_vfs_file, fl.fl_type, &flp))) {
+ if ((status = vfs_setlease(fl.fl_file, fl.fl_type, &flp))) {
dprintk("NFSD: setlease failed [%d], no delegation\n", status);
unhash_delegation(dp);
flag = NFS4_OPEN_DELEGATE_NONE;
@@ -2514,18 +2605,12 @@ nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nf
*/
if (stp) {
/* Stateid was found, this is an OPEN upgrade */
- status = nfs4_upgrade_open(rqstp, current_fh, stp, open);
+ status = nfs4_upgrade_open(rqstp, fp, current_fh, stp, open);
if (status)
goto out;
update_stateid(&stp->st_stateid);
} else {
- /* Stateid was not found, this is a new OPEN */
- int flags = 0;
- if (open->op_share_access & NFS4_SHARE_ACCESS_READ)
- flags |= NFSD_MAY_READ;
- if (open->op_share_access & NFS4_SHARE_ACCESS_WRITE)
- flags |= NFSD_MAY_WRITE;
- status = nfs4_new_open(rqstp, &stp, dp, current_fh, flags);
+ status = nfs4_new_open(rqstp, &stp, fp, current_fh, open);
if (status)
goto out;
init_stateid(stp, fp, open);
@@ -2727,7 +2812,7 @@ search_close_lru(u32 st_id, int flags)
static inline int
nfs4_check_fh(struct svc_fh *fhp, struct nfs4_stateid *stp)
{
- return fhp->fh_dentry->d_inode != stp->st_vfs_file->f_path.dentry->d_inode;
+ return fhp->fh_dentry->d_inode != stp->st_file->fi_inode;
}
static int
@@ -2760,6 +2845,9 @@ __be32 nfs4_check_openmode(struct nfs4_stateid *stp, int flags)
{
__be32 status = nfserr_openmode;
+ /* For lock stateid's, we test the parent open, not the lock: */
+ if (stp->st_openstp)
+ stp = stp->st_openstp;
if ((flags & WR_STATE) && (!access_permit_write(stp->st_access_bmap)))
goto out;
if ((flags & RD_STATE) && (!access_permit_read(stp->st_access_bmap)))
@@ -2872,7 +2960,8 @@ nfs4_preprocess_stateid_op(struct nfsd4_compound_state *cstate,
goto out;
renew_client(dp->dl_client);
if (filpp)
- *filpp = dp->dl_vfs_file;
+ *filpp = find_readable_file(dp->dl_file);
+ BUG_ON(!*filpp);
} else { /* open or lock stateid */
stp = find_stateid(stateid, flags);
if (!stp)
@@ -2889,8 +2978,13 @@ nfs4_preprocess_stateid_op(struct nfsd4_compound_state *cstate,
if (status)
goto out;
renew_client(stp->st_stateowner->so_client);
- if (filpp)
- *filpp = stp->st_vfs_file;
+ if (filpp) {
+ if (flags & RD_STATE)
+ *filpp = find_readable_file(stp->st_file);
+ else
+ *filpp = find_writeable_file(stp->st_file);
+ BUG_ON(!*filpp); /* assured by check_openmode */
+ }
}
status = nfs_ok;
out:
@@ -3126,8 +3220,7 @@ nfsd4_open_downgrade(struct svc_rqst *rqstp,
goto out;
}
set_access(&share_access, stp->st_access_bmap);
- nfs4_file_downgrade(stp->st_vfs_file,
- share_access & ~od->od_share_access);
+ nfs4_file_downgrade(stp->st_file, share_access & ~od->od_share_access);
reset_union_bmap_access(od->od_share_access, &stp->st_access_bmap);
reset_union_bmap_deny(od->od_share_deny, &stp->st_deny_bmap);
@@ -3346,11 +3439,9 @@ static inline void
nfs4_set_lock_denied(struct file_lock *fl, struct nfsd4_lock_denied *deny)
{
struct nfs4_stateowner *sop;
- unsigned int hval;
if (fl->fl_lmops == &nfsd_posix_mng_ops) {
sop = (struct nfs4_stateowner *) fl->fl_owner;
- hval = lockownerid_hashval(sop->so_id);
kref_get(&sop->so_ref);
deny->ld_sop = sop;
deny->ld_clientid = sop->so_client->cl_clientid;
@@ -3446,8 +3537,6 @@ alloc_init_lock_stateid(struct nfs4_stateowner *sop, struct nfs4_file *fp, struc
stp->st_stateid.si_stateownerid = sop->so_id;
stp->st_stateid.si_fileid = fp->fi_id;
stp->st_stateid.si_generation = 0;
- stp->st_vfs_file = open_stp->st_vfs_file; /* FIXME refcount?? */
- stp->st_access_bmap = open_stp->st_access_bmap;
stp->st_deny_bmap = open_stp->st_deny_bmap;
stp->st_openstp = open_stp;
@@ -3547,7 +3636,6 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
lock_sop = lock->lk_replay_owner;
}
/* lock->lk_replay_owner and lock_stp have been created or found */
- filp = lock_stp->st_vfs_file;
status = nfserr_grace;
if (locks_in_grace() && !lock->lk_reclaim)
@@ -3560,11 +3648,13 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
switch (lock->lk_type) {
case NFS4_READ_LT:
case NFS4_READW_LT:
+ filp = find_readable_file(lock_stp->st_file);
file_lock.fl_type = F_RDLCK;
cmd = F_SETLK;
break;
case NFS4_WRITE_LT:
case NFS4_WRITEW_LT:
+ filp = find_writeable_file(lock_stp->st_file);
file_lock.fl_type = F_WRLCK;
cmd = F_SETLK;
break;
@@ -3572,6 +3662,10 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
status = nfserr_inval;
goto out;
}
+ if (!filp) {
+ status = nfserr_openmode;
+ goto out;
+ }
file_lock.fl_owner = (fl_owner_t)lock_sop;
file_lock.fl_pid = current->tgid;
file_lock.fl_file = filp;
@@ -3740,7 +3834,11 @@ nfsd4_locku(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
&locku->lu_stateowner, &stp, NULL)))
goto out;
- filp = stp->st_vfs_file;
+ filp = find_any_file(stp->st_file);
+ if (!filp) {
+ status = nfserr_lock_range;
+ goto out;
+ }
BUG_ON(!filp);
locks_init_lock(&file_lock);
file_lock.fl_type = F_UNLCK;
@@ -3787,10 +3885,10 @@ out_nfserr:
* 0: no locks held by lockowner
*/
static int
-check_for_locks(struct file *filp, struct nfs4_stateowner *lowner)
+check_for_locks(struct nfs4_file *filp, struct nfs4_stateowner *lowner)
{
struct file_lock **flpp;
- struct inode *inode = filp->f_path.dentry->d_inode;
+ struct inode *inode = filp->fi_inode;
int status = 0;
lock_kernel();
@@ -3841,7 +3939,7 @@ nfsd4_release_lockowner(struct svc_rqst *rqstp,
continue;
list_for_each_entry(stp, &sop->so_stateids,
st_perstateowner) {
- if (check_for_locks(stp->st_vfs_file, sop))
+ if (check_for_locks(stp->st_file, sop))
goto out;
/* Note: so_perclient unused for lockowners,
* so it's OK to fool with here. */
@@ -4066,16 +4164,8 @@ out_free_laundry:
int
nfs4_state_start(void)
{
- int ret;
-
- if (nfs4_init)
- return 0;
nfsd4_load_reboot_recovery_data();
- ret = __nfs4_state_start();
- if (ret)
- return ret;
- nfs4_init = 1;
- return 0;
+ return __nfs4_state_start();
}
static void
@@ -4110,7 +4200,6 @@ __nfs4_state_shutdown(void)
}
nfsd4_shutdown_recdir();
- nfs4_init = 0;
}
void
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
index ac17a708023..f8931acb05f 100644
--- a/fs/nfsd/nfs4xdr.c
+++ b/fs/nfsd/nfs4xdr.c
@@ -2630,7 +2630,7 @@ nfsd4_encode_read(struct nfsd4_compoundres *resp, __be32 nfserr,
}
read->rd_vlen = v;
- nfserr = nfsd_read(read->rd_rqstp, read->rd_fhp, read->rd_filp,
+ nfserr = nfsd_read_file(read->rd_rqstp, read->rd_fhp, read->rd_filp,
read->rd_offset, resp->rqstp->rq_vec, read->rd_vlen,
&maxcount);
@@ -3325,6 +3325,7 @@ nfs4svc_encode_compoundres(struct svc_rqst *rqstp, __be32 *p, struct nfsd4_compo
}
/* Renew the clientid on success and on replay */
release_session_client(cs->session);
+ nfsd4_put_session(cs->session);
}
return 1;
}
diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c
index 508941c23af..b53b1d042f1 100644
--- a/fs/nfsd/nfsctl.c
+++ b/fs/nfsd/nfsctl.c
@@ -949,15 +949,12 @@ static ssize_t __write_ports_addfd(char *buf)
if (err != 0)
return err;
- err = lockd_up();
- if (err != 0)
- goto out;
-
err = svc_addsock(nfsd_serv, fd, buf, SIMPLE_TRANSACTION_LIMIT);
- if (err < 0)
- lockd_down();
+ if (err < 0) {
+ svc_destroy(nfsd_serv);
+ return err;
+ }
-out:
/* Decrease the count, but don't shut down the service */
nfsd_serv->sv_nrthreads--;
return err;
@@ -978,9 +975,6 @@ static ssize_t __write_ports_delfd(char *buf)
if (nfsd_serv != NULL)
len = svc_sock_names(nfsd_serv, buf,
SIMPLE_TRANSACTION_LIMIT, toclose);
- if (len >= 0)
- lockd_down();
-
kfree(toclose);
return len;
}
@@ -1014,6 +1008,9 @@ static ssize_t __write_ports_addxprt(char *buf)
PF_INET6, port, SVC_SOCK_ANONYMOUS);
if (err < 0 && err != -EAFNOSUPPORT)
goto out_close;
+
+ /* Decrease the count, but don't shut down the service */
+ nfsd_serv->sv_nrthreads--;
return 0;
out_close:
xprt = svc_find_xprt(nfsd_serv, transport, PF_INET, port);
@@ -1022,8 +1019,7 @@ out_close:
svc_xprt_put(xprt);
}
out_err:
- /* Decrease the count, but don't shut down the service */
- nfsd_serv->sv_nrthreads--;
+ svc_destroy(nfsd_serv);
return err;
}
@@ -1194,7 +1190,7 @@ static ssize_t write_maxblksize(struct file *file, char *buf, size_t size)
bsize = NFSSVC_MAXBLKSIZE;
bsize &= ~(1024-1);
mutex_lock(&nfsd_mutex);
- if (nfsd_serv && nfsd_serv->sv_nrthreads) {
+ if (nfsd_serv) {
mutex_unlock(&nfsd_mutex);
return -EBUSY;
}
@@ -1310,6 +1306,8 @@ static ssize_t __write_recoverydir(struct file *file, char *buf, size_t size)
return -EINVAL;
status = nfs4_reset_recoverydir(recdir);
+ if (status)
+ return status;
}
return scnprintf(buf, SIMPLE_TRANSACTION_LIMIT, "%s\n",
diff --git a/fs/nfsd/nfsd.h b/fs/nfsd/nfsd.h
index 72377761270..b76ac3a82e3 100644
--- a/fs/nfsd/nfsd.h
+++ b/fs/nfsd/nfsd.h
@@ -153,6 +153,7 @@ void nfsd_lockd_shutdown(void);
#define nfserr_bad_seqid cpu_to_be32(NFSERR_BAD_SEQID)
#define nfserr_symlink cpu_to_be32(NFSERR_SYMLINK)
#define nfserr_not_same cpu_to_be32(NFSERR_NOT_SAME)
+#define nfserr_lock_range cpu_to_be32(NFSERR_LOCK_RANGE)
#define nfserr_restorefh cpu_to_be32(NFSERR_RESTOREFH)
#define nfserr_attrnotsupp cpu_to_be32(NFSERR_ATTRNOTSUPP)
#define nfserr_bad_xdr cpu_to_be32(NFSERR_BAD_XDR)
diff --git a/fs/nfsd/nfsproc.c b/fs/nfsd/nfsproc.c
index a047ad6111e..08e17264784 100644
--- a/fs/nfsd/nfsproc.c
+++ b/fs/nfsd/nfsproc.c
@@ -144,7 +144,7 @@ nfsd_proc_read(struct svc_rqst *rqstp, struct nfsd_readargs *argp,
svc_reserve_auth(rqstp, (19<<2) + argp->count + 4);
resp->count = argp->count;
- nfserr = nfsd_read(rqstp, fh_copy(&resp->fh, &argp->fh), NULL,
+ nfserr = nfsd_read(rqstp, fh_copy(&resp->fh, &argp->fh),
argp->offset,
rqstp->rq_vec, argp->vlen,
&resp->count);
@@ -290,7 +290,6 @@ nfsd_proc_create(struct svc_rqst *rqstp, struct nfsd_createargs *argp,
* gospel of sun micro
*/
if (type != S_IFREG) {
- int is_borc = 0;
if (type != S_IFBLK && type != S_IFCHR) {
rdev = 0;
} else if (type == S_IFCHR && !(attr->ia_valid & ATTR_SIZE)) {
@@ -298,7 +297,6 @@ nfsd_proc_create(struct svc_rqst *rqstp, struct nfsd_createargs *argp,
type = S_IFIFO;
} else {
/* Okay, char or block special */
- is_borc = 1;
if (!rdev)
rdev = wanted;
}
diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c
index 06b2a26edfe..e2c43464f23 100644
--- a/fs/nfsd/nfssvc.c
+++ b/fs/nfsd/nfssvc.c
@@ -180,15 +180,80 @@ int nfsd_nrthreads(void)
return rv;
}
+static int nfsd_init_socks(int port)
+{
+ int error;
+ if (!list_empty(&nfsd_serv->sv_permsocks))
+ return 0;
+
+ error = svc_create_xprt(nfsd_serv, "udp", PF_INET, port,
+ SVC_SOCK_DEFAULTS);
+ if (error < 0)
+ return error;
+
+ error = svc_create_xprt(nfsd_serv, "tcp", PF_INET, port,
+ SVC_SOCK_DEFAULTS);
+ if (error < 0)
+ return error;
+
+ return 0;
+}
+
+static bool nfsd_up = false;
+
+static int nfsd_startup(unsigned short port, int nrservs)
+{
+ int ret;
+
+ if (nfsd_up)
+ return 0;
+ /*
+ * Readahead param cache - will no-op if it already exists.
+ * (Note therefore results will be suboptimal if number of
+ * threads is modified after nfsd start.)
+ */
+ ret = nfsd_racache_init(2*nrservs);
+ if (ret)
+ return ret;
+ ret = nfsd_init_socks(port);
+ if (ret)
+ goto out_racache;
+ ret = lockd_up();
+ if (ret)
+ goto out_racache;
+ ret = nfs4_state_start();
+ if (ret)
+ goto out_lockd;
+ nfsd_up = true;
+ return 0;
+out_lockd:
+ lockd_down();
+out_racache:
+ nfsd_racache_shutdown();
+ return ret;
+}
+
+static void nfsd_shutdown(void)
+{
+ /*
+ * write_ports can create the server without actually starting
+ * any threads--if we get shut down before any threads are
+ * started, then nfsd_last_thread will be run before any of this
+ * other initialization has been done.
+ */
+ if (!nfsd_up)
+ return;
+ nfs4_state_shutdown();
+ lockd_down();
+ nfsd_racache_shutdown();
+ nfsd_up = false;
+}
+
static void nfsd_last_thread(struct svc_serv *serv)
{
/* When last nfsd thread exits we need to do some clean-up */
- struct svc_xprt *xprt;
- list_for_each_entry(xprt, &serv->sv_permsocks, xpt_list)
- lockd_down();
nfsd_serv = NULL;
- nfsd_racache_shutdown();
- nfs4_state_shutdown();
+ nfsd_shutdown();
printk(KERN_WARNING "nfsd: last server has exited, flushing export "
"cache\n");
@@ -263,45 +328,18 @@ int nfsd_create_serv(void)
nfsd_max_blksize >= 8*1024*2)
nfsd_max_blksize /= 2;
}
+ nfsd_reset_versions();
nfsd_serv = svc_create_pooled(&nfsd_program, nfsd_max_blksize,
nfsd_last_thread, nfsd, THIS_MODULE);
if (nfsd_serv == NULL)
- err = -ENOMEM;
- else
- set_max_drc();
+ return -ENOMEM;
+ set_max_drc();
do_gettimeofday(&nfssvc_boot); /* record boot time */
return err;
}
-static int nfsd_init_socks(int port)
-{
- int error;
- if (!list_empty(&nfsd_serv->sv_permsocks))
- return 0;
-
- error = svc_create_xprt(nfsd_serv, "udp", PF_INET, port,
- SVC_SOCK_DEFAULTS);
- if (error < 0)
- return error;
-
- error = lockd_up();
- if (error < 0)
- return error;
-
- error = svc_create_xprt(nfsd_serv, "tcp", PF_INET, port,
- SVC_SOCK_DEFAULTS);
- if (error < 0)
- return error;
-
- error = lockd_up();
- if (error < 0)
- return error;
-
- return 0;
-}
-
int nfsd_nrpools(void)
{
if (nfsd_serv == NULL)
@@ -376,10 +414,16 @@ int nfsd_set_nrthreads(int n, int *nthreads)
return err;
}
+/*
+ * Adjust the number of threads and return the new number of threads.
+ * This is also the function that starts the server if necessary, if
+ * this is the first time nrservs is nonzero.
+ */
int
nfsd_svc(unsigned short port, int nrservs)
{
int error;
+ bool nfsd_up_before;
mutex_lock(&nfsd_mutex);
dprintk("nfsd: creating service\n");
@@ -391,34 +435,29 @@ nfsd_svc(unsigned short port, int nrservs)
if (nrservs == 0 && nfsd_serv == NULL)
goto out;
- /* Readahead param cache - will no-op if it already exists */
- error = nfsd_racache_init(2*nrservs);
- if (error<0)
- goto out;
- error = nfs4_state_start();
+ error = nfsd_create_serv();
if (error)
goto out;
- nfsd_reset_versions();
-
- error = nfsd_create_serv();
+ nfsd_up_before = nfsd_up;
+ error = nfsd_startup(port, nrservs);
if (error)
- goto out;
- error = nfsd_init_socks(port);
- if (error)
- goto failure;
-
+ goto out_destroy;
error = svc_set_num_threads(nfsd_serv, NULL, nrservs);
- if (error == 0)
- /* We are holding a reference to nfsd_serv which
- * we don't want to count in the return value,
- * so subtract 1
- */
- error = nfsd_serv->sv_nrthreads - 1;
- failure:
+ if (error)
+ goto out_shutdown;
+ /* We are holding a reference to nfsd_serv which
+ * we don't want to count in the return value,
+ * so subtract 1
+ */
+ error = nfsd_serv->sv_nrthreads - 1;
+out_shutdown:
+ if (error < 0 && !nfsd_up_before)
+ nfsd_shutdown();
+out_destroy:
svc_destroy(nfsd_serv); /* Release server */
- out:
+out:
mutex_unlock(&nfsd_mutex);
return error;
}
diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h
index 006c84230c7..7731a75971d 100644
--- a/fs/nfsd/state.h
+++ b/fs/nfsd/state.h
@@ -88,7 +88,6 @@ struct nfs4_delegation {
struct nfs4_client *dl_client;
struct nfs4_file *dl_file;
struct file_lock *dl_flock;
- struct file *dl_vfs_file;
u32 dl_type;
time_t dl_time;
/* For recall: */
@@ -342,12 +341,50 @@ struct nfs4_file {
struct list_head fi_hash; /* hash by "struct inode *" */
struct list_head fi_stateids;
struct list_head fi_delegations;
+ /* One each for O_RDONLY, O_WRONLY, O_RDWR: */
+ struct file * fi_fds[3];
+ /* One each for O_RDONLY, O_WRONLY: */
+ atomic_t fi_access[2];
+ /*
+ * Each open stateid contributes 1 to either fi_readers or
+ * fi_writers, or both, depending on the open mode. A
+ * delegation also takes an fi_readers reference. Lock
+ * stateid's take none.
+ */
+ atomic_t fi_readers;
+ atomic_t fi_writers;
struct inode *fi_inode;
u32 fi_id; /* used with stateowner->so_id
* for stateid_hashtbl hash */
bool fi_had_conflict;
};
+/* XXX: for first cut may fall back on returning file that doesn't work
+ * at all? */
+static inline struct file *find_writeable_file(struct nfs4_file *f)
+{
+ if (f->fi_fds[O_RDWR])
+ return f->fi_fds[O_RDWR];
+ return f->fi_fds[O_WRONLY];
+}
+
+static inline struct file *find_readable_file(struct nfs4_file *f)
+{
+ if (f->fi_fds[O_RDWR])
+ return f->fi_fds[O_RDWR];
+ return f->fi_fds[O_RDONLY];
+}
+
+static inline struct file *find_any_file(struct nfs4_file *f)
+{
+ if (f->fi_fds[O_RDWR])
+ return f->fi_fds[O_RDWR];
+ else if (f->fi_fds[O_RDWR])
+ return f->fi_fds[O_WRONLY];
+ else
+ return f->fi_fds[O_RDONLY];
+}
+
/*
* nfs4_stateid can either be an open stateid or (eventually) a lock stateid
*
@@ -373,7 +410,6 @@ struct nfs4_stateid {
struct nfs4_stateowner * st_stateowner;
struct nfs4_file * st_file;
stateid_t st_stateid;
- struct file * st_vfs_file;
unsigned long st_access_bmap;
unsigned long st_deny_bmap;
struct nfs4_stateid * st_openstp;
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c
index 3c111120b61..9df85a13af2 100644
--- a/fs/nfsd/vfs.c
+++ b/fs/nfsd/vfs.c
@@ -604,7 +604,7 @@ nfsd4_get_nfs4_acl(struct svc_rqst *rqstp, struct dentry *dentry, struct nfs4_ac
return error;
}
-#endif /* defined(CONFIG_NFS_V4) */
+#endif /* defined(CONFIG_NFSD_V4) */
#ifdef CONFIG_NFSD_V3
/*
@@ -903,7 +903,6 @@ nfsd_vfs_read(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file,
loff_t offset, struct kvec *vec, int vlen, unsigned long *count)
{
struct inode *inode;
- struct raparms *ra;
mm_segment_t oldfs;
__be32 err;
int host_err;
@@ -914,12 +913,6 @@ nfsd_vfs_read(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file,
if (svc_msnfs(fhp) && !lock_may_read(inode, offset, *count))
goto out;
- /* Get readahead parameters */
- ra = nfsd_get_raparms(inode->i_sb->s_dev, inode->i_ino);
-
- if (ra && ra->p_set)
- file->f_ra = ra->p_ra;
-
if (file->f_op->splice_read && rqstp->rq_splice_ok) {
struct splice_desc sd = {
.len = 0,
@@ -937,16 +930,6 @@ nfsd_vfs_read(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file,
set_fs(oldfs);
}
- /* Write back readahead params */
- if (ra) {
- struct raparm_hbucket *rab = &raparm_hash[ra->p_hindex];
- spin_lock(&rab->pb_lock);
- ra->p_ra = file->f_ra;
- ra->p_set = 1;
- ra->p_count--;
- spin_unlock(&rab->pb_lock);
- }
-
if (host_err >= 0) {
nfsdstats.io_read += host_err;
*count = host_err;
@@ -1086,8 +1069,45 @@ out:
* on entry. On return, *count contains the number of bytes actually read.
* N.B. After this call fhp needs an fh_put
*/
+__be32 nfsd_read(struct svc_rqst *rqstp, struct svc_fh *fhp,
+ loff_t offset, struct kvec *vec, int vlen, unsigned long *count)
+{
+ struct file *file;
+ struct inode *inode;
+ struct raparms *ra;
+ __be32 err;
+
+ err = nfsd_open(rqstp, fhp, S_IFREG, NFSD_MAY_READ, &file);
+ if (err)
+ return err;
+
+ inode = file->f_path.dentry->d_inode;
+
+ /* Get readahead parameters */
+ ra = nfsd_get_raparms(inode->i_sb->s_dev, inode->i_ino);
+
+ if (ra && ra->p_set)
+ file->f_ra = ra->p_ra;
+
+ err = nfsd_vfs_read(rqstp, fhp, file, offset, vec, vlen, count);
+
+ /* Write back readahead params */
+ if (ra) {
+ struct raparm_hbucket *rab = &raparm_hash[ra->p_hindex];
+ spin_lock(&rab->pb_lock);
+ ra->p_ra = file->f_ra;
+ ra->p_set = 1;
+ ra->p_count--;
+ spin_unlock(&rab->pb_lock);
+ }
+
+ nfsd_close(file);
+ return err;
+}
+
+/* As above, but use the provided file descriptor. */
__be32
-nfsd_read(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file,
+nfsd_read_file(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file,
loff_t offset, struct kvec *vec, int vlen,
unsigned long *count)
{
@@ -1099,13 +1119,8 @@ nfsd_read(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file,
if (err)
goto out;
err = nfsd_vfs_read(rqstp, fhp, file, offset, vec, vlen, count);
- } else {
- err = nfsd_open(rqstp, fhp, S_IFREG, NFSD_MAY_READ, &file);
- if (err)
- goto out;
- err = nfsd_vfs_read(rqstp, fhp, file, offset, vec, vlen, count);
- nfsd_close(file);
- }
+ } else /* Note file may still be NULL in NFSv4 special stateid case: */
+ err = nfsd_read(rqstp, fhp, offset, vec, vlen, count);
out:
return err;
}
@@ -1631,7 +1646,7 @@ nfsd_link(struct svc_rqst *rqstp, struct svc_fh *ffhp,
char *name, int len, struct svc_fh *tfhp)
{
struct dentry *ddir, *dnew, *dold;
- struct inode *dirp, *dest;
+ struct inode *dirp;
__be32 err;
int host_err;
@@ -1659,7 +1674,6 @@ nfsd_link(struct svc_rqst *rqstp, struct svc_fh *ffhp,
goto out_nfserr;
dold = tfhp->fh_dentry;
- dest = dold->d_inode;
host_err = mnt_want_write(tfhp->fh_export->ex_path.mnt);
if (host_err) {
@@ -2038,7 +2052,6 @@ nfsd_permission(struct svc_rqst *rqstp, struct svc_export *exp,
struct dentry *dentry, int acc)
{
struct inode *inode = dentry->d_inode;
- struct path path;
int err;
if (acc == NFSD_MAY_NOP)
@@ -2111,15 +2124,7 @@ nfsd_permission(struct svc_rqst *rqstp, struct svc_export *exp,
if (err == -EACCES && S_ISREG(inode->i_mode) &&
acc == (NFSD_MAY_READ | NFSD_MAY_OWNER_OVERRIDE))
err = inode_permission(inode, MAY_EXEC);
- if (err)
- goto nfsd_out;
- /* Do integrity (permission) checking now, but defer incrementing
- * IMA counts to the actual file open.
- */
- path.mnt = exp->ex_path.mnt;
- path.dentry = dentry;
-nfsd_out:
return err? nfserrno(err) : 0;
}
diff --git a/fs/nfsd/vfs.h b/fs/nfsd/vfs.h
index 217a62c2a35..9a370a5e36b 100644
--- a/fs/nfsd/vfs.h
+++ b/fs/nfsd/vfs.h
@@ -64,7 +64,9 @@ __be32 nfsd_commit(struct svc_rqst *, struct svc_fh *,
__be32 nfsd_open(struct svc_rqst *, struct svc_fh *, int,
int, struct file **);
void nfsd_close(struct file *);
-__be32 nfsd_read(struct svc_rqst *, struct svc_fh *, struct file *,
+__be32 nfsd_read(struct svc_rqst *, struct svc_fh *,
+ loff_t, struct kvec *, int, unsigned long *);
+__be32 nfsd_read_file(struct svc_rqst *, struct svc_fh *, struct file *,
loff_t, struct kvec *, int, unsigned long *);
__be32 nfsd_write(struct svc_rqst *, struct svc_fh *,struct file *,
loff_t, struct kvec *,int, unsigned long *, int *);
diff --git a/fs/nilfs2/bmap.c b/fs/nilfs2/bmap.c
index effdbdbe6c1..3dbdc1d356b 100644
--- a/fs/nilfs2/bmap.c
+++ b/fs/nilfs2/bmap.c
@@ -26,6 +26,8 @@
#include "nilfs.h"
#include "bmap.h"
#include "sb.h"
+#include "btree.h"
+#include "direct.h"
#include "btnode.h"
#include "mdt.h"
#include "dat.h"
@@ -533,7 +535,7 @@ void nilfs_bmap_init_gc(struct nilfs_bmap *bmap)
void nilfs_bmap_init_gcdat(struct nilfs_bmap *gcbmap, struct nilfs_bmap *bmap)
{
- memcpy(gcbmap, bmap, sizeof(union nilfs_bmap_union));
+ memcpy(gcbmap, bmap, sizeof(*bmap));
init_rwsem(&gcbmap->b_sem);
lockdep_set_class(&bmap->b_sem, &nilfs_bmap_dat_lock_key);
gcbmap->b_inode = &NILFS_BMAP_I(gcbmap)->vfs_inode;
@@ -541,7 +543,7 @@ void nilfs_bmap_init_gcdat(struct nilfs_bmap *gcbmap, struct nilfs_bmap *bmap)
void nilfs_bmap_commit_gcdat(struct nilfs_bmap *gcbmap, struct nilfs_bmap *bmap)
{
- memcpy(bmap, gcbmap, sizeof(union nilfs_bmap_union));
+ memcpy(bmap, gcbmap, sizeof(*bmap));
init_rwsem(&bmap->b_sem);
lockdep_set_class(&bmap->b_sem, &nilfs_bmap_dat_lock_key);
bmap->b_inode = &NILFS_BMAP_I(bmap)->vfs_inode;
diff --git a/fs/nilfs2/bmap.h b/fs/nilfs2/bmap.h
index 9980d7dbab9..a20569b1992 100644
--- a/fs/nilfs2/bmap.h
+++ b/fs/nilfs2/bmap.h
@@ -32,11 +32,6 @@
#define NILFS_BMAP_INVALID_PTR 0
-#define nilfs_bmap_dkey_to_key(dkey) le64_to_cpu(dkey)
-#define nilfs_bmap_key_to_dkey(key) cpu_to_le64(key)
-#define nilfs_bmap_dptr_to_ptr(dptr) le64_to_cpu(dptr)
-#define nilfs_bmap_ptr_to_dptr(ptr) cpu_to_le64(ptr)
-
#define nilfs_bmap_keydiff_abs(diff) ((diff) < 0 ? -(diff) : (diff))
@@ -71,7 +66,7 @@ struct nilfs_bmap_operations {
int (*bop_delete)(struct nilfs_bmap *, __u64);
void (*bop_clear)(struct nilfs_bmap *);
- int (*bop_propagate)(const struct nilfs_bmap *, struct buffer_head *);
+ int (*bop_propagate)(struct nilfs_bmap *, struct buffer_head *);
void (*bop_lookup_dirty_buffers)(struct nilfs_bmap *,
struct list_head *);
@@ -110,6 +105,7 @@ static inline int nilfs_bmap_is_new_ptr(unsigned long ptr)
* @b_last_allocated_ptr: last allocated ptr for data block
* @b_ptr_type: pointer type
* @b_state: state
+ * @b_nchildren_per_block: maximum number of child nodes for non-root nodes
*/
struct nilfs_bmap {
union {
@@ -123,6 +119,7 @@ struct nilfs_bmap {
__u64 b_last_allocated_ptr;
int b_ptr_type;
int b_state;
+ __u16 b_nchildren_per_block;
};
/* pointer type */
@@ -224,6 +221,13 @@ static inline void nilfs_bmap_abort_end_ptr(struct nilfs_bmap *bmap,
nilfs_dat_abort_end(dat, &req->bpr_req);
}
+static inline void nilfs_bmap_set_target_v(struct nilfs_bmap *bmap, __u64 key,
+ __u64 ptr)
+{
+ bmap->b_last_allocated_key = key;
+ bmap->b_last_allocated_ptr = ptr;
+}
+
__u64 nilfs_bmap_data_get_key(const struct nilfs_bmap *,
const struct buffer_head *);
diff --git a/fs/nilfs2/btnode.c b/fs/nilfs2/btnode.c
index 447ce47a330..f78ab1044d1 100644
--- a/fs/nilfs2/btnode.c
+++ b/fs/nilfs2/btnode.c
@@ -96,10 +96,12 @@ nilfs_btnode_create_block(struct address_space *btnc, __u64 blocknr)
}
int nilfs_btnode_submit_block(struct address_space *btnc, __u64 blocknr,
- sector_t pblocknr, struct buffer_head **pbh)
+ sector_t pblocknr, int mode,
+ struct buffer_head **pbh, sector_t *submit_ptr)
{
struct buffer_head *bh;
struct inode *inode = NILFS_BTNC_I(btnc);
+ struct page *page;
int err;
bh = nilfs_grab_buffer(inode, btnc, blocknr, 1 << BH_NILFS_Node);
@@ -107,6 +109,7 @@ int nilfs_btnode_submit_block(struct address_space *btnc, __u64 blocknr,
return -ENOMEM;
err = -EEXIST; /* internal code */
+ page = bh->b_page;
if (buffer_uptodate(bh) || buffer_dirty(bh))
goto found;
@@ -125,7 +128,16 @@ int nilfs_btnode_submit_block(struct address_space *btnc, __u64 blocknr,
}
}
}
- lock_buffer(bh);
+
+ if (mode == READA) {
+ if (pblocknr != *submit_ptr + 1 || !trylock_buffer(bh)) {
+ err = -EBUSY; /* internal code */
+ brelse(bh);
+ goto out_locked;
+ }
+ } else { /* mode == READ */
+ lock_buffer(bh);
+ }
if (buffer_uptodate(bh)) {
unlock_buffer(bh);
err = -EEXIST; /* internal code */
@@ -136,15 +148,16 @@ int nilfs_btnode_submit_block(struct address_space *btnc, __u64 blocknr,
bh->b_blocknr = pblocknr; /* set block address for read */
bh->b_end_io = end_buffer_read_sync;
get_bh(bh);
- submit_bh(READ, bh);
+ submit_bh(mode, bh);
bh->b_blocknr = blocknr; /* set back to the given block address */
+ *submit_ptr = pblocknr;
err = 0;
found:
*pbh = bh;
out_locked:
- unlock_page(bh->b_page);
- page_cache_release(bh->b_page);
+ unlock_page(page);
+ page_cache_release(page);
return err;
}
diff --git a/fs/nilfs2/btnode.h b/fs/nilfs2/btnode.h
index 07da83f0771..79037494f1e 100644
--- a/fs/nilfs2/btnode.h
+++ b/fs/nilfs2/btnode.h
@@ -42,8 +42,8 @@ void nilfs_btnode_cache_init(struct address_space *, struct backing_dev_info *);
void nilfs_btnode_cache_clear(struct address_space *);
struct buffer_head *nilfs_btnode_create_block(struct address_space *btnc,
__u64 blocknr);
-int nilfs_btnode_submit_block(struct address_space *, __u64, sector_t,
- struct buffer_head **);
+int nilfs_btnode_submit_block(struct address_space *, __u64, sector_t, int,
+ struct buffer_head **, sector_t *);
void nilfs_btnode_delete(struct buffer_head *);
int nilfs_btnode_prepare_change_key(struct address_space *,
struct nilfs_btnode_chkey_ctxt *);
diff --git a/fs/nilfs2/btree.c b/fs/nilfs2/btree.c
index b27a342c5af..300c2bc00c3 100644
--- a/fs/nilfs2/btree.c
+++ b/fs/nilfs2/btree.c
@@ -66,30 +66,10 @@ static void nilfs_btree_free_path(struct nilfs_btree_path *path)
/*
* B-tree node operations
*/
-static int nilfs_btree_get_block(const struct nilfs_btree *btree, __u64 ptr,
- struct buffer_head **bhp)
-{
- struct address_space *btnc =
- &NILFS_BMAP_I((struct nilfs_bmap *)btree)->i_btnode_cache;
- int err;
-
- err = nilfs_btnode_submit_block(btnc, ptr, 0, bhp);
- if (err)
- return err == -EEXIST ? 0 : err;
-
- wait_on_buffer(*bhp);
- if (!buffer_uptodate(*bhp)) {
- brelse(*bhp);
- return -EIO;
- }
- return 0;
-}
-
-static int nilfs_btree_get_new_block(const struct nilfs_btree *btree,
+static int nilfs_btree_get_new_block(const struct nilfs_bmap *btree,
__u64 ptr, struct buffer_head **bhp)
{
- struct address_space *btnc =
- &NILFS_BMAP_I((struct nilfs_bmap *)btree)->i_btnode_cache;
+ struct address_space *btnc = &NILFS_BMAP_I(btree)->i_btnode_cache;
struct buffer_head *bh;
bh = nilfs_btnode_create_block(btnc, ptr);
@@ -101,71 +81,55 @@ static int nilfs_btree_get_new_block(const struct nilfs_btree *btree,
return 0;
}
-static inline int
-nilfs_btree_node_get_flags(const struct nilfs_btree_node *node)
+static int nilfs_btree_node_get_flags(const struct nilfs_btree_node *node)
{
return node->bn_flags;
}
-static inline void
+static void
nilfs_btree_node_set_flags(struct nilfs_btree_node *node, int flags)
{
node->bn_flags = flags;
}
-static inline int nilfs_btree_node_root(const struct nilfs_btree_node *node)
+static int nilfs_btree_node_root(const struct nilfs_btree_node *node)
{
return nilfs_btree_node_get_flags(node) & NILFS_BTREE_NODE_ROOT;
}
-static inline int
-nilfs_btree_node_get_level(const struct nilfs_btree_node *node)
+static int nilfs_btree_node_get_level(const struct nilfs_btree_node *node)
{
return node->bn_level;
}
-static inline void
+static void
nilfs_btree_node_set_level(struct nilfs_btree_node *node, int level)
{
node->bn_level = level;
}
-static inline int
-nilfs_btree_node_get_nchildren(const struct nilfs_btree_node *node)
+static int nilfs_btree_node_get_nchildren(const struct nilfs_btree_node *node)
{
return le16_to_cpu(node->bn_nchildren);
}
-static inline void
+static void
nilfs_btree_node_set_nchildren(struct nilfs_btree_node *node, int nchildren)
{
node->bn_nchildren = cpu_to_le16(nchildren);
}
-static inline int nilfs_btree_node_size(const struct nilfs_btree *btree)
+static int nilfs_btree_node_size(const struct nilfs_bmap *btree)
{
- return 1 << btree->bt_bmap.b_inode->i_blkbits;
+ return 1 << btree->b_inode->i_blkbits;
}
-static inline int
-nilfs_btree_node_nchildren_min(const struct nilfs_btree_node *node,
- const struct nilfs_btree *btree)
+static int nilfs_btree_nchildren_per_block(const struct nilfs_bmap *btree)
{
- return nilfs_btree_node_root(node) ?
- NILFS_BTREE_ROOT_NCHILDREN_MIN :
- NILFS_BTREE_NODE_NCHILDREN_MIN(nilfs_btree_node_size(btree));
+ return btree->b_nchildren_per_block;
}
-static inline int
-nilfs_btree_node_nchildren_max(const struct nilfs_btree_node *node,
- const struct nilfs_btree *btree)
-{
- return nilfs_btree_node_root(node) ?
- NILFS_BTREE_ROOT_NCHILDREN_MAX :
- NILFS_BTREE_NODE_NCHILDREN_MAX(nilfs_btree_node_size(btree));
-}
-
-static inline __le64 *
+static __le64 *
nilfs_btree_node_dkeys(const struct nilfs_btree_node *node)
{
return (__le64 *)((char *)(node + 1) +
@@ -173,45 +137,40 @@ nilfs_btree_node_dkeys(const struct nilfs_btree_node *node)
0 : NILFS_BTREE_NODE_EXTRA_PAD_SIZE));
}
-static inline __le64 *
-nilfs_btree_node_dptrs(const struct nilfs_btree_node *node,
- const struct nilfs_btree *btree)
+static __le64 *
+nilfs_btree_node_dptrs(const struct nilfs_btree_node *node, int ncmax)
{
- return (__le64 *)(nilfs_btree_node_dkeys(node) +
- nilfs_btree_node_nchildren_max(node, btree));
+ return (__le64 *)(nilfs_btree_node_dkeys(node) + ncmax);
}
-static inline __u64
+static __u64
nilfs_btree_node_get_key(const struct nilfs_btree_node *node, int index)
{
- return nilfs_bmap_dkey_to_key(*(nilfs_btree_node_dkeys(node) + index));
+ return le64_to_cpu(*(nilfs_btree_node_dkeys(node) + index));
}
-static inline void
+static void
nilfs_btree_node_set_key(struct nilfs_btree_node *node, int index, __u64 key)
{
- *(nilfs_btree_node_dkeys(node) + index) = nilfs_bmap_key_to_dkey(key);
+ *(nilfs_btree_node_dkeys(node) + index) = cpu_to_le64(key);
}
-static inline __u64
-nilfs_btree_node_get_ptr(const struct nilfs_btree *btree,
- const struct nilfs_btree_node *node, int index)
+static __u64
+nilfs_btree_node_get_ptr(const struct nilfs_btree_node *node, int index,
+ int ncmax)
{
- return nilfs_bmap_dptr_to_ptr(*(nilfs_btree_node_dptrs(node, btree) +
- index));
+ return le64_to_cpu(*(nilfs_btree_node_dptrs(node, ncmax) + index));
}
-static inline void
-nilfs_btree_node_set_ptr(struct nilfs_btree *btree,
- struct nilfs_btree_node *node, int index, __u64 ptr)
+static void
+nilfs_btree_node_set_ptr(struct nilfs_btree_node *node, int index, __u64 ptr,
+ int ncmax)
{
- *(nilfs_btree_node_dptrs(node, btree) + index) =
- nilfs_bmap_ptr_to_dptr(ptr);
+ *(nilfs_btree_node_dptrs(node, ncmax) + index) = cpu_to_le64(ptr);
}
-static void nilfs_btree_node_init(struct nilfs_btree *btree,
- struct nilfs_btree_node *node,
- int flags, int level, int nchildren,
+static void nilfs_btree_node_init(struct nilfs_btree_node *node, int flags,
+ int level, int nchildren, int ncmax,
const __u64 *keys, const __u64 *ptrs)
{
__le64 *dkeys;
@@ -223,29 +182,28 @@ static void nilfs_btree_node_init(struct nilfs_btree *btree,
nilfs_btree_node_set_nchildren(node, nchildren);
dkeys = nilfs_btree_node_dkeys(node);
- dptrs = nilfs_btree_node_dptrs(node, btree);
+ dptrs = nilfs_btree_node_dptrs(node, ncmax);
for (i = 0; i < nchildren; i++) {
- dkeys[i] = nilfs_bmap_key_to_dkey(keys[i]);
- dptrs[i] = nilfs_bmap_ptr_to_dptr(ptrs[i]);
+ dkeys[i] = cpu_to_le64(keys[i]);
+ dptrs[i] = cpu_to_le64(ptrs[i]);
}
}
/* Assume the buffer heads corresponding to left and right are locked. */
-static void nilfs_btree_node_move_left(struct nilfs_btree *btree,
- struct nilfs_btree_node *left,
+static void nilfs_btree_node_move_left(struct nilfs_btree_node *left,
struct nilfs_btree_node *right,
- int n)
+ int n, int lncmax, int rncmax)
{
__le64 *ldkeys, *rdkeys;
__le64 *ldptrs, *rdptrs;
int lnchildren, rnchildren;
ldkeys = nilfs_btree_node_dkeys(left);
- ldptrs = nilfs_btree_node_dptrs(left, btree);
+ ldptrs = nilfs_btree_node_dptrs(left, lncmax);
lnchildren = nilfs_btree_node_get_nchildren(left);
rdkeys = nilfs_btree_node_dkeys(right);
- rdptrs = nilfs_btree_node_dptrs(right, btree);
+ rdptrs = nilfs_btree_node_dptrs(right, rncmax);
rnchildren = nilfs_btree_node_get_nchildren(right);
memcpy(ldkeys + lnchildren, rdkeys, n * sizeof(*rdkeys));
@@ -260,21 +218,20 @@ static void nilfs_btree_node_move_left(struct nilfs_btree *btree,
}
/* Assume that the buffer heads corresponding to left and right are locked. */
-static void nilfs_btree_node_move_right(struct nilfs_btree *btree,
- struct nilfs_btree_node *left,
+static void nilfs_btree_node_move_right(struct nilfs_btree_node *left,
struct nilfs_btree_node *right,
- int n)
+ int n, int lncmax, int rncmax)
{
__le64 *ldkeys, *rdkeys;
__le64 *ldptrs, *rdptrs;
int lnchildren, rnchildren;
ldkeys = nilfs_btree_node_dkeys(left);
- ldptrs = nilfs_btree_node_dptrs(left, btree);
+ ldptrs = nilfs_btree_node_dptrs(left, lncmax);
lnchildren = nilfs_btree_node_get_nchildren(left);
rdkeys = nilfs_btree_node_dkeys(right);
- rdptrs = nilfs_btree_node_dptrs(right, btree);
+ rdptrs = nilfs_btree_node_dptrs(right, rncmax);
rnchildren = nilfs_btree_node_get_nchildren(right);
memmove(rdkeys + n, rdkeys, rnchildren * sizeof(*rdkeys));
@@ -289,16 +246,15 @@ static void nilfs_btree_node_move_right(struct nilfs_btree *btree,
}
/* Assume that the buffer head corresponding to node is locked. */
-static void nilfs_btree_node_insert(struct nilfs_btree *btree,
- struct nilfs_btree_node *node,
- __u64 key, __u64 ptr, int index)
+static void nilfs_btree_node_insert(struct nilfs_btree_node *node, int index,
+ __u64 key, __u64 ptr, int ncmax)
{
__le64 *dkeys;
__le64 *dptrs;
int nchildren;
dkeys = nilfs_btree_node_dkeys(node);
- dptrs = nilfs_btree_node_dptrs(node, btree);
+ dptrs = nilfs_btree_node_dptrs(node, ncmax);
nchildren = nilfs_btree_node_get_nchildren(node);
if (index < nchildren) {
memmove(dkeys + index + 1, dkeys + index,
@@ -306,16 +262,15 @@ static void nilfs_btree_node_insert(struct nilfs_btree *btree,
memmove(dptrs + index + 1, dptrs + index,
(nchildren - index) * sizeof(*dptrs));
}
- dkeys[index] = nilfs_bmap_key_to_dkey(key);
- dptrs[index] = nilfs_bmap_ptr_to_dptr(ptr);
+ dkeys[index] = cpu_to_le64(key);
+ dptrs[index] = cpu_to_le64(ptr);
nchildren++;
nilfs_btree_node_set_nchildren(node, nchildren);
}
/* Assume that the buffer head corresponding to node is locked. */
-static void nilfs_btree_node_delete(struct nilfs_btree *btree,
- struct nilfs_btree_node *node,
- __u64 *keyp, __u64 *ptrp, int index)
+static void nilfs_btree_node_delete(struct nilfs_btree_node *node, int index,
+ __u64 *keyp, __u64 *ptrp, int ncmax)
{
__u64 key;
__u64 ptr;
@@ -324,9 +279,9 @@ static void nilfs_btree_node_delete(struct nilfs_btree *btree,
int nchildren;
dkeys = nilfs_btree_node_dkeys(node);
- dptrs = nilfs_btree_node_dptrs(node, btree);
- key = nilfs_bmap_dkey_to_key(dkeys[index]);
- ptr = nilfs_bmap_dptr_to_ptr(dptrs[index]);
+ dptrs = nilfs_btree_node_dptrs(node, ncmax);
+ key = le64_to_cpu(dkeys[index]);
+ ptr = le64_to_cpu(dptrs[index]);
nchildren = nilfs_btree_node_get_nchildren(node);
if (keyp != NULL)
*keyp = key;
@@ -382,40 +337,92 @@ static int nilfs_btree_node_lookup(const struct nilfs_btree_node *node,
return s == 0;
}
-static inline struct nilfs_btree_node *
-nilfs_btree_get_root(const struct nilfs_btree *btree)
+/**
+ * nilfs_btree_node_broken - verify consistency of btree node
+ * @node: btree node block to be examined
+ * @size: node size (in bytes)
+ * @blocknr: block number
+ *
+ * Return Value: If node is broken, 1 is returned. Otherwise, 0 is returned.
+ */
+static int nilfs_btree_node_broken(const struct nilfs_btree_node *node,
+ size_t size, sector_t blocknr)
{
- return (struct nilfs_btree_node *)btree->bt_bmap.b_u.u_data;
+ int level, flags, nchildren;
+ int ret = 0;
+
+ level = nilfs_btree_node_get_level(node);
+ flags = nilfs_btree_node_get_flags(node);
+ nchildren = nilfs_btree_node_get_nchildren(node);
+
+ if (unlikely(level < NILFS_BTREE_LEVEL_NODE_MIN ||
+ level >= NILFS_BTREE_LEVEL_MAX ||
+ (flags & NILFS_BTREE_NODE_ROOT) ||
+ nchildren < 0 ||
+ nchildren > NILFS_BTREE_NODE_NCHILDREN_MAX(size))) {
+ printk(KERN_CRIT "NILFS: bad btree node (blocknr=%llu): "
+ "level = %d, flags = 0x%x, nchildren = %d\n",
+ (unsigned long long)blocknr, level, flags, nchildren);
+ ret = 1;
+ }
+ return ret;
}
-static inline struct nilfs_btree_node *
+int nilfs_btree_broken_node_block(struct buffer_head *bh)
+{
+ int ret;
+
+ if (buffer_nilfs_checked(bh))
+ return 0;
+
+ ret = nilfs_btree_node_broken((struct nilfs_btree_node *)bh->b_data,
+ bh->b_size, bh->b_blocknr);
+ if (likely(!ret))
+ set_buffer_nilfs_checked(bh);
+ return ret;
+}
+
+static struct nilfs_btree_node *
+nilfs_btree_get_root(const struct nilfs_bmap *btree)
+{
+ return (struct nilfs_btree_node *)btree->b_u.u_data;
+}
+
+static struct nilfs_btree_node *
nilfs_btree_get_nonroot_node(const struct nilfs_btree_path *path, int level)
{
return (struct nilfs_btree_node *)path[level].bp_bh->b_data;
}
-static inline struct nilfs_btree_node *
+static struct nilfs_btree_node *
nilfs_btree_get_sib_node(const struct nilfs_btree_path *path, int level)
{
return (struct nilfs_btree_node *)path[level].bp_sib_bh->b_data;
}
-static inline int nilfs_btree_height(const struct nilfs_btree *btree)
+static int nilfs_btree_height(const struct nilfs_bmap *btree)
{
return nilfs_btree_node_get_level(nilfs_btree_get_root(btree)) + 1;
}
-static inline struct nilfs_btree_node *
-nilfs_btree_get_node(const struct nilfs_btree *btree,
+static struct nilfs_btree_node *
+nilfs_btree_get_node(const struct nilfs_bmap *btree,
const struct nilfs_btree_path *path,
- int level)
+ int level, int *ncmaxp)
{
- return (level == nilfs_btree_height(btree) - 1) ?
- nilfs_btree_get_root(btree) :
- nilfs_btree_get_nonroot_node(path, level);
+ struct nilfs_btree_node *node;
+
+ if (level == nilfs_btree_height(btree) - 1) {
+ node = nilfs_btree_get_root(btree);
+ *ncmaxp = NILFS_BTREE_ROOT_NCHILDREN_MAX;
+ } else {
+ node = nilfs_btree_get_nonroot_node(path, level);
+ *ncmaxp = nilfs_btree_nchildren_per_block(btree);
+ }
+ return node;
}
-static inline int
+static int
nilfs_btree_bad_node(struct nilfs_btree_node *node, int level)
{
if (unlikely(nilfs_btree_node_get_level(node) != level)) {
@@ -427,13 +434,83 @@ nilfs_btree_bad_node(struct nilfs_btree_node *node, int level)
return 0;
}
-static int nilfs_btree_do_lookup(const struct nilfs_btree *btree,
+struct nilfs_btree_readahead_info {
+ struct nilfs_btree_node *node; /* parent node */
+ int max_ra_blocks; /* max nof blocks to read ahead */
+ int index; /* current index on the parent node */
+ int ncmax; /* nof children in the parent node */
+};
+
+static int __nilfs_btree_get_block(const struct nilfs_bmap *btree, __u64 ptr,
+ struct buffer_head **bhp,
+ const struct nilfs_btree_readahead_info *ra)
+{
+ struct address_space *btnc = &NILFS_BMAP_I(btree)->i_btnode_cache;
+ struct buffer_head *bh, *ra_bh;
+ sector_t submit_ptr = 0;
+ int ret;
+
+ ret = nilfs_btnode_submit_block(btnc, ptr, 0, READ, &bh, &submit_ptr);
+ if (ret) {
+ if (ret != -EEXIST)
+ return ret;
+ goto out_check;
+ }
+
+ if (ra) {
+ int i, n;
+ __u64 ptr2;
+
+ /* read ahead sibling nodes */
+ for (n = ra->max_ra_blocks, i = ra->index + 1;
+ n > 0 && i < ra->ncmax; n--, i++) {
+ ptr2 = nilfs_btree_node_get_ptr(ra->node, i, ra->ncmax);
+
+ ret = nilfs_btnode_submit_block(btnc, ptr2, 0, READA,
+ &ra_bh, &submit_ptr);
+ if (likely(!ret || ret == -EEXIST))
+ brelse(ra_bh);
+ else if (ret != -EBUSY)
+ break;
+ if (!buffer_locked(bh))
+ goto out_no_wait;
+ }
+ }
+
+ wait_on_buffer(bh);
+
+ out_no_wait:
+ if (!buffer_uptodate(bh)) {
+ brelse(bh);
+ return -EIO;
+ }
+
+ out_check:
+ if (nilfs_btree_broken_node_block(bh)) {
+ clear_buffer_uptodate(bh);
+ brelse(bh);
+ return -EINVAL;
+ }
+
+ *bhp = bh;
+ return 0;
+}
+
+static int nilfs_btree_get_block(const struct nilfs_bmap *btree, __u64 ptr,
+ struct buffer_head **bhp)
+{
+ return __nilfs_btree_get_block(btree, ptr, bhp, NULL);
+}
+
+static int nilfs_btree_do_lookup(const struct nilfs_bmap *btree,
struct nilfs_btree_path *path,
- __u64 key, __u64 *ptrp, int minlevel)
+ __u64 key, __u64 *ptrp, int minlevel,
+ int readahead)
{
struct nilfs_btree_node *node;
+ struct nilfs_btree_readahead_info p, *ra;
__u64 ptr;
- int level, index, found, ret;
+ int level, index, found, ncmax, ret;
node = nilfs_btree_get_root(btree);
level = nilfs_btree_node_get_level(node);
@@ -441,14 +518,27 @@ static int nilfs_btree_do_lookup(const struct nilfs_btree *btree,
return -ENOENT;
found = nilfs_btree_node_lookup(node, key, &index);
- ptr = nilfs_btree_node_get_ptr(btree, node, index);
+ ptr = nilfs_btree_node_get_ptr(node, index,
+ NILFS_BTREE_ROOT_NCHILDREN_MAX);
path[level].bp_bh = NULL;
path[level].bp_index = index;
- for (level--; level >= minlevel; level--) {
- ret = nilfs_btree_get_block(btree, ptr, &path[level].bp_bh);
+ ncmax = nilfs_btree_nchildren_per_block(btree);
+
+ while (--level >= minlevel) {
+ ra = NULL;
+ if (level == NILFS_BTREE_LEVEL_NODE_MIN && readahead) {
+ p.node = nilfs_btree_get_node(btree, path, level + 1,
+ &p.ncmax);
+ p.index = index;
+ p.max_ra_blocks = 7;
+ ra = &p;
+ }
+ ret = __nilfs_btree_get_block(btree, ptr, &path[level].bp_bh,
+ ra);
if (ret < 0)
return ret;
+
node = nilfs_btree_get_nonroot_node(path, level);
if (nilfs_btree_bad_node(node, level))
return -EINVAL;
@@ -456,9 +546,9 @@ static int nilfs_btree_do_lookup(const struct nilfs_btree *btree,
found = nilfs_btree_node_lookup(node, key, &index);
else
index = 0;
- if (index < nilfs_btree_node_nchildren_max(node, btree))
- ptr = nilfs_btree_node_get_ptr(btree, node, index);
- else {
+ if (index < ncmax) {
+ ptr = nilfs_btree_node_get_ptr(node, index, ncmax);
+ } else {
WARN_ON(found || level != NILFS_BTREE_LEVEL_NODE_MIN);
/* insert */
ptr = NILFS_BMAP_INVALID_PTR;
@@ -474,22 +564,24 @@ static int nilfs_btree_do_lookup(const struct nilfs_btree *btree,
return 0;
}
-static int nilfs_btree_do_lookup_last(const struct nilfs_btree *btree,
+static int nilfs_btree_do_lookup_last(const struct nilfs_bmap *btree,
struct nilfs_btree_path *path,
__u64 *keyp, __u64 *ptrp)
{
struct nilfs_btree_node *node;
__u64 ptr;
- int index, level, ret;
+ int index, level, ncmax, ret;
node = nilfs_btree_get_root(btree);
index = nilfs_btree_node_get_nchildren(node) - 1;
if (index < 0)
return -ENOENT;
level = nilfs_btree_node_get_level(node);
- ptr = nilfs_btree_node_get_ptr(btree, node, index);
+ ptr = nilfs_btree_node_get_ptr(node, index,
+ NILFS_BTREE_ROOT_NCHILDREN_MAX);
path[level].bp_bh = NULL;
path[level].bp_index = index;
+ ncmax = nilfs_btree_nchildren_per_block(btree);
for (level--; level > 0; level--) {
ret = nilfs_btree_get_block(btree, ptr, &path[level].bp_bh);
@@ -499,7 +591,7 @@ static int nilfs_btree_do_lookup_last(const struct nilfs_btree *btree,
if (nilfs_btree_bad_node(node, level))
return -EINVAL;
index = nilfs_btree_node_get_nchildren(node) - 1;
- ptr = nilfs_btree_node_get_ptr(btree, node, index);
+ ptr = nilfs_btree_node_get_ptr(node, index, ncmax);
path[level].bp_index = index;
}
@@ -511,51 +603,45 @@ static int nilfs_btree_do_lookup_last(const struct nilfs_btree *btree,
return 0;
}
-static int nilfs_btree_lookup(const struct nilfs_bmap *bmap,
+static int nilfs_btree_lookup(const struct nilfs_bmap *btree,
__u64 key, int level, __u64 *ptrp)
{
- struct nilfs_btree *btree;
struct nilfs_btree_path *path;
- __u64 ptr;
int ret;
- btree = (struct nilfs_btree *)bmap;
path = nilfs_btree_alloc_path();
if (path == NULL)
return -ENOMEM;
- ret = nilfs_btree_do_lookup(btree, path, key, &ptr, level);
-
- if (ptrp != NULL)
- *ptrp = ptr;
+ ret = nilfs_btree_do_lookup(btree, path, key, ptrp, level, 0);
nilfs_btree_free_path(path);
return ret;
}
-static int nilfs_btree_lookup_contig(const struct nilfs_bmap *bmap,
+static int nilfs_btree_lookup_contig(const struct nilfs_bmap *btree,
__u64 key, __u64 *ptrp, unsigned maxblocks)
{
- struct nilfs_btree *btree = (struct nilfs_btree *)bmap;
struct nilfs_btree_path *path;
struct nilfs_btree_node *node;
struct inode *dat = NULL;
__u64 ptr, ptr2;
sector_t blocknr;
int level = NILFS_BTREE_LEVEL_NODE_MIN;
- int ret, cnt, index, maxlevel;
+ int ret, cnt, index, maxlevel, ncmax;
+ struct nilfs_btree_readahead_info p;
path = nilfs_btree_alloc_path();
if (path == NULL)
return -ENOMEM;
- ret = nilfs_btree_do_lookup(btree, path, key, &ptr, level);
+ ret = nilfs_btree_do_lookup(btree, path, key, &ptr, level, 1);
if (ret < 0)
goto out;
- if (NILFS_BMAP_USE_VBN(bmap)) {
- dat = nilfs_bmap_get_dat(bmap);
+ if (NILFS_BMAP_USE_VBN(btree)) {
+ dat = nilfs_bmap_get_dat(btree);
ret = nilfs_dat_translate(dat, ptr, &blocknr);
if (ret < 0)
goto out;
@@ -566,14 +652,14 @@ static int nilfs_btree_lookup_contig(const struct nilfs_bmap *bmap,
goto end;
maxlevel = nilfs_btree_height(btree) - 1;
- node = nilfs_btree_get_node(btree, path, level);
+ node = nilfs_btree_get_node(btree, path, level, &ncmax);
index = path[level].bp_index + 1;
for (;;) {
while (index < nilfs_btree_node_get_nchildren(node)) {
if (nilfs_btree_node_get_key(node, index) !=
key + cnt)
goto end;
- ptr2 = nilfs_btree_node_get_ptr(btree, node, index);
+ ptr2 = nilfs_btree_node_get_ptr(node, index, ncmax);
if (dat) {
ret = nilfs_dat_translate(dat, ptr2, &blocknr);
if (ret < 0)
@@ -589,20 +675,24 @@ static int nilfs_btree_lookup_contig(const struct nilfs_bmap *bmap,
break;
/* look-up right sibling node */
- node = nilfs_btree_get_node(btree, path, level + 1);
- index = path[level + 1].bp_index + 1;
- if (index >= nilfs_btree_node_get_nchildren(node) ||
- nilfs_btree_node_get_key(node, index) != key + cnt)
+ p.node = nilfs_btree_get_node(btree, path, level + 1, &p.ncmax);
+ p.index = path[level + 1].bp_index + 1;
+ p.max_ra_blocks = 7;
+ if (p.index >= nilfs_btree_node_get_nchildren(p.node) ||
+ nilfs_btree_node_get_key(p.node, p.index) != key + cnt)
break;
- ptr2 = nilfs_btree_node_get_ptr(btree, node, index);
- path[level + 1].bp_index = index;
+ ptr2 = nilfs_btree_node_get_ptr(p.node, p.index, p.ncmax);
+ path[level + 1].bp_index = p.index;
brelse(path[level].bp_bh);
path[level].bp_bh = NULL;
- ret = nilfs_btree_get_block(btree, ptr2, &path[level].bp_bh);
+
+ ret = __nilfs_btree_get_block(btree, ptr2, &path[level].bp_bh,
+ &p);
if (ret < 0)
goto out;
node = nilfs_btree_get_nonroot_node(path, level);
+ ncmax = nilfs_btree_nchildren_per_block(btree);
index = 0;
path[level].bp_index = index;
}
@@ -614,7 +704,7 @@ static int nilfs_btree_lookup_contig(const struct nilfs_bmap *bmap,
return ret;
}
-static void nilfs_btree_promote_key(struct nilfs_btree *btree,
+static void nilfs_btree_promote_key(struct nilfs_bmap *btree,
struct nilfs_btree_path *path,
int level, __u64 key)
{
@@ -636,16 +726,18 @@ static void nilfs_btree_promote_key(struct nilfs_btree *btree,
}
}
-static void nilfs_btree_do_insert(struct nilfs_btree *btree,
+static void nilfs_btree_do_insert(struct nilfs_bmap *btree,
struct nilfs_btree_path *path,
int level, __u64 *keyp, __u64 *ptrp)
{
struct nilfs_btree_node *node;
+ int ncblk;
if (level < nilfs_btree_height(btree) - 1) {
node = nilfs_btree_get_nonroot_node(path, level);
- nilfs_btree_node_insert(btree, node, *keyp, *ptrp,
- path[level].bp_index);
+ ncblk = nilfs_btree_nchildren_per_block(btree);
+ nilfs_btree_node_insert(node, path[level].bp_index,
+ *keyp, *ptrp, ncblk);
if (!buffer_dirty(path[level].bp_bh))
nilfs_btnode_mark_dirty(path[level].bp_bh);
@@ -655,22 +747,24 @@ static void nilfs_btree_do_insert(struct nilfs_btree *btree,
0));
} else {
node = nilfs_btree_get_root(btree);
- nilfs_btree_node_insert(btree, node, *keyp, *ptrp,
- path[level].bp_index);
+ nilfs_btree_node_insert(node, path[level].bp_index,
+ *keyp, *ptrp,
+ NILFS_BTREE_ROOT_NCHILDREN_MAX);
}
}
-static void nilfs_btree_carry_left(struct nilfs_btree *btree,
+static void nilfs_btree_carry_left(struct nilfs_bmap *btree,
struct nilfs_btree_path *path,
int level, __u64 *keyp, __u64 *ptrp)
{
struct nilfs_btree_node *node, *left;
- int nchildren, lnchildren, n, move;
+ int nchildren, lnchildren, n, move, ncblk;
node = nilfs_btree_get_nonroot_node(path, level);
left = nilfs_btree_get_sib_node(path, level);
nchildren = nilfs_btree_node_get_nchildren(node);
lnchildren = nilfs_btree_node_get_nchildren(left);
+ ncblk = nilfs_btree_nchildren_per_block(btree);
move = 0;
n = (nchildren + lnchildren + 1) / 2 - lnchildren;
@@ -680,7 +774,7 @@ static void nilfs_btree_carry_left(struct nilfs_btree *btree,
move = 1;
}
- nilfs_btree_node_move_left(btree, left, node, n);
+ nilfs_btree_node_move_left(left, node, n, ncblk, ncblk);
if (!buffer_dirty(path[level].bp_bh))
nilfs_btnode_mark_dirty(path[level].bp_bh);
@@ -705,17 +799,18 @@ static void nilfs_btree_carry_left(struct nilfs_btree *btree,
nilfs_btree_do_insert(btree, path, level, keyp, ptrp);
}
-static void nilfs_btree_carry_right(struct nilfs_btree *btree,
+static void nilfs_btree_carry_right(struct nilfs_bmap *btree,
struct nilfs_btree_path *path,
int level, __u64 *keyp, __u64 *ptrp)
{
struct nilfs_btree_node *node, *right;
- int nchildren, rnchildren, n, move;
+ int nchildren, rnchildren, n, move, ncblk;
node = nilfs_btree_get_nonroot_node(path, level);
right = nilfs_btree_get_sib_node(path, level);
nchildren = nilfs_btree_node_get_nchildren(node);
rnchildren = nilfs_btree_node_get_nchildren(right);
+ ncblk = nilfs_btree_nchildren_per_block(btree);
move = 0;
n = (nchildren + rnchildren + 1) / 2 - rnchildren;
@@ -725,7 +820,7 @@ static void nilfs_btree_carry_right(struct nilfs_btree *btree,
move = 1;
}
- nilfs_btree_node_move_right(btree, node, right, n);
+ nilfs_btree_node_move_right(node, right, n, ncblk, ncblk);
if (!buffer_dirty(path[level].bp_bh))
nilfs_btnode_mark_dirty(path[level].bp_bh);
@@ -751,18 +846,19 @@ static void nilfs_btree_carry_right(struct nilfs_btree *btree,
nilfs_btree_do_insert(btree, path, level, keyp, ptrp);
}
-static void nilfs_btree_split(struct nilfs_btree *btree,
+static void nilfs_btree_split(struct nilfs_bmap *btree,
struct nilfs_btree_path *path,
int level, __u64 *keyp, __u64 *ptrp)
{
struct nilfs_btree_node *node, *right;
__u64 newkey;
__u64 newptr;
- int nchildren, n, move;
+ int nchildren, n, move, ncblk;
node = nilfs_btree_get_nonroot_node(path, level);
right = nilfs_btree_get_sib_node(path, level);
nchildren = nilfs_btree_node_get_nchildren(node);
+ ncblk = nilfs_btree_nchildren_per_block(btree);
move = 0;
n = (nchildren + 1) / 2;
@@ -771,7 +867,7 @@ static void nilfs_btree_split(struct nilfs_btree *btree,
move = 1;
}
- nilfs_btree_node_move_right(btree, node, right, n);
+ nilfs_btree_node_move_right(node, right, n, ncblk, ncblk);
if (!buffer_dirty(path[level].bp_bh))
nilfs_btnode_mark_dirty(path[level].bp_bh);
@@ -783,8 +879,8 @@ static void nilfs_btree_split(struct nilfs_btree *btree,
if (move) {
path[level].bp_index -= nilfs_btree_node_get_nchildren(node);
- nilfs_btree_node_insert(btree, right, *keyp, *ptrp,
- path[level].bp_index);
+ nilfs_btree_node_insert(right, path[level].bp_index,
+ *keyp, *ptrp, ncblk);
*keyp = nilfs_btree_node_get_key(right, 0);
*ptrp = path[level].bp_newreq.bpr_ptr;
@@ -805,19 +901,21 @@ static void nilfs_btree_split(struct nilfs_btree *btree,
path[level + 1].bp_index++;
}
-static void nilfs_btree_grow(struct nilfs_btree *btree,
+static void nilfs_btree_grow(struct nilfs_bmap *btree,
struct nilfs_btree_path *path,
int level, __u64 *keyp, __u64 *ptrp)
{
struct nilfs_btree_node *root, *child;
- int n;
+ int n, ncblk;
root = nilfs_btree_get_root(btree);
child = nilfs_btree_get_sib_node(path, level);
+ ncblk = nilfs_btree_nchildren_per_block(btree);
n = nilfs_btree_node_get_nchildren(root);
- nilfs_btree_node_move_right(btree, root, child, n);
+ nilfs_btree_node_move_right(root, child, n,
+ NILFS_BTREE_ROOT_NCHILDREN_MAX, ncblk);
nilfs_btree_node_set_level(root, level + 1);
if (!buffer_dirty(path[level].bp_sib_bh))
@@ -832,11 +930,11 @@ static void nilfs_btree_grow(struct nilfs_btree *btree,
*ptrp = path[level].bp_newreq.bpr_ptr;
}
-static __u64 nilfs_btree_find_near(const struct nilfs_btree *btree,
+static __u64 nilfs_btree_find_near(const struct nilfs_bmap *btree,
const struct nilfs_btree_path *path)
{
struct nilfs_btree_node *node;
- int level;
+ int level, ncmax;
if (path == NULL)
return NILFS_BMAP_INVALID_PTR;
@@ -844,29 +942,30 @@ static __u64 nilfs_btree_find_near(const struct nilfs_btree *btree,
/* left sibling */
level = NILFS_BTREE_LEVEL_NODE_MIN;
if (path[level].bp_index > 0) {
- node = nilfs_btree_get_node(btree, path, level);
- return nilfs_btree_node_get_ptr(btree, node,
- path[level].bp_index - 1);
+ node = nilfs_btree_get_node(btree, path, level, &ncmax);
+ return nilfs_btree_node_get_ptr(node,
+ path[level].bp_index - 1,
+ ncmax);
}
/* parent */
level = NILFS_BTREE_LEVEL_NODE_MIN + 1;
if (level <= nilfs_btree_height(btree) - 1) {
- node = nilfs_btree_get_node(btree, path, level);
- return nilfs_btree_node_get_ptr(btree, node,
- path[level].bp_index);
+ node = nilfs_btree_get_node(btree, path, level, &ncmax);
+ return nilfs_btree_node_get_ptr(node, path[level].bp_index,
+ ncmax);
}
return NILFS_BMAP_INVALID_PTR;
}
-static __u64 nilfs_btree_find_target_v(const struct nilfs_btree *btree,
+static __u64 nilfs_btree_find_target_v(const struct nilfs_bmap *btree,
const struct nilfs_btree_path *path,
__u64 key)
{
__u64 ptr;
- ptr = nilfs_bmap_find_target_seq(&btree->bt_bmap, key);
+ ptr = nilfs_bmap_find_target_seq(btree, key);
if (ptr != NILFS_BMAP_INVALID_PTR)
/* sequential access */
return ptr;
@@ -877,17 +976,10 @@ static __u64 nilfs_btree_find_target_v(const struct nilfs_btree *btree,
return ptr;
}
/* block group */
- return nilfs_bmap_find_target_in_group(&btree->bt_bmap);
-}
-
-static void nilfs_btree_set_target_v(struct nilfs_btree *btree, __u64 key,
- __u64 ptr)
-{
- btree->bt_bmap.b_last_allocated_key = key;
- btree->bt_bmap.b_last_allocated_ptr = ptr;
+ return nilfs_bmap_find_target_in_group(btree);
}
-static int nilfs_btree_prepare_insert(struct nilfs_btree *btree,
+static int nilfs_btree_prepare_insert(struct nilfs_bmap *btree,
struct nilfs_btree_path *path,
int *levelp, __u64 key, __u64 ptr,
struct nilfs_bmap_stats *stats)
@@ -895,79 +987,78 @@ static int nilfs_btree_prepare_insert(struct nilfs_btree *btree,
struct buffer_head *bh;
struct nilfs_btree_node *node, *parent, *sib;
__u64 sibptr;
- int pindex, level, ret;
+ int pindex, level, ncmax, ncblk, ret;
struct inode *dat = NULL;
stats->bs_nblocks = 0;
level = NILFS_BTREE_LEVEL_DATA;
/* allocate a new ptr for data block */
- if (NILFS_BMAP_USE_VBN(&btree->bt_bmap)) {
+ if (NILFS_BMAP_USE_VBN(btree)) {
path[level].bp_newreq.bpr_ptr =
nilfs_btree_find_target_v(btree, path, key);
- dat = nilfs_bmap_get_dat(&btree->bt_bmap);
+ dat = nilfs_bmap_get_dat(btree);
}
- ret = nilfs_bmap_prepare_alloc_ptr(&btree->bt_bmap,
- &path[level].bp_newreq, dat);
+ ret = nilfs_bmap_prepare_alloc_ptr(btree, &path[level].bp_newreq, dat);
if (ret < 0)
goto err_out_data;
+ ncblk = nilfs_btree_nchildren_per_block(btree);
+
for (level = NILFS_BTREE_LEVEL_NODE_MIN;
level < nilfs_btree_height(btree) - 1;
level++) {
node = nilfs_btree_get_nonroot_node(path, level);
- if (nilfs_btree_node_get_nchildren(node) <
- nilfs_btree_node_nchildren_max(node, btree)) {
+ if (nilfs_btree_node_get_nchildren(node) < ncblk) {
path[level].bp_op = nilfs_btree_do_insert;
stats->bs_nblocks++;
goto out;
}
- parent = nilfs_btree_get_node(btree, path, level + 1);
+ parent = nilfs_btree_get_node(btree, path, level + 1, &ncmax);
pindex = path[level + 1].bp_index;
/* left sibling */
if (pindex > 0) {
- sibptr = nilfs_btree_node_get_ptr(btree, parent,
- pindex - 1);
+ sibptr = nilfs_btree_node_get_ptr(parent, pindex - 1,
+ ncmax);
ret = nilfs_btree_get_block(btree, sibptr, &bh);
if (ret < 0)
goto err_out_child_node;
sib = (struct nilfs_btree_node *)bh->b_data;
- if (nilfs_btree_node_get_nchildren(sib) <
- nilfs_btree_node_nchildren_max(sib, btree)) {
+ if (nilfs_btree_node_get_nchildren(sib) < ncblk) {
path[level].bp_sib_bh = bh;
path[level].bp_op = nilfs_btree_carry_left;
stats->bs_nblocks++;
goto out;
- } else
+ } else {
brelse(bh);
+ }
}
/* right sibling */
- if (pindex <
- nilfs_btree_node_get_nchildren(parent) - 1) {
- sibptr = nilfs_btree_node_get_ptr(btree, parent,
- pindex + 1);
+ if (pindex < nilfs_btree_node_get_nchildren(parent) - 1) {
+ sibptr = nilfs_btree_node_get_ptr(parent, pindex + 1,
+ ncmax);
ret = nilfs_btree_get_block(btree, sibptr, &bh);
if (ret < 0)
goto err_out_child_node;
sib = (struct nilfs_btree_node *)bh->b_data;
- if (nilfs_btree_node_get_nchildren(sib) <
- nilfs_btree_node_nchildren_max(sib, btree)) {
+ if (nilfs_btree_node_get_nchildren(sib) < ncblk) {
path[level].bp_sib_bh = bh;
path[level].bp_op = nilfs_btree_carry_right;
stats->bs_nblocks++;
goto out;
- } else
+ } else {
brelse(bh);
+ }
}
/* split */
path[level].bp_newreq.bpr_ptr =
path[level - 1].bp_newreq.bpr_ptr + 1;
- ret = nilfs_bmap_prepare_alloc_ptr(&btree->bt_bmap,
+ ret = nilfs_bmap_prepare_alloc_ptr(btree,
&path[level].bp_newreq, dat);
if (ret < 0)
goto err_out_child_node;
@@ -979,9 +1070,8 @@ static int nilfs_btree_prepare_insert(struct nilfs_btree *btree,
stats->bs_nblocks++;
- nilfs_btree_node_init(btree,
- (struct nilfs_btree_node *)bh->b_data,
- 0, level, 0, NULL, NULL);
+ sib = (struct nilfs_btree_node *)bh->b_data;
+ nilfs_btree_node_init(sib, 0, level, 0, ncblk, NULL, NULL);
path[level].bp_sib_bh = bh;
path[level].bp_op = nilfs_btree_split;
}
@@ -989,7 +1079,7 @@ static int nilfs_btree_prepare_insert(struct nilfs_btree *btree,
/* root */
node = nilfs_btree_get_root(btree);
if (nilfs_btree_node_get_nchildren(node) <
- nilfs_btree_node_nchildren_max(node, btree)) {
+ NILFS_BTREE_ROOT_NCHILDREN_MAX) {
path[level].bp_op = nilfs_btree_do_insert;
stats->bs_nblocks++;
goto out;
@@ -997,8 +1087,7 @@ static int nilfs_btree_prepare_insert(struct nilfs_btree *btree,
/* grow */
path[level].bp_newreq.bpr_ptr = path[level - 1].bp_newreq.bpr_ptr + 1;
- ret = nilfs_bmap_prepare_alloc_ptr(&btree->bt_bmap,
- &path[level].bp_newreq, dat);
+ ret = nilfs_bmap_prepare_alloc_ptr(btree, &path[level].bp_newreq, dat);
if (ret < 0)
goto err_out_child_node;
ret = nilfs_btree_get_new_block(btree, path[level].bp_newreq.bpr_ptr,
@@ -1006,8 +1095,8 @@ static int nilfs_btree_prepare_insert(struct nilfs_btree *btree,
if (ret < 0)
goto err_out_curr_node;
- nilfs_btree_node_init(btree, (struct nilfs_btree_node *)bh->b_data,
- 0, level, 0, NULL, NULL);
+ nilfs_btree_node_init((struct nilfs_btree_node *)bh->b_data,
+ 0, level, 0, ncblk, NULL, NULL);
path[level].bp_sib_bh = bh;
path[level].bp_op = nilfs_btree_grow;
@@ -1024,25 +1113,22 @@ static int nilfs_btree_prepare_insert(struct nilfs_btree *btree,
/* error */
err_out_curr_node:
- nilfs_bmap_abort_alloc_ptr(&btree->bt_bmap, &path[level].bp_newreq,
- dat);
+ nilfs_bmap_abort_alloc_ptr(btree, &path[level].bp_newreq, dat);
err_out_child_node:
for (level--; level > NILFS_BTREE_LEVEL_DATA; level--) {
nilfs_btnode_delete(path[level].bp_sib_bh);
- nilfs_bmap_abort_alloc_ptr(&btree->bt_bmap,
- &path[level].bp_newreq, dat);
+ nilfs_bmap_abort_alloc_ptr(btree, &path[level].bp_newreq, dat);
}
- nilfs_bmap_abort_alloc_ptr(&btree->bt_bmap, &path[level].bp_newreq,
- dat);
+ nilfs_bmap_abort_alloc_ptr(btree, &path[level].bp_newreq, dat);
err_out_data:
*levelp = level;
stats->bs_nblocks = 0;
return ret;
}
-static void nilfs_btree_commit_insert(struct nilfs_btree *btree,
+static void nilfs_btree_commit_insert(struct nilfs_bmap *btree,
struct nilfs_btree_path *path,
int maxlevel, __u64 key, __u64 ptr)
{
@@ -1051,35 +1137,33 @@ static void nilfs_btree_commit_insert(struct nilfs_btree *btree,
set_buffer_nilfs_volatile((struct buffer_head *)((unsigned long)ptr));
ptr = path[NILFS_BTREE_LEVEL_DATA].bp_newreq.bpr_ptr;
- if (NILFS_BMAP_USE_VBN(&btree->bt_bmap)) {
- nilfs_btree_set_target_v(btree, key, ptr);
- dat = nilfs_bmap_get_dat(&btree->bt_bmap);
+ if (NILFS_BMAP_USE_VBN(btree)) {
+ nilfs_bmap_set_target_v(btree, key, ptr);
+ dat = nilfs_bmap_get_dat(btree);
}
for (level = NILFS_BTREE_LEVEL_NODE_MIN; level <= maxlevel; level++) {
- nilfs_bmap_commit_alloc_ptr(&btree->bt_bmap,
+ nilfs_bmap_commit_alloc_ptr(btree,
&path[level - 1].bp_newreq, dat);
path[level].bp_op(btree, path, level, &key, &ptr);
}
- if (!nilfs_bmap_dirty(&btree->bt_bmap))
- nilfs_bmap_set_dirty(&btree->bt_bmap);
+ if (!nilfs_bmap_dirty(btree))
+ nilfs_bmap_set_dirty(btree);
}
-static int nilfs_btree_insert(struct nilfs_bmap *bmap, __u64 key, __u64 ptr)
+static int nilfs_btree_insert(struct nilfs_bmap *btree, __u64 key, __u64 ptr)
{
- struct nilfs_btree *btree;
struct nilfs_btree_path *path;
struct nilfs_bmap_stats stats;
int level, ret;
- btree = (struct nilfs_btree *)bmap;
path = nilfs_btree_alloc_path();
if (path == NULL)
return -ENOMEM;
ret = nilfs_btree_do_lookup(btree, path, key, NULL,
- NILFS_BTREE_LEVEL_NODE_MIN);
+ NILFS_BTREE_LEVEL_NODE_MIN, 0);
if (ret != -ENOENT) {
if (ret == 0)
ret = -EEXIST;
@@ -1090,23 +1174,25 @@ static int nilfs_btree_insert(struct nilfs_bmap *bmap, __u64 key, __u64 ptr)
if (ret < 0)
goto out;
nilfs_btree_commit_insert(btree, path, level, key, ptr);
- nilfs_bmap_add_blocks(bmap, stats.bs_nblocks);
+ nilfs_bmap_add_blocks(btree, stats.bs_nblocks);
out:
nilfs_btree_free_path(path);
return ret;
}
-static void nilfs_btree_do_delete(struct nilfs_btree *btree,
+static void nilfs_btree_do_delete(struct nilfs_bmap *btree,
struct nilfs_btree_path *path,
int level, __u64 *keyp, __u64 *ptrp)
{
struct nilfs_btree_node *node;
+ int ncblk;
if (level < nilfs_btree_height(btree) - 1) {
node = nilfs_btree_get_nonroot_node(path, level);
- nilfs_btree_node_delete(btree, node, keyp, ptrp,
- path[level].bp_index);
+ ncblk = nilfs_btree_nchildren_per_block(btree);
+ nilfs_btree_node_delete(node, path[level].bp_index,
+ keyp, ptrp, ncblk);
if (!buffer_dirty(path[level].bp_bh))
nilfs_btnode_mark_dirty(path[level].bp_bh);
if (path[level].bp_index == 0)
@@ -1114,17 +1200,18 @@ static void nilfs_btree_do_delete(struct nilfs_btree *btree,
nilfs_btree_node_get_key(node, 0));
} else {
node = nilfs_btree_get_root(btree);
- nilfs_btree_node_delete(btree, node, keyp, ptrp,
- path[level].bp_index);
+ nilfs_btree_node_delete(node, path[level].bp_index,
+ keyp, ptrp,
+ NILFS_BTREE_ROOT_NCHILDREN_MAX);
}
}
-static void nilfs_btree_borrow_left(struct nilfs_btree *btree,
+static void nilfs_btree_borrow_left(struct nilfs_bmap *btree,
struct nilfs_btree_path *path,
int level, __u64 *keyp, __u64 *ptrp)
{
struct nilfs_btree_node *node, *left;
- int nchildren, lnchildren, n;
+ int nchildren, lnchildren, n, ncblk;
nilfs_btree_do_delete(btree, path, level, keyp, ptrp);
@@ -1132,10 +1219,11 @@ static void nilfs_btree_borrow_left(struct nilfs_btree *btree,
left = nilfs_btree_get_sib_node(path, level);
nchildren = nilfs_btree_node_get_nchildren(node);
lnchildren = nilfs_btree_node_get_nchildren(left);
+ ncblk = nilfs_btree_nchildren_per_block(btree);
n = (nchildren + lnchildren) / 2 - nchildren;
- nilfs_btree_node_move_right(btree, left, node, n);
+ nilfs_btree_node_move_right(left, node, n, ncblk, ncblk);
if (!buffer_dirty(path[level].bp_bh))
nilfs_btnode_mark_dirty(path[level].bp_bh);
@@ -1150,12 +1238,12 @@ static void nilfs_btree_borrow_left(struct nilfs_btree *btree,
path[level].bp_index += n;
}
-static void nilfs_btree_borrow_right(struct nilfs_btree *btree,
+static void nilfs_btree_borrow_right(struct nilfs_bmap *btree,
struct nilfs_btree_path *path,
int level, __u64 *keyp, __u64 *ptrp)
{
struct nilfs_btree_node *node, *right;
- int nchildren, rnchildren, n;
+ int nchildren, rnchildren, n, ncblk;
nilfs_btree_do_delete(btree, path, level, keyp, ptrp);
@@ -1163,10 +1251,11 @@ static void nilfs_btree_borrow_right(struct nilfs_btree *btree,
right = nilfs_btree_get_sib_node(path, level);
nchildren = nilfs_btree_node_get_nchildren(node);
rnchildren = nilfs_btree_node_get_nchildren(right);
+ ncblk = nilfs_btree_nchildren_per_block(btree);
n = (nchildren + rnchildren) / 2 - nchildren;
- nilfs_btree_node_move_left(btree, node, right, n);
+ nilfs_btree_node_move_left(node, right, n, ncblk, ncblk);
if (!buffer_dirty(path[level].bp_bh))
nilfs_btnode_mark_dirty(path[level].bp_bh);
@@ -1182,21 +1271,22 @@ static void nilfs_btree_borrow_right(struct nilfs_btree *btree,
path[level].bp_sib_bh = NULL;
}
-static void nilfs_btree_concat_left(struct nilfs_btree *btree,
+static void nilfs_btree_concat_left(struct nilfs_bmap *btree,
struct nilfs_btree_path *path,
int level, __u64 *keyp, __u64 *ptrp)
{
struct nilfs_btree_node *node, *left;
- int n;
+ int n, ncblk;
nilfs_btree_do_delete(btree, path, level, keyp, ptrp);
node = nilfs_btree_get_nonroot_node(path, level);
left = nilfs_btree_get_sib_node(path, level);
+ ncblk = nilfs_btree_nchildren_per_block(btree);
n = nilfs_btree_node_get_nchildren(node);
- nilfs_btree_node_move_left(btree, left, node, n);
+ nilfs_btree_node_move_left(left, node, n, ncblk, ncblk);
if (!buffer_dirty(path[level].bp_sib_bh))
nilfs_btnode_mark_dirty(path[level].bp_sib_bh);
@@ -1207,21 +1297,22 @@ static void nilfs_btree_concat_left(struct nilfs_btree *btree,
path[level].bp_index += nilfs_btree_node_get_nchildren(left);
}
-static void nilfs_btree_concat_right(struct nilfs_btree *btree,
+static void nilfs_btree_concat_right(struct nilfs_bmap *btree,
struct nilfs_btree_path *path,
int level, __u64 *keyp, __u64 *ptrp)
{
struct nilfs_btree_node *node, *right;
- int n;
+ int n, ncblk;
nilfs_btree_do_delete(btree, path, level, keyp, ptrp);
node = nilfs_btree_get_nonroot_node(path, level);
right = nilfs_btree_get_sib_node(path, level);
+ ncblk = nilfs_btree_nchildren_per_block(btree);
n = nilfs_btree_node_get_nchildren(right);
- nilfs_btree_node_move_left(btree, node, right, n);
+ nilfs_btree_node_move_left(node, right, n, ncblk, ncblk);
if (!buffer_dirty(path[level].bp_bh))
nilfs_btnode_mark_dirty(path[level].bp_bh);
@@ -1231,29 +1322,32 @@ static void nilfs_btree_concat_right(struct nilfs_btree *btree,
path[level + 1].bp_index++;
}
-static void nilfs_btree_shrink(struct nilfs_btree *btree,
+static void nilfs_btree_shrink(struct nilfs_bmap *btree,
struct nilfs_btree_path *path,
int level, __u64 *keyp, __u64 *ptrp)
{
struct nilfs_btree_node *root, *child;
- int n;
+ int n, ncblk;
nilfs_btree_do_delete(btree, path, level, keyp, ptrp);
root = nilfs_btree_get_root(btree);
child = nilfs_btree_get_nonroot_node(path, level);
+ ncblk = nilfs_btree_nchildren_per_block(btree);
- nilfs_btree_node_delete(btree, root, NULL, NULL, 0);
+ nilfs_btree_node_delete(root, 0, NULL, NULL,
+ NILFS_BTREE_ROOT_NCHILDREN_MAX);
nilfs_btree_node_set_level(root, level);
n = nilfs_btree_node_get_nchildren(child);
- nilfs_btree_node_move_left(btree, root, child, n);
+ nilfs_btree_node_move_left(root, child, n,
+ NILFS_BTREE_ROOT_NCHILDREN_MAX, ncblk);
nilfs_btnode_delete(path[level].bp_bh);
path[level].bp_bh = NULL;
}
-static int nilfs_btree_prepare_delete(struct nilfs_btree *btree,
+static int nilfs_btree_prepare_delete(struct nilfs_bmap *btree,
struct nilfs_btree_path *path,
int *levelp,
struct nilfs_bmap_stats *stats,
@@ -1262,42 +1356,43 @@ static int nilfs_btree_prepare_delete(struct nilfs_btree *btree,
struct buffer_head *bh;
struct nilfs_btree_node *node, *parent, *sib;
__u64 sibptr;
- int pindex, level, ret;
+ int pindex, level, ncmin, ncmax, ncblk, ret;
ret = 0;
stats->bs_nblocks = 0;
+ ncmin = NILFS_BTREE_NODE_NCHILDREN_MIN(nilfs_btree_node_size(btree));
+ ncblk = nilfs_btree_nchildren_per_block(btree);
+
for (level = NILFS_BTREE_LEVEL_NODE_MIN;
level < nilfs_btree_height(btree) - 1;
level++) {
node = nilfs_btree_get_nonroot_node(path, level);
path[level].bp_oldreq.bpr_ptr =
- nilfs_btree_node_get_ptr(btree, node,
- path[level].bp_index);
- ret = nilfs_bmap_prepare_end_ptr(&btree->bt_bmap,
+ nilfs_btree_node_get_ptr(node, path[level].bp_index,
+ ncblk);
+ ret = nilfs_bmap_prepare_end_ptr(btree,
&path[level].bp_oldreq, dat);
if (ret < 0)
goto err_out_child_node;
- if (nilfs_btree_node_get_nchildren(node) >
- nilfs_btree_node_nchildren_min(node, btree)) {
+ if (nilfs_btree_node_get_nchildren(node) > ncmin) {
path[level].bp_op = nilfs_btree_do_delete;
stats->bs_nblocks++;
goto out;
}
- parent = nilfs_btree_get_node(btree, path, level + 1);
+ parent = nilfs_btree_get_node(btree, path, level + 1, &ncmax);
pindex = path[level + 1].bp_index;
if (pindex > 0) {
/* left sibling */
- sibptr = nilfs_btree_node_get_ptr(btree, parent,
- pindex - 1);
+ sibptr = nilfs_btree_node_get_ptr(parent, pindex - 1,
+ ncmax);
ret = nilfs_btree_get_block(btree, sibptr, &bh);
if (ret < 0)
goto err_out_curr_node;
sib = (struct nilfs_btree_node *)bh->b_data;
- if (nilfs_btree_node_get_nchildren(sib) >
- nilfs_btree_node_nchildren_min(sib, btree)) {
+ if (nilfs_btree_node_get_nchildren(sib) > ncmin) {
path[level].bp_sib_bh = bh;
path[level].bp_op = nilfs_btree_borrow_left;
stats->bs_nblocks++;
@@ -1311,14 +1406,13 @@ static int nilfs_btree_prepare_delete(struct nilfs_btree *btree,
} else if (pindex <
nilfs_btree_node_get_nchildren(parent) - 1) {
/* right sibling */
- sibptr = nilfs_btree_node_get_ptr(btree, parent,
- pindex + 1);
+ sibptr = nilfs_btree_node_get_ptr(parent, pindex + 1,
+ ncmax);
ret = nilfs_btree_get_block(btree, sibptr, &bh);
if (ret < 0)
goto err_out_curr_node;
sib = (struct nilfs_btree_node *)bh->b_data;
- if (nilfs_btree_node_get_nchildren(sib) >
- nilfs_btree_node_nchildren_min(sib, btree)) {
+ if (nilfs_btree_node_get_nchildren(sib) > ncmin) {
path[level].bp_sib_bh = bh;
path[level].bp_op = nilfs_btree_borrow_right;
stats->bs_nblocks++;
@@ -1349,10 +1443,10 @@ static int nilfs_btree_prepare_delete(struct nilfs_btree *btree,
node = nilfs_btree_get_root(btree);
path[level].bp_oldreq.bpr_ptr =
- nilfs_btree_node_get_ptr(btree, node, path[level].bp_index);
+ nilfs_btree_node_get_ptr(node, path[level].bp_index,
+ NILFS_BTREE_ROOT_NCHILDREN_MAX);
- ret = nilfs_bmap_prepare_end_ptr(&btree->bt_bmap,
- &path[level].bp_oldreq, dat);
+ ret = nilfs_bmap_prepare_end_ptr(btree, &path[level].bp_oldreq, dat);
if (ret < 0)
goto err_out_child_node;
@@ -1367,75 +1461,68 @@ static int nilfs_btree_prepare_delete(struct nilfs_btree *btree,
/* error */
err_out_curr_node:
- nilfs_bmap_abort_end_ptr(&btree->bt_bmap, &path[level].bp_oldreq, dat);
+ nilfs_bmap_abort_end_ptr(btree, &path[level].bp_oldreq, dat);
err_out_child_node:
for (level--; level >= NILFS_BTREE_LEVEL_NODE_MIN; level--) {
brelse(path[level].bp_sib_bh);
- nilfs_bmap_abort_end_ptr(&btree->bt_bmap,
- &path[level].bp_oldreq, dat);
+ nilfs_bmap_abort_end_ptr(btree, &path[level].bp_oldreq, dat);
}
*levelp = level;
stats->bs_nblocks = 0;
return ret;
}
-static void nilfs_btree_commit_delete(struct nilfs_btree *btree,
+static void nilfs_btree_commit_delete(struct nilfs_bmap *btree,
struct nilfs_btree_path *path,
int maxlevel, struct inode *dat)
{
int level;
for (level = NILFS_BTREE_LEVEL_NODE_MIN; level <= maxlevel; level++) {
- nilfs_bmap_commit_end_ptr(&btree->bt_bmap,
- &path[level].bp_oldreq, dat);
+ nilfs_bmap_commit_end_ptr(btree, &path[level].bp_oldreq, dat);
path[level].bp_op(btree, path, level, NULL, NULL);
}
- if (!nilfs_bmap_dirty(&btree->bt_bmap))
- nilfs_bmap_set_dirty(&btree->bt_bmap);
+ if (!nilfs_bmap_dirty(btree))
+ nilfs_bmap_set_dirty(btree);
}
-static int nilfs_btree_delete(struct nilfs_bmap *bmap, __u64 key)
+static int nilfs_btree_delete(struct nilfs_bmap *btree, __u64 key)
{
- struct nilfs_btree *btree;
struct nilfs_btree_path *path;
struct nilfs_bmap_stats stats;
struct inode *dat;
int level, ret;
- btree = (struct nilfs_btree *)bmap;
path = nilfs_btree_alloc_path();
if (path == NULL)
return -ENOMEM;
ret = nilfs_btree_do_lookup(btree, path, key, NULL,
- NILFS_BTREE_LEVEL_NODE_MIN);
+ NILFS_BTREE_LEVEL_NODE_MIN, 0);
if (ret < 0)
goto out;
- dat = NILFS_BMAP_USE_VBN(&btree->bt_bmap) ?
- nilfs_bmap_get_dat(&btree->bt_bmap) : NULL;
+ dat = NILFS_BMAP_USE_VBN(btree) ? nilfs_bmap_get_dat(btree) : NULL;
ret = nilfs_btree_prepare_delete(btree, path, &level, &stats, dat);
if (ret < 0)
goto out;
nilfs_btree_commit_delete(btree, path, level, dat);
- nilfs_bmap_sub_blocks(bmap, stats.bs_nblocks);
+ nilfs_bmap_sub_blocks(btree, stats.bs_nblocks);
out:
nilfs_btree_free_path(path);
return ret;
}
-static int nilfs_btree_last_key(const struct nilfs_bmap *bmap, __u64 *keyp)
+static int nilfs_btree_last_key(const struct nilfs_bmap *btree, __u64 *keyp)
{
- struct nilfs_btree *btree;
struct nilfs_btree_path *path;
int ret;
- btree = (struct nilfs_btree *)bmap;
path = nilfs_btree_alloc_path();
if (path == NULL)
return -ENOMEM;
@@ -1447,16 +1534,14 @@ static int nilfs_btree_last_key(const struct nilfs_bmap *bmap, __u64 *keyp)
return ret;
}
-static int nilfs_btree_check_delete(struct nilfs_bmap *bmap, __u64 key)
+static int nilfs_btree_check_delete(struct nilfs_bmap *btree, __u64 key)
{
struct buffer_head *bh;
- struct nilfs_btree *btree;
struct nilfs_btree_node *root, *node;
__u64 maxkey, nextmaxkey;
__u64 ptr;
int nchildren, ret;
- btree = (struct nilfs_btree *)bmap;
root = nilfs_btree_get_root(btree);
switch (nilfs_btree_height(btree)) {
case 2:
@@ -1467,7 +1552,8 @@ static int nilfs_btree_check_delete(struct nilfs_bmap *bmap, __u64 key)
nchildren = nilfs_btree_node_get_nchildren(root);
if (nchildren > 1)
return 0;
- ptr = nilfs_btree_node_get_ptr(btree, root, nchildren - 1);
+ ptr = nilfs_btree_node_get_ptr(root, nchildren - 1,
+ NILFS_BTREE_ROOT_NCHILDREN_MAX);
ret = nilfs_btree_get_block(btree, ptr, &bh);
if (ret < 0)
return ret;
@@ -1487,32 +1573,33 @@ static int nilfs_btree_check_delete(struct nilfs_bmap *bmap, __u64 key)
return (maxkey == key) && (nextmaxkey < NILFS_BMAP_LARGE_LOW);
}
-static int nilfs_btree_gather_data(struct nilfs_bmap *bmap,
+static int nilfs_btree_gather_data(struct nilfs_bmap *btree,
__u64 *keys, __u64 *ptrs, int nitems)
{
struct buffer_head *bh;
- struct nilfs_btree *btree;
struct nilfs_btree_node *node, *root;
__le64 *dkeys;
__le64 *dptrs;
__u64 ptr;
- int nchildren, i, ret;
+ int nchildren, ncmax, i, ret;
- btree = (struct nilfs_btree *)bmap;
root = nilfs_btree_get_root(btree);
switch (nilfs_btree_height(btree)) {
case 2:
bh = NULL;
node = root;
+ ncmax = NILFS_BTREE_ROOT_NCHILDREN_MAX;
break;
case 3:
nchildren = nilfs_btree_node_get_nchildren(root);
WARN_ON(nchildren > 1);
- ptr = nilfs_btree_node_get_ptr(btree, root, nchildren - 1);
+ ptr = nilfs_btree_node_get_ptr(root, nchildren - 1,
+ NILFS_BTREE_ROOT_NCHILDREN_MAX);
ret = nilfs_btree_get_block(btree, ptr, &bh);
if (ret < 0)
return ret;
node = (struct nilfs_btree_node *)bh->b_data;
+ ncmax = nilfs_btree_nchildren_per_block(btree);
break;
default:
node = NULL;
@@ -1523,10 +1610,10 @@ static int nilfs_btree_gather_data(struct nilfs_bmap *bmap,
if (nchildren < nitems)
nitems = nchildren;
dkeys = nilfs_btree_node_dkeys(node);
- dptrs = nilfs_btree_node_dptrs(node, btree);
+ dptrs = nilfs_btree_node_dptrs(node, ncmax);
for (i = 0; i < nitems; i++) {
- keys[i] = nilfs_bmap_dkey_to_key(dkeys[i]);
- ptrs[i] = nilfs_bmap_dptr_to_ptr(dptrs[i]);
+ keys[i] = le64_to_cpu(dkeys[i]);
+ ptrs[i] = le64_to_cpu(dptrs[i]);
}
if (bh != NULL)
@@ -1536,14 +1623,13 @@ static int nilfs_btree_gather_data(struct nilfs_bmap *bmap,
}
static int
-nilfs_btree_prepare_convert_and_insert(struct nilfs_bmap *bmap, __u64 key,
+nilfs_btree_prepare_convert_and_insert(struct nilfs_bmap *btree, __u64 key,
union nilfs_bmap_ptr_req *dreq,
union nilfs_bmap_ptr_req *nreq,
struct buffer_head **bhp,
struct nilfs_bmap_stats *stats)
{
struct buffer_head *bh;
- struct nilfs_btree *btree = (struct nilfs_btree *)bmap;
struct inode *dat = NULL;
int ret;
@@ -1551,12 +1637,12 @@ nilfs_btree_prepare_convert_and_insert(struct nilfs_bmap *bmap, __u64 key,
/* for data */
/* cannot find near ptr */
- if (NILFS_BMAP_USE_VBN(bmap)) {
+ if (NILFS_BMAP_USE_VBN(btree)) {
dreq->bpr_ptr = nilfs_btree_find_target_v(btree, NULL, key);
- dat = nilfs_bmap_get_dat(bmap);
+ dat = nilfs_bmap_get_dat(btree);
}
- ret = nilfs_bmap_prepare_alloc_ptr(bmap, dreq, dat);
+ ret = nilfs_bmap_prepare_alloc_ptr(btree, dreq, dat);
if (ret < 0)
return ret;
@@ -1564,7 +1650,7 @@ nilfs_btree_prepare_convert_and_insert(struct nilfs_bmap *bmap, __u64 key,
stats->bs_nblocks++;
if (nreq != NULL) {
nreq->bpr_ptr = dreq->bpr_ptr + 1;
- ret = nilfs_bmap_prepare_alloc_ptr(bmap, nreq, dat);
+ ret = nilfs_bmap_prepare_alloc_ptr(btree, nreq, dat);
if (ret < 0)
goto err_out_dreq;
@@ -1581,16 +1667,16 @@ nilfs_btree_prepare_convert_and_insert(struct nilfs_bmap *bmap, __u64 key,
/* error */
err_out_nreq:
- nilfs_bmap_abort_alloc_ptr(bmap, nreq, dat);
+ nilfs_bmap_abort_alloc_ptr(btree, nreq, dat);
err_out_dreq:
- nilfs_bmap_abort_alloc_ptr(bmap, dreq, dat);
+ nilfs_bmap_abort_alloc_ptr(btree, dreq, dat);
stats->bs_nblocks = 0;
return ret;
}
static void
-nilfs_btree_commit_convert_and_insert(struct nilfs_bmap *bmap,
+nilfs_btree_commit_convert_and_insert(struct nilfs_bmap *btree,
__u64 key, __u64 ptr,
const __u64 *keys, const __u64 *ptrs,
int n,
@@ -1598,57 +1684,59 @@ nilfs_btree_commit_convert_and_insert(struct nilfs_bmap *bmap,
union nilfs_bmap_ptr_req *nreq,
struct buffer_head *bh)
{
- struct nilfs_btree *btree = (struct nilfs_btree *)bmap;
struct nilfs_btree_node *node;
struct inode *dat;
__u64 tmpptr;
+ int ncblk;
/* free resources */
- if (bmap->b_ops->bop_clear != NULL)
- bmap->b_ops->bop_clear(bmap);
+ if (btree->b_ops->bop_clear != NULL)
+ btree->b_ops->bop_clear(btree);
/* ptr must be a pointer to a buffer head. */
set_buffer_nilfs_volatile((struct buffer_head *)((unsigned long)ptr));
/* convert and insert */
- dat = NILFS_BMAP_USE_VBN(bmap) ? nilfs_bmap_get_dat(bmap) : NULL;
- nilfs_btree_init(bmap);
+ dat = NILFS_BMAP_USE_VBN(btree) ? nilfs_bmap_get_dat(btree) : NULL;
+ nilfs_btree_init(btree);
if (nreq != NULL) {
- nilfs_bmap_commit_alloc_ptr(bmap, dreq, dat);
- nilfs_bmap_commit_alloc_ptr(bmap, nreq, dat);
+ nilfs_bmap_commit_alloc_ptr(btree, dreq, dat);
+ nilfs_bmap_commit_alloc_ptr(btree, nreq, dat);
/* create child node at level 1 */
node = (struct nilfs_btree_node *)bh->b_data;
- nilfs_btree_node_init(btree, node, 0, 1, n, keys, ptrs);
- nilfs_btree_node_insert(btree, node,
- key, dreq->bpr_ptr, n);
+ ncblk = nilfs_btree_nchildren_per_block(btree);
+ nilfs_btree_node_init(node, 0, 1, n, ncblk, keys, ptrs);
+ nilfs_btree_node_insert(node, n, key, dreq->bpr_ptr, ncblk);
if (!buffer_dirty(bh))
nilfs_btnode_mark_dirty(bh);
- if (!nilfs_bmap_dirty(bmap))
- nilfs_bmap_set_dirty(bmap);
+ if (!nilfs_bmap_dirty(btree))
+ nilfs_bmap_set_dirty(btree);
brelse(bh);
/* create root node at level 2 */
node = nilfs_btree_get_root(btree);
tmpptr = nreq->bpr_ptr;
- nilfs_btree_node_init(btree, node, NILFS_BTREE_NODE_ROOT,
- 2, 1, &keys[0], &tmpptr);
+ nilfs_btree_node_init(node, NILFS_BTREE_NODE_ROOT, 2, 1,
+ NILFS_BTREE_ROOT_NCHILDREN_MAX,
+ &keys[0], &tmpptr);
} else {
- nilfs_bmap_commit_alloc_ptr(bmap, dreq, dat);
+ nilfs_bmap_commit_alloc_ptr(btree, dreq, dat);
/* create root node at level 1 */
node = nilfs_btree_get_root(btree);
- nilfs_btree_node_init(btree, node, NILFS_BTREE_NODE_ROOT,
- 1, n, keys, ptrs);
- nilfs_btree_node_insert(btree, node,
- key, dreq->bpr_ptr, n);
- if (!nilfs_bmap_dirty(bmap))
- nilfs_bmap_set_dirty(bmap);
+ nilfs_btree_node_init(node, NILFS_BTREE_NODE_ROOT, 1, n,
+ NILFS_BTREE_ROOT_NCHILDREN_MAX,
+ keys, ptrs);
+ nilfs_btree_node_insert(node, n, key, dreq->bpr_ptr,
+ NILFS_BTREE_ROOT_NCHILDREN_MAX);
+ if (!nilfs_bmap_dirty(btree))
+ nilfs_bmap_set_dirty(btree);
}
- if (NILFS_BMAP_USE_VBN(bmap))
- nilfs_btree_set_target_v(btree, key, dreq->bpr_ptr);
+ if (NILFS_BMAP_USE_VBN(btree))
+ nilfs_bmap_set_target_v(btree, key, dreq->bpr_ptr);
}
/**
@@ -1660,7 +1748,7 @@ nilfs_btree_commit_convert_and_insert(struct nilfs_bmap *bmap,
* @ptrs:
* @n:
*/
-int nilfs_btree_convert_and_insert(struct nilfs_bmap *bmap,
+int nilfs_btree_convert_and_insert(struct nilfs_bmap *btree,
__u64 key, __u64 ptr,
const __u64 *keys, const __u64 *ptrs, int n)
{
@@ -1673,7 +1761,7 @@ int nilfs_btree_convert_and_insert(struct nilfs_bmap *bmap,
di = &dreq;
ni = NULL;
} else if ((n + 1) <= NILFS_BTREE_NODE_NCHILDREN_MAX(
- 1 << bmap->b_inode->i_blkbits)) {
+ 1 << btree->b_inode->i_blkbits)) {
di = &dreq;
ni = &nreq;
} else {
@@ -1682,17 +1770,17 @@ int nilfs_btree_convert_and_insert(struct nilfs_bmap *bmap,
BUG();
}
- ret = nilfs_btree_prepare_convert_and_insert(bmap, key, di, ni, &bh,
+ ret = nilfs_btree_prepare_convert_and_insert(btree, key, di, ni, &bh,
&stats);
if (ret < 0)
return ret;
- nilfs_btree_commit_convert_and_insert(bmap, key, ptr, keys, ptrs, n,
+ nilfs_btree_commit_convert_and_insert(btree, key, ptr, keys, ptrs, n,
di, ni, bh);
- nilfs_bmap_add_blocks(bmap, stats.bs_nblocks);
+ nilfs_bmap_add_blocks(btree, stats.bs_nblocks);
return 0;
}
-static int nilfs_btree_propagate_p(struct nilfs_btree *btree,
+static int nilfs_btree_propagate_p(struct nilfs_bmap *btree,
struct nilfs_btree_path *path,
int level,
struct buffer_head *bh)
@@ -1704,17 +1792,17 @@ static int nilfs_btree_propagate_p(struct nilfs_btree *btree,
return 0;
}
-static int nilfs_btree_prepare_update_v(struct nilfs_btree *btree,
+static int nilfs_btree_prepare_update_v(struct nilfs_bmap *btree,
struct nilfs_btree_path *path,
int level, struct inode *dat)
{
struct nilfs_btree_node *parent;
- int ret;
+ int ncmax, ret;
- parent = nilfs_btree_get_node(btree, path, level + 1);
+ parent = nilfs_btree_get_node(btree, path, level + 1, &ncmax);
path[level].bp_oldreq.bpr_ptr =
- nilfs_btree_node_get_ptr(btree, parent,
- path[level + 1].bp_index);
+ nilfs_btree_node_get_ptr(parent, path[level + 1].bp_index,
+ ncmax);
path[level].bp_newreq.bpr_ptr = path[level].bp_oldreq.bpr_ptr + 1;
ret = nilfs_dat_prepare_update(dat, &path[level].bp_oldreq.bpr_req,
&path[level].bp_newreq.bpr_req);
@@ -1726,7 +1814,7 @@ static int nilfs_btree_prepare_update_v(struct nilfs_btree *btree,
path[level].bp_ctxt.newkey = path[level].bp_newreq.bpr_ptr;
path[level].bp_ctxt.bh = path[level].bp_bh;
ret = nilfs_btnode_prepare_change_key(
- &NILFS_BMAP_I(&btree->bt_bmap)->i_btnode_cache,
+ &NILFS_BMAP_I(btree)->i_btnode_cache,
&path[level].bp_ctxt);
if (ret < 0) {
nilfs_dat_abort_update(dat,
@@ -1739,30 +1827,31 @@ static int nilfs_btree_prepare_update_v(struct nilfs_btree *btree,
return 0;
}
-static void nilfs_btree_commit_update_v(struct nilfs_btree *btree,
+static void nilfs_btree_commit_update_v(struct nilfs_bmap *btree,
struct nilfs_btree_path *path,
int level, struct inode *dat)
{
struct nilfs_btree_node *parent;
+ int ncmax;
nilfs_dat_commit_update(dat, &path[level].bp_oldreq.bpr_req,
&path[level].bp_newreq.bpr_req,
- btree->bt_bmap.b_ptr_type == NILFS_BMAP_PTR_VS);
+ btree->b_ptr_type == NILFS_BMAP_PTR_VS);
if (buffer_nilfs_node(path[level].bp_bh)) {
nilfs_btnode_commit_change_key(
- &NILFS_BMAP_I(&btree->bt_bmap)->i_btnode_cache,
+ &NILFS_BMAP_I(btree)->i_btnode_cache,
&path[level].bp_ctxt);
path[level].bp_bh = path[level].bp_ctxt.bh;
}
set_buffer_nilfs_volatile(path[level].bp_bh);
- parent = nilfs_btree_get_node(btree, path, level + 1);
- nilfs_btree_node_set_ptr(btree, parent, path[level + 1].bp_index,
- path[level].bp_newreq.bpr_ptr);
+ parent = nilfs_btree_get_node(btree, path, level + 1, &ncmax);
+ nilfs_btree_node_set_ptr(parent, path[level + 1].bp_index,
+ path[level].bp_newreq.bpr_ptr, ncmax);
}
-static void nilfs_btree_abort_update_v(struct nilfs_btree *btree,
+static void nilfs_btree_abort_update_v(struct nilfs_bmap *btree,
struct nilfs_btree_path *path,
int level, struct inode *dat)
{
@@ -1770,11 +1859,11 @@ static void nilfs_btree_abort_update_v(struct nilfs_btree *btree,
&path[level].bp_newreq.bpr_req);
if (buffer_nilfs_node(path[level].bp_bh))
nilfs_btnode_abort_change_key(
- &NILFS_BMAP_I(&btree->bt_bmap)->i_btnode_cache,
+ &NILFS_BMAP_I(btree)->i_btnode_cache,
&path[level].bp_ctxt);
}
-static int nilfs_btree_prepare_propagate_v(struct nilfs_btree *btree,
+static int nilfs_btree_prepare_propagate_v(struct nilfs_bmap *btree,
struct nilfs_btree_path *path,
int minlevel, int *maxlevelp,
struct inode *dat)
@@ -1809,7 +1898,7 @@ static int nilfs_btree_prepare_propagate_v(struct nilfs_btree *btree,
return ret;
}
-static void nilfs_btree_commit_propagate_v(struct nilfs_btree *btree,
+static void nilfs_btree_commit_propagate_v(struct nilfs_bmap *btree,
struct nilfs_btree_path *path,
int minlevel, int maxlevel,
struct buffer_head *bh,
@@ -1824,14 +1913,15 @@ static void nilfs_btree_commit_propagate_v(struct nilfs_btree *btree,
nilfs_btree_commit_update_v(btree, path, level, dat);
}
-static int nilfs_btree_propagate_v(struct nilfs_btree *btree,
+static int nilfs_btree_propagate_v(struct nilfs_bmap *btree,
struct nilfs_btree_path *path,
int level, struct buffer_head *bh)
{
int maxlevel = 0, ret;
struct nilfs_btree_node *parent;
- struct inode *dat = nilfs_bmap_get_dat(&btree->bt_bmap);
+ struct inode *dat = nilfs_bmap_get_dat(btree);
__u64 ptr;
+ int ncmax;
get_bh(bh);
path[level].bp_bh = bh;
@@ -1841,9 +1931,10 @@ static int nilfs_btree_propagate_v(struct nilfs_btree *btree,
goto out;
if (buffer_nilfs_volatile(path[level].bp_bh)) {
- parent = nilfs_btree_get_node(btree, path, level + 1);
- ptr = nilfs_btree_node_get_ptr(btree, parent,
- path[level + 1].bp_index);
+ parent = nilfs_btree_get_node(btree, path, level + 1, &ncmax);
+ ptr = nilfs_btree_node_get_ptr(parent,
+ path[level + 1].bp_index,
+ ncmax);
ret = nilfs_dat_mark_dirty(dat, ptr);
if (ret < 0)
goto out;
@@ -1857,10 +1948,9 @@ static int nilfs_btree_propagate_v(struct nilfs_btree *btree,
return ret;
}
-static int nilfs_btree_propagate(const struct nilfs_bmap *bmap,
+static int nilfs_btree_propagate(struct nilfs_bmap *btree,
struct buffer_head *bh)
{
- struct nilfs_btree *btree;
struct nilfs_btree_path *path;
struct nilfs_btree_node *node;
__u64 key;
@@ -1868,7 +1958,6 @@ static int nilfs_btree_propagate(const struct nilfs_bmap *bmap,
WARN_ON(!buffer_dirty(bh));
- btree = (struct nilfs_btree *)bmap;
path = nilfs_btree_alloc_path();
if (path == NULL)
return -ENOMEM;
@@ -1878,11 +1967,11 @@ static int nilfs_btree_propagate(const struct nilfs_bmap *bmap,
key = nilfs_btree_node_get_key(node, 0);
level = nilfs_btree_node_get_level(node);
} else {
- key = nilfs_bmap_data_get_key(bmap, bh);
+ key = nilfs_bmap_data_get_key(btree, bh);
level = NILFS_BTREE_LEVEL_DATA;
}
- ret = nilfs_btree_do_lookup(btree, path, key, NULL, level + 1);
+ ret = nilfs_btree_do_lookup(btree, path, key, NULL, level + 1, 0);
if (ret < 0) {
if (unlikely(ret == -ENOENT))
printk(KERN_CRIT "%s: key = %llu, level == %d\n",
@@ -1890,7 +1979,7 @@ static int nilfs_btree_propagate(const struct nilfs_bmap *bmap,
goto out;
}
- ret = NILFS_BMAP_USE_VBN(bmap) ?
+ ret = NILFS_BMAP_USE_VBN(btree) ?
nilfs_btree_propagate_v(btree, path, level, bh) :
nilfs_btree_propagate_p(btree, path, level, bh);
@@ -1900,13 +1989,13 @@ static int nilfs_btree_propagate(const struct nilfs_bmap *bmap,
return ret;
}
-static int nilfs_btree_propagate_gc(const struct nilfs_bmap *bmap,
+static int nilfs_btree_propagate_gc(struct nilfs_bmap *btree,
struct buffer_head *bh)
{
- return nilfs_dat_mark_dirty(nilfs_bmap_get_dat(bmap), bh->b_blocknr);
+ return nilfs_dat_mark_dirty(nilfs_bmap_get_dat(btree), bh->b_blocknr);
}
-static void nilfs_btree_add_dirty_buffer(struct nilfs_btree *btree,
+static void nilfs_btree_add_dirty_buffer(struct nilfs_bmap *btree,
struct list_head *lists,
struct buffer_head *bh)
{
@@ -1920,6 +2009,18 @@ static void nilfs_btree_add_dirty_buffer(struct nilfs_btree *btree,
node = (struct nilfs_btree_node *)bh->b_data;
key = nilfs_btree_node_get_key(node, 0);
level = nilfs_btree_node_get_level(node);
+ if (level < NILFS_BTREE_LEVEL_NODE_MIN ||
+ level >= NILFS_BTREE_LEVEL_MAX) {
+ dump_stack();
+ printk(KERN_WARNING
+ "%s: invalid btree level: %d (key=%llu, ino=%lu, "
+ "blocknr=%llu)\n",
+ __func__, level, (unsigned long long)key,
+ NILFS_BMAP_I(btree)->vfs_inode.i_ino,
+ (unsigned long long)bh->b_blocknr);
+ return;
+ }
+
list_for_each(head, &lists[level]) {
cbh = list_entry(head, struct buffer_head, b_assoc_buffers);
cnode = (struct nilfs_btree_node *)cbh->b_data;
@@ -1930,11 +2031,10 @@ static void nilfs_btree_add_dirty_buffer(struct nilfs_btree *btree,
list_add_tail(&bh->b_assoc_buffers, head);
}
-static void nilfs_btree_lookup_dirty_buffers(struct nilfs_bmap *bmap,
+static void nilfs_btree_lookup_dirty_buffers(struct nilfs_bmap *btree,
struct list_head *listp)
{
- struct nilfs_btree *btree = (struct nilfs_btree *)bmap;
- struct address_space *btcache = &NILFS_BMAP_I(bmap)->i_btnode_cache;
+ struct address_space *btcache = &NILFS_BMAP_I(btree)->i_btnode_cache;
struct list_head lists[NILFS_BTREE_LEVEL_MAX];
struct pagevec pvec;
struct buffer_head *bh, *head;
@@ -1968,7 +2068,7 @@ static void nilfs_btree_lookup_dirty_buffers(struct nilfs_bmap *bmap,
list_splice_tail(&lists[level], listp);
}
-static int nilfs_btree_assign_p(struct nilfs_btree *btree,
+static int nilfs_btree_assign_p(struct nilfs_bmap *btree,
struct nilfs_btree_path *path,
int level,
struct buffer_head **bh,
@@ -1978,38 +2078,38 @@ static int nilfs_btree_assign_p(struct nilfs_btree *btree,
struct nilfs_btree_node *parent;
__u64 key;
__u64 ptr;
- int ret;
+ int ncmax, ret;
- parent = nilfs_btree_get_node(btree, path, level + 1);
- ptr = nilfs_btree_node_get_ptr(btree, parent,
- path[level + 1].bp_index);
+ parent = nilfs_btree_get_node(btree, path, level + 1, &ncmax);
+ ptr = nilfs_btree_node_get_ptr(parent, path[level + 1].bp_index,
+ ncmax);
if (buffer_nilfs_node(*bh)) {
path[level].bp_ctxt.oldkey = ptr;
path[level].bp_ctxt.newkey = blocknr;
path[level].bp_ctxt.bh = *bh;
ret = nilfs_btnode_prepare_change_key(
- &NILFS_BMAP_I(&btree->bt_bmap)->i_btnode_cache,
+ &NILFS_BMAP_I(btree)->i_btnode_cache,
&path[level].bp_ctxt);
if (ret < 0)
return ret;
nilfs_btnode_commit_change_key(
- &NILFS_BMAP_I(&btree->bt_bmap)->i_btnode_cache,
+ &NILFS_BMAP_I(btree)->i_btnode_cache,
&path[level].bp_ctxt);
*bh = path[level].bp_ctxt.bh;
}
- nilfs_btree_node_set_ptr(btree, parent,
- path[level + 1].bp_index, blocknr);
+ nilfs_btree_node_set_ptr(parent, path[level + 1].bp_index, blocknr,
+ ncmax);
key = nilfs_btree_node_get_key(parent, path[level + 1].bp_index);
/* on-disk format */
- binfo->bi_dat.bi_blkoff = nilfs_bmap_key_to_dkey(key);
+ binfo->bi_dat.bi_blkoff = cpu_to_le64(key);
binfo->bi_dat.bi_level = level;
return 0;
}
-static int nilfs_btree_assign_v(struct nilfs_btree *btree,
+static int nilfs_btree_assign_v(struct nilfs_bmap *btree,
struct nilfs_btree_path *path,
int level,
struct buffer_head **bh,
@@ -2017,15 +2117,15 @@ static int nilfs_btree_assign_v(struct nilfs_btree *btree,
union nilfs_binfo *binfo)
{
struct nilfs_btree_node *parent;
- struct inode *dat = nilfs_bmap_get_dat(&btree->bt_bmap);
+ struct inode *dat = nilfs_bmap_get_dat(btree);
__u64 key;
__u64 ptr;
union nilfs_bmap_ptr_req req;
- int ret;
+ int ncmax, ret;
- parent = nilfs_btree_get_node(btree, path, level + 1);
- ptr = nilfs_btree_node_get_ptr(btree, parent,
- path[level + 1].bp_index);
+ parent = nilfs_btree_get_node(btree, path, level + 1, &ncmax);
+ ptr = nilfs_btree_node_get_ptr(parent, path[level + 1].bp_index,
+ ncmax);
req.bpr_ptr = ptr;
ret = nilfs_dat_prepare_start(dat, &req.bpr_req);
if (ret < 0)
@@ -2034,24 +2134,22 @@ static int nilfs_btree_assign_v(struct nilfs_btree *btree,
key = nilfs_btree_node_get_key(parent, path[level + 1].bp_index);
/* on-disk format */
- binfo->bi_v.bi_vblocknr = nilfs_bmap_ptr_to_dptr(ptr);
- binfo->bi_v.bi_blkoff = nilfs_bmap_key_to_dkey(key);
+ binfo->bi_v.bi_vblocknr = cpu_to_le64(ptr);
+ binfo->bi_v.bi_blkoff = cpu_to_le64(key);
return 0;
}
-static int nilfs_btree_assign(struct nilfs_bmap *bmap,
+static int nilfs_btree_assign(struct nilfs_bmap *btree,
struct buffer_head **bh,
sector_t blocknr,
union nilfs_binfo *binfo)
{
- struct nilfs_btree *btree;
struct nilfs_btree_path *path;
struct nilfs_btree_node *node;
__u64 key;
int level, ret;
- btree = (struct nilfs_btree *)bmap;
path = nilfs_btree_alloc_path();
if (path == NULL)
return -ENOMEM;
@@ -2061,17 +2159,17 @@ static int nilfs_btree_assign(struct nilfs_bmap *bmap,
key = nilfs_btree_node_get_key(node, 0);
level = nilfs_btree_node_get_level(node);
} else {
- key = nilfs_bmap_data_get_key(bmap, *bh);
+ key = nilfs_bmap_data_get_key(btree, *bh);
level = NILFS_BTREE_LEVEL_DATA;
}
- ret = nilfs_btree_do_lookup(btree, path, key, NULL, level + 1);
+ ret = nilfs_btree_do_lookup(btree, path, key, NULL, level + 1, 0);
if (ret < 0) {
WARN_ON(ret == -ENOENT);
goto out;
}
- ret = NILFS_BMAP_USE_VBN(bmap) ?
+ ret = NILFS_BMAP_USE_VBN(btree) ?
nilfs_btree_assign_v(btree, path, level, bh, blocknr, binfo) :
nilfs_btree_assign_p(btree, path, level, bh, blocknr, binfo);
@@ -2081,7 +2179,7 @@ static int nilfs_btree_assign(struct nilfs_bmap *bmap,
return ret;
}
-static int nilfs_btree_assign_gc(struct nilfs_bmap *bmap,
+static int nilfs_btree_assign_gc(struct nilfs_bmap *btree,
struct buffer_head **bh,
sector_t blocknr,
union nilfs_binfo *binfo)
@@ -2090,7 +2188,7 @@ static int nilfs_btree_assign_gc(struct nilfs_bmap *bmap,
__u64 key;
int ret;
- ret = nilfs_dat_move(nilfs_bmap_get_dat(bmap), (*bh)->b_blocknr,
+ ret = nilfs_dat_move(nilfs_bmap_get_dat(btree), (*bh)->b_blocknr,
blocknr);
if (ret < 0)
return ret;
@@ -2099,29 +2197,27 @@ static int nilfs_btree_assign_gc(struct nilfs_bmap *bmap,
node = (struct nilfs_btree_node *)(*bh)->b_data;
key = nilfs_btree_node_get_key(node, 0);
} else
- key = nilfs_bmap_data_get_key(bmap, *bh);
+ key = nilfs_bmap_data_get_key(btree, *bh);
/* on-disk format */
binfo->bi_v.bi_vblocknr = cpu_to_le64((*bh)->b_blocknr);
- binfo->bi_v.bi_blkoff = nilfs_bmap_key_to_dkey(key);
+ binfo->bi_v.bi_blkoff = cpu_to_le64(key);
return 0;
}
-static int nilfs_btree_mark(struct nilfs_bmap *bmap, __u64 key, int level)
+static int nilfs_btree_mark(struct nilfs_bmap *btree, __u64 key, int level)
{
struct buffer_head *bh;
- struct nilfs_btree *btree;
struct nilfs_btree_path *path;
__u64 ptr;
int ret;
- btree = (struct nilfs_btree *)bmap;
path = nilfs_btree_alloc_path();
if (path == NULL)
return -ENOMEM;
- ret = nilfs_btree_do_lookup(btree, path, key, &ptr, level + 1);
+ ret = nilfs_btree_do_lookup(btree, path, key, &ptr, level + 1, 0);
if (ret < 0) {
WARN_ON(ret == -ENOENT);
goto out;
@@ -2135,8 +2231,8 @@ static int nilfs_btree_mark(struct nilfs_bmap *bmap, __u64 key, int level)
if (!buffer_dirty(bh))
nilfs_btnode_mark_dirty(bh);
brelse(bh);
- if (!nilfs_bmap_dirty(&btree->bt_bmap))
- nilfs_bmap_set_dirty(&btree->bt_bmap);
+ if (!nilfs_bmap_dirty(btree))
+ nilfs_bmap_set_dirty(btree);
out:
nilfs_btree_free_path(path);
@@ -2186,10 +2282,14 @@ static const struct nilfs_bmap_operations nilfs_btree_ops_gc = {
int nilfs_btree_init(struct nilfs_bmap *bmap)
{
bmap->b_ops = &nilfs_btree_ops;
+ bmap->b_nchildren_per_block =
+ NILFS_BTREE_NODE_NCHILDREN_MAX(nilfs_btree_node_size(bmap));
return 0;
}
void nilfs_btree_init_gc(struct nilfs_bmap *bmap)
{
bmap->b_ops = &nilfs_btree_ops_gc;
+ bmap->b_nchildren_per_block =
+ NILFS_BTREE_NODE_NCHILDREN_MAX(nilfs_btree_node_size(bmap));
}
diff --git a/fs/nilfs2/btree.h b/fs/nilfs2/btree.h
index 43c8c5b541f..22c02e35b6e 100644
--- a/fs/nilfs2/btree.h
+++ b/fs/nilfs2/btree.h
@@ -31,14 +31,6 @@
#include "bmap.h"
/**
- * struct nilfs_btree - B-tree structure
- * @bt_bmap: bmap base structure
- */
-struct nilfs_btree {
- struct nilfs_bmap bt_bmap;
-};
-
-/**
* struct nilfs_btree_path - A path on which B-tree operations are executed
* @bp_bh: buffer head of node block
* @bp_sib_bh: buffer head of sibling node block
@@ -54,7 +46,7 @@ struct nilfs_btree_path {
union nilfs_bmap_ptr_req bp_oldreq;
union nilfs_bmap_ptr_req bp_newreq;
struct nilfs_btnode_chkey_ctxt bp_ctxt;
- void (*bp_op)(struct nilfs_btree *, struct nilfs_btree_path *,
+ void (*bp_op)(struct nilfs_bmap *, struct nilfs_btree_path *,
int, __u64 *, __u64 *);
};
@@ -80,4 +72,6 @@ int nilfs_btree_convert_and_insert(struct nilfs_bmap *, __u64, __u64,
const __u64 *, const __u64 *, int);
void nilfs_btree_init_gc(struct nilfs_bmap *);
+int nilfs_btree_broken_node_block(struct buffer_head *bh);
+
#endif /* _NILFS_BTREE_H */
diff --git a/fs/nilfs2/dir.c b/fs/nilfs2/dir.c
index 85c89dfc71f..b60277b4446 100644
--- a/fs/nilfs2/dir.c
+++ b/fs/nilfs2/dir.c
@@ -141,7 +141,7 @@ static void nilfs_check_page(struct page *page)
}
for (offs = 0; offs <= limit - NILFS_DIR_REC_LEN(1); offs += rec_len) {
p = (struct nilfs_dir_entry *)(kaddr + offs);
- rec_len = le16_to_cpu(p->rec_len);
+ rec_len = nilfs_rec_len_from_disk(p->rec_len);
if (rec_len < NILFS_DIR_REC_LEN(1))
goto Eshort;
@@ -199,13 +199,10 @@ fail:
static struct page *nilfs_get_page(struct inode *dir, unsigned long n)
{
struct address_space *mapping = dir->i_mapping;
- struct page *page = read_cache_page(mapping, n,
- (filler_t *)mapping->a_ops->readpage, NULL);
+ struct page *page = read_mapping_page(mapping, n, NULL);
+
if (!IS_ERR(page)) {
- wait_on_page_locked(page);
kmap(page);
- if (!PageUptodate(page))
- goto fail;
if (!PageChecked(page))
nilfs_check_page(page);
if (PageError(page))
@@ -238,7 +235,8 @@ nilfs_match(int len, const unsigned char *name, struct nilfs_dir_entry *de)
*/
static struct nilfs_dir_entry *nilfs_next_entry(struct nilfs_dir_entry *p)
{
- return (struct nilfs_dir_entry *)((char *)p + le16_to_cpu(p->rec_len));
+ return (struct nilfs_dir_entry *)((char *)p +
+ nilfs_rec_len_from_disk(p->rec_len));
}
static unsigned char
@@ -329,7 +327,7 @@ static int nilfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
goto success;
}
}
- filp->f_pos += le16_to_cpu(de->rec_len);
+ filp->f_pos += nilfs_rec_len_from_disk(de->rec_len);
}
nilfs_put_page(page);
}
@@ -444,7 +442,7 @@ void nilfs_set_link(struct inode *dir, struct nilfs_dir_entry *de,
struct page *page, struct inode *inode)
{
unsigned from = (char *) de - (char *) page_address(page);
- unsigned to = from + le16_to_cpu(de->rec_len);
+ unsigned to = from + nilfs_rec_len_from_disk(de->rec_len);
struct address_space *mapping = page->mapping;
int err;
@@ -500,7 +498,7 @@ int nilfs_add_link(struct dentry *dentry, struct inode *inode)
/* We hit i_size */
name_len = 0;
rec_len = chunk_size;
- de->rec_len = cpu_to_le16(chunk_size);
+ de->rec_len = nilfs_rec_len_to_disk(chunk_size);
de->inode = 0;
goto got_it;
}
@@ -514,7 +512,7 @@ int nilfs_add_link(struct dentry *dentry, struct inode *inode)
if (nilfs_match(namelen, name, de))
goto out_unlock;
name_len = NILFS_DIR_REC_LEN(de->name_len);
- rec_len = le16_to_cpu(de->rec_len);
+ rec_len = nilfs_rec_len_from_disk(de->rec_len);
if (!de->inode && rec_len >= reclen)
goto got_it;
if (rec_len >= name_len + reclen)
@@ -537,8 +535,8 @@ got_it:
struct nilfs_dir_entry *de1;
de1 = (struct nilfs_dir_entry *)((char *)de + name_len);
- de1->rec_len = cpu_to_le16(rec_len - name_len);
- de->rec_len = cpu_to_le16(name_len);
+ de1->rec_len = nilfs_rec_len_to_disk(rec_len - name_len);
+ de->rec_len = nilfs_rec_len_to_disk(name_len);
de = de1;
}
de->name_len = namelen;
@@ -569,7 +567,8 @@ int nilfs_delete_entry(struct nilfs_dir_entry *dir, struct page *page)
struct inode *inode = mapping->host;
char *kaddr = page_address(page);
unsigned from = ((char *)dir - kaddr) & ~(nilfs_chunk_size(inode) - 1);
- unsigned to = ((char *)dir - kaddr) + le16_to_cpu(dir->rec_len);
+ unsigned to = ((char *)dir - kaddr) +
+ nilfs_rec_len_from_disk(dir->rec_len);
struct nilfs_dir_entry *pde = NULL;
struct nilfs_dir_entry *de = (struct nilfs_dir_entry *)(kaddr + from);
int err;
@@ -590,7 +589,7 @@ int nilfs_delete_entry(struct nilfs_dir_entry *dir, struct page *page)
err = nilfs_prepare_chunk(page, mapping, from, to);
BUG_ON(err);
if (pde)
- pde->rec_len = cpu_to_le16(to - from);
+ pde->rec_len = nilfs_rec_len_to_disk(to - from);
dir->inode = 0;
nilfs_commit_chunk(page, mapping, from, to);
inode->i_ctime = inode->i_mtime = CURRENT_TIME;
@@ -624,14 +623,14 @@ int nilfs_make_empty(struct inode *inode, struct inode *parent)
memset(kaddr, 0, chunk_size);
de = (struct nilfs_dir_entry *)kaddr;
de->name_len = 1;
- de->rec_len = cpu_to_le16(NILFS_DIR_REC_LEN(1));
+ de->rec_len = nilfs_rec_len_to_disk(NILFS_DIR_REC_LEN(1));
memcpy(de->name, ".\0\0", 4);
de->inode = cpu_to_le64(inode->i_ino);
nilfs_set_de_type(de, inode);
de = (struct nilfs_dir_entry *)(kaddr + NILFS_DIR_REC_LEN(1));
de->name_len = 2;
- de->rec_len = cpu_to_le16(chunk_size - NILFS_DIR_REC_LEN(1));
+ de->rec_len = nilfs_rec_len_to_disk(chunk_size - NILFS_DIR_REC_LEN(1));
de->inode = cpu_to_le64(parent->i_ino);
memcpy(de->name, "..\0", 4);
nilfs_set_de_type(de, inode);
diff --git a/fs/nilfs2/direct.c b/fs/nilfs2/direct.c
index 236753df5cd..324d80c5751 100644
--- a/fs/nilfs2/direct.c
+++ b/fs/nilfs2/direct.c
@@ -27,47 +27,43 @@
#include "alloc.h"
#include "dat.h"
-static inline __le64 *nilfs_direct_dptrs(const struct nilfs_direct *direct)
+static inline __le64 *nilfs_direct_dptrs(const struct nilfs_bmap *direct)
{
return (__le64 *)
- ((struct nilfs_direct_node *)direct->d_bmap.b_u.u_data + 1);
+ ((struct nilfs_direct_node *)direct->b_u.u_data + 1);
}
static inline __u64
-nilfs_direct_get_ptr(const struct nilfs_direct *direct, __u64 key)
+nilfs_direct_get_ptr(const struct nilfs_bmap *direct, __u64 key)
{
- return nilfs_bmap_dptr_to_ptr(*(nilfs_direct_dptrs(direct) + key));
+ return le64_to_cpu(*(nilfs_direct_dptrs(direct) + key));
}
-static inline void nilfs_direct_set_ptr(struct nilfs_direct *direct,
+static inline void nilfs_direct_set_ptr(struct nilfs_bmap *direct,
__u64 key, __u64 ptr)
{
- *(nilfs_direct_dptrs(direct) + key) = nilfs_bmap_ptr_to_dptr(ptr);
+ *(nilfs_direct_dptrs(direct) + key) = cpu_to_le64(ptr);
}
-static int nilfs_direct_lookup(const struct nilfs_bmap *bmap,
+static int nilfs_direct_lookup(const struct nilfs_bmap *direct,
__u64 key, int level, __u64 *ptrp)
{
- struct nilfs_direct *direct;
__u64 ptr;
- direct = (struct nilfs_direct *)bmap; /* XXX: use macro for level 1 */
if (key > NILFS_DIRECT_KEY_MAX || level != 1)
return -ENOENT;
ptr = nilfs_direct_get_ptr(direct, key);
if (ptr == NILFS_BMAP_INVALID_PTR)
return -ENOENT;
- if (ptrp != NULL)
- *ptrp = ptr;
+ *ptrp = ptr;
return 0;
}
-static int nilfs_direct_lookup_contig(const struct nilfs_bmap *bmap,
+static int nilfs_direct_lookup_contig(const struct nilfs_bmap *direct,
__u64 key, __u64 *ptrp,
unsigned maxblocks)
{
- struct nilfs_direct *direct = (struct nilfs_direct *)bmap;
struct inode *dat = NULL;
__u64 ptr, ptr2;
sector_t blocknr;
@@ -79,8 +75,8 @@ static int nilfs_direct_lookup_contig(const struct nilfs_bmap *bmap,
if (ptr == NILFS_BMAP_INVALID_PTR)
return -ENOENT;
- if (NILFS_BMAP_USE_VBN(bmap)) {
- dat = nilfs_bmap_get_dat(bmap);
+ if (NILFS_BMAP_USE_VBN(direct)) {
+ dat = nilfs_bmap_get_dat(direct);
ret = nilfs_dat_translate(dat, ptr, &blocknr);
if (ret < 0)
return ret;
@@ -106,29 +102,21 @@ static int nilfs_direct_lookup_contig(const struct nilfs_bmap *bmap,
}
static __u64
-nilfs_direct_find_target_v(const struct nilfs_direct *direct, __u64 key)
+nilfs_direct_find_target_v(const struct nilfs_bmap *direct, __u64 key)
{
__u64 ptr;
- ptr = nilfs_bmap_find_target_seq(&direct->d_bmap, key);
+ ptr = nilfs_bmap_find_target_seq(direct, key);
if (ptr != NILFS_BMAP_INVALID_PTR)
/* sequential access */
return ptr;
else
/* block group */
- return nilfs_bmap_find_target_in_group(&direct->d_bmap);
-}
-
-static void nilfs_direct_set_target_v(struct nilfs_direct *direct,
- __u64 key, __u64 ptr)
-{
- direct->d_bmap.b_last_allocated_key = key;
- direct->d_bmap.b_last_allocated_ptr = ptr;
+ return nilfs_bmap_find_target_in_group(direct);
}
static int nilfs_direct_insert(struct nilfs_bmap *bmap, __u64 key, __u64 ptr)
{
- struct nilfs_direct *direct = (struct nilfs_direct *)bmap;
union nilfs_bmap_ptr_req req;
struct inode *dat = NULL;
struct buffer_head *bh;
@@ -136,11 +124,11 @@ static int nilfs_direct_insert(struct nilfs_bmap *bmap, __u64 key, __u64 ptr)
if (key > NILFS_DIRECT_KEY_MAX)
return -ENOENT;
- if (nilfs_direct_get_ptr(direct, key) != NILFS_BMAP_INVALID_PTR)
+ if (nilfs_direct_get_ptr(bmap, key) != NILFS_BMAP_INVALID_PTR)
return -EEXIST;
if (NILFS_BMAP_USE_VBN(bmap)) {
- req.bpr_ptr = nilfs_direct_find_target_v(direct, key);
+ req.bpr_ptr = nilfs_direct_find_target_v(bmap, key);
dat = nilfs_bmap_get_dat(bmap);
}
ret = nilfs_bmap_prepare_alloc_ptr(bmap, &req, dat);
@@ -150,13 +138,13 @@ static int nilfs_direct_insert(struct nilfs_bmap *bmap, __u64 key, __u64 ptr)
set_buffer_nilfs_volatile(bh);
nilfs_bmap_commit_alloc_ptr(bmap, &req, dat);
- nilfs_direct_set_ptr(direct, key, req.bpr_ptr);
+ nilfs_direct_set_ptr(bmap, key, req.bpr_ptr);
if (!nilfs_bmap_dirty(bmap))
nilfs_bmap_set_dirty(bmap);
if (NILFS_BMAP_USE_VBN(bmap))
- nilfs_direct_set_target_v(direct, key, req.bpr_ptr);
+ nilfs_bmap_set_target_v(bmap, key, req.bpr_ptr);
nilfs_bmap_add_blocks(bmap, 1);
}
@@ -165,33 +153,30 @@ static int nilfs_direct_insert(struct nilfs_bmap *bmap, __u64 key, __u64 ptr)
static int nilfs_direct_delete(struct nilfs_bmap *bmap, __u64 key)
{
- struct nilfs_direct *direct = (struct nilfs_direct *)bmap;
union nilfs_bmap_ptr_req req;
struct inode *dat;
int ret;
if (key > NILFS_DIRECT_KEY_MAX ||
- nilfs_direct_get_ptr(direct, key) == NILFS_BMAP_INVALID_PTR)
+ nilfs_direct_get_ptr(bmap, key) == NILFS_BMAP_INVALID_PTR)
return -ENOENT;
dat = NILFS_BMAP_USE_VBN(bmap) ? nilfs_bmap_get_dat(bmap) : NULL;
- req.bpr_ptr = nilfs_direct_get_ptr(direct, key);
+ req.bpr_ptr = nilfs_direct_get_ptr(bmap, key);
ret = nilfs_bmap_prepare_end_ptr(bmap, &req, dat);
if (!ret) {
nilfs_bmap_commit_end_ptr(bmap, &req, dat);
- nilfs_direct_set_ptr(direct, key, NILFS_BMAP_INVALID_PTR);
+ nilfs_direct_set_ptr(bmap, key, NILFS_BMAP_INVALID_PTR);
nilfs_bmap_sub_blocks(bmap, 1);
}
return ret;
}
-static int nilfs_direct_last_key(const struct nilfs_bmap *bmap, __u64 *keyp)
+static int nilfs_direct_last_key(const struct nilfs_bmap *direct, __u64 *keyp)
{
- struct nilfs_direct *direct;
__u64 key, lastkey;
- direct = (struct nilfs_direct *)bmap;
lastkey = NILFS_DIRECT_KEY_MAX + 1;
for (key = NILFS_DIRECT_KEY_MIN; key <= NILFS_DIRECT_KEY_MAX; key++)
if (nilfs_direct_get_ptr(direct, key) !=
@@ -211,15 +196,13 @@ static int nilfs_direct_check_insert(const struct nilfs_bmap *bmap, __u64 key)
return key > NILFS_DIRECT_KEY_MAX;
}
-static int nilfs_direct_gather_data(struct nilfs_bmap *bmap,
+static int nilfs_direct_gather_data(struct nilfs_bmap *direct,
__u64 *keys, __u64 *ptrs, int nitems)
{
- struct nilfs_direct *direct;
__u64 key;
__u64 ptr;
int n;
- direct = (struct nilfs_direct *)bmap;
if (nitems > NILFS_DIRECT_NBLOCKS)
nitems = NILFS_DIRECT_NBLOCKS;
n = 0;
@@ -237,7 +220,6 @@ static int nilfs_direct_gather_data(struct nilfs_bmap *bmap,
int nilfs_direct_delete_and_convert(struct nilfs_bmap *bmap,
__u64 key, __u64 *keys, __u64 *ptrs, int n)
{
- struct nilfs_direct *direct;
__le64 *dptrs;
int ret, i, j;
@@ -253,12 +235,11 @@ int nilfs_direct_delete_and_convert(struct nilfs_bmap *bmap,
bmap->b_ops->bop_clear(bmap);
/* convert */
- direct = (struct nilfs_direct *)bmap;
- dptrs = nilfs_direct_dptrs(direct);
+ dptrs = nilfs_direct_dptrs(bmap);
for (i = 0, j = 0; i < NILFS_DIRECT_NBLOCKS; i++) {
if ((j < n) && (i == keys[j])) {
dptrs[i] = (i != key) ?
- nilfs_bmap_ptr_to_dptr(ptrs[j]) :
+ cpu_to_le64(ptrs[j]) :
NILFS_BMAP_INVALID_PTR;
j++;
} else
@@ -269,10 +250,9 @@ int nilfs_direct_delete_and_convert(struct nilfs_bmap *bmap,
return 0;
}
-static int nilfs_direct_propagate(const struct nilfs_bmap *bmap,
+static int nilfs_direct_propagate(struct nilfs_bmap *bmap,
struct buffer_head *bh)
{
- struct nilfs_direct *direct = (struct nilfs_direct *)bmap;
struct nilfs_palloc_req oldreq, newreq;
struct inode *dat;
__u64 key;
@@ -284,7 +264,7 @@ static int nilfs_direct_propagate(const struct nilfs_bmap *bmap,
dat = nilfs_bmap_get_dat(bmap);
key = nilfs_bmap_data_get_key(bmap, bh);
- ptr = nilfs_direct_get_ptr(direct, key);
+ ptr = nilfs_direct_get_ptr(bmap, key);
if (!buffer_nilfs_volatile(bh)) {
oldreq.pr_entry_nr = ptr;
newreq.pr_entry_nr = ptr;
@@ -294,20 +274,20 @@ static int nilfs_direct_propagate(const struct nilfs_bmap *bmap,
nilfs_dat_commit_update(dat, &oldreq, &newreq,
bmap->b_ptr_type == NILFS_BMAP_PTR_VS);
set_buffer_nilfs_volatile(bh);
- nilfs_direct_set_ptr(direct, key, newreq.pr_entry_nr);
+ nilfs_direct_set_ptr(bmap, key, newreq.pr_entry_nr);
} else
ret = nilfs_dat_mark_dirty(dat, ptr);
return ret;
}
-static int nilfs_direct_assign_v(struct nilfs_direct *direct,
+static int nilfs_direct_assign_v(struct nilfs_bmap *direct,
__u64 key, __u64 ptr,
struct buffer_head **bh,
sector_t blocknr,
union nilfs_binfo *binfo)
{
- struct inode *dat = nilfs_bmap_get_dat(&direct->d_bmap);
+ struct inode *dat = nilfs_bmap_get_dat(direct);
union nilfs_bmap_ptr_req req;
int ret;
@@ -315,13 +295,13 @@ static int nilfs_direct_assign_v(struct nilfs_direct *direct,
ret = nilfs_dat_prepare_start(dat, &req.bpr_req);
if (!ret) {
nilfs_dat_commit_start(dat, &req.bpr_req, blocknr);
- binfo->bi_v.bi_vblocknr = nilfs_bmap_ptr_to_dptr(ptr);
- binfo->bi_v.bi_blkoff = nilfs_bmap_key_to_dkey(key);
+ binfo->bi_v.bi_vblocknr = cpu_to_le64(ptr);
+ binfo->bi_v.bi_blkoff = cpu_to_le64(key);
}
return ret;
}
-static int nilfs_direct_assign_p(struct nilfs_direct *direct,
+static int nilfs_direct_assign_p(struct nilfs_bmap *direct,
__u64 key, __u64 ptr,
struct buffer_head **bh,
sector_t blocknr,
@@ -329,7 +309,7 @@ static int nilfs_direct_assign_p(struct nilfs_direct *direct,
{
nilfs_direct_set_ptr(direct, key, blocknr);
- binfo->bi_dat.bi_blkoff = nilfs_bmap_key_to_dkey(key);
+ binfo->bi_dat.bi_blkoff = cpu_to_le64(key);
binfo->bi_dat.bi_level = 0;
return 0;
@@ -340,18 +320,16 @@ static int nilfs_direct_assign(struct nilfs_bmap *bmap,
sector_t blocknr,
union nilfs_binfo *binfo)
{
- struct nilfs_direct *direct;
__u64 key;
__u64 ptr;
- direct = (struct nilfs_direct *)bmap;
key = nilfs_bmap_data_get_key(bmap, *bh);
if (unlikely(key > NILFS_DIRECT_KEY_MAX)) {
printk(KERN_CRIT "%s: invalid key: %llu\n", __func__,
(unsigned long long)key);
return -EINVAL;
}
- ptr = nilfs_direct_get_ptr(direct, key);
+ ptr = nilfs_direct_get_ptr(bmap, key);
if (unlikely(ptr == NILFS_BMAP_INVALID_PTR)) {
printk(KERN_CRIT "%s: invalid pointer: %llu\n", __func__,
(unsigned long long)ptr);
@@ -359,8 +337,8 @@ static int nilfs_direct_assign(struct nilfs_bmap *bmap,
}
return NILFS_BMAP_USE_VBN(bmap) ?
- nilfs_direct_assign_v(direct, key, ptr, bh, blocknr, binfo) :
- nilfs_direct_assign_p(direct, key, ptr, bh, blocknr, binfo);
+ nilfs_direct_assign_v(bmap, key, ptr, bh, blocknr, binfo) :
+ nilfs_direct_assign_p(bmap, key, ptr, bh, blocknr, binfo);
}
static const struct nilfs_bmap_operations nilfs_direct_ops = {
diff --git a/fs/nilfs2/direct.h b/fs/nilfs2/direct.h
index a5ffd66e25d..dc643de20a2 100644
--- a/fs/nilfs2/direct.h
+++ b/fs/nilfs2/direct.h
@@ -28,8 +28,6 @@
#include "bmap.h"
-struct nilfs_direct;
-
/**
* struct nilfs_direct_node - direct node
* @dn_flags: flags
@@ -40,15 +38,6 @@ struct nilfs_direct_node {
__u8 pad[7];
};
-/**
- * struct nilfs_direct - direct mapping
- * @d_bmap: bmap structure
- */
-struct nilfs_direct {
- struct nilfs_bmap d_bmap;
-};
-
-
#define NILFS_DIRECT_NBLOCKS (NILFS_BMAP_SIZE / sizeof(__le64) - 1)
#define NILFS_DIRECT_KEY_MIN 0
#define NILFS_DIRECT_KEY_MAX (NILFS_DIRECT_NBLOCKS - 1)
diff --git a/fs/nilfs2/gcinode.c b/fs/nilfs2/gcinode.c
index 145f03cd7d3..bed3a783129 100644
--- a/fs/nilfs2/gcinode.c
+++ b/fs/nilfs2/gcinode.c
@@ -48,6 +48,8 @@
#include <linux/slab.h>
#include <linux/swap.h>
#include "nilfs.h"
+#include "btree.h"
+#include "btnode.h"
#include "page.h"
#include "mdt.h"
#include "dat.h"
@@ -149,8 +151,10 @@ int nilfs_gccache_submit_read_data(struct inode *inode, sector_t blkoff,
int nilfs_gccache_submit_read_node(struct inode *inode, sector_t pbn,
__u64 vbn, struct buffer_head **out_bh)
{
- int ret = nilfs_btnode_submit_block(&NILFS_I(inode)->i_btnode_cache,
- vbn ? : pbn, pbn, out_bh);
+ int ret;
+
+ ret = nilfs_btnode_submit_block(&NILFS_I(inode)->i_btnode_cache,
+ vbn ? : pbn, pbn, READ, out_bh, &pbn);
if (ret == -EEXIST) /* internal code (cache hit) */
ret = 0;
return ret;
@@ -164,10 +168,15 @@ int nilfs_gccache_wait_and_mark_dirty(struct buffer_head *bh)
if (buffer_dirty(bh))
return -EEXIST;
- if (buffer_nilfs_node(bh))
+ if (buffer_nilfs_node(bh)) {
+ if (nilfs_btree_broken_node_block(bh)) {
+ clear_buffer_uptodate(bh);
+ return -EIO;
+ }
nilfs_btnode_mark_dirty(bh);
- else
+ } else {
nilfs_mdt_mark_buffer_dirty(bh);
+ }
return 0;
}
diff --git a/fs/nilfs2/mdt.c b/fs/nilfs2/mdt.c
index 024be8c35bb..d01aff4957d 100644
--- a/fs/nilfs2/mdt.c
+++ b/fs/nilfs2/mdt.c
@@ -28,6 +28,7 @@
#include <linux/swap.h>
#include <linux/slab.h>
#include "nilfs.h"
+#include "btnode.h"
#include "segment.h"
#include "page.h"
#include "mdt.h"
diff --git a/fs/nilfs2/nilfs.h b/fs/nilfs2/nilfs.h
index 47d6d792812..0842d775b3e 100644
--- a/fs/nilfs2/nilfs.h
+++ b/fs/nilfs2/nilfs.h
@@ -32,7 +32,6 @@
#include "the_nilfs.h"
#include "sb.h"
#include "bmap.h"
-#include "bmap_union.h"
/*
* nilfs inode data in memory
@@ -41,7 +40,7 @@ struct nilfs_inode_info {
__u32 i_flags;
unsigned long i_state; /* Dynamic state flags */
struct nilfs_bmap *i_bmap;
- union nilfs_bmap_union i_bmap_union;
+ struct nilfs_bmap i_bmap_data;
__u64 i_xattr; /* sector_t ??? */
__u32 i_dir_start_lookup;
__u64 i_cno; /* check point number for GC inode */
@@ -71,9 +70,7 @@ static inline struct nilfs_inode_info *NILFS_I(const struct inode *inode)
static inline struct nilfs_inode_info *
NILFS_BMAP_I(const struct nilfs_bmap *bmap)
{
- return container_of((union nilfs_bmap_union *)bmap,
- struct nilfs_inode_info,
- i_bmap_union);
+ return container_of(bmap, struct nilfs_inode_info, i_bmap_data);
}
static inline struct inode *NILFS_BTNC_I(struct address_space *btnc)
@@ -107,6 +104,14 @@ enum {
};
/*
+ * commit flags for nilfs_commit_super and nilfs_sync_super
+ */
+enum {
+ NILFS_SB_COMMIT = 0, /* Commit a super block alternately */
+ NILFS_SB_COMMIT_ALL /* Commit both super blocks */
+};
+
+/*
* Macros to check inode numbers
*/
#define NILFS_MDT_INO_BITS \
@@ -270,7 +275,14 @@ extern struct nilfs_super_block *
nilfs_read_super_block(struct super_block *, u64, int, struct buffer_head **);
extern int nilfs_store_magic_and_option(struct super_block *,
struct nilfs_super_block *, char *);
+extern int nilfs_check_feature_compatibility(struct super_block *,
+ struct nilfs_super_block *);
+extern void nilfs_set_log_cursor(struct nilfs_super_block *,
+ struct the_nilfs *);
+extern struct nilfs_super_block **nilfs_prepare_super(struct nilfs_sb_info *,
+ int flip);
extern int nilfs_commit_super(struct nilfs_sb_info *, int);
+extern int nilfs_cleanup_super(struct nilfs_sb_info *);
extern int nilfs_attach_checkpoint(struct nilfs_sb_info *, __u64);
extern void nilfs_detach_checkpoint(struct nilfs_sb_info *);
diff --git a/fs/nilfs2/page.c b/fs/nilfs2/page.c
index 8de3e1e4813..aab11db2cb0 100644
--- a/fs/nilfs2/page.c
+++ b/fs/nilfs2/page.c
@@ -37,7 +37,8 @@
#define NILFS_BUFFER_INHERENT_BITS \
((1UL << BH_Uptodate) | (1UL << BH_Mapped) | (1UL << BH_NILFS_Node) | \
- (1UL << BH_NILFS_Volatile) | (1UL << BH_NILFS_Allocated))
+ (1UL << BH_NILFS_Volatile) | (1UL << BH_NILFS_Allocated) | \
+ (1UL << BH_NILFS_Checked))
static struct buffer_head *
__nilfs_get_page_block(struct page *page, unsigned long block, pgoff_t index,
@@ -129,6 +130,7 @@ void nilfs_forget_buffer(struct buffer_head *bh)
lock_buffer(bh);
clear_buffer_nilfs_volatile(bh);
+ clear_buffer_nilfs_checked(bh);
clear_buffer_dirty(bh);
if (nilfs_page_buffers_clean(page))
__nilfs_clear_page_dirty(page);
@@ -480,6 +482,7 @@ void nilfs_clear_dirty_pages(struct address_space *mapping)
lock_buffer(bh);
clear_buffer_dirty(bh);
clear_buffer_nilfs_volatile(bh);
+ clear_buffer_nilfs_checked(bh);
clear_buffer_uptodate(bh);
clear_buffer_mapped(bh);
unlock_buffer(bh);
diff --git a/fs/nilfs2/page.h b/fs/nilfs2/page.h
index 8abca4d1c1f..f53d8da41ed 100644
--- a/fs/nilfs2/page.h
+++ b/fs/nilfs2/page.h
@@ -34,11 +34,13 @@ enum {
BH_NILFS_Allocated = BH_PrivateStart,
BH_NILFS_Node,
BH_NILFS_Volatile,
+ BH_NILFS_Checked,
};
BUFFER_FNS(NILFS_Allocated, nilfs_allocated) /* nilfs private buffers */
BUFFER_FNS(NILFS_Node, nilfs_node) /* nilfs node buffers */
BUFFER_FNS(NILFS_Volatile, nilfs_volatile)
+BUFFER_FNS(NILFS_Checked, nilfs_checked) /* buffer is verified */
void nilfs_mark_buffer_dirty(struct buffer_head *bh);
diff --git a/fs/nilfs2/recovery.c b/fs/nilfs2/recovery.c
index bae2a516b4e..83e3d8c61a0 100644
--- a/fs/nilfs2/recovery.c
+++ b/fs/nilfs2/recovery.c
@@ -91,27 +91,9 @@ static int nilfs_warn_segment_error(int err)
return -EINVAL;
}
-static void store_segsum_info(struct nilfs_segsum_info *ssi,
- struct nilfs_segment_summary *sum,
- unsigned int blocksize)
-{
- ssi->flags = le16_to_cpu(sum->ss_flags);
- ssi->seg_seq = le64_to_cpu(sum->ss_seq);
- ssi->ctime = le64_to_cpu(sum->ss_create);
- ssi->next = le64_to_cpu(sum->ss_next);
- ssi->nblocks = le32_to_cpu(sum->ss_nblocks);
- ssi->nfinfo = le32_to_cpu(sum->ss_nfinfo);
- ssi->sumbytes = le32_to_cpu(sum->ss_sumbytes);
-
- ssi->nsumblk = DIV_ROUND_UP(ssi->sumbytes, blocksize);
- ssi->nfileblk = ssi->nblocks - ssi->nsumblk - !!NILFS_SEG_HAS_SR(ssi);
-
- /* need to verify ->ss_bytes field if read ->ss_cno */
-}
-
/**
- * calc_crc_cont - check CRC of blocks continuously
- * @sbi: nilfs_sb_info
+ * nilfs_compute_checksum - compute checksum of blocks continuously
+ * @nilfs: nilfs object
* @bhs: buffer head of start block
* @sum: place to store result
* @offset: offset bytes in the first block
@@ -119,23 +101,25 @@ static void store_segsum_info(struct nilfs_segsum_info *ssi,
* @start: DBN of start block
* @nblock: number of blocks to be checked
*/
-static int calc_crc_cont(struct nilfs_sb_info *sbi, struct buffer_head *bhs,
- u32 *sum, unsigned long offset, u64 check_bytes,
- sector_t start, unsigned long nblock)
+static int nilfs_compute_checksum(struct the_nilfs *nilfs,
+ struct buffer_head *bhs, u32 *sum,
+ unsigned long offset, u64 check_bytes,
+ sector_t start, unsigned long nblock)
{
- unsigned long blocksize = sbi->s_super->s_blocksize;
+ unsigned int blocksize = nilfs->ns_blocksize;
unsigned long size;
u32 crc;
BUG_ON(offset >= blocksize);
check_bytes -= offset;
size = min_t(u64, check_bytes, blocksize - offset);
- crc = crc32_le(sbi->s_nilfs->ns_crc_seed,
+ crc = crc32_le(nilfs->ns_crc_seed,
(unsigned char *)bhs->b_data + offset, size);
if (--nblock > 0) {
do {
- struct buffer_head *bh
- = sb_bread(sbi->s_super, ++start);
+ struct buffer_head *bh;
+
+ bh = __bread(nilfs->ns_bdev, ++start, blocksize);
if (!bh)
return -EIO;
check_bytes -= size;
@@ -150,12 +134,12 @@ static int calc_crc_cont(struct nilfs_sb_info *sbi, struct buffer_head *bhs,
/**
* nilfs_read_super_root_block - read super root block
- * @sb: super_block
+ * @nilfs: nilfs object
* @sr_block: disk block number of the super root block
* @pbh: address of a buffer_head pointer to return super root buffer
* @check: CRC check flag
*/
-int nilfs_read_super_root_block(struct super_block *sb, sector_t sr_block,
+int nilfs_read_super_root_block(struct the_nilfs *nilfs, sector_t sr_block,
struct buffer_head **pbh, int check)
{
struct buffer_head *bh_sr;
@@ -164,7 +148,7 @@ int nilfs_read_super_root_block(struct super_block *sb, sector_t sr_block,
int ret;
*pbh = NULL;
- bh_sr = sb_bread(sb, sr_block);
+ bh_sr = __bread(nilfs->ns_bdev, sr_block, nilfs->ns_blocksize);
if (unlikely(!bh_sr)) {
ret = NILFS_SEG_FAIL_IO;
goto failed;
@@ -174,12 +158,13 @@ int nilfs_read_super_root_block(struct super_block *sb, sector_t sr_block,
if (check) {
unsigned bytes = le16_to_cpu(sr->sr_bytes);
- if (bytes == 0 || bytes > sb->s_blocksize) {
+ if (bytes == 0 || bytes > nilfs->ns_blocksize) {
ret = NILFS_SEG_FAIL_CHECKSUM_SUPER_ROOT;
goto failed_bh;
}
- if (calc_crc_cont(NILFS_SB(sb), bh_sr, &crc,
- sizeof(sr->sr_sum), bytes, sr_block, 1)) {
+ if (nilfs_compute_checksum(
+ nilfs, bh_sr, &crc, sizeof(sr->sr_sum), bytes,
+ sr_block, 1)) {
ret = NILFS_SEG_FAIL_IO;
goto failed_bh;
}
@@ -199,64 +184,76 @@ int nilfs_read_super_root_block(struct super_block *sb, sector_t sr_block,
}
/**
- * load_segment_summary - read segment summary of the specified partial segment
- * @sbi: nilfs_sb_info
- * @pseg_start: start disk block number of partial segment
- * @seg_seq: sequence number requested
- * @ssi: pointer to nilfs_segsum_info struct to store information
+ * nilfs_read_log_header - read summary header of the specified log
+ * @nilfs: nilfs object
+ * @start_blocknr: start block number of the log
+ * @sum: pointer to return segment summary structure
*/
-static int
-load_segment_summary(struct nilfs_sb_info *sbi, sector_t pseg_start,
- u64 seg_seq, struct nilfs_segsum_info *ssi)
+static struct buffer_head *
+nilfs_read_log_header(struct the_nilfs *nilfs, sector_t start_blocknr,
+ struct nilfs_segment_summary **sum)
{
struct buffer_head *bh_sum;
- struct nilfs_segment_summary *sum;
+
+ bh_sum = __bread(nilfs->ns_bdev, start_blocknr, nilfs->ns_blocksize);
+ if (bh_sum)
+ *sum = (struct nilfs_segment_summary *)bh_sum->b_data;
+ return bh_sum;
+}
+
+/**
+ * nilfs_validate_log - verify consistency of log
+ * @nilfs: nilfs object
+ * @seg_seq: sequence number of segment
+ * @bh_sum: buffer head of summary block
+ * @sum: segment summary struct
+ */
+static int nilfs_validate_log(struct the_nilfs *nilfs, u64 seg_seq,
+ struct buffer_head *bh_sum,
+ struct nilfs_segment_summary *sum)
+{
unsigned long nblock;
u32 crc;
- int ret = NILFS_SEG_FAIL_IO;
+ int ret;
- bh_sum = sb_bread(sbi->s_super, pseg_start);
- if (!bh_sum)
+ ret = NILFS_SEG_FAIL_MAGIC;
+ if (le32_to_cpu(sum->ss_magic) != NILFS_SEGSUM_MAGIC)
goto out;
- sum = (struct nilfs_segment_summary *)bh_sum->b_data;
-
- /* Check consistency of segment summary */
- if (le32_to_cpu(sum->ss_magic) != NILFS_SEGSUM_MAGIC) {
- ret = NILFS_SEG_FAIL_MAGIC;
- goto failed;
- }
- store_segsum_info(ssi, sum, sbi->s_super->s_blocksize);
- if (seg_seq != ssi->seg_seq) {
- ret = NILFS_SEG_FAIL_SEQ;
- goto failed;
- }
+ ret = NILFS_SEG_FAIL_SEQ;
+ if (le64_to_cpu(sum->ss_seq) != seg_seq)
+ goto out;
- nblock = ssi->nblocks;
- if (unlikely(nblock == 0 ||
- nblock > sbi->s_nilfs->ns_blocks_per_segment)) {
+ nblock = le32_to_cpu(sum->ss_nblocks);
+ ret = NILFS_SEG_FAIL_CONSISTENCY;
+ if (unlikely(nblock == 0 || nblock > nilfs->ns_blocks_per_segment))
/* This limits the number of blocks read in the CRC check */
- ret = NILFS_SEG_FAIL_CONSISTENCY;
- goto failed;
- }
- if (calc_crc_cont(sbi, bh_sum, &crc, sizeof(sum->ss_datasum),
- ((u64)nblock << sbi->s_super->s_blocksize_bits),
- pseg_start, nblock)) {
- ret = NILFS_SEG_FAIL_IO;
- goto failed;
- }
- if (crc == le32_to_cpu(sum->ss_datasum))
- ret = 0;
- else
- ret = NILFS_SEG_FAIL_CHECKSUM_FULL;
- failed:
- brelse(bh_sum);
- out:
+ goto out;
+
+ ret = NILFS_SEG_FAIL_IO;
+ if (nilfs_compute_checksum(nilfs, bh_sum, &crc, sizeof(sum->ss_datasum),
+ ((u64)nblock << nilfs->ns_blocksize_bits),
+ bh_sum->b_blocknr, nblock))
+ goto out;
+
+ ret = NILFS_SEG_FAIL_CHECKSUM_FULL;
+ if (crc != le32_to_cpu(sum->ss_datasum))
+ goto out;
+ ret = 0;
+out:
return ret;
}
-static void *segsum_get(struct super_block *sb, struct buffer_head **pbh,
- unsigned int *offset, unsigned int bytes)
+/**
+ * nilfs_read_summary_info - read an item on summary blocks of a log
+ * @nilfs: nilfs object
+ * @pbh: the current buffer head on summary blocks [in, out]
+ * @offset: the current byte offset on summary blocks [in, out]
+ * @bytes: byte size of the item to be read
+ */
+static void *nilfs_read_summary_info(struct the_nilfs *nilfs,
+ struct buffer_head **pbh,
+ unsigned int *offset, unsigned int bytes)
{
void *ptr;
sector_t blocknr;
@@ -265,7 +262,8 @@ static void *segsum_get(struct super_block *sb, struct buffer_head **pbh,
if (bytes > (*pbh)->b_size - *offset) {
blocknr = (*pbh)->b_blocknr;
brelse(*pbh);
- *pbh = sb_bread(sb, blocknr + 1);
+ *pbh = __bread(nilfs->ns_bdev, blocknr + 1,
+ nilfs->ns_blocksize);
if (unlikely(!*pbh))
return NULL;
*offset = 0;
@@ -275,9 +273,18 @@ static void *segsum_get(struct super_block *sb, struct buffer_head **pbh,
return ptr;
}
-static void segsum_skip(struct super_block *sb, struct buffer_head **pbh,
- unsigned int *offset, unsigned int bytes,
- unsigned long count)
+/**
+ * nilfs_skip_summary_info - skip items on summary blocks of a log
+ * @nilfs: nilfs object
+ * @pbh: the current buffer head on summary blocks [in, out]
+ * @offset: the current byte offset on summary blocks [in, out]
+ * @bytes: byte size of the item to be skipped
+ * @count: number of items to be skipped
+ */
+static void nilfs_skip_summary_info(struct the_nilfs *nilfs,
+ struct buffer_head **pbh,
+ unsigned int *offset, unsigned int bytes,
+ unsigned long count)
{
unsigned int rest_item_in_current_block
= ((*pbh)->b_size - *offset) / bytes;
@@ -294,36 +301,46 @@ static void segsum_skip(struct super_block *sb, struct buffer_head **pbh,
*offset = bytes * (count - (bcnt - 1) * nitem_per_block);
brelse(*pbh);
- *pbh = sb_bread(sb, blocknr + bcnt);
+ *pbh = __bread(nilfs->ns_bdev, blocknr + bcnt,
+ nilfs->ns_blocksize);
}
}
-static int
-collect_blocks_from_segsum(struct nilfs_sb_info *sbi, sector_t sum_blocknr,
- struct nilfs_segsum_info *ssi,
- struct list_head *head)
+/**
+ * nilfs_scan_dsync_log - get block information of a log written for data sync
+ * @nilfs: nilfs object
+ * @start_blocknr: start block number of the log
+ * @sum: log summary information
+ * @head: list head to add nilfs_recovery_block struct
+ */
+static int nilfs_scan_dsync_log(struct the_nilfs *nilfs, sector_t start_blocknr,
+ struct nilfs_segment_summary *sum,
+ struct list_head *head)
{
struct buffer_head *bh;
unsigned int offset;
- unsigned long nfinfo = ssi->nfinfo;
- sector_t blocknr = sum_blocknr + ssi->nsumblk;
+ u32 nfinfo, sumbytes;
+ sector_t blocknr;
ino_t ino;
int err = -EIO;
+ nfinfo = le32_to_cpu(sum->ss_nfinfo);
if (!nfinfo)
return 0;
- bh = sb_bread(sbi->s_super, sum_blocknr);
+ sumbytes = le32_to_cpu(sum->ss_sumbytes);
+ blocknr = start_blocknr + DIV_ROUND_UP(sumbytes, nilfs->ns_blocksize);
+ bh = __bread(nilfs->ns_bdev, start_blocknr, nilfs->ns_blocksize);
if (unlikely(!bh))
goto out;
- offset = le16_to_cpu(
- ((struct nilfs_segment_summary *)bh->b_data)->ss_bytes);
+ offset = le16_to_cpu(sum->ss_bytes);
for (;;) {
unsigned long nblocks, ndatablk, nnodeblk;
struct nilfs_finfo *finfo;
- finfo = segsum_get(sbi->s_super, &bh, &offset, sizeof(*finfo));
+ finfo = nilfs_read_summary_info(nilfs, &bh, &offset,
+ sizeof(*finfo));
if (unlikely(!finfo))
goto out;
@@ -336,8 +353,8 @@ collect_blocks_from_segsum(struct nilfs_sb_info *sbi, sector_t sum_blocknr,
struct nilfs_recovery_block *rb;
struct nilfs_binfo_v *binfo;
- binfo = segsum_get(sbi->s_super, &bh, &offset,
- sizeof(*binfo));
+ binfo = nilfs_read_summary_info(nilfs, &bh, &offset,
+ sizeof(*binfo));
if (unlikely(!binfo))
goto out;
@@ -355,9 +372,9 @@ collect_blocks_from_segsum(struct nilfs_sb_info *sbi, sector_t sum_blocknr,
}
if (--nfinfo == 0)
break;
- blocknr += nnodeblk; /* always 0 for the data sync segments */
- segsum_skip(sbi->s_super, &bh, &offset, sizeof(__le64),
- nnodeblk);
+ blocknr += nnodeblk; /* always 0 for data sync logs */
+ nilfs_skip_summary_info(nilfs, &bh, &offset, sizeof(__le64),
+ nnodeblk);
if (unlikely(!bh))
goto out;
}
@@ -467,14 +484,14 @@ static int nilfs_prepare_segment_for_recovery(struct the_nilfs *nilfs,
return err;
}
-static int nilfs_recovery_copy_block(struct nilfs_sb_info *sbi,
+static int nilfs_recovery_copy_block(struct the_nilfs *nilfs,
struct nilfs_recovery_block *rb,
struct page *page)
{
struct buffer_head *bh_org;
void *kaddr;
- bh_org = sb_bread(sbi->s_super, rb->blocknr);
+ bh_org = __bread(nilfs->ns_bdev, rb->blocknr, nilfs->ns_blocksize);
if (unlikely(!bh_org))
return -EIO;
@@ -485,13 +502,14 @@ static int nilfs_recovery_copy_block(struct nilfs_sb_info *sbi,
return 0;
}
-static int recover_dsync_blocks(struct nilfs_sb_info *sbi,
- struct list_head *head,
- unsigned long *nr_salvaged_blocks)
+static int nilfs_recover_dsync_blocks(struct the_nilfs *nilfs,
+ struct nilfs_sb_info *sbi,
+ struct list_head *head,
+ unsigned long *nr_salvaged_blocks)
{
struct inode *inode;
struct nilfs_recovery_block *rb, *n;
- unsigned blocksize = sbi->s_super->s_blocksize;
+ unsigned blocksize = nilfs->ns_blocksize;
struct page *page;
loff_t pos;
int err = 0, err2 = 0;
@@ -511,7 +529,7 @@ static int recover_dsync_blocks(struct nilfs_sb_info *sbi,
if (unlikely(err))
goto failed_inode;
- err = nilfs_recovery_copy_block(sbi, rb, page);
+ err = nilfs_recovery_copy_block(nilfs, rb, page);
if (unlikely(err))
goto failed_page;
@@ -551,18 +569,20 @@ static int recover_dsync_blocks(struct nilfs_sb_info *sbi,
/**
* nilfs_do_roll_forward - salvage logical segments newer than the latest
* checkpoint
+ * @nilfs: nilfs object
* @sbi: nilfs_sb_info
- * @nilfs: the_nilfs
* @ri: pointer to a nilfs_recovery_info
*/
static int nilfs_do_roll_forward(struct the_nilfs *nilfs,
struct nilfs_sb_info *sbi,
struct nilfs_recovery_info *ri)
{
- struct nilfs_segsum_info ssi;
+ struct buffer_head *bh_sum = NULL;
+ struct nilfs_segment_summary *sum;
sector_t pseg_start;
sector_t seg_start, seg_end; /* Starting/ending DBN of full segment */
unsigned long nsalvaged_blocks = 0;
+ unsigned int flags;
u64 seg_seq;
__u64 segnum, nextnum = 0;
int empty_seg = 0;
@@ -581,8 +601,14 @@ static int nilfs_do_roll_forward(struct the_nilfs *nilfs,
nilfs_get_segment_range(nilfs, segnum, &seg_start, &seg_end);
while (segnum != ri->ri_segnum || pseg_start <= ri->ri_pseg_start) {
+ brelse(bh_sum);
+ bh_sum = nilfs_read_log_header(nilfs, pseg_start, &sum);
+ if (!bh_sum) {
+ err = -EIO;
+ goto failed;
+ }
- ret = load_segment_summary(sbi, pseg_start, seg_seq, &ssi);
+ ret = nilfs_validate_log(nilfs, seg_seq, bh_sum, sum);
if (ret) {
if (ret == NILFS_SEG_FAIL_IO) {
err = -EIO;
@@ -590,33 +616,38 @@ static int nilfs_do_roll_forward(struct the_nilfs *nilfs,
}
goto strayed;
}
- if (unlikely(NILFS_SEG_HAS_SR(&ssi)))
+
+ flags = le16_to_cpu(sum->ss_flags);
+ if (flags & NILFS_SS_SR)
goto confused;
/* Found a valid partial segment; do recovery actions */
- nextnum = nilfs_get_segnum_of_block(nilfs, ssi.next);
+ nextnum = nilfs_get_segnum_of_block(nilfs,
+ le64_to_cpu(sum->ss_next));
empty_seg = 0;
- nilfs->ns_ctime = ssi.ctime;
- if (!(ssi.flags & NILFS_SS_GC))
- nilfs->ns_nongc_ctime = ssi.ctime;
+ nilfs->ns_ctime = le64_to_cpu(sum->ss_create);
+ if (!(flags & NILFS_SS_GC))
+ nilfs->ns_nongc_ctime = nilfs->ns_ctime;
switch (state) {
case RF_INIT_ST:
- if (!NILFS_SEG_LOGBGN(&ssi) || !NILFS_SEG_DSYNC(&ssi))
+ if (!(flags & NILFS_SS_LOGBGN) ||
+ !(flags & NILFS_SS_SYNDT))
goto try_next_pseg;
state = RF_DSYNC_ST;
/* Fall through */
case RF_DSYNC_ST:
- if (!NILFS_SEG_DSYNC(&ssi))
+ if (!(flags & NILFS_SS_SYNDT))
goto confused;
- err = collect_blocks_from_segsum(
- sbi, pseg_start, &ssi, &dsync_blocks);
+ err = nilfs_scan_dsync_log(nilfs, pseg_start, sum,
+ &dsync_blocks);
if (unlikely(err))
goto failed;
- if (NILFS_SEG_LOGEND(&ssi)) {
- err = recover_dsync_blocks(
- sbi, &dsync_blocks, &nsalvaged_blocks);
+ if (flags & NILFS_SS_LOGEND) {
+ err = nilfs_recover_dsync_blocks(
+ nilfs, sbi, &dsync_blocks,
+ &nsalvaged_blocks);
if (unlikely(err))
goto failed;
state = RF_INIT_ST;
@@ -627,7 +658,7 @@ static int nilfs_do_roll_forward(struct the_nilfs *nilfs,
try_next_pseg:
if (pseg_start == ri->ri_lsegs_end)
break;
- pseg_start += ssi.nblocks;
+ pseg_start += le32_to_cpu(sum->ss_nblocks);
if (pseg_start < seg_end)
continue;
goto feed_segment;
@@ -652,8 +683,9 @@ static int nilfs_do_roll_forward(struct the_nilfs *nilfs,
ri->ri_need_recovery = NILFS_RECOVERY_ROLLFORWARD_DONE;
}
out:
+ brelse(bh_sum);
dispose_recovery_list(&dsync_blocks);
- nilfs_detach_writer(sbi->s_nilfs, sbi);
+ nilfs_detach_writer(nilfs, sbi);
return err;
confused:
@@ -667,7 +699,6 @@ static int nilfs_do_roll_forward(struct the_nilfs *nilfs,
}
static void nilfs_finish_roll_forward(struct the_nilfs *nilfs,
- struct nilfs_sb_info *sbi,
struct nilfs_recovery_info *ri)
{
struct buffer_head *bh;
@@ -677,7 +708,7 @@ static void nilfs_finish_roll_forward(struct the_nilfs *nilfs,
nilfs_get_segnum_of_block(nilfs, ri->ri_super_root))
return;
- bh = sb_getblk(sbi->s_super, ri->ri_lsegs_start);
+ bh = __getblk(nilfs->ns_bdev, ri->ri_lsegs_start, nilfs->ns_blocksize);
BUG_ON(!bh);
memset(bh->b_data, 0, bh->b_size);
set_buffer_dirty(bh);
@@ -690,9 +721,8 @@ static void nilfs_finish_roll_forward(struct the_nilfs *nilfs,
}
/**
- * nilfs_recover_logical_segments - salvage logical segments written after
- * the latest super root
- * @nilfs: the_nilfs
+ * nilfs_salvage_orphan_logs - salvage logs written after the latest checkpoint
+ * @nilfs: nilfs object
* @sbi: nilfs_sb_info
* @ri: pointer to a nilfs_recovery_info struct to store search results.
*
@@ -709,9 +739,9 @@ static void nilfs_finish_roll_forward(struct the_nilfs *nilfs,
*
* %-ENOMEM - Insufficient memory available.
*/
-int nilfs_recover_logical_segments(struct the_nilfs *nilfs,
- struct nilfs_sb_info *sbi,
- struct nilfs_recovery_info *ri)
+int nilfs_salvage_orphan_logs(struct the_nilfs *nilfs,
+ struct nilfs_sb_info *sbi,
+ struct nilfs_recovery_info *ri)
{
int err;
@@ -751,7 +781,7 @@ int nilfs_recover_logical_segments(struct the_nilfs *nilfs,
goto failed;
}
- nilfs_finish_roll_forward(nilfs, sbi, ri);
+ nilfs_finish_roll_forward(nilfs, ri);
}
failed:
@@ -762,7 +792,6 @@ int nilfs_recover_logical_segments(struct the_nilfs *nilfs,
/**
* nilfs_search_super_root - search the latest valid super root
* @nilfs: the_nilfs
- * @sbi: nilfs_sb_info
* @ri: pointer to a nilfs_recovery_info struct to store search results.
*
* nilfs_search_super_root() looks for the latest super-root from a partial
@@ -775,14 +804,19 @@ int nilfs_recover_logical_segments(struct the_nilfs *nilfs,
* %-EINVAL - No valid segment found
*
* %-EIO - I/O error
+ *
+ * %-ENOMEM - Insufficient memory available.
*/
-int nilfs_search_super_root(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi,
+int nilfs_search_super_root(struct the_nilfs *nilfs,
struct nilfs_recovery_info *ri)
{
- struct nilfs_segsum_info ssi;
+ struct buffer_head *bh_sum = NULL;
+ struct nilfs_segment_summary *sum;
sector_t pseg_start, pseg_end, sr_pseg_start = 0;
sector_t seg_start, seg_end; /* range of full segment (block number) */
sector_t b, end;
+ unsigned long nblocks;
+ unsigned int flags;
u64 seg_seq;
__u64 segnum, nextnum = 0;
__u64 cno;
@@ -801,17 +835,24 @@ int nilfs_search_super_root(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi,
/* Read ahead segment */
b = seg_start;
while (b <= seg_end)
- sb_breadahead(sbi->s_super, b++);
+ __breadahead(nilfs->ns_bdev, b++, nilfs->ns_blocksize);
for (;;) {
- /* Load segment summary */
- ret = load_segment_summary(sbi, pseg_start, seg_seq, &ssi);
+ brelse(bh_sum);
+ ret = NILFS_SEG_FAIL_IO;
+ bh_sum = nilfs_read_log_header(nilfs, pseg_start, &sum);
+ if (!bh_sum)
+ goto failed;
+
+ ret = nilfs_validate_log(nilfs, seg_seq, bh_sum, sum);
if (ret) {
if (ret == NILFS_SEG_FAIL_IO)
goto failed;
goto strayed;
}
- pseg_end = pseg_start + ssi.nblocks - 1;
+
+ nblocks = le32_to_cpu(sum->ss_nblocks);
+ pseg_end = pseg_start + nblocks - 1;
if (unlikely(pseg_end > seg_end)) {
ret = NILFS_SEG_FAIL_CONSISTENCY;
goto strayed;
@@ -821,11 +862,13 @@ int nilfs_search_super_root(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi,
ri->ri_pseg_start = pseg_start;
ri->ri_seq = seg_seq;
ri->ri_segnum = segnum;
- nextnum = nilfs_get_segnum_of_block(nilfs, ssi.next);
+ nextnum = nilfs_get_segnum_of_block(nilfs,
+ le64_to_cpu(sum->ss_next));
ri->ri_nextnum = nextnum;
empty_seg = 0;
- if (!NILFS_SEG_HAS_SR(&ssi) && !scan_newer) {
+ flags = le16_to_cpu(sum->ss_flags);
+ if (!(flags & NILFS_SS_SR) && !scan_newer) {
/* This will never happen because a superblock
(last_segment) always points to a pseg
having a super root. */
@@ -836,14 +879,15 @@ int nilfs_search_super_root(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi,
if (pseg_start == seg_start) {
nilfs_get_segment_range(nilfs, nextnum, &b, &end);
while (b <= end)
- sb_breadahead(sbi->s_super, b++);
+ __breadahead(nilfs->ns_bdev, b++,
+ nilfs->ns_blocksize);
}
- if (!NILFS_SEG_HAS_SR(&ssi)) {
- if (!ri->ri_lsegs_start && NILFS_SEG_LOGBGN(&ssi)) {
+ if (!(flags & NILFS_SS_SR)) {
+ if (!ri->ri_lsegs_start && (flags & NILFS_SS_LOGBGN)) {
ri->ri_lsegs_start = pseg_start;
ri->ri_lsegs_start_seq = seg_seq;
}
- if (NILFS_SEG_LOGEND(&ssi))
+ if (flags & NILFS_SS_LOGEND)
ri->ri_lsegs_end = pseg_start;
goto try_next_pseg;
}
@@ -854,12 +898,12 @@ int nilfs_search_super_root(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi,
ri->ri_lsegs_start = ri->ri_lsegs_end = 0;
nilfs_dispose_segment_list(&segments);
- nilfs->ns_pseg_offset = (sr_pseg_start = pseg_start)
- + ssi.nblocks - seg_start;
+ sr_pseg_start = pseg_start;
+ nilfs->ns_pseg_offset = pseg_start + nblocks - seg_start;
nilfs->ns_seg_seq = seg_seq;
nilfs->ns_segnum = segnum;
nilfs->ns_cno = cno; /* nilfs->ns_cno = ri->ri_cno + 1 */
- nilfs->ns_ctime = ssi.ctime;
+ nilfs->ns_ctime = le64_to_cpu(sum->ss_create);
nilfs->ns_nextnum = nextnum;
if (scan_newer)
@@ -870,15 +914,9 @@ int nilfs_search_super_root(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi,
scan_newer = 1;
}
- /* reset region for roll-forward */
- pseg_start += ssi.nblocks;
- if (pseg_start < seg_end)
- continue;
- goto feed_segment;
-
try_next_pseg:
/* Standing on a course, or met an inconsistent state */
- pseg_start += ssi.nblocks;
+ pseg_start += nblocks;
if (pseg_start < seg_end)
continue;
goto feed_segment;
@@ -909,6 +947,7 @@ int nilfs_search_super_root(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi,
super_root_found:
/* Updating pointers relating to the latest checkpoint */
+ brelse(bh_sum);
list_splice_tail(&segments, &ri->ri_used_segments);
nilfs->ns_last_pseg = sr_pseg_start;
nilfs->ns_last_seq = nilfs->ns_seg_seq;
@@ -916,6 +955,7 @@ int nilfs_search_super_root(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi,
return 0;
failed:
+ brelse(bh_sum);
nilfs_dispose_segment_list(&segments);
return (ret < 0) ? ret : nilfs_warn_segment_error(ret);
}
diff --git a/fs/nilfs2/segbuf.h b/fs/nilfs2/segbuf.h
index 85fbb66455e..b04f08cc239 100644
--- a/fs/nilfs2/segbuf.h
+++ b/fs/nilfs2/segbuf.h
@@ -54,17 +54,6 @@ struct nilfs_segsum_info {
sector_t next;
};
-/* macro for the flags */
-#define NILFS_SEG_HAS_SR(sum) ((sum)->flags & NILFS_SS_SR)
-#define NILFS_SEG_LOGBGN(sum) ((sum)->flags & NILFS_SS_LOGBGN)
-#define NILFS_SEG_LOGEND(sum) ((sum)->flags & NILFS_SS_LOGEND)
-#define NILFS_SEG_DSYNC(sum) ((sum)->flags & NILFS_SS_SYNDT)
-#define NILFS_SEG_SIMPLEX(sum) \
- (((sum)->flags & (NILFS_SS_LOGBGN | NILFS_SS_LOGEND)) == \
- (NILFS_SS_LOGBGN | NILFS_SS_LOGEND))
-
-#define NILFS_SEG_EMPTY(sum) ((sum)->nblocks == (sum)->nsumblk)
-
/**
* struct nilfs_segment_buffer - Segment buffer
* @sb_super: back pointer to a superblock struct
@@ -141,6 +130,19 @@ int nilfs_segbuf_extend_payload(struct nilfs_segment_buffer *,
struct buffer_head **);
void nilfs_segbuf_fill_in_segsum(struct nilfs_segment_buffer *);
+static inline int nilfs_segbuf_simplex(struct nilfs_segment_buffer *segbuf)
+{
+ unsigned int flags = segbuf->sb_sum.flags;
+
+ return (flags & (NILFS_SS_LOGBGN | NILFS_SS_LOGEND)) ==
+ (NILFS_SS_LOGBGN | NILFS_SS_LOGEND);
+}
+
+static inline int nilfs_segbuf_empty(struct nilfs_segment_buffer *segbuf)
+{
+ return segbuf->sb_sum.nblocks == segbuf->sb_sum.nsumblk;
+}
+
static inline void
nilfs_segbuf_add_segsum_buffer(struct nilfs_segment_buffer *segbuf,
struct buffer_head *bh)
diff --git a/fs/nilfs2/segment.c b/fs/nilfs2/segment.c
index c9201649cc4..9fd051a33c4 100644
--- a/fs/nilfs2/segment.c
+++ b/fs/nilfs2/segment.c
@@ -1914,12 +1914,12 @@ static void nilfs_segctor_complete_write(struct nilfs_sc_info *sci)
}
}
- if (!NILFS_SEG_SIMPLEX(&segbuf->sb_sum)) {
- if (NILFS_SEG_LOGBGN(&segbuf->sb_sum)) {
+ if (!nilfs_segbuf_simplex(segbuf)) {
+ if (segbuf->sb_sum.flags & NILFS_SS_LOGBGN) {
set_bit(NILFS_SC_UNCLOSED, &sci->sc_flags);
sci->sc_lseg_stime = jiffies;
}
- if (NILFS_SEG_LOGEND(&segbuf->sb_sum))
+ if (segbuf->sb_sum.flags & NILFS_SS_LOGEND)
clear_bit(NILFS_SC_UNCLOSED, &sci->sc_flags);
}
}
@@ -1951,7 +1951,6 @@ static void nilfs_segctor_complete_write(struct nilfs_sc_info *sci)
if (update_sr) {
nilfs_set_last_segment(nilfs, segbuf->sb_pseg_start,
segbuf->sb_sum.seg_seq, nilfs->ns_cno++);
- set_nilfs_sb_dirty(nilfs);
clear_bit(NILFS_SC_HAVE_DELTA, &sci->sc_flags);
clear_bit(NILFS_SC_DIRTY, &sci->sc_flags);
@@ -2082,7 +2081,7 @@ static int nilfs_segctor_do_construct(struct nilfs_sc_info *sci, int mode)
/* Avoid empty segment */
if (sci->sc_stage.scnt == NILFS_ST_DONE &&
- NILFS_SEG_EMPTY(&sci->sc_curseg->sb_sum)) {
+ nilfs_segbuf_empty(sci->sc_curseg)) {
nilfs_segctor_abort_construction(sci, nilfs, 1);
goto out;
}
@@ -2408,6 +2407,7 @@ static int nilfs_segctor_construct(struct nilfs_sc_info *sci, int mode)
{
struct nilfs_sb_info *sbi = sci->sc_sbi;
struct the_nilfs *nilfs = sbi->s_nilfs;
+ struct nilfs_super_block **sbp;
int err = 0;
nilfs_segctor_accept(sci);
@@ -2423,8 +2423,13 @@ static int nilfs_segctor_construct(struct nilfs_sc_info *sci, int mode)
if (test_bit(NILFS_SC_SUPER_ROOT, &sci->sc_flags) &&
nilfs_discontinued(nilfs)) {
down_write(&nilfs->ns_sem);
- err = nilfs_commit_super(
- sbi, nilfs_altsb_need_update(nilfs));
+ err = -EIO;
+ sbp = nilfs_prepare_super(sbi,
+ nilfs_sb_will_flip(nilfs));
+ if (likely(sbp)) {
+ nilfs_set_log_cursor(sbp[0], nilfs);
+ err = nilfs_commit_super(sbi, NILFS_SB_COMMIT);
+ }
up_write(&nilfs->ns_sem);
}
}
diff --git a/fs/nilfs2/segment.h b/fs/nilfs2/segment.h
index 01e20dbb217..17c487bd815 100644
--- a/fs/nilfs2/segment.h
+++ b/fs/nilfs2/segment.h
@@ -234,13 +234,13 @@ extern int nilfs_attach_segment_constructor(struct nilfs_sb_info *);
extern void nilfs_detach_segment_constructor(struct nilfs_sb_info *);
/* recovery.c */
-extern int nilfs_read_super_root_block(struct super_block *, sector_t,
+extern int nilfs_read_super_root_block(struct the_nilfs *, sector_t,
struct buffer_head **, int);
-extern int nilfs_search_super_root(struct the_nilfs *, struct nilfs_sb_info *,
+extern int nilfs_search_super_root(struct the_nilfs *,
struct nilfs_recovery_info *);
-extern int nilfs_recover_logical_segments(struct the_nilfs *,
- struct nilfs_sb_info *,
- struct nilfs_recovery_info *);
+extern int nilfs_salvage_orphan_logs(struct the_nilfs *,
+ struct nilfs_sb_info *,
+ struct nilfs_recovery_info *);
extern void nilfs_dispose_segment_list(struct list_head *);
#endif /* _NILFS_SEGMENT_H */
diff --git a/fs/nilfs2/super.c b/fs/nilfs2/super.c
index 414ef68931c..26078b3407c 100644
--- a/fs/nilfs2/super.c
+++ b/fs/nilfs2/super.c
@@ -55,6 +55,8 @@
#include "nilfs.h"
#include "mdt.h"
#include "alloc.h"
+#include "btree.h"
+#include "btnode.h"
#include "page.h"
#include "cpfile.h"
#include "ifile.h"
@@ -74,6 +76,25 @@ struct kmem_cache *nilfs_btree_path_cache;
static int nilfs_remount(struct super_block *sb, int *flags, char *data);
+static void nilfs_set_error(struct nilfs_sb_info *sbi)
+{
+ struct the_nilfs *nilfs = sbi->s_nilfs;
+ struct nilfs_super_block **sbp;
+
+ down_write(&nilfs->ns_sem);
+ if (!(nilfs->ns_mount_state & NILFS_ERROR_FS)) {
+ nilfs->ns_mount_state |= NILFS_ERROR_FS;
+ sbp = nilfs_prepare_super(sbi, 0);
+ if (likely(sbp)) {
+ sbp[0]->s_state |= cpu_to_le16(NILFS_ERROR_FS);
+ if (sbp[1])
+ sbp[1]->s_state |= cpu_to_le16(NILFS_ERROR_FS);
+ nilfs_commit_super(sbi, NILFS_SB_COMMIT_ALL);
+ }
+ }
+ up_write(&nilfs->ns_sem);
+}
+
/**
* nilfs_error() - report failure condition on a filesystem
*
@@ -99,16 +120,7 @@ void nilfs_error(struct super_block *sb, const char *function,
va_end(args);
if (!(sb->s_flags & MS_RDONLY)) {
- struct the_nilfs *nilfs = sbi->s_nilfs;
-
- down_write(&nilfs->ns_sem);
- if (!(nilfs->ns_mount_state & NILFS_ERROR_FS)) {
- nilfs->ns_mount_state |= NILFS_ERROR_FS;
- nilfs->ns_sbp[0]->s_state |=
- cpu_to_le16(NILFS_ERROR_FS);
- nilfs_commit_super(sbi, 1);
- }
- up_write(&nilfs->ns_sem);
+ nilfs_set_error(sbi);
if (nilfs_test_opt(sbi, ERRORS_RO)) {
printk(KERN_CRIT "Remounting filesystem read-only\n");
@@ -176,7 +188,7 @@ static void nilfs_clear_inode(struct inode *inode)
nilfs_btnode_cache_clear(&ii->i_btnode_cache);
}
-static int nilfs_sync_super(struct nilfs_sb_info *sbi, int dupsb)
+static int nilfs_sync_super(struct nilfs_sb_info *sbi, int flag)
{
struct the_nilfs *nilfs = sbi->s_nilfs;
int err;
@@ -202,12 +214,20 @@ static int nilfs_sync_super(struct nilfs_sb_info *sbi, int dupsb)
printk(KERN_ERR
"NILFS: unable to write superblock (err=%d)\n", err);
if (err == -EIO && nilfs->ns_sbh[1]) {
+ /*
+ * sbp[0] points to newer log than sbp[1],
+ * so copy sbp[0] to sbp[1] to take over sbp[0].
+ */
+ memcpy(nilfs->ns_sbp[1], nilfs->ns_sbp[0],
+ nilfs->ns_sbsize);
nilfs_fall_back_super_block(nilfs);
goto retry;
}
} else {
struct nilfs_super_block *sbp = nilfs->ns_sbp[0];
+ nilfs->ns_sbwcount++;
+
/*
* The latest segment becomes trailable from the position
* written in superblock.
@@ -216,66 +236,122 @@ static int nilfs_sync_super(struct nilfs_sb_info *sbi, int dupsb)
/* update GC protection for recent segments */
if (nilfs->ns_sbh[1]) {
- sbp = NULL;
- if (dupsb) {
+ if (flag == NILFS_SB_COMMIT_ALL) {
set_buffer_dirty(nilfs->ns_sbh[1]);
- if (!sync_dirty_buffer(nilfs->ns_sbh[1]))
- sbp = nilfs->ns_sbp[1];
+ if (sync_dirty_buffer(nilfs->ns_sbh[1]) < 0)
+ goto out;
}
+ if (le64_to_cpu(nilfs->ns_sbp[1]->s_last_cno) <
+ le64_to_cpu(nilfs->ns_sbp[0]->s_last_cno))
+ sbp = nilfs->ns_sbp[1];
}
- if (sbp) {
- spin_lock(&nilfs->ns_last_segment_lock);
- nilfs->ns_prot_seq = le64_to_cpu(sbp->s_last_seq);
- spin_unlock(&nilfs->ns_last_segment_lock);
- }
- }
+ spin_lock(&nilfs->ns_last_segment_lock);
+ nilfs->ns_prot_seq = le64_to_cpu(sbp->s_last_seq);
+ spin_unlock(&nilfs->ns_last_segment_lock);
+ }
+ out:
return err;
}
-int nilfs_commit_super(struct nilfs_sb_info *sbi, int dupsb)
+void nilfs_set_log_cursor(struct nilfs_super_block *sbp,
+ struct the_nilfs *nilfs)
+{
+ sector_t nfreeblocks;
+
+ /* nilfs->ns_sem must be locked by the caller. */
+ nilfs_count_free_blocks(nilfs, &nfreeblocks);
+ sbp->s_free_blocks_count = cpu_to_le64(nfreeblocks);
+
+ spin_lock(&nilfs->ns_last_segment_lock);
+ sbp->s_last_seq = cpu_to_le64(nilfs->ns_last_seq);
+ sbp->s_last_pseg = cpu_to_le64(nilfs->ns_last_pseg);
+ sbp->s_last_cno = cpu_to_le64(nilfs->ns_last_cno);
+ spin_unlock(&nilfs->ns_last_segment_lock);
+}
+
+struct nilfs_super_block **nilfs_prepare_super(struct nilfs_sb_info *sbi,
+ int flip)
{
struct the_nilfs *nilfs = sbi->s_nilfs;
struct nilfs_super_block **sbp = nilfs->ns_sbp;
- sector_t nfreeblocks;
- time_t t;
- int err;
- /* nilfs->sem must be locked by the caller. */
+ /* nilfs->ns_sem must be locked by the caller. */
if (sbp[0]->s_magic != cpu_to_le16(NILFS_SUPER_MAGIC)) {
- if (sbp[1] && sbp[1]->s_magic == cpu_to_le16(NILFS_SUPER_MAGIC))
- nilfs_swap_super_block(nilfs);
- else {
+ if (sbp[1] &&
+ sbp[1]->s_magic == cpu_to_le16(NILFS_SUPER_MAGIC)) {
+ memcpy(sbp[0], sbp[1], nilfs->ns_sbsize);
+ } else {
printk(KERN_CRIT "NILFS: superblock broke on dev %s\n",
sbi->s_super->s_id);
- return -EIO;
+ return NULL;
}
+ } else if (sbp[1] &&
+ sbp[1]->s_magic != cpu_to_le16(NILFS_SUPER_MAGIC)) {
+ memcpy(sbp[1], sbp[0], nilfs->ns_sbsize);
}
- err = nilfs_count_free_blocks(nilfs, &nfreeblocks);
- if (unlikely(err)) {
- printk(KERN_ERR "NILFS: failed to count free blocks\n");
- return err;
- }
- spin_lock(&nilfs->ns_last_segment_lock);
- sbp[0]->s_last_seq = cpu_to_le64(nilfs->ns_last_seq);
- sbp[0]->s_last_pseg = cpu_to_le64(nilfs->ns_last_pseg);
- sbp[0]->s_last_cno = cpu_to_le64(nilfs->ns_last_cno);
- spin_unlock(&nilfs->ns_last_segment_lock);
+ if (flip && sbp[1])
+ nilfs_swap_super_block(nilfs);
+
+ return sbp;
+}
+
+int nilfs_commit_super(struct nilfs_sb_info *sbi, int flag)
+{
+ struct the_nilfs *nilfs = sbi->s_nilfs;
+ struct nilfs_super_block **sbp = nilfs->ns_sbp;
+ time_t t;
+
+ /* nilfs->ns_sem must be locked by the caller. */
t = get_seconds();
- nilfs->ns_sbwtime[0] = t;
- sbp[0]->s_free_blocks_count = cpu_to_le64(nfreeblocks);
+ nilfs->ns_sbwtime = t;
sbp[0]->s_wtime = cpu_to_le64(t);
sbp[0]->s_sum = 0;
sbp[0]->s_sum = cpu_to_le32(crc32_le(nilfs->ns_crc_seed,
(unsigned char *)sbp[0],
nilfs->ns_sbsize));
- if (dupsb && sbp[1]) {
- memcpy(sbp[1], sbp[0], nilfs->ns_sbsize);
- nilfs->ns_sbwtime[1] = t;
+ if (flag == NILFS_SB_COMMIT_ALL && sbp[1]) {
+ sbp[1]->s_wtime = sbp[0]->s_wtime;
+ sbp[1]->s_sum = 0;
+ sbp[1]->s_sum = cpu_to_le32(crc32_le(nilfs->ns_crc_seed,
+ (unsigned char *)sbp[1],
+ nilfs->ns_sbsize));
}
clear_nilfs_sb_dirty(nilfs);
- return nilfs_sync_super(sbi, dupsb);
+ return nilfs_sync_super(sbi, flag);
+}
+
+/**
+ * nilfs_cleanup_super() - write filesystem state for cleanup
+ * @sbi: nilfs_sb_info to be unmounted or degraded to read-only
+ *
+ * This function restores state flags in the on-disk super block.
+ * This will set "clean" flag (i.e. NILFS_VALID_FS) unless the
+ * filesystem was not clean previously.
+ */
+int nilfs_cleanup_super(struct nilfs_sb_info *sbi)
+{
+ struct nilfs_super_block **sbp;
+ int flag = NILFS_SB_COMMIT;
+ int ret = -EIO;
+
+ sbp = nilfs_prepare_super(sbi, 0);
+ if (sbp) {
+ sbp[0]->s_state = cpu_to_le16(sbi->s_nilfs->ns_mount_state);
+ nilfs_set_log_cursor(sbp[0], sbi->s_nilfs);
+ if (sbp[1] && sbp[0]->s_last_cno == sbp[1]->s_last_cno) {
+ /*
+ * make the "clean" flag also to the opposite
+ * super block if both super blocks point to
+ * the same checkpoint.
+ */
+ sbp[1]->s_state = sbp[0]->s_state;
+ flag = NILFS_SB_COMMIT_ALL;
+ }
+ ret = nilfs_commit_super(sbi, flag);
+ }
+ return ret;
}
static void nilfs_put_super(struct super_block *sb)
@@ -289,8 +365,7 @@ static void nilfs_put_super(struct super_block *sb)
if (!(sb->s_flags & MS_RDONLY)) {
down_write(&nilfs->ns_sem);
- nilfs->ns_sbp[0]->s_state = cpu_to_le16(nilfs->ns_mount_state);
- nilfs_commit_super(sbi, 1);
+ nilfs_cleanup_super(sbi);
up_write(&nilfs->ns_sem);
}
down_write(&nilfs->ns_super_sem);
@@ -311,6 +386,7 @@ static int nilfs_sync_fs(struct super_block *sb, int wait)
{
struct nilfs_sb_info *sbi = NILFS_SB(sb);
struct the_nilfs *nilfs = sbi->s_nilfs;
+ struct nilfs_super_block **sbp;
int err = 0;
/* This function is called when super block should be written back */
@@ -318,8 +394,13 @@ static int nilfs_sync_fs(struct super_block *sb, int wait)
err = nilfs_construct_segment(sb);
down_write(&nilfs->ns_sem);
- if (nilfs_sb_dirty(nilfs))
- nilfs_commit_super(sbi, 1);
+ if (nilfs_sb_dirty(nilfs)) {
+ sbp = nilfs_prepare_super(sbi, nilfs_sb_will_flip(nilfs));
+ if (likely(sbp)) {
+ nilfs_set_log_cursor(sbp[0], nilfs);
+ nilfs_commit_super(sbi, NILFS_SB_COMMIT);
+ }
+ }
up_write(&nilfs->ns_sem);
return err;
@@ -442,20 +523,20 @@ static int nilfs_show_options(struct seq_file *seq, struct vfsmount *vfs)
struct nilfs_sb_info *sbi = NILFS_SB(sb);
if (!nilfs_test_opt(sbi, BARRIER))
- seq_printf(seq, ",nobarrier");
+ seq_puts(seq, ",nobarrier");
if (nilfs_test_opt(sbi, SNAPSHOT))
seq_printf(seq, ",cp=%llu",
(unsigned long long int)sbi->s_snapshot_cno);
if (nilfs_test_opt(sbi, ERRORS_PANIC))
- seq_printf(seq, ",errors=panic");
+ seq_puts(seq, ",errors=panic");
if (nilfs_test_opt(sbi, ERRORS_CONT))
- seq_printf(seq, ",errors=continue");
+ seq_puts(seq, ",errors=continue");
if (nilfs_test_opt(sbi, STRICT_ORDER))
- seq_printf(seq, ",order=strict");
+ seq_puts(seq, ",order=strict");
if (nilfs_test_opt(sbi, NORECOVERY))
- seq_printf(seq, ",norecovery");
+ seq_puts(seq, ",norecovery");
if (nilfs_test_opt(sbi, DISCARD))
- seq_printf(seq, ",discard");
+ seq_puts(seq, ",discard");
return 0;
}
@@ -524,23 +605,25 @@ static const struct export_operations nilfs_export_ops = {
enum {
Opt_err_cont, Opt_err_panic, Opt_err_ro,
- Opt_nobarrier, Opt_snapshot, Opt_order, Opt_norecovery,
- Opt_discard, Opt_err,
+ Opt_barrier, Opt_nobarrier, Opt_snapshot, Opt_order, Opt_norecovery,
+ Opt_discard, Opt_nodiscard, Opt_err,
};
static match_table_t tokens = {
{Opt_err_cont, "errors=continue"},
{Opt_err_panic, "errors=panic"},
{Opt_err_ro, "errors=remount-ro"},
+ {Opt_barrier, "barrier"},
{Opt_nobarrier, "nobarrier"},
{Opt_snapshot, "cp=%u"},
{Opt_order, "order=%s"},
{Opt_norecovery, "norecovery"},
{Opt_discard, "discard"},
+ {Opt_nodiscard, "nodiscard"},
{Opt_err, NULL}
};
-static int parse_options(char *options, struct super_block *sb)
+static int parse_options(char *options, struct super_block *sb, int is_remount)
{
struct nilfs_sb_info *sbi = NILFS_SB(sb);
char *p;
@@ -557,6 +640,9 @@ static int parse_options(char *options, struct super_block *sb)
token = match_token(p, tokens, args);
switch (token) {
+ case Opt_barrier:
+ nilfs_set_opt(sbi, BARRIER);
+ break;
case Opt_nobarrier:
nilfs_clear_opt(sbi, BARRIER);
break;
@@ -582,8 +668,26 @@ static int parse_options(char *options, struct super_block *sb)
case Opt_snapshot:
if (match_int(&args[0], &option) || option <= 0)
return 0;
- if (!(sb->s_flags & MS_RDONLY))
+ if (is_remount) {
+ if (!nilfs_test_opt(sbi, SNAPSHOT)) {
+ printk(KERN_ERR
+ "NILFS: cannot change regular "
+ "mount to snapshot.\n");
+ return 0;
+ } else if (option != sbi->s_snapshot_cno) {
+ printk(KERN_ERR
+ "NILFS: cannot remount to a "
+ "different snapshot.\n");
+ return 0;
+ }
+ break;
+ }
+ if (!(sb->s_flags & MS_RDONLY)) {
+ printk(KERN_ERR "NILFS: cannot mount snapshot "
+ "read/write. A read-only option is "
+ "required.\n");
return 0;
+ }
sbi->s_snapshot_cno = option;
nilfs_set_opt(sbi, SNAPSHOT);
break;
@@ -593,6 +697,9 @@ static int parse_options(char *options, struct super_block *sb)
case Opt_discard:
nilfs_set_opt(sbi, DISCARD);
break;
+ case Opt_nodiscard:
+ nilfs_clear_opt(sbi, DISCARD);
+ break;
default:
printk(KERN_ERR
"NILFS: Unrecognized mount option \"%s\"\n", p);
@@ -613,11 +720,18 @@ nilfs_set_default_options(struct nilfs_sb_info *sbi,
static int nilfs_setup_super(struct nilfs_sb_info *sbi)
{
struct the_nilfs *nilfs = sbi->s_nilfs;
- struct nilfs_super_block *sbp = nilfs->ns_sbp[0];
- int max_mnt_count = le16_to_cpu(sbp->s_max_mnt_count);
- int mnt_count = le16_to_cpu(sbp->s_mnt_count);
+ struct nilfs_super_block **sbp;
+ int max_mnt_count;
+ int mnt_count;
+
+ /* nilfs->ns_sem must be locked by the caller. */
+ sbp = nilfs_prepare_super(sbi, 0);
+ if (!sbp)
+ return -EIO;
+
+ max_mnt_count = le16_to_cpu(sbp[0]->s_max_mnt_count);
+ mnt_count = le16_to_cpu(sbp[0]->s_mnt_count);
- /* nilfs->sem must be locked by the caller. */
if (nilfs->ns_mount_state & NILFS_ERROR_FS) {
printk(KERN_WARNING
"NILFS warning: mounting fs with errors\n");
@@ -628,12 +742,15 @@ static int nilfs_setup_super(struct nilfs_sb_info *sbi)
#endif
}
if (!max_mnt_count)
- sbp->s_max_mnt_count = cpu_to_le16(NILFS_DFL_MAX_MNT_COUNT);
-
- sbp->s_mnt_count = cpu_to_le16(mnt_count + 1);
- sbp->s_state = cpu_to_le16(le16_to_cpu(sbp->s_state) & ~NILFS_VALID_FS);
- sbp->s_mtime = cpu_to_le64(get_seconds());
- return nilfs_commit_super(sbi, 1);
+ sbp[0]->s_max_mnt_count = cpu_to_le16(NILFS_DFL_MAX_MNT_COUNT);
+
+ sbp[0]->s_mnt_count = cpu_to_le16(mnt_count + 1);
+ sbp[0]->s_state =
+ cpu_to_le16(le16_to_cpu(sbp[0]->s_state) & ~NILFS_VALID_FS);
+ sbp[0]->s_mtime = cpu_to_le64(get_seconds());
+ /* synchronize sbp[1] with sbp[0] */
+ memcpy(sbp[1], sbp[0], nilfs->ns_sbsize);
+ return nilfs_commit_super(sbi, NILFS_SB_COMMIT_ALL);
}
struct nilfs_super_block *nilfs_read_super_block(struct super_block *sb,
@@ -670,7 +787,31 @@ int nilfs_store_magic_and_option(struct super_block *sb,
sbi->s_interval = le32_to_cpu(sbp->s_c_interval);
sbi->s_watermark = le32_to_cpu(sbp->s_c_block_max);
- return !parse_options(data, sb) ? -EINVAL : 0 ;
+ return !parse_options(data, sb, 0) ? -EINVAL : 0 ;
+}
+
+int nilfs_check_feature_compatibility(struct super_block *sb,
+ struct nilfs_super_block *sbp)
+{
+ __u64 features;
+
+ features = le64_to_cpu(sbp->s_feature_incompat) &
+ ~NILFS_FEATURE_INCOMPAT_SUPP;
+ if (features) {
+ printk(KERN_ERR "NILFS: couldn't mount because of unsupported "
+ "optional features (%llx)\n",
+ (unsigned long long)features);
+ return -EINVAL;
+ }
+ features = le64_to_cpu(sbp->s_feature_compat_ro) &
+ ~NILFS_FEATURE_COMPAT_RO_SUPP;
+ if (!(sb->s_flags & MS_RDONLY) && features) {
+ printk(KERN_ERR "NILFS: couldn't mount RDWR because of "
+ "unsupported optional features (%llx)\n",
+ (unsigned long long)features);
+ return -EINVAL;
+ }
+ return 0;
}
/**
@@ -819,7 +960,6 @@ nilfs_fill_super(struct super_block *sb, void *data, int silent,
static int nilfs_remount(struct super_block *sb, int *flags, char *data)
{
struct nilfs_sb_info *sbi = NILFS_SB(sb);
- struct nilfs_super_block *sbp;
struct the_nilfs *nilfs = sbi->s_nilfs;
unsigned long old_sb_flags;
struct nilfs_mount_options old_opts;
@@ -833,32 +973,17 @@ static int nilfs_remount(struct super_block *sb, int *flags, char *data)
old_opts.snapshot_cno = sbi->s_snapshot_cno;
was_snapshot = nilfs_test_opt(sbi, SNAPSHOT);
- if (!parse_options(data, sb)) {
+ if (!parse_options(data, sb, 1)) {
err = -EINVAL;
goto restore_opts;
}
sb->s_flags = (sb->s_flags & ~MS_POSIXACL);
err = -EINVAL;
- if (was_snapshot) {
- if (!(*flags & MS_RDONLY)) {
- printk(KERN_ERR "NILFS (device %s): cannot remount "
- "snapshot read/write.\n",
- sb->s_id);
- goto restore_opts;
- } else if (sbi->s_snapshot_cno != old_opts.snapshot_cno) {
- printk(KERN_ERR "NILFS (device %s): cannot "
- "remount to a different snapshot.\n",
- sb->s_id);
- goto restore_opts;
- }
- } else {
- if (nilfs_test_opt(sbi, SNAPSHOT)) {
- printk(KERN_ERR "NILFS (device %s): cannot change "
- "a regular mount to a snapshot.\n",
- sb->s_id);
- goto restore_opts;
- }
+ if (was_snapshot && !(*flags & MS_RDONLY)) {
+ printk(KERN_ERR "NILFS (device %s): cannot remount snapshot "
+ "read/write.\n", sb->s_id);
+ goto restore_opts;
}
if (!nilfs_valid_fs(nilfs)) {
@@ -880,19 +1005,29 @@ static int nilfs_remount(struct super_block *sb, int *flags, char *data)
* the RDONLY flag and then mark the partition as valid again.
*/
down_write(&nilfs->ns_sem);
- sbp = nilfs->ns_sbp[0];
- if (!(sbp->s_state & le16_to_cpu(NILFS_VALID_FS)) &&
- (nilfs->ns_mount_state & NILFS_VALID_FS))
- sbp->s_state = cpu_to_le16(nilfs->ns_mount_state);
- sbp->s_mtime = cpu_to_le64(get_seconds());
- nilfs_commit_super(sbi, 1);
+ nilfs_cleanup_super(sbi);
up_write(&nilfs->ns_sem);
} else {
+ __u64 features;
+
/*
* Mounting a RDONLY partition read-write, so reread and
* store the current valid flag. (It may have been changed
* by fsck since we originally mounted the partition.)
*/
+ down_read(&nilfs->ns_sem);
+ features = le64_to_cpu(nilfs->ns_sbp[0]->s_feature_compat_ro) &
+ ~NILFS_FEATURE_COMPAT_RO_SUPP;
+ up_read(&nilfs->ns_sem);
+ if (features) {
+ printk(KERN_WARNING "NILFS (device %s): couldn't "
+ "remount RDWR because of unsupported optional "
+ "features (%llx)\n",
+ sb->s_id, (unsigned long long)features);
+ err = -EROFS;
+ goto restore_opts;
+ }
+
sb->s_flags &= ~MS_RDONLY;
err = nilfs_attach_segment_constructor(sbi);
@@ -1119,7 +1254,7 @@ static void nilfs_inode_init_once(void *obj)
init_rwsem(&ii->xattr_sem);
#endif
nilfs_btnode_cache_init_once(&ii->i_btnode_cache);
- ii->i_bmap = (struct nilfs_bmap *)&ii->i_bmap_union;
+ ii->i_bmap = &ii->i_bmap_data;
inode_init_once(&ii->vfs_inode);
}
diff --git a/fs/nilfs2/the_nilfs.c b/fs/nilfs2/the_nilfs.c
index 8c1097327ab..37de1f062d8 100644
--- a/fs/nilfs2/the_nilfs.c
+++ b/fs/nilfs2/the_nilfs.c
@@ -38,6 +38,8 @@
static LIST_HEAD(nilfs_objects);
static DEFINE_SPINLOCK(nilfs_lock);
+static int nilfs_valid_sb(struct nilfs_super_block *sbp);
+
void nilfs_set_last_segment(struct the_nilfs *nilfs,
sector_t start_blocknr, u64 seq, __u64 cno)
{
@@ -45,6 +47,16 @@ void nilfs_set_last_segment(struct the_nilfs *nilfs,
nilfs->ns_last_pseg = start_blocknr;
nilfs->ns_last_seq = seq;
nilfs->ns_last_cno = cno;
+
+ if (!nilfs_sb_dirty(nilfs)) {
+ if (nilfs->ns_prev_seq == nilfs->ns_last_seq)
+ goto stay_cursor;
+
+ set_nilfs_sb_dirty(nilfs);
+ }
+ nilfs->ns_prev_seq = nilfs->ns_last_seq;
+
+ stay_cursor:
spin_unlock(&nilfs->ns_last_segment_lock);
}
@@ -159,8 +171,7 @@ void put_nilfs(struct the_nilfs *nilfs)
kfree(nilfs);
}
-static int nilfs_load_super_root(struct the_nilfs *nilfs,
- struct nilfs_sb_info *sbi, sector_t sr_block)
+static int nilfs_load_super_root(struct the_nilfs *nilfs, sector_t sr_block)
{
struct buffer_head *bh_sr;
struct nilfs_super_root *raw_sr;
@@ -169,7 +180,7 @@ static int nilfs_load_super_root(struct the_nilfs *nilfs,
unsigned inode_size;
int err;
- err = nilfs_read_super_root_block(sbi->s_super, sr_block, &bh_sr, 1);
+ err = nilfs_read_super_root_block(nilfs, sr_block, &bh_sr, 1);
if (unlikely(err))
return err;
@@ -248,6 +259,37 @@ static void nilfs_clear_recovery_info(struct nilfs_recovery_info *ri)
}
/**
+ * nilfs_store_log_cursor - load log cursor from a super block
+ * @nilfs: nilfs object
+ * @sbp: buffer storing super block to be read
+ *
+ * nilfs_store_log_cursor() reads the last position of the log
+ * containing a super root from a given super block, and initializes
+ * relevant information on the nilfs object preparatory for log
+ * scanning and recovery.
+ */
+static int nilfs_store_log_cursor(struct the_nilfs *nilfs,
+ struct nilfs_super_block *sbp)
+{
+ int ret = 0;
+
+ nilfs->ns_last_pseg = le64_to_cpu(sbp->s_last_pseg);
+ nilfs->ns_last_cno = le64_to_cpu(sbp->s_last_cno);
+ nilfs->ns_last_seq = le64_to_cpu(sbp->s_last_seq);
+
+ nilfs->ns_prev_seq = nilfs->ns_last_seq;
+ nilfs->ns_seg_seq = nilfs->ns_last_seq;
+ nilfs->ns_segnum =
+ nilfs_get_segnum_of_block(nilfs, nilfs->ns_last_pseg);
+ nilfs->ns_cno = nilfs->ns_last_cno + 1;
+ if (nilfs->ns_segnum >= nilfs->ns_nsegments) {
+ printk(KERN_ERR "NILFS invalid last segment number.\n");
+ ret = -EINVAL;
+ }
+ return ret;
+}
+
+/**
* load_nilfs - load and recover the nilfs
* @nilfs: the_nilfs structure to be released
* @sbi: nilfs_sb_info used to recover past segment
@@ -285,13 +327,55 @@ int load_nilfs(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi)
nilfs_init_recovery_info(&ri);
- err = nilfs_search_super_root(nilfs, sbi, &ri);
+ err = nilfs_search_super_root(nilfs, &ri);
if (unlikely(err)) {
- printk(KERN_ERR "NILFS: error searching super root.\n");
- goto failed;
+ struct nilfs_super_block **sbp = nilfs->ns_sbp;
+ int blocksize;
+
+ if (err != -EINVAL)
+ goto scan_error;
+
+ if (!nilfs_valid_sb(sbp[1])) {
+ printk(KERN_WARNING
+ "NILFS warning: unable to fall back to spare"
+ "super block\n");
+ goto scan_error;
+ }
+ printk(KERN_INFO
+ "NILFS: try rollback from an earlier position\n");
+
+ /*
+ * restore super block with its spare and reconfigure
+ * relevant states of the nilfs object.
+ */
+ memcpy(sbp[0], sbp[1], nilfs->ns_sbsize);
+ nilfs->ns_crc_seed = le32_to_cpu(sbp[0]->s_crc_seed);
+ nilfs->ns_sbwtime = le64_to_cpu(sbp[0]->s_wtime);
+
+ /* verify consistency between two super blocks */
+ blocksize = BLOCK_SIZE << le32_to_cpu(sbp[0]->s_log_block_size);
+ if (blocksize != nilfs->ns_blocksize) {
+ printk(KERN_WARNING
+ "NILFS warning: blocksize differs between "
+ "two super blocks (%d != %d)\n",
+ blocksize, nilfs->ns_blocksize);
+ goto scan_error;
+ }
+
+ err = nilfs_store_log_cursor(nilfs, sbp[0]);
+ if (err)
+ goto scan_error;
+
+ /* drop clean flag to allow roll-forward and recovery */
+ nilfs->ns_mount_state &= ~NILFS_VALID_FS;
+ valid_fs = 0;
+
+ err = nilfs_search_super_root(nilfs, &ri);
+ if (err)
+ goto scan_error;
}
- err = nilfs_load_super_root(nilfs, sbi, ri.ri_super_root);
+ err = nilfs_load_super_root(nilfs, ri.ri_super_root);
if (unlikely(err)) {
printk(KERN_ERR "NILFS: error loading super root.\n");
goto failed;
@@ -301,11 +385,23 @@ int load_nilfs(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi)
goto skip_recovery;
if (s_flags & MS_RDONLY) {
+ __u64 features;
+
if (nilfs_test_opt(sbi, NORECOVERY)) {
printk(KERN_INFO "NILFS: norecovery option specified. "
"skipping roll-forward recovery\n");
goto skip_recovery;
}
+ features = le64_to_cpu(nilfs->ns_sbp[0]->s_feature_compat_ro) &
+ ~NILFS_FEATURE_COMPAT_RO_SUPP;
+ if (features) {
+ printk(KERN_ERR "NILFS: couldn't proceed with "
+ "recovery because of unsupported optional "
+ "features (%llx)\n",
+ (unsigned long long)features);
+ err = -EROFS;
+ goto failed_unload;
+ }
if (really_read_only) {
printk(KERN_ERR "NILFS: write access "
"unavailable, cannot proceed.\n");
@@ -320,14 +416,13 @@ int load_nilfs(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi)
goto failed_unload;
}
- err = nilfs_recover_logical_segments(nilfs, sbi, &ri);
+ err = nilfs_salvage_orphan_logs(nilfs, sbi, &ri);
if (err)
goto failed_unload;
down_write(&nilfs->ns_sem);
- nilfs->ns_mount_state |= NILFS_VALID_FS;
- nilfs->ns_sbp[0]->s_state = cpu_to_le16(nilfs->ns_mount_state);
- err = nilfs_commit_super(sbi, 1);
+ nilfs->ns_mount_state |= NILFS_VALID_FS; /* set "clean" flag */
+ err = nilfs_cleanup_super(sbi);
up_write(&nilfs->ns_sem);
if (err) {
@@ -343,6 +438,10 @@ int load_nilfs(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi)
sbi->s_super->s_flags = s_flags;
return 0;
+ scan_error:
+ printk(KERN_ERR "NILFS: error searching super root.\n");
+ goto failed;
+
failed_unload:
nilfs_mdt_destroy(nilfs->ns_cpfile);
nilfs_mdt_destroy(nilfs->ns_sufile);
@@ -515,8 +614,8 @@ static int nilfs_load_super_block(struct the_nilfs *nilfs,
nilfs_swap_super_block(nilfs);
}
- nilfs->ns_sbwtime[0] = le64_to_cpu(sbp[0]->s_wtime);
- nilfs->ns_sbwtime[1] = valid[!swp] ? le64_to_cpu(sbp[1]->s_wtime) : 0;
+ nilfs->ns_sbwcount = 0;
+ nilfs->ns_sbwtime = le64_to_cpu(sbp[0]->s_wtime);
nilfs->ns_prot_seq = le64_to_cpu(sbp[valid[1] & !swp]->s_last_seq);
*sbpp = sbp[0];
return 0;
@@ -557,6 +656,10 @@ int init_nilfs(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi, char *data)
if (err)
goto out;
+ err = nilfs_check_feature_compatibility(sb, sbp);
+ if (err)
+ goto out;
+
blocksize = BLOCK_SIZE << le32_to_cpu(sbp->s_log_block_size);
if (sb->s_blocksize != blocksize &&
!sb_set_blocksize(sb, blocksize)) {
@@ -568,7 +671,7 @@ int init_nilfs(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi, char *data)
goto out;
}
- blocksize = sb_min_blocksize(sb, BLOCK_SIZE);
+ blocksize = sb_min_blocksize(sb, NILFS_MIN_BLOCK_SIZE);
if (!blocksize) {
printk(KERN_ERR "NILFS: unable to set blocksize\n");
err = -EINVAL;
@@ -582,7 +685,18 @@ int init_nilfs(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi, char *data)
if (err)
goto failed_sbh;
+ err = nilfs_check_feature_compatibility(sb, sbp);
+ if (err)
+ goto failed_sbh;
+
blocksize = BLOCK_SIZE << le32_to_cpu(sbp->s_log_block_size);
+ if (blocksize < NILFS_MIN_BLOCK_SIZE ||
+ blocksize > NILFS_MAX_BLOCK_SIZE) {
+ printk(KERN_ERR "NILFS: couldn't mount because of unsupported "
+ "filesystem blocksize %d\n", blocksize);
+ err = -EINVAL;
+ goto failed_sbh;
+ }
if (sb->s_blocksize != blocksize) {
int hw_blocksize = bdev_logical_block_size(sb->s_bdev);
@@ -604,6 +718,7 @@ int init_nilfs(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi, char *data)
when reloading fails. */
}
nilfs->ns_blocksize_bits = sb->s_blocksize_bits;
+ nilfs->ns_blocksize = blocksize;
err = nilfs_store_disk_layout(nilfs, sbp);
if (err)
@@ -616,23 +731,9 @@ int init_nilfs(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi, char *data)
bdi = nilfs->ns_bdev->bd_inode->i_mapping->backing_dev_info;
nilfs->ns_bdi = bdi ? : &default_backing_dev_info;
- /* Finding last segment */
- nilfs->ns_last_pseg = le64_to_cpu(sbp->s_last_pseg);
- nilfs->ns_last_cno = le64_to_cpu(sbp->s_last_cno);
- nilfs->ns_last_seq = le64_to_cpu(sbp->s_last_seq);
-
- nilfs->ns_seg_seq = nilfs->ns_last_seq;
- nilfs->ns_segnum =
- nilfs_get_segnum_of_block(nilfs, nilfs->ns_last_pseg);
- nilfs->ns_cno = nilfs->ns_last_cno + 1;
- if (nilfs->ns_segnum >= nilfs->ns_nsegments) {
- printk(KERN_ERR "NILFS invalid last segment number.\n");
- err = -EINVAL;
+ err = nilfs_store_log_cursor(nilfs, sbp);
+ if (err)
goto failed_sbh;
- }
- /* Dummy values */
- nilfs->ns_free_segments_count =
- nilfs->ns_nsegments - (nilfs->ns_segnum + 1);
/* Initialize gcinode cache */
err = nilfs_init_gccache(nilfs);
diff --git a/fs/nilfs2/the_nilfs.h b/fs/nilfs2/the_nilfs.h
index 1ab97453369..f785a7b0ab9 100644
--- a/fs/nilfs2/the_nilfs.h
+++ b/fs/nilfs2/the_nilfs.h
@@ -57,7 +57,8 @@ enum {
* @ns_current: back pointer to current mount
* @ns_sbh: buffer heads of on-disk super blocks
* @ns_sbp: pointers to super block data
- * @ns_sbwtime: previous write time of super blocks
+ * @ns_sbwtime: previous write time of super block
+ * @ns_sbwcount: write count of super block
* @ns_sbsize: size of valid data in super block
* @ns_supers: list of nilfs super block structs
* @ns_seg_seq: segment sequence counter
@@ -73,7 +74,7 @@ enum {
* @ns_last_seq: sequence value of the latest segment
* @ns_last_cno: checkpoint number of the latest segment
* @ns_prot_seq: least sequence number of segments which must not be reclaimed
- * @ns_free_segments_count: counter of free segments
+ * @ns_prev_seq: base sequence number used to decide if advance log cursor
* @ns_segctor_sem: segment constructor semaphore
* @ns_dat: DAT file inode
* @ns_cpfile: checkpoint file inode
@@ -82,6 +83,7 @@ enum {
* @ns_gc_inodes: dummy inodes to keep live blocks
* @ns_gc_inodes_h: hash list to keep dummy inode holding live blocks
* @ns_blocksize_bits: bit length of block size
+ * @ns_blocksize: block size
* @ns_nsegments: number of segments in filesystem
* @ns_blocks_per_segment: number of blocks per segment
* @ns_r_segments_percentage: reserved segments percentage
@@ -119,7 +121,8 @@ struct the_nilfs {
*/
struct buffer_head *ns_sbh[2];
struct nilfs_super_block *ns_sbp[2];
- time_t ns_sbwtime[2];
+ time_t ns_sbwtime;
+ unsigned ns_sbwcount;
unsigned ns_sbsize;
unsigned ns_mount_state;
@@ -149,7 +152,7 @@ struct the_nilfs {
u64 ns_last_seq;
__u64 ns_last_cno;
u64 ns_prot_seq;
- unsigned long ns_free_segments_count;
+ u64 ns_prev_seq;
struct rw_semaphore ns_segctor_sem;
@@ -168,6 +171,7 @@ struct the_nilfs {
/* Disk layout information (static) */
unsigned int ns_blocksize_bits;
+ unsigned int ns_blocksize;
unsigned long ns_nsegments;
unsigned long ns_blocks_per_segment;
unsigned long ns_r_segments_percentage;
@@ -203,20 +207,17 @@ THE_NILFS_FNS(SB_DIRTY, sb_dirty)
/* Minimum interval of periodical update of superblocks (in seconds) */
#define NILFS_SB_FREQ 10
-#define NILFS_ALTSB_FREQ 60 /* spare superblock */
static inline int nilfs_sb_need_update(struct the_nilfs *nilfs)
{
u64 t = get_seconds();
- return t < nilfs->ns_sbwtime[0] ||
- t > nilfs->ns_sbwtime[0] + NILFS_SB_FREQ;
+ return t < nilfs->ns_sbwtime || t > nilfs->ns_sbwtime + NILFS_SB_FREQ;
}
-static inline int nilfs_altsb_need_update(struct the_nilfs *nilfs)
+static inline int nilfs_sb_will_flip(struct the_nilfs *nilfs)
{
- u64 t = get_seconds();
- struct nilfs_super_block **sbp = nilfs->ns_sbp;
- return sbp[1] && t > nilfs->ns_sbwtime[1] + NILFS_ALTSB_FREQ;
+ int flip_bits = nilfs->ns_sbwcount & 0x0FL;
+ return (flip_bits != 0x08 && flip_bits != 0x0F);
}
void nilfs_set_last_segment(struct the_nilfs *, sector_t, u64, __u64);
diff --git a/fs/ocfs2/aops.c b/fs/ocfs2/aops.c
index 356e976772b..96337a4fbbd 100644
--- a/fs/ocfs2/aops.c
+++ b/fs/ocfs2/aops.c
@@ -578,7 +578,9 @@ bail:
static void ocfs2_dio_end_io(struct kiocb *iocb,
loff_t offset,
ssize_t bytes,
- void *private)
+ void *private,
+ int ret,
+ bool is_async)
{
struct inode *inode = iocb->ki_filp->f_path.dentry->d_inode;
int level;
@@ -592,6 +594,9 @@ static void ocfs2_dio_end_io(struct kiocb *iocb,
if (!level)
up_read(&inode->i_alloc_sem);
ocfs2_rw_unlock(inode, level);
+
+ if (is_async)
+ aio_complete(iocb, ret, 0);
}
/*
diff --git a/fs/ocfs2/dlm/dlmdebug.c b/fs/ocfs2/dlm/dlmdebug.c
index 0cd24cf5439..5efdd37dfe4 100644
--- a/fs/ocfs2/dlm/dlmdebug.c
+++ b/fs/ocfs2/dlm/dlmdebug.c
@@ -419,7 +419,7 @@ static loff_t debug_buffer_llseek(struct file *file, loff_t off, int whence)
static int debug_buffer_release(struct inode *inode, struct file *file)
{
- struct debug_buffer *db = (struct debug_buffer *)file->private_data;
+ struct debug_buffer *db = file->private_data;
if (db)
kfree(db->buf);
@@ -715,7 +715,7 @@ static int debug_lockres_open(struct inode *inode, struct file *file)
goto bail;
}
- seq = (struct seq_file *) file->private_data;
+ seq = file->private_data;
seq->private = dl;
dlm_grab(dlm);
@@ -731,7 +731,7 @@ bail:
static int debug_lockres_release(struct inode *inode, struct file *file)
{
- struct seq_file *seq = (struct seq_file *)file->private_data;
+ struct seq_file *seq = file->private_data;
struct debug_lockres *dl = (struct debug_lockres *)seq->private;
if (dl->dl_res)
diff --git a/fs/ocfs2/dlmfs/dlmfs.c b/fs/ocfs2/dlmfs/dlmfs.c
index b83d6107a1f..bef34d0528d 100644
--- a/fs/ocfs2/dlmfs/dlmfs.c
+++ b/fs/ocfs2/dlmfs/dlmfs.c
@@ -182,8 +182,7 @@ static int dlmfs_file_release(struct inode *inode,
{
int level, status;
struct dlmfs_inode_private *ip = DLMFS_I(inode);
- struct dlmfs_filp_private *fp =
- (struct dlmfs_filp_private *) file->private_data;
+ struct dlmfs_filp_private *fp = file->private_data;
if (S_ISDIR(inode->i_mode))
BUG();
diff --git a/fs/ocfs2/dlmglue.c b/fs/ocfs2/dlmglue.c
index 39eb16ac5f9..5e02a893f46 100644
--- a/fs/ocfs2/dlmglue.c
+++ b/fs/ocfs2/dlmglue.c
@@ -2966,7 +2966,7 @@ static const struct seq_operations ocfs2_dlm_seq_ops = {
static int ocfs2_dlm_debug_release(struct inode *inode, struct file *file)
{
- struct seq_file *seq = (struct seq_file *) file->private_data;
+ struct seq_file *seq = file->private_data;
struct ocfs2_dlm_seq_priv *priv = seq->private;
struct ocfs2_lock_res *res = &priv->p_iter_res;
@@ -3000,7 +3000,7 @@ static int ocfs2_dlm_debug_open(struct inode *inode, struct file *file)
goto out;
}
- seq = (struct seq_file *) file->private_data;
+ seq = file->private_data;
seq->private = priv;
ocfs2_add_lockres_tracking(&priv->p_iter_res,
diff --git a/fs/ocfs2/journal.c b/fs/ocfs2/journal.c
index 625de9d7088..9b57c0350ff 100644
--- a/fs/ocfs2/journal.c
+++ b/fs/ocfs2/journal.c
@@ -760,13 +760,13 @@ void ocfs2_set_journal_params(struct ocfs2_super *osb)
if (osb->osb_commit_interval)
commit_interval = osb->osb_commit_interval;
- spin_lock(&journal->j_state_lock);
+ write_lock(&journal->j_state_lock);
journal->j_commit_interval = commit_interval;
if (osb->s_mount_opt & OCFS2_MOUNT_BARRIER)
journal->j_flags |= JBD2_BARRIER;
else
journal->j_flags &= ~JBD2_BARRIER;
- spin_unlock(&journal->j_state_lock);
+ write_unlock(&journal->j_state_lock);
}
int ocfs2_journal_init(struct ocfs2_journal *journal, int *dirty)
diff --git a/fs/ocfs2/super.c b/fs/ocfs2/super.c
index 0eaa929a4db..03a799fdd74 100644
--- a/fs/ocfs2/super.c
+++ b/fs/ocfs2/super.c
@@ -2472,7 +2472,7 @@ static void ocfs2_delete_osb(struct ocfs2_super *osb)
kfree(osb->slot_recovery_generations);
/* FIXME
* This belongs in journal shutdown, but because we have to
- * allocate osb->journal at the start of ocfs2_initalize_osb(),
+ * allocate osb->journal at the start of ocfs2_initialize_osb(),
* we free it here.
*/
kfree(osb->journal);
diff --git a/fs/open.c b/fs/open.c
index 5463266db9e..0d1fa3dc0ef 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -110,7 +110,7 @@ static long do_sys_truncate(const char __user *pathname, loff_t length)
error = locks_verify_truncate(inode, NULL, length);
if (!error)
- error = security_path_truncate(&path, length, 0);
+ error = security_path_truncate(&path);
if (!error)
error = do_truncate(path.dentry, length, 0, NULL);
@@ -165,8 +165,7 @@ static long do_sys_ftruncate(unsigned int fd, loff_t length, int small)
error = locks_verify_truncate(inode, file, length);
if (!error)
- error = security_path_truncate(&file->f_path, length,
- ATTR_MTIME|ATTR_CTIME);
+ error = security_path_truncate(&file->f_path);
if (!error)
error = do_truncate(dentry, length, ATTR_MTIME|ATTR_CTIME, file);
out_putf:
@@ -367,7 +366,7 @@ SYSCALL_DEFINE1(chdir, const char __user *, filename)
if (error)
goto out;
- error = inode_permission(path.dentry->d_inode, MAY_EXEC | MAY_ACCESS);
+ error = inode_permission(path.dentry->d_inode, MAY_EXEC | MAY_CHDIR);
if (error)
goto dput_and_out;
@@ -396,7 +395,7 @@ SYSCALL_DEFINE1(fchdir, unsigned int, fd)
if (!S_ISDIR(inode->i_mode))
goto out_putf;
- error = inode_permission(inode, MAY_EXEC | MAY_ACCESS);
+ error = inode_permission(inode, MAY_EXEC | MAY_CHDIR);
if (!error)
set_fs_pwd(current->fs, &file->f_path);
out_putf:
@@ -414,7 +413,7 @@ SYSCALL_DEFINE1(chroot, const char __user *, filename)
if (error)
goto out;
- error = inode_permission(path.dentry->d_inode, MAY_EXEC | MAY_ACCESS);
+ error = inode_permission(path.dentry->d_inode, MAY_EXEC | MAY_CHDIR);
if (error)
goto dput_and_out;
diff --git a/fs/partitions/check.c b/fs/partitions/check.c
index 5dcd4b0c553..72c52656dc2 100644
--- a/fs/partitions/check.c
+++ b/fs/partitions/check.c
@@ -459,7 +459,6 @@ struct hd_struct *add_partition(struct gendisk *disk, int partno,
}
/* everything is up and running, commence */
- INIT_RCU_HEAD(&p->rcu_head);
rcu_assign_pointer(ptbl->part[partno], p);
/* suppress uevent if the disk supresses it */
diff --git a/fs/quota/dquot.c b/fs/quota/dquot.c
index 437d2ca2de9..ef72b169942 100644
--- a/fs/quota/dquot.c
+++ b/fs/quota/dquot.c
@@ -132,6 +132,22 @@ static __cacheline_aligned_in_smp DEFINE_SPINLOCK(dq_state_lock);
__cacheline_aligned_in_smp DEFINE_SPINLOCK(dq_data_lock);
EXPORT_SYMBOL(dq_data_lock);
+void __quota_error(struct super_block *sb, const char *func,
+ const char *fmt, ...)
+{
+ va_list args;
+
+ if (printk_ratelimit()) {
+ va_start(args, fmt);
+ printk(KERN_ERR "Quota error (device %s): %s: ",
+ sb->s_id, func);
+ vprintk(fmt, args);
+ printk("\n");
+ va_end(args);
+ }
+}
+EXPORT_SYMBOL(__quota_error);
+
#if defined(CONFIG_QUOTA_DEBUG) || defined(CONFIG_PRINT_QUOTA_WARNING)
static char *quotatypes[] = INITQFNAMES;
#endif
@@ -705,11 +721,8 @@ void dqput(struct dquot *dquot)
return;
#ifdef CONFIG_QUOTA_DEBUG
if (!atomic_read(&dquot->dq_count)) {
- printk("VFS: dqput: trying to free free dquot\n");
- printk("VFS: device %s, dquot of %s %d\n",
- dquot->dq_sb->s_id,
- quotatypes[dquot->dq_type],
- dquot->dq_id);
+ quota_error(dquot->dq_sb, "trying to free free dquot of %s %d",
+ quotatypes[dquot->dq_type], dquot->dq_id);
BUG();
}
#endif
@@ -732,9 +745,9 @@ we_slept:
/* Commit dquot before releasing */
ret = dquot->dq_sb->dq_op->write_dquot(dquot);
if (ret < 0) {
- printk(KERN_ERR "VFS: cannot write quota structure on "
- "device %s (error %d). Quota may get out of "
- "sync!\n", dquot->dq_sb->s_id, ret);
+ quota_error(dquot->dq_sb, "Can't write quota structure"
+ " (error %d). Quota may get out of sync!",
+ ret);
/*
* We clear dirty bit anyway, so that we avoid
* infinite loop here
@@ -914,9 +927,9 @@ static void add_dquot_ref(struct super_block *sb, int type)
#ifdef CONFIG_QUOTA_DEBUG
if (reserved) {
- printk(KERN_WARNING "VFS (%s): Writes happened before quota"
- " was turned on thus quota information is probably "
- "inconsistent. Please run quotacheck(8).\n", sb->s_id);
+ quota_error(sb, "Writes happened before quota was turned on "
+ "thus quota information is probably inconsistent. "
+ "Please run quotacheck(8)");
}
#endif
}
@@ -947,7 +960,9 @@ static int remove_inode_dquot_ref(struct inode *inode, int type,
if (dqput_blocks(dquot)) {
#ifdef CONFIG_QUOTA_DEBUG
if (atomic_read(&dquot->dq_count) != 1)
- printk(KERN_WARNING "VFS: Adding dquot with dq_count %d to dispose list.\n", atomic_read(&dquot->dq_count));
+ quota_error(inode->i_sb, "Adding dquot with "
+ "dq_count %d to dispose list",
+ atomic_read(&dquot->dq_count));
#endif
spin_lock(&dq_list_lock);
/* As dquot must have currently users it can't be on
@@ -986,6 +1001,7 @@ static void remove_dquot_ref(struct super_block *sb, int type,
struct list_head *tofree_head)
{
struct inode *inode;
+ int reserved = 0;
spin_lock(&inode_lock);
list_for_each_entry(inode, &sb->s_inodes, i_sb_list) {
@@ -995,10 +1011,20 @@ static void remove_dquot_ref(struct super_block *sb, int type,
* only quota pointers and these have separate locking
* (dqptr_sem).
*/
- if (!IS_NOQUOTA(inode))
+ if (!IS_NOQUOTA(inode)) {
+ if (unlikely(inode_get_rsv_space(inode) > 0))
+ reserved = 1;
remove_inode_dquot_ref(inode, type, tofree_head);
+ }
}
spin_unlock(&inode_lock);
+#ifdef CONFIG_QUOTA_DEBUG
+ if (reserved) {
+ printk(KERN_WARNING "VFS (%s): Writes happened after quota"
+ " was disabled thus quota information is probably "
+ "inconsistent. Please run quotacheck(8).\n", sb->s_id);
+ }
+#endif
}
/* Gather all references from inodes and drop them */
@@ -1304,6 +1330,15 @@ static int info_bdq_free(struct dquot *dquot, qsize_t space)
return QUOTA_NL_NOWARN;
}
+static int dquot_active(const struct inode *inode)
+{
+ struct super_block *sb = inode->i_sb;
+
+ if (IS_NOQUOTA(inode))
+ return 0;
+ return sb_any_quota_loaded(sb) & ~sb_any_quota_suspended(sb);
+}
+
/*
* Initialize quota pointers in inode
*
@@ -1323,7 +1358,7 @@ static void __dquot_initialize(struct inode *inode, int type)
/* First test before acquiring mutex - solves deadlocks when we
* re-enter the quota code and are already holding the mutex */
- if (!sb_any_quota_active(inode->i_sb) || IS_NOQUOTA(inode))
+ if (!dquot_active(inode))
return;
/* First get references to structures we might need. */
@@ -1507,7 +1542,7 @@ int __dquot_alloc_space(struct inode *inode, qsize_t number, int flags)
* First test before acquiring mutex - solves deadlocks when we
* re-enter the quota code and are already holding the mutex
*/
- if (!sb_any_quota_active(inode->i_sb) || IS_NOQUOTA(inode)) {
+ if (!dquot_active(inode)) {
inode_incr_space(inode, number, reserve);
goto out;
}
@@ -1559,7 +1594,7 @@ int dquot_alloc_inode(const struct inode *inode)
/* First test before acquiring mutex - solves deadlocks when we
* re-enter the quota code and are already holding the mutex */
- if (!sb_any_quota_active(inode->i_sb) || IS_NOQUOTA(inode))
+ if (!dquot_active(inode))
return 0;
for (cnt = 0; cnt < MAXQUOTAS; cnt++)
warntype[cnt] = QUOTA_NL_NOWARN;
@@ -1596,7 +1631,7 @@ int dquot_claim_space_nodirty(struct inode *inode, qsize_t number)
{
int cnt;
- if (!sb_any_quota_active(inode->i_sb) || IS_NOQUOTA(inode)) {
+ if (!dquot_active(inode)) {
inode_claim_rsv_space(inode, number);
return 0;
}
@@ -1629,7 +1664,7 @@ void __dquot_free_space(struct inode *inode, qsize_t number, int flags)
/* First test before acquiring mutex - solves deadlocks when we
* re-enter the quota code and are already holding the mutex */
- if (!sb_any_quota_active(inode->i_sb) || IS_NOQUOTA(inode)) {
+ if (!dquot_active(inode)) {
inode_decr_space(inode, number, reserve);
return;
}
@@ -1667,7 +1702,7 @@ void dquot_free_inode(const struct inode *inode)
/* First test before acquiring mutex - solves deadlocks when we
* re-enter the quota code and are already holding the mutex */
- if (!sb_any_quota_active(inode->i_sb) || IS_NOQUOTA(inode))
+ if (!dquot_active(inode))
return;
down_read(&sb_dqopt(inode->i_sb)->dqptr_sem);
@@ -1790,7 +1825,7 @@ int dquot_transfer(struct inode *inode, struct iattr *iattr)
struct super_block *sb = inode->i_sb;
int ret;
- if (!sb_any_quota_active(sb) || IS_NOQUOTA(inode))
+ if (!dquot_active(inode))
return 0;
if (iattr->ia_valid & ATTR_UID && iattr->ia_uid != inode->i_uid)
@@ -1957,7 +1992,7 @@ int dquot_disable(struct super_block *sb, int type, unsigned int flags)
truncate_inode_pages(&toputinode[cnt]->i_data,
0);
mutex_unlock(&toputinode[cnt]->i_mutex);
- mark_inode_dirty(toputinode[cnt]);
+ mark_inode_dirty_sync(toputinode[cnt]);
}
mutex_unlock(&dqopt->dqonoff_mutex);
}
@@ -2270,7 +2305,7 @@ static void do_get_dqblk(struct dquot *dquot, struct fs_disk_quota *di)
memset(di, 0, sizeof(*di));
di->d_version = FS_DQUOT_VERSION;
di->d_flags = dquot->dq_type == USRQUOTA ?
- XFS_USER_QUOTA : XFS_GROUP_QUOTA;
+ FS_USER_QUOTA : FS_GROUP_QUOTA;
di->d_id = dquot->dq_id;
spin_lock(&dq_data_lock);
diff --git a/fs/quota/quota_tree.c b/fs/quota/quota_tree.c
index 24f03407eeb..9e48874eabc 100644
--- a/fs/quota/quota_tree.c
+++ b/fs/quota/quota_tree.c
@@ -65,8 +65,7 @@ static ssize_t write_blk(struct qtree_mem_dqinfo *info, uint blk, char *buf)
ret = sb->s_op->quota_write(sb, info->dqi_type, buf,
info->dqi_usable_bs, blk << info->dqi_blocksize_bits);
if (ret != info->dqi_usable_bs) {
- q_warn(KERN_WARNING "VFS: dquota write failed on "
- "dev %s\n", sb->s_id);
+ quota_error(sb, "dquota write failed");
if (ret >= 0)
ret = -EIO;
}
@@ -160,9 +159,8 @@ static int remove_free_dqentry(struct qtree_mem_dqinfo *info, char *buf,
dh->dqdh_next_free = dh->dqdh_prev_free = cpu_to_le32(0);
/* No matter whether write succeeds block is out of list */
if (write_blk(info, blk, buf) < 0)
- q_warn(KERN_ERR
- "VFS: Can't write block (%u) with free entries.\n",
- blk);
+ quota_error(info->dqi_sb, "Can't write block (%u) "
+ "with free entries", blk);
return 0;
out_buf:
kfree(tmpbuf);
@@ -252,9 +250,8 @@ static uint find_free_dqentry(struct qtree_mem_dqinfo *info,
if (le16_to_cpu(dh->dqdh_entries) + 1 >= qtree_dqstr_in_blk(info)) {
*err = remove_free_dqentry(info, buf, blk);
if (*err < 0) {
- q_warn(KERN_ERR "VFS: find_free_dqentry(): Can't "
- "remove block (%u) from entry free list.\n",
- blk);
+ quota_error(dquot->dq_sb, "Can't remove block (%u) "
+ "from entry free list", blk);
goto out_buf;
}
}
@@ -268,16 +265,15 @@ static uint find_free_dqentry(struct qtree_mem_dqinfo *info,
}
#ifdef __QUOTA_QT_PARANOIA
if (i == qtree_dqstr_in_blk(info)) {
- printk(KERN_ERR "VFS: find_free_dqentry(): Data block full "
- "but it shouldn't.\n");
+ quota_error(dquot->dq_sb, "Data block full but it shouldn't");
*err = -EIO;
goto out_buf;
}
#endif
*err = write_blk(info, blk, buf);
if (*err < 0) {
- q_warn(KERN_ERR "VFS: find_free_dqentry(): Can't write quota "
- "data block %u.\n", blk);
+ quota_error(dquot->dq_sb, "Can't write quota data block %u",
+ blk);
goto out_buf;
}
dquot->dq_off = (blk << info->dqi_blocksize_bits) +
@@ -311,8 +307,8 @@ static int do_insert_tree(struct qtree_mem_dqinfo *info, struct dquot *dquot,
} else {
ret = read_blk(info, *treeblk, buf);
if (ret < 0) {
- q_warn(KERN_ERR "VFS: Can't read tree quota block "
- "%u.\n", *treeblk);
+ quota_error(dquot->dq_sb, "Can't read tree quota "
+ "block %u", *treeblk);
goto out_buf;
}
}
@@ -323,9 +319,9 @@ static int do_insert_tree(struct qtree_mem_dqinfo *info, struct dquot *dquot,
if (depth == info->dqi_qtree_depth - 1) {
#ifdef __QUOTA_QT_PARANOIA
if (newblk) {
- printk(KERN_ERR "VFS: Inserting already present quota "
- "entry (block %u).\n",
- le32_to_cpu(ref[get_index(info,
+ quota_error(dquot->dq_sb, "Inserting already present "
+ "quota entry (block %u)",
+ le32_to_cpu(ref[get_index(info,
dquot->dq_id, depth)]));
ret = -EIO;
goto out_buf;
@@ -373,8 +369,8 @@ int qtree_write_dquot(struct qtree_mem_dqinfo *info, struct dquot *dquot)
if (!dquot->dq_off) {
ret = dq_insert_tree(info, dquot);
if (ret < 0) {
- q_warn(KERN_ERR "VFS: Error %zd occurred while "
- "creating quota.\n", ret);
+ quota_error(sb, "Error %zd occurred while creating "
+ "quota", ret);
kfree(ddquot);
return ret;
}
@@ -385,8 +381,7 @@ int qtree_write_dquot(struct qtree_mem_dqinfo *info, struct dquot *dquot)
ret = sb->s_op->quota_write(sb, type, ddquot, info->dqi_entry_size,
dquot->dq_off);
if (ret != info->dqi_entry_size) {
- q_warn(KERN_WARNING "VFS: dquota write failed on dev %s\n",
- sb->s_id);
+ quota_error(sb, "dquota write failed");
if (ret >= 0)
ret = -ENOSPC;
} else {
@@ -410,14 +405,15 @@ static int free_dqentry(struct qtree_mem_dqinfo *info, struct dquot *dquot,
if (!buf)
return -ENOMEM;
if (dquot->dq_off >> info->dqi_blocksize_bits != blk) {
- q_warn(KERN_ERR "VFS: Quota structure has offset to other "
- "block (%u) than it should (%u).\n", blk,
- (uint)(dquot->dq_off >> info->dqi_blocksize_bits));
+ quota_error(dquot->dq_sb, "Quota structure has offset to "
+ "other block (%u) than it should (%u)", blk,
+ (uint)(dquot->dq_off >> info->dqi_blocksize_bits));
goto out_buf;
}
ret = read_blk(info, blk, buf);
if (ret < 0) {
- q_warn(KERN_ERR "VFS: Can't read quota data block %u\n", blk);
+ quota_error(dquot->dq_sb, "Can't read quota data block %u",
+ blk);
goto out_buf;
}
dh = (struct qt_disk_dqdbheader *)buf;
@@ -427,8 +423,8 @@ static int free_dqentry(struct qtree_mem_dqinfo *info, struct dquot *dquot,
if (ret >= 0)
ret = put_free_dqblk(info, buf, blk);
if (ret < 0) {
- q_warn(KERN_ERR "VFS: Can't move quota data block (%u) "
- "to free list.\n", blk);
+ quota_error(dquot->dq_sb, "Can't move quota data block "
+ "(%u) to free list", blk);
goto out_buf;
}
} else {
@@ -440,15 +436,15 @@ static int free_dqentry(struct qtree_mem_dqinfo *info, struct dquot *dquot,
/* Insert will write block itself */
ret = insert_free_dqentry(info, buf, blk);
if (ret < 0) {
- q_warn(KERN_ERR "VFS: Can't insert quota data "
- "block (%u) to free entry list.\n", blk);
+ quota_error(dquot->dq_sb, "Can't insert quota "
+ "data block (%u) to free entry list", blk);
goto out_buf;
}
} else {
ret = write_blk(info, blk, buf);
if (ret < 0) {
- q_warn(KERN_ERR "VFS: Can't write quota data "
- "block %u\n", blk);
+ quota_error(dquot->dq_sb, "Can't write quota "
+ "data block %u", blk);
goto out_buf;
}
}
@@ -472,7 +468,8 @@ static int remove_tree(struct qtree_mem_dqinfo *info, struct dquot *dquot,
return -ENOMEM;
ret = read_blk(info, *blk, buf);
if (ret < 0) {
- q_warn(KERN_ERR "VFS: Can't read quota data block %u\n", *blk);
+ quota_error(dquot->dq_sb, "Can't read quota data "
+ "block %u", blk);
goto out_buf;
}
newblk = le32_to_cpu(ref[get_index(info, dquot->dq_id, depth)]);
@@ -496,8 +493,8 @@ static int remove_tree(struct qtree_mem_dqinfo *info, struct dquot *dquot,
} else {
ret = write_blk(info, *blk, buf);
if (ret < 0)
- q_warn(KERN_ERR "VFS: Can't write quota tree "
- "block %u.\n", *blk);
+ quota_error(dquot->dq_sb, "Can't write quota "
+ "tree block %u", blk);
}
}
out_buf:
@@ -529,7 +526,8 @@ static loff_t find_block_dqentry(struct qtree_mem_dqinfo *info,
return -ENOMEM;
ret = read_blk(info, blk, buf);
if (ret < 0) {
- q_warn(KERN_ERR "VFS: Can't read quota tree block %u.\n", blk);
+ quota_error(dquot->dq_sb, "Can't read quota tree "
+ "block %u", blk);
goto out_buf;
}
ddquot = buf + sizeof(struct qt_disk_dqdbheader);
@@ -539,8 +537,8 @@ static loff_t find_block_dqentry(struct qtree_mem_dqinfo *info,
ddquot += info->dqi_entry_size;
}
if (i == qtree_dqstr_in_blk(info)) {
- q_warn(KERN_ERR "VFS: Quota for id %u referenced "
- "but not present.\n", dquot->dq_id);
+ quota_error(dquot->dq_sb, "Quota for id %u referenced "
+ "but not present", dquot->dq_id);
ret = -EIO;
goto out_buf;
} else {
@@ -564,7 +562,8 @@ static loff_t find_tree_dqentry(struct qtree_mem_dqinfo *info,
return -ENOMEM;
ret = read_blk(info, blk, buf);
if (ret < 0) {
- q_warn(KERN_ERR "VFS: Can't read quota tree block %u.\n", blk);
+ quota_error(dquot->dq_sb, "Can't read quota tree block %u",
+ blk);
goto out_buf;
}
ret = 0;
@@ -598,7 +597,7 @@ int qtree_read_dquot(struct qtree_mem_dqinfo *info, struct dquot *dquot)
#ifdef __QUOTA_QT_PARANOIA
/* Invalidated quota? */
if (!sb_dqopt(dquot->dq_sb)->files[type]) {
- printk(KERN_ERR "VFS: Quota invalidated while reading!\n");
+ quota_error(sb, "Quota invalidated while reading!");
return -EIO;
}
#endif
@@ -607,8 +606,8 @@ int qtree_read_dquot(struct qtree_mem_dqinfo *info, struct dquot *dquot)
offset = find_dqentry(info, dquot);
if (offset <= 0) { /* Entry not present? */
if (offset < 0)
- q_warn(KERN_ERR "VFS: Can't read quota "
- "structure for id %u.\n", dquot->dq_id);
+ quota_error(sb, "Can't read quota structure "
+ "for id %u", dquot->dq_id);
dquot->dq_off = 0;
set_bit(DQ_FAKE_B, &dquot->dq_flags);
memset(&dquot->dq_dqb, 0, sizeof(struct mem_dqblk));
@@ -625,8 +624,8 @@ int qtree_read_dquot(struct qtree_mem_dqinfo *info, struct dquot *dquot)
if (ret != info->dqi_entry_size) {
if (ret >= 0)
ret = -EIO;
- q_warn(KERN_ERR "VFS: Error while reading quota "
- "structure for id %u.\n", dquot->dq_id);
+ quota_error(sb, "Error while reading quota structure for id %u",
+ dquot->dq_id);
set_bit(DQ_FAKE_B, &dquot->dq_flags);
memset(&dquot->dq_dqb, 0, sizeof(struct mem_dqblk));
kfree(ddquot);
diff --git a/fs/quota/quota_tree.h b/fs/quota/quota_tree.h
index ccc3e71fb1d..a1ab8db81a5 100644
--- a/fs/quota/quota_tree.h
+++ b/fs/quota/quota_tree.h
@@ -22,10 +22,4 @@ struct qt_disk_dqdbheader {
#define QT_TREEOFF 1 /* Offset of tree in file in blocks */
-#define q_warn(fmt, args...) \
-do { \
- if (printk_ratelimit()) \
- printk(fmt, ## args); \
-} while(0)
-
#endif /* _LINUX_QUOTAIO_TREE_H */
diff --git a/fs/quota/quota_v1.c b/fs/quota/quota_v1.c
index 4af344c5852..34b37a67bb1 100644
--- a/fs/quota/quota_v1.c
+++ b/fs/quota/quota_v1.c
@@ -95,8 +95,7 @@ static int v1_commit_dqblk(struct dquot *dquot)
(char *)&dqblk, sizeof(struct v1_disk_dqblk),
v1_dqoff(dquot->dq_id));
if (ret != sizeof(struct v1_disk_dqblk)) {
- printk(KERN_WARNING "VFS: dquota write failed on dev %s\n",
- dquot->dq_sb->s_id);
+ quota_error(dquot->dq_sb, "dquota write failed");
if (ret >= 0)
ret = -EIO;
goto out;
diff --git a/fs/quota/quota_v2.c b/fs/quota/quota_v2.c
index 135206af145..65444d29406 100644
--- a/fs/quota/quota_v2.c
+++ b/fs/quota/quota_v2.c
@@ -63,9 +63,8 @@ static int v2_read_header(struct super_block *sb, int type,
size = sb->s_op->quota_read(sb, type, (char *)dqhead,
sizeof(struct v2_disk_dqheader), 0);
if (size != sizeof(struct v2_disk_dqheader)) {
- q_warn(KERN_WARNING "quota_v2: Failed header read:"
- " expected=%zd got=%zd\n",
- sizeof(struct v2_disk_dqheader), size);
+ quota_error(sb, "Failed header read: expected=%zd got=%zd",
+ sizeof(struct v2_disk_dqheader), size);
return 0;
}
return 1;
@@ -106,8 +105,7 @@ static int v2_read_file_info(struct super_block *sb, int type)
size = sb->s_op->quota_read(sb, type, (char *)&dinfo,
sizeof(struct v2_disk_dqinfo), V2_DQINFOOFF);
if (size != sizeof(struct v2_disk_dqinfo)) {
- q_warn(KERN_WARNING "quota_v2: Can't read info structure on device %s.\n",
- sb->s_id);
+ quota_error(sb, "Can't read info structure");
return -1;
}
info->dqi_priv = kmalloc(sizeof(struct qtree_mem_dqinfo), GFP_NOFS);
@@ -167,8 +165,7 @@ static int v2_write_file_info(struct super_block *sb, int type)
size = sb->s_op->quota_write(sb, type, (char *)&dinfo,
sizeof(struct v2_disk_dqinfo), V2_DQINFOOFF);
if (size != sizeof(struct v2_disk_dqinfo)) {
- q_warn(KERN_WARNING "Can't write info structure on device %s.\n",
- sb->s_id);
+ quota_error(sb, "Can't write info structure");
return -1;
}
return 0;
diff --git a/fs/reiserfs/inode.c b/fs/reiserfs/inode.c
index 0f22fdaf54a..29db72203bd 100644
--- a/fs/reiserfs/inode.c
+++ b/fs/reiserfs/inode.c
@@ -1221,7 +1221,7 @@ static void init_inode(struct inode *inode, struct treepath *path)
inode_set_bytes(inode,
to_real_used_space(inode, inode->i_blocks,
SD_V2_SIZE));
- /* read persistent inode attributes from sd and initalise
+ /* read persistent inode attributes from sd and initialise
generic inode flags from them */
REISERFS_I(inode)->i_attrs = sd_v2_attrs(sd);
sd_attrs_to_i_attrs(sd_v2_attrs(sd), inode);
diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c
index 1beaa739d0a..1b27b5688f6 100644
--- a/fs/sysfs/file.c
+++ b/fs/sysfs/file.c
@@ -593,7 +593,8 @@ EXPORT_SYMBOL_GPL(sysfs_add_file_to_group);
* @mode: file permissions.
*
*/
-int sysfs_chmod_file(struct kobject *kobj, struct attribute *attr, mode_t mode)
+int sysfs_chmod_file(struct kobject *kobj, const struct attribute *attr,
+ mode_t mode)
{
struct sysfs_dirent *sd;
struct iattr newattrs;
diff --git a/fs/ubifs/lpt.c b/fs/ubifs/lpt.c
index ad7f67b827e..0084a33c4c6 100644
--- a/fs/ubifs/lpt.c
+++ b/fs/ubifs/lpt.c
@@ -1457,13 +1457,13 @@ struct ubifs_lprops *ubifs_lpt_lookup(struct ubifs_info *c, int lnum)
shft -= UBIFS_LPT_FANOUT_SHIFT;
nnode = ubifs_get_nnode(c, nnode, iip);
if (IS_ERR(nnode))
- return ERR_PTR(PTR_ERR(nnode));
+ return ERR_CAST(nnode);
}
iip = ((i >> shft) & (UBIFS_LPT_FANOUT - 1));
shft -= UBIFS_LPT_FANOUT_SHIFT;
pnode = ubifs_get_pnode(c, nnode, iip);
if (IS_ERR(pnode))
- return ERR_PTR(PTR_ERR(pnode));
+ return ERR_CAST(pnode);
iip = (i & (UBIFS_LPT_FANOUT - 1));
dbg_lp("LEB %d, free %d, dirty %d, flags %d", lnum,
pnode->lprops[iip].free, pnode->lprops[iip].dirty,
@@ -1586,7 +1586,7 @@ struct ubifs_lprops *ubifs_lpt_lookup_dirty(struct ubifs_info *c, int lnum)
nnode = c->nroot;
nnode = dirty_cow_nnode(c, nnode);
if (IS_ERR(nnode))
- return ERR_PTR(PTR_ERR(nnode));
+ return ERR_CAST(nnode);
i = lnum - c->main_first;
shft = c->lpt_hght * UBIFS_LPT_FANOUT_SHIFT;
for (h = 1; h < c->lpt_hght; h++) {
@@ -1594,19 +1594,19 @@ struct ubifs_lprops *ubifs_lpt_lookup_dirty(struct ubifs_info *c, int lnum)
shft -= UBIFS_LPT_FANOUT_SHIFT;
nnode = ubifs_get_nnode(c, nnode, iip);
if (IS_ERR(nnode))
- return ERR_PTR(PTR_ERR(nnode));
+ return ERR_CAST(nnode);
nnode = dirty_cow_nnode(c, nnode);
if (IS_ERR(nnode))
- return ERR_PTR(PTR_ERR(nnode));
+ return ERR_CAST(nnode);
}
iip = ((i >> shft) & (UBIFS_LPT_FANOUT - 1));
shft -= UBIFS_LPT_FANOUT_SHIFT;
pnode = ubifs_get_pnode(c, nnode, iip);
if (IS_ERR(pnode))
- return ERR_PTR(PTR_ERR(pnode));
+ return ERR_CAST(pnode);
pnode = dirty_cow_pnode(c, pnode);
if (IS_ERR(pnode))
- return ERR_PTR(PTR_ERR(pnode));
+ return ERR_CAST(pnode);
iip = (i & (UBIFS_LPT_FANOUT - 1));
dbg_lp("LEB %d, free %d, dirty %d, flags %d", lnum,
pnode->lprops[iip].free, pnode->lprops[iip].dirty,
diff --git a/fs/ubifs/lpt_commit.c b/fs/ubifs/lpt_commit.c
index 13cb7a4237b..d12535b7fc7 100644
--- a/fs/ubifs/lpt_commit.c
+++ b/fs/ubifs/lpt_commit.c
@@ -646,7 +646,7 @@ static struct ubifs_pnode *pnode_lookup(struct ubifs_info *c, int i)
shft -= UBIFS_LPT_FANOUT_SHIFT;
nnode = ubifs_get_nnode(c, nnode, iip);
if (IS_ERR(nnode))
- return ERR_PTR(PTR_ERR(nnode));
+ return ERR_CAST(nnode);
}
iip = ((i >> shft) & (UBIFS_LPT_FANOUT - 1));
return ubifs_get_pnode(c, nnode, iip);
diff --git a/fs/ubifs/recovery.c b/fs/ubifs/recovery.c
index 109c6ea03bb..daae9e1f538 100644
--- a/fs/ubifs/recovery.c
+++ b/fs/ubifs/recovery.c
@@ -24,7 +24,7 @@
* This file implements functions needed to recover from unclean un-mounts.
* When UBIFS is mounted, it checks a flag on the master node to determine if
* an un-mount was completed successfully. If not, the process of mounting
- * incorparates additional checking and fixing of on-flash data structures.
+ * incorporates additional checking and fixing of on-flash data structures.
* UBIFS always cleans away all remnants of an unclean un-mount, so that
* errors do not accumulate. However UBIFS defers recovery if it is mounted
* read-only, and the flash is not modified in that case.
@@ -1063,8 +1063,21 @@ int ubifs_rcvry_gc_commit(struct ubifs_info *c)
}
err = ubifs_find_dirty_leb(c, &lp, wbuf->offs, 2);
if (err) {
- if (err == -ENOSPC)
- dbg_err("could not find a dirty LEB");
+ /*
+ * There are no dirty or empty LEBs subject to here being
+ * enough for the index. Try to use
+ * 'ubifs_find_free_leb_for_idx()', which will return any empty
+ * LEBs (ignoring index requirements). If the index then
+ * doesn't have enough LEBs the recovery commit will fail -
+ * which is the same result anyway i.e. recovery fails. So
+ * there is no problem ignoring index requirements and just
+ * grabbing a free LEB since we have already established there
+ * is not a dirty LEB we could have used instead.
+ */
+ if (err == -ENOSPC) {
+ dbg_rcvry("could not find a dirty LEB");
+ goto find_free;
+ }
return err;
}
ubifs_assert(!(lp.flags & LPROPS_INDEX));
@@ -1139,8 +1152,8 @@ int ubifs_rcvry_gc_commit(struct ubifs_info *c)
find_free:
/*
* There is no GC head LEB or the free space in the GC head LEB is too
- * small. Allocate gc_lnum by calling 'ubifs_find_free_leb_for_idx()' so
- * GC is not run.
+ * small, or there are not dirty LEBs. Allocate gc_lnum by calling
+ * 'ubifs_find_free_leb_for_idx()' so GC is not run.
*/
lnum = ubifs_find_free_leb_for_idx(c);
if (lnum < 0) {
diff --git a/fs/ubifs/super.c b/fs/ubifs/super.c
index 4d2f2157dd3..5fc5a098897 100644
--- a/fs/ubifs/super.c
+++ b/fs/ubifs/super.c
@@ -1307,6 +1307,8 @@ static int mount_ubifs(struct ubifs_info *c)
if (err)
goto out_orphans;
err = ubifs_rcvry_gc_commit(c);
+ if (err)
+ goto out_orphans;
} else {
err = take_gc_lnum(c);
if (err)
@@ -1318,7 +1320,7 @@ static int mount_ubifs(struct ubifs_info *c)
*/
err = ubifs_leb_unmap(c, c->gc_lnum);
if (err)
- return err;
+ goto out_orphans;
}
err = dbg_check_lprops(c);
diff --git a/fs/udf/file.c b/fs/udf/file.c
index 94e06d6bddb..6e450e01a1b 100644
--- a/fs/udf/file.c
+++ b/fs/udf/file.c
@@ -36,7 +36,6 @@
#include <linux/pagemap.h>
#include <linux/buffer_head.h>
#include <linux/aio.h>
-#include <linux/smp_lock.h>
#include "udf_i.h"
#include "udf_sb.h"
diff --git a/fs/udf/super.c b/fs/udf/super.c
index 612d1e2e285..12bb651e540 100644
--- a/fs/udf/super.c
+++ b/fs/udf/super.c
@@ -1579,9 +1579,7 @@ static int udf_load_sequence(struct super_block *sb, struct buffer_head *bh,
{
struct anchorVolDescPtr *anchor;
long main_s, main_e, reserve_s, reserve_e;
- struct udf_sb_info *sbi;
- sbi = UDF_SB(sb);
anchor = (struct anchorVolDescPtr *)bh->b_data;
/* Locate the main sequence */
diff --git a/fs/xfs/Makefile b/fs/xfs/Makefile
index c8fb13f83b3..0dce969d6ca 100644
--- a/fs/xfs/Makefile
+++ b/fs/xfs/Makefile
@@ -87,11 +87,9 @@ xfs-y += xfs_alloc.o \
xfs_trans_buf.o \
xfs_trans_extfree.o \
xfs_trans_inode.o \
- xfs_trans_item.o \
xfs_utils.o \
xfs_vnodeops.o \
- xfs_rw.o \
- xfs_dmops.o
+ xfs_rw.o
xfs-$(CONFIG_XFS_TRACE) += xfs_btree_trace.o
diff --git a/fs/xfs/linux-2.6/xfs_acl.c b/fs/xfs/linux-2.6/xfs_acl.c
index 9f769b5b38f..b2771862fd3 100644
--- a/fs/xfs/linux-2.6/xfs_acl.c
+++ b/fs/xfs/linux-2.6/xfs_acl.c
@@ -225,7 +225,7 @@ xfs_check_acl(struct inode *inode, int mask)
struct posix_acl *acl;
int error = -EAGAIN;
- xfs_itrace_entry(ip);
+ trace_xfs_check_acl(ip);
/*
* If there is no attribute fork no ACL exists on this inode and
diff --git a/fs/xfs/linux-2.6/xfs_aops.c b/fs/xfs/linux-2.6/xfs_aops.c
index 34640d6dbdc..d24e78f32f3 100644
--- a/fs/xfs/linux-2.6/xfs_aops.c
+++ b/fs/xfs/linux-2.6/xfs_aops.c
@@ -21,19 +21,12 @@
#include "xfs_inum.h"
#include "xfs_sb.h"
#include "xfs_ag.h"
-#include "xfs_dir2.h"
#include "xfs_trans.h"
-#include "xfs_dmapi.h"
#include "xfs_mount.h"
#include "xfs_bmap_btree.h"
-#include "xfs_alloc_btree.h"
-#include "xfs_ialloc_btree.h"
-#include "xfs_dir2_sf.h"
-#include "xfs_attr_sf.h"
#include "xfs_dinode.h"
#include "xfs_inode.h"
#include "xfs_alloc.h"
-#include "xfs_btree.h"
#include "xfs_error.h"
#include "xfs_rw.h"
#include "xfs_iomap.h"
@@ -92,18 +85,15 @@ void
xfs_count_page_state(
struct page *page,
int *delalloc,
- int *unmapped,
int *unwritten)
{
struct buffer_head *bh, *head;
- *delalloc = *unmapped = *unwritten = 0;
+ *delalloc = *unwritten = 0;
bh = head = page_buffers(page);
do {
- if (buffer_uptodate(bh) && !buffer_mapped(bh))
- (*unmapped) = 1;
- else if (buffer_unwritten(bh))
+ if (buffer_unwritten(bh))
(*unwritten) = 1;
else if (buffer_delay(bh))
(*delalloc) = 1;
@@ -212,23 +202,17 @@ xfs_setfilesize(
}
/*
- * Schedule IO completion handling on a xfsdatad if this was
- * the final hold on this ioend. If we are asked to wait,
- * flush the workqueue.
+ * Schedule IO completion handling on the final put of an ioend.
*/
STATIC void
xfs_finish_ioend(
- xfs_ioend_t *ioend,
- int wait)
+ struct xfs_ioend *ioend)
{
if (atomic_dec_and_test(&ioend->io_remaining)) {
- struct workqueue_struct *wq;
-
- wq = (ioend->io_type == IO_UNWRITTEN) ?
- xfsconvertd_workqueue : xfsdatad_workqueue;
- queue_work(wq, &ioend->io_work);
- if (wait)
- flush_workqueue(wq);
+ if (ioend->io_type == IO_UNWRITTEN)
+ queue_work(xfsconvertd_workqueue, &ioend->io_work);
+ else
+ queue_work(xfsdatad_workqueue, &ioend->io_work);
}
}
@@ -272,11 +256,25 @@ xfs_end_io(
*/
if (error == EAGAIN) {
atomic_inc(&ioend->io_remaining);
- xfs_finish_ioend(ioend, 0);
+ xfs_finish_ioend(ioend);
/* ensure we don't spin on blocked ioends */
delay(1);
- } else
+ } else {
+ if (ioend->io_iocb)
+ aio_complete(ioend->io_iocb, ioend->io_result, 0);
xfs_destroy_ioend(ioend);
+ }
+}
+
+/*
+ * Call IO completion handling in caller context on the final put of an ioend.
+ */
+STATIC void
+xfs_finish_ioend_sync(
+ struct xfs_ioend *ioend)
+{
+ if (atomic_dec_and_test(&ioend->io_remaining))
+ xfs_end_io(&ioend->io_work);
}
/*
@@ -309,6 +307,8 @@ xfs_alloc_ioend(
atomic_inc(&XFS_I(ioend->io_inode)->i_iocount);
ioend->io_offset = 0;
ioend->io_size = 0;
+ ioend->io_iocb = NULL;
+ ioend->io_result = 0;
INIT_WORK(&ioend->io_work, xfs_end_io);
return ioend;
@@ -358,7 +358,7 @@ xfs_end_bio(
bio->bi_end_io = NULL;
bio_put(bio);
- xfs_finish_ioend(ioend, 0);
+ xfs_finish_ioend(ioend);
}
STATIC void
@@ -500,7 +500,7 @@ xfs_submit_ioend(
}
if (bio)
xfs_submit_ioend_bio(wbc, ioend, bio);
- xfs_finish_ioend(ioend, 0);
+ xfs_finish_ioend(ioend);
} while ((ioend = next) != NULL);
}
@@ -614,31 +614,30 @@ xfs_map_at_offset(
STATIC unsigned int
xfs_probe_page(
struct page *page,
- unsigned int pg_offset,
- int mapped)
+ unsigned int pg_offset)
{
+ struct buffer_head *bh, *head;
int ret = 0;
if (PageWriteback(page))
return 0;
+ if (!PageDirty(page))
+ return 0;
+ if (!page->mapping)
+ return 0;
+ if (!page_has_buffers(page))
+ return 0;
- if (page->mapping && PageDirty(page)) {
- if (page_has_buffers(page)) {
- struct buffer_head *bh, *head;
-
- bh = head = page_buffers(page);
- do {
- if (!buffer_uptodate(bh))
- break;
- if (mapped != buffer_mapped(bh))
- break;
- ret += bh->b_size;
- if (ret >= pg_offset)
- break;
- } while ((bh = bh->b_this_page) != head);
- } else
- ret = mapped ? 0 : PAGE_CACHE_SIZE;
- }
+ bh = head = page_buffers(page);
+ do {
+ if (!buffer_uptodate(bh))
+ break;
+ if (!buffer_mapped(bh))
+ break;
+ ret += bh->b_size;
+ if (ret >= pg_offset)
+ break;
+ } while ((bh = bh->b_this_page) != head);
return ret;
}
@@ -648,8 +647,7 @@ xfs_probe_cluster(
struct inode *inode,
struct page *startpage,
struct buffer_head *bh,
- struct buffer_head *head,
- int mapped)
+ struct buffer_head *head)
{
struct pagevec pvec;
pgoff_t tindex, tlast, tloff;
@@ -658,7 +656,7 @@ xfs_probe_cluster(
/* First sum forwards in this page */
do {
- if (!buffer_uptodate(bh) || (mapped != buffer_mapped(bh)))
+ if (!buffer_uptodate(bh) || !buffer_mapped(bh))
return total;
total += bh->b_size;
} while ((bh = bh->b_this_page) != head);
@@ -692,7 +690,7 @@ xfs_probe_cluster(
pg_offset = PAGE_CACHE_SIZE;
if (page->index == tindex && trylock_page(page)) {
- pg_len = xfs_probe_page(page, pg_offset, mapped);
+ pg_len = xfs_probe_page(page, pg_offset);
unlock_page(page);
}
@@ -761,7 +759,6 @@ xfs_convert_page(
struct xfs_bmbt_irec *imap,
xfs_ioend_t **ioendp,
struct writeback_control *wbc,
- int startio,
int all_bh)
{
struct buffer_head *bh, *head;
@@ -832,19 +829,14 @@ xfs_convert_page(
ASSERT(imap->br_startblock != DELAYSTARTBLOCK);
xfs_map_at_offset(inode, bh, imap, offset);
- if (startio) {
- xfs_add_to_ioend(inode, bh, offset,
- type, ioendp, done);
- } else {
- set_buffer_dirty(bh);
- unlock_buffer(bh);
- mark_buffer_dirty(bh);
- }
+ xfs_add_to_ioend(inode, bh, offset, type,
+ ioendp, done);
+
page_dirty--;
count++;
} else {
type = IO_NEW;
- if (buffer_mapped(bh) && all_bh && startio) {
+ if (buffer_mapped(bh) && all_bh) {
lock_buffer(bh);
xfs_add_to_ioend(inode, bh, offset,
type, ioendp, done);
@@ -859,14 +851,12 @@ xfs_convert_page(
if (uptodate && bh == head)
SetPageUptodate(page);
- if (startio) {
- if (count) {
- wbc->nr_to_write--;
- if (wbc->nr_to_write <= 0)
- done = 1;
- }
- xfs_start_page_writeback(page, !page_dirty, count);
+ if (count) {
+ wbc->nr_to_write--;
+ if (wbc->nr_to_write <= 0)
+ done = 1;
}
+ xfs_start_page_writeback(page, !page_dirty, count);
return done;
fail_unlock_page:
@@ -886,7 +876,6 @@ xfs_cluster_write(
struct xfs_bmbt_irec *imap,
xfs_ioend_t **ioendp,
struct writeback_control *wbc,
- int startio,
int all_bh,
pgoff_t tlast)
{
@@ -902,7 +891,7 @@ xfs_cluster_write(
for (i = 0; i < pagevec_count(&pvec); i++) {
done = xfs_convert_page(inode, pvec.pages[i], tindex++,
- imap, ioendp, wbc, startio, all_bh);
+ imap, ioendp, wbc, all_bh);
if (done)
break;
}
@@ -981,7 +970,7 @@ xfs_aops_discard_page(
*/
error = xfs_bmapi(NULL, ip, offset_fsb, 1,
XFS_BMAPI_ENTIRE, NULL, 0, &imap,
- &nimaps, NULL, NULL);
+ &nimaps, NULL);
if (error) {
/* something screwed, just bail */
@@ -1009,7 +998,7 @@ xfs_aops_discard_page(
*/
xfs_bmap_init(&flist, &firstblock);
error = xfs_bunmapi(NULL, ip, offset_fsb, 1, 0, 1, &firstblock,
- &flist, NULL, &done);
+ &flist, &done);
ASSERT(!flist.xbf_count && !flist.xbf_first);
if (error) {
@@ -1032,50 +1021,66 @@ out_invalidate:
}
/*
- * Calling this without startio set means we are being asked to make a dirty
- * page ready for freeing it's buffers. When called with startio set then
- * we are coming from writepage.
+ * Write out a dirty page.
+ *
+ * For delalloc space on the page we need to allocate space and flush it.
+ * For unwritten space on the page we need to start the conversion to
+ * regular allocated space.
+ * For any other dirty buffer heads on the page we should flush them.
*
- * When called with startio set it is important that we write the WHOLE
- * page if possible.
- * The bh->b_state's cannot know if any of the blocks or which block for
- * that matter are dirty due to mmap writes, and therefore bh uptodate is
- * only valid if the page itself isn't completely uptodate. Some layers
- * may clear the page dirty flag prior to calling write page, under the
- * assumption the entire page will be written out; by not writing out the
- * whole page the page can be reused before all valid dirty data is
- * written out. Note: in the case of a page that has been dirty'd by
- * mapwrite and but partially setup by block_prepare_write the
- * bh->b_states's will not agree and only ones setup by BPW/BCW will have
- * valid state, thus the whole page must be written out thing.
+ * If we detect that a transaction would be required to flush the page, we
+ * have to check the process flags first, if we are already in a transaction
+ * or disk I/O during allocations is off, we need to fail the writepage and
+ * redirty the page.
*/
-
STATIC int
-xfs_page_state_convert(
- struct inode *inode,
- struct page *page,
- struct writeback_control *wbc,
- int startio,
- int unmapped) /* also implies page uptodate */
+xfs_vm_writepage(
+ struct page *page,
+ struct writeback_control *wbc)
{
+ struct inode *inode = page->mapping->host;
+ int delalloc, unwritten;
struct buffer_head *bh, *head;
struct xfs_bmbt_irec imap;
xfs_ioend_t *ioend = NULL, *iohead = NULL;
loff_t offset;
- unsigned long p_offset = 0;
unsigned int type;
__uint64_t end_offset;
pgoff_t end_index, last_index;
ssize_t size, len;
int flags, err, imap_valid = 0, uptodate = 1;
- int page_dirty, count = 0;
- int trylock = 0;
- int all_bh = unmapped;
+ int count = 0;
+ int all_bh = 0;
- if (startio) {
- if (wbc->sync_mode == WB_SYNC_NONE && wbc->nonblocking)
- trylock |= BMAPI_TRYLOCK;
- }
+ trace_xfs_writepage(inode, page, 0);
+
+ ASSERT(page_has_buffers(page));
+
+ /*
+ * Refuse to write the page out if we are called from reclaim context.
+ *
+ * This avoids stack overflows when called from deeply used stacks in
+ * random callers for direct reclaim or memcg reclaim. We explicitly
+ * allow reclaim from kswapd as the stack usage there is relatively low.
+ *
+ * This should really be done by the core VM, but until that happens
+ * filesystems like XFS, btrfs and ext4 have to take care of this
+ * by themselves.
+ */
+ if ((current->flags & (PF_MEMALLOC|PF_KSWAPD)) == PF_MEMALLOC)
+ goto out_fail;
+
+ /*
+ * We need a transaction if there are delalloc or unwritten buffers
+ * on the page.
+ *
+ * If we need a transaction and the process flags say we are already
+ * in a transaction, or no IO is allowed then mark the page dirty
+ * again and leave the page as is.
+ */
+ xfs_count_page_state(page, &delalloc, &unwritten);
+ if ((current->flags & PF_FSTRANS) && (delalloc || unwritten))
+ goto out_fail;
/* Is this page beyond the end of the file? */
offset = i_size_read(inode);
@@ -1084,50 +1089,33 @@ xfs_page_state_convert(
if (page->index >= end_index) {
if ((page->index >= end_index + 1) ||
!(i_size_read(inode) & (PAGE_CACHE_SIZE - 1))) {
- if (startio)
- unlock_page(page);
+ unlock_page(page);
return 0;
}
}
- /*
- * page_dirty is initially a count of buffers on the page before
- * EOF and is decremented as we move each into a cleanable state.
- *
- * Derivation:
- *
- * End offset is the highest offset that this page should represent.
- * If we are on the last page, (end_offset & (PAGE_CACHE_SIZE - 1))
- * will evaluate non-zero and be less than PAGE_CACHE_SIZE and
- * hence give us the correct page_dirty count. On any other page,
- * it will be zero and in that case we need page_dirty to be the
- * count of buffers on the page.
- */
end_offset = min_t(unsigned long long,
- (xfs_off_t)(page->index + 1) << PAGE_CACHE_SHIFT, offset);
+ (xfs_off_t)(page->index + 1) << PAGE_CACHE_SHIFT,
+ offset);
len = 1 << inode->i_blkbits;
- p_offset = min_t(unsigned long, end_offset & (PAGE_CACHE_SIZE - 1),
- PAGE_CACHE_SIZE);
- p_offset = p_offset ? roundup(p_offset, len) : PAGE_CACHE_SIZE;
- page_dirty = p_offset / len;
bh = head = page_buffers(page);
offset = page_offset(page);
flags = BMAPI_READ;
type = IO_NEW;
- /* TODO: cleanup count and page_dirty */
-
do {
if (offset >= end_offset)
break;
if (!buffer_uptodate(bh))
uptodate = 0;
- if (!(PageUptodate(page) || buffer_uptodate(bh)) && !startio) {
- /*
- * the iomap is actually still valid, but the ioend
- * isn't. shouldn't happen too often.
- */
+
+ /*
+ * A hole may still be marked uptodate because discard_buffer
+ * leaves the flag set.
+ */
+ if (!buffer_mapped(bh) && buffer_uptodate(bh)) {
+ ASSERT(!buffer_dirty(bh));
imap_valid = 0;
continue;
}
@@ -1135,19 +1123,7 @@ xfs_page_state_convert(
if (imap_valid)
imap_valid = xfs_imap_valid(inode, &imap, offset);
- /*
- * First case, map an unwritten extent and prepare for
- * extent state conversion transaction on completion.
- *
- * Second case, allocate space for a delalloc buffer.
- * We can return EAGAIN here in the release page case.
- *
- * Third case, an unmapped buffer was found, and we are
- * in a path where we need to write the whole page out.
- */
- if (buffer_unwritten(bh) || buffer_delay(bh) ||
- ((buffer_uptodate(bh) || PageUptodate(page)) &&
- !buffer_mapped(bh) && (unmapped || startio))) {
+ if (buffer_unwritten(bh) || buffer_delay(bh)) {
int new_ioend = 0;
/*
@@ -1161,15 +1137,16 @@ xfs_page_state_convert(
flags = BMAPI_WRITE | BMAPI_IGNSTATE;
} else if (buffer_delay(bh)) {
type = IO_DELAY;
- flags = BMAPI_ALLOCATE | trylock;
- } else {
- type = IO_NEW;
- flags = BMAPI_WRITE | BMAPI_MMAP;
+ flags = BMAPI_ALLOCATE;
+
+ if (wbc->sync_mode == WB_SYNC_NONE &&
+ wbc->nonblocking)
+ flags |= BMAPI_TRYLOCK;
}
if (!imap_valid) {
/*
- * if we didn't have a valid mapping then we
+ * 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
@@ -1177,14 +1154,7 @@ xfs_page_state_convert(
* for unwritten extent conversion.
*/
new_ioend = 1;
- if (type == IO_NEW) {
- size = xfs_probe_cluster(inode,
- page, bh, head, 0);
- } else {
- size = len;
- }
-
- err = xfs_map_blocks(inode, offset, size,
+ err = xfs_map_blocks(inode, offset, len,
&imap, flags);
if (err)
goto error;
@@ -1193,19 +1163,11 @@ xfs_page_state_convert(
}
if (imap_valid) {
xfs_map_at_offset(inode, bh, &imap, offset);
- if (startio) {
- xfs_add_to_ioend(inode, bh, offset,
- type, &ioend,
- new_ioend);
- } else {
- set_buffer_dirty(bh);
- unlock_buffer(bh);
- mark_buffer_dirty(bh);
- }
- page_dirty--;
+ xfs_add_to_ioend(inode, bh, offset, type,
+ &ioend, new_ioend);
count++;
}
- } else if (buffer_uptodate(bh) && startio) {
+ } else if (buffer_uptodate(bh)) {
/*
* we got here because the buffer is already mapped.
* That means it must already have extents allocated
@@ -1213,8 +1175,7 @@ xfs_page_state_convert(
*/
if (!imap_valid || flags != BMAPI_READ) {
flags = BMAPI_READ;
- size = xfs_probe_cluster(inode, page, bh,
- head, 1);
+ size = xfs_probe_cluster(inode, page, bh, head);
err = xfs_map_blocks(inode, offset, size,
&imap, flags);
if (err)
@@ -1233,18 +1194,16 @@ xfs_page_state_convert(
*/
type = IO_NEW;
if (trylock_buffer(bh)) {
- ASSERT(buffer_mapped(bh));
if (imap_valid)
all_bh = 1;
xfs_add_to_ioend(inode, bh, offset, type,
&ioend, !imap_valid);
- page_dirty--;
count++;
} else {
imap_valid = 0;
}
- } else if ((buffer_uptodate(bh) || PageUptodate(page)) &&
- (unmapped || startio)) {
+ } else if (PageUptodate(page)) {
+ ASSERT(buffer_mapped(bh));
imap_valid = 0;
}
@@ -1256,8 +1215,7 @@ xfs_page_state_convert(
if (uptodate && bh == head)
SetPageUptodate(page);
- if (startio)
- xfs_start_page_writeback(page, 1, count);
+ xfs_start_page_writeback(page, 1, count);
if (ioend && imap_valid) {
xfs_off_t end_index;
@@ -1275,131 +1233,27 @@ xfs_page_state_convert(
end_index = last_index;
xfs_cluster_write(inode, page->index + 1, &imap, &ioend,
- wbc, startio, all_bh, end_index);
+ wbc, all_bh, end_index);
}
if (iohead)
xfs_submit_ioend(wbc, iohead);
- return page_dirty;
+ return 0;
error:
if (iohead)
xfs_cancel_ioend(iohead);
- /*
- * If it's delalloc and we have nowhere to put it,
- * throw it away, unless the lower layers told
- * us to try again.
- */
- if (err != -EAGAIN) {
- if (!unmapped)
- xfs_aops_discard_page(page);
- ClearPageUptodate(page);
- }
+ xfs_aops_discard_page(page);
+ ClearPageUptodate(page);
+ unlock_page(page);
return err;
-}
-
-/*
- * writepage: Called from one of two places:
- *
- * 1. we are flushing a delalloc buffer head.
- *
- * 2. we are writing out a dirty page. Typically the page dirty
- * state is cleared before we get here. In this case is it
- * conceivable we have no buffer heads.
- *
- * For delalloc space on the page we need to allocate space and
- * flush it. For unmapped buffer heads on the page we should
- * allocate space if the page is uptodate. For any other dirty
- * buffer heads on the page we should flush them.
- *
- * If we detect that a transaction would be required to flush
- * the page, we have to check the process flags first, if we
- * are already in a transaction or disk I/O during allocations
- * is off, we need to fail the writepage and redirty the page.
- */
-
-STATIC int
-xfs_vm_writepage(
- struct page *page,
- struct writeback_control *wbc)
-{
- int error;
- int need_trans;
- int delalloc, unmapped, unwritten;
- struct inode *inode = page->mapping->host;
-
- trace_xfs_writepage(inode, page, 0);
-
- /*
- * Refuse to write the page out if we are called from reclaim context.
- *
- * This is primarily to avoid stack overflows when called from deep
- * used stacks in random callers for direct reclaim, but disabling
- * reclaim for kswap is a nice side-effect as kswapd causes rather
- * suboptimal I/O patters, too.
- *
- * This should really be done by the core VM, but until that happens
- * filesystems like XFS, btrfs and ext4 have to take care of this
- * by themselves.
- */
- if (current->flags & PF_MEMALLOC)
- goto out_fail;
-
- /*
- * We need a transaction if:
- * 1. There are delalloc buffers on the page
- * 2. The page is uptodate and we have unmapped buffers
- * 3. The page is uptodate and we have no buffers
- * 4. There are unwritten buffers on the page
- */
-
- if (!page_has_buffers(page)) {
- unmapped = 1;
- need_trans = 1;
- } else {
- xfs_count_page_state(page, &delalloc, &unmapped, &unwritten);
- if (!PageUptodate(page))
- unmapped = 0;
- need_trans = delalloc + unmapped + unwritten;
- }
-
- /*
- * If we need a transaction and the process flags say
- * we are already in a transaction, or no IO is allowed
- * then mark the page dirty again and leave the page
- * as is.
- */
- if (current_test_flags(PF_FSTRANS) && need_trans)
- goto out_fail;
-
- /*
- * Delay hooking up buffer heads until we have
- * made our go/no-go decision.
- */
- if (!page_has_buffers(page))
- create_empty_buffers(page, 1 << inode->i_blkbits, 0);
-
- /*
- * Convert delayed allocate, unwritten or unmapped space
- * to real space and flush out to disk.
- */
- error = xfs_page_state_convert(inode, page, wbc, 1, unmapped);
- if (error == -EAGAIN)
- goto out_fail;
- if (unlikely(error < 0))
- goto out_unlock;
-
- return 0;
out_fail:
redirty_page_for_writepage(wbc, page);
unlock_page(page);
return 0;
-out_unlock:
- unlock_page(page);
- return error;
}
STATIC int
@@ -1413,65 +1267,27 @@ xfs_vm_writepages(
/*
* Called to move a page into cleanable state - and from there
- * to be released. Possibly the page is already clean. We always
+ * to be released. The page should already be clean. We always
* have buffer heads in this call.
*
- * Returns 0 if the page is ok to release, 1 otherwise.
- *
- * Possible scenarios are:
- *
- * 1. We are being called to release a page which has been written
- * to via regular I/O. buffer heads will be dirty and possibly
- * delalloc. If no delalloc buffer heads in this case then we
- * can just return zero.
- *
- * 2. We are called to release a page which has been written via
- * mmap, all we need to do is ensure there is no delalloc
- * state in the buffer heads, if not we can let the caller
- * free them and we should come back later via writepage.
+ * Returns 1 if the page is ok to release, 0 otherwise.
*/
STATIC int
xfs_vm_releasepage(
struct page *page,
gfp_t gfp_mask)
{
- struct inode *inode = page->mapping->host;
- int dirty, delalloc, unmapped, unwritten;
- struct writeback_control wbc = {
- .sync_mode = WB_SYNC_ALL,
- .nr_to_write = 1,
- };
+ int delalloc, unwritten;
- trace_xfs_releasepage(inode, page, 0);
-
- if (!page_has_buffers(page))
- return 0;
+ trace_xfs_releasepage(page->mapping->host, page, 0);
- xfs_count_page_state(page, &delalloc, &unmapped, &unwritten);
- if (!delalloc && !unwritten)
- goto free_buffers;
+ xfs_count_page_state(page, &delalloc, &unwritten);
- if (!(gfp_mask & __GFP_FS))
+ if (WARN_ON(delalloc))
return 0;
-
- /* If we are already inside a transaction or the thread cannot
- * do I/O, we cannot release this page.
- */
- if (current_test_flags(PF_FSTRANS))
+ if (WARN_ON(unwritten))
return 0;
- /*
- * Convert delalloc space to real space, do not flush the
- * data out to disk, that will be done by the caller.
- * Never need to allocate space here - we will always
- * come back to writepage in that case.
- */
- dirty = xfs_page_state_convert(inode, page, &wbc, 0, 0);
- if (dirty == 0 && !unwritten)
- goto free_buffers;
- return 0;
-
-free_buffers:
return try_to_free_buffers(page);
}
@@ -1481,9 +1297,9 @@ __xfs_get_blocks(
sector_t iblock,
struct buffer_head *bh_result,
int create,
- int direct,
- bmapi_flags_t flags)
+ int direct)
{
+ int flags = create ? BMAPI_WRITE : BMAPI_READ;
struct xfs_bmbt_irec imap;
xfs_off_t offset;
ssize_t size;
@@ -1498,8 +1314,11 @@ __xfs_get_blocks(
if (!create && direct && offset >= i_size_read(inode))
return 0;
- error = xfs_iomap(XFS_I(inode), offset, size,
- create ? flags : BMAPI_READ, &imap, &nimap, &new);
+ if (direct && create)
+ flags |= BMAPI_DIRECT;
+
+ error = xfs_iomap(XFS_I(inode), offset, size, flags, &imap, &nimap,
+ &new);
if (error)
return -error;
if (nimap == 0)
@@ -1579,8 +1398,7 @@ xfs_get_blocks(
struct buffer_head *bh_result,
int create)
{
- return __xfs_get_blocks(inode, iblock,
- bh_result, create, 0, BMAPI_WRITE);
+ return __xfs_get_blocks(inode, iblock, bh_result, create, 0);
}
STATIC int
@@ -1590,61 +1408,59 @@ xfs_get_blocks_direct(
struct buffer_head *bh_result,
int create)
{
- return __xfs_get_blocks(inode, iblock,
- bh_result, create, 1, BMAPI_WRITE|BMAPI_DIRECT);
+ return __xfs_get_blocks(inode, iblock, bh_result, create, 1);
}
+/*
+ * Complete a direct I/O write request.
+ *
+ * If the private argument is non-NULL __xfs_get_blocks signals us that we
+ * need to issue a transaction to convert the range from unwritten to written
+ * extents. In case this is regular synchronous I/O we just call xfs_end_io
+ * to do this and we are done. But in case this was a successfull AIO
+ * request this handler is called from interrupt context, from which we
+ * can't start transactions. In that case offload the I/O completion to
+ * the workqueues we also use for buffered I/O completion.
+ */
STATIC void
-xfs_end_io_direct(
- struct kiocb *iocb,
- loff_t offset,
- ssize_t size,
- void *private)
+xfs_end_io_direct_write(
+ struct kiocb *iocb,
+ loff_t offset,
+ ssize_t size,
+ void *private,
+ int ret,
+ bool is_async)
{
- xfs_ioend_t *ioend = iocb->private;
+ struct xfs_ioend *ioend = iocb->private;
/*
- * Non-NULL private data means we need to issue a transaction to
- * convert a range from unwritten to written extents. This needs
- * to happen from process context but aio+dio I/O completion
- * happens from irq context so we need to defer it to a workqueue.
- * 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.
+ * blockdev_direct_IO can return an error even after the I/O
+ * completion handler was called. Thus we need to protect
+ * against double-freeing.
*/
+ iocb->private = NULL;
+
ioend->io_offset = offset;
ioend->io_size = size;
- if (ioend->io_type == IO_READ) {
- xfs_finish_ioend(ioend, 0);
- } else if (private && size > 0) {
- xfs_finish_ioend(ioend, is_sync_kiocb(iocb));
- } else {
+ if (private && size > 0)
+ ioend->io_type = IO_UNWRITTEN;
+
+ if (is_async) {
/*
- * A direct I/O write ioend starts it's life in unwritten
- * state in case they map an unwritten extent. This write
- * didn't map an unwritten extent so switch it's completion
- * handler.
+ * If we are converting an unwritten extent we need to delay
+ * the AIO completion until after the unwrittent extent
+ * conversion has completed, otherwise do it ASAP.
*/
- ioend->io_type = IO_NEW;
- xfs_finish_ioend(ioend, 0);
+ if (ioend->io_type == IO_UNWRITTEN) {
+ ioend->io_iocb = iocb;
+ ioend->io_result = ret;
+ } else {
+ aio_complete(iocb, ret, 0);
+ }
+ xfs_finish_ioend(ioend);
+ } else {
+ xfs_finish_ioend_sync(ioend);
}
-
- /*
- * blockdev_direct_IO can return an error even after the I/O
- * completion handler was called. Thus we need to protect
- * against double-freeing.
- */
- iocb->private = NULL;
}
STATIC ssize_t
@@ -1655,23 +1471,26 @@ xfs_vm_direct_IO(
loff_t offset,
unsigned long nr_segs)
{
- struct file *file = iocb->ki_filp;
- struct inode *inode = file->f_mapping->host;
- struct block_device *bdev;
- ssize_t ret;
-
- bdev = xfs_find_bdev_for_inode(inode);
-
- iocb->private = xfs_alloc_ioend(inode, rw == WRITE ?
- IO_UNWRITTEN : IO_READ);
-
- ret = blockdev_direct_IO_no_locking(rw, iocb, inode, bdev, iov,
- offset, nr_segs,
- xfs_get_blocks_direct,
- xfs_end_io_direct);
+ struct inode *inode = iocb->ki_filp->f_mapping->host;
+ struct block_device *bdev = xfs_find_bdev_for_inode(inode);
+ ssize_t ret;
+
+ if (rw & WRITE) {
+ iocb->private = xfs_alloc_ioend(inode, IO_NEW);
+
+ ret = blockdev_direct_IO_no_locking(rw, iocb, inode, bdev, iov,
+ offset, nr_segs,
+ xfs_get_blocks_direct,
+ xfs_end_io_direct_write);
+ if (ret != -EIOCBQUEUED && iocb->private)
+ xfs_destroy_ioend(iocb->private);
+ } else {
+ ret = blockdev_direct_IO_no_locking(rw, iocb, inode, bdev, iov,
+ offset, nr_segs,
+ xfs_get_blocks_direct,
+ NULL);
+ }
- if (unlikely(ret != -EIOCBQUEUED && iocb->private))
- xfs_destroy_ioend(iocb->private);
return ret;
}
@@ -1686,8 +1505,8 @@ xfs_vm_write_begin(
void **fsdata)
{
*pagep = NULL;
- return block_write_begin(file, mapping, pos, len, flags, pagep, fsdata,
- xfs_get_blocks);
+ return block_write_begin(file, mapping, pos, len, flags | AOP_FLAG_NOFS,
+ pagep, fsdata, xfs_get_blocks);
}
STATIC sector_t
@@ -1698,7 +1517,7 @@ xfs_vm_bmap(
struct inode *inode = (struct inode *)mapping->host;
struct xfs_inode *ip = XFS_I(inode);
- xfs_itrace_entry(XFS_I(inode));
+ trace_xfs_vm_bmap(XFS_I(inode));
xfs_ilock(ip, XFS_IOLOCK_SHARED);
xfs_flush_pages(ip, (xfs_off_t)0, -1, 0, FI_REMAPF);
xfs_iunlock(ip, XFS_IOLOCK_SHARED);
diff --git a/fs/xfs/linux-2.6/xfs_aops.h b/fs/xfs/linux-2.6/xfs_aops.h
index 4cfc6ea87df..c5057fb6237 100644
--- a/fs/xfs/linux-2.6/xfs_aops.h
+++ b/fs/xfs/linux-2.6/xfs_aops.h
@@ -37,6 +37,8 @@ typedef struct xfs_ioend {
size_t io_size; /* size of the extent */
xfs_off_t io_offset; /* offset in the file */
struct work_struct io_work; /* xfsdatad work queue */
+ struct kiocb *io_iocb;
+ int io_result;
} xfs_ioend_t;
extern const struct address_space_operations xfs_address_space_operations;
@@ -45,6 +47,6 @@ extern int xfs_get_blocks(struct inode *, sector_t, struct buffer_head *, int);
extern void xfs_ioend_init(void);
extern void xfs_ioend_wait(struct xfs_inode *);
-extern void xfs_count_page_state(struct page *, int *, int *, int *);
+extern void xfs_count_page_state(struct page *, int *, int *);
#endif /* __XFS_AOPS_H__ */
diff --git a/fs/xfs/linux-2.6/xfs_buf.c b/fs/xfs/linux-2.6/xfs_buf.c
index 2ee3f7a6016..ea79072f521 100644
--- a/fs/xfs/linux-2.6/xfs_buf.c
+++ b/fs/xfs/linux-2.6/xfs_buf.c
@@ -39,7 +39,6 @@
#include "xfs_inum.h"
#include "xfs_log.h"
#include "xfs_ag.h"
-#include "xfs_dmapi.h"
#include "xfs_mount.h"
#include "xfs_trace.h"
@@ -579,9 +578,9 @@ _xfs_buf_read(
XBF_READ_AHEAD | _XBF_RUN_QUEUES);
status = xfs_buf_iorequest(bp);
- if (!status && !(flags & XBF_ASYNC))
- status = xfs_buf_iowait(bp);
- return status;
+ if (status || XFS_BUF_ISERROR(bp) || (flags & XBF_ASYNC))
+ return status;
+ return xfs_buf_iowait(bp);
}
xfs_buf_t *
@@ -897,36 +896,6 @@ xfs_buf_unlock(
trace_xfs_buf_unlock(bp, _RET_IP_);
}
-
-/*
- * Pinning Buffer Storage in Memory
- * Ensure that no attempt to force a buffer to disk will succeed.
- */
-void
-xfs_buf_pin(
- xfs_buf_t *bp)
-{
- trace_xfs_buf_pin(bp, _RET_IP_);
- atomic_inc(&bp->b_pin_count);
-}
-
-void
-xfs_buf_unpin(
- xfs_buf_t *bp)
-{
- trace_xfs_buf_unpin(bp, _RET_IP_);
-
- if (atomic_dec_and_test(&bp->b_pin_count))
- wake_up_all(&bp->b_waiters);
-}
-
-int
-xfs_buf_ispin(
- xfs_buf_t *bp)
-{
- return atomic_read(&bp->b_pin_count);
-}
-
STATIC void
xfs_buf_wait_unpin(
xfs_buf_t *bp)
@@ -1018,13 +987,12 @@ xfs_bwrite(
{
int error;
- bp->b_strat = xfs_bdstrat_cb;
bp->b_mount = mp;
bp->b_flags |= XBF_WRITE;
bp->b_flags &= ~(XBF_ASYNC | XBF_READ);
xfs_buf_delwri_dequeue(bp);
- xfs_buf_iostrategy(bp);
+ xfs_bdstrat_cb(bp);
error = xfs_buf_iowait(bp);
if (error)
@@ -1040,7 +1008,6 @@ xfs_bdwrite(
{
trace_xfs_buf_bdwrite(bp, _RET_IP_);
- bp->b_strat = xfs_bdstrat_cb;
bp->b_mount = mp;
bp->b_flags &= ~XBF_READ;
@@ -1075,7 +1042,6 @@ xfs_bioerror(
XFS_BUF_UNDONE(bp);
XFS_BUF_STALE(bp);
- XFS_BUF_CLR_BDSTRAT_FUNC(bp);
xfs_biodone(bp);
return EIO;
@@ -1105,7 +1071,6 @@ xfs_bioerror_relse(
XFS_BUF_DONE(bp);
XFS_BUF_STALE(bp);
XFS_BUF_CLR_IODONE_FUNC(bp);
- XFS_BUF_CLR_BDSTRAT_FUNC(bp);
if (!(fl & XBF_ASYNC)) {
/*
* Mark b_error and B_ERROR _both_.
@@ -1311,8 +1276,19 @@ submit_io:
if (size)
goto next_chunk;
} else {
- bio_put(bio);
+ /*
+ * if we get here, no pages were added to the bio. However,
+ * we can't just error out here - if the pages are locked then
+ * we have to unlock them otherwise we can hang on a later
+ * access to the page.
+ */
xfs_buf_ioerror(bp, EIO);
+ if (bp->b_flags & _XBF_PAGE_LOCKED) {
+ int i;
+ for (i = 0; i < bp->b_page_count; i++)
+ unlock_page(bp->b_pages[i]);
+ }
+ bio_put(bio);
}
}
@@ -1804,7 +1780,7 @@ xfs_buf_delwri_split(
trace_xfs_buf_delwri_split(bp, _RET_IP_);
ASSERT(bp->b_flags & XBF_DELWRI);
- if (!xfs_buf_ispin(bp) && !xfs_buf_cond_lock(bp)) {
+ if (!XFS_BUF_ISPINNED(bp) && !xfs_buf_cond_lock(bp)) {
if (!force &&
time_before(jiffies, bp->b_queuetime + age)) {
xfs_buf_unlock(bp);
@@ -1889,7 +1865,7 @@ xfsbufd(
struct xfs_buf *bp;
bp = list_first_entry(&tmp, struct xfs_buf, b_list);
list_del_init(&bp->b_list);
- xfs_buf_iostrategy(bp);
+ xfs_bdstrat_cb(bp);
count++;
}
if (count)
@@ -1936,7 +1912,7 @@ xfs_flush_buftarg(
bp->b_flags &= ~XBF_ASYNC;
list_add(&bp->b_list, &wait_list);
}
- xfs_buf_iostrategy(bp);
+ xfs_bdstrat_cb(bp);
}
if (wait) {
diff --git a/fs/xfs/linux-2.6/xfs_buf.h b/fs/xfs/linux-2.6/xfs_buf.h
index 5fbecefa5df..d072e5ff923 100644
--- a/fs/xfs/linux-2.6/xfs_buf.h
+++ b/fs/xfs/linux-2.6/xfs_buf.h
@@ -44,57 +44,57 @@ typedef enum {
XBRW_ZERO = 3, /* Zero target memory */
} xfs_buf_rw_t;
-typedef enum {
- XBF_READ = (1 << 0), /* buffer intended for reading from device */
- XBF_WRITE = (1 << 1), /* buffer intended for writing to device */
- XBF_MAPPED = (1 << 2), /* buffer mapped (b_addr valid) */
- XBF_ASYNC = (1 << 4), /* initiator will not wait for completion */
- XBF_DONE = (1 << 5), /* all pages in the buffer uptodate */
- XBF_DELWRI = (1 << 6), /* buffer has dirty pages */
- XBF_STALE = (1 << 7), /* buffer has been staled, do not find it */
- XBF_FS_MANAGED = (1 << 8), /* filesystem controls freeing memory */
- XBF_ORDERED = (1 << 11), /* use ordered writes */
- XBF_READ_AHEAD = (1 << 12), /* asynchronous read-ahead */
- XBF_LOG_BUFFER = (1 << 13), /* this is a buffer used for the log */
-
- /* flags used only as arguments to access routines */
- XBF_LOCK = (1 << 14), /* lock requested */
- XBF_TRYLOCK = (1 << 15), /* lock requested, but do not wait */
- XBF_DONT_BLOCK = (1 << 16), /* do not block in current thread */
-
- /* flags used only internally */
- _XBF_PAGE_CACHE = (1 << 17),/* backed by pagecache */
- _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 */
-
- /*
- * Special flag for supporting metadata blocks smaller than a FSB.
- *
- * In this case we can have multiple xfs_buf_t on a single page and
- * need to lock out concurrent xfs_buf_t readers as they only
- * serialise access to the buffer.
- *
- * If the FSB size >= PAGE_CACHE_SIZE case, we have no serialisation
- * between reads of the page. Hence we can have one thread read the
- * page and modify it, but then race with another thread that thinks
- * the page is not up-to-date and hence reads it again.
- *
- * The result is that the first modifcation to the page is lost.
- * This sort of AGF/AGI reading race can happen when unlinking inodes
- * that require truncation and results in the AGI unlinked list
- * modifications being lost.
- */
- _XBF_PAGE_LOCKED = (1 << 22),
-
- /*
- * If we try a barrier write, but it fails we have to communicate
- * this to the upper layers. Unfortunately b_error gets overwritten
- * when the buffer is re-issued so we have to add another flag to
- * keep this information.
- */
- _XFS_BARRIER_FAILED = (1 << 23),
-} xfs_buf_flags_t;
+#define XBF_READ (1 << 0) /* buffer intended for reading from device */
+#define XBF_WRITE (1 << 1) /* buffer intended for writing to device */
+#define XBF_MAPPED (1 << 2) /* buffer mapped (b_addr valid) */
+#define XBF_ASYNC (1 << 4) /* initiator will not wait for completion */
+#define XBF_DONE (1 << 5) /* all pages in the buffer uptodate */
+#define XBF_DELWRI (1 << 6) /* buffer has dirty pages */
+#define XBF_STALE (1 << 7) /* buffer has been staled, do not find it */
+#define XBF_FS_MANAGED (1 << 8) /* filesystem controls freeing memory */
+#define XBF_ORDERED (1 << 11)/* use ordered writes */
+#define XBF_READ_AHEAD (1 << 12)/* asynchronous read-ahead */
+#define XBF_LOG_BUFFER (1 << 13)/* this is a buffer used for the log */
+
+/* flags used only as arguments to access routines */
+#define XBF_LOCK (1 << 14)/* lock requested */
+#define XBF_TRYLOCK (1 << 15)/* lock requested, but do not wait */
+#define XBF_DONT_BLOCK (1 << 16)/* do not block in current thread */
+
+/* flags used only internally */
+#define _XBF_PAGE_CACHE (1 << 17)/* backed by pagecache */
+#define _XBF_PAGES (1 << 18)/* backed by refcounted pages */
+#define _XBF_RUN_QUEUES (1 << 19)/* run block device task queue */
+#define _XBF_DELWRI_Q (1 << 21)/* buffer on delwri queue */
+
+/*
+ * Special flag for supporting metadata blocks smaller than a FSB.
+ *
+ * In this case we can have multiple xfs_buf_t on a single page and
+ * need to lock out concurrent xfs_buf_t readers as they only
+ * serialise access to the buffer.
+ *
+ * If the FSB size >= PAGE_CACHE_SIZE case, we have no serialisation
+ * between reads of the page. Hence we can have one thread read the
+ * page and modify it, but then race with another thread that thinks
+ * the page is not up-to-date and hence reads it again.
+ *
+ * The result is that the first modifcation to the page is lost.
+ * This sort of AGF/AGI reading race can happen when unlinking inodes
+ * that require truncation and results in the AGI unlinked list
+ * modifications being lost.
+ */
+#define _XBF_PAGE_LOCKED (1 << 22)
+
+/*
+ * If we try a barrier write, but it fails we have to communicate
+ * this to the upper layers. Unfortunately b_error gets overwritten
+ * when the buffer is re-issued so we have to add another flag to
+ * keep this information.
+ */
+#define _XFS_BARRIER_FAILED (1 << 23)
+
+typedef unsigned int xfs_buf_flags_t;
#define XFS_BUF_FLAGS \
{ XBF_READ, "READ" }, \
@@ -187,7 +187,6 @@ typedef struct xfs_buf {
atomic_t b_io_remaining; /* #outstanding I/O requests */
xfs_buf_iodone_t b_iodone; /* I/O completion function */
xfs_buf_relse_t b_relse; /* releasing function */
- xfs_buf_bdstrat_t b_strat; /* pre-write function */
struct completion b_iowait; /* queue for I/O waiters */
void *b_fspriv;
void *b_fspriv2;
@@ -245,11 +244,6 @@ extern int xfs_buf_iowait(xfs_buf_t *);
extern void xfs_buf_iomove(xfs_buf_t *, size_t, size_t, void *,
xfs_buf_rw_t);
-static inline int xfs_buf_iostrategy(xfs_buf_t *bp)
-{
- return bp->b_strat ? bp->b_strat(bp) : xfs_buf_iorequest(bp);
-}
-
static inline int xfs_buf_geterror(xfs_buf_t *bp)
{
return bp ? bp->b_error : ENOMEM;
@@ -258,11 +252,6 @@ static inline int xfs_buf_geterror(xfs_buf_t *bp)
/* Buffer Utility Routines */
extern xfs_caddr_t xfs_buf_offset(xfs_buf_t *, size_t);
-/* Pinning Buffer Storage in Memory */
-extern void xfs_buf_pin(xfs_buf_t *);
-extern void xfs_buf_unpin(xfs_buf_t *);
-extern int xfs_buf_ispin(xfs_buf_t *);
-
/* Delayed Write Buffer Routines */
extern void xfs_buf_delwri_dequeue(xfs_buf_t *);
extern void xfs_buf_delwri_promote(xfs_buf_t *);
@@ -326,8 +315,6 @@ extern void xfs_buf_terminate(void);
#define XFS_BUF_IODONE_FUNC(bp) ((bp)->b_iodone)
#define XFS_BUF_SET_IODONE_FUNC(bp, func) ((bp)->b_iodone = (func))
#define XFS_BUF_CLR_IODONE_FUNC(bp) ((bp)->b_iodone = NULL)
-#define XFS_BUF_SET_BDSTRAT_FUNC(bp, func) ((bp)->b_strat = (func))
-#define XFS_BUF_CLR_BDSTRAT_FUNC(bp) ((bp)->b_strat = NULL)
#define XFS_BUF_FSPRIVATE(bp, type) ((type)(bp)->b_fspriv)
#define XFS_BUF_SET_FSPRIVATE(bp, val) ((bp)->b_fspriv = (void*)(val))
@@ -351,7 +338,7 @@ extern void xfs_buf_terminate(void);
#define XFS_BUF_SET_VTYPE(bp, type) do { } while (0)
#define XFS_BUF_SET_REF(bp, ref) do { } while (0)
-#define XFS_BUF_ISPINNED(bp) xfs_buf_ispin(bp)
+#define XFS_BUF_ISPINNED(bp) atomic_read(&((bp)->b_pin_count))
#define XFS_BUF_VALUSEMA(bp) xfs_buf_lock_value(bp)
#define XFS_BUF_CPSEMA(bp) (xfs_buf_cond_lock(bp) == 0)
@@ -370,8 +357,6 @@ static inline void xfs_buf_relse(xfs_buf_t *bp)
xfs_buf_rele(bp);
}
-#define xfs_bpin(bp) xfs_buf_pin(bp)
-#define xfs_bunpin(bp) xfs_buf_unpin(bp)
#define xfs_biodone(bp) xfs_buf_ioend(bp, 0)
#define xfs_biomove(bp, off, len, data, rw) \
diff --git a/fs/xfs/linux-2.6/xfs_dmapi_priv.h b/fs/xfs/linux-2.6/xfs_dmapi_priv.h
deleted file mode 100644
index a8b0b1685ee..00000000000
--- a/fs/xfs/linux-2.6/xfs_dmapi_priv.h
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Copyright (c) 2000-2006 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_DMAPI_PRIV_H__
-#define __XFS_DMAPI_PRIV_H__
-
-/*
- * Based on IO_ISDIRECT, decide which i_ flag is set.
- */
-#define DM_SEM_FLAG_RD(ioflags) (((ioflags) & IO_ISDIRECT) ? \
- DM_FLAGS_IMUX : 0)
-#define DM_SEM_FLAG_WR (DM_FLAGS_IALLOCSEM_WR | DM_FLAGS_IMUX)
-
-#endif /*__XFS_DMAPI_PRIV_H__*/
diff --git a/fs/xfs/linux-2.6/xfs_export.c b/fs/xfs/linux-2.6/xfs_export.c
index e7839ee49e4..3764d74790e 100644
--- a/fs/xfs/linux-2.6/xfs_export.c
+++ b/fs/xfs/linux-2.6/xfs_export.c
@@ -23,13 +23,13 @@
#include "xfs_sb.h"
#include "xfs_ag.h"
#include "xfs_dir2.h"
-#include "xfs_dmapi.h"
#include "xfs_mount.h"
#include "xfs_export.h"
#include "xfs_vnodeops.h"
#include "xfs_bmap_btree.h"
#include "xfs_inode.h"
#include "xfs_inode_item.h"
+#include "xfs_trace.h"
/*
* Note that we only accept fileids which are long enough rather than allow
@@ -132,8 +132,7 @@ xfs_nfs_get_inode(
* fine and not an indication of a corrupted filesystem as clients can
* send invalid file handles and we have to handle it gracefully..
*/
- error = xfs_iget(mp, NULL, ino, XFS_IGET_UNTRUSTED,
- XFS_ILOCK_SHARED, &ip);
+ error = xfs_iget(mp, NULL, ino, XFS_IGET_UNTRUSTED, 0, &ip);
if (error) {
/*
* EINVAL means the inode cluster doesn't exist anymore.
@@ -148,11 +147,10 @@ xfs_nfs_get_inode(
}
if (ip->i_d.di_gen != generation) {
- xfs_iput_new(ip, XFS_ILOCK_SHARED);
+ IRELE(ip);
return ERR_PTR(-ENOENT);
}
- xfs_iunlock(ip, XFS_ILOCK_SHARED);
return VFS_I(ip);
}
diff --git a/fs/xfs/linux-2.6/xfs_file.c b/fs/xfs/linux-2.6/xfs_file.c
index 257a56b127c..ba8ad422a16 100644
--- a/fs/xfs/linux-2.6/xfs_file.c
+++ b/fs/xfs/linux-2.6/xfs_file.c
@@ -22,23 +22,15 @@
#include "xfs_inum.h"
#include "xfs_sb.h"
#include "xfs_ag.h"
-#include "xfs_dir2.h"
#include "xfs_trans.h"
-#include "xfs_dmapi.h"
#include "xfs_mount.h"
#include "xfs_bmap_btree.h"
-#include "xfs_alloc_btree.h"
-#include "xfs_ialloc_btree.h"
#include "xfs_alloc.h"
-#include "xfs_btree.h"
-#include "xfs_attr_sf.h"
-#include "xfs_dir2_sf.h"
#include "xfs_dinode.h"
#include "xfs_inode.h"
#include "xfs_inode_item.h"
#include "xfs_bmap.h"
#include "xfs_error.h"
-#include "xfs_rw.h"
#include "xfs_vnodeops.h"
#include "xfs_da_btree.h"
#include "xfs_ioctl.h"
@@ -108,7 +100,7 @@ xfs_file_fsync(
int error = 0;
int log_flushed = 0;
- xfs_itrace_entry(ip);
+ trace_xfs_file_fsync(ip);
if (XFS_FORCED_SHUTDOWN(ip->i_mount))
return -XFS_ERROR(EIO);
@@ -166,8 +158,7 @@ xfs_file_fsync(
* transaction. So we play it safe and fire off the
* transaction anyway.
*/
- xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL);
- xfs_trans_ihold(tp, ip);
+ xfs_trans_ijoin(tp, ip);
xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
xfs_trans_set_sync(tp);
error = _xfs_trans_commit(tp, 0, &log_flushed);
@@ -275,20 +266,6 @@ xfs_file_aio_read(
mutex_lock(&inode->i_mutex);
xfs_ilock(ip, XFS_IOLOCK_SHARED);
- if (DM_EVENT_ENABLED(ip, DM_EVENT_READ) && !(ioflags & IO_INVIS)) {
- int dmflags = FILP_DELAY_FLAG(file) | DM_SEM_FLAG_RD(ioflags);
- int iolock = XFS_IOLOCK_SHARED;
-
- ret = -XFS_SEND_DATA(mp, DM_EVENT_READ, ip, iocb->ki_pos, size,
- dmflags, &iolock);
- if (ret) {
- xfs_iunlock(ip, XFS_IOLOCK_SHARED);
- if (unlikely(ioflags & IO_ISDIRECT))
- mutex_unlock(&inode->i_mutex);
- return ret;
- }
- }
-
if (unlikely(ioflags & IO_ISDIRECT)) {
if (inode->i_mapping->nrpages) {
ret = -xfs_flushinval_pages(ip,
@@ -321,7 +298,6 @@ xfs_file_splice_read(
unsigned int flags)
{
struct xfs_inode *ip = XFS_I(infilp->f_mapping->host);
- struct xfs_mount *mp = ip->i_mount;
int ioflags = 0;
ssize_t ret;
@@ -335,18 +311,6 @@ xfs_file_splice_read(
xfs_ilock(ip, XFS_IOLOCK_SHARED);
- if (DM_EVENT_ENABLED(ip, DM_EVENT_READ) && !(ioflags & IO_INVIS)) {
- int iolock = XFS_IOLOCK_SHARED;
- int error;
-
- error = XFS_SEND_DATA(mp, DM_EVENT_READ, ip, *ppos, count,
- FILP_DELAY_FLAG(infilp), &iolock);
- if (error) {
- xfs_iunlock(ip, XFS_IOLOCK_SHARED);
- return -error;
- }
- }
-
trace_xfs_file_splice_read(ip, count, *ppos, ioflags);
ret = generic_file_splice_read(infilp, ppos, pipe, count, flags);
@@ -367,7 +331,6 @@ xfs_file_splice_write(
{
struct inode *inode = outfilp->f_mapping->host;
struct xfs_inode *ip = XFS_I(inode);
- struct xfs_mount *mp = ip->i_mount;
xfs_fsize_t isize, new_size;
int ioflags = 0;
ssize_t ret;
@@ -382,18 +345,6 @@ xfs_file_splice_write(
xfs_ilock(ip, XFS_IOLOCK_EXCL);
- if (DM_EVENT_ENABLED(ip, DM_EVENT_WRITE) && !(ioflags & IO_INVIS)) {
- int iolock = XFS_IOLOCK_EXCL;
- int error;
-
- error = XFS_SEND_DATA(mp, DM_EVENT_WRITE, ip, *ppos, count,
- FILP_DELAY_FLAG(outfilp), &iolock);
- if (error) {
- xfs_iunlock(ip, XFS_IOLOCK_EXCL);
- return -error;
- }
- }
-
new_size = *ppos + count;
xfs_ilock(ip, XFS_ILOCK_EXCL);
@@ -463,7 +414,7 @@ xfs_zero_last_block(
last_fsb = XFS_B_TO_FSBT(mp, isize);
nimaps = 1;
error = xfs_bmapi(NULL, ip, last_fsb, 1, 0, NULL, 0, &imap,
- &nimaps, NULL, NULL);
+ &nimaps, NULL);
if (error) {
return error;
}
@@ -558,7 +509,7 @@ xfs_zero_eof(
nimaps = 1;
zero_count_fsb = end_zero_fsb - start_zero_fsb + 1;
error = xfs_bmapi(NULL, ip, start_zero_fsb, zero_count_fsb,
- 0, NULL, 0, &imap, &nimaps, NULL, NULL);
+ 0, NULL, 0, &imap, &nimaps, NULL);
if (error) {
ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL|XFS_IOLOCK_EXCL));
return error;
@@ -627,7 +578,6 @@ xfs_file_aio_write(
int ioflags = 0;
xfs_fsize_t isize, new_size;
int iolock;
- int eventsent = 0;
size_t ocount = 0, count;
int need_i_mutex;
@@ -673,33 +623,6 @@ start:
goto out_unlock_mutex;
}
- if ((DM_EVENT_ENABLED(ip, DM_EVENT_WRITE) &&
- !(ioflags & IO_INVIS) && !eventsent)) {
- int dmflags = FILP_DELAY_FLAG(file);
-
- if (need_i_mutex)
- dmflags |= DM_FLAGS_IMUX;
-
- xfs_iunlock(ip, XFS_ILOCK_EXCL);
- error = XFS_SEND_DATA(ip->i_mount, DM_EVENT_WRITE, ip,
- pos, count, dmflags, &iolock);
- if (error) {
- goto out_unlock_internal;
- }
- xfs_ilock(ip, XFS_ILOCK_EXCL);
- eventsent = 1;
-
- /*
- * The iolock was dropped and reacquired in XFS_SEND_DATA
- * so we have to recheck the size when appending.
- * We will only "goto start;" once, since having sent the
- * event prevents another call to XFS_SEND_DATA, which is
- * what allows the size to change in the first place.
- */
- if ((file->f_flags & O_APPEND) && pos != ip->i_size)
- goto start;
- }
-
if (ioflags & IO_ISDIRECT) {
xfs_buftarg_t *target =
XFS_IS_REALTIME_INODE(ip) ?
@@ -830,22 +753,6 @@ write_retry:
xfs_iunlock(ip, XFS_ILOCK_EXCL);
}
- if (ret == -ENOSPC &&
- DM_EVENT_ENABLED(ip, DM_EVENT_NOSPACE) && !(ioflags & IO_INVIS)) {
- xfs_iunlock(ip, iolock);
- if (need_i_mutex)
- mutex_unlock(&inode->i_mutex);
- error = XFS_SEND_NAMESP(ip->i_mount, DM_EVENT_NOSPACE, ip,
- DM_RIGHT_NULL, ip, DM_RIGHT_NULL, NULL, NULL,
- 0, 0, 0); /* Delay flag intentionally unused */
- if (need_i_mutex)
- mutex_lock(&inode->i_mutex);
- xfs_ilock(ip, iolock);
- if (error)
- goto out_unlock_internal;
- goto start;
- }
-
error = -ret;
if (ret <= 0)
goto out_unlock_internal;
@@ -1014,9 +921,6 @@ const struct file_operations xfs_file_operations = {
.open = xfs_file_open,
.release = xfs_file_release,
.fsync = xfs_file_fsync,
-#ifdef HAVE_FOP_OPEN_EXEC
- .open_exec = xfs_file_open_exec,
-#endif
};
const struct file_operations xfs_dir_file_operations = {
diff --git a/fs/xfs/linux-2.6/xfs_fs_subr.c b/fs/xfs/linux-2.6/xfs_fs_subr.c
index b6918d76bc7..1f279b012f9 100644
--- a/fs/xfs/linux-2.6/xfs_fs_subr.c
+++ b/fs/xfs/linux-2.6/xfs_fs_subr.c
@@ -21,10 +21,6 @@
#include "xfs_inode.h"
#include "xfs_trace.h"
-int fs_noerr(void) { return 0; }
-int fs_nosys(void) { return ENOSYS; }
-void fs_noval(void) { return; }
-
/*
* note: all filemap functions return negative error codes. These
* need to be inverted before returning to the xfs core functions.
diff --git a/fs/xfs/linux-2.6/xfs_fs_subr.h b/fs/xfs/linux-2.6/xfs_fs_subr.h
deleted file mode 100644
index 82bb19b2599..00000000000
--- a/fs/xfs/linux-2.6/xfs_fs_subr.h
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * Copyright (c) 2000,2002,2005 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_FS_SUBR_H__
-#define __XFS_FS_SUBR_H__
-
-extern int fs_noerr(void);
-extern int fs_nosys(void);
-extern void fs_noval(void);
-
-#endif /* __XFS_FS_SUBR_H__ */
diff --git a/fs/xfs/linux-2.6/xfs_ioctl.c b/fs/xfs/linux-2.6/xfs_ioctl.c
index e59a8106283..237f5ffb2ee 100644
--- a/fs/xfs/linux-2.6/xfs_ioctl.c
+++ b/fs/xfs/linux-2.6/xfs_ioctl.c
@@ -23,24 +23,15 @@
#include "xfs_trans.h"
#include "xfs_sb.h"
#include "xfs_ag.h"
-#include "xfs_dir2.h"
#include "xfs_alloc.h"
-#include "xfs_dmapi.h"
#include "xfs_mount.h"
#include "xfs_bmap_btree.h"
-#include "xfs_alloc_btree.h"
-#include "xfs_ialloc_btree.h"
-#include "xfs_attr_sf.h"
-#include "xfs_dir2_sf.h"
#include "xfs_dinode.h"
#include "xfs_inode.h"
#include "xfs_ioctl.h"
-#include "xfs_btree.h"
-#include "xfs_ialloc.h"
#include "xfs_rtalloc.h"
#include "xfs_itable.h"
#include "xfs_error.h"
-#include "xfs_rw.h"
#include "xfs_attr.h"
#include "xfs_bmap.h"
#include "xfs_buf_item.h"
@@ -908,7 +899,7 @@ xfs_ioctl_setattr(
struct xfs_dquot *olddquot = NULL;
int code;
- xfs_itrace_entry(ip);
+ trace_xfs_ioctl_setattr(ip);
if (mp->m_flags & XFS_MOUNT_RDONLY)
return XFS_ERROR(EROFS);
@@ -1043,8 +1034,7 @@ xfs_ioctl_setattr(
}
}
- xfs_trans_ijoin(tp, ip, lock_flags);
- xfs_trans_ihold(tp, ip);
+ xfs_trans_ijoin(tp, ip);
/*
* Change file ownership. Must be the owner or privileged.
@@ -1116,16 +1106,7 @@ xfs_ioctl_setattr(
xfs_qm_dqrele(udqp);
xfs_qm_dqrele(gdqp);
- if (code)
- return code;
-
- if (DM_EVENT_ENABLED(ip, DM_EVENT_ATTRIBUTE)) {
- XFS_SEND_NAMESP(mp, DM_EVENT_ATTRIBUTE, ip, DM_RIGHT_NULL,
- NULL, DM_RIGHT_NULL, NULL, NULL, 0, 0,
- (mask & FSX_NONBLOCK) ? DM_FLAGS_NDELAY : 0);
- }
-
- return 0;
+ return code;
error_return:
xfs_qm_dqrele(udqp);
@@ -1301,7 +1282,7 @@ xfs_file_ioctl(
if (filp->f_mode & FMODE_NOCMTIME)
ioflags |= IO_INVIS;
- xfs_itrace_entry(ip);
+ trace_xfs_file_ioctl(ip);
switch (cmd) {
case XFS_IOC_ALLOCSP:
diff --git a/fs/xfs/linux-2.6/xfs_ioctl32.c b/fs/xfs/linux-2.6/xfs_ioctl32.c
index 52ed49e6465..6c83f7f62dc 100644
--- a/fs/xfs/linux-2.6/xfs_ioctl32.c
+++ b/fs/xfs/linux-2.6/xfs_ioctl32.c
@@ -28,12 +28,8 @@
#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_vnode.h"
#include "xfs_dinode.h"
#include "xfs_inode.h"
@@ -544,7 +540,7 @@ xfs_file_compat_ioctl(
if (filp->f_mode & FMODE_NOCMTIME)
ioflags |= IO_INVIS;
- xfs_itrace_entry(ip);
+ trace_xfs_file_compat_ioctl(ip);
switch (cmd) {
/* No size or alignment issues on any arch */
diff --git a/fs/xfs/linux-2.6/xfs_iops.c b/fs/xfs/linux-2.6/xfs_iops.c
index 44f0b2de153..536b81e63a3 100644
--- a/fs/xfs/linux-2.6/xfs_iops.c
+++ b/fs/xfs/linux-2.6/xfs_iops.c
@@ -24,21 +24,13 @@
#include "xfs_trans.h"
#include "xfs_sb.h"
#include "xfs_ag.h"
-#include "xfs_dir2.h"
#include "xfs_alloc.h"
-#include "xfs_dmapi.h"
#include "xfs_quota.h"
#include "xfs_mount.h"
#include "xfs_bmap_btree.h"
-#include "xfs_alloc_btree.h"
-#include "xfs_ialloc_btree.h"
-#include "xfs_dir2_sf.h"
-#include "xfs_attr_sf.h"
#include "xfs_dinode.h"
#include "xfs_inode.h"
#include "xfs_bmap.h"
-#include "xfs_btree.h"
-#include "xfs_ialloc.h"
#include "xfs_rtalloc.h"
#include "xfs_error.h"
#include "xfs_itable.h"
@@ -496,7 +488,7 @@ xfs_vn_getattr(
struct xfs_inode *ip = XFS_I(inode);
struct xfs_mount *mp = ip->i_mount;
- xfs_itrace_entry(ip);
+ trace_xfs_getattr(ip);
if (XFS_FORCED_SHUTDOWN(mp))
return XFS_ERROR(EIO);
diff --git a/fs/xfs/linux-2.6/xfs_linux.h b/fs/xfs/linux-2.6/xfs_linux.h
index facfb323a70..998a9d7fb9c 100644
--- a/fs/xfs/linux-2.6/xfs_linux.h
+++ b/fs/xfs/linux-2.6/xfs_linux.h
@@ -87,7 +87,6 @@
#include <xfs_aops.h>
#include <xfs_super.h>
#include <xfs_globals.h>
-#include <xfs_fs_subr.h>
#include <xfs_buf.h>
/*
diff --git a/fs/xfs/linux-2.6/xfs_quotaops.c b/fs/xfs/linux-2.6/xfs_quotaops.c
index 067cafbfc63..29b9d642e93 100644
--- a/fs/xfs/linux-2.6/xfs_quotaops.c
+++ b/fs/xfs/linux-2.6/xfs_quotaops.c
@@ -16,7 +16,6 @@
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "xfs.h"
-#include "xfs_dmapi.h"
#include "xfs_sb.h"
#include "xfs_inum.h"
#include "xfs_log.h"
@@ -69,15 +68,15 @@ xfs_fs_set_xstate(
if (op != Q_XQUOTARM && !XFS_IS_QUOTA_RUNNING(mp))
return -ENOSYS;
- if (uflags & XFS_QUOTA_UDQ_ACCT)
+ if (uflags & FS_QUOTA_UDQ_ACCT)
flags |= XFS_UQUOTA_ACCT;
- if (uflags & XFS_QUOTA_PDQ_ACCT)
+ if (uflags & FS_QUOTA_PDQ_ACCT)
flags |= XFS_PQUOTA_ACCT;
- if (uflags & XFS_QUOTA_GDQ_ACCT)
+ if (uflags & FS_QUOTA_GDQ_ACCT)
flags |= XFS_GQUOTA_ACCT;
- if (uflags & XFS_QUOTA_UDQ_ENFD)
+ if (uflags & FS_QUOTA_UDQ_ENFD)
flags |= XFS_UQUOTA_ENFD;
- if (uflags & (XFS_QUOTA_PDQ_ENFD|XFS_QUOTA_GDQ_ENFD))
+ if (uflags & (FS_QUOTA_PDQ_ENFD|FS_QUOTA_GDQ_ENFD))
flags |= XFS_OQUOTA_ENFD;
switch (op) {
diff --git a/fs/xfs/linux-2.6/xfs_super.c b/fs/xfs/linux-2.6/xfs_super.c
index 80938c736c2..758df94690e 100644
--- a/fs/xfs/linux-2.6/xfs_super.c
+++ b/fs/xfs/linux-2.6/xfs_super.c
@@ -25,14 +25,11 @@
#include "xfs_ag.h"
#include "xfs_dir2.h"
#include "xfs_alloc.h"
-#include "xfs_dmapi.h"
#include "xfs_quota.h"
#include "xfs_mount.h"
#include "xfs_bmap_btree.h"
#include "xfs_alloc_btree.h"
#include "xfs_ialloc_btree.h"
-#include "xfs_dir2_sf.h"
-#include "xfs_attr_sf.h"
#include "xfs_dinode.h"
#include "xfs_inode.h"
#include "xfs_btree.h"
@@ -43,7 +40,6 @@
#include "xfs_error.h"
#include "xfs_itable.h"
#include "xfs_fsops.h"
-#include "xfs_rw.h"
#include "xfs_attr.h"
#include "xfs_buf_item.h"
#include "xfs_utils.h"
@@ -94,7 +90,6 @@ mempool_t *xfs_ioend_pool;
#define MNTOPT_BARRIER "barrier" /* use writer barriers for log write and
* unwritten extent conversion */
#define MNTOPT_NOBARRIER "nobarrier" /* .. disable */
-#define MNTOPT_OSYNCISOSYNC "osyncisosync" /* o_sync is REALLY o_sync */
#define MNTOPT_64BITINODE "inode64" /* inodes can be allocated anywhere */
#define MNTOPT_IKEEP "ikeep" /* do not free empty inode clusters */
#define MNTOPT_NOIKEEP "noikeep" /* free empty inode clusters */
@@ -116,9 +111,6 @@ mempool_t *xfs_ioend_pool;
#define MNTOPT_GQUOTANOENF "gqnoenforce"/* group quota limit enforcement */
#define MNTOPT_PQUOTANOENF "pqnoenforce"/* project quota limit enforcement */
#define MNTOPT_QUOTANOENF "qnoenforce" /* same as uqnoenforce */
-#define MNTOPT_DMAPI "dmapi" /* DMI enabled (DMAPI / XDSM) */
-#define MNTOPT_XDSM "xdsm" /* DMI enabled (DMAPI / XDSM) */
-#define MNTOPT_DMI "dmi" /* DMI enabled (DMAPI / XDSM) */
#define MNTOPT_DELAYLOG "delaylog" /* Delayed loging enabled */
#define MNTOPT_NODELAYLOG "nodelaylog" /* Delayed loging disabled */
@@ -172,15 +164,13 @@ suffix_strtoul(char *s, char **endp, unsigned int base)
STATIC int
xfs_parseargs(
struct xfs_mount *mp,
- char *options,
- char **mtpt)
+ char *options)
{
struct super_block *sb = mp->m_super;
char *this_char, *value, *eov;
int dsunit = 0;
int dswidth = 0;
int iosize = 0;
- int dmapi_implies_ikeep = 1;
__uint8_t iosizelog = 0;
/*
@@ -243,15 +233,10 @@ xfs_parseargs(
if (!mp->m_logname)
return ENOMEM;
} else if (!strcmp(this_char, MNTOPT_MTPT)) {
- if (!value || !*value) {
- cmn_err(CE_WARN,
- "XFS: %s option requires an argument",
- this_char);
- return EINVAL;
- }
- *mtpt = kstrndup(value, MAXNAMELEN, GFP_KERNEL);
- if (!*mtpt)
- return ENOMEM;
+ cmn_err(CE_WARN,
+ "XFS: %s option not allowed on this system",
+ this_char);
+ return EINVAL;
} else if (!strcmp(this_char, MNTOPT_RTDEV)) {
if (!value || !*value) {
cmn_err(CE_WARN,
@@ -288,8 +273,6 @@ xfs_parseargs(
mp->m_flags &= ~XFS_MOUNT_GRPID;
} else if (!strcmp(this_char, MNTOPT_WSYNC)) {
mp->m_flags |= XFS_MOUNT_WSYNC;
- } else if (!strcmp(this_char, MNTOPT_OSYNCISOSYNC)) {
- mp->m_flags |= XFS_MOUNT_OSYNCISOSYNC;
} else if (!strcmp(this_char, MNTOPT_NORECOVERY)) {
mp->m_flags |= XFS_MOUNT_NORECOVERY;
} else if (!strcmp(this_char, MNTOPT_NOALIGN)) {
@@ -329,7 +312,6 @@ xfs_parseargs(
} else if (!strcmp(this_char, MNTOPT_IKEEP)) {
mp->m_flags |= XFS_MOUNT_IKEEP;
} else if (!strcmp(this_char, MNTOPT_NOIKEEP)) {
- dmapi_implies_ikeep = 0;
mp->m_flags &= ~XFS_MOUNT_IKEEP;
} else if (!strcmp(this_char, MNTOPT_LARGEIO)) {
mp->m_flags &= ~XFS_MOUNT_COMPAT_IOSIZE;
@@ -370,12 +352,6 @@ xfs_parseargs(
} else if (!strcmp(this_char, MNTOPT_GQUOTANOENF)) {
mp->m_qflags |= (XFS_GQUOTA_ACCT | XFS_GQUOTA_ACTIVE);
mp->m_qflags &= ~XFS_OQUOTA_ENFD;
- } else if (!strcmp(this_char, MNTOPT_DMAPI)) {
- mp->m_flags |= XFS_MOUNT_DMAPI;
- } else if (!strcmp(this_char, MNTOPT_XDSM)) {
- mp->m_flags |= XFS_MOUNT_DMAPI;
- } else if (!strcmp(this_char, MNTOPT_DMI)) {
- mp->m_flags |= XFS_MOUNT_DMAPI;
} else if (!strcmp(this_char, MNTOPT_DELAYLOG)) {
mp->m_flags |= XFS_MOUNT_DELAYLOG;
cmn_err(CE_WARN,
@@ -387,9 +363,11 @@ xfs_parseargs(
cmn_err(CE_WARN,
"XFS: ihashsize no longer used, option is deprecated.");
} else if (!strcmp(this_char, "osyncisdsync")) {
- /* no-op, this is now the default */
cmn_err(CE_WARN,
- "XFS: osyncisdsync is now the default, option is deprecated.");
+ "XFS: osyncisdsync has no effect, option is deprecated.");
+ } else if (!strcmp(this_char, "osyncisosync")) {
+ cmn_err(CE_WARN,
+ "XFS: osyncisosync has no effect, option is deprecated.");
} else if (!strcmp(this_char, "irixsgid")) {
cmn_err(CE_WARN,
"XFS: irixsgid is now a sysctl(2) variable, option is deprecated.");
@@ -430,12 +408,6 @@ xfs_parseargs(
return EINVAL;
}
- if ((mp->m_flags & XFS_MOUNT_DMAPI) && (!*mtpt || *mtpt[0] == '\0')) {
- printk("XFS: %s option needs the mount point option as well\n",
- MNTOPT_DMAPI);
- return EINVAL;
- }
-
if ((dsunit && !dswidth) || (!dsunit && dswidth)) {
cmn_err(CE_WARN,
"XFS: sunit and swidth must be specified together");
@@ -449,18 +421,6 @@ xfs_parseargs(
return EINVAL;
}
- /*
- * Applications using DMI filesystems often expect the
- * inode generation number to be monotonically increasing.
- * If we delete inode chunks we break this assumption, so
- * keep unused inode chunks on disk for DMI filesystems
- * until we come up with a better solution.
- * Note that if "ikeep" or "noikeep" mount options are
- * supplied, then they are honored.
- */
- if ((mp->m_flags & XFS_MOUNT_DMAPI) && dmapi_implies_ikeep)
- mp->m_flags |= XFS_MOUNT_IKEEP;
-
done:
if (!(mp->m_flags & XFS_MOUNT_NOALIGN)) {
/*
@@ -539,10 +499,8 @@ xfs_showargs(
{ XFS_MOUNT_SWALLOC, "," MNTOPT_SWALLOC },
{ XFS_MOUNT_NOUUID, "," MNTOPT_NOUUID },
{ XFS_MOUNT_NORECOVERY, "," MNTOPT_NORECOVERY },
- { XFS_MOUNT_OSYNCISOSYNC, "," MNTOPT_OSYNCISOSYNC },
{ XFS_MOUNT_ATTR2, "," MNTOPT_ATTR2 },
{ XFS_MOUNT_FILESTREAMS, "," MNTOPT_FILESTREAM },
- { XFS_MOUNT_DMAPI, "," MNTOPT_DMAPI },
{ XFS_MOUNT_GRPID, "," MNTOPT_GRPID },
{ XFS_MOUNT_DELAYLOG, "," MNTOPT_DELAYLOG },
{ 0, NULL }
@@ -947,7 +905,7 @@ xfs_fs_destroy_inode(
{
struct xfs_inode *ip = XFS_I(inode);
- xfs_itrace_entry(ip);
+ trace_xfs_destroy_inode(ip);
XFS_STATS_INC(vn_reclaim);
@@ -1063,10 +1021,8 @@ xfs_log_inode(
* an inode in another recent transaction. So we play it safe and
* fire off the transaction anyway.
*/
- xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL);
- xfs_trans_ihold(tp, ip);
+ xfs_trans_ijoin(tp, ip);
xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
- xfs_trans_set_sync(tp);
error = xfs_trans_commit(tp, 0);
xfs_ilock_demote(ip, XFS_ILOCK_EXCL);
@@ -1082,27 +1038,18 @@ xfs_fs_write_inode(
struct xfs_mount *mp = ip->i_mount;
int error = EAGAIN;
- xfs_itrace_entry(ip);
+ trace_xfs_write_inode(ip);
if (XFS_FORCED_SHUTDOWN(mp))
return XFS_ERROR(EIO);
if (wbc->sync_mode == WB_SYNC_ALL) {
/*
- * Make sure the inode has hit stable storage. By using the
- * log and the fsync transactions we reduce the IOs we have
- * to do here from two (log and inode) to just the log.
- *
- * Note: We still need to do a delwri write of the inode after
- * this to flush it to the backing buffer so that bulkstat
- * works properly if this is the first time the inode has been
- * written. Because we hold the ilock atomically over the
- * transaction commit and the inode flush we are guaranteed
- * that the inode is not pinned when it returns. If the flush
- * lock is already held, then the inode has already been
- * flushed once and we don't need to flush it again. Hence
- * the code will only flush the inode if it isn't already
- * being flushed.
+ * Make sure the inode has made it it into the log. Instead
+ * of forcing it all the way to stable storage using a
+ * synchronous transaction we let the log force inside the
+ * ->sync_fs call do that for thus, which reduces the number
+ * of synchronous log foces dramatically.
*/
xfs_ioend_wait(ip);
xfs_ilock(ip, XFS_ILOCK_SHARED);
@@ -1116,27 +1063,29 @@ xfs_fs_write_inode(
* We make this non-blocking if the inode is contended, return
* EAGAIN to indicate to the caller that they did not succeed.
* This prevents the flush path from blocking on inodes inside
- * another operation right now, they get caught later by xfs_sync.
+ * another operation right now, they get caught later by
+ * xfs_sync.
*/
if (!xfs_ilock_nowait(ip, XFS_ILOCK_SHARED))
goto out;
- }
- if (xfs_ipincount(ip) || !xfs_iflock_nowait(ip))
- goto out_unlock;
+ if (xfs_ipincount(ip) || !xfs_iflock_nowait(ip))
+ goto out_unlock;
- /*
- * Now we have the flush lock and the inode is not pinned, we can check
- * if the inode is really clean as we know that there are no pending
- * transaction completions, it is not waiting on the delayed write
- * queue and there is no IO in progress.
- */
- if (xfs_inode_clean(ip)) {
- xfs_ifunlock(ip);
- error = 0;
- goto out_unlock;
+ /*
+ * Now we have the flush lock and the inode is not pinned, we
+ * can check if the inode is really clean as we know that
+ * there are no pending transaction completions, it is not
+ * waiting on the delayed write queue and there is no IO in
+ * progress.
+ */
+ if (xfs_inode_clean(ip)) {
+ xfs_ifunlock(ip);
+ error = 0;
+ goto out_unlock;
+ }
+ error = xfs_iflush(ip, 0);
}
- error = xfs_iflush(ip, 0);
out_unlock:
xfs_iunlock(ip, XFS_ILOCK_SHARED);
@@ -1156,7 +1105,8 @@ xfs_fs_clear_inode(
{
xfs_inode_t *ip = XFS_I(inode);
- xfs_itrace_entry(ip);
+ trace_xfs_clear_inode(ip);
+
XFS_STATS_INC(vn_rele);
XFS_STATS_INC(vn_remove);
XFS_STATS_DEC(vn_active);
@@ -1193,22 +1143,13 @@ xfs_fs_put_super(
{
struct xfs_mount *mp = XFS_M(sb);
+ /*
+ * Unregister the memory shrinker before we tear down the mount
+ * structure so we don't have memory reclaim racing with us here.
+ */
+ xfs_inode_shrinker_unregister(mp);
xfs_syncd_stop(mp);
- if (!(sb->s_flags & MS_RDONLY)) {
- /*
- * XXX(hch): this should be SYNC_WAIT.
- *
- * Or more likely not needed at all because the VFS is already
- * calling ->sync_fs after shutting down all filestem
- * operations and just before calling ->put_super.
- */
- xfs_sync_data(mp, 0);
- xfs_sync_attr(mp, 0);
- }
-
- XFS_SEND_PREUNMOUNT(mp);
-
/*
* Blow away any referenced inode in the filestreams cache.
* This can and will cause log traffic as inodes go inactive
@@ -1218,14 +1159,10 @@ xfs_fs_put_super(
XFS_bflush(mp->m_ddev_targp);
- XFS_SEND_UNMOUNT(mp);
-
xfs_unmountfs(mp);
xfs_freesb(mp);
- xfs_inode_shrinker_unregister(mp);
xfs_icsb_destroy_counters(mp);
xfs_close_devices(mp);
- xfs_dmops_put(mp);
xfs_free_fsname(mp);
kfree(mp);
}
@@ -1543,7 +1480,6 @@ xfs_fs_fill_super(
struct inode *root;
struct xfs_mount *mp = NULL;
int flags = 0, error = ENOMEM;
- char *mtpt = NULL;
mp = kzalloc(sizeof(struct xfs_mount), GFP_KERNEL);
if (!mp)
@@ -1559,7 +1495,7 @@ xfs_fs_fill_super(
mp->m_super = sb;
sb->s_fs_info = mp;
- error = xfs_parseargs(mp, (char *)data, &mtpt);
+ error = xfs_parseargs(mp, (char *)data);
if (error)
goto out_free_fsname;
@@ -1571,16 +1507,12 @@ xfs_fs_fill_super(
#endif
sb->s_op = &xfs_super_operations;
- error = xfs_dmops_get(mp);
- if (error)
- goto out_free_fsname;
-
if (silent)
flags |= XFS_MFSI_QUIET;
error = xfs_open_devices(mp);
if (error)
- goto out_put_dmops;
+ goto out_free_fsname;
if (xfs_icsb_init_counters(mp))
mp->m_flags |= XFS_MOUNT_NO_PERCPU_SB;
@@ -1608,8 +1540,6 @@ xfs_fs_fill_super(
if (error)
goto out_filestream_unmount;
- XFS_SEND_MOUNT(mp, DM_RIGHT_NULL, mtpt, mp->m_fsname);
-
sb->s_magic = XFS_SB_MAGIC;
sb->s_blocksize = mp->m_sb.sb_blocksize;
sb->s_blocksize_bits = ffs(sb->s_blocksize) - 1;
@@ -1638,7 +1568,6 @@ xfs_fs_fill_super(
xfs_inode_shrinker_register(mp);
- kfree(mtpt);
return 0;
out_filestream_unmount:
@@ -1648,11 +1577,8 @@ xfs_fs_fill_super(
out_destroy_counters:
xfs_icsb_destroy_counters(mp);
xfs_close_devices(mp);
- out_put_dmops:
- xfs_dmops_put(mp);
out_free_fsname:
xfs_free_fsname(mp);
- kfree(mtpt);
kfree(mp);
out:
return -error;
@@ -1759,6 +1685,12 @@ xfs_init_zones(void)
if (!xfs_trans_zone)
goto out_destroy_ifork_zone;
+ xfs_log_item_desc_zone =
+ kmem_zone_init(sizeof(struct xfs_log_item_desc),
+ "xfs_log_item_desc");
+ if (!xfs_log_item_desc_zone)
+ goto out_destroy_trans_zone;
+
/*
* The size of the zone allocated buf log item is the maximum
* size possible under XFS. This wastes a little bit of memory,
@@ -1768,7 +1700,7 @@ xfs_init_zones(void)
(((XFS_MAX_BLOCKSIZE / XFS_BLF_CHUNK) /
NBWORD) * sizeof(int))), "xfs_buf_item");
if (!xfs_buf_item_zone)
- goto out_destroy_trans_zone;
+ goto out_destroy_log_item_desc_zone;
xfs_efd_zone = kmem_zone_init((sizeof(xfs_efd_log_item_t) +
((XFS_EFD_MAX_FAST_EXTENTS - 1) *
@@ -1805,6 +1737,8 @@ xfs_init_zones(void)
kmem_zone_destroy(xfs_efd_zone);
out_destroy_buf_item_zone:
kmem_zone_destroy(xfs_buf_item_zone);
+ out_destroy_log_item_desc_zone:
+ kmem_zone_destroy(xfs_log_item_desc_zone);
out_destroy_trans_zone:
kmem_zone_destroy(xfs_trans_zone);
out_destroy_ifork_zone:
@@ -1835,6 +1769,7 @@ xfs_destroy_zones(void)
kmem_zone_destroy(xfs_efi_zone);
kmem_zone_destroy(xfs_efd_zone);
kmem_zone_destroy(xfs_buf_item_zone);
+ kmem_zone_destroy(xfs_log_item_desc_zone);
kmem_zone_destroy(xfs_trans_zone);
kmem_zone_destroy(xfs_ifork_zone);
kmem_zone_destroy(xfs_dabuf_zone);
diff --git a/fs/xfs/linux-2.6/xfs_super.h b/fs/xfs/linux-2.6/xfs_super.h
index 519618e9279..1ef4a4d2d99 100644
--- a/fs/xfs/linux-2.6/xfs_super.h
+++ b/fs/xfs/linux-2.6/xfs_super.h
@@ -56,12 +56,6 @@ extern void xfs_qm_exit(void);
# define XFS_BIGFS_STRING
#endif
-#ifdef CONFIG_XFS_DMAPI
-# define XFS_DMAPI_STRING "dmapi support, "
-#else
-# define XFS_DMAPI_STRING
-#endif
-
#ifdef DEBUG
# define XFS_DBG_STRING "debug"
#else
@@ -72,7 +66,6 @@ extern void xfs_qm_exit(void);
XFS_SECURITY_STRING \
XFS_REALTIME_STRING \
XFS_BIGFS_STRING \
- XFS_DMAPI_STRING \
XFS_DBG_STRING /* DBG must be last */
struct xfs_inode;
diff --git a/fs/xfs/linux-2.6/xfs_sync.c b/fs/xfs/linux-2.6/xfs_sync.c
index a51a07c3a70..dfcbd98d159 100644
--- a/fs/xfs/linux-2.6/xfs_sync.c
+++ b/fs/xfs/linux-2.6/xfs_sync.c
@@ -24,25 +24,14 @@
#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_alloc_btree.h"
-#include "xfs_ialloc_btree.h"
-#include "xfs_btree.h"
-#include "xfs_dir2_sf.h"
-#include "xfs_attr_sf.h"
#include "xfs_inode.h"
#include "xfs_dinode.h"
#include "xfs_error.h"
-#include "xfs_mru_cache.h"
#include "xfs_filestream.h"
#include "xfs_vnodeops.h"
-#include "xfs_utils.h"
-#include "xfs_buf_item.h"
#include "xfs_inode_item.h"
-#include "xfs_rw.h"
#include "xfs_quota.h"
#include "xfs_trace.h"
@@ -319,7 +308,7 @@ xfs_sync_inode_attr(
/*
* Write out pagecache data for the whole filesystem.
*/
-int
+STATIC int
xfs_sync_data(
struct xfs_mount *mp,
int flags)
@@ -340,7 +329,7 @@ xfs_sync_data(
/*
* Write out inode metadata (attributes) for the whole filesystem.
*/
-int
+STATIC int
xfs_sync_attr(
struct xfs_mount *mp,
int flags)
@@ -373,8 +362,7 @@ xfs_commit_dummy_trans(
xfs_ilock(ip, XFS_ILOCK_EXCL);
- xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL);
- xfs_trans_ihold(tp, ip);
+ xfs_trans_ijoin(tp, ip);
xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
error = xfs_trans_commit(tp, 0);
xfs_iunlock(ip, XFS_ILOCK_EXCL);
@@ -867,7 +855,36 @@ out:
reclaim:
xfs_ifunlock(ip);
xfs_iunlock(ip, XFS_ILOCK_EXCL);
- xfs_ireclaim(ip);
+
+ XFS_STATS_INC(xs_ig_reclaims);
+ /*
+ * Remove the inode from the per-AG radix tree.
+ *
+ * Because radix_tree_delete won't complain even if the item was never
+ * added to the tree assert that it's been there before to catch
+ * problems with the inode life time early on.
+ */
+ write_lock(&pag->pag_ici_lock);
+ if (!radix_tree_delete(&pag->pag_ici_root,
+ XFS_INO_TO_AGINO(ip->i_mount, ip->i_ino)))
+ ASSERT(0);
+ write_unlock(&pag->pag_ici_lock);
+
+ /*
+ * Here we do an (almost) spurious inode lock in order to coordinate
+ * with inode cache radix tree lookups. This is because the lookup
+ * can reference the inodes in the cache without taking references.
+ *
+ * We make that OK here by ensuring that we wait until the inode is
+ * unlocked after the lookup before we go ahead and free it. We get
+ * both the ilock and the iolock because the code may need to drop the
+ * ilock one but will still hold the iolock.
+ */
+ xfs_ilock(ip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL);
+ xfs_qm_dqdetach(ip);
+ xfs_iunlock(ip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL);
+
+ xfs_inode_free(ip);
return error;
}
diff --git a/fs/xfs/linux-2.6/xfs_sync.h b/fs/xfs/linux-2.6/xfs_sync.h
index e28139aaa4a..fe78726196f 100644
--- a/fs/xfs/linux-2.6/xfs_sync.h
+++ b/fs/xfs/linux-2.6/xfs_sync.h
@@ -35,9 +35,6 @@ typedef struct xfs_sync_work {
int xfs_syncd_init(struct xfs_mount *mp);
void xfs_syncd_stop(struct xfs_mount *mp);
-int xfs_sync_attr(struct xfs_mount *mp, int flags);
-int xfs_sync_data(struct xfs_mount *mp, int flags);
-
int xfs_quiesce_data(struct xfs_mount *mp);
void xfs_quiesce_attr(struct xfs_mount *mp);
diff --git a/fs/xfs/linux-2.6/xfs_trace.c b/fs/xfs/linux-2.6/xfs_trace.c
index d12be8470cb..88d25d4aa56 100644
--- a/fs/xfs/linux-2.6/xfs_trace.c
+++ b/fs/xfs/linux-2.6/xfs_trace.c
@@ -24,17 +24,13 @@
#include "xfs_trans.h"
#include "xfs_sb.h"
#include "xfs_ag.h"
-#include "xfs_dir2.h"
#include "xfs_da_btree.h"
#include "xfs_bmap_btree.h"
#include "xfs_alloc_btree.h"
#include "xfs_ialloc_btree.h"
-#include "xfs_dir2_sf.h"
-#include "xfs_attr_sf.h"
#include "xfs_dinode.h"
#include "xfs_inode.h"
#include "xfs_btree.h"
-#include "xfs_dmapi.h"
#include "xfs_mount.h"
#include "xfs_ialloc.h"
#include "xfs_itable.h"
diff --git a/fs/xfs/linux-2.6/xfs_trace.h b/fs/xfs/linux-2.6/xfs_trace.h
index 30282069090..c657cdca2cd 100644
--- a/fs/xfs/linux-2.6/xfs_trace.h
+++ b/fs/xfs/linux-2.6/xfs_trace.h
@@ -317,8 +317,6 @@ DEFINE_BUF_EVENT(xfs_buf_init);
DEFINE_BUF_EVENT(xfs_buf_free);
DEFINE_BUF_EVENT(xfs_buf_hold);
DEFINE_BUF_EVENT(xfs_buf_rele);
-DEFINE_BUF_EVENT(xfs_buf_pin);
-DEFINE_BUF_EVENT(xfs_buf_unpin);
DEFINE_BUF_EVENT(xfs_buf_iodone);
DEFINE_BUF_EVENT(xfs_buf_iorequest);
DEFINE_BUF_EVENT(xfs_buf_bawrite);
@@ -541,7 +539,7 @@ DEFINE_LOCK_EVENT(xfs_ilock_nowait);
DEFINE_LOCK_EVENT(xfs_ilock_demote);
DEFINE_LOCK_EVENT(xfs_iunlock);
-DECLARE_EVENT_CLASS(xfs_iget_class,
+DECLARE_EVENT_CLASS(xfs_inode_class,
TP_PROTO(struct xfs_inode *ip),
TP_ARGS(ip),
TP_STRUCT__entry(
@@ -557,16 +555,38 @@ DECLARE_EVENT_CLASS(xfs_iget_class,
__entry->ino)
)
-#define DEFINE_IGET_EVENT(name) \
-DEFINE_EVENT(xfs_iget_class, name, \
+#define DEFINE_INODE_EVENT(name) \
+DEFINE_EVENT(xfs_inode_class, name, \
TP_PROTO(struct xfs_inode *ip), \
TP_ARGS(ip))
-DEFINE_IGET_EVENT(xfs_iget_skip);
-DEFINE_IGET_EVENT(xfs_iget_reclaim);
-DEFINE_IGET_EVENT(xfs_iget_found);
-DEFINE_IGET_EVENT(xfs_iget_alloc);
-
-DECLARE_EVENT_CLASS(xfs_inode_class,
+DEFINE_INODE_EVENT(xfs_iget_skip);
+DEFINE_INODE_EVENT(xfs_iget_reclaim);
+DEFINE_INODE_EVENT(xfs_iget_reclaim_fail);
+DEFINE_INODE_EVENT(xfs_iget_hit);
+DEFINE_INODE_EVENT(xfs_iget_miss);
+
+DEFINE_INODE_EVENT(xfs_getattr);
+DEFINE_INODE_EVENT(xfs_setattr);
+DEFINE_INODE_EVENT(xfs_readlink);
+DEFINE_INODE_EVENT(xfs_alloc_file_space);
+DEFINE_INODE_EVENT(xfs_free_file_space);
+DEFINE_INODE_EVENT(xfs_readdir);
+#ifdef CONFIG_XFS_POSIX_ACL
+DEFINE_INODE_EVENT(xfs_check_acl);
+#endif
+DEFINE_INODE_EVENT(xfs_vm_bmap);
+DEFINE_INODE_EVENT(xfs_file_ioctl);
+DEFINE_INODE_EVENT(xfs_file_compat_ioctl);
+DEFINE_INODE_EVENT(xfs_ioctl_setattr);
+DEFINE_INODE_EVENT(xfs_file_fsync);
+DEFINE_INODE_EVENT(xfs_destroy_inode);
+DEFINE_INODE_EVENT(xfs_write_inode);
+DEFINE_INODE_EVENT(xfs_clear_inode);
+
+DEFINE_INODE_EVENT(xfs_dquot_dqalloc);
+DEFINE_INODE_EVENT(xfs_dquot_dqdetach);
+
+DECLARE_EVENT_CLASS(xfs_iref_class,
TP_PROTO(struct xfs_inode *ip, unsigned long caller_ip),
TP_ARGS(ip, caller_ip),
TP_STRUCT__entry(
@@ -591,20 +611,71 @@ DECLARE_EVENT_CLASS(xfs_inode_class,
(char *)__entry->caller_ip)
)
-#define DEFINE_INODE_EVENT(name) \
-DEFINE_EVENT(xfs_inode_class, name, \
+#define DEFINE_IREF_EVENT(name) \
+DEFINE_EVENT(xfs_iref_class, name, \
TP_PROTO(struct xfs_inode *ip, unsigned long caller_ip), \
TP_ARGS(ip, caller_ip))
-DEFINE_INODE_EVENT(xfs_ihold);
-DEFINE_INODE_EVENT(xfs_irele);
-DEFINE_INODE_EVENT(xfs_inode_pin);
-DEFINE_INODE_EVENT(xfs_inode_unpin);
-DEFINE_INODE_EVENT(xfs_inode_unpin_nowait);
+DEFINE_IREF_EVENT(xfs_ihold);
+DEFINE_IREF_EVENT(xfs_irele);
+DEFINE_IREF_EVENT(xfs_inode_pin);
+DEFINE_IREF_EVENT(xfs_inode_unpin);
+DEFINE_IREF_EVENT(xfs_inode_unpin_nowait);
+
+DECLARE_EVENT_CLASS(xfs_namespace_class,
+ TP_PROTO(struct xfs_inode *dp, struct xfs_name *name),
+ TP_ARGS(dp, name),
+ TP_STRUCT__entry(
+ __field(dev_t, dev)
+ __field(xfs_ino_t, dp_ino)
+ __dynamic_array(char, name, name->len)
+ ),
+ TP_fast_assign(
+ __entry->dev = VFS_I(dp)->i_sb->s_dev;
+ __entry->dp_ino = dp->i_ino;
+ memcpy(__get_str(name), name->name, name->len);
+ ),
+ TP_printk("dev %d:%d dp ino 0x%llx name %s",
+ MAJOR(__entry->dev), MINOR(__entry->dev),
+ __entry->dp_ino,
+ __get_str(name))
+)
-/* the old xfs_itrace_entry tracer - to be replaced by s.th. in the VFS */
-DEFINE_INODE_EVENT(xfs_inode);
-#define xfs_itrace_entry(ip) \
- trace_xfs_inode(ip, _THIS_IP_)
+#define DEFINE_NAMESPACE_EVENT(name) \
+DEFINE_EVENT(xfs_namespace_class, name, \
+ TP_PROTO(struct xfs_inode *dp, struct xfs_name *name), \
+ TP_ARGS(dp, name))
+DEFINE_NAMESPACE_EVENT(xfs_remove);
+DEFINE_NAMESPACE_EVENT(xfs_link);
+DEFINE_NAMESPACE_EVENT(xfs_lookup);
+DEFINE_NAMESPACE_EVENT(xfs_create);
+DEFINE_NAMESPACE_EVENT(xfs_symlink);
+
+TRACE_EVENT(xfs_rename,
+ TP_PROTO(struct xfs_inode *src_dp, struct xfs_inode *target_dp,
+ struct xfs_name *src_name, struct xfs_name *target_name),
+ TP_ARGS(src_dp, target_dp, src_name, target_name),
+ TP_STRUCT__entry(
+ __field(dev_t, dev)
+ __field(xfs_ino_t, src_dp_ino)
+ __field(xfs_ino_t, target_dp_ino)
+ __dynamic_array(char, src_name, src_name->len)
+ __dynamic_array(char, target_name, target_name->len)
+ ),
+ TP_fast_assign(
+ __entry->dev = VFS_I(src_dp)->i_sb->s_dev;
+ __entry->src_dp_ino = src_dp->i_ino;
+ __entry->target_dp_ino = target_dp->i_ino;
+ memcpy(__get_str(src_name), src_name->name, src_name->len);
+ memcpy(__get_str(target_name), target_name->name, target_name->len);
+ ),
+ TP_printk("dev %d:%d src dp ino 0x%llx target dp ino 0x%llx"
+ " src name %s target name %s",
+ MAJOR(__entry->dev), MINOR(__entry->dev),
+ __entry->src_dp_ino,
+ __entry->target_dp_ino,
+ __get_str(src_name),
+ __get_str(target_name))
+)
DECLARE_EVENT_CLASS(xfs_dquot_class,
TP_PROTO(struct xfs_dquot *dqp),
@@ -684,9 +755,6 @@ DEFINE_DQUOT_EVENT(xfs_dqrele);
DEFINE_DQUOT_EVENT(xfs_dqflush);
DEFINE_DQUOT_EVENT(xfs_dqflush_force);
DEFINE_DQUOT_EVENT(xfs_dqflush_done);
-/* not really iget events, but we re-use the format */
-DEFINE_IGET_EVENT(xfs_dquot_dqalloc);
-DEFINE_IGET_EVENT(xfs_dquot_dqdetach);
DECLARE_EVENT_CLASS(xfs_loggrant_class,
TP_PROTO(struct log *log, struct xlog_ticket *tic),
@@ -834,33 +902,29 @@ DECLARE_EVENT_CLASS(xfs_page_class,
__field(loff_t, size)
__field(unsigned long, offset)
__field(int, delalloc)
- __field(int, unmapped)
__field(int, unwritten)
),
TP_fast_assign(
- int delalloc = -1, unmapped = -1, unwritten = -1;
+ int delalloc = -1, unwritten = -1;
if (page_has_buffers(page))
- xfs_count_page_state(page, &delalloc,
- &unmapped, &unwritten);
+ xfs_count_page_state(page, &delalloc, &unwritten);
__entry->dev = inode->i_sb->s_dev;
__entry->ino = XFS_I(inode)->i_ino;
__entry->pgoff = page_offset(page);
__entry->size = i_size_read(inode);
__entry->offset = off;
__entry->delalloc = delalloc;
- __entry->unmapped = unmapped;
__entry->unwritten = unwritten;
),
TP_printk("dev %d:%d ino 0x%llx pgoff 0x%lx size 0x%llx offset %lx "
- "delalloc %d unmapped %d unwritten %d",
+ "delalloc %d unwritten %d",
MAJOR(__entry->dev), MINOR(__entry->dev),
__entry->ino,
__entry->pgoff,
__entry->size,
__entry->offset,
__entry->delalloc,
- __entry->unmapped,
__entry->unwritten)
)
diff --git a/fs/xfs/quota/xfs_dquot.c b/fs/xfs/quota/xfs_dquot.c
index 585e7633dfc..e1a2f6800e0 100644
--- a/fs/xfs/quota/xfs_dquot.c
+++ b/fs/xfs/quota/xfs_dquot.c
@@ -23,25 +23,15 @@
#include "xfs_trans.h"
#include "xfs_sb.h"
#include "xfs_ag.h"
-#include "xfs_dir2.h"
#include "xfs_alloc.h"
-#include "xfs_dmapi.h"
#include "xfs_quota.h"
#include "xfs_mount.h"
#include "xfs_bmap_btree.h"
-#include "xfs_alloc_btree.h"
-#include "xfs_ialloc_btree.h"
-#include "xfs_dir2_sf.h"
-#include "xfs_attr_sf.h"
-#include "xfs_dinode.h"
#include "xfs_inode.h"
-#include "xfs_btree.h"
-#include "xfs_ialloc.h"
#include "xfs_bmap.h"
#include "xfs_rtalloc.h"
#include "xfs_error.h"
#include "xfs_itable.h"
-#include "xfs_rw.h"
#include "xfs_attr.h"
#include "xfs_buf_item.h"
#include "xfs_trans_space.h"
@@ -64,8 +54,6 @@
flush lock - ditto.
*/
-STATIC void xfs_qm_dqflush_done(xfs_buf_t *, xfs_dq_logitem_t *);
-
#ifdef DEBUG
xfs_buftarg_t *xfs_dqerror_target;
int xfs_do_dqerror;
@@ -390,21 +378,14 @@ xfs_qm_dqalloc(
return (ESRCH);
}
- /*
- * xfs_trans_commit normally decrements the vnode ref count
- * when it unlocks the inode. Since we want to keep the quota
- * inode around, we bump the vnode ref count now.
- */
- IHOLD(quotip);
-
- xfs_trans_ijoin(tp, quotip, XFS_ILOCK_EXCL);
+ xfs_trans_ijoin_ref(tp, quotip, XFS_ILOCK_EXCL);
nmaps = 1;
if ((error = xfs_bmapi(tp, quotip,
offset_fsb, XFS_DQUOT_CLUSTER_SIZE_FSB,
XFS_BMAPI_METADATA | XFS_BMAPI_WRITE,
&firstblock,
XFS_QM_DQALLOC_SPACE_RES(mp),
- &map, &nmaps, &flist, NULL))) {
+ &map, &nmaps, &flist))) {
goto error0;
}
ASSERT(map.br_blockcount == XFS_DQUOT_CLUSTER_SIZE_FSB);
@@ -520,7 +501,7 @@ xfs_qm_dqtobp(
error = xfs_bmapi(NULL, quotip, dqp->q_fileoffset,
XFS_DQUOT_CLUSTER_SIZE_FSB,
XFS_BMAPI_METADATA,
- NULL, 0, &map, &nmaps, NULL, NULL);
+ NULL, 0, &map, &nmaps, NULL);
xfs_iunlock(quotip, XFS_ILOCK_SHARED);
if (error)
@@ -1141,6 +1122,46 @@ xfs_qm_dqrele(
xfs_qm_dqput(dqp);
}
+/*
+ * This is the dquot flushing I/O completion routine. It is called
+ * from interrupt level when the buffer containing the dquot is
+ * flushed to disk. It is responsible for removing the dquot logitem
+ * from the AIL if it has not been re-logged, and unlocking the dquot's
+ * flush lock. This behavior is very similar to that of inodes..
+ */
+STATIC void
+xfs_qm_dqflush_done(
+ struct xfs_buf *bp,
+ struct xfs_log_item *lip)
+{
+ xfs_dq_logitem_t *qip = (struct xfs_dq_logitem *)lip;
+ xfs_dquot_t *dqp = qip->qli_dquot;
+ struct xfs_ail *ailp = lip->li_ailp;
+
+ /*
+ * We only want to pull the item from the AIL if its
+ * location in the log has not changed since we started the flush.
+ * Thus, we only bother if the dquot's lsn has
+ * not changed. First we check the lsn outside the lock
+ * since it's cheaper, and then we recheck while
+ * holding the lock before removing the dquot from the AIL.
+ */
+ if ((lip->li_flags & XFS_LI_IN_AIL) &&
+ lip->li_lsn == qip->qli_flush_lsn) {
+
+ /* xfs_trans_ail_delete() drops the AIL lock. */
+ spin_lock(&ailp->xa_lock);
+ if (lip->li_lsn == qip->qli_flush_lsn)
+ xfs_trans_ail_delete(ailp, lip);
+ else
+ spin_unlock(&ailp->xa_lock);
+ }
+
+ /*
+ * Release the dq's flush lock since we're done with it.
+ */
+ xfs_dqfunlock(dqp);
+}
/*
* Write a modified dquot to disk.
@@ -1222,8 +1243,9 @@ xfs_qm_dqflush(
* Attach an iodone routine so that we can remove this dquot from the
* AIL and release the flush lock once the dquot is synced to disk.
*/
- xfs_buf_attach_iodone(bp, (void(*)(xfs_buf_t *, xfs_log_item_t *))
- xfs_qm_dqflush_done, &(dqp->q_logitem.qli_item));
+ xfs_buf_attach_iodone(bp, xfs_qm_dqflush_done,
+ &dqp->q_logitem.qli_item);
+
/*
* If the buffer is pinned then push on the log so we won't
* get stuck waiting in the write for too long.
@@ -1247,50 +1269,6 @@ xfs_qm_dqflush(
}
-/*
- * This is the dquot flushing I/O completion routine. It is called
- * from interrupt level when the buffer containing the dquot is
- * flushed to disk. It is responsible for removing the dquot logitem
- * from the AIL if it has not been re-logged, and unlocking the dquot's
- * flush lock. This behavior is very similar to that of inodes..
- */
-/*ARGSUSED*/
-STATIC void
-xfs_qm_dqflush_done(
- xfs_buf_t *bp,
- xfs_dq_logitem_t *qip)
-{
- xfs_dquot_t *dqp;
- struct xfs_ail *ailp;
-
- dqp = qip->qli_dquot;
- ailp = qip->qli_item.li_ailp;
-
- /*
- * We only want to pull the item from the AIL if its
- * location in the log has not changed since we started the flush.
- * Thus, we only bother if the dquot's lsn has
- * not changed. First we check the lsn outside the lock
- * since it's cheaper, and then we recheck while
- * holding the lock before removing the dquot from the AIL.
- */
- if ((qip->qli_item.li_flags & XFS_LI_IN_AIL) &&
- qip->qli_item.li_lsn == qip->qli_flush_lsn) {
-
- /* xfs_trans_ail_delete() drops the AIL lock. */
- spin_lock(&ailp->xa_lock);
- if (qip->qli_item.li_lsn == qip->qli_flush_lsn)
- xfs_trans_ail_delete(ailp, (xfs_log_item_t*)qip);
- else
- spin_unlock(&ailp->xa_lock);
- }
-
- /*
- * Release the dq's flush lock since we're done with it.
- */
- xfs_dqfunlock(dqp);
-}
-
int
xfs_qm_dqlock_nowait(
xfs_dquot_t *dqp)
diff --git a/fs/xfs/quota/xfs_dquot_item.c b/fs/xfs/quota/xfs_dquot_item.c
index 8d89a24ae32..2a1f3dc10a0 100644
--- a/fs/xfs/quota/xfs_dquot_item.c
+++ b/fs/xfs/quota/xfs_dquot_item.c
@@ -23,42 +23,36 @@
#include "xfs_trans.h"
#include "xfs_sb.h"
#include "xfs_ag.h"
-#include "xfs_dir2.h"
#include "xfs_alloc.h"
-#include "xfs_dmapi.h"
#include "xfs_quota.h"
#include "xfs_mount.h"
#include "xfs_bmap_btree.h"
-#include "xfs_alloc_btree.h"
-#include "xfs_ialloc_btree.h"
-#include "xfs_dir2_sf.h"
-#include "xfs_attr_sf.h"
-#include "xfs_dinode.h"
#include "xfs_inode.h"
#include "xfs_bmap.h"
-#include "xfs_btree.h"
-#include "xfs_ialloc.h"
#include "xfs_rtalloc.h"
#include "xfs_error.h"
#include "xfs_itable.h"
-#include "xfs_rw.h"
#include "xfs_attr.h"
#include "xfs_buf_item.h"
#include "xfs_trans_priv.h"
#include "xfs_qm.h"
+static inline struct xfs_dq_logitem *DQUOT_ITEM(struct xfs_log_item *lip)
+{
+ return container_of(lip, struct xfs_dq_logitem, qli_item);
+}
+
/*
* returns the number of iovecs needed to log the given dquot item.
*/
-/* ARGSUSED */
STATIC uint
xfs_qm_dquot_logitem_size(
- xfs_dq_logitem_t *logitem)
+ struct xfs_log_item *lip)
{
/*
* we need only two iovecs, one for the format, one for the real thing
*/
- return (2);
+ return 2;
}
/*
@@ -66,22 +60,21 @@ xfs_qm_dquot_logitem_size(
*/
STATIC void
xfs_qm_dquot_logitem_format(
- xfs_dq_logitem_t *logitem,
- xfs_log_iovec_t *logvec)
+ struct xfs_log_item *lip,
+ struct xfs_log_iovec *logvec)
{
- ASSERT(logitem);
- ASSERT(logitem->qli_dquot);
+ struct xfs_dq_logitem *qlip = DQUOT_ITEM(lip);
- logvec->i_addr = (xfs_caddr_t)&logitem->qli_format;
+ logvec->i_addr = &qlip->qli_format;
logvec->i_len = sizeof(xfs_dq_logformat_t);
logvec->i_type = XLOG_REG_TYPE_QFORMAT;
logvec++;
- logvec->i_addr = (xfs_caddr_t)&logitem->qli_dquot->q_core;
+ logvec->i_addr = &qlip->qli_dquot->q_core;
logvec->i_len = sizeof(xfs_disk_dquot_t);
logvec->i_type = XLOG_REG_TYPE_DQUOT;
- ASSERT(2 == logitem->qli_item.li_desc->lid_size);
- logitem->qli_format.qlf_size = 2;
+ ASSERT(2 == lip->li_desc->lid_size);
+ qlip->qli_format.qlf_size = 2;
}
@@ -90,9 +83,9 @@ xfs_qm_dquot_logitem_format(
*/
STATIC void
xfs_qm_dquot_logitem_pin(
- xfs_dq_logitem_t *logitem)
+ struct xfs_log_item *lip)
{
- xfs_dquot_t *dqp = logitem->qli_dquot;
+ struct xfs_dquot *dqp = DQUOT_ITEM(lip)->qli_dquot;
ASSERT(XFS_DQ_IS_LOCKED(dqp));
atomic_inc(&dqp->q_pincount);
@@ -104,27 +97,18 @@ xfs_qm_dquot_logitem_pin(
* dquot must have been previously pinned with a call to
* xfs_qm_dquot_logitem_pin().
*/
-/* ARGSUSED */
STATIC void
xfs_qm_dquot_logitem_unpin(
- xfs_dq_logitem_t *logitem)
+ struct xfs_log_item *lip,
+ int remove)
{
- xfs_dquot_t *dqp = logitem->qli_dquot;
+ struct xfs_dquot *dqp = DQUOT_ITEM(lip)->qli_dquot;
ASSERT(atomic_read(&dqp->q_pincount) > 0);
if (atomic_dec_and_test(&dqp->q_pincount))
wake_up(&dqp->q_pinwait);
}
-/* ARGSUSED */
-STATIC void
-xfs_qm_dquot_logitem_unpin_remove(
- xfs_dq_logitem_t *logitem,
- xfs_trans_t *tp)
-{
- xfs_qm_dquot_logitem_unpin(logitem);
-}
-
/*
* Given the logitem, this writes the corresponding dquot entry to disk
* asynchronously. This is called with the dquot entry securely locked;
@@ -133,12 +117,10 @@ xfs_qm_dquot_logitem_unpin_remove(
*/
STATIC void
xfs_qm_dquot_logitem_push(
- xfs_dq_logitem_t *logitem)
+ struct xfs_log_item *lip)
{
- xfs_dquot_t *dqp;
- int error;
-
- dqp = logitem->qli_dquot;
+ struct xfs_dquot *dqp = DQUOT_ITEM(lip)->qli_dquot;
+ int error;
ASSERT(XFS_DQ_IS_LOCKED(dqp));
ASSERT(!completion_done(&dqp->q_flush));
@@ -160,27 +142,25 @@ xfs_qm_dquot_logitem_push(
xfs_dqunlock(dqp);
}
-/*ARGSUSED*/
STATIC xfs_lsn_t
xfs_qm_dquot_logitem_committed(
- xfs_dq_logitem_t *l,
+ struct xfs_log_item *lip,
xfs_lsn_t lsn)
{
/*
* We always re-log the entire dquot when it becomes dirty,
* so, the latest copy _is_ the only one that matters.
*/
- return (lsn);
+ return lsn;
}
-
/*
* This is called to wait for the given dquot to be unpinned.
* Most of these pin/unpin routines are plagiarized from inode code.
*/
void
xfs_qm_dqunpin_wait(
- xfs_dquot_t *dqp)
+ struct xfs_dquot *dqp)
{
ASSERT(XFS_DQ_IS_LOCKED(dqp));
if (atomic_read(&dqp->q_pincount) == 0)
@@ -206,13 +186,12 @@ xfs_qm_dqunpin_wait(
*/
STATIC void
xfs_qm_dquot_logitem_pushbuf(
- xfs_dq_logitem_t *qip)
+ struct xfs_log_item *lip)
{
- xfs_dquot_t *dqp;
- xfs_mount_t *mp;
- xfs_buf_t *bp;
+ struct xfs_dq_logitem *qlip = DQUOT_ITEM(lip);
+ struct xfs_dquot *dqp = qlip->qli_dquot;
+ struct xfs_buf *bp;
- dqp = qip->qli_dquot;
ASSERT(XFS_DQ_IS_LOCKED(dqp));
/*
@@ -220,22 +199,20 @@ xfs_qm_dquot_logitem_pushbuf(
* inode flush completed and the inode was taken off the AIL.
* So, just get out.
*/
- if (completion_done(&dqp->q_flush) ||
- ((qip->qli_item.li_flags & XFS_LI_IN_AIL) == 0)) {
+ if (completion_done(&dqp->q_flush) ||
+ !(lip->li_flags & XFS_LI_IN_AIL)) {
xfs_dqunlock(dqp);
return;
}
- mp = dqp->q_mount;
- bp = xfs_incore(mp->m_ddev_targp, qip->qli_format.qlf_blkno,
- mp->m_quotainfo->qi_dqchunklen, XBF_TRYLOCK);
+
+ bp = xfs_incore(dqp->q_mount->m_ddev_targp, qlip->qli_format.qlf_blkno,
+ dqp->q_mount->m_quotainfo->qi_dqchunklen, XBF_TRYLOCK);
xfs_dqunlock(dqp);
if (!bp)
return;
if (XFS_BUF_ISDELAYWRITE(bp))
xfs_buf_delwri_promote(bp);
xfs_buf_relse(bp);
- return;
-
}
/*
@@ -250,15 +227,14 @@ xfs_qm_dquot_logitem_pushbuf(
*/
STATIC uint
xfs_qm_dquot_logitem_trylock(
- xfs_dq_logitem_t *qip)
+ struct xfs_log_item *lip)
{
- xfs_dquot_t *dqp;
+ struct xfs_dquot *dqp = DQUOT_ITEM(lip)->qli_dquot;
- dqp = qip->qli_dquot;
if (atomic_read(&dqp->q_pincount) > 0)
return XFS_ITEM_PINNED;
- if (! xfs_qm_dqlock_nowait(dqp))
+ if (!xfs_qm_dqlock_nowait(dqp))
return XFS_ITEM_LOCKED;
if (!xfs_dqflock_nowait(dqp)) {
@@ -269,11 +245,10 @@ xfs_qm_dquot_logitem_trylock(
return XFS_ITEM_PUSHBUF;
}
- ASSERT(qip->qli_item.li_flags & XFS_LI_IN_AIL);
+ ASSERT(lip->li_flags & XFS_LI_IN_AIL);
return XFS_ITEM_SUCCESS;
}
-
/*
* Unlock the dquot associated with the log item.
* Clear the fields of the dquot and dquot log item that
@@ -282,12 +257,10 @@ xfs_qm_dquot_logitem_trylock(
*/
STATIC void
xfs_qm_dquot_logitem_unlock(
- xfs_dq_logitem_t *ql)
+ struct xfs_log_item *lip)
{
- xfs_dquot_t *dqp;
+ struct xfs_dquot *dqp = DQUOT_ITEM(lip)->qli_dquot;
- ASSERT(ql != NULL);
- dqp = ql->qli_dquot;
ASSERT(XFS_DQ_IS_LOCKED(dqp));
/*
@@ -304,43 +277,32 @@ xfs_qm_dquot_logitem_unlock(
xfs_dqunlock(dqp);
}
-
/*
* this needs to stamp an lsn into the dquot, I think.
* rpc's that look at user dquot's would then have to
* push on the dependency recorded in the dquot
*/
-/* ARGSUSED */
STATIC void
xfs_qm_dquot_logitem_committing(
- xfs_dq_logitem_t *l,
+ struct xfs_log_item *lip,
xfs_lsn_t lsn)
{
- return;
}
-
/*
* This is the ops vector for dquots
*/
static struct xfs_item_ops xfs_dquot_item_ops = {
- .iop_size = (uint(*)(xfs_log_item_t*))xfs_qm_dquot_logitem_size,
- .iop_format = (void(*)(xfs_log_item_t*, xfs_log_iovec_t*))
- xfs_qm_dquot_logitem_format,
- .iop_pin = (void(*)(xfs_log_item_t*))xfs_qm_dquot_logitem_pin,
- .iop_unpin = (void(*)(xfs_log_item_t*))xfs_qm_dquot_logitem_unpin,
- .iop_unpin_remove = (void(*)(xfs_log_item_t*, xfs_trans_t*))
- xfs_qm_dquot_logitem_unpin_remove,
- .iop_trylock = (uint(*)(xfs_log_item_t*))
- xfs_qm_dquot_logitem_trylock,
- .iop_unlock = (void(*)(xfs_log_item_t*))xfs_qm_dquot_logitem_unlock,
- .iop_committed = (xfs_lsn_t(*)(xfs_log_item_t*, xfs_lsn_t))
- xfs_qm_dquot_logitem_committed,
- .iop_push = (void(*)(xfs_log_item_t*))xfs_qm_dquot_logitem_push,
- .iop_pushbuf = (void(*)(xfs_log_item_t*))
- xfs_qm_dquot_logitem_pushbuf,
- .iop_committing = (void(*)(xfs_log_item_t*, xfs_lsn_t))
- xfs_qm_dquot_logitem_committing
+ .iop_size = xfs_qm_dquot_logitem_size,
+ .iop_format = xfs_qm_dquot_logitem_format,
+ .iop_pin = xfs_qm_dquot_logitem_pin,
+ .iop_unpin = xfs_qm_dquot_logitem_unpin,
+ .iop_trylock = xfs_qm_dquot_logitem_trylock,
+ .iop_unlock = xfs_qm_dquot_logitem_unlock,
+ .iop_committed = xfs_qm_dquot_logitem_committed,
+ .iop_push = xfs_qm_dquot_logitem_push,
+ .iop_pushbuf = xfs_qm_dquot_logitem_pushbuf,
+ .iop_committing = xfs_qm_dquot_logitem_committing
};
/*
@@ -350,10 +312,9 @@ static struct xfs_item_ops xfs_dquot_item_ops = {
*/
void
xfs_qm_dquot_logitem_init(
- struct xfs_dquot *dqp)
+ struct xfs_dquot *dqp)
{
- xfs_dq_logitem_t *lp;
- lp = &dqp->q_logitem;
+ struct xfs_dq_logitem *lp = &dqp->q_logitem;
xfs_log_item_init(dqp->q_mount, &lp->qli_item, XFS_LI_DQUOT,
&xfs_dquot_item_ops);
@@ -374,16 +335,22 @@ xfs_qm_dquot_logitem_init(
/*------------------ QUOTAOFF LOG ITEMS -------------------*/
+static inline struct xfs_qoff_logitem *QOFF_ITEM(struct xfs_log_item *lip)
+{
+ return container_of(lip, struct xfs_qoff_logitem, qql_item);
+}
+
+
/*
* This returns the number of iovecs needed to log the given quotaoff item.
* We only need 1 iovec for an quotaoff item. It just logs the
* quotaoff_log_format structure.
*/
-/*ARGSUSED*/
STATIC uint
-xfs_qm_qoff_logitem_size(xfs_qoff_logitem_t *qf)
+xfs_qm_qoff_logitem_size(
+ struct xfs_log_item *lip)
{
- return (1);
+ return 1;
}
/*
@@ -394,53 +361,46 @@ xfs_qm_qoff_logitem_size(xfs_qoff_logitem_t *qf)
* slots in the quotaoff item have been filled.
*/
STATIC void
-xfs_qm_qoff_logitem_format(xfs_qoff_logitem_t *qf,
- xfs_log_iovec_t *log_vector)
+xfs_qm_qoff_logitem_format(
+ struct xfs_log_item *lip,
+ struct xfs_log_iovec *log_vector)
{
- ASSERT(qf->qql_format.qf_type == XFS_LI_QUOTAOFF);
+ struct xfs_qoff_logitem *qflip = QOFF_ITEM(lip);
+
+ ASSERT(qflip->qql_format.qf_type == XFS_LI_QUOTAOFF);
- log_vector->i_addr = (xfs_caddr_t)&(qf->qql_format);
+ log_vector->i_addr = &qflip->qql_format;
log_vector->i_len = sizeof(xfs_qoff_logitem_t);
log_vector->i_type = XLOG_REG_TYPE_QUOTAOFF;
- qf->qql_format.qf_size = 1;
+ qflip->qql_format.qf_size = 1;
}
-
/*
* Pinning has no meaning for an quotaoff item, so just return.
*/
-/*ARGSUSED*/
STATIC void
-xfs_qm_qoff_logitem_pin(xfs_qoff_logitem_t *qf)
+xfs_qm_qoff_logitem_pin(
+ struct xfs_log_item *lip)
{
- return;
}
-
/*
* Since pinning has no meaning for an quotaoff item, unpinning does
* not either.
*/
-/*ARGSUSED*/
STATIC void
-xfs_qm_qoff_logitem_unpin(xfs_qoff_logitem_t *qf)
+xfs_qm_qoff_logitem_unpin(
+ struct xfs_log_item *lip,
+ int remove)
{
- return;
-}
-
-/*ARGSUSED*/
-STATIC void
-xfs_qm_qoff_logitem_unpin_remove(xfs_qoff_logitem_t *qf, xfs_trans_t *tp)
-{
- return;
}
/*
* Quotaoff items have no locking, so just return success.
*/
-/*ARGSUSED*/
STATIC uint
-xfs_qm_qoff_logitem_trylock(xfs_qoff_logitem_t *qf)
+xfs_qm_qoff_logitem_trylock(
+ struct xfs_log_item *lip)
{
return XFS_ITEM_LOCKED;
}
@@ -449,53 +409,51 @@ xfs_qm_qoff_logitem_trylock(xfs_qoff_logitem_t *qf)
* Quotaoff items have no locking or pushing, so return failure
* so that the caller doesn't bother with us.
*/
-/*ARGSUSED*/
STATIC void
-xfs_qm_qoff_logitem_unlock(xfs_qoff_logitem_t *qf)
+xfs_qm_qoff_logitem_unlock(
+ struct xfs_log_item *lip)
{
- return;
}
/*
* The quotaoff-start-item is logged only once and cannot be moved in the log,
* so simply return the lsn at which it's been logged.
*/
-/*ARGSUSED*/
STATIC xfs_lsn_t
-xfs_qm_qoff_logitem_committed(xfs_qoff_logitem_t *qf, xfs_lsn_t lsn)
+xfs_qm_qoff_logitem_committed(
+ struct xfs_log_item *lip,
+ xfs_lsn_t lsn)
{
- return (lsn);
+ return lsn;
}
/*
* There isn't much you can do to push on an quotaoff item. It is simply
* stuck waiting for the log to be flushed to disk.
*/
-/*ARGSUSED*/
STATIC void
-xfs_qm_qoff_logitem_push(xfs_qoff_logitem_t *qf)
+xfs_qm_qoff_logitem_push(
+ struct xfs_log_item *lip)
{
- return;
}
-/*ARGSUSED*/
STATIC xfs_lsn_t
xfs_qm_qoffend_logitem_committed(
- xfs_qoff_logitem_t *qfe,
- xfs_lsn_t lsn)
+ struct xfs_log_item *lip,
+ xfs_lsn_t lsn)
{
- xfs_qoff_logitem_t *qfs;
- struct xfs_ail *ailp;
+ struct xfs_qoff_logitem *qfe = QOFF_ITEM(lip);
+ struct xfs_qoff_logitem *qfs = qfe->qql_start_lip;
+ struct xfs_ail *ailp = qfs->qql_item.li_ailp;
- qfs = qfe->qql_start_lip;
- ailp = qfs->qql_item.li_ailp;
- spin_lock(&ailp->xa_lock);
/*
* Delete the qoff-start logitem from the AIL.
* xfs_trans_ail_delete() drops the AIL lock.
*/
+ spin_lock(&ailp->xa_lock);
xfs_trans_ail_delete(ailp, (xfs_log_item_t *)qfs);
+
kmem_free(qfs);
kmem_free(qfe);
return (xfs_lsn_t)-1;
@@ -515,71 +473,52 @@ xfs_qm_qoffend_logitem_committed(
* (truly makes the quotaoff irrevocable). If we do something else,
* then maybe we don't need two.
*/
-/* ARGSUSED */
-STATIC void
-xfs_qm_qoff_logitem_committing(xfs_qoff_logitem_t *qip, xfs_lsn_t commit_lsn)
-{
- return;
-}
-
-/* ARGSUSED */
STATIC void
-xfs_qm_qoffend_logitem_committing(xfs_qoff_logitem_t *qip, xfs_lsn_t commit_lsn)
+xfs_qm_qoff_logitem_committing(
+ struct xfs_log_item *lip,
+ xfs_lsn_t commit_lsn)
{
- return;
}
static struct xfs_item_ops xfs_qm_qoffend_logitem_ops = {
- .iop_size = (uint(*)(xfs_log_item_t*))xfs_qm_qoff_logitem_size,
- .iop_format = (void(*)(xfs_log_item_t*, xfs_log_iovec_t*))
- xfs_qm_qoff_logitem_format,
- .iop_pin = (void(*)(xfs_log_item_t*))xfs_qm_qoff_logitem_pin,
- .iop_unpin = (void(*)(xfs_log_item_t*))xfs_qm_qoff_logitem_unpin,
- .iop_unpin_remove = (void(*)(xfs_log_item_t*,xfs_trans_t*))
- xfs_qm_qoff_logitem_unpin_remove,
- .iop_trylock = (uint(*)(xfs_log_item_t*))xfs_qm_qoff_logitem_trylock,
- .iop_unlock = (void(*)(xfs_log_item_t*))xfs_qm_qoff_logitem_unlock,
- .iop_committed = (xfs_lsn_t(*)(xfs_log_item_t*, xfs_lsn_t))
- xfs_qm_qoffend_logitem_committed,
- .iop_push = (void(*)(xfs_log_item_t*))xfs_qm_qoff_logitem_push,
- .iop_pushbuf = NULL,
- .iop_committing = (void(*)(xfs_log_item_t*, xfs_lsn_t))
- xfs_qm_qoffend_logitem_committing
+ .iop_size = xfs_qm_qoff_logitem_size,
+ .iop_format = xfs_qm_qoff_logitem_format,
+ .iop_pin = xfs_qm_qoff_logitem_pin,
+ .iop_unpin = xfs_qm_qoff_logitem_unpin,
+ .iop_trylock = xfs_qm_qoff_logitem_trylock,
+ .iop_unlock = xfs_qm_qoff_logitem_unlock,
+ .iop_committed = xfs_qm_qoffend_logitem_committed,
+ .iop_push = xfs_qm_qoff_logitem_push,
+ .iop_committing = xfs_qm_qoff_logitem_committing
};
/*
* This is the ops vector shared by all quotaoff-start log items.
*/
static struct xfs_item_ops xfs_qm_qoff_logitem_ops = {
- .iop_size = (uint(*)(xfs_log_item_t*))xfs_qm_qoff_logitem_size,
- .iop_format = (void(*)(xfs_log_item_t*, xfs_log_iovec_t*))
- xfs_qm_qoff_logitem_format,
- .iop_pin = (void(*)(xfs_log_item_t*))xfs_qm_qoff_logitem_pin,
- .iop_unpin = (void(*)(xfs_log_item_t*))xfs_qm_qoff_logitem_unpin,
- .iop_unpin_remove = (void(*)(xfs_log_item_t*,xfs_trans_t*))
- xfs_qm_qoff_logitem_unpin_remove,
- .iop_trylock = (uint(*)(xfs_log_item_t*))xfs_qm_qoff_logitem_trylock,
- .iop_unlock = (void(*)(xfs_log_item_t*))xfs_qm_qoff_logitem_unlock,
- .iop_committed = (xfs_lsn_t(*)(xfs_log_item_t*, xfs_lsn_t))
- xfs_qm_qoff_logitem_committed,
- .iop_push = (void(*)(xfs_log_item_t*))xfs_qm_qoff_logitem_push,
- .iop_pushbuf = NULL,
- .iop_committing = (void(*)(xfs_log_item_t*, xfs_lsn_t))
- xfs_qm_qoff_logitem_committing
+ .iop_size = xfs_qm_qoff_logitem_size,
+ .iop_format = xfs_qm_qoff_logitem_format,
+ .iop_pin = xfs_qm_qoff_logitem_pin,
+ .iop_unpin = xfs_qm_qoff_logitem_unpin,
+ .iop_trylock = xfs_qm_qoff_logitem_trylock,
+ .iop_unlock = xfs_qm_qoff_logitem_unlock,
+ .iop_committed = xfs_qm_qoff_logitem_committed,
+ .iop_push = xfs_qm_qoff_logitem_push,
+ .iop_committing = xfs_qm_qoff_logitem_committing
};
/*
* Allocate and initialize an quotaoff item of the correct quota type(s).
*/
-xfs_qoff_logitem_t *
+struct xfs_qoff_logitem *
xfs_qm_qoff_logitem_init(
- struct xfs_mount *mp,
- xfs_qoff_logitem_t *start,
- uint flags)
+ struct xfs_mount *mp,
+ struct xfs_qoff_logitem *start,
+ uint flags)
{
- xfs_qoff_logitem_t *qf;
+ struct xfs_qoff_logitem *qf;
- qf = (xfs_qoff_logitem_t*) kmem_zalloc(sizeof(xfs_qoff_logitem_t), KM_SLEEP);
+ qf = kmem_zalloc(sizeof(struct xfs_qoff_logitem), KM_SLEEP);
xfs_log_item_init(mp, &qf->qql_item, XFS_LI_QUOTAOFF, start ?
&xfs_qm_qoffend_logitem_ops : &xfs_qm_qoff_logitem_ops);
@@ -587,5 +526,5 @@ xfs_qm_qoff_logitem_init(
qf->qql_format.qf_type = XFS_LI_QUOTAOFF;
qf->qql_format.qf_flags = flags;
qf->qql_start_lip = start;
- return (qf);
+ return qf;
}
diff --git a/fs/xfs/quota/xfs_qm.c b/fs/xfs/quota/xfs_qm.c
index 67c018392d6..9a92407109a 100644
--- a/fs/xfs/quota/xfs_qm.c
+++ b/fs/xfs/quota/xfs_qm.c
@@ -23,25 +23,18 @@
#include "xfs_trans.h"
#include "xfs_sb.h"
#include "xfs_ag.h"
-#include "xfs_dir2.h"
#include "xfs_alloc.h"
-#include "xfs_dmapi.h"
#include "xfs_quota.h"
#include "xfs_mount.h"
#include "xfs_bmap_btree.h"
-#include "xfs_alloc_btree.h"
#include "xfs_ialloc_btree.h"
-#include "xfs_dir2_sf.h"
-#include "xfs_attr_sf.h"
#include "xfs_dinode.h"
#include "xfs_inode.h"
-#include "xfs_btree.h"
#include "xfs_ialloc.h"
#include "xfs_itable.h"
#include "xfs_rtalloc.h"
#include "xfs_error.h"
#include "xfs_bmap.h"
-#include "xfs_rw.h"
#include "xfs_attr.h"
#include "xfs_buf_item.h"
#include "xfs_trans_space.h"
@@ -1497,7 +1490,7 @@ xfs_qm_dqiterate(
maxlblkcnt - lblkno,
XFS_BMAPI_METADATA,
NULL,
- 0, map, &nmaps, NULL, NULL);
+ 0, map, &nmaps, NULL);
xfs_iunlock(qip, XFS_ILOCK_SHARED);
if (error)
break;
@@ -1669,7 +1662,8 @@ xfs_qm_dqusage_adjust(
* making us disable quotas for the file system.
*/
if ((error = xfs_qm_dqget_noattach(ip, &udqp, &gdqp))) {
- xfs_iput(ip, XFS_ILOCK_EXCL);
+ xfs_iunlock(ip, XFS_ILOCK_EXCL);
+ IRELE(ip);
*res = BULKSTAT_RV_GIVEUP;
return error;
}
@@ -1682,7 +1676,8 @@ xfs_qm_dqusage_adjust(
* Walk thru the extent list and count the realtime blocks.
*/
if ((error = xfs_qm_get_rtblks(ip, &rtblks))) {
- xfs_iput(ip, XFS_ILOCK_EXCL);
+ xfs_iunlock(ip, XFS_ILOCK_EXCL);
+ IRELE(ip);
if (udqp)
xfs_qm_dqput(udqp);
if (gdqp)
diff --git a/fs/xfs/quota/xfs_qm_bhv.c b/fs/xfs/quota/xfs_qm_bhv.c
index 97b410c1279..bea02d786c5 100644
--- a/fs/xfs/quota/xfs_qm_bhv.c
+++ b/fs/xfs/quota/xfs_qm_bhv.c
@@ -23,25 +23,15 @@
#include "xfs_trans.h"
#include "xfs_sb.h"
#include "xfs_ag.h"
-#include "xfs_dir2.h"
#include "xfs_alloc.h"
-#include "xfs_dmapi.h"
#include "xfs_quota.h"
#include "xfs_mount.h"
#include "xfs_bmap_btree.h"
-#include "xfs_alloc_btree.h"
-#include "xfs_ialloc_btree.h"
-#include "xfs_dir2_sf.h"
-#include "xfs_attr_sf.h"
-#include "xfs_dinode.h"
#include "xfs_inode.h"
-#include "xfs_ialloc.h"
#include "xfs_itable.h"
-#include "xfs_btree.h"
#include "xfs_bmap.h"
#include "xfs_rtalloc.h"
#include "xfs_error.h"
-#include "xfs_rw.h"
#include "xfs_attr.h"
#include "xfs_buf_item.h"
#include "xfs_qm.h"
diff --git a/fs/xfs/quota/xfs_qm_stats.c b/fs/xfs/quota/xfs_qm_stats.c
index 3d1fc79532e..8671a0b3264 100644
--- a/fs/xfs/quota/xfs_qm_stats.c
+++ b/fs/xfs/quota/xfs_qm_stats.c
@@ -23,25 +23,15 @@
#include "xfs_trans.h"
#include "xfs_sb.h"
#include "xfs_ag.h"
-#include "xfs_dir2.h"
#include "xfs_alloc.h"
-#include "xfs_dmapi.h"
#include "xfs_quota.h"
#include "xfs_mount.h"
#include "xfs_bmap_btree.h"
-#include "xfs_alloc_btree.h"
-#include "xfs_ialloc_btree.h"
-#include "xfs_dir2_sf.h"
-#include "xfs_attr_sf.h"
-#include "xfs_dinode.h"
#include "xfs_inode.h"
-#include "xfs_ialloc.h"
#include "xfs_itable.h"
#include "xfs_bmap.h"
-#include "xfs_btree.h"
#include "xfs_rtalloc.h"
#include "xfs_error.h"
-#include "xfs_rw.h"
#include "xfs_attr.h"
#include "xfs_buf_item.h"
#include "xfs_qm.h"
diff --git a/fs/xfs/quota/xfs_qm_syscalls.c b/fs/xfs/quota/xfs_qm_syscalls.c
index b4487764e92..45e5849df23 100644
--- a/fs/xfs/quota/xfs_qm_syscalls.c
+++ b/fs/xfs/quota/xfs_qm_syscalls.c
@@ -26,25 +26,15 @@
#include "xfs_trans.h"
#include "xfs_sb.h"
#include "xfs_ag.h"
-#include "xfs_dir2.h"
#include "xfs_alloc.h"
-#include "xfs_dmapi.h"
#include "xfs_quota.h"
#include "xfs_mount.h"
#include "xfs_bmap_btree.h"
-#include "xfs_alloc_btree.h"
-#include "xfs_ialloc_btree.h"
-#include "xfs_dir2_sf.h"
-#include "xfs_attr_sf.h"
-#include "xfs_dinode.h"
#include "xfs_inode.h"
-#include "xfs_ialloc.h"
#include "xfs_itable.h"
#include "xfs_bmap.h"
-#include "xfs_btree.h"
#include "xfs_rtalloc.h"
#include "xfs_error.h"
-#include "xfs_rw.h"
#include "xfs_attr.h"
#include "xfs_buf_item.h"
#include "xfs_utils.h"
@@ -248,40 +238,74 @@ out_unlock:
return error;
}
+STATIC int
+xfs_qm_scall_trunc_qfile(
+ struct xfs_mount *mp,
+ xfs_ino_t ino)
+{
+ struct xfs_inode *ip;
+ struct xfs_trans *tp;
+ int error;
+
+ if (ino == NULLFSINO)
+ return 0;
+
+ error = xfs_iget(mp, NULL, ino, 0, 0, &ip);
+ if (error)
+ return error;
+
+ xfs_ilock(ip, XFS_IOLOCK_EXCL);
+
+ tp = xfs_trans_alloc(mp, XFS_TRANS_TRUNCATE_FILE);
+ error = xfs_trans_reserve(tp, 0, XFS_ITRUNCATE_LOG_RES(mp), 0,
+ XFS_TRANS_PERM_LOG_RES,
+ XFS_ITRUNCATE_LOG_COUNT);
+ if (error) {
+ xfs_trans_cancel(tp, 0);
+ xfs_iunlock(ip, XFS_IOLOCK_EXCL);
+ goto out_put;
+ }
+
+ xfs_ilock(ip, XFS_ILOCK_EXCL);
+ xfs_trans_ijoin(tp, ip);
+
+ error = xfs_itruncate_finish(&tp, ip, 0, XFS_DATA_FORK, 1);
+ if (error) {
+ xfs_trans_cancel(tp, XFS_TRANS_RELEASE_LOG_RES |
+ XFS_TRANS_ABORT);
+ goto out_unlock;
+ }
+
+ xfs_ichgtime(ip, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
+ error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES);
+
+out_unlock:
+ xfs_iunlock(ip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL);
+out_put:
+ IRELE(ip);
+ return error;
+}
+
int
xfs_qm_scall_trunc_qfiles(
xfs_mount_t *mp,
uint flags)
{
int error = 0, error2 = 0;
- xfs_inode_t *qip;
if (!xfs_sb_version_hasquota(&mp->m_sb) || flags == 0) {
qdprintk("qtrunc flags=%x m_qflags=%x\n", flags, mp->m_qflags);
return XFS_ERROR(EINVAL);
}
- if ((flags & XFS_DQ_USER) && mp->m_sb.sb_uquotino != NULLFSINO) {
- error = xfs_iget(mp, NULL, mp->m_sb.sb_uquotino, 0, 0, &qip);
- if (!error) {
- error = xfs_truncate_file(mp, qip);
- IRELE(qip);
- }
- }
-
- if ((flags & (XFS_DQ_GROUP|XFS_DQ_PROJ)) &&
- mp->m_sb.sb_gquotino != NULLFSINO) {
- error2 = xfs_iget(mp, NULL, mp->m_sb.sb_gquotino, 0, 0, &qip);
- if (!error2) {
- error2 = xfs_truncate_file(mp, qip);
- IRELE(qip);
- }
- }
+ if (flags & XFS_DQ_USER)
+ error = xfs_qm_scall_trunc_qfile(mp, mp->m_sb.sb_uquotino);
+ if (flags & (XFS_DQ_GROUP|XFS_DQ_PROJ))
+ error2 = xfs_qm_scall_trunc_qfile(mp, mp->m_sb.sb_gquotino);
return error ? error : error2;
}
-
/*
* Switch on (a given) quota enforcement for a filesystem. This takes
* effect immediately.
@@ -786,9 +810,9 @@ xfs_qm_export_dquot(
}
#ifdef DEBUG
- if (((XFS_IS_UQUOTA_ENFORCED(mp) && dst->d_flags == XFS_USER_QUOTA) ||
+ if (((XFS_IS_UQUOTA_ENFORCED(mp) && dst->d_flags == FS_USER_QUOTA) ||
(XFS_IS_OQUOTA_ENFORCED(mp) &&
- (dst->d_flags & (XFS_PROJ_QUOTA | XFS_GROUP_QUOTA)))) &&
+ (dst->d_flags & (FS_PROJ_QUOTA | FS_GROUP_QUOTA)))) &&
dst->d_id != 0) {
if (((int) dst->d_bcount >= (int) dst->d_blk_softlimit) &&
(dst->d_blk_softlimit > 0)) {
@@ -809,17 +833,17 @@ xfs_qm_export_qtype_flags(
/*
* Can't be more than one, or none.
*/
- ASSERT((flags & (XFS_PROJ_QUOTA | XFS_USER_QUOTA)) !=
- (XFS_PROJ_QUOTA | XFS_USER_QUOTA));
- ASSERT((flags & (XFS_PROJ_QUOTA | XFS_GROUP_QUOTA)) !=
- (XFS_PROJ_QUOTA | XFS_GROUP_QUOTA));
- ASSERT((flags & (XFS_USER_QUOTA | XFS_GROUP_QUOTA)) !=
- (XFS_USER_QUOTA | XFS_GROUP_QUOTA));
- ASSERT((flags & (XFS_PROJ_QUOTA|XFS_USER_QUOTA|XFS_GROUP_QUOTA)) != 0);
+ ASSERT((flags & (FS_PROJ_QUOTA | FS_USER_QUOTA)) !=
+ (FS_PROJ_QUOTA | FS_USER_QUOTA));
+ ASSERT((flags & (FS_PROJ_QUOTA | FS_GROUP_QUOTA)) !=
+ (FS_PROJ_QUOTA | FS_GROUP_QUOTA));
+ ASSERT((flags & (FS_USER_QUOTA | FS_GROUP_QUOTA)) !=
+ (FS_USER_QUOTA | FS_GROUP_QUOTA));
+ ASSERT((flags & (FS_PROJ_QUOTA|FS_USER_QUOTA|FS_GROUP_QUOTA)) != 0);
return (flags & XFS_DQ_USER) ?
- XFS_USER_QUOTA : (flags & XFS_DQ_PROJ) ?
- XFS_PROJ_QUOTA : XFS_GROUP_QUOTA;
+ FS_USER_QUOTA : (flags & XFS_DQ_PROJ) ?
+ FS_PROJ_QUOTA : FS_GROUP_QUOTA;
}
STATIC uint
@@ -830,16 +854,16 @@ xfs_qm_export_flags(
uflags = 0;
if (flags & XFS_UQUOTA_ACCT)
- uflags |= XFS_QUOTA_UDQ_ACCT;
+ uflags |= FS_QUOTA_UDQ_ACCT;
if (flags & XFS_PQUOTA_ACCT)
- uflags |= XFS_QUOTA_PDQ_ACCT;
+ uflags |= FS_QUOTA_PDQ_ACCT;
if (flags & XFS_GQUOTA_ACCT)
- uflags |= XFS_QUOTA_GDQ_ACCT;
+ uflags |= FS_QUOTA_GDQ_ACCT;
if (flags & XFS_UQUOTA_ENFD)
- uflags |= XFS_QUOTA_UDQ_ENFD;
+ uflags |= FS_QUOTA_UDQ_ENFD;
if (flags & (XFS_OQUOTA_ENFD)) {
uflags |= (flags & XFS_GQUOTA_ACCT) ?
- XFS_QUOTA_GDQ_ENFD : XFS_QUOTA_PDQ_ENFD;
+ FS_QUOTA_GDQ_ENFD : FS_QUOTA_PDQ_ENFD;
}
return (uflags);
}
@@ -875,8 +899,9 @@ xfs_dqrele_inode(
xfs_qm_dqrele(ip->i_gdquot);
ip->i_gdquot = NULL;
}
- xfs_iput(ip, XFS_ILOCK_EXCL);
+ xfs_iunlock(ip, XFS_ILOCK_EXCL);
+ IRELE(ip);
return 0;
}
@@ -1143,7 +1168,8 @@ xfs_qm_internalqcheck_adjust(
* of those now.
*/
if (! ipreleased) {
- xfs_iput(ip, lock_flags);
+ xfs_iunlock(ip, lock_flags);
+ IRELE(ip);
ipreleased = B_TRUE;
goto again;
}
@@ -1160,7 +1186,8 @@ xfs_qm_internalqcheck_adjust(
ASSERT(gd);
xfs_qm_internalqcheck_dqadjust(ip, gd);
}
- xfs_iput(ip, lock_flags);
+ xfs_iunlock(ip, lock_flags);
+ IRELE(ip);
*res = BULKSTAT_RV_DIDONE;
return (0);
}
diff --git a/fs/xfs/quota/xfs_trans_dquot.c b/fs/xfs/quota/xfs_trans_dquot.c
index 061d827da33..7de91d1b75c 100644
--- a/fs/xfs/quota/xfs_trans_dquot.c
+++ b/fs/xfs/quota/xfs_trans_dquot.c
@@ -23,25 +23,15 @@
#include "xfs_trans.h"
#include "xfs_sb.h"
#include "xfs_ag.h"
-#include "xfs_dir2.h"
#include "xfs_alloc.h"
-#include "xfs_dmapi.h"
#include "xfs_quota.h"
#include "xfs_mount.h"
#include "xfs_bmap_btree.h"
-#include "xfs_alloc_btree.h"
-#include "xfs_ialloc_btree.h"
-#include "xfs_attr_sf.h"
-#include "xfs_dir2_sf.h"
-#include "xfs_dinode.h"
#include "xfs_inode.h"
-#include "xfs_ialloc.h"
#include "xfs_itable.h"
-#include "xfs_btree.h"
#include "xfs_bmap.h"
#include "xfs_rtalloc.h"
#include "xfs_error.h"
-#include "xfs_rw.h"
#include "xfs_attr.h"
#include "xfs_buf_item.h"
#include "xfs_trans_priv.h"
@@ -59,16 +49,14 @@ xfs_trans_dqjoin(
xfs_trans_t *tp,
xfs_dquot_t *dqp)
{
- xfs_dq_logitem_t *lp = &dqp->q_logitem;
-
ASSERT(dqp->q_transp != tp);
ASSERT(XFS_DQ_IS_LOCKED(dqp));
- ASSERT(lp->qli_dquot == dqp);
+ ASSERT(dqp->q_logitem.qli_dquot == dqp);
/*
* Get a log_item_desc to point at the new item.
*/
- (void) xfs_trans_add_item(tp, (xfs_log_item_t*)(lp));
+ xfs_trans_add_item(tp, &dqp->q_logitem.qli_item);
/*
* Initialize i_transp so we can later determine if this dquot is
@@ -93,16 +81,11 @@ xfs_trans_log_dquot(
xfs_trans_t *tp,
xfs_dquot_t *dqp)
{
- xfs_log_item_desc_t *lidp;
-
ASSERT(dqp->q_transp == tp);
ASSERT(XFS_DQ_IS_LOCKED(dqp));
- lidp = xfs_trans_find_item(tp, (xfs_log_item_t*)(&dqp->q_logitem));
- ASSERT(lidp != NULL);
-
tp->t_flags |= XFS_TRANS_DIRTY;
- lidp->lid_flags |= XFS_LID_DIRTY;
+ dqp->q_logitem.qli_item.li_desc->lid_flags |= XFS_LID_DIRTY;
}
/*
@@ -874,9 +857,8 @@ xfs_trans_get_qoff_item(
/*
* Get a log_item_desc to point at the new item.
*/
- (void) xfs_trans_add_item(tp, (xfs_log_item_t*)q);
-
- return (q);
+ xfs_trans_add_item(tp, &q->qql_item);
+ return q;
}
@@ -890,13 +872,8 @@ xfs_trans_log_quotaoff_item(
xfs_trans_t *tp,
xfs_qoff_logitem_t *qlp)
{
- xfs_log_item_desc_t *lidp;
-
- lidp = xfs_trans_find_item(tp, (xfs_log_item_t *)qlp);
- ASSERT(lidp != NULL);
-
tp->t_flags |= XFS_TRANS_DIRTY;
- lidp->lid_flags |= XFS_LID_DIRTY;
+ qlp->qql_item.li_desc->lid_flags |= XFS_LID_DIRTY;
}
STATIC void
diff --git a/fs/xfs/support/debug.c b/fs/xfs/support/debug.c
index 3f3610a7ee0..975aa10e1a4 100644
--- a/fs/xfs/support/debug.c
+++ b/fs/xfs/support/debug.c
@@ -22,7 +22,6 @@
#include "xfs_sb.h"
#include "xfs_inum.h"
#include "xfs_ag.h"
-#include "xfs_dmapi.h"
#include "xfs_mount.h"
#include "xfs_error.h"
diff --git a/fs/xfs/xfs_alloc.c b/fs/xfs/xfs_alloc.c
index a7fbe8a99b1..af168faccc7 100644
--- a/fs/xfs/xfs_alloc.c
+++ b/fs/xfs/xfs_alloc.c
@@ -24,18 +24,13 @@
#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_alloc_btree.h"
#include "xfs_ialloc_btree.h"
-#include "xfs_dir2_sf.h"
-#include "xfs_attr_sf.h"
#include "xfs_dinode.h"
#include "xfs_inode.h"
#include "xfs_btree.h"
-#include "xfs_ialloc.h"
#include "xfs_alloc.h"
#include "xfs_error.h"
#include "xfs_trace.h"
@@ -688,8 +683,6 @@ xfs_alloc_ag_vextent_near(
xfs_agblock_t ltbno; /* start bno of left side entry */
xfs_agblock_t ltbnoa; /* aligned ... */
xfs_extlen_t ltdiff; /* difference to left side entry */
- /*REFERENCED*/
- xfs_agblock_t ltend; /* end bno of left side entry */
xfs_extlen_t ltlen; /* length of left side entry */
xfs_extlen_t ltlena; /* aligned ... */
xfs_agblock_t ltnew; /* useful start bno of left side */
@@ -814,8 +807,7 @@ xfs_alloc_ag_vextent_near(
if ((error = xfs_alloc_get_rec(cnt_cur, &ltbno, &ltlen, &i)))
goto error0;
XFS_WANT_CORRUPTED_GOTO(i == 1, error0);
- ltend = ltbno + ltlen;
- ASSERT(ltend <= be32_to_cpu(XFS_BUF_TO_AGF(args->agbp)->agf_length));
+ ASSERT(ltbno + ltlen <= be32_to_cpu(XFS_BUF_TO_AGF(args->agbp)->agf_length));
args->len = blen;
if (!xfs_alloc_fix_minleft(args)) {
xfs_btree_del_cursor(cnt_cur, XFS_BTREE_NOERROR);
@@ -828,7 +820,7 @@ xfs_alloc_ag_vextent_near(
*/
args->agbno = bnew;
ASSERT(bnew >= ltbno);
- ASSERT(bnew + blen <= ltend);
+ ASSERT(bnew + blen <= ltbno + ltlen);
/*
* Set up a cursor for the by-bno tree.
*/
@@ -1157,7 +1149,6 @@ xfs_alloc_ag_vextent_near(
/*
* Fix up the length and compute the useful address.
*/
- ltend = ltbno + ltlen;
args->len = XFS_EXTLEN_MIN(ltlena, args->maxlen);
xfs_alloc_fix_len(args);
if (!xfs_alloc_fix_minleft(args)) {
@@ -1170,7 +1161,7 @@ xfs_alloc_ag_vextent_near(
(void)xfs_alloc_compute_diff(args->agbno, rlen, args->alignment, ltbno,
ltlen, &ltnew);
ASSERT(ltnew >= ltbno);
- ASSERT(ltnew + rlen <= ltend);
+ ASSERT(ltnew + rlen <= ltbno + ltlen);
ASSERT(ltnew + rlen <= be32_to_cpu(XFS_BUF_TO_AGF(args->agbp)->agf_length));
args->agbno = ltnew;
if ((error = xfs_alloc_fixup_trees(cnt_cur, bno_cur_lt, ltbno, ltlen,
diff --git a/fs/xfs/xfs_alloc.h b/fs/xfs/xfs_alloc.h
index 6d05199b667..895009a9727 100644
--- a/fs/xfs/xfs_alloc.h
+++ b/fs/xfs/xfs_alloc.h
@@ -27,16 +27,16 @@ struct xfs_busy_extent;
/*
* Freespace allocation types. Argument to xfs_alloc_[v]extent.
*/
-typedef enum xfs_alloctype
-{
- XFS_ALLOCTYPE_ANY_AG, /* allocate anywhere, use rotor */
- XFS_ALLOCTYPE_FIRST_AG, /* ... start at ag 0 */
- XFS_ALLOCTYPE_START_AG, /* anywhere, start in this a.g. */
- XFS_ALLOCTYPE_THIS_AG, /* anywhere in this a.g. */
- XFS_ALLOCTYPE_START_BNO, /* near this block else anywhere */
- XFS_ALLOCTYPE_NEAR_BNO, /* in this a.g. and near this block */
- XFS_ALLOCTYPE_THIS_BNO /* at exactly this block */
-} xfs_alloctype_t;
+#define XFS_ALLOCTYPE_ANY_AG 0x01 /* allocate anywhere, use rotor */
+#define XFS_ALLOCTYPE_FIRST_AG 0x02 /* ... start at ag 0 */
+#define XFS_ALLOCTYPE_START_AG 0x04 /* anywhere, start in this a.g. */
+#define XFS_ALLOCTYPE_THIS_AG 0x08 /* anywhere in this a.g. */
+#define XFS_ALLOCTYPE_START_BNO 0x10 /* near this block else anywhere */
+#define XFS_ALLOCTYPE_NEAR_BNO 0x20 /* in this a.g. and near this block */
+#define XFS_ALLOCTYPE_THIS_BNO 0x40 /* at exactly this block */
+
+/* this should become an enum again when the tracing code is fixed */
+typedef unsigned int xfs_alloctype_t;
#define XFS_ALLOC_TYPES \
{ XFS_ALLOCTYPE_ANY_AG, "ANY_AG" }, \
diff --git a/fs/xfs/xfs_alloc_btree.c b/fs/xfs/xfs_alloc_btree.c
index 83f49421875..97f7328967f 100644
--- a/fs/xfs/xfs_alloc_btree.c
+++ b/fs/xfs/xfs_alloc_btree.c
@@ -24,19 +24,14 @@
#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_alloc_btree.h"
#include "xfs_ialloc_btree.h"
-#include "xfs_dir2_sf.h"
-#include "xfs_attr_sf.h"
#include "xfs_dinode.h"
#include "xfs_inode.h"
#include "xfs_btree.h"
#include "xfs_btree_trace.h"
-#include "xfs_ialloc.h"
#include "xfs_alloc.h"
#include "xfs_error.h"
#include "xfs_trace.h"
diff --git a/fs/xfs/xfs_attr.c b/fs/xfs/xfs_attr.c
index b9c196a53c4..c2568242a90 100644
--- a/fs/xfs/xfs_attr.c
+++ b/fs/xfs/xfs_attr.c
@@ -25,19 +25,13 @@
#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_da_btree.h"
#include "xfs_bmap_btree.h"
-#include "xfs_alloc_btree.h"
-#include "xfs_ialloc_btree.h"
-#include "xfs_dir2_sf.h"
#include "xfs_attr_sf.h"
#include "xfs_dinode.h"
#include "xfs_inode.h"
#include "xfs_alloc.h"
-#include "xfs_btree.h"
#include "xfs_inode_item.h"
#include "xfs_bmap.h"
#include "xfs_attr.h"
@@ -325,8 +319,7 @@ xfs_attr_set_int(
return (error);
}
- xfs_trans_ijoin(args.trans, dp, XFS_ILOCK_EXCL);
- xfs_trans_ihold(args.trans, dp);
+ xfs_trans_ijoin(args.trans, dp);
/*
* If the attribute list is non-existent or a shortform list,
@@ -396,10 +389,8 @@ xfs_attr_set_int(
* bmap_finish() may have committed the last trans and started
* a new one. We need the inode to be in all transactions.
*/
- if (committed) {
- xfs_trans_ijoin(args.trans, dp, XFS_ILOCK_EXCL);
- xfs_trans_ihold(args.trans, dp);
- }
+ if (committed)
+ xfs_trans_ijoin(args.trans, dp);
/*
* Commit the leaf transformation. We'll need another (linked)
@@ -544,8 +535,7 @@ xfs_attr_remove_int(xfs_inode_t *dp, struct xfs_name *name, int flags)
* No need to make quota reservations here. We expect to release some
* blocks not allocate in the common case.
*/
- xfs_trans_ijoin(args.trans, dp, XFS_ILOCK_EXCL);
- xfs_trans_ihold(args.trans, dp);
+ xfs_trans_ijoin(args.trans, dp);
/*
* Decide on what work routines to call based on the inode size.
@@ -821,8 +811,7 @@ xfs_attr_inactive(xfs_inode_t *dp)
* No need to make quota reservations here. We expect to release some
* blocks, not allocate, in the common case.
*/
- xfs_trans_ijoin(trans, dp, XFS_ILOCK_EXCL);
- xfs_trans_ihold(trans, dp);
+ xfs_trans_ijoin(trans, dp);
/*
* Decide on what work routines to call based on the inode size.
@@ -981,10 +970,8 @@ xfs_attr_leaf_addname(xfs_da_args_t *args)
* bmap_finish() may have committed the last trans and started
* a new one. We need the inode to be in all transactions.
*/
- if (committed) {
- xfs_trans_ijoin(args->trans, dp, XFS_ILOCK_EXCL);
- xfs_trans_ihold(args->trans, dp);
- }
+ if (committed)
+ xfs_trans_ijoin(args->trans, dp);
/*
* Commit the current trans (including the inode) and start
@@ -1085,10 +1072,8 @@ xfs_attr_leaf_addname(xfs_da_args_t *args)
* and started a new one. We need the inode to be
* in all transactions.
*/
- if (committed) {
- xfs_trans_ijoin(args->trans, dp, XFS_ILOCK_EXCL);
- xfs_trans_ihold(args->trans, dp);
- }
+ if (committed)
+ xfs_trans_ijoin(args->trans, dp);
} else
xfs_da_buf_done(bp);
@@ -1161,10 +1146,8 @@ xfs_attr_leaf_removename(xfs_da_args_t *args)
* bmap_finish() may have committed the last trans and started
* a new one. We need the inode to be in all transactions.
*/
- if (committed) {
- xfs_trans_ijoin(args->trans, dp, XFS_ILOCK_EXCL);
- xfs_trans_ihold(args->trans, dp);
- }
+ if (committed)
+ xfs_trans_ijoin(args->trans, dp);
} else
xfs_da_buf_done(bp);
return(0);
@@ -1317,10 +1300,8 @@ restart:
* and started a new one. We need the inode to be
* in all transactions.
*/
- if (committed) {
- xfs_trans_ijoin(args->trans, dp, XFS_ILOCK_EXCL);
- xfs_trans_ihold(args->trans, dp);
- }
+ if (committed)
+ xfs_trans_ijoin(args->trans, dp);
/*
* Commit the node conversion and start the next
@@ -1356,10 +1337,8 @@ restart:
* bmap_finish() may have committed the last trans and started
* a new one. We need the inode to be in all transactions.
*/
- if (committed) {
- xfs_trans_ijoin(args->trans, dp, XFS_ILOCK_EXCL);
- xfs_trans_ihold(args->trans, dp);
- }
+ if (committed)
+ xfs_trans_ijoin(args->trans, dp);
} else {
/*
* Addition succeeded, update Btree hashvals.
@@ -1470,10 +1449,8 @@ restart:
* and started a new one. We need the inode to be
* in all transactions.
*/
- if (committed) {
- xfs_trans_ijoin(args->trans, dp, XFS_ILOCK_EXCL);
- xfs_trans_ihold(args->trans, dp);
- }
+ if (committed)
+ xfs_trans_ijoin(args->trans, dp);
}
/*
@@ -1604,10 +1581,8 @@ xfs_attr_node_removename(xfs_da_args_t *args)
* bmap_finish() may have committed the last trans and started
* a new one. We need the inode to be in all transactions.
*/
- if (committed) {
- xfs_trans_ijoin(args->trans, dp, XFS_ILOCK_EXCL);
- xfs_trans_ihold(args->trans, dp);
- }
+ if (committed)
+ xfs_trans_ijoin(args->trans, dp);
/*
* Commit the Btree join operation and start a new trans.
@@ -1658,10 +1633,8 @@ xfs_attr_node_removename(xfs_da_args_t *args)
* and started a new one. We need the inode to be
* in all transactions.
*/
- if (committed) {
- xfs_trans_ijoin(args->trans, dp, XFS_ILOCK_EXCL);
- xfs_trans_ihold(args->trans, dp);
- }
+ if (committed)
+ xfs_trans_ijoin(args->trans, dp);
} else
xfs_da_brelse(args->trans, bp);
}
@@ -2004,7 +1977,7 @@ xfs_attr_rmtval_get(xfs_da_args_t *args)
error = xfs_bmapi(args->trans, args->dp, (xfs_fileoff_t)lblkno,
args->rmtblkcnt,
XFS_BMAPI_ATTRFORK | XFS_BMAPI_METADATA,
- NULL, 0, map, &nmap, NULL, NULL);
+ NULL, 0, map, &nmap, NULL);
if (error)
return(error);
ASSERT(nmap >= 1);
@@ -2083,7 +2056,7 @@ xfs_attr_rmtval_set(xfs_da_args_t *args)
XFS_BMAPI_ATTRFORK | XFS_BMAPI_METADATA |
XFS_BMAPI_WRITE,
args->firstblock, args->total, &map, &nmap,
- args->flist, NULL);
+ args->flist);
if (!error) {
error = xfs_bmap_finish(&args->trans, args->flist,
&committed);
@@ -2099,10 +2072,8 @@ xfs_attr_rmtval_set(xfs_da_args_t *args)
* bmap_finish() may have committed the last trans and started
* a new one. We need the inode to be in all transactions.
*/
- if (committed) {
- xfs_trans_ijoin(args->trans, dp, XFS_ILOCK_EXCL);
- xfs_trans_ihold(args->trans, dp);
- }
+ if (committed)
+ xfs_trans_ijoin(args->trans, dp);
ASSERT(nmap == 1);
ASSERT((map.br_startblock != DELAYSTARTBLOCK) &&
@@ -2136,7 +2107,7 @@ xfs_attr_rmtval_set(xfs_da_args_t *args)
args->rmtblkcnt,
XFS_BMAPI_ATTRFORK | XFS_BMAPI_METADATA,
args->firstblock, 0, &map, &nmap,
- NULL, NULL);
+ NULL);
if (error) {
return(error);
}
@@ -2201,7 +2172,7 @@ xfs_attr_rmtval_remove(xfs_da_args_t *args)
args->rmtblkcnt,
XFS_BMAPI_ATTRFORK | XFS_BMAPI_METADATA,
args->firstblock, 0, &map, &nmap,
- args->flist, NULL);
+ args->flist);
if (error) {
return(error);
}
@@ -2239,7 +2210,7 @@ xfs_attr_rmtval_remove(xfs_da_args_t *args)
error = xfs_bunmapi(args->trans, args->dp, lblkno, blkcnt,
XFS_BMAPI_ATTRFORK | XFS_BMAPI_METADATA,
1, args->firstblock, args->flist,
- NULL, &done);
+ &done);
if (!error) {
error = xfs_bmap_finish(&args->trans, args->flist,
&committed);
@@ -2255,10 +2226,8 @@ xfs_attr_rmtval_remove(xfs_da_args_t *args)
* bmap_finish() may have committed the last trans and started
* a new one. We need the inode to be in all transactions.
*/
- if (committed) {
- xfs_trans_ijoin(args->trans, args->dp, XFS_ILOCK_EXCL);
- xfs_trans_ihold(args->trans, args->dp);
- }
+ if (committed)
+ xfs_trans_ijoin(args->trans, args->dp);
/*
* Close out trans and start the next one in the chain.
diff --git a/fs/xfs/xfs_attr_leaf.c b/fs/xfs/xfs_attr_leaf.c
index a90ce74fc25..a6cff8edcdb 100644
--- a/fs/xfs/xfs_attr_leaf.c
+++ b/fs/xfs/xfs_attr_leaf.c
@@ -24,8 +24,6 @@
#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_da_btree.h"
#include "xfs_bmap_btree.h"
@@ -33,7 +31,6 @@
#include "xfs_ialloc_btree.h"
#include "xfs_alloc.h"
#include "xfs_btree.h"
-#include "xfs_dir2_sf.h"
#include "xfs_attr_sf.h"
#include "xfs_dinode.h"
#include "xfs_inode.h"
@@ -2931,7 +2928,7 @@ xfs_attr_leaf_freextent(xfs_trans_t **trans, xfs_inode_t *dp,
nmap = 1;
error = xfs_bmapi(*trans, dp, (xfs_fileoff_t)tblkno, tblkcnt,
XFS_BMAPI_ATTRFORK | XFS_BMAPI_METADATA,
- NULL, 0, &map, &nmap, NULL, NULL);
+ NULL, 0, &map, &nmap, NULL);
if (error) {
return(error);
}
diff --git a/fs/xfs/xfs_bmap.c b/fs/xfs/xfs_bmap.c
index 99587ded043..23f14e595c1 100644
--- a/fs/xfs/xfs_bmap.c
+++ b/fs/xfs/xfs_bmap.c
@@ -30,13 +30,10 @@
#include "xfs_alloc_btree.h"
#include "xfs_ialloc_btree.h"
#include "xfs_dir2_sf.h"
-#include "xfs_attr_sf.h"
#include "xfs_dinode.h"
#include "xfs_inode.h"
#include "xfs_btree.h"
-#include "xfs_dmapi.h"
#include "xfs_mount.h"
-#include "xfs_ialloc.h"
#include "xfs_itable.h"
#include "xfs_dir2_data.h"
#include "xfs_dir2_leaf.h"
@@ -104,7 +101,6 @@ xfs_bmap_add_extent(
xfs_fsblock_t *first, /* pointer to firstblock variable */
xfs_bmap_free_t *flist, /* list of extents to be freed */
int *logflagsp, /* inode logging flags */
- xfs_extdelta_t *delta, /* Change made to incore extents */
int whichfork, /* data or attr fork */
int rsvd); /* OK to allocate reserved blocks */
@@ -122,7 +118,6 @@ xfs_bmap_add_extent_delay_real(
xfs_fsblock_t *first, /* pointer to firstblock variable */
xfs_bmap_free_t *flist, /* list of extents to be freed */
int *logflagsp, /* inode logging flags */
- xfs_extdelta_t *delta, /* Change made to incore extents */
int rsvd); /* OK to allocate reserved blocks */
/*
@@ -135,7 +130,6 @@ xfs_bmap_add_extent_hole_delay(
xfs_extnum_t idx, /* extent number to update/insert */
xfs_bmbt_irec_t *new, /* new data to add to file extents */
int *logflagsp,/* inode logging flags */
- xfs_extdelta_t *delta, /* Change made to incore extents */
int rsvd); /* OK to allocate reserved blocks */
/*
@@ -149,7 +143,6 @@ xfs_bmap_add_extent_hole_real(
xfs_btree_cur_t *cur, /* if null, not a btree */
xfs_bmbt_irec_t *new, /* new data to add to file extents */
int *logflagsp, /* inode logging flags */
- xfs_extdelta_t *delta, /* Change made to incore extents */
int whichfork); /* data or attr fork */
/*
@@ -162,8 +155,7 @@ xfs_bmap_add_extent_unwritten_real(
xfs_extnum_t idx, /* extent number to update/insert */
xfs_btree_cur_t **curp, /* if *curp is null, not a btree */
xfs_bmbt_irec_t *new, /* new data to add to file extents */
- int *logflagsp, /* inode logging flags */
- xfs_extdelta_t *delta); /* Change made to incore extents */
+ int *logflagsp); /* inode logging flags */
/*
* xfs_bmap_alloc is called by xfs_bmapi to allocate an extent for a file.
@@ -200,7 +192,6 @@ xfs_bmap_del_extent(
xfs_btree_cur_t *cur, /* if null, not a btree */
xfs_bmbt_irec_t *new, /* new data to add to file extents */
int *logflagsp,/* inode logging flags */
- xfs_extdelta_t *delta, /* Change made to incore extents */
int whichfork, /* data or attr fork */
int rsvd); /* OK to allocate reserved blocks */
@@ -489,7 +480,6 @@ xfs_bmap_add_extent(
xfs_fsblock_t *first, /* pointer to firstblock variable */
xfs_bmap_free_t *flist, /* list of extents to be freed */
int *logflagsp, /* inode logging flags */
- xfs_extdelta_t *delta, /* Change made to incore extents */
int whichfork, /* data or attr fork */
int rsvd) /* OK to use reserved data blocks */
{
@@ -524,15 +514,6 @@ xfs_bmap_add_extent(
logflags = XFS_ILOG_CORE | xfs_ilog_fext(whichfork);
} else
logflags = 0;
- /* DELTA: single new extent */
- if (delta) {
- if (delta->xed_startoff > new->br_startoff)
- delta->xed_startoff = new->br_startoff;
- if (delta->xed_blockcount <
- new->br_startoff + new->br_blockcount)
- delta->xed_blockcount = new->br_startoff +
- new->br_blockcount;
- }
}
/*
* Any kind of new delayed allocation goes here.
@@ -542,7 +523,7 @@ xfs_bmap_add_extent(
ASSERT((cur->bc_private.b.flags &
XFS_BTCUR_BPRV_WASDEL) == 0);
if ((error = xfs_bmap_add_extent_hole_delay(ip, idx, new,
- &logflags, delta, rsvd)))
+ &logflags, rsvd)))
goto done;
}
/*
@@ -553,7 +534,7 @@ xfs_bmap_add_extent(
ASSERT((cur->bc_private.b.flags &
XFS_BTCUR_BPRV_WASDEL) == 0);
if ((error = xfs_bmap_add_extent_hole_real(ip, idx, cur, new,
- &logflags, delta, whichfork)))
+ &logflags, whichfork)))
goto done;
} else {
xfs_bmbt_irec_t prev; /* old extent at offset idx */
@@ -578,17 +559,17 @@ xfs_bmap_add_extent(
XFS_BTCUR_BPRV_WASDEL);
if ((error = xfs_bmap_add_extent_delay_real(ip,
idx, &cur, new, &da_new, first, flist,
- &logflags, delta, rsvd)))
+ &logflags, rsvd)))
goto done;
} else if (new->br_state == XFS_EXT_NORM) {
ASSERT(new->br_state == XFS_EXT_NORM);
if ((error = xfs_bmap_add_extent_unwritten_real(
- ip, idx, &cur, new, &logflags, delta)))
+ ip, idx, &cur, new, &logflags)))
goto done;
} else {
ASSERT(new->br_state == XFS_EXT_UNWRITTEN);
if ((error = xfs_bmap_add_extent_unwritten_real(
- ip, idx, &cur, new, &logflags, delta)))
+ ip, idx, &cur, new, &logflags)))
goto done;
}
ASSERT(*curp == cur || *curp == NULL);
@@ -601,7 +582,7 @@ xfs_bmap_add_extent(
ASSERT((cur->bc_private.b.flags &
XFS_BTCUR_BPRV_WASDEL) == 0);
if ((error = xfs_bmap_add_extent_hole_real(ip, idx, cur,
- new, &logflags, delta, whichfork)))
+ new, &logflags, whichfork)))
goto done;
}
}
@@ -666,7 +647,6 @@ xfs_bmap_add_extent_delay_real(
xfs_fsblock_t *first, /* pointer to firstblock variable */
xfs_bmap_free_t *flist, /* list of extents to be freed */
int *logflagsp, /* inode logging flags */
- xfs_extdelta_t *delta, /* Change made to incore extents */
int rsvd) /* OK to use reserved data block allocation */
{
xfs_btree_cur_t *cur; /* btree cursor */
@@ -797,11 +777,6 @@ xfs_bmap_add_extent_delay_real(
goto done;
}
*dnew = 0;
- /* DELTA: Three in-core extents are replaced by one. */
- temp = LEFT.br_startoff;
- temp2 = LEFT.br_blockcount +
- PREV.br_blockcount +
- RIGHT.br_blockcount;
break;
case BMAP_LEFT_FILLING | BMAP_RIGHT_FILLING | BMAP_LEFT_CONTIG:
@@ -832,10 +807,6 @@ xfs_bmap_add_extent_delay_real(
goto done;
}
*dnew = 0;
- /* DELTA: Two in-core extents are replaced by one. */
- temp = LEFT.br_startoff;
- temp2 = LEFT.br_blockcount +
- PREV.br_blockcount;
break;
case BMAP_LEFT_FILLING | BMAP_RIGHT_FILLING | BMAP_RIGHT_CONTIG:
@@ -867,10 +838,6 @@ xfs_bmap_add_extent_delay_real(
goto done;
}
*dnew = 0;
- /* DELTA: Two in-core extents are replaced by one. */
- temp = PREV.br_startoff;
- temp2 = PREV.br_blockcount +
- RIGHT.br_blockcount;
break;
case BMAP_LEFT_FILLING | BMAP_RIGHT_FILLING:
@@ -900,9 +867,6 @@ xfs_bmap_add_extent_delay_real(
XFS_WANT_CORRUPTED_GOTO(i == 1, done);
}
*dnew = 0;
- /* DELTA: The in-core extent described by new changed type. */
- temp = new->br_startoff;
- temp2 = new->br_blockcount;
break;
case BMAP_LEFT_FILLING | BMAP_LEFT_CONTIG:
@@ -942,10 +906,6 @@ xfs_bmap_add_extent_delay_real(
xfs_bmbt_set_startblock(ep, nullstartblock((int)temp));
trace_xfs_bmap_post_update(ip, idx, state, _THIS_IP_);
*dnew = temp;
- /* DELTA: The boundary between two in-core extents moved. */
- temp = LEFT.br_startoff;
- temp2 = LEFT.br_blockcount +
- PREV.br_blockcount;
break;
case BMAP_LEFT_FILLING:
@@ -990,9 +950,6 @@ xfs_bmap_add_extent_delay_real(
xfs_bmbt_set_startblock(ep, nullstartblock((int)temp));
trace_xfs_bmap_post_update(ip, idx + 1, state, _THIS_IP_);
*dnew = temp;
- /* DELTA: One in-core extent is split in two. */
- temp = PREV.br_startoff;
- temp2 = PREV.br_blockcount;
break;
case BMAP_RIGHT_FILLING | BMAP_RIGHT_CONTIG:
@@ -1031,10 +988,6 @@ xfs_bmap_add_extent_delay_real(
xfs_bmbt_set_startblock(ep, nullstartblock((int)temp));
trace_xfs_bmap_post_update(ip, idx, state, _THIS_IP_);
*dnew = temp;
- /* DELTA: The boundary between two in-core extents moved. */
- temp = PREV.br_startoff;
- temp2 = PREV.br_blockcount +
- RIGHT.br_blockcount;
break;
case BMAP_RIGHT_FILLING:
@@ -1078,9 +1031,6 @@ xfs_bmap_add_extent_delay_real(
xfs_bmbt_set_startblock(ep, nullstartblock((int)temp));
trace_xfs_bmap_post_update(ip, idx, state, _THIS_IP_);
*dnew = temp;
- /* DELTA: One in-core extent is split in two. */
- temp = PREV.br_startoff;
- temp2 = PREV.br_blockcount;
break;
case 0:
@@ -1161,9 +1111,6 @@ xfs_bmap_add_extent_delay_real(
nullstartblock((int)temp2));
trace_xfs_bmap_post_update(ip, idx + 2, state, _THIS_IP_);
*dnew = temp + temp2;
- /* DELTA: One in-core extent is split in three. */
- temp = PREV.br_startoff;
- temp2 = PREV.br_blockcount;
break;
case BMAP_LEFT_FILLING | BMAP_LEFT_CONTIG | BMAP_RIGHT_CONTIG:
@@ -1179,13 +1126,6 @@ xfs_bmap_add_extent_delay_real(
ASSERT(0);
}
*curp = cur;
- if (delta) {
- temp2 += temp;
- if (delta->xed_startoff > temp)
- delta->xed_startoff = temp;
- if (delta->xed_blockcount < temp2)
- delta->xed_blockcount = temp2;
- }
done:
*logflagsp = rval;
return error;
@@ -1204,8 +1144,7 @@ xfs_bmap_add_extent_unwritten_real(
xfs_extnum_t idx, /* extent number to update/insert */
xfs_btree_cur_t **curp, /* if *curp is null, not a btree */
xfs_bmbt_irec_t *new, /* new data to add to file extents */
- int *logflagsp, /* inode logging flags */
- xfs_extdelta_t *delta) /* Change made to incore extents */
+ int *logflagsp) /* inode logging flags */
{
xfs_btree_cur_t *cur; /* btree cursor */
xfs_bmbt_rec_host_t *ep; /* extent entry for idx */
@@ -1219,8 +1158,6 @@ xfs_bmap_add_extent_unwritten_real(
/* left is 0, right is 1, prev is 2 */
int rval=0; /* return value (logging flags) */
int state = 0;/* state bits, accessed thru macros */
- xfs_filblks_t temp=0;
- xfs_filblks_t temp2=0;
#define LEFT r[0]
#define RIGHT r[1]
@@ -1341,11 +1278,6 @@ xfs_bmap_add_extent_unwritten_real(
RIGHT.br_blockcount, LEFT.br_state)))
goto done;
}
- /* DELTA: Three in-core extents are replaced by one. */
- temp = LEFT.br_startoff;
- temp2 = LEFT.br_blockcount +
- PREV.br_blockcount +
- RIGHT.br_blockcount;
break;
case BMAP_LEFT_FILLING | BMAP_RIGHT_FILLING | BMAP_LEFT_CONTIG:
@@ -1382,10 +1314,6 @@ xfs_bmap_add_extent_unwritten_real(
LEFT.br_state)))
goto done;
}
- /* DELTA: Two in-core extents are replaced by one. */
- temp = LEFT.br_startoff;
- temp2 = LEFT.br_blockcount +
- PREV.br_blockcount;
break;
case BMAP_LEFT_FILLING | BMAP_RIGHT_FILLING | BMAP_RIGHT_CONTIG:
@@ -1422,10 +1350,6 @@ xfs_bmap_add_extent_unwritten_real(
newext)))
goto done;
}
- /* DELTA: Two in-core extents are replaced by one. */
- temp = PREV.br_startoff;
- temp2 = PREV.br_blockcount +
- RIGHT.br_blockcount;
break;
case BMAP_LEFT_FILLING | BMAP_RIGHT_FILLING:
@@ -1453,9 +1377,6 @@ xfs_bmap_add_extent_unwritten_real(
newext)))
goto done;
}
- /* DELTA: The in-core extent described by new changed type. */
- temp = new->br_startoff;
- temp2 = new->br_blockcount;
break;
case BMAP_LEFT_FILLING | BMAP_LEFT_CONTIG:
@@ -1501,10 +1422,6 @@ xfs_bmap_add_extent_unwritten_real(
LEFT.br_state))
goto done;
}
- /* DELTA: The boundary between two in-core extents moved. */
- temp = LEFT.br_startoff;
- temp2 = LEFT.br_blockcount +
- PREV.br_blockcount;
break;
case BMAP_LEFT_FILLING:
@@ -1544,9 +1461,6 @@ xfs_bmap_add_extent_unwritten_real(
goto done;
XFS_WANT_CORRUPTED_GOTO(i == 1, done);
}
- /* DELTA: One in-core extent is split in two. */
- temp = PREV.br_startoff;
- temp2 = PREV.br_blockcount;
break;
case BMAP_RIGHT_FILLING | BMAP_RIGHT_CONTIG:
@@ -1587,10 +1501,6 @@ xfs_bmap_add_extent_unwritten_real(
newext)))
goto done;
}
- /* DELTA: The boundary between two in-core extents moved. */
- temp = PREV.br_startoff;
- temp2 = PREV.br_blockcount +
- RIGHT.br_blockcount;
break;
case BMAP_RIGHT_FILLING:
@@ -1630,9 +1540,6 @@ xfs_bmap_add_extent_unwritten_real(
goto done;
XFS_WANT_CORRUPTED_GOTO(i == 1, done);
}
- /* DELTA: One in-core extent is split in two. */
- temp = PREV.br_startoff;
- temp2 = PREV.br_blockcount;
break;
case 0:
@@ -1692,9 +1599,6 @@ xfs_bmap_add_extent_unwritten_real(
goto done;
XFS_WANT_CORRUPTED_GOTO(i == 1, done);
}
- /* DELTA: One in-core extent is split in three. */
- temp = PREV.br_startoff;
- temp2 = PREV.br_blockcount;
break;
case BMAP_LEFT_FILLING | BMAP_LEFT_CONTIG | BMAP_RIGHT_CONTIG:
@@ -1710,13 +1614,6 @@ xfs_bmap_add_extent_unwritten_real(
ASSERT(0);
}
*curp = cur;
- if (delta) {
- temp2 += temp;
- if (delta->xed_startoff > temp)
- delta->xed_startoff = temp;
- if (delta->xed_blockcount < temp2)
- delta->xed_blockcount = temp2;
- }
done:
*logflagsp = rval;
return error;
@@ -1736,7 +1633,6 @@ xfs_bmap_add_extent_hole_delay(
xfs_extnum_t idx, /* extent number to update/insert */
xfs_bmbt_irec_t *new, /* new data to add to file extents */
int *logflagsp, /* inode logging flags */
- xfs_extdelta_t *delta, /* Change made to incore extents */
int rsvd) /* OK to allocate reserved blocks */
{
xfs_bmbt_rec_host_t *ep; /* extent record for idx */
@@ -1747,7 +1643,6 @@ xfs_bmap_add_extent_hole_delay(
xfs_bmbt_irec_t right; /* right neighbor extent entry */
int state; /* state bits, accessed thru macros */
xfs_filblks_t temp=0; /* temp for indirect calculations */
- xfs_filblks_t temp2=0;
ifp = XFS_IFORK_PTR(ip, XFS_DATA_FORK);
ep = xfs_iext_get_ext(ifp, idx);
@@ -1819,9 +1714,6 @@ xfs_bmap_add_extent_hole_delay(
xfs_iext_remove(ip, idx, 1, state);
ip->i_df.if_lastex = idx - 1;
- /* DELTA: Two in-core extents were replaced by one. */
- temp2 = temp;
- temp = left.br_startoff;
break;
case BMAP_LEFT_CONTIG:
@@ -1841,9 +1733,6 @@ xfs_bmap_add_extent_hole_delay(
trace_xfs_bmap_post_update(ip, idx - 1, state, _THIS_IP_);
ip->i_df.if_lastex = idx - 1;
- /* DELTA: One in-core extent grew into a hole. */
- temp2 = temp;
- temp = left.br_startoff;
break;
case BMAP_RIGHT_CONTIG:
@@ -1862,9 +1751,6 @@ xfs_bmap_add_extent_hole_delay(
trace_xfs_bmap_post_update(ip, idx, state, _THIS_IP_);
ip->i_df.if_lastex = idx;
- /* DELTA: One in-core extent grew into a hole. */
- temp2 = temp;
- temp = new->br_startoff;
break;
case 0:
@@ -1876,9 +1762,6 @@ xfs_bmap_add_extent_hole_delay(
oldlen = newlen = 0;
xfs_iext_insert(ip, idx, 1, new, state);
ip->i_df.if_lastex = idx;
- /* DELTA: A new in-core extent was added in a hole. */
- temp2 = new->br_blockcount;
- temp = new->br_startoff;
break;
}
if (oldlen != newlen) {
@@ -1889,13 +1772,6 @@ xfs_bmap_add_extent_hole_delay(
* Nothing to do for disk quota accounting here.
*/
}
- if (delta) {
- temp2 += temp;
- if (delta->xed_startoff > temp)
- delta->xed_startoff = temp;
- if (delta->xed_blockcount < temp2)
- delta->xed_blockcount = temp2;
- }
*logflagsp = 0;
return 0;
}
@@ -1911,7 +1787,6 @@ xfs_bmap_add_extent_hole_real(
xfs_btree_cur_t *cur, /* if null, not a btree */
xfs_bmbt_irec_t *new, /* new data to add to file extents */
int *logflagsp, /* inode logging flags */
- xfs_extdelta_t *delta, /* Change made to incore extents */
int whichfork) /* data or attr fork */
{
xfs_bmbt_rec_host_t *ep; /* pointer to extent entry ins. point */
@@ -1922,8 +1797,6 @@ xfs_bmap_add_extent_hole_real(
xfs_bmbt_irec_t right; /* right neighbor extent entry */
int rval=0; /* return value (logging flags) */
int state; /* state bits, accessed thru macros */
- xfs_filblks_t temp=0;
- xfs_filblks_t temp2=0;
ifp = XFS_IFORK_PTR(ip, whichfork);
ASSERT(idx <= ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t));
@@ -2020,11 +1893,6 @@ xfs_bmap_add_extent_hole_real(
left.br_state)))
goto done;
}
- /* DELTA: Two in-core extents were replaced by one. */
- temp = left.br_startoff;
- temp2 = left.br_blockcount +
- new->br_blockcount +
- right.br_blockcount;
break;
case BMAP_LEFT_CONTIG:
@@ -2056,10 +1924,6 @@ xfs_bmap_add_extent_hole_real(
left.br_state)))
goto done;
}
- /* DELTA: One in-core extent grew. */
- temp = left.br_startoff;
- temp2 = left.br_blockcount +
- new->br_blockcount;
break;
case BMAP_RIGHT_CONTIG:
@@ -2092,10 +1956,6 @@ xfs_bmap_add_extent_hole_real(
right.br_state)))
goto done;
}
- /* DELTA: One in-core extent grew. */
- temp = new->br_startoff;
- temp2 = new->br_blockcount +
- right.br_blockcount;
break;
case 0:
@@ -2123,18 +1983,8 @@ xfs_bmap_add_extent_hole_real(
goto done;
XFS_WANT_CORRUPTED_GOTO(i == 1, done);
}
- /* DELTA: A new extent was added in a hole. */
- temp = new->br_startoff;
- temp2 = new->br_blockcount;
break;
}
- if (delta) {
- temp2 += temp;
- if (delta->xed_startoff > temp)
- delta->xed_startoff = temp;
- if (delta->xed_blockcount < temp2)
- delta->xed_blockcount = temp2;
- }
done:
*logflagsp = rval;
return error;
@@ -2959,7 +2809,6 @@ xfs_bmap_del_extent(
xfs_btree_cur_t *cur, /* if null, not a btree */
xfs_bmbt_irec_t *del, /* data to remove from extents */
int *logflagsp, /* inode logging flags */
- xfs_extdelta_t *delta, /* Change made to incore extents */
int whichfork, /* data or attr fork */
int rsvd) /* OK to allocate reserved blocks */
{
@@ -3265,14 +3114,6 @@ xfs_bmap_del_extent(
if (da_old > da_new)
xfs_mod_incore_sb(mp, XFS_SBS_FDBLOCKS, (int64_t)(da_old - da_new),
rsvd);
- if (delta) {
- /* DELTA: report the original extent. */
- if (delta->xed_startoff > got.br_startoff)
- delta->xed_startoff = got.br_startoff;
- if (delta->xed_blockcount < got.br_startoff+got.br_blockcount)
- delta->xed_blockcount = got.br_startoff +
- got.br_blockcount;
- }
done:
*logflagsp = flags;
return error;
@@ -3754,9 +3595,10 @@ xfs_bmap_add_attrfork(
ip->i_d.di_aformat = XFS_DINODE_FMT_EXTENTS;
}
ASSERT(ip->i_d.di_anextents == 0);
- IHOLD(ip);
- xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL);
+
+ xfs_trans_ijoin_ref(tp, ip, XFS_ILOCK_EXCL);
xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
+
switch (ip->i_d.di_format) {
case XFS_DINODE_FMT_DEV:
ip->i_d.di_forkoff = roundup(sizeof(xfs_dev_t), 8) >> 3;
@@ -4483,8 +4325,7 @@ xfs_bmapi(
xfs_extlen_t total, /* total blocks needed */
xfs_bmbt_irec_t *mval, /* output: map values */
int *nmap, /* i/o: mval size/count */
- xfs_bmap_free_t *flist, /* i/o: list extents to free */
- xfs_extdelta_t *delta) /* o: change made to incore extents */
+ xfs_bmap_free_t *flist) /* i/o: list extents to free */
{
xfs_fsblock_t abno; /* allocated block number */
xfs_extlen_t alen; /* allocated extent length */
@@ -4596,10 +4437,7 @@ xfs_bmapi(
end = bno + len;
obno = bno;
bma.ip = NULL;
- if (delta) {
- delta->xed_startoff = NULLFILEOFF;
- delta->xed_blockcount = 0;
- }
+
while (bno < end && n < *nmap) {
/*
* Reading past eof, act as though there's a hole
@@ -4620,19 +4458,13 @@ xfs_bmapi(
* allocate the stuff asked for in this bmap call
* but that wouldn't be as good.
*/
- if (wasdelay && !(flags & XFS_BMAPI_EXACT)) {
+ if (wasdelay) {
alen = (xfs_extlen_t)got.br_blockcount;
aoff = got.br_startoff;
if (lastx != NULLEXTNUM && lastx) {
ep = xfs_iext_get_ext(ifp, lastx - 1);
xfs_bmbt_get_all(ep, &prev);
}
- } else if (wasdelay) {
- alen = (xfs_extlen_t)
- XFS_FILBLKS_MIN(len,
- (got.br_startoff +
- got.br_blockcount) - bno);
- aoff = bno;
} else {
alen = (xfs_extlen_t)
XFS_FILBLKS_MIN(len, MAXEXTLEN);
@@ -4831,7 +4663,7 @@ xfs_bmapi(
got.br_state = XFS_EXT_UNWRITTEN;
}
error = xfs_bmap_add_extent(ip, lastx, &cur, &got,
- firstblock, flist, &tmp_logflags, delta,
+ firstblock, flist, &tmp_logflags,
whichfork, (flags & XFS_BMAPI_RSVBLOCKS));
logflags |= tmp_logflags;
if (error)
@@ -4927,7 +4759,7 @@ xfs_bmapi(
}
mval->br_state = XFS_EXT_NORM;
error = xfs_bmap_add_extent(ip, lastx, &cur, mval,
- firstblock, flist, &tmp_logflags, delta,
+ firstblock, flist, &tmp_logflags,
whichfork, (flags & XFS_BMAPI_RSVBLOCKS));
logflags |= tmp_logflags;
if (error)
@@ -5017,14 +4849,6 @@ xfs_bmapi(
ASSERT(XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_BTREE ||
XFS_IFORK_NEXTENTS(ip, whichfork) > ifp->if_ext_max);
error = 0;
- if (delta && delta->xed_startoff != NULLFILEOFF) {
- /* A change was actually made.
- * Note that delta->xed_blockount is an offset at this
- * point and needs to be converted to a block count.
- */
- ASSERT(delta->xed_blockcount > delta->xed_startoff);
- delta->xed_blockcount -= delta->xed_startoff;
- }
error0:
/*
* Log everything. Do this after conversion, there's no point in
@@ -5136,8 +4960,6 @@ xfs_bunmapi(
xfs_fsblock_t *firstblock, /* first allocated block
controls a.g. for allocs */
xfs_bmap_free_t *flist, /* i/o: list extents to free */
- xfs_extdelta_t *delta, /* o: change made to incore
- extents */
int *done) /* set if not done yet */
{
xfs_btree_cur_t *cur; /* bmap btree cursor */
@@ -5196,10 +5018,7 @@ xfs_bunmapi(
bno = start + len - 1;
ep = xfs_bmap_search_extents(ip, bno, whichfork, &eof, &lastx, &got,
&prev);
- if (delta) {
- delta->xed_startoff = NULLFILEOFF;
- delta->xed_blockcount = 0;
- }
+
/*
* Check to see if the given block number is past the end of the
* file, back up to the last block if so...
@@ -5297,7 +5116,7 @@ xfs_bunmapi(
}
del.br_state = XFS_EXT_UNWRITTEN;
error = xfs_bmap_add_extent(ip, lastx, &cur, &del,
- firstblock, flist, &logflags, delta,
+ firstblock, flist, &logflags,
XFS_DATA_FORK, 0);
if (error)
goto error0;
@@ -5352,7 +5171,7 @@ xfs_bunmapi(
prev.br_state = XFS_EXT_UNWRITTEN;
error = xfs_bmap_add_extent(ip, lastx - 1, &cur,
&prev, firstblock, flist, &logflags,
- delta, XFS_DATA_FORK, 0);
+ XFS_DATA_FORK, 0);
if (error)
goto error0;
goto nodelete;
@@ -5361,7 +5180,7 @@ xfs_bunmapi(
del.br_state = XFS_EXT_UNWRITTEN;
error = xfs_bmap_add_extent(ip, lastx, &cur,
&del, firstblock, flist, &logflags,
- delta, XFS_DATA_FORK, 0);
+ XFS_DATA_FORK, 0);
if (error)
goto error0;
goto nodelete;
@@ -5414,7 +5233,7 @@ xfs_bunmapi(
goto error0;
}
error = xfs_bmap_del_extent(ip, tp, lastx, flist, cur, &del,
- &tmp_logflags, delta, whichfork, rsvd);
+ &tmp_logflags, whichfork, rsvd);
logflags |= tmp_logflags;
if (error)
goto error0;
@@ -5471,14 +5290,6 @@ nodelete:
ASSERT(ifp->if_ext_max ==
XFS_IFORK_SIZE(ip, whichfork) / (uint)sizeof(xfs_bmbt_rec_t));
error = 0;
- if (delta && delta->xed_startoff != NULLFILEOFF) {
- /* A change was actually made.
- * Note that delta->xed_blockount is an offset at this
- * point and needs to be converted to a block count.
- */
- ASSERT(delta->xed_blockcount > delta->xed_startoff);
- delta->xed_blockcount -= delta->xed_startoff;
- }
error0:
/*
* Log everything. Do this after conversion, there's no point in
@@ -5605,28 +5416,6 @@ xfs_getbmap(
prealloced = 0;
fixlen = 1LL << 32;
} else {
- /*
- * If the BMV_IF_NO_DMAPI_READ interface bit specified, do
- * not generate a DMAPI read event. Otherwise, if the
- * DM_EVENT_READ bit is set for the file, generate a read
- * event in order that the DMAPI application may do its thing
- * before we return the extents. Usually this means restoring
- * user file data to regions of the file that look like holes.
- *
- * The "old behavior" (from XFS_IOC_GETBMAP) is to not specify
- * BMV_IF_NO_DMAPI_READ so that read events are generated.
- * If this were not true, callers of ioctl(XFS_IOC_GETBMAP)
- * could misinterpret holes in a DMAPI file as true holes,
- * when in fact they may represent offline user data.
- */
- if (DM_EVENT_ENABLED(ip, DM_EVENT_READ) &&
- !(iflags & BMV_IF_NO_DMAPI_READ)) {
- error = XFS_SEND_DATA(mp, DM_EVENT_READ, ip,
- 0, 0, 0, NULL);
- if (error)
- return XFS_ERROR(error);
- }
-
if (ip->i_d.di_format != XFS_DINODE_FMT_EXTENTS &&
ip->i_d.di_format != XFS_DINODE_FMT_BTREE &&
ip->i_d.di_format != XFS_DINODE_FMT_LOCAL)
@@ -5713,7 +5502,7 @@ xfs_getbmap(
error = xfs_bmapi(NULL, ip, XFS_BB_TO_FSBT(mp, bmv->bmv_offset),
XFS_BB_TO_FSB(mp, bmv->bmv_length),
bmapi_flags, NULL, 0, map, &nmap,
- NULL, NULL);
+ NULL);
if (error)
goto out_free_map;
ASSERT(nmap <= subnex);
@@ -5859,66 +5648,34 @@ xfs_bmap_eof(
}
#ifdef DEBUG
-STATIC
-xfs_buf_t *
+STATIC struct xfs_buf *
xfs_bmap_get_bp(
- xfs_btree_cur_t *cur,
+ struct xfs_btree_cur *cur,
xfs_fsblock_t bno)
{
- int i;
- xfs_buf_t *bp;
+ struct xfs_log_item_desc *lidp;
+ int i;
if (!cur)
- return(NULL);
-
- bp = NULL;
- for(i = 0; i < XFS_BTREE_MAXLEVELS; i++) {
- bp = cur->bc_bufs[i];
- if (!bp) break;
- if (XFS_BUF_ADDR(bp) == bno)
- break; /* Found it */
- }
- if (i == XFS_BTREE_MAXLEVELS)
- bp = NULL;
-
- if (!bp) { /* Chase down all the log items to see if the bp is there */
- xfs_log_item_chunk_t *licp;
- xfs_trans_t *tp;
-
- tp = cur->bc_tp;
- licp = &tp->t_items;
- while (!bp && licp != NULL) {
- if (xfs_lic_are_all_free(licp)) {
- licp = licp->lic_next;
- continue;
- }
- for (i = 0; i < licp->lic_unused; i++) {
- xfs_log_item_desc_t *lidp;
- xfs_log_item_t *lip;
- xfs_buf_log_item_t *bip;
- xfs_buf_t *lbp;
-
- if (xfs_lic_isfree(licp, i)) {
- continue;
- }
-
- lidp = xfs_lic_slot(licp, i);
- lip = lidp->lid_item;
- if (lip->li_type != XFS_LI_BUF)
- continue;
+ return NULL;
- bip = (xfs_buf_log_item_t *)lip;
- lbp = bip->bli_buf;
+ for (i = 0; i < XFS_BTREE_MAXLEVELS; i++) {
+ if (!cur->bc_bufs[i])
+ break;
+ if (XFS_BUF_ADDR(cur->bc_bufs[i]) == bno)
+ return cur->bc_bufs[i];
+ }
- if (XFS_BUF_ADDR(lbp) == bno) {
- bp = lbp;
- break; /* Found it */
- }
- }
- licp = licp->lic_next;
- }
+ /* Chase down all the log items to see if the bp is there */
+ list_for_each_entry(lidp, &cur->bc_tp->t_items, lid_trans) {
+ struct xfs_buf_log_item *bip;
+ bip = (struct xfs_buf_log_item *)lidp->lid_item;
+ if (bip->bli_item.li_type == XFS_LI_BUF &&
+ XFS_BUF_ADDR(bip->bli_buf) == bno)
+ return bip->bli_buf;
}
- return(bp);
+
+ return NULL;
}
STATIC void
diff --git a/fs/xfs/xfs_bmap.h b/fs/xfs/xfs_bmap.h
index 419dafb9d87..b13569a6179 100644
--- a/fs/xfs/xfs_bmap.h
+++ b/fs/xfs/xfs_bmap.h
@@ -28,20 +28,6 @@ struct xfs_trans;
extern kmem_zone_t *xfs_bmap_free_item_zone;
/*
- * DELTA: describe a change to the in-core extent list.
- *
- * Internally the use of xed_blockount is somewhat funky.
- * xed_blockcount contains an offset much of the time because this
- * makes merging changes easier. (xfs_fileoff_t and xfs_filblks_t are
- * the same underlying type).
- */
-typedef struct xfs_extdelta
-{
- xfs_fileoff_t xed_startoff; /* offset of range */
- xfs_filblks_t xed_blockcount; /* blocks in range */
-} xfs_extdelta_t;
-
-/*
* List of extents to be free "later".
* The list is kept sorted on xbf_startblock.
*/
@@ -82,16 +68,13 @@ typedef struct xfs_bmap_free
#define XFS_BMAPI_DELAY 0x002 /* delayed write operation */
#define XFS_BMAPI_ENTIRE 0x004 /* return entire extent, not trimmed */
#define XFS_BMAPI_METADATA 0x008 /* mapping metadata not user data */
-#define XFS_BMAPI_EXACT 0x010 /* allocate only to spec'd bounds */
-#define XFS_BMAPI_ATTRFORK 0x020 /* use attribute fork not data */
-#define XFS_BMAPI_ASYNC 0x040 /* bunmapi xactions can be async */
-#define XFS_BMAPI_RSVBLOCKS 0x080 /* OK to alloc. reserved data blocks */
-#define XFS_BMAPI_PREALLOC 0x100 /* preallocation op: unwritten space */
-#define XFS_BMAPI_IGSTATE 0x200 /* Ignore state - */
+#define XFS_BMAPI_ATTRFORK 0x010 /* use attribute fork not data */
+#define XFS_BMAPI_RSVBLOCKS 0x020 /* OK to alloc. reserved data blocks */
+#define XFS_BMAPI_PREALLOC 0x040 /* preallocation op: unwritten space */
+#define XFS_BMAPI_IGSTATE 0x080 /* Ignore state - */
/* combine contig. space */
-#define XFS_BMAPI_CONTIG 0x400 /* must allocate only one extent */
-/* XFS_BMAPI_DIRECT_IO 0x800 */
-#define XFS_BMAPI_CONVERT 0x1000 /* unwritten extent conversion - */
+#define XFS_BMAPI_CONTIG 0x100 /* must allocate only one extent */
+#define XFS_BMAPI_CONVERT 0x200 /* unwritten extent conversion - */
/* need write cache flushing and no */
/* additional allocation alignments */
@@ -100,9 +83,7 @@ typedef struct xfs_bmap_free
{ XFS_BMAPI_DELAY, "DELAY" }, \
{ XFS_BMAPI_ENTIRE, "ENTIRE" }, \
{ XFS_BMAPI_METADATA, "METADATA" }, \
- { XFS_BMAPI_EXACT, "EXACT" }, \
{ XFS_BMAPI_ATTRFORK, "ATTRFORK" }, \
- { XFS_BMAPI_ASYNC, "ASYNC" }, \
{ XFS_BMAPI_RSVBLOCKS, "RSVBLOCKS" }, \
{ XFS_BMAPI_PREALLOC, "PREALLOC" }, \
{ XFS_BMAPI_IGSTATE, "IGSTATE" }, \
@@ -310,9 +291,7 @@ xfs_bmapi(
xfs_extlen_t total, /* total blocks needed */
struct xfs_bmbt_irec *mval, /* output: map values */
int *nmap, /* i/o: mval size/count */
- xfs_bmap_free_t *flist, /* i/o: list extents to free */
- xfs_extdelta_t *delta); /* o: change made to incore
- extents */
+ xfs_bmap_free_t *flist); /* i/o: list extents to free */
/*
* Map file blocks to filesystem blocks, simple version.
@@ -346,8 +325,6 @@ xfs_bunmapi(
xfs_fsblock_t *firstblock, /* first allocated block
controls a.g. for allocs */
xfs_bmap_free_t *flist, /* i/o: list extents to free */
- xfs_extdelta_t *delta, /* o: change made to incore
- extents */
int *done); /* set if not done yet */
/*
diff --git a/fs/xfs/xfs_bmap_btree.c b/fs/xfs/xfs_bmap_btree.c
index 416e47e54b8..87d3c10b695 100644
--- a/fs/xfs/xfs_bmap_btree.c
+++ b/fs/xfs/xfs_bmap_btree.c
@@ -24,21 +24,16 @@
#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_alloc_btree.h"
#include "xfs_ialloc_btree.h"
-#include "xfs_dir2_sf.h"
-#include "xfs_attr_sf.h"
#include "xfs_dinode.h"
#include "xfs_inode.h"
#include "xfs_inode_item.h"
#include "xfs_alloc.h"
#include "xfs_btree.h"
#include "xfs_btree_trace.h"
-#include "xfs_ialloc.h"
#include "xfs_itable.h"
#include "xfs_bmap.h"
#include "xfs_error.h"
diff --git a/fs/xfs/xfs_btree.c b/fs/xfs/xfs_btree.c
index 96be4b0f249..829af92f0fb 100644
--- a/fs/xfs/xfs_btree.c
+++ b/fs/xfs/xfs_btree.c
@@ -24,20 +24,15 @@
#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_alloc_btree.h"
#include "xfs_ialloc_btree.h"
-#include "xfs_dir2_sf.h"
-#include "xfs_attr_sf.h"
#include "xfs_dinode.h"
#include "xfs_inode.h"
#include "xfs_inode_item.h"
#include "xfs_btree.h"
#include "xfs_btree_trace.h"
-#include "xfs_ialloc.h"
#include "xfs_error.h"
#include "xfs_trace.h"
diff --git a/fs/xfs/xfs_buf_item.c b/fs/xfs/xfs_buf_item.c
index 02a80984aa0..1b09d7a280d 100644
--- a/fs/xfs/xfs_buf_item.c
+++ b/fs/xfs/xfs_buf_item.c
@@ -24,7 +24,6 @@
#include "xfs_trans.h"
#include "xfs_sb.h"
#include "xfs_ag.h"
-#include "xfs_dmapi.h"
#include "xfs_mount.h"
#include "xfs_buf_item.h"
#include "xfs_trans_priv.h"
@@ -34,6 +33,12 @@
kmem_zone_t *xfs_buf_item_zone;
+static inline struct xfs_buf_log_item *BUF_ITEM(struct xfs_log_item *lip)
+{
+ return container_of(lip, struct xfs_buf_log_item, bli_item);
+}
+
+
#ifdef XFS_TRANS_DEBUG
/*
* This function uses an alternate strategy for tracking the bytes
@@ -151,12 +156,13 @@ STATIC void xfs_buf_do_callbacks(xfs_buf_t *bp, xfs_log_item_t *lip);
*/
STATIC uint
xfs_buf_item_size(
- xfs_buf_log_item_t *bip)
+ struct xfs_log_item *lip)
{
- uint nvecs;
- int next_bit;
- int last_bit;
- xfs_buf_t *bp;
+ struct xfs_buf_log_item *bip = BUF_ITEM(lip);
+ struct xfs_buf *bp = bip->bli_buf;
+ uint nvecs;
+ int next_bit;
+ int last_bit;
ASSERT(atomic_read(&bip->bli_refcount) > 0);
if (bip->bli_flags & XFS_BLI_STALE) {
@@ -170,7 +176,6 @@ xfs_buf_item_size(
return 1;
}
- bp = bip->bli_buf;
ASSERT(bip->bli_flags & XFS_BLI_LOGGED);
nvecs = 1;
last_bit = xfs_next_bit(bip->bli_format.blf_data_map,
@@ -219,13 +224,13 @@ xfs_buf_item_size(
*/
STATIC void
xfs_buf_item_format(
- xfs_buf_log_item_t *bip,
- xfs_log_iovec_t *log_vector)
+ struct xfs_log_item *lip,
+ struct xfs_log_iovec *vecp)
{
+ struct xfs_buf_log_item *bip = BUF_ITEM(lip);
+ struct xfs_buf *bp = bip->bli_buf;
uint base_size;
uint nvecs;
- xfs_log_iovec_t *vecp;
- xfs_buf_t *bp;
int first_bit;
int last_bit;
int next_bit;
@@ -235,8 +240,6 @@ xfs_buf_item_format(
ASSERT(atomic_read(&bip->bli_refcount) > 0);
ASSERT((bip->bli_flags & XFS_BLI_LOGGED) ||
(bip->bli_flags & XFS_BLI_STALE));
- bp = bip->bli_buf;
- vecp = log_vector;
/*
* The size of the base structure is the size of the
@@ -248,7 +251,7 @@ xfs_buf_item_format(
base_size =
(uint)(sizeof(xfs_buf_log_format_t) +
((bip->bli_format.blf_map_size - 1) * sizeof(uint)));
- vecp->i_addr = (xfs_caddr_t)&bip->bli_format;
+ vecp->i_addr = &bip->bli_format;
vecp->i_len = base_size;
vecp->i_type = XLOG_REG_TYPE_BFORMAT;
vecp++;
@@ -263,7 +266,7 @@ xfs_buf_item_format(
*/
if (bip->bli_flags & XFS_BLI_INODE_BUF) {
if (!((bip->bli_flags & XFS_BLI_INODE_ALLOC_BUF) &&
- xfs_log_item_in_current_chkpt(&bip->bli_item)))
+ xfs_log_item_in_current_chkpt(lip)))
bip->bli_format.blf_flags |= XFS_BLF_INODE_BUF;
bip->bli_flags &= ~XFS_BLI_INODE_BUF;
}
@@ -356,66 +359,90 @@ xfs_buf_item_format(
/*
* This is called to pin the buffer associated with the buf log item in memory
- * so it cannot be written out. Simply call bpin() on the buffer to do this.
+ * so it cannot be written out.
*
* We also always take a reference to the buffer log item here so that the bli
* is held while the item is pinned in memory. This means that we can
* unconditionally drop the reference count a transaction holds when the
* transaction is completed.
*/
-
STATIC void
xfs_buf_item_pin(
- xfs_buf_log_item_t *bip)
+ struct xfs_log_item *lip)
{
- xfs_buf_t *bp;
+ struct xfs_buf_log_item *bip = BUF_ITEM(lip);
- bp = bip->bli_buf;
- ASSERT(XFS_BUF_ISBUSY(bp));
+ ASSERT(XFS_BUF_ISBUSY(bip->bli_buf));
ASSERT(atomic_read(&bip->bli_refcount) > 0);
ASSERT((bip->bli_flags & XFS_BLI_LOGGED) ||
(bip->bli_flags & XFS_BLI_STALE));
- atomic_inc(&bip->bli_refcount);
+
trace_xfs_buf_item_pin(bip);
- xfs_bpin(bp);
-}
+ atomic_inc(&bip->bli_refcount);
+ atomic_inc(&bip->bli_buf->b_pin_count);
+}
/*
* This is called to unpin the buffer associated with the buf log
* item which was previously pinned with a call to xfs_buf_item_pin().
- * Just call bunpin() on the buffer to do this.
*
* Also drop the reference to the buf item for the current transaction.
* If the XFS_BLI_STALE flag is set and we are the last reference,
* then free up the buf log item and unlock the buffer.
+ *
+ * If the remove flag is set we are called from uncommit in the
+ * forced-shutdown path. If that is true and the reference count on
+ * the log item is going to drop to zero we need to free the item's
+ * descriptor in the transaction.
*/
STATIC void
xfs_buf_item_unpin(
- xfs_buf_log_item_t *bip)
+ struct xfs_log_item *lip,
+ int remove)
{
- struct xfs_ail *ailp;
- xfs_buf_t *bp;
- int freed;
+ struct xfs_buf_log_item *bip = BUF_ITEM(lip);
+ xfs_buf_t *bp = bip->bli_buf;
+ struct xfs_ail *ailp = lip->li_ailp;
int stale = bip->bli_flags & XFS_BLI_STALE;
+ int freed;
- bp = bip->bli_buf;
- ASSERT(bp != NULL);
ASSERT(XFS_BUF_FSPRIVATE(bp, xfs_buf_log_item_t *) == bip);
ASSERT(atomic_read(&bip->bli_refcount) > 0);
+
trace_xfs_buf_item_unpin(bip);
freed = atomic_dec_and_test(&bip->bli_refcount);
- ailp = bip->bli_item.li_ailp;
- xfs_bunpin(bp);
+
+ if (atomic_dec_and_test(&bp->b_pin_count))
+ wake_up_all(&bp->b_waiters);
+
if (freed && stale) {
ASSERT(bip->bli_flags & XFS_BLI_STALE);
ASSERT(XFS_BUF_VALUSEMA(bp) <= 0);
ASSERT(!(XFS_BUF_ISDELAYWRITE(bp)));
ASSERT(XFS_BUF_ISSTALE(bp));
ASSERT(bip->bli_format.blf_flags & XFS_BLF_CANCEL);
+
trace_xfs_buf_item_unpin_stale(bip);
+ if (remove) {
+ /*
+ * We have to remove the log item from the transaction
+ * as we are about to release our reference to the
+ * buffer. If we don't, the unlock that occurs later
+ * in xfs_trans_uncommit() will ry to reference the
+ * buffer which we no longer have a hold on.
+ */
+ xfs_trans_del_item(lip);
+
+ /*
+ * Since the transaction no longer refers to the buffer,
+ * the buffer should no longer refer to the transaction.
+ */
+ XFS_BUF_SET_FSPRIVATE2(bp, NULL);
+ }
+
/*
* If we get called here because of an IO error, we may
* or may not have the item on the AIL. xfs_trans_ail_delete()
@@ -437,48 +464,6 @@ xfs_buf_item_unpin(
}
/*
- * this is called from uncommit in the forced-shutdown path.
- * we need to check to see if the reference count on the log item
- * is going to drop to zero. If so, unpin will free the log item
- * so we need to free the item's descriptor (that points to the item)
- * in the transaction.
- */
-STATIC void
-xfs_buf_item_unpin_remove(
- xfs_buf_log_item_t *bip,
- xfs_trans_t *tp)
-{
- /* will xfs_buf_item_unpin() call xfs_buf_item_relse()? */
- if ((atomic_read(&bip->bli_refcount) == 1) &&
- (bip->bli_flags & XFS_BLI_STALE)) {
- /*
- * yes -- We can safely do some work here and then call
- * buf_item_unpin to do the rest because we are
- * are holding the buffer locked so no one else will be
- * able to bump up the refcount. We have to remove the
- * log item from the transaction as we are about to release
- * our reference to the buffer. If we don't, the unlock that
- * occurs later in the xfs_trans_uncommit() will try to
- * reference the buffer which we no longer have a hold on.
- */
- struct xfs_log_item_desc *lidp;
-
- ASSERT(XFS_BUF_VALUSEMA(bip->bli_buf) <= 0);
- trace_xfs_buf_item_unpin_stale(bip);
-
- lidp = xfs_trans_find_item(tp, (xfs_log_item_t *)bip);
- xfs_trans_free_item(tp, lidp);
-
- /*
- * Since the transaction no longer refers to the buffer, the
- * buffer should no longer refer to the transaction.
- */
- XFS_BUF_SET_FSPRIVATE2(bip->bli_buf, NULL);
- }
- xfs_buf_item_unpin(bip);
-}
-
-/*
* This is called to attempt to lock the buffer associated with this
* buf log item. Don't sleep on the buffer lock. If we can't get
* the lock right away, return 0. If we can get the lock, take a
@@ -488,11 +473,11 @@ xfs_buf_item_unpin_remove(
*/
STATIC uint
xfs_buf_item_trylock(
- xfs_buf_log_item_t *bip)
+ struct xfs_log_item *lip)
{
- xfs_buf_t *bp;
+ struct xfs_buf_log_item *bip = BUF_ITEM(lip);
+ struct xfs_buf *bp = bip->bli_buf;
- bp = bip->bli_buf;
if (XFS_BUF_ISPINNED(bp))
return XFS_ITEM_PINNED;
if (!XFS_BUF_CPSEMA(bp))
@@ -529,13 +514,12 @@ xfs_buf_item_trylock(
*/
STATIC void
xfs_buf_item_unlock(
- xfs_buf_log_item_t *bip)
+ struct xfs_log_item *lip)
{
- int aborted;
- xfs_buf_t *bp;
- uint hold;
-
- bp = bip->bli_buf;
+ struct xfs_buf_log_item *bip = BUF_ITEM(lip);
+ struct xfs_buf *bp = bip->bli_buf;
+ int aborted;
+ uint hold;
/* Clear the buffer's association with this transaction. */
XFS_BUF_SET_FSPRIVATE2(bp, NULL);
@@ -546,7 +530,7 @@ xfs_buf_item_unlock(
* (cancelled) buffers at unpin time, but we'll never go through the
* pin/unpin cycle if we abort inside commit.
*/
- aborted = (bip->bli_item.li_flags & XFS_LI_ABORTED) != 0;
+ aborted = (lip->li_flags & XFS_LI_ABORTED) != 0;
/*
* Before possibly freeing the buf item, determine if we should
@@ -607,16 +591,16 @@ xfs_buf_item_unlock(
*/
STATIC xfs_lsn_t
xfs_buf_item_committed(
- xfs_buf_log_item_t *bip,
+ struct xfs_log_item *lip,
xfs_lsn_t lsn)
{
+ struct xfs_buf_log_item *bip = BUF_ITEM(lip);
+
trace_xfs_buf_item_committed(bip);
- if ((bip->bli_flags & XFS_BLI_INODE_ALLOC_BUF) &&
- (bip->bli_item.li_lsn != 0)) {
- return bip->bli_item.li_lsn;
- }
- return (lsn);
+ if ((bip->bli_flags & XFS_BLI_INODE_ALLOC_BUF) && lip->li_lsn != 0)
+ return lip->li_lsn;
+ return lsn;
}
/*
@@ -626,15 +610,16 @@ xfs_buf_item_committed(
*/
STATIC void
xfs_buf_item_push(
- xfs_buf_log_item_t *bip)
+ struct xfs_log_item *lip)
{
- xfs_buf_t *bp;
+ struct xfs_buf_log_item *bip = BUF_ITEM(lip);
+ struct xfs_buf *bp = bip->bli_buf;
ASSERT(!(bip->bli_flags & XFS_BLI_STALE));
+ ASSERT(!XFS_BUF_ISDELAYWRITE(bp));
+
trace_xfs_buf_item_push(bip);
- bp = bip->bli_buf;
- ASSERT(!XFS_BUF_ISDELAYWRITE(bp));
xfs_buf_relse(bp);
}
@@ -646,22 +631,24 @@ xfs_buf_item_push(
*/
STATIC void
xfs_buf_item_pushbuf(
- xfs_buf_log_item_t *bip)
+ struct xfs_log_item *lip)
{
- xfs_buf_t *bp;
+ struct xfs_buf_log_item *bip = BUF_ITEM(lip);
+ struct xfs_buf *bp = bip->bli_buf;
ASSERT(!(bip->bli_flags & XFS_BLI_STALE));
+ ASSERT(XFS_BUF_ISDELAYWRITE(bp));
+
trace_xfs_buf_item_pushbuf(bip);
- bp = bip->bli_buf;
- ASSERT(XFS_BUF_ISDELAYWRITE(bp));
xfs_buf_delwri_promote(bp);
xfs_buf_relse(bp);
}
-/* ARGSUSED */
STATIC void
-xfs_buf_item_committing(xfs_buf_log_item_t *bip, xfs_lsn_t commit_lsn)
+xfs_buf_item_committing(
+ struct xfs_log_item *lip,
+ xfs_lsn_t commit_lsn)
{
}
@@ -669,21 +656,16 @@ xfs_buf_item_committing(xfs_buf_log_item_t *bip, xfs_lsn_t commit_lsn)
* This is the ops vector shared by all buf log items.
*/
static struct xfs_item_ops xfs_buf_item_ops = {
- .iop_size = (uint(*)(xfs_log_item_t*))xfs_buf_item_size,
- .iop_format = (void(*)(xfs_log_item_t*, xfs_log_iovec_t*))
- xfs_buf_item_format,
- .iop_pin = (void(*)(xfs_log_item_t*))xfs_buf_item_pin,
- .iop_unpin = (void(*)(xfs_log_item_t*))xfs_buf_item_unpin,
- .iop_unpin_remove = (void(*)(xfs_log_item_t*, xfs_trans_t *))
- xfs_buf_item_unpin_remove,
- .iop_trylock = (uint(*)(xfs_log_item_t*))xfs_buf_item_trylock,
- .iop_unlock = (void(*)(xfs_log_item_t*))xfs_buf_item_unlock,
- .iop_committed = (xfs_lsn_t(*)(xfs_log_item_t*, xfs_lsn_t))
- xfs_buf_item_committed,
- .iop_push = (void(*)(xfs_log_item_t*))xfs_buf_item_push,
- .iop_pushbuf = (void(*)(xfs_log_item_t*))xfs_buf_item_pushbuf,
- .iop_committing = (void(*)(xfs_log_item_t*, xfs_lsn_t))
- xfs_buf_item_committing
+ .iop_size = xfs_buf_item_size,
+ .iop_format = xfs_buf_item_format,
+ .iop_pin = xfs_buf_item_pin,
+ .iop_unpin = xfs_buf_item_unpin,
+ .iop_trylock = xfs_buf_item_trylock,
+ .iop_unlock = xfs_buf_item_unlock,
+ .iop_committed = xfs_buf_item_committed,
+ .iop_push = xfs_buf_item_push,
+ .iop_pushbuf = xfs_buf_item_pushbuf,
+ .iop_committing = xfs_buf_item_committing
};
@@ -712,7 +694,6 @@ xfs_buf_item_init(
*/
if (bp->b_mount != mp)
bp->b_mount = mp;
- XFS_BUF_SET_BDSTRAT_FUNC(bp, xfs_bdstrat_cb);
if (XFS_BUF_FSPRIVATE(bp, void *) != NULL) {
lip = XFS_BUF_FSPRIVATE(bp, xfs_log_item_t *);
if (lip->li_type == XFS_LI_BUF) {
@@ -1098,15 +1079,14 @@ xfs_buf_error_relse(
* It is called by xfs_buf_iodone_callbacks() above which will take
* care of cleaning up the buffer itself.
*/
-/* ARGSUSED */
void
xfs_buf_iodone(
- xfs_buf_t *bp,
- xfs_buf_log_item_t *bip)
+ struct xfs_buf *bp,
+ struct xfs_log_item *lip)
{
- struct xfs_ail *ailp = bip->bli_item.li_ailp;
+ struct xfs_ail *ailp = lip->li_ailp;
- ASSERT(bip->bli_buf == bp);
+ ASSERT(BUF_ITEM(lip)->bli_buf == bp);
xfs_buf_rele(bp);
@@ -1120,6 +1100,6 @@ xfs_buf_iodone(
* Either way, AIL is useless if we're forcing a shutdown.
*/
spin_lock(&ailp->xa_lock);
- xfs_trans_ail_delete(ailp, (xfs_log_item_t *)bip);
- xfs_buf_item_free(bip);
+ xfs_trans_ail_delete(ailp, lip);
+ xfs_buf_item_free(BUF_ITEM(lip));
}
diff --git a/fs/xfs/xfs_buf_item.h b/fs/xfs/xfs_buf_item.h
index f20bb472d58..0e2ed43f16c 100644
--- a/fs/xfs/xfs_buf_item.h
+++ b/fs/xfs/xfs_buf_item.h
@@ -124,7 +124,7 @@ void xfs_buf_attach_iodone(struct xfs_buf *,
void(*)(struct xfs_buf *, xfs_log_item_t *),
xfs_log_item_t *);
void xfs_buf_iodone_callbacks(struct xfs_buf *);
-void xfs_buf_iodone(struct xfs_buf *, xfs_buf_log_item_t *);
+void xfs_buf_iodone(struct xfs_buf *, struct xfs_log_item *);
#ifdef XFS_TRANS_DEBUG
void
diff --git a/fs/xfs/xfs_da_btree.c b/fs/xfs/xfs_da_btree.c
index 0ca556b4bf3..30fa0e206fb 100644
--- a/fs/xfs/xfs_da_btree.c
+++ b/fs/xfs/xfs_da_btree.c
@@ -25,19 +25,14 @@
#include "xfs_sb.h"
#include "xfs_ag.h"
#include "xfs_dir2.h"
-#include "xfs_dmapi.h"
#include "xfs_mount.h"
#include "xfs_da_btree.h"
#include "xfs_bmap_btree.h"
-#include "xfs_alloc_btree.h"
-#include "xfs_ialloc_btree.h"
#include "xfs_dir2_sf.h"
-#include "xfs_attr_sf.h"
#include "xfs_dinode.h"
#include "xfs_inode.h"
#include "xfs_inode_item.h"
#include "xfs_alloc.h"
-#include "xfs_btree.h"
#include "xfs_bmap.h"
#include "xfs_attr.h"
#include "xfs_attr_leaf.h"
@@ -581,16 +576,14 @@ xfs_da_node_add(xfs_da_state_t *state, xfs_da_state_blk_t *oldblk,
xfs_da_intnode_t *node;
xfs_da_node_entry_t *btree;
int tmp;
- xfs_mount_t *mp;
node = oldblk->bp->data;
- mp = state->mp;
ASSERT(be16_to_cpu(node->hdr.info.magic) == XFS_DA_NODE_MAGIC);
ASSERT((oldblk->index >= 0) && (oldblk->index <= be16_to_cpu(node->hdr.count)));
ASSERT(newblk->blkno != 0);
if (state->args->whichfork == XFS_DATA_FORK)
- ASSERT(newblk->blkno >= mp->m_dirleafblk &&
- newblk->blkno < mp->m_dirfreeblk);
+ ASSERT(newblk->blkno >= state->mp->m_dirleafblk &&
+ newblk->blkno < state->mp->m_dirfreeblk);
/*
* We may need to make some room before we insert the new node.
@@ -1601,7 +1594,7 @@ xfs_da_grow_inode(xfs_da_args_t *args, xfs_dablk_t *new_blkno)
xfs_bmapi_aflag(w)|XFS_BMAPI_WRITE|XFS_BMAPI_METADATA|
XFS_BMAPI_CONTIG,
args->firstblock, args->total, &map, &nmap,
- args->flist, NULL))) {
+ args->flist))) {
return error;
}
ASSERT(nmap <= 1);
@@ -1622,8 +1615,7 @@ xfs_da_grow_inode(xfs_da_args_t *args, xfs_dablk_t *new_blkno)
xfs_bmapi_aflag(w)|XFS_BMAPI_WRITE|
XFS_BMAPI_METADATA,
args->firstblock, args->total,
- &mapp[mapi], &nmap, args->flist,
- NULL))) {
+ &mapp[mapi], &nmap, args->flist))) {
kmem_free(mapp);
return error;
}
@@ -1884,7 +1876,7 @@ xfs_da_shrink_inode(xfs_da_args_t *args, xfs_dablk_t dead_blkno,
*/
if ((error = xfs_bunmapi(tp, dp, dead_blkno, count,
xfs_bmapi_aflag(w)|XFS_BMAPI_METADATA,
- 0, args->firstblock, args->flist, NULL,
+ 0, args->firstblock, args->flist,
&done)) == ENOSPC) {
if (w != XFS_DATA_FORK)
break;
@@ -1989,7 +1981,7 @@ xfs_da_do_buf(
nfsb,
XFS_BMAPI_METADATA |
xfs_bmapi_aflag(whichfork),
- NULL, 0, mapp, &nmap, NULL, NULL)))
+ NULL, 0, mapp, &nmap, NULL)))
goto exit0;
}
} else {
diff --git a/fs/xfs/xfs_dfrag.c b/fs/xfs/xfs_dfrag.c
index 7f159d2a429..3b9582c60a2 100644
--- a/fs/xfs/xfs_dfrag.c
+++ b/fs/xfs/xfs_dfrag.c
@@ -24,24 +24,15 @@
#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_alloc_btree.h"
-#include "xfs_ialloc_btree.h"
-#include "xfs_dir2_sf.h"
-#include "xfs_attr_sf.h"
#include "xfs_dinode.h"
#include "xfs_inode.h"
#include "xfs_inode_item.h"
#include "xfs_bmap.h"
-#include "xfs_btree.h"
-#include "xfs_ialloc.h"
#include "xfs_itable.h"
#include "xfs_dfrag.h"
#include "xfs_error.h"
-#include "xfs_rw.h"
#include "xfs_vnodeops.h"
#include "xfs_trace.h"
@@ -425,11 +416,8 @@ xfs_swap_extents(
}
- IHOLD(ip);
- xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL);
-
- IHOLD(tip);
- xfs_trans_ijoin(tp, tip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL);
+ xfs_trans_ijoin_ref(tp, ip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL);
+ xfs_trans_ijoin_ref(tp, tip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL);
xfs_trans_log_inode(tp, ip, ilf_fields);
xfs_trans_log_inode(tp, tip, tilf_fields);
diff --git a/fs/xfs/xfs_dir2.c b/fs/xfs/xfs_dir2.c
index 42520f04126..a1321bc7f19 100644
--- a/fs/xfs/xfs_dir2.c
+++ b/fs/xfs/xfs_dir2.c
@@ -25,13 +25,11 @@
#include "xfs_sb.h"
#include "xfs_ag.h"
#include "xfs_dir2.h"
-#include "xfs_dmapi.h"
#include "xfs_mount.h"
#include "xfs_da_btree.h"
#include "xfs_bmap_btree.h"
#include "xfs_alloc_btree.h"
#include "xfs_dir2_sf.h"
-#include "xfs_attr_sf.h"
#include "xfs_dinode.h"
#include "xfs_inode.h"
#include "xfs_inode_item.h"
@@ -382,7 +380,7 @@ xfs_readdir(
int rval; /* return value */
int v; /* type-checking value */
- xfs_itrace_entry(dp);
+ trace_xfs_readdir(dp);
if (XFS_FORCED_SHUTDOWN(dp->i_mount))
return XFS_ERROR(EIO);
@@ -549,7 +547,7 @@ xfs_dir2_grow_inode(
if ((error = xfs_bmapi(tp, dp, bno, count,
XFS_BMAPI_WRITE|XFS_BMAPI_METADATA|XFS_BMAPI_CONTIG,
args->firstblock, args->total, &map, &nmap,
- args->flist, NULL)))
+ args->flist)))
return error;
ASSERT(nmap <= 1);
if (nmap == 1) {
@@ -581,8 +579,7 @@ xfs_dir2_grow_inode(
if ((error = xfs_bmapi(tp, dp, b, c,
XFS_BMAPI_WRITE|XFS_BMAPI_METADATA,
args->firstblock, args->total,
- &mapp[mapi], &nmap, args->flist,
- NULL))) {
+ &mapp[mapi], &nmap, args->flist))) {
kmem_free(mapp);
return error;
}
@@ -715,7 +712,7 @@ xfs_dir2_shrink_inode(
*/
if ((error = xfs_bunmapi(tp, dp, da, mp->m_dirblkfsbs,
XFS_BMAPI_METADATA, 0, args->firstblock, args->flist,
- NULL, &done))) {
+ &done))) {
/*
* ENOSPC actually can happen if we're in a removename with
* no space reservation, and the resulting block removal
diff --git a/fs/xfs/xfs_dir2_block.c b/fs/xfs/xfs_dir2_block.c
index 779a267b0a8..580d99cef9e 100644
--- a/fs/xfs/xfs_dir2_block.c
+++ b/fs/xfs/xfs_dir2_block.c
@@ -24,12 +24,10 @@
#include "xfs_sb.h"
#include "xfs_ag.h"
#include "xfs_dir2.h"
-#include "xfs_dmapi.h"
#include "xfs_mount.h"
#include "xfs_da_btree.h"
#include "xfs_bmap_btree.h"
#include "xfs_dir2_sf.h"
-#include "xfs_attr_sf.h"
#include "xfs_dinode.h"
#include "xfs_inode.h"
#include "xfs_inode_item.h"
@@ -1073,10 +1071,10 @@ xfs_dir2_sf_to_block(
*/
buf_len = dp->i_df.if_bytes;
- buf = kmem_alloc(dp->i_df.if_bytes, KM_SLEEP);
+ buf = kmem_alloc(buf_len, KM_SLEEP);
- memcpy(buf, sfp, dp->i_df.if_bytes);
- xfs_idata_realloc(dp, -dp->i_df.if_bytes, XFS_DATA_FORK);
+ memcpy(buf, sfp, buf_len);
+ xfs_idata_realloc(dp, -buf_len, XFS_DATA_FORK);
dp->i_d.di_size = 0;
xfs_trans_log_inode(tp, dp, XFS_ILOG_CORE);
/*
diff --git a/fs/xfs/xfs_dir2_data.c b/fs/xfs/xfs_dir2_data.c
index 498f8d69433..921595b84f5 100644
--- a/fs/xfs/xfs_dir2_data.c
+++ b/fs/xfs/xfs_dir2_data.c
@@ -24,12 +24,10 @@
#include "xfs_sb.h"
#include "xfs_ag.h"
#include "xfs_dir2.h"
-#include "xfs_dmapi.h"
#include "xfs_mount.h"
#include "xfs_da_btree.h"
#include "xfs_bmap_btree.h"
#include "xfs_dir2_sf.h"
-#include "xfs_attr_sf.h"
#include "xfs_dinode.h"
#include "xfs_inode.h"
#include "xfs_dir2_data.h"
diff --git a/fs/xfs/xfs_dir2_leaf.c b/fs/xfs/xfs_dir2_leaf.c
index e2d89854ec9..504be8640e9 100644
--- a/fs/xfs/xfs_dir2_leaf.c
+++ b/fs/xfs/xfs_dir2_leaf.c
@@ -25,11 +25,9 @@
#include "xfs_sb.h"
#include "xfs_ag.h"
#include "xfs_dir2.h"
-#include "xfs_dmapi.h"
#include "xfs_mount.h"
#include "xfs_da_btree.h"
#include "xfs_bmap_btree.h"
-#include "xfs_attr_sf.h"
#include "xfs_dir2_sf.h"
#include "xfs_dinode.h"
#include "xfs_inode.h"
@@ -875,7 +873,7 @@ xfs_dir2_leaf_getdents(
xfs_dir2_byte_to_da(mp,
XFS_DIR2_LEAF_OFFSET) - map_off,
XFS_BMAPI_METADATA, NULL, 0,
- &map[map_valid], &nmap, NULL, NULL);
+ &map[map_valid], &nmap, NULL);
/*
* Don't know if we should ignore this or
* try to return an error.
diff --git a/fs/xfs/xfs_dir2_node.c b/fs/xfs/xfs_dir2_node.c
index 78fc4d9ae75..f9a0864b696 100644
--- a/fs/xfs/xfs_dir2_node.c
+++ b/fs/xfs/xfs_dir2_node.c
@@ -24,12 +24,10 @@
#include "xfs_sb.h"
#include "xfs_ag.h"
#include "xfs_dir2.h"
-#include "xfs_dmapi.h"
#include "xfs_mount.h"
#include "xfs_da_btree.h"
#include "xfs_bmap_btree.h"
#include "xfs_dir2_sf.h"
-#include "xfs_attr_sf.h"
#include "xfs_dinode.h"
#include "xfs_inode.h"
#include "xfs_bmap.h"
diff --git a/fs/xfs/xfs_dir2_sf.c b/fs/xfs/xfs_dir2_sf.c
index c1a5945d463..b1bae6b1eed 100644
--- a/fs/xfs/xfs_dir2_sf.c
+++ b/fs/xfs/xfs_dir2_sf.c
@@ -24,12 +24,10 @@
#include "xfs_sb.h"
#include "xfs_ag.h"
#include "xfs_dir2.h"
-#include "xfs_dmapi.h"
#include "xfs_mount.h"
#include "xfs_da_btree.h"
#include "xfs_bmap_btree.h"
#include "xfs_dir2_sf.h"
-#include "xfs_attr_sf.h"
#include "xfs_dinode.h"
#include "xfs_inode.h"
#include "xfs_inode_item.h"
diff --git a/fs/xfs/xfs_dmapi.h b/fs/xfs/xfs_dmapi.h
deleted file mode 100644
index 2813cdd7237..00000000000
--- a/fs/xfs/xfs_dmapi.h
+++ /dev/null
@@ -1,170 +0,0 @@
-/*
- * Copyright (c) 2000-2005 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_DMAPI_H__
-#define __XFS_DMAPI_H__
-
-/* Values used to define the on-disk version of dm_attrname_t. All
- * on-disk attribute names start with the 8-byte string "SGI_DMI_".
- *
- * In the on-disk inode, DMAPI attribute names consist of the user-provided
- * name with the DMATTR_PREFIXSTRING pre-pended. This string must NEVER be
- * changed.
- */
-
-#define DMATTR_PREFIXLEN 8
-#define DMATTR_PREFIXSTRING "SGI_DMI_"
-
-typedef enum {
- DM_EVENT_INVALID = -1,
- DM_EVENT_CANCEL = 0, /* not supported */
- DM_EVENT_MOUNT = 1,
- DM_EVENT_PREUNMOUNT = 2,
- DM_EVENT_UNMOUNT = 3,
- DM_EVENT_DEBUT = 4, /* not supported */
- DM_EVENT_CREATE = 5,
- DM_EVENT_CLOSE = 6, /* not supported */
- DM_EVENT_POSTCREATE = 7,
- DM_EVENT_REMOVE = 8,
- DM_EVENT_POSTREMOVE = 9,
- DM_EVENT_RENAME = 10,
- DM_EVENT_POSTRENAME = 11,
- DM_EVENT_LINK = 12,
- DM_EVENT_POSTLINK = 13,
- DM_EVENT_SYMLINK = 14,
- DM_EVENT_POSTSYMLINK = 15,
- DM_EVENT_READ = 16,
- DM_EVENT_WRITE = 17,
- DM_EVENT_TRUNCATE = 18,
- DM_EVENT_ATTRIBUTE = 19,
- DM_EVENT_DESTROY = 20,
- DM_EVENT_NOSPACE = 21,
- DM_EVENT_USER = 22,
- DM_EVENT_MAX = 23
-} dm_eventtype_t;
-#define HAVE_DM_EVENTTYPE_T
-
-typedef enum {
- DM_RIGHT_NULL,
- DM_RIGHT_SHARED,
- DM_RIGHT_EXCL
-} dm_right_t;
-#define HAVE_DM_RIGHT_T
-
-/* Defines for determining if an event message should be sent. */
-#ifdef HAVE_DMAPI
-#define DM_EVENT_ENABLED(ip, event) ( \
- unlikely ((ip)->i_mount->m_flags & XFS_MOUNT_DMAPI) && \
- ( ((ip)->i_d.di_dmevmask & (1 << event)) || \
- ((ip)->i_mount->m_dmevmask & (1 << event)) ) \
- )
-#else
-#define DM_EVENT_ENABLED(ip, event) (0)
-#endif
-
-#define DM_XFS_VALID_FS_EVENTS ( \
- (1 << DM_EVENT_PREUNMOUNT) | \
- (1 << DM_EVENT_UNMOUNT) | \
- (1 << DM_EVENT_NOSPACE) | \
- (1 << DM_EVENT_DEBUT) | \
- (1 << DM_EVENT_CREATE) | \
- (1 << DM_EVENT_POSTCREATE) | \
- (1 << DM_EVENT_REMOVE) | \
- (1 << DM_EVENT_POSTREMOVE) | \
- (1 << DM_EVENT_RENAME) | \
- (1 << DM_EVENT_POSTRENAME) | \
- (1 << DM_EVENT_LINK) | \
- (1 << DM_EVENT_POSTLINK) | \
- (1 << DM_EVENT_SYMLINK) | \
- (1 << DM_EVENT_POSTSYMLINK) | \
- (1 << DM_EVENT_ATTRIBUTE) | \
- (1 << DM_EVENT_DESTROY) )
-
-/* Events valid in dm_set_eventlist() when called with a file handle for
- a regular file or a symlink. These events are persistent.
-*/
-
-#define DM_XFS_VALID_FILE_EVENTS ( \
- (1 << DM_EVENT_ATTRIBUTE) | \
- (1 << DM_EVENT_DESTROY) )
-
-/* Events valid in dm_set_eventlist() when called with a file handle for
- a directory. These events are persistent.
-*/
-
-#define DM_XFS_VALID_DIRECTORY_EVENTS ( \
- (1 << DM_EVENT_CREATE) | \
- (1 << DM_EVENT_POSTCREATE) | \
- (1 << DM_EVENT_REMOVE) | \
- (1 << DM_EVENT_POSTREMOVE) | \
- (1 << DM_EVENT_RENAME) | \
- (1 << DM_EVENT_POSTRENAME) | \
- (1 << DM_EVENT_LINK) | \
- (1 << DM_EVENT_POSTLINK) | \
- (1 << DM_EVENT_SYMLINK) | \
- (1 << DM_EVENT_POSTSYMLINK) | \
- (1 << DM_EVENT_ATTRIBUTE) | \
- (1 << DM_EVENT_DESTROY) )
-
-/* Events supported by the XFS filesystem. */
-#define DM_XFS_SUPPORTED_EVENTS ( \
- (1 << DM_EVENT_MOUNT) | \
- (1 << DM_EVENT_PREUNMOUNT) | \
- (1 << DM_EVENT_UNMOUNT) | \
- (1 << DM_EVENT_NOSPACE) | \
- (1 << DM_EVENT_CREATE) | \
- (1 << DM_EVENT_POSTCREATE) | \
- (1 << DM_EVENT_REMOVE) | \
- (1 << DM_EVENT_POSTREMOVE) | \
- (1 << DM_EVENT_RENAME) | \
- (1 << DM_EVENT_POSTRENAME) | \
- (1 << DM_EVENT_LINK) | \
- (1 << DM_EVENT_POSTLINK) | \
- (1 << DM_EVENT_SYMLINK) | \
- (1 << DM_EVENT_POSTSYMLINK) | \
- (1 << DM_EVENT_READ) | \
- (1 << DM_EVENT_WRITE) | \
- (1 << DM_EVENT_TRUNCATE) | \
- (1 << DM_EVENT_ATTRIBUTE) | \
- (1 << DM_EVENT_DESTROY) )
-
-
-/*
- * Definitions used for the flags field on dm_send_*_event().
- */
-
-#define DM_FLAGS_NDELAY 0x001 /* return EAGAIN after dm_pending() */
-#define DM_FLAGS_UNWANTED 0x002 /* event not in fsys dm_eventset_t */
-#define DM_FLAGS_IMUX 0x004 /* thread holds i_mutex */
-#define DM_FLAGS_IALLOCSEM_RD 0x010 /* thread holds i_alloc_sem rd */
-#define DM_FLAGS_IALLOCSEM_WR 0x020 /* thread holds i_alloc_sem wr */
-
-/*
- * Pull in platform specific event flags defines
- */
-#include "xfs_dmapi_priv.h"
-
-/*
- * Macros to turn caller specified delay/block flags into
- * dm_send_xxxx_event flag DM_FLAGS_NDELAY.
- */
-
-#define FILP_DELAY_FLAG(filp) ((filp->f_flags&(O_NDELAY|O_NONBLOCK)) ? \
- DM_FLAGS_NDELAY : 0)
-#define AT_DELAY_FLAG(f) ((f & XFS_ATTR_NONBLOCK) ? DM_FLAGS_NDELAY : 0)
-
-#endif /* __XFS_DMAPI_H__ */
diff --git a/fs/xfs/xfs_dmops.c b/fs/xfs/xfs_dmops.c
deleted file mode 100644
index e71e2581c0c..00000000000
--- a/fs/xfs/xfs_dmops.c
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright (c) 2000-2003,2005 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_fs.h"
-#include "xfs_types.h"
-#include "xfs_log.h"
-#include "xfs_trans.h"
-#include "xfs_sb.h"
-#include "xfs_dmapi.h"
-#include "xfs_inum.h"
-#include "xfs_ag.h"
-#include "xfs_mount.h"
-
-
-static struct xfs_dmops xfs_dmcore_stub = {
- .xfs_send_data = (xfs_send_data_t)fs_nosys,
- .xfs_send_mmap = (xfs_send_mmap_t)fs_noerr,
- .xfs_send_destroy = (xfs_send_destroy_t)fs_nosys,
- .xfs_send_namesp = (xfs_send_namesp_t)fs_nosys,
- .xfs_send_mount = (xfs_send_mount_t)fs_nosys,
- .xfs_send_unmount = (xfs_send_unmount_t)fs_noerr,
-};
-
-int
-xfs_dmops_get(struct xfs_mount *mp)
-{
- if (mp->m_flags & XFS_MOUNT_DMAPI) {
- cmn_err(CE_WARN,
- "XFS: dmapi support not available in this kernel.");
- return EINVAL;
- }
-
- mp->m_dm_ops = &xfs_dmcore_stub;
- return 0;
-}
-
-void
-xfs_dmops_put(struct xfs_mount *mp)
-{
-}
diff --git a/fs/xfs/xfs_error.c b/fs/xfs/xfs_error.c
index 047b8a8e5c2..ed999026766 100644
--- a/fs/xfs/xfs_error.c
+++ b/fs/xfs/xfs_error.c
@@ -23,12 +23,8 @@
#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_dir2_sf.h"
-#include "xfs_attr_sf.h"
#include "xfs_dinode.h"
#include "xfs_inode.h"
#include "xfs_utils.h"
diff --git a/fs/xfs/xfs_extfree_item.c b/fs/xfs/xfs_extfree_item.c
index 409fe81585f..a55e687bf56 100644
--- a/fs/xfs/xfs_extfree_item.c
+++ b/fs/xfs/xfs_extfree_item.c
@@ -24,7 +24,6 @@
#include "xfs_buf_item.h"
#include "xfs_sb.h"
#include "xfs_ag.h"
-#include "xfs_dmapi.h"
#include "xfs_mount.h"
#include "xfs_trans_priv.h"
#include "xfs_extfree_item.h"
@@ -33,18 +32,19 @@
kmem_zone_t *xfs_efi_zone;
kmem_zone_t *xfs_efd_zone;
-STATIC void xfs_efi_item_unlock(xfs_efi_log_item_t *);
+static inline struct xfs_efi_log_item *EFI_ITEM(struct xfs_log_item *lip)
+{
+ return container_of(lip, struct xfs_efi_log_item, efi_item);
+}
void
-xfs_efi_item_free(xfs_efi_log_item_t *efip)
+xfs_efi_item_free(
+ struct xfs_efi_log_item *efip)
{
- int nexts = efip->efi_format.efi_nextents;
-
- if (nexts > XFS_EFI_MAX_FAST_EXTENTS) {
+ if (efip->efi_format.efi_nextents > XFS_EFI_MAX_FAST_EXTENTS)
kmem_free(efip);
- } else {
+ else
kmem_zone_free(xfs_efi_zone, efip);
- }
}
/*
@@ -52,9 +52,9 @@ xfs_efi_item_free(xfs_efi_log_item_t *efip)
* We only need 1 iovec for an efi item. It just logs the efi_log_format
* structure.
*/
-/*ARGSUSED*/
STATIC uint
-xfs_efi_item_size(xfs_efi_log_item_t *efip)
+xfs_efi_item_size(
+ struct xfs_log_item *lip)
{
return 1;
}
@@ -67,10 +67,12 @@ xfs_efi_item_size(xfs_efi_log_item_t *efip)
* slots in the efi item have been filled.
*/
STATIC void
-xfs_efi_item_format(xfs_efi_log_item_t *efip,
- xfs_log_iovec_t *log_vector)
+xfs_efi_item_format(
+ struct xfs_log_item *lip,
+ struct xfs_log_iovec *log_vector)
{
- uint size;
+ struct xfs_efi_log_item *efip = EFI_ITEM(lip);
+ uint size;
ASSERT(efip->efi_next_extent == efip->efi_format.efi_nextents);
@@ -80,7 +82,7 @@ xfs_efi_item_format(xfs_efi_log_item_t *efip,
size += (efip->efi_format.efi_nextents - 1) * sizeof(xfs_extent_t);
efip->efi_format.efi_size = 1;
- log_vector->i_addr = (xfs_caddr_t)&(efip->efi_format);
+ log_vector->i_addr = &efip->efi_format;
log_vector->i_len = size;
log_vector->i_type = XLOG_REG_TYPE_EFI_FORMAT;
ASSERT(size >= sizeof(xfs_efi_log_format_t));
@@ -90,60 +92,33 @@ xfs_efi_item_format(xfs_efi_log_item_t *efip,
/*
* Pinning has no meaning for an efi item, so just return.
*/
-/*ARGSUSED*/
STATIC void
-xfs_efi_item_pin(xfs_efi_log_item_t *efip)
+xfs_efi_item_pin(
+ struct xfs_log_item *lip)
{
- return;
}
-
/*
* While EFIs cannot really be pinned, the unpin operation is the
* last place at which the EFI is manipulated during a transaction.
* Here we coordinate with xfs_efi_cancel() to determine who gets to
* free the EFI.
*/
-/*ARGSUSED*/
-STATIC void
-xfs_efi_item_unpin(xfs_efi_log_item_t *efip)
-{
- struct xfs_ail *ailp = efip->efi_item.li_ailp;
-
- spin_lock(&ailp->xa_lock);
- if (efip->efi_flags & XFS_EFI_CANCELED) {
- /* xfs_trans_ail_delete() drops the AIL lock. */
- xfs_trans_ail_delete(ailp, (xfs_log_item_t *)efip);
- xfs_efi_item_free(efip);
- } else {
- efip->efi_flags |= XFS_EFI_COMMITTED;
- spin_unlock(&ailp->xa_lock);
- }
-}
-
-/*
- * like unpin only we have to also clear the xaction descriptor
- * pointing the log item if we free the item. This routine duplicates
- * unpin because efi_flags is protected by the AIL lock. Freeing
- * the descriptor and then calling unpin would force us to drop the AIL
- * lock which would open up a race condition.
- */
STATIC void
-xfs_efi_item_unpin_remove(xfs_efi_log_item_t *efip, xfs_trans_t *tp)
+xfs_efi_item_unpin(
+ struct xfs_log_item *lip,
+ int remove)
{
- struct xfs_ail *ailp = efip->efi_item.li_ailp;
- xfs_log_item_desc_t *lidp;
+ struct xfs_efi_log_item *efip = EFI_ITEM(lip);
+ struct xfs_ail *ailp = lip->li_ailp;
spin_lock(&ailp->xa_lock);
if (efip->efi_flags & XFS_EFI_CANCELED) {
- /*
- * free the xaction descriptor pointing to this item
- */
- lidp = xfs_trans_find_item(tp, (xfs_log_item_t *) efip);
- xfs_trans_free_item(tp, lidp);
+ if (remove)
+ xfs_trans_del_item(lip);
/* xfs_trans_ail_delete() drops the AIL lock. */
- xfs_trans_ail_delete(ailp, (xfs_log_item_t *)efip);
+ xfs_trans_ail_delete(ailp, lip);
xfs_efi_item_free(efip);
} else {
efip->efi_flags |= XFS_EFI_COMMITTED;
@@ -158,9 +133,9 @@ xfs_efi_item_unpin_remove(xfs_efi_log_item_t *efip, xfs_trans_t *tp)
* XFS_ITEM_PINNED so that the caller will eventually flush the log.
* This should help in getting the EFI out of the AIL.
*/
-/*ARGSUSED*/
STATIC uint
-xfs_efi_item_trylock(xfs_efi_log_item_t *efip)
+xfs_efi_item_trylock(
+ struct xfs_log_item *lip)
{
return XFS_ITEM_PINNED;
}
@@ -168,13 +143,12 @@ xfs_efi_item_trylock(xfs_efi_log_item_t *efip)
/*
* Efi items have no locking, so just return.
*/
-/*ARGSUSED*/
STATIC void
-xfs_efi_item_unlock(xfs_efi_log_item_t *efip)
+xfs_efi_item_unlock(
+ struct xfs_log_item *lip)
{
- if (efip->efi_item.li_flags & XFS_LI_ABORTED)
- xfs_efi_item_free(efip);
- return;
+ if (lip->li_flags & XFS_LI_ABORTED)
+ xfs_efi_item_free(EFI_ITEM(lip));
}
/*
@@ -183,9 +157,10 @@ xfs_efi_item_unlock(xfs_efi_log_item_t *efip)
* flag is not paid any attention here. Checking for that is delayed
* until the EFI is unpinned.
*/
-/*ARGSUSED*/
STATIC xfs_lsn_t
-xfs_efi_item_committed(xfs_efi_log_item_t *efip, xfs_lsn_t lsn)
+xfs_efi_item_committed(
+ struct xfs_log_item *lip,
+ xfs_lsn_t lsn)
{
return lsn;
}
@@ -195,11 +170,10 @@ xfs_efi_item_committed(xfs_efi_log_item_t *efip, xfs_lsn_t lsn)
* stuck waiting for all of its corresponding efd items to be
* committed to disk.
*/
-/*ARGSUSED*/
STATIC void
-xfs_efi_item_push(xfs_efi_log_item_t *efip)
+xfs_efi_item_push(
+ struct xfs_log_item *lip)
{
- return;
}
/*
@@ -209,61 +183,55 @@ xfs_efi_item_push(xfs_efi_log_item_t *efip)
* example, for inodes, the inode is locked throughout the extent freeing
* so the dependency should be recorded there.
*/
-/*ARGSUSED*/
STATIC void
-xfs_efi_item_committing(xfs_efi_log_item_t *efip, xfs_lsn_t lsn)
+xfs_efi_item_committing(
+ struct xfs_log_item *lip,
+ xfs_lsn_t lsn)
{
- return;
}
/*
* This is the ops vector shared by all efi log items.
*/
static struct xfs_item_ops xfs_efi_item_ops = {
- .iop_size = (uint(*)(xfs_log_item_t*))xfs_efi_item_size,
- .iop_format = (void(*)(xfs_log_item_t*, xfs_log_iovec_t*))
- xfs_efi_item_format,
- .iop_pin = (void(*)(xfs_log_item_t*))xfs_efi_item_pin,
- .iop_unpin = (void(*)(xfs_log_item_t*))xfs_efi_item_unpin,
- .iop_unpin_remove = (void(*)(xfs_log_item_t*, xfs_trans_t *))
- xfs_efi_item_unpin_remove,
- .iop_trylock = (uint(*)(xfs_log_item_t*))xfs_efi_item_trylock,
- .iop_unlock = (void(*)(xfs_log_item_t*))xfs_efi_item_unlock,
- .iop_committed = (xfs_lsn_t(*)(xfs_log_item_t*, xfs_lsn_t))
- xfs_efi_item_committed,
- .iop_push = (void(*)(xfs_log_item_t*))xfs_efi_item_push,
- .iop_pushbuf = NULL,
- .iop_committing = (void(*)(xfs_log_item_t*, xfs_lsn_t))
- xfs_efi_item_committing
+ .iop_size = xfs_efi_item_size,
+ .iop_format = xfs_efi_item_format,
+ .iop_pin = xfs_efi_item_pin,
+ .iop_unpin = xfs_efi_item_unpin,
+ .iop_trylock = xfs_efi_item_trylock,
+ .iop_unlock = xfs_efi_item_unlock,
+ .iop_committed = xfs_efi_item_committed,
+ .iop_push = xfs_efi_item_push,
+ .iop_committing = xfs_efi_item_committing
};
/*
* Allocate and initialize an efi item with the given number of extents.
*/
-xfs_efi_log_item_t *
-xfs_efi_init(xfs_mount_t *mp,
- uint nextents)
+struct xfs_efi_log_item *
+xfs_efi_init(
+ struct xfs_mount *mp,
+ uint nextents)
{
- xfs_efi_log_item_t *efip;
+ struct xfs_efi_log_item *efip;
uint size;
ASSERT(nextents > 0);
if (nextents > XFS_EFI_MAX_FAST_EXTENTS) {
size = (uint)(sizeof(xfs_efi_log_item_t) +
((nextents - 1) * sizeof(xfs_extent_t)));
- efip = (xfs_efi_log_item_t*)kmem_zalloc(size, KM_SLEEP);
+ efip = kmem_zalloc(size, KM_SLEEP);
} else {
- efip = (xfs_efi_log_item_t*)kmem_zone_zalloc(xfs_efi_zone,
- KM_SLEEP);
+ efip = kmem_zone_zalloc(xfs_efi_zone, KM_SLEEP);
}
xfs_log_item_init(mp, &efip->efi_item, XFS_LI_EFI, &xfs_efi_item_ops);
efip->efi_format.efi_nextents = nextents;
efip->efi_format.efi_id = (__psint_t)(void*)efip;
- return (efip);
+ return efip;
}
/*
@@ -276,7 +244,7 @@ xfs_efi_init(xfs_mount_t *mp,
int
xfs_efi_copy_format(xfs_log_iovec_t *buf, xfs_efi_log_format_t *dst_efi_fmt)
{
- xfs_efi_log_format_t *src_efi_fmt = (xfs_efi_log_format_t *)buf->i_addr;
+ xfs_efi_log_format_t *src_efi_fmt = buf->i_addr;
uint i;
uint len = sizeof(xfs_efi_log_format_t) +
(src_efi_fmt->efi_nextents - 1) * sizeof(xfs_extent_t);
@@ -289,8 +257,7 @@ xfs_efi_copy_format(xfs_log_iovec_t *buf, xfs_efi_log_format_t *dst_efi_fmt)
memcpy((char *)dst_efi_fmt, (char*)src_efi_fmt, len);
return 0;
} else if (buf->i_len == len32) {
- xfs_efi_log_format_32_t *src_efi_fmt_32 =
- (xfs_efi_log_format_32_t *)buf->i_addr;
+ xfs_efi_log_format_32_t *src_efi_fmt_32 = buf->i_addr;
dst_efi_fmt->efi_type = src_efi_fmt_32->efi_type;
dst_efi_fmt->efi_size = src_efi_fmt_32->efi_size;
@@ -304,8 +271,7 @@ xfs_efi_copy_format(xfs_log_iovec_t *buf, xfs_efi_log_format_t *dst_efi_fmt)
}
return 0;
} else if (buf->i_len == len64) {
- xfs_efi_log_format_64_t *src_efi_fmt_64 =
- (xfs_efi_log_format_64_t *)buf->i_addr;
+ xfs_efi_log_format_64_t *src_efi_fmt_64 = buf->i_addr;
dst_efi_fmt->efi_type = src_efi_fmt_64->efi_type;
dst_efi_fmt->efi_size = src_efi_fmt_64->efi_size;
@@ -356,16 +322,18 @@ xfs_efi_release(xfs_efi_log_item_t *efip,
}
}
-STATIC void
-xfs_efd_item_free(xfs_efd_log_item_t *efdp)
+static inline struct xfs_efd_log_item *EFD_ITEM(struct xfs_log_item *lip)
{
- int nexts = efdp->efd_format.efd_nextents;
+ return container_of(lip, struct xfs_efd_log_item, efd_item);
+}
- if (nexts > XFS_EFD_MAX_FAST_EXTENTS) {
+STATIC void
+xfs_efd_item_free(struct xfs_efd_log_item *efdp)
+{
+ if (efdp->efd_format.efd_nextents > XFS_EFD_MAX_FAST_EXTENTS)
kmem_free(efdp);
- } else {
+ else
kmem_zone_free(xfs_efd_zone, efdp);
- }
}
/*
@@ -373,9 +341,9 @@ xfs_efd_item_free(xfs_efd_log_item_t *efdp)
* We only need 1 iovec for an efd item. It just logs the efd_log_format
* structure.
*/
-/*ARGSUSED*/
STATIC uint
-xfs_efd_item_size(xfs_efd_log_item_t *efdp)
+xfs_efd_item_size(
+ struct xfs_log_item *lip)
{
return 1;
}
@@ -388,10 +356,12 @@ xfs_efd_item_size(xfs_efd_log_item_t *efdp)
* slots in the efd item have been filled.
*/
STATIC void
-xfs_efd_item_format(xfs_efd_log_item_t *efdp,
- xfs_log_iovec_t *log_vector)
+xfs_efd_item_format(
+ struct xfs_log_item *lip,
+ struct xfs_log_iovec *log_vector)
{
- uint size;
+ struct xfs_efd_log_item *efdp = EFD_ITEM(lip);
+ uint size;
ASSERT(efdp->efd_next_extent == efdp->efd_format.efd_nextents);
@@ -401,48 +371,38 @@ xfs_efd_item_format(xfs_efd_log_item_t *efdp,
size += (efdp->efd_format.efd_nextents - 1) * sizeof(xfs_extent_t);
efdp->efd_format.efd_size = 1;
- log_vector->i_addr = (xfs_caddr_t)&(efdp->efd_format);
+ log_vector->i_addr = &efdp->efd_format;
log_vector->i_len = size;
log_vector->i_type = XLOG_REG_TYPE_EFD_FORMAT;
ASSERT(size >= sizeof(xfs_efd_log_format_t));
}
-
/*
* Pinning has no meaning for an efd item, so just return.
*/
-/*ARGSUSED*/
STATIC void
-xfs_efd_item_pin(xfs_efd_log_item_t *efdp)
+xfs_efd_item_pin(
+ struct xfs_log_item *lip)
{
- return;
}
-
/*
* Since pinning has no meaning for an efd item, unpinning does
* not either.
*/
-/*ARGSUSED*/
-STATIC void
-xfs_efd_item_unpin(xfs_efd_log_item_t *efdp)
-{
- return;
-}
-
-/*ARGSUSED*/
STATIC void
-xfs_efd_item_unpin_remove(xfs_efd_log_item_t *efdp, xfs_trans_t *tp)
+xfs_efd_item_unpin(
+ struct xfs_log_item *lip,
+ int remove)
{
- return;
}
/*
* Efd items have no locking, so just return success.
*/
-/*ARGSUSED*/
STATIC uint
-xfs_efd_item_trylock(xfs_efd_log_item_t *efdp)
+xfs_efd_item_trylock(
+ struct xfs_log_item *lip)
{
return XFS_ITEM_LOCKED;
}
@@ -451,13 +411,12 @@ xfs_efd_item_trylock(xfs_efd_log_item_t *efdp)
* Efd items have no locking or pushing, so return failure
* so that the caller doesn't bother with us.
*/
-/*ARGSUSED*/
STATIC void
-xfs_efd_item_unlock(xfs_efd_log_item_t *efdp)
+xfs_efd_item_unlock(
+ struct xfs_log_item *lip)
{
- if (efdp->efd_item.li_flags & XFS_LI_ABORTED)
- xfs_efd_item_free(efdp);
- return;
+ if (lip->li_flags & XFS_LI_ABORTED)
+ xfs_efd_item_free(EFD_ITEM(lip));
}
/*
@@ -467,15 +426,18 @@ xfs_efd_item_unlock(xfs_efd_log_item_t *efdp)
* return -1 to keep the transaction code from further referencing
* this item.
*/
-/*ARGSUSED*/
STATIC xfs_lsn_t
-xfs_efd_item_committed(xfs_efd_log_item_t *efdp, xfs_lsn_t lsn)
+xfs_efd_item_committed(
+ struct xfs_log_item *lip,
+ xfs_lsn_t lsn)
{
+ struct xfs_efd_log_item *efdp = EFD_ITEM(lip);
+
/*
* If we got a log I/O error, it's always the case that the LR with the
* EFI got unpinned and freed before the EFD got aborted.
*/
- if ((efdp->efd_item.li_flags & XFS_LI_ABORTED) == 0)
+ if (!(lip->li_flags & XFS_LI_ABORTED))
xfs_efi_release(efdp->efd_efip, efdp->efd_format.efd_nextents);
xfs_efd_item_free(efdp);
@@ -486,11 +448,10 @@ xfs_efd_item_committed(xfs_efd_log_item_t *efdp, xfs_lsn_t lsn)
* There isn't much you can do to push on an efd item. It is simply
* stuck waiting for the log to be flushed to disk.
*/
-/*ARGSUSED*/
STATIC void
-xfs_efd_item_push(xfs_efd_log_item_t *efdp)
+xfs_efd_item_push(
+ struct xfs_log_item *lip)
{
- return;
}
/*
@@ -500,55 +461,48 @@ xfs_efd_item_push(xfs_efd_log_item_t *efdp)
* example, for inodes, the inode is locked throughout the extent freeing
* so the dependency should be recorded there.
*/
-/*ARGSUSED*/
STATIC void
-xfs_efd_item_committing(xfs_efd_log_item_t *efip, xfs_lsn_t lsn)
+xfs_efd_item_committing(
+ struct xfs_log_item *lip,
+ xfs_lsn_t lsn)
{
- return;
}
/*
* This is the ops vector shared by all efd log items.
*/
static struct xfs_item_ops xfs_efd_item_ops = {
- .iop_size = (uint(*)(xfs_log_item_t*))xfs_efd_item_size,
- .iop_format = (void(*)(xfs_log_item_t*, xfs_log_iovec_t*))
- xfs_efd_item_format,
- .iop_pin = (void(*)(xfs_log_item_t*))xfs_efd_item_pin,
- .iop_unpin = (void(*)(xfs_log_item_t*))xfs_efd_item_unpin,
- .iop_unpin_remove = (void(*)(xfs_log_item_t*, xfs_trans_t*))
- xfs_efd_item_unpin_remove,
- .iop_trylock = (uint(*)(xfs_log_item_t*))xfs_efd_item_trylock,
- .iop_unlock = (void(*)(xfs_log_item_t*))xfs_efd_item_unlock,
- .iop_committed = (xfs_lsn_t(*)(xfs_log_item_t*, xfs_lsn_t))
- xfs_efd_item_committed,
- .iop_push = (void(*)(xfs_log_item_t*))xfs_efd_item_push,
- .iop_pushbuf = NULL,
- .iop_committing = (void(*)(xfs_log_item_t*, xfs_lsn_t))
- xfs_efd_item_committing
+ .iop_size = xfs_efd_item_size,
+ .iop_format = xfs_efd_item_format,
+ .iop_pin = xfs_efd_item_pin,
+ .iop_unpin = xfs_efd_item_unpin,
+ .iop_trylock = xfs_efd_item_trylock,
+ .iop_unlock = xfs_efd_item_unlock,
+ .iop_committed = xfs_efd_item_committed,
+ .iop_push = xfs_efd_item_push,
+ .iop_committing = xfs_efd_item_committing
};
-
/*
* Allocate and initialize an efd item with the given number of extents.
*/
-xfs_efd_log_item_t *
-xfs_efd_init(xfs_mount_t *mp,
- xfs_efi_log_item_t *efip,
- uint nextents)
+struct xfs_efd_log_item *
+xfs_efd_init(
+ struct xfs_mount *mp,
+ struct xfs_efi_log_item *efip,
+ uint nextents)
{
- xfs_efd_log_item_t *efdp;
+ struct xfs_efd_log_item *efdp;
uint size;
ASSERT(nextents > 0);
if (nextents > XFS_EFD_MAX_FAST_EXTENTS) {
size = (uint)(sizeof(xfs_efd_log_item_t) +
((nextents - 1) * sizeof(xfs_extent_t)));
- efdp = (xfs_efd_log_item_t*)kmem_zalloc(size, KM_SLEEP);
+ efdp = kmem_zalloc(size, KM_SLEEP);
} else {
- efdp = (xfs_efd_log_item_t*)kmem_zone_zalloc(xfs_efd_zone,
- KM_SLEEP);
+ efdp = kmem_zone_zalloc(xfs_efd_zone, KM_SLEEP);
}
xfs_log_item_init(mp, &efdp->efd_item, XFS_LI_EFD, &xfs_efd_item_ops);
@@ -556,5 +510,5 @@ xfs_efd_init(xfs_mount_t *mp,
efdp->efd_format.efd_nextents = nextents;
efdp->efd_format.efd_efi_id = efip->efi_format.efi_id;
- return (efdp);
+ return efdp;
}
diff --git a/fs/xfs/xfs_filestream.c b/fs/xfs/xfs_filestream.c
index 390850ee660..9b715dce569 100644
--- a/fs/xfs/xfs_filestream.c
+++ b/fs/xfs/xfs_filestream.c
@@ -18,13 +18,9 @@
#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"
@@ -127,6 +123,82 @@ typedef struct fstrm_item
xfs_inode_t *pip; /* Parent directory inode pointer. */
} fstrm_item_t;
+/*
+ * 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 int
+xfs_filestream_peek_ag(
+ xfs_mount_t *mp,
+ xfs_agnumber_t agno)
+{
+ struct xfs_perag *pag;
+ int ret;
+
+ pag = xfs_perag_get(mp, agno);
+ ret = atomic_read(&pag->pagf_fstrms);
+ xfs_perag_put(pag);
+ return ret;
+}
+
+static int
+xfs_filestream_get_ag(
+ xfs_mount_t *mp,
+ xfs_agnumber_t agno)
+{
+ struct xfs_perag *pag;
+ int ret;
+
+ pag = xfs_perag_get(mp, agno);
+ ret = atomic_inc_return(&pag->pagf_fstrms);
+ xfs_perag_put(pag);
+ return ret;
+}
+
+static void
+xfs_filestream_put_ag(
+ xfs_mount_t *mp,
+ xfs_agnumber_t agno)
+{
+ struct xfs_perag *pag;
+
+ pag = xfs_perag_get(mp, agno);
+ atomic_dec(&pag->pagf_fstrms);
+ xfs_perag_put(pag);
+}
/*
* Scan the AGs starting at startag looking for an AG that isn't in use and has
@@ -355,16 +427,14 @@ xfs_fstrm_free_func(
{
fstrm_item_t *item = (fstrm_item_t *)data;
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);
+ 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));
diff --git a/fs/xfs/xfs_filestream.h b/fs/xfs/xfs_filestream.h
index 260f757bbc5..09dd9af4543 100644
--- a/fs/xfs/xfs_filestream.h
+++ b/fs/xfs/xfs_filestream.h
@@ -42,88 +42,6 @@ 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.
- */
-/*
- * xfs_filestream_peek_ag is only used in tracing code
- */
-static inline int
-xfs_filestream_peek_ag(
- xfs_mount_t *mp,
- xfs_agnumber_t agno)
-{
- struct xfs_perag *pag;
- int ret;
-
- pag = xfs_perag_get(mp, agno);
- ret = atomic_read(&pag->pagf_fstrms);
- xfs_perag_put(pag);
- return ret;
-}
-
-static inline int
-xfs_filestream_get_ag(
- xfs_mount_t *mp,
- xfs_agnumber_t agno)
-{
- struct xfs_perag *pag;
- int ret;
-
- pag = xfs_perag_get(mp, agno);
- ret = atomic_inc_return(&pag->pagf_fstrms);
- xfs_perag_put(pag);
- return ret;
-}
-
-static inline int
-xfs_filestream_put_ag(
- xfs_mount_t *mp,
- xfs_agnumber_t agno)
-{
- struct xfs_perag *pag;
- int ret;
-
- pag = xfs_perag_get(mp, agno);
- ret = atomic_dec_return(&pag->pagf_fstrms);
- xfs_perag_put(pag);
- return ret;
-}
-
/* allocation selection flags */
typedef enum xfs_fstrm_alloc {
XFS_PICK_USERDATA = 1,
diff --git a/fs/xfs/xfs_fsops.c b/fs/xfs/xfs_fsops.c
index 37a6f62c57b..dbca5f5c37b 100644
--- a/fs/xfs/xfs_fsops.c
+++ b/fs/xfs/xfs_fsops.c
@@ -24,14 +24,10 @@
#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_alloc_btree.h"
#include "xfs_ialloc_btree.h"
-#include "xfs_dir2_sf.h"
-#include "xfs_attr_sf.h"
#include "xfs_dinode.h"
#include "xfs_inode.h"
#include "xfs_inode_item.h"
@@ -626,8 +622,7 @@ xfs_fs_log_dummy(
ip = mp->m_rootip;
xfs_ilock(ip, XFS_ILOCK_EXCL);
- xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL);
- xfs_trans_ihold(tp, ip);
+ xfs_trans_ijoin(tp, ip);
xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
xfs_trans_set_sync(tp);
error = xfs_trans_commit(tp, 0);
diff --git a/fs/xfs/xfs_ialloc.c b/fs/xfs/xfs_ialloc.c
index c7142a064c4..abf80ae1e95 100644
--- a/fs/xfs/xfs_ialloc.c
+++ b/fs/xfs/xfs_ialloc.c
@@ -24,14 +24,10 @@
#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_alloc_btree.h"
#include "xfs_ialloc_btree.h"
-#include "xfs_dir2_sf.h"
-#include "xfs_attr_sf.h"
#include "xfs_dinode.h"
#include "xfs_inode.h"
#include "xfs_btree.h"
diff --git a/fs/xfs/xfs_ialloc_btree.c b/fs/xfs/xfs_ialloc_btree.c
index c282a9af539..d352862cefa 100644
--- a/fs/xfs/xfs_ialloc_btree.c
+++ b/fs/xfs/xfs_ialloc_btree.c
@@ -24,14 +24,10 @@
#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_alloc_btree.h"
#include "xfs_ialloc_btree.h"
-#include "xfs_dir2_sf.h"
-#include "xfs_attr_sf.h"
#include "xfs_dinode.h"
#include "xfs_inode.h"
#include "xfs_btree.h"
diff --git a/fs/xfs/xfs_iget.c b/fs/xfs/xfs_iget.c
index 8f8b91be2c9..b1ecc6f97ad 100644
--- a/fs/xfs/xfs_iget.c
+++ b/fs/xfs/xfs_iget.c
@@ -25,14 +25,10 @@
#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_alloc_btree.h"
#include "xfs_ialloc_btree.h"
-#include "xfs_dir2_sf.h"
-#include "xfs_attr_sf.h"
#include "xfs_dinode.h"
#include "xfs_inode.h"
#include "xfs_btree.h"
@@ -95,7 +91,7 @@ xfs_inode_alloc(
return ip;
}
-STATIC void
+void
xfs_inode_free(
struct xfs_inode *ip)
{
@@ -212,7 +208,7 @@ xfs_iget_cache_hit(
ip->i_flags &= ~XFS_INEW;
ip->i_flags |= XFS_IRECLAIMABLE;
__xfs_inode_set_reclaim_tag(pag, ip);
- trace_xfs_iget_reclaim(ip);
+ trace_xfs_iget_reclaim_fail(ip);
goto out_error;
}
@@ -227,6 +223,7 @@ xfs_iget_cache_hit(
} else {
/* If the VFS inode is being torn down, pause and try again. */
if (!igrab(inode)) {
+ trace_xfs_iget_skip(ip);
error = EAGAIN;
goto out_error;
}
@@ -234,6 +231,7 @@ xfs_iget_cache_hit(
/* We've got a live one. */
spin_unlock(&ip->i_flags_lock);
read_unlock(&pag->pag_ici_lock);
+ trace_xfs_iget_hit(ip);
}
if (lock_flags != 0)
@@ -242,7 +240,6 @@ xfs_iget_cache_hit(
xfs_iflags_clear(ip, XFS_ISTALE);
XFS_STATS_INC(xs_ig_found);
- trace_xfs_iget_found(ip);
return 0;
out_error:
@@ -264,7 +261,6 @@ xfs_iget_cache_miss(
{
struct xfs_inode *ip;
int error;
- unsigned long first_index, mask;
xfs_agino_t agino = XFS_INO_TO_AGINO(mp, ino);
ip = xfs_inode_alloc(mp, ino);
@@ -275,7 +271,7 @@ xfs_iget_cache_miss(
if (error)
goto out_destroy;
- xfs_itrace_entry(ip);
+ trace_xfs_iget_miss(ip);
if ((ip->i_d.di_mode == 0) && !(flags & XFS_IGET_CREATE)) {
error = ENOENT;
@@ -301,8 +297,6 @@ xfs_iget_cache_miss(
BUG();
}
- mask = ~(((XFS_INODE_CLUSTER_SIZE(mp) >> mp->m_sb.sb_inodelog)) - 1);
- first_index = agino & mask;
write_lock(&pag->pag_ici_lock);
/* insert the new inode */
@@ -321,7 +315,6 @@ xfs_iget_cache_miss(
write_unlock(&pag->pag_ici_lock);
radix_tree_preload_end();
- trace_xfs_iget_alloc(ip);
*ipp = ip;
return 0;
@@ -422,97 +415,6 @@ out_error_or_again:
}
/*
- * Decrement reference count of an inode structure and unlock it.
- *
- * ip -- the inode being released
- * lock_flags -- this parameter indicates the inode's locks to be
- * to be released. See the comment on xfs_iunlock() for a list
- * of valid values.
- */
-void
-xfs_iput(xfs_inode_t *ip,
- uint lock_flags)
-{
- xfs_itrace_entry(ip);
- xfs_iunlock(ip, lock_flags);
- IRELE(ip);
-}
-
-/*
- * Special iput for brand-new inodes that are still locked
- */
-void
-xfs_iput_new(
- xfs_inode_t *ip,
- uint lock_flags)
-{
- struct inode *inode = VFS_I(ip);
-
- xfs_itrace_entry(ip);
-
- if ((ip->i_d.di_mode == 0)) {
- ASSERT(!xfs_iflags_test(ip, XFS_IRECLAIMABLE));
- make_bad_inode(inode);
- }
- if (inode->i_state & I_NEW)
- unlock_new_inode(inode);
- if (lock_flags)
- xfs_iunlock(ip, lock_flags);
- IRELE(ip);
-}
-
-/*
- * This is called free all the memory associated with an inode.
- * It must free the inode itself and any buffers allocated for
- * if_extents/if_data and if_broot. It must also free the lock
- * associated with the inode.
- *
- * Note: because we don't initialise everything on reallocation out
- * of the zone, we must ensure we nullify everything correctly before
- * freeing the structure.
- */
-void
-xfs_ireclaim(
- struct xfs_inode *ip)
-{
- struct xfs_mount *mp = ip->i_mount;
- struct xfs_perag *pag;
- xfs_agino_t agino = XFS_INO_TO_AGINO(mp, ip->i_ino);
-
- XFS_STATS_INC(xs_ig_reclaims);
-
- /*
- * Remove the inode from the per-AG radix tree.
- *
- * Because radix_tree_delete won't complain even if the item was never
- * added to the tree assert that it's been there before to catch
- * problems with the inode life time early on.
- */
- pag = xfs_perag_get(mp, XFS_INO_TO_AGNO(mp, ip->i_ino));
- write_lock(&pag->pag_ici_lock);
- if (!radix_tree_delete(&pag->pag_ici_root, agino))
- ASSERT(0);
- write_unlock(&pag->pag_ici_lock);
- xfs_perag_put(pag);
-
- /*
- * Here we do an (almost) spurious inode lock in order to coordinate
- * with inode cache radix tree lookups. This is because the lookup
- * can reference the inodes in the cache without taking references.
- *
- * We make that OK here by ensuring that we wait until the inode is
- * unlocked after the lookup before we go ahead and free it. We get
- * both the ilock and the iolock because the code may need to drop the
- * ilock one but will still hold the iolock.
- */
- xfs_ilock(ip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL);
- xfs_qm_dqdetach(ip);
- xfs_iunlock(ip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL);
-
- xfs_inode_free(ip);
-}
-
-/*
* This is a wrapper routine around the xfs_ilock() routine
* used to centralize some grungy code. It is used in places
* that wish to lock the inode solely for reading the extents.
diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
index b76a829d7e2..68415cb4f23 100644
--- a/fs/xfs/xfs_inode.c
+++ b/fs/xfs/xfs_inode.c
@@ -27,13 +27,10 @@
#include "xfs_trans_priv.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_alloc_btree.h"
#include "xfs_ialloc_btree.h"
-#include "xfs_dir2_sf.h"
#include "xfs_attr_sf.h"
#include "xfs_dinode.h"
#include "xfs_inode.h"
@@ -44,7 +41,6 @@
#include "xfs_alloc.h"
#include "xfs_ialloc.h"
#include "xfs_bmap.h"
-#include "xfs_rw.h"
#include "xfs_error.h"
#include "xfs_utils.h"
#include "xfs_quota.h"
@@ -426,7 +422,7 @@ xfs_iformat(
if (!XFS_DFORK_Q(dip))
return 0;
ASSERT(ip->i_afp == NULL);
- ip->i_afp = kmem_zone_zalloc(xfs_ifork_zone, KM_SLEEP);
+ ip->i_afp = kmem_zone_zalloc(xfs_ifork_zone, KM_SLEEP | KM_NOFS);
ip->i_afp->if_ext_max =
XFS_IFORK_ASIZE(ip) / (uint)sizeof(xfs_bmbt_rec_t);
switch (dip->di_aformat) {
@@ -509,7 +505,7 @@ xfs_iformat_local(
ifp->if_u1.if_data = ifp->if_u2.if_inline_data;
else {
real_size = roundup(size, 4);
- ifp->if_u1.if_data = kmem_alloc(real_size, KM_SLEEP);
+ ifp->if_u1.if_data = kmem_alloc(real_size, KM_SLEEP | KM_NOFS);
}
ifp->if_bytes = size;
ifp->if_real_bytes = real_size;
@@ -636,7 +632,7 @@ xfs_iformat_btree(
}
ifp->if_broot_bytes = size;
- ifp->if_broot = kmem_alloc(size, KM_SLEEP);
+ ifp->if_broot = kmem_alloc(size, KM_SLEEP | KM_NOFS);
ASSERT(ifp->if_broot != NULL);
/*
* Copy and convert from the on-disk structure
@@ -922,7 +918,6 @@ xfs_iread_extents(
int error;
xfs_ifork_t *ifp;
xfs_extnum_t nextents;
- size_t size;
if (unlikely(XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_BTREE)) {
XFS_ERROR_REPORT("xfs_iread_extents", XFS_ERRLEVEL_LOW,
@@ -930,7 +925,6 @@ xfs_iread_extents(
return XFS_ERROR(EFSCORRUPTED);
}
nextents = XFS_IFORK_NEXTENTS(ip, whichfork);
- size = nextents * sizeof(xfs_bmbt_rec_t);
ifp = XFS_IFORK_PTR(ip, whichfork);
/*
@@ -1226,7 +1220,7 @@ xfs_isize_check(
(xfs_ufsize_t)XFS_MAXIOFFSET(mp)) -
map_first),
XFS_BMAPI_ENTIRE, NULL, 0, imaps, &nimaps,
- NULL, NULL))
+ NULL))
return;
ASSERT(nimaps == 1);
ASSERT(imaps[0].br_startblock == HOLESTARTBLOCK);
@@ -1460,7 +1454,7 @@ xfs_itruncate_finish(
ASSERT((*tp)->t_flags & XFS_TRANS_PERM_LOG_RES);
ASSERT(ip->i_transp == *tp);
ASSERT(ip->i_itemp != NULL);
- ASSERT(ip->i_itemp->ili_flags & XFS_ILI_HOLD);
+ ASSERT(ip->i_itemp->ili_lock_flags == 0);
ntp = *tp;
@@ -1589,11 +1583,10 @@ xfs_itruncate_finish(
xfs_bmap_init(&free_list, &first_block);
error = xfs_bunmapi(ntp, ip,
first_unmap_block, unmap_len,
- xfs_bmapi_aflag(fork) |
- (sync ? 0 : XFS_BMAPI_ASYNC),
+ xfs_bmapi_aflag(fork),
XFS_ITRUNC_MAX_EXTENTS,
&first_block, &free_list,
- NULL, &done);
+ &done);
if (error) {
/*
* If the bunmapi call encounters an error,
@@ -1612,12 +1605,8 @@ xfs_itruncate_finish(
*/
error = xfs_bmap_finish(tp, &free_list, &committed);
ntp = *tp;
- if (committed) {
- /* link the inode into the next xact in the chain */
- xfs_trans_ijoin(ntp, ip,
- XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL);
- xfs_trans_ihold(ntp, ip);
- }
+ if (committed)
+ xfs_trans_ijoin(ntp, ip);
if (error) {
/*
@@ -1646,9 +1635,7 @@ xfs_itruncate_finish(
error = xfs_trans_commit(*tp, 0);
*tp = ntp;
- /* link the inode into the next transaction in the chain */
- xfs_trans_ijoin(ntp, ip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL);
- xfs_trans_ihold(ntp, ip);
+ xfs_trans_ijoin(ntp, ip);
if (error)
return error;
@@ -1985,7 +1972,7 @@ xfs_ifree_cluster(
if (lip->li_type == XFS_LI_INODE) {
iip = (xfs_inode_log_item_t *)lip;
ASSERT(iip->ili_logged == 1);
- lip->li_cb = (void(*)(xfs_buf_t*,xfs_log_item_t*)) xfs_istale_done;
+ lip->li_cb = xfs_istale_done;
xfs_trans_ail_copy_lsn(mp->m_ail,
&iip->ili_flush_lsn,
&iip->ili_item.li_lsn);
@@ -2055,9 +2042,8 @@ xfs_ifree_cluster(
xfs_trans_ail_copy_lsn(mp->m_ail, &iip->ili_flush_lsn,
&iip->ili_item.li_lsn);
- xfs_buf_attach_iodone(bp,
- (void(*)(xfs_buf_t*,xfs_log_item_t*))
- xfs_istale_done, (xfs_log_item_t *)iip);
+ xfs_buf_attach_iodone(bp, xfs_istale_done,
+ &iip->ili_item);
if (ip != free_ip)
xfs_iunlock(ip, XFS_ILOCK_EXCL);
@@ -2203,7 +2189,7 @@ xfs_iroot_realloc(
*/
if (ifp->if_broot_bytes == 0) {
new_size = (size_t)XFS_BMAP_BROOT_SPACE_CALC(rec_diff);
- ifp->if_broot = kmem_alloc(new_size, KM_SLEEP);
+ ifp->if_broot = kmem_alloc(new_size, KM_SLEEP | KM_NOFS);
ifp->if_broot_bytes = (int)new_size;
return;
}
@@ -2219,7 +2205,7 @@ xfs_iroot_realloc(
new_size = (size_t)XFS_BMAP_BROOT_SPACE_CALC(new_max);
ifp->if_broot = kmem_realloc(ifp->if_broot, new_size,
(size_t)XFS_BMAP_BROOT_SPACE_CALC(cur_max), /* old size */
- KM_SLEEP);
+ KM_SLEEP | KM_NOFS);
op = (char *)XFS_BMAP_BROOT_PTR_ADDR(mp, ifp->if_broot, 1,
ifp->if_broot_bytes);
np = (char *)XFS_BMAP_BROOT_PTR_ADDR(mp, ifp->if_broot, 1,
@@ -2245,7 +2231,7 @@ xfs_iroot_realloc(
else
new_size = 0;
if (new_size > 0) {
- new_broot = kmem_alloc(new_size, KM_SLEEP);
+ new_broot = kmem_alloc(new_size, KM_SLEEP | KM_NOFS);
/*
* First copy over the btree block header.
*/
@@ -2349,7 +2335,8 @@ xfs_idata_realloc(
real_size = roundup(new_size, 4);
if (ifp->if_u1.if_data == NULL) {
ASSERT(ifp->if_real_bytes == 0);
- ifp->if_u1.if_data = kmem_alloc(real_size, KM_SLEEP);
+ ifp->if_u1.if_data = kmem_alloc(real_size,
+ KM_SLEEP | KM_NOFS);
} else if (ifp->if_u1.if_data != ifp->if_u2.if_inline_data) {
/*
* Only do the realloc if the underlying size
@@ -2360,11 +2347,12 @@ xfs_idata_realloc(
kmem_realloc(ifp->if_u1.if_data,
real_size,
ifp->if_real_bytes,
- KM_SLEEP);
+ KM_SLEEP | KM_NOFS);
}
} else {
ASSERT(ifp->if_real_bytes == 0);
- ifp->if_u1.if_data = kmem_alloc(real_size, KM_SLEEP);
+ ifp->if_u1.if_data = kmem_alloc(real_size,
+ KM_SLEEP | KM_NOFS);
memcpy(ifp->if_u1.if_data, ifp->if_u2.if_inline_data,
ifp->if_bytes);
}
@@ -2731,7 +2719,6 @@ cluster_corrupt_out:
* mark it as stale and brelse.
*/
if (XFS_BUF_IODONE_FUNC(bp)) {
- XFS_BUF_CLR_BDSTRAT_FUNC(bp);
XFS_BUF_UNDONE(bp);
XFS_BUF_STALE(bp);
XFS_BUF_ERROR(bp,EIO);
@@ -3069,8 +3056,7 @@ xfs_iflush_int(
* and unlock the inode's flush lock when the inode is
* completely written to disk.
*/
- xfs_buf_attach_iodone(bp, (void(*)(xfs_buf_t*,xfs_log_item_t*))
- xfs_iflush_done, (xfs_log_item_t *)iip);
+ xfs_buf_attach_iodone(bp, xfs_iflush_done, &iip->ili_item);
ASSERT(XFS_BUF_FSPRIVATE(bp, void *) != NULL);
ASSERT(XFS_BUF_IODONE_FUNC(bp) != NULL);
@@ -3514,13 +3500,11 @@ xfs_iext_remove_indirect(
xfs_extnum_t ext_diff; /* extents to remove in current list */
xfs_extnum_t nex1; /* number of extents before idx */
xfs_extnum_t nex2; /* extents after idx + count */
- int nlists; /* entries in indirection array */
int page_idx = idx; /* index in target extent list */
ASSERT(ifp->if_flags & XFS_IFEXTIREC);
erp = xfs_iext_idx_to_irec(ifp, &page_idx, &erp_idx, 0);
ASSERT(erp != NULL);
- nlists = ifp->if_real_bytes / XFS_IEXT_BUFSZ;
nex1 = page_idx;
ext_cnt = count;
while (ext_cnt) {
diff --git a/fs/xfs/xfs_inode.h b/fs/xfs/xfs_inode.h
index 78550df13cd..0898c5417d1 100644
--- a/fs/xfs/xfs_inode.h
+++ b/fs/xfs/xfs_inode.h
@@ -443,8 +443,6 @@ static inline void xfs_ifunlock(xfs_inode_t *ip)
*/
int xfs_iget(struct xfs_mount *, struct xfs_trans *, xfs_ino_t,
uint, uint, xfs_inode_t **);
-void xfs_iput(xfs_inode_t *, uint);
-void xfs_iput_new(xfs_inode_t *, uint);
void xfs_ilock(xfs_inode_t *, uint);
int xfs_ilock_nowait(xfs_inode_t *, uint);
void xfs_iunlock(xfs_inode_t *, uint);
@@ -452,7 +450,7 @@ void xfs_ilock_demote(xfs_inode_t *, uint);
int xfs_isilocked(xfs_inode_t *, uint);
uint xfs_ilock_map_shared(xfs_inode_t *);
void xfs_iunlock_map_shared(xfs_inode_t *, uint);
-void xfs_ireclaim(xfs_inode_t *);
+void xfs_inode_free(struct xfs_inode *ip);
/*
* xfs_inode.c prototypes.
diff --git a/fs/xfs/xfs_inode_item.c b/fs/xfs/xfs_inode_item.c
index cf8249a6000..fe00777e279 100644
--- a/fs/xfs/xfs_inode_item.c
+++ b/fs/xfs/xfs_inode_item.c
@@ -22,30 +22,26 @@
#include "xfs_log.h"
#include "xfs_inum.h"
#include "xfs_trans.h"
-#include "xfs_buf_item.h"
#include "xfs_sb.h"
#include "xfs_ag.h"
-#include "xfs_dir2.h"
-#include "xfs_dmapi.h"
#include "xfs_mount.h"
#include "xfs_trans_priv.h"
#include "xfs_bmap_btree.h"
-#include "xfs_alloc_btree.h"
-#include "xfs_ialloc_btree.h"
-#include "xfs_dir2_sf.h"
-#include "xfs_attr_sf.h"
#include "xfs_dinode.h"
#include "xfs_inode.h"
#include "xfs_inode_item.h"
-#include "xfs_btree.h"
-#include "xfs_ialloc.h"
-#include "xfs_rw.h"
#include "xfs_error.h"
#include "xfs_trace.h"
kmem_zone_t *xfs_ili_zone; /* inode log item zone */
+static inline struct xfs_inode_log_item *INODE_ITEM(struct xfs_log_item *lip)
+{
+ return container_of(lip, struct xfs_inode_log_item, ili_item);
+}
+
+
/*
* This returns the number of iovecs needed to log the given inode item.
*
@@ -55,13 +51,11 @@ kmem_zone_t *xfs_ili_zone; /* inode log item zone */
*/
STATIC uint
xfs_inode_item_size(
- xfs_inode_log_item_t *iip)
+ struct xfs_log_item *lip)
{
- uint nvecs;
- xfs_inode_t *ip;
-
- ip = iip->ili_inode;
- nvecs = 2;
+ struct xfs_inode_log_item *iip = INODE_ITEM(lip);
+ struct xfs_inode *ip = iip->ili_inode;
+ uint nvecs = 2;
/*
* Only log the data/extents/b-tree root if there is something
@@ -212,21 +206,17 @@ xfs_inode_item_size(
*/
STATIC void
xfs_inode_item_format(
- xfs_inode_log_item_t *iip,
- xfs_log_iovec_t *log_vector)
+ struct xfs_log_item *lip,
+ struct xfs_log_iovec *vecp)
{
+ struct xfs_inode_log_item *iip = INODE_ITEM(lip);
+ struct xfs_inode *ip = iip->ili_inode;
uint nvecs;
- xfs_log_iovec_t *vecp;
- xfs_inode_t *ip;
size_t data_bytes;
xfs_bmbt_rec_t *ext_buffer;
- int nrecs;
xfs_mount_t *mp;
- ip = iip->ili_inode;
- vecp = log_vector;
-
- vecp->i_addr = (xfs_caddr_t)&iip->ili_format;
+ vecp->i_addr = &iip->ili_format;
vecp->i_len = sizeof(xfs_inode_log_format_t);
vecp->i_type = XLOG_REG_TYPE_IFORMAT;
vecp++;
@@ -277,7 +267,7 @@ xfs_inode_item_format(
*/
xfs_synchronize_times(ip);
- vecp->i_addr = (xfs_caddr_t)&ip->i_d;
+ vecp->i_addr = &ip->i_d;
vecp->i_len = sizeof(struct xfs_icdinode);
vecp->i_type = XLOG_REG_TYPE_ICORE;
vecp++;
@@ -323,18 +313,17 @@ xfs_inode_item_format(
ASSERT(ip->i_df.if_u1.if_extents != NULL);
ASSERT(ip->i_d.di_nextents > 0);
ASSERT(iip->ili_extents_buf == NULL);
- nrecs = ip->i_df.if_bytes /
- (uint)sizeof(xfs_bmbt_rec_t);
- ASSERT(nrecs > 0);
+ ASSERT((ip->i_df.if_bytes /
+ (uint)sizeof(xfs_bmbt_rec_t)) > 0);
#ifdef XFS_NATIVE_HOST
- if (nrecs == ip->i_d.di_nextents) {
+ if (ip->i_d.di_nextents == ip->i_df.if_bytes /
+ (uint)sizeof(xfs_bmbt_rec_t)) {
/*
* There are no delayed allocation
* extents, so just point to the
* real extents array.
*/
- vecp->i_addr =
- (char *)(ip->i_df.if_u1.if_extents);
+ vecp->i_addr = ip->i_df.if_u1.if_extents;
vecp->i_len = ip->i_df.if_bytes;
vecp->i_type = XLOG_REG_TYPE_IEXT;
} else
@@ -352,7 +341,7 @@ xfs_inode_item_format(
ext_buffer = kmem_alloc(ip->i_df.if_bytes,
KM_SLEEP);
iip->ili_extents_buf = ext_buffer;
- vecp->i_addr = (xfs_caddr_t)ext_buffer;
+ vecp->i_addr = ext_buffer;
vecp->i_len = xfs_iextents_copy(ip, ext_buffer,
XFS_DATA_FORK);
vecp->i_type = XLOG_REG_TYPE_IEXT;
@@ -371,7 +360,7 @@ xfs_inode_item_format(
if (iip->ili_format.ilf_fields & XFS_ILOG_DBROOT) {
ASSERT(ip->i_df.if_broot_bytes > 0);
ASSERT(ip->i_df.if_broot != NULL);
- vecp->i_addr = (xfs_caddr_t)ip->i_df.if_broot;
+ vecp->i_addr = ip->i_df.if_broot;
vecp->i_len = ip->i_df.if_broot_bytes;
vecp->i_type = XLOG_REG_TYPE_IBROOT;
vecp++;
@@ -389,7 +378,7 @@ xfs_inode_item_format(
ASSERT(ip->i_df.if_u1.if_data != NULL);
ASSERT(ip->i_d.di_size > 0);
- vecp->i_addr = (xfs_caddr_t)ip->i_df.if_u1.if_data;
+ vecp->i_addr = ip->i_df.if_u1.if_data;
/*
* Round i_bytes up to a word boundary.
* The underlying memory is guaranteed to
@@ -437,7 +426,7 @@ xfs_inode_item_format(
* Assert that no attribute-related log flags are set.
*/
if (!XFS_IFORK_Q(ip)) {
- ASSERT(nvecs == iip->ili_item.li_desc->lid_size);
+ ASSERT(nvecs == lip->li_desc->lid_size);
iip->ili_format.ilf_size = nvecs;
ASSERT(!(iip->ili_format.ilf_fields &
(XFS_ILOG_ADATA | XFS_ILOG_ABROOT | XFS_ILOG_AEXT)));
@@ -449,21 +438,21 @@ xfs_inode_item_format(
ASSERT(!(iip->ili_format.ilf_fields &
(XFS_ILOG_ADATA | XFS_ILOG_ABROOT)));
if (iip->ili_format.ilf_fields & XFS_ILOG_AEXT) {
- ASSERT(ip->i_afp->if_bytes > 0);
- ASSERT(ip->i_afp->if_u1.if_extents != NULL);
- ASSERT(ip->i_d.di_anextents > 0);
#ifdef DEBUG
- nrecs = ip->i_afp->if_bytes /
+ int nrecs = ip->i_afp->if_bytes /
(uint)sizeof(xfs_bmbt_rec_t);
-#endif
ASSERT(nrecs > 0);
ASSERT(nrecs == ip->i_d.di_anextents);
+ ASSERT(ip->i_afp->if_bytes > 0);
+ ASSERT(ip->i_afp->if_u1.if_extents != NULL);
+ ASSERT(ip->i_d.di_anextents > 0);
+#endif
#ifdef XFS_NATIVE_HOST
/*
* There are not delayed allocation extents
* for attributes, so just point at the array.
*/
- vecp->i_addr = (char *)(ip->i_afp->if_u1.if_extents);
+ vecp->i_addr = ip->i_afp->if_u1.if_extents;
vecp->i_len = ip->i_afp->if_bytes;
#else
ASSERT(iip->ili_aextents_buf == NULL);
@@ -473,7 +462,7 @@ xfs_inode_item_format(
ext_buffer = kmem_alloc(ip->i_afp->if_bytes,
KM_SLEEP);
iip->ili_aextents_buf = ext_buffer;
- vecp->i_addr = (xfs_caddr_t)ext_buffer;
+ vecp->i_addr = ext_buffer;
vecp->i_len = xfs_iextents_copy(ip, ext_buffer,
XFS_ATTR_FORK);
#endif
@@ -490,7 +479,7 @@ xfs_inode_item_format(
if (iip->ili_format.ilf_fields & XFS_ILOG_ABROOT) {
ASSERT(ip->i_afp->if_broot_bytes > 0);
ASSERT(ip->i_afp->if_broot != NULL);
- vecp->i_addr = (xfs_caddr_t)ip->i_afp->if_broot;
+ vecp->i_addr = ip->i_afp->if_broot;
vecp->i_len = ip->i_afp->if_broot_bytes;
vecp->i_type = XLOG_REG_TYPE_IATTR_BROOT;
vecp++;
@@ -506,7 +495,7 @@ xfs_inode_item_format(
ASSERT(ip->i_afp->if_bytes > 0);
ASSERT(ip->i_afp->if_u1.if_data != NULL);
- vecp->i_addr = (xfs_caddr_t)ip->i_afp->if_u1.if_data;
+ vecp->i_addr = ip->i_afp->if_u1.if_data;
/*
* Round i_bytes up to a word boundary.
* The underlying memory is guaranteed to
@@ -528,7 +517,7 @@ xfs_inode_item_format(
break;
}
- ASSERT(nvecs == iip->ili_item.li_desc->lid_size);
+ ASSERT(nvecs == lip->li_desc->lid_size);
iip->ili_format.ilf_size = nvecs;
}
@@ -539,12 +528,14 @@ xfs_inode_item_format(
*/
STATIC void
xfs_inode_item_pin(
- xfs_inode_log_item_t *iip)
+ struct xfs_log_item *lip)
{
- ASSERT(xfs_isilocked(iip->ili_inode, XFS_ILOCK_EXCL));
+ struct xfs_inode *ip = INODE_ITEM(lip)->ili_inode;
+
+ ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL));
- trace_xfs_inode_pin(iip->ili_inode, _RET_IP_);
- atomic_inc(&iip->ili_inode->i_pincount);
+ trace_xfs_inode_pin(ip, _RET_IP_);
+ atomic_inc(&ip->i_pincount);
}
@@ -554,12 +545,12 @@ xfs_inode_item_pin(
*
* Also wake up anyone in xfs_iunpin_wait() if the count goes to 0.
*/
-/* ARGSUSED */
STATIC void
xfs_inode_item_unpin(
- xfs_inode_log_item_t *iip)
+ struct xfs_log_item *lip,
+ int remove)
{
- struct xfs_inode *ip = iip->ili_inode;
+ struct xfs_inode *ip = INODE_ITEM(lip)->ili_inode;
trace_xfs_inode_unpin(ip, _RET_IP_);
ASSERT(atomic_read(&ip->i_pincount) > 0);
@@ -567,15 +558,6 @@ xfs_inode_item_unpin(
wake_up(&ip->i_ipin_wait);
}
-/* ARGSUSED */
-STATIC void
-xfs_inode_item_unpin_remove(
- xfs_inode_log_item_t *iip,
- xfs_trans_t *tp)
-{
- xfs_inode_item_unpin(iip);
-}
-
/*
* This is called to attempt to lock the inode associated with this
* inode log item, in preparation for the push routine which does the actual
@@ -591,19 +573,16 @@ xfs_inode_item_unpin_remove(
*/
STATIC uint
xfs_inode_item_trylock(
- xfs_inode_log_item_t *iip)
+ struct xfs_log_item *lip)
{
- register xfs_inode_t *ip;
-
- ip = iip->ili_inode;
+ struct xfs_inode_log_item *iip = INODE_ITEM(lip);
+ struct xfs_inode *ip = iip->ili_inode;
- if (xfs_ipincount(ip) > 0) {
+ if (xfs_ipincount(ip) > 0)
return XFS_ITEM_PINNED;
- }
- if (!xfs_ilock_nowait(ip, XFS_ILOCK_SHARED)) {
+ if (!xfs_ilock_nowait(ip, XFS_ILOCK_SHARED))
return XFS_ITEM_LOCKED;
- }
if (!xfs_iflock_nowait(ip)) {
/*
@@ -629,7 +608,7 @@ xfs_inode_item_trylock(
if (!XFS_FORCED_SHUTDOWN(ip->i_mount)) {
ASSERT(iip->ili_format.ilf_fields != 0);
ASSERT(iip->ili_logged == 0);
- ASSERT(iip->ili_item.li_flags & XFS_LI_IN_AIL);
+ ASSERT(lip->li_flags & XFS_LI_IN_AIL);
}
#endif
return XFS_ITEM_SUCCESS;
@@ -643,26 +622,18 @@ xfs_inode_item_trylock(
*/
STATIC void
xfs_inode_item_unlock(
- xfs_inode_log_item_t *iip)
+ struct xfs_log_item *lip)
{
- uint hold;
- uint iolocked;
- uint lock_flags;
- xfs_inode_t *ip;
+ struct xfs_inode_log_item *iip = INODE_ITEM(lip);
+ struct xfs_inode *ip = iip->ili_inode;
+ unsigned short lock_flags;
- ASSERT(iip != NULL);
ASSERT(iip->ili_inode->i_itemp != NULL);
ASSERT(xfs_isilocked(iip->ili_inode, XFS_ILOCK_EXCL));
- ASSERT((!(iip->ili_inode->i_itemp->ili_flags &
- XFS_ILI_IOLOCKED_EXCL)) ||
- xfs_isilocked(iip->ili_inode, XFS_IOLOCK_EXCL));
- ASSERT((!(iip->ili_inode->i_itemp->ili_flags &
- XFS_ILI_IOLOCKED_SHARED)) ||
- xfs_isilocked(iip->ili_inode, XFS_IOLOCK_SHARED));
+
/*
* Clear the transaction pointer in the inode.
*/
- ip = iip->ili_inode;
ip->i_transp = NULL;
/*
@@ -686,34 +657,11 @@ xfs_inode_item_unlock(
iip->ili_aextents_buf = NULL;
}
- /*
- * Figure out if we should unlock the inode or not.
- */
- hold = iip->ili_flags & XFS_ILI_HOLD;
-
- /*
- * Before clearing out the flags, remember whether we
- * are holding the inode's IO lock.
- */
- iolocked = iip->ili_flags & XFS_ILI_IOLOCKED_ANY;
-
- /*
- * Clear out the fields of the inode log item particular
- * to the current transaction.
- */
- iip->ili_flags = 0;
-
- /*
- * Unlock the inode if XFS_ILI_HOLD was not set.
- */
- if (!hold) {
- lock_flags = XFS_ILOCK_EXCL;
- if (iolocked & XFS_ILI_IOLOCKED_EXCL) {
- lock_flags |= XFS_IOLOCK_EXCL;
- } else if (iolocked & XFS_ILI_IOLOCKED_SHARED) {
- lock_flags |= XFS_IOLOCK_SHARED;
- }
- xfs_iput(iip->ili_inode, lock_flags);
+ lock_flags = iip->ili_lock_flags;
+ iip->ili_lock_flags = 0;
+ if (lock_flags) {
+ xfs_iunlock(iip->ili_inode, lock_flags);
+ IRELE(iip->ili_inode);
}
}
@@ -725,13 +673,12 @@ xfs_inode_item_unlock(
* is the only one that matters. Therefore, simply return the
* given lsn.
*/
-/*ARGSUSED*/
STATIC xfs_lsn_t
xfs_inode_item_committed(
- xfs_inode_log_item_t *iip,
+ struct xfs_log_item *lip,
xfs_lsn_t lsn)
{
- return (lsn);
+ return lsn;
}
/*
@@ -743,13 +690,12 @@ xfs_inode_item_committed(
*/
STATIC void
xfs_inode_item_pushbuf(
- xfs_inode_log_item_t *iip)
+ struct xfs_log_item *lip)
{
- xfs_inode_t *ip;
- xfs_mount_t *mp;
- xfs_buf_t *bp;
+ struct xfs_inode_log_item *iip = INODE_ITEM(lip);
+ struct xfs_inode *ip = iip->ili_inode;
+ struct xfs_buf *bp;
- ip = iip->ili_inode;
ASSERT(xfs_isilocked(ip, XFS_ILOCK_SHARED));
/*
@@ -757,14 +703,13 @@ xfs_inode_item_pushbuf(
* inode was taken off the AIL. So, just get out.
*/
if (completion_done(&ip->i_flush) ||
- ((iip->ili_item.li_flags & XFS_LI_IN_AIL) == 0)) {
+ !(lip->li_flags & XFS_LI_IN_AIL)) {
xfs_iunlock(ip, XFS_ILOCK_SHARED);
return;
}
- mp = ip->i_mount;
- bp = xfs_incore(mp->m_ddev_targp, iip->ili_format.ilf_blkno,
- iip->ili_format.ilf_len, XBF_TRYLOCK);
+ bp = xfs_incore(ip->i_mount->m_ddev_targp, iip->ili_format.ilf_blkno,
+ iip->ili_format.ilf_len, XBF_TRYLOCK);
xfs_iunlock(ip, XFS_ILOCK_SHARED);
if (!bp)
@@ -772,10 +717,8 @@ xfs_inode_item_pushbuf(
if (XFS_BUF_ISDELAYWRITE(bp))
xfs_buf_delwri_promote(bp);
xfs_buf_relse(bp);
- return;
}
-
/*
* This is called to asynchronously write the inode associated with this
* inode log item out to disk. The inode will already have been locked by
@@ -783,14 +726,14 @@ xfs_inode_item_pushbuf(
*/
STATIC void
xfs_inode_item_push(
- xfs_inode_log_item_t *iip)
+ struct xfs_log_item *lip)
{
- xfs_inode_t *ip;
-
- ip = iip->ili_inode;
+ struct xfs_inode_log_item *iip = INODE_ITEM(lip);
+ struct xfs_inode *ip = iip->ili_inode;
ASSERT(xfs_isilocked(ip, XFS_ILOCK_SHARED));
ASSERT(!completion_done(&ip->i_flush));
+
/*
* Since we were able to lock the inode's flush lock and
* we found it on the AIL, the inode must be dirty. This
@@ -813,43 +756,34 @@ xfs_inode_item_push(
*/
(void) xfs_iflush(ip, 0);
xfs_iunlock(ip, XFS_ILOCK_SHARED);
-
- return;
}
/*
* XXX rcc - this one really has to do something. Probably needs
* to stamp in a new field in the incore inode.
*/
-/* ARGSUSED */
STATIC void
xfs_inode_item_committing(
- xfs_inode_log_item_t *iip,
+ struct xfs_log_item *lip,
xfs_lsn_t lsn)
{
- iip->ili_last_lsn = lsn;
- return;
+ INODE_ITEM(lip)->ili_last_lsn = lsn;
}
/*
* This is the ops vector shared by all buf log items.
*/
static struct xfs_item_ops xfs_inode_item_ops = {
- .iop_size = (uint(*)(xfs_log_item_t*))xfs_inode_item_size,
- .iop_format = (void(*)(xfs_log_item_t*, xfs_log_iovec_t*))
- xfs_inode_item_format,
- .iop_pin = (void(*)(xfs_log_item_t*))xfs_inode_item_pin,
- .iop_unpin = (void(*)(xfs_log_item_t*))xfs_inode_item_unpin,
- .iop_unpin_remove = (void(*)(xfs_log_item_t*, xfs_trans_t*))
- xfs_inode_item_unpin_remove,
- .iop_trylock = (uint(*)(xfs_log_item_t*))xfs_inode_item_trylock,
- .iop_unlock = (void(*)(xfs_log_item_t*))xfs_inode_item_unlock,
- .iop_committed = (xfs_lsn_t(*)(xfs_log_item_t*, xfs_lsn_t))
- xfs_inode_item_committed,
- .iop_push = (void(*)(xfs_log_item_t*))xfs_inode_item_push,
- .iop_pushbuf = (void(*)(xfs_log_item_t*))xfs_inode_item_pushbuf,
- .iop_committing = (void(*)(xfs_log_item_t*, xfs_lsn_t))
- xfs_inode_item_committing
+ .iop_size = xfs_inode_item_size,
+ .iop_format = xfs_inode_item_format,
+ .iop_pin = xfs_inode_item_pin,
+ .iop_unpin = xfs_inode_item_unpin,
+ .iop_trylock = xfs_inode_item_trylock,
+ .iop_unlock = xfs_inode_item_unlock,
+ .iop_committed = xfs_inode_item_committed,
+ .iop_push = xfs_inode_item_push,
+ .iop_pushbuf = xfs_inode_item_pushbuf,
+ .iop_committing = xfs_inode_item_committing
};
@@ -858,10 +792,10 @@ static struct xfs_item_ops xfs_inode_item_ops = {
*/
void
xfs_inode_item_init(
- xfs_inode_t *ip,
- xfs_mount_t *mp)
+ struct xfs_inode *ip,
+ struct xfs_mount *mp)
{
- xfs_inode_log_item_t *iip;
+ struct xfs_inode_log_item *iip;
ASSERT(ip->i_itemp == NULL);
iip = ip->i_itemp = kmem_zone_zalloc(xfs_ili_zone, KM_SLEEP);
@@ -899,14 +833,14 @@ xfs_inode_item_destroy(
* from the AIL if it has not been re-logged, and unlocking the inode's
* flush lock.
*/
-/*ARGSUSED*/
void
xfs_iflush_done(
- xfs_buf_t *bp,
- xfs_inode_log_item_t *iip)
+ struct xfs_buf *bp,
+ struct xfs_log_item *lip)
{
+ struct xfs_inode_log_item *iip = INODE_ITEM(lip);
xfs_inode_t *ip = iip->ili_inode;
- struct xfs_ail *ailp = iip->ili_item.li_ailp;
+ struct xfs_ail *ailp = lip->li_ailp;
/*
* We only want to pull the item from the AIL if it is
@@ -917,12 +851,11 @@ xfs_iflush_done(
* the lock since it's cheaper, and then we recheck while
* holding the lock before removing the inode from the AIL.
*/
- if (iip->ili_logged &&
- (iip->ili_item.li_lsn == iip->ili_flush_lsn)) {
+ if (iip->ili_logged && lip->li_lsn == iip->ili_flush_lsn) {
spin_lock(&ailp->xa_lock);
- if (iip->ili_item.li_lsn == iip->ili_flush_lsn) {
+ if (lip->li_lsn == iip->ili_flush_lsn) {
/* xfs_trans_ail_delete() drops the AIL lock. */
- xfs_trans_ail_delete(ailp, (xfs_log_item_t*)iip);
+ xfs_trans_ail_delete(ailp, lip);
} else {
spin_unlock(&ailp->xa_lock);
}
@@ -940,8 +873,6 @@ xfs_iflush_done(
* Release the inode's flush lock since we're done with it.
*/
xfs_ifunlock(ip);
-
- return;
}
/*
@@ -957,10 +888,8 @@ xfs_iflush_abort(
xfs_inode_t *ip)
{
xfs_inode_log_item_t *iip = ip->i_itemp;
- xfs_mount_t *mp;
iip = ip->i_itemp;
- mp = ip->i_mount;
if (iip) {
struct xfs_ail *ailp = iip->ili_item.li_ailp;
if (iip->ili_item.li_flags & XFS_LI_IN_AIL) {
@@ -991,10 +920,10 @@ xfs_iflush_abort(
void
xfs_istale_done(
- xfs_buf_t *bp,
- xfs_inode_log_item_t *iip)
+ struct xfs_buf *bp,
+ struct xfs_log_item *lip)
{
- xfs_iflush_abort(iip->ili_inode);
+ xfs_iflush_abort(INODE_ITEM(lip)->ili_inode);
}
/*
@@ -1007,9 +936,8 @@ xfs_inode_item_format_convert(
xfs_inode_log_format_t *in_f)
{
if (buf->i_len == sizeof(xfs_inode_log_format_32_t)) {
- xfs_inode_log_format_32_t *in_f32;
+ xfs_inode_log_format_32_t *in_f32 = buf->i_addr;
- in_f32 = (xfs_inode_log_format_32_t *)buf->i_addr;
in_f->ilf_type = in_f32->ilf_type;
in_f->ilf_size = in_f32->ilf_size;
in_f->ilf_fields = in_f32->ilf_fields;
@@ -1025,9 +953,8 @@ xfs_inode_item_format_convert(
in_f->ilf_boffset = in_f32->ilf_boffset;
return 0;
} else if (buf->i_len == sizeof(xfs_inode_log_format_64_t)){
- xfs_inode_log_format_64_t *in_f64;
+ xfs_inode_log_format_64_t *in_f64 = buf->i_addr;
- in_f64 = (xfs_inode_log_format_64_t *)buf->i_addr;
in_f->ilf_type = in_f64->ilf_type;
in_f->ilf_size = in_f64->ilf_size;
in_f->ilf_fields = in_f64->ilf_fields;
diff --git a/fs/xfs/xfs_inode_item.h b/fs/xfs/xfs_inode_item.h
index 9a467958ecd..d3dee61e6d9 100644
--- a/fs/xfs/xfs_inode_item.h
+++ b/fs/xfs/xfs_inode_item.h
@@ -103,12 +103,6 @@ typedef struct xfs_inode_log_format_64 {
XFS_ILOG_ADATA | XFS_ILOG_AEXT | \
XFS_ILOG_ABROOT)
-#define XFS_ILI_HOLD 0x1
-#define XFS_ILI_IOLOCKED_EXCL 0x2
-#define XFS_ILI_IOLOCKED_SHARED 0x4
-
-#define XFS_ILI_IOLOCKED_ANY (XFS_ILI_IOLOCKED_EXCL | XFS_ILI_IOLOCKED_SHARED)
-
static inline int xfs_ilog_fbroot(int w)
{
return (w == XFS_DATA_FORK ? XFS_ILOG_DBROOT : XFS_ILOG_ABROOT);
@@ -137,7 +131,7 @@ typedef struct xfs_inode_log_item {
struct xfs_inode *ili_inode; /* inode ptr */
xfs_lsn_t ili_flush_lsn; /* lsn at last flush */
xfs_lsn_t ili_last_lsn; /* lsn at last transaction */
- unsigned short ili_flags; /* misc flags */
+ unsigned short ili_lock_flags; /* lock flags */
unsigned short ili_logged; /* flushed logged data */
unsigned int ili_last_fields; /* fields when flushed */
struct xfs_bmbt_rec *ili_extents_buf; /* array of logged
@@ -161,8 +155,8 @@ static inline int xfs_inode_clean(xfs_inode_t *ip)
extern void xfs_inode_item_init(struct xfs_inode *, struct xfs_mount *);
extern void xfs_inode_item_destroy(struct xfs_inode *);
-extern void xfs_iflush_done(struct xfs_buf *, xfs_inode_log_item_t *);
-extern void xfs_istale_done(struct xfs_buf *, xfs_inode_log_item_t *);
+extern void xfs_iflush_done(struct xfs_buf *, struct xfs_log_item *);
+extern void xfs_istale_done(struct xfs_buf *, struct xfs_log_item *);
extern void xfs_iflush_abort(struct xfs_inode *);
extern int xfs_inode_item_format_convert(xfs_log_iovec_t *,
xfs_inode_log_format_t *);
diff --git a/fs/xfs/xfs_iomap.c b/fs/xfs/xfs_iomap.c
index ef14943829d..20576146369 100644
--- a/fs/xfs/xfs_iomap.c
+++ b/fs/xfs/xfs_iomap.c
@@ -23,19 +23,14 @@
#include "xfs_trans.h"
#include "xfs_sb.h"
#include "xfs_ag.h"
-#include "xfs_dir2.h"
#include "xfs_alloc.h"
-#include "xfs_dmapi.h"
#include "xfs_quota.h"
#include "xfs_mount.h"
#include "xfs_bmap_btree.h"
#include "xfs_alloc_btree.h"
#include "xfs_ialloc_btree.h"
-#include "xfs_dir2_sf.h"
-#include "xfs_attr_sf.h"
#include "xfs_dinode.h"
#include "xfs_inode.h"
-#include "xfs_ialloc.h"
#include "xfs_btree.h"
#include "xfs_bmap.h"
#include "xfs_rtalloc.h"
@@ -123,7 +118,7 @@ xfs_iomap(
error = xfs_bmapi(NULL, ip, offset_fsb,
(xfs_filblks_t)(end_fsb - offset_fsb),
bmapi_flags, NULL, 0, imap,
- nimaps, NULL, NULL);
+ nimaps, NULL);
if (error)
goto out;
@@ -138,7 +133,7 @@ xfs_iomap(
break;
}
- if (flags & (BMAPI_DIRECT|BMAPI_MMAP)) {
+ if (flags & BMAPI_DIRECT) {
error = xfs_iomap_write_direct(ip, offset, count, flags,
imap, nimaps);
} else {
@@ -247,7 +242,7 @@ xfs_iomap_write_direct(
xfs_off_t offset,
size_t count,
int flags,
- xfs_bmbt_irec_t *ret_imap,
+ xfs_bmbt_irec_t *imap,
int *nmaps)
{
xfs_mount_t *mp = ip->i_mount;
@@ -261,7 +256,6 @@ xfs_iomap_write_direct(
int quota_flag;
int rt;
xfs_trans_t *tp;
- xfs_bmbt_irec_t imap;
xfs_bmap_free_t free_list;
uint qblocks, resblks, resrtextents;
int committed;
@@ -285,10 +279,10 @@ xfs_iomap_write_direct(
if (error)
goto error_out;
} else {
- if (*nmaps && (ret_imap->br_startblock == HOLESTARTBLOCK))
+ if (*nmaps && (imap->br_startblock == HOLESTARTBLOCK))
last_fsb = MIN(last_fsb, (xfs_fileoff_t)
- ret_imap->br_blockcount +
- ret_imap->br_startoff);
+ imap->br_blockcount +
+ imap->br_startoff);
}
count_fsb = last_fsb - offset_fsb;
ASSERT(count_fsb > 0);
@@ -334,20 +328,22 @@ xfs_iomap_write_direct(
if (error)
goto error1;
- xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL);
- xfs_trans_ihold(tp, ip);
+ xfs_trans_ijoin(tp, ip);
bmapi_flag = XFS_BMAPI_WRITE;
if ((flags & BMAPI_DIRECT) && (offset < ip->i_size || extsz))
bmapi_flag |= XFS_BMAPI_PREALLOC;
/*
- * Issue the xfs_bmapi() call to allocate the blocks
+ * Issue the xfs_bmapi() call to allocate the blocks.
+ *
+ * From this point onwards we overwrite the imap pointer that the
+ * caller gave to us.
*/
xfs_bmap_init(&free_list, &firstfsb);
nimaps = 1;
error = xfs_bmapi(tp, ip, offset_fsb, count_fsb, bmapi_flag,
- &firstfsb, 0, &imap, &nimaps, &free_list, NULL);
+ &firstfsb, 0, imap, &nimaps, &free_list);
if (error)
goto error0;
@@ -369,12 +365,11 @@ xfs_iomap_write_direct(
goto error_out;
}
- if (!(imap.br_startblock || XFS_IS_REALTIME_INODE(ip))) {
- error = xfs_cmn_err_fsblock_zero(ip, &imap);
+ if (!(imap->br_startblock || XFS_IS_REALTIME_INODE(ip))) {
+ error = xfs_cmn_err_fsblock_zero(ip, imap);
goto error_out;
}
- *ret_imap = imap;
*nmaps = 1;
return 0;
@@ -425,7 +420,7 @@ xfs_iomap_eof_want_preallocate(
imaps = nimaps;
firstblock = NULLFSBLOCK;
error = xfs_bmapi(NULL, ip, start_fsb, count_fsb, 0,
- &firstblock, 0, imap, &imaps, NULL, NULL);
+ &firstblock, 0, imap, &imaps, NULL);
if (error)
return error;
for (n = 0; n < imaps; n++) {
@@ -500,7 +495,7 @@ retry:
(xfs_filblks_t)(last_fsb - offset_fsb),
XFS_BMAPI_DELAY | XFS_BMAPI_WRITE |
XFS_BMAPI_ENTIRE, &firstblock, 1, imap,
- &nimaps, NULL, NULL);
+ &nimaps, NULL);
if (error && (error != ENOSPC))
return XFS_ERROR(error);
@@ -548,7 +543,7 @@ xfs_iomap_write_allocate(
xfs_inode_t *ip,
xfs_off_t offset,
size_t count,
- xfs_bmbt_irec_t *map,
+ xfs_bmbt_irec_t *imap,
int *retmap)
{
xfs_mount_t *mp = ip->i_mount;
@@ -557,7 +552,6 @@ xfs_iomap_write_allocate(
xfs_fsblock_t first_block;
xfs_bmap_free_t free_list;
xfs_filblks_t count_fsb;
- xfs_bmbt_irec_t imap;
xfs_trans_t *tp;
int nimaps, committed;
int error = 0;
@@ -573,8 +567,8 @@ xfs_iomap_write_allocate(
return XFS_ERROR(error);
offset_fsb = XFS_B_TO_FSBT(mp, offset);
- count_fsb = map->br_blockcount;
- map_start_fsb = map->br_startoff;
+ count_fsb = imap->br_blockcount;
+ map_start_fsb = imap->br_startoff;
XFS_STATS_ADD(xs_xstrat_bytes, XFS_FSB_TO_B(mp, count_fsb));
@@ -602,8 +596,7 @@ xfs_iomap_write_allocate(
return XFS_ERROR(error);
}
xfs_ilock(ip, XFS_ILOCK_EXCL);
- xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL);
- xfs_trans_ihold(tp, ip);
+ xfs_trans_ijoin(tp, ip);
xfs_bmap_init(&free_list, &first_block);
@@ -654,10 +647,15 @@ xfs_iomap_write_allocate(
}
}
- /* Go get the actual blocks */
+ /*
+ * Go get the actual blocks.
+ *
+ * From this point onwards we overwrite the imap
+ * pointer that the caller gave to us.
+ */
error = xfs_bmapi(tp, ip, map_start_fsb, count_fsb,
XFS_BMAPI_WRITE, &first_block, 1,
- &imap, &nimaps, &free_list, NULL);
+ imap, &nimaps, &free_list);
if (error)
goto trans_cancel;
@@ -676,13 +674,12 @@ xfs_iomap_write_allocate(
* See if we were able to allocate an extent that
* covers at least part of the callers request
*/
- if (!(imap.br_startblock || XFS_IS_REALTIME_INODE(ip)))
- return xfs_cmn_err_fsblock_zero(ip, &imap);
+ if (!(imap->br_startblock || XFS_IS_REALTIME_INODE(ip)))
+ return xfs_cmn_err_fsblock_zero(ip, imap);
- if ((offset_fsb >= imap.br_startoff) &&
- (offset_fsb < (imap.br_startoff +
- imap.br_blockcount))) {
- *map = imap;
+ if ((offset_fsb >= imap->br_startoff) &&
+ (offset_fsb < (imap->br_startoff +
+ imap->br_blockcount))) {
*retmap = 1;
XFS_STATS_INC(xs_xstrat_quick);
return 0;
@@ -692,8 +689,8 @@ xfs_iomap_write_allocate(
* So far we have not mapped the requested part of the
* file, just surrounding data, try again.
*/
- count_fsb -= imap.br_blockcount;
- map_start_fsb = imap.br_startoff + imap.br_blockcount;
+ count_fsb -= imap->br_blockcount;
+ map_start_fsb = imap->br_startoff + imap->br_blockcount;
}
trans_cancel:
@@ -766,8 +763,7 @@ xfs_iomap_write_unwritten(
}
xfs_ilock(ip, XFS_ILOCK_EXCL);
- xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL);
- xfs_trans_ihold(tp, ip);
+ xfs_trans_ijoin(tp, ip);
/*
* Modify the unwritten extent state of the buffer.
@@ -776,7 +772,7 @@ xfs_iomap_write_unwritten(
nimaps = 1;
error = xfs_bmapi(tp, ip, offset_fsb, count_fsb,
XFS_BMAPI_WRITE|XFS_BMAPI_CONVERT, &firstfsb,
- 1, &imap, &nimaps, &free_list, NULL);
+ 1, &imap, &nimaps, &free_list);
if (error)
goto error_on_bmapi_transaction;
diff --git a/fs/xfs/xfs_iomap.h b/fs/xfs/xfs_iomap.h
index 81ac4afd45b..7748a430f50 100644
--- a/fs/xfs/xfs_iomap.h
+++ b/fs/xfs/xfs_iomap.h
@@ -18,17 +18,16 @@
#ifndef __XFS_IOMAP_H__
#define __XFS_IOMAP_H__
-typedef enum {
- /* base extent manipulation calls */
- BMAPI_READ = (1 << 0), /* read extents */
- BMAPI_WRITE = (1 << 1), /* create extents */
- BMAPI_ALLOCATE = (1 << 2), /* delayed allocate to real extents */
- /* modifiers */
- BMAPI_IGNSTATE = (1 << 4), /* ignore unwritten state on read */
- BMAPI_DIRECT = (1 << 5), /* direct instead of buffered write */
- BMAPI_MMAP = (1 << 6), /* allocate for mmap write */
- BMAPI_TRYLOCK = (1 << 7), /* non-blocking request */
-} bmapi_flags_t;
+/* base extent manipulation calls */
+#define BMAPI_READ (1 << 0) /* read extents */
+#define BMAPI_WRITE (1 << 1) /* create extents */
+#define BMAPI_ALLOCATE (1 << 2) /* delayed allocate to real extents */
+
+/* modifiers */
+#define BMAPI_IGNSTATE (1 << 4) /* ignore unwritten state on read */
+#define BMAPI_DIRECT (1 << 5) /* direct instead of buffered write */
+#define BMAPI_MMA (1 << 6) /* allocate for mmap write */
+#define BMAPI_TRYLOCK (1 << 7) /* non-blocking request */
#define BMAPI_FLAGS \
{ BMAPI_READ, "READ" }, \
@@ -36,7 +35,6 @@ typedef enum {
{ BMAPI_ALLOCATE, "ALLOCATE" }, \
{ BMAPI_IGNSTATE, "IGNSTATE" }, \
{ BMAPI_DIRECT, "DIRECT" }, \
- { BMAPI_MMAP, "MMAP" }, \
{ BMAPI_TRYLOCK, "TRYLOCK" }
struct xfs_inode;
diff --git a/fs/xfs/xfs_itable.c b/fs/xfs/xfs_itable.c
index 2b86f861051..7e3626e5925 100644
--- a/fs/xfs/xfs_itable.c
+++ b/fs/xfs/xfs_itable.c
@@ -24,20 +24,17 @@
#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_alloc_btree.h"
#include "xfs_ialloc_btree.h"
-#include "xfs_dir2_sf.h"
-#include "xfs_attr_sf.h"
#include "xfs_dinode.h"
#include "xfs_inode.h"
#include "xfs_ialloc.h"
#include "xfs_itable.h"
#include "xfs_error.h"
#include "xfs_btree.h"
+#include "xfs_trace.h"
STATIC int
xfs_internal_inum(
@@ -143,7 +140,8 @@ xfs_bulkstat_one_int(
buf->bs_blocks = dic->di_nblocks + ip->i_delayed_blks;
break;
}
- xfs_iput(ip, XFS_ILOCK_SHARED);
+ xfs_iunlock(ip, XFS_ILOCK_SHARED);
+ IRELE(ip);
error = formatter(buffer, ubsize, ubused, buf);
diff --git a/fs/xfs/xfs_log.c b/fs/xfs/xfs_log.c
index 5215abc8023..925d572bf0f 100644
--- a/fs/xfs/xfs_log.c
+++ b/fs/xfs/xfs_log.c
@@ -24,8 +24,6 @@
#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_error.h"
#include "xfs_log_priv.h"
@@ -35,8 +33,6 @@
#include "xfs_ialloc_btree.h"
#include "xfs_log_recover.h"
#include "xfs_trans_priv.h"
-#include "xfs_dir2_sf.h"
-#include "xfs_attr_sf.h"
#include "xfs_dinode.h"
#include "xfs_inode.h"
#include "xfs_rw.h"
@@ -337,7 +333,6 @@ xfs_log_reserve(
int retval = 0;
ASSERT(client == XFS_TRANSACTION || client == XFS_LOG);
- ASSERT((flags & XFS_LOG_NOSLEEP) == 0);
if (XLOG_FORCED_SHUTDOWN(log))
return XFS_ERROR(EIO);
@@ -552,7 +547,7 @@ xfs_log_unmount_write(xfs_mount_t *mp)
.magic = XLOG_UNMOUNT_TYPE,
};
struct xfs_log_iovec reg = {
- .i_addr = (void *)&magic,
+ .i_addr = &magic,
.i_len = sizeof(magic),
.i_type = XLOG_REG_TYPE_UNMOUNT,
};
@@ -1047,7 +1042,6 @@ xlog_alloc_log(xfs_mount_t *mp,
xlog_in_core_t *iclog, *prev_iclog=NULL;
xfs_buf_t *bp;
int i;
- int iclogsize;
int error = ENOMEM;
uint log2_size = 0;
@@ -1127,7 +1121,6 @@ xlog_alloc_log(xfs_mount_t *mp,
* with different amounts of memory. See the definition of
* xlog_in_core_t in xfs_log_priv.h for details.
*/
- iclogsize = log->l_iclog_size;
ASSERT(log->l_iclog_size >= 4096);
for (i=0; i < log->l_iclog_bufs; i++) {
*iclogp = kmem_zalloc(sizeof(xlog_in_core_t), KM_MAYFAIL);
@@ -1428,11 +1421,8 @@ xlog_sync(xlog_t *log,
XFS_BUF_BUSY(bp);
XFS_BUF_ASYNC(bp);
bp->b_flags |= XBF_LOG_BUFFER;
- /*
- * Do an ordered write for the log block.
- * Its unnecessary to flush the first split block in the log wrap case.
- */
- if (!split && (log->l_mp->m_flags & XFS_MOUNT_BARRIER))
+
+ if (log->l_mp->m_flags & XFS_MOUNT_BARRIER)
XFS_BUF_ORDERED(bp);
ASSERT(XFS_BUF_ADDR(bp) <= log->l_logBBsize-1);
diff --git a/fs/xfs/xfs_log.h b/fs/xfs/xfs_log.h
index 04c78e642cc..916eb7db14d 100644
--- a/fs/xfs/xfs_log.h
+++ b/fs/xfs/xfs_log.h
@@ -55,14 +55,10 @@ static inline xfs_lsn_t _lsn_cmp(xfs_lsn_t lsn1, xfs_lsn_t lsn2)
/*
* Flags to xfs_log_reserve()
*
- * XFS_LOG_SLEEP: If space is not available, sleep (default)
- * XFS_LOG_NOSLEEP: If space is not available, return error
* XFS_LOG_PERM_RESERV: Permanent reservation. When writes are
* performed against this type of reservation, the reservation
* is not decreased. Long running transactions should use this.
*/
-#define XFS_LOG_SLEEP 0x0
-#define XFS_LOG_NOSLEEP 0x1
#define XFS_LOG_PERM_RESERV 0x2
/*
@@ -104,7 +100,7 @@ static inline xfs_lsn_t _lsn_cmp(xfs_lsn_t lsn1, xfs_lsn_t lsn2)
#define XLOG_REG_TYPE_MAX 19
typedef struct xfs_log_iovec {
- xfs_caddr_t i_addr; /* beginning address of region */
+ void *i_addr; /* beginning address of region */
int i_len; /* length in bytes of region */
uint i_type; /* type of region */
} xfs_log_iovec_t;
@@ -201,9 +197,4 @@ int xfs_log_commit_cil(struct xfs_mount *mp, struct xfs_trans *tp,
bool xfs_log_item_in_current_chkpt(struct xfs_log_item *lip);
#endif
-
-
-extern int xlog_debug; /* set to 1 to enable real log */
-
-
#endif /* __XFS_LOG_H__ */
diff --git a/fs/xfs/xfs_log_cil.c b/fs/xfs/xfs_log_cil.c
index bb17cc044bf..31e4ea2d19a 100644
--- a/fs/xfs/xfs_log_cil.c
+++ b/fs/xfs/xfs_log_cil.c
@@ -26,8 +26,6 @@
#include "xfs_log_priv.h"
#include "xfs_sb.h"
#include "xfs_ag.h"
-#include "xfs_dir2.h"
-#include "xfs_dmapi.h"
#include "xfs_mount.h"
#include "xfs_error.h"
#include "xfs_alloc.h"
@@ -554,7 +552,7 @@ xlog_cil_push(
thdr.th_type = XFS_TRANS_CHECKPOINT;
thdr.th_tid = tic->t_tid;
thdr.th_num_items = num_iovecs;
- lhdr.i_addr = (xfs_caddr_t)&thdr;
+ lhdr.i_addr = &thdr;
lhdr.i_len = sizeof(xfs_trans_header_t);
lhdr.i_type = XLOG_REG_TYPE_TRANSHDR;
tic->t_curr_res -= lhdr.i_len + sizeof(xlog_op_header_t);
diff --git a/fs/xfs/xfs_log_recover.c b/fs/xfs/xfs_log_recover.c
index 9ac5cfab27b..6f3f5fa37ac 100644
--- a/fs/xfs/xfs_log_recover.c
+++ b/fs/xfs/xfs_log_recover.c
@@ -24,15 +24,11 @@
#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_error.h"
#include "xfs_bmap_btree.h"
#include "xfs_alloc_btree.h"
#include "xfs_ialloc_btree.h"
-#include "xfs_dir2_sf.h"
-#include "xfs_attr_sf.h"
#include "xfs_dinode.h"
#include "xfs_inode.h"
#include "xfs_inode_item.h"
@@ -1565,9 +1561,7 @@ xlog_recover_reorder_trans(
list_splice_init(&trans->r_itemq, &sort_list);
list_for_each_entry_safe(item, n, &sort_list, ri_list) {
- xfs_buf_log_format_t *buf_f;
-
- buf_f = (xfs_buf_log_format_t *)item->ri_buf[0].i_addr;
+ xfs_buf_log_format_t *buf_f = item->ri_buf[0].i_addr;
switch (ITEM_TYPE(item)) {
case XFS_LI_BUF:
@@ -1892,9 +1886,8 @@ xlog_recover_do_inode_buffer(
* current di_next_unlinked field. Extract its value
* and copy it to the buffer copy.
*/
- logged_nextp = (xfs_agino_t *)
- ((char *)(item->ri_buf[item_index].i_addr) +
- (next_unlinked_offset - reg_buf_offset));
+ logged_nextp = item->ri_buf[item_index].i_addr +
+ next_unlinked_offset - reg_buf_offset;
if (unlikely(*logged_nextp == 0)) {
xfs_fs_cmn_err(CE_ALERT, mp,
"bad inode buffer log record (ptr = 0x%p, bp = 0x%p). XFS trying to replay bad (0) inode di_next_unlinked field",
@@ -1973,8 +1966,7 @@ xlog_recover_do_reg_buffer(
item->ri_buf[i].i_len, __func__);
goto next;
}
- error = xfs_qm_dqcheck((xfs_disk_dquot_t *)
- item->ri_buf[i].i_addr,
+ error = xfs_qm_dqcheck(item->ri_buf[i].i_addr,
-1, 0, XFS_QMOPT_DOWARN,
"dquot_buf_recover");
if (error)
@@ -2187,7 +2179,7 @@ xlog_recover_do_buffer_trans(
xlog_recover_item_t *item,
int pass)
{
- xfs_buf_log_format_t *buf_f;
+ xfs_buf_log_format_t *buf_f = item->ri_buf[0].i_addr;
xfs_mount_t *mp;
xfs_buf_t *bp;
int error;
@@ -2197,8 +2189,6 @@ xlog_recover_do_buffer_trans(
ushort flags;
uint buf_flags;
- buf_f = (xfs_buf_log_format_t *)item->ri_buf[0].i_addr;
-
if (pass == XLOG_RECOVER_PASS1) {
/*
* In this pass we're only looking for buf items
@@ -2319,10 +2309,9 @@ xlog_recover_do_inode_trans(
}
if (item->ri_buf[0].i_len == sizeof(xfs_inode_log_format_t)) {
- in_f = (xfs_inode_log_format_t *)item->ri_buf[0].i_addr;
+ in_f = item->ri_buf[0].i_addr;
} else {
- in_f = (xfs_inode_log_format_t *)kmem_alloc(
- sizeof(xfs_inode_log_format_t), KM_SLEEP);
+ in_f = kmem_alloc(sizeof(xfs_inode_log_format_t), KM_SLEEP);
need_free = 1;
error = xfs_inode_item_format_convert(&item->ri_buf[0], in_f);
if (error)
@@ -2370,7 +2359,7 @@ xlog_recover_do_inode_trans(
error = EFSCORRUPTED;
goto error;
}
- dicp = (xfs_icdinode_t *)(item->ri_buf[1].i_addr);
+ dicp = item->ri_buf[1].i_addr;
if (unlikely(dicp->di_magic != XFS_DINODE_MAGIC)) {
xfs_buf_relse(bp);
xfs_fs_cmn_err(CE_ALERT, mp,
@@ -2461,7 +2450,7 @@ xlog_recover_do_inode_trans(
}
/* The core is in in-core format */
- xfs_dinode_to_disk(dip, (xfs_icdinode_t *)item->ri_buf[1].i_addr);
+ xfs_dinode_to_disk(dip, item->ri_buf[1].i_addr);
/* the rest is in on-disk format */
if (item->ri_buf[1].i_len > sizeof(struct xfs_icdinode)) {
@@ -2578,7 +2567,7 @@ xlog_recover_do_quotaoff_trans(
return (0);
}
- qoff_f = (xfs_qoff_logformat_t *)item->ri_buf[0].i_addr;
+ qoff_f = item->ri_buf[0].i_addr;
ASSERT(qoff_f);
/*
@@ -2622,9 +2611,8 @@ xlog_recover_do_dquot_trans(
if (mp->m_qflags == 0)
return (0);
- recddq = (xfs_disk_dquot_t *)item->ri_buf[1].i_addr;
-
- if (item->ri_buf[1].i_addr == NULL) {
+ recddq = item->ri_buf[1].i_addr;
+ if (recddq == NULL) {
cmn_err(CE_ALERT,
"XFS: NULL dquot in %s.", __func__);
return XFS_ERROR(EIO);
@@ -2654,7 +2642,7 @@ xlog_recover_do_dquot_trans(
* The other possibility, of course, is that the quota subsystem was
* removed since the last mount - ENOSYS.
*/
- dq_f = (xfs_dq_logformat_t *)item->ri_buf[0].i_addr;
+ dq_f = item->ri_buf[0].i_addr;
ASSERT(dq_f);
if ((error = xfs_qm_dqcheck(recddq,
dq_f->qlf_id,
@@ -2721,7 +2709,7 @@ xlog_recover_do_efi_trans(
return 0;
}
- efi_formatp = (xfs_efi_log_format_t *)item->ri_buf[0].i_addr;
+ efi_formatp = item->ri_buf[0].i_addr;
mp = log->l_mp;
efip = xfs_efi_init(mp, efi_formatp->efi_nextents);
@@ -2767,7 +2755,7 @@ xlog_recover_do_efd_trans(
return;
}
- efd_formatp = (xfs_efd_log_format_t *)item->ri_buf[0].i_addr;
+ efd_formatp = item->ri_buf[0].i_addr;
ASSERT((item->ri_buf[0].i_len == (sizeof(xfs_efd_log_format_32_t) +
((efd_formatp->efd_nextents - 1) * sizeof(xfs_extent_32_t)))) ||
(item->ri_buf[0].i_len == (sizeof(xfs_efd_log_format_64_t) +
diff --git a/fs/xfs/xfs_mount.c b/fs/xfs/xfs_mount.c
index 69f62d8b281..aeb9d72ebf6 100644
--- a/fs/xfs/xfs_mount.c
+++ b/fs/xfs/xfs_mount.c
@@ -25,13 +25,10 @@
#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_alloc_btree.h"
#include "xfs_ialloc_btree.h"
-#include "xfs_dir2_sf.h"
-#include "xfs_attr_sf.h"
#include "xfs_dinode.h"
#include "xfs_inode.h"
#include "xfs_btree.h"
diff --git a/fs/xfs/xfs_mount.h b/fs/xfs/xfs_mount.h
index 5761087ee8e..622da2179a5 100644
--- a/fs/xfs/xfs_mount.h
+++ b/fs/xfs/xfs_mount.h
@@ -66,65 +66,6 @@ struct xfs_nameops;
struct xfs_ail;
struct xfs_quotainfo;
-
-/*
- * Prototypes and functions for the Data Migration subsystem.
- */
-
-typedef int (*xfs_send_data_t)(int, struct xfs_inode *,
- xfs_off_t, size_t, int, int *);
-typedef int (*xfs_send_mmap_t)(struct vm_area_struct *, uint);
-typedef int (*xfs_send_destroy_t)(struct xfs_inode *, dm_right_t);
-typedef int (*xfs_send_namesp_t)(dm_eventtype_t, struct xfs_mount *,
- struct xfs_inode *, dm_right_t,
- struct xfs_inode *, dm_right_t,
- const unsigned char *, const unsigned char *,
- mode_t, int, int);
-typedef int (*xfs_send_mount_t)(struct xfs_mount *, dm_right_t,
- char *, char *);
-typedef void (*xfs_send_unmount_t)(struct xfs_mount *, struct xfs_inode *,
- dm_right_t, mode_t, int, int);
-
-typedef struct xfs_dmops {
- xfs_send_data_t xfs_send_data;
- xfs_send_mmap_t xfs_send_mmap;
- xfs_send_destroy_t xfs_send_destroy;
- xfs_send_namesp_t xfs_send_namesp;
- xfs_send_mount_t xfs_send_mount;
- xfs_send_unmount_t xfs_send_unmount;
-} xfs_dmops_t;
-
-#define XFS_DMAPI_UNMOUNT_FLAGS(mp) \
- (((mp)->m_dmevmask & (1 << DM_EVENT_UNMOUNT)) ? 0 : DM_FLAGS_UNWANTED)
-
-#define XFS_SEND_DATA(mp, ev,ip,off,len,fl,lock) \
- (*(mp)->m_dm_ops->xfs_send_data)(ev,ip,off,len,fl,lock)
-#define XFS_SEND_MMAP(mp, vma,fl) \
- (*(mp)->m_dm_ops->xfs_send_mmap)(vma,fl)
-#define XFS_SEND_DESTROY(mp, ip,right) \
- (*(mp)->m_dm_ops->xfs_send_destroy)(ip,right)
-#define XFS_SEND_NAMESP(mp, ev,b1,r1,b2,r2,n1,n2,mode,rval,fl) \
- (*(mp)->m_dm_ops->xfs_send_namesp)(ev,NULL,b1,r1,b2,r2,n1,n2,mode,rval,fl)
-#define XFS_SEND_MOUNT(mp,right,path,name) \
- (*(mp)->m_dm_ops->xfs_send_mount)(mp,right,path,name)
-#define XFS_SEND_PREUNMOUNT(mp) \
-do { \
- if (mp->m_flags & XFS_MOUNT_DMAPI) { \
- (*(mp)->m_dm_ops->xfs_send_namesp)(DM_EVENT_PREUNMOUNT, mp, \
- (mp)->m_rootip, DM_RIGHT_NULL, \
- (mp)->m_rootip, DM_RIGHT_NULL, \
- NULL, NULL, 0, 0, XFS_DMAPI_UNMOUNT_FLAGS(mp)); \
- } \
-} while (0)
-#define XFS_SEND_UNMOUNT(mp) \
-do { \
- if (mp->m_flags & XFS_MOUNT_DMAPI) { \
- (*(mp)->m_dm_ops->xfs_send_unmount)(mp, (mp)->m_rootip, \
- DM_RIGHT_NULL, 0, 0, XFS_DMAPI_UNMOUNT_FLAGS(mp)); \
- } \
-} while (0)
-
-
#ifdef HAVE_PERCPU_SB
/*
@@ -241,8 +182,6 @@ typedef struct xfs_mount {
uint m_chsize; /* size of next field */
struct xfs_chash *m_chash; /* fs private inode per-cluster
* hash table */
- struct xfs_dmops *m_dm_ops; /* vector of DMI ops */
- struct xfs_qmops *m_qm_ops; /* vector of XQM ops */
atomic_t m_active_trans; /* number trans frozen */
#ifdef HAVE_PERCPU_SB
xfs_icsb_cnts_t __percpu *m_sb_cnts; /* per-cpu superblock counters */
@@ -269,7 +208,6 @@ typedef struct xfs_mount {
must be synchronous except
for space allocations */
#define XFS_MOUNT_DELAYLOG (1ULL << 1) /* delayed logging is enabled */
-#define XFS_MOUNT_DMAPI (1ULL << 2) /* dmapi is enabled */
#define XFS_MOUNT_WAS_CLEAN (1ULL << 3)
#define XFS_MOUNT_FS_SHUTDOWN (1ULL << 4) /* atomic stop of all filesystem
operations, typically for
@@ -282,8 +220,6 @@ typedef struct xfs_mount {
#define XFS_MOUNT_GRPID (1ULL << 9) /* group-ID assigned from directory */
#define XFS_MOUNT_NORECOVERY (1ULL << 10) /* no recovery - dirty fs */
#define XFS_MOUNT_DFLT_IOSIZE (1ULL << 12) /* set default i/o size */
-#define XFS_MOUNT_OSYNCISOSYNC (1ULL << 13) /* o_sync is REALLY o_sync */
- /* osyncisdsync is now default*/
#define XFS_MOUNT_32BITINODES (1ULL << 14) /* do not create inodes above
* 32 bits in size */
#define XFS_MOUNT_SMALL_INUMS (1ULL << 15) /* users wants 32bit inodes */
@@ -440,11 +376,6 @@ extern int xfs_sb_validate_fsb_count(struct xfs_sb *, __uint64_t);
extern int xfs_dev_is_read_only(struct xfs_mount *, char *);
-extern int xfs_dmops_get(struct xfs_mount *);
-extern void xfs_dmops_put(struct xfs_mount *);
-
-extern struct xfs_dmops xfs_dmcore_xfs;
-
#endif /* __KERNEL__ */
extern void xfs_mod_sb(struct xfs_trans *, __int64_t);
diff --git a/fs/xfs/xfs_rename.c b/fs/xfs/xfs_rename.c
index fc1cda23b81..8fca957200d 100644
--- a/fs/xfs/xfs_rename.c
+++ b/fs/xfs/xfs_rename.c
@@ -24,12 +24,9 @@
#include "xfs_sb.h"
#include "xfs_ag.h"
#include "xfs_dir2.h"
-#include "xfs_dmapi.h"
#include "xfs_mount.h"
#include "xfs_da_btree.h"
#include "xfs_bmap_btree.h"
-#include "xfs_dir2_sf.h"
-#include "xfs_attr_sf.h"
#include "xfs_dinode.h"
#include "xfs_inode.h"
#include "xfs_inode_item.h"
@@ -116,20 +113,7 @@ xfs_rename(
int spaceres;
int num_inodes;
- xfs_itrace_entry(src_dp);
- xfs_itrace_entry(target_dp);
-
- if (DM_EVENT_ENABLED(src_dp, DM_EVENT_RENAME) ||
- DM_EVENT_ENABLED(target_dp, DM_EVENT_RENAME)) {
- error = XFS_SEND_NAMESP(mp, DM_EVENT_RENAME,
- src_dp, DM_RIGHT_NULL,
- target_dp, DM_RIGHT_NULL,
- src_name->name, target_name->name,
- 0, 0, 0);
- if (error)
- return error;
- }
- /* Return through std_return after this point. */
+ trace_xfs_rename(src_dp, target_dp, src_name, target_name);
new_parent = (src_dp != target_dp);
src_is_directory = ((src_ip->i_d.di_mode & S_IFMT) == S_IFDIR);
@@ -184,26 +168,14 @@ xfs_rename(
/*
* Join all the inodes to the transaction. From this point on,
* we can rely on either trans_commit or trans_cancel to unlock
- * them. Note that we need to add a vnode reference to the
- * directories since trans_commit & trans_cancel will decrement
- * them when they unlock the inodes. Also, we need to be careful
- * not to add an inode to the transaction more than once.
+ * them.
*/
- IHOLD(src_dp);
- xfs_trans_ijoin(tp, src_dp, XFS_ILOCK_EXCL);
-
- if (new_parent) {
- IHOLD(target_dp);
- xfs_trans_ijoin(tp, target_dp, XFS_ILOCK_EXCL);
- }
-
- IHOLD(src_ip);
- xfs_trans_ijoin(tp, src_ip, XFS_ILOCK_EXCL);
-
- if (target_ip) {
- IHOLD(target_ip);
- xfs_trans_ijoin(tp, target_ip, XFS_ILOCK_EXCL);
- }
+ xfs_trans_ijoin_ref(tp, src_dp, XFS_ILOCK_EXCL);
+ if (new_parent)
+ xfs_trans_ijoin_ref(tp, target_dp, XFS_ILOCK_EXCL);
+ xfs_trans_ijoin_ref(tp, src_ip, XFS_ILOCK_EXCL);
+ if (target_ip)
+ xfs_trans_ijoin_ref(tp, target_ip, XFS_ILOCK_EXCL);
/*
* If we are using project inheritance, we only allow renames
@@ -369,26 +341,13 @@ xfs_rename(
* trans_commit will unlock src_ip, target_ip & decrement
* the vnode references.
*/
- error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES);
-
- /* Fall through to std_return with error = 0 or errno from
- * xfs_trans_commit */
-std_return:
- if (DM_EVENT_ENABLED(src_dp, DM_EVENT_POSTRENAME) ||
- DM_EVENT_ENABLED(target_dp, DM_EVENT_POSTRENAME)) {
- (void) XFS_SEND_NAMESP (mp, DM_EVENT_POSTRENAME,
- src_dp, DM_RIGHT_NULL,
- target_dp, DM_RIGHT_NULL,
- src_name->name, target_name->name,
- 0, error, 0);
- }
- return error;
+ return xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES);
abort_return:
cancel_flags |= XFS_TRANS_ABORT;
- /* FALLTHROUGH */
error_return:
xfs_bmap_cancel(&free_list);
xfs_trans_cancel(tp, cancel_flags);
- goto std_return;
+ std_return:
+ return error;
}
diff --git a/fs/xfs/xfs_rtalloc.c b/fs/xfs/xfs_rtalloc.c
index a2d32ce335a..891260fea11 100644
--- a/fs/xfs/xfs_rtalloc.c
+++ b/fs/xfs/xfs_rtalloc.c
@@ -25,17 +25,10 @@
#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_alloc_btree.h"
-#include "xfs_ialloc_btree.h"
-#include "xfs_dir2_sf.h"
-#include "xfs_attr_sf.h"
#include "xfs_dinode.h"
#include "xfs_inode.h"
-#include "xfs_btree.h"
-#include "xfs_ialloc.h"
#include "xfs_alloc.h"
#include "xfs_bmap.h"
#include "xfs_rtalloc.h"
@@ -129,7 +122,7 @@ xfs_growfs_rt_alloc(
cancelflags |= XFS_TRANS_ABORT;
error = xfs_bmapi(tp, ip, oblocks, nblocks - oblocks,
XFS_BMAPI_WRITE | XFS_BMAPI_METADATA, &firstblock,
- resblks, &map, &nmap, &flist, NULL);
+ resblks, &map, &nmap, &flist);
if (!error && nmap < 1)
error = XFS_ERROR(ENOSPC);
if (error)
diff --git a/fs/xfs/xfs_rw.c b/fs/xfs/xfs_rw.c
index e336742a58a..56861d5daae 100644
--- a/fs/xfs/xfs_rw.c
+++ b/fs/xfs/xfs_rw.c
@@ -24,27 +24,12 @@
#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_alloc_btree.h"
-#include "xfs_ialloc_btree.h"
-#include "xfs_dir2_sf.h"
-#include "xfs_attr_sf.h"
#include "xfs_dinode.h"
#include "xfs_inode.h"
-#include "xfs_inode_item.h"
-#include "xfs_itable.h"
-#include "xfs_btree.h"
-#include "xfs_alloc.h"
-#include "xfs_ialloc.h"
-#include "xfs_attr.h"
-#include "xfs_bmap.h"
#include "xfs_error.h"
-#include "xfs_buf_item.h"
#include "xfs_rw.h"
-#include "xfs_trace.h"
/*
* Force a shutdown of the filesystem instantly while keeping
diff --git a/fs/xfs/xfs_trans.c b/fs/xfs/xfs_trans.c
index 28547dfce03..fdca7416c75 100644
--- a/fs/xfs/xfs_trans.c
+++ b/fs/xfs/xfs_trans.c
@@ -1,5 +1,6 @@
/*
* Copyright (c) 2000-2003,2005 Silicon Graphics, Inc.
+ * Copyright (C) 2010 Red Hat, Inc.
* All Rights Reserved.
*
* This program is free software; you can redistribute it and/or
@@ -24,16 +25,12 @@
#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_error.h"
#include "xfs_da_btree.h"
#include "xfs_bmap_btree.h"
#include "xfs_alloc_btree.h"
#include "xfs_ialloc_btree.h"
-#include "xfs_dir2_sf.h"
-#include "xfs_attr_sf.h"
#include "xfs_dinode.h"
#include "xfs_inode.h"
#include "xfs_btree.h"
@@ -47,6 +44,7 @@
#include "xfs_trace.h"
kmem_zone_t *xfs_trans_zone;
+kmem_zone_t *xfs_log_item_desc_zone;
/*
@@ -597,8 +595,7 @@ _xfs_trans_alloc(
tp->t_magic = XFS_TRANS_MAGIC;
tp->t_type = type;
tp->t_mountp = mp;
- tp->t_items_free = XFS_LIC_NUM_SLOTS;
- xfs_lic_init(&(tp->t_items));
+ INIT_LIST_HEAD(&tp->t_items);
INIT_LIST_HEAD(&tp->t_busy);
return tp;
}
@@ -643,8 +640,7 @@ xfs_trans_dup(
ntp->t_magic = XFS_TRANS_MAGIC;
ntp->t_type = tp->t_type;
ntp->t_mountp = tp->t_mountp;
- ntp->t_items_free = XFS_LIC_NUM_SLOTS;
- xfs_lic_init(&(ntp->t_items));
+ INIT_LIST_HEAD(&ntp->t_items);
INIT_LIST_HEAD(&ntp->t_busy);
ASSERT(tp->t_flags & XFS_TRANS_PERM_LOG_RES);
@@ -1124,6 +1120,108 @@ xfs_trans_unreserve_and_mod_sb(
}
/*
+ * Add the given log item to the transaction's list of log items.
+ *
+ * The log item will now point to its new descriptor with its li_desc field.
+ */
+void
+xfs_trans_add_item(
+ struct xfs_trans *tp,
+ struct xfs_log_item *lip)
+{
+ struct xfs_log_item_desc *lidp;
+
+ ASSERT(lip->li_mountp = tp->t_mountp);
+ ASSERT(lip->li_ailp = tp->t_mountp->m_ail);
+
+ lidp = kmem_zone_zalloc(xfs_log_item_desc_zone, KM_SLEEP | KM_NOFS);
+
+ lidp->lid_item = lip;
+ lidp->lid_flags = 0;
+ lidp->lid_size = 0;
+ list_add_tail(&lidp->lid_trans, &tp->t_items);
+
+ lip->li_desc = lidp;
+}
+
+STATIC void
+xfs_trans_free_item_desc(
+ struct xfs_log_item_desc *lidp)
+{
+ list_del_init(&lidp->lid_trans);
+ kmem_zone_free(xfs_log_item_desc_zone, lidp);
+}
+
+/*
+ * Unlink and free the given descriptor.
+ */
+void
+xfs_trans_del_item(
+ struct xfs_log_item *lip)
+{
+ xfs_trans_free_item_desc(lip->li_desc);
+ lip->li_desc = NULL;
+}
+
+/*
+ * Unlock all of the items of a transaction and free all the descriptors
+ * of that transaction.
+ */
+STATIC void
+xfs_trans_free_items(
+ struct xfs_trans *tp,
+ xfs_lsn_t commit_lsn,
+ int flags)
+{
+ struct xfs_log_item_desc *lidp, *next;
+
+ list_for_each_entry_safe(lidp, next, &tp->t_items, lid_trans) {
+ struct xfs_log_item *lip = lidp->lid_item;
+
+ lip->li_desc = NULL;
+
+ if (commit_lsn != NULLCOMMITLSN)
+ IOP_COMMITTING(lip, commit_lsn);
+ if (flags & XFS_TRANS_ABORT)
+ lip->li_flags |= XFS_LI_ABORTED;
+ IOP_UNLOCK(lip);
+
+ xfs_trans_free_item_desc(lidp);
+ }
+}
+
+/*
+ * Unlock the items associated with a transaction.
+ *
+ * Items which were not logged should be freed. Those which were logged must
+ * still be tracked so they can be unpinned when the transaction commits.
+ */
+STATIC void
+xfs_trans_unlock_items(
+ struct xfs_trans *tp,
+ xfs_lsn_t commit_lsn)
+{
+ struct xfs_log_item_desc *lidp, *next;
+
+ list_for_each_entry_safe(lidp, next, &tp->t_items, lid_trans) {
+ struct xfs_log_item *lip = lidp->lid_item;
+
+ lip->li_desc = NULL;
+
+ if (commit_lsn != NULLCOMMITLSN)
+ IOP_COMMITTING(lip, commit_lsn);
+ IOP_UNLOCK(lip);
+
+ /*
+ * Free the descriptor if the item is not dirty
+ * within this transaction.
+ */
+ if (!(lidp->lid_flags & XFS_LID_DIRTY))
+ xfs_trans_free_item_desc(lidp);
+ }
+}
+
+/*
* Total up the number of log iovecs needed to commit this
* transaction. The transaction itself needs one for the
* transaction header. Ask each dirty item in turn how many
@@ -1134,30 +1232,27 @@ xfs_trans_count_vecs(
struct xfs_trans *tp)
{
int nvecs;
- xfs_log_item_desc_t *lidp;
+ struct xfs_log_item_desc *lidp;
nvecs = 1;
- lidp = xfs_trans_first_item(tp);
- ASSERT(lidp != NULL);
/* In the non-debug case we need to start bailing out if we
* didn't find a log_item here, return zero and let trans_commit
* deal with it.
*/
- if (lidp == NULL)
+ if (list_empty(&tp->t_items)) {
+ ASSERT(0);
return 0;
+ }
- while (lidp != NULL) {
+ list_for_each_entry(lidp, &tp->t_items, lid_trans) {
/*
* Skip items which aren't dirty in this transaction.
*/
- if (!(lidp->lid_flags & XFS_LID_DIRTY)) {
- lidp = xfs_trans_next_item(tp, lidp);
+ if (!(lidp->lid_flags & XFS_LID_DIRTY))
continue;
- }
lidp->lid_size = IOP_SIZE(lidp->lid_item);
nvecs += lidp->lid_size;
- lidp = xfs_trans_next_item(tp, lidp);
}
return nvecs;
@@ -1177,7 +1272,7 @@ xfs_trans_fill_vecs(
struct xfs_trans *tp,
struct xfs_log_iovec *log_vector)
{
- xfs_log_item_desc_t *lidp;
+ struct xfs_log_item_desc *lidp;
struct xfs_log_iovec *vecp;
uint nitems;
@@ -1188,14 +1283,11 @@ xfs_trans_fill_vecs(
vecp = log_vector + 1;
nitems = 0;
- lidp = xfs_trans_first_item(tp);
- ASSERT(lidp);
- while (lidp) {
+ ASSERT(!list_empty(&tp->t_items));
+ list_for_each_entry(lidp, &tp->t_items, lid_trans) {
/* Skip items which aren't dirty in this transaction. */
- if (!(lidp->lid_flags & XFS_LID_DIRTY)) {
- lidp = xfs_trans_next_item(tp, lidp);
+ if (!(lidp->lid_flags & XFS_LID_DIRTY))
continue;
- }
/*
* The item may be marked dirty but not log anything. This can
@@ -1206,7 +1298,6 @@ xfs_trans_fill_vecs(
IOP_FORMAT(lidp->lid_item, vecp);
vecp += lidp->lid_size;
IOP_PIN(lidp->lid_item);
- lidp = xfs_trans_next_item(tp, lidp);
}
/*
@@ -1284,7 +1375,7 @@ xfs_trans_item_committed(
* log item flags, if anyone else stales the buffer we do not want to
* pay any attention to it.
*/
- IOP_UNPIN(lip);
+ IOP_UNPIN(lip, 0);
}
/*
@@ -1301,24 +1392,15 @@ xfs_trans_committed(
struct xfs_trans *tp,
int abortflag)
{
- xfs_log_item_desc_t *lidp;
- xfs_log_item_chunk_t *licp;
- xfs_log_item_chunk_t *next_licp;
+ struct xfs_log_item_desc *lidp, *next;
/* Call the transaction's completion callback if there is one. */
if (tp->t_callback != NULL)
tp->t_callback(tp, tp->t_callarg);
- for (lidp = xfs_trans_first_item(tp);
- lidp != NULL;
- lidp = xfs_trans_next_item(tp, lidp)) {
+ list_for_each_entry_safe(lidp, next, &tp->t_items, lid_trans) {
xfs_trans_item_committed(lidp->lid_item, tp->t_lsn, abortflag);
- }
-
- /* free the item chunks, ignoring the embedded chunk */
- for (licp = tp->t_items.lic_next; licp != NULL; licp = next_licp) {
- next_licp = licp->lic_next;
- kmem_free(licp);
+ xfs_trans_free_item_desc(lidp);
}
xfs_trans_free(tp);
@@ -1333,16 +1415,14 @@ xfs_trans_uncommit(
struct xfs_trans *tp,
uint flags)
{
- xfs_log_item_desc_t *lidp;
+ struct xfs_log_item_desc *lidp;
- for (lidp = xfs_trans_first_item(tp);
- lidp != NULL;
- lidp = xfs_trans_next_item(tp, lidp)) {
+ list_for_each_entry(lidp, &tp->t_items, lid_trans) {
/*
* Unpin all but those that aren't dirty.
*/
if (lidp->lid_flags & XFS_LID_DIRTY)
- IOP_UNPIN_REMOVE(lidp->lid_item, tp);
+ IOP_UNPIN(lidp->lid_item, 1);
}
xfs_trans_unreserve_and_mod_sb(tp);
@@ -1508,33 +1588,28 @@ STATIC struct xfs_log_vec *
xfs_trans_alloc_log_vecs(
xfs_trans_t *tp)
{
- xfs_log_item_desc_t *lidp;
+ struct xfs_log_item_desc *lidp;
struct xfs_log_vec *lv = NULL;
struct xfs_log_vec *ret_lv = NULL;
- lidp = xfs_trans_first_item(tp);
/* Bail out if we didn't find a log item. */
- if (!lidp) {
+ if (list_empty(&tp->t_items)) {
ASSERT(0);
return NULL;
}
- while (lidp != NULL) {
+ list_for_each_entry(lidp, &tp->t_items, lid_trans) {
struct xfs_log_vec *new_lv;
/* Skip items which aren't dirty in this transaction. */
- if (!(lidp->lid_flags & XFS_LID_DIRTY)) {
- lidp = xfs_trans_next_item(tp, lidp);
+ if (!(lidp->lid_flags & XFS_LID_DIRTY))
continue;
- }
/* Skip items that do not have any vectors for writing */
lidp->lid_size = IOP_SIZE(lidp->lid_item);
- if (!lidp->lid_size) {
- lidp = xfs_trans_next_item(tp, lidp);
+ if (!lidp->lid_size)
continue;
- }
new_lv = kmem_zalloc(sizeof(*new_lv) +
lidp->lid_size * sizeof(struct xfs_log_iovec),
@@ -1549,7 +1624,6 @@ xfs_trans_alloc_log_vecs(
else
lv->lv_next = new_lv;
lv = new_lv;
- lidp = xfs_trans_next_item(tp, lidp);
}
return ret_lv;
@@ -1708,12 +1782,6 @@ xfs_trans_cancel(
int flags)
{
int log_flags;
-#ifdef DEBUG
- xfs_log_item_chunk_t *licp;
- xfs_log_item_desc_t *lidp;
- xfs_log_item_t *lip;
- int i;
-#endif
xfs_mount_t *mp = tp->t_mountp;
/*
@@ -1732,21 +1800,11 @@ xfs_trans_cancel(
xfs_force_shutdown(mp, SHUTDOWN_CORRUPT_INCORE);
}
#ifdef DEBUG
- if (!(flags & XFS_TRANS_ABORT)) {
- licp = &(tp->t_items);
- while (licp != NULL) {
- lidp = licp->lic_descs;
- for (i = 0; i < licp->lic_unused; i++, lidp++) {
- if (xfs_lic_isfree(licp, i)) {
- continue;
- }
-
- lip = lidp->lid_item;
- if (!XFS_FORCED_SHUTDOWN(mp))
- ASSERT(!(lip->li_type == XFS_LI_EFD));
- }
- licp = licp->lic_next;
- }
+ if (!(flags & XFS_TRANS_ABORT) && !XFS_FORCED_SHUTDOWN(mp)) {
+ struct xfs_log_item_desc *lidp;
+
+ list_for_each_entry(lidp, &tp->t_items, lid_trans)
+ ASSERT(!(lidp->lid_item->li_type == XFS_LI_EFD));
}
#endif
xfs_trans_unreserve_and_mod_sb(tp);
@@ -1834,7 +1892,6 @@ xfs_trans_roll(
if (error)
return error;
- xfs_trans_ijoin(trans, dp, XFS_ILOCK_EXCL);
- xfs_trans_ihold(trans, dp);
+ xfs_trans_ijoin(trans, dp);
return 0;
}
diff --git a/fs/xfs/xfs_trans.h b/fs/xfs/xfs_trans.h
index e639e8e9a2a..c13c0f97b49 100644
--- a/fs/xfs/xfs_trans.h
+++ b/fs/xfs/xfs_trans.h
@@ -161,105 +161,14 @@ typedef struct xfs_trans_header {
* the amount of space needed to log the item it describes
* once we get to commit processing (see xfs_trans_commit()).
*/
-typedef struct xfs_log_item_desc {
+struct xfs_log_item_desc {
struct xfs_log_item *lid_item;
- ushort lid_size;
- unsigned char lid_flags;
- unsigned char lid_index;
-} xfs_log_item_desc_t;
+ ushort lid_size;
+ unsigned char lid_flags;
+ struct list_head lid_trans;
+};
#define XFS_LID_DIRTY 0x1
-#define XFS_LID_PINNED 0x2
-
-/*
- * This structure is used to maintain a chunk list of log_item_desc
- * structures. The free field is a bitmask indicating which descriptors
- * in this chunk's array are free. The unused field is the first value
- * not used since this chunk was allocated.
- */
-#define XFS_LIC_NUM_SLOTS 15
-typedef struct xfs_log_item_chunk {
- struct xfs_log_item_chunk *lic_next;
- ushort lic_free;
- ushort lic_unused;
- xfs_log_item_desc_t lic_descs[XFS_LIC_NUM_SLOTS];
-} xfs_log_item_chunk_t;
-
-#define XFS_LIC_MAX_SLOT (XFS_LIC_NUM_SLOTS - 1)
-#define XFS_LIC_FREEMASK ((1 << XFS_LIC_NUM_SLOTS) - 1)
-
-
-/*
- * Initialize the given chunk. Set the chunk's free descriptor mask
- * to indicate that all descriptors are free. The caller gets to set
- * lic_unused to the right value (0 matches all free). The
- * lic_descs.lid_index values are set up as each desc is allocated.
- */
-static inline void xfs_lic_init(xfs_log_item_chunk_t *cp)
-{
- cp->lic_free = XFS_LIC_FREEMASK;
-}
-
-static inline void xfs_lic_init_slot(xfs_log_item_chunk_t *cp, int slot)
-{
- cp->lic_descs[slot].lid_index = (unsigned char)(slot);
-}
-
-static inline int xfs_lic_vacancy(xfs_log_item_chunk_t *cp)
-{
- return cp->lic_free & XFS_LIC_FREEMASK;
-}
-
-static inline void xfs_lic_all_free(xfs_log_item_chunk_t *cp)
-{
- cp->lic_free = XFS_LIC_FREEMASK;
-}
-
-static inline int xfs_lic_are_all_free(xfs_log_item_chunk_t *cp)
-{
- return ((cp->lic_free & XFS_LIC_FREEMASK) == XFS_LIC_FREEMASK);
-}
-
-static inline int xfs_lic_isfree(xfs_log_item_chunk_t *cp, int slot)
-{
- return (cp->lic_free & (1 << slot));
-}
-
-static inline void xfs_lic_claim(xfs_log_item_chunk_t *cp, int slot)
-{
- cp->lic_free &= ~(1 << slot);
-}
-
-static inline void xfs_lic_relse(xfs_log_item_chunk_t *cp, int slot)
-{
- cp->lic_free |= 1 << slot;
-}
-
-static inline xfs_log_item_desc_t *
-xfs_lic_slot(xfs_log_item_chunk_t *cp, int slot)
-{
- return &(cp->lic_descs[slot]);
-}
-
-static inline int xfs_lic_desc_to_slot(xfs_log_item_desc_t *dp)
-{
- return (uint)dp->lid_index;
-}
-
-/*
- * Calculate the address of a chunk given a descriptor pointer:
- * dp - dp->lid_index give the address of the start of the lic_descs array.
- * From this we subtract the offset of the lic_descs field in a chunk.
- * All of this yields the address of the chunk, which is
- * cast to a chunk pointer.
- */
-static inline xfs_log_item_chunk_t *
-xfs_lic_desc_to_chunk(xfs_log_item_desc_t *dp)
-{
- return (xfs_log_item_chunk_t*) \
- (((xfs_caddr_t)((dp) - (dp)->lid_index)) - \
- (xfs_caddr_t)(((xfs_log_item_chunk_t*)0)->lic_descs));
-}
#define XFS_TRANS_MAGIC 0x5452414E /* 'TRAN' */
/*
@@ -275,8 +184,6 @@ xfs_lic_desc_to_chunk(xfs_log_item_desc_t *dp)
/*
* Values for call flags parameter.
*/
-#define XFS_TRANS_NOSLEEP 0x1
-#define XFS_TRANS_WAIT 0x2
#define XFS_TRANS_RELEASE_LOG_RES 0x4
#define XFS_TRANS_ABORT 0x8
@@ -438,8 +345,7 @@ typedef struct xfs_item_ops {
uint (*iop_size)(xfs_log_item_t *);
void (*iop_format)(xfs_log_item_t *, struct xfs_log_iovec *);
void (*iop_pin)(xfs_log_item_t *);
- void (*iop_unpin)(xfs_log_item_t *);
- void (*iop_unpin_remove)(xfs_log_item_t *, struct xfs_trans *);
+ void (*iop_unpin)(xfs_log_item_t *, int remove);
uint (*iop_trylock)(xfs_log_item_t *);
void (*iop_unlock)(xfs_log_item_t *);
xfs_lsn_t (*iop_committed)(xfs_log_item_t *, xfs_lsn_t);
@@ -451,8 +357,7 @@ typedef struct xfs_item_ops {
#define IOP_SIZE(ip) (*(ip)->li_ops->iop_size)(ip)
#define IOP_FORMAT(ip,vp) (*(ip)->li_ops->iop_format)(ip, vp)
#define IOP_PIN(ip) (*(ip)->li_ops->iop_pin)(ip)
-#define IOP_UNPIN(ip) (*(ip)->li_ops->iop_unpin)(ip)
-#define IOP_UNPIN_REMOVE(ip,tp) (*(ip)->li_ops->iop_unpin_remove)(ip, tp)
+#define IOP_UNPIN(ip, remove) (*(ip)->li_ops->iop_unpin)(ip, remove)
#define IOP_TRYLOCK(ip) (*(ip)->li_ops->iop_trylock)(ip)
#define IOP_UNLOCK(ip) (*(ip)->li_ops->iop_unlock)(ip)
#define IOP_COMMITTED(ip, lsn) (*(ip)->li_ops->iop_committed)(ip, lsn)
@@ -516,8 +421,7 @@ typedef struct xfs_trans {
int64_t t_rblocks_delta;/* superblock rblocks change */
int64_t t_rextents_delta;/* superblocks rextents chg */
int64_t t_rextslog_delta;/* superblocks rextslog chg */
- unsigned int t_items_free; /* log item descs free */
- xfs_log_item_chunk_t t_items; /* first log item desc chunk */
+ struct list_head t_items; /* log item descriptors */
xfs_trans_header_t t_header; /* header for in-log trans */
struct list_head t_busy; /* list of busy extents */
unsigned long t_pflags; /* saved process flags state */
@@ -569,8 +473,8 @@ void xfs_trans_dquot_buf(xfs_trans_t *, struct xfs_buf *, uint);
void xfs_trans_inode_alloc_buf(xfs_trans_t *, struct xfs_buf *);
int xfs_trans_iget(struct xfs_mount *, xfs_trans_t *,
xfs_ino_t , uint, uint, struct xfs_inode **);
-void xfs_trans_ijoin(xfs_trans_t *, struct xfs_inode *, uint);
-void xfs_trans_ihold(xfs_trans_t *, struct xfs_inode *);
+void xfs_trans_ijoin_ref(struct xfs_trans *, struct xfs_inode *, uint);
+void xfs_trans_ijoin(struct xfs_trans *, struct xfs_inode *);
void xfs_trans_log_buf(xfs_trans_t *, struct xfs_buf *, uint, uint);
void xfs_trans_log_inode(xfs_trans_t *, struct xfs_inode *, uint);
struct xfs_efi_log_item *xfs_trans_get_efi(xfs_trans_t *, uint);
@@ -595,6 +499,7 @@ int xfs_trans_ail_init(struct xfs_mount *);
void xfs_trans_ail_destroy(struct xfs_mount *);
extern kmem_zone_t *xfs_trans_zone;
+extern kmem_zone_t *xfs_log_item_desc_zone;
#endif /* __KERNEL__ */
diff --git a/fs/xfs/xfs_trans_ail.c b/fs/xfs/xfs_trans_ail.c
index e799824f724..dc9069568ff 100644
--- a/fs/xfs/xfs_trans_ail.c
+++ b/fs/xfs/xfs_trans_ail.c
@@ -24,7 +24,6 @@
#include "xfs_trans.h"
#include "xfs_sb.h"
#include "xfs_ag.h"
-#include "xfs_dmapi.h"
#include "xfs_mount.h"
#include "xfs_trans_priv.h"
#include "xfs_error.h"
diff --git a/fs/xfs/xfs_trans_buf.c b/fs/xfs/xfs_trans_buf.c
index 63d81a22f4f..90af025e683 100644
--- a/fs/xfs/xfs_trans_buf.c
+++ b/fs/xfs/xfs_trans_buf.c
@@ -24,14 +24,10 @@
#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_alloc_btree.h"
#include "xfs_ialloc_btree.h"
-#include "xfs_dir2_sf.h"
-#include "xfs_attr_sf.h"
#include "xfs_dinode.h"
#include "xfs_inode.h"
#include "xfs_buf_item.h"
@@ -51,36 +47,17 @@ xfs_trans_buf_item_match(
xfs_daddr_t blkno,
int len)
{
- xfs_log_item_chunk_t *licp;
- xfs_log_item_desc_t *lidp;
- xfs_buf_log_item_t *blip;
- int i;
+ struct xfs_log_item_desc *lidp;
+ struct xfs_buf_log_item *blip;
len = BBTOB(len);
- for (licp = &tp->t_items; licp != NULL; licp = licp->lic_next) {
- if (xfs_lic_are_all_free(licp)) {
- ASSERT(licp == &tp->t_items);
- ASSERT(licp->lic_next == NULL);
- return NULL;
- }
-
- for (i = 0; i < licp->lic_unused; i++) {
- /*
- * Skip unoccupied slots.
- */
- if (xfs_lic_isfree(licp, i))
- continue;
-
- lidp = xfs_lic_slot(licp, i);
- blip = (xfs_buf_log_item_t *)lidp->lid_item;
- if (blip->bli_item.li_type != XFS_LI_BUF)
- continue;
-
- if (XFS_BUF_TARGET(blip->bli_buf) == target &&
- XFS_BUF_ADDR(blip->bli_buf) == blkno &&
- XFS_BUF_COUNT(blip->bli_buf) == len)
- return blip->bli_buf;
- }
+ list_for_each_entry(lidp, &tp->t_items, lid_trans) {
+ blip = (struct xfs_buf_log_item *)lidp->lid_item;
+ if (blip->bli_item.li_type == XFS_LI_BUF &&
+ XFS_BUF_TARGET(blip->bli_buf) == target &&
+ XFS_BUF_ADDR(blip->bli_buf) == blkno &&
+ XFS_BUF_COUNT(blip->bli_buf) == len)
+ return blip->bli_buf;
}
return NULL;
@@ -127,7 +104,7 @@ _xfs_trans_bjoin(
/*
* Get a log_item_desc to point at the new item.
*/
- (void) xfs_trans_add_item(tp, (xfs_log_item_t *)bip);
+ xfs_trans_add_item(tp, &bip->bli_item);
/*
* Initialize b_fsprivate2 so we can find it with incore_match()
@@ -483,7 +460,6 @@ xfs_trans_brelse(xfs_trans_t *tp,
{
xfs_buf_log_item_t *bip;
xfs_log_item_t *lip;
- xfs_log_item_desc_t *lidp;
/*
* Default to a normal brelse() call if the tp is NULL.
@@ -514,13 +490,6 @@ xfs_trans_brelse(xfs_trans_t *tp,
ASSERT(!(bip->bli_format.blf_flags & XFS_BLF_CANCEL));
ASSERT(atomic_read(&bip->bli_refcount) > 0);
- /*
- * Find the item descriptor pointing to this buffer's
- * log item. It must be there.
- */
- lidp = xfs_trans_find_item(tp, (xfs_log_item_t*)bip);
- ASSERT(lidp != NULL);
-
trace_xfs_trans_brelse(bip);
/*
@@ -536,7 +505,7 @@ xfs_trans_brelse(xfs_trans_t *tp,
* If the buffer is dirty within this transaction, we can't
* release it until we commit.
*/
- if (lidp->lid_flags & XFS_LID_DIRTY)
+ if (bip->bli_item.li_desc->lid_flags & XFS_LID_DIRTY)
return;
/*
@@ -553,7 +522,7 @@ xfs_trans_brelse(xfs_trans_t *tp,
/*
* Free up the log item descriptor tracking the released item.
*/
- xfs_trans_free_item(tp, lidp);
+ xfs_trans_del_item(&bip->bli_item);
/*
* Clear the hold flag in the buf log item if it is set.
@@ -665,7 +634,6 @@ xfs_trans_log_buf(xfs_trans_t *tp,
uint last)
{
xfs_buf_log_item_t *bip;
- xfs_log_item_desc_t *lidp;
ASSERT(XFS_BUF_ISBUSY(bp));
ASSERT(XFS_BUF_FSPRIVATE2(bp, xfs_trans_t *) == tp);
@@ -690,7 +658,7 @@ xfs_trans_log_buf(xfs_trans_t *tp,
bip = XFS_BUF_FSPRIVATE(bp, xfs_buf_log_item_t *);
ASSERT(atomic_read(&bip->bli_refcount) > 0);
XFS_BUF_SET_IODONE_FUNC(bp, xfs_buf_iodone_callbacks);
- bip->bli_item.li_cb = (void(*)(xfs_buf_t*,xfs_log_item_t*))xfs_buf_iodone;
+ bip->bli_item.li_cb = xfs_buf_iodone;
trace_xfs_trans_log_buf(bip);
@@ -707,11 +675,8 @@ xfs_trans_log_buf(xfs_trans_t *tp,
bip->bli_format.blf_flags &= ~XFS_BLF_CANCEL;
}
- lidp = xfs_trans_find_item(tp, (xfs_log_item_t*)bip);
- ASSERT(lidp != NULL);
-
tp->t_flags |= XFS_TRANS_DIRTY;
- lidp->lid_flags |= XFS_LID_DIRTY;
+ bip->bli_item.li_desc->lid_flags |= XFS_LID_DIRTY;
bip->bli_flags |= XFS_BLI_LOGGED;
xfs_buf_item_log(bip, first, last);
}
@@ -740,7 +705,6 @@ xfs_trans_binval(
xfs_trans_t *tp,
xfs_buf_t *bp)
{
- xfs_log_item_desc_t *lidp;
xfs_buf_log_item_t *bip;
ASSERT(XFS_BUF_ISBUSY(bp));
@@ -748,8 +712,6 @@ xfs_trans_binval(
ASSERT(XFS_BUF_FSPRIVATE(bp, void *) != NULL);
bip = XFS_BUF_FSPRIVATE(bp, xfs_buf_log_item_t *);
- lidp = xfs_trans_find_item(tp, (xfs_log_item_t*)bip);
- ASSERT(lidp != NULL);
ASSERT(atomic_read(&bip->bli_refcount) > 0);
trace_xfs_trans_binval(bip);
@@ -764,7 +726,7 @@ xfs_trans_binval(
ASSERT(!(bip->bli_flags & (XFS_BLI_LOGGED | XFS_BLI_DIRTY)));
ASSERT(!(bip->bli_format.blf_flags & XFS_BLF_INODE_BUF));
ASSERT(bip->bli_format.blf_flags & XFS_BLF_CANCEL);
- ASSERT(lidp->lid_flags & XFS_LID_DIRTY);
+ ASSERT(bip->bli_item.li_desc->lid_flags & XFS_LID_DIRTY);
ASSERT(tp->t_flags & XFS_TRANS_DIRTY);
return;
}
@@ -797,7 +759,7 @@ xfs_trans_binval(
bip->bli_format.blf_flags |= XFS_BLF_CANCEL;
memset((char *)(bip->bli_format.blf_data_map), 0,
(bip->bli_format.blf_map_size * sizeof(uint)));
- lidp->lid_flags |= XFS_LID_DIRTY;
+ bip->bli_item.li_desc->lid_flags |= XFS_LID_DIRTY;
tp->t_flags |= XFS_TRANS_DIRTY;
}
@@ -853,12 +815,9 @@ xfs_trans_stale_inode_buf(
ASSERT(atomic_read(&bip->bli_refcount) > 0);
bip->bli_flags |= XFS_BLI_STALE_INODE;
- bip->bli_item.li_cb = (void(*)(xfs_buf_t*,xfs_log_item_t*))
- xfs_buf_iodone;
+ bip->bli_item.li_cb = xfs_buf_iodone;
}
-
-
/*
* Mark the buffer as being one which contains newly allocated
* inodes. We need to make sure that even if this buffer is
diff --git a/fs/xfs/xfs_trans_extfree.c b/fs/xfs/xfs_trans_extfree.c
index 27cce2a9c7e..f783d5e9fa7 100644
--- a/fs/xfs/xfs_trans_extfree.c
+++ b/fs/xfs/xfs_trans_extfree.c
@@ -23,7 +23,6 @@
#include "xfs_trans.h"
#include "xfs_sb.h"
#include "xfs_ag.h"
-#include "xfs_dmapi.h"
#include "xfs_mount.h"
#include "xfs_trans_priv.h"
#include "xfs_extfree_item.h"
@@ -49,9 +48,8 @@ xfs_trans_get_efi(xfs_trans_t *tp,
/*
* Get a log_item_desc to point at the new item.
*/
- (void) xfs_trans_add_item(tp, (xfs_log_item_t*)efip);
-
- return (efip);
+ xfs_trans_add_item(tp, &efip->efi_item);
+ return efip;
}
/*
@@ -65,15 +63,11 @@ xfs_trans_log_efi_extent(xfs_trans_t *tp,
xfs_fsblock_t start_block,
xfs_extlen_t ext_len)
{
- xfs_log_item_desc_t *lidp;
uint next_extent;
xfs_extent_t *extp;
- lidp = xfs_trans_find_item(tp, (xfs_log_item_t*)efip);
- ASSERT(lidp != NULL);
-
tp->t_flags |= XFS_TRANS_DIRTY;
- lidp->lid_flags |= XFS_LID_DIRTY;
+ efip->efi_item.li_desc->lid_flags |= XFS_LID_DIRTY;
next_extent = efip->efi_next_extent;
ASSERT(next_extent < efip->efi_format.efi_nextents);
@@ -106,9 +100,8 @@ xfs_trans_get_efd(xfs_trans_t *tp,
/*
* Get a log_item_desc to point at the new item.
*/
- (void) xfs_trans_add_item(tp, (xfs_log_item_t*)efdp);
-
- return (efdp);
+ xfs_trans_add_item(tp, &efdp->efd_item);
+ return efdp;
}
/*
@@ -122,15 +115,11 @@ xfs_trans_log_efd_extent(xfs_trans_t *tp,
xfs_fsblock_t start_block,
xfs_extlen_t ext_len)
{
- xfs_log_item_desc_t *lidp;
uint next_extent;
xfs_extent_t *extp;
- lidp = xfs_trans_find_item(tp, (xfs_log_item_t*)efdp);
- ASSERT(lidp != NULL);
-
tp->t_flags |= XFS_TRANS_DIRTY;
- lidp->lid_flags |= XFS_LID_DIRTY;
+ efdp->efd_item.li_desc->lid_flags |= XFS_LID_DIRTY;
next_extent = efdp->efd_next_extent;
ASSERT(next_extent < efdp->efd_format.efd_nextents);
diff --git a/fs/xfs/xfs_trans_inode.c b/fs/xfs/xfs_trans_inode.c
index 2559dfec946..cdc53a1050c 100644
--- a/fs/xfs/xfs_trans_inode.c
+++ b/fs/xfs/xfs_trans_inode.c
@@ -24,20 +24,16 @@
#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_alloc_btree.h"
#include "xfs_ialloc_btree.h"
-#include "xfs_dir2_sf.h"
-#include "xfs_attr_sf.h"
#include "xfs_dinode.h"
#include "xfs_inode.h"
#include "xfs_btree.h"
-#include "xfs_ialloc.h"
#include "xfs_trans_priv.h"
#include "xfs_inode_item.h"
+#include "xfs_trace.h"
#ifdef XFS_TRANS_DEBUG
STATIC void
@@ -47,7 +43,6 @@ xfs_trans_inode_broot_debug(
#define xfs_trans_inode_broot_debug(ip)
#endif
-
/*
* Get an inode and join it to the transaction.
*/
@@ -63,77 +58,65 @@ xfs_trans_iget(
int error;
error = xfs_iget(mp, tp, ino, flags, lock_flags, ipp);
- if (!error && tp)
- xfs_trans_ijoin(tp, *ipp, lock_flags);
+ if (!error && tp) {
+ xfs_trans_ijoin(tp, *ipp);
+ (*ipp)->i_itemp->ili_lock_flags = lock_flags;
+ }
return error;
}
/*
- * Add the locked inode to the transaction.
- * The inode must be locked, and it cannot be associated with any
- * transaction. The caller must specify the locks already held
- * on the inode.
+ * Add a locked inode to the transaction.
+ *
+ * The inode must be locked, and it cannot be associated with any transaction.
*/
void
xfs_trans_ijoin(
- xfs_trans_t *tp,
- xfs_inode_t *ip,
- uint lock_flags)
+ struct xfs_trans *tp,
+ struct xfs_inode *ip)
{
xfs_inode_log_item_t *iip;
ASSERT(ip->i_transp == NULL);
ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL));
- ASSERT(lock_flags & XFS_ILOCK_EXCL);
if (ip->i_itemp == NULL)
xfs_inode_item_init(ip, ip->i_mount);
iip = ip->i_itemp;
- ASSERT(iip->ili_flags == 0);
+ ASSERT(iip->ili_lock_flags == 0);
/*
* Get a log_item_desc to point at the new item.
*/
- (void) xfs_trans_add_item(tp, (xfs_log_item_t*)(iip));
+ xfs_trans_add_item(tp, &iip->ili_item);
xfs_trans_inode_broot_debug(ip);
/*
- * If the IO lock is already held, mark that in the inode log item.
- */
- if (lock_flags & XFS_IOLOCK_EXCL) {
- iip->ili_flags |= XFS_ILI_IOLOCKED_EXCL;
- } else if (lock_flags & XFS_IOLOCK_SHARED) {
- iip->ili_flags |= XFS_ILI_IOLOCKED_SHARED;
- }
-
- /*
* Initialize i_transp so we can find it with xfs_inode_incore()
* in xfs_trans_iget() above.
*/
ip->i_transp = tp;
}
-
-
/*
- * Mark the inode as not needing to be unlocked when the inode item's
- * IOP_UNLOCK() routine is called. The inode must already be locked
- * and associated with the given transaction.
+ * Add a locked inode to the transaction.
+ *
+ *
+ * Grabs a reference to the inode which will be dropped when the transaction
+ * is commited. The inode will also be unlocked at that point. The inode
+ * must be locked, and it cannot be associated with any transaction.
*/
-/*ARGSUSED*/
void
-xfs_trans_ihold(
- xfs_trans_t *tp,
- xfs_inode_t *ip)
+xfs_trans_ijoin_ref(
+ struct xfs_trans *tp,
+ struct xfs_inode *ip,
+ uint lock_flags)
{
- ASSERT(ip->i_transp == tp);
- ASSERT(ip->i_itemp != NULL);
- ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL));
-
- ip->i_itemp->ili_flags |= XFS_ILI_HOLD;
+ xfs_trans_ijoin(tp, ip);
+ IHOLD(ip);
+ ip->i_itemp->ili_lock_flags = lock_flags;
}
-
/*
* This is called to mark the fields indicated in fieldmask as needing
* to be logged when the transaction is committed. The inode must
@@ -149,17 +132,12 @@ xfs_trans_log_inode(
xfs_inode_t *ip,
uint flags)
{
- xfs_log_item_desc_t *lidp;
-
ASSERT(ip->i_transp == tp);
ASSERT(ip->i_itemp != NULL);
ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL));
- lidp = xfs_trans_find_item(tp, (xfs_log_item_t*)(ip->i_itemp));
- ASSERT(lidp != NULL);
-
tp->t_flags |= XFS_TRANS_DIRTY;
- lidp->lid_flags |= XFS_LID_DIRTY;
+ ip->i_itemp->ili_item.li_desc->lid_flags |= XFS_LID_DIRTY;
/*
* Always OR in the bits from the ili_last_fields field.
diff --git a/fs/xfs/xfs_trans_item.c b/fs/xfs/xfs_trans_item.c
deleted file mode 100644
index f11d37d06dc..00000000000
--- a/fs/xfs/xfs_trans_item.c
+++ /dev/null
@@ -1,441 +0,0 @@
-/*
- * Copyright (c) 2000-2002,2005 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_fs.h"
-#include "xfs_types.h"
-#include "xfs_log.h"
-#include "xfs_inum.h"
-#include "xfs_trans.h"
-#include "xfs_trans_priv.h"
-/* XXX: from here down needed until struct xfs_trans has its own ailp */
-#include "xfs_bit.h"
-#include "xfs_buf_item.h"
-#include "xfs_sb.h"
-#include "xfs_ag.h"
-#include "xfs_dir2.h"
-#include "xfs_dmapi.h"
-#include "xfs_mount.h"
-
-STATIC int xfs_trans_unlock_chunk(xfs_log_item_chunk_t *,
- int, int, xfs_lsn_t);
-
-/*
- * This is called to add the given log item to the transaction's
- * list of log items. It must find a free log item descriptor
- * or allocate a new one and add the item to that descriptor.
- * The function returns a pointer to item descriptor used to point
- * to the new item. The log item will now point to its new descriptor
- * with its li_desc field.
- */
-xfs_log_item_desc_t *
-xfs_trans_add_item(xfs_trans_t *tp, xfs_log_item_t *lip)
-{
- xfs_log_item_desc_t *lidp;
- xfs_log_item_chunk_t *licp;
- int i=0;
-
- /*
- * If there are no free descriptors, allocate a new chunk
- * of them and put it at the front of the chunk list.
- */
- if (tp->t_items_free == 0) {
- licp = (xfs_log_item_chunk_t*)
- kmem_alloc(sizeof(xfs_log_item_chunk_t), KM_SLEEP);
- ASSERT(licp != NULL);
- /*
- * Initialize the chunk, and then
- * claim the first slot in the newly allocated chunk.
- */
- xfs_lic_init(licp);
- xfs_lic_claim(licp, 0);
- licp->lic_unused = 1;
- xfs_lic_init_slot(licp, 0);
- lidp = xfs_lic_slot(licp, 0);
-
- /*
- * Link in the new chunk and update the free count.
- */
- licp->lic_next = tp->t_items.lic_next;
- tp->t_items.lic_next = licp;
- tp->t_items_free = XFS_LIC_NUM_SLOTS - 1;
-
- /*
- * Initialize the descriptor and the generic portion
- * of the log item.
- *
- * Point the new slot at this item and return it.
- * Also point the log item at its currently active
- * descriptor and set the item's mount pointer.
- */
- lidp->lid_item = lip;
- lidp->lid_flags = 0;
- lidp->lid_size = 0;
- lip->li_desc = lidp;
- lip->li_mountp = tp->t_mountp;
- lip->li_ailp = tp->t_mountp->m_ail;
- return lidp;
- }
-
- /*
- * Find the free descriptor. It is somewhere in the chunklist
- * of descriptors.
- */
- licp = &tp->t_items;
- while (licp != NULL) {
- if (xfs_lic_vacancy(licp)) {
- if (licp->lic_unused <= XFS_LIC_MAX_SLOT) {
- i = licp->lic_unused;
- ASSERT(xfs_lic_isfree(licp, i));
- break;
- }
- for (i = 0; i <= XFS_LIC_MAX_SLOT; i++) {
- if (xfs_lic_isfree(licp, i))
- break;
- }
- ASSERT(i <= XFS_LIC_MAX_SLOT);
- break;
- }
- licp = licp->lic_next;
- }
- ASSERT(licp != NULL);
- /*
- * If we find a free descriptor, claim it,
- * initialize it, and return it.
- */
- xfs_lic_claim(licp, i);
- if (licp->lic_unused <= i) {
- licp->lic_unused = i + 1;
- xfs_lic_init_slot(licp, i);
- }
- lidp = xfs_lic_slot(licp, i);
- tp->t_items_free--;
- lidp->lid_item = lip;
- lidp->lid_flags = 0;
- lidp->lid_size = 0;
- lip->li_desc = lidp;
- lip->li_mountp = tp->t_mountp;
- lip->li_ailp = tp->t_mountp->m_ail;
- return lidp;
-}
-
-/*
- * Free the given descriptor.
- *
- * This requires setting the bit in the chunk's free mask corresponding
- * to the given slot.
- */
-void
-xfs_trans_free_item(xfs_trans_t *tp, xfs_log_item_desc_t *lidp)
-{
- uint slot;
- xfs_log_item_chunk_t *licp;
- xfs_log_item_chunk_t **licpp;
-
- slot = xfs_lic_desc_to_slot(lidp);
- licp = xfs_lic_desc_to_chunk(lidp);
- xfs_lic_relse(licp, slot);
- lidp->lid_item->li_desc = NULL;
- tp->t_items_free++;
-
- /*
- * If there are no more used items in the chunk and this is not
- * the chunk embedded in the transaction structure, then free
- * the chunk. First pull it from the chunk list and then
- * free it back to the heap. We didn't bother with a doubly
- * linked list here because the lists should be very short
- * and this is not a performance path. It's better to save
- * the memory of the extra pointer.
- *
- * Also decrement the transaction structure's count of free items
- * by the number in a chunk since we are freeing an empty chunk.
- */
- if (xfs_lic_are_all_free(licp) && (licp != &(tp->t_items))) {
- licpp = &(tp->t_items.lic_next);
- while (*licpp != licp) {
- ASSERT(*licpp != NULL);
- licpp = &((*licpp)->lic_next);
- }
- *licpp = licp->lic_next;
- kmem_free(licp);
- tp->t_items_free -= XFS_LIC_NUM_SLOTS;
- }
-}
-
-/*
- * This is called to find the descriptor corresponding to the given
- * log item. It returns a pointer to the descriptor.
- * The log item MUST have a corresponding descriptor in the given
- * transaction. This routine does not return NULL, it panics.
- *
- * The descriptor pointer is kept in the log item's li_desc field.
- * Just return it.
- */
-/*ARGSUSED*/
-xfs_log_item_desc_t *
-xfs_trans_find_item(xfs_trans_t *tp, xfs_log_item_t *lip)
-{
- ASSERT(lip->li_desc != NULL);
-
- return lip->li_desc;
-}
-
-
-/*
- * Return a pointer to the first descriptor in the chunk list.
- * This does not return NULL if there are none, it panics.
- *
- * The first descriptor must be in either the first or second chunk.
- * This is because the only chunk allowed to be empty is the first.
- * All others are freed when they become empty.
- *
- * At some point this and xfs_trans_next_item() should be optimized
- * to quickly look at the mask to determine if there is anything to
- * look at.
- */
-xfs_log_item_desc_t *
-xfs_trans_first_item(xfs_trans_t *tp)
-{
- xfs_log_item_chunk_t *licp;
- int i;
-
- licp = &tp->t_items;
- /*
- * If it's not in the first chunk, skip to the second.
- */
- if (xfs_lic_are_all_free(licp)) {
- licp = licp->lic_next;
- }
-
- /*
- * Return the first non-free descriptor in the chunk.
- */
- ASSERT(!xfs_lic_are_all_free(licp));
- for (i = 0; i < licp->lic_unused; i++) {
- if (xfs_lic_isfree(licp, i)) {
- continue;
- }
-
- return xfs_lic_slot(licp, i);
- }
- cmn_err(CE_WARN, "xfs_trans_first_item() -- no first item");
- return NULL;
-}
-
-
-/*
- * Given a descriptor, return the next descriptor in the chunk list.
- * This returns NULL if there are no more used descriptors in the list.
- *
- * We do this by first locating the chunk in which the descriptor resides,
- * and then scanning forward in the chunk and the list for the next
- * used descriptor.
- */
-/*ARGSUSED*/
-xfs_log_item_desc_t *
-xfs_trans_next_item(xfs_trans_t *tp, xfs_log_item_desc_t *lidp)
-{
- xfs_log_item_chunk_t *licp;
- int i;
-
- licp = xfs_lic_desc_to_chunk(lidp);
-
- /*
- * First search the rest of the chunk. The for loop keeps us
- * from referencing things beyond the end of the chunk.
- */
- for (i = (int)xfs_lic_desc_to_slot(lidp) + 1; i < licp->lic_unused; i++) {
- if (xfs_lic_isfree(licp, i)) {
- continue;
- }
-
- return xfs_lic_slot(licp, i);
- }
-
- /*
- * Now search the next chunk. It must be there, because the
- * next chunk would have been freed if it were empty.
- * If there is no next chunk, return NULL.
- */
- if (licp->lic_next == NULL) {
- return NULL;
- }
-
- licp = licp->lic_next;
- ASSERT(!xfs_lic_are_all_free(licp));
- for (i = 0; i < licp->lic_unused; i++) {
- if (xfs_lic_isfree(licp, i)) {
- continue;
- }
-
- return xfs_lic_slot(licp, i);
- }
- ASSERT(0);
- /* NOTREACHED */
- return NULL; /* keep gcc quite */
-}
-
-/*
- * This is called to unlock all of the items of a transaction and to free
- * all the descriptors of that transaction.
- *
- * It walks the list of descriptors and unlocks each item. It frees
- * each chunk except that embedded in the transaction as it goes along.
- */
-void
-xfs_trans_free_items(
- xfs_trans_t *tp,
- xfs_lsn_t commit_lsn,
- int flags)
-{
- xfs_log_item_chunk_t *licp;
- xfs_log_item_chunk_t *next_licp;
- int abort;
-
- abort = flags & XFS_TRANS_ABORT;
- licp = &tp->t_items;
- /*
- * Special case the embedded chunk so we don't free it below.
- */
- if (!xfs_lic_are_all_free(licp)) {
- (void) xfs_trans_unlock_chunk(licp, 1, abort, commit_lsn);
- xfs_lic_all_free(licp);
- licp->lic_unused = 0;
- }
- licp = licp->lic_next;
-
- /*
- * Unlock each item in each chunk and free the chunks.
- */
- while (licp != NULL) {
- ASSERT(!xfs_lic_are_all_free(licp));
- (void) xfs_trans_unlock_chunk(licp, 1, abort, commit_lsn);
- next_licp = licp->lic_next;
- kmem_free(licp);
- licp = next_licp;
- }
-
- /*
- * Reset the transaction structure's free item count.
- */
- tp->t_items_free = XFS_LIC_NUM_SLOTS;
- tp->t_items.lic_next = NULL;
-}
-
-
-
-/*
- * This is called to unlock the items associated with a transaction.
- * Items which were not logged should be freed.
- * Those which were logged must still be tracked so they can be unpinned
- * when the transaction commits.
- */
-void
-xfs_trans_unlock_items(xfs_trans_t *tp, xfs_lsn_t commit_lsn)
-{
- xfs_log_item_chunk_t *licp;
- xfs_log_item_chunk_t *next_licp;
- xfs_log_item_chunk_t **licpp;
- int freed;
-
- freed = 0;
- licp = &tp->t_items;
-
- /*
- * Special case the embedded chunk so we don't free.
- */
- if (!xfs_lic_are_all_free(licp)) {
- freed = xfs_trans_unlock_chunk(licp, 0, 0, commit_lsn);
- }
- licpp = &(tp->t_items.lic_next);
- licp = licp->lic_next;
-
- /*
- * Unlock each item in each chunk, free non-dirty descriptors,
- * and free empty chunks.
- */
- while (licp != NULL) {
- ASSERT(!xfs_lic_are_all_free(licp));
- freed += xfs_trans_unlock_chunk(licp, 0, 0, commit_lsn);
- next_licp = licp->lic_next;
- if (xfs_lic_are_all_free(licp)) {
- *licpp = next_licp;
- kmem_free(licp);
- freed -= XFS_LIC_NUM_SLOTS;
- } else {
- licpp = &(licp->lic_next);
- }
- ASSERT(*licpp == next_licp);
- licp = next_licp;
- }
-
- /*
- * Fix the free descriptor count in the transaction.
- */
- tp->t_items_free += freed;
-}
-
-/*
- * Unlock each item pointed to by a descriptor in the given chunk.
- * Stamp the commit lsn into each item if necessary.
- * Free descriptors pointing to items which are not dirty if freeing_chunk
- * is zero. If freeing_chunk is non-zero, then we need to unlock all
- * items in the chunk.
- *
- * Return the number of descriptors freed.
- */
-STATIC int
-xfs_trans_unlock_chunk(
- xfs_log_item_chunk_t *licp,
- int freeing_chunk,
- int abort,
- xfs_lsn_t commit_lsn)
-{
- xfs_log_item_desc_t *lidp;
- xfs_log_item_t *lip;
- int i;
- int freed;
-
- freed = 0;
- lidp = licp->lic_descs;
- for (i = 0; i < licp->lic_unused; i++, lidp++) {
- if (xfs_lic_isfree(licp, i)) {
- continue;
- }
- lip = lidp->lid_item;
- lip->li_desc = NULL;
-
- if (commit_lsn != NULLCOMMITLSN)
- IOP_COMMITTING(lip, commit_lsn);
- if (abort)
- lip->li_flags |= XFS_LI_ABORTED;
- IOP_UNLOCK(lip);
-
- /*
- * Free the descriptor if the item is not dirty
- * within this transaction and the caller is not
- * going to just free the entire thing regardless.
- */
- if (!(freeing_chunk) &&
- (!(lidp->lid_flags & XFS_LID_DIRTY) || abort)) {
- xfs_lic_relse(licp, i);
- freed++;
- }
- }
-
- return freed;
-}
diff --git a/fs/xfs/xfs_trans_priv.h b/fs/xfs/xfs_trans_priv.h
index c6e4f2c8de6..e2d93d8ead7 100644
--- a/fs/xfs/xfs_trans_priv.h
+++ b/fs/xfs/xfs_trans_priv.h
@@ -23,22 +23,8 @@ struct xfs_log_item_desc;
struct xfs_mount;
struct xfs_trans;
-/*
- * From xfs_trans_item.c
- */
-struct xfs_log_item_desc *xfs_trans_add_item(struct xfs_trans *,
- struct xfs_log_item *);
-void xfs_trans_free_item(struct xfs_trans *,
- struct xfs_log_item_desc *);
-struct xfs_log_item_desc *xfs_trans_find_item(struct xfs_trans *,
- struct xfs_log_item *);
-struct xfs_log_item_desc *xfs_trans_first_item(struct xfs_trans *);
-struct xfs_log_item_desc *xfs_trans_next_item(struct xfs_trans *,
- struct xfs_log_item_desc *);
-
-void xfs_trans_unlock_items(struct xfs_trans *tp, xfs_lsn_t commit_lsn);
-void xfs_trans_free_items(struct xfs_trans *tp, xfs_lsn_t commit_lsn,
- int flags);
+void xfs_trans_add_item(struct xfs_trans *, struct xfs_log_item *);
+void xfs_trans_del_item(struct xfs_log_item *);
void xfs_trans_item_committed(struct xfs_log_item *lip,
xfs_lsn_t commit_lsn, int aborted);
diff --git a/fs/xfs/xfs_utils.c b/fs/xfs/xfs_utils.c
index 4d88616bde9..b7d5769d2df 100644
--- a/fs/xfs/xfs_utils.c
+++ b/fs/xfs/xfs_utils.c
@@ -25,18 +25,14 @@
#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_dir2_sf.h"
-#include "xfs_attr_sf.h"
#include "xfs_dinode.h"
#include "xfs_inode.h"
#include "xfs_inode_item.h"
#include "xfs_bmap.h"
#include "xfs_error.h"
#include "xfs_quota.h"
-#include "xfs_rw.h"
#include "xfs_itable.h"
#include "xfs_utils.h"
@@ -324,86 +320,3 @@ xfs_bumplink(
xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
return 0;
}
-
-/*
- * Try to truncate the given file to 0 length. Currently called
- * only out of xfs_remove when it has to truncate a file to free
- * up space for the remove to proceed.
- */
-int
-xfs_truncate_file(
- xfs_mount_t *mp,
- xfs_inode_t *ip)
-{
- xfs_trans_t *tp;
- int error;
-
-#ifdef QUOTADEBUG
- /*
- * This is called to truncate the quotainodes too.
- */
- if (XFS_IS_UQUOTA_ON(mp)) {
- if (ip->i_ino != mp->m_sb.sb_uquotino)
- ASSERT(ip->i_udquot);
- }
- if (XFS_IS_OQUOTA_ON(mp)) {
- if (ip->i_ino != mp->m_sb.sb_gquotino)
- ASSERT(ip->i_gdquot);
- }
-#endif
- /*
- * Make the call to xfs_itruncate_start before starting the
- * transaction, because we cannot make the call while we're
- * in a transaction.
- */
- xfs_ilock(ip, XFS_IOLOCK_EXCL);
- error = xfs_itruncate_start(ip, XFS_ITRUNC_DEFINITE, (xfs_fsize_t)0);
- if (error) {
- xfs_iunlock(ip, XFS_IOLOCK_EXCL);
- return error;
- }
-
- tp = xfs_trans_alloc(mp, XFS_TRANS_TRUNCATE_FILE);
- if ((error = xfs_trans_reserve(tp, 0, XFS_ITRUNCATE_LOG_RES(mp), 0,
- XFS_TRANS_PERM_LOG_RES,
- XFS_ITRUNCATE_LOG_COUNT))) {
- xfs_trans_cancel(tp, 0);
- xfs_iunlock(ip, XFS_IOLOCK_EXCL);
- return error;
- }
-
- /*
- * Follow the normal truncate locking protocol. Since we
- * hold the inode in the transaction, we know that its number
- * of references will stay constant.
- */
- xfs_ilock(ip, XFS_ILOCK_EXCL);
- xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL);
- xfs_trans_ihold(tp, ip);
- /*
- * Signal a sync xaction. The only case where that isn't
- * the case is if we're truncating an already unlinked file
- * on a wsync fs. In that case, we know the blocks can't
- * reappear in the file because the links to file are
- * permanently toast. Currently, we're always going to
- * want a sync transaction because this code is being
- * called from places where nlink is guaranteed to be 1
- * but I'm leaving the tests in to protect against future
- * changes -- rcc.
- */
- error = xfs_itruncate_finish(&tp, ip, (xfs_fsize_t)0,
- XFS_DATA_FORK,
- ((ip->i_d.di_nlink != 0 ||
- !(mp->m_flags & XFS_MOUNT_WSYNC))
- ? 1 : 0));
- if (error) {
- xfs_trans_cancel(tp, XFS_TRANS_RELEASE_LOG_RES |
- XFS_TRANS_ABORT);
- } else {
- xfs_ichgtime(ip, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
- error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES);
- }
- xfs_iunlock(ip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL);
-
- return error;
-}
diff --git a/fs/xfs/xfs_utils.h b/fs/xfs/xfs_utils.h
index ef321225d26..f55b9678264 100644
--- a/fs/xfs/xfs_utils.h
+++ b/fs/xfs/xfs_utils.h
@@ -18,7 +18,6 @@
#ifndef __XFS_UTILS_H__
#define __XFS_UTILS_H__
-extern int xfs_truncate_file(xfs_mount_t *, xfs_inode_t *);
extern int xfs_dir_ialloc(xfs_trans_t **, xfs_inode_t *, mode_t, xfs_nlink_t,
xfs_dev_t, cred_t *, prid_t, int,
xfs_inode_t **, int *);
diff --git a/fs/xfs/xfs_vnodeops.c b/fs/xfs/xfs_vnodeops.c
index c1646838898..3ac137dd531 100644
--- a/fs/xfs/xfs_vnodeops.c
+++ b/fs/xfs/xfs_vnodeops.c
@@ -26,19 +26,14 @@
#include "xfs_sb.h"
#include "xfs_ag.h"
#include "xfs_dir2.h"
-#include "xfs_dmapi.h"
#include "xfs_mount.h"
#include "xfs_da_btree.h"
#include "xfs_bmap_btree.h"
-#include "xfs_alloc_btree.h"
#include "xfs_ialloc_btree.h"
-#include "xfs_dir2_sf.h"
-#include "xfs_attr_sf.h"
#include "xfs_dinode.h"
#include "xfs_inode.h"
#include "xfs_inode_item.h"
#include "xfs_itable.h"
-#include "xfs_btree.h"
#include "xfs_ialloc.h"
#include "xfs_alloc.h"
#include "xfs_bmap.h"
@@ -73,7 +68,7 @@ xfs_setattr(
struct xfs_dquot *udqp, *gdqp, *olddquot1, *olddquot2;
int need_iolock = 1;
- xfs_itrace_entry(ip);
+ trace_xfs_setattr(ip);
if (mp->m_flags & XFS_MOUNT_RDONLY)
return XFS_ERROR(EROFS);
@@ -143,16 +138,6 @@ xfs_setattr(
goto error_return;
}
} else {
- if (DM_EVENT_ENABLED(ip, DM_EVENT_TRUNCATE) &&
- !(flags & XFS_ATTR_DMI)) {
- int dmflags = AT_DELAY_FLAG(flags) | DM_SEM_FLAG_WR;
- code = XFS_SEND_DATA(mp, DM_EVENT_TRUNCATE, ip,
- iattr->ia_size, 0, dmflags, NULL);
- if (code) {
- lock_flags = 0;
- goto error_return;
- }
- }
if (need_iolock)
lock_flags |= XFS_IOLOCK_EXCL;
}
@@ -283,8 +268,7 @@ xfs_setattr(
commit_flags = XFS_TRANS_RELEASE_LOG_RES;
xfs_ilock(ip, XFS_ILOCK_EXCL);
- xfs_trans_ijoin(tp, ip, lock_flags);
- xfs_trans_ihold(tp, ip);
+ xfs_trans_ijoin(tp, ip);
/*
* Only change the c/mtime if we are changing the size
@@ -334,8 +318,7 @@ xfs_setattr(
xfs_iflags_set(ip, XFS_ITRUNCATED);
}
} else if (tp) {
- xfs_trans_ijoin(tp, ip, lock_flags);
- xfs_trans_ihold(tp, ip);
+ xfs_trans_ijoin(tp, ip);
}
/*
@@ -470,17 +453,10 @@ xfs_setattr(
return XFS_ERROR(code);
}
- if (DM_EVENT_ENABLED(ip, DM_EVENT_ATTRIBUTE) &&
- !(flags & XFS_ATTR_DMI)) {
- (void) XFS_SEND_NAMESP(mp, DM_EVENT_ATTRIBUTE, ip, DM_RIGHT_NULL,
- NULL, DM_RIGHT_NULL, NULL, NULL,
- 0, 0, AT_DELAY_FLAG(flags));
- }
return 0;
abort_return:
commit_flags |= XFS_TRANS_ABORT;
- /* FALLTHROUGH */
error_return:
xfs_qm_dqrele(udqp);
xfs_qm_dqrele(gdqp);
@@ -516,7 +492,7 @@ xfs_readlink_bmap(
int error = 0;
error = xfs_bmapi(NULL, ip, 0, XFS_B_TO_FSB(mp, pathlen), 0, NULL, 0,
- mval, &nmaps, NULL, NULL);
+ mval, &nmaps, NULL);
if (error)
goto out;
@@ -557,7 +533,7 @@ xfs_readlink(
int pathlen;
int error = 0;
- xfs_itrace_entry(ip);
+ trace_xfs_readlink(ip);
if (XFS_FORCED_SHUTDOWN(mp))
return XFS_ERROR(EIO);
@@ -613,14 +589,14 @@ xfs_free_eofblocks(
*/
end_fsb = XFS_B_TO_FSB(mp, ((xfs_ufsize_t)ip->i_size));
last_fsb = XFS_B_TO_FSB(mp, (xfs_ufsize_t)XFS_MAXIOFFSET(mp));
- map_len = last_fsb - end_fsb;
- if (map_len <= 0)
+ if (last_fsb <= end_fsb)
return 0;
+ map_len = last_fsb - end_fsb;
nimaps = 1;
xfs_ilock(ip, XFS_ILOCK_SHARED);
error = xfs_bmapi(NULL, ip, end_fsb, map_len, 0,
- NULL, 0, &imap, &nimaps, NULL, NULL);
+ NULL, 0, &imap, &nimaps, NULL);
xfs_iunlock(ip, XFS_ILOCK_SHARED);
if (!error && (nimaps != 0) &&
@@ -675,10 +651,7 @@ xfs_free_eofblocks(
}
xfs_ilock(ip, XFS_ILOCK_EXCL);
- xfs_trans_ijoin(tp, ip,
- XFS_IOLOCK_EXCL |
- XFS_ILOCK_EXCL);
- xfs_trans_ihold(tp, ip);
+ xfs_trans_ijoin(tp, ip);
error = xfs_itruncate_finish(&tp, ip,
ip->i_size,
@@ -750,8 +723,7 @@ xfs_inactive_symlink_rmt(
xfs_ilock(ip, XFS_IOLOCK_EXCL | XFS_ILOCK_EXCL);
size = (int)ip->i_d.di_size;
ip->i_d.di_size = 0;
- xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL);
- xfs_trans_ihold(tp, ip);
+ xfs_trans_ijoin(tp, ip);
xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
/*
* Find the block(s) so we can inval and unmap them.
@@ -761,7 +733,7 @@ xfs_inactive_symlink_rmt(
nmaps = ARRAY_SIZE(mval);
if ((error = xfs_bmapi(tp, ip, 0, XFS_B_TO_FSB(mp, size),
XFS_BMAPI_METADATA, &first_block, 0, mval, &nmaps,
- &free_list, NULL)))
+ &free_list)))
goto error0;
/*
* Invalidate the block(s).
@@ -776,7 +748,7 @@ xfs_inactive_symlink_rmt(
* Unmap the dead block(s) to the free_list.
*/
if ((error = xfs_bunmapi(tp, ip, 0, size, XFS_BMAPI_METADATA, nmaps,
- &first_block, &free_list, NULL, &done)))
+ &first_block, &free_list, &done)))
goto error1;
ASSERT(done);
/*
@@ -795,8 +767,7 @@ xfs_inactive_symlink_rmt(
* Mark it dirty so it will be logged and moved forward in the log as
* part of every commit.
*/
- xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL);
- xfs_trans_ihold(tp, ip);
+ xfs_trans_ijoin(tp, ip);
xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
/*
* Get a new, empty transaction to return to our caller.
@@ -929,8 +900,7 @@ xfs_inactive_attrs(
goto error_cancel;
xfs_ilock(ip, XFS_ILOCK_EXCL);
- xfs_trans_ijoin(tp, ip, XFS_IOLOCK_EXCL | XFS_ILOCK_EXCL);
- xfs_trans_ihold(tp, ip);
+ xfs_trans_ijoin(tp, ip);
xfs_idestroy_fork(ip, XFS_ATTR_FORK);
ASSERT(ip->i_d.di_anextents == 0);
@@ -1035,8 +1005,6 @@ xfs_inactive(
int error;
int truncate;
- xfs_itrace_entry(ip);
-
/*
* If the inode is already free, then there can be nothing
* to clean up here.
@@ -1060,9 +1028,6 @@ xfs_inactive(
mp = ip->i_mount;
- if (ip->i_d.di_nlink == 0 && DM_EVENT_ENABLED(ip, DM_EVENT_DESTROY))
- XFS_SEND_DESTROY(mp, ip, DM_RIGHT_NULL);
-
error = 0;
/* If this is a read-only mount, don't do this (would generate I/O) */
@@ -1120,8 +1085,7 @@ xfs_inactive(
}
xfs_ilock(ip, XFS_ILOCK_EXCL);
- xfs_trans_ijoin(tp, ip, XFS_IOLOCK_EXCL | XFS_ILOCK_EXCL);
- xfs_trans_ihold(tp, ip);
+ xfs_trans_ijoin(tp, ip);
/*
* normally, we have to run xfs_itruncate_finish sync.
@@ -1154,8 +1118,7 @@ xfs_inactive(
return VN_INACTIVE_CACHE;
}
- xfs_trans_ijoin(tp, ip, XFS_IOLOCK_EXCL | XFS_ILOCK_EXCL);
- xfs_trans_ihold(tp, ip);
+ xfs_trans_ijoin(tp, ip);
} else {
error = xfs_trans_reserve(tp, 0,
XFS_IFREE_LOG_RES(mp),
@@ -1168,8 +1131,7 @@ xfs_inactive(
}
xfs_ilock(ip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL);
- xfs_trans_ijoin(tp, ip, XFS_IOLOCK_EXCL | XFS_ILOCK_EXCL);
- xfs_trans_ihold(tp, ip);
+ xfs_trans_ijoin(tp, ip);
}
/*
@@ -1257,7 +1219,7 @@ xfs_lookup(
int error;
uint lock_mode;
- xfs_itrace_entry(dp);
+ trace_xfs_lookup(dp, name);
if (XFS_FORCED_SHUTDOWN(dp->i_mount))
return XFS_ERROR(EIO);
@@ -1309,21 +1271,11 @@ xfs_create(
uint log_res;
uint log_count;
- xfs_itrace_entry(dp);
+ trace_xfs_create(dp, name);
if (XFS_FORCED_SHUTDOWN(mp))
return XFS_ERROR(EIO);
- if (DM_EVENT_ENABLED(dp, DM_EVENT_CREATE)) {
- error = XFS_SEND_NAMESP(mp, DM_EVENT_CREATE,
- dp, DM_RIGHT_NULL, NULL,
- DM_RIGHT_NULL, name->name, NULL,
- mode, 0, 0);
-
- if (error)
- return error;
- }
-
if (dp->i_d.di_flags & XFS_DIFLAG_PROJINHERIT)
prid = dp->i_d.di_projid;
else
@@ -1427,8 +1379,7 @@ xfs_create(
* the transaction cancel unlocking dp so don't do it explicitly in the
* error path.
*/
- IHOLD(dp);
- xfs_trans_ijoin(tp, dp, XFS_ILOCK_EXCL);
+ xfs_trans_ijoin_ref(tp, dp, XFS_ILOCK_EXCL);
unlock_dp_on_error = B_FALSE;
error = xfs_dir_createname(tp, dp, name, ip->i_ino,
@@ -1487,16 +1438,7 @@ xfs_create(
xfs_qm_dqrele(gdqp);
*ipp = ip;
-
- /* Fallthrough to std_return with error = 0 */
- std_return:
- if (DM_EVENT_ENABLED(dp, DM_EVENT_POSTCREATE)) {
- XFS_SEND_NAMESP(mp, DM_EVENT_POSTCREATE, dp, DM_RIGHT_NULL,
- ip, DM_RIGHT_NULL, name->name, NULL, mode,
- error, 0);
- }
-
- return error;
+ return 0;
out_bmap_cancel:
xfs_bmap_cancel(&free_list);
@@ -1510,8 +1452,8 @@ xfs_create(
if (unlock_dp_on_error)
xfs_iunlock(dp, XFS_ILOCK_EXCL);
-
- goto std_return;
+ std_return:
+ return error;
out_abort_rele:
/*
@@ -1726,20 +1668,11 @@ xfs_remove(
uint resblks;
uint log_count;
- xfs_itrace_entry(dp);
- xfs_itrace_entry(ip);
+ trace_xfs_remove(dp, name);
if (XFS_FORCED_SHUTDOWN(mp))
return XFS_ERROR(EIO);
- if (DM_EVENT_ENABLED(dp, DM_EVENT_REMOVE)) {
- error = XFS_SEND_NAMESP(mp, DM_EVENT_REMOVE, dp, DM_RIGHT_NULL,
- NULL, DM_RIGHT_NULL, name->name, NULL,
- ip->i_d.di_mode, 0, 0);
- if (error)
- return error;
- }
-
error = xfs_qm_dqattach(dp, 0);
if (error)
goto std_return;
@@ -1782,15 +1715,8 @@ xfs_remove(
xfs_lock_two_inodes(dp, ip, XFS_ILOCK_EXCL);
- /*
- * At this point, we've gotten both the directory and the entry
- * inodes locked.
- */
- IHOLD(ip);
- xfs_trans_ijoin(tp, dp, XFS_ILOCK_EXCL);
-
- IHOLD(dp);
- xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL);
+ xfs_trans_ijoin_ref(tp, dp, XFS_ILOCK_EXCL);
+ xfs_trans_ijoin_ref(tp, ip, XFS_ILOCK_EXCL);
/*
* If we're removing a directory perform some additional validation.
@@ -1877,21 +1803,15 @@ xfs_remove(
if (!is_dir && link_zero && xfs_inode_is_filestream(ip))
xfs_filestream_deassociate(ip);
- std_return:
- if (DM_EVENT_ENABLED(dp, DM_EVENT_POSTREMOVE)) {
- XFS_SEND_NAMESP(mp, DM_EVENT_POSTREMOVE, dp, DM_RIGHT_NULL,
- NULL, DM_RIGHT_NULL, name->name, NULL,
- ip->i_d.di_mode, error, 0);
- }
-
- return error;
+ return 0;
out_bmap_cancel:
xfs_bmap_cancel(&free_list);
cancel_flags |= XFS_TRANS_ABORT;
out_trans_cancel:
xfs_trans_cancel(tp, cancel_flags);
- goto std_return;
+ std_return:
+ return error;
}
int
@@ -1909,25 +1829,13 @@ xfs_link(
int committed;
int resblks;
- xfs_itrace_entry(tdp);
- xfs_itrace_entry(sip);
+ trace_xfs_link(tdp, target_name);
ASSERT(!S_ISDIR(sip->i_d.di_mode));
if (XFS_FORCED_SHUTDOWN(mp))
return XFS_ERROR(EIO);
- if (DM_EVENT_ENABLED(tdp, DM_EVENT_LINK)) {
- error = XFS_SEND_NAMESP(mp, DM_EVENT_LINK,
- tdp, DM_RIGHT_NULL,
- sip, DM_RIGHT_NULL,
- target_name->name, NULL, 0, 0, 0);
- if (error)
- return error;
- }
-
- /* Return through std_return after this point. */
-
error = xfs_qm_dqattach(sip, 0);
if (error)
goto std_return;
@@ -1953,15 +1861,8 @@ xfs_link(
xfs_lock_two_inodes(sip, tdp, XFS_ILOCK_EXCL);
- /*
- * Increment vnode ref counts since xfs_trans_commit &
- * xfs_trans_cancel will both unlock the inodes and
- * decrement the associated ref counts.
- */
- IHOLD(sip);
- IHOLD(tdp);
- xfs_trans_ijoin(tp, sip, XFS_ILOCK_EXCL);
- xfs_trans_ijoin(tp, tdp, XFS_ILOCK_EXCL);
+ xfs_trans_ijoin_ref(tp, sip, XFS_ILOCK_EXCL);
+ xfs_trans_ijoin_ref(tp, tdp, XFS_ILOCK_EXCL);
/*
* If the source has too many links, we can't make any more to it.
@@ -2014,27 +1915,14 @@ xfs_link(
goto abort_return;
}
- error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES);
- if (error)
- goto std_return;
-
- /* Fall through to std_return with error = 0. */
-std_return:
- if (DM_EVENT_ENABLED(sip, DM_EVENT_POSTLINK)) {
- (void) XFS_SEND_NAMESP(mp, DM_EVENT_POSTLINK,
- tdp, DM_RIGHT_NULL,
- sip, DM_RIGHT_NULL,
- target_name->name, NULL, 0, error, 0);
- }
- return error;
+ return xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES);
abort_return:
cancel_flags |= XFS_TRANS_ABORT;
- /* FALLTHROUGH */
-
error_return:
xfs_trans_cancel(tp, cancel_flags);
- goto std_return;
+ std_return:
+ return error;
}
int
@@ -2074,7 +1962,7 @@ xfs_symlink(
ip = NULL;
tp = NULL;
- xfs_itrace_entry(dp);
+ trace_xfs_symlink(dp, link_name);
if (XFS_FORCED_SHUTDOWN(mp))
return XFS_ERROR(EIO);
@@ -2086,17 +1974,6 @@ xfs_symlink(
if (pathlen >= MAXPATHLEN) /* total string too long */
return XFS_ERROR(ENAMETOOLONG);
- if (DM_EVENT_ENABLED(dp, DM_EVENT_SYMLINK)) {
- error = XFS_SEND_NAMESP(mp, DM_EVENT_SYMLINK, dp,
- DM_RIGHT_NULL, NULL, DM_RIGHT_NULL,
- link_name->name,
- (unsigned char *)target_path, 0, 0, 0);
- if (error)
- return error;
- }
-
- /* Return through std_return after this point. */
-
udqp = gdqp = NULL;
if (dp->i_d.di_flags & XFS_DIFLAG_PROJINHERIT)
prid = dp->i_d.di_projid;
@@ -2180,8 +2057,7 @@ xfs_symlink(
* transaction cancel unlocking dp so don't do it explicitly in the
* error path.
*/
- IHOLD(dp);
- xfs_trans_ijoin(tp, dp, XFS_ILOCK_EXCL);
+ xfs_trans_ijoin_ref(tp, dp, XFS_ILOCK_EXCL);
unlock_dp_on_error = B_FALSE;
/*
@@ -2215,7 +2091,7 @@ xfs_symlink(
error = xfs_bmapi(tp, ip, first_fsb, fs_blocks,
XFS_BMAPI_WRITE | XFS_BMAPI_METADATA,
&first_block, resblks, mval, &nmaps,
- &free_list, NULL);
+ &free_list);
if (error) {
goto error1;
}
@@ -2278,21 +2154,8 @@ xfs_symlink(
xfs_qm_dqrele(udqp);
xfs_qm_dqrele(gdqp);
- /* Fall through to std_return with error = 0 or errno from
- * xfs_trans_commit */
-std_return:
- if (DM_EVENT_ENABLED(dp, DM_EVENT_POSTSYMLINK)) {
- (void) XFS_SEND_NAMESP(mp, DM_EVENT_POSTSYMLINK,
- dp, DM_RIGHT_NULL,
- error ? NULL : ip,
- DM_RIGHT_NULL, link_name->name,
- (unsigned char *)target_path,
- 0, error, 0);
- }
-
- if (!error)
- *ipp = ip;
- return error;
+ *ipp = ip;
+ return 0;
error2:
IRELE(ip);
@@ -2306,8 +2169,8 @@ std_return:
if (unlock_dp_on_error)
xfs_iunlock(dp, XFS_ILOCK_EXCL);
-
- goto std_return;
+ std_return:
+ return error;
}
int
@@ -2333,13 +2196,12 @@ xfs_set_dmattrs(
return error;
}
xfs_ilock(ip, XFS_ILOCK_EXCL);
- xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL);
+ xfs_trans_ijoin_ref(tp, ip, XFS_ILOCK_EXCL);
ip->i_d.di_dmevmask = evmask;
ip->i_d.di_dmstate = state;
xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
- IHOLD(ip);
error = xfs_trans_commit(tp, 0);
return error;
@@ -2390,7 +2252,7 @@ xfs_alloc_file_space(
int committed;
int error;
- xfs_itrace_entry(ip);
+ trace_xfs_alloc_file_space(ip);
if (XFS_FORCED_SHUTDOWN(mp))
return XFS_ERROR(EIO);
@@ -2412,25 +2274,9 @@ xfs_alloc_file_space(
startoffset_fsb = XFS_B_TO_FSBT(mp, offset);
allocatesize_fsb = XFS_B_TO_FSB(mp, count);
- /* Generate a DMAPI event if needed. */
- if (alloc_type != 0 && offset < ip->i_size &&
- (attr_flags & XFS_ATTR_DMI) == 0 &&
- DM_EVENT_ENABLED(ip, DM_EVENT_WRITE)) {
- xfs_off_t end_dmi_offset;
-
- end_dmi_offset = offset+len;
- if (end_dmi_offset > ip->i_size)
- end_dmi_offset = ip->i_size;
- error = XFS_SEND_DATA(mp, DM_EVENT_WRITE, ip, offset,
- end_dmi_offset - offset, 0, NULL);
- if (error)
- return error;
- }
-
/*
* Allocate file space until done or until there is an error
*/
-retry:
while (allocatesize_fsb && !error) {
xfs_fileoff_t s, e;
@@ -2488,8 +2334,7 @@ retry:
if (error)
goto error1;
- xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL);
- xfs_trans_ihold(tp, ip);
+ xfs_trans_ijoin(tp, ip);
/*
* Issue the xfs_bmapi() call to allocate the blocks
@@ -2498,7 +2343,7 @@ retry:
error = xfs_bmapi(tp, ip, startoffset_fsb,
allocatesize_fsb, bmapi_flag,
&firstfsb, 0, imapp, &nimaps,
- &free_list, NULL);
+ &free_list);
if (error) {
goto error0;
}
@@ -2527,17 +2372,6 @@ retry:
startoffset_fsb += allocated_fsb;
allocatesize_fsb -= allocated_fsb;
}
-dmapi_enospc_check:
- if (error == ENOSPC && (attr_flags & XFS_ATTR_DMI) == 0 &&
- DM_EVENT_ENABLED(ip, DM_EVENT_NOSPACE)) {
- error = XFS_SEND_NAMESP(mp, DM_EVENT_NOSPACE,
- ip, DM_RIGHT_NULL,
- ip, DM_RIGHT_NULL,
- NULL, NULL, 0, 0, 0); /* Delay flag intentionally unused */
- if (error == 0)
- goto retry; /* Maybe DMAPI app. has made space */
- /* else fall through with error from XFS_SEND_DATA */
- }
return error;
@@ -2548,7 +2382,7 @@ error0: /* Cancel bmap, unlock inode, unreserve quota blocks, cancel trans */
error1: /* Just cancel transaction */
xfs_trans_cancel(tp, XFS_TRANS_RELEASE_LOG_RES | XFS_TRANS_ABORT);
xfs_iunlock(ip, XFS_ILOCK_EXCL);
- goto dmapi_enospc_check;
+ return error;
}
/*
@@ -2598,7 +2432,7 @@ xfs_zero_remaining_bytes(
offset_fsb = XFS_B_TO_FSBT(mp, offset);
nimap = 1;
error = xfs_bmapi(NULL, ip, offset_fsb, 1, 0,
- NULL, 0, &imap, &nimap, NULL, NULL);
+ NULL, 0, &imap, &nimap, NULL);
if (error || nimap < 1)
break;
ASSERT(imap.br_blockcount >= 1);
@@ -2661,7 +2495,6 @@ xfs_free_file_space(
{
int committed;
int done;
- xfs_off_t end_dmi_offset;
xfs_fileoff_t endoffset_fsb;
int error;
xfs_fsblock_t firstfsb;
@@ -2680,7 +2513,7 @@ xfs_free_file_space(
mp = ip->i_mount;
- xfs_itrace_entry(ip);
+ trace_xfs_free_file_space(ip);
error = xfs_qm_dqattach(ip, 0);
if (error)
@@ -2691,19 +2524,7 @@ xfs_free_file_space(
return error;
rt = XFS_IS_REALTIME_INODE(ip);
startoffset_fsb = XFS_B_TO_FSB(mp, offset);
- end_dmi_offset = offset + len;
- endoffset_fsb = XFS_B_TO_FSBT(mp, end_dmi_offset);
-
- if (offset < ip->i_size && (attr_flags & XFS_ATTR_DMI) == 0 &&
- DM_EVENT_ENABLED(ip, DM_EVENT_WRITE)) {
- if (end_dmi_offset > ip->i_size)
- end_dmi_offset = ip->i_size;
- error = XFS_SEND_DATA(mp, DM_EVENT_WRITE, ip,
- offset, end_dmi_offset - offset,
- AT_DELAY_FLAG(attr_flags), NULL);
- if (error)
- return error;
- }
+ endoffset_fsb = XFS_B_TO_FSBT(mp, offset + len);
if (attr_flags & XFS_ATTR_NOLOCK)
need_iolock = 0;
@@ -2731,7 +2552,7 @@ xfs_free_file_space(
if (rt && !xfs_sb_version_hasextflgbit(&mp->m_sb)) {
nimap = 1;
error = xfs_bmapi(NULL, ip, startoffset_fsb,
- 1, 0, NULL, 0, &imap, &nimap, NULL, NULL);
+ 1, 0, NULL, 0, &imap, &nimap, NULL);
if (error)
goto out_unlock_iolock;
ASSERT(nimap == 0 || nimap == 1);
@@ -2746,7 +2567,7 @@ xfs_free_file_space(
}
nimap = 1;
error = xfs_bmapi(NULL, ip, endoffset_fsb - 1,
- 1, 0, NULL, 0, &imap, &nimap, NULL, NULL);
+ 1, 0, NULL, 0, &imap, &nimap, NULL);
if (error)
goto out_unlock_iolock;
ASSERT(nimap == 0 || nimap == 1);
@@ -2814,8 +2635,7 @@ xfs_free_file_space(
if (error)
goto error1;
- xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL);
- xfs_trans_ihold(tp, ip);
+ xfs_trans_ijoin(tp, ip);
/*
* issue the bunmapi() call to free the blocks
@@ -2823,7 +2643,7 @@ xfs_free_file_space(
xfs_bmap_init(&free_list, &firstfsb);
error = xfs_bunmapi(tp, ip, startoffset_fsb,
endoffset_fsb - startoffset_fsb,
- 0, 2, &firstfsb, &free_list, NULL, &done);
+ 0, 2, &firstfsb, &free_list, &done);
if (error) {
goto error0;
}
@@ -2883,8 +2703,6 @@ xfs_change_file_space(
xfs_trans_t *tp;
struct iattr iattr;
- xfs_itrace_entry(ip);
-
if (!S_ISREG(ip->i_d.di_mode))
return XFS_ERROR(EINVAL);
@@ -2985,8 +2803,7 @@ xfs_change_file_space(
xfs_ilock(ip, XFS_ILOCK_EXCL);
- xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL);
- xfs_trans_ihold(tp, ip);
+ xfs_trans_ijoin(tp, ip);
if ((attr_flags & XFS_ATTR_DMI) == 0) {
ip->i_d.di_mode &= ~S_ISUID;
diff --git a/include/acpi/acoutput.h b/include/acpi/acoutput.h
index 5e952262d6e..bc4a6deb73b 100644
--- a/include/acpi/acoutput.h
+++ b/include/acpi/acoutput.h
@@ -71,8 +71,9 @@
#define ACPI_TOOLS 0x00002000
#define ACPI_EXAMPLE 0x00004000
#define ACPI_DRIVER 0x00008000
+#define DT_COMPILER 0x00010000
-#define ACPI_ALL_COMPONENTS 0x0000FFFF
+#define ACPI_ALL_COMPONENTS 0x0001FFFF
#define ACPI_COMPONENT_DEFAULT (ACPI_ALL_COMPONENTS)
/* Component IDs reserved for ACPI drivers */
diff --git a/include/acpi/acpixf.h b/include/acpi/acpixf.h
index 1371cc99739..81d4f3d4b9f 100644
--- a/include/acpi/acpixf.h
+++ b/include/acpi/acpixf.h
@@ -47,7 +47,7 @@
/* Current ACPICA subsystem version in YYYYMMDD format */
-#define ACPI_CA_VERSION 0x20100428
+#define ACPI_CA_VERSION 0x20100702
#include "actypes.h"
#include "actbl.h"
@@ -63,7 +63,6 @@ extern u32 acpi_dbg_layer;
extern u8 acpi_gbl_enable_interpreter_slack;
extern u8 acpi_gbl_all_methods_serialized;
extern u8 acpi_gbl_create_osi_method;
-extern u8 acpi_gbl_leave_wake_gpes_disabled;
extern u8 acpi_gbl_use_default_register_widths;
extern acpi_name acpi_gbl_trace_method_name;
extern u32 acpi_gbl_trace_flags;
@@ -282,16 +281,16 @@ acpi_status acpi_get_event_status(u32 event, acpi_event_status * event_status);
/*
* GPE Interfaces
*/
-acpi_status acpi_set_gpe(acpi_handle gpe_device, u32 gpe_number, u8 action);
+acpi_status acpi_enable_gpe(acpi_handle gpe_device, u32 gpe_number);
-acpi_status
-acpi_enable_gpe(acpi_handle gpe_device, u32 gpe_number, u8 gpe_type);
+acpi_status acpi_disable_gpe(acpi_handle gpe_device, u32 gpe_number);
-acpi_status
-acpi_disable_gpe(acpi_handle gpe_device, u32 gpe_number, u8 gpe_type);
+acpi_status acpi_gpe_can_wake(acpi_handle gpe_device, u32 gpe_number);
acpi_status acpi_clear_gpe(acpi_handle gpe_device, u32 gpe_number);
+acpi_status acpi_gpe_wakeup(acpi_handle gpe_device, u32 gpe_number, u8 action);
+
acpi_status
acpi_get_gpe_status(acpi_handle gpe_device,
u32 gpe_number, acpi_event_status *event_status);
diff --git a/include/acpi/actbl2.h b/include/acpi/actbl2.h
index 95f4d0ef481..d4136b28011 100644
--- a/include/acpi/actbl2.h
+++ b/include/acpi/actbl2.h
@@ -77,8 +77,18 @@
#define ACPI_SIG_UEFI "UEFI" /* Uefi Boot Optimization Table */
#define ACPI_SIG_WAET "WAET" /* Windows ACPI Emulated devices Table */
#define ACPI_SIG_WDAT "WDAT" /* Watchdog Action Table */
+#define ACPI_SIG_WDDT "WDDT" /* Watchdog Timer Description Table */
#define ACPI_SIG_WDRT "WDRT" /* Watchdog Resource Table */
+#ifdef ACPI_UNDEFINED_TABLES
+/*
+ * These tables have been seen in the field, but no definition has been found
+ */
+#define ACPI_SIG_ATKG "ATKG"
+#define ACPI_SIG_GSCI "GSCI" /* GMCH SCI table */
+#define ACPI_SIG_IEIT "IEIT"
+#endif
+
/*
* All tables must be byte-packed to match the ACPI specification, since
* the tables are provided by the system BIOS.
@@ -909,6 +919,44 @@ enum acpi_wdat_instructions {
/*******************************************************************************
*
+ * WDDT - Watchdog Descriptor Table
+ * Version 1
+ *
+ * Conforms to "Using the Intel ICH Family Watchdog Timer (WDT)",
+ * Version 001, September 2002
+ *
+ ******************************************************************************/
+
+struct acpi_table_wddt {
+ struct acpi_table_header header; /* Common ACPI table header */
+ u16 spec_version;
+ u16 table_version;
+ u16 pci_vendor_id;
+ struct acpi_generic_address address;
+ u16 max_count; /* Maximum counter value supported */
+ u16 min_count; /* Minimum counter value supported */
+ u16 period;
+ u16 status;
+ u16 capability;
+};
+
+/* Flags for Status field above */
+
+#define ACPI_WDDT_AVAILABLE (1)
+#define ACPI_WDDT_ACTIVE (1<<1)
+#define ACPI_WDDT_TCO_OS_OWNED (1<<2)
+#define ACPI_WDDT_USER_RESET (1<<11)
+#define ACPI_WDDT_WDT_RESET (1<<12)
+#define ACPI_WDDT_POWER_FAIL (1<<13)
+#define ACPI_WDDT_UNKNOWN_RESET (1<<14)
+
+/* Flags for Capability field above */
+
+#define ACPI_WDDT_AUTO_RESET (1)
+#define ACPI_WDDT_ALERT_SUPPORT (1<<1)
+
+/*******************************************************************************
+ *
* WDRT - Watchdog Resource Table
* Version 1
*
diff --git a/include/acpi/actypes.h b/include/acpi/actypes.h
index d55f4a7b824..5db8f472fec 100644
--- a/include/acpi/actypes.h
+++ b/include/acpi/actypes.h
@@ -663,18 +663,12 @@ typedef u32 acpi_event_status;
#define ACPI_GPE_MAX 0xFF
#define ACPI_NUM_GPE 256
-/* Actions for acpi_set_gpe and acpi_hw_low_set_gpe */
+/* Actions for acpi_gpe_wakeup, acpi_hw_low_set_gpe */
#define ACPI_GPE_ENABLE 0
#define ACPI_GPE_DISABLE 1
#define ACPI_GPE_COND_ENABLE 2
-/* gpe_types for acpi_enable_gpe and acpi_disable_gpe */
-
-#define ACPI_GPE_TYPE_WAKE (u8) 0x01
-#define ACPI_GPE_TYPE_RUNTIME (u8) 0x02
-#define ACPI_GPE_TYPE_WAKE_RUN (u8) 0x03
-
/*
* GPE info flags - Per GPE
* +-------+---+-+-+
diff --git a/include/asm-generic/gpio.h b/include/asm-generic/gpio.h
index 4f3d75e1ad3..c7376bf80b0 100644
--- a/include/asm-generic/gpio.h
+++ b/include/asm-generic/gpio.h
@@ -31,6 +31,7 @@ static inline int gpio_is_valid(int number)
struct device;
struct seq_file;
struct module;
+struct device_node;
/**
* struct gpio_chip - abstract a GPIO controller
@@ -106,6 +107,17 @@ struct gpio_chip {
const char *const *names;
unsigned can_sleep:1;
unsigned exported:1;
+
+#if defined(CONFIG_OF_GPIO)
+ /*
+ * If CONFIG_OF is enabled, then all GPIO controllers described in the
+ * device tree automatically may have an OF translation
+ */
+ struct device_node *of_node;
+ int of_gpio_n_cells;
+ int (*of_xlate)(struct gpio_chip *gc, struct device_node *np,
+ const void *gpio_spec, u32 *flags);
+#endif
};
extern const char *gpiochip_is_requested(struct gpio_chip *chip,
@@ -115,6 +127,9 @@ extern int __must_check gpiochip_reserve(int start, int ngpio);
/* add/remove chips */
extern int gpiochip_add(struct gpio_chip *chip);
extern int __must_check gpiochip_remove(struct gpio_chip *chip);
+extern struct gpio_chip *gpiochip_find(void *data,
+ int (*match)(struct gpio_chip *chip,
+ void *data));
/* Always use the library code for GPIO management calls,
diff --git a/include/asm-generic/local64.h b/include/asm-generic/local64.h
new file mode 100644
index 00000000000..02ac760c1a8
--- /dev/null
+++ b/include/asm-generic/local64.h
@@ -0,0 +1,96 @@
+#ifndef _ASM_GENERIC_LOCAL64_H
+#define _ASM_GENERIC_LOCAL64_H
+
+#include <linux/percpu.h>
+#include <asm/types.h>
+
+/*
+ * A signed long type for operations which are atomic for a single CPU.
+ * Usually used in combination with per-cpu variables.
+ *
+ * This is the default implementation, which uses atomic64_t. Which is
+ * rather pointless. The whole point behind local64_t is that some processors
+ * can perform atomic adds and subtracts in a manner which is atomic wrt IRQs
+ * running on this CPU. local64_t allows exploitation of such capabilities.
+ */
+
+/* Implement in terms of atomics. */
+
+#if BITS_PER_LONG == 64
+
+#include <asm/local.h>
+
+typedef struct {
+ local_t a;
+} local64_t;
+
+#define LOCAL64_INIT(i) { LOCAL_INIT(i) }
+
+#define local64_read(l) local_read(&(l)->a)
+#define local64_set(l,i) local_set((&(l)->a),(i))
+#define local64_inc(l) local_inc(&(l)->a)
+#define local64_dec(l) local_dec(&(l)->a)
+#define local64_add(i,l) local_add((i),(&(l)->a))
+#define local64_sub(i,l) local_sub((i),(&(l)->a))
+
+#define local64_sub_and_test(i, l) local_sub_and_test((i), (&(l)->a))
+#define local64_dec_and_test(l) local_dec_and_test(&(l)->a)
+#define local64_inc_and_test(l) local_inc_and_test(&(l)->a)
+#define local64_add_negative(i, l) local_add_negative((i), (&(l)->a))
+#define local64_add_return(i, l) local_add_return((i), (&(l)->a))
+#define local64_sub_return(i, l) local_sub_return((i), (&(l)->a))
+#define local64_inc_return(l) local_inc_return(&(l)->a)
+
+#define local64_cmpxchg(l, o, n) local_cmpxchg((&(l)->a), (o), (n))
+#define local64_xchg(l, n) local_xchg((&(l)->a), (n))
+#define local64_add_unless(l, _a, u) local_add_unless((&(l)->a), (_a), (u))
+#define local64_inc_not_zero(l) local_inc_not_zero(&(l)->a)
+
+/* Non-atomic variants, ie. preemption disabled and won't be touched
+ * in interrupt, etc. Some archs can optimize this case well. */
+#define __local64_inc(l) local64_set((l), local64_read(l) + 1)
+#define __local64_dec(l) local64_set((l), local64_read(l) - 1)
+#define __local64_add(i,l) local64_set((l), local64_read(l) + (i))
+#define __local64_sub(i,l) local64_set((l), local64_read(l) - (i))
+
+#else /* BITS_PER_LONG != 64 */
+
+#include <asm/atomic.h>
+
+/* Don't use typedef: don't want them to be mixed with atomic_t's. */
+typedef struct {
+ atomic64_t a;
+} local64_t;
+
+#define LOCAL64_INIT(i) { ATOMIC_LONG_INIT(i) }
+
+#define local64_read(l) atomic64_read(&(l)->a)
+#define local64_set(l,i) atomic64_set((&(l)->a),(i))
+#define local64_inc(l) atomic64_inc(&(l)->a)
+#define local64_dec(l) atomic64_dec(&(l)->a)
+#define local64_add(i,l) atomic64_add((i),(&(l)->a))
+#define local64_sub(i,l) atomic64_sub((i),(&(l)->a))
+
+#define local64_sub_and_test(i, l) atomic64_sub_and_test((i), (&(l)->a))
+#define local64_dec_and_test(l) atomic64_dec_and_test(&(l)->a)
+#define local64_inc_and_test(l) atomic64_inc_and_test(&(l)->a)
+#define local64_add_negative(i, l) atomic64_add_negative((i), (&(l)->a))
+#define local64_add_return(i, l) atomic64_add_return((i), (&(l)->a))
+#define local64_sub_return(i, l) atomic64_sub_return((i), (&(l)->a))
+#define local64_inc_return(l) atomic64_inc_return(&(l)->a)
+
+#define local64_cmpxchg(l, o, n) atomic64_cmpxchg((&(l)->a), (o), (n))
+#define local64_xchg(l, n) atomic64_xchg((&(l)->a), (n))
+#define local64_add_unless(l, _a, u) atomic64_add_unless((&(l)->a), (_a), (u))
+#define local64_inc_not_zero(l) atomic64_inc_not_zero(&(l)->a)
+
+/* Non-atomic variants, ie. preemption disabled and won't be touched
+ * in interrupt, etc. Some archs can optimize this case well. */
+#define __local64_inc(l) local64_set((l), local64_read(l) + 1)
+#define __local64_dec(l) local64_set((l), local64_read(l) - 1)
+#define __local64_add(i,l) local64_set((l), local64_read(l) + (i))
+#define __local64_sub(i,l) local64_set((l), local64_read(l) - (i))
+
+#endif /* BITS_PER_LONG != 64 */
+
+#endif /* _ASM_GENERIC_LOCAL64_H */
diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h
index 030a954ed29..8a92a170fb7 100644
--- a/include/asm-generic/vmlinux.lds.h
+++ b/include/asm-generic/vmlinux.lds.h
@@ -156,10 +156,6 @@
CPU_KEEP(exit.data) \
MEM_KEEP(init.data) \
MEM_KEEP(exit.data) \
- . = ALIGN(8); \
- VMLINUX_SYMBOL(__start___markers) = .; \
- *(__markers) \
- VMLINUX_SYMBOL(__stop___markers) = .; \
. = ALIGN(32); \
VMLINUX_SYMBOL(__start___tracepoints) = .; \
*(__tracepoints) \
@@ -653,6 +649,7 @@
EXIT_DATA \
EXIT_CALL \
*(.discard) \
+ *(.discard.*) \
}
/**
diff --git a/include/drm/drm.h b/include/drm/drm.h
index e3f46e0cb7d..e5f70617dec 100644
--- a/include/drm/drm.h
+++ b/include/drm/drm.h
@@ -663,6 +663,8 @@ struct drm_gem_open {
#define DRM_IOCTL_UNLOCK DRM_IOW( 0x2b, struct drm_lock)
#define DRM_IOCTL_FINISH DRM_IOW( 0x2c, struct drm_lock)
+#define DRM_IOCTL_GEM_PRIME_OPEN DRM_IOWR(0x2e, struct drm_gem_open)
+
#define DRM_IOCTL_AGP_ACQUIRE DRM_IO( 0x30)
#define DRM_IOCTL_AGP_RELEASE DRM_IO( 0x31)
#define DRM_IOCTL_AGP_ENABLE DRM_IOW( 0x32, struct drm_agp_mode)
diff --git a/include/drm/drmP.h b/include/drm/drmP.h
index c1b987158df..e2a4da7d7fa 100644
--- a/include/drm/drmP.h
+++ b/include/drm/drmP.h
@@ -9,6 +9,7 @@
/*
* Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
* Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
+ * Copyright (c) 2009-2010, Code Aurora Forum.
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
@@ -48,9 +49,9 @@
#include <linux/proc_fs.h>
#include <linux/init.h>
#include <linux/file.h>
+#include <linux/platform_device.h>
#include <linux/pci.h>
#include <linux/jiffies.h>
-#include <linux/smp_lock.h> /* For (un)lock_kernel */
#include <linux/dma-mapping.h>
#include <linux/mm.h>
#include <linux/cdev.h>
@@ -144,6 +145,7 @@ extern void drm_ut_debug_printk(unsigned int request_level,
#define DRIVER_IRQ_VBL2 0x800
#define DRIVER_GEM 0x1000
#define DRIVER_MODESET 0x2000
+#define DRIVER_USE_PLATFORM_DEVICE 0x4000
/***********************************************************************/
/** \name Begin the DRM... */
@@ -403,6 +405,8 @@ struct drm_pending_event {
struct drm_event *event;
struct list_head link;
struct drm_file *file_priv;
+ pid_t pid; /* pid of requester, no guarantee it's valid by the time
+ we deliver the event, for tracing only */
void (*destroy)(struct drm_pending_event *event);
};
@@ -823,6 +827,7 @@ struct drm_driver {
int num_ioctls;
struct file_operations fops;
struct pci_driver pci_driver;
+ struct platform_device *platform_device;
/* List of devices hanging off this driver */
struct list_head device_list;
};
@@ -1015,12 +1020,16 @@ struct drm_device {
struct drm_agp_head *agp; /**< AGP data */
+ struct device *dev; /**< Device structure */
struct pci_dev *pdev; /**< PCI device structure */
int pci_vendor; /**< PCI vendor id */
int pci_device; /**< PCI device id */
#ifdef __alpha__
struct pci_controller *hose;
#endif
+
+ struct platform_device *platformdev; /**< Platform device struture */
+
struct drm_sg_mem *sg; /**< Scatter gather memory */
int num_crtcs; /**< Number of CRTCs on this device */
void *dev_private; /**< device private data */
@@ -1060,17 +1069,21 @@ struct drm_device {
};
-static inline int drm_dev_to_irq(struct drm_device *dev)
-{
- return dev->pdev->irq;
-}
-
static __inline__ int drm_core_check_feature(struct drm_device *dev,
int feature)
{
return ((dev->driver->driver_features & feature) ? 1 : 0);
}
+
+static inline int drm_dev_to_irq(struct drm_device *dev)
+{
+ if (drm_core_check_feature(dev, DRIVER_USE_PLATFORM_DEVICE))
+ return platform_get_irq(dev->platformdev, 0);
+ else
+ return dev->pdev->irq;
+}
+
#ifdef __alpha__
#define drm_get_pci_domain(dev) dev->hose->index
#else
@@ -1138,6 +1151,7 @@ extern long drm_compat_ioctl(struct file *filp,
extern int drm_lastclose(struct drm_device *dev);
/* Device support (drm_fops.h) */
+extern struct mutex drm_global_mutex;
extern int drm_open(struct inode *inode, struct file *filp);
extern int drm_stub_open(struct inode *inode, struct file *filp);
extern int drm_fasync(int fd, struct file *filp, int on);
@@ -1273,10 +1287,6 @@ extern int drm_freebufs(struct drm_device *dev, void *data,
extern int drm_mapbufs(struct drm_device *dev, void *data,
struct drm_file *file_priv);
extern int drm_order(unsigned long size);
-extern resource_size_t drm_get_resource_start(struct drm_device *dev,
- unsigned int resource);
-extern resource_size_t drm_get_resource_len(struct drm_device *dev,
- unsigned int resource);
/* DMA support (drm_dma.h) */
extern int drm_dma_setup(struct drm_device *dev);
@@ -1351,8 +1361,11 @@ extern int drm_dropmaster_ioctl(struct drm_device *dev, void *data,
struct drm_master *drm_master_create(struct drm_minor *minor);
extern struct drm_master *drm_master_get(struct drm_master *master);
extern void drm_master_put(struct drm_master **master);
-extern int drm_get_dev(struct pci_dev *pdev, const struct pci_device_id *ent,
- struct drm_driver *driver);
+extern int drm_get_pci_dev(struct pci_dev *pdev,
+ const struct pci_device_id *ent,
+ struct drm_driver *driver);
+extern int drm_get_platform_dev(struct platform_device *pdev,
+ struct drm_driver *driver);
extern void drm_put_dev(struct drm_device *dev);
extern int drm_put_minor(struct drm_minor **minor);
extern unsigned int drm_debug;
@@ -1440,6 +1453,8 @@ void drm_gem_vm_open(struct vm_area_struct *vma);
void drm_gem_vm_close(struct vm_area_struct *vma);
int drm_gem_mmap(struct file *filp, struct vm_area_struct *vma);
+#include "drm_global.h"
+
static inline void
drm_gem_object_reference(struct drm_gem_object *obj)
{
@@ -1529,6 +1544,9 @@ static __inline__ struct drm_local_map *drm_core_findmap(struct drm_device *dev,
static __inline__ int drm_device_is_agp(struct drm_device *dev)
{
+ if (drm_core_check_feature(dev, DRIVER_USE_PLATFORM_DEVICE))
+ return 0;
+
if (dev->driver->device_is_agp != NULL) {
int err = (*dev->driver->device_is_agp) (dev);
@@ -1542,7 +1560,10 @@ static __inline__ int drm_device_is_agp(struct drm_device *dev)
static __inline__ int drm_device_is_pcie(struct drm_device *dev)
{
- return pci_find_capability(dev->pdev, PCI_CAP_ID_EXP);
+ if (drm_core_check_feature(dev, DRIVER_USE_PLATFORM_DEVICE))
+ return 0;
+ else
+ return pci_find_capability(dev->pdev, PCI_CAP_ID_EXP);
}
static __inline__ void drm_core_dropmap(struct drm_local_map *map)
@@ -1550,6 +1571,21 @@ static __inline__ void drm_core_dropmap(struct drm_local_map *map)
}
#include "drm_mem_util.h"
+
+static inline void *drm_get_device(struct drm_device *dev)
+{
+ if (drm_core_check_feature(dev, DRIVER_USE_PLATFORM_DEVICE))
+ return dev->platformdev;
+ else
+ return dev->pdev;
+}
+
+extern int drm_platform_init(struct drm_driver *driver);
+extern int drm_pci_init(struct drm_driver *driver);
+extern int drm_fill_in_dev(struct drm_device *dev,
+ const struct pci_device_id *ent,
+ struct drm_driver *driver);
+int drm_get_minor(struct drm_device *dev, struct drm_minor **minor, int type);
/*@}*/
#endif /* __KERNEL__ */
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
index 93a1a31b9c2..c707270bff5 100644
--- a/include/drm/drm_crtc.h
+++ b/include/drm/drm_crtc.h
@@ -31,7 +31,6 @@
#include <linux/idr.h>
#include <linux/fb.h>
-#include <linux/slow-work.h>
struct drm_device;
struct drm_mode_set;
@@ -595,7 +594,7 @@ struct drm_mode_config {
/* output poll support */
bool poll_enabled;
- struct delayed_slow_work output_poll_slow_work;
+ struct delayed_work output_poll_work;
/* pointers to standard properties */
struct list_head property_blob_list;
diff --git a/include/drm/drm_crtc_helper.h b/include/drm/drm_crtc_helper.h
index 1121f7799c6..59b7073b13f 100644
--- a/include/drm/drm_crtc_helper.h
+++ b/include/drm/drm_crtc_helper.h
@@ -60,9 +60,14 @@ struct drm_crtc_helper_funcs {
/* Move the crtc on the current fb to the given position *optional* */
int (*mode_set_base)(struct drm_crtc *crtc, int x, int y,
struct drm_framebuffer *old_fb);
+ int (*mode_set_base_atomic)(struct drm_crtc *crtc,
+ struct drm_framebuffer *fb, int x, int y);
/* reload the current crtc LUT */
void (*load_lut)(struct drm_crtc *crtc);
+
+ /* disable crtc when not in use - more explicit than dpms off */
+ void (*disable)(struct drm_crtc *crtc);
};
struct drm_encoder_helper_funcs {
diff --git a/include/drm/drm_fb_helper.h b/include/drm/drm_fb_helper.h
index f0a6afc47e7..f22e7fe4b6d 100644
--- a/include/drm/drm_fb_helper.h
+++ b/include/drm/drm_fb_helper.h
@@ -32,6 +32,8 @@
struct drm_fb_helper;
+#include <linux/kgdb.h>
+
struct drm_fb_helper_crtc {
uint32_t crtc_id;
struct drm_mode_set mode_set;
@@ -78,6 +80,7 @@ struct drm_fb_helper_connector {
struct drm_fb_helper {
struct drm_framebuffer *fb;
+ struct drm_framebuffer *saved_fb;
struct drm_device *dev;
struct drm_display_mode *mode;
int crtc_count;
@@ -126,5 +129,7 @@ int drm_fb_helper_setcmap(struct fb_cmap *cmap, struct fb_info *info);
bool drm_fb_helper_hotplug_event(struct drm_fb_helper *fb_helper);
bool drm_fb_helper_initial_config(struct drm_fb_helper *fb_helper, int bpp_sel);
int drm_fb_helper_single_add_all_connectors(struct drm_fb_helper *fb_helper);
+int drm_fb_helper_debug_enter(struct fb_info *info);
+int drm_fb_helper_debug_leave(struct fb_info *info);
#endif
diff --git a/include/drm/drm_global.h b/include/drm/drm_global.h
new file mode 100644
index 00000000000..a06805eaf64
--- /dev/null
+++ b/include/drm/drm_global.h
@@ -0,0 +1,53 @@
+/**************************************************************************
+ *
+ * Copyright 2008-2009 VMware, Inc., Palo Alto, CA., USA
+ * All Rights Reserved.
+ *
+ * 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, sub license, 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 (including the
+ * next paragraph) 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 NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ **************************************************************************/
+/*
+ * Authors: Thomas Hellstrom <thellstrom-at-vmware-dot-com>
+ */
+
+#ifndef _DRM_GLOBAL_H_
+#define _DRM_GLOBAL_H_
+enum drm_global_types {
+ DRM_GLOBAL_TTM_MEM = 0,
+ DRM_GLOBAL_TTM_BO,
+ DRM_GLOBAL_TTM_OBJECT,
+ DRM_GLOBAL_NUM
+};
+
+struct drm_global_reference {
+ enum drm_global_types global_type;
+ size_t size;
+ void *object;
+ int (*init) (struct drm_global_reference *);
+ void (*release) (struct drm_global_reference *);
+};
+
+extern void drm_global_init(void);
+extern void drm_global_release(void);
+extern int drm_global_item_ref(struct drm_global_reference *ref);
+extern void drm_global_item_unref(struct drm_global_reference *ref);
+
+#endif
diff --git a/include/drm/drm_mm.h b/include/drm/drm_mm.h
index 4c10be39a43..bf01531193d 100644
--- a/include/drm/drm_mm.h
+++ b/include/drm/drm_mm.h
@@ -42,21 +42,31 @@
#endif
struct drm_mm_node {
- struct list_head fl_entry;
- struct list_head ml_entry;
- int free;
+ struct list_head free_stack;
+ struct list_head node_list;
+ unsigned free : 1;
+ unsigned scanned_block : 1;
+ unsigned scanned_prev_free : 1;
+ unsigned scanned_next_free : 1;
unsigned long start;
unsigned long size;
struct drm_mm *mm;
- void *private;
};
struct drm_mm {
- struct list_head fl_entry;
- struct list_head ml_entry;
+ /* List of free memory blocks, most recently freed ordered. */
+ struct list_head free_stack;
+ /* List of all memory nodes, ordered according to the (increasing) start
+ * address of the memory node. */
+ struct list_head node_list;
struct list_head unused_nodes;
int num_unused;
spinlock_t unused_lock;
+ unsigned scan_alignment;
+ unsigned long scan_size;
+ unsigned long scan_hit_start;
+ unsigned scan_hit_size;
+ unsigned scanned_blocks;
};
/*
@@ -133,6 +143,11 @@ static inline struct drm_mm *drm_get_mm(struct drm_mm_node *block)
return block->mm;
}
+void drm_mm_init_scan(struct drm_mm *mm, unsigned long size,
+ unsigned alignment);
+int drm_mm_scan_add_block(struct drm_mm_node *node);
+int drm_mm_scan_remove_block(struct drm_mm_node *node);
+
extern void drm_mm_debug_table(struct drm_mm *mm, const char *prefix);
#ifdef CONFIG_DEBUG_FS
int drm_mm_dump_table(struct seq_file *m, struct drm_mm *mm);
diff --git a/include/drm/drm_mode.h b/include/drm/drm_mode.h
index c5ba1636613..0fc7397c8f1 100644
--- a/include/drm/drm_mode.h
+++ b/include/drm/drm_mode.h
@@ -74,6 +74,7 @@
/* Dithering mode options */
#define DRM_MODE_DITHERING_OFF 0
#define DRM_MODE_DITHERING_ON 1
+#define DRM_MODE_DITHERING_AUTO 2
/* Dirty info options */
#define DRM_MODE_DIRTY_OFF 0
diff --git a/include/drm/drm_pciids.h b/include/drm/drm_pciids.h
index 2d428b088cc..3a9940ef728 100644
--- a/include/drm/drm_pciids.h
+++ b/include/drm/drm_pciids.h
@@ -146,6 +146,8 @@
{0x1002, 0x6888, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CYPRESS|RADEON_NEW_MEMMAP}, \
{0x1002, 0x6889, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CYPRESS|RADEON_NEW_MEMMAP}, \
{0x1002, 0x688A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CYPRESS|RADEON_NEW_MEMMAP}, \
+ {0x1002, 0x688C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CYPRESS|RADEON_NEW_MEMMAP}, \
+ {0x1002, 0x688D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CYPRESS|RADEON_NEW_MEMMAP}, \
{0x1002, 0x6898, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CYPRESS|RADEON_NEW_MEMMAP}, \
{0x1002, 0x6899, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CYPRESS|RADEON_NEW_MEMMAP}, \
{0x1002, 0x689c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_HEMLOCK|RADEON_NEW_MEMMAP}, \
@@ -161,6 +163,7 @@
{0x1002, 0x68be, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_JUNIPER|RADEON_NEW_MEMMAP}, \
{0x1002, 0x68c0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_REDWOOD|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
{0x1002, 0x68c1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_REDWOOD|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
+ {0x1002, 0x68c7, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_REDWOOD|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
{0x1002, 0x68c8, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_REDWOOD|RADEON_NEW_MEMMAP}, \
{0x1002, 0x68c9, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_REDWOOD|RADEON_NEW_MEMMAP}, \
{0x1002, 0x68d8, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_REDWOOD|RADEON_NEW_MEMMAP}, \
@@ -174,6 +177,7 @@
{0x1002, 0x68e8, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CEDAR|RADEON_NEW_MEMMAP}, \
{0x1002, 0x68e9, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CEDAR|RADEON_NEW_MEMMAP}, \
{0x1002, 0x68f1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CEDAR|RADEON_NEW_MEMMAP}, \
+ {0x1002, 0x68f2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CEDAR|RADEON_NEW_MEMMAP}, \
{0x1002, 0x68f8, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CEDAR|RADEON_NEW_MEMMAP}, \
{0x1002, 0x68f9, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CEDAR|RADEON_NEW_MEMMAP}, \
{0x1002, 0x68fe, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CEDAR|RADEON_NEW_MEMMAP}, \
@@ -314,6 +318,7 @@
{0x1002, 0x9456, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV770|RADEON_NEW_MEMMAP}, \
{0x1002, 0x945A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV770|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
{0x1002, 0x945B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV770|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
+ {0x1002, 0x945E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV770|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
{0x1002, 0x9460, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV770|RADEON_NEW_MEMMAP}, \
{0x1002, 0x9462, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV770|RADEON_NEW_MEMMAP}, \
{0x1002, 0x946A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV770|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
@@ -324,6 +329,7 @@
{0x1002, 0x9487, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV730|RADEON_NEW_MEMMAP}, \
{0x1002, 0x9488, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV730|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
{0x1002, 0x9489, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV730|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
+ {0x1002, 0x948A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV730|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
{0x1002, 0x948F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV730|RADEON_NEW_MEMMAP}, \
{0x1002, 0x9490, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV730|RADEON_NEW_MEMMAP}, \
{0x1002, 0x9491, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV730|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
@@ -366,6 +372,7 @@
{0x1002, 0x9553, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV710|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
{0x1002, 0x9555, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV710|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
{0x1002, 0x9557, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV710|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
+ {0x1002, 0x955f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV710|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
{0x1002, 0x9580, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV630|RADEON_NEW_MEMMAP}, \
{0x1002, 0x9581, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV630|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
{0x1002, 0x9583, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV630|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
diff --git a/include/drm/i2c/sil164.h b/include/drm/i2c/sil164.h
new file mode 100644
index 00000000000..205e27384c8
--- /dev/null
+++ b/include/drm/i2c/sil164.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2010 Francisco Jerez.
+ * All Rights Reserved.
+ *
+ * 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 (including the
+ * next paragraph) 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 COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS 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 __DRM_I2C_SIL164_H__
+#define __DRM_I2C_SIL164_H__
+
+/**
+ * struct sil164_encoder_params
+ *
+ * Describes how the sil164 is connected to the GPU. It should be used
+ * as the @params parameter of its @set_config method.
+ *
+ * See "http://www.siliconimage.com/docs/SiI-DS-0021-E-164.pdf".
+ */
+struct sil164_encoder_params {
+ enum {
+ SIL164_INPUT_EDGE_FALLING = 0,
+ SIL164_INPUT_EDGE_RISING
+ } input_edge;
+
+ enum {
+ SIL164_INPUT_WIDTH_12BIT = 0,
+ SIL164_INPUT_WIDTH_24BIT
+ } input_width;
+
+ enum {
+ SIL164_INPUT_SINGLE_EDGE = 0,
+ SIL164_INPUT_DUAL_EDGE
+ } input_dual;
+
+ enum {
+ SIL164_PLL_FILTER_ON = 0,
+ SIL164_PLL_FILTER_OFF,
+ } pll_filter;
+
+ int input_skew; /** < Allowed range [-4, 3], use 0 for no de-skew. */
+ int duallink_skew; /** < Allowed range [-4, 3]. */
+};
+
+#endif
diff --git a/include/drm/i915_drm.h b/include/drm/i915_drm.h
index 7f0028e1010..8f8b072c4c7 100644
--- a/include/drm/i915_drm.h
+++ b/include/drm/i915_drm.h
@@ -33,6 +33,15 @@
* subject to backwards-compatibility constraints.
*/
+#ifdef __KERNEL__
+/* For use by IPS driver */
+extern unsigned long i915_read_mch_val(void);
+extern bool i915_gpu_raise(void);
+extern bool i915_gpu_lower(void);
+extern bool i915_gpu_busy(void);
+extern bool i915_gpu_turbo_disable(void);
+#endif
+
/* Each region is a minimum of 16k, and there are at most 255 of them.
*/
#define I915_NR_TEX_REGIONS 255 /* table size 2k - maximum due to use
diff --git a/include/drm/radeon_drm.h b/include/drm/radeon_drm.h
index 5347063e9d5..0acaf8f9143 100644
--- a/include/drm/radeon_drm.h
+++ b/include/drm/radeon_drm.h
@@ -904,6 +904,8 @@ struct drm_radeon_cs {
#define RADEON_INFO_ACCEL_WORKING 0x03
#define RADEON_INFO_CRTC_FROM_ID 0x04
#define RADEON_INFO_ACCEL_WORKING2 0x05
+#define RADEON_INFO_TILING_CONFIG 0x06
+#define RADEON_INFO_WANT_HYPERZ 0x07
struct drm_radeon_info {
uint32_t request;
diff --git a/include/drm/ttm/ttm_bo_driver.h b/include/drm/ttm/ttm_bo_driver.h
index 0ea602da43e..b87504235f1 100644
--- a/include/drm/ttm/ttm_bo_driver.h
+++ b/include/drm/ttm/ttm_bo_driver.h
@@ -34,6 +34,7 @@
#include "ttm/ttm_memory.h"
#include "ttm/ttm_module.h"
#include "drm_mm.h"
+#include "drm_global.h"
#include "linux/workqueue.h"
#include "linux/fs.h"
#include "linux/spinlock.h"
@@ -362,7 +363,7 @@ struct ttm_bo_driver {
*/
struct ttm_bo_global_ref {
- struct ttm_global_reference ref;
+ struct drm_global_reference ref;
struct ttm_mem_global *mem_glob;
};
@@ -687,8 +688,8 @@ extern int ttm_mem_io_reserve(struct ttm_bo_device *bdev,
extern void ttm_mem_io_free(struct ttm_bo_device *bdev,
struct ttm_mem_reg *mem);
-extern void ttm_bo_global_release(struct ttm_global_reference *ref);
-extern int ttm_bo_global_init(struct ttm_global_reference *ref);
+extern void ttm_bo_global_release(struct drm_global_reference *ref);
+extern int ttm_bo_global_init(struct drm_global_reference *ref);
extern int ttm_bo_device_release(struct ttm_bo_device *bdev);
diff --git a/include/drm/ttm/ttm_module.h b/include/drm/ttm/ttm_module.h
index cf416aee19a..45fa318c158 100644
--- a/include/drm/ttm/ttm_module.h
+++ b/include/drm/ttm/ttm_module.h
@@ -35,26 +35,6 @@
struct kobject;
#define TTM_PFX "[TTM] "
-
-enum ttm_global_types {
- TTM_GLOBAL_TTM_MEM = 0,
- TTM_GLOBAL_TTM_BO,
- TTM_GLOBAL_TTM_OBJECT,
- TTM_GLOBAL_NUM
-};
-
-struct ttm_global_reference {
- enum ttm_global_types global_type;
- size_t size;
- void *object;
- int (*init) (struct ttm_global_reference *);
- void (*release) (struct ttm_global_reference *);
-};
-
-extern void ttm_global_init(void);
-extern void ttm_global_release(void);
-extern int ttm_global_item_ref(struct ttm_global_reference *ref);
-extern void ttm_global_item_unref(struct ttm_global_reference *ref);
extern struct kobject *ttm_get_kobj(void);
#endif /* _TTM_MODULE_H_ */
diff --git a/include/keys/dns_resolver-type.h b/include/keys/dns_resolver-type.h
new file mode 100644
index 00000000000..9284a19393a
--- /dev/null
+++ b/include/keys/dns_resolver-type.h
@@ -0,0 +1,23 @@
+/* DNS resolver key type
+ *
+ * Copyright (C) 2010 Wang Lei. All Rights Reserved.
+ * Written by Wang Lei (wang840925@gmail.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 _KEYS_DNS_RESOLVER_TYPE_H
+#define _KEYS_DNS_RESOLVER_TYPE_H
+
+#include <linux/key-type.h>
+
+extern struct key_type key_type_dns_resolver;
+
+extern int request_dns_resolver_key(const char *description,
+ const char *callout_info,
+ char **data);
+
+#endif /* _KEYS_DNS_RESOLVER_TYPE_H */
diff --git a/include/linux/Kbuild b/include/linux/Kbuild
index 2fc8e14cc24..9aa9bcadf86 100644
--- a/include/linux/Kbuild
+++ b/include/linux/Kbuild
@@ -276,6 +276,7 @@ ifneq ($(wildcard $(srctree)/arch/$(SRCARCH)/include/asm/kvm_para.h \
$(srctree)/include/asm-$(SRCARCH)/kvm_para.h),)
unifdef-y += kvm_para.h
endif
+unifdef-y += l2tp.h
unifdef-y += llc.h
unifdef-y += loop.h
unifdef-y += lp.h
diff --git a/include/linux/ahci_platform.h b/include/linux/ahci_platform.h
index f7dd576dd5a..be3d9a77d6e 100644
--- a/include/linux/ahci_platform.h
+++ b/include/linux/ahci_platform.h
@@ -15,11 +15,13 @@
#ifndef _AHCI_PLATFORM_H
#define _AHCI_PLATFORM_H
+#include <linux/compiler.h>
+
struct device;
struct ata_port_info;
struct ahci_platform_data {
- int (*init)(struct device *dev);
+ int (*init)(struct device *dev, void __iomem *addr);
void (*exit)(struct device *dev);
const struct ata_port_info *ata_port_info;
unsigned int force_port_map;
diff --git a/include/linux/atmdev.h b/include/linux/atmdev.h
index 817b23705c9..f6481daf6e5 100644
--- a/include/linux/atmdev.h
+++ b/include/linux/atmdev.h
@@ -431,6 +431,14 @@ struct atm_dev *atm_dev_register(const char *type,const struct atmdev_ops *ops,
int number,unsigned long *flags); /* number == -1: pick first available */
struct atm_dev *atm_dev_lookup(int number);
void atm_dev_deregister(struct atm_dev *dev);
+
+/* atm_dev_signal_change
+ *
+ * Propagate lower layer signal change in atm_dev->signal to netdevice.
+ * The event will be sent via a notifier call chain.
+ */
+void atm_dev_signal_change(struct atm_dev *dev, char signal);
+
void vcc_insert_socket(struct sock *sk);
@@ -510,6 +518,15 @@ void register_atm_ioctl(struct atm_ioctl *);
*/
void deregister_atm_ioctl(struct atm_ioctl *);
+
+/* register_atmdevice_notifier - register atm_dev notify events
+ *
+ * Clients like br2684 will register notify events
+ * Currently we notify of signal found/lost
+ */
+int register_atmdevice_notifier(struct notifier_block *nb);
+void unregister_atmdevice_notifier(struct notifier_block *nb);
+
#endif /* __KERNEL__ */
#endif
diff --git a/include/linux/brcmphy.h b/include/linux/brcmphy.h
index 7f437ca1ed4..b840a496028 100644
--- a/include/linux/brcmphy.h
+++ b/include/linux/brcmphy.h
@@ -1,6 +1,13 @@
#define PHY_ID_BCM50610 0x0143bd60
#define PHY_ID_BCM50610M 0x0143bd70
+#define PHY_ID_BCM5241 0x0143bc30
#define PHY_ID_BCMAC131 0x0143bc70
+#define PHY_ID_BCM5481 0x0143bca0
+#define PHY_ID_BCM5482 0x0143bcb0
+#define PHY_ID_BCM5411 0x00206070
+#define PHY_ID_BCM5421 0x002060e0
+#define PHY_ID_BCM5464 0x002060b0
+#define PHY_ID_BCM5461 0x002060c0
#define PHY_ID_BCM57780 0x03625d90
#define PHY_BCM_OUI_MASK 0xfffffc00
diff --git a/include/linux/caif/caif_socket.h b/include/linux/caif/caif_socket.h
index 2a61eb1beb8..d9cb19b7cff 100644
--- a/include/linux/caif/caif_socket.h
+++ b/include/linux/caif/caif_socket.h
@@ -62,6 +62,7 @@ enum caif_channel_priority {
* @CAIFPROTO_DATAGRAM_LOOP: Datagram loopback channel, used for testing.
* @CAIFPROTO_UTIL: Utility (Psock) channel.
* @CAIFPROTO_RFM: Remote File Manager
+ * @CAIFPROTO_DEBUG: Debug link
*
* This enum defines the CAIF Channel type to be used. This defines
* the service to connect to on the modem.
@@ -72,6 +73,7 @@ enum caif_protocol_type {
CAIFPROTO_DATAGRAM_LOOP,
CAIFPROTO_UTIL,
CAIFPROTO_RFM,
+ CAIFPROTO_DEBUG,
_CAIFPROTO_MAX
};
#define CAIFPROTO_MAX _CAIFPROTO_MAX
@@ -83,6 +85,28 @@ enum caif_protocol_type {
enum caif_at_type {
CAIF_ATTYPE_PLAIN = 2
};
+ /**
+ * enum caif_debug_type - Content selection for debug connection
+ * @CAIF_DEBUG_TRACE_INTERACTIVE: Connection will contain
+ * both trace and interactive debug.
+ * @CAIF_DEBUG_TRACE: Connection contains trace only.
+ * @CAIF_DEBUG_INTERACTIVE: Connection to interactive debug.
+ */
+enum caif_debug_type {
+ CAIF_DEBUG_TRACE_INTERACTIVE = 0,
+ CAIF_DEBUG_TRACE,
+ CAIF_DEBUG_INTERACTIVE,
+};
+
+/**
+ * enum caif_debug_service - Debug Service Endpoint
+ * @CAIF_RADIO_DEBUG_SERVICE: Debug service on the Radio sub-system
+ * @CAIF_APP_DEBUG_SERVICE: Debug for the applications sub-system
+ */
+enum caif_debug_service {
+ CAIF_RADIO_DEBUG_SERVICE = 1,
+ CAIF_APP_DEBUG_SERVICE
+};
/**
* struct sockaddr_caif - the sockaddr structure for CAIF sockets.
@@ -109,6 +133,12 @@ enum caif_at_type {
*
* @u.rfm.volume: Volume to mount.
*
+ * @u.dbg: Applies when family = CAIFPROTO_DEBUG.
+ *
+ * @u.dbg.type: Type of debug connection to set up
+ * (caif_debug_type).
+ *
+ * @u.dbg.service: Service sub-system to connect (caif_debug_service
* Description:
* This structure holds the connect parameters used for setting up a
* CAIF Channel. It defines the service to connect to on the modem.
@@ -130,6 +160,10 @@ struct sockaddr_caif {
__u32 connection_id;
char volume[16];
} rfm; /* CAIFPROTO_RFM */
+ struct {
+ __u8 type; /* type:enum caif_debug_type */
+ __u8 service; /* service:caif_debug_service */
+ } dbg; /* CAIFPROTO_DEBUG */
} u;
};
diff --git a/include/linux/can/platform/flexcan.h b/include/linux/can/platform/flexcan.h
new file mode 100644
index 00000000000..72b713ab57e
--- /dev/null
+++ b/include/linux/can/platform/flexcan.h
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2010 Marc Kleine-Budde <kernel@pengutronix.de>
+ *
+ * This file is released under the GPLv2
+ *
+ */
+
+#ifndef __CAN_PLATFORM_FLEXCAN_H
+#define __CAN_PLATFORM_FLEXCAN_H
+
+/**
+ * struct flexcan_platform_data - flex CAN controller platform data
+ * @transceiver_enable: - called to power on/off the transceiver
+ *
+ */
+struct flexcan_platform_data {
+ void (*transceiver_switch)(int enable);
+};
+
+#endif /* __CAN_PLATFORM_FLEXCAN_H */
diff --git a/include/linux/capability.h b/include/linux/capability.h
index 39e5ff512fb..90012b9ddbf 100644
--- a/include/linux/capability.h
+++ b/include/linux/capability.h
@@ -49,9 +49,6 @@ typedef struct __user_cap_data_struct {
} __user *cap_user_data_t;
-#define XATTR_CAPS_SUFFIX "capability"
-#define XATTR_NAME_CAPS XATTR_SECURITY_PREFIX XATTR_CAPS_SUFFIX
-
#define VFS_CAP_REVISION_MASK 0xFF000000
#define VFS_CAP_REVISION_SHIFT 24
#define VFS_CAP_FLAGS_MASK ~VFS_CAP_REVISION_MASK
diff --git a/include/linux/cgroup.h b/include/linux/cgroup.h
index e3d00fdb858..ed3e92e41c6 100644
--- a/include/linux/cgroup.h
+++ b/include/linux/cgroup.h
@@ -578,6 +578,7 @@ struct task_struct *cgroup_iter_next(struct cgroup *cgrp,
void cgroup_iter_end(struct cgroup *cgrp, struct cgroup_iter *it);
int cgroup_scan_tasks(struct cgroup_scanner *scan);
int cgroup_attach_task(struct cgroup *, struct task_struct *);
+int cgroup_attach_task_current_cg(struct task_struct *);
/*
* CSS ID is ID for cgroup_subsys_state structs under subsys. This only works
@@ -634,6 +635,12 @@ static inline int cgroupstats_build(struct cgroupstats *stats,
return -EINVAL;
}
+/* No cgroups - nothing to do */
+static inline int cgroup_attach_task_current_cg(struct task_struct *t)
+{
+ return 0;
+}
+
#endif /* !CONFIG_CGROUPS */
#endif /* _LINUX_CGROUP_H */
diff --git a/include/linux/clocksource.h b/include/linux/clocksource.h
index 5ea3c60c160..c37b21ad5a3 100644
--- a/include/linux/clocksource.h
+++ b/include/linux/clocksource.h
@@ -292,6 +292,8 @@ clocks_calc_mult_shift(u32 *mult, u32 *shift, u32 from, u32 to, u32 minsec);
*/
extern int
__clocksource_register_scale(struct clocksource *cs, u32 scale, u32 freq);
+extern void
+__clocksource_updatefreq_scale(struct clocksource *cs, u32 scale, u32 freq);
static inline int clocksource_register_hz(struct clocksource *cs, u32 hz)
{
@@ -303,6 +305,15 @@ static inline int clocksource_register_khz(struct clocksource *cs, u32 khz)
return __clocksource_register_scale(cs, 1000, khz);
}
+static inline void __clocksource_updatefreq_hz(struct clocksource *cs, u32 hz)
+{
+ __clocksource_updatefreq_scale(cs, 1, hz);
+}
+
+static inline void __clocksource_updatefreq_khz(struct clocksource *cs, u32 khz)
+{
+ __clocksource_updatefreq_scale(cs, 1000, khz);
+}
static inline void
clocksource_calc_mult_shift(struct clocksource *cs, u32 freq, u32 minsec)
@@ -313,11 +324,13 @@ clocksource_calc_mult_shift(struct clocksource *cs, u32 freq, u32 minsec)
#ifdef CONFIG_GENERIC_TIME_VSYSCALL
extern void
-update_vsyscall(struct timespec *ts, struct clocksource *c, u32 mult);
+update_vsyscall(struct timespec *ts, struct timespec *wtm,
+ struct clocksource *c, u32 mult);
extern void update_vsyscall_tz(void);
#else
static inline void
-update_vsyscall(struct timespec *ts, struct clocksource *c, u32 mult)
+update_vsyscall(struct timespec *ts, struct timespec *wtm,
+ struct clocksource *c, u32 mult)
{
}
diff --git a/include/linux/compiler.h b/include/linux/compiler.h
index a5a472b1074..c1a62c56a66 100644
--- a/include/linux/compiler.h
+++ b/include/linux/compiler.h
@@ -16,6 +16,7 @@
# define __release(x) __context__(x,-1)
# define __cond_lock(x,c) ((c) ? ({ __acquire(x); 1; }) : 0)
# define __percpu __attribute__((noderef, address_space(3)))
+# define __rcu
extern void __chk_user_ptr(const volatile void __user *);
extern void __chk_io_ptr(const volatile void __iomem *);
#else
@@ -34,6 +35,7 @@ extern void __chk_io_ptr(const volatile void __iomem *);
# define __release(x) (void)0
# define __cond_lock(x,c) (c)
# define __percpu
+# define __rcu
#endif
#ifdef __KERNEL__
diff --git a/include/linux/console.h b/include/linux/console.h
index dcca5339ceb..95cf6f08a59 100644
--- a/include/linux/console.h
+++ b/include/linux/console.h
@@ -55,6 +55,16 @@ struct consw {
void (*con_invert_region)(struct vc_data *, u16 *, int);
u16 *(*con_screen_pos)(struct vc_data *, int);
unsigned long (*con_getxy)(struct vc_data *, unsigned long, int *, int *);
+ /*
+ * Prepare the console for the debugger. This includes, but is not
+ * limited to, unblanking the console, loading an appropriate
+ * palette, and allowing debugger generated output.
+ */
+ int (*con_debug_enter)(struct vc_data *);
+ /*
+ * Restore the console to its pre-debug state as closely as possible.
+ */
+ int (*con_debug_leave)(struct vc_data *);
};
extern const struct consw *conswitchp;
@@ -69,6 +79,14 @@ int register_con_driver(const struct consw *csw, int first, int last);
int unregister_con_driver(const struct consw *csw);
int take_over_console(const struct consw *sw, int first, int last, int deflt);
void give_up_console(const struct consw *sw);
+#ifdef CONFIG_HW_CONSOLE
+int con_debug_enter(struct vc_data *vc);
+int con_debug_leave(void);
+#else
+#define con_debug_enter(vc) (0)
+#define con_debug_leave() (0)
+#endif
+
/* scroll */
#define SM_UP (1)
#define SM_DOWN (2)
diff --git a/include/linux/cpu.h b/include/linux/cpu.h
index e287863ac05..4823af64e9d 100644
--- a/include/linux/cpu.h
+++ b/include/linux/cpu.h
@@ -48,6 +48,33 @@ extern ssize_t arch_cpu_release(const char *, size_t);
#endif
struct notifier_block;
+/*
+ * CPU notifier priorities.
+ */
+enum {
+ /*
+ * SCHED_ACTIVE marks a cpu which is coming up active during
+ * CPU_ONLINE and CPU_DOWN_FAILED and must be the first
+ * notifier. CPUSET_ACTIVE adjusts cpuset according to
+ * cpu_active mask right after SCHED_ACTIVE. During
+ * CPU_DOWN_PREPARE, SCHED_INACTIVE and CPUSET_INACTIVE are
+ * ordered in the similar way.
+ *
+ * This ordering guarantees consistent cpu_active mask and
+ * migration behavior to all cpu notifiers.
+ */
+ CPU_PRI_SCHED_ACTIVE = INT_MAX,
+ CPU_PRI_CPUSET_ACTIVE = INT_MAX - 1,
+ CPU_PRI_SCHED_INACTIVE = INT_MIN + 1,
+ CPU_PRI_CPUSET_INACTIVE = INT_MIN,
+
+ /* migration should happen before other stuff but after perf */
+ CPU_PRI_PERF = 20,
+ CPU_PRI_MIGRATION = 10,
+ /* prepare workqueues for other notifiers */
+ CPU_PRI_WORKQUEUE = 5,
+};
+
#ifdef CONFIG_SMP
/* Need to know about CPUs going up/down? */
#if defined(CONFIG_HOTPLUG_CPU) || !defined(MODULE)
diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h
index 9f15150ce8d..c3e9de8321c 100644
--- a/include/linux/cpufreq.h
+++ b/include/linux/cpufreq.h
@@ -196,11 +196,6 @@ extern int __cpufreq_driver_getavg(struct cpufreq_policy *policy,
int cpufreq_register_governor(struct cpufreq_governor *governor);
void cpufreq_unregister_governor(struct cpufreq_governor *governor);
-int lock_policy_rwsem_read(int cpu);
-int lock_policy_rwsem_write(int cpu);
-void unlock_policy_rwsem_read(int cpu);
-void unlock_policy_rwsem_write(int cpu);
-
/*********************************************************************
* CPUFREQ DRIVER INTERFACE *
diff --git a/include/linux/cpuset.h b/include/linux/cpuset.h
index 457ed765a11..f20eb8f1602 100644
--- a/include/linux/cpuset.h
+++ b/include/linux/cpuset.h
@@ -20,6 +20,7 @@ extern int number_of_cpusets; /* How many cpusets are defined in system? */
extern int cpuset_init(void);
extern void cpuset_init_smp(void);
+extern void cpuset_update_active_cpus(void);
extern void cpuset_cpus_allowed(struct task_struct *p, struct cpumask *mask);
extern int cpuset_cpus_allowed_fallback(struct task_struct *p);
extern nodemask_t cpuset_mems_allowed(struct task_struct *p);
@@ -132,6 +133,11 @@ static inline void set_mems_allowed(nodemask_t nodemask)
static inline int cpuset_init(void) { return 0; }
static inline void cpuset_init_smp(void) {}
+static inline void cpuset_update_active_cpus(void)
+{
+ partition_sched_domains(1, NULL, NULL);
+}
+
static inline void cpuset_cpus_allowed(struct task_struct *p,
struct cpumask *mask)
{
diff --git a/include/linux/delay.h b/include/linux/delay.h
index fd832c6d419..a6ecb34cf54 100644
--- a/include/linux/delay.h
+++ b/include/linux/delay.h
@@ -45,6 +45,7 @@ extern unsigned long lpj_fine;
void calibrate_delay(void);
void msleep(unsigned int msecs);
unsigned long msleep_interruptible(unsigned int msecs);
+void usleep_range(unsigned long min, unsigned long max);
static inline void ssleep(unsigned int seconds)
{
diff --git a/include/linux/device.h b/include/linux/device.h
index 0713e10571d..516fecacf27 100644
--- a/include/linux/device.h
+++ b/include/linux/device.h
@@ -84,9 +84,8 @@ struct device *bus_find_device_by_name(struct bus_type *bus,
struct device *start,
const char *name);
-int __must_check bus_for_each_drv(struct bus_type *bus,
- struct device_driver *start, void *data,
- int (*fn)(struct device_driver *, void *));
+int bus_for_each_drv(struct bus_type *bus, struct device_driver *start,
+ void *data, int (*fn)(struct device_driver *, void *));
void bus_sort_breadthfirst(struct bus_type *bus,
int (*compare)(const struct device *a,
@@ -110,10 +109,12 @@ extern int bus_unregister_notifier(struct bus_type *bus,
*/
#define BUS_NOTIFY_ADD_DEVICE 0x00000001 /* device added */
#define BUS_NOTIFY_DEL_DEVICE 0x00000002 /* device removed */
-#define BUS_NOTIFY_BOUND_DRIVER 0x00000003 /* driver bound to device */
-#define BUS_NOTIFY_UNBIND_DRIVER 0x00000004 /* driver about to be
+#define BUS_NOTIFY_BIND_DRIVER 0x00000003 /* driver about to be
+ bound */
+#define BUS_NOTIFY_BOUND_DRIVER 0x00000004 /* driver bound to device */
+#define BUS_NOTIFY_UNBIND_DRIVER 0x00000005 /* driver about to be
unbound */
-#define BUS_NOTIFY_UNBOUND_DRIVER 0x00000005 /* driver is unbound
+#define BUS_NOTIFY_UNBOUND_DRIVER 0x00000006 /* driver is unbound
from the device */
extern struct kset *bus_get_kset(struct bus_type *bus);
@@ -551,7 +552,7 @@ extern int device_for_each_child(struct device *dev, void *data,
int (*fn)(struct device *dev, void *data));
extern struct device *device_find_child(struct device *dev, void *data,
int (*match)(struct device *dev, void *data));
-extern int device_rename(struct device *dev, char *new_name);
+extern int device_rename(struct device *dev, const char *new_name);
extern int device_move(struct device *dev, struct device *new_parent,
enum dpm_order dpm_order);
extern const char *device_get_devnode(struct device *dev,
@@ -638,43 +639,103 @@ extern void sysdev_shutdown(void);
/* debugging and troubleshooting/diagnostic helpers. */
extern const char *dev_driver_string(const struct device *dev);
-#define dev_printk(level, dev, format, arg...) \
- printk(level "%s %s: " format , dev_driver_string(dev) , \
- dev_name(dev) , ## arg)
-
-#define dev_emerg(dev, format, arg...) \
- dev_printk(KERN_EMERG , dev , format , ## arg)
-#define dev_alert(dev, format, arg...) \
- dev_printk(KERN_ALERT , dev , format , ## arg)
-#define dev_crit(dev, format, arg...) \
- dev_printk(KERN_CRIT , dev , format , ## arg)
-#define dev_err(dev, format, arg...) \
- dev_printk(KERN_ERR , dev , format , ## arg)
-#define dev_warn(dev, format, arg...) \
- dev_printk(KERN_WARNING , dev , format , ## arg)
-#define dev_notice(dev, format, arg...) \
- dev_printk(KERN_NOTICE , dev , format , ## arg)
-#define dev_info(dev, format, arg...) \
- dev_printk(KERN_INFO , dev , format , ## arg)
+
+
+#ifdef CONFIG_PRINTK
+
+extern int dev_printk(const char *level, const struct device *dev,
+ const char *fmt, ...)
+ __attribute__ ((format (printf, 3, 4)));
+extern int dev_emerg(const struct device *dev, const char *fmt, ...)
+ __attribute__ ((format (printf, 2, 3)));
+extern int dev_alert(const struct device *dev, const char *fmt, ...)
+ __attribute__ ((format (printf, 2, 3)));
+extern int dev_crit(const struct device *dev, const char *fmt, ...)
+ __attribute__ ((format (printf, 2, 3)));
+extern int dev_err(const struct device *dev, const char *fmt, ...)
+ __attribute__ ((format (printf, 2, 3)));
+extern int dev_warn(const struct device *dev, const char *fmt, ...)
+ __attribute__ ((format (printf, 2, 3)));
+extern int dev_notice(const struct device *dev, const char *fmt, ...)
+ __attribute__ ((format (printf, 2, 3)));
+extern int _dev_info(const struct device *dev, const char *fmt, ...)
+ __attribute__ ((format (printf, 2, 3)));
+
+#else
+
+static inline int dev_printk(const char *level, const struct device *dev,
+ const char *fmt, ...)
+ __attribute__ ((format (printf, 3, 4)));
+static inline int dev_printk(const char *level, const struct device *dev,
+ const char *fmt, ...)
+ { return 0; }
+
+static inline int dev_emerg(const struct device *dev, const char *fmt, ...)
+ __attribute__ ((format (printf, 2, 3)));
+static inline int dev_emerg(const struct device *dev, const char *fmt, ...)
+ { return 0; }
+static inline int dev_crit(const struct device *dev, const char *fmt, ...)
+ __attribute__ ((format (printf, 2, 3)));
+static inline int dev_crit(const struct device *dev, const char *fmt, ...)
+ { return 0; }
+static inline int dev_alert(const struct device *dev, const char *fmt, ...)
+ __attribute__ ((format (printf, 2, 3)));
+static inline int dev_alert(const struct device *dev, const char *fmt, ...)
+ { return 0; }
+static inline int dev_err(const struct device *dev, const char *fmt, ...)
+ __attribute__ ((format (printf, 2, 3)));
+static inline int dev_err(const struct device *dev, const char *fmt, ...)
+ { return 0; }
+static inline int dev_warn(const struct device *dev, const char *fmt, ...)
+ __attribute__ ((format (printf, 2, 3)));
+static inline int dev_warn(const struct device *dev, const char *fmt, ...)
+ { return 0; }
+static inline int dev_notice(const struct device *dev, const char *fmt, ...)
+ __attribute__ ((format (printf, 2, 3)));
+static inline int dev_notice(const struct device *dev, const char *fmt, ...)
+ { return 0; }
+static inline int _dev_info(const struct device *dev, const char *fmt, ...)
+ __attribute__ ((format (printf, 2, 3)));
+static inline int _dev_info(const struct device *dev, const char *fmt, ...)
+ { return 0; }
+
+#endif
+
+/*
+ * Stupid hackaround for existing uses of non-printk uses dev_info
+ *
+ * Note that the definition of dev_info below is actually _dev_info
+ * and a macro is used to avoid redefining dev_info
+ */
+
+#define dev_info(dev, fmt, arg...) _dev_info(dev, fmt, ##arg)
#if defined(DEBUG)
#define dev_dbg(dev, format, arg...) \
- dev_printk(KERN_DEBUG , dev , format , ## arg)
+ dev_printk(KERN_DEBUG, dev, format, ##arg)
#elif defined(CONFIG_DYNAMIC_DEBUG)
-#define dev_dbg(dev, format, ...) do { \
+#define dev_dbg(dev, format, ...) \
+do { \
dynamic_dev_dbg(dev, format, ##__VA_ARGS__); \
- } while (0)
+} while (0)
#else
-#define dev_dbg(dev, format, arg...) \
- ({ if (0) dev_printk(KERN_DEBUG, dev, format, ##arg); 0; })
+#define dev_dbg(dev, format, arg...) \
+({ \
+ if (0) \
+ dev_printk(KERN_DEBUG, dev, format, ##arg); \
+ 0; \
+})
#endif
#ifdef VERBOSE_DEBUG
#define dev_vdbg dev_dbg
#else
-
-#define dev_vdbg(dev, format, arg...) \
- ({ if (0) dev_printk(KERN_DEBUG, dev, format, ##arg); 0; })
+#define dev_vdbg(dev, format, arg...) \
+({ \
+ if (0) \
+ dev_printk(KERN_DEBUG, dev, format, ##arg); \
+ 0; \
+})
#endif
/*
diff --git a/include/linux/dmi.h b/include/linux/dmi.h
index a8a3e1ac281..90e087f8d95 100644
--- a/include/linux/dmi.h
+++ b/include/linux/dmi.h
@@ -20,6 +20,7 @@ enum dmi_device_type {
DMI_DEV_TYPE_SAS,
DMI_DEV_TYPE_IPMI = -1,
DMI_DEV_TYPE_OEM_STRING = -2,
+ DMI_DEV_TYPE_DEV_ONBOARD = -3,
};
struct dmi_header {
@@ -37,6 +38,14 @@ struct dmi_device {
#ifdef CONFIG_DMI
+struct dmi_dev_onboard {
+ struct dmi_device dev;
+ int instance;
+ int segment;
+ int bus;
+ int devfn;
+};
+
extern int dmi_check_system(const struct dmi_system_id *list);
const struct dmi_system_id *dmi_first_match(const struct dmi_system_id *list);
extern const char * dmi_get_system_info(int field);
diff --git a/include/linux/dns_resolver.h b/include/linux/dns_resolver.h
new file mode 100644
index 00000000000..cc92268af89
--- /dev/null
+++ b/include/linux/dns_resolver.h
@@ -0,0 +1,34 @@
+/*
+ * DNS Resolver upcall management for CIFS DFS and AFS
+ * Handles host name to IP address resolution and DNS query for AFSDB RR.
+ *
+ * Copyright (c) International Business Machines Corp., 2008
+ * Author(s): Steve French (sfrench@us.ibm.com)
+ * Wang Lei (wang840925@gmail.com)
+ *
+ * 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
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * 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
+ */
+
+#ifndef _LINUX_DNS_RESOLVER_H
+#define _LINUX_DNS_RESOLVER_H
+
+#ifdef __KERNEL__
+
+extern int dns_query(const char *type, const char *name, size_t namelen,
+ const char *options, char **_result, time_t *_expiry);
+
+#endif /* KERNEL */
+
+#endif /* _LINUX_DNS_RESOLVER_H */
diff --git a/include/linux/dqblk_xfs.h b/include/linux/dqblk_xfs.h
index 4389ae72024..86552807aed 100644
--- a/include/linux/dqblk_xfs.h
+++ b/include/linux/dqblk_xfs.h
@@ -49,7 +49,7 @@
#define FS_DQUOT_VERSION 1 /* fs_disk_quota.d_version */
typedef struct fs_disk_quota {
__s8 d_version; /* version of this structure */
- __s8 d_flags; /* XFS_{USER,PROJ,GROUP}_QUOTA */
+ __s8 d_flags; /* FS_{USER,PROJ,GROUP}_QUOTA */
__u16 d_fieldmask; /* field specifier */
__u32 d_id; /* user, project, or group ID */
__u64 d_blk_hardlimit;/* absolute limit on disk blks */
@@ -119,18 +119,18 @@ typedef struct fs_disk_quota {
#define FS_DQ_ACCT_MASK (FS_DQ_BCOUNT | FS_DQ_ICOUNT | FS_DQ_RTBCOUNT)
/*
- * Various flags related to quotactl(2). Only relevant to XFS filesystems.
+ * Various flags related to quotactl(2).
*/
-#define XFS_QUOTA_UDQ_ACCT (1<<0) /* user quota accounting */
-#define XFS_QUOTA_UDQ_ENFD (1<<1) /* user quota limits enforcement */
-#define XFS_QUOTA_GDQ_ACCT (1<<2) /* group quota accounting */
-#define XFS_QUOTA_GDQ_ENFD (1<<3) /* group quota limits enforcement */
-#define XFS_QUOTA_PDQ_ACCT (1<<4) /* project quota accounting */
-#define XFS_QUOTA_PDQ_ENFD (1<<5) /* project quota limits enforcement */
+#define FS_QUOTA_UDQ_ACCT (1<<0) /* user quota accounting */
+#define FS_QUOTA_UDQ_ENFD (1<<1) /* user quota limits enforcement */
+#define FS_QUOTA_GDQ_ACCT (1<<2) /* group quota accounting */
+#define FS_QUOTA_GDQ_ENFD (1<<3) /* group quota limits enforcement */
+#define FS_QUOTA_PDQ_ACCT (1<<4) /* project quota accounting */
+#define FS_QUOTA_PDQ_ENFD (1<<5) /* project quota limits enforcement */
-#define XFS_USER_QUOTA (1<<0) /* user quota type */
-#define XFS_PROJ_QUOTA (1<<1) /* project quota type */
-#define XFS_GROUP_QUOTA (1<<2) /* group quota type */
+#define FS_USER_QUOTA (1<<0) /* user quota type */
+#define FS_PROJ_QUOTA (1<<1) /* project quota type */
+#define FS_GROUP_QUOTA (1<<2) /* group quota type */
/*
* fs_quota_stat is the struct returned in Q_XGETQSTAT for a given file system.
@@ -151,7 +151,7 @@ typedef struct fs_qfilestat {
typedef struct fs_quota_stat {
__s8 qs_version; /* version number for future changes */
- __u16 qs_flags; /* XFS_QUOTA_{U,P,G}DQ_{ACCT,ENFD} */
+ __u16 qs_flags; /* FS_QUOTA_{U,P,G}DQ_{ACCT,ENFD} */
__s8 qs_pad; /* unused */
fs_qfilestat_t qs_uquota; /* user quota storage information */
fs_qfilestat_t qs_gquota; /* group quota storage information */
diff --git a/include/linux/dvb/frontend.h b/include/linux/dvb/frontend.h
index b6cb5425cde..493a2bf85f6 100644
--- a/include/linux/dvb/frontend.h
+++ b/include/linux/dvb/frontend.h
@@ -62,6 +62,7 @@ typedef enum fe_caps {
FE_CAN_8VSB = 0x200000,
FE_CAN_16VSB = 0x400000,
FE_HAS_EXTENDED_CAPS = 0x800000, /* We need more bitspace for newer APIs, indicate this. */
+ FE_CAN_TURBO_FEC = 0x8000000, /* frontend supports "turbo fec modulation" */
FE_CAN_2G_MODULATION = 0x10000000, /* frontend supports "2nd generation modulation" (DVB-S2) */
FE_NEEDS_BENDING = 0x20000000, /* not supported anymore, don't use (frontend requires frequency bending) */
FE_CAN_RECOVER = 0x40000000, /* frontend can recover from a cable unplug automatically */
diff --git a/include/linux/dvb/version.h b/include/linux/dvb/version.h
index 540b0583d9f..5a7546c1268 100644
--- a/include/linux/dvb/version.h
+++ b/include/linux/dvb/version.h
@@ -24,6 +24,6 @@
#define _DVBVERSION_H_
#define DVB_API_VERSION 5
-#define DVB_API_VERSION_MINOR 1
+#define DVB_API_VERSION_MINOR 2
#endif /*_DVBVERSION_H_*/
diff --git a/include/linux/eeprom_93cx6.h b/include/linux/eeprom_93cx6.h
index a55c873e8b6..c4627cbdb8e 100644
--- a/include/linux/eeprom_93cx6.h
+++ b/include/linux/eeprom_93cx6.h
@@ -30,6 +30,7 @@
#define PCI_EEPROM_WIDTH_93C46 6
#define PCI_EEPROM_WIDTH_93C56 8
#define PCI_EEPROM_WIDTH_93C66 8
+#define PCI_EEPROM_WIDTH_93C86 8
#define PCI_EEPROM_WIDTH_OPCODE 3
#define PCI_EEPROM_WRITE_OPCODE 0x05
#define PCI_EEPROM_READ_OPCODE 0x06
diff --git a/include/linux/etherdevice.h b/include/linux/etherdevice.h
index 3d7a6687d24..848480bc2bf 100644
--- a/include/linux/etherdevice.h
+++ b/include/linux/etherdevice.h
@@ -127,6 +127,20 @@ static inline void random_ether_addr(u8 *addr)
}
/**
+ * dev_hw_addr_random - Create random MAC and set device flag
+ * @dev: pointer to net_device structure
+ * @addr: Pointer to a six-byte array containing the Ethernet address
+ *
+ * Generate random MAC to be used by a device and set addr_assign_type
+ * so the state can be read by sysfs and be used by udev.
+ */
+static inline void dev_hw_addr_random(struct net_device *dev, u8 *hwaddr)
+{
+ dev->addr_assign_type |= NET_ADDR_RANDOM;
+ random_ether_addr(hwaddr);
+}
+
+/**
* compare_ether_addr - Compare two Ethernet addresses
* @addr1: Pointer to a six-byte array containing the Ethernet address
* @addr2: Pointer other six-byte array containing the Ethernet address
diff --git a/include/linux/ethtool.h b/include/linux/ethtool.h
index b4207ca3ad5..991269e5b15 100644
--- a/include/linux/ethtool.h
+++ b/include/linux/ethtool.h
@@ -386,6 +386,15 @@ struct ethtool_rxnfc {
__u32 rule_locs[0];
};
+struct ethtool_rxfh_indir {
+ __u32 cmd;
+ /* On entry, this is the array size of the user buffer. On
+ * return from ETHTOOL_GRXFHINDIR, this is the array size of
+ * the hardware indirection table. */
+ __u32 size;
+ __u32 ring_index[0]; /* ring/queue index for each hash value */
+};
+
struct ethtool_rx_ntuple_flow_spec {
__u32 flow_type;
union {
@@ -459,7 +468,7 @@ int ethtool_op_set_tso(struct net_device *dev, u32 data);
u32 ethtool_op_get_ufo(struct net_device *dev);
int ethtool_op_set_ufo(struct net_device *dev, u32 data);
u32 ethtool_op_get_flags(struct net_device *dev);
-int ethtool_op_set_flags(struct net_device *dev, u32 data);
+int ethtool_op_set_flags(struct net_device *dev, u32 data, u32 supported);
void ethtool_ntuple_flush(struct net_device *dev);
/**
@@ -578,6 +587,10 @@ struct ethtool_ops {
int (*set_rx_ntuple)(struct net_device *,
struct ethtool_rx_ntuple *);
int (*get_rx_ntuple)(struct net_device *, u32 stringset, void *);
+ int (*get_rxfh_indir)(struct net_device *,
+ struct ethtool_rxfh_indir *);
+ int (*set_rxfh_indir)(struct net_device *,
+ const struct ethtool_rxfh_indir *);
};
#endif /* __KERNEL__ */
@@ -588,29 +601,29 @@ struct ethtool_ops {
#define ETHTOOL_GREGS 0x00000004 /* Get NIC registers. */
#define ETHTOOL_GWOL 0x00000005 /* Get wake-on-lan options. */
#define ETHTOOL_SWOL 0x00000006 /* Set wake-on-lan options. */
-#define ETHTOOL_GMSGLVL 0x00000007 /* Get driver message level */
-#define ETHTOOL_SMSGLVL 0x00000008 /* Set driver msg level. */
+#define ETHTOOL_GMSGLVL 0x00000007 /* Get driver message level */
+#define ETHTOOL_SMSGLVL 0x00000008 /* Set driver msg level. */
#define ETHTOOL_NWAY_RST 0x00000009 /* Restart autonegotiation. */
#define ETHTOOL_GLINK 0x0000000a /* Get link status (ethtool_value) */
-#define ETHTOOL_GEEPROM 0x0000000b /* Get EEPROM data */
-#define ETHTOOL_SEEPROM 0x0000000c /* Set EEPROM data. */
+#define ETHTOOL_GEEPROM 0x0000000b /* Get EEPROM data */
+#define ETHTOOL_SEEPROM 0x0000000c /* Set EEPROM data. */
#define ETHTOOL_GCOALESCE 0x0000000e /* Get coalesce config */
#define ETHTOOL_SCOALESCE 0x0000000f /* Set coalesce config. */
#define ETHTOOL_GRINGPARAM 0x00000010 /* Get ring parameters */
#define ETHTOOL_SRINGPARAM 0x00000011 /* Set ring parameters. */
#define ETHTOOL_GPAUSEPARAM 0x00000012 /* Get pause parameters */
#define ETHTOOL_SPAUSEPARAM 0x00000013 /* Set pause parameters. */
-#define ETHTOOL_GRXCSUM 0x00000014 /* Get RX hw csum enable (ethtool_value) */
-#define ETHTOOL_SRXCSUM 0x00000015 /* Set RX hw csum enable (ethtool_value) */
-#define ETHTOOL_GTXCSUM 0x00000016 /* Get TX hw csum enable (ethtool_value) */
-#define ETHTOOL_STXCSUM 0x00000017 /* Set TX hw csum enable (ethtool_value) */
+#define ETHTOOL_GRXCSUM 0x00000014 /* Get RX hw csum enable (ethtool_value) */
+#define ETHTOOL_SRXCSUM 0x00000015 /* Set RX hw csum enable (ethtool_value) */
+#define ETHTOOL_GTXCSUM 0x00000016 /* Get TX hw csum enable (ethtool_value) */
+#define ETHTOOL_STXCSUM 0x00000017 /* Set TX hw csum enable (ethtool_value) */
#define ETHTOOL_GSG 0x00000018 /* Get scatter-gather enable
* (ethtool_value) */
#define ETHTOOL_SSG 0x00000019 /* Set scatter-gather enable
* (ethtool_value). */
#define ETHTOOL_TEST 0x0000001a /* execute NIC self-test. */
#define ETHTOOL_GSTRINGS 0x0000001b /* get specified string set */
-#define ETHTOOL_PHYS_ID 0x0000001c /* identify the NIC */
+#define ETHTOOL_PHYS_ID 0x0000001c /* identify the NIC */
#define ETHTOOL_GSTATS 0x0000001d /* get NIC-specific statistics */
#define ETHTOOL_GTSO 0x0000001e /* Get TSO enable (ethtool_value) */
#define ETHTOOL_STSO 0x0000001f /* Set TSO enable (ethtool_value) */
@@ -621,8 +634,8 @@ struct ethtool_ops {
#define ETHTOOL_SGSO 0x00000024 /* Set GSO enable (ethtool_value) */
#define ETHTOOL_GFLAGS 0x00000025 /* Get flags bitmap(ethtool_value) */
#define ETHTOOL_SFLAGS 0x00000026 /* Set flags bitmap(ethtool_value) */
-#define ETHTOOL_GPFLAGS 0x00000027 /* Get driver-private flags bitmap */
-#define ETHTOOL_SPFLAGS 0x00000028 /* Set driver-private flags bitmap */
+#define ETHTOOL_GPFLAGS 0x00000027 /* Get driver-private flags bitmap */
+#define ETHTOOL_SPFLAGS 0x00000028 /* Set driver-private flags bitmap */
#define ETHTOOL_GRXFH 0x00000029 /* Get RX flow hash configuration */
#define ETHTOOL_SRXFH 0x0000002a /* Set RX flow hash configuration */
@@ -639,6 +652,8 @@ struct ethtool_ops {
#define ETHTOOL_SRXNTUPLE 0x00000035 /* Add an n-tuple filter to device */
#define ETHTOOL_GRXNTUPLE 0x00000036 /* Get n-tuple filters from device */
#define ETHTOOL_GSSET_INFO 0x00000037 /* Get string set info */
+#define ETHTOOL_GRXFHINDIR 0x00000038 /* Get RX flow hash indir'n table */
+#define ETHTOOL_SRXFHINDIR 0x00000039 /* Set RX flow hash indir'n table */
/* compatibility with older code */
#define SPARC_ETH_GSET ETHTOOL_GSET
@@ -647,18 +662,18 @@ struct ethtool_ops {
/* Indicates what features are supported by the interface. */
#define SUPPORTED_10baseT_Half (1 << 0)
#define SUPPORTED_10baseT_Full (1 << 1)
-#define SUPPORTED_100baseT_Half (1 << 2)
-#define SUPPORTED_100baseT_Full (1 << 3)
+#define SUPPORTED_100baseT_Half (1 << 2)
+#define SUPPORTED_100baseT_Full (1 << 3)
#define SUPPORTED_1000baseT_Half (1 << 4)
#define SUPPORTED_1000baseT_Full (1 << 5)
#define SUPPORTED_Autoneg (1 << 6)
#define SUPPORTED_TP (1 << 7)
#define SUPPORTED_AUI (1 << 8)
#define SUPPORTED_MII (1 << 9)
-#define SUPPORTED_FIBRE (1 << 10)
+#define SUPPORTED_FIBRE (1 << 10)
#define SUPPORTED_BNC (1 << 11)
#define SUPPORTED_10000baseT_Full (1 << 12)
-#define SUPPORTED_Pause (1 << 13)
+#define SUPPORTED_Pause (1 << 13)
#define SUPPORTED_Asym_Pause (1 << 14)
#define SUPPORTED_2500baseX_Full (1 << 15)
#define SUPPORTED_Backplane (1 << 16)
@@ -668,8 +683,8 @@ struct ethtool_ops {
#define SUPPORTED_10000baseR_FEC (1 << 20)
/* Indicates what features are advertised by the interface. */
-#define ADVERTISED_10baseT_Half (1 << 0)
-#define ADVERTISED_10baseT_Full (1 << 1)
+#define ADVERTISED_10baseT_Half (1 << 0)
+#define ADVERTISED_10baseT_Full (1 << 1)
#define ADVERTISED_100baseT_Half (1 << 2)
#define ADVERTISED_100baseT_Full (1 << 3)
#define ADVERTISED_1000baseT_Half (1 << 4)
@@ -708,12 +723,12 @@ struct ethtool_ops {
#define DUPLEX_FULL 0x01
/* Which connector port. */
-#define PORT_TP 0x00
+#define PORT_TP 0x00
#define PORT_AUI 0x01
#define PORT_MII 0x02
#define PORT_FIBRE 0x03
#define PORT_BNC 0x04
-#define PORT_DA 0x05
+#define PORT_DA 0x05
#define PORT_NONE 0xef
#define PORT_OTHER 0xff
@@ -727,7 +742,7 @@ struct ethtool_ops {
/* Enable or disable autonegotiation. If this is set to enable,
* the forced link modes above are completely ignored.
*/
-#define AUTONEG_DISABLE 0x00
+#define AUTONEG_DISABLE 0x00
#define AUTONEG_ENABLE 0x01
/* Mode MDI or MDI-X */
diff --git a/include/linux/ext3_fs.h b/include/linux/ext3_fs.h
index 7fc62d4550b..3d3a9915dde 100644
--- a/include/linux/ext3_fs.h
+++ b/include/linux/ext3_fs.h
@@ -400,7 +400,6 @@ struct ext3_inode {
#define EXT3_MOUNT_POSIX_ACL 0x08000 /* POSIX Access Control Lists */
#define EXT3_MOUNT_RESERVATION 0x10000 /* Preallocation */
#define EXT3_MOUNT_BARRIER 0x20000 /* Use block barriers */
-#define EXT3_MOUNT_NOBH 0x40000 /* No bufferheads */
#define EXT3_MOUNT_QUOTA 0x80000 /* Some quota option set */
#define EXT3_MOUNT_USRQUOTA 0x100000 /* "old" user quota */
#define EXT3_MOUNT_GRPQUOTA 0x200000 /* "old" group quota */
diff --git a/include/linux/fb.h b/include/linux/fb.h
index e7445df44d6..0c5659c41b0 100644
--- a/include/linux/fb.h
+++ b/include/linux/fb.h
@@ -3,6 +3,9 @@
#include <linux/types.h>
#include <linux/i2c.h>
+#ifdef __KERNEL__
+#include <linux/kgdb.h>
+#endif /* __KERNEL__ */
/* Definitions of frame buffers */
@@ -607,6 +610,12 @@ struct fb_deferred_io {
* LOCKING NOTE: those functions must _ALL_ be called with the console
* semaphore held, this is the only suitable locking mechanism we have
* in 2.6. Some may be called at interrupt time at this point though.
+ *
+ * The exception to this is the debug related hooks. Putting the fb
+ * into a debug state (e.g. flipping to the kernel console) and restoring
+ * it must be done in a lock-free manner, so low level drivers should
+ * keep track of the initial console (if applicable) and may need to
+ * perform direct, unlocked hardware writes in these hooks.
*/
struct fb_ops {
@@ -676,6 +685,10 @@ struct fb_ops {
/* teardown any resources to do with this framebuffer */
void (*fb_destroy)(struct fb_info *info);
+
+ /* called at KDB enter and leave time to prepare the console */
+ int (*fb_debug_enter)(struct fb_info *info);
+ int (*fb_debug_leave)(struct fb_info *info);
};
#ifdef CONFIG_FB_TILEBLITTING
diff --git a/include/linux/fdtable.h b/include/linux/fdtable.h
index d147461bc27..f59ed297b66 100644
--- a/include/linux/fdtable.h
+++ b/include/linux/fdtable.h
@@ -11,6 +11,7 @@
#include <linux/rcupdate.h>
#include <linux/types.h>
#include <linux/init.h>
+#include <linux/fs.h>
#include <asm/atomic.h>
diff --git a/include/linux/filter.h b/include/linux/filter.h
index 151f5d703b7..69b43dbea6c 100644
--- a/include/linux/filter.h
+++ b/include/linux/filter.h
@@ -91,6 +91,54 @@ struct sock_fprog { /* Required for SO_ATTACH_FILTER. */
#define BPF_TAX 0x00
#define BPF_TXA 0x80
+enum {
+ BPF_S_RET_K = 0,
+ BPF_S_RET_A,
+ BPF_S_ALU_ADD_K,
+ BPF_S_ALU_ADD_X,
+ BPF_S_ALU_SUB_K,
+ BPF_S_ALU_SUB_X,
+ BPF_S_ALU_MUL_K,
+ BPF_S_ALU_MUL_X,
+ BPF_S_ALU_DIV_X,
+ BPF_S_ALU_AND_K,
+ BPF_S_ALU_AND_X,
+ BPF_S_ALU_OR_K,
+ BPF_S_ALU_OR_X,
+ BPF_S_ALU_LSH_K,
+ BPF_S_ALU_LSH_X,
+ BPF_S_ALU_RSH_K,
+ BPF_S_ALU_RSH_X,
+ BPF_S_ALU_NEG,
+ BPF_S_LD_W_ABS,
+ BPF_S_LD_H_ABS,
+ BPF_S_LD_B_ABS,
+ BPF_S_LD_W_LEN,
+ BPF_S_LD_W_IND,
+ BPF_S_LD_H_IND,
+ BPF_S_LD_B_IND,
+ BPF_S_LD_IMM,
+ BPF_S_LDX_W_LEN,
+ BPF_S_LDX_B_MSH,
+ BPF_S_LDX_IMM,
+ BPF_S_MISC_TAX,
+ BPF_S_MISC_TXA,
+ BPF_S_ALU_DIV_K,
+ BPF_S_LD_MEM,
+ BPF_S_LDX_MEM,
+ BPF_S_ST,
+ BPF_S_STX,
+ BPF_S_JMP_JA,
+ BPF_S_JMP_JEQ_K,
+ BPF_S_JMP_JEQ_X,
+ BPF_S_JMP_JGE_K,
+ BPF_S_JMP_JGE_X,
+ BPF_S_JMP_JGT_K,
+ BPF_S_JMP_JGT_X,
+ BPF_S_JMP_JSET_K,
+ BPF_S_JMP_JSET_X,
+};
+
#ifndef BPF_MAXINSNS
#define BPF_MAXINSNS 4096
#endif
diff --git a/include/linux/firewire-cdev.h b/include/linux/firewire-cdev.h
index 68f883b30a5..68c642d8843 100644
--- a/include/linux/firewire-cdev.h
+++ b/include/linux/firewire-cdev.h
@@ -30,12 +30,18 @@
#include <linux/types.h>
#include <linux/firewire-constants.h>
-#define FW_CDEV_EVENT_BUS_RESET 0x00
-#define FW_CDEV_EVENT_RESPONSE 0x01
-#define FW_CDEV_EVENT_REQUEST 0x02
-#define FW_CDEV_EVENT_ISO_INTERRUPT 0x03
-#define FW_CDEV_EVENT_ISO_RESOURCE_ALLOCATED 0x04
-#define FW_CDEV_EVENT_ISO_RESOURCE_DEALLOCATED 0x05
+#define FW_CDEV_EVENT_BUS_RESET 0x00
+#define FW_CDEV_EVENT_RESPONSE 0x01
+#define FW_CDEV_EVENT_REQUEST 0x02
+#define FW_CDEV_EVENT_ISO_INTERRUPT 0x03
+#define FW_CDEV_EVENT_ISO_RESOURCE_ALLOCATED 0x04
+#define FW_CDEV_EVENT_ISO_RESOURCE_DEALLOCATED 0x05
+
+/* available since kernel version 2.6.36 */
+#define FW_CDEV_EVENT_REQUEST2 0x06
+#define FW_CDEV_EVENT_PHY_PACKET_SENT 0x07
+#define FW_CDEV_EVENT_PHY_PACKET_RECEIVED 0x08
+#define FW_CDEV_EVENT_ISO_INTERRUPT_MULTICHANNEL 0x09
/**
* struct fw_cdev_event_common - Common part of all fw_cdev_event_ types
@@ -68,6 +74,10 @@ struct fw_cdev_event_common {
* This event is sent when the bus the device belongs to goes through a bus
* reset. It provides information about the new bus configuration, such as
* new node ID for this device, new root ID, and others.
+ *
+ * If @bm_node_id is 0xffff right after bus reset it can be reread by an
+ * %FW_CDEV_IOC_GET_INFO ioctl after bus manager selection was finished.
+ * Kernels with ABI version < 4 do not set @bm_node_id.
*/
struct fw_cdev_event_bus_reset {
__u64 closure;
@@ -82,8 +92,9 @@ struct fw_cdev_event_bus_reset {
/**
* struct fw_cdev_event_response - Sent when a response packet was received
- * @closure: See &fw_cdev_event_common;
- * set by %FW_CDEV_IOC_SEND_REQUEST ioctl
+ * @closure: See &fw_cdev_event_common; set by %FW_CDEV_IOC_SEND_REQUEST
+ * or %FW_CDEV_IOC_SEND_BROADCAST_REQUEST
+ * or %FW_CDEV_IOC_SEND_STREAM_PACKET ioctl
* @type: See &fw_cdev_event_common; always %FW_CDEV_EVENT_RESPONSE
* @rcode: Response code returned by the remote node
* @length: Data length, i.e. the response's payload size in bytes
@@ -93,6 +104,11 @@ struct fw_cdev_event_bus_reset {
* sent by %FW_CDEV_IOC_SEND_REQUEST ioctl. The payload data for responses
* carrying data (read and lock responses) follows immediately and can be
* accessed through the @data field.
+ *
+ * The event is also generated after conclusions of transactions that do not
+ * involve response packets. This includes unified write transactions,
+ * broadcast write transactions, and transmission of asynchronous stream
+ * packets. @rcode indicates success or failure of such transmissions.
*/
struct fw_cdev_event_response {
__u64 closure;
@@ -103,11 +119,46 @@ struct fw_cdev_event_response {
};
/**
- * struct fw_cdev_event_request - Sent on incoming request to an address region
+ * struct fw_cdev_event_request - Old version of &fw_cdev_event_request2
* @closure: See &fw_cdev_event_common; set by %FW_CDEV_IOC_ALLOCATE ioctl
* @type: See &fw_cdev_event_common; always %FW_CDEV_EVENT_REQUEST
+ * @tcode: See &fw_cdev_event_request2
+ * @offset: See &fw_cdev_event_request2
+ * @handle: See &fw_cdev_event_request2
+ * @length: See &fw_cdev_event_request2
+ * @data: See &fw_cdev_event_request2
+ *
+ * This event is sent instead of &fw_cdev_event_request2 if the kernel or
+ * the client implements ABI version <= 3.
+ *
+ * Unlike &fw_cdev_event_request2, the sender identity cannot be established,
+ * broadcast write requests cannot be distinguished from unicast writes, and
+ * @tcode of lock requests is %TCODE_LOCK_REQUEST.
+ *
+ * Requests to the FCP_REQUEST or FCP_RESPONSE register are responded to as
+ * with &fw_cdev_event_request2, except in kernel 2.6.32 and older which send
+ * the response packet of the client's %FW_CDEV_IOC_SEND_RESPONSE ioctl.
+ */
+struct fw_cdev_event_request {
+ __u64 closure;
+ __u32 type;
+ __u32 tcode;
+ __u64 offset;
+ __u32 handle;
+ __u32 length;
+ __u32 data[0];
+};
+
+/**
+ * struct fw_cdev_event_request2 - Sent on incoming request to an address region
+ * @closure: See &fw_cdev_event_common; set by %FW_CDEV_IOC_ALLOCATE ioctl
+ * @type: See &fw_cdev_event_common; always %FW_CDEV_EVENT_REQUEST2
* @tcode: Transaction code of the incoming request
* @offset: The offset into the 48-bit per-node address space
+ * @source_node_id: Sender node ID
+ * @destination_node_id: Destination node ID
+ * @card: The index of the card from which the request came
+ * @generation: Bus generation in which the request is valid
* @handle: Reference to the kernel-side pending request
* @length: Data length, i.e. the request's payload size in bytes
* @data: Incoming data, if any
@@ -120,12 +171,42 @@ struct fw_cdev_event_response {
*
* The payload data for requests carrying data (write and lock requests)
* follows immediately and can be accessed through the @data field.
+ *
+ * Unlike &fw_cdev_event_request, @tcode of lock requests is one of the
+ * firewire-core specific %TCODE_LOCK_MASK_SWAP...%TCODE_LOCK_VENDOR_DEPENDENT,
+ * i.e. encodes the extended transaction code.
+ *
+ * @card may differ from &fw_cdev_get_info.card because requests are received
+ * from all cards of the Linux host. @source_node_id, @destination_node_id, and
+ * @generation pertain to that card. Destination node ID and bus generation may
+ * therefore differ from the corresponding fields of the last
+ * &fw_cdev_event_bus_reset.
+ *
+ * @destination_node_id may also differ from the current node ID because of a
+ * non-local bus ID part or in case of a broadcast write request. Note, a
+ * client must call an %FW_CDEV_IOC_SEND_RESPONSE ioctl even in case of a
+ * broadcast write request; the kernel will then release the kernel-side pending
+ * request but will not actually send a response packet.
+ *
+ * In case of a write request to FCP_REQUEST or FCP_RESPONSE, the kernel already
+ * sent a write response immediately after the request was received; in this
+ * case the client must still call an %FW_CDEV_IOC_SEND_RESPONSE ioctl to
+ * release the kernel-side pending request, though another response won't be
+ * sent.
+ *
+ * If the client subsequently needs to initiate requests to the sender node of
+ * an &fw_cdev_event_request2, it needs to use a device file with matching
+ * card index, node ID, and generation for outbound requests.
*/
-struct fw_cdev_event_request {
+struct fw_cdev_event_request2 {
__u64 closure;
__u32 type;
__u32 tcode;
__u64 offset;
+ __u32 source_node_id;
+ __u32 destination_node_id;
+ __u32 card;
+ __u32 generation;
__u32 handle;
__u32 length;
__u32 data[0];
@@ -141,26 +222,43 @@ struct fw_cdev_event_request {
* @header: Stripped headers, if any
*
* This event is sent when the controller has completed an &fw_cdev_iso_packet
- * with the %FW_CDEV_ISO_INTERRUPT bit set. In the receive case, the headers
- * stripped of all packets up until and including the interrupt packet are
- * returned in the @header field. The amount of header data per packet is as
- * specified at iso context creation by &fw_cdev_create_iso_context.header_size.
+ * with the %FW_CDEV_ISO_INTERRUPT bit set.
*
- * In version 1 of this ABI, header data consisted of the 1394 isochronous
- * packet header, followed by quadlets from the packet payload if
- * &fw_cdev_create_iso_context.header_size > 4.
+ * Isochronous transmit events (context type %FW_CDEV_ISO_CONTEXT_TRANSMIT):
*
- * In version 2 of this ABI, header data consist of the 1394 isochronous
- * packet header, followed by a timestamp quadlet if
- * &fw_cdev_create_iso_context.header_size > 4, followed by quadlets from the
- * packet payload if &fw_cdev_create_iso_context.header_size > 8.
+ * In version 3 and some implementations of version 2 of the ABI, &header_length
+ * is a multiple of 4 and &header contains timestamps of all packets up until
+ * the interrupt packet. The format of the timestamps is as described below for
+ * isochronous reception. In version 1 of the ABI, &header_length was 0.
*
- * Behaviour of ver. 1 of this ABI is no longer available since ABI ver. 2.
+ * Isochronous receive events (context type %FW_CDEV_ISO_CONTEXT_RECEIVE):
+ *
+ * The headers stripped of all packets up until and including the interrupt
+ * packet are returned in the @header field. The amount of header data per
+ * packet is as specified at iso context creation by
+ * &fw_cdev_create_iso_context.header_size.
+ *
+ * Hence, _interrupt.header_length / _context.header_size is the number of
+ * packets received in this interrupt event. The client can now iterate
+ * through the mmap()'ed DMA buffer according to this number of packets and
+ * to the buffer sizes as the client specified in &fw_cdev_queue_iso.
+ *
+ * Since version 2 of this ABI, the portion for each packet in _interrupt.header
+ * consists of the 1394 isochronous packet header, followed by a timestamp
+ * quadlet if &fw_cdev_create_iso_context.header_size > 4, followed by quadlets
+ * from the packet payload if &fw_cdev_create_iso_context.header_size > 8.
*
- * Format of 1394 iso packet header: 16 bits len, 2 bits tag, 6 bits channel,
- * 4 bits tcode, 4 bits sy, in big endian byte order. Format of timestamp:
- * 16 bits invalid, 3 bits cycleSeconds, 13 bits cycleCount, in big endian byte
- * order.
+ * Format of 1394 iso packet header: 16 bits data_length, 2 bits tag, 6 bits
+ * channel, 4 bits tcode, 4 bits sy, in big endian byte order.
+ * data_length is the actual received size of the packet without the four
+ * 1394 iso packet header bytes.
+ *
+ * Format of timestamp: 16 bits invalid, 3 bits cycleSeconds, 13 bits
+ * cycleCount, in big endian byte order.
+ *
+ * In version 1 of the ABI, no timestamp quadlet was inserted; instead, payload
+ * data followed directly after the 1394 is header if header_size > 4.
+ * Behaviour of ver. 1 of this ABI is no longer available since ABI ver. 2.
*/
struct fw_cdev_event_iso_interrupt {
__u64 closure;
@@ -171,6 +269,43 @@ struct fw_cdev_event_iso_interrupt {
};
/**
+ * struct fw_cdev_event_iso_interrupt_mc - An iso buffer chunk was completed
+ * @closure: See &fw_cdev_event_common;
+ * set by %FW_CDEV_CREATE_ISO_CONTEXT ioctl
+ * @type: %FW_CDEV_EVENT_ISO_INTERRUPT_MULTICHANNEL
+ * @completed: Offset into the receive buffer; data before this offest is valid
+ *
+ * This event is sent in multichannel contexts (context type
+ * %FW_CDEV_ISO_CONTEXT_RECEIVE_MULTICHANNEL) for &fw_cdev_iso_packet buffer
+ * chunks that have the %FW_CDEV_ISO_INTERRUPT bit set. Whether this happens
+ * when a packet is completed and/or when a buffer chunk is completed depends
+ * on the hardware implementation.
+ *
+ * The buffer is continuously filled with the following data, per packet:
+ * - the 1394 iso packet header as described at &fw_cdev_event_iso_interrupt,
+ * but in little endian byte order,
+ * - packet payload (as many bytes as specified in the data_length field of
+ * the 1394 iso packet header) in big endian byte order,
+ * - 0...3 padding bytes as needed to align the following trailer quadlet,
+ * - trailer quadlet, containing the reception timestamp as described at
+ * &fw_cdev_event_iso_interrupt, but in little endian byte order.
+ *
+ * Hence the per-packet size is data_length (rounded up to a multiple of 4) + 8.
+ * When processing the data, stop before a packet that would cross the
+ * @completed offset.
+ *
+ * A packet near the end of a buffer chunk will typically spill over into the
+ * next queued buffer chunk. It is the responsibility of the client to check
+ * for this condition, assemble a broken-up packet from its parts, and not to
+ * re-queue any buffer chunks in which as yet unread packet parts reside.
+ */
+struct fw_cdev_event_iso_interrupt_mc {
+ __u64 closure;
+ __u32 type;
+ __u32 completed;
+};
+
+/**
* struct fw_cdev_event_iso_resource - Iso resources were allocated or freed
* @closure: See &fw_cdev_event_common;
* set by %FW_CDEV_IOC_(DE)ALLOCATE_ISO_RESOURCE(_ONCE) ioctl
@@ -200,15 +335,45 @@ struct fw_cdev_event_iso_resource {
};
/**
+ * struct fw_cdev_event_phy_packet - A PHY packet was transmitted or received
+ * @closure: See &fw_cdev_event_common; set by %FW_CDEV_IOC_SEND_PHY_PACKET
+ * or %FW_CDEV_IOC_RECEIVE_PHY_PACKETS ioctl
+ * @type: %FW_CDEV_EVENT_PHY_PACKET_SENT or %..._RECEIVED
+ * @rcode: %RCODE_..., indicates success or failure of transmission
+ * @length: Data length in bytes
+ * @data: Incoming data
+ *
+ * If @type is %FW_CDEV_EVENT_PHY_PACKET_SENT, @length is 0 and @data empty,
+ * except in case of a ping packet: Then, @length is 4, and @data[0] is the
+ * ping time in 49.152MHz clocks if @rcode is %RCODE_COMPLETE.
+ *
+ * If @type is %FW_CDEV_EVENT_PHY_PACKET_RECEIVED, @length is 8 and @data
+ * consists of the two PHY packet quadlets, in host byte order.
+ */
+struct fw_cdev_event_phy_packet {
+ __u64 closure;
+ __u32 type;
+ __u32 rcode;
+ __u32 length;
+ __u32 data[0];
+};
+
+/**
* union fw_cdev_event - Convenience union of fw_cdev_event_ types
- * @common: Valid for all types
- * @bus_reset: Valid if @common.type == %FW_CDEV_EVENT_BUS_RESET
- * @response: Valid if @common.type == %FW_CDEV_EVENT_RESPONSE
- * @request: Valid if @common.type == %FW_CDEV_EVENT_REQUEST
- * @iso_interrupt: Valid if @common.type == %FW_CDEV_EVENT_ISO_INTERRUPT
- * @iso_resource: Valid if @common.type ==
+ * @common: Valid for all types
+ * @bus_reset: Valid if @common.type == %FW_CDEV_EVENT_BUS_RESET
+ * @response: Valid if @common.type == %FW_CDEV_EVENT_RESPONSE
+ * @request: Valid if @common.type == %FW_CDEV_EVENT_REQUEST
+ * @request2: Valid if @common.type == %FW_CDEV_EVENT_REQUEST2
+ * @iso_interrupt: Valid if @common.type == %FW_CDEV_EVENT_ISO_INTERRUPT
+ * @iso_interrupt_mc: Valid if @common.type ==
+ * %FW_CDEV_EVENT_ISO_INTERRUPT_MULTICHANNEL
+ * @iso_resource: Valid if @common.type ==
* %FW_CDEV_EVENT_ISO_RESOURCE_ALLOCATED or
* %FW_CDEV_EVENT_ISO_RESOURCE_DEALLOCATED
+ * @phy_packet: Valid if @common.type ==
+ * %FW_CDEV_EVENT_PHY_PACKET_SENT or
+ * %FW_CDEV_EVENT_PHY_PACKET_RECEIVED
*
* Convenience union for userspace use. Events could be read(2) into an
* appropriately aligned char buffer and then cast to this union for further
@@ -223,8 +388,11 @@ union fw_cdev_event {
struct fw_cdev_event_bus_reset bus_reset;
struct fw_cdev_event_response response;
struct fw_cdev_event_request request;
+ struct fw_cdev_event_request2 request2; /* added in 2.6.36 */
struct fw_cdev_event_iso_interrupt iso_interrupt;
- struct fw_cdev_event_iso_resource iso_resource;
+ struct fw_cdev_event_iso_interrupt_mc iso_interrupt_mc; /* added in 2.6.36 */
+ struct fw_cdev_event_iso_resource iso_resource; /* added in 2.6.30 */
+ struct fw_cdev_event_phy_packet phy_packet; /* added in 2.6.36 */
};
/* available since kernel version 2.6.22 */
@@ -256,23 +424,46 @@ union fw_cdev_event {
/* available since kernel version 2.6.34 */
#define FW_CDEV_IOC_GET_CYCLE_TIMER2 _IOWR('#', 0x14, struct fw_cdev_get_cycle_timer2)
+/* available since kernel version 2.6.36 */
+#define FW_CDEV_IOC_SEND_PHY_PACKET _IOWR('#', 0x15, struct fw_cdev_send_phy_packet)
+#define FW_CDEV_IOC_RECEIVE_PHY_PACKETS _IOW('#', 0x16, struct fw_cdev_receive_phy_packets)
+#define FW_CDEV_IOC_SET_ISO_CHANNELS _IOW('#', 0x17, struct fw_cdev_set_iso_channels)
+
/*
- * FW_CDEV_VERSION History
+ * ABI version history
* 1 (2.6.22) - initial version
+ * (2.6.24) - added %FW_CDEV_IOC_GET_CYCLE_TIMER
* 2 (2.6.30) - changed &fw_cdev_event_iso_interrupt.header if
* &fw_cdev_create_iso_context.header_size is 8 or more
+ * - added %FW_CDEV_IOC_*_ISO_RESOURCE*,
+ * %FW_CDEV_IOC_GET_SPEED, %FW_CDEV_IOC_SEND_BROADCAST_REQUEST,
+ * %FW_CDEV_IOC_SEND_STREAM_PACKET
* (2.6.32) - added time stamp to xmit &fw_cdev_event_iso_interrupt
* (2.6.33) - IR has always packet-per-buffer semantics now, not one of
* dual-buffer or packet-per-buffer depending on hardware
+ * - shared use and auto-response for FCP registers
* 3 (2.6.34) - made &fw_cdev_get_cycle_timer reliable
+ * - added %FW_CDEV_IOC_GET_CYCLE_TIMER2
+ * 4 (2.6.36) - added %FW_CDEV_EVENT_REQUEST2, %FW_CDEV_EVENT_PHY_PACKET_*,
+ * and &fw_cdev_allocate.region_end
+ * - implemented &fw_cdev_event_bus_reset.bm_node_id
+ * - added %FW_CDEV_IOC_SEND_PHY_PACKET, _RECEIVE_PHY_PACKETS
+ * - added %FW_CDEV_EVENT_ISO_INTERRUPT_MULTICHANNEL,
+ * %FW_CDEV_ISO_CONTEXT_RECEIVE_MULTICHANNEL, and
+ * %FW_CDEV_IOC_SET_ISO_CHANNELS
*/
-#define FW_CDEV_VERSION 3
+#define FW_CDEV_VERSION 3 /* Meaningless; don't use this macro. */
/**
* struct fw_cdev_get_info - General purpose information ioctl
- * @version: The version field is just a running serial number.
- * We never break backwards compatibility, but may add more
- * structs and ioctls in later revisions.
+ * @version: The version field is just a running serial number. Both an
+ * input parameter (ABI version implemented by the client) and
+ * output parameter (ABI version implemented by the kernel).
+ * A client must not fill in an %FW_CDEV_VERSION defined from an
+ * included kernel header file but the actual version for which
+ * the client was implemented. This is necessary for forward
+ * compatibility. We never break backwards compatibility, but
+ * may add more structs, events, and ioctls in later revisions.
* @rom_length: If @rom is non-zero, at most rom_length bytes of configuration
* ROM will be copied into that user space address. In either
* case, @rom_length is updated with the actual length of the
@@ -339,28 +530,48 @@ struct fw_cdev_send_response {
};
/**
- * struct fw_cdev_allocate - Allocate a CSR address range
+ * struct fw_cdev_allocate - Allocate a CSR in an address range
* @offset: Start offset of the address range
* @closure: To be passed back to userspace in request events
- * @length: Length of the address range, in bytes
+ * @length: Length of the CSR, in bytes
* @handle: Handle to the allocation, written by the kernel
+ * @region_end: First address above the address range (added in ABI v4, 2.6.36)
*
* Allocate an address range in the 48-bit address space on the local node
* (the controller). This allows userspace to listen for requests with an
- * offset within that address range. When the kernel receives a request
- * within the range, an &fw_cdev_event_request event will be written back.
- * The @closure field is passed back to userspace in the response event.
+ * offset within that address range. Every time when the kernel receives a
+ * request within the range, an &fw_cdev_event_request2 event will be emitted.
+ * (If the kernel or the client implements ABI version <= 3, an
+ * &fw_cdev_event_request will be generated instead.)
+ *
+ * The @closure field is passed back to userspace in these request events.
* The @handle field is an out parameter, returning a handle to the allocated
* range to be used for later deallocation of the range.
*
* The address range is allocated on all local nodes. The address allocation
- * is exclusive except for the FCP command and response registers.
+ * is exclusive except for the FCP command and response registers. If an
+ * exclusive address region is already in use, the ioctl fails with errno set
+ * to %EBUSY.
+ *
+ * If kernel and client implement ABI version >= 4, the kernel looks up a free
+ * spot of size @length inside [@offset..@region_end) and, if found, writes
+ * the start address of the new CSR back in @offset. I.e. @offset is an
+ * in and out parameter. If this automatic placement of a CSR in a bigger
+ * address range is not desired, the client simply needs to set @region_end
+ * = @offset + @length.
+ *
+ * If the kernel or the client implements ABI version <= 3, @region_end is
+ * ignored and effectively assumed to be @offset + @length.
+ *
+ * @region_end is only present in a kernel header >= 2.6.36. If necessary,
+ * this can for example be tested by #ifdef FW_CDEV_EVENT_REQUEST2.
*/
struct fw_cdev_allocate {
__u64 offset;
__u64 closure;
__u32 length;
__u32 handle;
+ __u64 region_end; /* available since kernel version 2.6.36 */
};
/**
@@ -382,9 +593,14 @@ struct fw_cdev_deallocate {
* Initiate a bus reset for the bus this device is on. The bus reset can be
* either the original (long) bus reset or the arbitrated (short) bus reset
* introduced in 1394a-2000.
+ *
+ * The ioctl returns immediately. A subsequent &fw_cdev_event_bus_reset
+ * indicates when the reset actually happened. Since ABI v4, this may be
+ * considerably later than the ioctl because the kernel ensures a grace period
+ * between subsequent bus resets as per IEEE 1394 bus management specification.
*/
struct fw_cdev_initiate_bus_reset {
- __u32 type; /* FW_CDEV_SHORT_RESET or FW_CDEV_LONG_RESET */
+ __u32 type;
};
/**
@@ -408,9 +624,10 @@ struct fw_cdev_initiate_bus_reset {
*
* @immediate, @key, and @data array elements are CPU-endian quadlets.
*
- * If successful, the kernel adds the descriptor and writes back a handle to the
- * kernel-side object to be used for later removal of the descriptor block and
- * immediate key.
+ * If successful, the kernel adds the descriptor and writes back a @handle to
+ * the kernel-side object to be used for later removal of the descriptor block
+ * and immediate key. The kernel will also generate a bus reset to signal the
+ * change of the configuration ROM to other nodes.
*
* This ioctl affects the configuration ROMs of all local nodes.
* The ioctl only succeeds on device files which represent a local node.
@@ -429,38 +646,50 @@ struct fw_cdev_add_descriptor {
* descriptor was added
*
* Remove a descriptor block and accompanying immediate key from the local
- * nodes' configuration ROMs.
+ * nodes' configuration ROMs. The kernel will also generate a bus reset to
+ * signal the change of the configuration ROM to other nodes.
*/
struct fw_cdev_remove_descriptor {
__u32 handle;
};
-#define FW_CDEV_ISO_CONTEXT_TRANSMIT 0
-#define FW_CDEV_ISO_CONTEXT_RECEIVE 1
+#define FW_CDEV_ISO_CONTEXT_TRANSMIT 0
+#define FW_CDEV_ISO_CONTEXT_RECEIVE 1
+#define FW_CDEV_ISO_CONTEXT_RECEIVE_MULTICHANNEL 2 /* added in 2.6.36 */
/**
- * struct fw_cdev_create_iso_context - Create a context for isochronous IO
- * @type: %FW_CDEV_ISO_CONTEXT_TRANSMIT or %FW_CDEV_ISO_CONTEXT_RECEIVE
- * @header_size: Header size to strip for receive contexts
- * @channel: Channel to bind to
- * @speed: Speed for transmit contexts
- * @closure: To be returned in &fw_cdev_event_iso_interrupt
+ * struct fw_cdev_create_iso_context - Create a context for isochronous I/O
+ * @type: %FW_CDEV_ISO_CONTEXT_TRANSMIT or %FW_CDEV_ISO_CONTEXT_RECEIVE or
+ * %FW_CDEV_ISO_CONTEXT_RECEIVE_MULTICHANNEL
+ * @header_size: Header size to strip in single-channel reception
+ * @channel: Channel to bind to in single-channel reception or transmission
+ * @speed: Transmission speed
+ * @closure: To be returned in &fw_cdev_event_iso_interrupt or
+ * &fw_cdev_event_iso_interrupt_multichannel
* @handle: Handle to context, written back by kernel
*
* Prior to sending or receiving isochronous I/O, a context must be created.
* The context records information about the transmit or receive configuration
* and typically maps to an underlying hardware resource. A context is set up
* for either sending or receiving. It is bound to a specific isochronous
- * channel.
+ * @channel.
+ *
+ * In case of multichannel reception, @header_size and @channel are ignored
+ * and the channels are selected by %FW_CDEV_IOC_SET_ISO_CHANNELS.
+ *
+ * For %FW_CDEV_ISO_CONTEXT_RECEIVE contexts, @header_size must be at least 4
+ * and must be a multiple of 4. It is ignored in other context types.
+ *
+ * @speed is ignored in receive context types.
*
* If a context was successfully created, the kernel writes back a handle to the
* context, which must be passed in for subsequent operations on that context.
*
- * For receive contexts, @header_size must be at least 4 and must be a multiple
- * of 4.
- *
- * Note that the effect of a @header_size > 4 depends on
- * &fw_cdev_get_info.version, as documented at &fw_cdev_event_iso_interrupt.
+ * Limitations:
+ * No more than one iso context can be created per fd.
+ * The total number of contexts that all userspace and kernelspace drivers can
+ * create on a card at a time is a hardware limit, typically 4 or 8 contexts per
+ * direction, and of them at most one multichannel receive context.
*/
struct fw_cdev_create_iso_context {
__u32 type;
@@ -471,6 +700,22 @@ struct fw_cdev_create_iso_context {
__u32 handle;
};
+/**
+ * struct fw_cdev_set_iso_channels - Select channels in multichannel reception
+ * @channels: Bitmask of channels to listen to
+ * @handle: Handle of the mutichannel receive context
+ *
+ * @channels is the bitwise or of 1ULL << n for each channel n to listen to.
+ *
+ * The ioctl fails with errno %EBUSY if there is already another receive context
+ * on a channel in @channels. In that case, the bitmask of all unoccupied
+ * channels is returned in @channels.
+ */
+struct fw_cdev_set_iso_channels {
+ __u64 channels;
+ __u32 handle;
+};
+
#define FW_CDEV_ISO_PAYLOAD_LENGTH(v) (v)
#define FW_CDEV_ISO_INTERRUPT (1 << 16)
#define FW_CDEV_ISO_SKIP (1 << 17)
@@ -481,42 +726,72 @@ struct fw_cdev_create_iso_context {
/**
* struct fw_cdev_iso_packet - Isochronous packet
- * @control: Contains the header length (8 uppermost bits), the sy field
- * (4 bits), the tag field (2 bits), a sync flag (1 bit),
- * a skip flag (1 bit), an interrupt flag (1 bit), and the
+ * @control: Contains the header length (8 uppermost bits),
+ * the sy field (4 bits), the tag field (2 bits), a sync flag
+ * or a skip flag (1 bit), an interrupt flag (1 bit), and the
* payload length (16 lowermost bits)
- * @header: Header and payload
+ * @header: Header and payload in case of a transmit context.
*
* &struct fw_cdev_iso_packet is used to describe isochronous packet queues.
- *
* Use the FW_CDEV_ISO_ macros to fill in @control.
+ * The @header array is empty in case of receive contexts.
+ *
+ * Context type %FW_CDEV_ISO_CONTEXT_TRANSMIT:
+ *
+ * @control.HEADER_LENGTH must be a multiple of 4. It specifies the numbers of
+ * bytes in @header that will be prepended to the packet's payload. These bytes
+ * are copied into the kernel and will not be accessed after the ioctl has
+ * returned.
+ *
+ * The @control.SY and TAG fields are copied to the iso packet header. These
+ * fields are specified by IEEE 1394a and IEC 61883-1.
+ *
+ * The @control.SKIP flag specifies that no packet is to be sent in a frame.
+ * When using this, all other fields except @control.INTERRUPT must be zero.
+ *
+ * When a packet with the @control.INTERRUPT flag set has been completed, an
+ * &fw_cdev_event_iso_interrupt event will be sent.
+ *
+ * Context type %FW_CDEV_ISO_CONTEXT_RECEIVE:
+ *
+ * @control.HEADER_LENGTH must be a multiple of the context's header_size.
+ * If the HEADER_LENGTH is larger than the context's header_size, multiple
+ * packets are queued for this entry.
+ *
+ * The @control.SY and TAG fields are ignored.
+ *
+ * If the @control.SYNC flag is set, the context drops all packets until a
+ * packet with a sy field is received which matches &fw_cdev_start_iso.sync.
+ *
+ * @control.PAYLOAD_LENGTH defines how many payload bytes can be received for
+ * one packet (in addition to payload quadlets that have been defined as headers
+ * and are stripped and returned in the &fw_cdev_event_iso_interrupt structure).
+ * If more bytes are received, the additional bytes are dropped. If less bytes
+ * are received, the remaining bytes in this part of the payload buffer will not
+ * be written to, not even by the next packet. I.e., packets received in
+ * consecutive frames will not necessarily be consecutive in memory. If an
+ * entry has queued multiple packets, the PAYLOAD_LENGTH is divided equally
+ * among them.
*
- * For transmit packets, the header length must be a multiple of 4 and specifies
- * the numbers of bytes in @header that will be prepended to the packet's
- * payload; these bytes are copied into the kernel and will not be accessed
- * after the ioctl has returned. The sy and tag fields are copied to the iso
- * packet header (these fields are specified by IEEE 1394a and IEC 61883-1).
- * The skip flag specifies that no packet is to be sent in a frame; when using
- * this, all other fields except the interrupt flag must be zero.
- *
- * For receive packets, the header length must be a multiple of the context's
- * header size; if the header length is larger than the context's header size,
- * multiple packets are queued for this entry. The sy and tag fields are
- * ignored. If the sync flag is set, the context drops all packets until
- * a packet with a matching sy field is received (the sync value to wait for is
- * specified in the &fw_cdev_start_iso structure). The payload length defines
- * how many payload bytes can be received for one packet (in addition to payload
- * quadlets that have been defined as headers and are stripped and returned in
- * the &fw_cdev_event_iso_interrupt structure). If more bytes are received, the
- * additional bytes are dropped. If less bytes are received, the remaining
- * bytes in this part of the payload buffer will not be written to, not even by
- * the next packet, i.e., packets received in consecutive frames will not
- * necessarily be consecutive in memory. If an entry has queued multiple
- * packets, the payload length is divided equally among them.
- *
- * When a packet with the interrupt flag set has been completed, the
+ * When a packet with the @control.INTERRUPT flag set has been completed, an
* &fw_cdev_event_iso_interrupt event will be sent. An entry that has queued
* multiple receive packets is completed when its last packet is completed.
+ *
+ * Context type %FW_CDEV_ISO_CONTEXT_RECEIVE_MULTICHANNEL:
+ *
+ * Here, &fw_cdev_iso_packet would be more aptly named _iso_buffer_chunk since
+ * it specifies a chunk of the mmap()'ed buffer, while the number and alignment
+ * of packets to be placed into the buffer chunk is not known beforehand.
+ *
+ * @control.PAYLOAD_LENGTH is the size of the buffer chunk and specifies room
+ * for header, payload, padding, and trailer bytes of one or more packets.
+ * It must be a multiple of 4.
+ *
+ * @control.HEADER_LENGTH, TAG and SY are ignored. SYNC is treated as described
+ * for single-channel reception.
+ *
+ * When a buffer chunk with the @control.INTERRUPT flag set has been filled
+ * entirely, an &fw_cdev_event_iso_interrupt_mc event will be sent.
*/
struct fw_cdev_iso_packet {
__u32 control;
@@ -525,9 +800,9 @@ struct fw_cdev_iso_packet {
/**
* struct fw_cdev_queue_iso - Queue isochronous packets for I/O
- * @packets: Userspace pointer to packet data
+ * @packets: Userspace pointer to an array of &fw_cdev_iso_packet
* @data: Pointer into mmap()'ed payload buffer
- * @size: Size of packet data in bytes
+ * @size: Size of the @packets array, in bytes
* @handle: Isochronous context handle
*
* Queue a number of isochronous packets for reception or transmission.
@@ -540,6 +815,9 @@ struct fw_cdev_iso_packet {
* The kernel may or may not queue all packets, but will write back updated
* values of the @packets, @data and @size fields, so the ioctl can be
* resubmitted easily.
+ *
+ * In case of a multichannel receive context, @data must be quadlet-aligned
+ * relative to the buffer start.
*/
struct fw_cdev_queue_iso {
__u64 packets;
@@ -698,4 +976,39 @@ struct fw_cdev_send_stream_packet {
__u32 speed;
};
+/**
+ * struct fw_cdev_send_phy_packet - send a PHY packet
+ * @closure: Passed back to userspace in the PHY-packet-sent event
+ * @data: First and second quadlet of the PHY packet
+ * @generation: The bus generation where packet is valid
+ *
+ * The %FW_CDEV_IOC_SEND_PHY_PACKET ioctl sends a PHY packet to all nodes
+ * on the same card as this device. After transmission, an
+ * %FW_CDEV_EVENT_PHY_PACKET_SENT event is generated.
+ *
+ * The payload @data[] shall be specified in host byte order. Usually,
+ * @data[1] needs to be the bitwise inverse of @data[0]. VersaPHY packets
+ * are an exception to this rule.
+ *
+ * The ioctl is only permitted on device files which represent a local node.
+ */
+struct fw_cdev_send_phy_packet {
+ __u64 closure;
+ __u32 data[2];
+ __u32 generation;
+};
+
+/**
+ * struct fw_cdev_receive_phy_packets - start reception of PHY packets
+ * @closure: Passed back to userspace in phy packet events
+ *
+ * This ioctl activates issuing of %FW_CDEV_EVENT_PHY_PACKET_RECEIVED due to
+ * incoming PHY packets from any node on the same bus as the device.
+ *
+ * The ioctl is only permitted on device files which represent a local node.
+ */
+struct fw_cdev_receive_phy_packets {
+ __u64 closure;
+};
+
#endif /* _LINUX_FIREWIRE_CDEV_H */
diff --git a/include/linux/firewire.h b/include/linux/firewire.h
index 72e2b8ac2a5..1cd637ef62d 100644
--- a/include/linux/firewire.h
+++ b/include/linux/firewire.h
@@ -32,11 +32,13 @@
#define CSR_CYCLE_TIME 0x200
#define CSR_BUS_TIME 0x204
#define CSR_BUSY_TIMEOUT 0x210
+#define CSR_PRIORITY_BUDGET 0x218
#define CSR_BUS_MANAGER_ID 0x21c
#define CSR_BANDWIDTH_AVAILABLE 0x220
#define CSR_CHANNELS_AVAILABLE 0x224
#define CSR_CHANNELS_AVAILABLE_HI 0x224
#define CSR_CHANNELS_AVAILABLE_LO 0x228
+#define CSR_MAINT_UTILITY 0x230
#define CSR_BROADCAST_CHANNEL 0x234
#define CSR_CONFIG_ROM 0x400
#define CSR_CONFIG_ROM_END 0x800
@@ -89,6 +91,11 @@ struct fw_card {
struct list_head transaction_list;
unsigned long reset_jiffies;
+ u32 split_timeout_hi;
+ u32 split_timeout_lo;
+ unsigned int split_timeout_cycles;
+ unsigned int split_timeout_jiffies;
+
unsigned long long guid;
unsigned max_receive;
int link_speed;
@@ -104,18 +111,28 @@ struct fw_card {
bool beta_repeaters_present;
int index;
-
struct list_head link;
- /* Work struct for BM duties. */
- struct delayed_work work;
+ struct list_head phy_receiver_list;
+
+ struct delayed_work br_work; /* bus reset job */
+ bool br_short;
+
+ struct delayed_work bm_work; /* bus manager job */
int bm_retries;
int bm_generation;
__be32 bm_transaction_data[2];
+ int bm_node_id;
+ bool bm_abdicate;
+
+ bool priority_budget_implemented; /* controller feature */
+ bool broadcast_channel_auto_allocated; /* controller feature */
bool broadcast_channel_allocated;
u32 broadcast_channel;
__be32 topology_map[(CSR_TOPOLOGY_MAP_END - CSR_TOPOLOGY_MAP) / 4];
+
+ __be32 maint_utility_register;
};
struct fw_attribute_group {
@@ -252,7 +269,7 @@ typedef void (*fw_transaction_callback_t)(struct fw_card *card, int rcode,
typedef void (*fw_address_callback_t)(struct fw_card *card,
struct fw_request *request,
int tcode, int destination, int source,
- int generation, int speed,
+ int generation,
unsigned long long offset,
void *data, size_t length,
void *callback_data);
@@ -269,10 +286,10 @@ struct fw_packet {
u32 timestamp;
/*
- * This callback is called when the packet transmission has
- * completed; for successful transmission, the status code is
- * the ack received from the destination, otherwise it's a
- * negative errno: ENOMEM, ESTALE, ETIMEDOUT, ENODEV, EIO.
+ * This callback is called when the packet transmission has completed.
+ * For successful transmission, the status code is the ack received
+ * from the destination. Otherwise it is one of the juju-specific
+ * rcodes: RCODE_SEND_ERROR, _CANCELLED, _BUSY, _GENERATION, _NO_ACK.
* The callback can be called from tasklet context and thus
* must never block.
*/
@@ -355,17 +372,19 @@ void fw_core_remove_descriptor(struct fw_descriptor *desc);
* scatter-gather streaming (e.g. assembling video frame automatically).
*/
struct fw_iso_packet {
- u16 payload_length; /* Length of indirect payload. */
- u32 interrupt:1; /* Generate interrupt on this packet */
- u32 skip:1; /* Set to not send packet at all. */
- u32 tag:2;
- u32 sy:4;
- u32 header_length:8; /* Length of immediate header. */
- u32 header[0];
+ u16 payload_length; /* Length of indirect payload */
+ u32 interrupt:1; /* Generate interrupt on this packet */
+ u32 skip:1; /* tx: Set to not send packet at all */
+ /* rx: Sync bit, wait for matching sy */
+ u32 tag:2; /* tx: Tag in packet header */
+ u32 sy:4; /* tx: Sy in packet header */
+ u32 header_length:8; /* Length of immediate header */
+ u32 header[0]; /* tx: Top of 1394 isoch. data_block */
};
-#define FW_ISO_CONTEXT_TRANSMIT 0
-#define FW_ISO_CONTEXT_RECEIVE 1
+#define FW_ISO_CONTEXT_TRANSMIT 0
+#define FW_ISO_CONTEXT_RECEIVE 1
+#define FW_ISO_CONTEXT_RECEIVE_MULTICHANNEL 2
#define FW_ISO_CONTEXT_MATCH_TAG0 1
#define FW_ISO_CONTEXT_MATCH_TAG1 2
@@ -389,24 +408,31 @@ struct fw_iso_buffer {
int fw_iso_buffer_init(struct fw_iso_buffer *buffer, struct fw_card *card,
int page_count, enum dma_data_direction direction);
void fw_iso_buffer_destroy(struct fw_iso_buffer *buffer, struct fw_card *card);
+size_t fw_iso_buffer_lookup(struct fw_iso_buffer *buffer, dma_addr_t completed);
struct fw_iso_context;
typedef void (*fw_iso_callback_t)(struct fw_iso_context *context,
u32 cycle, size_t header_length,
void *header, void *data);
+typedef void (*fw_iso_mc_callback_t)(struct fw_iso_context *context,
+ dma_addr_t completed, void *data);
struct fw_iso_context {
struct fw_card *card;
int type;
int channel;
int speed;
size_t header_size;
- fw_iso_callback_t callback;
+ union {
+ fw_iso_callback_t sc;
+ fw_iso_mc_callback_t mc;
+ } callback;
void *callback_data;
};
struct fw_iso_context *fw_iso_context_create(struct fw_card *card,
int type, int channel, int speed, size_t header_size,
fw_iso_callback_t callback, void *callback_data);
+int fw_iso_context_set_channels(struct fw_iso_context *ctx, u64 *channels);
int fw_iso_context_queue(struct fw_iso_context *ctx,
struct fw_iso_packet *packet,
struct fw_iso_buffer *buffer,
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 68ca1b0491a..e5106e49bd2 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -53,6 +53,7 @@ struct inodes_stat_t {
#define MAY_APPEND 8
#define MAY_ACCESS 16
#define MAY_OPEN 32
+#define MAY_CHDIR 64
/*
* flags in file.f_mode. Note that FMODE_READ and FMODE_WRITE must correspond
@@ -415,7 +416,8 @@ struct buffer_head;
typedef int (get_block_t)(struct inode *inode, sector_t iblock,
struct buffer_head *bh_result, int create);
typedef void (dio_iodone_t)(struct kiocb *iocb, loff_t offset,
- ssize_t bytes, void *private);
+ ssize_t bytes, void *private, int ret,
+ bool is_async);
/*
* Attribute flags. These should be or-ed together to figure out what
diff --git a/include/linux/fscache-cache.h b/include/linux/fscache-cache.h
index c57db27ac86..b8581c09d19 100644
--- a/include/linux/fscache-cache.h
+++ b/include/linux/fscache-cache.h
@@ -20,7 +20,7 @@
#include <linux/fscache.h>
#include <linux/sched.h>
-#include <linux/slow-work.h>
+#include <linux/workqueue.h>
#define NR_MAXCACHES BITS_PER_LONG
@@ -76,18 +76,14 @@ typedef void (*fscache_operation_release_t)(struct fscache_operation *op);
typedef void (*fscache_operation_processor_t)(struct fscache_operation *op);
struct fscache_operation {
- union {
- struct work_struct fast_work; /* record for fast ops */
- struct slow_work slow_work; /* record for (very) slow ops */
- };
+ struct work_struct work; /* record for async ops */
struct list_head pend_link; /* link in object->pending_ops */
struct fscache_object *object; /* object to be operated upon */
unsigned long flags;
#define FSCACHE_OP_TYPE 0x000f /* operation type */
-#define FSCACHE_OP_FAST 0x0001 /* - fast op, processor may not sleep for disk */
-#define FSCACHE_OP_SLOW 0x0002 /* - (very) slow op, processor may sleep for disk */
-#define FSCACHE_OP_MYTHREAD 0x0003 /* - processing is done be issuing thread, not pool */
+#define FSCACHE_OP_ASYNC 0x0001 /* - async op, processor may sleep for disk */
+#define FSCACHE_OP_MYTHREAD 0x0002 /* - processing is done be issuing thread, not pool */
#define FSCACHE_OP_WAITING 4 /* cleared when op is woken */
#define FSCACHE_OP_EXCLUSIVE 5 /* exclusive op, other ops must wait */
#define FSCACHE_OP_DEAD 6 /* op is now dead */
@@ -105,7 +101,8 @@ struct fscache_operation {
/* operation releaser */
fscache_operation_release_t release;
-#ifdef CONFIG_SLOW_WORK_DEBUG
+#ifdef CONFIG_WORKQUEUE_DEBUGFS
+ struct work_struct put_work; /* work to delay operation put */
const char *name; /* operation name */
const char *state; /* operation state */
#define fscache_set_op_name(OP, N) do { (OP)->name = (N); } while(0)
@@ -117,7 +114,7 @@ struct fscache_operation {
};
extern atomic_t fscache_op_debug_id;
-extern const struct slow_work_ops fscache_op_slow_work_ops;
+extern void fscache_op_work_func(struct work_struct *work);
extern void fscache_enqueue_operation(struct fscache_operation *);
extern void fscache_put_operation(struct fscache_operation *);
@@ -128,33 +125,21 @@ extern void fscache_put_operation(struct fscache_operation *);
* @release: The release function to assign
*
* Do basic initialisation of an operation. The caller must still set flags,
- * object, either fast_work or slow_work if necessary, and processor if needed.
+ * object and processor if needed.
*/
static inline void fscache_operation_init(struct fscache_operation *op,
- fscache_operation_release_t release)
+ fscache_operation_processor_t processor,
+ fscache_operation_release_t release)
{
+ INIT_WORK(&op->work, fscache_op_work_func);
atomic_set(&op->usage, 1);
op->debug_id = atomic_inc_return(&fscache_op_debug_id);
+ op->processor = processor;
op->release = release;
INIT_LIST_HEAD(&op->pend_link);
fscache_set_op_state(op, "Init");
}
-/**
- * fscache_operation_init_slow - Do additional initialisation of a slow op
- * @op: The operation to initialise
- * @processor: The processor function to assign
- *
- * Do additional initialisation of an operation as required for slow work.
- */
-static inline
-void fscache_operation_init_slow(struct fscache_operation *op,
- fscache_operation_processor_t processor)
-{
- op->processor = processor;
- slow_work_init(&op->slow_work, &fscache_op_slow_work_ops);
-}
-
/*
* data read operation
*/
@@ -389,7 +374,7 @@ struct fscache_object {
struct fscache_cache *cache; /* cache that supplied this object */
struct fscache_cookie *cookie; /* netfs's file/index object */
struct fscache_object *parent; /* parent object */
- struct slow_work work; /* attention scheduling record */
+ struct work_struct work; /* attention scheduling record */
struct list_head dependents; /* FIFO of dependent objects */
struct list_head dep_link; /* link in parent's dependents list */
struct list_head pending_ops; /* unstarted operations on this object */
@@ -411,7 +396,7 @@ extern const char *fscache_object_states[];
(test_bit(FSCACHE_IOERROR, &(obj)->cache->flags) && \
(obj)->state >= FSCACHE_OBJECT_DYING)
-extern const struct slow_work_ops fscache_object_slow_work_ops;
+extern void fscache_object_work_func(struct work_struct *work);
/**
* fscache_object_init - Initialise a cache object description
@@ -433,7 +418,7 @@ void fscache_object_init(struct fscache_object *object,
spin_lock_init(&object->lock);
INIT_LIST_HEAD(&object->cache_link);
INIT_HLIST_NODE(&object->cookie_link);
- vslow_work_init(&object->work, &fscache_object_slow_work_ops);
+ INIT_WORK(&object->work, fscache_object_work_func);
INIT_LIST_HEAD(&object->dependents);
INIT_LIST_HEAD(&object->dep_link);
INIT_LIST_HEAD(&object->pending_ops);
@@ -534,6 +519,8 @@ extern void fscache_io_error(struct fscache_cache *cache);
extern void fscache_mark_pages_cached(struct fscache_retrieval *op,
struct pagevec *pagevec);
+extern bool fscache_object_sleep_till_congested(signed long *timeoutp);
+
extern enum fscache_checkaux fscache_check_aux(struct fscache_object *object,
const void *data,
uint16_t datalen);
diff --git a/include/linux/fscache.h b/include/linux/fscache.h
index 595ce49288b..ec0dad5ab90 100644
--- a/include/linux/fscache.h
+++ b/include/linux/fscache.h
@@ -85,7 +85,7 @@ struct fscache_cookie_def {
/* get an index key
* - should store the key data in the buffer
- * - should return the amount of amount stored
+ * - should return the amount of data stored
* - not permitted to return an error
* - the netfs data from the cookie being used as the source is
* presented
@@ -454,6 +454,7 @@ int fscache_read_or_alloc_page(struct fscache_cookie *cookie,
* @cookie: The cookie representing the cache object
* @mapping: The netfs inode mapping to which the pages will be attached
* @pages: A list of potential netfs pages to be filled
+ * @nr_pages: Number of pages to be read and/or allocated
* @end_io_func: The callback to invoke when and if each page is filled
* @context: An arbitrary piece of data to pass on to end_io_func()
* @gfp: The conditions under which memory allocation should be made
diff --git a/drivers/video/fsl-diu-fb.h b/include/linux/fsl-diu-fb.h
index fc295d7ea46..fc295d7ea46 100644
--- a/drivers/video/fsl-diu-fb.h
+++ b/include/linux/fsl-diu-fb.h
diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h
index 41e46330d9b..dcd6a7c3a43 100644
--- a/include/linux/ftrace.h
+++ b/include/linux/ftrace.h
@@ -1,3 +1,8 @@
+/*
+ * Ftrace header. For implementation details beyond the random comments
+ * scattered below, see: Documentation/trace/ftrace-design.txt
+ */
+
#ifndef _LINUX_FTRACE_H
#define _LINUX_FTRACE_H
diff --git a/include/linux/ftrace_event.h b/include/linux/ftrace_event.h
index 3167f2df412..02b8b24f8f5 100644
--- a/include/linux/ftrace_event.h
+++ b/include/linux/ftrace_event.h
@@ -11,8 +11,6 @@ struct trace_array;
struct tracer;
struct dentry;
-DECLARE_PER_CPU(struct trace_seq, ftrace_event_seq);
-
struct trace_print_flags {
unsigned long mask;
const char *name;
@@ -58,6 +56,9 @@ struct trace_iterator {
struct ring_buffer_iter *buffer_iter[NR_CPUS];
unsigned long iter_flags;
+ /* trace_seq for __print_flags() and __print_symbolic() etc. */
+ struct trace_seq tmp_seq;
+
/* The below is zeroed out in pipe_read */
struct trace_seq seq;
struct trace_entry *ent;
@@ -146,14 +147,19 @@ struct ftrace_event_class {
int (*raw_init)(struct ftrace_event_call *);
};
+extern int ftrace_event_reg(struct ftrace_event_call *event,
+ enum trace_reg type);
+
enum {
TRACE_EVENT_FL_ENABLED_BIT,
TRACE_EVENT_FL_FILTERED_BIT,
+ TRACE_EVENT_FL_RECORDED_CMD_BIT,
};
enum {
- TRACE_EVENT_FL_ENABLED = (1 << TRACE_EVENT_FL_ENABLED_BIT),
- TRACE_EVENT_FL_FILTERED = (1 << TRACE_EVENT_FL_FILTERED_BIT),
+ TRACE_EVENT_FL_ENABLED = (1 << TRACE_EVENT_FL_ENABLED_BIT),
+ TRACE_EVENT_FL_FILTERED = (1 << TRACE_EVENT_FL_FILTERED_BIT),
+ TRACE_EVENT_FL_RECORDED_CMD = (1 << TRACE_EVENT_FL_RECORDED_CMD_BIT),
};
struct ftrace_event_call {
@@ -171,6 +177,7 @@ struct ftrace_event_call {
* 32 bit flags:
* bit 1: enabled
* bit 2: filter_active
+ * bit 3: enabled cmd record
*
* Changes to flags must hold the event_mutex.
*
@@ -257,8 +264,7 @@ static inline void
perf_trace_buf_submit(void *raw_data, int size, int rctx, u64 addr,
u64 count, struct pt_regs *regs, void *head)
{
- perf_tp_event(addr, count, raw_data, size, regs, head);
- perf_swevent_put_recursion_context(rctx);
+ perf_tp_event(addr, count, raw_data, size, regs, head, rctx);
}
#endif
diff --git a/include/linux/fuse.h b/include/linux/fuse.h
index 88e0eb59691..c3c578e0983 100644
--- a/include/linux/fuse.h
+++ b/include/linux/fuse.h
@@ -37,6 +37,10 @@
*
* 7.14
* - add splice support to fuse device
+ *
+ * 7.15
+ * - add store notify
+ * - add retrieve notify
*/
#ifndef _LINUX_FUSE_H
@@ -68,7 +72,7 @@
#define FUSE_KERNEL_VERSION 7
/** Minor version number of this interface */
-#define FUSE_KERNEL_MINOR_VERSION 14
+#define FUSE_KERNEL_MINOR_VERSION 15
/** The node ID of the root inode */
#define FUSE_ROOT_ID 1
@@ -251,6 +255,7 @@ enum fuse_opcode {
FUSE_DESTROY = 38,
FUSE_IOCTL = 39,
FUSE_POLL = 40,
+ FUSE_NOTIFY_REPLY = 41,
/* CUSE specific operations */
CUSE_INIT = 4096,
@@ -260,6 +265,8 @@ enum fuse_notify_code {
FUSE_NOTIFY_POLL = 1,
FUSE_NOTIFY_INVAL_INODE = 2,
FUSE_NOTIFY_INVAL_ENTRY = 3,
+ FUSE_NOTIFY_STORE = 4,
+ FUSE_NOTIFY_RETRIEVE = 5,
FUSE_NOTIFY_CODE_MAX,
};
@@ -568,4 +575,29 @@ struct fuse_notify_inval_entry_out {
__u32 padding;
};
+struct fuse_notify_store_out {
+ __u64 nodeid;
+ __u64 offset;
+ __u32 size;
+ __u32 padding;
+};
+
+struct fuse_notify_retrieve_out {
+ __u64 notify_unique;
+ __u64 nodeid;
+ __u64 offset;
+ __u32 size;
+ __u32 padding;
+};
+
+/* Matches the size of fuse_write_in */
+struct fuse_notify_retrieve_in {
+ __u64 dummy1;
+ __u64 offset;
+ __u32 size;
+ __u32 dummy2;
+ __u64 dummy3;
+ __u64 dummy4;
+};
+
#endif /* _LINUX_FUSE_H */
diff --git a/include/linux/hid.h b/include/linux/hid.h
index 895001f7f4b..42a0f1d1136 100644
--- a/include/linux/hid.h
+++ b/include/linux/hid.h
@@ -311,6 +311,7 @@ struct hid_item {
#define HID_QUIRK_HIDDEV_FORCE 0x00000010
#define HID_QUIRK_BADPAD 0x00000020
#define HID_QUIRK_MULTI_INPUT 0x00000040
+#define HID_QUIRK_HIDINPUT_FORCE 0x00000080
#define HID_QUIRK_SKIP_OUTPUT_REPORTS 0x00010000
#define HID_QUIRK_FULLSPEED_INTERVAL 0x10000000
#define HID_QUIRK_NO_INIT_REPORTS 0x20000000
diff --git a/include/linux/i2c/adp5588.h b/include/linux/i2c/adp5588.h
index 02c9af37474..269181b8f62 100644
--- a/include/linux/i2c/adp5588.h
+++ b/include/linux/i2c/adp5588.h
@@ -78,6 +78,40 @@
#define ADP5588_KEYMAPSIZE 80
+#define GPI_PIN_ROW0 97
+#define GPI_PIN_ROW1 98
+#define GPI_PIN_ROW2 99
+#define GPI_PIN_ROW3 100
+#define GPI_PIN_ROW4 101
+#define GPI_PIN_ROW5 102
+#define GPI_PIN_ROW6 103
+#define GPI_PIN_ROW7 104
+#define GPI_PIN_COL0 105
+#define GPI_PIN_COL1 106
+#define GPI_PIN_COL2 107
+#define GPI_PIN_COL3 108
+#define GPI_PIN_COL4 109
+#define GPI_PIN_COL5 110
+#define GPI_PIN_COL6 111
+#define GPI_PIN_COL7 112
+#define GPI_PIN_COL8 113
+#define GPI_PIN_COL9 114
+
+#define GPI_PIN_ROW_BASE GPI_PIN_ROW0
+#define GPI_PIN_ROW_END GPI_PIN_ROW7
+#define GPI_PIN_COL_BASE GPI_PIN_COL0
+#define GPI_PIN_COL_END GPI_PIN_COL9
+
+#define GPI_PIN_BASE GPI_PIN_ROW_BASE
+#define GPI_PIN_END GPI_PIN_COL_END
+
+#define ADP5588_GPIMAPSIZE_MAX (GPI_PIN_END - GPI_PIN_BASE + 1)
+
+struct adp5588_gpi_map {
+ unsigned short pin;
+ unsigned short sw_evt;
+};
+
struct adp5588_kpad_platform_data {
int rows; /* Number of rows */
int cols; /* Number of columns */
@@ -87,6 +121,9 @@ struct adp5588_kpad_platform_data {
unsigned en_keylock:1; /* Enable Key Lock feature */
unsigned short unlock_key1; /* Unlock Key 1 */
unsigned short unlock_key2; /* Unlock Key 2 */
+ const struct adp5588_gpi_map *gpimap;
+ unsigned short gpimapsize;
+ const struct adp5588_gpio_platform_data *gpio_data;
};
struct adp5588_gpio_platform_data {
diff --git a/include/linux/i2c/mcs.h b/include/linux/i2c/mcs.h
new file mode 100644
index 00000000000..725ae7c313f
--- /dev/null
+++ b/include/linux/i2c/mcs.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2009 - 2010 Samsung Electronics Co.Ltd
+ * Author: Joonyoung Shim <jy0922.shim@samsung.com>
+ * Author: HeungJun Kim <riverful.kim@samsung.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 __LINUX_MCS_H
+#define __LINUX_MCS_H
+
+#define MCS_KEY_MAP(v, c) ((((v) & 0xff) << 16) | ((c) & 0xffff))
+#define MCS_KEY_VAL(v) (((v) >> 16) & 0xff)
+#define MCS_KEY_CODE(v) ((v) & 0xffff)
+
+struct mcs_platform_data {
+ void (*cfg_pin)(void);
+
+ /* touchscreen */
+ unsigned int x_size;
+ unsigned int y_size;
+
+ /* touchkey */
+ const u32 *keymap;
+ unsigned int keymap_size;
+ unsigned int key_maxval;
+ bool no_autorepeat;
+};
+
+#endif /* __LINUX_MCS_H */
diff --git a/include/linux/i2c/mcs5000_ts.h b/include/linux/i2c/mcs5000_ts.h
deleted file mode 100644
index 5a117b5ca15..00000000000
--- a/include/linux/i2c/mcs5000_ts.h
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * mcs5000_ts.h
- *
- * Copyright (C) 2009 Samsung Electronics Co.Ltd
- * Author: Joonyoung Shim <jy0922.shim@samsung.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 __LINUX_MCS5000_TS_H
-#define __LINUX_MCS5000_TS_H
-
-/* platform data for the MELFAS MCS-5000 touchscreen driver */
-struct mcs5000_ts_platform_data {
- void (*cfg_pin)(void);
- int x_size;
- int y_size;
-};
-
-#endif /* __LINUX_MCS5000_TS_H */
diff --git a/include/linux/i2c/qt602240_ts.h b/include/linux/i2c/qt602240_ts.h
new file mode 100644
index 00000000000..c5033e10109
--- /dev/null
+++ b/include/linux/i2c/qt602240_ts.h
@@ -0,0 +1,38 @@
+/*
+ * AT42QT602240/ATMXT224 Touchscreen driver
+ *
+ * Copyright (C) 2010 Samsung Electronics Co.Ltd
+ * Author: Joonyoung Shim <jy0922.shim@samsung.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 __LINUX_QT602240_TS_H
+#define __LINUX_QT602240_TS_H
+
+/* Orient */
+#define QT602240_NORMAL 0x0
+#define QT602240_DIAGONAL 0x1
+#define QT602240_HORIZONTAL_FLIP 0x2
+#define QT602240_ROTATED_90_COUNTER 0x3
+#define QT602240_VERTICAL_FLIP 0x4
+#define QT602240_ROTATED_90 0x5
+#define QT602240_ROTATED_180 0x6
+#define QT602240_DIAGONAL_COUNTER 0x7
+
+/* The platform data for the AT42QT602240/ATMXT224 touchscreen driver */
+struct qt602240_platform_data {
+ unsigned int x_line;
+ unsigned int y_line;
+ unsigned int x_size;
+ unsigned int y_size;
+ unsigned int blen;
+ unsigned int threshold;
+ unsigned int voltage;
+ unsigned char orient;
+};
+
+#endif /* __LINUX_QT602240_TS_H */
diff --git a/include/linux/ide.h b/include/linux/ide.h
index 7b02aa5ce9b..072fe8c93e6 100644
--- a/include/linux/ide.h
+++ b/include/linux/ide.h
@@ -458,7 +458,7 @@ enum {
IDE_DFLAG_DOORLOCKING = (1 << 15),
/* disallow DMA */
IDE_DFLAG_NODMA = (1 << 16),
- /* powermanagment told us not to do anything, so sleep nicely */
+ /* powermanagement told us not to do anything, so sleep nicely */
IDE_DFLAG_BLOCKED = (1 << 17),
/* sleeping & sleep field valid */
IDE_DFLAG_SLEEPING = (1 << 18),
diff --git a/include/linux/if.h b/include/linux/if.h
index be350e62a90..53558ec59e1 100644
--- a/include/linux/if.h
+++ b/include/linux/if.h
@@ -73,6 +73,8 @@
#define IFF_DONT_BRIDGE 0x800 /* disallow bridging this ether dev */
#define IFF_IN_NETPOLL 0x1000 /* whether we are processing netpoll */
#define IFF_DISABLE_NETPOLL 0x2000 /* disable netpoll at run-time */
+#define IFF_MACVLAN_PORT 0x4000 /* device used as macvlan port */
+#define IFF_BRIDGE_PORT 0x8000 /* device used as bridge port */
#define IF_GET_IFACE 0x0001 /* for querying only */
#define IF_GET_PROTO 0x0002
diff --git a/include/linux/if_bonding.h b/include/linux/if_bonding.h
index cd525fae3c9..2c7994372bd 100644
--- a/include/linux/if_bonding.h
+++ b/include/linux/if_bonding.h
@@ -83,6 +83,7 @@
#define BOND_DEFAULT_MAX_BONDS 1 /* Default maximum number of devices to support */
+#define BOND_DEFAULT_TX_QUEUES 16 /* Default number of tx queues per device */
/* hashing types */
#define BOND_XMIT_POLICY_LAYER2 0 /* layer 2 (MAC only), default */
#define BOND_XMIT_POLICY_LAYER34 1 /* layer 3+4 (IP ^ (TCP || UDP)) */
diff --git a/include/linux/if_bridge.h b/include/linux/if_bridge.h
index 938b7e81df9..0d241a5c490 100644
--- a/include/linux/if_bridge.h
+++ b/include/linux/if_bridge.h
@@ -102,8 +102,6 @@ struct __fdb_entry {
#include <linux/netdevice.h>
extern void brioctl_set(int (*ioctl_hook)(struct net *, unsigned int, void __user *));
-extern struct sk_buff *(*br_handle_frame_hook)(struct net_bridge_port *p,
- struct sk_buff *skb);
extern int (*br_should_route_hook)(struct sk_buff *skb);
#endif
diff --git a/include/linux/if_ether.h b/include/linux/if_ether.h
index bed7a4682b9..c831467774d 100644
--- a/include/linux/if_ether.h
+++ b/include/linux/if_ether.h
@@ -119,7 +119,7 @@ struct ethhdr {
unsigned char h_dest[ETH_ALEN]; /* destination eth addr */
unsigned char h_source[ETH_ALEN]; /* source ether addr */
__be16 h_proto; /* packet type ID field */
-} __attribute__((packed));
+} __packed;
#ifdef __KERNEL__
#include <linux/skbuff.h>
diff --git a/include/linux/if_fddi.h b/include/linux/if_fddi.h
index 5459c5c0993..9947c39e62f 100644
--- a/include/linux/if_fddi.h
+++ b/include/linux/if_fddi.h
@@ -67,7 +67,7 @@ struct fddi_8022_1_hdr {
__u8 dsap; /* destination service access point */
__u8 ssap; /* source service access point */
__u8 ctrl; /* control byte #1 */
-} __attribute__ ((packed));
+} __packed;
/* Define 802.2 Type 2 header */
struct fddi_8022_2_hdr {
@@ -75,7 +75,7 @@ struct fddi_8022_2_hdr {
__u8 ssap; /* source service access point */
__u8 ctrl_1; /* control byte #1 */
__u8 ctrl_2; /* control byte #2 */
-} __attribute__ ((packed));
+} __packed;
/* Define 802.2 SNAP header */
#define FDDI_K_OUI_LEN 3
@@ -85,7 +85,7 @@ struct fddi_snap_hdr {
__u8 ctrl; /* always 0x03 */
__u8 oui[FDDI_K_OUI_LEN]; /* organizational universal id */
__be16 ethertype; /* packet type ID field */
-} __attribute__ ((packed));
+} __packed;
/* Define FDDI LLC frame header */
struct fddihdr {
@@ -98,7 +98,7 @@ struct fddihdr {
struct fddi_8022_2_hdr llc_8022_2;
struct fddi_snap_hdr llc_snap;
} hdr;
-} __attribute__ ((packed));
+} __packed;
#ifdef __KERNEL__
#include <linux/netdevice.h>
diff --git a/include/linux/if_frad.h b/include/linux/if_frad.h
index 80b3a1056a5..191ee0869bc 100644
--- a/include/linux/if_frad.h
+++ b/include/linux/if_frad.h
@@ -135,7 +135,7 @@ struct frhdr
__be16 PID;
#define IP_NLPID pad
-} __attribute__((packed));
+} __packed;
/* see RFC 1490 for the definition of the following */
#define FRAD_I_UI 0x03
diff --git a/include/linux/if_hippi.h b/include/linux/if_hippi.h
index 8d038eb8db5..5fe5f307c6f 100644
--- a/include/linux/if_hippi.h
+++ b/include/linux/if_hippi.h
@@ -104,7 +104,7 @@ struct hippi_fp_hdr {
__be32 fixed;
#endif
__be32 d2_size;
-} __attribute__ ((packed));
+} __packed;
struct hippi_le_hdr {
#if defined (__BIG_ENDIAN_BITFIELD)
@@ -129,7 +129,7 @@ struct hippi_le_hdr {
__u8 daddr[HIPPI_ALEN];
__u16 locally_administered;
__u8 saddr[HIPPI_ALEN];
-} __attribute__ ((packed));
+} __packed;
#define HIPPI_OUI_LEN 3
/*
@@ -142,12 +142,12 @@ struct hippi_snap_hdr {
__u8 ctrl; /* always 0x03 */
__u8 oui[HIPPI_OUI_LEN]; /* organizational universal id (zero)*/
__be16 ethertype; /* packet type ID field */
-} __attribute__ ((packed));
+} __packed;
struct hippi_hdr {
struct hippi_fp_hdr fp;
struct hippi_le_hdr le;
struct hippi_snap_hdr snap;
-} __attribute__ ((packed));
+} __packed;
#endif /* _LINUX_IF_HIPPI_H */
diff --git a/include/linux/if_link.h b/include/linux/if_link.h
index 85c812db5a3..2fc66dd783e 100644
--- a/include/linux/if_link.h
+++ b/include/linux/if_link.h
@@ -4,7 +4,7 @@
#include <linux/types.h>
#include <linux/netlink.h>
-/* The struct should be in sync with struct net_device_stats */
+/* This struct should be in sync with struct rtnl_link_stats64 */
struct rtnl_link_stats {
__u32 rx_packets; /* total packets received */
__u32 tx_packets; /* total packets transmitted */
@@ -37,6 +37,7 @@ struct rtnl_link_stats {
__u32 tx_compressed;
};
+/* The main device statistics structure */
struct rtnl_link_stats64 {
__u64 rx_packets; /* total packets received */
__u64 tx_packets; /* total packets transmitted */
@@ -233,7 +234,7 @@ enum macvlan_mode {
MACVLAN_MODE_BRIDGE = 4, /* talk to bridge ports directly */
};
-/* SR-IOV virtual function managment section */
+/* SR-IOV virtual function management section */
enum {
IFLA_VF_INFO_UNSPEC,
diff --git a/include/linux/if_macvlan.h b/include/linux/if_macvlan.h
index 1ffaeffeff7..35280b30229 100644
--- a/include/linux/if_macvlan.h
+++ b/include/linux/if_macvlan.h
@@ -6,6 +6,7 @@
#include <linux/netdevice.h>
#include <linux/netlink.h>
#include <net/netlink.h>
+#include <linux/u64_stats_sync.h>
#if defined(CONFIG_MACVTAP) || defined(CONFIG_MACVTAP_MODULE)
struct socket *macvtap_get_socket(struct file *);
@@ -27,14 +28,16 @@ struct macvtap_queue;
* struct macvlan_rx_stats - MACVLAN percpu rx stats
* @rx_packets: number of received packets
* @rx_bytes: number of received bytes
- * @multicast: number of received multicast packets
+ * @rx_multicast: number of received multicast packets
+ * @syncp: synchronization point for 64bit counters
* @rx_errors: number of errors
*/
struct macvlan_rx_stats {
- unsigned long rx_packets;
- unsigned long rx_bytes;
- unsigned long multicast;
- unsigned long rx_errors;
+ u64 rx_packets;
+ u64 rx_bytes;
+ u64 rx_multicast;
+ struct u64_stats_sync syncp;
+ unsigned long rx_errors;
};
struct macvlan_dev {
@@ -56,12 +59,14 @@ static inline void macvlan_count_rx(const struct macvlan_dev *vlan,
{
struct macvlan_rx_stats *rx_stats;
- rx_stats = per_cpu_ptr(vlan->rx_stats, smp_processor_id());
+ rx_stats = this_cpu_ptr(vlan->rx_stats);
if (likely(success)) {
+ u64_stats_update_begin(&rx_stats->syncp);
rx_stats->rx_packets++;;
rx_stats->rx_bytes += len;
if (multicast)
- rx_stats->multicast++;
+ rx_stats->rx_multicast++;
+ u64_stats_update_end(&rx_stats->syncp);
} else {
rx_stats->rx_errors++;
}
@@ -86,8 +91,4 @@ extern int macvlan_link_register(struct rtnl_link_ops *ops);
extern netdev_tx_t macvlan_start_xmit(struct sk_buff *skb,
struct net_device *dev);
-
-extern struct sk_buff *(*macvlan_handle_frame_hook)(struct macvlan_port *,
- struct sk_buff *);
-
#endif /* _LINUX_IF_MACVLAN_H */
diff --git a/include/linux/if_packet.h b/include/linux/if_packet.h
index 6ac23ef1801..72bfa5a034d 100644
--- a/include/linux/if_packet.h
+++ b/include/linux/if_packet.h
@@ -48,6 +48,7 @@ struct sockaddr_ll {
#define PACKET_LOSS 14
#define PACKET_VNET_HDR 15
#define PACKET_TX_TIMESTAMP 16
+#define PACKET_TIMESTAMP 17
struct tpacket_stats {
unsigned int tp_packets;
diff --git a/include/linux/if_pppox.h b/include/linux/if_pppox.h
index a6577af0c4e..1925e0c3f16 100644
--- a/include/linux/if_pppox.h
+++ b/include/linux/if_pppox.h
@@ -59,7 +59,7 @@ struct sockaddr_pppox {
union{
struct pppoe_addr pppoe;
}sa_addr;
-}__attribute__ ((packed));
+} __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
@@ -70,7 +70,7 @@ struct sockaddr_pppol2tp {
sa_family_t sa_family; /* address family, AF_PPPOX */
unsigned int sa_protocol; /* protocol identifier */
struct pppol2tp_addr pppol2tp;
-}__attribute__ ((packed));
+} __packed;
/* The L2TPv3 protocol changes tunnel and session ids from 16 to 32
* bits. So we need a different sockaddr structure.
@@ -79,7 +79,7 @@ struct sockaddr_pppol2tpv3 {
sa_family_t sa_family; /* address family, AF_PPPOX */
unsigned int sa_protocol; /* protocol identifier */
struct pppol2tpv3_addr pppol2tp;
-} __attribute__ ((packed));
+} __packed;
/*********************************************************************
*
@@ -129,7 +129,7 @@ struct pppoe_hdr {
__be16 sid;
__be16 length;
struct pppoe_tag tag[0];
-} __attribute__ ((packed));
+} __packed;
/* Length of entire PPPoE + PPP header */
#define PPPOE_SES_HLEN 8
diff --git a/include/linux/in.h b/include/linux/in.h
index 583c76f9c30..41d88a4689a 100644
--- a/include/linux/in.h
+++ b/include/linux/in.h
@@ -85,6 +85,7 @@ struct in_addr {
#define IP_RECVORIGDSTADDR IP_ORIGDSTADDR
#define IP_MINTTL 21
+#define IP_NODEFRAG 22
/* IP_MTU_DISCOVER values */
#define IP_PMTUDISC_DONT 0 /* Never send DF frames */
diff --git a/include/linux/input.h b/include/linux/input.h
index 6fcc9101bee..339d043ccb5 100644
--- a/include/linux/input.h
+++ b/include/linux/input.h
@@ -691,9 +691,12 @@ struct input_absinfo {
#define ABS_TILT_X 0x1a
#define ABS_TILT_Y 0x1b
#define ABS_TOOL_WIDTH 0x1c
+
#define ABS_VOLUME 0x20
+
#define ABS_MISC 0x28
+#define ABS_MT_SLOT 0x2f /* MT slot being modified */
#define ABS_MT_TOUCH_MAJOR 0x30 /* Major axis of touching ellipse */
#define ABS_MT_TOUCH_MINOR 0x31 /* Minor axis (omit if circular) */
#define ABS_MT_WIDTH_MAJOR 0x32 /* Major axis of approaching ellipse */
@@ -706,6 +709,12 @@ struct input_absinfo {
#define ABS_MT_TRACKING_ID 0x39 /* Unique ID of initiated contact */
#define ABS_MT_PRESSURE 0x3a /* Pressure on contact area */
+#ifdef __KERNEL__
+/* Implementation details, userspace should not care about these */
+#define ABS_MT_FIRST ABS_MT_TOUCH_MAJOR
+#define ABS_MT_LAST ABS_MT_PRESSURE
+#endif
+
#define ABS_MAX 0x3f
#define ABS_CNT (ABS_MAX+1)
@@ -1048,6 +1057,14 @@ struct ff_effect {
#include <linux/mod_devicetable.h>
/**
+ * struct input_mt_slot - represents the state of an input MT slot
+ * @abs: holds current values of ABS_MT axes for this slot
+ */
+struct input_mt_slot {
+ int abs[ABS_MT_LAST - ABS_MT_FIRST + 1];
+};
+
+/**
* struct input_dev - represents an input device
* @name: name of the device
* @phys: physical path to the device in the system hierarchy
@@ -1063,6 +1080,10 @@ struct ff_effect {
* @sndbit: bitmap of sound effects supported by the device
* @ffbit: bitmap of force feedback effects supported by the device
* @swbit: bitmap of switches present on the device
+ * @hint_events_per_packet: average number of events generated by the
+ * device in a packet (between EV_SYN/SYN_REPORT events). Used by
+ * event handlers to estimate size of the buffer needed to hold
+ * events.
* @keycodemax: size of keycode table
* @keycodesize: size of elements in keycode table
* @keycode: map of scancodes to keycodes for this device
@@ -1078,9 +1099,12 @@ struct ff_effect {
* @repeat_key: stores key code of the last key pressed; used to implement
* software autorepeat
* @timer: timer for software autorepeat
- * @sync: set to 1 when there were no new events since last EV_SYNC
* @abs: current values for reports from absolute axes
* @rep: current values for autorepeat parameters (delay, rate)
+ * @mt: pointer to array of struct input_mt_slot holding current values
+ * of tracked contacts
+ * @mtsize: number of MT slots the device uses
+ * @slot: MT slot currently being transmitted
* @key: reflects current state of device's keys/buttons
* @led: reflects current state of device's LEDs
* @snd: reflects current state of sound effects
@@ -1119,6 +1143,7 @@ struct ff_effect {
* last user closes the device
* @going_away: marks devices that are in a middle of unregistering and
* causes input_open_device*() fail with -ENODEV.
+ * @sync: set to %true when there were no new events since last EV_SYN
* @dev: driver model's view of this device
* @h_list: list of input handles associated with the device. When
* accessing the list dev->mutex must be held
@@ -1140,6 +1165,8 @@ struct input_dev {
unsigned long ffbit[BITS_TO_LONGS(FF_CNT)];
unsigned long swbit[BITS_TO_LONGS(SW_CNT)];
+ unsigned int hint_events_per_packet;
+
unsigned int keycodemax;
unsigned int keycodesize;
void *keycode;
@@ -1153,11 +1180,13 @@ struct input_dev {
unsigned int repeat_key;
struct timer_list timer;
- int sync;
-
int abs[ABS_CNT];
int rep[REP_MAX + 1];
+ struct input_mt_slot *mt;
+ int mtsize;
+ int slot;
+
unsigned long key[BITS_TO_LONGS(KEY_CNT)];
unsigned long led[BITS_TO_LONGS(LED_CNT)];
unsigned long snd[BITS_TO_LONGS(SND_CNT)];
@@ -1182,6 +1211,8 @@ struct input_dev {
unsigned int users;
bool going_away;
+ bool sync;
+
struct device dev;
struct list_head h_list;
@@ -1406,8 +1437,28 @@ static inline void input_mt_sync(struct input_dev *dev)
input_event(dev, EV_SYN, SYN_MT_REPORT, 0);
}
+static inline void input_mt_slot(struct input_dev *dev, int slot)
+{
+ input_event(dev, EV_ABS, ABS_MT_SLOT, slot);
+}
+
void input_set_capability(struct input_dev *dev, unsigned int type, unsigned int code);
+/**
+ * input_set_events_per_packet - tell handlers about the driver event rate
+ * @dev: the input device used by the driver
+ * @n_events: the average number of events between calls to input_sync()
+ *
+ * If the event rate sent from a device is unusually large, use this
+ * function to set the expected event rate. This will allow handlers
+ * to set up an appropriate buffer size for the event stream, in order
+ * to minimize information loss.
+ */
+static inline void input_set_events_per_packet(struct input_dev *dev, int n_events)
+{
+ dev->hint_events_per_packet = n_events;
+}
+
static inline void input_set_abs_params(struct input_dev *dev, int axis, int min, int max, int fuzz, int flat)
{
dev->absmin[axis] = min;
@@ -1485,5 +1536,8 @@ int input_ff_erase(struct input_dev *dev, int effect_id, struct file *file);
int input_ff_create_memless(struct input_dev *dev, void *data,
int (*play_effect)(struct input_dev *, void *, struct ff_effect *));
+int input_mt_create_slots(struct input_dev *dev, unsigned int num_slots);
+void input_mt_destroy_slots(struct input_dev *dev);
+
#endif
#endif
diff --git a/include/linux/input/adxl34x.h b/include/linux/input/adxl34x.h
new file mode 100644
index 00000000000..df00d998a44
--- /dev/null
+++ b/include/linux/input/adxl34x.h
@@ -0,0 +1,349 @@
+/*
+ * include/linux/input/adxl34x.h
+ *
+ * Digital Accelerometer characteristics are highly application specific
+ * and may vary between boards and models. The platform_data for the
+ * device's "struct device" holds this information.
+ *
+ * Copyright 2009 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#ifndef __LINUX_INPUT_ADXL34X_H__
+#define __LINUX_INPUT_ADXL34X_H__
+
+struct adxl34x_platform_data {
+
+ /*
+ * X,Y,Z Axis Offset:
+ * offer user offset adjustments in twoscompliment
+ * form with a scale factor of 15.6 mg/LSB (i.e. 0x7F = +2 g)
+ */
+
+ s8 x_axis_offset;
+ s8 y_axis_offset;
+ s8 z_axis_offset;
+
+ /*
+ * TAP_X/Y/Z Enable: Setting TAP_X, Y, or Z Enable enables X,
+ * Y, or Z participation in Tap detection. A '0' excludes the
+ * selected axis from participation in Tap detection.
+ * Setting the SUPPRESS bit suppresses Double Tap detection if
+ * acceleration greater than tap_threshold is present between
+ * taps.
+ */
+
+#define ADXL_SUPPRESS (1 << 3)
+#define ADXL_TAP_X_EN (1 << 2)
+#define ADXL_TAP_Y_EN (1 << 1)
+#define ADXL_TAP_Z_EN (1 << 0)
+
+ u8 tap_axis_control;
+
+ /*
+ * tap_threshold:
+ * holds the threshold value for tap detection/interrupts.
+ * The data format is unsigned. The scale factor is 62.5 mg/LSB
+ * (i.e. 0xFF = +16 g). A zero value may result in undesirable
+ * behavior if Tap/Double Tap is enabled.
+ */
+
+ u8 tap_threshold;
+
+ /*
+ * tap_duration:
+ * is an unsigned time value representing the maximum
+ * time that an event must be above the tap_threshold threshold
+ * to qualify as a tap event. The scale factor is 625 us/LSB. A zero
+ * value will prevent Tap/Double Tap functions from working.
+ */
+
+ u8 tap_duration;
+
+ /*
+ * tap_latency:
+ * is an unsigned time value representing the wait time
+ * from the detection of a tap event to the opening of the time
+ * window tap_window for a possible second tap event. The scale
+ * factor is 1.25 ms/LSB. A zero value will disable the Double Tap
+ * function.
+ */
+
+ u8 tap_latency;
+
+ /*
+ * tap_window:
+ * is an unsigned time value representing the amount
+ * of time after the expiration of tap_latency during which a second
+ * tap can begin. The scale factor is 1.25 ms/LSB. A zero value will
+ * disable the Double Tap function.
+ */
+
+ u8 tap_window;
+
+ /*
+ * act_axis_control:
+ * X/Y/Z Enable: A '1' enables X, Y, or Z participation in activity
+ * or inactivity detection. A '0' excludes the selected axis from
+ * participation. If all of the axes are excluded, the function is
+ * disabled.
+ * AC/DC: A '0' = DC coupled operation and a '1' = AC coupled
+ * operation. In DC coupled operation, the current acceleration is
+ * compared with activity_threshold and inactivity_threshold directly
+ * to determine whether activity or inactivity is detected. In AC
+ * coupled operation for activity detection, the acceleration value
+ * at the start of activity detection is taken as a reference value.
+ * New samples of acceleration are then compared to this
+ * reference value and if the magnitude of the difference exceeds
+ * activity_threshold the device will trigger an activity interrupt. In
+ * AC coupled operation for inactivity detection, a reference value
+ * is used again for comparison and is updated whenever the
+ * device exceeds the inactivity threshold. Once the reference
+ * value is selected, the device compares the magnitude of the
+ * difference between the reference value and the current
+ * acceleration with inactivity_threshold. If the difference is below
+ * inactivity_threshold for a total of inactivity_time, the device is
+ * considered inactive and the inactivity interrupt is triggered.
+ */
+
+#define ADXL_ACT_ACDC (1 << 7)
+#define ADXL_ACT_X_EN (1 << 6)
+#define ADXL_ACT_Y_EN (1 << 5)
+#define ADXL_ACT_Z_EN (1 << 4)
+#define ADXL_INACT_ACDC (1 << 3)
+#define ADXL_INACT_X_EN (1 << 2)
+#define ADXL_INACT_Y_EN (1 << 1)
+#define ADXL_INACT_Z_EN (1 << 0)
+
+ u8 act_axis_control;
+
+ /*
+ * activity_threshold:
+ * holds the threshold value for activity detection.
+ * The data format is unsigned. The scale factor is
+ * 62.5 mg/LSB. A zero value may result in undesirable behavior if
+ * Activity interrupt is enabled.
+ */
+
+ u8 activity_threshold;
+
+ /*
+ * inactivity_threshold:
+ * holds the threshold value for inactivity
+ * detection. The data format is unsigned. The scale
+ * factor is 62.5 mg/LSB. A zero value may result in undesirable
+ * behavior if Inactivity interrupt is enabled.
+ */
+
+ u8 inactivity_threshold;
+
+ /*
+ * inactivity_time:
+ * is an unsigned time value representing the
+ * amount of time that acceleration must be below the value in
+ * inactivity_threshold for inactivity to be declared. The scale factor
+ * is 1 second/LSB. Unlike the other interrupt functions, which
+ * operate on unfiltered data, the inactivity function operates on the
+ * filtered output data. At least one output sample must be
+ * generated for the inactivity interrupt to be triggered. This will
+ * result in the function appearing un-responsive if the
+ * inactivity_time register is set with a value less than the time
+ * constant of the Output Data Rate. A zero value will result in an
+ * interrupt when the output data is below inactivity_threshold.
+ */
+
+ u8 inactivity_time;
+
+ /*
+ * free_fall_threshold:
+ * holds the threshold value for Free-Fall detection.
+ * The data format is unsigned. The root-sum-square(RSS) value
+ * of all axes is calculated and compared to the value in
+ * free_fall_threshold to determine if a free fall event may be
+ * occurring. The scale factor is 62.5 mg/LSB. A zero value may
+ * result in undesirable behavior if Free-Fall interrupt is
+ * enabled. Values between 300 and 600 mg (0x05 to 0x09) are
+ * recommended.
+ */
+
+ u8 free_fall_threshold;
+
+ /*
+ * free_fall_time:
+ * is an unsigned time value representing the minimum
+ * time that the RSS value of all axes must be less than
+ * free_fall_threshold to generate a Free-Fall interrupt. The
+ * scale factor is 5 ms/LSB. A zero value may result in
+ * undesirable behavior if Free-Fall interrupt is enabled.
+ * Values between 100 to 350 ms (0x14 to 0x46) are recommended.
+ */
+
+ u8 free_fall_time;
+
+ /*
+ * data_rate:
+ * Selects device bandwidth and output data rate.
+ * RATE = 3200 Hz / (2^(15 - x)). Default value is 0x0A, or 100 Hz
+ * Output Data Rate. An Output Data Rate should be selected that
+ * is appropriate for the communication protocol and frequency
+ * selected. Selecting too high of an Output Data Rate with a low
+ * communication speed will result in samples being discarded.
+ */
+
+ u8 data_rate;
+
+ /*
+ * data_range:
+ * FULL_RES: When this bit is set with the device is
+ * in Full-Resolution Mode, where the output resolution increases
+ * with RANGE to maintain a 4 mg/LSB scale factor. When this
+ * bit is cleared the device is in 10-bit Mode and RANGE determine the
+ * maximum g-Range and scale factor.
+ */
+
+#define ADXL_FULL_RES (1 << 3)
+#define ADXL_RANGE_PM_2g 0
+#define ADXL_RANGE_PM_4g 1
+#define ADXL_RANGE_PM_8g 2
+#define ADXL_RANGE_PM_16g 3
+
+ u8 data_range;
+
+ /*
+ * low_power_mode:
+ * A '0' = Normal operation and a '1' = Reduced
+ * power operation with somewhat higher noise.
+ */
+
+ u8 low_power_mode;
+
+ /*
+ * power_mode:
+ * LINK: A '1' with both the activity and inactivity functions
+ * enabled will delay the start of the activity function until
+ * inactivity is detected. Once activity is detected, inactivity
+ * detection will begin and prevent the detection of activity. This
+ * bit serially links the activity and inactivity functions. When '0'
+ * the inactivity and activity functions are concurrent. Additional
+ * information can be found in the Application section under Link
+ * Mode.
+ * AUTO_SLEEP: A '1' sets the ADXL34x to switch to Sleep Mode
+ * when inactivity (acceleration has been below inactivity_threshold
+ * for at least inactivity_time) is detected and the LINK bit is set.
+ * A '0' disables automatic switching to Sleep Mode. See SLEEP
+ * for further description.
+ */
+
+#define ADXL_LINK (1 << 5)
+#define ADXL_AUTO_SLEEP (1 << 4)
+
+ u8 power_mode;
+
+ /*
+ * fifo_mode:
+ * BYPASS The FIFO is bypassed
+ * FIFO FIFO collects up to 32 values then stops collecting data
+ * STREAM FIFO holds the last 32 data values. Once full, the FIFO's
+ * oldest data is lost as it is replaced with newer data
+ *
+ * DEFAULT should be ADXL_FIFO_STREAM
+ */
+
+#define ADXL_FIFO_BYPASS 0
+#define ADXL_FIFO_FIFO 1
+#define ADXL_FIFO_STREAM 2
+
+ u8 fifo_mode;
+
+ /*
+ * watermark:
+ * The Watermark feature can be used to reduce the interrupt load
+ * of the system. The FIFO fills up to the value stored in watermark
+ * [1..32] and then generates an interrupt.
+ * A '0' disables the watermark feature.
+ */
+
+ u8 watermark;
+
+ u32 ev_type; /* EV_ABS or EV_REL */
+
+ u32 ev_code_x; /* ABS_X,Y,Z or REL_X,Y,Z */
+ u32 ev_code_y; /* ABS_X,Y,Z or REL_X,Y,Z */
+ u32 ev_code_z; /* ABS_X,Y,Z or REL_X,Y,Z */
+
+ /*
+ * A valid BTN or KEY Code; use tap_axis_control to disable
+ * event reporting
+ */
+
+ u32 ev_code_tap[3]; /* EV_KEY {X-Axis, Y-Axis, Z-Axis} */
+
+ /*
+ * A valid BTN or KEY Code for Free-Fall or Activity enables
+ * input event reporting. A '0' disables the Free-Fall or
+ * Activity reporting.
+ */
+
+ u32 ev_code_ff; /* EV_KEY */
+ u32 ev_code_act_inactivity; /* EV_KEY */
+
+ /*
+ * Use ADXL34x INT2 instead of INT1
+ */
+ u8 use_int2;
+
+ /*
+ * ADXL346 only ORIENTATION SENSING feature
+ * The orientation function of the ADXL346 reports both 2-D and
+ * 3-D orientation concurrently.
+ */
+
+#define ADXL_EN_ORIENTATION_2D 1
+#define ADXL_EN_ORIENTATION_3D 2
+#define ADXL_EN_ORIENTATION_2D_3D 3
+
+ u8 orientation_enable;
+
+ /*
+ * The width of the deadzone region between two or more
+ * orientation positions is determined by setting the Deadzone
+ * value. The deadzone region size can be specified with a
+ * resolution of 3.6deg. The deadzone angle represents the total
+ * angle where the orientation is considered invalid.
+ */
+
+#define ADXL_DEADZONE_ANGLE_0p0 0 /* !!!0.0 [deg] */
+#define ADXL_DEADZONE_ANGLE_3p6 1 /* 3.6 [deg] */
+#define ADXL_DEADZONE_ANGLE_7p2 2 /* 7.2 [deg] */
+#define ADXL_DEADZONE_ANGLE_10p8 3 /* 10.8 [deg] */
+#define ADXL_DEADZONE_ANGLE_14p4 4 /* 14.4 [deg] */
+#define ADXL_DEADZONE_ANGLE_18p0 5 /* 18.0 [deg] */
+#define ADXL_DEADZONE_ANGLE_21p6 6 /* 21.6 [deg] */
+#define ADXL_DEADZONE_ANGLE_25p2 7 /* 25.2 [deg] */
+
+ u8 deadzone_angle;
+
+ /*
+ * To eliminate most human motion such as walking or shaking,
+ * a Divisor value should be selected to effectively limit the
+ * orientation bandwidth. Set the depth of the filter used to
+ * low-pass filter the measured acceleration for stable
+ * orientation sensing
+ */
+
+#define ADXL_LP_FILTER_DIVISOR_2 0
+#define ADXL_LP_FILTER_DIVISOR_4 1
+#define ADXL_LP_FILTER_DIVISOR_8 2
+#define ADXL_LP_FILTER_DIVISOR_16 3
+#define ADXL_LP_FILTER_DIVISOR_32 4
+#define ADXL_LP_FILTER_DIVISOR_64 5
+#define ADXL_LP_FILTER_DIVISOR_128 6
+#define ADXL_LP_FILTER_DIVISOR_256 7
+
+ u8 divisor_length;
+
+ u32 ev_codes_orient_2d[4]; /* EV_KEY {+X, -X, +Y, -Y} */
+ u32 ev_codes_orient_3d[6]; /* EV_KEY {+Z, +Y, +X, -X, -Y, -Z} */
+};
+#endif
diff --git a/include/linux/input/cy8ctmg110_pdata.h b/include/linux/input/cy8ctmg110_pdata.h
new file mode 100644
index 00000000000..09522cb5991
--- /dev/null
+++ b/include/linux/input/cy8ctmg110_pdata.h
@@ -0,0 +1,10 @@
+#ifndef _LINUX_CY8CTMG110_PDATA_H
+#define _LINUX_CY8CTMG110_PDATA_H
+
+struct cy8ctmg110_pdata
+{
+ int reset_pin; /* Reset pin is wired to this GPIO (optional) */
+ int irq_pin; /* IRQ pin is wired to this GPIO */
+};
+
+#endif
diff --git a/include/linux/input/matrix_keypad.h b/include/linux/input/matrix_keypad.h
index c964cd7f436..80352ad6581 100644
--- a/include/linux/input/matrix_keypad.h
+++ b/include/linux/input/matrix_keypad.h
@@ -41,6 +41,9 @@ struct matrix_keymap_data {
* @col_scan_delay_us: delay, measured in microseconds, that is
* needed before we can keypad after activating column gpio
* @debounce_ms: debounce interval in milliseconds
+ * @clustered_irq: may be specified if interrupts of all row/column GPIOs
+ * are bundled to one single irq
+ * @clustered_irq_flags: flags that are needed for the clustered irq
* @active_low: gpio polarity
* @wakeup: controls whether the device should be set up as wakeup
* source
@@ -63,6 +66,9 @@ struct matrix_keypad_platform_data {
/* key debounce interval in milli-second */
unsigned int debounce_ms;
+ unsigned int clustered_irq;
+ unsigned int clustered_irq_flags;
+
bool active_low;
bool wakeup;
bool no_autorepeat;
diff --git a/include/linux/intel_pmic_gpio.h b/include/linux/intel_pmic_gpio.h
new file mode 100644
index 00000000000..920109a2919
--- /dev/null
+++ b/include/linux/intel_pmic_gpio.h
@@ -0,0 +1,15 @@
+#ifndef LINUX_INTEL_PMIC_H
+#define LINUX_INTEL_PMIC_H
+
+struct intel_pmic_gpio_platform_data {
+ /* the first IRQ of the chip */
+ unsigned irq_base;
+ /* number assigned to the first GPIO */
+ unsigned gpio_base;
+ /* sram address for gpiointr register, the langwell chip will map
+ * the PMIC spi GPIO expander's GPIOINTR register in sram.
+ */
+ unsigned gpiointr;
+};
+
+#endif
diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h
index c2331138ca1..a0384a4d1e6 100644
--- a/include/linux/interrupt.h
+++ b/include/linux/interrupt.h
@@ -53,16 +53,21 @@
* IRQF_ONESHOT - Interrupt is not reenabled after the hardirq handler finished.
* Used by threaded interrupts which need to keep the
* irq line disabled until the threaded handler has been run.
+ * IRQF_NO_SUSPEND - Do not disable this IRQ during suspend
+ *
*/
#define IRQF_DISABLED 0x00000020
#define IRQF_SAMPLE_RANDOM 0x00000040
#define IRQF_SHARED 0x00000080
#define IRQF_PROBE_SHARED 0x00000100
-#define IRQF_TIMER 0x00000200
+#define __IRQF_TIMER 0x00000200
#define IRQF_PERCPU 0x00000400
#define IRQF_NOBALANCING 0x00000800
#define IRQF_IRQPOLL 0x00001000
#define IRQF_ONESHOT 0x00002000
+#define IRQF_NO_SUSPEND 0x00004000
+
+#define IRQF_TIMER (__IRQF_TIMER | IRQF_NO_SUSPEND)
/*
* Bits used by threaded handlers:
diff --git a/include/linux/io-mapping.h b/include/linux/io-mapping.h
index 25085ddd955..e0ea40f6c51 100644
--- a/include/linux/io-mapping.h
+++ b/include/linux/io-mapping.h
@@ -79,7 +79,9 @@ io_mapping_free(struct io_mapping *mapping)
/* Atomic map/unmap */
static inline void *
-io_mapping_map_atomic_wc(struct io_mapping *mapping, unsigned long offset)
+io_mapping_map_atomic_wc(struct io_mapping *mapping,
+ unsigned long offset,
+ int slot)
{
resource_size_t phys_addr;
unsigned long pfn;
@@ -87,13 +89,13 @@ io_mapping_map_atomic_wc(struct io_mapping *mapping, unsigned long offset)
BUG_ON(offset >= mapping->size);
phys_addr = mapping->base + offset;
pfn = (unsigned long) (phys_addr >> PAGE_SHIFT);
- return iomap_atomic_prot_pfn(pfn, KM_USER0, mapping->prot);
+ return iomap_atomic_prot_pfn(pfn, slot, mapping->prot);
}
static inline void
-io_mapping_unmap_atomic(void *vaddr)
+io_mapping_unmap_atomic(void *vaddr, int slot)
{
- iounmap_atomic(vaddr, KM_USER0);
+ iounmap_atomic(vaddr, slot);
}
static inline void *
@@ -133,13 +135,15 @@ io_mapping_free(struct io_mapping *mapping)
/* Atomic map/unmap */
static inline void *
-io_mapping_map_atomic_wc(struct io_mapping *mapping, unsigned long offset)
+io_mapping_map_atomic_wc(struct io_mapping *mapping,
+ unsigned long offset,
+ int slot)
{
return ((char *) mapping) + offset;
}
static inline void
-io_mapping_unmap_atomic(void *vaddr)
+io_mapping_unmap_atomic(void *vaddr, int slot)
{
}
diff --git a/include/linux/io.h b/include/linux/io.h
index 6c7f0ba0d5f..7fd2d2138bf 100644
--- a/include/linux/io.h
+++ b/include/linux/io.h
@@ -29,10 +29,10 @@ void __iowrite64_copy(void __iomem *to, const void *from, size_t count);
#ifdef CONFIG_MMU
int ioremap_page_range(unsigned long addr, unsigned long end,
- unsigned long phys_addr, pgprot_t prot);
+ phys_addr_t phys_addr, pgprot_t prot);
#else
static inline int ioremap_page_range(unsigned long addr, unsigned long end,
- unsigned long phys_addr, pgprot_t prot)
+ phys_addr_t phys_addr, pgprot_t prot)
{
return 0;
}
diff --git a/include/linux/iommu.h b/include/linux/iommu.h
index be22ad83689..0a2ba409899 100644
--- a/include/linux/iommu.h
+++ b/include/linux/iommu.h
@@ -30,6 +30,7 @@ struct iommu_domain {
};
#define IOMMU_CAP_CACHE_COHERENCY 0x1
+#define IOMMU_CAP_INTR_REMAP 0x2 /* isolates device intrs */
struct iommu_ops {
int (*domain_init)(struct iommu_domain *domain);
diff --git a/include/linux/ip_vs.h b/include/linux/ip_vs.h
index dfc17036284..9708de265bb 100644
--- a/include/linux/ip_vs.h
+++ b/include/linux/ip_vs.h
@@ -19,6 +19,7 @@
*/
#define IP_VS_SVC_F_PERSISTENT 0x0001 /* persistent port */
#define IP_VS_SVC_F_HASHED 0x0002 /* hashed entry */
+#define IP_VS_SVC_F_ONEPACKET 0x0004 /* one-packet scheduling */
/*
* Destination Server Flags
@@ -85,6 +86,7 @@
#define IP_VS_CONN_F_SEQ_MASK 0x0600 /* in/out sequence mask */
#define IP_VS_CONN_F_NO_CPORT 0x0800 /* no client port set yet */
#define IP_VS_CONN_F_TEMPLATE 0x1000 /* template, not connection */
+#define IP_VS_CONN_F_ONE_PACKET 0x2000 /* forward only one packet */
#define IP_VS_SCHEDNAME_MAXLEN 16
#define IP_VS_IFNAME_MAXLEN 16
diff --git a/include/linux/ipv6.h b/include/linux/ipv6.h
index 99e1ab7e3ee..ab9e9e89e40 100644
--- a/include/linux/ipv6.h
+++ b/include/linux/ipv6.h
@@ -58,7 +58,7 @@ struct ipv6_opt_hdr {
/*
* TLV encoded option data follows.
*/
-} __attribute__ ((packed)); /* required for some archs */
+} __packed; /* required for some archs */
#define ipv6_destopt_hdr ipv6_opt_hdr
#define ipv6_hopopt_hdr ipv6_opt_hdr
@@ -99,7 +99,7 @@ struct ipv6_destopt_hao {
__u8 type;
__u8 length;
struct in6_addr addr;
-} __attribute__ ((__packed__));
+} __packed;
/*
* IPv6 fixed header
@@ -246,7 +246,7 @@ struct inet6_skb_parm {
__u16 srcrt;
__u16 dst1;
__u16 lastopt;
- __u32 nhoff;
+ __u16 nhoff;
__u16 flags;
#if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE)
__u16 dsthao;
diff --git a/include/linux/iscsi_boot_sysfs.h b/include/linux/iscsi_boot_sysfs.h
new file mode 100644
index 00000000000..f1e6c184f14
--- /dev/null
+++ b/include/linux/iscsi_boot_sysfs.h
@@ -0,0 +1,123 @@
+/*
+ * Export the iSCSI boot info to userland via sysfs.
+ *
+ * Copyright (C) 2010 Red Hat, Inc. All rights reserved.
+ * Copyright (C) 2010 Mike Christie
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License v2.0 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.
+ */
+#ifndef _ISCSI_BOOT_SYSFS_
+#define _ISCSI_BOOT_SYSFS_
+
+/*
+ * The text attributes names for each of the kobjects.
+*/
+enum iscsi_boot_eth_properties_enum {
+ ISCSI_BOOT_ETH_INDEX,
+ ISCSI_BOOT_ETH_FLAGS,
+ ISCSI_BOOT_ETH_IP_ADDR,
+ ISCSI_BOOT_ETH_SUBNET_MASK,
+ ISCSI_BOOT_ETH_ORIGIN,
+ ISCSI_BOOT_ETH_GATEWAY,
+ ISCSI_BOOT_ETH_PRIMARY_DNS,
+ ISCSI_BOOT_ETH_SECONDARY_DNS,
+ ISCSI_BOOT_ETH_DHCP,
+ ISCSI_BOOT_ETH_VLAN,
+ ISCSI_BOOT_ETH_MAC,
+ /* eth_pci_bdf - this is replaced by link to the device itself. */
+ ISCSI_BOOT_ETH_HOSTNAME,
+ ISCSI_BOOT_ETH_END_MARKER,
+};
+
+enum iscsi_boot_tgt_properties_enum {
+ ISCSI_BOOT_TGT_INDEX,
+ ISCSI_BOOT_TGT_FLAGS,
+ ISCSI_BOOT_TGT_IP_ADDR,
+ ISCSI_BOOT_TGT_PORT,
+ ISCSI_BOOT_TGT_LUN,
+ ISCSI_BOOT_TGT_CHAP_TYPE,
+ ISCSI_BOOT_TGT_NIC_ASSOC,
+ ISCSI_BOOT_TGT_NAME,
+ ISCSI_BOOT_TGT_CHAP_NAME,
+ ISCSI_BOOT_TGT_CHAP_SECRET,
+ ISCSI_BOOT_TGT_REV_CHAP_NAME,
+ ISCSI_BOOT_TGT_REV_CHAP_SECRET,
+ ISCSI_BOOT_TGT_END_MARKER,
+};
+
+enum iscsi_boot_initiator_properties_enum {
+ ISCSI_BOOT_INI_INDEX,
+ ISCSI_BOOT_INI_FLAGS,
+ ISCSI_BOOT_INI_ISNS_SERVER,
+ ISCSI_BOOT_INI_SLP_SERVER,
+ ISCSI_BOOT_INI_PRI_RADIUS_SERVER,
+ ISCSI_BOOT_INI_SEC_RADIUS_SERVER,
+ ISCSI_BOOT_INI_INITIATOR_NAME,
+ ISCSI_BOOT_INI_END_MARKER,
+};
+
+struct attribute_group;
+
+struct iscsi_boot_kobj {
+ struct kobject kobj;
+ struct attribute_group *attr_group;
+ struct list_head list;
+
+ /*
+ * Pointer to store driver specific info. If set this will
+ * be freed for the LLD when the kobj release function is called.
+ */
+ void *data;
+ /*
+ * Driver specific show function.
+ *
+ * The enum of the type. This can be any value of the above
+ * properties.
+ */
+ ssize_t (*show) (void *data, int type, char *buf);
+
+ /*
+ * Drivers specific visibility function.
+ * The function should return if they the attr should be readable
+ * writable or should not be shown.
+ *
+ * The enum of the type. This can be any value of the above
+ * properties.
+ */
+ mode_t (*is_visible) (void *data, int type);
+};
+
+struct iscsi_boot_kset {
+ struct list_head kobj_list;
+ struct kset *kset;
+};
+
+struct iscsi_boot_kobj *
+iscsi_boot_create_initiator(struct iscsi_boot_kset *boot_kset, int index,
+ void *data,
+ ssize_t (*show) (void *data, int type, char *buf),
+ mode_t (*is_visible) (void *data, int type));
+
+struct iscsi_boot_kobj *
+iscsi_boot_create_ethernet(struct iscsi_boot_kset *boot_kset, int index,
+ void *data,
+ ssize_t (*show) (void *data, int type, char *buf),
+ mode_t (*is_visible) (void *data, int type));
+struct iscsi_boot_kobj *
+iscsi_boot_create_target(struct iscsi_boot_kset *boot_kset, int index,
+ void *data,
+ ssize_t (*show) (void *data, int type, char *buf),
+ mode_t (*is_visible) (void *data, int type));
+
+struct iscsi_boot_kset *iscsi_boot_create_kset(const char *set_name);
+struct iscsi_boot_kset *iscsi_boot_create_host_kset(unsigned int hostno);
+void iscsi_boot_destroy_kset(struct iscsi_boot_kset *boot_kset);
+
+#endif
diff --git a/include/linux/iscsi_ibft.h b/include/linux/iscsi_ibft.h
index d2e4042f8f5..8ba7e5b9d62 100644
--- a/include/linux/iscsi_ibft.h
+++ b/include/linux/iscsi_ibft.h
@@ -21,21 +21,13 @@
#ifndef ISCSI_IBFT_H
#define ISCSI_IBFT_H
-struct ibft_table_header {
- char signature[4];
- u32 length;
- u8 revision;
- u8 checksum;
- char oem_id[6];
- char oem_table_id[8];
- char reserved[24];
-} __attribute__((__packed__));
+#include <acpi/acpi.h>
/*
* Logical location of iSCSI Boot Format Table.
* If the value is NULL there is no iBFT on the machine.
*/
-extern struct ibft_table_header *ibft_addr;
+extern struct acpi_table_ibft *ibft_addr;
/*
* Routine used to find and reserve the iSCSI Boot Format Table. The
diff --git a/include/linux/isdnif.h b/include/linux/isdnif.h
index b9b5a684ed6..b8c23f88dd5 100644
--- a/include/linux/isdnif.h
+++ b/include/linux/isdnif.h
@@ -317,7 +317,7 @@ typedef struct T30_s {
__u8 r_scantime;
__u8 r_id[FAXIDLEN];
__u8 r_code;
-} __attribute__((packed)) T30_s;
+} __packed T30_s;
#define ISDN_TTY_FAX_CONN_IN 0
#define ISDN_TTY_FAX_CONN_OUT 1
diff --git a/include/linux/jbd2.h b/include/linux/jbd2.h
index adf832dec3f..0b52924a0cb 100644
--- a/include/linux/jbd2.h
+++ b/include/linux/jbd2.h
@@ -601,13 +601,13 @@ struct transaction_s
* Number of outstanding updates running on this transaction
* [t_handle_lock]
*/
- int t_updates;
+ atomic_t t_updates;
/*
* Number of buffers reserved for use by all handles in this transaction
* handle but not yet modified. [t_handle_lock]
*/
- int t_outstanding_credits;
+ atomic_t t_outstanding_credits;
/*
* Forward and backward links for the circular list of all transactions
@@ -629,7 +629,7 @@ struct transaction_s
/*
* How many handles used this transaction? [t_handle_lock]
*/
- int t_handle_count;
+ atomic_t t_handle_count;
/*
* This transaction is being forced and some process is
@@ -764,7 +764,7 @@ struct journal_s
/*
* Protect the various scalars in the journal
*/
- spinlock_t j_state_lock;
+ rwlock_t j_state_lock;
/*
* Number of processes waiting to create a barrier lock [j_state_lock]
@@ -1082,7 +1082,9 @@ static inline handle_t *journal_current_handle(void)
*/
extern handle_t *jbd2_journal_start(journal_t *, int nblocks);
-extern int jbd2_journal_restart (handle_t *, int nblocks);
+extern handle_t *jbd2__journal_start(journal_t *, int nblocks, int gfp_mask);
+extern int jbd2_journal_restart(handle_t *, int nblocks);
+extern int jbd2__journal_restart(handle_t *, int nblocks, int gfp_mask);
extern int jbd2_journal_extend (handle_t *, int nblocks);
extern int jbd2_journal_get_write_access(handle_t *, struct buffer_head *);
extern int jbd2_journal_get_create_access (handle_t *, struct buffer_head *);
@@ -1257,8 +1259,8 @@ static inline int jbd_space_needed(journal_t *journal)
{
int nblocks = journal->j_max_transaction_buffers;
if (journal->j_committing_transaction)
- nblocks += journal->j_committing_transaction->
- t_outstanding_credits;
+ nblocks += atomic_read(&journal->j_committing_transaction->
+ t_outstanding_credits);
return nblocks;
}
diff --git a/include/linux/jffs2.h b/include/linux/jffs2.h
index 0874ab59ffe..edb9231f189 100644
--- a/include/linux/jffs2.h
+++ b/include/linux/jffs2.h
@@ -185,7 +185,7 @@ struct jffs2_raw_xref
jint32_t hdr_crc;
jint32_t ino; /* inode number */
jint32_t xid; /* XATTR identifier number */
- jint32_t xseqno; /* xref sequencial number */
+ jint32_t xseqno; /* xref sequential number */
jint32_t node_crc;
} __attribute__((packed));
diff --git a/include/linux/kdb.h b/include/linux/kdb.h
index ccb2b3ec0fe..ea6e5244ed3 100644
--- a/include/linux/kdb.h
+++ b/include/linux/kdb.h
@@ -114,4 +114,8 @@ enum {
KDB_INIT_EARLY,
KDB_INIT_FULL,
};
+
+extern int kdbgetintenv(const char *, int *);
+extern int kdb_set(int, const char **);
+
#endif /* !_KDB_H */
diff --git a/include/linux/kernel.h b/include/linux/kernel.h
index 8317ec4b9f3..7d5b10ff63e 100644
--- a/include/linux/kernel.h
+++ b/include/linux/kernel.h
@@ -171,6 +171,11 @@ static inline void might_fault(void)
}
#endif
+struct va_format {
+ const char *fmt;
+ va_list *va;
+};
+
extern struct atomic_notifier_head panic_notifier_list;
extern long (*panic_blink)(long time);
NORET_TYPE void panic(const char * fmt, ...)
@@ -247,6 +252,13 @@ extern struct pid *session_of_pgrp(struct pid *pgrp);
#define FW_WARN "[Firmware Warn]: "
#define FW_INFO "[Firmware Info]: "
+/*
+ * HW_ERR
+ * Add this to a message for hardware errors, so that user can report
+ * it to hardware vendor instead of LKML or software vendor.
+ */
+#define HW_ERR "[Hardware Error]: "
+
#ifdef CONFIG_PRINTK
asmlinkage int vprintk(const char *fmt, va_list args)
__attribute__ ((format (printf, 1, 0)));
@@ -508,9 +520,6 @@ extern void tracing_start(void);
extern void tracing_stop(void);
extern void ftrace_off_permanent(void);
-extern void
-ftrace_special(unsigned long arg1, unsigned long arg2, unsigned long arg3);
-
static inline void __attribute__ ((format (printf, 1, 2)))
____trace_printk_check_format(const char *fmt, ...)
{
@@ -586,8 +595,6 @@ __ftrace_vprintk(unsigned long ip, const char *fmt, va_list ap);
extern void ftrace_dump(enum ftrace_dump_mode oops_dump_mode);
#else
-static inline void
-ftrace_special(unsigned long arg1, unsigned long arg2, unsigned long arg3) { }
static inline int
trace_printk(const char *fmt, ...) __attribute__ ((format (printf, 1, 2)));
@@ -728,12 +735,6 @@ extern int do_sysinfo(struct sysinfo *info);
#endif /* __KERNEL__ */
-#ifndef __EXPORTED_HEADERS__
-#ifndef __KERNEL__
-#warning Attempt to use kernel headers from user space, see http://kernelnewbies.org/KernelHeaders
-#endif /* __KERNEL__ */
-#endif /* __EXPORTED_HEADERS__ */
-
#define SI_LOAD_SHIFT 16
struct sysinfo {
long uptime; /* Seconds since boot */
diff --git a/include/linux/kgdb.h b/include/linux/kgdb.h
index 9340f34d1bb..cc96f0f23e0 100644
--- a/include/linux/kgdb.h
+++ b/include/linux/kgdb.h
@@ -90,6 +90,19 @@ struct kgdb_bkpt {
enum kgdb_bpstate state;
};
+struct dbg_reg_def_t {
+ char *name;
+ int size;
+ int offset;
+};
+
+#ifndef DBG_MAX_REG_NUM
+#define DBG_MAX_REG_NUM 0
+#else
+extern struct dbg_reg_def_t dbg_reg_def[];
+extern char *dbg_get_reg(int regno, void *mem, struct pt_regs *regs);
+extern int dbg_set_reg(int regno, void *mem, struct pt_regs *regs);
+#endif
#ifndef KGDB_MAX_BREAKPOINTS
# define KGDB_MAX_BREAKPOINTS 1000
#endif
@@ -281,7 +294,7 @@ extern void kgdb_unregister_io_module(struct kgdb_io *local_kgdb_io_ops);
extern struct kgdb_io *dbg_io_ops;
extern int kgdb_hex2long(char **ptr, unsigned long *long_val);
-extern int kgdb_mem2hex(char *mem, char *buf, int count);
+extern char *kgdb_mem2hex(char *mem, char *buf, int count);
extern int kgdb_hex2mem(char *buf, char *mem, int count);
extern int kgdb_isremovedbreak(unsigned long addr);
diff --git a/include/linux/kmemtrace.h b/include/linux/kmemtrace.h
deleted file mode 100644
index b616d3930c3..00000000000
--- a/include/linux/kmemtrace.h
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * Copyright (C) 2008 Eduard - Gabriel Munteanu
- *
- * This file is released under GPL version 2.
- */
-
-#ifndef _LINUX_KMEMTRACE_H
-#define _LINUX_KMEMTRACE_H
-
-#ifdef __KERNEL__
-
-#include <trace/events/kmem.h>
-
-#ifdef CONFIG_KMEMTRACE
-extern void kmemtrace_init(void);
-#else
-static inline void kmemtrace_init(void)
-{
-}
-#endif
-
-#endif /* __KERNEL__ */
-
-#endif /* _LINUX_KMEMTRACE_H */
-
diff --git a/include/linux/ks8842.h b/include/linux/ks8842.h
index da0341b8ca0..14ba4452296 100644
--- a/include/linux/ks8842.h
+++ b/include/linux/ks8842.h
@@ -25,10 +25,14 @@
* struct ks8842_platform_data - Platform data of the KS8842 network driver
* @macaddr: The MAC address of the device, set to all 0:s to use the on in
* the chip.
+ * @rx_dma_channel: The DMA channel to use for RX, -1 for none.
+ * @tx_dma_channel: The DMA channel to use for TX, -1 for none.
*
*/
struct ks8842_platform_data {
u8 macaddr[ETH_ALEN];
+ int rx_dma_channel;
+ int tx_dma_channel;
};
#endif
diff --git a/include/linux/kthread.h b/include/linux/kthread.h
index aabc8a13ba7..685ea65eb80 100644
--- a/include/linux/kthread.h
+++ b/include/linux/kthread.h
@@ -30,8 +30,73 @@ struct task_struct *kthread_create(int (*threadfn)(void *data),
void kthread_bind(struct task_struct *k, unsigned int cpu);
int kthread_stop(struct task_struct *k);
int kthread_should_stop(void);
+void *kthread_data(struct task_struct *k);
int kthreadd(void *unused);
extern struct task_struct *kthreadd_task;
+/*
+ * Simple work processor based on kthread.
+ *
+ * This provides easier way to make use of kthreads. A kthread_work
+ * can be queued and flushed using queue/flush_kthread_work()
+ * respectively. Queued kthread_works are processed by a kthread
+ * running kthread_worker_fn().
+ *
+ * A kthread_work can't be freed while it is executing.
+ */
+struct kthread_work;
+typedef void (*kthread_work_func_t)(struct kthread_work *work);
+
+struct kthread_worker {
+ spinlock_t lock;
+ struct list_head work_list;
+ struct task_struct *task;
+};
+
+struct kthread_work {
+ struct list_head node;
+ kthread_work_func_t func;
+ wait_queue_head_t done;
+ atomic_t flushing;
+ int queue_seq;
+ int done_seq;
+};
+
+#define KTHREAD_WORKER_INIT(worker) { \
+ .lock = SPIN_LOCK_UNLOCKED, \
+ .work_list = LIST_HEAD_INIT((worker).work_list), \
+ }
+
+#define KTHREAD_WORK_INIT(work, fn) { \
+ .node = LIST_HEAD_INIT((work).node), \
+ .func = (fn), \
+ .done = __WAIT_QUEUE_HEAD_INITIALIZER((work).done), \
+ .flushing = ATOMIC_INIT(0), \
+ }
+
+#define DEFINE_KTHREAD_WORKER(worker) \
+ struct kthread_worker worker = KTHREAD_WORKER_INIT(worker)
+
+#define DEFINE_KTHREAD_WORK(work, fn) \
+ struct kthread_work work = KTHREAD_WORK_INIT(work, fn)
+
+static inline void init_kthread_worker(struct kthread_worker *worker)
+{
+ *worker = (struct kthread_worker)KTHREAD_WORKER_INIT(*worker);
+}
+
+static inline void init_kthread_work(struct kthread_work *work,
+ kthread_work_func_t fn)
+{
+ *work = (struct kthread_work)KTHREAD_WORK_INIT(*work, fn);
+}
+
+int kthread_worker_fn(void *worker_ptr);
+
+bool queue_kthread_work(struct kthread_worker *worker,
+ struct kthread_work *work);
+void flush_kthread_work(struct kthread_work *work);
+void flush_kthread_worker(struct kthread_worker *worker);
+
#endif /* _LINUX_KTHREAD_H */
diff --git a/include/linux/kvm.h b/include/linux/kvm.h
index 23ea0225390..636fc381c89 100644
--- a/include/linux/kvm.h
+++ b/include/linux/kvm.h
@@ -524,6 +524,12 @@ struct kvm_enable_cap {
#define KVM_CAP_PPC_OSI 52
#define KVM_CAP_PPC_UNSET_IRQ 53
#define KVM_CAP_ENABLE_CAP 54
+#ifdef __KVM_HAVE_XSAVE
+#define KVM_CAP_XSAVE 55
+#endif
+#ifdef __KVM_HAVE_XCRS
+#define KVM_CAP_XCRS 56
+#endif
#ifdef KVM_CAP_IRQ_ROUTING
@@ -613,6 +619,7 @@ struct kvm_clock_data {
*/
#define KVM_CREATE_VCPU _IO(KVMIO, 0x41)
#define KVM_GET_DIRTY_LOG _IOW(KVMIO, 0x42, struct kvm_dirty_log)
+/* KVM_SET_MEMORY_ALIAS is obsolete: */
#define KVM_SET_MEMORY_ALIAS _IOW(KVMIO, 0x43, struct kvm_memory_alias)
#define KVM_SET_NR_MMU_PAGES _IO(KVMIO, 0x44)
#define KVM_GET_NR_MMU_PAGES _IO(KVMIO, 0x45)
@@ -714,6 +721,12 @@ struct kvm_clock_data {
#define KVM_GET_DEBUGREGS _IOR(KVMIO, 0xa1, struct kvm_debugregs)
#define KVM_SET_DEBUGREGS _IOW(KVMIO, 0xa2, struct kvm_debugregs)
#define KVM_ENABLE_CAP _IOW(KVMIO, 0xa3, struct kvm_enable_cap)
+/* Available with KVM_CAP_XSAVE */
+#define KVM_GET_XSAVE _IOR(KVMIO, 0xa4, struct kvm_xsave)
+#define KVM_SET_XSAVE _IOW(KVMIO, 0xa5, struct kvm_xsave)
+/* Available with KVM_CAP_XCRS */
+#define KVM_GET_XCRS _IOR(KVMIO, 0xa6, struct kvm_xcrs)
+#define KVM_SET_XCRS _IOW(KVMIO, 0xa7, struct kvm_xcrs)
#define KVM_DEV_ASSIGN_ENABLE_IOMMU (1 << 0)
diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h
index 7cb116afa1c..c13cc48697a 100644
--- a/include/linux/kvm_host.h
+++ b/include/linux/kvm_host.h
@@ -81,13 +81,14 @@ struct kvm_vcpu {
int vcpu_id;
struct mutex mutex;
int cpu;
+ atomic_t guest_mode;
struct kvm_run *run;
unsigned long requests;
unsigned long guest_debug;
int srcu_idx;
int fpu_active;
- int guest_fpu_loaded;
+ int guest_fpu_loaded, guest_xcr0_loaded;
wait_queue_head_t wq;
int sigset_active;
sigset_t sigset;
@@ -123,6 +124,7 @@ struct kvm_memory_slot {
} *lpage_info[KVM_NR_PAGE_SIZES - 1];
unsigned long userspace_addr;
int user_alloc;
+ int id;
};
static inline unsigned long kvm_dirty_bitmap_bytes(struct kvm_memory_slot *memslot)
@@ -266,6 +268,8 @@ extern pfn_t bad_pfn;
int is_error_page(struct page *page);
int is_error_pfn(pfn_t pfn);
+int is_hwpoison_pfn(pfn_t pfn);
+int is_fault_pfn(pfn_t pfn);
int kvm_is_error_hva(unsigned long addr);
int kvm_set_memory_region(struct kvm *kvm,
struct kvm_userspace_memory_region *mem,
@@ -284,8 +288,6 @@ void kvm_arch_commit_memory_region(struct kvm *kvm,
int user_alloc);
void kvm_disable_largepages(void);
void kvm_arch_flush_shadow(struct kvm *kvm);
-gfn_t unalias_gfn(struct kvm *kvm, gfn_t gfn);
-gfn_t unalias_gfn_instantiation(struct kvm *kvm, gfn_t gfn);
struct page *gfn_to_page(struct kvm *kvm, gfn_t gfn);
unsigned long gfn_to_hva(struct kvm *kvm, gfn_t gfn);
@@ -445,7 +447,8 @@ void kvm_register_irq_mask_notifier(struct kvm *kvm, int irq,
struct kvm_irq_mask_notifier *kimn);
void kvm_unregister_irq_mask_notifier(struct kvm *kvm, int irq,
struct kvm_irq_mask_notifier *kimn);
-void kvm_fire_mask_notifiers(struct kvm *kvm, int irq, bool mask);
+void kvm_fire_mask_notifiers(struct kvm *kvm, unsigned irqchip, unsigned pin,
+ bool mask);
#ifdef __KVM_HAVE_IOAPIC
void kvm_get_intr_delivery_bitmask(struct kvm_ioapic *ioapic,
@@ -562,10 +565,6 @@ static inline int mmu_notifier_retry(struct kvm_vcpu *vcpu, unsigned long mmu_se
}
#endif
-#ifndef KVM_ARCH_HAS_UNALIAS_INSTANTIATION
-#define unalias_gfn_instantiation unalias_gfn
-#endif
-
#ifdef CONFIG_HAVE_KVM_IRQCHIP
#define KVM_MAX_IRQ_ROUTES 1024
@@ -628,5 +627,25 @@ static inline long kvm_vm_ioctl_assigned_device(struct kvm *kvm, unsigned ioctl,
#endif
+static inline void kvm_make_request(int req, struct kvm_vcpu *vcpu)
+{
+ set_bit(req, &vcpu->requests);
+}
+
+static inline bool kvm_make_check_request(int req, struct kvm_vcpu *vcpu)
+{
+ return test_and_set_bit(req, &vcpu->requests);
+}
+
+static inline bool kvm_check_request(int req, struct kvm_vcpu *vcpu)
+{
+ if (test_bit(req, &vcpu->requests)) {
+ clear_bit(req, &vcpu->requests);
+ return true;
+ } else {
+ return false;
+ }
+}
+
#endif
diff --git a/include/linux/kvm_types.h b/include/linux/kvm_types.h
index fb46efbeabe..7ac0d4eee43 100644
--- a/include/linux/kvm_types.h
+++ b/include/linux/kvm_types.h
@@ -32,11 +32,11 @@
typedef unsigned long gva_t;
typedef u64 gpa_t;
-typedef unsigned long gfn_t;
+typedef u64 gfn_t;
typedef unsigned long hva_t;
typedef u64 hpa_t;
-typedef unsigned long hfn_t;
+typedef u64 hfn_t;
typedef hfn_t pfn_t;
diff --git a/include/linux/libata.h b/include/linux/libata.h
index b85f3ff34d7..f010f18a0f8 100644
--- a/include/linux/libata.h
+++ b/include/linux/libata.h
@@ -751,6 +751,7 @@ struct ata_port {
struct ata_host *host;
struct device *dev;
+ struct mutex scsi_scan_mutex;
struct delayed_work hotplug_task;
struct work_struct scsi_rescan_task;
diff --git a/include/linux/lru_cache.h b/include/linux/lru_cache.h
index de48d167568..78fbf24f357 100644
--- a/include/linux/lru_cache.h
+++ b/include/linux/lru_cache.h
@@ -262,7 +262,7 @@ extern void lc_seq_dump_details(struct seq_file *seq, struct lru_cache *lc, char
* @lc: the lru cache to operate on
*
* Note that the reference counts and order on the active and lru lists may
- * still change. Returns true if we aquired the lock.
+ * still change. Returns true if we acquired the lock.
*/
static inline int lc_try_lock(struct lru_cache *lc)
{
diff --git a/include/linux/lsm_audit.h b/include/linux/lsm_audit.h
index 6907251d520..112a5503335 100644
--- a/include/linux/lsm_audit.h
+++ b/include/linux/lsm_audit.h
@@ -90,10 +90,42 @@ struct common_audit_data {
u32 requested;
u32 audited;
u32 denied;
+ /*
+ * auditdeny is a bit tricky and unintuitive. See the
+ * comments in avc.c for it's meaning and usage.
+ */
+ u32 auditdeny;
struct av_decision *avd;
int result;
} selinux_audit_data;
#endif
+#ifdef CONFIG_SECURITY_APPARMOR
+ struct {
+ int error;
+ int op;
+ int type;
+ void *profile;
+ const char *name;
+ const char *info;
+ union {
+ void *target;
+ struct {
+ long pos;
+ void *target;
+ } iface;
+ struct {
+ int rlim;
+ unsigned long max;
+ } rlim;
+ struct {
+ const char *target;
+ u32 request;
+ u32 denied;
+ uid_t ouid;
+ } fs;
+ };
+ } apparmor_audit_data;
+#endif
};
/* these callback will be implemented by a specific LSM */
void (*lsm_pre_audit)(struct audit_buffer *, void *);
diff --git a/include/linux/mISDNif.h b/include/linux/mISDNif.h
index 78c3bed1c3f..b5e7f220248 100644
--- a/include/linux/mISDNif.h
+++ b/include/linux/mISDNif.h
@@ -251,7 +251,7 @@
struct mISDNhead {
unsigned int prim;
unsigned int id;
-} __attribute__((packed));
+} __packed;
#define MISDN_HEADER_LEN sizeof(struct mISDNhead)
#define MAX_DATA_SIZE 2048
diff --git a/include/linux/marvell_phy.h b/include/linux/marvell_phy.h
index 2ed4fb8bbd5..d0f08018335 100644
--- a/include/linux/marvell_phy.h
+++ b/include/linux/marvell_phy.h
@@ -12,6 +12,7 @@
#define MARVELL_PHY_ID_88E1121R 0x01410cb0
#define MARVELL_PHY_ID_88E1145 0x01410cd0
#define MARVELL_PHY_ID_88E1240 0x01410e30
+#define MARVELL_PHY_ID_88EC048 0x01410e90
/* struct phy_device dev_flags definitions */
#define MARVELL_PHY_M1145_FLAGS_RESISTANCE 0x00000001
diff --git a/include/linux/mm.h b/include/linux/mm.h
index a2b48041b91..7a9ab7db197 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -1465,6 +1465,14 @@ extern int sysctl_memory_failure_recovery;
extern void shake_page(struct page *p, int access);
extern atomic_long_t mce_bad_pages;
extern int soft_offline_page(struct page *page, int flags);
+#ifdef CONFIG_MEMORY_FAILURE
+int is_hwpoison_address(unsigned long addr);
+#else
+static inline int is_hwpoison_address(unsigned long addr)
+{
+ return 0;
+}
+#endif
extern void dump_page(struct page *page);
diff --git a/include/linux/msi.h b/include/linux/msi.h
index 6991ab5b24d..91b05c17185 100644
--- a/include/linux/msi.h
+++ b/include/linux/msi.h
@@ -14,8 +14,10 @@ struct irq_desc;
extern void mask_msi_irq(unsigned int irq);
extern void unmask_msi_irq(unsigned int irq);
extern void read_msi_msg_desc(struct irq_desc *desc, struct msi_msg *msg);
+extern void get_cached_msi_msg_desc(struct irq_desc *desc, struct msi_msg *msg);
extern void write_msi_msg_desc(struct irq_desc *desc, struct msi_msg *msg);
extern void read_msi_msg(unsigned int irq, struct msi_msg *msg);
+extern void get_cached_msi_msg(unsigned int irq, struct msi_msg *msg);
extern void write_msi_msg(unsigned int irq, struct msi_msg *msg);
struct msi_desc {
diff --git a/include/linux/nbd.h b/include/linux/nbd.h
index 155719dab81..bb58854a806 100644
--- a/include/linux/nbd.h
+++ b/include/linux/nbd.h
@@ -88,7 +88,7 @@ struct nbd_request {
char handle[8];
__be64 from;
__be32 len;
-} __attribute__ ((packed));
+} __packed;
/*
* This is the reply packet that nbd-server sends back to the client after
diff --git a/include/linux/ncp.h b/include/linux/ncp.h
index 99f0adeeb3f..3ace8370e61 100644
--- a/include/linux/ncp.h
+++ b/include/linux/ncp.h
@@ -27,7 +27,7 @@ struct ncp_request_header {
__u8 conn_high;
__u8 function;
__u8 data[0];
-} __attribute__((packed));
+} __packed;
#define NCP_REPLY (0x3333)
#define NCP_WATCHDOG (0x3E3E)
@@ -42,7 +42,7 @@ struct ncp_reply_header {
__u8 completion_code;
__u8 connection_state;
__u8 data[0];
-} __attribute__((packed));
+} __packed;
#define NCP_VOLNAME_LEN (16)
#define NCP_NUMBER_OF_VOLUMES (256)
@@ -158,7 +158,7 @@ struct nw_info_struct {
#ifdef __KERNEL__
struct nw_nfs_info nfs;
#endif
-} __attribute__((packed));
+} __packed;
/* modify mask - use with MODIFY_DOS_INFO structure */
#define DM_ATTRIBUTES (cpu_to_le32(0x02))
@@ -190,12 +190,12 @@ struct nw_modify_dos_info {
__u16 inheritanceGrantMask;
__u16 inheritanceRevokeMask;
__u32 maximumSpace;
-} __attribute__((packed));
+} __packed;
struct nw_search_sequence {
__u8 volNumber;
__u32 dirBase;
__u32 sequence;
-} __attribute__((packed));
+} __packed;
#endif /* _LINUX_NCP_H */
diff --git a/include/linux/ncp_fs_sb.h b/include/linux/ncp_fs_sb.h
index 5ec9ca67168..8da05bc098c 100644
--- a/include/linux/ncp_fs_sb.h
+++ b/include/linux/ncp_fs_sb.h
@@ -104,13 +104,13 @@ struct ncp_server {
unsigned int state; /* STREAM only: receiver state */
struct {
- __u32 magic __attribute__((packed));
- __u32 len __attribute__((packed));
- __u16 type __attribute__((packed));
- __u16 p1 __attribute__((packed));
- __u16 p2 __attribute__((packed));
- __u16 p3 __attribute__((packed));
- __u16 type2 __attribute__((packed));
+ __u32 magic __packed;
+ __u32 len __packed;
+ __u16 type __packed;
+ __u16 p1 __packed;
+ __u16 p2 __packed;
+ __u16 p3 __packed;
+ __u16 type2 __packed;
} buf; /* STREAM only: temporary buffer */
unsigned char* ptr; /* STREAM only: pointer to data */
size_t len; /* STREAM only: length of data to receive */
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index b21e4054c12..46c36ffe20e 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -54,6 +54,7 @@
struct vlan_group;
struct netpoll_info;
+struct phy_device;
/* 802.11 specific */
struct wireless_dev;
/* source back-compat hooks */
@@ -65,6 +66,11 @@ struct wireless_dev;
#define HAVE_FREE_NETDEV /* free_netdev() */
#define HAVE_NETDEV_PRIV /* netdev_priv() */
+/* hardware address assignment types */
+#define NET_ADDR_PERM 0 /* address is permanent (default) */
+#define NET_ADDR_RANDOM 1 /* address is generated randomly */
+#define NET_ADDR_STOLEN 2 /* address is stolen from other device */
+
/* Backlog congestion levels */
#define NET_RX_SUCCESS 0 /* keep 'em coming, baby */
#define NET_RX_DROP 1 /* packet dropped */
@@ -159,45 +165,39 @@ static inline bool dev_xmit_complete(int rc)
#define MAX_HEADER (LL_MAX_HEADER + 48)
#endif
-#endif /* __KERNEL__ */
-
/*
- * Network device statistics. Akin to the 2.0 ether stats but
- * with byte counters.
+ * Old network device statistics. Fields are native words
+ * (unsigned long) so they can be read and written atomically.
*/
struct net_device_stats {
- unsigned long rx_packets; /* total packets received */
- unsigned long tx_packets; /* total packets transmitted */
- unsigned long rx_bytes; /* total bytes received */
- unsigned long tx_bytes; /* total bytes transmitted */
- unsigned long rx_errors; /* bad packets received */
- unsigned long tx_errors; /* packet transmit problems */
- unsigned long rx_dropped; /* no space in linux buffers */
- unsigned long tx_dropped; /* no space available in linux */
- unsigned long multicast; /* multicast packets received */
+ unsigned long rx_packets;
+ unsigned long tx_packets;
+ unsigned long rx_bytes;
+ unsigned long tx_bytes;
+ unsigned long rx_errors;
+ unsigned long tx_errors;
+ unsigned long rx_dropped;
+ unsigned long tx_dropped;
+ unsigned long multicast;
unsigned long collisions;
-
- /* detailed rx_errors: */
unsigned long rx_length_errors;
- unsigned long rx_over_errors; /* receiver ring buff overflow */
- unsigned long rx_crc_errors; /* recved pkt with crc error */
- unsigned long rx_frame_errors; /* recv'd frame alignment error */
- unsigned long rx_fifo_errors; /* recv'r fifo overrun */
- unsigned long rx_missed_errors; /* receiver missed packet */
-
- /* detailed tx_errors */
+ unsigned long rx_over_errors;
+ unsigned long rx_crc_errors;
+ unsigned long rx_frame_errors;
+ unsigned long rx_fifo_errors;
+ unsigned long rx_missed_errors;
unsigned long tx_aborted_errors;
unsigned long tx_carrier_errors;
unsigned long tx_fifo_errors;
unsigned long tx_heartbeat_errors;
unsigned long tx_window_errors;
-
- /* for cslip etc */
unsigned long rx_compressed;
unsigned long tx_compressed;
};
+#endif /* __KERNEL__ */
+
/* Media selection options. */
enum {
@@ -381,6 +381,8 @@ enum gro_result {
};
typedef enum gro_result gro_result_t;
+typedef struct sk_buff *rx_handler_func_t(struct sk_buff *skb);
+
extern void __napi_schedule(struct napi_struct *n);
static inline int napi_disable_pending(struct napi_struct *n)
@@ -504,9 +506,9 @@ struct netdev_queue {
* please use this field instead of dev->trans_start
*/
unsigned long trans_start;
- unsigned long tx_bytes;
- unsigned long tx_packets;
- unsigned long tx_dropped;
+ u64 tx_bytes;
+ u64 tx_packets;
+ u64 tx_dropped;
} ____cacheline_aligned_in_smp;
#ifdef CONFIG_RPS
@@ -660,10 +662,19 @@ struct netdev_rx_queue {
* Callback uses when the transmitter has not made any progress
* for dev->watchdog ticks.
*
+ * struct rtnl_link_stats64* (*ndo_get_stats64)(struct net_device *dev,
+ * struct rtnl_link_stats64 *storage);
* struct net_device_stats* (*ndo_get_stats)(struct net_device *dev);
* Called when a user wants to get the network device usage
- * statistics. If not defined, the counters in dev->stats will
- * be used.
+ * statistics. Drivers must do one of the following:
+ * 1. Define @ndo_get_stats64 to fill in a zero-initialised
+ * rtnl_link_stats64 structure passed by the caller.
+ * 2. Define @ndo_get_stats to update a net_device_stats structure
+ * (which should normally be dev->stats) and return a pointer to
+ * it. The structure may be changed asynchronously only if each
+ * field is written atomically.
+ * 3. Update dev->stats asynchronously and atomically, and define
+ * neither operation.
*
* void (*ndo_vlan_rx_register)(struct net_device *dev, struct vlan_group *grp);
* If device support VLAN receive accleration
@@ -718,6 +729,8 @@ struct net_device_ops {
struct neigh_parms *);
void (*ndo_tx_timeout) (struct net_device *dev);
+ struct rtnl_link_stats64* (*ndo_get_stats64)(struct net_device *dev,
+ struct rtnl_link_stats64 *storage);
struct net_device_stats* (*ndo_get_stats)(struct net_device *dev);
void (*ndo_vlan_rx_register)(struct net_device *dev,
@@ -728,6 +741,8 @@ struct net_device_ops {
unsigned short vid);
#ifdef CONFIG_NET_POLL_CONTROLLER
void (*ndo_poll_controller)(struct net_device *dev);
+ int (*ndo_netpoll_setup)(struct net_device *dev,
+ struct netpoll_info *info);
void (*ndo_netpoll_cleanup)(struct net_device *dev);
#endif
int (*ndo_set_vf_mac)(struct net_device *dev,
@@ -775,11 +790,11 @@ struct net_device {
/*
* This is the first field of the "visible" part of this structure
* (i.e. as seen by users in the "Space.c" file). It is the name
- * the interface.
+ * of the interface.
*/
char name[IFNAMSIZ];
- struct pm_qos_request_list *pm_qos_req;
+ struct pm_qos_request_list pm_qos_req;
/* device name hash chain */
struct hlist_node name_hlist;
@@ -847,7 +862,8 @@ struct net_device {
#define NETIF_F_FSO (SKB_GSO_FCOE << NETIF_F_GSO_SHIFT)
/* List of features with software fallbacks. */
-#define NETIF_F_GSO_SOFTWARE (NETIF_F_TSO | NETIF_F_TSO_ECN | NETIF_F_TSO6)
+#define NETIF_F_GSO_SOFTWARE (NETIF_F_TSO | NETIF_F_TSO_ECN | \
+ NETIF_F_TSO6 | NETIF_F_UFO)
#define NETIF_F_GEN_CSUM (NETIF_F_NO_CSUM | NETIF_F_HW_CSUM)
@@ -908,6 +924,7 @@ struct net_device {
/* Interface address info. */
unsigned char perm_addr[MAX_ADDR_LEN]; /* permanent hw address */
+ unsigned char addr_assign_type; /* hw address assignment type */
unsigned char addr_len; /* hardware address length */
unsigned short dev_id; /* for shared network cards */
@@ -957,6 +974,8 @@ struct net_device {
#endif
struct netdev_queue rx_queue;
+ rx_handler_func_t *rx_handler;
+ void *rx_handler_data;
struct netdev_queue *_tx ____cacheline_aligned_in_smp;
@@ -1024,10 +1043,6 @@ struct net_device {
/* mid-layer private */
void *ml_priv;
- /* bridge stuff */
- struct net_bridge_port *br_port;
- /* macvlan */
- struct macvlan_port *macvlan_port;
/* GARP */
struct garp_port *garp_port;
@@ -1057,6 +1072,9 @@ struct net_device {
#endif
/* n-tuple filter list attached to this device */
struct ethtool_rx_ntuple_list ethtool_ntuple_list;
+
+ /* phy device may attach itself for hardware timestamping */
+ struct phy_device *phydev;
};
#define to_net_dev(d) container_of(d, struct net_device, dev)
@@ -1087,11 +1105,7 @@ static inline void netdev_for_each_tx_queue(struct net_device *dev,
static inline
struct net *dev_net(const struct net_device *dev)
{
-#ifdef CONFIG_NET_NS
- return dev->nd_net;
-#else
- return &init_net;
-#endif
+ return read_pnet(&dev->nd_net);
}
static inline
@@ -1272,8 +1286,8 @@ extern void dev_add_pack(struct packet_type *pt);
extern void dev_remove_pack(struct packet_type *pt);
extern void __dev_remove_pack(struct packet_type *pt);
-extern struct net_device *dev_get_by_flags(struct net *net, unsigned short flags,
- unsigned short mask);
+extern struct net_device *dev_get_by_flags_rcu(struct net *net, unsigned short flags,
+ unsigned short mask);
extern struct net_device *dev_get_by_name(struct net *net, const char *name);
extern struct net_device *dev_get_by_name_rcu(struct net *net, const char *name);
extern struct net_device *__dev_get_by_name(struct net *net, const char *name);
@@ -1696,6 +1710,11 @@ static inline void napi_free_frags(struct napi_struct *napi)
napi->skb = NULL;
}
+extern int netdev_rx_handler_register(struct net_device *dev,
+ rx_handler_func_t *rx_handler,
+ void *rx_handler_data);
+extern void netdev_rx_handler_unregister(struct net_device *dev);
+
extern void netif_nit_deliver(struct sk_buff *skb);
extern int dev_valid_name(const char *name);
extern int dev_ioctl(struct net *net, unsigned int cmd, void __user *);
@@ -1775,6 +1794,8 @@ extern void netif_carrier_on(struct net_device *dev);
extern void netif_carrier_off(struct net_device *dev);
+extern void netif_notify_peers(struct net_device *dev);
+
/**
* netif_dormant_on - mark device as dormant.
* @dev: network device
@@ -2119,8 +2140,10 @@ extern void netdev_features_change(struct net_device *dev);
/* Load a device via the kmod */
extern void dev_load(struct net *net, const char *name);
extern void dev_mcast_init(void);
-extern const struct net_device_stats *dev_get_stats(struct net_device *dev);
-extern void dev_txq_stats_fold(const struct net_device *dev, struct net_device_stats *stats);
+extern struct rtnl_link_stats64 *dev_get_stats(struct net_device *dev,
+ struct rtnl_link_stats64 *storage);
+extern void dev_txq_stats_fold(const struct net_device *dev,
+ struct rtnl_link_stats64 *stats);
extern int netdev_max_backlog;
extern int netdev_tstamp_prequeue;
@@ -2230,25 +2253,23 @@ static inline const char *netdev_name(const struct net_device *dev)
return dev->name;
}
-#define netdev_printk(level, netdev, format, args...) \
- dev_printk(level, (netdev)->dev.parent, \
- "%s: " format, \
- netdev_name(netdev), ##args)
-
-#define netdev_emerg(dev, format, args...) \
- netdev_printk(KERN_EMERG, dev, format, ##args)
-#define netdev_alert(dev, format, args...) \
- netdev_printk(KERN_ALERT, dev, format, ##args)
-#define netdev_crit(dev, format, args...) \
- netdev_printk(KERN_CRIT, dev, format, ##args)
-#define netdev_err(dev, format, args...) \
- netdev_printk(KERN_ERR, dev, format, ##args)
-#define netdev_warn(dev, format, args...) \
- netdev_printk(KERN_WARNING, dev, format, ##args)
-#define netdev_notice(dev, format, args...) \
- netdev_printk(KERN_NOTICE, dev, format, ##args)
-#define netdev_info(dev, format, args...) \
- netdev_printk(KERN_INFO, dev, format, ##args)
+extern int netdev_printk(const char *level, const struct net_device *dev,
+ const char *format, ...)
+ __attribute__ ((format (printf, 3, 4)));
+extern int netdev_emerg(const struct net_device *dev, const char *format, ...)
+ __attribute__ ((format (printf, 2, 3)));
+extern int netdev_alert(const struct net_device *dev, const char *format, ...)
+ __attribute__ ((format (printf, 2, 3)));
+extern int netdev_crit(const struct net_device *dev, const char *format, ...)
+ __attribute__ ((format (printf, 2, 3)));
+extern int netdev_err(const struct net_device *dev, const char *format, ...)
+ __attribute__ ((format (printf, 2, 3)));
+extern int netdev_warn(const struct net_device *dev, const char *format, ...)
+ __attribute__ ((format (printf, 2, 3)));
+extern int netdev_notice(const struct net_device *dev, const char *format, ...)
+ __attribute__ ((format (printf, 2, 3)));
+extern int netdev_info(const struct net_device *dev, const char *format, ...)
+ __attribute__ ((format (printf, 2, 3)));
#if defined(DEBUG)
#define netdev_dbg(__dev, format, args...) \
@@ -2296,20 +2317,26 @@ do { \
netdev_printk(level, (dev), fmt, ##args); \
} while (0)
+#define netif_level(level, priv, type, dev, fmt, args...) \
+do { \
+ if (netif_msg_##type(priv)) \
+ netdev_##level(dev, fmt, ##args); \
+} while (0)
+
#define netif_emerg(priv, type, dev, fmt, args...) \
- netif_printk(priv, type, KERN_EMERG, dev, fmt, ##args)
+ netif_level(emerg, priv, type, dev, fmt, ##args)
#define netif_alert(priv, type, dev, fmt, args...) \
- netif_printk(priv, type, KERN_ALERT, dev, fmt, ##args)
+ netif_level(alert, priv, type, dev, fmt, ##args)
#define netif_crit(priv, type, dev, fmt, args...) \
- netif_printk(priv, type, KERN_CRIT, dev, fmt, ##args)
+ netif_level(crit, priv, type, dev, fmt, ##args)
#define netif_err(priv, type, dev, fmt, args...) \
- netif_printk(priv, type, KERN_ERR, dev, fmt, ##args)
+ netif_level(err, priv, type, dev, fmt, ##args)
#define netif_warn(priv, type, dev, fmt, args...) \
- netif_printk(priv, type, KERN_WARNING, dev, fmt, ##args)
+ netif_level(warn, priv, type, dev, fmt, ##args)
#define netif_notice(priv, type, dev, fmt, args...) \
- netif_printk(priv, type, KERN_NOTICE, dev, fmt, ##args)
+ netif_level(notice, priv, type, dev, fmt, ##args)
#define netif_info(priv, type, dev, fmt, args...) \
- netif_printk(priv, type, KERN_INFO, (dev), fmt, ##args)
+ netif_level(info, priv, type, dev, fmt, ##args)
#if defined(DEBUG)
#define netif_dbg(priv, type, dev, format, args...) \
diff --git a/include/linux/netfilter/Kbuild b/include/linux/netfilter/Kbuild
index 48767cd1645..edeeabdc150 100644
--- a/include/linux/netfilter/Kbuild
+++ b/include/linux/netfilter/Kbuild
@@ -3,11 +3,13 @@ header-y += nf_conntrack_tuple_common.h
header-y += nfnetlink_conntrack.h
header-y += nfnetlink_log.h
header-y += nfnetlink_queue.h
+header-y += xt_CHECKSUM.h
header-y += xt_CLASSIFY.h
header-y += xt_CONNMARK.h
header-y += xt_CONNSECMARK.h
header-y += xt_CT.h
header-y += xt_DSCP.h
+header-y += xt_IDLETIMER.h
header-y += xt_LED.h
header-y += xt_MARK.h
header-y += xt_NFLOG.h
@@ -18,17 +20,19 @@ header-y += xt_TCPMSS.h
header-y += xt_TCPOPTSTRIP.h
header-y += xt_TEE.h
header-y += xt_TPROXY.h
+header-y += xt_cluster.h
header-y += xt_comment.h
header-y += xt_connbytes.h
header-y += xt_connlimit.h
header-y += xt_connmark.h
header-y += xt_conntrack.h
-header-y += xt_cluster.h
+header-y += xt_cpu.h
header-y += xt_dccp.h
header-y += xt_dscp.h
header-y += xt_esp.h
header-y += xt_hashlimit.h
header-y += xt_iprange.h
+header-y += xt_ipvs.h
header-y += xt_helper.h
header-y += xt_length.h
header-y += xt_limit.h
diff --git a/include/linux/netfilter/nf_conntrack_common.h b/include/linux/netfilter/nf_conntrack_common.h
index 14e6d32002c..1afd18c855e 100644
--- a/include/linux/netfilter/nf_conntrack_common.h
+++ b/include/linux/netfilter/nf_conntrack_common.h
@@ -76,6 +76,10 @@ enum ip_conntrack_status {
/* Conntrack is a template */
IPS_TEMPLATE_BIT = 11,
IPS_TEMPLATE = (1 << IPS_TEMPLATE_BIT),
+
+ /* Conntrack is a fake untracked entry */
+ IPS_UNTRACKED_BIT = 12,
+ IPS_UNTRACKED = (1 << IPS_UNTRACKED_BIT),
};
/* Connection tracking event types */
diff --git a/include/linux/netfilter/nfnetlink_log.h b/include/linux/netfilter/nfnetlink_log.h
index d3bab7a2c9b..ea9b8d38052 100644
--- a/include/linux/netfilter/nfnetlink_log.h
+++ b/include/linux/netfilter/nfnetlink_log.h
@@ -89,6 +89,7 @@ enum nfulnl_attr_config {
#define NFULNL_COPY_NONE 0x00
#define NFULNL_COPY_META 0x01
#define NFULNL_COPY_PACKET 0x02
+/* 0xff is reserved, don't use it for new copy modes. */
#define NFULNL_CFG_F_SEQ 0x0001
#define NFULNL_CFG_F_SEQ_GLOBAL 0x0002
diff --git a/include/linux/netfilter/xt_CHECKSUM.h b/include/linux/netfilter/xt_CHECKSUM.h
new file mode 100644
index 00000000000..9a2e4661654
--- /dev/null
+++ b/include/linux/netfilter/xt_CHECKSUM.h
@@ -0,0 +1,20 @@
+/* Header file for iptables ipt_CHECKSUM target
+ *
+ * (C) 2002 by Harald Welte <laforge@gnumonks.org>
+ * (C) 2010 Red Hat Inc
+ * Author: Michael S. Tsirkin <mst@redhat.com>
+ *
+ * This software is distributed under GNU GPL v2, 1991
+*/
+#ifndef _XT_CHECKSUM_TARGET_H
+#define _XT_CHECKSUM_TARGET_H
+
+#include <linux/types.h>
+
+#define XT_CHECKSUM_OP_FILL 0x01 /* fill in checksum in IP header */
+
+struct xt_CHECKSUM_info {
+ __u8 operation; /* bitset of operations */
+};
+
+#endif /* _XT_CHECKSUM_TARGET_H */
diff --git a/include/linux/netfilter/xt_IDLETIMER.h b/include/linux/netfilter/xt_IDLETIMER.h
new file mode 100644
index 00000000000..3e1aa1be942
--- /dev/null
+++ b/include/linux/netfilter/xt_IDLETIMER.h
@@ -0,0 +1,45 @@
+/*
+ * linux/include/linux/netfilter/xt_IDLETIMER.h
+ *
+ * Header file for Xtables timer target module.
+ *
+ * Copyright (C) 2004, 2010 Nokia Corporation
+ * Written by Timo Teras <ext-timo.teras@nokia.com>
+ *
+ * Converted to x_tables and forward-ported to 2.6.34
+ * by Luciano Coelho <luciano.coelho@nokia.com>
+ *
+ * Contact: Luciano Coelho <luciano.coelho@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#ifndef _XT_IDLETIMER_H
+#define _XT_IDLETIMER_H
+
+#include <linux/types.h>
+
+#define MAX_IDLETIMER_LABEL_SIZE 28
+
+struct idletimer_tg_info {
+ __u32 timeout;
+
+ char label[MAX_IDLETIMER_LABEL_SIZE];
+
+ /* for kernel module internal use only */
+ struct idletimer_tg *timer __attribute((aligned(8)));
+};
+
+#endif
diff --git a/include/linux/netfilter/xt_cpu.h b/include/linux/netfilter/xt_cpu.h
new file mode 100644
index 00000000000..93c7f11d8f4
--- /dev/null
+++ b/include/linux/netfilter/xt_cpu.h
@@ -0,0 +1,11 @@
+#ifndef _XT_CPU_H
+#define _XT_CPU_H
+
+#include <linux/types.h>
+
+struct xt_cpu_info {
+ __u32 cpu;
+ __u32 invert;
+};
+
+#endif /*_XT_CPU_H*/
diff --git a/include/linux/netfilter/xt_ipvs.h b/include/linux/netfilter/xt_ipvs.h
new file mode 100644
index 00000000000..1167aeb7a34
--- /dev/null
+++ b/include/linux/netfilter/xt_ipvs.h
@@ -0,0 +1,27 @@
+#ifndef _XT_IPVS_H
+#define _XT_IPVS_H
+
+enum {
+ XT_IPVS_IPVS_PROPERTY = 1 << 0, /* all other options imply this one */
+ XT_IPVS_PROTO = 1 << 1,
+ XT_IPVS_VADDR = 1 << 2,
+ XT_IPVS_VPORT = 1 << 3,
+ XT_IPVS_DIR = 1 << 4,
+ XT_IPVS_METHOD = 1 << 5,
+ XT_IPVS_VPORTCTL = 1 << 6,
+ XT_IPVS_MASK = (1 << 7) - 1,
+ XT_IPVS_ONCE_MASK = XT_IPVS_MASK & ~XT_IPVS_IPVS_PROPERTY
+};
+
+struct xt_ipvs_mtinfo {
+ union nf_inet_addr vaddr, vmask;
+ __be16 vport;
+ __u8 l4proto;
+ __u8 fwd_method;
+ __be16 vportctl;
+
+ __u8 invert;
+ __u8 bitmask;
+};
+
+#endif /* _XT_IPVS_H */
diff --git a/include/linux/netfilter/xt_quota.h b/include/linux/netfilter/xt_quota.h
index 8dc89dfc136..b0d28c659ab 100644
--- a/include/linux/netfilter/xt_quota.h
+++ b/include/linux/netfilter/xt_quota.h
@@ -11,9 +11,9 @@ struct xt_quota_priv;
struct xt_quota_info {
u_int32_t flags;
u_int32_t pad;
+ aligned_u64 quota;
/* Used internally by the kernel */
- aligned_u64 quota;
struct xt_quota_priv *master;
};
diff --git a/include/linux/netfilter_ipv4/ipt_LOG.h b/include/linux/netfilter_ipv4/ipt_LOG.h
index 90fa6525ef9..dcdbadf9fd4 100644
--- a/include/linux/netfilter_ipv4/ipt_LOG.h
+++ b/include/linux/netfilter_ipv4/ipt_LOG.h
@@ -7,7 +7,8 @@
#define IPT_LOG_IPOPT 0x04 /* Log IP options */
#define IPT_LOG_UID 0x08 /* Log UID owning local socket */
#define IPT_LOG_NFLOG 0x10 /* Unsupported, don't reuse */
-#define IPT_LOG_MASK 0x1f
+#define IPT_LOG_MACDECODE 0x20 /* Decode MAC header */
+#define IPT_LOG_MASK 0x2f
struct ipt_log_info {
unsigned char level;
diff --git a/include/linux/netfilter_ipv6/ip6t_LOG.h b/include/linux/netfilter_ipv6/ip6t_LOG.h
index 0d0119b0458..9dd5579e02e 100644
--- a/include/linux/netfilter_ipv6/ip6t_LOG.h
+++ b/include/linux/netfilter_ipv6/ip6t_LOG.h
@@ -7,7 +7,8 @@
#define IP6T_LOG_IPOPT 0x04 /* Log IP options */
#define IP6T_LOG_UID 0x08 /* Log UID owning local socket */
#define IP6T_LOG_NFLOG 0x10 /* Unsupported, don't use */
-#define IP6T_LOG_MASK 0x1f
+#define IP6T_LOG_MACDECODE 0x20 /* Decode MAC header */
+#define IP6T_LOG_MASK 0x2f
struct ip6t_log_info {
unsigned char level;
diff --git a/include/linux/netpoll.h b/include/linux/netpoll.h
index e9e23121586..413742c92d1 100644
--- a/include/linux/netpoll.h
+++ b/include/linux/netpoll.h
@@ -46,9 +46,11 @@ void netpoll_poll(struct netpoll *np);
void netpoll_send_udp(struct netpoll *np, const char *msg, int len);
void netpoll_print_options(struct netpoll *np);
int netpoll_parse_options(struct netpoll *np, char *opt);
+int __netpoll_setup(struct netpoll *np);
int netpoll_setup(struct netpoll *np);
int netpoll_trap(void);
void netpoll_set_trap(int trap);
+void __netpoll_cleanup(struct netpoll *np);
void netpoll_cleanup(struct netpoll *np);
int __netpoll_rx(struct sk_buff *skb);
void netpoll_send_skb(struct netpoll *np, struct sk_buff *skb);
@@ -57,12 +59,15 @@ void netpoll_send_skb(struct netpoll *np, struct sk_buff *skb);
#ifdef CONFIG_NETPOLL
static inline bool netpoll_rx(struct sk_buff *skb)
{
- struct netpoll_info *npinfo = skb->dev->npinfo;
+ struct netpoll_info *npinfo;
unsigned long flags;
bool ret = false;
+ rcu_read_lock_bh();
+ npinfo = rcu_dereference_bh(skb->dev->npinfo);
+
if (!npinfo || (list_empty(&npinfo->rx_np) && !npinfo->rx_flags))
- return false;
+ goto out;
spin_lock_irqsave(&npinfo->rx_lock, flags);
/* check rx_flags again with the lock held */
@@ -70,12 +75,14 @@ static inline bool netpoll_rx(struct sk_buff *skb)
ret = true;
spin_unlock_irqrestore(&npinfo->rx_lock, flags);
+out:
+ rcu_read_unlock_bh();
return ret;
}
static inline int netpoll_rx_on(struct sk_buff *skb)
{
- struct netpoll_info *npinfo = skb->dev->npinfo;
+ struct netpoll_info *npinfo = rcu_dereference_bh(skb->dev->npinfo);
return npinfo && (!list_empty(&npinfo->rx_np) || npinfo->rx_flags);
}
@@ -91,7 +98,6 @@ static inline void *netpoll_poll_lock(struct napi_struct *napi)
{
struct net_device *dev = napi->dev;
- rcu_read_lock(); /* deal with race on ->npinfo */
if (dev && dev->npinfo) {
spin_lock(&napi->poll_lock);
napi->poll_owner = smp_processor_id();
@@ -108,7 +114,11 @@ static inline void netpoll_poll_unlock(void *have)
napi->poll_owner = -1;
spin_unlock(&napi->poll_lock);
}
- rcu_read_unlock();
+}
+
+static inline int netpoll_tx_running(struct net_device *dev)
+{
+ return irqs_disabled();
}
#else
@@ -134,6 +144,10 @@ static inline void netpoll_poll_unlock(void *have)
static inline void netpoll_netdev_init(struct net_device *dev)
{
}
+static inline int netpoll_tx_running(struct net_device *dev)
+{
+ return 0;
+}
#endif
#endif
diff --git a/include/linux/nfs4.h b/include/linux/nfs4.h
index 9b8299af374..07e40c62597 100644
--- a/include/linux/nfs4.h
+++ b/include/linux/nfs4.h
@@ -523,6 +523,7 @@ enum {
NFSPROC4_CLNT_GETACL,
NFSPROC4_CLNT_SETACL,
NFSPROC4_CLNT_FS_LOCATIONS,
+ NFSPROC4_CLNT_RELEASE_LOCKOWNER,
/* nfs41 */
NFSPROC4_CLNT_EXCHANGE_ID,
diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h
index bad4d121b16..508f8cf6da3 100644
--- a/include/linux/nfs_fs.h
+++ b/include/linux/nfs_fs.h
@@ -72,13 +72,20 @@ struct nfs_access_entry {
int mask;
};
+struct nfs_lock_context {
+ atomic_t count;
+ struct list_head list;
+ struct nfs_open_context *open_context;
+ fl_owner_t lockowner;
+ pid_t pid;
+};
+
struct nfs4_state;
struct nfs_open_context {
- atomic_t count;
+ struct nfs_lock_context lock_context;
struct path path;
struct rpc_cred *cred;
struct nfs4_state *state;
- fl_owner_t lockowner;
fmode_t mode;
unsigned long flags;
@@ -353,6 +360,8 @@ extern void nfs_setattr_update_inode(struct inode *inode, struct iattr *attr);
extern struct nfs_open_context *get_nfs_open_context(struct nfs_open_context *ctx);
extern void put_nfs_open_context(struct nfs_open_context *ctx);
extern struct nfs_open_context *nfs_find_open_context(struct inode *inode, struct rpc_cred *cred, fmode_t mode);
+extern struct nfs_lock_context *nfs_get_lock_context(struct nfs_open_context *ctx);
+extern void nfs_put_lock_context(struct nfs_lock_context *l_ctx);
extern u64 nfs_compat_user_ino64(u64 fileid);
extern void nfs_fattr_init(struct nfs_fattr *fattr);
diff --git a/include/linux/nfs_fs_sb.h b/include/linux/nfs_fs_sb.h
index d6e10a4c06e..c82ee7cd628 100644
--- a/include/linux/nfs_fs_sb.h
+++ b/include/linux/nfs_fs_sb.h
@@ -15,6 +15,7 @@ struct nlm_host;
struct nfs4_sequence_args;
struct nfs4_sequence_res;
struct nfs_server;
+struct nfs4_minor_version_ops;
/*
* The nfs_client identifies our client state to the server.
@@ -70,11 +71,7 @@ struct nfs_client {
*/
char cl_ipaddr[48];
unsigned char cl_id_uniquifier;
- int (* cl_call_sync)(struct nfs_server *server,
- struct rpc_message *msg,
- struct nfs4_sequence_args *args,
- struct nfs4_sequence_res *res,
- int cache_reply);
+ const struct nfs4_minor_version_ops *cl_mvops;
#endif /* CONFIG_NFS_V4 */
#ifdef CONFIG_NFS_V4_1
diff --git a/include/linux/nfs_mount.h b/include/linux/nfs_mount.h
index 4499016e6d0..5d59ae861aa 100644
--- a/include/linux/nfs_mount.h
+++ b/include/linux/nfs_mount.h
@@ -69,5 +69,6 @@ struct nfs_mount_data {
#define NFS_MOUNT_LOOKUP_CACHE_NONEG 0x10000
#define NFS_MOUNT_LOOKUP_CACHE_NONE 0x20000
#define NFS_MOUNT_NORESVPORT 0x40000
+#define NFS_MOUNT_LEGACY_INTERFACE 0x80000
#endif
diff --git a/include/linux/nfs_page.h b/include/linux/nfs_page.h
index 3c60685d972..f8b60e7f4c4 100644
--- a/include/linux/nfs_page.h
+++ b/include/linux/nfs_page.h
@@ -39,6 +39,7 @@ struct nfs_page {
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 */
+ struct nfs_lock_context *wb_lock_context; /* lock context info */
atomic_t wb_complete; /* i/os we're waiting for */
pgoff_t wb_index; /* Offset >> PAGE_CACHE_SHIFT */
unsigned int wb_offset, /* Offset & ~PAGE_CACHE_MASK */
diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h
index 51914d7d6cc..fc461926c41 100644
--- a/include/linux/nfs_xdr.h
+++ b/include/linux/nfs_xdr.h
@@ -196,8 +196,10 @@ struct nfs_openargs {
__u64 clientid;
__u64 id;
union {
- struct iattr * attrs; /* UNCHECKED, GUARDED */
- nfs4_verifier verifier; /* EXCLUSIVE */
+ struct {
+ struct iattr * attrs; /* UNCHECKED, GUARDED */
+ nfs4_verifier verifier; /* EXCLUSIVE */
+ };
nfs4_stateid delegation; /* CLAIM_DELEGATE_CUR */
fmode_t delegation_type; /* CLAIM_PREVIOUS */
} u;
@@ -313,6 +315,10 @@ struct nfs_lockt_res {
struct nfs4_sequence_res seq_res;
};
+struct nfs_release_lockowner_args {
+ struct nfs_lowner lock_owner;
+};
+
struct nfs4_delegreturnargs {
const struct nfs_fh *fhandle;
const nfs4_stateid *stateid;
@@ -332,6 +338,7 @@ struct nfs4_delegreturnres {
struct nfs_readargs {
struct nfs_fh * fh;
struct nfs_open_context *context;
+ struct nfs_lock_context *lock_context;
__u64 offset;
__u32 count;
unsigned int pgbase;
@@ -352,6 +359,7 @@ struct nfs_readres {
struct nfs_writeargs {
struct nfs_fh * fh;
struct nfs_open_context *context;
+ struct nfs_lock_context *lock_context;
__u64 offset;
__u32 count;
enum nfs3_stable_how stable;
diff --git a/include/linux/nilfs2_fs.h b/include/linux/nilfs2_fs.h
index 8c2c6116e78..f5487b6f91e 100644
--- a/include/linux/nilfs2_fs.h
+++ b/include/linux/nilfs2_fs.h
@@ -160,7 +160,7 @@ struct nilfs_super_root {
* struct nilfs_super_block - structure of super block on disk
*/
struct nilfs_super_block {
- __le32 s_rev_level; /* Revision level */
+/*00*/ __le32 s_rev_level; /* Revision level */
__le16 s_minor_rev_level; /* minor revision level */
__le16 s_magic; /* Magic signature */
@@ -169,50 +169,53 @@ struct nilfs_super_block {
is excluded. */
__le16 s_flags; /* flags */
__le32 s_crc_seed; /* Seed value of CRC calculation */
- __le32 s_sum; /* Check sum of super block */
+/*10*/ __le32 s_sum; /* Check sum of super block */
__le32 s_log_block_size; /* Block size represented as follows
blocksize =
1 << (s_log_block_size + 10) */
__le64 s_nsegments; /* Number of segments in filesystem */
- __le64 s_dev_size; /* block device size in bytes */
+/*20*/ __le64 s_dev_size; /* block device size in bytes */
__le64 s_first_data_block; /* 1st seg disk block number */
- __le32 s_blocks_per_segment; /* number of blocks per full segment */
+/*30*/ __le32 s_blocks_per_segment; /* number of blocks per full segment */
__le32 s_r_segments_percentage; /* Reserved segments percentage */
__le64 s_last_cno; /* Last checkpoint number */
- __le64 s_last_pseg; /* disk block addr pseg written last */
+/*40*/ __le64 s_last_pseg; /* disk block addr pseg written last */
__le64 s_last_seq; /* seq. number of seg written last */
- __le64 s_free_blocks_count; /* Free blocks count */
+/*50*/ __le64 s_free_blocks_count; /* Free blocks count */
__le64 s_ctime; /* Creation time (execution time of
newfs) */
- __le64 s_mtime; /* Mount time */
+/*60*/ __le64 s_mtime; /* Mount time */
__le64 s_wtime; /* Write time */
- __le16 s_mnt_count; /* Mount count */
+/*70*/ __le16 s_mnt_count; /* Mount count */
__le16 s_max_mnt_count; /* Maximal mount count */
__le16 s_state; /* File system state */
__le16 s_errors; /* Behaviour when detecting errors */
__le64 s_lastcheck; /* time of last check */
- __le32 s_checkinterval; /* max. time between checks */
+/*80*/ __le32 s_checkinterval; /* max. time between checks */
__le32 s_creator_os; /* OS */
__le16 s_def_resuid; /* Default uid for reserved blocks */
__le16 s_def_resgid; /* Default gid for reserved blocks */
__le32 s_first_ino; /* First non-reserved inode */
- __le16 s_inode_size; /* Size of an inode */
+/*90*/ __le16 s_inode_size; /* Size of an inode */
__le16 s_dat_entry_size; /* Size of a dat entry */
__le16 s_checkpoint_size; /* Size of a checkpoint */
__le16 s_segment_usage_size; /* Size of a segment usage */
- __u8 s_uuid[16]; /* 128-bit uuid for volume */
- char s_volume_name[80]; /* volume name */
+/*98*/ __u8 s_uuid[16]; /* 128-bit uuid for volume */
+/*A8*/ char s_volume_name[80]; /* volume name */
- __le32 s_c_interval; /* Commit interval of segment */
+/*F8*/ __le32 s_c_interval; /* Commit interval of segment */
__le32 s_c_block_max; /* Threshold of data amount for
the segment construction */
- __u32 s_reserved[192]; /* padding to the end of the block */
+/*100*/ __le64 s_feature_compat; /* Compatible feature set */
+ __le64 s_feature_compat_ro; /* Read-only compatible feature set */
+ __le64 s_feature_incompat; /* Incompatible feature set */
+ __u32 s_reserved[186]; /* padding to the end of the block */
};
/*
@@ -228,6 +231,16 @@ struct nilfs_super_block {
#define NILFS_MINOR_REV 0 /* minor revision */
/*
+ * Feature set definitions
+ *
+ * If there is a bit set in the incompatible feature set that the kernel
+ * doesn't know about, it should refuse to mount the filesystem.
+ */
+#define NILFS_FEATURE_COMPAT_SUPP 0ULL
+#define NILFS_FEATURE_COMPAT_RO_SUPP 0ULL
+#define NILFS_FEATURE_INCOMPAT_SUPP 0ULL
+
+/*
* Bytes count of super_block for CRC-calculation
*/
#define NILFS_SB_BYTES \
@@ -274,6 +287,12 @@ struct nilfs_super_block {
#define NILFS_NAME_LEN 255
/*
+ * Block size limitations
+ */
+#define NILFS_MIN_BLOCK_SIZE 1024
+#define NILFS_MAX_BLOCK_SIZE 65536
+
+/*
* The new version of the directory entry. Since V0 structures are
* stored in intel byte order, and the name_len field could never be
* bigger than 255 chars, it's safe to reclaim the extra byte for the
@@ -313,7 +332,25 @@ enum {
#define NILFS_DIR_ROUND (NILFS_DIR_PAD - 1)
#define NILFS_DIR_REC_LEN(name_len) (((name_len) + 12 + NILFS_DIR_ROUND) & \
~NILFS_DIR_ROUND)
+#define NILFS_MAX_REC_LEN ((1<<16)-1)
+static inline unsigned nilfs_rec_len_from_disk(__le16 dlen)
+{
+ unsigned len = le16_to_cpu(dlen);
+
+ if (len == NILFS_MAX_REC_LEN)
+ return 1 << 16;
+ return len;
+}
+
+static inline __le16 nilfs_rec_len_to_disk(unsigned len)
+{
+ if (len == (1 << 16))
+ return cpu_to_le16(NILFS_MAX_REC_LEN);
+ else if (len > (1 << 16))
+ BUG();
+ return cpu_to_le16(len);
+}
/**
* struct nilfs_finfo - file information
diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h
index b7c77f9712f..2c870168733 100644
--- a/include/linux/nl80211.h
+++ b/include/linux/nl80211.h
@@ -132,7 +132,7 @@
* %NL80211_ATTR_REG_RULE_POWER_MAX_ANT_GAIN and
* %NL80211_ATTR_REG_RULE_POWER_MAX_EIRP.
* @NL80211_CMD_REQ_SET_REG: ask the wireless core to set the regulatory domain
- * to the the specified ISO/IEC 3166-1 alpha2 country code. The core will
+ * to the specified ISO/IEC 3166-1 alpha2 country code. The core will
* store this as a valid request and then query userspace for it.
*
* @NL80211_CMD_GET_MESH_PARAMS: Get mesh networking properties for the
@@ -725,6 +725,12 @@ enum nl80211_commands {
* @NL80211_ATTR_AP_ISOLATE: (AP mode) Do not forward traffic between stations
* connected to this BSS.
*
+ * @NL80211_ATTR_WIPHY_TX_POWER_SETTING: Transmit power setting type. See
+ * &enum nl80211_tx_power_setting for possible values.
+ * @NL80211_ATTR_WIPHY_TX_POWER_LEVEL: Transmit power level in signed mBm units.
+ * This is used in association with @NL80211_ATTR_WIPHY_TX_POWER_SETTING
+ * for non-automatic settings.
+ *
* @NL80211_ATTR_MAX: highest attribute number currently defined
* @__NL80211_ATTR_AFTER_LAST: internal use
*/
@@ -882,6 +888,9 @@ enum nl80211_attrs {
NL80211_ATTR_AP_ISOLATE,
+ NL80211_ATTR_WIPHY_TX_POWER_SETTING,
+ NL80211_ATTR_WIPHY_TX_POWER_LEVEL,
+
/* add attributes here, update the policy in nl80211.c */
__NL80211_ATTR_AFTER_LAST,
@@ -1659,4 +1668,17 @@ enum nl80211_cqm_rssi_threshold_event {
NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH,
};
+
+/**
+ * enum nl80211_tx_power_setting - TX power adjustment
+ * @NL80211_TX_POWER_AUTOMATIC: automatically determine transmit power
+ * @NL80211_TX_POWER_LIMITED: limit TX power by the mBm parameter
+ * @NL80211_TX_POWER_FIXED: fix TX power to the mBm parameter
+ */
+enum nl80211_tx_power_setting {
+ NL80211_TX_POWER_AUTOMATIC,
+ NL80211_TX_POWER_LIMITED,
+ NL80211_TX_POWER_FIXED,
+};
+
#endif /* __LINUX_NL80211_H */
diff --git a/include/linux/nmi.h b/include/linux/nmi.h
index b752e807add..06aab5eee13 100644
--- a/include/linux/nmi.h
+++ b/include/linux/nmi.h
@@ -20,10 +20,14 @@ extern void touch_nmi_watchdog(void);
extern void acpi_nmi_disable(void);
extern void acpi_nmi_enable(void);
#else
+#ifndef CONFIG_HARDLOCKUP_DETECTOR
static inline void touch_nmi_watchdog(void)
{
touch_softlockup_watchdog();
}
+#else
+extern void touch_nmi_watchdog(void);
+#endif
static inline void acpi_nmi_disable(void) { }
static inline void acpi_nmi_enable(void) { }
#endif
@@ -47,4 +51,13 @@ static inline bool trigger_all_cpu_backtrace(void)
}
#endif
+#ifdef CONFIG_LOCKUP_DETECTOR
+int hw_nmi_is_cpu_stuck(struct pt_regs *);
+u64 hw_nmi_get_sample_period(void);
+extern int watchdog_enabled;
+struct ctl_table;
+extern int proc_dowatchdog_enabled(struct ctl_table *, int ,
+ void __user *, size_t *, loff_t *);
+#endif
+
#endif
diff --git a/include/linux/notifier.h b/include/linux/notifier.h
index 540703b555c..b2f1a4d8355 100644
--- a/include/linux/notifier.h
+++ b/include/linux/notifier.h
@@ -210,6 +210,7 @@ static inline int notifier_to_errno(int ret)
#define NETDEV_POST_INIT 0x0010
#define NETDEV_UNREGISTER_BATCH 0x0011
#define NETDEV_BONDING_DESLAVE 0x0012
+#define NETDEV_NOTIFY_PEERS 0x0013
#define SYS_DOWN 0x0001 /* Notify of system down */
#define SYS_RESTART SYS_DOWN
diff --git a/include/linux/of.h b/include/linux/of.h
index a367e19bb3a..cad7cf0ab27 100644
--- a/include/linux/of.h
+++ b/include/linux/of.h
@@ -70,6 +70,11 @@ extern struct device_node *allnodes;
extern struct device_node *of_chosen;
extern rwlock_t devtree_lock;
+static inline bool of_node_is_root(const struct device_node *node)
+{
+ return node && (node->parent == NULL);
+}
+
static inline int of_node_check_flag(struct device_node *n, unsigned long flag)
{
return test_bit(flag, &n->_flags);
@@ -141,6 +146,11 @@ static inline unsigned long of_read_ulong(const __be32 *cell, int size)
#define OF_BAD_ADDR ((u64)-1)
+#ifndef of_node_to_nid
+static inline int of_node_to_nid(struct device_node *np) { return -1; }
+#define of_node_to_nid of_node_to_nid
+#endif
+
extern struct device_node *of_find_node_by_name(struct device_node *from,
const char *name);
#define for_each_node_by_name(dn, name) \
diff --git a/include/linux/of_address.h b/include/linux/of_address.h
new file mode 100644
index 00000000000..8aea06f0564
--- /dev/null
+++ b/include/linux/of_address.h
@@ -0,0 +1,44 @@
+#ifndef __OF_ADDRESS_H
+#define __OF_ADDRESS_H
+#include <linux/ioport.h>
+#include <linux/of.h>
+
+extern u64 of_translate_address(struct device_node *np, const u32 *addr);
+extern int of_address_to_resource(struct device_node *dev, int index,
+ struct resource *r);
+extern void __iomem *of_iomap(struct device_node *device, int index);
+
+/* Extract an address from a device, returns the region size and
+ * the address space flags too. The PCI version uses a BAR number
+ * instead of an absolute index
+ */
+extern const u32 *of_get_address(struct device_node *dev, int index,
+ u64 *size, unsigned int *flags);
+
+#ifndef pci_address_to_pio
+static inline unsigned long pci_address_to_pio(phys_addr_t addr) { return -1; }
+#define pci_address_to_pio pci_address_to_pio
+#endif
+
+#ifdef CONFIG_PCI
+extern const u32 *of_get_pci_address(struct device_node *dev, int bar_no,
+ u64 *size, unsigned int *flags);
+extern int of_pci_address_to_resource(struct device_node *dev, int bar,
+ struct resource *r);
+#else /* CONFIG_PCI */
+static inline int of_pci_address_to_resource(struct device_node *dev, int bar,
+ struct resource *r)
+{
+ return -ENOSYS;
+}
+
+static inline const u32 *of_get_pci_address(struct device_node *dev,
+ int bar_no, u64 *size, unsigned int *flags)
+{
+ return NULL;
+}
+#endif /* CONFIG_PCI */
+
+
+#endif /* __OF_ADDRESS_H */
+
diff --git a/include/linux/of_device.h b/include/linux/of_device.h
index 11651facc5f..35aa44ad9f2 100644
--- a/include/linux/of_device.h
+++ b/include/linux/of_device.h
@@ -1,32 +1,77 @@
#ifndef _LINUX_OF_DEVICE_H
#define _LINUX_OF_DEVICE_H
+/*
+ * The of_device *was* a kind of "base class" that was a superset of
+ * struct device for use by devices attached to an OF node and probed
+ * using OF properties. However, the important bit of OF-style
+ * probing, namely the device node pointer, has been moved into the
+ * common struct device when CONFIG_OF is set to make OF-style probing
+ * available to all bus types. So now, just make of_device and
+ * platform_device equivalent so that current of_platform bus users
+ * can be transparently migrated over to using the platform bus.
+ *
+ * This line will go away once all references to of_device are removed
+ * from the kernel.
+ */
+#define of_device platform_device
+#include <linux/platform_device.h>
+#include <linux/of_platform.h> /* temporary until merge */
+
#ifdef CONFIG_OF_DEVICE
#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_device(
const struct of_device_id *matches, const struct device *dev);
+extern void of_device_make_bus_id(struct device *dev);
+
+/**
+ * of_driver_match_device - Tell if a driver's of_match_table matches a device.
+ * @drv: the device_driver structure to test
+ * @dev: the device structure to match against
+ */
+static inline int of_driver_match_device(const struct device *dev,
+ const struct device_driver *drv)
+{
+ return of_match_device(drv->of_match_table, dev) != NULL;
+}
-extern struct of_device *of_dev_get(struct of_device *dev);
-extern void of_dev_put(struct of_device *dev);
+extern struct platform_device *of_dev_get(struct platform_device *dev);
+extern void of_dev_put(struct platform_device *dev);
-extern int of_device_register(struct of_device *ofdev);
-extern void of_device_unregister(struct of_device *ofdev);
+extern int of_device_register(struct platform_device *ofdev);
+extern void of_device_unregister(struct platform_device *ofdev);
extern void of_release_dev(struct device *dev);
-static inline void of_device_free(struct of_device *dev)
+static inline void of_device_free(struct platform_device *dev)
{
of_release_dev(&dev->dev);
}
-extern ssize_t of_device_get_modalias(struct of_device *ofdev,
+extern ssize_t of_device_get_modalias(struct device *dev,
char *str, ssize_t len);
+
+extern int of_device_uevent(struct device *dev, struct kobj_uevent_env *env);
+
+
+#else /* CONFIG_OF_DEVICE */
+
+static inline int of_driver_match_device(struct device *dev,
+ struct device_driver *drv)
+{
+ return 0;
+}
+
+static inline int of_device_uevent(struct device *dev,
+ struct kobj_uevent_env *env)
+{
+ return -ENODEV;
+}
+
#endif /* CONFIG_OF_DEVICE */
#endif /* _LINUX_OF_DEVICE_H */
diff --git a/include/linux/of_gpio.h b/include/linux/of_gpio.h
index fc2472c3c25..6598c04dab0 100644
--- a/include/linux/of_gpio.h
+++ b/include/linux/of_gpio.h
@@ -33,34 +33,17 @@ enum of_gpio_flags {
#ifdef CONFIG_OF_GPIO
/*
- * Generic OF GPIO chip
- */
-struct of_gpio_chip {
- struct gpio_chip gc;
- int gpio_cells;
- int (*xlate)(struct of_gpio_chip *of_gc, struct device_node *np,
- const void *gpio_spec, enum of_gpio_flags *flags);
-};
-
-static inline struct of_gpio_chip *to_of_gpio_chip(struct gpio_chip *gc)
-{
- return container_of(gc, struct of_gpio_chip, gc);
-}
-
-/*
* OF GPIO chip for memory mapped banks
*/
struct of_mm_gpio_chip {
- struct of_gpio_chip of_gc;
+ struct gpio_chip gc;
void (*save_regs)(struct of_mm_gpio_chip *mm_gc);
void __iomem *regs;
};
static inline struct of_mm_gpio_chip *to_of_mm_gpio_chip(struct gpio_chip *gc)
{
- struct of_gpio_chip *of_gc = to_of_gpio_chip(gc);
-
- return container_of(of_gc, struct of_mm_gpio_chip, of_gc);
+ return container_of(gc, struct of_mm_gpio_chip, gc);
}
extern int of_get_gpio_flags(struct device_node *np, int index,
@@ -69,11 +52,12 @@ extern unsigned int of_gpio_count(struct device_node *np);
extern int of_mm_gpiochip_add(struct device_node *np,
struct of_mm_gpio_chip *mm_gc);
-extern int of_gpio_simple_xlate(struct of_gpio_chip *of_gc,
- struct device_node *np,
- const void *gpio_spec,
- enum of_gpio_flags *flags);
-#else
+
+extern void of_gpiochip_add(struct gpio_chip *gc);
+extern void of_gpiochip_remove(struct gpio_chip *gc);
+extern struct gpio_chip *of_node_to_gpiochip(struct device_node *np);
+
+#else /* CONFIG_OF_GPIO */
/* Drivers may not strictly depend on the GPIO support, so let them link. */
static inline int of_get_gpio_flags(struct device_node *np, int index,
@@ -87,6 +71,9 @@ static inline unsigned int of_gpio_count(struct device_node *np)
return 0;
}
+static inline void of_gpiochip_add(struct gpio_chip *gc) { }
+static inline void of_gpiochip_remove(struct gpio_chip *gc) { }
+
#endif /* CONFIG_OF_GPIO */
/**
diff --git a/include/linux/of_i2c.h b/include/linux/of_i2c.h
index 34974b5a76f..0efe8d465f5 100644
--- a/include/linux/of_i2c.h
+++ b/include/linux/of_i2c.h
@@ -12,12 +12,19 @@
#ifndef __LINUX_OF_I2C_H
#define __LINUX_OF_I2C_H
+#if defined(CONFIG_OF_I2C) || defined(CONFIG_OF_I2C_MODULE)
#include <linux/i2c.h>
-void of_register_i2c_devices(struct i2c_adapter *adap,
- struct device_node *adap_node);
+extern void of_i2c_register_devices(struct i2c_adapter *adap);
/* must call put_device() when done with returned i2c_client device */
-struct i2c_client *of_find_i2c_device_by_node(struct device_node *node);
+extern struct i2c_client *of_find_i2c_device_by_node(struct device_node *node);
+
+#else
+static inline void of_i2c_register_devices(struct i2c_adapter *adap)
+{
+ return;
+}
+#endif /* CONFIG_OF_I2C */
#endif /* __LINUX_OF_I2C_H */
diff --git a/include/linux/of_irq.h b/include/linux/of_irq.h
new file mode 100644
index 00000000000..5929781c104
--- /dev/null
+++ b/include/linux/of_irq.h
@@ -0,0 +1,70 @@
+#ifndef __OF_IRQ_H
+#define __OF_IRQ_H
+
+#if defined(CONFIG_OF)
+struct of_irq;
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/of.h>
+
+/*
+ * irq_of_parse_and_map() is used ba all OF enabled platforms; but SPARC
+ * implements it differently. However, the prototype is the same for all,
+ * so declare it here regardless of the CONFIG_OF_IRQ setting.
+ */
+extern unsigned int irq_of_parse_and_map(struct device_node *node, int index);
+
+#if defined(CONFIG_OF_IRQ)
+/**
+ * of_irq - container for device_node/irq_specifier pair for an irq controller
+ * @controller: pointer to interrupt controller device tree node
+ * @size: size of interrupt specifier
+ * @specifier: array of cells @size long specifing the specific interrupt
+ *
+ * This structure is returned when an interrupt is mapped. The controller
+ * field needs to be put() after use
+ */
+#define OF_MAX_IRQ_SPEC 4 /* We handle specifiers of at most 4 cells */
+struct of_irq {
+ struct device_node *controller; /* Interrupt controller node */
+ u32 size; /* Specifier size */
+ u32 specifier[OF_MAX_IRQ_SPEC]; /* Specifier copy */
+};
+
+/*
+ * Workarounds only applied to 32bit powermac machines
+ */
+#define OF_IMAP_OLDWORLD_MAC 0x00000001
+#define OF_IMAP_NO_PHANDLE 0x00000002
+
+#if defined(CONFIG_PPC32) && defined(CONFIG_PPC_PMAC)
+extern unsigned int of_irq_workarounds;
+extern struct device_node *of_irq_dflt_pic;
+extern int of_irq_map_oldworld(struct device_node *device, int index,
+ struct of_irq *out_irq);
+#else /* CONFIG_PPC32 && CONFIG_PPC_PMAC */
+#define of_irq_workarounds (0)
+#define of_irq_dflt_pic (NULL)
+static inline int of_irq_map_oldworld(struct device_node *device, int index,
+ struct of_irq *out_irq)
+{
+ return -EINVAL;
+}
+#endif /* CONFIG_PPC32 && CONFIG_PPC_PMAC */
+
+
+extern int of_irq_map_raw(struct device_node *parent, const u32 *intspec,
+ u32 ointsize, const u32 *addr,
+ struct of_irq *out_irq);
+extern int of_irq_map_one(struct device_node *device, int index,
+ struct of_irq *out_irq);
+extern unsigned int irq_create_of_mapping(struct device_node *controller,
+ const u32 *intspec,
+ unsigned int intsize);
+extern int of_irq_to_resource(struct device_node *dev, int index,
+ struct resource *r);
+
+#endif /* CONFIG_OF_IRQ */
+#endif /* CONFIG_OF */
+#endif /* __OF_IRQ_H */
diff --git a/include/linux/of_platform.h b/include/linux/of_platform.h
index 1643d3761eb..4e6d989c06d 100644
--- a/include/linux/of_platform.h
+++ b/include/linux/of_platform.h
@@ -17,29 +17,24 @@
#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;
+#include <linux/platform_device.h>
/*
* An of_platform_driver driver is attached to a basic of_device on
- * the "platform bus" (of_platform_bus_type).
+ * the "platform bus" (platform_bus_type).
*/
struct of_platform_driver
{
- int (*probe)(struct of_device* dev,
+ int (*probe)(struct platform_device* dev,
const struct of_device_id *match);
- int (*remove)(struct of_device* dev);
+ int (*remove)(struct platform_device* dev);
- int (*suspend)(struct of_device* dev, pm_message_t state);
- int (*resume)(struct of_device* dev);
- int (*shutdown)(struct of_device* dev);
+ int (*suspend)(struct platform_device* dev, pm_message_t state);
+ int (*resume)(struct platform_device* dev);
+ int (*shutdown)(struct platform_device* dev);
struct device_driver driver;
+ struct platform_driver platform_driver;
};
#define to_of_platform_driver(drv) \
container_of(drv,struct of_platform_driver, driver)
@@ -49,20 +44,30 @@ extern int of_register_driver(struct of_platform_driver *drv,
extern void of_unregister_driver(struct of_platform_driver *drv);
/* Platform drivers register/unregister */
-static inline int of_register_platform_driver(struct of_platform_driver *drv)
-{
- return of_register_driver(drv, &of_platform_bus_type);
-}
-static inline void of_unregister_platform_driver(struct of_platform_driver *drv)
-{
- of_unregister_driver(drv);
-}
+extern int of_register_platform_driver(struct of_platform_driver *drv);
+extern void of_unregister_platform_driver(struct of_platform_driver *drv);
-#include <asm/of_platform.h>
-
-extern struct of_device *of_find_device_by_node(struct device_node *np);
+extern struct platform_device *of_device_alloc(struct device_node *np,
+ const char *bus_id,
+ struct device *parent);
+extern struct platform_device *of_find_device_by_node(struct device_node *np);
extern int of_bus_type_init(struct bus_type *bus, const char *name);
+
+#if !defined(CONFIG_SPARC) /* SPARC has its own device registration method */
+/* Platform devices and busses creation */
+extern struct platform_device *of_platform_device_create(struct device_node *np,
+ const char *bus_id,
+ struct device *parent);
+
+/* pseudo "matches" value to not do deep probe */
+#define OF_NO_DEEP_PROBE ((struct of_device_id *)-1)
+
+extern int of_platform_bus_probe(struct device_node *root,
+ const struct of_device_id *matches,
+ struct device *parent);
+#endif /* !CONFIG_SPARC */
+
#endif /* CONFIG_OF_DEVICE */
#endif /* _LINUX_OF_PLATFORM_H */
diff --git a/include/linux/of_spi.h b/include/linux/of_spi.h
index 5f71ee8c086..9e3e70f78ae 100644
--- a/include/linux/of_spi.h
+++ b/include/linux/of_spi.h
@@ -9,10 +9,15 @@
#ifndef __LINUX_OF_SPI_H
#define __LINUX_OF_SPI_H
-#include <linux/of.h>
#include <linux/spi/spi.h>
-extern void of_register_spi_devices(struct spi_master *master,
- struct device_node *np);
+#if defined(CONFIG_OF_SPI) || defined(CONFIG_OF_SPI_MODULE)
+extern void of_register_spi_devices(struct spi_master *master);
+#else
+static inline void of_register_spi_devices(struct spi_master *master)
+{
+ return;
+}
+#endif /* CONFIG_OF_SPI */
#endif /* __LINUX_OF_SPI */
diff --git a/include/linux/padata.h b/include/linux/padata.h
index 8d8406246ee..bdcd1e9eace 100644
--- a/include/linux/padata.h
+++ b/include/linux/padata.h
@@ -25,6 +25,11 @@
#include <linux/spinlock.h>
#include <linux/list.h>
#include <linux/timer.h>
+#include <linux/notifier.h>
+#include <linux/kobject.h>
+
+#define PADATA_CPU_SERIAL 0x01
+#define PADATA_CPU_PARALLEL 0x02
/**
* struct padata_priv - Embedded to the users data structure.
@@ -59,7 +64,20 @@ struct padata_list {
};
/**
- * struct padata_queue - The percpu padata queues.
+* struct padata_serial_queue - The percpu padata serial queue
+*
+* @serial: List to wait for serialization after reordering.
+* @work: work struct for serialization.
+* @pd: Backpointer to the internal control structure.
+*/
+struct padata_serial_queue {
+ struct padata_list serial;
+ struct work_struct work;
+ struct parallel_data *pd;
+};
+
+/**
+ * struct padata_parallel_queue - The percpu padata parallel queue
*
* @parallel: List to wait for parallelization.
* @reorder: List to wait for reordering after parallel processing.
@@ -67,18 +85,28 @@ struct padata_list {
* @pwork: work struct for parallelization.
* @swork: work struct for serialization.
* @pd: Backpointer to the internal control structure.
+ * @work: work struct for parallelization.
* @num_obj: Number of objects that are processed by this cpu.
* @cpu_index: Index of the cpu.
*/
-struct padata_queue {
- struct padata_list parallel;
- struct padata_list reorder;
- struct padata_list serial;
- struct work_struct pwork;
- struct work_struct swork;
- struct parallel_data *pd;
- atomic_t num_obj;
- int cpu_index;
+struct padata_parallel_queue {
+ struct padata_list parallel;
+ struct padata_list reorder;
+ struct parallel_data *pd;
+ struct work_struct work;
+ atomic_t num_obj;
+ int cpu_index;
+};
+
+/**
+ * struct padata_cpumask - The cpumasks for the parallel/serial workers
+ *
+ * @pcpu: cpumask for the parallel workers.
+ * @cbcpu: cpumask for the serial (callback) workers.
+ */
+struct padata_cpumask {
+ cpumask_var_t pcpu;
+ cpumask_var_t cbcpu;
};
/**
@@ -86,25 +114,29 @@ struct padata_queue {
* that depends on the cpumask in use.
*
* @pinst: padata instance.
- * @queue: percpu padata queues.
+ * @pqueue: percpu padata queues used for parallelization.
+ * @squeue: percpu padata queues used for serialuzation.
* @seq_nr: The sequence number that will be attached to the next object.
* @reorder_objects: Number of objects waiting in the reorder queues.
* @refcnt: Number of objects holding a reference on this parallel_data.
* @max_seq_nr: Maximal used sequence number.
- * @cpumask: cpumask in use.
+ * @cpumask: The cpumasks in use for parallel and serial workers.
* @lock: Reorder lock.
+ * @processed: Number of already processed objects.
* @timer: Reorder timer.
*/
struct parallel_data {
- struct padata_instance *pinst;
- struct padata_queue *queue;
- atomic_t seq_nr;
- atomic_t reorder_objects;
- atomic_t refcnt;
- unsigned int max_seq_nr;
- cpumask_var_t cpumask;
- spinlock_t lock;
- struct timer_list timer;
+ struct padata_instance *pinst;
+ struct padata_parallel_queue *pqueue;
+ struct padata_serial_queue *squeue;
+ atomic_t seq_nr;
+ atomic_t reorder_objects;
+ atomic_t refcnt;
+ unsigned int max_seq_nr;
+ struct padata_cpumask cpumask;
+ spinlock_t lock ____cacheline_aligned;
+ unsigned int processed;
+ struct timer_list timer;
};
/**
@@ -113,31 +145,48 @@ struct parallel_data {
* @cpu_notifier: cpu hotplug notifier.
* @wq: The workqueue in use.
* @pd: The internal control structure.
- * @cpumask: User supplied cpumask.
+ * @cpumask: User supplied cpumasks for parallel and serial works.
+ * @cpumask_change_notifier: Notifiers chain for user-defined notify
+ * callbacks that will be called when either @pcpu or @cbcpu
+ * or both cpumasks change.
+ * @kobj: padata instance kernel object.
* @lock: padata instance lock.
* @flags: padata flags.
*/
struct padata_instance {
- struct notifier_block cpu_notifier;
- struct workqueue_struct *wq;
- struct parallel_data *pd;
- cpumask_var_t cpumask;
- struct mutex lock;
- u8 flags;
-#define PADATA_INIT 1
-#define PADATA_RESET 2
+ struct notifier_block cpu_notifier;
+ struct workqueue_struct *wq;
+ struct parallel_data *pd;
+ struct padata_cpumask cpumask;
+ struct blocking_notifier_head cpumask_change_notifier;
+ struct kobject kobj;
+ struct mutex lock;
+ u8 flags;
+#define PADATA_INIT 1
+#define PADATA_RESET 2
+#define PADATA_INVALID 4
};
-extern struct padata_instance *padata_alloc(const struct cpumask *cpumask,
- struct workqueue_struct *wq);
+extern struct padata_instance *padata_alloc_possible(
+ struct workqueue_struct *wq);
+extern struct padata_instance *padata_alloc(struct workqueue_struct *wq,
+ const struct cpumask *pcpumask,
+ const struct cpumask *cbcpumask);
extern void padata_free(struct padata_instance *pinst);
extern int padata_do_parallel(struct padata_instance *pinst,
struct padata_priv *padata, int cb_cpu);
extern void padata_do_serial(struct padata_priv *padata);
-extern int padata_set_cpumask(struct padata_instance *pinst,
+extern int padata_set_cpumask(struct padata_instance *pinst, int cpumask_type,
cpumask_var_t cpumask);
-extern int padata_add_cpu(struct padata_instance *pinst, int cpu);
-extern int padata_remove_cpu(struct padata_instance *pinst, int cpu);
-extern void padata_start(struct padata_instance *pinst);
+extern int padata_set_cpumasks(struct padata_instance *pinst,
+ cpumask_var_t pcpumask,
+ cpumask_var_t cbcpumask);
+extern int padata_add_cpu(struct padata_instance *pinst, int cpu, int mask);
+extern int padata_remove_cpu(struct padata_instance *pinst, int cpu, int mask);
+extern int padata_start(struct padata_instance *pinst);
extern void padata_stop(struct padata_instance *pinst);
+extern int padata_register_cpumask_notifier(struct padata_instance *pinst,
+ struct notifier_block *nblock);
+extern int padata_unregister_cpumask_notifier(struct padata_instance *pinst,
+ struct notifier_block *nblock);
#endif
diff --git a/include/linux/page-flags.h b/include/linux/page-flags.h
index 5b59f35dcb8..6fa317801e1 100644
--- a/include/linux/page-flags.h
+++ b/include/linux/page-flags.h
@@ -128,7 +128,6 @@ enum pageflags {
/* SLUB */
PG_slub_frozen = PG_active,
- PG_slub_debug = PG_error,
};
#ifndef __GENERATING_BOUNDS_H
@@ -215,7 +214,6 @@ PAGEFLAG(SwapBacked, swapbacked) __CLEARPAGEFLAG(SwapBacked, swapbacked)
__PAGEFLAG(SlobFree, slob_free)
__PAGEFLAG(SlubFrozen, slub_frozen)
-__PAGEFLAG(SlubDebug, slub_debug)
/*
* Private page markings that may be used by the filesystem that owns the page
diff --git a/include/linux/pci.h b/include/linux/pci.h
index f26fda76b87..b1d17956a15 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -270,6 +270,8 @@ struct pci_dev {
unsigned int d1_support:1; /* Low power state D1 is supported */
unsigned int d2_support:1; /* Low power state D2 is supported */
unsigned int no_d1d2:1; /* Only allow D0 and D3 */
+ unsigned int mmio_always_on:1; /* disallow turning off io/mem
+ decoding during bar sizing */
unsigned int wakeup_prepared:1;
unsigned int d3_delay; /* D3->D0 transition time in ms */
diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h
index 3bedcc149c8..c81eec4d3c3 100644
--- a/include/linux/pci_ids.h
+++ b/include/linux/pci_ids.h
@@ -1494,6 +1494,9 @@
#define PCI_DEVICE_ID_SBE_WANXL100 0x0301
#define PCI_DEVICE_ID_SBE_WANXL200 0x0302
#define PCI_DEVICE_ID_SBE_WANXL400 0x0104
+#define PCI_SUBDEVICE_ID_SBE_T3E3 0x0009
+#define PCI_SUBDEVICE_ID_SBE_2T3E3_P0 0x0901
+#define PCI_SUBDEVICE_ID_SBE_2T3E3_P1 0x0902
#define PCI_VENDOR_ID_TOSHIBA 0x1179
#define PCI_DEVICE_ID_TOSHIBA_PICCOLO_1 0x0101
@@ -2054,7 +2057,6 @@
#define PCI_DEVICE_ID_NX2_57711E 0x1650
#define PCI_DEVICE_ID_TIGON3_5705 0x1653
#define PCI_DEVICE_ID_TIGON3_5705_2 0x1654
-#define PCI_DEVICE_ID_TIGON3_5720 0x1658
#define PCI_DEVICE_ID_TIGON3_5721 0x1659
#define PCI_DEVICE_ID_TIGON3_5722 0x165a
#define PCI_DEVICE_ID_TIGON3_5723 0x165b
@@ -2068,13 +2070,11 @@
#define PCI_DEVICE_ID_TIGON3_5754M 0x1672
#define PCI_DEVICE_ID_TIGON3_5755M 0x1673
#define PCI_DEVICE_ID_TIGON3_5756 0x1674
-#define PCI_DEVICE_ID_TIGON3_5750 0x1676
#define PCI_DEVICE_ID_TIGON3_5751 0x1677
#define PCI_DEVICE_ID_TIGON3_5715 0x1678
#define PCI_DEVICE_ID_TIGON3_5715S 0x1679
#define PCI_DEVICE_ID_TIGON3_5754 0x167a
#define PCI_DEVICE_ID_TIGON3_5755 0x167b
-#define PCI_DEVICE_ID_TIGON3_5750M 0x167c
#define PCI_DEVICE_ID_TIGON3_5751M 0x167d
#define PCI_DEVICE_ID_TIGON3_5751F 0x167e
#define PCI_DEVICE_ID_TIGON3_5787F 0x167f
@@ -2264,6 +2264,7 @@
#define PCI_DEVICE_ID_TDI_EHCI 0x0101
#define PCI_VENDOR_ID_FREESCALE 0x1957
+#define PCI_DEVICE_ID_MPC8308 0xc006
#define PCI_DEVICE_ID_MPC8315E 0x00b4
#define PCI_DEVICE_ID_MPC8315 0x00b5
#define PCI_DEVICE_ID_MPC8314E 0x00b6
@@ -2324,9 +2325,11 @@
#define PCI_DEVICE_ID_JMICRON_JMB361 0x2361
#define PCI_DEVICE_ID_JMICRON_JMB362 0x2362
#define PCI_DEVICE_ID_JMICRON_JMB363 0x2363
+#define PCI_DEVICE_ID_JMICRON_JMB364 0x2364
#define PCI_DEVICE_ID_JMICRON_JMB365 0x2365
#define PCI_DEVICE_ID_JMICRON_JMB366 0x2366
#define PCI_DEVICE_ID_JMICRON_JMB368 0x2368
+#define PCI_DEVICE_ID_JMICRON_JMB369 0x2369
#define PCI_DEVICE_ID_JMICRON_JMB38X_SD 0x2381
#define PCI_DEVICE_ID_JMICRON_JMB38X_MMC 0x2382
#define PCI_DEVICE_ID_JMICRON_JMB38X_MS 0x2383
@@ -2772,3 +2775,6 @@
#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_XEN 0x5853
+#define PCI_DEVICE_ID_XEN_PLATFORM 0x0001
diff --git a/include/linux/percpu.h b/include/linux/percpu.h
index d3a38d68710..b8b9084527b 100644
--- a/include/linux/percpu.h
+++ b/include/linux/percpu.h
@@ -45,6 +45,16 @@
#define PCPU_MIN_UNIT_SIZE PFN_ALIGN(64 << 10)
/*
+ * Percpu allocator can serve percpu allocations before slab is
+ * initialized which allows slab to depend on the percpu allocator.
+ * The following two parameters decide how much resource to
+ * preallocate for this. Keep PERCPU_DYNAMIC_RESERVE equal to or
+ * larger than PERCPU_DYNAMIC_EARLY_SIZE.
+ */
+#define PERCPU_DYNAMIC_EARLY_SLOTS 128
+#define PERCPU_DYNAMIC_EARLY_SIZE (12 << 10)
+
+/*
* PERCPU_DYNAMIC_RESERVE indicates the amount of free area to piggy
* back on the first chunk for dynamic percpu allocation if arch is
* manually allocating and mapping it for faster access (as a part of
@@ -104,16 +114,11 @@ extern struct pcpu_alloc_info * __init pcpu_alloc_alloc_info(int nr_groups,
int nr_units);
extern void __init pcpu_free_alloc_info(struct pcpu_alloc_info *ai);
-extern struct pcpu_alloc_info * __init pcpu_build_alloc_info(
- size_t reserved_size, ssize_t dyn_size,
- size_t atom_size,
- pcpu_fc_cpu_distance_fn_t cpu_distance_fn);
-
extern int __init pcpu_setup_first_chunk(const struct pcpu_alloc_info *ai,
void *base_addr);
#ifdef CONFIG_NEED_PER_CPU_EMBED_FIRST_CHUNK
-extern int __init pcpu_embed_first_chunk(size_t reserved_size, ssize_t dyn_size,
+extern int __init pcpu_embed_first_chunk(size_t reserved_size, size_t dyn_size,
size_t atom_size,
pcpu_fc_cpu_distance_fn_t cpu_distance_fn,
pcpu_fc_alloc_fn_t alloc_fn,
@@ -140,6 +145,7 @@ extern bool is_kernel_percpu_address(unsigned long addr);
#ifndef CONFIG_HAVE_SETUP_PER_CPU_AREA
extern void __init setup_per_cpu_areas(void);
#endif
+extern void __init percpu_init_late(void);
#else /* CONFIG_SMP */
@@ -153,6 +159,8 @@ static inline bool is_kernel_percpu_address(unsigned long addr)
static inline void __init setup_per_cpu_areas(void) { }
+static inline void __init percpu_init_late(void) { }
+
static inline void *pcpu_lpage_remapped(void *kaddr)
{
return NULL;
diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h
index 5d0266d9498..716f99b682c 100644
--- a/include/linux/perf_event.h
+++ b/include/linux/perf_event.h
@@ -214,8 +214,9 @@ struct perf_event_attr {
* See also PERF_RECORD_MISC_EXACT_IP
*/
precise_ip : 2, /* skid constraint */
+ mmap_data : 1, /* non-exec mmap data */
- __reserved_1 : 47;
+ __reserved_1 : 46;
union {
__u32 wakeup_events; /* wakeup every n events */
@@ -461,6 +462,7 @@ enum perf_callchain_context {
#ifdef CONFIG_PERF_EVENTS
# include <asm/perf_event.h>
+# include <asm/local64.h>
#endif
struct perf_guest_info_callbacks {
@@ -531,14 +533,16 @@ struct hw_perf_event {
struct hrtimer hrtimer;
};
#ifdef CONFIG_HAVE_HW_BREAKPOINT
- /* breakpoint */
- struct arch_hw_breakpoint info;
+ struct { /* breakpoint */
+ struct arch_hw_breakpoint info;
+ struct list_head bp_list;
+ };
#endif
};
- atomic64_t prev_count;
+ local64_t prev_count;
u64 sample_period;
u64 last_period;
- atomic64_t period_left;
+ local64_t period_left;
u64 interrupts;
u64 freq_time_stamp;
@@ -548,7 +552,10 @@ struct hw_perf_event {
struct perf_event;
-#define PERF_EVENT_TXN_STARTED 1
+/*
+ * Common implementation detail of pmu::{start,commit,cancel}_txn
+ */
+#define PERF_EVENT_TXN 0x1
/**
* struct pmu - generic performance monitoring unit
@@ -562,14 +569,28 @@ struct pmu {
void (*unthrottle) (struct perf_event *event);
/*
- * group events scheduling is treated as a transaction,
- * add group events as a whole and perform one schedulability test.
- * If test fails, roll back the whole group
+ * Group events scheduling is treated as a transaction, add group
+ * events as a whole and perform one schedulability test. If the test
+ * fails, roll back the whole group
*/
+ /*
+ * Start the transaction, after this ->enable() doesn't need
+ * to do schedulability tests.
+ */
void (*start_txn) (const struct pmu *pmu);
- void (*cancel_txn) (const struct pmu *pmu);
+ /*
+ * If ->start_txn() disabled the ->enable() schedulability test
+ * then ->commit_txn() is required to perform one. On success
+ * the transaction is closed. On error the transaction is kept
+ * open until ->cancel_txn() is called.
+ */
int (*commit_txn) (const struct pmu *pmu);
+ /*
+ * Will cancel the transaction, assumes ->disable() is called for
+ * each successfull ->enable() during the transaction.
+ */
+ void (*cancel_txn) (const struct pmu *pmu);
};
/**
@@ -584,7 +605,9 @@ enum perf_event_active_state {
struct file;
-struct perf_mmap_data {
+#define PERF_BUFFER_WRITABLE 0x01
+
+struct perf_buffer {
atomic_t refcount;
struct rcu_head rcu_head;
#ifdef CONFIG_PERF_USE_VMALLOC
@@ -650,7 +673,8 @@ struct perf_event {
enum perf_event_active_state state;
unsigned int attach_state;
- atomic64_t count;
+ local64_t count;
+ atomic64_t child_count;
/*
* These are the total time in nanoseconds that the event
@@ -709,7 +733,7 @@ struct perf_event {
atomic_t mmap_count;
int mmap_locked;
struct user_struct *mmap_user;
- struct perf_mmap_data *data;
+ struct perf_buffer *buffer;
/* poll related */
wait_queue_head_t waitq;
@@ -807,7 +831,7 @@ struct perf_cpu_context {
struct perf_output_handle {
struct perf_event *event;
- struct perf_mmap_data *data;
+ struct perf_buffer *buffer;
unsigned long wakeup;
unsigned long size;
void *addr;
@@ -910,8 +934,10 @@ extern atomic_t perf_swevent_enabled[PERF_COUNT_SW_MAX];
extern void __perf_sw_event(u32, u64, int, struct pt_regs *, u64);
-extern void
-perf_arch_fetch_caller_regs(struct pt_regs *regs, unsigned long ip, int skip);
+#ifndef perf_arch_fetch_caller_regs
+static inline void
+perf_arch_fetch_caller_regs(struct pt_regs *regs, unsigned long ip) { }
+#endif
/*
* Take a snapshot of the regs. Skip ip and frame pointer to
@@ -921,31 +947,11 @@ perf_arch_fetch_caller_regs(struct pt_regs *regs, unsigned long ip, int skip);
* - bp for callchains
* - eflags, for future purposes, just in case
*/
-static inline void perf_fetch_caller_regs(struct pt_regs *regs, int skip)
+static inline void perf_fetch_caller_regs(struct pt_regs *regs)
{
- unsigned long ip;
-
memset(regs, 0, sizeof(*regs));
- switch (skip) {
- case 1 :
- ip = CALLER_ADDR0;
- break;
- case 2 :
- ip = CALLER_ADDR1;
- break;
- case 3 :
- ip = CALLER_ADDR2;
- break;
- case 4:
- ip = CALLER_ADDR3;
- break;
- /* No need to support further for now */
- default:
- ip = 0;
- }
-
- return perf_arch_fetch_caller_regs(regs, ip, skip);
+ perf_arch_fetch_caller_regs(regs, CALLER_ADDR0);
}
static inline void
@@ -955,21 +961,14 @@ perf_sw_event(u32 event_id, u64 nr, int nmi, struct pt_regs *regs, u64 addr)
struct pt_regs hot_regs;
if (!regs) {
- perf_fetch_caller_regs(&hot_regs, 1);
+ perf_fetch_caller_regs(&hot_regs);
regs = &hot_regs;
}
__perf_sw_event(event_id, nr, nmi, regs, addr);
}
}
-extern void __perf_event_mmap(struct vm_area_struct *vma);
-
-static inline void perf_event_mmap(struct vm_area_struct *vma)
-{
- if (vma->vm_flags & VM_EXEC)
- __perf_event_mmap(vma);
-}
-
+extern void perf_event_mmap(struct vm_area_struct *vma);
extern struct perf_guest_info_callbacks *perf_guest_cbs;
extern int perf_register_guest_info_callbacks(struct perf_guest_info_callbacks *callbacks);
extern int perf_unregister_guest_info_callbacks(struct perf_guest_info_callbacks *callbacks);
@@ -1001,7 +1000,7 @@ static inline bool perf_paranoid_kernel(void)
extern void perf_event_init(void);
extern void perf_tp_event(u64 addr, u64 count, void *record,
int entry_size, struct pt_regs *regs,
- struct hlist_head *head);
+ struct hlist_head *head, int rctx);
extern void perf_bp_event(struct perf_event *event, void *data);
#ifndef perf_misc_flags
@@ -1068,7 +1067,7 @@ static inline void perf_event_disable(struct perf_event *event) { }
#define perf_cpu_notifier(fn) \
do { \
static struct notifier_block fn##_nb __cpuinitdata = \
- { .notifier_call = fn, .priority = 20 }; \
+ { .notifier_call = fn, .priority = CPU_PRI_PERF }; \
fn(&fn##_nb, (unsigned long)CPU_UP_PREPARE, \
(void *)(unsigned long)smp_processor_id()); \
fn(&fn##_nb, (unsigned long)CPU_STARTING, \
diff --git a/include/linux/phonet.h b/include/linux/phonet.h
index e5126cff9b2..24426c3d6b5 100644
--- a/include/linux/phonet.h
+++ b/include/linux/phonet.h
@@ -56,7 +56,7 @@ struct phonethdr {
__be16 pn_length;
__u8 pn_robj;
__u8 pn_sobj;
-} __attribute__((packed));
+} __packed;
/* Common Phonet payload header */
struct phonetmsg {
@@ -98,7 +98,7 @@ struct sockaddr_pn {
__u8 spn_dev;
__u8 spn_resource;
__u8 spn_zero[sizeof(struct sockaddr) - sizeof(sa_family_t) - 3];
-} __attribute__ ((packed));
+} __packed;
/* Well known address */
#define PN_DEV_PC 0x10
diff --git a/include/linux/phy.h b/include/linux/phy.h
index 987e111f7b1..6b0a782c622 100644
--- a/include/linux/phy.h
+++ b/include/linux/phy.h
@@ -234,6 +234,8 @@ enum phy_state {
PHY_RESUMING
};
+struct sk_buff;
+
/* phy_device: An instance of a PHY
*
* drv: Pointer to the driver for this PHY instance
@@ -402,6 +404,26 @@ struct phy_driver {
/* Clears up any memory if needed */
void (*remove)(struct phy_device *phydev);
+ /* Handles SIOCSHWTSTAMP ioctl for hardware time stamping. */
+ int (*hwtstamp)(struct phy_device *phydev, struct ifreq *ifr);
+
+ /*
+ * Requests a Rx timestamp for 'skb'. If the skb is accepted,
+ * the phy driver promises to deliver it using netif_rx() as
+ * soon as a timestamp becomes available. One of the
+ * PTP_CLASS_ values is passed in 'type'. The function must
+ * return true if the skb is accepted for delivery.
+ */
+ bool (*rxtstamp)(struct phy_device *dev, struct sk_buff *skb, int type);
+
+ /*
+ * Requests a Tx timestamp for 'skb'. The phy driver promises
+ * to deliver it to the socket's error queue as soon as a
+ * timestamp becomes available. One of the PTP_CLASS_ values
+ * is passed in 'type'.
+ */
+ void (*txtstamp)(struct phy_device *dev, struct sk_buff *skb, int type);
+
struct device_driver driver;
};
#define to_phy_driver(d) container_of(d, struct phy_driver, driver)
@@ -498,7 +520,7 @@ void phy_stop_machine(struct phy_device *phydev);
int phy_ethtool_sset(struct phy_device *phydev, struct ethtool_cmd *cmd);
int phy_ethtool_gset(struct phy_device *phydev, struct ethtool_cmd *cmd);
int phy_mii_ioctl(struct phy_device *phydev,
- struct mii_ioctl_data *mii_data, int cmd);
+ struct ifreq *ifr, int cmd);
int phy_start_interrupts(struct phy_device *phydev);
void phy_print_status(struct phy_device *phydev);
struct phy_device* phy_device_create(struct mii_bus *bus, int addr, int phy_id);
diff --git a/include/linux/platform_device.h b/include/linux/platform_device.h
index 5417944d368..d7ecad0093b 100644
--- a/include/linux/platform_device.h
+++ b/include/linux/platform_device.h
@@ -43,10 +43,64 @@ extern struct resource *platform_get_resource_byname(struct platform_device *, u
extern int platform_get_irq_byname(struct platform_device *, const char *);
extern int platform_add_devices(struct platform_device **, int);
-extern struct platform_device *platform_device_register_simple(const char *, int id,
- const struct resource *, unsigned int);
-extern struct platform_device *platform_device_register_data(struct device *,
- const char *, int, const void *, size_t);
+extern struct platform_device *platform_device_register_resndata(
+ struct device *parent, const char *name, int id,
+ const struct resource *res, unsigned int num,
+ const void *data, size_t size);
+
+/**
+ * platform_device_register_simple - add a platform-level device and its resources
+ * @name: base name of the device we're adding
+ * @id: instance id
+ * @res: set of resources that needs to be allocated for the device
+ * @num: number of resources
+ *
+ * This function creates a simple platform device that requires minimal
+ * resource and memory management. Canned release function freeing memory
+ * allocated for the device allows drivers using such devices to be
+ * unloaded without waiting for the last reference to the device to be
+ * dropped.
+ *
+ * This interface is primarily intended for use with legacy drivers which
+ * probe hardware directly. Because such drivers create sysfs device nodes
+ * themselves, rather than letting system infrastructure handle such device
+ * enumeration tasks, they don't fully conform to the Linux driver model.
+ * In particular, when such drivers are built as modules, they can't be
+ * "hotplugged".
+ *
+ * Returns &struct platform_device pointer on success, or ERR_PTR() on error.
+ */
+static inline struct platform_device *platform_device_register_simple(
+ const char *name, int id,
+ const struct resource *res, unsigned int num)
+{
+ return platform_device_register_resndata(NULL, name, id,
+ res, num, NULL, 0);
+}
+
+/**
+ * platform_device_register_data - add a platform-level device with platform-specific data
+ * @parent: parent device for the device we're adding
+ * @name: base name of the device we're adding
+ * @id: instance id
+ * @data: platform specific data for this platform device
+ * @size: size of platform specific data
+ *
+ * This function creates a simple platform device that requires minimal
+ * resource and memory management. Canned release function freeing memory
+ * allocated for the device allows drivers using such devices to be
+ * unloaded without waiting for the last reference to the device to be
+ * dropped.
+ *
+ * Returns &struct platform_device pointer on success, or ERR_PTR() on error.
+ */
+static inline struct platform_device *platform_device_register_data(
+ struct device *parent, const char *name, int id,
+ const void *data, size_t size)
+{
+ return platform_device_register_resndata(parent, name, id,
+ NULL, 0, data, size);
+}
extern struct platform_device *platform_device_alloc(const char *name, int id);
extern int platform_device_add_resources(struct platform_device *pdev,
diff --git a/include/linux/plist.h b/include/linux/plist.h
index 6898985e7b3..7254eda078e 100644
--- a/include/linux/plist.h
+++ b/include/linux/plist.h
@@ -260,6 +260,23 @@ static inline int plist_node_empty(const struct plist_node *node)
#endif
/**
+ * plist_last_entry - get the struct for the last entry
+ * @head: the &struct plist_head pointer
+ * @type: the type of the struct this is embedded in
+ * @member: the name of the list_struct within the struct
+ */
+#ifdef CONFIG_DEBUG_PI_LIST
+# define plist_last_entry(head, type, member) \
+({ \
+ WARN_ON(plist_head_empty(head)); \
+ container_of(plist_last(head), type, member); \
+})
+#else
+# define plist_last_entry(head, type, member) \
+ container_of(plist_last(head), type, member)
+#endif
+
+/**
* plist_first - return the first node (and thus, highest priority)
* @head: the &struct plist_head pointer
*
@@ -271,4 +288,16 @@ static inline struct plist_node *plist_first(const struct plist_head *head)
struct plist_node, plist.node_list);
}
+/**
+ * plist_last - return the last node (and thus, lowest priority)
+ * @head: the &struct plist_head pointer
+ *
+ * Assumes the plist is _not_ empty.
+ */
+static inline struct plist_node *plist_last(const struct plist_head *head)
+{
+ return list_entry(head->node_list.prev,
+ struct plist_node, plist.node_list);
+}
+
#endif
diff --git a/include/linux/pm.h b/include/linux/pm.h
index 8e258c72797..52e8c55ff31 100644
--- a/include/linux/pm.h
+++ b/include/linux/pm.h
@@ -457,6 +457,7 @@ struct dev_pm_info {
#ifdef CONFIG_PM_SLEEP
struct list_head entry;
struct completion completion;
+ unsigned long wakeup_count;
#endif
#ifdef CONFIG_PM_RUNTIME
struct timer_list suspend_timer;
@@ -476,9 +477,15 @@ struct dev_pm_info {
enum rpm_request request;
enum rpm_status runtime_status;
int runtime_error;
+ unsigned long active_jiffies;
+ unsigned long suspended_jiffies;
+ unsigned long accounting_timestamp;
#endif
};
+extern void update_pm_runtime_accounting(struct device *dev);
+
+
/*
* The PM_EVENT_ messages are also used by drivers implementing the legacy
* suspend framework, based on the ->suspend() and ->resume() callbacks common
@@ -552,6 +559,11 @@ extern void __suspend_report_result(const char *function, void *fn, int ret);
} while (0)
extern void device_pm_wait_for_dev(struct device *sub, struct device *dev);
+
+/* drivers/base/power/wakeup.c */
+extern void pm_wakeup_event(struct device *dev, unsigned int msec);
+extern void pm_stay_awake(struct device *dev);
+extern void pm_relax(void);
#else /* !CONFIG_PM_SLEEP */
#define device_pm_lock() do {} while (0)
@@ -565,6 +577,10 @@ static inline int dpm_suspend_start(pm_message_t state)
#define suspend_report_result(fn, ret) do {} while (0)
static inline void device_pm_wait_for_dev(struct device *a, struct device *b) {}
+
+static inline void pm_wakeup_event(struct device *dev, unsigned int msec) {}
+static inline void pm_stay_awake(struct device *dev) {}
+static inline void pm_relax(void) {}
#endif /* !CONFIG_PM_SLEEP */
/* How to reorder dpm_list after device_move() */
diff --git a/include/linux/pm_qos_params.h b/include/linux/pm_qos_params.h
index 8ba440e5eb7..77cbddb3784 100644
--- a/include/linux/pm_qos_params.h
+++ b/include/linux/pm_qos_params.h
@@ -1,8 +1,10 @@
+#ifndef _LINUX_PM_QOS_PARAMS_H
+#define _LINUX_PM_QOS_PARAMS_H
/* interface for the pm_qos_power infrastructure of the linux kernel.
*
* Mark Gross <mgross@linux.intel.com>
*/
-#include <linux/list.h>
+#include <linux/plist.h>
#include <linux/notifier.h>
#include <linux/miscdevice.h>
@@ -14,9 +16,12 @@
#define PM_QOS_NUM_CLASSES 4
#define PM_QOS_DEFAULT_VALUE -1
-struct pm_qos_request_list;
+struct pm_qos_request_list {
+ struct plist_node list;
+ int pm_qos_class;
+};
-struct pm_qos_request_list *pm_qos_add_request(int pm_qos_class, s32 value);
+void pm_qos_add_request(struct pm_qos_request_list *l, int pm_qos_class, s32 value);
void pm_qos_update_request(struct pm_qos_request_list *pm_qos_req,
s32 new_value);
void pm_qos_remove_request(struct pm_qos_request_list *pm_qos_req);
@@ -24,4 +29,6 @@ void pm_qos_remove_request(struct pm_qos_request_list *pm_qos_req);
int pm_qos_request(int pm_qos_class);
int pm_qos_add_notifier(int pm_qos_class, struct notifier_block *notifier);
int pm_qos_remove_notifier(int pm_qos_class, struct notifier_block *notifier);
+int pm_qos_request_active(struct pm_qos_request_list *req);
+#endif
diff --git a/include/linux/pm_wakeup.h b/include/linux/pm_wakeup.h
index 22d64c18056..76aca48722a 100644
--- a/include/linux/pm_wakeup.h
+++ b/include/linux/pm_wakeup.h
@@ -29,8 +29,11 @@
#ifdef CONFIG_PM
-/* changes to device_may_wakeup take effect on the next pm state change.
- * by default, devices should wakeup if they can.
+/* Changes to device_may_wakeup take effect on the next pm state change.
+ *
+ * By default, most devices should leave wakeup disabled. The exceptions
+ * are devices that everyone expects to be wakeup sources: keyboards,
+ * power buttons, possibly network interfaces, etc.
*/
static inline void device_init_wakeup(struct device *dev, bool val)
{
@@ -59,7 +62,7 @@ static inline bool device_may_wakeup(struct device *dev)
#else /* !CONFIG_PM */
-/* For some reason the next two routines work even without CONFIG_PM */
+/* For some reason the following routines work even without CONFIG_PM */
static inline void device_init_wakeup(struct device *dev, bool val)
{
dev->power.can_wakeup = val;
@@ -67,6 +70,7 @@ static inline void device_init_wakeup(struct device *dev, bool val)
static inline void device_set_wakeup_capable(struct device *dev, bool capable)
{
+ dev->power.can_wakeup = capable;
}
static inline bool device_can_wakeup(struct device *dev)
diff --git a/include/linux/pnp.h b/include/linux/pnp.h
index 7c4193eb007..1bc1338b817 100644
--- a/include/linux/pnp.h
+++ b/include/linux/pnp.h
@@ -414,6 +414,7 @@ struct pnp_protocol {
int (*disable) (struct pnp_dev *dev);
/* protocol specific suspend/resume */
+ bool (*can_wakeup) (struct pnp_dev *dev);
int (*suspend) (struct pnp_dev * dev, pm_message_t state);
int (*resume) (struct pnp_dev * dev);
diff --git a/include/linux/power/jz4740-battery.h b/include/linux/power/jz4740-battery.h
new file mode 100644
index 00000000000..19c9610c720
--- /dev/null
+++ b/include/linux/power/jz4740-battery.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2009, Jiejing Zhang <kzjeef@gmail.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.
+ *
+ * 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 __JZ4740_BATTERY_H
+#define __JZ4740_BATTERY_H
+
+struct jz_battery_platform_data {
+ struct power_supply_info info;
+ int gpio_charge; /* GPIO port of Charger state */
+ int gpio_charge_active_low;
+};
+
+#endif
diff --git a/include/linux/ptp_classify.h b/include/linux/ptp_classify.h
new file mode 100644
index 00000000000..943a85ab002
--- /dev/null
+++ b/include/linux/ptp_classify.h
@@ -0,0 +1,126 @@
+/*
+ * PTP 1588 support
+ *
+ * This file implements a BPF that recognizes PTP event messages.
+ *
+ * Copyright (C) 2010 OMICRON electronics 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.
+ */
+
+#ifndef _PTP_CLASSIFY_H_
+#define _PTP_CLASSIFY_H_
+
+#include <linux/if_ether.h>
+#include <linux/if_vlan.h>
+#include <linux/filter.h>
+#ifdef __KERNEL__
+#include <linux/in.h>
+#else
+#include <netinet/in.h>
+#endif
+
+#define PTP_CLASS_NONE 0x00 /* not a PTP event message */
+#define PTP_CLASS_V1 0x01 /* protocol version 1 */
+#define PTP_CLASS_V2 0x02 /* protocol version 2 */
+#define PTP_CLASS_VMASK 0x0f /* max protocol version is 15 */
+#define PTP_CLASS_IPV4 0x10 /* event in an IPV4 UDP packet */
+#define PTP_CLASS_IPV6 0x20 /* event in an IPV6 UDP packet */
+#define PTP_CLASS_L2 0x30 /* event in a L2 packet */
+#define PTP_CLASS_VLAN 0x40 /* event in a VLAN tagged L2 packet */
+#define PTP_CLASS_PMASK 0xf0 /* mask for the packet type field */
+
+#define PTP_CLASS_V1_IPV4 (PTP_CLASS_V1 | PTP_CLASS_IPV4)
+#define PTP_CLASS_V1_IPV6 (PTP_CLASS_V1 | PTP_CLASS_IPV6) /*probably DNE*/
+#define PTP_CLASS_V2_IPV4 (PTP_CLASS_V2 | PTP_CLASS_IPV4)
+#define PTP_CLASS_V2_IPV6 (PTP_CLASS_V2 | PTP_CLASS_IPV6)
+#define PTP_CLASS_V2_L2 (PTP_CLASS_V2 | PTP_CLASS_L2)
+#define PTP_CLASS_V2_VLAN (PTP_CLASS_V2 | PTP_CLASS_VLAN)
+
+#define PTP_EV_PORT 319
+
+#define OFF_ETYPE 12
+#define OFF_IHL 14
+#define OFF_FRAG 20
+#define OFF_PROTO4 23
+#define OFF_NEXT 6
+#define OFF_UDP_DST 2
+
+#define IP6_HLEN 40
+#define UDP_HLEN 8
+
+#define RELOFF_DST4 (ETH_HLEN + OFF_UDP_DST)
+#define OFF_DST6 (ETH_HLEN + IP6_HLEN + OFF_UDP_DST)
+#define OFF_PTP6 (ETH_HLEN + IP6_HLEN + UDP_HLEN)
+
+#define OP_AND (BPF_ALU | BPF_AND | BPF_K)
+#define OP_JEQ (BPF_JMP | BPF_JEQ | BPF_K)
+#define OP_JSET (BPF_JMP | BPF_JSET | BPF_K)
+#define OP_LDB (BPF_LD | BPF_B | BPF_ABS)
+#define OP_LDH (BPF_LD | BPF_H | BPF_ABS)
+#define OP_LDHI (BPF_LD | BPF_H | BPF_IND)
+#define OP_LDX (BPF_LDX | BPF_B | BPF_MSH)
+#define OP_OR (BPF_ALU | BPF_OR | BPF_K)
+#define OP_RETA (BPF_RET | BPF_A)
+#define OP_RETK (BPF_RET | BPF_K)
+
+static inline int ptp_filter_init(struct sock_filter *f, int len)
+{
+ if (OP_LDH == f[0].code)
+ return sk_chk_filter(f, len);
+ else
+ return 0;
+}
+
+#define PTP_FILTER \
+ {OP_LDH, 0, 0, OFF_ETYPE }, /* */ \
+ {OP_JEQ, 0, 12, ETH_P_IP }, /* f goto L20 */ \
+ {OP_LDB, 0, 0, OFF_PROTO4 }, /* */ \
+ {OP_JEQ, 0, 9, IPPROTO_UDP }, /* f goto L10 */ \
+ {OP_LDH, 0, 0, OFF_FRAG }, /* */ \
+ {OP_JSET, 7, 0, 0x1fff }, /* t goto L11 */ \
+ {OP_LDX, 0, 0, OFF_IHL }, /* */ \
+ {OP_LDHI, 0, 0, RELOFF_DST4 }, /* */ \
+ {OP_JEQ, 0, 4, PTP_EV_PORT }, /* f goto L12 */ \
+ {OP_LDHI, 0, 0, ETH_HLEN + UDP_HLEN }, /* */ \
+ {OP_AND, 0, 0, PTP_CLASS_VMASK }, /* */ \
+ {OP_OR, 0, 0, PTP_CLASS_IPV4 }, /* */ \
+ {OP_RETA, 0, 0, 0 }, /* */ \
+/*L1x*/ {OP_RETK, 0, 0, PTP_CLASS_NONE }, /* */ \
+/*L20*/ {OP_JEQ, 0, 9, ETH_P_IPV6 }, /* f goto L40 */ \
+ {OP_LDB, 0, 0, ETH_HLEN + OFF_NEXT }, /* */ \
+ {OP_JEQ, 0, 6, IPPROTO_UDP }, /* f goto L30 */ \
+ {OP_LDH, 0, 0, OFF_DST6 }, /* */ \
+ {OP_JEQ, 0, 4, PTP_EV_PORT }, /* f goto L31 */ \
+ {OP_LDH, 0, 0, OFF_PTP6 }, /* */ \
+ {OP_AND, 0, 0, PTP_CLASS_VMASK }, /* */ \
+ {OP_OR, 0, 0, PTP_CLASS_IPV6 }, /* */ \
+ {OP_RETA, 0, 0, 0 }, /* */ \
+/*L3x*/ {OP_RETK, 0, 0, PTP_CLASS_NONE }, /* */ \
+/*L40*/ {OP_JEQ, 0, 6, ETH_P_8021Q }, /* f goto L50 */ \
+ {OP_LDH, 0, 0, OFF_ETYPE + 4 }, /* */ \
+ {OP_JEQ, 0, 9, ETH_P_1588 }, /* f goto L60 */ \
+ {OP_LDH, 0, 0, ETH_HLEN + VLAN_HLEN }, /* */ \
+ {OP_AND, 0, 0, PTP_CLASS_VMASK }, /* */ \
+ {OP_OR, 0, 0, PTP_CLASS_VLAN }, /* */ \
+ {OP_RETA, 0, 0, 0 }, /* */ \
+/*L50*/ {OP_JEQ, 0, 4, ETH_P_1588 }, /* f goto L61 */ \
+ {OP_LDH, 0, 0, ETH_HLEN }, /* */ \
+ {OP_AND, 0, 0, PTP_CLASS_VMASK }, /* */ \
+ {OP_OR, 0, 0, PTP_CLASS_L2 }, /* */ \
+ {OP_RETA, 0, 0, 0 }, /* */ \
+/*L6x*/ {OP_RETK, 0, 0, PTP_CLASS_NONE },
+
+#endif
diff --git a/include/linux/quotaops.h b/include/linux/quotaops.h
index aa36793b48b..d50ba858cfe 100644
--- a/include/linux/quotaops.h
+++ b/include/linux/quotaops.h
@@ -28,6 +28,12 @@ static inline bool is_quota_modification(struct inode *inode, struct iattr *ia)
#if defined(CONFIG_QUOTA)
+#define quota_error(sb, fmt, args...) \
+ __quota_error((sb), __func__, fmt , ## args)
+
+extern void __quota_error(struct super_block *sb, const char *func,
+ const char *fmt, ...);
+
/*
* declaration of quota_function calls in kernel.
*/
@@ -145,11 +151,6 @@ static inline bool sb_has_quota_active(struct super_block *sb, int type)
!sb_has_quota_suspended(sb, type);
}
-static inline unsigned sb_any_quota_active(struct super_block *sb)
-{
- return sb_any_quota_loaded(sb) & ~sb_any_quota_suspended(sb);
-}
-
/*
* Operations supported for diskquotas.
*/
@@ -194,11 +195,6 @@ static inline int sb_has_quota_active(struct super_block *sb, int type)
return 0;
}
-static inline int sb_any_quota_active(struct super_block *sb)
-{
- return 0;
-}
-
static inline void dquot_initialize(struct inode *inode)
{
}
@@ -270,7 +266,7 @@ static inline int dquot_alloc_space_nodirty(struct inode *inode, qsize_t nr)
static inline void dquot_alloc_space_nofail(struct inode *inode, qsize_t nr)
{
__dquot_alloc_space(inode, nr, DQUOT_SPACE_WARN|DQUOT_SPACE_NOFAIL);
- mark_inode_dirty(inode);
+ mark_inode_dirty_sync(inode);
}
static inline int dquot_alloc_space(struct inode *inode, qsize_t nr)
@@ -279,7 +275,7 @@ static inline int dquot_alloc_space(struct inode *inode, qsize_t nr)
ret = dquot_alloc_space_nodirty(inode, nr);
if (!ret)
- mark_inode_dirty(inode);
+ mark_inode_dirty_sync(inode);
return ret;
}
@@ -309,7 +305,7 @@ static inline int dquot_prealloc_block(struct inode *inode, qsize_t nr)
ret = dquot_prealloc_block_nodirty(inode, nr);
if (!ret)
- mark_inode_dirty(inode);
+ mark_inode_dirty_sync(inode);
return ret;
}
@@ -325,7 +321,7 @@ static inline int dquot_claim_block(struct inode *inode, qsize_t nr)
ret = dquot_claim_space_nodirty(inode, nr << inode->i_blkbits);
if (!ret)
- mark_inode_dirty(inode);
+ mark_inode_dirty_sync(inode);
return ret;
}
@@ -337,7 +333,7 @@ static inline void dquot_free_space_nodirty(struct inode *inode, qsize_t nr)
static inline void dquot_free_space(struct inode *inode, qsize_t nr)
{
dquot_free_space_nodirty(inode, nr);
- mark_inode_dirty(inode);
+ mark_inode_dirty_sync(inode);
}
static inline void dquot_free_block_nodirty(struct inode *inode, qsize_t nr)
diff --git a/drivers/staging/rar_register/rar_register.h b/include/linux/rar_register.h
index ffa805780f8..ffa805780f8 100644
--- a/drivers/staging/rar_register/rar_register.h
+++ b/include/linux/rar_register.h
diff --git a/include/linux/rcupdate.h b/include/linux/rcupdate.h
index b653b4aaa8a..9fbc54a2585 100644
--- a/include/linux/rcupdate.h
+++ b/include/linux/rcupdate.h
@@ -40,6 +40,7 @@
#include <linux/seqlock.h>
#include <linux/lockdep.h>
#include <linux/completion.h>
+#include <linux/debugobjects.h>
#ifdef CONFIG_RCU_TORTURE_TEST
extern int rcutorture_runnable; /* for sysctl */
@@ -79,6 +80,16 @@ extern void rcu_init(void);
(ptr)->next = NULL; (ptr)->func = NULL; \
} while (0)
+/*
+ * init_rcu_head_on_stack()/destroy_rcu_head_on_stack() are needed for dynamic
+ * initialization and destruction of rcu_head on the stack. rcu_head structures
+ * allocated dynamically in the heap or defined statically don't need any
+ * initialization.
+ */
+#ifdef CONFIG_DEBUG_OBJECTS_RCU_HEAD
+extern void init_rcu_head_on_stack(struct rcu_head *head);
+extern void destroy_rcu_head_on_stack(struct rcu_head *head);
+#else /* !CONFIG_DEBUG_OBJECTS_RCU_HEAD */
static inline void init_rcu_head_on_stack(struct rcu_head *head)
{
}
@@ -86,6 +97,7 @@ static inline void init_rcu_head_on_stack(struct rcu_head *head)
static inline void destroy_rcu_head_on_stack(struct rcu_head *head)
{
}
+#endif /* #else !CONFIG_DEBUG_OBJECTS_RCU_HEAD */
#ifdef CONFIG_DEBUG_LOCK_ALLOC
@@ -517,4 +529,74 @@ extern void call_rcu(struct rcu_head *head,
extern void call_rcu_bh(struct rcu_head *head,
void (*func)(struct rcu_head *head));
+/*
+ * debug_rcu_head_queue()/debug_rcu_head_unqueue() are used internally
+ * by call_rcu() and rcu callback execution, and are therefore not part of the
+ * RCU API. Leaving in rcupdate.h because they are used by all RCU flavors.
+ */
+
+#ifdef CONFIG_DEBUG_OBJECTS_RCU_HEAD
+# define STATE_RCU_HEAD_READY 0
+# define STATE_RCU_HEAD_QUEUED 1
+
+extern struct debug_obj_descr rcuhead_debug_descr;
+
+static inline void debug_rcu_head_queue(struct rcu_head *head)
+{
+ debug_object_activate(head, &rcuhead_debug_descr);
+ debug_object_active_state(head, &rcuhead_debug_descr,
+ STATE_RCU_HEAD_READY,
+ STATE_RCU_HEAD_QUEUED);
+}
+
+static inline void debug_rcu_head_unqueue(struct rcu_head *head)
+{
+ debug_object_active_state(head, &rcuhead_debug_descr,
+ STATE_RCU_HEAD_QUEUED,
+ STATE_RCU_HEAD_READY);
+ debug_object_deactivate(head, &rcuhead_debug_descr);
+}
+#else /* !CONFIG_DEBUG_OBJECTS_RCU_HEAD */
+static inline void debug_rcu_head_queue(struct rcu_head *head)
+{
+}
+
+static inline void debug_rcu_head_unqueue(struct rcu_head *head)
+{
+}
+#endif /* #else !CONFIG_DEBUG_OBJECTS_RCU_HEAD */
+
+#ifndef CONFIG_PROVE_RCU
+#define __do_rcu_dereference_check(c) do { } while (0)
+#endif /* #ifdef CONFIG_PROVE_RCU */
+
+#define __rcu_dereference_index_check(p, c) \
+ ({ \
+ typeof(p) _________p1 = ACCESS_ONCE(p); \
+ __do_rcu_dereference_check(c); \
+ smp_read_barrier_depends(); \
+ (_________p1); \
+ })
+
+/**
+ * rcu_dereference_index_check() - rcu_dereference for indices with debug checking
+ * @p: The pointer to read, prior to dereferencing
+ * @c: The conditions under which the dereference will take place
+ *
+ * Similar to rcu_dereference_check(), but omits the sparse checking.
+ * This allows rcu_dereference_index_check() to be used on integers,
+ * which can then be used as array indices. Attempting to use
+ * rcu_dereference_check() on an integer will give compiler warnings
+ * because the sparse address-space mechanism relies on dereferencing
+ * the RCU-protected pointer. Dereferencing integers is not something
+ * that even gcc will put up with.
+ *
+ * Note that this function does not implicitly check for RCU read-side
+ * critical sections. If this function gains lots of uses, it might
+ * make sense to provide versions for each flavor of RCU, but it does
+ * not make sense as of early 2010.
+ */
+#define rcu_dereference_index_check(p, c) \
+ __rcu_dereference_index_check((p), (c))
+
#endif /* __LINUX_RCUPDATE_H */
diff --git a/include/linux/rds.h b/include/linux/rds.h
index cab4994c2f6..24bce3ded9e 100644
--- a/include/linux/rds.h
+++ b/include/linux/rds.h
@@ -100,7 +100,7 @@
struct rds_info_counter {
u_int8_t name[32];
u_int64_t value;
-} __attribute__((packed));
+} __packed;
#define RDS_INFO_CONNECTION_FLAG_SENDING 0x01
#define RDS_INFO_CONNECTION_FLAG_CONNECTING 0x02
@@ -115,7 +115,7 @@ struct rds_info_connection {
__be32 faddr;
u_int8_t transport[TRANSNAMSIZ]; /* null term ascii */
u_int8_t flags;
-} __attribute__((packed));
+} __packed;
struct rds_info_flow {
__be32 laddr;
@@ -123,7 +123,7 @@ struct rds_info_flow {
u_int32_t bytes;
__be16 lport;
__be16 fport;
-} __attribute__((packed));
+} __packed;
#define RDS_INFO_MESSAGE_FLAG_ACK 0x01
#define RDS_INFO_MESSAGE_FLAG_FAST_ACK 0x02
@@ -136,7 +136,7 @@ struct rds_info_message {
__be16 lport;
__be16 fport;
u_int8_t flags;
-} __attribute__((packed));
+} __packed;
struct rds_info_socket {
u_int32_t sndbuf;
@@ -146,7 +146,7 @@ struct rds_info_socket {
__be16 connected_port;
u_int32_t rcvbuf;
u_int64_t inum;
-} __attribute__((packed));
+} __packed;
struct rds_info_tcp_socket {
__be32 local_addr;
@@ -158,7 +158,7 @@ struct rds_info_tcp_socket {
u_int32_t last_sent_nxt;
u_int32_t last_expected_una;
u_int32_t last_seen_una;
-} __attribute__((packed));
+} __packed;
#define RDS_IB_GID_LEN 16
struct rds_info_rdma_connection {
diff --git a/include/linux/reiserfs_fs.h b/include/linux/reiserfs_fs.h
index 3b603f47418..ba394163dea 100644
--- a/include/linux/reiserfs_fs.h
+++ b/include/linux/reiserfs_fs.h
@@ -360,7 +360,7 @@ int is_reiserfs_jr(struct reiserfs_super_block *rs);
/* the spot for the super in versions 3.5 - 3.5.10 (inclusive) */
#define REISERFS_OLD_DISK_OFFSET_IN_BYTES (8 * 1024)
-// reiserfs internal error code (used by search_by_key adn fix_nodes))
+/* reiserfs internal error code (used by search_by_key and fix_nodes)) */
#define CARRY_ON 0
#define REPEAT_SEARCH -1
#define IO_ERROR -2
diff --git a/include/linux/rtnetlink.h b/include/linux/rtnetlink.h
index fbc8cb0d48c..58d44491880 100644
--- a/include/linux/rtnetlink.h
+++ b/include/linux/rtnetlink.h
@@ -282,6 +282,7 @@ enum rtattr_type_t {
RTA_SESSION, /* no longer used */
RTA_MP_ALGO, /* no longer used */
RTA_TABLE,
+ RTA_MARK,
__RTA_MAX
};
diff --git a/include/linux/sched.h b/include/linux/sched.h
index 0478888c689..9591907c4f7 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -272,19 +272,10 @@ extern int runqueue_is_locked(int cpu);
extern cpumask_var_t nohz_cpu_mask;
#if defined(CONFIG_SMP) && defined(CONFIG_NO_HZ)
-extern int select_nohz_load_balancer(int cpu);
-extern int get_nohz_load_balancer(void);
-extern int nohz_ratelimit(int cpu);
+extern void select_nohz_load_balancer(int stop_tick);
+extern int get_nohz_timer_target(void);
#else
-static inline int select_nohz_load_balancer(int cpu)
-{
- return 0;
-}
-
-static inline int nohz_ratelimit(int cpu)
-{
- return 0;
-}
+static inline void select_nohz_load_balancer(int stop_tick) { }
#endif
/*
@@ -316,20 +307,16 @@ extern void scheduler_tick(void);
extern void sched_show_task(struct task_struct *p);
-#ifdef CONFIG_DETECT_SOFTLOCKUP
-extern void softlockup_tick(void);
+#ifdef CONFIG_LOCKUP_DETECTOR
extern void touch_softlockup_watchdog(void);
extern void touch_softlockup_watchdog_sync(void);
extern void touch_all_softlockup_watchdogs(void);
-extern int proc_dosoftlockup_thresh(struct ctl_table *table, int write,
- void __user *buffer,
- size_t *lenp, loff_t *ppos);
+extern int proc_dowatchdog_thresh(struct ctl_table *table, int write,
+ void __user *buffer,
+ size_t *lenp, loff_t *ppos);
extern unsigned int softlockup_panic;
extern int softlockup_thresh;
#else
-static inline void softlockup_tick(void)
-{
-}
static inline void touch_softlockup_watchdog(void)
{
}
@@ -805,7 +792,7 @@ enum cpu_idle_type {
#define SD_POWERSAVINGS_BALANCE 0x0100 /* Balance for power savings */
#define SD_SHARE_PKG_RESOURCES 0x0200 /* Domain members share cpu pkg resources */
#define SD_SERIALIZE 0x0400 /* Only a single load balancing instance */
-
+#define SD_ASYM_PACKING 0x0800 /* Place busy groups earlier in the domain */
#define SD_PREFER_SIBLING 0x1000 /* Prefer to place tasks in a sibling domain */
enum powersavings_balance_level {
@@ -840,6 +827,8 @@ static inline int sd_balance_for_package_power(void)
return SD_PREFER_SIBLING;
}
+extern int __weak arch_sd_sibiling_asym_packing(void);
+
/*
* Optimise SD flags for power savings:
* SD_BALANCE_NEWIDLE helps agressive task consolidation and power savings.
@@ -861,7 +850,7 @@ struct sched_group {
* CPU power of this group, SCHED_LOAD_SCALE being max power for a
* single CPU.
*/
- unsigned int cpu_power;
+ unsigned int cpu_power, cpu_power_orig;
/*
* The CPUs this group covers.
@@ -1697,6 +1686,7 @@ extern void thread_group_times(struct task_struct *p, cputime_t *ut, cputime_t *
#define PF_EXITING 0x00000004 /* getting shut down */
#define PF_EXITPIDONE 0x00000008 /* pi exit done on shut down */
#define PF_VCPU 0x00000010 /* I'm a virtual CPU */
+#define PF_WQ_WORKER 0x00000020 /* I'm a workqueue worker */
#define PF_FORKNOEXEC 0x00000040 /* forked but didn't exec */
#define PF_MCE_PROCESS 0x00000080 /* process policy on mce errors */
#define PF_SUPERPRIV 0x00000100 /* used super-user privileges */
@@ -1791,20 +1781,23 @@ static inline int set_cpus_allowed(struct task_struct *p, cpumask_t new_mask)
#endif
/*
- * Architectures can set this to 1 if they have specified
- * CONFIG_HAVE_UNSTABLE_SCHED_CLOCK in their arch Kconfig,
- * but then during bootup it turns out that sched_clock()
- * is reliable after all:
+ * Do not use outside of architecture code which knows its limitations.
+ *
+ * sched_clock() has no promise of monotonicity or bounded drift between
+ * CPUs, use (which you should not) requires disabling IRQs.
+ *
+ * Please use one of the three interfaces below.
*/
-#ifdef CONFIG_HAVE_UNSTABLE_SCHED_CLOCK
-extern int sched_clock_stable;
-#endif
-
-/* ftrace calls sched_clock() directly */
extern unsigned long long notrace sched_clock(void);
+/*
+ * See the comment in kernel/sched_clock.c
+ */
+extern u64 cpu_clock(int cpu);
+extern u64 local_clock(void);
+extern u64 sched_clock_cpu(int cpu);
+
extern void sched_clock_init(void);
-extern u64 sched_clock_cpu(int cpu);
#ifndef CONFIG_HAVE_UNSTABLE_SCHED_CLOCK
static inline void sched_clock_tick(void)
@@ -1819,17 +1812,19 @@ static inline void sched_clock_idle_wakeup_event(u64 delta_ns)
{
}
#else
+/*
+ * Architectures can set this to 1 if they have specified
+ * CONFIG_HAVE_UNSTABLE_SCHED_CLOCK in their arch Kconfig,
+ * but then during bootup it turns out that sched_clock()
+ * is reliable after all:
+ */
+extern int sched_clock_stable;
+
extern void sched_clock_tick(void);
extern void sched_clock_idle_sleep_event(void);
extern void sched_clock_idle_wakeup_event(u64 delta_ns);
#endif
-/*
- * 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);
extern unsigned long long thread_group_sched_runtime(struct task_struct *task);
@@ -2435,18 +2430,6 @@ static inline void set_task_cpu(struct task_struct *p, unsigned int cpu)
#endif /* CONFIG_SMP */
-#ifdef CONFIG_TRACING
-extern void
-__trace_special(void *__tr, void *__data,
- unsigned long arg1, unsigned long arg2, unsigned long arg3);
-#else
-static inline void
-__trace_special(void *__tr, void *__data,
- unsigned long arg1, unsigned long arg2, unsigned long arg3)
-{
-}
-#endif
-
extern long sched_setaffinity(pid_t pid, const struct cpumask *new_mask);
extern long sched_getaffinity(pid_t pid, struct cpumask *mask);
diff --git a/include/linux/sctp.h b/include/linux/sctp.h
index c20d3ce673c..c11a28706fa 100644
--- a/include/linux/sctp.h
+++ b/include/linux/sctp.h
@@ -61,7 +61,7 @@ typedef struct sctphdr {
__be16 dest;
__be32 vtag;
__le32 checksum;
-} __attribute__((packed)) sctp_sctphdr_t;
+} __packed sctp_sctphdr_t;
#ifdef __KERNEL__
#include <linux/skbuff.h>
@@ -77,7 +77,7 @@ typedef struct sctp_chunkhdr {
__u8 type;
__u8 flags;
__be16 length;
-} __attribute__((packed)) sctp_chunkhdr_t;
+} __packed sctp_chunkhdr_t;
/* Section 3.2. Chunk Type Values.
@@ -167,7 +167,7 @@ enum { SCTP_CHUNK_FLAG_T = 0x01 };
typedef struct sctp_paramhdr {
__be16 type;
__be16 length;
-} __attribute__((packed)) sctp_paramhdr_t;
+} __packed sctp_paramhdr_t;
typedef enum {
@@ -228,12 +228,12 @@ typedef struct sctp_datahdr {
__be16 ssn;
__be32 ppid;
__u8 payload[0];
-} __attribute__((packed)) sctp_datahdr_t;
+} __packed sctp_datahdr_t;
typedef struct sctp_data_chunk {
sctp_chunkhdr_t chunk_hdr;
sctp_datahdr_t data_hdr;
-} __attribute__((packed)) sctp_data_chunk_t;
+} __packed sctp_data_chunk_t;
/* DATA Chuck Specific Flags */
enum {
@@ -259,78 +259,78 @@ typedef struct sctp_inithdr {
__be16 num_inbound_streams;
__be32 initial_tsn;
__u8 params[0];
-} __attribute__((packed)) sctp_inithdr_t;
+} __packed sctp_inithdr_t;
typedef struct sctp_init_chunk {
sctp_chunkhdr_t chunk_hdr;
sctp_inithdr_t init_hdr;
-} __attribute__((packed)) sctp_init_chunk_t;
+} __packed sctp_init_chunk_t;
/* Section 3.3.2.1. IPv4 Address Parameter (5) */
typedef struct sctp_ipv4addr_param {
sctp_paramhdr_t param_hdr;
struct in_addr addr;
-} __attribute__((packed)) sctp_ipv4addr_param_t;
+} __packed sctp_ipv4addr_param_t;
/* Section 3.3.2.1. IPv6 Address Parameter (6) */
typedef struct sctp_ipv6addr_param {
sctp_paramhdr_t param_hdr;
struct in6_addr addr;
-} __attribute__((packed)) sctp_ipv6addr_param_t;
+} __packed sctp_ipv6addr_param_t;
/* Section 3.3.2.1 Cookie Preservative (9) */
typedef struct sctp_cookie_preserve_param {
sctp_paramhdr_t param_hdr;
__be32 lifespan_increment;
-} __attribute__((packed)) sctp_cookie_preserve_param_t;
+} __packed sctp_cookie_preserve_param_t;
/* Section 3.3.2.1 Host Name Address (11) */
typedef struct sctp_hostname_param {
sctp_paramhdr_t param_hdr;
uint8_t hostname[0];
-} __attribute__((packed)) sctp_hostname_param_t;
+} __packed sctp_hostname_param_t;
/* Section 3.3.2.1 Supported Address Types (12) */
typedef struct sctp_supported_addrs_param {
sctp_paramhdr_t param_hdr;
__be16 types[0];
-} __attribute__((packed)) sctp_supported_addrs_param_t;
+} __packed sctp_supported_addrs_param_t;
/* Appendix A. ECN Capable (32768) */
typedef struct sctp_ecn_capable_param {
sctp_paramhdr_t param_hdr;
-} __attribute__((packed)) sctp_ecn_capable_param_t;
+} __packed sctp_ecn_capable_param_t;
/* ADDIP Section 3.2.6 Adaptation Layer Indication */
typedef struct sctp_adaptation_ind_param {
struct sctp_paramhdr param_hdr;
__be32 adaptation_ind;
-} __attribute__((packed)) sctp_adaptation_ind_param_t;
+} __packed sctp_adaptation_ind_param_t;
/* ADDIP Section 4.2.7 Supported Extensions Parameter */
typedef struct sctp_supported_ext_param {
struct sctp_paramhdr param_hdr;
__u8 chunks[0];
-} __attribute__((packed)) sctp_supported_ext_param_t;
+} __packed sctp_supported_ext_param_t;
/* AUTH Section 3.1 Random */
typedef struct sctp_random_param {
sctp_paramhdr_t param_hdr;
__u8 random_val[0];
-} __attribute__((packed)) sctp_random_param_t;
+} __packed sctp_random_param_t;
/* AUTH Section 3.2 Chunk List */
typedef struct sctp_chunks_param {
sctp_paramhdr_t param_hdr;
__u8 chunks[0];
-} __attribute__((packed)) sctp_chunks_param_t;
+} __packed sctp_chunks_param_t;
/* AUTH Section 3.3 HMAC Algorithm */
typedef struct sctp_hmac_algo_param {
sctp_paramhdr_t param_hdr;
__be16 hmac_ids[0];
-} __attribute__((packed)) sctp_hmac_algo_param_t;
+} __packed sctp_hmac_algo_param_t;
/* RFC 2960. Section 3.3.3 Initiation Acknowledgement (INIT ACK) (2):
* The INIT ACK chunk is used to acknowledge the initiation of an SCTP
@@ -342,13 +342,13 @@ typedef sctp_init_chunk_t sctp_initack_chunk_t;
typedef struct sctp_cookie_param {
sctp_paramhdr_t p;
__u8 body[0];
-} __attribute__((packed)) sctp_cookie_param_t;
+} __packed sctp_cookie_param_t;
/* Section 3.3.3.1 Unrecognized Parameters (8) */
typedef struct sctp_unrecognized_param {
sctp_paramhdr_t param_hdr;
sctp_paramhdr_t unrecognized;
-} __attribute__((packed)) sctp_unrecognized_param_t;
+} __packed sctp_unrecognized_param_t;
@@ -363,7 +363,7 @@ typedef struct sctp_unrecognized_param {
typedef struct sctp_gap_ack_block {
__be16 start;
__be16 end;
-} __attribute__((packed)) sctp_gap_ack_block_t;
+} __packed sctp_gap_ack_block_t;
typedef __be32 sctp_dup_tsn_t;
@@ -378,12 +378,12 @@ typedef struct sctp_sackhdr {
__be16 num_gap_ack_blocks;
__be16 num_dup_tsns;
sctp_sack_variable_t variable[0];
-} __attribute__((packed)) sctp_sackhdr_t;
+} __packed sctp_sackhdr_t;
typedef struct sctp_sack_chunk {
sctp_chunkhdr_t chunk_hdr;
sctp_sackhdr_t sack_hdr;
-} __attribute__((packed)) sctp_sack_chunk_t;
+} __packed sctp_sack_chunk_t;
/* RFC 2960. Section 3.3.5 Heartbeat Request (HEARTBEAT) (4):
@@ -395,12 +395,12 @@ typedef struct sctp_sack_chunk {
typedef struct sctp_heartbeathdr {
sctp_paramhdr_t info;
-} __attribute__((packed)) sctp_heartbeathdr_t;
+} __packed sctp_heartbeathdr_t;
typedef struct sctp_heartbeat_chunk {
sctp_chunkhdr_t chunk_hdr;
sctp_heartbeathdr_t hb_hdr;
-} __attribute__((packed)) sctp_heartbeat_chunk_t;
+} __packed sctp_heartbeat_chunk_t;
/* For the abort and shutdown ACK we must carry the init tag in the
@@ -409,7 +409,7 @@ typedef struct sctp_heartbeat_chunk {
*/
typedef struct sctp_abort_chunk {
sctp_chunkhdr_t uh;
-} __attribute__((packed)) sctp_abort_chunk_t;
+} __packed sctp_abort_chunk_t;
/* For the graceful shutdown we must carry the tag (in common header)
@@ -417,12 +417,12 @@ typedef struct sctp_abort_chunk {
*/
typedef struct sctp_shutdownhdr {
__be32 cum_tsn_ack;
-} __attribute__((packed)) sctp_shutdownhdr_t;
+} __packed sctp_shutdownhdr_t;
struct sctp_shutdown_chunk_t {
sctp_chunkhdr_t chunk_hdr;
sctp_shutdownhdr_t shutdown_hdr;
-} __attribute__ ((packed));
+} __packed;
/* RFC 2960. Section 3.3.10 Operation Error (ERROR) (9) */
@@ -430,12 +430,12 @@ typedef struct sctp_errhdr {
__be16 cause;
__be16 length;
__u8 variable[0];
-} __attribute__((packed)) sctp_errhdr_t;
+} __packed sctp_errhdr_t;
typedef struct sctp_operr_chunk {
sctp_chunkhdr_t chunk_hdr;
sctp_errhdr_t err_hdr;
-} __attribute__((packed)) sctp_operr_chunk_t;
+} __packed sctp_operr_chunk_t;
/* RFC 2960 3.3.10 - Operation Error
*
@@ -525,7 +525,7 @@ typedef struct sctp_ecnehdr {
typedef struct sctp_ecne_chunk {
sctp_chunkhdr_t chunk_hdr;
sctp_ecnehdr_t ence_hdr;
-} __attribute__((packed)) sctp_ecne_chunk_t;
+} __packed sctp_ecne_chunk_t;
/* RFC 2960. Appendix A. Explicit Congestion Notification.
* Congestion Window Reduced (CWR) (13)
@@ -537,7 +537,7 @@ typedef struct sctp_cwrhdr {
typedef struct sctp_cwr_chunk {
sctp_chunkhdr_t chunk_hdr;
sctp_cwrhdr_t cwr_hdr;
-} __attribute__((packed)) sctp_cwr_chunk_t;
+} __packed sctp_cwr_chunk_t;
/* PR-SCTP
* 3.2 Forward Cumulative TSN Chunk Definition (FORWARD TSN)
@@ -588,17 +588,17 @@ typedef struct sctp_cwr_chunk {
struct sctp_fwdtsn_skip {
__be16 stream;
__be16 ssn;
-} __attribute__((packed));
+} __packed;
struct sctp_fwdtsn_hdr {
__be32 new_cum_tsn;
struct sctp_fwdtsn_skip skip[0];
-} __attribute((packed));
+} __packed;
struct sctp_fwdtsn_chunk {
struct sctp_chunkhdr chunk_hdr;
struct sctp_fwdtsn_hdr fwdtsn_hdr;
-} __attribute((packed));
+} __packed;
/* ADDIP
@@ -636,17 +636,17 @@ struct sctp_fwdtsn_chunk {
typedef struct sctp_addip_param {
sctp_paramhdr_t param_hdr;
__be32 crr_id;
-} __attribute__((packed)) sctp_addip_param_t;
+} __packed sctp_addip_param_t;
typedef struct sctp_addiphdr {
__be32 serial;
__u8 params[0];
-} __attribute__((packed)) sctp_addiphdr_t;
+} __packed sctp_addiphdr_t;
typedef struct sctp_addip_chunk {
sctp_chunkhdr_t chunk_hdr;
sctp_addiphdr_t addip_hdr;
-} __attribute__((packed)) sctp_addip_chunk_t;
+} __packed sctp_addip_chunk_t;
/* AUTH
* Section 4.1 Authentication Chunk (AUTH)
@@ -701,11 +701,11 @@ typedef struct sctp_authhdr {
__be16 shkey_id;
__be16 hmac_id;
__u8 hmac[0];
-} __attribute__((packed)) sctp_authhdr_t;
+} __packed sctp_authhdr_t;
typedef struct sctp_auth_chunk {
sctp_chunkhdr_t chunk_hdr;
sctp_authhdr_t auth_hdr;
-} __attribute__((packed)) sctp_auth_chunk_t;
+} __packed sctp_auth_chunk_t;
#endif /* __LINUX_SCTP_H__ */
diff --git a/include/linux/security.h b/include/linux/security.h
index 0c881917046..723a93df756 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -470,8 +470,6 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
* @path_truncate:
* Check permission before truncating a file.
* @path contains the path structure for the file.
- * @length is the new length of the file.
- * @time_attrs is the flags passed to do_truncate().
* Return 0 if permission is granted.
* @inode_getattr:
* Check permission before obtaining file attributes.
@@ -1412,8 +1410,7 @@ struct security_operations {
int (*path_rmdir) (struct path *dir, struct dentry *dentry);
int (*path_mknod) (struct path *dir, struct dentry *dentry, int mode,
unsigned int dev);
- int (*path_truncate) (struct path *path, loff_t length,
- unsigned int time_attrs);
+ int (*path_truncate) (struct path *path);
int (*path_symlink) (struct path *dir, struct dentry *dentry,
const char *old_name);
int (*path_link) (struct dentry *old_dentry, struct path *new_dir,
@@ -2806,8 +2803,7 @@ int security_path_mkdir(struct path *dir, struct dentry *dentry, int mode);
int security_path_rmdir(struct path *dir, struct dentry *dentry);
int security_path_mknod(struct path *dir, struct dentry *dentry, int mode,
unsigned int dev);
-int security_path_truncate(struct path *path, loff_t length,
- unsigned int time_attrs);
+int security_path_truncate(struct path *path);
int security_path_symlink(struct path *dir, struct dentry *dentry,
const char *old_name);
int security_path_link(struct dentry *old_dentry, struct path *new_dir,
@@ -2841,8 +2837,7 @@ static inline int security_path_mknod(struct path *dir, struct dentry *dentry,
return 0;
}
-static inline int security_path_truncate(struct path *path, loff_t length,
- unsigned int time_attrs)
+static inline int security_path_truncate(struct path *path)
{
return 0;
}
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
index f89e7fd59a4..d20d9e7a9bb 100644
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -169,6 +169,7 @@ struct skb_shared_hwtstamps {
* @software: generate software time stamp
* @in_progress: device driver is going to provide
* hardware time stamp
+ * @prevent_sk_orphan: make sk reference available on driver level
* @flags: all shared_tx flags
*
* These flags are attached to packets as part of the
@@ -178,7 +179,8 @@ union skb_shared_tx {
struct {
__u8 hardware:1,
software:1,
- in_progress:1;
+ in_progress:1,
+ prevent_sk_orphan:1;
};
__u8 flags;
};
@@ -202,10 +204,11 @@ struct skb_shared_info {
*/
atomic_t dataref;
- skb_frag_t frags[MAX_SKB_FRAGS];
/* Intermediate layers must ensure that destructor_arg
* remains valid until skb destructor */
void * destructor_arg;
+ /* must be last field, see pskb_expand_head() */
+ skb_frag_t frags[MAX_SKB_FRAGS];
};
/* We divide dataref into two halves. The higher 16 bits hold references
@@ -1414,12 +1417,14 @@ static inline int skb_network_offset(const struct sk_buff *skb)
*
* Various parts of the networking layer expect at least 32 bytes of
* headroom, you should not reduce this.
- * With RPS, we raised NET_SKB_PAD to 64 so that get_rps_cpus() fetches span
- * a 64 bytes aligned block to fit modern (>= 64 bytes) cache line sizes
+ *
+ * Using max(32, L1_CACHE_BYTES) makes sense (especially with RPS)
+ * to reduce average number of cache lines per packet.
+ * get_rps_cpus() for example only access one 64 bytes aligned block :
* NET_IP_ALIGN(2) + ethernet_header(14) + IP_header(20/40) + ports(8)
*/
#ifndef NET_SKB_PAD
-#define NET_SKB_PAD 64
+#define NET_SKB_PAD max(32, L1_CACHE_BYTES)
#endif
extern int ___pskb_trim(struct sk_buff *skb, unsigned int len);
@@ -1931,6 +1936,36 @@ static inline ktime_t net_invalid_timestamp(void)
return ktime_set(0, 0);
}
+extern void skb_timestamping_init(void);
+
+#ifdef CONFIG_NETWORK_PHY_TIMESTAMPING
+
+extern void skb_clone_tx_timestamp(struct sk_buff *skb);
+extern bool skb_defer_rx_timestamp(struct sk_buff *skb);
+
+#else /* CONFIG_NETWORK_PHY_TIMESTAMPING */
+
+static inline void skb_clone_tx_timestamp(struct sk_buff *skb)
+{
+}
+
+static inline bool skb_defer_rx_timestamp(struct sk_buff *skb)
+{
+ return false;
+}
+
+#endif /* !CONFIG_NETWORK_PHY_TIMESTAMPING */
+
+/**
+ * skb_complete_tx_timestamp() - deliver cloned skb with tx timestamps
+ *
+ * @skb: clone of the the original outgoing packet
+ * @hwtstamps: hardware time stamps
+ *
+ */
+void skb_complete_tx_timestamp(struct sk_buff *skb,
+ struct skb_shared_hwtstamps *hwtstamps);
+
/**
* skb_tstamp_tx - queue clone of skb with send time stamps
* @orig_skb: the original outgoing packet
@@ -1945,6 +1980,28 @@ static inline ktime_t net_invalid_timestamp(void)
extern void skb_tstamp_tx(struct sk_buff *orig_skb,
struct skb_shared_hwtstamps *hwtstamps);
+static inline void sw_tx_timestamp(struct sk_buff *skb)
+{
+ union skb_shared_tx *shtx = skb_tx(skb);
+ if (shtx->software && !shtx->in_progress)
+ skb_tstamp_tx(skb, NULL);
+}
+
+/**
+ * skb_tx_timestamp() - Driver hook for transmit timestamping
+ *
+ * Ethernet MAC Drivers should call this function in their hard_xmit()
+ * function as soon as possible after giving the sk_buff to the MAC
+ * hardware, but before freeing the sk_buff.
+ *
+ * @skb: A socket buffer.
+ */
+static inline void skb_tx_timestamp(struct sk_buff *skb)
+{
+ skb_clone_tx_timestamp(skb);
+ sw_tx_timestamp(skb);
+}
+
extern __sum16 __skb_checksum_complete_head(struct sk_buff *skb, int len);
extern __sum16 __skb_checksum_complete(struct sk_buff *skb);
@@ -2132,7 +2189,8 @@ static inline bool skb_warn_if_lro(const struct sk_buff *skb)
/* LRO sets gso_size but not gso_type, whereas if GSO is really
* wanted then gso_type will be set. */
struct skb_shared_info *shinfo = skb_shinfo(skb);
- if (shinfo->gso_size != 0 && unlikely(shinfo->gso_type == 0)) {
+ if (skb_is_nonlinear(skb) && shinfo->gso_size != 0 &&
+ unlikely(shinfo->gso_type == 0)) {
__skb_warn_lro_forwarding(skb);
return true;
}
diff --git a/include/linux/slab.h b/include/linux/slab.h
index 49d1247cd6d..59260e21bdf 100644
--- a/include/linux/slab.h
+++ b/include/linux/slab.h
@@ -268,7 +268,8 @@ static inline void *kmem_cache_alloc_node(struct kmem_cache *cachep,
* allocator where we care about the real place the memory allocation
* request comes from.
*/
-#if defined(CONFIG_DEBUG_SLAB) || defined(CONFIG_SLUB)
+#if defined(CONFIG_DEBUG_SLAB) || defined(CONFIG_SLUB) || \
+ (defined(CONFIG_SLAB) && defined(CONFIG_TRACING))
extern void *__kmalloc_track_caller(size_t, gfp_t, unsigned long);
#define kmalloc_track_caller(size, flags) \
__kmalloc_track_caller(size, flags, _RET_IP_)
@@ -286,7 +287,8 @@ extern void *__kmalloc_track_caller(size_t, gfp_t, unsigned long);
* standard allocator where we care about the real place the memory
* allocation request comes from.
*/
-#if defined(CONFIG_DEBUG_SLAB) || defined(CONFIG_SLUB)
+#if defined(CONFIG_DEBUG_SLAB) || defined(CONFIG_SLUB) || \
+ (defined(CONFIG_SLAB) && defined(CONFIG_TRACING))
extern void *__kmalloc_node_track_caller(size_t, gfp_t, int, unsigned long);
#define kmalloc_node_track_caller(size, flags, node) \
__kmalloc_node_track_caller(size, flags, node, \
diff --git a/include/linux/slab_def.h b/include/linux/slab_def.h
index 1812dac8c49..1acfa73ce2a 100644
--- a/include/linux/slab_def.h
+++ b/include/linux/slab_def.h
@@ -14,7 +14,8 @@
#include <asm/page.h> /* kmalloc_sizes.h needs PAGE_SIZE */
#include <asm/cache.h> /* kmalloc_sizes.h needs L1_CACHE_BYTES */
#include <linux/compiler.h>
-#include <linux/kmemtrace.h>
+
+#include <trace/events/kmem.h>
#ifndef ARCH_KMALLOC_MINALIGN
/*
diff --git a/include/linux/slow-work.h b/include/linux/slow-work.h
deleted file mode 100644
index 13337bf6c3f..00000000000
--- a/include/linux/slow-work.h
+++ /dev/null
@@ -1,163 +0,0 @@
-/* Worker thread pool for slow items, such as filesystem lookups or mkdirs
- *
- * Copyright (C) 2008 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 Licence
- * as published by the Free Software Foundation; either version
- * 2 of the Licence, or (at your option) any later version.
- *
- * See Documentation/slow-work.txt
- */
-
-#ifndef _LINUX_SLOW_WORK_H
-#define _LINUX_SLOW_WORK_H
-
-#ifdef CONFIG_SLOW_WORK
-
-#include <linux/sysctl.h>
-#include <linux/timer.h>
-
-struct slow_work;
-#ifdef CONFIG_SLOW_WORK_DEBUG
-struct seq_file;
-#endif
-
-/*
- * The operations used to support slow work items
- */
-struct slow_work_ops {
- /* owner */
- struct module *owner;
-
- /* get a ref on a work item
- * - return 0 if successful, -ve if not
- */
- int (*get_ref)(struct slow_work *work);
-
- /* discard a ref to a work item */
- void (*put_ref)(struct slow_work *work);
-
- /* execute a work item */
- void (*execute)(struct slow_work *work);
-
-#ifdef CONFIG_SLOW_WORK_DEBUG
- /* describe a work item for debugfs */
- void (*desc)(struct slow_work *work, struct seq_file *m);
-#endif
-};
-
-/*
- * A slow work item
- * - A reference is held on the parent object by the thread pool when it is
- * queued
- */
-struct slow_work {
- struct module *owner; /* the owning module */
- unsigned long flags;
-#define SLOW_WORK_PENDING 0 /* item pending (further) execution */
-#define SLOW_WORK_EXECUTING 1 /* item currently executing */
-#define SLOW_WORK_ENQ_DEFERRED 2 /* item enqueue deferred */
-#define SLOW_WORK_VERY_SLOW 3 /* item is very slow */
-#define SLOW_WORK_CANCELLING 4 /* item is being cancelled, don't enqueue */
-#define SLOW_WORK_DELAYED 5 /* item is struct delayed_slow_work with active timer */
- const struct slow_work_ops *ops; /* operations table for this item */
- struct list_head link; /* link in queue */
-#ifdef CONFIG_SLOW_WORK_DEBUG
- struct timespec mark; /* jiffies at which queued or exec begun */
-#endif
-};
-
-struct delayed_slow_work {
- struct slow_work work;
- struct timer_list timer;
-};
-
-/**
- * slow_work_init - Initialise a slow work item
- * @work: The work item to initialise
- * @ops: The operations to use to handle the slow work item
- *
- * Initialise a slow work item.
- */
-static inline void slow_work_init(struct slow_work *work,
- const struct slow_work_ops *ops)
-{
- work->flags = 0;
- work->ops = ops;
- INIT_LIST_HEAD(&work->link);
-}
-
-/**
- * slow_work_init - Initialise a delayed slow work item
- * @work: The work item to initialise
- * @ops: The operations to use to handle the slow work item
- *
- * Initialise a delayed slow work item.
- */
-static inline void delayed_slow_work_init(struct delayed_slow_work *dwork,
- const struct slow_work_ops *ops)
-{
- init_timer(&dwork->timer);
- slow_work_init(&dwork->work, ops);
-}
-
-/**
- * vslow_work_init - Initialise a very slow work item
- * @work: The work item to initialise
- * @ops: The operations to use to handle the slow work item
- *
- * Initialise a very slow work item. This item will be restricted such that
- * only a certain number of the pool threads will be able to execute items of
- * this type.
- */
-static inline void vslow_work_init(struct slow_work *work,
- const struct slow_work_ops *ops)
-{
- work->flags = 1 << SLOW_WORK_VERY_SLOW;
- work->ops = ops;
- INIT_LIST_HEAD(&work->link);
-}
-
-/**
- * slow_work_is_queued - Determine if a slow work item is on the work queue
- * work: The work item to test
- *
- * Determine if the specified slow-work item is on the work queue. This
- * returns true if it is actually on the queue.
- *
- * If the item is executing and has been marked for requeue when execution
- * finishes, then false will be returned.
- *
- * Anyone wishing to wait for completion of execution can wait on the
- * SLOW_WORK_EXECUTING bit.
- */
-static inline bool slow_work_is_queued(struct slow_work *work)
-{
- unsigned long flags = work->flags;
- return flags & SLOW_WORK_PENDING && !(flags & SLOW_WORK_EXECUTING);
-}
-
-extern int slow_work_enqueue(struct slow_work *work);
-extern void slow_work_cancel(struct slow_work *work);
-extern int slow_work_register_user(struct module *owner);
-extern void slow_work_unregister_user(struct module *owner);
-
-extern int delayed_slow_work_enqueue(struct delayed_slow_work *dwork,
- unsigned long delay);
-
-static inline void delayed_slow_work_cancel(struct delayed_slow_work *dwork)
-{
- slow_work_cancel(&dwork->work);
-}
-
-extern bool slow_work_sleep_till_thread_needed(struct slow_work *work,
- signed long *_timeout);
-
-#ifdef CONFIG_SYSCTL
-extern ctl_table slow_work_sysctls[];
-#endif
-
-#endif /* CONFIG_SLOW_WORK */
-#endif /* _LINUX_SLOW_WORK_H */
diff --git a/include/linux/slub_def.h b/include/linux/slub_def.h
index 4ba59cfc1f7..6447a723ecb 100644
--- a/include/linux/slub_def.h
+++ b/include/linux/slub_def.h
@@ -10,9 +10,10 @@
#include <linux/gfp.h>
#include <linux/workqueue.h>
#include <linux/kobject.h>
-#include <linux/kmemtrace.h>
#include <linux/kmemleak.h>
+#include <trace/events/kmem.h>
+
enum stat_item {
ALLOC_FASTPATH, /* Allocation from cpu slab */
ALLOC_SLOWPATH, /* Allocation by getting a new cpu slab */
diff --git a/include/linux/snmp.h b/include/linux/snmp.h
index 52797714ade..ebb0c80ffd6 100644
--- a/include/linux/snmp.h
+++ b/include/linux/snmp.h
@@ -229,6 +229,7 @@ enum
LINUX_MIB_TCPBACKLOGDROP,
LINUX_MIB_TCPMINTTLDROP, /* RFC 5082 */
LINUX_MIB_TCPDEFERACCEPTDROP,
+ LINUX_MIB_IPRPFILTER, /* IP Reverse Path Filter (rp_filter) */
__LINUX_MIB_MAX
};
diff --git a/include/linux/socket.h b/include/linux/socket.h
index 032a19eb61b..a2fada9becb 100644
--- a/include/linux/socket.h
+++ b/include/linux/socket.h
@@ -24,6 +24,9 @@ struct __kernel_sockaddr_storage {
#include <linux/types.h> /* pid_t */
#include <linux/compiler.h> /* __user */
+struct pid;
+struct cred;
+
#define __sockaddr_check_size(size) \
BUILD_BUG_ON(((size) > sizeof(struct __kernel_sockaddr_storage)))
@@ -309,6 +312,8 @@ struct ucred {
#define IPX_TYPE 1
#ifdef __KERNEL__
+extern void cred_to_ucred(struct pid *pid, const struct cred *cred, struct ucred *ucred);
+
extern int memcpy_fromiovec(unsigned char *kdata, struct iovec *iov, int len);
extern int memcpy_fromiovecend(unsigned char *kdata, const struct iovec *iov,
int offset, int len);
diff --git a/include/linux/spi/ads7846.h b/include/linux/spi/ads7846.h
index b4ae570d3c9..92bd0839d5b 100644
--- a/include/linux/spi/ads7846.h
+++ b/include/linux/spi/ads7846.h
@@ -48,11 +48,12 @@ struct ads7846_platform_data {
* state if get_pendown_state == NULL
*/
int (*get_pendown_state)(void);
- int (*filter_init) (struct ads7846_platform_data *pdata,
+ int (*filter_init) (const struct ads7846_platform_data *pdata,
void **filter_data);
int (*filter) (void *filter_data, int data_idx, int *val);
void (*filter_cleanup)(void *filter_data);
void (*wait_for_sync)(void);
bool wakeup;
+ unsigned long irq_flags;
};
diff --git a/include/linux/ssb/ssb.h b/include/linux/ssb/ssb.h
index a2608bff9c7..623b704fdc4 100644
--- a/include/linux/ssb/ssb.h
+++ b/include/linux/ssb/ssb.h
@@ -167,7 +167,7 @@ struct ssb_device {
* is an optimization. */
const struct ssb_bus_ops *ops;
- struct device *dev;
+ struct device *dev, *dma_dev;
struct ssb_bus *bus;
struct ssb_device_id id;
@@ -470,14 +470,6 @@ extern u32 ssb_dma_translation(struct ssb_device *dev);
#define SSB_DMA_TRANSLATION_MASK 0xC0000000
#define SSB_DMA_TRANSLATION_SHIFT 30
-extern int ssb_dma_set_mask(struct ssb_device *dev, u64 mask);
-
-extern void * ssb_dma_alloc_consistent(struct ssb_device *dev, size_t size,
- dma_addr_t *dma_handle, gfp_t gfp_flags);
-extern void ssb_dma_free_consistent(struct ssb_device *dev, size_t size,
- void *vaddr, dma_addr_t dma_handle,
- gfp_t gfp_flags);
-
static inline void __cold __ssb_dma_not_implemented(struct ssb_device *dev)
{
#ifdef CONFIG_SSB_DEBUG
@@ -486,155 +478,6 @@ static inline void __cold __ssb_dma_not_implemented(struct ssb_device *dev)
#endif /* DEBUG */
}
-static inline int ssb_dma_mapping_error(struct ssb_device *dev, dma_addr_t addr)
-{
- switch (dev->bus->bustype) {
- case SSB_BUSTYPE_PCI:
-#ifdef CONFIG_SSB_PCIHOST
- return pci_dma_mapping_error(dev->bus->host_pci, addr);
-#endif
- break;
- case SSB_BUSTYPE_SSB:
- return dma_mapping_error(dev->dev, addr);
- default:
- break;
- }
- __ssb_dma_not_implemented(dev);
- return -ENOSYS;
-}
-
-static inline dma_addr_t ssb_dma_map_single(struct ssb_device *dev, void *p,
- size_t size, enum dma_data_direction dir)
-{
- switch (dev->bus->bustype) {
- case SSB_BUSTYPE_PCI:
-#ifdef CONFIG_SSB_PCIHOST
- return pci_map_single(dev->bus->host_pci, p, size, dir);
-#endif
- break;
- case SSB_BUSTYPE_SSB:
- return dma_map_single(dev->dev, p, size, dir);
- default:
- break;
- }
- __ssb_dma_not_implemented(dev);
- return 0;
-}
-
-static inline void ssb_dma_unmap_single(struct ssb_device *dev, dma_addr_t dma_addr,
- size_t size, enum dma_data_direction dir)
-{
- switch (dev->bus->bustype) {
- case SSB_BUSTYPE_PCI:
-#ifdef CONFIG_SSB_PCIHOST
- pci_unmap_single(dev->bus->host_pci, dma_addr, size, dir);
- return;
-#endif
- break;
- case SSB_BUSTYPE_SSB:
- dma_unmap_single(dev->dev, dma_addr, size, dir);
- return;
- default:
- break;
- }
- __ssb_dma_not_implemented(dev);
-}
-
-static inline void ssb_dma_sync_single_for_cpu(struct ssb_device *dev,
- dma_addr_t dma_addr,
- size_t size,
- enum dma_data_direction dir)
-{
- switch (dev->bus->bustype) {
- case SSB_BUSTYPE_PCI:
-#ifdef CONFIG_SSB_PCIHOST
- pci_dma_sync_single_for_cpu(dev->bus->host_pci, dma_addr,
- size, dir);
- return;
-#endif
- break;
- case SSB_BUSTYPE_SSB:
- dma_sync_single_for_cpu(dev->dev, dma_addr, size, dir);
- return;
- default:
- break;
- }
- __ssb_dma_not_implemented(dev);
-}
-
-static inline void ssb_dma_sync_single_for_device(struct ssb_device *dev,
- dma_addr_t dma_addr,
- size_t size,
- enum dma_data_direction dir)
-{
- switch (dev->bus->bustype) {
- case SSB_BUSTYPE_PCI:
-#ifdef CONFIG_SSB_PCIHOST
- pci_dma_sync_single_for_device(dev->bus->host_pci, dma_addr,
- size, dir);
- return;
-#endif
- break;
- case SSB_BUSTYPE_SSB:
- dma_sync_single_for_device(dev->dev, dma_addr, size, dir);
- return;
- default:
- break;
- }
- __ssb_dma_not_implemented(dev);
-}
-
-static inline void ssb_dma_sync_single_range_for_cpu(struct ssb_device *dev,
- dma_addr_t dma_addr,
- unsigned long offset,
- size_t size,
- enum dma_data_direction dir)
-{
- switch (dev->bus->bustype) {
- case SSB_BUSTYPE_PCI:
-#ifdef CONFIG_SSB_PCIHOST
- /* Just sync everything. That's all the PCI API can do. */
- pci_dma_sync_single_for_cpu(dev->bus->host_pci, dma_addr,
- offset + size, dir);
- return;
-#endif
- break;
- case SSB_BUSTYPE_SSB:
- dma_sync_single_range_for_cpu(dev->dev, dma_addr, offset,
- size, dir);
- return;
- default:
- break;
- }
- __ssb_dma_not_implemented(dev);
-}
-
-static inline void ssb_dma_sync_single_range_for_device(struct ssb_device *dev,
- dma_addr_t dma_addr,
- unsigned long offset,
- size_t size,
- enum dma_data_direction dir)
-{
- switch (dev->bus->bustype) {
- case SSB_BUSTYPE_PCI:
-#ifdef CONFIG_SSB_PCIHOST
- /* Just sync everything. That's all the PCI API can do. */
- pci_dma_sync_single_for_device(dev->bus->host_pci, dma_addr,
- offset + size, dir);
- return;
-#endif
- break;
- case SSB_BUSTYPE_SSB:
- dma_sync_single_range_for_device(dev->dev, dma_addr, offset,
- size, dir);
- return;
- default:
- break;
- }
- __ssb_dma_not_implemented(dev);
-}
-
-
#ifdef CONFIG_SSB_PCIHOST
/* PCI-host wrapper driver */
extern int ssb_pcihost_register(struct pci_driver *driver);
diff --git a/include/linux/sunrpc/auth.h b/include/linux/sunrpc/auth.h
index 87d7ec0bf77..5bbc447175d 100644
--- a/include/linux/sunrpc/auth.h
+++ b/include/linux/sunrpc/auth.h
@@ -61,13 +61,7 @@ struct rpc_cred {
/*
* Client authentication handle
*/
-#define RPC_CREDCACHE_HASHBITS 4
-#define RPC_CREDCACHE_NR (1 << RPC_CREDCACHE_HASHBITS)
-struct rpc_cred_cache {
- struct hlist_head hashtable[RPC_CREDCACHE_NR];
- spinlock_t lock;
-};
-
+struct rpc_cred_cache;
struct rpc_authops;
struct rpc_auth {
unsigned int au_cslack; /* call cred size estimate */
@@ -112,7 +106,7 @@ struct rpc_credops {
void (*crdestroy)(struct rpc_cred *);
int (*crmatch)(struct auth_cred *, struct rpc_cred *, int);
- void (*crbind)(struct rpc_task *, struct rpc_cred *, int);
+ struct rpc_cred * (*crbind)(struct rpc_task *, struct rpc_cred *, int);
__be32 * (*crmarshal)(struct rpc_task *, __be32 *);
int (*crrefresh)(struct rpc_task *);
__be32 * (*crvalidate)(struct rpc_task *, __be32 *);
@@ -125,11 +119,12 @@ struct rpc_credops {
extern const struct rpc_authops authunix_ops;
extern const struct rpc_authops authnull_ops;
-void __init rpc_init_authunix(void);
-void __init rpc_init_generic_auth(void);
-void __init rpcauth_init_module(void);
+int __init rpc_init_authunix(void);
+int __init rpc_init_generic_auth(void);
+int __init rpcauth_init_module(void);
void __exit rpcauth_remove_module(void);
void __exit rpc_destroy_generic_auth(void);
+void rpc_destroy_authunix(void);
struct rpc_cred * rpc_lookup_cred(void);
struct rpc_cred * rpc_lookup_machine_cred(void);
@@ -140,10 +135,8 @@ 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);
-void rpcauth_bindcred(struct rpc_task *, struct rpc_cred *, int);
-void rpcauth_generic_bind_cred(struct rpc_task *, struct rpc_cred *, int);
+struct rpc_cred * rpcauth_generic_bind_cred(struct rpc_task *, struct rpc_cred *, int);
void put_rpccred(struct rpc_cred *);
-void rpcauth_unbindcred(struct rpc_task *);
__be32 * rpcauth_marshcred(struct rpc_task *, __be32 *);
__be32 * rpcauth_checkverf(struct rpc_task *, __be32 *);
int rpcauth_wrap_req(struct rpc_task *task, kxdrproc_t encode, void *rqstp, __be32 *data, void *obj);
diff --git a/include/linux/sunrpc/cache.h b/include/linux/sunrpc/cache.h
index 6f52b4d7c44..7bf3e84b92f 100644
--- a/include/linux/sunrpc/cache.h
+++ b/include/linux/sunrpc/cache.h
@@ -192,6 +192,7 @@ extern int cache_check(struct cache_detail *detail,
extern void cache_flush(void);
extern void cache_purge(struct cache_detail *detail);
#define NEVER (0x7FFFFFFF)
+extern void __init cache_initialize(void);
extern int cache_register(struct cache_detail *cd);
extern void cache_unregister(struct cache_detail *cd);
diff --git a/include/linux/sunrpc/clnt.h b/include/linux/sunrpc/clnt.h
index 8ed9642a5a7..569dc722a60 100644
--- a/include/linux/sunrpc/clnt.h
+++ b/include/linux/sunrpc/clnt.h
@@ -131,6 +131,7 @@ struct rpc_clnt *rpc_bind_new_program(struct rpc_clnt *,
struct rpc_clnt *rpc_clone_client(struct rpc_clnt *);
void rpc_shutdown_client(struct rpc_clnt *);
void rpc_release_client(struct rpc_clnt *);
+void rpc_task_release_client(struct rpc_task *);
int rpcb_register(u32, u32, int, unsigned short);
int rpcb_v4_register(const u32 program, const u32 version,
@@ -148,8 +149,8 @@ int rpc_call_sync(struct rpc_clnt *clnt,
const 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_prepare(struct rpc_task *);
-void rpc_restart_call(struct rpc_task *);
+int rpc_restart_call_prepare(struct rpc_task *);
+int rpc_restart_call(struct rpc_task *);
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 *);
diff --git a/include/linux/sunrpc/sched.h b/include/linux/sunrpc/sched.h
index 7be4f3a6d24..88513fd8e20 100644
--- a/include/linux/sunrpc/sched.h
+++ b/include/linux/sunrpc/sched.h
@@ -213,6 +213,7 @@ struct rpc_task *rpc_run_bc_task(struct rpc_rqst *req,
const struct rpc_call_ops *ops);
void rpc_put_task(struct rpc_task *);
void rpc_exit_task(struct rpc_task *);
+void rpc_exit(struct rpc_task *, int);
void rpc_release_calldata(const struct rpc_call_ops *, void *);
void rpc_killall_tasks(struct rpc_clnt *);
void rpc_execute(struct rpc_task *);
@@ -241,12 +242,6 @@ void rpc_destroy_mempool(void);
extern struct workqueue_struct *rpciod_workqueue;
void rpc_prepare_task(struct rpc_task *task);
-static inline void rpc_exit(struct rpc_task *task, int status)
-{
- task->tk_status = status;
- task->tk_action = rpc_exit_task;
-}
-
static inline int rpc_wait_for_completion_task(struct rpc_task *task)
{
return __rpc_wait_for_completion_task(task, NULL);
diff --git a/include/linux/sunrpc/xprt.h b/include/linux/sunrpc/xprt.h
index b5147030239..ff5a77b28c5 100644
--- a/include/linux/sunrpc/xprt.h
+++ b/include/linux/sunrpc/xprt.h
@@ -64,6 +64,7 @@ struct rpc_rqst {
* This is the private part
*/
struct rpc_task * rq_task; /* RPC task data */
+ struct rpc_cred * rq_cred; /* Bound cred */
__be32 rq_xid; /* request XID */
int rq_cong; /* has incremented xprt->cong */
u32 rq_seqno; /* gss seq no. used on req. */
diff --git a/include/linux/suspend.h b/include/linux/suspend.h
index bc7d6bb4cd8..4af270ec220 100644
--- a/include/linux/suspend.h
+++ b/include/linux/suspend.h
@@ -61,14 +61,15 @@ typedef int __bitwise suspend_state_t;
* before device drivers' late suspend callbacks are executed. It returns
* 0 on success or a negative error code otherwise, in which case the
* system cannot enter the desired sleep state (@prepare_late(), @enter(),
- * @wake(), and @finish() will not be called in that case).
+ * and @wake() will not be called in that case).
*
* @prepare_late: Finish preparing the platform for entering the system sleep
* state indicated by @begin().
* @prepare_late is called before disabling nonboot CPUs and after
* device drivers' late suspend callbacks have been executed. It returns
* 0 on success or a negative error code otherwise, in which case the
- * system cannot enter the desired sleep state (@enter() and @wake()).
+ * system cannot enter the desired sleep state (@enter() will not be
+ * executed).
*
* @enter: Enter the system sleep state indicated by @begin() or represented by
* the argument if @begin() is not implemented.
@@ -81,14 +82,15 @@ typedef int __bitwise suspend_state_t;
* resume callbacks are executed.
* This callback is optional, but should be implemented by the platforms
* that implement @prepare_late(). If implemented, it is always called
- * after @enter(), even if @enter() fails.
+ * after @prepare_late and @enter(), even if one of them fails.
*
* @finish: Finish wake-up of the platform.
* @finish is called right prior to calling device drivers' regular suspend
* callbacks.
* This callback is optional, but should be implemented by the platforms
* that implement @prepare(). If implemented, it is always called after
- * @enter() and @wake(), if implemented, even if any of them fails.
+ * @enter() and @wake(), even if any of them fails. It is executed after
+ * a failing @prepare.
*
* @end: Called by the PM core right after resuming devices, to indicate to
* the platform that the system has returned to the working state or
@@ -286,6 +288,13 @@ extern int unregister_pm_notifier(struct notifier_block *nb);
{ .notifier_call = fn, .priority = pri }; \
register_pm_notifier(&fn##_nb); \
}
+
+/* drivers/base/power/wakeup.c */
+extern bool events_check_enabled;
+
+extern bool pm_check_wakeup_events(void);
+extern bool pm_get_wakeup_count(unsigned long *count);
+extern bool pm_save_wakeup_count(unsigned long count);
#else /* !CONFIG_PM_SLEEP */
static inline int register_pm_notifier(struct notifier_block *nb)
diff --git a/include/linux/swiotlb.h b/include/linux/swiotlb.h
index 81a4e213c6c..8c0e349f4a6 100644
--- a/include/linux/swiotlb.h
+++ b/include/linux/swiotlb.h
@@ -23,6 +23,29 @@ extern int swiotlb_force;
#define IO_TLB_SHIFT 11
extern void swiotlb_init(int verbose);
+extern void swiotlb_init_with_tbl(char *tlb, unsigned long nslabs, int verbose);
+
+/*
+ * Enumeration for sync targets
+ */
+enum dma_sync_target {
+ SYNC_FOR_CPU = 0,
+ SYNC_FOR_DEVICE = 1,
+};
+extern void *swiotlb_tbl_map_single(struct device *hwdev, dma_addr_t tbl_dma_addr,
+ phys_addr_t phys, size_t size,
+ enum dma_data_direction dir);
+
+extern void swiotlb_tbl_unmap_single(struct device *hwdev, char *dma_addr,
+ size_t size, enum dma_data_direction dir);
+
+extern void swiotlb_tbl_sync_single(struct device *hwdev, char *dma_addr,
+ size_t size, enum dma_data_direction dir,
+ enum dma_sync_target target);
+
+/* Accessory functions. */
+extern void swiotlb_bounce(phys_addr_t phys, char *dma_addr, size_t size,
+ enum dma_data_direction dir);
extern void
*swiotlb_alloc_coherent(struct device *hwdev, size_t size,
@@ -42,11 +65,11 @@ extern void swiotlb_unmap_page(struct device *hwdev, dma_addr_t dev_addr,
extern int
swiotlb_map_sg(struct device *hwdev, struct scatterlist *sg, int nents,
- int direction);
+ enum dma_data_direction dir);
extern void
swiotlb_unmap_sg(struct device *hwdev, struct scatterlist *sg, int nents,
- int direction);
+ enum dma_data_direction dir);
extern int
swiotlb_map_sg_attrs(struct device *hwdev, struct scatterlist *sgl, int nelems,
diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h
index 13ebb5413a7..a6bfd1367d2 100644
--- a/include/linux/syscalls.h
+++ b/include/linux/syscalls.h
@@ -167,7 +167,6 @@ extern struct trace_event_functions exit_syscall_print_funcs;
.enter_event = &event_enter_##sname, \
.exit_event = &event_exit_##sname, \
.enter_fields = LIST_HEAD_INIT(__syscall_meta_##sname.enter_fields), \
- .exit_fields = LIST_HEAD_INIT(__syscall_meta_##sname.exit_fields), \
};
#define SYSCALL_DEFINE0(sname) \
@@ -182,7 +181,6 @@ extern struct trace_event_functions exit_syscall_print_funcs;
.enter_event = &event_enter__##sname, \
.exit_event = &event_exit__##sname, \
.enter_fields = LIST_HEAD_INIT(__syscall_meta__##sname.enter_fields), \
- .exit_fields = LIST_HEAD_INIT(__syscall_meta__##sname.exit_fields), \
}; \
asmlinkage long sys_##sname(void)
#else
diff --git a/include/linux/sysfs.h b/include/linux/sysfs.h
index f2694eb4dd3..3c92121ba9a 100644
--- a/include/linux/sysfs.h
+++ b/include/linux/sysfs.h
@@ -22,14 +22,8 @@ struct kobject;
struct module;
enum kobj_ns_type;
-/* FIXME
- * The *owner field is no longer used.
- * x86 tree has been cleaned up. The owner
- * attribute is still left for other arches.
- */
struct attribute {
const char *name;
- struct module *owner;
mode_t mode;
#ifdef CONFIG_DEBUG_LOCK_ALLOC
struct lock_class_key *key;
@@ -136,8 +130,8 @@ int __must_check sysfs_create_file(struct kobject *kobj,
const struct attribute *attr);
int __must_check sysfs_create_files(struct kobject *kobj,
const struct attribute **attr);
-int __must_check sysfs_chmod_file(struct kobject *kobj, struct attribute *attr,
- mode_t mode);
+int __must_check sysfs_chmod_file(struct kobject *kobj,
+ const struct attribute *attr, mode_t mode);
void sysfs_remove_file(struct kobject *kobj, const struct attribute *attr);
void sysfs_remove_files(struct kobject *kobj, const struct attribute **attr);
@@ -225,7 +219,7 @@ static inline int sysfs_create_files(struct kobject *kobj,
}
static inline int sysfs_chmod_file(struct kobject *kobj,
- struct attribute *attr, mode_t mode)
+ const struct attribute *attr, mode_t mode)
{
return 0;
}
diff --git a/include/linux/time.h b/include/linux/time.h
index ea3559f0b3f..cb34e35faba 100644
--- a/include/linux/time.h
+++ b/include/linux/time.h
@@ -76,9 +76,25 @@ extern unsigned long mktime(const unsigned int year, const unsigned int mon,
const unsigned int min, const unsigned int sec);
extern void set_normalized_timespec(struct timespec *ts, time_t sec, s64 nsec);
+
+/*
+ * timespec_add_safe assumes both values are positive and checks
+ * for overflow. It will return TIME_T_MAX if the reutrn would be
+ * smaller then either of the arguments.
+ */
extern struct timespec timespec_add_safe(const struct timespec lhs,
const struct timespec rhs);
+
+static inline struct timespec timespec_add(struct timespec lhs,
+ struct timespec rhs)
+{
+ struct timespec ts_delta;
+ set_normalized_timespec(&ts_delta, lhs.tv_sec + rhs.tv_sec,
+ lhs.tv_nsec + rhs.tv_nsec);
+ return ts_delta;
+}
+
/*
* sub = lhs - rhs, in normalized form
*/
@@ -97,8 +113,6 @@ static inline struct timespec timespec_sub(struct timespec lhs,
#define timespec_valid(ts) \
(((ts)->tv_sec >= 0) && (((unsigned long) (ts)->tv_nsec) < NSEC_PER_SEC))
-extern struct timespec xtime;
-extern struct timespec wall_to_monotonic;
extern seqlock_t xtime_lock;
extern void read_persistent_clock(struct timespec *ts);
@@ -110,7 +124,8 @@ extern int timekeeping_suspended;
unsigned long get_seconds(void);
struct timespec current_kernel_time(void);
-struct timespec __current_kernel_time(void); /* does not hold xtime_lock */
+struct timespec __current_kernel_time(void); /* does not take xtime_lock */
+struct timespec __get_wall_to_monotonic(void); /* does not take xtime_lock */
struct timespec get_monotonic_coarse(void);
#define CURRENT_TIME (current_kernel_time())
diff --git a/include/linux/timer.h b/include/linux/timer.h
index ea965b857a5..38cf093ef62 100644
--- a/include/linux/timer.h
+++ b/include/linux/timer.h
@@ -100,6 +100,13 @@ void init_timer_deferrable_key(struct timer_list *timer,
setup_timer_on_stack_key((timer), #timer, &__key, \
(fn), (data)); \
} while (0)
+#define setup_deferrable_timer_on_stack(timer, fn, data) \
+ do { \
+ static struct lock_class_key __key; \
+ setup_deferrable_timer_on_stack_key((timer), #timer, \
+ &__key, (fn), \
+ (data)); \
+ } while (0)
#else
#define init_timer(timer)\
init_timer_key((timer), NULL, NULL)
@@ -111,6 +118,8 @@ void init_timer_deferrable_key(struct timer_list *timer,
setup_timer_key((timer), NULL, NULL, (fn), (data))
#define setup_timer_on_stack(timer, fn, data)\
setup_timer_on_stack_key((timer), NULL, NULL, (fn), (data))
+#define setup_deferrable_timer_on_stack(timer, fn, data)\
+ setup_deferrable_timer_on_stack_key((timer), NULL, NULL, (fn), (data))
#endif
#ifdef CONFIG_DEBUG_OBJECTS_TIMERS
@@ -150,6 +159,12 @@ static inline void setup_timer_on_stack_key(struct timer_list *timer,
init_timer_on_stack_key(timer, name, key);
}
+extern void setup_deferrable_timer_on_stack_key(struct timer_list *timer,
+ const char *name,
+ struct lock_class_key *key,
+ void (*function)(unsigned long),
+ unsigned long data);
+
/**
* timer_pending - is a timer pending?
* @timer: the timer in question
diff --git a/include/linux/topology.h b/include/linux/topology.h
index c44df50a05a..b572e432d2f 100644
--- a/include/linux/topology.h
+++ b/include/linux/topology.h
@@ -103,6 +103,7 @@ int arch_update_cpu_topology(void);
| 1*SD_SHARE_PKG_RESOURCES \
| 0*SD_SERIALIZE \
| 0*SD_PREFER_SIBLING \
+ | arch_sd_sibling_asym_packing() \
, \
.last_balance = jiffies, \
.balance_interval = 1, \
diff --git a/include/linux/tty.h b/include/linux/tty.h
index 931078b7322..7802a243ee1 100644
--- a/include/linux/tty.h
+++ b/include/linux/tty.h
@@ -552,6 +552,9 @@ static inline void tty_audit_push_task(struct task_struct *tsk,
}
#endif
+/* tty_io.c */
+extern int __init tty_init(void);
+
/* tty_ioctl.c */
extern int n_tty_ioctl_helper(struct tty_struct *tty, struct file *file,
unsigned int cmd, unsigned long arg);
diff --git a/include/linux/types.h b/include/linux/types.h
index 23d237a075e..331d8baabcf 100644
--- a/include/linux/types.h
+++ b/include/linux/types.h
@@ -8,7 +8,10 @@
#define DECLARE_BITMAP(name,bits) \
unsigned long name[BITS_TO_LONGS(bits)]
-
+#else
+#ifndef __EXPORTED_HEADERS__
+#warning "Attempt to use kernel headers from user space, see http://kernelnewbies.org/KernelHeaders"
+#endif /* __EXPORTED_HEADERS__ */
#endif
#include <linux/posix_types.h>
diff --git a/include/linux/u64_stats_sync.h b/include/linux/u64_stats_sync.h
new file mode 100644
index 00000000000..fa261a0da28
--- /dev/null
+++ b/include/linux/u64_stats_sync.h
@@ -0,0 +1,140 @@
+#ifndef _LINUX_U64_STATS_SYNC_H
+#define _LINUX_U64_STATS_SYNC_H
+
+/*
+ * To properly implement 64bits network statistics on 32bit and 64bit hosts,
+ * we provide a synchronization point, that is a noop on 64bit or UP kernels.
+ *
+ * Key points :
+ * 1) Use a seqcount on SMP 32bits, with low overhead.
+ * 2) Whole thing is a noop on 64bit arches or UP kernels.
+ * 3) Write side must ensure mutual exclusion or one seqcount update could
+ * be lost, thus blocking readers forever.
+ * If this synchronization point is not a mutex, but a spinlock or
+ * spinlock_bh() or disable_bh() :
+ * 3.1) Write side should not sleep.
+ * 3.2) Write side should not allow preemption.
+ * 3.3) If applicable, interrupts should be disabled.
+ *
+ * 4) If reader fetches several counters, there is no guarantee the whole values
+ * are consistent (remember point 1) : this is a noop on 64bit arches anyway)
+ *
+ * 5) readers are allowed to sleep or be preempted/interrupted : They perform
+ * pure reads. But if they have to fetch many values, it's better to not allow
+ * preemptions/interruptions to avoid many retries.
+ *
+ * 6) If counter might be written by an interrupt, readers should block interrupts.
+ * (On UP, there is no seqcount_t protection, a reader allowing interrupts could
+ * read partial values)
+ *
+ * 7) For softirq uses, readers can use u64_stats_fetch_begin_bh() and
+ * u64_stats_fetch_retry_bh() helpers
+ *
+ * Usage :
+ *
+ * Stats producer (writer) should use following template granted it already got
+ * an exclusive access to counters (a lock is already taken, or per cpu
+ * data is used [in a non preemptable context])
+ *
+ * spin_lock_bh(...) or other synchronization to get exclusive access
+ * ...
+ * u64_stats_update_begin(&stats->syncp);
+ * stats->bytes64 += len; // non atomic operation
+ * stats->packets64++; // non atomic operation
+ * u64_stats_update_end(&stats->syncp);
+ *
+ * While a consumer (reader) should use following template to get consistent
+ * snapshot for each variable (but no guarantee on several ones)
+ *
+ * u64 tbytes, tpackets;
+ * unsigned int start;
+ *
+ * do {
+ * start = u64_stats_fetch_begin(&stats->syncp);
+ * tbytes = stats->bytes64; // non atomic operation
+ * tpackets = stats->packets64; // non atomic operation
+ * } while (u64_stats_fetch_retry(&stats->syncp, start));
+ *
+ *
+ * Example of use in drivers/net/loopback.c, using per_cpu containers,
+ * in BH disabled context.
+ */
+#include <linux/seqlock.h>
+
+struct u64_stats_sync {
+#if BITS_PER_LONG==32 && defined(CONFIG_SMP)
+ seqcount_t seq;
+#endif
+};
+
+static void inline u64_stats_update_begin(struct u64_stats_sync *syncp)
+{
+#if BITS_PER_LONG==32 && defined(CONFIG_SMP)
+ write_seqcount_begin(&syncp->seq);
+#endif
+}
+
+static void inline u64_stats_update_end(struct u64_stats_sync *syncp)
+{
+#if BITS_PER_LONG==32 && defined(CONFIG_SMP)
+ write_seqcount_end(&syncp->seq);
+#endif
+}
+
+static unsigned int inline u64_stats_fetch_begin(const struct u64_stats_sync *syncp)
+{
+#if BITS_PER_LONG==32 && defined(CONFIG_SMP)
+ return read_seqcount_begin(&syncp->seq);
+#else
+#if BITS_PER_LONG==32
+ preempt_disable();
+#endif
+ return 0;
+#endif
+}
+
+static bool inline u64_stats_fetch_retry(const struct u64_stats_sync *syncp,
+ unsigned int start)
+{
+#if BITS_PER_LONG==32 && defined(CONFIG_SMP)
+ return read_seqcount_retry(&syncp->seq, start);
+#else
+#if BITS_PER_LONG==32
+ preempt_enable();
+#endif
+ return false;
+#endif
+}
+
+/*
+ * In case softirq handlers can update u64 counters, readers can use following helpers
+ * - SMP 32bit arches use seqcount protection, irq safe.
+ * - UP 32bit must disable BH.
+ * - 64bit have no problem atomically reading u64 values, irq safe.
+ */
+static unsigned int inline u64_stats_fetch_begin_bh(const struct u64_stats_sync *syncp)
+{
+#if BITS_PER_LONG==32 && defined(CONFIG_SMP)
+ return read_seqcount_begin(&syncp->seq);
+#else
+#if BITS_PER_LONG==32
+ local_bh_disable();
+#endif
+ return 0;
+#endif
+}
+
+static bool inline u64_stats_fetch_retry_bh(const struct u64_stats_sync *syncp,
+ unsigned int start)
+{
+#if BITS_PER_LONG==32 && defined(CONFIG_SMP)
+ return read_seqcount_retry(&syncp->seq, start);
+#else
+#if BITS_PER_LONG==32
+ local_bh_enable();
+#endif
+ return false;
+#endif
+}
+
+#endif /* _LINUX_U64_STATS_SYNC_H */
diff --git a/include/linux/usb/audio-v2.h b/include/linux/usb/audio-v2.h
index 383b94ba8c2..964cb603f7c 100644
--- a/include/linux/usb/audio-v2.h
+++ b/include/linux/usb/audio-v2.h
@@ -18,6 +18,21 @@
/* v1.0 and v2.0 of this standard have many things in common. For the rest
* of the definitions, please refer to audio.h */
+/*
+ * bmControl field decoders
+ *
+ * From the USB Audio spec v2.0:
+ *
+ * bmaControls() is a (ch+1)-element array of 4-byte bitmaps,
+ * each containing a set of bit pairs. If a Control is present,
+ * it must be Host readable. If a certain Control is not
+ * present then the bit pair must be set to 0b00.
+ * If a Control is present but read-only, the bit pair must be
+ * set to 0b01. If a Control is also Host programmable, the bit
+ * pair must be set to 0b11. The value 0b10 is not allowed.
+ *
+ */
+
static inline bool uac2_control_is_readable(u32 bmControls, u8 control)
{
return (bmControls >> (control * 2)) & 0x1;
@@ -121,7 +136,7 @@ struct uac2_feature_unit_descriptor {
/* 4.9.2 Class-Specific AS Interface Descriptor */
-struct uac_as_header_descriptor_v2 {
+struct uac2_as_header_descriptor {
__u8 bLength;
__u8 bDescriptorType;
__u8 bDescriptorSubtype;
diff --git a/include/linux/usb/audio.h b/include/linux/usb/audio.h
index c51200c715e..a54b8255d75 100644
--- a/include/linux/usb/audio.h
+++ b/include/linux/usb/audio.h
@@ -39,8 +39,8 @@
#define UAC_MIXER_UNIT 0x04
#define UAC_SELECTOR_UNIT 0x05
#define UAC_FEATURE_UNIT 0x06
-#define UAC_PROCESSING_UNIT_V1 0x07
-#define UAC_EXTENSION_UNIT_V1 0x08
+#define UAC1_PROCESSING_UNIT 0x07
+#define UAC1_EXTENSION_UNIT 0x08
/* A.6 Audio Class-Specific AS Interface Descriptor Subtypes */
#define UAC_AS_GENERAL 0x01
@@ -151,7 +151,7 @@
/* Terminal Control Selectors */
/* 4.3.2 Class-Specific AC Interface Descriptor */
-struct uac_ac_header_descriptor_v1 {
+struct uac1_ac_header_descriptor {
__u8 bLength; /* 8 + n */
__u8 bDescriptorType; /* USB_DT_CS_INTERFACE */
__u8 bDescriptorSubtype; /* UAC_MS_HEADER */
@@ -165,7 +165,7 @@ struct uac_ac_header_descriptor_v1 {
/* As above, but more useful for defining your own descriptors: */
#define DECLARE_UAC_AC_HEADER_DESCRIPTOR(n) \
-struct uac_ac_header_descriptor_v1_##n { \
+struct uac1_ac_header_descriptor_##n { \
__u8 bLength; \
__u8 bDescriptorType; \
__u8 bDescriptorSubtype; \
@@ -205,7 +205,7 @@ struct uac_input_terminal_descriptor {
#define UAC_TERMINAL_CS_COPY_PROTECT_CONTROL 0x01
/* 4.3.2.2 Output Terminal Descriptor */
-struct uac_output_terminal_descriptor_v1 {
+struct uac1_output_terminal_descriptor {
__u8 bLength; /* in bytes: 9 */
__u8 bDescriptorType; /* CS_INTERFACE descriptor type */
__u8 bDescriptorSubtype; /* OUTPUT_TERMINAL descriptor subtype */
@@ -395,7 +395,7 @@ static inline __u8 *uac_processing_unit_specific(struct uac_processing_unit_desc
}
/* 4.5.2 Class-Specific AS Interface Descriptor */
-struct uac_as_header_descriptor_v1 {
+struct uac1_as_header_descriptor {
__u8 bLength; /* in bytes: 7 */
__u8 bDescriptorType; /* USB_DT_CS_INTERFACE */
__u8 bDescriptorSubtype; /* AS_GENERAL */
diff --git a/include/linux/usb/video.h b/include/linux/usb/video.h
index be436d9ee47..3b3b95e01f7 100644
--- a/include/linux/usb/video.h
+++ b/include/linux/usb/video.h
@@ -160,5 +160,409 @@
#define UVC_STATUS_TYPE_CONTROL 1
#define UVC_STATUS_TYPE_STREAMING 2
+/* 2.4.3.3. Payload Header Information */
+#define UVC_STREAM_EOH (1 << 7)
+#define UVC_STREAM_ERR (1 << 6)
+#define UVC_STREAM_STI (1 << 5)
+#define UVC_STREAM_RES (1 << 4)
+#define UVC_STREAM_SCR (1 << 3)
+#define UVC_STREAM_PTS (1 << 2)
+#define UVC_STREAM_EOF (1 << 1)
+#define UVC_STREAM_FID (1 << 0)
+
+/* 4.1.2. Control Capabilities */
+#define UVC_CONTROL_CAP_GET (1 << 0)
+#define UVC_CONTROL_CAP_SET (1 << 1)
+#define UVC_CONTROL_CAP_DISABLED (1 << 2)
+#define UVC_CONTROL_CAP_AUTOUPDATE (1 << 3)
+#define UVC_CONTROL_CAP_ASYNCHRONOUS (1 << 4)
+
+/* ------------------------------------------------------------------------
+ * UVC structures
+ */
+
+/* All UVC descriptors have these 3 fields at the beginning */
+struct uvc_descriptor_header {
+ __u8 bLength;
+ __u8 bDescriptorType;
+ __u8 bDescriptorSubType;
+} __attribute__((packed));
+
+/* 3.7.2. Video Control Interface Header Descriptor */
+struct uvc_header_descriptor {
+ __u8 bLength;
+ __u8 bDescriptorType;
+ __u8 bDescriptorSubType;
+ __u16 bcdUVC;
+ __u16 wTotalLength;
+ __u32 dwClockFrequency;
+ __u8 bInCollection;
+ __u8 baInterfaceNr[];
+} __attribute__((__packed__));
+
+#define UVC_DT_HEADER_SIZE(n) (12+(n))
+
+#define UVC_HEADER_DESCRIPTOR(n) \
+ uvc_header_descriptor_##n
+
+#define DECLARE_UVC_HEADER_DESCRIPTOR(n) \
+struct UVC_HEADER_DESCRIPTOR(n) { \
+ __u8 bLength; \
+ __u8 bDescriptorType; \
+ __u8 bDescriptorSubType; \
+ __u16 bcdUVC; \
+ __u16 wTotalLength; \
+ __u32 dwClockFrequency; \
+ __u8 bInCollection; \
+ __u8 baInterfaceNr[n]; \
+} __attribute__ ((packed))
+
+/* 3.7.2.1. Input Terminal Descriptor */
+struct uvc_input_terminal_descriptor {
+ __u8 bLength;
+ __u8 bDescriptorType;
+ __u8 bDescriptorSubType;
+ __u8 bTerminalID;
+ __u16 wTerminalType;
+ __u8 bAssocTerminal;
+ __u8 iTerminal;
+} __attribute__((__packed__));
+
+#define UVC_DT_INPUT_TERMINAL_SIZE 8
+
+/* 3.7.2.2. Output Terminal Descriptor */
+struct uvc_output_terminal_descriptor {
+ __u8 bLength;
+ __u8 bDescriptorType;
+ __u8 bDescriptorSubType;
+ __u8 bTerminalID;
+ __u16 wTerminalType;
+ __u8 bAssocTerminal;
+ __u8 bSourceID;
+ __u8 iTerminal;
+} __attribute__((__packed__));
+
+#define UVC_DT_OUTPUT_TERMINAL_SIZE 9
+
+/* 3.7.2.3. Camera Terminal Descriptor */
+struct uvc_camera_terminal_descriptor {
+ __u8 bLength;
+ __u8 bDescriptorType;
+ __u8 bDescriptorSubType;
+ __u8 bTerminalID;
+ __u16 wTerminalType;
+ __u8 bAssocTerminal;
+ __u8 iTerminal;
+ __u16 wObjectiveFocalLengthMin;
+ __u16 wObjectiveFocalLengthMax;
+ __u16 wOcularFocalLength;
+ __u8 bControlSize;
+ __u8 bmControls[3];
+} __attribute__((__packed__));
+
+#define UVC_DT_CAMERA_TERMINAL_SIZE(n) (15+(n))
+
+/* 3.7.2.4. Selector Unit Descriptor */
+struct uvc_selector_unit_descriptor {
+ __u8 bLength;
+ __u8 bDescriptorType;
+ __u8 bDescriptorSubType;
+ __u8 bUnitID;
+ __u8 bNrInPins;
+ __u8 baSourceID[0];
+ __u8 iSelector;
+} __attribute__((__packed__));
+
+#define UVC_DT_SELECTOR_UNIT_SIZE(n) (6+(n))
+
+#define UVC_SELECTOR_UNIT_DESCRIPTOR(n) \
+ uvc_selector_unit_descriptor_##n
+
+#define DECLARE_UVC_SELECTOR_UNIT_DESCRIPTOR(n) \
+struct UVC_SELECTOR_UNIT_DESCRIPTOR(n) { \
+ __u8 bLength; \
+ __u8 bDescriptorType; \
+ __u8 bDescriptorSubType; \
+ __u8 bUnitID; \
+ __u8 bNrInPins; \
+ __u8 baSourceID[n]; \
+ __u8 iSelector; \
+} __attribute__ ((packed))
+
+/* 3.7.2.5. Processing Unit Descriptor */
+struct uvc_processing_unit_descriptor {
+ __u8 bLength;
+ __u8 bDescriptorType;
+ __u8 bDescriptorSubType;
+ __u8 bUnitID;
+ __u8 bSourceID;
+ __u16 wMaxMultiplier;
+ __u8 bControlSize;
+ __u8 bmControls[2];
+ __u8 iProcessing;
+} __attribute__((__packed__));
+
+#define UVC_DT_PROCESSING_UNIT_SIZE(n) (9+(n))
+
+/* 3.7.2.6. Extension Unit Descriptor */
+struct uvc_extension_unit_descriptor {
+ __u8 bLength;
+ __u8 bDescriptorType;
+ __u8 bDescriptorSubType;
+ __u8 bUnitID;
+ __u8 guidExtensionCode[16];
+ __u8 bNumControls;
+ __u8 bNrInPins;
+ __u8 baSourceID[0];
+ __u8 bControlSize;
+ __u8 bmControls[0];
+ __u8 iExtension;
+} __attribute__((__packed__));
+
+#define UVC_DT_EXTENSION_UNIT_SIZE(p, n) (24+(p)+(n))
+
+#define UVC_EXTENSION_UNIT_DESCRIPTOR(p, n) \
+ uvc_extension_unit_descriptor_##p_##n
+
+#define DECLARE_UVC_EXTENSION_UNIT_DESCRIPTOR(p, n) \
+struct UVC_EXTENSION_UNIT_DESCRIPTOR(p, n) { \
+ __u8 bLength; \
+ __u8 bDescriptorType; \
+ __u8 bDescriptorSubType; \
+ __u8 bUnitID; \
+ __u8 guidExtensionCode[16]; \
+ __u8 bNumControls; \
+ __u8 bNrInPins; \
+ __u8 baSourceID[p]; \
+ __u8 bControlSize; \
+ __u8 bmControls[n]; \
+ __u8 iExtension; \
+} __attribute__ ((packed))
+
+/* 3.8.2.2. Video Control Interrupt Endpoint Descriptor */
+struct uvc_control_endpoint_descriptor {
+ __u8 bLength;
+ __u8 bDescriptorType;
+ __u8 bDescriptorSubType;
+ __u16 wMaxTransferSize;
+} __attribute__((__packed__));
+
+#define UVC_DT_CONTROL_ENDPOINT_SIZE 5
+
+/* 3.9.2.1. Input Header Descriptor */
+struct uvc_input_header_descriptor {
+ __u8 bLength;
+ __u8 bDescriptorType;
+ __u8 bDescriptorSubType;
+ __u8 bNumFormats;
+ __u16 wTotalLength;
+ __u8 bEndpointAddress;
+ __u8 bmInfo;
+ __u8 bTerminalLink;
+ __u8 bStillCaptureMethod;
+ __u8 bTriggerSupport;
+ __u8 bTriggerUsage;
+ __u8 bControlSize;
+ __u8 bmaControls[];
+} __attribute__((__packed__));
+
+#define UVC_DT_INPUT_HEADER_SIZE(n, p) (13+(n*p))
+
+#define UVC_INPUT_HEADER_DESCRIPTOR(n, p) \
+ uvc_input_header_descriptor_##n_##p
+
+#define DECLARE_UVC_INPUT_HEADER_DESCRIPTOR(n, p) \
+struct UVC_INPUT_HEADER_DESCRIPTOR(n, p) { \
+ __u8 bLength; \
+ __u8 bDescriptorType; \
+ __u8 bDescriptorSubType; \
+ __u8 bNumFormats; \
+ __u16 wTotalLength; \
+ __u8 bEndpointAddress; \
+ __u8 bmInfo; \
+ __u8 bTerminalLink; \
+ __u8 bStillCaptureMethod; \
+ __u8 bTriggerSupport; \
+ __u8 bTriggerUsage; \
+ __u8 bControlSize; \
+ __u8 bmaControls[p][n]; \
+} __attribute__ ((packed))
+
+/* 3.9.2.2. Output Header Descriptor */
+struct uvc_output_header_descriptor {
+ __u8 bLength;
+ __u8 bDescriptorType;
+ __u8 bDescriptorSubType;
+ __u8 bNumFormats;
+ __u16 wTotalLength;
+ __u8 bEndpointAddress;
+ __u8 bTerminalLink;
+ __u8 bControlSize;
+ __u8 bmaControls[];
+} __attribute__((__packed__));
+
+#define UVC_DT_OUTPUT_HEADER_SIZE(n, p) (9+(n*p))
+
+#define UVC_OUTPUT_HEADER_DESCRIPTOR(n, p) \
+ uvc_output_header_descriptor_##n_##p
+
+#define DECLARE_UVC_OUTPUT_HEADER_DESCRIPTOR(n, p) \
+struct UVC_OUTPUT_HEADER_DESCRIPTOR(n, p) { \
+ __u8 bLength; \
+ __u8 bDescriptorType; \
+ __u8 bDescriptorSubType; \
+ __u8 bNumFormats; \
+ __u16 wTotalLength; \
+ __u8 bEndpointAddress; \
+ __u8 bTerminalLink; \
+ __u8 bControlSize; \
+ __u8 bmaControls[p][n]; \
+} __attribute__ ((packed))
+
+/* 3.9.2.6. Color matching descriptor */
+struct uvc_color_matching_descriptor {
+ __u8 bLength;
+ __u8 bDescriptorType;
+ __u8 bDescriptorSubType;
+ __u8 bColorPrimaries;
+ __u8 bTransferCharacteristics;
+ __u8 bMatrixCoefficients;
+} __attribute__((__packed__));
+
+#define UVC_DT_COLOR_MATCHING_SIZE 6
+
+/* 4.3.1.1. Video Probe and Commit Controls */
+struct uvc_streaming_control {
+ __u16 bmHint;
+ __u8 bFormatIndex;
+ __u8 bFrameIndex;
+ __u32 dwFrameInterval;
+ __u16 wKeyFrameRate;
+ __u16 wPFrameRate;
+ __u16 wCompQuality;
+ __u16 wCompWindowSize;
+ __u16 wDelay;
+ __u32 dwMaxVideoFrameSize;
+ __u32 dwMaxPayloadTransferSize;
+ __u32 dwClockFrequency;
+ __u8 bmFramingInfo;
+ __u8 bPreferedVersion;
+ __u8 bMinVersion;
+ __u8 bMaxVersion;
+} __attribute__((__packed__));
+
+/* Uncompressed Payload - 3.1.1. Uncompressed Video Format Descriptor */
+struct uvc_format_uncompressed {
+ __u8 bLength;
+ __u8 bDescriptorType;
+ __u8 bDescriptorSubType;
+ __u8 bFormatIndex;
+ __u8 bNumFrameDescriptors;
+ __u8 guidFormat[16];
+ __u8 bBitsPerPixel;
+ __u8 bDefaultFrameIndex;
+ __u8 bAspectRatioX;
+ __u8 bAspectRatioY;
+ __u8 bmInterfaceFlags;
+ __u8 bCopyProtect;
+} __attribute__((__packed__));
+
+#define UVC_DT_FORMAT_UNCOMPRESSED_SIZE 27
+
+/* Uncompressed Payload - 3.1.2. Uncompressed Video Frame Descriptor */
+struct uvc_frame_uncompressed {
+ __u8 bLength;
+ __u8 bDescriptorType;
+ __u8 bDescriptorSubType;
+ __u8 bFrameIndex;
+ __u8 bmCapabilities;
+ __u16 wWidth;
+ __u16 wHeight;
+ __u32 dwMinBitRate;
+ __u32 dwMaxBitRate;
+ __u32 dwMaxVideoFrameBufferSize;
+ __u32 dwDefaultFrameInterval;
+ __u8 bFrameIntervalType;
+ __u32 dwFrameInterval[];
+} __attribute__((__packed__));
+
+#define UVC_DT_FRAME_UNCOMPRESSED_SIZE(n) (26+4*(n))
+
+#define UVC_FRAME_UNCOMPRESSED(n) \
+ uvc_frame_uncompressed_##n
+
+#define DECLARE_UVC_FRAME_UNCOMPRESSED(n) \
+struct UVC_FRAME_UNCOMPRESSED(n) { \
+ __u8 bLength; \
+ __u8 bDescriptorType; \
+ __u8 bDescriptorSubType; \
+ __u8 bFrameIndex; \
+ __u8 bmCapabilities; \
+ __u16 wWidth; \
+ __u16 wHeight; \
+ __u32 dwMinBitRate; \
+ __u32 dwMaxBitRate; \
+ __u32 dwMaxVideoFrameBufferSize; \
+ __u32 dwDefaultFrameInterval; \
+ __u8 bFrameIntervalType; \
+ __u32 dwFrameInterval[n]; \
+} __attribute__ ((packed))
+
+/* MJPEG Payload - 3.1.1. MJPEG Video Format Descriptor */
+struct uvc_format_mjpeg {
+ __u8 bLength;
+ __u8 bDescriptorType;
+ __u8 bDescriptorSubType;
+ __u8 bFormatIndex;
+ __u8 bNumFrameDescriptors;
+ __u8 bmFlags;
+ __u8 bDefaultFrameIndex;
+ __u8 bAspectRatioX;
+ __u8 bAspectRatioY;
+ __u8 bmInterfaceFlags;
+ __u8 bCopyProtect;
+} __attribute__((__packed__));
+
+#define UVC_DT_FORMAT_MJPEG_SIZE 11
+
+/* MJPEG Payload - 3.1.2. MJPEG Video Frame Descriptor */
+struct uvc_frame_mjpeg {
+ __u8 bLength;
+ __u8 bDescriptorType;
+ __u8 bDescriptorSubType;
+ __u8 bFrameIndex;
+ __u8 bmCapabilities;
+ __u16 wWidth;
+ __u16 wHeight;
+ __u32 dwMinBitRate;
+ __u32 dwMaxBitRate;
+ __u32 dwMaxVideoFrameBufferSize;
+ __u32 dwDefaultFrameInterval;
+ __u8 bFrameIntervalType;
+ __u32 dwFrameInterval[];
+} __attribute__((__packed__));
+
+#define UVC_DT_FRAME_MJPEG_SIZE(n) (26+4*(n))
+
+#define UVC_FRAME_MJPEG(n) \
+ uvc_frame_mjpeg_##n
+
+#define DECLARE_UVC_FRAME_MJPEG(n) \
+struct UVC_FRAME_MJPEG(n) { \
+ __u8 bLength; \
+ __u8 bDescriptorType; \
+ __u8 bDescriptorSubType; \
+ __u8 bFrameIndex; \
+ __u8 bmCapabilities; \
+ __u16 wWidth; \
+ __u16 wHeight; \
+ __u32 dwMinBitRate; \
+ __u32 dwMaxBitRate; \
+ __u32 dwMaxVideoFrameBufferSize; \
+ __u32 dwDefaultFrameInterval; \
+ __u8 bFrameIntervalType; \
+ __u32 dwFrameInterval[n]; \
+} __attribute__ ((packed))
+
#endif /* __LINUX_USB_VIDEO_H */
diff --git a/include/linux/user_namespace.h b/include/linux/user_namespace.h
index cc4f45361db..8178156711f 100644
--- a/include/linux/user_namespace.h
+++ b/include/linux/user_namespace.h
@@ -36,6 +36,9 @@ static inline void put_user_ns(struct user_namespace *ns)
kref_put(&ns->kref, free_user_ns);
}
+uid_t user_ns_map_uid(struct user_namespace *to, const struct cred *cred, uid_t uid);
+gid_t user_ns_map_gid(struct user_namespace *to, const struct cred *cred, gid_t gid);
+
#else
static inline struct user_namespace *get_user_ns(struct user_namespace *ns)
@@ -52,6 +55,17 @@ static inline void put_user_ns(struct user_namespace *ns)
{
}
+static inline uid_t user_ns_map_uid(struct user_namespace *to,
+ const struct cred *cred, uid_t uid)
+{
+ return uid;
+}
+static inline gid_t user_ns_map_gid(struct user_namespace *to,
+ const struct cred *cred, gid_t gid)
+{
+ return gid;
+}
+
#endif
#endif /* _LINUX_USER_H */
diff --git a/include/linux/virtio_9p.h b/include/linux/virtio_9p.h
index 5cf11765146..395c38a47ad 100644
--- a/include/linux/virtio_9p.h
+++ b/include/linux/virtio_9p.h
@@ -4,6 +4,7 @@
* compatible drivers/servers. */
#include <linux/virtio_ids.h>
#include <linux/virtio_config.h>
+#include <linux/types.h>
/* The feature bitmap for virtio 9P */
diff --git a/include/linux/vmalloc.h b/include/linux/vmalloc.h
index 227c2a585e4..de05e96e0a7 100644
--- a/include/linux/vmalloc.h
+++ b/include/linux/vmalloc.h
@@ -30,7 +30,7 @@ struct vm_struct {
unsigned long flags;
struct page **pages;
unsigned int nr_pages;
- unsigned long phys_addr;
+ phys_addr_t phys_addr;
void *caller;
};
diff --git a/include/linux/wlp.h b/include/linux/wlp.h
index ac95ce6606a..c76fe239250 100644
--- a/include/linux/wlp.h
+++ b/include/linux/wlp.h
@@ -300,7 +300,7 @@ struct wlp_ie {
__le16 cycle_param;
__le16 acw_anchor_addr;
u8 wssid_hash_list[];
-} __attribute__((packed));
+} __packed;
static inline int wlp_ie_hash_length(struct wlp_ie *ie)
{
@@ -324,7 +324,7 @@ static inline void wlp_ie_set_hash_length(struct wlp_ie *ie, int hash_length)
*/
struct wlp_nonce {
u8 data[16];
-} __attribute__((packed));
+} __packed;
/**
* WLP UUID
@@ -336,7 +336,7 @@ struct wlp_nonce {
*/
struct wlp_uuid {
u8 data[16];
-} __attribute__((packed));
+} __packed;
/**
@@ -348,7 +348,7 @@ struct wlp_dev_type {
u8 OUI[3];
u8 OUIsubdiv;
__le16 subID;
-} __attribute__((packed));
+} __packed;
/**
* WLP frame header
@@ -357,7 +357,7 @@ struct wlp_dev_type {
struct wlp_frame_hdr {
__le16 mux_hdr; /* WLP_PROTOCOL_ID */
enum wlp_frame_type type:8;
-} __attribute__((packed));
+} __packed;
/**
* WLP attribute field header
@@ -368,7 +368,7 @@ struct wlp_frame_hdr {
struct wlp_attr_hdr {
__le16 type;
__le16 length;
-} __attribute__((packed));
+} __packed;
/**
* Device information commonly used together
@@ -401,13 +401,13 @@ struct wlp_device_info {
struct wlp_attr_##name { \
struct wlp_attr_hdr hdr; \
type name; \
-} __attribute__((packed));
+} __packed;
#define wlp_attr_array(type, name) \
struct wlp_attr_##name { \
struct wlp_attr_hdr hdr; \
type name[]; \
-} __attribute__((packed));
+} __packed;
/**
* WLP association attribute fields
@@ -483,7 +483,7 @@ struct wlp_wss_info {
struct wlp_attr_accept_enrl accept;
struct wlp_attr_wss_sec_status sec_stat;
struct wlp_attr_wss_bcast bcast;
-} __attribute__((packed));
+} __packed;
/* WLP WSS Information */
wlp_attr_array(struct wlp_wss_info, wss_info)
@@ -520,7 +520,7 @@ wlp_attr(u8, wlp_assc_err)
struct wlp_frame_std_abbrv_hdr {
struct wlp_frame_hdr hdr;
u8 tag;
-} __attribute__((packed));
+} __packed;
/**
* WLP association frames
@@ -533,7 +533,7 @@ struct wlp_frame_assoc {
struct wlp_attr_version version;
struct wlp_attr_msg_type msg_type;
u8 attr[];
-} __attribute__((packed));
+} __packed;
/* Ethernet to dev address mapping */
struct wlp_eda {
diff --git a/include/linux/workqueue.h b/include/linux/workqueue.h
index 9466e860d8c..4f9d277bcd9 100644
--- a/include/linux/workqueue.h
+++ b/include/linux/workqueue.h
@@ -9,6 +9,7 @@
#include <linux/linkage.h>
#include <linux/bitops.h>
#include <linux/lockdep.h>
+#include <linux/threads.h>
#include <asm/atomic.h>
struct workqueue_struct;
@@ -22,12 +23,59 @@ typedef void (*work_func_t)(struct work_struct *work);
*/
#define work_data_bits(work) ((unsigned long *)(&(work)->data))
+enum {
+ WORK_STRUCT_PENDING_BIT = 0, /* work item is pending execution */
+ WORK_STRUCT_CWQ_BIT = 1, /* data points to cwq */
+ WORK_STRUCT_LINKED_BIT = 2, /* next work is linked to this one */
+#ifdef CONFIG_DEBUG_OBJECTS_WORK
+ WORK_STRUCT_STATIC_BIT = 3, /* static initializer (debugobjects) */
+ WORK_STRUCT_COLOR_SHIFT = 4, /* color for workqueue flushing */
+#else
+ WORK_STRUCT_COLOR_SHIFT = 3, /* color for workqueue flushing */
+#endif
+
+ WORK_STRUCT_COLOR_BITS = 4,
+
+ WORK_STRUCT_PENDING = 1 << WORK_STRUCT_PENDING_BIT,
+ WORK_STRUCT_CWQ = 1 << WORK_STRUCT_CWQ_BIT,
+ WORK_STRUCT_LINKED = 1 << WORK_STRUCT_LINKED_BIT,
+#ifdef CONFIG_DEBUG_OBJECTS_WORK
+ WORK_STRUCT_STATIC = 1 << WORK_STRUCT_STATIC_BIT,
+#else
+ WORK_STRUCT_STATIC = 0,
+#endif
+
+ /*
+ * The last color is no color used for works which don't
+ * participate in workqueue flushing.
+ */
+ WORK_NR_COLORS = (1 << WORK_STRUCT_COLOR_BITS) - 1,
+ WORK_NO_COLOR = WORK_NR_COLORS,
+
+ /* special cpu IDs */
+ WORK_CPU_UNBOUND = NR_CPUS,
+ WORK_CPU_NONE = NR_CPUS + 1,
+ WORK_CPU_LAST = WORK_CPU_NONE,
+
+ /*
+ * Reserve 7 bits off of cwq pointer w/ debugobjects turned
+ * off. This makes cwqs aligned to 128 bytes which isn't too
+ * excessive while allowing 15 workqueue flush colors.
+ */
+ WORK_STRUCT_FLAG_BITS = WORK_STRUCT_COLOR_SHIFT +
+ WORK_STRUCT_COLOR_BITS,
+
+ WORK_STRUCT_FLAG_MASK = (1UL << WORK_STRUCT_FLAG_BITS) - 1,
+ WORK_STRUCT_WQ_DATA_MASK = ~WORK_STRUCT_FLAG_MASK,
+ WORK_STRUCT_NO_CPU = WORK_CPU_NONE << WORK_STRUCT_FLAG_BITS,
+
+ /* bit mask for work_busy() return values */
+ WORK_BUSY_PENDING = 1 << 0,
+ WORK_BUSY_RUNNING = 1 << 1,
+};
+
struct work_struct {
atomic_long_t data;
-#define WORK_STRUCT_PENDING 0 /* T if work item pending execution */
-#define WORK_STRUCT_STATIC 1 /* static initializer (debugobjects) */
-#define WORK_STRUCT_FLAG_MASK (3UL)
-#define WORK_STRUCT_WQ_DATA_MASK (~WORK_STRUCT_FLAG_MASK)
struct list_head entry;
work_func_t func;
#ifdef CONFIG_LOCKDEP
@@ -35,8 +83,9 @@ struct work_struct {
#endif
};
-#define WORK_DATA_INIT() ATOMIC_LONG_INIT(0)
-#define WORK_DATA_STATIC_INIT() ATOMIC_LONG_INIT(2)
+#define WORK_DATA_INIT() ATOMIC_LONG_INIT(WORK_STRUCT_NO_CPU)
+#define WORK_DATA_STATIC_INIT() \
+ ATOMIC_LONG_INIT(WORK_STRUCT_NO_CPU | WORK_STRUCT_STATIC)
struct delayed_work {
struct work_struct work;
@@ -96,9 +145,14 @@ struct execute_work {
#ifdef CONFIG_DEBUG_OBJECTS_WORK
extern void __init_work(struct work_struct *work, int onstack);
extern void destroy_work_on_stack(struct work_struct *work);
+static inline unsigned int work_static(struct work_struct *work)
+{
+ return *work_data_bits(work) & WORK_STRUCT_STATIC;
+}
#else
static inline void __init_work(struct work_struct *work, int onstack) { }
static inline void destroy_work_on_stack(struct work_struct *work) { }
+static inline unsigned int work_static(struct work_struct *work) { return 0; }
#endif
/*
@@ -162,7 +216,7 @@ static inline void destroy_work_on_stack(struct work_struct *work) { }
* @work: The work item in question
*/
#define work_pending(work) \
- test_bit(WORK_STRUCT_PENDING, work_data_bits(work))
+ test_bit(WORK_STRUCT_PENDING_BIT, work_data_bits(work))
/**
* delayed_work_pending - Find out whether a delayable work item is currently
@@ -177,16 +231,56 @@ static inline void destroy_work_on_stack(struct work_struct *work) { }
* @work: The work item in question
*/
#define work_clear_pending(work) \
- clear_bit(WORK_STRUCT_PENDING, work_data_bits(work))
+ clear_bit(WORK_STRUCT_PENDING_BIT, work_data_bits(work))
+
+enum {
+ WQ_NON_REENTRANT = 1 << 0, /* guarantee non-reentrance */
+ WQ_UNBOUND = 1 << 1, /* not bound to any cpu */
+ WQ_FREEZEABLE = 1 << 2, /* freeze during suspend */
+ WQ_RESCUER = 1 << 3, /* has an rescue worker */
+ WQ_HIGHPRI = 1 << 4, /* high priority */
+ WQ_CPU_INTENSIVE = 1 << 5, /* cpu instensive workqueue */
+
+ WQ_MAX_ACTIVE = 512, /* I like 512, better ideas? */
+ WQ_MAX_UNBOUND_PER_CPU = 4, /* 4 * #cpus for unbound wq */
+ WQ_DFL_ACTIVE = WQ_MAX_ACTIVE / 2,
+};
+/* unbound wq's aren't per-cpu, scale max_active according to #cpus */
+#define WQ_UNBOUND_MAX_ACTIVE \
+ max_t(int, WQ_MAX_ACTIVE, num_possible_cpus() * WQ_MAX_UNBOUND_PER_CPU)
+
+/*
+ * System-wide workqueues which are always present.
+ *
+ * system_wq is the one used by schedule[_delayed]_work[_on]().
+ * Multi-CPU multi-threaded. There are users which expect relatively
+ * short queue flush time. Don't queue works which can run for too
+ * long.
+ *
+ * system_long_wq is similar to system_wq but may host long running
+ * works. Queue flushing might take relatively long.
+ *
+ * system_nrt_wq is non-reentrant and guarantees that any given work
+ * item is never executed in parallel by multiple CPUs. Queue
+ * flushing might take relatively long.
+ *
+ * system_unbound_wq is unbound workqueue. Workers are not bound to
+ * any specific CPU, not concurrency managed, and all queued works are
+ * executed immediately as long as max_active limit is not reached and
+ * resources are available.
+ */
+extern struct workqueue_struct *system_wq;
+extern struct workqueue_struct *system_long_wq;
+extern struct workqueue_struct *system_nrt_wq;
+extern struct workqueue_struct *system_unbound_wq;
extern struct workqueue_struct *
-__create_workqueue_key(const char *name, int singlethread,
- int freezeable, int rt, struct lock_class_key *key,
- const char *lock_name);
+__alloc_workqueue_key(const char *name, unsigned int flags, int max_active,
+ struct lock_class_key *key, const char *lock_name);
#ifdef CONFIG_LOCKDEP
-#define __create_workqueue(name, singlethread, freezeable, rt) \
+#define alloc_workqueue(name, flags, max_active) \
({ \
static struct lock_class_key __key; \
const char *__lock_name; \
@@ -196,20 +290,20 @@ __create_workqueue_key(const char *name, int singlethread,
else \
__lock_name = #name; \
\
- __create_workqueue_key((name), (singlethread), \
- (freezeable), (rt), &__key, \
- __lock_name); \
+ __alloc_workqueue_key((name), (flags), (max_active), \
+ &__key, __lock_name); \
})
#else
-#define __create_workqueue(name, singlethread, freezeable, rt) \
- __create_workqueue_key((name), (singlethread), (freezeable), (rt), \
- NULL, NULL)
+#define alloc_workqueue(name, flags, max_active) \
+ __alloc_workqueue_key((name), (flags), (max_active), NULL, NULL)
#endif
-#define create_workqueue(name) __create_workqueue((name), 0, 0, 0)
-#define create_rt_workqueue(name) __create_workqueue((name), 0, 0, 1)
-#define create_freezeable_workqueue(name) __create_workqueue((name), 1, 1, 0)
-#define create_singlethread_workqueue(name) __create_workqueue((name), 1, 0, 0)
+#define create_workqueue(name) \
+ alloc_workqueue((name), WQ_RESCUER, 1)
+#define create_freezeable_workqueue(name) \
+ alloc_workqueue((name), WQ_FREEZEABLE | WQ_UNBOUND | WQ_RESCUER, 1)
+#define create_singlethread_workqueue(name) \
+ alloc_workqueue((name), WQ_UNBOUND | WQ_RESCUER, 1)
extern void destroy_workqueue(struct workqueue_struct *wq);
@@ -231,16 +325,19 @@ extern int schedule_delayed_work(struct delayed_work *work, unsigned long delay)
extern int schedule_delayed_work_on(int cpu, struct delayed_work *work,
unsigned long delay);
extern int schedule_on_each_cpu(work_func_t func);
-extern int current_is_keventd(void);
extern int keventd_up(void);
-extern void init_workqueues(void);
int execute_in_process_context(work_func_t fn, struct execute_work *);
extern int flush_work(struct work_struct *work);
-
extern int cancel_work_sync(struct work_struct *work);
+extern void workqueue_set_max_active(struct workqueue_struct *wq,
+ int max_active);
+extern bool workqueue_congested(unsigned int cpu, struct workqueue_struct *wq);
+extern unsigned int work_cpu(struct work_struct *work);
+extern unsigned int work_busy(struct work_struct *work);
+
/*
* Kill off a pending schedule_delayed_work(). Note that the work callback
* function may still be running on return from cancel_delayed_work(), unless
@@ -297,4 +394,15 @@ static inline long work_on_cpu(unsigned int cpu, long (*fn)(void *), void *arg)
#else
long work_on_cpu(unsigned int cpu, long (*fn)(void *), void *arg);
#endif /* CONFIG_SMP */
+
+#ifdef CONFIG_FREEZER
+extern void freeze_workqueues_begin(void);
+extern bool freeze_workqueues_busy(void);
+extern void thaw_workqueues(void);
+#endif /* CONFIG_FREEZER */
+
+#ifdef CONFIG_LOCKDEP
+int in_workqueue_context(struct workqueue_struct *wq);
+#endif
+
#endif
diff --git a/include/linux/xattr.h b/include/linux/xattr.h
index 0cfa1e9c4cc..f1e5bde4b35 100644
--- a/include/linux/xattr.h
+++ b/include/linux/xattr.h
@@ -33,6 +33,20 @@
#define XATTR_USER_PREFIX "user."
#define XATTR_USER_PREFIX_LEN (sizeof (XATTR_USER_PREFIX) - 1)
+/* Security namespace */
+#define XATTR_SELINUX_SUFFIX "selinux"
+#define XATTR_NAME_SELINUX XATTR_SECURITY_PREFIX XATTR_SELINUX_SUFFIX
+
+#define XATTR_SMACK_SUFFIX "SMACK64"
+#define XATTR_SMACK_IPIN "SMACK64IPIN"
+#define XATTR_SMACK_IPOUT "SMACK64IPOUT"
+#define XATTR_NAME_SMACK XATTR_SECURITY_PREFIX XATTR_SMACK_SUFFIX
+#define XATTR_NAME_SMACKIPIN XATTR_SECURITY_PREFIX XATTR_SMACK_IPIN
+#define XATTR_NAME_SMACKIPOUT XATTR_SECURITY_PREFIX XATTR_SMACK_IPOUT
+
+#define XATTR_CAPS_SUFFIX "capability"
+#define XATTR_NAME_CAPS XATTR_SECURITY_PREFIX XATTR_CAPS_SUFFIX
+
struct inode;
struct dentry;
diff --git a/include/media/ir-core.h b/include/media/ir-core.h
index ad1303f20e0..513e60dd101 100644
--- a/include/media/ir-core.h
+++ b/include/media/ir-core.h
@@ -47,15 +47,21 @@ enum rc_driver_type {
* is opened.
* @close: callback to allow drivers to disable polling/irq when IR input device
* is opened.
+ * @s_tx_mask: set transmitter mask (for devices with multiple tx outputs)
+ * @s_tx_carrier: set transmit carrier frequency
+ * @tx_ir: transmit IR
*/
struct ir_dev_props {
enum rc_driver_type driver_type;
unsigned long allowed_protos;
u32 scanmask;
- void *priv;
+ void *priv;
int (*change_protocol)(void *priv, u64 ir_type);
int (*open)(void *priv);
void (*close)(void *priv);
+ int (*s_tx_mask)(void *priv, u32 mask);
+ int (*s_tx_carrier)(void *priv, u32 carrier);
+ int (*tx_ir)(void *priv, int *txbuf, u32 n);
};
struct ir_input_dev {
diff --git a/include/media/ir-kbd-i2c.h b/include/media/ir-kbd-i2c.h
index 0506e45c9a4..5e96d7a430b 100644
--- a/include/media/ir-kbd-i2c.h
+++ b/include/media/ir-kbd-i2c.h
@@ -11,7 +11,7 @@ struct IR_i2c {
struct i2c_client *c;
struct input_dev *input;
struct ir_input_state ir;
-
+ u64 ir_type;
/* Used to avoid fast repeating */
unsigned char old;
diff --git a/include/media/lirc.h b/include/media/lirc.h
new file mode 100644
index 00000000000..42c467c5051
--- /dev/null
+++ b/include/media/lirc.h
@@ -0,0 +1,165 @@
+/*
+ * lirc.h - linux infrared remote control header file
+ * last modified 2010/07/13 by Jarod Wilson
+ */
+
+#ifndef _LINUX_LIRC_H
+#define _LINUX_LIRC_H
+
+#include <linux/types.h>
+#include <linux/ioctl.h>
+
+#define PULSE_BIT 0x01000000
+#define PULSE_MASK 0x00FFFFFF
+
+#define LIRC_MODE2_SPACE 0x00000000
+#define LIRC_MODE2_PULSE 0x01000000
+#define LIRC_MODE2_FREQUENCY 0x02000000
+#define LIRC_MODE2_TIMEOUT 0x03000000
+
+#define LIRC_VALUE_MASK 0x00FFFFFF
+#define LIRC_MODE2_MASK 0xFF000000
+
+#define LIRC_SPACE(val) (((val)&LIRC_VALUE_MASK) | LIRC_MODE2_SPACE)
+#define LIRC_PULSE(val) (((val)&LIRC_VALUE_MASK) | LIRC_MODE2_PULSE)
+#define LIRC_FREQUENCY(val) (((val)&LIRC_VALUE_MASK) | LIRC_MODE2_FREQUENCY)
+#define LIRC_TIMEOUT(val) (((val)&LIRC_VALUE_MASK) | LIRC_MODE2_TIMEOUT)
+
+#define LIRC_VALUE(val) ((val)&LIRC_VALUE_MASK)
+#define LIRC_MODE2(val) ((val)&LIRC_MODE2_MASK)
+
+#define LIRC_IS_SPACE(val) (LIRC_MODE2(val) == LIRC_MODE2_SPACE)
+#define LIRC_IS_PULSE(val) (LIRC_MODE2(val) == LIRC_MODE2_PULSE)
+#define LIRC_IS_FREQUENCY(val) (LIRC_MODE2(val) == LIRC_MODE2_FREQUENCY)
+#define LIRC_IS_TIMEOUT(val) (LIRC_MODE2(val) == LIRC_MODE2_TIMEOUT)
+
+/* used heavily by lirc userspace */
+#define lirc_t int
+
+/*** lirc compatible hardware features ***/
+
+#define LIRC_MODE2SEND(x) (x)
+#define LIRC_SEND2MODE(x) (x)
+#define LIRC_MODE2REC(x) ((x) << 16)
+#define LIRC_REC2MODE(x) ((x) >> 16)
+
+#define LIRC_MODE_RAW 0x00000001
+#define LIRC_MODE_PULSE 0x00000002
+#define LIRC_MODE_MODE2 0x00000004
+#define LIRC_MODE_LIRCCODE 0x00000010
+
+
+#define LIRC_CAN_SEND_RAW LIRC_MODE2SEND(LIRC_MODE_RAW)
+#define LIRC_CAN_SEND_PULSE LIRC_MODE2SEND(LIRC_MODE_PULSE)
+#define LIRC_CAN_SEND_MODE2 LIRC_MODE2SEND(LIRC_MODE_MODE2)
+#define LIRC_CAN_SEND_LIRCCODE LIRC_MODE2SEND(LIRC_MODE_LIRCCODE)
+
+#define LIRC_CAN_SEND_MASK 0x0000003f
+
+#define LIRC_CAN_SET_SEND_CARRIER 0x00000100
+#define LIRC_CAN_SET_SEND_DUTY_CYCLE 0x00000200
+#define LIRC_CAN_SET_TRANSMITTER_MASK 0x00000400
+
+#define LIRC_CAN_REC_RAW LIRC_MODE2REC(LIRC_MODE_RAW)
+#define LIRC_CAN_REC_PULSE LIRC_MODE2REC(LIRC_MODE_PULSE)
+#define LIRC_CAN_REC_MODE2 LIRC_MODE2REC(LIRC_MODE_MODE2)
+#define LIRC_CAN_REC_LIRCCODE LIRC_MODE2REC(LIRC_MODE_LIRCCODE)
+
+#define LIRC_CAN_REC_MASK LIRC_MODE2REC(LIRC_CAN_SEND_MASK)
+
+#define LIRC_CAN_SET_REC_CARRIER (LIRC_CAN_SET_SEND_CARRIER << 16)
+#define LIRC_CAN_SET_REC_DUTY_CYCLE (LIRC_CAN_SET_SEND_DUTY_CYCLE << 16)
+
+#define LIRC_CAN_SET_REC_DUTY_CYCLE_RANGE 0x40000000
+#define LIRC_CAN_SET_REC_CARRIER_RANGE 0x80000000
+#define LIRC_CAN_GET_REC_RESOLUTION 0x20000000
+#define LIRC_CAN_SET_REC_TIMEOUT 0x10000000
+#define LIRC_CAN_SET_REC_FILTER 0x08000000
+
+#define LIRC_CAN_MEASURE_CARRIER 0x02000000
+
+#define LIRC_CAN_SEND(x) ((x)&LIRC_CAN_SEND_MASK)
+#define LIRC_CAN_REC(x) ((x)&LIRC_CAN_REC_MASK)
+
+#define LIRC_CAN_NOTIFY_DECODE 0x01000000
+
+/*** IOCTL commands for lirc driver ***/
+
+#define LIRC_GET_FEATURES _IOR('i', 0x00000000, __u32)
+
+#define LIRC_GET_SEND_MODE _IOR('i', 0x00000001, __u32)
+#define LIRC_GET_REC_MODE _IOR('i', 0x00000002, __u32)
+#define LIRC_GET_SEND_CARRIER _IOR('i', 0x00000003, __u32)
+#define LIRC_GET_REC_CARRIER _IOR('i', 0x00000004, __u32)
+#define LIRC_GET_SEND_DUTY_CYCLE _IOR('i', 0x00000005, __u32)
+#define LIRC_GET_REC_DUTY_CYCLE _IOR('i', 0x00000006, __u32)
+#define LIRC_GET_REC_RESOLUTION _IOR('i', 0x00000007, __u32)
+
+#define LIRC_GET_MIN_TIMEOUT _IOR('i', 0x00000008, __u32)
+#define LIRC_GET_MAX_TIMEOUT _IOR('i', 0x00000009, __u32)
+
+#define LIRC_GET_MIN_FILTER_PULSE _IOR('i', 0x0000000a, __u32)
+#define LIRC_GET_MAX_FILTER_PULSE _IOR('i', 0x0000000b, __u32)
+#define LIRC_GET_MIN_FILTER_SPACE _IOR('i', 0x0000000c, __u32)
+#define LIRC_GET_MAX_FILTER_SPACE _IOR('i', 0x0000000d, __u32)
+
+/* code length in bits, currently only for LIRC_MODE_LIRCCODE */
+#define LIRC_GET_LENGTH _IOR('i', 0x0000000f, __u32)
+
+#define LIRC_SET_SEND_MODE _IOW('i', 0x00000011, __u32)
+#define LIRC_SET_REC_MODE _IOW('i', 0x00000012, __u32)
+/* Note: these can reset the according pulse_width */
+#define LIRC_SET_SEND_CARRIER _IOW('i', 0x00000013, __u32)
+#define LIRC_SET_REC_CARRIER _IOW('i', 0x00000014, __u32)
+#define LIRC_SET_SEND_DUTY_CYCLE _IOW('i', 0x00000015, __u32)
+#define LIRC_SET_REC_DUTY_CYCLE _IOW('i', 0x00000016, __u32)
+#define LIRC_SET_TRANSMITTER_MASK _IOW('i', 0x00000017, __u32)
+
+/*
+ * when a timeout != 0 is set the driver will send a
+ * LIRC_MODE2_TIMEOUT data packet, otherwise LIRC_MODE2_TIMEOUT is
+ * never sent, timeout is disabled by default
+ */
+#define LIRC_SET_REC_TIMEOUT _IOW('i', 0x00000018, __u32)
+
+/* 1 enables, 0 disables timeout reports in MODE2 */
+#define LIRC_SET_REC_TIMEOUT_REPORTS _IOW('i', 0x00000019, __u32)
+
+/*
+ * pulses shorter than this are filtered out by hardware (software
+ * emulation in lirc_dev?)
+ */
+#define LIRC_SET_REC_FILTER_PULSE _IOW('i', 0x0000001a, __u32)
+/*
+ * spaces shorter than this are filtered out by hardware (software
+ * emulation in lirc_dev?)
+ */
+#define LIRC_SET_REC_FILTER_SPACE _IOW('i', 0x0000001b, __u32)
+/*
+ * if filter cannot be set independantly for pulse/space, this should
+ * be used
+ */
+#define LIRC_SET_REC_FILTER _IOW('i', 0x0000001c, __u32)
+
+/*
+ * if enabled from the next key press on the driver will send
+ * LIRC_MODE2_FREQUENCY packets
+ */
+#define LIRC_SET_MEASURE_CARRIER_MODE _IOW('i', 0x0000001d, __u32)
+
+/*
+ * to set a range use
+ * LIRC_SET_REC_DUTY_CYCLE_RANGE/LIRC_SET_REC_CARRIER_RANGE with the
+ * lower bound first and later
+ * LIRC_SET_REC_DUTY_CYCLE/LIRC_SET_REC_CARRIER with the upper bound
+ */
+
+#define LIRC_SET_REC_DUTY_CYCLE_RANGE _IOW('i', 0x0000001e, __u32)
+#define LIRC_SET_REC_CARRIER_RANGE _IOW('i', 0x0000001f, __u32)
+
+#define LIRC_NOTIFY_DECODE _IO('i', 0x00000020)
+
+#define LIRC_SETUP_START _IO('i', 0x00000021)
+#define LIRC_SETUP_END _IO('i', 0x00000022)
+
+#endif
diff --git a/include/media/lirc_dev.h b/include/media/lirc_dev.h
new file mode 100644
index 00000000000..b1f60663cb3
--- /dev/null
+++ b/include/media/lirc_dev.h
@@ -0,0 +1,225 @@
+/*
+ * LIRC base driver
+ *
+ * by Artur Lipowski <alipowski@interia.pl>
+ * This code is licensed under GNU GPL
+ *
+ */
+
+#ifndef _LINUX_LIRC_DEV_H
+#define _LINUX_LIRC_DEV_H
+
+#define MAX_IRCTL_DEVICES 4
+#define BUFLEN 16
+
+#define mod(n, div) ((n) % (div))
+
+#include <linux/slab.h>
+#include <linux/fs.h>
+#include <linux/ioctl.h>
+#include <linux/poll.h>
+#include <linux/kfifo.h>
+#include <media/lirc.h>
+
+struct lirc_buffer {
+ wait_queue_head_t wait_poll;
+ spinlock_t fifo_lock;
+ unsigned int chunk_size;
+ unsigned int size; /* in chunks */
+ /* Using chunks instead of bytes pretends to simplify boundary checking
+ * And should allow for some performance fine tunning later */
+ struct kfifo fifo;
+ u8 fifo_initialized;
+};
+
+static inline void lirc_buffer_clear(struct lirc_buffer *buf)
+{
+ unsigned long flags;
+
+ if (buf->fifo_initialized) {
+ spin_lock_irqsave(&buf->fifo_lock, flags);
+ kfifo_reset(&buf->fifo);
+ spin_unlock_irqrestore(&buf->fifo_lock, flags);
+ } else
+ WARN(1, "calling %s on an uninitialized lirc_buffer\n",
+ __func__);
+}
+
+static inline int lirc_buffer_init(struct lirc_buffer *buf,
+ unsigned int chunk_size,
+ unsigned int size)
+{
+ int ret;
+
+ init_waitqueue_head(&buf->wait_poll);
+ spin_lock_init(&buf->fifo_lock);
+ buf->chunk_size = chunk_size;
+ buf->size = size;
+ ret = kfifo_alloc(&buf->fifo, size * chunk_size, GFP_KERNEL);
+ if (ret == 0)
+ buf->fifo_initialized = 1;
+
+ return ret;
+}
+
+static inline void lirc_buffer_free(struct lirc_buffer *buf)
+{
+ if (buf->fifo_initialized) {
+ kfifo_free(&buf->fifo);
+ buf->fifo_initialized = 0;
+ } else
+ WARN(1, "calling %s on an uninitialized lirc_buffer\n",
+ __func__);
+}
+
+static inline int lirc_buffer_len(struct lirc_buffer *buf)
+{
+ int len;
+ unsigned long flags;
+
+ spin_lock_irqsave(&buf->fifo_lock, flags);
+ len = kfifo_len(&buf->fifo);
+ spin_unlock_irqrestore(&buf->fifo_lock, flags);
+
+ return len;
+}
+
+static inline int lirc_buffer_full(struct lirc_buffer *buf)
+{
+ return lirc_buffer_len(buf) == buf->size * buf->chunk_size;
+}
+
+static inline int lirc_buffer_empty(struct lirc_buffer *buf)
+{
+ return !lirc_buffer_len(buf);
+}
+
+static inline int lirc_buffer_available(struct lirc_buffer *buf)
+{
+ return buf->size - (lirc_buffer_len(buf) / buf->chunk_size);
+}
+
+static inline unsigned int lirc_buffer_read(struct lirc_buffer *buf,
+ unsigned char *dest)
+{
+ unsigned int ret = 0;
+
+ if (lirc_buffer_len(buf) >= buf->chunk_size)
+ ret = kfifo_out_locked(&buf->fifo, dest, buf->chunk_size,
+ &buf->fifo_lock);
+ return ret;
+
+}
+
+static inline unsigned int lirc_buffer_write(struct lirc_buffer *buf,
+ unsigned char *orig)
+{
+ unsigned int ret;
+
+ ret = kfifo_in_locked(&buf->fifo, orig, buf->chunk_size,
+ &buf->fifo_lock);
+
+ return ret;
+}
+
+struct lirc_driver {
+ char name[40];
+ int minor;
+ unsigned long code_length;
+ unsigned int buffer_size; /* in chunks holding one code each */
+ int sample_rate;
+ unsigned long features;
+
+ unsigned int chunk_size;
+
+ void *data;
+ int min_timeout;
+ int max_timeout;
+ int (*add_to_buf) (void *data, struct lirc_buffer *buf);
+ struct lirc_buffer *rbuf;
+ int (*set_use_inc) (void *data);
+ void (*set_use_dec) (void *data);
+ struct file_operations *fops;
+ struct device *dev;
+ struct module *owner;
+};
+
+/* name:
+ * this string will be used for logs
+ *
+ * minor:
+ * indicates minor device (/dev/lirc) number for registered driver
+ * if caller fills it with negative value, then the first free minor
+ * number will be used (if available)
+ *
+ * code_length:
+ * length of the remote control key code expressed in bits
+ *
+ * sample_rate:
+ *
+ * data:
+ * it may point to any driver data and this pointer will be passed to
+ * all callback functions
+ *
+ * add_to_buf:
+ * add_to_buf will be called after specified period of the time or
+ * triggered by the external event, this behavior depends on value of
+ * the sample_rate this function will be called in user context. This
+ * routine should return 0 if data was added to the buffer and
+ * -ENODATA if none was available. This should add some number of bits
+ * evenly divisible by code_length to the buffer
+ *
+ * rbuf:
+ * if not NULL, it will be used as a read buffer, you will have to
+ * write to the buffer by other means, like irq's (see also
+ * lirc_serial.c).
+ *
+ * set_use_inc:
+ * set_use_inc will be called after device is opened
+ *
+ * set_use_dec:
+ * set_use_dec will be called after device is closed
+ *
+ * fops:
+ * file_operations for drivers which don't fit the current driver model.
+ *
+ * Some ioctl's can be directly handled by lirc_dev if the driver's
+ * ioctl function is NULL or if it returns -ENOIOCTLCMD (see also
+ * lirc_serial.c).
+ *
+ * owner:
+ * the module owning this struct
+ *
+ */
+
+
+/* following functions can be called ONLY from user context
+ *
+ * returns negative value on error or minor number
+ * of the registered device if success
+ * contents of the structure pointed by p is copied
+ */
+extern int lirc_register_driver(struct lirc_driver *d);
+
+/* returns negative value on error or 0 if success
+*/
+extern int lirc_unregister_driver(int minor);
+
+/* Returns the private data stored in the lirc_driver
+ * associated with the given device file pointer.
+ */
+void *lirc_get_pdata(struct file *file);
+
+/* default file operations
+ * used by drivers if they override only some operations
+ */
+int lirc_dev_fop_open(struct inode *inode, struct file *file);
+int lirc_dev_fop_close(struct inode *inode, struct file *file);
+unsigned int lirc_dev_fop_poll(struct file *file, poll_table *wait);
+long lirc_dev_fop_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
+ssize_t lirc_dev_fop_read(struct file *file, char *buffer, size_t length,
+ loff_t *ppos);
+ssize_t lirc_dev_fop_write(struct file *file, const char *buffer, size_t length,
+ loff_t *ppos);
+
+#endif
diff --git a/include/media/rc-map.h b/include/media/rc-map.h
index c78e99a435b..9569d0863f8 100644
--- a/include/media/rc-map.h
+++ b/include/media/rc-map.h
@@ -17,8 +17,13 @@
#define IR_TYPE_RC6 (1 << 2) /* Philips RC6 protocol */
#define IR_TYPE_JVC (1 << 3) /* JVC protocol */
#define IR_TYPE_SONY (1 << 4) /* Sony12/15/20 protocol */
+#define IR_TYPE_LIRC (1 << 30) /* Pass raw IR to lirc userspace */
#define IR_TYPE_OTHER (1u << 31)
+#define IR_TYPE_ALL (IR_TYPE_RC5 | IR_TYPE_NEC | IR_TYPE_RC6 | \
+ IR_TYPE_JVC | IR_TYPE_SONY | IR_TYPE_LIRC | \
+ IR_TYPE_OTHER)
+
struct ir_scancode {
u32 scancode;
u32 keycode;
@@ -64,6 +69,8 @@ void rc_map_init(void);
#define RC_MAP_BUDGET_CI_OLD "rc-budget-ci-old"
#define RC_MAP_CINERGY_1400 "rc-cinergy-1400"
#define RC_MAP_CINERGY "rc-cinergy"
+#define RC_MAP_DIB0700_NEC_TABLE "rc-dib0700-nec"
+#define RC_MAP_DIB0700_RC5_TABLE "rc-dib0700-rc5"
#define RC_MAP_DM1105_NEC "rc-dm1105-nec"
#define RC_MAP_DNTV_LIVE_DVBT_PRO "rc-dntv-live-dvbt-pro"
#define RC_MAP_DNTV_LIVE_DVB_T "rc-dntv-live-dvb-t"
@@ -87,6 +94,7 @@ void rc_map_init(void);
#define RC_MAP_KAIOMY "rc-kaiomy"
#define RC_MAP_KWORLD_315U "rc-kworld-315u"
#define RC_MAP_KWORLD_PLUS_TV_ANALOG "rc-kworld-plus-tv-analog"
+#define RC_MAP_LIRC "rc-lirc"
#define RC_MAP_MANLI "rc-manli"
#define RC_MAP_MSI_TVANYWHERE_PLUS "rc-msi-tvanywhere-plus"
#define RC_MAP_MSI_TVANYWHERE "rc-msi-tvanywhere"
@@ -107,6 +115,7 @@ void rc_map_init(void);
#define RC_MAP_PV951 "rc-pv951"
#define RC_MAP_RC5_HAUPPAUGE_NEW "rc-rc5-hauppauge-new"
#define RC_MAP_RC5_TV "rc-rc5-tv"
+#define RC_MAP_RC6_MCE "rc-rc6-mce"
#define RC_MAP_REAL_AUDIO_220_32_KEYS "rc-real-audio-220-32-keys"
#define RC_MAP_TBS_NEC "rc-tbs-nec"
#define RC_MAP_TERRATEC_CINERGY_XS "rc-terratec-cinergy-xs"
@@ -116,6 +125,7 @@ void rc_map_init(void);
#define RC_MAP_VIDEOMATE_TV_PVR "rc-videomate-tv-pvr"
#define RC_MAP_WINFAST "rc-winfast"
#define RC_MAP_WINFAST_USBII_DELUXE "rc-winfast-usbii-deluxe"
+
/*
* Please, do not just append newer Remote Controller names at the end.
* The names should be ordered in alphabetical order
diff --git a/include/media/sh_mobile_ceu.h b/include/media/sh_mobile_ceu.h
index b6774783687..80346a6d28a 100644
--- a/include/media/sh_mobile_ceu.h
+++ b/include/media/sh_mobile_ceu.h
@@ -6,8 +6,11 @@
#define SH_CEU_FLAG_HSYNC_LOW (1 << 2) /* default High if possible */
#define SH_CEU_FLAG_VSYNC_LOW (1 << 3) /* default High if possible */
+struct device;
+
struct sh_mobile_ceu_info {
unsigned long flags;
+ struct device *csi2_dev;
};
#endif /* __ASM_SH_MOBILE_CEU_H__ */
diff --git a/include/media/sh_mobile_csi2.h b/include/media/sh_mobile_csi2.h
new file mode 100644
index 00000000000..4d261517446
--- /dev/null
+++ b/include/media/sh_mobile_csi2.h
@@ -0,0 +1,46 @@
+/*
+ * Driver header for the SH-Mobile MIPI CSI-2 unit
+ *
+ * Copyright (C) 2010, Guennadi Liakhovetski <g.liakhovetski@gmx.de>
+ *
+ * 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 SH_MIPI_CSI
+#define SH_MIPI_CSI
+
+enum sh_csi2_phy {
+ SH_CSI2_PHY_MAIN,
+ SH_CSI2_PHY_SUB,
+};
+
+enum sh_csi2_type {
+ SH_CSI2C,
+ SH_CSI2I,
+};
+
+#define SH_CSI2_CRC (1 << 0)
+#define SH_CSI2_ECC (1 << 1)
+
+struct platform_device;
+
+struct sh_csi2_client_config {
+ enum sh_csi2_phy phy;
+ unsigned char lanes; /* bitmask[3:0] */
+ unsigned char channel; /* 0..3 */
+ struct platform_device *pdev; /* client platform device */
+};
+
+struct sh_csi2_pdata {
+ enum sh_csi2_type type;
+ unsigned int flags;
+ struct sh_csi2_client_config *clients;
+ int num_clients;
+};
+
+struct device;
+struct v4l2_device;
+
+#endif
diff --git a/include/media/soc_camera.h b/include/media/soc_camera.h
index b8289c2f609..2ce957301f7 100644
--- a/include/media/soc_camera.h
+++ b/include/media/soc_camera.h
@@ -12,12 +12,15 @@
#ifndef SOC_CAMERA_H
#define SOC_CAMERA_H
+#include <linux/device.h>
#include <linux/mutex.h>
#include <linux/pm.h>
#include <linux/videodev2.h>
#include <media/videobuf-core.h>
#include <media/v4l2-device.h>
+extern struct bus_type soc_camera_bus_type;
+
struct soc_camera_device {
struct list_head list;
struct device dev;
diff --git a/include/media/v4l2-mediabus.h b/include/media/v4l2-mediabus.h
index 865cda7cd61..f0cf2e7def0 100644
--- a/include/media/v4l2-mediabus.h
+++ b/include/media/v4l2-mediabus.h
@@ -24,10 +24,10 @@
*/
enum v4l2_mbus_pixelcode {
V4L2_MBUS_FMT_FIXED = 1,
- V4L2_MBUS_FMT_YUYV8_2X8_LE,
- V4L2_MBUS_FMT_YVYU8_2X8_LE,
- V4L2_MBUS_FMT_YUYV8_2X8_BE,
- V4L2_MBUS_FMT_YVYU8_2X8_BE,
+ V4L2_MBUS_FMT_YUYV8_2X8,
+ V4L2_MBUS_FMT_YVYU8_2X8,
+ V4L2_MBUS_FMT_UYVY8_2X8,
+ V4L2_MBUS_FMT_VYUY8_2X8,
V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE,
V4L2_MBUS_FMT_RGB555_2X8_PADHI_BE,
V4L2_MBUS_FMT_RGB565_2X8_LE,
@@ -41,6 +41,11 @@ enum v4l2_mbus_pixelcode {
V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_BE,
V4L2_MBUS_FMT_SBGGR10_2X8_PADLO_BE,
V4L2_MBUS_FMT_SGRBG8_1X8,
+ V4L2_MBUS_FMT_SBGGR12_1X12,
+ V4L2_MBUS_FMT_YUYV8_1_5X8,
+ V4L2_MBUS_FMT_YVYU8_1_5X8,
+ V4L2_MBUS_FMT_UYVY8_1_5X8,
+ V4L2_MBUS_FMT_VYUY8_1_5X8,
};
/**
diff --git a/include/media/videobuf-core.h b/include/media/videobuf-core.h
index f91a736c133..f2c41cebf45 100644
--- a/include/media/videobuf-core.h
+++ b/include/media/videobuf-core.h
@@ -54,8 +54,6 @@ struct videobuf_queue;
struct videobuf_mapping {
unsigned int count;
- unsigned long start;
- unsigned long end;
struct videobuf_queue *q;
};
@@ -127,7 +125,7 @@ struct videobuf_queue_ops {
struct videobuf_qtype_ops {
u32 magic;
- struct videobuf_buffer *(*alloc)(size_t size);
+ struct videobuf_buffer *(*alloc_vb)(size_t size);
void *(*vaddr) (struct videobuf_buffer *buf);
int (*iolock) (struct videobuf_queue *q,
struct videobuf_buffer *vb,
@@ -173,7 +171,7 @@ int videobuf_waiton(struct videobuf_buffer *vb, int non_blocking, int intr);
int videobuf_iolock(struct videobuf_queue *q, struct videobuf_buffer *vb,
struct v4l2_framebuffer *fbuf);
-struct videobuf_buffer *videobuf_alloc(struct videobuf_queue *q);
+struct videobuf_buffer *videobuf_alloc_vb(struct videobuf_queue *q);
/* Used on videobuf-dvb */
void *videobuf_queue_to_vaddr(struct videobuf_queue *q,
diff --git a/include/media/videobuf-dma-sg.h b/include/media/videobuf-dma-sg.h
index a195f3b9c00..97e07f46a0f 100644
--- a/include/media/videobuf-dma-sg.h
+++ b/include/media/videobuf-dma-sg.h
@@ -25,23 +25,6 @@
/* --------------------------------------------------------------------- */
/*
- * Return a scatterlist for some page-aligned vmalloc()'ed memory
- * block (NULL on errors). Memory for the scatterlist is allocated
- * using kmalloc. The caller must free the memory.
- */
-struct scatterlist *videobuf_vmalloc_to_sg(unsigned char *virt, int nr_pages);
-
-/*
- * Return a scatterlist for a an array of userpages (NULL on errors).
- * Memory for the scatterlist is allocated using kmalloc. The caller
- * must free the memory.
- */
-struct scatterlist *videobuf_pages_to_sg(struct page **pages, int nr_pages,
- int offset);
-
-/* --------------------------------------------------------------------- */
-
-/*
* A small set of helper functions to manage buffers (both userland
* and kernel) for DMA.
*
@@ -68,7 +51,7 @@ struct videobuf_dmabuf {
struct page **pages;
/* for kernel buffers */
- void *vmalloc;
+ void *vaddr;
/* for overlay buffers (pci-pci dma) */
dma_addr_t bus_addr;
@@ -87,6 +70,16 @@ struct videobuf_dma_sg_memory {
struct videobuf_dmabuf dma;
};
+/*
+ * Scatter-gather DMA buffer API.
+ *
+ * These functions provide a simple way to create a page list and a
+ * scatter-gather list from a kernel, userspace of physical address and map the
+ * memory for DMA operation.
+ *
+ * Despite the name, this is totally unrelated to videobuf, except that
+ * videobuf-dma-sg uses the same API internally.
+ */
void videobuf_dma_init(struct videobuf_dmabuf *dma);
int videobuf_dma_init_user(struct videobuf_dmabuf *dma, int direction,
unsigned long data, unsigned long size);
@@ -96,8 +89,8 @@ int videobuf_dma_init_overlay(struct videobuf_dmabuf *dma, int direction,
dma_addr_t addr, int nr_pages);
int videobuf_dma_free(struct videobuf_dmabuf *dma);
-int videobuf_dma_map(struct videobuf_queue *q, struct videobuf_dmabuf *dma);
-int videobuf_dma_unmap(struct videobuf_queue *q, struct videobuf_dmabuf *dma);
+int videobuf_dma_map(struct device *dev, struct videobuf_dmabuf *dma);
+int videobuf_dma_unmap(struct device *dev, struct videobuf_dmabuf *dma);
struct videobuf_dmabuf *videobuf_to_dma(struct videobuf_buffer *buf);
void *videobuf_sg_alloc(size_t size);
@@ -111,11 +104,5 @@ void videobuf_queue_sg_init(struct videobuf_queue *q,
unsigned int msize,
void *priv);
-/*FIXME: these variants are used only on *-alsa code, where videobuf is
- * used without queue
- */
-int videobuf_sg_dma_map(struct device *dev, struct videobuf_dmabuf *dma);
-int videobuf_sg_dma_unmap(struct device *dev, struct videobuf_dmabuf *dma);
-
#endif /* _VIDEOBUF_DMA_SG_H */
diff --git a/include/media/videobuf-vmalloc.h b/include/media/videobuf-vmalloc.h
index 851eb1a2ff2..e19403c18da 100644
--- a/include/media/videobuf-vmalloc.h
+++ b/include/media/videobuf-vmalloc.h
@@ -22,7 +22,7 @@
struct videobuf_vmalloc_memory {
u32 magic;
- void *vmalloc;
+ void *vaddr;
/* remap_vmalloc_range seems to need to run
* after mmap() on some cases */
diff --git a/include/net/9p/9p.h b/include/net/9p/9p.h
index 156c26bb8bd..a8de812ccbc 100644
--- a/include/net/9p/9p.h
+++ b/include/net/9p/9p.h
@@ -88,8 +88,16 @@ do { \
* enum p9_msg_t - 9P message types
* @P9_TSTATFS: file system status request
* @P9_RSTATFS: file system status response
+ * @P9_TSYMLINK: make symlink request
+ * @P9_RSYMLINK: make symlink response
+ * @P9_TMKNOD: create a special file object request
+ * @P9_RMKNOD: create a special file object response
+ * @P9_TLCREATE: prepare a handle for I/O on an new file for 9P2000.L
+ * @P9_RLCREATE: response with file access information for 9P2000.L
* @P9_TRENAME: rename request
* @P9_RRENAME: rename response
+ * @P9_TMKDIR: create a directory request
+ * @P9_RMKDIR: create a directory response
* @P9_TVERSION: version handshake request
* @P9_RVERSION: version handshake response
* @P9_TAUTH: request to establish authentication channel
@@ -131,8 +139,30 @@ do { \
enum p9_msg_t {
P9_TSTATFS = 8,
P9_RSTATFS,
+ P9_TLOPEN = 12,
+ P9_RLOPEN,
+ P9_TLCREATE = 14,
+ P9_RLCREATE,
+ P9_TSYMLINK = 16,
+ P9_RSYMLINK,
+ P9_TMKNOD = 18,
+ P9_RMKNOD,
P9_TRENAME = 20,
P9_RRENAME,
+ P9_TGETATTR = 24,
+ P9_RGETATTR,
+ P9_TSETATTR = 26,
+ P9_RSETATTR,
+ P9_TXATTRWALK = 30,
+ P9_RXATTRWALK,
+ P9_TXATTRCREATE = 32,
+ P9_RXATTRCREATE,
+ P9_TREADDIR = 40,
+ P9_RREADDIR,
+ P9_TLINK = 70,
+ P9_RLINK,
+ P9_TMKDIR = 72,
+ P9_RMKDIR,
P9_TVERSION = 100,
P9_RVERSION,
P9_TAUTH = 102,
@@ -275,6 +305,9 @@ enum p9_qid_t {
/* ample room for Twrite/Rread header */
#define P9_IOHDRSZ 24
+/* Room for readdir header */
+#define P9_READDIRHDRSZ 24
+
/**
* struct p9_str - length prefixed string type
* @len: length of the string
@@ -357,6 +390,74 @@ struct p9_wstat {
u32 n_muid; /* 9p2000.u extensions */
};
+struct p9_stat_dotl {
+ u64 st_result_mask;
+ struct p9_qid qid;
+ u32 st_mode;
+ u32 st_uid;
+ u32 st_gid;
+ u64 st_nlink;
+ u64 st_rdev;
+ u64 st_size;
+ u64 st_blksize;
+ u64 st_blocks;
+ u64 st_atime_sec;
+ u64 st_atime_nsec;
+ u64 st_mtime_sec;
+ u64 st_mtime_nsec;
+ u64 st_ctime_sec;
+ u64 st_ctime_nsec;
+ u64 st_btime_sec;
+ u64 st_btime_nsec;
+ u64 st_gen;
+ u64 st_data_version;
+};
+
+#define P9_STATS_MODE 0x00000001ULL
+#define P9_STATS_NLINK 0x00000002ULL
+#define P9_STATS_UID 0x00000004ULL
+#define P9_STATS_GID 0x00000008ULL
+#define P9_STATS_RDEV 0x00000010ULL
+#define P9_STATS_ATIME 0x00000020ULL
+#define P9_STATS_MTIME 0x00000040ULL
+#define P9_STATS_CTIME 0x00000080ULL
+#define P9_STATS_INO 0x00000100ULL
+#define P9_STATS_SIZE 0x00000200ULL
+#define P9_STATS_BLOCKS 0x00000400ULL
+
+#define P9_STATS_BTIME 0x00000800ULL
+#define P9_STATS_GEN 0x00001000ULL
+#define P9_STATS_DATA_VERSION 0x00002000ULL
+
+#define P9_STATS_BASIC 0x000007ffULL /* Mask for fields up to BLOCKS */
+#define P9_STATS_ALL 0x00003fffULL /* Mask for All fields above */
+
+/**
+ * struct p9_iattr_dotl - P9 inode attribute for setattr
+ * @valid: bitfield specifying which fields are valid
+ * same as in struct iattr
+ * @mode: File permission bits
+ * @uid: user id of owner
+ * @gid: group id
+ * @size: File size
+ * @atime_sec: Last access time, seconds
+ * @atime_nsec: Last access time, nanoseconds
+ * @mtime_sec: Last modification time, seconds
+ * @mtime_nsec: Last modification time, nanoseconds
+ */
+
+struct p9_iattr_dotl {
+ u32 valid;
+ u32 mode;
+ u32 uid;
+ u32 gid;
+ u64 size;
+ u64 atime_sec;
+ u64 atime_nsec;
+ u64 mtime_sec;
+ u64 mtime_nsec;
+};
+
/* Structures for Protocol Operations */
struct p9_tstatfs {
u32 fid;
@@ -485,6 +586,18 @@ struct p9_rwrite {
u32 count;
};
+struct p9_treaddir {
+ u32 fid;
+ u64 offset;
+ u32 count;
+};
+
+struct p9_rreaddir {
+ u32 count;
+ u8 *data;
+};
+
+
struct p9_tclunk {
u32 fid;
};
diff --git a/include/net/9p/client.h b/include/net/9p/client.h
index 7dd3ed85c78..d1aa2cfb30f 100644
--- a/include/net/9p/client.h
+++ b/include/net/9p/client.h
@@ -195,6 +195,21 @@ struct p9_fid {
struct list_head dlist; /* list of all fids attached to a dentry */
};
+/**
+ * struct p9_dirent - directory entry structure
+ * @qid: The p9 server qid for this dirent
+ * @d_off: offset to the next dirent
+ * @d_type: type of file
+ * @d_name: file name
+ */
+
+struct p9_dirent {
+ struct p9_qid qid;
+ u64 d_off;
+ unsigned char d_type;
+ char d_name[256];
+};
+
int p9_client_statfs(struct p9_fid *fid, struct p9_rstatfs *sb);
int p9_client_rename(struct p9_fid *fid, struct p9_fid *newdirfid, char *name);
int p9_client_version(struct p9_client *);
@@ -211,15 +226,31 @@ struct p9_fid *p9_client_walk(struct p9_fid *oldfid, int nwname, char **wnames,
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_link(struct p9_fid *fid, struct p9_fid *oldfid, char *newname);
+int p9_client_symlink(struct p9_fid *fid, char *name, char *symname, gid_t gid,
+ struct p9_qid *qid);
+int p9_client_create_dotl(struct p9_fid *ofid, char *name, u32 flags, u32 mode,
+ gid_t gid, struct p9_qid *qid);
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, char __user *udata,
u64 offset, u32 count);
int p9_client_write(struct p9_fid *fid, char *data, const char __user *udata,
u64 offset, u32 count);
+int p9_client_readdir(struct p9_fid *fid, char *data, u32 count, u64 offset);
+int p9dirent_read(char *buf, int len, struct p9_dirent *dirent,
+ int proto_version);
struct p9_wstat *p9_client_stat(struct p9_fid *fid);
int p9_client_wstat(struct p9_fid *fid, struct p9_wstat *wst);
+int p9_client_setattr(struct p9_fid *fid, struct p9_iattr_dotl *attr);
+
+struct p9_stat_dotl *p9_client_getattr_dotl(struct p9_fid *fid,
+ u64 request_mask);
+int p9_client_mknod_dotl(struct p9_fid *oldfid, char *name, int mode,
+ dev_t rdev, gid_t gid, struct p9_qid *);
+int p9_client_mkdir_dotl(struct p9_fid *fid, char *name, int mode,
+ gid_t gid, struct p9_qid *);
struct p9_req_t *p9_tag_lookup(struct p9_client *, u16);
void p9_client_cb(struct p9_client *c, struct p9_req_t *req);
@@ -229,5 +260,7 @@ void p9stat_free(struct p9_wstat *);
int p9_is_proto_dotu(struct p9_client *clnt);
int p9_is_proto_dotl(struct p9_client *clnt);
+struct p9_fid *p9_client_xattrwalk(struct p9_fid *, const char *, u64 *);
+int p9_client_xattrcreate(struct p9_fid *, const char *, u64, int);
#endif /* NET_9P_CLIENT_H */
diff --git a/include/net/act_api.h b/include/net/act_api.h
index c05fd717c58..bab385f13ac 100644
--- a/include/net/act_api.h
+++ b/include/net/act_api.h
@@ -20,6 +20,7 @@ struct tcf_common {
struct gnet_stats_queue tcfc_qstats;
struct gnet_stats_rate_est tcfc_rate_est;
spinlock_t tcfc_lock;
+ struct rcu_head tcfc_rcu;
};
#define tcf_next common.tcfc_next
#define tcf_index common.tcfc_index
@@ -32,6 +33,7 @@ struct tcf_common {
#define tcf_qstats common.tcfc_qstats
#define tcf_rate_est common.tcfc_rate_est
#define tcf_lock common.tcfc_lock
+#define tcf_rcu common.tcfc_rcu
struct tcf_police {
struct tcf_common common;
diff --git a/include/net/af_unix.h b/include/net/af_unix.h
index 20725e213ae..90c9e2872f2 100644
--- a/include/net/af_unix.h
+++ b/include/net/af_unix.h
@@ -23,7 +23,8 @@ struct unix_address {
};
struct unix_skb_parms {
- struct ucred creds; /* Skb credentials */
+ struct pid *pid; /* Skb credentials */
+ const struct cred *cred;
struct scm_fp_list *fp; /* Passed files */
#ifdef CONFIG_SECURITY_NETWORK
u32 secid; /* Security ID */
@@ -31,7 +32,6 @@ struct unix_skb_parms {
};
#define UNIXCB(skb) (*(struct unix_skb_parms *)&((skb)->cb))
-#define UNIXCREDS(skb) (&UNIXCB((skb)).creds)
#define UNIXSID(skb) (&UNIXCB((skb)).secid)
#define unix_state_lock(s) spin_lock(&unix_sk(s)->lock)
diff --git a/include/net/bluetooth/bluetooth.h b/include/net/bluetooth/bluetooth.h
index ff77e8f882f..27a902d9b3a 100644
--- a/include/net/bluetooth/bluetooth.h
+++ b/include/net/bluetooth/bluetooth.h
@@ -84,7 +84,7 @@ enum {
/* BD Address */
typedef struct {
__u8 b[6];
-} __attribute__((packed)) bdaddr_t;
+} __packed bdaddr_t;
#define BDADDR_ANY (&(bdaddr_t) {{0, 0, 0, 0, 0, 0}})
#define BDADDR_LOCAL (&(bdaddr_t) {{0, 0, 0, 0xff, 0xff, 0xff}})
@@ -138,6 +138,7 @@ struct sock *bt_accept_dequeue(struct sock *parent, struct socket *newsock);
struct bt_skb_cb {
__u8 pkt_type;
__u8 incoming;
+ __u16 expect;
__u8 tx_seq;
__u8 retries;
__u8 sar;
diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
index fc0c502d9fd..bcbdd6d4e6d 100644
--- a/include/net/bluetooth/hci.h
+++ b/include/net/bluetooth/hci.h
@@ -100,6 +100,9 @@ enum {
#define HCISETACLMTU _IOW('H', 227, int)
#define HCISETSCOMTU _IOW('H', 228, int)
+#define HCIBLOCKADDR _IOW('H', 230, int)
+#define HCIUNBLOCKADDR _IOW('H', 231, int)
+
#define HCIINQUIRY _IOR('H', 240, int)
/* HCI timeouts */
@@ -227,7 +230,7 @@ struct hci_cp_inquiry {
__u8 lap[3];
__u8 length;
__u8 num_rsp;
-} __attribute__ ((packed));
+} __packed;
#define HCI_OP_INQUIRY_CANCEL 0x0402
@@ -241,81 +244,81 @@ struct hci_cp_create_conn {
__u8 pscan_mode;
__le16 clock_offset;
__u8 role_switch;
-} __attribute__ ((packed));
+} __packed;
#define HCI_OP_DISCONNECT 0x0406
struct hci_cp_disconnect {
__le16 handle;
__u8 reason;
-} __attribute__ ((packed));
+} __packed;
#define HCI_OP_ADD_SCO 0x0407
struct hci_cp_add_sco {
__le16 handle;
__le16 pkt_type;
-} __attribute__ ((packed));
+} __packed;
#define HCI_OP_CREATE_CONN_CANCEL 0x0408
struct hci_cp_create_conn_cancel {
bdaddr_t bdaddr;
-} __attribute__ ((packed));
+} __packed;
#define HCI_OP_ACCEPT_CONN_REQ 0x0409
struct hci_cp_accept_conn_req {
bdaddr_t bdaddr;
__u8 role;
-} __attribute__ ((packed));
+} __packed;
#define HCI_OP_REJECT_CONN_REQ 0x040a
struct hci_cp_reject_conn_req {
bdaddr_t bdaddr;
__u8 reason;
-} __attribute__ ((packed));
+} __packed;
#define HCI_OP_LINK_KEY_REPLY 0x040b
struct hci_cp_link_key_reply {
bdaddr_t bdaddr;
__u8 link_key[16];
-} __attribute__ ((packed));
+} __packed;
#define HCI_OP_LINK_KEY_NEG_REPLY 0x040c
struct hci_cp_link_key_neg_reply {
bdaddr_t bdaddr;
-} __attribute__ ((packed));
+} __packed;
#define HCI_OP_PIN_CODE_REPLY 0x040d
struct hci_cp_pin_code_reply {
bdaddr_t bdaddr;
__u8 pin_len;
__u8 pin_code[16];
-} __attribute__ ((packed));
+} __packed;
#define HCI_OP_PIN_CODE_NEG_REPLY 0x040e
struct hci_cp_pin_code_neg_reply {
bdaddr_t bdaddr;
-} __attribute__ ((packed));
+} __packed;
#define HCI_OP_CHANGE_CONN_PTYPE 0x040f
struct hci_cp_change_conn_ptype {
__le16 handle;
__le16 pkt_type;
-} __attribute__ ((packed));
+} __packed;
#define HCI_OP_AUTH_REQUESTED 0x0411
struct hci_cp_auth_requested {
__le16 handle;
-} __attribute__ ((packed));
+} __packed;
#define HCI_OP_SET_CONN_ENCRYPT 0x0413
struct hci_cp_set_conn_encrypt {
__le16 handle;
__u8 encrypt;
-} __attribute__ ((packed));
+} __packed;
#define HCI_OP_CHANGE_CONN_LINK_KEY 0x0415
struct hci_cp_change_conn_link_key {
__le16 handle;
-} __attribute__ ((packed));
+} __packed;
#define HCI_OP_REMOTE_NAME_REQ 0x0419
struct hci_cp_remote_name_req {
@@ -323,28 +326,28 @@ struct hci_cp_remote_name_req {
__u8 pscan_rep_mode;
__u8 pscan_mode;
__le16 clock_offset;
-} __attribute__ ((packed));
+} __packed;
#define HCI_OP_REMOTE_NAME_REQ_CANCEL 0x041a
struct hci_cp_remote_name_req_cancel {
bdaddr_t bdaddr;
-} __attribute__ ((packed));
+} __packed;
#define HCI_OP_READ_REMOTE_FEATURES 0x041b
struct hci_cp_read_remote_features {
__le16 handle;
-} __attribute__ ((packed));
+} __packed;
#define HCI_OP_READ_REMOTE_EXT_FEATURES 0x041c
struct hci_cp_read_remote_ext_features {
__le16 handle;
__u8 page;
-} __attribute__ ((packed));
+} __packed;
#define HCI_OP_READ_REMOTE_VERSION 0x041d
struct hci_cp_read_remote_version {
__le16 handle;
-} __attribute__ ((packed));
+} __packed;
#define HCI_OP_SETUP_SYNC_CONN 0x0428
struct hci_cp_setup_sync_conn {
@@ -355,7 +358,7 @@ struct hci_cp_setup_sync_conn {
__le16 voice_setting;
__u8 retrans_effort;
__le16 pkt_type;
-} __attribute__ ((packed));
+} __packed;
#define HCI_OP_ACCEPT_SYNC_CONN_REQ 0x0429
struct hci_cp_accept_sync_conn_req {
@@ -366,13 +369,13 @@ struct hci_cp_accept_sync_conn_req {
__le16 content_format;
__u8 retrans_effort;
__le16 pkt_type;
-} __attribute__ ((packed));
+} __packed;
#define HCI_OP_REJECT_SYNC_CONN_REQ 0x042a
struct hci_cp_reject_sync_conn_req {
bdaddr_t bdaddr;
__u8 reason;
-} __attribute__ ((packed));
+} __packed;
#define HCI_OP_SNIFF_MODE 0x0803
struct hci_cp_sniff_mode {
@@ -381,59 +384,59 @@ struct hci_cp_sniff_mode {
__le16 min_interval;
__le16 attempt;
__le16 timeout;
-} __attribute__ ((packed));
+} __packed;
#define HCI_OP_EXIT_SNIFF_MODE 0x0804
struct hci_cp_exit_sniff_mode {
__le16 handle;
-} __attribute__ ((packed));
+} __packed;
#define HCI_OP_ROLE_DISCOVERY 0x0809
struct hci_cp_role_discovery {
__le16 handle;
-} __attribute__ ((packed));
+} __packed;
struct hci_rp_role_discovery {
__u8 status;
__le16 handle;
__u8 role;
-} __attribute__ ((packed));
+} __packed;
#define HCI_OP_SWITCH_ROLE 0x080b
struct hci_cp_switch_role {
bdaddr_t bdaddr;
__u8 role;
-} __attribute__ ((packed));
+} __packed;
#define HCI_OP_READ_LINK_POLICY 0x080c
struct hci_cp_read_link_policy {
__le16 handle;
-} __attribute__ ((packed));
+} __packed;
struct hci_rp_read_link_policy {
__u8 status;
__le16 handle;
__le16 policy;
-} __attribute__ ((packed));
+} __packed;
#define HCI_OP_WRITE_LINK_POLICY 0x080d
struct hci_cp_write_link_policy {
__le16 handle;
__le16 policy;
-} __attribute__ ((packed));
+} __packed;
struct hci_rp_write_link_policy {
__u8 status;
__le16 handle;
-} __attribute__ ((packed));
+} __packed;
#define HCI_OP_READ_DEF_LINK_POLICY 0x080e
struct hci_rp_read_def_link_policy {
__u8 status;
__le16 policy;
-} __attribute__ ((packed));
+} __packed;
#define HCI_OP_WRITE_DEF_LINK_POLICY 0x080f
struct hci_cp_write_def_link_policy {
__le16 policy;
-} __attribute__ ((packed));
+} __packed;
#define HCI_OP_SNIFF_SUBRATE 0x0811
struct hci_cp_sniff_subrate {
@@ -441,12 +444,12 @@ struct hci_cp_sniff_subrate {
__le16 max_latency;
__le16 min_remote_timeout;
__le16 min_local_timeout;
-} __attribute__ ((packed));
+} __packed;
#define HCI_OP_SET_EVENT_MASK 0x0c01
struct hci_cp_set_event_mask {
__u8 mask[8];
-} __attribute__ ((packed));
+} __packed;
#define HCI_OP_RESET 0x0c03
@@ -455,7 +458,7 @@ struct hci_cp_set_event_flt {
__u8 flt_type;
__u8 cond_type;
__u8 condition[0];
-} __attribute__ ((packed));
+} __packed;
/* Filter types */
#define HCI_FLT_CLEAR_ALL 0x00
@@ -474,13 +477,13 @@ struct hci_cp_set_event_flt {
#define HCI_OP_WRITE_LOCAL_NAME 0x0c13
struct hci_cp_write_local_name {
__u8 name[248];
-} __attribute__ ((packed));
+} __packed;
#define HCI_OP_READ_LOCAL_NAME 0x0c14
struct hci_rp_read_local_name {
__u8 status;
__u8 name[248];
-} __attribute__ ((packed));
+} __packed;
#define HCI_OP_WRITE_CA_TIMEOUT 0x0c16
@@ -508,23 +511,23 @@ struct hci_rp_read_local_name {
struct hci_rp_read_class_of_dev {
__u8 status;
__u8 dev_class[3];
-} __attribute__ ((packed));
+} __packed;
#define HCI_OP_WRITE_CLASS_OF_DEV 0x0c24
struct hci_cp_write_class_of_dev {
__u8 dev_class[3];
-} __attribute__ ((packed));
+} __packed;
#define HCI_OP_READ_VOICE_SETTING 0x0c25
struct hci_rp_read_voice_setting {
__u8 status;
__le16 voice_setting;
-} __attribute__ ((packed));
+} __packed;
#define HCI_OP_WRITE_VOICE_SETTING 0x0c26
struct hci_cp_write_voice_setting {
__le16 voice_setting;
-} __attribute__ ((packed));
+} __packed;
#define HCI_OP_HOST_BUFFER_SIZE 0x0c33
struct hci_cp_host_buffer_size {
@@ -532,18 +535,18 @@ struct hci_cp_host_buffer_size {
__u8 sco_mtu;
__le16 acl_max_pkt;
__le16 sco_max_pkt;
-} __attribute__ ((packed));
+} __packed;
#define HCI_OP_READ_SSP_MODE 0x0c55
struct hci_rp_read_ssp_mode {
__u8 status;
__u8 mode;
-} __attribute__ ((packed));
+} __packed;
#define HCI_OP_WRITE_SSP_MODE 0x0c56
struct hci_cp_write_ssp_mode {
__u8 mode;
-} __attribute__ ((packed));
+} __packed;
#define HCI_OP_READ_LOCAL_VERSION 0x1001
struct hci_rp_read_local_version {
@@ -553,19 +556,19 @@ struct hci_rp_read_local_version {
__u8 lmp_ver;
__le16 manufacturer;
__le16 lmp_subver;
-} __attribute__ ((packed));
+} __packed;
#define HCI_OP_READ_LOCAL_COMMANDS 0x1002
struct hci_rp_read_local_commands {
__u8 status;
__u8 commands[64];
-} __attribute__ ((packed));
+} __packed;
#define HCI_OP_READ_LOCAL_FEATURES 0x1003
struct hci_rp_read_local_features {
__u8 status;
__u8 features[8];
-} __attribute__ ((packed));
+} __packed;
#define HCI_OP_READ_LOCAL_EXT_FEATURES 0x1004
struct hci_rp_read_local_ext_features {
@@ -573,7 +576,7 @@ struct hci_rp_read_local_ext_features {
__u8 page;
__u8 max_page;
__u8 features[8];
-} __attribute__ ((packed));
+} __packed;
#define HCI_OP_READ_BUFFER_SIZE 0x1005
struct hci_rp_read_buffer_size {
@@ -582,13 +585,13 @@ struct hci_rp_read_buffer_size {
__u8 sco_mtu;
__le16 acl_max_pkt;
__le16 sco_max_pkt;
-} __attribute__ ((packed));
+} __packed;
#define HCI_OP_READ_BD_ADDR 0x1009
struct hci_rp_read_bd_addr {
__u8 status;
bdaddr_t bdaddr;
-} __attribute__ ((packed));
+} __packed;
/* ---- HCI Events ---- */
#define HCI_EV_INQUIRY_COMPLETE 0x01
@@ -601,7 +604,7 @@ struct inquiry_info {
__u8 pscan_mode;
__u8 dev_class[3];
__le16 clock_offset;
-} __attribute__ ((packed));
+} __packed;
#define HCI_EV_CONN_COMPLETE 0x03
struct hci_ev_conn_complete {
@@ -610,54 +613,54 @@ struct hci_ev_conn_complete {
bdaddr_t bdaddr;
__u8 link_type;
__u8 encr_mode;
-} __attribute__ ((packed));
+} __packed;
#define HCI_EV_CONN_REQUEST 0x04
struct hci_ev_conn_request {
bdaddr_t bdaddr;
__u8 dev_class[3];
__u8 link_type;
-} __attribute__ ((packed));
+} __packed;
#define HCI_EV_DISCONN_COMPLETE 0x05
struct hci_ev_disconn_complete {
__u8 status;
__le16 handle;
__u8 reason;
-} __attribute__ ((packed));
+} __packed;
#define HCI_EV_AUTH_COMPLETE 0x06
struct hci_ev_auth_complete {
__u8 status;
__le16 handle;
-} __attribute__ ((packed));
+} __packed;
#define HCI_EV_REMOTE_NAME 0x07
struct hci_ev_remote_name {
__u8 status;
bdaddr_t bdaddr;
__u8 name[248];
-} __attribute__ ((packed));
+} __packed;
#define HCI_EV_ENCRYPT_CHANGE 0x08
struct hci_ev_encrypt_change {
__u8 status;
__le16 handle;
__u8 encrypt;
-} __attribute__ ((packed));
+} __packed;
#define HCI_EV_CHANGE_LINK_KEY_COMPLETE 0x09
struct hci_ev_change_link_key_complete {
__u8 status;
__le16 handle;
-} __attribute__ ((packed));
+} __packed;
#define HCI_EV_REMOTE_FEATURES 0x0b
struct hci_ev_remote_features {
__u8 status;
__le16 handle;
__u8 features[8];
-} __attribute__ ((packed));
+} __packed;
#define HCI_EV_REMOTE_VERSION 0x0c
struct hci_ev_remote_version {
@@ -666,7 +669,7 @@ struct hci_ev_remote_version {
__u8 lmp_ver;
__le16 manufacturer;
__le16 lmp_subver;
-} __attribute__ ((packed));
+} __packed;
#define HCI_EV_QOS_SETUP_COMPLETE 0x0d
struct hci_qos {
@@ -675,38 +678,38 @@ struct hci_qos {
__u32 peak_bandwidth;
__u32 latency;
__u32 delay_variation;
-} __attribute__ ((packed));
+} __packed;
struct hci_ev_qos_setup_complete {
__u8 status;
__le16 handle;
struct hci_qos qos;
-} __attribute__ ((packed));
+} __packed;
#define HCI_EV_CMD_COMPLETE 0x0e
struct hci_ev_cmd_complete {
__u8 ncmd;
__le16 opcode;
-} __attribute__ ((packed));
+} __packed;
#define HCI_EV_CMD_STATUS 0x0f
struct hci_ev_cmd_status {
__u8 status;
__u8 ncmd;
__le16 opcode;
-} __attribute__ ((packed));
+} __packed;
#define HCI_EV_ROLE_CHANGE 0x12
struct hci_ev_role_change {
__u8 status;
bdaddr_t bdaddr;
__u8 role;
-} __attribute__ ((packed));
+} __packed;
#define HCI_EV_NUM_COMP_PKTS 0x13
struct hci_ev_num_comp_pkts {
__u8 num_hndl;
/* variable length part */
-} __attribute__ ((packed));
+} __packed;
#define HCI_EV_MODE_CHANGE 0x14
struct hci_ev_mode_change {
@@ -714,44 +717,44 @@ struct hci_ev_mode_change {
__le16 handle;
__u8 mode;
__le16 interval;
-} __attribute__ ((packed));
+} __packed;
#define HCI_EV_PIN_CODE_REQ 0x16
struct hci_ev_pin_code_req {
bdaddr_t bdaddr;
-} __attribute__ ((packed));
+} __packed;
#define HCI_EV_LINK_KEY_REQ 0x17
struct hci_ev_link_key_req {
bdaddr_t bdaddr;
-} __attribute__ ((packed));
+} __packed;
#define HCI_EV_LINK_KEY_NOTIFY 0x18
struct hci_ev_link_key_notify {
bdaddr_t bdaddr;
__u8 link_key[16];
__u8 key_type;
-} __attribute__ ((packed));
+} __packed;
#define HCI_EV_CLOCK_OFFSET 0x1c
struct hci_ev_clock_offset {
__u8 status;
__le16 handle;
__le16 clock_offset;
-} __attribute__ ((packed));
+} __packed;
#define HCI_EV_PKT_TYPE_CHANGE 0x1d
struct hci_ev_pkt_type_change {
__u8 status;
__le16 handle;
__le16 pkt_type;
-} __attribute__ ((packed));
+} __packed;
#define HCI_EV_PSCAN_REP_MODE 0x20
struct hci_ev_pscan_rep_mode {
bdaddr_t bdaddr;
__u8 pscan_rep_mode;
-} __attribute__ ((packed));
+} __packed;
#define HCI_EV_INQUIRY_RESULT_WITH_RSSI 0x22
struct inquiry_info_with_rssi {
@@ -761,7 +764,7 @@ struct inquiry_info_with_rssi {
__u8 dev_class[3];
__le16 clock_offset;
__s8 rssi;
-} __attribute__ ((packed));
+} __packed;
struct inquiry_info_with_rssi_and_pscan_mode {
bdaddr_t bdaddr;
__u8 pscan_rep_mode;
@@ -770,7 +773,7 @@ struct inquiry_info_with_rssi_and_pscan_mode {
__u8 dev_class[3];
__le16 clock_offset;
__s8 rssi;
-} __attribute__ ((packed));
+} __packed;
#define HCI_EV_REMOTE_EXT_FEATURES 0x23
struct hci_ev_remote_ext_features {
@@ -779,7 +782,7 @@ struct hci_ev_remote_ext_features {
__u8 page;
__u8 max_page;
__u8 features[8];
-} __attribute__ ((packed));
+} __packed;
#define HCI_EV_SYNC_CONN_COMPLETE 0x2c
struct hci_ev_sync_conn_complete {
@@ -792,7 +795,7 @@ struct hci_ev_sync_conn_complete {
__le16 rx_pkt_len;
__le16 tx_pkt_len;
__u8 air_mode;
-} __attribute__ ((packed));
+} __packed;
#define HCI_EV_SYNC_CONN_CHANGED 0x2d
struct hci_ev_sync_conn_changed {
@@ -802,7 +805,7 @@ struct hci_ev_sync_conn_changed {
__u8 retrans_window;
__le16 rx_pkt_len;
__le16 tx_pkt_len;
-} __attribute__ ((packed));
+} __packed;
#define HCI_EV_SNIFF_SUBRATE 0x2e
struct hci_ev_sniff_subrate {
@@ -812,7 +815,7 @@ struct hci_ev_sniff_subrate {
__le16 max_rx_latency;
__le16 max_remote_timeout;
__le16 max_local_timeout;
-} __attribute__ ((packed));
+} __packed;
#define HCI_EV_EXTENDED_INQUIRY_RESULT 0x2f
struct extended_inquiry_info {
@@ -823,37 +826,37 @@ struct extended_inquiry_info {
__le16 clock_offset;
__s8 rssi;
__u8 data[240];
-} __attribute__ ((packed));
+} __packed;
#define HCI_EV_IO_CAPA_REQUEST 0x31
struct hci_ev_io_capa_request {
bdaddr_t bdaddr;
-} __attribute__ ((packed));
+} __packed;
#define HCI_EV_SIMPLE_PAIR_COMPLETE 0x36
struct hci_ev_simple_pair_complete {
__u8 status;
bdaddr_t bdaddr;
-} __attribute__ ((packed));
+} __packed;
#define HCI_EV_REMOTE_HOST_FEATURES 0x3d
struct hci_ev_remote_host_features {
bdaddr_t bdaddr;
__u8 features[8];
-} __attribute__ ((packed));
+} __packed;
/* Internal events generated by Bluetooth stack */
#define HCI_EV_STACK_INTERNAL 0xfd
struct hci_ev_stack_internal {
__u16 type;
__u8 data[0];
-} __attribute__ ((packed));
+} __packed;
#define HCI_EV_SI_DEVICE 0x01
struct hci_ev_si_device {
__u16 event;
__u16 dev_id;
-} __attribute__ ((packed));
+} __packed;
#define HCI_EV_SI_SECURITY 0x02
struct hci_ev_si_security {
@@ -861,7 +864,7 @@ struct hci_ev_si_security {
__u16 proto;
__u16 subproto;
__u8 incoming;
-} __attribute__ ((packed));
+} __packed;
/* ---- HCI Packet structures ---- */
#define HCI_COMMAND_HDR_SIZE 3
@@ -872,22 +875,22 @@ struct hci_ev_si_security {
struct hci_command_hdr {
__le16 opcode; /* OCF & OGF */
__u8 plen;
-} __attribute__ ((packed));
+} __packed;
struct hci_event_hdr {
__u8 evt;
__u8 plen;
-} __attribute__ ((packed));
+} __packed;
struct hci_acl_hdr {
__le16 handle; /* Handle & Flags(PB, BC) */
__le16 dlen;
-} __attribute__ ((packed));
+} __packed;
struct hci_sco_hdr {
__le16 handle;
__u8 dlen;
-} __attribute__ ((packed));
+} __packed;
#ifdef __KERNEL__
#include <linux/skbuff.h>
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index e42f6ed5421..8b28962e737 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -1,6 +1,6 @@
-/*
+/*
BlueZ - Bluetooth protocol stack for Linux
- Copyright (C) 2000-2001 Qualcomm Incorporated
+ Copyright (c) 2000-2001, 2010, Code Aurora Forum. All rights reserved.
Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
@@ -12,13 +12,13 @@
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
- CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
- COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
+ ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
+ COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
SOFTWARE IS DISCLAIMED.
*/
@@ -62,6 +62,11 @@ struct hci_conn_hash {
unsigned int sco_num;
};
+struct bdaddr_list {
+ struct list_head list;
+ bdaddr_t bdaddr;
+};
+#define NUM_REASSEMBLY 4
struct hci_dev {
struct list_head list;
spinlock_t lock;
@@ -118,7 +123,7 @@ struct hci_dev {
struct sk_buff_head cmd_q;
struct sk_buff *sent_cmd;
- struct sk_buff *reassembly[3];
+ struct sk_buff *reassembly[NUM_REASSEMBLY];
struct mutex req_lock;
wait_queue_head_t req_wait_q;
@@ -127,6 +132,7 @@ struct hci_dev {
struct inquiry_cache inq_cache;
struct hci_conn_hash conn_hash;
+ struct bdaddr_list blacklist;
struct hci_dev_stats stat;
@@ -250,6 +256,7 @@ enum {
HCI_CONN_ENCRYPT_PEND,
HCI_CONN_RSWITCH_PEND,
HCI_CONN_MODE_CHANGE_PEND,
+ HCI_CONN_SCO_SETUP_PEND,
};
static inline void hci_conn_hash_init(struct hci_dev *hdev)
@@ -330,6 +337,7 @@ void hci_acl_connect(struct hci_conn *conn);
void hci_acl_disconn(struct hci_conn *conn, __u8 reason);
void hci_add_sco(struct hci_conn *conn, __u16 handle);
void hci_setup_sync(struct hci_conn *conn, __u16 handle);
+void hci_sco_setup(struct hci_conn *conn, __u8 status);
struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst);
int hci_conn_del(struct hci_conn *conn);
@@ -380,7 +388,7 @@ static inline void __hci_dev_put(struct hci_dev *d)
}
static inline void hci_dev_put(struct hci_dev *d)
-{
+{
__hci_dev_put(d);
module_put(d->owner);
}
@@ -424,10 +432,14 @@ int hci_get_conn_info(struct hci_dev *hdev, void __user *arg);
int hci_get_auth_info(struct hci_dev *hdev, void __user *arg);
int hci_inquiry(void __user *arg);
+struct bdaddr_list *hci_blacklist_lookup(struct hci_dev *hdev, bdaddr_t *bdaddr);
+int hci_blacklist_clear(struct hci_dev *hdev);
+
void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb);
int hci_recv_frame(struct sk_buff *skb);
int hci_recv_fragment(struct hci_dev *hdev, int type, void *data, int count);
+int hci_recv_stream_fragment(struct hci_dev *hdev, void *data, int count);
int hci_register_sysfs(struct hci_dev *hdev);
void hci_unregister_sysfs(struct hci_dev *hdev);
diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h
index 7c695bfd853..636724b203e 100644
--- a/include/net/bluetooth/l2cap.h
+++ b/include/net/bluetooth/l2cap.h
@@ -1,6 +1,8 @@
/*
BlueZ - Bluetooth protocol stack for Linux
Copyright (C) 2000-2001 Qualcomm Incorporated
+ Copyright (C) 2009-2010 Gustavo F. Padovan <gustavo@padovan.org>
+ Copyright (C) 2010 Google Inc.
Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
@@ -129,31 +131,31 @@ struct l2cap_conninfo {
struct l2cap_hdr {
__le16 len;
__le16 cid;
-} __attribute__ ((packed));
+} __packed;
#define L2CAP_HDR_SIZE 4
struct l2cap_cmd_hdr {
__u8 code;
__u8 ident;
__le16 len;
-} __attribute__ ((packed));
+} __packed;
#define L2CAP_CMD_HDR_SIZE 4
struct l2cap_cmd_rej {
__le16 reason;
-} __attribute__ ((packed));
+} __packed;
struct l2cap_conn_req {
__le16 psm;
__le16 scid;
-} __attribute__ ((packed));
+} __packed;
struct l2cap_conn_rsp {
__le16 dcid;
__le16 scid;
__le16 result;
__le16 status;
-} __attribute__ ((packed));
+} __packed;
/* channel indentifier */
#define L2CAP_CID_SIGNALING 0x0001
@@ -177,14 +179,14 @@ struct l2cap_conf_req {
__le16 dcid;
__le16 flags;
__u8 data[0];
-} __attribute__ ((packed));
+} __packed;
struct l2cap_conf_rsp {
__le16 scid;
__le16 flags;
__le16 result;
__u8 data[0];
-} __attribute__ ((packed));
+} __packed;
#define L2CAP_CONF_SUCCESS 0x0000
#define L2CAP_CONF_UNACCEPT 0x0001
@@ -195,7 +197,7 @@ struct l2cap_conf_opt {
__u8 type;
__u8 len;
__u8 val[0];
-} __attribute__ ((packed));
+} __packed;
#define L2CAP_CONF_OPT_SIZE 2
#define L2CAP_CONF_HINT 0x80
@@ -216,7 +218,7 @@ struct l2cap_conf_rfc {
__le16 retrans_timeout;
__le16 monitor_timeout;
__le16 max_pdu_size;
-} __attribute__ ((packed));
+} __packed;
#define L2CAP_MODE_BASIC 0x00
#define L2CAP_MODE_RETRANS 0x01
@@ -227,22 +229,22 @@ struct l2cap_conf_rfc {
struct l2cap_disconn_req {
__le16 dcid;
__le16 scid;
-} __attribute__ ((packed));
+} __packed;
struct l2cap_disconn_rsp {
__le16 dcid;
__le16 scid;
-} __attribute__ ((packed));
+} __packed;
struct l2cap_info_req {
__le16 type;
-} __attribute__ ((packed));
+} __packed;
struct l2cap_info_rsp {
__le16 type;
__le16 result;
__u8 data[0];
-} __attribute__ ((packed));
+} __packed;
/* info type */
#define L2CAP_IT_CL_MTU 0x0001
@@ -287,6 +289,11 @@ struct l2cap_conn {
struct l2cap_chan_list chan_list;
};
+struct sock_del_list {
+ struct sock *sk;
+ struct list_head list;
+};
+
#define L2CAP_INFO_CL_MTU_REQ_SENT 0x01
#define L2CAP_INFO_FEAT_MASK_REQ_SENT 0x04
#define L2CAP_INFO_FEAT_MASK_REQ_DONE 0x08
@@ -353,7 +360,6 @@ struct l2cap_pinfo {
__le16 sport;
- spinlock_t send_lock;
struct timer_list retrans_timer;
struct timer_list monitor_timer;
struct timer_list ack_timer;
diff --git a/include/net/bluetooth/rfcomm.h b/include/net/bluetooth/rfcomm.h
index 921d7b3c7f8..a140847d622 100644
--- a/include/net/bluetooth/rfcomm.h
+++ b/include/net/bluetooth/rfcomm.h
@@ -106,19 +106,19 @@ struct rfcomm_hdr {
u8 addr;
u8 ctrl;
u8 len; // Actual size can be 2 bytes
-} __attribute__ ((packed));
+} __packed;
struct rfcomm_cmd {
u8 addr;
u8 ctrl;
u8 len;
u8 fcs;
-} __attribute__ ((packed));
+} __packed;
struct rfcomm_mcc {
u8 type;
u8 len;
-} __attribute__ ((packed));
+} __packed;
struct rfcomm_pn {
u8 dlci;
@@ -128,7 +128,7 @@ struct rfcomm_pn {
__le16 mtu;
u8 max_retrans;
u8 credits;
-} __attribute__ ((packed));
+} __packed;
struct rfcomm_rpn {
u8 dlci;
@@ -138,17 +138,17 @@ struct rfcomm_rpn {
u8 xon_char;
u8 xoff_char;
__le16 param_mask;
-} __attribute__ ((packed));
+} __packed;
struct rfcomm_rls {
u8 dlci;
u8 status;
-} __attribute__ ((packed));
+} __packed;
struct rfcomm_msc {
u8 dlci;
u8 v24_sig;
-} __attribute__ ((packed));
+} __packed;
/* ---- Core structures, flags etc ---- */
diff --git a/include/net/caif/caif_dev.h b/include/net/caif/caif_dev.h
index 318ab9478a4..6da573c75d5 100644
--- a/include/net/caif/caif_dev.h
+++ b/include/net/caif/caif_dev.h
@@ -50,6 +50,9 @@ struct caif_connect_request {
* @client_layer: User implementation of client layer. This layer
* MUST have receive and control callback functions
* implemented.
+ * @ifindex: Link layer interface index used for this connection.
+ * @headroom: Head room needed by CAIF protocol.
+ * @tailroom: Tail room needed by CAIF protocol.
*
* This function connects a CAIF channel. The Client must implement
* the struct cflayer. This layer represents the Client layer and holds
@@ -59,8 +62,9 @@ struct caif_connect_request {
* E.g. CAIF Socket will call this function for each socket it connects
* and have one client_layer instance for each socket.
*/
-int caif_connect_client(struct caif_connect_request *config,
- struct cflayer *client_layer);
+int caif_connect_client(struct caif_connect_request *conn_req,
+ struct cflayer *client_layer, int *ifindex,
+ int *headroom, int *tailroom);
/**
* caif_disconnect_client - Disconnects a client from the CAIF stack.
diff --git a/include/net/caif/caif_layer.h b/include/net/caif/caif_layer.h
index 25c472f0e5b..c8b07a904e7 100644
--- a/include/net/caif/caif_layer.h
+++ b/include/net/caif/caif_layer.h
@@ -15,14 +15,8 @@ struct cfpktq;
struct caif_payload_info;
struct caif_packet_funcs;
-#define CAIF_MAX_FRAMESIZE 4096
-#define CAIF_MAX_PAYLOAD_SIZE (4096 - 64)
-#define CAIF_NEEDED_HEADROOM (10)
-#define CAIF_NEEDED_TAILROOM (2)
#define CAIF_LAYER_NAME_SZ 16
-#define CAIF_SUCCESS 1
-#define CAIF_FAILURE 0
/**
* caif_assert() - Assert function for CAIF.
diff --git a/include/net/caif/caif_spi.h b/include/net/caif/caif_spi.h
new file mode 100644
index 00000000000..ce4570dff02
--- /dev/null
+++ b/include/net/caif/caif_spi.h
@@ -0,0 +1,153 @@
+/*
+ * Copyright (C) ST-Ericsson AB 2010
+ * Author: Daniel Martensson / Daniel.Martensson@stericsson.com
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#ifndef CAIF_SPI_H_
+#define CAIF_SPI_H_
+
+#include <net/caif/caif_device.h>
+
+#define SPI_CMD_WR 0x00
+#define SPI_CMD_RD 0x01
+#define SPI_CMD_EOT 0x02
+#define SPI_CMD_IND 0x04
+
+#define SPI_DMA_BUF_LEN 8192
+
+#define WL_SZ 2 /* 16 bits. */
+#define SPI_CMD_SZ 4 /* 32 bits. */
+#define SPI_IND_SZ 4 /* 32 bits. */
+
+#define SPI_XFER 0
+#define SPI_SS_ON 1
+#define SPI_SS_OFF 2
+#define SPI_TERMINATE 3
+
+/* Minimum time between different levels is 50 microseconds. */
+#define MIN_TRANSITION_TIME_USEC 50
+
+/* Defines for calculating duration of SPI transfers for a particular
+ * number of bytes.
+ */
+#define SPI_MASTER_CLK_MHZ 13
+#define SPI_XFER_TIME_USEC(bytes, clk) (((bytes) * 8) / clk)
+
+/* Normally this should be aligned on the modem in order to benefit from full
+ * duplex transfers. However a size of 8188 provokes errors when running with
+ * the modem. These errors occur when packet sizes approaches 4 kB of data.
+ */
+#define CAIF_MAX_SPI_FRAME 4092
+
+/* Maximum number of uplink CAIF frames that can reside in the same SPI frame.
+ * This number should correspond with the modem setting. The application side
+ * CAIF accepts any number of embedded downlink CAIF frames.
+ */
+#define CAIF_MAX_SPI_PKTS 9
+
+/* Decides if SPI buffers should be prefilled with 0xFF pattern for easier
+ * debugging. Both TX and RX buffers will be filled before the transfer.
+ */
+#define CFSPI_DBG_PREFILL 0
+
+/* Structure describing a SPI transfer. */
+struct cfspi_xfer {
+ u16 tx_dma_len;
+ u16 rx_dma_len;
+ void *va_tx;
+ dma_addr_t pa_tx;
+ void *va_rx;
+ dma_addr_t pa_rx;
+};
+
+/* Structure implemented by the SPI interface. */
+struct cfspi_ifc {
+ void (*ss_cb) (bool assert, struct cfspi_ifc *ifc);
+ void (*xfer_done_cb) (struct cfspi_ifc *ifc);
+ void *priv;
+};
+
+/* Structure implemented by SPI clients. */
+struct cfspi_dev {
+ int (*init_xfer) (struct cfspi_xfer *xfer, struct cfspi_dev *dev);
+ void (*sig_xfer) (bool xfer, struct cfspi_dev *dev);
+ struct cfspi_ifc *ifc;
+ char *name;
+ u32 clk_mhz;
+ void *priv;
+};
+
+/* Enumeration describing the CAIF SPI state. */
+enum cfspi_state {
+ CFSPI_STATE_WAITING = 0,
+ CFSPI_STATE_AWAKE,
+ CFSPI_STATE_FETCH_PKT,
+ CFSPI_STATE_GET_NEXT,
+ CFSPI_STATE_INIT_XFER,
+ CFSPI_STATE_WAIT_ACTIVE,
+ CFSPI_STATE_SIG_ACTIVE,
+ CFSPI_STATE_WAIT_XFER_DONE,
+ CFSPI_STATE_XFER_DONE,
+ CFSPI_STATE_WAIT_INACTIVE,
+ CFSPI_STATE_SIG_INACTIVE,
+ CFSPI_STATE_DELIVER_PKT,
+ CFSPI_STATE_MAX,
+};
+
+/* Structure implemented by SPI physical interfaces. */
+struct cfspi {
+ struct caif_dev_common cfdev;
+ struct net_device *ndev;
+ struct platform_device *pdev;
+ struct sk_buff_head qhead;
+ struct sk_buff_head chead;
+ u16 cmd;
+ u16 tx_cpck_len;
+ u16 tx_npck_len;
+ u16 rx_cpck_len;
+ u16 rx_npck_len;
+ struct cfspi_ifc ifc;
+ struct cfspi_xfer xfer;
+ struct cfspi_dev *dev;
+ unsigned long state;
+ struct work_struct work;
+ struct workqueue_struct *wq;
+ struct list_head list;
+ int flow_off_sent;
+ u32 qd_low_mark;
+ u32 qd_high_mark;
+ struct completion comp;
+ wait_queue_head_t wait;
+ spinlock_t lock;
+ bool flow_stop;
+#ifdef CONFIG_DEBUG_FS
+ enum cfspi_state dbg_state;
+ u16 pcmd;
+ u16 tx_ppck_len;
+ u16 rx_ppck_len;
+ struct dentry *dbgfs_dir;
+ struct dentry *dbgfs_state;
+ struct dentry *dbgfs_frame;
+#endif /* CONFIG_DEBUG_FS */
+};
+
+extern int spi_frm_align;
+extern int spi_up_head_align;
+extern int spi_up_tail_align;
+extern int spi_down_head_align;
+extern int spi_down_tail_align;
+extern struct platform_driver cfspi_spi_driver;
+
+void cfspi_dbg_state(struct cfspi *cfspi, int state);
+int cfspi_xmitfrm(struct cfspi *cfspi, u8 *buf, size_t len);
+int cfspi_xmitlen(struct cfspi *cfspi);
+int cfspi_rxfrm(struct cfspi *cfspi, u8 *buf, size_t len);
+int cfspi_spi_remove(struct platform_device *pdev);
+int cfspi_spi_probe(struct platform_device *pdev);
+int cfspi_xmitfrm(struct cfspi *cfspi, u8 *buf, size_t len);
+int cfspi_xmitlen(struct cfspi *cfspi);
+int cfspi_rxfrm(struct cfspi *cfspi, u8 *buf, size_t len);
+void cfspi_xfer(struct work_struct *work);
+
+#endif /* CAIF_SPI_H_ */
diff --git a/include/net/caif/cfcnfg.h b/include/net/caif/cfcnfg.h
index 9fc2fc20b88..bd646faffa4 100644
--- a/include/net/caif/cfcnfg.h
+++ b/include/net/caif/cfcnfg.h
@@ -7,6 +7,7 @@
#ifndef CFCNFG_H_
#define CFCNFG_H_
#include <linux/spinlock.h>
+#include <linux/netdevice.h>
#include <net/caif/caif_layer.h>
#include <net/caif/cfctrl.h>
@@ -73,8 +74,8 @@ void cfcnfg_remove(struct cfcnfg *cfg);
void
cfcnfg_add_phy_layer(struct cfcnfg *cnfg, enum cfcnfg_phy_type phy_type,
- void *dev, struct cflayer *phy_layer, u16 *phyid,
- enum cfcnfg_phy_preference pref,
+ struct net_device *dev, struct cflayer *phy_layer,
+ u16 *phyid, enum cfcnfg_phy_preference pref,
bool fcs, bool stx);
/**
@@ -114,11 +115,18 @@ void cfcnfg_release_adap_layer(struct cflayer *adap_layer);
* @param: Link setup parameters.
* @adap_layer: Specify the adaptation layer; the receive and
* flow-control functions MUST be set in the structure.
- *
+ * @ifindex: Link layer interface index used for this connection.
+ * @proto_head: Protocol head-space needed by CAIF protocol,
+ * excluding link layer.
+ * @proto_tail: Protocol tail-space needed by CAIF protocol,
+ * excluding link layer.
*/
int cfcnfg_add_adaptation_layer(struct cfcnfg *cnfg,
struct cfctrl_link_param *param,
- struct cflayer *adap_layer);
+ struct cflayer *adap_layer,
+ int *ifindex,
+ int *proto_head,
+ int *proto_tail);
/**
* cfcnfg_get_phyid() - Get physical ID, given type.
diff --git a/include/net/caif/cfsrvl.h b/include/net/caif/cfsrvl.h
index 2dc9eb193ec..b1fa87ee099 100644
--- a/include/net/caif/cfsrvl.h
+++ b/include/net/caif/cfsrvl.h
@@ -16,6 +16,8 @@ struct cfsrvl {
bool open;
bool phy_flow_on;
bool modem_flow_on;
+ bool supports_flowctrl;
+ void (*release)(struct kref *);
struct dev_info dev_info;
struct kref ref;
};
@@ -25,13 +27,15 @@ struct cflayer *cfvei_create(u8 linkid, struct dev_info *dev_info);
struct cflayer *cfdgml_create(u8 linkid, struct dev_info *dev_info);
struct cflayer *cfutill_create(u8 linkid, struct dev_info *dev_info);
struct cflayer *cfvidl_create(u8 linkid, struct dev_info *dev_info);
-struct cflayer *cfrfml_create(u8 linkid, struct dev_info *dev_info);
+struct cflayer *cfrfml_create(u8 linkid, struct dev_info *dev_info,
+ int mtu_size);
struct cflayer *cfdbgl_create(u8 linkid, struct dev_info *dev_info);
bool cfsrvl_phyid_match(struct cflayer *layer, int phyid);
void cfservl_destroy(struct cflayer *layer);
void cfsrvl_init(struct cfsrvl *service,
- u8 channel_id,
- struct dev_info *dev_info);
+ u8 channel_id,
+ struct dev_info *dev_info,
+ bool supports_flowctrl);
bool cfsrvl_ready(struct cfsrvl *service, int *err);
u8 cfsrvl_getphyid(struct cflayer *layer);
@@ -50,7 +54,10 @@ static inline void cfsrvl_put(struct cflayer *layr)
if (layr == NULL)
return;
s = container_of(layr, struct cfsrvl, layer);
- kref_put(&s->ref, cfsrvl_release);
+
+ WARN_ON(!s->release);
+ if (s->release)
+ kref_put(&s->ref, s->release);
}
#endif /* CFSRVL_H_ */
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index b44a2e5321a..2fd06c60ffb 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -37,6 +37,7 @@
*
* @IEEE80211_BAND_2GHZ: 2.4GHz ISM band
* @IEEE80211_BAND_5GHZ: around 5GHz band (4.9-5.7)
+ * @IEEE80211_NUM_BANDS: number of defined bands
*/
enum ieee80211_band {
IEEE80211_BAND_2GHZ = NL80211_BAND_2GHZ,
@@ -89,7 +90,7 @@ enum ieee80211_channel_flags {
* @max_power: maximum transmission power (in dBm)
* @beacon_found: helper to regulatory code to indicate when a beacon
* has been found on this channel. Use regulatory_hint_found_beacon()
- * to enable this, this is is useful only on 5 GHz band.
+ * to enable this, this is useful only on 5 GHz band.
* @orig_mag: internal use
* @orig_mpwr: internal use
*/
@@ -188,6 +189,7 @@ struct ieee80211_sta_ht_cap {
* in this band. Must be sorted to give a valid "supported
* rates" IE, i.e. CCK rates first, then OFDM.
* @n_bitrates: Number of bitrates in @bitrates
+ * @ht_cap: HT capabilities in this band
*/
struct ieee80211_supported_band {
struct ieee80211_channel *channels;
@@ -225,6 +227,7 @@ struct vif_params {
* @seq: sequence counter (IV/PN) for TKIP and CCMP keys, only used
* with the get_key() callback, must be in little endian,
* length given by @seq_len.
+ * @seq_len: length of @seq.
*/
struct key_params {
u8 *key;
@@ -237,6 +240,8 @@ struct key_params {
/**
* enum survey_info_flags - survey information flags
*
+ * @SURVEY_INFO_NOISE_DBM: noise (in dBm) was filled in
+ *
* Used by the driver to indicate which info in &struct survey_info
* it has filled in during the get_survey().
*/
@@ -247,13 +252,13 @@ enum survey_info_flags {
/**
* struct survey_info - channel survey response
*
- * Used by dump_survey() to report back per-channel survey information.
- *
* @channel: the channel this survey record reports, mandatory
* @filled: bitflag of flags from &enum survey_info_flags
* @noise: channel noise in dBm. This and all following fields are
* optional
*
+ * Used by dump_survey() to report back per-channel survey information.
+ *
* This structure can later be expanded with things like
* channel duty cycle etc.
*/
@@ -288,7 +293,7 @@ struct beacon_parameters {
*
* @PLINK_ACTION_INVALID: action 0 is reserved
* @PLINK_ACTION_OPEN: start mesh peer link establishment
- * @PLINK_ACTION_BLOCL: block traffic from this mesh peer
+ * @PLINK_ACTION_BLOCK: block traffic from this mesh peer
*/
enum plink_actions {
PLINK_ACTION_INVALID,
@@ -311,6 +316,8 @@ enum plink_actions {
* (bitmask of BIT(NL80211_STA_FLAG_...))
* @listen_interval: listen interval or -1 for no change
* @aid: AID or zero for no change
+ * @plink_action: plink action to take
+ * @ht_capa: HT capabilities of station
*/
struct station_parameters {
u8 *supported_rates;
@@ -448,13 +455,13 @@ enum monitor_flags {
* Used by the driver to indicate which info in &struct mpath_info it has filled
* in during get_station() or dump_station().
*
- * MPATH_INFO_FRAME_QLEN: @frame_qlen filled
- * MPATH_INFO_SN: @sn filled
- * MPATH_INFO_METRIC: @metric filled
- * MPATH_INFO_EXPTIME: @exptime filled
- * MPATH_INFO_DISCOVERY_TIMEOUT: @discovery_timeout filled
- * MPATH_INFO_DISCOVERY_RETRIES: @discovery_retries filled
- * MPATH_INFO_FLAGS: @flags filled
+ * @MPATH_INFO_FRAME_QLEN: @frame_qlen filled
+ * @MPATH_INFO_SN: @sn filled
+ * @MPATH_INFO_METRIC: @metric filled
+ * @MPATH_INFO_EXPTIME: @exptime filled
+ * @MPATH_INFO_DISCOVERY_TIMEOUT: @discovery_timeout filled
+ * @MPATH_INFO_DISCOVERY_RETRIES: @discovery_retries filled
+ * @MPATH_INFO_FLAGS: @flags filled
*/
enum mpath_info_flags {
MPATH_INFO_FRAME_QLEN = BIT(0),
@@ -587,6 +594,7 @@ struct cfg80211_ssid {
* @ie_len: length of ie in octets
* @wiphy: the wiphy this was for
* @dev: the interface
+ * @aborted: (internal) scan request was notified as aborted
*/
struct cfg80211_scan_request {
struct cfg80211_ssid *ssids;
@@ -623,6 +631,7 @@ enum cfg80211_signal_type {
* This structure describes a BSS (which may also be a mesh network)
* for use in scan results and similar.
*
+ * @channel: channel this BSS is on
* @bssid: BSSID of the BSS
* @tsf: timestamp of last received update
* @beacon_interval: the beacon interval as from the frame
@@ -801,6 +810,7 @@ struct cfg80211_disassoc_request {
* @beacon_interval: beacon interval to use
* @privacy: this is a protected network, keys will be configured
* after joining
+ * @basic_rates: bitmap of basic rates to use when creating the IBSS
*/
struct cfg80211_ibss_params {
u8 *ssid;
@@ -809,6 +819,7 @@ struct cfg80211_ibss_params {
u8 *ie;
u8 ssid_len, ie_len;
u16 beacon_interval;
+ u32 basic_rates;
bool channel_fixed;
bool privacy;
};
@@ -826,8 +837,8 @@ struct cfg80211_ibss_params {
* @ssid: SSID
* @ssid_len: Length of ssid in octets
* @auth_type: Authentication type (algorithm)
- * @assoc_ie: IEs for association request
- * @assoc_ie_len: Length of assoc_ie in octets
+ * @ie: IEs for association request
+ * @ie_len: Length of assoc_ie in octets
* @privacy: indicates whether privacy-enabled APs should be used
* @crypto: crypto settings
* @key_len: length of WEP key for shared key authentication
@@ -850,10 +861,11 @@ struct cfg80211_connect_params {
/**
* enum wiphy_params_flags - set_wiphy_params bitfield values
- * WIPHY_PARAM_RETRY_SHORT: wiphy->retry_short has changed
- * WIPHY_PARAM_RETRY_LONG: wiphy->retry_long has changed
- * WIPHY_PARAM_FRAG_THRESHOLD: wiphy->frag_threshold has changed
- * WIPHY_PARAM_RTS_THRESHOLD: wiphy->rts_threshold has changed
+ * @WIPHY_PARAM_RETRY_SHORT: wiphy->retry_short has changed
+ * @WIPHY_PARAM_RETRY_LONG: wiphy->retry_long has changed
+ * @WIPHY_PARAM_FRAG_THRESHOLD: wiphy->frag_threshold has changed
+ * @WIPHY_PARAM_RTS_THRESHOLD: wiphy->rts_threshold has changed
+ * @WIPHY_PARAM_COVERAGE_CLASS: coverage class changed
*/
enum wiphy_params_flags {
WIPHY_PARAM_RETRY_SHORT = 1 << 0,
@@ -863,19 +875,6 @@ enum wiphy_params_flags {
WIPHY_PARAM_COVERAGE_CLASS = 1 << 4,
};
-/**
- * enum tx_power_setting - TX power adjustment
- *
- * @TX_POWER_AUTOMATIC: the dbm parameter is ignored
- * @TX_POWER_LIMITED: limit TX power by the dbm parameter
- * @TX_POWER_FIXED: fix TX power to the dbm parameter
- */
-enum tx_power_setting {
- TX_POWER_AUTOMATIC,
- TX_POWER_LIMITED,
- TX_POWER_FIXED,
-};
-
/*
* cfg80211_bitrate_mask - masks for bitrate control
*/
@@ -949,10 +948,16 @@ struct cfg80211_pmksa {
* @del_beacon: Remove beacon configuration and stop sending the beacon.
*
* @add_station: Add a new station.
- *
* @del_station: Remove a station; @mac may be NULL to remove all stations.
- *
* @change_station: Modify a given station.
+ * @get_station: get station information for the station identified by @mac
+ * @dump_station: dump station callback -- resume dump at index @idx
+ *
+ * @add_mpath: add a fixed mesh path
+ * @del_mpath: delete a given mesh path
+ * @change_mpath: change a given mesh path
+ * @get_mpath: get a mesh path for the given parameters
+ * @dump_mpath: dump mesh path callback -- resume dump at index @idx
*
* @get_mesh_params: Put the current mesh parameters into *params
*
@@ -960,8 +965,6 @@ struct cfg80211_pmksa {
* The mask is a bitfield which tells us which parameters to
* set, and which to leave alone.
*
- * @set_mesh_cfg: set mesh parameters (by now, just mesh id)
- *
* @change_bss: Modify parameters for a given BSS.
*
* @set_txq_params: Set TX queue parameters
@@ -1002,6 +1005,8 @@ struct cfg80211_pmksa {
* @get_tx_power: store the current TX power into the dbm variable;
* return 0 if successful
*
+ * @set_wds_peer: set the WDS peer for a WDS interface
+ *
* @rfkill_poll: polls the hw rfkill line, use cfg80211 reporting
* functions to adjust rfkill hw state
*
@@ -1019,6 +1024,8 @@ struct cfg80211_pmksa {
*
* @testmode_cmd: run a test mode command
*
+ * @set_bitrate_mask: set the bitrate mask configuration
+ *
* @set_pmksa: Cache a PMKID for a BSSID. This is mostly useful for fullmac
* devices running firmwares capable of generating the (re) association
* RSN IE. It allows for faster roaming between WPA2 BSSIDs.
@@ -1129,7 +1136,7 @@ struct cfg80211_ops {
int (*set_wiphy_params)(struct wiphy *wiphy, u32 changed);
int (*set_tx_power)(struct wiphy *wiphy,
- enum tx_power_setting type, int dbm);
+ enum nl80211_tx_power_setting type, int mbm);
int (*get_tx_power)(struct wiphy *wiphy, int *dbm);
int (*set_wds_peer)(struct wiphy *wiphy, struct net_device *dev,
@@ -1168,6 +1175,7 @@ struct cfg80211_ops {
int (*action)(struct wiphy *wiphy, struct net_device *dev,
struct ieee80211_channel *chan,
enum nl80211_channel_type channel_type,
+ bool channel_type_valid,
const u8 *buf, size_t len, u64 *cookie);
int (*set_power_mgmt)(struct wiphy *wiphy, struct net_device *dev,
@@ -1230,8 +1238,6 @@ struct mac_address {
/**
* struct wiphy - wireless hardware description
- * @idx: the wiphy index assigned to this item
- * @class_dev: the class device representing /sys/class/ieee80211/<wiphy-name>
* @reg_notifier: the driver's regulatory notification callback
* @regd: the driver's regulatory domain, if one was requested via
* the regulatory_hint() API. This can be used by the driver
@@ -1245,7 +1251,7 @@ struct mac_address {
* @frag_threshold: Fragmentation threshold (dot11FragmentationThreshold);
* -1 = fragmentation disabled, only odd values >= 256 used
* @rts_threshold: RTS threshold (dot11RTSThreshold); -1 = RTS/CTS disabled
- * @net: the network namespace this wiphy currently lives in
+ * @_net: the network namespace this wiphy currently lives in
* @perm_addr: permanent MAC address of this device
* @addr_mask: If the device supports multiple MAC addresses by masking,
* set this to a mask with variable bits set to 1, e.g. if the last
@@ -1258,6 +1264,28 @@ struct mac_address {
* by default for perm_addr. In this case, the mask should be set to
* all-zeroes. In this case it is assumed that the device can handle
* the same number of arbitrary MAC addresses.
+ * @debugfsdir: debugfs directory used for this wiphy, will be renamed
+ * automatically on wiphy renames
+ * @dev: (virtual) struct device for this wiphy
+ * @wext: wireless extension handlers
+ * @priv: driver private data (sized according to wiphy_new() parameter)
+ * @interface_modes: bitmask of interfaces types valid for this wiphy,
+ * must be set by driver
+ * @flags: wiphy flags, see &enum wiphy_flags
+ * @bss_priv_size: each BSS struct has private data allocated with it,
+ * this variable determines its size
+ * @max_scan_ssids: maximum number of SSIDs the device can scan for in
+ * any given scan
+ * @max_scan_ie_len: maximum length of user-controlled IEs device can
+ * add to probe request frames transmitted during a scan, must not
+ * include fixed IEs like supported rates
+ * @coverage_class: current coverage class
+ * @fw_version: firmware version for ethtool reporting
+ * @hw_version: hardware version for ethtool reporting
+ * @max_num_pmkids: maximum number of PMKIDs supported by device
+ * @privid: a pointer that drivers can use to identify if an arbitrary
+ * wiphy is theirs, e.g. in global notifiers
+ * @bands: information about bands/channels supported by this device
*/
struct wiphy {
/* assign these fields before you register the wiphy */
@@ -1330,27 +1358,16 @@ struct wiphy {
char priv[0] __attribute__((__aligned__(NETDEV_ALIGN)));
};
-#ifdef CONFIG_NET_NS
static inline struct net *wiphy_net(struct wiphy *wiphy)
{
- return wiphy->_net;
+ return read_pnet(&wiphy->_net);
}
static inline void wiphy_net_set(struct wiphy *wiphy, struct net *net)
{
- wiphy->_net = net;
-}
-#else
-static inline struct net *wiphy_net(struct wiphy *wiphy)
-{
- return &init_net;
+ write_pnet(&wiphy->_net, net);
}
-static inline void wiphy_net_set(struct wiphy *wiphy, struct net *net)
-{
-}
-#endif
-
/**
* wiphy_priv - return priv from wiphy
*
@@ -1399,7 +1416,7 @@ static inline struct device *wiphy_dev(struct wiphy *wiphy)
*
* @wiphy: The wiphy whose name to return
*/
-static inline const char *wiphy_name(struct wiphy *wiphy)
+static inline const char *wiphy_name(const struct wiphy *wiphy)
{
return dev_name(&wiphy->dev);
}
@@ -1471,13 +1488,14 @@ struct cfg80211_cached_keys;
* @ssid: (private) Used by the internal configuration code
* @ssid_len: (private) Used by the internal configuration code
* @wext: (private) Used by the internal wireless extensions compat code
- * @wext_bssid: (private) Used by the internal wireless extensions compat code
* @use_4addr: indicates 4addr mode is used on this interface, must be
* set by driver (if supported) on add_interface BEFORE registering the
* netdev and may otherwise be used by driver read-only, will be update
* by cfg80211 on change_interface
* @action_registrations: list of registrations for action frames
* @action_registrations_lock: lock for the list
+ * @mtx: mutex used to lock data in this struct
+ * @cleanup_work: work struct used for cleanup that can't be done directly
*/
struct wireless_dev {
struct wiphy *wiphy;
@@ -1551,11 +1569,13 @@ static inline void *wdev_priv(struct wireless_dev *wdev)
/**
* ieee80211_channel_to_frequency - convert channel number to frequency
+ * @chan: channel number
*/
extern int ieee80211_channel_to_frequency(int chan);
/**
* ieee80211_frequency_to_channel - convert frequency to channel number
+ * @freq: center frequency
*/
extern int ieee80211_frequency_to_channel(int freq);
@@ -1570,6 +1590,8 @@ extern struct ieee80211_channel *__ieee80211_get_channel(struct wiphy *wiphy,
int freq);
/**
* ieee80211_get_channel - get channel struct from wiphy for specified frequency
+ * @wiphy: the struct wiphy to get the channel for
+ * @freq: the center frequency of the channel
*/
static inline struct ieee80211_channel *
ieee80211_get_channel(struct wiphy *wiphy, int freq)
@@ -1630,9 +1652,6 @@ struct ieee80211_radiotap_vendor_namespaces {
* @is_radiotap_ns: indicates whether the current namespace is the default
* radiotap namespace or not
*
- * @overrides: override standard radiotap fields
- * @n_overrides: number of overrides
- *
* @_rtheader: pointer to the radiotap header we are walking through
* @_max_length: length of radiotap header in cpu byte ordering
* @_arg_index: next argument index
@@ -1933,6 +1952,10 @@ int cfg80211_wext_giwap(struct net_device *dev,
struct iw_request_info *info,
struct sockaddr *ap_addr, char *extra);
+int cfg80211_wext_siwpmksa(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *data, char *extra);
+
/*
* callbacks for asynchronous cfg80211 methods, notification
* functions and BSS handling helpers
@@ -1948,10 +1971,12 @@ int cfg80211_wext_giwap(struct net_device *dev,
void cfg80211_scan_done(struct cfg80211_scan_request *request, bool aborted);
/**
- * cfg80211_inform_bss - inform cfg80211 of a new BSS
+ * cfg80211_inform_bss_frame - inform cfg80211 of a received BSS frame
*
* @wiphy: the wiphy reporting the BSS
- * @bss: the found BSS
+ * @channel: The channel the frame was received on
+ * @mgmt: the management frame (probe response or beacon)
+ * @len: length of the management frame
* @signal: the signal strength, type depends on the wiphy's signal_type
* @gfp: context flags
*
@@ -1964,6 +1989,23 @@ cfg80211_inform_bss_frame(struct wiphy *wiphy,
struct ieee80211_mgmt *mgmt, size_t len,
s32 signal, gfp_t gfp);
+/**
+ * cfg80211_inform_bss - inform cfg80211 of a new BSS
+ *
+ * @wiphy: the wiphy reporting the BSS
+ * @channel: The channel the frame was received on
+ * @bssid: the BSSID of the BSS
+ * @timestamp: the TSF timestamp sent by the peer
+ * @capability: the capability field sent by the peer
+ * @beacon_interval: the beacon interval announced by the peer
+ * @ie: additional IEs sent by the peer
+ * @ielen: length of the additional IEs
+ * @signal: the signal strength, type depends on the wiphy's signal_type
+ * @gfp: context flags
+ *
+ * This informs cfg80211 that BSS information was found and
+ * the BSS should be updated/added.
+ */
struct cfg80211_bss*
cfg80211_inform_bss(struct wiphy *wiphy,
struct ieee80211_channel *channel,
@@ -2378,4 +2420,67 @@ void cfg80211_cqm_rssi_notify(struct net_device *dev,
enum nl80211_cqm_rssi_threshold_event rssi_event,
gfp_t gfp);
+#ifdef __KERNEL__
+
+/* Logging, debugging and troubleshooting/diagnostic helpers. */
+
+/* wiphy_printk helpers, similar to dev_printk */
+
+#define wiphy_printk(level, wiphy, format, args...) \
+ printk(level "%s: " format, wiphy_name(wiphy), ##args)
+#define wiphy_emerg(wiphy, format, args...) \
+ wiphy_printk(KERN_EMERG, wiphy, format, ##args)
+#define wiphy_alert(wiphy, format, args...) \
+ wiphy_printk(KERN_ALERT, wiphy, format, ##args)
+#define wiphy_crit(wiphy, format, args...) \
+ wiphy_printk(KERN_CRIT, wiphy, format, ##args)
+#define wiphy_err(wiphy, format, args...) \
+ wiphy_printk(KERN_ERR, wiphy, format, ##args)
+#define wiphy_warn(wiphy, format, args...) \
+ wiphy_printk(KERN_WARNING, wiphy, format, ##args)
+#define wiphy_notice(wiphy, format, args...) \
+ wiphy_printk(KERN_NOTICE, wiphy, format, ##args)
+#define wiphy_info(wiphy, format, args...) \
+ wiphy_printk(KERN_INFO, wiphy, format, ##args)
+
+int wiphy_debug(const struct wiphy *wiphy, const char *format, ...)
+ __attribute__ ((format (printf, 2, 3)));
+
+#if defined(DEBUG)
+#define wiphy_dbg(wiphy, format, args...) \
+ wiphy_printk(KERN_DEBUG, wiphy, format, ##args)
+#elif defined(CONFIG_DYNAMIC_DEBUG)
+#define wiphy_dbg(wiphy, format, args...) \
+ dynamic_pr_debug("%s: " format, wiphy_name(wiphy), ##args)
+#else
+#define wiphy_dbg(wiphy, format, args...) \
+({ \
+ if (0) \
+ wiphy_printk(KERN_DEBUG, wiphy, format, ##args); \
+ 0; \
+})
+#endif
+
+#if defined(VERBOSE_DEBUG)
+#define wiphy_vdbg wiphy_dbg
+#else
+
+#define wiphy_vdbg(wiphy, format, args...) \
+({ \
+ if (0) \
+ wiphy_printk(KERN_DEBUG, wiphy, format, ##args); \
+ 0; \
+})
+#endif
+
+/*
+ * wiphy_WARN() acts like wiphy_printk(), but with the key difference
+ * of using a WARN/WARN_ON to get the message out, including the
+ * file/line information and a backtrace.
+ */
+#define wiphy_WARN(wiphy, format, args...) \
+ WARN(1, "wiphy: %s\n" format, wiphy_name(wiphy), ##args);
+
+#endif
+
#endif /* __NET_CFG80211_H */
diff --git a/include/net/dn_dev.h b/include/net/dn_dev.h
index 511a459ec10..0916bbf3bdf 100644
--- a/include/net/dn_dev.h
+++ b/include/net/dn_dev.h
@@ -101,7 +101,7 @@ struct dn_short_packet {
__le16 dstnode;
__le16 srcnode;
__u8 forward;
-} __attribute__((packed));
+} __packed;
struct dn_long_packet {
__u8 msgflg;
@@ -115,7 +115,7 @@ struct dn_long_packet {
__u8 visit_ct;
__u8 s_class;
__u8 pt;
-} __attribute__((packed));
+} __packed;
/*------------------------- DRP - Routing messages ---------------------*/
@@ -132,7 +132,7 @@ struct endnode_hello_message {
__u8 mpd;
__u8 datalen;
__u8 data[2];
-} __attribute__((packed));
+} __packed;
struct rtnode_hello_message {
__u8 msgflg;
@@ -144,7 +144,7 @@ struct rtnode_hello_message {
__u8 area;
__le16 timer;
__u8 mpd;
-} __attribute__((packed));
+} __packed;
extern void dn_dev_init(void);
diff --git a/include/net/dn_nsp.h b/include/net/dn_nsp.h
index 17d43d2db5e..e43a2893f13 100644
--- a/include/net/dn_nsp.h
+++ b/include/net/dn_nsp.h
@@ -74,18 +74,18 @@ struct nsp_data_seg_msg {
__u8 msgflg;
__le16 dstaddr;
__le16 srcaddr;
-} __attribute__((packed));
+} __packed;
struct nsp_data_opt_msg {
__le16 acknum;
__le16 segnum;
__le16 lsflgs;
-} __attribute__((packed));
+} __packed;
struct nsp_data_opt_msg1 {
__le16 acknum;
__le16 segnum;
-} __attribute__((packed));
+} __packed;
/* Acknowledgment Message (data/other data) */
@@ -94,13 +94,13 @@ struct nsp_data_ack_msg {
__le16 dstaddr;
__le16 srcaddr;
__le16 acknum;
-} __attribute__((packed));
+} __packed;
/* Connect Acknowledgment Message */
struct nsp_conn_ack_msg {
__u8 msgflg;
__le16 dstaddr;
-} __attribute__((packed));
+} __packed;
/* Connect Initiate/Retransmit Initiate/Connect Confirm */
@@ -117,7 +117,7 @@ struct nsp_conn_init_msg {
#define NSP_FC_MASK 0x0c /* FC type mask */
__u8 info;
__le16 segsize;
-} __attribute__((packed));
+} __packed;
/* Disconnect Initiate/Disconnect Confirm */
struct nsp_disconn_init_msg {
@@ -125,7 +125,7 @@ struct nsp_disconn_init_msg {
__le16 dstaddr;
__le16 srcaddr;
__le16 reason;
-} __attribute__((packed));
+} __packed;
@@ -135,7 +135,7 @@ struct srcobj_fmt {
__le16 grpcode;
__le16 usrcode;
__u8 dlen;
-} __attribute__((packed));
+} __packed;
/*
* A collection of functions for manipulating the sequence
diff --git a/include/net/dn_route.h b/include/net/dn_route.h
index 60c9f22d869..ccadab3aa3f 100644
--- a/include/net/dn_route.h
+++ b/include/net/dn_route.h
@@ -65,9 +65,7 @@ extern void dn_rt_cache_flush(int delay);
* packets to the originating host.
*/
struct dn_route {
- union {
- struct dst_entry dst;
- } u;
+ struct dst_entry dst;
struct flowi fl;
diff --git a/include/net/genetlink.h b/include/net/genetlink.h
index eb551baafc0..f7dcd2c7041 100644
--- a/include/net/genetlink.h
+++ b/include/net/genetlink.h
@@ -68,26 +68,15 @@ struct genl_info {
#endif
};
-#ifdef CONFIG_NET_NS
static inline struct net *genl_info_net(struct genl_info *info)
{
- return info->_net;
+ return read_pnet(&info->_net);
}
static inline void genl_info_net_set(struct genl_info *info, struct net *net)
{
- info->_net = net;
+ write_pnet(&info->_net, net);
}
-#else
-static inline struct net *genl_info_net(struct genl_info *info)
-{
- return &init_net;
-}
-
-static inline void genl_info_net_set(struct genl_info *info, struct net *net)
-{
-}
-#endif
/**
* struct genl_ops - generic netlink operations
diff --git a/include/net/inet_common.h b/include/net/inet_common.h
index 18c773286b9..22fac9892b1 100644
--- a/include/net/inet_common.h
+++ b/include/net/inet_common.h
@@ -1,8 +1,8 @@
#ifndef _INET_COMMON_H
#define _INET_COMMON_H
-extern const struct proto_ops inet_stream_ops;
-extern const struct proto_ops inet_dgram_ops;
+extern const struct proto_ops inet_stream_ops;
+extern const struct proto_ops inet_dgram_ops;
/*
* INET4 prototypes used by INET6
@@ -13,37 +13,28 @@ struct sock;
struct sockaddr;
struct socket;
-extern int inet_release(struct socket *sock);
-extern int inet_stream_connect(struct socket *sock,
- struct sockaddr * uaddr,
- int addr_len, int flags);
-extern int inet_dgram_connect(struct socket *sock,
- struct sockaddr * uaddr,
- int addr_len, int flags);
-extern int inet_accept(struct socket *sock,
- struct socket *newsock, int flags);
-extern int inet_sendmsg(struct kiocb *iocb,
- struct socket *sock,
- struct msghdr *msg,
- size_t size);
-extern int inet_shutdown(struct socket *sock, int how);
-extern int inet_listen(struct socket *sock, int backlog);
-
-extern void inet_sock_destruct(struct sock *sk);
-
-extern int inet_bind(struct socket *sock,
- struct sockaddr *uaddr, int addr_len);
-extern int inet_getname(struct socket *sock,
- struct sockaddr *uaddr,
- int *uaddr_len, int peer);
-extern int inet_ioctl(struct socket *sock,
- unsigned int cmd, unsigned long arg);
-
-extern int inet_ctl_sock_create(struct sock **sk,
- unsigned short family,
- unsigned short type,
- unsigned char protocol,
- struct net *net);
+extern int inet_release(struct socket *sock);
+extern int inet_stream_connect(struct socket *sock, struct sockaddr * uaddr,
+ int addr_len, int flags);
+extern int inet_dgram_connect(struct socket *sock, struct sockaddr * uaddr,
+ int addr_len, int flags);
+extern int inet_accept(struct socket *sock, struct socket *newsock, int flags);
+extern int inet_sendmsg(struct kiocb *iocb, struct socket *sock,
+ struct msghdr *msg, size_t size);
+extern ssize_t inet_sendpage(struct socket *sock, struct page *page, int offset,
+ size_t size, int flags);
+extern int inet_recvmsg(struct kiocb *iocb, struct socket *sock,
+ struct msghdr *msg, size_t size, int flags);
+extern int inet_shutdown(struct socket *sock, int how);
+extern int inet_listen(struct socket *sock, int backlog);
+extern void inet_sock_destruct(struct sock *sk);
+extern int inet_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len);
+extern int inet_getname(struct socket *sock, struct sockaddr *uaddr,
+ int *uaddr_len, int peer);
+extern int inet_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg);
+extern int inet_ctl_sock_create(struct sock **sk, unsigned short family,
+ unsigned short type, unsigned char protocol,
+ struct net *net);
static inline void inet_ctl_sock_destroy(struct sock *sk)
{
@@ -51,5 +42,3 @@ static inline void inet_ctl_sock_destroy(struct sock *sk)
}
#endif
-
-
diff --git a/include/net/inet_frag.h b/include/net/inet_frag.h
index 39f2dc94390..16ff29a7bb3 100644
--- a/include/net/inet_frag.h
+++ b/include/net/inet_frag.h
@@ -20,6 +20,7 @@ struct inet_frag_queue {
atomic_t refcnt;
struct timer_list timer; /* when will this queue expire? */
struct sk_buff *fragments; /* list of received fragments */
+ struct sk_buff *fragments_tail;
ktime_t stamp;
int len; /* total length of orig datagram */
int meat;
diff --git a/include/net/inet_sock.h b/include/net/inet_sock.h
index 1653de515ce..1989cfd7405 100644
--- a/include/net/inet_sock.h
+++ b/include/net/inet_sock.h
@@ -137,7 +137,8 @@ struct inet_sock {
hdrincl:1,
mc_loop:1,
transparent:1,
- mc_all:1;
+ mc_all:1,
+ nodefrag:1;
int mc_index;
__be32 mc_addr;
struct ip_mc_socklist *mc_list;
diff --git a/include/net/inetpeer.h b/include/net/inetpeer.h
index 87b1df0d4d8..417d0c894f2 100644
--- a/include/net/inetpeer.h
+++ b/include/net/inetpeer.h
@@ -22,10 +22,21 @@ struct inet_peer {
__u32 dtime; /* the time of last use of not
* referenced entries */
atomic_t refcnt;
- atomic_t rid; /* Frag reception counter */
- atomic_t ip_id_count; /* IP ID for the next packet */
- __u32 tcp_ts;
- __u32 tcp_ts_stamp;
+ /*
+ * Once inet_peer is queued for deletion (refcnt == -1), following fields
+ * are not available: rid, ip_id_count, tcp_ts, tcp_ts_stamp
+ * We can share memory with rcu_head to keep inet_peer small
+ * (less then 64 bytes)
+ */
+ union {
+ struct {
+ atomic_t rid; /* Frag reception counter */
+ atomic_t ip_id_count; /* IP ID for the next packet */
+ __u32 tcp_ts;
+ __u32 tcp_ts_stamp;
+ };
+ struct rcu_head rcu;
+ };
};
void inet_initpeers(void) __init;
@@ -36,10 +47,21 @@ struct inet_peer *inet_getpeer(__be32 daddr, int create);
/* can be called from BH context or outside */
extern void inet_putpeer(struct inet_peer *p);
+/*
+ * temporary check to make sure we dont access rid, ip_id_count, tcp_ts,
+ * tcp_ts_stamp if no refcount is taken on inet_peer
+ */
+static inline void inet_peer_refcheck(const struct inet_peer *p)
+{
+ WARN_ON_ONCE(atomic_read(&p->refcnt) <= 0);
+}
+
+
/* can be called with or without local BH being disabled */
static inline __u16 inet_getid(struct inet_peer *p, int more)
{
more++;
+ inet_peer_refcheck(p);
return atomic_add_return(more, &p->ip_id_count) - more;
}
diff --git a/include/net/ip.h b/include/net/ip.h
index 452f229c380..890f9725d68 100644
--- a/include/net/ip.h
+++ b/include/net/ip.h
@@ -61,11 +61,14 @@ struct ipcm_cookie {
struct ip_ra_chain {
struct ip_ra_chain *next;
struct sock *sk;
- void (*destructor)(struct sock *);
+ union {
+ void (*destructor)(struct sock *);
+ struct sock *saved_sk;
+ };
+ struct rcu_head rcu;
};
extern struct ip_ra_chain *ip_ra_chain;
-extern rwlock_t ip_ra_lock;
/* IP flags. */
#define IP_CE 0x8000 /* Flag: "Congestion" */
@@ -162,12 +165,12 @@ struct ipv4_config {
};
extern struct ipv4_config ipv4_config;
-#define IP_INC_STATS(net, field) SNMP_INC_STATS((net)->mib.ip_statistics, field)
-#define IP_INC_STATS_BH(net, field) SNMP_INC_STATS_BH((net)->mib.ip_statistics, field)
-#define IP_ADD_STATS(net, field, val) SNMP_ADD_STATS((net)->mib.ip_statistics, field, val)
-#define IP_ADD_STATS_BH(net, field, val) SNMP_ADD_STATS_BH((net)->mib.ip_statistics, field, val)
-#define IP_UPD_PO_STATS(net, field, val) SNMP_UPD_PO_STATS((net)->mib.ip_statistics, field, val)
-#define IP_UPD_PO_STATS_BH(net, field, val) SNMP_UPD_PO_STATS_BH((net)->mib.ip_statistics, field, val)
+#define IP_INC_STATS(net, field) SNMP_INC_STATS64((net)->mib.ip_statistics, field)
+#define IP_INC_STATS_BH(net, field) SNMP_INC_STATS64_BH((net)->mib.ip_statistics, field)
+#define IP_ADD_STATS(net, field, val) SNMP_ADD_STATS64((net)->mib.ip_statistics, field, val)
+#define IP_ADD_STATS_BH(net, field, val) SNMP_ADD_STATS64_BH((net)->mib.ip_statistics, field, val)
+#define IP_UPD_PO_STATS(net, field, val) SNMP_UPD_PO_STATS64((net)->mib.ip_statistics, field, val)
+#define IP_UPD_PO_STATS_BH(net, field, val) SNMP_UPD_PO_STATS64_BH((net)->mib.ip_statistics, field, val)
#define NET_INC_STATS(net, field) SNMP_INC_STATS((net)->mib.net_statistics, field)
#define NET_INC_STATS_BH(net, field) SNMP_INC_STATS_BH((net)->mib.net_statistics, field)
#define NET_INC_STATS_USER(net, field) SNMP_INC_STATS_USER((net)->mib.net_statistics, field)
@@ -175,7 +178,15 @@ extern struct ipv4_config ipv4_config;
#define NET_ADD_STATS_USER(net, field, adnd) SNMP_ADD_STATS_USER((net)->mib.net_statistics, field, adnd)
extern unsigned long snmp_fold_field(void __percpu *mib[], int offt);
-extern int snmp_mib_init(void __percpu *ptr[2], size_t mibsize);
+#if BITS_PER_LONG==32
+extern u64 snmp_fold_field64(void __percpu *mib[], int offt, size_t sync_off);
+#else
+static inline u64 snmp_fold_field64(void __percpu *mib[], int offt, size_t syncp_off)
+{
+ return snmp_fold_field(mib, offt);
+}
+#endif
+extern int snmp_mib_init(void __percpu *ptr[2], size_t mibsize, size_t align);
extern void snmp_mib_free(void __percpu *ptr[2]);
extern struct local_ports {
diff --git a/include/net/ip6_fib.h b/include/net/ip6_fib.h
index 4b1dc1161c3..062a823d311 100644
--- a/include/net/ip6_fib.h
+++ b/include/net/ip6_fib.h
@@ -84,13 +84,11 @@ struct rt6key {
struct fib6_table;
struct rt6_info {
- union {
- struct dst_entry dst;
- } u;
+ struct dst_entry dst;
-#define rt6i_dev u.dst.dev
-#define rt6i_nexthop u.dst.neighbour
-#define rt6i_expires u.dst.expires
+#define rt6i_dev dst.dev
+#define rt6i_nexthop dst.neighbour
+#define rt6i_expires dst.expires
/*
* Tail elements of dst_entry (__refcnt etc.)
diff --git a/include/net/ip6_tunnel.h b/include/net/ip6_tunnel.h
index fbf9d1cda27..fc94ec568a5 100644
--- a/include/net/ip6_tunnel.h
+++ b/include/net/ip6_tunnel.h
@@ -27,6 +27,6 @@ struct ipv6_tlv_tnl_enc_lim {
__u8 type; /* type-code for option */
__u8 length; /* option length */
__u8 encap_limit; /* tunnel encapsulation limit */
-} __attribute__ ((packed));
+} __packed;
#endif
diff --git a/include/net/ip_vs.h b/include/net/ip_vs.h
index fe82b1e10a2..a4747a0f730 100644
--- a/include/net/ip_vs.h
+++ b/include/net/ip_vs.h
@@ -632,10 +632,22 @@ extern struct ip_vs_conn *ip_vs_ct_in_get
(int af, int protocol, const union nf_inet_addr *s_addr, __be16 s_port,
const union nf_inet_addr *d_addr, __be16 d_port);
+struct ip_vs_conn * ip_vs_conn_in_get_proto(int af, const struct sk_buff *skb,
+ struct ip_vs_protocol *pp,
+ const struct ip_vs_iphdr *iph,
+ unsigned int proto_off,
+ int inverse);
+
extern struct ip_vs_conn *ip_vs_conn_out_get
(int af, int protocol, const union nf_inet_addr *s_addr, __be16 s_port,
const union nf_inet_addr *d_addr, __be16 d_port);
+struct ip_vs_conn * ip_vs_conn_out_get_proto(int af, const struct sk_buff *skb,
+ struct ip_vs_protocol *pp,
+ const struct ip_vs_iphdr *iph,
+ unsigned int proto_off,
+ int inverse);
+
/* put back the conn without restarting its timer */
static inline void __ip_vs_conn_put(struct ip_vs_conn *cp)
{
@@ -736,8 +748,6 @@ extern void ip_vs_app_inc_put(struct ip_vs_app *inc);
extern int ip_vs_app_pkt_out(struct ip_vs_conn *, struct sk_buff *skb);
extern int ip_vs_app_pkt_in(struct ip_vs_conn *, struct sk_buff *skb);
-extern int ip_vs_skb_replace(struct sk_buff *skb, gfp_t pri,
- char *o_buf, int o_len, char *n_buf, int n_len);
extern int ip_vs_app_init(void);
extern void ip_vs_app_cleanup(void);
diff --git a/include/net/ipip.h b/include/net/ipip.h
index 11e8513d2d0..65caea8b414 100644
--- a/include/net/ipip.h
+++ b/include/net/ipip.h
@@ -50,7 +50,7 @@ struct ip_tunnel_prl_entry {
int pkt_len = skb->len - skb_transport_offset(skb); \
\
skb->ip_summed = CHECKSUM_NONE; \
- ip_select_ident(iph, &rt->u.dst, NULL); \
+ ip_select_ident(iph, &rt->dst, NULL); \
\
err = ip_local_out(skb); \
if (likely(net_xmit_eval(err) == 0)) { \
diff --git a/include/net/ipv6.h b/include/net/ipv6.h
index 2600b69757b..1f841241099 100644
--- a/include/net/ipv6.h
+++ b/include/net/ipv6.h
@@ -136,17 +136,17 @@ extern struct ctl_path net_ipv6_ctl_path[];
/* MIBs */
#define IP6_INC_STATS(net, idev,field) \
- _DEVINC(net, ipv6, , idev, field)
+ _DEVINC(net, ipv6, 64, idev, field)
#define IP6_INC_STATS_BH(net, idev,field) \
- _DEVINC(net, ipv6, _BH, idev, field)
+ _DEVINC(net, ipv6, 64_BH, idev, field)
#define IP6_ADD_STATS(net, idev,field,val) \
- _DEVADD(net, ipv6, , idev, field, val)
+ _DEVADD(net, ipv6, 64, idev, field, val)
#define IP6_ADD_STATS_BH(net, idev,field,val) \
- _DEVADD(net, ipv6, _BH, idev, field, val)
+ _DEVADD(net, ipv6, 64_BH, idev, field, val)
#define IP6_UPD_PO_STATS(net, idev,field,val) \
- _DEVUPD(net, ipv6, , idev, field, val)
+ _DEVUPD(net, ipv6, 64, idev, field, val)
#define IP6_UPD_PO_STATS_BH(net, idev,field,val) \
- _DEVUPD(net, ipv6, _BH, idev, field, val)
+ _DEVUPD(net, ipv6, 64_BH, idev, field, val)
#define ICMP6_INC_STATS(net, idev, field) \
_DEVINC(net, icmpv6, , idev, field)
#define ICMP6_INC_STATS_BH(net, idev, field) \
@@ -551,6 +551,10 @@ extern int ipv6_ext_hdr(u8 nexthdr);
extern int ipv6_find_tlv(struct sk_buff *skb, int offset, int type);
+extern struct in6_addr *fl6_update_dst(struct flowi *fl,
+ const struct ipv6_txoptions *opt,
+ struct in6_addr *orig);
+
/*
* socket options (ipv6_sockglue.c)
*/
diff --git a/include/net/ipx.h b/include/net/ipx.h
index ef51a668ba1..05d7e4a88b4 100644
--- a/include/net/ipx.h
+++ b/include/net/ipx.h
@@ -27,9 +27,9 @@ struct ipx_address {
#define IPX_MAX_PPROP_HOPS 8
struct ipxhdr {
- __be16 ipx_checksum __attribute__ ((packed));
+ __be16 ipx_checksum __packed;
#define IPX_NO_CHECKSUM cpu_to_be16(0xFFFF)
- __be16 ipx_pktsize __attribute__ ((packed));
+ __be16 ipx_pktsize __packed;
__u8 ipx_tctrl;
__u8 ipx_type;
#define IPX_TYPE_UNKNOWN 0x00
@@ -38,8 +38,8 @@ struct ipxhdr {
#define IPX_TYPE_SPX 0x05 /* SPX protocol */
#define IPX_TYPE_NCP 0x11 /* $lots for docs on this (SPIT) */
#define IPX_TYPE_PPROP 0x14 /* complicated flood fill brdcast */
- struct ipx_address ipx_dest __attribute__ ((packed));
- struct ipx_address ipx_source __attribute__ ((packed));
+ struct ipx_address ipx_dest __packed;
+ struct ipx_address ipx_source __packed;
};
static __inline__ struct ipxhdr *ipx_hdr(struct sk_buff *skb)
diff --git a/include/net/irda/irda.h b/include/net/irda/irda.h
index 7e582061b23..3bed61d379a 100644
--- a/include/net/irda/irda.h
+++ b/include/net/irda/irda.h
@@ -53,10 +53,6 @@ typedef __u32 magic_t;
#ifndef IRDA_ALIGN
# define IRDA_ALIGN __attribute__((aligned))
#endif
-#ifndef IRDA_PACK
-# define IRDA_PACK __attribute__((packed))
-#endif
-
#ifdef CONFIG_IRDA_DEBUG
diff --git a/include/net/irda/irlap_frame.h b/include/net/irda/irlap_frame.h
index 641f88e848b..6b1dc4f8eca 100644
--- a/include/net/irda/irlap_frame.h
+++ b/include/net/irda/irlap_frame.h
@@ -85,7 +85,7 @@ struct discovery_t;
struct disc_frame {
__u8 caddr; /* Connection address */
__u8 control;
-} IRDA_PACK;
+} __packed;
struct xid_frame {
__u8 caddr; /* Connection address */
@@ -96,41 +96,41 @@ struct xid_frame {
__u8 flags; /* Discovery flags */
__u8 slotnr;
__u8 version;
-} IRDA_PACK;
+} __packed;
struct test_frame {
__u8 caddr; /* Connection address */
__u8 control;
__le32 saddr; /* Source device address */
__le32 daddr; /* Destination device address */
-} IRDA_PACK;
+} __packed;
struct ua_frame {
__u8 caddr;
__u8 control;
__le32 saddr; /* Source device address */
__le32 daddr; /* Dest device address */
-} IRDA_PACK;
+} __packed;
struct dm_frame {
__u8 caddr; /* Connection address */
__u8 control;
-} IRDA_PACK;
+} __packed;
struct rd_frame {
__u8 caddr; /* Connection address */
__u8 control;
-} IRDA_PACK;
+} __packed;
struct rr_frame {
__u8 caddr; /* Connection address */
__u8 control;
-} IRDA_PACK;
+} __packed;
struct i_frame {
__u8 caddr;
__u8 control;
-} IRDA_PACK;
+} __packed;
struct snrm_frame {
__u8 caddr;
@@ -138,7 +138,7 @@ struct snrm_frame {
__le32 saddr;
__le32 daddr;
__u8 ncaddr;
-} IRDA_PACK;
+} __packed;
void irlap_queue_xmit(struct irlap_cb *self, struct sk_buff *skb);
void irlap_send_discovery_xid_frame(struct irlap_cb *, int S, __u8 s,
diff --git a/include/net/lib80211.h b/include/net/lib80211.h
index fb4e2784857..848cce1bb7a 100644
--- a/include/net/lib80211.h
+++ b/include/net/lib80211.h
@@ -54,9 +54,6 @@ struct lib80211_crypto_ops {
/* deinitialize crypto context and free allocated private data */
void (*deinit) (void *priv);
- int (*build_iv) (struct sk_buff * skb, int hdr_len,
- u8 *key, int keylen, void *priv);
-
/* encrypt/decrypt return < 0 on error or >= 0 on success. The return
* value from decrypt_mpdu is passed as the keyidx value for
* decrypt_msdu. skb must have enough head and tail room for the
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index de22cbfef23..b0787a1dea9 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -146,6 +146,9 @@ struct ieee80211_low_level_stats {
* enabled/disabled (beaconing modes)
* @BSS_CHANGED_CQM: Connection quality monitor config changed
* @BSS_CHANGED_IBSS: IBSS join status changed
+ * @BSS_CHANGED_ARP_FILTER: Hardware ARP filter address list or state changed.
+ * @BSS_CHANGED_QOS: QoS for this association was enabled/disabled. Note
+ * that it is only ever disabled for station mode.
*/
enum ieee80211_bss_change {
BSS_CHANGED_ASSOC = 1<<0,
@@ -160,10 +163,19 @@ enum ieee80211_bss_change {
BSS_CHANGED_BEACON_ENABLED = 1<<9,
BSS_CHANGED_CQM = 1<<10,
BSS_CHANGED_IBSS = 1<<11,
+ BSS_CHANGED_ARP_FILTER = 1<<12,
+ BSS_CHANGED_QOS = 1<<13,
/* when adding here, make sure to change ieee80211_reconfig */
};
+/*
+ * The maximum number of IPv4 addresses listed for ARP filtering. If the number
+ * of addresses for an interface increase beyond this value, hardware ARP
+ * filtering will be disabled.
+ */
+#define IEEE80211_BSS_ARP_ADDR_LIST_LEN 4
+
/**
* struct ieee80211_bss_conf - holds the BSS's changing parameters
*
@@ -182,7 +194,9 @@ enum ieee80211_bss_change {
* if the hardware cannot handle this it must set the
* IEEE80211_HW_2GHZ_SHORT_SLOT_INCAPABLE hardware flag
* @dtim_period: num of beacons before the next DTIM, for beaconing,
- * not valid in station mode (cf. hw conf ps_dtim_period)
+ * valid in station mode only while @assoc is true and if also
+ * requested by %IEEE80211_HW_NEED_DTIM_PERIOD (cf. also hw conf
+ * @ps_dtim_period)
* @timestamp: beacon timestamp
* @beacon_int: beacon interval
* @assoc_capability: capabilities taken from assoc resp
@@ -199,6 +213,16 @@ enum ieee80211_bss_change {
* @cqm_rssi_thold: Connection quality monitor RSSI threshold, a zero value
* implies disabled
* @cqm_rssi_hyst: Connection quality monitor RSSI hysteresis
+ * @arp_addr_list: List of IPv4 addresses for hardware ARP filtering. The
+ * may filter ARP queries targeted for other addresses than listed here.
+ * The driver must allow ARP queries targeted for all address listed here
+ * to pass through. An empty list implies no ARP queries need to pass.
+ * @arp_addr_cnt: Number of addresses currently on the list.
+ * @arp_filter_enabled: Enable ARP filtering - if enabled, the hardware may
+ * filter ARP queries based on the @arp_addr_list, if disabled, the
+ * hardware must not perform any ARP filtering. Note, that the filter will
+ * be enabled also in promiscuous mode.
+ * @qos: This is a QoS-enabled BSS.
*/
struct ieee80211_bss_conf {
const u8 *bssid;
@@ -219,6 +243,10 @@ struct ieee80211_bss_conf {
s32 cqm_rssi_thold;
u32 cqm_rssi_hyst;
enum nl80211_channel_type channel_type;
+ __be32 arp_addr_list[IEEE80211_BSS_ARP_ADDR_LIST_LEN];
+ u8 arp_addr_cnt;
+ bool arp_filter_enabled;
+ bool qos;
};
/**
@@ -312,9 +340,10 @@ enum mac80211_tx_control_flags {
IEEE80211_TX_INTFL_NL80211_FRAME_TX = BIT(21),
IEEE80211_TX_CTL_LDPC = BIT(22),
IEEE80211_TX_CTL_STBC = BIT(23) | BIT(24),
-#define IEEE80211_TX_CTL_STBC_SHIFT 23
};
+#define IEEE80211_TX_CTL_STBC_SHIFT 23
+
/**
* enum mac80211_rate_control_flags - per-rate flags set by the
* Rate Control algorithm.
@@ -390,7 +419,7 @@ struct ieee80211_tx_rate {
s8 idx;
u8 count;
u8 flags;
-} __attribute__((packed));
+} __packed;
/**
* struct ieee80211_tx_info - skb transmit information
@@ -412,8 +441,6 @@ struct ieee80211_tx_rate {
* @driver_data: array of driver_data pointers
* @ampdu_ack_len: number of acked aggregated frames.
* relevant only if IEEE80211_TX_STAT_AMPDU was set.
- * @ampdu_ack_map: block ack bit map for the aggregation.
- * relevant only if IEEE80211_TX_STAT_AMPDU was set.
* @ampdu_len: number of aggregated frames.
* relevant only if IEEE80211_TX_STAT_AMPDU was set.
* @ack_signal: signal strength of the ACK frame
@@ -448,10 +475,9 @@ struct ieee80211_tx_info {
struct {
struct ieee80211_tx_rate rates[IEEE80211_TX_MAX_RATES];
u8 ampdu_ack_len;
- u64 ampdu_ack_map;
int ack_signal;
u8 ampdu_len;
- /* 7 bytes free */
+ /* 15 bytes free */
} status;
struct {
struct ieee80211_tx_rate driver_rates[
@@ -601,15 +627,14 @@ struct ieee80211_rx_status {
* may turn the device off as much as possible. Typically, this flag will
* be set when an interface is set UP but not associated or scanning, but
* it can also be unset in that case when monitor interfaces are active.
- * @IEEE80211_CONF_QOS: Enable 802.11e QoS also know as WMM (Wireless
- * Multimedia). On some drivers (iwlwifi is one of know) we have
- * to enable/disable QoS explicitly.
+ * @IEEE80211_CONF_OFFCHANNEL: The device is currently not on its main
+ * operating channel.
*/
enum ieee80211_conf_flags {
IEEE80211_CONF_MONITOR = (1<<0),
IEEE80211_CONF_PS = (1<<1),
IEEE80211_CONF_IDLE = (1<<2),
- IEEE80211_CONF_QOS = (1<<3),
+ IEEE80211_CONF_OFFCHANNEL = (1<<3),
};
@@ -624,7 +649,6 @@ enum ieee80211_conf_flags {
* @IEEE80211_CONF_CHANGE_RETRY_LIMITS: retry limits changed
* @IEEE80211_CONF_CHANGE_IDLE: Idle flag changed
* @IEEE80211_CONF_CHANGE_SMPS: Spatial multiplexing powersave mode changed
- * @IEEE80211_CONF_CHANGE_QOS: Quality of service was enabled or disabled
*/
enum ieee80211_conf_changed {
IEEE80211_CONF_CHANGE_SMPS = BIT(1),
@@ -635,7 +659,6 @@ enum ieee80211_conf_changed {
IEEE80211_CONF_CHANGE_CHANNEL = BIT(6),
IEEE80211_CONF_CHANGE_RETRY_LIMITS = BIT(7),
IEEE80211_CONF_CHANGE_IDLE = BIT(8),
- IEEE80211_CONF_CHANGE_QOS = BIT(9),
};
/**
@@ -676,9 +699,6 @@ enum ieee80211_smps_mode {
* @dynamic_ps_timeout: The dynamic powersave timeout (in ms), see the
* powersave documentation below. This variable is valid only when
* the CONF_PS flag is set.
- * @dynamic_ps_forced_timeout: The dynamic powersave timeout (in ms) configured
- * by cfg80211 (essentially, wext) If set, this value overrules the value
- * chosen by mac80211 based on ps qos network latency.
*
* @power_level: requested transmit power (in dBm)
*
@@ -698,7 +718,7 @@ enum ieee80211_smps_mode {
*/
struct ieee80211_conf {
u32 flags;
- int power_level, dynamic_ps_timeout, dynamic_ps_forced_timeout;
+ int power_level, dynamic_ps_timeout;
int max_sleep_period;
u16 listen_interval;
@@ -815,7 +835,6 @@ enum ieee80211_key_flags {
* encrypted in hardware.
* @alg: The key algorithm.
* @flags: key flags, see &enum ieee80211_key_flags.
- * @ap_addr: AP's MAC address
* @keyidx: the key index (0-3)
* @keylen: key material length
* @key: key material. For ALG_TKIP the key is encoded as a 256-bit (32 byte)
@@ -881,16 +900,12 @@ struct ieee80211_sta {
* enum sta_notify_cmd - sta notify command
*
* Used with the sta_notify() callback in &struct ieee80211_ops, this
- * indicates addition and removal of a station to station table,
- * or if a associated station made a power state transition.
+ * indicates if an associated station made a power state transition.
*
- * @STA_NOTIFY_ADD: (DEPRECATED) a station was added to the station table
- * @STA_NOTIFY_REMOVE: (DEPRECATED) a station being removed from the station table
* @STA_NOTIFY_SLEEP: a station is now sleeping
* @STA_NOTIFY_AWAKE: a sleeping station woke up
*/
enum sta_notify_cmd {
- STA_NOTIFY_ADD, STA_NOTIFY_REMOVE,
STA_NOTIFY_SLEEP, STA_NOTIFY_AWAKE,
};
@@ -1014,6 +1029,9 @@ enum ieee80211_tkip_key_type {
* connection quality related parameters, such as the RSSI level and
* provide notifications if configured trigger levels are reached.
*
+ * @IEEE80211_HW_NEED_DTIM_PERIOD:
+ * This device needs to know the DTIM period for the BSS before
+ * associating.
*/
enum ieee80211_hw_flags {
IEEE80211_HW_HAS_RATE_CONTROL = 1<<0,
@@ -1023,7 +1041,7 @@ enum ieee80211_hw_flags {
IEEE80211_HW_2GHZ_SHORT_PREAMBLE_INCAPABLE = 1<<4,
IEEE80211_HW_SIGNAL_UNSPEC = 1<<5,
IEEE80211_HW_SIGNAL_DBM = 1<<6,
- /* use this hole */
+ IEEE80211_HW_NEED_DTIM_PERIOD = 1<<7,
IEEE80211_HW_SPECTRUM_MGMT = 1<<8,
IEEE80211_HW_AMPDU_AGGREGATION = 1<<9,
IEEE80211_HW_SUPPORTS_PS = 1<<10,
@@ -1260,6 +1278,15 @@ ieee80211_get_alt_retry_rate(const struct ieee80211_hw *hw,
* dynamic PS feature in stack and will just keep %IEEE80211_CONF_PS
* enabled whenever user has enabled powersave.
*
+ * Some hardware need to toggle a single shared antenna between WLAN and
+ * Bluetooth to facilitate co-existence. These types of hardware set
+ * limitations on the use of host controlled dynamic powersave whenever there
+ * is simultaneous WLAN and Bluetooth traffic. For these types of hardware, the
+ * driver may request temporarily going into full power save, in order to
+ * enable toggling the antenna between BT and WLAN. If the driver requests
+ * disabling dynamic powersave, the @dynamic_ps_timeout value will be
+ * temporarily set to zero until the driver re-enables dynamic powersave.
+ *
* Driver informs U-APSD client support by enabling
* %IEEE80211_HW_SUPPORTS_UAPSD flag. The mode is configured through the
* uapsd paramater in conf_tx() operation. Hardware needs to send the QoS
@@ -1451,7 +1478,7 @@ enum ieee80211_filter_flags {
*
* Note that drivers MUST be able to deal with a TX aggregation
* session being stopped even before they OK'ed starting it by
- * calling ieee80211_start_tx_ba_cb(_irqsafe), because the peer
+ * calling ieee80211_start_tx_ba_cb_irqsafe, because the peer
* might receive the addBA frame and send a delBA right away!
*
* @IEEE80211_AMPDU_RX_START: start Rx aggregation
@@ -1636,7 +1663,7 @@ enum ieee80211_ampdu_mlme_action {
* is the first frame we expect to perform the action on. Notice
* that TX/RX_STOP can pass NULL for this parameter.
* Returns a negative error code on failure.
- * The callback must be atomic.
+ * The callback can sleep.
*
* @get_survey: Return per-channel survey information
*
@@ -2307,25 +2334,14 @@ void ieee80211_queue_delayed_work(struct ieee80211_hw *hw,
int ieee80211_start_tx_ba_session(struct ieee80211_sta *sta, u16 tid);
/**
- * ieee80211_start_tx_ba_cb - low level driver ready to aggregate.
- * @vif: &struct ieee80211_vif pointer from the add_interface callback
- * @ra: receiver address of the BA session recipient.
- * @tid: the TID to BA on.
- *
- * This function must be called by low level driver once it has
- * finished with preparations for the BA session.
- */
-void ieee80211_start_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u16 tid);
-
-/**
* ieee80211_start_tx_ba_cb_irqsafe - low level driver ready to aggregate.
* @vif: &struct ieee80211_vif pointer from the add_interface callback
* @ra: receiver address of the BA session recipient.
* @tid: the TID to BA on.
*
* This function must be called by low level driver once it has
- * finished with preparations for the BA session.
- * This version of the function is IRQ-safe.
+ * finished with preparations for the BA session. It can be called
+ * from any context.
*/
void ieee80211_start_tx_ba_cb_irqsafe(struct ieee80211_vif *vif, const u8 *ra,
u16 tid);
@@ -2334,27 +2350,14 @@ void ieee80211_start_tx_ba_cb_irqsafe(struct ieee80211_vif *vif, const u8 *ra,
* ieee80211_stop_tx_ba_session - Stop a Block Ack session.
* @sta: the station whose BA session to stop
* @tid: the TID to stop BA.
- * @initiator: if indicates initiator DELBA frame will be sent.
*
- * Return: error if no sta with matching da found, success otherwise
+ * Return: negative error if the TID is invalid, or no aggregation active
*
* Although mac80211/low level driver/user space application can estimate
* the need to stop aggregation on a certain RA/TID, the session level
* will be managed by the mac80211.
*/
-int ieee80211_stop_tx_ba_session(struct ieee80211_sta *sta, u16 tid,
- enum ieee80211_back_parties initiator);
-
-/**
- * ieee80211_stop_tx_ba_cb - low level driver ready to stop aggregate.
- * @vif: &struct ieee80211_vif pointer from the add_interface callback
- * @ra: receiver address of the BA session recipient.
- * @tid: the desired TID to BA on.
- *
- * This function must be called by low level driver once it has
- * finished with preparations for the BA session tear down.
- */
-void ieee80211_stop_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u8 tid);
+int ieee80211_stop_tx_ba_session(struct ieee80211_sta *sta, u16 tid);
/**
* ieee80211_stop_tx_ba_cb_irqsafe - low level driver ready to stop aggregate.
@@ -2363,8 +2366,8 @@ void ieee80211_stop_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u8 tid);
* @tid: the desired TID to BA on.
*
* This function must be called by low level driver once it has
- * finished with preparations for the BA session tear down.
- * This version of the function is IRQ-safe.
+ * finished with preparations for the BA session tear down. It
+ * can be called from any context.
*/
void ieee80211_stop_tx_ba_cb_irqsafe(struct ieee80211_vif *vif, const u8 *ra,
u16 tid);
@@ -2460,6 +2463,36 @@ void ieee80211_beacon_loss(struct ieee80211_vif *vif);
void ieee80211_connection_loss(struct ieee80211_vif *vif);
/**
+ * ieee80211_disable_dyn_ps - force mac80211 to temporarily disable dynamic psm
+ *
+ * @vif: &struct ieee80211_vif pointer from the add_interface callback.
+ *
+ * Some hardware require full power save to manage simultaneous BT traffic
+ * on the WLAN frequency. Full PSM is required periodically, whenever there are
+ * burst of BT traffic. The hardware gets information of BT traffic via
+ * hardware co-existence lines, and consequentially requests mac80211 to
+ * (temporarily) enter full psm.
+ * This function will only temporarily disable dynamic PS, not enable PSM if
+ * it was not already enabled.
+ * The driver must make sure to re-enable dynamic PS using
+ * ieee80211_enable_dyn_ps() if the driver has disabled it.
+ *
+ */
+void ieee80211_disable_dyn_ps(struct ieee80211_vif *vif);
+
+/**
+ * ieee80211_enable_dyn_ps - restore dynamic psm after being disabled
+ *
+ * @vif: &struct ieee80211_vif pointer from the add_interface callback.
+ *
+ * This function restores dynamic PS after being temporarily disabled via
+ * ieee80211_disable_dyn_ps(). Each ieee80211_disable_dyn_ps() call must
+ * be coupled with an eventual call to this function.
+ *
+ */
+void ieee80211_enable_dyn_ps(struct ieee80211_vif *vif);
+
+/**
* ieee80211_cqm_rssi_notify - inform a configured connection quality monitoring
* rssi threshold triggered
*
diff --git a/include/net/mip6.h b/include/net/mip6.h
index a83ad1982a9..26ba99b5a4b 100644
--- a/include/net/mip6.h
+++ b/include/net/mip6.h
@@ -39,7 +39,7 @@ struct ip6_mh {
__u16 ip6mh_cksum;
/* Followed by type specific messages */
__u8 data[0];
-} __attribute__ ((__packed__));
+} __packed;
#define IP6_MH_TYPE_BRR 0 /* Binding Refresh Request */
#define IP6_MH_TYPE_HOTI 1 /* HOTI Message */
diff --git a/include/net/ndisc.h b/include/net/ndisc.h
index f76f22d0572..895997bc2ea 100644
--- a/include/net/ndisc.h
+++ b/include/net/ndisc.h
@@ -82,7 +82,7 @@ struct ra_msg {
struct nd_opt_hdr {
__u8 nd_opt_type;
__u8 nd_opt_len;
-} __attribute__((__packed__));
+} __packed;
extern int ndisc_init(void);
diff --git a/include/net/neighbour.h b/include/net/neighbour.h
index eb21340a573..242879b6c4d 100644
--- a/include/net/neighbour.h
+++ b/include/net/neighbour.h
@@ -151,7 +151,7 @@ struct neigh_table {
void (*proxy_redo)(struct sk_buff *skb);
char *id;
struct neigh_parms parms;
- /* HACK. gc_* shoul follow parms without a gap! */
+ /* HACK. gc_* should follow parms without a gap! */
int gc_interval;
int gc_thresh1;
int gc_thresh2;
diff --git a/include/net/netfilter/nf_conntrack.h b/include/net/netfilter/nf_conntrack.h
index bde095f7e84..e624dae54fa 100644
--- a/include/net/netfilter/nf_conntrack.h
+++ b/include/net/netfilter/nf_conntrack.h
@@ -152,11 +152,7 @@ extern struct net init_net;
static inline struct net *nf_ct_net(const struct nf_conn *ct)
{
-#ifdef CONFIG_NET_NS
- return ct->ct_net;
-#else
- return &init_net;
-#endif
+ return read_pnet(&ct->ct_net);
}
/* Alter reply tuple (maybe alter helper). */
@@ -261,7 +257,12 @@ extern s16 (*nf_ct_nat_offset)(const struct nf_conn *ct,
u32 seq);
/* Fake conntrack entry for untracked connections */
-extern struct nf_conn nf_conntrack_untracked;
+DECLARE_PER_CPU(struct nf_conn, nf_conntrack_untracked);
+static inline struct nf_conn *nf_ct_untracked_get(void)
+{
+ return &__raw_get_cpu_var(nf_conntrack_untracked);
+}
+extern void nf_ct_untracked_status_or(unsigned long bits);
/* Iterate over all conntracks: if iter returns true, it's deleted. */
extern void
@@ -289,9 +290,9 @@ static inline int nf_ct_is_dying(struct nf_conn *ct)
return test_bit(IPS_DYING_BIT, &ct->status);
}
-static inline int nf_ct_is_untracked(const struct sk_buff *skb)
+static inline int nf_ct_is_untracked(const struct nf_conn *ct)
{
- return (skb->nfct == &nf_conntrack_untracked.ct_general);
+ return test_bit(IPS_UNTRACKED_BIT, &ct->status);
}
extern int nf_conntrack_set_hashsize(const char *val, struct kernel_param *kp);
diff --git a/include/net/netfilter/nf_conntrack_acct.h b/include/net/netfilter/nf_conntrack_acct.h
index 03e218f0be4..4e9c63a20db 100644
--- a/include/net/netfilter/nf_conntrack_acct.h
+++ b/include/net/netfilter/nf_conntrack_acct.h
@@ -45,6 +45,18 @@ struct nf_conn_counter *nf_ct_acct_ext_add(struct nf_conn *ct, gfp_t gfp)
extern unsigned int
seq_print_acct(struct seq_file *s, const struct nf_conn *ct, int dir);
+/* Check if connection tracking accounting is enabled */
+static inline bool nf_ct_acct_enabled(struct net *net)
+{
+ return net->ct.sysctl_acct != 0;
+}
+
+/* Enable/disable connection tracking accounting */
+static inline void nf_ct_set_acct(struct net *net, bool enable)
+{
+ net->ct.sysctl_acct = enable;
+}
+
extern int nf_conntrack_acct_init(struct net *net);
extern void nf_conntrack_acct_fini(struct net *net);
diff --git a/include/net/netfilter/nf_conntrack_core.h b/include/net/netfilter/nf_conntrack_core.h
index 3d7524fba19..aced085132e 100644
--- a/include/net/netfilter/nf_conntrack_core.h
+++ b/include/net/netfilter/nf_conntrack_core.h
@@ -60,7 +60,7 @@ static inline int nf_conntrack_confirm(struct sk_buff *skb)
struct nf_conn *ct = (struct nf_conn *)skb->nfct;
int ret = NF_ACCEPT;
- if (ct && ct != &nf_conntrack_untracked) {
+ if (ct && !nf_ct_is_untracked(ct)) {
if (!nf_ct_is_confirmed(ct))
ret = __nf_conntrack_confirm(skb);
if (likely(ret == NF_ACCEPT))
diff --git a/include/net/netfilter/nf_conntrack_extend.h b/include/net/netfilter/nf_conntrack_extend.h
index 32d15bd6efa..0772d296dfd 100644
--- a/include/net/netfilter/nf_conntrack_extend.h
+++ b/include/net/netfilter/nf_conntrack_extend.h
@@ -28,9 +28,14 @@ struct nf_ct_ext {
char data[0];
};
-static inline int nf_ct_ext_exist(const struct nf_conn *ct, u8 id)
+static inline bool __nf_ct_ext_exist(const struct nf_ct_ext *ext, u8 id)
{
- return (ct->ext && ct->ext->offset[id]);
+ return !!ext->offset[id];
+}
+
+static inline bool nf_ct_ext_exist(const struct nf_conn *ct, u8 id)
+{
+ return (ct->ext && __nf_ct_ext_exist(ct->ext, id));
}
static inline void *__nf_ct_ext_find(const struct nf_conn *ct, u8 id)
diff --git a/include/net/netfilter/nf_nat_protocol.h b/include/net/netfilter/nf_nat_protocol.h
index c398017ccfa..df17bac46bf 100644
--- a/include/net/netfilter/nf_nat_protocol.h
+++ b/include/net/netfilter/nf_nat_protocol.h
@@ -27,9 +27,9 @@ struct nf_nat_protocol {
/* Alter the per-proto part of the tuple (depending on
maniptype), to give a unique tuple in the given range if
- possible; return false if not. Per-protocol part of tuple
- is initialized to the incoming packet. */
- bool (*unique_tuple)(struct nf_conntrack_tuple *tuple,
+ possible. Per-protocol part of tuple is initialized to the
+ incoming packet. */
+ void (*unique_tuple)(struct nf_conntrack_tuple *tuple,
const struct nf_nat_range *range,
enum nf_nat_manip_type maniptype,
const struct nf_conn *ct);
@@ -63,7 +63,7 @@ extern bool nf_nat_proto_in_range(const struct nf_conntrack_tuple *tuple,
const union nf_conntrack_man_proto *min,
const union nf_conntrack_man_proto *max);
-extern bool nf_nat_proto_unique_tuple(struct nf_conntrack_tuple *tuple,
+extern void nf_nat_proto_unique_tuple(struct nf_conntrack_tuple *tuple,
const struct nf_nat_range *range,
enum nf_nat_manip_type maniptype,
const struct nf_conn *ct,
diff --git a/include/net/netfilter/nf_nat_rule.h b/include/net/netfilter/nf_nat_rule.h
index e4a18ae361c..2890bdc4cd9 100644
--- a/include/net/netfilter/nf_nat_rule.h
+++ b/include/net/netfilter/nf_nat_rule.h
@@ -12,6 +12,4 @@ extern int nf_nat_rule_find(struct sk_buff *skb,
const struct net_device *out,
struct nf_conn *ct);
-extern unsigned int
-alloc_null_binding(struct nf_conn *ct, unsigned int hooknum);
#endif /* _NF_NAT_RULE_H */
diff --git a/include/net/netfilter/nfnetlink_log.h b/include/net/netfilter/nfnetlink_log.h
index b0569ff0775..e2dec42c2db 100644
--- a/include/net/netfilter/nfnetlink_log.h
+++ b/include/net/netfilter/nfnetlink_log.h
@@ -10,5 +10,7 @@ nfulnl_log_packet(u_int8_t pf,
const struct nf_loginfo *li_user,
const char *prefix);
+#define NFULNL_COPY_DISABLED 0xff
+
#endif /* _KER_NFNETLINK_LOG_H */
diff --git a/include/net/netfilter/xt_rateest.h b/include/net/netfilter/xt_rateest.h
index ddbf37e1961..5a2978d1cb2 100644
--- a/include/net/netfilter/xt_rateest.h
+++ b/include/net/netfilter/xt_rateest.h
@@ -2,13 +2,18 @@
#define _XT_RATEEST_H
struct xt_rateest {
+ /* keep lock and bstats on same cache line to speedup xt_rateest_tg() */
+ struct gnet_stats_basic_packed bstats;
+ spinlock_t lock;
+ /* keep rstats and lock on same cache line to speedup xt_rateest_mt() */
+ struct gnet_stats_rate_est rstats;
+
+ /* following fields not accessed in hot path */
struct hlist_node list;
char name[IFNAMSIZ];
unsigned int refcnt;
- spinlock_t lock;
struct gnet_estimator params;
- struct gnet_stats_rate_est rstats;
- struct gnet_stats_basic_packed bstats;
+ struct rcu_head rcu;
};
extern struct xt_rateest *xt_rateest_lookup(const char *name);
diff --git a/include/net/netlink.h b/include/net/netlink.h
index 4fc05b58503..f3b201d335b 100644
--- a/include/net/netlink.h
+++ b/include/net/netlink.h
@@ -35,7 +35,7 @@
* nlmsg_new() create a new netlink message
* nlmsg_put() add a netlink message to an skb
* nlmsg_put_answer() callback based nlmsg_put()
- * nlmsg_end() finanlize netlink message
+ * nlmsg_end() finalize netlink message
* nlmsg_get_pos() return current position in message
* nlmsg_trim() trim part of message
* nlmsg_cancel() cancel message construction
diff --git a/include/net/phonet/pn_dev.h b/include/net/phonet/pn_dev.h
index d7b989ca3d6..2d16783d5e2 100644
--- a/include/net/phonet/pn_dev.h
+++ b/include/net/phonet/pn_dev.h
@@ -34,6 +34,7 @@ struct phonet_device {
struct list_head list;
struct net_device *netdev;
DECLARE_BITMAP(addrs, 64);
+ struct rcu_head rcu;
};
int phonet_device_init(void);
diff --git a/include/net/pkt_sched.h b/include/net/pkt_sched.h
index 9d4d87cc970..d9549af6929 100644
--- a/include/net/pkt_sched.h
+++ b/include/net/pkt_sched.h
@@ -95,7 +95,7 @@ extern void __qdisc_run(struct Qdisc *q);
static inline void qdisc_run(struct Qdisc *q)
{
- if (!test_and_set_bit(__QDISC_STATE_RUNNING, &q->state))
+ if (qdisc_run_begin(q))
__qdisc_run(q);
}
diff --git a/include/net/regulatory.h b/include/net/regulatory.h
index f873ee37f7e..9e103a4e91e 100644
--- a/include/net/regulatory.h
+++ b/include/net/regulatory.h
@@ -54,7 +54,6 @@ struct regulatory_request {
enum nl80211_reg_initiator initiator;
char alpha2[2];
bool intersect;
- u32 country_ie_checksum;
enum environment_cap country_ie_env;
struct list_head list;
};
diff --git a/include/net/route.h b/include/net/route.h
index af6cf4b4c9d..bd732d62e1c 100644
--- a/include/net/route.h
+++ b/include/net/route.h
@@ -50,9 +50,7 @@
struct fib_nh;
struct inet_peer;
struct rtable {
- union {
- struct dst_entry dst;
- } u;
+ struct dst_entry dst;
/* Cache lookup keys */
struct flowi fl;
@@ -144,7 +142,7 @@ extern void fib_add_ifaddr(struct in_ifaddr *);
static inline void ip_rt_put(struct rtable * rt)
{
if (rt)
- dst_release(&rt->u.dst);
+ dst_release(&rt->dst);
}
#define IPTOS_RT_MASK (IPTOS_TOS_MASK & ~3)
diff --git a/include/net/sch_generic.h b/include/net/sch_generic.h
index 433604bb3fe..3c8728aaab4 100644
--- a/include/net/sch_generic.h
+++ b/include/net/sch_generic.h
@@ -23,11 +23,17 @@ struct qdisc_rate_table {
};
enum qdisc_state_t {
- __QDISC_STATE_RUNNING,
__QDISC_STATE_SCHED,
__QDISC_STATE_DEACTIVATED,
};
+/*
+ * following bits are only changed while qdisc lock is held
+ */
+enum qdisc___state_t {
+ __QDISC___STATE_RUNNING,
+};
+
struct qdisc_size_table {
struct list_head list;
struct tc_sizespec szopts;
@@ -72,10 +78,27 @@ struct Qdisc {
unsigned long state;
struct sk_buff_head q;
struct gnet_stats_basic_packed bstats;
+ unsigned long __state;
struct gnet_stats_queue qstats;
- struct rcu_head rcu_head;
+ struct rcu_head rcu_head;
+ spinlock_t busylock;
};
+static inline bool qdisc_is_running(struct Qdisc *qdisc)
+{
+ return test_bit(__QDISC___STATE_RUNNING, &qdisc->__state);
+}
+
+static inline bool qdisc_run_begin(struct Qdisc *qdisc)
+{
+ return !__test_and_set_bit(__QDISC___STATE_RUNNING, &qdisc->__state);
+}
+
+static inline void qdisc_run_end(struct Qdisc *qdisc)
+{
+ __clear_bit(__QDISC___STATE_RUNNING, &qdisc->__state);
+}
+
struct Qdisc_class_ops {
/* Child qdisc manipulation */
struct netdev_queue * (*select_queue)(struct Qdisc *, struct tcmsg *);
@@ -583,9 +606,16 @@ static inline u32 qdisc_l2t(struct qdisc_rate_table* rtab, unsigned int pktlen)
}
#ifdef CONFIG_NET_CLS_ACT
-static inline struct sk_buff *skb_act_clone(struct sk_buff *skb, gfp_t gfp_mask)
+static inline struct sk_buff *skb_act_clone(struct sk_buff *skb, gfp_t gfp_mask,
+ int action)
{
- struct sk_buff *n = skb_clone(skb, gfp_mask);
+ struct sk_buff *n;
+
+ if ((action == TC_ACT_STOLEN || action == TC_ACT_QUEUED) &&
+ !skb_shared(skb))
+ n = skb_get(skb);
+ else
+ n = skb_clone(skb, gfp_mask);
if (n) {
n->tc_verd = SET_TC_VERD(n->tc_verd, 0);
diff --git a/include/net/scm.h b/include/net/scm.h
index 8360e47aa7e..31656506d96 100644
--- a/include/net/scm.h
+++ b/include/net/scm.h
@@ -19,8 +19,10 @@ struct scm_fp_list {
};
struct scm_cookie {
- struct ucred creds; /* Skb credentials */
+ struct pid *pid; /* Skb credentials */
+ const struct cred *cred;
struct scm_fp_list *fp; /* Passed files */
+ struct ucred creds; /* Skb credentials */
#ifdef CONFIG_SECURITY_NETWORK
u32 secid; /* Passed security ID */
#endif
@@ -42,8 +44,27 @@ static __inline__ void unix_get_peersec_dgram(struct socket *sock, struct scm_co
{ }
#endif /* CONFIG_SECURITY_NETWORK */
+static __inline__ void scm_set_cred(struct scm_cookie *scm,
+ struct pid *pid, const struct cred *cred)
+{
+ scm->pid = get_pid(pid);
+ scm->cred = get_cred(cred);
+ cred_to_ucred(pid, cred, &scm->creds);
+}
+
+static __inline__ void scm_destroy_cred(struct scm_cookie *scm)
+{
+ put_pid(scm->pid);
+ scm->pid = NULL;
+
+ if (scm->cred)
+ put_cred(scm->cred);
+ scm->cred = NULL;
+}
+
static __inline__ void scm_destroy(struct scm_cookie *scm)
{
+ scm_destroy_cred(scm);
if (scm && scm->fp)
__scm_destroy(scm);
}
@@ -51,10 +72,7 @@ static __inline__ void scm_destroy(struct scm_cookie *scm)
static __inline__ int scm_send(struct socket *sock, struct msghdr *msg,
struct scm_cookie *scm)
{
- struct task_struct *p = current;
- scm->creds.uid = current_uid();
- scm->creds.gid = current_gid();
- scm->creds.pid = task_tgid_vnr(p);
+ scm_set_cred(scm, task_tgid(current), current_cred());
scm->fp = NULL;
unix_get_peersec_dgram(sock, scm);
if (msg->msg_controllen <= 0)
@@ -96,6 +114,8 @@ static __inline__ void scm_recv(struct socket *sock, struct msghdr *msg,
if (test_bit(SOCK_PASSCRED, &sock->flags))
put_cmsg(msg, SOL_SOCKET, SCM_CREDENTIALS, sizeof(scm->creds), &scm->creds);
+ scm_destroy_cred(scm);
+
scm_passec(sock, msg, scm);
if (!scm->fp)
diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h
index 4b860116e09..f9e7473613b 100644
--- a/include/net/sctp/structs.h
+++ b/include/net/sctp/structs.h
@@ -443,7 +443,7 @@ struct sctp_signed_cookie {
__u8 signature[SCTP_SECRET_SIZE];
__u32 __pad; /* force sctp_cookie alignment to 64 bits */
struct sctp_cookie c;
-} __attribute__((packed));
+} __packed;
/* This is another convenience type to allocate memory for address
* params for the maximum size and pass such structures around
@@ -488,7 +488,7 @@ typedef struct sctp_sender_hb_info {
union sctp_addr daddr;
unsigned long sent_at;
__u64 hb_nonce;
-} __attribute__((packed)) sctp_sender_hb_info_t;
+} __packed sctp_sender_hb_info_t;
/*
* RFC 2960 1.3.2 Sequenced Delivery within Streams
diff --git a/include/net/snmp.h b/include/net/snmp.h
index 899003d18db..a0e61806d48 100644
--- a/include/net/snmp.h
+++ b/include/net/snmp.h
@@ -47,15 +47,16 @@ struct snmp_mib {
}
/*
- * We use all unsigned longs. Linux will soon be so reliable that even
- * these will rapidly get too small 8-). Seriously consider the IpInReceives
- * count on the 20Gb/s + networks people expect in a few years time!
+ * We use unsigned longs for most mibs but u64 for ipstats.
*/
+#include <linux/u64_stats_sync.h>
/* IPstats */
#define IPSTATS_MIB_MAX __IPSTATS_MIB_MAX
struct ipstats_mib {
- unsigned long mibs[IPSTATS_MIB_MAX];
+ /* mibs[] must be first field of struct ipstats_mib */
+ u64 mibs[IPSTATS_MIB_MAX];
+ struct u64_stats_sync syncp;
};
/* ICMP */
@@ -155,4 +156,70 @@ struct linux_xfrm_mib {
ptr->mibs[basefield##PKTS]++; \
ptr->mibs[basefield##OCTETS] += addend;\
} while (0)
+
+
+#if BITS_PER_LONG==32
+
+#define SNMP_ADD_STATS64_BH(mib, field, addend) \
+ do { \
+ __typeof__(*mib[0]) *ptr = __this_cpu_ptr((mib)[0]); \
+ u64_stats_update_begin(&ptr->syncp); \
+ ptr->mibs[field] += addend; \
+ u64_stats_update_end(&ptr->syncp); \
+ } while (0)
+#define SNMP_ADD_STATS64_USER(mib, field, addend) \
+ do { \
+ __typeof__(*mib[0]) *ptr; \
+ preempt_disable(); \
+ ptr = __this_cpu_ptr((mib)[1]); \
+ u64_stats_update_begin(&ptr->syncp); \
+ ptr->mibs[field] += addend; \
+ u64_stats_update_end(&ptr->syncp); \
+ preempt_enable(); \
+ } while (0)
+#define SNMP_ADD_STATS64(mib, field, addend) \
+ do { \
+ __typeof__(*mib[0]) *ptr; \
+ preempt_disable(); \
+ ptr = __this_cpu_ptr((mib)[!in_softirq()]); \
+ u64_stats_update_begin(&ptr->syncp); \
+ ptr->mibs[field] += addend; \
+ u64_stats_update_end(&ptr->syncp); \
+ preempt_enable(); \
+ } while (0)
+#define SNMP_INC_STATS64_BH(mib, field) SNMP_ADD_STATS64_BH(mib, field, 1)
+#define SNMP_INC_STATS64_USER(mib, field) SNMP_ADD_STATS64_USER(mib, field, 1)
+#define SNMP_INC_STATS64(mib, field) SNMP_ADD_STATS64(mib, field, 1)
+#define SNMP_UPD_PO_STATS64(mib, basefield, addend) \
+ do { \
+ __typeof__(*mib[0]) *ptr; \
+ preempt_disable(); \
+ ptr = __this_cpu_ptr((mib)[!in_softirq()]); \
+ u64_stats_update_begin(&ptr->syncp); \
+ ptr->mibs[basefield##PKTS]++; \
+ ptr->mibs[basefield##OCTETS] += addend; \
+ u64_stats_update_end(&ptr->syncp); \
+ preempt_enable(); \
+ } while (0)
+#define SNMP_UPD_PO_STATS64_BH(mib, basefield, addend) \
+ do { \
+ __typeof__(*mib[0]) *ptr; \
+ ptr = __this_cpu_ptr((mib)[!in_softirq()]); \
+ u64_stats_update_begin(&ptr->syncp); \
+ ptr->mibs[basefield##PKTS]++; \
+ ptr->mibs[basefield##OCTETS] += addend; \
+ u64_stats_update_end(&ptr->syncp); \
+ } while (0)
+#else
+#define SNMP_INC_STATS64_BH(mib, field) SNMP_INC_STATS_BH(mib, field)
+#define SNMP_INC_STATS64_USER(mib, field) SNMP_INC_STATS_USER(mib, field)
+#define SNMP_INC_STATS64(mib, field) SNMP_INC_STATS(mib, field)
+#define SNMP_DEC_STATS64(mib, field) SNMP_DEC_STATS(mib, field)
+#define SNMP_ADD_STATS64_BH(mib, field, addend) SNMP_ADD_STATS_BH(mib, field, addend)
+#define SNMP_ADD_STATS64_USER(mib, field, addend) SNMP_ADD_STATS_USER(mib, field, addend)
+#define SNMP_ADD_STATS64(mib, field, addend) SNMP_ADD_STATS(mib, field, addend)
+#define SNMP_UPD_PO_STATS64(mib, basefield, addend) SNMP_UPD_PO_STATS(mib, basefield, addend)
+#define SNMP_UPD_PO_STATS64_BH(mib, basefield, addend) SNMP_UPD_PO_STATS_BH(mib, basefield, addend)
+#endif
+
#endif
diff --git a/include/net/sock.h b/include/net/sock.h
index 0a691ea7654..a441c9cdd62 100644
--- a/include/net/sock.h
+++ b/include/net/sock.h
@@ -295,7 +295,8 @@ struct sock {
unsigned short sk_ack_backlog;
unsigned short sk_max_ack_backlog;
__u32 sk_priority;
- struct ucred sk_peercred;
+ struct pid *sk_peer_pid;
+ const struct cred *sk_peer_cred;
long sk_rcvtimeo;
long sk_sndtimeo;
struct sk_filter *sk_filter;
@@ -771,6 +772,7 @@ struct proto {
int *sysctl_wmem;
int *sysctl_rmem;
int max_header;
+ bool no_autobind;
struct kmem_cache *slab;
unsigned int obj_size;
@@ -1706,19 +1708,13 @@ static inline void sk_eat_skb(struct sock *sk, struct sk_buff *skb, int copied_e
static inline
struct net *sock_net(const struct sock *sk)
{
-#ifdef CONFIG_NET_NS
- return sk->sk_net;
-#else
- return &init_net;
-#endif
+ return read_pnet(&sk->sk_net);
}
static inline
void sock_net_set(struct sock *sk, struct net *net)
{
-#ifdef CONFIG_NET_NS
- sk->sk_net = net;
-#endif
+ write_pnet(&sk->sk_net, net);
}
/*
diff --git a/include/net/tcp.h b/include/net/tcp.h
index a1449144848..df6a2eb2019 100644
--- a/include/net/tcp.h
+++ b/include/net/tcp.h
@@ -296,45 +296,30 @@ extern struct proto tcp_prot;
#define TCP_ADD_STATS_USER(net, field, val) SNMP_ADD_STATS_USER((net)->mib.tcp_statistics, field, val)
#define TCP_ADD_STATS(net, field, val) SNMP_ADD_STATS((net)->mib.tcp_statistics, field, val)
-extern void tcp_v4_err(struct sk_buff *skb, u32);
-
-extern void tcp_shutdown (struct sock *sk, int how);
-
-extern int tcp_v4_rcv(struct sk_buff *skb);
-
-extern int tcp_v4_remember_stamp(struct sock *sk);
-
-extern int tcp_v4_tw_remember_stamp(struct inet_timewait_sock *tw);
-
-extern int tcp_sendmsg(struct kiocb *iocb, struct socket *sock,
- struct msghdr *msg, size_t size);
-extern ssize_t tcp_sendpage(struct socket *sock, struct page *page, int offset, size_t size, int flags);
-
-extern int tcp_ioctl(struct sock *sk,
- int cmd,
- unsigned long arg);
-
-extern int tcp_rcv_state_process(struct sock *sk,
- struct sk_buff *skb,
- struct tcphdr *th,
- unsigned len);
-
-extern int tcp_rcv_established(struct sock *sk,
- struct sk_buff *skb,
- struct tcphdr *th,
- unsigned len);
-
-extern void tcp_rcv_space_adjust(struct sock *sk);
-
-extern void tcp_cleanup_rbuf(struct sock *sk, int copied);
-
-extern int tcp_twsk_unique(struct sock *sk,
- struct sock *sktw, void *twp);
-
-extern void tcp_twsk_destructor(struct sock *sk);
-
-extern ssize_t tcp_splice_read(struct socket *sk, loff_t *ppos,
- struct pipe_inode_info *pipe, size_t len, unsigned int flags);
+extern void tcp_v4_err(struct sk_buff *skb, u32);
+
+extern void tcp_shutdown (struct sock *sk, int how);
+
+extern int tcp_v4_rcv(struct sk_buff *skb);
+
+extern int tcp_v4_remember_stamp(struct sock *sk);
+extern int tcp_v4_tw_remember_stamp(struct inet_timewait_sock *tw);
+extern int tcp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
+ size_t size);
+extern int tcp_sendpage(struct sock *sk, struct page *page, int offset,
+ size_t size, int flags);
+extern int tcp_ioctl(struct sock *sk, int cmd, unsigned long arg);
+extern int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb,
+ struct tcphdr *th, unsigned len);
+extern int tcp_rcv_established(struct sock *sk, struct sk_buff *skb,
+ struct tcphdr *th, unsigned len);
+extern void tcp_rcv_space_adjust(struct sock *sk);
+extern void tcp_cleanup_rbuf(struct sock *sk, int copied);
+extern int tcp_twsk_unique(struct sock *sk, struct sock *sktw, void *twp);
+extern void tcp_twsk_destructor(struct sock *sk);
+extern ssize_t tcp_splice_read(struct socket *sk, loff_t *ppos,
+ struct pipe_inode_info *pipe, size_t len,
+ unsigned int flags);
static inline void tcp_dec_quickack_mode(struct sock *sk,
const unsigned int pkts)
@@ -372,88 +357,59 @@ enum tcp_tw_status {
};
-extern enum tcp_tw_status tcp_timewait_state_process(struct inet_timewait_sock *tw,
- struct sk_buff *skb,
- const struct tcphdr *th);
-
-extern struct sock * tcp_check_req(struct sock *sk,struct sk_buff *skb,
- struct request_sock *req,
- struct request_sock **prev);
-extern int tcp_child_process(struct sock *parent,
- struct sock *child,
- struct sk_buff *skb);
-extern int tcp_use_frto(struct sock *sk);
-extern void tcp_enter_frto(struct sock *sk);
-extern void tcp_enter_loss(struct sock *sk, int how);
-extern void tcp_clear_retrans(struct tcp_sock *tp);
-extern void tcp_update_metrics(struct sock *sk);
-
-extern void tcp_close(struct sock *sk,
- long timeout);
-extern unsigned int tcp_poll(struct file * file, struct socket *sock, struct poll_table_struct *wait);
-
-extern int tcp_getsockopt(struct sock *sk, int level,
- int optname,
- char __user *optval,
- int __user *optlen);
-extern int tcp_setsockopt(struct sock *sk, int level,
- int optname, char __user *optval,
- unsigned int optlen);
-extern int compat_tcp_getsockopt(struct sock *sk,
- int level, int optname,
- char __user *optval, int __user *optlen);
-extern int compat_tcp_setsockopt(struct sock *sk,
- int level, int optname,
- char __user *optval, unsigned int optlen);
-extern void tcp_set_keepalive(struct sock *sk, int val);
-extern void tcp_syn_ack_timeout(struct sock *sk,
- struct request_sock *req);
-extern int tcp_recvmsg(struct kiocb *iocb, struct sock *sk,
- struct msghdr *msg,
- size_t len, int nonblock,
- int flags, int *addr_len);
-
-extern void tcp_parse_options(struct sk_buff *skb,
- struct tcp_options_received *opt_rx,
- u8 **hvpp,
- int estab);
-
-extern u8 *tcp_parse_md5sig_option(struct tcphdr *th);
+extern enum tcp_tw_status tcp_timewait_state_process(struct inet_timewait_sock *tw,
+ struct sk_buff *skb,
+ const struct tcphdr *th);
+extern struct sock * tcp_check_req(struct sock *sk,struct sk_buff *skb,
+ struct request_sock *req,
+ struct request_sock **prev);
+extern int tcp_child_process(struct sock *parent, struct sock *child,
+ struct sk_buff *skb);
+extern int tcp_use_frto(struct sock *sk);
+extern void tcp_enter_frto(struct sock *sk);
+extern void tcp_enter_loss(struct sock *sk, int how);
+extern void tcp_clear_retrans(struct tcp_sock *tp);
+extern void tcp_update_metrics(struct sock *sk);
+extern void tcp_close(struct sock *sk, long timeout);
+extern unsigned int tcp_poll(struct file * file, struct socket *sock,
+ struct poll_table_struct *wait);
+extern int tcp_getsockopt(struct sock *sk, int level, int optname,
+ char __user *optval, int __user *optlen);
+extern int tcp_setsockopt(struct sock *sk, int level, int optname,
+ char __user *optval, unsigned int optlen);
+extern int compat_tcp_getsockopt(struct sock *sk, int level, int optname,
+ char __user *optval, int __user *optlen);
+extern int compat_tcp_setsockopt(struct sock *sk, int level, int optname,
+ char __user *optval, unsigned int optlen);
+extern void tcp_set_keepalive(struct sock *sk, int val);
+extern void tcp_syn_ack_timeout(struct sock *sk, struct request_sock *req);
+extern int tcp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
+ size_t len, int nonblock, int flags, int *addr_len);
+extern void tcp_parse_options(struct sk_buff *skb,
+ struct tcp_options_received *opt_rx, u8 **hvpp,
+ int estab);
+extern u8 *tcp_parse_md5sig_option(struct tcphdr *th);
/*
* TCP v4 functions exported for the inet6 API
*/
-extern void tcp_v4_send_check(struct sock *sk,
- struct sk_buff *skb);
-
-extern int tcp_v4_conn_request(struct sock *sk,
- struct sk_buff *skb);
-
-extern struct sock * tcp_create_openreq_child(struct sock *sk,
- struct request_sock *req,
- struct sk_buff *skb);
-
-extern struct sock * tcp_v4_syn_recv_sock(struct sock *sk,
- struct sk_buff *skb,
- struct request_sock *req,
- struct dst_entry *dst);
-
-extern int tcp_v4_do_rcv(struct sock *sk,
+extern void tcp_v4_send_check(struct sock *sk, struct sk_buff *skb);
+extern int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb);
+extern struct sock * tcp_create_openreq_child(struct sock *sk,
+ struct request_sock *req,
struct sk_buff *skb);
-
-extern int tcp_v4_connect(struct sock *sk,
- struct sockaddr *uaddr,
- int addr_len);
-
-extern int tcp_connect(struct sock *sk);
-
-extern struct sk_buff * tcp_make_synack(struct sock *sk,
- struct dst_entry *dst,
- struct request_sock *req,
- struct request_values *rvp);
-
-extern int tcp_disconnect(struct sock *sk, int flags);
+extern struct sock * tcp_v4_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
+ struct request_sock *req,
+ struct dst_entry *dst);
+extern int tcp_v4_do_rcv(struct sock *sk, struct sk_buff *skb);
+extern int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr,
+ int addr_len);
+extern int tcp_connect(struct sock *sk);
+extern struct sk_buff * tcp_make_synack(struct sock *sk, struct dst_entry *dst,
+ struct request_sock *req,
+ struct request_values *rvp);
+extern int tcp_disconnect(struct sock *sk, int flags);
/* From syncookies.c */
@@ -464,7 +420,7 @@ extern __u32 cookie_v4_init_sequence(struct sock *sk, struct sk_buff *skb,
__u16 *mss);
extern __u32 cookie_init_timestamp(struct request_sock *req);
-extern void cookie_check_timestamp(struct tcp_options_received *tcp_opt);
+extern bool cookie_check_timestamp(struct tcp_options_received *opt, bool *);
/* From net/ipv6/syncookies.c */
extern struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb);
@@ -485,10 +441,10 @@ extern int tcp_fragment(struct sock *, struct sk_buff *, u32, unsigned int);
extern void tcp_send_probe0(struct sock *);
extern void tcp_send_partial(struct sock *);
-extern int tcp_write_wakeup(struct sock *);
+extern int tcp_write_wakeup(struct sock *);
extern void tcp_send_fin(struct sock *sk);
extern void tcp_send_active_reset(struct sock *sk, gfp_t priority);
-extern int tcp_send_synack(struct sock *);
+extern int tcp_send_synack(struct sock *);
extern void tcp_push_one(struct sock *, unsigned int mss_now);
extern void tcp_send_ack(struct sock *sk);
extern void tcp_send_delayed_ack(struct sock *sk);
@@ -592,7 +548,7 @@ static inline u32 tcp_receive_window(const struct tcp_sock *tp)
* scaling applied to the result. The caller does these things
* if necessary. This is a "raw" window selection.
*/
-extern u32 __tcp_select_window(struct sock *sk);
+extern u32 __tcp_select_window(struct sock *sk);
/* TCP timestamps are only 32-bits, this causes a slight
* complication on 64-bit systems since we store a snapshot
@@ -602,12 +558,22 @@ extern u32 __tcp_select_window(struct sock *sk);
*/
#define tcp_time_stamp ((__u32)(jiffies))
+#define tcp_flag_byte(th) (((u_int8_t *)th)[13])
+
+#define TCPHDR_FIN 0x01
+#define TCPHDR_SYN 0x02
+#define TCPHDR_RST 0x04
+#define TCPHDR_PSH 0x08
+#define TCPHDR_ACK 0x10
+#define TCPHDR_URG 0x20
+#define TCPHDR_ECE 0x40
+#define TCPHDR_CWR 0x80
+
/* This is what the send packet queuing engine uses to pass
- * TCP per-packet control information to the transmission
- * code. We also store the host-order sequence numbers in
- * here too. This is 36 bytes on 32-bit architectures,
- * 40 bytes on 64-bit machines, if this grows please adjust
- * skbuff.h:skbuff->cb[xxx] size appropriately.
+ * TCP per-packet control information to the transmission code.
+ * We also store the host-order sequence numbers in here too.
+ * This is 44 bytes if IPV6 is enabled.
+ * If this grows please adjust skbuff.h:skbuff->cb[xxx] size appropriately.
*/
struct tcp_skb_cb {
union {
@@ -620,19 +586,6 @@ struct tcp_skb_cb {
__u32 end_seq; /* SEQ + FIN + SYN + datalen */
__u32 when; /* used to compute rtt's */
__u8 flags; /* TCP header flags. */
-
- /* NOTE: These must match up to the flags byte in a
- * real TCP header.
- */
-#define TCPCB_FLAG_FIN 0x01
-#define TCPCB_FLAG_SYN 0x02
-#define TCPCB_FLAG_RST 0x04
-#define TCPCB_FLAG_PSH 0x08
-#define TCPCB_FLAG_ACK 0x10
-#define TCPCB_FLAG_URG 0x20
-#define TCPCB_FLAG_ECE 0x40
-#define TCPCB_FLAG_CWR 0x80
-
__u8 sacked; /* State flags for SACK/FACK. */
#define TCPCB_SACKED_ACKED 0x01 /* SKB ACK'd by a SACK block */
#define TCPCB_SACKED_RETRANS 0x02 /* SKB retransmitted */
@@ -1176,22 +1129,14 @@ struct tcp_md5sig_pool {
#define TCP_MD5SIG_MAXKEYS (~(u32)0) /* really?! */
/* - functions */
-extern int tcp_v4_md5_hash_skb(char *md5_hash,
- struct tcp_md5sig_key *key,
- struct sock *sk,
- struct request_sock *req,
- struct sk_buff *skb);
-
-extern struct tcp_md5sig_key *tcp_v4_md5_lookup(struct sock *sk,
- struct sock *addr_sk);
-
-extern int tcp_v4_md5_do_add(struct sock *sk,
- __be32 addr,
- u8 *newkey,
- u8 newkeylen);
-
-extern int tcp_v4_md5_do_del(struct sock *sk,
- __be32 addr);
+extern int tcp_v4_md5_hash_skb(char *md5_hash, struct tcp_md5sig_key *key,
+ struct sock *sk, struct request_sock *req,
+ struct sk_buff *skb);
+extern struct tcp_md5sig_key * tcp_v4_md5_lookup(struct sock *sk,
+ struct sock *addr_sk);
+extern int tcp_v4_md5_do_add(struct sock *sk, __be32 addr, u8 *newkey,
+ u8 newkeylen);
+extern int tcp_v4_md5_do_del(struct sock *sk, __be32 addr);
#ifdef CONFIG_TCP_MD5SIG
#define tcp_twsk_md5_key(twsk) ((twsk)->tw_md5_keylen ? \
@@ -1204,10 +1149,10 @@ extern int tcp_v4_md5_do_del(struct sock *sk,
#endif
extern struct tcp_md5sig_pool * __percpu *tcp_alloc_md5sig_pool(struct sock *);
-extern void tcp_free_md5sig_pool(void);
+extern void tcp_free_md5sig_pool(void);
extern struct tcp_md5sig_pool *tcp_get_md5sig_pool(void);
-extern void tcp_put_md5sig_pool(void);
+extern void tcp_put_md5sig_pool(void);
extern int tcp_md5_hash_header(struct tcp_md5sig_pool *, struct tcphdr *);
extern int tcp_md5_hash_skb_data(struct tcp_md5sig_pool *, struct sk_buff *,
@@ -1413,7 +1358,8 @@ struct tcp_iter_state {
sa_family_t family;
enum tcp_seq_states state;
struct sock *syn_wait_sk;
- int bucket, sbucket, num, uid;
+ int bucket, offset, sbucket, num, uid;
+ loff_t last_pos;
};
extern int tcp_proc_register(struct net *net, struct tcp_seq_afinfo *afinfo);
@@ -1434,7 +1380,7 @@ extern int tcp_gro_complete(struct sk_buff *skb);
extern int tcp4_gro_complete(struct sk_buff *skb);
#ifdef CONFIG_PROC_FS
-extern int tcp4_proc_init(void);
+extern int tcp4_proc_init(void);
extern void tcp4_proc_exit(void);
#endif
diff --git a/include/net/udp.h b/include/net/udp.h
index 5348d80b25b..7abdf305da5 100644
--- a/include/net/udp.h
+++ b/include/net/udp.h
@@ -157,30 +157,28 @@ static inline void udp_lib_close(struct sock *sk, long timeout)
sk_common_release(sk);
}
-extern int udp_lib_get_port(struct sock *sk, unsigned short snum,
- int (*)(const struct sock *,const struct sock *),
- unsigned int hash2_nulladdr);
+extern int udp_lib_get_port(struct sock *sk, unsigned short snum,
+ int (*)(const struct sock *,const struct sock *),
+ unsigned int hash2_nulladdr);
/* net/ipv4/udp.c */
-extern int udp_get_port(struct sock *sk, unsigned short snum,
- int (*saddr_cmp)(const struct sock *, const struct sock *));
-extern void udp_err(struct sk_buff *, u32);
-
-extern int udp_sendmsg(struct kiocb *iocb, struct sock *sk,
+extern int udp_get_port(struct sock *sk, unsigned short snum,
+ int (*saddr_cmp)(const struct sock *,
+ const struct sock *));
+extern void udp_err(struct sk_buff *, u32);
+extern int udp_sendmsg(struct kiocb *iocb, struct sock *sk,
struct msghdr *msg, size_t len);
-extern void udp_flush_pending_frames(struct sock *sk);
-
-extern int udp_rcv(struct sk_buff *skb);
-extern int udp_ioctl(struct sock *sk, int cmd, unsigned long arg);
-extern int udp_disconnect(struct sock *sk, int flags);
+extern void udp_flush_pending_frames(struct sock *sk);
+extern int udp_rcv(struct sk_buff *skb);
+extern int udp_ioctl(struct sock *sk, int cmd, unsigned long arg);
+extern int udp_disconnect(struct sock *sk, int flags);
extern unsigned int udp_poll(struct file *file, struct socket *sock,
poll_table *wait);
-extern int udp_lib_getsockopt(struct sock *sk, int level, int optname,
- char __user *optval, int __user *optlen);
-extern int udp_lib_setsockopt(struct sock *sk, int level, int optname,
- char __user *optval, unsigned int optlen,
- int (*push_pending_frames)(struct sock *));
-
+extern int udp_lib_getsockopt(struct sock *sk, int level, int optname,
+ char __user *optval, int __user *optlen);
+extern int udp_lib_setsockopt(struct sock *sk, int level, int optname,
+ char __user *optval, unsigned int optlen,
+ int (*push_pending_frames)(struct sock *));
extern struct sock *udp4_lib_lookup(struct net *net, __be32 saddr, __be16 sport,
__be32 daddr, __be16 dport,
int dif);
@@ -236,7 +234,7 @@ struct udp_iter_state {
extern int udp_proc_register(struct net *net, struct udp_seq_afinfo *afinfo);
extern void udp_proc_unregister(struct net *net, struct udp_seq_afinfo *afinfo);
-extern int udp4_proc_init(void);
+extern int udp4_proc_init(void);
extern void udp4_proc_exit(void);
#endif
diff --git a/include/pcmcia/cistpl.h b/include/pcmcia/cistpl.h
index cfdd5af77dc..1c5088c9f7b 100644
--- a/include/pcmcia/cistpl.h
+++ b/include/pcmcia/cistpl.h
@@ -15,6 +15,8 @@
#ifndef _LINUX_CISTPL_H
#define _LINUX_CISTPL_H
+typedef unsigned char cisdata_t;
+
#define CISTPL_NULL 0x00
#define CISTPL_DEVICE 0x01
#define CISTPL_LONGLINK_CB 0x02
diff --git a/include/pcmcia/cs.h b/include/pcmcia/cs.h
index 57d8d039356..68d8bde7e8d 100644
--- a/include/pcmcia/cs.h
+++ b/include/pcmcia/cs.h
@@ -19,44 +19,6 @@
#include <linux/interrupt.h>
#endif
-/* For AccessConfigurationRegister */
-typedef struct conf_reg_t {
- u_char Function;
- u_int Action;
- off_t Offset;
- u_int Value;
-} conf_reg_t;
-
-/* Actions */
-#define CS_READ 1
-#define CS_WRITE 2
-
-/* for AdjustResourceInfo */
-/* Action field */
-#define REMOVE_MANAGED_RESOURCE 1
-#define ADD_MANAGED_RESOURCE 2
-
-
-typedef struct event_callback_args_t {
- struct pcmcia_device *client_handle;
- void *client_data;
-} event_callback_args_t;
-
-/* For CardValues field */
-#define CV_OPTION_VALUE 0x01
-#define CV_STATUS_VALUE 0x02
-#define CV_PIN_REPLACEMENT 0x04
-#define CV_COPY_VALUE 0x08
-#define CV_EXT_STATUS 0x10
-
-/* For GetFirst/NextClient */
-typedef struct client_req_t {
- socket_t Socket;
- u_int Attributes;
-} client_req_t;
-
-#define CLIENT_THIS_SOCKET 0x01
-
/* ModifyConfiguration */
typedef struct modconf_t {
u_int Attributes;
@@ -94,43 +56,6 @@ typedef struct config_req_t {
#define INT_CARDBUS 0x04
#define INT_ZOOMED_VIDEO 0x08
-/* For RequestIO and ReleaseIO */
-typedef struct io_req_t {
- u_int BasePort1;
- u_int NumPorts1;
- u_int Attributes1;
- u_int BasePort2;
- u_int NumPorts2;
- u_int Attributes2;
- u_int IOAddrLines;
-} io_req_t;
-
-/* Attributes for RequestIO and ReleaseIO */
-#define IO_SHARED 0x01
-#define IO_FIRST_SHARED 0x02
-#define IO_FORCE_ALIAS_ACCESS 0x04
-#define IO_DATA_PATH_WIDTH 0x18
-#define IO_DATA_PATH_WIDTH_8 0x00
-#define IO_DATA_PATH_WIDTH_16 0x08
-#define IO_DATA_PATH_WIDTH_AUTO 0x10
-
-/* Bits in IRQInfo1 field */
-#define IRQ_NMI_ID 0x01
-#define IRQ_IOCK_ID 0x02
-#define IRQ_BERR_ID 0x04
-#define IRQ_VEND_ID 0x08
-#define IRQ_INFO2_VALID 0x10
-#define IRQ_LEVEL_ID 0x20
-#define IRQ_PULSE_ID 0x40
-#define IRQ_SHARE_ID 0x80
-
-typedef struct eventmask_t {
- u_int Attributes;
- u_int EventMask;
-} eventmask_t;
-
-#define CONF_EVENT_MASK_VALID 0x01
-
/* Configuration registers present */
#define PRESENT_OPTION 0x001
#define PRESENT_STATUS 0x002
@@ -143,18 +68,6 @@ typedef struct eventmask_t {
#define PRESENT_IOBASE_3 0x100
#define PRESENT_IOSIZE 0x200
-/* For GetMemPage, MapMemPage */
-typedef struct memreq_t {
- u_int CardOffset;
- page_t Page;
-} memreq_t;
-
-/* For ModifyWindow */
-typedef struct modwin_t {
- u_int Attributes;
- u_int AccessSpeed;
-} modwin_t;
-
/* For RequestWindow */
typedef struct win_req_t {
u_int Attributes;
@@ -164,61 +77,19 @@ typedef struct win_req_t {
} win_req_t;
/* Attributes for RequestWindow */
-#define WIN_ADDR_SPACE 0x0001
-#define WIN_ADDR_SPACE_MEM 0x0000
-#define WIN_ADDR_SPACE_IO 0x0001
-#define WIN_MEMORY_TYPE 0x0002
-#define WIN_MEMORY_TYPE_CM 0x0000
-#define WIN_MEMORY_TYPE_AM 0x0002
-#define WIN_ENABLE 0x0004
-#define WIN_DATA_WIDTH 0x0018
-#define WIN_DATA_WIDTH_8 0x0000
-#define WIN_DATA_WIDTH_16 0x0008
-#define WIN_DATA_WIDTH_32 0x0010
-#define WIN_PAGED 0x0020
-#define WIN_SHARED 0x0040
-#define WIN_FIRST_SHARED 0x0080
-#define WIN_USE_WAIT 0x0100
-#define WIN_STRICT_ALIGN 0x0200
-#define WIN_MAP_BELOW_1MB 0x0400
-#define WIN_PREFETCH 0x0800
-#define WIN_CACHEABLE 0x1000
-#define WIN_BAR_MASK 0xe000
-#define WIN_BAR_SHIFT 13
-
-typedef struct error_info_t {
- int func;
- int retcode;
-} error_info_t;
-
-/* Flag to bind to all functions */
-#define BIND_FN_ALL 0xff
-
-/* Events */
-#define CS_EVENT_PRI_LOW 0
-#define CS_EVENT_PRI_HIGH 1
-
-#define CS_EVENT_WRITE_PROTECT 0x000001
-#define CS_EVENT_CARD_LOCK 0x000002
-#define CS_EVENT_CARD_INSERTION 0x000004
-#define CS_EVENT_CARD_REMOVAL 0x000008
-#define CS_EVENT_BATTERY_DEAD 0x000010
-#define CS_EVENT_BATTERY_LOW 0x000020
-#define CS_EVENT_READY_CHANGE 0x000040
-#define CS_EVENT_CARD_DETECT 0x000080
-#define CS_EVENT_RESET_REQUEST 0x000100
-#define CS_EVENT_RESET_PHYSICAL 0x000200
-#define CS_EVENT_CARD_RESET 0x000400
-#define CS_EVENT_REGISTRATION_COMPLETE 0x000800
-#define CS_EVENT_PM_SUSPEND 0x002000
-#define CS_EVENT_PM_RESUME 0x004000
-#define CS_EVENT_INSERTION_REQUEST 0x008000
-#define CS_EVENT_EJECTION_REQUEST 0x010000
-#define CS_EVENT_MTD_REQUEST 0x020000
-#define CS_EVENT_ERASE_COMPLETE 0x040000
-#define CS_EVENT_REQUEST_ATTENTION 0x080000
-#define CS_EVENT_CB_DETECT 0x100000
-#define CS_EVENT_3VCARD 0x200000
-#define CS_EVENT_XVCARD 0x400000
+#define WIN_MEMORY_TYPE_CM 0x00 /* default */
+#define WIN_MEMORY_TYPE_AM 0x20 /* MAP_ATTRIB */
+#define WIN_DATA_WIDTH_8 0x00 /* default */
+#define WIN_DATA_WIDTH_16 0x02 /* MAP_16BIT */
+#define WIN_ENABLE 0x01 /* MAP_ACTIVE */
+#define WIN_USE_WAIT 0x40 /* MAP_USE_WAIT */
+
+#define WIN_FLAGS_MAP 0x63 /* MAP_ATTRIB | MAP_16BIT | MAP_ACTIVE |
+ MAP_USE_WAIT */
+#define WIN_FLAGS_REQ 0x1c /* mapping to socket->win[i]:
+ 0x04 -> 0
+ 0x08 -> 1
+ 0x0c -> 2
+ 0x10 -> 3 */
#endif /* _LINUX_CS_H */
diff --git a/include/pcmcia/cs_types.h b/include/pcmcia/cs_types.h
deleted file mode 100644
index f5e3b8386c8..00000000000
--- a/include/pcmcia/cs_types.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * cs_types.h
- *
- * 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 initial developer of the original code is David A. Hinds
- * <dahinds@users.sourceforge.net>. Portions created by David A. Hinds
- * are Copyright (C) 1999 David A. Hinds. All Rights Reserved.
- *
- * (C) 1999 David A. Hinds
- */
-
-#ifndef _LINUX_CS_TYPES_H
-#define _LINUX_CS_TYPES_H
-
-#ifdef __KERNEL__
-#include <linux/types.h>
-#else
-#include <sys/types.h>
-#endif
-
-typedef u_short socket_t;
-typedef u_int event_t;
-typedef u_char cisdata_t;
-typedef u_short page_t;
-
-typedef unsigned long window_handle_t;
-
-struct region_t;
-typedef struct region_t *memory_handle_t;
-
-#ifndef DEV_NAME_LEN
-#define DEV_NAME_LEN 32
-#endif
-
-typedef char dev_info_t[DEV_NAME_LEN];
-
-#endif /* _LINUX_CS_TYPES_H */
diff --git a/include/pcmcia/ds.h b/include/pcmcia/ds.h
index c180165fbd3..70c58ed2278 100644
--- a/include/pcmcia/ds.h
+++ b/include/pcmcia/ds.h
@@ -20,7 +20,6 @@
#include <linux/mod_devicetable.h>
#endif
-#include <pcmcia/cs_types.h>
#include <pcmcia/device_id.h>
#ifdef __KERNEL__
@@ -37,6 +36,8 @@ struct pcmcia_device;
struct config_t;
struct net_device;
+typedef struct resource *window_handle_t;
+
/* dynamic device IDs for PCMCIA device drivers. See
* Documentation/pcmcia/driver.txt for details.
*/
@@ -62,6 +63,17 @@ struct pcmcia_driver {
int pcmcia_register_driver(struct pcmcia_driver *driver);
void pcmcia_unregister_driver(struct pcmcia_driver *driver);
+/* for struct resource * array embedded in struct pcmcia_device */
+enum {
+ PCMCIA_IOPORT_0,
+ PCMCIA_IOPORT_1,
+ PCMCIA_IOMEM_0,
+ PCMCIA_IOMEM_1,
+ PCMCIA_IOMEM_2,
+ PCMCIA_IOMEM_3,
+ PCMCIA_NUM_RESOURCES,
+};
+
struct pcmcia_device {
/* the socket and the device_no [for multifunction devices]
uniquely define a pcmcia_device */
@@ -79,13 +91,14 @@ struct pcmcia_device {
struct list_head socket_device_list;
/* deprecated, will be cleaned up soon */
- u_int open;
- io_req_t io;
config_req_t conf;
window_handle_t win;
/* device setup */
unsigned int irq;
+ struct resource *resource[PCMCIA_NUM_RESOURCES];
+
+ unsigned int io_lines; /* number of I/O lines */
/* Is the device suspended? */
u16 suspended:1;
@@ -117,13 +130,9 @@ struct pcmcia_device {
u64 dma_mask;
struct device dev;
-#ifdef CONFIG_PCMCIA_IOCTL
- /* device driver wanted by cardmgr */
- struct pcmcia_driver *cardmgr;
-#endif
-
/* data private to drivers */
void *priv;
+ unsigned int open;
};
#define to_pcmcia_dev(n) container_of(n, struct pcmcia_device, dev)
@@ -178,11 +187,11 @@ struct pcmcia_device *pcmcia_dev_present(struct pcmcia_device *p_dev);
int pcmcia_reset_card(struct pcmcia_socket *skt);
/* CIS config */
-int pcmcia_access_configuration_register(struct pcmcia_device *p_dev,
- conf_reg_t *reg);
+int pcmcia_read_config_byte(struct pcmcia_device *p_dev, off_t where, u8 *val);
+int pcmcia_write_config_byte(struct pcmcia_device *p_dev, off_t where, u8 val);
/* device configuration */
-int pcmcia_request_io(struct pcmcia_device *p_dev, io_req_t *req);
+int pcmcia_request_io(struct pcmcia_device *p_dev);
int __must_check
__pcmcia_request_exclusive_irq(struct pcmcia_device *p_dev,
@@ -204,215 +213,27 @@ int pcmcia_request_window(struct pcmcia_device *p_dev, win_req_t *req,
window_handle_t *wh);
int pcmcia_release_window(struct pcmcia_device *p_dev, window_handle_t win);
int pcmcia_map_mem_page(struct pcmcia_device *p_dev, window_handle_t win,
- memreq_t *req);
+ unsigned int offset);
int pcmcia_modify_configuration(struct pcmcia_device *p_dev, modconf_t *mod);
void pcmcia_disable_device(struct pcmcia_device *p_dev);
-#endif /* __KERNEL__ */
-
-
+/* IO ports */
+#define IO_DATA_PATH_WIDTH 0x18
+#define IO_DATA_PATH_WIDTH_8 0x00
+#define IO_DATA_PATH_WIDTH_16 0x08
+#define IO_DATA_PATH_WIDTH_AUTO 0x10
-/* Below, there are only definitions which are used by
- * - the PCMCIA ioctl
- * - deprecated PCMCIA userspace tools only
- *
- * here be dragons ... here be dragons ... here be dragons ... here be drag
- */
-
-#if defined(CONFIG_PCMCIA_IOCTL) || !defined(__KERNEL__)
-
-#if defined(__arm__) || defined(__mips__) || defined(__avr32__) || \
- defined(__bfin__)
-/* This (ioaddr_t) is exposed to userspace & hence cannot be changed. */
-typedef u_int ioaddr_t;
-#else
-typedef u_short ioaddr_t;
-#endif
+/* convert flag found in cfgtable to data path width parameter */
+static inline int pcmcia_io_cfg_data_width(unsigned int flags)
+{
+ if (!(flags & CISTPL_IO_8BIT))
+ return IO_DATA_PATH_WIDTH_16;
+ if (!(flags & CISTPL_IO_16BIT))
+ return IO_DATA_PATH_WIDTH_8;
+ return IO_DATA_PATH_WIDTH_AUTO;
+}
-/* for AdjustResourceInfo */
-typedef struct adjust_t {
- u_int Action;
- u_int Resource;
- u_int Attributes;
- union {
- struct memory {
- u_long Base;
- u_long Size;
- } memory;
- struct io {
- ioaddr_t BasePort;
- ioaddr_t NumPorts;
- u_int IOAddrLines;
- } io;
- struct irq {
- u_int IRQ;
- } irq;
- } resource;
-} adjust_t;
-
-/* Action field */
-#define REMOVE_MANAGED_RESOURCE 1
-#define ADD_MANAGED_RESOURCE 2
-#define GET_FIRST_MANAGED_RESOURCE 3
-#define GET_NEXT_MANAGED_RESOURCE 4
-/* Resource field */
-#define RES_MEMORY_RANGE 1
-#define RES_IO_RANGE 2
-#define RES_IRQ 3
-/* Attribute field */
-#define RES_IRQ_TYPE 0x03
-#define RES_IRQ_TYPE_EXCLUSIVE 0
-#define RES_IRQ_TYPE_TIME 1
-#define RES_IRQ_TYPE_DYNAMIC 2
-#define RES_IRQ_CSC 0x04
-#define RES_SHARED 0x08
-#define RES_RESERVED 0x10
-#define RES_ALLOCATED 0x20
-#define RES_REMOVED 0x40
-
-
-typedef struct tuple_parse_t {
- tuple_t tuple;
- cisdata_t data[255];
- cisparse_t parse;
-} tuple_parse_t;
-
-typedef struct win_info_t {
- window_handle_t handle;
- win_req_t window;
- memreq_t map;
-} win_info_t;
-
-typedef struct bind_info_t {
- dev_info_t dev_info;
- u_char function;
- struct pcmcia_device *instance;
- char name[DEV_NAME_LEN];
- u_short major, minor;
- void *next;
-} bind_info_t;
-
-typedef struct mtd_info_t {
- dev_info_t dev_info;
- u_int Attributes;
- u_int CardOffset;
-} mtd_info_t;
-
-typedef struct region_info_t {
- u_int Attributes;
- u_int CardOffset;
- u_int RegionSize;
- u_int AccessSpeed;
- u_int BlockSize;
- u_int PartMultiple;
- u_char JedecMfr, JedecInfo;
- memory_handle_t next;
-} region_info_t;
-
-#define REGION_TYPE 0x0001
-#define REGION_TYPE_CM 0x0000
-#define REGION_TYPE_AM 0x0001
-#define REGION_PREFETCH 0x0008
-#define REGION_CACHEABLE 0x0010
-#define REGION_BAR_MASK 0xe000
-#define REGION_BAR_SHIFT 13
-
-/* For ReplaceCIS */
-typedef struct cisdump_t {
- u_int Length;
- cisdata_t Data[CISTPL_MAX_CIS_SIZE];
-} cisdump_t;
-
-/* for GetConfigurationInfo */
-typedef struct config_info_t {
- u_char Function;
- u_int Attributes;
- u_int Vcc, Vpp1, Vpp2;
- u_int IntType;
- u_int ConfigBase;
- u_char Status, Pin, Copy, Option, ExtStatus;
- u_int Present;
- u_int CardValues;
- u_int AssignedIRQ;
- u_int IRQAttributes;
- ioaddr_t BasePort1;
- ioaddr_t NumPorts1;
- u_int Attributes1;
- ioaddr_t BasePort2;
- ioaddr_t NumPorts2;
- u_int Attributes2;
- u_int IOAddrLines;
-} config_info_t;
-
-/* For ValidateCIS */
-typedef struct cisinfo_t {
- u_int Chains;
-} cisinfo_t;
-
-typedef struct cs_status_t {
- u_char Function;
- event_t CardState;
- event_t SocketState;
-} cs_status_t;
-
-typedef union ds_ioctl_arg_t {
- adjust_t adjust;
- config_info_t config;
- tuple_t tuple;
- tuple_parse_t tuple_parse;
- client_req_t client_req;
- cs_status_t status;
- conf_reg_t conf_reg;
- cisinfo_t cisinfo;
- region_info_t region;
- bind_info_t bind_info;
- mtd_info_t mtd_info;
- win_info_t win_info;
- cisdump_t cisdump;
-} ds_ioctl_arg_t;
-
-#define DS_ADJUST_RESOURCE_INFO _IOWR('d', 2, adjust_t)
-#define DS_GET_CONFIGURATION_INFO _IOWR('d', 3, config_info_t)
-#define DS_GET_FIRST_TUPLE _IOWR('d', 4, tuple_t)
-#define DS_GET_NEXT_TUPLE _IOWR('d', 5, tuple_t)
-#define DS_GET_TUPLE_DATA _IOWR('d', 6, tuple_parse_t)
-#define DS_PARSE_TUPLE _IOWR('d', 7, tuple_parse_t)
-#define DS_RESET_CARD _IO ('d', 8)
-#define DS_GET_STATUS _IOWR('d', 9, cs_status_t)
-#define DS_ACCESS_CONFIGURATION_REGISTER _IOWR('d', 10, conf_reg_t)
-#define DS_VALIDATE_CIS _IOR ('d', 11, cisinfo_t)
-#define DS_SUSPEND_CARD _IO ('d', 12)
-#define DS_RESUME_CARD _IO ('d', 13)
-#define DS_EJECT_CARD _IO ('d', 14)
-#define DS_INSERT_CARD _IO ('d', 15)
-#define DS_GET_FIRST_REGION _IOWR('d', 16, region_info_t)
-#define DS_GET_NEXT_REGION _IOWR('d', 17, region_info_t)
-#define DS_REPLACE_CIS _IOWR('d', 18, cisdump_t)
-#define DS_GET_FIRST_WINDOW _IOR ('d', 19, win_info_t)
-#define DS_GET_NEXT_WINDOW _IOWR('d', 20, win_info_t)
-#define DS_GET_MEM_PAGE _IOWR('d', 21, win_info_t)
-
-#define DS_BIND_REQUEST _IOWR('d', 60, bind_info_t)
-#define DS_GET_DEVICE_INFO _IOWR('d', 61, bind_info_t)
-#define DS_GET_NEXT_DEVICE _IOWR('d', 62, bind_info_t)
-#define DS_UNBIND_REQUEST _IOW ('d', 63, bind_info_t)
-#define DS_BIND_MTD _IOWR('d', 64, mtd_info_t)
-
-
-/* used in userspace only */
-#define CS_IN_USE 0x1e
-
-#define INFO_MASTER_CLIENT 0x01
-#define INFO_IO_CLIENT 0x02
-#define INFO_MTD_CLIENT 0x04
-#define INFO_MEM_CLIENT 0x08
-#define MAX_NUM_CLIENTS 3
-
-#define INFO_CARD_SHARE 0x10
-#define INFO_CARD_EXCL 0x20
-
-
-#endif /* !defined(__KERNEL__) || defined(CONFIG_PCMCIA_IOCTL) */
+#endif /* __KERNEL__ */
#endif /* _LINUX_DS_H */
diff --git a/include/pcmcia/ss.h b/include/pcmcia/ss.h
index 764281b2921..626b63c33d9 100644
--- a/include/pcmcia/ss.h
+++ b/include/pcmcia/ss.h
@@ -19,7 +19,6 @@
#include <linux/sched.h> /* task_struct, completion */
#include <linux/mutex.h>
-#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#ifdef CONFIG_CARDBUS
#include <linux/pci.h>
@@ -162,17 +161,10 @@ struct pcmcia_socket {
u_int pci_irq;
struct pci_dev *cb_dev;
-
/* socket setup is done so resources should be able to be allocated.
* Only if set to 1, calls to find_{io,mem}_region are handled, and
* insertio events are actually managed by the PCMCIA layer.*/
- u8 resource_setup_done:1;
-
- /* It's old if resource setup is done using adjust_resource_info() */
- u8 resource_setup_old:1;
- u8 resource_setup_new:1;
-
- u8 reserved:5;
+ u8 resource_setup_done;
/* socket operations */
struct pccard_operations *ops;
@@ -218,15 +210,8 @@ struct pcmcia_socket {
* incorrectness and change */
u8 device_count;
- /* 16-bit state: */
- struct {
- /* "master" ioctl is used */
- u8 busy:1;
- /* the PCMCIA card consists of two pseudo devices */
- u8 has_pfc:1;
-
- u8 reserved:6;
- } pcmcia_state;
+ /* does the PCMCIA card consist of two pseudo devices? */
+ u8 pcmcia_pfc;
/* non-zero if PCMCIA card is present */
atomic_t present;
@@ -234,10 +219,6 @@ struct pcmcia_socket {
/* IRQ to be used by PCMCIA devices. May not be IRQ 0. */
unsigned int pcmcia_irq;
-#ifdef CONFIG_PCMCIA_IOCTL
- struct user_info_t *user;
- wait_queue_head_t queue;
-#endif /* CONFIG_PCMCIA_IOCTL */
#endif /* CONFIG_PCMCIA */
/* socket device */
diff --git a/include/rdma/ib_verbs.h b/include/rdma/ib_verbs.h
index f3e8f3c0772..857b3b9cf12 100644
--- a/include/rdma/ib_verbs.h
+++ b/include/rdma/ib_verbs.h
@@ -555,7 +555,7 @@ enum ib_qp_type {
IB_QPT_UC,
IB_QPT_UD,
IB_QPT_RAW_IPV6,
- IB_QPT_RAW_ETY
+ IB_QPT_RAW_ETHERTYPE
};
enum ib_qp_create_flags {
diff --git a/include/rxrpc/packet.h b/include/rxrpc/packet.h
index b69e6e173ea..9b2c30897e5 100644
--- a/include/rxrpc/packet.h
+++ b/include/rxrpc/packet.h
@@ -65,7 +65,7 @@ struct rxrpc_header {
};
__be16 serviceId; /* service ID */
-} __attribute__((packed));
+} __packed;
#define __rxrpc_header_off(X) offsetof(struct rxrpc_header,X)
@@ -120,7 +120,7 @@ struct rxrpc_ackpacket {
#define RXRPC_ACK_TYPE_NACK 0
#define RXRPC_ACK_TYPE_ACK 1
-} __attribute__((packed));
+} __packed;
/*
* ACK packets can have a further piece of information tagged on the end
@@ -141,7 +141,7 @@ struct rxkad_challenge {
__be32 nonce; /* encrypted random number */
__be32 min_level; /* minimum security level */
__be32 __padding; /* padding to 8-byte boundary */
-} __attribute__((packed));
+} __packed;
/*****************************************************************************/
/*
@@ -164,7 +164,7 @@ struct rxkad_response {
__be32 kvno; /* Kerberos key version number */
__be32 ticket_len; /* Kerberos ticket length */
-} __attribute__((packed));
+} __packed;
/*****************************************************************************/
/*
diff --git a/include/scsi/fc/fc_els.h b/include/scsi/fc/fc_els.h
index f94328132a2..481abbd48e3 100644
--- a/include/scsi/fc/fc_els.h
+++ b/include/scsi/fc/fc_els.h
@@ -191,6 +191,7 @@ enum fc_els_rjt_reason {
ELS_RJT_UNAB = 0x09, /* unable to perform command request */
ELS_RJT_UNSUP = 0x0b, /* command not supported */
ELS_RJT_INPROG = 0x0e, /* command already in progress */
+ ELS_RJT_FIP = 0x20, /* FIP error */
ELS_RJT_VENDOR = 0xff, /* vendor specific error */
};
@@ -212,6 +213,7 @@ enum fc_els_rjt_explan {
ELS_EXPL_UNAB_DATA = 0x2a, /* unable to supply requested data */
ELS_EXPL_UNSUPR = 0x2c, /* Request not supported */
ELS_EXPL_INV_LEN = 0x2d, /* Invalid payload length */
+ ELS_EXPL_NOT_NEIGHBOR = 0x62, /* VN2VN_Port not in neighbor set */
/* TBD - above definitions incomplete */
};
@@ -405,6 +407,15 @@ struct fc_els_prli {
};
/*
+ * ELS_PRLO - Process logout request and response.
+ */
+struct fc_els_prlo {
+ __u8 prlo_cmd; /* command */
+ __u8 prlo_obs; /* obsolete, but shall be set to 10h */
+ __be16 prlo_len; /* payload length */
+};
+
+/*
* ELS_ADISC payload
*/
struct fc_els_adisc {
diff --git a/include/scsi/fc/fc_fcoe.h b/include/scsi/fc/fc_fcoe.h
index e6ad3d2ae47..d5dcd606281 100644
--- a/include/scsi/fc/fc_fcoe.h
+++ b/include/scsi/fc/fc_fcoe.h
@@ -22,23 +22,18 @@
/*
* FCoE - Fibre Channel over Ethernet.
+ * See T11 FC-BB-5 Rev 2.00 (09-056v5.pdf)
*/
/*
- * FC_FCOE_OUI hasn't been standardized yet. XXX TBD.
+ * Default FC_FCOE_OUI / FC-MAP value.
*/
-#ifndef FC_FCOE_OUI
-#define FC_FCOE_OUI 0x0efc00 /* upper 24 bits of FCOE dest MAC TBD */
-#endif
+#define FC_FCOE_OUI 0x0efc00 /* upper 24 bits of FCOE MAC */
/*
- * The destination MAC address for the fabric login may get a different OUI.
- * This isn't standardized yet.
+ * Fabric Login (FLOGI) MAC for non-FIP use. Non-FIP use is deprecated.
*/
-#ifndef FC_FCOE_FLOGI_MAC
-/* gateway MAC - TBD */
#define FC_FCOE_FLOGI_MAC { 0x0e, 0xfc, 0x00, 0xff, 0xff, 0xfe }
-#endif
#define FC_FCOE_VER 0 /* version */
@@ -51,8 +46,6 @@
/*
* FCoE frame header - 14 bytes
- *
- * This is the August 2007 version of the FCoE header as defined by T11.
* This follows the VLAN header, which includes the ethertype.
*/
struct fcoe_hdr {
diff --git a/include/scsi/fc/fc_fip.h b/include/scsi/fc/fc_fip.h
index 17baa19380f..ae25d4ab254 100644
--- a/include/scsi/fc/fc_fip.h
+++ b/include/scsi/fc/fc_fip.h
@@ -17,9 +17,12 @@
#ifndef _FC_FIP_H_
#define _FC_FIP_H_
+#include <scsi/fc/fc_ns.h>
+
/*
* This version is based on:
* http://www.t11.org/ftp/t11/pub/fc/bb-5/08-543v1.pdf
+ * and T11 FC-BB-6 10-019v4.pdf (June 2010 VN2VN proposal)
*/
#define FIP_DEF_PRI 128 /* default selection priority */
@@ -29,11 +32,24 @@
#define FIP_FCF_FUZZ 100 /* random time added by FCF (mS) */
/*
+ * VN2VN proposed-standard values.
+ */
+#define FIP_VN_FC_MAP 0x0efd00 /* MAC OUI for VN2VN use */
+#define FIP_VN_PROBE_WAIT 100 /* interval between VN2VN probes (ms) */
+#define FIP_VN_ANN_WAIT 400 /* interval between VN2VN announcements (ms) */
+#define FIP_VN_RLIM_INT 10000 /* interval between probes when rate limited */
+#define FIP_VN_RLIM_COUNT 10 /* number of probes before rate limiting */
+#define FIP_VN_BEACON_INT 8000 /* interval between VN2VN beacons */
+#define FIP_VN_BEACON_FUZZ 100 /* random time to add to beacon period (ms) */
+
+/*
* Multicast MAC addresses. T11-adopted.
*/
-#define FIP_ALL_FCOE_MACS ((u8[6]) { 1, 0x10, 0x18, 1, 0, 0 })
-#define FIP_ALL_ENODE_MACS ((u8[6]) { 1, 0x10, 0x18, 1, 0, 1 })
-#define FIP_ALL_FCF_MACS ((u8[6]) { 1, 0x10, 0x18, 1, 0, 2 })
+#define FIP_ALL_FCOE_MACS ((__u8[6]) { 1, 0x10, 0x18, 1, 0, 0 })
+#define FIP_ALL_ENODE_MACS ((__u8[6]) { 1, 0x10, 0x18, 1, 0, 1 })
+#define FIP_ALL_FCF_MACS ((__u8[6]) { 1, 0x10, 0x18, 1, 0, 2 })
+#define FIP_ALL_VN2VN_MACS ((__u8[6]) { 1, 0x10, 0x18, 1, 0, 4 })
+#define FIP_ALL_P2P_MACS ((__u8[6]) { 1, 0x10, 0x18, 1, 0, 5 })
#define FIP_VER 1 /* version for fip_header */
@@ -60,6 +76,7 @@ enum fip_opcode {
FIP_OP_LS = 2, /* Link Service request or reply */
FIP_OP_CTRL = 3, /* Keep Alive / Link Reset */
FIP_OP_VLAN = 4, /* VLAN discovery */
+ FIP_OP_VN2VN = 5, /* VN2VN operation */
FIP_OP_VENDOR_MIN = 0xfff8, /* min vendor-specific opcode */
FIP_OP_VENDOR_MAX = 0xfffe, /* max vendor-specific opcode */
};
@@ -97,11 +114,23 @@ enum fip_vlan_subcode {
};
/*
+ * Subcodes for FIP_OP_VN2VN.
+ */
+enum fip_vn2vn_subcode {
+ FIP_SC_VN_PROBE_REQ = 1, /* probe request */
+ FIP_SC_VN_PROBE_REP = 2, /* probe reply */
+ FIP_SC_VN_CLAIM_NOTIFY = 3, /* claim notification */
+ FIP_SC_VN_CLAIM_REP = 4, /* claim response */
+ FIP_SC_VN_BEACON = 5, /* beacon */
+};
+
+/*
* flags in header fip_flags.
*/
enum fip_flag {
FIP_FL_FPMA = 0x8000, /* supports FPMA fabric-provided MACs */
FIP_FL_SPMA = 0x4000, /* supports SPMA server-provided MACs */
+ FIP_FL_REC_OR_P2P = 0x0008, /* configured addr or point-to-point */
FIP_FL_AVAIL = 0x0004, /* available for FLOGI/ELP */
FIP_FL_SOL = 0x0002, /* this is a solicited message */
FIP_FL_FPORT = 0x0001, /* sent from an F port */
@@ -130,6 +159,7 @@ enum fip_desc_type {
FIP_DT_FKA = 12, /* advertisement keep-alive period */
FIP_DT_VENDOR = 13, /* vendor ID */
FIP_DT_VLAN = 14, /* vlan number */
+ FIP_DT_FC4F = 15, /* FC-4 features */
FIP_DT_LIMIT, /* max defined desc_type + 1 */
FIP_DT_VENDOR_BASE = 128, /* first vendor-specific desc_type */
};
@@ -229,6 +259,16 @@ enum fip_fka_flags {
/* FIP_DT_FKA flags */
/*
+ * FIP_DT_FC4F - FC-4 features.
+ */
+struct fip_fc4_feat {
+ struct fip_desc fd_desc;
+ __u8 fd_resvd[2];
+ struct fc_ns_fts fd_fts;
+ struct fc_ns_ff fd_ff;
+} __attribute__((packed));
+
+/*
* FIP_DT_VENDOR descriptor.
*/
struct fip_vendor_desc {
diff --git a/include/scsi/fc/fc_ns.h b/include/scsi/fc/fc_ns.h
index e7d3ac497d7..185015dd116 100644
--- a/include/scsi/fc/fc_ns.h
+++ b/include/scsi/fc/fc_ns.h
@@ -100,6 +100,13 @@ struct fc_ns_fts {
};
/*
+ * FC4-features object.
+ */
+struct fc_ns_ff {
+ __be32 fd_feat[FC_NS_TYPES * 4 / FC_NS_BPW]; /* 4-bits per FC-type */
+};
+
+/*
* GID_PT request.
*/
struct fc_ns_gid_pt {
diff --git a/include/scsi/fc_encode.h b/include/scsi/fc_encode.h
index 9b4867c9c2d..6d293c846a4 100644
--- a/include/scsi/fc_encode.h
+++ b/include/scsi/fc_encode.h
@@ -21,6 +21,13 @@
#define _FC_ENCODE_H_
#include <asm/unaligned.h>
+/*
+ * F_CTL values for simple requests and responses.
+ */
+#define FC_FCTL_REQ (FC_FC_FIRST_SEQ | FC_FC_END_SEQ | FC_FC_SEQ_INIT)
+#define FC_FCTL_RESP (FC_FC_EX_CTX | FC_FC_LAST_SEQ | \
+ FC_FC_END_SEQ | FC_FC_SEQ_INIT)
+
struct fc_ns_rft {
struct fc_ns_fid fid; /* port ID object */
struct fc_ns_fts fts; /* FC4-types object */
diff --git a/include/scsi/fc_frame.h b/include/scsi/fc_frame.h
index 4d3e9c7b7c5..4ad02041b66 100644
--- a/include/scsi/fc_frame.h
+++ b/include/scsi/fc_frame.h
@@ -30,6 +30,23 @@
#include <linux/if_ether.h>
+/* some helpful macros */
+
+#define ntohll(x) be64_to_cpu(x)
+#define htonll(x) cpu_to_be64(x)
+
+static inline u32 ntoh24(const u8 *p)
+{
+ return (p[0] << 16) | (p[1] << 8) | p[2];
+}
+
+static inline void hton24(u8 *p, u32 v)
+{
+ p[0] = (v >> 16) & 0xff;
+ p[1] = (v >> 8) & 0xff;
+ p[2] = v & 0xff;
+}
+
/*
* The fc_frame interface is used to pass frame data between functions.
* The frame includes the data buffer, length, and SOF / EOF delimiter types.
@@ -51,6 +68,7 @@
#define fr_sof(fp) (fr_cb(fp)->fr_sof)
#define fr_eof(fp) (fr_cb(fp)->fr_eof)
#define fr_flags(fp) (fr_cb(fp)->fr_flags)
+#define fr_encaps(fp) (fr_cb(fp)->fr_encaps)
#define fr_max_payload(fp) (fr_cb(fp)->fr_max_payload)
#define fr_fsp(fp) (fr_cb(fp)->fr_fsp)
#define fr_crc(fp) (fr_cb(fp)->fr_crc)
@@ -66,9 +84,10 @@ struct fcoe_rcv_info {
struct fc_fcp_pkt *fr_fsp; /* for the corresponding fcp I/O */
u32 fr_crc;
u16 fr_max_payload; /* max FC payload */
- enum fc_sof fr_sof; /* start of frame delimiter */
- enum fc_eof fr_eof; /* end of frame delimiter */
+ u8 fr_sof; /* start of frame delimiter */
+ u8 fr_eof; /* end of frame delimiter */
u8 fr_flags; /* flags - see below */
+ u8 fr_encaps; /* LLD encapsulation info (e.g. FIP) */
u8 granted_mac[ETH_ALEN]; /* FCoE MAC address */
};
@@ -97,6 +116,7 @@ static inline void fc_frame_init(struct fc_frame *fp)
fr_dev(fp) = NULL;
fr_seq(fp) = NULL;
fr_flags(fp) = 0;
+ fr_encaps(fp) = 0;
}
struct fc_frame *fc_frame_alloc_fill(struct fc_lport *, size_t payload_len);
@@ -136,13 +156,39 @@ static inline int fc_frame_is_linear(struct fc_frame *fp)
/*
* Get frame header from message in fc_frame structure.
+ * This version doesn't do a length check.
+ */
+static inline
+struct fc_frame_header *__fc_frame_header_get(const struct fc_frame *fp)
+{
+ return (struct fc_frame_header *)fr_hdr(fp);
+}
+
+/*
+ * Get frame header from message in fc_frame structure.
* This hides a cast and provides a place to add some checking.
*/
static inline
struct fc_frame_header *fc_frame_header_get(const struct fc_frame *fp)
{
WARN_ON(fr_len(fp) < sizeof(struct fc_frame_header));
- return (struct fc_frame_header *) fr_hdr(fp);
+ return __fc_frame_header_get(fp);
+}
+
+/*
+ * Get source FC_ID (S_ID) from frame header in message.
+ */
+static inline u32 fc_frame_sid(const struct fc_frame *fp)
+{
+ return ntoh24(__fc_frame_header_get(fp)->fh_s_id);
+}
+
+/*
+ * Get destination FC_ID (D_ID) from frame header in message.
+ */
+static inline u32 fc_frame_did(const struct fc_frame *fp)
+{
+ return ntoh24(__fc_frame_header_get(fp)->fh_d_id);
}
/*
diff --git a/include/scsi/iscsi_if.h b/include/scsi/iscsi_if.h
index 66d377b9c72..a8631acd37c 100644
--- a/include/scsi/iscsi_if.h
+++ b/include/scsi/iscsi_if.h
@@ -313,6 +313,7 @@ enum iscsi_param {
ISCSI_PARAM_INITIATOR_NAME,
ISCSI_PARAM_TGT_RESET_TMO,
+ ISCSI_PARAM_TARGET_ALIAS,
/* must always be last */
ISCSI_PARAM_MAX,
};
@@ -353,6 +354,7 @@ enum iscsi_param {
#define ISCSI_ISID (1ULL << ISCSI_PARAM_ISID)
#define ISCSI_INITIATOR_NAME (1ULL << ISCSI_PARAM_INITIATOR_NAME)
#define ISCSI_TGT_RESET_TMO (1ULL << ISCSI_PARAM_TGT_RESET_TMO)
+#define ISCSI_TARGET_ALIAS (1ULL << ISCSI_PARAM_TARGET_ALIAS)
/* iSCSI HBA params */
enum iscsi_host_param {
diff --git a/include/scsi/libfc.h b/include/scsi/libfc.h
index 7495c0ba67e..14be49b44e8 100644
--- a/include/scsi/libfc.h
+++ b/include/scsi/libfc.h
@@ -42,24 +42,6 @@
#define FC_EX_TIMEOUT 1 /* Exchange timeout */
#define FC_EX_CLOSED 2 /* Exchange closed */
-/* some helpful macros */
-
-#define ntohll(x) be64_to_cpu(x)
-#define htonll(x) cpu_to_be64(x)
-
-
-static inline u32 ntoh24(const u8 *p)
-{
- return (p[0] << 16) | (p[1] << 8) | p[2];
-}
-
-static inline void hton24(u8 *p, u32 v)
-{
- p[0] = (v >> 16) & 0xff;
- p[1] = (v >> 8) & 0xff;
- p[2] = v & 0xff;
-}
-
/**
* enum fc_lport_state - Local port states
* @LPORT_ST_DISABLED: Disabled
@@ -97,25 +79,25 @@ enum fc_disc_event {
/**
* enum fc_rport_state - Remote port states
* @RPORT_ST_INIT: Initialized
+ * @RPORT_ST_FLOGI: Waiting for FLOGI completion for point-to-multipoint
+ * @RPORT_ST_PLOGI_WAIT: Waiting for peer to login for point-to-multipoint
* @RPORT_ST_PLOGI: Waiting for PLOGI completion
* @RPORT_ST_PRLI: Waiting for PRLI completion
* @RPORT_ST_RTV: Waiting for RTV completion
* @RPORT_ST_READY: Ready for use
- * @RPORT_ST_LOGO: Remote port logout (LOGO) sent
* @RPORT_ST_ADISC: Discover Address sent
* @RPORT_ST_DELETE: Remote port being deleted
- * @RPORT_ST_RESTART: Remote port being deleted and will restart
*/
enum fc_rport_state {
RPORT_ST_INIT,
+ RPORT_ST_FLOGI,
+ RPORT_ST_PLOGI_WAIT,
RPORT_ST_PLOGI,
RPORT_ST_PRLI,
RPORT_ST_RTV,
RPORT_ST_READY,
- RPORT_ST_LOGO,
RPORT_ST_ADISC,
RPORT_ST_DELETE,
- RPORT_ST_RESTART,
};
/**
@@ -173,6 +155,7 @@ struct fc_rport_libfc_priv {
u16 flags;
#define FC_RP_FLAGS_REC_SUPPORTED (1 << 0)
#define FC_RP_FLAGS_RETRY (1 << 1)
+ #define FC_RP_STARTED (1 << 2)
unsigned int e_d_tov;
unsigned int r_a_tov;
};
@@ -185,16 +168,18 @@ struct fc_rport_libfc_priv {
* @rp_state: Enumeration that tracks progress of PLOGI, PRLI,
* and RTV exchanges
* @ids: The remote port identifiers and roles
- * @flags: REC and RETRY supported flags
+ * @flags: STARTED, REC and RETRY_SUPPORTED flags
* @max_seq: Maximum number of concurrent sequences
* @disc_id: The discovery identifier
* @maxframe_size: The maximum frame size
* @retries: The retry count for the current state
+ * @major_retries: The retry count for the entire PLOGI/PRLI state machine
* @e_d_tov: Error detect timeout value (in msec)
* @r_a_tov: Resource allocation timeout value (in msec)
* @rp_mutex: The mutex that protects the remote port
* @retry_work: Handle for retries
* @event_callback: Callback when READY, FAILED or LOGO states complete
+ * @rcu: Structure used for freeing in an RCU-safe manner
*/
struct fc_rport_priv {
struct fc_lport *local_port;
@@ -207,6 +192,7 @@ struct fc_rport_priv {
u16 disc_id;
u16 maxframe_size;
unsigned int retries;
+ unsigned int major_retries;
unsigned int e_d_tov;
unsigned int r_a_tov;
struct mutex rp_mutex;
@@ -216,6 +202,7 @@ struct fc_rport_priv {
struct list_head peers;
struct work_struct event_work;
u32 supported_classes;
+ struct rcu_head rcu;
};
/**
@@ -262,14 +249,12 @@ struct fcoe_dev_stats {
/**
* struct fc_seq_els_data - ELS data used for passing ELS specific responses
- * @fp: The ELS frame
* @reason: The reason for rejection
* @explan: The explaination of the rejection
*
* Mainly used by the exchange manager layer.
*/
struct fc_seq_els_data {
- struct fc_frame *fp;
enum fc_els_rjt_reason reason;
enum fc_els_rjt_explan explan;
};
@@ -405,6 +390,7 @@ struct fc_seq {
* @esb_stat: ESB exchange status
* @r_a_tov: Resouce allocation time out value (in msecs)
* @seq_id: The next sequence ID to use
+ * @encaps: encapsulation information for lower-level driver
* @f_ctl: F_CTL flags for the sequence
* @fh_type: The frame type
* @class: The class of service
@@ -436,6 +422,7 @@ struct fc_exch {
u32 esb_stat;
u32 r_a_tov;
u8 seq_id;
+ u8 encaps;
u32 f_ctl;
u8 fh_type;
enum fc_class class;
@@ -530,12 +517,11 @@ struct libfc_function_template {
struct fc_frame *);
/*
- * Send an ELS response using infomation from a previous
- * exchange and sequence.
+ * Send an ELS response using infomation from the received frame.
*
* STATUS: OPTIONAL
*/
- void (*seq_els_rsp_send)(struct fc_seq *, enum fc_els_cmd,
+ void (*seq_els_rsp_send)(struct fc_frame *, enum fc_els_cmd,
struct fc_seq_els_data *);
/*
@@ -567,6 +553,13 @@ struct libfc_function_template {
struct fc_seq *(*seq_start_next)(struct fc_seq *);
/*
+ * Assign a sequence for an incoming request frame.
+ *
+ * STATUS: OPTIONAL
+ */
+ struct fc_seq *(*seq_assign)(struct fc_lport *, struct fc_frame *);
+
+ /*
* Reset an exchange manager, completing all sequences and exchanges.
* If s_id is non-zero, reset only exchanges originating from that FID.
* If d_id is non-zero, reset only exchanges sending to that FID.
@@ -587,8 +580,7 @@ struct libfc_function_template {
*
* STATUS: OPTIONAL
*/
- void (*lport_recv)(struct fc_lport *, struct fc_seq *,
- struct fc_frame *);
+ void (*lport_recv)(struct fc_lport *, struct fc_frame *);
/*
* Reset the local port.
@@ -650,8 +642,7 @@ struct libfc_function_template {
*
* STATUS: OPTIONAL
*/
- void (*rport_recv_req)(struct fc_seq *, struct fc_frame *,
- struct fc_lport *);
+ void (*rport_recv_req)(struct fc_lport *, struct fc_frame *);
/*
* lookup an rport by it's port ID.
@@ -697,8 +688,7 @@ struct libfc_function_template {
*
* STATUS: OPTIONAL
*/
- void (*disc_recv_req)(struct fc_seq *, struct fc_frame *,
- struct fc_lport *);
+ void (*disc_recv_req)(struct fc_lport *, struct fc_frame *);
/*
* Start discovery for a local port.
@@ -736,7 +726,7 @@ struct libfc_function_template {
* @buf_len: Length of the discovery buffer
* @disc_id: Discovery ID
* @rports: List of discovered remote ports
- * @lport: The local port that discovery is for
+ * @priv: Private pointer for use by discovery code
* @disc_mutex: Mutex that protects the discovery context
* @partial_buf: Partial name buffer (if names are returned
* in multiple frames)
@@ -752,7 +742,7 @@ struct fc_disc {
u16 disc_id;
struct list_head rports;
- struct fc_lport *lport;
+ void *priv;
struct mutex disc_mutex;
struct fc_gpn_ft_resp partial_buf;
struct delayed_work disc_work;
@@ -796,6 +786,7 @@ struct fc_disc {
* @mfs: The maximum Fibre Channel payload size
* @max_retry_count: The maximum retry attempts
* @max_rport_retry_count: The maximum remote port retry attempts
+ * @rport_priv_size: Size needed by driver after struct fc_rport_priv
* @lro_xid: The maximum XID for LRO
* @lso_max: The maximum large offload send size
* @fcts: FC-4 type mask
@@ -842,9 +833,11 @@ struct fc_lport {
u32 lro_enabled:1;
u32 does_npiv:1;
u32 npiv_enabled:1;
+ u32 point_to_multipoint:1;
u32 mfs;
u8 max_retry_count;
u8 max_rport_retry_count;
+ u16 rport_priv_size;
u16 link_speed;
u16 link_supported_speeds;
u16 lro_xid;
@@ -986,6 +979,7 @@ int fc_set_mfs(struct fc_lport *, u32 mfs);
struct fc_lport *libfc_vport_create(struct fc_vport *, int privsize);
struct fc_lport *fc_vport_id_lookup(struct fc_lport *, u32 port_id);
int fc_lport_bsg_request(struct fc_bsg_job *);
+void fc_lport_set_local_id(struct fc_lport *, u32 port_id);
/*
* REMOTE PORT LAYER
@@ -998,6 +992,11 @@ void fc_rport_terminate_io(struct fc_rport *);
*****************************/
int fc_disc_init(struct fc_lport *);
+static inline struct fc_lport *fc_disc_lport(struct fc_disc *disc)
+{
+ return container_of(disc, struct fc_lport, disc);
+}
+
/*
* FCP LAYER
*****************************/
@@ -1029,6 +1028,10 @@ struct fc_seq *fc_elsct_send(struct fc_lport *, u32 did,
void *arg, u32 timer_msec);
void fc_lport_flogi_resp(struct fc_seq *, struct fc_frame *, void *);
void fc_lport_logo_resp(struct fc_seq *, struct fc_frame *, void *);
+void fc_fill_reply_hdr(struct fc_frame *, const struct fc_frame *,
+ enum fc_rctl, u32 parm_offset);
+void fc_fill_hdr(struct fc_frame *, const struct fc_frame *,
+ enum fc_rctl, u32 f_ctl, u16 seq_cnt, u32 parm_offset);
/*
diff --git a/include/scsi/libfcoe.h b/include/scsi/libfcoe.h
index ec13f51531f..06f1b5a8ed1 100644
--- a/include/scsi/libfcoe.h
+++ b/include/scsi/libfcoe.h
@@ -26,6 +26,7 @@
#include <linux/netdevice.h>
#include <linux/skbuff.h>
#include <linux/workqueue.h>
+#include <linux/random.h>
#include <scsi/fc/fc_fcoe.h>
#include <scsi/libfc.h>
@@ -37,6 +38,7 @@
#define FCOE_CTLR_START_DELAY 2000 /* mS after first adv. to choose FCF */
#define FCOE_CTRL_SOL_TOV 2000 /* min. solicitation interval (mS) */
#define FCOE_CTLR_FCF_LIMIT 20 /* max. number of FCF entries */
+#define FCOE_CTLR_VN2VN_LOGIN_LIMIT 3 /* max. VN2VN rport login retries */
/**
* enum fip_state - internal state of FCoE controller.
@@ -45,6 +47,11 @@
* @FIP_ST_AUTO: determining whether to use FIP or non-FIP mode.
* @FIP_ST_NON_FIP: non-FIP mode selected.
* @FIP_ST_ENABLED: FIP mode selected.
+ * @FIP_ST_VNMP_START: VN2VN multipath mode start, wait
+ * @FIP_ST_VNMP_PROBE1: VN2VN sent first probe, listening
+ * @FIP_ST_VNMP_PROBE2: VN2VN sent second probe, listening
+ * @FIP_ST_VNMP_CLAIM: VN2VN sent claim, waiting for responses
+ * @FIP_ST_VNMP_UP: VN2VN multipath mode operation
*/
enum fip_state {
FIP_ST_DISABLED,
@@ -52,8 +59,23 @@ enum fip_state {
FIP_ST_AUTO,
FIP_ST_NON_FIP,
FIP_ST_ENABLED,
+ FIP_ST_VNMP_START,
+ FIP_ST_VNMP_PROBE1,
+ FIP_ST_VNMP_PROBE2,
+ FIP_ST_VNMP_CLAIM,
+ FIP_ST_VNMP_UP,
};
+/*
+ * Modes:
+ * The mode is the state that is to be entered after link up.
+ * It must not change after fcoe_ctlr_init() sets it.
+ */
+#define FIP_MODE_AUTO FIP_ST_AUTO
+#define FIP_MODE_NON_FIP FIP_ST_NON_FIP
+#define FIP_MODE_FABRIC FIP_ST_ENABLED
+#define FIP_MODE_VN2VN FIP_ST_VNMP_START
+
/**
* struct fcoe_ctlr - FCoE Controller and FIP state
* @state: internal FIP state for network link and FIP or non-FIP mode.
@@ -70,19 +92,20 @@ enum fip_state {
* @timer_work: &work_struct for doing keep-alives and resets.
* @recv_work: &work_struct for receiving FIP frames.
* @fip_recv_list: list of received FIP frames.
+ * @rnd_state: state for pseudo-random number generator.
+ * @port_id: proposed or selected local-port ID.
* @user_mfs: configured maximum FC frame size, including FC header.
* @flogi_oxid: exchange ID of most recent fabric login.
* @flogi_count: number of FLOGI attempts in AUTO mode.
* @map_dest: use the FC_MAP mode for destination MAC addresses.
* @spma: supports SPMA server-provided MACs mode
- * @send_ctlr_ka: need to send controller keep alive
- * @send_port_ka: need to send port keep alives
+ * @probe_tries: number of FC_IDs probed
* @dest_addr: MAC address of the selected FC forwarder.
* @ctl_src_addr: the native MAC address of our local port.
* @send: LLD-supplied function to handle sending FIP Ethernet frames
* @update_mac: LLD-supplied function to handle changes to MAC addresses.
* @get_src_addr: LLD-supplied function to supply a source MAC address.
- * @lock: lock protecting this structure.
+ * @ctlr_mutex: lock protecting this structure.
*
* This structure is used by all FCoE drivers. It contains information
* needed by all FCoE low-level drivers (LLDs) as well as internal state
@@ -103,21 +126,23 @@ struct fcoe_ctlr {
struct work_struct timer_work;
struct work_struct recv_work;
struct sk_buff_head fip_recv_list;
+
+ struct rnd_state rnd_state;
+ u32 port_id;
+
u16 user_mfs;
u16 flogi_oxid;
u8 flogi_count;
- u8 reset_req;
u8 map_dest;
u8 spma;
- u8 send_ctlr_ka;
- u8 send_port_ka;
+ u8 probe_tries;
u8 dest_addr[ETH_ALEN];
u8 ctl_src_addr[ETH_ALEN];
void (*send)(struct fcoe_ctlr *, struct sk_buff *);
void (*update_mac)(struct fc_lport *, u8 *addr);
u8 * (*get_src_addr)(struct fc_lport *);
- spinlock_t lock;
+ struct mutex ctlr_mutex;
};
/**
@@ -156,8 +181,26 @@ struct fcoe_fcf {
u8 fd_flags:1;
};
+/**
+ * struct fcoe_rport - VN2VN remote port
+ * @time: time of create or last beacon packet received from node
+ * @fcoe_len: max FCoE frame size, not including VLAN or Ethernet headers
+ * @flags: flags from probe or claim
+ * @login_count: number of unsuccessful rport logins to this port
+ * @enode_mac: E_Node control MAC address
+ * @vn_mac: VN_Node assigned MAC address for data
+ */
+struct fcoe_rport {
+ unsigned long time;
+ u16 fcoe_len;
+ u16 flags;
+ u8 login_count;
+ u8 enode_mac[ETH_ALEN];
+ u8 vn_mac[ETH_ALEN];
+};
+
/* FIP API functions */
-void fcoe_ctlr_init(struct fcoe_ctlr *);
+void fcoe_ctlr_init(struct fcoe_ctlr *, enum fip_state);
void fcoe_ctlr_destroy(struct fcoe_ctlr *);
void fcoe_ctlr_link_up(struct fcoe_ctlr *);
int fcoe_ctlr_link_down(struct fcoe_ctlr *);
@@ -168,6 +211,17 @@ int fcoe_ctlr_recv_flogi(struct fcoe_ctlr *, struct fc_lport *,
/* libfcoe funcs */
u64 fcoe_wwn_from_mac(unsigned char mac[], unsigned int, unsigned int);
-int fcoe_libfc_config(struct fc_lport *, struct libfc_function_template *);
+int fcoe_libfc_config(struct fc_lport *, struct fcoe_ctlr *,
+ const struct libfc_function_template *, int init_fcp);
+
+/**
+ * is_fip_mode() - returns true if FIP mode selected.
+ * @fip: FCoE controller.
+ */
+static inline bool is_fip_mode(struct fcoe_ctlr *fip)
+{
+ return fip->state == FIP_ST_ENABLED;
+}
+
#endif /* _LIBFCOE_H */
diff --git a/include/scsi/libsas.h b/include/scsi/libsas.h
index 3b586859669..d06e13be717 100644
--- a/include/scsi/libsas.h
+++ b/include/scsi/libsas.h
@@ -422,16 +422,7 @@ enum service_response {
};
enum exec_status {
- SAM_GOOD = 0,
- SAM_CHECK_COND = 2,
- SAM_COND_MET = 4,
- SAM_BUSY = 8,
- SAM_INTERMEDIATE = 0x10,
- SAM_IM_COND_MET = 0x12,
- SAM_RESV_CONFLICT= 0x14,
- SAM_TASK_SET_FULL= 0x28,
- SAM_ACA_ACTIVE = 0x30,
- SAM_TASK_ABORTED = 0x40,
+ /* The SAM_STAT_.. codes fit in the lower 6 bits */
SAS_DEV_NO_RESPONSE = 0x80,
SAS_DATA_UNDERRUN,
diff --git a/include/scsi/scsi_device.h b/include/scsi/scsi_device.h
index d80b6dbed1c..50cb34ffef1 100644
--- a/include/scsi/scsi_device.h
+++ b/include/scsi/scsi_device.h
@@ -381,6 +381,14 @@ extern int scsi_execute_req(struct scsi_device *sdev, const unsigned char *cmd,
struct scsi_sense_hdr *, int timeout, int retries,
int *resid);
+#ifdef CONFIG_PM_RUNTIME
+extern int scsi_autopm_get_device(struct scsi_device *);
+extern void scsi_autopm_put_device(struct scsi_device *);
+#else
+static inline int scsi_autopm_get_device(struct scsi_device *d) { return 0; }
+static inline void scsi_autopm_put_device(struct scsi_device *d) {}
+#endif /* CONFIG_PM_RUNTIME */
+
static inline int __must_check scsi_device_reprobe(struct scsi_device *sdev)
{
return device_reprobe(&sdev->sdev_gendev);
diff --git a/include/scsi/scsi_transport_iscsi.h b/include/scsi/scsi_transport_iscsi.h
index 349c7f30720..7fff94b3b2a 100644
--- a/include/scsi/scsi_transport_iscsi.h
+++ b/include/scsi/scsi_transport_iscsi.h
@@ -32,6 +32,7 @@ struct scsi_transport_template;
struct iscsi_transport;
struct iscsi_endpoint;
struct Scsi_Host;
+struct scsi_cmnd;
struct iscsi_cls_conn;
struct iscsi_conn;
struct iscsi_task;
@@ -255,5 +256,6 @@ extern int iscsi_scan_finished(struct Scsi_Host *shost, unsigned long time);
extern struct iscsi_endpoint *iscsi_create_endpoint(int dd_size);
extern void iscsi_destroy_endpoint(struct iscsi_endpoint *ep);
extern struct iscsi_endpoint *iscsi_lookup_endpoint(u64 handle);
+extern int iscsi_block_scsi_eh(struct scsi_cmnd *cmd);
#endif
diff --git a/include/sound/asound.h b/include/sound/asound.h
index 9f1eecf99e6..a1803ecea34 100644
--- a/include/sound/asound.h
+++ b/include/sound/asound.h
@@ -212,7 +212,11 @@ typedef int __bitwise snd_pcm_format_t;
#define SNDRV_PCM_FORMAT_S18_3BE ((__force snd_pcm_format_t) 41) /* in three bytes */
#define SNDRV_PCM_FORMAT_U18_3LE ((__force snd_pcm_format_t) 42) /* in three bytes */
#define SNDRV_PCM_FORMAT_U18_3BE ((__force snd_pcm_format_t) 43) /* in three bytes */
-#define SNDRV_PCM_FORMAT_LAST SNDRV_PCM_FORMAT_U18_3BE
+#define SNDRV_PCM_FORMAT_G723_24 ((__force snd_pcm_format_t) 44) /* 8 samples in 3 bytes */
+#define SNDRV_PCM_FORMAT_G723_24_1B ((__force snd_pcm_format_t) 45) /* 1 sample in 1 byte */
+#define SNDRV_PCM_FORMAT_G723_40 ((__force snd_pcm_format_t) 46) /* 8 Samples in 5 bytes */
+#define SNDRV_PCM_FORMAT_G723_40_1B ((__force snd_pcm_format_t) 47) /* 1 sample in 1 byte */
+#define SNDRV_PCM_FORMAT_LAST SNDRV_PCM_FORMAT_G723_40_1B
#ifdef SNDRV_LITTLE_ENDIAN
#define SNDRV_PCM_FORMAT_S16 SNDRV_PCM_FORMAT_S16_LE
diff --git a/include/sound/pcm.h b/include/sound/pcm.h
index dd76cdede64..85f1c6bf856 100644
--- a/include/sound/pcm.h
+++ b/include/sound/pcm.h
@@ -174,6 +174,10 @@ struct snd_pcm_ops {
#define SNDRV_PCM_FMTBIT_U18_3LE (1ULL << SNDRV_PCM_FORMAT_U18_3LE)
#define SNDRV_PCM_FMTBIT_S18_3BE (1ULL << SNDRV_PCM_FORMAT_S18_3BE)
#define SNDRV_PCM_FMTBIT_U18_3BE (1ULL << SNDRV_PCM_FORMAT_U18_3BE)
+#define SNDRV_PCM_FMTBIT_G723_24 (1ULL << SNDRV_PCM_FORMAT_G723_24)
+#define SNDRV_PCM_FMTBIT_G723_24_1B (1ULL << SNDRV_PCM_FORMAT_G723_24_1B)
+#define SNDRV_PCM_FMTBIT_G723_40 (1ULL << SNDRV_PCM_FORMAT_G723_40)
+#define SNDRV_PCM_FMTBIT_G723_40_1B (1ULL << SNDRV_PCM_FORMAT_G723_40_1B)
#ifdef SNDRV_LITTLE_ENDIAN
#define SNDRV_PCM_FMTBIT_S16 SNDRV_PCM_FMTBIT_S16_LE
@@ -313,7 +317,7 @@ struct snd_pcm_runtime {
struct snd_pcm_mmap_control *control;
/* -- locking / scheduling -- */
- unsigned int twake: 1; /* do transfer (!poll) wakeup */
+ snd_pcm_uframes_t twake; /* do transfer (!poll) wakeup if non-zero */
wait_queue_head_t sleep; /* poll sleep */
wait_queue_head_t tsleep; /* transfer sleep */
struct fasync_struct *fasync;
@@ -366,7 +370,7 @@ struct snd_pcm_substream {
int number;
char name[32]; /* substream name */
int stream; /* stream (direction) */
- struct pm_qos_request_list *latency_pm_qos_req; /* pm_qos request */
+ struct pm_qos_request_list latency_pm_qos_req; /* pm_qos request */
size_t buffer_bytes_max; /* limit ring buffer size */
struct snd_dma_buffer dma_buffer;
unsigned int dma_buf_id;
diff --git a/include/sound/sh_fsi.h b/include/sound/sh_fsi.h
index c0227361a87..9d51d6f3589 100644
--- a/include/sound/sh_fsi.h
+++ b/include/sound/sh_fsi.h
@@ -12,6 +12,9 @@
* published by the Free Software Foundation.
*/
+#define FSI_PORT_A 0
+#define FSI_PORT_B 1
+
/* flags format
* 0xABCDEEFF
@@ -55,12 +58,14 @@
#define SH_FSI_GET_IFMT(x) ((x >> 8) & SH_FSI_FMT_MASK)
#define SH_FSI_GET_OFMT(x) ((x >> 0) & SH_FSI_FMT_MASK)
-#define SH_FSI_FMT_MONO (1 << 0)
-#define SH_FSI_FMT_MONO_DELAY (1 << 1)
-#define SH_FSI_FMT_PCM (1 << 2)
-#define SH_FSI_FMT_I2S (1 << 3)
-#define SH_FSI_FMT_TDM (1 << 4)
-#define SH_FSI_FMT_TDM_DELAY (1 << 5)
+#define SH_FSI_FMT_MONO 0
+#define SH_FSI_FMT_MONO_DELAY 1
+#define SH_FSI_FMT_PCM 2
+#define SH_FSI_FMT_I2S 3
+#define SH_FSI_FMT_TDM 4
+#define SH_FSI_FMT_TDM_DELAY 5
+#define SH_FSI_FMT_SPDIF 6
+
#define SH_FSI_IFMT_TDM_CH(x) \
(SH_FSI_IFMT(TDM) | SH_FSI_SET_CH_I(x))
@@ -72,9 +77,41 @@
#define SH_FSI_OFMT_TDM_DELAY_CH(x) \
(SH_FSI_OFMT(TDM_DELAY) | SH_FSI_SET_CH_O(x))
+
+/*
+ * set_rate return value
+ *
+ * see ACKMD/BPFMD on
+ * ACK_MD (FSI2)
+ * CKG1 (FSI)
+ *
+ * err: return value < 0
+ *
+ * 0x-00000AB
+ *
+ * A: ACKMD value
+ * B: BPFMD value
+ */
+
+#define SH_FSI_ACKMD_MASK (0xF << 0)
+#define SH_FSI_ACKMD_512 (1 << 0)
+#define SH_FSI_ACKMD_256 (2 << 0)
+#define SH_FSI_ACKMD_128 (3 << 0)
+#define SH_FSI_ACKMD_64 (4 << 0)
+#define SH_FSI_ACKMD_32 (5 << 0)
+
+#define SH_FSI_BPFMD_MASK (0xF << 4)
+#define SH_FSI_BPFMD_512 (1 << 4)
+#define SH_FSI_BPFMD_256 (2 << 4)
+#define SH_FSI_BPFMD_128 (3 << 4)
+#define SH_FSI_BPFMD_64 (4 << 4)
+#define SH_FSI_BPFMD_32 (5 << 4)
+#define SH_FSI_BPFMD_16 (6 << 4)
+
struct sh_fsi_platform_info {
unsigned long porta_flags;
unsigned long portb_flags;
+ int (*set_rate)(int is_porta, int rate); /* for master mode */
};
extern struct snd_soc_dai fsi_soc_dai[2];
diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h
index 66ff4c124db..c5d9987bc89 100644
--- a/include/sound/soc-dapm.h
+++ b/include/sound/soc-dapm.h
@@ -273,6 +273,8 @@
#define SND_SOC_DAPM_POST_PMD 0x8 /* after widget power down */
#define SND_SOC_DAPM_PRE_REG 0x10 /* before audio path setup */
#define SND_SOC_DAPM_POST_REG 0x20 /* after audio path setup */
+#define SND_SOC_DAPM_PRE_POST_PMD \
+ (SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD)
/* convenience event type detection */
#define SND_SOC_DAPM_EVENT_ON(e) \
diff --git a/include/sound/soc.h b/include/sound/soc.h
index 697e7ffe39d..65e9d03ed4f 100644
--- a/include/sound/soc.h
+++ b/include/sound/soc.h
@@ -170,6 +170,21 @@
.get = xhandler_get, .put = xhandler_put, \
.private_value = (unsigned long)&xenum }
+#define SOC_DOUBLE_R_SX_TLV(xname, xreg_left, xreg_right, xshift,\
+ xmin, xmax, tlv_array) \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
+ .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | \
+ SNDRV_CTL_ELEM_ACCESS_READWRITE, \
+ .tlv.p = (tlv_array), \
+ .info = snd_soc_info_volsw_2r_sx, \
+ .get = snd_soc_get_volsw_2r_sx, \
+ .put = snd_soc_put_volsw_2r_sx, \
+ .private_value = (unsigned long)&(struct soc_mixer_control) \
+ {.reg = xreg_left, \
+ .rreg = xreg_right, .shift = xshift, \
+ .min = xmin, .max = xmax} }
+
+
/*
* Simplified versions of above macros, declaring a struct and calculating
* ARRAY_SIZE internally
@@ -329,6 +344,12 @@ int snd_soc_put_volsw_s8(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol);
int snd_soc_limit_volume(struct snd_soc_codec *codec,
const char *name, int max);
+int snd_soc_info_volsw_2r_sx(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo);
+int snd_soc_get_volsw_2r_sx(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol);
+int snd_soc_put_volsw_2r_sx(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol);
/**
* struct snd_soc_jack_pin - Describes a pin to update based on jack detection
diff --git a/include/sound/tlv320dac33-plat.h b/include/sound/tlv320dac33-plat.h
index 3f428d53195..6c664965679 100644
--- a/include/sound/tlv320dac33-plat.h
+++ b/include/sound/tlv320dac33-plat.h
@@ -15,6 +15,8 @@
struct tlv320dac33_platform_data {
int power_gpio;
+ int mode1_latency; /* latency caused by the i2c writes in us */
+ int auto_fifo_config; /* FIFO config based on the period size */
int keep_bclk; /* Keep the BCLK running in FIFO modes */
u8 burst_bclkdiv;
};
diff --git a/include/sound/uda134x.h b/include/sound/uda134x.h
index 509efb05017..e475659bd3b 100644
--- a/include/sound/uda134x.h
+++ b/include/sound/uda134x.h
@@ -18,6 +18,18 @@ struct uda134x_platform_data {
struct l3_pins l3;
void (*power) (int);
int model;
+ /*
+ ALSA SOC usually puts the device in standby mode when it's not used
+ for sometime. If you unset is_powered_on_standby the driver will
+ turn off the ADC/DAC when this callback is invoked and turn it back
+ on when needed. Unfortunately this will result in a very light bump
+ (it can be audible only with good earphones). If this bothers you
+ set is_powered_on_standby, you will have slightly higher power
+ consumption. Please note that sending the L3 command for ADC is
+ enough to make the bump, so it doesn't make difference if you
+ completely take off power from the codec.
+ */
+ int is_powered_on_standby;
#define UDA134X_UDA1340 1
#define UDA134X_UDA1341 2
#define UDA134X_UDA1344 3
diff --git a/include/trace/boot.h b/include/trace/boot.h
deleted file mode 100644
index 088ea089e31..00000000000
--- a/include/trace/boot.h
+++ /dev/null
@@ -1,60 +0,0 @@
-#ifndef _LINUX_TRACE_BOOT_H
-#define _LINUX_TRACE_BOOT_H
-
-#include <linux/module.h>
-#include <linux/kallsyms.h>
-#include <linux/init.h>
-
-/*
- * Structure which defines the trace of an initcall
- * while it is called.
- * You don't have to fill the func field since it is
- * only used internally by the tracer.
- */
-struct boot_trace_call {
- pid_t caller;
- char func[KSYM_SYMBOL_LEN];
-};
-
-/*
- * Structure which defines the trace of an initcall
- * while it returns.
- */
-struct boot_trace_ret {
- char func[KSYM_SYMBOL_LEN];
- int result;
- unsigned long long duration; /* nsecs */
-};
-
-#ifdef CONFIG_BOOT_TRACER
-/* Append the traces on the ring-buffer */
-extern void trace_boot_call(struct boot_trace_call *bt, initcall_t fn);
-extern void trace_boot_ret(struct boot_trace_ret *bt, initcall_t fn);
-
-/* Tells the tracer that smp_pre_initcall is finished.
- * So we can start the tracing
- */
-extern void start_boot_trace(void);
-
-/* Resume the tracing of other necessary events
- * such as sched switches
- */
-extern void enable_boot_trace(void);
-
-/* Suspend this tracing. Actually, only sched_switches tracing have
- * to be suspended. Initcalls doesn't need it.)
- */
-extern void disable_boot_trace(void);
-#else
-static inline
-void trace_boot_call(struct boot_trace_call *bt, initcall_t fn) { }
-
-static inline
-void trace_boot_ret(struct boot_trace_ret *bt, initcall_t fn) { }
-
-static inline void start_boot_trace(void) { }
-static inline void enable_boot_trace(void) { }
-static inline void disable_boot_trace(void) { }
-#endif /* CONFIG_BOOT_TRACER */
-
-#endif /* __LINUX_TRACE_BOOT_H */
diff --git a/include/trace/events/ext4.h b/include/trace/events/ext4.h
index f3865c7b416..01e9e0076a9 100644
--- a/include/trace/events/ext4.h
+++ b/include/trace/events/ext4.h
@@ -395,11 +395,12 @@ DEFINE_EVENT(ext4__mb_new_pa, ext4_mb_new_group_pa,
);
TRACE_EVENT(ext4_mb_release_inode_pa,
- TP_PROTO(struct ext4_allocation_context *ac,
+ TP_PROTO(struct super_block *sb,
+ struct ext4_allocation_context *ac,
struct ext4_prealloc_space *pa,
unsigned long long block, unsigned int count),
- TP_ARGS(ac, pa, block, count),
+ TP_ARGS(sb, ac, pa, block, count),
TP_STRUCT__entry(
__field( dev_t, dev )
@@ -410,8 +411,9 @@ TRACE_EVENT(ext4_mb_release_inode_pa,
),
TP_fast_assign(
- __entry->dev = ac->ac_sb->s_dev;
- __entry->ino = ac->ac_inode->i_ino;
+ __entry->dev = sb->s_dev;
+ __entry->ino = (ac && ac->ac_inode) ?
+ ac->ac_inode->i_ino : 0;
__entry->block = block;
__entry->count = count;
),
@@ -422,10 +424,11 @@ TRACE_EVENT(ext4_mb_release_inode_pa,
);
TRACE_EVENT(ext4_mb_release_group_pa,
- TP_PROTO(struct ext4_allocation_context *ac,
+ TP_PROTO(struct super_block *sb,
+ struct ext4_allocation_context *ac,
struct ext4_prealloc_space *pa),
- TP_ARGS(ac, pa),
+ TP_ARGS(sb, ac, pa),
TP_STRUCT__entry(
__field( dev_t, dev )
@@ -436,8 +439,9 @@ TRACE_EVENT(ext4_mb_release_group_pa,
),
TP_fast_assign(
- __entry->dev = ac->ac_sb->s_dev;
- __entry->ino = ac->ac_inode->i_ino;
+ __entry->dev = sb->s_dev;
+ __entry->ino = (ac && ac->ac_inode) ?
+ ac->ac_inode->i_ino : 0;
__entry->pa_pstart = pa->pa_pstart;
__entry->pa_len = pa->pa_len;
),
diff --git a/include/trace/events/power.h b/include/trace/events/power.h
index c4efe9b8280..35a2a6e7bf1 100644
--- a/include/trace/events/power.h
+++ b/include/trace/events/power.h
@@ -18,52 +18,55 @@ enum {
DECLARE_EVENT_CLASS(power,
- TP_PROTO(unsigned int type, unsigned int state),
+ TP_PROTO(unsigned int type, unsigned int state, unsigned int cpu_id),
- TP_ARGS(type, state),
+ TP_ARGS(type, state, cpu_id),
TP_STRUCT__entry(
__field( u64, type )
__field( u64, state )
+ __field( u64, cpu_id )
),
TP_fast_assign(
__entry->type = type;
__entry->state = state;
+ __entry->cpu_id = cpu_id;
),
- TP_printk("type=%lu state=%lu", (unsigned long)__entry->type, (unsigned long)__entry->state)
+ TP_printk("type=%lu state=%lu cpu_id=%lu", (unsigned long)__entry->type,
+ (unsigned long)__entry->state, (unsigned long)__entry->cpu_id)
);
DEFINE_EVENT(power, power_start,
- TP_PROTO(unsigned int type, unsigned int state),
+ TP_PROTO(unsigned int type, unsigned int state, unsigned int cpu_id),
- TP_ARGS(type, state)
+ TP_ARGS(type, state, cpu_id)
);
DEFINE_EVENT(power, power_frequency,
- TP_PROTO(unsigned int type, unsigned int state),
+ TP_PROTO(unsigned int type, unsigned int state, unsigned int cpu_id),
- TP_ARGS(type, state)
+ TP_ARGS(type, state, cpu_id)
);
TRACE_EVENT(power_end,
- TP_PROTO(int dummy),
+ TP_PROTO(unsigned int cpu_id),
- TP_ARGS(dummy),
+ TP_ARGS(cpu_id),
TP_STRUCT__entry(
- __field( u64, dummy )
+ __field( u64, cpu_id )
),
TP_fast_assign(
- __entry->dummy = 0xffff;
+ __entry->cpu_id = cpu_id;
),
- TP_printk("dummy=%lu", (unsigned long)__entry->dummy)
+ TP_printk("cpu_id=%lu", (unsigned long)__entry->cpu_id)
);
diff --git a/include/trace/events/sched.h b/include/trace/events/sched.h
index b9e1dd6c620..9208c92aeab 100644
--- a/include/trace/events/sched.h
+++ b/include/trace/events/sched.h
@@ -50,31 +50,6 @@ TRACE_EVENT(sched_kthread_stop_ret,
);
/*
- * Tracepoint for waiting on task to unschedule:
- */
-TRACE_EVENT(sched_wait_task,
-
- TP_PROTO(struct task_struct *p),
-
- TP_ARGS(p),
-
- TP_STRUCT__entry(
- __array( char, comm, TASK_COMM_LEN )
- __field( pid_t, pid )
- __field( int, prio )
- ),
-
- TP_fast_assign(
- memcpy(__entry->comm, p->comm, TASK_COMM_LEN);
- __entry->pid = p->pid;
- __entry->prio = p->prio;
- ),
-
- TP_printk("comm=%s pid=%d prio=%d",
- __entry->comm, __entry->pid, __entry->prio)
-);
-
-/*
* Tracepoint for waking up a task:
*/
DECLARE_EVENT_CLASS(sched_wakeup_template,
@@ -240,6 +215,13 @@ DEFINE_EVENT(sched_process_template, sched_process_exit,
TP_ARGS(p));
/*
+ * Tracepoint for waiting on task to unschedule:
+ */
+DEFINE_EVENT(sched_process_template, sched_wait_task,
+ TP_PROTO(struct task_struct *p),
+ TP_ARGS(p));
+
+/*
* Tracepoint for a waiting task:
*/
TRACE_EVENT(sched_process_wait,
diff --git a/include/trace/events/timer.h b/include/trace/events/timer.h
index 9496b965d62..c624126a9c8 100644
--- a/include/trace/events/timer.h
+++ b/include/trace/events/timer.h
@@ -8,11 +8,7 @@
#include <linux/hrtimer.h>
#include <linux/timer.h>
-/**
- * timer_init - called when the timer is initialized
- * @timer: pointer to struct timer_list
- */
-TRACE_EVENT(timer_init,
+DECLARE_EVENT_CLASS(timer_class,
TP_PROTO(struct timer_list *timer),
@@ -30,6 +26,17 @@ TRACE_EVENT(timer_init,
);
/**
+ * timer_init - called when the timer is initialized
+ * @timer: pointer to struct timer_list
+ */
+DEFINE_EVENT(timer_class, timer_init,
+
+ TP_PROTO(struct timer_list *timer),
+
+ TP_ARGS(timer)
+);
+
+/**
* timer_start - called when the timer is started
* @timer: pointer to struct timer_list
* @expires: the timers expiry time
@@ -94,42 +101,22 @@ TRACE_EVENT(timer_expire_entry,
* NOTE: Do NOT derefernce timer in TP_fast_assign. The pointer might
* be invalid. We solely track the pointer.
*/
-TRACE_EVENT(timer_expire_exit,
+DEFINE_EVENT(timer_class, timer_expire_exit,
TP_PROTO(struct timer_list *timer),
- TP_ARGS(timer),
-
- TP_STRUCT__entry(
- __field(void *, timer )
- ),
-
- TP_fast_assign(
- __entry->timer = timer;
- ),
-
- TP_printk("timer=%p", __entry->timer)
+ TP_ARGS(timer)
);
/**
* timer_cancel - called when the timer is canceled
* @timer: pointer to struct timer_list
*/
-TRACE_EVENT(timer_cancel,
+DEFINE_EVENT(timer_class, timer_cancel,
TP_PROTO(struct timer_list *timer),
- TP_ARGS(timer),
-
- TP_STRUCT__entry(
- __field( void *, timer )
- ),
-
- TP_fast_assign(
- __entry->timer = timer;
- ),
-
- TP_printk("timer=%p", __entry->timer)
+ TP_ARGS(timer)
);
/**
@@ -224,14 +211,7 @@ TRACE_EVENT(hrtimer_expire_entry,
(unsigned long long)ktime_to_ns((ktime_t) { .tv64 = __entry->now }))
);
-/**
- * hrtimer_expire_exit - called immediately after the hrtimer callback returns
- * @timer: pointer to struct hrtimer
- *
- * When used in combination with the hrtimer_expire_entry tracepoint we can
- * determine the runtime of the callback function.
- */
-TRACE_EVENT(hrtimer_expire_exit,
+DECLARE_EVENT_CLASS(hrtimer_class,
TP_PROTO(struct hrtimer *hrtimer),
@@ -249,24 +229,28 @@ TRACE_EVENT(hrtimer_expire_exit,
);
/**
- * hrtimer_cancel - called when the hrtimer is canceled
- * @hrtimer: pointer to struct hrtimer
+ * hrtimer_expire_exit - called immediately after the hrtimer callback returns
+ * @timer: pointer to struct hrtimer
+ *
+ * When used in combination with the hrtimer_expire_entry tracepoint we can
+ * determine the runtime of the callback function.
*/
-TRACE_EVENT(hrtimer_cancel,
+DEFINE_EVENT(hrtimer_class, hrtimer_expire_exit,
TP_PROTO(struct hrtimer *hrtimer),
- TP_ARGS(hrtimer),
+ TP_ARGS(hrtimer)
+);
- TP_STRUCT__entry(
- __field( void *, hrtimer )
- ),
+/**
+ * hrtimer_cancel - called when the hrtimer is canceled
+ * @hrtimer: pointer to struct hrtimer
+ */
+DEFINE_EVENT(hrtimer_class, hrtimer_cancel,
- TP_fast_assign(
- __entry->hrtimer = hrtimer;
- ),
+ TP_PROTO(struct hrtimer *hrtimer),
- TP_printk("hrtimer=%p", __entry->hrtimer)
+ TP_ARGS(hrtimer)
);
/**
diff --git a/include/trace/events/workqueue.h b/include/trace/events/workqueue.h
deleted file mode 100644
index d6c974474e7..00000000000
--- a/include/trace/events/workqueue.h
+++ /dev/null
@@ -1,92 +0,0 @@
-#undef TRACE_SYSTEM
-#define TRACE_SYSTEM workqueue
-
-#if !defined(_TRACE_WORKQUEUE_H) || defined(TRACE_HEADER_MULTI_READ)
-#define _TRACE_WORKQUEUE_H
-
-#include <linux/workqueue.h>
-#include <linux/sched.h>
-#include <linux/tracepoint.h>
-
-DECLARE_EVENT_CLASS(workqueue,
-
- TP_PROTO(struct task_struct *wq_thread, struct work_struct *work),
-
- TP_ARGS(wq_thread, work),
-
- TP_STRUCT__entry(
- __array(char, thread_comm, TASK_COMM_LEN)
- __field(pid_t, thread_pid)
- __field(work_func_t, func)
- ),
-
- TP_fast_assign(
- memcpy(__entry->thread_comm, wq_thread->comm, TASK_COMM_LEN);
- __entry->thread_pid = wq_thread->pid;
- __entry->func = work->func;
- ),
-
- TP_printk("thread=%s:%d func=%pf", __entry->thread_comm,
- __entry->thread_pid, __entry->func)
-);
-
-DEFINE_EVENT(workqueue, workqueue_insertion,
-
- TP_PROTO(struct task_struct *wq_thread, struct work_struct *work),
-
- TP_ARGS(wq_thread, work)
-);
-
-DEFINE_EVENT(workqueue, workqueue_execution,
-
- TP_PROTO(struct task_struct *wq_thread, struct work_struct *work),
-
- TP_ARGS(wq_thread, work)
-);
-
-/* Trace the creation of one workqueue thread on a cpu */
-TRACE_EVENT(workqueue_creation,
-
- TP_PROTO(struct task_struct *wq_thread, int cpu),
-
- TP_ARGS(wq_thread, cpu),
-
- TP_STRUCT__entry(
- __array(char, thread_comm, TASK_COMM_LEN)
- __field(pid_t, thread_pid)
- __field(int, cpu)
- ),
-
- TP_fast_assign(
- memcpy(__entry->thread_comm, wq_thread->comm, TASK_COMM_LEN);
- __entry->thread_pid = wq_thread->pid;
- __entry->cpu = cpu;
- ),
-
- TP_printk("thread=%s:%d cpu=%d", __entry->thread_comm,
- __entry->thread_pid, __entry->cpu)
-);
-
-TRACE_EVENT(workqueue_destruction,
-
- TP_PROTO(struct task_struct *wq_thread),
-
- TP_ARGS(wq_thread),
-
- TP_STRUCT__entry(
- __array(char, thread_comm, TASK_COMM_LEN)
- __field(pid_t, thread_pid)
- ),
-
- TP_fast_assign(
- memcpy(__entry->thread_comm, wq_thread->comm, TASK_COMM_LEN);
- __entry->thread_pid = wq_thread->pid;
- ),
-
- TP_printk("thread=%s:%d", __entry->thread_comm, __entry->thread_pid)
-);
-
-#endif /* _TRACE_WORKQUEUE_H */
-
-/* This part must be outside protection */
-#include <trace/define_trace.h>
diff --git a/include/trace/ftrace.h b/include/trace/ftrace.h
index 5a64905d727..a9377c0083a 100644
--- a/include/trace/ftrace.h
+++ b/include/trace/ftrace.h
@@ -75,15 +75,12 @@
#define DEFINE_EVENT_PRINT(template, name, proto, args, print) \
DEFINE_EVENT(template, name, PARAMS(proto), PARAMS(args))
-#undef __cpparg
-#define __cpparg(arg...) arg
-
/* Callbacks are meaningless to ftrace. */
#undef TRACE_EVENT_FN
#define TRACE_EVENT_FN(name, proto, args, tstruct, \
assign, print, reg, unreg) \
- TRACE_EVENT(name, __cpparg(proto), __cpparg(args), \
- __cpparg(tstruct), __cpparg(assign), __cpparg(print)) \
+ TRACE_EVENT(name, PARAMS(proto), PARAMS(args), \
+ PARAMS(tstruct), PARAMS(assign), PARAMS(print)) \
#include TRACE_INCLUDE(TRACE_INCLUDE_FILE)
@@ -145,7 +142,7 @@
* struct trace_seq *s = &iter->seq;
* struct ftrace_raw_<call> *field; <-- defined in stage 1
* struct trace_entry *entry;
- * struct trace_seq *p;
+ * struct trace_seq *p = &iter->tmp_seq;
* int ret;
*
* entry = iter->ent;
@@ -157,12 +154,10 @@
*
* field = (typeof(field))entry;
*
- * p = &get_cpu_var(ftrace_event_seq);
* trace_seq_init(p);
* ret = trace_seq_printf(s, "%s: ", <call>);
* if (ret)
* ret = trace_seq_printf(s, <TP_printk> "\n");
- * put_cpu();
* if (!ret)
* return TRACE_TYPE_PARTIAL_LINE;
*
@@ -216,7 +211,7 @@ ftrace_raw_output_##call(struct trace_iterator *iter, int flags, \
struct trace_seq *s = &iter->seq; \
struct ftrace_raw_##call *field; \
struct trace_entry *entry; \
- struct trace_seq *p; \
+ struct trace_seq *p = &iter->tmp_seq; \
int ret; \
\
event = container_of(trace_event, struct ftrace_event_call, \
@@ -231,12 +226,10 @@ ftrace_raw_output_##call(struct trace_iterator *iter, int flags, \
\
field = (typeof(field))entry; \
\
- p = &get_cpu_var(ftrace_event_seq); \
trace_seq_init(p); \
ret = trace_seq_printf(s, "%s: ", event->name); \
if (ret) \
ret = trace_seq_printf(s, print); \
- put_cpu(); \
if (!ret) \
return TRACE_TYPE_PARTIAL_LINE; \
\
@@ -255,7 +248,7 @@ ftrace_raw_output_##call(struct trace_iterator *iter, int flags, \
struct trace_seq *s = &iter->seq; \
struct ftrace_raw_##template *field; \
struct trace_entry *entry; \
- struct trace_seq *p; \
+ struct trace_seq *p = &iter->tmp_seq; \
int ret; \
\
entry = iter->ent; \
@@ -267,12 +260,10 @@ ftrace_raw_output_##call(struct trace_iterator *iter, int flags, \
\
field = (typeof(field))entry; \
\
- p = &get_cpu_var(ftrace_event_seq); \
trace_seq_init(p); \
ret = trace_seq_printf(s, "%s: ", #call); \
if (ret) \
ret = trace_seq_printf(s, print); \
- put_cpu(); \
if (!ret) \
return TRACE_TYPE_PARTIAL_LINE; \
\
@@ -439,6 +430,7 @@ static inline notrace int ftrace_get_offsets_##call( \
* .fields = LIST_HEAD_INIT(event_class_##call.fields),
* .raw_init = trace_event_raw_init,
* .probe = ftrace_raw_event_##call,
+ * .reg = ftrace_event_reg,
* };
*
* static struct ftrace_event_call __used
@@ -567,6 +559,7 @@ static struct ftrace_event_class __used event_class_##call = { \
.fields = LIST_HEAD_INIT(event_class_##call.fields),\
.raw_init = trace_event_raw_init, \
.probe = ftrace_raw_event_##call, \
+ .reg = ftrace_event_reg, \
_TRACE_PERF_INIT(call) \
};
@@ -705,7 +698,7 @@ perf_trace_##call(void *__data, proto) \
int __data_size; \
int rctx; \
\
- perf_fetch_caller_regs(&__regs, 1); \
+ perf_fetch_caller_regs(&__regs); \
\
__data_size = ftrace_get_offsets_##call(&__data_offsets, args); \
__entry_size = ALIGN(__data_size + sizeof(*entry) + sizeof(u32),\
diff --git a/include/trace/syscall.h b/include/trace/syscall.h
index 257e08960d7..31966a4fb8c 100644
--- a/include/trace/syscall.h
+++ b/include/trace/syscall.h
@@ -26,7 +26,6 @@ struct syscall_metadata {
const char **types;
const char **args;
struct list_head enter_fields;
- struct list_head exit_fields;
struct ftrace_event_call *enter_event;
struct ftrace_event_call *exit_event;
diff --git a/include/xen/events.h b/include/xen/events.h
index e68d59a90ca..a15d93262e3 100644
--- a/include/xen/events.h
+++ b/include/xen/events.h
@@ -56,4 +56,11 @@ void xen_poll_irq(int irq);
/* Determine the IRQ which is bound to an event channel */
unsigned irq_from_evtchn(unsigned int evtchn);
+/* Xen HVM evtchn vector callback */
+extern void xen_hvm_callback_vector(void);
+extern int xen_have_vector_callback;
+int xen_set_callback_via(uint64_t via);
+void xen_evtchn_do_upcall(struct pt_regs *regs);
+void xen_hvm_evtchn_do_upcall(void);
+
#endif /* _XEN_EVENTS_H */
diff --git a/include/xen/grant_table.h b/include/xen/grant_table.h
index a40f1cd91be..9a731706a01 100644
--- a/include/xen/grant_table.h
+++ b/include/xen/grant_table.h
@@ -51,6 +51,7 @@ struct gnttab_free_callback {
u16 count;
};
+int gnttab_init(void);
int gnttab_suspend(void);
int gnttab_resume(void);
@@ -112,6 +113,9 @@ int arch_gnttab_map_shared(unsigned long *frames, unsigned long nr_gframes,
void arch_gnttab_unmap_shared(struct grant_entry *shared,
unsigned long nr_gframes);
+extern unsigned long xen_hvm_resume_frames;
+unsigned int gnttab_max_grant_frames(void);
+
#define gnttab_map_vaddr(map) ((void *)(map.host_virt_addr))
#endif /* __ASM_GNTTAB_H__ */
diff --git a/include/xen/hvm.h b/include/xen/hvm.h
new file mode 100644
index 00000000000..b193fa2f9fd
--- /dev/null
+++ b/include/xen/hvm.h
@@ -0,0 +1,30 @@
+/* Simple wrappers around HVM functions */
+#ifndef XEN_HVM_H__
+#define XEN_HVM_H__
+
+#include <xen/interface/hvm/params.h>
+#include <asm/xen/hypercall.h>
+
+static inline int hvm_get_parameter(int idx, uint64_t *value)
+{
+ struct xen_hvm_param xhv;
+ int r;
+
+ xhv.domid = DOMID_SELF;
+ xhv.index = idx;
+ r = HYPERVISOR_hvm_op(HVMOP_get_param, &xhv);
+ if (r < 0) {
+ printk(KERN_ERR "Cannot get hvm parameter %d: %d!\n",
+ idx, r);
+ return r;
+ }
+ *value = xhv.value;
+ return r;
+}
+
+#define HVM_CALLBACK_VIA_TYPE_VECTOR 0x2
+#define HVM_CALLBACK_VIA_TYPE_SHIFT 56
+#define HVM_CALLBACK_VECTOR(x) (((uint64_t)HVM_CALLBACK_VIA_TYPE_VECTOR)<<\
+ HVM_CALLBACK_VIA_TYPE_SHIFT | (x))
+
+#endif /* XEN_HVM_H__ */
diff --git a/include/xen/interface/features.h b/include/xen/interface/features.h
index f51b6413b05..70d2563ab16 100644
--- a/include/xen/interface/features.h
+++ b/include/xen/interface/features.h
@@ -41,6 +41,12 @@
/* x86: Does this Xen host support the MMU_PT_UPDATE_PRESERVE_AD hypercall? */
#define XENFEAT_mmu_pt_update_preserve_ad 5
+/* x86: Does this Xen host support the HVM callback vector type? */
+#define XENFEAT_hvm_callback_vector 8
+
+/* x86: pvclock algorithm is safe to use on HVM */
+#define XENFEAT_hvm_safe_pvclock 9
+
#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
index 39da93c21de..39e571796e3 100644
--- a/include/xen/interface/grant_table.h
+++ b/include/xen/interface/grant_table.h
@@ -28,6 +28,7 @@
#ifndef __XEN_PUBLIC_GRANT_TABLE_H__
#define __XEN_PUBLIC_GRANT_TABLE_H__
+#include <xen/interface/xen.h>
/***********************************
* GRANT TABLE REPRESENTATION
diff --git a/include/xen/interface/hvm/hvm_op.h b/include/xen/interface/hvm/hvm_op.h
new file mode 100644
index 00000000000..a4827f46ee9
--- /dev/null
+++ b/include/xen/interface/hvm/hvm_op.h
@@ -0,0 +1,46 @@
+/*
+ * 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_HVM_HVM_OP_H__
+#define __XEN_PUBLIC_HVM_HVM_OP_H__
+
+/* Get/set subcommands: the second argument of the hypercall is a
+ * pointer to a xen_hvm_param struct. */
+#define HVMOP_set_param 0
+#define HVMOP_get_param 1
+struct xen_hvm_param {
+ domid_t domid; /* IN */
+ uint32_t index; /* IN */
+ uint64_t value; /* IN/OUT */
+};
+DEFINE_GUEST_HANDLE_STRUCT(xen_hvm_param);
+
+/* Hint from PV drivers for pagetable destruction. */
+#define HVMOP_pagetable_dying 9
+struct xen_hvm_pagetable_dying {
+ /* Domain with a pagetable about to be destroyed. */
+ domid_t domid;
+ /* guest physical address of the toplevel pagetable dying */
+ aligned_u64 gpa;
+};
+typedef struct xen_hvm_pagetable_dying xen_hvm_pagetable_dying_t;
+DEFINE_GUEST_HANDLE_STRUCT(xen_hvm_pagetable_dying_t);
+
+#endif /* __XEN_PUBLIC_HVM_HVM_OP_H__ */
diff --git a/include/xen/interface/hvm/params.h b/include/xen/interface/hvm/params.h
new file mode 100644
index 00000000000..1888d8c157e
--- /dev/null
+++ b/include/xen/interface/hvm/params.h
@@ -0,0 +1,95 @@
+/*
+ * 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_HVM_PARAMS_H__
+#define __XEN_PUBLIC_HVM_PARAMS_H__
+
+#include "hvm_op.h"
+
+/*
+ * Parameter space for HVMOP_{set,get}_param.
+ */
+
+/*
+ * How should CPU0 event-channel notifications be delivered?
+ * val[63:56] == 0: val[55:0] is a delivery GSI (Global System Interrupt).
+ * val[63:56] == 1: val[55:0] is a delivery PCI INTx line, as follows:
+ * Domain = val[47:32], Bus = val[31:16],
+ * DevFn = val[15: 8], IntX = val[ 1: 0]
+ * val[63:56] == 2: val[7:0] is a vector number.
+ * If val == 0 then CPU0 event-channel notifications are not delivered.
+ */
+#define HVM_PARAM_CALLBACK_IRQ 0
+
+#define HVM_PARAM_STORE_PFN 1
+#define HVM_PARAM_STORE_EVTCHN 2
+
+#define HVM_PARAM_PAE_ENABLED 4
+
+#define HVM_PARAM_IOREQ_PFN 5
+
+#define HVM_PARAM_BUFIOREQ_PFN 6
+
+/*
+ * Set mode for virtual timers (currently x86 only):
+ * delay_for_missed_ticks (default):
+ * Do not advance a vcpu's time beyond the correct delivery time for
+ * interrupts that have been missed due to preemption. Deliver missed
+ * interrupts when the vcpu is rescheduled and advance the vcpu's virtual
+ * time stepwise for each one.
+ * no_delay_for_missed_ticks:
+ * As above, missed interrupts are delivered, but guest time always tracks
+ * wallclock (i.e., real) time while doing so.
+ * no_missed_ticks_pending:
+ * No missed interrupts are held pending. Instead, to ensure ticks are
+ * delivered at some non-zero rate, if we detect missed ticks then the
+ * internal tick alarm is not disabled if the VCPU is preempted during the
+ * next tick period.
+ * one_missed_tick_pending:
+ * Missed interrupts are collapsed together and delivered as one 'late tick'.
+ * Guest time always tracks wallclock (i.e., real) time.
+ */
+#define HVM_PARAM_TIMER_MODE 10
+#define HVMPTM_delay_for_missed_ticks 0
+#define HVMPTM_no_delay_for_missed_ticks 1
+#define HVMPTM_no_missed_ticks_pending 2
+#define HVMPTM_one_missed_tick_pending 3
+
+/* Boolean: Enable virtual HPET (high-precision event timer)? (x86-only) */
+#define HVM_PARAM_HPET_ENABLED 11
+
+/* Identity-map page directory used by Intel EPT when CR0.PG=0. */
+#define HVM_PARAM_IDENT_PT 12
+
+/* Device Model domain, defaults to 0. */
+#define HVM_PARAM_DM_DOMAIN 13
+
+/* ACPI S state: currently support S0 and S3 on x86. */
+#define HVM_PARAM_ACPI_S_STATE 14
+
+/* TSS used on Intel when CR0.PE=0. */
+#define HVM_PARAM_VM86_TSS 15
+
+/* Boolean: Enable aligning all periodic vpts to reduce interrupts */
+#define HVM_PARAM_VPT_ALIGN 16
+
+#define HVM_NR_PARAMS 17
+
+#endif /* __XEN_PUBLIC_HVM_PARAMS_H__ */
diff --git a/include/xen/platform_pci.h b/include/xen/platform_pci.h
new file mode 100644
index 00000000000..ce9d671c636
--- /dev/null
+++ b/include/xen/platform_pci.h
@@ -0,0 +1,49 @@
+#ifndef _XEN_PLATFORM_PCI_H
+#define _XEN_PLATFORM_PCI_H
+
+#define XEN_IOPORT_MAGIC_VAL 0x49d2
+#define XEN_IOPORT_LINUX_PRODNUM 0x0003
+#define XEN_IOPORT_LINUX_DRVVER 0x0001
+
+#define XEN_IOPORT_BASE 0x10
+
+#define XEN_IOPORT_PLATFLAGS (XEN_IOPORT_BASE + 0) /* 1 byte access (R/W) */
+#define XEN_IOPORT_MAGIC (XEN_IOPORT_BASE + 0) /* 2 byte access (R) */
+#define XEN_IOPORT_UNPLUG (XEN_IOPORT_BASE + 0) /* 2 byte access (W) */
+#define XEN_IOPORT_DRVVER (XEN_IOPORT_BASE + 0) /* 4 byte access (W) */
+
+#define XEN_IOPORT_SYSLOG (XEN_IOPORT_BASE + 2) /* 1 byte access (W) */
+#define XEN_IOPORT_PROTOVER (XEN_IOPORT_BASE + 2) /* 1 byte access (R) */
+#define XEN_IOPORT_PRODNUM (XEN_IOPORT_BASE + 2) /* 2 byte access (W) */
+
+#define XEN_UNPLUG_ALL_IDE_DISKS 1
+#define XEN_UNPLUG_ALL_NICS 2
+#define XEN_UNPLUG_AUX_IDE_DISKS 4
+#define XEN_UNPLUG_ALL 7
+#define XEN_UNPLUG_IGNORE 8
+
+static inline int xen_must_unplug_nics(void) {
+#if (defined(CONFIG_XEN_NETDEV_FRONTEND) || \
+ defined(CONFIG_XEN_NETDEV_FRONTEND_MODULE)) && \
+ (defined(CONFIG_XEN_PLATFORM_PCI) || \
+ defined(CONFIG_XEN_PLATFORM_PCI_MODULE))
+ return 1;
+#else
+ return 0;
+#endif
+}
+
+static inline int xen_must_unplug_disks(void) {
+#if (defined(CONFIG_XEN_BLKDEV_FRONTEND) || \
+ defined(CONFIG_XEN_BLKDEV_FRONTEND_MODULE)) && \
+ (defined(CONFIG_XEN_PLATFORM_PCI) || \
+ defined(CONFIG_XEN_PLATFORM_PCI_MODULE))
+ return 1;
+#else
+ return 0;
+#endif
+}
+
+extern int xen_platform_pci_unplug;
+
+#endif /* _XEN_PLATFORM_PCI_H */
diff --git a/include/xen/xen-ops.h b/include/xen/xen-ops.h
index 883a21bba24..46bc81ef74c 100644
--- a/include/xen/xen-ops.h
+++ b/include/xen/xen-ops.h
@@ -7,6 +7,7 @@ DECLARE_PER_CPU(struct vcpu_info *, xen_vcpu);
void xen_pre_suspend(void);
void xen_post_suspend(int suspend_cancelled);
+void xen_hvm_post_suspend(int suspend_cancelled);
void xen_mm_pin_all(void);
void xen_mm_unpin_all(void);
@@ -14,4 +15,6 @@ void xen_mm_unpin_all(void);
void xen_timer_resume(void);
void xen_arch_resume(void);
+int xen_setup_shutdown_event(void);
+
#endif /* INCLUDE_XEN_OPS_H */
diff --git a/init/Kconfig b/init/Kconfig
index 5cff9a980c3..cb64c5889e0 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -1143,30 +1143,6 @@ config TRACEPOINTS
source "arch/Kconfig"
-config SLOW_WORK
- default n
- bool
- help
- The slow work thread pool provides a number of dynamically allocated
- threads that can be used by the kernel to perform operations that
- take a relatively long time.
-
- An example of this would be CacheFiles doing a path lookup followed
- by a series of mkdirs and a create call, all of which have to touch
- disk.
-
- See Documentation/slow-work.txt.
-
-config SLOW_WORK_DEBUG
- bool "Slow work debugging through debugfs"
- default n
- depends on SLOW_WORK && DEBUG_FS
- help
- Display the contents of the slow work run queue through debugfs,
- including items currently executing.
-
- See Documentation/slow-work.txt.
-
endmenu # General setup
config HAVE_GENERIC_DMA_COHERENT
diff --git a/init/main.c b/init/main.c
index a42fdf4aeba..b8b6effe9ff 100644
--- a/init/main.c
+++ b/init/main.c
@@ -32,7 +32,6 @@
#include <linux/start_kernel.h>
#include <linux/security.h>
#include <linux/smp.h>
-#include <linux/workqueue.h>
#include <linux/profile.h>
#include <linux/rcupdate.h>
#include <linux/moduleparam.h>
@@ -66,11 +65,9 @@
#include <linux/ftrace.h>
#include <linux/async.h>
#include <linux/kmemcheck.h>
-#include <linux/kmemtrace.h>
#include <linux/sfi.h>
#include <linux/shmem_fs.h>
#include <linux/slab.h>
-#include <trace/boot.h>
#include <asm/io.h>
#include <asm/bugs.h>
@@ -444,7 +441,6 @@ static noinline void __init_refok rest_init(void)
kthreadd_task = find_task_by_pid_ns(pid, &init_pid_ns);
rcu_read_unlock();
complete(&kthreadd_done);
- unlock_kernel();
/*
* The boot idle thread must execute schedule()
@@ -532,6 +528,7 @@ static void __init mm_init(void)
page_cgroup_init_flatmem();
mem_init();
kmem_cache_init();
+ percpu_init_late();
pgtable_cache_init();
vmalloc_init();
}
@@ -565,7 +562,6 @@ asmlinkage void __init start_kernel(void)
* Interrupts are still disabled. Do necessary setups, then
* enable them
*/
- lock_kernel();
tick_init();
boot_cpu_init();
page_address_init();
@@ -663,7 +659,6 @@ asmlinkage void __init start_kernel(void)
#endif
page_cgroup_init();
enable_debug_pagealloc();
- kmemtrace_init();
kmemleak_init();
debug_objects_mem_init();
idr_init_cache();
@@ -725,38 +720,33 @@ int initcall_debug;
core_param(initcall_debug, initcall_debug, bool, 0644);
static char msgbuf[64];
-static struct boot_trace_call call;
-static struct boot_trace_ret ret;
int do_one_initcall(initcall_t fn)
{
int count = preempt_count();
ktime_t calltime, delta, rettime;
+ unsigned long long duration;
+ int ret;
if (initcall_debug) {
- call.caller = task_pid_nr(current);
- printk("calling %pF @ %i\n", fn, call.caller);
+ printk("calling %pF @ %i\n", fn, task_pid_nr(current));
calltime = ktime_get();
- trace_boot_call(&call, fn);
- enable_boot_trace();
}
- ret.result = fn();
+ ret = fn();
if (initcall_debug) {
- disable_boot_trace();
rettime = ktime_get();
delta = ktime_sub(rettime, calltime);
- ret.duration = (unsigned long long) ktime_to_ns(delta) >> 10;
- trace_boot_ret(&ret, fn);
- printk("initcall %pF returned %d after %Ld usecs\n", fn,
- ret.result, ret.duration);
+ duration = (unsigned long long) ktime_to_ns(delta) >> 10;
+ printk("initcall %pF returned %d after %lld usecs\n", fn,
+ ret, duration);
}
msgbuf[0] = 0;
- if (ret.result && ret.result != -ENODEV && initcall_debug)
- sprintf(msgbuf, "error code %d ", ret.result);
+ if (ret && ret != -ENODEV && initcall_debug)
+ sprintf(msgbuf, "error code %d ", ret);
if (preempt_count() != count) {
strlcat(msgbuf, "preemption imbalance ", sizeof(msgbuf));
@@ -770,7 +760,7 @@ int do_one_initcall(initcall_t fn)
printk("initcall %pF returned with %s\n", fn, msgbuf);
}
- return ret.result;
+ return ret;
}
@@ -796,7 +786,6 @@ static void __init do_initcalls(void)
*/
static void __init do_basic_setup(void)
{
- init_workqueues();
cpuset_init_smp();
usermodehelper_init();
init_tmpfs();
@@ -829,7 +818,6 @@ static noinline int init_post(void)
/* need to finish all async __init code before freeing the memory */
async_synchronize_full();
free_initmem();
- unlock_kernel();
mark_rodata_ro();
system_state = SYSTEM_RUNNING;
numa_default_policy();
@@ -869,8 +857,6 @@ static int __init kernel_init(void * unused)
* Wait until kthreadd is all set-up.
*/
wait_for_completion(&kthreadd_done);
- lock_kernel();
-
/*
* init can allocate pages on any node
*/
@@ -894,7 +880,6 @@ static int __init kernel_init(void * unused)
smp_prepare_cpus(setup_max_cpus);
do_pre_smp_initcalls();
- start_boot_trace();
smp_init();
sched_init_smp();
diff --git a/kernel/Makefile b/kernel/Makefile
index 057472fbc27..c53e491e25a 100644
--- a/kernel/Makefile
+++ b/kernel/Makefile
@@ -76,8 +76,8 @@ obj-$(CONFIG_GCOV_KERNEL) += gcov/
obj-$(CONFIG_AUDIT_TREE) += audit_tree.o
obj-$(CONFIG_KPROBES) += kprobes.o
obj-$(CONFIG_KGDB) += debug/
-obj-$(CONFIG_DETECT_SOFTLOCKUP) += softlockup.o
obj-$(CONFIG_DETECT_HUNG_TASK) += hung_task.o
+obj-$(CONFIG_LOCKUP_DETECTOR) += watchdog.o
obj-$(CONFIG_GENERIC_HARDIRQS) += irq/
obj-$(CONFIG_SECCOMP) += seccomp.o
obj-$(CONFIG_RCU_TORTURE_TEST) += rcutorture.o
@@ -99,8 +99,6 @@ obj-$(CONFIG_TRACING) += trace/
obj-$(CONFIG_X86_DS) += trace/
obj-$(CONFIG_RING_BUFFER) += trace/
obj-$(CONFIG_SMP) += sched_cpupri.o
-obj-$(CONFIG_SLOW_WORK) += slow-work.o
-obj-$(CONFIG_SLOW_WORK_DEBUG) += slow-work-debugfs.o
obj-$(CONFIG_PERF_EVENTS) += perf_event.o
obj-$(CONFIG_HAVE_HW_BREAKPOINT) += hw_breakpoint.o
obj-$(CONFIG_USER_RETURN_NOTIFIER) += user-return-notifier.o
diff --git a/kernel/async.c b/kernel/async.c
index 15319d6c18f..cd9dbb913c7 100644
--- a/kernel/async.c
+++ b/kernel/async.c
@@ -49,40 +49,33 @@ asynchronous and synchronous parts of the kernel.
*/
#include <linux/async.h>
-#include <linux/bug.h>
#include <linux/module.h>
#include <linux/wait.h>
#include <linux/sched.h>
-#include <linux/init.h>
-#include <linux/kthread.h>
-#include <linux/delay.h>
#include <linux/slab.h>
+#include <linux/workqueue.h>
#include <asm/atomic.h>
static async_cookie_t next_cookie = 1;
-#define MAX_THREADS 256
#define MAX_WORK 32768
static LIST_HEAD(async_pending);
static LIST_HEAD(async_running);
static DEFINE_SPINLOCK(async_lock);
-static int async_enabled = 0;
-
struct async_entry {
- struct list_head list;
- async_cookie_t cookie;
- async_func_ptr *func;
- void *data;
- struct list_head *running;
+ struct list_head list;
+ struct work_struct work;
+ async_cookie_t cookie;
+ async_func_ptr *func;
+ void *data;
+ struct list_head *running;
};
static DECLARE_WAIT_QUEUE_HEAD(async_done);
-static DECLARE_WAIT_QUEUE_HEAD(async_new);
static atomic_t entry_count;
-static atomic_t thread_count;
extern int initcall_debug;
@@ -117,27 +110,23 @@ static async_cookie_t lowest_in_progress(struct list_head *running)
spin_unlock_irqrestore(&async_lock, flags);
return ret;
}
+
/*
* pick the first pending entry and run it
*/
-static void run_one_entry(void)
+static void async_run_entry_fn(struct work_struct *work)
{
+ struct async_entry *entry =
+ container_of(work, struct async_entry, work);
unsigned long flags;
- struct async_entry *entry;
ktime_t calltime, delta, rettime;
- /* 1) pick one task from the pending queue */
-
+ /* 1) move self to the running queue */
spin_lock_irqsave(&async_lock, flags);
- if (list_empty(&async_pending))
- goto out;
- entry = list_first_entry(&async_pending, struct async_entry, list);
-
- /* 2) move it to the running queue */
list_move_tail(&entry->list, entry->running);
spin_unlock_irqrestore(&async_lock, flags);
- /* 3) run it (and print duration)*/
+ /* 2) run (and print duration) */
if (initcall_debug && system_state == SYSTEM_BOOTING) {
printk("calling %lli_%pF @ %i\n", (long long)entry->cookie,
entry->func, task_pid_nr(current));
@@ -153,31 +142,25 @@ static void run_one_entry(void)
(long long)ktime_to_ns(delta) >> 10);
}
- /* 4) remove it from the running queue */
+ /* 3) remove self from the running queue */
spin_lock_irqsave(&async_lock, flags);
list_del(&entry->list);
- /* 5) free the entry */
+ /* 4) free the entry */
kfree(entry);
atomic_dec(&entry_count);
spin_unlock_irqrestore(&async_lock, flags);
- /* 6) wake up any waiters. */
+ /* 5) wake up any waiters */
wake_up(&async_done);
- return;
-
-out:
- spin_unlock_irqrestore(&async_lock, flags);
}
-
static async_cookie_t __async_schedule(async_func_ptr *ptr, void *data, struct list_head *running)
{
struct async_entry *entry;
unsigned long flags;
async_cookie_t newcookie;
-
/* allow irq-off callers */
entry = kzalloc(sizeof(struct async_entry), GFP_ATOMIC);
@@ -186,7 +169,7 @@ static async_cookie_t __async_schedule(async_func_ptr *ptr, void *data, struct l
* If we're out of memory or if there's too much work
* pending already, we execute synchronously.
*/
- if (!async_enabled || !entry || atomic_read(&entry_count) > MAX_WORK) {
+ if (!entry || atomic_read(&entry_count) > MAX_WORK) {
kfree(entry);
spin_lock_irqsave(&async_lock, flags);
newcookie = next_cookie++;
@@ -196,6 +179,7 @@ static async_cookie_t __async_schedule(async_func_ptr *ptr, void *data, struct l
ptr(data, newcookie);
return newcookie;
}
+ INIT_WORK(&entry->work, async_run_entry_fn);
entry->func = ptr;
entry->data = data;
entry->running = running;
@@ -205,7 +189,10 @@ static async_cookie_t __async_schedule(async_func_ptr *ptr, void *data, struct l
list_add_tail(&entry->list, &async_pending);
atomic_inc(&entry_count);
spin_unlock_irqrestore(&async_lock, flags);
- wake_up(&async_new);
+
+ /* schedule for execution */
+ queue_work(system_unbound_wq, &entry->work);
+
return newcookie;
}
@@ -312,87 +299,3 @@ void async_synchronize_cookie(async_cookie_t cookie)
async_synchronize_cookie_domain(cookie, &async_running);
}
EXPORT_SYMBOL_GPL(async_synchronize_cookie);
-
-
-static int async_thread(void *unused)
-{
- DECLARE_WAITQUEUE(wq, current);
- add_wait_queue(&async_new, &wq);
-
- while (!kthread_should_stop()) {
- int ret = HZ;
- set_current_state(TASK_INTERRUPTIBLE);
- /*
- * check the list head without lock.. false positives
- * are dealt with inside run_one_entry() while holding
- * the lock.
- */
- rmb();
- if (!list_empty(&async_pending))
- run_one_entry();
- else
- ret = schedule_timeout(HZ);
-
- if (ret == 0) {
- /*
- * we timed out, this means we as thread are redundant.
- * we sign off and die, but we to avoid any races there
- * is a last-straw check to see if work snuck in.
- */
- atomic_dec(&thread_count);
- wmb(); /* manager must see our departure first */
- if (list_empty(&async_pending))
- break;
- /*
- * woops work came in between us timing out and us
- * signing off; we need to stay alive and keep working.
- */
- atomic_inc(&thread_count);
- }
- }
- remove_wait_queue(&async_new, &wq);
-
- return 0;
-}
-
-static int async_manager_thread(void *unused)
-{
- DECLARE_WAITQUEUE(wq, current);
- add_wait_queue(&async_new, &wq);
-
- while (!kthread_should_stop()) {
- int tc, ec;
-
- set_current_state(TASK_INTERRUPTIBLE);
-
- tc = atomic_read(&thread_count);
- rmb();
- ec = atomic_read(&entry_count);
-
- while (tc < ec && tc < MAX_THREADS) {
- if (IS_ERR(kthread_run(async_thread, NULL, "async/%i",
- tc))) {
- msleep(100);
- continue;
- }
- atomic_inc(&thread_count);
- tc++;
- }
-
- schedule();
- }
- remove_wait_queue(&async_new, &wq);
-
- return 0;
-}
-
-static int __init async_init(void)
-{
- async_enabled =
- !IS_ERR(kthread_run(async_manager_thread, NULL, "async/mgr"));
-
- WARN_ON(!async_enabled);
- return 0;
-}
-
-core_initcall(async_init);
diff --git a/kernel/audit.c b/kernel/audit.c
index c71bd26631a..8296aa516c5 100644
--- a/kernel/audit.c
+++ b/kernel/audit.c
@@ -407,7 +407,7 @@ static void kauditd_send_skb(struct sk_buff *skb)
audit_hold_skb(skb);
} else
/* drop the extra reference if sent ok */
- kfree_skb(skb);
+ consume_skb(skb);
}
static int kauditd_thread(void *dummy)
diff --git a/kernel/cgroup.c b/kernel/cgroup.c
index 3ac6f5b0a64..d83cab06da8 100644
--- a/kernel/cgroup.c
+++ b/kernel/cgroup.c
@@ -1623,6 +1623,8 @@ static struct file_system_type cgroup_fs_type = {
.kill_sb = cgroup_kill_sb,
};
+static struct kobject *cgroup_kobj;
+
static inline struct cgroup *__d_cgrp(struct dentry *dentry)
{
return dentry->d_fsdata;
@@ -1788,6 +1790,29 @@ out:
return retval;
}
+/**
+ * cgroup_attach_task_current_cg - attach task 'tsk' to current task's cgroup
+ * @tsk: the task to be attached
+ */
+int cgroup_attach_task_current_cg(struct task_struct *tsk)
+{
+ struct cgroupfs_root *root;
+ struct cgroup *cur_cg;
+ int retval = 0;
+
+ cgroup_lock();
+ for_each_active_root(root) {
+ cur_cg = task_cgroup_from_root(current, root);
+ retval = cgroup_attach_task(cur_cg, tsk);
+ if (retval)
+ break;
+ }
+ cgroup_unlock();
+
+ return retval;
+}
+EXPORT_SYMBOL_GPL(cgroup_attach_task_current_cg);
+
/*
* Attach task with pid 'pid' to cgroup 'cgrp'. Call with cgroup_mutex
* held. May take task_lock of task
@@ -3871,9 +3896,18 @@ int __init cgroup_init(void)
hhead = css_set_hash(init_css_set.subsys);
hlist_add_head(&init_css_set.hlist, hhead);
BUG_ON(!init_root_id(&rootnode));
+
+ cgroup_kobj = kobject_create_and_add("cgroup", fs_kobj);
+ if (!cgroup_kobj) {
+ err = -ENOMEM;
+ goto out;
+ }
+
err = register_filesystem(&cgroup_fs_type);
- if (err < 0)
+ if (err < 0) {
+ kobject_put(cgroup_kobj);
goto out;
+ }
proc_create("cgroups", 0, NULL, &proc_cgroupstats_operations);
diff --git a/kernel/cpu.c b/kernel/cpu.c
index 97d1b426a4a..f6e726f1849 100644
--- a/kernel/cpu.c
+++ b/kernel/cpu.c
@@ -235,11 +235,8 @@ static int __ref _cpu_down(unsigned int cpu, int tasks_frozen)
return -EINVAL;
cpu_hotplug_begin();
- set_cpu_active(cpu, false);
err = __cpu_notify(CPU_DOWN_PREPARE | mod, hcpu, -1, &nr_calls);
if (err) {
- set_cpu_active(cpu, true);
-
nr_calls--;
__cpu_notify(CPU_DOWN_FAILED | mod, hcpu, nr_calls, NULL);
printk("%s: attempt to take down CPU %u failed\n",
@@ -249,7 +246,6 @@ static int __ref _cpu_down(unsigned int cpu, int tasks_frozen)
err = __stop_machine(take_cpu_down, &tcd_param, cpumask_of(cpu));
if (err) {
- set_cpu_active(cpu, true);
/* CPU didn't die: tell everyone. Can't complain. */
cpu_notify_nofail(CPU_DOWN_FAILED | mod, hcpu);
@@ -321,8 +317,6 @@ static int __cpuinit _cpu_up(unsigned int cpu, int tasks_frozen)
goto out_notify;
BUG_ON(!cpu_online(cpu));
- set_cpu_active(cpu, true);
-
/* Now call notifier in preparation. */
cpu_notify(CPU_ONLINE | mod, hcpu);
diff --git a/kernel/cpuset.c b/kernel/cpuset.c
index 02b9611eadd..b23c0979bbe 100644
--- a/kernel/cpuset.c
+++ b/kernel/cpuset.c
@@ -105,7 +105,7 @@ struct cpuset {
/* for custom sched domain */
int relax_domain_level;
- /* used for walking a cpuset heirarchy */
+ /* used for walking a cpuset hierarchy */
struct list_head stack_list;
};
@@ -2113,31 +2113,17 @@ static void scan_for_empty_cpusets(struct cpuset *root)
* but making no active use of cpusets.
*
* This routine ensures that top_cpuset.cpus_allowed tracks
- * cpu_online_map on each CPU hotplug (cpuhp) event.
+ * cpu_active_mask on each CPU hotplug (cpuhp) event.
*
* Called within get_online_cpus(). Needs to call cgroup_lock()
* before calling generate_sched_domains().
*/
-static int cpuset_track_online_cpus(struct notifier_block *unused_nb,
- unsigned long phase, void *unused_cpu)
+void cpuset_update_active_cpus(void)
{
struct sched_domain_attr *attr;
cpumask_var_t *doms;
int ndoms;
- switch (phase) {
- case CPU_ONLINE:
- case CPU_ONLINE_FROZEN:
- case CPU_DOWN_PREPARE:
- case CPU_DOWN_PREPARE_FROZEN:
- case CPU_DOWN_FAILED:
- case CPU_DOWN_FAILED_FROZEN:
- break;
-
- default:
- return NOTIFY_DONE;
- }
-
cgroup_lock();
mutex_lock(&callback_mutex);
cpumask_copy(top_cpuset.cpus_allowed, cpu_active_mask);
@@ -2148,8 +2134,6 @@ static int cpuset_track_online_cpus(struct notifier_block *unused_nb,
/* Have scheduler rebuild the domains */
partition_sched_domains(ndoms, doms, attr);
-
- return NOTIFY_OK;
}
#ifdef CONFIG_MEMORY_HOTPLUG
@@ -2203,7 +2187,6 @@ void __init cpuset_init_smp(void)
cpumask_copy(top_cpuset.cpus_allowed, cpu_active_mask);
top_cpuset.mems_allowed = node_states[N_HIGH_MEMORY];
- hotcpu_notifier(cpuset_track_online_cpus, 0);
hotplug_memory_notifier(cpuset_track_online_nodes, 10);
cpuset_wq = create_singlethread_workqueue("cpuset");
diff --git a/kernel/debug/debug_core.c b/kernel/debug/debug_core.c
index 8bc5eeffec8..3c2d4972d23 100644
--- a/kernel/debug/debug_core.c
+++ b/kernel/debug/debug_core.c
@@ -6,7 +6,7 @@
* Copyright (C) 2000-2001 VERITAS Software Corporation.
* Copyright (C) 2002-2004 Timesys Corporation
* Copyright (C) 2003-2004 Amit S. Kale <amitkale@linsyssoft.com>
- * Copyright (C) 2004 Pavel Machek <pavel@suse.cz>
+ * Copyright (C) 2004 Pavel Machek <pavel@ucw.cz>
* Copyright (C) 2004-2006 Tom Rini <trini@kernel.crashing.org>
* Copyright (C) 2004-2006 LinSysSoft Technologies Pvt. Ltd.
* Copyright (C) 2005-2009 Wind River Systems, Inc.
@@ -605,6 +605,8 @@ cpu_master_loop:
if (dbg_kdb_mode) {
kgdb_connected = 1;
error = kdb_stub(ks);
+ if (error == -1)
+ continue;
kgdb_connected = 0;
} else {
error = gdb_serial_stub(ks);
diff --git a/kernel/debug/gdbstub.c b/kernel/debug/gdbstub.c
index e8fd6868682..481a7bd2dfe 100644
--- a/kernel/debug/gdbstub.c
+++ b/kernel/debug/gdbstub.c
@@ -6,7 +6,7 @@
* Copyright (C) 2000-2001 VERITAS Software Corporation.
* Copyright (C) 2002-2004 Timesys Corporation
* Copyright (C) 2003-2004 Amit S. Kale <amitkale@linsyssoft.com>
- * Copyright (C) 2004 Pavel Machek <pavel@suse.cz>
+ * Copyright (C) 2004 Pavel Machek <pavel@ucw.cz>
* Copyright (C) 2004-2006 Tom Rini <trini@kernel.crashing.org>
* Copyright (C) 2004-2006 LinSysSoft Technologies Pvt. Ltd.
* Copyright (C) 2005-2009 Wind River Systems, Inc.
@@ -52,17 +52,6 @@ static unsigned long gdb_regs[(NUMREGBYTES +
* GDB remote protocol parser:
*/
-static int hex(char ch)
-{
- if ((ch >= 'a') && (ch <= 'f'))
- return ch - 'a' + 10;
- if ((ch >= '0') && (ch <= '9'))
- return ch - '0';
- if ((ch >= 'A') && (ch <= 'F'))
- return ch - 'A' + 10;
- return -1;
-}
-
#ifdef CONFIG_KGDB_KDB
static int gdbstub_read_wait(void)
{
@@ -123,8 +112,8 @@ static void get_packet(char *buffer)
buffer[count] = 0;
if (ch == '#') {
- xmitcsum = hex(gdbstub_read_wait()) << 4;
- xmitcsum += hex(gdbstub_read_wait());
+ xmitcsum = hex_to_bin(gdbstub_read_wait()) << 4;
+ xmitcsum += hex_to_bin(gdbstub_read_wait());
if (checksum != xmitcsum)
/* failed checksum */
@@ -236,7 +225,7 @@ void gdbstub_msg_write(const char *s, int len)
* buf. Return a pointer to the last char put in buf (null). May
* return an error.
*/
-int kgdb_mem2hex(char *mem, char *buf, int count)
+char *kgdb_mem2hex(char *mem, char *buf, int count)
{
char *tmp;
int err;
@@ -248,17 +237,16 @@ int kgdb_mem2hex(char *mem, char *buf, int count)
tmp = buf + count;
err = probe_kernel_read(tmp, mem, count);
- if (!err) {
- while (count > 0) {
- buf = pack_hex_byte(buf, *tmp);
- tmp++;
- count--;
- }
-
- *buf = 0;
+ if (err)
+ return NULL;
+ while (count > 0) {
+ buf = pack_hex_byte(buf, *tmp);
+ tmp++;
+ count--;
}
+ *buf = 0;
- return err;
+ return buf;
}
/*
@@ -280,8 +268,8 @@ int kgdb_hex2mem(char *buf, char *mem, int count)
tmp_hex = tmp_raw - 1;
while (tmp_hex >= buf) {
tmp_raw--;
- *tmp_raw = hex(*tmp_hex--);
- *tmp_raw |= hex(*tmp_hex--) << 4;
+ *tmp_raw = hex_to_bin(*tmp_hex--);
+ *tmp_raw |= hex_to_bin(*tmp_hex--) << 4;
}
return probe_kernel_write(mem, tmp_raw, count);
@@ -304,7 +292,7 @@ int kgdb_hex2long(char **ptr, unsigned long *long_val)
(*ptr)++;
}
while (**ptr) {
- hex_val = hex(**ptr);
+ hex_val = hex_to_bin(**ptr);
if (hex_val < 0)
break;
@@ -339,6 +327,32 @@ static int kgdb_ebin2mem(char *buf, char *mem, int count)
return probe_kernel_write(mem, c, size);
}
+#if DBG_MAX_REG_NUM > 0
+void pt_regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *regs)
+{
+ int i;
+ int idx = 0;
+ char *ptr = (char *)gdb_regs;
+
+ for (i = 0; i < DBG_MAX_REG_NUM; i++) {
+ dbg_get_reg(i, ptr + idx, regs);
+ idx += dbg_reg_def[i].size;
+ }
+}
+
+void gdb_regs_to_pt_regs(unsigned long *gdb_regs, struct pt_regs *regs)
+{
+ int i;
+ int idx = 0;
+ char *ptr = (char *)gdb_regs;
+
+ for (i = 0; i < DBG_MAX_REG_NUM; i++) {
+ dbg_set_reg(i, ptr + idx, regs);
+ idx += dbg_reg_def[i].size;
+ }
+}
+#endif /* DBG_MAX_REG_NUM > 0 */
+
/* Write memory due to an 'M' or 'X' packet. */
static int write_mem_msg(int binary)
{
@@ -378,28 +392,31 @@ static void error_packet(char *pkt, int error)
* remapped to negative TIDs.
*/
-#define BUF_THREAD_ID_SIZE 16
+#define BUF_THREAD_ID_SIZE 8
static char *pack_threadid(char *pkt, unsigned char *id)
{
- char *limit;
+ unsigned char *limit;
+ int lzero = 1;
+
+ limit = id + (BUF_THREAD_ID_SIZE / 2);
+ while (id < limit) {
+ if (!lzero || *id != 0) {
+ pkt = pack_hex_byte(pkt, *id);
+ lzero = 0;
+ }
+ id++;
+ }
- limit = pkt + BUF_THREAD_ID_SIZE;
- while (pkt < limit)
- pkt = pack_hex_byte(pkt, *id++);
+ if (lzero)
+ pkt = pack_hex_byte(pkt, 0);
return pkt;
}
static void int_to_threadref(unsigned char *id, int value)
{
- unsigned char *scan;
- int i = 4;
-
- scan = (unsigned char *)id;
- while (i--)
- *scan++ = 0;
- put_unaligned_be32(value, scan);
+ put_unaligned_be32(value, id);
}
static struct task_struct *getthread(struct pt_regs *regs, int tid)
@@ -463,8 +480,7 @@ static void gdb_cmd_status(struct kgdb_state *ks)
pack_hex_byte(&remcom_out_buffer[1], ks->signo);
}
-/* Handle the 'g' get registers request */
-static void gdb_cmd_getregs(struct kgdb_state *ks)
+static void gdb_get_regs_helper(struct kgdb_state *ks)
{
struct task_struct *thread;
void *local_debuggerinfo;
@@ -505,6 +521,12 @@ static void gdb_cmd_getregs(struct kgdb_state *ks)
*/
sleeping_thread_to_gdb_regs(gdb_regs, thread);
}
+}
+
+/* Handle the 'g' get registers request */
+static void gdb_cmd_getregs(struct kgdb_state *ks)
+{
+ gdb_get_regs_helper(ks);
kgdb_mem2hex((char *)gdb_regs, remcom_out_buffer, NUMREGBYTES);
}
@@ -527,13 +549,13 @@ static void gdb_cmd_memread(struct kgdb_state *ks)
char *ptr = &remcom_in_buffer[1];
unsigned long length;
unsigned long addr;
- int err;
+ char *err;
if (kgdb_hex2long(&ptr, &addr) > 0 && *ptr++ == ',' &&
kgdb_hex2long(&ptr, &length) > 0) {
err = kgdb_mem2hex((char *)addr, remcom_out_buffer, length);
- if (err)
- error_packet(remcom_out_buffer, err);
+ if (!err)
+ error_packet(remcom_out_buffer, -EINVAL);
} else {
error_packet(remcom_out_buffer, -EINVAL);
}
@@ -550,6 +572,60 @@ static void gdb_cmd_memwrite(struct kgdb_state *ks)
strcpy(remcom_out_buffer, "OK");
}
+#if DBG_MAX_REG_NUM > 0
+static char *gdb_hex_reg_helper(int regnum, char *out)
+{
+ int i;
+ int offset = 0;
+
+ for (i = 0; i < regnum; i++)
+ offset += dbg_reg_def[i].size;
+ return kgdb_mem2hex((char *)gdb_regs + offset, out,
+ dbg_reg_def[i].size);
+}
+
+/* Handle the 'p' individual regster get */
+static void gdb_cmd_reg_get(struct kgdb_state *ks)
+{
+ unsigned long regnum;
+ char *ptr = &remcom_in_buffer[1];
+
+ kgdb_hex2long(&ptr, &regnum);
+ if (regnum >= DBG_MAX_REG_NUM) {
+ error_packet(remcom_out_buffer, -EINVAL);
+ return;
+ }
+ gdb_get_regs_helper(ks);
+ gdb_hex_reg_helper(regnum, remcom_out_buffer);
+}
+
+/* Handle the 'P' individual regster set */
+static void gdb_cmd_reg_set(struct kgdb_state *ks)
+{
+ unsigned long regnum;
+ char *ptr = &remcom_in_buffer[1];
+ int i = 0;
+
+ kgdb_hex2long(&ptr, &regnum);
+ if (*ptr++ != '=' ||
+ !(!kgdb_usethread || kgdb_usethread == current) ||
+ !dbg_get_reg(regnum, gdb_regs, ks->linux_regs)) {
+ error_packet(remcom_out_buffer, -EINVAL);
+ return;
+ }
+ memset(gdb_regs, 0, sizeof(gdb_regs));
+ while (i < sizeof(gdb_regs) * 2)
+ if (hex_to_bin(ptr[i]) >= 0)
+ i++;
+ else
+ break;
+ i = i / 2;
+ kgdb_hex2mem(ptr, (char *)gdb_regs, i);
+ dbg_set_reg(regnum, gdb_regs, ks->linux_regs);
+ strcpy(remcom_out_buffer, "OK");
+}
+#endif /* DBG_MAX_REG_NUM > 0 */
+
/* Handle the 'X' memory binary write bytes */
static void gdb_cmd_binwrite(struct kgdb_state *ks)
{
@@ -612,7 +688,7 @@ static void gdb_cmd_query(struct kgdb_state *ks)
{
struct task_struct *g;
struct task_struct *p;
- unsigned char thref[8];
+ unsigned char thref[BUF_THREAD_ID_SIZE];
char *ptr;
int i;
int cpu;
@@ -632,8 +708,7 @@ static void gdb_cmd_query(struct kgdb_state *ks)
for_each_online_cpu(cpu) {
ks->thr_query = 0;
int_to_threadref(thref, -cpu - 2);
- pack_threadid(ptr, thref);
- ptr += BUF_THREAD_ID_SIZE;
+ ptr = pack_threadid(ptr, thref);
*(ptr++) = ',';
i++;
}
@@ -642,8 +717,7 @@ static void gdb_cmd_query(struct kgdb_state *ks)
do_each_thread(g, p) {
if (i >= ks->thr_query && !finished) {
int_to_threadref(thref, p->pid);
- pack_threadid(ptr, thref);
- ptr += BUF_THREAD_ID_SIZE;
+ ptr = pack_threadid(ptr, thref);
*(ptr++) = ',';
ks->thr_query++;
if (ks->thr_query % KGDB_MAX_THREAD_QUERY == 0)
@@ -858,11 +932,14 @@ int gdb_serial_stub(struct kgdb_state *ks)
int error = 0;
int tmp;
- /* Clear the out buffer. */
+ /* Initialize comm buffer and globals. */
memset(remcom_out_buffer, 0, sizeof(remcom_out_buffer));
+ kgdb_usethread = kgdb_info[ks->cpu].task;
+ ks->kgdb_usethreadid = shadow_pid(kgdb_info[ks->cpu].task->pid);
+ ks->pass_exception = 0;
if (kgdb_connected) {
- unsigned char thref[8];
+ unsigned char thref[BUF_THREAD_ID_SIZE];
char *ptr;
/* Reply to host that an exception has occurred */
@@ -876,10 +953,6 @@ int gdb_serial_stub(struct kgdb_state *ks)
put_packet(remcom_out_buffer);
}
- kgdb_usethread = kgdb_info[ks->cpu].task;
- ks->kgdb_usethreadid = shadow_pid(kgdb_info[ks->cpu].task->pid);
- ks->pass_exception = 0;
-
while (1) {
error = 0;
@@ -904,6 +977,14 @@ int gdb_serial_stub(struct kgdb_state *ks)
case 'M': /* MAA..AA,LLLL: Write LLLL bytes at address AA..AA */
gdb_cmd_memwrite(ks);
break;
+#if DBG_MAX_REG_NUM > 0
+ case 'p': /* pXX Return gdb register XX (in hex) */
+ gdb_cmd_reg_get(ks);
+ break;
+ case 'P': /* PXX=aaaa Set gdb register XX to aaaa (in hex) */
+ gdb_cmd_reg_set(ks);
+ break;
+#endif /* DBG_MAX_REG_NUM > 0 */
case 'X': /* XAA..AA,LLLL: Write LLLL bytes at address AA..AA */
gdb_cmd_binwrite(ks);
break;
diff --git a/kernel/debug/kdb/kdb_main.c b/kernel/debug/kdb/kdb_main.c
index ebe4a287419..28b844118bb 100644
--- a/kernel/debug/kdb/kdb_main.c
+++ b/kernel/debug/kdb/kdb_main.c
@@ -312,7 +312,7 @@ int kdbgetularg(const char *arg, unsigned long *value)
if (endp == arg) {
/*
- * Try base 16, for us folks too lazy to type the
+ * Also try base 16, for us folks too lazy to type the
* leading 0x...
*/
val = simple_strtoul(arg, &endp, 16);
@@ -325,6 +325,25 @@ int kdbgetularg(const char *arg, unsigned long *value)
return 0;
}
+int kdbgetu64arg(const char *arg, u64 *value)
+{
+ char *endp;
+ u64 val;
+
+ val = simple_strtoull(arg, &endp, 0);
+
+ if (endp == arg) {
+
+ val = simple_strtoull(arg, &endp, 16);
+ if (endp == arg)
+ return KDB_BADINT;
+ }
+
+ *value = val;
+
+ return 0;
+}
+
/*
* kdb_set - This function implements the 'set' command. Alter an
* existing environment variable or create a new one.
@@ -1770,11 +1789,65 @@ static int kdb_go(int argc, const char **argv)
*/
static int kdb_rd(int argc, const char **argv)
{
- int diag = kdb_check_regs();
- if (diag)
- return diag;
+ int len = kdb_check_regs();
+#if DBG_MAX_REG_NUM > 0
+ int i;
+ char *rname;
+ int rsize;
+ u64 reg64;
+ u32 reg32;
+ u16 reg16;
+ u8 reg8;
+
+ if (len)
+ return len;
+
+ for (i = 0; i < DBG_MAX_REG_NUM; i++) {
+ rsize = dbg_reg_def[i].size * 2;
+ if (rsize > 16)
+ rsize = 2;
+ if (len + strlen(dbg_reg_def[i].name) + 4 + rsize > 80) {
+ len = 0;
+ kdb_printf("\n");
+ }
+ if (len)
+ len += kdb_printf(" ");
+ switch(dbg_reg_def[i].size * 8) {
+ case 8:
+ rname = dbg_get_reg(i, &reg8, kdb_current_regs);
+ if (!rname)
+ break;
+ len += kdb_printf("%s: %02x", rname, reg8);
+ break;
+ case 16:
+ rname = dbg_get_reg(i, &reg16, kdb_current_regs);
+ if (!rname)
+ break;
+ len += kdb_printf("%s: %04x", rname, reg16);
+ break;
+ case 32:
+ rname = dbg_get_reg(i, &reg32, kdb_current_regs);
+ if (!rname)
+ break;
+ len += kdb_printf("%s: %08x", rname, reg32);
+ break;
+ case 64:
+ rname = dbg_get_reg(i, &reg64, kdb_current_regs);
+ if (!rname)
+ break;
+ len += kdb_printf("%s: %016llx", rname, reg64);
+ break;
+ default:
+ len += kdb_printf("%s: ??", dbg_reg_def[i].name);
+ }
+ }
+ kdb_printf("\n");
+#else
+ if (len)
+ return len;
kdb_dumpregs(kdb_current_regs);
+#endif
return 0;
}
@@ -1782,32 +1855,67 @@ static int kdb_rd(int argc, const char **argv)
* kdb_rm - This function implements the 'rm' (register modify) command.
* rm register-name new-contents
* Remarks:
- * Currently doesn't allow modification of control or
- * debug registers.
+ * Allows register modification with the same restrictions as gdb
*/
static int kdb_rm(int argc, const char **argv)
{
+#if DBG_MAX_REG_NUM > 0
int diag;
- int ind = 0;
- unsigned long contents;
+ const char *rname;
+ int i;
+ u64 reg64;
+ u32 reg32;
+ u16 reg16;
+ u8 reg8;
if (argc != 2)
return KDB_ARGCOUNT;
/*
* Allow presence or absence of leading '%' symbol.
*/
- if (argv[1][0] == '%')
- ind = 1;
+ rname = argv[1];
+ if (*rname == '%')
+ rname++;
- diag = kdbgetularg(argv[2], &contents);
+ diag = kdbgetu64arg(argv[2], &reg64);
if (diag)
return diag;
diag = kdb_check_regs();
if (diag)
return diag;
+
+ diag = KDB_BADREG;
+ for (i = 0; i < DBG_MAX_REG_NUM; i++) {
+ if (strcmp(rname, dbg_reg_def[i].name) == 0) {
+ diag = 0;
+ break;
+ }
+ }
+ if (!diag) {
+ switch(dbg_reg_def[i].size * 8) {
+ case 8:
+ reg8 = reg64;
+ dbg_set_reg(i, &reg8, kdb_current_regs);
+ break;
+ case 16:
+ reg16 = reg64;
+ dbg_set_reg(i, &reg16, kdb_current_regs);
+ break;
+ case 32:
+ reg32 = reg64;
+ dbg_set_reg(i, &reg32, kdb_current_regs);
+ break;
+ case 64:
+ dbg_set_reg(i, &reg64, kdb_current_regs);
+ break;
+ }
+ }
+ return diag;
+#else
kdb_printf("ERROR: Register set currently not implemented\n");
- return 0;
+ return 0;
+#endif
}
#if defined(CONFIG_MAGIC_SYSRQ)
@@ -2440,6 +2548,7 @@ static void kdb_sysinfo(struct sysinfo *val)
*/
static int kdb_summary(int argc, const char **argv)
{
+ struct timespec now;
struct kdb_tm tm;
struct sysinfo val;
@@ -2454,7 +2563,8 @@ static int kdb_summary(int argc, const char **argv)
kdb_printf("domainname %s\n", init_uts_ns.name.domainname);
kdb_printf("ccversion %s\n", __stringify(CCVERSION));
- kdb_gmtime(&xtime, &tm);
+ now = __current_kernel_time();
+ kdb_gmtime(&now, &tm);
kdb_printf("date %04d-%02d-%02d %02d:%02d:%02d "
"tz_minuteswest %d\n",
1900+tm.tm_year, tm.tm_mon+1, tm.tm_mday,
diff --git a/kernel/debug/kdb/kdb_private.h b/kernel/debug/kdb/kdb_private.h
index 97d3ba69775..c438f545a32 100644
--- a/kernel/debug/kdb/kdb_private.h
+++ b/kernel/debug/kdb/kdb_private.h
@@ -144,9 +144,7 @@ extern int kdb_getword(unsigned long *, unsigned long, size_t);
extern int kdb_putword(unsigned long, unsigned long, size_t);
extern int kdbgetularg(const char *, unsigned long *);
-extern int kdb_set(int, const char **);
extern char *kdbgetenv(const char *);
-extern int kdbgetintenv(const char *, int *);
extern int kdbgetaddrarg(int, const char **, int*, unsigned long *,
long *, char **);
extern int kdbgetsymval(const char *, kdb_symtab_t *);
diff --git a/kernel/fork.c b/kernel/fork.c
index b6cce14ba04..a82a65cef74 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -907,7 +907,7 @@ static void copy_flags(unsigned long clone_flags, struct task_struct *p)
{
unsigned long new_flags = p->flags;
- new_flags &= ~PF_SUPERPRIV;
+ new_flags &= ~(PF_SUPERPRIV | PF_WQ_WORKER);
new_flags |= PF_FORKNOEXEC;
new_flags |= PF_STARTING;
p->flags = new_flags;
diff --git a/kernel/hrtimer.c b/kernel/hrtimer.c
index 5c69e996bd0..ce669174f35 100644
--- a/kernel/hrtimer.c
+++ b/kernel/hrtimer.c
@@ -90,7 +90,7 @@ static void hrtimer_get_softirq_time(struct hrtimer_cpu_base *base)
do {
seq = read_seqbegin(&xtime_lock);
xts = __current_kernel_time();
- tom = wall_to_monotonic;
+ tom = __get_wall_to_monotonic();
} while (read_seqretry(&xtime_lock, seq));
xtim = timespec_to_ktime(xts);
@@ -144,12 +144,8 @@ struct hrtimer_clock_base *lock_hrtimer_base(const struct hrtimer *timer,
static int hrtimer_get_target(int this_cpu, int pinned)
{
#ifdef CONFIG_NO_HZ
- if (!pinned && get_sysctl_timer_migration() && idle_cpu(this_cpu)) {
- int preferred_cpu = get_nohz_load_balancer();
-
- if (preferred_cpu >= 0)
- return preferred_cpu;
- }
+ if (!pinned && get_sysctl_timer_migration() && idle_cpu(this_cpu))
+ return get_nohz_timer_target();
#endif
return this_cpu;
}
@@ -612,7 +608,7 @@ static int hrtimer_reprogram(struct hrtimer *timer,
static void retrigger_next_event(void *arg)
{
struct hrtimer_cpu_base *base;
- struct timespec realtime_offset;
+ struct timespec realtime_offset, wtm;
unsigned long seq;
if (!hrtimer_hres_active())
@@ -620,10 +616,9 @@ static void retrigger_next_event(void *arg)
do {
seq = read_seqbegin(&xtime_lock);
- set_normalized_timespec(&realtime_offset,
- -wall_to_monotonic.tv_sec,
- -wall_to_monotonic.tv_nsec);
+ wtm = __get_wall_to_monotonic();
} while (read_seqretry(&xtime_lock, seq));
+ set_normalized_timespec(&realtime_offset, -wtm.tv_sec, -wtm.tv_nsec);
base = &__get_cpu_var(hrtimer_bases);
diff --git a/kernel/hw_breakpoint.c b/kernel/hw_breakpoint.c
index 7a56b22e060..d71a987fd2b 100644
--- a/kernel/hw_breakpoint.c
+++ b/kernel/hw_breakpoint.c
@@ -41,6 +41,7 @@
#include <linux/sched.h>
#include <linux/init.h>
#include <linux/slab.h>
+#include <linux/list.h>
#include <linux/cpu.h>
#include <linux/smp.h>
@@ -62,6 +63,9 @@ static DEFINE_PER_CPU(unsigned int, nr_bp_flexible[TYPE_MAX]);
static int nr_slots[TYPE_MAX];
+/* Keep track of the breakpoints attached to tasks */
+static LIST_HEAD(bp_task_head);
+
static int constraints_initialized;
/* Gather the number of total pinned and un-pinned bp in a cpuset */
@@ -103,33 +107,21 @@ static unsigned int max_task_bp_pinned(int cpu, enum bp_type_idx type)
return 0;
}
-static int task_bp_pinned(struct task_struct *tsk, enum bp_type_idx type)
+/*
+ * Count the number of breakpoints of the same type and same task.
+ * The given event must be not on the list.
+ */
+static int task_bp_pinned(struct perf_event *bp, enum bp_type_idx type)
{
- struct perf_event_context *ctx = tsk->perf_event_ctxp;
- struct list_head *list;
- struct perf_event *bp;
- unsigned long flags;
+ struct perf_event_context *ctx = bp->ctx;
+ struct perf_event *iter;
int count = 0;
- if (WARN_ONCE(!ctx, "No perf context for this task"))
- return 0;
-
- list = &ctx->event_list;
-
- raw_spin_lock_irqsave(&ctx->lock, flags);
-
- /*
- * The current breakpoint counter is not included in the list
- * at the open() callback time
- */
- list_for_each_entry(bp, list, event_entry) {
- if (bp->attr.type == PERF_TYPE_BREAKPOINT)
- if (find_slot_idx(bp) == type)
- count += hw_breakpoint_weight(bp);
+ list_for_each_entry(iter, &bp_task_head, hw.bp_list) {
+ if (iter->ctx == ctx && find_slot_idx(iter) == type)
+ count += hw_breakpoint_weight(iter);
}
- raw_spin_unlock_irqrestore(&ctx->lock, flags);
-
return count;
}
@@ -149,7 +141,7 @@ fetch_bp_busy_slots(struct bp_busy_slots *slots, struct perf_event *bp,
if (!tsk)
slots->pinned += max_task_bp_pinned(cpu, type);
else
- slots->pinned += task_bp_pinned(tsk, type);
+ slots->pinned += task_bp_pinned(bp, type);
slots->flexible = per_cpu(nr_bp_flexible[type], cpu);
return;
@@ -162,7 +154,7 @@ fetch_bp_busy_slots(struct bp_busy_slots *slots, struct perf_event *bp,
if (!tsk)
nr += max_task_bp_pinned(cpu, type);
else
- nr += task_bp_pinned(tsk, type);
+ nr += task_bp_pinned(bp, type);
if (nr > slots->pinned)
slots->pinned = nr;
@@ -188,7 +180,7 @@ fetch_this_slot(struct bp_busy_slots *slots, int weight)
/*
* Add a pinned breakpoint for the given task in our constraint table
*/
-static void toggle_bp_task_slot(struct task_struct *tsk, int cpu, bool enable,
+static void toggle_bp_task_slot(struct perf_event *bp, int cpu, bool enable,
enum bp_type_idx type, int weight)
{
unsigned int *tsk_pinned;
@@ -196,10 +188,11 @@ static void toggle_bp_task_slot(struct task_struct *tsk, int cpu, bool enable,
int old_idx = 0;
int idx = 0;
- old_count = task_bp_pinned(tsk, type);
+ old_count = task_bp_pinned(bp, type);
old_idx = old_count - 1;
idx = old_idx + weight;
+ /* tsk_pinned[n] is the number of tasks having n breakpoints */
tsk_pinned = per_cpu(nr_task_bp_pinned[type], cpu);
if (enable) {
tsk_pinned[idx]++;
@@ -222,23 +215,41 @@ toggle_bp_slot(struct perf_event *bp, bool enable, enum bp_type_idx type,
int cpu = bp->cpu;
struct task_struct *tsk = bp->ctx->task;
+ /* Pinned counter cpu profiling */
+ if (!tsk) {
+
+ if (enable)
+ per_cpu(nr_cpu_bp_pinned[type], bp->cpu) += weight;
+ else
+ per_cpu(nr_cpu_bp_pinned[type], bp->cpu) -= weight;
+ return;
+ }
+
/* Pinned counter task profiling */
- if (tsk) {
- if (cpu >= 0) {
- toggle_bp_task_slot(tsk, cpu, enable, type, weight);
- return;
- }
+ if (!enable)
+ list_del(&bp->hw.bp_list);
+
+ if (cpu >= 0) {
+ toggle_bp_task_slot(bp, cpu, enable, type, weight);
+ } else {
for_each_online_cpu(cpu)
- toggle_bp_task_slot(tsk, cpu, enable, type, weight);
- return;
+ toggle_bp_task_slot(bp, cpu, enable, type, weight);
}
- /* Pinned counter cpu profiling */
if (enable)
- per_cpu(nr_cpu_bp_pinned[type], bp->cpu) += weight;
- else
- per_cpu(nr_cpu_bp_pinned[type], bp->cpu) -= weight;
+ list_add_tail(&bp->hw.bp_list, &bp_task_head);
+}
+
+/*
+ * Function to perform processor-specific cleanup during unregistration
+ */
+__weak void arch_unregister_hw_breakpoint(struct perf_event *bp)
+{
+ /*
+ * A weak stub function here for those archs that don't define
+ * it inside arch/.../kernel/hw_breakpoint.c
+ */
}
/*
@@ -301,6 +312,10 @@ static int __reserve_bp_slot(struct perf_event *bp)
weight = hw_breakpoint_weight(bp);
fetch_bp_busy_slots(&slots, bp, type);
+ /*
+ * Simulate the addition of this breakpoint to the constraints
+ * and see the result.
+ */
fetch_this_slot(&slots, weight);
/* Flexible counters need to keep at least one slot */
@@ -339,6 +354,7 @@ void release_bp_slot(struct perf_event *bp)
{
mutex_lock(&nr_bp_mutex);
+ arch_unregister_hw_breakpoint(bp);
__release_bp_slot(bp);
mutex_unlock(&nr_bp_mutex);
diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c
index e1497481fe8..c3003e9d91a 100644
--- a/kernel/irq/manage.c
+++ b/kernel/irq/manage.c
@@ -216,7 +216,7 @@ static inline int setup_affinity(unsigned int irq, struct irq_desc *desc)
void __disable_irq(struct irq_desc *desc, unsigned int irq, bool suspend)
{
if (suspend) {
- if (!desc->action || (desc->action->flags & IRQF_TIMER))
+ if (!desc->action || (desc->action->flags & IRQF_NO_SUSPEND))
return;
desc->status |= IRQ_SUSPENDED;
}
diff --git a/kernel/kthread.c b/kernel/kthread.c
index 83911c78017..2dc3786349d 100644
--- a/kernel/kthread.c
+++ b/kernel/kthread.c
@@ -14,6 +14,8 @@
#include <linux/file.h>
#include <linux/module.h>
#include <linux/mutex.h>
+#include <linux/slab.h>
+#include <linux/freezer.h>
#include <trace/events/sched.h>
static DEFINE_SPINLOCK(kthread_create_lock);
@@ -35,6 +37,7 @@ struct kthread_create_info
struct kthread {
int should_stop;
+ void *data;
struct completion exited;
};
@@ -54,6 +57,19 @@ int kthread_should_stop(void)
}
EXPORT_SYMBOL(kthread_should_stop);
+/**
+ * kthread_data - return data value specified on kthread creation
+ * @task: kthread task in question
+ *
+ * Return the data value specified when kthread @task was created.
+ * The caller is responsible for ensuring the validity of @task when
+ * calling this function.
+ */
+void *kthread_data(struct task_struct *task)
+{
+ return to_kthread(task)->data;
+}
+
static int kthread(void *_create)
{
/* Copy data: it's on kthread's stack */
@@ -64,6 +80,7 @@ static int kthread(void *_create)
int ret;
self.should_stop = 0;
+ self.data = data;
init_completion(&self.exited);
current->vfork_done = &self.exited;
@@ -247,3 +264,150 @@ int kthreadd(void *unused)
return 0;
}
+
+/**
+ * kthread_worker_fn - kthread function to process kthread_worker
+ * @worker_ptr: pointer to initialized kthread_worker
+ *
+ * This function can be used as @threadfn to kthread_create() or
+ * kthread_run() with @worker_ptr argument pointing to an initialized
+ * kthread_worker. The started kthread will process work_list until
+ * the it is stopped with kthread_stop(). A kthread can also call
+ * this function directly after extra initialization.
+ *
+ * Different kthreads can be used for the same kthread_worker as long
+ * as there's only one kthread attached to it at any given time. A
+ * kthread_worker without an attached kthread simply collects queued
+ * kthread_works.
+ */
+int kthread_worker_fn(void *worker_ptr)
+{
+ struct kthread_worker *worker = worker_ptr;
+ struct kthread_work *work;
+
+ WARN_ON(worker->task);
+ worker->task = current;
+repeat:
+ set_current_state(TASK_INTERRUPTIBLE); /* mb paired w/ kthread_stop */
+
+ if (kthread_should_stop()) {
+ __set_current_state(TASK_RUNNING);
+ spin_lock_irq(&worker->lock);
+ worker->task = NULL;
+ spin_unlock_irq(&worker->lock);
+ return 0;
+ }
+
+ work = NULL;
+ spin_lock_irq(&worker->lock);
+ if (!list_empty(&worker->work_list)) {
+ work = list_first_entry(&worker->work_list,
+ struct kthread_work, node);
+ list_del_init(&work->node);
+ }
+ spin_unlock_irq(&worker->lock);
+
+ if (work) {
+ __set_current_state(TASK_RUNNING);
+ work->func(work);
+ smp_wmb(); /* wmb worker-b0 paired with flush-b1 */
+ work->done_seq = work->queue_seq;
+ smp_mb(); /* mb worker-b1 paired with flush-b0 */
+ if (atomic_read(&work->flushing))
+ wake_up_all(&work->done);
+ } else if (!freezing(current))
+ schedule();
+
+ try_to_freeze();
+ goto repeat;
+}
+EXPORT_SYMBOL_GPL(kthread_worker_fn);
+
+/**
+ * queue_kthread_work - queue a kthread_work
+ * @worker: target kthread_worker
+ * @work: kthread_work to queue
+ *
+ * Queue @work to work processor @task for async execution. @task
+ * must have been created with kthread_worker_create(). Returns %true
+ * if @work was successfully queued, %false if it was already pending.
+ */
+bool queue_kthread_work(struct kthread_worker *worker,
+ struct kthread_work *work)
+{
+ bool ret = false;
+ unsigned long flags;
+
+ spin_lock_irqsave(&worker->lock, flags);
+ if (list_empty(&work->node)) {
+ list_add_tail(&work->node, &worker->work_list);
+ work->queue_seq++;
+ if (likely(worker->task))
+ wake_up_process(worker->task);
+ ret = true;
+ }
+ spin_unlock_irqrestore(&worker->lock, flags);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(queue_kthread_work);
+
+/**
+ * flush_kthread_work - flush a kthread_work
+ * @work: work to flush
+ *
+ * If @work is queued or executing, wait for it to finish execution.
+ */
+void flush_kthread_work(struct kthread_work *work)
+{
+ int seq = work->queue_seq;
+
+ atomic_inc(&work->flushing);
+
+ /*
+ * mb flush-b0 paired with worker-b1, to make sure either
+ * worker sees the above increment or we see done_seq update.
+ */
+ smp_mb__after_atomic_inc();
+
+ /* A - B <= 0 tests whether B is in front of A regardless of overflow */
+ wait_event(work->done, seq - work->done_seq <= 0);
+ atomic_dec(&work->flushing);
+
+ /*
+ * rmb flush-b1 paired with worker-b0, to make sure our caller
+ * sees every change made by work->func().
+ */
+ smp_mb__after_atomic_dec();
+}
+EXPORT_SYMBOL_GPL(flush_kthread_work);
+
+struct kthread_flush_work {
+ struct kthread_work work;
+ struct completion done;
+};
+
+static void kthread_flush_work_fn(struct kthread_work *work)
+{
+ struct kthread_flush_work *fwork =
+ container_of(work, struct kthread_flush_work, work);
+ complete(&fwork->done);
+}
+
+/**
+ * flush_kthread_worker - flush all current works on a kthread_worker
+ * @worker: worker to flush
+ *
+ * Wait until all currently executing or pending works on @worker are
+ * finished.
+ */
+void flush_kthread_worker(struct kthread_worker *worker)
+{
+ struct kthread_flush_work fwork = {
+ KTHREAD_WORK_INIT(fwork.work, kthread_flush_work_fn),
+ COMPLETION_INITIALIZER_ONSTACK(fwork.done),
+ };
+
+ queue_kthread_work(worker, &fwork.work);
+ wait_for_completion(&fwork.done);
+}
+EXPORT_SYMBOL_GPL(flush_kthread_worker);
diff --git a/kernel/lockdep.c b/kernel/lockdep.c
index 54286798c37..f2852a51023 100644
--- a/kernel/lockdep.c
+++ b/kernel/lockdep.c
@@ -146,7 +146,7 @@ static DEFINE_PER_CPU(struct lock_class_stats[MAX_LOCKDEP_KEYS],
static inline u64 lockstat_clock(void)
{
- return cpu_clock(smp_processor_id());
+ return local_clock();
}
static int lock_point(unsigned long points[], unsigned long ip)
diff --git a/kernel/module.c b/kernel/module.c
index 6c562828c85..d0b5f8db11b 100644
--- a/kernel/module.c
+++ b/kernel/module.c
@@ -1,6 +1,6 @@
/*
Copyright (C) 2002 Richard Henderson
- Copyright (C) 2001 Rusty Russell, 2002 Rusty Russell IBM.
+ Copyright (C) 2001 Rusty Russell, 2002, 2010 Rusty Russell IBM.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -110,6 +110,20 @@ int unregister_module_notifier(struct notifier_block * nb)
}
EXPORT_SYMBOL(unregister_module_notifier);
+struct load_info {
+ Elf_Ehdr *hdr;
+ unsigned long len;
+ Elf_Shdr *sechdrs;
+ char *secstrings, *strtab;
+ unsigned long *strmap;
+ unsigned long symoffs, stroffs;
+ struct _ddebug *debug;
+ unsigned int num_debug;
+ struct {
+ unsigned int sym, str, mod, vers, info, pcpu;
+ } index;
+};
+
/* We require a truly strong try_module_get(): 0 means failure due to
ongoing or failed initialization etc. */
static inline int strong_try_module_get(struct module *mod)
@@ -140,42 +154,38 @@ void __module_put_and_exit(struct module *mod, long code)
EXPORT_SYMBOL(__module_put_and_exit);
/* Find a module section: 0 means not found. */
-static unsigned int find_sec(Elf_Ehdr *hdr,
- Elf_Shdr *sechdrs,
- const char *secstrings,
- const char *name)
+static unsigned int find_sec(const struct load_info *info, const char *name)
{
unsigned int i;
- for (i = 1; i < hdr->e_shnum; i++)
+ for (i = 1; i < info->hdr->e_shnum; i++) {
+ Elf_Shdr *shdr = &info->sechdrs[i];
/* Alloc bit cleared means "ignore it." */
- if ((sechdrs[i].sh_flags & SHF_ALLOC)
- && strcmp(secstrings+sechdrs[i].sh_name, name) == 0)
+ if ((shdr->sh_flags & SHF_ALLOC)
+ && strcmp(info->secstrings + shdr->sh_name, name) == 0)
return i;
+ }
return 0;
}
/* Find a module section, or NULL. */
-static void *section_addr(Elf_Ehdr *hdr, Elf_Shdr *shdrs,
- const char *secstrings, const char *name)
+static void *section_addr(const struct load_info *info, const char *name)
{
/* Section 0 has sh_addr 0. */
- return (void *)shdrs[find_sec(hdr, shdrs, secstrings, name)].sh_addr;
+ return (void *)info->sechdrs[find_sec(info, name)].sh_addr;
}
/* Find a module section, or NULL. Fill in number of "objects" in section. */
-static void *section_objs(Elf_Ehdr *hdr,
- Elf_Shdr *sechdrs,
- const char *secstrings,
+static void *section_objs(const struct load_info *info,
const char *name,
size_t object_size,
unsigned int *num)
{
- unsigned int sec = find_sec(hdr, sechdrs, secstrings, name);
+ unsigned int sec = find_sec(info, name);
/* Section 0 has sh_addr 0 and sh_size 0. */
- *num = sechdrs[sec].sh_size / object_size;
- return (void *)sechdrs[sec].sh_addr;
+ *num = info->sechdrs[sec].sh_size / object_size;
+ return (void *)info->sechdrs[sec].sh_addr;
}
/* Provided by the linker */
@@ -227,7 +237,7 @@ bool each_symbol(bool (*fn)(const struct symsearch *arr, struct module *owner,
unsigned int symnum, void *data), void *data)
{
struct module *mod;
- const struct symsearch arr[] = {
+ static const struct symsearch arr[] = {
{ __start___ksymtab, __stop___ksymtab, __start___kcrctab,
NOT_GPL_ONLY, false },
{ __start___ksymtab_gpl, __stop___ksymtab_gpl,
@@ -392,7 +402,8 @@ static int percpu_modalloc(struct module *mod,
mod->percpu = __alloc_reserved_percpu(size, align);
if (!mod->percpu) {
printk(KERN_WARNING
- "Could not allocate %lu bytes percpu data\n", size);
+ "%s: Could not allocate %lu bytes percpu data\n",
+ mod->name, size);
return -ENOMEM;
}
mod->percpu_size = size;
@@ -404,11 +415,9 @@ static void percpu_modfree(struct module *mod)
free_percpu(mod->percpu);
}
-static unsigned int find_pcpusec(Elf_Ehdr *hdr,
- Elf_Shdr *sechdrs,
- const char *secstrings)
+static unsigned int find_pcpusec(struct load_info *info)
{
- return find_sec(hdr, sechdrs, secstrings, ".data..percpu");
+ return find_sec(info, ".data..percpu");
}
static void percpu_modcopy(struct module *mod,
@@ -468,9 +477,7 @@ static inline int percpu_modalloc(struct module *mod,
static inline void percpu_modfree(struct module *mod)
{
}
-static inline unsigned int find_pcpusec(Elf_Ehdr *hdr,
- Elf_Shdr *sechdrs,
- const char *secstrings)
+static unsigned int find_pcpusec(struct load_info *info)
{
return 0;
}
@@ -524,21 +531,21 @@ static char last_unloaded_module[MODULE_NAME_LEN+1];
EXPORT_TRACEPOINT_SYMBOL(module_get);
/* Init the unload section of the module. */
-static void module_unload_init(struct module *mod)
+static int module_unload_init(struct module *mod)
{
- int cpu;
+ mod->refptr = alloc_percpu(struct module_ref);
+ if (!mod->refptr)
+ return -ENOMEM;
INIT_LIST_HEAD(&mod->source_list);
INIT_LIST_HEAD(&mod->target_list);
- for_each_possible_cpu(cpu) {
- per_cpu_ptr(mod->refptr, cpu)->incs = 0;
- per_cpu_ptr(mod->refptr, cpu)->decs = 0;
- }
/* Hold reference count during initialization. */
__this_cpu_write(mod->refptr->incs, 1);
/* Backwards compatibility macros put refcount during init. */
mod->waiter = current;
+
+ return 0;
}
/* Does a already use b? */
@@ -618,6 +625,8 @@ static void module_unload_free(struct module *mod)
kfree(use);
}
mutex_unlock(&module_mutex);
+
+ free_percpu(mod->refptr);
}
#ifdef CONFIG_MODULE_FORCE_UNLOAD
@@ -891,8 +900,9 @@ int ref_module(struct module *a, struct module *b)
}
EXPORT_SYMBOL_GPL(ref_module);
-static inline void module_unload_init(struct module *mod)
+static inline int module_unload_init(struct module *mod)
{
+ return 0;
}
#endif /* CONFIG_MODULE_UNLOAD */
@@ -1051,10 +1061,9 @@ static inline int same_magic(const char *amagic, const char *bmagic,
#endif /* CONFIG_MODVERSIONS */
/* Resolve a symbol for this module. I.e. if we find one, record usage. */
-static const struct kernel_symbol *resolve_symbol(Elf_Shdr *sechdrs,
- unsigned int versindex,
+static const struct kernel_symbol *resolve_symbol(struct module *mod,
+ const struct load_info *info,
const char *name,
- struct module *mod,
char ownername[])
{
struct module *owner;
@@ -1068,7 +1077,8 @@ static const struct kernel_symbol *resolve_symbol(Elf_Shdr *sechdrs,
if (!sym)
goto unlock;
- if (!check_version(sechdrs, versindex, name, mod, crc, owner)) {
+ if (!check_version(info->sechdrs, info->index.vers, name, mod, crc,
+ owner)) {
sym = ERR_PTR(-EINVAL);
goto getname;
}
@@ -1087,21 +1097,20 @@ unlock:
return sym;
}
-static const struct kernel_symbol *resolve_symbol_wait(Elf_Shdr *sechdrs,
- unsigned int versindex,
- const char *name,
- struct module *mod)
+static const struct kernel_symbol *
+resolve_symbol_wait(struct module *mod,
+ const struct load_info *info,
+ const char *name)
{
const struct kernel_symbol *ksym;
- char ownername[MODULE_NAME_LEN];
+ char owner[MODULE_NAME_LEN];
if (wait_event_interruptible_timeout(module_wq,
- !IS_ERR(ksym = resolve_symbol(sechdrs, versindex, name,
- mod, ownername)) ||
- PTR_ERR(ksym) != -EBUSY,
+ !IS_ERR(ksym = resolve_symbol(mod, info, name, owner))
+ || PTR_ERR(ksym) != -EBUSY,
30 * HZ) <= 0) {
printk(KERN_WARNING "%s: gave up waiting for init of module %s.\n",
- mod->name, ownername);
+ mod->name, owner);
}
return ksym;
}
@@ -1110,8 +1119,9 @@ static const struct kernel_symbol *resolve_symbol_wait(Elf_Shdr *sechdrs,
* /sys/module/foo/sections stuff
* J. Corbet <corbet@lwn.net>
*/
-#if defined(CONFIG_KALLSYMS) && defined(CONFIG_SYSFS)
+#ifdef CONFIG_SYSFS
+#ifdef CONFIG_KALLSYMS
static inline bool sect_empty(const Elf_Shdr *sect)
{
return !(sect->sh_flags & SHF_ALLOC) || sect->sh_size == 0;
@@ -1148,8 +1158,7 @@ static void free_sect_attrs(struct module_sect_attrs *sect_attrs)
kfree(sect_attrs);
}
-static void add_sect_attrs(struct module *mod, unsigned int nsect,
- char *secstrings, Elf_Shdr *sechdrs)
+static void add_sect_attrs(struct module *mod, const struct load_info *info)
{
unsigned int nloaded = 0, i, size[2];
struct module_sect_attrs *sect_attrs;
@@ -1157,8 +1166,8 @@ static void add_sect_attrs(struct module *mod, unsigned int nsect,
struct attribute **gattr;
/* Count loaded sections and allocate structures */
- for (i = 0; i < nsect; i++)
- if (!sect_empty(&sechdrs[i]))
+ for (i = 0; i < info->hdr->e_shnum; i++)
+ if (!sect_empty(&info->sechdrs[i]))
nloaded++;
size[0] = ALIGN(sizeof(*sect_attrs)
+ nloaded * sizeof(sect_attrs->attrs[0]),
@@ -1175,11 +1184,12 @@ static void add_sect_attrs(struct module *mod, unsigned int nsect,
sect_attrs->nsections = 0;
sattr = &sect_attrs->attrs[0];
gattr = &sect_attrs->grp.attrs[0];
- for (i = 0; i < nsect; i++) {
- if (sect_empty(&sechdrs[i]))
+ for (i = 0; i < info->hdr->e_shnum; i++) {
+ Elf_Shdr *sec = &info->sechdrs[i];
+ if (sect_empty(sec))
continue;
- sattr->address = sechdrs[i].sh_addr;
- sattr->name = kstrdup(secstrings + sechdrs[i].sh_name,
+ sattr->address = sec->sh_addr;
+ sattr->name = kstrdup(info->secstrings + sec->sh_name,
GFP_KERNEL);
if (sattr->name == NULL)
goto out;
@@ -1247,8 +1257,7 @@ static void free_notes_attrs(struct module_notes_attrs *notes_attrs,
kfree(notes_attrs);
}
-static void add_notes_attrs(struct module *mod, unsigned int nsect,
- char *secstrings, Elf_Shdr *sechdrs)
+static void add_notes_attrs(struct module *mod, const struct load_info *info)
{
unsigned int notes, loaded, i;
struct module_notes_attrs *notes_attrs;
@@ -1260,9 +1269,9 @@ static void add_notes_attrs(struct module *mod, unsigned int nsect,
/* Count notes sections and allocate structures. */
notes = 0;
- for (i = 0; i < nsect; i++)
- if (!sect_empty(&sechdrs[i]) &&
- (sechdrs[i].sh_type == SHT_NOTE))
+ for (i = 0; i < info->hdr->e_shnum; i++)
+ if (!sect_empty(&info->sechdrs[i]) &&
+ (info->sechdrs[i].sh_type == SHT_NOTE))
++notes;
if (notes == 0)
@@ -1276,15 +1285,15 @@ static void add_notes_attrs(struct module *mod, unsigned int nsect,
notes_attrs->notes = notes;
nattr = &notes_attrs->attrs[0];
- for (loaded = i = 0; i < nsect; ++i) {
- if (sect_empty(&sechdrs[i]))
+ for (loaded = i = 0; i < info->hdr->e_shnum; ++i) {
+ if (sect_empty(&info->sechdrs[i]))
continue;
- if (sechdrs[i].sh_type == SHT_NOTE) {
+ if (info->sechdrs[i].sh_type == SHT_NOTE) {
sysfs_bin_attr_init(nattr);
nattr->attr.name = mod->sect_attrs->attrs[loaded].name;
nattr->attr.mode = S_IRUGO;
- nattr->size = sechdrs[i].sh_size;
- nattr->private = (void *) sechdrs[i].sh_addr;
+ nattr->size = info->sechdrs[i].sh_size;
+ nattr->private = (void *) info->sechdrs[i].sh_addr;
nattr->read = module_notes_read;
++nattr;
}
@@ -1315,8 +1324,8 @@ static void remove_notes_attrs(struct module *mod)
#else
-static inline void add_sect_attrs(struct module *mod, unsigned int nsect,
- char *sectstrings, Elf_Shdr *sechdrs)
+static inline void add_sect_attrs(struct module *mod,
+ const struct load_info *info)
{
}
@@ -1324,17 +1333,16 @@ static inline void remove_sect_attrs(struct module *mod)
{
}
-static inline void add_notes_attrs(struct module *mod, unsigned int nsect,
- char *sectstrings, Elf_Shdr *sechdrs)
+static inline void add_notes_attrs(struct module *mod,
+ const struct load_info *info)
{
}
static inline void remove_notes_attrs(struct module *mod)
{
}
-#endif
+#endif /* CONFIG_KALLSYMS */
-#ifdef CONFIG_SYSFS
static void add_usage_links(struct module *mod)
{
#ifdef CONFIG_MODULE_UNLOAD
@@ -1439,6 +1447,7 @@ out:
}
static int mod_sysfs_setup(struct module *mod,
+ const struct load_info *info,
struct kernel_param *kparam,
unsigned int num_params)
{
@@ -1463,6 +1472,8 @@ static int mod_sysfs_setup(struct module *mod,
goto out_unreg_param;
add_usage_links(mod);
+ add_sect_attrs(mod, info);
+ add_notes_attrs(mod, info);
kobject_uevent(&mod->mkobj.kobj, KOBJ_ADD);
return 0;
@@ -1479,33 +1490,26 @@ out:
static void mod_sysfs_fini(struct module *mod)
{
+ remove_notes_attrs(mod);
+ remove_sect_attrs(mod);
kobject_put(&mod->mkobj.kobj);
}
-#else /* CONFIG_SYSFS */
-
-static inline int mod_sysfs_init(struct module *mod)
-{
- return 0;
-}
+#else /* !CONFIG_SYSFS */
-static inline int mod_sysfs_setup(struct module *mod,
+static int mod_sysfs_setup(struct module *mod,
+ const struct load_info *info,
struct kernel_param *kparam,
unsigned int num_params)
{
return 0;
}
-static inline int module_add_modinfo_attrs(struct module *mod)
-{
- return 0;
-}
-
-static inline void module_remove_modinfo_attrs(struct module *mod)
+static void mod_sysfs_fini(struct module *mod)
{
}
-static void mod_sysfs_fini(struct module *mod)
+static void module_remove_modinfo_attrs(struct module *mod)
{
}
@@ -1515,7 +1519,7 @@ static void del_usage_links(struct module *mod)
#endif /* CONFIG_SYSFS */
-static void mod_kobject_remove(struct module *mod)
+static void mod_sysfs_teardown(struct module *mod)
{
del_usage_links(mod);
module_remove_modinfo_attrs(mod);
@@ -1545,9 +1549,7 @@ static void free_module(struct module *mod)
mutex_lock(&module_mutex);
stop_machine(__unlink_module, mod, NULL);
mutex_unlock(&module_mutex);
- remove_notes_attrs(mod);
- remove_sect_attrs(mod);
- mod_kobject_remove(mod);
+ mod_sysfs_teardown(mod);
/* Remove dynamic debug info */
ddebug_remove_module(mod->name);
@@ -1565,10 +1567,7 @@ static void free_module(struct module *mod)
module_free(mod, mod->module_init);
kfree(mod->args);
percpu_modfree(mod);
-#if defined(CONFIG_MODULE_UNLOAD)
- if (mod->refptr)
- free_percpu(mod->refptr);
-#endif
+
/* Free lock-classes: */
lockdep_free_key_range(mod->module_core, mod->core_size);
@@ -1634,25 +1633,23 @@ static int verify_export_symbols(struct module *mod)
}
/* Change all symbols so that st_value encodes the pointer directly. */
-static int simplify_symbols(Elf_Shdr *sechdrs,
- unsigned int symindex,
- const char *strtab,
- unsigned int versindex,
- unsigned int pcpuindex,
- struct module *mod)
-{
- Elf_Sym *sym = (void *)sechdrs[symindex].sh_addr;
+static int simplify_symbols(struct module *mod, const struct load_info *info)
+{
+ Elf_Shdr *symsec = &info->sechdrs[info->index.sym];
+ Elf_Sym *sym = (void *)symsec->sh_addr;
unsigned long secbase;
- unsigned int i, n = sechdrs[symindex].sh_size / sizeof(Elf_Sym);
+ unsigned int i;
int ret = 0;
const struct kernel_symbol *ksym;
- for (i = 1; i < n; i++) {
+ for (i = 1; i < symsec->sh_size / sizeof(Elf_Sym); i++) {
+ const char *name = info->strtab + sym[i].st_name;
+
switch (sym[i].st_shndx) {
case SHN_COMMON:
/* We compiled with -fno-common. These are not
supposed to happen. */
- DEBUGP("Common symbol: %s\n", strtab + sym[i].st_name);
+ DEBUGP("Common symbol: %s\n", name);
printk("%s: please compile with -fno-common\n",
mod->name);
ret = -ENOEXEC;
@@ -1665,9 +1662,7 @@ static int simplify_symbols(Elf_Shdr *sechdrs,
break;
case SHN_UNDEF:
- ksym = resolve_symbol_wait(sechdrs, versindex,
- strtab + sym[i].st_name,
- mod);
+ ksym = resolve_symbol_wait(mod, info, name);
/* Ok if resolved. */
if (ksym && !IS_ERR(ksym)) {
sym[i].st_value = ksym->value;
@@ -1679,17 +1674,16 @@ static int simplify_symbols(Elf_Shdr *sechdrs,
break;
printk(KERN_WARNING "%s: Unknown symbol %s (err %li)\n",
- mod->name, strtab + sym[i].st_name,
- PTR_ERR(ksym));
+ mod->name, name, PTR_ERR(ksym));
ret = PTR_ERR(ksym) ?: -ENOENT;
break;
default:
/* Divert to percpu allocation if a percpu var. */
- if (sym[i].st_shndx == pcpuindex)
+ if (sym[i].st_shndx == info->index.pcpu)
secbase = (unsigned long)mod_percpu(mod);
else
- secbase = sechdrs[sym[i].st_shndx].sh_addr;
+ secbase = info->sechdrs[sym[i].st_shndx].sh_addr;
sym[i].st_value += secbase;
break;
}
@@ -1698,6 +1692,35 @@ static int simplify_symbols(Elf_Shdr *sechdrs,
return ret;
}
+static int apply_relocations(struct module *mod, const struct load_info *info)
+{
+ unsigned int i;
+ int err = 0;
+
+ /* Now do relocations. */
+ for (i = 1; i < info->hdr->e_shnum; i++) {
+ unsigned int infosec = info->sechdrs[i].sh_info;
+
+ /* Not a valid relocation section? */
+ if (infosec >= info->hdr->e_shnum)
+ continue;
+
+ /* Don't bother with non-allocated sections */
+ if (!(info->sechdrs[infosec].sh_flags & SHF_ALLOC))
+ continue;
+
+ if (info->sechdrs[i].sh_type == SHT_REL)
+ err = apply_relocate(info->sechdrs, info->strtab,
+ info->index.sym, i, mod);
+ else if (info->sechdrs[i].sh_type == SHT_RELA)
+ err = apply_relocate_add(info->sechdrs, info->strtab,
+ info->index.sym, i, mod);
+ if (err < 0)
+ break;
+ }
+ return err;
+}
+
/* Additional bytes needed by arch in front of individual sections */
unsigned int __weak arch_mod_section_prepend(struct module *mod,
unsigned int section)
@@ -1722,10 +1745,7 @@ static long get_offset(struct module *mod, unsigned int *size,
might -- code, read-only data, read-write data, small data. Tally
sizes, and place the offsets into sh_entsize fields: high bit means it
belongs in init. */
-static void layout_sections(struct module *mod,
- const Elf_Ehdr *hdr,
- Elf_Shdr *sechdrs,
- const char *secstrings)
+static void layout_sections(struct module *mod, struct load_info *info)
{
static unsigned long const masks[][2] = {
/* NOTE: all executable code must be the first section
@@ -1738,21 +1758,22 @@ static void layout_sections(struct module *mod,
};
unsigned int m, i;
- for (i = 0; i < hdr->e_shnum; i++)
- sechdrs[i].sh_entsize = ~0UL;
+ for (i = 0; i < info->hdr->e_shnum; i++)
+ info->sechdrs[i].sh_entsize = ~0UL;
DEBUGP("Core section allocation order:\n");
for (m = 0; m < ARRAY_SIZE(masks); ++m) {
- for (i = 0; i < hdr->e_shnum; ++i) {
- Elf_Shdr *s = &sechdrs[i];
+ for (i = 0; i < info->hdr->e_shnum; ++i) {
+ Elf_Shdr *s = &info->sechdrs[i];
+ const char *sname = info->secstrings + s->sh_name;
if ((s->sh_flags & masks[m][0]) != masks[m][0]
|| (s->sh_flags & masks[m][1])
|| s->sh_entsize != ~0UL
- || strstarts(secstrings + s->sh_name, ".init"))
+ || strstarts(sname, ".init"))
continue;
s->sh_entsize = get_offset(mod, &mod->core_size, s, i);
- DEBUGP("\t%s\n", secstrings + s->sh_name);
+ DEBUGP("\t%s\n", name);
}
if (m == 0)
mod->core_text_size = mod->core_size;
@@ -1760,17 +1781,18 @@ static void layout_sections(struct module *mod,
DEBUGP("Init section allocation order:\n");
for (m = 0; m < ARRAY_SIZE(masks); ++m) {
- for (i = 0; i < hdr->e_shnum; ++i) {
- Elf_Shdr *s = &sechdrs[i];
+ for (i = 0; i < info->hdr->e_shnum; ++i) {
+ Elf_Shdr *s = &info->sechdrs[i];
+ const char *sname = info->secstrings + s->sh_name;
if ((s->sh_flags & masks[m][0]) != masks[m][0]
|| (s->sh_flags & masks[m][1])
|| s->sh_entsize != ~0UL
- || !strstarts(secstrings + s->sh_name, ".init"))
+ || !strstarts(sname, ".init"))
continue;
s->sh_entsize = (get_offset(mod, &mod->init_size, s, i)
| INIT_OFFSET_MASK);
- DEBUGP("\t%s\n", secstrings + s->sh_name);
+ DEBUGP("\t%s\n", sname);
}
if (m == 0)
mod->init_text_size = mod->init_size;
@@ -1809,33 +1831,28 @@ static char *next_string(char *string, unsigned long *secsize)
return string;
}
-static char *get_modinfo(Elf_Shdr *sechdrs,
- unsigned int info,
- const char *tag)
+static char *get_modinfo(struct load_info *info, const char *tag)
{
char *p;
unsigned int taglen = strlen(tag);
- unsigned long size = sechdrs[info].sh_size;
+ Elf_Shdr *infosec = &info->sechdrs[info->index.info];
+ unsigned long size = infosec->sh_size;
- for (p = (char *)sechdrs[info].sh_addr; p; p = next_string(p, &size)) {
+ for (p = (char *)infosec->sh_addr; p; p = next_string(p, &size)) {
if (strncmp(p, tag, taglen) == 0 && p[taglen] == '=')
return p + taglen + 1;
}
return NULL;
}
-static void setup_modinfo(struct module *mod, Elf_Shdr *sechdrs,
- unsigned int infoindex)
+static void setup_modinfo(struct module *mod, struct load_info *info)
{
struct module_attribute *attr;
int i;
for (i = 0; (attr = modinfo_attrs[i]); i++) {
if (attr->setup)
- attr->setup(mod,
- get_modinfo(sechdrs,
- infoindex,
- attr->attr.name));
+ attr->setup(mod, get_modinfo(info, attr->attr.name));
}
}
@@ -1876,11 +1893,10 @@ static int is_exported(const char *name, unsigned long value,
}
/* As per nm */
-static char elf_type(const Elf_Sym *sym,
- Elf_Shdr *sechdrs,
- const char *secstrings,
- struct module *mod)
+static char elf_type(const Elf_Sym *sym, const struct load_info *info)
{
+ const Elf_Shdr *sechdrs = info->sechdrs;
+
if (ELF_ST_BIND(sym->st_info) == STB_WEAK) {
if (ELF_ST_TYPE(sym->st_info) == STT_OBJECT)
return 'v';
@@ -1910,8 +1926,10 @@ static char elf_type(const Elf_Sym *sym,
else
return 'b';
}
- if (strstarts(secstrings + sechdrs[sym->st_shndx].sh_name, ".debug"))
+ if (strstarts(info->secstrings + sechdrs[sym->st_shndx].sh_name,
+ ".debug")) {
return 'n';
+ }
return '?';
}
@@ -1936,127 +1954,96 @@ static bool is_core_symbol(const Elf_Sym *src, const Elf_Shdr *sechdrs,
return true;
}
-static unsigned long layout_symtab(struct module *mod,
- Elf_Shdr *sechdrs,
- unsigned int symindex,
- unsigned int strindex,
- const Elf_Ehdr *hdr,
- const char *secstrings,
- unsigned long *pstroffs,
- unsigned long *strmap)
+static void layout_symtab(struct module *mod, struct load_info *info)
{
- unsigned long symoffs;
- Elf_Shdr *symsect = sechdrs + symindex;
- Elf_Shdr *strsect = sechdrs + strindex;
+ Elf_Shdr *symsect = info->sechdrs + info->index.sym;
+ Elf_Shdr *strsect = info->sechdrs + info->index.str;
const Elf_Sym *src;
- const char *strtab;
unsigned int i, nsrc, ndst;
/* Put symbol section at end of init part of module. */
symsect->sh_flags |= SHF_ALLOC;
symsect->sh_entsize = get_offset(mod, &mod->init_size, symsect,
- symindex) | INIT_OFFSET_MASK;
- DEBUGP("\t%s\n", secstrings + symsect->sh_name);
+ info->index.sym) | INIT_OFFSET_MASK;
+ DEBUGP("\t%s\n", info->secstrings + symsect->sh_name);
- src = (void *)hdr + symsect->sh_offset;
+ src = (void *)info->hdr + symsect->sh_offset;
nsrc = symsect->sh_size / sizeof(*src);
- strtab = (void *)hdr + strsect->sh_offset;
for (ndst = i = 1; i < nsrc; ++i, ++src)
- if (is_core_symbol(src, sechdrs, hdr->e_shnum)) {
+ if (is_core_symbol(src, info->sechdrs, info->hdr->e_shnum)) {
unsigned int j = src->st_name;
- while(!__test_and_set_bit(j, strmap) && strtab[j])
+ while (!__test_and_set_bit(j, info->strmap)
+ && info->strtab[j])
++j;
++ndst;
}
/* Append room for core symbols at end of core part. */
- symoffs = ALIGN(mod->core_size, symsect->sh_addralign ?: 1);
- mod->core_size = symoffs + ndst * sizeof(Elf_Sym);
+ info->symoffs = ALIGN(mod->core_size, symsect->sh_addralign ?: 1);
+ mod->core_size = info->symoffs + ndst * sizeof(Elf_Sym);
/* Put string table section at end of init part of module. */
strsect->sh_flags |= SHF_ALLOC;
strsect->sh_entsize = get_offset(mod, &mod->init_size, strsect,
- strindex) | INIT_OFFSET_MASK;
- DEBUGP("\t%s\n", secstrings + strsect->sh_name);
+ info->index.str) | INIT_OFFSET_MASK;
+ DEBUGP("\t%s\n", info->secstrings + strsect->sh_name);
/* Append room for core symbols' strings at end of core part. */
- *pstroffs = mod->core_size;
- __set_bit(0, strmap);
- mod->core_size += bitmap_weight(strmap, strsect->sh_size);
-
- return symoffs;
+ info->stroffs = mod->core_size;
+ __set_bit(0, info->strmap);
+ mod->core_size += bitmap_weight(info->strmap, strsect->sh_size);
}
-static void add_kallsyms(struct module *mod,
- Elf_Shdr *sechdrs,
- unsigned int shnum,
- unsigned int symindex,
- unsigned int strindex,
- unsigned long symoffs,
- unsigned long stroffs,
- const char *secstrings,
- unsigned long *strmap)
+static void add_kallsyms(struct module *mod, const struct load_info *info)
{
unsigned int i, ndst;
const Elf_Sym *src;
Elf_Sym *dst;
char *s;
+ Elf_Shdr *symsec = &info->sechdrs[info->index.sym];
- mod->symtab = (void *)sechdrs[symindex].sh_addr;
- mod->num_symtab = sechdrs[symindex].sh_size / sizeof(Elf_Sym);
- mod->strtab = (void *)sechdrs[strindex].sh_addr;
+ mod->symtab = (void *)symsec->sh_addr;
+ mod->num_symtab = symsec->sh_size / sizeof(Elf_Sym);
+ /* Make sure we get permanent strtab: don't use info->strtab. */
+ mod->strtab = (void *)info->sechdrs[info->index.str].sh_addr;
/* Set types up while we still have access to sections. */
for (i = 0; i < mod->num_symtab; i++)
- mod->symtab[i].st_info
- = elf_type(&mod->symtab[i], sechdrs, secstrings, mod);
+ mod->symtab[i].st_info = elf_type(&mod->symtab[i], info);
- mod->core_symtab = dst = mod->module_core + symoffs;
+ mod->core_symtab = dst = mod->module_core + info->symoffs;
src = mod->symtab;
*dst = *src;
for (ndst = i = 1; i < mod->num_symtab; ++i, ++src) {
- if (!is_core_symbol(src, sechdrs, shnum))
+ if (!is_core_symbol(src, info->sechdrs, info->hdr->e_shnum))
continue;
dst[ndst] = *src;
- dst[ndst].st_name = bitmap_weight(strmap, dst[ndst].st_name);
+ dst[ndst].st_name = bitmap_weight(info->strmap,
+ dst[ndst].st_name);
++ndst;
}
mod->core_num_syms = ndst;
- mod->core_strtab = s = mod->module_core + stroffs;
- for (*s = 0, i = 1; i < sechdrs[strindex].sh_size; ++i)
- if (test_bit(i, strmap))
+ mod->core_strtab = s = mod->module_core + info->stroffs;
+ for (*s = 0, i = 1; i < info->sechdrs[info->index.str].sh_size; ++i)
+ if (test_bit(i, info->strmap))
*++s = mod->strtab[i];
}
#else
-static inline unsigned long layout_symtab(struct module *mod,
- Elf_Shdr *sechdrs,
- unsigned int symindex,
- unsigned int strindex,
- const Elf_Ehdr *hdr,
- const char *secstrings,
- unsigned long *pstroffs,
- unsigned long *strmap)
+static inline void layout_symtab(struct module *mod, struct load_info *info)
{
- return 0;
}
-static inline void add_kallsyms(struct module *mod,
- Elf_Shdr *sechdrs,
- unsigned int shnum,
- unsigned int symindex,
- unsigned int strindex,
- unsigned long symoffs,
- unsigned long stroffs,
- const char *secstrings,
- const unsigned long *strmap)
+static void add_kallsyms(struct module *mod, struct load_info *info)
{
}
#endif /* CONFIG_KALLSYMS */
static void dynamic_debug_setup(struct _ddebug *debug, unsigned int num)
{
+ if (!debug)
+ return;
#ifdef CONFIG_DYNAMIC_DEBUG
if (ddebug_add_module(debug, num, debug->modname))
printk(KERN_ERR "dynamic debug error adding module: %s\n",
@@ -2087,65 +2074,47 @@ static void *module_alloc_update_bounds(unsigned long size)
}
#ifdef CONFIG_DEBUG_KMEMLEAK
-static void kmemleak_load_module(struct module *mod, Elf_Ehdr *hdr,
- Elf_Shdr *sechdrs, char *secstrings)
+static void kmemleak_load_module(const struct module *mod,
+ const struct load_info *info)
{
unsigned int i;
/* only scan the sections containing data */
kmemleak_scan_area(mod, sizeof(struct module), GFP_KERNEL);
- for (i = 1; i < hdr->e_shnum; i++) {
- if (!(sechdrs[i].sh_flags & SHF_ALLOC))
+ for (i = 1; i < info->hdr->e_shnum; i++) {
+ const char *name = info->secstrings + info->sechdrs[i].sh_name;
+ if (!(info->sechdrs[i].sh_flags & SHF_ALLOC))
continue;
- if (strncmp(secstrings + sechdrs[i].sh_name, ".data", 5) != 0
- && strncmp(secstrings + sechdrs[i].sh_name, ".bss", 4) != 0)
+ if (!strstarts(name, ".data") && !strstarts(name, ".bss"))
continue;
- kmemleak_scan_area((void *)sechdrs[i].sh_addr,
- sechdrs[i].sh_size, GFP_KERNEL);
+ kmemleak_scan_area((void *)info->sechdrs[i].sh_addr,
+ info->sechdrs[i].sh_size, GFP_KERNEL);
}
}
#else
-static inline void kmemleak_load_module(struct module *mod, Elf_Ehdr *hdr,
- Elf_Shdr *sechdrs, char *secstrings)
+static inline void kmemleak_load_module(const struct module *mod,
+ const struct load_info *info)
{
}
#endif
-/* Allocate and load the module: note that size of section 0 is always
- zero, and we rely on this for optional sections. */
-static noinline struct module *load_module(void __user *umod,
- unsigned long len,
- const char __user *uargs)
+/* Sets info->hdr and info->len. */
+static int copy_and_check(struct load_info *info,
+ const void __user *umod, unsigned long len,
+ const char __user *uargs)
{
+ int err;
Elf_Ehdr *hdr;
- Elf_Shdr *sechdrs;
- char *secstrings, *args, *modmagic, *strtab = NULL;
- char *staging;
- unsigned int i;
- unsigned int symindex = 0;
- unsigned int strindex = 0;
- unsigned int modindex, versindex, infoindex, pcpuindex;
- struct module *mod;
- long err = 0;
- void *ptr = NULL; /* Stops spurious gcc warning */
- unsigned long symoffs, stroffs, *strmap;
- void __percpu *percpu;
- struct _ddebug *debug = NULL;
- unsigned int num_debug = 0;
- mm_segment_t old_fs;
-
- DEBUGP("load_module: umod=%p, len=%lu, uargs=%p\n",
- umod, len, uargs);
if (len < sizeof(*hdr))
- return ERR_PTR(-ENOEXEC);
+ return -ENOEXEC;
/* Suck in entire file: we'll want most of it. */
/* vmalloc barfs on "unusual" numbers. Check here */
if (len > 64 * 1024 * 1024 || (hdr = vmalloc(len)) == NULL)
- return ERR_PTR(-ENOMEM);
+ return -ENOMEM;
if (copy_from_user(hdr, umod, len) != 0) {
err = -EFAULT;
@@ -2153,135 +2122,225 @@ static noinline struct module *load_module(void __user *umod,
}
/* Sanity checks against insmoding binaries or wrong arch,
- weird elf version */
+ weird elf version */
if (memcmp(hdr->e_ident, ELFMAG, SELFMAG) != 0
|| hdr->e_type != ET_REL
|| !elf_check_arch(hdr)
- || hdr->e_shentsize != sizeof(*sechdrs)) {
+ || hdr->e_shentsize != sizeof(Elf_Shdr)) {
err = -ENOEXEC;
goto free_hdr;
}
- if (len < hdr->e_shoff + hdr->e_shnum * sizeof(Elf_Shdr))
- goto truncated;
+ if (len < hdr->e_shoff + hdr->e_shnum * sizeof(Elf_Shdr)) {
+ err = -ENOEXEC;
+ goto free_hdr;
+ }
- /* Convenience variables */
- sechdrs = (void *)hdr + hdr->e_shoff;
- secstrings = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset;
- sechdrs[0].sh_addr = 0;
+ info->hdr = hdr;
+ info->len = len;
+ return 0;
- for (i = 1; i < hdr->e_shnum; i++) {
- if (sechdrs[i].sh_type != SHT_NOBITS
- && len < sechdrs[i].sh_offset + sechdrs[i].sh_size)
- goto truncated;
+free_hdr:
+ vfree(hdr);
+ return err;
+}
+
+static void free_copy(struct load_info *info)
+{
+ vfree(info->hdr);
+}
+
+static int rewrite_section_headers(struct load_info *info)
+{
+ unsigned int i;
+
+ /* This should always be true, but let's be sure. */
+ info->sechdrs[0].sh_addr = 0;
+
+ for (i = 1; i < info->hdr->e_shnum; i++) {
+ Elf_Shdr *shdr = &info->sechdrs[i];
+ if (shdr->sh_type != SHT_NOBITS
+ && info->len < shdr->sh_offset + shdr->sh_size) {
+ printk(KERN_ERR "Module len %lu truncated\n",
+ info->len);
+ return -ENOEXEC;
+ }
/* Mark all sections sh_addr with their address in the
temporary image. */
- sechdrs[i].sh_addr = (size_t)hdr + sechdrs[i].sh_offset;
+ shdr->sh_addr = (size_t)info->hdr + shdr->sh_offset;
- /* Internal symbols and strings. */
- if (sechdrs[i].sh_type == SHT_SYMTAB) {
- symindex = i;
- strindex = sechdrs[i].sh_link;
- strtab = (char *)hdr + sechdrs[strindex].sh_offset;
- }
#ifndef CONFIG_MODULE_UNLOAD
/* Don't load .exit sections */
- if (strstarts(secstrings+sechdrs[i].sh_name, ".exit"))
- sechdrs[i].sh_flags &= ~(unsigned long)SHF_ALLOC;
+ if (strstarts(info->secstrings+shdr->sh_name, ".exit"))
+ shdr->sh_flags &= ~(unsigned long)SHF_ALLOC;
#endif
}
- modindex = find_sec(hdr, sechdrs, secstrings,
- ".gnu.linkonce.this_module");
- if (!modindex) {
+ /* Track but don't keep modinfo and version sections. */
+ info->index.vers = find_sec(info, "__versions");
+ info->index.info = find_sec(info, ".modinfo");
+ info->sechdrs[info->index.info].sh_flags &= ~(unsigned long)SHF_ALLOC;
+ info->sechdrs[info->index.vers].sh_flags &= ~(unsigned long)SHF_ALLOC;
+ return 0;
+}
+
+/*
+ * Set up our basic convenience variables (pointers to section headers,
+ * search for module section index etc), and do some basic section
+ * verification.
+ *
+ * Return the temporary module pointer (we'll replace it with the final
+ * one when we move the module sections around).
+ */
+static struct module *setup_load_info(struct load_info *info)
+{
+ unsigned int i;
+ int err;
+ struct module *mod;
+
+ /* Set up the convenience variables */
+ info->sechdrs = (void *)info->hdr + info->hdr->e_shoff;
+ info->secstrings = (void *)info->hdr
+ + info->sechdrs[info->hdr->e_shstrndx].sh_offset;
+
+ err = rewrite_section_headers(info);
+ if (err)
+ return ERR_PTR(err);
+
+ /* Find internal symbols and strings. */
+ for (i = 1; i < info->hdr->e_shnum; i++) {
+ if (info->sechdrs[i].sh_type == SHT_SYMTAB) {
+ info->index.sym = i;
+ info->index.str = info->sechdrs[i].sh_link;
+ info->strtab = (char *)info->hdr
+ + info->sechdrs[info->index.str].sh_offset;
+ break;
+ }
+ }
+
+ info->index.mod = find_sec(info, ".gnu.linkonce.this_module");
+ if (!info->index.mod) {
printk(KERN_WARNING "No module found in object\n");
- err = -ENOEXEC;
- goto free_hdr;
+ return ERR_PTR(-ENOEXEC);
}
/* This is temporary: point mod into copy of data. */
- mod = (void *)sechdrs[modindex].sh_addr;
+ mod = (void *)info->sechdrs[info->index.mod].sh_addr;
- if (symindex == 0) {
+ if (info->index.sym == 0) {
printk(KERN_WARNING "%s: module has no symbols (stripped?)\n",
mod->name);
- err = -ENOEXEC;
- goto free_hdr;
+ return ERR_PTR(-ENOEXEC);
}
- versindex = find_sec(hdr, sechdrs, secstrings, "__versions");
- infoindex = find_sec(hdr, sechdrs, secstrings, ".modinfo");
- pcpuindex = find_pcpusec(hdr, sechdrs, secstrings);
-
- /* Don't keep modinfo and version sections. */
- sechdrs[infoindex].sh_flags &= ~(unsigned long)SHF_ALLOC;
- sechdrs[versindex].sh_flags &= ~(unsigned long)SHF_ALLOC;
+ info->index.pcpu = find_pcpusec(info);
/* Check module struct version now, before we try to use module. */
- if (!check_modstruct_version(sechdrs, versindex, mod)) {
- err = -ENOEXEC;
- goto free_hdr;
- }
+ if (!check_modstruct_version(info->sechdrs, info->index.vers, mod))
+ return ERR_PTR(-ENOEXEC);
+
+ return mod;
+}
+
+static int check_modinfo(struct module *mod, struct load_info *info)
+{
+ const char *modmagic = get_modinfo(info, "vermagic");
+ int err;
- modmagic = get_modinfo(sechdrs, infoindex, "vermagic");
/* This is allowed: modprobe --force will invalidate it. */
if (!modmagic) {
err = try_to_force_load(mod, "bad vermagic");
if (err)
- goto free_hdr;
- } else if (!same_magic(modmagic, vermagic, versindex)) {
+ return err;
+ } else if (!same_magic(modmagic, vermagic, info->index.vers)) {
printk(KERN_ERR "%s: version magic '%s' should be '%s'\n",
mod->name, modmagic, vermagic);
- err = -ENOEXEC;
- goto free_hdr;
+ return -ENOEXEC;
}
- staging = get_modinfo(sechdrs, infoindex, "staging");
- if (staging) {
+ if (get_modinfo(info, "staging")) {
add_taint_module(mod, TAINT_CRAP);
printk(KERN_WARNING "%s: module is from the staging directory,"
" the quality is unknown, you have been warned.\n",
mod->name);
}
- /* Now copy in args */
- args = strndup_user(uargs, ~0UL >> 1);
- if (IS_ERR(args)) {
- err = PTR_ERR(args);
- goto free_hdr;
- }
+ /* Set up license info based on the info section */
+ set_license(mod, get_modinfo(info, "license"));
- strmap = kzalloc(BITS_TO_LONGS(sechdrs[strindex].sh_size)
- * sizeof(long), GFP_KERNEL);
- if (!strmap) {
- err = -ENOMEM;
- goto free_mod;
- }
+ return 0;
+}
- mod->state = MODULE_STATE_COMING;
+static void find_module_sections(struct module *mod, struct load_info *info)
+{
+ mod->kp = section_objs(info, "__param",
+ sizeof(*mod->kp), &mod->num_kp);
+ mod->syms = section_objs(info, "__ksymtab",
+ sizeof(*mod->syms), &mod->num_syms);
+ mod->crcs = section_addr(info, "__kcrctab");
+ mod->gpl_syms = section_objs(info, "__ksymtab_gpl",
+ sizeof(*mod->gpl_syms),
+ &mod->num_gpl_syms);
+ mod->gpl_crcs = section_addr(info, "__kcrctab_gpl");
+ mod->gpl_future_syms = section_objs(info,
+ "__ksymtab_gpl_future",
+ sizeof(*mod->gpl_future_syms),
+ &mod->num_gpl_future_syms);
+ mod->gpl_future_crcs = section_addr(info, "__kcrctab_gpl_future");
- /* Allow arches to frob section contents and sizes. */
- err = module_frob_arch_sections(hdr, sechdrs, secstrings, mod);
- if (err < 0)
- goto free_mod;
+#ifdef CONFIG_UNUSED_SYMBOLS
+ mod->unused_syms = section_objs(info, "__ksymtab_unused",
+ sizeof(*mod->unused_syms),
+ &mod->num_unused_syms);
+ mod->unused_crcs = section_addr(info, "__kcrctab_unused");
+ mod->unused_gpl_syms = section_objs(info, "__ksymtab_unused_gpl",
+ sizeof(*mod->unused_gpl_syms),
+ &mod->num_unused_gpl_syms);
+ mod->unused_gpl_crcs = section_addr(info, "__kcrctab_unused_gpl");
+#endif
+#ifdef CONFIG_CONSTRUCTORS
+ mod->ctors = section_objs(info, ".ctors",
+ sizeof(*mod->ctors), &mod->num_ctors);
+#endif
- if (pcpuindex) {
- /* We have a special allocation for this section. */
- err = percpu_modalloc(mod, sechdrs[pcpuindex].sh_size,
- sechdrs[pcpuindex].sh_addralign);
- if (err)
- goto free_mod;
- sechdrs[pcpuindex].sh_flags &= ~(unsigned long)SHF_ALLOC;
- }
- /* Keep this around for failure path. */
- percpu = mod_percpu(mod);
+#ifdef CONFIG_TRACEPOINTS
+ mod->tracepoints = section_objs(info, "__tracepoints",
+ sizeof(*mod->tracepoints),
+ &mod->num_tracepoints);
+#endif
+#ifdef CONFIG_EVENT_TRACING
+ mod->trace_events = section_objs(info, "_ftrace_events",
+ sizeof(*mod->trace_events),
+ &mod->num_trace_events);
+ /*
+ * This section contains pointers to allocated objects in the trace
+ * code and not scanning it leads to false positives.
+ */
+ kmemleak_scan_area(mod->trace_events, sizeof(*mod->trace_events) *
+ mod->num_trace_events, GFP_KERNEL);
+#endif
+#ifdef CONFIG_FTRACE_MCOUNT_RECORD
+ /* sechdrs[0].sh_size is always zero */
+ mod->ftrace_callsites = section_objs(info, "__mcount_loc",
+ sizeof(*mod->ftrace_callsites),
+ &mod->num_ftrace_callsites);
+#endif
- /* Determine total sizes, and put offsets in sh_entsize. For now
- this is done generically; there doesn't appear to be any
- special cases for the architectures. */
- layout_sections(mod, hdr, sechdrs, secstrings);
- symoffs = layout_symtab(mod, sechdrs, symindex, strindex, hdr,
- secstrings, &stroffs, strmap);
+ mod->extable = section_objs(info, "__ex_table",
+ sizeof(*mod->extable), &mod->num_exentries);
+
+ if (section_addr(info, "__obsparm"))
+ printk(KERN_WARNING "%s: Ignoring obsolete parameters\n",
+ mod->name);
+
+ info->debug = section_objs(info, "__verbose",
+ sizeof(*info->debug), &info->num_debug);
+}
+
+static int move_module(struct module *mod, struct load_info *info)
+{
+ int i;
+ void *ptr;
/* Do the allocs. */
ptr = module_alloc_update_bounds(mod->core_size);
@@ -2291,10 +2350,9 @@ static noinline struct module *load_module(void __user *umod,
* leak.
*/
kmemleak_not_leak(ptr);
- if (!ptr) {
- err = -ENOMEM;
- goto free_percpu;
- }
+ if (!ptr)
+ return -ENOMEM;
+
memset(ptr, 0, mod->core_size);
mod->module_core = ptr;
@@ -2307,50 +2365,40 @@ static noinline struct module *load_module(void __user *umod,
*/
kmemleak_ignore(ptr);
if (!ptr && mod->init_size) {
- err = -ENOMEM;
- goto free_core;
+ module_free(mod, mod->module_core);
+ return -ENOMEM;
}
memset(ptr, 0, mod->init_size);
mod->module_init = ptr;
/* Transfer each section which specifies SHF_ALLOC */
DEBUGP("final section addresses:\n");
- for (i = 0; i < hdr->e_shnum; i++) {
+ for (i = 0; i < info->hdr->e_shnum; i++) {
void *dest;
+ Elf_Shdr *shdr = &info->sechdrs[i];
- if (!(sechdrs[i].sh_flags & SHF_ALLOC))
+ if (!(shdr->sh_flags & SHF_ALLOC))
continue;
- if (sechdrs[i].sh_entsize & INIT_OFFSET_MASK)
+ if (shdr->sh_entsize & INIT_OFFSET_MASK)
dest = mod->module_init
- + (sechdrs[i].sh_entsize & ~INIT_OFFSET_MASK);
+ + (shdr->sh_entsize & ~INIT_OFFSET_MASK);
else
- dest = mod->module_core + sechdrs[i].sh_entsize;
+ dest = mod->module_core + shdr->sh_entsize;
- if (sechdrs[i].sh_type != SHT_NOBITS)
- memcpy(dest, (void *)sechdrs[i].sh_addr,
- sechdrs[i].sh_size);
+ if (shdr->sh_type != SHT_NOBITS)
+ memcpy(dest, (void *)shdr->sh_addr, shdr->sh_size);
/* Update sh_addr to point to copy in image. */
- sechdrs[i].sh_addr = (unsigned long)dest;
- DEBUGP("\t0x%lx %s\n", sechdrs[i].sh_addr, secstrings + sechdrs[i].sh_name);
- }
- /* Module has been moved. */
- mod = (void *)sechdrs[modindex].sh_addr;
- kmemleak_load_module(mod, hdr, sechdrs, secstrings);
-
-#if defined(CONFIG_MODULE_UNLOAD)
- mod->refptr = alloc_percpu(struct module_ref);
- if (!mod->refptr) {
- err = -ENOMEM;
- goto free_init;
+ shdr->sh_addr = (unsigned long)dest;
+ DEBUGP("\t0x%lx %s\n",
+ shdr->sh_addr, info->secstrings + shdr->sh_name);
}
-#endif
- /* Now we've moved module, initialize linked lists, etc. */
- module_unload_init(mod);
- /* Set up license info based on the info section */
- set_license(mod, get_modinfo(sechdrs, infoindex, "license"));
+ return 0;
+}
+static int check_module_license_and_versions(struct module *mod)
+{
/*
* ndiswrapper is under GPL by itself, but loads proprietary modules.
* Don't use add_taint_module(), as it would prevent ndiswrapper from
@@ -2363,77 +2411,6 @@ static noinline struct module *load_module(void __user *umod,
if (strcmp(mod->name, "driverloader") == 0)
add_taint_module(mod, TAINT_PROPRIETARY_MODULE);
- /* Set up MODINFO_ATTR fields */
- setup_modinfo(mod, sechdrs, infoindex);
-
- /* Fix up syms, so that st_value is a pointer to location. */
- err = simplify_symbols(sechdrs, symindex, strtab, versindex, pcpuindex,
- mod);
- if (err < 0)
- goto cleanup;
-
- /* Now we've got everything in the final locations, we can
- * find optional sections. */
- mod->kp = section_objs(hdr, sechdrs, secstrings, "__param",
- sizeof(*mod->kp), &mod->num_kp);
- mod->syms = section_objs(hdr, sechdrs, secstrings, "__ksymtab",
- sizeof(*mod->syms), &mod->num_syms);
- mod->crcs = section_addr(hdr, sechdrs, secstrings, "__kcrctab");
- mod->gpl_syms = section_objs(hdr, sechdrs, secstrings, "__ksymtab_gpl",
- sizeof(*mod->gpl_syms),
- &mod->num_gpl_syms);
- mod->gpl_crcs = section_addr(hdr, sechdrs, secstrings, "__kcrctab_gpl");
- mod->gpl_future_syms = section_objs(hdr, sechdrs, secstrings,
- "__ksymtab_gpl_future",
- sizeof(*mod->gpl_future_syms),
- &mod->num_gpl_future_syms);
- mod->gpl_future_crcs = section_addr(hdr, sechdrs, secstrings,
- "__kcrctab_gpl_future");
-
-#ifdef CONFIG_UNUSED_SYMBOLS
- mod->unused_syms = section_objs(hdr, sechdrs, secstrings,
- "__ksymtab_unused",
- sizeof(*mod->unused_syms),
- &mod->num_unused_syms);
- mod->unused_crcs = section_addr(hdr, sechdrs, secstrings,
- "__kcrctab_unused");
- mod->unused_gpl_syms = section_objs(hdr, sechdrs, secstrings,
- "__ksymtab_unused_gpl",
- sizeof(*mod->unused_gpl_syms),
- &mod->num_unused_gpl_syms);
- mod->unused_gpl_crcs = section_addr(hdr, sechdrs, secstrings,
- "__kcrctab_unused_gpl");
-#endif
-#ifdef CONFIG_CONSTRUCTORS
- mod->ctors = section_objs(hdr, sechdrs, secstrings, ".ctors",
- sizeof(*mod->ctors), &mod->num_ctors);
-#endif
-
-#ifdef CONFIG_TRACEPOINTS
- mod->tracepoints = section_objs(hdr, sechdrs, secstrings,
- "__tracepoints",
- sizeof(*mod->tracepoints),
- &mod->num_tracepoints);
-#endif
-#ifdef CONFIG_EVENT_TRACING
- mod->trace_events = section_objs(hdr, sechdrs, secstrings,
- "_ftrace_events",
- sizeof(*mod->trace_events),
- &mod->num_trace_events);
- /*
- * This section contains pointers to allocated objects in the trace
- * code and not scanning it leads to false positives.
- */
- kmemleak_scan_area(mod->trace_events, sizeof(*mod->trace_events) *
- mod->num_trace_events, GFP_KERNEL);
-#endif
-#ifdef CONFIG_FTRACE_MCOUNT_RECORD
- /* sechdrs[0].sh_size is always zero */
- mod->ftrace_callsites = section_objs(hdr, sechdrs, secstrings,
- "__mcount_loc",
- sizeof(*mod->ftrace_callsites),
- &mod->num_ftrace_callsites);
-#endif
#ifdef CONFIG_MODVERSIONS
if ((mod->num_syms && !mod->crcs)
|| (mod->num_gpl_syms && !mod->gpl_crcs)
@@ -2443,56 +2420,16 @@ static noinline struct module *load_module(void __user *umod,
|| (mod->num_unused_gpl_syms && !mod->unused_gpl_crcs)
#endif
) {
- err = try_to_force_load(mod,
- "no versions for exported symbols");
- if (err)
- goto cleanup;
+ return try_to_force_load(mod,
+ "no versions for exported symbols");
}
#endif
+ return 0;
+}
- /* Now do relocations. */
- for (i = 1; i < hdr->e_shnum; i++) {
- const char *strtab = (char *)sechdrs[strindex].sh_addr;
- unsigned int info = sechdrs[i].sh_info;
-
- /* Not a valid relocation section? */
- if (info >= hdr->e_shnum)
- continue;
-
- /* Don't bother with non-allocated sections */
- if (!(sechdrs[info].sh_flags & SHF_ALLOC))
- continue;
-
- if (sechdrs[i].sh_type == SHT_REL)
- err = apply_relocate(sechdrs, strtab, symindex, i,mod);
- else if (sechdrs[i].sh_type == SHT_RELA)
- err = apply_relocate_add(sechdrs, strtab, symindex, i,
- mod);
- if (err < 0)
- goto cleanup;
- }
-
- /* Set up and sort exception table */
- mod->extable = section_objs(hdr, sechdrs, secstrings, "__ex_table",
- sizeof(*mod->extable), &mod->num_exentries);
- sort_extable(mod->extable, mod->extable + mod->num_exentries);
-
- /* Finally, copy percpu area over. */
- percpu_modcopy(mod, (void *)sechdrs[pcpuindex].sh_addr,
- sechdrs[pcpuindex].sh_size);
-
- add_kallsyms(mod, sechdrs, hdr->e_shnum, symindex, strindex,
- symoffs, stroffs, secstrings, strmap);
- kfree(strmap);
- strmap = NULL;
-
- if (!mod->taints)
- debug = section_objs(hdr, sechdrs, secstrings, "__verbose",
- sizeof(*debug), &num_debug);
-
- err = module_finalize(hdr, sechdrs, mod);
- if (err < 0)
- goto cleanup;
+static void flush_module_icache(const struct module *mod)
+{
+ mm_segment_t old_fs;
/* flush the icache in correct context */
old_fs = get_fs();
@@ -2511,11 +2448,160 @@ static noinline struct module *load_module(void __user *umod,
(unsigned long)mod->module_core + mod->core_size);
set_fs(old_fs);
+}
- mod->args = args;
- if (section_addr(hdr, sechdrs, secstrings, "__obsparm"))
- printk(KERN_WARNING "%s: Ignoring obsolete parameters\n",
- mod->name);
+static struct module *layout_and_allocate(struct load_info *info)
+{
+ /* Module within temporary copy. */
+ struct module *mod;
+ Elf_Shdr *pcpusec;
+ int err;
+
+ mod = setup_load_info(info);
+ if (IS_ERR(mod))
+ return mod;
+
+ err = check_modinfo(mod, info);
+ if (err)
+ return ERR_PTR(err);
+
+ /* Allow arches to frob section contents and sizes. */
+ err = module_frob_arch_sections(info->hdr, info->sechdrs,
+ info->secstrings, mod);
+ if (err < 0)
+ goto out;
+
+ pcpusec = &info->sechdrs[info->index.pcpu];
+ if (pcpusec->sh_size) {
+ /* We have a special allocation for this section. */
+ err = percpu_modalloc(mod,
+ pcpusec->sh_size, pcpusec->sh_addralign);
+ if (err)
+ goto out;
+ pcpusec->sh_flags &= ~(unsigned long)SHF_ALLOC;
+ }
+
+ /* Determine total sizes, and put offsets in sh_entsize. For now
+ this is done generically; there doesn't appear to be any
+ special cases for the architectures. */
+ layout_sections(mod, info);
+
+ info->strmap = kzalloc(BITS_TO_LONGS(info->sechdrs[info->index.str].sh_size)
+ * sizeof(long), GFP_KERNEL);
+ if (!info->strmap) {
+ err = -ENOMEM;
+ goto free_percpu;
+ }
+ layout_symtab(mod, info);
+
+ /* Allocate and move to the final place */
+ err = move_module(mod, info);
+ if (err)
+ goto free_strmap;
+
+ /* Module has been copied to its final place now: return it. */
+ mod = (void *)info->sechdrs[info->index.mod].sh_addr;
+ kmemleak_load_module(mod, info);
+ return mod;
+
+free_strmap:
+ kfree(info->strmap);
+free_percpu:
+ percpu_modfree(mod);
+out:
+ return ERR_PTR(err);
+}
+
+/* mod is no longer valid after this! */
+static void module_deallocate(struct module *mod, struct load_info *info)
+{
+ kfree(info->strmap);
+ percpu_modfree(mod);
+ module_free(mod, mod->module_init);
+ module_free(mod, mod->module_core);
+}
+
+static int post_relocation(struct module *mod, const struct load_info *info)
+{
+ /* Sort exception table now relocations are done. */
+ sort_extable(mod->extable, mod->extable + mod->num_exentries);
+
+ /* Copy relocated percpu area over. */
+ percpu_modcopy(mod, (void *)info->sechdrs[info->index.pcpu].sh_addr,
+ info->sechdrs[info->index.pcpu].sh_size);
+
+ /* Setup kallsyms-specific fields. */
+ add_kallsyms(mod, info);
+
+ /* Arch-specific module finalizing. */
+ return module_finalize(info->hdr, info->sechdrs, mod);
+}
+
+/* Allocate and load the module: note that size of section 0 is always
+ zero, and we rely on this for optional sections. */
+static struct module *load_module(void __user *umod,
+ unsigned long len,
+ const char __user *uargs)
+{
+ struct load_info info = { NULL, };
+ struct module *mod;
+ long err;
+
+ DEBUGP("load_module: umod=%p, len=%lu, uargs=%p\n",
+ umod, len, uargs);
+
+ /* Copy in the blobs from userspace, check they are vaguely sane. */
+ err = copy_and_check(&info, umod, len, uargs);
+ if (err)
+ return ERR_PTR(err);
+
+ /* Figure out module layout, and allocate all the memory. */
+ mod = layout_and_allocate(&info);
+ if (IS_ERR(mod)) {
+ err = PTR_ERR(mod);
+ goto free_copy;
+ }
+
+ /* Now module is in final location, initialize linked lists, etc. */
+ err = module_unload_init(mod);
+ if (err)
+ goto free_module;
+
+ /* Now we've got everything in the final locations, we can
+ * find optional sections. */
+ find_module_sections(mod, &info);
+
+ err = check_module_license_and_versions(mod);
+ if (err)
+ goto free_unload;
+
+ /* Set up MODINFO_ATTR fields */
+ setup_modinfo(mod, &info);
+
+ /* Fix up syms, so that st_value is a pointer to location. */
+ err = simplify_symbols(mod, &info);
+ if (err < 0)
+ goto free_modinfo;
+
+ err = apply_relocations(mod, &info);
+ if (err < 0)
+ goto free_modinfo;
+
+ err = post_relocation(mod, &info);
+ if (err < 0)
+ goto free_modinfo;
+
+ flush_module_icache(mod);
+
+ /* Now copy in args */
+ mod->args = strndup_user(uargs, ~0UL >> 1);
+ if (IS_ERR(mod->args)) {
+ err = PTR_ERR(mod->args);
+ goto free_arch_cleanup;
+ }
+
+ /* Mark state as coming so strong_try_module_get() ignores us. */
+ mod->state = MODULE_STATE_COMING;
/* Now sew it into the lists so we can get lockdep and oops
* info during argument parsing. Noone should access us, since
@@ -2530,8 +2616,9 @@ static noinline struct module *load_module(void __user *umod,
goto unlock;
}
- if (debug)
- dynamic_debug_setup(debug, num_debug);
+ /* This has to be done once we're sure module name is unique. */
+ if (!mod->taints)
+ dynamic_debug_setup(info.debug, info.num_debug);
/* Find duplicate symbols */
err = verify_export_symbols(mod);
@@ -2541,23 +2628,22 @@ static noinline struct module *load_module(void __user *umod,
list_add_rcu(&mod->list, &modules);
mutex_unlock(&module_mutex);
+ /* Module is ready to execute: parsing args may do that. */
err = parse_args(mod->name, mod->args, mod->kp, mod->num_kp, NULL);
if (err < 0)
goto unlink;
- err = mod_sysfs_setup(mod, mod->kp, mod->num_kp);
+ /* Link in to syfs. */
+ err = mod_sysfs_setup(mod, &info, mod->kp, mod->num_kp);
if (err < 0)
goto unlink;
- add_sect_attrs(mod, hdr->e_shnum, secstrings, sechdrs);
- add_notes_attrs(mod, hdr->e_shnum, secstrings, sechdrs);
-
- /* Get rid of temporary copy */
- vfree(hdr);
-
- trace_module_load(mod);
+ /* Get rid of temporary copy and strmap. */
+ kfree(info.strmap);
+ free_copy(&info);
/* Done! */
+ trace_module_load(mod);
return mod;
unlink:
@@ -2565,35 +2651,23 @@ static noinline struct module *load_module(void __user *umod,
/* Unlink carefully: kallsyms could be walking list. */
list_del_rcu(&mod->list);
ddebug:
- dynamic_debug_remove(debug);
+ if (!mod->taints)
+ dynamic_debug_remove(info.debug);
unlock:
mutex_unlock(&module_mutex);
synchronize_sched();
+ kfree(mod->args);
+ free_arch_cleanup:
module_arch_cleanup(mod);
- cleanup:
+ free_modinfo:
free_modinfo(mod);
+ free_unload:
module_unload_free(mod);
-#if defined(CONFIG_MODULE_UNLOAD)
- free_percpu(mod->refptr);
- free_init:
-#endif
- module_free(mod, mod->module_init);
- free_core:
- module_free(mod, mod->module_core);
- /* mod will be freed with core. Don't access it beyond this line! */
- free_percpu:
- free_percpu(percpu);
- free_mod:
- kfree(args);
- kfree(strmap);
- free_hdr:
- vfree(hdr);
+ free_module:
+ module_deallocate(mod, &info);
+ free_copy:
+ free_copy(&info);
return ERR_PTR(err);
-
- truncated:
- printk(KERN_ERR "Module len %lu truncated\n", len);
- err = -ENOEXEC;
- goto free_hdr;
}
/* Call module constructors. */
diff --git a/kernel/padata.c b/kernel/padata.c
index fdd8ae609ce..751019415d2 100644
--- a/kernel/padata.c
+++ b/kernel/padata.c
@@ -26,18 +26,19 @@
#include <linux/mutex.h>
#include <linux/sched.h>
#include <linux/slab.h>
+#include <linux/sysfs.h>
#include <linux/rcupdate.h>
-#define MAX_SEQ_NR INT_MAX - NR_CPUS
+#define MAX_SEQ_NR (INT_MAX - NR_CPUS)
#define MAX_OBJ_NUM 1000
static int padata_index_to_cpu(struct parallel_data *pd, int cpu_index)
{
int cpu, target_cpu;
- target_cpu = cpumask_first(pd->cpumask);
+ target_cpu = cpumask_first(pd->cpumask.pcpu);
for (cpu = 0; cpu < cpu_index; cpu++)
- target_cpu = cpumask_next(target_cpu, pd->cpumask);
+ target_cpu = cpumask_next(target_cpu, pd->cpumask.pcpu);
return target_cpu;
}
@@ -53,26 +54,27 @@ static int padata_cpu_hash(struct padata_priv *padata)
* Hash the sequence numbers to the cpus by taking
* seq_nr mod. number of cpus in use.
*/
- cpu_index = padata->seq_nr % cpumask_weight(pd->cpumask);
+ cpu_index = padata->seq_nr % cpumask_weight(pd->cpumask.pcpu);
return padata_index_to_cpu(pd, cpu_index);
}
-static void padata_parallel_worker(struct work_struct *work)
+static void padata_parallel_worker(struct work_struct *parallel_work)
{
- struct padata_queue *queue;
+ struct padata_parallel_queue *pqueue;
struct parallel_data *pd;
struct padata_instance *pinst;
LIST_HEAD(local_list);
local_bh_disable();
- queue = container_of(work, struct padata_queue, pwork);
- pd = queue->pd;
+ pqueue = container_of(parallel_work,
+ struct padata_parallel_queue, work);
+ pd = pqueue->pd;
pinst = pd->pinst;
- spin_lock(&queue->parallel.lock);
- list_replace_init(&queue->parallel.list, &local_list);
- spin_unlock(&queue->parallel.lock);
+ spin_lock(&pqueue->parallel.lock);
+ list_replace_init(&pqueue->parallel.list, &local_list);
+ spin_unlock(&pqueue->parallel.lock);
while (!list_empty(&local_list)) {
struct padata_priv *padata;
@@ -94,7 +96,7 @@ static void padata_parallel_worker(struct work_struct *work)
* @pinst: padata instance
* @padata: object to be parallelized
* @cb_cpu: cpu the serialization callback function will run on,
- * must be in the cpumask of padata.
+ * must be in the serial cpumask of padata(i.e. cpumask.cbcpu).
*
* The parallelization callback function will run with BHs off.
* Note: Every object which is parallelized by padata_do_parallel
@@ -104,15 +106,18 @@ int padata_do_parallel(struct padata_instance *pinst,
struct padata_priv *padata, int cb_cpu)
{
int target_cpu, err;
- struct padata_queue *queue;
+ struct padata_parallel_queue *queue;
struct parallel_data *pd;
rcu_read_lock_bh();
pd = rcu_dereference(pinst->pd);
- err = 0;
- if (!(pinst->flags & PADATA_INIT))
+ err = -EINVAL;
+ if (!(pinst->flags & PADATA_INIT) || pinst->flags & PADATA_INVALID)
+ goto out;
+
+ if (!cpumask_test_cpu(cb_cpu, pd->cpumask.cbcpu))
goto out;
err = -EBUSY;
@@ -122,11 +127,7 @@ int padata_do_parallel(struct padata_instance *pinst,
if (atomic_read(&pd->refcnt) >= MAX_OBJ_NUM)
goto out;
- err = -EINVAL;
- if (!cpumask_test_cpu(cb_cpu, pd->cpumask))
- goto out;
-
- err = -EINPROGRESS;
+ err = 0;
atomic_inc(&pd->refcnt);
padata->pd = pd;
padata->cb_cpu = cb_cpu;
@@ -137,13 +138,13 @@ int padata_do_parallel(struct padata_instance *pinst,
padata->seq_nr = atomic_inc_return(&pd->seq_nr);
target_cpu = padata_cpu_hash(padata);
- queue = per_cpu_ptr(pd->queue, target_cpu);
+ queue = per_cpu_ptr(pd->pqueue, target_cpu);
spin_lock(&queue->parallel.lock);
list_add_tail(&padata->list, &queue->parallel.list);
spin_unlock(&queue->parallel.lock);
- queue_work_on(target_cpu, pinst->wq, &queue->pwork);
+ queue_work_on(target_cpu, pinst->wq, &queue->work);
out:
rcu_read_unlock_bh();
@@ -171,84 +172,52 @@ EXPORT_SYMBOL(padata_do_parallel);
*/
static struct padata_priv *padata_get_next(struct parallel_data *pd)
{
- int cpu, num_cpus, empty, calc_seq_nr;
- int seq_nr, next_nr, overrun, next_overrun;
- struct padata_queue *queue, *next_queue;
+ int cpu, num_cpus;
+ int next_nr, next_index;
+ struct padata_parallel_queue *queue, *next_queue;
struct padata_priv *padata;
struct padata_list *reorder;
- empty = 0;
- next_nr = -1;
- next_overrun = 0;
- next_queue = NULL;
-
- num_cpus = cpumask_weight(pd->cpumask);
-
- for_each_cpu(cpu, pd->cpumask) {
- queue = per_cpu_ptr(pd->queue, cpu);
- reorder = &queue->reorder;
-
- /*
- * Calculate the seq_nr of the object that should be
- * next in this reorder queue.
- */
- overrun = 0;
- calc_seq_nr = (atomic_read(&queue->num_obj) * num_cpus)
- + queue->cpu_index;
+ num_cpus = cpumask_weight(pd->cpumask.pcpu);
- if (unlikely(calc_seq_nr > pd->max_seq_nr)) {
- calc_seq_nr = calc_seq_nr - pd->max_seq_nr - 1;
- overrun = 1;
- }
-
- if (!list_empty(&reorder->list)) {
- padata = list_entry(reorder->list.next,
- struct padata_priv, list);
-
- seq_nr = padata->seq_nr;
- BUG_ON(calc_seq_nr != seq_nr);
- } else {
- seq_nr = calc_seq_nr;
- empty++;
- }
-
- if (next_nr < 0 || seq_nr < next_nr
- || (next_overrun && !overrun)) {
- next_nr = seq_nr;
- next_overrun = overrun;
- next_queue = queue;
- }
+ /*
+ * Calculate the percpu reorder queue and the sequence
+ * number of the next object.
+ */
+ next_nr = pd->processed;
+ next_index = next_nr % num_cpus;
+ cpu = padata_index_to_cpu(pd, next_index);
+ next_queue = per_cpu_ptr(pd->pqueue, cpu);
+
+ if (unlikely(next_nr > pd->max_seq_nr)) {
+ next_nr = next_nr - pd->max_seq_nr - 1;
+ next_index = next_nr % num_cpus;
+ cpu = padata_index_to_cpu(pd, next_index);
+ next_queue = per_cpu_ptr(pd->pqueue, cpu);
+ pd->processed = 0;
}
padata = NULL;
- if (empty == num_cpus)
- goto out;
-
reorder = &next_queue->reorder;
if (!list_empty(&reorder->list)) {
padata = list_entry(reorder->list.next,
struct padata_priv, list);
- if (unlikely(next_overrun)) {
- for_each_cpu(cpu, pd->cpumask) {
- queue = per_cpu_ptr(pd->queue, cpu);
- atomic_set(&queue->num_obj, 0);
- }
- }
+ BUG_ON(next_nr != padata->seq_nr);
spin_lock(&reorder->lock);
list_del_init(&padata->list);
atomic_dec(&pd->reorder_objects);
spin_unlock(&reorder->lock);
- atomic_inc(&next_queue->num_obj);
+ pd->processed++;
goto out;
}
- queue = per_cpu_ptr(pd->queue, smp_processor_id());
+ queue = per_cpu_ptr(pd->pqueue, smp_processor_id());
if (queue->cpu_index == next_queue->cpu_index) {
padata = ERR_PTR(-ENODATA);
goto out;
@@ -262,7 +231,7 @@ out:
static void padata_reorder(struct parallel_data *pd)
{
struct padata_priv *padata;
- struct padata_queue *queue;
+ struct padata_serial_queue *squeue;
struct padata_instance *pinst = pd->pinst;
/*
@@ -301,13 +270,13 @@ static void padata_reorder(struct parallel_data *pd)
return;
}
- queue = per_cpu_ptr(pd->queue, padata->cb_cpu);
+ squeue = per_cpu_ptr(pd->squeue, padata->cb_cpu);
- spin_lock(&queue->serial.lock);
- list_add_tail(&padata->list, &queue->serial.list);
- spin_unlock(&queue->serial.lock);
+ spin_lock(&squeue->serial.lock);
+ list_add_tail(&padata->list, &squeue->serial.list);
+ spin_unlock(&squeue->serial.lock);
- queue_work_on(padata->cb_cpu, pinst->wq, &queue->swork);
+ queue_work_on(padata->cb_cpu, pinst->wq, &squeue->work);
}
spin_unlock_bh(&pd->lock);
@@ -333,19 +302,19 @@ static void padata_reorder_timer(unsigned long arg)
padata_reorder(pd);
}
-static void padata_serial_worker(struct work_struct *work)
+static void padata_serial_worker(struct work_struct *serial_work)
{
- struct padata_queue *queue;
+ struct padata_serial_queue *squeue;
struct parallel_data *pd;
LIST_HEAD(local_list);
local_bh_disable();
- queue = container_of(work, struct padata_queue, swork);
- pd = queue->pd;
+ squeue = container_of(serial_work, struct padata_serial_queue, work);
+ pd = squeue->pd;
- spin_lock(&queue->serial.lock);
- list_replace_init(&queue->serial.list, &local_list);
- spin_unlock(&queue->serial.lock);
+ spin_lock(&squeue->serial.lock);
+ list_replace_init(&squeue->serial.list, &local_list);
+ spin_unlock(&squeue->serial.lock);
while (!list_empty(&local_list)) {
struct padata_priv *padata;
@@ -372,18 +341,18 @@ static void padata_serial_worker(struct work_struct *work)
void padata_do_serial(struct padata_priv *padata)
{
int cpu;
- struct padata_queue *queue;
+ struct padata_parallel_queue *pqueue;
struct parallel_data *pd;
pd = padata->pd;
cpu = get_cpu();
- queue = per_cpu_ptr(pd->queue, cpu);
+ pqueue = per_cpu_ptr(pd->pqueue, cpu);
- spin_lock(&queue->reorder.lock);
+ spin_lock(&pqueue->reorder.lock);
atomic_inc(&pd->reorder_objects);
- list_add_tail(&padata->list, &queue->reorder.list);
- spin_unlock(&queue->reorder.lock);
+ list_add_tail(&padata->list, &pqueue->reorder.list);
+ spin_unlock(&pqueue->reorder.lock);
put_cpu();
@@ -391,52 +360,89 @@ void padata_do_serial(struct padata_priv *padata)
}
EXPORT_SYMBOL(padata_do_serial);
-/* Allocate and initialize the internal cpumask dependend resources. */
-static struct parallel_data *padata_alloc_pd(struct padata_instance *pinst,
- const struct cpumask *cpumask)
+static int padata_setup_cpumasks(struct parallel_data *pd,
+ const struct cpumask *pcpumask,
+ const struct cpumask *cbcpumask)
{
- int cpu, cpu_index, num_cpus;
- struct padata_queue *queue;
- struct parallel_data *pd;
-
- cpu_index = 0;
+ if (!alloc_cpumask_var(&pd->cpumask.pcpu, GFP_KERNEL))
+ return -ENOMEM;
- pd = kzalloc(sizeof(struct parallel_data), GFP_KERNEL);
- if (!pd)
- goto err;
+ cpumask_and(pd->cpumask.pcpu, pcpumask, cpu_active_mask);
+ if (!alloc_cpumask_var(&pd->cpumask.cbcpu, GFP_KERNEL)) {
+ free_cpumask_var(pd->cpumask.cbcpu);
+ return -ENOMEM;
+ }
- pd->queue = alloc_percpu(struct padata_queue);
- if (!pd->queue)
- goto err_free_pd;
+ cpumask_and(pd->cpumask.cbcpu, cbcpumask, cpu_active_mask);
+ return 0;
+}
- if (!alloc_cpumask_var(&pd->cpumask, GFP_KERNEL))
- goto err_free_queue;
+static void __padata_list_init(struct padata_list *pd_list)
+{
+ INIT_LIST_HEAD(&pd_list->list);
+ spin_lock_init(&pd_list->lock);
+}
- cpumask_and(pd->cpumask, cpumask, cpu_active_mask);
+/* Initialize all percpu queues used by serial workers */
+static void padata_init_squeues(struct parallel_data *pd)
+{
+ int cpu;
+ struct padata_serial_queue *squeue;
- for_each_cpu(cpu, pd->cpumask) {
- queue = per_cpu_ptr(pd->queue, cpu);
+ for_each_cpu(cpu, pd->cpumask.cbcpu) {
+ squeue = per_cpu_ptr(pd->squeue, cpu);
+ squeue->pd = pd;
+ __padata_list_init(&squeue->serial);
+ INIT_WORK(&squeue->work, padata_serial_worker);
+ }
+}
- queue->pd = pd;
+/* Initialize all percpu queues used by parallel workers */
+static void padata_init_pqueues(struct parallel_data *pd)
+{
+ int cpu_index, num_cpus, cpu;
+ struct padata_parallel_queue *pqueue;
- queue->cpu_index = cpu_index;
+ cpu_index = 0;
+ for_each_cpu(cpu, pd->cpumask.pcpu) {
+ pqueue = per_cpu_ptr(pd->pqueue, cpu);
+ pqueue->pd = pd;
+ pqueue->cpu_index = cpu_index;
cpu_index++;
- INIT_LIST_HEAD(&queue->reorder.list);
- INIT_LIST_HEAD(&queue->parallel.list);
- INIT_LIST_HEAD(&queue->serial.list);
- spin_lock_init(&queue->reorder.lock);
- spin_lock_init(&queue->parallel.lock);
- spin_lock_init(&queue->serial.lock);
-
- INIT_WORK(&queue->pwork, padata_parallel_worker);
- INIT_WORK(&queue->swork, padata_serial_worker);
- atomic_set(&queue->num_obj, 0);
+ __padata_list_init(&pqueue->reorder);
+ __padata_list_init(&pqueue->parallel);
+ INIT_WORK(&pqueue->work, padata_parallel_worker);
+ atomic_set(&pqueue->num_obj, 0);
}
- num_cpus = cpumask_weight(pd->cpumask);
- pd->max_seq_nr = (MAX_SEQ_NR / num_cpus) * num_cpus - 1;
+ num_cpus = cpumask_weight(pd->cpumask.pcpu);
+ pd->max_seq_nr = num_cpus ? (MAX_SEQ_NR / num_cpus) * num_cpus - 1 : 0;
+}
+
+/* Allocate and initialize the internal cpumask dependend resources. */
+static struct parallel_data *padata_alloc_pd(struct padata_instance *pinst,
+ const struct cpumask *pcpumask,
+ const struct cpumask *cbcpumask)
+{
+ struct parallel_data *pd;
+ pd = kzalloc(sizeof(struct parallel_data), GFP_KERNEL);
+ if (!pd)
+ goto err;
+
+ pd->pqueue = alloc_percpu(struct padata_parallel_queue);
+ if (!pd->pqueue)
+ goto err_free_pd;
+
+ pd->squeue = alloc_percpu(struct padata_serial_queue);
+ if (!pd->squeue)
+ goto err_free_pqueue;
+ if (padata_setup_cpumasks(pd, pcpumask, cbcpumask) < 0)
+ goto err_free_squeue;
+
+ padata_init_pqueues(pd);
+ padata_init_squeues(pd);
setup_timer(&pd->timer, padata_reorder_timer, (unsigned long)pd);
atomic_set(&pd->seq_nr, -1);
atomic_set(&pd->reorder_objects, 0);
@@ -446,8 +452,10 @@ static struct parallel_data *padata_alloc_pd(struct padata_instance *pinst,
return pd;
-err_free_queue:
- free_percpu(pd->queue);
+err_free_squeue:
+ free_percpu(pd->squeue);
+err_free_pqueue:
+ free_percpu(pd->pqueue);
err_free_pd:
kfree(pd);
err:
@@ -456,8 +464,10 @@ err:
static void padata_free_pd(struct parallel_data *pd)
{
- free_cpumask_var(pd->cpumask);
- free_percpu(pd->queue);
+ free_cpumask_var(pd->cpumask.pcpu);
+ free_cpumask_var(pd->cpumask.cbcpu);
+ free_percpu(pd->pqueue);
+ free_percpu(pd->squeue);
kfree(pd);
}
@@ -465,11 +475,12 @@ static void padata_free_pd(struct parallel_data *pd)
static void padata_flush_queues(struct parallel_data *pd)
{
int cpu;
- struct padata_queue *queue;
+ struct padata_parallel_queue *pqueue;
+ struct padata_serial_queue *squeue;
- for_each_cpu(cpu, pd->cpumask) {
- queue = per_cpu_ptr(pd->queue, cpu);
- flush_work(&queue->pwork);
+ for_each_cpu(cpu, pd->cpumask.pcpu) {
+ pqueue = per_cpu_ptr(pd->pqueue, cpu);
+ flush_work(&pqueue->work);
}
del_timer_sync(&pd->timer);
@@ -477,19 +488,39 @@ static void padata_flush_queues(struct parallel_data *pd)
if (atomic_read(&pd->reorder_objects))
padata_reorder(pd);
- for_each_cpu(cpu, pd->cpumask) {
- queue = per_cpu_ptr(pd->queue, cpu);
- flush_work(&queue->swork);
+ for_each_cpu(cpu, pd->cpumask.cbcpu) {
+ squeue = per_cpu_ptr(pd->squeue, cpu);
+ flush_work(&squeue->work);
}
BUG_ON(atomic_read(&pd->refcnt) != 0);
}
+static void __padata_start(struct padata_instance *pinst)
+{
+ pinst->flags |= PADATA_INIT;
+}
+
+static void __padata_stop(struct padata_instance *pinst)
+{
+ if (!(pinst->flags & PADATA_INIT))
+ return;
+
+ pinst->flags &= ~PADATA_INIT;
+
+ synchronize_rcu();
+
+ get_online_cpus();
+ padata_flush_queues(pinst->pd);
+ put_online_cpus();
+}
+
/* Replace the internal control stucture with a new one. */
static void padata_replace(struct padata_instance *pinst,
struct parallel_data *pd_new)
{
struct parallel_data *pd_old = pinst->pd;
+ int notification_mask = 0;
pinst->flags |= PADATA_RESET;
@@ -497,41 +528,162 @@ static void padata_replace(struct padata_instance *pinst,
synchronize_rcu();
+ if (!cpumask_equal(pd_old->cpumask.pcpu, pd_new->cpumask.pcpu))
+ notification_mask |= PADATA_CPU_PARALLEL;
+ if (!cpumask_equal(pd_old->cpumask.cbcpu, pd_new->cpumask.cbcpu))
+ notification_mask |= PADATA_CPU_SERIAL;
+
padata_flush_queues(pd_old);
padata_free_pd(pd_old);
+ if (notification_mask)
+ blocking_notifier_call_chain(&pinst->cpumask_change_notifier,
+ notification_mask,
+ &pd_new->cpumask);
+
pinst->flags &= ~PADATA_RESET;
}
/**
- * padata_set_cpumask - set the cpumask that padata should use
+ * padata_register_cpumask_notifier - Registers a notifier that will be called
+ * if either pcpu or cbcpu or both cpumasks change.
*
- * @pinst: padata instance
- * @cpumask: the cpumask to use
+ * @pinst: A poineter to padata instance
+ * @nblock: A pointer to notifier block.
*/
-int padata_set_cpumask(struct padata_instance *pinst,
- cpumask_var_t cpumask)
+int padata_register_cpumask_notifier(struct padata_instance *pinst,
+ struct notifier_block *nblock)
{
+ return blocking_notifier_chain_register(&pinst->cpumask_change_notifier,
+ nblock);
+}
+EXPORT_SYMBOL(padata_register_cpumask_notifier);
+
+/**
+ * padata_unregister_cpumask_notifier - Unregisters cpumask notifier
+ * registered earlier using padata_register_cpumask_notifier
+ *
+ * @pinst: A pointer to data instance.
+ * @nlock: A pointer to notifier block.
+ */
+int padata_unregister_cpumask_notifier(struct padata_instance *pinst,
+ struct notifier_block *nblock)
+{
+ return blocking_notifier_chain_unregister(
+ &pinst->cpumask_change_notifier,
+ nblock);
+}
+EXPORT_SYMBOL(padata_unregister_cpumask_notifier);
+
+
+/* If cpumask contains no active cpu, we mark the instance as invalid. */
+static bool padata_validate_cpumask(struct padata_instance *pinst,
+ const struct cpumask *cpumask)
+{
+ if (!cpumask_intersects(cpumask, cpu_active_mask)) {
+ pinst->flags |= PADATA_INVALID;
+ return false;
+ }
+
+ pinst->flags &= ~PADATA_INVALID;
+ return true;
+}
+
+static int __padata_set_cpumasks(struct padata_instance *pinst,
+ cpumask_var_t pcpumask,
+ cpumask_var_t cbcpumask)
+{
+ int valid;
struct parallel_data *pd;
- int err = 0;
+
+ valid = padata_validate_cpumask(pinst, pcpumask);
+ if (!valid) {
+ __padata_stop(pinst);
+ goto out_replace;
+ }
+
+ valid = padata_validate_cpumask(pinst, cbcpumask);
+ if (!valid)
+ __padata_stop(pinst);
+
+out_replace:
+ pd = padata_alloc_pd(pinst, pcpumask, cbcpumask);
+ if (!pd)
+ return -ENOMEM;
+
+ cpumask_copy(pinst->cpumask.pcpu, pcpumask);
+ cpumask_copy(pinst->cpumask.cbcpu, cbcpumask);
+
+ padata_replace(pinst, pd);
+
+ if (valid)
+ __padata_start(pinst);
+
+ return 0;
+}
+
+/**
+ * padata_set_cpumasks - Set both parallel and serial cpumasks. The first
+ * one is used by parallel workers and the second one
+ * by the wokers doing serialization.
+ *
+ * @pinst: padata instance
+ * @pcpumask: the cpumask to use for parallel workers
+ * @cbcpumask: the cpumsak to use for serial workers
+ */
+int padata_set_cpumasks(struct padata_instance *pinst, cpumask_var_t pcpumask,
+ cpumask_var_t cbcpumask)
+{
+ int err;
mutex_lock(&pinst->lock);
+ get_online_cpus();
+ err = __padata_set_cpumasks(pinst, pcpumask, cbcpumask);
+
+ put_online_cpus();
+ mutex_unlock(&pinst->lock);
+
+ return err;
+
+}
+EXPORT_SYMBOL(padata_set_cpumasks);
+
+/**
+ * padata_set_cpumask: Sets specified by @cpumask_type cpumask to the value
+ * equivalent to @cpumask.
+ *
+ * @pinst: padata instance
+ * @cpumask_type: PADATA_CPU_SERIAL or PADATA_CPU_PARALLEL corresponding
+ * to parallel and serial cpumasks respectively.
+ * @cpumask: the cpumask to use
+ */
+int padata_set_cpumask(struct padata_instance *pinst, int cpumask_type,
+ cpumask_var_t cpumask)
+{
+ struct cpumask *serial_mask, *parallel_mask;
+ int err = -EINVAL;
+
+ mutex_lock(&pinst->lock);
get_online_cpus();
- pd = padata_alloc_pd(pinst, cpumask);
- if (!pd) {
- err = -ENOMEM;
- goto out;
+ switch (cpumask_type) {
+ case PADATA_CPU_PARALLEL:
+ serial_mask = pinst->cpumask.cbcpu;
+ parallel_mask = cpumask;
+ break;
+ case PADATA_CPU_SERIAL:
+ parallel_mask = pinst->cpumask.pcpu;
+ serial_mask = cpumask;
+ break;
+ default:
+ goto out;
}
- cpumask_copy(pinst->cpumask, cpumask);
-
- padata_replace(pinst, pd);
+ err = __padata_set_cpumasks(pinst, parallel_mask, serial_mask);
out:
put_online_cpus();
-
mutex_unlock(&pinst->lock);
return err;
@@ -543,30 +695,48 @@ static int __padata_add_cpu(struct padata_instance *pinst, int cpu)
struct parallel_data *pd;
if (cpumask_test_cpu(cpu, cpu_active_mask)) {
- pd = padata_alloc_pd(pinst, pinst->cpumask);
+ pd = padata_alloc_pd(pinst, pinst->cpumask.pcpu,
+ pinst->cpumask.cbcpu);
if (!pd)
return -ENOMEM;
padata_replace(pinst, pd);
+
+ if (padata_validate_cpumask(pinst, pinst->cpumask.pcpu) &&
+ padata_validate_cpumask(pinst, pinst->cpumask.cbcpu))
+ __padata_start(pinst);
}
return 0;
}
-/**
- * padata_add_cpu - add a cpu to the padata cpumask
+ /**
+ * padata_add_cpu - add a cpu to one or both(parallel and serial)
+ * padata cpumasks.
*
* @pinst: padata instance
* @cpu: cpu to add
+ * @mask: bitmask of flags specifying to which cpumask @cpu shuld be added.
+ * The @mask may be any combination of the following flags:
+ * PADATA_CPU_SERIAL - serial cpumask
+ * PADATA_CPU_PARALLEL - parallel cpumask
*/
-int padata_add_cpu(struct padata_instance *pinst, int cpu)
+
+int padata_add_cpu(struct padata_instance *pinst, int cpu, int mask)
{
int err;
+ if (!(mask & (PADATA_CPU_SERIAL | PADATA_CPU_PARALLEL)))
+ return -EINVAL;
+
mutex_lock(&pinst->lock);
get_online_cpus();
- cpumask_set_cpu(cpu, pinst->cpumask);
+ if (mask & PADATA_CPU_SERIAL)
+ cpumask_set_cpu(cpu, pinst->cpumask.cbcpu);
+ if (mask & PADATA_CPU_PARALLEL)
+ cpumask_set_cpu(cpu, pinst->cpumask.pcpu);
+
err = __padata_add_cpu(pinst, cpu);
put_online_cpus();
@@ -578,10 +748,16 @@ EXPORT_SYMBOL(padata_add_cpu);
static int __padata_remove_cpu(struct padata_instance *pinst, int cpu)
{
- struct parallel_data *pd;
+ struct parallel_data *pd = NULL;
if (cpumask_test_cpu(cpu, cpu_online_mask)) {
- pd = padata_alloc_pd(pinst, pinst->cpumask);
+
+ if (!padata_validate_cpumask(pinst, pinst->cpumask.pcpu) ||
+ !padata_validate_cpumask(pinst, pinst->cpumask.cbcpu))
+ __padata_stop(pinst);
+
+ pd = padata_alloc_pd(pinst, pinst->cpumask.pcpu,
+ pinst->cpumask.cbcpu);
if (!pd)
return -ENOMEM;
@@ -591,20 +767,32 @@ static int __padata_remove_cpu(struct padata_instance *pinst, int cpu)
return 0;
}
-/**
- * padata_remove_cpu - remove a cpu from the padata cpumask
+ /**
+ * padata_remove_cpu - remove a cpu from the one or both(serial and paralell)
+ * padata cpumasks.
*
* @pinst: padata instance
* @cpu: cpu to remove
+ * @mask: bitmask specifying from which cpumask @cpu should be removed
+ * The @mask may be any combination of the following flags:
+ * PADATA_CPU_SERIAL - serial cpumask
+ * PADATA_CPU_PARALLEL - parallel cpumask
*/
-int padata_remove_cpu(struct padata_instance *pinst, int cpu)
+int padata_remove_cpu(struct padata_instance *pinst, int cpu, int mask)
{
int err;
+ if (!(mask & (PADATA_CPU_SERIAL | PADATA_CPU_PARALLEL)))
+ return -EINVAL;
+
mutex_lock(&pinst->lock);
get_online_cpus();
- cpumask_clear_cpu(cpu, pinst->cpumask);
+ if (mask & PADATA_CPU_SERIAL)
+ cpumask_clear_cpu(cpu, pinst->cpumask.cbcpu);
+ if (mask & PADATA_CPU_PARALLEL)
+ cpumask_clear_cpu(cpu, pinst->cpumask.pcpu);
+
err = __padata_remove_cpu(pinst, cpu);
put_online_cpus();
@@ -619,11 +807,20 @@ EXPORT_SYMBOL(padata_remove_cpu);
*
* @pinst: padata instance to start
*/
-void padata_start(struct padata_instance *pinst)
+int padata_start(struct padata_instance *pinst)
{
+ int err = 0;
+
mutex_lock(&pinst->lock);
- pinst->flags |= PADATA_INIT;
+
+ if (pinst->flags & PADATA_INVALID)
+ err =-EINVAL;
+
+ __padata_start(pinst);
+
mutex_unlock(&pinst->lock);
+
+ return err;
}
EXPORT_SYMBOL(padata_start);
@@ -635,12 +832,20 @@ EXPORT_SYMBOL(padata_start);
void padata_stop(struct padata_instance *pinst)
{
mutex_lock(&pinst->lock);
- pinst->flags &= ~PADATA_INIT;
+ __padata_stop(pinst);
mutex_unlock(&pinst->lock);
}
EXPORT_SYMBOL(padata_stop);
#ifdef CONFIG_HOTPLUG_CPU
+
+static inline int pinst_has_cpu(struct padata_instance *pinst, int cpu)
+{
+ return cpumask_test_cpu(cpu, pinst->cpumask.pcpu) ||
+ cpumask_test_cpu(cpu, pinst->cpumask.cbcpu);
+}
+
+
static int padata_cpu_callback(struct notifier_block *nfb,
unsigned long action, void *hcpu)
{
@@ -653,7 +858,7 @@ static int padata_cpu_callback(struct notifier_block *nfb,
switch (action) {
case CPU_ONLINE:
case CPU_ONLINE_FROZEN:
- if (!cpumask_test_cpu(cpu, pinst->cpumask))
+ if (!pinst_has_cpu(pinst, cpu))
break;
mutex_lock(&pinst->lock);
err = __padata_add_cpu(pinst, cpu);
@@ -664,7 +869,7 @@ static int padata_cpu_callback(struct notifier_block *nfb,
case CPU_DOWN_PREPARE:
case CPU_DOWN_PREPARE_FROZEN:
- if (!cpumask_test_cpu(cpu, pinst->cpumask))
+ if (!pinst_has_cpu(pinst, cpu))
break;
mutex_lock(&pinst->lock);
err = __padata_remove_cpu(pinst, cpu);
@@ -675,7 +880,7 @@ static int padata_cpu_callback(struct notifier_block *nfb,
case CPU_UP_CANCELED:
case CPU_UP_CANCELED_FROZEN:
- if (!cpumask_test_cpu(cpu, pinst->cpumask))
+ if (!pinst_has_cpu(pinst, cpu))
break;
mutex_lock(&pinst->lock);
__padata_remove_cpu(pinst, cpu);
@@ -683,7 +888,7 @@ static int padata_cpu_callback(struct notifier_block *nfb,
case CPU_DOWN_FAILED:
case CPU_DOWN_FAILED_FROZEN:
- if (!cpumask_test_cpu(cpu, pinst->cpumask))
+ if (!pinst_has_cpu(pinst, cpu))
break;
mutex_lock(&pinst->lock);
__padata_add_cpu(pinst, cpu);
@@ -694,36 +899,202 @@ static int padata_cpu_callback(struct notifier_block *nfb,
}
#endif
+static void __padata_free(struct padata_instance *pinst)
+{
+#ifdef CONFIG_HOTPLUG_CPU
+ unregister_hotcpu_notifier(&pinst->cpu_notifier);
+#endif
+
+ padata_stop(pinst);
+ padata_free_pd(pinst->pd);
+ free_cpumask_var(pinst->cpumask.pcpu);
+ free_cpumask_var(pinst->cpumask.cbcpu);
+ kfree(pinst);
+}
+
+#define kobj2pinst(_kobj) \
+ container_of(_kobj, struct padata_instance, kobj)
+#define attr2pentry(_attr) \
+ container_of(_attr, struct padata_sysfs_entry, attr)
+
+static void padata_sysfs_release(struct kobject *kobj)
+{
+ struct padata_instance *pinst = kobj2pinst(kobj);
+ __padata_free(pinst);
+}
+
+struct padata_sysfs_entry {
+ struct attribute attr;
+ ssize_t (*show)(struct padata_instance *, struct attribute *, char *);
+ ssize_t (*store)(struct padata_instance *, struct attribute *,
+ const char *, size_t);
+};
+
+static ssize_t show_cpumask(struct padata_instance *pinst,
+ struct attribute *attr, char *buf)
+{
+ struct cpumask *cpumask;
+ ssize_t len;
+
+ mutex_lock(&pinst->lock);
+ if (!strcmp(attr->name, "serial_cpumask"))
+ cpumask = pinst->cpumask.cbcpu;
+ else
+ cpumask = pinst->cpumask.pcpu;
+
+ len = bitmap_scnprintf(buf, PAGE_SIZE, cpumask_bits(cpumask),
+ nr_cpu_ids);
+ if (PAGE_SIZE - len < 2)
+ len = -EINVAL;
+ else
+ len += sprintf(buf + len, "\n");
+
+ mutex_unlock(&pinst->lock);
+ return len;
+}
+
+static ssize_t store_cpumask(struct padata_instance *pinst,
+ struct attribute *attr,
+ const char *buf, size_t count)
+{
+ cpumask_var_t new_cpumask;
+ ssize_t ret;
+ int mask_type;
+
+ if (!alloc_cpumask_var(&new_cpumask, GFP_KERNEL))
+ return -ENOMEM;
+
+ ret = bitmap_parse(buf, count, cpumask_bits(new_cpumask),
+ nr_cpumask_bits);
+ if (ret < 0)
+ goto out;
+
+ mask_type = !strcmp(attr->name, "serial_cpumask") ?
+ PADATA_CPU_SERIAL : PADATA_CPU_PARALLEL;
+ ret = padata_set_cpumask(pinst, mask_type, new_cpumask);
+ if (!ret)
+ ret = count;
+
+out:
+ free_cpumask_var(new_cpumask);
+ return ret;
+}
+
+#define PADATA_ATTR_RW(_name, _show_name, _store_name) \
+ static struct padata_sysfs_entry _name##_attr = \
+ __ATTR(_name, 0644, _show_name, _store_name)
+#define PADATA_ATTR_RO(_name, _show_name) \
+ static struct padata_sysfs_entry _name##_attr = \
+ __ATTR(_name, 0400, _show_name, NULL)
+
+PADATA_ATTR_RW(serial_cpumask, show_cpumask, store_cpumask);
+PADATA_ATTR_RW(parallel_cpumask, show_cpumask, store_cpumask);
+
+/*
+ * Padata sysfs provides the following objects:
+ * serial_cpumask [RW] - cpumask for serial workers
+ * parallel_cpumask [RW] - cpumask for parallel workers
+ */
+static struct attribute *padata_default_attrs[] = {
+ &serial_cpumask_attr.attr,
+ &parallel_cpumask_attr.attr,
+ NULL,
+};
+
+static ssize_t padata_sysfs_show(struct kobject *kobj,
+ struct attribute *attr, char *buf)
+{
+ struct padata_instance *pinst;
+ struct padata_sysfs_entry *pentry;
+ ssize_t ret = -EIO;
+
+ pinst = kobj2pinst(kobj);
+ pentry = attr2pentry(attr);
+ if (pentry->show)
+ ret = pentry->show(pinst, attr, buf);
+
+ return ret;
+}
+
+static ssize_t padata_sysfs_store(struct kobject *kobj, struct attribute *attr,
+ const char *buf, size_t count)
+{
+ struct padata_instance *pinst;
+ struct padata_sysfs_entry *pentry;
+ ssize_t ret = -EIO;
+
+ pinst = kobj2pinst(kobj);
+ pentry = attr2pentry(attr);
+ if (pentry->show)
+ ret = pentry->store(pinst, attr, buf, count);
+
+ return ret;
+}
+
+static const struct sysfs_ops padata_sysfs_ops = {
+ .show = padata_sysfs_show,
+ .store = padata_sysfs_store,
+};
+
+static struct kobj_type padata_attr_type = {
+ .sysfs_ops = &padata_sysfs_ops,
+ .default_attrs = padata_default_attrs,
+ .release = padata_sysfs_release,
+};
+
/**
- * padata_alloc - allocate and initialize a padata instance
+ * padata_alloc_possible - Allocate and initialize padata instance.
+ * Use the cpu_possible_mask for serial and
+ * parallel workers.
*
- * @cpumask: cpumask that padata uses for parallelization
* @wq: workqueue to use for the allocated padata instance
*/
-struct padata_instance *padata_alloc(const struct cpumask *cpumask,
- struct workqueue_struct *wq)
+struct padata_instance *padata_alloc_possible(struct workqueue_struct *wq)
+{
+ return padata_alloc(wq, cpu_possible_mask, cpu_possible_mask);
+}
+EXPORT_SYMBOL(padata_alloc_possible);
+
+/**
+ * padata_alloc - allocate and initialize a padata instance and specify
+ * cpumasks for serial and parallel workers.
+ *
+ * @wq: workqueue to use for the allocated padata instance
+ * @pcpumask: cpumask that will be used for padata parallelization
+ * @cbcpumask: cpumask that will be used for padata serialization
+ */
+struct padata_instance *padata_alloc(struct workqueue_struct *wq,
+ const struct cpumask *pcpumask,
+ const struct cpumask *cbcpumask)
{
struct padata_instance *pinst;
- struct parallel_data *pd;
+ struct parallel_data *pd = NULL;
pinst = kzalloc(sizeof(struct padata_instance), GFP_KERNEL);
if (!pinst)
goto err;
get_online_cpus();
-
- pd = padata_alloc_pd(pinst, cpumask);
- if (!pd)
+ if (!alloc_cpumask_var(&pinst->cpumask.pcpu, GFP_KERNEL))
goto err_free_inst;
+ if (!alloc_cpumask_var(&pinst->cpumask.cbcpu, GFP_KERNEL)) {
+ free_cpumask_var(pinst->cpumask.pcpu);
+ goto err_free_inst;
+ }
+ if (!padata_validate_cpumask(pinst, pcpumask) ||
+ !padata_validate_cpumask(pinst, cbcpumask))
+ goto err_free_masks;
- if (!alloc_cpumask_var(&pinst->cpumask, GFP_KERNEL))
- goto err_free_pd;
+ pd = padata_alloc_pd(pinst, pcpumask, cbcpumask);
+ if (!pd)
+ goto err_free_masks;
rcu_assign_pointer(pinst->pd, pd);
pinst->wq = wq;
- cpumask_copy(pinst->cpumask, cpumask);
+ cpumask_copy(pinst->cpumask.pcpu, pcpumask);
+ cpumask_copy(pinst->cpumask.cbcpu, cbcpumask);
pinst->flags = 0;
@@ -735,12 +1106,15 @@ struct padata_instance *padata_alloc(const struct cpumask *cpumask,
put_online_cpus();
+ BLOCKING_INIT_NOTIFIER_HEAD(&pinst->cpumask_change_notifier);
+ kobject_init(&pinst->kobj, &padata_attr_type);
mutex_init(&pinst->lock);
return pinst;
-err_free_pd:
- padata_free_pd(pd);
+err_free_masks:
+ free_cpumask_var(pinst->cpumask.pcpu);
+ free_cpumask_var(pinst->cpumask.cbcpu);
err_free_inst:
kfree(pinst);
put_online_cpus();
@@ -756,19 +1130,6 @@ EXPORT_SYMBOL(padata_alloc);
*/
void padata_free(struct padata_instance *pinst)
{
- padata_stop(pinst);
-
- synchronize_rcu();
-
-#ifdef CONFIG_HOTPLUG_CPU
- unregister_hotcpu_notifier(&pinst->cpu_notifier);
-#endif
- get_online_cpus();
- padata_flush_queues(pinst->pd);
- put_online_cpus();
-
- padata_free_pd(pinst->pd);
- free_cpumask_var(pinst->cpumask);
- kfree(pinst);
+ kobject_put(&pinst->kobj);
}
EXPORT_SYMBOL(padata_free);
diff --git a/kernel/perf_event.c b/kernel/perf_event.c
index ff86c558af4..403d1804b19 100644
--- a/kernel/perf_event.c
+++ b/kernel/perf_event.c
@@ -214,7 +214,7 @@ static void perf_unpin_context(struct perf_event_context *ctx)
static inline u64 perf_clock(void)
{
- return cpu_clock(raw_smp_processor_id());
+ return local_clock();
}
/*
@@ -675,7 +675,6 @@ group_sched_in(struct perf_event *group_event,
struct perf_event *event, *partial_group = NULL;
const struct pmu *pmu = group_event->pmu;
bool txn = false;
- int ret;
if (group_event->state == PERF_EVENT_STATE_OFF)
return 0;
@@ -703,14 +702,8 @@ group_sched_in(struct perf_event *group_event,
}
}
- if (!txn)
- return 0;
-
- ret = pmu->commit_txn(pmu);
- if (!ret) {
- pmu->cancel_txn(pmu);
+ if (!txn || !pmu->commit_txn(pmu))
return 0;
- }
group_error:
/*
@@ -1155,9 +1148,9 @@ static void __perf_event_sync_stat(struct perf_event *event,
* In order to keep per-task stats reliable we need to flip the event
* values when we flip the contexts.
*/
- value = atomic64_read(&next_event->count);
- value = atomic64_xchg(&event->count, value);
- atomic64_set(&next_event->count, value);
+ value = local64_read(&next_event->count);
+ value = local64_xchg(&event->count, value);
+ local64_set(&next_event->count, value);
swap(event->total_time_enabled, next_event->total_time_enabled);
swap(event->total_time_running, next_event->total_time_running);
@@ -1547,10 +1540,10 @@ static void perf_adjust_period(struct perf_event *event, u64 nsec, u64 count)
hwc->sample_period = sample_period;
- if (atomic64_read(&hwc->period_left) > 8*sample_period) {
+ if (local64_read(&hwc->period_left) > 8*sample_period) {
perf_disable();
perf_event_stop(event);
- atomic64_set(&hwc->period_left, 0);
+ local64_set(&hwc->period_left, 0);
perf_event_start(event);
perf_enable();
}
@@ -1591,7 +1584,7 @@ static void perf_ctx_adjust_freq(struct perf_event_context *ctx)
perf_disable();
event->pmu->read(event);
- now = atomic64_read(&event->count);
+ now = local64_read(&event->count);
delta = now - hwc->freq_count_stamp;
hwc->freq_count_stamp = now;
@@ -1743,6 +1736,11 @@ static void __perf_event_read(void *info)
event->pmu->read(event);
}
+static inline u64 perf_event_count(struct perf_event *event)
+{
+ return local64_read(&event->count) + atomic64_read(&event->child_count);
+}
+
static u64 perf_event_read(struct perf_event *event)
{
/*
@@ -1762,7 +1760,7 @@ static u64 perf_event_read(struct perf_event *event)
raw_spin_unlock_irqrestore(&ctx->lock, flags);
}
- return atomic64_read(&event->count);
+ return perf_event_count(event);
}
/*
@@ -1883,7 +1881,7 @@ static void free_event_rcu(struct rcu_head *head)
}
static void perf_pending_sync(struct perf_event *event);
-static void perf_mmap_data_put(struct perf_mmap_data *data);
+static void perf_buffer_put(struct perf_buffer *buffer);
static void free_event(struct perf_event *event)
{
@@ -1891,7 +1889,7 @@ static void free_event(struct perf_event *event)
if (!event->parent) {
atomic_dec(&nr_events);
- if (event->attr.mmap)
+ if (event->attr.mmap || event->attr.mmap_data)
atomic_dec(&nr_mmap_events);
if (event->attr.comm)
atomic_dec(&nr_comm_events);
@@ -1899,9 +1897,9 @@ static void free_event(struct perf_event *event)
atomic_dec(&nr_task_events);
}
- if (event->data) {
- perf_mmap_data_put(event->data);
- event->data = NULL;
+ if (event->buffer) {
+ perf_buffer_put(event->buffer);
+ event->buffer = NULL;
}
if (event->destroy)
@@ -2126,13 +2124,13 @@ perf_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
static unsigned int perf_poll(struct file *file, poll_table *wait)
{
struct perf_event *event = file->private_data;
- struct perf_mmap_data *data;
+ struct perf_buffer *buffer;
unsigned int events = POLL_HUP;
rcu_read_lock();
- data = rcu_dereference(event->data);
- if (data)
- events = atomic_xchg(&data->poll, 0);
+ buffer = rcu_dereference(event->buffer);
+ if (buffer)
+ events = atomic_xchg(&buffer->poll, 0);
rcu_read_unlock();
poll_wait(file, &event->waitq, wait);
@@ -2143,7 +2141,7 @@ static unsigned int perf_poll(struct file *file, poll_table *wait)
static void perf_event_reset(struct perf_event *event)
{
(void)perf_event_read(event);
- atomic64_set(&event->count, 0);
+ local64_set(&event->count, 0);
perf_event_update_userpage(event);
}
@@ -2342,14 +2340,14 @@ static int perf_event_index(struct perf_event *event)
void perf_event_update_userpage(struct perf_event *event)
{
struct perf_event_mmap_page *userpg;
- struct perf_mmap_data *data;
+ struct perf_buffer *buffer;
rcu_read_lock();
- data = rcu_dereference(event->data);
- if (!data)
+ buffer = rcu_dereference(event->buffer);
+ if (!buffer)
goto unlock;
- userpg = data->user_page;
+ userpg = buffer->user_page;
/*
* Disable preemption so as to not let the corresponding user-space
@@ -2359,9 +2357,9 @@ void perf_event_update_userpage(struct perf_event *event)
++userpg->lock;
barrier();
userpg->index = perf_event_index(event);
- userpg->offset = atomic64_read(&event->count);
+ userpg->offset = perf_event_count(event);
if (event->state == PERF_EVENT_STATE_ACTIVE)
- userpg->offset -= atomic64_read(&event->hw.prev_count);
+ userpg->offset -= local64_read(&event->hw.prev_count);
userpg->time_enabled = event->total_time_enabled +
atomic64_read(&event->child_total_time_enabled);
@@ -2376,6 +2374,25 @@ unlock:
rcu_read_unlock();
}
+static unsigned long perf_data_size(struct perf_buffer *buffer);
+
+static void
+perf_buffer_init(struct perf_buffer *buffer, long watermark, int flags)
+{
+ long max_size = perf_data_size(buffer);
+
+ if (watermark)
+ buffer->watermark = min(max_size, watermark);
+
+ if (!buffer->watermark)
+ buffer->watermark = max_size / 2;
+
+ if (flags & PERF_BUFFER_WRITABLE)
+ buffer->writable = 1;
+
+ atomic_set(&buffer->refcount, 1);
+}
+
#ifndef CONFIG_PERF_USE_VMALLOC
/*
@@ -2383,15 +2400,15 @@ unlock:
*/
static struct page *
-perf_mmap_to_page(struct perf_mmap_data *data, unsigned long pgoff)
+perf_mmap_to_page(struct perf_buffer *buffer, unsigned long pgoff)
{
- if (pgoff > data->nr_pages)
+ if (pgoff > buffer->nr_pages)
return NULL;
if (pgoff == 0)
- return virt_to_page(data->user_page);
+ return virt_to_page(buffer->user_page);
- return virt_to_page(data->data_pages[pgoff - 1]);
+ return virt_to_page(buffer->data_pages[pgoff - 1]);
}
static void *perf_mmap_alloc_page(int cpu)
@@ -2407,42 +2424,44 @@ static void *perf_mmap_alloc_page(int cpu)
return page_address(page);
}
-static struct perf_mmap_data *
-perf_mmap_data_alloc(struct perf_event *event, int nr_pages)
+static struct perf_buffer *
+perf_buffer_alloc(int nr_pages, long watermark, int cpu, int flags)
{
- struct perf_mmap_data *data;
+ struct perf_buffer *buffer;
unsigned long size;
int i;
- size = sizeof(struct perf_mmap_data);
+ size = sizeof(struct perf_buffer);
size += nr_pages * sizeof(void *);
- data = kzalloc(size, GFP_KERNEL);
- if (!data)
+ buffer = kzalloc(size, GFP_KERNEL);
+ if (!buffer)
goto fail;
- data->user_page = perf_mmap_alloc_page(event->cpu);
- if (!data->user_page)
+ buffer->user_page = perf_mmap_alloc_page(cpu);
+ if (!buffer->user_page)
goto fail_user_page;
for (i = 0; i < nr_pages; i++) {
- data->data_pages[i] = perf_mmap_alloc_page(event->cpu);
- if (!data->data_pages[i])
+ buffer->data_pages[i] = perf_mmap_alloc_page(cpu);
+ if (!buffer->data_pages[i])
goto fail_data_pages;
}
- data->nr_pages = nr_pages;
+ buffer->nr_pages = nr_pages;
+
+ perf_buffer_init(buffer, watermark, flags);
- return data;
+ return buffer;
fail_data_pages:
for (i--; i >= 0; i--)
- free_page((unsigned long)data->data_pages[i]);
+ free_page((unsigned long)buffer->data_pages[i]);
- free_page((unsigned long)data->user_page);
+ free_page((unsigned long)buffer->user_page);
fail_user_page:
- kfree(data);
+ kfree(buffer);
fail:
return NULL;
@@ -2456,17 +2475,17 @@ static void perf_mmap_free_page(unsigned long addr)
__free_page(page);
}
-static void perf_mmap_data_free(struct perf_mmap_data *data)
+static void perf_buffer_free(struct perf_buffer *buffer)
{
int i;
- perf_mmap_free_page((unsigned long)data->user_page);
- for (i = 0; i < data->nr_pages; i++)
- perf_mmap_free_page((unsigned long)data->data_pages[i]);
- kfree(data);
+ perf_mmap_free_page((unsigned long)buffer->user_page);
+ for (i = 0; i < buffer->nr_pages; i++)
+ perf_mmap_free_page((unsigned long)buffer->data_pages[i]);
+ kfree(buffer);
}
-static inline int page_order(struct perf_mmap_data *data)
+static inline int page_order(struct perf_buffer *buffer)
{
return 0;
}
@@ -2479,18 +2498,18 @@ static inline int page_order(struct perf_mmap_data *data)
* Required for architectures that have d-cache aliasing issues.
*/
-static inline int page_order(struct perf_mmap_data *data)
+static inline int page_order(struct perf_buffer *buffer)
{
- return data->page_order;
+ return buffer->page_order;
}
static struct page *
-perf_mmap_to_page(struct perf_mmap_data *data, unsigned long pgoff)
+perf_mmap_to_page(struct perf_buffer *buffer, unsigned long pgoff)
{
- if (pgoff > (1UL << page_order(data)))
+ if (pgoff > (1UL << page_order(buffer)))
return NULL;
- return vmalloc_to_page((void *)data->user_page + pgoff * PAGE_SIZE);
+ return vmalloc_to_page((void *)buffer->user_page + pgoff * PAGE_SIZE);
}
static void perf_mmap_unmark_page(void *addr)
@@ -2500,57 +2519,59 @@ static void perf_mmap_unmark_page(void *addr)
page->mapping = NULL;
}
-static void perf_mmap_data_free_work(struct work_struct *work)
+static void perf_buffer_free_work(struct work_struct *work)
{
- struct perf_mmap_data *data;
+ struct perf_buffer *buffer;
void *base;
int i, nr;
- data = container_of(work, struct perf_mmap_data, work);
- nr = 1 << page_order(data);
+ buffer = container_of(work, struct perf_buffer, work);
+ nr = 1 << page_order(buffer);
- base = data->user_page;
+ base = buffer->user_page;
for (i = 0; i < nr + 1; i++)
perf_mmap_unmark_page(base + (i * PAGE_SIZE));
vfree(base);
- kfree(data);
+ kfree(buffer);
}
-static void perf_mmap_data_free(struct perf_mmap_data *data)
+static void perf_buffer_free(struct perf_buffer *buffer)
{
- schedule_work(&data->work);
+ schedule_work(&buffer->work);
}
-static struct perf_mmap_data *
-perf_mmap_data_alloc(struct perf_event *event, int nr_pages)
+static struct perf_buffer *
+perf_buffer_alloc(int nr_pages, long watermark, int cpu, int flags)
{
- struct perf_mmap_data *data;
+ struct perf_buffer *buffer;
unsigned long size;
void *all_buf;
- size = sizeof(struct perf_mmap_data);
+ size = sizeof(struct perf_buffer);
size += sizeof(void *);
- data = kzalloc(size, GFP_KERNEL);
- if (!data)
+ buffer = kzalloc(size, GFP_KERNEL);
+ if (!buffer)
goto fail;
- INIT_WORK(&data->work, perf_mmap_data_free_work);
+ INIT_WORK(&buffer->work, perf_buffer_free_work);
all_buf = vmalloc_user((nr_pages + 1) * PAGE_SIZE);
if (!all_buf)
goto fail_all_buf;
- data->user_page = all_buf;
- data->data_pages[0] = all_buf + PAGE_SIZE;
- data->page_order = ilog2(nr_pages);
- data->nr_pages = 1;
+ buffer->user_page = all_buf;
+ buffer->data_pages[0] = all_buf + PAGE_SIZE;
+ buffer->page_order = ilog2(nr_pages);
+ buffer->nr_pages = 1;
+
+ perf_buffer_init(buffer, watermark, flags);
- return data;
+ return buffer;
fail_all_buf:
- kfree(data);
+ kfree(buffer);
fail:
return NULL;
@@ -2558,15 +2579,15 @@ fail:
#endif
-static unsigned long perf_data_size(struct perf_mmap_data *data)
+static unsigned long perf_data_size(struct perf_buffer *buffer)
{
- return data->nr_pages << (PAGE_SHIFT + page_order(data));
+ return buffer->nr_pages << (PAGE_SHIFT + page_order(buffer));
}
static int perf_mmap_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
{
struct perf_event *event = vma->vm_file->private_data;
- struct perf_mmap_data *data;
+ struct perf_buffer *buffer;
int ret = VM_FAULT_SIGBUS;
if (vmf->flags & FAULT_FLAG_MKWRITE) {
@@ -2576,14 +2597,14 @@ static int perf_mmap_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
}
rcu_read_lock();
- data = rcu_dereference(event->data);
- if (!data)
+ buffer = rcu_dereference(event->buffer);
+ if (!buffer)
goto unlock;
if (vmf->pgoff && (vmf->flags & FAULT_FLAG_WRITE))
goto unlock;
- vmf->page = perf_mmap_to_page(data, vmf->pgoff);
+ vmf->page = perf_mmap_to_page(buffer, vmf->pgoff);
if (!vmf->page)
goto unlock;
@@ -2598,52 +2619,35 @@ unlock:
return ret;
}
-static void
-perf_mmap_data_init(struct perf_event *event, struct perf_mmap_data *data)
-{
- long max_size = perf_data_size(data);
-
- if (event->attr.watermark) {
- data->watermark = min_t(long, max_size,
- event->attr.wakeup_watermark);
- }
-
- if (!data->watermark)
- data->watermark = max_size / 2;
-
- atomic_set(&data->refcount, 1);
- rcu_assign_pointer(event->data, data);
-}
-
-static void perf_mmap_data_free_rcu(struct rcu_head *rcu_head)
+static void perf_buffer_free_rcu(struct rcu_head *rcu_head)
{
- struct perf_mmap_data *data;
+ struct perf_buffer *buffer;
- data = container_of(rcu_head, struct perf_mmap_data, rcu_head);
- perf_mmap_data_free(data);
+ buffer = container_of(rcu_head, struct perf_buffer, rcu_head);
+ perf_buffer_free(buffer);
}
-static struct perf_mmap_data *perf_mmap_data_get(struct perf_event *event)
+static struct perf_buffer *perf_buffer_get(struct perf_event *event)
{
- struct perf_mmap_data *data;
+ struct perf_buffer *buffer;
rcu_read_lock();
- data = rcu_dereference(event->data);
- if (data) {
- if (!atomic_inc_not_zero(&data->refcount))
- data = NULL;
+ buffer = rcu_dereference(event->buffer);
+ if (buffer) {
+ if (!atomic_inc_not_zero(&buffer->refcount))
+ buffer = NULL;
}
rcu_read_unlock();
- return data;
+ return buffer;
}
-static void perf_mmap_data_put(struct perf_mmap_data *data)
+static void perf_buffer_put(struct perf_buffer *buffer)
{
- if (!atomic_dec_and_test(&data->refcount))
+ if (!atomic_dec_and_test(&buffer->refcount))
return;
- call_rcu(&data->rcu_head, perf_mmap_data_free_rcu);
+ call_rcu(&buffer->rcu_head, perf_buffer_free_rcu);
}
static void perf_mmap_open(struct vm_area_struct *vma)
@@ -2658,16 +2662,16 @@ static void perf_mmap_close(struct vm_area_struct *vma)
struct perf_event *event = vma->vm_file->private_data;
if (atomic_dec_and_mutex_lock(&event->mmap_count, &event->mmap_mutex)) {
- unsigned long size = perf_data_size(event->data);
+ unsigned long size = perf_data_size(event->buffer);
struct user_struct *user = event->mmap_user;
- struct perf_mmap_data *data = event->data;
+ struct perf_buffer *buffer = event->buffer;
atomic_long_sub((size >> PAGE_SHIFT) + 1, &user->locked_vm);
vma->vm_mm->locked_vm -= event->mmap_locked;
- rcu_assign_pointer(event->data, NULL);
+ rcu_assign_pointer(event->buffer, NULL);
mutex_unlock(&event->mmap_mutex);
- perf_mmap_data_put(data);
+ perf_buffer_put(buffer);
free_uid(user);
}
}
@@ -2685,11 +2689,11 @@ static int perf_mmap(struct file *file, struct vm_area_struct *vma)
unsigned long user_locked, user_lock_limit;
struct user_struct *user = current_user();
unsigned long locked, lock_limit;
- struct perf_mmap_data *data;
+ struct perf_buffer *buffer;
unsigned long vma_size;
unsigned long nr_pages;
long user_extra, extra;
- int ret = 0;
+ int ret = 0, flags = 0;
/*
* Don't allow mmap() of inherited per-task counters. This would
@@ -2706,7 +2710,7 @@ static int perf_mmap(struct file *file, struct vm_area_struct *vma)
nr_pages = (vma_size / PAGE_SIZE) - 1;
/*
- * If we have data pages ensure they're a power-of-two number, so we
+ * If we have buffer pages ensure they're a power-of-two number, so we
* can do bitmasks instead of modulo.
*/
if (nr_pages != 0 && !is_power_of_2(nr_pages))
@@ -2720,9 +2724,9 @@ static int perf_mmap(struct file *file, struct vm_area_struct *vma)
WARN_ON_ONCE(event->ctx->parent_ctx);
mutex_lock(&event->mmap_mutex);
- if (event->data) {
- if (event->data->nr_pages == nr_pages)
- atomic_inc(&event->data->refcount);
+ if (event->buffer) {
+ if (event->buffer->nr_pages == nr_pages)
+ atomic_inc(&event->buffer->refcount);
else
ret = -EINVAL;
goto unlock;
@@ -2752,17 +2756,18 @@ static int perf_mmap(struct file *file, struct vm_area_struct *vma)
goto unlock;
}
- WARN_ON(event->data);
+ WARN_ON(event->buffer);
+
+ if (vma->vm_flags & VM_WRITE)
+ flags |= PERF_BUFFER_WRITABLE;
- data = perf_mmap_data_alloc(event, nr_pages);
- if (!data) {
+ buffer = perf_buffer_alloc(nr_pages, event->attr.wakeup_watermark,
+ event->cpu, flags);
+ if (!buffer) {
ret = -ENOMEM;
goto unlock;
}
-
- perf_mmap_data_init(event, data);
- if (vma->vm_flags & VM_WRITE)
- event->data->writable = 1;
+ rcu_assign_pointer(event->buffer, buffer);
atomic_long_add(user_extra, &user->locked_vm);
event->mmap_locked = extra;
@@ -2941,11 +2946,6 @@ __weak struct perf_callchain_entry *perf_callchain(struct pt_regs *regs)
return NULL;
}
-__weak
-void perf_arch_fetch_caller_regs(struct pt_regs *regs, unsigned long ip, int skip)
-{
-}
-
/*
* We assume there is only KVM supporting the callbacks.
@@ -2971,15 +2971,15 @@ EXPORT_SYMBOL_GPL(perf_unregister_guest_info_callbacks);
/*
* Output
*/
-static bool perf_output_space(struct perf_mmap_data *data, unsigned long tail,
+static bool perf_output_space(struct perf_buffer *buffer, unsigned long tail,
unsigned long offset, unsigned long head)
{
unsigned long mask;
- if (!data->writable)
+ if (!buffer->writable)
return true;
- mask = perf_data_size(data) - 1;
+ mask = perf_data_size(buffer) - 1;
offset = (offset - tail) & mask;
head = (head - tail) & mask;
@@ -2992,7 +2992,7 @@ static bool perf_output_space(struct perf_mmap_data *data, unsigned long tail,
static void perf_output_wakeup(struct perf_output_handle *handle)
{
- atomic_set(&handle->data->poll, POLL_IN);
+ atomic_set(&handle->buffer->poll, POLL_IN);
if (handle->nmi) {
handle->event->pending_wakeup = 1;
@@ -3012,45 +3012,45 @@ static void perf_output_wakeup(struct perf_output_handle *handle)
*/
static void perf_output_get_handle(struct perf_output_handle *handle)
{
- struct perf_mmap_data *data = handle->data;
+ struct perf_buffer *buffer = handle->buffer;
preempt_disable();
- local_inc(&data->nest);
- handle->wakeup = local_read(&data->wakeup);
+ local_inc(&buffer->nest);
+ handle->wakeup = local_read(&buffer->wakeup);
}
static void perf_output_put_handle(struct perf_output_handle *handle)
{
- struct perf_mmap_data *data = handle->data;
+ struct perf_buffer *buffer = handle->buffer;
unsigned long head;
again:
- head = local_read(&data->head);
+ head = local_read(&buffer->head);
/*
* IRQ/NMI can happen here, which means we can miss a head update.
*/
- if (!local_dec_and_test(&data->nest))
+ if (!local_dec_and_test(&buffer->nest))
goto out;
/*
* Publish the known good head. Rely on the full barrier implied
- * by atomic_dec_and_test() order the data->head read and this
+ * by atomic_dec_and_test() order the buffer->head read and this
* write.
*/
- data->user_page->data_head = head;
+ buffer->user_page->data_head = head;
/*
* Now check if we missed an update, rely on the (compiler)
- * barrier in atomic_dec_and_test() to re-read data->head.
+ * barrier in atomic_dec_and_test() to re-read buffer->head.
*/
- if (unlikely(head != local_read(&data->head))) {
- local_inc(&data->nest);
+ if (unlikely(head != local_read(&buffer->head))) {
+ local_inc(&buffer->nest);
goto again;
}
- if (handle->wakeup != local_read(&data->wakeup))
+ if (handle->wakeup != local_read(&buffer->wakeup))
perf_output_wakeup(handle);
out:
@@ -3070,12 +3070,12 @@ __always_inline void perf_output_copy(struct perf_output_handle *handle,
buf += size;
handle->size -= size;
if (!handle->size) {
- struct perf_mmap_data *data = handle->data;
+ struct perf_buffer *buffer = handle->buffer;
handle->page++;
- handle->page &= data->nr_pages - 1;
- handle->addr = data->data_pages[handle->page];
- handle->size = PAGE_SIZE << page_order(data);
+ handle->page &= buffer->nr_pages - 1;
+ handle->addr = buffer->data_pages[handle->page];
+ handle->size = PAGE_SIZE << page_order(buffer);
}
} while (len);
}
@@ -3084,7 +3084,7 @@ int perf_output_begin(struct perf_output_handle *handle,
struct perf_event *event, unsigned int size,
int nmi, int sample)
{
- struct perf_mmap_data *data;
+ struct perf_buffer *buffer;
unsigned long tail, offset, head;
int have_lost;
struct {
@@ -3100,19 +3100,19 @@ int perf_output_begin(struct perf_output_handle *handle,
if (event->parent)
event = event->parent;
- data = rcu_dereference(event->data);
- if (!data)
+ buffer = rcu_dereference(event->buffer);
+ if (!buffer)
goto out;
- handle->data = data;
+ handle->buffer = buffer;
handle->event = event;
handle->nmi = nmi;
handle->sample = sample;
- if (!data->nr_pages)
+ if (!buffer->nr_pages)
goto out;
- have_lost = local_read(&data->lost);
+ have_lost = local_read(&buffer->lost);
if (have_lost)
size += sizeof(lost_event);
@@ -3124,30 +3124,30 @@ int perf_output_begin(struct perf_output_handle *handle,
* tail pointer. So that all reads will be completed before the
* write is issued.
*/
- tail = ACCESS_ONCE(data->user_page->data_tail);
+ tail = ACCESS_ONCE(buffer->user_page->data_tail);
smp_rmb();
- offset = head = local_read(&data->head);
+ offset = head = local_read(&buffer->head);
head += size;
- if (unlikely(!perf_output_space(data, tail, offset, head)))
+ if (unlikely(!perf_output_space(buffer, tail, offset, head)))
goto fail;
- } while (local_cmpxchg(&data->head, offset, head) != offset);
+ } while (local_cmpxchg(&buffer->head, offset, head) != offset);
- if (head - local_read(&data->wakeup) > data->watermark)
- local_add(data->watermark, &data->wakeup);
+ if (head - local_read(&buffer->wakeup) > buffer->watermark)
+ local_add(buffer->watermark, &buffer->wakeup);
- handle->page = offset >> (PAGE_SHIFT + page_order(data));
- handle->page &= data->nr_pages - 1;
- handle->size = offset & ((PAGE_SIZE << page_order(data)) - 1);
- handle->addr = data->data_pages[handle->page];
+ handle->page = offset >> (PAGE_SHIFT + page_order(buffer));
+ handle->page &= buffer->nr_pages - 1;
+ handle->size = offset & ((PAGE_SIZE << page_order(buffer)) - 1);
+ handle->addr = buffer->data_pages[handle->page];
handle->addr += handle->size;
- handle->size = (PAGE_SIZE << page_order(data)) - handle->size;
+ handle->size = (PAGE_SIZE << page_order(buffer)) - handle->size;
if (have_lost) {
lost_event.header.type = PERF_RECORD_LOST;
lost_event.header.misc = 0;
lost_event.header.size = sizeof(lost_event);
lost_event.id = event->id;
- lost_event.lost = local_xchg(&data->lost, 0);
+ lost_event.lost = local_xchg(&buffer->lost, 0);
perf_output_put(handle, lost_event);
}
@@ -3155,7 +3155,7 @@ int perf_output_begin(struct perf_output_handle *handle,
return 0;
fail:
- local_inc(&data->lost);
+ local_inc(&buffer->lost);
perf_output_put_handle(handle);
out:
rcu_read_unlock();
@@ -3166,15 +3166,15 @@ out:
void perf_output_end(struct perf_output_handle *handle)
{
struct perf_event *event = handle->event;
- struct perf_mmap_data *data = handle->data;
+ struct perf_buffer *buffer = handle->buffer;
int wakeup_events = event->attr.wakeup_events;
if (handle->sample && wakeup_events) {
- int events = local_inc_return(&data->events);
+ int events = local_inc_return(&buffer->events);
if (events >= wakeup_events) {
- local_sub(wakeup_events, &data->events);
- local_inc(&data->wakeup);
+ local_sub(wakeup_events, &buffer->events);
+ local_inc(&buffer->wakeup);
}
}
@@ -3211,7 +3211,7 @@ static void perf_output_read_one(struct perf_output_handle *handle,
u64 values[4];
int n = 0;
- values[n++] = atomic64_read(&event->count);
+ values[n++] = perf_event_count(event);
if (read_format & PERF_FORMAT_TOTAL_TIME_ENABLED) {
values[n++] = event->total_time_enabled +
atomic64_read(&event->child_total_time_enabled);
@@ -3248,7 +3248,7 @@ static void perf_output_read_group(struct perf_output_handle *handle,
if (leader != event)
leader->pmu->read(leader);
- values[n++] = atomic64_read(&leader->count);
+ values[n++] = perf_event_count(leader);
if (read_format & PERF_FORMAT_ID)
values[n++] = primary_event_id(leader);
@@ -3260,7 +3260,7 @@ static void perf_output_read_group(struct perf_output_handle *handle,
if (sub != event)
sub->pmu->read(sub);
- values[n++] = atomic64_read(&sub->count);
+ values[n++] = perf_event_count(sub);
if (read_format & PERF_FORMAT_ID)
values[n++] = primary_event_id(sub);
@@ -3491,7 +3491,7 @@ perf_event_read_event(struct perf_event *event,
/*
* task tracking -- fork/exit
*
- * enabled by: attr.comm | attr.mmap | attr.task
+ * enabled by: attr.comm | attr.mmap | attr.mmap_data | attr.task
*/
struct perf_task_event {
@@ -3541,7 +3541,8 @@ static int perf_event_task_match(struct perf_event *event)
if (event->cpu != -1 && event->cpu != smp_processor_id())
return 0;
- if (event->attr.comm || event->attr.mmap || event->attr.task)
+ if (event->attr.comm || event->attr.mmap ||
+ event->attr.mmap_data || event->attr.task)
return 1;
return 0;
@@ -3766,7 +3767,8 @@ static void perf_event_mmap_output(struct perf_event *event,
}
static int perf_event_mmap_match(struct perf_event *event,
- struct perf_mmap_event *mmap_event)
+ struct perf_mmap_event *mmap_event,
+ int executable)
{
if (event->state < PERF_EVENT_STATE_INACTIVE)
return 0;
@@ -3774,19 +3776,21 @@ static int perf_event_mmap_match(struct perf_event *event,
if (event->cpu != -1 && event->cpu != smp_processor_id())
return 0;
- if (event->attr.mmap)
+ if ((!executable && event->attr.mmap_data) ||
+ (executable && event->attr.mmap))
return 1;
return 0;
}
static void perf_event_mmap_ctx(struct perf_event_context *ctx,
- struct perf_mmap_event *mmap_event)
+ struct perf_mmap_event *mmap_event,
+ int executable)
{
struct perf_event *event;
list_for_each_entry_rcu(event, &ctx->event_list, event_entry) {
- if (perf_event_mmap_match(event, mmap_event))
+ if (perf_event_mmap_match(event, mmap_event, executable))
perf_event_mmap_output(event, mmap_event);
}
}
@@ -3830,6 +3834,14 @@ static void perf_event_mmap_event(struct perf_mmap_event *mmap_event)
if (!vma->vm_mm) {
name = strncpy(tmp, "[vdso]", sizeof(tmp));
goto got_name;
+ } else if (vma->vm_start <= vma->vm_mm->start_brk &&
+ vma->vm_end >= vma->vm_mm->brk) {
+ name = strncpy(tmp, "[heap]", sizeof(tmp));
+ goto got_name;
+ } else if (vma->vm_start <= vma->vm_mm->start_stack &&
+ vma->vm_end >= vma->vm_mm->start_stack) {
+ name = strncpy(tmp, "[stack]", sizeof(tmp));
+ goto got_name;
}
name = strncpy(tmp, "//anon", sizeof(tmp));
@@ -3846,17 +3858,17 @@ got_name:
rcu_read_lock();
cpuctx = &get_cpu_var(perf_cpu_context);
- perf_event_mmap_ctx(&cpuctx->ctx, mmap_event);
+ perf_event_mmap_ctx(&cpuctx->ctx, mmap_event, vma->vm_flags & VM_EXEC);
ctx = rcu_dereference(current->perf_event_ctxp);
if (ctx)
- perf_event_mmap_ctx(ctx, mmap_event);
+ perf_event_mmap_ctx(ctx, mmap_event, vma->vm_flags & VM_EXEC);
put_cpu_var(perf_cpu_context);
rcu_read_unlock();
kfree(buf);
}
-void __perf_event_mmap(struct vm_area_struct *vma)
+void perf_event_mmap(struct vm_area_struct *vma)
{
struct perf_mmap_event mmap_event;
@@ -4018,14 +4030,14 @@ static u64 perf_swevent_set_period(struct perf_event *event)
hwc->last_period = hwc->sample_period;
again:
- old = val = atomic64_read(&hwc->period_left);
+ old = val = local64_read(&hwc->period_left);
if (val < 0)
return 0;
nr = div64_u64(period + val, period);
offset = nr * period;
val -= offset;
- if (atomic64_cmpxchg(&hwc->period_left, old, val) != old)
+ if (local64_cmpxchg(&hwc->period_left, old, val) != old)
goto again;
return nr;
@@ -4064,7 +4076,7 @@ static void perf_swevent_add(struct perf_event *event, u64 nr,
{
struct hw_perf_event *hwc = &event->hw;
- atomic64_add(nr, &event->count);
+ local64_add(nr, &event->count);
if (!regs)
return;
@@ -4075,7 +4087,7 @@ static void perf_swevent_add(struct perf_event *event, u64 nr,
if (nr == 1 && hwc->sample_period == 1 && !event->attr.freq)
return perf_swevent_overflow(event, 1, nmi, data, regs);
- if (atomic64_add_negative(nr, &hwc->period_left))
+ if (local64_add_negative(nr, &hwc->period_left))
return;
perf_swevent_overflow(event, 0, nmi, data, regs);
@@ -4213,14 +4225,12 @@ int perf_swevent_get_recursion_context(void)
}
EXPORT_SYMBOL_GPL(perf_swevent_get_recursion_context);
-void perf_swevent_put_recursion_context(int rctx)
+void inline perf_swevent_put_recursion_context(int rctx)
{
struct perf_cpu_context *cpuctx = &__get_cpu_var(perf_cpu_context);
barrier();
cpuctx->recursion[rctx]--;
}
-EXPORT_SYMBOL_GPL(perf_swevent_put_recursion_context);
-
void __perf_sw_event(u32 event_id, u64 nr, int nmi,
struct pt_regs *regs, u64 addr)
@@ -4368,8 +4378,8 @@ static void cpu_clock_perf_event_update(struct perf_event *event)
u64 now;
now = cpu_clock(cpu);
- prev = atomic64_xchg(&event->hw.prev_count, now);
- atomic64_add(now - prev, &event->count);
+ prev = local64_xchg(&event->hw.prev_count, now);
+ local64_add(now - prev, &event->count);
}
static int cpu_clock_perf_event_enable(struct perf_event *event)
@@ -4377,7 +4387,7 @@ static int cpu_clock_perf_event_enable(struct perf_event *event)
struct hw_perf_event *hwc = &event->hw;
int cpu = raw_smp_processor_id();
- atomic64_set(&hwc->prev_count, cpu_clock(cpu));
+ local64_set(&hwc->prev_count, cpu_clock(cpu));
perf_swevent_start_hrtimer(event);
return 0;
@@ -4409,9 +4419,9 @@ static void task_clock_perf_event_update(struct perf_event *event, u64 now)
u64 prev;
s64 delta;
- prev = atomic64_xchg(&event->hw.prev_count, now);
+ prev = local64_xchg(&event->hw.prev_count, now);
delta = now - prev;
- atomic64_add(delta, &event->count);
+ local64_add(delta, &event->count);
}
static int task_clock_perf_event_enable(struct perf_event *event)
@@ -4421,7 +4431,7 @@ static int task_clock_perf_event_enable(struct perf_event *event)
now = event->ctx->time;
- atomic64_set(&hwc->prev_count, now);
+ local64_set(&hwc->prev_count, now);
perf_swevent_start_hrtimer(event);
@@ -4601,7 +4611,7 @@ static int perf_tp_event_match(struct perf_event *event,
}
void perf_tp_event(u64 addr, u64 count, void *record, int entry_size,
- struct pt_regs *regs, struct hlist_head *head)
+ struct pt_regs *regs, struct hlist_head *head, int rctx)
{
struct perf_sample_data data;
struct perf_event *event;
@@ -4615,12 +4625,12 @@ void perf_tp_event(u64 addr, u64 count, void *record, int entry_size,
perf_sample_data_init(&data, addr);
data.raw = &raw;
- rcu_read_lock();
hlist_for_each_entry_rcu(event, node, head, hlist_entry) {
if (perf_tp_event_match(event, &data, regs))
perf_swevent_add(event, count, 1, &data, regs);
}
- rcu_read_unlock();
+
+ perf_swevent_put_recursion_context(rctx);
}
EXPORT_SYMBOL_GPL(perf_tp_event);
@@ -4864,7 +4874,7 @@ perf_event_alloc(struct perf_event_attr *attr,
hwc->sample_period = 1;
hwc->last_period = hwc->sample_period;
- atomic64_set(&hwc->period_left, hwc->sample_period);
+ local64_set(&hwc->period_left, hwc->sample_period);
/*
* we currently do not support PERF_FORMAT_GROUP on inherited events
@@ -4913,7 +4923,7 @@ done:
if (!event->parent) {
atomic_inc(&nr_events);
- if (event->attr.mmap)
+ if (event->attr.mmap || event->attr.mmap_data)
atomic_inc(&nr_mmap_events);
if (event->attr.comm)
atomic_inc(&nr_comm_events);
@@ -5007,7 +5017,7 @@ err_size:
static int
perf_event_set_output(struct perf_event *event, struct perf_event *output_event)
{
- struct perf_mmap_data *data = NULL, *old_data = NULL;
+ struct perf_buffer *buffer = NULL, *old_buffer = NULL;
int ret = -EINVAL;
if (!output_event)
@@ -5037,19 +5047,19 @@ set:
if (output_event) {
/* get the buffer we want to redirect to */
- data = perf_mmap_data_get(output_event);
- if (!data)
+ buffer = perf_buffer_get(output_event);
+ if (!buffer)
goto unlock;
}
- old_data = event->data;
- rcu_assign_pointer(event->data, data);
+ old_buffer = event->buffer;
+ rcu_assign_pointer(event->buffer, buffer);
ret = 0;
unlock:
mutex_unlock(&event->mmap_mutex);
- if (old_data)
- perf_mmap_data_put(old_data);
+ if (old_buffer)
+ perf_buffer_put(old_buffer);
out:
return ret;
}
@@ -5298,7 +5308,7 @@ inherit_event(struct perf_event *parent_event,
hwc->sample_period = sample_period;
hwc->last_period = sample_period;
- atomic64_set(&hwc->period_left, sample_period);
+ local64_set(&hwc->period_left, sample_period);
}
child_event->overflow_handler = parent_event->overflow_handler;
@@ -5359,12 +5369,12 @@ static void sync_child_event(struct perf_event *child_event,
if (child_event->attr.inherit_stat)
perf_event_read_event(child_event, child);
- child_val = atomic64_read(&child_event->count);
+ child_val = perf_event_count(child_event);
/*
* Add back the child's count to the parent's count:
*/
- atomic64_add(child_val, &parent_event->count);
+ atomic64_add(child_val, &parent_event->child_count);
atomic64_add(child_event->total_time_enabled,
&parent_event->child_total_time_enabled);
atomic64_add(child_event->total_time_running,
diff --git a/kernel/pm_qos_params.c b/kernel/pm_qos_params.c
index f42d3f737a3..996a4dec5f9 100644
--- a/kernel/pm_qos_params.c
+++ b/kernel/pm_qos_params.c
@@ -48,59 +48,49 @@
* or pm_qos_object list and pm_qos_objects need to happen with pm_qos_lock
* held, taken with _irqsave. One lock to rule them all
*/
-struct pm_qos_request_list {
- struct list_head list;
- union {
- s32 value;
- s32 usec;
- s32 kbps;
- };
- int pm_qos_class;
+enum pm_qos_type {
+ PM_QOS_MAX, /* return the largest value */
+ PM_QOS_MIN /* return the smallest value */
};
-static s32 max_compare(s32 v1, s32 v2);
-static s32 min_compare(s32 v1, s32 v2);
-
struct pm_qos_object {
- struct pm_qos_request_list requests;
+ struct plist_head requests;
struct blocking_notifier_head *notifiers;
struct miscdevice pm_qos_power_miscdev;
char *name;
s32 default_value;
- atomic_t target_value;
- s32 (*comparitor)(s32, s32);
+ enum pm_qos_type type;
};
+static DEFINE_SPINLOCK(pm_qos_lock);
+
static struct pm_qos_object null_pm_qos;
static BLOCKING_NOTIFIER_HEAD(cpu_dma_lat_notifier);
static struct pm_qos_object cpu_dma_pm_qos = {
- .requests = {LIST_HEAD_INIT(cpu_dma_pm_qos.requests.list)},
+ .requests = PLIST_HEAD_INIT(cpu_dma_pm_qos.requests, pm_qos_lock),
.notifiers = &cpu_dma_lat_notifier,
.name = "cpu_dma_latency",
.default_value = 2000 * USEC_PER_SEC,
- .target_value = ATOMIC_INIT(2000 * USEC_PER_SEC),
- .comparitor = min_compare
+ .type = PM_QOS_MIN,
};
static BLOCKING_NOTIFIER_HEAD(network_lat_notifier);
static struct pm_qos_object network_lat_pm_qos = {
- .requests = {LIST_HEAD_INIT(network_lat_pm_qos.requests.list)},
+ .requests = PLIST_HEAD_INIT(network_lat_pm_qos.requests, pm_qos_lock),
.notifiers = &network_lat_notifier,
.name = "network_latency",
.default_value = 2000 * USEC_PER_SEC,
- .target_value = ATOMIC_INIT(2000 * USEC_PER_SEC),
- .comparitor = min_compare
+ .type = PM_QOS_MIN
};
static BLOCKING_NOTIFIER_HEAD(network_throughput_notifier);
static struct pm_qos_object network_throughput_pm_qos = {
- .requests = {LIST_HEAD_INIT(network_throughput_pm_qos.requests.list)},
+ .requests = PLIST_HEAD_INIT(network_throughput_pm_qos.requests, pm_qos_lock),
.notifiers = &network_throughput_notifier,
.name = "network_throughput",
.default_value = 0,
- .target_value = ATOMIC_INIT(0),
- .comparitor = max_compare
+ .type = PM_QOS_MAX,
};
@@ -111,8 +101,6 @@ static struct pm_qos_object *pm_qos_array[] = {
&network_throughput_pm_qos
};
-static DEFINE_SPINLOCK(pm_qos_lock);
-
static ssize_t pm_qos_power_write(struct file *filp, const char __user *buf,
size_t count, loff_t *f_pos);
static int pm_qos_power_open(struct inode *inode, struct file *filp);
@@ -124,46 +112,55 @@ static const struct file_operations pm_qos_power_fops = {
.release = pm_qos_power_release,
};
-/* static helper functions */
-static s32 max_compare(s32 v1, s32 v2)
+/* unlocked internal variant */
+static inline int pm_qos_get_value(struct pm_qos_object *o)
{
- return max(v1, v2);
-}
+ if (plist_head_empty(&o->requests))
+ return o->default_value;
-static s32 min_compare(s32 v1, s32 v2)
-{
- return min(v1, v2);
-}
+ switch (o->type) {
+ case PM_QOS_MIN:
+ return plist_last(&o->requests)->prio;
+ case PM_QOS_MAX:
+ return plist_first(&o->requests)->prio;
-static void update_target(int pm_qos_class)
+ default:
+ /* runtime check for not using enum */
+ BUG();
+ }
+}
+
+static void update_target(struct pm_qos_object *o, struct plist_node *node,
+ int del, int value)
{
- s32 extreme_value;
- struct pm_qos_request_list *node;
unsigned long flags;
- int call_notifier = 0;
+ int prev_value, curr_value;
spin_lock_irqsave(&pm_qos_lock, flags);
- extreme_value = pm_qos_array[pm_qos_class]->default_value;
- list_for_each_entry(node,
- &pm_qos_array[pm_qos_class]->requests.list, list) {
- extreme_value = pm_qos_array[pm_qos_class]->comparitor(
- extreme_value, node->value);
- }
- if (atomic_read(&pm_qos_array[pm_qos_class]->target_value) !=
- extreme_value) {
- call_notifier = 1;
- atomic_set(&pm_qos_array[pm_qos_class]->target_value,
- extreme_value);
- pr_debug(KERN_ERR "new target for qos %d is %d\n", pm_qos_class,
- atomic_read(&pm_qos_array[pm_qos_class]->target_value));
+ prev_value = pm_qos_get_value(o);
+ /* PM_QOS_DEFAULT_VALUE is a signal that the value is unchanged */
+ if (value != PM_QOS_DEFAULT_VALUE) {
+ /*
+ * to change the list, we atomically remove, reinit
+ * with new value and add, then see if the extremal
+ * changed
+ */
+ plist_del(node, &o->requests);
+ plist_node_init(node, value);
+ plist_add(node, &o->requests);
+ } else if (del) {
+ plist_del(node, &o->requests);
+ } else {
+ plist_add(node, &o->requests);
}
+ curr_value = pm_qos_get_value(o);
spin_unlock_irqrestore(&pm_qos_lock, flags);
- if (call_notifier)
- blocking_notifier_call_chain(
- pm_qos_array[pm_qos_class]->notifiers,
- (unsigned long) extreme_value, NULL);
+ if (prev_value != curr_value)
+ blocking_notifier_call_chain(o->notifiers,
+ (unsigned long)curr_value,
+ NULL);
}
static int register_pm_qos_misc(struct pm_qos_object *qos)
@@ -196,10 +193,23 @@ static int find_pm_qos_object_by_minor(int minor)
*/
int pm_qos_request(int pm_qos_class)
{
- return atomic_read(&pm_qos_array[pm_qos_class]->target_value);
+ unsigned long flags;
+ int value;
+
+ spin_lock_irqsave(&pm_qos_lock, flags);
+ value = pm_qos_get_value(pm_qos_array[pm_qos_class]);
+ spin_unlock_irqrestore(&pm_qos_lock, flags);
+
+ return value;
}
EXPORT_SYMBOL_GPL(pm_qos_request);
+int pm_qos_request_active(struct pm_qos_request_list *req)
+{
+ return req->pm_qos_class != 0;
+}
+EXPORT_SYMBOL_GPL(pm_qos_request_active);
+
/**
* pm_qos_add_request - inserts new qos request into the list
* @pm_qos_class: identifies which list of qos request to us
@@ -211,27 +221,23 @@ EXPORT_SYMBOL_GPL(pm_qos_request);
* element as a handle for use in updating and removal. Call needs to save
* this handle for later use.
*/
-struct pm_qos_request_list *pm_qos_add_request(int pm_qos_class, s32 value)
+void pm_qos_add_request(struct pm_qos_request_list *dep,
+ int pm_qos_class, s32 value)
{
- struct pm_qos_request_list *dep;
- unsigned long flags;
+ struct pm_qos_object *o = pm_qos_array[pm_qos_class];
+ int new_value;
- dep = kzalloc(sizeof(struct pm_qos_request_list), GFP_KERNEL);
- if (dep) {
- if (value == PM_QOS_DEFAULT_VALUE)
- dep->value = pm_qos_array[pm_qos_class]->default_value;
- else
- dep->value = value;
- dep->pm_qos_class = pm_qos_class;
-
- spin_lock_irqsave(&pm_qos_lock, flags);
- list_add(&dep->list,
- &pm_qos_array[pm_qos_class]->requests.list);
- spin_unlock_irqrestore(&pm_qos_lock, flags);
- update_target(pm_qos_class);
+ if (pm_qos_request_active(dep)) {
+ WARN(1, KERN_ERR "pm_qos_add_request() called for already added request\n");
+ return;
}
-
- return dep;
+ if (value == PM_QOS_DEFAULT_VALUE)
+ new_value = o->default_value;
+ else
+ new_value = value;
+ plist_node_init(&dep->list, new_value);
+ dep->pm_qos_class = pm_qos_class;
+ update_target(o, &dep->list, 0, PM_QOS_DEFAULT_VALUE);
}
EXPORT_SYMBOL_GPL(pm_qos_add_request);
@@ -246,27 +252,28 @@ EXPORT_SYMBOL_GPL(pm_qos_add_request);
* Attempts are made to make this code callable on hot code paths.
*/
void pm_qos_update_request(struct pm_qos_request_list *pm_qos_req,
- s32 new_value)
+ s32 new_value)
{
- unsigned long flags;
- int pending_update = 0;
s32 temp;
+ struct pm_qos_object *o;
+
+ if (!pm_qos_req) /*guard against callers passing in null */
+ return;
- if (pm_qos_req) { /*guard against callers passing in null */
- spin_lock_irqsave(&pm_qos_lock, flags);
- if (new_value == PM_QOS_DEFAULT_VALUE)
- temp = pm_qos_array[pm_qos_req->pm_qos_class]->default_value;
- else
- temp = new_value;
-
- if (temp != pm_qos_req->value) {
- pending_update = 1;
- pm_qos_req->value = temp;
- }
- spin_unlock_irqrestore(&pm_qos_lock, flags);
- if (pending_update)
- update_target(pm_qos_req->pm_qos_class);
+ if (!pm_qos_request_active(pm_qos_req)) {
+ WARN(1, KERN_ERR "pm_qos_update_request() called for unknown object\n");
+ return;
}
+
+ o = pm_qos_array[pm_qos_req->pm_qos_class];
+
+ if (new_value == PM_QOS_DEFAULT_VALUE)
+ temp = o->default_value;
+ else
+ temp = new_value;
+
+ if (temp != pm_qos_req->list.prio)
+ update_target(o, &pm_qos_req->list, 0, temp);
}
EXPORT_SYMBOL_GPL(pm_qos_update_request);
@@ -280,19 +287,20 @@ EXPORT_SYMBOL_GPL(pm_qos_update_request);
*/
void pm_qos_remove_request(struct pm_qos_request_list *pm_qos_req)
{
- unsigned long flags;
- int qos_class;
+ struct pm_qos_object *o;
if (pm_qos_req == NULL)
return;
/* silent return to keep pcm code cleaner */
- qos_class = pm_qos_req->pm_qos_class;
- spin_lock_irqsave(&pm_qos_lock, flags);
- list_del(&pm_qos_req->list);
- kfree(pm_qos_req);
- spin_unlock_irqrestore(&pm_qos_lock, flags);
- update_target(qos_class);
+ if (!pm_qos_request_active(pm_qos_req)) {
+ WARN(1, KERN_ERR "pm_qos_remove_request() called for unknown object\n");
+ return;
+ }
+
+ o = pm_qos_array[pm_qos_req->pm_qos_class];
+ update_target(o, &pm_qos_req->list, 1, PM_QOS_DEFAULT_VALUE);
+ memset(pm_qos_req, 0, sizeof(*pm_qos_req));
}
EXPORT_SYMBOL_GPL(pm_qos_remove_request);
@@ -340,8 +348,12 @@ static int pm_qos_power_open(struct inode *inode, struct file *filp)
pm_qos_class = find_pm_qos_object_by_minor(iminor(inode));
if (pm_qos_class >= 0) {
- filp->private_data = (void *) pm_qos_add_request(pm_qos_class,
- PM_QOS_DEFAULT_VALUE);
+ struct pm_qos_request_list *req = kzalloc(GFP_KERNEL, sizeof(*req));
+ if (!req)
+ return -ENOMEM;
+
+ pm_qos_add_request(req, pm_qos_class, PM_QOS_DEFAULT_VALUE);
+ filp->private_data = req;
if (filp->private_data)
return 0;
@@ -353,8 +365,9 @@ static int pm_qos_power_release(struct inode *inode, struct file *filp)
{
struct pm_qos_request_list *req;
- req = (struct pm_qos_request_list *)filp->private_data;
+ req = filp->private_data;
pm_qos_remove_request(req);
+ kfree(req);
return 0;
}
diff --git a/kernel/posix-cpu-timers.c b/kernel/posix-cpu-timers.c
index 9829646d399..f66bdd33a6c 100644
--- a/kernel/posix-cpu-timers.c
+++ b/kernel/posix-cpu-timers.c
@@ -232,31 +232,24 @@ static int cpu_clock_sample(const clockid_t which_clock, struct task_struct *p,
void thread_group_cputime(struct task_struct *tsk, struct task_cputime *times)
{
- struct sighand_struct *sighand;
- struct signal_struct *sig;
+ struct signal_struct *sig = tsk->signal;
struct task_struct *t;
- *times = INIT_CPUTIME;
+ times->utime = sig->utime;
+ times->stime = sig->stime;
+ times->sum_exec_runtime = sig->sum_sched_runtime;
rcu_read_lock();
- sighand = rcu_dereference(tsk->sighand);
- if (!sighand)
+ /* make sure we can trust tsk->thread_group list */
+ if (!likely(pid_alive(tsk)))
goto out;
- sig = tsk->signal;
-
t = tsk;
do {
times->utime = cputime_add(times->utime, t->utime);
times->stime = cputime_add(times->stime, t->stime);
times->sum_exec_runtime += t->se.sum_exec_runtime;
-
- t = next_thread(t);
- } while (t != tsk);
-
- times->utime = cputime_add(times->utime, sig->utime);
- times->stime = cputime_add(times->stime, sig->stime);
- times->sum_exec_runtime += sig->sum_sched_runtime;
+ } while_each_thread(tsk, t);
out:
rcu_read_unlock();
}
@@ -1279,10 +1272,6 @@ static inline int fastpath_timer_check(struct task_struct *tsk)
{
struct signal_struct *sig;
- /* tsk == current, ensure it is safe to use ->signal/sighand */
- if (unlikely(tsk->exit_state))
- return 0;
-
if (!task_cputime_zero(&tsk->cputime_expires)) {
struct task_cputime task_sample = {
.utime = tsk->utime,
@@ -1298,7 +1287,10 @@ static inline int fastpath_timer_check(struct task_struct *tsk)
if (sig->cputimer.running) {
struct task_cputime group_sample;
- thread_group_cputimer(tsk, &group_sample);
+ spin_lock(&sig->cputimer.lock);
+ group_sample = sig->cputimer.cputime;
+ spin_unlock(&sig->cputimer.lock);
+
if (task_cputime_expired(&group_sample, &sig->cputime_expires))
return 1;
}
@@ -1315,6 +1307,7 @@ void run_posix_cpu_timers(struct task_struct *tsk)
{
LIST_HEAD(firing);
struct k_itimer *timer, *next;
+ unsigned long flags;
BUG_ON(!irqs_disabled());
@@ -1325,7 +1318,8 @@ void run_posix_cpu_timers(struct task_struct *tsk)
if (!fastpath_timer_check(tsk))
return;
- spin_lock(&tsk->sighand->siglock);
+ if (!lock_task_sighand(tsk, &flags))
+ return;
/*
* Here we take off tsk->signal->cpu_timers[N] and
* tsk->cpu_timers[N] all the timers that are firing, and
@@ -1347,7 +1341,7 @@ void run_posix_cpu_timers(struct task_struct *tsk)
* that gets the timer lock before we do will give it up and
* spin until we've taken care of that timer below.
*/
- spin_unlock(&tsk->sighand->siglock);
+ unlock_task_sighand(tsk, &flags);
/*
* Now that all the timers on our list have the firing flag,
diff --git a/kernel/posix-timers.c b/kernel/posix-timers.c
index ad723420acc..9ca4973f736 100644
--- a/kernel/posix-timers.c
+++ b/kernel/posix-timers.c
@@ -560,11 +560,6 @@ SYSCALL_DEFINE3(timer_create, const clockid_t, which_clock,
new_timer->it_clock = which_clock;
new_timer->it_overrun = -1;
- if (copy_to_user(created_timer_id,
- &new_timer_id, sizeof (new_timer_id))) {
- error = -EFAULT;
- goto out;
- }
if (timer_event_spec) {
if (copy_from_user(&event, timer_event_spec, sizeof (event))) {
error = -EFAULT;
@@ -590,6 +585,12 @@ SYSCALL_DEFINE3(timer_create, const clockid_t, which_clock,
new_timer->sigq->info.si_tid = new_timer->it_id;
new_timer->sigq->info.si_code = SI_TIMER;
+ if (copy_to_user(created_timer_id,
+ &new_timer_id, sizeof (new_timer_id))) {
+ error = -EFAULT;
+ goto out;
+ }
+
error = CLOCK_DISPATCH(which_clock, timer_create, (new_timer));
if (error)
goto out;
diff --git a/kernel/power/hibernate.c b/kernel/power/hibernate.c
index aa9e916da4d..8dc31e02ae1 100644
--- a/kernel/power/hibernate.c
+++ b/kernel/power/hibernate.c
@@ -3,7 +3,7 @@
*
* Copyright (c) 2003 Patrick Mochel
* Copyright (c) 2003 Open Source Development Lab
- * Copyright (c) 2004 Pavel Machek <pavel@suse.cz>
+ * Copyright (c) 2004 Pavel Machek <pavel@ucw.cz>
* Copyright (c) 2009 Rafael J. Wysocki, Novell Inc.
*
* This file is released under the GPLv2.
@@ -277,7 +277,7 @@ static int create_image(int platform_mode)
goto Enable_irqs;
}
- if (hibernation_test(TEST_CORE))
+ if (hibernation_test(TEST_CORE) || !pm_check_wakeup_events())
goto Power_up;
in_suspend = 1;
@@ -288,8 +288,10 @@ static int create_image(int platform_mode)
error);
/* Restore control flow magically appears here */
restore_processor_state();
- if (!in_suspend)
+ if (!in_suspend) {
+ events_check_enabled = false;
platform_leave(platform_mode);
+ }
Power_up:
sysdev_resume();
@@ -328,7 +330,7 @@ int hibernation_snapshot(int platform_mode)
error = platform_begin(platform_mode);
if (error)
- return error;
+ goto Close;
/* Preallocate image memory before shutting down devices. */
error = hibernate_preallocate_memory();
@@ -511,18 +513,24 @@ int hibernation_platform_enter(void)
local_irq_disable();
sysdev_suspend(PMSG_HIBERNATE);
+ if (!pm_check_wakeup_events()) {
+ error = -EAGAIN;
+ goto Power_up;
+ }
+
hibernation_ops->enter();
/* We should never get here */
while (1);
- /*
- * We don't need to reenable the nonboot CPUs or resume consoles, since
- * the system is going to be halted anyway.
- */
+ Power_up:
+ sysdev_resume();
+ local_irq_enable();
+ enable_nonboot_cpus();
+
Platform_finish:
hibernation_ops->finish();
- dpm_suspend_noirq(PMSG_RESTORE);
+ dpm_resume_noirq(PMSG_RESTORE);
Resume_devices:
entering_platform_hibernation = false;
diff --git a/kernel/power/main.c b/kernel/power/main.c
index b58800b21fc..62b0bc6e498 100644
--- a/kernel/power/main.c
+++ b/kernel/power/main.c
@@ -204,6 +204,60 @@ static ssize_t state_store(struct kobject *kobj, struct kobj_attribute *attr,
power_attr(state);
+#ifdef CONFIG_PM_SLEEP
+/*
+ * The 'wakeup_count' attribute, along with the functions defined in
+ * drivers/base/power/wakeup.c, provides a means by which wakeup events can be
+ * handled in a non-racy way.
+ *
+ * If a wakeup event occurs when the system is in a sleep state, it simply is
+ * woken up. In turn, if an event that would wake the system up from a sleep
+ * state occurs when it is undergoing a transition to that sleep state, the
+ * transition should be aborted. Moreover, if such an event occurs when the
+ * system is in the working state, an attempt to start a transition to the
+ * given sleep state should fail during certain period after the detection of
+ * the event. Using the 'state' attribute alone is not sufficient to satisfy
+ * these requirements, because a wakeup event may occur exactly when 'state'
+ * is being written to and may be delivered to user space right before it is
+ * frozen, so the event will remain only partially processed until the system is
+ * woken up by another event. In particular, it won't cause the transition to
+ * a sleep state to be aborted.
+ *
+ * This difficulty may be overcome if user space uses 'wakeup_count' before
+ * writing to 'state'. It first should read from 'wakeup_count' and store
+ * the read value. Then, after carrying out its own preparations for the system
+ * transition to a sleep state, it should write the stored value to
+ * 'wakeup_count'. If that fails, at least one wakeup event has occured since
+ * 'wakeup_count' was read and 'state' should not be written to. Otherwise, it
+ * is allowed to write to 'state', but the transition will be aborted if there
+ * are any wakeup events detected after 'wakeup_count' was written to.
+ */
+
+static ssize_t wakeup_count_show(struct kobject *kobj,
+ struct kobj_attribute *attr,
+ char *buf)
+{
+ unsigned long val;
+
+ return pm_get_wakeup_count(&val) ? sprintf(buf, "%lu\n", val) : -EINTR;
+}
+
+static ssize_t wakeup_count_store(struct kobject *kobj,
+ struct kobj_attribute *attr,
+ const char *buf, size_t n)
+{
+ unsigned long val;
+
+ if (sscanf(buf, "%lu", &val) == 1) {
+ if (pm_save_wakeup_count(val))
+ return n;
+ }
+ return -EINVAL;
+}
+
+power_attr(wakeup_count);
+#endif /* CONFIG_PM_SLEEP */
+
#ifdef CONFIG_PM_TRACE
int pm_trace_enabled;
@@ -236,6 +290,7 @@ static struct attribute * g[] = {
#endif
#ifdef CONFIG_PM_SLEEP
&pm_async_attr.attr,
+ &wakeup_count_attr.attr,
#ifdef CONFIG_PM_DEBUG
&pm_test_attr.attr,
#endif
diff --git a/kernel/power/process.c b/kernel/power/process.c
index 71ae29052ab..028a99598f4 100644
--- a/kernel/power/process.c
+++ b/kernel/power/process.c
@@ -15,6 +15,7 @@
#include <linux/syscalls.h>
#include <linux/freezer.h>
#include <linux/delay.h>
+#include <linux/workqueue.h>
/*
* Timeout for stopping processes
@@ -35,6 +36,7 @@ static int try_to_freeze_tasks(bool sig_only)
struct task_struct *g, *p;
unsigned long end_time;
unsigned int todo;
+ bool wq_busy = false;
struct timeval start, end;
u64 elapsed_csecs64;
unsigned int elapsed_csecs;
@@ -42,6 +44,10 @@ static int try_to_freeze_tasks(bool sig_only)
do_gettimeofday(&start);
end_time = jiffies + TIMEOUT;
+
+ if (!sig_only)
+ freeze_workqueues_begin();
+
while (true) {
todo = 0;
read_lock(&tasklist_lock);
@@ -63,6 +69,12 @@ static int try_to_freeze_tasks(bool sig_only)
todo++;
} while_each_thread(g, p);
read_unlock(&tasklist_lock);
+
+ if (!sig_only) {
+ wq_busy = freeze_workqueues_busy();
+ todo += wq_busy;
+ }
+
if (!todo || time_after(jiffies, end_time))
break;
@@ -86,8 +98,12 @@ static int try_to_freeze_tasks(bool sig_only)
*/
printk("\n");
printk(KERN_ERR "Freezing of tasks failed after %d.%02d seconds "
- "(%d tasks refusing to freeze):\n",
- elapsed_csecs / 100, elapsed_csecs % 100, todo);
+ "(%d tasks refusing to freeze, wq_busy=%d):\n",
+ elapsed_csecs / 100, elapsed_csecs % 100,
+ todo - wq_busy, wq_busy);
+
+ thaw_workqueues();
+
read_lock(&tasklist_lock);
do_each_thread(g, p) {
task_lock(p);
@@ -157,6 +173,7 @@ void thaw_processes(void)
oom_killer_enable();
printk("Restarting tasks ... ");
+ thaw_workqueues();
thaw_tasks(true);
thaw_tasks(false);
schedule();
diff --git a/kernel/power/snapshot.c b/kernel/power/snapshot.c
index 25ce010e9f8..f6cd6faf84f 100644
--- a/kernel/power/snapshot.c
+++ b/kernel/power/snapshot.c
@@ -3,7 +3,7 @@
*
* This file provides system snapshot/restore functionality for swsusp.
*
- * Copyright (C) 1998-2005 Pavel Machek <pavel@suse.cz>
+ * Copyright (C) 1998-2005 Pavel Machek <pavel@ucw.cz>
* Copyright (C) 2006 Rafael J. Wysocki <rjw@sisk.pl>
*
* This file is released under the GPLv2.
diff --git a/kernel/power/suspend.c b/kernel/power/suspend.c
index f37cb7dd440..7335952ee47 100644
--- a/kernel/power/suspend.c
+++ b/kernel/power/suspend.c
@@ -136,19 +136,19 @@ static int suspend_enter(suspend_state_t state)
if (suspend_ops->prepare) {
error = suspend_ops->prepare();
if (error)
- return error;
+ goto Platform_finish;
}
error = dpm_suspend_noirq(PMSG_SUSPEND);
if (error) {
printk(KERN_ERR "PM: Some devices failed to power down\n");
- goto Platfrom_finish;
+ goto Platform_finish;
}
if (suspend_ops->prepare_late) {
error = suspend_ops->prepare_late();
if (error)
- goto Power_up_devices;
+ goto Platform_wake;
}
if (suspend_test(TEST_PLATFORM))
@@ -163,8 +163,10 @@ static int suspend_enter(suspend_state_t state)
error = sysdev_suspend(PMSG_SUSPEND);
if (!error) {
- if (!suspend_test(TEST_CORE))
+ if (!suspend_test(TEST_CORE) && pm_check_wakeup_events()) {
error = suspend_ops->enter(state);
+ events_check_enabled = false;
+ }
sysdev_resume();
}
@@ -178,10 +180,9 @@ static int suspend_enter(suspend_state_t state)
if (suspend_ops->wake)
suspend_ops->wake();
- Power_up_devices:
dpm_resume_noirq(PMSG_RESUME);
- Platfrom_finish:
+ Platform_finish:
if (suspend_ops->finish)
suspend_ops->finish();
diff --git a/kernel/power/swap.c b/kernel/power/swap.c
index b0bb2177839..e6a5bdf61a3 100644
--- a/kernel/power/swap.c
+++ b/kernel/power/swap.c
@@ -4,7 +4,7 @@
* This file provides functions for reading the suspend image from
* and writing it to a swap partition.
*
- * Copyright (C) 1998,2001-2005 Pavel Machek <pavel@suse.cz>
+ * Copyright (C) 1998,2001-2005 Pavel Machek <pavel@ucw.cz>
* Copyright (C) 2006 Rafael J. Wysocki <rjw@sisk.pl>
*
* This file is released under the GPLv2.
@@ -32,7 +32,7 @@
/*
* The swap map is a data structure used for keeping track of each page
* written to a swap partition. It consists of many swap_map_page
- * structures that contain each an array of MAP_PAGE_SIZE swap entries.
+ * structures that contain each an array of MAP_PAGE_ENTRIES swap entries.
* These structures are stored on the swap and linked together with the
* help of the .next_swap member.
*
@@ -148,7 +148,7 @@ sector_t alloc_swapdev_block(int swap)
/**
* free_all_swap_pages - free swap pages allocated for saving image data.
- * It also frees the extents used to register which swap entres had been
+ * It also frees the extents used to register which swap entries had been
* allocated.
*/
diff --git a/kernel/printk.c b/kernel/printk.c
index 444b770c959..4ab0164bcf8 100644
--- a/kernel/printk.c
+++ b/kernel/printk.c
@@ -37,6 +37,8 @@
#include <linux/ratelimit.h>
#include <linux/kmsg_dump.h>
#include <linux/syslog.h>
+#include <linux/cpu.h>
+#include <linux/notifier.h>
#include <asm/uaccess.h>
@@ -985,6 +987,32 @@ void resume_console(void)
}
/**
+ * console_cpu_notify - print deferred console messages after CPU hotplug
+ * @self: notifier struct
+ * @action: CPU hotplug event
+ * @hcpu: unused
+ *
+ * If printk() is called from a CPU that is not online yet, the messages
+ * will be spooled but will not show up on the console. This function is
+ * called when a new CPU comes online (or fails to come up), and ensures
+ * that any such output gets printed.
+ */
+static int __cpuinit console_cpu_notify(struct notifier_block *self,
+ unsigned long action, void *hcpu)
+{
+ switch (action) {
+ case CPU_ONLINE:
+ case CPU_DEAD:
+ case CPU_DYING:
+ case CPU_DOWN_FAILED:
+ case CPU_UP_CANCELED:
+ acquire_console_sem();
+ release_console_sem();
+ }
+ return NOTIFY_OK;
+}
+
+/**
* acquire_console_sem - lock the console system for exclusive use.
*
* Acquires a semaphore which guarantees that the caller has
@@ -1371,7 +1399,7 @@ int unregister_console(struct console *console)
}
EXPORT_SYMBOL(unregister_console);
-static int __init disable_boot_consoles(void)
+static int __init printk_late_init(void)
{
struct console *con;
@@ -1382,9 +1410,10 @@ static int __init disable_boot_consoles(void)
unregister_console(con);
}
}
+ hotcpu_notifier(console_cpu_notify, 0);
return 0;
}
-late_initcall(disable_boot_consoles);
+late_initcall(printk_late_init);
#if defined CONFIG_PRINTK
diff --git a/kernel/rcupdate.c b/kernel/rcupdate.c
index 72a8dc9567f..4d169835fb3 100644
--- a/kernel/rcupdate.c
+++ b/kernel/rcupdate.c
@@ -114,3 +114,163 @@ int rcu_my_thread_group_empty(void)
}
EXPORT_SYMBOL_GPL(rcu_my_thread_group_empty);
#endif /* #ifdef CONFIG_PROVE_RCU */
+
+#ifdef CONFIG_DEBUG_OBJECTS_RCU_HEAD
+static inline void debug_init_rcu_head(struct rcu_head *head)
+{
+ debug_object_init(head, &rcuhead_debug_descr);
+}
+
+static inline void debug_rcu_head_free(struct rcu_head *head)
+{
+ debug_object_free(head, &rcuhead_debug_descr);
+}
+
+/*
+ * fixup_init is called when:
+ * - an active object is initialized
+ */
+static int rcuhead_fixup_init(void *addr, enum debug_obj_state state)
+{
+ struct rcu_head *head = addr;
+
+ switch (state) {
+ case ODEBUG_STATE_ACTIVE:
+ /*
+ * Ensure that queued callbacks are all executed.
+ * If we detect that we are nested in a RCU read-side critical
+ * section, we should simply fail, otherwise we would deadlock.
+ */
+ if (rcu_preempt_depth() != 0 || preempt_count() != 0 ||
+ irqs_disabled()) {
+ WARN_ON(1);
+ return 0;
+ }
+ rcu_barrier();
+ rcu_barrier_sched();
+ rcu_barrier_bh();
+ debug_object_init(head, &rcuhead_debug_descr);
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+/*
+ * fixup_activate is called when:
+ * - an active object is activated
+ * - an unknown object is activated (might be a statically initialized object)
+ * Activation is performed internally by call_rcu().
+ */
+static int rcuhead_fixup_activate(void *addr, enum debug_obj_state state)
+{
+ struct rcu_head *head = addr;
+
+ switch (state) {
+
+ case ODEBUG_STATE_NOTAVAILABLE:
+ /*
+ * This is not really a fixup. We just make sure that it is
+ * tracked in the object tracker.
+ */
+ debug_object_init(head, &rcuhead_debug_descr);
+ debug_object_activate(head, &rcuhead_debug_descr);
+ return 0;
+
+ case ODEBUG_STATE_ACTIVE:
+ /*
+ * Ensure that queued callbacks are all executed.
+ * If we detect that we are nested in a RCU read-side critical
+ * section, we should simply fail, otherwise we would deadlock.
+ */
+ if (rcu_preempt_depth() != 0 || preempt_count() != 0 ||
+ irqs_disabled()) {
+ WARN_ON(1);
+ return 0;
+ }
+ rcu_barrier();
+ rcu_barrier_sched();
+ rcu_barrier_bh();
+ debug_object_activate(head, &rcuhead_debug_descr);
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+/*
+ * fixup_free is called when:
+ * - an active object is freed
+ */
+static int rcuhead_fixup_free(void *addr, enum debug_obj_state state)
+{
+ struct rcu_head *head = addr;
+
+ switch (state) {
+ case ODEBUG_STATE_ACTIVE:
+ /*
+ * Ensure that queued callbacks are all executed.
+ * If we detect that we are nested in a RCU read-side critical
+ * section, we should simply fail, otherwise we would deadlock.
+ */
+#ifndef CONFIG_PREEMPT
+ WARN_ON(1);
+ return 0;
+#else
+ if (rcu_preempt_depth() != 0 || preempt_count() != 0 ||
+ irqs_disabled()) {
+ WARN_ON(1);
+ return 0;
+ }
+ rcu_barrier();
+ rcu_barrier_sched();
+ rcu_barrier_bh();
+ debug_object_free(head, &rcuhead_debug_descr);
+ return 1;
+#endif
+ default:
+ return 0;
+ }
+}
+
+/**
+ * init_rcu_head_on_stack() - initialize on-stack rcu_head for debugobjects
+ * @head: pointer to rcu_head structure to be initialized
+ *
+ * This function informs debugobjects of a new rcu_head structure that
+ * has been allocated as an auto variable on the stack. This function
+ * is not required for rcu_head structures that are statically defined or
+ * that are dynamically allocated on the heap. This function has no
+ * effect for !CONFIG_DEBUG_OBJECTS_RCU_HEAD kernel builds.
+ */
+void init_rcu_head_on_stack(struct rcu_head *head)
+{
+ debug_object_init_on_stack(head, &rcuhead_debug_descr);
+}
+EXPORT_SYMBOL_GPL(init_rcu_head_on_stack);
+
+/**
+ * destroy_rcu_head_on_stack() - destroy on-stack rcu_head for debugobjects
+ * @head: pointer to rcu_head structure to be initialized
+ *
+ * This function informs debugobjects that an on-stack rcu_head structure
+ * is about to go out of scope. As with init_rcu_head_on_stack(), this
+ * function is not required for rcu_head structures that are statically
+ * defined or that are dynamically allocated on the heap. Also as with
+ * init_rcu_head_on_stack(), this function has no effect for
+ * !CONFIG_DEBUG_OBJECTS_RCU_HEAD kernel builds.
+ */
+void destroy_rcu_head_on_stack(struct rcu_head *head)
+{
+ debug_object_free(head, &rcuhead_debug_descr);
+}
+EXPORT_SYMBOL_GPL(destroy_rcu_head_on_stack);
+
+struct debug_obj_descr rcuhead_debug_descr = {
+ .name = "rcu_head",
+ .fixup_init = rcuhead_fixup_init,
+ .fixup_activate = rcuhead_fixup_activate,
+ .fixup_free = rcuhead_fixup_free,
+};
+EXPORT_SYMBOL_GPL(rcuhead_debug_descr);
+#endif /* #ifdef CONFIG_DEBUG_OBJECTS_RCU_HEAD */
diff --git a/kernel/rcutiny.c b/kernel/rcutiny.c
index 38729d3cd23..196ec02f8be 100644
--- a/kernel/rcutiny.c
+++ b/kernel/rcutiny.c
@@ -169,6 +169,7 @@ static void __rcu_process_callbacks(struct rcu_ctrlblk *rcp)
while (list) {
next = list->next;
prefetch(next);
+ debug_rcu_head_unqueue(list);
list->func(list);
list = next;
}
@@ -211,6 +212,7 @@ static void __call_rcu(struct rcu_head *head,
{
unsigned long flags;
+ debug_rcu_head_queue(head);
head->func = func;
head->next = NULL;
diff --git a/kernel/rcutorture.c b/kernel/rcutorture.c
index 6535ac8bc6a..2e2726d790b 100644
--- a/kernel/rcutorture.c
+++ b/kernel/rcutorture.c
@@ -239,8 +239,7 @@ static unsigned long
rcu_random(struct rcu_random_state *rrsp)
{
if (--rrsp->rrs_count < 0) {
- rrsp->rrs_state +=
- (unsigned long)cpu_clock(raw_smp_processor_id());
+ rrsp->rrs_state += (unsigned long)local_clock();
rrsp->rrs_count = RCU_RANDOM_REFRESH;
}
rrsp->rrs_state = rrsp->rrs_state * RCU_RANDOM_MULT + RCU_RANDOM_ADD;
diff --git a/kernel/rcutree.c b/kernel/rcutree.c
index d4437345706..d5bc43976c5 100644
--- a/kernel/rcutree.c
+++ b/kernel/rcutree.c
@@ -1112,6 +1112,7 @@ static void rcu_do_batch(struct rcu_state *rsp, struct rcu_data *rdp)
while (list) {
next = list->next;
prefetch(next);
+ debug_rcu_head_unqueue(list);
list->func(list);
list = next;
if (++count >= rdp->blimit)
@@ -1388,6 +1389,7 @@ __call_rcu(struct rcu_head *head, void (*func)(struct rcu_head *rcu),
unsigned long flags;
struct rcu_data *rdp;
+ debug_rcu_head_queue(head);
head->func = func;
head->next = NULL;
diff --git a/kernel/sched.c b/kernel/sched.c
index f52a8801b7a..41541d79e3c 100644
--- a/kernel/sched.c
+++ b/kernel/sched.c
@@ -77,6 +77,7 @@
#include <asm/irq_regs.h>
#include "sched_cpupri.h"
+#include "workqueue_sched.h"
#define CREATE_TRACE_POINTS
#include <trace/events/sched.h>
@@ -456,9 +457,10 @@ struct rq {
unsigned long nr_running;
#define CPU_LOAD_IDX_MAX 5
unsigned long cpu_load[CPU_LOAD_IDX_MAX];
+ unsigned long last_load_update_tick;
#ifdef CONFIG_NO_HZ
u64 nohz_stamp;
- unsigned char in_nohz_recently;
+ unsigned char nohz_balance_kick;
#endif
unsigned int skip_clock_update;
@@ -1193,6 +1195,27 @@ static void resched_cpu(int cpu)
#ifdef CONFIG_NO_HZ
/*
+ * In the semi idle case, use the nearest busy cpu for migrating timers
+ * from an idle cpu. This is good for power-savings.
+ *
+ * We don't do similar optimization for completely idle system, as
+ * selecting an idle cpu will add more delays to the timers than intended
+ * (as that cpu's timer base may not be uptodate wrt jiffies etc).
+ */
+int get_nohz_timer_target(void)
+{
+ int cpu = smp_processor_id();
+ int i;
+ struct sched_domain *sd;
+
+ for_each_domain(cpu, sd) {
+ for_each_cpu(i, sched_domain_span(sd))
+ if (!idle_cpu(i))
+ return i;
+ }
+ return cpu;
+}
+/*
* When add_timer_on() enqueues a timer into the timer wheel of an
* idle CPU then this timer might expire before the next timer event
* which is scheduled to wake up that CPU. In case of a completely
@@ -1232,16 +1255,6 @@ void wake_up_idle_cpu(int cpu)
smp_send_reschedule(cpu);
}
-int nohz_ratelimit(int cpu)
-{
- struct rq *rq = cpu_rq(cpu);
- u64 diff = rq->clock - rq->nohz_stamp;
-
- rq->nohz_stamp = rq->clock;
-
- return diff < (NSEC_PER_SEC / HZ) >> 1;
-}
-
#endif /* CONFIG_NO_HZ */
static u64 sched_avg_period(void)
@@ -1652,7 +1665,7 @@ static void update_shares(struct sched_domain *sd)
if (root_task_group_empty())
return;
- now = cpu_clock(raw_smp_processor_id());
+ now = local_clock();
elapsed = now - sd->last_update;
if (elapsed >= (s64)(u64)sysctl_sched_shares_ratelimit) {
@@ -1805,6 +1818,7 @@ static void cfs_rq_set_shares(struct cfs_rq *cfs_rq, unsigned long shares)
static void calc_load_account_idle(struct rq *this_rq);
static void update_sysctl(void);
static int get_update_sysctl_factor(void);
+static void update_cpu_load(struct rq *this_rq);
static inline void __set_task_cpu(struct task_struct *p, unsigned int cpu)
{
@@ -2267,11 +2281,55 @@ static void update_avg(u64 *avg, u64 sample)
}
#endif
-/***
+static inline void ttwu_activate(struct task_struct *p, struct rq *rq,
+ bool is_sync, bool is_migrate, bool is_local,
+ unsigned long en_flags)
+{
+ schedstat_inc(p, se.statistics.nr_wakeups);
+ if (is_sync)
+ schedstat_inc(p, se.statistics.nr_wakeups_sync);
+ if (is_migrate)
+ schedstat_inc(p, se.statistics.nr_wakeups_migrate);
+ if (is_local)
+ schedstat_inc(p, se.statistics.nr_wakeups_local);
+ else
+ schedstat_inc(p, se.statistics.nr_wakeups_remote);
+
+ activate_task(rq, p, en_flags);
+}
+
+static inline void ttwu_post_activation(struct task_struct *p, struct rq *rq,
+ int wake_flags, bool success)
+{
+ trace_sched_wakeup(p, success);
+ check_preempt_curr(rq, p, wake_flags);
+
+ p->state = TASK_RUNNING;
+#ifdef CONFIG_SMP
+ if (p->sched_class->task_woken)
+ p->sched_class->task_woken(rq, p);
+
+ if (unlikely(rq->idle_stamp)) {
+ u64 delta = rq->clock - rq->idle_stamp;
+ u64 max = 2*sysctl_sched_migration_cost;
+
+ if (delta > max)
+ rq->avg_idle = max;
+ else
+ update_avg(&rq->avg_idle, delta);
+ rq->idle_stamp = 0;
+ }
+#endif
+ /* if a worker is waking up, notify workqueue */
+ if ((p->flags & PF_WQ_WORKER) && success)
+ wq_worker_waking_up(p, cpu_of(rq));
+}
+
+/**
* try_to_wake_up - wake up a thread
- * @p: the to-be-woken-up thread
+ * @p: the thread to be awakened
* @state: the mask of task states that can be woken
- * @sync: do a synchronous wakeup?
+ * @wake_flags: wake modifier flags (WF_*)
*
* Put it on the run-queue if it's not already there. The "current"
* thread is always on the run-queue (except when the actual
@@ -2279,7 +2337,8 @@ static void update_avg(u64 *avg, u64 sample)
* the simpler "current->state = TASK_RUNNING" to mark yourself
* runnable without the overhead of this.
*
- * returns failure only if the task is already active.
+ * Returns %true if @p was woken up, %false if it was already running
+ * or @state didn't match @p's state.
*/
static int try_to_wake_up(struct task_struct *p, unsigned int state,
int wake_flags)
@@ -2359,38 +2418,11 @@ static int try_to_wake_up(struct task_struct *p, unsigned int state,
out_activate:
#endif /* CONFIG_SMP */
- schedstat_inc(p, se.statistics.nr_wakeups);
- if (wake_flags & WF_SYNC)
- schedstat_inc(p, se.statistics.nr_wakeups_sync);
- if (orig_cpu != cpu)
- schedstat_inc(p, se.statistics.nr_wakeups_migrate);
- if (cpu == this_cpu)
- schedstat_inc(p, se.statistics.nr_wakeups_local);
- else
- schedstat_inc(p, se.statistics.nr_wakeups_remote);
- activate_task(rq, p, en_flags);
+ ttwu_activate(p, rq, wake_flags & WF_SYNC, orig_cpu != cpu,
+ cpu == this_cpu, en_flags);
success = 1;
-
out_running:
- trace_sched_wakeup(p, success);
- check_preempt_curr(rq, p, wake_flags);
-
- p->state = TASK_RUNNING;
-#ifdef CONFIG_SMP
- if (p->sched_class->task_woken)
- p->sched_class->task_woken(rq, p);
-
- if (unlikely(rq->idle_stamp)) {
- u64 delta = rq->clock - rq->idle_stamp;
- u64 max = 2*sysctl_sched_migration_cost;
-
- if (delta > max)
- rq->avg_idle = max;
- else
- update_avg(&rq->avg_idle, delta);
- rq->idle_stamp = 0;
- }
-#endif
+ ttwu_post_activation(p, rq, wake_flags, success);
out:
task_rq_unlock(rq, &flags);
put_cpu();
@@ -2399,6 +2431,37 @@ out:
}
/**
+ * try_to_wake_up_local - try to wake up a local task with rq lock held
+ * @p: the thread to be awakened
+ *
+ * Put @p on the run-queue if it's not alredy there. The caller must
+ * ensure that this_rq() is locked, @p is bound to this_rq() and not
+ * the current task. this_rq() stays locked over invocation.
+ */
+static void try_to_wake_up_local(struct task_struct *p)
+{
+ struct rq *rq = task_rq(p);
+ bool success = false;
+
+ BUG_ON(rq != this_rq());
+ BUG_ON(p == current);
+ lockdep_assert_held(&rq->lock);
+
+ if (!(p->state & TASK_NORMAL))
+ return;
+
+ if (!p->se.on_rq) {
+ if (likely(!task_running(rq, p))) {
+ schedstat_inc(rq, ttwu_count);
+ schedstat_inc(rq, ttwu_local);
+ }
+ ttwu_activate(p, rq, false, false, true, ENQUEUE_WAKEUP);
+ success = true;
+ }
+ ttwu_post_activation(p, rq, 0, success);
+}
+
+/**
* wake_up_process - Wake up a specific process
* @p: The process to be woken up.
*
@@ -3012,23 +3075,102 @@ static void calc_load_account_active(struct rq *this_rq)
}
/*
+ * The exact cpuload at various idx values, calculated at every tick would be
+ * load = (2^idx - 1) / 2^idx * load + 1 / 2^idx * cur_load
+ *
+ * If a cpu misses updates for n-1 ticks (as it was idle) and update gets called
+ * on nth tick when cpu may be busy, then we have:
+ * load = ((2^idx - 1) / 2^idx)^(n-1) * load
+ * load = (2^idx - 1) / 2^idx) * load + 1 / 2^idx * cur_load
+ *
+ * decay_load_missed() below does efficient calculation of
+ * load = ((2^idx - 1) / 2^idx)^(n-1) * load
+ * avoiding 0..n-1 loop doing load = ((2^idx - 1) / 2^idx) * load
+ *
+ * The calculation is approximated on a 128 point scale.
+ * degrade_zero_ticks is the number of ticks after which load at any
+ * particular idx is approximated to be zero.
+ * degrade_factor is a precomputed table, a row for each load idx.
+ * Each column corresponds to degradation factor for a power of two ticks,
+ * based on 128 point scale.
+ * Example:
+ * row 2, col 3 (=12) says that the degradation at load idx 2 after
+ * 8 ticks is 12/128 (which is an approximation of exact factor 3^8/4^8).
+ *
+ * With this power of 2 load factors, we can degrade the load n times
+ * by looking at 1 bits in n and doing as many mult/shift instead of
+ * n mult/shifts needed by the exact degradation.
+ */
+#define DEGRADE_SHIFT 7
+static const unsigned char
+ degrade_zero_ticks[CPU_LOAD_IDX_MAX] = {0, 8, 32, 64, 128};
+static const unsigned char
+ degrade_factor[CPU_LOAD_IDX_MAX][DEGRADE_SHIFT + 1] = {
+ {0, 0, 0, 0, 0, 0, 0, 0},
+ {64, 32, 8, 0, 0, 0, 0, 0},
+ {96, 72, 40, 12, 1, 0, 0},
+ {112, 98, 75, 43, 15, 1, 0},
+ {120, 112, 98, 76, 45, 16, 2} };
+
+/*
+ * Update cpu_load for any missed ticks, due to tickless idle. The backlog
+ * would be when CPU is idle and so we just decay the old load without
+ * adding any new load.
+ */
+static unsigned long
+decay_load_missed(unsigned long load, unsigned long missed_updates, int idx)
+{
+ int j = 0;
+
+ if (!missed_updates)
+ return load;
+
+ if (missed_updates >= degrade_zero_ticks[idx])
+ return 0;
+
+ if (idx == 1)
+ return load >> missed_updates;
+
+ while (missed_updates) {
+ if (missed_updates % 2)
+ load = (load * degrade_factor[idx][j]) >> DEGRADE_SHIFT;
+
+ missed_updates >>= 1;
+ j++;
+ }
+ return load;
+}
+
+/*
* Update rq->cpu_load[] statistics. This function is usually called every
- * scheduler tick (TICK_NSEC).
+ * scheduler tick (TICK_NSEC). With tickless idle this will not be called
+ * every tick. We fix it up based on jiffies.
*/
static void update_cpu_load(struct rq *this_rq)
{
unsigned long this_load = this_rq->load.weight;
+ unsigned long curr_jiffies = jiffies;
+ unsigned long pending_updates;
int i, scale;
this_rq->nr_load_updates++;
+ /* Avoid repeated calls on same jiffy, when moving in and out of idle */
+ if (curr_jiffies == this_rq->last_load_update_tick)
+ return;
+
+ pending_updates = curr_jiffies - this_rq->last_load_update_tick;
+ this_rq->last_load_update_tick = curr_jiffies;
+
/* Update our load: */
- for (i = 0, scale = 1; i < CPU_LOAD_IDX_MAX; i++, scale += scale) {
+ this_rq->cpu_load[0] = this_load; /* Fasttrack for idx 0 */
+ for (i = 1, scale = 2; i < CPU_LOAD_IDX_MAX; i++, scale += scale) {
unsigned long old_load, new_load;
/* scale is effectively 1 << i now, and >> i divides by scale */
old_load = this_rq->cpu_load[i];
+ old_load = decay_load_missed(old_load, pending_updates - 1, i);
new_load = this_load;
/*
* Round up the averaging division if load is increasing. This
@@ -3036,9 +3178,15 @@ static void update_cpu_load(struct rq *this_rq)
* example.
*/
if (new_load > old_load)
- new_load += scale-1;
- this_rq->cpu_load[i] = (old_load*(scale-1) + new_load) >> i;
+ new_load += scale - 1;
+
+ this_rq->cpu_load[i] = (old_load * (scale - 1) + new_load) >> i;
}
+}
+
+static void update_cpu_load_active(struct rq *this_rq)
+{
+ update_cpu_load(this_rq);
calc_load_account_active(this_rq);
}
@@ -3426,7 +3574,7 @@ void scheduler_tick(void)
raw_spin_lock(&rq->lock);
update_rq_clock(rq);
- update_cpu_load(rq);
+ update_cpu_load_active(rq);
curr->sched_class->task_tick(rq, curr, 0);
raw_spin_unlock(&rq->lock);
@@ -3598,7 +3746,6 @@ need_resched:
rq = cpu_rq(cpu);
rcu_note_context_switch(cpu);
prev = rq->curr;
- switch_count = &prev->nivcsw;
release_kernel_lock(prev);
need_resched_nonpreemptible:
@@ -3611,11 +3758,26 @@ need_resched_nonpreemptible:
raw_spin_lock_irq(&rq->lock);
clear_tsk_need_resched(prev);
+ switch_count = &prev->nivcsw;
if (prev->state && !(preempt_count() & PREEMPT_ACTIVE)) {
- if (unlikely(signal_pending_state(prev->state, prev)))
+ if (unlikely(signal_pending_state(prev->state, prev))) {
prev->state = TASK_RUNNING;
- else
+ } else {
+ /*
+ * If a worker is going to sleep, notify and
+ * ask workqueue whether it wants to wake up a
+ * task to maintain concurrency. If so, wake
+ * up the task.
+ */
+ if (prev->flags & PF_WQ_WORKER) {
+ struct task_struct *to_wakeup;
+
+ to_wakeup = wq_worker_sleeping(prev, cpu);
+ if (to_wakeup)
+ try_to_wake_up_local(to_wakeup);
+ }
deactivate_task(rq, prev, DEQUEUE_SLEEP);
+ }
switch_count = &prev->nvcsw;
}
@@ -3637,8 +3799,10 @@ need_resched_nonpreemptible:
context_switch(rq, prev, next); /* unlocks the rq */
/*
- * the context switch might have flipped the stack from under
- * us, hence refresh the local variables.
+ * The context switch have flipped the stack from under us
+ * and restored the local variables which were saved when
+ * this task called schedule() in the past. prev == current
+ * is still correct, but it can be moved to another cpu/rq.
*/
cpu = smp_processor_id();
rq = cpu_rq(cpu);
@@ -3647,11 +3811,8 @@ need_resched_nonpreemptible:
post_schedule(rq);
- if (unlikely(reacquire_kernel_lock(current) < 0)) {
- prev = rq->curr;
- switch_count = &prev->nivcsw;
+ if (unlikely(reacquire_kernel_lock(prev)))
goto need_resched_nonpreemptible;
- }
preempt_enable_no_resched();
if (need_resched())
@@ -3726,7 +3887,7 @@ int mutex_spin_on_owner(struct mutex *lock, struct thread_info *owner)
* off of preempt_enable. Kernel preemptions off return from interrupt
* occur there and call schedule directly.
*/
-asmlinkage void __sched preempt_schedule(void)
+asmlinkage void __sched notrace preempt_schedule(void)
{
struct thread_info *ti = current_thread_info();
@@ -3738,9 +3899,9 @@ asmlinkage void __sched preempt_schedule(void)
return;
do {
- add_preempt_count(PREEMPT_ACTIVE);
+ add_preempt_count_notrace(PREEMPT_ACTIVE);
schedule();
- sub_preempt_count(PREEMPT_ACTIVE);
+ sub_preempt_count_notrace(PREEMPT_ACTIVE);
/*
* Check again in case we missed a preemption opportunity
@@ -4441,12 +4602,8 @@ recheck:
*/
if (user && !capable(CAP_SYS_NICE)) {
if (rt_policy(policy)) {
- unsigned long rlim_rtprio;
-
- if (!lock_task_sighand(p, &flags))
- return -ESRCH;
- rlim_rtprio = task_rlimit(p, RLIMIT_RTPRIO);
- unlock_task_sighand(p, &flags);
+ unsigned long rlim_rtprio =
+ task_rlimit(p, RLIMIT_RTPRIO);
/* can't set/change the rt policy */
if (policy != p->policy && !rlim_rtprio)
@@ -5816,20 +5973,49 @@ migration_call(struct notifier_block *nfb, unsigned long action, void *hcpu)
*/
static struct notifier_block __cpuinitdata migration_notifier = {
.notifier_call = migration_call,
- .priority = 10
+ .priority = CPU_PRI_MIGRATION,
};
+static int __cpuinit sched_cpu_active(struct notifier_block *nfb,
+ unsigned long action, void *hcpu)
+{
+ switch (action & ~CPU_TASKS_FROZEN) {
+ case CPU_ONLINE:
+ case CPU_DOWN_FAILED:
+ set_cpu_active((long)hcpu, true);
+ return NOTIFY_OK;
+ default:
+ return NOTIFY_DONE;
+ }
+}
+
+static int __cpuinit sched_cpu_inactive(struct notifier_block *nfb,
+ unsigned long action, void *hcpu)
+{
+ switch (action & ~CPU_TASKS_FROZEN) {
+ case CPU_DOWN_PREPARE:
+ set_cpu_active((long)hcpu, false);
+ return NOTIFY_OK;
+ default:
+ return NOTIFY_DONE;
+ }
+}
+
static int __init migration_init(void)
{
void *cpu = (void *)(long)smp_processor_id();
int err;
- /* Start one for the boot CPU: */
+ /* Initialize migration for the boot CPU */
err = migration_call(&migration_notifier, CPU_UP_PREPARE, cpu);
BUG_ON(err == NOTIFY_BAD);
migration_call(&migration_notifier, CPU_ONLINE, cpu);
register_cpu_notifier(&migration_notifier);
+ /* Register cpu active notifiers */
+ cpu_notifier(sched_cpu_active, CPU_PRI_SCHED_ACTIVE);
+ cpu_notifier(sched_cpu_inactive, CPU_PRI_SCHED_INACTIVE);
+
return 0;
}
early_initcall(migration_init);
@@ -6064,23 +6250,18 @@ static void rq_attach_root(struct rq *rq, struct root_domain *rd)
free_rootdomain(old_rd);
}
-static int init_rootdomain(struct root_domain *rd, bool bootmem)
+static int init_rootdomain(struct root_domain *rd)
{
- gfp_t gfp = GFP_KERNEL;
-
memset(rd, 0, sizeof(*rd));
- if (bootmem)
- gfp = GFP_NOWAIT;
-
- if (!alloc_cpumask_var(&rd->span, gfp))
+ if (!alloc_cpumask_var(&rd->span, GFP_KERNEL))
goto out;
- if (!alloc_cpumask_var(&rd->online, gfp))
+ if (!alloc_cpumask_var(&rd->online, GFP_KERNEL))
goto free_span;
- if (!alloc_cpumask_var(&rd->rto_mask, gfp))
+ if (!alloc_cpumask_var(&rd->rto_mask, GFP_KERNEL))
goto free_online;
- if (cpupri_init(&rd->cpupri, bootmem) != 0)
+ if (cpupri_init(&rd->cpupri) != 0)
goto free_rto_mask;
return 0;
@@ -6096,7 +6277,7 @@ out:
static void init_defrootdomain(void)
{
- init_rootdomain(&def_root_domain, true);
+ init_rootdomain(&def_root_domain);
atomic_set(&def_root_domain.refcount, 1);
}
@@ -6109,7 +6290,7 @@ static struct root_domain *alloc_rootdomain(void)
if (!rd)
return NULL;
- if (init_rootdomain(rd, false) != 0) {
+ if (init_rootdomain(rd) != 0) {
kfree(rd);
return NULL;
}
@@ -7288,29 +7469,35 @@ int __init sched_create_sysfs_power_savings_entries(struct sysdev_class *cls)
}
#endif /* CONFIG_SCHED_MC || CONFIG_SCHED_SMT */
-#ifndef CONFIG_CPUSETS
/*
- * Add online and remove offline CPUs from the scheduler domains.
- * When cpusets are enabled they take over this function.
+ * Update cpusets according to cpu_active mask. If cpusets are
+ * disabled, cpuset_update_active_cpus() becomes a simple wrapper
+ * around partition_sched_domains().
*/
-static int update_sched_domains(struct notifier_block *nfb,
- unsigned long action, void *hcpu)
+static int cpuset_cpu_active(struct notifier_block *nfb, unsigned long action,
+ void *hcpu)
{
- switch (action) {
+ switch (action & ~CPU_TASKS_FROZEN) {
case CPU_ONLINE:
- case CPU_ONLINE_FROZEN:
- case CPU_DOWN_PREPARE:
- case CPU_DOWN_PREPARE_FROZEN:
case CPU_DOWN_FAILED:
- case CPU_DOWN_FAILED_FROZEN:
- partition_sched_domains(1, NULL, NULL);
+ cpuset_update_active_cpus();
return NOTIFY_OK;
+ default:
+ return NOTIFY_DONE;
+ }
+}
+static int cpuset_cpu_inactive(struct notifier_block *nfb, unsigned long action,
+ void *hcpu)
+{
+ switch (action & ~CPU_TASKS_FROZEN) {
+ case CPU_DOWN_PREPARE:
+ cpuset_update_active_cpus();
+ return NOTIFY_OK;
default:
return NOTIFY_DONE;
}
}
-#endif
static int update_runtime(struct notifier_block *nfb,
unsigned long action, void *hcpu)
@@ -7356,10 +7543,8 @@ void __init sched_init_smp(void)
mutex_unlock(&sched_domains_mutex);
put_online_cpus();
-#ifndef CONFIG_CPUSETS
- /* XXX: Theoretical race here - CPU may be hotplugged now */
- hotcpu_notifier(update_sched_domains, 0);
-#endif
+ hotcpu_notifier(cpuset_cpu_active, CPU_PRI_CPUSET_ACTIVE);
+ hotcpu_notifier(cpuset_cpu_inactive, CPU_PRI_CPUSET_INACTIVE);
/* RT runtime code needs to handle some hotplug events */
hotcpu_notifier(update_runtime, 0);
@@ -7604,6 +7789,9 @@ void __init sched_init(void)
for (j = 0; j < CPU_LOAD_IDX_MAX; j++)
rq->cpu_load[j] = 0;
+
+ rq->last_load_update_tick = jiffies;
+
#ifdef CONFIG_SMP
rq->sd = NULL;
rq->rd = NULL;
@@ -7617,6 +7805,10 @@ void __init sched_init(void)
rq->idle_stamp = 0;
rq->avg_idle = 2*sysctl_sched_migration_cost;
rq_attach_root(rq, &def_root_domain);
+#ifdef CONFIG_NO_HZ
+ rq->nohz_balance_kick = 0;
+ init_sched_softirq_csd(&per_cpu(remote_sched_softirq_cb, i));
+#endif
#endif
init_rq_hrtick(rq);
atomic_set(&rq->nr_iowait, 0);
@@ -7661,8 +7853,11 @@ void __init sched_init(void)
zalloc_cpumask_var(&nohz_cpu_mask, GFP_NOWAIT);
#ifdef CONFIG_SMP
#ifdef CONFIG_NO_HZ
- zalloc_cpumask_var(&nohz.cpu_mask, GFP_NOWAIT);
- alloc_cpumask_var(&nohz.ilb_grp_nohz_mask, GFP_NOWAIT);
+ zalloc_cpumask_var(&nohz.idle_cpus_mask, GFP_NOWAIT);
+ alloc_cpumask_var(&nohz.grp_idle_mask, GFP_NOWAIT);
+ atomic_set(&nohz.load_balancer, nr_cpu_ids);
+ atomic_set(&nohz.first_pick_cpu, nr_cpu_ids);
+ atomic_set(&nohz.second_pick_cpu, nr_cpu_ids);
#endif
/* May be allocated at isolcpus cmdline parse time */
if (cpu_isolated_map == NULL)
diff --git a/kernel/sched_clock.c b/kernel/sched_clock.c
index 906a0f718cb..52f1a149bfb 100644
--- a/kernel/sched_clock.c
+++ b/kernel/sched_clock.c
@@ -10,19 +10,55 @@
* Ingo Molnar <mingo@redhat.com>
* Guillaume Chazarain <guichaz@gmail.com>
*
- * Create a semi stable clock from a mixture of other events, including:
- * - gtod
+ *
+ * What:
+ *
+ * cpu_clock(i) provides a fast (execution time) high resolution
+ * clock with bounded drift between CPUs. The value of cpu_clock(i)
+ * is monotonic for constant i. The timestamp returned is in nanoseconds.
+ *
+ * ######################### BIG FAT WARNING ##########################
+ * # when comparing cpu_clock(i) to cpu_clock(j) for i != j, time can #
+ * # go backwards !! #
+ * ####################################################################
+ *
+ * There is no strict promise about the base, although it tends to start
+ * at 0 on boot (but people really shouldn't rely on that).
+ *
+ * cpu_clock(i) -- can be used from any context, including NMI.
+ * sched_clock_cpu(i) -- must be used with local IRQs disabled (implied by NMI)
+ * local_clock() -- is cpu_clock() on the current cpu.
+ *
+ * How:
+ *
+ * The implementation either uses sched_clock() when
+ * !CONFIG_HAVE_UNSTABLE_SCHED_CLOCK, which means in that case the
+ * sched_clock() is assumed to provide these properties (mostly it means
+ * the architecture provides a globally synchronized highres time source).
+ *
+ * Otherwise it tries to create a semi stable clock from a mixture of other
+ * clocks, including:
+ *
+ * - GTOD (clock monotomic)
* - sched_clock()
* - explicit idle events
*
- * We use gtod as base and the unstable clock deltas. The deltas are filtered,
- * making it monotonic and keeping it within an expected window.
+ * We use GTOD as base and use sched_clock() deltas to improve resolution. The
+ * deltas are filtered to provide monotonicity and keeping it within an
+ * expected window.
*
* Furthermore, explicit sleep and wakeup hooks allow us to account for time
* that is otherwise invisible (TSC gets stopped).
*
- * The clock: sched_clock_cpu() is monotonic per cpu, and should be somewhat
- * consistent between cpus (never more than 2 jiffies difference).
+ *
+ * Notes:
+ *
+ * The !IRQ-safetly of sched_clock() and sched_clock_cpu() comes from things
+ * like cpufreq interrupts that can change the base clock (TSC) multiplier
+ * and cause funny jumps in time -- although the filtering provided by
+ * sched_clock_cpu() should mitigate serious artifacts we cannot rely on it
+ * in general since for !CONFIG_HAVE_UNSTABLE_SCHED_CLOCK we fully rely on
+ * sched_clock().
*/
#include <linux/spinlock.h>
#include <linux/hardirq.h>
@@ -170,6 +206,11 @@ again:
return val;
}
+/*
+ * Similar to cpu_clock(), but requires local IRQs to be disabled.
+ *
+ * See cpu_clock().
+ */
u64 sched_clock_cpu(int cpu)
{
struct sched_clock_data *scd;
@@ -237,9 +278,19 @@ void sched_clock_idle_wakeup_event(u64 delta_ns)
}
EXPORT_SYMBOL_GPL(sched_clock_idle_wakeup_event);
-unsigned long long cpu_clock(int cpu)
+/*
+ * As outlined at the top, provides a fast, high resolution, nanosecond
+ * time source that is monotonic per cpu argument and has bounded drift
+ * between cpus.
+ *
+ * ######################### BIG FAT WARNING ##########################
+ * # when comparing cpu_clock(i) to cpu_clock(j) for i != j, time can #
+ * # go backwards !! #
+ * ####################################################################
+ */
+u64 cpu_clock(int cpu)
{
- unsigned long long clock;
+ u64 clock;
unsigned long flags;
local_irq_save(flags);
@@ -249,6 +300,25 @@ unsigned long long cpu_clock(int cpu)
return clock;
}
+/*
+ * Similar to cpu_clock() for the current cpu. Time will only be observed
+ * to be monotonic if care is taken to only compare timestampt taken on the
+ * same CPU.
+ *
+ * See cpu_clock().
+ */
+u64 local_clock(void)
+{
+ u64 clock;
+ unsigned long flags;
+
+ local_irq_save(flags);
+ clock = sched_clock_cpu(smp_processor_id());
+ local_irq_restore(flags);
+
+ return clock;
+}
+
#else /* CONFIG_HAVE_UNSTABLE_SCHED_CLOCK */
void sched_clock_init(void)
@@ -264,12 +334,17 @@ u64 sched_clock_cpu(int cpu)
return sched_clock();
}
-
-unsigned long long cpu_clock(int cpu)
+u64 cpu_clock(int cpu)
{
return sched_clock_cpu(cpu);
}
+u64 local_clock(void)
+{
+ return sched_clock_cpu(0);
+}
+
#endif /* CONFIG_HAVE_UNSTABLE_SCHED_CLOCK */
EXPORT_SYMBOL_GPL(cpu_clock);
+EXPORT_SYMBOL_GPL(local_clock);
diff --git a/kernel/sched_cpupri.c b/kernel/sched_cpupri.c
index e6871cb3fc8..2722dc1b413 100644
--- a/kernel/sched_cpupri.c
+++ b/kernel/sched_cpupri.c
@@ -166,14 +166,10 @@ void cpupri_set(struct cpupri *cp, int cpu, int newpri)
*
* Returns: -ENOMEM if memory fails.
*/
-int cpupri_init(struct cpupri *cp, bool bootmem)
+int cpupri_init(struct cpupri *cp)
{
- gfp_t gfp = GFP_KERNEL;
int i;
- if (bootmem)
- gfp = GFP_NOWAIT;
-
memset(cp, 0, sizeof(*cp));
for (i = 0; i < CPUPRI_NR_PRIORITIES; i++) {
@@ -181,7 +177,7 @@ int cpupri_init(struct cpupri *cp, bool bootmem)
raw_spin_lock_init(&vec->lock);
vec->count = 0;
- if (!zalloc_cpumask_var(&vec->mask, gfp))
+ if (!zalloc_cpumask_var(&vec->mask, GFP_KERNEL))
goto cleanup;
}
diff --git a/kernel/sched_cpupri.h b/kernel/sched_cpupri.h
index 7cb5bb6b95b..9fc7d386fea 100644
--- a/kernel/sched_cpupri.h
+++ b/kernel/sched_cpupri.h
@@ -27,7 +27,7 @@ struct cpupri {
int cpupri_find(struct cpupri *cp,
struct task_struct *p, struct cpumask *lowest_mask);
void cpupri_set(struct cpupri *cp, int cpu, int pri);
-int cpupri_init(struct cpupri *cp, bool bootmem);
+int cpupri_init(struct cpupri *cp);
void cpupri_cleanup(struct cpupri *cp);
#else
#define cpupri_set(cp, cpu, pri) do { } while (0)
diff --git a/kernel/sched_debug.c b/kernel/sched_debug.c
index 35565395d00..2e1b0d17dd9 100644
--- a/kernel/sched_debug.c
+++ b/kernel/sched_debug.c
@@ -332,7 +332,7 @@ static int sched_debug_show(struct seq_file *m, void *v)
PN(sysctl_sched_latency);
PN(sysctl_sched_min_granularity);
PN(sysctl_sched_wakeup_granularity);
- PN(sysctl_sched_child_runs_first);
+ P(sysctl_sched_child_runs_first);
P(sysctl_sched_features);
#undef PN
#undef P
diff --git a/kernel/sched_fair.c b/kernel/sched_fair.c
index a878b5332da..806d1b227a2 100644
--- a/kernel/sched_fair.c
+++ b/kernel/sched_fair.c
@@ -2287,13 +2287,6 @@ static void update_cpu_power(struct sched_domain *sd, int cpu)
unsigned long power = SCHED_LOAD_SCALE;
struct sched_group *sdg = sd->groups;
- if (sched_feat(ARCH_POWER))
- power *= arch_scale_freq_power(sd, cpu);
- else
- power *= default_scale_freq_power(sd, cpu);
-
- power >>= SCHED_LOAD_SHIFT;
-
if ((sd->flags & SD_SHARE_CPUPOWER) && weight > 1) {
if (sched_feat(ARCH_POWER))
power *= arch_scale_smt_power(sd, cpu);
@@ -2303,6 +2296,15 @@ static void update_cpu_power(struct sched_domain *sd, int cpu)
power >>= SCHED_LOAD_SHIFT;
}
+ sdg->cpu_power_orig = power;
+
+ if (sched_feat(ARCH_POWER))
+ power *= arch_scale_freq_power(sd, cpu);
+ else
+ power *= default_scale_freq_power(sd, cpu);
+
+ power >>= SCHED_LOAD_SHIFT;
+
power *= scale_rt_power(cpu);
power >>= SCHED_LOAD_SHIFT;
@@ -2335,6 +2337,31 @@ static void update_group_power(struct sched_domain *sd, int cpu)
sdg->cpu_power = power;
}
+/*
+ * Try and fix up capacity for tiny siblings, this is needed when
+ * things like SD_ASYM_PACKING need f_b_g to select another sibling
+ * which on its own isn't powerful enough.
+ *
+ * See update_sd_pick_busiest() and check_asym_packing().
+ */
+static inline int
+fix_small_capacity(struct sched_domain *sd, struct sched_group *group)
+{
+ /*
+ * Only siblings can have significantly less than SCHED_LOAD_SCALE
+ */
+ if (sd->level != SD_LV_SIBLING)
+ return 0;
+
+ /*
+ * If ~90% of the cpu_power is still there, we're good.
+ */
+ if (group->cpu_power * 32 > group->cpu_power_orig * 29)
+ return 1;
+
+ return 0;
+}
+
/**
* update_sg_lb_stats - Update sched_group's statistics for load balancing.
* @sd: The sched_domain whose statistics are to be updated.
@@ -2400,14 +2427,14 @@ static inline void update_sg_lb_stats(struct sched_domain *sd,
* domains. In the newly idle case, we will allow all the cpu's
* to do the newly idle load balance.
*/
- if (idle != CPU_NEWLY_IDLE && local_group &&
- balance_cpu != this_cpu) {
- *balance = 0;
- return;
+ if (idle != CPU_NEWLY_IDLE && local_group) {
+ if (balance_cpu != this_cpu) {
+ *balance = 0;
+ return;
+ }
+ update_group_power(sd, this_cpu);
}
- update_group_power(sd, this_cpu);
-
/* Adjust by relative CPU power of the group */
sgs->avg_load = (sgs->group_load * SCHED_LOAD_SCALE) / group->cpu_power;
@@ -2428,6 +2455,51 @@ static inline void update_sg_lb_stats(struct sched_domain *sd,
sgs->group_capacity =
DIV_ROUND_CLOSEST(group->cpu_power, SCHED_LOAD_SCALE);
+ if (!sgs->group_capacity)
+ sgs->group_capacity = fix_small_capacity(sd, group);
+}
+
+/**
+ * update_sd_pick_busiest - return 1 on busiest group
+ * @sd: sched_domain whose statistics are to be checked
+ * @sds: sched_domain statistics
+ * @sg: sched_group candidate to be checked for being the busiest
+ * @sgs: sched_group statistics
+ * @this_cpu: the current cpu
+ *
+ * Determine if @sg is a busier group than the previously selected
+ * busiest group.
+ */
+static bool update_sd_pick_busiest(struct sched_domain *sd,
+ struct sd_lb_stats *sds,
+ struct sched_group *sg,
+ struct sg_lb_stats *sgs,
+ int this_cpu)
+{
+ if (sgs->avg_load <= sds->max_load)
+ return false;
+
+ if (sgs->sum_nr_running > sgs->group_capacity)
+ return true;
+
+ if (sgs->group_imb)
+ return true;
+
+ /*
+ * ASYM_PACKING needs to move all the work to the lowest
+ * numbered CPUs in the group, therefore mark all groups
+ * higher than ourself as busy.
+ */
+ if ((sd->flags & SD_ASYM_PACKING) && sgs->sum_nr_running &&
+ this_cpu < group_first_cpu(sg)) {
+ if (!sds->busiest)
+ return true;
+
+ if (group_first_cpu(sds->busiest) > group_first_cpu(sg))
+ return true;
+ }
+
+ return false;
}
/**
@@ -2435,7 +2507,7 @@ static inline void update_sg_lb_stats(struct sched_domain *sd,
* @sd: sched_domain whose statistics are to be updated.
* @this_cpu: Cpu for which load balance is currently performed.
* @idle: Idle status of this_cpu
- * @sd_idle: Idle status of the sched_domain containing group.
+ * @sd_idle: Idle status of the sched_domain containing sg.
* @cpus: Set of cpus considered for load balancing.
* @balance: Should we balance.
* @sds: variable to hold the statistics for this sched_domain.
@@ -2446,7 +2518,7 @@ static inline void update_sd_lb_stats(struct sched_domain *sd, int this_cpu,
struct sd_lb_stats *sds)
{
struct sched_domain *child = sd->child;
- struct sched_group *group = sd->groups;
+ struct sched_group *sg = sd->groups;
struct sg_lb_stats sgs;
int load_idx, prefer_sibling = 0;
@@ -2459,21 +2531,20 @@ static inline void update_sd_lb_stats(struct sched_domain *sd, int this_cpu,
do {
int local_group;
- local_group = cpumask_test_cpu(this_cpu,
- sched_group_cpus(group));
+ local_group = cpumask_test_cpu(this_cpu, sched_group_cpus(sg));
memset(&sgs, 0, sizeof(sgs));
- update_sg_lb_stats(sd, group, this_cpu, idle, load_idx, sd_idle,
+ update_sg_lb_stats(sd, sg, this_cpu, idle, load_idx, sd_idle,
local_group, cpus, balance, &sgs);
if (local_group && !(*balance))
return;
sds->total_load += sgs.group_load;
- sds->total_pwr += group->cpu_power;
+ sds->total_pwr += sg->cpu_power;
/*
* In case the child domain prefers tasks go to siblings
- * first, lower the group capacity to one so that we'll try
+ * first, lower the sg capacity to one so that we'll try
* and move all the excess tasks away.
*/
if (prefer_sibling)
@@ -2481,23 +2552,72 @@ static inline void update_sd_lb_stats(struct sched_domain *sd, int this_cpu,
if (local_group) {
sds->this_load = sgs.avg_load;
- sds->this = group;
+ sds->this = sg;
sds->this_nr_running = sgs.sum_nr_running;
sds->this_load_per_task = sgs.sum_weighted_load;
- } else if (sgs.avg_load > sds->max_load &&
- (sgs.sum_nr_running > sgs.group_capacity ||
- sgs.group_imb)) {
+ } else if (update_sd_pick_busiest(sd, sds, sg, &sgs, this_cpu)) {
sds->max_load = sgs.avg_load;
- sds->busiest = group;
+ sds->busiest = sg;
sds->busiest_nr_running = sgs.sum_nr_running;
sds->busiest_group_capacity = sgs.group_capacity;
sds->busiest_load_per_task = sgs.sum_weighted_load;
sds->group_imb = sgs.group_imb;
}
- update_sd_power_savings_stats(group, sds, local_group, &sgs);
- group = group->next;
- } while (group != sd->groups);
+ update_sd_power_savings_stats(sg, sds, local_group, &sgs);
+ sg = sg->next;
+ } while (sg != sd->groups);
+}
+
+int __weak arch_sd_sibling_asym_packing(void)
+{
+ return 0*SD_ASYM_PACKING;
+}
+
+/**
+ * check_asym_packing - Check to see if the group is packed into the
+ * sched doman.
+ *
+ * This is primarily intended to used at the sibling level. Some
+ * cores like POWER7 prefer to use lower numbered SMT threads. In the
+ * case of POWER7, it can move to lower SMT modes only when higher
+ * threads are idle. When in lower SMT modes, the threads will
+ * perform better since they share less core resources. Hence when we
+ * have idle threads, we want them to be the higher ones.
+ *
+ * This packing function is run on idle threads. It checks to see if
+ * the busiest CPU in this domain (core in the P7 case) has a higher
+ * CPU number than the packing function is being run on. Here we are
+ * assuming lower CPU number will be equivalent to lower a SMT thread
+ * number.
+ *
+ * Returns 1 when packing is required and a task should be moved to
+ * this CPU. The amount of the imbalance is returned in *imbalance.
+ *
+ * @sd: The sched_domain whose packing is to be checked.
+ * @sds: Statistics of the sched_domain which is to be packed
+ * @this_cpu: The cpu at whose sched_domain we're performing load-balance.
+ * @imbalance: returns amount of imbalanced due to packing.
+ */
+static int check_asym_packing(struct sched_domain *sd,
+ struct sd_lb_stats *sds,
+ int this_cpu, unsigned long *imbalance)
+{
+ int busiest_cpu;
+
+ if (!(sd->flags & SD_ASYM_PACKING))
+ return 0;
+
+ if (!sds->busiest)
+ return 0;
+
+ busiest_cpu = group_first_cpu(sds->busiest);
+ if (this_cpu > busiest_cpu)
+ return 0;
+
+ *imbalance = DIV_ROUND_CLOSEST(sds->max_load * sds->busiest->cpu_power,
+ SCHED_LOAD_SCALE);
+ return 1;
}
/**
@@ -2692,6 +2812,10 @@ find_busiest_group(struct sched_domain *sd, int this_cpu,
if (!(*balance))
goto ret;
+ if ((idle == CPU_IDLE || idle == CPU_NEWLY_IDLE) &&
+ check_asym_packing(sd, &sds, this_cpu, imbalance))
+ return sds.busiest;
+
if (!sds.busiest || sds.busiest_nr_running == 0)
goto out_balanced;
@@ -2726,8 +2850,9 @@ ret:
* find_busiest_queue - find the busiest runqueue among the cpus in group.
*/
static struct rq *
-find_busiest_queue(struct sched_group *group, enum cpu_idle_type idle,
- unsigned long imbalance, const struct cpumask *cpus)
+find_busiest_queue(struct sched_domain *sd, struct sched_group *group,
+ enum cpu_idle_type idle, unsigned long imbalance,
+ const struct cpumask *cpus)
{
struct rq *busiest = NULL, *rq;
unsigned long max_load = 0;
@@ -2738,6 +2863,9 @@ find_busiest_queue(struct sched_group *group, enum cpu_idle_type idle,
unsigned long capacity = DIV_ROUND_CLOSEST(power, SCHED_LOAD_SCALE);
unsigned long wl;
+ if (!capacity)
+ capacity = fix_small_capacity(sd, group);
+
if (!cpumask_test_cpu(i, cpus))
continue;
@@ -2777,9 +2905,19 @@ find_busiest_queue(struct sched_group *group, enum cpu_idle_type idle,
/* Working cpumask for load_balance and load_balance_newidle. */
static DEFINE_PER_CPU(cpumask_var_t, load_balance_tmpmask);
-static int need_active_balance(struct sched_domain *sd, int sd_idle, int idle)
+static int need_active_balance(struct sched_domain *sd, int sd_idle, int idle,
+ int busiest_cpu, int this_cpu)
{
if (idle == CPU_NEWLY_IDLE) {
+
+ /*
+ * ASYM_PACKING needs to force migrate tasks from busy but
+ * higher numbered CPUs in order to pack all tasks in the
+ * lowest numbered CPUs.
+ */
+ if ((sd->flags & SD_ASYM_PACKING) && busiest_cpu > this_cpu)
+ return 1;
+
/*
* The only task running in a non-idle cpu can be moved to this
* cpu in an attempt to completely freeup the other CPU
@@ -2854,7 +2992,7 @@ redo:
goto out_balanced;
}
- busiest = find_busiest_queue(group, idle, imbalance, cpus);
+ busiest = find_busiest_queue(sd, group, idle, imbalance, cpus);
if (!busiest) {
schedstat_inc(sd, lb_nobusyq[idle]);
goto out_balanced;
@@ -2898,7 +3036,8 @@ redo:
schedstat_inc(sd, lb_failed[idle]);
sd->nr_balance_failed++;
- if (need_active_balance(sd, sd_idle, idle)) {
+ if (need_active_balance(sd, sd_idle, idle, cpu_of(busiest),
+ this_cpu)) {
raw_spin_lock_irqsave(&busiest->lock, flags);
/* don't kick the active_load_balance_cpu_stop,
@@ -3093,13 +3232,40 @@ out_unlock:
}
#ifdef CONFIG_NO_HZ
+
+static DEFINE_PER_CPU(struct call_single_data, remote_sched_softirq_cb);
+
+static void trigger_sched_softirq(void *data)
+{
+ raise_softirq_irqoff(SCHED_SOFTIRQ);
+}
+
+static inline void init_sched_softirq_csd(struct call_single_data *csd)
+{
+ csd->func = trigger_sched_softirq;
+ csd->info = NULL;
+ csd->flags = 0;
+ csd->priv = 0;
+}
+
+/*
+ * idle load balancing details
+ * - One of the idle CPUs nominates itself as idle load_balancer, while
+ * entering idle.
+ * - This idle load balancer CPU will also go into tickless mode when
+ * it is idle, just like all other idle CPUs
+ * - When one of the busy CPUs notice that there may be an idle rebalancing
+ * needed, they will kick the idle load balancer, which then does idle
+ * load balancing for all the idle CPUs.
+ */
static struct {
atomic_t load_balancer;
- cpumask_var_t cpu_mask;
- cpumask_var_t ilb_grp_nohz_mask;
-} nohz ____cacheline_aligned = {
- .load_balancer = ATOMIC_INIT(-1),
-};
+ atomic_t first_pick_cpu;
+ atomic_t second_pick_cpu;
+ cpumask_var_t idle_cpus_mask;
+ cpumask_var_t grp_idle_mask;
+ unsigned long next_balance; /* in jiffy units */
+} nohz ____cacheline_aligned;
int get_nohz_load_balancer(void)
{
@@ -3153,17 +3319,17 @@ static inline struct sched_domain *lowest_flag_domain(int cpu, int flag)
*/
static inline int is_semi_idle_group(struct sched_group *ilb_group)
{
- cpumask_and(nohz.ilb_grp_nohz_mask, nohz.cpu_mask,
+ cpumask_and(nohz.grp_idle_mask, nohz.idle_cpus_mask,
sched_group_cpus(ilb_group));
/*
* A sched_group is semi-idle when it has atleast one busy cpu
* and atleast one idle cpu.
*/
- if (cpumask_empty(nohz.ilb_grp_nohz_mask))
+ if (cpumask_empty(nohz.grp_idle_mask))
return 0;
- if (cpumask_equal(nohz.ilb_grp_nohz_mask, sched_group_cpus(ilb_group)))
+ if (cpumask_equal(nohz.grp_idle_mask, sched_group_cpus(ilb_group)))
return 0;
return 1;
@@ -3196,7 +3362,7 @@ static int find_new_ilb(int cpu)
* Optimize for the case when we have no idle CPUs or only one
* idle CPU. Don't walk the sched_domain hierarchy in such cases
*/
- if (cpumask_weight(nohz.cpu_mask) < 2)
+ if (cpumask_weight(nohz.idle_cpus_mask) < 2)
goto out_done;
for_each_flag_domain(cpu, sd, SD_POWERSAVINGS_BALANCE) {
@@ -3204,7 +3370,7 @@ static int find_new_ilb(int cpu)
do {
if (is_semi_idle_group(ilb_group))
- return cpumask_first(nohz.ilb_grp_nohz_mask);
+ return cpumask_first(nohz.grp_idle_mask);
ilb_group = ilb_group->next;
@@ -3212,98 +3378,116 @@ static int find_new_ilb(int cpu)
}
out_done:
- return cpumask_first(nohz.cpu_mask);
+ return nr_cpu_ids;
}
#else /* (CONFIG_SCHED_MC || CONFIG_SCHED_SMT) */
static inline int find_new_ilb(int call_cpu)
{
- return cpumask_first(nohz.cpu_mask);
+ return nr_cpu_ids;
}
#endif
/*
+ * Kick a CPU to do the nohz balancing, if it is time for it. We pick the
+ * nohz_load_balancer CPU (if there is one) otherwise fallback to any idle
+ * CPU (if there is one).
+ */
+static void nohz_balancer_kick(int cpu)
+{
+ int ilb_cpu;
+
+ nohz.next_balance++;
+
+ ilb_cpu = get_nohz_load_balancer();
+
+ if (ilb_cpu >= nr_cpu_ids) {
+ ilb_cpu = cpumask_first(nohz.idle_cpus_mask);
+ if (ilb_cpu >= nr_cpu_ids)
+ return;
+ }
+
+ if (!cpu_rq(ilb_cpu)->nohz_balance_kick) {
+ struct call_single_data *cp;
+
+ cpu_rq(ilb_cpu)->nohz_balance_kick = 1;
+ cp = &per_cpu(remote_sched_softirq_cb, cpu);
+ __smp_call_function_single(ilb_cpu, cp, 0);
+ }
+ return;
+}
+
+/*
* This routine will try to nominate the ilb (idle load balancing)
* owner among the cpus whose ticks are stopped. ilb owner will do the idle
- * load balancing on behalf of all those cpus. If all the cpus in the system
- * go into this tickless mode, then there will be no ilb owner (as there is
- * no need for one) and all the cpus will sleep till the next wakeup event
- * arrives...
- *
- * For the ilb owner, tick is not stopped. And this tick will be used
- * for idle load balancing. ilb owner will still be part of
- * nohz.cpu_mask..
+ * load balancing on behalf of all those cpus.
*
- * While stopping the tick, this cpu will become the ilb owner if there
- * is no other owner. And will be the owner till that cpu becomes busy
- * or if all cpus in the system stop their ticks at which point
- * there is no need for ilb owner.
+ * When the ilb owner becomes busy, we will not have new ilb owner until some
+ * idle CPU wakes up and goes back to idle or some busy CPU tries to kick
+ * idle load balancing by kicking one of the idle CPUs.
*
- * When the ilb owner becomes busy, it nominates another owner, during the
- * next busy scheduler_tick()
+ * Ticks are stopped for the ilb owner as well, with busy CPU kicking this
+ * ilb owner CPU in future (when there is a need for idle load balancing on
+ * behalf of all idle CPUs).
*/
-int select_nohz_load_balancer(int stop_tick)
+void select_nohz_load_balancer(int stop_tick)
{
int cpu = smp_processor_id();
if (stop_tick) {
- cpu_rq(cpu)->in_nohz_recently = 1;
-
if (!cpu_active(cpu)) {
if (atomic_read(&nohz.load_balancer) != cpu)
- return 0;
+ return;
/*
* If we are going offline and still the leader,
* give up!
*/
- if (atomic_cmpxchg(&nohz.load_balancer, cpu, -1) != cpu)
+ if (atomic_cmpxchg(&nohz.load_balancer, cpu,
+ nr_cpu_ids) != cpu)
BUG();
- return 0;
+ return;
}
- cpumask_set_cpu(cpu, nohz.cpu_mask);
+ cpumask_set_cpu(cpu, nohz.idle_cpus_mask);
- /* time for ilb owner also to sleep */
- if (cpumask_weight(nohz.cpu_mask) == num_active_cpus()) {
- if (atomic_read(&nohz.load_balancer) == cpu)
- atomic_set(&nohz.load_balancer, -1);
- return 0;
- }
+ if (atomic_read(&nohz.first_pick_cpu) == cpu)
+ atomic_cmpxchg(&nohz.first_pick_cpu, cpu, nr_cpu_ids);
+ if (atomic_read(&nohz.second_pick_cpu) == cpu)
+ atomic_cmpxchg(&nohz.second_pick_cpu, cpu, nr_cpu_ids);
- if (atomic_read(&nohz.load_balancer) == -1) {
- /* make me the ilb owner */
- if (atomic_cmpxchg(&nohz.load_balancer, -1, cpu) == -1)
- return 1;
- } else if (atomic_read(&nohz.load_balancer) == cpu) {
+ if (atomic_read(&nohz.load_balancer) >= nr_cpu_ids) {
int new_ilb;
- if (!(sched_smt_power_savings ||
- sched_mc_power_savings))
- return 1;
+ /* make me the ilb owner */
+ if (atomic_cmpxchg(&nohz.load_balancer, nr_cpu_ids,
+ cpu) != nr_cpu_ids)
+ return;
+
/*
* Check to see if there is a more power-efficient
* ilb.
*/
new_ilb = find_new_ilb(cpu);
if (new_ilb < nr_cpu_ids && new_ilb != cpu) {
- atomic_set(&nohz.load_balancer, -1);
+ atomic_set(&nohz.load_balancer, nr_cpu_ids);
resched_cpu(new_ilb);
- return 0;
+ return;
}
- return 1;
+ return;
}
} else {
- if (!cpumask_test_cpu(cpu, nohz.cpu_mask))
- return 0;
+ if (!cpumask_test_cpu(cpu, nohz.idle_cpus_mask))
+ return;
- cpumask_clear_cpu(cpu, nohz.cpu_mask);
+ cpumask_clear_cpu(cpu, nohz.idle_cpus_mask);
if (atomic_read(&nohz.load_balancer) == cpu)
- if (atomic_cmpxchg(&nohz.load_balancer, cpu, -1) != cpu)
+ if (atomic_cmpxchg(&nohz.load_balancer, cpu,
+ nr_cpu_ids) != cpu)
BUG();
}
- return 0;
+ return;
}
#endif
@@ -3385,11 +3569,102 @@ out:
rq->next_balance = next_balance;
}
+#ifdef CONFIG_NO_HZ
/*
- * run_rebalance_domains is triggered when needed from the scheduler tick.
- * In CONFIG_NO_HZ case, the idle load balance owner will do the
+ * In CONFIG_NO_HZ case, the idle balance kickee will do the
* rebalancing for all the cpus for whom scheduler ticks are stopped.
*/
+static void nohz_idle_balance(int this_cpu, enum cpu_idle_type idle)
+{
+ struct rq *this_rq = cpu_rq(this_cpu);
+ struct rq *rq;
+ int balance_cpu;
+
+ if (idle != CPU_IDLE || !this_rq->nohz_balance_kick)
+ return;
+
+ for_each_cpu(balance_cpu, nohz.idle_cpus_mask) {
+ if (balance_cpu == this_cpu)
+ continue;
+
+ /*
+ * If this cpu gets work to do, stop the load balancing
+ * work being done for other cpus. Next load
+ * balancing owner will pick it up.
+ */
+ if (need_resched()) {
+ this_rq->nohz_balance_kick = 0;
+ break;
+ }
+
+ raw_spin_lock_irq(&this_rq->lock);
+ update_rq_clock(this_rq);
+ update_cpu_load(this_rq);
+ raw_spin_unlock_irq(&this_rq->lock);
+
+ rebalance_domains(balance_cpu, CPU_IDLE);
+
+ rq = cpu_rq(balance_cpu);
+ if (time_after(this_rq->next_balance, rq->next_balance))
+ this_rq->next_balance = rq->next_balance;
+ }
+ nohz.next_balance = this_rq->next_balance;
+ this_rq->nohz_balance_kick = 0;
+}
+
+/*
+ * Current heuristic for kicking the idle load balancer
+ * - first_pick_cpu is the one of the busy CPUs. It will kick
+ * idle load balancer when it has more than one process active. This
+ * eliminates the need for idle load balancing altogether when we have
+ * only one running process in the system (common case).
+ * - If there are more than one busy CPU, idle load balancer may have
+ * to run for active_load_balance to happen (i.e., two busy CPUs are
+ * SMT or core siblings and can run better if they move to different
+ * physical CPUs). So, second_pick_cpu is the second of the busy CPUs
+ * which will kick idle load balancer as soon as it has any load.
+ */
+static inline int nohz_kick_needed(struct rq *rq, int cpu)
+{
+ unsigned long now = jiffies;
+ int ret;
+ int first_pick_cpu, second_pick_cpu;
+
+ if (time_before(now, nohz.next_balance))
+ return 0;
+
+ if (!rq->nr_running)
+ return 0;
+
+ first_pick_cpu = atomic_read(&nohz.first_pick_cpu);
+ second_pick_cpu = atomic_read(&nohz.second_pick_cpu);
+
+ if (first_pick_cpu < nr_cpu_ids && first_pick_cpu != cpu &&
+ second_pick_cpu < nr_cpu_ids && second_pick_cpu != cpu)
+ return 0;
+
+ ret = atomic_cmpxchg(&nohz.first_pick_cpu, nr_cpu_ids, cpu);
+ if (ret == nr_cpu_ids || ret == cpu) {
+ atomic_cmpxchg(&nohz.second_pick_cpu, cpu, nr_cpu_ids);
+ if (rq->nr_running > 1)
+ return 1;
+ } else {
+ ret = atomic_cmpxchg(&nohz.second_pick_cpu, nr_cpu_ids, cpu);
+ if (ret == nr_cpu_ids || ret == cpu) {
+ if (rq->nr_running)
+ return 1;
+ }
+ }
+ return 0;
+}
+#else
+static void nohz_idle_balance(int this_cpu, enum cpu_idle_type idle) { }
+#endif
+
+/*
+ * run_rebalance_domains is triggered when needed from the scheduler tick.
+ * Also triggered for nohz idle balancing (with nohz_balancing_kick set).
+ */
static void run_rebalance_domains(struct softirq_action *h)
{
int this_cpu = smp_processor_id();
@@ -3399,37 +3674,12 @@ static void run_rebalance_domains(struct softirq_action *h)
rebalance_domains(this_cpu, idle);
-#ifdef CONFIG_NO_HZ
/*
- * If this cpu is the owner for idle load balancing, then do the
+ * If this cpu has a pending nohz_balance_kick, then do the
* balancing on behalf of the other idle cpus whose ticks are
* stopped.
*/
- if (this_rq->idle_at_tick &&
- atomic_read(&nohz.load_balancer) == this_cpu) {
- struct rq *rq;
- int balance_cpu;
-
- for_each_cpu(balance_cpu, nohz.cpu_mask) {
- if (balance_cpu == this_cpu)
- continue;
-
- /*
- * If this cpu gets work to do, stop the load balancing
- * work being done for other cpus. Next load
- * balancing owner will pick it up.
- */
- if (need_resched())
- break;
-
- rebalance_domains(balance_cpu, CPU_IDLE);
-
- rq = cpu_rq(balance_cpu);
- if (time_after(this_rq->next_balance, rq->next_balance))
- this_rq->next_balance = rq->next_balance;
- }
- }
-#endif
+ nohz_idle_balance(this_cpu, idle);
}
static inline int on_null_domain(int cpu)
@@ -3439,57 +3689,17 @@ static inline int on_null_domain(int cpu)
/*
* Trigger the SCHED_SOFTIRQ if it is time to do periodic load balancing.
- *
- * In case of CONFIG_NO_HZ, this is the place where we nominate a new
- * idle load balancing owner or decide to stop the periodic load balancing,
- * if the whole system is idle.
*/
static inline void trigger_load_balance(struct rq *rq, int cpu)
{
-#ifdef CONFIG_NO_HZ
- /*
- * If we were in the nohz mode recently and busy at the current
- * scheduler tick, then check if we need to nominate new idle
- * load balancer.
- */
- if (rq->in_nohz_recently && !rq->idle_at_tick) {
- rq->in_nohz_recently = 0;
-
- if (atomic_read(&nohz.load_balancer) == cpu) {
- cpumask_clear_cpu(cpu, nohz.cpu_mask);
- atomic_set(&nohz.load_balancer, -1);
- }
-
- if (atomic_read(&nohz.load_balancer) == -1) {
- int ilb = find_new_ilb(cpu);
-
- if (ilb < nr_cpu_ids)
- resched_cpu(ilb);
- }
- }
-
- /*
- * If this cpu is idle and doing idle load balancing for all the
- * cpus with ticks stopped, is it time for that to stop?
- */
- if (rq->idle_at_tick && atomic_read(&nohz.load_balancer) == cpu &&
- cpumask_weight(nohz.cpu_mask) == num_online_cpus()) {
- resched_cpu(cpu);
- return;
- }
-
- /*
- * If this cpu is idle and the idle load balancing is done by
- * someone else, then no need raise the SCHED_SOFTIRQ
- */
- if (rq->idle_at_tick && atomic_read(&nohz.load_balancer) != cpu &&
- cpumask_test_cpu(cpu, nohz.cpu_mask))
- return;
-#endif
/* Don't need to rebalance while attached to NULL domain */
if (time_after_eq(jiffies, rq->next_balance) &&
likely(!on_null_domain(cpu)))
raise_softirq(SCHED_SOFTIRQ);
+#ifdef CONFIG_NO_HZ
+ else if (nohz_kick_needed(rq, cpu) && likely(!on_null_domain(cpu)))
+ nohz_balancer_kick(cpu);
+#endif
}
static void rq_online_fair(struct rq *rq)
diff --git a/kernel/sched_rt.c b/kernel/sched_rt.c
index 8afb953e31c..d10c80ebb67 100644
--- a/kernel/sched_rt.c
+++ b/kernel/sched_rt.c
@@ -1663,9 +1663,6 @@ static void watchdog(struct rq *rq, struct task_struct *p)
{
unsigned long soft, hard;
- if (!p->signal)
- return;
-
/* max may change after cur was read, this will be fixed next tick */
soft = task_rlimit(p, RLIMIT_RTTIME);
hard = task_rlimit_max(p, RLIMIT_RTTIME);
diff --git a/kernel/sched_stats.h b/kernel/sched_stats.h
index 32d2bd4061b..25c2f962f6f 100644
--- a/kernel/sched_stats.h
+++ b/kernel/sched_stats.h
@@ -295,13 +295,7 @@ sched_info_switch(struct task_struct *prev, struct task_struct *next)
static inline void account_group_user_time(struct task_struct *tsk,
cputime_t cputime)
{
- struct thread_group_cputimer *cputimer;
-
- /* tsk == current, ensure it is safe to use ->signal */
- if (unlikely(tsk->exit_state))
- return;
-
- cputimer = &tsk->signal->cputimer;
+ struct thread_group_cputimer *cputimer = &tsk->signal->cputimer;
if (!cputimer->running)
return;
@@ -325,13 +319,7 @@ static inline void account_group_user_time(struct task_struct *tsk,
static inline void account_group_system_time(struct task_struct *tsk,
cputime_t cputime)
{
- struct thread_group_cputimer *cputimer;
-
- /* tsk == current, ensure it is safe to use ->signal */
- if (unlikely(tsk->exit_state))
- return;
-
- cputimer = &tsk->signal->cputimer;
+ struct thread_group_cputimer *cputimer = &tsk->signal->cputimer;
if (!cputimer->running)
return;
@@ -355,16 +343,7 @@ static inline void account_group_system_time(struct task_struct *tsk,
static inline void account_group_exec_runtime(struct task_struct *tsk,
unsigned long long ns)
{
- struct thread_group_cputimer *cputimer;
- struct signal_struct *sig;
-
- sig = tsk->signal;
- /* see __exit_signal()->task_rq_unlock_wait() */
- barrier();
- if (unlikely(!sig))
- return;
-
- cputimer = &sig->cputimer;
+ struct thread_group_cputimer *cputimer = &tsk->signal->cputimer;
if (!cputimer->running)
return;
diff --git a/kernel/signal.c b/kernel/signal.c
index 906ae5a1779..bded6518778 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -637,7 +637,7 @@ static inline bool si_fromuser(const struct siginfo *info)
/*
* Bad permissions for sending the signal
- * - the caller must hold at least the RCU read lock
+ * - the caller must hold the RCU read lock
*/
static int check_kill_permission(int sig, struct siginfo *info,
struct task_struct *t)
@@ -1127,11 +1127,14 @@ struct sighand_struct *lock_task_sighand(struct task_struct *tsk, unsigned long
/*
* send signal info to all the members of a group
- * - the caller must hold the RCU read lock at least
*/
int group_send_sig_info(int sig, struct siginfo *info, struct task_struct *p)
{
- int ret = check_kill_permission(sig, info, p);
+ int ret;
+
+ rcu_read_lock();
+ ret = check_kill_permission(sig, info, p);
+ rcu_read_unlock();
if (!ret && sig)
ret = do_send_sig_info(sig, info, p, true);
diff --git a/kernel/slow-work-debugfs.c b/kernel/slow-work-debugfs.c
deleted file mode 100644
index e45c4364529..00000000000
--- a/kernel/slow-work-debugfs.c
+++ /dev/null
@@ -1,227 +0,0 @@
-/* Slow work debugging
- *
- * Copyright (C) 2009 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 Licence
- * as published by the Free Software Foundation; either version
- * 2 of the Licence, or (at your option) any later version.
- */
-
-#include <linux/module.h>
-#include <linux/slow-work.h>
-#include <linux/fs.h>
-#include <linux/time.h>
-#include <linux/seq_file.h>
-#include "slow-work.h"
-
-#define ITERATOR_SHIFT (BITS_PER_LONG - 4)
-#define ITERATOR_SELECTOR (0xfUL << ITERATOR_SHIFT)
-#define ITERATOR_COUNTER (~ITERATOR_SELECTOR)
-
-void slow_work_new_thread_desc(struct slow_work *work, struct seq_file *m)
-{
- seq_puts(m, "Slow-work: New thread");
-}
-
-/*
- * Render the time mark field on a work item into a 5-char time with units plus
- * a space
- */
-static void slow_work_print_mark(struct seq_file *m, struct slow_work *work)
-{
- struct timespec now, diff;
-
- now = CURRENT_TIME;
- diff = timespec_sub(now, work->mark);
-
- if (diff.tv_sec < 0)
- seq_puts(m, " -ve ");
- else if (diff.tv_sec == 0 && diff.tv_nsec < 1000)
- seq_printf(m, "%3luns ", diff.tv_nsec);
- else if (diff.tv_sec == 0 && diff.tv_nsec < 1000000)
- seq_printf(m, "%3luus ", diff.tv_nsec / 1000);
- else if (diff.tv_sec == 0 && diff.tv_nsec < 1000000000)
- seq_printf(m, "%3lums ", diff.tv_nsec / 1000000);
- else if (diff.tv_sec <= 1)
- seq_puts(m, " 1s ");
- else if (diff.tv_sec < 60)
- seq_printf(m, "%4lus ", diff.tv_sec);
- else if (diff.tv_sec < 60 * 60)
- seq_printf(m, "%4lum ", diff.tv_sec / 60);
- else if (diff.tv_sec < 60 * 60 * 24)
- seq_printf(m, "%4luh ", diff.tv_sec / 3600);
- else
- seq_puts(m, "exces ");
-}
-
-/*
- * Describe a slow work item for debugfs
- */
-static int slow_work_runqueue_show(struct seq_file *m, void *v)
-{
- struct slow_work *work;
- struct list_head *p = v;
- unsigned long id;
-
- switch ((unsigned long) v) {
- case 1:
- seq_puts(m, "THR PID ITEM ADDR FL MARK DESC\n");
- return 0;
- case 2:
- seq_puts(m, "=== ===== ================ == ===== ==========\n");
- return 0;
-
- case 3 ... 3 + SLOW_WORK_THREAD_LIMIT - 1:
- id = (unsigned long) v - 3;
-
- read_lock(&slow_work_execs_lock);
- work = slow_work_execs[id];
- if (work) {
- smp_read_barrier_depends();
-
- seq_printf(m, "%3lu %5d %16p %2lx ",
- id, slow_work_pids[id], work, work->flags);
- slow_work_print_mark(m, work);
-
- if (work->ops->desc)
- work->ops->desc(work, m);
- seq_putc(m, '\n');
- }
- read_unlock(&slow_work_execs_lock);
- return 0;
-
- default:
- work = list_entry(p, struct slow_work, link);
- seq_printf(m, "%3s - %16p %2lx ",
- work->flags & SLOW_WORK_VERY_SLOW ? "vsq" : "sq",
- work, work->flags);
- slow_work_print_mark(m, work);
-
- if (work->ops->desc)
- work->ops->desc(work, m);
- seq_putc(m, '\n');
- return 0;
- }
-}
-
-/*
- * map the iterator to a work item
- */
-static void *slow_work_runqueue_index(struct seq_file *m, loff_t *_pos)
-{
- struct list_head *p;
- unsigned long count, id;
-
- switch (*_pos >> ITERATOR_SHIFT) {
- case 0x0:
- if (*_pos == 0)
- *_pos = 1;
- if (*_pos < 3)
- return (void *)(unsigned long) *_pos;
- if (*_pos < 3 + SLOW_WORK_THREAD_LIMIT)
- for (id = *_pos - 3;
- id < SLOW_WORK_THREAD_LIMIT;
- id++, (*_pos)++)
- if (slow_work_execs[id])
- return (void *)(unsigned long) *_pos;
- *_pos = 0x1UL << ITERATOR_SHIFT;
-
- case 0x1:
- count = *_pos & ITERATOR_COUNTER;
- list_for_each(p, &slow_work_queue) {
- if (count == 0)
- return p;
- count--;
- }
- *_pos = 0x2UL << ITERATOR_SHIFT;
-
- case 0x2:
- count = *_pos & ITERATOR_COUNTER;
- list_for_each(p, &vslow_work_queue) {
- if (count == 0)
- return p;
- count--;
- }
- *_pos = 0x3UL << ITERATOR_SHIFT;
-
- default:
- return NULL;
- }
-}
-
-/*
- * set up the iterator to start reading from the first line
- */
-static void *slow_work_runqueue_start(struct seq_file *m, loff_t *_pos)
-{
- spin_lock_irq(&slow_work_queue_lock);
- return slow_work_runqueue_index(m, _pos);
-}
-
-/*
- * move to the next line
- */
-static void *slow_work_runqueue_next(struct seq_file *m, void *v, loff_t *_pos)
-{
- struct list_head *p = v;
- unsigned long selector = *_pos >> ITERATOR_SHIFT;
-
- (*_pos)++;
- switch (selector) {
- case 0x0:
- return slow_work_runqueue_index(m, _pos);
-
- case 0x1:
- if (*_pos >> ITERATOR_SHIFT == 0x1) {
- p = p->next;
- if (p != &slow_work_queue)
- return p;
- }
- *_pos = 0x2UL << ITERATOR_SHIFT;
- p = &vslow_work_queue;
-
- case 0x2:
- if (*_pos >> ITERATOR_SHIFT == 0x2) {
- p = p->next;
- if (p != &vslow_work_queue)
- return p;
- }
- *_pos = 0x3UL << ITERATOR_SHIFT;
-
- default:
- return NULL;
- }
-}
-
-/*
- * clean up after reading
- */
-static void slow_work_runqueue_stop(struct seq_file *m, void *v)
-{
- spin_unlock_irq(&slow_work_queue_lock);
-}
-
-static const struct seq_operations slow_work_runqueue_ops = {
- .start = slow_work_runqueue_start,
- .stop = slow_work_runqueue_stop,
- .next = slow_work_runqueue_next,
- .show = slow_work_runqueue_show,
-};
-
-/*
- * open "/sys/kernel/debug/slow_work/runqueue" to list queue contents
- */
-static int slow_work_runqueue_open(struct inode *inode, struct file *file)
-{
- return seq_open(file, &slow_work_runqueue_ops);
-}
-
-const struct file_operations slow_work_runqueue_fops = {
- .owner = THIS_MODULE,
- .open = slow_work_runqueue_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = seq_release,
-};
diff --git a/kernel/slow-work.c b/kernel/slow-work.c
deleted file mode 100644
index 7d3f4fa9ef4..00000000000
--- a/kernel/slow-work.c
+++ /dev/null
@@ -1,1068 +0,0 @@
-/* Worker thread pool for slow items, such as filesystem lookups or mkdirs
- *
- * Copyright (C) 2008 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 Licence
- * as published by the Free Software Foundation; either version
- * 2 of the Licence, or (at your option) any later version.
- *
- * See Documentation/slow-work.txt
- */
-
-#include <linux/module.h>
-#include <linux/slow-work.h>
-#include <linux/kthread.h>
-#include <linux/freezer.h>
-#include <linux/wait.h>
-#include <linux/debugfs.h>
-#include "slow-work.h"
-
-static void slow_work_cull_timeout(unsigned long);
-static void slow_work_oom_timeout(unsigned long);
-
-#ifdef CONFIG_SYSCTL
-static int slow_work_min_threads_sysctl(struct ctl_table *, int,
- void __user *, size_t *, loff_t *);
-
-static int slow_work_max_threads_sysctl(struct ctl_table *, int ,
- void __user *, size_t *, loff_t *);
-#endif
-
-/*
- * The pool of threads has at least min threads in it as long as someone is
- * using the facility, and may have as many as max.
- *
- * A portion of the pool may be processing very slow operations.
- */
-static unsigned slow_work_min_threads = 2;
-static unsigned slow_work_max_threads = 4;
-static unsigned vslow_work_proportion = 50; /* % of threads that may process
- * very slow work */
-
-#ifdef CONFIG_SYSCTL
-static const int slow_work_min_min_threads = 2;
-static int slow_work_max_max_threads = SLOW_WORK_THREAD_LIMIT;
-static const int slow_work_min_vslow = 1;
-static const int slow_work_max_vslow = 99;
-
-ctl_table slow_work_sysctls[] = {
- {
- .procname = "min-threads",
- .data = &slow_work_min_threads,
- .maxlen = sizeof(unsigned),
- .mode = 0644,
- .proc_handler = slow_work_min_threads_sysctl,
- .extra1 = (void *) &slow_work_min_min_threads,
- .extra2 = &slow_work_max_threads,
- },
- {
- .procname = "max-threads",
- .data = &slow_work_max_threads,
- .maxlen = sizeof(unsigned),
- .mode = 0644,
- .proc_handler = slow_work_max_threads_sysctl,
- .extra1 = &slow_work_min_threads,
- .extra2 = (void *) &slow_work_max_max_threads,
- },
- {
- .procname = "vslow-percentage",
- .data = &vslow_work_proportion,
- .maxlen = sizeof(unsigned),
- .mode = 0644,
- .proc_handler = proc_dointvec_minmax,
- .extra1 = (void *) &slow_work_min_vslow,
- .extra2 = (void *) &slow_work_max_vslow,
- },
- {}
-};
-#endif
-
-/*
- * The active state of the thread pool
- */
-static atomic_t slow_work_thread_count;
-static atomic_t vslow_work_executing_count;
-
-static bool slow_work_may_not_start_new_thread;
-static bool slow_work_cull; /* cull a thread due to lack of activity */
-static DEFINE_TIMER(slow_work_cull_timer, slow_work_cull_timeout, 0, 0);
-static DEFINE_TIMER(slow_work_oom_timer, slow_work_oom_timeout, 0, 0);
-static struct slow_work slow_work_new_thread; /* new thread starter */
-
-/*
- * slow work ID allocation (use slow_work_queue_lock)
- */
-static DECLARE_BITMAP(slow_work_ids, SLOW_WORK_THREAD_LIMIT);
-
-/*
- * Unregistration tracking to prevent put_ref() from disappearing during module
- * unload
- */
-#ifdef CONFIG_MODULES
-static struct module *slow_work_thread_processing[SLOW_WORK_THREAD_LIMIT];
-static struct module *slow_work_unreg_module;
-static struct slow_work *slow_work_unreg_work_item;
-static DECLARE_WAIT_QUEUE_HEAD(slow_work_unreg_wq);
-static DEFINE_MUTEX(slow_work_unreg_sync_lock);
-
-static void slow_work_set_thread_processing(int id, struct slow_work *work)
-{
- if (work)
- slow_work_thread_processing[id] = work->owner;
-}
-static void slow_work_done_thread_processing(int id, struct slow_work *work)
-{
- struct module *module = slow_work_thread_processing[id];
-
- slow_work_thread_processing[id] = NULL;
- smp_mb();
- if (slow_work_unreg_work_item == work ||
- slow_work_unreg_module == module)
- wake_up_all(&slow_work_unreg_wq);
-}
-static void slow_work_clear_thread_processing(int id)
-{
- slow_work_thread_processing[id] = NULL;
-}
-#else
-static void slow_work_set_thread_processing(int id, struct slow_work *work) {}
-static void slow_work_done_thread_processing(int id, struct slow_work *work) {}
-static void slow_work_clear_thread_processing(int id) {}
-#endif
-
-/*
- * Data for tracking currently executing items for indication through /proc
- */
-#ifdef CONFIG_SLOW_WORK_DEBUG
-struct slow_work *slow_work_execs[SLOW_WORK_THREAD_LIMIT];
-pid_t slow_work_pids[SLOW_WORK_THREAD_LIMIT];
-DEFINE_RWLOCK(slow_work_execs_lock);
-#endif
-
-/*
- * The queues of work items and the lock governing access to them. These are
- * shared between all the CPUs. It doesn't make sense to have per-CPU queues
- * as the number of threads bears no relation to the number of CPUs.
- *
- * There are two queues of work items: one for slow work items, and one for
- * very slow work items.
- */
-LIST_HEAD(slow_work_queue);
-LIST_HEAD(vslow_work_queue);
-DEFINE_SPINLOCK(slow_work_queue_lock);
-
-/*
- * The following are two wait queues that get pinged when a work item is placed
- * on an empty queue. These allow work items that are hogging a thread by
- * sleeping in a way that could be deferred to yield their thread and enqueue
- * themselves.
- */
-static DECLARE_WAIT_QUEUE_HEAD(slow_work_queue_waits_for_occupation);
-static DECLARE_WAIT_QUEUE_HEAD(vslow_work_queue_waits_for_occupation);
-
-/*
- * The thread controls. A variable used to signal to the threads that they
- * should exit when the queue is empty, a waitqueue used by the threads to wait
- * for signals, and a completion set by the last thread to exit.
- */
-static bool slow_work_threads_should_exit;
-static DECLARE_WAIT_QUEUE_HEAD(slow_work_thread_wq);
-static DECLARE_COMPLETION(slow_work_last_thread_exited);
-
-/*
- * The number of users of the thread pool and its lock. Whilst this is zero we
- * have no threads hanging around, and when this reaches zero, we wait for all
- * active or queued work items to complete and kill all the threads we do have.
- */
-static int slow_work_user_count;
-static DEFINE_MUTEX(slow_work_user_lock);
-
-static inline int slow_work_get_ref(struct slow_work *work)
-{
- if (work->ops->get_ref)
- return work->ops->get_ref(work);
-
- return 0;
-}
-
-static inline void slow_work_put_ref(struct slow_work *work)
-{
- if (work->ops->put_ref)
- work->ops->put_ref(work);
-}
-
-/*
- * Calculate the maximum number of active threads in the pool that are
- * permitted to process very slow work items.
- *
- * The answer is rounded up to at least 1, but may not equal or exceed the
- * maximum number of the threads in the pool. This means we always have at
- * least one thread that can process slow work items, and we always have at
- * least one thread that won't get tied up doing so.
- */
-static unsigned slow_work_calc_vsmax(void)
-{
- unsigned vsmax;
-
- vsmax = atomic_read(&slow_work_thread_count) * vslow_work_proportion;
- vsmax /= 100;
- vsmax = max(vsmax, 1U);
- return min(vsmax, slow_work_max_threads - 1);
-}
-
-/*
- * Attempt to execute stuff queued on a slow thread. Return true if we managed
- * it, false if there was nothing to do.
- */
-static noinline bool slow_work_execute(int id)
-{
- struct slow_work *work = NULL;
- unsigned vsmax;
- bool very_slow;
-
- vsmax = slow_work_calc_vsmax();
-
- /* see if we can schedule a new thread to be started if we're not
- * keeping up with the work */
- if (!waitqueue_active(&slow_work_thread_wq) &&
- (!list_empty(&slow_work_queue) || !list_empty(&vslow_work_queue)) &&
- atomic_read(&slow_work_thread_count) < slow_work_max_threads &&
- !slow_work_may_not_start_new_thread)
- slow_work_enqueue(&slow_work_new_thread);
-
- /* find something to execute */
- spin_lock_irq(&slow_work_queue_lock);
- if (!list_empty(&vslow_work_queue) &&
- atomic_read(&vslow_work_executing_count) < vsmax) {
- work = list_entry(vslow_work_queue.next,
- struct slow_work, link);
- if (test_and_set_bit_lock(SLOW_WORK_EXECUTING, &work->flags))
- BUG();
- list_del_init(&work->link);
- atomic_inc(&vslow_work_executing_count);
- very_slow = true;
- } else if (!list_empty(&slow_work_queue)) {
- work = list_entry(slow_work_queue.next,
- struct slow_work, link);
- if (test_and_set_bit_lock(SLOW_WORK_EXECUTING, &work->flags))
- BUG();
- list_del_init(&work->link);
- very_slow = false;
- } else {
- very_slow = false; /* avoid the compiler warning */
- }
-
- slow_work_set_thread_processing(id, work);
- if (work) {
- slow_work_mark_time(work);
- slow_work_begin_exec(id, work);
- }
-
- spin_unlock_irq(&slow_work_queue_lock);
-
- if (!work)
- return false;
-
- if (!test_and_clear_bit(SLOW_WORK_PENDING, &work->flags))
- BUG();
-
- /* don't execute if the work is in the process of being cancelled */
- if (!test_bit(SLOW_WORK_CANCELLING, &work->flags))
- work->ops->execute(work);
-
- if (very_slow)
- atomic_dec(&vslow_work_executing_count);
- clear_bit_unlock(SLOW_WORK_EXECUTING, &work->flags);
-
- /* wake up anyone waiting for this work to be complete */
- wake_up_bit(&work->flags, SLOW_WORK_EXECUTING);
-
- slow_work_end_exec(id, work);
-
- /* if someone tried to enqueue the item whilst we were executing it,
- * then it'll be left unenqueued to avoid multiple threads trying to
- * execute it simultaneously
- *
- * there is, however, a race between us testing the pending flag and
- * getting the spinlock, and between the enqueuer setting the pending
- * flag and getting the spinlock, so we use a deferral bit to tell us
- * if the enqueuer got there first
- */
- if (test_bit(SLOW_WORK_PENDING, &work->flags)) {
- spin_lock_irq(&slow_work_queue_lock);
-
- if (!test_bit(SLOW_WORK_EXECUTING, &work->flags) &&
- test_and_clear_bit(SLOW_WORK_ENQ_DEFERRED, &work->flags))
- goto auto_requeue;
-
- spin_unlock_irq(&slow_work_queue_lock);
- }
-
- /* sort out the race between module unloading and put_ref() */
- slow_work_put_ref(work);
- slow_work_done_thread_processing(id, work);
-
- return true;
-
-auto_requeue:
- /* we must complete the enqueue operation
- * - we transfer our ref on the item back to the appropriate queue
- * - don't wake another thread up as we're awake already
- */
- slow_work_mark_time(work);
- if (test_bit(SLOW_WORK_VERY_SLOW, &work->flags))
- list_add_tail(&work->link, &vslow_work_queue);
- else
- list_add_tail(&work->link, &slow_work_queue);
- spin_unlock_irq(&slow_work_queue_lock);
- slow_work_clear_thread_processing(id);
- return true;
-}
-
-/**
- * slow_work_sleep_till_thread_needed - Sleep till thread needed by other work
- * work: The work item under execution that wants to sleep
- * _timeout: Scheduler sleep timeout
- *
- * Allow a requeueable work item to sleep on a slow-work processor thread until
- * that thread is needed to do some other work or the sleep is interrupted by
- * some other event.
- *
- * The caller must set up a wake up event before calling this and must have set
- * the appropriate sleep mode (such as TASK_UNINTERRUPTIBLE) and tested its own
- * condition before calling this function as no test is made here.
- *
- * False is returned if there is nothing on the queue; true is returned if the
- * work item should be requeued
- */
-bool slow_work_sleep_till_thread_needed(struct slow_work *work,
- signed long *_timeout)
-{
- wait_queue_head_t *wfo_wq;
- struct list_head *queue;
-
- DEFINE_WAIT(wait);
-
- if (test_bit(SLOW_WORK_VERY_SLOW, &work->flags)) {
- wfo_wq = &vslow_work_queue_waits_for_occupation;
- queue = &vslow_work_queue;
- } else {
- wfo_wq = &slow_work_queue_waits_for_occupation;
- queue = &slow_work_queue;
- }
-
- if (!list_empty(queue))
- return true;
-
- add_wait_queue_exclusive(wfo_wq, &wait);
- if (list_empty(queue))
- *_timeout = schedule_timeout(*_timeout);
- finish_wait(wfo_wq, &wait);
-
- return !list_empty(queue);
-}
-EXPORT_SYMBOL(slow_work_sleep_till_thread_needed);
-
-/**
- * slow_work_enqueue - Schedule a slow work item for processing
- * @work: The work item to queue
- *
- * Schedule a slow work item for processing. If the item is already undergoing
- * execution, this guarantees not to re-enter the execution routine until the
- * first execution finishes.
- *
- * The item is pinned by this function as it retains a reference to it, managed
- * through the item operations. The item is unpinned once it has been
- * executed.
- *
- * An item may hog the thread that is running it for a relatively large amount
- * of time, sufficient, for example, to perform several lookup, mkdir, create
- * and setxattr operations. It may sleep on I/O and may sleep to obtain locks.
- *
- * Conversely, if a number of items are awaiting processing, it may take some
- * time before any given item is given attention. The number of threads in the
- * pool may be increased to deal with demand, but only up to a limit.
- *
- * If SLOW_WORK_VERY_SLOW is set on the work item, then it will be placed in
- * the very slow queue, from which only a portion of the threads will be
- * allowed to pick items to execute. This ensures that very slow items won't
- * overly block ones that are just ordinarily slow.
- *
- * Returns 0 if successful, -EAGAIN if not (or -ECANCELED if cancelled work is
- * attempted queued)
- */
-int slow_work_enqueue(struct slow_work *work)
-{
- wait_queue_head_t *wfo_wq;
- struct list_head *queue;
- unsigned long flags;
- int ret;
-
- if (test_bit(SLOW_WORK_CANCELLING, &work->flags))
- return -ECANCELED;
-
- BUG_ON(slow_work_user_count <= 0);
- BUG_ON(!work);
- BUG_ON(!work->ops);
-
- /* when honouring an enqueue request, we only promise that we will run
- * the work function in the future; we do not promise to run it once
- * per enqueue request
- *
- * we use the PENDING bit to merge together repeat requests without
- * having to disable IRQs and take the spinlock, whilst still
- * maintaining our promise
- */
- if (!test_and_set_bit_lock(SLOW_WORK_PENDING, &work->flags)) {
- if (test_bit(SLOW_WORK_VERY_SLOW, &work->flags)) {
- wfo_wq = &vslow_work_queue_waits_for_occupation;
- queue = &vslow_work_queue;
- } else {
- wfo_wq = &slow_work_queue_waits_for_occupation;
- queue = &slow_work_queue;
- }
-
- spin_lock_irqsave(&slow_work_queue_lock, flags);
-
- if (unlikely(test_bit(SLOW_WORK_CANCELLING, &work->flags)))
- goto cancelled;
-
- /* we promise that we will not attempt to execute the work
- * function in more than one thread simultaneously
- *
- * this, however, leaves us with a problem if we're asked to
- * enqueue the work whilst someone is executing the work
- * function as simply queueing the work immediately means that
- * another thread may try executing it whilst it is already
- * under execution
- *
- * to deal with this, we set the ENQ_DEFERRED bit instead of
- * enqueueing, and the thread currently executing the work
- * function will enqueue the work item when the work function
- * returns and it has cleared the EXECUTING bit
- */
- if (test_bit(SLOW_WORK_EXECUTING, &work->flags)) {
- set_bit(SLOW_WORK_ENQ_DEFERRED, &work->flags);
- } else {
- ret = slow_work_get_ref(work);
- if (ret < 0)
- goto failed;
- slow_work_mark_time(work);
- list_add_tail(&work->link, queue);
- wake_up(&slow_work_thread_wq);
-
- /* if someone who could be requeued is sleeping on a
- * thread, then ask them to yield their thread */
- if (work->link.prev == queue)
- wake_up(wfo_wq);
- }
-
- spin_unlock_irqrestore(&slow_work_queue_lock, flags);
- }
- return 0;
-
-cancelled:
- ret = -ECANCELED;
-failed:
- spin_unlock_irqrestore(&slow_work_queue_lock, flags);
- return ret;
-}
-EXPORT_SYMBOL(slow_work_enqueue);
-
-static int slow_work_wait(void *word)
-{
- schedule();
- return 0;
-}
-
-/**
- * slow_work_cancel - Cancel a slow work item
- * @work: The work item to cancel
- *
- * This function will cancel a previously enqueued work item. If we cannot
- * cancel the work item, it is guarenteed to have run when this function
- * returns.
- */
-void slow_work_cancel(struct slow_work *work)
-{
- bool wait = true, put = false;
-
- set_bit(SLOW_WORK_CANCELLING, &work->flags);
- smp_mb();
-
- /* if the work item is a delayed work item with an active timer, we
- * need to wait for the timer to finish _before_ getting the spinlock,
- * lest we deadlock against the timer routine
- *
- * the timer routine will leave DELAYED set if it notices the
- * CANCELLING flag in time
- */
- if (test_bit(SLOW_WORK_DELAYED, &work->flags)) {
- struct delayed_slow_work *dwork =
- container_of(work, struct delayed_slow_work, work);
- del_timer_sync(&dwork->timer);
- }
-
- spin_lock_irq(&slow_work_queue_lock);
-
- if (test_bit(SLOW_WORK_DELAYED, &work->flags)) {
- /* the timer routine aborted or never happened, so we are left
- * holding the timer's reference on the item and should just
- * drop the pending flag and wait for any ongoing execution to
- * finish */
- struct delayed_slow_work *dwork =
- container_of(work, struct delayed_slow_work, work);
-
- BUG_ON(timer_pending(&dwork->timer));
- BUG_ON(!list_empty(&work->link));
-
- clear_bit(SLOW_WORK_DELAYED, &work->flags);
- put = true;
- clear_bit(SLOW_WORK_PENDING, &work->flags);
-
- } else if (test_bit(SLOW_WORK_PENDING, &work->flags) &&
- !list_empty(&work->link)) {
- /* the link in the pending queue holds a reference on the item
- * that we will need to release */
- list_del_init(&work->link);
- wait = false;
- put = true;
- clear_bit(SLOW_WORK_PENDING, &work->flags);
-
- } else if (test_and_clear_bit(SLOW_WORK_ENQ_DEFERRED, &work->flags)) {
- /* the executor is holding our only reference on the item, so
- * we merely need to wait for it to finish executing */
- clear_bit(SLOW_WORK_PENDING, &work->flags);
- }
-
- spin_unlock_irq(&slow_work_queue_lock);
-
- /* the EXECUTING flag is set by the executor whilst the spinlock is set
- * and before the item is dequeued - so assuming the above doesn't
- * actually dequeue it, simply waiting for the EXECUTING flag to be
- * released here should be sufficient */
- if (wait)
- wait_on_bit(&work->flags, SLOW_WORK_EXECUTING, slow_work_wait,
- TASK_UNINTERRUPTIBLE);
-
- clear_bit(SLOW_WORK_CANCELLING, &work->flags);
- if (put)
- slow_work_put_ref(work);
-}
-EXPORT_SYMBOL(slow_work_cancel);
-
-/*
- * Handle expiry of the delay timer, indicating that a delayed slow work item
- * should now be queued if not cancelled
- */
-static void delayed_slow_work_timer(unsigned long data)
-{
- wait_queue_head_t *wfo_wq;
- struct list_head *queue;
- struct slow_work *work = (struct slow_work *) data;
- unsigned long flags;
- bool queued = false, put = false, first = false;
-
- if (test_bit(SLOW_WORK_VERY_SLOW, &work->flags)) {
- wfo_wq = &vslow_work_queue_waits_for_occupation;
- queue = &vslow_work_queue;
- } else {
- wfo_wq = &slow_work_queue_waits_for_occupation;
- queue = &slow_work_queue;
- }
-
- spin_lock_irqsave(&slow_work_queue_lock, flags);
- if (likely(!test_bit(SLOW_WORK_CANCELLING, &work->flags))) {
- clear_bit(SLOW_WORK_DELAYED, &work->flags);
-
- if (test_bit(SLOW_WORK_EXECUTING, &work->flags)) {
- /* we discard the reference the timer was holding in
- * favour of the one the executor holds */
- set_bit(SLOW_WORK_ENQ_DEFERRED, &work->flags);
- put = true;
- } else {
- slow_work_mark_time(work);
- list_add_tail(&work->link, queue);
- queued = true;
- if (work->link.prev == queue)
- first = true;
- }
- }
-
- spin_unlock_irqrestore(&slow_work_queue_lock, flags);
- if (put)
- slow_work_put_ref(work);
- if (first)
- wake_up(wfo_wq);
- if (queued)
- wake_up(&slow_work_thread_wq);
-}
-
-/**
- * delayed_slow_work_enqueue - Schedule a delayed slow work item for processing
- * @dwork: The delayed work item to queue
- * @delay: When to start executing the work, in jiffies from now
- *
- * This is similar to slow_work_enqueue(), but it adds a delay before the work
- * is actually queued for processing.
- *
- * The item can have delayed processing requested on it whilst it is being
- * executed. The delay will begin immediately, and if it expires before the
- * item finishes executing, the item will be placed back on the queue when it
- * has done executing.
- */
-int delayed_slow_work_enqueue(struct delayed_slow_work *dwork,
- unsigned long delay)
-{
- struct slow_work *work = &dwork->work;
- unsigned long flags;
- int ret;
-
- if (delay == 0)
- return slow_work_enqueue(&dwork->work);
-
- BUG_ON(slow_work_user_count <= 0);
- BUG_ON(!work);
- BUG_ON(!work->ops);
-
- if (test_bit(SLOW_WORK_CANCELLING, &work->flags))
- return -ECANCELED;
-
- if (!test_and_set_bit_lock(SLOW_WORK_PENDING, &work->flags)) {
- spin_lock_irqsave(&slow_work_queue_lock, flags);
-
- if (test_bit(SLOW_WORK_CANCELLING, &work->flags))
- goto cancelled;
-
- /* the timer holds a reference whilst it is pending */
- ret = slow_work_get_ref(work);
- if (ret < 0)
- goto cant_get_ref;
-
- if (test_and_set_bit(SLOW_WORK_DELAYED, &work->flags))
- BUG();
- dwork->timer.expires = jiffies + delay;
- dwork->timer.data = (unsigned long) work;
- dwork->timer.function = delayed_slow_work_timer;
- add_timer(&dwork->timer);
-
- spin_unlock_irqrestore(&slow_work_queue_lock, flags);
- }
-
- return 0;
-
-cancelled:
- ret = -ECANCELED;
-cant_get_ref:
- spin_unlock_irqrestore(&slow_work_queue_lock, flags);
- return ret;
-}
-EXPORT_SYMBOL(delayed_slow_work_enqueue);
-
-/*
- * Schedule a cull of the thread pool at some time in the near future
- */
-static void slow_work_schedule_cull(void)
-{
- mod_timer(&slow_work_cull_timer,
- round_jiffies(jiffies + SLOW_WORK_CULL_TIMEOUT));
-}
-
-/*
- * Worker thread culling algorithm
- */
-static bool slow_work_cull_thread(void)
-{
- unsigned long flags;
- bool do_cull = false;
-
- spin_lock_irqsave(&slow_work_queue_lock, flags);
-
- if (slow_work_cull) {
- slow_work_cull = false;
-
- if (list_empty(&slow_work_queue) &&
- list_empty(&vslow_work_queue) &&
- atomic_read(&slow_work_thread_count) >
- slow_work_min_threads) {
- slow_work_schedule_cull();
- do_cull = true;
- }
- }
-
- spin_unlock_irqrestore(&slow_work_queue_lock, flags);
- return do_cull;
-}
-
-/*
- * Determine if there is slow work available for dispatch
- */
-static inline bool slow_work_available(int vsmax)
-{
- return !list_empty(&slow_work_queue) ||
- (!list_empty(&vslow_work_queue) &&
- atomic_read(&vslow_work_executing_count) < vsmax);
-}
-
-/*
- * Worker thread dispatcher
- */
-static int slow_work_thread(void *_data)
-{
- int vsmax, id;
-
- DEFINE_WAIT(wait);
-
- set_freezable();
- set_user_nice(current, -5);
-
- /* allocate ourselves an ID */
- spin_lock_irq(&slow_work_queue_lock);
- id = find_first_zero_bit(slow_work_ids, SLOW_WORK_THREAD_LIMIT);
- BUG_ON(id < 0 || id >= SLOW_WORK_THREAD_LIMIT);
- __set_bit(id, slow_work_ids);
- slow_work_set_thread_pid(id, current->pid);
- spin_unlock_irq(&slow_work_queue_lock);
-
- sprintf(current->comm, "kslowd%03u", id);
-
- for (;;) {
- vsmax = vslow_work_proportion;
- vsmax *= atomic_read(&slow_work_thread_count);
- vsmax /= 100;
-
- prepare_to_wait_exclusive(&slow_work_thread_wq, &wait,
- TASK_INTERRUPTIBLE);
- if (!freezing(current) &&
- !slow_work_threads_should_exit &&
- !slow_work_available(vsmax) &&
- !slow_work_cull)
- schedule();
- finish_wait(&slow_work_thread_wq, &wait);
-
- try_to_freeze();
-
- vsmax = vslow_work_proportion;
- vsmax *= atomic_read(&slow_work_thread_count);
- vsmax /= 100;
-
- if (slow_work_available(vsmax) && slow_work_execute(id)) {
- cond_resched();
- if (list_empty(&slow_work_queue) &&
- list_empty(&vslow_work_queue) &&
- atomic_read(&slow_work_thread_count) >
- slow_work_min_threads)
- slow_work_schedule_cull();
- continue;
- }
-
- if (slow_work_threads_should_exit)
- break;
-
- if (slow_work_cull && slow_work_cull_thread())
- break;
- }
-
- spin_lock_irq(&slow_work_queue_lock);
- slow_work_set_thread_pid(id, 0);
- __clear_bit(id, slow_work_ids);
- spin_unlock_irq(&slow_work_queue_lock);
-
- if (atomic_dec_and_test(&slow_work_thread_count))
- complete_and_exit(&slow_work_last_thread_exited, 0);
- return 0;
-}
-
-/*
- * Handle thread cull timer expiration
- */
-static void slow_work_cull_timeout(unsigned long data)
-{
- slow_work_cull = true;
- wake_up(&slow_work_thread_wq);
-}
-
-/*
- * Start a new slow work thread
- */
-static void slow_work_new_thread_execute(struct slow_work *work)
-{
- struct task_struct *p;
-
- if (slow_work_threads_should_exit)
- return;
-
- if (atomic_read(&slow_work_thread_count) >= slow_work_max_threads)
- return;
-
- if (!mutex_trylock(&slow_work_user_lock))
- return;
-
- slow_work_may_not_start_new_thread = true;
- atomic_inc(&slow_work_thread_count);
- p = kthread_run(slow_work_thread, NULL, "kslowd");
- if (IS_ERR(p)) {
- printk(KERN_DEBUG "Slow work thread pool: OOM\n");
- if (atomic_dec_and_test(&slow_work_thread_count))
- BUG(); /* we're running on a slow work thread... */
- mod_timer(&slow_work_oom_timer,
- round_jiffies(jiffies + SLOW_WORK_OOM_TIMEOUT));
- } else {
- /* ratelimit the starting of new threads */
- mod_timer(&slow_work_oom_timer, jiffies + 1);
- }
-
- mutex_unlock(&slow_work_user_lock);
-}
-
-static const struct slow_work_ops slow_work_new_thread_ops = {
- .owner = THIS_MODULE,
- .execute = slow_work_new_thread_execute,
-#ifdef CONFIG_SLOW_WORK_DEBUG
- .desc = slow_work_new_thread_desc,
-#endif
-};
-
-/*
- * post-OOM new thread start suppression expiration
- */
-static void slow_work_oom_timeout(unsigned long data)
-{
- slow_work_may_not_start_new_thread = false;
-}
-
-#ifdef CONFIG_SYSCTL
-/*
- * Handle adjustment of the minimum number of threads
- */
-static int slow_work_min_threads_sysctl(struct ctl_table *table, int write,
- void __user *buffer,
- size_t *lenp, loff_t *ppos)
-{
- int ret = proc_dointvec_minmax(table, write, buffer, lenp, ppos);
- int n;
-
- if (ret == 0) {
- mutex_lock(&slow_work_user_lock);
- if (slow_work_user_count > 0) {
- /* see if we need to start or stop threads */
- n = atomic_read(&slow_work_thread_count) -
- slow_work_min_threads;
-
- if (n < 0 && !slow_work_may_not_start_new_thread)
- slow_work_enqueue(&slow_work_new_thread);
- else if (n > 0)
- slow_work_schedule_cull();
- }
- mutex_unlock(&slow_work_user_lock);
- }
-
- return ret;
-}
-
-/*
- * Handle adjustment of the maximum number of threads
- */
-static int slow_work_max_threads_sysctl(struct ctl_table *table, int write,
- void __user *buffer,
- size_t *lenp, loff_t *ppos)
-{
- int ret = proc_dointvec_minmax(table, write, buffer, lenp, ppos);
- int n;
-
- if (ret == 0) {
- mutex_lock(&slow_work_user_lock);
- if (slow_work_user_count > 0) {
- /* see if we need to stop threads */
- n = slow_work_max_threads -
- atomic_read(&slow_work_thread_count);
-
- if (n < 0)
- slow_work_schedule_cull();
- }
- mutex_unlock(&slow_work_user_lock);
- }
-
- return ret;
-}
-#endif /* CONFIG_SYSCTL */
-
-/**
- * slow_work_register_user - Register a user of the facility
- * @module: The module about to make use of the facility
- *
- * Register a user of the facility, starting up the initial threads if there
- * aren't any other users at this point. This will return 0 if successful, or
- * an error if not.
- */
-int slow_work_register_user(struct module *module)
-{
- struct task_struct *p;
- int loop;
-
- mutex_lock(&slow_work_user_lock);
-
- if (slow_work_user_count == 0) {
- printk(KERN_NOTICE "Slow work thread pool: Starting up\n");
- init_completion(&slow_work_last_thread_exited);
-
- slow_work_threads_should_exit = false;
- slow_work_init(&slow_work_new_thread,
- &slow_work_new_thread_ops);
- slow_work_may_not_start_new_thread = false;
- slow_work_cull = false;
-
- /* start the minimum number of threads */
- for (loop = 0; loop < slow_work_min_threads; loop++) {
- atomic_inc(&slow_work_thread_count);
- p = kthread_run(slow_work_thread, NULL, "kslowd");
- if (IS_ERR(p))
- goto error;
- }
- printk(KERN_NOTICE "Slow work thread pool: Ready\n");
- }
-
- slow_work_user_count++;
- mutex_unlock(&slow_work_user_lock);
- return 0;
-
-error:
- if (atomic_dec_and_test(&slow_work_thread_count))
- complete(&slow_work_last_thread_exited);
- if (loop > 0) {
- printk(KERN_ERR "Slow work thread pool:"
- " Aborting startup on ENOMEM\n");
- slow_work_threads_should_exit = true;
- wake_up_all(&slow_work_thread_wq);
- wait_for_completion(&slow_work_last_thread_exited);
- printk(KERN_ERR "Slow work thread pool: Aborted\n");
- }
- mutex_unlock(&slow_work_user_lock);
- return PTR_ERR(p);
-}
-EXPORT_SYMBOL(slow_work_register_user);
-
-/*
- * wait for all outstanding items from the calling module to complete
- * - note that more items may be queued whilst we're waiting
- */
-static void slow_work_wait_for_items(struct module *module)
-{
-#ifdef CONFIG_MODULES
- DECLARE_WAITQUEUE(myself, current);
- struct slow_work *work;
- int loop;
-
- mutex_lock(&slow_work_unreg_sync_lock);
- add_wait_queue(&slow_work_unreg_wq, &myself);
-
- for (;;) {
- spin_lock_irq(&slow_work_queue_lock);
-
- /* first of all, we wait for the last queued item in each list
- * to be processed */
- list_for_each_entry_reverse(work, &vslow_work_queue, link) {
- if (work->owner == module) {
- set_current_state(TASK_UNINTERRUPTIBLE);
- slow_work_unreg_work_item = work;
- goto do_wait;
- }
- }
- list_for_each_entry_reverse(work, &slow_work_queue, link) {
- if (work->owner == module) {
- set_current_state(TASK_UNINTERRUPTIBLE);
- slow_work_unreg_work_item = work;
- goto do_wait;
- }
- }
-
- /* then we wait for the items being processed to finish */
- slow_work_unreg_module = module;
- smp_mb();
- for (loop = 0; loop < SLOW_WORK_THREAD_LIMIT; loop++) {
- if (slow_work_thread_processing[loop] == module)
- goto do_wait;
- }
- spin_unlock_irq(&slow_work_queue_lock);
- break; /* okay, we're done */
-
- do_wait:
- spin_unlock_irq(&slow_work_queue_lock);
- schedule();
- slow_work_unreg_work_item = NULL;
- slow_work_unreg_module = NULL;
- }
-
- remove_wait_queue(&slow_work_unreg_wq, &myself);
- mutex_unlock(&slow_work_unreg_sync_lock);
-#endif /* CONFIG_MODULES */
-}
-
-/**
- * slow_work_unregister_user - Unregister a user of the facility
- * @module: The module whose items should be cleared
- *
- * Unregister a user of the facility, killing all the threads if this was the
- * last one.
- *
- * This waits for all the work items belonging to the nominated module to go
- * away before proceeding.
- */
-void slow_work_unregister_user(struct module *module)
-{
- /* first of all, wait for all outstanding items from the calling module
- * to complete */
- if (module)
- slow_work_wait_for_items(module);
-
- /* then we can actually go about shutting down the facility if need
- * be */
- mutex_lock(&slow_work_user_lock);
-
- BUG_ON(slow_work_user_count <= 0);
-
- slow_work_user_count--;
- if (slow_work_user_count == 0) {
- printk(KERN_NOTICE "Slow work thread pool: Shutting down\n");
- slow_work_threads_should_exit = true;
- del_timer_sync(&slow_work_cull_timer);
- del_timer_sync(&slow_work_oom_timer);
- wake_up_all(&slow_work_thread_wq);
- wait_for_completion(&slow_work_last_thread_exited);
- printk(KERN_NOTICE "Slow work thread pool:"
- " Shut down complete\n");
- }
-
- mutex_unlock(&slow_work_user_lock);
-}
-EXPORT_SYMBOL(slow_work_unregister_user);
-
-/*
- * Initialise the slow work facility
- */
-static int __init init_slow_work(void)
-{
- unsigned nr_cpus = num_possible_cpus();
-
- if (slow_work_max_threads < nr_cpus)
- slow_work_max_threads = nr_cpus;
-#ifdef CONFIG_SYSCTL
- if (slow_work_max_max_threads < nr_cpus * 2)
- slow_work_max_max_threads = nr_cpus * 2;
-#endif
-#ifdef CONFIG_SLOW_WORK_DEBUG
- {
- struct dentry *dbdir;
-
- dbdir = debugfs_create_dir("slow_work", NULL);
- if (dbdir && !IS_ERR(dbdir))
- debugfs_create_file("runqueue", S_IFREG | 0400, dbdir,
- NULL, &slow_work_runqueue_fops);
- }
-#endif
- return 0;
-}
-
-subsys_initcall(init_slow_work);
diff --git a/kernel/slow-work.h b/kernel/slow-work.h
deleted file mode 100644
index a29ebd1ef41..00000000000
--- a/kernel/slow-work.h
+++ /dev/null
@@ -1,72 +0,0 @@
-/* Slow work private definitions
- *
- * Copyright (C) 2009 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 Licence
- * as published by the Free Software Foundation; either version
- * 2 of the Licence, or (at your option) any later version.
- */
-
-#define SLOW_WORK_CULL_TIMEOUT (5 * HZ) /* cull threads 5s after running out of
- * things to do */
-#define SLOW_WORK_OOM_TIMEOUT (5 * HZ) /* can't start new threads for 5s after
- * OOM */
-
-#define SLOW_WORK_THREAD_LIMIT 255 /* abs maximum number of slow-work threads */
-
-/*
- * slow-work.c
- */
-#ifdef CONFIG_SLOW_WORK_DEBUG
-extern struct slow_work *slow_work_execs[];
-extern pid_t slow_work_pids[];
-extern rwlock_t slow_work_execs_lock;
-#endif
-
-extern struct list_head slow_work_queue;
-extern struct list_head vslow_work_queue;
-extern spinlock_t slow_work_queue_lock;
-
-/*
- * slow-work-debugfs.c
- */
-#ifdef CONFIG_SLOW_WORK_DEBUG
-extern const struct file_operations slow_work_runqueue_fops;
-
-extern void slow_work_new_thread_desc(struct slow_work *, struct seq_file *);
-#endif
-
-/*
- * Helper functions
- */
-static inline void slow_work_set_thread_pid(int id, pid_t pid)
-{
-#ifdef CONFIG_SLOW_WORK_DEBUG
- slow_work_pids[id] = pid;
-#endif
-}
-
-static inline void slow_work_mark_time(struct slow_work *work)
-{
-#ifdef CONFIG_SLOW_WORK_DEBUG
- work->mark = CURRENT_TIME;
-#endif
-}
-
-static inline void slow_work_begin_exec(int id, struct slow_work *work)
-{
-#ifdef CONFIG_SLOW_WORK_DEBUG
- slow_work_execs[id] = work;
-#endif
-}
-
-static inline void slow_work_end_exec(int id, struct slow_work *work)
-{
-#ifdef CONFIG_SLOW_WORK_DEBUG
- write_lock(&slow_work_execs_lock);
- slow_work_execs[id] = NULL;
- write_unlock(&slow_work_execs_lock);
-#endif
-}
diff --git a/kernel/softlockup.c b/kernel/softlockup.c
deleted file mode 100644
index 4b493f67dcb..00000000000
--- a/kernel/softlockup.c
+++ /dev/null
@@ -1,293 +0,0 @@
-/*
- * Detect Soft Lockups
- *
- * started by Ingo Molnar, Copyright (C) 2005, 2006 Red Hat, Inc.
- *
- * this code detects soft lockups: incidents in where on a CPU
- * the kernel does not reschedule for 10 seconds or more.
- */
-#include <linux/mm.h>
-#include <linux/cpu.h>
-#include <linux/nmi.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/freezer.h>
-#include <linux/kthread.h>
-#include <linux/lockdep.h>
-#include <linux/notifier.h>
-#include <linux/module.h>
-#include <linux/sysctl.h>
-
-#include <asm/irq_regs.h>
-
-static DEFINE_SPINLOCK(print_lock);
-
-static DEFINE_PER_CPU(unsigned long, softlockup_touch_ts); /* touch timestamp */
-static DEFINE_PER_CPU(unsigned long, softlockup_print_ts); /* print timestamp */
-static DEFINE_PER_CPU(struct task_struct *, softlockup_watchdog);
-static DEFINE_PER_CPU(bool, softlock_touch_sync);
-
-static int __read_mostly did_panic;
-int __read_mostly softlockup_thresh = 60;
-
-/*
- * Should we panic (and reboot, if panic_timeout= is set) when a
- * soft-lockup occurs:
- */
-unsigned int __read_mostly softlockup_panic =
- CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE;
-
-static int __init softlockup_panic_setup(char *str)
-{
- softlockup_panic = simple_strtoul(str, NULL, 0);
-
- return 1;
-}
-__setup("softlockup_panic=", softlockup_panic_setup);
-
-static int
-softlock_panic(struct notifier_block *this, unsigned long event, void *ptr)
-{
- did_panic = 1;
-
- return NOTIFY_DONE;
-}
-
-static struct notifier_block panic_block = {
- .notifier_call = softlock_panic,
-};
-
-/*
- * Returns seconds, approximately. We don't need nanosecond
- * resolution, and we don't need to waste time with a big divide when
- * 2^30ns == 1.074s.
- */
-static unsigned long get_timestamp(int this_cpu)
-{
- return cpu_clock(this_cpu) >> 30LL; /* 2^30 ~= 10^9 */
-}
-
-static void __touch_softlockup_watchdog(void)
-{
- int this_cpu = raw_smp_processor_id();
-
- __raw_get_cpu_var(softlockup_touch_ts) = get_timestamp(this_cpu);
-}
-
-void touch_softlockup_watchdog(void)
-{
- __raw_get_cpu_var(softlockup_touch_ts) = 0;
-}
-EXPORT_SYMBOL(touch_softlockup_watchdog);
-
-void touch_softlockup_watchdog_sync(void)
-{
- __raw_get_cpu_var(softlock_touch_sync) = true;
- __raw_get_cpu_var(softlockup_touch_ts) = 0;
-}
-
-void touch_all_softlockup_watchdogs(void)
-{
- int cpu;
-
- /* Cause each CPU to re-update its timestamp rather than complain */
- for_each_online_cpu(cpu)
- per_cpu(softlockup_touch_ts, cpu) = 0;
-}
-EXPORT_SYMBOL(touch_all_softlockup_watchdogs);
-
-int proc_dosoftlockup_thresh(struct ctl_table *table, int write,
- void __user *buffer,
- size_t *lenp, loff_t *ppos)
-{
- touch_all_softlockup_watchdogs();
- return proc_dointvec_minmax(table, write, buffer, lenp, ppos);
-}
-
-/*
- * This callback runs from the timer interrupt, and checks
- * whether the watchdog thread has hung or not:
- */
-void softlockup_tick(void)
-{
- int this_cpu = smp_processor_id();
- unsigned long touch_ts = per_cpu(softlockup_touch_ts, this_cpu);
- unsigned long print_ts;
- struct pt_regs *regs = get_irq_regs();
- unsigned long now;
-
- /* Is detection switched off? */
- if (!per_cpu(softlockup_watchdog, this_cpu) || softlockup_thresh <= 0) {
- /* Be sure we don't false trigger if switched back on */
- if (touch_ts)
- per_cpu(softlockup_touch_ts, this_cpu) = 0;
- return;
- }
-
- if (touch_ts == 0) {
- if (unlikely(per_cpu(softlock_touch_sync, this_cpu))) {
- /*
- * If the time stamp was touched atomically
- * make sure the scheduler tick is up to date.
- */
- per_cpu(softlock_touch_sync, this_cpu) = false;
- sched_clock_tick();
- }
- __touch_softlockup_watchdog();
- return;
- }
-
- print_ts = per_cpu(softlockup_print_ts, this_cpu);
-
- /* report at most once a second */
- if (print_ts == touch_ts || did_panic)
- return;
-
- /* do not print during early bootup: */
- if (unlikely(system_state != SYSTEM_RUNNING)) {
- __touch_softlockup_watchdog();
- return;
- }
-
- now = get_timestamp(this_cpu);
-
- /*
- * Wake up the high-prio watchdog task twice per
- * threshold timespan.
- */
- if (time_after(now - softlockup_thresh/2, touch_ts))
- wake_up_process(per_cpu(softlockup_watchdog, this_cpu));
-
- /* Warn about unreasonable delays: */
- if (time_before_eq(now - softlockup_thresh, touch_ts))
- return;
-
- per_cpu(softlockup_print_ts, this_cpu) = touch_ts;
-
- spin_lock(&print_lock);
- printk(KERN_ERR "BUG: soft lockup - CPU#%d stuck for %lus! [%s:%d]\n",
- this_cpu, now - touch_ts,
- current->comm, task_pid_nr(current));
- print_modules();
- print_irqtrace_events(current);
- if (regs)
- show_regs(regs);
- else
- dump_stack();
- spin_unlock(&print_lock);
-
- if (softlockup_panic)
- panic("softlockup: hung tasks");
-}
-
-/*
- * The watchdog thread - runs every second and touches the timestamp.
- */
-static int watchdog(void *__bind_cpu)
-{
- struct sched_param param = { .sched_priority = MAX_RT_PRIO-1 };
-
- sched_setscheduler(current, SCHED_FIFO, &param);
-
- /* initialize timestamp */
- __touch_softlockup_watchdog();
-
- set_current_state(TASK_INTERRUPTIBLE);
- /*
- * Run briefly once per second to reset the softlockup timestamp.
- * If this gets delayed for more than 60 seconds then the
- * debug-printout triggers in softlockup_tick().
- */
- while (!kthread_should_stop()) {
- __touch_softlockup_watchdog();
- schedule();
-
- if (kthread_should_stop())
- break;
-
- set_current_state(TASK_INTERRUPTIBLE);
- }
- __set_current_state(TASK_RUNNING);
-
- return 0;
-}
-
-/*
- * Create/destroy watchdog threads as CPUs come and go:
- */
-static int __cpuinit
-cpu_callback(struct notifier_block *nfb, unsigned long action, void *hcpu)
-{
- int hotcpu = (unsigned long)hcpu;
- struct task_struct *p;
-
- switch (action) {
- case CPU_UP_PREPARE:
- case CPU_UP_PREPARE_FROZEN:
- BUG_ON(per_cpu(softlockup_watchdog, hotcpu));
- p = kthread_create(watchdog, hcpu, "watchdog/%d", hotcpu);
- if (IS_ERR(p)) {
- printk(KERN_ERR "watchdog for %i failed\n", hotcpu);
- return NOTIFY_BAD;
- }
- per_cpu(softlockup_touch_ts, hotcpu) = 0;
- per_cpu(softlockup_watchdog, hotcpu) = p;
- kthread_bind(p, hotcpu);
- break;
- case CPU_ONLINE:
- case CPU_ONLINE_FROZEN:
- wake_up_process(per_cpu(softlockup_watchdog, hotcpu));
- break;
-#ifdef CONFIG_HOTPLUG_CPU
- case CPU_UP_CANCELED:
- case CPU_UP_CANCELED_FROZEN:
- if (!per_cpu(softlockup_watchdog, hotcpu))
- break;
- /* Unbind so it can run. Fall thru. */
- kthread_bind(per_cpu(softlockup_watchdog, hotcpu),
- cpumask_any(cpu_online_mask));
- case CPU_DEAD:
- case CPU_DEAD_FROZEN:
- p = per_cpu(softlockup_watchdog, hotcpu);
- per_cpu(softlockup_watchdog, hotcpu) = NULL;
- kthread_stop(p);
- break;
-#endif /* CONFIG_HOTPLUG_CPU */
- }
- return NOTIFY_OK;
-}
-
-static struct notifier_block __cpuinitdata cpu_nfb = {
- .notifier_call = cpu_callback
-};
-
-static int __initdata nosoftlockup;
-
-static int __init nosoftlockup_setup(char *str)
-{
- nosoftlockup = 1;
- return 1;
-}
-__setup("nosoftlockup", nosoftlockup_setup);
-
-static int __init spawn_softlockup_task(void)
-{
- void *cpu = (void *)(long)smp_processor_id();
- int err;
-
- if (nosoftlockup)
- return 0;
-
- err = cpu_callback(&cpu_nfb, CPU_UP_PREPARE, cpu);
- if (err == NOTIFY_BAD) {
- BUG();
- return 1;
- }
- cpu_callback(&cpu_nfb, CPU_ONLINE, cpu);
- register_cpu_notifier(&cpu_nfb);
-
- atomic_notifier_chain_register(&panic_notifier_list, &panic_block);
-
- return 0;
-}
-early_initcall(spawn_softlockup_task);
diff --git a/kernel/sysctl.c b/kernel/sysctl.c
index d24f761f487..6d850bf0a51 100644
--- a/kernel/sysctl.c
+++ b/kernel/sysctl.c
@@ -50,7 +50,6 @@
#include <linux/acpi.h>
#include <linux/reboot.h>
#include <linux/ftrace.h>
-#include <linux/slow-work.h>
#include <linux/perf_event.h>
#include <linux/kprobes.h>
#include <linux/pipe_fs_i.h>
@@ -76,6 +75,10 @@
#include <scsi/sg.h>
#endif
+#ifdef CONFIG_LOCKUP_DETECTOR
+#include <linux/nmi.h>
+#endif
+
#if defined(CONFIG_SYSCTL)
@@ -106,7 +109,7 @@ extern int blk_iopoll_enabled;
#endif
/* Constants used for minimum and maximum */
-#ifdef CONFIG_DETECT_SOFTLOCKUP
+#ifdef CONFIG_LOCKUP_DETECTOR
static int sixty = 60;
static int neg_one = -1;
#endif
@@ -562,7 +565,7 @@ static struct ctl_table kern_table[] = {
.extra2 = &one,
},
#endif
-#if defined(CONFIG_HOTPLUG) && defined(CONFIG_NET)
+#ifdef CONFIG_HOTPLUG
{
.procname = "hotplug",
.data = &uevent_helper,
@@ -710,7 +713,34 @@ static struct ctl_table kern_table[] = {
.mode = 0444,
.proc_handler = proc_dointvec,
},
-#if defined(CONFIG_X86_LOCAL_APIC) && defined(CONFIG_X86)
+#if defined(CONFIG_LOCKUP_DETECTOR)
+ {
+ .procname = "watchdog",
+ .data = &watchdog_enabled,
+ .maxlen = sizeof (int),
+ .mode = 0644,
+ .proc_handler = proc_dowatchdog_enabled,
+ },
+ {
+ .procname = "watchdog_thresh",
+ .data = &softlockup_thresh,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = proc_dowatchdog_thresh,
+ .extra1 = &neg_one,
+ .extra2 = &sixty,
+ },
+ {
+ .procname = "softlockup_panic",
+ .data = &softlockup_panic,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = proc_dointvec_minmax,
+ .extra1 = &zero,
+ .extra2 = &one,
+ },
+#endif
+#if defined(CONFIG_X86_LOCAL_APIC) && defined(CONFIG_X86) && !defined(CONFIG_LOCKUP_DETECTOR)
{
.procname = "unknown_nmi_panic",
.data = &unknown_nmi_panic,
@@ -813,26 +843,6 @@ static struct ctl_table kern_table[] = {
.proc_handler = proc_dointvec,
},
#endif
-#ifdef CONFIG_DETECT_SOFTLOCKUP
- {
- .procname = "softlockup_panic",
- .data = &softlockup_panic,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = proc_dointvec_minmax,
- .extra1 = &zero,
- .extra2 = &one,
- },
- {
- .procname = "softlockup_thresh",
- .data = &softlockup_thresh,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = proc_dosoftlockup_thresh,
- .extra1 = &neg_one,
- .extra2 = &sixty,
- },
-#endif
#ifdef CONFIG_DETECT_HUNG_TASK
{
.procname = "hung_task_panic",
@@ -906,13 +916,6 @@ static struct ctl_table kern_table[] = {
.proc_handler = proc_dointvec,
},
#endif
-#ifdef CONFIG_SLOW_WORK
- {
- .procname = "slow-work",
- .mode = 0555,
- .child = slow_work_sysctls,
- },
-#endif
#ifdef CONFIG_PERF_EVENTS
{
.procname = "perf_event_paranoid",
diff --git a/kernel/time.c b/kernel/time.c
index 848b1c2ab09..ba9b338d183 100644
--- a/kernel/time.c
+++ b/kernel/time.c
@@ -300,22 +300,6 @@ struct timespec timespec_trunc(struct timespec t, unsigned gran)
}
EXPORT_SYMBOL(timespec_trunc);
-#ifndef CONFIG_GENERIC_TIME
-/*
- * Simulate gettimeofday using do_gettimeofday which only allows a timeval
- * and therefore only yields usec accuracy
- */
-void getnstimeofday(struct timespec *tv)
-{
- struct timeval x;
-
- do_gettimeofday(&x);
- tv->tv_sec = x.tv_sec;
- tv->tv_nsec = x.tv_usec * NSEC_PER_USEC;
-}
-EXPORT_SYMBOL_GPL(getnstimeofday);
-#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
* => year=1980, mon=12, day=31, hour=23, min=59, sec=59.
diff --git a/kernel/time/Kconfig b/kernel/time/Kconfig
index 95ed42951e0..f06a8a36564 100644
--- a/kernel/time/Kconfig
+++ b/kernel/time/Kconfig
@@ -6,7 +6,7 @@ config TICK_ONESHOT
config NO_HZ
bool "Tickless System (Dynamic Ticks)"
- depends on GENERIC_TIME && GENERIC_CLOCKEVENTS
+ depends on !ARCH_USES_GETTIMEOFFSET && GENERIC_CLOCKEVENTS
select TICK_ONESHOT
help
This option enables a tickless system: timer interrupts will
@@ -15,7 +15,7 @@ config NO_HZ
config HIGH_RES_TIMERS
bool "High Resolution Timer Support"
- depends on GENERIC_TIME && GENERIC_CLOCKEVENTS
+ depends on !ARCH_USES_GETTIMEOFFSET && GENERIC_CLOCKEVENTS
select TICK_ONESHOT
help
This option enables high resolution timer support. If your
diff --git a/kernel/time/clocksource.c b/kernel/time/clocksource.c
index f08e99c1d56..c18d7efa1b4 100644
--- a/kernel/time/clocksource.c
+++ b/kernel/time/clocksource.c
@@ -531,7 +531,7 @@ static u64 clocksource_max_deferment(struct clocksource *cs)
return max_nsecs - (max_nsecs >> 5);
}
-#ifdef CONFIG_GENERIC_TIME
+#ifndef CONFIG_ARCH_USES_GETTIMEOFFSET
/**
* clocksource_select - Select the best clocksource available
@@ -577,7 +577,7 @@ static void clocksource_select(void)
}
}
-#else /* CONFIG_GENERIC_TIME */
+#else /* !CONFIG_ARCH_USES_GETTIMEOFFSET */
static inline void clocksource_select(void) { }
@@ -639,19 +639,18 @@ static void clocksource_enqueue(struct clocksource *cs)
#define MAX_UPDATE_LENGTH 5 /* Seconds */
/**
- * __clocksource_register_scale - Used to install new clocksources
+ * __clocksource_updatefreq_scale - Used update clocksource with new freq
* @t: clocksource to be registered
* @scale: Scale factor multiplied against freq to get clocksource hz
* @freq: clocksource frequency (cycles per second) divided by scale
*
- * Returns -EBUSY if registration fails, zero otherwise.
+ * This should only be called from the clocksource->enable() method.
*
* This *SHOULD NOT* be called directly! Please use the
- * clocksource_register_hz() or clocksource_register_khz helper functions.
+ * clocksource_updatefreq_hz() or clocksource_updatefreq_khz helper functions.
*/
-int __clocksource_register_scale(struct clocksource *cs, u32 scale, u32 freq)
+void __clocksource_updatefreq_scale(struct clocksource *cs, u32 scale, u32 freq)
{
-
/*
* Ideally we want to use some of the limits used in
* clocksource_max_deferment, to provide a more informed
@@ -662,7 +661,27 @@ int __clocksource_register_scale(struct clocksource *cs, u32 scale, u32 freq)
NSEC_PER_SEC/scale,
MAX_UPDATE_LENGTH*scale);
cs->max_idle_ns = clocksource_max_deferment(cs);
+}
+EXPORT_SYMBOL_GPL(__clocksource_updatefreq_scale);
+
+/**
+ * __clocksource_register_scale - Used to install new clocksources
+ * @t: clocksource to be registered
+ * @scale: Scale factor multiplied against freq to get clocksource hz
+ * @freq: clocksource frequency (cycles per second) divided by scale
+ *
+ * Returns -EBUSY if registration fails, zero otherwise.
+ *
+ * This *SHOULD NOT* be called directly! Please use the
+ * clocksource_register_hz() or clocksource_register_khz helper functions.
+ */
+int __clocksource_register_scale(struct clocksource *cs, u32 scale, u32 freq)
+{
+
+ /* Intialize mult/shift and max_idle_ns */
+ __clocksource_updatefreq_scale(cs, scale, freq);
+ /* Add clocksource to the clcoksource list */
mutex_lock(&clocksource_mutex);
clocksource_enqueue(cs);
clocksource_select();
diff --git a/kernel/time/tick-broadcast.c b/kernel/time/tick-broadcast.c
index b3bafd5fc66..48b2761b566 100644
--- a/kernel/time/tick-broadcast.c
+++ b/kernel/time/tick-broadcast.c
@@ -188,7 +188,7 @@ static void tick_handle_periodic_broadcast(struct clock_event_device *dev)
/*
* Setup the next period for devices, which do not have
* periodic mode. We read dev->next_event first and add to it
- * when the event alrady expired. clockevents_program_event()
+ * when the event already expired. clockevents_program_event()
* sets dev->next_event only when the event is really
* programmed to the device.
*/
diff --git a/kernel/time/tick-sched.c b/kernel/time/tick-sched.c
index 813993b5fb6..3e216e01bbd 100644
--- a/kernel/time/tick-sched.c
+++ b/kernel/time/tick-sched.c
@@ -325,7 +325,7 @@ void tick_nohz_stop_sched_tick(int inidle)
} while (read_seqretry(&xtime_lock, seq));
if (rcu_needs_cpu(cpu) || printk_needs_cpu(cpu) ||
- arch_needs_cpu(cpu) || nohz_ratelimit(cpu)) {
+ arch_needs_cpu(cpu)) {
next_jiffies = last_jiffies + 1;
delta_jiffies = 1;
} else {
@@ -405,13 +405,7 @@ void tick_nohz_stop_sched_tick(int inidle)
* the scheduler tick in nohz_restart_sched_tick.
*/
if (!ts->tick_stopped) {
- if (select_nohz_load_balancer(1)) {
- /*
- * sched tick not stopped!
- */
- cpumask_clear_cpu(cpu, nohz_cpu_mask);
- goto out;
- }
+ select_nohz_load_balancer(1);
ts->idle_tick = hrtimer_get_expires(&ts->sched_timer);
ts->tick_stopped = 1;
@@ -780,7 +774,6 @@ 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:
@@ -790,10 +783,6 @@ void tick_setup_sched_timer(void)
/* Get the next period (per cpu) */
hrtimer_set_expires(&ts->sched_timer, tick_init_jiffy_update());
- offset = ktime_to_ns(tick_period) >> 1;
- do_div(offset, num_possible_cpus());
- offset *= smp_processor_id();
- hrtimer_add_expires_ns(&ts->sched_timer, offset);
for (;;) {
hrtimer_forward(&ts->sched_timer, now, tick_period);
diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c
index caf8d4d4f5c..e14c839e9fa 100644
--- a/kernel/time/timekeeping.c
+++ b/kernel/time/timekeeping.c
@@ -153,8 +153,8 @@ __cacheline_aligned_in_smp DEFINE_SEQLOCK(xtime_lock);
* - 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 struct timespec xtime __attribute__ ((aligned (16)));
+static struct timespec wall_to_monotonic __attribute__ ((aligned (16)));
static struct timespec total_sleep_time;
/*
@@ -170,11 +170,10 @@ void timekeeping_leap_insert(int leapsecond)
{
xtime.tv_sec += leapsecond;
wall_to_monotonic.tv_sec -= leapsecond;
- update_vsyscall(&xtime, timekeeper.clock, timekeeper.mult);
+ update_vsyscall(&xtime, &wall_to_monotonic, timekeeper.clock,
+ timekeeper.mult);
}
-#ifdef CONFIG_GENERIC_TIME
-
/**
* timekeeping_forward_now - update clock to the current time
*
@@ -328,7 +327,8 @@ int do_settimeofday(struct timespec *tv)
timekeeper.ntp_error = 0;
ntp_clear();
- update_vsyscall(&xtime, timekeeper.clock, timekeeper.mult);
+ update_vsyscall(&xtime, &wall_to_monotonic, timekeeper.clock,
+ timekeeper.mult);
write_sequnlock_irqrestore(&xtime_lock, flags);
@@ -376,52 +376,6 @@ void timekeeping_notify(struct clocksource *clock)
tick_clock_notify();
}
-#else /* GENERIC_TIME */
-
-static inline void timekeeping_forward_now(void) { }
-
-/**
- * ktime_get - get the monotonic time in ktime_t format
- *
- * returns the time in ktime_t format
- */
-ktime_t ktime_get(void)
-{
- struct timespec now;
-
- ktime_get_ts(&now);
-
- return timespec_to_ktime(now);
-}
-EXPORT_SYMBOL_GPL(ktime_get);
-
-/**
- * ktime_get_ts - get the monotonic clock in timespec format
- * @ts: pointer to timespec variable
- *
- * The function calculates the monotonic clock from the realtime
- * clock and the wall_to_monotonic offset and stores the result
- * in normalized timespec format in the variable pointed to by @ts.
- */
-void ktime_get_ts(struct timespec *ts)
-{
- struct timespec tomono;
- unsigned long seq;
-
- do {
- seq = read_seqbegin(&xtime_lock);
- getnstimeofday(ts);
- tomono = wall_to_monotonic;
-
- } while (read_seqretry(&xtime_lock, seq));
-
- set_normalized_timespec(ts, ts->tv_sec + tomono.tv_sec,
- ts->tv_nsec + tomono.tv_nsec);
-}
-EXPORT_SYMBOL_GPL(ktime_get_ts);
-
-#endif /* !GENERIC_TIME */
-
/**
* ktime_get_real - get the real (wall-) time in ktime_t format
*
@@ -579,9 +533,9 @@ static int timekeeping_resume(struct sys_device *dev)
if (timespec_compare(&ts, &timekeeping_suspend_time) > 0) {
ts = timespec_sub(ts, timekeeping_suspend_time);
- xtime = timespec_add_safe(xtime, ts);
+ xtime = timespec_add(xtime, ts);
wall_to_monotonic = timespec_sub(wall_to_monotonic, ts);
- total_sleep_time = timespec_add_safe(total_sleep_time, ts);
+ total_sleep_time = timespec_add(total_sleep_time, ts);
}
/* re-base the last cycle value */
timekeeper.clock->cycle_last = timekeeper.clock->read(timekeeper.clock);
@@ -784,10 +738,11 @@ void update_wall_time(void)
return;
clock = timekeeper.clock;
-#ifdef CONFIG_GENERIC_TIME
- offset = (clock->read(clock) - clock->cycle_last) & clock->mask;
-#else
+
+#ifdef CONFIG_ARCH_USES_GETTIMEOFFSET
offset = timekeeper.cycle_interval;
+#else
+ offset = (clock->read(clock) - clock->cycle_last) & clock->mask;
#endif
timekeeper.xtime_nsec = (s64)xtime.tv_nsec << timekeeper.shift;
@@ -856,7 +811,8 @@ void update_wall_time(void)
}
/* check to see if there is a new clocksource to use */
- update_vsyscall(&xtime, timekeeper.clock, timekeeper.mult);
+ update_vsyscall(&xtime, &wall_to_monotonic, timekeeper.clock,
+ timekeeper.mult);
}
/**
@@ -887,7 +843,7 @@ EXPORT_SYMBOL_GPL(getboottime);
*/
void monotonic_to_bootbased(struct timespec *ts)
{
- *ts = timespec_add_safe(*ts, total_sleep_time);
+ *ts = timespec_add(*ts, total_sleep_time);
}
EXPORT_SYMBOL_GPL(monotonic_to_bootbased);
@@ -902,6 +858,11 @@ struct timespec __current_kernel_time(void)
return xtime;
}
+struct timespec __get_wall_to_monotonic(void)
+{
+ return wall_to_monotonic;
+}
+
struct timespec current_kernel_time(void)
{
struct timespec now;
diff --git a/kernel/timer.c b/kernel/timer.c
index ee305c8d4e1..f1b8afe1ad8 100644
--- a/kernel/timer.c
+++ b/kernel/timer.c
@@ -90,8 +90,13 @@ static DEFINE_PER_CPU(struct tvec_base *, tvec_bases) = &boot_tvec_bases;
/*
* Note that all tvec_bases are 2 byte aligned and lower bit of
- * base in timer_list is guaranteed to be zero. Use the LSB for
- * the new flag to indicate whether the timer is deferrable
+ * base in timer_list is guaranteed to be zero. Use the LSB to
+ * indicate whether the timer is deferrable.
+ *
+ * A deferrable timer will work normally when the system is busy, but
+ * will not cause a CPU to come out of idle just to service it; instead,
+ * the timer will be serviced when the CPU eventually wakes up with a
+ * subsequent non-deferrable timer.
*/
#define TBASE_DEFERRABLE_FLAG (0x1)
@@ -577,6 +582,19 @@ static void __init_timer(struct timer_list *timer,
lockdep_init_map(&timer->lockdep_map, name, key, 0);
}
+void setup_deferrable_timer_on_stack_key(struct timer_list *timer,
+ const char *name,
+ struct lock_class_key *key,
+ void (*function)(unsigned long),
+ unsigned long data)
+{
+ timer->function = function;
+ timer->data = data;
+ init_timer_on_stack_key(timer, name, key);
+ timer_set_deferrable(timer);
+}
+EXPORT_SYMBOL_GPL(setup_deferrable_timer_on_stack_key);
+
/**
* init_timer_key - initialize a timer
* @timer: the timer to be initialized
@@ -679,12 +697,8 @@ __mod_timer(struct timer_list *timer, unsigned long expires,
cpu = smp_processor_id();
#if defined(CONFIG_NO_HZ) && defined(CONFIG_SMP)
- if (!pinned && get_sysctl_timer_migration() && idle_cpu(cpu)) {
- int preferred_cpu = get_nohz_load_balancer();
-
- if (preferred_cpu >= 0)
- cpu = preferred_cpu;
- }
+ if (!pinned && get_sysctl_timer_migration() && idle_cpu(cpu))
+ cpu = get_nohz_timer_target();
#endif
new_base = per_cpu(tvec_bases, cpu);
@@ -1289,7 +1303,6 @@ void run_local_timers(void)
{
hrtimer_run_queues();
raise_softirq(TIMER_SOFTIRQ);
- softlockup_tick();
}
/*
@@ -1750,3 +1763,25 @@ unsigned long msleep_interruptible(unsigned int msecs)
}
EXPORT_SYMBOL(msleep_interruptible);
+
+static int __sched do_usleep_range(unsigned long min, unsigned long max)
+{
+ ktime_t kmin;
+ unsigned long delta;
+
+ kmin = ktime_set(0, min * NSEC_PER_USEC);
+ delta = (max - min) * NSEC_PER_USEC;
+ return schedule_hrtimeout_range(&kmin, delta, HRTIMER_MODE_REL);
+}
+
+/**
+ * usleep_range - Drop in replacement for udelay where wakeup is flexible
+ * @min: Minimum time in usecs to sleep
+ * @max: Maximum time in usecs to sleep
+ */
+void usleep_range(unsigned long min, unsigned long max)
+{
+ __set_current_state(TASK_UNINTERRUPTIBLE);
+ do_usleep_range(min, max);
+}
+EXPORT_SYMBOL(usleep_range);
diff --git a/kernel/trace/Kconfig b/kernel/trace/Kconfig
index 8b1797c4545..538501c6ea5 100644
--- a/kernel/trace/Kconfig
+++ b/kernel/trace/Kconfig
@@ -153,7 +153,7 @@ config IRQSOFF_TRACER
bool "Interrupts-off Latency Tracer"
default n
depends on TRACE_IRQFLAGS_SUPPORT
- depends on GENERIC_TIME
+ depends on !ARCH_USES_GETTIMEOFFSET
select TRACE_IRQFLAGS
select GENERIC_TRACER
select TRACER_MAX_TRACE
@@ -175,7 +175,7 @@ config IRQSOFF_TRACER
config PREEMPT_TRACER
bool "Preemption-off Latency Tracer"
default n
- depends on GENERIC_TIME
+ depends on !ARCH_USES_GETTIMEOFFSET
depends on PREEMPT
select GENERIC_TRACER
select TRACER_MAX_TRACE
@@ -194,15 +194,6 @@ config PREEMPT_TRACER
enabled. This option and the irqs-off timing option can be
used together or separately.)
-config SYSPROF_TRACER
- bool "Sysprof Tracer"
- depends on X86
- select GENERIC_TRACER
- select CONTEXT_SWITCH_TRACER
- help
- This tracer provides the trace needed by the 'Sysprof' userspace
- tool.
-
config SCHED_TRACER
bool "Scheduling Latency Tracer"
select GENERIC_TRACER
@@ -229,23 +220,6 @@ config FTRACE_SYSCALLS
help
Basic tracer to catch the syscall entry and exit events.
-config BOOT_TRACER
- bool "Trace boot initcalls"
- select GENERIC_TRACER
- select CONTEXT_SWITCH_TRACER
- help
- This tracer helps developers to optimize boot times: it records
- the timings of the initcalls and traces key events and the identity
- of tasks that can cause boot delays, such as context-switches.
-
- Its aim is to be parsed by the scripts/bootgraph.pl tool to
- produce pretty graphics about boot inefficiencies, giving a visual
- representation of the delays during initcalls - but the raw
- /debug/tracing/trace text output is readable too.
-
- You must pass in initcall_debug and ftrace=initcall to the kernel
- command line to enable this on bootup.
-
config TRACE_BRANCH_PROFILING
bool
select GENERIC_TRACER
@@ -325,28 +299,6 @@ config BRANCH_TRACER
Say N if unsure.
-config KSYM_TRACER
- bool "Trace read and write access on kernel memory locations"
- depends on HAVE_HW_BREAKPOINT
- select TRACING
- help
- This tracer helps find read and write operations on any given kernel
- symbol i.e. /proc/kallsyms.
-
-config PROFILE_KSYM_TRACER
- bool "Profile all kernel memory accesses on 'watched' variables"
- depends on KSYM_TRACER
- help
- This tracer profiles kernel accesses on variables watched through the
- ksym tracer ftrace plugin. Depending upon the hardware, all read
- and write operations on kernel variables can be monitored for
- accesses.
-
- The results will be displayed in:
- /debugfs/tracing/profile_ksym
-
- Say N if unsure.
-
config STACK_TRACER
bool "Trace max stack"
depends on HAVE_FUNCTION_TRACER
@@ -371,37 +323,6 @@ config STACK_TRACER
Say N if unsure.
-config KMEMTRACE
- bool "Trace SLAB allocations"
- select GENERIC_TRACER
- help
- kmemtrace provides tracing for slab allocator functions, such as
- kmalloc, kfree, kmem_cache_alloc, kmem_cache_free, etc. Collected
- data is then fed to the userspace application in order to analyse
- allocation hotspots, internal fragmentation and so on, making it
- possible to see how well an allocator performs, as well as debug
- and profile kernel code.
-
- This requires an userspace application to use. See
- Documentation/trace/kmemtrace.txt for more information.
-
- Saying Y will make the kernel somewhat larger and slower. However,
- if you disable kmemtrace at run-time or boot-time, the performance
- impact is minimal (depending on the arch the kernel is built for).
-
- If unsure, say N.
-
-config WORKQUEUE_TRACER
- bool "Trace workqueues"
- select GENERIC_TRACER
- help
- The workqueue tracer provides some statistical information
- about each cpu workqueue thread such as the number of the
- works inserted and executed since their creation. It can help
- to evaluate the amount of work each of them has to perform.
- For example it can help a developer to decide whether he should
- choose a per-cpu workqueue instead of a singlethreaded one.
-
config BLK_DEV_IO_TRACE
bool "Support for tracing block IO actions"
depends on SYSFS
diff --git a/kernel/trace/Makefile b/kernel/trace/Makefile
index ffb1a5b0550..53f338190b2 100644
--- a/kernel/trace/Makefile
+++ b/kernel/trace/Makefile
@@ -30,7 +30,6 @@ obj-$(CONFIG_TRACING) += trace_output.o
obj-$(CONFIG_TRACING) += trace_stat.o
obj-$(CONFIG_TRACING) += trace_printk.o
obj-$(CONFIG_CONTEXT_SWITCH_TRACER) += trace_sched_switch.o
-obj-$(CONFIG_SYSPROF_TRACER) += trace_sysprof.o
obj-$(CONFIG_FUNCTION_TRACER) += trace_functions.o
obj-$(CONFIG_IRQSOFF_TRACER) += trace_irqsoff.o
obj-$(CONFIG_PREEMPT_TRACER) += trace_irqsoff.o
@@ -38,10 +37,8 @@ obj-$(CONFIG_SCHED_TRACER) += trace_sched_wakeup.o
obj-$(CONFIG_NOP_TRACER) += trace_nop.o
obj-$(CONFIG_STACK_TRACER) += trace_stack.o
obj-$(CONFIG_MMIOTRACE) += trace_mmiotrace.o
-obj-$(CONFIG_BOOT_TRACER) += trace_boot.o
obj-$(CONFIG_FUNCTION_GRAPH_TRACER) += trace_functions_graph.o
obj-$(CONFIG_TRACE_BRANCH_PROFILING) += trace_branch.o
-obj-$(CONFIG_KMEMTRACE) += kmemtrace.o
obj-$(CONFIG_WORKQUEUE_TRACER) += trace_workqueue.o
obj-$(CONFIG_BLK_DEV_IO_TRACE) += blktrace.o
ifeq ($(CONFIG_BLOCK),y)
@@ -55,7 +52,9 @@ obj-$(CONFIG_EVENT_TRACING) += trace_event_perf.o
endif
obj-$(CONFIG_EVENT_TRACING) += trace_events_filter.o
obj-$(CONFIG_KPROBE_EVENT) += trace_kprobe.o
-obj-$(CONFIG_KSYM_TRACER) += trace_ksym.o
obj-$(CONFIG_EVENT_TRACING) += power-traces.o
+ifeq ($(CONFIG_TRACING),y)
+obj-$(CONFIG_KGDB_KDB) += trace_kdb.o
+endif
libftrace-y := ftrace.o
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
index 6d2cb14f944..0d88ce9b9fb 100644
--- a/kernel/trace/ftrace.c
+++ b/kernel/trace/ftrace.c
@@ -1883,7 +1883,6 @@ function_trace_probe_call(unsigned long ip, unsigned long parent_ip)
struct hlist_head *hhd;
struct hlist_node *n;
unsigned long key;
- int resched;
key = hash_long(ip, FTRACE_HASH_BITS);
@@ -1897,12 +1896,12 @@ function_trace_probe_call(unsigned long ip, unsigned long parent_ip)
* period. This syncs the hash iteration and freeing of items
* on the hash. rcu_read_lock is too dangerous here.
*/
- resched = ftrace_preempt_disable();
+ preempt_disable_notrace();
hlist_for_each_entry_rcu(entry, n, hhd, node) {
if (entry->ip == ip)
entry->ops->func(ip, parent_ip, &entry->data);
}
- ftrace_preempt_enable(resched);
+ preempt_enable_notrace();
}
static struct ftrace_ops trace_probe_ops __read_mostly =
diff --git a/kernel/trace/kmemtrace.c b/kernel/trace/kmemtrace.c
deleted file mode 100644
index bbfc1bb1660..00000000000
--- a/kernel/trace/kmemtrace.c
+++ /dev/null
@@ -1,529 +0,0 @@
-/*
- * Memory allocator tracing
- *
- * Copyright (C) 2008 Eduard - Gabriel Munteanu
- * Copyright (C) 2008 Pekka Enberg <penberg@cs.helsinki.fi>
- * Copyright (C) 2008 Frederic Weisbecker <fweisbec@gmail.com>
- */
-
-#include <linux/tracepoint.h>
-#include <linux/seq_file.h>
-#include <linux/debugfs.h>
-#include <linux/dcache.h>
-#include <linux/fs.h>
-
-#include <linux/kmemtrace.h>
-
-#include "trace_output.h"
-#include "trace.h"
-
-/* Select an alternative, minimalistic output than the original one */
-#define TRACE_KMEM_OPT_MINIMAL 0x1
-
-static struct tracer_opt kmem_opts[] = {
- /* Default disable the minimalistic output */
- { TRACER_OPT(kmem_minimalistic, TRACE_KMEM_OPT_MINIMAL) },
- { }
-};
-
-static struct tracer_flags kmem_tracer_flags = {
- .val = 0,
- .opts = kmem_opts
-};
-
-static struct trace_array *kmemtrace_array;
-
-/* Trace allocations */
-static inline void kmemtrace_alloc(enum kmemtrace_type_id type_id,
- unsigned long call_site,
- const void *ptr,
- size_t bytes_req,
- size_t bytes_alloc,
- gfp_t gfp_flags,
- int node)
-{
- struct ftrace_event_call *call = &event_kmem_alloc;
- struct trace_array *tr = kmemtrace_array;
- struct kmemtrace_alloc_entry *entry;
- struct ring_buffer_event *event;
-
- event = ring_buffer_lock_reserve(tr->buffer, sizeof(*entry));
- if (!event)
- return;
-
- entry = ring_buffer_event_data(event);
- tracing_generic_entry_update(&entry->ent, 0, 0);
-
- entry->ent.type = TRACE_KMEM_ALLOC;
- entry->type_id = type_id;
- entry->call_site = call_site;
- entry->ptr = ptr;
- entry->bytes_req = bytes_req;
- entry->bytes_alloc = bytes_alloc;
- entry->gfp_flags = gfp_flags;
- entry->node = node;
-
- if (!filter_check_discard(call, entry, tr->buffer, event))
- ring_buffer_unlock_commit(tr->buffer, event);
-
- trace_wake_up();
-}
-
-static inline void kmemtrace_free(enum kmemtrace_type_id type_id,
- unsigned long call_site,
- const void *ptr)
-{
- struct ftrace_event_call *call = &event_kmem_free;
- struct trace_array *tr = kmemtrace_array;
- struct kmemtrace_free_entry *entry;
- struct ring_buffer_event *event;
-
- event = ring_buffer_lock_reserve(tr->buffer, sizeof(*entry));
- if (!event)
- return;
- entry = ring_buffer_event_data(event);
- tracing_generic_entry_update(&entry->ent, 0, 0);
-
- entry->ent.type = TRACE_KMEM_FREE;
- entry->type_id = type_id;
- entry->call_site = call_site;
- entry->ptr = ptr;
-
- if (!filter_check_discard(call, entry, tr->buffer, event))
- ring_buffer_unlock_commit(tr->buffer, event);
-
- trace_wake_up();
-}
-
-static void kmemtrace_kmalloc(void *ignore,
- unsigned long call_site,
- const void *ptr,
- size_t bytes_req,
- size_t bytes_alloc,
- gfp_t gfp_flags)
-{
- kmemtrace_alloc(KMEMTRACE_TYPE_KMALLOC, call_site, ptr,
- bytes_req, bytes_alloc, gfp_flags, -1);
-}
-
-static void kmemtrace_kmem_cache_alloc(void *ignore,
- unsigned long call_site,
- const void *ptr,
- size_t bytes_req,
- size_t bytes_alloc,
- gfp_t gfp_flags)
-{
- kmemtrace_alloc(KMEMTRACE_TYPE_CACHE, call_site, ptr,
- bytes_req, bytes_alloc, gfp_flags, -1);
-}
-
-static void kmemtrace_kmalloc_node(void *ignore,
- unsigned long call_site,
- const void *ptr,
- size_t bytes_req,
- size_t bytes_alloc,
- gfp_t gfp_flags,
- int node)
-{
- kmemtrace_alloc(KMEMTRACE_TYPE_KMALLOC, call_site, ptr,
- bytes_req, bytes_alloc, gfp_flags, node);
-}
-
-static void kmemtrace_kmem_cache_alloc_node(void *ignore,
- unsigned long call_site,
- const void *ptr,
- size_t bytes_req,
- size_t bytes_alloc,
- gfp_t gfp_flags,
- int node)
-{
- kmemtrace_alloc(KMEMTRACE_TYPE_CACHE, call_site, ptr,
- bytes_req, bytes_alloc, gfp_flags, node);
-}
-
-static void
-kmemtrace_kfree(void *ignore, unsigned long call_site, const void *ptr)
-{
- kmemtrace_free(KMEMTRACE_TYPE_KMALLOC, call_site, ptr);
-}
-
-static void kmemtrace_kmem_cache_free(void *ignore,
- unsigned long call_site, const void *ptr)
-{
- kmemtrace_free(KMEMTRACE_TYPE_CACHE, call_site, ptr);
-}
-
-static int kmemtrace_start_probes(void)
-{
- int err;
-
- err = register_trace_kmalloc(kmemtrace_kmalloc, NULL);
- if (err)
- return err;
- err = register_trace_kmem_cache_alloc(kmemtrace_kmem_cache_alloc, NULL);
- if (err)
- return err;
- err = register_trace_kmalloc_node(kmemtrace_kmalloc_node, NULL);
- if (err)
- return err;
- err = register_trace_kmem_cache_alloc_node(kmemtrace_kmem_cache_alloc_node, NULL);
- if (err)
- return err;
- err = register_trace_kfree(kmemtrace_kfree, NULL);
- if (err)
- return err;
- err = register_trace_kmem_cache_free(kmemtrace_kmem_cache_free, NULL);
-
- return err;
-}
-
-static void kmemtrace_stop_probes(void)
-{
- unregister_trace_kmalloc(kmemtrace_kmalloc, NULL);
- unregister_trace_kmem_cache_alloc(kmemtrace_kmem_cache_alloc, NULL);
- unregister_trace_kmalloc_node(kmemtrace_kmalloc_node, NULL);
- unregister_trace_kmem_cache_alloc_node(kmemtrace_kmem_cache_alloc_node, NULL);
- unregister_trace_kfree(kmemtrace_kfree, NULL);
- unregister_trace_kmem_cache_free(kmemtrace_kmem_cache_free, NULL);
-}
-
-static int kmem_trace_init(struct trace_array *tr)
-{
- kmemtrace_array = tr;
-
- tracing_reset_online_cpus(tr);
-
- kmemtrace_start_probes();
-
- return 0;
-}
-
-static void kmem_trace_reset(struct trace_array *tr)
-{
- kmemtrace_stop_probes();
-}
-
-static void kmemtrace_headers(struct seq_file *s)
-{
- /* Don't need headers for the original kmemtrace output */
- if (!(kmem_tracer_flags.val & TRACE_KMEM_OPT_MINIMAL))
- return;
-
- seq_printf(s, "#\n");
- seq_printf(s, "# ALLOC TYPE REQ GIVEN FLAGS "
- " POINTER NODE CALLER\n");
- seq_printf(s, "# FREE | | | | "
- " | | | |\n");
- seq_printf(s, "# |\n\n");
-}
-
-/*
- * The following functions give the original output from kmemtrace,
- * plus the origin CPU, since reordering occurs in-kernel now.
- */
-
-#define KMEMTRACE_USER_ALLOC 0
-#define KMEMTRACE_USER_FREE 1
-
-struct kmemtrace_user_event {
- u8 event_id;
- u8 type_id;
- u16 event_size;
- u32 cpu;
- u64 timestamp;
- unsigned long call_site;
- unsigned long ptr;
-};
-
-struct kmemtrace_user_event_alloc {
- size_t bytes_req;
- size_t bytes_alloc;
- unsigned gfp_flags;
- int node;
-};
-
-static enum print_line_t
-kmemtrace_print_alloc(struct trace_iterator *iter, int flags,
- struct trace_event *event)
-{
- struct trace_seq *s = &iter->seq;
- struct kmemtrace_alloc_entry *entry;
- int ret;
-
- trace_assign_type(entry, iter->ent);
-
- ret = trace_seq_printf(s, "type_id %d call_site %pF ptr %lu "
- "bytes_req %lu bytes_alloc %lu gfp_flags %lu node %d\n",
- entry->type_id, (void *)entry->call_site, (unsigned long)entry->ptr,
- (unsigned long)entry->bytes_req, (unsigned long)entry->bytes_alloc,
- (unsigned long)entry->gfp_flags, entry->node);
-
- if (!ret)
- return TRACE_TYPE_PARTIAL_LINE;
- return TRACE_TYPE_HANDLED;
-}
-
-static enum print_line_t
-kmemtrace_print_free(struct trace_iterator *iter, int flags,
- struct trace_event *event)
-{
- struct trace_seq *s = &iter->seq;
- struct kmemtrace_free_entry *entry;
- int ret;
-
- trace_assign_type(entry, iter->ent);
-
- ret = trace_seq_printf(s, "type_id %d call_site %pF ptr %lu\n",
- entry->type_id, (void *)entry->call_site,
- (unsigned long)entry->ptr);
-
- if (!ret)
- return TRACE_TYPE_PARTIAL_LINE;
- return TRACE_TYPE_HANDLED;
-}
-
-static enum print_line_t
-kmemtrace_print_alloc_user(struct trace_iterator *iter, int flags,
- struct trace_event *event)
-{
- struct trace_seq *s = &iter->seq;
- struct kmemtrace_alloc_entry *entry;
- struct kmemtrace_user_event *ev;
- struct kmemtrace_user_event_alloc *ev_alloc;
-
- trace_assign_type(entry, iter->ent);
-
- ev = trace_seq_reserve(s, sizeof(*ev));
- if (!ev)
- return TRACE_TYPE_PARTIAL_LINE;
-
- ev->event_id = KMEMTRACE_USER_ALLOC;
- ev->type_id = entry->type_id;
- ev->event_size = sizeof(*ev) + sizeof(*ev_alloc);
- ev->cpu = iter->cpu;
- ev->timestamp = iter->ts;
- ev->call_site = entry->call_site;
- ev->ptr = (unsigned long)entry->ptr;
-
- ev_alloc = trace_seq_reserve(s, sizeof(*ev_alloc));
- if (!ev_alloc)
- return TRACE_TYPE_PARTIAL_LINE;
-
- ev_alloc->bytes_req = entry->bytes_req;
- ev_alloc->bytes_alloc = entry->bytes_alloc;
- ev_alloc->gfp_flags = entry->gfp_flags;
- ev_alloc->node = entry->node;
-
- return TRACE_TYPE_HANDLED;
-}
-
-static enum print_line_t
-kmemtrace_print_free_user(struct trace_iterator *iter, int flags,
- struct trace_event *event)
-{
- struct trace_seq *s = &iter->seq;
- struct kmemtrace_free_entry *entry;
- struct kmemtrace_user_event *ev;
-
- trace_assign_type(entry, iter->ent);
-
- ev = trace_seq_reserve(s, sizeof(*ev));
- if (!ev)
- return TRACE_TYPE_PARTIAL_LINE;
-
- ev->event_id = KMEMTRACE_USER_FREE;
- ev->type_id = entry->type_id;
- ev->event_size = sizeof(*ev);
- ev->cpu = iter->cpu;
- ev->timestamp = iter->ts;
- ev->call_site = entry->call_site;
- ev->ptr = (unsigned long)entry->ptr;
-
- return TRACE_TYPE_HANDLED;
-}
-
-/* The two other following provide a more minimalistic output */
-static enum print_line_t
-kmemtrace_print_alloc_compress(struct trace_iterator *iter)
-{
- struct kmemtrace_alloc_entry *entry;
- struct trace_seq *s = &iter->seq;
- int ret;
-
- trace_assign_type(entry, iter->ent);
-
- /* Alloc entry */
- ret = trace_seq_printf(s, " + ");
- if (!ret)
- return TRACE_TYPE_PARTIAL_LINE;
-
- /* Type */
- switch (entry->type_id) {
- case KMEMTRACE_TYPE_KMALLOC:
- ret = trace_seq_printf(s, "K ");
- break;
- case KMEMTRACE_TYPE_CACHE:
- ret = trace_seq_printf(s, "C ");
- break;
- case KMEMTRACE_TYPE_PAGES:
- ret = trace_seq_printf(s, "P ");
- break;
- default:
- ret = trace_seq_printf(s, "? ");
- }
-
- if (!ret)
- return TRACE_TYPE_PARTIAL_LINE;
-
- /* Requested */
- ret = trace_seq_printf(s, "%4zu ", entry->bytes_req);
- if (!ret)
- return TRACE_TYPE_PARTIAL_LINE;
-
- /* Allocated */
- ret = trace_seq_printf(s, "%4zu ", entry->bytes_alloc);
- if (!ret)
- return TRACE_TYPE_PARTIAL_LINE;
-
- /* Flags
- * TODO: would be better to see the name of the GFP flag names
- */
- ret = trace_seq_printf(s, "%08x ", entry->gfp_flags);
- if (!ret)
- return TRACE_TYPE_PARTIAL_LINE;
-
- /* Pointer to allocated */
- ret = trace_seq_printf(s, "0x%tx ", (ptrdiff_t)entry->ptr);
- if (!ret)
- return TRACE_TYPE_PARTIAL_LINE;
-
- /* Node and call site*/
- ret = trace_seq_printf(s, "%4d %pf\n", entry->node,
- (void *)entry->call_site);
- if (!ret)
- return TRACE_TYPE_PARTIAL_LINE;
-
- return TRACE_TYPE_HANDLED;
-}
-
-static enum print_line_t
-kmemtrace_print_free_compress(struct trace_iterator *iter)
-{
- struct kmemtrace_free_entry *entry;
- struct trace_seq *s = &iter->seq;
- int ret;
-
- trace_assign_type(entry, iter->ent);
-
- /* Free entry */
- ret = trace_seq_printf(s, " - ");
- if (!ret)
- return TRACE_TYPE_PARTIAL_LINE;
-
- /* Type */
- switch (entry->type_id) {
- case KMEMTRACE_TYPE_KMALLOC:
- ret = trace_seq_printf(s, "K ");
- break;
- case KMEMTRACE_TYPE_CACHE:
- ret = trace_seq_printf(s, "C ");
- break;
- case KMEMTRACE_TYPE_PAGES:
- ret = trace_seq_printf(s, "P ");
- break;
- default:
- ret = trace_seq_printf(s, "? ");
- }
-
- if (!ret)
- return TRACE_TYPE_PARTIAL_LINE;
-
- /* Skip requested/allocated/flags */
- ret = trace_seq_printf(s, " ");
- if (!ret)
- return TRACE_TYPE_PARTIAL_LINE;
-
- /* Pointer to allocated */
- ret = trace_seq_printf(s, "0x%tx ", (ptrdiff_t)entry->ptr);
- if (!ret)
- return TRACE_TYPE_PARTIAL_LINE;
-
- /* Skip node and print call site*/
- ret = trace_seq_printf(s, " %pf\n", (void *)entry->call_site);
- if (!ret)
- return TRACE_TYPE_PARTIAL_LINE;
-
- return TRACE_TYPE_HANDLED;
-}
-
-static enum print_line_t kmemtrace_print_line(struct trace_iterator *iter)
-{
- struct trace_entry *entry = iter->ent;
-
- if (!(kmem_tracer_flags.val & TRACE_KMEM_OPT_MINIMAL))
- return TRACE_TYPE_UNHANDLED;
-
- switch (entry->type) {
- case TRACE_KMEM_ALLOC:
- return kmemtrace_print_alloc_compress(iter);
- case TRACE_KMEM_FREE:
- return kmemtrace_print_free_compress(iter);
- default:
- return TRACE_TYPE_UNHANDLED;
- }
-}
-
-static struct trace_event_functions kmem_trace_alloc_funcs = {
- .trace = kmemtrace_print_alloc,
- .binary = kmemtrace_print_alloc_user,
-};
-
-static struct trace_event kmem_trace_alloc = {
- .type = TRACE_KMEM_ALLOC,
- .funcs = &kmem_trace_alloc_funcs,
-};
-
-static struct trace_event_functions kmem_trace_free_funcs = {
- .trace = kmemtrace_print_free,
- .binary = kmemtrace_print_free_user,
-};
-
-static struct trace_event kmem_trace_free = {
- .type = TRACE_KMEM_FREE,
- .funcs = &kmem_trace_free_funcs,
-};
-
-static struct tracer kmem_tracer __read_mostly = {
- .name = "kmemtrace",
- .init = kmem_trace_init,
- .reset = kmem_trace_reset,
- .print_line = kmemtrace_print_line,
- .print_header = kmemtrace_headers,
- .flags = &kmem_tracer_flags
-};
-
-void kmemtrace_init(void)
-{
- /* earliest opportunity to start kmem tracing */
-}
-
-static int __init init_kmem_tracer(void)
-{
- if (!register_ftrace_event(&kmem_trace_alloc)) {
- pr_warning("Warning: could not register kmem events\n");
- return 1;
- }
-
- if (!register_ftrace_event(&kmem_trace_free)) {
- pr_warning("Warning: could not register kmem events\n");
- return 1;
- }
-
- if (register_tracer(&kmem_tracer) != 0) {
- pr_warning("Warning: could not register the kmem tracer\n");
- return 1;
- }
-
- return 0;
-}
-device_initcall(init_kmem_tracer);
diff --git a/kernel/trace/ring_buffer.c b/kernel/trace/ring_buffer.c
index 1da7b6ea8b8..3632ce87674 100644
--- a/kernel/trace/ring_buffer.c
+++ b/kernel/trace/ring_buffer.c
@@ -443,6 +443,7 @@ int ring_buffer_print_page_header(struct trace_seq *s)
*/
struct ring_buffer_per_cpu {
int cpu;
+ atomic_t record_disabled;
struct ring_buffer *buffer;
spinlock_t reader_lock; /* serialize readers */
arch_spinlock_t lock;
@@ -462,7 +463,6 @@ struct ring_buffer_per_cpu {
unsigned long read;
u64 write_stamp;
u64 read_stamp;
- atomic_t record_disabled;
};
struct ring_buffer {
@@ -2242,8 +2242,6 @@ static void trace_recursive_unlock(void)
#endif
-static DEFINE_PER_CPU(int, rb_need_resched);
-
/**
* ring_buffer_lock_reserve - reserve a part of the buffer
* @buffer: the ring buffer to reserve from
@@ -2264,13 +2262,13 @@ ring_buffer_lock_reserve(struct ring_buffer *buffer, unsigned long length)
{
struct ring_buffer_per_cpu *cpu_buffer;
struct ring_buffer_event *event;
- int cpu, resched;
+ int cpu;
if (ring_buffer_flags != RB_BUFFERS_ON)
return NULL;
/* If we are tracing schedule, we don't want to recurse */
- resched = ftrace_preempt_disable();
+ preempt_disable_notrace();
if (atomic_read(&buffer->record_disabled))
goto out_nocheck;
@@ -2295,21 +2293,13 @@ ring_buffer_lock_reserve(struct ring_buffer *buffer, unsigned long length)
if (!event)
goto out;
- /*
- * Need to store resched state on this cpu.
- * Only the first needs to.
- */
-
- if (preempt_count() == 1)
- per_cpu(rb_need_resched, cpu) = resched;
-
return event;
out:
trace_recursive_unlock();
out_nocheck:
- ftrace_preempt_enable(resched);
+ preempt_enable_notrace();
return NULL;
}
EXPORT_SYMBOL_GPL(ring_buffer_lock_reserve);
@@ -2355,13 +2345,7 @@ int ring_buffer_unlock_commit(struct ring_buffer *buffer,
trace_recursive_unlock();
- /*
- * Only the last preempt count needs to restore preemption.
- */
- if (preempt_count() == 1)
- ftrace_preempt_enable(per_cpu(rb_need_resched, cpu));
- else
- preempt_enable_no_resched_notrace();
+ preempt_enable_notrace();
return 0;
}
@@ -2469,13 +2453,7 @@ void ring_buffer_discard_commit(struct ring_buffer *buffer,
trace_recursive_unlock();
- /*
- * Only the last preempt count needs to restore preemption.
- */
- if (preempt_count() == 1)
- ftrace_preempt_enable(per_cpu(rb_need_resched, cpu));
- else
- preempt_enable_no_resched_notrace();
+ preempt_enable_notrace();
}
EXPORT_SYMBOL_GPL(ring_buffer_discard_commit);
@@ -2501,12 +2479,12 @@ int ring_buffer_write(struct ring_buffer *buffer,
struct ring_buffer_event *event;
void *body;
int ret = -EBUSY;
- int cpu, resched;
+ int cpu;
if (ring_buffer_flags != RB_BUFFERS_ON)
return -EBUSY;
- resched = ftrace_preempt_disable();
+ preempt_disable_notrace();
if (atomic_read(&buffer->record_disabled))
goto out;
@@ -2536,7 +2514,7 @@ int ring_buffer_write(struct ring_buffer *buffer,
ret = 0;
out:
- ftrace_preempt_enable(resched);
+ preempt_enable_notrace();
return ret;
}
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
index 086d3631680..ba14a22be4c 100644
--- a/kernel/trace/trace.c
+++ b/kernel/trace/trace.c
@@ -101,10 +101,7 @@ static inline void ftrace_enable_cpu(void)
preempt_enable();
}
-static cpumask_var_t __read_mostly tracing_buffer_mask;
-
-#define for_each_tracing_cpu(cpu) \
- for_each_cpu(cpu, tracing_buffer_mask)
+cpumask_var_t __read_mostly tracing_buffer_mask;
/*
* ftrace_dump_on_oops - variable to dump ftrace buffer on oops
@@ -344,7 +341,7 @@ static DECLARE_WAIT_QUEUE_HEAD(trace_wait);
/* trace_flags holds trace_options default values */
unsigned long trace_flags = TRACE_ITER_PRINT_PARENT | TRACE_ITER_PRINTK |
TRACE_ITER_ANNOTATE | TRACE_ITER_CONTEXT_INFO | TRACE_ITER_SLEEP_TIME |
- TRACE_ITER_GRAPH_TIME;
+ TRACE_ITER_GRAPH_TIME | TRACE_ITER_RECORD_CMD;
static int trace_stop_count;
static DEFINE_SPINLOCK(tracing_start_lock);
@@ -428,6 +425,7 @@ static const char *trace_options[] = {
"latency-format",
"sleep-time",
"graph-time",
+ "record-cmd",
NULL
};
@@ -659,6 +657,10 @@ update_max_tr(struct trace_array *tr, struct task_struct *tsk, int cpu)
return;
WARN_ON_ONCE(!irqs_disabled());
+ if (!current_trace->use_max_tr) {
+ WARN_ON_ONCE(1);
+ return;
+ }
arch_spin_lock(&ftrace_max_lock);
tr->buffer = max_tr.buffer;
@@ -685,6 +687,11 @@ update_max_tr_single(struct trace_array *tr, struct task_struct *tsk, int cpu)
return;
WARN_ON_ONCE(!irqs_disabled());
+ if (!current_trace->use_max_tr) {
+ WARN_ON_ONCE(1);
+ return;
+ }
+
arch_spin_lock(&ftrace_max_lock);
ftrace_disable_cpu();
@@ -729,18 +736,11 @@ __acquires(kernel_lock)
return -1;
}
- if (strlen(type->name) > MAX_TRACER_SIZE) {
+ if (strlen(type->name) >= MAX_TRACER_SIZE) {
pr_info("Tracer has a name longer than %d\n", MAX_TRACER_SIZE);
return -1;
}
- /*
- * When this gets called we hold the BKL which means that
- * preemption is disabled. Various trace selftests however
- * need to disable and enable preemption for successful tests.
- * So we drop the BKL here and grab it after the tests again.
- */
- unlock_kernel();
mutex_lock(&trace_types_lock);
tracing_selftest_running = true;
@@ -822,7 +822,6 @@ __acquires(kernel_lock)
#endif
out_unlock:
- lock_kernel();
return ret;
}
@@ -1331,61 +1330,6 @@ static void __trace_userstack(struct trace_array *tr, unsigned long flags)
#endif /* CONFIG_STACKTRACE */
-static void
-ftrace_trace_special(void *__tr,
- unsigned long arg1, unsigned long arg2, unsigned long arg3,
- int pc)
-{
- struct ftrace_event_call *call = &event_special;
- struct ring_buffer_event *event;
- struct trace_array *tr = __tr;
- struct ring_buffer *buffer = tr->buffer;
- struct special_entry *entry;
-
- event = trace_buffer_lock_reserve(buffer, TRACE_SPECIAL,
- sizeof(*entry), 0, pc);
- if (!event)
- return;
- entry = ring_buffer_event_data(event);
- entry->arg1 = arg1;
- entry->arg2 = arg2;
- entry->arg3 = arg3;
-
- if (!filter_check_discard(call, entry, buffer, event))
- trace_buffer_unlock_commit(buffer, event, 0, pc);
-}
-
-void
-__trace_special(void *__tr, void *__data,
- unsigned long arg1, unsigned long arg2, unsigned long arg3)
-{
- ftrace_trace_special(__tr, arg1, arg2, arg3, preempt_count());
-}
-
-void
-ftrace_special(unsigned long arg1, unsigned long arg2, unsigned long arg3)
-{
- struct trace_array *tr = &global_trace;
- struct trace_array_cpu *data;
- unsigned long flags;
- int cpu;
- int pc;
-
- if (tracing_disabled)
- return;
-
- pc = preempt_count();
- local_irq_save(flags);
- cpu = raw_smp_processor_id();
- data = tr->data[cpu];
-
- if (likely(atomic_inc_return(&data->disabled) == 1))
- ftrace_trace_special(tr, arg1, arg2, arg3, pc);
-
- atomic_dec(&data->disabled);
- local_irq_restore(flags);
-}
-
/**
* trace_vbprintk - write binary msg to tracing buffer
*
@@ -1404,7 +1348,6 @@ int trace_vbprintk(unsigned long ip, const char *fmt, va_list args)
struct bprint_entry *entry;
unsigned long flags;
int disable;
- int resched;
int cpu, len = 0, size, pc;
if (unlikely(tracing_selftest_running || tracing_disabled))
@@ -1414,7 +1357,7 @@ int trace_vbprintk(unsigned long ip, const char *fmt, va_list args)
pause_graph_tracing();
pc = preempt_count();
- resched = ftrace_preempt_disable();
+ preempt_disable_notrace();
cpu = raw_smp_processor_id();
data = tr->data[cpu];
@@ -1452,7 +1395,7 @@ out_unlock:
out:
atomic_dec_return(&data->disabled);
- ftrace_preempt_enable(resched);
+ preempt_enable_notrace();
unpause_graph_tracing();
return len;
@@ -1539,11 +1482,6 @@ int trace_vprintk(unsigned long ip, const char *fmt, va_list args)
}
EXPORT_SYMBOL_GPL(trace_vprintk);
-enum trace_file_type {
- TRACE_FILE_LAT_FMT = 1,
- TRACE_FILE_ANNOTATE = 2,
-};
-
static void trace_iterator_increment(struct trace_iterator *iter)
{
/* Don't allow ftrace to trace into the ring buffers */
@@ -1641,7 +1579,7 @@ struct trace_entry *trace_find_next_entry(struct trace_iterator *iter,
}
/* Find the next real entry, and increment the iterator to the next entry */
-static void *find_next_entry_inc(struct trace_iterator *iter)
+void *trace_find_next_entry_inc(struct trace_iterator *iter)
{
iter->ent = __find_next_entry(iter, &iter->cpu,
&iter->lost_events, &iter->ts);
@@ -1676,19 +1614,19 @@ static void *s_next(struct seq_file *m, void *v, loff_t *pos)
return NULL;
if (iter->idx < 0)
- ent = find_next_entry_inc(iter);
+ ent = trace_find_next_entry_inc(iter);
else
ent = iter;
while (ent && iter->idx < i)
- ent = find_next_entry_inc(iter);
+ ent = trace_find_next_entry_inc(iter);
iter->pos = *pos;
return ent;
}
-static void tracing_iter_reset(struct trace_iterator *iter, int cpu)
+void tracing_iter_reset(struct trace_iterator *iter, int cpu)
{
struct trace_array *tr = iter->tr;
struct ring_buffer_event *event;
@@ -2049,7 +1987,7 @@ int trace_empty(struct trace_iterator *iter)
}
/* Called with trace_event_read_lock() held. */
-static enum print_line_t print_trace_line(struct trace_iterator *iter)
+enum print_line_t print_trace_line(struct trace_iterator *iter)
{
enum print_line_t ret;
@@ -2394,6 +2332,7 @@ static const struct file_operations show_traces_fops = {
.open = show_traces_open,
.read = seq_read,
.release = seq_release,
+ .llseek = seq_lseek,
};
/*
@@ -2487,6 +2426,7 @@ static const struct file_operations tracing_cpumask_fops = {
.open = tracing_open_generic,
.read = tracing_cpumask_read,
.write = tracing_cpumask_write,
+ .llseek = generic_file_llseek,
};
static int tracing_trace_options_show(struct seq_file *m, void *v)
@@ -2562,6 +2502,9 @@ static void set_tracer_flags(unsigned int mask, int enabled)
trace_flags |= mask;
else
trace_flags &= ~mask;
+
+ if (mask == TRACE_ITER_RECORD_CMD)
+ trace_event_enable_cmd_record(enabled);
}
static ssize_t
@@ -2653,6 +2596,7 @@ tracing_readme_read(struct file *filp, char __user *ubuf,
static const struct file_operations tracing_readme_fops = {
.open = tracing_open_generic,
.read = tracing_readme_read,
+ .llseek = generic_file_llseek,
};
static ssize_t
@@ -2703,6 +2647,7 @@ tracing_saved_cmdlines_read(struct file *file, char __user *ubuf,
static const struct file_operations tracing_saved_cmdlines_fops = {
.open = tracing_open_generic,
.read = tracing_saved_cmdlines_read,
+ .llseek = generic_file_llseek,
};
static ssize_t
@@ -2798,6 +2743,9 @@ static int tracing_resize_ring_buffer(unsigned long size)
if (ret < 0)
return ret;
+ if (!current_trace->use_max_tr)
+ goto out;
+
ret = ring_buffer_resize(max_tr.buffer, size);
if (ret < 0) {
int r;
@@ -2825,11 +2773,14 @@ static int tracing_resize_ring_buffer(unsigned long size)
return ret;
}
+ max_tr.entries = size;
+ out:
global_trace.entries = size;
return ret;
}
+
/**
* tracing_update_buffers - used by tracing facility to expand ring buffers
*
@@ -2890,12 +2841,26 @@ static int tracing_set_tracer(const char *buf)
trace_branch_disable();
if (current_trace && current_trace->reset)
current_trace->reset(tr);
-
+ if (current_trace && current_trace->use_max_tr) {
+ /*
+ * We don't free the ring buffer. instead, resize it because
+ * The max_tr ring buffer has some state (e.g. ring->clock) and
+ * we want preserve it.
+ */
+ ring_buffer_resize(max_tr.buffer, 1);
+ max_tr.entries = 1;
+ }
destroy_trace_option_files(topts);
current_trace = t;
topts = create_trace_option_files(current_trace);
+ if (current_trace->use_max_tr) {
+ ret = ring_buffer_resize(max_tr.buffer, global_trace.entries);
+ if (ret < 0)
+ goto out;
+ max_tr.entries = global_trace.entries;
+ }
if (t->init) {
ret = tracer_init(t, tr);
@@ -3032,6 +2997,7 @@ static int tracing_open_pipe(struct inode *inode, struct file *filp)
if (iter->trace->pipe_open)
iter->trace->pipe_open(iter);
+ nonseekable_open(inode, filp);
out:
mutex_unlock(&trace_types_lock);
return ret;
@@ -3211,7 +3177,7 @@ waitagain:
trace_event_read_lock();
trace_access_lock(iter->cpu_file);
- while (find_next_entry_inc(iter) != NULL) {
+ while (trace_find_next_entry_inc(iter) != NULL) {
enum print_line_t ret;
int len = iter->seq.len;
@@ -3294,7 +3260,7 @@ tracing_fill_pipe_page(size_t rem, struct trace_iterator *iter)
if (ret != TRACE_TYPE_NO_CONSUME)
trace_consume(iter);
rem -= count;
- if (!find_next_entry_inc(iter)) {
+ if (!trace_find_next_entry_inc(iter)) {
rem = 0;
iter->ent = NULL;
break;
@@ -3350,7 +3316,7 @@ static ssize_t tracing_splice_read_pipe(struct file *filp,
if (ret <= 0)
goto out_err;
- if (!iter->ent && !find_next_entry_inc(iter)) {
+ if (!iter->ent && !trace_find_next_entry_inc(iter)) {
ret = -EFAULT;
goto out_err;
}
@@ -3477,7 +3443,6 @@ tracing_entries_write(struct file *filp, const char __user *ubuf,
}
tracing_start();
- max_tr.entries = global_trace.entries;
mutex_unlock(&trace_types_lock);
return cnt;
@@ -3590,18 +3555,21 @@ static const struct file_operations tracing_max_lat_fops = {
.open = tracing_open_generic,
.read = tracing_max_lat_read,
.write = tracing_max_lat_write,
+ .llseek = generic_file_llseek,
};
static const struct file_operations tracing_ctrl_fops = {
.open = tracing_open_generic,
.read = tracing_ctrl_read,
.write = tracing_ctrl_write,
+ .llseek = generic_file_llseek,
};
static const struct file_operations set_tracer_fops = {
.open = tracing_open_generic,
.read = tracing_set_trace_read,
.write = tracing_set_trace_write,
+ .llseek = generic_file_llseek,
};
static const struct file_operations tracing_pipe_fops = {
@@ -3610,17 +3578,20 @@ static const struct file_operations tracing_pipe_fops = {
.read = tracing_read_pipe,
.splice_read = tracing_splice_read_pipe,
.release = tracing_release_pipe,
+ .llseek = no_llseek,
};
static const struct file_operations tracing_entries_fops = {
.open = tracing_open_generic,
.read = tracing_entries_read,
.write = tracing_entries_write,
+ .llseek = generic_file_llseek,
};
static const struct file_operations tracing_mark_fops = {
.open = tracing_open_generic,
.write = tracing_mark_write,
+ .llseek = generic_file_llseek,
};
static const struct file_operations trace_clock_fops = {
@@ -3926,6 +3897,7 @@ tracing_stats_read(struct file *filp, char __user *ubuf,
static const struct file_operations tracing_stats_fops = {
.open = tracing_open_generic,
.read = tracing_stats_read,
+ .llseek = generic_file_llseek,
};
#ifdef CONFIG_DYNAMIC_FTRACE
@@ -3962,6 +3934,7 @@ tracing_read_dyn_info(struct file *filp, char __user *ubuf,
static const struct file_operations tracing_dyn_info_fops = {
.open = tracing_open_generic,
.read = tracing_read_dyn_info,
+ .llseek = generic_file_llseek,
};
#endif
@@ -4115,6 +4088,7 @@ static const struct file_operations trace_options_fops = {
.open = tracing_open_generic,
.read = trace_options_read,
.write = trace_options_write,
+ .llseek = generic_file_llseek,
};
static ssize_t
@@ -4166,6 +4140,7 @@ static const struct file_operations trace_options_core_fops = {
.open = tracing_open_generic,
.read = trace_options_core_read,
.write = trace_options_core_write,
+ .llseek = generic_file_llseek,
};
struct dentry *trace_create_file(const char *name,
@@ -4355,9 +4330,6 @@ static __init int tracer_init_debugfs(void)
trace_create_file("dyn_ftrace_total_info", 0444, d_tracer,
&ftrace_update_tot_cnt, &tracing_dyn_info_fops);
#endif
-#ifdef CONFIG_SYSPROF_TRACER
- init_tracer_sysprof_debugfs(d_tracer);
-#endif
create_trace_options_dir();
@@ -4414,7 +4386,7 @@ static struct notifier_block trace_die_notifier = {
*/
#define KERN_TRACE KERN_EMERG
-static void
+void
trace_printk_seq(struct trace_seq *s)
{
/* Probably should print a warning here. */
@@ -4429,6 +4401,13 @@ trace_printk_seq(struct trace_seq *s)
trace_seq_init(s);
}
+void trace_init_global_iter(struct trace_iterator *iter)
+{
+ iter->tr = &global_trace;
+ iter->trace = current_trace;
+ iter->cpu_file = TRACE_PIPE_ALL_CPU;
+}
+
static void
__ftrace_dump(bool disable_tracing, enum ftrace_dump_mode oops_dump_mode)
{
@@ -4454,8 +4433,10 @@ __ftrace_dump(bool disable_tracing, enum ftrace_dump_mode oops_dump_mode)
if (disable_tracing)
ftrace_kill();
+ trace_init_global_iter(&iter);
+
for_each_tracing_cpu(cpu) {
- atomic_inc(&global_trace.data[cpu]->disabled);
+ atomic_inc(&iter.tr->data[cpu]->disabled);
}
old_userobj = trace_flags & TRACE_ITER_SYM_USEROBJ;
@@ -4504,7 +4485,7 @@ __ftrace_dump(bool disable_tracing, enum ftrace_dump_mode oops_dump_mode)
iter.iter_flags |= TRACE_FILE_LAT_FMT;
iter.pos = -1;
- if (find_next_entry_inc(&iter) != NULL) {
+ if (trace_find_next_entry_inc(&iter) != NULL) {
int ret;
ret = print_trace_line(&iter);
@@ -4526,7 +4507,7 @@ __ftrace_dump(bool disable_tracing, enum ftrace_dump_mode oops_dump_mode)
trace_flags |= old_userobj;
for_each_tracing_cpu(cpu) {
- atomic_dec(&global_trace.data[cpu]->disabled);
+ atomic_dec(&iter.tr->data[cpu]->disabled);
}
tracing_on();
}
@@ -4575,16 +4556,14 @@ __init static int tracer_alloc_buffers(void)
#ifdef CONFIG_TRACER_MAX_TRACE
- max_tr.buffer = ring_buffer_alloc(ring_buf_size,
- TRACE_BUFFER_FLAGS);
+ max_tr.buffer = ring_buffer_alloc(1, TRACE_BUFFER_FLAGS);
if (!max_tr.buffer) {
printk(KERN_ERR "tracer: failed to allocate max ring buffer!\n");
WARN_ON(1);
ring_buffer_free(global_trace.buffer);
goto out_free_cpumask;
}
- max_tr.entries = ring_buffer_size(max_tr.buffer);
- WARN_ON(max_tr.entries != global_trace.entries);
+ max_tr.entries = 1;
#endif
/* Allocate the first page for all buffers */
@@ -4597,9 +4576,6 @@ __init static int tracer_alloc_buffers(void)
register_tracer(&nop_trace);
current_trace = &nop_trace;
-#ifdef CONFIG_BOOT_TRACER
- register_tracer(&boot_tracer);
-#endif
/* All seems OK, enable tracing */
tracing_disabled = 0;
diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h
index 2cd96399463..d39b3c5454a 100644
--- a/kernel/trace/trace.h
+++ b/kernel/trace/trace.h
@@ -9,10 +9,7 @@
#include <linux/mmiotrace.h>
#include <linux/tracepoint.h>
#include <linux/ftrace.h>
-#include <trace/boot.h>
-#include <linux/kmemtrace.h>
#include <linux/hw_breakpoint.h>
-
#include <linux/trace_seq.h>
#include <linux/ftrace_event.h>
@@ -25,30 +22,17 @@ enum trace_type {
TRACE_STACK,
TRACE_PRINT,
TRACE_BPRINT,
- TRACE_SPECIAL,
TRACE_MMIO_RW,
TRACE_MMIO_MAP,
TRACE_BRANCH,
- TRACE_BOOT_CALL,
- TRACE_BOOT_RET,
TRACE_GRAPH_RET,
TRACE_GRAPH_ENT,
TRACE_USER_STACK,
- TRACE_KMEM_ALLOC,
- TRACE_KMEM_FREE,
TRACE_BLK,
- TRACE_KSYM,
__TRACE_LAST_TYPE,
};
-enum kmemtrace_type_id {
- KMEMTRACE_TYPE_KMALLOC = 0, /* kmalloc() or kfree(). */
- KMEMTRACE_TYPE_CACHE, /* kmem_cache_*(). */
- KMEMTRACE_TYPE_PAGES, /* __get_free_pages() and friends. */
-};
-
-extern struct tracer boot_tracer;
#undef __field
#define __field(type, item) type item;
@@ -204,23 +188,15 @@ extern void __ftrace_bad_type(void);
IF_ASSIGN(var, ent, struct userstack_entry, TRACE_USER_STACK);\
IF_ASSIGN(var, ent, struct print_entry, TRACE_PRINT); \
IF_ASSIGN(var, ent, struct bprint_entry, TRACE_BPRINT); \
- IF_ASSIGN(var, ent, struct special_entry, 0); \
IF_ASSIGN(var, ent, struct trace_mmiotrace_rw, \
TRACE_MMIO_RW); \
IF_ASSIGN(var, ent, struct trace_mmiotrace_map, \
TRACE_MMIO_MAP); \
- IF_ASSIGN(var, ent, struct trace_boot_call, TRACE_BOOT_CALL);\
- IF_ASSIGN(var, ent, struct trace_boot_ret, TRACE_BOOT_RET);\
IF_ASSIGN(var, ent, struct trace_branch, TRACE_BRANCH); \
IF_ASSIGN(var, ent, struct ftrace_graph_ent_entry, \
TRACE_GRAPH_ENT); \
IF_ASSIGN(var, ent, struct ftrace_graph_ret_entry, \
TRACE_GRAPH_RET); \
- IF_ASSIGN(var, ent, struct kmemtrace_alloc_entry, \
- TRACE_KMEM_ALLOC); \
- IF_ASSIGN(var, ent, struct kmemtrace_free_entry, \
- TRACE_KMEM_FREE); \
- IF_ASSIGN(var, ent, struct ksym_trace_entry, TRACE_KSYM);\
__ftrace_bad_type(); \
} while (0)
@@ -298,6 +274,7 @@ struct tracer {
struct tracer *next;
int print_max;
struct tracer_flags *flags;
+ int use_max_tr;
};
@@ -318,7 +295,6 @@ struct dentry *trace_create_file(const char *name,
const struct file_operations *fops);
struct dentry *tracing_init_dentry(void);
-void init_tracer_sysprof_debugfs(struct dentry *d_tracer);
struct ring_buffer_event;
@@ -338,6 +314,14 @@ struct trace_entry *tracing_get_trace_entry(struct trace_array *tr,
struct trace_entry *trace_find_next_entry(struct trace_iterator *iter,
int *ent_cpu, u64 *ent_ts);
+int trace_empty(struct trace_iterator *iter);
+
+void *trace_find_next_entry_inc(struct trace_iterator *iter);
+
+void trace_init_global_iter(struct trace_iterator *iter);
+
+void tracing_iter_reset(struct trace_iterator *iter, int cpu);
+
void default_wait_pipe(struct trace_iterator *iter);
void poll_wait_pipe(struct trace_iterator *iter);
@@ -355,11 +339,6 @@ void tracing_sched_wakeup_trace(struct trace_array *tr,
struct task_struct *wakee,
struct task_struct *cur,
unsigned long flags, int pc);
-void trace_special(struct trace_array *tr,
- struct trace_array_cpu *data,
- unsigned long arg1,
- unsigned long arg2,
- unsigned long arg3, int pc);
void trace_function(struct trace_array *tr,
unsigned long ip,
unsigned long parent_ip,
@@ -380,8 +359,15 @@ void tracing_start_sched_switch_record(void);
int register_tracer(struct tracer *type);
void unregister_tracer(struct tracer *type);
int is_tracing_stopped(void);
+enum trace_file_type {
+ TRACE_FILE_LAT_FMT = 1,
+ TRACE_FILE_ANNOTATE = 2,
+};
+
+extern cpumask_var_t __read_mostly tracing_buffer_mask;
-extern int process_new_ksym_entry(char *ksymname, int op, unsigned long addr);
+#define for_each_tracing_cpu(cpu) \
+ for_each_cpu(cpu, tracing_buffer_mask)
extern unsigned long nsecs_to_usecs(unsigned long nsecs);
@@ -452,12 +438,8 @@ extern int trace_selftest_startup_nop(struct tracer *trace,
struct trace_array *tr);
extern int trace_selftest_startup_sched_switch(struct tracer *trace,
struct trace_array *tr);
-extern int trace_selftest_startup_sysprof(struct tracer *trace,
- struct trace_array *tr);
extern int trace_selftest_startup_branch(struct tracer *trace,
struct trace_array *tr);
-extern int trace_selftest_startup_ksym(struct tracer *trace,
- struct trace_array *tr);
#endif /* CONFIG_FTRACE_STARTUP_TEST */
extern void *head_page(struct trace_array_cpu *data);
@@ -471,6 +453,8 @@ trace_array_vprintk(struct trace_array *tr,
unsigned long ip, const char *fmt, va_list args);
int trace_array_printk(struct trace_array *tr,
unsigned long ip, const char *fmt, ...);
+void trace_printk_seq(struct trace_seq *s);
+enum print_line_t print_trace_line(struct trace_iterator *iter);
extern unsigned long trace_flags;
@@ -617,6 +601,7 @@ enum trace_iterator_flags {
TRACE_ITER_LATENCY_FMT = 0x20000,
TRACE_ITER_SLEEP_TIME = 0x40000,
TRACE_ITER_GRAPH_TIME = 0x80000,
+ TRACE_ITER_RECORD_CMD = 0x100000,
};
/*
@@ -628,54 +613,6 @@ enum trace_iterator_flags {
extern struct tracer nop_trace;
-/**
- * ftrace_preempt_disable - disable preemption scheduler safe
- *
- * When tracing can happen inside the scheduler, there exists
- * cases that the tracing might happen before the need_resched
- * flag is checked. If this happens and the tracer calls
- * preempt_enable (after a disable), a schedule might take place
- * causing an infinite recursion.
- *
- * To prevent this, we read the need_resched flag before
- * disabling preemption. When we want to enable preemption we
- * check the flag, if it is set, then we call preempt_enable_no_resched.
- * Otherwise, we call preempt_enable.
- *
- * The rational for doing the above is that if need_resched is set
- * and we have yet to reschedule, we are either in an atomic location
- * (where we do not need to check for scheduling) or we are inside
- * the scheduler and do not want to resched.
- */
-static inline int ftrace_preempt_disable(void)
-{
- int resched;
-
- resched = need_resched();
- preempt_disable_notrace();
-
- return resched;
-}
-
-/**
- * ftrace_preempt_enable - enable preemption scheduler safe
- * @resched: the return value from ftrace_preempt_disable
- *
- * This is a scheduler safe way to enable preemption and not miss
- * any preemption checks. The disabled saved the state of preemption.
- * If resched is set, then we are either inside an atomic or
- * are inside the scheduler (we would have already scheduled
- * otherwise). In this case, we do not want to call normal
- * preempt_enable, but preempt_enable_no_resched instead.
- */
-static inline void ftrace_preempt_enable(int resched)
-{
- if (resched)
- preempt_enable_no_resched_notrace();
- else
- preempt_enable_notrace();
-}
-
#ifdef CONFIG_BRANCH_TRACER
extern int enable_branch_tracing(struct trace_array *tr);
extern void disable_branch_tracing(void);
@@ -766,6 +703,8 @@ struct filter_pred {
int pop_n;
};
+extern struct list_head ftrace_common_fields;
+
extern enum regex_type
filter_parse_regex(char *buff, int len, char **search, int *not);
extern void print_event_filter(struct ftrace_event_call *call,
@@ -795,6 +734,8 @@ filter_check_discard(struct ftrace_event_call *call, void *rec,
return 0;
}
+extern void trace_event_enable_cmd_record(bool enable);
+
extern struct mutex event_mutex;
extern struct list_head ftrace_events;
diff --git a/kernel/trace/trace_boot.c b/kernel/trace/trace_boot.c
deleted file mode 100644
index c21d5f3956a..00000000000
--- a/kernel/trace/trace_boot.c
+++ /dev/null
@@ -1,185 +0,0 @@
-/*
- * ring buffer based initcalls tracer
- *
- * Copyright (C) 2008 Frederic Weisbecker <fweisbec@gmail.com>
- *
- */
-
-#include <linux/init.h>
-#include <linux/debugfs.h>
-#include <linux/ftrace.h>
-#include <linux/kallsyms.h>
-#include <linux/time.h>
-
-#include "trace.h"
-#include "trace_output.h"
-
-static struct trace_array *boot_trace;
-static bool pre_initcalls_finished;
-
-/* Tells the boot tracer that the pre_smp_initcalls are finished.
- * So we are ready .
- * It doesn't enable sched events tracing however.
- * You have to call enable_boot_trace to do so.
- */
-void start_boot_trace(void)
-{
- pre_initcalls_finished = true;
-}
-
-void enable_boot_trace(void)
-{
- if (boot_trace && pre_initcalls_finished)
- tracing_start_sched_switch_record();
-}
-
-void disable_boot_trace(void)
-{
- if (boot_trace && pre_initcalls_finished)
- tracing_stop_sched_switch_record();
-}
-
-static int boot_trace_init(struct trace_array *tr)
-{
- boot_trace = tr;
-
- if (!tr)
- return 0;
-
- tracing_reset_online_cpus(tr);
-
- tracing_sched_switch_assign_trace(tr);
- return 0;
-}
-
-static enum print_line_t
-initcall_call_print_line(struct trace_iterator *iter)
-{
- struct trace_entry *entry = iter->ent;
- struct trace_seq *s = &iter->seq;
- struct trace_boot_call *field;
- struct boot_trace_call *call;
- u64 ts;
- unsigned long nsec_rem;
- int ret;
-
- trace_assign_type(field, entry);
- call = &field->boot_call;
- ts = iter->ts;
- nsec_rem = do_div(ts, NSEC_PER_SEC);
-
- ret = trace_seq_printf(s, "[%5ld.%09ld] calling %s @ %i\n",
- (unsigned long)ts, nsec_rem, call->func, call->caller);
-
- if (!ret)
- return TRACE_TYPE_PARTIAL_LINE;
- else
- return TRACE_TYPE_HANDLED;
-}
-
-static enum print_line_t
-initcall_ret_print_line(struct trace_iterator *iter)
-{
- struct trace_entry *entry = iter->ent;
- struct trace_seq *s = &iter->seq;
- struct trace_boot_ret *field;
- struct boot_trace_ret *init_ret;
- u64 ts;
- unsigned long nsec_rem;
- int ret;
-
- trace_assign_type(field, entry);
- init_ret = &field->boot_ret;
- ts = iter->ts;
- nsec_rem = do_div(ts, NSEC_PER_SEC);
-
- ret = trace_seq_printf(s, "[%5ld.%09ld] initcall %s "
- "returned %d after %llu msecs\n",
- (unsigned long) ts,
- nsec_rem,
- init_ret->func, init_ret->result, init_ret->duration);
-
- if (!ret)
- return TRACE_TYPE_PARTIAL_LINE;
- else
- return TRACE_TYPE_HANDLED;
-}
-
-static enum print_line_t initcall_print_line(struct trace_iterator *iter)
-{
- struct trace_entry *entry = iter->ent;
-
- switch (entry->type) {
- case TRACE_BOOT_CALL:
- return initcall_call_print_line(iter);
- case TRACE_BOOT_RET:
- return initcall_ret_print_line(iter);
- default:
- return TRACE_TYPE_UNHANDLED;
- }
-}
-
-struct tracer boot_tracer __read_mostly =
-{
- .name = "initcall",
- .init = boot_trace_init,
- .reset = tracing_reset_online_cpus,
- .print_line = initcall_print_line,
-};
-
-void trace_boot_call(struct boot_trace_call *bt, initcall_t fn)
-{
- struct ftrace_event_call *call = &event_boot_call;
- struct ring_buffer_event *event;
- struct ring_buffer *buffer;
- struct trace_boot_call *entry;
- struct trace_array *tr = boot_trace;
-
- if (!tr || !pre_initcalls_finished)
- return;
-
- /* Get its name now since this function could
- * disappear because it is in the .init section.
- */
- sprint_symbol(bt->func, (unsigned long)fn);
- preempt_disable();
-
- buffer = tr->buffer;
- event = trace_buffer_lock_reserve(buffer, TRACE_BOOT_CALL,
- sizeof(*entry), 0, 0);
- if (!event)
- goto out;
- entry = ring_buffer_event_data(event);
- entry->boot_call = *bt;
- if (!filter_check_discard(call, entry, buffer, event))
- trace_buffer_unlock_commit(buffer, event, 0, 0);
- out:
- preempt_enable();
-}
-
-void trace_boot_ret(struct boot_trace_ret *bt, initcall_t fn)
-{
- struct ftrace_event_call *call = &event_boot_ret;
- struct ring_buffer_event *event;
- struct ring_buffer *buffer;
- struct trace_boot_ret *entry;
- struct trace_array *tr = boot_trace;
-
- if (!tr || !pre_initcalls_finished)
- return;
-
- sprint_symbol(bt->func, (unsigned long)fn);
- preempt_disable();
-
- buffer = tr->buffer;
- event = trace_buffer_lock_reserve(buffer, TRACE_BOOT_RET,
- sizeof(*entry), 0, 0);
- if (!event)
- goto out;
- entry = ring_buffer_event_data(event);
- entry->boot_ret = *bt;
- if (!filter_check_discard(call, entry, buffer, event))
- trace_buffer_unlock_commit(buffer, event, 0, 0);
- out:
- preempt_enable();
-}
diff --git a/kernel/trace/trace_clock.c b/kernel/trace/trace_clock.c
index 9d589d8dcd1..685a67d55db 100644
--- a/kernel/trace/trace_clock.c
+++ b/kernel/trace/trace_clock.c
@@ -32,16 +32,15 @@
u64 notrace trace_clock_local(void)
{
u64 clock;
- int resched;
/*
* sched_clock() is an architecture implemented, fast, scalable,
* lockless clock. It is not guaranteed to be coherent across
* CPUs, nor across CPU idle events.
*/
- resched = ftrace_preempt_disable();
+ preempt_disable_notrace();
clock = sched_clock();
- ftrace_preempt_enable(resched);
+ preempt_enable_notrace();
return clock;
}
@@ -56,7 +55,7 @@ u64 notrace trace_clock_local(void)
*/
u64 notrace trace_clock(void)
{
- return cpu_clock(raw_smp_processor_id());
+ return local_clock();
}
diff --git a/kernel/trace/trace_entries.h b/kernel/trace/trace_entries.h
index dc008c1240d..e3dfecaf13e 100644
--- a/kernel/trace/trace_entries.h
+++ b/kernel/trace/trace_entries.h
@@ -151,23 +151,6 @@ FTRACE_ENTRY_DUP(wakeup, ctx_switch_entry,
);
/*
- * Special (free-form) trace entry:
- */
-FTRACE_ENTRY(special, special_entry,
-
- TRACE_SPECIAL,
-
- F_STRUCT(
- __field( unsigned long, arg1 )
- __field( unsigned long, arg2 )
- __field( unsigned long, arg3 )
- ),
-
- F_printk("(%08lx) (%08lx) (%08lx)",
- __entry->arg1, __entry->arg2, __entry->arg3)
-);
-
-/*
* Stack-trace entry:
*/
@@ -271,33 +254,6 @@ FTRACE_ENTRY(mmiotrace_map, trace_mmiotrace_map,
__entry->map_id, __entry->opcode)
);
-FTRACE_ENTRY(boot_call, trace_boot_call,
-
- TRACE_BOOT_CALL,
-
- F_STRUCT(
- __field_struct( struct boot_trace_call, boot_call )
- __field_desc( pid_t, boot_call, caller )
- __array_desc( char, boot_call, func, KSYM_SYMBOL_LEN)
- ),
-
- F_printk("%d %s", __entry->caller, __entry->func)
-);
-
-FTRACE_ENTRY(boot_ret, trace_boot_ret,
-
- TRACE_BOOT_RET,
-
- F_STRUCT(
- __field_struct( struct boot_trace_ret, boot_ret )
- __array_desc( char, boot_ret, func, KSYM_SYMBOL_LEN)
- __field_desc( int, boot_ret, result )
- __field_desc( unsigned long, boot_ret, duration )
- ),
-
- F_printk("%s %d %lx",
- __entry->func, __entry->result, __entry->duration)
-);
#define TRACE_FUNC_SIZE 30
#define TRACE_FILE_SIZE 20
@@ -318,53 +274,3 @@ FTRACE_ENTRY(branch, trace_branch,
__entry->func, __entry->file, __entry->correct)
);
-FTRACE_ENTRY(kmem_alloc, kmemtrace_alloc_entry,
-
- TRACE_KMEM_ALLOC,
-
- F_STRUCT(
- __field( enum kmemtrace_type_id, type_id )
- __field( unsigned long, call_site )
- __field( const void *, ptr )
- __field( size_t, bytes_req )
- __field( size_t, bytes_alloc )
- __field( gfp_t, gfp_flags )
- __field( int, node )
- ),
-
- F_printk("type:%u call_site:%lx ptr:%p req:%zi alloc:%zi"
- " flags:%x node:%d",
- __entry->type_id, __entry->call_site, __entry->ptr,
- __entry->bytes_req, __entry->bytes_alloc,
- __entry->gfp_flags, __entry->node)
-);
-
-FTRACE_ENTRY(kmem_free, kmemtrace_free_entry,
-
- TRACE_KMEM_FREE,
-
- F_STRUCT(
- __field( enum kmemtrace_type_id, type_id )
- __field( unsigned long, call_site )
- __field( const void *, ptr )
- ),
-
- F_printk("type:%u call_site:%lx ptr:%p",
- __entry->type_id, __entry->call_site, __entry->ptr)
-);
-
-FTRACE_ENTRY(ksym_trace, ksym_trace_entry,
-
- TRACE_KSYM,
-
- F_STRUCT(
- __field( unsigned long, ip )
- __field( unsigned char, type )
- __array( char , cmd, TASK_COMM_LEN )
- __field( unsigned long, addr )
- ),
-
- F_printk("ip: %pF type: %d ksym_name: %pS cmd: %s",
- (void *)__entry->ip, (unsigned int)__entry->type,
- (void *)__entry->addr, __entry->cmd)
-);
diff --git a/kernel/trace/trace_event_perf.c b/kernel/trace/trace_event_perf.c
index 8a2b73f7c06..000e6e85b44 100644
--- a/kernel/trace/trace_event_perf.c
+++ b/kernel/trace/trace_event_perf.c
@@ -9,8 +9,6 @@
#include <linux/kprobes.h>
#include "trace.h"
-EXPORT_SYMBOL_GPL(perf_arch_fetch_caller_regs);
-
static char *perf_trace_buf[4];
/*
@@ -56,13 +54,7 @@ static int perf_trace_event_init(struct ftrace_event_call *tp_event,
}
}
- if (tp_event->class->reg)
- ret = tp_event->class->reg(tp_event, TRACE_REG_PERF_REGISTER);
- else
- ret = tracepoint_probe_register(tp_event->name,
- tp_event->class->perf_probe,
- tp_event);
-
+ ret = tp_event->class->reg(tp_event, TRACE_REG_PERF_REGISTER);
if (ret)
goto fail;
@@ -96,9 +88,7 @@ int perf_trace_init(struct perf_event *p_event)
mutex_lock(&event_mutex);
list_for_each_entry(tp_event, &ftrace_events, list) {
if (tp_event->event.type == event_id &&
- tp_event->class &&
- (tp_event->class->perf_probe ||
- tp_event->class->reg) &&
+ tp_event->class && tp_event->class->reg &&
try_module_get(tp_event->mod)) {
ret = perf_trace_event_init(tp_event, p_event);
break;
@@ -138,18 +128,13 @@ void perf_trace_destroy(struct perf_event *p_event)
if (--tp_event->perf_refcount > 0)
goto out;
- if (tp_event->class->reg)
- tp_event->class->reg(tp_event, TRACE_REG_PERF_UNREGISTER);
- else
- tracepoint_probe_unregister(tp_event->name,
- tp_event->class->perf_probe,
- tp_event);
+ tp_event->class->reg(tp_event, TRACE_REG_PERF_UNREGISTER);
/*
- * Ensure our callback won't be called anymore. See
- * tracepoint_probe_unregister() and __DO_TRACE().
+ * Ensure our callback won't be called anymore. The buffers
+ * will be freed after that.
*/
- synchronize_sched();
+ tracepoint_synchronize_unregister();
free_percpu(tp_event->perf_events);
tp_event->perf_events = NULL;
diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c
index 53cffc0b080..09b4fa6e4d3 100644
--- a/kernel/trace/trace_events.c
+++ b/kernel/trace/trace_events.c
@@ -28,6 +28,7 @@
DEFINE_MUTEX(event_mutex);
LIST_HEAD(ftrace_events);
+LIST_HEAD(ftrace_common_fields);
struct list_head *
trace_get_fields(struct ftrace_event_call *event_call)
@@ -37,15 +38,11 @@ trace_get_fields(struct ftrace_event_call *event_call)
return event_call->class->get_fields(event_call);
}
-int trace_define_field(struct ftrace_event_call *call, const char *type,
- const char *name, int offset, int size, int is_signed,
- int filter_type)
+static int __trace_define_field(struct list_head *head, const char *type,
+ const char *name, int offset, int size,
+ int is_signed, int filter_type)
{
struct ftrace_event_field *field;
- struct list_head *head;
-
- if (WARN_ON(!call->class))
- return 0;
field = kzalloc(sizeof(*field), GFP_KERNEL);
if (!field)
@@ -68,7 +65,6 @@ int trace_define_field(struct ftrace_event_call *call, const char *type,
field->size = size;
field->is_signed = is_signed;
- head = trace_get_fields(call);
list_add(&field->link, head);
return 0;
@@ -80,17 +76,32 @@ err:
return -ENOMEM;
}
+
+int trace_define_field(struct ftrace_event_call *call, const char *type,
+ const char *name, int offset, int size, int is_signed,
+ int filter_type)
+{
+ struct list_head *head;
+
+ if (WARN_ON(!call->class))
+ return 0;
+
+ head = trace_get_fields(call);
+ return __trace_define_field(head, type, name, offset, size,
+ is_signed, filter_type);
+}
EXPORT_SYMBOL_GPL(trace_define_field);
#define __common_field(type, item) \
- ret = trace_define_field(call, #type, "common_" #item, \
- offsetof(typeof(ent), item), \
- sizeof(ent.item), \
- is_signed_type(type), FILTER_OTHER); \
+ ret = __trace_define_field(&ftrace_common_fields, #type, \
+ "common_" #item, \
+ offsetof(typeof(ent), item), \
+ sizeof(ent.item), \
+ is_signed_type(type), FILTER_OTHER); \
if (ret) \
return ret;
-static int trace_define_common_fields(struct ftrace_event_call *call)
+static int trace_define_common_fields(void)
{
int ret;
struct trace_entry ent;
@@ -130,6 +141,55 @@ int trace_event_raw_init(struct ftrace_event_call *call)
}
EXPORT_SYMBOL_GPL(trace_event_raw_init);
+int ftrace_event_reg(struct ftrace_event_call *call, enum trace_reg type)
+{
+ switch (type) {
+ case TRACE_REG_REGISTER:
+ return tracepoint_probe_register(call->name,
+ call->class->probe,
+ call);
+ case TRACE_REG_UNREGISTER:
+ tracepoint_probe_unregister(call->name,
+ call->class->probe,
+ call);
+ return 0;
+
+#ifdef CONFIG_PERF_EVENTS
+ case TRACE_REG_PERF_REGISTER:
+ return tracepoint_probe_register(call->name,
+ call->class->perf_probe,
+ call);
+ case TRACE_REG_PERF_UNREGISTER:
+ tracepoint_probe_unregister(call->name,
+ call->class->perf_probe,
+ call);
+ return 0;
+#endif
+ }
+ return 0;
+}
+EXPORT_SYMBOL_GPL(ftrace_event_reg);
+
+void trace_event_enable_cmd_record(bool enable)
+{
+ struct ftrace_event_call *call;
+
+ mutex_lock(&event_mutex);
+ list_for_each_entry(call, &ftrace_events, list) {
+ if (!(call->flags & TRACE_EVENT_FL_ENABLED))
+ continue;
+
+ if (enable) {
+ tracing_start_cmdline_record();
+ call->flags |= TRACE_EVENT_FL_RECORDED_CMD;
+ } else {
+ tracing_stop_cmdline_record();
+ call->flags &= ~TRACE_EVENT_FL_RECORDED_CMD;
+ }
+ }
+ mutex_unlock(&event_mutex);
+}
+
static int ftrace_event_enable_disable(struct ftrace_event_call *call,
int enable)
{
@@ -139,24 +199,20 @@ static int ftrace_event_enable_disable(struct ftrace_event_call *call,
case 0:
if (call->flags & TRACE_EVENT_FL_ENABLED) {
call->flags &= ~TRACE_EVENT_FL_ENABLED;
- tracing_stop_cmdline_record();
- if (call->class->reg)
- call->class->reg(call, TRACE_REG_UNREGISTER);
- else
- tracepoint_probe_unregister(call->name,
- call->class->probe,
- call);
+ if (call->flags & TRACE_EVENT_FL_RECORDED_CMD) {
+ tracing_stop_cmdline_record();
+ call->flags &= ~TRACE_EVENT_FL_RECORDED_CMD;
+ }
+ call->class->reg(call, TRACE_REG_UNREGISTER);
}
break;
case 1:
if (!(call->flags & TRACE_EVENT_FL_ENABLED)) {
- tracing_start_cmdline_record();
- if (call->class->reg)
- ret = call->class->reg(call, TRACE_REG_REGISTER);
- else
- ret = tracepoint_probe_register(call->name,
- call->class->probe,
- call);
+ if (trace_flags & TRACE_ITER_RECORD_CMD) {
+ tracing_start_cmdline_record();
+ call->flags |= TRACE_EVENT_FL_RECORDED_CMD;
+ }
+ ret = call->class->reg(call, TRACE_REG_REGISTER);
if (ret) {
tracing_stop_cmdline_record();
pr_info("event trace: Could not enable event "
@@ -194,8 +250,7 @@ static int __ftrace_set_clr_event(const char *match, const char *sub,
mutex_lock(&event_mutex);
list_for_each_entry(call, &ftrace_events, list) {
- if (!call->name || !call->class ||
- (!call->class->probe && !call->class->reg))
+ if (!call->name || !call->class || !call->class->reg)
continue;
if (match &&
@@ -321,7 +376,7 @@ t_next(struct seq_file *m, void *v, loff_t *pos)
* The ftrace subsystem is for showing formats only.
* They can not be enabled or disabled via the event files.
*/
- if (call->class && (call->class->probe || call->class->reg))
+ if (call->class && call->class->reg)
return call;
}
@@ -474,8 +529,7 @@ system_enable_read(struct file *filp, char __user *ubuf, size_t cnt,
mutex_lock(&event_mutex);
list_for_each_entry(call, &ftrace_events, list) {
- if (!call->name || !call->class ||
- (!call->class->probe && !call->class->reg))
+ if (!call->name || !call->class || !call->class->reg)
continue;
if (system && strcmp(call->class->system, system) != 0)
@@ -544,32 +598,10 @@ out:
return ret;
}
-static ssize_t
-event_format_read(struct file *filp, char __user *ubuf, size_t cnt,
- loff_t *ppos)
+static void print_event_fields(struct trace_seq *s, struct list_head *head)
{
- struct ftrace_event_call *call = filp->private_data;
struct ftrace_event_field *field;
- struct list_head *head;
- struct trace_seq *s;
- int common_field_count = 5;
- char *buf;
- int r = 0;
-
- if (*ppos)
- return 0;
-
- s = kmalloc(sizeof(*s), GFP_KERNEL);
- if (!s)
- return -ENOMEM;
-
- trace_seq_init(s);
-
- trace_seq_printf(s, "name: %s\n", call->name);
- trace_seq_printf(s, "ID: %d\n", call->event.type);
- trace_seq_printf(s, "format:\n");
- head = trace_get_fields(call);
list_for_each_entry_reverse(field, head, link) {
/*
* Smartly shows the array type(except dynamic array).
@@ -584,29 +616,54 @@ event_format_read(struct file *filp, char __user *ubuf, size_t cnt,
array_descriptor = NULL;
if (!array_descriptor) {
- r = trace_seq_printf(s, "\tfield:%s %s;\toffset:%u;"
+ trace_seq_printf(s, "\tfield:%s %s;\toffset:%u;"
"\tsize:%u;\tsigned:%d;\n",
field->type, field->name, field->offset,
field->size, !!field->is_signed);
} else {
- r = trace_seq_printf(s, "\tfield:%.*s %s%s;\toffset:%u;"
+ trace_seq_printf(s, "\tfield:%.*s %s%s;\toffset:%u;"
"\tsize:%u;\tsigned:%d;\n",
(int)(array_descriptor - field->type),
field->type, field->name,
array_descriptor, field->offset,
field->size, !!field->is_signed);
}
+ }
+}
- if (--common_field_count == 0)
- r = trace_seq_printf(s, "\n");
+static ssize_t
+event_format_read(struct file *filp, char __user *ubuf, size_t cnt,
+ loff_t *ppos)
+{
+ struct ftrace_event_call *call = filp->private_data;
+ struct list_head *head;
+ struct trace_seq *s;
+ char *buf;
+ int r;
- if (!r)
- break;
- }
+ if (*ppos)
+ return 0;
+
+ s = kmalloc(sizeof(*s), GFP_KERNEL);
+ if (!s)
+ return -ENOMEM;
+
+ trace_seq_init(s);
+
+ trace_seq_printf(s, "name: %s\n", call->name);
+ trace_seq_printf(s, "ID: %d\n", call->event.type);
+ trace_seq_printf(s, "format:\n");
+
+ /* print common fields */
+ print_event_fields(s, &ftrace_common_fields);
- if (r)
- r = trace_seq_printf(s, "\nprint fmt: %s\n",
- call->print_fmt);
+ trace_seq_putc(s, '\n');
+
+ /* print event specific fields */
+ head = trace_get_fields(call);
+ print_event_fields(s, head);
+
+ r = trace_seq_printf(s, "\nprint fmt: %s\n", call->print_fmt);
if (!r) {
/*
@@ -963,35 +1020,31 @@ event_create_dir(struct ftrace_event_call *call, struct dentry *d_events,
return -1;
}
- if (call->class->probe || call->class->reg)
+ if (call->class->reg)
trace_create_file("enable", 0644, call->dir, call,
enable);
#ifdef CONFIG_PERF_EVENTS
- if (call->event.type && (call->class->perf_probe || call->class->reg))
+ if (call->event.type && call->class->reg)
trace_create_file("id", 0444, call->dir, call,
id);
#endif
- if (call->class->define_fields) {
- /*
- * Other events may have the same class. Only update
- * the fields if they are not already defined.
- */
- head = trace_get_fields(call);
- if (list_empty(head)) {
- ret = trace_define_common_fields(call);
- if (!ret)
- ret = call->class->define_fields(call);
- if (ret < 0) {
- pr_warning("Could not initialize trace point"
- " events/%s\n", call->name);
- return ret;
- }
+ /*
+ * Other events may have the same class. Only update
+ * the fields if they are not already defined.
+ */
+ head = trace_get_fields(call);
+ if (list_empty(head)) {
+ ret = call->class->define_fields(call);
+ if (ret < 0) {
+ pr_warning("Could not initialize trace point"
+ " events/%s\n", call->name);
+ return ret;
}
- trace_create_file("filter", 0644, call->dir, call,
- filter);
}
+ trace_create_file("filter", 0644, call->dir, call,
+ filter);
trace_create_file("format", 0444, call->dir, call,
format);
@@ -999,11 +1052,17 @@ event_create_dir(struct ftrace_event_call *call, struct dentry *d_events,
return 0;
}
-static int __trace_add_event_call(struct ftrace_event_call *call)
+static int
+__trace_add_event_call(struct ftrace_event_call *call, struct module *mod,
+ const struct file_operations *id,
+ const struct file_operations *enable,
+ const struct file_operations *filter,
+ const struct file_operations *format)
{
struct dentry *d_events;
int ret;
+ /* The linker may leave blanks */
if (!call->name)
return -EINVAL;
@@ -1011,8 +1070,8 @@ static int __trace_add_event_call(struct ftrace_event_call *call)
ret = call->class->raw_init(call);
if (ret < 0) {
if (ret != -ENOSYS)
- pr_warning("Could not initialize trace "
- "events/%s\n", call->name);
+ pr_warning("Could not initialize trace events/%s\n",
+ call->name);
return ret;
}
}
@@ -1021,11 +1080,10 @@ static int __trace_add_event_call(struct ftrace_event_call *call)
if (!d_events)
return -ENOENT;
- ret = event_create_dir(call, d_events, &ftrace_event_id_fops,
- &ftrace_enable_fops, &ftrace_event_filter_fops,
- &ftrace_event_format_fops);
+ ret = event_create_dir(call, d_events, id, enable, filter, format);
if (!ret)
list_add(&call->list, &ftrace_events);
+ call->mod = mod;
return ret;
}
@@ -1035,7 +1093,10 @@ int trace_add_event_call(struct ftrace_event_call *call)
{
int ret;
mutex_lock(&event_mutex);
- ret = __trace_add_event_call(call);
+ ret = __trace_add_event_call(call, NULL, &ftrace_event_id_fops,
+ &ftrace_enable_fops,
+ &ftrace_event_filter_fops,
+ &ftrace_event_format_fops);
mutex_unlock(&event_mutex);
return ret;
}
@@ -1152,8 +1213,6 @@ static void trace_module_add_events(struct module *mod)
{
struct ftrace_module_file_ops *file_ops = NULL;
struct ftrace_event_call *call, *start, *end;
- struct dentry *d_events;
- int ret;
start = mod->trace_events;
end = mod->trace_events + mod->num_trace_events;
@@ -1161,38 +1220,14 @@ static void trace_module_add_events(struct module *mod)
if (start == end)
return;
- d_events = event_trace_events_dir();
- if (!d_events)
+ file_ops = trace_create_file_ops(mod);
+ if (!file_ops)
return;
for_each_event(call, start, end) {
- /* The linker may leave blanks */
- if (!call->name)
- continue;
- if (call->class->raw_init) {
- ret = call->class->raw_init(call);
- if (ret < 0) {
- if (ret != -ENOSYS)
- pr_warning("Could not initialize trace "
- "point events/%s\n", call->name);
- continue;
- }
- }
- /*
- * This module has events, create file ops for this module
- * if not already done.
- */
- if (!file_ops) {
- file_ops = trace_create_file_ops(mod);
- if (!file_ops)
- return;
- }
- call->mod = mod;
- ret = event_create_dir(call, d_events,
+ __trace_add_event_call(call, mod,
&file_ops->id, &file_ops->enable,
&file_ops->filter, &file_ops->format);
- if (!ret)
- list_add(&call->list, &ftrace_events);
}
}
@@ -1319,25 +1354,14 @@ static __init int event_trace_init(void)
trace_create_file("enable", 0644, d_events,
NULL, &ftrace_system_enable_fops);
+ if (trace_define_common_fields())
+ pr_warning("tracing: Failed to allocate common fields");
+
for_each_event(call, __start_ftrace_events, __stop_ftrace_events) {
- /* The linker may leave blanks */
- if (!call->name)
- continue;
- if (call->class->raw_init) {
- ret = call->class->raw_init(call);
- if (ret < 0) {
- if (ret != -ENOSYS)
- pr_warning("Could not initialize trace "
- "point events/%s\n", call->name);
- continue;
- }
- }
- ret = event_create_dir(call, d_events, &ftrace_event_id_fops,
+ __trace_add_event_call(call, NULL, &ftrace_event_id_fops,
&ftrace_enable_fops,
&ftrace_event_filter_fops,
&ftrace_event_format_fops);
- if (!ret)
- list_add(&call->list, &ftrace_events);
}
while (true) {
@@ -1524,12 +1548,11 @@ function_test_events_call(unsigned long ip, unsigned long parent_ip)
struct ftrace_entry *entry;
unsigned long flags;
long disabled;
- int resched;
int cpu;
int pc;
pc = preempt_count();
- resched = ftrace_preempt_disable();
+ preempt_disable_notrace();
cpu = raw_smp_processor_id();
disabled = atomic_inc_return(&per_cpu(ftrace_test_event_disable, cpu));
@@ -1551,7 +1574,7 @@ function_test_events_call(unsigned long ip, unsigned long parent_ip)
out:
atomic_dec(&per_cpu(ftrace_test_event_disable, cpu));
- ftrace_preempt_enable(resched);
+ preempt_enable_notrace();
}
static struct ftrace_ops trace_ops __initdata =
diff --git a/kernel/trace/trace_events_filter.c b/kernel/trace/trace_events_filter.c
index 57bb1bb3299..36d40104b17 100644
--- a/kernel/trace/trace_events_filter.c
+++ b/kernel/trace/trace_events_filter.c
@@ -497,12 +497,10 @@ void print_subsystem_event_filter(struct event_subsystem *system,
}
static struct ftrace_event_field *
-find_event_field(struct ftrace_event_call *call, char *name)
+__find_event_field(struct list_head *head, char *name)
{
struct ftrace_event_field *field;
- struct list_head *head;
- head = trace_get_fields(call);
list_for_each_entry(field, head, link) {
if (!strcmp(field->name, name))
return field;
@@ -511,6 +509,20 @@ find_event_field(struct ftrace_event_call *call, char *name)
return NULL;
}
+static struct ftrace_event_field *
+find_event_field(struct ftrace_event_call *call, char *name)
+{
+ struct ftrace_event_field *field;
+ struct list_head *head;
+
+ field = __find_event_field(&ftrace_common_fields, name);
+ if (field)
+ return field;
+
+ head = trace_get_fields(call);
+ return __find_event_field(head, name);
+}
+
static void filter_free_pred(struct filter_pred *pred)
{
if (!pred)
@@ -627,9 +639,6 @@ static int init_subsystem_preds(struct event_subsystem *system)
int err;
list_for_each_entry(call, &ftrace_events, list) {
- if (!call->class || !call->class->define_fields)
- continue;
-
if (strcmp(call->class->system, system->name) != 0)
continue;
@@ -646,9 +655,6 @@ static void filter_free_subsystem_preds(struct event_subsystem *system)
struct ftrace_event_call *call;
list_for_each_entry(call, &ftrace_events, list) {
- if (!call->class || !call->class->define_fields)
- continue;
-
if (strcmp(call->class->system, system->name) != 0)
continue;
@@ -1251,9 +1257,6 @@ static int replace_system_preds(struct event_subsystem *system,
list_for_each_entry(call, &ftrace_events, list) {
struct event_filter *filter = call->filter;
- if (!call->class || !call->class->define_fields)
- continue;
-
if (strcmp(call->class->system, system->name) != 0)
continue;
diff --git a/kernel/trace/trace_export.c b/kernel/trace/trace_export.c
index 8536e2a6596..4ba44deaac2 100644
--- a/kernel/trace/trace_export.c
+++ b/kernel/trace/trace_export.c
@@ -125,12 +125,6 @@ ftrace_define_fields_##name(struct ftrace_event_call *event_call) \
#include "trace_entries.h"
-static int ftrace_raw_init_event(struct ftrace_event_call *call)
-{
- INIT_LIST_HEAD(&call->class->fields);
- return 0;
-}
-
#undef __entry
#define __entry REC
@@ -158,7 +152,7 @@ static int ftrace_raw_init_event(struct ftrace_event_call *call)
struct ftrace_event_class event_class_ftrace_##call = { \
.system = __stringify(TRACE_SYSTEM), \
.define_fields = ftrace_define_fields_##call, \
- .raw_init = ftrace_raw_init_event, \
+ .fields = LIST_HEAD_INIT(event_class_ftrace_##call.fields),\
}; \
\
struct ftrace_event_call __used \
diff --git a/kernel/trace/trace_functions.c b/kernel/trace/trace_functions.c
index b3f3776b0cd..16aee4d44e8 100644
--- a/kernel/trace/trace_functions.c
+++ b/kernel/trace/trace_functions.c
@@ -54,14 +54,14 @@ function_trace_call_preempt_only(unsigned long ip, unsigned long parent_ip)
struct trace_array_cpu *data;
unsigned long flags;
long disabled;
- int cpu, resched;
+ int cpu;
int pc;
if (unlikely(!ftrace_function_enabled))
return;
pc = preempt_count();
- resched = ftrace_preempt_disable();
+ preempt_disable_notrace();
local_save_flags(flags);
cpu = raw_smp_processor_id();
data = tr->data[cpu];
@@ -71,7 +71,7 @@ function_trace_call_preempt_only(unsigned long ip, unsigned long parent_ip)
trace_function(tr, ip, parent_ip, flags, pc);
atomic_dec(&data->disabled);
- ftrace_preempt_enable(resched);
+ preempt_enable_notrace();
}
static void
diff --git a/kernel/trace/trace_functions_graph.c b/kernel/trace/trace_functions_graph.c
index 79f4bac99a9..6bff2362578 100644
--- a/kernel/trace/trace_functions_graph.c
+++ b/kernel/trace/trace_functions_graph.c
@@ -641,7 +641,8 @@ trace_print_graph_duration(unsigned long long duration, struct trace_seq *s)
/* Print nsecs (we don't want to exceed 7 numbers) */
if (len < 7) {
- snprintf(nsecs_str, 8 - len, "%03lu", nsecs_rem);
+ snprintf(nsecs_str, min(sizeof(nsecs_str), 8UL - len), "%03lu",
+ nsecs_rem);
ret = trace_seq_printf(s, ".%s", nsecs_str);
if (!ret)
return TRACE_TYPE_PARTIAL_LINE;
diff --git a/kernel/trace/trace_irqsoff.c b/kernel/trace/trace_irqsoff.c
index 6fd486e0cef..73a6b0601f2 100644
--- a/kernel/trace/trace_irqsoff.c
+++ b/kernel/trace/trace_irqsoff.c
@@ -649,6 +649,7 @@ static struct tracer irqsoff_tracer __read_mostly =
#endif
.open = irqsoff_trace_open,
.close = irqsoff_trace_close,
+ .use_max_tr = 1,
};
# define register_irqsoff(trace) register_tracer(&trace)
#else
@@ -681,6 +682,7 @@ static struct tracer preemptoff_tracer __read_mostly =
#endif
.open = irqsoff_trace_open,
.close = irqsoff_trace_close,
+ .use_max_tr = 1,
};
# define register_preemptoff(trace) register_tracer(&trace)
#else
@@ -715,6 +717,7 @@ static struct tracer preemptirqsoff_tracer __read_mostly =
#endif
.open = irqsoff_trace_open,
.close = irqsoff_trace_close,
+ .use_max_tr = 1,
};
# define register_preemptirqsoff(trace) register_tracer(&trace)
diff --git a/kernel/trace/trace_kdb.c b/kernel/trace/trace_kdb.c
new file mode 100644
index 00000000000..7b8ecd751d9
--- /dev/null
+++ b/kernel/trace/trace_kdb.c
@@ -0,0 +1,136 @@
+/*
+ * kdb helper for dumping the ftrace buffer
+ *
+ * Copyright (C) 2010 Jason Wessel <jason.wessel@windriver.com>
+ *
+ * ftrace_dump_buf based on ftrace_dump:
+ * Copyright (C) 2007-2008 Steven Rostedt <srostedt@redhat.com>
+ * Copyright (C) 2008 Ingo Molnar <mingo@redhat.com>
+ *
+ */
+#include <linux/init.h>
+#include <linux/kgdb.h>
+#include <linux/kdb.h>
+#include <linux/ftrace.h>
+
+#include "../debug/kdb/kdb_private.h"
+#include "trace.h"
+#include "trace_output.h"
+
+static void ftrace_dump_buf(int skip_lines, long cpu_file)
+{
+ /* use static because iter can be a bit big for the stack */
+ static struct trace_iterator iter;
+ unsigned int old_userobj;
+ int cnt = 0, cpu;
+
+ trace_init_global_iter(&iter);
+
+ for_each_tracing_cpu(cpu) {
+ atomic_inc(&iter.tr->data[cpu]->disabled);
+ }
+
+ old_userobj = trace_flags;
+
+ /* don't look at user memory in panic mode */
+ trace_flags &= ~TRACE_ITER_SYM_USEROBJ;
+
+ kdb_printf("Dumping ftrace buffer:\n");
+
+ /* reset all but tr, trace, and overruns */
+ memset(&iter.seq, 0,
+ sizeof(struct trace_iterator) -
+ offsetof(struct trace_iterator, seq));
+ iter.iter_flags |= TRACE_FILE_LAT_FMT;
+ iter.pos = -1;
+
+ if (cpu_file == TRACE_PIPE_ALL_CPU) {
+ for_each_tracing_cpu(cpu) {
+ iter.buffer_iter[cpu] =
+ ring_buffer_read_prepare(iter.tr->buffer, cpu);
+ ring_buffer_read_start(iter.buffer_iter[cpu]);
+ tracing_iter_reset(&iter, cpu);
+ }
+ } else {
+ iter.cpu_file = cpu_file;
+ iter.buffer_iter[cpu_file] =
+ ring_buffer_read_prepare(iter.tr->buffer, cpu_file);
+ ring_buffer_read_start(iter.buffer_iter[cpu_file]);
+ tracing_iter_reset(&iter, cpu_file);
+ }
+ if (!trace_empty(&iter))
+ trace_find_next_entry_inc(&iter);
+ while (!trace_empty(&iter)) {
+ if (!cnt)
+ kdb_printf("---------------------------------\n");
+ cnt++;
+
+ if (trace_find_next_entry_inc(&iter) != NULL && !skip_lines)
+ print_trace_line(&iter);
+ if (!skip_lines)
+ trace_printk_seq(&iter.seq);
+ else
+ skip_lines--;
+ if (KDB_FLAG(CMD_INTERRUPT))
+ goto out;
+ }
+
+ if (!cnt)
+ kdb_printf(" (ftrace buffer empty)\n");
+ else
+ kdb_printf("---------------------------------\n");
+
+out:
+ trace_flags = old_userobj;
+
+ for_each_tracing_cpu(cpu) {
+ atomic_dec(&iter.tr->data[cpu]->disabled);
+ }
+
+ for_each_tracing_cpu(cpu)
+ if (iter.buffer_iter[cpu])
+ ring_buffer_read_finish(iter.buffer_iter[cpu]);
+}
+
+/*
+ * kdb_ftdump - Dump the ftrace log buffer
+ */
+static int kdb_ftdump(int argc, const char **argv)
+{
+ int skip_lines = 0;
+ long cpu_file;
+ char *cp;
+
+ if (argc > 2)
+ return KDB_ARGCOUNT;
+
+ if (argc) {
+ skip_lines = simple_strtol(argv[1], &cp, 0);
+ if (*cp)
+ skip_lines = 0;
+ }
+
+ if (argc == 2) {
+ cpu_file = simple_strtol(argv[2], &cp, 0);
+ if (*cp || cpu_file >= NR_CPUS || cpu_file < 0 ||
+ !cpu_online(cpu_file))
+ return KDB_BADINT;
+ } else {
+ cpu_file = TRACE_PIPE_ALL_CPU;
+ }
+
+ kdb_trap_printk++;
+ ftrace_dump_buf(skip_lines, cpu_file);
+ kdb_trap_printk--;
+
+ return 0;
+}
+
+static __init int kdb_ftrace_register(void)
+{
+ kdb_register_repeat("ftdump", kdb_ftdump, "[skip_#lines] [cpu]",
+ "Dump ftrace log", 0, KDB_REPEAT_NONE);
+ return 0;
+}
+
+late_initcall(kdb_ftrace_register);
diff --git a/kernel/trace/trace_kprobe.c b/kernel/trace/trace_kprobe.c
index f52b5f50299..8b27c9849b4 100644
--- a/kernel/trace/trace_kprobe.c
+++ b/kernel/trace/trace_kprobe.c
@@ -30,6 +30,8 @@
#include <linux/ptrace.h>
#include <linux/perf_event.h>
#include <linux/stringify.h>
+#include <linux/limits.h>
+#include <linux/uaccess.h>
#include <asm/bitsperlong.h>
#include "trace.h"
@@ -38,6 +40,7 @@
#define MAX_TRACE_ARGS 128
#define MAX_ARGSTR_LEN 63
#define MAX_EVENT_NAME_LEN 64
+#define MAX_STRING_SIZE PATH_MAX
#define KPROBE_EVENT_SYSTEM "kprobes"
/* Reserved field names */
@@ -58,14 +61,16 @@ const char *reserved_field_names[] = {
};
/* Printing function type */
-typedef int (*print_type_func_t)(struct trace_seq *, const char *, void *);
+typedef int (*print_type_func_t)(struct trace_seq *, const char *, void *,
+ void *);
#define PRINT_TYPE_FUNC_NAME(type) print_type_##type
#define PRINT_TYPE_FMT_NAME(type) print_type_format_##type
/* Printing in basic type function template */
#define DEFINE_BASIC_PRINT_TYPE_FUNC(type, fmt, cast) \
static __kprobes int PRINT_TYPE_FUNC_NAME(type)(struct trace_seq *s, \
- const char *name, void *data)\
+ const char *name, \
+ void *data, void *ent)\
{ \
return trace_seq_printf(s, " %s=" fmt, name, (cast)*(type *)data);\
} \
@@ -80,6 +85,49 @@ DEFINE_BASIC_PRINT_TYPE_FUNC(s16, "%d", int)
DEFINE_BASIC_PRINT_TYPE_FUNC(s32, "%ld", long)
DEFINE_BASIC_PRINT_TYPE_FUNC(s64, "%lld", long long)
+/* data_rloc: data relative location, compatible with u32 */
+#define make_data_rloc(len, roffs) \
+ (((u32)(len) << 16) | ((u32)(roffs) & 0xffff))
+#define get_rloc_len(dl) ((u32)(dl) >> 16)
+#define get_rloc_offs(dl) ((u32)(dl) & 0xffff)
+
+static inline void *get_rloc_data(u32 *dl)
+{
+ return (u8 *)dl + get_rloc_offs(*dl);
+}
+
+/* For data_loc conversion */
+static inline void *get_loc_data(u32 *dl, void *ent)
+{
+ return (u8 *)ent + get_rloc_offs(*dl);
+}
+
+/*
+ * Convert data_rloc to data_loc:
+ * data_rloc stores the offset from data_rloc itself, but data_loc
+ * stores the offset from event entry.
+ */
+#define convert_rloc_to_loc(dl, offs) ((u32)(dl) + (offs))
+
+/* For defining macros, define string/string_size types */
+typedef u32 string;
+typedef u32 string_size;
+
+/* Print type function for string type */
+static __kprobes int PRINT_TYPE_FUNC_NAME(string)(struct trace_seq *s,
+ const char *name,
+ void *data, void *ent)
+{
+ int len = *(u32 *)data >> 16;
+
+ if (!len)
+ return trace_seq_printf(s, " %s=(fault)", name);
+ else
+ return trace_seq_printf(s, " %s=\"%s\"", name,
+ (const char *)get_loc_data(data, ent));
+}
+static const char PRINT_TYPE_FMT_NAME(string)[] = "\\\"%s\\\"";
+
/* Data fetch function type */
typedef void (*fetch_func_t)(struct pt_regs *, void *, void *);
@@ -94,32 +142,38 @@ static __kprobes void call_fetch(struct fetch_param *fprm,
return fprm->fn(regs, fprm->data, dest);
}
-#define FETCH_FUNC_NAME(kind, type) fetch_##kind##_##type
+#define FETCH_FUNC_NAME(method, type) fetch_##method##_##type
/*
* Define macro for basic types - we don't need to define s* types, because
* we have to care only about bitwidth at recording time.
*/
-#define DEFINE_BASIC_FETCH_FUNCS(kind) \
-DEFINE_FETCH_##kind(u8) \
-DEFINE_FETCH_##kind(u16) \
-DEFINE_FETCH_##kind(u32) \
-DEFINE_FETCH_##kind(u64)
-
-#define CHECK_BASIC_FETCH_FUNCS(kind, fn) \
- ((FETCH_FUNC_NAME(kind, u8) == fn) || \
- (FETCH_FUNC_NAME(kind, u16) == fn) || \
- (FETCH_FUNC_NAME(kind, u32) == fn) || \
- (FETCH_FUNC_NAME(kind, u64) == fn))
+#define DEFINE_BASIC_FETCH_FUNCS(method) \
+DEFINE_FETCH_##method(u8) \
+DEFINE_FETCH_##method(u16) \
+DEFINE_FETCH_##method(u32) \
+DEFINE_FETCH_##method(u64)
+
+#define CHECK_FETCH_FUNCS(method, fn) \
+ (((FETCH_FUNC_NAME(method, u8) == fn) || \
+ (FETCH_FUNC_NAME(method, u16) == fn) || \
+ (FETCH_FUNC_NAME(method, u32) == fn) || \
+ (FETCH_FUNC_NAME(method, u64) == fn) || \
+ (FETCH_FUNC_NAME(method, string) == fn) || \
+ (FETCH_FUNC_NAME(method, string_size) == fn)) \
+ && (fn != NULL))
/* Data fetch function templates */
#define DEFINE_FETCH_reg(type) \
static __kprobes void FETCH_FUNC_NAME(reg, type)(struct pt_regs *regs, \
- void *offset, void *dest) \
+ void *offset, void *dest) \
{ \
*(type *)dest = (type)regs_get_register(regs, \
(unsigned int)((unsigned long)offset)); \
}
DEFINE_BASIC_FETCH_FUNCS(reg)
+/* No string on the register */
+#define fetch_reg_string NULL
+#define fetch_reg_string_size NULL
#define DEFINE_FETCH_stack(type) \
static __kprobes void FETCH_FUNC_NAME(stack, type)(struct pt_regs *regs,\
@@ -129,6 +183,9 @@ static __kprobes void FETCH_FUNC_NAME(stack, type)(struct pt_regs *regs,\
(unsigned int)((unsigned long)offset)); \
}
DEFINE_BASIC_FETCH_FUNCS(stack)
+/* No string on the stack entry */
+#define fetch_stack_string NULL
+#define fetch_stack_string_size NULL
#define DEFINE_FETCH_retval(type) \
static __kprobes void FETCH_FUNC_NAME(retval, type)(struct pt_regs *regs,\
@@ -137,6 +194,9 @@ static __kprobes void FETCH_FUNC_NAME(retval, type)(struct pt_regs *regs,\
*(type *)dest = (type)regs_return_value(regs); \
}
DEFINE_BASIC_FETCH_FUNCS(retval)
+/* No string on the retval */
+#define fetch_retval_string NULL
+#define fetch_retval_string_size NULL
#define DEFINE_FETCH_memory(type) \
static __kprobes void FETCH_FUNC_NAME(memory, type)(struct pt_regs *regs,\
@@ -149,6 +209,62 @@ static __kprobes void FETCH_FUNC_NAME(memory, type)(struct pt_regs *regs,\
*(type *)dest = retval; \
}
DEFINE_BASIC_FETCH_FUNCS(memory)
+/*
+ * Fetch a null-terminated string. Caller MUST set *(u32 *)dest with max
+ * length and relative data location.
+ */
+static __kprobes void FETCH_FUNC_NAME(memory, string)(struct pt_regs *regs,
+ void *addr, void *dest)
+{
+ long ret;
+ int maxlen = get_rloc_len(*(u32 *)dest);
+ u8 *dst = get_rloc_data(dest);
+ u8 *src = addr;
+ mm_segment_t old_fs = get_fs();
+ if (!maxlen)
+ return;
+ /*
+ * Try to get string again, since the string can be changed while
+ * probing.
+ */
+ set_fs(KERNEL_DS);
+ pagefault_disable();
+ do
+ ret = __copy_from_user_inatomic(dst++, src++, 1);
+ while (dst[-1] && ret == 0 && src - (u8 *)addr < maxlen);
+ dst[-1] = '\0';
+ pagefault_enable();
+ set_fs(old_fs);
+
+ if (ret < 0) { /* Failed to fetch string */
+ ((u8 *)get_rloc_data(dest))[0] = '\0';
+ *(u32 *)dest = make_data_rloc(0, get_rloc_offs(*(u32 *)dest));
+ } else
+ *(u32 *)dest = make_data_rloc(src - (u8 *)addr,
+ get_rloc_offs(*(u32 *)dest));
+}
+/* Return the length of string -- including null terminal byte */
+static __kprobes void FETCH_FUNC_NAME(memory, string_size)(struct pt_regs *regs,
+ void *addr, void *dest)
+{
+ int ret, len = 0;
+ u8 c;
+ mm_segment_t old_fs = get_fs();
+
+ set_fs(KERNEL_DS);
+ pagefault_disable();
+ do {
+ ret = __copy_from_user_inatomic(&c, (u8 *)addr + len, 1);
+ len++;
+ } while (c && ret == 0 && len < MAX_STRING_SIZE);
+ pagefault_enable();
+ set_fs(old_fs);
+
+ if (ret < 0) /* Failed to check the length */
+ *(u32 *)dest = 0;
+ else
+ *(u32 *)dest = len;
+}
/* Memory fetching by symbol */
struct symbol_cache {
@@ -203,6 +319,8 @@ static __kprobes void FETCH_FUNC_NAME(symbol, type)(struct pt_regs *regs,\
*(type *)dest = 0; \
}
DEFINE_BASIC_FETCH_FUNCS(symbol)
+DEFINE_FETCH_symbol(string)
+DEFINE_FETCH_symbol(string_size)
/* Dereference memory access function */
struct deref_fetch_param {
@@ -224,12 +342,14 @@ static __kprobes void FETCH_FUNC_NAME(deref, type)(struct pt_regs *regs,\
*(type *)dest = 0; \
}
DEFINE_BASIC_FETCH_FUNCS(deref)
+DEFINE_FETCH_deref(string)
+DEFINE_FETCH_deref(string_size)
static __kprobes void free_deref_fetch_param(struct deref_fetch_param *data)
{
- if (CHECK_BASIC_FETCH_FUNCS(deref, data->orig.fn))
+ if (CHECK_FETCH_FUNCS(deref, data->orig.fn))
free_deref_fetch_param(data->orig.data);
- else if (CHECK_BASIC_FETCH_FUNCS(symbol, data->orig.fn))
+ else if (CHECK_FETCH_FUNCS(symbol, data->orig.fn))
free_symbol_cache(data->orig.data);
kfree(data);
}
@@ -240,23 +360,43 @@ static __kprobes void free_deref_fetch_param(struct deref_fetch_param *data)
#define DEFAULT_FETCH_TYPE _DEFAULT_FETCH_TYPE(BITS_PER_LONG)
#define DEFAULT_FETCH_TYPE_STR __stringify(DEFAULT_FETCH_TYPE)
-#define ASSIGN_FETCH_FUNC(kind, type) \
- .kind = FETCH_FUNC_NAME(kind, type)
-
-#define ASSIGN_FETCH_TYPE(ptype, ftype, sign) \
- {.name = #ptype, \
- .size = sizeof(ftype), \
- .is_signed = sign, \
- .print = PRINT_TYPE_FUNC_NAME(ptype), \
- .fmt = PRINT_TYPE_FMT_NAME(ptype), \
-ASSIGN_FETCH_FUNC(reg, ftype), \
-ASSIGN_FETCH_FUNC(stack, ftype), \
-ASSIGN_FETCH_FUNC(retval, ftype), \
-ASSIGN_FETCH_FUNC(memory, ftype), \
-ASSIGN_FETCH_FUNC(symbol, ftype), \
-ASSIGN_FETCH_FUNC(deref, ftype), \
+/* Fetch types */
+enum {
+ FETCH_MTD_reg = 0,
+ FETCH_MTD_stack,
+ FETCH_MTD_retval,
+ FETCH_MTD_memory,
+ FETCH_MTD_symbol,
+ FETCH_MTD_deref,
+ FETCH_MTD_END,
+};
+
+#define ASSIGN_FETCH_FUNC(method, type) \
+ [FETCH_MTD_##method] = FETCH_FUNC_NAME(method, type)
+
+#define __ASSIGN_FETCH_TYPE(_name, ptype, ftype, _size, sign, _fmttype) \
+ {.name = _name, \
+ .size = _size, \
+ .is_signed = sign, \
+ .print = PRINT_TYPE_FUNC_NAME(ptype), \
+ .fmt = PRINT_TYPE_FMT_NAME(ptype), \
+ .fmttype = _fmttype, \
+ .fetch = { \
+ASSIGN_FETCH_FUNC(reg, ftype), \
+ASSIGN_FETCH_FUNC(stack, ftype), \
+ASSIGN_FETCH_FUNC(retval, ftype), \
+ASSIGN_FETCH_FUNC(memory, ftype), \
+ASSIGN_FETCH_FUNC(symbol, ftype), \
+ASSIGN_FETCH_FUNC(deref, ftype), \
+ } \
}
+#define ASSIGN_FETCH_TYPE(ptype, ftype, sign) \
+ __ASSIGN_FETCH_TYPE(#ptype, ptype, ftype, sizeof(ftype), sign, #ptype)
+
+#define FETCH_TYPE_STRING 0
+#define FETCH_TYPE_STRSIZE 1
+
/* Fetch type information table */
static const struct fetch_type {
const char *name; /* Name of type */
@@ -264,14 +404,16 @@ static const struct fetch_type {
int is_signed; /* Signed flag */
print_type_func_t print; /* Print functions */
const char *fmt; /* Fromat string */
+ const char *fmttype; /* Name in format file */
/* Fetch functions */
- fetch_func_t reg;
- fetch_func_t stack;
- fetch_func_t retval;
- fetch_func_t memory;
- fetch_func_t symbol;
- fetch_func_t deref;
+ fetch_func_t fetch[FETCH_MTD_END];
} fetch_type_table[] = {
+ /* Special types */
+ [FETCH_TYPE_STRING] = __ASSIGN_FETCH_TYPE("string", string, string,
+ sizeof(u32), 1, "__data_loc char[]"),
+ [FETCH_TYPE_STRSIZE] = __ASSIGN_FETCH_TYPE("string_size", u32,
+ string_size, sizeof(u32), 0, "u32"),
+ /* Basic types */
ASSIGN_FETCH_TYPE(u8, u8, 0),
ASSIGN_FETCH_TYPE(u16, u16, 0),
ASSIGN_FETCH_TYPE(u32, u32, 0),
@@ -302,12 +444,28 @@ static __kprobes void fetch_stack_address(struct pt_regs *regs,
*(unsigned long *)dest = kernel_stack_pointer(regs);
}
+static fetch_func_t get_fetch_size_function(const struct fetch_type *type,
+ fetch_func_t orig_fn)
+{
+ int i;
+
+ if (type != &fetch_type_table[FETCH_TYPE_STRING])
+ return NULL; /* Only string type needs size function */
+ for (i = 0; i < FETCH_MTD_END; i++)
+ if (type->fetch[i] == orig_fn)
+ return fetch_type_table[FETCH_TYPE_STRSIZE].fetch[i];
+
+ WARN_ON(1); /* This should not happen */
+ return NULL;
+}
+
/**
* Kprobe event core functions
*/
struct probe_arg {
struct fetch_param fetch;
+ struct fetch_param fetch_size;
unsigned int offset; /* Offset from argument entry */
const char *name; /* Name of this argument */
const char *comm; /* Command of this argument */
@@ -429,9 +587,9 @@ error:
static void free_probe_arg(struct probe_arg *arg)
{
- if (CHECK_BASIC_FETCH_FUNCS(deref, arg->fetch.fn))
+ if (CHECK_FETCH_FUNCS(deref, arg->fetch.fn))
free_deref_fetch_param(arg->fetch.data);
- else if (CHECK_BASIC_FETCH_FUNCS(symbol, arg->fetch.fn))
+ else if (CHECK_FETCH_FUNCS(symbol, arg->fetch.fn))
free_symbol_cache(arg->fetch.data);
kfree(arg->name);
kfree(arg->comm);
@@ -548,7 +706,7 @@ static int parse_probe_vars(char *arg, const struct fetch_type *t,
if (strcmp(arg, "retval") == 0) {
if (is_return)
- f->fn = t->retval;
+ f->fn = t->fetch[FETCH_MTD_retval];
else
ret = -EINVAL;
} else if (strncmp(arg, "stack", 5) == 0) {
@@ -562,7 +720,7 @@ static int parse_probe_vars(char *arg, const struct fetch_type *t,
if (ret || param > PARAM_MAX_STACK)
ret = -EINVAL;
else {
- f->fn = t->stack;
+ f->fn = t->fetch[FETCH_MTD_stack];
f->data = (void *)param;
}
} else
@@ -588,7 +746,7 @@ static int __parse_probe_arg(char *arg, const struct fetch_type *t,
case '%': /* named register */
ret = regs_query_register_offset(arg + 1);
if (ret >= 0) {
- f->fn = t->reg;
+ f->fn = t->fetch[FETCH_MTD_reg];
f->data = (void *)(unsigned long)ret;
ret = 0;
}
@@ -598,7 +756,7 @@ static int __parse_probe_arg(char *arg, const struct fetch_type *t,
ret = strict_strtoul(arg + 1, 0, &param);
if (ret)
break;
- f->fn = t->memory;
+ f->fn = t->fetch[FETCH_MTD_memory];
f->data = (void *)param;
} else {
ret = split_symbol_offset(arg + 1, &offset);
@@ -606,7 +764,7 @@ static int __parse_probe_arg(char *arg, const struct fetch_type *t,
break;
f->data = alloc_symbol_cache(arg + 1, offset);
if (f->data)
- f->fn = t->symbol;
+ f->fn = t->fetch[FETCH_MTD_symbol];
}
break;
case '+': /* deref memory */
@@ -636,14 +794,17 @@ static int __parse_probe_arg(char *arg, const struct fetch_type *t,
if (ret)
kfree(dprm);
else {
- f->fn = t->deref;
+ f->fn = t->fetch[FETCH_MTD_deref];
f->data = (void *)dprm;
}
}
break;
}
- if (!ret && !f->fn)
+ if (!ret && !f->fn) { /* Parsed, but do not find fetch method */
+ pr_info("%s type has no corresponding fetch method.\n",
+ t->name);
ret = -EINVAL;
+ }
return ret;
}
@@ -652,6 +813,7 @@ static int parse_probe_arg(char *arg, struct trace_probe *tp,
struct probe_arg *parg, int is_return)
{
const char *t;
+ int ret;
if (strlen(arg) > MAX_ARGSTR_LEN) {
pr_info("Argument is too long.: %s\n", arg);
@@ -674,7 +836,13 @@ static int parse_probe_arg(char *arg, struct trace_probe *tp,
}
parg->offset = tp->size;
tp->size += parg->type->size;
- return __parse_probe_arg(arg, parg->type, &parg->fetch, is_return);
+ ret = __parse_probe_arg(arg, parg->type, &parg->fetch, is_return);
+ if (ret >= 0) {
+ parg->fetch_size.fn = get_fetch_size_function(parg->type,
+ parg->fetch.fn);
+ parg->fetch_size.data = parg->fetch.data;
+ }
+ return ret;
}
/* Return 1 if name is reserved or already used by another argument */
@@ -757,14 +925,17 @@ static int create_trace_probe(int argc, char **argv)
pr_info("Delete command needs an event name.\n");
return -EINVAL;
}
+ mutex_lock(&probe_lock);
tp = find_probe_event(event, group);
if (!tp) {
+ mutex_unlock(&probe_lock);
pr_info("Event %s/%s doesn't exist.\n", group, event);
return -ENOENT;
}
/* delete an event */
unregister_trace_probe(tp);
free_trace_probe(tp);
+ mutex_unlock(&probe_lock);
return 0;
}
@@ -1043,6 +1214,54 @@ static const struct file_operations kprobe_profile_ops = {
.release = seq_release,
};
+/* Sum up total data length for dynamic arraies (strings) */
+static __kprobes int __get_data_size(struct trace_probe *tp,
+ struct pt_regs *regs)
+{
+ int i, ret = 0;
+ u32 len;
+
+ for (i = 0; i < tp->nr_args; i++)
+ if (unlikely(tp->args[i].fetch_size.fn)) {
+ call_fetch(&tp->args[i].fetch_size, regs, &len);
+ ret += len;
+ }
+
+ return ret;
+}
+
+/* Store the value of each argument */
+static __kprobes void store_trace_args(int ent_size, struct trace_probe *tp,
+ struct pt_regs *regs,
+ u8 *data, int maxlen)
+{
+ int i;
+ u32 end = tp->size;
+ u32 *dl; /* Data (relative) location */
+
+ for (i = 0; i < tp->nr_args; i++) {
+ if (unlikely(tp->args[i].fetch_size.fn)) {
+ /*
+ * First, we set the relative location and
+ * maximum data length to *dl
+ */
+ dl = (u32 *)(data + tp->args[i].offset);
+ *dl = make_data_rloc(maxlen, end - tp->args[i].offset);
+ /* Then try to fetch string or dynamic array data */
+ call_fetch(&tp->args[i].fetch, regs, dl);
+ /* Reduce maximum length */
+ end += get_rloc_len(*dl);
+ maxlen -= get_rloc_len(*dl);
+ /* Trick here, convert data_rloc to data_loc */
+ *dl = convert_rloc_to_loc(*dl,
+ ent_size + tp->args[i].offset);
+ } else
+ /* Just fetching data normally */
+ call_fetch(&tp->args[i].fetch, regs,
+ data + tp->args[i].offset);
+ }
+}
+
/* Kprobe handler */
static __kprobes void kprobe_trace_func(struct kprobe *kp, struct pt_regs *regs)
{
@@ -1050,8 +1269,7 @@ static __kprobes void kprobe_trace_func(struct kprobe *kp, struct pt_regs *regs)
struct kprobe_trace_entry_head *entry;
struct ring_buffer_event *event;
struct ring_buffer *buffer;
- u8 *data;
- int size, i, pc;
+ int size, dsize, pc;
unsigned long irq_flags;
struct ftrace_event_call *call = &tp->call;
@@ -1060,7 +1278,8 @@ static __kprobes void kprobe_trace_func(struct kprobe *kp, struct pt_regs *regs)
local_save_flags(irq_flags);
pc = preempt_count();
- size = sizeof(*entry) + tp->size;
+ dsize = __get_data_size(tp, regs);
+ size = sizeof(*entry) + tp->size + dsize;
event = trace_current_buffer_lock_reserve(&buffer, call->event.type,
size, irq_flags, pc);
@@ -1069,9 +1288,7 @@ static __kprobes void kprobe_trace_func(struct kprobe *kp, struct pt_regs *regs)
entry = ring_buffer_event_data(event);
entry->ip = (unsigned long)kp->addr;
- data = (u8 *)&entry[1];
- for (i = 0; i < tp->nr_args; i++)
- call_fetch(&tp->args[i].fetch, regs, data + tp->args[i].offset);
+ store_trace_args(sizeof(*entry), tp, regs, (u8 *)&entry[1], dsize);
if (!filter_current_check_discard(buffer, call, entry, event))
trace_nowake_buffer_unlock_commit(buffer, event, irq_flags, pc);
@@ -1085,15 +1302,15 @@ static __kprobes void kretprobe_trace_func(struct kretprobe_instance *ri,
struct kretprobe_trace_entry_head *entry;
struct ring_buffer_event *event;
struct ring_buffer *buffer;
- u8 *data;
- int size, i, pc;
+ int size, pc, dsize;
unsigned long irq_flags;
struct ftrace_event_call *call = &tp->call;
local_save_flags(irq_flags);
pc = preempt_count();
- size = sizeof(*entry) + tp->size;
+ dsize = __get_data_size(tp, regs);
+ size = sizeof(*entry) + tp->size + dsize;
event = trace_current_buffer_lock_reserve(&buffer, call->event.type,
size, irq_flags, pc);
@@ -1103,9 +1320,7 @@ static __kprobes void kretprobe_trace_func(struct kretprobe_instance *ri,
entry = ring_buffer_event_data(event);
entry->func = (unsigned long)tp->rp.kp.addr;
entry->ret_ip = (unsigned long)ri->ret_addr;
- data = (u8 *)&entry[1];
- for (i = 0; i < tp->nr_args; i++)
- call_fetch(&tp->args[i].fetch, regs, data + tp->args[i].offset);
+ store_trace_args(sizeof(*entry), tp, regs, (u8 *)&entry[1], dsize);
if (!filter_current_check_discard(buffer, call, entry, event))
trace_nowake_buffer_unlock_commit(buffer, event, irq_flags, pc);
@@ -1137,7 +1352,7 @@ print_kprobe_event(struct trace_iterator *iter, int flags,
data = (u8 *)&field[1];
for (i = 0; i < tp->nr_args; i++)
if (!tp->args[i].type->print(s, tp->args[i].name,
- data + tp->args[i].offset))
+ data + tp->args[i].offset, field))
goto partial;
if (!trace_seq_puts(s, "\n"))
@@ -1179,7 +1394,7 @@ print_kretprobe_event(struct trace_iterator *iter, int flags,
data = (u8 *)&field[1];
for (i = 0; i < tp->nr_args; i++)
if (!tp->args[i].type->print(s, tp->args[i].name,
- data + tp->args[i].offset))
+ data + tp->args[i].offset, field))
goto partial;
if (!trace_seq_puts(s, "\n"))
@@ -1214,11 +1429,6 @@ static void probe_event_disable(struct ftrace_event_call *call)
}
}
-static int probe_event_raw_init(struct ftrace_event_call *event_call)
-{
- return 0;
-}
-
#undef DEFINE_FIELD
#define DEFINE_FIELD(type, item, name, is_signed) \
do { \
@@ -1239,7 +1449,7 @@ static int kprobe_event_define_fields(struct ftrace_event_call *event_call)
DEFINE_FIELD(unsigned long, ip, FIELD_STRING_IP, 0);
/* Set argument names as fields */
for (i = 0; i < tp->nr_args; i++) {
- ret = trace_define_field(event_call, tp->args[i].type->name,
+ ret = trace_define_field(event_call, tp->args[i].type->fmttype,
tp->args[i].name,
sizeof(field) + tp->args[i].offset,
tp->args[i].type->size,
@@ -1261,7 +1471,7 @@ static int kretprobe_event_define_fields(struct ftrace_event_call *event_call)
DEFINE_FIELD(unsigned long, ret_ip, FIELD_STRING_RETIP, 0);
/* Set argument names as fields */
for (i = 0; i < tp->nr_args; i++) {
- ret = trace_define_field(event_call, tp->args[i].type->name,
+ ret = trace_define_field(event_call, tp->args[i].type->fmttype,
tp->args[i].name,
sizeof(field) + tp->args[i].offset,
tp->args[i].type->size,
@@ -1301,8 +1511,13 @@ static int __set_print_fmt(struct trace_probe *tp, char *buf, int len)
pos += snprintf(buf + pos, LEN_OR_ZERO, "\", %s", arg);
for (i = 0; i < tp->nr_args; i++) {
- pos += snprintf(buf + pos, LEN_OR_ZERO, ", REC->%s",
- tp->args[i].name);
+ if (strcmp(tp->args[i].type->name, "string") == 0)
+ pos += snprintf(buf + pos, LEN_OR_ZERO,
+ ", __get_str(%s)",
+ tp->args[i].name);
+ else
+ pos += snprintf(buf + pos, LEN_OR_ZERO, ", REC->%s",
+ tp->args[i].name);
}
#undef LEN_OR_ZERO
@@ -1339,11 +1554,11 @@ static __kprobes void kprobe_perf_func(struct kprobe *kp,
struct ftrace_event_call *call = &tp->call;
struct kprobe_trace_entry_head *entry;
struct hlist_head *head;
- u8 *data;
- int size, __size, i;
+ int size, __size, dsize;
int rctx;
- __size = sizeof(*entry) + tp->size;
+ dsize = __get_data_size(tp, regs);
+ __size = sizeof(*entry) + tp->size + dsize;
size = ALIGN(__size + sizeof(u32), sizeof(u64));
size -= sizeof(u32);
if (WARN_ONCE(size > PERF_MAX_TRACE_SIZE,
@@ -1355,9 +1570,8 @@ static __kprobes void kprobe_perf_func(struct kprobe *kp,
return;
entry->ip = (unsigned long)kp->addr;
- data = (u8 *)&entry[1];
- for (i = 0; i < tp->nr_args; i++)
- call_fetch(&tp->args[i].fetch, regs, data + tp->args[i].offset);
+ memset(&entry[1], 0, dsize);
+ store_trace_args(sizeof(*entry), tp, regs, (u8 *)&entry[1], dsize);
head = this_cpu_ptr(call->perf_events);
perf_trace_buf_submit(entry, size, rctx, entry->ip, 1, regs, head);
@@ -1371,11 +1585,11 @@ static __kprobes void kretprobe_perf_func(struct kretprobe_instance *ri,
struct ftrace_event_call *call = &tp->call;
struct kretprobe_trace_entry_head *entry;
struct hlist_head *head;
- u8 *data;
- int size, __size, i;
+ int size, __size, dsize;
int rctx;
- __size = sizeof(*entry) + tp->size;
+ dsize = __get_data_size(tp, regs);
+ __size = sizeof(*entry) + tp->size + dsize;
size = ALIGN(__size + sizeof(u32), sizeof(u64));
size -= sizeof(u32);
if (WARN_ONCE(size > PERF_MAX_TRACE_SIZE,
@@ -1388,9 +1602,7 @@ static __kprobes void kretprobe_perf_func(struct kretprobe_instance *ri,
entry->func = (unsigned long)tp->rp.kp.addr;
entry->ret_ip = (unsigned long)ri->ret_addr;
- data = (u8 *)&entry[1];
- for (i = 0; i < tp->nr_args; i++)
- call_fetch(&tp->args[i].fetch, regs, data + tp->args[i].offset);
+ store_trace_args(sizeof(*entry), tp, regs, (u8 *)&entry[1], dsize);
head = this_cpu_ptr(call->perf_events);
perf_trace_buf_submit(entry, size, rctx, entry->ret_ip, 1, regs, head);
@@ -1486,15 +1698,12 @@ static int register_probe_event(struct trace_probe *tp)
int ret;
/* Initialize ftrace_event_call */
+ INIT_LIST_HEAD(&call->class->fields);
if (probe_is_return(tp)) {
- INIT_LIST_HEAD(&call->class->fields);
call->event.funcs = &kretprobe_funcs;
- call->class->raw_init = probe_event_raw_init;
call->class->define_fields = kretprobe_event_define_fields;
} else {
- INIT_LIST_HEAD(&call->class->fields);
call->event.funcs = &kprobe_funcs;
- call->class->raw_init = probe_event_raw_init;
call->class->define_fields = kprobe_event_define_fields;
}
if (set_print_fmt(tp) < 0)
diff --git a/kernel/trace/trace_ksym.c b/kernel/trace/trace_ksym.c
deleted file mode 100644
index 8eaf00749b6..00000000000
--- a/kernel/trace/trace_ksym.c
+++ /dev/null
@@ -1,508 +0,0 @@
-/*
- * trace_ksym.c - Kernel Symbol Tracer
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * Copyright (C) IBM Corporation, 2009
- */
-
-#include <linux/kallsyms.h>
-#include <linux/uaccess.h>
-#include <linux/debugfs.h>
-#include <linux/ftrace.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/fs.h>
-
-#include "trace_output.h"
-#include "trace.h"
-
-#include <linux/hw_breakpoint.h>
-#include <asm/hw_breakpoint.h>
-
-#include <asm/atomic.h>
-
-#define KSYM_TRACER_OP_LEN 3 /* rw- */
-
-struct trace_ksym {
- struct perf_event **ksym_hbp;
- struct perf_event_attr attr;
-#ifdef CONFIG_PROFILE_KSYM_TRACER
- atomic64_t counter;
-#endif
- struct hlist_node ksym_hlist;
-};
-
-static struct trace_array *ksym_trace_array;
-
-static unsigned int ksym_tracing_enabled;
-
-static HLIST_HEAD(ksym_filter_head);
-
-static DEFINE_MUTEX(ksym_tracer_mutex);
-
-#ifdef CONFIG_PROFILE_KSYM_TRACER
-
-#define MAX_UL_INT 0xffffffff
-
-void ksym_collect_stats(unsigned long hbp_hit_addr)
-{
- struct hlist_node *node;
- struct trace_ksym *entry;
-
- rcu_read_lock();
- hlist_for_each_entry_rcu(entry, node, &ksym_filter_head, ksym_hlist) {
- if (entry->attr.bp_addr == hbp_hit_addr) {
- atomic64_inc(&entry->counter);
- break;
- }
- }
- rcu_read_unlock();
-}
-#endif /* CONFIG_PROFILE_KSYM_TRACER */
-
-void ksym_hbp_handler(struct perf_event *hbp, int nmi,
- struct perf_sample_data *data,
- struct pt_regs *regs)
-{
- struct ring_buffer_event *event;
- struct ksym_trace_entry *entry;
- struct ring_buffer *buffer;
- int pc;
-
- if (!ksym_tracing_enabled)
- return;
-
- buffer = ksym_trace_array->buffer;
-
- pc = preempt_count();
-
- event = trace_buffer_lock_reserve(buffer, TRACE_KSYM,
- sizeof(*entry), 0, pc);
- if (!event)
- return;
-
- entry = ring_buffer_event_data(event);
- entry->ip = instruction_pointer(regs);
- entry->type = hw_breakpoint_type(hbp);
- entry->addr = hw_breakpoint_addr(hbp);
- strlcpy(entry->cmd, current->comm, TASK_COMM_LEN);
-
-#ifdef CONFIG_PROFILE_KSYM_TRACER
- ksym_collect_stats(hw_breakpoint_addr(hbp));
-#endif /* CONFIG_PROFILE_KSYM_TRACER */
-
- trace_buffer_unlock_commit(buffer, event, 0, pc);
-}
-
-/* Valid access types are represented as
- *
- * rw- : Set Read/Write Access Breakpoint
- * -w- : Set Write Access Breakpoint
- * --- : Clear Breakpoints
- * --x : Set Execution Break points (Not available yet)
- *
- */
-static int ksym_trace_get_access_type(char *str)
-{
- int access = 0;
-
- if (str[0] == 'r')
- access |= HW_BREAKPOINT_R;
-
- if (str[1] == 'w')
- access |= HW_BREAKPOINT_W;
-
- if (str[2] == 'x')
- access |= HW_BREAKPOINT_X;
-
- switch (access) {
- case HW_BREAKPOINT_R:
- case HW_BREAKPOINT_W:
- case HW_BREAKPOINT_W | HW_BREAKPOINT_R:
- return access;
- default:
- return -EINVAL;
- }
-}
-
-/*
- * There can be several possible malformed requests and we attempt to capture
- * all of them. We enumerate some of the rules
- * 1. We will not allow kernel symbols with ':' since it is used as a delimiter.
- * i.e. multiple ':' symbols disallowed. Possible uses are of the form
- * <module>:<ksym_name>:<op>.
- * 2. No delimiter symbol ':' in the input string
- * 3. Spurious operator symbols or symbols not in their respective positions
- * 4. <ksym_name>:--- i.e. clear breakpoint request when ksym_name not in file
- * 5. Kernel symbol not a part of /proc/kallsyms
- * 6. Duplicate requests
- */
-static int parse_ksym_trace_str(char *input_string, char **ksymname,
- unsigned long *addr)
-{
- int ret;
-
- *ksymname = strsep(&input_string, ":");
- *addr = kallsyms_lookup_name(*ksymname);
-
- /* Check for malformed request: (2), (1) and (5) */
- if ((!input_string) ||
- (strlen(input_string) != KSYM_TRACER_OP_LEN) ||
- (*addr == 0))
- return -EINVAL;;
-
- ret = ksym_trace_get_access_type(input_string);
-
- return ret;
-}
-
-int process_new_ksym_entry(char *ksymname, int op, unsigned long addr)
-{
- struct trace_ksym *entry;
- int ret = -ENOMEM;
-
- entry = kzalloc(sizeof(struct trace_ksym), GFP_KERNEL);
- if (!entry)
- return -ENOMEM;
-
- hw_breakpoint_init(&entry->attr);
-
- entry->attr.bp_type = op;
- entry->attr.bp_addr = addr;
- entry->attr.bp_len = HW_BREAKPOINT_LEN_4;
-
- entry->ksym_hbp = register_wide_hw_breakpoint(&entry->attr,
- ksym_hbp_handler);
-
- if (IS_ERR(entry->ksym_hbp)) {
- ret = PTR_ERR(entry->ksym_hbp);
- if (ret == -ENOSPC) {
- printk(KERN_ERR "ksym_tracer: Maximum limit reached."
- " No new requests for tracing can be accepted now.\n");
- } else {
- printk(KERN_INFO "ksym_tracer request failed. Try again"
- " later!!\n");
- }
- goto err;
- }
-
- hlist_add_head_rcu(&(entry->ksym_hlist), &ksym_filter_head);
-
- return 0;
-
-err:
- kfree(entry);
-
- return ret;
-}
-
-static ssize_t ksym_trace_filter_read(struct file *filp, char __user *ubuf,
- size_t count, loff_t *ppos)
-{
- struct trace_ksym *entry;
- struct hlist_node *node;
- struct trace_seq *s;
- ssize_t cnt = 0;
- int ret;
-
- s = kmalloc(sizeof(*s), GFP_KERNEL);
- if (!s)
- return -ENOMEM;
- trace_seq_init(s);
-
- mutex_lock(&ksym_tracer_mutex);
-
- hlist_for_each_entry(entry, node, &ksym_filter_head, ksym_hlist) {
- ret = trace_seq_printf(s, "%pS:",
- (void *)(unsigned long)entry->attr.bp_addr);
- if (entry->attr.bp_type == HW_BREAKPOINT_R)
- ret = trace_seq_puts(s, "r--\n");
- else if (entry->attr.bp_type == HW_BREAKPOINT_W)
- ret = trace_seq_puts(s, "-w-\n");
- else if (entry->attr.bp_type == (HW_BREAKPOINT_W | HW_BREAKPOINT_R))
- ret = trace_seq_puts(s, "rw-\n");
- WARN_ON_ONCE(!ret);
- }
-
- cnt = simple_read_from_buffer(ubuf, count, ppos, s->buffer, s->len);
-
- mutex_unlock(&ksym_tracer_mutex);
-
- kfree(s);
-
- return cnt;
-}
-
-static void __ksym_trace_reset(void)
-{
- struct trace_ksym *entry;
- struct hlist_node *node, *node1;
-
- mutex_lock(&ksym_tracer_mutex);
- hlist_for_each_entry_safe(entry, node, node1, &ksym_filter_head,
- ksym_hlist) {
- unregister_wide_hw_breakpoint(entry->ksym_hbp);
- hlist_del_rcu(&(entry->ksym_hlist));
- synchronize_rcu();
- kfree(entry);
- }
- mutex_unlock(&ksym_tracer_mutex);
-}
-
-static ssize_t ksym_trace_filter_write(struct file *file,
- const char __user *buffer,
- size_t count, loff_t *ppos)
-{
- struct trace_ksym *entry;
- struct hlist_node *node;
- char *buf, *input_string, *ksymname = NULL;
- unsigned long ksym_addr = 0;
- int ret, op, changed = 0;
-
- buf = kzalloc(count + 1, GFP_KERNEL);
- if (!buf)
- return -ENOMEM;
-
- ret = -EFAULT;
- if (copy_from_user(buf, buffer, count))
- goto out;
-
- buf[count] = '\0';
- input_string = strstrip(buf);
-
- /*
- * Clear all breakpoints if:
- * 1: echo > ksym_trace_filter
- * 2: echo 0 > ksym_trace_filter
- * 3: echo "*:---" > ksym_trace_filter
- */
- if (!input_string[0] || !strcmp(input_string, "0") ||
- !strcmp(input_string, "*:---")) {
- __ksym_trace_reset();
- ret = 0;
- goto out;
- }
-
- ret = op = parse_ksym_trace_str(input_string, &ksymname, &ksym_addr);
- if (ret < 0)
- goto out;
-
- mutex_lock(&ksym_tracer_mutex);
-
- ret = -EINVAL;
- hlist_for_each_entry(entry, node, &ksym_filter_head, ksym_hlist) {
- if (entry->attr.bp_addr == ksym_addr) {
- /* Check for malformed request: (6) */
- if (entry->attr.bp_type != op)
- changed = 1;
- else
- goto out_unlock;
- break;
- }
- }
- if (changed) {
- unregister_wide_hw_breakpoint(entry->ksym_hbp);
- entry->attr.bp_type = op;
- ret = 0;
- if (op > 0) {
- entry->ksym_hbp =
- register_wide_hw_breakpoint(&entry->attr,
- ksym_hbp_handler);
- if (IS_ERR(entry->ksym_hbp))
- ret = PTR_ERR(entry->ksym_hbp);
- else
- goto out_unlock;
- }
- /* Error or "symbol:---" case: drop it */
- hlist_del_rcu(&(entry->ksym_hlist));
- synchronize_rcu();
- kfree(entry);
- goto out_unlock;
- } else {
- /* Check for malformed request: (4) */
- if (op)
- ret = process_new_ksym_entry(ksymname, op, ksym_addr);
- }
-out_unlock:
- mutex_unlock(&ksym_tracer_mutex);
-out:
- kfree(buf);
- return !ret ? count : ret;
-}
-
-static const struct file_operations ksym_tracing_fops = {
- .open = tracing_open_generic,
- .read = ksym_trace_filter_read,
- .write = ksym_trace_filter_write,
-};
-
-static void ksym_trace_reset(struct trace_array *tr)
-{
- ksym_tracing_enabled = 0;
- __ksym_trace_reset();
-}
-
-static int ksym_trace_init(struct trace_array *tr)
-{
- int cpu, ret = 0;
-
- for_each_online_cpu(cpu)
- tracing_reset(tr, cpu);
- ksym_tracing_enabled = 1;
- ksym_trace_array = tr;
-
- return ret;
-}
-
-static void ksym_trace_print_header(struct seq_file *m)
-{
- seq_puts(m,
- "# TASK-PID CPU# Symbol "
- "Type Function\n");
- seq_puts(m,
- "# | | | "
- " | |\n");
-}
-
-static enum print_line_t ksym_trace_output(struct trace_iterator *iter)
-{
- struct trace_entry *entry = iter->ent;
- struct trace_seq *s = &iter->seq;
- struct ksym_trace_entry *field;
- char str[KSYM_SYMBOL_LEN];
- int ret;
-
- if (entry->type != TRACE_KSYM)
- return TRACE_TYPE_UNHANDLED;
-
- trace_assign_type(field, entry);
-
- ret = trace_seq_printf(s, "%11s-%-5d [%03d] %pS", field->cmd,
- entry->pid, iter->cpu, (char *)field->addr);
- if (!ret)
- return TRACE_TYPE_PARTIAL_LINE;
-
- switch (field->type) {
- case HW_BREAKPOINT_R:
- ret = trace_seq_printf(s, " R ");
- break;
- case HW_BREAKPOINT_W:
- ret = trace_seq_printf(s, " W ");
- break;
- case HW_BREAKPOINT_R | HW_BREAKPOINT_W:
- ret = trace_seq_printf(s, " RW ");
- break;
- default:
- return TRACE_TYPE_PARTIAL_LINE;
- }
-
- if (!ret)
- return TRACE_TYPE_PARTIAL_LINE;
-
- sprint_symbol(str, field->ip);
- ret = trace_seq_printf(s, "%s\n", str);
- if (!ret)
- return TRACE_TYPE_PARTIAL_LINE;
-
- return TRACE_TYPE_HANDLED;
-}
-
-struct tracer ksym_tracer __read_mostly =
-{
- .name = "ksym_tracer",
- .init = ksym_trace_init,
- .reset = ksym_trace_reset,
-#ifdef CONFIG_FTRACE_SELFTEST
- .selftest = trace_selftest_startup_ksym,
-#endif
- .print_header = ksym_trace_print_header,
- .print_line = ksym_trace_output
-};
-
-#ifdef CONFIG_PROFILE_KSYM_TRACER
-static int ksym_profile_show(struct seq_file *m, void *v)
-{
- struct hlist_node *node;
- struct trace_ksym *entry;
- int access_type = 0;
- char fn_name[KSYM_NAME_LEN];
-
- seq_puts(m, " Access Type ");
- seq_puts(m, " Symbol Counter\n");
- seq_puts(m, " ----------- ");
- seq_puts(m, " ------ -------\n");
-
- rcu_read_lock();
- hlist_for_each_entry_rcu(entry, node, &ksym_filter_head, ksym_hlist) {
-
- access_type = entry->attr.bp_type;
-
- switch (access_type) {
- case HW_BREAKPOINT_R:
- seq_puts(m, " R ");
- break;
- case HW_BREAKPOINT_W:
- seq_puts(m, " W ");
- break;
- case HW_BREAKPOINT_R | HW_BREAKPOINT_W:
- seq_puts(m, " RW ");
- break;
- default:
- seq_puts(m, " NA ");
- }
-
- if (lookup_symbol_name(entry->attr.bp_addr, fn_name) >= 0)
- seq_printf(m, " %-36s", fn_name);
- else
- seq_printf(m, " %-36s", "<NA>");
- seq_printf(m, " %15llu\n",
- (unsigned long long)atomic64_read(&entry->counter));
- }
- rcu_read_unlock();
-
- return 0;
-}
-
-static int ksym_profile_open(struct inode *node, struct file *file)
-{
- return single_open(file, ksym_profile_show, NULL);
-}
-
-static const struct file_operations ksym_profile_fops = {
- .open = ksym_profile_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
-#endif /* CONFIG_PROFILE_KSYM_TRACER */
-
-__init static int init_ksym_trace(void)
-{
- struct dentry *d_tracer;
-
- d_tracer = tracing_init_dentry();
-
- trace_create_file("ksym_trace_filter", 0644, d_tracer,
- NULL, &ksym_tracing_fops);
-
-#ifdef CONFIG_PROFILE_KSYM_TRACER
- trace_create_file("ksym_profile", 0444, d_tracer,
- NULL, &ksym_profile_fops);
-#endif
-
- return register_tracer(&ksym_tracer);
-}
-device_initcall(init_ksym_trace);
diff --git a/kernel/trace/trace_output.c b/kernel/trace/trace_output.c
index 57c1b459647..02272baa220 100644
--- a/kernel/trace/trace_output.c
+++ b/kernel/trace/trace_output.c
@@ -16,9 +16,6 @@
DECLARE_RWSEM(trace_event_mutex);
-DEFINE_PER_CPU(struct trace_seq, ftrace_event_seq);
-EXPORT_PER_CPU_SYMBOL(ftrace_event_seq);
-
static struct hlist_head event_hash[EVENT_HASHSIZE] __read_mostly;
static int next_event_type = __TRACE_LAST_TYPE + 1;
@@ -1069,65 +1066,6 @@ static struct trace_event trace_wake_event = {
.funcs = &trace_wake_funcs,
};
-/* TRACE_SPECIAL */
-static enum print_line_t trace_special_print(struct trace_iterator *iter,
- int flags, struct trace_event *event)
-{
- struct special_entry *field;
-
- trace_assign_type(field, iter->ent);
-
- if (!trace_seq_printf(&iter->seq, "# %ld %ld %ld\n",
- field->arg1,
- field->arg2,
- field->arg3))
- return TRACE_TYPE_PARTIAL_LINE;
-
- return TRACE_TYPE_HANDLED;
-}
-
-static enum print_line_t trace_special_hex(struct trace_iterator *iter,
- int flags, struct trace_event *event)
-{
- struct special_entry *field;
- struct trace_seq *s = &iter->seq;
-
- trace_assign_type(field, iter->ent);
-
- SEQ_PUT_HEX_FIELD_RET(s, field->arg1);
- SEQ_PUT_HEX_FIELD_RET(s, field->arg2);
- SEQ_PUT_HEX_FIELD_RET(s, field->arg3);
-
- return TRACE_TYPE_HANDLED;
-}
-
-static enum print_line_t trace_special_bin(struct trace_iterator *iter,
- int flags, struct trace_event *event)
-{
- struct special_entry *field;
- struct trace_seq *s = &iter->seq;
-
- trace_assign_type(field, iter->ent);
-
- SEQ_PUT_FIELD_RET(s, field->arg1);
- SEQ_PUT_FIELD_RET(s, field->arg2);
- SEQ_PUT_FIELD_RET(s, field->arg3);
-
- return TRACE_TYPE_HANDLED;
-}
-
-static struct trace_event_functions trace_special_funcs = {
- .trace = trace_special_print,
- .raw = trace_special_print,
- .hex = trace_special_hex,
- .binary = trace_special_bin,
-};
-
-static struct trace_event trace_special_event = {
- .type = TRACE_SPECIAL,
- .funcs = &trace_special_funcs,
-};
-
/* TRACE_STACK */
static enum print_line_t trace_stack_print(struct trace_iterator *iter,
@@ -1161,9 +1099,6 @@ static enum print_line_t trace_stack_print(struct trace_iterator *iter,
static struct trace_event_functions trace_stack_funcs = {
.trace = trace_stack_print,
- .raw = trace_special_print,
- .hex = trace_special_hex,
- .binary = trace_special_bin,
};
static struct trace_event trace_stack_event = {
@@ -1194,9 +1129,6 @@ static enum print_line_t trace_user_stack_print(struct trace_iterator *iter,
static struct trace_event_functions trace_user_stack_funcs = {
.trace = trace_user_stack_print,
- .raw = trace_special_print,
- .hex = trace_special_hex,
- .binary = trace_special_bin,
};
static struct trace_event trace_user_stack_event = {
@@ -1314,7 +1246,6 @@ static struct trace_event *events[] __initdata = {
&trace_fn_event,
&trace_ctx_event,
&trace_wake_event,
- &trace_special_event,
&trace_stack_event,
&trace_user_stack_event,
&trace_bprint_event,
diff --git a/kernel/trace/trace_sched_wakeup.c b/kernel/trace/trace_sched_wakeup.c
index 0e73bc2ef8c..4086eae6e81 100644
--- a/kernel/trace/trace_sched_wakeup.c
+++ b/kernel/trace/trace_sched_wakeup.c
@@ -46,7 +46,6 @@ wakeup_tracer_call(unsigned long ip, unsigned long parent_ip)
struct trace_array_cpu *data;
unsigned long flags;
long disabled;
- int resched;
int cpu;
int pc;
@@ -54,7 +53,7 @@ wakeup_tracer_call(unsigned long ip, unsigned long parent_ip)
return;
pc = preempt_count();
- resched = ftrace_preempt_disable();
+ preempt_disable_notrace();
cpu = raw_smp_processor_id();
if (cpu != wakeup_current_cpu)
@@ -74,7 +73,7 @@ wakeup_tracer_call(unsigned long ip, unsigned long parent_ip)
out:
atomic_dec(&data->disabled);
out_enable:
- ftrace_preempt_enable(resched);
+ preempt_enable_notrace();
}
static struct ftrace_ops trace_ops __read_mostly =
@@ -383,6 +382,7 @@ static struct tracer wakeup_tracer __read_mostly =
#ifdef CONFIG_FTRACE_SELFTEST
.selftest = trace_selftest_startup_wakeup,
#endif
+ .use_max_tr = 1,
};
static struct tracer wakeup_rt_tracer __read_mostly =
@@ -397,6 +397,7 @@ static struct tracer wakeup_rt_tracer __read_mostly =
#ifdef CONFIG_FTRACE_SELFTEST
.selftest = trace_selftest_startup_wakeup,
#endif
+ .use_max_tr = 1,
};
__init static int init_wakeup_tracer(void)
diff --git a/kernel/trace/trace_selftest.c b/kernel/trace/trace_selftest.c
index 250e7f9bd2f..155a415b320 100644
--- a/kernel/trace/trace_selftest.c
+++ b/kernel/trace/trace_selftest.c
@@ -13,11 +13,9 @@ static inline int trace_valid_entry(struct trace_entry *entry)
case TRACE_WAKE:
case TRACE_STACK:
case TRACE_PRINT:
- case TRACE_SPECIAL:
case TRACE_BRANCH:
case TRACE_GRAPH_ENT:
case TRACE_GRAPH_RET:
- case TRACE_KSYM:
return 1;
}
return 0;
@@ -691,38 +689,6 @@ trace_selftest_startup_sched_switch(struct tracer *trace, struct trace_array *tr
}
#endif /* CONFIG_CONTEXT_SWITCH_TRACER */
-#ifdef CONFIG_SYSPROF_TRACER
-int
-trace_selftest_startup_sysprof(struct tracer *trace, struct trace_array *tr)
-{
- unsigned long count;
- int ret;
-
- /* start the tracing */
- ret = tracer_init(trace, tr);
- if (ret) {
- warn_failed_init_tracer(trace, ret);
- return ret;
- }
-
- /* Sleep for a 1/10 of a second */
- msleep(100);
- /* stop the tracing. */
- tracing_stop();
- /* check the trace buffer */
- ret = trace_test_buffer(tr, &count);
- trace->reset(tr);
- tracing_start();
-
- if (!ret && !count) {
- printk(KERN_CONT ".. no entries found ..");
- ret = -1;
- }
-
- return ret;
-}
-#endif /* CONFIG_SYSPROF_TRACER */
-
#ifdef CONFIG_BRANCH_TRACER
int
trace_selftest_startup_branch(struct tracer *trace, struct trace_array *tr)
@@ -755,56 +721,3 @@ trace_selftest_startup_branch(struct tracer *trace, struct trace_array *tr)
}
#endif /* CONFIG_BRANCH_TRACER */
-#ifdef CONFIG_KSYM_TRACER
-static int ksym_selftest_dummy;
-
-int
-trace_selftest_startup_ksym(struct tracer *trace, struct trace_array *tr)
-{
- unsigned long count;
- int ret;
-
- /* start the tracing */
- ret = tracer_init(trace, tr);
- if (ret) {
- warn_failed_init_tracer(trace, ret);
- return ret;
- }
-
- ksym_selftest_dummy = 0;
- /* Register the read-write tracing request */
-
- ret = process_new_ksym_entry("ksym_selftest_dummy",
- HW_BREAKPOINT_R | HW_BREAKPOINT_W,
- (unsigned long)(&ksym_selftest_dummy));
-
- if (ret < 0) {
- printk(KERN_CONT "ksym_trace read-write startup test failed\n");
- goto ret_path;
- }
- /* Perform a read and a write operation over the dummy variable to
- * trigger the tracer
- */
- if (ksym_selftest_dummy == 0)
- ksym_selftest_dummy++;
-
- /* stop the tracing. */
- tracing_stop();
- /* check the trace buffer */
- ret = trace_test_buffer(tr, &count);
- trace->reset(tr);
- tracing_start();
-
- /* read & write operations - one each is performed on the dummy variable
- * triggering two entries in the trace buffer
- */
- if (!ret && count != 2) {
- printk(KERN_CONT "Ksym tracer startup test failed");
- ret = -1;
- }
-
-ret_path:
- return ret;
-}
-#endif /* CONFIG_KSYM_TRACER */
-
diff --git a/kernel/trace/trace_stack.c b/kernel/trace/trace_stack.c
index f4bc9b27de5..056468eae7c 100644
--- a/kernel/trace/trace_stack.c
+++ b/kernel/trace/trace_stack.c
@@ -110,12 +110,12 @@ static inline void check_stack(void)
static void
stack_trace_call(unsigned long ip, unsigned long parent_ip)
{
- int cpu, resched;
+ int cpu;
if (unlikely(!ftrace_enabled || stack_trace_disabled))
return;
- resched = ftrace_preempt_disable();
+ preempt_disable_notrace();
cpu = raw_smp_processor_id();
/* no atomic needed, we only modify this variable by this cpu */
@@ -127,7 +127,7 @@ stack_trace_call(unsigned long ip, unsigned long parent_ip)
out:
per_cpu(trace_active, cpu)--;
/* prevent recursion in schedule */
- ftrace_preempt_enable(resched);
+ preempt_enable_notrace();
}
static struct ftrace_ops trace_ops __read_mostly =
diff --git a/kernel/trace/trace_syscalls.c b/kernel/trace/trace_syscalls.c
index 34e35804304..bac752f0cfb 100644
--- a/kernel/trace/trace_syscalls.c
+++ b/kernel/trace/trace_syscalls.c
@@ -23,6 +23,9 @@ static int syscall_exit_register(struct ftrace_event_call *event,
static int syscall_enter_define_fields(struct ftrace_event_call *call);
static int syscall_exit_define_fields(struct ftrace_event_call *call);
+/* All syscall exit events have the same fields */
+static LIST_HEAD(syscall_exit_fields);
+
static struct list_head *
syscall_get_enter_fields(struct ftrace_event_call *call)
{
@@ -34,9 +37,7 @@ syscall_get_enter_fields(struct ftrace_event_call *call)
static struct list_head *
syscall_get_exit_fields(struct ftrace_event_call *call)
{
- struct syscall_metadata *entry = call->data;
-
- return &entry->exit_fields;
+ return &syscall_exit_fields;
}
struct trace_event_functions enter_syscall_print_funcs = {
diff --git a/kernel/trace/trace_sysprof.c b/kernel/trace/trace_sysprof.c
deleted file mode 100644
index a7974a552ca..00000000000
--- a/kernel/trace/trace_sysprof.c
+++ /dev/null
@@ -1,329 +0,0 @@
-/*
- * trace stack traces
- *
- * Copyright (C) 2004-2008, Soeren Sandmann
- * Copyright (C) 2007 Steven Rostedt <srostedt@redhat.com>
- * Copyright (C) 2008 Ingo Molnar <mingo@redhat.com>
- */
-#include <linux/kallsyms.h>
-#include <linux/debugfs.h>
-#include <linux/hrtimer.h>
-#include <linux/uaccess.h>
-#include <linux/ftrace.h>
-#include <linux/module.h>
-#include <linux/irq.h>
-#include <linux/fs.h>
-
-#include <asm/stacktrace.h>
-
-#include "trace.h"
-
-static struct trace_array *sysprof_trace;
-static int __read_mostly tracer_enabled;
-
-/*
- * 1 msec sample interval by default:
- */
-static unsigned long sample_period = 1000000;
-static const unsigned int sample_max_depth = 512;
-
-static DEFINE_MUTEX(sample_timer_lock);
-/*
- * Per CPU hrtimers that do the profiling:
- */
-static DEFINE_PER_CPU(struct hrtimer, stack_trace_hrtimer);
-
-struct stack_frame {
- const void __user *next_fp;
- unsigned long return_address;
-};
-
-static int copy_stack_frame(const void __user *fp, struct stack_frame *frame)
-{
- int ret;
-
- if (!access_ok(VERIFY_READ, fp, sizeof(*frame)))
- return 0;
-
- ret = 1;
- pagefault_disable();
- if (__copy_from_user_inatomic(frame, fp, sizeof(*frame)))
- ret = 0;
- pagefault_enable();
-
- return ret;
-}
-
-struct backtrace_info {
- struct trace_array_cpu *data;
- struct trace_array *tr;
- int pos;
-};
-
-static void
-backtrace_warning_symbol(void *data, char *msg, unsigned long symbol)
-{
- /* Ignore warnings */
-}
-
-static void backtrace_warning(void *data, char *msg)
-{
- /* Ignore warnings */
-}
-
-static int backtrace_stack(void *data, char *name)
-{
- /* Don't bother with IRQ stacks for now */
- return -1;
-}
-
-static void backtrace_address(void *data, unsigned long addr, int reliable)
-{
- struct backtrace_info *info = data;
-
- if (info->pos < sample_max_depth && reliable) {
- __trace_special(info->tr, info->data, 1, addr, 0);
-
- info->pos++;
- }
-}
-
-static const struct stacktrace_ops backtrace_ops = {
- .warning = backtrace_warning,
- .warning_symbol = backtrace_warning_symbol,
- .stack = backtrace_stack,
- .address = backtrace_address,
- .walk_stack = print_context_stack,
-};
-
-static int
-trace_kernel(struct pt_regs *regs, struct trace_array *tr,
- struct trace_array_cpu *data)
-{
- struct backtrace_info info;
- unsigned long bp;
- char *stack;
-
- info.tr = tr;
- info.data = data;
- info.pos = 1;
-
- __trace_special(info.tr, info.data, 1, regs->ip, 0);
-
- stack = ((char *)regs + sizeof(struct pt_regs));
-#ifdef CONFIG_FRAME_POINTER
- bp = regs->bp;
-#else
- bp = 0;
-#endif
-
- dump_trace(NULL, regs, (void *)stack, bp, &backtrace_ops, &info);
-
- return info.pos;
-}
-
-static void timer_notify(struct pt_regs *regs, int cpu)
-{
- struct trace_array_cpu *data;
- struct stack_frame frame;
- struct trace_array *tr;
- const void __user *fp;
- int is_user;
- int i;
-
- if (!regs)
- return;
-
- tr = sysprof_trace;
- data = tr->data[cpu];
- is_user = user_mode(regs);
-
- if (!current || current->pid == 0)
- return;
-
- if (is_user && current->state != TASK_RUNNING)
- return;
-
- __trace_special(tr, data, 0, 0, current->pid);
-
- if (!is_user)
- i = trace_kernel(regs, tr, data);
- else
- i = 0;
-
- /*
- * Trace user stack if we are not a kernel thread
- */
- if (current->mm && i < sample_max_depth) {
- regs = (struct pt_regs *)current->thread.sp0 - 1;
-
- fp = (void __user *)regs->bp;
-
- __trace_special(tr, data, 2, regs->ip, 0);
-
- while (i < sample_max_depth) {
- frame.next_fp = NULL;
- frame.return_address = 0;
- if (!copy_stack_frame(fp, &frame))
- break;
- if ((unsigned long)fp < regs->sp)
- break;
-
- __trace_special(tr, data, 2, frame.return_address,
- (unsigned long)fp);
- fp = frame.next_fp;
-
- i++;
- }
-
- }
-
- /*
- * Special trace entry if we overflow the max depth:
- */
- if (i == sample_max_depth)
- __trace_special(tr, data, -1, -1, -1);
-
- __trace_special(tr, data, 3, current->pid, i);
-}
-
-static enum hrtimer_restart stack_trace_timer_fn(struct hrtimer *hrtimer)
-{
- /* trace here */
- timer_notify(get_irq_regs(), smp_processor_id());
-
- hrtimer_forward_now(hrtimer, ns_to_ktime(sample_period));
-
- return HRTIMER_RESTART;
-}
-
-static void start_stack_timer(void *unused)
-{
- struct hrtimer *hrtimer = &__get_cpu_var(stack_trace_hrtimer);
-
- hrtimer_init(hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
- hrtimer->function = stack_trace_timer_fn;
-
- hrtimer_start(hrtimer, ns_to_ktime(sample_period),
- HRTIMER_MODE_REL_PINNED);
-}
-
-static void start_stack_timers(void)
-{
- on_each_cpu(start_stack_timer, NULL, 1);
-}
-
-static void stop_stack_timer(int cpu)
-{
- struct hrtimer *hrtimer = &per_cpu(stack_trace_hrtimer, cpu);
-
- hrtimer_cancel(hrtimer);
-}
-
-static void stop_stack_timers(void)
-{
- int cpu;
-
- for_each_online_cpu(cpu)
- stop_stack_timer(cpu);
-}
-
-static void stop_stack_trace(struct trace_array *tr)
-{
- mutex_lock(&sample_timer_lock);
- stop_stack_timers();
- tracer_enabled = 0;
- mutex_unlock(&sample_timer_lock);
-}
-
-static int stack_trace_init(struct trace_array *tr)
-{
- sysprof_trace = tr;
-
- tracing_start_cmdline_record();
-
- mutex_lock(&sample_timer_lock);
- start_stack_timers();
- tracer_enabled = 1;
- mutex_unlock(&sample_timer_lock);
- return 0;
-}
-
-static void stack_trace_reset(struct trace_array *tr)
-{
- tracing_stop_cmdline_record();
- stop_stack_trace(tr);
-}
-
-static struct tracer stack_trace __read_mostly =
-{
- .name = "sysprof",
- .init = stack_trace_init,
- .reset = stack_trace_reset,
-#ifdef CONFIG_FTRACE_SELFTEST
- .selftest = trace_selftest_startup_sysprof,
-#endif
-};
-
-__init static int init_stack_trace(void)
-{
- return register_tracer(&stack_trace);
-}
-device_initcall(init_stack_trace);
-
-#define MAX_LONG_DIGITS 22
-
-static ssize_t
-sysprof_sample_read(struct file *filp, char __user *ubuf,
- size_t cnt, loff_t *ppos)
-{
- char buf[MAX_LONG_DIGITS];
- int r;
-
- r = sprintf(buf, "%ld\n", nsecs_to_usecs(sample_period));
-
- return simple_read_from_buffer(ubuf, cnt, ppos, buf, r);
-}
-
-static ssize_t
-sysprof_sample_write(struct file *filp, const char __user *ubuf,
- size_t cnt, loff_t *ppos)
-{
- char buf[MAX_LONG_DIGITS];
- unsigned long val;
-
- if (cnt > MAX_LONG_DIGITS-1)
- cnt = MAX_LONG_DIGITS-1;
-
- if (copy_from_user(&buf, ubuf, cnt))
- return -EFAULT;
-
- buf[cnt] = 0;
-
- val = simple_strtoul(buf, NULL, 10);
- /*
- * Enforce a minimum sample period of 100 usecs:
- */
- if (val < 100)
- val = 100;
-
- mutex_lock(&sample_timer_lock);
- stop_stack_timers();
- sample_period = val * 1000;
- start_stack_timers();
- mutex_unlock(&sample_timer_lock);
-
- return cnt;
-}
-
-static const struct file_operations sysprof_sample_fops = {
- .read = sysprof_sample_read,
- .write = sysprof_sample_write,
-};
-
-void init_tracer_sysprof_debugfs(struct dentry *d_tracer)
-{
-
- trace_create_file("sysprof_sample_period", 0644,
- d_tracer, NULL, &sysprof_sample_fops);
-}
diff --git a/kernel/user_namespace.c b/kernel/user_namespace.c
index b2d70d38dff..25915832291 100644
--- a/kernel/user_namespace.c
+++ b/kernel/user_namespace.c
@@ -9,6 +9,7 @@
#include <linux/nsproxy.h>
#include <linux/slab.h>
#include <linux/user_namespace.h>
+#include <linux/highuid.h>
#include <linux/cred.h>
/*
@@ -82,3 +83,46 @@ void free_user_ns(struct kref *kref)
schedule_work(&ns->destroyer);
}
EXPORT_SYMBOL(free_user_ns);
+
+uid_t user_ns_map_uid(struct user_namespace *to, const struct cred *cred, uid_t uid)
+{
+ struct user_namespace *tmp;
+
+ if (likely(to == cred->user->user_ns))
+ return uid;
+
+
+ /* Is cred->user the creator of the target user_ns
+ * or the creator of one of it's parents?
+ */
+ for ( tmp = to; tmp != &init_user_ns;
+ tmp = tmp->creator->user_ns ) {
+ if (cred->user == tmp->creator) {
+ return (uid_t)0;
+ }
+ }
+
+ /* No useful relationship so no mapping */
+ return overflowuid;
+}
+
+gid_t user_ns_map_gid(struct user_namespace *to, const struct cred *cred, gid_t gid)
+{
+ struct user_namespace *tmp;
+
+ if (likely(to == cred->user->user_ns))
+ return gid;
+
+ /* Is cred->user the creator of the target user_ns
+ * or the creator of one of it's parents?
+ */
+ for ( tmp = to; tmp != &init_user_ns;
+ tmp = tmp->creator->user_ns ) {
+ if (cred->user == tmp->creator) {
+ return (gid_t)0;
+ }
+ }
+
+ /* No useful relationship so no mapping */
+ return overflowgid;
+}
diff --git a/kernel/watchdog.c b/kernel/watchdog.c
new file mode 100644
index 00000000000..613bc1f0461
--- /dev/null
+++ b/kernel/watchdog.c
@@ -0,0 +1,567 @@
+/*
+ * Detect hard and soft lockups on a system
+ *
+ * started by Don Zickus, Copyright (C) 2010 Red Hat, Inc.
+ *
+ * this code detects hard lockups: incidents in where on a CPU
+ * the kernel does not respond to anything except NMI.
+ *
+ * Note: Most of this code is borrowed heavily from softlockup.c,
+ * so thanks to Ingo for the initial implementation.
+ * Some chunks also taken from arch/x86/kernel/apic/nmi.c, thanks
+ * to those contributors as well.
+ */
+
+#include <linux/mm.h>
+#include <linux/cpu.h>
+#include <linux/nmi.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/freezer.h>
+#include <linux/kthread.h>
+#include <linux/lockdep.h>
+#include <linux/notifier.h>
+#include <linux/module.h>
+#include <linux/sysctl.h>
+
+#include <asm/irq_regs.h>
+#include <linux/perf_event.h>
+
+int watchdog_enabled;
+int __read_mostly softlockup_thresh = 60;
+
+static DEFINE_PER_CPU(unsigned long, watchdog_touch_ts);
+static DEFINE_PER_CPU(struct task_struct *, softlockup_watchdog);
+static DEFINE_PER_CPU(struct hrtimer, watchdog_hrtimer);
+static DEFINE_PER_CPU(bool, softlockup_touch_sync);
+static DEFINE_PER_CPU(bool, soft_watchdog_warn);
+#ifdef CONFIG_HARDLOCKUP_DETECTOR
+static DEFINE_PER_CPU(bool, hard_watchdog_warn);
+static DEFINE_PER_CPU(bool, watchdog_nmi_touch);
+static DEFINE_PER_CPU(unsigned long, hrtimer_interrupts);
+static DEFINE_PER_CPU(unsigned long, hrtimer_interrupts_saved);
+static DEFINE_PER_CPU(struct perf_event *, watchdog_ev);
+#endif
+
+static int __read_mostly did_panic;
+static int __initdata no_watchdog;
+
+
+/* boot commands */
+/*
+ * Should we panic when a soft-lockup or hard-lockup occurs:
+ */
+#ifdef CONFIG_HARDLOCKUP_DETECTOR
+static int hardlockup_panic;
+
+static int __init hardlockup_panic_setup(char *str)
+{
+ if (!strncmp(str, "panic", 5))
+ hardlockup_panic = 1;
+ return 1;
+}
+__setup("nmi_watchdog=", hardlockup_panic_setup);
+#endif
+
+unsigned int __read_mostly softlockup_panic =
+ CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE;
+
+static int __init softlockup_panic_setup(char *str)
+{
+ softlockup_panic = simple_strtoul(str, NULL, 0);
+
+ return 1;
+}
+__setup("softlockup_panic=", softlockup_panic_setup);
+
+static int __init nowatchdog_setup(char *str)
+{
+ no_watchdog = 1;
+ return 1;
+}
+__setup("nowatchdog", nowatchdog_setup);
+
+/* deprecated */
+static int __init nosoftlockup_setup(char *str)
+{
+ no_watchdog = 1;
+ return 1;
+}
+__setup("nosoftlockup", nosoftlockup_setup);
+/* */
+
+
+/*
+ * Returns seconds, approximately. We don't need nanosecond
+ * resolution, and we don't need to waste time with a big divide when
+ * 2^30ns == 1.074s.
+ */
+static unsigned long get_timestamp(int this_cpu)
+{
+ return cpu_clock(this_cpu) >> 30LL; /* 2^30 ~= 10^9 */
+}
+
+static unsigned long get_sample_period(void)
+{
+ /*
+ * convert softlockup_thresh from seconds to ns
+ * the divide by 5 is to give hrtimer 5 chances to
+ * increment before the hardlockup detector generates
+ * a warning
+ */
+ return softlockup_thresh / 5 * NSEC_PER_SEC;
+}
+
+/* Commands for resetting the watchdog */
+static void __touch_watchdog(void)
+{
+ int this_cpu = smp_processor_id();
+
+ __get_cpu_var(watchdog_touch_ts) = get_timestamp(this_cpu);
+}
+
+void touch_softlockup_watchdog(void)
+{
+ __get_cpu_var(watchdog_touch_ts) = 0;
+}
+EXPORT_SYMBOL(touch_softlockup_watchdog);
+
+void touch_all_softlockup_watchdogs(void)
+{
+ int cpu;
+
+ /*
+ * this is done lockless
+ * do we care if a 0 races with a timestamp?
+ * all it means is the softlock check starts one cycle later
+ */
+ for_each_online_cpu(cpu)
+ per_cpu(watchdog_touch_ts, cpu) = 0;
+}
+
+#ifdef CONFIG_HARDLOCKUP_DETECTOR
+void touch_nmi_watchdog(void)
+{
+ __get_cpu_var(watchdog_nmi_touch) = true;
+ touch_softlockup_watchdog();
+}
+EXPORT_SYMBOL(touch_nmi_watchdog);
+
+#endif
+
+void touch_softlockup_watchdog_sync(void)
+{
+ __raw_get_cpu_var(softlockup_touch_sync) = true;
+ __raw_get_cpu_var(watchdog_touch_ts) = 0;
+}
+
+#ifdef CONFIG_HARDLOCKUP_DETECTOR
+/* watchdog detector functions */
+static int is_hardlockup(void)
+{
+ unsigned long hrint = __get_cpu_var(hrtimer_interrupts);
+
+ if (__get_cpu_var(hrtimer_interrupts_saved) == hrint)
+ return 1;
+
+ __get_cpu_var(hrtimer_interrupts_saved) = hrint;
+ return 0;
+}
+#endif
+
+static int is_softlockup(unsigned long touch_ts)
+{
+ unsigned long now = get_timestamp(smp_processor_id());
+
+ /* Warn about unreasonable delays: */
+ if (time_after(now, touch_ts + softlockup_thresh))
+ return now - touch_ts;
+
+ return 0;
+}
+
+static int
+watchdog_panic(struct notifier_block *this, unsigned long event, void *ptr)
+{
+ did_panic = 1;
+
+ return NOTIFY_DONE;
+}
+
+static struct notifier_block panic_block = {
+ .notifier_call = watchdog_panic,
+};
+
+#ifdef CONFIG_HARDLOCKUP_DETECTOR
+static struct perf_event_attr wd_hw_attr = {
+ .type = PERF_TYPE_HARDWARE,
+ .config = PERF_COUNT_HW_CPU_CYCLES,
+ .size = sizeof(struct perf_event_attr),
+ .pinned = 1,
+ .disabled = 1,
+};
+
+/* Callback function for perf event subsystem */
+void watchdog_overflow_callback(struct perf_event *event, int nmi,
+ struct perf_sample_data *data,
+ struct pt_regs *regs)
+{
+ if (__get_cpu_var(watchdog_nmi_touch) == true) {
+ __get_cpu_var(watchdog_nmi_touch) = false;
+ return;
+ }
+
+ /* check for a hardlockup
+ * This is done by making sure our timer interrupt
+ * is incrementing. The timer interrupt should have
+ * fired multiple times before we overflow'd. If it hasn't
+ * then this is a good indication the cpu is stuck
+ */
+ if (is_hardlockup()) {
+ int this_cpu = smp_processor_id();
+
+ /* only print hardlockups once */
+ if (__get_cpu_var(hard_watchdog_warn) == true)
+ return;
+
+ if (hardlockup_panic)
+ panic("Watchdog detected hard LOCKUP on cpu %d", this_cpu);
+ else
+ WARN(1, "Watchdog detected hard LOCKUP on cpu %d", this_cpu);
+
+ __get_cpu_var(hard_watchdog_warn) = true;
+ return;
+ }
+
+ __get_cpu_var(hard_watchdog_warn) = false;
+ return;
+}
+static void watchdog_interrupt_count(void)
+{
+ __get_cpu_var(hrtimer_interrupts)++;
+}
+#else
+static inline void watchdog_interrupt_count(void) { return; }
+#endif /* CONFIG_HARDLOCKUP_DETECTOR */
+
+/* watchdog kicker functions */
+static enum hrtimer_restart watchdog_timer_fn(struct hrtimer *hrtimer)
+{
+ unsigned long touch_ts = __get_cpu_var(watchdog_touch_ts);
+ struct pt_regs *regs = get_irq_regs();
+ int duration;
+
+ /* kick the hardlockup detector */
+ watchdog_interrupt_count();
+
+ /* kick the softlockup detector */
+ wake_up_process(__get_cpu_var(softlockup_watchdog));
+
+ /* .. and repeat */
+ hrtimer_forward_now(hrtimer, ns_to_ktime(get_sample_period()));
+
+ if (touch_ts == 0) {
+ if (unlikely(__get_cpu_var(softlockup_touch_sync))) {
+ /*
+ * If the time stamp was touched atomically
+ * make sure the scheduler tick is up to date.
+ */
+ __get_cpu_var(softlockup_touch_sync) = false;
+ sched_clock_tick();
+ }
+ __touch_watchdog();
+ return HRTIMER_RESTART;
+ }
+
+ /* check for a softlockup
+ * This is done by making sure a high priority task is
+ * being scheduled. The task touches the watchdog to
+ * indicate it is getting cpu time. If it hasn't then
+ * this is a good indication some task is hogging the cpu
+ */
+ duration = is_softlockup(touch_ts);
+ if (unlikely(duration)) {
+ /* only warn once */
+ if (__get_cpu_var(soft_watchdog_warn) == true)
+ return HRTIMER_RESTART;
+
+ printk(KERN_ERR "BUG: soft lockup - CPU#%d stuck for %us! [%s:%d]\n",
+ smp_processor_id(), duration,
+ current->comm, task_pid_nr(current));
+ print_modules();
+ print_irqtrace_events(current);
+ if (regs)
+ show_regs(regs);
+ else
+ dump_stack();
+
+ if (softlockup_panic)
+ panic("softlockup: hung tasks");
+ __get_cpu_var(soft_watchdog_warn) = true;
+ } else
+ __get_cpu_var(soft_watchdog_warn) = false;
+
+ return HRTIMER_RESTART;
+}
+
+
+/*
+ * The watchdog thread - touches the timestamp.
+ */
+static int watchdog(void *unused)
+{
+ struct sched_param param = { .sched_priority = MAX_RT_PRIO-1 };
+ struct hrtimer *hrtimer = &__raw_get_cpu_var(watchdog_hrtimer);
+
+ sched_setscheduler(current, SCHED_FIFO, &param);
+
+ /* initialize timestamp */
+ __touch_watchdog();
+
+ /* kick off the timer for the hardlockup detector */
+ /* done here because hrtimer_start can only pin to smp_processor_id() */
+ hrtimer_start(hrtimer, ns_to_ktime(get_sample_period()),
+ HRTIMER_MODE_REL_PINNED);
+
+ set_current_state(TASK_INTERRUPTIBLE);
+ /*
+ * Run briefly once per second to reset the softlockup timestamp.
+ * If this gets delayed for more than 60 seconds then the
+ * debug-printout triggers in watchdog_timer_fn().
+ */
+ while (!kthread_should_stop()) {
+ __touch_watchdog();
+ schedule();
+
+ if (kthread_should_stop())
+ break;
+
+ set_current_state(TASK_INTERRUPTIBLE);
+ }
+ __set_current_state(TASK_RUNNING);
+
+ return 0;
+}
+
+
+#ifdef CONFIG_HARDLOCKUP_DETECTOR
+static int watchdog_nmi_enable(int cpu)
+{
+ struct perf_event_attr *wd_attr;
+ struct perf_event *event = per_cpu(watchdog_ev, cpu);
+
+ /* is it already setup and enabled? */
+ if (event && event->state > PERF_EVENT_STATE_OFF)
+ goto out;
+
+ /* it is setup but not enabled */
+ if (event != NULL)
+ goto out_enable;
+
+ /* Try to register using hardware perf events */
+ wd_attr = &wd_hw_attr;
+ wd_attr->sample_period = hw_nmi_get_sample_period();
+ event = perf_event_create_kernel_counter(wd_attr, cpu, -1, watchdog_overflow_callback);
+ if (!IS_ERR(event)) {
+ printk(KERN_INFO "NMI watchdog enabled, takes one hw-pmu counter.\n");
+ goto out_save;
+ }
+
+ printk(KERN_ERR "NMI watchdog failed to create perf event on cpu%i: %p\n", cpu, event);
+ return -1;
+
+ /* success path */
+out_save:
+ per_cpu(watchdog_ev, cpu) = event;
+out_enable:
+ perf_event_enable(per_cpu(watchdog_ev, cpu));
+out:
+ return 0;
+}
+
+static void watchdog_nmi_disable(int cpu)
+{
+ struct perf_event *event = per_cpu(watchdog_ev, cpu);
+
+ if (event) {
+ perf_event_disable(event);
+ per_cpu(watchdog_ev, cpu) = NULL;
+
+ /* should be in cleanup, but blocks oprofile */
+ perf_event_release_kernel(event);
+ }
+ return;
+}
+#else
+static int watchdog_nmi_enable(int cpu) { return 0; }
+static void watchdog_nmi_disable(int cpu) { return; }
+#endif /* CONFIG_HARDLOCKUP_DETECTOR */
+
+/* prepare/enable/disable routines */
+static int watchdog_prepare_cpu(int cpu)
+{
+ struct hrtimer *hrtimer = &per_cpu(watchdog_hrtimer, cpu);
+
+ WARN_ON(per_cpu(softlockup_watchdog, cpu));
+ hrtimer_init(hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+ hrtimer->function = watchdog_timer_fn;
+
+ return 0;
+}
+
+static int watchdog_enable(int cpu)
+{
+ struct task_struct *p = per_cpu(softlockup_watchdog, cpu);
+
+ /* enable the perf event */
+ if (watchdog_nmi_enable(cpu) != 0)
+ return -1;
+
+ /* create the watchdog thread */
+ if (!p) {
+ p = kthread_create(watchdog, (void *)(unsigned long)cpu, "watchdog/%d", cpu);
+ if (IS_ERR(p)) {
+ printk(KERN_ERR "softlockup watchdog for %i failed\n", cpu);
+ return -1;
+ }
+ kthread_bind(p, cpu);
+ per_cpu(watchdog_touch_ts, cpu) = 0;
+ per_cpu(softlockup_watchdog, cpu) = p;
+ wake_up_process(p);
+ }
+
+ return 0;
+}
+
+static void watchdog_disable(int cpu)
+{
+ struct task_struct *p = per_cpu(softlockup_watchdog, cpu);
+ struct hrtimer *hrtimer = &per_cpu(watchdog_hrtimer, cpu);
+
+ /*
+ * cancel the timer first to stop incrementing the stats
+ * and waking up the kthread
+ */
+ hrtimer_cancel(hrtimer);
+
+ /* disable the perf event */
+ watchdog_nmi_disable(cpu);
+
+ /* stop the watchdog thread */
+ if (p) {
+ per_cpu(softlockup_watchdog, cpu) = NULL;
+ kthread_stop(p);
+ }
+
+ /* if any cpu succeeds, watchdog is considered enabled for the system */
+ watchdog_enabled = 1;
+}
+
+static void watchdog_enable_all_cpus(void)
+{
+ int cpu;
+ int result = 0;
+
+ for_each_online_cpu(cpu)
+ result += watchdog_enable(cpu);
+
+ if (result)
+ printk(KERN_ERR "watchdog: failed to be enabled on some cpus\n");
+
+}
+
+static void watchdog_disable_all_cpus(void)
+{
+ int cpu;
+
+ for_each_online_cpu(cpu)
+ watchdog_disable(cpu);
+
+ /* if all watchdogs are disabled, then they are disabled for the system */
+ watchdog_enabled = 0;
+}
+
+
+/* sysctl functions */
+#ifdef CONFIG_SYSCTL
+/*
+ * proc handler for /proc/sys/kernel/nmi_watchdog
+ */
+
+int proc_dowatchdog_enabled(struct ctl_table *table, int write,
+ void __user *buffer, size_t *length, loff_t *ppos)
+{
+ proc_dointvec(table, write, buffer, length, ppos);
+
+ if (watchdog_enabled)
+ watchdog_enable_all_cpus();
+ else
+ watchdog_disable_all_cpus();
+ return 0;
+}
+
+int proc_dowatchdog_thresh(struct ctl_table *table, int write,
+ void __user *buffer,
+ size_t *lenp, loff_t *ppos)
+{
+ return proc_dointvec_minmax(table, write, buffer, lenp, ppos);
+}
+#endif /* CONFIG_SYSCTL */
+
+
+/*
+ * Create/destroy watchdog threads as CPUs come and go:
+ */
+static int __cpuinit
+cpu_callback(struct notifier_block *nfb, unsigned long action, void *hcpu)
+{
+ int hotcpu = (unsigned long)hcpu;
+
+ switch (action) {
+ case CPU_UP_PREPARE:
+ case CPU_UP_PREPARE_FROZEN:
+ if (watchdog_prepare_cpu(hotcpu))
+ return NOTIFY_BAD;
+ break;
+ case CPU_ONLINE:
+ case CPU_ONLINE_FROZEN:
+ if (watchdog_enable(hotcpu))
+ return NOTIFY_BAD;
+ break;
+#ifdef CONFIG_HOTPLUG_CPU
+ case CPU_UP_CANCELED:
+ case CPU_UP_CANCELED_FROZEN:
+ watchdog_disable(hotcpu);
+ break;
+ case CPU_DEAD:
+ case CPU_DEAD_FROZEN:
+ watchdog_disable(hotcpu);
+ break;
+#endif /* CONFIG_HOTPLUG_CPU */
+ }
+ return NOTIFY_OK;
+}
+
+static struct notifier_block __cpuinitdata cpu_nfb = {
+ .notifier_call = cpu_callback
+};
+
+static int __init spawn_watchdog_task(void)
+{
+ void *cpu = (void *)(long)smp_processor_id();
+ int err;
+
+ if (no_watchdog)
+ return 0;
+
+ err = cpu_callback(&cpu_nfb, CPU_UP_PREPARE, cpu);
+ WARN_ON(err == NOTIFY_BAD);
+
+ cpu_callback(&cpu_nfb, CPU_ONLINE, cpu);
+ register_cpu_notifier(&cpu_nfb);
+
+ atomic_notifier_chain_register(&panic_notifier_list, &panic_block);
+
+ return 0;
+}
+early_initcall(spawn_watchdog_task);
diff --git a/kernel/workqueue.c b/kernel/workqueue.c
index 327d2deb445..9ca34cddaf6 100644
--- a/kernel/workqueue.c
+++ b/kernel/workqueue.c
@@ -33,41 +33,287 @@
#include <linux/kallsyms.h>
#include <linux/debug_locks.h>
#include <linux/lockdep.h>
-#define CREATE_TRACE_POINTS
-#include <trace/events/workqueue.h>
+#include <linux/idr.h>
+
+#include "workqueue_sched.h"
+
+enum {
+ /* global_cwq flags */
+ GCWQ_MANAGE_WORKERS = 1 << 0, /* need to manage workers */
+ GCWQ_MANAGING_WORKERS = 1 << 1, /* managing workers */
+ GCWQ_DISASSOCIATED = 1 << 2, /* cpu can't serve workers */
+ GCWQ_FREEZING = 1 << 3, /* freeze in progress */
+ GCWQ_HIGHPRI_PENDING = 1 << 4, /* highpri works on queue */
+
+ /* worker flags */
+ WORKER_STARTED = 1 << 0, /* started */
+ WORKER_DIE = 1 << 1, /* die die die */
+ WORKER_IDLE = 1 << 2, /* is idle */
+ WORKER_PREP = 1 << 3, /* preparing to run works */
+ WORKER_ROGUE = 1 << 4, /* not bound to any cpu */
+ WORKER_REBIND = 1 << 5, /* mom is home, come back */
+ WORKER_CPU_INTENSIVE = 1 << 6, /* cpu intensive */
+ WORKER_UNBOUND = 1 << 7, /* worker is unbound */
+
+ WORKER_NOT_RUNNING = WORKER_PREP | WORKER_ROGUE | WORKER_REBIND |
+ WORKER_CPU_INTENSIVE | WORKER_UNBOUND,
+
+ /* gcwq->trustee_state */
+ TRUSTEE_START = 0, /* start */
+ TRUSTEE_IN_CHARGE = 1, /* trustee in charge of gcwq */
+ TRUSTEE_BUTCHER = 2, /* butcher workers */
+ TRUSTEE_RELEASE = 3, /* release workers */
+ TRUSTEE_DONE = 4, /* trustee is done */
+
+ BUSY_WORKER_HASH_ORDER = 6, /* 64 pointers */
+ BUSY_WORKER_HASH_SIZE = 1 << BUSY_WORKER_HASH_ORDER,
+ BUSY_WORKER_HASH_MASK = BUSY_WORKER_HASH_SIZE - 1,
+
+ MAX_IDLE_WORKERS_RATIO = 4, /* 1/4 of busy can be idle */
+ IDLE_WORKER_TIMEOUT = 300 * HZ, /* keep idle ones for 5 mins */
+
+ MAYDAY_INITIAL_TIMEOUT = HZ / 100, /* call for help after 10ms */
+ MAYDAY_INTERVAL = HZ / 10, /* and then every 100ms */
+ CREATE_COOLDOWN = HZ, /* time to breath after fail */
+ TRUSTEE_COOLDOWN = HZ / 10, /* for trustee draining */
+
+ /*
+ * Rescue workers are used only on emergencies and shared by
+ * all cpus. Give -20.
+ */
+ RESCUER_NICE_LEVEL = -20,
+};
/*
- * The per-CPU workqueue (if single thread, we always use the first
- * possible cpu).
+ * Structure fields follow one of the following exclusion rules.
+ *
+ * I: Set during initialization and read-only afterwards.
+ *
+ * P: Preemption protected. Disabling preemption is enough and should
+ * only be modified and accessed from the local cpu.
+ *
+ * L: gcwq->lock protected. Access with gcwq->lock held.
+ *
+ * X: During normal operation, modification requires gcwq->lock and
+ * should be done only from local cpu. Either disabling preemption
+ * on local cpu or grabbing gcwq->lock is enough for read access.
+ * If GCWQ_DISASSOCIATED is set, it's identical to L.
+ *
+ * F: wq->flush_mutex protected.
+ *
+ * W: workqueue_lock protected.
*/
-struct cpu_workqueue_struct {
- spinlock_t lock;
+struct global_cwq;
- struct list_head worklist;
- wait_queue_head_t more_work;
- struct work_struct *current_work;
+/*
+ * The poor guys doing the actual heavy lifting. All on-duty workers
+ * are either serving the manager role, on idle list or on busy hash.
+ */
+struct worker {
+ /* on idle list while idle, on busy hash table while busy */
+ union {
+ struct list_head entry; /* L: while idle */
+ struct hlist_node hentry; /* L: while busy */
+ };
- struct workqueue_struct *wq;
- struct task_struct *thread;
-} ____cacheline_aligned;
+ struct work_struct *current_work; /* L: work being processed */
+ struct cpu_workqueue_struct *current_cwq; /* L: current_work's cwq */
+ struct list_head scheduled; /* L: scheduled works */
+ struct task_struct *task; /* I: worker task */
+ struct global_cwq *gcwq; /* I: the associated gcwq */
+ /* 64 bytes boundary on 64bit, 32 on 32bit */
+ unsigned long last_active; /* L: last active timestamp */
+ unsigned int flags; /* X: flags */
+ int id; /* I: worker id */
+ struct work_struct rebind_work; /* L: rebind worker to cpu */
+};
+
+/*
+ * Global per-cpu workqueue. There's one and only one for each cpu
+ * and all works are queued and processed here regardless of their
+ * target workqueues.
+ */
+struct global_cwq {
+ spinlock_t lock; /* the gcwq lock */
+ struct list_head worklist; /* L: list of pending works */
+ unsigned int cpu; /* I: the associated cpu */
+ unsigned int flags; /* L: GCWQ_* flags */
+
+ int nr_workers; /* L: total number of workers */
+ int nr_idle; /* L: currently idle ones */
+
+ /* workers are chained either in the idle_list or busy_hash */
+ struct list_head idle_list; /* X: list of idle workers */
+ struct hlist_head busy_hash[BUSY_WORKER_HASH_SIZE];
+ /* L: hash of busy workers */
+
+ struct timer_list idle_timer; /* L: worker idle timeout */
+ struct timer_list mayday_timer; /* L: SOS timer for dworkers */
+
+ struct ida worker_ida; /* L: for worker IDs */
+
+ struct task_struct *trustee; /* L: for gcwq shutdown */
+ unsigned int trustee_state; /* L: trustee state */
+ wait_queue_head_t trustee_wait; /* trustee wait */
+ struct worker *first_idle; /* L: first idle worker */
+} ____cacheline_aligned_in_smp;
+
+/*
+ * The per-CPU workqueue. The lower WORK_STRUCT_FLAG_BITS of
+ * work_struct->data are used for flags and thus cwqs need to be
+ * aligned at two's power of the number of flag bits.
+ */
+struct cpu_workqueue_struct {
+ struct global_cwq *gcwq; /* I: the associated gcwq */
+ struct workqueue_struct *wq; /* I: the owning workqueue */
+ int work_color; /* L: current color */
+ int flush_color; /* L: flushing color */
+ int nr_in_flight[WORK_NR_COLORS];
+ /* L: nr of in_flight works */
+ int nr_active; /* L: nr of active works */
+ int max_active; /* L: max active works */
+ struct list_head delayed_works; /* L: delayed works */
+};
+
+/*
+ * Structure used to wait for workqueue flush.
+ */
+struct wq_flusher {
+ struct list_head list; /* F: list of flushers */
+ int flush_color; /* F: flush color waiting for */
+ struct completion done; /* flush completion */
+};
+
+/*
+ * All cpumasks are assumed to be always set on UP and thus can't be
+ * used to determine whether there's something to be done.
+ */
+#ifdef CONFIG_SMP
+typedef cpumask_var_t mayday_mask_t;
+#define mayday_test_and_set_cpu(cpu, mask) \
+ cpumask_test_and_set_cpu((cpu), (mask))
+#define mayday_clear_cpu(cpu, mask) cpumask_clear_cpu((cpu), (mask))
+#define for_each_mayday_cpu(cpu, mask) for_each_cpu((cpu), (mask))
+#define alloc_mayday_mask(maskp, gfp) alloc_cpumask_var((maskp), (gfp))
+#define free_mayday_mask(mask) free_cpumask_var((mask))
+#else
+typedef unsigned long mayday_mask_t;
+#define mayday_test_and_set_cpu(cpu, mask) test_and_set_bit(0, &(mask))
+#define mayday_clear_cpu(cpu, mask) clear_bit(0, &(mask))
+#define for_each_mayday_cpu(cpu, mask) if ((cpu) = 0, (mask))
+#define alloc_mayday_mask(maskp, gfp) true
+#define free_mayday_mask(mask) do { } while (0)
+#endif
/*
* The externally visible workqueue abstraction is an array of
* per-CPU workqueues:
*/
struct workqueue_struct {
- struct cpu_workqueue_struct *cpu_wq;
- struct list_head list;
- const char *name;
- int singlethread;
- int freezeable; /* Freeze threads during suspend */
- int rt;
+ unsigned int flags; /* I: WQ_* flags */
+ union {
+ struct cpu_workqueue_struct __percpu *pcpu;
+ struct cpu_workqueue_struct *single;
+ unsigned long v;
+ } cpu_wq; /* I: cwq's */
+ struct list_head list; /* W: list of all workqueues */
+
+ struct mutex flush_mutex; /* protects wq flushing */
+ int work_color; /* F: current work color */
+ int flush_color; /* F: current flush color */
+ atomic_t nr_cwqs_to_flush; /* flush in progress */
+ struct wq_flusher *first_flusher; /* F: first flusher */
+ struct list_head flusher_queue; /* F: flush waiters */
+ struct list_head flusher_overflow; /* F: flush overflow list */
+
+ mayday_mask_t mayday_mask; /* cpus requesting rescue */
+ struct worker *rescuer; /* I: rescue worker */
+
+ int saved_max_active; /* W: saved cwq max_active */
+ const char *name; /* I: workqueue name */
#ifdef CONFIG_LOCKDEP
- struct lockdep_map lockdep_map;
+ struct lockdep_map lockdep_map;
#endif
};
+struct workqueue_struct *system_wq __read_mostly;
+struct workqueue_struct *system_long_wq __read_mostly;
+struct workqueue_struct *system_nrt_wq __read_mostly;
+struct workqueue_struct *system_unbound_wq __read_mostly;
+EXPORT_SYMBOL_GPL(system_wq);
+EXPORT_SYMBOL_GPL(system_long_wq);
+EXPORT_SYMBOL_GPL(system_nrt_wq);
+EXPORT_SYMBOL_GPL(system_unbound_wq);
+
+#define for_each_busy_worker(worker, i, pos, gcwq) \
+ for (i = 0; i < BUSY_WORKER_HASH_SIZE; i++) \
+ hlist_for_each_entry(worker, pos, &gcwq->busy_hash[i], hentry)
+
+static inline int __next_gcwq_cpu(int cpu, const struct cpumask *mask,
+ unsigned int sw)
+{
+ if (cpu < nr_cpu_ids) {
+ if (sw & 1) {
+ cpu = cpumask_next(cpu, mask);
+ if (cpu < nr_cpu_ids)
+ return cpu;
+ }
+ if (sw & 2)
+ return WORK_CPU_UNBOUND;
+ }
+ return WORK_CPU_NONE;
+}
+
+static inline int __next_wq_cpu(int cpu, const struct cpumask *mask,
+ struct workqueue_struct *wq)
+{
+ return __next_gcwq_cpu(cpu, mask, !(wq->flags & WQ_UNBOUND) ? 1 : 2);
+}
+
+/*
+ * CPU iterators
+ *
+ * An extra gcwq is defined for an invalid cpu number
+ * (WORK_CPU_UNBOUND) to host workqueues which are not bound to any
+ * specific CPU. The following iterators are similar to
+ * for_each_*_cpu() iterators but also considers the unbound gcwq.
+ *
+ * for_each_gcwq_cpu() : possible CPUs + WORK_CPU_UNBOUND
+ * for_each_online_gcwq_cpu() : online CPUs + WORK_CPU_UNBOUND
+ * for_each_cwq_cpu() : possible CPUs for bound workqueues,
+ * WORK_CPU_UNBOUND for unbound workqueues
+ */
+#define for_each_gcwq_cpu(cpu) \
+ for ((cpu) = __next_gcwq_cpu(-1, cpu_possible_mask, 3); \
+ (cpu) < WORK_CPU_NONE; \
+ (cpu) = __next_gcwq_cpu((cpu), cpu_possible_mask, 3))
+
+#define for_each_online_gcwq_cpu(cpu) \
+ for ((cpu) = __next_gcwq_cpu(-1, cpu_online_mask, 3); \
+ (cpu) < WORK_CPU_NONE; \
+ (cpu) = __next_gcwq_cpu((cpu), cpu_online_mask, 3))
+
+#define for_each_cwq_cpu(cpu, wq) \
+ for ((cpu) = __next_wq_cpu(-1, cpu_possible_mask, (wq)); \
+ (cpu) < WORK_CPU_NONE; \
+ (cpu) = __next_wq_cpu((cpu), cpu_possible_mask, (wq)))
+
+#ifdef CONFIG_LOCKDEP
+/**
+ * in_workqueue_context() - in context of specified workqueue?
+ * @wq: the workqueue of interest
+ *
+ * Checks lockdep state to see if the current task is executing from
+ * within a workqueue item. This function exists only if lockdep is
+ * enabled.
+ */
+int in_workqueue_context(struct workqueue_struct *wq)
+{
+ return lock_is_held(&wq->lockdep_map);
+}
+#endif
+
#ifdef CONFIG_DEBUG_OBJECTS_WORK
static struct debug_obj_descr work_debug_descr;
@@ -107,7 +353,7 @@ static int work_fixup_activate(void *addr, enum debug_obj_state state)
* statically initialized. We just make sure that it
* is tracked in the object tracker.
*/
- if (test_bit(WORK_STRUCT_STATIC, work_data_bits(work))) {
+ if (test_bit(WORK_STRUCT_STATIC_BIT, work_data_bits(work))) {
debug_object_init(work, &work_debug_descr);
debug_object_activate(work, &work_debug_descr);
return 0;
@@ -181,94 +427,575 @@ static inline void debug_work_deactivate(struct work_struct *work) { }
/* Serializes the accesses to the list of workqueues. */
static DEFINE_SPINLOCK(workqueue_lock);
static LIST_HEAD(workqueues);
+static bool workqueue_freezing; /* W: have wqs started freezing? */
+
+/*
+ * The almighty global cpu workqueues. nr_running is the only field
+ * which is expected to be used frequently by other cpus via
+ * try_to_wake_up(). Put it in a separate cacheline.
+ */
+static DEFINE_PER_CPU(struct global_cwq, global_cwq);
+static DEFINE_PER_CPU_SHARED_ALIGNED(atomic_t, gcwq_nr_running);
-static int singlethread_cpu __read_mostly;
-static const struct cpumask *cpu_singlethread_map __read_mostly;
/*
- * _cpu_down() first removes CPU from cpu_online_map, then CPU_DEAD
- * flushes cwq->worklist. This means that flush_workqueue/wait_on_work
- * which comes in between can't use for_each_online_cpu(). We could
- * use cpu_possible_map, the cpumask below is more a documentation
- * than optimization.
+ * Global cpu workqueue and nr_running counter for unbound gcwq. The
+ * gcwq is always online, has GCWQ_DISASSOCIATED set, and all its
+ * workers have WORKER_UNBOUND set.
*/
-static cpumask_var_t cpu_populated_map __read_mostly;
+static struct global_cwq unbound_global_cwq;
+static atomic_t unbound_gcwq_nr_running = ATOMIC_INIT(0); /* always 0 */
-/* If it's single threaded, it isn't in the list of workqueues. */
-static inline int is_wq_single_threaded(struct workqueue_struct *wq)
+static int worker_thread(void *__worker);
+
+static struct global_cwq *get_gcwq(unsigned int cpu)
{
- return wq->singlethread;
+ if (cpu != WORK_CPU_UNBOUND)
+ return &per_cpu(global_cwq, cpu);
+ else
+ return &unbound_global_cwq;
}
-static const struct cpumask *wq_cpu_map(struct workqueue_struct *wq)
+static atomic_t *get_gcwq_nr_running(unsigned int cpu)
{
- return is_wq_single_threaded(wq)
- ? cpu_singlethread_map : cpu_populated_map;
+ if (cpu != WORK_CPU_UNBOUND)
+ return &per_cpu(gcwq_nr_running, cpu);
+ else
+ return &unbound_gcwq_nr_running;
}
-static
-struct cpu_workqueue_struct *wq_per_cpu(struct workqueue_struct *wq, int cpu)
+static struct cpu_workqueue_struct *get_cwq(unsigned int cpu,
+ struct workqueue_struct *wq)
{
- if (unlikely(is_wq_single_threaded(wq)))
- cpu = singlethread_cpu;
- return per_cpu_ptr(wq->cpu_wq, cpu);
+ if (!(wq->flags & WQ_UNBOUND)) {
+ if (likely(cpu < nr_cpu_ids)) {
+#ifdef CONFIG_SMP
+ return per_cpu_ptr(wq->cpu_wq.pcpu, cpu);
+#else
+ return wq->cpu_wq.single;
+#endif
+ }
+ } else if (likely(cpu == WORK_CPU_UNBOUND))
+ return wq->cpu_wq.single;
+ return NULL;
+}
+
+static unsigned int work_color_to_flags(int color)
+{
+ return color << WORK_STRUCT_COLOR_SHIFT;
+}
+
+static int get_work_color(struct work_struct *work)
+{
+ return (*work_data_bits(work) >> WORK_STRUCT_COLOR_SHIFT) &
+ ((1 << WORK_STRUCT_COLOR_BITS) - 1);
+}
+
+static int work_next_color(int color)
+{
+ return (color + 1) % WORK_NR_COLORS;
}
/*
- * Set the workqueue on which a work item is to be run
- * - Must *only* be called if the pending flag is set
+ * A work's data points to the cwq with WORK_STRUCT_CWQ set while the
+ * work is on queue. Once execution starts, WORK_STRUCT_CWQ is
+ * cleared and the work data contains the cpu number it was last on.
+ *
+ * set_work_{cwq|cpu}() and clear_work_data() can be used to set the
+ * cwq, cpu or clear work->data. These functions should only be
+ * called while the work is owned - ie. while the PENDING bit is set.
+ *
+ * get_work_[g]cwq() can be used to obtain the gcwq or cwq
+ * corresponding to a work. gcwq is available once the work has been
+ * queued anywhere after initialization. cwq is available only from
+ * queueing until execution starts.
*/
-static inline void set_wq_data(struct work_struct *work,
- struct cpu_workqueue_struct *cwq)
+static inline void set_work_data(struct work_struct *work, unsigned long data,
+ unsigned long flags)
{
- unsigned long new;
-
BUG_ON(!work_pending(work));
+ atomic_long_set(&work->data, data | flags | work_static(work));
+}
+
+static void set_work_cwq(struct work_struct *work,
+ struct cpu_workqueue_struct *cwq,
+ unsigned long extra_flags)
+{
+ set_work_data(work, (unsigned long)cwq,
+ WORK_STRUCT_PENDING | WORK_STRUCT_CWQ | extra_flags);
+}
+
+static void set_work_cpu(struct work_struct *work, unsigned int cpu)
+{
+ set_work_data(work, cpu << WORK_STRUCT_FLAG_BITS, WORK_STRUCT_PENDING);
+}
+
+static void clear_work_data(struct work_struct *work)
+{
+ set_work_data(work, WORK_STRUCT_NO_CPU, 0);
+}
+
+static struct cpu_workqueue_struct *get_work_cwq(struct work_struct *work)
+{
+ unsigned long data = atomic_long_read(&work->data);
+
+ if (data & WORK_STRUCT_CWQ)
+ return (void *)(data & WORK_STRUCT_WQ_DATA_MASK);
+ else
+ return NULL;
+}
+
+static struct global_cwq *get_work_gcwq(struct work_struct *work)
+{
+ unsigned long data = atomic_long_read(&work->data);
+ unsigned int cpu;
+
+ if (data & WORK_STRUCT_CWQ)
+ return ((struct cpu_workqueue_struct *)
+ (data & WORK_STRUCT_WQ_DATA_MASK))->gcwq;
+
+ cpu = data >> WORK_STRUCT_FLAG_BITS;
+ if (cpu == WORK_CPU_NONE)
+ return NULL;
+
+ BUG_ON(cpu >= nr_cpu_ids && cpu != WORK_CPU_UNBOUND);
+ return get_gcwq(cpu);
+}
+
+/*
+ * Policy functions. These define the policies on how the global
+ * worker pool is managed. Unless noted otherwise, these functions
+ * assume that they're being called with gcwq->lock held.
+ */
+
+static bool __need_more_worker(struct global_cwq *gcwq)
+{
+ return !atomic_read(get_gcwq_nr_running(gcwq->cpu)) ||
+ gcwq->flags & GCWQ_HIGHPRI_PENDING;
+}
+
+/*
+ * Need to wake up a worker? Called from anything but currently
+ * running workers.
+ */
+static bool need_more_worker(struct global_cwq *gcwq)
+{
+ return !list_empty(&gcwq->worklist) && __need_more_worker(gcwq);
+}
+
+/* Can I start working? Called from busy but !running workers. */
+static bool may_start_working(struct global_cwq *gcwq)
+{
+ return gcwq->nr_idle;
+}
+
+/* Do I need to keep working? Called from currently running workers. */
+static bool keep_working(struct global_cwq *gcwq)
+{
+ atomic_t *nr_running = get_gcwq_nr_running(gcwq->cpu);
+
+ return !list_empty(&gcwq->worklist) && atomic_read(nr_running) <= 1;
+}
+
+/* Do we need a new worker? Called from manager. */
+static bool need_to_create_worker(struct global_cwq *gcwq)
+{
+ return need_more_worker(gcwq) && !may_start_working(gcwq);
+}
+
+/* Do I need to be the manager? */
+static bool need_to_manage_workers(struct global_cwq *gcwq)
+{
+ return need_to_create_worker(gcwq) || gcwq->flags & GCWQ_MANAGE_WORKERS;
+}
+
+/* Do we have too many workers and should some go away? */
+static bool too_many_workers(struct global_cwq *gcwq)
+{
+ bool managing = gcwq->flags & GCWQ_MANAGING_WORKERS;
+ int nr_idle = gcwq->nr_idle + managing; /* manager is considered idle */
+ int nr_busy = gcwq->nr_workers - nr_idle;
- new = (unsigned long) cwq | (1UL << WORK_STRUCT_PENDING);
- new |= WORK_STRUCT_FLAG_MASK & *work_data_bits(work);
- atomic_long_set(&work->data, new);
+ return nr_idle > 2 && (nr_idle - 2) * MAX_IDLE_WORKERS_RATIO >= nr_busy;
}
/*
- * Clear WORK_STRUCT_PENDING and the workqueue on which it was queued.
+ * Wake up functions.
*/
-static inline void clear_wq_data(struct work_struct *work)
+
+/* Return the first worker. Safe with preemption disabled */
+static struct worker *first_worker(struct global_cwq *gcwq)
{
- unsigned long flags = *work_data_bits(work) &
- (1UL << WORK_STRUCT_STATIC);
- atomic_long_set(&work->data, flags);
+ if (unlikely(list_empty(&gcwq->idle_list)))
+ return NULL;
+
+ return list_first_entry(&gcwq->idle_list, struct worker, entry);
}
-static inline
-struct cpu_workqueue_struct *get_wq_data(struct work_struct *work)
+/**
+ * wake_up_worker - wake up an idle worker
+ * @gcwq: gcwq to wake worker for
+ *
+ * Wake up the first idle worker of @gcwq.
+ *
+ * CONTEXT:
+ * spin_lock_irq(gcwq->lock).
+ */
+static void wake_up_worker(struct global_cwq *gcwq)
{
- return (void *) (atomic_long_read(&work->data) & WORK_STRUCT_WQ_DATA_MASK);
+ struct worker *worker = first_worker(gcwq);
+
+ if (likely(worker))
+ wake_up_process(worker->task);
+}
+
+/**
+ * wq_worker_waking_up - a worker is waking up
+ * @task: task waking up
+ * @cpu: CPU @task is waking up to
+ *
+ * This function is called during try_to_wake_up() when a worker is
+ * being awoken.
+ *
+ * CONTEXT:
+ * spin_lock_irq(rq->lock)
+ */
+void wq_worker_waking_up(struct task_struct *task, unsigned int cpu)
+{
+ struct worker *worker = kthread_data(task);
+
+ if (likely(!(worker->flags & WORKER_NOT_RUNNING)))
+ atomic_inc(get_gcwq_nr_running(cpu));
+}
+
+/**
+ * wq_worker_sleeping - a worker is going to sleep
+ * @task: task going to sleep
+ * @cpu: CPU in question, must be the current CPU number
+ *
+ * This function is called during schedule() when a busy worker is
+ * going to sleep. Worker on the same cpu can be woken up by
+ * returning pointer to its task.
+ *
+ * CONTEXT:
+ * spin_lock_irq(rq->lock)
+ *
+ * RETURNS:
+ * Worker task on @cpu to wake up, %NULL if none.
+ */
+struct task_struct *wq_worker_sleeping(struct task_struct *task,
+ unsigned int cpu)
+{
+ struct worker *worker = kthread_data(task), *to_wakeup = NULL;
+ struct global_cwq *gcwq = get_gcwq(cpu);
+ atomic_t *nr_running = get_gcwq_nr_running(cpu);
+
+ if (unlikely(worker->flags & WORKER_NOT_RUNNING))
+ return NULL;
+
+ /* this can only happen on the local cpu */
+ BUG_ON(cpu != raw_smp_processor_id());
+
+ /*
+ * The counterpart of the following dec_and_test, implied mb,
+ * worklist not empty test sequence is in insert_work().
+ * Please read comment there.
+ *
+ * NOT_RUNNING is clear. This means that trustee is not in
+ * charge and we're running on the local cpu w/ rq lock held
+ * and preemption disabled, which in turn means that none else
+ * could be manipulating idle_list, so dereferencing idle_list
+ * without gcwq lock is safe.
+ */
+ if (atomic_dec_and_test(nr_running) && !list_empty(&gcwq->worklist))
+ to_wakeup = first_worker(gcwq);
+ return to_wakeup ? to_wakeup->task : NULL;
+}
+
+/**
+ * worker_set_flags - set worker flags and adjust nr_running accordingly
+ * @worker: self
+ * @flags: flags to set
+ * @wakeup: wakeup an idle worker if necessary
+ *
+ * Set @flags in @worker->flags and adjust nr_running accordingly. If
+ * nr_running becomes zero and @wakeup is %true, an idle worker is
+ * woken up.
+ *
+ * CONTEXT:
+ * spin_lock_irq(gcwq->lock)
+ */
+static inline void worker_set_flags(struct worker *worker, unsigned int flags,
+ bool wakeup)
+{
+ struct global_cwq *gcwq = worker->gcwq;
+
+ WARN_ON_ONCE(worker->task != current);
+
+ /*
+ * If transitioning into NOT_RUNNING, adjust nr_running and
+ * wake up an idle worker as necessary if requested by
+ * @wakeup.
+ */
+ if ((flags & WORKER_NOT_RUNNING) &&
+ !(worker->flags & WORKER_NOT_RUNNING)) {
+ atomic_t *nr_running = get_gcwq_nr_running(gcwq->cpu);
+
+ if (wakeup) {
+ if (atomic_dec_and_test(nr_running) &&
+ !list_empty(&gcwq->worklist))
+ wake_up_worker(gcwq);
+ } else
+ atomic_dec(nr_running);
+ }
+
+ worker->flags |= flags;
}
+/**
+ * worker_clr_flags - clear worker flags and adjust nr_running accordingly
+ * @worker: self
+ * @flags: flags to clear
+ *
+ * Clear @flags in @worker->flags and adjust nr_running accordingly.
+ *
+ * CONTEXT:
+ * spin_lock_irq(gcwq->lock)
+ */
+static inline void worker_clr_flags(struct worker *worker, unsigned int flags)
+{
+ struct global_cwq *gcwq = worker->gcwq;
+ unsigned int oflags = worker->flags;
+
+ WARN_ON_ONCE(worker->task != current);
+
+ worker->flags &= ~flags;
+
+ /* if transitioning out of NOT_RUNNING, increment nr_running */
+ if ((flags & WORKER_NOT_RUNNING) && (oflags & WORKER_NOT_RUNNING))
+ if (!(worker->flags & WORKER_NOT_RUNNING))
+ atomic_inc(get_gcwq_nr_running(gcwq->cpu));
+}
+
+/**
+ * busy_worker_head - return the busy hash head for a work
+ * @gcwq: gcwq of interest
+ * @work: work to be hashed
+ *
+ * Return hash head of @gcwq for @work.
+ *
+ * CONTEXT:
+ * spin_lock_irq(gcwq->lock).
+ *
+ * RETURNS:
+ * Pointer to the hash head.
+ */
+static struct hlist_head *busy_worker_head(struct global_cwq *gcwq,
+ struct work_struct *work)
+{
+ const int base_shift = ilog2(sizeof(struct work_struct));
+ unsigned long v = (unsigned long)work;
+
+ /* simple shift and fold hash, do we need something better? */
+ v >>= base_shift;
+ v += v >> BUSY_WORKER_HASH_ORDER;
+ v &= BUSY_WORKER_HASH_MASK;
+
+ return &gcwq->busy_hash[v];
+}
+
+/**
+ * __find_worker_executing_work - find worker which is executing a work
+ * @gcwq: gcwq of interest
+ * @bwh: hash head as returned by busy_worker_head()
+ * @work: work to find worker for
+ *
+ * Find a worker which is executing @work on @gcwq. @bwh should be
+ * the hash head obtained by calling busy_worker_head() with the same
+ * work.
+ *
+ * CONTEXT:
+ * spin_lock_irq(gcwq->lock).
+ *
+ * RETURNS:
+ * Pointer to worker which is executing @work if found, NULL
+ * otherwise.
+ */
+static struct worker *__find_worker_executing_work(struct global_cwq *gcwq,
+ struct hlist_head *bwh,
+ struct work_struct *work)
+{
+ struct worker *worker;
+ struct hlist_node *tmp;
+
+ hlist_for_each_entry(worker, tmp, bwh, hentry)
+ if (worker->current_work == work)
+ return worker;
+ return NULL;
+}
+
+/**
+ * find_worker_executing_work - find worker which is executing a work
+ * @gcwq: gcwq of interest
+ * @work: work to find worker for
+ *
+ * Find a worker which is executing @work on @gcwq. This function is
+ * identical to __find_worker_executing_work() except that this
+ * function calculates @bwh itself.
+ *
+ * CONTEXT:
+ * spin_lock_irq(gcwq->lock).
+ *
+ * RETURNS:
+ * Pointer to worker which is executing @work if found, NULL
+ * otherwise.
+ */
+static struct worker *find_worker_executing_work(struct global_cwq *gcwq,
+ struct work_struct *work)
+{
+ return __find_worker_executing_work(gcwq, busy_worker_head(gcwq, work),
+ work);
+}
+
+/**
+ * gcwq_determine_ins_pos - find insertion position
+ * @gcwq: gcwq of interest
+ * @cwq: cwq a work is being queued for
+ *
+ * A work for @cwq is about to be queued on @gcwq, determine insertion
+ * position for the work. If @cwq is for HIGHPRI wq, the work is
+ * queued at the head of the queue but in FIFO order with respect to
+ * other HIGHPRI works; otherwise, at the end of the queue. This
+ * function also sets GCWQ_HIGHPRI_PENDING flag to hint @gcwq that
+ * there are HIGHPRI works pending.
+ *
+ * CONTEXT:
+ * spin_lock_irq(gcwq->lock).
+ *
+ * RETURNS:
+ * Pointer to inserstion position.
+ */
+static inline struct list_head *gcwq_determine_ins_pos(struct global_cwq *gcwq,
+ struct cpu_workqueue_struct *cwq)
+{
+ struct work_struct *twork;
+
+ if (likely(!(cwq->wq->flags & WQ_HIGHPRI)))
+ return &gcwq->worklist;
+
+ list_for_each_entry(twork, &gcwq->worklist, entry) {
+ struct cpu_workqueue_struct *tcwq = get_work_cwq(twork);
+
+ if (!(tcwq->wq->flags & WQ_HIGHPRI))
+ break;
+ }
+
+ gcwq->flags |= GCWQ_HIGHPRI_PENDING;
+ return &twork->entry;
+}
+
+/**
+ * insert_work - insert a work into gcwq
+ * @cwq: cwq @work belongs to
+ * @work: work to insert
+ * @head: insertion point
+ * @extra_flags: extra WORK_STRUCT_* flags to set
+ *
+ * Insert @work which belongs to @cwq into @gcwq after @head.
+ * @extra_flags is or'd to work_struct flags.
+ *
+ * CONTEXT:
+ * spin_lock_irq(gcwq->lock).
+ */
static void insert_work(struct cpu_workqueue_struct *cwq,
- struct work_struct *work, struct list_head *head)
+ struct work_struct *work, struct list_head *head,
+ unsigned int extra_flags)
{
- trace_workqueue_insertion(cwq->thread, work);
+ struct global_cwq *gcwq = cwq->gcwq;
+
+ /* we own @work, set data and link */
+ set_work_cwq(work, cwq, extra_flags);
- set_wq_data(work, cwq);
/*
* Ensure that we get the right work->data if we see the
* result of list_add() below, see try_to_grab_pending().
*/
smp_wmb();
+
list_add_tail(&work->entry, head);
- wake_up(&cwq->more_work);
+
+ /*
+ * Ensure either worker_sched_deactivated() sees the above
+ * list_add_tail() or we see zero nr_running to avoid workers
+ * lying around lazily while there are works to be processed.
+ */
+ smp_mb();
+
+ if (__need_more_worker(gcwq))
+ wake_up_worker(gcwq);
}
-static void __queue_work(struct cpu_workqueue_struct *cwq,
+static void __queue_work(unsigned int cpu, struct workqueue_struct *wq,
struct work_struct *work)
{
+ struct global_cwq *gcwq;
+ struct cpu_workqueue_struct *cwq;
+ struct list_head *worklist;
unsigned long flags;
debug_work_activate(work);
- spin_lock_irqsave(&cwq->lock, flags);
- insert_work(cwq, work, &cwq->worklist);
- spin_unlock_irqrestore(&cwq->lock, flags);
+
+ /* determine gcwq to use */
+ if (!(wq->flags & WQ_UNBOUND)) {
+ struct global_cwq *last_gcwq;
+
+ if (unlikely(cpu == WORK_CPU_UNBOUND))
+ cpu = raw_smp_processor_id();
+
+ /*
+ * It's multi cpu. If @wq is non-reentrant and @work
+ * was previously on a different cpu, it might still
+ * be running there, in which case the work needs to
+ * be queued on that cpu to guarantee non-reentrance.
+ */
+ gcwq = get_gcwq(cpu);
+ if (wq->flags & WQ_NON_REENTRANT &&
+ (last_gcwq = get_work_gcwq(work)) && last_gcwq != gcwq) {
+ struct worker *worker;
+
+ spin_lock_irqsave(&last_gcwq->lock, flags);
+
+ worker = find_worker_executing_work(last_gcwq, work);
+
+ if (worker && worker->current_cwq->wq == wq)
+ gcwq = last_gcwq;
+ else {
+ /* meh... not running there, queue here */
+ spin_unlock_irqrestore(&last_gcwq->lock, flags);
+ spin_lock_irqsave(&gcwq->lock, flags);
+ }
+ } else
+ spin_lock_irqsave(&gcwq->lock, flags);
+ } else {
+ gcwq = get_gcwq(WORK_CPU_UNBOUND);
+ spin_lock_irqsave(&gcwq->lock, flags);
+ }
+
+ /* gcwq determined, get cwq and queue */
+ cwq = get_cwq(gcwq->cpu, wq);
+
+ BUG_ON(!list_empty(&work->entry));
+
+ cwq->nr_in_flight[cwq->work_color]++;
+
+ if (likely(cwq->nr_active < cwq->max_active)) {
+ cwq->nr_active++;
+ worklist = gcwq_determine_ins_pos(gcwq, cwq);
+ } else
+ worklist = &cwq->delayed_works;
+
+ insert_work(cwq, work, worklist, work_color_to_flags(cwq->work_color));
+
+ spin_unlock_irqrestore(&gcwq->lock, flags);
}
/**
@@ -308,9 +1035,8 @@ queue_work_on(int cpu, struct workqueue_struct *wq, struct work_struct *work)
{
int ret = 0;
- if (!test_and_set_bit(WORK_STRUCT_PENDING, work_data_bits(work))) {
- BUG_ON(!list_empty(&work->entry));
- __queue_work(wq_per_cpu(wq, cpu), work);
+ if (!test_and_set_bit(WORK_STRUCT_PENDING_BIT, work_data_bits(work))) {
+ __queue_work(cpu, wq, work);
ret = 1;
}
return ret;
@@ -320,10 +1046,9 @@ EXPORT_SYMBOL_GPL(queue_work_on);
static void delayed_work_timer_fn(unsigned long __data)
{
struct delayed_work *dwork = (struct delayed_work *)__data;
- struct cpu_workqueue_struct *cwq = get_wq_data(&dwork->work);
- struct workqueue_struct *wq = cwq->wq;
+ struct cpu_workqueue_struct *cwq = get_work_cwq(&dwork->work);
- __queue_work(wq_per_cpu(wq, smp_processor_id()), &dwork->work);
+ __queue_work(smp_processor_id(), cwq->wq, &dwork->work);
}
/**
@@ -360,14 +1085,31 @@ int queue_delayed_work_on(int cpu, struct workqueue_struct *wq,
struct timer_list *timer = &dwork->timer;
struct work_struct *work = &dwork->work;
- if (!test_and_set_bit(WORK_STRUCT_PENDING, work_data_bits(work))) {
+ if (!test_and_set_bit(WORK_STRUCT_PENDING_BIT, work_data_bits(work))) {
+ unsigned int lcpu;
+
BUG_ON(timer_pending(timer));
BUG_ON(!list_empty(&work->entry));
timer_stats_timer_set_start_info(&dwork->timer);
- /* This stores cwq for the moment, for the timer_fn */
- set_wq_data(work, wq_per_cpu(wq, raw_smp_processor_id()));
+ /*
+ * This stores cwq for the moment, for the timer_fn.
+ * Note that the work's gcwq is preserved to allow
+ * reentrance detection for delayed works.
+ */
+ if (!(wq->flags & WQ_UNBOUND)) {
+ struct global_cwq *gcwq = get_work_gcwq(work);
+
+ if (gcwq && gcwq->cpu != WORK_CPU_UNBOUND)
+ lcpu = gcwq->cpu;
+ else
+ lcpu = raw_smp_processor_id();
+ } else
+ lcpu = WORK_CPU_UNBOUND;
+
+ set_work_cwq(work, get_cwq(lcpu, wq), 0);
+
timer->expires = jiffies + delay;
timer->data = (unsigned long)dwork;
timer->function = delayed_work_timer_fn;
@@ -382,80 +1124,872 @@ int queue_delayed_work_on(int cpu, struct workqueue_struct *wq,
}
EXPORT_SYMBOL_GPL(queue_delayed_work_on);
-static void run_workqueue(struct cpu_workqueue_struct *cwq)
+/**
+ * worker_enter_idle - enter idle state
+ * @worker: worker which is entering idle state
+ *
+ * @worker is entering idle state. Update stats and idle timer if
+ * necessary.
+ *
+ * LOCKING:
+ * spin_lock_irq(gcwq->lock).
+ */
+static void worker_enter_idle(struct worker *worker)
{
- spin_lock_irq(&cwq->lock);
- while (!list_empty(&cwq->worklist)) {
- struct work_struct *work = list_entry(cwq->worklist.next,
- struct work_struct, entry);
- work_func_t f = work->func;
-#ifdef CONFIG_LOCKDEP
+ struct global_cwq *gcwq = worker->gcwq;
+
+ BUG_ON(worker->flags & WORKER_IDLE);
+ BUG_ON(!list_empty(&worker->entry) &&
+ (worker->hentry.next || worker->hentry.pprev));
+
+ /* can't use worker_set_flags(), also called from start_worker() */
+ worker->flags |= WORKER_IDLE;
+ gcwq->nr_idle++;
+ worker->last_active = jiffies;
+
+ /* idle_list is LIFO */
+ list_add(&worker->entry, &gcwq->idle_list);
+
+ if (likely(!(worker->flags & WORKER_ROGUE))) {
+ if (too_many_workers(gcwq) && !timer_pending(&gcwq->idle_timer))
+ mod_timer(&gcwq->idle_timer,
+ jiffies + IDLE_WORKER_TIMEOUT);
+ } else
+ wake_up_all(&gcwq->trustee_wait);
+
+ /* sanity check nr_running */
+ WARN_ON_ONCE(gcwq->nr_workers == gcwq->nr_idle &&
+ atomic_read(get_gcwq_nr_running(gcwq->cpu)));
+}
+
+/**
+ * worker_leave_idle - leave idle state
+ * @worker: worker which is leaving idle state
+ *
+ * @worker is leaving idle state. Update stats.
+ *
+ * LOCKING:
+ * spin_lock_irq(gcwq->lock).
+ */
+static void worker_leave_idle(struct worker *worker)
+{
+ struct global_cwq *gcwq = worker->gcwq;
+
+ BUG_ON(!(worker->flags & WORKER_IDLE));
+ worker_clr_flags(worker, WORKER_IDLE);
+ gcwq->nr_idle--;
+ list_del_init(&worker->entry);
+}
+
+/**
+ * worker_maybe_bind_and_lock - bind worker to its cpu if possible and lock gcwq
+ * @worker: self
+ *
+ * Works which are scheduled while the cpu is online must at least be
+ * scheduled to a worker which is bound to the cpu so that if they are
+ * flushed from cpu callbacks while cpu is going down, they are
+ * guaranteed to execute on the cpu.
+ *
+ * This function is to be used by rogue workers and rescuers to bind
+ * themselves to the target cpu and may race with cpu going down or
+ * coming online. kthread_bind() can't be used because it may put the
+ * worker to already dead cpu and set_cpus_allowed_ptr() can't be used
+ * verbatim as it's best effort and blocking and gcwq may be
+ * [dis]associated in the meantime.
+ *
+ * This function tries set_cpus_allowed() and locks gcwq and verifies
+ * the binding against GCWQ_DISASSOCIATED which is set during
+ * CPU_DYING and cleared during CPU_ONLINE, so if the worker enters
+ * idle state or fetches works without dropping lock, it can guarantee
+ * the scheduling requirement described in the first paragraph.
+ *
+ * CONTEXT:
+ * Might sleep. Called without any lock but returns with gcwq->lock
+ * held.
+ *
+ * RETURNS:
+ * %true if the associated gcwq is online (@worker is successfully
+ * bound), %false if offline.
+ */
+static bool worker_maybe_bind_and_lock(struct worker *worker)
+{
+ struct global_cwq *gcwq = worker->gcwq;
+ struct task_struct *task = worker->task;
+
+ while (true) {
/*
- * It is permissible to free the struct work_struct
- * from inside the function that is called from it,
- * this we need to take into account for lockdep too.
- * To avoid bogus "held lock freed" warnings as well
- * as problems when looking into work->lockdep_map,
- * make a copy and use that here.
+ * The following call may fail, succeed or succeed
+ * without actually migrating the task to the cpu if
+ * it races with cpu hotunplug operation. Verify
+ * against GCWQ_DISASSOCIATED.
*/
- struct lockdep_map lockdep_map = work->lockdep_map;
-#endif
- trace_workqueue_execution(cwq->thread, work);
- debug_work_deactivate(work);
- cwq->current_work = work;
- list_del_init(cwq->worklist.next);
- spin_unlock_irq(&cwq->lock);
-
- BUG_ON(get_wq_data(work) != cwq);
- work_clear_pending(work);
- lock_map_acquire(&cwq->wq->lockdep_map);
- lock_map_acquire(&lockdep_map);
- f(work);
- lock_map_release(&lockdep_map);
- lock_map_release(&cwq->wq->lockdep_map);
-
- if (unlikely(in_atomic() || lockdep_depth(current) > 0)) {
- printk(KERN_ERR "BUG: workqueue leaked lock or atomic: "
- "%s/0x%08x/%d\n",
- current->comm, preempt_count(),
- task_pid_nr(current));
- printk(KERN_ERR " last function: ");
- print_symbol("%s\n", (unsigned long)f);
- debug_show_held_locks(current);
- dump_stack();
+ if (!(gcwq->flags & GCWQ_DISASSOCIATED))
+ set_cpus_allowed_ptr(task, get_cpu_mask(gcwq->cpu));
+
+ spin_lock_irq(&gcwq->lock);
+ if (gcwq->flags & GCWQ_DISASSOCIATED)
+ return false;
+ if (task_cpu(task) == gcwq->cpu &&
+ cpumask_equal(&current->cpus_allowed,
+ get_cpu_mask(gcwq->cpu)))
+ return true;
+ spin_unlock_irq(&gcwq->lock);
+
+ /* CPU has come up inbetween, retry migration */
+ cpu_relax();
+ }
+}
+
+/*
+ * Function for worker->rebind_work used to rebind rogue busy workers
+ * to the associated cpu which is coming back online. This is
+ * scheduled by cpu up but can race with other cpu hotplug operations
+ * and may be executed twice without intervening cpu down.
+ */
+static void worker_rebind_fn(struct work_struct *work)
+{
+ struct worker *worker = container_of(work, struct worker, rebind_work);
+ struct global_cwq *gcwq = worker->gcwq;
+
+ if (worker_maybe_bind_and_lock(worker))
+ worker_clr_flags(worker, WORKER_REBIND);
+
+ spin_unlock_irq(&gcwq->lock);
+}
+
+static struct worker *alloc_worker(void)
+{
+ struct worker *worker;
+
+ worker = kzalloc(sizeof(*worker), GFP_KERNEL);
+ if (worker) {
+ INIT_LIST_HEAD(&worker->entry);
+ INIT_LIST_HEAD(&worker->scheduled);
+ INIT_WORK(&worker->rebind_work, worker_rebind_fn);
+ /* on creation a worker is in !idle && prep state */
+ worker->flags = WORKER_PREP;
+ }
+ return worker;
+}
+
+/**
+ * create_worker - create a new workqueue worker
+ * @gcwq: gcwq the new worker will belong to
+ * @bind: whether to set affinity to @cpu or not
+ *
+ * Create a new worker which is bound to @gcwq. The returned worker
+ * can be started by calling start_worker() or destroyed using
+ * destroy_worker().
+ *
+ * CONTEXT:
+ * Might sleep. Does GFP_KERNEL allocations.
+ *
+ * RETURNS:
+ * Pointer to the newly created worker.
+ */
+static struct worker *create_worker(struct global_cwq *gcwq, bool bind)
+{
+ bool on_unbound_cpu = gcwq->cpu == WORK_CPU_UNBOUND;
+ struct worker *worker = NULL;
+ int id = -1;
+
+ spin_lock_irq(&gcwq->lock);
+ while (ida_get_new(&gcwq->worker_ida, &id)) {
+ spin_unlock_irq(&gcwq->lock);
+ if (!ida_pre_get(&gcwq->worker_ida, GFP_KERNEL))
+ goto fail;
+ spin_lock_irq(&gcwq->lock);
+ }
+ spin_unlock_irq(&gcwq->lock);
+
+ worker = alloc_worker();
+ if (!worker)
+ goto fail;
+
+ worker->gcwq = gcwq;
+ worker->id = id;
+
+ if (!on_unbound_cpu)
+ worker->task = kthread_create(worker_thread, worker,
+ "kworker/%u:%d", gcwq->cpu, id);
+ else
+ worker->task = kthread_create(worker_thread, worker,
+ "kworker/u:%d", id);
+ if (IS_ERR(worker->task))
+ goto fail;
+
+ /*
+ * A rogue worker will become a regular one if CPU comes
+ * online later on. Make sure every worker has
+ * PF_THREAD_BOUND set.
+ */
+ if (bind && !on_unbound_cpu)
+ kthread_bind(worker->task, gcwq->cpu);
+ else {
+ worker->task->flags |= PF_THREAD_BOUND;
+ if (on_unbound_cpu)
+ worker->flags |= WORKER_UNBOUND;
+ }
+
+ return worker;
+fail:
+ if (id >= 0) {
+ spin_lock_irq(&gcwq->lock);
+ ida_remove(&gcwq->worker_ida, id);
+ spin_unlock_irq(&gcwq->lock);
+ }
+ kfree(worker);
+ return NULL;
+}
+
+/**
+ * start_worker - start a newly created worker
+ * @worker: worker to start
+ *
+ * Make the gcwq aware of @worker and start it.
+ *
+ * CONTEXT:
+ * spin_lock_irq(gcwq->lock).
+ */
+static void start_worker(struct worker *worker)
+{
+ worker->flags |= WORKER_STARTED;
+ worker->gcwq->nr_workers++;
+ worker_enter_idle(worker);
+ wake_up_process(worker->task);
+}
+
+/**
+ * destroy_worker - destroy a workqueue worker
+ * @worker: worker to be destroyed
+ *
+ * Destroy @worker and adjust @gcwq stats accordingly.
+ *
+ * CONTEXT:
+ * spin_lock_irq(gcwq->lock) which is released and regrabbed.
+ */
+static void destroy_worker(struct worker *worker)
+{
+ struct global_cwq *gcwq = worker->gcwq;
+ int id = worker->id;
+
+ /* sanity check frenzy */
+ BUG_ON(worker->current_work);
+ BUG_ON(!list_empty(&worker->scheduled));
+
+ if (worker->flags & WORKER_STARTED)
+ gcwq->nr_workers--;
+ if (worker->flags & WORKER_IDLE)
+ gcwq->nr_idle--;
+
+ list_del_init(&worker->entry);
+ worker->flags |= WORKER_DIE;
+
+ spin_unlock_irq(&gcwq->lock);
+
+ kthread_stop(worker->task);
+ kfree(worker);
+
+ spin_lock_irq(&gcwq->lock);
+ ida_remove(&gcwq->worker_ida, id);
+}
+
+static void idle_worker_timeout(unsigned long __gcwq)
+{
+ struct global_cwq *gcwq = (void *)__gcwq;
+
+ spin_lock_irq(&gcwq->lock);
+
+ if (too_many_workers(gcwq)) {
+ struct worker *worker;
+ unsigned long expires;
+
+ /* idle_list is kept in LIFO order, check the last one */
+ worker = list_entry(gcwq->idle_list.prev, struct worker, entry);
+ expires = worker->last_active + IDLE_WORKER_TIMEOUT;
+
+ if (time_before(jiffies, expires))
+ mod_timer(&gcwq->idle_timer, expires);
+ else {
+ /* it's been idle for too long, wake up manager */
+ gcwq->flags |= GCWQ_MANAGE_WORKERS;
+ wake_up_worker(gcwq);
+ }
+ }
+
+ spin_unlock_irq(&gcwq->lock);
+}
+
+static bool send_mayday(struct work_struct *work)
+{
+ struct cpu_workqueue_struct *cwq = get_work_cwq(work);
+ struct workqueue_struct *wq = cwq->wq;
+ unsigned int cpu;
+
+ if (!(wq->flags & WQ_RESCUER))
+ return false;
+
+ /* mayday mayday mayday */
+ cpu = cwq->gcwq->cpu;
+ /* WORK_CPU_UNBOUND can't be set in cpumask, use cpu 0 instead */
+ if (cpu == WORK_CPU_UNBOUND)
+ cpu = 0;
+ if (!mayday_test_and_set_cpu(cpu, wq->mayday_mask))
+ wake_up_process(wq->rescuer->task);
+ return true;
+}
+
+static void gcwq_mayday_timeout(unsigned long __gcwq)
+{
+ struct global_cwq *gcwq = (void *)__gcwq;
+ struct work_struct *work;
+
+ spin_lock_irq(&gcwq->lock);
+
+ if (need_to_create_worker(gcwq)) {
+ /*
+ * We've been trying to create a new worker but
+ * haven't been successful. We might be hitting an
+ * allocation deadlock. Send distress signals to
+ * rescuers.
+ */
+ list_for_each_entry(work, &gcwq->worklist, entry)
+ send_mayday(work);
+ }
+
+ spin_unlock_irq(&gcwq->lock);
+
+ mod_timer(&gcwq->mayday_timer, jiffies + MAYDAY_INTERVAL);
+}
+
+/**
+ * maybe_create_worker - create a new worker if necessary
+ * @gcwq: gcwq to create a new worker for
+ *
+ * Create a new worker for @gcwq if necessary. @gcwq is guaranteed to
+ * have at least one idle worker on return from this function. If
+ * creating a new worker takes longer than MAYDAY_INTERVAL, mayday is
+ * sent to all rescuers with works scheduled on @gcwq to resolve
+ * possible allocation deadlock.
+ *
+ * On return, need_to_create_worker() is guaranteed to be false and
+ * may_start_working() true.
+ *
+ * LOCKING:
+ * spin_lock_irq(gcwq->lock) which may be released and regrabbed
+ * multiple times. Does GFP_KERNEL allocations. Called only from
+ * manager.
+ *
+ * RETURNS:
+ * false if no action was taken and gcwq->lock stayed locked, true
+ * otherwise.
+ */
+static bool maybe_create_worker(struct global_cwq *gcwq)
+{
+ if (!need_to_create_worker(gcwq))
+ return false;
+restart:
+ spin_unlock_irq(&gcwq->lock);
+
+ /* if we don't make progress in MAYDAY_INITIAL_TIMEOUT, call for help */
+ mod_timer(&gcwq->mayday_timer, jiffies + MAYDAY_INITIAL_TIMEOUT);
+
+ while (true) {
+ struct worker *worker;
+
+ worker = create_worker(gcwq, true);
+ if (worker) {
+ del_timer_sync(&gcwq->mayday_timer);
+ spin_lock_irq(&gcwq->lock);
+ start_worker(worker);
+ BUG_ON(need_to_create_worker(gcwq));
+ return true;
}
- spin_lock_irq(&cwq->lock);
- cwq->current_work = NULL;
+ if (!need_to_create_worker(gcwq))
+ break;
+
+ __set_current_state(TASK_INTERRUPTIBLE);
+ schedule_timeout(CREATE_COOLDOWN);
+
+ if (!need_to_create_worker(gcwq))
+ break;
}
- spin_unlock_irq(&cwq->lock);
+
+ del_timer_sync(&gcwq->mayday_timer);
+ spin_lock_irq(&gcwq->lock);
+ if (need_to_create_worker(gcwq))
+ goto restart;
+ return true;
}
-static int worker_thread(void *__cwq)
+/**
+ * maybe_destroy_worker - destroy workers which have been idle for a while
+ * @gcwq: gcwq to destroy workers for
+ *
+ * Destroy @gcwq workers which have been idle for longer than
+ * IDLE_WORKER_TIMEOUT.
+ *
+ * LOCKING:
+ * spin_lock_irq(gcwq->lock) which may be released and regrabbed
+ * multiple times. Called only from manager.
+ *
+ * RETURNS:
+ * false if no action was taken and gcwq->lock stayed locked, true
+ * otherwise.
+ */
+static bool maybe_destroy_workers(struct global_cwq *gcwq)
{
- struct cpu_workqueue_struct *cwq = __cwq;
- DEFINE_WAIT(wait);
+ bool ret = false;
- if (cwq->wq->freezeable)
- set_freezable();
+ while (too_many_workers(gcwq)) {
+ struct worker *worker;
+ unsigned long expires;
- for (;;) {
- prepare_to_wait(&cwq->more_work, &wait, TASK_INTERRUPTIBLE);
- if (!freezing(current) &&
- !kthread_should_stop() &&
- list_empty(&cwq->worklist))
- schedule();
- finish_wait(&cwq->more_work, &wait);
+ worker = list_entry(gcwq->idle_list.prev, struct worker, entry);
+ expires = worker->last_active + IDLE_WORKER_TIMEOUT;
- try_to_freeze();
+ if (time_before(jiffies, expires)) {
+ mod_timer(&gcwq->idle_timer, expires);
+ break;
+ }
- if (kthread_should_stop())
+ destroy_worker(worker);
+ ret = true;
+ }
+
+ return ret;
+}
+
+/**
+ * manage_workers - manage worker pool
+ * @worker: self
+ *
+ * Assume the manager role and manage gcwq worker pool @worker belongs
+ * to. At any given time, there can be only zero or one manager per
+ * gcwq. The exclusion is handled automatically by this function.
+ *
+ * The caller can safely start processing works on false return. On
+ * true return, it's guaranteed that need_to_create_worker() is false
+ * and may_start_working() is true.
+ *
+ * CONTEXT:
+ * spin_lock_irq(gcwq->lock) which may be released and regrabbed
+ * multiple times. Does GFP_KERNEL allocations.
+ *
+ * RETURNS:
+ * false if no action was taken and gcwq->lock stayed locked, true if
+ * some action was taken.
+ */
+static bool manage_workers(struct worker *worker)
+{
+ struct global_cwq *gcwq = worker->gcwq;
+ bool ret = false;
+
+ if (gcwq->flags & GCWQ_MANAGING_WORKERS)
+ return ret;
+
+ gcwq->flags &= ~GCWQ_MANAGE_WORKERS;
+ gcwq->flags |= GCWQ_MANAGING_WORKERS;
+
+ /*
+ * Destroy and then create so that may_start_working() is true
+ * on return.
+ */
+ ret |= maybe_destroy_workers(gcwq);
+ ret |= maybe_create_worker(gcwq);
+
+ gcwq->flags &= ~GCWQ_MANAGING_WORKERS;
+
+ /*
+ * The trustee might be waiting to take over the manager
+ * position, tell it we're done.
+ */
+ if (unlikely(gcwq->trustee))
+ wake_up_all(&gcwq->trustee_wait);
+
+ return ret;
+}
+
+/**
+ * move_linked_works - move linked works to a list
+ * @work: start of series of works to be scheduled
+ * @head: target list to append @work to
+ * @nextp: out paramter for nested worklist walking
+ *
+ * Schedule linked works starting from @work to @head. Work series to
+ * be scheduled starts at @work and includes any consecutive work with
+ * WORK_STRUCT_LINKED set in its predecessor.
+ *
+ * If @nextp is not NULL, it's updated to point to the next work of
+ * the last scheduled work. This allows move_linked_works() to be
+ * nested inside outer list_for_each_entry_safe().
+ *
+ * CONTEXT:
+ * spin_lock_irq(gcwq->lock).
+ */
+static void move_linked_works(struct work_struct *work, struct list_head *head,
+ struct work_struct **nextp)
+{
+ struct work_struct *n;
+
+ /*
+ * Linked worklist will always end before the end of the list,
+ * use NULL for list head.
+ */
+ list_for_each_entry_safe_from(work, n, NULL, entry) {
+ list_move_tail(&work->entry, head);
+ if (!(*work_data_bits(work) & WORK_STRUCT_LINKED))
break;
+ }
+
+ /*
+ * If we're already inside safe list traversal and have moved
+ * multiple works to the scheduled queue, the next position
+ * needs to be updated.
+ */
+ if (nextp)
+ *nextp = n;
+}
+
+static void cwq_activate_first_delayed(struct cpu_workqueue_struct *cwq)
+{
+ struct work_struct *work = list_first_entry(&cwq->delayed_works,
+ struct work_struct, entry);
+ struct list_head *pos = gcwq_determine_ins_pos(cwq->gcwq, cwq);
+
+ move_linked_works(work, pos, NULL);
+ cwq->nr_active++;
+}
- run_workqueue(cwq);
+/**
+ * cwq_dec_nr_in_flight - decrement cwq's nr_in_flight
+ * @cwq: cwq of interest
+ * @color: color of work which left the queue
+ *
+ * A work either has completed or is removed from pending queue,
+ * decrement nr_in_flight of its cwq and handle workqueue flushing.
+ *
+ * CONTEXT:
+ * spin_lock_irq(gcwq->lock).
+ */
+static void cwq_dec_nr_in_flight(struct cpu_workqueue_struct *cwq, int color)
+{
+ /* ignore uncolored works */
+ if (color == WORK_NO_COLOR)
+ return;
+
+ cwq->nr_in_flight[color]--;
+ cwq->nr_active--;
+
+ if (!list_empty(&cwq->delayed_works)) {
+ /* one down, submit a delayed one */
+ if (cwq->nr_active < cwq->max_active)
+ cwq_activate_first_delayed(cwq);
}
- return 0;
+ /* is flush in progress and are we at the flushing tip? */
+ if (likely(cwq->flush_color != color))
+ return;
+
+ /* are there still in-flight works? */
+ if (cwq->nr_in_flight[color])
+ return;
+
+ /* this cwq is done, clear flush_color */
+ cwq->flush_color = -1;
+
+ /*
+ * If this was the last cwq, wake up the first flusher. It
+ * will handle the rest.
+ */
+ if (atomic_dec_and_test(&cwq->wq->nr_cwqs_to_flush))
+ complete(&cwq->wq->first_flusher->done);
+}
+
+/**
+ * process_one_work - process single work
+ * @worker: self
+ * @work: work to process
+ *
+ * Process @work. This function contains all the logics necessary to
+ * process a single work including synchronization against and
+ * interaction with other workers on the same cpu, queueing and
+ * flushing. As long as context requirement is met, any worker can
+ * call this function to process a work.
+ *
+ * CONTEXT:
+ * spin_lock_irq(gcwq->lock) which is released and regrabbed.
+ */
+static void process_one_work(struct worker *worker, struct work_struct *work)
+{
+ struct cpu_workqueue_struct *cwq = get_work_cwq(work);
+ struct global_cwq *gcwq = cwq->gcwq;
+ struct hlist_head *bwh = busy_worker_head(gcwq, work);
+ bool cpu_intensive = cwq->wq->flags & WQ_CPU_INTENSIVE;
+ work_func_t f = work->func;
+ int work_color;
+ struct worker *collision;
+#ifdef CONFIG_LOCKDEP
+ /*
+ * It is permissible to free the struct work_struct from
+ * inside the function that is called from it, this we need to
+ * take into account for lockdep too. To avoid bogus "held
+ * lock freed" warnings as well as problems when looking into
+ * work->lockdep_map, make a copy and use that here.
+ */
+ struct lockdep_map lockdep_map = work->lockdep_map;
+#endif
+ /*
+ * A single work shouldn't be executed concurrently by
+ * multiple workers on a single cpu. Check whether anyone is
+ * already processing the work. If so, defer the work to the
+ * currently executing one.
+ */
+ collision = __find_worker_executing_work(gcwq, bwh, work);
+ if (unlikely(collision)) {
+ move_linked_works(work, &collision->scheduled, NULL);
+ return;
+ }
+
+ /* claim and process */
+ debug_work_deactivate(work);
+ hlist_add_head(&worker->hentry, bwh);
+ worker->current_work = work;
+ worker->current_cwq = cwq;
+ work_color = get_work_color(work);
+
+ /* record the current cpu number in the work data and dequeue */
+ set_work_cpu(work, gcwq->cpu);
+ list_del_init(&work->entry);
+
+ /*
+ * If HIGHPRI_PENDING, check the next work, and, if HIGHPRI,
+ * wake up another worker; otherwise, clear HIGHPRI_PENDING.
+ */
+ if (unlikely(gcwq->flags & GCWQ_HIGHPRI_PENDING)) {
+ struct work_struct *nwork = list_first_entry(&gcwq->worklist,
+ struct work_struct, entry);
+
+ if (!list_empty(&gcwq->worklist) &&
+ get_work_cwq(nwork)->wq->flags & WQ_HIGHPRI)
+ wake_up_worker(gcwq);
+ else
+ gcwq->flags &= ~GCWQ_HIGHPRI_PENDING;
+ }
+
+ /*
+ * CPU intensive works don't participate in concurrency
+ * management. They're the scheduler's responsibility.
+ */
+ if (unlikely(cpu_intensive))
+ worker_set_flags(worker, WORKER_CPU_INTENSIVE, true);
+
+ spin_unlock_irq(&gcwq->lock);
+
+ work_clear_pending(work);
+ lock_map_acquire(&cwq->wq->lockdep_map);
+ lock_map_acquire(&lockdep_map);
+ f(work);
+ lock_map_release(&lockdep_map);
+ lock_map_release(&cwq->wq->lockdep_map);
+
+ if (unlikely(in_atomic() || lockdep_depth(current) > 0)) {
+ printk(KERN_ERR "BUG: workqueue leaked lock or atomic: "
+ "%s/0x%08x/%d\n",
+ current->comm, preempt_count(), task_pid_nr(current));
+ printk(KERN_ERR " last function: ");
+ print_symbol("%s\n", (unsigned long)f);
+ debug_show_held_locks(current);
+ dump_stack();
+ }
+
+ spin_lock_irq(&gcwq->lock);
+
+ /* clear cpu intensive status */
+ if (unlikely(cpu_intensive))
+ worker_clr_flags(worker, WORKER_CPU_INTENSIVE);
+
+ /* we're done with it, release */
+ hlist_del_init(&worker->hentry);
+ worker->current_work = NULL;
+ worker->current_cwq = NULL;
+ cwq_dec_nr_in_flight(cwq, work_color);
+}
+
+/**
+ * process_scheduled_works - process scheduled works
+ * @worker: self
+ *
+ * Process all scheduled works. Please note that the scheduled list
+ * may change while processing a work, so this function repeatedly
+ * fetches a work from the top and executes it.
+ *
+ * CONTEXT:
+ * spin_lock_irq(gcwq->lock) which may be released and regrabbed
+ * multiple times.
+ */
+static void process_scheduled_works(struct worker *worker)
+{
+ while (!list_empty(&worker->scheduled)) {
+ struct work_struct *work = list_first_entry(&worker->scheduled,
+ struct work_struct, entry);
+ process_one_work(worker, work);
+ }
+}
+
+/**
+ * worker_thread - the worker thread function
+ * @__worker: self
+ *
+ * The gcwq worker thread function. There's a single dynamic pool of
+ * these per each cpu. These workers process all works regardless of
+ * their specific target workqueue. The only exception is works which
+ * belong to workqueues with a rescuer which will be explained in
+ * rescuer_thread().
+ */
+static int worker_thread(void *__worker)
+{
+ struct worker *worker = __worker;
+ struct global_cwq *gcwq = worker->gcwq;
+
+ /* tell the scheduler that this is a workqueue worker */
+ worker->task->flags |= PF_WQ_WORKER;
+woke_up:
+ spin_lock_irq(&gcwq->lock);
+
+ /* DIE can be set only while we're idle, checking here is enough */
+ if (worker->flags & WORKER_DIE) {
+ spin_unlock_irq(&gcwq->lock);
+ worker->task->flags &= ~PF_WQ_WORKER;
+ return 0;
+ }
+
+ worker_leave_idle(worker);
+recheck:
+ /* no more worker necessary? */
+ if (!need_more_worker(gcwq))
+ goto sleep;
+
+ /* do we need to manage? */
+ if (unlikely(!may_start_working(gcwq)) && manage_workers(worker))
+ goto recheck;
+
+ /*
+ * ->scheduled list can only be filled while a worker is
+ * preparing to process a work or actually processing it.
+ * Make sure nobody diddled with it while I was sleeping.
+ */
+ BUG_ON(!list_empty(&worker->scheduled));
+
+ /*
+ * When control reaches this point, we're guaranteed to have
+ * at least one idle worker or that someone else has already
+ * assumed the manager role.
+ */
+ worker_clr_flags(worker, WORKER_PREP);
+
+ do {
+ struct work_struct *work =
+ list_first_entry(&gcwq->worklist,
+ struct work_struct, entry);
+
+ if (likely(!(*work_data_bits(work) & WORK_STRUCT_LINKED))) {
+ /* optimization path, not strictly necessary */
+ process_one_work(worker, work);
+ if (unlikely(!list_empty(&worker->scheduled)))
+ process_scheduled_works(worker);
+ } else {
+ move_linked_works(work, &worker->scheduled, NULL);
+ process_scheduled_works(worker);
+ }
+ } while (keep_working(gcwq));
+
+ worker_set_flags(worker, WORKER_PREP, false);
+sleep:
+ if (unlikely(need_to_manage_workers(gcwq)) && manage_workers(worker))
+ goto recheck;
+
+ /*
+ * gcwq->lock is held and there's no work to process and no
+ * need to manage, sleep. Workers are woken up only while
+ * holding gcwq->lock or from local cpu, so setting the
+ * current state before releasing gcwq->lock is enough to
+ * prevent losing any event.
+ */
+ worker_enter_idle(worker);
+ __set_current_state(TASK_INTERRUPTIBLE);
+ spin_unlock_irq(&gcwq->lock);
+ schedule();
+ goto woke_up;
+}
+
+/**
+ * rescuer_thread - the rescuer thread function
+ * @__wq: the associated workqueue
+ *
+ * Workqueue rescuer thread function. There's one rescuer for each
+ * workqueue which has WQ_RESCUER set.
+ *
+ * Regular work processing on a gcwq may block trying to create a new
+ * worker which uses GFP_KERNEL allocation which has slight chance of
+ * developing into deadlock if some works currently on the same queue
+ * need to be processed to satisfy the GFP_KERNEL allocation. This is
+ * the problem rescuer solves.
+ *
+ * When such condition is possible, the gcwq summons rescuers of all
+ * workqueues which have works queued on the gcwq and let them process
+ * those works so that forward progress can be guaranteed.
+ *
+ * This should happen rarely.
+ */
+static int rescuer_thread(void *__wq)
+{
+ struct workqueue_struct *wq = __wq;
+ struct worker *rescuer = wq->rescuer;
+ struct list_head *scheduled = &rescuer->scheduled;
+ bool is_unbound = wq->flags & WQ_UNBOUND;
+ unsigned int cpu;
+
+ set_user_nice(current, RESCUER_NICE_LEVEL);
+repeat:
+ set_current_state(TASK_INTERRUPTIBLE);
+
+ if (kthread_should_stop())
+ return 0;
+
+ /*
+ * See whether any cpu is asking for help. Unbounded
+ * workqueues use cpu 0 in mayday_mask for CPU_UNBOUND.
+ */
+ for_each_mayday_cpu(cpu, wq->mayday_mask) {
+ unsigned int tcpu = is_unbound ? WORK_CPU_UNBOUND : cpu;
+ struct cpu_workqueue_struct *cwq = get_cwq(tcpu, wq);
+ struct global_cwq *gcwq = cwq->gcwq;
+ struct work_struct *work, *n;
+
+ __set_current_state(TASK_RUNNING);
+ mayday_clear_cpu(cpu, wq->mayday_mask);
+
+ /* migrate to the target cpu if possible */
+ rescuer->gcwq = gcwq;
+ worker_maybe_bind_and_lock(rescuer);
+
+ /*
+ * Slurp in all works issued via this workqueue and
+ * process'em.
+ */
+ BUG_ON(!list_empty(&rescuer->scheduled));
+ list_for_each_entry_safe(work, n, &gcwq->worklist, entry)
+ if (get_work_cwq(work) == cwq)
+ move_linked_works(work, scheduled, &n);
+
+ process_scheduled_works(rescuer);
+ spin_unlock_irq(&gcwq->lock);
+ }
+
+ schedule();
+ goto repeat;
}
struct wq_barrier {
@@ -469,44 +2003,137 @@ static void wq_barrier_func(struct work_struct *work)
complete(&barr->done);
}
+/**
+ * insert_wq_barrier - insert a barrier work
+ * @cwq: cwq to insert barrier into
+ * @barr: wq_barrier to insert
+ * @target: target work to attach @barr to
+ * @worker: worker currently executing @target, NULL if @target is not executing
+ *
+ * @barr is linked to @target such that @barr is completed only after
+ * @target finishes execution. Please note that the ordering
+ * guarantee is observed only with respect to @target and on the local
+ * cpu.
+ *
+ * Currently, a queued barrier can't be canceled. This is because
+ * try_to_grab_pending() can't determine whether the work to be
+ * grabbed is at the head of the queue and thus can't clear LINKED
+ * flag of the previous work while there must be a valid next work
+ * after a work with LINKED flag set.
+ *
+ * Note that when @worker is non-NULL, @target may be modified
+ * underneath us, so we can't reliably determine cwq from @target.
+ *
+ * CONTEXT:
+ * spin_lock_irq(gcwq->lock).
+ */
static void insert_wq_barrier(struct cpu_workqueue_struct *cwq,
- struct wq_barrier *barr, struct list_head *head)
+ struct wq_barrier *barr,
+ struct work_struct *target, struct worker *worker)
{
+ struct list_head *head;
+ unsigned int linked = 0;
+
/*
- * debugobject calls are safe here even with cwq->lock locked
+ * debugobject calls are safe here even with gcwq->lock locked
* as we know for sure that this will not trigger any of the
* checks and call back into the fixup functions where we
* might deadlock.
*/
INIT_WORK_ON_STACK(&barr->work, wq_barrier_func);
- __set_bit(WORK_STRUCT_PENDING, work_data_bits(&barr->work));
-
+ __set_bit(WORK_STRUCT_PENDING_BIT, work_data_bits(&barr->work));
init_completion(&barr->done);
+ /*
+ * If @target is currently being executed, schedule the
+ * barrier to the worker; otherwise, put it after @target.
+ */
+ if (worker)
+ head = worker->scheduled.next;
+ else {
+ unsigned long *bits = work_data_bits(target);
+
+ head = target->entry.next;
+ /* there can already be other linked works, inherit and set */
+ linked = *bits & WORK_STRUCT_LINKED;
+ __set_bit(WORK_STRUCT_LINKED_BIT, bits);
+ }
+
debug_work_activate(&barr->work);
- insert_work(cwq, &barr->work, head);
+ insert_work(cwq, &barr->work, head,
+ work_color_to_flags(WORK_NO_COLOR) | linked);
}
-static int flush_cpu_workqueue(struct cpu_workqueue_struct *cwq)
+/**
+ * flush_workqueue_prep_cwqs - prepare cwqs for workqueue flushing
+ * @wq: workqueue being flushed
+ * @flush_color: new flush color, < 0 for no-op
+ * @work_color: new work color, < 0 for no-op
+ *
+ * Prepare cwqs for workqueue flushing.
+ *
+ * If @flush_color is non-negative, flush_color on all cwqs should be
+ * -1. If no cwq has in-flight commands at the specified color, all
+ * cwq->flush_color's stay at -1 and %false is returned. If any cwq
+ * has in flight commands, its cwq->flush_color is set to
+ * @flush_color, @wq->nr_cwqs_to_flush is updated accordingly, cwq
+ * wakeup logic is armed and %true is returned.
+ *
+ * The caller should have initialized @wq->first_flusher prior to
+ * calling this function with non-negative @flush_color. If
+ * @flush_color is negative, no flush color update is done and %false
+ * is returned.
+ *
+ * If @work_color is non-negative, all cwqs should have the same
+ * work_color which is previous to @work_color and all will be
+ * advanced to @work_color.
+ *
+ * CONTEXT:
+ * mutex_lock(wq->flush_mutex).
+ *
+ * RETURNS:
+ * %true if @flush_color >= 0 and there's something to flush. %false
+ * otherwise.
+ */
+static bool flush_workqueue_prep_cwqs(struct workqueue_struct *wq,
+ int flush_color, int work_color)
{
- int active = 0;
- struct wq_barrier barr;
+ bool wait = false;
+ unsigned int cpu;
- WARN_ON(cwq->thread == current);
-
- spin_lock_irq(&cwq->lock);
- if (!list_empty(&cwq->worklist) || cwq->current_work != NULL) {
- insert_wq_barrier(cwq, &barr, &cwq->worklist);
- active = 1;
+ if (flush_color >= 0) {
+ BUG_ON(atomic_read(&wq->nr_cwqs_to_flush));
+ atomic_set(&wq->nr_cwqs_to_flush, 1);
}
- spin_unlock_irq(&cwq->lock);
- if (active) {
- wait_for_completion(&barr.done);
- destroy_work_on_stack(&barr.work);
+ for_each_cwq_cpu(cpu, wq) {
+ struct cpu_workqueue_struct *cwq = get_cwq(cpu, wq);
+ struct global_cwq *gcwq = cwq->gcwq;
+
+ spin_lock_irq(&gcwq->lock);
+
+ if (flush_color >= 0) {
+ BUG_ON(cwq->flush_color != -1);
+
+ if (cwq->nr_in_flight[flush_color]) {
+ cwq->flush_color = flush_color;
+ atomic_inc(&wq->nr_cwqs_to_flush);
+ wait = true;
+ }
+ }
+
+ if (work_color >= 0) {
+ BUG_ON(work_color != work_next_color(cwq->work_color));
+ cwq->work_color = work_color;
+ }
+
+ spin_unlock_irq(&gcwq->lock);
}
- return active;
+ if (flush_color >= 0 && atomic_dec_and_test(&wq->nr_cwqs_to_flush))
+ complete(&wq->first_flusher->done);
+
+ return wait;
}
/**
@@ -518,20 +2145,150 @@ static int flush_cpu_workqueue(struct cpu_workqueue_struct *cwq)
*
* We sleep until all works which were queued on entry have been handled,
* but we are not livelocked by new incoming ones.
- *
- * This function used to run the workqueues itself. Now we just wait for the
- * helper threads to do it.
*/
void flush_workqueue(struct workqueue_struct *wq)
{
- const struct cpumask *cpu_map = wq_cpu_map(wq);
- int cpu;
+ struct wq_flusher this_flusher = {
+ .list = LIST_HEAD_INIT(this_flusher.list),
+ .flush_color = -1,
+ .done = COMPLETION_INITIALIZER_ONSTACK(this_flusher.done),
+ };
+ int next_color;
- might_sleep();
lock_map_acquire(&wq->lockdep_map);
lock_map_release(&wq->lockdep_map);
- for_each_cpu(cpu, cpu_map)
- flush_cpu_workqueue(per_cpu_ptr(wq->cpu_wq, cpu));
+
+ mutex_lock(&wq->flush_mutex);
+
+ /*
+ * Start-to-wait phase
+ */
+ next_color = work_next_color(wq->work_color);
+
+ if (next_color != wq->flush_color) {
+ /*
+ * Color space is not full. The current work_color
+ * becomes our flush_color and work_color is advanced
+ * by one.
+ */
+ BUG_ON(!list_empty(&wq->flusher_overflow));
+ this_flusher.flush_color = wq->work_color;
+ wq->work_color = next_color;
+
+ if (!wq->first_flusher) {
+ /* no flush in progress, become the first flusher */
+ BUG_ON(wq->flush_color != this_flusher.flush_color);
+
+ wq->first_flusher = &this_flusher;
+
+ if (!flush_workqueue_prep_cwqs(wq, wq->flush_color,
+ wq->work_color)) {
+ /* nothing to flush, done */
+ wq->flush_color = next_color;
+ wq->first_flusher = NULL;
+ goto out_unlock;
+ }
+ } else {
+ /* wait in queue */
+ BUG_ON(wq->flush_color == this_flusher.flush_color);
+ list_add_tail(&this_flusher.list, &wq->flusher_queue);
+ flush_workqueue_prep_cwqs(wq, -1, wq->work_color);
+ }
+ } else {
+ /*
+ * Oops, color space is full, wait on overflow queue.
+ * The next flush completion will assign us
+ * flush_color and transfer to flusher_queue.
+ */
+ list_add_tail(&this_flusher.list, &wq->flusher_overflow);
+ }
+
+ mutex_unlock(&wq->flush_mutex);
+
+ wait_for_completion(&this_flusher.done);
+
+ /*
+ * Wake-up-and-cascade phase
+ *
+ * First flushers are responsible for cascading flushes and
+ * handling overflow. Non-first flushers can simply return.
+ */
+ if (wq->first_flusher != &this_flusher)
+ return;
+
+ mutex_lock(&wq->flush_mutex);
+
+ /* we might have raced, check again with mutex held */
+ if (wq->first_flusher != &this_flusher)
+ goto out_unlock;
+
+ wq->first_flusher = NULL;
+
+ BUG_ON(!list_empty(&this_flusher.list));
+ BUG_ON(wq->flush_color != this_flusher.flush_color);
+
+ while (true) {
+ struct wq_flusher *next, *tmp;
+
+ /* complete all the flushers sharing the current flush color */
+ list_for_each_entry_safe(next, tmp, &wq->flusher_queue, list) {
+ if (next->flush_color != wq->flush_color)
+ break;
+ list_del_init(&next->list);
+ complete(&next->done);
+ }
+
+ BUG_ON(!list_empty(&wq->flusher_overflow) &&
+ wq->flush_color != work_next_color(wq->work_color));
+
+ /* this flush_color is finished, advance by one */
+ wq->flush_color = work_next_color(wq->flush_color);
+
+ /* one color has been freed, handle overflow queue */
+ if (!list_empty(&wq->flusher_overflow)) {
+ /*
+ * Assign the same color to all overflowed
+ * flushers, advance work_color and append to
+ * flusher_queue. This is the start-to-wait
+ * phase for these overflowed flushers.
+ */
+ list_for_each_entry(tmp, &wq->flusher_overflow, list)
+ tmp->flush_color = wq->work_color;
+
+ wq->work_color = work_next_color(wq->work_color);
+
+ list_splice_tail_init(&wq->flusher_overflow,
+ &wq->flusher_queue);
+ flush_workqueue_prep_cwqs(wq, -1, wq->work_color);
+ }
+
+ if (list_empty(&wq->flusher_queue)) {
+ BUG_ON(wq->flush_color != wq->work_color);
+ break;
+ }
+
+ /*
+ * Need to flush more colors. Make the next flusher
+ * the new first flusher and arm cwqs.
+ */
+ BUG_ON(wq->flush_color == wq->work_color);
+ BUG_ON(wq->flush_color != next->flush_color);
+
+ list_del_init(&next->list);
+ wq->first_flusher = next;
+
+ if (flush_workqueue_prep_cwqs(wq, wq->flush_color, -1))
+ break;
+
+ /*
+ * Meh... this color is already done, clear first
+ * flusher and repeat cascading.
+ */
+ wq->first_flusher = NULL;
+ }
+
+out_unlock:
+ mutex_unlock(&wq->flush_mutex);
}
EXPORT_SYMBOL_GPL(flush_workqueue);
@@ -547,43 +2304,46 @@ EXPORT_SYMBOL_GPL(flush_workqueue);
*/
int flush_work(struct work_struct *work)
{
+ struct worker *worker = NULL;
+ struct global_cwq *gcwq;
struct cpu_workqueue_struct *cwq;
- struct list_head *prev;
struct wq_barrier barr;
might_sleep();
- cwq = get_wq_data(work);
- if (!cwq)
+ gcwq = get_work_gcwq(work);
+ if (!gcwq)
return 0;
- lock_map_acquire(&cwq->wq->lockdep_map);
- lock_map_release(&cwq->wq->lockdep_map);
-
- prev = NULL;
- spin_lock_irq(&cwq->lock);
+ spin_lock_irq(&gcwq->lock);
if (!list_empty(&work->entry)) {
/*
* See the comment near try_to_grab_pending()->smp_rmb().
- * If it was re-queued under us we are not going to wait.
+ * If it was re-queued to a different gcwq under us, we
+ * are not going to wait.
*/
smp_rmb();
- if (unlikely(cwq != get_wq_data(work)))
- goto out;
- prev = &work->entry;
+ cwq = get_work_cwq(work);
+ if (unlikely(!cwq || gcwq != cwq->gcwq))
+ goto already_gone;
} else {
- if (cwq->current_work != work)
- goto out;
- prev = &cwq->worklist;
+ worker = find_worker_executing_work(gcwq, work);
+ if (!worker)
+ goto already_gone;
+ cwq = worker->current_cwq;
}
- insert_wq_barrier(cwq, &barr, prev->next);
-out:
- spin_unlock_irq(&cwq->lock);
- if (!prev)
- return 0;
+
+ insert_wq_barrier(cwq, &barr, work, worker);
+ spin_unlock_irq(&gcwq->lock);
+
+ lock_map_acquire(&cwq->wq->lockdep_map);
+ lock_map_release(&cwq->wq->lockdep_map);
wait_for_completion(&barr.done);
destroy_work_on_stack(&barr.work);
return 1;
+already_gone:
+ spin_unlock_irq(&gcwq->lock);
+ return 0;
}
EXPORT_SYMBOL_GPL(flush_work);
@@ -593,54 +2353,55 @@ EXPORT_SYMBOL_GPL(flush_work);
*/
static int try_to_grab_pending(struct work_struct *work)
{
- struct cpu_workqueue_struct *cwq;
+ struct global_cwq *gcwq;
int ret = -1;
- if (!test_and_set_bit(WORK_STRUCT_PENDING, work_data_bits(work)))
+ if (!test_and_set_bit(WORK_STRUCT_PENDING_BIT, work_data_bits(work)))
return 0;
/*
* The queueing is in progress, or it is already queued. Try to
* steal it from ->worklist without clearing WORK_STRUCT_PENDING.
*/
-
- cwq = get_wq_data(work);
- if (!cwq)
+ gcwq = get_work_gcwq(work);
+ if (!gcwq)
return ret;
- spin_lock_irq(&cwq->lock);
+ spin_lock_irq(&gcwq->lock);
if (!list_empty(&work->entry)) {
/*
- * This work is queued, but perhaps we locked the wrong cwq.
+ * This work is queued, but perhaps we locked the wrong gcwq.
* In that case we must see the new value after rmb(), see
* insert_work()->wmb().
*/
smp_rmb();
- if (cwq == get_wq_data(work)) {
+ if (gcwq == get_work_gcwq(work)) {
debug_work_deactivate(work);
list_del_init(&work->entry);
+ cwq_dec_nr_in_flight(get_work_cwq(work),
+ get_work_color(work));
ret = 1;
}
}
- spin_unlock_irq(&cwq->lock);
+ spin_unlock_irq(&gcwq->lock);
return ret;
}
-static void wait_on_cpu_work(struct cpu_workqueue_struct *cwq,
- struct work_struct *work)
+static void wait_on_cpu_work(struct global_cwq *gcwq, struct work_struct *work)
{
struct wq_barrier barr;
- int running = 0;
+ struct worker *worker;
- spin_lock_irq(&cwq->lock);
- if (unlikely(cwq->current_work == work)) {
- insert_wq_barrier(cwq, &barr, cwq->worklist.next);
- running = 1;
- }
- spin_unlock_irq(&cwq->lock);
+ spin_lock_irq(&gcwq->lock);
+
+ worker = find_worker_executing_work(gcwq, work);
+ if (unlikely(worker))
+ insert_wq_barrier(worker->current_cwq, &barr, work, worker);
- if (unlikely(running)) {
+ spin_unlock_irq(&gcwq->lock);
+
+ if (unlikely(worker)) {
wait_for_completion(&barr.done);
destroy_work_on_stack(&barr.work);
}
@@ -648,9 +2409,6 @@ static void wait_on_cpu_work(struct cpu_workqueue_struct *cwq,
static void wait_on_work(struct work_struct *work)
{
- struct cpu_workqueue_struct *cwq;
- struct workqueue_struct *wq;
- const struct cpumask *cpu_map;
int cpu;
might_sleep();
@@ -658,15 +2416,8 @@ static void wait_on_work(struct work_struct *work)
lock_map_acquire(&work->lockdep_map);
lock_map_release(&work->lockdep_map);
- cwq = get_wq_data(work);
- if (!cwq)
- return;
-
- wq = cwq->wq;
- cpu_map = wq_cpu_map(wq);
-
- for_each_cpu(cpu, cpu_map)
- wait_on_cpu_work(per_cpu_ptr(wq->cpu_wq, cpu), work);
+ for_each_gcwq_cpu(cpu)
+ wait_on_cpu_work(get_gcwq(cpu), work);
}
static int __cancel_work_timer(struct work_struct *work,
@@ -681,7 +2432,7 @@ static int __cancel_work_timer(struct work_struct *work,
wait_on_work(work);
} while (unlikely(ret < 0));
- clear_wq_data(work);
+ clear_work_data(work);
return ret;
}
@@ -727,8 +2478,6 @@ int cancel_delayed_work_sync(struct delayed_work *dwork)
}
EXPORT_SYMBOL(cancel_delayed_work_sync);
-static struct workqueue_struct *keventd_wq __read_mostly;
-
/**
* schedule_work - put work task in global workqueue
* @work: job to be done
@@ -742,7 +2491,7 @@ static struct workqueue_struct *keventd_wq __read_mostly;
*/
int schedule_work(struct work_struct *work)
{
- return queue_work(keventd_wq, work);
+ return queue_work(system_wq, work);
}
EXPORT_SYMBOL(schedule_work);
@@ -755,7 +2504,7 @@ EXPORT_SYMBOL(schedule_work);
*/
int schedule_work_on(int cpu, struct work_struct *work)
{
- return queue_work_on(cpu, keventd_wq, work);
+ return queue_work_on(cpu, system_wq, work);
}
EXPORT_SYMBOL(schedule_work_on);
@@ -770,7 +2519,7 @@ EXPORT_SYMBOL(schedule_work_on);
int schedule_delayed_work(struct delayed_work *dwork,
unsigned long delay)
{
- return queue_delayed_work(keventd_wq, dwork, delay);
+ return queue_delayed_work(system_wq, dwork, delay);
}
EXPORT_SYMBOL(schedule_delayed_work);
@@ -783,9 +2532,8 @@ EXPORT_SYMBOL(schedule_delayed_work);
void flush_delayed_work(struct delayed_work *dwork)
{
if (del_timer_sync(&dwork->timer)) {
- struct cpu_workqueue_struct *cwq;
- cwq = wq_per_cpu(get_wq_data(&dwork->work)->wq, get_cpu());
- __queue_work(cwq, &dwork->work);
+ __queue_work(get_cpu(), get_work_cwq(&dwork->work)->wq,
+ &dwork->work);
put_cpu();
}
flush_work(&dwork->work);
@@ -804,7 +2552,7 @@ EXPORT_SYMBOL(flush_delayed_work);
int schedule_delayed_work_on(int cpu,
struct delayed_work *dwork, unsigned long delay)
{
- return queue_delayed_work_on(cpu, keventd_wq, dwork, delay);
+ return queue_delayed_work_on(cpu, system_wq, dwork, delay);
}
EXPORT_SYMBOL(schedule_delayed_work_on);
@@ -820,7 +2568,6 @@ EXPORT_SYMBOL(schedule_delayed_work_on);
int schedule_on_each_cpu(work_func_t func)
{
int cpu;
- int orig = -1;
struct work_struct *works;
works = alloc_percpu(struct work_struct);
@@ -829,23 +2576,12 @@ int schedule_on_each_cpu(work_func_t func)
get_online_cpus();
- /*
- * When running in keventd don't schedule a work item on
- * itself. Can just call directly because the work queue is
- * already bound. This also is faster.
- */
- if (current_is_keventd())
- orig = raw_smp_processor_id();
-
for_each_online_cpu(cpu) {
struct work_struct *work = per_cpu_ptr(works, cpu);
INIT_WORK(work, func);
- if (cpu != orig)
- schedule_work_on(cpu, work);
+ schedule_work_on(cpu, work);
}
- if (orig >= 0)
- func(per_cpu_ptr(works, orig));
for_each_online_cpu(cpu)
flush_work(per_cpu_ptr(works, cpu));
@@ -881,7 +2617,7 @@ int schedule_on_each_cpu(work_func_t func)
*/
void flush_scheduled_work(void)
{
- flush_workqueue(keventd_wq);
+ flush_workqueue(system_wq);
}
EXPORT_SYMBOL(flush_scheduled_work);
@@ -913,170 +2649,170 @@ EXPORT_SYMBOL_GPL(execute_in_process_context);
int keventd_up(void)
{
- return keventd_wq != NULL;
+ return system_wq != NULL;
}
-int current_is_keventd(void)
+static int alloc_cwqs(struct workqueue_struct *wq)
{
- struct cpu_workqueue_struct *cwq;
- int cpu = raw_smp_processor_id(); /* preempt-safe: keventd is per-cpu */
- int ret = 0;
-
- BUG_ON(!keventd_wq);
+ /*
+ * cwqs are forced aligned according to WORK_STRUCT_FLAG_BITS.
+ * Make sure that the alignment isn't lower than that of
+ * unsigned long long.
+ */
+ const size_t size = sizeof(struct cpu_workqueue_struct);
+ const size_t align = max_t(size_t, 1 << WORK_STRUCT_FLAG_BITS,
+ __alignof__(unsigned long long));
+#ifdef CONFIG_SMP
+ bool percpu = !(wq->flags & WQ_UNBOUND);
+#else
+ bool percpu = false;
+#endif
- cwq = per_cpu_ptr(keventd_wq->cpu_wq, cpu);
- if (current == cwq->thread)
- ret = 1;
+ if (percpu)
+ wq->cpu_wq.pcpu = __alloc_percpu(size, align);
+ else {
+ void *ptr;
- return ret;
+ /*
+ * Allocate enough room to align cwq and put an extra
+ * pointer at the end pointing back to the originally
+ * allocated pointer which will be used for free.
+ */
+ ptr = kzalloc(size + align + sizeof(void *), GFP_KERNEL);
+ if (ptr) {
+ wq->cpu_wq.single = PTR_ALIGN(ptr, align);
+ *(void **)(wq->cpu_wq.single + 1) = ptr;
+ }
+ }
+ /* just in case, make sure it's actually aligned */
+ BUG_ON(!IS_ALIGNED(wq->cpu_wq.v, align));
+ return wq->cpu_wq.v ? 0 : -ENOMEM;
}
-static struct cpu_workqueue_struct *
-init_cpu_workqueue(struct workqueue_struct *wq, int cpu)
+static void free_cwqs(struct workqueue_struct *wq)
{
- struct cpu_workqueue_struct *cwq = per_cpu_ptr(wq->cpu_wq, cpu);
-
- cwq->wq = wq;
- spin_lock_init(&cwq->lock);
- INIT_LIST_HEAD(&cwq->worklist);
- init_waitqueue_head(&cwq->more_work);
+#ifdef CONFIG_SMP
+ bool percpu = !(wq->flags & WQ_UNBOUND);
+#else
+ bool percpu = false;
+#endif
- return cwq;
+ if (percpu)
+ free_percpu(wq->cpu_wq.pcpu);
+ else if (wq->cpu_wq.single) {
+ /* the pointer to free is stored right after the cwq */
+ kfree(*(void **)(wq->cpu_wq.single + 1));
+ }
}
-static int create_workqueue_thread(struct cpu_workqueue_struct *cwq, int cpu)
+static int wq_clamp_max_active(int max_active, unsigned int flags,
+ const char *name)
{
- struct sched_param param = { .sched_priority = MAX_RT_PRIO-1 };
- struct workqueue_struct *wq = cwq->wq;
- const char *fmt = is_wq_single_threaded(wq) ? "%s" : "%s/%d";
- struct task_struct *p;
+ int lim = flags & WQ_UNBOUND ? WQ_UNBOUND_MAX_ACTIVE : WQ_MAX_ACTIVE;
- p = kthread_create(worker_thread, cwq, fmt, wq->name, cpu);
- /*
- * Nobody can add the work_struct to this cwq,
- * if (caller is __create_workqueue)
- * nobody should see this wq
- * else // caller is CPU_UP_PREPARE
- * cpu is not on cpu_online_map
- * so we can abort safely.
- */
- if (IS_ERR(p))
- return PTR_ERR(p);
- if (cwq->wq->rt)
- sched_setscheduler_nocheck(p, SCHED_FIFO, &param);
- cwq->thread = p;
+ if (max_active < 1 || max_active > lim)
+ printk(KERN_WARNING "workqueue: max_active %d requested for %s "
+ "is out of range, clamping between %d and %d\n",
+ max_active, name, 1, lim);
- trace_workqueue_creation(cwq->thread, cpu);
-
- return 0;
+ return clamp_val(max_active, 1, lim);
}
-static void start_workqueue_thread(struct cpu_workqueue_struct *cwq, int cpu)
+struct workqueue_struct *__alloc_workqueue_key(const char *name,
+ unsigned int flags,
+ int max_active,
+ struct lock_class_key *key,
+ const char *lock_name)
{
- struct task_struct *p = cwq->thread;
+ struct workqueue_struct *wq;
+ unsigned int cpu;
- if (p != NULL) {
- if (cpu >= 0)
- kthread_bind(p, cpu);
- wake_up_process(p);
- }
-}
+ /*
+ * Unbound workqueues aren't concurrency managed and should be
+ * dispatched to workers immediately.
+ */
+ if (flags & WQ_UNBOUND)
+ flags |= WQ_HIGHPRI;
-struct workqueue_struct *__create_workqueue_key(const char *name,
- int singlethread,
- int freezeable,
- int rt,
- struct lock_class_key *key,
- const char *lock_name)
-{
- struct workqueue_struct *wq;
- struct cpu_workqueue_struct *cwq;
- int err = 0, cpu;
+ max_active = max_active ?: WQ_DFL_ACTIVE;
+ max_active = wq_clamp_max_active(max_active, flags, name);
wq = kzalloc(sizeof(*wq), GFP_KERNEL);
if (!wq)
- return NULL;
+ goto err;
- wq->cpu_wq = alloc_percpu(struct cpu_workqueue_struct);
- if (!wq->cpu_wq) {
- kfree(wq);
- return NULL;
- }
+ wq->flags = flags;
+ wq->saved_max_active = max_active;
+ mutex_init(&wq->flush_mutex);
+ atomic_set(&wq->nr_cwqs_to_flush, 0);
+ INIT_LIST_HEAD(&wq->flusher_queue);
+ INIT_LIST_HEAD(&wq->flusher_overflow);
wq->name = name;
lockdep_init_map(&wq->lockdep_map, lock_name, key, 0);
- wq->singlethread = singlethread;
- wq->freezeable = freezeable;
- wq->rt = rt;
INIT_LIST_HEAD(&wq->list);
- if (singlethread) {
- cwq = init_cpu_workqueue(wq, singlethread_cpu);
- err = create_workqueue_thread(cwq, singlethread_cpu);
- start_workqueue_thread(cwq, -1);
- } else {
- cpu_maps_update_begin();
- /*
- * We must place this wq on list even if the code below fails.
- * cpu_down(cpu) can remove cpu from cpu_populated_map before
- * destroy_workqueue() takes the lock, in that case we leak
- * cwq[cpu]->thread.
- */
- spin_lock(&workqueue_lock);
- list_add(&wq->list, &workqueues);
- spin_unlock(&workqueue_lock);
- /*
- * We must initialize cwqs for each possible cpu even if we
- * are going to call destroy_workqueue() finally. Otherwise
- * cpu_up() can hit the uninitialized cwq once we drop the
- * lock.
- */
- for_each_possible_cpu(cpu) {
- cwq = init_cpu_workqueue(wq, cpu);
- if (err || !cpu_online(cpu))
- continue;
- err = create_workqueue_thread(cwq, cpu);
- start_workqueue_thread(cwq, cpu);
- }
- cpu_maps_update_done();
+ if (alloc_cwqs(wq) < 0)
+ goto err;
+
+ for_each_cwq_cpu(cpu, wq) {
+ struct cpu_workqueue_struct *cwq = get_cwq(cpu, wq);
+ struct global_cwq *gcwq = get_gcwq(cpu);
+
+ BUG_ON((unsigned long)cwq & WORK_STRUCT_FLAG_MASK);
+ cwq->gcwq = gcwq;
+ cwq->wq = wq;
+ cwq->flush_color = -1;
+ cwq->max_active = max_active;
+ INIT_LIST_HEAD(&cwq->delayed_works);
}
- if (err) {
- destroy_workqueue(wq);
- wq = NULL;
+ if (flags & WQ_RESCUER) {
+ struct worker *rescuer;
+
+ if (!alloc_mayday_mask(&wq->mayday_mask, GFP_KERNEL))
+ goto err;
+
+ wq->rescuer = rescuer = alloc_worker();
+ if (!rescuer)
+ goto err;
+
+ rescuer->task = kthread_create(rescuer_thread, wq, "%s", name);
+ if (IS_ERR(rescuer->task))
+ goto err;
+
+ wq->rescuer = rescuer;
+ rescuer->task->flags |= PF_THREAD_BOUND;
+ wake_up_process(rescuer->task);
}
- return wq;
-}
-EXPORT_SYMBOL_GPL(__create_workqueue_key);
-static void cleanup_workqueue_thread(struct cpu_workqueue_struct *cwq)
-{
/*
- * Our caller is either destroy_workqueue() or CPU_POST_DEAD,
- * cpu_add_remove_lock protects cwq->thread.
+ * workqueue_lock protects global freeze state and workqueues
+ * list. Grab it, set max_active accordingly and add the new
+ * workqueue to workqueues list.
*/
- if (cwq->thread == NULL)
- return;
+ spin_lock(&workqueue_lock);
- lock_map_acquire(&cwq->wq->lockdep_map);
- lock_map_release(&cwq->wq->lockdep_map);
+ if (workqueue_freezing && wq->flags & WQ_FREEZEABLE)
+ for_each_cwq_cpu(cpu, wq)
+ get_cwq(cpu, wq)->max_active = 0;
- flush_cpu_workqueue(cwq);
- /*
- * If the caller is CPU_POST_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.
- */
- trace_workqueue_destruction(cwq->thread);
- kthread_stop(cwq->thread);
- cwq->thread = NULL;
+ list_add(&wq->list, &workqueues);
+
+ spin_unlock(&workqueue_lock);
+
+ return wq;
+err:
+ if (wq) {
+ free_cwqs(wq);
+ free_mayday_mask(wq->mayday_mask);
+ kfree(wq->rescuer);
+ kfree(wq);
+ }
+ return NULL;
}
+EXPORT_SYMBOL_GPL(__alloc_workqueue_key);
/**
* destroy_workqueue - safely terminate a workqueue
@@ -1086,72 +2822,516 @@ static void cleanup_workqueue_thread(struct cpu_workqueue_struct *cwq)
*/
void destroy_workqueue(struct workqueue_struct *wq)
{
- const struct cpumask *cpu_map = wq_cpu_map(wq);
- int cpu;
+ unsigned int cpu;
- cpu_maps_update_begin();
+ flush_workqueue(wq);
+
+ /*
+ * wq list is used to freeze wq, remove from list after
+ * flushing is complete in case freeze races us.
+ */
spin_lock(&workqueue_lock);
list_del(&wq->list);
spin_unlock(&workqueue_lock);
- for_each_cpu(cpu, cpu_map)
- cleanup_workqueue_thread(per_cpu_ptr(wq->cpu_wq, cpu));
- cpu_maps_update_done();
+ /* sanity check */
+ for_each_cwq_cpu(cpu, wq) {
+ struct cpu_workqueue_struct *cwq = get_cwq(cpu, wq);
+ int i;
+
+ for (i = 0; i < WORK_NR_COLORS; i++)
+ BUG_ON(cwq->nr_in_flight[i]);
+ BUG_ON(cwq->nr_active);
+ BUG_ON(!list_empty(&cwq->delayed_works));
+ }
+
+ if (wq->flags & WQ_RESCUER) {
+ kthread_stop(wq->rescuer->task);
+ free_mayday_mask(wq->mayday_mask);
+ }
- free_percpu(wq->cpu_wq);
+ free_cwqs(wq);
kfree(wq);
}
EXPORT_SYMBOL_GPL(destroy_workqueue);
+/**
+ * workqueue_set_max_active - adjust max_active of a workqueue
+ * @wq: target workqueue
+ * @max_active: new max_active value.
+ *
+ * Set max_active of @wq to @max_active.
+ *
+ * CONTEXT:
+ * Don't call from IRQ context.
+ */
+void workqueue_set_max_active(struct workqueue_struct *wq, int max_active)
+{
+ unsigned int cpu;
+
+ max_active = wq_clamp_max_active(max_active, wq->flags, wq->name);
+
+ spin_lock(&workqueue_lock);
+
+ wq->saved_max_active = max_active;
+
+ for_each_cwq_cpu(cpu, wq) {
+ struct global_cwq *gcwq = get_gcwq(cpu);
+
+ spin_lock_irq(&gcwq->lock);
+
+ if (!(wq->flags & WQ_FREEZEABLE) ||
+ !(gcwq->flags & GCWQ_FREEZING))
+ get_cwq(gcwq->cpu, wq)->max_active = max_active;
+
+ spin_unlock_irq(&gcwq->lock);
+ }
+
+ spin_unlock(&workqueue_lock);
+}
+EXPORT_SYMBOL_GPL(workqueue_set_max_active);
+
+/**
+ * workqueue_congested - test whether a workqueue is congested
+ * @cpu: CPU in question
+ * @wq: target workqueue
+ *
+ * Test whether @wq's cpu workqueue for @cpu is congested. There is
+ * no synchronization around this function and the test result is
+ * unreliable and only useful as advisory hints or for debugging.
+ *
+ * RETURNS:
+ * %true if congested, %false otherwise.
+ */
+bool workqueue_congested(unsigned int cpu, struct workqueue_struct *wq)
+{
+ struct cpu_workqueue_struct *cwq = get_cwq(cpu, wq);
+
+ return !list_empty(&cwq->delayed_works);
+}
+EXPORT_SYMBOL_GPL(workqueue_congested);
+
+/**
+ * work_cpu - return the last known associated cpu for @work
+ * @work: the work of interest
+ *
+ * RETURNS:
+ * CPU number if @work was ever queued. WORK_CPU_NONE otherwise.
+ */
+unsigned int work_cpu(struct work_struct *work)
+{
+ struct global_cwq *gcwq = get_work_gcwq(work);
+
+ return gcwq ? gcwq->cpu : WORK_CPU_NONE;
+}
+EXPORT_SYMBOL_GPL(work_cpu);
+
+/**
+ * work_busy - test whether a work is currently pending or running
+ * @work: the work to be tested
+ *
+ * Test whether @work is currently pending or running. There is no
+ * synchronization around this function and the test result is
+ * unreliable and only useful as advisory hints or for debugging.
+ * Especially for reentrant wqs, the pending state might hide the
+ * running state.
+ *
+ * RETURNS:
+ * OR'd bitmask of WORK_BUSY_* bits.
+ */
+unsigned int work_busy(struct work_struct *work)
+{
+ struct global_cwq *gcwq = get_work_gcwq(work);
+ unsigned long flags;
+ unsigned int ret = 0;
+
+ if (!gcwq)
+ return false;
+
+ spin_lock_irqsave(&gcwq->lock, flags);
+
+ if (work_pending(work))
+ ret |= WORK_BUSY_PENDING;
+ if (find_worker_executing_work(gcwq, work))
+ ret |= WORK_BUSY_RUNNING;
+
+ spin_unlock_irqrestore(&gcwq->lock, flags);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(work_busy);
+
+/*
+ * CPU hotplug.
+ *
+ * There are two challenges in supporting CPU hotplug. Firstly, there
+ * are a lot of assumptions on strong associations among work, cwq and
+ * gcwq which make migrating pending and scheduled works very
+ * difficult to implement without impacting hot paths. Secondly,
+ * gcwqs serve mix of short, long and very long running works making
+ * blocked draining impractical.
+ *
+ * This is solved by allowing a gcwq to be detached from CPU, running
+ * it with unbound (rogue) workers and allowing it to be reattached
+ * later if the cpu comes back online. A separate thread is created
+ * to govern a gcwq in such state and is called the trustee of the
+ * gcwq.
+ *
+ * Trustee states and their descriptions.
+ *
+ * START Command state used on startup. On CPU_DOWN_PREPARE, a
+ * new trustee is started with this state.
+ *
+ * IN_CHARGE Once started, trustee will enter this state after
+ * assuming the manager role and making all existing
+ * workers rogue. DOWN_PREPARE waits for trustee to
+ * enter this state. After reaching IN_CHARGE, trustee
+ * tries to execute the pending worklist until it's empty
+ * and the state is set to BUTCHER, or the state is set
+ * to RELEASE.
+ *
+ * BUTCHER Command state which is set by the cpu callback after
+ * the cpu has went down. Once this state is set trustee
+ * knows that there will be no new works on the worklist
+ * and once the worklist is empty it can proceed to
+ * killing idle workers.
+ *
+ * RELEASE Command state which is set by the cpu callback if the
+ * cpu down has been canceled or it has come online
+ * again. After recognizing this state, trustee stops
+ * trying to drain or butcher and clears ROGUE, rebinds
+ * all remaining workers back to the cpu and releases
+ * manager role.
+ *
+ * DONE Trustee will enter this state after BUTCHER or RELEASE
+ * is complete.
+ *
+ * trustee CPU draining
+ * took over down complete
+ * START -----------> IN_CHARGE -----------> BUTCHER -----------> DONE
+ * | | ^
+ * | CPU is back online v return workers |
+ * ----------------> RELEASE --------------
+ */
+
+/**
+ * trustee_wait_event_timeout - timed event wait for trustee
+ * @cond: condition to wait for
+ * @timeout: timeout in jiffies
+ *
+ * wait_event_timeout() for trustee to use. Handles locking and
+ * checks for RELEASE request.
+ *
+ * CONTEXT:
+ * spin_lock_irq(gcwq->lock) which may be released and regrabbed
+ * multiple times. To be used by trustee.
+ *
+ * RETURNS:
+ * Positive indicating left time if @cond is satisfied, 0 if timed
+ * out, -1 if canceled.
+ */
+#define trustee_wait_event_timeout(cond, timeout) ({ \
+ long __ret = (timeout); \
+ while (!((cond) || (gcwq->trustee_state == TRUSTEE_RELEASE)) && \
+ __ret) { \
+ spin_unlock_irq(&gcwq->lock); \
+ __wait_event_timeout(gcwq->trustee_wait, (cond) || \
+ (gcwq->trustee_state == TRUSTEE_RELEASE), \
+ __ret); \
+ spin_lock_irq(&gcwq->lock); \
+ } \
+ gcwq->trustee_state == TRUSTEE_RELEASE ? -1 : (__ret); \
+})
+
+/**
+ * trustee_wait_event - event wait for trustee
+ * @cond: condition to wait for
+ *
+ * wait_event() for trustee to use. Automatically handles locking and
+ * checks for CANCEL request.
+ *
+ * CONTEXT:
+ * spin_lock_irq(gcwq->lock) which may be released and regrabbed
+ * multiple times. To be used by trustee.
+ *
+ * RETURNS:
+ * 0 if @cond is satisfied, -1 if canceled.
+ */
+#define trustee_wait_event(cond) ({ \
+ long __ret1; \
+ __ret1 = trustee_wait_event_timeout(cond, MAX_SCHEDULE_TIMEOUT);\
+ __ret1 < 0 ? -1 : 0; \
+})
+
+static int __cpuinit trustee_thread(void *__gcwq)
+{
+ struct global_cwq *gcwq = __gcwq;
+ struct worker *worker;
+ struct work_struct *work;
+ struct hlist_node *pos;
+ long rc;
+ int i;
+
+ BUG_ON(gcwq->cpu != smp_processor_id());
+
+ spin_lock_irq(&gcwq->lock);
+ /*
+ * Claim the manager position and make all workers rogue.
+ * Trustee must be bound to the target cpu and can't be
+ * cancelled.
+ */
+ BUG_ON(gcwq->cpu != smp_processor_id());
+ rc = trustee_wait_event(!(gcwq->flags & GCWQ_MANAGING_WORKERS));
+ BUG_ON(rc < 0);
+
+ gcwq->flags |= GCWQ_MANAGING_WORKERS;
+
+ list_for_each_entry(worker, &gcwq->idle_list, entry)
+ worker->flags |= WORKER_ROGUE;
+
+ for_each_busy_worker(worker, i, pos, gcwq)
+ worker->flags |= WORKER_ROGUE;
+
+ /*
+ * Call schedule() so that we cross rq->lock and thus can
+ * guarantee sched callbacks see the rogue flag. This is
+ * necessary as scheduler callbacks may be invoked from other
+ * cpus.
+ */
+ spin_unlock_irq(&gcwq->lock);
+ schedule();
+ spin_lock_irq(&gcwq->lock);
+
+ /*
+ * Sched callbacks are disabled now. Zap nr_running. After
+ * this, nr_running stays zero and need_more_worker() and
+ * keep_working() are always true as long as the worklist is
+ * not empty.
+ */
+ atomic_set(get_gcwq_nr_running(gcwq->cpu), 0);
+
+ spin_unlock_irq(&gcwq->lock);
+ del_timer_sync(&gcwq->idle_timer);
+ spin_lock_irq(&gcwq->lock);
+
+ /*
+ * We're now in charge. Notify and proceed to drain. We need
+ * to keep the gcwq running during the whole CPU down
+ * procedure as other cpu hotunplug callbacks may need to
+ * flush currently running tasks.
+ */
+ gcwq->trustee_state = TRUSTEE_IN_CHARGE;
+ wake_up_all(&gcwq->trustee_wait);
+
+ /*
+ * The original cpu is in the process of dying and may go away
+ * anytime now. When that happens, we and all workers would
+ * be migrated to other cpus. Try draining any left work. We
+ * want to get it over with ASAP - spam rescuers, wake up as
+ * many idlers as necessary and create new ones till the
+ * worklist is empty. Note that if the gcwq is frozen, there
+ * may be frozen works in freezeable cwqs. Don't declare
+ * completion while frozen.
+ */
+ while (gcwq->nr_workers != gcwq->nr_idle ||
+ gcwq->flags & GCWQ_FREEZING ||
+ gcwq->trustee_state == TRUSTEE_IN_CHARGE) {
+ int nr_works = 0;
+
+ list_for_each_entry(work, &gcwq->worklist, entry) {
+ send_mayday(work);
+ nr_works++;
+ }
+
+ list_for_each_entry(worker, &gcwq->idle_list, entry) {
+ if (!nr_works--)
+ break;
+ wake_up_process(worker->task);
+ }
+
+ if (need_to_create_worker(gcwq)) {
+ spin_unlock_irq(&gcwq->lock);
+ worker = create_worker(gcwq, false);
+ spin_lock_irq(&gcwq->lock);
+ if (worker) {
+ worker->flags |= WORKER_ROGUE;
+ start_worker(worker);
+ }
+ }
+
+ /* give a breather */
+ if (trustee_wait_event_timeout(false, TRUSTEE_COOLDOWN) < 0)
+ break;
+ }
+
+ /*
+ * Either all works have been scheduled and cpu is down, or
+ * cpu down has already been canceled. Wait for and butcher
+ * all workers till we're canceled.
+ */
+ do {
+ rc = trustee_wait_event(!list_empty(&gcwq->idle_list));
+ while (!list_empty(&gcwq->idle_list))
+ destroy_worker(list_first_entry(&gcwq->idle_list,
+ struct worker, entry));
+ } while (gcwq->nr_workers && rc >= 0);
+
+ /*
+ * At this point, either draining has completed and no worker
+ * is left, or cpu down has been canceled or the cpu is being
+ * brought back up. There shouldn't be any idle one left.
+ * Tell the remaining busy ones to rebind once it finishes the
+ * currently scheduled works by scheduling the rebind_work.
+ */
+ WARN_ON(!list_empty(&gcwq->idle_list));
+
+ for_each_busy_worker(worker, i, pos, gcwq) {
+ struct work_struct *rebind_work = &worker->rebind_work;
+
+ /*
+ * Rebind_work may race with future cpu hotplug
+ * operations. Use a separate flag to mark that
+ * rebinding is scheduled.
+ */
+ worker->flags |= WORKER_REBIND;
+ worker->flags &= ~WORKER_ROGUE;
+
+ /* queue rebind_work, wq doesn't matter, use the default one */
+ if (test_and_set_bit(WORK_STRUCT_PENDING_BIT,
+ work_data_bits(rebind_work)))
+ continue;
+
+ debug_work_activate(rebind_work);
+ insert_work(get_cwq(gcwq->cpu, system_wq), rebind_work,
+ worker->scheduled.next,
+ work_color_to_flags(WORK_NO_COLOR));
+ }
+
+ /* relinquish manager role */
+ gcwq->flags &= ~GCWQ_MANAGING_WORKERS;
+
+ /* notify completion */
+ gcwq->trustee = NULL;
+ gcwq->trustee_state = TRUSTEE_DONE;
+ wake_up_all(&gcwq->trustee_wait);
+ spin_unlock_irq(&gcwq->lock);
+ return 0;
+}
+
+/**
+ * wait_trustee_state - wait for trustee to enter the specified state
+ * @gcwq: gcwq the trustee of interest belongs to
+ * @state: target state to wait for
+ *
+ * Wait for the trustee to reach @state. DONE is already matched.
+ *
+ * CONTEXT:
+ * spin_lock_irq(gcwq->lock) which may be released and regrabbed
+ * multiple times. To be used by cpu_callback.
+ */
+static void __cpuinit wait_trustee_state(struct global_cwq *gcwq, int state)
+{
+ if (!(gcwq->trustee_state == state ||
+ gcwq->trustee_state == TRUSTEE_DONE)) {
+ spin_unlock_irq(&gcwq->lock);
+ __wait_event(gcwq->trustee_wait,
+ gcwq->trustee_state == state ||
+ gcwq->trustee_state == TRUSTEE_DONE);
+ spin_lock_irq(&gcwq->lock);
+ }
+}
+
static int __devinit workqueue_cpu_callback(struct notifier_block *nfb,
unsigned long action,
void *hcpu)
{
unsigned int cpu = (unsigned long)hcpu;
- struct cpu_workqueue_struct *cwq;
- struct workqueue_struct *wq;
- int err = 0;
+ struct global_cwq *gcwq = get_gcwq(cpu);
+ struct task_struct *new_trustee = NULL;
+ struct worker *uninitialized_var(new_worker);
+ unsigned long flags;
action &= ~CPU_TASKS_FROZEN;
switch (action) {
+ case CPU_DOWN_PREPARE:
+ new_trustee = kthread_create(trustee_thread, gcwq,
+ "workqueue_trustee/%d\n", cpu);
+ if (IS_ERR(new_trustee))
+ return notifier_from_errno(PTR_ERR(new_trustee));
+ kthread_bind(new_trustee, cpu);
+ /* fall through */
case CPU_UP_PREPARE:
- cpumask_set_cpu(cpu, cpu_populated_map);
- }
-undo:
- list_for_each_entry(wq, &workqueues, list) {
- cwq = per_cpu_ptr(wq->cpu_wq, cpu);
-
- switch (action) {
- case CPU_UP_PREPARE:
- err = create_workqueue_thread(cwq, cpu);
- if (!err)
- break;
- printk(KERN_ERR "workqueue [%s] for %i failed\n",
- wq->name, cpu);
- action = CPU_UP_CANCELED;
- err = -ENOMEM;
- goto undo;
-
- case CPU_ONLINE:
- start_workqueue_thread(cwq, cpu);
- break;
-
- case CPU_UP_CANCELED:
- start_workqueue_thread(cwq, -1);
- case CPU_POST_DEAD:
- cleanup_workqueue_thread(cwq);
- break;
+ BUG_ON(gcwq->first_idle);
+ new_worker = create_worker(gcwq, false);
+ if (!new_worker) {
+ if (new_trustee)
+ kthread_stop(new_trustee);
+ return NOTIFY_BAD;
}
}
+ /* some are called w/ irq disabled, don't disturb irq status */
+ spin_lock_irqsave(&gcwq->lock, flags);
+
switch (action) {
- case CPU_UP_CANCELED:
+ case CPU_DOWN_PREPARE:
+ /* initialize trustee and tell it to acquire the gcwq */
+ BUG_ON(gcwq->trustee || gcwq->trustee_state != TRUSTEE_DONE);
+ gcwq->trustee = new_trustee;
+ gcwq->trustee_state = TRUSTEE_START;
+ wake_up_process(gcwq->trustee);
+ wait_trustee_state(gcwq, TRUSTEE_IN_CHARGE);
+ /* fall through */
+ case CPU_UP_PREPARE:
+ BUG_ON(gcwq->first_idle);
+ gcwq->first_idle = new_worker;
+ break;
+
+ case CPU_DYING:
+ /*
+ * Before this, the trustee and all workers except for
+ * the ones which are still executing works from
+ * before the last CPU down must be on the cpu. After
+ * this, they'll all be diasporas.
+ */
+ gcwq->flags |= GCWQ_DISASSOCIATED;
+ break;
+
case CPU_POST_DEAD:
- cpumask_clear_cpu(cpu, cpu_populated_map);
+ gcwq->trustee_state = TRUSTEE_BUTCHER;
+ /* fall through */
+ case CPU_UP_CANCELED:
+ destroy_worker(gcwq->first_idle);
+ gcwq->first_idle = NULL;
+ break;
+
+ case CPU_DOWN_FAILED:
+ case CPU_ONLINE:
+ gcwq->flags &= ~GCWQ_DISASSOCIATED;
+ if (gcwq->trustee_state != TRUSTEE_DONE) {
+ gcwq->trustee_state = TRUSTEE_RELEASE;
+ wake_up_process(gcwq->trustee);
+ wait_trustee_state(gcwq, TRUSTEE_DONE);
+ }
+
+ /*
+ * Trustee is done and there might be no worker left.
+ * Put the first_idle in and request a real manager to
+ * take a look.
+ */
+ spin_unlock_irq(&gcwq->lock);
+ kthread_bind(gcwq->first_idle->task, cpu);
+ spin_lock_irq(&gcwq->lock);
+ gcwq->flags |= GCWQ_MANAGE_WORKERS;
+ start_worker(gcwq->first_idle);
+ gcwq->first_idle = NULL;
+ break;
}
- return notifier_from_errno(err);
+ spin_unlock_irqrestore(&gcwq->lock, flags);
+
+ return notifier_from_errno(0);
}
#ifdef CONFIG_SMP
@@ -1201,14 +3381,199 @@ long work_on_cpu(unsigned int cpu, long (*fn)(void *), void *arg)
EXPORT_SYMBOL_GPL(work_on_cpu);
#endif /* CONFIG_SMP */
-void __init init_workqueues(void)
+#ifdef CONFIG_FREEZER
+
+/**
+ * freeze_workqueues_begin - begin freezing workqueues
+ *
+ * Start freezing workqueues. After this function returns, all
+ * freezeable workqueues will queue new works to their frozen_works
+ * list instead of gcwq->worklist.
+ *
+ * CONTEXT:
+ * Grabs and releases workqueue_lock and gcwq->lock's.
+ */
+void freeze_workqueues_begin(void)
{
- alloc_cpumask_var(&cpu_populated_map, GFP_KERNEL);
+ unsigned int cpu;
- cpumask_copy(cpu_populated_map, cpu_online_mask);
- singlethread_cpu = cpumask_first(cpu_possible_mask);
- cpu_singlethread_map = cpumask_of(singlethread_cpu);
- hotcpu_notifier(workqueue_cpu_callback, 0);
- keventd_wq = create_workqueue("events");
- BUG_ON(!keventd_wq);
+ spin_lock(&workqueue_lock);
+
+ BUG_ON(workqueue_freezing);
+ workqueue_freezing = true;
+
+ for_each_gcwq_cpu(cpu) {
+ struct global_cwq *gcwq = get_gcwq(cpu);
+ struct workqueue_struct *wq;
+
+ spin_lock_irq(&gcwq->lock);
+
+ BUG_ON(gcwq->flags & GCWQ_FREEZING);
+ gcwq->flags |= GCWQ_FREEZING;
+
+ list_for_each_entry(wq, &workqueues, list) {
+ struct cpu_workqueue_struct *cwq = get_cwq(cpu, wq);
+
+ if (cwq && wq->flags & WQ_FREEZEABLE)
+ cwq->max_active = 0;
+ }
+
+ spin_unlock_irq(&gcwq->lock);
+ }
+
+ spin_unlock(&workqueue_lock);
+}
+
+/**
+ * freeze_workqueues_busy - are freezeable workqueues still busy?
+ *
+ * Check whether freezing is complete. This function must be called
+ * between freeze_workqueues_begin() and thaw_workqueues().
+ *
+ * CONTEXT:
+ * Grabs and releases workqueue_lock.
+ *
+ * RETURNS:
+ * %true if some freezeable workqueues are still busy. %false if
+ * freezing is complete.
+ */
+bool freeze_workqueues_busy(void)
+{
+ unsigned int cpu;
+ bool busy = false;
+
+ spin_lock(&workqueue_lock);
+
+ BUG_ON(!workqueue_freezing);
+
+ for_each_gcwq_cpu(cpu) {
+ struct workqueue_struct *wq;
+ /*
+ * nr_active is monotonically decreasing. It's safe
+ * to peek without lock.
+ */
+ list_for_each_entry(wq, &workqueues, list) {
+ struct cpu_workqueue_struct *cwq = get_cwq(cpu, wq);
+
+ if (!cwq || !(wq->flags & WQ_FREEZEABLE))
+ continue;
+
+ BUG_ON(cwq->nr_active < 0);
+ if (cwq->nr_active) {
+ busy = true;
+ goto out_unlock;
+ }
+ }
+ }
+out_unlock:
+ spin_unlock(&workqueue_lock);
+ return busy;
+}
+
+/**
+ * thaw_workqueues - thaw workqueues
+ *
+ * Thaw workqueues. Normal queueing is restored and all collected
+ * frozen works are transferred to their respective gcwq worklists.
+ *
+ * CONTEXT:
+ * Grabs and releases workqueue_lock and gcwq->lock's.
+ */
+void thaw_workqueues(void)
+{
+ unsigned int cpu;
+
+ spin_lock(&workqueue_lock);
+
+ if (!workqueue_freezing)
+ goto out_unlock;
+
+ for_each_gcwq_cpu(cpu) {
+ struct global_cwq *gcwq = get_gcwq(cpu);
+ struct workqueue_struct *wq;
+
+ spin_lock_irq(&gcwq->lock);
+
+ BUG_ON(!(gcwq->flags & GCWQ_FREEZING));
+ gcwq->flags &= ~GCWQ_FREEZING;
+
+ list_for_each_entry(wq, &workqueues, list) {
+ struct cpu_workqueue_struct *cwq = get_cwq(cpu, wq);
+
+ if (!cwq || !(wq->flags & WQ_FREEZEABLE))
+ continue;
+
+ /* restore max_active and repopulate worklist */
+ cwq->max_active = wq->saved_max_active;
+
+ while (!list_empty(&cwq->delayed_works) &&
+ cwq->nr_active < cwq->max_active)
+ cwq_activate_first_delayed(cwq);
+ }
+
+ wake_up_worker(gcwq);
+
+ spin_unlock_irq(&gcwq->lock);
+ }
+
+ workqueue_freezing = false;
+out_unlock:
+ spin_unlock(&workqueue_lock);
+}
+#endif /* CONFIG_FREEZER */
+
+static int __init init_workqueues(void)
+{
+ unsigned int cpu;
+ int i;
+
+ hotcpu_notifier(workqueue_cpu_callback, CPU_PRI_WORKQUEUE);
+
+ /* initialize gcwqs */
+ for_each_gcwq_cpu(cpu) {
+ struct global_cwq *gcwq = get_gcwq(cpu);
+
+ spin_lock_init(&gcwq->lock);
+ INIT_LIST_HEAD(&gcwq->worklist);
+ gcwq->cpu = cpu;
+ if (cpu == WORK_CPU_UNBOUND)
+ gcwq->flags |= GCWQ_DISASSOCIATED;
+
+ INIT_LIST_HEAD(&gcwq->idle_list);
+ for (i = 0; i < BUSY_WORKER_HASH_SIZE; i++)
+ INIT_HLIST_HEAD(&gcwq->busy_hash[i]);
+
+ init_timer_deferrable(&gcwq->idle_timer);
+ gcwq->idle_timer.function = idle_worker_timeout;
+ gcwq->idle_timer.data = (unsigned long)gcwq;
+
+ setup_timer(&gcwq->mayday_timer, gcwq_mayday_timeout,
+ (unsigned long)gcwq);
+
+ ida_init(&gcwq->worker_ida);
+
+ gcwq->trustee_state = TRUSTEE_DONE;
+ init_waitqueue_head(&gcwq->trustee_wait);
+ }
+
+ /* create the initial worker */
+ for_each_online_gcwq_cpu(cpu) {
+ struct global_cwq *gcwq = get_gcwq(cpu);
+ struct worker *worker;
+
+ worker = create_worker(gcwq, true);
+ BUG_ON(!worker);
+ spin_lock_irq(&gcwq->lock);
+ start_worker(worker);
+ spin_unlock_irq(&gcwq->lock);
+ }
+
+ system_wq = alloc_workqueue("events", 0, 0);
+ system_long_wq = alloc_workqueue("events_long", 0, 0);
+ system_nrt_wq = alloc_workqueue("events_nrt", WQ_NON_REENTRANT, 0);
+ system_unbound_wq = alloc_workqueue("events_unbound", WQ_UNBOUND,
+ WQ_UNBOUND_MAX_ACTIVE);
+ BUG_ON(!system_wq || !system_long_wq || !system_nrt_wq);
+ return 0;
}
+early_initcall(init_workqueues);
diff --git a/kernel/workqueue_sched.h b/kernel/workqueue_sched.h
new file mode 100644
index 00000000000..2d10fc98dc7
--- /dev/null
+++ b/kernel/workqueue_sched.h
@@ -0,0 +1,9 @@
+/*
+ * kernel/workqueue_sched.h
+ *
+ * Scheduler hooks for concurrency managed workqueue. Only to be
+ * included from sched.c and workqueue.c.
+ */
+void wq_worker_waking_up(struct task_struct *task, unsigned int cpu);
+struct task_struct *wq_worker_sleeping(struct task_struct *task,
+ unsigned int cpu);
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
index e722e9d6222..79e0dff1cdc 100644
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -76,7 +76,6 @@ config UNUSED_SYMBOLS
config DEBUG_FS
bool "Debug Filesystem"
- depends on SYSFS
help
debugfs is a virtual file system that kernel developers use to put
debugging files into. Enable this option to be able to read and
@@ -152,28 +151,33 @@ config DEBUG_SHIRQ
Drivers ought to be able to handle interrupts coming in at those
points; some don't and need to be caught.
-config DETECT_SOFTLOCKUP
- bool "Detect Soft Lockups"
+config LOCKUP_DETECTOR
+ bool "Detect Hard and Soft Lockups"
depends on DEBUG_KERNEL && !S390
- default y
help
- Say Y here to enable the kernel to detect "soft lockups",
- which are bugs that cause the kernel to loop in kernel
+ Say Y here to enable the kernel to act as a watchdog to detect
+ hard and soft lockups.
+
+ Softlockups are bugs that cause the kernel to loop in kernel
mode for more than 60 seconds, without giving other tasks a
- chance to run.
+ chance to run. The current stack trace is displayed upon
+ detection and the system will stay locked up.
- When a soft-lockup is detected, the kernel will print the
- current stack trace (which you should report), but the
- system will stay locked up. This feature has negligible
- overhead.
+ Hardlockups are bugs that cause the CPU to loop in kernel mode
+ for more than 60 seconds, without letting other interrupts have a
+ chance to run. The current stack trace is displayed upon detection
+ and the system will stay locked up.
- (Note that "hard lockups" are separate type of bugs that
- can be detected via the NMI-watchdog, on platforms that
- support it.)
+ The overhead should be minimal. A periodic hrtimer runs to
+ generate interrupts and kick the watchdog task every 10-12 seconds.
+ An NMI is generated every 60 seconds or so to check for hardlockups.
+
+config HARDLOCKUP_DETECTOR
+ def_bool LOCKUP_DETECTOR && PERF_EVENTS && HAVE_PERF_EVENTS_NMI
config BOOTPARAM_SOFTLOCKUP_PANIC
bool "Panic (Reboot) On Soft Lockups"
- depends on DETECT_SOFTLOCKUP
+ depends on LOCKUP_DETECTOR
help
Say Y here to enable the kernel to panic on "soft lockups",
which are bugs that cause the kernel to loop in kernel
@@ -190,7 +194,7 @@ config BOOTPARAM_SOFTLOCKUP_PANIC
config BOOTPARAM_SOFTLOCKUP_PANIC_VALUE
int
- depends on DETECT_SOFTLOCKUP
+ depends on LOCKUP_DETECTOR
range 0 1
default 0 if !BOOTPARAM_SOFTLOCKUP_PANIC
default 1 if BOOTPARAM_SOFTLOCKUP_PANIC
@@ -307,6 +311,12 @@ config DEBUG_OBJECTS_WORK
work queue routines to track the life time of work objects and
validate the work operations.
+config DEBUG_OBJECTS_RCU_HEAD
+ bool "Debug RCU callbacks objects"
+ depends on DEBUG_OBJECTS && PREEMPT
+ help
+ Enable this to turn on debugging of RCU list heads (call_rcu() usage).
+
config DEBUG_OBJECTS_ENABLE_DEFAULT
int "debug_objects bootup default value (0-1)"
range 0 1
@@ -528,7 +538,7 @@ config LOCKDEP
bool
depends on DEBUG_KERNEL && TRACE_IRQFLAGS_SUPPORT && STACKTRACE_SUPPORT && LOCKDEP_SUPPORT
select STACKTRACE
- select FRAME_POINTER if !MIPS && !PPC && !ARM_UNWIND && !S390
+ select FRAME_POINTER if !MIPS && !PPC && !ARM_UNWIND && !S390 && !MICROBLAZE
select KALLSYMS
select KALLSYMS_ALL
@@ -628,6 +638,19 @@ config DEBUG_INFO
If unsure, say N.
+config DEBUG_INFO_REDUCED
+ bool "Reduce debugging information"
+ depends on DEBUG_INFO
+ help
+ If you say Y here gcc is instructed to generate less debugging
+ information for structure types. This means that tools that
+ need full debugging information (like kgdb or systemtap) won't
+ be happy. But if you merely need debugging information to
+ resolve line numbers there is no loss. Advantage is that
+ build directory object sizes shrink dramatically over a full
+ DEBUG_INFO build and compile times are reduced too.
+ Only works with newer gcc versions.
+
config DEBUG_VM
bool "Debug VM"
depends on DEBUG_KERNEL
@@ -937,7 +960,7 @@ config FAIL_MAKE_REQUEST
Provide fault-injection capability for disk IO.
config FAIL_IO_TIMEOUT
- bool "Faul-injection capability for faking disk interrupts"
+ bool "Fault-injection capability for faking disk interrupts"
depends on FAULT_INJECTION && BLOCK
help
Provide fault-injection capability on end IO handling. This
@@ -958,13 +981,13 @@ config FAULT_INJECTION_STACKTRACE_FILTER
depends on FAULT_INJECTION_DEBUG_FS && STACKTRACE_SUPPORT
depends on !X86_64
select STACKTRACE
- select FRAME_POINTER if !PPC && !S390
+ select FRAME_POINTER if !PPC && !S390 && !MICROBLAZE
help
Provide stacktrace filter for fault-injection capabilities
config LATENCYTOP
bool "Latency measuring infrastructure"
- select FRAME_POINTER if !MIPS && !PPC && !S390
+ select FRAME_POINTER if !MIPS && !PPC && !S390 && !MICROBLAZE
select KALLSYMS
select KALLSYMS_ALL
select STACKTRACE
diff --git a/lib/devres.c b/lib/devres.c
index 49368608f98..6efddf53b90 100644
--- a/lib/devres.c
+++ b/lib/devres.c
@@ -328,7 +328,7 @@ EXPORT_SYMBOL(pcim_iomap_regions_request_all);
* @pdev: PCI device to map IO resources for
* @mask: Mask of BARs to unmap and release
*
- * Unamp and release regions specified by @mask.
+ * Unmap and release regions specified by @mask.
*/
void pcim_iounmap_regions(struct pci_dev *pdev, u16 mask)
{
diff --git a/lib/ioremap.c b/lib/ioremap.c
index 14c6078f17a..5730ecd3eb6 100644
--- a/lib/ioremap.c
+++ b/lib/ioremap.c
@@ -13,10 +13,10 @@
#include <asm/pgtable.h>
static int ioremap_pte_range(pmd_t *pmd, unsigned long addr,
- unsigned long end, unsigned long phys_addr, pgprot_t prot)
+ unsigned long end, phys_addr_t phys_addr, pgprot_t prot)
{
pte_t *pte;
- unsigned long pfn;
+ u64 pfn;
pfn = phys_addr >> PAGE_SHIFT;
pte = pte_alloc_kernel(pmd, addr);
@@ -31,7 +31,7 @@ static int ioremap_pte_range(pmd_t *pmd, unsigned long addr,
}
static inline int ioremap_pmd_range(pud_t *pud, unsigned long addr,
- unsigned long end, unsigned long phys_addr, pgprot_t prot)
+ unsigned long end, phys_addr_t phys_addr, pgprot_t prot)
{
pmd_t *pmd;
unsigned long next;
@@ -49,7 +49,7 @@ static inline int ioremap_pmd_range(pud_t *pud, unsigned long addr,
}
static inline int ioremap_pud_range(pgd_t *pgd, unsigned long addr,
- unsigned long end, unsigned long phys_addr, pgprot_t prot)
+ unsigned long end, phys_addr_t phys_addr, pgprot_t prot)
{
pud_t *pud;
unsigned long next;
@@ -67,7 +67,7 @@ static inline int ioremap_pud_range(pgd_t *pgd, unsigned long addr,
}
int ioremap_page_range(unsigned long addr,
- unsigned long end, unsigned long phys_addr, pgprot_t prot)
+ unsigned long end, phys_addr_t phys_addr, pgprot_t prot)
{
pgd_t *pgd;
unsigned long start;
diff --git a/lib/random32.c b/lib/random32.c
index 870dc3fc0f0..fc3545a3277 100644
--- a/lib/random32.c
+++ b/lib/random32.c
@@ -127,7 +127,7 @@ core_initcall(random32_init);
/*
* Generate better values after random number generator
- * is fully initalized.
+ * is fully initialized.
*/
static int __init random32_reseed(void)
{
diff --git a/lib/swiotlb.c b/lib/swiotlb.c
index a009055140e..34e3082632d 100644
--- a/lib/swiotlb.c
+++ b/lib/swiotlb.c
@@ -50,19 +50,11 @@
*/
#define IO_TLB_MIN_SLABS ((1<<20) >> IO_TLB_SHIFT)
-/*
- * Enumeration for sync targets
- */
-enum dma_sync_target {
- SYNC_FOR_CPU = 0,
- SYNC_FOR_DEVICE = 1,
-};
-
int swiotlb_force;
/*
- * Used to do a quick range check in unmap_single and
- * sync_single_*, to see if the memory was in fact allocated by this
+ * Used to do a quick range check in swiotlb_tbl_unmap_single and
+ * swiotlb_tbl_sync_single_*, to see if the memory was in fact allocated by this
* API.
*/
static char *io_tlb_start, *io_tlb_end;
@@ -140,28 +132,14 @@ void swiotlb_print_info(void)
(unsigned long long)pend);
}
-/*
- * Statically reserve bounce buffer space and initialize bounce buffer data
- * structures for the software IO TLB used to implement the DMA API.
- */
-void __init
-swiotlb_init_with_default_size(size_t default_size, int verbose)
+void __init swiotlb_init_with_tbl(char *tlb, unsigned long nslabs, int verbose)
{
unsigned long i, bytes;
- if (!io_tlb_nslabs) {
- io_tlb_nslabs = (default_size >> IO_TLB_SHIFT);
- io_tlb_nslabs = ALIGN(io_tlb_nslabs, IO_TLB_SEGSIZE);
- }
-
- bytes = io_tlb_nslabs << IO_TLB_SHIFT;
+ bytes = nslabs << IO_TLB_SHIFT;
- /*
- * Get IO TLB memory from the low pages
- */
- io_tlb_start = alloc_bootmem_low_pages(bytes);
- if (!io_tlb_start)
- panic("Cannot allocate SWIOTLB buffer");
+ io_tlb_nslabs = nslabs;
+ io_tlb_start = tlb;
io_tlb_end = io_tlb_start + bytes;
/*
@@ -185,6 +163,32 @@ swiotlb_init_with_default_size(size_t default_size, int verbose)
swiotlb_print_info();
}
+/*
+ * Statically reserve bounce buffer space and initialize bounce buffer data
+ * structures for the software IO TLB used to implement the DMA API.
+ */
+void __init
+swiotlb_init_with_default_size(size_t default_size, int verbose)
+{
+ unsigned long bytes;
+
+ if (!io_tlb_nslabs) {
+ io_tlb_nslabs = (default_size >> IO_TLB_SHIFT);
+ io_tlb_nslabs = ALIGN(io_tlb_nslabs, IO_TLB_SEGSIZE);
+ }
+
+ bytes = io_tlb_nslabs << IO_TLB_SHIFT;
+
+ /*
+ * Get IO TLB memory from the low pages
+ */
+ io_tlb_start = alloc_bootmem_low_pages(bytes);
+ if (!io_tlb_start)
+ panic("Cannot allocate SWIOTLB buffer");
+
+ swiotlb_init_with_tbl(io_tlb_start, io_tlb_nslabs, verbose);
+}
+
void __init
swiotlb_init(int verbose)
{
@@ -323,8 +327,8 @@ static int is_swiotlb_buffer(phys_addr_t paddr)
/*
* Bounce: copy the swiotlb buffer back to the original dma location
*/
-static void swiotlb_bounce(phys_addr_t phys, char *dma_addr, size_t size,
- enum dma_data_direction dir)
+void swiotlb_bounce(phys_addr_t phys, char *dma_addr, size_t size,
+ enum dma_data_direction dir)
{
unsigned long pfn = PFN_DOWN(phys);
@@ -360,26 +364,25 @@ static void swiotlb_bounce(phys_addr_t phys, char *dma_addr, size_t size,
memcpy(phys_to_virt(phys), dma_addr, size);
}
}
+EXPORT_SYMBOL_GPL(swiotlb_bounce);
-/*
- * Allocates bounce buffer and returns its kernel virtual address.
- */
-static void *
-map_single(struct device *hwdev, phys_addr_t phys, size_t size, int dir)
+void *swiotlb_tbl_map_single(struct device *hwdev, dma_addr_t tbl_dma_addr,
+ phys_addr_t phys, size_t size,
+ enum dma_data_direction dir)
{
unsigned long flags;
char *dma_addr;
unsigned int nslots, stride, index, wrap;
int i;
- unsigned long start_dma_addr;
unsigned long mask;
unsigned long offset_slots;
unsigned long max_slots;
mask = dma_get_seg_boundary(hwdev);
- start_dma_addr = swiotlb_virt_to_bus(hwdev, io_tlb_start) & mask;
- offset_slots = ALIGN(start_dma_addr, 1 << IO_TLB_SHIFT) >> IO_TLB_SHIFT;
+ tbl_dma_addr &= mask;
+
+ offset_slots = ALIGN(tbl_dma_addr, 1 << IO_TLB_SHIFT) >> IO_TLB_SHIFT;
/*
* Carefully handle integer overflow which can occur when mask == ~0UL.
@@ -466,12 +469,27 @@ found:
return dma_addr;
}
+EXPORT_SYMBOL_GPL(swiotlb_tbl_map_single);
+
+/*
+ * Allocates bounce buffer and returns its kernel virtual address.
+ */
+
+static void *
+map_single(struct device *hwdev, phys_addr_t phys, size_t size,
+ enum dma_data_direction dir)
+{
+ dma_addr_t start_dma_addr = swiotlb_virt_to_bus(hwdev, io_tlb_start);
+
+ return swiotlb_tbl_map_single(hwdev, start_dma_addr, phys, size, dir);
+}
/*
* dma_addr is the kernel virtual address of the bounce buffer to unmap.
*/
-static void
-do_unmap_single(struct device *hwdev, char *dma_addr, size_t size, int dir)
+void
+swiotlb_tbl_unmap_single(struct device *hwdev, char *dma_addr, size_t size,
+ enum dma_data_direction dir)
{
unsigned long flags;
int i, count, nslots = ALIGN(size, 1 << IO_TLB_SHIFT) >> IO_TLB_SHIFT;
@@ -509,10 +527,12 @@ do_unmap_single(struct device *hwdev, char *dma_addr, size_t size, int dir)
}
spin_unlock_irqrestore(&io_tlb_lock, flags);
}
+EXPORT_SYMBOL_GPL(swiotlb_tbl_unmap_single);
-static void
-sync_single(struct device *hwdev, char *dma_addr, size_t size,
- int dir, int target)
+void
+swiotlb_tbl_sync_single(struct device *hwdev, char *dma_addr, size_t size,
+ enum dma_data_direction dir,
+ enum dma_sync_target target)
{
int index = (dma_addr - io_tlb_start) >> IO_TLB_SHIFT;
phys_addr_t phys = io_tlb_orig_addr[index];
@@ -536,6 +556,7 @@ sync_single(struct device *hwdev, char *dma_addr, size_t size,
BUG();
}
}
+EXPORT_SYMBOL_GPL(swiotlb_tbl_sync_single);
void *
swiotlb_alloc_coherent(struct device *hwdev, size_t size,
@@ -559,8 +580,8 @@ swiotlb_alloc_coherent(struct device *hwdev, size_t size,
}
if (!ret) {
/*
- * We are either out of memory or the device can't DMA
- * to GFP_DMA memory; fall back on map_single(), which
+ * We are either out of memory or the device can't DMA to
+ * GFP_DMA memory; fall back on map_single(), which
* will grab memory from the lowest available address range.
*/
ret = map_single(hwdev, 0, size, DMA_FROM_DEVICE);
@@ -578,7 +599,7 @@ swiotlb_alloc_coherent(struct device *hwdev, size_t size,
(unsigned long long)dev_addr);
/* DMA_TO_DEVICE to avoid memcpy in unmap_single */
- do_unmap_single(hwdev, ret, size, DMA_TO_DEVICE);
+ swiotlb_tbl_unmap_single(hwdev, ret, size, DMA_TO_DEVICE);
return NULL;
}
*dma_handle = dev_addr;
@@ -596,13 +617,14 @@ swiotlb_free_coherent(struct device *hwdev, size_t size, void *vaddr,
if (!is_swiotlb_buffer(paddr))
free_pages((unsigned long)vaddr, get_order(size));
else
- /* DMA_TO_DEVICE to avoid memcpy in unmap_single */
- do_unmap_single(hwdev, vaddr, size, DMA_TO_DEVICE);
+ /* DMA_TO_DEVICE to avoid memcpy in swiotlb_tbl_unmap_single */
+ swiotlb_tbl_unmap_single(hwdev, vaddr, size, DMA_TO_DEVICE);
}
EXPORT_SYMBOL(swiotlb_free_coherent);
static void
-swiotlb_full(struct device *dev, size_t size, int dir, int do_panic)
+swiotlb_full(struct device *dev, size_t size, enum dma_data_direction dir,
+ int do_panic)
{
/*
* Ran out of IOMMU space for this operation. This is very bad.
@@ -680,14 +702,14 @@ EXPORT_SYMBOL_GPL(swiotlb_map_page);
* whatever the device wrote there.
*/
static void unmap_single(struct device *hwdev, dma_addr_t dev_addr,
- size_t size, int dir)
+ size_t size, enum dma_data_direction dir)
{
phys_addr_t paddr = dma_to_phys(hwdev, dev_addr);
BUG_ON(dir == DMA_NONE);
if (is_swiotlb_buffer(paddr)) {
- do_unmap_single(hwdev, phys_to_virt(paddr), size, dir);
+ swiotlb_tbl_unmap_single(hwdev, phys_to_virt(paddr), size, dir);
return;
}
@@ -723,14 +745,16 @@ EXPORT_SYMBOL_GPL(swiotlb_unmap_page);
*/
static void
swiotlb_sync_single(struct device *hwdev, dma_addr_t dev_addr,
- size_t size, int dir, int target)
+ size_t size, enum dma_data_direction dir,
+ enum dma_sync_target target)
{
phys_addr_t paddr = dma_to_phys(hwdev, dev_addr);
BUG_ON(dir == DMA_NONE);
if (is_swiotlb_buffer(paddr)) {
- sync_single(hwdev, phys_to_virt(paddr), size, dir, target);
+ swiotlb_tbl_sync_single(hwdev, phys_to_virt(paddr), size, dir,
+ target);
return;
}
@@ -809,7 +833,7 @@ EXPORT_SYMBOL(swiotlb_map_sg_attrs);
int
swiotlb_map_sg(struct device *hwdev, struct scatterlist *sgl, int nelems,
- int dir)
+ enum dma_data_direction dir)
{
return swiotlb_map_sg_attrs(hwdev, sgl, nelems, dir, NULL);
}
@@ -836,7 +860,7 @@ EXPORT_SYMBOL(swiotlb_unmap_sg_attrs);
void
swiotlb_unmap_sg(struct device *hwdev, struct scatterlist *sgl, int nelems,
- int dir)
+ enum dma_data_direction dir)
{
return swiotlb_unmap_sg_attrs(hwdev, sgl, nelems, dir, NULL);
}
@@ -851,7 +875,8 @@ EXPORT_SYMBOL(swiotlb_unmap_sg);
*/
static void
swiotlb_sync_sg(struct device *hwdev, struct scatterlist *sgl,
- int nelems, int dir, int target)
+ int nelems, enum dma_data_direction dir,
+ enum dma_sync_target target)
{
struct scatterlist *sg;
int i;
diff --git a/lib/vsprintf.c b/lib/vsprintf.c
index b8a2f549ab0..4ee19d0d391 100644
--- a/lib/vsprintf.c
+++ b/lib/vsprintf.c
@@ -980,6 +980,11 @@ char *uuid_string(char *buf, char *end, const u8 *addr,
* [0][1][2][3]-[4][5]-[6][7]-[8][9]-[10][11][12][13][14][15]
* little endian output byte order is:
* [3][2][1][0]-[5][4]-[7][6]-[8][9]-[10][11][12][13][14][15]
+ * - 'V' For a struct va_format which contains a format string * and va_list *,
+ * call vsnprintf(->format, *->va_list).
+ * Implements a "recursive vsnprintf".
+ * Do not use this feature without some mechanism to verify the
+ * correctness of the format string and va_list arguments.
*
* Note: The difference between 'S' and 'F' is that on ia64 and ppc64
* function pointers are really function descriptors, which contain a
@@ -1025,6 +1030,10 @@ char *pointer(const char *fmt, char *buf, char *end, void *ptr,
break;
case 'U':
return uuid_string(buf, end, ptr, spec, fmt);
+ case 'V':
+ return buf + vsnprintf(buf, end - buf,
+ ((struct va_format *)ptr)->fmt,
+ *(((struct va_format *)ptr)->va));
}
spec.flags |= SMALL;
if (spec.field_width == -1) {
diff --git a/mm/backing-dev.c b/mm/backing-dev.c
index 123bcef13e5..f9fd3dd3916 100644
--- a/mm/backing-dev.c
+++ b/mm/backing-dev.c
@@ -665,7 +665,6 @@ int bdi_init(struct backing_dev_info *bdi)
bdi->max_ratio = 100;
bdi->max_prop_frac = PROP_FRAC_BASE;
spin_lock_init(&bdi->wb_lock);
- INIT_RCU_HEAD(&bdi->rcu_head);
INIT_LIST_HEAD(&bdi->bdi_list);
INIT_LIST_HEAD(&bdi->wb_list);
INIT_LIST_HEAD(&bdi->work_list);
diff --git a/mm/highmem.c b/mm/highmem.c
index 66baa20f78f..7a0aa1be499 100644
--- a/mm/highmem.c
+++ b/mm/highmem.c
@@ -26,6 +26,7 @@
#include <linux/init.h>
#include <linux/hash.h>
#include <linux/highmem.h>
+#include <linux/kgdb.h>
#include <asm/tlbflush.h>
/*
@@ -470,6 +471,12 @@ void debug_kmap_atomic(enum km_type type)
warn_count--;
}
}
+#ifdef CONFIG_KGDB_KDB
+ if (unlikely(type == KM_KDB && atomic_read(&kgdb_active) == -1)) {
+ WARN_ON(1);
+ warn_count--;
+ }
+#endif /* CONFIG_KGDB_KDB */
}
#endif
diff --git a/mm/memory-failure.c b/mm/memory-failure.c
index 620b0b46159..6b44e52caca 100644
--- a/mm/memory-failure.c
+++ b/mm/memory-failure.c
@@ -45,6 +45,7 @@
#include <linux/page-isolation.h>
#include <linux/suspend.h>
#include <linux/slab.h>
+#include <linux/swapops.h>
#include "internal.h"
int sysctl_memory_failure_early_kill __read_mostly = 0;
@@ -1296,3 +1297,35 @@ done:
/* keep elevated page count for bad page */
return ret;
}
+
+/*
+ * The caller must hold current->mm->mmap_sem in read mode.
+ */
+int is_hwpoison_address(unsigned long addr)
+{
+ pgd_t *pgdp;
+ pud_t pud, *pudp;
+ pmd_t pmd, *pmdp;
+ pte_t pte, *ptep;
+ swp_entry_t entry;
+
+ pgdp = pgd_offset(current->mm, addr);
+ if (!pgd_present(*pgdp))
+ return 0;
+ pudp = pud_offset(pgdp, addr);
+ pud = *pudp;
+ if (!pud_present(pud) || pud_large(pud))
+ return 0;
+ pmdp = pmd_offset(pudp, addr);
+ pmd = *pmdp;
+ if (!pmd_present(pmd) || pmd_large(pmd))
+ return 0;
+ ptep = pte_offset_map(pmdp, addr);
+ pte = *ptep;
+ pte_unmap(ptep);
+ if (!is_swap_pte(pte))
+ return 0;
+ entry = pte_to_swp_entry(pte);
+ return is_hwpoison_entry(entry);
+}
+EXPORT_SYMBOL_GPL(is_hwpoison_address);
diff --git a/mm/mmap.c b/mm/mmap.c
index 456ec6f2788..e38e910cb75 100644
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -1734,8 +1734,10 @@ int expand_upwards(struct vm_area_struct *vma, unsigned long address)
grow = (address - vma->vm_end) >> PAGE_SHIFT;
error = acct_stack_growth(vma, size, grow);
- if (!error)
+ if (!error) {
vma->vm_end = address;
+ perf_event_mmap(vma);
+ }
}
anon_vma_unlock(vma);
return error;
@@ -1781,6 +1783,7 @@ static int expand_downwards(struct vm_area_struct *vma,
if (!error) {
vma->vm_start = address;
vma->vm_pgoff -= grow;
+ perf_event_mmap(vma);
}
}
anon_vma_unlock(vma);
@@ -2208,6 +2211,7 @@ unsigned long do_brk(unsigned long addr, unsigned long len)
vma->vm_page_prot = vm_get_page_prot(flags);
vma_link(mm, vma, prev, rb_link, rb_parent);
out:
+ perf_event_mmap(vma);
mm->total_vm += len >> PAGE_SHIFT;
if (flags & VM_LOCKED) {
if (!mlock_vma_pages_range(vma, addr, addr + len))
diff --git a/mm/percpu.c b/mm/percpu.c
index 6470e771023..e61dc2cc587 100644
--- a/mm/percpu.c
+++ b/mm/percpu.c
@@ -282,6 +282,9 @@ static void __maybe_unused pcpu_next_pop(struct pcpu_chunk *chunk,
*/
static void *pcpu_mem_alloc(size_t size)
{
+ if (WARN_ON_ONCE(!slab_is_available()))
+ return NULL;
+
if (size <= PAGE_SIZE)
return kzalloc(size, GFP_KERNEL);
else {
@@ -392,13 +395,6 @@ static int pcpu_extend_area_map(struct pcpu_chunk *chunk, int new_alloc)
old_size = chunk->map_alloc * sizeof(chunk->map[0]);
memcpy(new, chunk->map, old_size);
- /*
- * map_alloc < PCPU_DFL_MAP_ALLOC indicates that the chunk is
- * one of the first chunks and still using static map.
- */
- if (chunk->map_alloc >= PCPU_DFL_MAP_ALLOC)
- old = chunk->map;
-
chunk->map_alloc = new_alloc;
chunk->map = new;
new = NULL;
@@ -604,7 +600,7 @@ static struct pcpu_chunk *pcpu_alloc_chunk(void)
{
struct pcpu_chunk *chunk;
- chunk = kzalloc(pcpu_chunk_struct_size, GFP_KERNEL);
+ chunk = pcpu_mem_alloc(pcpu_chunk_struct_size);
if (!chunk)
return NULL;
@@ -1013,20 +1009,6 @@ phys_addr_t per_cpu_ptr_to_phys(void *addr)
return page_to_phys(pcpu_addr_to_page(addr));
}
-static inline size_t pcpu_calc_fc_sizes(size_t static_size,
- size_t reserved_size,
- ssize_t *dyn_sizep)
-{
- size_t size_sum;
-
- size_sum = PFN_ALIGN(static_size + reserved_size +
- (*dyn_sizep >= 0 ? *dyn_sizep : 0));
- if (*dyn_sizep != 0)
- *dyn_sizep = size_sum - static_size - reserved_size;
-
- return size_sum;
-}
-
/**
* pcpu_alloc_alloc_info - allocate percpu allocation info
* @nr_groups: the number of groups
@@ -1085,7 +1067,7 @@ void __init pcpu_free_alloc_info(struct pcpu_alloc_info *ai)
/**
* pcpu_build_alloc_info - build alloc_info considering distances between CPUs
* @reserved_size: the size of reserved percpu area in bytes
- * @dyn_size: free size for dynamic allocation in bytes, -1 for auto
+ * @dyn_size: minimum free size for dynamic allocation in bytes
* @atom_size: allocation atom size
* @cpu_distance_fn: callback to determine distance between cpus, optional
*
@@ -1103,8 +1085,8 @@ void __init pcpu_free_alloc_info(struct pcpu_alloc_info *ai)
* On success, pointer to the new allocation_info is returned. On
* failure, ERR_PTR value is returned.
*/
-struct pcpu_alloc_info * __init pcpu_build_alloc_info(
- size_t reserved_size, ssize_t dyn_size,
+static struct pcpu_alloc_info * __init pcpu_build_alloc_info(
+ size_t reserved_size, size_t dyn_size,
size_t atom_size,
pcpu_fc_cpu_distance_fn_t cpu_distance_fn)
{
@@ -1123,13 +1105,17 @@ struct pcpu_alloc_info * __init pcpu_build_alloc_info(
memset(group_map, 0, sizeof(group_map));
memset(group_cnt, 0, sizeof(group_cnt));
+ /* calculate size_sum and ensure dyn_size is enough for early alloc */
+ size_sum = PFN_ALIGN(static_size + reserved_size +
+ max_t(size_t, dyn_size, PERCPU_DYNAMIC_EARLY_SIZE));
+ dyn_size = size_sum - static_size - reserved_size;
+
/*
* Determine min_unit_size, alloc_size and max_upa such that
* alloc_size is multiple of atom_size and is the smallest
* which can accomodate 4k aligned segments which are equal to
* or larger than min_unit_size.
*/
- size_sum = pcpu_calc_fc_sizes(static_size, reserved_size, &dyn_size);
min_unit_size = max_t(size_t, size_sum, PCPU_MIN_UNIT_SIZE);
alloc_size = roundup(min_unit_size, atom_size);
@@ -1350,7 +1336,8 @@ int __init pcpu_setup_first_chunk(const struct pcpu_alloc_info *ai,
void *base_addr)
{
static char cpus_buf[4096] __initdata;
- static int smap[2], dmap[2];
+ static int smap[PERCPU_DYNAMIC_EARLY_SLOTS] __initdata;
+ static int dmap[PERCPU_DYNAMIC_EARLY_SLOTS] __initdata;
size_t dyn_size = ai->dyn_size;
size_t size_sum = ai->static_size + ai->reserved_size + dyn_size;
struct pcpu_chunk *schunk, *dchunk = NULL;
@@ -1373,14 +1360,13 @@ int __init pcpu_setup_first_chunk(const struct pcpu_alloc_info *ai,
} while (0)
/* sanity checks */
- BUILD_BUG_ON(ARRAY_SIZE(smap) >= PCPU_DFL_MAP_ALLOC ||
- ARRAY_SIZE(dmap) >= PCPU_DFL_MAP_ALLOC);
PCPU_SETUP_BUG_ON(ai->nr_groups <= 0);
PCPU_SETUP_BUG_ON(!ai->static_size);
PCPU_SETUP_BUG_ON(!base_addr);
PCPU_SETUP_BUG_ON(ai->unit_size < size_sum);
PCPU_SETUP_BUG_ON(ai->unit_size & ~PAGE_MASK);
PCPU_SETUP_BUG_ON(ai->unit_size < PCPU_MIN_UNIT_SIZE);
+ PCPU_SETUP_BUG_ON(ai->dyn_size < PERCPU_DYNAMIC_EARLY_SIZE);
PCPU_SETUP_BUG_ON(pcpu_verify_alloc_info(ai) < 0);
/* process group information and build config tables accordingly */
@@ -1532,7 +1518,7 @@ early_param("percpu_alloc", percpu_alloc_setup);
/**
* pcpu_embed_first_chunk - embed the first percpu chunk into bootmem
* @reserved_size: the size of reserved percpu area in bytes
- * @dyn_size: free size for dynamic allocation in bytes, -1 for auto
+ * @dyn_size: minimum free size for dynamic allocation in bytes
* @atom_size: allocation atom size
* @cpu_distance_fn: callback to determine distance between cpus, optional
* @alloc_fn: function to allocate percpu page
@@ -1553,10 +1539,7 @@ early_param("percpu_alloc", percpu_alloc_setup);
* vmalloc space is not orders of magnitude larger than distances
* between node memory addresses (ie. 32bit NUMA machines).
*
- * When @dyn_size is positive, dynamic area might be larger than
- * specified to fill page alignment. When @dyn_size is auto,
- * @dyn_size is just big enough to fill page alignment after static
- * and reserved areas.
+ * @dyn_size specifies the minimum dynamic area size.
*
* If the needed size is smaller than the minimum or specified unit
* size, the leftover is returned using @free_fn.
@@ -1564,7 +1547,7 @@ early_param("percpu_alloc", percpu_alloc_setup);
* RETURNS:
* 0 on success, -errno on failure.
*/
-int __init pcpu_embed_first_chunk(size_t reserved_size, ssize_t dyn_size,
+int __init pcpu_embed_first_chunk(size_t reserved_size, size_t dyn_size,
size_t atom_size,
pcpu_fc_cpu_distance_fn_t cpu_distance_fn,
pcpu_fc_alloc_fn_t alloc_fn,
@@ -1695,7 +1678,7 @@ int __init pcpu_page_first_chunk(size_t reserved_size,
snprintf(psize_str, sizeof(psize_str), "%luK", PAGE_SIZE >> 10);
- ai = pcpu_build_alloc_info(reserved_size, -1, PAGE_SIZE, NULL);
+ ai = pcpu_build_alloc_info(reserved_size, 0, PAGE_SIZE, NULL);
if (IS_ERR(ai))
return PTR_ERR(ai);
BUG_ON(ai->nr_groups != 1);
@@ -1821,3 +1804,33 @@ void __init setup_per_cpu_areas(void)
__per_cpu_offset[cpu] = delta + pcpu_unit_offsets[cpu];
}
#endif /* CONFIG_HAVE_SETUP_PER_CPU_AREA */
+
+/*
+ * First and reserved chunks are initialized with temporary allocation
+ * map in initdata so that they can be used before slab is online.
+ * This function is called after slab is brought up and replaces those
+ * with properly allocated maps.
+ */
+void __init percpu_init_late(void)
+{
+ struct pcpu_chunk *target_chunks[] =
+ { pcpu_first_chunk, pcpu_reserved_chunk, NULL };
+ struct pcpu_chunk *chunk;
+ unsigned long flags;
+ int i;
+
+ for (i = 0; (chunk = target_chunks[i]); i++) {
+ int *map;
+ const size_t size = PERCPU_DYNAMIC_EARLY_SLOTS * sizeof(map[0]);
+
+ BUILD_BUG_ON(size > PAGE_SIZE);
+
+ map = pcpu_mem_alloc(size);
+ BUG_ON(!map);
+
+ spin_lock_irqsave(&pcpu_lock, flags);
+ memcpy(map, chunk->map, size);
+ chunk->map = map;
+ spin_unlock_irqrestore(&pcpu_lock, flags);
+ }
+}
diff --git a/mm/slab.c b/mm/slab.c
index e49f8f46f46..736e497733d 100644
--- a/mm/slab.c
+++ b/mm/slab.c
@@ -102,7 +102,6 @@
#include <linux/cpu.h>
#include <linux/sysctl.h>
#include <linux/module.h>
-#include <linux/kmemtrace.h>
#include <linux/rcupdate.h>
#include <linux/string.h>
#include <linux/uaccess.h>
@@ -861,7 +860,7 @@ static void __cpuinit start_cpu_timer(int cpu)
*/
if (keventd_up() && reap_work->work.func == NULL) {
init_reap_node(cpu);
- INIT_DELAYED_WORK(reap_work, cache_reap);
+ INIT_DELAYED_WORK_DEFERRABLE(reap_work, cache_reap);
schedule_delayed_work_on(cpu, reap_work,
__round_jiffies_relative(HZ, cpu));
}
diff --git a/mm/slob.c b/mm/slob.c
index 23631e2bb57..d582171c810 100644
--- a/mm/slob.c
+++ b/mm/slob.c
@@ -66,8 +66,10 @@
#include <linux/module.h>
#include <linux/rcupdate.h>
#include <linux/list.h>
-#include <linux/kmemtrace.h>
#include <linux/kmemleak.h>
+
+#include <trace/events/kmem.h>
+
#include <asm/atomic.h>
/*
@@ -394,6 +396,7 @@ static void slob_free(void *block, int size)
slob_t *prev, *next, *b = (slob_t *)block;
slobidx_t units;
unsigned long flags;
+ struct list_head *slob_list;
if (unlikely(ZERO_OR_NULL_PTR(block)))
return;
@@ -422,7 +425,13 @@ static void slob_free(void *block, int size)
set_slob(b, units,
(void *)((unsigned long)(b +
SLOB_UNITS(PAGE_SIZE)) & PAGE_MASK));
- set_slob_page_free(sp, &free_slob_small);
+ if (size < SLOB_BREAK1)
+ slob_list = &free_slob_small;
+ else if (size < SLOB_BREAK2)
+ slob_list = &free_slob_medium;
+ else
+ slob_list = &free_slob_large;
+ set_slob_page_free(sp, slob_list);
goto out;
}
@@ -639,7 +648,6 @@ void kmem_cache_free(struct kmem_cache *c, void *b)
if (unlikely(c->flags & SLAB_DESTROY_BY_RCU)) {
struct slob_rcu *slob_rcu;
slob_rcu = b + (c->size - sizeof(struct slob_rcu));
- INIT_RCU_HEAD(&slob_rcu->head);
slob_rcu->size = c->size;
call_rcu(&slob_rcu->head, kmem_rcu_free);
} else {
diff --git a/mm/slub.c b/mm/slub.c
index 578f68f3c51..13fffe1f0f3 100644
--- a/mm/slub.c
+++ b/mm/slub.c
@@ -17,7 +17,6 @@
#include <linux/slab.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
-#include <linux/kmemtrace.h>
#include <linux/kmemcheck.h>
#include <linux/cpu.h>
#include <linux/cpuset.h>
@@ -107,11 +106,17 @@
* the fast path and disables lockless freelists.
*/
+#define SLAB_DEBUG_FLAGS (SLAB_RED_ZONE | SLAB_POISON | SLAB_STORE_USER | \
+ SLAB_TRACE | SLAB_DEBUG_FREE)
+
+static inline int kmem_cache_debug(struct kmem_cache *s)
+{
#ifdef CONFIG_SLUB_DEBUG
-#define SLABDEBUG 1
+ return unlikely(s->flags & SLAB_DEBUG_FLAGS);
#else
-#define SLABDEBUG 0
+ return 0;
#endif
+}
/*
* Issues still to be resolved:
@@ -162,8 +167,8 @@
#define MAX_OBJS_PER_PAGE 65535 /* since page.objects is u16 */
/* Internal SLUB flags */
-#define __OBJECT_POISON 0x80000000 /* Poison object */
-#define __SYSFS_ADD_DEFERRED 0x40000000 /* Not yet visible via sysfs */
+#define __OBJECT_POISON 0x80000000UL /* Poison object */
+#define __SYSFS_ADD_DEFERRED 0x40000000UL /* Not yet visible via sysfs */
static int kmem_size = sizeof(struct kmem_cache);
@@ -1073,7 +1078,7 @@ static inline struct page *alloc_slab_page(gfp_t flags, int node,
flags |= __GFP_NOTRACK;
- if (node == -1)
+ if (node == NUMA_NO_NODE)
return alloc_pages(flags, order);
else
return alloc_pages_exact_node(node, flags, order);
@@ -1157,9 +1162,6 @@ static struct page *new_slab(struct kmem_cache *s, gfp_t flags, int node)
inc_slabs_node(s, page_to_nid(page), page->objects);
page->slab = s;
page->flags |= 1 << PG_slab;
- if (s->flags & (SLAB_DEBUG_FREE | SLAB_RED_ZONE | SLAB_POISON |
- SLAB_STORE_USER | SLAB_TRACE))
- __SetPageSlubDebug(page);
start = page_address(page);
@@ -1186,14 +1188,13 @@ static void __free_slab(struct kmem_cache *s, struct page *page)
int order = compound_order(page);
int pages = 1 << order;
- if (unlikely(SLABDEBUG && PageSlubDebug(page))) {
+ if (kmem_cache_debug(s)) {
void *p;
slab_pad_check(s, page);
for_each_object(p, s, page_address(page),
page->objects)
check_object(s, page, p, 0);
- __ClearPageSlubDebug(page);
}
kmemcheck_free_shadow(page, compound_order(page));
@@ -1387,10 +1388,10 @@ static struct page *get_any_partial(struct kmem_cache *s, gfp_t flags)
static struct page *get_partial(struct kmem_cache *s, gfp_t flags, int node)
{
struct page *page;
- int searchnode = (node == -1) ? numa_node_id() : node;
+ int searchnode = (node == NUMA_NO_NODE) ? numa_node_id() : node;
page = get_partial_node(get_node(s, searchnode));
- if (page || (flags & __GFP_THISNODE))
+ if (page || node != -1)
return page;
return get_any_partial(s, flags);
@@ -1415,8 +1416,7 @@ static void unfreeze_slab(struct kmem_cache *s, struct page *page, int tail)
stat(s, tail ? DEACTIVATE_TO_TAIL : DEACTIVATE_TO_HEAD);
} else {
stat(s, DEACTIVATE_FULL);
- if (SLABDEBUG && PageSlubDebug(page) &&
- (s->flags & SLAB_STORE_USER))
+ if (kmem_cache_debug(s) && (s->flags & SLAB_STORE_USER))
add_full(n, page);
}
slab_unlock(page);
@@ -1515,7 +1515,7 @@ static void flush_all(struct kmem_cache *s)
static inline int node_match(struct kmem_cache_cpu *c, int node)
{
#ifdef CONFIG_NUMA
- if (node != -1 && c->node != node)
+ if (node != NUMA_NO_NODE && c->node != node)
return 0;
#endif
return 1;
@@ -1624,7 +1624,7 @@ load_freelist:
object = c->page->freelist;
if (unlikely(!object))
goto another_slab;
- if (unlikely(SLABDEBUG && PageSlubDebug(c->page)))
+ if (kmem_cache_debug(s))
goto debug;
c->freelist = get_freepointer(s, object);
@@ -1727,7 +1727,7 @@ static __always_inline void *slab_alloc(struct kmem_cache *s,
void *kmem_cache_alloc(struct kmem_cache *s, gfp_t gfpflags)
{
- void *ret = slab_alloc(s, gfpflags, -1, _RET_IP_);
+ void *ret = slab_alloc(s, gfpflags, NUMA_NO_NODE, _RET_IP_);
trace_kmem_cache_alloc(_RET_IP_, ret, s->objsize, s->size, gfpflags);
@@ -1738,7 +1738,7 @@ EXPORT_SYMBOL(kmem_cache_alloc);
#ifdef CONFIG_TRACING
void *kmem_cache_alloc_notrace(struct kmem_cache *s, gfp_t gfpflags)
{
- return slab_alloc(s, gfpflags, -1, _RET_IP_);
+ return slab_alloc(s, gfpflags, NUMA_NO_NODE, _RET_IP_);
}
EXPORT_SYMBOL(kmem_cache_alloc_notrace);
#endif
@@ -1783,7 +1783,7 @@ static void __slab_free(struct kmem_cache *s, struct page *page,
stat(s, FREE_SLOWPATH);
slab_lock(page);
- if (unlikely(SLABDEBUG && PageSlubDebug(page)))
+ if (kmem_cache_debug(s))
goto debug;
checks_ok:
@@ -2490,7 +2490,6 @@ 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)) {
printk(KERN_ERR "SLUB %s: %s called for cache that "
"still has objects.\n", s->name, __func__);
@@ -2499,8 +2498,8 @@ void kmem_cache_destroy(struct kmem_cache *s)
if (s->flags & SLAB_DESTROY_BY_RCU)
rcu_barrier();
sysfs_slab_remove(s);
- } else
- up_write(&slub_lock);
+ }
+ up_write(&slub_lock);
}
EXPORT_SYMBOL(kmem_cache_destroy);
@@ -2728,7 +2727,7 @@ void *__kmalloc(size_t size, gfp_t flags)
if (unlikely(ZERO_OR_NULL_PTR(s)))
return s;
- ret = slab_alloc(s, flags, -1, _RET_IP_);
+ ret = slab_alloc(s, flags, NUMA_NO_NODE, _RET_IP_);
trace_kmalloc(_RET_IP_, ret, size, s->size, flags);
@@ -3118,9 +3117,12 @@ void __init kmem_cache_init(void)
slab_state = UP;
/* Provide the correct kmalloc names now that the caches are up */
- for (i = KMALLOC_SHIFT_LOW; i < SLUB_PAGE_SHIFT; i++)
- kmalloc_caches[i]. name =
- kasprintf(GFP_NOWAIT, "kmalloc-%d", 1 << i);
+ for (i = KMALLOC_SHIFT_LOW; i < SLUB_PAGE_SHIFT; i++) {
+ char *s = kasprintf(GFP_NOWAIT, "kmalloc-%d", 1 << i);
+
+ BUG_ON(!s);
+ kmalloc_caches[i].name = s;
+ }
#ifdef CONFIG_SMP
register_cpu_notifier(&slab_notifier);
@@ -3223,14 +3225,12 @@ 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)) {
- down_write(&slub_lock);
s->refcount--;
- up_write(&slub_lock);
goto err;
}
+ up_write(&slub_lock);
return s;
}
@@ -3239,14 +3239,12 @@ struct kmem_cache *kmem_cache_create(const char *name, size_t size,
if (kmem_cache_open(s, GFP_KERNEL, name,
size, align, flags, ctor)) {
list_add(&s->list, &slab_caches);
- up_write(&slub_lock);
if (sysfs_slab_add(s)) {
- down_write(&slub_lock);
list_del(&s->list);
- up_write(&slub_lock);
kfree(s);
goto err;
}
+ up_write(&slub_lock);
return s;
}
kfree(s);
@@ -3312,7 +3310,7 @@ void *__kmalloc_track_caller(size_t size, gfp_t gfpflags, unsigned long caller)
if (unlikely(ZERO_OR_NULL_PTR(s)))
return s;
- ret = slab_alloc(s, gfpflags, -1, caller);
+ ret = slab_alloc(s, gfpflags, NUMA_NO_NODE, caller);
/* Honor the call site pointer we recieved. */
trace_kmalloc(caller, ret, size, s->size, gfpflags);
@@ -3395,16 +3393,6 @@ static void validate_slab_slab(struct kmem_cache *s, struct page *page,
} else
printk(KERN_INFO "SLUB %s: Skipped busy slab 0x%p\n",
s->name, page);
-
- if (s->flags & DEBUG_DEFAULT_FLAGS) {
- if (!PageSlubDebug(page))
- printk(KERN_ERR "SLUB %s: SlubDebug not set "
- "on slab 0x%p\n", s->name, page);
- } else {
- if (PageSlubDebug(page))
- printk(KERN_ERR "SLUB %s: SlubDebug set on "
- "slab 0x%p\n", s->name, page);
- }
}
static int validate_slab_node(struct kmem_cache *s,
@@ -4504,6 +4492,13 @@ static int sysfs_slab_add(struct kmem_cache *s)
static void sysfs_slab_remove(struct kmem_cache *s)
{
+ if (slab_state < SYSFS)
+ /*
+ * Sysfs has not been setup yet so no need to remove the
+ * cache from sysfs.
+ */
+ return;
+
kobject_uevent(&s->kobj, KOBJ_REMOVE);
kobject_del(&s->kobj);
kobject_put(&s->kobj);
@@ -4549,8 +4544,11 @@ static int __init slab_sysfs_init(void)
struct kmem_cache *s;
int err;
+ down_write(&slub_lock);
+
slab_kset = kset_create_and_add("slab", &slab_uevent_ops, kernel_kobj);
if (!slab_kset) {
+ up_write(&slub_lock);
printk(KERN_ERR "Cannot register slab subsystem.\n");
return -ENOSYS;
}
@@ -4575,6 +4573,7 @@ static int __init slab_sysfs_init(void)
kfree(al);
}
+ up_write(&slub_lock);
resiliency_test();
return 0;
}
diff --git a/mm/vmalloc.c b/mm/vmalloc.c
index ae007462b7f..b7e314b1009 100644
--- a/mm/vmalloc.c
+++ b/mm/vmalloc.c
@@ -2403,7 +2403,7 @@ static int s_show(struct seq_file *m, void *p)
seq_printf(m, " pages=%d", v->nr_pages);
if (v->phys_addr)
- seq_printf(m, " phys=%lx", v->phys_addr);
+ seq_printf(m, " phys=%llx", (unsigned long long)v->phys_addr);
if (v->flags & VM_IOREMAP)
seq_printf(m, " ioremap");
diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c
index 3c1c8c14e92..a2ad1525057 100644
--- a/net/8021q/vlan.c
+++ b/net/8021q/vlan.c
@@ -155,9 +155,10 @@ void unregister_vlan_dev(struct net_device *dev, struct list_head *head)
BUG_ON(!grp);
/* Take it out of our own structures, but be sure to interlock with
- * HW accelerating devices or SW vlan input packet processing.
+ * HW accelerating devices or SW vlan input packet processing if
+ * VLAN is not 0 (leave it there for 802.1p).
*/
- if (real_dev->features & NETIF_F_HW_VLAN_FILTER)
+ if (vlan_id && (real_dev->features & NETIF_F_HW_VLAN_FILTER))
ops->ndo_vlan_rx_kill_vid(real_dev, vlan_id);
grp->nr_vlans--;
@@ -419,6 +420,14 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event,
if (is_vlan_dev(dev))
__vlan_device_event(dev, event);
+ if ((event == NETDEV_UP) &&
+ (dev->features & NETIF_F_HW_VLAN_FILTER) &&
+ dev->netdev_ops->ndo_vlan_rx_add_vid) {
+ pr_info("8021q: adding VLAN 0 to HW filter on device %s\n",
+ dev->name);
+ dev->netdev_ops->ndo_vlan_rx_add_vid(dev, 0);
+ }
+
grp = __vlan_find_group(dev);
if (!grp)
goto out;
diff --git a/net/8021q/vlan.h b/net/8021q/vlan.h
index 6abdcac1b2e..8d9503ad01d 100644
--- a/net/8021q/vlan.h
+++ b/net/8021q/vlan.h
@@ -2,6 +2,7 @@
#define __BEN_VLAN_802_1Q_INC__
#include <linux/if_vlan.h>
+#include <linux/u64_stats_sync.h>
/**
@@ -21,14 +22,16 @@ struct vlan_priority_tci_mapping {
* struct vlan_rx_stats - VLAN percpu rx stats
* @rx_packets: number of received packets
* @rx_bytes: number of received bytes
- * @multicast: number of received multicast packets
+ * @rx_multicast: number of received multicast packets
+ * @syncp: synchronization point for 64bit counters
* @rx_errors: number of errors
*/
struct vlan_rx_stats {
- unsigned long rx_packets;
- unsigned long rx_bytes;
- unsigned long multicast;
- unsigned long rx_errors;
+ u64 rx_packets;
+ u64 rx_bytes;
+ u64 rx_multicast;
+ struct u64_stats_sync syncp;
+ unsigned long rx_errors;
};
/**
diff --git a/net/8021q/vlan_core.c b/net/8021q/vlan_core.c
index 50f58f5f1c3..01ddb0472f8 100644
--- a/net/8021q/vlan_core.c
+++ b/net/8021q/vlan_core.c
@@ -8,6 +8,9 @@
int __vlan_hwaccel_rx(struct sk_buff *skb, struct vlan_group *grp,
u16 vlan_tci, int polling)
{
+ struct net_device *vlan_dev;
+ u16 vlan_id;
+
if (netpoll_rx(skb))
return NET_RX_DROP;
@@ -16,9 +19,12 @@ int __vlan_hwaccel_rx(struct sk_buff *skb, struct vlan_group *grp,
skb->skb_iif = skb->dev->ifindex;
__vlan_hwaccel_put_tag(skb, vlan_tci);
- skb->dev = vlan_group_get_device(grp, vlan_tci & VLAN_VID_MASK);
+ vlan_id = vlan_tci & VLAN_VID_MASK;
+ vlan_dev = vlan_group_get_device(grp, vlan_id);
- if (!skb->dev)
+ if (vlan_dev)
+ skb->dev = vlan_dev;
+ else if (vlan_id)
goto drop;
return (polling ? netif_receive_skb(skb) : netif_rx(skb));
@@ -41,9 +47,9 @@ int vlan_hwaccel_do_receive(struct sk_buff *skb)
skb->priority = vlan_get_ingress_priority(dev, skb->vlan_tci);
skb->vlan_tci = 0;
- rx_stats = per_cpu_ptr(vlan_dev_info(dev)->vlan_rx_stats,
- smp_processor_id());
+ rx_stats = this_cpu_ptr(vlan_dev_info(dev)->vlan_rx_stats);
+ u64_stats_update_begin(&rx_stats->syncp);
rx_stats->rx_packets++;
rx_stats->rx_bytes += skb->len;
@@ -51,7 +57,7 @@ int vlan_hwaccel_do_receive(struct sk_buff *skb)
case PACKET_BROADCAST:
break;
case PACKET_MULTICAST:
- rx_stats->multicast++;
+ rx_stats->rx_multicast++;
break;
case PACKET_OTHERHOST:
/* Our lower layer thinks this is not local, let's make sure.
@@ -62,6 +68,7 @@ int vlan_hwaccel_do_receive(struct sk_buff *skb)
skb->pkt_type = PACKET_HOST;
break;
}
+ u64_stats_update_end(&rx_stats->syncp);
return 0;
}
@@ -82,15 +89,20 @@ vlan_gro_common(struct napi_struct *napi, struct vlan_group *grp,
unsigned int vlan_tci, struct sk_buff *skb)
{
struct sk_buff *p;
+ struct net_device *vlan_dev;
+ u16 vlan_id;
if (skb_bond_should_drop(skb, ACCESS_ONCE(skb->dev->master)))
skb->deliver_no_wcard = 1;
skb->skb_iif = skb->dev->ifindex;
__vlan_hwaccel_put_tag(skb, vlan_tci);
- skb->dev = vlan_group_get_device(grp, vlan_tci & VLAN_VID_MASK);
+ vlan_id = vlan_tci & VLAN_VID_MASK;
+ vlan_dev = vlan_group_get_device(grp, vlan_id);
- if (!skb->dev)
+ if (vlan_dev)
+ skb->dev = vlan_dev;
+ else if (vlan_id)
goto drop;
for (p = napi->gro_list; p; p = p->next) {
diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c
index 52984267781..3d59c9bf8fe 100644
--- a/net/8021q/vlan_dev.c
+++ b/net/8021q/vlan_dev.c
@@ -142,6 +142,7 @@ int vlan_skb_recv(struct sk_buff *skb, struct net_device *dev,
{
struct vlan_hdr *vhdr;
struct vlan_rx_stats *rx_stats;
+ struct net_device *vlan_dev;
u16 vlan_id;
u16 vlan_tci;
@@ -157,53 +158,71 @@ int vlan_skb_recv(struct sk_buff *skb, struct net_device *dev,
vlan_id = vlan_tci & VLAN_VID_MASK;
rcu_read_lock();
- skb->dev = __find_vlan_dev(dev, vlan_id);
- if (!skb->dev) {
- pr_debug("%s: ERROR: No net_device for VID: %u on dev: %s\n",
- __func__, vlan_id, dev->name);
- goto err_unlock;
- }
-
- rx_stats = per_cpu_ptr(vlan_dev_info(skb->dev)->vlan_rx_stats,
- smp_processor_id());
- rx_stats->rx_packets++;
- rx_stats->rx_bytes += skb->len;
-
- skb_pull_rcsum(skb, VLAN_HLEN);
-
- skb->priority = vlan_get_ingress_priority(skb->dev, vlan_tci);
-
- pr_debug("%s: priority: %u for TCI: %hu\n",
- __func__, skb->priority, vlan_tci);
-
- switch (skb->pkt_type) {
- case PACKET_BROADCAST: /* Yeah, stats collect these together.. */
- /* stats->broadcast ++; // no such counter :-( */
- break;
+ vlan_dev = __find_vlan_dev(dev, vlan_id);
- case PACKET_MULTICAST:
- rx_stats->multicast++;
- break;
+ /* If the VLAN device is defined, we use it.
+ * If not, and the VID is 0, it is a 802.1p packet (not
+ * really a VLAN), so we will just netif_rx it later to the
+ * original interface, but with the skb->proto set to the
+ * wrapped proto: we do nothing here.
+ */
- case PACKET_OTHERHOST:
- /* Our lower layer thinks this is not local, let's make sure.
- * This allows the VLAN to have a different MAC than the
- * underlying device, and still route correctly.
- */
- if (!compare_ether_addr(eth_hdr(skb)->h_dest,
- skb->dev->dev_addr))
- skb->pkt_type = PACKET_HOST;
- break;
- default:
- break;
+ if (!vlan_dev) {
+ if (vlan_id) {
+ pr_debug("%s: ERROR: No net_device for VID: %u on dev: %s\n",
+ __func__, vlan_id, dev->name);
+ goto err_unlock;
+ }
+ rx_stats = NULL;
+ } else {
+ skb->dev = vlan_dev;
+
+ rx_stats = per_cpu_ptr(vlan_dev_info(skb->dev)->vlan_rx_stats,
+ smp_processor_id());
+ u64_stats_update_begin(&rx_stats->syncp);
+ rx_stats->rx_packets++;
+ rx_stats->rx_bytes += skb->len;
+
+ skb->priority = vlan_get_ingress_priority(skb->dev, vlan_tci);
+
+ pr_debug("%s: priority: %u for TCI: %hu\n",
+ __func__, skb->priority, vlan_tci);
+
+ switch (skb->pkt_type) {
+ case PACKET_BROADCAST:
+ /* Yeah, stats collect these together.. */
+ /* stats->broadcast ++; // no such counter :-( */
+ break;
+
+ case PACKET_MULTICAST:
+ rx_stats->rx_multicast++;
+ break;
+
+ case PACKET_OTHERHOST:
+ /* Our lower layer thinks this is not local, let's make
+ * sure.
+ * This allows the VLAN to have a different MAC than the
+ * underlying device, and still route correctly.
+ */
+ if (!compare_ether_addr(eth_hdr(skb)->h_dest,
+ skb->dev->dev_addr))
+ skb->pkt_type = PACKET_HOST;
+ break;
+ default:
+ break;
+ }
+ u64_stats_update_end(&rx_stats->syncp);
}
+ skb_pull_rcsum(skb, VLAN_HLEN);
vlan_set_encap_proto(skb, vhdr);
- skb = vlan_check_reorder_header(skb);
- if (!skb) {
- rx_stats->rx_errors++;
- goto err_unlock;
+ if (vlan_dev) {
+ skb = vlan_check_reorder_header(skb);
+ if (!skb) {
+ rx_stats->rx_errors++;
+ goto err_unlock;
+ }
}
netif_rx(skb);
@@ -801,37 +820,65 @@ static u32 vlan_ethtool_get_flags(struct net_device *dev)
return dev_ethtool_get_flags(vlan->real_dev);
}
-static struct net_device_stats *vlan_dev_get_stats(struct net_device *dev)
+static struct rtnl_link_stats64 *vlan_dev_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats)
{
- struct net_device_stats *stats = &dev->stats;
-
dev_txq_stats_fold(dev, stats);
if (vlan_dev_info(dev)->vlan_rx_stats) {
- struct vlan_rx_stats *p, rx = {0};
+ struct vlan_rx_stats *p, accum = {0};
int i;
for_each_possible_cpu(i) {
+ u64 rxpackets, rxbytes, rxmulticast;
+ unsigned int start;
+
p = per_cpu_ptr(vlan_dev_info(dev)->vlan_rx_stats, i);
- rx.rx_packets += p->rx_packets;
- rx.rx_bytes += p->rx_bytes;
- rx.rx_errors += p->rx_errors;
- rx.multicast += p->multicast;
+ do {
+ start = u64_stats_fetch_begin_bh(&p->syncp);
+ rxpackets = p->rx_packets;
+ rxbytes = p->rx_bytes;
+ rxmulticast = p->rx_multicast;
+ } while (u64_stats_fetch_retry_bh(&p->syncp, start));
+ accum.rx_packets += rxpackets;
+ accum.rx_bytes += rxbytes;
+ accum.rx_multicast += rxmulticast;
+ /* rx_errors is an ulong, not protected by syncp */
+ accum.rx_errors += p->rx_errors;
}
- stats->rx_packets = rx.rx_packets;
- stats->rx_bytes = rx.rx_bytes;
- stats->rx_errors = rx.rx_errors;
- stats->multicast = rx.multicast;
+ stats->rx_packets = accum.rx_packets;
+ stats->rx_bytes = accum.rx_bytes;
+ stats->rx_errors = accum.rx_errors;
+ stats->multicast = accum.rx_multicast;
}
return stats;
}
+static int vlan_ethtool_set_tso(struct net_device *dev, u32 data)
+{
+ if (data) {
+ struct net_device *real_dev = vlan_dev_info(dev)->real_dev;
+
+ /* Underlying device must support TSO for VLAN-tagged packets
+ * and must have TSO enabled now.
+ */
+ if (!(real_dev->vlan_features & NETIF_F_TSO))
+ return -EOPNOTSUPP;
+ if (!(real_dev->features & NETIF_F_TSO))
+ return -EINVAL;
+ dev->features |= NETIF_F_TSO;
+ } else {
+ dev->features &= ~NETIF_F_TSO;
+ }
+ return 0;
+}
+
static const struct ethtool_ops vlan_ethtool_ops = {
.get_settings = vlan_ethtool_get_settings,
.get_drvinfo = vlan_ethtool_get_drvinfo,
.get_link = ethtool_op_get_link,
.get_rx_csum = vlan_ethtool_get_rx_csum,
.get_flags = vlan_ethtool_get_flags,
+ .set_tso = vlan_ethtool_set_tso,
};
static const struct net_device_ops vlan_netdev_ops = {
@@ -848,7 +895,7 @@ static const struct net_device_ops vlan_netdev_ops = {
.ndo_change_rx_flags = vlan_dev_change_rx_flags,
.ndo_do_ioctl = vlan_dev_ioctl,
.ndo_neigh_setup = vlan_dev_neigh_setup,
- .ndo_get_stats = vlan_dev_get_stats,
+ .ndo_get_stats64 = vlan_dev_get_stats64,
#if defined(CONFIG_FCOE) || defined(CONFIG_FCOE_MODULE)
.ndo_fcoe_ddp_setup = vlan_dev_fcoe_ddp_setup,
.ndo_fcoe_ddp_done = vlan_dev_fcoe_ddp_done,
@@ -872,7 +919,7 @@ static const struct net_device_ops vlan_netdev_accel_ops = {
.ndo_change_rx_flags = vlan_dev_change_rx_flags,
.ndo_do_ioctl = vlan_dev_ioctl,
.ndo_neigh_setup = vlan_dev_neigh_setup,
- .ndo_get_stats = vlan_dev_get_stats,
+ .ndo_get_stats64 = vlan_dev_get_stats64,
#if defined(CONFIG_FCOE) || defined(CONFIG_FCOE_MODULE)
.ndo_fcoe_ddp_setup = vlan_dev_fcoe_ddp_setup,
.ndo_fcoe_ddp_done = vlan_dev_fcoe_ddp_done,
@@ -897,7 +944,7 @@ static const struct net_device_ops vlan_netdev_ops_sq = {
.ndo_change_rx_flags = vlan_dev_change_rx_flags,
.ndo_do_ioctl = vlan_dev_ioctl,
.ndo_neigh_setup = vlan_dev_neigh_setup,
- .ndo_get_stats = vlan_dev_get_stats,
+ .ndo_get_stats64 = vlan_dev_get_stats64,
#if defined(CONFIG_FCOE) || defined(CONFIG_FCOE_MODULE)
.ndo_fcoe_ddp_setup = vlan_dev_fcoe_ddp_setup,
.ndo_fcoe_ddp_done = vlan_dev_fcoe_ddp_done,
@@ -922,7 +969,7 @@ static const struct net_device_ops vlan_netdev_accel_ops_sq = {
.ndo_change_rx_flags = vlan_dev_change_rx_flags,
.ndo_do_ioctl = vlan_dev_ioctl,
.ndo_neigh_setup = vlan_dev_neigh_setup,
- .ndo_get_stats = vlan_dev_get_stats,
+ .ndo_get_stats64 = vlan_dev_get_stats64,
#if defined(CONFIG_FCOE) || defined(CONFIG_FCOE_MODULE)
.ndo_fcoe_ddp_setup = vlan_dev_fcoe_ddp_setup,
.ndo_fcoe_ddp_done = vlan_dev_fcoe_ddp_done,
diff --git a/net/8021q/vlanproc.c b/net/8021q/vlanproc.c
index afead353e21..80e280f5668 100644
--- a/net/8021q/vlanproc.c
+++ b/net/8021q/vlanproc.c
@@ -278,25 +278,27 @@ static int vlandev_seq_show(struct seq_file *seq, void *offset)
{
struct net_device *vlandev = (struct net_device *) seq->private;
const struct vlan_dev_info *dev_info = vlan_dev_info(vlandev);
- const struct net_device_stats *stats;
+ struct rtnl_link_stats64 temp;
+ const struct rtnl_link_stats64 *stats;
static const char fmt[] = "%30s %12lu\n";
+ static const char fmt64[] = "%30s %12llu\n";
int i;
if (!is_vlan_dev(vlandev))
return 0;
- stats = dev_get_stats(vlandev);
+ stats = dev_get_stats(vlandev, &temp);
seq_printf(seq,
"%s VID: %d REORDER_HDR: %i dev->priv_flags: %hx\n",
vlandev->name, dev_info->vlan_id,
(int)(dev_info->flags & 1), vlandev->priv_flags);
- seq_printf(seq, fmt, "total frames received", stats->rx_packets);
- seq_printf(seq, fmt, "total bytes received", stats->rx_bytes);
- seq_printf(seq, fmt, "Broadcast/Multicast Rcvd", stats->multicast);
+ seq_printf(seq, fmt64, "total frames received", stats->rx_packets);
+ seq_printf(seq, fmt64, "total bytes received", stats->rx_bytes);
+ seq_printf(seq, fmt64, "Broadcast/Multicast Rcvd", stats->multicast);
seq_puts(seq, "\n");
- seq_printf(seq, fmt, "total frames transmitted", stats->tx_packets);
- seq_printf(seq, fmt, "total bytes transmitted", stats->tx_bytes);
+ seq_printf(seq, fmt64, "total frames transmitted", stats->tx_packets);
+ seq_printf(seq, fmt64, "total bytes transmitted", stats->tx_bytes);
seq_printf(seq, fmt, "total headroom inc",
dev_info->cnt_inc_headroom_on_tx);
seq_printf(seq, fmt, "total encap on xmit",
diff --git a/net/9p/client.c b/net/9p/client.c
index 37c8da07a80..dc6f2f26d02 100644
--- a/net/9p/client.c
+++ b/net/9p/client.c
@@ -460,7 +460,8 @@ static int p9_check_errors(struct p9_client *c, struct p9_req_t *req)
return err;
}
- if (p9_is_proto_dotu(c))
+ if (p9_is_proto_dotu(c) ||
+ p9_is_proto_dotl(c))
err = -ecode;
if (!err || !IS_ERR_VALUE(err))
@@ -1015,14 +1016,18 @@ int p9_client_open(struct p9_fid *fid, int mode)
struct p9_qid qid;
int iounit;
- P9_DPRINTK(P9_DEBUG_9P, ">>> TOPEN fid %d mode %d\n", fid->fid, mode);
- err = 0;
clnt = fid->clnt;
+ P9_DPRINTK(P9_DEBUG_9P, ">>> %s fid %d mode %d\n",
+ p9_is_proto_dotl(clnt) ? "TLOPEN" : "TOPEN", fid->fid, mode);
+ err = 0;
if (fid->mode != -1)
return -EINVAL;
- req = p9_client_rpc(clnt, P9_TOPEN, "db", fid->fid, mode);
+ if (p9_is_proto_dotl(clnt))
+ req = p9_client_rpc(clnt, P9_TLOPEN, "dd", fid->fid, mode);
+ else
+ req = p9_client_rpc(clnt, P9_TOPEN, "db", fid->fid, mode);
if (IS_ERR(req)) {
err = PTR_ERR(req);
goto error;
@@ -1034,10 +1039,9 @@ int p9_client_open(struct p9_fid *fid, int mode)
goto free_and_error;
}
- P9_DPRINTK(P9_DEBUG_9P, "<<< ROPEN qid %x.%llx.%x iounit %x\n",
- qid.type,
- (unsigned long long)qid.path,
- qid.version, iounit);
+ P9_DPRINTK(P9_DEBUG_9P, "<<< %s qid %x.%llx.%x iounit %x\n",
+ p9_is_proto_dotl(clnt) ? "RLOPEN" : "ROPEN", qid.type,
+ (unsigned long long)qid.path, qid.version, iounit);
fid->mode = mode;
fid->iounit = iounit;
@@ -1049,6 +1053,50 @@ error:
}
EXPORT_SYMBOL(p9_client_open);
+int p9_client_create_dotl(struct p9_fid *ofid, char *name, u32 flags, u32 mode,
+ gid_t gid, struct p9_qid *qid)
+{
+ int err = 0;
+ struct p9_client *clnt;
+ struct p9_req_t *req;
+ int iounit;
+
+ P9_DPRINTK(P9_DEBUG_9P,
+ ">>> TLCREATE fid %d name %s flags %d mode %d gid %d\n",
+ ofid->fid, name, flags, mode, gid);
+ clnt = ofid->clnt;
+
+ if (ofid->mode != -1)
+ return -EINVAL;
+
+ req = p9_client_rpc(clnt, P9_TLCREATE, "dsddd", ofid->fid, name, flags,
+ mode, gid);
+ if (IS_ERR(req)) {
+ err = PTR_ERR(req);
+ goto error;
+ }
+
+ err = p9pdu_readf(req->rc, clnt->proto_version, "Qd", qid, &iounit);
+ if (err) {
+ p9pdu_dump(1, req->rc);
+ goto free_and_error;
+ }
+
+ P9_DPRINTK(P9_DEBUG_9P, "<<< RLCREATE qid %x.%llx.%x iounit %x\n",
+ qid->type,
+ (unsigned long long)qid->path,
+ qid->version, iounit);
+
+ ofid->mode = mode;
+ ofid->iounit = iounit;
+
+free_and_error:
+ p9_free_req(clnt, req);
+error:
+ return err;
+}
+EXPORT_SYMBOL(p9_client_create_dotl);
+
int p9_client_fcreate(struct p9_fid *fid, char *name, u32 perm, int mode,
char *extension)
{
@@ -1094,6 +1142,59 @@ error:
}
EXPORT_SYMBOL(p9_client_fcreate);
+int p9_client_symlink(struct p9_fid *dfid, char *name, char *symtgt, gid_t gid,
+ struct p9_qid *qid)
+{
+ int err = 0;
+ struct p9_client *clnt;
+ struct p9_req_t *req;
+
+ P9_DPRINTK(P9_DEBUG_9P, ">>> TSYMLINK dfid %d name %s symtgt %s\n",
+ dfid->fid, name, symtgt);
+ clnt = dfid->clnt;
+
+ req = p9_client_rpc(clnt, P9_TSYMLINK, "dssd", dfid->fid, name, symtgt,
+ gid);
+ if (IS_ERR(req)) {
+ err = PTR_ERR(req);
+ goto error;
+ }
+
+ err = p9pdu_readf(req->rc, clnt->proto_version, "Q", qid);
+ if (err) {
+ p9pdu_dump(1, req->rc);
+ goto free_and_error;
+ }
+
+ P9_DPRINTK(P9_DEBUG_9P, "<<< RSYMLINK qid %x.%llx.%x\n",
+ qid->type, (unsigned long long)qid->path, qid->version);
+
+free_and_error:
+ p9_free_req(clnt, req);
+error:
+ return err;
+}
+EXPORT_SYMBOL(p9_client_symlink);
+
+int p9_client_link(struct p9_fid *dfid, struct p9_fid *oldfid, char *newname)
+{
+ struct p9_client *clnt;
+ struct p9_req_t *req;
+
+ P9_DPRINTK(P9_DEBUG_9P, ">>> TLINK dfid %d oldfid %d newname %s\n",
+ dfid->fid, oldfid->fid, newname);
+ clnt = dfid->clnt;
+ req = p9_client_rpc(clnt, P9_TLINK, "dds", dfid->fid, oldfid->fid,
+ newname);
+ if (IS_ERR(req))
+ return PTR_ERR(req);
+
+ P9_DPRINTK(P9_DEBUG_9P, "<<< RLINK\n");
+ p9_free_req(clnt, req);
+ return 0;
+}
+EXPORT_SYMBOL(p9_client_link);
+
int p9_client_clunk(struct p9_fid *fid)
{
int err;
@@ -1139,9 +1240,8 @@ int p9_client_remove(struct p9_fid *fid)
P9_DPRINTK(P9_DEBUG_9P, "<<< RREMOVE fid %d\n", fid->fid);
p9_free_req(clnt, req);
- p9_fid_destroy(fid);
-
error:
+ p9_fid_destroy(fid);
return err;
}
EXPORT_SYMBOL(p9_client_remove);
@@ -1302,6 +1402,65 @@ error:
}
EXPORT_SYMBOL(p9_client_stat);
+struct p9_stat_dotl *p9_client_getattr_dotl(struct p9_fid *fid,
+ u64 request_mask)
+{
+ int err;
+ struct p9_client *clnt;
+ struct p9_stat_dotl *ret = kmalloc(sizeof(struct p9_stat_dotl),
+ GFP_KERNEL);
+ struct p9_req_t *req;
+
+ P9_DPRINTK(P9_DEBUG_9P, ">>> TGETATTR fid %d, request_mask %lld\n",
+ fid->fid, request_mask);
+
+ if (!ret)
+ return ERR_PTR(-ENOMEM);
+
+ err = 0;
+ clnt = fid->clnt;
+
+ req = p9_client_rpc(clnt, P9_TGETATTR, "dq", fid->fid, request_mask);
+ if (IS_ERR(req)) {
+ err = PTR_ERR(req);
+ goto error;
+ }
+
+ err = p9pdu_readf(req->rc, clnt->proto_version, "A", ret);
+ if (err) {
+ p9pdu_dump(1, req->rc);
+ p9_free_req(clnt, req);
+ goto error;
+ }
+
+ P9_DPRINTK(P9_DEBUG_9P,
+ "<<< RGETATTR st_result_mask=%lld\n"
+ "<<< qid=%x.%llx.%x\n"
+ "<<< st_mode=%8.8x st_nlink=%llu\n"
+ "<<< st_uid=%d st_gid=%d\n"
+ "<<< st_rdev=%llx st_size=%llx st_blksize=%llu st_blocks=%llu\n"
+ "<<< st_atime_sec=%lld st_atime_nsec=%lld\n"
+ "<<< st_mtime_sec=%lld st_mtime_nsec=%lld\n"
+ "<<< st_ctime_sec=%lld st_ctime_nsec=%lld\n"
+ "<<< st_btime_sec=%lld st_btime_nsec=%lld\n"
+ "<<< st_gen=%lld st_data_version=%lld",
+ ret->st_result_mask, ret->qid.type, ret->qid.path,
+ ret->qid.version, ret->st_mode, ret->st_nlink, ret->st_uid,
+ ret->st_gid, ret->st_rdev, ret->st_size, ret->st_blksize,
+ ret->st_blocks, ret->st_atime_sec, ret->st_atime_nsec,
+ ret->st_mtime_sec, ret->st_mtime_nsec, ret->st_ctime_sec,
+ ret->st_ctime_nsec, ret->st_btime_sec, ret->st_btime_nsec,
+ ret->st_gen, ret->st_data_version);
+
+ p9_free_req(clnt, req);
+ return ret;
+
+error:
+ kfree(ret);
+ return ERR_PTR(err);
+}
+EXPORT_SYMBOL(p9_client_getattr_dotl);
+
static int p9_client_statsize(struct p9_wstat *wst, int proto_version)
{
int ret;
@@ -1366,6 +1525,36 @@ error:
}
EXPORT_SYMBOL(p9_client_wstat);
+int p9_client_setattr(struct p9_fid *fid, struct p9_iattr_dotl *p9attr)
+{
+ int err;
+ struct p9_req_t *req;
+ struct p9_client *clnt;
+
+ err = 0;
+ clnt = fid->clnt;
+ P9_DPRINTK(P9_DEBUG_9P, ">>> TSETATTR fid %d\n", fid->fid);
+ P9_DPRINTK(P9_DEBUG_9P,
+ " valid=%x mode=%x uid=%d gid=%d size=%lld\n"
+ " atime_sec=%lld atime_nsec=%lld\n"
+ " mtime_sec=%lld mtime_nsec=%lld\n",
+ p9attr->valid, p9attr->mode, p9attr->uid, p9attr->gid,
+ p9attr->size, p9attr->atime_sec, p9attr->atime_nsec,
+ p9attr->mtime_sec, p9attr->mtime_nsec);
+
+ req = p9_client_rpc(clnt, P9_TSETATTR, "dI", fid->fid, p9attr);
+
+ if (IS_ERR(req)) {
+ err = PTR_ERR(req);
+ goto error;
+ }
+ P9_DPRINTK(P9_DEBUG_9P, "<<< RSETATTR fid %d\n", fid->fid);
+ p9_free_req(clnt, req);
+error:
+ return err;
+}
+EXPORT_SYMBOL(p9_client_setattr);
+
int p9_client_statfs(struct p9_fid *fid, struct p9_rstatfs *sb)
{
int err;
@@ -1432,3 +1621,187 @@ error:
}
EXPORT_SYMBOL(p9_client_rename);
+/*
+ * An xattrwalk without @attr_name gives the fid for the lisxattr namespace
+ */
+struct p9_fid *p9_client_xattrwalk(struct p9_fid *file_fid,
+ const char *attr_name, u64 *attr_size)
+{
+ int err;
+ struct p9_req_t *req;
+ struct p9_client *clnt;
+ struct p9_fid *attr_fid;
+
+ err = 0;
+ clnt = file_fid->clnt;
+ attr_fid = p9_fid_create(clnt);
+ if (IS_ERR(attr_fid)) {
+ err = PTR_ERR(attr_fid);
+ attr_fid = NULL;
+ goto error;
+ }
+ P9_DPRINTK(P9_DEBUG_9P,
+ ">>> TXATTRWALK file_fid %d, attr_fid %d name %s\n",
+ file_fid->fid, attr_fid->fid, attr_name);
+
+ req = p9_client_rpc(clnt, P9_TXATTRWALK, "dds",
+ file_fid->fid, attr_fid->fid, attr_name);
+ if (IS_ERR(req)) {
+ err = PTR_ERR(req);
+ goto error;
+ }
+ err = p9pdu_readf(req->rc, clnt->proto_version, "q", attr_size);
+ if (err) {
+ p9pdu_dump(1, req->rc);
+ p9_free_req(clnt, req);
+ goto clunk_fid;
+ }
+ p9_free_req(clnt, req);
+ P9_DPRINTK(P9_DEBUG_9P, "<<< RXATTRWALK fid %d size %llu\n",
+ attr_fid->fid, *attr_size);
+ return attr_fid;
+clunk_fid:
+ p9_client_clunk(attr_fid);
+ attr_fid = NULL;
+error:
+ if (attr_fid && (attr_fid != file_fid))
+ p9_fid_destroy(attr_fid);
+
+ return ERR_PTR(err);
+}
+EXPORT_SYMBOL_GPL(p9_client_xattrwalk);
+
+int p9_client_xattrcreate(struct p9_fid *fid, const char *name,
+ u64 attr_size, int flags)
+{
+ int err;
+ struct p9_req_t *req;
+ struct p9_client *clnt;
+
+ P9_DPRINTK(P9_DEBUG_9P,
+ ">>> TXATTRCREATE fid %d name %s size %lld flag %d\n",
+ fid->fid, name, (long long)attr_size, flags);
+ err = 0;
+ clnt = fid->clnt;
+ req = p9_client_rpc(clnt, P9_TXATTRCREATE, "dsqd",
+ fid->fid, name, attr_size, flags);
+ if (IS_ERR(req)) {
+ err = PTR_ERR(req);
+ goto error;
+ }
+ P9_DPRINTK(P9_DEBUG_9P, "<<< RXATTRCREATE fid %d\n", fid->fid);
+ p9_free_req(clnt, req);
+error:
+ return err;
+}
+EXPORT_SYMBOL_GPL(p9_client_xattrcreate);
+
+int p9_client_readdir(struct p9_fid *fid, char *data, u32 count, u64 offset)
+{
+ int err, rsize, total;
+ struct p9_client *clnt;
+ struct p9_req_t *req;
+ char *dataptr;
+
+ P9_DPRINTK(P9_DEBUG_9P, ">>> TREADDIR fid %d offset %llu count %d\n",
+ fid->fid, (long long unsigned) offset, count);
+
+ err = 0;
+ clnt = fid->clnt;
+ total = 0;
+
+ rsize = fid->iounit;
+ if (!rsize || rsize > clnt->msize-P9_READDIRHDRSZ)
+ rsize = clnt->msize - P9_READDIRHDRSZ;
+
+ if (count < rsize)
+ rsize = count;
+
+ req = p9_client_rpc(clnt, P9_TREADDIR, "dqd", fid->fid, offset, rsize);
+ if (IS_ERR(req)) {
+ err = PTR_ERR(req);
+ goto error;
+ }
+
+ err = p9pdu_readf(req->rc, clnt->proto_version, "D", &count, &dataptr);
+ if (err) {
+ p9pdu_dump(1, req->rc);
+ goto free_and_error;
+ }
+
+ P9_DPRINTK(P9_DEBUG_9P, "<<< RREADDIR count %d\n", count);
+
+ if (data)
+ memmove(data, dataptr, count);
+
+ p9_free_req(clnt, req);
+ return count;
+
+free_and_error:
+ p9_free_req(clnt, req);
+error:
+ return err;
+}
+EXPORT_SYMBOL(p9_client_readdir);
+
+int p9_client_mknod_dotl(struct p9_fid *fid, char *name, int mode,
+ dev_t rdev, gid_t gid, struct p9_qid *qid)
+{
+ int err;
+ struct p9_client *clnt;
+ struct p9_req_t *req;
+
+ err = 0;
+ clnt = fid->clnt;
+ P9_DPRINTK(P9_DEBUG_9P, ">>> TMKNOD fid %d name %s mode %d major %d "
+ "minor %d\n", fid->fid, name, mode, MAJOR(rdev), MINOR(rdev));
+ req = p9_client_rpc(clnt, P9_TMKNOD, "dsdddd", fid->fid, name, mode,
+ MAJOR(rdev), MINOR(rdev), gid);
+ if (IS_ERR(req))
+ return PTR_ERR(req);
+
+ err = p9pdu_readf(req->rc, clnt->proto_version, "Q", qid);
+ if (err) {
+ p9pdu_dump(1, req->rc);
+ goto error;
+ }
+ P9_DPRINTK(P9_DEBUG_9P, "<<< RMKNOD qid %x.%llx.%x\n", qid->type,
+ (unsigned long long)qid->path, qid->version);
+
+error:
+ p9_free_req(clnt, req);
+ return err;
+
+}
+EXPORT_SYMBOL(p9_client_mknod_dotl);
+
+int p9_client_mkdir_dotl(struct p9_fid *fid, char *name, int mode,
+ gid_t gid, struct p9_qid *qid)
+{
+ int err;
+ struct p9_client *clnt;
+ struct p9_req_t *req;
+
+ err = 0;
+ clnt = fid->clnt;
+ P9_DPRINTK(P9_DEBUG_9P, ">>> TMKDIR fid %d name %s mode %d gid %d\n",
+ fid->fid, name, mode, gid);
+ req = p9_client_rpc(clnt, P9_TMKDIR, "dsdd", fid->fid, name, mode,
+ gid);
+ if (IS_ERR(req))
+ return PTR_ERR(req);
+
+ err = p9pdu_readf(req->rc, clnt->proto_version, "Q", qid);
+ if (err) {
+ p9pdu_dump(1, req->rc);
+ goto error;
+ }
+ P9_DPRINTK(P9_DEBUG_9P, "<<< RMKDIR qid %x.%llx.%x\n", qid->type,
+ (unsigned long long)qid->path, qid->version);
+
+error:
+ p9_free_req(clnt, req);
+ return err;
+
+}
+EXPORT_SYMBOL(p9_client_mkdir_dotl);
diff --git a/net/9p/protocol.c b/net/9p/protocol.c
index 149f8216013..3acd3afb20c 100644
--- a/net/9p/protocol.c
+++ b/net/9p/protocol.c
@@ -141,6 +141,7 @@ pdu_write_u(struct p9_fcall *pdu, const char __user *udata, size_t size)
D - data blob (int32_t size followed by void *, results are not freed)
T - array of strings (int16_t count, followed by strings)
R - array of qids (int16_t count, followed by qids)
+ A - stat for 9p2000.L (p9_stat_dotl)
? - if optional = 1, continue parsing
*/
@@ -340,6 +341,33 @@ p9pdu_vreadf(struct p9_fcall *pdu, int proto_version, const char *fmt,
}
}
break;
+ case 'A': {
+ struct p9_stat_dotl *stbuf =
+ va_arg(ap, struct p9_stat_dotl *);
+
+ memset(stbuf, 0, sizeof(struct p9_stat_dotl));
+ errcode =
+ p9pdu_readf(pdu, proto_version,
+ "qQdddqqqqqqqqqqqqqqq",
+ &stbuf->st_result_mask,
+ &stbuf->qid,
+ &stbuf->st_mode,
+ &stbuf->st_uid, &stbuf->st_gid,
+ &stbuf->st_nlink,
+ &stbuf->st_rdev, &stbuf->st_size,
+ &stbuf->st_blksize, &stbuf->st_blocks,
+ &stbuf->st_atime_sec,
+ &stbuf->st_atime_nsec,
+ &stbuf->st_mtime_sec,
+ &stbuf->st_mtime_nsec,
+ &stbuf->st_ctime_sec,
+ &stbuf->st_ctime_nsec,
+ &stbuf->st_btime_sec,
+ &stbuf->st_btime_nsec,
+ &stbuf->st_gen,
+ &stbuf->st_data_version);
+ }
+ break;
case '?':
if ((proto_version != p9_proto_2000u) &&
(proto_version != p9_proto_2000L))
@@ -488,6 +516,23 @@ p9pdu_vwritef(struct p9_fcall *pdu, int proto_version, const char *fmt,
}
}
break;
+ case 'I':{
+ struct p9_iattr_dotl *p9attr = va_arg(ap,
+ struct p9_iattr_dotl *);
+
+ errcode = p9pdu_writef(pdu, proto_version,
+ "ddddqqqqq",
+ p9attr->valid,
+ p9attr->mode,
+ p9attr->uid,
+ p9attr->gid,
+ p9attr->size,
+ p9attr->atime_sec,
+ p9attr->atime_nsec,
+ p9attr->mtime_sec,
+ p9attr->mtime_nsec);
+ }
+ break;
case '?':
if ((proto_version != p9_proto_2000u) &&
(proto_version != p9_proto_2000L))
@@ -580,3 +625,30 @@ void p9pdu_reset(struct p9_fcall *pdu)
pdu->offset = 0;
pdu->size = 0;
}
+
+int p9dirent_read(char *buf, int len, struct p9_dirent *dirent,
+ int proto_version)
+{
+ struct p9_fcall fake_pdu;
+ int ret;
+ char *nameptr;
+
+ fake_pdu.size = len;
+ fake_pdu.capacity = len;
+ fake_pdu.sdata = buf;
+ fake_pdu.offset = 0;
+
+ ret = p9pdu_readf(&fake_pdu, proto_version, "Qqbs", &dirent->qid,
+ &dirent->d_off, &dirent->d_type, &nameptr);
+ if (ret) {
+ P9_DPRINTK(P9_DEBUG_9P, "<<< p9dirent_read failed: %d\n", ret);
+ p9pdu_dump(1, &fake_pdu);
+ goto out;
+ }
+
+ strcpy(dirent->d_name, nameptr);
+
+out:
+ return fake_pdu.offset;
+}
+EXPORT_SYMBOL(p9dirent_read);
diff --git a/net/9p/trans_fd.c b/net/9p/trans_fd.c
index 98ce9bcb0e1..c85109d809c 100644
--- a/net/9p/trans_fd.c
+++ b/net/9p/trans_fd.c
@@ -948,7 +948,7 @@ p9_fd_create_unix(struct p9_client *client, const char *addr, char *args)
csocket = NULL;
- if (strlen(addr) > UNIX_PATH_MAX) {
+ if (strlen(addr) >= UNIX_PATH_MAX) {
P9_EPRINTK(KERN_ERR, "p9_trans_unix: address too long: %s\n",
addr);
return -ENAMETOOLONG;
diff --git a/net/Kconfig b/net/Kconfig
index 0d68b40fc0e..e330594d370 100644
--- a/net/Kconfig
+++ b/net/Kconfig
@@ -32,7 +32,7 @@ config WANT_COMPAT_NETLINK_MESSAGES
config COMPAT_NETLINK_MESSAGES
def_bool y
depends on COMPAT
- depends on WIRELESS_EXT || WANT_COMPAT_NETLINK_MESSAGES
+ depends on WEXT_CORE || WANT_COMPAT_NETLINK_MESSAGES
help
This option makes it possible to send different netlink messages
to tasks depending on whether the task is a compat task or not. To
@@ -86,6 +86,16 @@ config NETWORK_SECMARK
to nfmark, but designated for security purposes.
If you are unsure how to answer this question, answer N.
+config NETWORK_PHY_TIMESTAMPING
+ bool "Timestamping in PHY devices"
+ depends on EXPERIMENTAL
+ help
+ This allows timestamping of network packets by PHYs with
+ hardware timestamping capabilities. This option adds some
+ overhead in the transmit and receive paths.
+
+ If you are unsure how to answer this question, answer N.
+
menuconfig NETFILTER
bool "Network packet filtering framework (Netfilter)"
---help---
@@ -203,6 +213,7 @@ source "net/phonet/Kconfig"
source "net/ieee802154/Kconfig"
source "net/sched/Kconfig"
source "net/dcb/Kconfig"
+source "net/dns_resolver/Kconfig"
config RPS
boolean
diff --git a/net/Makefile b/net/Makefile
index cb7bdc1210c..ea60fbce9b1 100644
--- a/net/Makefile
+++ b/net/Makefile
@@ -50,7 +50,7 @@ endif
obj-$(CONFIG_IP_DCCP) += dccp/
obj-$(CONFIG_IP_SCTP) += sctp/
obj-$(CONFIG_RDS) += rds/
-obj-y += wireless/
+obj-$(CONFIG_WIRELESS) += wireless/
obj-$(CONFIG_MAC80211) += mac80211/
obj-$(CONFIG_TIPC) += tipc/
obj-$(CONFIG_NETLABEL) += netlabel/
@@ -61,9 +61,10 @@ obj-$(CONFIG_CAIF) += caif/
ifneq ($(CONFIG_DCB),)
obj-y += dcb/
endif
-obj-y += ieee802154/
+obj-$(CONFIG_IEEE802154) += ieee802154/
ifeq ($(CONFIG_NET),y)
obj-$(CONFIG_SYSCTL) += sysctl_net.o
endif
obj-$(CONFIG_WIMAX) += wimax/
+obj-$(CONFIG_DNS_RESOLVER) += dns_resolver/
diff --git a/net/atm/br2684.c b/net/atm/br2684.c
index 6719af6a59f..651babdfab3 100644
--- a/net/atm/br2684.c
+++ b/net/atm/br2684.c
@@ -139,6 +139,43 @@ static struct net_device *br2684_find_dev(const struct br2684_if_spec *s)
return NULL;
}
+static int atm_dev_event(struct notifier_block *this, unsigned long event,
+ void *arg)
+{
+ struct atm_dev *atm_dev = arg;
+ struct list_head *lh;
+ struct net_device *net_dev;
+ struct br2684_vcc *brvcc;
+ struct atm_vcc *atm_vcc;
+ unsigned long flags;
+
+ pr_debug("event=%ld dev=%p\n", event, atm_dev);
+
+ read_lock_irqsave(&devs_lock, flags);
+ list_for_each(lh, &br2684_devs) {
+ net_dev = list_entry_brdev(lh);
+
+ list_for_each_entry(brvcc, &BRPRIV(net_dev)->brvccs, brvccs) {
+ atm_vcc = brvcc->atmvcc;
+ if (atm_vcc && brvcc->atmvcc->dev == atm_dev) {
+
+ if (atm_vcc->dev->signal == ATM_PHY_SIG_LOST)
+ netif_carrier_off(net_dev);
+ else
+ netif_carrier_on(net_dev);
+
+ }
+ }
+ }
+ read_unlock_irqrestore(&devs_lock, flags);
+
+ return NOTIFY_DONE;
+}
+
+static struct notifier_block atm_dev_notifier = {
+ .notifier_call = atm_dev_event,
+};
+
/* chained vcc->pop function. Check if we should wake the netif_queue */
static void br2684_pop(struct atm_vcc *vcc, struct sk_buff *skb)
{
@@ -362,6 +399,12 @@ static void br2684_push(struct atm_vcc *atmvcc, struct sk_buff *skb)
unregister_netdev(net_dev);
free_netdev(net_dev);
}
+ read_lock_irq(&devs_lock);
+ if (list_empty(&br2684_devs)) {
+ /* last br2684 device */
+ unregister_atmdevice_notifier(&atm_dev_notifier);
+ }
+ read_unlock_irq(&devs_lock);
return;
}
@@ -530,6 +573,13 @@ static int br2684_regvcc(struct atm_vcc *atmvcc, void __user * arg)
br2684_push(atmvcc, skb);
}
+
+ /* initialize netdev carrier state */
+ if (atmvcc->dev->signal == ATM_PHY_SIG_LOST)
+ netif_carrier_off(net_dev);
+ else
+ netif_carrier_on(net_dev);
+
__module_get(THIS_MODULE);
return 0;
@@ -620,9 +670,16 @@ static int br2684_create(void __user *arg)
}
write_lock_irq(&devs_lock);
+
brdev->payload = payload;
- brdev->number = list_empty(&br2684_devs) ? 1 :
- BRPRIV(list_entry_brdev(br2684_devs.prev))->number + 1;
+
+ if (list_empty(&br2684_devs)) {
+ /* 1st br2684 device */
+ register_atmdevice_notifier(&atm_dev_notifier);
+ brdev->number = 1;
+ } else
+ brdev->number = BRPRIV(list_entry_brdev(br2684_devs.prev))->number + 1;
+
list_add_tail(&brdev->br2684_devs, &br2684_devs);
write_unlock_irq(&devs_lock);
return 0;
@@ -772,6 +829,11 @@ static void __exit br2684_exit(void)
remove_proc_entry("br2684", atm_proc_root);
#endif
+
+ /* if not already empty */
+ if (!list_empty(&br2684_devs))
+ unregister_atmdevice_notifier(&atm_dev_notifier);
+
while (!list_empty(&br2684_devs)) {
net_dev = list_entry_brdev(br2684_devs.next);
brdev = BRPRIV(net_dev);
diff --git a/net/atm/clip.c b/net/atm/clip.c
index 313aba11316..95fdd118506 100644
--- a/net/atm/clip.c
+++ b/net/atm/clip.c
@@ -522,7 +522,7 @@ static int clip_setentry(struct atm_vcc *vcc, __be32 ip)
error = ip_route_output_key(&init_net, &rt, &fl);
if (error)
return error;
- neigh = __neigh_lookup(&clip_tbl, &ip, rt->u.dst.dev, 1);
+ neigh = __neigh_lookup(&clip_tbl, &ip, rt->dst.dev, 1);
ip_rt_put(rt);
if (!neigh)
return -ENOMEM;
diff --git a/net/atm/common.c b/net/atm/common.c
index b43feb1a399..940404a73b3 100644
--- a/net/atm/common.c
+++ b/net/atm/common.c
@@ -37,6 +37,8 @@ EXPORT_SYMBOL(vcc_hash);
DEFINE_RWLOCK(vcc_sklist_lock);
EXPORT_SYMBOL(vcc_sklist_lock);
+static ATOMIC_NOTIFIER_HEAD(atm_dev_notify_chain);
+
static void __vcc_insert_socket(struct sock *sk)
{
struct atm_vcc *vcc = atm_sk(sk);
@@ -212,6 +214,22 @@ void vcc_release_async(struct atm_vcc *vcc, int reply)
}
EXPORT_SYMBOL(vcc_release_async);
+void atm_dev_signal_change(struct atm_dev *dev, char signal)
+{
+ pr_debug("%s signal=%d dev=%p number=%d dev->signal=%d\n",
+ __func__, signal, dev, dev->number, dev->signal);
+
+ /* atm driver sending invalid signal */
+ WARN_ON(signal < ATM_PHY_SIG_LOST || signal > ATM_PHY_SIG_FOUND);
+
+ if (dev->signal == signal)
+ return; /* no change */
+
+ dev->signal = signal;
+
+ atomic_notifier_call_chain(&atm_dev_notify_chain, signal, dev);
+}
+EXPORT_SYMBOL(atm_dev_signal_change);
void atm_dev_release_vccs(struct atm_dev *dev)
{
@@ -781,6 +799,18 @@ int vcc_getsockopt(struct socket *sock, int level, int optname,
return vcc->dev->ops->getsockopt(vcc, level, optname, optval, len);
}
+int register_atmdevice_notifier(struct notifier_block *nb)
+{
+ return atomic_notifier_chain_register(&atm_dev_notify_chain, nb);
+}
+EXPORT_SYMBOL_GPL(register_atmdevice_notifier);
+
+void unregister_atmdevice_notifier(struct notifier_block *nb)
+{
+ atomic_notifier_chain_unregister(&atm_dev_notify_chain, nb);
+}
+EXPORT_SYMBOL_GPL(unregister_atmdevice_notifier);
+
static int __init atm_init(void)
{
int error;
diff --git a/net/bluetooth/Kconfig b/net/bluetooth/Kconfig
index ee3b3049d38..ed371684c13 100644
--- a/net/bluetooth/Kconfig
+++ b/net/bluetooth/Kconfig
@@ -43,19 +43,6 @@ config BT_L2CAP
Say Y here to compile L2CAP support into the kernel or say M to
compile it as module (l2cap).
-config BT_L2CAP_EXT_FEATURES
- bool "L2CAP Extended Features support (EXPERIMENTAL)"
- depends on BT_L2CAP && EXPERIMENTAL
- help
- This option enables the L2CAP Extended Features support. These
- new features include the Enhanced Retransmission and Streaming
- Modes, the Frame Check Sequence (FCS), and Segmentation and
- Reassembly (SAR) for L2CAP packets. They are a required for the
- new Alternate MAC/PHY and the Bluetooth Medical Profile.
-
- You should say N unless you know what you are doing. Note that
- this is in an experimental state yet.
-
config BT_SCO
tristate "SCO links support"
depends on BT
diff --git a/net/bluetooth/bnep/bnep.h b/net/bluetooth/bnep/bnep.h
index 0d9e506f5d5..70672544db8 100644
--- a/net/bluetooth/bnep/bnep.h
+++ b/net/bluetooth/bnep/bnep.h
@@ -86,26 +86,26 @@ struct bnep_setup_conn_req {
__u8 ctrl;
__u8 uuid_size;
__u8 service[0];
-} __attribute__((packed));
+} __packed;
struct bnep_set_filter_req {
__u8 type;
__u8 ctrl;
__be16 len;
__u8 list[0];
-} __attribute__((packed));
+} __packed;
struct bnep_control_rsp {
__u8 type;
__u8 ctrl;
__be16 resp;
-} __attribute__((packed));
+} __packed;
struct bnep_ext_hdr {
__u8 type;
__u8 len;
__u8 data[0];
-} __attribute__((packed));
+} __packed;
/* BNEP ioctl defines */
#define BNEPCONNADD _IOW('B', 200, int)
diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
index 800b6b9fbba..0b1e460fe44 100644
--- a/net/bluetooth/hci_conn.c
+++ b/net/bluetooth/hci_conn.c
@@ -1,6 +1,6 @@
/*
BlueZ - Bluetooth protocol stack for Linux
- Copyright (C) 2000-2001 Qualcomm Incorporated
+ Copyright (c) 2000-2001, 2010, Code Aurora Forum. All rights reserved.
Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
@@ -155,6 +155,27 @@ void hci_setup_sync(struct hci_conn *conn, __u16 handle)
hci_send_cmd(hdev, HCI_OP_SETUP_SYNC_CONN, sizeof(cp), &cp);
}
+/* Device _must_ be locked */
+void hci_sco_setup(struct hci_conn *conn, __u8 status)
+{
+ struct hci_conn *sco = conn->link;
+
+ BT_DBG("%p", conn);
+
+ if (!sco)
+ return;
+
+ if (!status) {
+ if (lmp_esco_capable(conn->hdev))
+ hci_setup_sync(sco, conn->handle);
+ else
+ hci_add_sco(sco, conn->handle);
+ } else {
+ hci_proto_connect_cfm(sco, status);
+ hci_conn_del(sco);
+ }
+}
+
static void hci_conn_timeout(unsigned long arg)
{
struct hci_conn *conn = (void *) arg;
@@ -385,10 +406,13 @@ struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst, __u8
acl->power_save = 1;
hci_conn_enter_active_mode(acl);
- if (lmp_esco_capable(hdev))
- hci_setup_sync(sco, acl->handle);
- else
- hci_add_sco(sco, acl->handle);
+ if (test_bit(HCI_CONN_MODE_CHANGE_PEND, &acl->pend)) {
+ /* defer SCO setup until mode change completed */
+ set_bit(HCI_CONN_SCO_SETUP_PEND, &acl->pend);
+ return sco;
+ }
+
+ hci_sco_setup(acl, 0x00);
}
return sco;
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index 2f768de8701..8303f1c9ef5 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -562,6 +562,7 @@ static int hci_dev_do_close(struct hci_dev *hdev)
hci_dev_lock_bh(hdev);
inquiry_cache_flush(hdev);
hci_conn_hash_flush(hdev);
+ hci_blacklist_clear(hdev);
hci_dev_unlock_bh(hdev);
hci_notify(hdev, HCI_DEV_DOWN);
@@ -913,7 +914,7 @@ 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++)
+ for (i = 0; i < NUM_REASSEMBLY; i++)
hdev->reassembly[i] = NULL;
init_waitqueue_head(&hdev->req_wait_q);
@@ -923,6 +924,8 @@ int hci_register_dev(struct hci_dev *hdev)
hci_conn_hash_init(hdev);
+ INIT_LIST_HEAD(&hdev->blacklist.list);
+
memset(&hdev->stat, 0, sizeof(struct hci_dev_stats));
atomic_set(&hdev->promisc, 0);
@@ -970,7 +973,7 @@ int hci_unregister_dev(struct hci_dev *hdev)
hci_dev_do_close(hdev);
- for (i = 0; i < 3; i++)
+ for (i = 0; i < NUM_REASSEMBLY; i++)
kfree_skb(hdev->reassembly[i]);
hci_notify(hdev, HCI_DEV_UNREG);
@@ -1030,89 +1033,170 @@ int hci_recv_frame(struct sk_buff *skb)
}
EXPORT_SYMBOL(hci_recv_frame);
-/* 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)
+static int hci_reassembly(struct hci_dev *hdev, int type, void *data,
+ int count, __u8 index, gfp_t gfp_mask)
{
- if (type < HCI_ACLDATA_PKT || type > HCI_EVENT_PKT)
+ int len = 0;
+ int hlen = 0;
+ int remain = count;
+ struct sk_buff *skb;
+ struct bt_skb_cb *scb;
+
+ if ((type < HCI_ACLDATA_PKT || type > HCI_EVENT_PKT) ||
+ index >= NUM_REASSEMBLY)
return -EILSEQ;
+ skb = hdev->reassembly[index];
+
+ if (!skb) {
+ switch (type) {
+ case HCI_ACLDATA_PKT:
+ len = HCI_MAX_FRAME_SIZE;
+ hlen = HCI_ACL_HDR_SIZE;
+ break;
+ case HCI_EVENT_PKT:
+ len = HCI_MAX_EVENT_SIZE;
+ hlen = HCI_EVENT_HDR_SIZE;
+ break;
+ case HCI_SCODATA_PKT:
+ len = HCI_MAX_SCO_SIZE;
+ hlen = HCI_SCO_HDR_SIZE;
+ break;
+ }
+
+ skb = bt_skb_alloc(len, gfp_mask);
+ if (!skb)
+ return -ENOMEM;
+
+ scb = (void *) skb->cb;
+ scb->expect = hlen;
+ scb->pkt_type = type;
+
+ skb->dev = (void *) hdev;
+ hdev->reassembly[index] = skb;
+ }
+
while (count) {
- struct sk_buff *skb = __reassembly(hdev, type);
- struct { int expect; } *scb;
- int len = 0;
+ scb = (void *) skb->cb;
+ len = min(scb->expect, (__u16)count);
- if (!skb) {
- /* Start of the frame */
+ memcpy(skb_put(skb, len), data, len);
- 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;
+ count -= len;
+ data += len;
+ scb->expect -= len;
+ remain = count;
- 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;
+ switch (type) {
+ case HCI_EVENT_PKT:
+ if (skb->len == HCI_EVENT_HDR_SIZE) {
+ struct hci_event_hdr *h = hci_event_hdr(skb);
+ scb->expect = h->plen;
+
+ if (skb_tailroom(skb) < scb->expect) {
+ kfree_skb(skb);
+ hdev->reassembly[index] = NULL;
+ return -ENOMEM;
+ }
+ }
+ 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;
+ case HCI_ACLDATA_PKT:
+ if (skb->len == HCI_ACL_HDR_SIZE) {
+ struct hci_acl_hdr *h = hci_acl_hdr(skb);
+ scb->expect = __le16_to_cpu(h->dlen);
+
+ if (skb_tailroom(skb) < scb->expect) {
+ kfree_skb(skb);
+ hdev->reassembly[index] = NULL;
+ return -ENOMEM;
+ }
}
+ break;
- skb = bt_skb_alloc(len, GFP_ATOMIC);
- if (!skb) {
- BT_ERR("%s no memory for packet", hdev->name);
- return -ENOMEM;
+ case HCI_SCODATA_PKT:
+ if (skb->len == HCI_SCO_HDR_SIZE) {
+ struct hci_sco_hdr *h = hci_sco_hdr(skb);
+ scb->expect = h->dlen;
+
+ if (skb_tailroom(skb) < scb->expect) {
+ kfree_skb(skb);
+ hdev->reassembly[index] = NULL;
+ return -ENOMEM;
+ }
}
+ break;
+ }
+
+ if (scb->expect == 0) {
+ /* Complete frame */
- skb->dev = (void *) hdev;
bt_cb(skb)->pkt_type = type;
+ hci_recv_frame(skb);
- __reassembly(hdev, type) = skb;
+ hdev->reassembly[index] = NULL;
+ return remain;
+ }
+ }
- scb = (void *) skb->cb;
- scb->expect = len;
- } else {
- /* Continuation */
+ return remain;
+}
- scb = (void *) skb->cb;
- len = scb->expect;
- }
+int hci_recv_fragment(struct hci_dev *hdev, int type, void *data, int count)
+{
+ int rem = 0;
- len = min(len, count);
+ if (type < HCI_ACLDATA_PKT || type > HCI_EVENT_PKT)
+ return -EILSEQ;
- memcpy(skb_put(skb, len), data, len);
+ while (count) {
+ rem = hci_reassembly(hdev, type, data, count,
+ type - 1, GFP_ATOMIC);
+ if (rem < 0)
+ return rem;
- scb->expect -= len;
+ data += (count - rem);
+ count = rem;
+ };
- if (scb->expect == 0) {
- /* Complete frame */
+ return rem;
+}
+EXPORT_SYMBOL(hci_recv_fragment);
- __reassembly(hdev, type) = NULL;
+#define STREAM_REASSEMBLY 0
- bt_cb(skb)->pkt_type = type;
- hci_recv_frame(skb);
- }
+int hci_recv_stream_fragment(struct hci_dev *hdev, void *data, int count)
+{
+ int type;
+ int rem = 0;
- count -= len; data += len;
- }
+ while (count) {
+ struct sk_buff *skb = hdev->reassembly[STREAM_REASSEMBLY];
- return 0;
+ if (!skb) {
+ struct { char type; } *pkt;
+
+ /* Start of the frame */
+ pkt = data;
+ type = pkt->type;
+
+ data++;
+ count--;
+ } else
+ type = bt_cb(skb)->pkt_type;
+
+ rem = hci_reassembly(hdev, type, data,
+ count, STREAM_REASSEMBLY, GFP_ATOMIC);
+ if (rem < 0)
+ return rem;
+
+ data += (count - rem);
+ count = rem;
+ };
+
+ return rem;
}
-EXPORT_SYMBOL(hci_recv_fragment);
+EXPORT_SYMBOL(hci_recv_stream_fragment);
/* ---- Interface to upper protocols ---- */
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index 786b5de0bac..bfef5bae0b3 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -1,6 +1,6 @@
/*
BlueZ - Bluetooth protocol stack for Linux
- Copyright (C) 2000-2001 Qualcomm Incorporated
+ Copyright (c) 2000-2001, 2010, Code Aurora Forum. All rights reserved.
Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
@@ -584,7 +584,7 @@ static inline void hci_cs_create_conn(struct hci_dev *hdev, __u8 status)
conn->out = 1;
conn->link_mode |= HCI_LM_MASTER;
} else
- BT_ERR("No memmory for new connection");
+ BT_ERR("No memory for new connection");
}
}
@@ -785,9 +785,13 @@ static void hci_cs_sniff_mode(struct hci_dev *hdev, __u8 status)
hci_dev_lock(hdev);
conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(cp->handle));
- if (conn)
+ if (conn) {
clear_bit(HCI_CONN_MODE_CHANGE_PEND, &conn->pend);
+ if (test_and_clear_bit(HCI_CONN_SCO_SETUP_PEND, &conn->pend))
+ hci_sco_setup(conn, status);
+ }
+
hci_dev_unlock(hdev);
}
@@ -808,9 +812,13 @@ static void hci_cs_exit_sniff_mode(struct hci_dev *hdev, __u8 status)
hci_dev_lock(hdev);
conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(cp->handle));
- if (conn)
+ if (conn) {
clear_bit(HCI_CONN_MODE_CHANGE_PEND, &conn->pend);
+ if (test_and_clear_bit(HCI_CONN_SCO_SETUP_PEND, &conn->pend))
+ hci_sco_setup(conn, status);
+ }
+
hci_dev_unlock(hdev);
}
@@ -915,20 +923,8 @@ static inline void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *s
} else
conn->state = BT_CLOSED;
- if (conn->type == ACL_LINK) {
- struct hci_conn *sco = conn->link;
- if (sco) {
- if (!ev->status) {
- if (lmp_esco_capable(hdev))
- hci_setup_sync(sco, conn->handle);
- else
- hci_add_sco(sco, conn->handle);
- } else {
- hci_proto_connect_cfm(sco, ev->status);
- hci_conn_del(sco);
- }
- }
- }
+ if (conn->type == ACL_LINK)
+ hci_sco_setup(conn, ev->status);
if (ev->status) {
hci_proto_connect_cfm(conn, ev->status);
@@ -952,7 +948,7 @@ static inline void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *sk
mask |= hci_proto_connect_ind(hdev, &ev->bdaddr, ev->link_type);
- if (mask & HCI_LM_ACCEPT) {
+ if ((mask & HCI_LM_ACCEPT) && !hci_blacklist_lookup(hdev, &ev->bdaddr)) {
/* Connection accepted */
struct inquiry_entry *ie;
struct hci_conn *conn;
@@ -965,7 +961,7 @@ static inline void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *sk
conn = hci_conn_hash_lookup_ba(hdev, ev->link_type, &ev->bdaddr);
if (!conn) {
if (!(conn = hci_conn_add(hdev, ev->link_type, &ev->bdaddr))) {
- BT_ERR("No memmory for new connection");
+ BT_ERR("No memory for new connection");
hci_dev_unlock(hdev);
return;
}
@@ -1481,6 +1477,9 @@ static inline void hci_mode_change_evt(struct hci_dev *hdev, struct sk_buff *skb
else
conn->power_save = 0;
}
+
+ if (test_and_clear_bit(HCI_CONN_SCO_SETUP_PEND, &conn->pend))
+ hci_sco_setup(conn, ev->status);
}
hci_dev_unlock(hdev);
diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c
index 38f08f6b86f..4f170a59593 100644
--- a/net/bluetooth/hci_sock.c
+++ b/net/bluetooth/hci_sock.c
@@ -165,6 +165,86 @@ static int hci_sock_release(struct socket *sock)
return 0;
}
+struct bdaddr_list *hci_blacklist_lookup(struct hci_dev *hdev, bdaddr_t *bdaddr)
+{
+ struct list_head *p;
+ struct bdaddr_list *blacklist = &hdev->blacklist;
+
+ list_for_each(p, &blacklist->list) {
+ struct bdaddr_list *b;
+
+ b = list_entry(p, struct bdaddr_list, list);
+
+ if (bacmp(bdaddr, &b->bdaddr) == 0)
+ return b;
+ }
+
+ return NULL;
+}
+
+static int hci_blacklist_add(struct hci_dev *hdev, void __user *arg)
+{
+ bdaddr_t bdaddr;
+ struct bdaddr_list *entry;
+
+ if (copy_from_user(&bdaddr, arg, sizeof(bdaddr)))
+ return -EFAULT;
+
+ if (bacmp(&bdaddr, BDADDR_ANY) == 0)
+ return -EBADF;
+
+ if (hci_blacklist_lookup(hdev, &bdaddr))
+ return -EEXIST;
+
+ entry = kzalloc(sizeof(struct bdaddr_list), GFP_KERNEL);
+ if (!entry)
+ return -ENOMEM;
+
+ bacpy(&entry->bdaddr, &bdaddr);
+
+ list_add(&entry->list, &hdev->blacklist.list);
+
+ return 0;
+}
+
+int hci_blacklist_clear(struct hci_dev *hdev)
+{
+ struct list_head *p, *n;
+ struct bdaddr_list *blacklist = &hdev->blacklist;
+
+ list_for_each_safe(p, n, &blacklist->list) {
+ struct bdaddr_list *b;
+
+ b = list_entry(p, struct bdaddr_list, list);
+
+ list_del(p);
+ kfree(b);
+ }
+
+ return 0;
+}
+
+static int hci_blacklist_del(struct hci_dev *hdev, void __user *arg)
+{
+ bdaddr_t bdaddr;
+ struct bdaddr_list *entry;
+
+ if (copy_from_user(&bdaddr, arg, sizeof(bdaddr)))
+ return -EFAULT;
+
+ if (bacmp(&bdaddr, BDADDR_ANY) == 0)
+ return hci_blacklist_clear(hdev);
+
+ entry = hci_blacklist_lookup(hdev, &bdaddr);
+ if (!entry)
+ return -ENOENT;
+
+ list_del(&entry->list);
+ kfree(entry);
+
+ return 0;
+}
+
/* Ioctls that require bound socket */
static inline int hci_sock_bound_ioctl(struct sock *sk, unsigned int cmd, unsigned long arg)
{
@@ -194,6 +274,16 @@ static inline int hci_sock_bound_ioctl(struct sock *sk, unsigned int cmd, unsign
case HCIGETAUTHINFO:
return hci_get_auth_info(hdev, (void __user *) arg);
+ case HCIBLOCKADDR:
+ if (!capable(CAP_NET_ADMIN))
+ return -EACCES;
+ return hci_blacklist_add(hdev, (void __user *) arg);
+
+ case HCIUNBLOCKADDR:
+ if (!capable(CAP_NET_ADMIN))
+ return -EACCES;
+ return hci_blacklist_del(hdev, (void __user *) arg);
+
default:
if (hdev->ioctl)
return hdev->ioctl(hdev, cmd, arg);
diff --git a/net/bluetooth/hci_sysfs.c b/net/bluetooth/hci_sysfs.c
index 463ffa4fe04..ce44c47eeac 100644
--- a/net/bluetooth/hci_sysfs.c
+++ b/net/bluetooth/hci_sysfs.c
@@ -436,6 +436,41 @@ static const struct file_operations inquiry_cache_fops = {
.release = single_release,
};
+static int blacklist_show(struct seq_file *f, void *p)
+{
+ struct hci_dev *hdev = f->private;
+ struct bdaddr_list *blacklist = &hdev->blacklist;
+ struct list_head *l;
+
+ hci_dev_lock_bh(hdev);
+
+ list_for_each(l, &blacklist->list) {
+ struct bdaddr_list *b;
+ bdaddr_t bdaddr;
+
+ b = list_entry(l, struct bdaddr_list, list);
+
+ baswap(&bdaddr, &b->bdaddr);
+
+ seq_printf(f, "%s\n", batostr(&bdaddr));
+ }
+
+ hci_dev_unlock_bh(hdev);
+
+ return 0;
+}
+
+static int blacklist_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, blacklist_show, inode->i_private);
+}
+
+static const struct file_operations blacklist_fops = {
+ .open = blacklist_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
int hci_register_sysfs(struct hci_dev *hdev)
{
struct device *dev = &hdev->dev;
@@ -465,6 +500,9 @@ int hci_register_sysfs(struct hci_dev *hdev)
debugfs_create_file("inquiry_cache", 0444, hdev->debugfs,
hdev, &inquiry_cache_fops);
+ debugfs_create_file("blacklist", 0444, hdev->debugfs,
+ hdev, &blacklist_fops);
+
return 0;
}
diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c
index cf3c4073a8a..9ba1e8eee37 100644
--- a/net/bluetooth/l2cap.c
+++ b/net/bluetooth/l2cap.c
@@ -1,6 +1,8 @@
/*
BlueZ - Bluetooth protocol stack for Linux
Copyright (C) 2000-2001 Qualcomm Incorporated
+ Copyright (C) 2009-2010 Gustavo F. Padovan <gustavo@padovan.org>
+ Copyright (C) 2010 Google Inc.
Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
@@ -53,15 +55,9 @@
#include <net/bluetooth/hci_core.h>
#include <net/bluetooth/l2cap.h>
-#define VERSION "2.14"
+#define VERSION "2.15"
-#ifdef CONFIG_BT_L2CAP_EXT_FEATURES
-static int enable_ertm = 1;
-#else
-static int enable_ertm = 0;
-#endif
-static int max_transmit = L2CAP_DEFAULT_MAX_TX;
-static int tx_window = L2CAP_DEFAULT_TX_WINDOW;
+static int disable_ertm = 0;
static u32 l2cap_feat_mask = L2CAP_FEAT_FIXED_CHAN;
static u8 l2cap_fixed_chan[8] = { 0x02, };
@@ -80,9 +76,12 @@ static void __l2cap_sock_close(struct sock *sk, int reason);
static void l2cap_sock_close(struct sock *sk);
static void l2cap_sock_kill(struct sock *sk);
+static int l2cap_build_conf_req(struct sock *sk, void *data);
static struct sk_buff *l2cap_build_cmd(struct l2cap_conn *conn,
u8 code, u8 ident, u16 dlen, void *data);
+static int l2cap_ertm_data_rcv(struct sock *sk, struct sk_buff *skb);
+
/* ---- L2CAP timers ---- */
static void l2cap_sock_timeout(unsigned long arg)
{
@@ -278,6 +277,24 @@ static void l2cap_chan_del(struct sock *sk, int err)
parent->sk_data_ready(parent, 0);
} else
sk->sk_state_change(sk);
+
+ skb_queue_purge(TX_QUEUE(sk));
+
+ if (l2cap_pi(sk)->mode == L2CAP_MODE_ERTM) {
+ struct srej_list *l, *tmp;
+
+ del_timer(&l2cap_pi(sk)->retrans_timer);
+ del_timer(&l2cap_pi(sk)->monitor_timer);
+ del_timer(&l2cap_pi(sk)->ack_timer);
+
+ skb_queue_purge(SREJ_QUEUE(sk));
+ skb_queue_purge(BUSY_QUEUE(sk));
+
+ list_for_each_entry_safe(l, tmp, SREJ_LIST(sk), list) {
+ list_del(&l->list);
+ kfree(l);
+ }
+ }
}
/* Service level security */
@@ -351,8 +368,12 @@ static inline void l2cap_send_sframe(struct l2cap_pinfo *pi, u16 control)
struct sk_buff *skb;
struct l2cap_hdr *lh;
struct l2cap_conn *conn = pi->conn;
+ struct sock *sk = (struct sock *)pi;
int count, hlen = L2CAP_HDR_SIZE + 2;
+ if (sk->sk_state != BT_CONNECTED)
+ return;
+
if (pi->fcs == L2CAP_FCS_CRC16)
hlen += 2;
@@ -440,24 +461,57 @@ static void l2cap_do_start(struct sock *sk)
}
}
-static void l2cap_send_disconn_req(struct l2cap_conn *conn, struct sock *sk)
+static inline int l2cap_mode_supported(__u8 mode, __u32 feat_mask)
+{
+ u32 local_feat_mask = l2cap_feat_mask;
+ if (!disable_ertm)
+ local_feat_mask |= L2CAP_FEAT_ERTM | L2CAP_FEAT_STREAMING;
+
+ switch (mode) {
+ case L2CAP_MODE_ERTM:
+ return L2CAP_FEAT_ERTM & feat_mask & local_feat_mask;
+ case L2CAP_MODE_STREAMING:
+ return L2CAP_FEAT_STREAMING & feat_mask & local_feat_mask;
+ default:
+ return 0x00;
+ }
+}
+
+static void l2cap_send_disconn_req(struct l2cap_conn *conn, struct sock *sk, int err)
{
struct l2cap_disconn_req req;
+ if (!conn)
+ return;
+
+ skb_queue_purge(TX_QUEUE(sk));
+
+ if (l2cap_pi(sk)->mode == L2CAP_MODE_ERTM) {
+ del_timer(&l2cap_pi(sk)->retrans_timer);
+ del_timer(&l2cap_pi(sk)->monitor_timer);
+ del_timer(&l2cap_pi(sk)->ack_timer);
+ }
+
req.dcid = cpu_to_le16(l2cap_pi(sk)->dcid);
req.scid = cpu_to_le16(l2cap_pi(sk)->scid);
l2cap_send_cmd(conn, l2cap_get_ident(conn),
L2CAP_DISCONN_REQ, sizeof(req), &req);
+
+ sk->sk_state = BT_DISCONN;
+ sk->sk_err = err;
}
/* ---- L2CAP connections ---- */
static void l2cap_conn_start(struct l2cap_conn *conn)
{
struct l2cap_chan_list *l = &conn->chan_list;
+ struct sock_del_list del, *tmp1, *tmp2;
struct sock *sk;
BT_DBG("conn %p", conn);
+ INIT_LIST_HEAD(&del.list);
+
read_lock(&l->lock);
for (sk = l->head; sk; sk = l2cap_pi(sk)->next_c) {
@@ -470,20 +524,38 @@ static void l2cap_conn_start(struct l2cap_conn *conn)
}
if (sk->sk_state == BT_CONNECT) {
- if (l2cap_check_security(sk) &&
- __l2cap_no_conn_pending(sk)) {
- struct l2cap_conn_req req;
- req.scid = cpu_to_le16(l2cap_pi(sk)->scid);
- req.psm = l2cap_pi(sk)->psm;
+ struct l2cap_conn_req req;
- l2cap_pi(sk)->ident = l2cap_get_ident(conn);
- l2cap_pi(sk)->conf_state |= L2CAP_CONF_CONNECT_PEND;
+ if (!l2cap_check_security(sk) ||
+ !__l2cap_no_conn_pending(sk)) {
+ bh_unlock_sock(sk);
+ continue;
+ }
- l2cap_send_cmd(conn, l2cap_pi(sk)->ident,
- L2CAP_CONN_REQ, sizeof(req), &req);
+ if (!l2cap_mode_supported(l2cap_pi(sk)->mode,
+ conn->feat_mask)
+ && l2cap_pi(sk)->conf_state &
+ L2CAP_CONF_STATE2_DEVICE) {
+ tmp1 = kzalloc(sizeof(struct sock_del_list),
+ GFP_ATOMIC);
+ tmp1->sk = sk;
+ list_add_tail(&tmp1->list, &del.list);
+ bh_unlock_sock(sk);
+ continue;
}
+
+ req.scid = cpu_to_le16(l2cap_pi(sk)->scid);
+ req.psm = l2cap_pi(sk)->psm;
+
+ l2cap_pi(sk)->ident = l2cap_get_ident(conn);
+ l2cap_pi(sk)->conf_state |= L2CAP_CONF_CONNECT_PEND;
+
+ l2cap_send_cmd(conn, l2cap_pi(sk)->ident,
+ L2CAP_CONN_REQ, sizeof(req), &req);
+
} else if (sk->sk_state == BT_CONNECT2) {
struct l2cap_conn_rsp rsp;
+ char buf[128];
rsp.scid = cpu_to_le16(l2cap_pi(sk)->dcid);
rsp.dcid = cpu_to_le16(l2cap_pi(sk)->scid);
@@ -506,12 +578,31 @@ static void l2cap_conn_start(struct l2cap_conn *conn)
l2cap_send_cmd(conn, l2cap_pi(sk)->ident,
L2CAP_CONN_RSP, sizeof(rsp), &rsp);
+
+ if (l2cap_pi(sk)->conf_state & L2CAP_CONF_REQ_SENT ||
+ rsp.result != L2CAP_CR_SUCCESS) {
+ bh_unlock_sock(sk);
+ continue;
+ }
+
+ l2cap_pi(sk)->conf_state |= L2CAP_CONF_REQ_SENT;
+ l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
+ l2cap_build_conf_req(sk, buf), buf);
+ l2cap_pi(sk)->num_conf_req++;
}
bh_unlock_sock(sk);
}
read_unlock(&l->lock);
+
+ list_for_each_entry_safe(tmp1, tmp2, &del.list, list) {
+ bh_lock_sock(tmp1->sk);
+ __l2cap_sock_close(tmp1->sk, ECONNRESET);
+ bh_unlock_sock(tmp1->sk);
+ list_del(&tmp1->list);
+ kfree(tmp1);
+ }
}
static void l2cap_conn_ready(struct l2cap_conn *conn)
@@ -740,9 +831,8 @@ static void __l2cap_sock_close(struct sock *sk, int reason)
sk->sk_type == SOCK_STREAM) {
struct l2cap_conn *conn = l2cap_pi(sk)->conn;
- sk->sk_state = BT_DISCONN;
l2cap_sock_set_timer(sk, sk->sk_sndtimeo);
- l2cap_send_disconn_req(conn, sk);
+ l2cap_send_disconn_req(conn, sk, reason);
} else
l2cap_chan_del(sk, reason);
break;
@@ -802,6 +892,7 @@ static void l2cap_sock_init(struct sock *sk, struct sock *parent)
pi->imtu = l2cap_pi(parent)->imtu;
pi->omtu = l2cap_pi(parent)->omtu;
+ pi->conf_state = l2cap_pi(parent)->conf_state;
pi->mode = l2cap_pi(parent)->mode;
pi->fcs = l2cap_pi(parent)->fcs;
pi->max_tx = l2cap_pi(parent)->max_tx;
@@ -812,13 +903,15 @@ static void l2cap_sock_init(struct sock *sk, struct sock *parent)
} else {
pi->imtu = L2CAP_DEFAULT_MTU;
pi->omtu = 0;
- if (enable_ertm && sk->sk_type == SOCK_STREAM)
+ if (!disable_ertm && sk->sk_type == SOCK_STREAM) {
pi->mode = L2CAP_MODE_ERTM;
- else
+ pi->conf_state |= L2CAP_CONF_STATE2_DEVICE;
+ } else {
pi->mode = L2CAP_MODE_BASIC;
- pi->max_tx = max_transmit;
+ }
+ pi->max_tx = L2CAP_DEFAULT_MAX_TX;
pi->fcs = L2CAP_FCS_CRC16;
- pi->tx_win = tx_window;
+ pi->tx_win = L2CAP_DEFAULT_TX_WINDOW;
pi->sec_level = BT_SECURITY_LOW;
pi->role_switch = 0;
pi->force_reliable = 0;
@@ -1067,7 +1160,7 @@ static int l2cap_sock_connect(struct socket *sock, struct sockaddr *addr, int al
break;
case L2CAP_MODE_ERTM:
case L2CAP_MODE_STREAMING:
- if (enable_ertm)
+ if (!disable_ertm)
break;
/* fall through */
default:
@@ -1084,6 +1177,7 @@ static int l2cap_sock_connect(struct socket *sock, struct sockaddr *addr, int al
case BT_CONNECTED:
/* Already connected */
+ err = -EISCONN;
goto done;
case BT_OPEN:
@@ -1132,7 +1226,7 @@ static int l2cap_sock_listen(struct socket *sock, int backlog)
break;
case L2CAP_MODE_ERTM:
case L2CAP_MODE_STREAMING:
- if (enable_ertm)
+ if (!disable_ertm)
break;
/* fall through */
default:
@@ -1285,9 +1379,11 @@ static void l2cap_monitor_timeout(unsigned long arg)
{
struct sock *sk = (void *) arg;
+ BT_DBG("sk %p", sk);
+
bh_lock_sock(sk);
if (l2cap_pi(sk)->retry_count >= l2cap_pi(sk)->remote_max_tx) {
- l2cap_send_disconn_req(l2cap_pi(sk)->conn, sk);
+ l2cap_send_disconn_req(l2cap_pi(sk)->conn, sk, ECONNABORTED);
bh_unlock_sock(sk);
return;
}
@@ -1303,6 +1399,8 @@ static void l2cap_retrans_timeout(unsigned long arg)
{
struct sock *sk = (void *) arg;
+ BT_DBG("sk %p", sk);
+
bh_lock_sock(sk);
l2cap_pi(sk)->retry_count = 1;
__mod_monitor_timer();
@@ -1341,7 +1439,7 @@ static inline void l2cap_do_send(struct sock *sk, struct sk_buff *skb)
hci_send_acl(pi->conn->hcon, skb, 0);
}
-static int l2cap_streaming_send(struct sock *sk)
+static void l2cap_streaming_send(struct sock *sk)
{
struct sk_buff *skb, *tx_skb;
struct l2cap_pinfo *pi = l2cap_pi(sk);
@@ -1371,7 +1469,6 @@ static int l2cap_streaming_send(struct sock *sk)
skb = skb_dequeue(TX_QUEUE(sk));
kfree_skb(skb);
}
- return 0;
}
static void l2cap_retransmit_one_frame(struct sock *sk, u8 tx_seq)
@@ -1395,15 +1492,22 @@ static void l2cap_retransmit_one_frame(struct sock *sk, u8 tx_seq)
if (pi->remote_max_tx &&
bt_cb(skb)->retries == pi->remote_max_tx) {
- l2cap_send_disconn_req(pi->conn, sk);
+ l2cap_send_disconn_req(pi->conn, sk, ECONNABORTED);
return;
}
tx_skb = skb_clone(skb, GFP_ATOMIC);
bt_cb(skb)->retries++;
control = get_unaligned_le16(tx_skb->data + L2CAP_HDR_SIZE);
+
+ if (pi->conn_state & L2CAP_CONN_SEND_FBIT) {
+ control |= L2CAP_CTRL_FINAL;
+ pi->conn_state &= ~L2CAP_CONN_SEND_FBIT;
+ }
+
control |= (pi->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT)
| (tx_seq << L2CAP_CTRL_TXSEQ_SHIFT);
+
put_unaligned_le16(control, tx_skb->data + L2CAP_HDR_SIZE);
if (pi->fcs == L2CAP_FCS_CRC16) {
@@ -1421,15 +1525,14 @@ static int l2cap_ertm_send(struct sock *sk)
u16 control, fcs;
int nsent = 0;
- if (pi->conn_state & L2CAP_CONN_WAIT_F)
- return 0;
+ if (sk->sk_state != BT_CONNECTED)
+ return -ENOTCONN;
- while ((skb = sk->sk_send_head) && (!l2cap_tx_window_full(sk)) &&
- !(pi->conn_state & L2CAP_CONN_REMOTE_BUSY)) {
+ while ((skb = sk->sk_send_head) && (!l2cap_tx_window_full(sk))) {
if (pi->remote_max_tx &&
bt_cb(skb)->retries == pi->remote_max_tx) {
- l2cap_send_disconn_req(pi->conn, sk);
+ l2cap_send_disconn_req(pi->conn, sk, ECONNABORTED);
break;
}
@@ -1438,6 +1541,8 @@ static int l2cap_ertm_send(struct sock *sk)
bt_cb(skb)->retries++;
control = get_unaligned_le16(tx_skb->data + L2CAP_HDR_SIZE);
+ control &= L2CAP_CTRL_SAR;
+
if (pi->conn_state & L2CAP_CONN_SEND_FBIT) {
control |= L2CAP_CTRL_FINAL;
pi->conn_state &= ~L2CAP_CONN_SEND_FBIT;
@@ -1478,16 +1583,11 @@ static int l2cap_retransmit_frames(struct sock *sk)
struct l2cap_pinfo *pi = l2cap_pi(sk);
int ret;
- spin_lock_bh(&pi->send_lock);
-
if (!skb_queue_empty(TX_QUEUE(sk)))
sk->sk_send_head = TX_QUEUE(sk)->next;
pi->next_tx_seq = pi->expected_ack_seq;
ret = l2cap_ertm_send(sk);
-
- spin_unlock_bh(&pi->send_lock);
-
return ret;
}
@@ -1495,7 +1595,6 @@ static void l2cap_send_ack(struct l2cap_pinfo *pi)
{
struct sock *sk = (struct sock *)pi;
u16 control = 0;
- int nframes;
control |= pi->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT;
@@ -1506,11 +1605,7 @@ static void l2cap_send_ack(struct l2cap_pinfo *pi)
return;
}
- spin_lock_bh(&pi->send_lock);
- nframes = l2cap_ertm_send(sk);
- spin_unlock_bh(&pi->send_lock);
-
- if (nframes > 0)
+ if (l2cap_ertm_send(sk) > 0)
return;
control |= L2CAP_SUPER_RCV_READY;
@@ -1705,10 +1800,8 @@ static inline int l2cap_sar_segment_sdu(struct sock *sk, struct msghdr *msg, siz
size += buflen;
}
skb_queue_splice_tail(&sar_queue, TX_QUEUE(sk));
- spin_lock_bh(&pi->send_lock);
if (sk->sk_send_head == NULL)
sk->sk_send_head = sar_queue.next;
- spin_unlock_bh(&pi->send_lock);
return size;
}
@@ -1753,7 +1846,7 @@ static int l2cap_sock_sendmsg(struct kiocb *iocb, struct socket *sock, struct ms
case L2CAP_MODE_BASIC:
/* Check outgoing MTU */
if (len > pi->omtu) {
- err = -EINVAL;
+ err = -EMSGSIZE;
goto done;
}
@@ -1780,14 +1873,9 @@ static int l2cap_sock_sendmsg(struct kiocb *iocb, struct socket *sock, struct ms
}
__skb_queue_tail(TX_QUEUE(sk), skb);
- if (pi->mode == L2CAP_MODE_ERTM)
- spin_lock_bh(&pi->send_lock);
-
if (sk->sk_send_head == NULL)
sk->sk_send_head = skb;
- if (pi->mode == L2CAP_MODE_ERTM)
- spin_unlock_bh(&pi->send_lock);
} else {
/* Segment SDU into multiples PDUs */
err = l2cap_sar_segment_sdu(sk, msg, len);
@@ -1796,11 +1884,14 @@ static int l2cap_sock_sendmsg(struct kiocb *iocb, struct socket *sock, struct ms
}
if (pi->mode == L2CAP_MODE_STREAMING) {
- err = l2cap_streaming_send(sk);
+ l2cap_streaming_send(sk);
} else {
- spin_lock_bh(&pi->send_lock);
+ if (pi->conn_state & L2CAP_CONN_REMOTE_BUSY &&
+ pi->conn_state && L2CAP_CONN_WAIT_F) {
+ err = len;
+ break;
+ }
err = l2cap_ertm_send(sk);
- spin_unlock_bh(&pi->send_lock);
}
if (err >= 0)
@@ -1809,7 +1900,7 @@ static int l2cap_sock_sendmsg(struct kiocb *iocb, struct socket *sock, struct ms
default:
BT_DBG("bad state %1.1x", pi->mode);
- err = -EINVAL;
+ err = -EBADFD;
}
done:
@@ -1825,6 +1916,8 @@ static int l2cap_sock_recvmsg(struct kiocb *iocb, struct socket *sock, struct ms
if (sk->sk_state == BT_CONNECT2 && bt_sk(sk)->defer_setup) {
struct l2cap_conn_rsp rsp;
+ struct l2cap_conn *conn = l2cap_pi(sk)->conn;
+ u8 buf[128];
sk->sk_state = BT_CONFIG;
@@ -1835,6 +1928,16 @@ static int l2cap_sock_recvmsg(struct kiocb *iocb, struct socket *sock, struct ms
l2cap_send_cmd(l2cap_pi(sk)->conn, l2cap_pi(sk)->ident,
L2CAP_CONN_RSP, sizeof(rsp), &rsp);
+ if (l2cap_pi(sk)->conf_state & L2CAP_CONF_REQ_SENT) {
+ release_sock(sk);
+ return 0;
+ }
+
+ l2cap_pi(sk)->conf_state |= L2CAP_CONF_REQ_SENT;
+ l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
+ l2cap_build_conf_req(sk, buf), buf);
+ l2cap_pi(sk)->num_conf_req++;
+
release_sock(sk);
return 0;
}
@@ -1871,13 +1974,19 @@ static int l2cap_sock_setsockopt_old(struct socket *sock, int optname, char __us
break;
}
+ if (opts.txwin_size > L2CAP_DEFAULT_TX_WINDOW) {
+ err = -EINVAL;
+ break;
+ }
+
l2cap_pi(sk)->mode = opts.mode;
switch (l2cap_pi(sk)->mode) {
case L2CAP_MODE_BASIC:
+ l2cap_pi(sk)->conf_state &= ~L2CAP_CONF_STATE2_DEVICE;
break;
case L2CAP_MODE_ERTM:
case L2CAP_MODE_STREAMING:
- if (enable_ertm)
+ if (!disable_ertm)
break;
/* fall through */
default:
@@ -2145,6 +2254,10 @@ static int l2cap_sock_shutdown(struct socket *sock, int how)
err = bt_sock_wait_state(sk, BT_CLOSED,
sk->sk_lingertime);
}
+
+ if (!err && sk->sk_err)
+ err = -sk->sk_err;
+
release_sock(sk);
return err;
}
@@ -2365,25 +2478,10 @@ static inline void l2cap_ertm_init(struct sock *sk)
__skb_queue_head_init(SREJ_QUEUE(sk));
__skb_queue_head_init(BUSY_QUEUE(sk));
- spin_lock_init(&l2cap_pi(sk)->send_lock);
INIT_WORK(&l2cap_pi(sk)->busy_work, l2cap_busy_work);
-}
-static int l2cap_mode_supported(__u8 mode, __u32 feat_mask)
-{
- u32 local_feat_mask = l2cap_feat_mask;
- if (enable_ertm)
- local_feat_mask |= L2CAP_FEAT_ERTM | L2CAP_FEAT_STREAMING;
-
- switch (mode) {
- case L2CAP_MODE_ERTM:
- return L2CAP_FEAT_ERTM & feat_mask & local_feat_mask;
- case L2CAP_MODE_STREAMING:
- return L2CAP_FEAT_STREAMING & feat_mask & local_feat_mask;
- default:
- return 0x00;
- }
+ sk->sk_backlog_rcv = l2cap_ertm_data_rcv;
}
static inline __u8 l2cap_select_mode(__u8 mode, __u16 remote_feat_mask)
@@ -2414,10 +2512,10 @@ static int l2cap_build_conf_req(struct sock *sk, void *data)
switch (pi->mode) {
case L2CAP_MODE_STREAMING:
case L2CAP_MODE_ERTM:
- pi->conf_state |= L2CAP_CONF_STATE2_DEVICE;
- if (!l2cap_mode_supported(pi->mode, pi->conn->feat_mask))
- l2cap_send_disconn_req(pi->conn, sk);
- break;
+ if (pi->conf_state & L2CAP_CONF_STATE2_DEVICE)
+ break;
+
+ /* fall through */
default:
pi->mode = l2cap_select_mode(rfc.mode, pi->conn->feat_mask);
break;
@@ -2428,6 +2526,14 @@ done:
case L2CAP_MODE_BASIC:
if (pi->imtu != L2CAP_DEFAULT_MTU)
l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, pi->imtu);
+
+ rfc.mode = L2CAP_MODE_BASIC;
+ rfc.txwin_size = 0;
+ rfc.max_transmit = 0;
+ rfc.retrans_timeout = 0;
+ rfc.monitor_timeout = 0;
+ rfc.max_pdu_size = 0;
+
break;
case L2CAP_MODE_ERTM:
@@ -2440,9 +2546,6 @@ done:
if (L2CAP_DEFAULT_MAX_PDU_SIZE > pi->conn->mtu - 10)
rfc.max_pdu_size = cpu_to_le16(pi->conn->mtu - 10);
- l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
- sizeof(rfc), (unsigned long) &rfc);
-
if (!(pi->conn->feat_mask & L2CAP_FEAT_FCS))
break;
@@ -2463,9 +2566,6 @@ done:
if (L2CAP_DEFAULT_MAX_PDU_SIZE > pi->conn->mtu - 10)
rfc.max_pdu_size = cpu_to_le16(pi->conn->mtu - 10);
- l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
- sizeof(rfc), (unsigned long) &rfc);
-
if (!(pi->conn->feat_mask & L2CAP_FEAT_FCS))
break;
@@ -2477,6 +2577,9 @@ done:
break;
}
+ l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc),
+ (unsigned long) &rfc);
+
/* FIXME: Need actual value of the flush timeout */
//if (flush_to != L2CAP_DEFAULT_FLUSH_TO)
// l2cap_add_conf_opt(&ptr, L2CAP_CONF_FLUSH_TO, 2, pi->flush_to);
@@ -2541,18 +2644,21 @@ static int l2cap_parse_conf_req(struct sock *sk, void *data)
}
}
- if (pi->num_conf_rsp || pi->num_conf_req)
+ if (pi->num_conf_rsp || pi->num_conf_req > 1)
goto done;
switch (pi->mode) {
case L2CAP_MODE_STREAMING:
case L2CAP_MODE_ERTM:
- pi->conf_state |= L2CAP_CONF_STATE2_DEVICE;
- if (!l2cap_mode_supported(pi->mode, pi->conn->feat_mask))
+ if (!(pi->conf_state & L2CAP_CONF_STATE2_DEVICE)) {
+ pi->mode = l2cap_select_mode(rfc.mode,
+ pi->conn->feat_mask);
+ break;
+ }
+
+ if (pi->mode != rfc.mode)
return -ECONNREFUSED;
- break;
- default:
- pi->mode = l2cap_select_mode(rfc.mode, pi->conn->feat_mask);
+
break;
}
@@ -2675,7 +2781,6 @@ static int l2cap_parse_conf_rsp(struct sock *sk, void *rsp, int len, void *data,
rfc.mode != pi->mode)
return -ECONNREFUSED;
- pi->mode = rfc.mode;
pi->fcs = 0;
l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
@@ -2684,6 +2789,11 @@ static int l2cap_parse_conf_rsp(struct sock *sk, void *rsp, int len, void *data,
}
}
+ if (pi->mode == L2CAP_MODE_BASIC && pi->mode != rfc.mode)
+ return -ECONNREFUSED;
+
+ pi->mode = rfc.mode;
+
if (*result == L2CAP_CONF_SUCCESS) {
switch (rfc.mode) {
case L2CAP_MODE_ERTM:
@@ -2778,7 +2888,7 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd
struct l2cap_chan_list *list = &conn->chan_list;
struct l2cap_conn_req *req = (struct l2cap_conn_req *) data;
struct l2cap_conn_rsp rsp;
- struct sock *sk, *parent;
+ struct sock *parent, *uninitialized_var(sk);
int result, status = L2CAP_CS_NO_INFO;
u16 dcid = 0, scid = __le16_to_cpu(req->scid);
@@ -2887,6 +2997,15 @@ sendresp:
L2CAP_INFO_REQ, sizeof(info), &info);
}
+ if (!(l2cap_pi(sk)->conf_state & L2CAP_CONF_REQ_SENT) &&
+ result == L2CAP_CR_SUCCESS) {
+ u8 buf[128];
+ l2cap_pi(sk)->conf_state |= L2CAP_CONF_REQ_SENT;
+ l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
+ l2cap_build_conf_req(sk, buf), buf);
+ l2cap_pi(sk)->num_conf_req++;
+ }
+
return 0;
}
@@ -2907,11 +3026,11 @@ static inline int l2cap_connect_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hd
if (scid) {
sk = l2cap_get_chan_by_scid(&conn->chan_list, scid);
if (!sk)
- return 0;
+ return -EFAULT;
} else {
sk = l2cap_get_chan_by_ident(&conn->chan_list, cmd->ident);
if (!sk)
- return 0;
+ return -EFAULT;
}
switch (result) {
@@ -2919,9 +3038,13 @@ static inline int l2cap_connect_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hd
sk->sk_state = BT_CONFIG;
l2cap_pi(sk)->ident = 0;
l2cap_pi(sk)->dcid = dcid;
- l2cap_pi(sk)->conf_state |= L2CAP_CONF_REQ_SENT;
l2cap_pi(sk)->conf_state &= ~L2CAP_CONF_CONNECT_PEND;
+ if (l2cap_pi(sk)->conf_state & L2CAP_CONF_REQ_SENT)
+ break;
+
+ l2cap_pi(sk)->conf_state |= L2CAP_CONF_REQ_SENT;
+
l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
l2cap_build_conf_req(sk, req), req);
l2cap_pi(sk)->num_conf_req++;
@@ -2957,8 +3080,14 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr
if (!sk)
return -ENOENT;
- if (sk->sk_state == BT_DISCONN)
+ if (sk->sk_state != BT_CONFIG) {
+ struct l2cap_cmd_rej rej;
+
+ rej.reason = cpu_to_le16(0x0002);
+ l2cap_send_cmd(conn, cmd->ident, L2CAP_COMMAND_REJ,
+ sizeof(rej), &rej);
goto unlock;
+ }
/* Reject if config buffer is too small. */
len = cmd_len - sizeof(*req);
@@ -2984,7 +3113,7 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr
/* Complete config. */
len = l2cap_parse_conf_req(sk, rsp);
if (len < 0) {
- l2cap_send_disconn_req(conn, sk);
+ l2cap_send_disconn_req(conn, sk, ECONNRESET);
goto unlock;
}
@@ -3054,7 +3183,7 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr
char req[64];
if (len > sizeof(req) - sizeof(struct l2cap_conf_req)) {
- l2cap_send_disconn_req(conn, sk);
+ l2cap_send_disconn_req(conn, sk, ECONNRESET);
goto done;
}
@@ -3063,7 +3192,7 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr
len = l2cap_parse_conf_rsp(sk, rsp->data,
len, req, &result);
if (len < 0) {
- l2cap_send_disconn_req(conn, sk);
+ l2cap_send_disconn_req(conn, sk, ECONNRESET);
goto done;
}
@@ -3076,10 +3205,9 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr
}
default:
- sk->sk_state = BT_DISCONN;
sk->sk_err = ECONNRESET;
l2cap_sock_set_timer(sk, HZ * 5);
- l2cap_send_disconn_req(conn, sk);
+ l2cap_send_disconn_req(conn, sk, ECONNRESET);
goto done;
}
@@ -3130,16 +3258,6 @@ static inline int l2cap_disconnect_req(struct l2cap_conn *conn, struct l2cap_cmd
sk->sk_shutdown = SHUTDOWN_MASK;
- skb_queue_purge(TX_QUEUE(sk));
-
- if (l2cap_pi(sk)->mode == L2CAP_MODE_ERTM) {
- skb_queue_purge(SREJ_QUEUE(sk));
- skb_queue_purge(BUSY_QUEUE(sk));
- del_timer(&l2cap_pi(sk)->retrans_timer);
- del_timer(&l2cap_pi(sk)->monitor_timer);
- del_timer(&l2cap_pi(sk)->ack_timer);
- }
-
l2cap_chan_del(sk, ECONNRESET);
bh_unlock_sock(sk);
@@ -3162,16 +3280,6 @@ static inline int l2cap_disconnect_rsp(struct l2cap_conn *conn, struct l2cap_cmd
if (!sk)
return 0;
- skb_queue_purge(TX_QUEUE(sk));
-
- if (l2cap_pi(sk)->mode == L2CAP_MODE_ERTM) {
- skb_queue_purge(SREJ_QUEUE(sk));
- skb_queue_purge(BUSY_QUEUE(sk));
- del_timer(&l2cap_pi(sk)->retrans_timer);
- del_timer(&l2cap_pi(sk)->monitor_timer);
- del_timer(&l2cap_pi(sk)->ack_timer);
- }
-
l2cap_chan_del(sk, 0);
bh_unlock_sock(sk);
@@ -3194,7 +3302,7 @@ static inline int l2cap_information_req(struct l2cap_conn *conn, struct l2cap_cm
struct l2cap_info_rsp *rsp = (struct l2cap_info_rsp *) buf;
rsp->type = cpu_to_le16(L2CAP_IT_FEAT_MASK);
rsp->result = cpu_to_le16(L2CAP_IR_SUCCESS);
- if (enable_ertm)
+ if (!disable_ertm)
feat_mask |= L2CAP_FEAT_ERTM | L2CAP_FEAT_STREAMING
| L2CAP_FEAT_FCS;
put_unaligned_le32(feat_mask, rsp->data);
@@ -3359,7 +3467,7 @@ static int l2cap_check_fcs(struct l2cap_pinfo *pi, struct sk_buff *skb)
our_fcs = crc16(0, skb->data - hdr_size, skb->len + hdr_size);
if (our_fcs != rcv_fcs)
- return -EINVAL;
+ return -EBADMSG;
}
return 0;
}
@@ -3370,25 +3478,19 @@ static inline void l2cap_send_i_or_rr_or_rnr(struct sock *sk)
u16 control = 0;
pi->frames_sent = 0;
- pi->conn_state |= L2CAP_CONN_SEND_FBIT;
control |= pi->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT;
if (pi->conn_state & L2CAP_CONN_LOCAL_BUSY) {
- control |= L2CAP_SUPER_RCV_NOT_READY | L2CAP_CTRL_FINAL;
+ control |= L2CAP_SUPER_RCV_NOT_READY;
l2cap_send_sframe(pi, control);
pi->conn_state |= L2CAP_CONN_RNR_SENT;
- pi->conn_state &= ~L2CAP_CONN_SEND_FBIT;
}
- if (pi->conn_state & L2CAP_CONN_REMOTE_BUSY && pi->unacked_frames > 0)
- __mod_retrans_timer();
-
- pi->conn_state &= ~L2CAP_CONN_REMOTE_BUSY;
+ if (pi->conn_state & L2CAP_CONN_REMOTE_BUSY)
+ l2cap_retransmit_frames(sk);
- spin_lock_bh(&pi->send_lock);
l2cap_ertm_send(sk);
- spin_unlock_bh(&pi->send_lock);
if (!(pi->conn_state & L2CAP_CONN_LOCAL_BUSY) &&
pi->frames_sent == 0) {
@@ -3400,6 +3502,8 @@ static inline void l2cap_send_i_or_rr_or_rnr(struct sock *sk)
static int l2cap_add_to_srej_queue(struct sock *sk, struct sk_buff *skb, u8 tx_seq, u8 sar)
{
struct sk_buff *next_skb;
+ struct l2cap_pinfo *pi = l2cap_pi(sk);
+ int tx_seq_offset, next_tx_seq_offset;
bt_cb(skb)->tx_seq = tx_seq;
bt_cb(skb)->sar = sar;
@@ -3410,11 +3514,20 @@ static int l2cap_add_to_srej_queue(struct sock *sk, struct sk_buff *skb, u8 tx_s
return 0;
}
+ tx_seq_offset = (tx_seq - pi->buffer_seq) % 64;
+ if (tx_seq_offset < 0)
+ tx_seq_offset += 64;
+
do {
if (bt_cb(next_skb)->tx_seq == tx_seq)
return -EINVAL;
- if (bt_cb(next_skb)->tx_seq > tx_seq) {
+ next_tx_seq_offset = (bt_cb(next_skb)->tx_seq -
+ pi->buffer_seq) % 64;
+ if (next_tx_seq_offset < 0)
+ next_tx_seq_offset += 64;
+
+ if (next_tx_seq_offset > tx_seq_offset) {
__skb_queue_before(SREJ_QUEUE(sk), next_skb, skb);
return 0;
}
@@ -3532,11 +3645,51 @@ drop:
pi->sdu = NULL;
disconnect:
- l2cap_send_disconn_req(pi->conn, sk);
+ l2cap_send_disconn_req(pi->conn, sk, ECONNRESET);
kfree_skb(skb);
return 0;
}
+static int l2cap_try_push_rx_skb(struct sock *sk)
+{
+ struct l2cap_pinfo *pi = l2cap_pi(sk);
+ struct sk_buff *skb;
+ u16 control;
+ int err;
+
+ while ((skb = skb_dequeue(BUSY_QUEUE(sk)))) {
+ control = bt_cb(skb)->sar << L2CAP_CTRL_SAR_SHIFT;
+ err = l2cap_ertm_reassembly_sdu(sk, skb, control);
+ if (err < 0) {
+ skb_queue_head(BUSY_QUEUE(sk), skb);
+ return -EBUSY;
+ }
+
+ pi->buffer_seq = (pi->buffer_seq + 1) % 64;
+ }
+
+ if (!(pi->conn_state & L2CAP_CONN_RNR_SENT))
+ goto done;
+
+ control = pi->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT;
+ control |= L2CAP_SUPER_RCV_READY | L2CAP_CTRL_POLL;
+ l2cap_send_sframe(pi, control);
+ l2cap_pi(sk)->retry_count = 1;
+
+ del_timer(&pi->retrans_timer);
+ __mod_monitor_timer();
+
+ l2cap_pi(sk)->conn_state |= L2CAP_CONN_WAIT_F;
+
+done:
+ pi->conn_state &= ~L2CAP_CONN_LOCAL_BUSY;
+ pi->conn_state &= ~L2CAP_CONN_RNR_SENT;
+
+ BT_DBG("sk %p, Exit local busy", sk);
+
+ return 0;
+}
+
static void l2cap_busy_work(struct work_struct *work)
{
DECLARE_WAITQUEUE(wait, current);
@@ -3545,7 +3698,6 @@ static void l2cap_busy_work(struct work_struct *work)
struct sock *sk = (struct sock *)pi;
int n_tries = 0, timeo = HZ/5, err;
struct sk_buff *skb;
- u16 control;
lock_sock(sk);
@@ -3555,8 +3707,8 @@ static void l2cap_busy_work(struct work_struct *work)
if (n_tries++ > L2CAP_LOCAL_BUSY_TRIES) {
err = -EBUSY;
- l2cap_send_disconn_req(pi->conn, sk);
- goto done;
+ l2cap_send_disconn_req(pi->conn, sk, EBUSY);
+ break;
}
if (!timeo)
@@ -3564,7 +3716,7 @@ static void l2cap_busy_work(struct work_struct *work)
if (signal_pending(current)) {
err = sock_intr_errno(timeo);
- goto done;
+ break;
}
release_sock(sk);
@@ -3573,40 +3725,12 @@ static void l2cap_busy_work(struct work_struct *work)
err = sock_error(sk);
if (err)
- goto done;
-
- while ((skb = skb_dequeue(BUSY_QUEUE(sk)))) {
- control = bt_cb(skb)->sar << L2CAP_CTRL_SAR_SHIFT;
- err = l2cap_ertm_reassembly_sdu(sk, skb, control);
- if (err < 0) {
- skb_queue_head(BUSY_QUEUE(sk), skb);
- break;
- }
-
- pi->buffer_seq = (pi->buffer_seq + 1) % 64;
- }
+ break;
- if (!skb)
+ if (l2cap_try_push_rx_skb(sk) == 0)
break;
}
- if (!(pi->conn_state & L2CAP_CONN_RNR_SENT))
- goto done;
-
- control = pi->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT;
- control |= L2CAP_SUPER_RCV_READY | L2CAP_CTRL_POLL;
- l2cap_send_sframe(pi, control);
- l2cap_pi(sk)->retry_count = 1;
-
- del_timer(&pi->retrans_timer);
- __mod_monitor_timer();
-
- l2cap_pi(sk)->conn_state |= L2CAP_CONN_WAIT_F;
-
-done:
- pi->conn_state &= ~L2CAP_CONN_LOCAL_BUSY;
- pi->conn_state &= ~L2CAP_CONN_RNR_SENT;
-
set_current_state(TASK_RUNNING);
remove_wait_queue(sk_sleep(sk), &wait);
@@ -3621,7 +3745,9 @@ static int l2cap_push_rx_skb(struct sock *sk, struct sk_buff *skb, u16 control)
if (pi->conn_state & L2CAP_CONN_LOCAL_BUSY) {
bt_cb(skb)->sar = control >> L2CAP_CTRL_SAR_SHIFT;
__skb_queue_tail(BUSY_QUEUE(sk), skb);
- return -EBUSY;
+ return l2cap_try_push_rx_skb(sk);
+
+
}
err = l2cap_ertm_reassembly_sdu(sk, skb, control);
@@ -3631,6 +3757,8 @@ static int l2cap_push_rx_skb(struct sock *sk, struct sk_buff *skb, u16 control)
}
/* Busy Condition */
+ BT_DBG("sk %p, Enter local busy", sk);
+
pi->conn_state |= L2CAP_CONN_LOCAL_BUSY;
bt_cb(skb)->sar = control >> L2CAP_CTRL_SAR_SHIFT;
__skb_queue_tail(BUSY_QUEUE(sk), skb);
@@ -3641,6 +3769,8 @@ static int l2cap_push_rx_skb(struct sock *sk, struct sk_buff *skb, u16 control)
pi->conn_state |= L2CAP_CONN_RNR_SENT;
+ del_timer(&pi->ack_timer);
+
queue_work(_busy_wq, &pi->busy_work);
return err;
@@ -3754,7 +3884,7 @@ static void l2cap_check_srej_gap(struct sock *sk, u8 tx_seq)
l2cap_ertm_reassembly_sdu(sk, skb, control);
l2cap_pi(sk)->buffer_seq_srej =
(l2cap_pi(sk)->buffer_seq_srej + 1) % 64;
- tx_seq++;
+ tx_seq = (tx_seq + 1) % 64;
}
}
@@ -3790,10 +3920,11 @@ static void l2cap_send_srejframe(struct sock *sk, u8 tx_seq)
l2cap_send_sframe(pi, control);
new = kzalloc(sizeof(struct srej_list), GFP_ATOMIC);
- new->tx_seq = pi->expected_tx_seq++;
+ new->tx_seq = pi->expected_tx_seq;
+ pi->expected_tx_seq = (pi->expected_tx_seq + 1) % 64;
list_add_tail(&new->list, SREJ_LIST(sk));
}
- pi->expected_tx_seq++;
+ pi->expected_tx_seq = (pi->expected_tx_seq + 1) % 64;
}
static inline int l2cap_data_channel_iframe(struct sock *sk, u16 rx_control, struct sk_buff *skb)
@@ -3802,11 +3933,12 @@ static inline int l2cap_data_channel_iframe(struct sock *sk, u16 rx_control, str
u8 tx_seq = __get_txseq(rx_control);
u8 req_seq = __get_reqseq(rx_control);
u8 sar = rx_control >> L2CAP_CTRL_SAR_SHIFT;
- u8 tx_seq_offset, expected_tx_seq_offset;
+ int tx_seq_offset, expected_tx_seq_offset;
int num_to_ack = (pi->tx_win/6) + 1;
int err = 0;
- BT_DBG("sk %p rx_control 0x%4.4x len %d", sk, rx_control, skb->len);
+ BT_DBG("sk %p len %d tx_seq %d rx_control 0x%4.4x", sk, skb->len, tx_seq,
+ rx_control);
if (L2CAP_CTRL_FINAL & rx_control &&
l2cap_pi(sk)->conn_state & L2CAP_CONN_WAIT_F) {
@@ -3828,7 +3960,7 @@ static inline int l2cap_data_channel_iframe(struct sock *sk, u16 rx_control, str
/* invalid tx_seq */
if (tx_seq_offset >= pi->tx_win) {
- l2cap_send_disconn_req(pi->conn, sk);
+ l2cap_send_disconn_req(pi->conn, sk, ECONNRESET);
goto drop;
}
@@ -3851,6 +3983,7 @@ static inline int l2cap_data_channel_iframe(struct sock *sk, u16 rx_control, str
pi->buffer_seq = pi->buffer_seq_srej;
pi->conn_state &= ~L2CAP_CONN_SREJ_SENT;
l2cap_send_ack(pi);
+ BT_DBG("sk %p, Exit SREJ_SENT", sk);
}
} else {
struct srej_list *l;
@@ -3879,6 +4012,8 @@ static inline int l2cap_data_channel_iframe(struct sock *sk, u16 rx_control, str
pi->conn_state |= L2CAP_CONN_SREJ_SENT;
+ BT_DBG("sk %p, Enter SREJ", sk);
+
INIT_LIST_HEAD(SREJ_LIST(sk));
pi->buffer_seq_srej = pi->buffer_seq;
@@ -3889,6 +4024,8 @@ static inline int l2cap_data_channel_iframe(struct sock *sk, u16 rx_control, str
pi->conn_state |= L2CAP_CONN_SEND_PBIT;
l2cap_send_srejframe(sk, tx_seq);
+
+ del_timer(&pi->ack_timer);
}
return 0;
@@ -3902,6 +4039,10 @@ expected:
return 0;
}
+ err = l2cap_push_rx_skb(sk, skb, rx_control);
+ if (err < 0)
+ return 0;
+
if (rx_control & L2CAP_CTRL_FINAL) {
if (pi->conn_state & L2CAP_CONN_REJ_ACT)
pi->conn_state &= ~L2CAP_CONN_REJ_ACT;
@@ -3909,10 +4050,6 @@ expected:
l2cap_retransmit_frames(sk);
}
- err = l2cap_push_rx_skb(sk, skb, rx_control);
- if (err < 0)
- return 0;
-
__mod_ack_timer();
pi->num_acked = (pi->num_acked + 1) % num_to_ack;
@@ -3930,10 +4067,14 @@ static inline void l2cap_data_channel_rrframe(struct sock *sk, u16 rx_control)
{
struct l2cap_pinfo *pi = l2cap_pi(sk);
+ BT_DBG("sk %p, req_seq %d ctrl 0x%4.4x", sk, __get_reqseq(rx_control),
+ rx_control);
+
pi->expected_ack_seq = __get_reqseq(rx_control);
l2cap_drop_acked_frames(sk);
if (rx_control & L2CAP_CTRL_POLL) {
+ pi->conn_state |= L2CAP_CONN_SEND_FBIT;
if (pi->conn_state & L2CAP_CONN_SREJ_SENT) {
if ((pi->conn_state & L2CAP_CONN_REMOTE_BUSY) &&
(pi->unacked_frames > 0))
@@ -3962,9 +4103,7 @@ static inline void l2cap_data_channel_rrframe(struct sock *sk, u16 rx_control)
if (pi->conn_state & L2CAP_CONN_SREJ_SENT) {
l2cap_send_ack(pi);
} else {
- spin_lock_bh(&pi->send_lock);
l2cap_ertm_send(sk);
- spin_unlock_bh(&pi->send_lock);
}
}
}
@@ -3974,6 +4113,8 @@ static inline void l2cap_data_channel_rejframe(struct sock *sk, u16 rx_control)
struct l2cap_pinfo *pi = l2cap_pi(sk);
u8 tx_seq = __get_reqseq(rx_control);
+ BT_DBG("sk %p, req_seq %d ctrl 0x%4.4x", sk, tx_seq, rx_control);
+
pi->conn_state &= ~L2CAP_CONN_REMOTE_BUSY;
pi->expected_ack_seq = tx_seq;
@@ -3996,16 +4137,18 @@ static inline void l2cap_data_channel_srejframe(struct sock *sk, u16 rx_control)
struct l2cap_pinfo *pi = l2cap_pi(sk);
u8 tx_seq = __get_reqseq(rx_control);
+ BT_DBG("sk %p, req_seq %d ctrl 0x%4.4x", sk, tx_seq, rx_control);
+
pi->conn_state &= ~L2CAP_CONN_REMOTE_BUSY;
if (rx_control & L2CAP_CTRL_POLL) {
pi->expected_ack_seq = tx_seq;
l2cap_drop_acked_frames(sk);
+
+ pi->conn_state |= L2CAP_CONN_SEND_FBIT;
l2cap_retransmit_one_frame(sk, tx_seq);
- spin_lock_bh(&pi->send_lock);
l2cap_ertm_send(sk);
- spin_unlock_bh(&pi->send_lock);
if (pi->conn_state & L2CAP_CONN_WAIT_F) {
pi->srej_save_reqseq = tx_seq;
@@ -4031,10 +4174,15 @@ static inline void l2cap_data_channel_rnrframe(struct sock *sk, u16 rx_control)
struct l2cap_pinfo *pi = l2cap_pi(sk);
u8 tx_seq = __get_reqseq(rx_control);
+ BT_DBG("sk %p, req_seq %d ctrl 0x%4.4x", sk, tx_seq, rx_control);
+
pi->conn_state |= L2CAP_CONN_REMOTE_BUSY;
pi->expected_ack_seq = tx_seq;
l2cap_drop_acked_frames(sk);
+ if (rx_control & L2CAP_CTRL_POLL)
+ pi->conn_state |= L2CAP_CONN_SEND_FBIT;
+
if (!(pi->conn_state & L2CAP_CONN_SREJ_SENT)) {
del_timer(&pi->retrans_timer);
if (rx_control & L2CAP_CTRL_POLL)
@@ -4082,12 +4230,83 @@ static inline int l2cap_data_channel_sframe(struct sock *sk, u16 rx_control, str
return 0;
}
+static int l2cap_ertm_data_rcv(struct sock *sk, struct sk_buff *skb)
+{
+ struct l2cap_pinfo *pi = l2cap_pi(sk);
+ u16 control;
+ u8 req_seq;
+ int len, next_tx_seq_offset, req_seq_offset;
+
+ control = get_unaligned_le16(skb->data);
+ skb_pull(skb, 2);
+ len = skb->len;
+
+ /*
+ * We can just drop the corrupted I-frame here.
+ * Receiver will miss it and start proper recovery
+ * procedures and ask retransmission.
+ */
+ if (l2cap_check_fcs(pi, skb))
+ goto drop;
+
+ if (__is_sar_start(control) && __is_iframe(control))
+ len -= 2;
+
+ if (pi->fcs == L2CAP_FCS_CRC16)
+ len -= 2;
+
+ if (len > pi->mps) {
+ l2cap_send_disconn_req(pi->conn, sk, ECONNRESET);
+ goto drop;
+ }
+
+ req_seq = __get_reqseq(control);
+ req_seq_offset = (req_seq - pi->expected_ack_seq) % 64;
+ if (req_seq_offset < 0)
+ req_seq_offset += 64;
+
+ next_tx_seq_offset =
+ (pi->next_tx_seq - pi->expected_ack_seq) % 64;
+ if (next_tx_seq_offset < 0)
+ next_tx_seq_offset += 64;
+
+ /* check for invalid req-seq */
+ if (req_seq_offset > next_tx_seq_offset) {
+ l2cap_send_disconn_req(pi->conn, sk, ECONNRESET);
+ goto drop;
+ }
+
+ if (__is_iframe(control)) {
+ if (len < 0) {
+ l2cap_send_disconn_req(pi->conn, sk, ECONNRESET);
+ goto drop;
+ }
+
+ l2cap_data_channel_iframe(sk, control, skb);
+ } else {
+ if (len != 0) {
+ BT_ERR("%d", len);
+ l2cap_send_disconn_req(pi->conn, sk, ECONNRESET);
+ goto drop;
+ }
+
+ l2cap_data_channel_sframe(sk, control, skb);
+ }
+
+ return 0;
+
+drop:
+ kfree_skb(skb);
+ return 0;
+}
+
static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk_buff *skb)
{
struct sock *sk;
struct l2cap_pinfo *pi;
- u16 control, len;
- u8 tx_seq, req_seq, next_tx_seq_offset, req_seq_offset;
+ u16 control;
+ u8 tx_seq;
+ int len;
sk = l2cap_get_chan_by_scid(&conn->chan_list, cid);
if (!sk) {
@@ -4117,59 +4336,11 @@ static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk
break;
case L2CAP_MODE_ERTM:
- control = get_unaligned_le16(skb->data);
- skb_pull(skb, 2);
- len = skb->len;
-
- if (__is_sar_start(control))
- len -= 2;
-
- if (pi->fcs == L2CAP_FCS_CRC16)
- len -= 2;
-
- /*
- * We can just drop the corrupted I-frame here.
- * Receiver will miss it and start proper recovery
- * procedures and ask retransmission.
- */
- if (len > pi->mps) {
- l2cap_send_disconn_req(pi->conn, sk);
- goto drop;
- }
-
- if (l2cap_check_fcs(pi, skb))
- goto drop;
-
- req_seq = __get_reqseq(control);
- req_seq_offset = (req_seq - pi->expected_ack_seq) % 64;
- if (req_seq_offset < 0)
- req_seq_offset += 64;
-
- next_tx_seq_offset =
- (pi->next_tx_seq - pi->expected_ack_seq) % 64;
- if (next_tx_seq_offset < 0)
- next_tx_seq_offset += 64;
-
- /* check for invalid req-seq */
- if (req_seq_offset > next_tx_seq_offset) {
- l2cap_send_disconn_req(pi->conn, sk);
- goto drop;
- }
-
- if (__is_iframe(control)) {
- if (len < 4) {
- l2cap_send_disconn_req(pi->conn, sk);
- goto drop;
- }
-
- l2cap_data_channel_iframe(sk, control, skb);
+ if (!sock_owned_by_user(sk)) {
+ l2cap_ertm_data_rcv(sk, skb);
} else {
- if (len != 0) {
- l2cap_send_disconn_req(pi->conn, sk);
+ if (sk_add_backlog(sk, skb))
goto drop;
- }
-
- l2cap_data_channel_sframe(sk, control, skb);
}
goto done;
@@ -4179,16 +4350,16 @@ static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk
skb_pull(skb, 2);
len = skb->len;
+ if (l2cap_check_fcs(pi, skb))
+ goto drop;
+
if (__is_sar_start(control))
len -= 2;
if (pi->fcs == L2CAP_FCS_CRC16)
len -= 2;
- if (len > pi->mps || len < 4 || __is_sframe(control))
- goto drop;
-
- if (l2cap_check_fcs(pi, skb))
+ if (len > pi->mps || len < 0 || __is_sframe(control))
goto drop;
tx_seq = __get_txseq(control);
@@ -4288,7 +4459,7 @@ static int l2cap_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
struct hlist_node *node;
if (type != ACL_LINK)
- return 0;
+ return -EINVAL;
BT_DBG("hdev %s, bdaddr %s", hdev->name, batostr(bdaddr));
@@ -4321,7 +4492,7 @@ static int l2cap_connect_cfm(struct hci_conn *hcon, u8 status)
BT_DBG("hcon %p bdaddr %s status %d", hcon, batostr(&hcon->dst), status);
if (hcon->type != ACL_LINK)
- return 0;
+ return -EINVAL;
if (!status) {
conn = l2cap_conn_add(hcon, status);
@@ -4350,7 +4521,7 @@ static int l2cap_disconn_cfm(struct hci_conn *hcon, u8 reason)
BT_DBG("hcon %p reason %d", hcon, reason);
if (hcon->type != ACL_LINK)
- return 0;
+ return -EINVAL;
l2cap_conn_del(hcon, bt_err(reason));
@@ -4679,14 +4850,8 @@ EXPORT_SYMBOL(l2cap_load);
module_init(l2cap_init);
module_exit(l2cap_exit);
-module_param(enable_ertm, bool, 0644);
-MODULE_PARM_DESC(enable_ertm, "Enable enhanced retransmission mode");
-
-module_param(max_transmit, uint, 0644);
-MODULE_PARM_DESC(max_transmit, "Max transmit value (default = 3)");
-
-module_param(tx_window, uint, 0644);
-MODULE_PARM_DESC(tx_window, "Transmission window size value (default = 63)");
+module_param(disable_ertm, bool, 0644);
+MODULE_PARM_DESC(disable_ertm, "Disable enhanced retransmission mode");
MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
MODULE_DESCRIPTION("Bluetooth L2CAP ver " VERSION);
diff --git a/net/bluetooth/rfcomm/sock.c b/net/bluetooth/rfcomm/sock.c
index 43fbf6b4b4b..44a62327595 100644
--- a/net/bluetooth/rfcomm/sock.c
+++ b/net/bluetooth/rfcomm/sock.c
@@ -1152,7 +1152,7 @@ error:
return err;
}
-void rfcomm_cleanup_sockets(void)
+void __exit rfcomm_cleanup_sockets(void)
{
debugfs_remove(rfcomm_sock_debugfs);
diff --git a/net/bluetooth/rfcomm/tty.c b/net/bluetooth/rfcomm/tty.c
index 309b6c261b2..026205c18b7 100644
--- a/net/bluetooth/rfcomm/tty.c
+++ b/net/bluetooth/rfcomm/tty.c
@@ -1153,7 +1153,7 @@ static const struct tty_operations rfcomm_ops = {
.tiocmset = rfcomm_tty_tiocmset,
};
-int rfcomm_init_ttys(void)
+int __init rfcomm_init_ttys(void)
{
rfcomm_tty_driver = alloc_tty_driver(RFCOMM_TTY_PORTS);
if (!rfcomm_tty_driver)
@@ -1183,7 +1183,7 @@ int rfcomm_init_ttys(void)
return 0;
}
-void rfcomm_cleanup_ttys(void)
+void __exit rfcomm_cleanup_ttys(void)
{
tty_unregister_driver(rfcomm_tty_driver);
put_tty_driver(rfcomm_tty_driver);
diff --git a/net/bridge/br.c b/net/bridge/br.c
index 76357b54775..c8436fa3134 100644
--- a/net/bridge/br.c
+++ b/net/bridge/br.c
@@ -63,7 +63,6 @@ static int __init br_init(void)
goto err_out4;
brioctl_set(br_ioctl_deviceless_stub);
- br_handle_frame_hook = br_handle_frame;
#if defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE)
br_fdb_test_addr_hook = br_fdb_test_addr;
@@ -100,7 +99,6 @@ static void __exit br_deinit(void)
br_fdb_test_addr_hook = NULL;
#endif
- br_handle_frame_hook = NULL;
br_fdb_fini();
}
diff --git a/net/bridge/br_device.c b/net/bridge/br_device.c
index 753fc4221f3..cf09fe591fc 100644
--- a/net/bridge/br_device.c
+++ b/net/bridge/br_device.c
@@ -22,7 +22,7 @@
#include <asm/uaccess.h>
#include "br_private.h"
-/* net device transmit always called with no BH (preempt_disabled) */
+/* net device transmit always called with BH disabled */
netdev_tx_t br_dev_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct net_bridge *br = netdev_priv(dev);
@@ -38,17 +38,26 @@ netdev_tx_t br_dev_xmit(struct sk_buff *skb, struct net_device *dev)
}
#endif
+ u64_stats_update_begin(&brstats->syncp);
brstats->tx_packets++;
brstats->tx_bytes += skb->len;
+ u64_stats_update_end(&brstats->syncp);
BR_INPUT_SKB_CB(skb)->brdev = dev;
skb_reset_mac_header(skb);
skb_pull(skb, ETH_HLEN);
+ rcu_read_lock();
if (is_multicast_ether_addr(dest)) {
- if (br_multicast_rcv(br, NULL, skb))
+ if (unlikely(netpoll_tx_running(dev))) {
+ br_flood_deliver(br, skb);
+ goto out;
+ }
+ if (br_multicast_rcv(br, NULL, skb)) {
+ kfree_skb(skb);
goto out;
+ }
mdst = br_mdb_get(br, skb);
if (mdst || BR_INPUT_SKB_CB_MROUTERS_ONLY(skb))
@@ -61,6 +70,7 @@ netdev_tx_t br_dev_xmit(struct sk_buff *skb, struct net_device *dev)
br_flood_deliver(br, skb);
out:
+ rcu_read_unlock();
return NETDEV_TX_OK;
}
@@ -92,21 +102,25 @@ static int br_dev_stop(struct net_device *dev)
return 0;
}
-static struct net_device_stats *br_get_stats(struct net_device *dev)
+static struct rtnl_link_stats64 *br_get_stats64(struct net_device *dev,
+ struct rtnl_link_stats64 *stats)
{
struct net_bridge *br = netdev_priv(dev);
- struct net_device_stats *stats = &dev->stats;
- struct br_cpu_netstats sum = { 0 };
+ struct br_cpu_netstats tmp, sum = { 0 };
unsigned int cpu;
for_each_possible_cpu(cpu) {
+ unsigned int start;
const struct br_cpu_netstats *bstats
= per_cpu_ptr(br->stats, cpu);
-
- sum.tx_bytes += bstats->tx_bytes;
- sum.tx_packets += bstats->tx_packets;
- sum.rx_bytes += bstats->rx_bytes;
- sum.rx_packets += bstats->rx_packets;
+ do {
+ start = u64_stats_fetch_begin(&bstats->syncp);
+ memcpy(&tmp, bstats, sizeof(tmp));
+ } while (u64_stats_fetch_retry(&bstats->syncp, start));
+ sum.tx_bytes += tmp.tx_bytes;
+ sum.tx_packets += tmp.tx_packets;
+ sum.rx_bytes += tmp.rx_bytes;
+ sum.rx_packets += tmp.rx_packets;
}
stats->tx_bytes = sum.tx_bytes;
@@ -127,7 +141,7 @@ static int br_change_mtu(struct net_device *dev, int new_mtu)
#ifdef CONFIG_BRIDGE_NETFILTER
/* remember the MTU in the rtable for PMTU */
- br->fake_rtable.u.dst.metrics[RTAX_MTU - 1] = new_mtu;
+ br->fake_rtable.dst.metrics[RTAX_MTU - 1] = new_mtu;
#endif
return 0;
@@ -199,65 +213,81 @@ static int br_set_tx_csum(struct net_device *dev, u32 data)
}
#ifdef CONFIG_NET_POLL_CONTROLLER
-static bool br_devices_support_netpoll(struct net_bridge *br)
+static void br_poll_controller(struct net_device *br_dev)
{
- struct net_bridge_port *p;
- bool ret = true;
- int count = 0;
- unsigned long flags;
-
- spin_lock_irqsave(&br->lock, flags);
- list_for_each_entry(p, &br->port_list, list) {
- count++;
- if ((p->dev->priv_flags & IFF_DISABLE_NETPOLL) ||
- !p->dev->netdev_ops->ndo_poll_controller)
- ret = false;
- }
- spin_unlock_irqrestore(&br->lock, flags);
- return count != 0 && ret;
}
-void br_netpoll_cleanup(struct net_device *dev)
+static void br_netpoll_cleanup(struct net_device *dev)
{
struct net_bridge *br = netdev_priv(dev);
struct net_bridge_port *p, *n;
- const struct net_device_ops *ops;
- br->dev->npinfo = NULL;
list_for_each_entry_safe(p, n, &br->port_list, list) {
- if (p->dev) {
- ops = p->dev->netdev_ops;
- if (ops->ndo_netpoll_cleanup)
- ops->ndo_netpoll_cleanup(p->dev);
- else
- p->dev->npinfo = NULL;
- }
+ br_netpoll_disable(p);
}
}
-void br_netpoll_disable(struct net_bridge *br,
- struct net_device *dev)
+static int br_netpoll_setup(struct net_device *dev, struct netpoll_info *ni)
{
- if (br_devices_support_netpoll(br))
- br->dev->priv_flags &= ~IFF_DISABLE_NETPOLL;
- if (dev->netdev_ops->ndo_netpoll_cleanup)
- dev->netdev_ops->ndo_netpoll_cleanup(dev);
- else
- dev->npinfo = NULL;
+ struct net_bridge *br = netdev_priv(dev);
+ struct net_bridge_port *p, *n;
+ int err = 0;
+
+ list_for_each_entry_safe(p, n, &br->port_list, list) {
+ if (!p->dev)
+ continue;
+
+ err = br_netpoll_enable(p);
+ if (err)
+ goto fail;
+ }
+
+out:
+ return err;
+
+fail:
+ br_netpoll_cleanup(dev);
+ goto out;
}
-void br_netpoll_enable(struct net_bridge *br,
- struct net_device *dev)
+int br_netpoll_enable(struct net_bridge_port *p)
{
- if (br_devices_support_netpoll(br)) {
- br->dev->priv_flags &= ~IFF_DISABLE_NETPOLL;
- if (br->dev->npinfo)
- dev->npinfo = br->dev->npinfo;
- } else if (!(br->dev->priv_flags & IFF_DISABLE_NETPOLL)) {
- br->dev->priv_flags |= IFF_DISABLE_NETPOLL;
- br_info(br,"new device %s does not support netpoll (disabling)",
- dev->name);
+ struct netpoll *np;
+ int err = 0;
+
+ np = kzalloc(sizeof(*p->np), GFP_KERNEL);
+ err = -ENOMEM;
+ if (!np)
+ goto out;
+
+ np->dev = p->dev;
+
+ err = __netpoll_setup(np);
+ if (err) {
+ kfree(np);
+ goto out;
}
+
+ p->np = np;
+
+out:
+ return err;
+}
+
+void br_netpoll_disable(struct net_bridge_port *p)
+{
+ struct netpoll *np = p->np;
+
+ if (!np)
+ return;
+
+ p->np = NULL;
+
+ /* Wait for transmitting packets to finish before freeing. */
+ synchronize_rcu_bh();
+
+ __netpoll_cleanup(np);
+ kfree(np);
}
#endif
@@ -280,13 +310,15 @@ static const struct net_device_ops br_netdev_ops = {
.ndo_open = br_dev_open,
.ndo_stop = br_dev_stop,
.ndo_start_xmit = br_dev_xmit,
- .ndo_get_stats = br_get_stats,
+ .ndo_get_stats64 = br_get_stats64,
.ndo_set_mac_address = br_set_mac_address,
.ndo_set_multicast_list = br_dev_set_multicast_list,
.ndo_change_mtu = br_change_mtu,
.ndo_do_ioctl = br_dev_ioctl,
#ifdef CONFIG_NET_POLL_CONTROLLER
+ .ndo_netpoll_setup = br_netpoll_setup,
.ndo_netpoll_cleanup = br_netpoll_cleanup,
+ .ndo_poll_controller = br_poll_controller,
#endif
};
diff --git a/net/bridge/br_fdb.c b/net/bridge/br_fdb.c
index b01dde35a69..90512ccfd3e 100644
--- a/net/bridge/br_fdb.c
+++ b/net/bridge/br_fdb.c
@@ -214,7 +214,7 @@ void br_fdb_delete_by_port(struct net_bridge *br,
spin_unlock_bh(&br->hash_lock);
}
-/* No locking or refcounting, assumes caller has no preempt (rcu_read_lock) */
+/* No locking or refcounting, assumes caller has rcu_read_lock */
struct net_bridge_fdb_entry *__br_fdb_get(struct net_bridge *br,
const unsigned char *addr)
{
@@ -240,11 +240,11 @@ int br_fdb_test_addr(struct net_device *dev, unsigned char *addr)
struct net_bridge_fdb_entry *fdb;
int ret;
- if (!dev->br_port)
+ if (!br_port_exists(dev))
return 0;
rcu_read_lock();
- fdb = __br_fdb_get(dev->br_port->br, addr);
+ fdb = __br_fdb_get(br_port_get_rcu(dev)->br, addr);
ret = fdb && fdb->dst->dev != dev &&
fdb->dst->state == BR_STATE_FORWARDING;
rcu_read_unlock();
diff --git a/net/bridge/br_forward.c b/net/bridge/br_forward.c
index 595da45f908..cbfe87f0f34 100644
--- a/net/bridge/br_forward.c
+++ b/net/bridge/br_forward.c
@@ -67,6 +67,17 @@ int br_forward_finish(struct sk_buff *skb)
static void __br_deliver(const struct net_bridge_port *to, struct sk_buff *skb)
{
skb->dev = to->dev;
+
+ if (unlikely(netpoll_tx_running(to->dev))) {
+ if (packet_length(skb) > skb->dev->mtu && !skb_is_gso(skb))
+ kfree_skb(skb);
+ else {
+ skb_push(skb, ETH_HLEN);
+ br_netpoll_send_skb(to, skb);
+ }
+ return;
+ }
+
NF_HOOK(NFPROTO_BRIDGE, NF_BR_LOCAL_OUT, skb, NULL, skb->dev,
br_forward_finish);
}
diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c
index 18b245e2c00..c03d2c3ff03 100644
--- a/net/bridge/br_if.c
+++ b/net/bridge/br_if.c
@@ -147,14 +147,17 @@ static void del_nbp(struct net_bridge_port *p)
list_del_rcu(&p->list);
- rcu_assign_pointer(dev->br_port, NULL);
+ dev->priv_flags &= ~IFF_BRIDGE_PORT;
+
+ netdev_rx_handler_unregister(dev);
br_multicast_del_port(p);
kobject_uevent(&p->kobj, KOBJ_REMOVE);
kobject_del(&p->kobj);
- br_netpoll_disable(br, dev);
+ br_netpoll_disable(p);
+
call_rcu(&p->rcu, destroy_nbp_rcu);
}
@@ -167,8 +170,6 @@ static void del_br(struct net_bridge *br, struct list_head *head)
del_nbp(p);
}
- br_netpoll_cleanup(br->dev);
-
del_timer_sync(&br->gc_timer);
br_sysfs_delbr(br->dev);
@@ -400,7 +401,7 @@ int br_add_if(struct net_bridge *br, struct net_device *dev)
return -ELOOP;
/* Device is already being bridged */
- if (dev->br_port != NULL)
+ if (br_port_exists(dev))
return -EBUSY;
/* No bridging devices that dislike that (e.g. wireless) */
@@ -428,7 +429,15 @@ int br_add_if(struct net_bridge *br, struct net_device *dev)
if (err)
goto err2;
- rcu_assign_pointer(dev->br_port, p);
+ if (br_netpoll_info(br) && ((err = br_netpoll_enable(p))))
+ goto err3;
+
+ err = netdev_rx_handler_register(dev, br_handle_frame, p);
+ if (err)
+ goto err3;
+
+ dev->priv_flags |= IFF_BRIDGE_PORT;
+
dev_disable_lro(dev);
list_add_rcu(&p->list, &br->port_list);
@@ -448,9 +457,9 @@ int br_add_if(struct net_bridge *br, struct net_device *dev)
kobject_uevent(&p->kobj, KOBJ_ADD);
- br_netpoll_enable(br, dev);
-
return 0;
+err3:
+ sysfs_remove_link(br->ifobj, p->dev->name);
err2:
br_fdb_delete_by_port(br, p, 1);
err1:
@@ -467,9 +476,13 @@ put_back:
/* called with RTNL */
int br_del_if(struct net_bridge *br, struct net_device *dev)
{
- struct net_bridge_port *p = dev->br_port;
+ struct net_bridge_port *p;
+
+ if (!br_port_exists(dev))
+ return -EINVAL;
- if (!p || p->br != br)
+ p = br_port_get(dev);
+ if (p->br != br)
return -EINVAL;
del_nbp(p);
diff --git a/net/bridge/br_input.c b/net/bridge/br_input.c
index d36e700f7a2..826cd522153 100644
--- a/net/bridge/br_input.c
+++ b/net/bridge/br_input.c
@@ -27,8 +27,10 @@ static int br_pass_frame_up(struct sk_buff *skb)
struct net_bridge *br = netdev_priv(brdev);
struct br_cpu_netstats *brstats = this_cpu_ptr(br->stats);
+ u64_stats_update_begin(&brstats->syncp);
brstats->rx_packets++;
brstats->rx_bytes += skb->len;
+ u64_stats_update_end(&brstats->syncp);
indev = skb->dev;
skb->dev = brdev;
@@ -37,11 +39,11 @@ static int br_pass_frame_up(struct sk_buff *skb)
netif_receive_skb);
}
-/* note: already called with rcu_read_lock (preempt_disabled) */
+/* note: already called with rcu_read_lock */
int br_handle_frame_finish(struct sk_buff *skb)
{
const unsigned char *dest = eth_hdr(skb)->h_dest;
- struct net_bridge_port *p = rcu_dereference(skb->dev->br_port);
+ struct net_bridge_port *p = br_port_get_rcu(skb->dev);
struct net_bridge *br;
struct net_bridge_fdb_entry *dst;
struct net_bridge_mdb_entry *mdst;
@@ -108,13 +110,12 @@ drop:
goto out;
}
-/* note: already called with rcu_read_lock (preempt_disabled) */
+/* note: already called with rcu_read_lock */
static int br_handle_local_finish(struct sk_buff *skb)
{
- struct net_bridge_port *p = rcu_dereference(skb->dev->br_port);
+ struct net_bridge_port *p = br_port_get_rcu(skb->dev);
- if (p)
- br_fdb_update(p->br, p, eth_hdr(skb)->h_source);
+ br_fdb_update(p->br, p, eth_hdr(skb)->h_source);
return 0; /* process further */
}
@@ -131,15 +132,18 @@ static inline int is_link_local(const unsigned char *dest)
}
/*
- * Called via br_handle_frame_hook.
* Return NULL if skb is handled
- * note: already called with rcu_read_lock (preempt_disabled)
+ * note: already called with rcu_read_lock
*/
-struct sk_buff *br_handle_frame(struct net_bridge_port *p, struct sk_buff *skb)
+struct sk_buff *br_handle_frame(struct sk_buff *skb)
{
+ struct net_bridge_port *p;
const unsigned char *dest = eth_hdr(skb)->h_dest;
int (*rhook)(struct sk_buff *skb);
+ if (skb->pkt_type == PACKET_LOOPBACK)
+ return skb;
+
if (!is_valid_ether_addr(eth_hdr(skb)->h_source))
goto drop;
@@ -147,6 +151,8 @@ struct sk_buff *br_handle_frame(struct net_bridge_port *p, struct sk_buff *skb)
if (!skb)
return NULL;
+ p = br_port_get_rcu(skb->dev);
+
if (unlikely(is_link_local(dest))) {
/* Pause frames shouldn't be passed up by driver anyway */
if (skb->protocol == htons(ETH_P_PAUSE))
diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c
index 27ae946363f..eb5b256ffc8 100644
--- a/net/bridge/br_multicast.c
+++ b/net/bridge/br_multicast.c
@@ -1435,7 +1435,7 @@ static int br_multicast_ipv6_rcv(struct net_bridge *br,
struct icmp6hdr *icmp6h;
u8 nexthdr;
unsigned len;
- unsigned offset;
+ int offset;
int err;
if (!pskb_may_pull(skb, sizeof(*ip6h)))
@@ -1728,13 +1728,9 @@ unlock:
int br_multicast_toggle(struct net_bridge *br, unsigned long val)
{
struct net_bridge_port *port;
- int err = -ENOENT;
+ int err = 0;
spin_lock(&br->multicast_lock);
- if (!netif_running(br->dev))
- goto unlock;
-
- err = 0;
if (br->multicast_disabled == !val)
goto unlock;
@@ -1742,6 +1738,9 @@ int br_multicast_toggle(struct net_bridge *br, unsigned long val)
if (br->multicast_disabled)
goto unlock;
+ if (!netif_running(br->dev))
+ goto unlock;
+
if (br->mdb) {
if (br->mdb->old) {
err = -EEXIST;
diff --git a/net/bridge/br_netfilter.c b/net/bridge/br_netfilter.c
index 8fb75f89c4a..2c911c0759c 100644
--- a/net/bridge/br_netfilter.c
+++ b/net/bridge/br_netfilter.c
@@ -55,6 +55,9 @@ static int brnf_call_arptables __read_mostly = 1;
static int brnf_filter_vlan_tagged __read_mostly = 0;
static int brnf_filter_pppoe_tagged __read_mostly = 0;
#else
+#define brnf_call_iptables 1
+#define brnf_call_ip6tables 1
+#define brnf_call_arptables 1
#define brnf_filter_vlan_tagged 0
#define brnf_filter_pppoe_tagged 0
#endif
@@ -117,26 +120,27 @@ void br_netfilter_rtable_init(struct net_bridge *br)
{
struct rtable *rt = &br->fake_rtable;
- atomic_set(&rt->u.dst.__refcnt, 1);
- rt->u.dst.dev = br->dev;
- rt->u.dst.path = &rt->u.dst;
- rt->u.dst.metrics[RTAX_MTU - 1] = 1500;
- rt->u.dst.flags = DST_NOXFRM;
- rt->u.dst.ops = &fake_dst_ops;
+ atomic_set(&rt->dst.__refcnt, 1);
+ rt->dst.dev = br->dev;
+ rt->dst.path = &rt->dst;
+ rt->dst.metrics[RTAX_MTU - 1] = 1500;
+ rt->dst.flags = DST_NOXFRM;
+ rt->dst.ops = &fake_dst_ops;
}
static inline struct rtable *bridge_parent_rtable(const struct net_device *dev)
{
- struct net_bridge_port *port = rcu_dereference(dev->br_port);
-
- return port ? &port->br->fake_rtable : NULL;
+ if (!br_port_exists(dev))
+ return NULL;
+ return &br_port_get_rcu(dev)->br->fake_rtable;
}
static inline struct net_device *bridge_parent(const struct net_device *dev)
{
- struct net_bridge_port *port = rcu_dereference(dev->br_port);
+ if (!br_port_exists(dev))
+ return NULL;
- return port ? port->br->dev : NULL;
+ return br_port_get_rcu(dev)->br->dev;
}
static inline struct nf_bridge_info *nf_bridge_alloc(struct sk_buff *skb)
@@ -244,8 +248,7 @@ static int br_nf_pre_routing_finish_ipv6(struct sk_buff *skb)
kfree_skb(skb);
return 0;
}
- dst_hold(&rt->u.dst);
- skb_dst_set(skb, &rt->u.dst);
+ skb_dst_set_noref(skb, &rt->dst);
skb->dev = nf_bridge->physindev;
nf_bridge_update_protocol(skb);
@@ -396,8 +399,7 @@ bridged_dnat:
kfree_skb(skb);
return 0;
}
- dst_hold(&rt->u.dst);
- skb_dst_set(skb, &rt->u.dst);
+ skb_dst_set_noref(skb, &rt->dst);
}
skb->dev = nf_bridge->physindev;
@@ -545,25 +547,30 @@ static unsigned int br_nf_pre_routing(unsigned int hook, struct sk_buff *skb,
const struct net_device *out,
int (*okfn)(struct sk_buff *))
{
+ struct net_bridge_port *p;
+ struct net_bridge *br;
struct iphdr *iph;
__u32 len = nf_bridge_encap_header_len(skb);
if (unlikely(!pskb_may_pull(skb, len)))
goto out;
+ p = br_port_get_rcu(in);
+ if (p == NULL)
+ goto out;
+ br = p->br;
+
if (skb->protocol == htons(ETH_P_IPV6) || IS_VLAN_IPV6(skb) ||
IS_PPPOE_IPV6(skb)) {
-#ifdef CONFIG_SYSCTL
- if (!brnf_call_ip6tables)
+ if (!brnf_call_ip6tables && !br->nf_call_ip6tables)
return NF_ACCEPT;
-#endif
+
nf_bridge_pull_encap_header_rcsum(skb);
return br_nf_pre_routing_ipv6(hook, skb, in, out, okfn);
}
-#ifdef CONFIG_SYSCTL
- if (!brnf_call_iptables)
+
+ if (!brnf_call_iptables && !br->nf_call_iptables)
return NF_ACCEPT;
-#endif
if (skb->protocol != htons(ETH_P_IP) && !IS_VLAN_IP(skb) &&
!IS_PPPOE_IP(skb))
@@ -719,12 +726,17 @@ static unsigned int br_nf_forward_arp(unsigned int hook, struct sk_buff *skb,
const struct net_device *out,
int (*okfn)(struct sk_buff *))
{
+ struct net_bridge_port *p;
+ struct net_bridge *br;
struct net_device **d = (struct net_device **)(skb->cb);
-#ifdef CONFIG_SYSCTL
- if (!brnf_call_arptables)
+ p = br_port_get_rcu(out);
+ if (p == NULL)
+ return NF_ACCEPT;
+ br = p->br;
+
+ if (!brnf_call_arptables && !br->nf_call_arptables)
return NF_ACCEPT;
-#endif
if (skb->protocol != htons(ETH_P_ARP)) {
if (!IS_VLAN_ARP(skb))
diff --git a/net/bridge/br_netlink.c b/net/bridge/br_netlink.c
index fe0a79018ab..4a6a378c84e 100644
--- a/net/bridge/br_netlink.c
+++ b/net/bridge/br_netlink.c
@@ -120,10 +120,11 @@ static int br_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb)
idx = 0;
for_each_netdev(net, dev) {
/* not a bridge port */
- if (dev->br_port == NULL || idx < cb->args[0])
+ if (!br_port_exists(dev) || idx < cb->args[0])
goto skip;
- if (br_fill_ifinfo(skb, dev->br_port, NETLINK_CB(cb->skb).pid,
+ if (br_fill_ifinfo(skb, br_port_get(dev),
+ NETLINK_CB(cb->skb).pid,
cb->nlh->nlmsg_seq, RTM_NEWLINK,
NLM_F_MULTI) < 0)
break;
@@ -168,9 +169,9 @@ static int br_rtm_setlink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
if (!dev)
return -ENODEV;
- p = dev->br_port;
- if (!p)
+ if (!br_port_exists(dev))
return -EINVAL;
+ p = br_port_get(dev);
/* if kernel STP is running, don't allow changes */
if (p->br->stp_enabled == BR_KERNEL_STP)
diff --git a/net/bridge/br_notify.c b/net/bridge/br_notify.c
index 717e1fd6133..404d4e14c6a 100644
--- a/net/bridge/br_notify.c
+++ b/net/bridge/br_notify.c
@@ -32,14 +32,15 @@ struct notifier_block br_device_notifier = {
static int br_device_event(struct notifier_block *unused, unsigned long event, void *ptr)
{
struct net_device *dev = ptr;
- struct net_bridge_port *p = dev->br_port;
+ struct net_bridge_port *p = br_port_get(dev);
struct net_bridge *br;
int err;
/* not a port of a bridge */
- if (p == NULL)
+ if (!br_port_exists(dev))
return NOTIFY_DONE;
+ p = br_port_get(dev);
br = p->br;
switch (event) {
diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h
index 0f4a74bc6a9..75c90edaf7d 100644
--- a/net/bridge/br_private.h
+++ b/net/bridge/br_private.h
@@ -15,6 +15,8 @@
#include <linux/netdevice.h>
#include <linux/if_bridge.h>
+#include <linux/netpoll.h>
+#include <linux/u64_stats_sync.h>
#include <net/route.h>
#define BR_HASH_BITS 8
@@ -143,13 +145,23 @@ struct net_bridge_port
#ifdef CONFIG_SYSFS
char sysfs_name[IFNAMSIZ];
#endif
+
+#ifdef CONFIG_NET_POLL_CONTROLLER
+ struct netpoll *np;
+#endif
};
+#define br_port_get_rcu(dev) \
+ ((struct net_bridge_port *) rcu_dereference(dev->rx_handler_data))
+#define br_port_get(dev) ((struct net_bridge_port *) dev->rx_handler_data)
+#define br_port_exists(dev) (dev->priv_flags & IFF_BRIDGE_PORT)
+
struct br_cpu_netstats {
- unsigned long rx_packets;
- unsigned long rx_bytes;
- unsigned long tx_packets;
- unsigned long tx_bytes;
+ u64 rx_packets;
+ u64 rx_bytes;
+ u64 tx_packets;
+ u64 tx_bytes;
+ struct u64_stats_sync syncp;
};
struct net_bridge
@@ -164,6 +176,9 @@ struct net_bridge
unsigned long feature_mask;
#ifdef CONFIG_BRIDGE_NETFILTER
struct rtable fake_rtable;
+ bool nf_call_iptables;
+ bool nf_call_ip6tables;
+ bool nf_call_arptables;
#endif
unsigned long flags;
#define BR_SET_MAC_ADDR 0x00000001
@@ -273,16 +288,41 @@ extern void br_dev_setup(struct net_device *dev);
extern netdev_tx_t br_dev_xmit(struct sk_buff *skb,
struct net_device *dev);
#ifdef CONFIG_NET_POLL_CONTROLLER
-extern void br_netpoll_cleanup(struct net_device *dev);
-extern void br_netpoll_enable(struct net_bridge *br,
- struct net_device *dev);
-extern void br_netpoll_disable(struct net_bridge *br,
- struct net_device *dev);
+static inline struct netpoll_info *br_netpoll_info(struct net_bridge *br)
+{
+ return br->dev->npinfo;
+}
+
+static inline void br_netpoll_send_skb(const struct net_bridge_port *p,
+ struct sk_buff *skb)
+{
+ struct netpoll *np = p->np;
+
+ if (np)
+ netpoll_send_skb(np, skb);
+}
+
+extern int br_netpoll_enable(struct net_bridge_port *p);
+extern void br_netpoll_disable(struct net_bridge_port *p);
#else
-#define br_netpoll_cleanup(br)
-#define br_netpoll_enable(br, dev)
-#define br_netpoll_disable(br, dev)
+static inline struct netpoll_info *br_netpoll_info(struct net_bridge *br)
+{
+ return NULL;
+}
+
+static inline void br_netpoll_send_skb(const struct net_bridge_port *p,
+ struct sk_buff *skb)
+{
+}
+static inline int br_netpoll_enable(struct net_bridge_port *p)
+{
+ return 0;
+}
+
+static inline void br_netpoll_disable(struct net_bridge_port *p)
+{
+}
#endif
/* br_fdb.c */
@@ -331,8 +371,7 @@ extern void br_features_recompute(struct net_bridge *br);
/* br_input.c */
extern int br_handle_frame_finish(struct sk_buff *skb);
-extern struct sk_buff *br_handle_frame(struct net_bridge_port *p,
- struct sk_buff *skb);
+extern struct sk_buff *br_handle_frame(struct sk_buff *skb);
/* br_ioctl.c */
extern int br_dev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
diff --git a/net/bridge/br_stp_bpdu.c b/net/bridge/br_stp_bpdu.c
index 217bd225a42..35cf27087b5 100644
--- a/net/bridge/br_stp_bpdu.c
+++ b/net/bridge/br_stp_bpdu.c
@@ -131,18 +131,19 @@ void br_send_tcn_bpdu(struct net_bridge_port *p)
/*
* Called from llc.
*
- * NO locks, but rcu_read_lock (preempt_disabled)
+ * NO locks, but rcu_read_lock
*/
void br_stp_rcv(const struct stp_proto *proto, struct sk_buff *skb,
struct net_device *dev)
{
const unsigned char *dest = eth_hdr(skb)->h_dest;
- struct net_bridge_port *p = rcu_dereference(dev->br_port);
+ struct net_bridge_port *p;
struct net_bridge *br;
const unsigned char *buf;
- if (!p)
+ if (!br_port_exists(dev))
goto err;
+ p = br_port_get_rcu(dev);
if (!pskb_may_pull(skb, 4))
goto err;
diff --git a/net/bridge/br_sysfs_br.c b/net/bridge/br_sysfs_br.c
index 486b8f3861d..5c1e5559ebb 100644
--- a/net/bridge/br_sysfs_br.c
+++ b/net/bridge/br_sysfs_br.c
@@ -611,6 +611,73 @@ static DEVICE_ATTR(multicast_startup_query_interval, S_IRUGO | S_IWUSR,
show_multicast_startup_query_interval,
store_multicast_startup_query_interval);
#endif
+#ifdef CONFIG_BRIDGE_NETFILTER
+static ssize_t show_nf_call_iptables(
+ struct device *d, struct device_attribute *attr, char *buf)
+{
+ struct net_bridge *br = to_bridge(d);
+ return sprintf(buf, "%u\n", br->nf_call_iptables);
+}
+
+static int set_nf_call_iptables(struct net_bridge *br, unsigned long val)
+{
+ br->nf_call_iptables = val ? true : false;
+ return 0;
+}
+
+static ssize_t store_nf_call_iptables(
+ struct device *d, struct device_attribute *attr, const char *buf,
+ size_t len)
+{
+ return store_bridge_parm(d, buf, len, set_nf_call_iptables);
+}
+static DEVICE_ATTR(nf_call_iptables, S_IRUGO | S_IWUSR,
+ show_nf_call_iptables, store_nf_call_iptables);
+
+static ssize_t show_nf_call_ip6tables(
+ struct device *d, struct device_attribute *attr, char *buf)
+{
+ struct net_bridge *br = to_bridge(d);
+ return sprintf(buf, "%u\n", br->nf_call_ip6tables);
+}
+
+static int set_nf_call_ip6tables(struct net_bridge *br, unsigned long val)
+{
+ br->nf_call_ip6tables = val ? true : false;
+ return 0;
+}
+
+static ssize_t store_nf_call_ip6tables(
+ struct device *d, struct device_attribute *attr, const char *buf,
+ size_t len)
+{
+ return store_bridge_parm(d, buf, len, set_nf_call_ip6tables);
+}
+static DEVICE_ATTR(nf_call_ip6tables, S_IRUGO | S_IWUSR,
+ show_nf_call_ip6tables, store_nf_call_ip6tables);
+
+static ssize_t show_nf_call_arptables(
+ struct device *d, struct device_attribute *attr, char *buf)
+{
+ struct net_bridge *br = to_bridge(d);
+ return sprintf(buf, "%u\n", br->nf_call_arptables);
+}
+
+static int set_nf_call_arptables(struct net_bridge *br, unsigned long val)
+{
+ br->nf_call_arptables = val ? true : false;
+ return 0;
+}
+
+static ssize_t store_nf_call_arptables(
+ struct device *d, struct device_attribute *attr, const char *buf,
+ size_t len)
+{
+ return store_bridge_parm(d, buf, len, set_nf_call_arptables);
+}
+static DEVICE_ATTR(nf_call_arptables, S_IRUGO | S_IWUSR,
+ show_nf_call_arptables, store_nf_call_arptables);
+#endif
static struct attribute *bridge_attrs[] = {
&dev_attr_forward_delay.attr,
@@ -645,6 +712,11 @@ static struct attribute *bridge_attrs[] = {
&dev_attr_multicast_query_response_interval.attr,
&dev_attr_multicast_startup_query_interval.attr,
#endif
+#ifdef CONFIG_BRIDGE_NETFILTER
+ &dev_attr_nf_call_iptables.attr,
+ &dev_attr_nf_call_ip6tables.attr,
+ &dev_attr_nf_call_arptables.attr,
+#endif
NULL
};
diff --git a/net/bridge/netfilter/ebt_redirect.c b/net/bridge/netfilter/ebt_redirect.c
index 9e19166ba45..46624bb6d9b 100644
--- a/net/bridge/netfilter/ebt_redirect.c
+++ b/net/bridge/netfilter/ebt_redirect.c
@@ -24,8 +24,9 @@ ebt_redirect_tg(struct sk_buff *skb, const struct xt_action_param *par)
return EBT_DROP;
if (par->hooknum != NF_BR_BROUTING)
+ /* rcu_read_lock()ed by nf_hook_slow */
memcpy(eth_hdr(skb)->h_dest,
- par->in->br_port->br->dev->dev_addr, ETH_ALEN);
+ br_port_get_rcu(par->in)->br->dev->dev_addr, ETH_ALEN);
else
memcpy(eth_hdr(skb)->h_dest, par->in->dev_addr, ETH_ALEN);
skb->pkt_type = PACKET_HOST;
diff --git a/net/bridge/netfilter/ebt_ulog.c b/net/bridge/netfilter/ebt_ulog.c
index ae3c7cef148..26377e96fa1 100644
--- a/net/bridge/netfilter/ebt_ulog.c
+++ b/net/bridge/netfilter/ebt_ulog.c
@@ -177,8 +177,9 @@ static void ebt_ulog_packet(unsigned int hooknr, const struct sk_buff *skb,
if (in) {
strcpy(pm->physindev, in->name);
/* If in isn't a bridge, then physindev==indev */
- if (in->br_port)
- strcpy(pm->indev, in->br_port->br->dev->name);
+ if (br_port_exists(in))
+ /* rcu_read_lock()ed by nf_hook_slow */
+ strcpy(pm->indev, br_port_get_rcu(in)->br->dev->name);
else
strcpy(pm->indev, in->name);
} else
@@ -187,7 +188,8 @@ static void ebt_ulog_packet(unsigned int hooknr, const struct sk_buff *skb,
if (out) {
/* If out exists, then out is a bridge port */
strcpy(pm->physoutdev, out->name);
- strcpy(pm->outdev, out->br_port->br->dev->name);
+ /* rcu_read_lock()ed by nf_hook_slow */
+ strcpy(pm->outdev, br_port_get_rcu(out)->br->dev->name);
} else
pm->outdev[0] = pm->physoutdev[0] = '\0';
diff --git a/net/bridge/netfilter/ebtables.c b/net/bridge/netfilter/ebtables.c
index 59ca00e40de..bcc102e3be4 100644
--- a/net/bridge/netfilter/ebtables.c
+++ b/net/bridge/netfilter/ebtables.c
@@ -140,11 +140,14 @@ ebt_basic_match(const struct ebt_entry *e, const struct ethhdr *h,
return 1;
if (FWINV2(ebt_dev_check(e->out, out), EBT_IOUT))
return 1;
- if ((!in || !in->br_port) ? 0 : FWINV2(ebt_dev_check(
- e->logical_in, in->br_port->br->dev), EBT_ILOGICALIN))
+ /* rcu_read_lock()ed by nf_hook_slow */
+ if (in && br_port_exists(in) &&
+ FWINV2(ebt_dev_check(e->logical_in, br_port_get_rcu(in)->br->dev),
+ EBT_ILOGICALIN))
return 1;
- if ((!out || !out->br_port) ? 0 : FWINV2(ebt_dev_check(
- e->logical_out, out->br_port->br->dev), EBT_ILOGICALOUT))
+ if (out && br_port_exists(out) &&
+ FWINV2(ebt_dev_check(e->logical_out, br_port_get_rcu(out)->br->dev),
+ EBT_ILOGICALOUT))
return 1;
if (e->bitmask & EBT_SOURCEMAC) {
diff --git a/net/caif/Kconfig b/net/caif/Kconfig
index ed651786f16..529750da962 100644
--- a/net/caif/Kconfig
+++ b/net/caif/Kconfig
@@ -21,19 +21,18 @@ menuconfig CAIF
See Documentation/networking/caif for a further explanation on how to
use and configure CAIF.
-if CAIF
-
config CAIF_DEBUG
bool "Enable Debug"
+ depends on CAIF
default n
--- help ---
Enable the inclusion of debug code in the CAIF stack.
Be aware that doing this will impact performance.
If unsure say N.
-
config CAIF_NETDEV
tristate "CAIF GPRS Network device"
+ depends on CAIF
default CAIF
---help---
Say Y if you will be using a CAIF based GPRS network device.
@@ -41,5 +40,3 @@ config CAIF_NETDEV
If you select to build it as a built-in then the main CAIF device must
also be a built-in.
If unsure say Y.
-
-endif
diff --git a/net/caif/Makefile b/net/caif/Makefile
index 34852af2595..f87481fb0e6 100644
--- a/net/caif/Makefile
+++ b/net/caif/Makefile
@@ -1,23 +1,13 @@
-ifeq ($(CONFIG_CAIF_DEBUG),1)
-CAIF_DBG_FLAGS := -DDEBUG
+ifeq ($(CONFIG_CAIF_DEBUG),y)
+EXTRA_CFLAGS += -DDEBUG
endif
-ccflags-y := $(CAIF_FLAGS) $(CAIF_DBG_FLAGS)
-
caif-objs := caif_dev.o \
cfcnfg.o cfmuxl.o cfctrl.o \
cffrml.o cfveil.o cfdbgl.o\
cfserl.o cfdgml.o \
cfrfml.o cfvidl.o cfutill.o \
cfsrvl.o cfpkt_skbuff.o caif_config_util.o
-clean-dirs:= .tmp_versions
-
-clean-files:= \
- Module.symvers \
- modules.order \
- *.cmd \
- *.o \
- *~
obj-$(CONFIG_CAIF) += caif.o
obj-$(CONFIG_CAIF_NETDEV) += chnl_net.o
diff --git a/net/caif/caif_config_util.c b/net/caif/caif_config_util.c
index 6f36580366f..76ae68303d3 100644
--- a/net/caif/caif_config_util.c
+++ b/net/caif/caif_config_util.c
@@ -80,6 +80,11 @@ int connect_req_to_link_param(struct cfcnfg *cnfg,
l->u.utility.paramlen);
break;
+ case CAIFPROTO_DEBUG:
+ l->linktype = CFCTRL_SRV_DBG;
+ l->endpoint = s->sockaddr.u.dbg.service;
+ l->chtype = s->sockaddr.u.dbg.type;
+ break;
default:
return -EINVAL;
}
diff --git a/net/caif/caif_dev.c b/net/caif/caif_dev.c
index e2b86f1f5a4..0b586e9d137 100644
--- a/net/caif/caif_dev.c
+++ b/net/caif/caif_dev.c
@@ -255,7 +255,7 @@ static int caif_device_notify(struct notifier_block *me, unsigned long what,
pref = CFPHYPREF_HIGH_BW;
break;
}
-
+ dev_hold(dev);
cfcnfg_add_phy_layer(get_caif_conf(),
phy_type,
dev,
@@ -285,6 +285,7 @@ static int caif_device_notify(struct notifier_block *me, unsigned long what,
caifd->layer.up->ctrlcmd(caifd->layer.up,
_CAIF_CTRLCMD_PHYIF_DOWN_IND,
caifd->layer.id);
+ might_sleep();
res = wait_event_interruptible_timeout(caifd->event,
atomic_read(&caifd->in_use) == 0,
TIMEOUT);
@@ -300,6 +301,7 @@ static int caif_device_notify(struct notifier_block *me, unsigned long what,
"Unregistering an active CAIF device: %s\n",
__func__, dev->name);
cfcnfg_del_phy_layer(get_caif_conf(), &caifd->layer);
+ dev_put(dev);
atomic_set(&caifd->state, what);
break;
@@ -326,7 +328,8 @@ struct cfcnfg *get_caif_conf(void)
EXPORT_SYMBOL(get_caif_conf);
int caif_connect_client(struct caif_connect_request *conn_req,
- struct cflayer *client_layer)
+ struct cflayer *client_layer, int *ifindex,
+ int *headroom, int *tailroom)
{
struct cfctrl_link_param param;
int ret;
@@ -334,8 +337,9 @@ int caif_connect_client(struct caif_connect_request *conn_req,
if (ret)
return ret;
/* Hook up the adaptation layer. */
- return cfcnfg_add_adaptation_layer(get_caif_conf(),
- &param, client_layer);
+ return cfcnfg_add_adaptation_layer(get_caif_conf(), &param,
+ client_layer, ifindex,
+ headroom, tailroom);
}
EXPORT_SYMBOL(caif_connect_client);
diff --git a/net/caif/caif_socket.c b/net/caif/caif_socket.c
index 3d0e09584fa..8ce90478611 100644
--- a/net/caif/caif_socket.c
+++ b/net/caif/caif_socket.c
@@ -28,8 +28,8 @@
MODULE_LICENSE("GPL");
MODULE_ALIAS_NETPROTO(AF_CAIF);
-#define CAIF_DEF_SNDBUF (CAIF_MAX_PAYLOAD_SIZE*10)
-#define CAIF_DEF_RCVBUF (CAIF_MAX_PAYLOAD_SIZE*100)
+#define CAIF_DEF_SNDBUF (4096*10)
+#define CAIF_DEF_RCVBUF (4096*100)
/*
* CAIF state is re-using the TCP socket states.
@@ -76,6 +76,7 @@ struct caifsock {
struct caif_connect_request conn_req;
struct mutex readlock;
struct dentry *debugfs_socket_dir;
+ int headroom, tailroom, maxframe;
};
static int rx_flow_is_on(struct caifsock *cf_sk)
@@ -594,27 +595,32 @@ static int caif_seqpkt_sendmsg(struct kiocb *kiocb, struct socket *sock,
goto err;
noblock = msg->msg_flags & MSG_DONTWAIT;
- buffer_size = len + CAIF_NEEDED_HEADROOM + CAIF_NEEDED_TAILROOM;
-
- ret = -EMSGSIZE;
- if (buffer_size > CAIF_MAX_PAYLOAD_SIZE)
- goto err;
-
timeo = sock_sndtimeo(sk, noblock);
timeo = caif_wait_for_flow_on(container_of(sk, struct caifsock, sk),
1, timeo, &ret);
+ if (ret)
+ goto err;
ret = -EPIPE;
if (cf_sk->sk.sk_state != CAIF_CONNECTED ||
sock_flag(sk, SOCK_DEAD) ||
(sk->sk_shutdown & RCV_SHUTDOWN))
goto err;
+ /* Error if trying to write more than maximum frame size. */
+ ret = -EMSGSIZE;
+ if (len > cf_sk->maxframe && cf_sk->sk.sk_protocol != CAIFPROTO_RFM)
+ goto err;
+
+ buffer_size = len + cf_sk->headroom + cf_sk->tailroom;
+
ret = -ENOMEM;
skb = sock_alloc_send_skb(sk, buffer_size, noblock, &ret);
- if (!skb)
+
+ if (!skb || skb_tailroom(skb) < buffer_size)
goto err;
- skb_reserve(skb, CAIF_NEEDED_HEADROOM);
+
+ skb_reserve(skb, cf_sk->headroom);
ret = memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len);
@@ -645,7 +651,6 @@ static int caif_stream_sendmsg(struct kiocb *kiocb, struct socket *sock,
long timeo;
err = -EOPNOTSUPP;
-
if (unlikely(msg->msg_flags&MSG_OOB))
goto out_err;
@@ -662,8 +667,8 @@ static int caif_stream_sendmsg(struct kiocb *kiocb, struct socket *sock,
size = len-sent;
- if (size > CAIF_MAX_PAYLOAD_SIZE)
- size = CAIF_MAX_PAYLOAD_SIZE;
+ if (size > cf_sk->maxframe)
+ size = cf_sk->maxframe;
/* If size is more than half of sndbuf, chop up message */
if (size > ((sk->sk_sndbuf >> 1) - 64))
@@ -673,14 +678,14 @@ static int caif_stream_sendmsg(struct kiocb *kiocb, struct socket *sock,
size = SKB_MAX_ALLOC;
skb = sock_alloc_send_skb(sk,
- size + CAIF_NEEDED_HEADROOM
- + CAIF_NEEDED_TAILROOM,
+ size + cf_sk->headroom +
+ cf_sk->tailroom,
msg->msg_flags&MSG_DONTWAIT,
&err);
if (skb == NULL)
goto out_err;
- skb_reserve(skb, CAIF_NEEDED_HEADROOM);
+ skb_reserve(skb, cf_sk->headroom);
/*
* If you pass two values to the sock_alloc_send_skb
* it tries to grab the large buffer with GFP_NOFS
@@ -821,17 +826,15 @@ static int caif_connect(struct socket *sock, struct sockaddr *uaddr,
struct caifsock *cf_sk = container_of(sk, struct caifsock, sk);
long timeo;
int err;
+ int ifindex, headroom, tailroom;
+ struct net_device *dev;
+
lock_sock(sk);
err = -EAFNOSUPPORT;
if (uaddr->sa_family != AF_CAIF)
goto out;
- err = -ESOCKTNOSUPPORT;
- if (unlikely(!(sk->sk_type == SOCK_STREAM &&
- cf_sk->sk.sk_protocol == CAIFPROTO_AT) &&
- sk->sk_type != SOCK_SEQPACKET))
- goto out;
switch (sock->state) {
case SS_UNCONNECTED:
/* Normal case, a fresh connect */
@@ -874,8 +877,7 @@ static int caif_connect(struct socket *sock, struct sockaddr *uaddr,
sk_stream_kill_queues(&cf_sk->sk);
err = -EINVAL;
- if (addr_len != sizeof(struct sockaddr_caif) ||
- !uaddr)
+ if (addr_len != sizeof(struct sockaddr_caif))
goto out;
memcpy(&cf_sk->conn_req.sockaddr, uaddr,
@@ -888,12 +890,23 @@ static int caif_connect(struct socket *sock, struct sockaddr *uaddr,
dbfs_atomic_inc(&cnt.num_connect_req);
cf_sk->layer.receive = caif_sktrecv_cb;
err = caif_connect_client(&cf_sk->conn_req,
- &cf_sk->layer);
+ &cf_sk->layer, &ifindex, &headroom, &tailroom);
if (err < 0) {
cf_sk->sk.sk_socket->state = SS_UNCONNECTED;
cf_sk->sk.sk_state = CAIF_DISCONNECTED;
goto out;
}
+ dev = dev_get_by_index(sock_net(sk), ifindex);
+ cf_sk->headroom = LL_RESERVED_SPACE_EXTRA(dev, headroom);
+ cf_sk->tailroom = tailroom;
+ cf_sk->maxframe = dev->mtu - (headroom + tailroom);
+ dev_put(dev);
+ if (cf_sk->maxframe < 1) {
+ pr_warning("CAIF: %s(): CAIF Interface MTU too small (%d)\n",
+ __func__, dev->mtu);
+ err = -ENODEV;
+ goto out;
+ }
err = -EINPROGRESS;
wait_connect:
diff --git a/net/caif/cfcnfg.c b/net/caif/cfcnfg.c
index df43f264d9f..1c29189b344 100644
--- a/net/caif/cfcnfg.c
+++ b/net/caif/cfcnfg.c
@@ -6,6 +6,7 @@
#include <linux/kernel.h>
#include <linux/stddef.h>
#include <linux/slab.h>
+#include <linux/netdevice.h>
#include <net/caif/caif_layer.h>
#include <net/caif/cfpkt.h>
#include <net/caif/cfcnfg.h>
@@ -22,6 +23,7 @@
#define PHY_NAME_LEN 20
#define container_obj(layr) container_of(layr, struct cfcnfg, layer)
+#define RFM_FRAGMENT_SIZE 4030
/* Information about CAIF physical interfaces held by Config Module in order
* to manage physical interfaces
@@ -41,6 +43,15 @@ struct cfcnfg_phyinfo {
/* Information about the physical device */
struct dev_info dev_info;
+
+ /* Interface index */
+ int ifindex;
+
+ /* Use Start of frame extension */
+ bool use_stx;
+
+ /* Use Start of frame checksum */
+ bool use_fcs;
};
struct cfcnfg {
@@ -248,9 +259,20 @@ static void cfcnfg_linkdestroy_rsp(struct cflayer *layer, u8 channel_id)
{
}
+int protohead[CFCTRL_SRV_MASK] = {
+ [CFCTRL_SRV_VEI] = 4,
+ [CFCTRL_SRV_DATAGRAM] = 7,
+ [CFCTRL_SRV_UTIL] = 4,
+ [CFCTRL_SRV_RFM] = 3,
+ [CFCTRL_SRV_DBG] = 3,
+};
+
int cfcnfg_add_adaptation_layer(struct cfcnfg *cnfg,
struct cfctrl_link_param *param,
- struct cflayer *adap_layer)
+ struct cflayer *adap_layer,
+ int *ifindex,
+ int *proto_head,
+ int *proto_tail)
{
struct cflayer *frml;
if (adap_layer == NULL) {
@@ -276,6 +298,14 @@ int cfcnfg_add_adaptation_layer(struct cfcnfg *cnfg,
param->phyid);
caif_assert(cnfg->phy_layers[param->phyid].phy_layer->id ==
param->phyid);
+
+ *ifindex = cnfg->phy_layers[param->phyid].ifindex;
+ *proto_head =
+ protohead[param->linktype]+
+ (cnfg->phy_layers[param->phyid].use_stx ? 1 : 0);
+
+ *proto_tail = 2;
+
/* FIXME: ENUMERATE INITIALLY WHEN ACTIVATING PHYSICAL INTERFACE */
cfctrl_enum_req(cnfg->ctrl, param->phyid);
return cfctrl_linkup_request(cnfg->ctrl, param, adap_layer);
@@ -297,6 +327,8 @@ cfcnfg_linkup_rsp(struct cflayer *layer, u8 channel_id, enum cfctrl_srv serv,
struct cfcnfg *cnfg = container_obj(layer);
struct cflayer *servicel = NULL;
struct cfcnfg_phyinfo *phyinfo;
+ struct net_device *netdev;
+
if (adapt_layer == NULL) {
pr_debug("CAIF: %s(): link setup response "
"but no client exist, send linkdown back\n",
@@ -308,19 +340,15 @@ cfcnfg_linkup_rsp(struct cflayer *layer, u8 channel_id, enum cfctrl_srv serv,
caif_assert(cnfg != NULL);
caif_assert(phyid != 0);
phyinfo = &cnfg->phy_layers[phyid];
- caif_assert(phyinfo != NULL);
caif_assert(phyinfo->id == phyid);
caif_assert(phyinfo->phy_layer != NULL);
caif_assert(phyinfo->phy_layer->id == phyid);
- if (phyinfo != NULL &&
- phyinfo->phy_ref_count++ == 0 &&
- phyinfo->phy_layer != NULL &&
+ phyinfo->phy_ref_count++;
+ if (phyinfo->phy_ref_count == 1 &&
phyinfo->phy_layer->modemcmd != NULL) {
- caif_assert(phyinfo->phy_layer->id == phyid);
phyinfo->phy_layer->modemcmd(phyinfo->phy_layer,
_CAIF_MODEMCMD_PHYIF_USEFULL);
-
}
adapt_layer->id = channel_id;
@@ -332,7 +360,9 @@ cfcnfg_linkup_rsp(struct cflayer *layer, u8 channel_id, enum cfctrl_srv serv,
servicel = cfdgml_create(channel_id, &phyinfo->dev_info);
break;
case CFCTRL_SRV_RFM:
- servicel = cfrfml_create(channel_id, &phyinfo->dev_info);
+ netdev = phyinfo->dev_info.dev;
+ servicel = cfrfml_create(channel_id, &phyinfo->dev_info,
+ netdev->mtu);
break;
case CFCTRL_SRV_UTIL:
servicel = cfutill_create(channel_id, &phyinfo->dev_info);
@@ -363,8 +393,8 @@ cfcnfg_linkup_rsp(struct cflayer *layer, u8 channel_id, enum cfctrl_srv serv,
void
cfcnfg_add_phy_layer(struct cfcnfg *cnfg, enum cfcnfg_phy_type phy_type,
- void *dev, struct cflayer *phy_layer, u16 *phyid,
- enum cfcnfg_phy_preference pref,
+ struct net_device *dev, struct cflayer *phy_layer,
+ u16 *phyid, enum cfcnfg_phy_preference pref,
bool fcs, bool stx)
{
struct cflayer *frml;
@@ -418,6 +448,10 @@ cfcnfg_add_phy_layer(struct cfcnfg *cnfg, enum cfcnfg_phy_type phy_type,
cnfg->phy_layers[*phyid].dev_info.dev = dev;
cnfg->phy_layers[*phyid].phy_layer = phy_layer;
cnfg->phy_layers[*phyid].phy_ref_count = 0;
+ cnfg->phy_layers[*phyid].ifindex = dev->ifindex;
+ cnfg->phy_layers[*phyid].use_stx = stx;
+ cnfg->phy_layers[*phyid].use_fcs = fcs;
+
phy_layer->type = phy_type;
frml = cffrml_create(*phyid, fcs);
if (!frml) {
diff --git a/net/caif/cfctrl.c b/net/caif/cfctrl.c
index fcfda98a5e6..563145fdc4c 100644
--- a/net/caif/cfctrl.c
+++ b/net/caif/cfctrl.c
@@ -19,7 +19,7 @@
#ifdef CAIF_NO_LOOP
static int handle_loop(struct cfctrl *ctrl,
int cmd, struct cfpkt *pkt){
- return CAIF_FAILURE;
+ return -1;
}
#else
static int handle_loop(struct cfctrl *ctrl,
@@ -43,7 +43,7 @@ struct cflayer *cfctrl_create(void)
memset(&dev_info, 0, sizeof(dev_info));
dev_info.id = 0xff;
memset(this, 0, sizeof(*this));
- cfsrvl_init(&this->serv, 0, &dev_info);
+ cfsrvl_init(&this->serv, 0, &dev_info, false);
atomic_set(&this->req_seq_no, 1);
atomic_set(&this->rsp_seq_no, 1);
this->serv.layer.receive = cfctrl_recv;
@@ -395,7 +395,7 @@ static int cfctrl_recv(struct cflayer *layer, struct cfpkt *pkt)
cmd = cmdrsp & CFCTRL_CMD_MASK;
if (cmd != CFCTRL_CMD_LINK_ERR
&& CFCTRL_RSP_BIT != (CFCTRL_RSP_BIT & cmdrsp)) {
- if (handle_loop(cfctrl, cmd, pkt) == CAIF_FAILURE)
+ if (handle_loop(cfctrl, cmd, pkt) != 0)
cmdrsp |= CFCTRL_ERR_BIT;
}
@@ -647,6 +647,6 @@ found:
default:
break;
}
- return CAIF_SUCCESS;
+ return 0;
}
#endif
diff --git a/net/caif/cfdbgl.c b/net/caif/cfdbgl.c
index ab6b6dc34cf..676648cac8d 100644
--- a/net/caif/cfdbgl.c
+++ b/net/caif/cfdbgl.c
@@ -22,7 +22,7 @@ struct cflayer *cfdbgl_create(u8 channel_id, struct dev_info *dev_info)
}
caif_assert(offsetof(struct cfsrvl, layer) == 0);
memset(dbg, 0, sizeof(struct cfsrvl));
- cfsrvl_init(dbg, channel_id, dev_info);
+ cfsrvl_init(dbg, channel_id, dev_info, false);
dbg->layer.receive = cfdbgl_receive;
dbg->layer.transmit = cfdbgl_transmit;
snprintf(dbg->layer.name, CAIF_LAYER_NAME_SZ - 1, "dbg%d", channel_id);
diff --git a/net/caif/cfdgml.c b/net/caif/cfdgml.c
index 53194840ecb..ed9d53aff28 100644
--- a/net/caif/cfdgml.c
+++ b/net/caif/cfdgml.c
@@ -17,6 +17,7 @@
#define DGM_FLOW_OFF 0x81
#define DGM_FLOW_ON 0x80
#define DGM_CTRL_PKT_SIZE 1
+#define DGM_MTU 1500
static int cfdgml_receive(struct cflayer *layr, struct cfpkt *pkt);
static int cfdgml_transmit(struct cflayer *layr, struct cfpkt *pkt);
@@ -30,7 +31,7 @@ struct cflayer *cfdgml_create(u8 channel_id, struct dev_info *dev_info)
}
caif_assert(offsetof(struct cfsrvl, layer) == 0);
memset(dgm, 0, sizeof(struct cfsrvl));
- cfsrvl_init(dgm, channel_id, dev_info);
+ cfsrvl_init(dgm, channel_id, dev_info, true);
dgm->layer.receive = cfdgml_receive;
dgm->layer.transmit = cfdgml_transmit;
snprintf(dgm->layer.name, CAIF_LAYER_NAME_SZ - 1, "dgm%d", channel_id);
@@ -89,6 +90,10 @@ static int cfdgml_transmit(struct cflayer *layr, struct cfpkt *pkt)
if (!cfsrvl_ready(service, &ret))
return ret;
+ /* STE Modem cannot handle more than 1500 bytes datagrams */
+ if (cfpkt_getlen(pkt) > DGM_MTU)
+ return -EMSGSIZE;
+
cfpkt_add_head(pkt, &zero, 4);
/* Add info for MUX-layer to route the packet out. */
diff --git a/net/caif/cfpkt_skbuff.c b/net/caif/cfpkt_skbuff.c
index a6fdf899741..01f238ff234 100644
--- a/net/caif/cfpkt_skbuff.c
+++ b/net/caif/cfpkt_skbuff.c
@@ -9,8 +9,8 @@
#include <linux/hardirq.h>
#include <net/caif/cfpkt.h>
-#define PKT_PREFIX CAIF_NEEDED_HEADROOM
-#define PKT_POSTFIX CAIF_NEEDED_TAILROOM
+#define PKT_PREFIX 16
+#define PKT_POSTFIX 2
#define PKT_LEN_WHEN_EXTENDING 128
#define PKT_ERROR(pkt, errmsg) do { \
cfpkt_priv(pkt)->erronous = true; \
@@ -338,7 +338,6 @@ struct cfpkt *cfpkt_append(struct cfpkt *dstpkt,
u16 dstlen;
u16 createlen;
if (unlikely(is_erronous(dstpkt) || is_erronous(addpkt))) {
- cfpkt_destroy(addpkt);
return dstpkt;
}
if (expectlen > addlen)
diff --git a/net/caif/cfrfml.c b/net/caif/cfrfml.c
index fd27b172fb5..eb1602022ac 100644
--- a/net/caif/cfrfml.c
+++ b/net/caif/cfrfml.c
@@ -7,102 +7,304 @@
#include <linux/stddef.h>
#include <linux/spinlock.h>
#include <linux/slab.h>
+#include <linux/unaligned/le_byteshift.h>
#include <net/caif/caif_layer.h>
#include <net/caif/cfsrvl.h>
#include <net/caif/cfpkt.h>
-#define container_obj(layr) container_of(layr, struct cfsrvl, layer)
-
+#define container_obj(layr) container_of(layr, struct cfrfml, serv.layer)
#define RFM_SEGMENTATION_BIT 0x01
-#define RFM_PAYLOAD 0x00
-#define RFM_CMD_BIT 0x80
-#define RFM_FLOW_OFF 0x81
-#define RFM_FLOW_ON 0x80
-#define RFM_SET_PIN 0x82
-#define RFM_CTRL_PKT_SIZE 1
+#define RFM_HEAD_SIZE 7
static int cfrfml_receive(struct cflayer *layr, struct cfpkt *pkt);
static int cfrfml_transmit(struct cflayer *layr, struct cfpkt *pkt);
-static int cfservl_modemcmd(struct cflayer *layr, enum caif_modemcmd ctrl);
-struct cflayer *cfrfml_create(u8 channel_id, struct dev_info *dev_info)
+struct cfrfml {
+ struct cfsrvl serv;
+ struct cfpkt *incomplete_frm;
+ int fragment_size;
+ u8 seghead[6];
+ u16 pdu_size;
+ /* Protects serialized processing of packets */
+ spinlock_t sync;
+};
+
+static void cfrfml_release(struct kref *kref)
+{
+ struct cfsrvl *srvl = container_of(kref, struct cfsrvl, ref);
+ struct cfrfml *rfml = container_obj(&srvl->layer);
+
+ if (rfml->incomplete_frm)
+ cfpkt_destroy(rfml->incomplete_frm);
+
+ kfree(srvl);
+}
+
+struct cflayer *cfrfml_create(u8 channel_id, struct dev_info *dev_info,
+ int mtu_size)
{
- struct cfsrvl *rfm = kmalloc(sizeof(struct cfsrvl), GFP_ATOMIC);
- if (!rfm) {
+ int tmp;
+ struct cfrfml *this =
+ kzalloc(sizeof(struct cfrfml), GFP_ATOMIC);
+
+ if (!this) {
pr_warning("CAIF: %s(): Out of memory\n", __func__);
return NULL;
}
- caif_assert(offsetof(struct cfsrvl, layer) == 0);
- memset(rfm, 0, sizeof(struct cfsrvl));
- cfsrvl_init(rfm, channel_id, dev_info);
- rfm->layer.modemcmd = cfservl_modemcmd;
- rfm->layer.receive = cfrfml_receive;
- rfm->layer.transmit = cfrfml_transmit;
- snprintf(rfm->layer.name, CAIF_LAYER_NAME_SZ, "rfm%d", channel_id);
- return &rfm->layer;
+
+ cfsrvl_init(&this->serv, channel_id, dev_info, false);
+ this->serv.release = cfrfml_release;
+ this->serv.layer.receive = cfrfml_receive;
+ this->serv.layer.transmit = cfrfml_transmit;
+
+ /* Round down to closest multiple of 16 */
+ tmp = (mtu_size - RFM_HEAD_SIZE - 6) / 16;
+ tmp *= 16;
+
+ this->fragment_size = tmp;
+ spin_lock_init(&this->sync);
+ snprintf(this->serv.layer.name, CAIF_LAYER_NAME_SZ,
+ "rfm%d", channel_id);
+
+ return &this->serv.layer;
}
-static int cfservl_modemcmd(struct cflayer *layr, enum caif_modemcmd ctrl)
+static struct cfpkt *rfm_append(struct cfrfml *rfml, char *seghead,
+ struct cfpkt *pkt, int *err)
{
- return -EPROTO;
+ struct cfpkt *tmppkt;
+ *err = -EPROTO;
+ /* n-th but not last segment */
+
+ if (cfpkt_extr_head(pkt, seghead, 6) < 0)
+ return NULL;
+
+ /* Verify correct header */
+ if (memcmp(seghead, rfml->seghead, 6) != 0)
+ return NULL;
+
+ tmppkt = cfpkt_append(rfml->incomplete_frm, pkt,
+ rfml->pdu_size + RFM_HEAD_SIZE);
+
+ /* If cfpkt_append failes input pkts are not freed */
+ *err = -ENOMEM;
+ if (tmppkt == NULL)
+ return NULL;
+
+ *err = 0;
+ return tmppkt;
}
static int cfrfml_receive(struct cflayer *layr, struct cfpkt *pkt)
{
u8 tmp;
bool segmented;
- int ret;
+ int err;
+ u8 seghead[6];
+ struct cfrfml *rfml;
+ struct cfpkt *tmppkt = NULL;
+
caif_assert(layr->up != NULL);
caif_assert(layr->receive != NULL);
+ rfml = container_obj(layr);
+ spin_lock(&rfml->sync);
+
+ err = -EPROTO;
+ if (cfpkt_extr_head(pkt, &tmp, 1) < 0)
+ goto out;
+ segmented = tmp & RFM_SEGMENTATION_BIT;
+
+ if (segmented) {
+ if (rfml->incomplete_frm == NULL) {
+ /* Initial Segment */
+ if (cfpkt_peek_head(pkt, rfml->seghead, 6) < 0)
+ goto out;
+
+ rfml->pdu_size = get_unaligned_le16(rfml->seghead+4);
+
+ if (cfpkt_erroneous(pkt))
+ goto out;
+ rfml->incomplete_frm = pkt;
+ pkt = NULL;
+ } else {
+
+ tmppkt = rfm_append(rfml, seghead, pkt, &err);
+ if (tmppkt == NULL)
+ goto out;
+
+ if (cfpkt_erroneous(tmppkt))
+ goto out;
+
+ rfml->incomplete_frm = tmppkt;
+
+
+ if (cfpkt_erroneous(tmppkt))
+ goto out;
+ }
+ err = 0;
+ goto out;
+ }
+
+ if (rfml->incomplete_frm) {
+
+ /* Last Segment */
+ tmppkt = rfm_append(rfml, seghead, pkt, &err);
+ if (tmppkt == NULL)
+ goto out;
+
+ if (cfpkt_erroneous(tmppkt))
+ goto out;
+
+ rfml->incomplete_frm = NULL;
+ pkt = tmppkt;
+ tmppkt = NULL;
+
+ /* Verify that length is correct */
+ err = EPROTO;
+ if (rfml->pdu_size != cfpkt_getlen(pkt) - RFM_HEAD_SIZE + 1)
+ goto out;
+ }
+
+ err = rfml->serv.layer.up->receive(rfml->serv.layer.up, pkt);
+
+out:
+
+ if (err != 0) {
+ if (tmppkt)
+ cfpkt_destroy(tmppkt);
+ if (pkt)
+ cfpkt_destroy(pkt);
+ if (rfml->incomplete_frm)
+ cfpkt_destroy(rfml->incomplete_frm);
+ rfml->incomplete_frm = NULL;
+
+ pr_info("CAIF: %s(): "
+ "Connection error %d triggered on RFM link\n",
+ __func__, err);
+
+ /* Trigger connection error upon failure.*/
+ layr->up->ctrlcmd(layr->up, CAIF_CTRLCMD_REMOTE_SHUTDOWN_IND,
+ rfml->serv.dev_info.id);
+ }
+ spin_unlock(&rfml->sync);
+ return err;
+}
+
+
+static int cfrfml_transmit_segment(struct cfrfml *rfml, struct cfpkt *pkt)
+{
+ caif_assert(cfpkt_getlen(pkt) >= rfml->fragment_size);
+
+ /* Add info for MUX-layer to route the packet out. */
+ cfpkt_info(pkt)->channel_id = rfml->serv.layer.id;
/*
- * RFM is taking care of segmentation and stripping of
- * segmentation bit.
+ * To optimize alignment, we add up the size of CAIF header before
+ * payload.
*/
- if (cfpkt_extr_head(pkt, &tmp, 1) < 0) {
- pr_err("CAIF: %s(): Packet is erroneous!\n", __func__);
- cfpkt_destroy(pkt);
- return -EPROTO;
- }
- segmented = tmp & RFM_SEGMENTATION_BIT;
- caif_assert(!segmented);
+ cfpkt_info(pkt)->hdr_len = RFM_HEAD_SIZE;
+ cfpkt_info(pkt)->dev_info = &rfml->serv.dev_info;
- ret = layr->up->receive(layr->up, pkt);
- return ret;
+ return rfml->serv.layer.dn->transmit(rfml->serv.layer.dn, pkt);
}
static int cfrfml_transmit(struct cflayer *layr, struct cfpkt *pkt)
{
- u8 tmp = 0;
- int ret;
- struct cfsrvl *service = container_obj(layr);
+ int err;
+ u8 seg;
+ u8 head[6];
+ struct cfpkt *rearpkt = NULL;
+ struct cfpkt *frontpkt = pkt;
+ struct cfrfml *rfml = container_obj(layr);
caif_assert(layr->dn != NULL);
caif_assert(layr->dn->transmit != NULL);
- if (!cfsrvl_ready(service, &ret))
- return ret;
+ if (!cfsrvl_ready(&rfml->serv, &err))
+ return err;
+
+ err = -EPROTO;
+ if (cfpkt_getlen(pkt) <= RFM_HEAD_SIZE-1)
+ goto out;
+
+ err = 0;
+ if (cfpkt_getlen(pkt) > rfml->fragment_size + RFM_HEAD_SIZE)
+ err = cfpkt_peek_head(pkt, head, 6);
+
+ if (err < 0)
+ goto out;
+
+ while (cfpkt_getlen(frontpkt) > rfml->fragment_size + RFM_HEAD_SIZE) {
+
+ seg = 1;
+ err = -EPROTO;
+
+ if (cfpkt_add_head(frontpkt, &seg, 1) < 0)
+ goto out;
+ /*
+ * On OOM error cfpkt_split returns NULL.
+ *
+ * NOTE: Segmented pdu is not correctly aligned.
+ * This has negative performance impact.
+ */
+
+ rearpkt = cfpkt_split(frontpkt, rfml->fragment_size);
+ if (rearpkt == NULL)
+ goto out;
+
+ err = cfrfml_transmit_segment(rfml, frontpkt);
+
+ if (err != 0)
+ goto out;
+ frontpkt = rearpkt;
+ rearpkt = NULL;
+
+ err = -ENOMEM;
+ if (frontpkt == NULL)
+ goto out;
+ err = -EPROTO;
+ if (cfpkt_add_head(frontpkt, head, 6) < 0)
+ goto out;
- if (cfpkt_getlen(pkt) > CAIF_MAX_PAYLOAD_SIZE) {
- pr_err("CAIF: %s():Packet too large - size=%d\n",
- __func__, cfpkt_getlen(pkt));
- return -EOVERFLOW;
}
- if (cfpkt_add_head(pkt, &tmp, 1) < 0) {
- pr_err("CAIF: %s(): Packet is erroneous!\n", __func__);
- return -EPROTO;
+
+ seg = 0;
+ err = -EPROTO;
+
+ if (cfpkt_add_head(frontpkt, &seg, 1) < 0)
+ goto out;
+
+ err = cfrfml_transmit_segment(rfml, frontpkt);
+
+ frontpkt = NULL;
+out:
+
+ if (err != 0) {
+ pr_info("CAIF: %s(): "
+ "Connection error %d triggered on RFM link\n",
+ __func__, err);
+ /* Trigger connection error upon failure.*/
+
+ layr->up->ctrlcmd(layr->up, CAIF_CTRLCMD_REMOTE_SHUTDOWN_IND,
+ rfml->serv.dev_info.id);
+
+ if (rearpkt)
+ cfpkt_destroy(rearpkt);
+
+ if (frontpkt && frontpkt != pkt) {
+
+ cfpkt_destroy(frontpkt);
+ /*
+ * Socket layer will free the original packet,
+ * but this packet may already be sent and
+ * freed. So we have to return 0 in this case
+ * to avoid socket layer to re-free this packet.
+ * The return of shutdown indication will
+ * cause connection to be invalidated anyhow.
+ */
+ err = 0;
+ }
}
- /* Add info for MUX-layer to route the packet out. */
- cfpkt_info(pkt)->channel_id = service->layer.id;
- /*
- * To optimize alignment, we add up the size of CAIF header before
- * payload.
- */
- cfpkt_info(pkt)->hdr_len = 1;
- cfpkt_info(pkt)->dev_info = &service->dev_info;
- ret = layr->dn->transmit(layr->dn, pkt);
- if (ret < 0)
- cfpkt_extr_head(pkt, &tmp, 1);
- return ret;
+ return err;
}
diff --git a/net/caif/cfserl.c b/net/caif/cfserl.c
index 965c5baace4..a11fbd68a13 100644
--- a/net/caif/cfserl.c
+++ b/net/caif/cfserl.c
@@ -14,7 +14,8 @@
#define container_obj(layr) ((struct cfserl *) layr)
#define CFSERL_STX 0x02
-#define CAIF_MINIUM_PACKET_SIZE 4
+#define SERIAL_MINIUM_PACKET_SIZE 4
+#define SERIAL_MAX_FRAMESIZE 4096
struct cfserl {
struct cflayer layer;
struct cfpkt *incomplete_frm;
@@ -119,8 +120,8 @@ static int cfserl_receive(struct cflayer *l, struct cfpkt *newpkt)
/*
* Frame error handling
*/
- if (expectlen < CAIF_MINIUM_PACKET_SIZE
- || expectlen > CAIF_MAX_FRAMESIZE) {
+ if (expectlen < SERIAL_MINIUM_PACKET_SIZE
+ || expectlen > SERIAL_MAX_FRAMESIZE) {
if (!layr->usestx) {
if (pkt != NULL)
cfpkt_destroy(pkt);
diff --git a/net/caif/cfsrvl.c b/net/caif/cfsrvl.c
index 6e5b7079a68..f40939a9121 100644
--- a/net/caif/cfsrvl.c
+++ b/net/caif/cfsrvl.c
@@ -24,8 +24,10 @@ static void cfservl_ctrlcmd(struct cflayer *layr, enum caif_ctrlcmd ctrl,
int phyid)
{
struct cfsrvl *service = container_obj(layr);
+
caif_assert(layr->up != NULL);
caif_assert(layr->up->ctrlcmd != NULL);
+
switch (ctrl) {
case CAIF_CTRLCMD_INIT_RSP:
service->open = true;
@@ -89,9 +91,14 @@ static void cfservl_ctrlcmd(struct cflayer *layr, enum caif_ctrlcmd ctrl,
static int cfservl_modemcmd(struct cflayer *layr, enum caif_modemcmd ctrl)
{
struct cfsrvl *service = container_obj(layr);
+
caif_assert(layr != NULL);
caif_assert(layr->dn != NULL);
caif_assert(layr->dn->transmit != NULL);
+
+ if (!service->supports_flowctrl)
+ return 0;
+
switch (ctrl) {
case CAIF_MODEMCMD_FLOW_ON_REQ:
{
@@ -152,9 +159,17 @@ void cfservl_destroy(struct cflayer *layer)
kfree(layer);
}
+void cfsrvl_release(struct kref *kref)
+{
+ struct cfsrvl *service = container_of(kref, struct cfsrvl, ref);
+ kfree(service);
+}
+
void cfsrvl_init(struct cfsrvl *service,
- u8 channel_id,
- struct dev_info *dev_info)
+ u8 channel_id,
+ struct dev_info *dev_info,
+ bool supports_flowctrl
+ )
{
caif_assert(offsetof(struct cfsrvl, layer) == 0);
service->open = false;
@@ -164,14 +179,11 @@ void cfsrvl_init(struct cfsrvl *service,
service->layer.ctrlcmd = cfservl_ctrlcmd;
service->layer.modemcmd = cfservl_modemcmd;
service->dev_info = *dev_info;
+ service->supports_flowctrl = supports_flowctrl;
+ service->release = cfsrvl_release;
kref_init(&service->ref);
}
-void cfsrvl_release(struct kref *kref)
-{
- struct cfsrvl *service = container_of(kref, struct cfsrvl, ref);
- kfree(service);
-}
bool cfsrvl_ready(struct cfsrvl *service, int *err)
{
diff --git a/net/caif/cfutill.c b/net/caif/cfutill.c
index 5fd2c9ea8b4..02795aff57a 100644
--- a/net/caif/cfutill.c
+++ b/net/caif/cfutill.c
@@ -31,7 +31,7 @@ struct cflayer *cfutill_create(u8 channel_id, struct dev_info *dev_info)
}
caif_assert(offsetof(struct cfsrvl, layer) == 0);
memset(util, 0, sizeof(struct cfsrvl));
- cfsrvl_init(util, channel_id, dev_info);
+ cfsrvl_init(util, channel_id, dev_info, true);
util->layer.receive = cfutill_receive;
util->layer.transmit = cfutill_transmit;
snprintf(util->layer.name, CAIF_LAYER_NAME_SZ - 1, "util1");
@@ -90,12 +90,6 @@ static int cfutill_transmit(struct cflayer *layr, struct cfpkt *pkt)
if (!cfsrvl_ready(service, &ret))
return ret;
- if (cfpkt_getlen(pkt) > CAIF_MAX_PAYLOAD_SIZE) {
- pr_err("CAIF: %s(): packet too large size=%d\n",
- __func__, cfpkt_getlen(pkt));
- return -EOVERFLOW;
- }
-
cfpkt_add_head(pkt, &zero, 1);
/* Add info for MUX-layer to route the packet out. */
info = cfpkt_info(pkt);
diff --git a/net/caif/cfveil.c b/net/caif/cfveil.c
index e04f7d964e8..77cc09faac9 100644
--- a/net/caif/cfveil.c
+++ b/net/caif/cfveil.c
@@ -30,7 +30,7 @@ struct cflayer *cfvei_create(u8 channel_id, struct dev_info *dev_info)
}
caif_assert(offsetof(struct cfsrvl, layer) == 0);
memset(vei, 0, sizeof(struct cfsrvl));
- cfsrvl_init(vei, channel_id, dev_info);
+ cfsrvl_init(vei, channel_id, dev_info, true);
vei->layer.receive = cfvei_receive;
vei->layer.transmit = cfvei_transmit;
snprintf(vei->layer.name, CAIF_LAYER_NAME_SZ - 1, "vei%d", channel_id);
@@ -84,11 +84,6 @@ static int cfvei_transmit(struct cflayer *layr, struct cfpkt *pkt)
return ret;
caif_assert(layr->dn != NULL);
caif_assert(layr->dn->transmit != NULL);
- if (cfpkt_getlen(pkt) > CAIF_MAX_PAYLOAD_SIZE) {
- pr_warning("CAIF: %s(): Packet too large - size=%d\n",
- __func__, cfpkt_getlen(pkt));
- return -EOVERFLOW;
- }
if (cfpkt_add_head(pkt, &tmp, 1) < 0) {
pr_err("CAIF: %s(): Packet is erroneous!\n", __func__);
diff --git a/net/caif/cfvidl.c b/net/caif/cfvidl.c
index 89ad4ea239f..ada6ee2d48f 100644
--- a/net/caif/cfvidl.c
+++ b/net/caif/cfvidl.c
@@ -27,7 +27,7 @@ struct cflayer *cfvidl_create(u8 channel_id, struct dev_info *dev_info)
caif_assert(offsetof(struct cfsrvl, layer) == 0);
memset(vid, 0, sizeof(struct cfsrvl));
- cfsrvl_init(vid, channel_id, dev_info);
+ cfsrvl_init(vid, channel_id, dev_info, false);
vid->layer.receive = cfvidl_receive;
vid->layer.transmit = cfvidl_transmit;
snprintf(vid->layer.name, CAIF_LAYER_NAME_SZ - 1, "vid1");
diff --git a/net/caif/chnl_net.c b/net/caif/chnl_net.c
index 610966abe2d..4293e190ec5 100644
--- a/net/caif/chnl_net.c
+++ b/net/caif/chnl_net.c
@@ -23,7 +23,7 @@
#include <net/caif/caif_dev.h>
/* GPRS PDP connection has MTU to 1500 */
-#define SIZE_MTU 1500
+#define GPRS_PDP_MTU 1500
/* 5 sec. connect timeout */
#define CONNECT_TIMEOUT (5 * HZ)
#define CAIF_NET_DEFAULT_QUEUE_LEN 500
@@ -232,6 +232,8 @@ static int chnl_net_open(struct net_device *dev)
{
struct chnl_net *priv = NULL;
int result = -1;
+ int llifindex, headroom, tailroom, mtu;
+ struct net_device *lldev;
ASSERT_RTNL();
priv = netdev_priv(dev);
if (!priv) {
@@ -241,41 +243,88 @@ static int chnl_net_open(struct net_device *dev)
if (priv->state != CAIF_CONNECTING) {
priv->state = CAIF_CONNECTING;
- result = caif_connect_client(&priv->conn_req, &priv->chnl);
+ result = caif_connect_client(&priv->conn_req, &priv->chnl,
+ &llifindex, &headroom, &tailroom);
if (result != 0) {
- priv->state = CAIF_DISCONNECTED;
pr_debug("CAIF: %s(): err: "
"Unable to register and open device,"
" Err:%d\n",
__func__,
result);
- return result;
+ goto error;
+ }
+
+ lldev = dev_get_by_index(dev_net(dev), llifindex);
+
+ if (lldev == NULL) {
+ pr_debug("CAIF: %s(): no interface?\n", __func__);
+ result = -ENODEV;
+ goto error;
+ }
+
+ dev->needed_tailroom = tailroom + lldev->needed_tailroom;
+ dev->hard_header_len = headroom + lldev->hard_header_len +
+ lldev->needed_tailroom;
+
+ /*
+ * MTU, head-room etc is not know before we have a
+ * CAIF link layer device available. MTU calculation may
+ * override initial RTNL configuration.
+ * MTU is minimum of current mtu, link layer mtu pluss
+ * CAIF head and tail, and PDP GPRS contexts max MTU.
+ */
+ mtu = min_t(int, dev->mtu, lldev->mtu - (headroom + tailroom));
+ mtu = min_t(int, GPRS_PDP_MTU, mtu);
+ dev_set_mtu(dev, mtu);
+ dev_put(lldev);
+
+ if (mtu < 100) {
+ pr_warning("CAIF: %s(): "
+ "CAIF Interface MTU too small (%d)\n",
+ __func__, mtu);
+ result = -ENODEV;
+ goto error;
}
}
+ rtnl_unlock(); /* Release RTNL lock during connect wait */
+
result = wait_event_interruptible_timeout(priv->netmgmt_wq,
priv->state != CAIF_CONNECTING,
CONNECT_TIMEOUT);
+ rtnl_lock();
+
if (result == -ERESTARTSYS) {
pr_debug("CAIF: %s(): wait_event_interruptible"
" woken by a signal\n", __func__);
- return -ERESTARTSYS;
+ result = -ERESTARTSYS;
+ goto error;
}
+
if (result == 0) {
pr_debug("CAIF: %s(): connect timeout\n", __func__);
caif_disconnect_client(&priv->chnl);
priv->state = CAIF_DISCONNECTED;
pr_debug("CAIF: %s(): state disconnected\n", __func__);
- return -ETIMEDOUT;
+ result = -ETIMEDOUT;
+ goto error;
}
if (priv->state != CAIF_CONNECTED) {
pr_debug("CAIF: %s(): connect failed\n", __func__);
- return -ECONNREFUSED;
+ result = -ECONNREFUSED;
+ goto error;
}
pr_debug("CAIF: %s(): CAIF Netdevice connected\n", __func__);
return 0;
+
+error:
+ caif_disconnect_client(&priv->chnl);
+ priv->state = CAIF_DISCONNECTED;
+ pr_debug("CAIF: %s(): state disconnected\n", __func__);
+ return result;
+
}
static int chnl_net_stop(struct net_device *dev)
@@ -321,9 +370,7 @@ static void ipcaif_net_setup(struct net_device *dev)
dev->destructor = free_netdev;
dev->flags |= IFF_NOARP;
dev->flags |= IFF_POINTOPOINT;
- dev->needed_headroom = CAIF_NEEDED_HEADROOM;
- dev->needed_tailroom = CAIF_NEEDED_TAILROOM;
- dev->mtu = SIZE_MTU;
+ dev->mtu = GPRS_PDP_MTU;
dev->tx_queue_len = CAIF_NET_DEFAULT_QUEUE_LEN;
priv = netdev_priv(dev);
diff --git a/net/can/raw.c b/net/can/raw.c
index da99cf153b3..a10e3338f08 100644
--- a/net/can/raw.c
+++ b/net/can/raw.c
@@ -436,14 +436,9 @@ static int raw_setsockopt(struct socket *sock, int level, int optname,
if (count > 1) {
/* filter does not fit into dfilter => alloc space */
- filter = kmalloc(optlen, GFP_KERNEL);
- if (!filter)
- return -ENOMEM;
-
- if (copy_from_user(filter, optval, optlen)) {
- kfree(filter);
- return -EFAULT;
- }
+ filter = memdup_user(optval, optlen);
+ if (IS_ERR(filter))
+ return PTR_ERR(filter);
} else if (count == 1) {
if (copy_from_user(&sfilter, optval, sizeof(sfilter)))
return -EFAULT;
@@ -655,6 +650,10 @@ static int raw_sendmsg(struct kiocb *iocb, struct socket *sock,
err = sock_tx_timestamp(msg, sk, skb_tx(skb));
if (err < 0)
goto free_skb;
+
+ /* to be able to check the received tx sock reference in raw_rcv() */
+ skb_tx(skb)->prevent_sk_orphan = 1;
+
skb->dev = dev;
skb->sk = sk;
diff --git a/net/compat.c b/net/compat.c
index ec24d9edb02..63d260e8147 100644
--- a/net/compat.c
+++ b/net/compat.c
@@ -81,7 +81,7 @@ int verify_compat_iovec(struct msghdr *kern_msg, struct iovec *kern_iov,
int tot_len;
if (kern_msg->msg_namelen) {
- if (mode==VERIFY_READ) {
+ if (mode == VERIFY_READ) {
int err = move_addr_to_kernel(kern_msg->msg_name,
kern_msg->msg_namelen,
kern_address);
@@ -354,7 +354,7 @@ static int do_set_attach_filter(struct socket *sock, int level, int optname,
static int do_set_sock_timeout(struct socket *sock, int level,
int optname, char __user *optval, unsigned int optlen)
{
- struct compat_timeval __user *up = (struct compat_timeval __user *) optval;
+ struct compat_timeval __user *up = (struct compat_timeval __user *)optval;
struct timeval ktime;
mm_segment_t old_fs;
int err;
@@ -367,7 +367,7 @@ static int do_set_sock_timeout(struct socket *sock, int level,
return -EFAULT;
old_fs = get_fs();
set_fs(KERNEL_DS);
- err = sock_setsockopt(sock, level, optname, (char *) &ktime, sizeof(ktime));
+ err = sock_setsockopt(sock, level, optname, (char *)&ktime, sizeof(ktime));
set_fs(old_fs);
return err;
@@ -389,11 +389,10 @@ asmlinkage long compat_sys_setsockopt(int fd, int level, int optname,
char __user *optval, unsigned int optlen)
{
int err;
- struct socket *sock;
+ struct socket *sock = sockfd_lookup(fd, &err);
- if ((sock = sockfd_lookup(fd, &err))!=NULL)
- {
- err = security_socket_setsockopt(sock,level,optname);
+ if (sock) {
+ err = security_socket_setsockopt(sock, level, optname);
if (err) {
sockfd_put(sock);
return err;
@@ -453,7 +452,7 @@ static int compat_sock_getsockopt(struct socket *sock, int level, int optname,
int compat_sock_get_timestamp(struct sock *sk, struct timeval __user *userstamp)
{
struct compat_timeval __user *ctv =
- (struct compat_timeval __user*) userstamp;
+ (struct compat_timeval __user *) userstamp;
int err = -ENOENT;
struct timeval tv;
@@ -477,7 +476,7 @@ EXPORT_SYMBOL(compat_sock_get_timestamp);
int compat_sock_get_timestampns(struct sock *sk, struct timespec __user *userstamp)
{
struct compat_timespec __user *ctv =
- (struct compat_timespec __user*) userstamp;
+ (struct compat_timespec __user *) userstamp;
int err = -ENOENT;
struct timespec ts;
@@ -502,12 +501,10 @@ asmlinkage long compat_sys_getsockopt(int fd, int level, int optname,
char __user *optval, int __user *optlen)
{
int err;
- struct socket *sock;
+ struct socket *sock = sockfd_lookup(fd, &err);
- if ((sock = sockfd_lookup(fd, &err))!=NULL)
- {
- err = security_socket_getsockopt(sock, level,
- optname);
+ if (sock) {
+ err = security_socket_getsockopt(sock, level, optname);
if (err) {
sockfd_put(sock);
return err;
@@ -531,7 +528,7 @@ struct compat_group_req {
__u32 gr_interface;
struct __kernel_sockaddr_storage gr_group
__attribute__ ((aligned(4)));
-} __attribute__ ((packed));
+} __packed;
struct compat_group_source_req {
__u32 gsr_interface;
@@ -539,7 +536,7 @@ struct compat_group_source_req {
__attribute__ ((aligned(4)));
struct __kernel_sockaddr_storage gsr_source
__attribute__ ((aligned(4)));
-} __attribute__ ((packed));
+} __packed;
struct compat_group_filter {
__u32 gf_interface;
@@ -549,7 +546,7 @@ struct compat_group_filter {
__u32 gf_numsrc;
struct __kernel_sockaddr_storage gf_slist[1]
__attribute__ ((aligned(4)));
-} __attribute__ ((packed));
+} __packed;
#define __COMPAT_GF0_SIZE (sizeof(struct compat_group_filter) - \
sizeof(struct __kernel_sockaddr_storage))
@@ -557,7 +554,7 @@ struct compat_group_filter {
int compat_mc_setsockopt(struct sock *sock, int level, int optname,
char __user *optval, unsigned int optlen,
- int (*setsockopt)(struct sock *,int,int,char __user *,unsigned int))
+ int (*setsockopt)(struct sock *, int, int, char __user *, unsigned int))
{
char __user *koptval = optval;
int koptlen = optlen;
@@ -640,12 +637,11 @@ int compat_mc_setsockopt(struct sock *sock, int level, int optname,
}
return setsockopt(sock, level, optname, koptval, koptlen);
}
-
EXPORT_SYMBOL(compat_mc_setsockopt);
int compat_mc_getsockopt(struct sock *sock, int level, int optname,
char __user *optval, int __user *optlen,
- int (*getsockopt)(struct sock *,int,int,char __user *,int __user *))
+ int (*getsockopt)(struct sock *, int, int, char __user *, int __user *))
{
struct compat_group_filter __user *gf32 = (void *)optval;
struct group_filter __user *kgf;
@@ -681,7 +677,7 @@ int compat_mc_getsockopt(struct sock *sock, int level, int optname,
__put_user(interface, &kgf->gf_interface) ||
__put_user(fmode, &kgf->gf_fmode) ||
__put_user(numsrc, &kgf->gf_numsrc) ||
- copy_in_user(&kgf->gf_group,&gf32->gf_group,sizeof(kgf->gf_group)))
+ copy_in_user(&kgf->gf_group, &gf32->gf_group, sizeof(kgf->gf_group)))
return -EFAULT;
err = getsockopt(sock, level, optname, (char __user *)kgf, koptlen);
@@ -714,21 +710,22 @@ int compat_mc_getsockopt(struct sock *sock, int level, int optname,
copylen = numsrc * sizeof(gf32->gf_slist[0]);
if (copylen > klen)
copylen = klen;
- if (copy_in_user(gf32->gf_slist, kgf->gf_slist, copylen))
+ if (copy_in_user(gf32->gf_slist, kgf->gf_slist, copylen))
return -EFAULT;
}
return err;
}
-
EXPORT_SYMBOL(compat_mc_getsockopt);
/* Argument list sizes for compat_sys_socketcall */
#define AL(x) ((x) * sizeof(u32))
-static unsigned char nas[20]={AL(0),AL(3),AL(3),AL(3),AL(2),AL(3),
- AL(3),AL(3),AL(4),AL(4),AL(4),AL(6),
- AL(6),AL(2),AL(5),AL(5),AL(3),AL(3),
- AL(4),AL(5)};
+static unsigned char nas[20] = {
+ AL(0), AL(3), AL(3), AL(3), AL(2), AL(3),
+ AL(3), AL(3), AL(4), AL(4), AL(4), AL(6),
+ AL(6), AL(2), AL(5), AL(5), AL(3), AL(3),
+ AL(4), AL(5)
+};
#undef AL
asmlinkage long compat_sys_sendmsg(int fd, struct compat_msghdr __user *msg, unsigned flags)
@@ -827,7 +824,7 @@ asmlinkage long compat_sys_socketcall(int call, u32 __user *args)
compat_ptr(a[4]), compat_ptr(a[5]));
break;
case SYS_SHUTDOWN:
- ret = sys_shutdown(a0,a1);
+ ret = sys_shutdown(a0, a1);
break;
case SYS_SETSOCKOPT:
ret = compat_sys_setsockopt(a0, a1, a[2],
diff --git a/net/core/Makefile b/net/core/Makefile
index 51c3eec850e..8a04dd22cf7 100644
--- a/net/core/Makefile
+++ b/net/core/Makefile
@@ -18,4 +18,4 @@ obj-$(CONFIG_NET_DMA) += user_dma.o
obj-$(CONFIG_FIB_RULES) += fib_rules.o
obj-$(CONFIG_TRACEPOINTS) += net-traces.o
obj-$(CONFIG_NET_DROP_MONITOR) += drop_monitor.o
-
+obj-$(CONFIG_NETWORK_PHY_TIMESTAMPING) += timestamping.o
diff --git a/net/core/datagram.c b/net/core/datagram.c
index f5b6f43a4c2..251997a9548 100644
--- a/net/core/datagram.c
+++ b/net/core/datagram.c
@@ -219,6 +219,7 @@ struct sk_buff *skb_recv_datagram(struct sock *sk, unsigned flags,
return __skb_recv_datagram(sk, flags | (noblock ? MSG_DONTWAIT : 0),
&peeked, err);
}
+EXPORT_SYMBOL(skb_recv_datagram);
void skb_free_datagram(struct sock *sk, struct sk_buff *skb)
{
@@ -288,7 +289,6 @@ int skb_kill_datagram(struct sock *sk, struct sk_buff *skb, unsigned int flags)
return err;
}
-
EXPORT_SYMBOL(skb_kill_datagram);
/**
@@ -373,6 +373,7 @@ int skb_copy_datagram_iovec(const struct sk_buff *skb, int offset,
fault:
return -EFAULT;
}
+EXPORT_SYMBOL(skb_copy_datagram_iovec);
/**
* skb_copy_datagram_const_iovec - Copy a datagram to an iovec.
@@ -716,6 +717,7 @@ csum_error:
fault:
return -EFAULT;
}
+EXPORT_SYMBOL(skb_copy_and_csum_datagram_iovec);
/**
* datagram_poll - generic datagram poll
@@ -770,8 +772,4 @@ unsigned int datagram_poll(struct file *file, struct socket *sock,
return mask;
}
-
EXPORT_SYMBOL(datagram_poll);
-EXPORT_SYMBOL(skb_copy_and_csum_datagram_iovec);
-EXPORT_SYMBOL(skb_copy_datagram_iovec);
-EXPORT_SYMBOL(skb_recv_datagram);
diff --git a/net/core/dev.c b/net/core/dev.c
index 1f466e82ac3..e1c1cdcc2bb 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -101,8 +101,6 @@
#include <linux/proc_fs.h>
#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>
@@ -803,35 +801,31 @@ struct net_device *dev_getfirstbyhwtype(struct net *net, unsigned short type)
EXPORT_SYMBOL(dev_getfirstbyhwtype);
/**
- * dev_get_by_flags - find any device with given flags
+ * dev_get_by_flags_rcu - find any device with given flags
* @net: the applicable net namespace
* @if_flags: IFF_* values
* @mask: bitmask of bits in if_flags to check
*
* Search for any interface with the given flags. Returns NULL if a device
- * is not found or a pointer to the device. The device returned has
- * had a reference added and the pointer is safe until the user calls
- * dev_put to indicate they have finished with it.
+ * is not found or a pointer to the device. Must be called inside
+ * rcu_read_lock(), and result refcount is unchanged.
*/
-struct net_device *dev_get_by_flags(struct net *net, unsigned short if_flags,
+struct net_device *dev_get_by_flags_rcu(struct net *net, unsigned short if_flags,
unsigned short mask)
{
struct net_device *dev, *ret;
ret = NULL;
- rcu_read_lock();
for_each_netdev_rcu(net, dev) {
if (((dev->flags ^ if_flags) & mask) == 0) {
- dev_hold(dev);
ret = dev;
break;
}
}
- rcu_read_unlock();
return ret;
}
-EXPORT_SYMBOL(dev_get_by_flags);
+EXPORT_SYMBOL(dev_get_by_flags_rcu);
/**
* dev_valid_name - check if name is okay for network device
@@ -1542,7 +1536,8 @@ static void dev_queue_xmit_nit(struct sk_buff *skb, struct net_device *dev)
if (net_ratelimit())
printk(KERN_CRIT "protocol %04x is "
"buggy, dev %s\n",
- skb2->protocol, dev->name);
+ ntohs(skb2->protocol),
+ dev->name);
skb_reset_network_header(skb2);
}
@@ -1924,6 +1919,22 @@ static inline void skb_orphan_try(struct sk_buff *skb)
}
}
+/*
+ * Returns true if either:
+ * 1. skb has frag_list and the device doesn't support FRAGLIST, or
+ * 2. skb is fragmented and the device does not support SG, or if
+ * at least one of fragments is in highmem and device does not
+ * support DMA from it.
+ */
+static inline int skb_needs_linearize(struct sk_buff *skb,
+ struct net_device *dev)
+{
+ return skb_is_nonlinear(skb) &&
+ ((skb_has_frags(skb) && !(dev->features & NETIF_F_FRAGLIST)) ||
+ (skb_shinfo(skb)->nr_frags && (!(dev->features & NETIF_F_SG) ||
+ illegal_highdma(dev, skb))));
+}
+
int dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev,
struct netdev_queue *txq)
{
@@ -1948,6 +1959,22 @@ int dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev,
goto out_kfree_skb;
if (skb->next)
goto gso;
+ } else {
+ if (skb_needs_linearize(skb, dev) &&
+ __skb_linearize(skb))
+ goto out_kfree_skb;
+
+ /* If packet is not checksummed and device does not
+ * support checksumming for this protocol, complete
+ * checksumming here.
+ */
+ if (skb->ip_summed == CHECKSUM_PARTIAL) {
+ skb_set_transport_header(skb, skb->csum_start -
+ skb_headroom(skb));
+ if (!dev_can_checksum(dev, skb) &&
+ skb_checksum_help(skb))
+ goto out_kfree_skb;
+ }
}
rc = ops->ndo_start_xmit(skb, dev);
@@ -2063,14 +2090,24 @@ static inline int __dev_xmit_skb(struct sk_buff *skb, struct Qdisc *q,
struct netdev_queue *txq)
{
spinlock_t *root_lock = qdisc_lock(q);
+ bool contended = qdisc_is_running(q);
int rc;
+ /*
+ * Heuristic to force contended enqueues to serialize on a
+ * separate lock before trying to get qdisc main lock.
+ * This permits __QDISC_STATE_RUNNING owner to get the lock more often
+ * and dequeue packets faster.
+ */
+ if (unlikely(contended))
+ spin_lock(&q->busylock);
+
spin_lock(root_lock);
if (unlikely(test_bit(__QDISC_STATE_DEACTIVATED, &q->state))) {
kfree_skb(skb);
rc = NET_XMIT_DROP;
} else if ((q->flags & TCQ_F_CAN_BYPASS) && !qdisc_qlen(q) &&
- !test_and_set_bit(__QDISC_STATE_RUNNING, &q->state)) {
+ qdisc_run_begin(q)) {
/*
* This is a work-conserving queue; there are no old skbs
* waiting to be sent out; and the qdisc is not running -
@@ -2079,37 +2116,33 @@ static inline int __dev_xmit_skb(struct sk_buff *skb, struct Qdisc *q,
if (!(dev->priv_flags & IFF_XMIT_DST_RELEASE))
skb_dst_force(skb);
__qdisc_update_bstats(q, skb->len);
- if (sch_direct_xmit(skb, q, dev, txq, root_lock))
+ if (sch_direct_xmit(skb, q, dev, txq, root_lock)) {
+ if (unlikely(contended)) {
+ spin_unlock(&q->busylock);
+ contended = false;
+ }
__qdisc_run(q);
- else
- clear_bit(__QDISC_STATE_RUNNING, &q->state);
+ } else
+ qdisc_run_end(q);
rc = NET_XMIT_SUCCESS;
} else {
skb_dst_force(skb);
rc = qdisc_enqueue_root(skb, q);
- qdisc_run(q);
+ if (qdisc_run_begin(q)) {
+ if (unlikely(contended)) {
+ spin_unlock(&q->busylock);
+ contended = false;
+ }
+ __qdisc_run(q);
+ }
}
spin_unlock(root_lock);
-
+ if (unlikely(contended))
+ spin_unlock(&q->busylock);
return rc;
}
-/*
- * Returns true if either:
- * 1. skb has frag_list and the device doesn't support FRAGLIST, or
- * 2. skb is fragmented and the device does not support SG, or if
- * at least one of fragments is in highmem and device does not
- * support DMA from it.
- */
-static inline int skb_needs_linearize(struct sk_buff *skb,
- struct net_device *dev)
-{
- return (skb_has_frags(skb) && !(dev->features & NETIF_F_FRAGLIST)) ||
- (skb_shinfo(skb)->nr_frags && (!(dev->features & NETIF_F_SG) ||
- illegal_highdma(dev, skb)));
-}
-
/**
* dev_queue_xmit - transmit a buffer
* @skb: buffer to transmit
@@ -2142,25 +2175,6 @@ int dev_queue_xmit(struct sk_buff *skb)
struct Qdisc *q;
int rc = -ENOMEM;
- /* GSO will handle the following emulations directly. */
- if (netif_needs_gso(dev, skb))
- goto gso;
-
- /* Convert a paged skb to linear, if required */
- if (skb_needs_linearize(skb, dev) && __skb_linearize(skb))
- goto out_kfree_skb;
-
- /* If packet is not checksummed and device does not support
- * checksumming for this protocol, complete checksumming here.
- */
- if (skb->ip_summed == CHECKSUM_PARTIAL) {
- skb_set_transport_header(skb, skb->csum_start -
- skb_headroom(skb));
- if (!dev_can_checksum(dev, skb) && skb_checksum_help(skb))
- goto out_kfree_skb;
- }
-
-gso:
/* Disable soft irqs for various locks below. Also
* stops preemption for RCU.
*/
@@ -2219,7 +2233,6 @@ gso:
rc = -ENETDOWN;
rcu_read_unlock_bh();
-out_kfree_skb:
kfree_skb(skb);
return rc;
out:
@@ -2604,70 +2617,14 @@ static inline int deliver_skb(struct sk_buff *skb,
return pt_prev->func(skb, skb->dev, pt_prev, orig_dev);
}
-#if defined(CONFIG_BRIDGE) || defined (CONFIG_BRIDGE_MODULE)
-
-#if defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE)
+#if (defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE)) && \
+ (defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE))
/* This hook is defined here for ATM LANE */
int (*br_fdb_test_addr_hook)(struct net_device *dev,
unsigned char *addr) __read_mostly;
EXPORT_SYMBOL_GPL(br_fdb_test_addr_hook);
#endif
-/*
- * If bridge module is loaded call bridging hook.
- * returns NULL if packet was consumed.
- */
-struct sk_buff *(*br_handle_frame_hook)(struct net_bridge_port *p,
- struct sk_buff *skb) __read_mostly;
-EXPORT_SYMBOL_GPL(br_handle_frame_hook);
-
-static inline struct sk_buff *handle_bridge(struct sk_buff *skb,
- struct packet_type **pt_prev, int *ret,
- struct net_device *orig_dev)
-{
- struct net_bridge_port *port;
-
- if (skb->pkt_type == PACKET_LOOPBACK ||
- (port = rcu_dereference(skb->dev->br_port)) == NULL)
- return skb;
-
- if (*pt_prev) {
- *ret = deliver_skb(skb, *pt_prev, orig_dev);
- *pt_prev = NULL;
- }
-
- return br_handle_frame_hook(port, skb);
-}
-#else
-#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 macvlan_port *p,
- 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)
-{
- struct macvlan_port *port;
-
- port = rcu_dereference(skb->dev->macvlan_port);
- if (!port)
- return skb;
-
- if (*pt_prev) {
- *ret = deliver_skb(skb, *pt_prev, orig_dev);
- *pt_prev = NULL;
- }
- return macvlan_handle_frame_hook(port, 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
@@ -2685,10 +2642,10 @@ static int ing_filter(struct sk_buff *skb)
int result = TC_ACT_OK;
struct Qdisc *q;
- if (MAX_RED_LOOP < ttl++) {
- printk(KERN_WARNING
- "Redir loop detected Dropping packet (%d->%d)\n",
- skb->skb_iif, dev->ifindex);
+ if (unlikely(MAX_RED_LOOP < ttl++)) {
+ if (net_ratelimit())
+ pr_warning( "Redir loop detected Dropping packet (%d->%d)\n",
+ skb->skb_iif, dev->ifindex);
return TC_ACT_SHOT;
}
@@ -2718,9 +2675,6 @@ static inline struct sk_buff *handle_ing(struct sk_buff *skb,
if (*pt_prev) {
*ret = deliver_skb(skb, *pt_prev, orig_dev);
*pt_prev = NULL;
- } else {
- /* Huh? Why does turning on AF_PACKET affect this? */
- skb->tc_verd = SET_TC_OK2MUNGE(skb->tc_verd);
}
switch (ing_filter(skb)) {
@@ -2763,6 +2717,51 @@ void netif_nit_deliver(struct sk_buff *skb)
rcu_read_unlock();
}
+/**
+ * netdev_rx_handler_register - register receive handler
+ * @dev: device to register a handler for
+ * @rx_handler: receive handler to register
+ * @rx_handler_data: data pointer that is used by rx handler
+ *
+ * Register a receive hander for a device. This handler will then be
+ * called from __netif_receive_skb. A negative errno code is returned
+ * on a failure.
+ *
+ * The caller must hold the rtnl_mutex.
+ */
+int netdev_rx_handler_register(struct net_device *dev,
+ rx_handler_func_t *rx_handler,
+ void *rx_handler_data)
+{
+ ASSERT_RTNL();
+
+ if (dev->rx_handler)
+ return -EBUSY;
+
+ rcu_assign_pointer(dev->rx_handler_data, rx_handler_data);
+ rcu_assign_pointer(dev->rx_handler, rx_handler);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(netdev_rx_handler_register);
+
+/**
+ * netdev_rx_handler_unregister - unregister receive handler
+ * @dev: device to unregister a handler from
+ *
+ * Unregister a receive hander from a device.
+ *
+ * The caller must hold the rtnl_mutex.
+ */
+void netdev_rx_handler_unregister(struct net_device *dev)
+{
+
+ ASSERT_RTNL();
+ rcu_assign_pointer(dev->rx_handler, NULL);
+ rcu_assign_pointer(dev->rx_handler_data, NULL);
+}
+EXPORT_SYMBOL_GPL(netdev_rx_handler_unregister);
+
static inline void skb_bond_set_mac_by_master(struct sk_buff *skb,
struct net_device *master)
{
@@ -2784,7 +2783,8 @@ int __skb_bond_should_drop(struct sk_buff *skb, struct net_device *master)
if (master->priv_flags & IFF_MASTER_ARPMON)
dev->last_rx = jiffies;
- if ((master->priv_flags & IFF_MASTER_ALB) && master->br_port) {
+ if ((master->priv_flags & IFF_MASTER_ALB) &&
+ (master->priv_flags & IFF_BRIDGE_PORT)) {
/* Do address unmangle. The local destination address
* will be always the one master has. Provides the right
* functionality in a bridge.
@@ -2815,6 +2815,7 @@ EXPORT_SYMBOL(__skb_bond_should_drop);
static int __netif_receive_skb(struct sk_buff *skb)
{
struct packet_type *ptype, *pt_prev;
+ rx_handler_func_t *rx_handler;
struct net_device *orig_dev;
struct net_device *master;
struct net_device *null_or_orig;
@@ -2856,8 +2857,7 @@ static int __netif_receive_skb(struct sk_buff *skb)
skb->dev = master;
}
- __get_cpu_var(softnet_data).processed++;
-
+ __this_cpu_inc(softnet_data.processed);
skb_reset_network_header(skb);
skb_reset_transport_header(skb);
skb->mac_len = skb->network_header - skb->mac_header;
@@ -2889,12 +2889,17 @@ static int __netif_receive_skb(struct sk_buff *skb)
ncls:
#endif
- 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;
+ /* Handle special case of bridge or macvlan */
+ rx_handler = rcu_dereference(skb->dev->rx_handler);
+ if (rx_handler) {
+ if (pt_prev) {
+ ret = deliver_skb(skb, pt_prev, orig_dev);
+ pt_prev = NULL;
+ }
+ skb = rx_handler(skb);
+ if (!skb)
+ goto out;
+ }
/*
* Make sure frames received on VLAN interfaces stacked on
@@ -2955,6 +2960,9 @@ int netif_receive_skb(struct sk_buff *skb)
if (netdev_tstamp_prequeue)
net_timestamp_check(skb);
+ if (skb_defer_rx_timestamp(skb))
+ return NET_RX_SUCCESS;
+
#ifdef CONFIG_RPS
{
struct rps_dev_flow voidflow, *rflow = &voidflow;
@@ -3719,10 +3727,11 @@ void dev_seq_stop(struct seq_file *seq, void *v)
static void dev_seq_printf_stats(struct seq_file *seq, struct net_device *dev)
{
- const struct net_device_stats *stats = dev_get_stats(dev);
+ struct rtnl_link_stats64 temp;
+ const struct rtnl_link_stats64 *stats = dev_get_stats(dev, &temp);
- seq_printf(seq, "%6s: %7lu %7lu %4lu %4lu %4lu %5lu %10lu %9lu "
- "%8lu %7lu %4lu %4lu %4lu %5lu %7lu %10lu\n",
+ seq_printf(seq, "%6s: %7llu %7llu %4llu %4llu %4llu %5llu %10llu %9llu "
+ "%8llu %7llu %4llu %4llu %4llu %5llu %7llu %10llu\n",
dev->name, stats->rx_bytes, stats->rx_packets,
stats->rx_errors,
stats->rx_dropped + stats->rx_missed_errors,
@@ -5271,20 +5280,22 @@ void netdev_run_todo(void)
/**
* dev_txq_stats_fold - fold tx_queues stats
* @dev: device to get statistics from
- * @stats: struct net_device_stats to hold results
+ * @stats: struct rtnl_link_stats64 to hold results
*/
void dev_txq_stats_fold(const struct net_device *dev,
- struct net_device_stats *stats)
+ struct rtnl_link_stats64 *stats)
{
- unsigned long tx_bytes = 0, tx_packets = 0, tx_dropped = 0;
+ u64 tx_bytes = 0, tx_packets = 0, tx_dropped = 0;
unsigned int i;
struct netdev_queue *txq;
for (i = 0; i < dev->num_tx_queues; i++) {
txq = netdev_get_tx_queue(dev, i);
+ spin_lock_bh(&txq->_xmit_lock);
tx_bytes += txq->tx_bytes;
tx_packets += txq->tx_packets;
tx_dropped += txq->tx_dropped;
+ spin_unlock_bh(&txq->_xmit_lock);
}
if (tx_bytes || tx_packets || tx_dropped) {
stats->tx_bytes = tx_bytes;
@@ -5294,23 +5305,53 @@ void dev_txq_stats_fold(const struct net_device *dev,
}
EXPORT_SYMBOL(dev_txq_stats_fold);
+/* Convert net_device_stats to rtnl_link_stats64. They have the same
+ * fields in the same order, with only the type differing.
+ */
+static void netdev_stats_to_stats64(struct rtnl_link_stats64 *stats64,
+ const struct net_device_stats *netdev_stats)
+{
+#if BITS_PER_LONG == 64
+ BUILD_BUG_ON(sizeof(*stats64) != sizeof(*netdev_stats));
+ memcpy(stats64, netdev_stats, sizeof(*stats64));
+#else
+ size_t i, n = sizeof(*stats64) / sizeof(u64);
+ const unsigned long *src = (const unsigned long *)netdev_stats;
+ u64 *dst = (u64 *)stats64;
+
+ BUILD_BUG_ON(sizeof(*netdev_stats) / sizeof(unsigned long) !=
+ sizeof(*stats64) / sizeof(u64));
+ for (i = 0; i < n; i++)
+ dst[i] = src[i];
+#endif
+}
+
/**
* dev_get_stats - get network device statistics
* @dev: device to get statistics from
+ * @storage: place to store stats
*
- * Get network statistics from device. The device driver may provide
- * its own method by setting dev->netdev_ops->get_stats; otherwise
- * the internal statistics structure is used.
+ * Get network statistics from device. Return @storage.
+ * The device driver may provide its own method by setting
+ * dev->netdev_ops->get_stats64 or dev->netdev_ops->get_stats;
+ * otherwise the internal statistics structure is used.
*/
-const struct net_device_stats *dev_get_stats(struct net_device *dev)
+struct rtnl_link_stats64 *dev_get_stats(struct net_device *dev,
+ struct rtnl_link_stats64 *storage)
{
const struct net_device_ops *ops = dev->netdev_ops;
- if (ops->ndo_get_stats)
- return ops->ndo_get_stats(dev);
-
- dev_txq_stats_fold(dev, &dev->stats);
- return &dev->stats;
+ if (ops->ndo_get_stats64) {
+ memset(storage, 0, sizeof(*storage));
+ return ops->ndo_get_stats64(dev, storage);
+ }
+ if (ops->ndo_get_stats) {
+ netdev_stats_to_stats64(storage, ops->ndo_get_stats(dev));
+ return storage;
+ }
+ netdev_stats_to_stats64(storage, &dev->stats);
+ dev_txq_stats_fold(dev, storage);
+ return storage;
}
EXPORT_SYMBOL(dev_get_stats);
@@ -5815,6 +5856,68 @@ char *netdev_drivername(const struct net_device *dev, char *buffer, int len)
return buffer;
}
+static int __netdev_printk(const char *level, const struct net_device *dev,
+ struct va_format *vaf)
+{
+ int r;
+
+ if (dev && dev->dev.parent)
+ r = dev_printk(level, dev->dev.parent, "%s: %pV",
+ netdev_name(dev), vaf);
+ else if (dev)
+ r = printk("%s%s: %pV", level, netdev_name(dev), vaf);
+ else
+ r = printk("%s(NULL net_device): %pV", level, vaf);
+
+ return r;
+}
+
+int netdev_printk(const char *level, const struct net_device *dev,
+ const char *format, ...)
+{
+ struct va_format vaf;
+ va_list args;
+ int r;
+
+ va_start(args, format);
+
+ vaf.fmt = format;
+ vaf.va = &args;
+
+ r = __netdev_printk(level, dev, &vaf);
+ va_end(args);
+
+ return r;
+}
+EXPORT_SYMBOL(netdev_printk);
+
+#define define_netdev_printk_level(func, level) \
+int func(const struct net_device *dev, const char *fmt, ...) \
+{ \
+ int r; \
+ struct va_format vaf; \
+ va_list args; \
+ \
+ va_start(args, fmt); \
+ \
+ vaf.fmt = fmt; \
+ vaf.va = &args; \
+ \
+ r = __netdev_printk(level, dev, &vaf); \
+ va_end(args); \
+ \
+ return r; \
+} \
+EXPORT_SYMBOL(func);
+
+define_netdev_printk_level(netdev_emerg, KERN_EMERG);
+define_netdev_printk_level(netdev_alert, KERN_ALERT);
+define_netdev_printk_level(netdev_crit, KERN_CRIT);
+define_netdev_printk_level(netdev_err, KERN_ERR);
+define_netdev_printk_level(netdev_warn, KERN_WARNING);
+define_netdev_printk_level(netdev_notice, KERN_NOTICE);
+define_netdev_printk_level(netdev_info, KERN_INFO);
+
static void __net_exit netdev_exit(struct net *net)
{
kfree(net->dev_name_head);
diff --git a/net/core/drop_monitor.c b/net/core/drop_monitor.c
index ad41529fb60..36e603c78ce 100644
--- a/net/core/drop_monitor.c
+++ b/net/core/drop_monitor.c
@@ -223,6 +223,11 @@ static int set_all_monitor_traces(int state)
spin_lock(&trace_state_lock);
+ if (state == trace_state) {
+ rc = -EAGAIN;
+ goto out_unlock;
+ }
+
switch (state) {
case TRACE_ON:
rc |= register_trace_kfree_skb(trace_kfree_skb_hit, NULL);
@@ -251,11 +256,12 @@ static int set_all_monitor_traces(int state)
if (!rc)
trace_state = state;
+ else
+ rc = -EINPROGRESS;
+out_unlock:
spin_unlock(&trace_state_lock);
- if (rc)
- return -EINPROGRESS;
return rc;
}
@@ -341,9 +347,9 @@ static struct notifier_block dropmon_net_notifier = {
static int __init init_net_drop_monitor(void)
{
- int cpu;
- int rc, i, ret;
struct per_cpu_dm_data *data;
+ int cpu, rc;
+
printk(KERN_INFO "Initalizing network drop monitor service\n");
if (sizeof(void *) > 8) {
@@ -351,21 +357,12 @@ static int __init init_net_drop_monitor(void)
return -ENOSPC;
}
- if (genl_register_family(&net_drop_monitor_family) < 0) {
+ rc = genl_register_family_with_ops(&net_drop_monitor_family,
+ dropmon_ops,
+ ARRAY_SIZE(dropmon_ops));
+ if (rc) {
printk(KERN_ERR "Could not create drop monitor netlink family\n");
- return -EFAULT;
- }
-
- rc = -EFAULT;
-
- for (i = 0; i < ARRAY_SIZE(dropmon_ops); i++) {
- ret = genl_register_ops(&net_drop_monitor_family,
- &dropmon_ops[i]);
- if (ret) {
- printk(KERN_CRIT "Failed to register operation %d\n",
- dropmon_ops[i].cmd);
- goto out_unreg;
- }
+ return rc;
}
rc = register_netdevice_notifier(&dropmon_net_notifier);
diff --git a/net/core/dst.c b/net/core/dst.c
index 9920722cc82..6c41b1fac3d 100644
--- a/net/core/dst.c
+++ b/net/core/dst.c
@@ -197,7 +197,6 @@ static void ___dst_free(struct dst_entry *dst)
dst->input = dst->output = dst_discard;
dst->obsolete = 2;
}
-EXPORT_SYMBOL(__dst_free);
void __dst_free(struct dst_entry *dst)
{
@@ -213,6 +212,7 @@ void __dst_free(struct dst_entry *dst)
}
spin_unlock_bh(&dst_garbage.lock);
}
+EXPORT_SYMBOL(__dst_free);
struct dst_entry *dst_destroy(struct dst_entry * dst)
{
diff --git a/net/core/ethtool.c b/net/core/ethtool.c
index 75e4ffeb8cc..7a85367b3c2 100644
--- a/net/core/ethtool.c
+++ b/net/core/ethtool.c
@@ -144,31 +144,13 @@ u32 ethtool_op_get_flags(struct net_device *dev)
}
EXPORT_SYMBOL(ethtool_op_get_flags);
-int ethtool_op_set_flags(struct net_device *dev, u32 data)
+int ethtool_op_set_flags(struct net_device *dev, u32 data, u32 supported)
{
- const struct ethtool_ops *ops = dev->ethtool_ops;
- unsigned long features = dev->features;
-
- if (data & ETH_FLAG_LRO)
- features |= NETIF_F_LRO;
- else
- features &= ~NETIF_F_LRO;
-
- if (data & ETH_FLAG_NTUPLE) {
- if (!ops->set_rx_ntuple)
- return -EOPNOTSUPP;
- features |= NETIF_F_NTUPLE;
- } else {
- /* safe to clear regardless */
- features &= ~NETIF_F_NTUPLE;
- }
-
- if (data & ETH_FLAG_RXHASH)
- features |= NETIF_F_RXHASH;
- else
- features &= ~NETIF_F_RXHASH;
+ if (data & ~supported)
+ return -EINVAL;
- dev->features = features;
+ dev->features = ((dev->features & ~flags_dup_features) |
+ (data & flags_dup_features));
return 0;
}
EXPORT_SYMBOL(ethtool_op_set_flags);
@@ -395,6 +377,80 @@ err_out:
return ret;
}
+static noinline_for_stack int ethtool_get_rxfh_indir(struct net_device *dev,
+ void __user *useraddr)
+{
+ struct ethtool_rxfh_indir *indir;
+ u32 table_size;
+ size_t full_size;
+ int ret;
+
+ if (!dev->ethtool_ops->get_rxfh_indir)
+ return -EOPNOTSUPP;
+
+ if (copy_from_user(&table_size,
+ useraddr + offsetof(struct ethtool_rxfh_indir, size),
+ sizeof(table_size)))
+ return -EFAULT;
+
+ if (table_size >
+ (KMALLOC_MAX_SIZE - sizeof(*indir)) / sizeof(*indir->ring_index))
+ return -ENOMEM;
+ full_size = sizeof(*indir) + sizeof(*indir->ring_index) * table_size;
+ indir = kmalloc(full_size, GFP_USER);
+ if (!indir)
+ return -ENOMEM;
+
+ indir->cmd = ETHTOOL_GRXFHINDIR;
+ indir->size = table_size;
+ ret = dev->ethtool_ops->get_rxfh_indir(dev, indir);
+ if (ret)
+ goto out;
+
+ if (copy_to_user(useraddr, indir, full_size))
+ ret = -EFAULT;
+
+out:
+ kfree(indir);
+ return ret;
+}
+
+static noinline_for_stack int ethtool_set_rxfh_indir(struct net_device *dev,
+ void __user *useraddr)
+{
+ struct ethtool_rxfh_indir *indir;
+ u32 table_size;
+ size_t full_size;
+ int ret;
+
+ if (!dev->ethtool_ops->set_rxfh_indir)
+ return -EOPNOTSUPP;
+
+ if (copy_from_user(&table_size,
+ useraddr + offsetof(struct ethtool_rxfh_indir, size),
+ sizeof(table_size)))
+ return -EFAULT;
+
+ if (table_size >
+ (KMALLOC_MAX_SIZE - sizeof(*indir)) / sizeof(*indir->ring_index))
+ return -ENOMEM;
+ full_size = sizeof(*indir) + sizeof(*indir->ring_index) * table_size;
+ indir = kmalloc(full_size, GFP_USER);
+ if (!indir)
+ return -ENOMEM;
+
+ if (copy_from_user(indir, useraddr, full_size)) {
+ ret = -EFAULT;
+ goto out;
+ }
+
+ ret = dev->ethtool_ops->set_rxfh_indir(dev, indir);
+
+out:
+ kfree(indir);
+ return ret;
+}
+
static void __rx_ntuple_filter_add(struct ethtool_rx_ntuple_list *list,
struct ethtool_rx_ntuple_flow_spec *spec,
struct ethtool_rx_ntuple_flow_spec_container *fsc)
@@ -1563,6 +1619,12 @@ int dev_ethtool(struct net *net, struct ifreq *ifr)
case ETHTOOL_GSSET_INFO:
rc = ethtool_get_sset_info(dev, useraddr);
break;
+ case ETHTOOL_GRXFHINDIR:
+ rc = ethtool_get_rxfh_indir(dev, useraddr);
+ break;
+ case ETHTOOL_SRXFHINDIR:
+ rc = ethtool_set_rxfh_indir(dev, useraddr);
+ break;
default:
rc = -EOPNOTSUPP;
}
diff --git a/net/core/filter.c b/net/core/filter.c
index da69fb728d3..52b051f82a0 100644
--- a/net/core/filter.c
+++ b/net/core/filter.c
@@ -128,87 +128,87 @@ unsigned int sk_run_filter(struct sk_buff *skb, struct sock_filter *filter, int
fentry = &filter[pc];
switch (fentry->code) {
- case BPF_ALU|BPF_ADD|BPF_X:
+ case BPF_S_ALU_ADD_X:
A += X;
continue;
- case BPF_ALU|BPF_ADD|BPF_K:
+ case BPF_S_ALU_ADD_K:
A += fentry->k;
continue;
- case BPF_ALU|BPF_SUB|BPF_X:
+ case BPF_S_ALU_SUB_X:
A -= X;
continue;
- case BPF_ALU|BPF_SUB|BPF_K:
+ case BPF_S_ALU_SUB_K:
A -= fentry->k;
continue;
- case BPF_ALU|BPF_MUL|BPF_X:
+ case BPF_S_ALU_MUL_X:
A *= X;
continue;
- case BPF_ALU|BPF_MUL|BPF_K:
+ case BPF_S_ALU_MUL_K:
A *= fentry->k;
continue;
- case BPF_ALU|BPF_DIV|BPF_X:
+ case BPF_S_ALU_DIV_X:
if (X == 0)
return 0;
A /= X;
continue;
- case BPF_ALU|BPF_DIV|BPF_K:
+ case BPF_S_ALU_DIV_K:
A /= fentry->k;
continue;
- case BPF_ALU|BPF_AND|BPF_X:
+ case BPF_S_ALU_AND_X:
A &= X;
continue;
- case BPF_ALU|BPF_AND|BPF_K:
+ case BPF_S_ALU_AND_K:
A &= fentry->k;
continue;
- case BPF_ALU|BPF_OR|BPF_X:
+ case BPF_S_ALU_OR_X:
A |= X;
continue;
- case BPF_ALU|BPF_OR|BPF_K:
+ case BPF_S_ALU_OR_K:
A |= fentry->k;
continue;
- case BPF_ALU|BPF_LSH|BPF_X:
+ case BPF_S_ALU_LSH_X:
A <<= X;
continue;
- case BPF_ALU|BPF_LSH|BPF_K:
+ case BPF_S_ALU_LSH_K:
A <<= fentry->k;
continue;
- case BPF_ALU|BPF_RSH|BPF_X:
+ case BPF_S_ALU_RSH_X:
A >>= X;
continue;
- case BPF_ALU|BPF_RSH|BPF_K:
+ case BPF_S_ALU_RSH_K:
A >>= fentry->k;
continue;
- case BPF_ALU|BPF_NEG:
+ case BPF_S_ALU_NEG:
A = -A;
continue;
- case BPF_JMP|BPF_JA:
+ case BPF_S_JMP_JA:
pc += fentry->k;
continue;
- case BPF_JMP|BPF_JGT|BPF_K:
+ case BPF_S_JMP_JGT_K:
pc += (A > fentry->k) ? fentry->jt : fentry->jf;
continue;
- case BPF_JMP|BPF_JGE|BPF_K:
+ case BPF_S_JMP_JGE_K:
pc += (A >= fentry->k) ? fentry->jt : fentry->jf;
continue;
- case BPF_JMP|BPF_JEQ|BPF_K:
+ case BPF_S_JMP_JEQ_K:
pc += (A == fentry->k) ? fentry->jt : fentry->jf;
continue;
- case BPF_JMP|BPF_JSET|BPF_K:
+ case BPF_S_JMP_JSET_K:
pc += (A & fentry->k) ? fentry->jt : fentry->jf;
continue;
- case BPF_JMP|BPF_JGT|BPF_X:
+ case BPF_S_JMP_JGT_X:
pc += (A > X) ? fentry->jt : fentry->jf;
continue;
- case BPF_JMP|BPF_JGE|BPF_X:
+ case BPF_S_JMP_JGE_X:
pc += (A >= X) ? fentry->jt : fentry->jf;
continue;
- case BPF_JMP|BPF_JEQ|BPF_X:
+ case BPF_S_JMP_JEQ_X:
pc += (A == X) ? fentry->jt : fentry->jf;
continue;
- case BPF_JMP|BPF_JSET|BPF_X:
+ case BPF_S_JMP_JSET_X:
pc += (A & X) ? fentry->jt : fentry->jf;
continue;
- case BPF_LD|BPF_W|BPF_ABS:
+ case BPF_S_LD_W_ABS:
k = fentry->k;
load_w:
ptr = load_pointer(skb, k, 4, &tmp);
@@ -217,7 +217,7 @@ load_w:
continue;
}
break;
- case BPF_LD|BPF_H|BPF_ABS:
+ case BPF_S_LD_H_ABS:
k = fentry->k;
load_h:
ptr = load_pointer(skb, k, 2, &tmp);
@@ -226,7 +226,7 @@ load_h:
continue;
}
break;
- case BPF_LD|BPF_B|BPF_ABS:
+ case BPF_S_LD_B_ABS:
k = fentry->k;
load_b:
ptr = load_pointer(skb, k, 1, &tmp);
@@ -235,54 +235,54 @@ load_b:
continue;
}
break;
- case BPF_LD|BPF_W|BPF_LEN:
+ case BPF_S_LD_W_LEN:
A = skb->len;
continue;
- case BPF_LDX|BPF_W|BPF_LEN:
+ case BPF_S_LDX_W_LEN:
X = skb->len;
continue;
- case BPF_LD|BPF_W|BPF_IND:
+ case BPF_S_LD_W_IND:
k = X + fentry->k;
goto load_w;
- case BPF_LD|BPF_H|BPF_IND:
+ case BPF_S_LD_H_IND:
k = X + fentry->k;
goto load_h;
- case BPF_LD|BPF_B|BPF_IND:
+ case BPF_S_LD_B_IND:
k = X + fentry->k;
goto load_b;
- case BPF_LDX|BPF_B|BPF_MSH:
+ case BPF_S_LDX_B_MSH:
ptr = load_pointer(skb, fentry->k, 1, &tmp);
if (ptr != NULL) {
X = (*(u8 *)ptr & 0xf) << 2;
continue;
}
return 0;
- case BPF_LD|BPF_IMM:
+ case BPF_S_LD_IMM:
A = fentry->k;
continue;
- case BPF_LDX|BPF_IMM:
+ case BPF_S_LDX_IMM:
X = fentry->k;
continue;
- case BPF_LD|BPF_MEM:
+ case BPF_S_LD_MEM:
A = mem[fentry->k];
continue;
- case BPF_LDX|BPF_MEM:
+ case BPF_S_LDX_MEM:
X = mem[fentry->k];
continue;
- case BPF_MISC|BPF_TAX:
+ case BPF_S_MISC_TAX:
X = A;
continue;
- case BPF_MISC|BPF_TXA:
+ case BPF_S_MISC_TXA:
A = X;
continue;
- case BPF_RET|BPF_K:
+ case BPF_S_RET_K:
return fentry->k;
- case BPF_RET|BPF_A:
+ case BPF_S_RET_A:
return A;
- case BPF_ST:
+ case BPF_S_ST:
mem[fentry->k] = A;
continue;
- case BPF_STX:
+ case BPF_S_STX:
mem[fentry->k] = X;
continue;
default:
@@ -390,53 +390,128 @@ int sk_chk_filter(struct sock_filter *filter, int flen)
/* Only allow valid instructions */
switch (ftest->code) {
case BPF_ALU|BPF_ADD|BPF_K:
+ ftest->code = BPF_S_ALU_ADD_K;
+ break;
case BPF_ALU|BPF_ADD|BPF_X:
+ ftest->code = BPF_S_ALU_ADD_X;
+ break;
case BPF_ALU|BPF_SUB|BPF_K:
+ ftest->code = BPF_S_ALU_SUB_K;
+ break;
case BPF_ALU|BPF_SUB|BPF_X:
+ ftest->code = BPF_S_ALU_SUB_X;
+ break;
case BPF_ALU|BPF_MUL|BPF_K:
+ ftest->code = BPF_S_ALU_MUL_K;
+ break;
case BPF_ALU|BPF_MUL|BPF_X:
+ ftest->code = BPF_S_ALU_MUL_X;
+ break;
case BPF_ALU|BPF_DIV|BPF_X:
+ ftest->code = BPF_S_ALU_DIV_X;
+ break;
case BPF_ALU|BPF_AND|BPF_K:
+ ftest->code = BPF_S_ALU_AND_K;
+ break;
case BPF_ALU|BPF_AND|BPF_X:
+ ftest->code = BPF_S_ALU_AND_X;
+ break;
case BPF_ALU|BPF_OR|BPF_K:
+ ftest->code = BPF_S_ALU_OR_K;
+ break;
case BPF_ALU|BPF_OR|BPF_X:
+ ftest->code = BPF_S_ALU_OR_X;
+ break;
case BPF_ALU|BPF_LSH|BPF_K:
+ ftest->code = BPF_S_ALU_LSH_K;
+ break;
case BPF_ALU|BPF_LSH|BPF_X:
+ ftest->code = BPF_S_ALU_LSH_X;
+ break;
case BPF_ALU|BPF_RSH|BPF_K:
+ ftest->code = BPF_S_ALU_RSH_K;
+ break;
case BPF_ALU|BPF_RSH|BPF_X:
+ ftest->code = BPF_S_ALU_RSH_X;
+ break;
case BPF_ALU|BPF_NEG:
+ ftest->code = BPF_S_ALU_NEG;
+ break;
case BPF_LD|BPF_W|BPF_ABS:
+ ftest->code = BPF_S_LD_W_ABS;
+ break;
case BPF_LD|BPF_H|BPF_ABS:
+ ftest->code = BPF_S_LD_H_ABS;
+ break;
case BPF_LD|BPF_B|BPF_ABS:
+ ftest->code = BPF_S_LD_B_ABS;
+ break;
case BPF_LD|BPF_W|BPF_LEN:
+ ftest->code = BPF_S_LD_W_LEN;
+ break;
case BPF_LD|BPF_W|BPF_IND:
+ ftest->code = BPF_S_LD_W_IND;
+ break;
case BPF_LD|BPF_H|BPF_IND:
+ ftest->code = BPF_S_LD_H_IND;
+ break;
case BPF_LD|BPF_B|BPF_IND:
+ ftest->code = BPF_S_LD_B_IND;
+ break;
case BPF_LD|BPF_IMM:
+ ftest->code = BPF_S_LD_IMM;
+ break;
case BPF_LDX|BPF_W|BPF_LEN:
+ ftest->code = BPF_S_LDX_W_LEN;
+ break;
case BPF_LDX|BPF_B|BPF_MSH:
+ ftest->code = BPF_S_LDX_B_MSH;
+ break;
case BPF_LDX|BPF_IMM:
+ ftest->code = BPF_S_LDX_IMM;
+ break;
case BPF_MISC|BPF_TAX:
+ ftest->code = BPF_S_MISC_TAX;
+ break;
case BPF_MISC|BPF_TXA:
+ ftest->code = BPF_S_MISC_TXA;
+ break;
case BPF_RET|BPF_K:
+ ftest->code = BPF_S_RET_K;
+ break;
case BPF_RET|BPF_A:
+ ftest->code = BPF_S_RET_A;
break;
/* Some instructions need special checks */
- case BPF_ALU|BPF_DIV|BPF_K:
/* check for division by zero */
+ case BPF_ALU|BPF_DIV|BPF_K:
if (ftest->k == 0)
return -EINVAL;
+ ftest->code = BPF_S_ALU_DIV_K;
break;
+ /* check for invalid memory addresses */
case BPF_LD|BPF_MEM:
+ if (ftest->k >= BPF_MEMWORDS)
+ return -EINVAL;
+ ftest->code = BPF_S_LD_MEM;
+ break;
case BPF_LDX|BPF_MEM:
+ if (ftest->k >= BPF_MEMWORDS)
+ return -EINVAL;
+ ftest->code = BPF_S_LDX_MEM;
+ break;
case BPF_ST:
+ if (ftest->k >= BPF_MEMWORDS)
+ return -EINVAL;
+ ftest->code = BPF_S_ST;
+ break;
case BPF_STX:
- /* check for invalid memory addresses */
if (ftest->k >= BPF_MEMWORDS)
return -EINVAL;
+ ftest->code = BPF_S_STX;
break;
case BPF_JMP|BPF_JA:
@@ -447,28 +522,63 @@ int sk_chk_filter(struct sock_filter *filter, int flen)
*/
if (ftest->k >= (unsigned)(flen-pc-1))
return -EINVAL;
+ ftest->code = BPF_S_JMP_JA;
break;
case BPF_JMP|BPF_JEQ|BPF_K:
+ ftest->code = BPF_S_JMP_JEQ_K;
+ break;
case BPF_JMP|BPF_JEQ|BPF_X:
+ ftest->code = BPF_S_JMP_JEQ_X;
+ break;
case BPF_JMP|BPF_JGE|BPF_K:
+ ftest->code = BPF_S_JMP_JGE_K;
+ break;
case BPF_JMP|BPF_JGE|BPF_X:
+ ftest->code = BPF_S_JMP_JGE_X;
+ break;
case BPF_JMP|BPF_JGT|BPF_K:
+ ftest->code = BPF_S_JMP_JGT_K;
+ break;
case BPF_JMP|BPF_JGT|BPF_X:
+ ftest->code = BPF_S_JMP_JGT_X;
+ break;
case BPF_JMP|BPF_JSET|BPF_K:
+ ftest->code = BPF_S_JMP_JSET_K;
+ break;
case BPF_JMP|BPF_JSET|BPF_X:
+ ftest->code = BPF_S_JMP_JSET_X;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
/* for conditionals both must be safe */
+ switch (ftest->code) {
+ case BPF_S_JMP_JEQ_K:
+ case BPF_S_JMP_JEQ_X:
+ case BPF_S_JMP_JGE_K:
+ case BPF_S_JMP_JGE_X:
+ case BPF_S_JMP_JGT_K:
+ case BPF_S_JMP_JGT_X:
+ case BPF_S_JMP_JSET_X:
+ case BPF_S_JMP_JSET_K:
if (pc + ftest->jt + 1 >= flen ||
pc + ftest->jf + 1 >= flen)
return -EINVAL;
- break;
+ }
+ }
+ /* last instruction must be a RET code */
+ switch (filter[flen - 1].code) {
+ case BPF_S_RET_K:
+ case BPF_S_RET_A:
+ return 0;
+ break;
default:
return -EINVAL;
}
- }
-
- return (BPF_CLASS(filter[flen - 1].code) == BPF_RET) ? 0 : -EINVAL;
}
EXPORT_SYMBOL(sk_chk_filter);
diff --git a/net/core/flow.c b/net/core/flow.c
index 16190067400..f67dcbfe54e 100644
--- a/net/core/flow.c
+++ b/net/core/flow.c
@@ -62,6 +62,7 @@ struct flow_cache {
};
atomic_t flow_cache_genid = ATOMIC_INIT(0);
+EXPORT_SYMBOL(flow_cache_genid);
static struct flow_cache flow_cache_global;
static struct kmem_cache *flow_cachep;
@@ -222,7 +223,7 @@ flow_cache_lookup(struct net *net, struct flowi *key, u16 family, u8 dir,
unsigned int hash;
local_bh_disable();
- fcp = per_cpu_ptr(fc->percpu, smp_processor_id());
+ fcp = this_cpu_ptr(fc->percpu);
fle = NULL;
flo = NULL;
@@ -291,6 +292,7 @@ ret_object:
local_bh_enable();
return flo;
}
+EXPORT_SYMBOL(flow_cache_lookup);
static void flow_cache_flush_tasklet(unsigned long data)
{
@@ -302,7 +304,7 @@ static void flow_cache_flush_tasklet(unsigned long data)
LIST_HEAD(gc_list);
int i, deleted = 0;
- fcp = per_cpu_ptr(fc->percpu, smp_processor_id());
+ fcp = this_cpu_ptr(fc->percpu);
for (i = 0; i < flow_cache_hash_size(fc); i++) {
hlist_for_each_entry_safe(fle, entry, tmp,
&fcp->hash_table[i], u.hlist) {
@@ -424,6 +426,3 @@ static int __init flow_cache_init_global(void)
}
module_init(flow_cache_init_global);
-
-EXPORT_SYMBOL(flow_cache_genid);
-EXPORT_SYMBOL(flow_cache_lookup);
diff --git a/net/core/gen_estimator.c b/net/core/gen_estimator.c
index 785e5276a30..9fbe7f7429b 100644
--- a/net/core/gen_estimator.c
+++ b/net/core/gen_estimator.c
@@ -263,6 +263,7 @@ static void __gen_kill_estimator(struct rcu_head *head)
*
* Removes the rate estimator specified by &bstats and &rate_est.
*
+ * Note : Caller should respect an RCU grace period before freeing stats_lock
*/
void gen_kill_estimator(struct gnet_stats_basic_packed *bstats,
struct gnet_stats_rate_est *rate_est)
diff --git a/net/core/gen_stats.c b/net/core/gen_stats.c
index 393b1d8618e..0452eb27a27 100644
--- a/net/core/gen_stats.c
+++ b/net/core/gen_stats.c
@@ -73,6 +73,7 @@ gnet_stats_start_copy_compat(struct sk_buff *skb, int type, int tc_stats_type,
return 0;
}
+EXPORT_SYMBOL(gnet_stats_start_copy_compat);
/**
* gnet_stats_start_copy_compat - start dumping procedure in compatibility mode
@@ -93,6 +94,7 @@ gnet_stats_start_copy(struct sk_buff *skb, int type, spinlock_t *lock,
{
return gnet_stats_start_copy_compat(skb, type, 0, 0, lock, d);
}
+EXPORT_SYMBOL(gnet_stats_start_copy);
/**
* gnet_stats_copy_basic - copy basic statistics into statistic TLV
@@ -123,6 +125,7 @@ gnet_stats_copy_basic(struct gnet_dump *d, struct gnet_stats_basic_packed *b)
}
return 0;
}
+EXPORT_SYMBOL(gnet_stats_copy_basic);
/**
* gnet_stats_copy_rate_est - copy rate estimator statistics into statistics TLV
@@ -154,6 +157,7 @@ gnet_stats_copy_rate_est(struct gnet_dump *d,
return 0;
}
+EXPORT_SYMBOL(gnet_stats_copy_rate_est);
/**
* gnet_stats_copy_queue - copy queue statistics into statistics TLV
@@ -181,6 +185,7 @@ gnet_stats_copy_queue(struct gnet_dump *d, struct gnet_stats_queue *q)
return 0;
}
+EXPORT_SYMBOL(gnet_stats_copy_queue);
/**
* gnet_stats_copy_app - copy application specific statistics into statistics TLV
@@ -208,6 +213,7 @@ gnet_stats_copy_app(struct gnet_dump *d, void *st, int len)
return 0;
}
+EXPORT_SYMBOL(gnet_stats_copy_app);
/**
* gnet_stats_finish_copy - finish dumping procedure
@@ -241,12 +247,4 @@ gnet_stats_finish_copy(struct gnet_dump *d)
spin_unlock_bh(d->lock);
return 0;
}
-
-
-EXPORT_SYMBOL(gnet_stats_start_copy);
-EXPORT_SYMBOL(gnet_stats_start_copy_compat);
-EXPORT_SYMBOL(gnet_stats_copy_basic);
-EXPORT_SYMBOL(gnet_stats_copy_rate_est);
-EXPORT_SYMBOL(gnet_stats_copy_queue);
-EXPORT_SYMBOL(gnet_stats_copy_app);
EXPORT_SYMBOL(gnet_stats_finish_copy);
diff --git a/net/core/iovec.c b/net/core/iovec.c
index 1e7f4e91a93..1cd98df412d 100644
--- a/net/core/iovec.c
+++ b/net/core/iovec.c
@@ -95,6 +95,7 @@ int memcpy_toiovec(struct iovec *iov, unsigned char *kdata, int len)
return 0;
}
+EXPORT_SYMBOL(memcpy_toiovec);
/*
* Copy kernel to iovec. Returns -EFAULT on error.
@@ -120,6 +121,7 @@ int memcpy_toiovecend(const struct iovec *iov, unsigned char *kdata,
return 0;
}
+EXPORT_SYMBOL(memcpy_toiovecend);
/*
* Copy iovec to kernel. Returns -EFAULT on error.
@@ -144,6 +146,7 @@ int memcpy_fromiovec(unsigned char *kdata, struct iovec *iov, int len)
return 0;
}
+EXPORT_SYMBOL(memcpy_fromiovec);
/*
* Copy iovec from kernel. Returns -EFAULT on error.
@@ -172,6 +175,7 @@ int memcpy_fromiovecend(unsigned char *kdata, const struct iovec *iov,
return 0;
}
+EXPORT_SYMBOL(memcpy_fromiovecend);
/*
* And now for the all-in-one: copy and checksum from a user iovec
@@ -256,9 +260,4 @@ out_fault:
err = -EFAULT;
goto out;
}
-
EXPORT_SYMBOL(csum_partial_copy_fromiovecend);
-EXPORT_SYMBOL(memcpy_fromiovec);
-EXPORT_SYMBOL(memcpy_fromiovecend);
-EXPORT_SYMBOL(memcpy_toiovec);
-EXPORT_SYMBOL(memcpy_toiovecend);
diff --git a/net/core/link_watch.c b/net/core/link_watch.c
index bdbce2f5875..01a1101b593 100644
--- a/net/core/link_watch.c
+++ b/net/core/link_watch.c
@@ -243,5 +243,4 @@ void linkwatch_fire_event(struct net_device *dev)
linkwatch_schedule_work(urgent);
}
-
EXPORT_SYMBOL(linkwatch_fire_event);
diff --git a/net/core/net-sysfs.c b/net/core/net-sysfs.c
index 99e7052d732..af4dfbadf2a 100644
--- a/net/core/net-sysfs.c
+++ b/net/core/net-sysfs.c
@@ -29,6 +29,7 @@ static const char fmt_hex[] = "%#x\n";
static const char fmt_long_hex[] = "%#lx\n";
static const char fmt_dec[] = "%d\n";
static const char fmt_ulong[] = "%lu\n";
+static const char fmt_u64[] = "%llu\n";
static inline int dev_isalive(const struct net_device *dev)
{
@@ -94,6 +95,7 @@ static ssize_t netdev_store(struct device *dev, struct device_attribute *attr,
}
NETDEVICE_SHOW(dev_id, fmt_hex);
+NETDEVICE_SHOW(addr_assign_type, fmt_dec);
NETDEVICE_SHOW(addr_len, fmt_dec);
NETDEVICE_SHOW(iflink, fmt_dec);
NETDEVICE_SHOW(ifindex, fmt_dec);
@@ -294,6 +296,7 @@ static ssize_t show_ifalias(struct device *dev,
}
static struct device_attribute net_class_attributes[] = {
+ __ATTR(addr_assign_type, S_IRUGO, show_addr_assign_type, NULL),
__ATTR(addr_len, S_IRUGO, show_addr_len, NULL),
__ATTR(dev_id, S_IRUGO, show_dev_id, NULL),
__ATTR(ifalias, S_IRUGO | S_IWUSR, show_ifalias, store_ifalias),
@@ -324,14 +327,15 @@ static ssize_t netstat_show(const struct device *d,
struct net_device *dev = to_net_dev(d);
ssize_t ret = -EINVAL;
- WARN_ON(offset > sizeof(struct net_device_stats) ||
- offset % sizeof(unsigned long) != 0);
+ WARN_ON(offset > sizeof(struct rtnl_link_stats64) ||
+ offset % sizeof(u64) != 0);
read_lock(&dev_base_lock);
if (dev_isalive(dev)) {
- const struct net_device_stats *stats = dev_get_stats(dev);
- ret = sprintf(buf, fmt_ulong,
- *(unsigned long *)(((u8 *) stats) + offset));
+ struct rtnl_link_stats64 temp;
+ const struct rtnl_link_stats64 *stats = dev_get_stats(dev, &temp);
+
+ ret = sprintf(buf, fmt_u64, *(u64 *)(((u8 *) stats) + offset));
}
read_unlock(&dev_base_lock);
return ret;
@@ -343,7 +347,7 @@ static ssize_t show_##name(struct device *d, \
struct device_attribute *attr, char *buf) \
{ \
return netstat_show(d, attr, buf, \
- offsetof(struct net_device_stats, name)); \
+ offsetof(struct rtnl_link_stats64, name)); \
} \
static DEVICE_ATTR(name, S_IRUGO, show_##name, NULL)
@@ -922,13 +926,12 @@ int netdev_class_create_file(struct class_attribute *class_attr)
{
return class_create_file(&net_class, class_attr);
}
+EXPORT_SYMBOL(netdev_class_create_file);
void netdev_class_remove_file(struct class_attribute *class_attr)
{
class_remove_file(&net_class, class_attr);
}
-
-EXPORT_SYMBOL(netdev_class_create_file);
EXPORT_SYMBOL(netdev_class_remove_file);
int netdev_kobject_init(void)
diff --git a/net/core/netevent.c b/net/core/netevent.c
index 95f81de8750..865f0ceb81f 100644
--- a/net/core/netevent.c
+++ b/net/core/netevent.c
@@ -35,6 +35,7 @@ int register_netevent_notifier(struct notifier_block *nb)
err = atomic_notifier_chain_register(&netevent_notif_chain, nb);
return err;
}
+EXPORT_SYMBOL_GPL(register_netevent_notifier);
/**
* netevent_unregister_notifier - unregister a netevent notifier block
@@ -50,6 +51,7 @@ int unregister_netevent_notifier(struct notifier_block *nb)
{
return atomic_notifier_chain_unregister(&netevent_notif_chain, nb);
}
+EXPORT_SYMBOL_GPL(unregister_netevent_notifier);
/**
* call_netevent_notifiers - call all netevent notifier blocks
@@ -64,7 +66,4 @@ int call_netevent_notifiers(unsigned long val, void *v)
{
return atomic_notifier_call_chain(&netevent_notif_chain, val, v);
}
-
-EXPORT_SYMBOL_GPL(register_netevent_notifier);
-EXPORT_SYMBOL_GPL(unregister_netevent_notifier);
EXPORT_SYMBOL_GPL(call_netevent_notifiers);
diff --git a/net/core/netpoll.c b/net/core/netpoll.c
index 94825b10955..537e01afd81 100644
--- a/net/core/netpoll.c
+++ b/net/core/netpoll.c
@@ -199,11 +199,13 @@ void netpoll_poll_dev(struct net_device *dev)
zap_completion_queue();
}
+EXPORT_SYMBOL(netpoll_poll_dev);
void netpoll_poll(struct netpoll *np)
{
netpoll_poll_dev(np->dev);
}
+EXPORT_SYMBOL(netpoll_poll);
static void refill_skbs(void)
{
@@ -292,6 +294,7 @@ void netpoll_send_skb(struct netpoll *np, struct sk_buff *skb)
unsigned long tries;
struct net_device *dev = np->dev;
const struct net_device_ops *ops = dev->netdev_ops;
+ /* It is up to the caller to keep npinfo alive. */
struct netpoll_info *npinfo = np->dev->npinfo;
if (!npinfo || !netif_running(dev) || !netif_device_present(dev)) {
@@ -343,6 +346,7 @@ void netpoll_send_skb(struct netpoll *np, struct sk_buff *skb)
schedule_delayed_work(&npinfo->tx_work,0);
}
}
+EXPORT_SYMBOL(netpoll_send_skb);
void netpoll_send_udp(struct netpoll *np, const char *msg, int len)
{
@@ -404,6 +408,7 @@ void netpoll_send_udp(struct netpoll *np, const char *msg, int len)
netpoll_send_skb(np, skb);
}
+EXPORT_SYMBOL(netpoll_send_udp);
static void arp_reply(struct sk_buff *skb)
{
@@ -630,6 +635,7 @@ void netpoll_print_options(struct netpoll *np)
printk(KERN_INFO "%s: remote ethernet address %pM\n",
np->name, np->remote_mac);
}
+EXPORT_SYMBOL(netpoll_print_options);
int netpoll_parse_options(struct netpoll *np, char *opt)
{
@@ -722,30 +728,29 @@ int netpoll_parse_options(struct netpoll *np, char *opt)
np->name, cur);
return -1;
}
+EXPORT_SYMBOL(netpoll_parse_options);
-int netpoll_setup(struct netpoll *np)
+int __netpoll_setup(struct netpoll *np)
{
- struct net_device *ndev = NULL;
- struct in_device *in_dev;
+ struct net_device *ndev = np->dev;
struct netpoll_info *npinfo;
- struct netpoll *npe, *tmp;
+ const struct net_device_ops *ops;
unsigned long flags;
int err;
- if (np->dev_name)
- ndev = dev_get_by_name(&init_net, np->dev_name);
- if (!ndev) {
- printk(KERN_ERR "%s: %s doesn't exist, aborting.\n",
+ if ((ndev->priv_flags & IFF_DISABLE_NETPOLL) ||
+ !ndev->netdev_ops->ndo_poll_controller) {
+ printk(KERN_ERR "%s: %s doesn't support polling, aborting.\n",
np->name, np->dev_name);
- return -ENODEV;
+ err = -ENOTSUPP;
+ goto out;
}
- np->dev = ndev;
if (!ndev->npinfo) {
npinfo = kmalloc(sizeof(*npinfo), GFP_KERNEL);
if (!npinfo) {
err = -ENOMEM;
- goto put;
+ goto out;
}
npinfo->rx_flags = 0;
@@ -757,6 +762,13 @@ int netpoll_setup(struct netpoll *np)
INIT_DELAYED_WORK(&npinfo->tx_work, queue_process);
atomic_set(&npinfo->refcnt, 1);
+
+ ops = np->dev->netdev_ops;
+ if (ops->ndo_netpoll_setup) {
+ err = ops->ndo_netpoll_setup(ndev, npinfo);
+ if (err)
+ goto free_npinfo;
+ }
} else {
npinfo = ndev->npinfo;
atomic_inc(&npinfo->refcnt);
@@ -764,12 +776,37 @@ int netpoll_setup(struct netpoll *np)
npinfo->netpoll = np;
- if ((ndev->priv_flags & IFF_DISABLE_NETPOLL) ||
- !ndev->netdev_ops->ndo_poll_controller) {
- printk(KERN_ERR "%s: %s doesn't support polling, aborting.\n",
+ if (np->rx_hook) {
+ spin_lock_irqsave(&npinfo->rx_lock, flags);
+ npinfo->rx_flags |= NETPOLL_RX_ENABLED;
+ list_add_tail(&np->rx, &npinfo->rx_np);
+ spin_unlock_irqrestore(&npinfo->rx_lock, flags);
+ }
+
+ /* last thing to do is link it to the net device structure */
+ rcu_assign_pointer(ndev->npinfo, npinfo);
+
+ return 0;
+
+free_npinfo:
+ kfree(npinfo);
+out:
+ return err;
+}
+EXPORT_SYMBOL_GPL(__netpoll_setup);
+
+int netpoll_setup(struct netpoll *np)
+{
+ struct net_device *ndev = NULL;
+ struct in_device *in_dev;
+ int err;
+
+ if (np->dev_name)
+ ndev = dev_get_by_name(&init_net, np->dev_name);
+ if (!ndev) {
+ printk(KERN_ERR "%s: %s doesn't exist, aborting.\n",
np->name, np->dev_name);
- err = -ENOTSUPP;
- goto release;
+ return -ENODEV;
}
if (!netif_running(ndev)) {
@@ -785,7 +822,7 @@ int netpoll_setup(struct netpoll *np)
if (err) {
printk(KERN_ERR "%s: failed to open %s\n",
np->name, ndev->name);
- goto release;
+ goto put;
}
atleast = jiffies + HZ/10;
@@ -822,7 +859,7 @@ int netpoll_setup(struct netpoll *np)
printk(KERN_ERR "%s: no IP address for %s, aborting\n",
np->name, np->dev_name);
err = -EDESTADDRREQ;
- goto release;
+ goto put;
}
np->local_ip = in_dev->ifa_list->ifa_local;
@@ -830,38 +867,25 @@ int netpoll_setup(struct netpoll *np)
printk(KERN_INFO "%s: local IP %pI4\n", np->name, &np->local_ip);
}
- if (np->rx_hook) {
- spin_lock_irqsave(&npinfo->rx_lock, flags);
- npinfo->rx_flags |= NETPOLL_RX_ENABLED;
- list_add_tail(&np->rx, &npinfo->rx_np);
- spin_unlock_irqrestore(&npinfo->rx_lock, flags);
- }
+ np->dev = ndev;
/* fill up the skb queue */
refill_skbs();
- /* last thing to do is link it to the net device structure */
- ndev->npinfo = npinfo;
+ rtnl_lock();
+ err = __netpoll_setup(np);
+ rtnl_unlock();
- /* avoid racing with NAPI reading npinfo */
- synchronize_rcu();
+ if (err)
+ goto put;
return 0;
- release:
- if (!ndev->npinfo) {
- spin_lock_irqsave(&npinfo->rx_lock, flags);
- list_for_each_entry_safe(npe, tmp, &npinfo->rx_np, rx) {
- npe->dev = NULL;
- }
- spin_unlock_irqrestore(&npinfo->rx_lock, flags);
-
- kfree(npinfo);
- }
put:
dev_put(ndev);
return err;
}
+EXPORT_SYMBOL(netpoll_setup);
static int __init netpoll_init(void)
{
@@ -870,49 +894,65 @@ static int __init netpoll_init(void)
}
core_initcall(netpoll_init);
-void netpoll_cleanup(struct netpoll *np)
+void __netpoll_cleanup(struct netpoll *np)
{
struct netpoll_info *npinfo;
unsigned long flags;
- if (np->dev) {
- npinfo = np->dev->npinfo;
- if (npinfo) {
- if (!list_empty(&npinfo->rx_np)) {
- spin_lock_irqsave(&npinfo->rx_lock, flags);
- list_del(&np->rx);
- if (list_empty(&npinfo->rx_np))
- npinfo->rx_flags &= ~NETPOLL_RX_ENABLED;
- spin_unlock_irqrestore(&npinfo->rx_lock, flags);
- }
+ npinfo = np->dev->npinfo;
+ if (!npinfo)
+ return;
- if (atomic_dec_and_test(&npinfo->refcnt)) {
- const struct net_device_ops *ops;
- skb_queue_purge(&npinfo->arp_tx);
- skb_queue_purge(&npinfo->txq);
- cancel_rearming_delayed_work(&npinfo->tx_work);
-
- /* clean after last, unfinished work */
- __skb_queue_purge(&npinfo->txq);
- kfree(npinfo);
- ops = np->dev->netdev_ops;
- if (ops->ndo_netpoll_cleanup)
- ops->ndo_netpoll_cleanup(np->dev);
- else
- np->dev->npinfo = NULL;
- }
- }
+ if (!list_empty(&npinfo->rx_np)) {
+ spin_lock_irqsave(&npinfo->rx_lock, flags);
+ list_del(&np->rx);
+ if (list_empty(&npinfo->rx_np))
+ npinfo->rx_flags &= ~NETPOLL_RX_ENABLED;
+ spin_unlock_irqrestore(&npinfo->rx_lock, flags);
+ }
+
+ if (atomic_dec_and_test(&npinfo->refcnt)) {
+ const struct net_device_ops *ops;
+
+ ops = np->dev->netdev_ops;
+ if (ops->ndo_netpoll_cleanup)
+ ops->ndo_netpoll_cleanup(np->dev);
+
+ rcu_assign_pointer(np->dev->npinfo, NULL);
+
+ /* avoid racing with NAPI reading npinfo */
+ synchronize_rcu_bh();
+
+ skb_queue_purge(&npinfo->arp_tx);
+ skb_queue_purge(&npinfo->txq);
+ cancel_rearming_delayed_work(&npinfo->tx_work);
- dev_put(np->dev);
+ /* clean after last, unfinished work */
+ __skb_queue_purge(&npinfo->txq);
+ kfree(npinfo);
}
+}
+EXPORT_SYMBOL_GPL(__netpoll_cleanup);
+
+void netpoll_cleanup(struct netpoll *np)
+{
+ if (!np->dev)
+ return;
+ rtnl_lock();
+ __netpoll_cleanup(np);
+ rtnl_unlock();
+
+ dev_put(np->dev);
np->dev = NULL;
}
+EXPORT_SYMBOL(netpoll_cleanup);
int netpoll_trap(void)
{
return atomic_read(&trapped);
}
+EXPORT_SYMBOL(netpoll_trap);
void netpoll_set_trap(int trap)
{
@@ -921,14 +961,4 @@ void netpoll_set_trap(int trap)
else
atomic_dec(&trapped);
}
-
-EXPORT_SYMBOL(netpoll_send_skb);
EXPORT_SYMBOL(netpoll_set_trap);
-EXPORT_SYMBOL(netpoll_trap);
-EXPORT_SYMBOL(netpoll_print_options);
-EXPORT_SYMBOL(netpoll_parse_options);
-EXPORT_SYMBOL(netpoll_setup);
-EXPORT_SYMBOL(netpoll_cleanup);
-EXPORT_SYMBOL(netpoll_send_udp);
-EXPORT_SYMBOL(netpoll_poll_dev);
-EXPORT_SYMBOL(netpoll_poll);
diff --git a/net/core/pktgen.c b/net/core/pktgen.c
index 1dacd7ba8db..10a1ea72010 100644
--- a/net/core/pktgen.c
+++ b/net/core/pktgen.c
@@ -115,6 +115,9 @@
* command by Adit Ranadive <adit.262@gmail.com>
*
*/
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/sys.h>
#include <linux/types.h>
#include <linux/module.h>
@@ -169,11 +172,13 @@
#include <asm/dma.h>
#include <asm/div64.h> /* do_div */
-#define VERSION "2.73"
+#define VERSION "2.74"
#define IP_NAME_SZ 32
#define MAX_MPLS_LABELS 16 /* This is the max label stack depth */
#define MPLS_STACK_BOTTOM htonl(0x00000100)
+#define func_enter() pr_debug("entering %s\n", __func__);
+
/* Device flag bits */
#define F_IPSRC_RND (1<<0) /* IP-Src Random */
#define F_IPDST_RND (1<<1) /* IP-Dst Random */
@@ -424,7 +429,8 @@ static inline int ktime_lt(const ktime_t cmp1, const ktime_t cmp2)
}
static const char version[] =
- "pktgen " VERSION ": Packet Generator for packet performance testing.\n";
+ "Packet Generator for packet performance testing. "
+ "Version: " VERSION "\n";
static int pktgen_remove_device(struct pktgen_thread *t, struct pktgen_dev *i);
static int pktgen_add_device(struct pktgen_thread *t, const char *ifname);
@@ -495,7 +501,7 @@ static ssize_t pgctrl_write(struct file *file, const char __user *buf,
pktgen_reset_all_threads();
else
- printk(KERN_WARNING "pktgen: Unknown command: %s\n", data);
+ pr_warning("Unknown command: %s\n", data);
err = count;
@@ -840,7 +846,7 @@ static ssize_t pktgen_if_write(struct file *file,
const char __user * user_buffer, size_t count,
loff_t * offset)
{
- struct seq_file *seq = (struct seq_file *)file->private_data;
+ struct seq_file *seq = file->private_data;
struct pktgen_dev *pkt_dev = seq->private;
int i = 0, max, len;
char name[16], valstr[32];
@@ -852,14 +858,14 @@ static ssize_t pktgen_if_write(struct file *file,
pg_result = &(pkt_dev->result[0]);
if (count < 1) {
- printk(KERN_WARNING "pktgen: wrong command format\n");
+ pr_warning("wrong command format\n");
return -EINVAL;
}
max = count - i;
tmp = count_trail_chars(&user_buffer[i], max);
if (tmp < 0) {
- printk(KERN_WARNING "pktgen: illegal format\n");
+ pr_warning("illegal format\n");
return tmp;
}
i += tmp;
@@ -980,6 +986,36 @@ static ssize_t pktgen_if_write(struct file *file,
(unsigned long long) pkt_dev->delay);
return count;
}
+ if (!strcmp(name, "rate")) {
+ len = num_arg(&user_buffer[i], 10, &value);
+ if (len < 0)
+ return len;
+
+ i += len;
+ if (!value)
+ return len;
+ pkt_dev->delay = pkt_dev->min_pkt_size*8*NSEC_PER_USEC/value;
+ if (debug)
+ pr_info("Delay set at: %llu ns\n", pkt_dev->delay);
+
+ sprintf(pg_result, "OK: rate=%lu", value);
+ return count;
+ }
+ if (!strcmp(name, "ratep")) {
+ len = num_arg(&user_buffer[i], 10, &value);
+ if (len < 0)
+ return len;
+
+ i += len;
+ if (!value)
+ return len;
+ pkt_dev->delay = NSEC_PER_SEC/value;
+ if (debug)
+ pr_info("Delay set at: %llu ns\n", pkt_dev->delay);
+
+ sprintf(pg_result, "OK: rate=%lu", value);
+ return count;
+ }
if (!strcmp(name, "udp_src_min")) {
len = num_arg(&user_buffer[i], 10, &value);
if (len < 0)
@@ -1398,18 +1434,12 @@ static ssize_t pktgen_if_write(struct file *file,
i += len;
for (*m = 0; *v && m < pkt_dev->dst_mac + 6; v++) {
- if (*v >= '0' && *v <= '9') {
- *m *= 16;
- *m += *v - '0';
- }
- if (*v >= 'A' && *v <= 'F') {
- *m *= 16;
- *m += *v - 'A' + 10;
- }
- if (*v >= 'a' && *v <= 'f') {
- *m *= 16;
- *m += *v - 'a' + 10;
- }
+ int value;
+
+ value = hex_to_bin(*v);
+ if (value >= 0)
+ *m = *m * 16 + value;
+
if (*v == ':') {
m++;
*m = 0;
@@ -1440,18 +1470,12 @@ static ssize_t pktgen_if_write(struct file *file,
i += len;
for (*m = 0; *v && m < pkt_dev->src_mac + 6; v++) {
- if (*v >= '0' && *v <= '9') {
- *m *= 16;
- *m += *v - '0';
- }
- if (*v >= 'A' && *v <= 'F') {
- *m *= 16;
- *m += *v - 'A' + 10;
- }
- if (*v >= 'a' && *v <= 'f') {
- *m *= 16;
- *m += *v - 'a' + 10;
- }
+ int value;
+
+ value = hex_to_bin(*v);
+ if (value >= 0)
+ *m = *m * 16 + value;
+
if (*v == ':') {
m++;
*m = 0;
@@ -1740,7 +1764,7 @@ static ssize_t pktgen_thread_write(struct file *file,
const char __user * user_buffer,
size_t count, loff_t * offset)
{
- struct seq_file *seq = (struct seq_file *)file->private_data;
+ struct seq_file *seq = file->private_data;
struct pktgen_thread *t = seq->private;
int i = 0, max, len, ret;
char name[40];
@@ -1781,7 +1805,7 @@ static ssize_t pktgen_thread_write(struct file *file,
name, (unsigned long)count);
if (!t) {
- printk(KERN_ERR "pktgen: ERROR: No thread\n");
+ pr_err("ERROR: No thread\n");
ret = -EINVAL;
goto out;
}
@@ -1874,7 +1898,7 @@ static void pktgen_mark_device(const char *ifname)
int i = 0;
mutex_lock(&pktgen_thread_lock);
- pr_debug("pktgen: pktgen_mark_device marking %s for removal\n", ifname);
+ pr_debug("%s: marking %s for removal\n", __func__, ifname);
while (1) {
@@ -1883,15 +1907,14 @@ static void pktgen_mark_device(const char *ifname)
break; /* success */
mutex_unlock(&pktgen_thread_lock);
- pr_debug("pktgen: pktgen_mark_device waiting for %s "
- "to disappear....\n", ifname);
+ pr_debug("%s: waiting for %s to disappear....\n",
+ __func__, ifname);
schedule_timeout_interruptible(msecs_to_jiffies(msec_per_try));
mutex_lock(&pktgen_thread_lock);
if (++i >= max_tries) {
- printk(KERN_ERR "pktgen_mark_device: timed out after "
- "waiting %d msec for device %s to be removed\n",
- msec_per_try * i, ifname);
+ pr_err("%s: timed out after waiting %d msec for device %s to be removed\n",
+ __func__, msec_per_try * i, ifname);
break;
}
@@ -1918,8 +1941,8 @@ static void pktgen_change_name(struct net_device *dev)
&pktgen_if_fops,
pkt_dev);
if (!pkt_dev->entry)
- printk(KERN_ERR "pktgen: can't move proc "
- " entry for '%s'\n", dev->name);
+ pr_err("can't move proc entry for '%s'\n",
+ dev->name);
break;
}
}
@@ -1983,15 +2006,15 @@ static int pktgen_setup_dev(struct pktgen_dev *pkt_dev, const char *ifname)
odev = pktgen_dev_get_by_name(pkt_dev, ifname);
if (!odev) {
- printk(KERN_ERR "pktgen: no such netdevice: \"%s\"\n", ifname);
+ pr_err("no such netdevice: \"%s\"\n", ifname);
return -ENODEV;
}
if (odev->type != ARPHRD_ETHER) {
- printk(KERN_ERR "pktgen: not an ethernet device: \"%s\"\n", ifname);
+ pr_err("not an ethernet device: \"%s\"\n", ifname);
err = -EINVAL;
} else if (!netif_running(odev)) {
- printk(KERN_ERR "pktgen: device is down: \"%s\"\n", ifname);
+ pr_err("device is down: \"%s\"\n", ifname);
err = -ENETDOWN;
} else {
pkt_dev->odev = odev;
@@ -2010,8 +2033,7 @@ static void pktgen_setup_inject(struct pktgen_dev *pkt_dev)
int ntxq;
if (!pkt_dev->odev) {
- printk(KERN_ERR "pktgen: ERROR: pkt_dev->odev == NULL in "
- "setup_inject.\n");
+ pr_err("ERROR: pkt_dev->odev == NULL in setup_inject\n");
sprintf(pkt_dev->result,
"ERROR: pkt_dev->odev == NULL in setup_inject.\n");
return;
@@ -2021,19 +2043,15 @@ static void pktgen_setup_inject(struct pktgen_dev *pkt_dev)
ntxq = pkt_dev->odev->real_num_tx_queues;
if (ntxq <= pkt_dev->queue_map_min) {
- printk(KERN_WARNING "pktgen: WARNING: Requested "
- "queue_map_min (zero-based) (%d) exceeds valid range "
- "[0 - %d] for (%d) queues on %s, resetting\n",
- pkt_dev->queue_map_min, (ntxq ?: 1) - 1, ntxq,
- pkt_dev->odevname);
+ pr_warning("WARNING: Requested queue_map_min (zero-based) (%d) exceeds valid range [0 - %d] for (%d) queues on %s, resetting\n",
+ pkt_dev->queue_map_min, (ntxq ?: 1) - 1, ntxq,
+ pkt_dev->odevname);
pkt_dev->queue_map_min = ntxq - 1;
}
if (pkt_dev->queue_map_max >= ntxq) {
- printk(KERN_WARNING "pktgen: WARNING: Requested "
- "queue_map_max (zero-based) (%d) exceeds valid range "
- "[0 - %d] for (%d) queues on %s, resetting\n",
- pkt_dev->queue_map_max, (ntxq ?: 1) - 1, ntxq,
- pkt_dev->odevname);
+ pr_warning("WARNING: Requested queue_map_max (zero-based) (%d) exceeds valid range [0 - %d] for (%d) queues on %s, resetting\n",
+ pkt_dev->queue_map_max, (ntxq ?: 1) - 1, ntxq,
+ pkt_dev->odevname);
pkt_dev->queue_map_max = ntxq - 1;
}
@@ -2093,8 +2111,7 @@ static void pktgen_setup_inject(struct pktgen_dev *pkt_dev)
}
rcu_read_unlock();
if (err)
- printk(KERN_ERR "pktgen: ERROR: IPv6 link "
- "address not availble.\n");
+ pr_err("ERROR: IPv6 link address not available\n");
}
#endif
} else {
@@ -2142,15 +2159,15 @@ static void spin(struct pktgen_dev *pkt_dev, ktime_t spin_until)
hrtimer_init_on_stack(&t.timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS);
hrtimer_set_expires(&t.timer, spin_until);
- remaining = ktime_to_us(hrtimer_expires_remaining(&t.timer));
+ remaining = ktime_to_ns(hrtimer_expires_remaining(&t.timer));
if (remaining <= 0) {
pkt_dev->next_tx = ktime_add_ns(spin_until, pkt_dev->delay);
return;
}
start_time = ktime_now();
- if (remaining < 100)
- udelay(remaining); /* really small just spin */
+ if (remaining < 100000)
+ ndelay(remaining); /* really small just spin */
else {
/* see do_nanosleep */
hrtimer_init_sleeper(&t, current);
@@ -2528,8 +2545,8 @@ static int process_ipsec(struct pktgen_dev *pkt_dev,
if (nhead > 0) {
ret = pskb_expand_head(skb, nhead, 0, GFP_ATOMIC);
if (ret < 0) {
- printk(KERN_ERR "Error expanding "
- "ipsec packet %d\n", ret);
+ pr_err("Error expanding ipsec packet %d\n",
+ ret);
goto err;
}
}
@@ -2538,8 +2555,7 @@ static int process_ipsec(struct pktgen_dev *pkt_dev,
skb_pull(skb, ETH_HLEN);
ret = pktgen_output_ipsec(skb, pkt_dev);
if (ret) {
- printk(KERN_ERR "Error creating ipsec "
- "packet %d\n", ret);
+ pr_err("Error creating ipsec packet %d\n", ret);
goto err;
}
/* restore ll */
@@ -3015,8 +3031,7 @@ static struct sk_buff *fill_packet_ipv6(struct net_device *odev,
if (datalen < sizeof(struct pktgen_hdr)) {
datalen = sizeof(struct pktgen_hdr);
if (net_ratelimit())
- printk(KERN_INFO "pktgen: increased datalen to %d\n",
- datalen);
+ pr_info("increased datalen to %d\n", datalen);
}
udph->source = htons(pkt_dev->cur_udp_src);
@@ -3143,7 +3158,7 @@ static void pktgen_run(struct pktgen_thread *t)
struct pktgen_dev *pkt_dev;
int started = 0;
- pr_debug("pktgen: entering pktgen_run. %p\n", t);
+ func_enter();
if_lock(t);
list_for_each_entry(pkt_dev, &t->if_list, list) {
@@ -3176,7 +3191,7 @@ static void pktgen_stop_all_threads_ifs(void)
{
struct pktgen_thread *t;
- pr_debug("pktgen: entering pktgen_stop_all_threads_ifs.\n");
+ func_enter();
mutex_lock(&pktgen_thread_lock);
@@ -3241,7 +3256,7 @@ static void pktgen_run_all_threads(void)
{
struct pktgen_thread *t;
- pr_debug("pktgen: entering pktgen_run_all_threads.\n");
+ func_enter();
mutex_lock(&pktgen_thread_lock);
@@ -3260,7 +3275,7 @@ static void pktgen_reset_all_threads(void)
{
struct pktgen_thread *t;
- pr_debug("pktgen: entering pktgen_reset_all_threads.\n");
+ func_enter();
mutex_lock(&pktgen_thread_lock);
@@ -3310,8 +3325,8 @@ static int pktgen_stop_device(struct pktgen_dev *pkt_dev)
int nr_frags = pkt_dev->skb ? skb_shinfo(pkt_dev->skb)->nr_frags : -1;
if (!pkt_dev->running) {
- printk(KERN_WARNING "pktgen: interface: %s is already "
- "stopped\n", pkt_dev->odevname);
+ pr_warning("interface: %s is already stopped\n",
+ pkt_dev->odevname);
return -EINVAL;
}
@@ -3347,7 +3362,7 @@ static void pktgen_stop(struct pktgen_thread *t)
{
struct pktgen_dev *pkt_dev;
- pr_debug("pktgen: entering pktgen_stop\n");
+ func_enter();
if_lock(t);
@@ -3367,7 +3382,7 @@ static void pktgen_rem_one_if(struct pktgen_thread *t)
struct list_head *q, *n;
struct pktgen_dev *cur;
- pr_debug("pktgen: entering pktgen_rem_one_if\n");
+ func_enter();
if_lock(t);
@@ -3393,9 +3408,10 @@ static void pktgen_rem_all_ifs(struct pktgen_thread *t)
struct list_head *q, *n;
struct pktgen_dev *cur;
+ func_enter();
+
/* Remove all devices, free mem */
- pr_debug("pktgen: entering pktgen_rem_all_ifs\n");
if_lock(t);
list_for_each_safe(q, n, &t->if_list) {
@@ -3477,8 +3493,7 @@ static void pktgen_xmit(struct pktgen_dev *pkt_dev)
pkt_dev->skb = fill_packet(odev, pkt_dev);
if (pkt_dev->skb == NULL) {
- printk(KERN_ERR "pktgen: ERROR: couldn't "
- "allocate skb in fill_packet.\n");
+ pr_err("ERROR: couldn't allocate skb in fill_packet\n");
schedule();
pkt_dev->clone_count--; /* back out increment, OOM */
return;
@@ -3558,8 +3573,7 @@ static int pktgen_thread_worker(void *arg)
init_waitqueue_head(&t->queue);
complete(&t->start_done);
- pr_debug("pktgen: starting pktgen/%d: pid=%d\n",
- cpu, task_pid_nr(current));
+ pr_debug("starting pktgen/%d: pid=%d\n", cpu, task_pid_nr(current));
set_current_state(TASK_INTERRUPTIBLE);
@@ -3612,13 +3626,13 @@ static int pktgen_thread_worker(void *arg)
set_current_state(TASK_INTERRUPTIBLE);
}
- pr_debug("pktgen: %s stopping all device\n", t->tsk->comm);
+ pr_debug("%s stopping all device\n", t->tsk->comm);
pktgen_stop(t);
- pr_debug("pktgen: %s removing all device\n", t->tsk->comm);
+ pr_debug("%s removing all device\n", t->tsk->comm);
pktgen_rem_all_ifs(t);
- pr_debug("pktgen: %s removing thread.\n", t->tsk->comm);
+ pr_debug("%s removing thread\n", t->tsk->comm);
pktgen_rem_thread(t);
return 0;
@@ -3642,7 +3656,7 @@ static struct pktgen_dev *pktgen_find_dev(struct pktgen_thread *t,
}
if_unlock(t);
- pr_debug("pktgen: find_dev(%s) returning %p\n", ifname, pkt_dev);
+ pr_debug("find_dev(%s) returning %p\n", ifname, pkt_dev);
return pkt_dev;
}
@@ -3658,8 +3672,7 @@ static int add_dev_to_thread(struct pktgen_thread *t,
if_lock(t);
if (pkt_dev->pg_thread) {
- printk(KERN_ERR "pktgen: ERROR: already assigned "
- "to a thread.\n");
+ pr_err("ERROR: already assigned to a thread\n");
rv = -EBUSY;
goto out;
}
@@ -3685,7 +3698,7 @@ static int pktgen_add_device(struct pktgen_thread *t, const char *ifname)
pkt_dev = __pktgen_NN_threads(ifname, FIND);
if (pkt_dev) {
- printk(KERN_ERR "pktgen: ERROR: interface already used.\n");
+ pr_err("ERROR: interface already used\n");
return -EBUSY;
}
@@ -3730,7 +3743,7 @@ static int pktgen_add_device(struct pktgen_thread *t, const char *ifname)
pkt_dev->entry = proc_create_data(ifname, 0600, pg_proc_dir,
&pktgen_if_fops, pkt_dev);
if (!pkt_dev->entry) {
- printk(KERN_ERR "pktgen: cannot create %s/%s procfs entry.\n",
+ pr_err("cannot create %s/%s procfs entry\n",
PG_PROC_DIR, ifname);
err = -EINVAL;
goto out2;
@@ -3761,8 +3774,7 @@ static int __init pktgen_create_thread(int cpu)
t = kzalloc_node(sizeof(struct pktgen_thread), GFP_KERNEL,
cpu_to_node(cpu));
if (!t) {
- printk(KERN_ERR "pktgen: ERROR: out of memory, can't "
- "create new thread.\n");
+ pr_err("ERROR: out of memory, can't create new thread\n");
return -ENOMEM;
}
@@ -3776,8 +3788,7 @@ static int __init pktgen_create_thread(int cpu)
p = kthread_create(pktgen_thread_worker, t, "kpktgend_%d", cpu);
if (IS_ERR(p)) {
- printk(KERN_ERR "pktgen: kernel_thread() failed "
- "for cpu %d\n", t->cpu);
+ pr_err("kernel_thread() failed for cpu %d\n", t->cpu);
list_del(&t->th_list);
kfree(t);
return PTR_ERR(p);
@@ -3788,7 +3799,7 @@ static int __init pktgen_create_thread(int cpu)
pe = proc_create_data(t->tsk->comm, 0600, pg_proc_dir,
&pktgen_thread_fops, t);
if (!pe) {
- printk(KERN_ERR "pktgen: cannot create %s/%s procfs entry.\n",
+ pr_err("cannot create %s/%s procfs entry\n",
PG_PROC_DIR, t->tsk->comm);
kthread_stop(p);
list_del(&t->th_list);
@@ -3822,11 +3833,10 @@ static int pktgen_remove_device(struct pktgen_thread *t,
struct pktgen_dev *pkt_dev)
{
- pr_debug("pktgen: remove_device pkt_dev=%p\n", pkt_dev);
+ pr_debug("remove_device pkt_dev=%p\n", pkt_dev);
if (pkt_dev->running) {
- printk(KERN_WARNING "pktgen: WARNING: trying to remove a "
- "running interface, stopping it now.\n");
+ pr_warning("WARNING: trying to remove a running interface, stopping it now\n");
pktgen_stop_device(pkt_dev);
}
@@ -3857,7 +3867,7 @@ static int __init pg_init(void)
int cpu;
struct proc_dir_entry *pe;
- printk(KERN_INFO "%s", version);
+ pr_info("%s", version);
pg_proc_dir = proc_mkdir(PG_PROC_DIR, init_net.proc_net);
if (!pg_proc_dir)
@@ -3865,8 +3875,7 @@ static int __init pg_init(void)
pe = proc_create(PGCTRL, 0600, pg_proc_dir, &pktgen_fops);
if (pe == NULL) {
- printk(KERN_ERR "pktgen: ERROR: cannot create %s "
- "procfs entry.\n", PGCTRL);
+ pr_err("ERROR: cannot create %s procfs entry\n", PGCTRL);
proc_net_remove(&init_net, PG_PROC_DIR);
return -EINVAL;
}
@@ -3879,13 +3888,12 @@ static int __init pg_init(void)
err = pktgen_create_thread(cpu);
if (err)
- printk(KERN_WARNING "pktgen: WARNING: Cannot create "
- "thread for cpu %d (%d)\n", cpu, err);
+ pr_warning("WARNING: Cannot create thread for cpu %d (%d)\n",
+ cpu, err);
}
if (list_empty(&pktgen_threads)) {
- printk(KERN_ERR "pktgen: ERROR: Initialization failed for "
- "all threads\n");
+ pr_err("ERROR: Initialization failed for all threads\n");
unregister_netdevice_notifier(&pktgen_notifier_block);
remove_proc_entry(PGCTRL, pg_proc_dir);
proc_net_remove(&init_net, PG_PROC_DIR);
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
index 1a2af24e9e3..f78d821bd93 100644
--- a/net/core/rtnetlink.c
+++ b/net/core/rtnetlink.c
@@ -579,7 +579,7 @@ static unsigned int rtnl_dev_combine_flags(const struct net_device *dev,
}
static void copy_rtnl_link_stats(struct rtnl_link_stats *a,
- const struct net_device_stats *b)
+ const struct rtnl_link_stats64 *b)
{
a->rx_packets = b->rx_packets;
a->tx_packets = b->tx_packets;
@@ -610,7 +610,7 @@ static void copy_rtnl_link_stats(struct rtnl_link_stats *a,
a->tx_compressed = b->tx_compressed;
}
-static void copy_rtnl_link_stats64(void *v, const struct net_device_stats *b)
+static void copy_rtnl_link_stats64(void *v, const struct rtnl_link_stats64 *b)
{
struct rtnl_link_stats64 a;
@@ -686,7 +686,7 @@ static size_t rtnl_port_size(const struct net_device *dev)
return port_self_size;
}
-static inline size_t if_nlmsg_size(const struct net_device *dev)
+static noinline size_t if_nlmsg_size(const struct net_device *dev)
{
return NLMSG_ALIGN(sizeof(struct ifinfomsg))
+ nla_total_size(IFNAMSIZ) /* IFLA_IFNAME */
@@ -791,7 +791,8 @@ static int rtnl_fill_ifinfo(struct sk_buff *skb, struct net_device *dev,
{
struct ifinfomsg *ifm;
struct nlmsghdr *nlh;
- const struct net_device_stats *stats;
+ struct rtnl_link_stats64 temp;
+ const struct rtnl_link_stats64 *stats;
struct nlattr *attr;
nlh = nlmsg_put(skb, pid, seq, type, sizeof(*ifm), flags);
@@ -847,7 +848,7 @@ static int rtnl_fill_ifinfo(struct sk_buff *skb, struct net_device *dev,
if (attr == NULL)
goto nla_put_failure;
- stats = dev_get_stats(dev);
+ stats = dev_get_stats(dev, &temp);
copy_rtnl_link_stats(nla_data(attr), stats);
attr = nla_reserve(skb, IFLA_STATS64,
diff --git a/net/core/scm.c b/net/core/scm.c
index b88f6f9d0b9..413cab89017 100644
--- a/net/core/scm.c
+++ b/net/core/scm.c
@@ -130,6 +130,7 @@ void __scm_destroy(struct scm_cookie *scm)
}
}
}
+EXPORT_SYMBOL(__scm_destroy);
int __scm_send(struct socket *sock, struct msghdr *msg, struct scm_cookie *p)
{
@@ -170,6 +171,30 @@ int __scm_send(struct socket *sock, struct msghdr *msg, struct scm_cookie *p)
err = scm_check_creds(&p->creds);
if (err)
goto error;
+
+ if (pid_vnr(p->pid) != p->creds.pid) {
+ struct pid *pid;
+ err = -ESRCH;
+ pid = find_get_pid(p->creds.pid);
+ if (!pid)
+ goto error;
+ put_pid(p->pid);
+ p->pid = pid;
+ }
+
+ if ((p->cred->euid != p->creds.uid) ||
+ (p->cred->egid != p->creds.gid)) {
+ struct cred *cred;
+ err = -ENOMEM;
+ cred = prepare_creds();
+ if (!cred)
+ goto error;
+
+ cred->uid = cred->euid = p->creds.uid;
+ cred->gid = cred->egid = p->creds.uid;
+ put_cred(p->cred);
+ p->cred = cred;
+ }
break;
default:
goto error;
@@ -187,6 +212,7 @@ error:
scm_destroy(p);
return err;
}
+EXPORT_SYMBOL(__scm_send);
int put_cmsg(struct msghdr * msg, int level, int type, int len, void *data)
{
@@ -225,6 +251,7 @@ int put_cmsg(struct msghdr * msg, int level, int type, int len, void *data)
out:
return err;
}
+EXPORT_SYMBOL(put_cmsg);
void scm_detach_fds(struct msghdr *msg, struct scm_cookie *scm)
{
@@ -294,6 +321,7 @@ void scm_detach_fds(struct msghdr *msg, struct scm_cookie *scm)
*/
__scm_destroy(scm);
}
+EXPORT_SYMBOL(scm_detach_fds);
struct scm_fp_list *scm_fp_dup(struct scm_fp_list *fpl)
{
@@ -311,9 +339,4 @@ struct scm_fp_list *scm_fp_dup(struct scm_fp_list *fpl)
}
return new_fpl;
}
-
-EXPORT_SYMBOL(__scm_destroy);
-EXPORT_SYMBOL(__scm_send);
-EXPORT_SYMBOL(put_cmsg);
-EXPORT_SYMBOL(scm_detach_fds);
EXPORT_SYMBOL(scm_fp_dup);
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index ce88293a34e..3a2513f0d0c 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -817,7 +817,7 @@ int pskb_expand_head(struct sk_buff *skb, int nhead, int ntail,
memcpy(data + nhead, skb->head, skb->tail - skb->head);
#endif
memcpy(data + size, skb_end_pointer(skb),
- sizeof(struct skb_shared_info));
+ offsetof(struct skb_shared_info, frags[skb_shinfo(skb)->nr_frags]));
for (i = 0; i < skb_shinfo(skb)->nr_frags; i++)
get_page(skb_shinfo(skb)->frags[i].page);
@@ -2486,7 +2486,6 @@ unsigned char *skb_pull_rcsum(struct sk_buff *skb, unsigned int len)
skb_postpull_rcsum(skb, skb->data, len);
return skb->data += len;
}
-
EXPORT_SYMBOL_GPL(skb_pull_rcsum);
/**
diff --git a/net/core/sock.c b/net/core/sock.c
index 2cf7f9f7e77..b05b9b6ddb8 100644
--- a/net/core/sock.c
+++ b/net/core/sock.c
@@ -110,6 +110,7 @@
#include <linux/tcp.h>
#include <linux/init.h>
#include <linux/highmem.h>
+#include <linux/user_namespace.h>
#include <asm/uaccess.h>
#include <asm/system.h>
@@ -156,7 +157,7 @@ static const char *const af_family_key_strings[AF_MAX+1] = {
"sk_lock-27" , "sk_lock-28" , "sk_lock-AF_CAN" ,
"sk_lock-AF_TIPC" , "sk_lock-AF_BLUETOOTH", "sk_lock-IUCV" ,
"sk_lock-AF_RXRPC" , "sk_lock-AF_ISDN" , "sk_lock-AF_PHONET" ,
- "sk_lock-AF_IEEE802154",
+ "sk_lock-AF_IEEE802154", "sk_lock-AF_CAIF" ,
"sk_lock-AF_MAX"
};
static const char *const af_family_slock_key_strings[AF_MAX+1] = {
@@ -172,7 +173,7 @@ static const char *const af_family_slock_key_strings[AF_MAX+1] = {
"slock-27" , "slock-28" , "slock-AF_CAN" ,
"slock-AF_TIPC" , "slock-AF_BLUETOOTH", "slock-AF_IUCV" ,
"slock-AF_RXRPC" , "slock-AF_ISDN" , "slock-AF_PHONET" ,
- "slock-AF_IEEE802154",
+ "slock-AF_IEEE802154", "slock-AF_CAIF" ,
"slock-AF_MAX"
};
static const char *const af_family_clock_key_strings[AF_MAX+1] = {
@@ -188,7 +189,7 @@ static const char *const af_family_clock_key_strings[AF_MAX+1] = {
"clock-27" , "clock-28" , "clock-AF_CAN" ,
"clock-AF_TIPC" , "clock-AF_BLUETOOTH", "clock-AF_IUCV" ,
"clock-AF_RXRPC" , "clock-AF_ISDN" , "clock-AF_PHONET" ,
- "clock-AF_IEEE802154",
+ "clock-AF_IEEE802154", "clock-AF_CAIF" ,
"clock-AF_MAX"
};
@@ -749,6 +750,20 @@ set_rcvbuf:
EXPORT_SYMBOL(sock_setsockopt);
+void cred_to_ucred(struct pid *pid, const struct cred *cred,
+ struct ucred *ucred)
+{
+ ucred->pid = pid_vnr(pid);
+ ucred->uid = ucred->gid = -1;
+ if (cred) {
+ struct user_namespace *current_ns = current_user_ns();
+
+ ucred->uid = user_ns_map_uid(current_ns, cred, cred->euid);
+ ucred->gid = user_ns_map_gid(current_ns, cred, cred->egid);
+ }
+}
+EXPORT_SYMBOL_GPL(cred_to_ucred);
+
int sock_getsockopt(struct socket *sock, int level, int optname,
char __user *optval, int __user *optlen)
{
@@ -901,11 +916,15 @@ int sock_getsockopt(struct socket *sock, int level, int optname,
break;
case SO_PEERCRED:
- if (len > sizeof(sk->sk_peercred))
- len = sizeof(sk->sk_peercred);
- if (copy_to_user(optval, &sk->sk_peercred, len))
+ {
+ struct ucred peercred;
+ if (len > sizeof(peercred))
+ len = sizeof(peercred);
+ cred_to_ucred(sk->sk_peer_pid, sk->sk_peer_cred, &peercred);
+ if (copy_to_user(optval, &peercred, len))
return -EFAULT;
goto lenout;
+ }
case SO_PEERNAME:
{
@@ -1119,6 +1138,9 @@ static void __sk_free(struct sock *sk)
printk(KERN_DEBUG "%s: optmem leakage (%d bytes) detected.\n",
__func__, atomic_read(&sk->sk_omem_alloc));
+ if (sk->sk_peer_cred)
+ put_cred(sk->sk_peer_cred);
+ put_pid(sk->sk_peer_pid);
put_net(sock_net(sk));
sk_prot_free(sk->sk_prot_creator, sk);
}
@@ -1317,9 +1339,10 @@ EXPORT_SYMBOL(sock_wfree);
void sock_rfree(struct sk_buff *skb)
{
struct sock *sk = skb->sk;
+ unsigned int len = skb->truesize;
- atomic_sub(skb->truesize, &sk->sk_rmem_alloc);
- sk_mem_uncharge(skb->sk, skb->truesize);
+ atomic_sub(len, &sk->sk_rmem_alloc);
+ sk_mem_uncharge(sk, len);
}
EXPORT_SYMBOL(sock_rfree);
@@ -1954,9 +1977,8 @@ void sock_init_data(struct socket *sock, struct sock *sk)
sk->sk_sndmsg_page = NULL;
sk->sk_sndmsg_off = 0;
- sk->sk_peercred.pid = 0;
- sk->sk_peercred.uid = -1;
- sk->sk_peercred.gid = -1;
+ sk->sk_peer_pid = NULL;
+ sk->sk_peer_cred = NULL;
sk->sk_write_pending = 0;
sk->sk_rcvlowat = 1;
sk->sk_rcvtimeo = MAX_SCHEDULE_TIMEOUT;
@@ -2210,8 +2232,7 @@ static DECLARE_BITMAP(proto_inuse_idx, PROTO_INUSE_NR);
#ifdef CONFIG_NET_NS
void sock_prot_inuse_add(struct net *net, struct proto *prot, int val)
{
- int cpu = smp_processor_id();
- per_cpu_ptr(net->core.inuse, cpu)->val[prot->inuse_idx] += val;
+ __this_cpu_add(net->core.inuse->val[prot->inuse_idx], val);
}
EXPORT_SYMBOL_GPL(sock_prot_inuse_add);
@@ -2257,7 +2278,7 @@ static DEFINE_PER_CPU(struct prot_inuse, prot_inuse);
void sock_prot_inuse_add(struct net *net, struct proto *prot, int val)
{
- __get_cpu_var(prot_inuse).val[prot->inuse_idx] += val;
+ __this_cpu_add(prot_inuse.val[prot->inuse_idx], val);
}
EXPORT_SYMBOL_GPL(sock_prot_inuse_add);
diff --git a/net/core/stream.c b/net/core/stream.c
index cc196f42b8d..d959e0f4152 100644
--- a/net/core/stream.c
+++ b/net/core/stream.c
@@ -43,7 +43,6 @@ void sk_stream_write_space(struct sock *sk)
rcu_read_unlock();
}
}
-
EXPORT_SYMBOL(sk_stream_write_space);
/**
@@ -81,7 +80,6 @@ int sk_stream_wait_connect(struct sock *sk, long *timeo_p)
} while (!done);
return 0;
}
-
EXPORT_SYMBOL(sk_stream_wait_connect);
/**
@@ -109,7 +107,6 @@ void sk_stream_wait_close(struct sock *sk, long timeout)
finish_wait(sk_sleep(sk), &wait);
}
}
-
EXPORT_SYMBOL(sk_stream_wait_close);
/**
@@ -174,7 +171,6 @@ do_interrupted:
err = sock_intr_errno(*timeo_p);
goto out;
}
-
EXPORT_SYMBOL(sk_stream_wait_memory);
int sk_stream_error(struct sock *sk, int flags, int err)
@@ -185,7 +181,6 @@ int sk_stream_error(struct sock *sk, int flags, int err)
send_sig(SIGPIPE, current, 0);
return err;
}
-
EXPORT_SYMBOL(sk_stream_error);
void sk_stream_kill_queues(struct sock *sk)
@@ -210,5 +205,4 @@ void sk_stream_kill_queues(struct sock *sk)
* have gone away, only the net layer knows can touch it.
*/
}
-
EXPORT_SYMBOL(sk_stream_kill_queues);
diff --git a/net/core/timestamping.c b/net/core/timestamping.c
new file mode 100644
index 00000000000..0ae6c22da85
--- /dev/null
+++ b/net/core/timestamping.c
@@ -0,0 +1,126 @@
+/*
+ * PTP 1588 clock support - support for timestamping in PHY devices
+ *
+ * Copyright (C) 2010 OMICRON electronics 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/errqueue.h>
+#include <linux/phy.h>
+#include <linux/ptp_classify.h>
+#include <linux/skbuff.h>
+
+static struct sock_filter ptp_filter[] = {
+ PTP_FILTER
+};
+
+static unsigned int classify(struct sk_buff *skb)
+{
+ if (likely(skb->dev &&
+ skb->dev->phydev &&
+ skb->dev->phydev->drv))
+ return sk_run_filter(skb, ptp_filter, ARRAY_SIZE(ptp_filter));
+ else
+ return PTP_CLASS_NONE;
+}
+
+void skb_clone_tx_timestamp(struct sk_buff *skb)
+{
+ struct phy_device *phydev;
+ struct sk_buff *clone;
+ struct sock *sk = skb->sk;
+ unsigned int type;
+
+ if (!sk)
+ return;
+
+ type = classify(skb);
+
+ switch (type) {
+ case PTP_CLASS_V1_IPV4:
+ case PTP_CLASS_V1_IPV6:
+ case PTP_CLASS_V2_IPV4:
+ case PTP_CLASS_V2_IPV6:
+ case PTP_CLASS_V2_L2:
+ case PTP_CLASS_V2_VLAN:
+ phydev = skb->dev->phydev;
+ if (likely(phydev->drv->txtstamp)) {
+ clone = skb_clone(skb, GFP_ATOMIC);
+ if (!clone)
+ return;
+ clone->sk = sk;
+ phydev->drv->txtstamp(phydev, clone, type);
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+void skb_complete_tx_timestamp(struct sk_buff *skb,
+ struct skb_shared_hwtstamps *hwtstamps)
+{
+ struct sock *sk = skb->sk;
+ struct sock_exterr_skb *serr;
+ int err;
+
+ if (!hwtstamps)
+ return;
+
+ *skb_hwtstamps(skb) = *hwtstamps;
+ serr = SKB_EXT_ERR(skb);
+ memset(serr, 0, sizeof(*serr));
+ serr->ee.ee_errno = ENOMSG;
+ serr->ee.ee_origin = SO_EE_ORIGIN_TIMESTAMPING;
+ skb->sk = NULL;
+ err = sock_queue_err_skb(sk, skb);
+ if (err)
+ kfree_skb(skb);
+}
+EXPORT_SYMBOL_GPL(skb_complete_tx_timestamp);
+
+bool skb_defer_rx_timestamp(struct sk_buff *skb)
+{
+ struct phy_device *phydev;
+ unsigned int type;
+
+ skb_push(skb, ETH_HLEN);
+
+ type = classify(skb);
+
+ skb_pull(skb, ETH_HLEN);
+
+ switch (type) {
+ case PTP_CLASS_V1_IPV4:
+ case PTP_CLASS_V1_IPV6:
+ case PTP_CLASS_V2_IPV4:
+ case PTP_CLASS_V2_IPV6:
+ case PTP_CLASS_V2_L2:
+ case PTP_CLASS_V2_VLAN:
+ phydev = skb->dev->phydev;
+ if (likely(phydev->drv->rxtstamp))
+ return phydev->drv->rxtstamp(phydev, skb, type);
+ break;
+ default:
+ break;
+ }
+
+ return false;
+}
+
+void __init skb_timestamping_init(void)
+{
+ BUG_ON(sk_chk_filter(ptp_filter, ARRAY_SIZE(ptp_filter)));
+}
diff --git a/net/core/utils.c b/net/core/utils.c
index 838250241d2..f4185447053 100644
--- a/net/core/utils.c
+++ b/net/core/utils.c
@@ -77,7 +77,6 @@ __be32 in_aton(const char *str)
}
return(htonl(l));
}
-
EXPORT_SYMBOL(in_aton);
#define IN6PTON_XDIGIT 0x00010000
@@ -162,7 +161,6 @@ out:
*end = s;
return ret;
}
-
EXPORT_SYMBOL(in4_pton);
int in6_pton(const char *src, int srclen,
@@ -280,7 +278,6 @@ out:
*end = s;
return ret;
}
-
EXPORT_SYMBOL(in6_pton);
void inet_proto_csum_replace4(__sum16 *sum, struct sk_buff *skb,
diff --git a/net/dccp/ackvec.c b/net/dccp/ackvec.c
index 01e4d39fa23..92a6fcb40d7 100644
--- a/net/dccp/ackvec.c
+++ b/net/dccp/ackvec.c
@@ -82,7 +82,7 @@ int dccp_insert_option_ackvec(struct sock *sk, struct sk_buff *skb)
elapsed_time = delta / 10;
if (elapsed_time != 0 &&
- dccp_insert_option_elapsed_time(sk, skb, elapsed_time))
+ dccp_insert_option_elapsed_time(skb, elapsed_time))
return -1;
avr = dccp_ackvec_record_new();
@@ -201,7 +201,7 @@ static inline int dccp_ackvec_set_buf_head_state(struct dccp_ackvec *av,
const unsigned int packets,
const unsigned char state)
{
- unsigned int gap;
+ long gap;
long new_head;
if (av->av_vec_len + packets > DCCP_MAX_ACKVEC_LEN)
diff --git a/net/dccp/ccids/ccid3.c b/net/dccp/ccids/ccid3.c
index d3235899c7e..95f75298649 100644
--- a/net/dccp/ccids/ccid3.c
+++ b/net/dccp/ccids/ccid3.c
@@ -715,9 +715,9 @@ static int ccid3_hc_rx_insert_options(struct sock *sk, struct sk_buff *skb)
x_recv = htonl(hc->rx_x_recv);
pinv = htonl(hc->rx_pinv);
- if (dccp_insert_option(sk, skb, TFRC_OPT_LOSS_EVENT_RATE,
+ if (dccp_insert_option(skb, TFRC_OPT_LOSS_EVENT_RATE,
&pinv, sizeof(pinv)) ||
- dccp_insert_option(sk, skb, TFRC_OPT_RECEIVE_RATE,
+ dccp_insert_option(skb, TFRC_OPT_RECEIVE_RATE,
&x_recv, sizeof(x_recv)))
return -1;
diff --git a/net/dccp/dccp.h b/net/dccp/dccp.h
index a10a61a1ded..3ccef1b70fe 100644
--- a/net/dccp/dccp.h
+++ b/net/dccp/dccp.h
@@ -446,16 +446,12 @@ extern void dccp_feat_list_purge(struct list_head *fn_list);
extern int dccp_insert_options(struct sock *sk, struct sk_buff *skb);
extern int dccp_insert_options_rsk(struct dccp_request_sock*, struct sk_buff*);
-extern int dccp_insert_option_elapsed_time(struct sock *sk,
- struct sk_buff *skb,
- u32 elapsed_time);
+extern int dccp_insert_option_elapsed_time(struct sk_buff *skb, u32 elapsed);
extern u32 dccp_timestamp(void);
extern void dccp_timestamping_init(void);
-extern int dccp_insert_option_timestamp(struct sock *sk,
- struct sk_buff *skb);
-extern int dccp_insert_option(struct sock *sk, struct sk_buff *skb,
- unsigned char option,
- const void *value, unsigned char len);
+extern int dccp_insert_option_timestamp(struct sk_buff *skb);
+extern int dccp_insert_option(struct sk_buff *skb, unsigned char option,
+ const void *value, unsigned char len);
#ifdef CONFIG_SYSCTL
extern int dccp_sysctl_init(void);
diff --git a/net/dccp/input.c b/net/dccp/input.c
index 6beb6a7d6fb..10c957a88f4 100644
--- a/net/dccp/input.c
+++ b/net/dccp/input.c
@@ -430,7 +430,7 @@ static int dccp_rcv_request_sent_state_process(struct sock *sk,
if (dccp_parse_options(sk, NULL, skb))
return 1;
- /* Obtain usec RTT sample from SYN exchange (used by CCID 3) */
+ /* Obtain usec RTT sample from SYN exchange (used by TFRC). */
if (likely(dp->dccps_options_received.dccpor_timestamp_echo))
dp->dccps_syn_rtt = dccp_sample_rtt(sk, 10 * (tstamp -
dp->dccps_options_received.dccpor_timestamp_echo));
@@ -535,6 +535,8 @@ static int dccp_rcv_respond_partopen_state_process(struct sock *sk,
const struct dccp_hdr *dh,
const unsigned len)
{
+ struct dccp_sock *dp = dccp_sk(sk);
+ u32 sample = dp->dccps_options_received.dccpor_timestamp_echo;
int queued = 0;
switch (dh->dccph_type) {
@@ -559,7 +561,14 @@ static int dccp_rcv_respond_partopen_state_process(struct sock *sk,
if (sk->sk_state == DCCP_PARTOPEN)
inet_csk_clear_xmit_timer(sk, ICSK_TIME_DACK);
- dccp_sk(sk)->dccps_osr = DCCP_SKB_CB(skb)->dccpd_seq;
+ /* Obtain usec RTT sample from SYN exchange (used by TFRC). */
+ if (likely(sample)) {
+ long delta = dccp_timestamp() - sample;
+
+ dp->dccps_syn_rtt = dccp_sample_rtt(sk, 10 * delta);
+ }
+
+ dp->dccps_osr = DCCP_SKB_CB(skb)->dccpd_seq;
dccp_set_state(sk, DCCP_OPEN);
if (dh->dccph_type == DCCP_PKT_DATAACK ||
diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c
index d9b11ef8694..d4a166f0f39 100644
--- a/net/dccp/ipv4.c
+++ b/net/dccp/ipv4.c
@@ -105,7 +105,7 @@ int dccp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
goto failure;
/* OK, now commit destination to socket. */
- sk_setup_caps(sk, &rt->u.dst);
+ sk_setup_caps(sk, &rt->dst);
dp->dccps_iss = secure_dccp_sequence_number(inet->inet_saddr,
inet->inet_daddr,
@@ -475,7 +475,7 @@ static struct dst_entry* dccp_v4_route_skb(struct net *net, struct sock *sk,
return NULL;
}
- return &rt->u.dst;
+ return &rt->dst;
}
static int dccp_v4_send_response(struct sock *sk, struct request_sock *req,
diff --git a/net/dccp/ipv6.c b/net/dccp/ipv6.c
index 09169889959..6e3f32575df 100644
--- a/net/dccp/ipv6.c
+++ b/net/dccp/ipv6.c
@@ -248,7 +248,7 @@ static int dccp_v6_send_response(struct sock *sk, struct request_sock *req,
struct ipv6_pinfo *np = inet6_sk(sk);
struct sk_buff *skb;
struct ipv6_txoptions *opt = NULL;
- struct in6_addr *final_p = NULL, final;
+ struct in6_addr *final_p, final;
struct flowi fl;
int err = -1;
struct dst_entry *dst;
@@ -265,13 +265,7 @@ static int dccp_v6_send_response(struct sock *sk, struct request_sock *req,
opt = np->opt;
- if (opt != NULL && opt->srcrt != NULL) {
- const struct rt0_hdr *rt0 = (struct rt0_hdr *)opt->srcrt;
-
- ipv6_addr_copy(&final, &fl.fl6_dst);
- ipv6_addr_copy(&fl.fl6_dst, rt0->addr);
- final_p = &final;
- }
+ final_p = fl6_update_dst(&fl, opt, &final);
err = ip6_dst_lookup(sk, &dst, &fl);
if (err)
@@ -545,19 +539,13 @@ static struct sock *dccp_v6_request_recv_sock(struct sock *sk,
goto out_overflow;
if (dst == NULL) {
- struct in6_addr *final_p = NULL, final;
+ struct in6_addr *final_p, final;
struct flowi fl;
memset(&fl, 0, sizeof(fl));
fl.proto = IPPROTO_DCCP;
ipv6_addr_copy(&fl.fl6_dst, &ireq6->rmt_addr);
- if (opt != NULL && opt->srcrt != NULL) {
- const struct rt0_hdr *rt0 = (struct rt0_hdr *)opt->srcrt;
-
- ipv6_addr_copy(&final, &fl.fl6_dst);
- ipv6_addr_copy(&fl.fl6_dst, rt0->addr);
- final_p = &final;
- }
+ final_p = fl6_update_dst(&fl, opt, &final);
ipv6_addr_copy(&fl.fl6_src, &ireq6->loc_addr);
fl.oif = sk->sk_bound_dev_if;
fl.fl_ip_dport = inet_rsk(req)->rmt_port;
@@ -885,7 +873,7 @@ static int dccp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
struct inet_sock *inet = inet_sk(sk);
struct ipv6_pinfo *np = inet6_sk(sk);
struct dccp_sock *dp = dccp_sk(sk);
- struct in6_addr *saddr = NULL, *final_p = NULL, final;
+ struct in6_addr *saddr = NULL, *final_p, final;
struct flowi fl;
struct dst_entry *dst;
int addr_type;
@@ -988,13 +976,7 @@ static int dccp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
fl.fl_ip_sport = inet->inet_sport;
security_sk_classify_flow(sk, &fl);
- if (np->opt != NULL && np->opt->srcrt != NULL) {
- const struct rt0_hdr *rt0 = (struct rt0_hdr *)np->opt->srcrt;
-
- ipv6_addr_copy(&final, &fl.fl6_dst);
- ipv6_addr_copy(&fl.fl6_dst, rt0->addr);
- final_p = &final;
- }
+ final_p = fl6_update_dst(&fl, np->opt, &final);
err = ip6_dst_lookup(sk, &dst, &fl);
if (err)
diff --git a/net/dccp/options.c b/net/dccp/options.c
index 07395f861d3..bfda087bd90 100644
--- a/net/dccp/options.c
+++ b/net/dccp/options.c
@@ -299,9 +299,8 @@ static inline u8 dccp_ndp_len(const u64 ndp)
return likely(ndp <= USHRT_MAX) ? 2 : (ndp <= UINT_MAX ? 4 : 6);
}
-int dccp_insert_option(struct sock *sk, struct sk_buff *skb,
- const unsigned char option,
- const void *value, const unsigned char len)
+int dccp_insert_option(struct sk_buff *skb, const unsigned char option,
+ const void *value, const unsigned char len)
{
unsigned char *to;
@@ -354,8 +353,7 @@ static inline int dccp_elapsed_time_len(const u32 elapsed_time)
return elapsed_time == 0 ? 0 : elapsed_time <= 0xFFFF ? 2 : 4;
}
-int dccp_insert_option_elapsed_time(struct sock *sk, struct sk_buff *skb,
- u32 elapsed_time)
+int dccp_insert_option_elapsed_time(struct sk_buff *skb, u32 elapsed_time)
{
const int elapsed_time_len = dccp_elapsed_time_len(elapsed_time);
const int len = 2 + elapsed_time_len;
@@ -386,13 +384,13 @@ int dccp_insert_option_elapsed_time(struct sock *sk, struct sk_buff *skb,
EXPORT_SYMBOL_GPL(dccp_insert_option_elapsed_time);
-int dccp_insert_option_timestamp(struct sock *sk, struct sk_buff *skb)
+int dccp_insert_option_timestamp(struct sk_buff *skb)
{
__be32 now = htonl(dccp_timestamp());
/* yes this will overflow but that is the point as we want a
* 10 usec 32 bit timer which mean it wraps every 11.9 hours */
- return dccp_insert_option(sk, skb, DCCPO_TIMESTAMP, &now, sizeof(now));
+ return dccp_insert_option(skb, DCCPO_TIMESTAMP, &now, sizeof(now));
}
EXPORT_SYMBOL_GPL(dccp_insert_option_timestamp);
@@ -531,9 +529,9 @@ int dccp_insert_options(struct sock *sk, struct sk_buff *skb)
if (DCCP_SKB_CB(skb)->dccpd_type == DCCP_PKT_REQUEST) {
/*
* Obtain RTT sample from Request/Response exchange.
- * This is currently used in CCID 3 initialisation.
+ * This is currently used for TFRC initialisation.
*/
- if (dccp_insert_option_timestamp(sk, skb))
+ if (dccp_insert_option_timestamp(skb))
return -1;
} else if (dp->dccps_hc_rx_ackvec != NULL &&
@@ -564,6 +562,10 @@ int dccp_insert_options_rsk(struct dccp_request_sock *dreq, struct sk_buff *skb)
if (dccp_feat_insert_opts(NULL, dreq, skb))
return -1;
+ /* Obtain RTT sample from Response/Ack exchange (used by TFRC). */
+ if (dccp_insert_option_timestamp(skb))
+ return -1;
+
if (dreq->dreq_timestamp_echo != 0 &&
dccp_insert_option_timestamp_echo(NULL, dreq, skb))
return -1;
diff --git a/net/dccp/proto.c b/net/dccp/proto.c
index b03ecf6b2bb..096250d1323 100644
--- a/net/dccp/proto.c
+++ b/net/dccp/proto.c
@@ -473,14 +473,9 @@ static int dccp_setsockopt_ccid(struct sock *sk, int type,
if (optlen < 1 || optlen > DCCP_FEAT_MAX_SP_VALS)
return -EINVAL;
- val = kmalloc(optlen, GFP_KERNEL);
- if (val == NULL)
- return -ENOMEM;
-
- if (copy_from_user(val, optval, optlen)) {
- kfree(val);
- return -EFAULT;
- }
+ val = memdup_user(optval, optlen);
+ if (IS_ERR(val))
+ return PTR_ERR(val);
lock_sock(sk);
if (type == DCCP_SOCKOPT_TX_CCID || type == DCCP_SOCKOPT_CCID)
@@ -1007,7 +1002,8 @@ EXPORT_SYMBOL_GPL(dccp_shutdown);
static inline int dccp_mib_init(void)
{
return snmp_mib_init((void __percpu **)dccp_statistics,
- sizeof(struct dccp_mib));
+ sizeof(struct dccp_mib),
+ __alignof__(struct dccp_mib));
}
static inline void dccp_mib_exit(void)
diff --git a/net/decnet/dn_route.c b/net/decnet/dn_route.c
index 812e6dff606..6585ea6d118 100644
--- a/net/decnet/dn_route.c
+++ b/net/decnet/dn_route.c
@@ -146,13 +146,13 @@ static __inline__ unsigned dn_hash(__le16 src, __le16 dst)
static inline void dnrt_free(struct dn_route *rt)
{
- call_rcu_bh(&rt->u.dst.rcu_head, dst_rcu_free);
+ call_rcu_bh(&rt->dst.rcu_head, dst_rcu_free);
}
static inline void dnrt_drop(struct dn_route *rt)
{
- dst_release(&rt->u.dst);
- call_rcu_bh(&rt->u.dst.rcu_head, dst_rcu_free);
+ dst_release(&rt->dst);
+ call_rcu_bh(&rt->dst.rcu_head, dst_rcu_free);
}
static void dn_dst_check_expire(unsigned long dummy)
@@ -167,13 +167,13 @@ static void dn_dst_check_expire(unsigned long dummy)
spin_lock(&dn_rt_hash_table[i].lock);
while((rt=*rtp) != NULL) {
- if (atomic_read(&rt->u.dst.__refcnt) ||
- (now - rt->u.dst.lastuse) < expire) {
- rtp = &rt->u.dst.dn_next;
+ if (atomic_read(&rt->dst.__refcnt) ||
+ (now - rt->dst.lastuse) < expire) {
+ rtp = &rt->dst.dn_next;
continue;
}
- *rtp = rt->u.dst.dn_next;
- rt->u.dst.dn_next = NULL;
+ *rtp = rt->dst.dn_next;
+ rt->dst.dn_next = NULL;
dnrt_free(rt);
}
spin_unlock(&dn_rt_hash_table[i].lock);
@@ -198,13 +198,13 @@ static int dn_dst_gc(struct dst_ops *ops)
rtp = &dn_rt_hash_table[i].chain;
while((rt=*rtp) != NULL) {
- if (atomic_read(&rt->u.dst.__refcnt) ||
- (now - rt->u.dst.lastuse) < expire) {
- rtp = &rt->u.dst.dn_next;
+ if (atomic_read(&rt->dst.__refcnt) ||
+ (now - rt->dst.lastuse) < expire) {
+ rtp = &rt->dst.dn_next;
continue;
}
- *rtp = rt->u.dst.dn_next;
- rt->u.dst.dn_next = NULL;
+ *rtp = rt->dst.dn_next;
+ rt->dst.dn_next = NULL;
dnrt_drop(rt);
break;
}
@@ -287,25 +287,25 @@ static int dn_insert_route(struct dn_route *rt, unsigned hash, struct dn_route *
while((rth = *rthp) != NULL) {
if (compare_keys(&rth->fl, &rt->fl)) {
/* Put it first */
- *rthp = rth->u.dst.dn_next;
- rcu_assign_pointer(rth->u.dst.dn_next,
+ *rthp = rth->dst.dn_next;
+ rcu_assign_pointer(rth->dst.dn_next,
dn_rt_hash_table[hash].chain);
rcu_assign_pointer(dn_rt_hash_table[hash].chain, rth);
- dst_use(&rth->u.dst, now);
+ dst_use(&rth->dst, now);
spin_unlock_bh(&dn_rt_hash_table[hash].lock);
dnrt_drop(rt);
*rp = rth;
return 0;
}
- rthp = &rth->u.dst.dn_next;
+ rthp = &rth->dst.dn_next;
}
- rcu_assign_pointer(rt->u.dst.dn_next, dn_rt_hash_table[hash].chain);
+ rcu_assign_pointer(rt->dst.dn_next, dn_rt_hash_table[hash].chain);
rcu_assign_pointer(dn_rt_hash_table[hash].chain, rt);
- dst_use(&rt->u.dst, now);
+ dst_use(&rt->dst, now);
spin_unlock_bh(&dn_rt_hash_table[hash].lock);
*rp = rt;
return 0;
@@ -323,8 +323,8 @@ static void dn_run_flush(unsigned long dummy)
goto nothing_to_declare;
for(; rt; rt=next) {
- next = rt->u.dst.dn_next;
- rt->u.dst.dn_next = NULL;
+ next = rt->dst.dn_next;
+ rt->dst.dn_next = NULL;
dst_free((struct dst_entry *)rt);
}
@@ -743,7 +743,7 @@ static int dn_forward(struct sk_buff *skb)
/* Ensure that we have enough space for headers */
rt = (struct dn_route *)skb_dst(skb);
header_len = dn_db->use_long ? 21 : 6;
- if (skb_cow(skb, LL_RESERVED_SPACE(rt->u.dst.dev)+header_len))
+ if (skb_cow(skb, LL_RESERVED_SPACE(rt->dst.dev)+header_len))
goto drop;
/*
@@ -752,7 +752,7 @@ static int dn_forward(struct sk_buff *skb)
if (++cb->hops > 30)
goto drop;
- skb->dev = rt->u.dst.dev;
+ skb->dev = rt->dst.dev;
/*
* If packet goes out same interface it came in on, then set
@@ -792,7 +792,7 @@ static int dn_rt_bug(struct sk_buff *skb)
static int dn_rt_set_next_hop(struct dn_route *rt, struct dn_fib_res *res)
{
struct dn_fib_info *fi = res->fi;
- struct net_device *dev = rt->u.dst.dev;
+ struct net_device *dev = rt->dst.dev;
struct neighbour *n;
unsigned mss;
@@ -800,25 +800,25 @@ static int dn_rt_set_next_hop(struct dn_route *rt, struct dn_fib_res *res)
if (DN_FIB_RES_GW(*res) &&
DN_FIB_RES_NH(*res).nh_scope == RT_SCOPE_LINK)
rt->rt_gateway = DN_FIB_RES_GW(*res);
- memcpy(rt->u.dst.metrics, fi->fib_metrics,
- sizeof(rt->u.dst.metrics));
+ memcpy(rt->dst.metrics, fi->fib_metrics,
+ sizeof(rt->dst.metrics));
}
rt->rt_type = res->type;
- if (dev != NULL && rt->u.dst.neighbour == NULL) {
+ if (dev != NULL && rt->dst.neighbour == NULL) {
n = __neigh_lookup_errno(&dn_neigh_table, &rt->rt_gateway, dev);
if (IS_ERR(n))
return PTR_ERR(n);
- rt->u.dst.neighbour = n;
+ rt->dst.neighbour = n;
}
- if (dst_metric(&rt->u.dst, RTAX_MTU) == 0 ||
- dst_metric(&rt->u.dst, RTAX_MTU) > rt->u.dst.dev->mtu)
- rt->u.dst.metrics[RTAX_MTU-1] = rt->u.dst.dev->mtu;
- mss = dn_mss_from_pmtu(dev, dst_mtu(&rt->u.dst));
- if (dst_metric(&rt->u.dst, RTAX_ADVMSS) == 0 ||
- dst_metric(&rt->u.dst, RTAX_ADVMSS) > mss)
- rt->u.dst.metrics[RTAX_ADVMSS-1] = mss;
+ if (dst_metric(&rt->dst, RTAX_MTU) == 0 ||
+ dst_metric(&rt->dst, RTAX_MTU) > rt->dst.dev->mtu)
+ rt->dst.metrics[RTAX_MTU-1] = rt->dst.dev->mtu;
+ mss = dn_mss_from_pmtu(dev, dst_mtu(&rt->dst));
+ if (dst_metric(&rt->dst, RTAX_ADVMSS) == 0 ||
+ dst_metric(&rt->dst, RTAX_ADVMSS) > mss)
+ rt->dst.metrics[RTAX_ADVMSS-1] = mss;
return 0;
}
@@ -1096,8 +1096,8 @@ make_route:
if (rt == NULL)
goto e_nobufs;
- atomic_set(&rt->u.dst.__refcnt, 1);
- rt->u.dst.flags = DST_HOST;
+ atomic_set(&rt->dst.__refcnt, 1);
+ rt->dst.flags = DST_HOST;
rt->fl.fld_src = oldflp->fld_src;
rt->fl.fld_dst = oldflp->fld_dst;
@@ -1113,17 +1113,17 @@ make_route:
rt->rt_dst_map = fl.fld_dst;
rt->rt_src_map = fl.fld_src;
- rt->u.dst.dev = dev_out;
+ rt->dst.dev = dev_out;
dev_hold(dev_out);
- rt->u.dst.neighbour = neigh;
+ rt->dst.neighbour = neigh;
neigh = NULL;
- rt->u.dst.lastuse = jiffies;
- rt->u.dst.output = dn_output;
- rt->u.dst.input = dn_rt_bug;
+ rt->dst.lastuse = jiffies;
+ rt->dst.output = dn_output;
+ rt->dst.input = dn_rt_bug;
rt->rt_flags = flags;
if (flags & RTCF_LOCAL)
- rt->u.dst.input = dn_nsp_rx;
+ rt->dst.input = dn_nsp_rx;
err = dn_rt_set_next_hop(rt, &res);
if (err)
@@ -1152,7 +1152,7 @@ e_nobufs:
err = -ENOBUFS;
goto done;
e_neighbour:
- dst_free(&rt->u.dst);
+ dst_free(&rt->dst);
goto e_nobufs;
}
@@ -1168,15 +1168,15 @@ static int __dn_route_output_key(struct dst_entry **pprt, const struct flowi *fl
if (!(flags & MSG_TRYHARD)) {
rcu_read_lock_bh();
for (rt = rcu_dereference_bh(dn_rt_hash_table[hash].chain); rt;
- rt = rcu_dereference_bh(rt->u.dst.dn_next)) {
+ rt = rcu_dereference_bh(rt->dst.dn_next)) {
if ((flp->fld_dst == rt->fl.fld_dst) &&
(flp->fld_src == rt->fl.fld_src) &&
(flp->mark == rt->fl.mark) &&
(rt->fl.iif == 0) &&
(rt->fl.oif == flp->oif)) {
- dst_use(&rt->u.dst, jiffies);
+ dst_use(&rt->dst, jiffies);
rcu_read_unlock_bh();
- *pprt = &rt->u.dst;
+ *pprt = &rt->dst;
return 0;
}
}
@@ -1375,29 +1375,29 @@ make_route:
rt->fl.iif = in_dev->ifindex;
rt->fl.mark = fl.mark;
- rt->u.dst.flags = DST_HOST;
- rt->u.dst.neighbour = neigh;
- rt->u.dst.dev = out_dev;
- rt->u.dst.lastuse = jiffies;
- rt->u.dst.output = dn_rt_bug;
+ rt->dst.flags = DST_HOST;
+ rt->dst.neighbour = neigh;
+ rt->dst.dev = out_dev;
+ rt->dst.lastuse = jiffies;
+ rt->dst.output = dn_rt_bug;
switch(res.type) {
case RTN_UNICAST:
- rt->u.dst.input = dn_forward;
+ rt->dst.input = dn_forward;
break;
case RTN_LOCAL:
- rt->u.dst.output = dn_output;
- rt->u.dst.input = dn_nsp_rx;
- rt->u.dst.dev = in_dev;
+ rt->dst.output = dn_output;
+ rt->dst.input = dn_nsp_rx;
+ rt->dst.dev = in_dev;
flags |= RTCF_LOCAL;
break;
default:
case RTN_UNREACHABLE:
case RTN_BLACKHOLE:
- rt->u.dst.input = dst_discard;
+ rt->dst.input = dst_discard;
}
rt->rt_flags = flags;
- if (rt->u.dst.dev)
- dev_hold(rt->u.dst.dev);
+ if (rt->dst.dev)
+ dev_hold(rt->dst.dev);
err = dn_rt_set_next_hop(rt, &res);
if (err)
@@ -1405,7 +1405,7 @@ make_route:
hash = dn_hash(rt->fl.fld_src, rt->fl.fld_dst);
dn_insert_route(rt, hash, &rt);
- skb_dst_set(skb, &rt->u.dst);
+ skb_dst_set(skb, &rt->dst);
done:
if (neigh)
@@ -1427,7 +1427,7 @@ e_nobufs:
goto done;
e_neighbour:
- dst_free(&rt->u.dst);
+ dst_free(&rt->dst);
goto done;
}
@@ -1442,13 +1442,13 @@ static int dn_route_input(struct sk_buff *skb)
rcu_read_lock();
for(rt = rcu_dereference(dn_rt_hash_table[hash].chain); rt != NULL;
- rt = rcu_dereference(rt->u.dst.dn_next)) {
+ rt = rcu_dereference(rt->dst.dn_next)) {
if ((rt->fl.fld_src == cb->src) &&
(rt->fl.fld_dst == cb->dst) &&
(rt->fl.oif == 0) &&
(rt->fl.mark == skb->mark) &&
(rt->fl.iif == cb->iif)) {
- dst_use(&rt->u.dst, jiffies);
+ dst_use(&rt->dst, jiffies);
rcu_read_unlock();
skb_dst_set(skb, (struct dst_entry *)rt);
return 0;
@@ -1487,8 +1487,8 @@ static int dn_rt_fill_info(struct sk_buff *skb, u32 pid, u32 seq,
r->rtm_src_len = 16;
RTA_PUT(skb, RTA_SRC, 2, &rt->fl.fld_src);
}
- if (rt->u.dst.dev)
- RTA_PUT(skb, RTA_OIF, sizeof(int), &rt->u.dst.dev->ifindex);
+ if (rt->dst.dev)
+ RTA_PUT(skb, RTA_OIF, sizeof(int), &rt->dst.dev->ifindex);
/*
* Note to self - change this if input routes reverse direction when
* they deal only with inputs and not with replies like they do
@@ -1497,11 +1497,11 @@ static int dn_rt_fill_info(struct sk_buff *skb, u32 pid, u32 seq,
RTA_PUT(skb, RTA_PREFSRC, 2, &rt->rt_local_src);
if (rt->rt_daddr != rt->rt_gateway)
RTA_PUT(skb, RTA_GATEWAY, 2, &rt->rt_gateway);
- if (rtnetlink_put_metrics(skb, rt->u.dst.metrics) < 0)
+ if (rtnetlink_put_metrics(skb, rt->dst.metrics) < 0)
goto rtattr_failure;
- expires = rt->u.dst.expires ? rt->u.dst.expires - jiffies : 0;
- if (rtnl_put_cacheinfo(skb, &rt->u.dst, 0, 0, 0, expires,
- rt->u.dst.error) < 0)
+ expires = rt->dst.expires ? rt->dst.expires - jiffies : 0;
+ if (rtnl_put_cacheinfo(skb, &rt->dst, 0, 0, 0, expires,
+ rt->dst.error) < 0)
goto rtattr_failure;
if (rt->fl.iif)
RTA_PUT(skb, RTA_IIF, sizeof(int), &rt->fl.iif);
@@ -1568,8 +1568,8 @@ static int dn_cache_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh, void
local_bh_enable();
memset(cb, 0, sizeof(struct dn_skb_cb));
rt = (struct dn_route *)skb_dst(skb);
- if (!err && -rt->u.dst.error)
- err = rt->u.dst.error;
+ if (!err && -rt->dst.error)
+ err = rt->dst.error;
} else {
int oif = 0;
if (rta[RTA_OIF - 1])
@@ -1583,7 +1583,7 @@ static int dn_cache_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh, void
skb->dev = NULL;
if (err)
goto out_free;
- skb_dst_set(skb, &rt->u.dst);
+ skb_dst_set(skb, &rt->dst);
if (rtm->rtm_flags & RTM_F_NOTIFY)
rt->rt_flags |= RTCF_NOTIFY;
@@ -1632,10 +1632,10 @@ int dn_cache_dump(struct sk_buff *skb, struct netlink_callback *cb)
rcu_read_lock_bh();
for(rt = rcu_dereference_bh(dn_rt_hash_table[h].chain), idx = 0;
rt;
- rt = rcu_dereference_bh(rt->u.dst.dn_next), idx++) {
+ rt = rcu_dereference_bh(rt->dst.dn_next), idx++) {
if (idx < s_idx)
continue;
- skb_dst_set(skb, dst_clone(&rt->u.dst));
+ skb_dst_set(skb, dst_clone(&rt->dst));
if (dn_rt_fill_info(skb, NETLINK_CB(cb->skb).pid,
cb->nlh->nlmsg_seq, RTM_NEWROUTE,
1, NLM_F_MULTI) <= 0) {
@@ -1678,7 +1678,7 @@ static struct dn_route *dn_rt_cache_get_next(struct seq_file *seq, struct dn_rou
{
struct dn_rt_cache_iter_state *s = seq->private;
- rt = rt->u.dst.dn_next;
+ rt = rt->dst.dn_next;
while(!rt) {
rcu_read_unlock_bh();
if (--s->bucket < 0)
@@ -1719,12 +1719,12 @@ static int dn_rt_cache_seq_show(struct seq_file *seq, void *v)
char buf1[DN_ASCBUF_LEN], buf2[DN_ASCBUF_LEN];
seq_printf(seq, "%-8s %-7s %-7s %04d %04d %04d\n",
- rt->u.dst.dev ? rt->u.dst.dev->name : "*",
+ rt->dst.dev ? rt->dst.dev->name : "*",
dn_addr2asc(le16_to_cpu(rt->rt_daddr), buf1),
dn_addr2asc(le16_to_cpu(rt->rt_saddr), buf2),
- atomic_read(&rt->u.dst.__refcnt),
- rt->u.dst.__use,
- (int) dst_metric(&rt->u.dst, RTAX_RTT));
+ atomic_read(&rt->dst.__refcnt),
+ rt->dst.__use,
+ (int) dst_metric(&rt->dst, RTAX_RTT));
return 0;
}
diff --git a/net/dns_resolver/Kconfig b/net/dns_resolver/Kconfig
new file mode 100644
index 00000000000..50d49f7e047
--- /dev/null
+++ b/net/dns_resolver/Kconfig
@@ -0,0 +1,27 @@
+#
+# Configuration for DNS Resolver
+#
+config DNS_RESOLVER
+ tristate "DNS Resolver support"
+ depends on NET && KEYS
+ help
+ Saying Y here will include support for the DNS Resolver key type
+ which can be used to make upcalls to perform DNS lookups in
+ userspace.
+
+ DNS Resolver is used to query DNS server for information. Examples
+ being resolving a UNC hostname element to an IP address for CIFS or
+ performing a DNS query for AFSDB records so that AFS can locate a
+ cell's volume location database servers.
+
+ DNS Resolver is used by the CIFS and AFS modules, and would support
+ SMB2 later. DNS Resolver is supported by the userspace upcall
+ helper "/sbin/dns.resolver" via /etc/request-key.conf.
+
+ See <file:Documentation/networking/dns_resolver.txt> for further
+ information.
+
+ To compile this as a module, choose M here: the module will be called
+ dnsresolver.
+
+ If unsure, say N.
diff --git a/net/dns_resolver/Makefile b/net/dns_resolver/Makefile
new file mode 100644
index 00000000000..c0ef4e71dc4
--- /dev/null
+++ b/net/dns_resolver/Makefile
@@ -0,0 +1,7 @@
+#
+# Makefile for the Linux DNS Resolver.
+#
+
+obj-$(CONFIG_DNS_RESOLVER) += dns_resolver.o
+
+dns_resolver-objs := dns_key.o dns_query.o
diff --git a/net/dns_resolver/dns_key.c b/net/dns_resolver/dns_key.c
new file mode 100644
index 00000000000..400a04d5c9a
--- /dev/null
+++ b/net/dns_resolver/dns_key.c
@@ -0,0 +1,211 @@
+/* Key type used to cache DNS lookups made by the kernel
+ *
+ * See Documentation/networking/dns_resolver.txt
+ *
+ * Copyright (c) 2007 Igor Mammedov
+ * Author(s): Igor Mammedov (niallain@gmail.com)
+ * Steve French (sfrench@us.ibm.com)
+ * Wang Lei (wang840925@gmail.com)
+ * David Howells (dhowells@redhat.com)
+ *
+ * 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
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * 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
+ */
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/keyctl.h>
+#include <linux/err.h>
+#include <keys/dns_resolver-type.h>
+#include <keys/user-type.h>
+#include "internal.h"
+
+MODULE_DESCRIPTION("DNS Resolver");
+MODULE_AUTHOR("Wang Lei");
+MODULE_LICENSE("GPL");
+
+unsigned dns_resolver_debug;
+module_param_named(debug, dns_resolver_debug, uint, S_IWUSR | S_IRUGO);
+MODULE_PARM_DESC(debug, "DNS Resolver debugging mask");
+
+const struct cred *dns_resolver_cache;
+
+/*
+ * Instantiate a user defined key for dns_resolver.
+ *
+ * The data must be a NUL-terminated string, with the NUL char accounted in
+ * datalen.
+ *
+ * If the data contains a '#' characters, then we take the clause after each
+ * one to be an option of the form 'key=value'. The actual data of interest is
+ * the string leading up to the first '#'. For instance:
+ *
+ * "ip1,ip2,...#foo=bar"
+ */
+static int
+dns_resolver_instantiate(struct key *key, const void *_data, size_t datalen)
+{
+ struct user_key_payload *upayload;
+ int ret;
+ size_t result_len = 0;
+ const char *data = _data, *opt;
+
+ kenter("%%%d,%s,'%s',%zu",
+ key->serial, key->description, data, datalen);
+
+ if (datalen <= 1 || !data || data[datalen - 1] != '\0')
+ return -EINVAL;
+ datalen--;
+
+ /* deal with any options embedded in the data */
+ opt = memchr(data, '#', datalen);
+ if (!opt) {
+ kdebug("no options currently supported");
+ return -EINVAL;
+ }
+
+ result_len = datalen;
+ ret = key_payload_reserve(key, result_len);
+ if (ret < 0)
+ return -EINVAL;
+
+ upayload = kmalloc(sizeof(*upayload) + result_len + 1, GFP_KERNEL);
+ if (!upayload) {
+ kleave(" = -ENOMEM");
+ return -ENOMEM;
+ }
+
+ upayload->datalen = result_len;
+ memcpy(upayload->data, data, result_len);
+ upayload->data[result_len] = '\0';
+ rcu_assign_pointer(key->payload.data, upayload);
+
+ kleave(" = 0");
+ return 0;
+}
+
+/*
+ * The description is of the form "[<type>:]<domain_name>"
+ *
+ * The domain name may be a simple name or an absolute domain name (which
+ * should end with a period). The domain name is case-independent.
+ */
+static int
+dns_resolver_match(const struct key *key, const void *description)
+{
+ int slen, dlen, ret = 0;
+ const char *src = key->description, *dsp = description;
+
+ kenter("%s,%s", src, dsp);
+
+ if (!src || !dsp)
+ goto no_match;
+
+ if (strcasecmp(src, dsp) == 0)
+ goto matched;
+
+ slen = strlen(src);
+ dlen = strlen(dsp);
+ if (slen <= 0 || dlen <= 0)
+ goto no_match;
+ if (src[slen - 1] == '.')
+ slen--;
+ if (dsp[dlen - 1] == '.')
+ dlen--;
+ if (slen != dlen || strncasecmp(src, dsp, slen) != 0)
+ goto no_match;
+
+matched:
+ ret = 1;
+no_match:
+ kleave(" = %d", ret);
+ return ret;
+}
+
+struct key_type key_type_dns_resolver = {
+ .name = "dns_resolver",
+ .instantiate = dns_resolver_instantiate,
+ .match = dns_resolver_match,
+ .revoke = user_revoke,
+ .destroy = user_destroy,
+ .describe = user_describe,
+ .read = user_read,
+};
+
+static int __init init_dns_resolver(void)
+{
+ struct cred *cred;
+ struct key *keyring;
+ int ret;
+
+ printk(KERN_NOTICE "Registering the %s key type\n",
+ key_type_dns_resolver.name);
+
+ /* create an override credential set with a special thread keyring in
+ * which DNS requests are cached
+ *
+ * this is used to prevent malicious redirections from being installed
+ * with add_key().
+ */
+ cred = prepare_kernel_cred(NULL);
+ if (!cred)
+ return -ENOMEM;
+
+ keyring = key_alloc(&key_type_keyring, ".dns_resolver", 0, 0, cred,
+ (KEY_POS_ALL & ~KEY_POS_SETATTR) |
+ KEY_USR_VIEW | KEY_USR_READ,
+ KEY_ALLOC_NOT_IN_QUOTA);
+ if (IS_ERR(keyring)) {
+ ret = PTR_ERR(keyring);
+ goto failed_put_cred;
+ }
+
+ ret = key_instantiate_and_link(keyring, NULL, 0, NULL, NULL);
+ if (ret < 0)
+ goto failed_put_key;
+
+ ret = register_key_type(&key_type_dns_resolver);
+ if (ret < 0)
+ goto failed_put_key;
+
+ /* instruct request_key() to use this special keyring as a cache for
+ * the results it looks up */
+ cred->thread_keyring = keyring;
+ cred->jit_keyring = KEY_REQKEY_DEFL_THREAD_KEYRING;
+ dns_resolver_cache = cred;
+
+ kdebug("DNS resolver keyring: %d\n", key_serial(keyring));
+ return 0;
+
+failed_put_key:
+ key_put(keyring);
+failed_put_cred:
+ put_cred(cred);
+ return ret;
+}
+
+static void __exit exit_dns_resolver(void)
+{
+ key_revoke(dns_resolver_cache->thread_keyring);
+ unregister_key_type(&key_type_dns_resolver);
+ put_cred(dns_resolver_cache);
+ printk(KERN_NOTICE "Unregistered %s key type\n",
+ key_type_dns_resolver.name);
+}
+
+module_init(init_dns_resolver)
+module_exit(exit_dns_resolver)
+MODULE_LICENSE("GPL");
diff --git a/net/dns_resolver/dns_query.c b/net/dns_resolver/dns_query.c
new file mode 100644
index 00000000000..03d5255f5cf
--- /dev/null
+++ b/net/dns_resolver/dns_query.c
@@ -0,0 +1,160 @@
+/* Upcall routine, designed to work as a key type and working through
+ * /sbin/request-key to contact userspace when handling DNS queries.
+ *
+ * See Documentation/networking/dns_resolver.txt
+ *
+ * Copyright (c) 2007 Igor Mammedov
+ * Author(s): Igor Mammedov (niallain@gmail.com)
+ * Steve French (sfrench@us.ibm.com)
+ * Wang Lei (wang840925@gmail.com)
+ * David Howells (dhowells@redhat.com)
+ *
+ * The upcall wrapper used to make an arbitrary DNS query.
+ *
+ * This function requires the appropriate userspace tool dns.upcall to be
+ * installed and something like the following lines should be added to the
+ * /etc/request-key.conf file:
+ *
+ * create dns_resolver * * /sbin/dns.upcall %k
+ *
+ * For example to use this module to query AFSDB RR:
+ *
+ * create dns_resolver afsdb:* * /sbin/dns.afsdb %k
+ *
+ * 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
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * 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
+ */
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/dns_resolver.h>
+#include <linux/err.h>
+#include <keys/dns_resolver-type.h>
+#include <keys/user-type.h>
+
+#include "internal.h"
+
+/**
+ * dns_query - Query the DNS
+ * @type: Query type (or NULL for straight host->IP lookup)
+ * @name: Name to look up
+ * @namelen: Length of name
+ * @options: Request options (or NULL if no options)
+ * @_result: Where to place the returned data.
+ * @_expiry: Where to store the result expiry time (or NULL)
+ *
+ * The data will be returned in the pointer at *result, and the caller is
+ * responsible for freeing it.
+ *
+ * The description should be of the form "[<query_type>:]<domain_name>", and
+ * the options need to be appropriate for the query type requested. If no
+ * query_type is given, then the query is a straight hostname to IP address
+ * lookup.
+ *
+ * The DNS resolution lookup is performed by upcalling to userspace by way of
+ * requesting a key of type dns_resolver.
+ *
+ * Returns the size of the result on success, -ve error code otherwise.
+ */
+int dns_query(const char *type, const char *name, size_t namelen,
+ const char *options, char **_result, time_t *_expiry)
+{
+ struct key *rkey;
+ struct user_key_payload *upayload;
+ const struct cred *saved_cred;
+ size_t typelen, desclen;
+ char *desc, *cp;
+ int ret, len;
+
+ kenter("%s,%*.*s,%zu,%s",
+ type, (int)namelen, (int)namelen, name, namelen, options);
+
+ if (!name || namelen == 0 || !_result)
+ return -EINVAL;
+
+ /* construct the query key description as "[<type>:]<name>" */
+ typelen = 0;
+ desclen = 0;
+ if (type) {
+ typelen = strlen(type);
+ if (typelen < 1)
+ return -EINVAL;
+ desclen += typelen + 1;
+ }
+
+ if (!namelen)
+ namelen = strlen(name);
+ if (namelen < 3)
+ return -EINVAL;
+ desclen += namelen + 1;
+
+ desc = kmalloc(desclen, GFP_KERNEL);
+ if (!desc)
+ return -ENOMEM;
+
+ cp = desc;
+ if (type) {
+ memcpy(cp, type, typelen);
+ cp += typelen;
+ *cp++ = ':';
+ }
+ memcpy(cp, name, namelen);
+ cp += namelen;
+ *cp = '\0';
+
+ if (!options)
+ options = "";
+ kdebug("call request_key(,%s,%s)", desc, options);
+
+ /* make the upcall, using special credentials to prevent the use of
+ * add_key() to preinstall malicious redirections
+ */
+ saved_cred = override_creds(dns_resolver_cache);
+ rkey = request_key(&key_type_dns_resolver, desc, options);
+ revert_creds(saved_cred);
+ kfree(desc);
+ if (IS_ERR(rkey)) {
+ ret = PTR_ERR(rkey);
+ goto out;
+ }
+
+ down_read(&rkey->sem);
+ rkey->perm |= KEY_USR_VIEW;
+
+ ret = key_validate(rkey);
+ if (ret < 0)
+ goto put;
+
+ upayload = rcu_dereference_protected(rkey->payload.data,
+ lockdep_is_held(&rkey->sem));
+ len = upayload->datalen;
+
+ ret = -ENOMEM;
+ *_result = kmalloc(len + 1, GFP_KERNEL);
+ if (!*_result)
+ goto put;
+
+ memcpy(*_result, upayload->data, len + 1);
+ if (_expiry)
+ *_expiry = rkey->expiry;
+
+ ret = len;
+put:
+ up_read(&rkey->sem);
+ key_put(rkey);
+out:
+ kleave(" = %d", ret);
+ return ret;
+}
+EXPORT_SYMBOL(dns_query);
diff --git a/net/dns_resolver/internal.h b/net/dns_resolver/internal.h
new file mode 100644
index 00000000000..189ca9e9b78
--- /dev/null
+++ b/net/dns_resolver/internal.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2010 Wang Lei
+ * Author(s): Wang Lei (wang840925@gmail.com). All Rights Reserved.
+ *
+ * Internal DNS Rsolver stuff
+ *
+ * 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
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * 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
+ */
+
+#include <linux/compiler.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+
+/*
+ * dns_key.c
+ */
+extern const struct cred *dns_resolver_cache;
+
+/*
+ * debug tracing
+ */
+extern unsigned dns_resolver_debug;
+
+#define kdebug(FMT, ...) \
+do { \
+ if (unlikely(dns_resolver_debug)) \
+ printk(KERN_DEBUG "[%-6.6s] "FMT"\n", \
+ current->comm, ##__VA_ARGS__); \
+} while (0)
+
+#define kenter(FMT, ...) kdebug("==> %s("FMT")", __func__, ##__VA_ARGS__)
+#define kleave(FMT, ...) kdebug("<== %s()"FMT"", __func__, ##__VA_ARGS__)
diff --git a/net/dsa/slave.c b/net/dsa/slave.c
index 8fdca56bb08..64ca2a6fa0d 100644
--- a/net/dsa/slave.c
+++ b/net/dsa/slave.c
@@ -164,10 +164,9 @@ out:
static int dsa_slave_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
{
struct dsa_slave_priv *p = netdev_priv(dev);
- struct mii_ioctl_data *mii_data = if_mii(ifr);
if (p->phy != NULL)
- return phy_mii_ioctl(p->phy, mii_data, cmd);
+ return phy_mii_ioctl(p->phy, ifr, cmd);
return -EOPNOTSUPP;
}
diff --git a/net/econet/af_econet.c b/net/econet/af_econet.c
index 2a5a8053e00..dc54bd0d083 100644
--- a/net/econet/af_econet.c
+++ b/net/econet/af_econet.c
@@ -48,7 +48,7 @@
static const struct proto_ops econet_ops;
static struct hlist_head econet_sklist;
-static DEFINE_RWLOCK(econet_lock);
+static DEFINE_SPINLOCK(econet_lock);
static DEFINE_MUTEX(econet_mutex);
/* Since there are only 256 possible network numbers (or fewer, depends
@@ -98,16 +98,16 @@ struct ec_cb
static void econet_remove_socket(struct hlist_head *list, struct sock *sk)
{
- write_lock_bh(&econet_lock);
+ spin_lock_bh(&econet_lock);
sk_del_node_init(sk);
- write_unlock_bh(&econet_lock);
+ spin_unlock_bh(&econet_lock);
}
static void econet_insert_socket(struct hlist_head *list, struct sock *sk)
{
- write_lock_bh(&econet_lock);
+ spin_lock_bh(&econet_lock);
sk_add_node(sk, list);
- write_unlock_bh(&econet_lock);
+ spin_unlock_bh(&econet_lock);
}
/*
@@ -782,15 +782,19 @@ static struct sock *ec_listening_socket(unsigned char port, unsigned char
struct sock *sk;
struct hlist_node *node;
+ spin_lock(&econet_lock);
sk_for_each(sk, node, &econet_sklist) {
struct econet_sock *opt = ec_sk(sk);
if ((opt->port == port || opt->port == 0) &&
(opt->station == station || opt->station == 0) &&
- (opt->net == net || opt->net == 0))
+ (opt->net == net || opt->net == 0)) {
+ sock_hold(sk);
goto found;
+ }
}
sk = NULL;
found:
+ spin_unlock(&econet_lock);
return sk;
}
@@ -852,7 +856,7 @@ static void aun_incoming(struct sk_buff *skb, struct aunhdr *ah, size_t len)
{
struct iphdr *ip = ip_hdr(skb);
unsigned char stn = ntohl(ip->saddr) & 0xff;
- struct sock *sk;
+ struct sock *sk = NULL;
struct sk_buff *newskb;
struct ec_device *edev = skb->dev->ec_ptr;
@@ -882,10 +886,13 @@ static void aun_incoming(struct sk_buff *skb, struct aunhdr *ah, size_t len)
}
aun_send_response(ip->saddr, ah->handle, 3, 0);
+ sock_put(sk);
return;
bad:
aun_send_response(ip->saddr, ah->handle, 4, 0);
+ if (sk)
+ sock_put(sk);
}
/*
@@ -1050,7 +1057,7 @@ release:
static int econet_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev)
{
struct ec_framehdr *hdr;
- struct sock *sk;
+ struct sock *sk = NULL;
struct ec_device *edev = dev->ec_ptr;
if (!net_eq(dev_net(dev), &init_net))
@@ -1085,10 +1092,12 @@ static int econet_rcv(struct sk_buff *skb, struct net_device *dev, struct packet
if (ec_queue_packet(sk, skb, edev->net, hdr->src_stn, hdr->cb,
hdr->port))
goto drop;
-
+ sock_put(sk);
return NET_RX_SUCCESS;
drop:
+ if (sk)
+ sock_put(sk);
kfree_skb(skb);
return NET_RX_DROP;
}
diff --git a/net/ethernet/eth.c b/net/ethernet/eth.c
index 61ec0329316..215c83986a9 100644
--- a/net/ethernet/eth.c
+++ b/net/ethernet/eth.c
@@ -158,7 +158,6 @@ EXPORT_SYMBOL(eth_rebuild_header);
__be16 eth_type_trans(struct sk_buff *skb, struct net_device *dev)
{
struct ethhdr *eth;
- unsigned char *rawp;
skb->dev = dev;
skb_reset_mac_header(skb);
@@ -199,15 +198,13 @@ __be16 eth_type_trans(struct sk_buff *skb, struct net_device *dev)
if (ntohs(eth->h_proto) >= 1536)
return eth->h_proto;
- rawp = skb->data;
-
/*
* This is a magic hack to spot IPX packets. Older Novell breaks
* the protocol design and runs IPX over 802.3 without an 802.2 LLC
* layer. We look for FFFF which isn't a used 802.2 SSAP/DSAP. This
* won't work for fault tolerant netware but does for the rest.
*/
- if (*(unsigned short *)rawp == 0xFFFF)
+ if (skb->len >= 2 && *(unsigned short *)(skb->data) == 0xFFFF)
return htons(ETH_P_802_3);
/*
diff --git a/net/ethernet/pe2.c b/net/ethernet/pe2.c
index eb00796758c..85d574addbc 100644
--- a/net/ethernet/pe2.c
+++ b/net/ethernet/pe2.c
@@ -28,11 +28,10 @@ struct datalink_proto *make_EII_client(void)
return proto;
}
+EXPORT_SYMBOL(make_EII_client);
void destroy_EII_client(struct datalink_proto *dl)
{
kfree(dl);
}
-
EXPORT_SYMBOL(destroy_EII_client);
-EXPORT_SYMBOL(make_EII_client);
diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c
index 551ce564b03..6a1100c25a9 100644
--- a/net/ipv4/af_inet.c
+++ b/net/ipv4/af_inet.c
@@ -355,6 +355,8 @@ lookup_protocol:
inet = inet_sk(sk);
inet->is_icsk = (INET_PROTOSW_ICSK & answer_flags) != 0;
+ inet->nodefrag = 0;
+
if (SOCK_RAW == sock->type) {
inet->inet_num = protocol;
if (IPPROTO_RAW == protocol)
@@ -725,28 +727,31 @@ int inet_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg,
sock_rps_record_flow(sk);
/* We may need to bind the socket. */
- if (!inet_sk(sk)->inet_num && inet_autobind(sk))
+ if (!inet_sk(sk)->inet_num && !sk->sk_prot->no_autobind &&
+ inet_autobind(sk))
return -EAGAIN;
return sk->sk_prot->sendmsg(iocb, sk, msg, size);
}
EXPORT_SYMBOL(inet_sendmsg);
-static ssize_t inet_sendpage(struct socket *sock, struct page *page, int offset,
- size_t size, int flags)
+ssize_t inet_sendpage(struct socket *sock, struct page *page, int offset,
+ size_t size, int flags)
{
struct sock *sk = sock->sk;
sock_rps_record_flow(sk);
/* We may need to bind the socket. */
- if (!inet_sk(sk)->inet_num && inet_autobind(sk))
+ if (!inet_sk(sk)->inet_num && !sk->sk_prot->no_autobind &&
+ inet_autobind(sk))
return -EAGAIN;
if (sk->sk_prot->sendpage)
return sk->sk_prot->sendpage(sk, page, offset, size, flags);
return sock_no_sendpage(sock, page, offset, size, flags);
}
+EXPORT_SYMBOL(inet_sendpage);
int inet_recvmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg,
size_t size, int flags)
@@ -892,10 +897,10 @@ const struct proto_ops inet_stream_ops = {
.shutdown = inet_shutdown,
.setsockopt = sock_common_setsockopt,
.getsockopt = sock_common_getsockopt,
- .sendmsg = tcp_sendmsg,
+ .sendmsg = inet_sendmsg,
.recvmsg = inet_recvmsg,
.mmap = sock_no_mmap,
- .sendpage = tcp_sendpage,
+ .sendpage = inet_sendpage,
.splice_read = tcp_splice_read,
#ifdef CONFIG_COMPAT
.compat_setsockopt = compat_sock_common_setsockopt,
@@ -1100,7 +1105,7 @@ static int inet_sk_reselect_saddr(struct sock *sk)
if (err)
return err;
- sk_setup_caps(sk, &rt->u.dst);
+ sk_setup_caps(sk, &rt->dst);
new_saddr = rt->rt_src;
@@ -1166,7 +1171,7 @@ int inet_sk_rebuild_header(struct sock *sk)
err = ip_route_output_flow(sock_net(sk), &rt, &fl, sk, 0);
}
if (!err)
- sk_setup_caps(sk, &rt->u.dst);
+ sk_setup_caps(sk, &rt->dst);
else {
/* Routing failed... */
sk->sk_route_caps = 0;
@@ -1425,13 +1430,49 @@ unsigned long snmp_fold_field(void __percpu *mib[], int offt)
}
EXPORT_SYMBOL_GPL(snmp_fold_field);
-int snmp_mib_init(void __percpu *ptr[2], size_t mibsize)
+#if BITS_PER_LONG==32
+
+u64 snmp_fold_field64(void __percpu *mib[], int offt, size_t syncp_offset)
+{
+ u64 res = 0;
+ int cpu;
+
+ for_each_possible_cpu(cpu) {
+ void *bhptr, *userptr;
+ struct u64_stats_sync *syncp;
+ u64 v_bh, v_user;
+ unsigned int start;
+
+ /* first mib used by softirq context, we must use _bh() accessors */
+ bhptr = per_cpu_ptr(SNMP_STAT_BHPTR(mib), cpu);
+ syncp = (struct u64_stats_sync *)(bhptr + syncp_offset);
+ do {
+ start = u64_stats_fetch_begin_bh(syncp);
+ v_bh = *(((u64 *) bhptr) + offt);
+ } while (u64_stats_fetch_retry_bh(syncp, start));
+
+ /* second mib used in USER context */
+ userptr = per_cpu_ptr(SNMP_STAT_USRPTR(mib), cpu);
+ syncp = (struct u64_stats_sync *)(userptr + syncp_offset);
+ do {
+ start = u64_stats_fetch_begin(syncp);
+ v_user = *(((u64 *) userptr) + offt);
+ } while (u64_stats_fetch_retry(syncp, start));
+
+ res += v_bh + v_user;
+ }
+ return res;
+}
+EXPORT_SYMBOL_GPL(snmp_fold_field64);
+#endif
+
+int snmp_mib_init(void __percpu *ptr[2], size_t mibsize, size_t align)
{
BUG_ON(ptr == NULL);
- ptr[0] = __alloc_percpu(mibsize, __alignof__(unsigned long));
+ ptr[0] = __alloc_percpu(mibsize, align);
if (!ptr[0])
goto err0;
- ptr[1] = __alloc_percpu(mibsize, __alignof__(unsigned long));
+ ptr[1] = __alloc_percpu(mibsize, align);
if (!ptr[1])
goto err1;
return 0;
@@ -1488,25 +1529,32 @@ static const struct net_protocol icmp_protocol = {
static __net_init int ipv4_mib_init_net(struct net *net)
{
if (snmp_mib_init((void __percpu **)net->mib.tcp_statistics,
- sizeof(struct tcp_mib)) < 0)
+ sizeof(struct tcp_mib),
+ __alignof__(struct tcp_mib)) < 0)
goto err_tcp_mib;
if (snmp_mib_init((void __percpu **)net->mib.ip_statistics,
- sizeof(struct ipstats_mib)) < 0)
+ sizeof(struct ipstats_mib),
+ __alignof__(struct ipstats_mib)) < 0)
goto err_ip_mib;
if (snmp_mib_init((void __percpu **)net->mib.net_statistics,
- sizeof(struct linux_mib)) < 0)
+ sizeof(struct linux_mib),
+ __alignof__(struct linux_mib)) < 0)
goto err_net_mib;
if (snmp_mib_init((void __percpu **)net->mib.udp_statistics,
- sizeof(struct udp_mib)) < 0)
+ sizeof(struct udp_mib),
+ __alignof__(struct udp_mib)) < 0)
goto err_udp_mib;
if (snmp_mib_init((void __percpu **)net->mib.udplite_statistics,
- sizeof(struct udp_mib)) < 0)
+ sizeof(struct udp_mib),
+ __alignof__(struct udp_mib)) < 0)
goto err_udplite_mib;
if (snmp_mib_init((void __percpu **)net->mib.icmp_statistics,
- sizeof(struct icmp_mib)) < 0)
+ sizeof(struct icmp_mib),
+ __alignof__(struct icmp_mib)) < 0)
goto err_icmp_mib;
if (snmp_mib_init((void __percpu **)net->mib.icmpmsg_statistics,
- sizeof(struct icmpmsg_mib)) < 0)
+ sizeof(struct icmpmsg_mib),
+ __alignof__(struct icmpmsg_mib)) < 0)
goto err_icmpmsg_mib;
tcp_mib_init(net);
diff --git a/net/ipv4/arp.c b/net/ipv4/arp.c
index f094b75810d..96c1955b3e2 100644
--- a/net/ipv4/arp.c
+++ b/net/ipv4/arp.c
@@ -116,6 +116,7 @@
#if defined(CONFIG_ATM_CLIP) || defined(CONFIG_ATM_CLIP_MODULE)
#include <net/atmclip.h>
struct neigh_table *clip_tbl_hook;
+EXPORT_SYMBOL(clip_tbl_hook);
#endif
#include <asm/system.h>
@@ -169,6 +170,7 @@ const struct neigh_ops arp_broken_ops = {
.hh_output = dev_queue_xmit,
.queue_xmit = dev_queue_xmit,
};
+EXPORT_SYMBOL(arp_broken_ops);
struct neigh_table arp_tbl = {
.family = AF_INET,
@@ -198,6 +200,7 @@ struct neigh_table arp_tbl = {
.gc_thresh2 = 512,
.gc_thresh3 = 1024,
};
+EXPORT_SYMBOL(arp_tbl);
int arp_mc_map(__be32 addr, u8 *haddr, struct net_device *dev, int dir)
{
@@ -333,11 +336,14 @@ static void arp_solicit(struct neighbour *neigh, struct sk_buff *skb)
struct net_device *dev = neigh->dev;
__be32 target = *(__be32*)neigh->primary_key;
int probes = atomic_read(&neigh->probes);
- struct in_device *in_dev = in_dev_get(dev);
+ struct in_device *in_dev;
- if (!in_dev)
+ rcu_read_lock();
+ in_dev = __in_dev_get_rcu(dev);
+ if (!in_dev) {
+ rcu_read_unlock();
return;
-
+ }
switch (IN_DEV_ARP_ANNOUNCE(in_dev)) {
default:
case 0: /* By default announce any local IP */
@@ -358,9 +364,8 @@ static void arp_solicit(struct neighbour *neigh, struct sk_buff *skb)
case 2: /* Avoid secondary IPs, get a primary/preferred one */
break;
}
+ rcu_read_unlock();
- if (in_dev)
- in_dev_put(in_dev);
if (!saddr)
saddr = inet_select_addr(dev, target, RT_SCOPE_LINK);
@@ -427,7 +432,7 @@ static int arp_filter(__be32 sip, __be32 tip, struct net_device *dev)
if (ip_route_output_key(net, &rt, &fl) < 0)
return 1;
- if (rt->u.dst.dev != dev) {
+ if (rt->dst.dev != dev) {
NET_INC_STATS_BH(net, LINUX_MIB_ARPFILTER);
flag = 1;
}
@@ -497,6 +502,7 @@ int arp_find(unsigned char *haddr, struct sk_buff *skb)
kfree_skb(skb);
return 1;
}
+EXPORT_SYMBOL(arp_find);
/* END OF OBSOLETE FUNCTIONS */
@@ -532,7 +538,7 @@ static inline int arp_fwd_proxy(struct in_device *in_dev,
struct in_device *out_dev;
int imi, omi = -1;
- if (rt->u.dst.dev == dev)
+ if (rt->dst.dev == dev)
return 0;
if (!IN_DEV_PROXY_ARP(in_dev))
@@ -545,10 +551,10 @@ static inline int arp_fwd_proxy(struct in_device *in_dev,
/* place to check for proxy_arp for routes */
- if ((out_dev = in_dev_get(rt->u.dst.dev)) != NULL) {
+ out_dev = __in_dev_get_rcu(rt->dst.dev);
+ if (out_dev)
omi = IN_DEV_MEDIUM_ID(out_dev);
- in_dev_put(out_dev);
- }
+
return (omi != imi && omi != -1);
}
@@ -576,7 +582,7 @@ static inline int arp_fwd_pvlan(struct in_device *in_dev,
__be32 sip, __be32 tip)
{
/* Private VLAN is only concerned about the same ethernet segment */
- if (rt->u.dst.dev != dev)
+ if (rt->dst.dev != dev)
return 0;
/* Don't reply on self probes (often done by windowz boxes)*/
@@ -698,6 +704,7 @@ out:
kfree_skb(skb);
return NULL;
}
+EXPORT_SYMBOL(arp_create);
/*
* Send an arp packet.
@@ -707,6 +714,7 @@ void arp_xmit(struct sk_buff *skb)
/* Send it off, maybe filter it using firewalling first. */
NF_HOOK(NFPROTO_ARP, NF_ARP_OUT, skb, NULL, skb->dev, dev_queue_xmit);
}
+EXPORT_SYMBOL(arp_xmit);
/*
* Create and send an arp packet.
@@ -733,6 +741,7 @@ void arp_send(int type, int ptype, __be32 dest_ip,
arp_xmit(skb);
}
+EXPORT_SYMBOL(arp_send);
/*
* Process an arp request.
@@ -741,7 +750,7 @@ void arp_send(int type, int ptype, __be32 dest_ip,
static int arp_process(struct sk_buff *skb)
{
struct net_device *dev = skb->dev;
- struct in_device *in_dev = in_dev_get(dev);
+ struct in_device *in_dev = __in_dev_get_rcu(dev);
struct arphdr *arp;
unsigned char *arp_ptr;
struct rtable *rt;
@@ -890,7 +899,6 @@ static int arp_process(struct sk_buff *skb)
arp_send(ARPOP_REPLY,ETH_P_ARP,sip,dev,tip,sha,dev->dev_addr,sha);
} else {
pneigh_enqueue(&arp_tbl, in_dev->arp_parms, skb);
- in_dev_put(in_dev);
return 0;
}
goto out;
@@ -936,8 +944,6 @@ static int arp_process(struct sk_buff *skb)
}
out:
- if (in_dev)
- in_dev_put(in_dev);
consume_skb(skb);
return 0;
}
@@ -1045,7 +1051,7 @@ static int arp_req_set(struct net *net, struct arpreq *r,
struct rtable * rt;
if ((err = ip_route_output_key(net, &rt, &fl)) != 0)
return err;
- dev = rt->u.dst.dev;
+ dev = rt->dst.dev;
ip_rt_put(rt);
if (!dev)
return -EINVAL;
@@ -1152,7 +1158,7 @@ static int arp_req_delete(struct net *net, struct arpreq *r,
struct rtable * rt;
if ((err = ip_route_output_key(net, &rt, &fl)) != 0)
return err;
- dev = rt->u.dst.dev;
+ dev = rt->dst.dev;
ip_rt_put(rt);
if (!dev)
return -EINVAL;
@@ -1453,14 +1459,3 @@ static int __init arp_proc_init(void)
}
#endif /* CONFIG_PROC_FS */
-
-EXPORT_SYMBOL(arp_broken_ops);
-EXPORT_SYMBOL(arp_find);
-EXPORT_SYMBOL(arp_create);
-EXPORT_SYMBOL(arp_xmit);
-EXPORT_SYMBOL(arp_send);
-EXPORT_SYMBOL(arp_tbl);
-
-#if defined(CONFIG_ATM_CLIP) || defined(CONFIG_ATM_CLIP_MODULE)
-EXPORT_SYMBOL(clip_tbl_hook);
-#endif
diff --git a/net/ipv4/datagram.c b/net/ipv4/datagram.c
index fb2465811b4..f0550941df7 100644
--- a/net/ipv4/datagram.c
+++ b/net/ipv4/datagram.c
@@ -69,9 +69,7 @@ int ip4_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
sk->sk_state = TCP_ESTABLISHED;
inet->inet_id = jiffies;
- sk_dst_set(sk, &rt->u.dst);
+ sk_dst_set(sk, &rt->dst);
return(0);
}
-
EXPORT_SYMBOL(ip4_datagram_connect);
-
diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c
index 382bc768ed5..da14c49284f 100644
--- a/net/ipv4/devinet.c
+++ b/net/ipv4/devinet.c
@@ -1081,6 +1081,7 @@ static int inetdev_event(struct notifier_block *this, unsigned long event,
}
ip_mc_up(in_dev);
/* fall through */
+ case NETDEV_NOTIFY_PEERS:
case NETDEV_CHANGEADDR:
/* Send gratuitous ARP to notify of link change */
if (IN_DEV_ARP_NOTIFY(in_dev)) {
diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c
index 4f0ed458c88..a4396891835 100644
--- a/net/ipv4/fib_frontend.c
+++ b/net/ipv4/fib_frontend.c
@@ -175,6 +175,7 @@ out:
fib_res_put(&res);
return dev;
}
+EXPORT_SYMBOL(ip_dev_find);
/*
* Find address type as if only "dev" was present in the system. If
@@ -214,12 +215,14 @@ unsigned int inet_addr_type(struct net *net, __be32 addr)
{
return __inet_dev_addr_type(net, NULL, addr);
}
+EXPORT_SYMBOL(inet_addr_type);
unsigned int inet_dev_addr_type(struct net *net, const struct net_device *dev,
__be32 addr)
{
return __inet_dev_addr_type(net, dev, addr);
}
+EXPORT_SYMBOL(inet_dev_addr_type);
/* Given (packet source, input interface) and optional (dst, oif, tos):
- (main) check, that source is valid i.e. not broadcast or our local
@@ -284,7 +287,7 @@ int fib_validate_source(__be32 src, __be32 dst, u8 tos, int oif,
if (no_addr)
goto last_resort;
if (rpf == 1)
- goto e_inval;
+ goto e_rpf;
fl.oif = dev->ifindex;
ret = 0;
@@ -299,7 +302,7 @@ int fib_validate_source(__be32 src, __be32 dst, u8 tos, int oif,
last_resort:
if (rpf)
- goto e_inval;
+ goto e_rpf;
*spec_dst = inet_select_addr(dev, 0, RT_SCOPE_UNIVERSE);
*itag = 0;
return 0;
@@ -308,6 +311,8 @@ e_inval_res:
fib_res_put(&res);
e_inval:
return -EINVAL;
+e_rpf:
+ return -EXDEV;
}
static inline __be32 sk_extract_addr(struct sockaddr *addr)
@@ -1075,7 +1080,3 @@ void __init ip_fib_init(void)
fib_hash_init();
}
-
-EXPORT_SYMBOL(inet_addr_type);
-EXPORT_SYMBOL(inet_dev_addr_type);
-EXPORT_SYMBOL(ip_dev_find);
diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c
index d65e9215bcd..a0d847c7cba 100644
--- a/net/ipv4/icmp.c
+++ b/net/ipv4/icmp.c
@@ -181,6 +181,7 @@ const struct icmp_err icmp_err_convert[] = {
.fatal = 1,
},
};
+EXPORT_SYMBOL(icmp_err_convert);
/*
* ICMP control array. This specifies what to do with each ICMP.
@@ -267,11 +268,12 @@ int xrlim_allow(struct dst_entry *dst, int timeout)
dst->rate_tokens = token;
return rc;
}
+EXPORT_SYMBOL(xrlim_allow);
static inline int icmpv4_xrlim_allow(struct net *net, struct rtable *rt,
int type, int code)
{
- struct dst_entry *dst = &rt->u.dst;
+ struct dst_entry *dst = &rt->dst;
int rc = 1;
if (type > NR_ICMP_TYPES)
@@ -327,7 +329,7 @@ static void icmp_push_reply(struct icmp_bxm *icmp_param,
struct sock *sk;
struct sk_buff *skb;
- sk = icmp_sk(dev_net((*rt)->u.dst.dev));
+ sk = icmp_sk(dev_net((*rt)->dst.dev));
if (ip_append_data(sk, icmp_glue_bits, icmp_param,
icmp_param->data_len+icmp_param->head_len,
icmp_param->head_len,
@@ -359,7 +361,7 @@ static void icmp_reply(struct icmp_bxm *icmp_param, struct sk_buff *skb)
{
struct ipcm_cookie ipc;
struct rtable *rt = skb_rtable(skb);
- struct net *net = dev_net(rt->u.dst.dev);
+ struct net *net = dev_net(rt->dst.dev);
struct sock *sk;
struct inet_sock *inet;
__be32 daddr;
@@ -427,7 +429,7 @@ void icmp_send(struct sk_buff *skb_in, int type, int code, __be32 info)
if (!rt)
goto out;
- net = dev_net(rt->u.dst.dev);
+ net = dev_net(rt->dst.dev);
/*
* Find the original header. It is expected to be valid, of course.
@@ -596,9 +598,9 @@ void icmp_send(struct sk_buff *skb_in, int type, int code, __be32 info)
/* Ugh! */
orefdst = skb_in->_skb_refdst; /* save old refdst */
err = ip_route_input(skb_in, fl.fl4_dst, fl.fl4_src,
- RT_TOS(tos), rt2->u.dst.dev);
+ RT_TOS(tos), rt2->dst.dev);
- dst_release(&rt2->u.dst);
+ dst_release(&rt2->dst);
rt2 = skb_rtable(skb_in);
skb_in->_skb_refdst = orefdst; /* restore old refdst */
}
@@ -610,7 +612,7 @@ void icmp_send(struct sk_buff *skb_in, int type, int code, __be32 info)
XFRM_LOOKUP_ICMP);
switch (err) {
case 0:
- dst_release(&rt->u.dst);
+ dst_release(&rt->dst);
rt = rt2;
break;
case -EPERM:
@@ -629,7 +631,7 @@ route_done:
/* RFC says return as much as we can without exceeding 576 bytes. */
- room = dst_mtu(&rt->u.dst);
+ room = dst_mtu(&rt->dst);
if (room > 576)
room = 576;
room -= sizeof(struct iphdr) + icmp_param.replyopts.optlen;
@@ -647,6 +649,7 @@ out_unlock:
icmp_xmit_unlock(sk);
out:;
}
+EXPORT_SYMBOL(icmp_send);
/*
@@ -925,6 +928,7 @@ static void icmp_address(struct sk_buff *skb)
/*
* RFC1812 (4.3.3.9). A router SHOULD listen all replies, and complain
* loudly if an inconsistency is found.
+ * called with rcu_read_lock()
*/
static void icmp_address_reply(struct sk_buff *skb)
@@ -935,12 +939,12 @@ static void icmp_address_reply(struct sk_buff *skb)
struct in_ifaddr *ifa;
if (skb->len < 4 || !(rt->rt_flags&RTCF_DIRECTSRC))
- goto out;
+ return;
- in_dev = in_dev_get(dev);
+ in_dev = __in_dev_get_rcu(dev);
if (!in_dev)
- goto out;
- rcu_read_lock();
+ return;
+
if (in_dev->ifa_list &&
IN_DEV_LOG_MARTIANS(in_dev) &&
IN_DEV_FORWARD(in_dev)) {
@@ -958,9 +962,6 @@ static void icmp_address_reply(struct sk_buff *skb)
mp, dev->name, &rt->rt_src);
}
}
- rcu_read_unlock();
- in_dev_put(in_dev);
-out:;
}
static void icmp_discard(struct sk_buff *skb)
@@ -974,7 +975,7 @@ int icmp_rcv(struct sk_buff *skb)
{
struct icmphdr *icmph;
struct rtable *rt = skb_rtable(skb);
- struct net *net = dev_net(rt->u.dst.dev);
+ struct net *net = dev_net(rt->dst.dev);
if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb)) {
struct sec_path *sp = skb_sec_path(skb);
@@ -1216,7 +1217,3 @@ int __init icmp_init(void)
{
return register_pernet_subsys(&icmp_sk_ops);
}
-
-EXPORT_SYMBOL(icmp_err_convert);
-EXPORT_SYMBOL(icmp_send);
-EXPORT_SYMBOL(xrlim_allow);
diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c
index 5fff865a4fa..a1ad0e7180d 100644
--- a/net/ipv4/igmp.c
+++ b/net/ipv4/igmp.c
@@ -312,7 +312,7 @@ static struct sk_buff *igmpv3_newpack(struct net_device *dev, int size)
return NULL;
}
- skb_dst_set(skb, &rt->u.dst);
+ skb_dst_set(skb, &rt->dst);
skb->dev = dev;
skb_reserve(skb, LL_RESERVED_SPACE(dev));
@@ -330,7 +330,7 @@ static struct sk_buff *igmpv3_newpack(struct net_device *dev, int size)
pip->saddr = rt->rt_src;
pip->protocol = IPPROTO_IGMP;
pip->tot_len = 0; /* filled in later */
- ip_select_ident(pip, &rt->u.dst, NULL);
+ ip_select_ident(pip, &rt->dst, NULL);
((u8*)&pip[1])[0] = IPOPT_RA;
((u8*)&pip[1])[1] = 4;
((u8*)&pip[1])[2] = 0;
@@ -660,7 +660,7 @@ static int igmp_send_report(struct in_device *in_dev, struct ip_mc_list *pmc,
return -1;
}
- skb_dst_set(skb, &rt->u.dst);
+ skb_dst_set(skb, &rt->dst);
skb_reserve(skb, LL_RESERVED_SPACE(dev));
@@ -676,7 +676,7 @@ static int igmp_send_report(struct in_device *in_dev, struct ip_mc_list *pmc,
iph->daddr = dst;
iph->saddr = rt->rt_src;
iph->protocol = IPPROTO_IGMP;
- ip_select_ident(iph, &rt->u.dst, NULL);
+ ip_select_ident(iph, &rt->dst, NULL);
((u8*)&iph[1])[0] = IPOPT_RA;
((u8*)&iph[1])[1] = 4;
((u8*)&iph[1])[2] = 0;
@@ -916,18 +916,19 @@ static void igmp_heard_query(struct in_device *in_dev, struct sk_buff *skb,
read_unlock(&in_dev->mc_list_lock);
}
+/* called in rcu_read_lock() section */
int igmp_rcv(struct sk_buff *skb)
{
/* This basically follows the spec line by line -- see RFC1112 */
struct igmphdr *ih;
- struct in_device *in_dev = in_dev_get(skb->dev);
+ struct in_device *in_dev = __in_dev_get_rcu(skb->dev);
int len = skb->len;
if (in_dev == NULL)
goto drop;
if (!pskb_may_pull(skb, sizeof(struct igmphdr)))
- goto drop_ref;
+ goto drop;
switch (skb->ip_summed) {
case CHECKSUM_COMPLETE:
@@ -937,7 +938,7 @@ int igmp_rcv(struct sk_buff *skb)
case CHECKSUM_NONE:
skb->csum = 0;
if (__skb_checksum_complete(skb))
- goto drop_ref;
+ goto drop;
}
ih = igmp_hdr(skb);
@@ -957,7 +958,6 @@ int igmp_rcv(struct sk_buff *skb)
break;
case IGMP_PIM:
#ifdef CONFIG_IP_PIMSM_V1
- in_dev_put(in_dev);
return pim_rcv_v1(skb);
#endif
case IGMPV3_HOST_MEMBERSHIP_REPORT:
@@ -971,8 +971,6 @@ int igmp_rcv(struct sk_buff *skb)
break;
}
-drop_ref:
- in_dev_put(in_dev);
drop:
kfree_skb(skb);
return 0;
@@ -1246,6 +1244,7 @@ void ip_mc_inc_group(struct in_device *in_dev, __be32 addr)
out:
return;
}
+EXPORT_SYMBOL(ip_mc_inc_group);
/*
* Resend IGMP JOIN report; used for bonding.
@@ -1268,6 +1267,7 @@ void ip_mc_rejoin_group(struct ip_mc_list *im)
igmp_ifc_event(in_dev);
#endif
}
+EXPORT_SYMBOL(ip_mc_rejoin_group);
/*
* A socket has left a multicast group on device dev
@@ -1298,6 +1298,7 @@ void ip_mc_dec_group(struct in_device *in_dev, __be32 addr)
}
}
}
+EXPORT_SYMBOL(ip_mc_dec_group);
/* Device changing type */
@@ -1427,7 +1428,7 @@ static struct in_device *ip_mc_find_dev(struct net *net, struct ip_mreqn *imr)
}
if (!dev && !ip_route_output_key(net, &rt, &fl)) {
- dev = rt->u.dst.dev;
+ dev = rt->dst.dev;
ip_rt_put(rt);
}
if (dev) {
@@ -1646,8 +1647,7 @@ static int sf_setstate(struct ip_mc_list *pmc)
if (dpsf->sf_inaddr == psf->sf_inaddr)
break;
if (!dpsf) {
- dpsf = (struct ip_sf_list *)
- kmalloc(sizeof(*dpsf), GFP_ATOMIC);
+ dpsf = kmalloc(sizeof(*dpsf), GFP_ATOMIC);
if (!dpsf)
continue;
*dpsf = *psf;
@@ -1807,6 +1807,7 @@ done:
rtnl_unlock();
return err;
}
+EXPORT_SYMBOL(ip_mc_join_group);
static void ip_sf_socklist_reclaim(struct rcu_head *rp)
{
@@ -2679,8 +2680,3 @@ int __init igmp_mc_proc_init(void)
return register_pernet_subsys(&igmp_net_ops);
}
#endif
-
-EXPORT_SYMBOL(ip_mc_dec_group);
-EXPORT_SYMBOL(ip_mc_inc_group);
-EXPORT_SYMBOL(ip_mc_join_group);
-EXPORT_SYMBOL(ip_mc_rejoin_group);
diff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c
index 70eb3507c40..7174370b119 100644
--- a/net/ipv4/inet_connection_sock.c
+++ b/net/ipv4/inet_connection_sock.c
@@ -84,7 +84,6 @@ int inet_csk_bind_conflict(const struct sock *sk,
}
return node != NULL;
}
-
EXPORT_SYMBOL_GPL(inet_csk_bind_conflict);
/* Obtain a reference to a local port for the given sock,
@@ -212,7 +211,6 @@ fail:
local_bh_enable();
return ret;
}
-
EXPORT_SYMBOL_GPL(inet_csk_get_port);
/*
@@ -305,7 +303,6 @@ out_err:
*err = error;
goto out;
}
-
EXPORT_SYMBOL(inet_csk_accept);
/*
@@ -327,7 +324,6 @@ void inet_csk_init_xmit_timers(struct sock *sk,
setup_timer(&sk->sk_timer, keepalive_handler, (unsigned long)sk);
icsk->icsk_pending = icsk->icsk_ack.pending = 0;
}
-
EXPORT_SYMBOL(inet_csk_init_xmit_timers);
void inet_csk_clear_xmit_timers(struct sock *sk)
@@ -340,21 +336,18 @@ void inet_csk_clear_xmit_timers(struct sock *sk)
sk_stop_timer(sk, &icsk->icsk_delack_timer);
sk_stop_timer(sk, &sk->sk_timer);
}
-
EXPORT_SYMBOL(inet_csk_clear_xmit_timers);
void inet_csk_delete_keepalive_timer(struct sock *sk)
{
sk_stop_timer(sk, &sk->sk_timer);
}
-
EXPORT_SYMBOL(inet_csk_delete_keepalive_timer);
void inet_csk_reset_keepalive_timer(struct sock *sk, unsigned long len)
{
sk_reset_timer(sk, &sk->sk_timer, jiffies + len);
}
-
EXPORT_SYMBOL(inet_csk_reset_keepalive_timer);
struct dst_entry *inet_csk_route_req(struct sock *sk,
@@ -383,7 +376,7 @@ struct dst_entry *inet_csk_route_req(struct sock *sk,
goto no_route;
if (opt && opt->is_strictroute && rt->rt_dst != rt->rt_gateway)
goto route_err;
- return &rt->u.dst;
+ return &rt->dst;
route_err:
ip_rt_put(rt);
@@ -391,7 +384,6 @@ no_route:
IP_INC_STATS_BH(net, IPSTATS_MIB_OUTNOROUTES);
return NULL;
}
-
EXPORT_SYMBOL_GPL(inet_csk_route_req);
static inline u32 inet_synq_hash(const __be32 raddr, const __be16 rport,
@@ -433,7 +425,6 @@ struct request_sock *inet_csk_search_req(const struct sock *sk,
return req;
}
-
EXPORT_SYMBOL_GPL(inet_csk_search_req);
void inet_csk_reqsk_queue_hash_add(struct sock *sk, struct request_sock *req,
@@ -447,11 +438,11 @@ void inet_csk_reqsk_queue_hash_add(struct sock *sk, struct request_sock *req,
reqsk_queue_hash_req(&icsk->icsk_accept_queue, h, req, timeout);
inet_csk_reqsk_queue_added(sk, timeout);
}
+EXPORT_SYMBOL_GPL(inet_csk_reqsk_queue_hash_add);
/* Only thing we need from tcp.h */
extern int sysctl_tcp_synack_retries;
-EXPORT_SYMBOL_GPL(inet_csk_reqsk_queue_hash_add);
/* Decide when to expire the request and when to resend SYN-ACK */
static inline void syn_ack_recalc(struct request_sock *req, const int thresh,
@@ -569,7 +560,6 @@ void inet_csk_reqsk_queue_prune(struct sock *parent,
if (lopt->qlen)
inet_csk_reset_keepalive_timer(parent, interval);
}
-
EXPORT_SYMBOL_GPL(inet_csk_reqsk_queue_prune);
struct sock *inet_csk_clone(struct sock *sk, const struct request_sock *req,
@@ -599,7 +589,6 @@ struct sock *inet_csk_clone(struct sock *sk, const struct request_sock *req,
}
return newsk;
}
-
EXPORT_SYMBOL_GPL(inet_csk_clone);
/*
@@ -630,7 +619,6 @@ void inet_csk_destroy_sock(struct sock *sk)
percpu_counter_dec(sk->sk_prot->orphan_count);
sock_put(sk);
}
-
EXPORT_SYMBOL(inet_csk_destroy_sock);
int inet_csk_listen_start(struct sock *sk, const int nr_table_entries)
@@ -665,7 +653,6 @@ int inet_csk_listen_start(struct sock *sk, const int nr_table_entries)
__reqsk_queue_destroy(&icsk->icsk_accept_queue);
return -EADDRINUSE;
}
-
EXPORT_SYMBOL_GPL(inet_csk_listen_start);
/*
@@ -720,7 +707,6 @@ void inet_csk_listen_stop(struct sock *sk)
}
WARN_ON(sk->sk_ack_backlog);
}
-
EXPORT_SYMBOL_GPL(inet_csk_listen_stop);
void inet_csk_addr2sockaddr(struct sock *sk, struct sockaddr *uaddr)
@@ -732,7 +718,6 @@ void inet_csk_addr2sockaddr(struct sock *sk, struct sockaddr *uaddr)
sin->sin_addr.s_addr = inet->inet_daddr;
sin->sin_port = inet->inet_dport;
}
-
EXPORT_SYMBOL_GPL(inet_csk_addr2sockaddr);
#ifdef CONFIG_COMPAT
@@ -747,7 +732,6 @@ int inet_csk_compat_getsockopt(struct sock *sk, int level, int optname,
return icsk->icsk_af_ops->getsockopt(sk, level, optname,
optval, optlen);
}
-
EXPORT_SYMBOL_GPL(inet_csk_compat_getsockopt);
int inet_csk_compat_setsockopt(struct sock *sk, int level, int optname,
@@ -761,6 +745,5 @@ int inet_csk_compat_setsockopt(struct sock *sk, int level, int optname,
return icsk->icsk_af_ops->setsockopt(sk, level, optname,
optval, optlen);
}
-
EXPORT_SYMBOL_GPL(inet_csk_compat_setsockopt);
#endif
diff --git a/net/ipv4/inet_fragment.c b/net/ipv4/inet_fragment.c
index a2ca6aed763..5ff2a51b6d0 100644
--- a/net/ipv4/inet_fragment.c
+++ b/net/ipv4/inet_fragment.c
@@ -114,7 +114,6 @@ void inet_frag_kill(struct inet_frag_queue *fq, struct inet_frags *f)
fq->last_in |= INET_FRAG_COMPLETE;
}
}
-
EXPORT_SYMBOL(inet_frag_kill);
static inline void frag_kfree_skb(struct netns_frags *nf, struct inet_frags *f,
diff --git a/net/ipv4/inet_hashtables.c b/net/ipv4/inet_hashtables.c
index d3e160a8821..fb7ad5a21ff 100644
--- a/net/ipv4/inet_hashtables.c
+++ b/net/ipv4/inet_hashtables.c
@@ -99,7 +99,6 @@ void inet_put_port(struct sock *sk)
__inet_put_port(sk);
local_bh_enable();
}
-
EXPORT_SYMBOL(inet_put_port);
void __inet_inherit_port(struct sock *sk, struct sock *child)
@@ -116,7 +115,6 @@ void __inet_inherit_port(struct sock *sk, struct sock *child)
inet_csk(child)->icsk_bind_hash = tb;
spin_unlock(&head->lock);
}
-
EXPORT_SYMBOL_GPL(__inet_inherit_port);
static inline int compute_score(struct sock *sk, struct net *net,
@@ -546,7 +544,6 @@ int inet_hash_connect(struct inet_timewait_death_row *death_row,
return __inet_hash_connect(death_row, sk, inet_sk_port_offset(sk),
__inet_check_established, __inet_hash_nolisten);
}
-
EXPORT_SYMBOL_GPL(inet_hash_connect);
void inet_hashinfo_init(struct inet_hashinfo *h)
@@ -560,5 +557,4 @@ void inet_hashinfo_init(struct inet_hashinfo *h)
i + LISTENING_NULLS_BASE);
}
}
-
EXPORT_SYMBOL_GPL(inet_hashinfo_init);
diff --git a/net/ipv4/inetpeer.c b/net/ipv4/inetpeer.c
index 6bcfe52a9c8..9ffa24b9a80 100644
--- a/net/ipv4/inetpeer.c
+++ b/net/ipv4/inetpeer.c
@@ -51,8 +51,8 @@
* lookups performed with disabled BHs.
*
* Serialisation issues.
- * 1. Nodes may appear in the tree only with the pool write lock held.
- * 2. Nodes may disappear from the tree only with the pool write lock held
+ * 1. Nodes may appear in the tree only with the pool lock held.
+ * 2. Nodes may disappear from the tree only with the pool lock held
* AND reference count being 0.
* 3. Nodes appears and disappears from unused node list only under
* "inet_peer_unused_lock".
@@ -64,23 +64,31 @@
* usually under some other lock to prevent node disappearing
* dtime: unused node list lock
* v4daddr: unchangeable
- * ip_id_count: idlock
+ * ip_id_count: atomic value (no lock needed)
*/
static struct kmem_cache *peer_cachep __read_mostly;
#define node_height(x) x->avl_height
-static struct inet_peer peer_fake_node = {
- .avl_left = &peer_fake_node,
- .avl_right = &peer_fake_node,
+
+#define peer_avl_empty ((struct inet_peer *)&peer_fake_node)
+static const struct inet_peer peer_fake_node = {
+ .avl_left = peer_avl_empty,
+ .avl_right = peer_avl_empty,
.avl_height = 0
};
-#define peer_avl_empty (&peer_fake_node)
-static struct inet_peer *peer_root = peer_avl_empty;
-static DEFINE_RWLOCK(peer_pool_lock);
+
+static struct {
+ struct inet_peer *root;
+ spinlock_t lock;
+ int total;
+} peers = {
+ .root = peer_avl_empty,
+ .lock = __SPIN_LOCK_UNLOCKED(peers.lock),
+ .total = 0,
+};
#define PEER_MAXDEPTH 40 /* sufficient for about 2^27 nodes */
-static int peer_total;
/* Exported for sysctl_net_ipv4. */
int inet_peer_threshold __read_mostly = 65536 + 128; /* start to throw entries more
* aggressively at this stage */
@@ -89,8 +97,13 @@ int inet_peer_maxttl __read_mostly = 10 * 60 * HZ; /* usual time to live: 10 min
int inet_peer_gc_mintime __read_mostly = 10 * HZ;
int inet_peer_gc_maxtime __read_mostly = 120 * HZ;
-static LIST_HEAD(unused_peers);
-static DEFINE_SPINLOCK(inet_peer_unused_lock);
+static struct {
+ struct list_head list;
+ spinlock_t lock;
+} unused_peers = {
+ .list = LIST_HEAD_INIT(unused_peers.list),
+ .lock = __SPIN_LOCK_UNLOCKED(unused_peers.lock),
+};
static void peer_check_expire(unsigned long dummy);
static DEFINE_TIMER(peer_periodic_timer, peer_check_expire, 0, 0);
@@ -116,7 +129,7 @@ void __init inet_initpeers(void)
peer_cachep = kmem_cache_create("inet_peer_cache",
sizeof(struct inet_peer),
- 0, SLAB_HWCACHE_ALIGN|SLAB_PANIC,
+ 0, SLAB_HWCACHE_ALIGN | SLAB_PANIC,
NULL);
/* All the timers, started at system startup tend
@@ -131,38 +144,69 @@ void __init inet_initpeers(void)
/* Called with or without local BH being disabled. */
static void unlink_from_unused(struct inet_peer *p)
{
- spin_lock_bh(&inet_peer_unused_lock);
- list_del_init(&p->unused);
- spin_unlock_bh(&inet_peer_unused_lock);
+ if (!list_empty(&p->unused)) {
+ spin_lock_bh(&unused_peers.lock);
+ list_del_init(&p->unused);
+ spin_unlock_bh(&unused_peers.lock);
+ }
}
/*
* Called with local BH disabled and the pool lock held.
- * _stack is known to be NULL or not at compile time,
- * so compiler will optimize the if (_stack) tests.
*/
#define lookup(_daddr, _stack) \
({ \
struct inet_peer *u, **v; \
- if (_stack != NULL) { \
- stackptr = _stack; \
- *stackptr++ = &peer_root; \
- } \
- for (u = peer_root; u != peer_avl_empty; ) { \
+ \
+ stackptr = _stack; \
+ *stackptr++ = &peers.root; \
+ for (u = peers.root; u != peer_avl_empty; ) { \
if (_daddr == u->v4daddr) \
break; \
if ((__force __u32)_daddr < (__force __u32)u->v4daddr) \
v = &u->avl_left; \
else \
v = &u->avl_right; \
- if (_stack != NULL) \
- *stackptr++ = v; \
+ *stackptr++ = v; \
u = *v; \
} \
u; \
})
-/* Called with local BH disabled and the pool write lock held. */
+/*
+ * Called with rcu_read_lock_bh()
+ * Because we hold no lock against a writer, its quite possible we fall
+ * in an endless loop.
+ * But every pointer we follow is guaranteed to be valid thanks to RCU.
+ * We exit from this function if number of links exceeds PEER_MAXDEPTH
+ */
+static struct inet_peer *lookup_rcu_bh(__be32 daddr)
+{
+ struct inet_peer *u = rcu_dereference_bh(peers.root);
+ int count = 0;
+
+ while (u != peer_avl_empty) {
+ if (daddr == u->v4daddr) {
+ /* Before taking a reference, check if this entry was
+ * deleted, unlink_from_pool() sets refcnt=-1 to make
+ * distinction between an unused entry (refcnt=0) and
+ * a freed one.
+ */
+ if (unlikely(!atomic_add_unless(&u->refcnt, 1, -1)))
+ u = NULL;
+ return u;
+ }
+ if ((__force __u32)daddr < (__force __u32)u->v4daddr)
+ u = rcu_dereference_bh(u->avl_left);
+ else
+ u = rcu_dereference_bh(u->avl_right);
+ if (unlikely(++count == PEER_MAXDEPTH))
+ break;
+ }
+ return NULL;
+}
+
+/* Called with local BH disabled and the pool lock held. */
#define lookup_rightempty(start) \
({ \
struct inet_peer *u, **v; \
@@ -176,9 +220,10 @@ static void unlink_from_unused(struct inet_peer *p)
u; \
})
-/* Called with local BH disabled and the pool write lock held.
+/* Called with local BH disabled and the pool lock held.
* Variable names are the proof of operation correctness.
- * Look into mm/map_avl.c for more detail description of the ideas. */
+ * Look into mm/map_avl.c for more detail description of the ideas.
+ */
static void peer_avl_rebalance(struct inet_peer **stack[],
struct inet_peer ***stackend)
{
@@ -254,15 +299,21 @@ static void peer_avl_rebalance(struct inet_peer **stack[],
}
}
-/* Called with local BH disabled and the pool write lock held. */
+/* Called with local BH disabled and the pool lock held. */
#define link_to_pool(n) \
do { \
n->avl_height = 1; \
n->avl_left = peer_avl_empty; \
n->avl_right = peer_avl_empty; \
+ smp_wmb(); /* lockless readers can catch us now */ \
**--stackptr = n; \
peer_avl_rebalance(stack, stackptr); \
-} while(0)
+} while (0)
+
+static void inetpeer_free_rcu(struct rcu_head *head)
+{
+ kmem_cache_free(peer_cachep, container_of(head, struct inet_peer, rcu));
+}
/* May be called with local BH enabled. */
static void unlink_from_pool(struct inet_peer *p)
@@ -271,13 +322,14 @@ static void unlink_from_pool(struct inet_peer *p)
do_free = 0;
- write_lock_bh(&peer_pool_lock);
+ spin_lock_bh(&peers.lock);
/* Check the reference counter. It was artificially incremented by 1
- * in cleanup() function to prevent sudden disappearing. If the
- * reference count is still 1 then the node is referenced only as `p'
- * here and from the pool. So under the exclusive pool lock it's safe
- * to remove the node and free it later. */
- if (atomic_read(&p->refcnt) == 1) {
+ * in cleanup() function to prevent sudden disappearing. If we can
+ * atomically (because of lockless readers) take this last reference,
+ * it's safe to remove the node and free it later.
+ * We use refcnt=-1 to alert lockless readers this entry is deleted.
+ */
+ if (atomic_cmpxchg(&p->refcnt, 1, -1) == 1) {
struct inet_peer **stack[PEER_MAXDEPTH];
struct inet_peer ***stackptr, ***delp;
if (lookup(p->v4daddr, stack) != p)
@@ -303,20 +355,21 @@ static void unlink_from_pool(struct inet_peer *p)
delp[1] = &t->avl_left; /* was &p->avl_left */
}
peer_avl_rebalance(stack, stackptr);
- peer_total--;
+ peers.total--;
do_free = 1;
}
- write_unlock_bh(&peer_pool_lock);
+ spin_unlock_bh(&peers.lock);
if (do_free)
- kmem_cache_free(peer_cachep, p);
+ call_rcu_bh(&p->rcu, inetpeer_free_rcu);
else
/* The node is used again. Decrease the reference counter
* back. The loop "cleanup -> unlink_from_unused
* -> unlink_from_pool -> putpeer -> link_to_unused
* -> cleanup (for the same node)"
* doesn't really exist because the entry will have a
- * recent deletion time and will not be cleaned again soon. */
+ * recent deletion time and will not be cleaned again soon.
+ */
inet_putpeer(p);
}
@@ -326,16 +379,16 @@ static int cleanup_once(unsigned long ttl)
struct inet_peer *p = NULL;
/* Remove the first entry from the list of unused nodes. */
- spin_lock_bh(&inet_peer_unused_lock);
- if (!list_empty(&unused_peers)) {
+ spin_lock_bh(&unused_peers.lock);
+ if (!list_empty(&unused_peers.list)) {
__u32 delta;
- p = list_first_entry(&unused_peers, struct inet_peer, unused);
+ p = list_first_entry(&unused_peers.list, struct inet_peer, unused);
delta = (__u32)jiffies - p->dtime;
if (delta < ttl) {
/* Do not prune fresh entries. */
- spin_unlock_bh(&inet_peer_unused_lock);
+ spin_unlock_bh(&unused_peers.lock);
return -1;
}
@@ -345,7 +398,7 @@ static int cleanup_once(unsigned long ttl)
* before unlink_from_pool() call. */
atomic_inc(&p->refcnt);
}
- spin_unlock_bh(&inet_peer_unused_lock);
+ spin_unlock_bh(&unused_peers.lock);
if (p == NULL)
/* It means that the total number of USED entries has
@@ -360,62 +413,56 @@ static int cleanup_once(unsigned long ttl)
/* Called with or without local BH being disabled. */
struct inet_peer *inet_getpeer(__be32 daddr, int create)
{
- struct inet_peer *p, *n;
+ struct inet_peer *p;
struct inet_peer **stack[PEER_MAXDEPTH], ***stackptr;
- /* Look up for the address quickly. */
- read_lock_bh(&peer_pool_lock);
- p = lookup(daddr, NULL);
- if (p != peer_avl_empty)
- atomic_inc(&p->refcnt);
- read_unlock_bh(&peer_pool_lock);
+ /* Look up for the address quickly, lockless.
+ * Because of a concurrent writer, we might not find an existing entry.
+ */
+ rcu_read_lock_bh();
+ p = lookup_rcu_bh(daddr);
+ rcu_read_unlock_bh();
+
+ if (p) {
+ /* The existing node has been found.
+ * Remove the entry from unused list if it was there.
+ */
+ unlink_from_unused(p);
+ return p;
+ }
+ /* retry an exact lookup, taking the lock before.
+ * At least, nodes should be hot in our cache.
+ */
+ spin_lock_bh(&peers.lock);
+ p = lookup(daddr, stack);
if (p != peer_avl_empty) {
- /* The existing node has been found. */
+ atomic_inc(&p->refcnt);
+ spin_unlock_bh(&peers.lock);
/* Remove the entry from unused list if it was there. */
unlink_from_unused(p);
return p;
}
+ p = create ? kmem_cache_alloc(peer_cachep, GFP_ATOMIC) : NULL;
+ if (p) {
+ p->v4daddr = daddr;
+ atomic_set(&p->refcnt, 1);
+ atomic_set(&p->rid, 0);
+ atomic_set(&p->ip_id_count, secure_ip_id(daddr));
+ p->tcp_ts_stamp = 0;
+ INIT_LIST_HEAD(&p->unused);
+
+
+ /* Link the node. */
+ link_to_pool(p);
+ peers.total++;
+ }
+ spin_unlock_bh(&peers.lock);
- if (!create)
- return NULL;
-
- /* Allocate the space outside the locked region. */
- n = kmem_cache_alloc(peer_cachep, GFP_ATOMIC);
- if (n == NULL)
- return NULL;
- n->v4daddr = daddr;
- atomic_set(&n->refcnt, 1);
- atomic_set(&n->rid, 0);
- atomic_set(&n->ip_id_count, secure_ip_id(daddr));
- n->tcp_ts_stamp = 0;
-
- write_lock_bh(&peer_pool_lock);
- /* Check if an entry has suddenly appeared. */
- p = lookup(daddr, stack);
- if (p != peer_avl_empty)
- goto out_free;
-
- /* Link the node. */
- link_to_pool(n);
- INIT_LIST_HEAD(&n->unused);
- peer_total++;
- write_unlock_bh(&peer_pool_lock);
-
- if (peer_total >= inet_peer_threshold)
+ if (peers.total >= inet_peer_threshold)
/* Remove one less-recently-used entry. */
cleanup_once(0);
- return n;
-
-out_free:
- /* The appropriate node is already in the pool. */
- atomic_inc(&p->refcnt);
- write_unlock_bh(&peer_pool_lock);
- /* Remove the entry from unused list if it was there. */
- unlink_from_unused(p);
- /* Free preallocated the preallocated node. */
- kmem_cache_free(peer_cachep, n);
return p;
}
@@ -425,12 +472,12 @@ static void peer_check_expire(unsigned long dummy)
unsigned long now = jiffies;
int ttl;
- if (peer_total >= inet_peer_threshold)
+ if (peers.total >= inet_peer_threshold)
ttl = inet_peer_minttl;
else
ttl = inet_peer_maxttl
- (inet_peer_maxttl - inet_peer_minttl) / HZ *
- peer_total / inet_peer_threshold * HZ;
+ peers.total / inet_peer_threshold * HZ;
while (!cleanup_once(ttl)) {
if (jiffies != now)
break;
@@ -439,22 +486,25 @@ static void peer_check_expire(unsigned long dummy)
/* Trigger the timer after inet_peer_gc_mintime .. inet_peer_gc_maxtime
* interval depending on the total number of entries (more entries,
* less interval). */
- if (peer_total >= inet_peer_threshold)
+ if (peers.total >= inet_peer_threshold)
peer_periodic_timer.expires = jiffies + inet_peer_gc_mintime;
else
peer_periodic_timer.expires = jiffies
+ inet_peer_gc_maxtime
- (inet_peer_gc_maxtime - inet_peer_gc_mintime) / HZ *
- peer_total / inet_peer_threshold * HZ;
+ peers.total / inet_peer_threshold * HZ;
add_timer(&peer_periodic_timer);
}
void inet_putpeer(struct inet_peer *p)
{
- spin_lock_bh(&inet_peer_unused_lock);
- if (atomic_dec_and_test(&p->refcnt)) {
- list_add_tail(&p->unused, &unused_peers);
+ local_bh_disable();
+
+ if (atomic_dec_and_lock(&p->refcnt, &unused_peers.lock)) {
+ list_add_tail(&p->unused, &unused_peers.list);
p->dtime = (__u32)jiffies;
+ spin_unlock(&unused_peers.lock);
}
- spin_unlock_bh(&inet_peer_unused_lock);
+
+ local_bh_enable();
}
diff --git a/net/ipv4/ip_forward.c b/net/ipv4/ip_forward.c
index 56cdf68a074..99461f09320 100644
--- a/net/ipv4/ip_forward.c
+++ b/net/ipv4/ip_forward.c
@@ -87,16 +87,16 @@ int ip_forward(struct sk_buff *skb)
if (opt->is_strictroute && rt->rt_dst != rt->rt_gateway)
goto sr_failed;
- if (unlikely(skb->len > dst_mtu(&rt->u.dst) && !skb_is_gso(skb) &&
+ if (unlikely(skb->len > dst_mtu(&rt->dst) && !skb_is_gso(skb) &&
(ip_hdr(skb)->frag_off & htons(IP_DF))) && !skb->local_df) {
- IP_INC_STATS(dev_net(rt->u.dst.dev), IPSTATS_MIB_FRAGFAILS);
+ IP_INC_STATS(dev_net(rt->dst.dev), IPSTATS_MIB_FRAGFAILS);
icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED,
- htonl(dst_mtu(&rt->u.dst)));
+ htonl(dst_mtu(&rt->dst)));
goto drop;
}
/* We are about to mangle packet. Copy it! */
- if (skb_cow(skb, LL_RESERVED_SPACE(rt->u.dst.dev)+rt->u.dst.header_len))
+ if (skb_cow(skb, LL_RESERVED_SPACE(rt->dst.dev)+rt->dst.header_len))
goto drop;
iph = ip_hdr(skb);
@@ -113,7 +113,7 @@ int ip_forward(struct sk_buff *skb)
skb->priority = rt_tos2priority(iph->tos);
return NF_HOOK(NFPROTO_IPV4, NF_INET_FORWARD, skb, skb->dev,
- rt->u.dst.dev, ip_forward_finish);
+ rt->dst.dev, ip_forward_finish);
sr_failed:
/*
diff --git a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c
index 75347ea70ea..b7c41654dde 100644
--- a/net/ipv4/ip_fragment.c
+++ b/net/ipv4/ip_fragment.c
@@ -124,11 +124,8 @@ static int ip4_frag_match(struct inet_frag_queue *q, void *a)
}
/* Memory Tracking Functions. */
-static __inline__ void frag_kfree_skb(struct netns_frags *nf,
- struct sk_buff *skb, int *work)
+static void frag_kfree_skb(struct netns_frags *nf, struct sk_buff *skb)
{
- if (work)
- *work -= skb->truesize;
atomic_sub(skb->truesize, &nf->mem);
kfree_skb(skb);
}
@@ -309,7 +306,7 @@ static int ip_frag_reinit(struct ipq *qp)
fp = qp->q.fragments;
do {
struct sk_buff *xp = fp->next;
- frag_kfree_skb(qp->q.net, fp, NULL);
+ frag_kfree_skb(qp->q.net, fp);
fp = xp;
} while (fp);
@@ -317,6 +314,7 @@ static int ip_frag_reinit(struct ipq *qp)
qp->q.len = 0;
qp->q.meat = 0;
qp->q.fragments = NULL;
+ qp->q.fragments_tail = NULL;
qp->iif = 0;
return 0;
@@ -389,6 +387,11 @@ static int ip_frag_queue(struct ipq *qp, struct sk_buff *skb)
* in the chain of fragments so far. We must know where to put
* this fragment, right?
*/
+ prev = qp->q.fragments_tail;
+ if (!prev || FRAG_CB(prev)->offset < offset) {
+ next = NULL;
+ goto found;
+ }
prev = NULL;
for (next = qp->q.fragments; next != NULL; next = next->next) {
if (FRAG_CB(next)->offset >= offset)
@@ -396,6 +399,7 @@ static int ip_frag_queue(struct ipq *qp, struct sk_buff *skb)
prev = next;
}
+found:
/* We found where to put this one. Check for overlap with
* preceding fragment, and, if needed, align things so that
* any overlaps are eliminated.
@@ -446,7 +450,7 @@ static int ip_frag_queue(struct ipq *qp, struct sk_buff *skb)
qp->q.fragments = next;
qp->q.meat -= free_it->len;
- frag_kfree_skb(qp->q.net, free_it, NULL);
+ frag_kfree_skb(qp->q.net, free_it);
}
}
@@ -454,6 +458,8 @@ static int ip_frag_queue(struct ipq *qp, struct sk_buff *skb)
/* Insert this fragment in the chain of fragments. */
skb->next = next;
+ if (!next)
+ qp->q.fragments_tail = skb;
if (prev)
prev->next = skb;
else
@@ -507,6 +513,8 @@ static int ip_frag_reasm(struct ipq *qp, struct sk_buff *prev,
goto out_nomem;
fp->next = head->next;
+ if (!fp->next)
+ qp->q.fragments_tail = fp;
prev->next = fp;
skb_morph(head, qp->q.fragments);
@@ -556,7 +564,6 @@ static int ip_frag_reasm(struct ipq *qp, struct sk_buff *prev,
skb_shinfo(head)->frag_list = head->next;
skb_push(head, head->data - skb_network_header(head));
- atomic_sub(head->truesize, &qp->q.net->mem);
for (fp=head->next; fp; fp = fp->next) {
head->data_len += fp->len;
@@ -566,8 +573,8 @@ static int ip_frag_reasm(struct ipq *qp, struct sk_buff *prev,
else if (head->ip_summed == CHECKSUM_COMPLETE)
head->csum = csum_add(head->csum, fp->csum);
head->truesize += fp->truesize;
- atomic_sub(fp->truesize, &qp->q.net->mem);
}
+ atomic_sub(head->truesize, &qp->q.net->mem);
head->next = NULL;
head->dev = dev;
@@ -578,6 +585,7 @@ static int ip_frag_reasm(struct ipq *qp, struct sk_buff *prev,
iph->tot_len = htons(len);
IP_INC_STATS_BH(net, IPSTATS_MIB_REASMOKS);
qp->q.fragments = NULL;
+ qp->q.fragments_tail = NULL;
return 0;
out_nomem:
@@ -624,6 +632,7 @@ int ip_defrag(struct sk_buff *skb, u32 user)
kfree_skb(skb);
return -ENOMEM;
}
+EXPORT_SYMBOL(ip_defrag);
#ifdef CONFIG_SYSCTL
static int zero;
@@ -777,5 +786,3 @@ void __init ipfrag_init(void)
ip4_frags.secret_interval = 10 * 60 * HZ;
inet_frags_init(&ip4_frags);
}
-
-EXPORT_SYMBOL(ip_defrag);
diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c
index 32618e11076..945b20a5ad5 100644
--- a/net/ipv4/ip_gre.c
+++ b/net/ipv4/ip_gre.c
@@ -731,6 +731,8 @@ static netdev_tx_t ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev
tos = 0;
if (skb->protocol == htons(ETH_P_IP))
tos = old_iph->tos;
+ else if (skb->protocol == htons(ETH_P_IPV6))
+ tos = ipv6_get_dsfield((struct ipv6hdr *)old_iph);
}
{
@@ -745,7 +747,7 @@ static netdev_tx_t ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev
goto tx_error;
}
}
- tdev = rt->u.dst.dev;
+ tdev = rt->dst.dev;
if (tdev == dev) {
ip_rt_put(rt);
@@ -755,7 +757,7 @@ static netdev_tx_t ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev
df = tiph->frag_off;
if (df)
- mtu = dst_mtu(&rt->u.dst) - dev->hard_header_len - tunnel->hlen;
+ mtu = dst_mtu(&rt->dst) - dev->hard_header_len - tunnel->hlen;
else
mtu = skb_dst(skb) ? dst_mtu(skb_dst(skb)) : dev->mtu;
@@ -803,7 +805,7 @@ static netdev_tx_t ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev
tunnel->err_count = 0;
}
- max_headroom = LL_RESERVED_SPACE(tdev) + gre_hlen + rt->u.dst.header_len;
+ max_headroom = LL_RESERVED_SPACE(tdev) + gre_hlen + rt->dst.header_len;
if (skb_headroom(skb) < max_headroom || skb_shared(skb)||
(skb_cloned(skb) && !skb_clone_writable(skb, 0))) {
@@ -830,7 +832,7 @@ static netdev_tx_t ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev
IPCB(skb)->flags &= ~(IPSKB_XFRM_TUNNEL_SIZE | IPSKB_XFRM_TRANSFORMED |
IPSKB_REROUTED);
skb_dst_drop(skb);
- skb_dst_set(skb, &rt->u.dst);
+ skb_dst_set(skb, &rt->dst);
/*
* Push down and install the IPIP header.
@@ -853,7 +855,7 @@ static netdev_tx_t ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev
iph->ttl = ((struct ipv6hdr *)old_iph)->hop_limit;
#endif
else
- iph->ttl = dst_metric(&rt->u.dst, RTAX_HOPLIMIT);
+ iph->ttl = dst_metric(&rt->dst, RTAX_HOPLIMIT);
}
((__be16 *)(iph + 1))[0] = tunnel->parms.o_flags;
@@ -915,7 +917,7 @@ static int ipgre_tunnel_bind_dev(struct net_device *dev)
.proto = IPPROTO_GRE };
struct rtable *rt;
if (!ip_route_output_key(dev_net(dev), &rt, &fl)) {
- tdev = rt->u.dst.dev;
+ tdev = rt->dst.dev;
ip_rt_put(rt);
}
@@ -1174,7 +1176,7 @@ static int ipgre_open(struct net_device *dev)
struct rtable *rt;
if (ip_route_output_key(dev_net(dev), &rt, &fl))
return -EADDRNOTAVAIL;
- dev = rt->u.dst.dev;
+ dev = rt->dst.dev;
ip_rt_put(rt);
if (__in_dev_get_rtnl(dev) == NULL)
return -EADDRNOTAVAIL;
diff --git a/net/ipv4/ip_input.c b/net/ipv4/ip_input.c
index d930dc5e4d8..d859bcc26cb 100644
--- a/net/ipv4/ip_input.c
+++ b/net/ipv4/ip_input.c
@@ -146,7 +146,7 @@
#include <linux/netlink.h>
/*
- * Process Router Attention IP option
+ * Process Router Attention IP option (RFC 2113)
*/
int ip_call_ra_chain(struct sk_buff *skb)
{
@@ -155,8 +155,7 @@ int ip_call_ra_chain(struct sk_buff *skb)
struct sock *last = NULL;
struct net_device *dev = skb->dev;
- read_lock(&ip_ra_lock);
- for (ra = ip_ra_chain; ra; ra = ra->next) {
+ for (ra = rcu_dereference(ip_ra_chain); ra; ra = rcu_dereference(ra->next)) {
struct sock *sk = ra->sk;
/* If socket is bound to an interface, only report
@@ -167,10 +166,8 @@ int ip_call_ra_chain(struct sk_buff *skb)
sk->sk_bound_dev_if == dev->ifindex) &&
net_eq(sock_net(sk), dev_net(dev))) {
if (ip_hdr(skb)->frag_off & htons(IP_MF | IP_OFFSET)) {
- if (ip_defrag(skb, IP_DEFRAG_CALL_RA_CHAIN)) {
- read_unlock(&ip_ra_lock);
+ if (ip_defrag(skb, IP_DEFRAG_CALL_RA_CHAIN))
return 1;
- }
}
if (last) {
struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC);
@@ -183,10 +180,8 @@ int ip_call_ra_chain(struct sk_buff *skb)
if (last) {
raw_rcv(last, skb);
- read_unlock(&ip_ra_lock);
return 1;
}
- read_unlock(&ip_ra_lock);
return 0;
}
@@ -298,18 +293,16 @@ static inline int ip_rcv_options(struct sk_buff *skb)
}
if (unlikely(opt->srr)) {
- struct in_device *in_dev = in_dev_get(dev);
+ struct in_device *in_dev = __in_dev_get_rcu(dev);
+
if (in_dev) {
if (!IN_DEV_SOURCE_ROUTE(in_dev)) {
if (IN_DEV_LOG_MARTIANS(in_dev) &&
net_ratelimit())
printk(KERN_INFO "source route option %pI4 -> %pI4\n",
&iph->saddr, &iph->daddr);
- in_dev_put(in_dev);
goto drop;
}
-
- in_dev_put(in_dev);
}
if (ip_options_rcv_srr(skb))
@@ -340,13 +333,16 @@ static int ip_rcv_finish(struct sk_buff *skb)
else if (err == -ENETUNREACH)
IP_INC_STATS_BH(dev_net(skb->dev),
IPSTATS_MIB_INNOROUTES);
+ else if (err == -EXDEV)
+ NET_INC_STATS_BH(dev_net(skb->dev),
+ LINUX_MIB_IPRPFILTER);
goto drop;
}
}
#ifdef CONFIG_NET_CLS_ROUTE
if (unlikely(skb_dst(skb)->tclassid)) {
- struct ip_rt_acct *st = per_cpu_ptr(ip_rt_acct, smp_processor_id());
+ struct ip_rt_acct *st = this_cpu_ptr(ip_rt_acct);
u32 idx = skb_dst(skb)->tclassid;
st[idx&0xFF].o_packets++;
st[idx&0xFF].o_bytes += skb->len;
@@ -360,10 +356,10 @@ static int ip_rcv_finish(struct sk_buff *skb)
rt = skb_rtable(skb);
if (rt->rt_type == RTN_MULTICAST) {
- IP_UPD_PO_STATS_BH(dev_net(rt->u.dst.dev), IPSTATS_MIB_INMCAST,
+ IP_UPD_PO_STATS_BH(dev_net(rt->dst.dev), IPSTATS_MIB_INMCAST,
skb->len);
} else if (rt->rt_type == RTN_BROADCAST)
- IP_UPD_PO_STATS_BH(dev_net(rt->u.dst.dev), IPSTATS_MIB_INBCAST,
+ IP_UPD_PO_STATS_BH(dev_net(rt->dst.dev), IPSTATS_MIB_INBCAST,
skb->len);
return dst_input(skb);
diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c
index 041d41df122..04b69896df5 100644
--- a/net/ipv4/ip_output.c
+++ b/net/ipv4/ip_output.c
@@ -89,6 +89,7 @@ __inline__ void ip_send_check(struct iphdr *iph)
iph->check = 0;
iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl);
}
+EXPORT_SYMBOL(ip_send_check);
int __ip_local_out(struct sk_buff *skb)
{
@@ -151,15 +152,15 @@ int ip_build_and_send_pkt(struct sk_buff *skb, struct sock *sk,
iph->version = 4;
iph->ihl = 5;
iph->tos = inet->tos;
- if (ip_dont_fragment(sk, &rt->u.dst))
+ if (ip_dont_fragment(sk, &rt->dst))
iph->frag_off = htons(IP_DF);
else
iph->frag_off = 0;
- iph->ttl = ip_select_ttl(inet, &rt->u.dst);
+ iph->ttl = ip_select_ttl(inet, &rt->dst);
iph->daddr = rt->rt_dst;
iph->saddr = rt->rt_src;
iph->protocol = sk->sk_protocol;
- ip_select_ident(iph, &rt->u.dst, sk);
+ ip_select_ident(iph, &rt->dst, sk);
if (opt && opt->optlen) {
iph->ihl += opt->optlen>>2;
@@ -172,7 +173,6 @@ int ip_build_and_send_pkt(struct sk_buff *skb, struct sock *sk,
/* Send it out. */
return ip_local_out(skb);
}
-
EXPORT_SYMBOL_GPL(ip_build_and_send_pkt);
static inline int ip_finish_output2(struct sk_buff *skb)
@@ -240,7 +240,7 @@ int ip_mc_output(struct sk_buff *skb)
{
struct sock *sk = skb->sk;
struct rtable *rt = skb_rtable(skb);
- struct net_device *dev = rt->u.dst.dev;
+ struct net_device *dev = rt->dst.dev;
/*
* If the indicated interface is up and running, send the packet.
@@ -359,9 +359,9 @@ int ip_queue_xmit(struct sk_buff *skb)
if (ip_route_output_flow(sock_net(sk), &rt, &fl, sk, 0))
goto no_route;
}
- sk_setup_caps(sk, &rt->u.dst);
+ sk_setup_caps(sk, &rt->dst);
}
- skb_dst_set_noref(skb, &rt->u.dst);
+ skb_dst_set_noref(skb, &rt->dst);
packet_routed:
if (opt && opt->is_strictroute && rt->rt_dst != rt->rt_gateway)
@@ -372,11 +372,11 @@ packet_routed:
skb_reset_network_header(skb);
iph = ip_hdr(skb);
*((__be16 *)iph) = htons((4 << 12) | (5 << 8) | (inet->tos & 0xff));
- if (ip_dont_fragment(sk, &rt->u.dst) && !skb->local_df)
+ if (ip_dont_fragment(sk, &rt->dst) && !skb->local_df)
iph->frag_off = htons(IP_DF);
else
iph->frag_off = 0;
- iph->ttl = ip_select_ttl(inet, &rt->u.dst);
+ iph->ttl = ip_select_ttl(inet, &rt->dst);
iph->protocol = sk->sk_protocol;
iph->saddr = rt->rt_src;
iph->daddr = rt->rt_dst;
@@ -387,7 +387,7 @@ packet_routed:
ip_options_build(skb, opt, inet->inet_daddr, rt, 0);
}
- ip_select_ident_more(iph, &rt->u.dst, sk,
+ ip_select_ident_more(iph, &rt->dst, sk,
(skb_shinfo(skb)->gso_segs ?: 1) - 1);
skb->priority = sk->sk_priority;
@@ -403,6 +403,7 @@ no_route:
kfree_skb(skb);
return -EHOSTUNREACH;
}
+EXPORT_SYMBOL(ip_queue_xmit);
static void ip_copy_metadata(struct sk_buff *to, struct sk_buff *from)
@@ -411,7 +412,7 @@ static void ip_copy_metadata(struct sk_buff *to, struct sk_buff *from)
to->priority = from->priority;
to->protocol = from->protocol;
skb_dst_drop(to);
- skb_dst_set(to, dst_clone(skb_dst(from)));
+ skb_dst_copy(to, from);
to->dev = from->dev;
to->mark = from->mark;
@@ -442,17 +443,16 @@ static void ip_copy_metadata(struct sk_buff *to, struct sk_buff *from)
int ip_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *))
{
struct iphdr *iph;
- int raw = 0;
int ptr;
struct net_device *dev;
struct sk_buff *skb2;
- unsigned int mtu, hlen, left, len, ll_rs, pad;
+ unsigned int mtu, hlen, left, len, ll_rs;
int offset;
__be16 not_last_frag;
struct rtable *rt = skb_rtable(skb);
int err = 0;
- dev = rt->u.dst.dev;
+ dev = rt->dst.dev;
/*
* Point into the IP datagram header.
@@ -473,7 +473,7 @@ int ip_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *))
*/
hlen = iph->ihl * 4;
- mtu = dst_mtu(&rt->u.dst) - hlen; /* Size of data space */
+ mtu = dst_mtu(&rt->dst) - hlen; /* Size of data space */
#ifdef CONFIG_BRIDGE_NETFILTER
if (skb->nf_bridge)
mtu -= nf_bridge_mtu_reduction(skb);
@@ -580,14 +580,12 @@ int ip_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *))
slow_path:
left = skb->len - hlen; /* Space per frame */
- ptr = raw + hlen; /* Where to start from */
+ ptr = hlen; /* Where to start from */
/* for bridged IP traffic encapsulated inside f.e. a vlan header,
* we need to make room for the encapsulating header
*/
- pad = nf_bridge_pad(skb);
- ll_rs = LL_RESERVED_SPACE_EXTRA(rt->u.dst.dev, pad);
- mtu -= pad;
+ ll_rs = LL_RESERVED_SPACE_EXTRA(rt->dst.dev, nf_bridge_pad(skb));
/*
* Fragment the datagram.
@@ -697,7 +695,6 @@ fail:
IP_INC_STATS(dev_net(dev), IPSTATS_MIB_FRAGFAILS);
return err;
}
-
EXPORT_SYMBOL(ip_fragment);
int
@@ -716,6 +713,7 @@ ip_generic_getfrag(void *from, char *to, int offset, int len, int odd, struct sk
}
return 0;
}
+EXPORT_SYMBOL(ip_generic_getfrag);
static inline __wsum
csum_page(struct page *page, int offset, int copy)
@@ -833,13 +831,13 @@ int ip_append_data(struct sock *sk,
*/
*rtp = NULL;
inet->cork.fragsize = mtu = inet->pmtudisc == IP_PMTUDISC_PROBE ?
- rt->u.dst.dev->mtu :
- dst_mtu(rt->u.dst.path);
- inet->cork.dst = &rt->u.dst;
+ rt->dst.dev->mtu :
+ dst_mtu(rt->dst.path);
+ inet->cork.dst = &rt->dst;
inet->cork.length = 0;
sk->sk_sndmsg_page = NULL;
sk->sk_sndmsg_off = 0;
- if ((exthdrlen = rt->u.dst.header_len) != 0) {
+ if ((exthdrlen = rt->dst.header_len) != 0) {
length += exthdrlen;
transhdrlen += exthdrlen;
}
@@ -852,7 +850,7 @@ int ip_append_data(struct sock *sk,
exthdrlen = 0;
mtu = inet->cork.fragsize;
}
- hh_len = LL_RESERVED_SPACE(rt->u.dst.dev);
+ hh_len = LL_RESERVED_SPACE(rt->dst.dev);
fragheaderlen = sizeof(struct iphdr) + (opt ? opt->optlen : 0);
maxfraglen = ((mtu - fragheaderlen) & ~7) + fragheaderlen;
@@ -869,7 +867,7 @@ int ip_append_data(struct sock *sk,
*/
if (transhdrlen &&
length + fragheaderlen <= mtu &&
- rt->u.dst.dev->features & NETIF_F_V4_CSUM &&
+ rt->dst.dev->features & NETIF_F_V4_CSUM &&
!exthdrlen)
csummode = CHECKSUM_PARTIAL;
@@ -878,7 +876,7 @@ int ip_append_data(struct sock *sk,
inet->cork.length += length;
if (((length > mtu) || (skb && skb_is_gso(skb))) &&
(sk->sk_protocol == IPPROTO_UDP) &&
- (rt->u.dst.dev->features & NETIF_F_UFO)) {
+ (rt->dst.dev->features & NETIF_F_UFO)) {
err = ip_ufo_append_data(sk, getfrag, from, length, hh_len,
fragheaderlen, transhdrlen, mtu,
flags);
@@ -926,7 +924,7 @@ alloc_new_skb:
fraglen = datalen + fragheaderlen;
if ((flags & MSG_MORE) &&
- !(rt->u.dst.dev->features&NETIF_F_SG))
+ !(rt->dst.dev->features&NETIF_F_SG))
alloclen = mtu;
else
alloclen = datalen + fragheaderlen;
@@ -937,7 +935,7 @@ alloc_new_skb:
* the last.
*/
if (datalen == length + fraggap)
- alloclen += rt->u.dst.trailer_len;
+ alloclen += rt->dst.trailer_len;
if (transhdrlen) {
skb = sock_alloc_send_skb(sk,
@@ -1010,7 +1008,7 @@ alloc_new_skb:
if (copy > length)
copy = length;
- if (!(rt->u.dst.dev->features&NETIF_F_SG)) {
+ if (!(rt->dst.dev->features&NETIF_F_SG)) {
unsigned int off;
off = skb->len;
@@ -1105,10 +1103,10 @@ ssize_t ip_append_page(struct sock *sk, struct page *page,
if (inet->cork.flags & IPCORK_OPT)
opt = inet->cork.opt;
- if (!(rt->u.dst.dev->features&NETIF_F_SG))
+ if (!(rt->dst.dev->features&NETIF_F_SG))
return -EOPNOTSUPP;
- hh_len = LL_RESERVED_SPACE(rt->u.dst.dev);
+ hh_len = LL_RESERVED_SPACE(rt->dst.dev);
mtu = inet->cork.fragsize;
fragheaderlen = sizeof(struct iphdr) + (opt ? opt->optlen : 0);
@@ -1125,7 +1123,7 @@ ssize_t ip_append_page(struct sock *sk, struct page *page,
inet->cork.length += size;
if ((size + skb->len > mtu) &&
(sk->sk_protocol == IPPROTO_UDP) &&
- (rt->u.dst.dev->features & NETIF_F_UFO)) {
+ (rt->dst.dev->features & NETIF_F_UFO)) {
skb_shinfo(skb)->gso_size = mtu - fragheaderlen;
skb_shinfo(skb)->gso_type = SKB_GSO_UDP;
}
@@ -1277,8 +1275,8 @@ int ip_push_pending_frames(struct sock *sk)
* If local_df is set too, we still allow to fragment this frame
* locally. */
if (inet->pmtudisc >= IP_PMTUDISC_DO ||
- (skb->len <= dst_mtu(&rt->u.dst) &&
- ip_dont_fragment(sk, &rt->u.dst)))
+ (skb->len <= dst_mtu(&rt->dst) &&
+ ip_dont_fragment(sk, &rt->dst)))
df = htons(IP_DF);
if (inet->cork.flags & IPCORK_OPT)
@@ -1287,7 +1285,7 @@ int ip_push_pending_frames(struct sock *sk)
if (rt->rt_type == RTN_MULTICAST)
ttl = inet->mc_ttl;
else
- ttl = ip_select_ttl(inet, &rt->u.dst);
+ ttl = ip_select_ttl(inet, &rt->dst);
iph = (struct iphdr *)skb->data;
iph->version = 4;
@@ -1298,7 +1296,7 @@ int ip_push_pending_frames(struct sock *sk)
}
iph->tos = inet->tos;
iph->frag_off = df;
- ip_select_ident(iph, &rt->u.dst, sk);
+ ip_select_ident(iph, &rt->dst, sk);
iph->ttl = ttl;
iph->protocol = sk->sk_protocol;
iph->saddr = rt->rt_src;
@@ -1311,7 +1309,7 @@ int ip_push_pending_frames(struct sock *sk)
* on dst refcount
*/
inet->cork.dst = NULL;
- skb_dst_set(skb, &rt->u.dst);
+ skb_dst_set(skb, &rt->dst);
if (iph->protocol == IPPROTO_ICMP)
icmp_out_count(net, ((struct icmphdr *)
@@ -1448,7 +1446,3 @@ void __init ip_init(void)
igmp_mc_proc_init();
#endif
}
-
-EXPORT_SYMBOL(ip_generic_getfrag);
-EXPORT_SYMBOL(ip_queue_xmit);
-EXPORT_SYMBOL(ip_send_check);
diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c
index ce231780a2b..6c40a8c46e7 100644
--- a/net/ipv4/ip_sockglue.c
+++ b/net/ipv4/ip_sockglue.c
@@ -239,7 +239,16 @@ int ip_cmsg_send(struct net *net, struct msghdr *msg, struct ipcm_cookie *ipc)
sent to multicast group to reach destination designated router.
*/
struct ip_ra_chain *ip_ra_chain;
-DEFINE_RWLOCK(ip_ra_lock);
+static DEFINE_SPINLOCK(ip_ra_lock);
+
+
+static void ip_ra_destroy_rcu(struct rcu_head *head)
+{
+ struct ip_ra_chain *ra = container_of(head, struct ip_ra_chain, rcu);
+
+ sock_put(ra->saved_sk);
+ kfree(ra);
+}
int ip_ra_control(struct sock *sk, unsigned char on,
void (*destructor)(struct sock *))
@@ -251,35 +260,42 @@ int ip_ra_control(struct sock *sk, unsigned char on,
new_ra = on ? kmalloc(sizeof(*new_ra), GFP_KERNEL) : NULL;
- write_lock_bh(&ip_ra_lock);
+ spin_lock_bh(&ip_ra_lock);
for (rap = &ip_ra_chain; (ra = *rap) != NULL; rap = &ra->next) {
if (ra->sk == sk) {
if (on) {
- write_unlock_bh(&ip_ra_lock);
+ spin_unlock_bh(&ip_ra_lock);
kfree(new_ra);
return -EADDRINUSE;
}
- *rap = ra->next;
- write_unlock_bh(&ip_ra_lock);
+ /* dont let ip_call_ra_chain() use sk again */
+ ra->sk = NULL;
+ rcu_assign_pointer(*rap, ra->next);
+ spin_unlock_bh(&ip_ra_lock);
if (ra->destructor)
ra->destructor(sk);
- sock_put(sk);
- kfree(ra);
+ /*
+ * Delay sock_put(sk) and kfree(ra) after one rcu grace
+ * period. This guarantee ip_call_ra_chain() dont need
+ * to mess with socket refcounts.
+ */
+ ra->saved_sk = sk;
+ call_rcu(&ra->rcu, ip_ra_destroy_rcu);
return 0;
}
}
if (new_ra == NULL) {
- write_unlock_bh(&ip_ra_lock);
+ spin_unlock_bh(&ip_ra_lock);
return -ENOBUFS;
}
new_ra->sk = sk;
new_ra->destructor = destructor;
new_ra->next = ra;
- *rap = new_ra;
+ rcu_assign_pointer(*rap, new_ra);
sock_hold(sk);
- write_unlock_bh(&ip_ra_lock);
+ spin_unlock_bh(&ip_ra_lock);
return 0;
}
@@ -449,7 +465,7 @@ static int do_ip_setsockopt(struct sock *sk, int level,
(1<<IP_MTU_DISCOVER) | (1<<IP_RECVERR) |
(1<<IP_ROUTER_ALERT) | (1<<IP_FREEBIND) |
(1<<IP_PASSSEC) | (1<<IP_TRANSPARENT) |
- (1<<IP_MINTTL))) ||
+ (1<<IP_MINTTL) | (1<<IP_NODEFRAG))) ||
optname == IP_MULTICAST_TTL ||
optname == IP_MULTICAST_ALL ||
optname == IP_MULTICAST_LOOP ||
@@ -572,6 +588,13 @@ static int do_ip_setsockopt(struct sock *sk, int level,
}
inet->hdrincl = val ? 1 : 0;
break;
+ case IP_NODEFRAG:
+ if (sk->sk_type != SOCK_RAW) {
+ err = -ENOPROTOOPT;
+ break;
+ }
+ inet->nodefrag = val ? 1 : 0;
+ break;
case IP_MTU_DISCOVER:
if (val < IP_PMTUDISC_DONT || val > IP_PMTUDISC_PROBE)
goto e_inval;
diff --git a/net/ipv4/ipconfig.c b/net/ipv4/ipconfig.c
index b9d84e800cf..3a6e1ec5e9a 100644
--- a/net/ipv4/ipconfig.c
+++ b/net/ipv4/ipconfig.c
@@ -665,6 +665,13 @@ ic_dhcp_init_options(u8 *options)
memcpy(e, ic_req_params, sizeof(ic_req_params));
e += sizeof(ic_req_params);
+ if (ic_host_name_set) {
+ *e++ = 12; /* host-name */
+ len = strlen(utsname()->nodename);
+ *e++ = len;
+ memcpy(e, utsname()->nodename, len);
+ e += len;
+ }
if (*vendor_class_identifier) {
printk(KERN_INFO "DHCP: sending class identifier \"%s\"\n",
vendor_class_identifier);
diff --git a/net/ipv4/ipip.c b/net/ipv4/ipip.c
index 7fd63671103..ec036731a70 100644
--- a/net/ipv4/ipip.c
+++ b/net/ipv4/ipip.c
@@ -435,7 +435,7 @@ static netdev_tx_t ipip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
goto tx_error_icmp;
}
}
- tdev = rt->u.dst.dev;
+ tdev = rt->dst.dev;
if (tdev == dev) {
ip_rt_put(rt);
@@ -446,7 +446,7 @@ static netdev_tx_t ipip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
df |= old_iph->frag_off & htons(IP_DF);
if (df) {
- mtu = dst_mtu(&rt->u.dst) - sizeof(struct iphdr);
+ mtu = dst_mtu(&rt->dst) - sizeof(struct iphdr);
if (mtu < 68) {
stats->collisions++;
@@ -503,7 +503,7 @@ static netdev_tx_t ipip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
IPCB(skb)->flags &= ~(IPSKB_XFRM_TUNNEL_SIZE | IPSKB_XFRM_TRANSFORMED |
IPSKB_REROUTED);
skb_dst_drop(skb);
- skb_dst_set(skb, &rt->u.dst);
+ skb_dst_set(skb, &rt->dst);
/*
* Push down and install the IPIP header.
@@ -552,7 +552,7 @@ static void ipip_tunnel_bind_dev(struct net_device *dev)
.proto = IPPROTO_IPIP };
struct rtable *rt;
if (!ip_route_output_key(dev_net(dev), &rt, &fl)) {
- tdev = rt->u.dst.dev;
+ tdev = rt->dst.dev;
ip_rt_put(rt);
}
dev->flags |= IFF_POINTOPOINT;
diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c
index 7f6273506ee..179fcab866f 100644
--- a/net/ipv4/ipmr.c
+++ b/net/ipv4/ipmr.c
@@ -1555,9 +1555,9 @@ static void ipmr_queue_xmit(struct net *net, struct mr_table *mrt,
goto out_free;
}
- dev = rt->u.dst.dev;
+ dev = rt->dst.dev;
- if (skb->len+encap > dst_mtu(&rt->u.dst) && (ntohs(iph->frag_off) & IP_DF)) {
+ if (skb->len+encap > dst_mtu(&rt->dst) && (ntohs(iph->frag_off) & IP_DF)) {
/* Do not fragment multicasts. Alas, IPv4 does not
allow to send ICMP, so that packets will disappear
to blackhole.
@@ -1568,7 +1568,7 @@ static void ipmr_queue_xmit(struct net *net, struct mr_table *mrt,
goto out_free;
}
- encap += LL_RESERVED_SPACE(dev) + rt->u.dst.header_len;
+ encap += LL_RESERVED_SPACE(dev) + rt->dst.header_len;
if (skb_cow(skb, encap)) {
ip_rt_put(rt);
@@ -1579,7 +1579,7 @@ static void ipmr_queue_xmit(struct net *net, struct mr_table *mrt,
vif->bytes_out += skb->len;
skb_dst_drop(skb);
- skb_dst_set(skb, &rt->u.dst);
+ skb_dst_set(skb, &rt->dst);
ip_decrease_ttl(ip_hdr(skb));
/* FIXME: forward and output firewalls used to be called here.
diff --git a/net/ipv4/netfilter.c b/net/ipv4/netfilter.c
index 07de855e217..d88a46c54fd 100644
--- a/net/ipv4/netfilter.c
+++ b/net/ipv4/netfilter.c
@@ -43,7 +43,7 @@ int ip_route_me_harder(struct sk_buff *skb, unsigned addr_type)
/* Drop old route. */
skb_dst_drop(skb);
- skb_dst_set(skb, &rt->u.dst);
+ skb_dst_set(skb, &rt->dst);
} else {
/* non-local src, find valid iif to satisfy
* rp-filter when calling ip_route_input. */
@@ -53,11 +53,11 @@ int ip_route_me_harder(struct sk_buff *skb, unsigned addr_type)
orefdst = skb->_skb_refdst;
if (ip_route_input(skb, iph->daddr, iph->saddr,
- RT_TOS(iph->tos), rt->u.dst.dev) != 0) {
- dst_release(&rt->u.dst);
+ RT_TOS(iph->tos), rt->dst.dev) != 0) {
+ dst_release(&rt->dst);
return -1;
}
- dst_release(&rt->u.dst);
+ dst_release(&rt->dst);
refdst_drop(orefdst);
}
@@ -212,9 +212,7 @@ static __sum16 nf_ip_checksum_partial(struct sk_buff *skb, unsigned int hook,
skb->csum = csum_tcpudp_nofold(iph->saddr, iph->daddr, protocol,
skb->len - dataoff, 0);
skb->ip_summed = CHECKSUM_NONE;
- csum = __skb_checksum_complete_head(skb, dataoff + len);
- if (!csum)
- skb->ip_summed = CHECKSUM_UNNECESSARY;
+ return __skb_checksum_complete_head(skb, dataoff + len);
}
return csum;
}
diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c
index 1ac01b12862..6bccba31d13 100644
--- a/net/ipv4/netfilter/arp_tables.c
+++ b/net/ipv4/netfilter/arp_tables.c
@@ -283,16 +283,13 @@ unsigned int arpt_do_table(struct sk_buff *skb,
arp = arp_hdr(skb);
do {
const struct arpt_entry_target *t;
- int hdr_len;
if (!arp_packet_match(arp, skb->dev, indev, outdev, &e->arp)) {
e = arpt_next_entry(e);
continue;
}
- hdr_len = sizeof(*arp) + (2 * sizeof(struct in_addr)) +
- (2 * skb->dev->addr_len);
- ADD_COUNTER(e->counters, hdr_len, 1);
+ ADD_COUNTER(e->counters, arp_hdr_len(skb->dev), 1);
t = arpt_get_target_c(e);
@@ -713,7 +710,7 @@ static void get_counters(const struct xt_table_info *t,
struct arpt_entry *iter;
unsigned int cpu;
unsigned int i;
- unsigned int curcpu;
+ unsigned int curcpu = get_cpu();
/* Instead of clearing (by a previous call to memset())
* the counters and using adds, we set the counters
@@ -723,14 +720,16 @@ static void get_counters(const struct xt_table_info *t,
* if new softirq were to run and call ipt_do_table
*/
local_bh_disable();
- curcpu = smp_processor_id();
-
i = 0;
xt_entry_foreach(iter, t->entries[curcpu], t->size) {
SET_COUNTER(counters[i], iter->counters.bcnt,
iter->counters.pcnt);
++i;
}
+ local_bh_enable();
+ /* Processing counters from other cpus, we can let bottom half enabled,
+ * (preemption is disabled)
+ */
for_each_possible_cpu(cpu) {
if (cpu == curcpu)
@@ -744,7 +743,7 @@ static void get_counters(const struct xt_table_info *t,
}
xt_info_wrunlock(cpu);
}
- local_bh_enable();
+ put_cpu();
}
static struct xt_counters *alloc_counters(const struct xt_table *table)
@@ -758,7 +757,7 @@ static struct xt_counters *alloc_counters(const struct xt_table *table)
* about).
*/
countersize = sizeof(struct xt_counters) * private->number;
- counters = vmalloc_node(countersize, numa_node_id());
+ counters = vmalloc(countersize);
if (counters == NULL)
return ERR_PTR(-ENOMEM);
@@ -1005,8 +1004,7 @@ static int __do_replace(struct net *net, const char *name,
struct arpt_entry *iter;
ret = 0;
- counters = vmalloc_node(num_counters * sizeof(struct xt_counters),
- numa_node_id());
+ counters = vmalloc(num_counters * sizeof(struct xt_counters));
if (!counters) {
ret = -ENOMEM;
goto out;
@@ -1159,7 +1157,7 @@ static int do_add_counters(struct net *net, const void __user *user,
if (len != size + num_counters * sizeof(struct xt_counters))
return -EINVAL;
- paddc = vmalloc_node(len - size, numa_node_id());
+ paddc = vmalloc(len - size);
if (!paddc)
return -ENOMEM;
diff --git a/net/ipv4/netfilter/ip_queue.c b/net/ipv4/netfilter/ip_queue.c
index a4e5fc5df4b..d2c1311cb28 100644
--- a/net/ipv4/netfilter/ip_queue.c
+++ b/net/ipv4/netfilter/ip_queue.c
@@ -42,7 +42,7 @@ typedef int (*ipq_cmpfn)(struct nf_queue_entry *, unsigned long);
static unsigned char copy_mode __read_mostly = IPQ_COPY_NONE;
static unsigned int queue_maxlen __read_mostly = IPQ_QMAX_DEFAULT;
-static DEFINE_RWLOCK(queue_lock);
+static DEFINE_SPINLOCK(queue_lock);
static int peer_pid __read_mostly;
static unsigned int copy_range __read_mostly;
static unsigned int queue_total;
@@ -72,10 +72,10 @@ __ipq_set_mode(unsigned char mode, unsigned int range)
break;
case IPQ_COPY_PACKET:
- copy_mode = mode;
+ if (range > 0xFFFF)
+ range = 0xFFFF;
copy_range = range;
- if (copy_range > 0xFFFF)
- copy_range = 0xFFFF;
+ copy_mode = mode;
break;
default:
@@ -101,7 +101,7 @@ ipq_find_dequeue_entry(unsigned long id)
{
struct nf_queue_entry *entry = NULL, *i;
- write_lock_bh(&queue_lock);
+ spin_lock_bh(&queue_lock);
list_for_each_entry(i, &queue_list, list) {
if ((unsigned long)i == id) {
@@ -115,7 +115,7 @@ ipq_find_dequeue_entry(unsigned long id)
queue_total--;
}
- write_unlock_bh(&queue_lock);
+ spin_unlock_bh(&queue_lock);
return entry;
}
@@ -136,9 +136,9 @@ __ipq_flush(ipq_cmpfn cmpfn, unsigned long data)
static void
ipq_flush(ipq_cmpfn cmpfn, unsigned long data)
{
- write_lock_bh(&queue_lock);
+ spin_lock_bh(&queue_lock);
__ipq_flush(cmpfn, data);
- write_unlock_bh(&queue_lock);
+ spin_unlock_bh(&queue_lock);
}
static struct sk_buff *
@@ -152,9 +152,7 @@ ipq_build_packet_message(struct nf_queue_entry *entry, int *errp)
struct nlmsghdr *nlh;
struct timeval tv;
- read_lock_bh(&queue_lock);
-
- switch (copy_mode) {
+ switch (ACCESS_ONCE(copy_mode)) {
case IPQ_COPY_META:
case IPQ_COPY_NONE:
size = NLMSG_SPACE(sizeof(*pmsg));
@@ -162,26 +160,21 @@ ipq_build_packet_message(struct nf_queue_entry *entry, int *errp)
case IPQ_COPY_PACKET:
if (entry->skb->ip_summed == CHECKSUM_PARTIAL &&
- (*errp = skb_checksum_help(entry->skb))) {
- read_unlock_bh(&queue_lock);
+ (*errp = skb_checksum_help(entry->skb)))
return NULL;
- }
- if (copy_range == 0 || copy_range > entry->skb->len)
+
+ data_len = ACCESS_ONCE(copy_range);
+ if (data_len == 0 || data_len > entry->skb->len)
data_len = entry->skb->len;
- else
- data_len = copy_range;
size = NLMSG_SPACE(sizeof(*pmsg) + data_len);
break;
default:
*errp = -EINVAL;
- read_unlock_bh(&queue_lock);
return NULL;
}
- read_unlock_bh(&queue_lock);
-
skb = alloc_skb(size, GFP_ATOMIC);
if (!skb)
goto nlmsg_failure;
@@ -242,7 +235,7 @@ ipq_enqueue_packet(struct nf_queue_entry *entry, unsigned int queuenum)
if (nskb == NULL)
return status;
- write_lock_bh(&queue_lock);
+ spin_lock_bh(&queue_lock);
if (!peer_pid)
goto err_out_free_nskb;
@@ -266,14 +259,14 @@ ipq_enqueue_packet(struct nf_queue_entry *entry, unsigned int queuenum)
__ipq_enqueue_entry(entry);
- write_unlock_bh(&queue_lock);
+ spin_unlock_bh(&queue_lock);
return status;
err_out_free_nskb:
kfree_skb(nskb);
err_out_unlock:
- write_unlock_bh(&queue_lock);
+ spin_unlock_bh(&queue_lock);
return status;
}
@@ -342,9 +335,9 @@ ipq_set_mode(unsigned char mode, unsigned int range)
{
int status;
- write_lock_bh(&queue_lock);
+ spin_lock_bh(&queue_lock);
status = __ipq_set_mode(mode, range);
- write_unlock_bh(&queue_lock);
+ spin_unlock_bh(&queue_lock);
return status;
}
@@ -440,11 +433,11 @@ __ipq_rcv_skb(struct sk_buff *skb)
if (security_netlink_recv(skb, CAP_NET_ADMIN))
RCV_SKB_FAIL(-EPERM);
- write_lock_bh(&queue_lock);
+ spin_lock_bh(&queue_lock);
if (peer_pid) {
if (peer_pid != pid) {
- write_unlock_bh(&queue_lock);
+ spin_unlock_bh(&queue_lock);
RCV_SKB_FAIL(-EBUSY);
}
} else {
@@ -452,7 +445,7 @@ __ipq_rcv_skb(struct sk_buff *skb)
peer_pid = pid;
}
- write_unlock_bh(&queue_lock);
+ spin_unlock_bh(&queue_lock);
status = ipq_receive_peer(NLMSG_DATA(nlh), type,
nlmsglen - NLMSG_LENGTH(0));
@@ -497,10 +490,10 @@ ipq_rcv_nl_event(struct notifier_block *this,
struct netlink_notify *n = ptr;
if (event == NETLINK_URELEASE && n->protocol == NETLINK_FIREWALL) {
- write_lock_bh(&queue_lock);
+ spin_lock_bh(&queue_lock);
if ((net_eq(n->net, &init_net)) && (n->pid == peer_pid))
__ipq_reset();
- write_unlock_bh(&queue_lock);
+ spin_unlock_bh(&queue_lock);
}
return NOTIFY_DONE;
}
@@ -527,7 +520,7 @@ static ctl_table ipq_table[] = {
#ifdef CONFIG_PROC_FS
static int ip_queue_show(struct seq_file *m, void *v)
{
- read_lock_bh(&queue_lock);
+ spin_lock_bh(&queue_lock);
seq_printf(m,
"Peer PID : %d\n"
@@ -545,7 +538,7 @@ static int ip_queue_show(struct seq_file *m, void *v)
queue_dropped,
queue_user_dropped);
- read_unlock_bh(&queue_lock);
+ spin_unlock_bh(&queue_lock);
return 0;
}
diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c
index 4b6c5ca610f..c439721b165 100644
--- a/net/ipv4/netfilter/ip_tables.c
+++ b/net/ipv4/netfilter/ip_tables.c
@@ -364,7 +364,7 @@ ipt_do_table(struct sk_buff *skb,
goto no_match;
}
- ADD_COUNTER(e->counters, ntohs(ip->tot_len), 1);
+ ADD_COUNTER(e->counters, skb->len, 1);
t = ipt_get_target(e);
IP_NF_ASSERT(t->u.kernel.target);
@@ -884,7 +884,7 @@ get_counters(const struct xt_table_info *t,
struct ipt_entry *iter;
unsigned int cpu;
unsigned int i;
- unsigned int curcpu;
+ unsigned int curcpu = get_cpu();
/* Instead of clearing (by a previous call to memset())
* the counters and using adds, we set the counters
@@ -894,14 +894,16 @@ get_counters(const struct xt_table_info *t,
* if new softirq were to run and call ipt_do_table
*/
local_bh_disable();
- curcpu = smp_processor_id();
-
i = 0;
xt_entry_foreach(iter, t->entries[curcpu], t->size) {
SET_COUNTER(counters[i], iter->counters.bcnt,
iter->counters.pcnt);
++i;
}
+ local_bh_enable();
+ /* Processing counters from other cpus, we can let bottom half enabled,
+ * (preemption is disabled)
+ */
for_each_possible_cpu(cpu) {
if (cpu == curcpu)
@@ -915,7 +917,7 @@ get_counters(const struct xt_table_info *t,
}
xt_info_wrunlock(cpu);
}
- local_bh_enable();
+ put_cpu();
}
static struct xt_counters *alloc_counters(const struct xt_table *table)
@@ -928,7 +930,7 @@ static struct xt_counters *alloc_counters(const struct xt_table *table)
(other than comefrom, which userspace doesn't care
about). */
countersize = sizeof(struct xt_counters) * private->number;
- counters = vmalloc_node(countersize, numa_node_id());
+ counters = vmalloc(countersize);
if (counters == NULL)
return ERR_PTR(-ENOMEM);
@@ -1352,7 +1354,7 @@ do_add_counters(struct net *net, const void __user *user,
if (len != size + num_counters * sizeof(struct xt_counters))
return -EINVAL;
- paddc = vmalloc_node(len - size, numa_node_id());
+ paddc = vmalloc(len - size);
if (!paddc)
return -ENOMEM;
diff --git a/net/ipv4/netfilter/ipt_CLUSTERIP.c b/net/ipv4/netfilter/ipt_CLUSTERIP.c
index f91c94b9a79..3a43cf36db8 100644
--- a/net/ipv4/netfilter/ipt_CLUSTERIP.c
+++ b/net/ipv4/netfilter/ipt_CLUSTERIP.c
@@ -53,12 +53,13 @@ struct clusterip_config {
#endif
enum clusterip_hashmode hash_mode; /* which hashing mode */
u_int32_t hash_initval; /* hash initialization */
+ struct rcu_head rcu;
};
static LIST_HEAD(clusterip_configs);
/* clusterip_lock protects the clusterip_configs list */
-static DEFINE_RWLOCK(clusterip_lock);
+static DEFINE_SPINLOCK(clusterip_lock);
#ifdef CONFIG_PROC_FS
static const struct file_operations clusterip_proc_fops;
@@ -71,11 +72,17 @@ clusterip_config_get(struct clusterip_config *c)
atomic_inc(&c->refcount);
}
+
+static void clusterip_config_rcu_free(struct rcu_head *head)
+{
+ kfree(container_of(head, struct clusterip_config, rcu));
+}
+
static inline void
clusterip_config_put(struct clusterip_config *c)
{
if (atomic_dec_and_test(&c->refcount))
- kfree(c);
+ call_rcu_bh(&c->rcu, clusterip_config_rcu_free);
}
/* decrease the count of entries using/referencing this config. If last
@@ -84,10 +91,11 @@ clusterip_config_put(struct clusterip_config *c)
static inline void
clusterip_config_entry_put(struct clusterip_config *c)
{
- write_lock_bh(&clusterip_lock);
- if (atomic_dec_and_test(&c->entries)) {
- list_del(&c->list);
- write_unlock_bh(&clusterip_lock);
+ local_bh_disable();
+ if (atomic_dec_and_lock(&c->entries, &clusterip_lock)) {
+ list_del_rcu(&c->list);
+ spin_unlock(&clusterip_lock);
+ local_bh_enable();
dev_mc_del(c->dev, c->clustermac);
dev_put(c->dev);
@@ -100,7 +108,7 @@ clusterip_config_entry_put(struct clusterip_config *c)
#endif
return;
}
- write_unlock_bh(&clusterip_lock);
+ local_bh_enable();
}
static struct clusterip_config *
@@ -108,7 +116,7 @@ __clusterip_config_find(__be32 clusterip)
{
struct clusterip_config *c;
- list_for_each_entry(c, &clusterip_configs, list) {
+ list_for_each_entry_rcu(c, &clusterip_configs, list) {
if (c->clusterip == clusterip)
return c;
}
@@ -121,16 +129,15 @@ clusterip_config_find_get(__be32 clusterip, int entry)
{
struct clusterip_config *c;
- read_lock_bh(&clusterip_lock);
+ rcu_read_lock_bh();
c = __clusterip_config_find(clusterip);
- if (!c) {
- read_unlock_bh(&clusterip_lock);
- return NULL;
+ if (c) {
+ if (unlikely(!atomic_inc_not_zero(&c->refcount)))
+ c = NULL;
+ else if (entry)
+ atomic_inc(&c->entries);
}
- atomic_inc(&c->refcount);
- if (entry)
- atomic_inc(&c->entries);
- read_unlock_bh(&clusterip_lock);
+ rcu_read_unlock_bh();
return c;
}
@@ -181,9 +188,9 @@ clusterip_config_init(const struct ipt_clusterip_tgt_info *i, __be32 ip,
}
#endif
- write_lock_bh(&clusterip_lock);
- list_add(&c->list, &clusterip_configs);
- write_unlock_bh(&clusterip_lock);
+ spin_lock_bh(&clusterip_lock);
+ list_add_rcu(&c->list, &clusterip_configs);
+ spin_unlock_bh(&clusterip_lock);
return c;
}
@@ -462,7 +469,7 @@ struct arp_payload {
__be32 src_ip;
u_int8_t dst_hw[ETH_ALEN];
__be32 dst_ip;
-} __attribute__ ((packed));
+} __packed;
#ifdef DEBUG
static void arp_print(struct arp_payload *payload)
@@ -733,6 +740,9 @@ static void __exit clusterip_tg_exit(void)
#endif
nf_unregister_hook(&cip_arp_ops);
xt_unregister_target(&clusterip_tg_reg);
+
+ /* Wait for completion of call_rcu_bh()'s (clusterip_config_rcu_free) */
+ rcu_barrier_bh();
}
module_init(clusterip_tg_init);
diff --git a/net/ipv4/netfilter/ipt_LOG.c b/net/ipv4/netfilter/ipt_LOG.c
index 5234f4f3499..915fc17d7ce 100644
--- a/net/ipv4/netfilter/ipt_LOG.c
+++ b/net/ipv4/netfilter/ipt_LOG.c
@@ -13,6 +13,7 @@
#include <linux/module.h>
#include <linux/spinlock.h>
#include <linux/skbuff.h>
+#include <linux/if_arp.h>
#include <linux/ip.h>
#include <net/icmp.h>
#include <net/udp.h>
@@ -363,6 +364,42 @@ static void dump_packet(const struct nf_loginfo *info,
/* maxlen = 230+ 91 + 230 + 252 = 803 */
}
+static void dump_mac_header(const struct nf_loginfo *info,
+ const struct sk_buff *skb)
+{
+ struct net_device *dev = skb->dev;
+ unsigned int logflags = 0;
+
+ if (info->type == NF_LOG_TYPE_LOG)
+ logflags = info->u.log.logflags;
+
+ if (!(logflags & IPT_LOG_MACDECODE))
+ goto fallback;
+
+ switch (dev->type) {
+ case ARPHRD_ETHER:
+ printk("MACSRC=%pM MACDST=%pM MACPROTO=%04x ",
+ eth_hdr(skb)->h_source, eth_hdr(skb)->h_dest,
+ ntohs(eth_hdr(skb)->h_proto));
+ return;
+ default:
+ break;
+ }
+
+fallback:
+ printk("MAC=");
+ if (dev->hard_header_len &&
+ skb->mac_header != skb->network_header) {
+ const unsigned char *p = skb_mac_header(skb);
+ unsigned int i;
+
+ printk("%02x", *p++);
+ for (i = 1; i < dev->hard_header_len; i++, p++)
+ printk(":%02x", *p);
+ }
+ printk(" ");
+}
+
static struct nf_loginfo default_loginfo = {
.type = NF_LOG_TYPE_LOG,
.u = {
@@ -404,20 +441,9 @@ ipt_log_packet(u_int8_t pf,
}
#endif
- if (in && !out) {
- /* MAC logging for input chain only. */
- printk("MAC=");
- if (skb->dev && skb->dev->hard_header_len &&
- skb->mac_header != skb->network_header) {
- int i;
- const unsigned char *p = skb_mac_header(skb);
- for (i = 0; i < skb->dev->hard_header_len; i++,p++)
- printk("%02x%c", *p,
- i==skb->dev->hard_header_len - 1
- ? ' ':':');
- } else
- printk(" ");
- }
+ /* MAC logging for input path only. */
+ if (in && !out)
+ dump_mac_header(loginfo, skb);
dump_packet(loginfo, skb, 0);
printk("\n");
diff --git a/net/ipv4/netfilter/ipt_NETMAP.c b/net/ipv4/netfilter/ipt_NETMAP.c
index f43867d1697..6cdb298f103 100644
--- a/net/ipv4/netfilter/ipt_NETMAP.c
+++ b/net/ipv4/netfilter/ipt_NETMAP.c
@@ -48,7 +48,8 @@ netmap_tg(struct sk_buff *skb, const struct xt_action_param *par)
NF_CT_ASSERT(par->hooknum == NF_INET_PRE_ROUTING ||
par->hooknum == NF_INET_POST_ROUTING ||
- par->hooknum == NF_INET_LOCAL_OUT);
+ par->hooknum == NF_INET_LOCAL_OUT ||
+ par->hooknum == NF_INET_LOCAL_IN);
ct = nf_ct_get(skb, &ctinfo);
netmask = ~(mr->range[0].min_ip ^ mr->range[0].max_ip);
@@ -77,7 +78,8 @@ static struct xt_target netmap_tg_reg __read_mostly = {
.table = "nat",
.hooks = (1 << NF_INET_PRE_ROUTING) |
(1 << NF_INET_POST_ROUTING) |
- (1 << NF_INET_LOCAL_OUT),
+ (1 << NF_INET_LOCAL_OUT) |
+ (1 << NF_INET_LOCAL_IN),
.checkentry = netmap_tg_check,
.me = THIS_MODULE
};
diff --git a/net/ipv4/netfilter/ipt_REJECT.c b/net/ipv4/netfilter/ipt_REJECT.c
index f5f4a888e4e..b254dafaf42 100644
--- a/net/ipv4/netfilter/ipt_REJECT.c
+++ b/net/ipv4/netfilter/ipt_REJECT.c
@@ -95,10 +95,11 @@ static void send_reset(struct sk_buff *oldskb, int hook)
}
tcph->rst = 1;
- tcph->check = tcp_v4_check(sizeof(struct tcphdr),
- niph->saddr, niph->daddr,
- csum_partial(tcph,
- sizeof(struct tcphdr), 0));
+ tcph->check = ~tcp_v4_check(sizeof(struct tcphdr), niph->saddr,
+ niph->daddr, 0);
+ nskb->ip_summed = CHECKSUM_PARTIAL;
+ nskb->csum_start = (unsigned char *)tcph - nskb->head;
+ nskb->csum_offset = offsetof(struct tcphdr, check);
addr_type = RTN_UNSPEC;
if (hook != NF_INET_FORWARD
@@ -109,13 +110,12 @@ static void send_reset(struct sk_buff *oldskb, int hook)
addr_type = RTN_LOCAL;
/* ip_route_me_harder expects skb->dst to be set */
- skb_dst_set(nskb, dst_clone(skb_dst(oldskb)));
+ skb_dst_set_noref(nskb, skb_dst(oldskb));
if (ip_route_me_harder(nskb, addr_type))
goto free_nskb;
niph->ttl = dst_metric(skb_dst(nskb), RTAX_HOPLIMIT);
- nskb->ip_summed = CHECKSUM_NONE;
/* "Never happens" */
if (nskb->len > dst_mtu(skb_dst(nskb)))
diff --git a/net/ipv4/netfilter/nf_defrag_ipv4.c b/net/ipv4/netfilter/nf_defrag_ipv4.c
index cb763ae9ed9..eab8de32f20 100644
--- a/net/ipv4/netfilter/nf_defrag_ipv4.c
+++ b/net/ipv4/netfilter/nf_defrag_ipv4.c
@@ -66,6 +66,11 @@ static unsigned int ipv4_conntrack_defrag(unsigned int hooknum,
const struct net_device *out,
int (*okfn)(struct sk_buff *))
{
+ struct inet_sock *inet = inet_sk(skb->sk);
+
+ if (inet && inet->nodefrag)
+ return NF_ACCEPT;
+
#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
#if !defined(CONFIG_NF_NAT) && !defined(CONFIG_NF_NAT_MODULE)
/* Previously seen (loopback)? Ignore. Do this before
diff --git a/net/ipv4/netfilter/nf_nat_core.c b/net/ipv4/netfilter/nf_nat_core.c
index 4f8bddb760c..8c8632d9b93 100644
--- a/net/ipv4/netfilter/nf_nat_core.c
+++ b/net/ipv4/netfilter/nf_nat_core.c
@@ -261,14 +261,9 @@ get_unique_tuple(struct nf_conntrack_tuple *tuple,
rcu_read_lock();
proto = __nf_nat_proto_find(orig_tuple->dst.protonum);
- /* Change protocol info to have some randomization */
- if (range->flags & IP_NAT_RANGE_PROTO_RANDOM) {
- proto->unique_tuple(tuple, range, maniptype, ct);
- goto out;
- }
-
/* Only bother mapping if it's not already in range and unique */
- if ((!(range->flags & IP_NAT_RANGE_PROTO_SPECIFIED) ||
+ if (!(range->flags & IP_NAT_RANGE_PROTO_RANDOM) &&
+ (!(range->flags & IP_NAT_RANGE_PROTO_SPECIFIED) ||
proto->in_range(tuple, maniptype, &range->min, &range->max)) &&
!nf_nat_used_tuple(tuple, ct))
goto out;
@@ -440,7 +435,7 @@ int nf_nat_icmp_reply_translation(struct nf_conn *ct,
if (!skb_make_writable(skb, hdrlen + sizeof(*inside)))
return 0;
- inside = (void *)skb->data + ip_hdrlen(skb);
+ inside = (void *)skb->data + hdrlen;
/* We're actually going to mangle it beyond trivial checksum
adjustment, so make sure the current checksum is correct. */
@@ -470,12 +465,10 @@ int nf_nat_icmp_reply_translation(struct nf_conn *ct,
/* rcu_read_lock()ed by nf_hook_slow */
l4proto = __nf_ct_l4proto_find(PF_INET, inside->ip.protocol);
- if (!nf_ct_get_tuple(skb,
- ip_hdrlen(skb) + sizeof(struct icmphdr),
- (ip_hdrlen(skb) +
+ if (!nf_ct_get_tuple(skb, hdrlen + sizeof(struct icmphdr),
+ (hdrlen +
sizeof(struct icmphdr) + inside->ip.ihl * 4),
- (u_int16_t)AF_INET,
- inside->ip.protocol,
+ (u_int16_t)AF_INET, inside->ip.protocol,
&inner, l3proto, l4proto))
return 0;
@@ -484,15 +477,13 @@ int nf_nat_icmp_reply_translation(struct nf_conn *ct,
pass all hooks (locally-generated ICMP). Consider incoming
packet: PREROUTING (DST manip), routing produces ICMP, goes
through POSTROUTING (which must correct the DST manip). */
- if (!manip_pkt(inside->ip.protocol, skb,
- ip_hdrlen(skb) + sizeof(inside->icmp),
- &ct->tuplehash[!dir].tuple,
- !manip))
+ if (!manip_pkt(inside->ip.protocol, skb, hdrlen + sizeof(inside->icmp),
+ &ct->tuplehash[!dir].tuple, !manip))
return 0;
if (skb->ip_summed != CHECKSUM_PARTIAL) {
/* Reloading "inside" here since manip_pkt inner. */
- inside = (void *)skb->data + ip_hdrlen(skb);
+ inside = (void *)skb->data + hdrlen;
inside->icmp.checksum = 0;
inside->icmp.checksum =
csum_fold(skb_checksum(skb, hdrlen,
@@ -742,7 +733,7 @@ static int __init nf_nat_init(void)
spin_unlock_bh(&nf_nat_lock);
/* Initialize fake conntrack so that NAT will skip it */
- nf_conntrack_untracked.status |= IPS_NAT_DONE_MASK;
+ nf_ct_untracked_status_or(IPS_NAT_DONE_MASK);
l3proto = nf_ct_l3proto_find_get((u_int16_t)AF_INET);
diff --git a/net/ipv4/netfilter/nf_nat_proto_common.c b/net/ipv4/netfilter/nf_nat_proto_common.c
index 6c4f11f5144..3e61faf23a9 100644
--- a/net/ipv4/netfilter/nf_nat_proto_common.c
+++ b/net/ipv4/netfilter/nf_nat_proto_common.c
@@ -34,7 +34,7 @@ bool nf_nat_proto_in_range(const struct nf_conntrack_tuple *tuple,
}
EXPORT_SYMBOL_GPL(nf_nat_proto_in_range);
-bool nf_nat_proto_unique_tuple(struct nf_conntrack_tuple *tuple,
+void nf_nat_proto_unique_tuple(struct nf_conntrack_tuple *tuple,
const struct nf_nat_range *range,
enum nf_nat_manip_type maniptype,
const struct nf_conn *ct,
@@ -53,7 +53,7 @@ bool nf_nat_proto_unique_tuple(struct nf_conntrack_tuple *tuple,
if (!(range->flags & IP_NAT_RANGE_PROTO_SPECIFIED)) {
/* If it's dst rewrite, can't change port */
if (maniptype == IP_NAT_MANIP_DST)
- return false;
+ return;
if (ntohs(*portptr) < 1024) {
/* Loose convention: >> 512 is credential passing */
@@ -81,15 +81,15 @@ bool nf_nat_proto_unique_tuple(struct nf_conntrack_tuple *tuple,
else
off = *rover;
- for (i = 0; i < range_size; i++, off++) {
+ for (i = 0; ; ++off) {
*portptr = htons(min + off % range_size);
- if (nf_nat_used_tuple(tuple, ct))
+ if (++i != range_size && nf_nat_used_tuple(tuple, ct))
continue;
if (!(range->flags & IP_NAT_RANGE_PROTO_RANDOM))
*rover = off;
- return true;
+ return;
}
- return false;
+ return;
}
EXPORT_SYMBOL_GPL(nf_nat_proto_unique_tuple);
diff --git a/net/ipv4/netfilter/nf_nat_proto_dccp.c b/net/ipv4/netfilter/nf_nat_proto_dccp.c
index 22485ce306d..570faf2667b 100644
--- a/net/ipv4/netfilter/nf_nat_proto_dccp.c
+++ b/net/ipv4/netfilter/nf_nat_proto_dccp.c
@@ -22,14 +22,14 @@
static u_int16_t dccp_port_rover;
-static bool
+static void
dccp_unique_tuple(struct nf_conntrack_tuple *tuple,
const struct nf_nat_range *range,
enum nf_nat_manip_type maniptype,
const struct nf_conn *ct)
{
- return nf_nat_proto_unique_tuple(tuple, range, maniptype, ct,
- &dccp_port_rover);
+ nf_nat_proto_unique_tuple(tuple, range, maniptype, ct,
+ &dccp_port_rover);
}
static bool
diff --git a/net/ipv4/netfilter/nf_nat_proto_gre.c b/net/ipv4/netfilter/nf_nat_proto_gre.c
index d7e89201351..bc8d83a31c7 100644
--- a/net/ipv4/netfilter/nf_nat_proto_gre.c
+++ b/net/ipv4/netfilter/nf_nat_proto_gre.c
@@ -37,7 +37,7 @@ MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>");
MODULE_DESCRIPTION("Netfilter NAT protocol helper module for GRE");
/* generate unique tuple ... */
-static bool
+static void
gre_unique_tuple(struct nf_conntrack_tuple *tuple,
const struct nf_nat_range *range,
enum nf_nat_manip_type maniptype,
@@ -50,7 +50,7 @@ gre_unique_tuple(struct nf_conntrack_tuple *tuple,
/* If there is no master conntrack we are not PPTP,
do not change tuples */
if (!ct->master)
- return false;
+ return;
if (maniptype == IP_NAT_MANIP_SRC)
keyptr = &tuple->src.u.gre.key;
@@ -68,14 +68,14 @@ gre_unique_tuple(struct nf_conntrack_tuple *tuple,
pr_debug("min = %u, range_size = %u\n", min, range_size);
- for (i = 0; i < range_size; i++, key++) {
+ for (i = 0; ; ++key) {
*keyptr = htons(min + key % range_size);
- if (!nf_nat_used_tuple(tuple, ct))
- return true;
+ if (++i == range_size || !nf_nat_used_tuple(tuple, ct))
+ return;
}
pr_debug("%p: no NAT mapping\n", ct);
- return false;
+ return;
}
/* manipulate a GRE packet according to maniptype */
diff --git a/net/ipv4/netfilter/nf_nat_proto_icmp.c b/net/ipv4/netfilter/nf_nat_proto_icmp.c
index 19a8b0b07d8..5744c3ec847 100644
--- a/net/ipv4/netfilter/nf_nat_proto_icmp.c
+++ b/net/ipv4/netfilter/nf_nat_proto_icmp.c
@@ -27,7 +27,7 @@ icmp_in_range(const struct nf_conntrack_tuple *tuple,
ntohs(tuple->src.u.icmp.id) <= ntohs(max->icmp.id);
}
-static bool
+static void
icmp_unique_tuple(struct nf_conntrack_tuple *tuple,
const struct nf_nat_range *range,
enum nf_nat_manip_type maniptype,
@@ -42,13 +42,13 @@ icmp_unique_tuple(struct nf_conntrack_tuple *tuple,
if (!(range->flags & IP_NAT_RANGE_PROTO_SPECIFIED))
range_size = 0xFFFF;
- for (i = 0; i < range_size; i++, id++) {
+ for (i = 0; ; ++id) {
tuple->src.u.icmp.id = htons(ntohs(range->min.icmp.id) +
(id % range_size));
- if (!nf_nat_used_tuple(tuple, ct))
- return true;
+ if (++i == range_size || !nf_nat_used_tuple(tuple, ct))
+ return;
}
- return false;
+ return;
}
static bool
diff --git a/net/ipv4/netfilter/nf_nat_proto_sctp.c b/net/ipv4/netfilter/nf_nat_proto_sctp.c
index 3fc598eeeb1..756331d4266 100644
--- a/net/ipv4/netfilter/nf_nat_proto_sctp.c
+++ b/net/ipv4/netfilter/nf_nat_proto_sctp.c
@@ -16,14 +16,14 @@
static u_int16_t nf_sctp_port_rover;
-static bool
+static void
sctp_unique_tuple(struct nf_conntrack_tuple *tuple,
const struct nf_nat_range *range,
enum nf_nat_manip_type maniptype,
const struct nf_conn *ct)
{
- return nf_nat_proto_unique_tuple(tuple, range, maniptype, ct,
- &nf_sctp_port_rover);
+ nf_nat_proto_unique_tuple(tuple, range, maniptype, ct,
+ &nf_sctp_port_rover);
}
static bool
diff --git a/net/ipv4/netfilter/nf_nat_proto_tcp.c b/net/ipv4/netfilter/nf_nat_proto_tcp.c
index 399e2cfa263..aa460a595d5 100644
--- a/net/ipv4/netfilter/nf_nat_proto_tcp.c
+++ b/net/ipv4/netfilter/nf_nat_proto_tcp.c
@@ -20,14 +20,13 @@
static u_int16_t tcp_port_rover;
-static bool
+static void
tcp_unique_tuple(struct nf_conntrack_tuple *tuple,
const struct nf_nat_range *range,
enum nf_nat_manip_type maniptype,
const struct nf_conn *ct)
{
- return nf_nat_proto_unique_tuple(tuple, range, maniptype, ct,
- &tcp_port_rover);
+ nf_nat_proto_unique_tuple(tuple, range, maniptype, ct, &tcp_port_rover);
}
static bool
diff --git a/net/ipv4/netfilter/nf_nat_proto_udp.c b/net/ipv4/netfilter/nf_nat_proto_udp.c
index 9e61c79492e..dfe65c7e292 100644
--- a/net/ipv4/netfilter/nf_nat_proto_udp.c
+++ b/net/ipv4/netfilter/nf_nat_proto_udp.c
@@ -19,14 +19,13 @@
static u_int16_t udp_port_rover;
-static bool
+static void
udp_unique_tuple(struct nf_conntrack_tuple *tuple,
const struct nf_nat_range *range,
enum nf_nat_manip_type maniptype,
const struct nf_conn *ct)
{
- return nf_nat_proto_unique_tuple(tuple, range, maniptype, ct,
- &udp_port_rover);
+ nf_nat_proto_unique_tuple(tuple, range, maniptype, ct, &udp_port_rover);
}
static bool
diff --git a/net/ipv4/netfilter/nf_nat_proto_udplite.c b/net/ipv4/netfilter/nf_nat_proto_udplite.c
index 440a229bbd8..3cc8c8af39e 100644
--- a/net/ipv4/netfilter/nf_nat_proto_udplite.c
+++ b/net/ipv4/netfilter/nf_nat_proto_udplite.c
@@ -18,14 +18,14 @@
static u_int16_t udplite_port_rover;
-static bool
+static void
udplite_unique_tuple(struct nf_conntrack_tuple *tuple,
const struct nf_nat_range *range,
enum nf_nat_manip_type maniptype,
const struct nf_conn *ct)
{
- return nf_nat_proto_unique_tuple(tuple, range, maniptype, ct,
- &udplite_port_rover);
+ nf_nat_proto_unique_tuple(tuple, range, maniptype, ct,
+ &udplite_port_rover);
}
static bool
diff --git a/net/ipv4/netfilter/nf_nat_proto_unknown.c b/net/ipv4/netfilter/nf_nat_proto_unknown.c
index 14381c62ace..a50f2bc1c73 100644
--- a/net/ipv4/netfilter/nf_nat_proto_unknown.c
+++ b/net/ipv4/netfilter/nf_nat_proto_unknown.c
@@ -26,14 +26,14 @@ static bool unknown_in_range(const struct nf_conntrack_tuple *tuple,
return true;
}
-static bool unknown_unique_tuple(struct nf_conntrack_tuple *tuple,
+static void unknown_unique_tuple(struct nf_conntrack_tuple *tuple,
const struct nf_nat_range *range,
enum nf_nat_manip_type maniptype,
const struct nf_conn *ct)
{
/* Sorry: we can't help you; if it's not unique, we can't frob
anything. */
- return false;
+ return;
}
static bool
diff --git a/net/ipv4/netfilter/nf_nat_rule.c b/net/ipv4/netfilter/nf_nat_rule.c
index 98ed78281ae..ebbd319f62f 100644
--- a/net/ipv4/netfilter/nf_nat_rule.c
+++ b/net/ipv4/netfilter/nf_nat_rule.c
@@ -28,7 +28,8 @@
#define NAT_VALID_HOOKS ((1 << NF_INET_PRE_ROUTING) | \
(1 << NF_INET_POST_ROUTING) | \
- (1 << NF_INET_LOCAL_OUT))
+ (1 << NF_INET_LOCAL_OUT) | \
+ (1 << NF_INET_LOCAL_IN))
static const struct xt_table nat_table = {
.name = "nat",
@@ -45,7 +46,8 @@ ipt_snat_target(struct sk_buff *skb, const struct xt_action_param *par)
enum ip_conntrack_info ctinfo;
const struct nf_nat_multi_range_compat *mr = par->targinfo;
- NF_CT_ASSERT(par->hooknum == NF_INET_POST_ROUTING);
+ NF_CT_ASSERT(par->hooknum == NF_INET_POST_ROUTING ||
+ par->hooknum == NF_INET_LOCAL_IN);
ct = nf_ct_get(skb, &ctinfo);
@@ -99,7 +101,7 @@ static int ipt_dnat_checkentry(const struct xt_tgchk_param *par)
return 0;
}
-unsigned int
+static unsigned int
alloc_null_binding(struct nf_conn *ct, unsigned int hooknum)
{
/* Force range to this IP; let proto decide mapping for
@@ -141,7 +143,7 @@ static struct xt_target ipt_snat_reg __read_mostly = {
.target = ipt_snat_target,
.targetsize = sizeof(struct nf_nat_multi_range_compat),
.table = "nat",
- .hooks = 1 << NF_INET_POST_ROUTING,
+ .hooks = (1 << NF_INET_POST_ROUTING) | (1 << NF_INET_LOCAL_IN),
.checkentry = ipt_snat_checkentry,
.family = AF_INET,
};
diff --git a/net/ipv4/netfilter/nf_nat_standalone.c b/net/ipv4/netfilter/nf_nat_standalone.c
index beb25819c9c..95481fee8bd 100644
--- a/net/ipv4/netfilter/nf_nat_standalone.c
+++ b/net/ipv4/netfilter/nf_nat_standalone.c
@@ -98,7 +98,7 @@ nf_nat_fn(unsigned int hooknum,
return NF_ACCEPT;
/* Don't try to NAT if this packet is not conntracked */
- if (ct == &nf_conntrack_untracked)
+ if (nf_ct_is_untracked(ct))
return NF_ACCEPT;
nat = nfct_nat(ct);
@@ -131,13 +131,7 @@ nf_nat_fn(unsigned int hooknum,
if (!nf_nat_initialized(ct, maniptype)) {
unsigned int ret;
- if (hooknum == NF_INET_LOCAL_IN)
- /* LOCAL_IN hook doesn't have a chain! */
- ret = alloc_null_binding(ct, hooknum);
- else
- ret = nf_nat_rule_find(skb, hooknum, in, out,
- ct);
-
+ ret = nf_nat_rule_find(skb, hooknum, in, out, ct);
if (ret != NF_ACCEPT)
return ret;
} else
diff --git a/net/ipv4/proc.c b/net/ipv4/proc.c
index 3dc9914c1dc..4ae1f203f7c 100644
--- a/net/ipv4/proc.c
+++ b/net/ipv4/proc.c
@@ -252,6 +252,7 @@ static const struct snmp_mib snmp4_net_list[] = {
SNMP_MIB_ITEM("TCPBacklogDrop", LINUX_MIB_TCPBACKLOGDROP),
SNMP_MIB_ITEM("TCPMinTTLDrop", LINUX_MIB_TCPMINTTLDROP),
SNMP_MIB_ITEM("TCPDeferAcceptDrop", LINUX_MIB_TCPDEFERACCEPTDROP),
+ SNMP_MIB_ITEM("IPReversePathFilter", LINUX_MIB_IPRPFILTER),
SNMP_MIB_SENTINEL
};
@@ -342,10 +343,12 @@ static int snmp_seq_show(struct seq_file *seq, void *v)
IPV4_DEVCONF_ALL(net, FORWARDING) ? 1 : 2,
sysctl_ip_default_ttl);
+ BUILD_BUG_ON(offsetof(struct ipstats_mib, mibs) != 0);
for (i = 0; snmp4_ipstats_list[i].name != NULL; i++)
- seq_printf(seq, " %lu",
- snmp_fold_field((void __percpu **)net->mib.ip_statistics,
- snmp4_ipstats_list[i].entry));
+ seq_printf(seq, " %llu",
+ snmp_fold_field64((void __percpu **)net->mib.ip_statistics,
+ snmp4_ipstats_list[i].entry,
+ offsetof(struct ipstats_mib, syncp)));
icmp_put(seq); /* RFC 2011 compatibility */
icmpmsg_put(seq);
@@ -431,9 +434,10 @@ static int netstat_seq_show(struct seq_file *seq, void *v)
seq_puts(seq, "\nIpExt:");
for (i = 0; snmp4_ipextstats_list[i].name != NULL; i++)
- seq_printf(seq, " %lu",
- snmp_fold_field((void __percpu **)net->mib.ip_statistics,
- snmp4_ipextstats_list[i].entry));
+ seq_printf(seq, " %llu",
+ snmp_fold_field64((void __percpu **)net->mib.ip_statistics,
+ snmp4_ipextstats_list[i].entry,
+ offsetof(struct ipstats_mib, syncp)));
seq_putc(seq, '\n');
return 0;
diff --git a/net/ipv4/protocol.c b/net/ipv4/protocol.c
index 542f22fc98b..f2d29735140 100644
--- a/net/ipv4/protocol.c
+++ b/net/ipv4/protocol.c
@@ -52,6 +52,7 @@ int inet_add_protocol(const struct net_protocol *prot, unsigned char protocol)
return ret;
}
+EXPORT_SYMBOL(inet_add_protocol);
/*
* Remove a protocol from the hash tables.
@@ -76,6 +77,4 @@ int inet_del_protocol(const struct net_protocol *prot, unsigned char protocol)
return ret;
}
-
-EXPORT_SYMBOL(inet_add_protocol);
EXPORT_SYMBOL(inet_del_protocol);
diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c
index 2c7a1639388..009a7b2aa1e 100644
--- a/net/ipv4/raw.c
+++ b/net/ipv4/raw.c
@@ -314,7 +314,7 @@ int raw_rcv(struct sock *sk, struct sk_buff *skb)
}
static int raw_send_hdrinc(struct sock *sk, void *from, size_t length,
- struct rtable *rt,
+ struct rtable **rtp,
unsigned int flags)
{
struct inet_sock *inet = inet_sk(sk);
@@ -323,25 +323,27 @@ static int raw_send_hdrinc(struct sock *sk, void *from, size_t length,
struct sk_buff *skb;
unsigned int iphlen;
int err;
+ struct rtable *rt = *rtp;
- if (length > rt->u.dst.dev->mtu) {
+ if (length > rt->dst.dev->mtu) {
ip_local_error(sk, EMSGSIZE, rt->rt_dst, inet->inet_dport,
- rt->u.dst.dev->mtu);
+ rt->dst.dev->mtu);
return -EMSGSIZE;
}
if (flags&MSG_PROBE)
goto out;
skb = sock_alloc_send_skb(sk,
- length + LL_ALLOCATED_SPACE(rt->u.dst.dev) + 15,
+ length + LL_ALLOCATED_SPACE(rt->dst.dev) + 15,
flags & MSG_DONTWAIT, &err);
if (skb == NULL)
goto error;
- skb_reserve(skb, LL_RESERVED_SPACE(rt->u.dst.dev));
+ skb_reserve(skb, LL_RESERVED_SPACE(rt->dst.dev));
skb->priority = sk->sk_priority;
skb->mark = sk->sk_mark;
- skb_dst_set(skb, dst_clone(&rt->u.dst));
+ skb_dst_set(skb, &rt->dst);
+ *rtp = NULL;
skb_reset_network_header(skb);
iph = ip_hdr(skb);
@@ -373,7 +375,7 @@ static int raw_send_hdrinc(struct sock *sk, void *from, size_t length,
iph->check = 0;
iph->tot_len = htons(length);
if (!iph->id)
- ip_select_ident(iph, &rt->u.dst, NULL);
+ ip_select_ident(iph, &rt->dst, NULL);
iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl);
}
@@ -382,7 +384,7 @@ static int raw_send_hdrinc(struct sock *sk, void *from, size_t length,
skb_transport_header(skb))->type);
err = NF_HOOK(NFPROTO_IPV4, NF_INET_LOCAL_OUT, skb, NULL,
- rt->u.dst.dev, dst_output);
+ rt->dst.dev, dst_output);
if (err > 0)
err = net_xmit_errno(err);
if (err)
@@ -576,7 +578,7 @@ back_from_confirm:
if (inet->hdrincl)
err = raw_send_hdrinc(sk, msg->msg_iov, len,
- rt, msg->msg_flags);
+ &rt, msg->msg_flags);
else {
if (!ipc.addr)
@@ -604,7 +606,7 @@ out:
return len;
do_confirm:
- dst_confirm(&rt->u.dst);
+ dst_confirm(&rt->dst);
if (!(msg->msg_flags & MSG_PROBE) || len)
goto back_from_confirm;
err = 0;
diff --git a/net/ipv4/route.c b/net/ipv4/route.c
index 560acc677ce..3f56b6e6c6a 100644
--- a/net/ipv4/route.c
+++ b/net/ipv4/route.c
@@ -253,8 +253,7 @@ static unsigned rt_hash_mask __read_mostly;
static unsigned int rt_hash_log __read_mostly;
static DEFINE_PER_CPU(struct rt_cache_stat, rt_cache_stat);
-#define RT_CACHE_STAT_INC(field) \
- (__raw_get_cpu_var(rt_cache_stat).field++)
+#define RT_CACHE_STAT_INC(field) __this_cpu_inc(rt_cache_stat.field)
static inline unsigned int rt_hash(__be32 daddr, __be32 saddr, int idx,
int genid)
@@ -287,10 +286,10 @@ static struct rtable *rt_cache_get_first(struct seq_file *seq)
rcu_read_lock_bh();
r = rcu_dereference_bh(rt_hash_table[st->bucket].chain);
while (r) {
- if (dev_net(r->u.dst.dev) == seq_file_net(seq) &&
+ if (dev_net(r->dst.dev) == seq_file_net(seq) &&
r->rt_genid == st->genid)
return r;
- r = rcu_dereference_bh(r->u.dst.rt_next);
+ r = rcu_dereference_bh(r->dst.rt_next);
}
rcu_read_unlock_bh();
}
@@ -302,7 +301,7 @@ static struct rtable *__rt_cache_get_next(struct seq_file *seq,
{
struct rt_cache_iter_state *st = seq->private;
- r = r->u.dst.rt_next;
+ r = r->dst.rt_next;
while (!r) {
rcu_read_unlock_bh();
do {
@@ -320,7 +319,7 @@ static struct rtable *rt_cache_get_next(struct seq_file *seq,
{
struct rt_cache_iter_state *st = seq->private;
while ((r = __rt_cache_get_next(seq, r)) != NULL) {
- if (dev_net(r->u.dst.dev) != seq_file_net(seq))
+ if (dev_net(r->dst.dev) != seq_file_net(seq))
continue;
if (r->rt_genid == st->genid)
break;
@@ -378,19 +377,19 @@ static int rt_cache_seq_show(struct seq_file *seq, void *v)
seq_printf(seq, "%s\t%08X\t%08X\t%8X\t%d\t%u\t%d\t"
"%08X\t%d\t%u\t%u\t%02X\t%d\t%1d\t%08X%n",
- r->u.dst.dev ? r->u.dst.dev->name : "*",
+ r->dst.dev ? r->dst.dev->name : "*",
(__force u32)r->rt_dst,
(__force u32)r->rt_gateway,
- r->rt_flags, atomic_read(&r->u.dst.__refcnt),
- r->u.dst.__use, 0, (__force u32)r->rt_src,
- (dst_metric(&r->u.dst, RTAX_ADVMSS) ?
- (int)dst_metric(&r->u.dst, RTAX_ADVMSS) + 40 : 0),
- dst_metric(&r->u.dst, RTAX_WINDOW),
- (int)((dst_metric(&r->u.dst, RTAX_RTT) >> 3) +
- dst_metric(&r->u.dst, RTAX_RTTVAR)),
+ r->rt_flags, atomic_read(&r->dst.__refcnt),
+ r->dst.__use, 0, (__force u32)r->rt_src,
+ (dst_metric(&r->dst, RTAX_ADVMSS) ?
+ (int)dst_metric(&r->dst, RTAX_ADVMSS) + 40 : 0),
+ dst_metric(&r->dst, RTAX_WINDOW),
+ (int)((dst_metric(&r->dst, RTAX_RTT) >> 3) +
+ dst_metric(&r->dst, RTAX_RTTVAR)),
r->fl.fl4_tos,
- r->u.dst.hh ? atomic_read(&r->u.dst.hh->hh_refcnt) : -1,
- r->u.dst.hh ? (r->u.dst.hh->hh_output ==
+ r->dst.hh ? atomic_read(&r->dst.hh->hh_refcnt) : -1,
+ r->dst.hh ? (r->dst.hh->hh_output ==
dev_queue_xmit) : 0,
r->rt_spec_dst, &len);
@@ -609,13 +608,13 @@ static inline int ip_rt_proc_init(void)
static inline void rt_free(struct rtable *rt)
{
- call_rcu_bh(&rt->u.dst.rcu_head, dst_rcu_free);
+ call_rcu_bh(&rt->dst.rcu_head, dst_rcu_free);
}
static inline void rt_drop(struct rtable *rt)
{
ip_rt_put(rt);
- call_rcu_bh(&rt->u.dst.rcu_head, dst_rcu_free);
+ call_rcu_bh(&rt->dst.rcu_head, dst_rcu_free);
}
static inline int rt_fast_clean(struct rtable *rth)
@@ -623,13 +622,13 @@ static inline int rt_fast_clean(struct rtable *rth)
/* Kill broadcast/multicast entries very aggresively, if they
collide in hash table with more useful entries */
return (rth->rt_flags & (RTCF_BROADCAST | RTCF_MULTICAST)) &&
- rth->fl.iif && rth->u.dst.rt_next;
+ rth->fl.iif && rth->dst.rt_next;
}
static inline int rt_valuable(struct rtable *rth)
{
return (rth->rt_flags & (RTCF_REDIRECTED | RTCF_NOTIFY)) ||
- rth->u.dst.expires;
+ rth->dst.expires;
}
static int rt_may_expire(struct rtable *rth, unsigned long tmo1, unsigned long tmo2)
@@ -637,15 +636,15 @@ static int rt_may_expire(struct rtable *rth, unsigned long tmo1, unsigned long t
unsigned long age;
int ret = 0;
- if (atomic_read(&rth->u.dst.__refcnt))
+ if (atomic_read(&rth->dst.__refcnt))
goto out;
ret = 1;
- if (rth->u.dst.expires &&
- time_after_eq(jiffies, rth->u.dst.expires))
+ if (rth->dst.expires &&
+ time_after_eq(jiffies, rth->dst.expires))
goto out;
- age = jiffies - rth->u.dst.lastuse;
+ age = jiffies - rth->dst.lastuse;
ret = 0;
if ((age <= tmo1 && !rt_fast_clean(rth)) ||
(age <= tmo2 && rt_valuable(rth)))
@@ -661,7 +660,7 @@ out: return ret;
*/
static inline u32 rt_score(struct rtable *rt)
{
- u32 score = jiffies - rt->u.dst.lastuse;
+ u32 score = jiffies - rt->dst.lastuse;
score = ~score & ~(3<<30);
@@ -701,12 +700,12 @@ static inline int compare_keys(struct flowi *fl1, struct flowi *fl2)
static inline int compare_netns(struct rtable *rt1, struct rtable *rt2)
{
- return net_eq(dev_net(rt1->u.dst.dev), dev_net(rt2->u.dst.dev));
+ return net_eq(dev_net(rt1->dst.dev), dev_net(rt2->dst.dev));
}
static inline int rt_is_expired(struct rtable *rth)
{
- return rth->rt_genid != rt_genid(dev_net(rth->u.dst.dev));
+ return rth->rt_genid != rt_genid(dev_net(rth->dst.dev));
}
/*
@@ -735,7 +734,7 @@ static void rt_do_flush(int process_context)
rth = rt_hash_table[i].chain;
/* defer releasing the head of the list after spin_unlock */
- for (tail = rth; tail; tail = tail->u.dst.rt_next)
+ for (tail = rth; tail; tail = tail->dst.rt_next)
if (!rt_is_expired(tail))
break;
if (rth != tail)
@@ -744,9 +743,9 @@ static void rt_do_flush(int process_context)
/* call rt_free on entries after the tail requiring flush */
prev = &rt_hash_table[i].chain;
for (p = *prev; p; p = next) {
- next = p->u.dst.rt_next;
+ next = p->dst.rt_next;
if (!rt_is_expired(p)) {
- prev = &p->u.dst.rt_next;
+ prev = &p->dst.rt_next;
} else {
*prev = next;
rt_free(p);
@@ -761,7 +760,7 @@ static void rt_do_flush(int process_context)
spin_unlock_bh(rt_hash_lock_addr(i));
for (; rth != tail; rth = next) {
- next = rth->u.dst.rt_next;
+ next = rth->dst.rt_next;
rt_free(rth);
}
}
@@ -792,7 +791,7 @@ static int has_noalias(const struct rtable *head, const struct rtable *rth)
while (aux != rth) {
if (compare_hash_inputs(&aux->fl, &rth->fl))
return 0;
- aux = aux->u.dst.rt_next;
+ aux = aux->dst.rt_next;
}
return ONE;
}
@@ -832,18 +831,18 @@ static void rt_check_expire(void)
length = 0;
spin_lock_bh(rt_hash_lock_addr(i));
while ((rth = *rthp) != NULL) {
- prefetch(rth->u.dst.rt_next);
+ prefetch(rth->dst.rt_next);
if (rt_is_expired(rth)) {
- *rthp = rth->u.dst.rt_next;
+ *rthp = rth->dst.rt_next;
rt_free(rth);
continue;
}
- if (rth->u.dst.expires) {
+ if (rth->dst.expires) {
/* Entry is expired even if it is in use */
- if (time_before_eq(jiffies, rth->u.dst.expires)) {
+ if (time_before_eq(jiffies, rth->dst.expires)) {
nofree:
tmo >>= 1;
- rthp = &rth->u.dst.rt_next;
+ rthp = &rth->dst.rt_next;
/*
* We only count entries on
* a chain with equal hash inputs once
@@ -859,7 +858,7 @@ nofree:
goto nofree;
/* Cleanup aged off entries. */
- *rthp = rth->u.dst.rt_next;
+ *rthp = rth->dst.rt_next;
rt_free(rth);
}
spin_unlock_bh(rt_hash_lock_addr(i));
@@ -1000,10 +999,10 @@ static int rt_garbage_collect(struct dst_ops *ops)
if (!rt_is_expired(rth) &&
!rt_may_expire(rth, tmo, expire)) {
tmo >>= 1;
- rthp = &rth->u.dst.rt_next;
+ rthp = &rth->dst.rt_next;
continue;
}
- *rthp = rth->u.dst.rt_next;
+ *rthp = rth->dst.rt_next;
rt_free(rth);
goal--;
}
@@ -1069,7 +1068,7 @@ static int slow_chain_length(const struct rtable *head)
while (rth) {
length += has_noalias(head, rth);
- rth = rth->u.dst.rt_next;
+ rth = rth->dst.rt_next;
}
return length >> FRACT_BITS;
}
@@ -1091,7 +1090,7 @@ restart:
candp = NULL;
now = jiffies;
- if (!rt_caching(dev_net(rt->u.dst.dev))) {
+ if (!rt_caching(dev_net(rt->dst.dev))) {
/*
* If we're not caching, just tell the caller we
* were successful and don't touch the route. The
@@ -1109,7 +1108,7 @@ restart:
*/
if (rt->rt_type == RTN_UNICAST || rt->fl.iif == 0) {
- int err = arp_bind_neighbour(&rt->u.dst);
+ int err = arp_bind_neighbour(&rt->dst);
if (err) {
if (net_ratelimit())
printk(KERN_WARNING
@@ -1128,19 +1127,19 @@ restart:
spin_lock_bh(rt_hash_lock_addr(hash));
while ((rth = *rthp) != NULL) {
if (rt_is_expired(rth)) {
- *rthp = rth->u.dst.rt_next;
+ *rthp = rth->dst.rt_next;
rt_free(rth);
continue;
}
if (compare_keys(&rth->fl, &rt->fl) && compare_netns(rth, rt)) {
/* Put it first */
- *rthp = rth->u.dst.rt_next;
+ *rthp = rth->dst.rt_next;
/*
* Since lookup is lockfree, the deletion
* must be visible to another weakly ordered CPU before
* the insertion at the start of the hash chain.
*/
- rcu_assign_pointer(rth->u.dst.rt_next,
+ rcu_assign_pointer(rth->dst.rt_next,
rt_hash_table[hash].chain);
/*
* Since lookup is lockfree, the update writes
@@ -1148,18 +1147,18 @@ restart:
*/
rcu_assign_pointer(rt_hash_table[hash].chain, rth);
- dst_use(&rth->u.dst, now);
+ dst_use(&rth->dst, now);
spin_unlock_bh(rt_hash_lock_addr(hash));
rt_drop(rt);
if (rp)
*rp = rth;
else
- skb_dst_set(skb, &rth->u.dst);
+ skb_dst_set(skb, &rth->dst);
return 0;
}
- if (!atomic_read(&rth->u.dst.__refcnt)) {
+ if (!atomic_read(&rth->dst.__refcnt)) {
u32 score = rt_score(rth);
if (score <= min_score) {
@@ -1171,7 +1170,7 @@ restart:
chain_length++;
- rthp = &rth->u.dst.rt_next;
+ rthp = &rth->dst.rt_next;
}
if (cand) {
@@ -1182,17 +1181,17 @@ restart:
* only 2 entries per bucket. We will see.
*/
if (chain_length > ip_rt_gc_elasticity) {
- *candp = cand->u.dst.rt_next;
+ *candp = cand->dst.rt_next;
rt_free(cand);
}
} else {
if (chain_length > rt_chain_length_max &&
slow_chain_length(rt_hash_table[hash].chain) > rt_chain_length_max) {
- struct net *net = dev_net(rt->u.dst.dev);
+ struct net *net = dev_net(rt->dst.dev);
int num = ++net->ipv4.current_rt_cache_rebuild_count;
if (!rt_caching(net)) {
printk(KERN_WARNING "%s: %d rebuilds is over limit, route caching disabled\n",
- rt->u.dst.dev->name, num);
+ rt->dst.dev->name, num);
}
rt_emergency_hash_rebuild(net);
spin_unlock_bh(rt_hash_lock_addr(hash));
@@ -1207,7 +1206,7 @@ restart:
route or unicast forwarding path.
*/
if (rt->rt_type == RTN_UNICAST || rt->fl.iif == 0) {
- int err = arp_bind_neighbour(&rt->u.dst);
+ int err = arp_bind_neighbour(&rt->dst);
if (err) {
spin_unlock_bh(rt_hash_lock_addr(hash));
@@ -1238,14 +1237,14 @@ restart:
}
}
- rt->u.dst.rt_next = rt_hash_table[hash].chain;
+ rt->dst.rt_next = rt_hash_table[hash].chain;
#if RT_CACHE_DEBUG >= 2
- if (rt->u.dst.rt_next) {
+ if (rt->dst.rt_next) {
struct rtable *trt;
printk(KERN_DEBUG "rt_cache @%02x: %pI4",
hash, &rt->rt_dst);
- for (trt = rt->u.dst.rt_next; trt; trt = trt->u.dst.rt_next)
+ for (trt = rt->dst.rt_next; trt; trt = trt->dst.rt_next)
printk(" . %pI4", &trt->rt_dst);
printk("\n");
}
@@ -1263,7 +1262,7 @@ skip_hashing:
if (rp)
*rp = rt;
else
- skb_dst_set(skb, &rt->u.dst);
+ skb_dst_set(skb, &rt->dst);
return 0;
}
@@ -1325,6 +1324,7 @@ void __ip_select_ident(struct iphdr *iph, struct dst_entry *dst, int more)
ip_select_fb_ident(iph);
}
+EXPORT_SYMBOL(__ip_select_ident);
static void rt_del(unsigned hash, struct rtable *rt)
{
@@ -1335,20 +1335,21 @@ static void rt_del(unsigned hash, struct rtable *rt)
ip_rt_put(rt);
while ((aux = *rthp) != NULL) {
if (aux == rt || rt_is_expired(aux)) {
- *rthp = aux->u.dst.rt_next;
+ *rthp = aux->dst.rt_next;
rt_free(aux);
continue;
}
- rthp = &aux->u.dst.rt_next;
+ rthp = &aux->dst.rt_next;
}
spin_unlock_bh(rt_hash_lock_addr(hash));
}
+/* called in rcu_read_lock() section */
void ip_rt_redirect(__be32 old_gw, __be32 daddr, __be32 new_gw,
__be32 saddr, struct net_device *dev)
{
int i, k;
- struct in_device *in_dev = in_dev_get(dev);
+ struct in_device *in_dev = __in_dev_get_rcu(dev);
struct rtable *rth, **rthp;
__be32 skeys[2] = { saddr, 0 };
int ikeys[2] = { dev->ifindex, 0 };
@@ -1384,7 +1385,6 @@ void ip_rt_redirect(__be32 old_gw, __be32 daddr, __be32 new_gw,
rthp=&rt_hash_table[hash].chain;
- rcu_read_lock();
while ((rth = rcu_dereference(*rthp)) != NULL) {
struct rtable *rt;
@@ -1393,44 +1393,42 @@ void ip_rt_redirect(__be32 old_gw, __be32 daddr, __be32 new_gw,
rth->fl.oif != ikeys[k] ||
rth->fl.iif != 0 ||
rt_is_expired(rth) ||
- !net_eq(dev_net(rth->u.dst.dev), net)) {
- rthp = &rth->u.dst.rt_next;
+ !net_eq(dev_net(rth->dst.dev), net)) {
+ rthp = &rth->dst.rt_next;
continue;
}
if (rth->rt_dst != daddr ||
rth->rt_src != saddr ||
- rth->u.dst.error ||
+ rth->dst.error ||
rth->rt_gateway != old_gw ||
- rth->u.dst.dev != dev)
+ rth->dst.dev != dev)
break;
- dst_hold(&rth->u.dst);
- rcu_read_unlock();
+ dst_hold(&rth->dst);
rt = dst_alloc(&ipv4_dst_ops);
if (rt == NULL) {
ip_rt_put(rth);
- in_dev_put(in_dev);
return;
}
/* Copy all the information. */
*rt = *rth;
- rt->u.dst.__use = 1;
- atomic_set(&rt->u.dst.__refcnt, 1);
- rt->u.dst.child = NULL;
- if (rt->u.dst.dev)
- dev_hold(rt->u.dst.dev);
+ rt->dst.__use = 1;
+ atomic_set(&rt->dst.__refcnt, 1);
+ rt->dst.child = NULL;
+ if (rt->dst.dev)
+ dev_hold(rt->dst.dev);
if (rt->idev)
in_dev_hold(rt->idev);
- rt->u.dst.obsolete = -1;
- rt->u.dst.lastuse = jiffies;
- rt->u.dst.path = &rt->u.dst;
- rt->u.dst.neighbour = NULL;
- rt->u.dst.hh = NULL;
+ rt->dst.obsolete = -1;
+ rt->dst.lastuse = jiffies;
+ rt->dst.path = &rt->dst;
+ rt->dst.neighbour = NULL;
+ rt->dst.hh = NULL;
#ifdef CONFIG_XFRM
- rt->u.dst.xfrm = NULL;
+ rt->dst.xfrm = NULL;
#endif
rt->rt_genid = rt_genid(net);
rt->rt_flags |= RTCF_REDIRECTED;
@@ -1439,23 +1437,23 @@ void ip_rt_redirect(__be32 old_gw, __be32 daddr, __be32 new_gw,
rt->rt_gateway = new_gw;
/* Redirect received -> path was valid */
- dst_confirm(&rth->u.dst);
+ dst_confirm(&rth->dst);
if (rt->peer)
atomic_inc(&rt->peer->refcnt);
- if (arp_bind_neighbour(&rt->u.dst) ||
- !(rt->u.dst.neighbour->nud_state &
+ if (arp_bind_neighbour(&rt->dst) ||
+ !(rt->dst.neighbour->nud_state &
NUD_VALID)) {
- if (rt->u.dst.neighbour)
- neigh_event_send(rt->u.dst.neighbour, NULL);
+ if (rt->dst.neighbour)
+ neigh_event_send(rt->dst.neighbour, NULL);
ip_rt_put(rth);
rt_drop(rt);
goto do_next;
}
- netevent.old = &rth->u.dst;
- netevent.new = &rt->u.dst;
+ netevent.old = &rth->dst;
+ netevent.new = &rt->dst;
call_netevent_notifiers(NETEVENT_REDIRECT,
&netevent);
@@ -1464,12 +1462,10 @@ void ip_rt_redirect(__be32 old_gw, __be32 daddr, __be32 new_gw,
ip_rt_put(rt);
goto do_next;
}
- rcu_read_unlock();
do_next:
;
}
}
- in_dev_put(in_dev);
return;
reject_redirect:
@@ -1480,7 +1476,7 @@ reject_redirect:
&old_gw, dev->name, &new_gw,
&saddr, &daddr);
#endif
- in_dev_put(in_dev);
+ ;
}
static struct dst_entry *ipv4_negative_advice(struct dst_entry *dst)
@@ -1493,8 +1489,8 @@ static struct dst_entry *ipv4_negative_advice(struct dst_entry *dst)
ip_rt_put(rt);
ret = NULL;
} else if ((rt->rt_flags & RTCF_REDIRECTED) ||
- (rt->u.dst.expires &&
- time_after_eq(jiffies, rt->u.dst.expires))) {
+ (rt->dst.expires &&
+ time_after_eq(jiffies, rt->dst.expires))) {
unsigned hash = rt_hash(rt->fl.fl4_dst, rt->fl.fl4_src,
rt->fl.oif,
rt_genid(dev_net(dst->dev)));
@@ -1532,7 +1528,7 @@ void ip_rt_send_redirect(struct sk_buff *skb)
int log_martians;
rcu_read_lock();
- in_dev = __in_dev_get_rcu(rt->u.dst.dev);
+ in_dev = __in_dev_get_rcu(rt->dst.dev);
if (!in_dev || !IN_DEV_TX_REDIRECTS(in_dev)) {
rcu_read_unlock();
return;
@@ -1543,30 +1539,30 @@ void ip_rt_send_redirect(struct sk_buff *skb)
/* No redirected packets during ip_rt_redirect_silence;
* reset the algorithm.
*/
- if (time_after(jiffies, rt->u.dst.rate_last + ip_rt_redirect_silence))
- rt->u.dst.rate_tokens = 0;
+ if (time_after(jiffies, rt->dst.rate_last + ip_rt_redirect_silence))
+ rt->dst.rate_tokens = 0;
/* Too many ignored redirects; do not send anything
- * set u.dst.rate_last to the last seen redirected packet.
+ * set dst.rate_last to the last seen redirected packet.
*/
- if (rt->u.dst.rate_tokens >= ip_rt_redirect_number) {
- rt->u.dst.rate_last = jiffies;
+ if (rt->dst.rate_tokens >= ip_rt_redirect_number) {
+ rt->dst.rate_last = jiffies;
return;
}
/* Check for load limit; set rate_last to the latest sent
* redirect.
*/
- if (rt->u.dst.rate_tokens == 0 ||
+ if (rt->dst.rate_tokens == 0 ||
time_after(jiffies,
- (rt->u.dst.rate_last +
- (ip_rt_redirect_load << rt->u.dst.rate_tokens)))) {
+ (rt->dst.rate_last +
+ (ip_rt_redirect_load << rt->dst.rate_tokens)))) {
icmp_send(skb, ICMP_REDIRECT, ICMP_REDIR_HOST, rt->rt_gateway);
- rt->u.dst.rate_last = jiffies;
- ++rt->u.dst.rate_tokens;
+ rt->dst.rate_last = jiffies;
+ ++rt->dst.rate_tokens;
#ifdef CONFIG_IP_ROUTE_VERBOSE
if (log_martians &&
- rt->u.dst.rate_tokens == ip_rt_redirect_number &&
+ rt->dst.rate_tokens == ip_rt_redirect_number &&
net_ratelimit())
printk(KERN_WARNING "host %pI4/if%d ignores redirects for %pI4 to %pI4.\n",
&rt->rt_src, rt->rt_iif,
@@ -1581,7 +1577,7 @@ static int ip_error(struct sk_buff *skb)
unsigned long now;
int code;
- switch (rt->u.dst.error) {
+ switch (rt->dst.error) {
case EINVAL:
default:
goto out;
@@ -1590,7 +1586,7 @@ static int ip_error(struct sk_buff *skb)
break;
case ENETUNREACH:
code = ICMP_NET_UNREACH;
- IP_INC_STATS_BH(dev_net(rt->u.dst.dev),
+ IP_INC_STATS_BH(dev_net(rt->dst.dev),
IPSTATS_MIB_INNOROUTES);
break;
case EACCES:
@@ -1599,12 +1595,12 @@ static int ip_error(struct sk_buff *skb)
}
now = jiffies;
- rt->u.dst.rate_tokens += now - rt->u.dst.rate_last;
- if (rt->u.dst.rate_tokens > ip_rt_error_burst)
- rt->u.dst.rate_tokens = ip_rt_error_burst;
- rt->u.dst.rate_last = now;
- if (rt->u.dst.rate_tokens >= ip_rt_error_cost) {
- rt->u.dst.rate_tokens -= ip_rt_error_cost;
+ rt->dst.rate_tokens += now - rt->dst.rate_last;
+ if (rt->dst.rate_tokens > ip_rt_error_burst)
+ rt->dst.rate_tokens = ip_rt_error_burst;
+ rt->dst.rate_last = now;
+ if (rt->dst.rate_tokens >= ip_rt_error_cost) {
+ rt->dst.rate_tokens -= ip_rt_error_cost;
icmp_send(skb, ICMP_DEST_UNREACH, code, 0);
}
@@ -1649,7 +1645,7 @@ unsigned short ip_rt_frag_needed(struct net *net, struct iphdr *iph,
rcu_read_lock();
for (rth = rcu_dereference(rt_hash_table[hash].chain); rth;
- rth = rcu_dereference(rth->u.dst.rt_next)) {
+ rth = rcu_dereference(rth->dst.rt_next)) {
unsigned short mtu = new_mtu;
if (rth->fl.fl4_dst != daddr ||
@@ -1658,8 +1654,8 @@ unsigned short ip_rt_frag_needed(struct net *net, struct iphdr *iph,
rth->rt_src != iph->saddr ||
rth->fl.oif != ikeys[k] ||
rth->fl.iif != 0 ||
- dst_metric_locked(&rth->u.dst, RTAX_MTU) ||
- !net_eq(dev_net(rth->u.dst.dev), net) ||
+ dst_metric_locked(&rth->dst, RTAX_MTU) ||
+ !net_eq(dev_net(rth->dst.dev), net) ||
rt_is_expired(rth))
continue;
@@ -1667,22 +1663,22 @@ unsigned short ip_rt_frag_needed(struct net *net, struct iphdr *iph,
/* BSD 4.2 compatibility hack :-( */
if (mtu == 0 &&
- old_mtu >= dst_mtu(&rth->u.dst) &&
+ old_mtu >= dst_mtu(&rth->dst) &&
old_mtu >= 68 + (iph->ihl << 2))
old_mtu -= iph->ihl << 2;
mtu = guess_mtu(old_mtu);
}
- if (mtu <= dst_mtu(&rth->u.dst)) {
- if (mtu < dst_mtu(&rth->u.dst)) {
- dst_confirm(&rth->u.dst);
+ if (mtu <= dst_mtu(&rth->dst)) {
+ if (mtu < dst_mtu(&rth->dst)) {
+ dst_confirm(&rth->dst);
if (mtu < ip_rt_min_pmtu) {
mtu = ip_rt_min_pmtu;
- rth->u.dst.metrics[RTAX_LOCK-1] |=
+ rth->dst.metrics[RTAX_LOCK-1] |=
(1 << RTAX_MTU);
}
- rth->u.dst.metrics[RTAX_MTU-1] = mtu;
- dst_set_expires(&rth->u.dst,
+ rth->dst.metrics[RTAX_MTU-1] = mtu;
+ dst_set_expires(&rth->dst,
ip_rt_mtu_expires);
}
est_mtu = mtu;
@@ -1755,7 +1751,7 @@ static void ipv4_link_failure(struct sk_buff *skb)
rt = skb_rtable(skb);
if (rt)
- dst_set_expires(&rt->u.dst, 0);
+ dst_set_expires(&rt->dst, 0);
}
static int ip_rt_bug(struct sk_buff *skb)
@@ -1783,11 +1779,11 @@ void ip_rt_get_source(u8 *addr, struct rtable *rt)
if (rt->fl.iif == 0)
src = rt->rt_src;
- else if (fib_lookup(dev_net(rt->u.dst.dev), &rt->fl, &res) == 0) {
+ else if (fib_lookup(dev_net(rt->dst.dev), &rt->fl, &res) == 0) {
src = FIB_RES_PREFSRC(res);
fib_res_put(&res);
} else
- src = inet_select_addr(rt->u.dst.dev, rt->rt_gateway,
+ src = inet_select_addr(rt->dst.dev, rt->rt_gateway,
RT_SCOPE_UNIVERSE);
memcpy(addr, &src, 4);
}
@@ -1795,10 +1791,10 @@ void ip_rt_get_source(u8 *addr, struct rtable *rt)
#ifdef CONFIG_NET_CLS_ROUTE
static void set_class_tag(struct rtable *rt, u32 tag)
{
- if (!(rt->u.dst.tclassid & 0xFFFF))
- rt->u.dst.tclassid |= tag & 0xFFFF;
- if (!(rt->u.dst.tclassid & 0xFFFF0000))
- rt->u.dst.tclassid |= tag & 0xFFFF0000;
+ if (!(rt->dst.tclassid & 0xFFFF))
+ rt->dst.tclassid |= tag & 0xFFFF;
+ if (!(rt->dst.tclassid & 0xFFFF0000))
+ rt->dst.tclassid |= tag & 0xFFFF0000;
}
#endif
@@ -1810,30 +1806,30 @@ static void rt_set_nexthop(struct rtable *rt, struct fib_result *res, u32 itag)
if (FIB_RES_GW(*res) &&
FIB_RES_NH(*res).nh_scope == RT_SCOPE_LINK)
rt->rt_gateway = FIB_RES_GW(*res);
- memcpy(rt->u.dst.metrics, fi->fib_metrics,
- sizeof(rt->u.dst.metrics));
+ memcpy(rt->dst.metrics, fi->fib_metrics,
+ sizeof(rt->dst.metrics));
if (fi->fib_mtu == 0) {
- rt->u.dst.metrics[RTAX_MTU-1] = rt->u.dst.dev->mtu;
- if (dst_metric_locked(&rt->u.dst, RTAX_MTU) &&
+ rt->dst.metrics[RTAX_MTU-1] = rt->dst.dev->mtu;
+ if (dst_metric_locked(&rt->dst, RTAX_MTU) &&
rt->rt_gateway != rt->rt_dst &&
- rt->u.dst.dev->mtu > 576)
- rt->u.dst.metrics[RTAX_MTU-1] = 576;
+ rt->dst.dev->mtu > 576)
+ rt->dst.metrics[RTAX_MTU-1] = 576;
}
#ifdef CONFIG_NET_CLS_ROUTE
- rt->u.dst.tclassid = FIB_RES_NH(*res).nh_tclassid;
+ rt->dst.tclassid = FIB_RES_NH(*res).nh_tclassid;
#endif
} else
- rt->u.dst.metrics[RTAX_MTU-1]= rt->u.dst.dev->mtu;
-
- if (dst_metric(&rt->u.dst, RTAX_HOPLIMIT) == 0)
- rt->u.dst.metrics[RTAX_HOPLIMIT-1] = sysctl_ip_default_ttl;
- if (dst_mtu(&rt->u.dst) > IP_MAX_MTU)
- rt->u.dst.metrics[RTAX_MTU-1] = IP_MAX_MTU;
- if (dst_metric(&rt->u.dst, RTAX_ADVMSS) == 0)
- rt->u.dst.metrics[RTAX_ADVMSS-1] = max_t(unsigned int, rt->u.dst.dev->mtu - 40,
+ rt->dst.metrics[RTAX_MTU-1]= rt->dst.dev->mtu;
+
+ if (dst_metric(&rt->dst, RTAX_HOPLIMIT) == 0)
+ rt->dst.metrics[RTAX_HOPLIMIT-1] = sysctl_ip_default_ttl;
+ if (dst_mtu(&rt->dst) > IP_MAX_MTU)
+ rt->dst.metrics[RTAX_MTU-1] = IP_MAX_MTU;
+ if (dst_metric(&rt->dst, RTAX_ADVMSS) == 0)
+ rt->dst.metrics[RTAX_ADVMSS-1] = max_t(unsigned int, rt->dst.dev->mtu - 40,
ip_rt_min_advmss);
- if (dst_metric(&rt->u.dst, RTAX_ADVMSS) > 65535 - 40)
- rt->u.dst.metrics[RTAX_ADVMSS-1] = 65535 - 40;
+ if (dst_metric(&rt->dst, RTAX_ADVMSS) > 65535 - 40)
+ rt->dst.metrics[RTAX_ADVMSS-1] = 65535 - 40;
#ifdef CONFIG_NET_CLS_ROUTE
#ifdef CONFIG_IP_MULTIPLE_TABLES
@@ -1844,14 +1840,16 @@ static void rt_set_nexthop(struct rtable *rt, struct fib_result *res, u32 itag)
rt->rt_type = res->type;
}
+/* called in rcu_read_lock() section */
static int ip_route_input_mc(struct sk_buff *skb, __be32 daddr, __be32 saddr,
u8 tos, struct net_device *dev, int our)
{
- unsigned hash;
+ unsigned int hash;
struct rtable *rth;
__be32 spec_dst;
- struct in_device *in_dev = in_dev_get(dev);
+ struct in_device *in_dev = __in_dev_get_rcu(dev);
u32 itag = 0;
+ int err;
/* Primary sanity checks. */
@@ -1866,21 +1864,23 @@ static int ip_route_input_mc(struct sk_buff *skb, __be32 daddr, __be32 saddr,
if (!ipv4_is_local_multicast(daddr))
goto e_inval;
spec_dst = inet_select_addr(dev, 0, RT_SCOPE_LINK);
- } else if (fib_validate_source(saddr, 0, tos, 0,
- dev, &spec_dst, &itag, 0) < 0)
- goto e_inval;
-
+ } else {
+ err = fib_validate_source(saddr, 0, tos, 0, dev, &spec_dst,
+ &itag, 0);
+ if (err < 0)
+ goto e_err;
+ }
rth = dst_alloc(&ipv4_dst_ops);
if (!rth)
goto e_nobufs;
- rth->u.dst.output = ip_rt_bug;
- rth->u.dst.obsolete = -1;
+ rth->dst.output = ip_rt_bug;
+ rth->dst.obsolete = -1;
- atomic_set(&rth->u.dst.__refcnt, 1);
- rth->u.dst.flags= DST_HOST;
+ atomic_set(&rth->dst.__refcnt, 1);
+ rth->dst.flags= DST_HOST;
if (IN_DEV_CONF_GET(in_dev, NOPOLICY))
- rth->u.dst.flags |= DST_NOPOLICY;
+ rth->dst.flags |= DST_NOPOLICY;
rth->fl.fl4_dst = daddr;
rth->rt_dst = daddr;
rth->fl.fl4_tos = tos;
@@ -1888,13 +1888,13 @@ static int ip_route_input_mc(struct sk_buff *skb, __be32 daddr, __be32 saddr,
rth->fl.fl4_src = saddr;
rth->rt_src = saddr;
#ifdef CONFIG_NET_CLS_ROUTE
- rth->u.dst.tclassid = itag;
+ rth->dst.tclassid = itag;
#endif
rth->rt_iif =
rth->fl.iif = dev->ifindex;
- rth->u.dst.dev = init_net.loopback_dev;
- dev_hold(rth->u.dst.dev);
- rth->idev = in_dev_get(rth->u.dst.dev);
+ rth->dst.dev = init_net.loopback_dev;
+ dev_hold(rth->dst.dev);
+ rth->idev = in_dev_get(rth->dst.dev);
rth->fl.oif = 0;
rth->rt_gateway = daddr;
rth->rt_spec_dst= spec_dst;
@@ -1902,27 +1902,25 @@ static int ip_route_input_mc(struct sk_buff *skb, __be32 daddr, __be32 saddr,
rth->rt_flags = RTCF_MULTICAST;
rth->rt_type = RTN_MULTICAST;
if (our) {
- rth->u.dst.input= ip_local_deliver;
+ rth->dst.input= ip_local_deliver;
rth->rt_flags |= RTCF_LOCAL;
}
#ifdef CONFIG_IP_MROUTE
if (!ipv4_is_local_multicast(daddr) && IN_DEV_MFORWARD(in_dev))
- rth->u.dst.input = ip_mr_input;
+ rth->dst.input = ip_mr_input;
#endif
RT_CACHE_STAT_INC(in_slow_mc);
- in_dev_put(in_dev);
hash = rt_hash(daddr, saddr, dev->ifindex, rt_genid(dev_net(dev)));
return rt_intern_hash(hash, rth, NULL, skb, dev->ifindex);
e_nobufs:
- in_dev_put(in_dev);
return -ENOBUFS;
-
e_inval:
- in_dev_put(in_dev);
return -EINVAL;
+e_err:
+ return err;
}
@@ -1956,22 +1954,22 @@ static void ip_handle_martian_source(struct net_device *dev,
#endif
}
+/* called in rcu_read_lock() section */
static int __mkroute_input(struct sk_buff *skb,
struct fib_result *res,
struct in_device *in_dev,
__be32 daddr, __be32 saddr, u32 tos,
struct rtable **result)
{
-
struct rtable *rth;
int err;
struct in_device *out_dev;
- unsigned flags = 0;
+ unsigned int flags = 0;
__be32 spec_dst;
u32 itag;
/* get a working reference to the output device */
- out_dev = in_dev_get(FIB_RES_DEV(*res));
+ out_dev = __in_dev_get_rcu(FIB_RES_DEV(*res));
if (out_dev == NULL) {
if (net_ratelimit())
printk(KERN_CRIT "Bug in ip_route_input" \
@@ -1986,7 +1984,6 @@ static int __mkroute_input(struct sk_buff *skb,
ip_handle_martian_source(in_dev->dev, in_dev, skb, daddr,
saddr);
- err = -EINVAL;
goto cleanup;
}
@@ -2020,12 +2017,12 @@ static int __mkroute_input(struct sk_buff *skb,
goto cleanup;
}
- atomic_set(&rth->u.dst.__refcnt, 1);
- rth->u.dst.flags= DST_HOST;
+ atomic_set(&rth->dst.__refcnt, 1);
+ rth->dst.flags= DST_HOST;
if (IN_DEV_CONF_GET(in_dev, NOPOLICY))
- rth->u.dst.flags |= DST_NOPOLICY;
+ rth->dst.flags |= DST_NOPOLICY;
if (IN_DEV_CONF_GET(out_dev, NOXFRM))
- rth->u.dst.flags |= DST_NOXFRM;
+ rth->dst.flags |= DST_NOXFRM;
rth->fl.fl4_dst = daddr;
rth->rt_dst = daddr;
rth->fl.fl4_tos = tos;
@@ -2035,16 +2032,16 @@ static int __mkroute_input(struct sk_buff *skb,
rth->rt_gateway = daddr;
rth->rt_iif =
rth->fl.iif = in_dev->dev->ifindex;
- rth->u.dst.dev = (out_dev)->dev;
- dev_hold(rth->u.dst.dev);
- rth->idev = in_dev_get(rth->u.dst.dev);
+ rth->dst.dev = (out_dev)->dev;
+ dev_hold(rth->dst.dev);
+ rth->idev = in_dev_get(rth->dst.dev);
rth->fl.oif = 0;
rth->rt_spec_dst= spec_dst;
- rth->u.dst.obsolete = -1;
- rth->u.dst.input = ip_forward;
- rth->u.dst.output = ip_output;
- rth->rt_genid = rt_genid(dev_net(rth->u.dst.dev));
+ rth->dst.obsolete = -1;
+ rth->dst.input = ip_forward;
+ rth->dst.output = ip_output;
+ rth->rt_genid = rt_genid(dev_net(rth->dst.dev));
rt_set_nexthop(rth, res, itag);
@@ -2053,8 +2050,6 @@ static int __mkroute_input(struct sk_buff *skb,
*result = rth;
err = 0;
cleanup:
- /* release the working reference to the output device */
- in_dev_put(out_dev);
return err;
}
@@ -2080,7 +2075,7 @@ static int ip_mkroute_input(struct sk_buff *skb,
/* put it into the cache */
hash = rt_hash(daddr, saddr, fl->iif,
- rt_genid(dev_net(rth->u.dst.dev)));
+ rt_genid(dev_net(rth->dst.dev)));
return rt_intern_hash(hash, rth, NULL, skb, fl->iif);
}
@@ -2098,7 +2093,7 @@ static int ip_route_input_slow(struct sk_buff *skb, __be32 daddr, __be32 saddr,
u8 tos, struct net_device *dev)
{
struct fib_result res;
- struct in_device *in_dev = in_dev_get(dev);
+ struct in_device *in_dev = __in_dev_get_rcu(dev);
struct flowi fl = { .nl_u = { .ip4_u =
{ .daddr = daddr,
.saddr = saddr,
@@ -2158,13 +2153,12 @@ static int ip_route_input_slow(struct sk_buff *skb, __be32 daddr, __be32 saddr,
goto brd_input;
if (res.type == RTN_LOCAL) {
- int result;
- result = fib_validate_source(saddr, daddr, tos,
+ err = fib_validate_source(saddr, daddr, tos,
net->loopback_dev->ifindex,
dev, &spec_dst, &itag, skb->mark);
- if (result < 0)
- goto martian_source;
- if (result)
+ if (err < 0)
+ goto martian_source_keep_err;
+ if (err)
flags |= RTCF_DIRECTSRC;
spec_dst = daddr;
goto local_input;
@@ -2177,7 +2171,6 @@ static int ip_route_input_slow(struct sk_buff *skb, __be32 daddr, __be32 saddr,
err = ip_mkroute_input(skb, &res, &fl, in_dev, daddr, saddr, tos);
done:
- in_dev_put(in_dev);
if (free_res)
fib_res_put(&res);
out: return err;
@@ -2192,7 +2185,7 @@ brd_input:
err = fib_validate_source(saddr, 0, tos, 0, dev, &spec_dst,
&itag, skb->mark);
if (err < 0)
- goto martian_source;
+ goto martian_source_keep_err;
if (err)
flags |= RTCF_DIRECTSRC;
}
@@ -2205,14 +2198,14 @@ local_input:
if (!rth)
goto e_nobufs;
- rth->u.dst.output= ip_rt_bug;
- rth->u.dst.obsolete = -1;
+ rth->dst.output= ip_rt_bug;
+ rth->dst.obsolete = -1;
rth->rt_genid = rt_genid(net);
- atomic_set(&rth->u.dst.__refcnt, 1);
- rth->u.dst.flags= DST_HOST;
+ atomic_set(&rth->dst.__refcnt, 1);
+ rth->dst.flags= DST_HOST;
if (IN_DEV_CONF_GET(in_dev, NOPOLICY))
- rth->u.dst.flags |= DST_NOPOLICY;
+ rth->dst.flags |= DST_NOPOLICY;
rth->fl.fl4_dst = daddr;
rth->rt_dst = daddr;
rth->fl.fl4_tos = tos;
@@ -2220,20 +2213,20 @@ local_input:
rth->fl.fl4_src = saddr;
rth->rt_src = saddr;
#ifdef CONFIG_NET_CLS_ROUTE
- rth->u.dst.tclassid = itag;
+ rth->dst.tclassid = itag;
#endif
rth->rt_iif =
rth->fl.iif = dev->ifindex;
- rth->u.dst.dev = net->loopback_dev;
- dev_hold(rth->u.dst.dev);
- rth->idev = in_dev_get(rth->u.dst.dev);
+ rth->dst.dev = net->loopback_dev;
+ dev_hold(rth->dst.dev);
+ rth->idev = in_dev_get(rth->dst.dev);
rth->rt_gateway = daddr;
rth->rt_spec_dst= spec_dst;
- rth->u.dst.input= ip_local_deliver;
+ rth->dst.input= ip_local_deliver;
rth->rt_flags = flags|RTCF_LOCAL;
if (res.type == RTN_UNREACHABLE) {
- rth->u.dst.input= ip_error;
- rth->u.dst.error= -err;
+ rth->dst.input= ip_error;
+ rth->dst.error= -err;
rth->rt_flags &= ~RTCF_LOCAL;
}
rth->rt_type = res.type;
@@ -2273,8 +2266,10 @@ e_nobufs:
goto done;
martian_source:
+ err = -EINVAL;
+martian_source_keep_err:
ip_handle_martian_source(dev, in_dev, skb, daddr, saddr);
- goto e_inval;
+ goto done;
}
int ip_route_input_common(struct sk_buff *skb, __be32 daddr, __be32 saddr,
@@ -2284,32 +2279,34 @@ int ip_route_input_common(struct sk_buff *skb, __be32 daddr, __be32 saddr,
unsigned hash;
int iif = dev->ifindex;
struct net *net;
+ int res;
net = dev_net(dev);
+ rcu_read_lock();
+
if (!rt_caching(net))
goto skip_cache;
tos &= IPTOS_RT_MASK;
hash = rt_hash(daddr, saddr, iif, rt_genid(net));
- rcu_read_lock();
for (rth = rcu_dereference(rt_hash_table[hash].chain); rth;
- rth = rcu_dereference(rth->u.dst.rt_next)) {
+ rth = rcu_dereference(rth->dst.rt_next)) {
if ((((__force u32)rth->fl.fl4_dst ^ (__force u32)daddr) |
((__force u32)rth->fl.fl4_src ^ (__force u32)saddr) |
(rth->fl.iif ^ iif) |
rth->fl.oif |
(rth->fl.fl4_tos ^ tos)) == 0 &&
rth->fl.mark == skb->mark &&
- net_eq(dev_net(rth->u.dst.dev), net) &&
+ net_eq(dev_net(rth->dst.dev), net) &&
!rt_is_expired(rth)) {
if (noref) {
- dst_use_noref(&rth->u.dst, jiffies);
- skb_dst_set_noref(skb, &rth->u.dst);
+ dst_use_noref(&rth->dst, jiffies);
+ skb_dst_set_noref(skb, &rth->dst);
} else {
- dst_use(&rth->u.dst, jiffies);
- skb_dst_set(skb, &rth->u.dst);
+ dst_use(&rth->dst, jiffies);
+ skb_dst_set(skb, &rth->dst);
}
RT_CACHE_STAT_INC(in_hit);
rcu_read_unlock();
@@ -2317,7 +2314,6 @@ int ip_route_input_common(struct sk_buff *skb, __be32 daddr, __be32 saddr,
}
RT_CACHE_STAT_INC(in_hlist_search);
}
- rcu_read_unlock();
skip_cache:
/* Multicast recognition logic is moved from route cache to here.
@@ -2332,12 +2328,11 @@ skip_cache:
route cache entry is created eventually.
*/
if (ipv4_is_multicast(daddr)) {
- struct in_device *in_dev;
+ struct in_device *in_dev = __in_dev_get_rcu(dev);
- rcu_read_lock();
- if ((in_dev = __in_dev_get_rcu(dev)) != NULL) {
+ if (in_dev) {
int our = ip_check_mc(in_dev, daddr, saddr,
- ip_hdr(skb)->protocol);
+ ip_hdr(skb)->protocol);
if (our
#ifdef CONFIG_IP_MROUTE
||
@@ -2345,15 +2340,18 @@ skip_cache:
IN_DEV_MFORWARD(in_dev))
#endif
) {
+ int res = ip_route_input_mc(skb, daddr, saddr,
+ tos, dev, our);
rcu_read_unlock();
- return ip_route_input_mc(skb, daddr, saddr,
- tos, dev, our);
+ return res;
}
}
rcu_read_unlock();
return -EINVAL;
}
- return ip_route_input_slow(skb, daddr, saddr, tos, dev);
+ res = ip_route_input_slow(skb, daddr, saddr, tos, dev);
+ rcu_read_unlock();
+ return res;
}
EXPORT_SYMBOL(ip_route_input_common);
@@ -2415,12 +2413,12 @@ static int __mkroute_output(struct rtable **result,
goto cleanup;
}
- atomic_set(&rth->u.dst.__refcnt, 1);
- rth->u.dst.flags= DST_HOST;
+ atomic_set(&rth->dst.__refcnt, 1);
+ rth->dst.flags= DST_HOST;
if (IN_DEV_CONF_GET(in_dev, NOXFRM))
- rth->u.dst.flags |= DST_NOXFRM;
+ rth->dst.flags |= DST_NOXFRM;
if (IN_DEV_CONF_GET(in_dev, NOPOLICY))
- rth->u.dst.flags |= DST_NOPOLICY;
+ rth->dst.flags |= DST_NOPOLICY;
rth->fl.fl4_dst = oldflp->fl4_dst;
rth->fl.fl4_tos = tos;
@@ -2432,35 +2430,35 @@ static int __mkroute_output(struct rtable **result,
rth->rt_iif = oldflp->oif ? : dev_out->ifindex;
/* get references to the devices that are to be hold by the routing
cache entry */
- rth->u.dst.dev = dev_out;
+ rth->dst.dev = dev_out;
dev_hold(dev_out);
rth->idev = in_dev_get(dev_out);
rth->rt_gateway = fl->fl4_dst;
rth->rt_spec_dst= fl->fl4_src;
- rth->u.dst.output=ip_output;
- rth->u.dst.obsolete = -1;
+ rth->dst.output=ip_output;
+ rth->dst.obsolete = -1;
rth->rt_genid = rt_genid(dev_net(dev_out));
RT_CACHE_STAT_INC(out_slow_tot);
if (flags & RTCF_LOCAL) {
- rth->u.dst.input = ip_local_deliver;
+ rth->dst.input = ip_local_deliver;
rth->rt_spec_dst = fl->fl4_dst;
}
if (flags & (RTCF_BROADCAST | RTCF_MULTICAST)) {
rth->rt_spec_dst = fl->fl4_src;
if (flags & RTCF_LOCAL &&
!(dev_out->flags & IFF_LOOPBACK)) {
- rth->u.dst.output = ip_mc_output;
+ rth->dst.output = ip_mc_output;
RT_CACHE_STAT_INC(out_slow_mc);
}
#ifdef CONFIG_IP_MROUTE
if (res->type == RTN_MULTICAST) {
if (IN_DEV_MFORWARD(in_dev) &&
!ipv4_is_local_multicast(oldflp->fl4_dst)) {
- rth->u.dst.input = ip_mr_input;
- rth->u.dst.output = ip_mc_output;
+ rth->dst.input = ip_mr_input;
+ rth->dst.output = ip_mc_output;
}
}
#endif
@@ -2715,7 +2713,7 @@ int __ip_route_output_key(struct net *net, struct rtable **rp,
rcu_read_lock_bh();
for (rth = rcu_dereference_bh(rt_hash_table[hash].chain); rth;
- rth = rcu_dereference_bh(rth->u.dst.rt_next)) {
+ rth = rcu_dereference_bh(rth->dst.rt_next)) {
if (rth->fl.fl4_dst == flp->fl4_dst &&
rth->fl.fl4_src == flp->fl4_src &&
rth->fl.iif == 0 &&
@@ -2723,9 +2721,9 @@ int __ip_route_output_key(struct net *net, struct rtable **rp,
rth->fl.mark == flp->mark &&
!((rth->fl.fl4_tos ^ flp->fl4_tos) &
(IPTOS_RT_MASK | RTO_ONLINK)) &&
- net_eq(dev_net(rth->u.dst.dev), net) &&
+ net_eq(dev_net(rth->dst.dev), net) &&
!rt_is_expired(rth)) {
- dst_use(&rth->u.dst, jiffies);
+ dst_use(&rth->dst, jiffies);
RT_CACHE_STAT_INC(out_hit);
rcu_read_unlock_bh();
*rp = rth;
@@ -2738,7 +2736,6 @@ int __ip_route_output_key(struct net *net, struct rtable **rp,
slow_output:
return ip_route_output_slow(net, rp, flp);
}
-
EXPORT_SYMBOL_GPL(__ip_route_output_key);
static void ipv4_rt_blackhole_update_pmtu(struct dst_entry *dst, u32 mtu)
@@ -2762,15 +2759,15 @@ static int ipv4_dst_blackhole(struct net *net, struct rtable **rp, struct flowi
dst_alloc(&ipv4_dst_blackhole_ops);
if (rt) {
- struct dst_entry *new = &rt->u.dst;
+ struct dst_entry *new = &rt->dst;
atomic_set(&new->__refcnt, 1);
new->__use = 1;
new->input = dst_discard;
new->output = dst_discard;
- memcpy(new->metrics, ort->u.dst.metrics, RTAX_MAX*sizeof(u32));
+ memcpy(new->metrics, ort->dst.metrics, RTAX_MAX*sizeof(u32));
- new->dev = ort->u.dst.dev;
+ new->dev = ort->dst.dev;
if (new->dev)
dev_hold(new->dev);
@@ -2794,7 +2791,7 @@ static int ipv4_dst_blackhole(struct net *net, struct rtable **rp, struct flowi
dst_free(new);
}
- dst_release(&(*rp)->u.dst);
+ dst_release(&(*rp)->dst);
*rp = rt;
return (rt ? 0 : -ENOMEM);
}
@@ -2822,13 +2819,13 @@ int ip_route_output_flow(struct net *net, struct rtable **rp, struct flowi *flp,
return 0;
}
-
EXPORT_SYMBOL_GPL(ip_route_output_flow);
int ip_route_output_key(struct net *net, struct rtable **rp, struct flowi *flp)
{
return ip_route_output_flow(net, rp, flp, NULL, 0);
}
+EXPORT_SYMBOL(ip_route_output_key);
static int rt_fill_info(struct net *net,
struct sk_buff *skb, u32 pid, u32 seq, int event,
@@ -2864,11 +2861,11 @@ static int rt_fill_info(struct net *net,
r->rtm_src_len = 32;
NLA_PUT_BE32(skb, RTA_SRC, rt->fl.fl4_src);
}
- if (rt->u.dst.dev)
- NLA_PUT_U32(skb, RTA_OIF, rt->u.dst.dev->ifindex);
+ if (rt->dst.dev)
+ NLA_PUT_U32(skb, RTA_OIF, rt->dst.dev->ifindex);
#ifdef CONFIG_NET_CLS_ROUTE
- if (rt->u.dst.tclassid)
- NLA_PUT_U32(skb, RTA_FLOW, rt->u.dst.tclassid);
+ if (rt->dst.tclassid)
+ NLA_PUT_U32(skb, RTA_FLOW, rt->dst.tclassid);
#endif
if (rt->fl.iif)
NLA_PUT_BE32(skb, RTA_PREFSRC, rt->rt_spec_dst);
@@ -2878,12 +2875,16 @@ static int rt_fill_info(struct net *net,
if (rt->rt_dst != rt->rt_gateway)
NLA_PUT_BE32(skb, RTA_GATEWAY, rt->rt_gateway);
- if (rtnetlink_put_metrics(skb, rt->u.dst.metrics) < 0)
+ if (rtnetlink_put_metrics(skb, rt->dst.metrics) < 0)
goto nla_put_failure;
- error = rt->u.dst.error;
- expires = rt->u.dst.expires ? rt->u.dst.expires - jiffies : 0;
+ if (rt->fl.mark)
+ NLA_PUT_BE32(skb, RTA_MARK, rt->fl.mark);
+
+ error = rt->dst.error;
+ expires = rt->dst.expires ? rt->dst.expires - jiffies : 0;
if (rt->peer) {
+ inet_peer_refcheck(rt->peer);
id = atomic_read(&rt->peer->ip_id_count) & 0xffff;
if (rt->peer->tcp_ts_stamp) {
ts = rt->peer->tcp_ts;
@@ -2914,7 +2915,7 @@ static int rt_fill_info(struct net *net,
NLA_PUT_U32(skb, RTA_IIF, rt->fl.iif);
}
- if (rtnl_put_cacheinfo(skb, &rt->u.dst, id, ts, tsage,
+ if (rtnl_put_cacheinfo(skb, &rt->dst, id, ts, tsage,
expires, error) < 0)
goto nla_put_failure;
@@ -2935,6 +2936,7 @@ static int inet_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void
__be32 src = 0;
u32 iif;
int err;
+ int mark;
struct sk_buff *skb;
err = nlmsg_parse(nlh, sizeof(*rtm), tb, RTA_MAX, rtm_ipv4_policy);
@@ -2962,6 +2964,7 @@ static int inet_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void
src = tb[RTA_SRC] ? nla_get_be32(tb[RTA_SRC]) : 0;
dst = tb[RTA_DST] ? nla_get_be32(tb[RTA_DST]) : 0;
iif = tb[RTA_IIF] ? nla_get_u32(tb[RTA_IIF]) : 0;
+ mark = tb[RTA_MARK] ? nla_get_u32(tb[RTA_MARK]) : 0;
if (iif) {
struct net_device *dev;
@@ -2974,13 +2977,14 @@ static int inet_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void
skb->protocol = htons(ETH_P_IP);
skb->dev = dev;
+ skb->mark = mark;
local_bh_disable();
err = ip_route_input(skb, dst, src, rtm->rtm_tos, dev);
local_bh_enable();
rt = skb_rtable(skb);
- if (err == 0 && rt->u.dst.error)
- err = -rt->u.dst.error;
+ if (err == 0 && rt->dst.error)
+ err = -rt->dst.error;
} else {
struct flowi fl = {
.nl_u = {
@@ -2991,6 +2995,7 @@ static int inet_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void
},
},
.oif = tb[RTA_OIF] ? nla_get_u32(tb[RTA_OIF]) : 0,
+ .mark = mark,
};
err = ip_route_output_key(net, &rt, &fl);
}
@@ -2998,7 +3003,7 @@ static int inet_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void
if (err)
goto errout_free;
- skb_dst_set(skb, &rt->u.dst);
+ skb_dst_set(skb, &rt->dst);
if (rtm->rtm_flags & RTM_F_NOTIFY)
rt->rt_flags |= RTCF_NOTIFY;
@@ -3034,12 +3039,12 @@ int ip_rt_dump(struct sk_buff *skb, struct netlink_callback *cb)
continue;
rcu_read_lock_bh();
for (rt = rcu_dereference_bh(rt_hash_table[h].chain), idx = 0; rt;
- rt = rcu_dereference_bh(rt->u.dst.rt_next), idx++) {
- if (!net_eq(dev_net(rt->u.dst.dev), net) || idx < s_idx)
+ rt = rcu_dereference_bh(rt->dst.rt_next), idx++) {
+ if (!net_eq(dev_net(rt->dst.dev), net) || idx < s_idx)
continue;
if (rt_is_expired(rt))
continue;
- skb_dst_set_noref(skb, &rt->u.dst);
+ skb_dst_set_noref(skb, &rt->dst);
if (rt_fill_info(net, skb, NETLINK_CB(cb->skb).pid,
cb->nlh->nlmsg_seq, RTM_NEWROUTE,
1, NLM_F_MULTI) <= 0) {
@@ -3365,6 +3370,3 @@ void __init ip_static_sysctl_init(void)
register_sysctl_paths(ipv4_path, ipv4_skeleton);
}
#endif
-
-EXPORT_SYMBOL(__ip_select_ident);
-EXPORT_SYMBOL(ip_route_output_key);
diff --git a/net/ipv4/syncookies.c b/net/ipv4/syncookies.c
index 9f6b22206c5..650cace2180 100644
--- a/net/ipv4/syncookies.c
+++ b/net/ipv4/syncookies.c
@@ -18,8 +18,8 @@
#include <net/tcp.h>
#include <net/route.h>
-/* Timestamps: lowest 9 bits store TCP options */
-#define TSBITS 9
+/* Timestamps: lowest bits store TCP options */
+#define TSBITS 6
#define TSMASK (((__u32)1 << TSBITS) - 1)
extern int sysctl_tcp_syncookies;
@@ -58,7 +58,7 @@ static u32 cookie_hash(__be32 saddr, __be32 daddr, __be16 sport, __be16 dport,
/*
* when syncookies are in effect and tcp timestamps are enabled we encode
- * tcp options in the lowest 9 bits of the timestamp value that will be
+ * tcp options in the lower bits of the timestamp value that will be
* sent in the syn-ack.
* Since subsequent timestamps use the normal tcp_time_stamp value, we
* must make sure that the resulting initial timestamp is <= tcp_time_stamp.
@@ -70,11 +70,10 @@ __u32 cookie_init_timestamp(struct request_sock *req)
u32 options = 0;
ireq = inet_rsk(req);
- if (ireq->wscale_ok) {
- options = ireq->snd_wscale;
- options |= ireq->rcv_wscale << 4;
- }
- options |= ireq->sack_ok << 8;
+
+ options = ireq->wscale_ok ? ireq->snd_wscale : 0xf;
+ options |= ireq->sack_ok << 4;
+ options |= ireq->ecn_ok << 5;
ts = ts_now & ~TSMASK;
ts |= options;
@@ -138,23 +137,23 @@ static __u32 check_tcp_syn_cookie(__u32 cookie, __be32 saddr, __be32 daddr,
}
/*
- * This table has to be sorted and terminated with (__u16)-1.
- * XXX generate a better table.
- * Unresolved Issues: HIPPI with a 64k MSS is not well supported.
+ * MSS Values are taken from the 2009 paper
+ * 'Measuring TCP Maximum Segment Size' by S. Alcock and R. Nelson:
+ * - values 1440 to 1460 accounted for 80% of observed mss values
+ * - values outside the 536-1460 range are rare (<0.2%).
+ *
+ * Table must be sorted.
*/
static __u16 const msstab[] = {
- 64 - 1,
- 256 - 1,
- 512 - 1,
- 536 - 1,
- 1024 - 1,
- 1440 - 1,
- 1460 - 1,
- 4312 - 1,
- (__u16)-1
+ 64,
+ 512,
+ 536,
+ 1024,
+ 1440,
+ 1460,
+ 4312,
+ 8960,
};
-/* The number doesn't include the -1 terminator */
-#define NUM_MSS (ARRAY_SIZE(msstab) - 1)
/*
* Generate a syncookie. mssp points to the mss, which is returned
@@ -169,10 +168,10 @@ __u32 cookie_v4_init_sequence(struct sock *sk, struct sk_buff *skb, __u16 *mssp)
tcp_synq_overflow(sk);
- /* XXX sort msstab[] by probability? Binary search? */
- for (mssind = 0; mss > msstab[mssind + 1]; mssind++)
- ;
- *mssp = msstab[mssind] + 1;
+ for (mssind = ARRAY_SIZE(msstab) - 1; mssind ; mssind--)
+ if (mss >= msstab[mssind])
+ break;
+ *mssp = msstab[mssind];
NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_SYNCOOKIESSENT);
@@ -202,7 +201,7 @@ static inline int cookie_check(struct sk_buff *skb, __u32 cookie)
jiffies / (HZ * 60),
COUNTER_TRIES);
- return mssind < NUM_MSS ? msstab[mssind] + 1 : 0;
+ return mssind < ARRAY_SIZE(msstab) ? msstab[mssind] : 0;
}
static inline struct sock *get_cookie_sock(struct sock *sk, struct sk_buff *skb,
@@ -227,26 +226,38 @@ static inline struct sock *get_cookie_sock(struct sock *sk, struct sk_buff *skb,
* additional tcp options in the timestamp.
* This extracts these options from the timestamp echo.
*
- * The lowest 4 bits are for snd_wscale
- * The next 4 lsb are for rcv_wscale
- * The next lsb is for sack_ok
+ * The lowest 4 bits store snd_wscale.
+ * next 2 bits indicate SACK and ECN support.
+ *
+ * return false if we decode an option that should not be.
*/
-void cookie_check_timestamp(struct tcp_options_received *tcp_opt)
+bool cookie_check_timestamp(struct tcp_options_received *tcp_opt, bool *ecn_ok)
{
- /* echoed timestamp, 9 lowest bits contain options */
+ /* echoed timestamp, lowest bits contain options */
u32 options = tcp_opt->rcv_tsecr & TSMASK;
- tcp_opt->snd_wscale = options & 0xf;
- options >>= 4;
- tcp_opt->rcv_wscale = options & 0xf;
+ if (!tcp_opt->saw_tstamp) {
+ tcp_clear_options(tcp_opt);
+ return true;
+ }
+
+ if (!sysctl_tcp_timestamps)
+ return false;
tcp_opt->sack_ok = (options >> 4) & 0x1;
+ *ecn_ok = (options >> 5) & 1;
+ if (*ecn_ok && !sysctl_tcp_ecn)
+ return false;
+
+ if (tcp_opt->sack_ok && !sysctl_tcp_sack)
+ return false;
- if (tcp_opt->sack_ok)
- tcp_sack_reset(tcp_opt);
+ if ((options & 0xf) == 0xf)
+ return true; /* no window scaling */
- if (tcp_opt->snd_wscale || tcp_opt->rcv_wscale)
- tcp_opt->wscale_ok = 1;
+ tcp_opt->wscale_ok = 1;
+ tcp_opt->snd_wscale = options & 0xf;
+ return sysctl_tcp_window_scaling != 0;
}
EXPORT_SYMBOL(cookie_check_timestamp);
@@ -265,8 +276,9 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb,
int mss;
struct rtable *rt;
__u8 rcv_wscale;
+ bool ecn_ok;
- if (!sysctl_tcp_syncookies || !th->ack)
+ if (!sysctl_tcp_syncookies || !th->ack || th->rst)
goto out;
if (tcp_synq_no_recent_overflow(sk) ||
@@ -281,8 +293,8 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb,
memset(&tcp_opt, 0, sizeof(tcp_opt));
tcp_parse_options(skb, &tcp_opt, &hash_location, 0);
- if (tcp_opt.saw_tstamp)
- cookie_check_timestamp(&tcp_opt);
+ if (!cookie_check_timestamp(&tcp_opt, &ecn_ok))
+ goto out;
ret = NULL;
req = inet_reqsk_alloc(&tcp_request_sock_ops); /* for safety */
@@ -298,9 +310,8 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb,
ireq->rmt_port = th->source;
ireq->loc_addr = ip_hdr(skb)->daddr;
ireq->rmt_addr = ip_hdr(skb)->saddr;
- ireq->ecn_ok = 0;
+ ireq->ecn_ok = ecn_ok;
ireq->snd_wscale = tcp_opt.snd_wscale;
- ireq->rcv_wscale = tcp_opt.rcv_wscale;
ireq->sack_ok = tcp_opt.sack_ok;
ireq->wscale_ok = tcp_opt.wscale_ok;
ireq->tstamp_ok = tcp_opt.saw_tstamp;
@@ -354,15 +365,15 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb,
}
/* Try to redo what tcp_v4_send_synack did. */
- req->window_clamp = tp->window_clamp ? :dst_metric(&rt->u.dst, RTAX_WINDOW);
+ req->window_clamp = tp->window_clamp ? :dst_metric(&rt->dst, RTAX_WINDOW);
tcp_select_initial_window(tcp_full_space(sk), req->mss,
&req->rcv_wnd, &req->window_clamp,
ireq->wscale_ok, &rcv_wscale,
- dst_metric(&rt->u.dst, RTAX_INITRWND));
+ dst_metric(&rt->dst, RTAX_INITRWND));
ireq->rcv_wscale = rcv_wscale;
- ret = get_cookie_sock(sk, skb, req, &rt->u.dst);
+ ret = get_cookie_sock(sk, skb, req, &rt->dst);
out: return ret;
}
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
index 65afeaec15b..176e11aaea7 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -315,7 +315,6 @@ struct tcp_splice_state {
* is strict, actions are advisory and have some latency.
*/
int tcp_memory_pressure __read_mostly;
-
EXPORT_SYMBOL(tcp_memory_pressure);
void tcp_enter_memory_pressure(struct sock *sk)
@@ -325,7 +324,6 @@ void tcp_enter_memory_pressure(struct sock *sk)
tcp_memory_pressure = 1;
}
}
-
EXPORT_SYMBOL(tcp_enter_memory_pressure);
/* Convert seconds to retransmits based on initial and max timeout */
@@ -460,6 +458,7 @@ unsigned int tcp_poll(struct file *file, struct socket *sock, poll_table *wait)
}
return mask;
}
+EXPORT_SYMBOL(tcp_poll);
int tcp_ioctl(struct sock *sk, int cmd, unsigned long arg)
{
@@ -508,10 +507,11 @@ int tcp_ioctl(struct sock *sk, int cmd, unsigned long arg)
return put_user(answ, (int __user *)arg);
}
+EXPORT_SYMBOL(tcp_ioctl);
static inline void tcp_mark_push(struct tcp_sock *tp, struct sk_buff *skb)
{
- TCP_SKB_CB(skb)->flags |= TCPCB_FLAG_PSH;
+ TCP_SKB_CB(skb)->flags |= TCPHDR_PSH;
tp->pushed_seq = tp->write_seq;
}
@@ -527,7 +527,7 @@ static inline void skb_entail(struct sock *sk, struct sk_buff *skb)
skb->csum = 0;
tcb->seq = tcb->end_seq = tp->write_seq;
- tcb->flags = TCPCB_FLAG_ACK;
+ tcb->flags = TCPHDR_ACK;
tcb->sacked = 0;
skb_header_release(skb);
tcp_add_write_queue_tail(sk, skb);
@@ -676,6 +676,7 @@ ssize_t tcp_splice_read(struct socket *sock, loff_t *ppos,
return ret;
}
+EXPORT_SYMBOL(tcp_splice_read);
struct sk_buff *sk_stream_alloc_skb(struct sock *sk, int size, gfp_t gfp)
{
@@ -816,7 +817,7 @@ new_segment:
skb_shinfo(skb)->gso_segs = 0;
if (!copied)
- TCP_SKB_CB(skb)->flags &= ~TCPCB_FLAG_PSH;
+ TCP_SKB_CB(skb)->flags &= ~TCPHDR_PSH;
copied += copy;
poffset += copy;
@@ -857,15 +858,15 @@ out_err:
return sk_stream_error(sk, flags, err);
}
-ssize_t tcp_sendpage(struct socket *sock, struct page *page, int offset,
- size_t size, int flags)
+int tcp_sendpage(struct sock *sk, struct page *page, int offset,
+ size_t size, int flags)
{
ssize_t res;
- struct sock *sk = sock->sk;
if (!(sk->sk_route_caps & NETIF_F_SG) ||
!(sk->sk_route_caps & NETIF_F_ALL_CSUM))
- return sock_no_sendpage(sock, page, offset, size, flags);
+ return sock_no_sendpage(sk->sk_socket, page, offset, size,
+ flags);
lock_sock(sk);
TCP_CHECK_TIMER(sk);
@@ -874,6 +875,7 @@ ssize_t tcp_sendpage(struct socket *sock, struct page *page, int offset,
release_sock(sk);
return res;
}
+EXPORT_SYMBOL(tcp_sendpage);
#define TCP_PAGE(sk) (sk->sk_sndmsg_page)
#define TCP_OFF(sk) (sk->sk_sndmsg_off)
@@ -898,10 +900,9 @@ static inline int select_size(struct sock *sk, int sg)
return tmp;
}
-int tcp_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg,
+int tcp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
size_t size)
{
- struct sock *sk = sock->sk;
struct iovec *iov;
struct tcp_sock *tp = tcp_sk(sk);
struct sk_buff *skb;
@@ -1062,7 +1063,7 @@ new_segment:
}
if (!copied)
- TCP_SKB_CB(skb)->flags &= ~TCPCB_FLAG_PSH;
+ TCP_SKB_CB(skb)->flags &= ~TCPHDR_PSH;
tp->write_seq += copy;
TCP_SKB_CB(skb)->end_seq += copy;
@@ -1122,6 +1123,7 @@ out_err:
release_sock(sk);
return err;
}
+EXPORT_SYMBOL(tcp_sendmsg);
/*
* Handle reading urgent data. BSD has very simple semantics for
@@ -1381,6 +1383,7 @@ int tcp_read_sock(struct sock *sk, read_descriptor_t *desc,
tcp_cleanup_rbuf(sk, copied);
return copied;
}
+EXPORT_SYMBOL(tcp_read_sock);
/*
* This routine copies from a sock struct into the user buffer.
@@ -1775,6 +1778,7 @@ recv_urg:
err = tcp_recv_urg(sk, msg, len, flags);
goto out;
}
+EXPORT_SYMBOL(tcp_recvmsg);
void tcp_set_state(struct sock *sk, int state)
{
@@ -1867,6 +1871,7 @@ void tcp_shutdown(struct sock *sk, int how)
tcp_send_fin(sk);
}
}
+EXPORT_SYMBOL(tcp_shutdown);
void tcp_close(struct sock *sk, long timeout)
{
@@ -1899,6 +1904,10 @@ void tcp_close(struct sock *sk, long timeout)
sk_mem_reclaim(sk);
+ /* If socket has been already reset (e.g. in tcp_reset()) - kill it. */
+ if (sk->sk_state == TCP_CLOSE)
+ goto adjudge_to_death;
+
/* As outlined in RFC 2525, section 2.17, we send a RST here because
* data was lost. To witness the awful effects of the old behavior of
* always doing a FIN, run an older 2.1.x kernel or 2.0.x, start a bulk
@@ -2026,6 +2035,7 @@ out:
local_bh_enable();
sock_put(sk);
}
+EXPORT_SYMBOL(tcp_close);
/* These states need RST on ABORT according to RFC793 */
@@ -2099,6 +2109,7 @@ int tcp_disconnect(struct sock *sk, int flags)
sk->sk_error_report(sk);
return err;
}
+EXPORT_SYMBOL(tcp_disconnect);
/*
* Socket option code for TCP.
@@ -2176,6 +2187,8 @@ static int do_tcp_setsockopt(struct sock *sk, int level,
GFP_KERNEL);
if (cvp == NULL)
return -ENOMEM;
+
+ kref_init(&cvp->kref);
}
lock_sock(sk);
tp->rx_opt.cookie_in_always =
@@ -2190,12 +2203,11 @@ static int do_tcp_setsockopt(struct sock *sk, int level,
*/
kref_put(&tp->cookie_values->kref,
tcp_cookie_values_release);
- kref_init(&cvp->kref);
- tp->cookie_values = cvp;
} else {
cvp = tp->cookie_values;
}
}
+
if (cvp != NULL) {
cvp->cookie_desired = ctd.tcpct_cookie_desired;
@@ -2209,6 +2221,8 @@ static int do_tcp_setsockopt(struct sock *sk, int level,
cvp->s_data_desired = ctd.tcpct_s_data_desired;
cvp->s_data_constant = 0; /* false */
}
+
+ tp->cookie_values = cvp;
}
release_sock(sk);
return err;
@@ -2397,6 +2411,7 @@ int tcp_setsockopt(struct sock *sk, int level, int optname, char __user *optval,
optval, optlen);
return do_tcp_setsockopt(sk, level, optname, optval, optlen);
}
+EXPORT_SYMBOL(tcp_setsockopt);
#ifdef CONFIG_COMPAT
int compat_tcp_setsockopt(struct sock *sk, int level, int optname,
@@ -2407,7 +2422,6 @@ int compat_tcp_setsockopt(struct sock *sk, int level, int optname,
optval, optlen);
return do_tcp_setsockopt(sk, level, optname, optval, optlen);
}
-
EXPORT_SYMBOL(compat_tcp_setsockopt);
#endif
@@ -2473,7 +2487,6 @@ void tcp_get_info(struct sock *sk, struct tcp_info *info)
info->tcpi_total_retrans = tp->total_retrans;
}
-
EXPORT_SYMBOL_GPL(tcp_get_info);
static int do_tcp_getsockopt(struct sock *sk, int level,
@@ -2591,6 +2604,12 @@ static int do_tcp_getsockopt(struct sock *sk, int level,
return -EFAULT;
return 0;
}
+ case TCP_THIN_LINEAR_TIMEOUTS:
+ val = tp->thin_lto;
+ break;
+ case TCP_THIN_DUPACK:
+ val = tp->thin_dupack;
+ break;
default:
return -ENOPROTOOPT;
}
@@ -2612,6 +2631,7 @@ int tcp_getsockopt(struct sock *sk, int level, int optname, char __user *optval,
optval, optlen);
return do_tcp_getsockopt(sk, level, optname, optval, optlen);
}
+EXPORT_SYMBOL(tcp_getsockopt);
#ifdef CONFIG_COMPAT
int compat_tcp_getsockopt(struct sock *sk, int level, int optname,
@@ -2622,7 +2642,6 @@ int compat_tcp_getsockopt(struct sock *sk, int level, int optname,
optval, optlen);
return do_tcp_getsockopt(sk, level, optname, optval, optlen);
}
-
EXPORT_SYMBOL(compat_tcp_getsockopt);
#endif
@@ -2859,7 +2878,6 @@ void tcp_free_md5sig_pool(void)
if (pool)
__tcp_free_md5sig_pool(pool);
}
-
EXPORT_SYMBOL(tcp_free_md5sig_pool);
static struct tcp_md5sig_pool * __percpu *
@@ -2935,7 +2953,6 @@ retry:
}
return pool;
}
-
EXPORT_SYMBOL(tcp_alloc_md5sig_pool);
@@ -2959,7 +2976,7 @@ struct tcp_md5sig_pool *tcp_get_md5sig_pool(void)
spin_unlock(&tcp_md5sig_pool_lock);
if (p)
- return *per_cpu_ptr(p, smp_processor_id());
+ return *this_cpu_ptr(p);
local_bh_enable();
return NULL;
@@ -2987,7 +3004,6 @@ int tcp_md5_hash_header(struct tcp_md5sig_pool *hp,
th->check = old_checksum;
return err;
}
-
EXPORT_SYMBOL(tcp_md5_hash_header);
int tcp_md5_hash_skb_data(struct tcp_md5sig_pool *hp,
@@ -3000,6 +3016,7 @@ int tcp_md5_hash_skb_data(struct tcp_md5sig_pool *hp,
const unsigned head_data_len = skb_headlen(skb) > header_len ?
skb_headlen(skb) - header_len : 0;
const struct skb_shared_info *shi = skb_shinfo(skb);
+ struct sk_buff *frag_iter;
sg_init_table(&sg, 1);
@@ -3014,9 +3031,12 @@ int tcp_md5_hash_skb_data(struct tcp_md5sig_pool *hp,
return 1;
}
+ skb_walk_frags(skb, frag_iter)
+ if (tcp_md5_hash_skb_data(hp, frag_iter, 0))
+ return 1;
+
return 0;
}
-
EXPORT_SYMBOL(tcp_md5_hash_skb_data);
int tcp_md5_hash_key(struct tcp_md5sig_pool *hp, struct tcp_md5sig_key *key)
@@ -3026,7 +3046,6 @@ int tcp_md5_hash_key(struct tcp_md5sig_pool *hp, struct tcp_md5sig_key *key)
sg_init_one(&sg, key->key, key->keylen);
return crypto_hash_update(&hp->md5_desc, &sg, key->keylen);
}
-
EXPORT_SYMBOL(tcp_md5_hash_key);
#endif
@@ -3298,16 +3317,3 @@ void __init tcp_init(void)
tcp_secret_retiring = &tcp_secret_two;
tcp_secret_secondary = &tcp_secret_two;
}
-
-EXPORT_SYMBOL(tcp_close);
-EXPORT_SYMBOL(tcp_disconnect);
-EXPORT_SYMBOL(tcp_getsockopt);
-EXPORT_SYMBOL(tcp_ioctl);
-EXPORT_SYMBOL(tcp_poll);
-EXPORT_SYMBOL(tcp_read_sock);
-EXPORT_SYMBOL(tcp_recvmsg);
-EXPORT_SYMBOL(tcp_sendmsg);
-EXPORT_SYMBOL(tcp_splice_read);
-EXPORT_SYMBOL(tcp_sendpage);
-EXPORT_SYMBOL(tcp_setsockopt);
-EXPORT_SYMBOL(tcp_shutdown);
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index 548d575e6cc..3c426cb318e 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -78,10 +78,13 @@ int sysctl_tcp_window_scaling __read_mostly = 1;
int sysctl_tcp_sack __read_mostly = 1;
int sysctl_tcp_fack __read_mostly = 1;
int sysctl_tcp_reordering __read_mostly = TCP_FASTRETRANS_THRESH;
+EXPORT_SYMBOL(sysctl_tcp_reordering);
int sysctl_tcp_ecn __read_mostly = 2;
+EXPORT_SYMBOL(sysctl_tcp_ecn);
int sysctl_tcp_dsack __read_mostly = 1;
int sysctl_tcp_app_win __read_mostly = 31;
int sysctl_tcp_adv_win_scale __read_mostly = 2;
+EXPORT_SYMBOL(sysctl_tcp_adv_win_scale);
int sysctl_tcp_stdurg __read_mostly;
int sysctl_tcp_rfc1337 __read_mostly;
@@ -419,6 +422,7 @@ void tcp_initialize_rcv_mss(struct sock *sk)
inet_csk(sk)->icsk_ack.rcv_mss = hint;
}
+EXPORT_SYMBOL(tcp_initialize_rcv_mss);
/* Receiver "autotuning" code.
*
@@ -2938,6 +2942,7 @@ void tcp_simple_retransmit(struct sock *sk)
}
tcp_xmit_retransmit_queue(sk);
}
+EXPORT_SYMBOL(tcp_simple_retransmit);
/* Process an event, which can update packets-in-flight not trivially.
* Main goal of this function is to calculate new estimate for left_out,
@@ -3286,7 +3291,7 @@ static int tcp_clean_rtx_queue(struct sock *sk, int prior_fackets,
* connection startup slow start one packet too
* quickly. This is severely frowned upon behavior.
*/
- if (!(scb->flags & TCPCB_FLAG_SYN)) {
+ if (!(scb->flags & TCPHDR_SYN)) {
flag |= FLAG_DATA_ACKED;
} else {
flag |= FLAG_SYN_ACKED;
@@ -3858,6 +3863,7 @@ void tcp_parse_options(struct sk_buff *skb, struct tcp_options_received *opt_rx,
}
}
}
+EXPORT_SYMBOL(tcp_parse_options);
static int tcp_parse_aligned_timestamp(struct tcp_sock *tp, struct tcphdr *th)
{
@@ -3931,6 +3937,7 @@ u8 *tcp_parse_md5sig_option(struct tcphdr *th)
}
return NULL;
}
+EXPORT_SYMBOL(tcp_parse_md5sig_option);
#endif
static inline void tcp_store_ts_recent(struct tcp_sock *tp)
@@ -5432,6 +5439,7 @@ discard:
__kfree_skb(skb);
return 0;
}
+EXPORT_SYMBOL(tcp_rcv_established);
static int tcp_rcv_synsent_state_process(struct sock *sk, struct sk_buff *skb,
struct tcphdr *th, unsigned len)
@@ -5931,14 +5939,4 @@ discard:
}
return 0;
}
-
-EXPORT_SYMBOL(sysctl_tcp_ecn);
-EXPORT_SYMBOL(sysctl_tcp_reordering);
-EXPORT_SYMBOL(sysctl_tcp_adv_win_scale);
-EXPORT_SYMBOL(tcp_parse_options);
-#ifdef CONFIG_TCP_MD5SIG
-EXPORT_SYMBOL(tcp_parse_md5sig_option);
-#endif
-EXPORT_SYMBOL(tcp_rcv_established);
EXPORT_SYMBOL(tcp_rcv_state_process);
-EXPORT_SYMBOL(tcp_initialize_rcv_mss);
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
index fe193e53af4..020766292bb 100644
--- a/net/ipv4/tcp_ipv4.c
+++ b/net/ipv4/tcp_ipv4.c
@@ -84,6 +84,7 @@
int sysctl_tcp_tw_reuse __read_mostly;
int sysctl_tcp_low_latency __read_mostly;
+EXPORT_SYMBOL(sysctl_tcp_low_latency);
#ifdef CONFIG_TCP_MD5SIG
@@ -100,6 +101,7 @@ struct tcp_md5sig_key *tcp_v4_md5_do_lookup(struct sock *sk, __be32 addr)
#endif
struct inet_hashinfo tcp_hashinfo;
+EXPORT_SYMBOL(tcp_hashinfo);
static inline __u32 tcp_v4_init_sequence(struct sk_buff *skb)
{
@@ -139,7 +141,6 @@ int tcp_twsk_unique(struct sock *sk, struct sock *sktw, void *twp)
return 0;
}
-
EXPORT_SYMBOL_GPL(tcp_twsk_unique);
/* This will initiate an outgoing connection. */
@@ -204,10 +205,12 @@ int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
* TIME-WAIT * and initialize rx_opt.ts_recent from it,
* when trying new connection.
*/
- if (peer != NULL &&
- (u32)get_seconds() - peer->tcp_ts_stamp <= TCP_PAWS_MSL) {
- tp->rx_opt.ts_recent_stamp = peer->tcp_ts_stamp;
- tp->rx_opt.ts_recent = peer->tcp_ts;
+ if (peer) {
+ inet_peer_refcheck(peer);
+ if ((u32)get_seconds() - peer->tcp_ts_stamp <= TCP_PAWS_MSL) {
+ tp->rx_opt.ts_recent_stamp = peer->tcp_ts_stamp;
+ tp->rx_opt.ts_recent = peer->tcp_ts;
+ }
}
}
@@ -237,7 +240,7 @@ int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
/* OK, now commit destination to socket. */
sk->sk_gso_type = SKB_GSO_TCPV4;
- sk_setup_caps(sk, &rt->u.dst);
+ sk_setup_caps(sk, &rt->dst);
if (!tp->write_seq)
tp->write_seq = secure_tcp_sequence_number(inet->inet_saddr,
@@ -265,6 +268,7 @@ failure:
inet->inet_dport = 0;
return err;
}
+EXPORT_SYMBOL(tcp_v4_connect);
/*
* This routine does path mtu discovery as defined in RFC1191.
@@ -543,6 +547,7 @@ void tcp_v4_send_check(struct sock *sk, struct sk_buff *skb)
__tcp_v4_send_check(skb, inet->inet_saddr, inet->inet_daddr);
}
+EXPORT_SYMBOL(tcp_v4_send_check);
int tcp_v4_gso_send_check(struct sk_buff *skb)
{
@@ -793,19 +798,20 @@ static void tcp_v4_reqsk_destructor(struct request_sock *req)
kfree(inet_rsk(req)->opt);
}
-#ifdef CONFIG_SYN_COOKIES
-static void syn_flood_warning(struct sk_buff *skb)
+static void syn_flood_warning(const struct sk_buff *skb)
{
- static unsigned long warntime;
+ const char *msg;
- if (time_after(jiffies, (warntime + HZ * 60))) {
- warntime = jiffies;
- printk(KERN_INFO
- "possible SYN flooding on port %d. Sending cookies.\n",
- ntohs(tcp_hdr(skb)->dest));
- }
-}
+#ifdef CONFIG_SYN_COOKIES
+ if (sysctl_tcp_syncookies)
+ msg = "Sending cookies";
+ else
#endif
+ msg = "Dropping request";
+
+ pr_info("TCP: Possible SYN flooding on port %d. %s.\n",
+ ntohs(tcp_hdr(skb)->dest), msg);
+}
/*
* Save and compile IPv4 options into the request_sock if needed.
@@ -857,7 +863,6 @@ struct tcp_md5sig_key *tcp_v4_md5_lookup(struct sock *sk,
{
return tcp_v4_md5_do_lookup(sk, inet_sk(addr_sk)->inet_daddr);
}
-
EXPORT_SYMBOL(tcp_v4_md5_lookup);
static struct tcp_md5sig_key *tcp_v4_reqsk_md5_lookup(struct sock *sk,
@@ -924,7 +929,6 @@ int tcp_v4_md5_do_add(struct sock *sk, __be32 addr,
}
return 0;
}
-
EXPORT_SYMBOL(tcp_v4_md5_do_add);
static int tcp_v4_md5_add_func(struct sock *sk, struct sock *addr_sk,
@@ -962,7 +966,6 @@ int tcp_v4_md5_do_del(struct sock *sk, __be32 addr)
}
return -ENOENT;
}
-
EXPORT_SYMBOL(tcp_v4_md5_do_del);
static void tcp_v4_clear_md5_list(struct sock *sk)
@@ -1135,7 +1138,6 @@ clear_hash_noput:
memset(md5_hash, 0, 16);
return 1;
}
-
EXPORT_SYMBOL(tcp_v4_md5_hash_skb);
static int tcp_v4_inbound_md5_hash(struct sock *sk, struct sk_buff *skb)
@@ -1243,6 +1245,8 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb)
* evidently real one.
*/
if (inet_csk_reqsk_queue_is_full(sk) && !isn) {
+ if (net_ratelimit())
+ syn_flood_warning(skb);
#ifdef CONFIG_SYN_COOKIES
if (sysctl_tcp_syncookies) {
want_cookie = 1;
@@ -1323,15 +1327,12 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb)
if (security_inet_conn_request(sk, skb, req))
goto drop_and_free;
- if (!want_cookie)
+ if (!want_cookie || tmp_opt.tstamp_ok)
TCP_ECN_create_request(req, tcp_hdr(skb));
if (want_cookie) {
-#ifdef CONFIG_SYN_COOKIES
- syn_flood_warning(skb);
- req->cookie_ts = tmp_opt.tstamp_ok;
-#endif
isn = cookie_v4_init_sequence(sk, skb, &req->mss);
+ req->cookie_ts = tmp_opt.tstamp_ok;
} else if (!isn) {
struct inet_peer *peer = NULL;
@@ -1349,6 +1350,7 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb)
(dst = inet_csk_route_req(sk, req)) != NULL &&
(peer = rt_get_peer((struct rtable *)dst)) != NULL &&
peer->v4daddr == saddr) {
+ inet_peer_refcheck(peer);
if ((u32)get_seconds() - peer->tcp_ts_stamp < TCP_PAWS_MSL &&
(s32)(peer->tcp_ts - req->ts_recent) >
TCP_PAWS_WINDOW) {
@@ -1393,6 +1395,7 @@ drop_and_free:
drop:
return 0;
}
+EXPORT_SYMBOL(tcp_v4_conn_request);
/*
@@ -1478,6 +1481,7 @@ exit:
dst_release(dst);
return NULL;
}
+EXPORT_SYMBOL(tcp_v4_syn_recv_sock);
static struct sock *tcp_v4_hnd_req(struct sock *sk, struct sk_buff *skb)
{
@@ -1504,7 +1508,7 @@ static struct sock *tcp_v4_hnd_req(struct sock *sk, struct sk_buff *skb)
}
#ifdef CONFIG_SYN_COOKIES
- if (!th->rst && !th->syn && th->ack)
+ if (!th->syn)
sk = cookie_v4_check(sk, skb, &(IPCB(skb)->opt));
#endif
return sk;
@@ -1607,6 +1611,7 @@ csum_err:
TCP_INC_STATS_BH(sock_net(sk), TCP_MIB_INERRS);
goto discard;
}
+EXPORT_SYMBOL(tcp_v4_do_rcv);
/*
* From tcp_input.c
@@ -1793,6 +1798,7 @@ int tcp_v4_remember_stamp(struct sock *sk)
return 0;
}
+EXPORT_SYMBOL(tcp_v4_remember_stamp);
int tcp_v4_tw_remember_stamp(struct inet_timewait_sock *tw)
{
@@ -1832,6 +1838,7 @@ const struct inet_connection_sock_af_ops ipv4_specific = {
.compat_getsockopt = compat_ip_getsockopt,
#endif
};
+EXPORT_SYMBOL(ipv4_specific);
#ifdef CONFIG_TCP_MD5SIG
static const struct tcp_sock_af_ops tcp_sock_ipv4_specific = {
@@ -1960,7 +1967,6 @@ void tcp_v4_destroy_sock(struct sock *sk)
percpu_counter_dec(&tcp_sockets_allocated);
}
-
EXPORT_SYMBOL(tcp_v4_destroy_sock);
#ifdef CONFIG_PROC_FS
@@ -1978,6 +1984,11 @@ static inline struct inet_timewait_sock *tw_next(struct inet_timewait_sock *tw)
hlist_nulls_entry(tw->tw_node.next, typeof(*tw), tw_node) : NULL;
}
+/*
+ * Get next listener socket follow cur. If cur is NULL, get first socket
+ * starting from bucket given in st->bucket; when st->bucket is zero the
+ * very first socket in the hash table is returned.
+ */
static void *listening_get_next(struct seq_file *seq, void *cur)
{
struct inet_connection_sock *icsk;
@@ -1988,14 +1999,15 @@ static void *listening_get_next(struct seq_file *seq, void *cur)
struct net *net = seq_file_net(seq);
if (!sk) {
- st->bucket = 0;
- ilb = &tcp_hashinfo.listening_hash[0];
+ ilb = &tcp_hashinfo.listening_hash[st->bucket];
spin_lock_bh(&ilb->lock);
sk = sk_nulls_head(&ilb->head);
+ st->offset = 0;
goto get_sk;
}
ilb = &tcp_hashinfo.listening_hash[st->bucket];
++st->num;
+ ++st->offset;
if (st->state == TCP_SEQ_STATE_OPENREQ) {
struct request_sock *req = cur;
@@ -2010,6 +2022,7 @@ static void *listening_get_next(struct seq_file *seq, void *cur)
}
req = req->dl_next;
}
+ st->offset = 0;
if (++st->sbucket >= icsk->icsk_accept_queue.listen_opt->nr_table_entries)
break;
get_req:
@@ -2045,6 +2058,7 @@ start_req:
read_unlock_bh(&icsk->icsk_accept_queue.syn_wait_lock);
}
spin_unlock_bh(&ilb->lock);
+ st->offset = 0;
if (++st->bucket < INET_LHTABLE_SIZE) {
ilb = &tcp_hashinfo.listening_hash[st->bucket];
spin_lock_bh(&ilb->lock);
@@ -2058,7 +2072,12 @@ out:
static void *listening_get_idx(struct seq_file *seq, loff_t *pos)
{
- void *rc = listening_get_next(seq, NULL);
+ struct tcp_iter_state *st = seq->private;
+ void *rc;
+
+ st->bucket = 0;
+ st->offset = 0;
+ rc = listening_get_next(seq, NULL);
while (rc && *pos) {
rc = listening_get_next(seq, rc);
@@ -2073,13 +2092,18 @@ static inline int empty_bucket(struct tcp_iter_state *st)
hlist_nulls_empty(&tcp_hashinfo.ehash[st->bucket].twchain);
}
+/*
+ * Get first established socket starting from bucket given in st->bucket.
+ * If st->bucket is zero, the very first socket in the hash is returned.
+ */
static void *established_get_first(struct seq_file *seq)
{
struct tcp_iter_state *st = seq->private;
struct net *net = seq_file_net(seq);
void *rc = NULL;
- for (st->bucket = 0; st->bucket <= tcp_hashinfo.ehash_mask; ++st->bucket) {
+ st->offset = 0;
+ for (; st->bucket <= tcp_hashinfo.ehash_mask; ++st->bucket) {
struct sock *sk;
struct hlist_nulls_node *node;
struct inet_timewait_sock *tw;
@@ -2124,6 +2148,7 @@ static void *established_get_next(struct seq_file *seq, void *cur)
struct net *net = seq_file_net(seq);
++st->num;
+ ++st->offset;
if (st->state == TCP_SEQ_STATE_TIME_WAIT) {
tw = cur;
@@ -2140,6 +2165,7 @@ get_tw:
st->state = TCP_SEQ_STATE_ESTABLISHED;
/* Look for next non empty bucket */
+ st->offset = 0;
while (++st->bucket <= tcp_hashinfo.ehash_mask &&
empty_bucket(st))
;
@@ -2167,7 +2193,11 @@ out:
static void *established_get_idx(struct seq_file *seq, loff_t pos)
{
- void *rc = established_get_first(seq);
+ struct tcp_iter_state *st = seq->private;
+ void *rc;
+
+ st->bucket = 0;
+ rc = established_get_first(seq);
while (rc && pos) {
rc = established_get_next(seq, rc);
@@ -2192,24 +2222,72 @@ static void *tcp_get_idx(struct seq_file *seq, loff_t pos)
return rc;
}
+static void *tcp_seek_last_pos(struct seq_file *seq)
+{
+ struct tcp_iter_state *st = seq->private;
+ int offset = st->offset;
+ int orig_num = st->num;
+ void *rc = NULL;
+
+ switch (st->state) {
+ case TCP_SEQ_STATE_OPENREQ:
+ case TCP_SEQ_STATE_LISTENING:
+ if (st->bucket >= INET_LHTABLE_SIZE)
+ break;
+ st->state = TCP_SEQ_STATE_LISTENING;
+ rc = listening_get_next(seq, NULL);
+ while (offset-- && rc)
+ rc = listening_get_next(seq, rc);
+ if (rc)
+ break;
+ st->bucket = 0;
+ /* Fallthrough */
+ case TCP_SEQ_STATE_ESTABLISHED:
+ case TCP_SEQ_STATE_TIME_WAIT:
+ st->state = TCP_SEQ_STATE_ESTABLISHED;
+ if (st->bucket > tcp_hashinfo.ehash_mask)
+ break;
+ rc = established_get_first(seq);
+ while (offset-- && rc)
+ rc = established_get_next(seq, rc);
+ }
+
+ st->num = orig_num;
+
+ return rc;
+}
+
static void *tcp_seq_start(struct seq_file *seq, loff_t *pos)
{
struct tcp_iter_state *st = seq->private;
+ void *rc;
+
+ if (*pos && *pos == st->last_pos) {
+ rc = tcp_seek_last_pos(seq);
+ if (rc)
+ goto out;
+ }
+
st->state = TCP_SEQ_STATE_LISTENING;
st->num = 0;
- return *pos ? tcp_get_idx(seq, *pos - 1) : SEQ_START_TOKEN;
+ st->bucket = 0;
+ st->offset = 0;
+ rc = *pos ? tcp_get_idx(seq, *pos - 1) : SEQ_START_TOKEN;
+
+out:
+ st->last_pos = *pos;
+ return rc;
}
static void *tcp_seq_next(struct seq_file *seq, void *v, loff_t *pos)
{
+ struct tcp_iter_state *st = seq->private;
void *rc = NULL;
- struct tcp_iter_state *st;
if (v == SEQ_START_TOKEN) {
rc = tcp_get_idx(seq, 0);
goto out;
}
- st = seq->private;
switch (st->state) {
case TCP_SEQ_STATE_OPENREQ:
@@ -2217,6 +2295,8 @@ static void *tcp_seq_next(struct seq_file *seq, void *v, loff_t *pos)
rc = listening_get_next(seq, v);
if (!rc) {
st->state = TCP_SEQ_STATE_ESTABLISHED;
+ st->bucket = 0;
+ st->offset = 0;
rc = established_get_first(seq);
}
break;
@@ -2227,6 +2307,7 @@ static void *tcp_seq_next(struct seq_file *seq, void *v, loff_t *pos)
}
out:
++*pos;
+ st->last_pos = *pos;
return rc;
}
@@ -2265,6 +2346,7 @@ static int tcp_seq_open(struct inode *inode, struct file *file)
s = ((struct seq_file *)file->private_data)->private;
s->family = afinfo->family;
+ s->last_pos = 0;
return 0;
}
@@ -2288,11 +2370,13 @@ int tcp_proc_register(struct net *net, struct tcp_seq_afinfo *afinfo)
rc = -ENOMEM;
return rc;
}
+EXPORT_SYMBOL(tcp_proc_register);
void tcp_proc_unregister(struct net *net, struct tcp_seq_afinfo *afinfo)
{
proc_net_remove(net, afinfo->name);
}
+EXPORT_SYMBOL(tcp_proc_unregister);
static void get_openreq4(struct sock *sk, struct request_sock *req,
struct seq_file *f, int i, int uid, int *len)
@@ -2516,6 +2600,8 @@ struct proto tcp_prot = {
.setsockopt = tcp_setsockopt,
.getsockopt = tcp_getsockopt,
.recvmsg = tcp_recvmsg,
+ .sendmsg = tcp_sendmsg,
+ .sendpage = tcp_sendpage,
.backlog_rcv = tcp_v4_do_rcv,
.hash = inet_hash,
.unhash = inet_unhash,
@@ -2534,11 +2620,13 @@ struct proto tcp_prot = {
.twsk_prot = &tcp_timewait_sock_ops,
.rsk_prot = &tcp_request_sock_ops,
.h.hashinfo = &tcp_hashinfo,
+ .no_autobind = true,
#ifdef CONFIG_COMPAT
.compat_setsockopt = compat_tcp_setsockopt,
.compat_getsockopt = compat_tcp_getsockopt,
#endif
};
+EXPORT_SYMBOL(tcp_prot);
static int __net_init tcp_sk_init(struct net *net)
@@ -2569,20 +2657,3 @@ void __init tcp_v4_init(void)
if (register_pernet_subsys(&tcp_sk_ops))
panic("Failed to create the TCP control socket.\n");
}
-
-EXPORT_SYMBOL(ipv4_specific);
-EXPORT_SYMBOL(tcp_hashinfo);
-EXPORT_SYMBOL(tcp_prot);
-EXPORT_SYMBOL(tcp_v4_conn_request);
-EXPORT_SYMBOL(tcp_v4_connect);
-EXPORT_SYMBOL(tcp_v4_do_rcv);
-EXPORT_SYMBOL(tcp_v4_remember_stamp);
-EXPORT_SYMBOL(tcp_v4_send_check);
-EXPORT_SYMBOL(tcp_v4_syn_recv_sock);
-
-#ifdef CONFIG_PROC_FS
-EXPORT_SYMBOL(tcp_proc_register);
-EXPORT_SYMBOL(tcp_proc_unregister);
-#endif
-EXPORT_SYMBOL(sysctl_tcp_low_latency);
-
diff --git a/net/ipv4/tcp_minisocks.c b/net/ipv4/tcp_minisocks.c
index 794c2e122a4..f25b56cb85c 100644
--- a/net/ipv4/tcp_minisocks.c
+++ b/net/ipv4/tcp_minisocks.c
@@ -47,7 +47,6 @@ struct inet_timewait_death_row tcp_death_row = {
.twcal_timer = TIMER_INITIALIZER(inet_twdr_twcal_tick, 0,
(unsigned long)&tcp_death_row),
};
-
EXPORT_SYMBOL_GPL(tcp_death_row);
static __inline__ int tcp_in_window(u32 seq, u32 end_seq, u32 s_win, u32 e_win)
@@ -262,6 +261,7 @@ kill:
inet_twsk_put(tw);
return TCP_TW_SUCCESS;
}
+EXPORT_SYMBOL(tcp_timewait_state_process);
/*
* Move a socket to time-wait or dead fin-wait-2 state.
@@ -362,7 +362,6 @@ void tcp_twsk_destructor(struct sock *sk)
tcp_free_md5sig_pool();
#endif
}
-
EXPORT_SYMBOL_GPL(tcp_twsk_destructor);
static inline void TCP_ECN_openreq_child(struct tcp_sock *tp,
@@ -510,6 +509,7 @@ struct sock *tcp_create_openreq_child(struct sock *sk, struct request_sock *req,
}
return newsk;
}
+EXPORT_SYMBOL(tcp_create_openreq_child);
/*
* Process an incoming packet for SYN_RECV sockets represented
@@ -706,6 +706,7 @@ embryonic_reset:
inet_csk_reqsk_queue_drop(sk, req, prev);
return NULL;
}
+EXPORT_SYMBOL(tcp_check_req);
/*
* Queue segment on the new socket if the new socket is active,
@@ -737,8 +738,4 @@ int tcp_child_process(struct sock *parent, struct sock *child,
sock_put(child);
return ret;
}
-
-EXPORT_SYMBOL(tcp_check_req);
EXPORT_SYMBOL(tcp_child_process);
-EXPORT_SYMBOL(tcp_create_openreq_child);
-EXPORT_SYMBOL(tcp_timewait_state_process);
diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c
index 7ed9dc1042d..de3bd845858 100644
--- a/net/ipv4/tcp_output.c
+++ b/net/ipv4/tcp_output.c
@@ -247,6 +247,7 @@ void tcp_select_initial_window(int __space, __u32 mss,
/* Set the clamp no higher than max representable value */
(*window_clamp) = min(65535U << (*rcv_wscale), *window_clamp);
}
+EXPORT_SYMBOL(tcp_select_initial_window);
/* Chose a new window to advertise, update state in tcp_sock for the
* socket, and return result with RFC1323 scaling applied. The return
@@ -294,9 +295,9 @@ static u16 tcp_select_window(struct sock *sk)
/* Packet ECN state for a SYN-ACK */
static inline void TCP_ECN_send_synack(struct tcp_sock *tp, struct sk_buff *skb)
{
- TCP_SKB_CB(skb)->flags &= ~TCPCB_FLAG_CWR;
+ TCP_SKB_CB(skb)->flags &= ~TCPHDR_CWR;
if (!(tp->ecn_flags & TCP_ECN_OK))
- TCP_SKB_CB(skb)->flags &= ~TCPCB_FLAG_ECE;
+ TCP_SKB_CB(skb)->flags &= ~TCPHDR_ECE;
}
/* Packet ECN state for a SYN. */
@@ -306,7 +307,7 @@ static inline void TCP_ECN_send_syn(struct sock *sk, struct sk_buff *skb)
tp->ecn_flags = 0;
if (sysctl_tcp_ecn == 1) {
- TCP_SKB_CB(skb)->flags |= TCPCB_FLAG_ECE | TCPCB_FLAG_CWR;
+ TCP_SKB_CB(skb)->flags |= TCPHDR_ECE | TCPHDR_CWR;
tp->ecn_flags = TCP_ECN_OK;
}
}
@@ -361,7 +362,7 @@ static void tcp_init_nondata_skb(struct sk_buff *skb, u32 seq, u8 flags)
skb_shinfo(skb)->gso_type = 0;
TCP_SKB_CB(skb)->seq = seq;
- if (flags & (TCPCB_FLAG_SYN | TCPCB_FLAG_FIN))
+ if (flags & (TCPHDR_SYN | TCPHDR_FIN))
seq++;
TCP_SKB_CB(skb)->end_seq = seq;
}
@@ -820,7 +821,7 @@ static int tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, int clone_it,
tcb = TCP_SKB_CB(skb);
memset(&opts, 0, sizeof(opts));
- if (unlikely(tcb->flags & TCPCB_FLAG_SYN))
+ if (unlikely(tcb->flags & TCPHDR_SYN))
tcp_options_size = tcp_syn_options(sk, skb, &opts, &md5);
else
tcp_options_size = tcp_established_options(sk, skb, &opts,
@@ -843,7 +844,7 @@ static int tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, int clone_it,
*(((__be16 *)th) + 6) = htons(((tcp_header_size >> 2) << 12) |
tcb->flags);
- if (unlikely(tcb->flags & TCPCB_FLAG_SYN)) {
+ if (unlikely(tcb->flags & TCPHDR_SYN)) {
/* RFC1323: The window in SYN & SYN/ACK segments
* is never scaled.
*/
@@ -866,7 +867,7 @@ static int tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, int clone_it,
}
tcp_options_write((__be32 *)(th + 1), tp, &opts);
- if (likely((tcb->flags & TCPCB_FLAG_SYN) == 0))
+ if (likely((tcb->flags & TCPHDR_SYN) == 0))
TCP_ECN_send(sk, skb, tcp_header_size);
#ifdef CONFIG_TCP_MD5SIG
@@ -880,7 +881,7 @@ static int tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, int clone_it,
icsk->icsk_af_ops->send_check(sk, skb);
- if (likely(tcb->flags & TCPCB_FLAG_ACK))
+ if (likely(tcb->flags & TCPHDR_ACK))
tcp_event_ack_sent(sk, tcp_skb_pcount(skb));
if (skb->len != tcp_header_size)
@@ -1023,7 +1024,7 @@ int tcp_fragment(struct sock *sk, struct sk_buff *skb, u32 len,
/* PSH and FIN should only be set in the second packet. */
flags = TCP_SKB_CB(skb)->flags;
- TCP_SKB_CB(skb)->flags = flags & ~(TCPCB_FLAG_FIN | TCPCB_FLAG_PSH);
+ TCP_SKB_CB(skb)->flags = flags & ~(TCPHDR_FIN | TCPHDR_PSH);
TCP_SKB_CB(buff)->flags = flags;
TCP_SKB_CB(buff)->sacked = TCP_SKB_CB(skb)->sacked;
@@ -1189,6 +1190,7 @@ void tcp_mtup_init(struct sock *sk)
icsk->icsk_mtup.search_low = tcp_mss_to_mtu(sk, sysctl_tcp_base_mss);
icsk->icsk_mtup.probe_size = 0;
}
+EXPORT_SYMBOL(tcp_mtup_init);
/* This function synchronize snd mss to current pmtu/exthdr set.
@@ -1232,6 +1234,7 @@ unsigned int tcp_sync_mss(struct sock *sk, u32 pmtu)
return mss_now;
}
+EXPORT_SYMBOL(tcp_sync_mss);
/* Compute the current effective MSS, taking SACKs and IP options,
* and even PMTU discovery events into account.
@@ -1328,8 +1331,7 @@ static inline unsigned int tcp_cwnd_test(struct tcp_sock *tp,
u32 in_flight, cwnd;
/* Don't be strict about the congestion window for the final FIN. */
- if ((TCP_SKB_CB(skb)->flags & TCPCB_FLAG_FIN) &&
- tcp_skb_pcount(skb) == 1)
+ if ((TCP_SKB_CB(skb)->flags & TCPHDR_FIN) && tcp_skb_pcount(skb) == 1)
return 1;
in_flight = tcp_packets_in_flight(tp);
@@ -1398,7 +1400,7 @@ static inline int tcp_nagle_test(struct tcp_sock *tp, struct sk_buff *skb,
* Nagle can be ignored during F-RTO too (see RFC4138).
*/
if (tcp_urg_mode(tp) || (tp->frto_counter == 2) ||
- (TCP_SKB_CB(skb)->flags & TCPCB_FLAG_FIN))
+ (TCP_SKB_CB(skb)->flags & TCPHDR_FIN))
return 1;
if (!tcp_nagle_check(tp, skb, cur_mss, nonagle))
@@ -1461,7 +1463,7 @@ int tcp_may_send_now(struct sock *sk)
* packet has never been sent out before (and thus is not cloned).
*/
static int tso_fragment(struct sock *sk, struct sk_buff *skb, unsigned int len,
- unsigned int mss_now)
+ unsigned int mss_now, gfp_t gfp)
{
struct sk_buff *buff;
int nlen = skb->len - len;
@@ -1471,7 +1473,7 @@ static int tso_fragment(struct sock *sk, struct sk_buff *skb, unsigned int len,
if (skb->len != skb->data_len)
return tcp_fragment(sk, skb, len, mss_now);
- buff = sk_stream_alloc_skb(sk, 0, GFP_ATOMIC);
+ buff = sk_stream_alloc_skb(sk, 0, gfp);
if (unlikely(buff == NULL))
return -ENOMEM;
@@ -1487,7 +1489,7 @@ static int tso_fragment(struct sock *sk, struct sk_buff *skb, unsigned int len,
/* PSH and FIN should only be set in the second packet. */
flags = TCP_SKB_CB(skb)->flags;
- TCP_SKB_CB(skb)->flags = flags & ~(TCPCB_FLAG_FIN | TCPCB_FLAG_PSH);
+ TCP_SKB_CB(skb)->flags = flags & ~(TCPHDR_FIN | TCPHDR_PSH);
TCP_SKB_CB(buff)->flags = flags;
/* This packet was never sent out yet, so no SACK bits. */
@@ -1518,7 +1520,7 @@ static int tcp_tso_should_defer(struct sock *sk, struct sk_buff *skb)
const struct inet_connection_sock *icsk = inet_csk(sk);
u32 send_win, cong_win, limit, in_flight;
- if (TCP_SKB_CB(skb)->flags & TCPCB_FLAG_FIN)
+ if (TCP_SKB_CB(skb)->flags & TCPHDR_FIN)
goto send_now;
if (icsk->icsk_ca_state != TCP_CA_Open)
@@ -1644,7 +1646,7 @@ static int tcp_mtu_probe(struct sock *sk)
TCP_SKB_CB(nskb)->seq = TCP_SKB_CB(skb)->seq;
TCP_SKB_CB(nskb)->end_seq = TCP_SKB_CB(skb)->seq + probe_size;
- TCP_SKB_CB(nskb)->flags = TCPCB_FLAG_ACK;
+ TCP_SKB_CB(nskb)->flags = TCPHDR_ACK;
TCP_SKB_CB(nskb)->sacked = 0;
nskb->csum = 0;
nskb->ip_summed = skb->ip_summed;
@@ -1669,7 +1671,7 @@ static int tcp_mtu_probe(struct sock *sk)
sk_wmem_free_skb(sk, skb);
} else {
TCP_SKB_CB(nskb)->flags |= TCP_SKB_CB(skb)->flags &
- ~(TCPCB_FLAG_FIN|TCPCB_FLAG_PSH);
+ ~(TCPHDR_FIN|TCPHDR_PSH);
if (!skb_shinfo(skb)->nr_frags) {
skb_pull(skb, copy);
if (skb->ip_summed != CHECKSUM_PARTIAL)
@@ -1769,7 +1771,7 @@ static int tcp_write_xmit(struct sock *sk, unsigned int mss_now, int nonagle,
cwnd_quota);
if (skb->len > limit &&
- unlikely(tso_fragment(sk, skb, limit, mss_now)))
+ unlikely(tso_fragment(sk, skb, limit, mss_now, gfp)))
break;
TCP_SKB_CB(skb)->when = tcp_time_stamp;
@@ -2020,7 +2022,7 @@ static void tcp_retrans_try_collapse(struct sock *sk, struct sk_buff *to,
if (!sysctl_tcp_retrans_collapse)
return;
- if (TCP_SKB_CB(skb)->flags & TCPCB_FLAG_SYN)
+ if (TCP_SKB_CB(skb)->flags & TCPHDR_SYN)
return;
tcp_for_write_queue_from_safe(skb, tmp, sk) {
@@ -2112,7 +2114,7 @@ int tcp_retransmit_skb(struct sock *sk, struct sk_buff *skb)
* since it is cheap to do so and saves bytes on the network.
*/
if (skb->len > 0 &&
- (TCP_SKB_CB(skb)->flags & TCPCB_FLAG_FIN) &&
+ (TCP_SKB_CB(skb)->flags & TCPHDR_FIN) &&
tp->snd_una == (TCP_SKB_CB(skb)->end_seq - 1)) {
if (!pskb_trim(skb, 0)) {
/* Reuse, even though it does some unnecessary work */
@@ -2304,7 +2306,7 @@ void tcp_send_fin(struct sock *sk)
mss_now = tcp_current_mss(sk);
if (tcp_send_head(sk) != NULL) {
- TCP_SKB_CB(skb)->flags |= TCPCB_FLAG_FIN;
+ TCP_SKB_CB(skb)->flags |= TCPHDR_FIN;
TCP_SKB_CB(skb)->end_seq++;
tp->write_seq++;
} else {
@@ -2321,7 +2323,7 @@ void tcp_send_fin(struct sock *sk)
skb_reserve(skb, MAX_TCP_HEADER);
/* FIN eats a sequence byte, write_seq advanced by tcp_queue_skb(). */
tcp_init_nondata_skb(skb, tp->write_seq,
- TCPCB_FLAG_ACK | TCPCB_FLAG_FIN);
+ TCPHDR_ACK | TCPHDR_FIN);
tcp_queue_skb(sk, skb);
}
__tcp_push_pending_frames(sk, mss_now, TCP_NAGLE_OFF);
@@ -2346,7 +2348,7 @@ void tcp_send_active_reset(struct sock *sk, gfp_t priority)
/* Reserve space for headers and prepare control bits. */
skb_reserve(skb, MAX_TCP_HEADER);
tcp_init_nondata_skb(skb, tcp_acceptable_seq(sk),
- TCPCB_FLAG_ACK | TCPCB_FLAG_RST);
+ TCPHDR_ACK | TCPHDR_RST);
/* Send it off. */
TCP_SKB_CB(skb)->when = tcp_time_stamp;
if (tcp_transmit_skb(sk, skb, 0, priority))
@@ -2366,11 +2368,11 @@ int tcp_send_synack(struct sock *sk)
struct sk_buff *skb;
skb = tcp_write_queue_head(sk);
- if (skb == NULL || !(TCP_SKB_CB(skb)->flags & TCPCB_FLAG_SYN)) {
+ if (skb == NULL || !(TCP_SKB_CB(skb)->flags & TCPHDR_SYN)) {
printk(KERN_DEBUG "tcp_send_synack: wrong queue state\n");
return -EFAULT;
}
- if (!(TCP_SKB_CB(skb)->flags & TCPCB_FLAG_ACK)) {
+ if (!(TCP_SKB_CB(skb)->flags & TCPHDR_ACK)) {
if (skb_cloned(skb)) {
struct sk_buff *nskb = skb_copy(skb, GFP_ATOMIC);
if (nskb == NULL)
@@ -2384,7 +2386,7 @@ int tcp_send_synack(struct sock *sk)
skb = nskb;
}
- TCP_SKB_CB(skb)->flags |= TCPCB_FLAG_ACK;
+ TCP_SKB_CB(skb)->flags |= TCPHDR_ACK;
TCP_ECN_send_synack(tcp_sk(sk), skb);
}
TCP_SKB_CB(skb)->when = tcp_time_stamp;
@@ -2463,7 +2465,7 @@ struct sk_buff *tcp_make_synack(struct sock *sk, struct dst_entry *dst,
* not even correctly set)
*/
tcp_init_nondata_skb(skb, tcp_rsk(req)->snt_isn,
- TCPCB_FLAG_SYN | TCPCB_FLAG_ACK);
+ TCPHDR_SYN | TCPHDR_ACK);
if (OPTION_COOKIE_EXTENSION & opts.options) {
if (s_data_desired) {
@@ -2518,6 +2520,7 @@ struct sk_buff *tcp_make_synack(struct sock *sk, struct dst_entry *dst,
return skb;
}
+EXPORT_SYMBOL(tcp_make_synack);
/* Do all connect socket setups that can be done AF independent. */
static void tcp_connect_init(struct sock *sk)
@@ -2595,7 +2598,7 @@ int tcp_connect(struct sock *sk)
skb_reserve(buff, MAX_TCP_HEADER);
tp->snd_nxt = tp->write_seq;
- tcp_init_nondata_skb(buff, tp->write_seq++, TCPCB_FLAG_SYN);
+ tcp_init_nondata_skb(buff, tp->write_seq++, TCPHDR_SYN);
TCP_ECN_send_syn(sk, buff);
/* Send it off. */
@@ -2620,6 +2623,7 @@ int tcp_connect(struct sock *sk)
inet_csk(sk)->icsk_rto, TCP_RTO_MAX);
return 0;
}
+EXPORT_SYMBOL(tcp_connect);
/* Send out a delayed ack, the caller does the policy checking
* to see if we should even be here. See tcp_input.c:tcp_ack_snd_check()
@@ -2701,7 +2705,7 @@ void tcp_send_ack(struct sock *sk)
/* Reserve space for headers and prepare control bits. */
skb_reserve(buff, MAX_TCP_HEADER);
- tcp_init_nondata_skb(buff, tcp_acceptable_seq(sk), TCPCB_FLAG_ACK);
+ tcp_init_nondata_skb(buff, tcp_acceptable_seq(sk), TCPHDR_ACK);
/* Send it off, this clears delayed acks for us. */
TCP_SKB_CB(buff)->when = tcp_time_stamp;
@@ -2735,7 +2739,7 @@ static int tcp_xmit_probe_skb(struct sock *sk, int urgent)
* end to send an ack. Don't queue or clone SKB, just
* send it.
*/
- tcp_init_nondata_skb(skb, tp->snd_una - !urgent, TCPCB_FLAG_ACK);
+ tcp_init_nondata_skb(skb, tp->snd_una - !urgent, TCPHDR_ACK);
TCP_SKB_CB(skb)->when = tcp_time_stamp;
return tcp_transmit_skb(sk, skb, 0, GFP_ATOMIC);
}
@@ -2765,13 +2769,13 @@ int tcp_write_wakeup(struct sock *sk)
if (seg_size < TCP_SKB_CB(skb)->end_seq - TCP_SKB_CB(skb)->seq ||
skb->len > mss) {
seg_size = min(seg_size, mss);
- TCP_SKB_CB(skb)->flags |= TCPCB_FLAG_PSH;
+ TCP_SKB_CB(skb)->flags |= TCPHDR_PSH;
if (tcp_fragment(sk, skb, seg_size, mss))
return -1;
} else if (!tcp_skb_pcount(skb))
tcp_set_skb_tso_segs(sk, skb, mss);
- TCP_SKB_CB(skb)->flags |= TCPCB_FLAG_PSH;
+ TCP_SKB_CB(skb)->flags |= TCPHDR_PSH;
TCP_SKB_CB(skb)->when = tcp_time_stamp;
err = tcp_transmit_skb(sk, skb, 1, GFP_ATOMIC);
if (!err)
@@ -2824,10 +2828,3 @@ void tcp_send_probe0(struct sock *sk)
TCP_RTO_MAX);
}
}
-
-EXPORT_SYMBOL(tcp_select_initial_window);
-EXPORT_SYMBOL(tcp_connect);
-EXPORT_SYMBOL(tcp_make_synack);
-EXPORT_SYMBOL(tcp_simple_retransmit);
-EXPORT_SYMBOL(tcp_sync_mss);
-EXPORT_SYMBOL(tcp_mtup_init);
diff --git a/net/ipv4/tcp_timer.c b/net/ipv4/tcp_timer.c
index 440a5c6004f..808bb920c9f 100644
--- a/net/ipv4/tcp_timer.c
+++ b/net/ipv4/tcp_timer.c
@@ -41,7 +41,6 @@ void tcp_init_xmit_timers(struct sock *sk)
inet_csk_init_xmit_timers(sk, &tcp_write_timer, &tcp_delack_timer,
&tcp_keepalive_timer);
}
-
EXPORT_SYMBOL(tcp_init_xmit_timers);
static void tcp_write_err(struct sock *sk)
diff --git a/net/ipv4/tunnel4.c b/net/ipv4/tunnel4.c
index 3b3813cc80b..59186ca7808 100644
--- a/net/ipv4/tunnel4.c
+++ b/net/ipv4/tunnel4.c
@@ -48,7 +48,6 @@ err:
return ret;
}
-
EXPORT_SYMBOL(xfrm4_tunnel_register);
int xfrm4_tunnel_deregister(struct xfrm_tunnel *handler, unsigned short family)
@@ -72,7 +71,6 @@ int xfrm4_tunnel_deregister(struct xfrm_tunnel *handler, unsigned short family)
return ret;
}
-
EXPORT_SYMBOL(xfrm4_tunnel_deregister);
static int tunnel4_rcv(struct sk_buff *skb)
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
index eec4ff456e3..32e0bef60d0 100644
--- a/net/ipv4/udp.c
+++ b/net/ipv4/udp.c
@@ -914,7 +914,7 @@ int udp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
!sock_flag(sk, SOCK_BROADCAST))
goto out;
if (connected)
- sk_dst_set(sk, dst_clone(&rt->u.dst));
+ sk_dst_set(sk, dst_clone(&rt->dst));
}
if (msg->msg_flags&MSG_CONFIRM)
@@ -978,7 +978,7 @@ out:
return err;
do_confirm:
- dst_confirm(&rt->u.dst);
+ dst_confirm(&rt->dst);
if (!(msg->msg_flags&MSG_PROBE) || len)
goto back_from_confirm;
err = 0;
diff --git a/net/ipv4/udplite.c b/net/ipv4/udplite.c
index 6610bf76369..ab76aa928fa 100644
--- a/net/ipv4/udplite.c
+++ b/net/ipv4/udplite.c
@@ -58,6 +58,7 @@ struct proto udplite_prot = {
.compat_getsockopt = compat_udp_getsockopt,
#endif
};
+EXPORT_SYMBOL(udplite_prot);
static struct inet_protosw udplite4_protosw = {
.type = SOCK_DGRAM,
@@ -127,5 +128,3 @@ out_unregister_proto:
out_register_err:
printk(KERN_CRIT "%s: Cannot add UDP-Lite protocol.\n", __func__);
}
-
-EXPORT_SYMBOL(udplite_prot);
diff --git a/net/ipv4/xfrm4_input.c b/net/ipv4/xfrm4_input.c
index ad8fbb871aa..06814b6216d 100644
--- a/net/ipv4/xfrm4_input.c
+++ b/net/ipv4/xfrm4_input.c
@@ -163,5 +163,4 @@ int xfrm4_rcv(struct sk_buff *skb)
{
return xfrm4_rcv_spi(skb, ip_hdr(skb)->protocol, 0);
}
-
EXPORT_SYMBOL(xfrm4_rcv);
diff --git a/net/ipv4/xfrm4_policy.c b/net/ipv4/xfrm4_policy.c
index 23883a48ebf..869078d4eeb 100644
--- a/net/ipv4/xfrm4_policy.c
+++ b/net/ipv4/xfrm4_policy.c
@@ -37,7 +37,7 @@ static struct dst_entry *xfrm4_dst_lookup(struct net *net, int tos,
fl.fl4_src = saddr->a4;
err = __ip_route_output_key(net, &rt, &fl);
- dst = &rt->u.dst;
+ dst = &rt->dst;
if (err)
dst = ERR_PTR(err);
return dst;
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index 784f34d11fd..ab70a3fbcaf 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -121,8 +121,6 @@ static inline void addrconf_sysctl_unregister(struct inet6_dev *idev)
static int __ipv6_regen_rndid(struct inet6_dev *idev);
static int __ipv6_try_regen_rndid(struct inet6_dev *idev, struct in6_addr *tmpaddr);
static void ipv6_regen_rndid(unsigned long data);
-
-static int desync_factor = MAX_DESYNC_FACTOR * HZ;
#endif
static int ipv6_generate_eui64(u8 *eui, struct net_device *dev);
@@ -284,13 +282,16 @@ static void addrconf_mod_timer(struct inet6_ifaddr *ifp,
static int snmp6_alloc_dev(struct inet6_dev *idev)
{
if (snmp_mib_init((void __percpu **)idev->stats.ipv6,
- sizeof(struct ipstats_mib)) < 0)
+ sizeof(struct ipstats_mib),
+ __alignof__(struct ipstats_mib)) < 0)
goto err_ip;
if (snmp_mib_init((void __percpu **)idev->stats.icmpv6,
- sizeof(struct icmpv6_mib)) < 0)
+ sizeof(struct icmpv6_mib),
+ __alignof__(struct icmpv6_mib)) < 0)
goto err_icmp;
if (snmp_mib_init((void __percpu **)idev->stats.icmpv6msg,
- sizeof(struct icmpv6msg_mib)) < 0)
+ sizeof(struct icmpv6msg_mib),
+ __alignof__(struct icmpv6msg_mib)) < 0)
goto err_icmpmsg;
return 0;
@@ -557,7 +558,7 @@ void inet6_ifa_finish_destroy(struct inet6_ifaddr *ifp)
pr_warning("Freeing alive inet6 address %p\n", ifp);
return;
}
- dst_release(&ifp->rt->u.dst);
+ dst_release(&ifp->rt->dst);
call_rcu(&ifp->rcu, inet6_ifa_finish_destroy_rcu);
}
@@ -823,7 +824,7 @@ static void ipv6_del_addr(struct inet6_ifaddr *ifp)
rt->rt6i_flags |= RTF_EXPIRES;
}
}
- dst_release(&rt->u.dst);
+ dst_release(&rt->dst);
}
out:
@@ -890,7 +891,8 @@ retry:
idev->cnf.temp_valid_lft);
tmp_prefered_lft = min_t(__u32,
ifp->prefered_lft,
- idev->cnf.temp_prefered_lft - desync_factor / HZ);
+ idev->cnf.temp_prefered_lft -
+ idev->cnf.max_desync_factor);
tmp_plen = ifp->prefix_len;
max_addresses = idev->cnf.max_addresses;
tmp_cstamp = ifp->cstamp;
@@ -1650,7 +1652,8 @@ static void ipv6_regen_rndid(unsigned long data)
expires = jiffies +
idev->cnf.temp_prefered_lft * HZ -
- idev->cnf.regen_max_retry * idev->cnf.dad_transmits * idev->nd_parms->retrans_time - desync_factor;
+ idev->cnf.regen_max_retry * idev->cnf.dad_transmits * idev->nd_parms->retrans_time -
+ idev->cnf.max_desync_factor * HZ;
if (time_before(expires, jiffies)) {
printk(KERN_WARNING
"ipv6_regen_rndid(): too short regeneration interval; timer disabled for %s.\n",
@@ -1866,7 +1869,7 @@ void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len)
dev, expires, flags);
}
if (rt)
- dst_release(&rt->u.dst);
+ dst_release(&rt->dst);
}
/* Try to figure out our local address for this prefix */
@@ -3496,8 +3499,12 @@ static int inet6_fill_ifaddr(struct sk_buff *skb, struct inet6_ifaddr *ifa,
preferred -= tval;
else
preferred = 0;
- if (valid != INFINITY_LIFE_TIME)
- valid -= tval;
+ if (valid != INFINITY_LIFE_TIME) {
+ if (valid > tval)
+ valid -= tval;
+ else
+ valid = 0;
+ }
}
} else {
preferred = INFINITY_LIFE_TIME;
@@ -3859,12 +3866,28 @@ static inline void __snmp6_fill_stats(u64 *stats, void __percpu **mib,
memset(&stats[items], 0, pad);
}
+static inline void __snmp6_fill_stats64(u64 *stats, void __percpu **mib,
+ int items, int bytes, size_t syncpoff)
+{
+ int i;
+ int pad = bytes - sizeof(u64) * items;
+ BUG_ON(pad < 0);
+
+ /* Use put_unaligned() because stats may not be aligned for u64. */
+ put_unaligned(items, &stats[0]);
+ for (i = 1; i < items; i++)
+ put_unaligned(snmp_fold_field64(mib, i, syncpoff), &stats[i]);
+
+ memset(&stats[items], 0, pad);
+}
+
static void snmp6_fill_stats(u64 *stats, struct inet6_dev *idev, int attrtype,
int bytes)
{
switch (attrtype) {
case IFLA_INET6_STATS:
- __snmp6_fill_stats(stats, (void __percpu **)idev->stats.ipv6, IPSTATS_MIB_MAX, bytes);
+ __snmp6_fill_stats64(stats, (void __percpu **)idev->stats.ipv6,
+ IPSTATS_MIB_MAX, bytes, offsetof(struct ipstats_mib, syncp));
break;
case IFLA_INET6_ICMP6STATS:
__snmp6_fill_stats(stats, (void __percpu **)idev->stats.icmpv6, ICMP6_MIB_MAX, bytes);
@@ -4097,11 +4120,11 @@ static void __ipv6_ifa_notify(int event, struct inet6_ifaddr *ifp)
if (ifp->idev->cnf.forwarding)
addrconf_leave_anycast(ifp);
addrconf_leave_solict(ifp->idev, &ifp->addr);
- dst_hold(&ifp->rt->u.dst);
+ dst_hold(&ifp->rt->dst);
if (ifp->state == INET6_IFADDR_STATE_DEAD &&
ip6_del_rt(ifp->rt))
- dst_free(&ifp->rt->u.dst);
+ dst_free(&ifp->rt->dst);
break;
}
}
diff --git a/net/ipv6/addrlabel.c b/net/ipv6/addrlabel.c
index 8c4348cb195..f0e774cea38 100644
--- a/net/ipv6/addrlabel.c
+++ b/net/ipv6/addrlabel.c
@@ -53,11 +53,7 @@ static struct ip6addrlbl_table
static inline
struct net *ip6addrlbl_net(const struct ip6addrlbl_entry *lbl)
{
-#ifdef CONFIG_NET_NS
- return lbl->lbl_net;
-#else
- return &init_net;
-#endif
+ return read_pnet(&lbl->lbl_net);
}
/*
diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c
index e733942dafe..56b9bf2516f 100644
--- a/net/ipv6/af_inet6.c
+++ b/net/ipv6/af_inet6.c
@@ -522,10 +522,10 @@ const struct proto_ops inet6_stream_ops = {
.shutdown = inet_shutdown, /* ok */
.setsockopt = sock_common_setsockopt, /* ok */
.getsockopt = sock_common_getsockopt, /* ok */
- .sendmsg = tcp_sendmsg, /* ok */
- .recvmsg = sock_common_recvmsg, /* ok */
+ .sendmsg = inet_sendmsg, /* ok */
+ .recvmsg = inet_recvmsg, /* ok */
.mmap = sock_no_mmap,
- .sendpage = tcp_sendpage,
+ .sendpage = inet_sendpage,
.splice_read = tcp_splice_read,
#ifdef CONFIG_COMPAT
.compat_setsockopt = compat_sock_common_setsockopt,
@@ -549,7 +549,7 @@ const struct proto_ops inet6_dgram_ops = {
.setsockopt = sock_common_setsockopt, /* ok */
.getsockopt = sock_common_getsockopt, /* ok */
.sendmsg = inet_sendmsg, /* ok */
- .recvmsg = sock_common_recvmsg, /* ok */
+ .recvmsg = inet_recvmsg, /* ok */
.mmap = sock_no_mmap,
.sendpage = sock_no_sendpage,
#ifdef CONFIG_COMPAT
@@ -651,7 +651,7 @@ int inet6_sk_rebuild_header(struct sock *sk)
if (dst == NULL) {
struct inet_sock *inet = inet_sk(sk);
- struct in6_addr *final_p = NULL, final;
+ struct in6_addr *final_p, final;
struct flowi fl;
memset(&fl, 0, sizeof(fl));
@@ -665,12 +665,7 @@ int inet6_sk_rebuild_header(struct sock *sk)
fl.fl_ip_sport = inet->inet_sport;
security_sk_classify_flow(sk, &fl);
- if (np->opt && np->opt->srcrt) {
- struct rt0_hdr *rt0 = (struct rt0_hdr *) np->opt->srcrt;
- ipv6_addr_copy(&final, &fl.fl6_dst);
- ipv6_addr_copy(&fl.fl6_dst, rt0->addr);
- final_p = &final;
- }
+ final_p = fl6_update_dst(&fl, np->opt, &final);
err = ip6_dst_lookup(sk, &dst, &fl);
if (err) {
@@ -976,19 +971,24 @@ static void ipv6_packet_cleanup(void)
static int __net_init ipv6_init_mibs(struct net *net)
{
if (snmp_mib_init((void __percpu **)net->mib.udp_stats_in6,
- sizeof (struct udp_mib)) < 0)
+ sizeof(struct udp_mib),
+ __alignof__(struct udp_mib)) < 0)
return -ENOMEM;
if (snmp_mib_init((void __percpu **)net->mib.udplite_stats_in6,
- sizeof (struct udp_mib)) < 0)
+ sizeof(struct udp_mib),
+ __alignof__(struct udp_mib)) < 0)
goto err_udplite_mib;
if (snmp_mib_init((void __percpu **)net->mib.ipv6_statistics,
- sizeof(struct ipstats_mib)) < 0)
+ sizeof(struct ipstats_mib),
+ __alignof__(struct ipstats_mib)) < 0)
goto err_ip_mib;
if (snmp_mib_init((void __percpu **)net->mib.icmpv6_statistics,
- sizeof(struct icmpv6_mib)) < 0)
+ sizeof(struct icmpv6_mib),
+ __alignof__(struct icmpv6_mib)) < 0)
goto err_icmp_mib;
if (snmp_mib_init((void __percpu **)net->mib.icmpv6msg_statistics,
- sizeof(struct icmpv6msg_mib)) < 0)
+ sizeof(struct icmpv6msg_mib),
+ __alignof__(struct icmpv6msg_mib)) < 0)
goto err_icmpmsg_mib;
return 0;
diff --git a/net/ipv6/anycast.c b/net/ipv6/anycast.c
index b5b07054508..0e5e943446f 100644
--- a/net/ipv6/anycast.c
+++ b/net/ipv6/anycast.c
@@ -77,41 +77,40 @@ int ipv6_sock_ac_join(struct sock *sk, int ifindex, struct in6_addr *addr)
pac->acl_next = NULL;
ipv6_addr_copy(&pac->acl_addr, addr);
+ rcu_read_lock();
if (ifindex == 0) {
struct rt6_info *rt;
rt = rt6_lookup(net, addr, NULL, 0, 0);
if (rt) {
dev = rt->rt6i_dev;
- dev_hold(dev);
- dst_release(&rt->u.dst);
+ dst_release(&rt->dst);
} else if (ishost) {
err = -EADDRNOTAVAIL;
- goto out_free_pac;
+ goto error;
} else {
/* router, no matching interface: just pick one */
-
- dev = dev_get_by_flags(net, IFF_UP, IFF_UP|IFF_LOOPBACK);
+ dev = dev_get_by_flags_rcu(net, IFF_UP,
+ IFF_UP | IFF_LOOPBACK);
}
} else
- dev = dev_get_by_index(net, ifindex);
+ dev = dev_get_by_index_rcu(net, ifindex);
if (dev == NULL) {
err = -ENODEV;
- goto out_free_pac;
+ goto error;
}
- idev = in6_dev_get(dev);
+ idev = __in6_dev_get(dev);
if (!idev) {
if (ifindex)
err = -ENODEV;
else
err = -EADDRNOTAVAIL;
- goto out_dev_put;
+ goto error;
}
/* reset ishost, now that we have a specific device */
ishost = !idev->cnf.forwarding;
- in6_dev_put(idev);
pac->acl_ifindex = dev->ifindex;
@@ -124,26 +123,22 @@ int ipv6_sock_ac_join(struct sock *sk, int ifindex, struct in6_addr *addr)
if (ishost)
err = -EADDRNOTAVAIL;
if (err)
- goto out_dev_put;
+ goto error;
}
err = ipv6_dev_ac_inc(dev, addr);
- if (err)
- goto out_dev_put;
-
- write_lock_bh(&ipv6_sk_ac_lock);
- pac->acl_next = np->ipv6_ac_list;
- np->ipv6_ac_list = pac;
- write_unlock_bh(&ipv6_sk_ac_lock);
-
- dev_put(dev);
-
- return 0;
+ if (!err) {
+ write_lock_bh(&ipv6_sk_ac_lock);
+ pac->acl_next = np->ipv6_ac_list;
+ np->ipv6_ac_list = pac;
+ write_unlock_bh(&ipv6_sk_ac_lock);
+ pac = NULL;
+ }
-out_dev_put:
- dev_put(dev);
-out_free_pac:
- sock_kfree_s(sk, pac, sizeof(*pac));
+error:
+ rcu_read_unlock();
+ if (pac)
+ sock_kfree_s(sk, pac, sizeof(*pac));
return err;
}
@@ -176,11 +171,12 @@ int ipv6_sock_ac_drop(struct sock *sk, int ifindex, struct in6_addr *addr)
write_unlock_bh(&ipv6_sk_ac_lock);
- dev = dev_get_by_index(net, pac->acl_ifindex);
- if (dev) {
+ rcu_read_lock();
+ dev = dev_get_by_index_rcu(net, pac->acl_ifindex);
+ if (dev)
ipv6_dev_ac_dec(dev, &pac->acl_addr);
- dev_put(dev);
- }
+ rcu_read_unlock();
+
sock_kfree_s(sk, pac, sizeof(*pac));
return 0;
}
@@ -199,13 +195,12 @@ void ipv6_sock_ac_close(struct sock *sk)
write_unlock_bh(&ipv6_sk_ac_lock);
prev_index = 0;
+ rcu_read_lock();
while (pac) {
struct ipv6_ac_socklist *next = pac->acl_next;
if (pac->acl_ifindex != prev_index) {
- if (dev)
- dev_put(dev);
- dev = dev_get_by_index(net, pac->acl_ifindex);
+ dev = dev_get_by_index_rcu(net, pac->acl_ifindex);
prev_index = pac->acl_ifindex;
}
if (dev)
@@ -213,8 +208,7 @@ void ipv6_sock_ac_close(struct sock *sk)
sock_kfree_s(sk, pac, sizeof(*pac));
pac = next;
}
- if (dev)
- dev_put(dev);
+ rcu_read_unlock();
}
#if 0
@@ -250,7 +244,7 @@ static void aca_put(struct ifacaddr6 *ac)
{
if (atomic_dec_and_test(&ac->aca_refcnt)) {
in6_dev_put(ac->aca_idev);
- dst_release(&ac->aca_rt->u.dst);
+ dst_release(&ac->aca_rt->dst);
kfree(ac);
}
}
@@ -356,40 +350,39 @@ int __ipv6_dev_ac_dec(struct inet6_dev *idev, struct in6_addr *addr)
write_unlock_bh(&idev->lock);
addrconf_leave_solict(idev, &aca->aca_addr);
- dst_hold(&aca->aca_rt->u.dst);
+ dst_hold(&aca->aca_rt->dst);
ip6_del_rt(aca->aca_rt);
aca_put(aca);
return 0;
}
+/* called with rcu_read_lock() */
static int ipv6_dev_ac_dec(struct net_device *dev, struct in6_addr *addr)
{
- int ret;
- struct inet6_dev *idev = in6_dev_get(dev);
+ struct inet6_dev *idev = __in6_dev_get(dev);
+
if (idev == NULL)
return -ENODEV;
- ret = __ipv6_dev_ac_dec(idev, addr);
- in6_dev_put(idev);
- return ret;
+ return __ipv6_dev_ac_dec(idev, addr);
}
/*
* check if the interface has this anycast address
+ * called with rcu_read_lock()
*/
static int ipv6_chk_acast_dev(struct net_device *dev, struct in6_addr *addr)
{
struct inet6_dev *idev;
struct ifacaddr6 *aca;
- idev = in6_dev_get(dev);
+ idev = __in6_dev_get(dev);
if (idev) {
read_lock_bh(&idev->lock);
for (aca = idev->ac_list; aca; aca = aca->aca_next)
if (ipv6_addr_equal(&aca->aca_addr, addr))
break;
read_unlock_bh(&idev->lock);
- in6_dev_put(idev);
return aca != NULL;
}
return 0;
@@ -403,14 +396,15 @@ int ipv6_chk_acast_addr(struct net *net, struct net_device *dev,
{
int found = 0;
- if (dev)
- return ipv6_chk_acast_dev(dev, addr);
rcu_read_lock();
- for_each_netdev_rcu(net, dev)
- if (ipv6_chk_acast_dev(dev, addr)) {
- found = 1;
- break;
- }
+ if (dev)
+ found = ipv6_chk_acast_dev(dev, addr);
+ else
+ for_each_netdev_rcu(net, dev)
+ if (ipv6_chk_acast_dev(dev, addr)) {
+ found = 1;
+ break;
+ }
rcu_read_unlock();
return found;
}
diff --git a/net/ipv6/datagram.c b/net/ipv6/datagram.c
index 712684687c9..7d929a22cbc 100644
--- a/net/ipv6/datagram.c
+++ b/net/ipv6/datagram.c
@@ -38,10 +38,11 @@ int ip6_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
struct sockaddr_in6 *usin = (struct sockaddr_in6 *) uaddr;
struct inet_sock *inet = inet_sk(sk);
struct ipv6_pinfo *np = inet6_sk(sk);
- struct in6_addr *daddr, *final_p = NULL, final;
+ struct in6_addr *daddr, *final_p, final;
struct dst_entry *dst;
struct flowi fl;
struct ip6_flowlabel *flowlabel = NULL;
+ struct ipv6_txoptions *opt;
int addr_type;
int err;
@@ -155,19 +156,8 @@ ipv4_connected:
security_sk_classify_flow(sk, &fl);
- if (flowlabel) {
- if (flowlabel->opt && flowlabel->opt->srcrt) {
- struct rt0_hdr *rt0 = (struct rt0_hdr *) flowlabel->opt->srcrt;
- ipv6_addr_copy(&final, &fl.fl6_dst);
- ipv6_addr_copy(&fl.fl6_dst, rt0->addr);
- final_p = &final;
- }
- } else if (np->opt && np->opt->srcrt) {
- struct rt0_hdr *rt0 = (struct rt0_hdr *)np->opt->srcrt;
- ipv6_addr_copy(&final, &fl.fl6_dst);
- ipv6_addr_copy(&fl.fl6_dst, rt0->addr);
- final_p = &final;
- }
+ opt = flowlabel ? flowlabel->opt : np->opt;
+ final_p = fl6_update_dst(&fl, opt, &final);
err = ip6_dst_lookup(sk, &dst, &fl);
if (err)
diff --git a/net/ipv6/exthdrs.c b/net/ipv6/exthdrs.c
index 8a659f92d17..262f105d23b 100644
--- a/net/ipv6/exthdrs.c
+++ b/net/ipv6/exthdrs.c
@@ -312,6 +312,7 @@ static int ipv6_destopt_rcv(struct sk_buff *skb)
Routing header.
********************************/
+/* called with rcu_read_lock() */
static int ipv6_rthdr_rcv(struct sk_buff *skb)
{
struct inet6_skb_parm *opt = IP6CB(skb);
@@ -324,12 +325,9 @@ static int ipv6_rthdr_rcv(struct sk_buff *skb)
struct net *net = dev_net(skb->dev);
int accept_source_route = net->ipv6.devconf_all->accept_source_route;
- 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);
- }
+ idev = __in6_dev_get(skb->dev);
+ if (idev && accept_source_route > idev->cnf.accept_source_route)
+ accept_source_route = idev->cnf.accept_source_route;
if (!pskb_may_pull(skb, skb_transport_offset(skb) + 8) ||
!pskb_may_pull(skb, (skb_transport_offset(skb) +
@@ -874,3 +872,27 @@ struct ipv6_txoptions *ipv6_fixup_options(struct ipv6_txoptions *opt_space,
return opt;
}
+/**
+ * fl6_update_dst - update flowi destination address with info given
+ * by srcrt option, if any.
+ *
+ * @fl: flowi for which fl6_dst is to be updated
+ * @opt: struct ipv6_txoptions in which to look for srcrt opt
+ * @orig: copy of original fl6_dst address if modified
+ *
+ * Returns NULL if no txoptions or no srcrt, otherwise returns orig
+ * and initial value of fl->fl6_dst set in orig
+ */
+struct in6_addr *fl6_update_dst(struct flowi *fl,
+ const struct ipv6_txoptions *opt,
+ struct in6_addr *orig)
+{
+ if (!opt || !opt->srcrt)
+ return NULL;
+
+ ipv6_addr_copy(orig, &fl->fl6_dst);
+ ipv6_addr_copy(&fl->fl6_dst, ((struct rt0_hdr *)opt->srcrt)->addr);
+ return orig;
+}
+
+EXPORT_SYMBOL_GPL(fl6_update_dst);
diff --git a/net/ipv6/fib6_rules.c b/net/ipv6/fib6_rules.c
index 8e44f8f9c18..b1108ede18e 100644
--- a/net/ipv6/fib6_rules.c
+++ b/net/ipv6/fib6_rules.c
@@ -43,8 +43,8 @@ struct dst_entry *fib6_rule_lookup(struct net *net, struct flowi *fl,
if (arg.result)
return arg.result;
- dst_hold(&net->ipv6.ip6_null_entry->u.dst);
- return &net->ipv6.ip6_null_entry->u.dst;
+ dst_hold(&net->ipv6.ip6_null_entry->dst);
+ return &net->ipv6.ip6_null_entry->dst;
}
static int fib6_rule_action(struct fib_rule *rule, struct flowi *flp,
@@ -86,7 +86,7 @@ static int fib6_rule_action(struct fib_rule *rule, struct flowi *flp,
struct in6_addr saddr;
if (ipv6_dev_get_saddr(net,
- ip6_dst_idev(&rt->u.dst)->dev,
+ ip6_dst_idev(&rt->dst)->dev,
&flp->fl6_dst,
rt6_flags2srcprefs(flags),
&saddr))
@@ -99,12 +99,12 @@ static int fib6_rule_action(struct fib_rule *rule, struct flowi *flp,
goto out;
}
again:
- dst_release(&rt->u.dst);
+ dst_release(&rt->dst);
rt = NULL;
goto out;
discard_pkt:
- dst_hold(&rt->u.dst);
+ dst_hold(&rt->dst);
out:
arg->result = rt;
return rt == NULL ? -EAGAIN : 0;
diff --git a/net/ipv6/inet6_connection_sock.c b/net/ipv6/inet6_connection_sock.c
index 0c5e3c3b7fd..8a1628023bd 100644
--- a/net/ipv6/inet6_connection_sock.c
+++ b/net/ipv6/inet6_connection_sock.c
@@ -185,7 +185,7 @@ int inet6_csk_xmit(struct sk_buff *skb)
struct ipv6_pinfo *np = inet6_sk(sk);
struct flowi fl;
struct dst_entry *dst;
- struct in6_addr *final_p = NULL, final;
+ struct in6_addr *final_p, final;
memset(&fl, 0, sizeof(fl));
fl.proto = sk->sk_protocol;
@@ -199,12 +199,7 @@ int inet6_csk_xmit(struct sk_buff *skb)
fl.fl_ip_dport = inet->inet_dport;
security_sk_classify_flow(sk, &fl);
- if (np->opt && np->opt->srcrt) {
- struct rt0_hdr *rt0 = (struct rt0_hdr *)np->opt->srcrt;
- ipv6_addr_copy(&final, &fl.fl6_dst);
- ipv6_addr_copy(&fl.fl6_dst, rt0->addr);
- final_p = &final;
- }
+ final_p = fl6_update_dst(&fl, np->opt, &final);
dst = __inet6_csk_dst_check(sk, np->dst_cookie);
diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c
index 92a122b7795..b6a585909d3 100644
--- a/net/ipv6/ip6_fib.c
+++ b/net/ipv6/ip6_fib.c
@@ -165,7 +165,7 @@ static __inline__ void node_free(struct fib6_node * fn)
static __inline__ void rt6_release(struct rt6_info *rt)
{
if (atomic_dec_and_test(&rt->rt6i_ref))
- dst_free(&rt->u.dst);
+ dst_free(&rt->dst);
}
static void fib6_link_table(struct net *net, struct fib6_table *tb)
@@ -278,7 +278,7 @@ static int fib6_dump_node(struct fib6_walker_t *w)
int res;
struct rt6_info *rt;
- for (rt = w->leaf; rt; rt = rt->u.dst.rt6_next) {
+ for (rt = w->leaf; rt; rt = rt->dst.rt6_next) {
res = rt6_dump_route(rt, w->args);
if (res < 0) {
/* Frame is full, suspend walking */
@@ -619,7 +619,7 @@ static int fib6_add_rt2node(struct fib6_node *fn, struct rt6_info *rt,
ins = &fn->leaf;
- for (iter = fn->leaf; iter; iter=iter->u.dst.rt6_next) {
+ for (iter = fn->leaf; iter; iter=iter->dst.rt6_next) {
/*
* Search for duplicates
*/
@@ -647,7 +647,7 @@ static int fib6_add_rt2node(struct fib6_node *fn, struct rt6_info *rt,
if (iter->rt6i_metric > rt->rt6i_metric)
break;
- ins = &iter->u.dst.rt6_next;
+ ins = &iter->dst.rt6_next;
}
/* Reset round-robin state, if necessary */
@@ -658,7 +658,7 @@ static int fib6_add_rt2node(struct fib6_node *fn, struct rt6_info *rt,
* insert node
*/
- rt->u.dst.rt6_next = iter;
+ rt->dst.rt6_next = iter;
*ins = rt;
rt->rt6i_node = fn;
atomic_inc(&rt->rt6i_ref);
@@ -799,7 +799,7 @@ out:
atomic_inc(&pn->leaf->rt6i_ref);
}
#endif
- dst_free(&rt->u.dst);
+ dst_free(&rt->dst);
}
return err;
@@ -810,7 +810,7 @@ out:
st_failure:
if (fn && !(fn->fn_flags & (RTN_RTINFO|RTN_ROOT)))
fib6_repair_tree(info->nl_net, fn);
- dst_free(&rt->u.dst);
+ dst_free(&rt->dst);
return err;
#endif
}
@@ -1108,7 +1108,7 @@ static void fib6_del_route(struct fib6_node *fn, struct rt6_info **rtp,
RT6_TRACE("fib6_del_route\n");
/* Unlink it */
- *rtp = rt->u.dst.rt6_next;
+ *rtp = rt->dst.rt6_next;
rt->rt6i_node = NULL;
net->ipv6.rt6_stats->fib_rt_entries--;
net->ipv6.rt6_stats->fib_discarded_routes++;
@@ -1122,14 +1122,14 @@ static void fib6_del_route(struct fib6_node *fn, struct rt6_info **rtp,
FOR_WALKERS(w) {
if (w->state == FWS_C && w->leaf == rt) {
RT6_TRACE("walker %p adjusted by delroute\n", w);
- w->leaf = rt->u.dst.rt6_next;
+ w->leaf = rt->dst.rt6_next;
if (w->leaf == NULL)
w->state = FWS_U;
}
}
read_unlock(&fib6_walker_lock);
- rt->u.dst.rt6_next = NULL;
+ rt->dst.rt6_next = NULL;
/* If it was last route, expunge its radix tree node */
if (fn->leaf == NULL) {
@@ -1168,7 +1168,7 @@ int fib6_del(struct rt6_info *rt, struct nl_info *info)
struct rt6_info **rtp;
#if RT6_DEBUG >= 2
- if (rt->u.dst.obsolete>0) {
+ if (rt->dst.obsolete>0) {
WARN_ON(fn != NULL);
return -ENOENT;
}
@@ -1195,7 +1195,7 @@ int fib6_del(struct rt6_info *rt, struct nl_info *info)
* Walk the leaf entries looking for ourself
*/
- for (rtp = &fn->leaf; *rtp; rtp = &(*rtp)->u.dst.rt6_next) {
+ for (rtp = &fn->leaf; *rtp; rtp = &(*rtp)->dst.rt6_next) {
if (*rtp == rt) {
fib6_del_route(fn, rtp, info);
return 0;
@@ -1334,7 +1334,7 @@ static int fib6_clean_node(struct fib6_walker_t *w)
.nl_net = c->net,
};
- for (rt = w->leaf; rt; rt = rt->u.dst.rt6_next) {
+ for (rt = w->leaf; rt; rt = rt->dst.rt6_next) {
res = c->func(rt, c->arg);
if (res < 0) {
w->leaf = rt;
@@ -1448,8 +1448,8 @@ static int fib6_age(struct rt6_info *rt, void *arg)
}
gc_args.more++;
} else if (rt->rt6i_flags & RTF_CACHE) {
- if (atomic_read(&rt->u.dst.__refcnt) == 0 &&
- time_after_eq(now, rt->u.dst.lastuse + gc_args.timeout)) {
+ if (atomic_read(&rt->dst.__refcnt) == 0 &&
+ time_after_eq(now, rt->dst.lastuse + gc_args.timeout)) {
RT6_TRACE("aging clone %p\n", rt);
return -1;
} else if ((rt->rt6i_flags & RTF_GATEWAY) &&
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
index 89425af0684..d40b330c0ee 100644
--- a/net/ipv6/ip6_output.c
+++ b/net/ipv6/ip6_output.c
@@ -698,7 +698,7 @@ static int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *))
ipv6_hdr(skb)->payload_len = htons(first_len -
sizeof(struct ipv6hdr));
- dst_hold(&rt->u.dst);
+ dst_hold(&rt->dst);
for (;;) {
/* Prepare header of the next frame,
@@ -726,7 +726,7 @@ static int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *))
err = output(skb);
if(!err)
- IP6_INC_STATS(net, ip6_dst_idev(&rt->u.dst),
+ IP6_INC_STATS(net, ip6_dst_idev(&rt->dst),
IPSTATS_MIB_FRAGCREATES);
if (err || !frag)
@@ -740,9 +740,9 @@ static int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *))
kfree(tmp_hdr);
if (err == 0) {
- IP6_INC_STATS(net, ip6_dst_idev(&rt->u.dst),
+ IP6_INC_STATS(net, ip6_dst_idev(&rt->dst),
IPSTATS_MIB_FRAGOKS);
- dst_release(&rt->u.dst);
+ dst_release(&rt->dst);
return 0;
}
@@ -752,9 +752,9 @@ static int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *))
frag = skb;
}
- IP6_INC_STATS(net, ip6_dst_idev(&rt->u.dst),
+ IP6_INC_STATS(net, ip6_dst_idev(&rt->dst),
IPSTATS_MIB_FRAGFAILS);
- dst_release(&rt->u.dst);
+ dst_release(&rt->dst);
return err;
}
@@ -785,7 +785,7 @@ slow_path:
* Allocate buffer.
*/
- if ((frag = alloc_skb(len+hlen+sizeof(struct frag_hdr)+LL_ALLOCATED_SPACE(rt->u.dst.dev), GFP_ATOMIC)) == NULL) {
+ if ((frag = alloc_skb(len+hlen+sizeof(struct frag_hdr)+LL_ALLOCATED_SPACE(rt->dst.dev), GFP_ATOMIC)) == NULL) {
NETDEBUG(KERN_INFO "IPv6: frag: no memory for new fragment!\n");
IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)),
IPSTATS_MIB_FRAGFAILS);
@@ -798,7 +798,7 @@ slow_path:
*/
ip6_copy_metadata(frag, skb);
- skb_reserve(frag, LL_RESERVED_SPACE(rt->u.dst.dev));
+ skb_reserve(frag, LL_RESERVED_SPACE(rt->dst.dev));
skb_put(frag, len + hlen + sizeof(struct frag_hdr));
skb_reset_network_header(frag);
fh = (struct frag_hdr *)(skb_network_header(frag) + hlen);
@@ -1156,24 +1156,24 @@ int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to,
/* need source address above miyazawa*/
}
- dst_hold(&rt->u.dst);
- inet->cork.dst = &rt->u.dst;
+ dst_hold(&rt->dst);
+ inet->cork.dst = &rt->dst;
inet->cork.fl = *fl;
np->cork.hop_limit = hlimit;
np->cork.tclass = tclass;
mtu = np->pmtudisc == IPV6_PMTUDISC_PROBE ?
- rt->u.dst.dev->mtu : dst_mtu(rt->u.dst.path);
+ rt->dst.dev->mtu : dst_mtu(rt->dst.path);
if (np->frag_size < mtu) {
if (np->frag_size)
mtu = np->frag_size;
}
inet->cork.fragsize = mtu;
- if (dst_allfrag(rt->u.dst.path))
+ if (dst_allfrag(rt->dst.path))
inet->cork.flags |= IPCORK_ALLFRAG;
inet->cork.length = 0;
sk->sk_sndmsg_page = NULL;
sk->sk_sndmsg_off = 0;
- exthdrlen = rt->u.dst.header_len + (opt ? opt->opt_flen : 0) -
+ exthdrlen = rt->dst.header_len + (opt ? opt->opt_flen : 0) -
rt->rt6i_nfheader_len;
length += exthdrlen;
transhdrlen += exthdrlen;
@@ -1186,7 +1186,7 @@ int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to,
mtu = inet->cork.fragsize;
}
- hh_len = LL_RESERVED_SPACE(rt->u.dst.dev);
+ hh_len = LL_RESERVED_SPACE(rt->dst.dev);
fragheaderlen = sizeof(struct ipv6hdr) + rt->rt6i_nfheader_len +
(opt ? opt->opt_nflen : 0);
@@ -1224,7 +1224,7 @@ int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to,
}
if (proto == IPPROTO_UDP &&
- (rt->u.dst.dev->features & NETIF_F_UFO)) {
+ (rt->dst.dev->features & NETIF_F_UFO)) {
err = ip6_ufo_append_data(sk, getfrag, from, length,
hh_len, fragheaderlen,
@@ -1270,7 +1270,7 @@ alloc_new_skb:
fraglen = datalen + fragheaderlen;
if ((flags & MSG_MORE) &&
- !(rt->u.dst.dev->features&NETIF_F_SG))
+ !(rt->dst.dev->features&NETIF_F_SG))
alloclen = mtu;
else
alloclen = datalen + fragheaderlen;
@@ -1281,7 +1281,7 @@ alloc_new_skb:
* because we have no idea if we're the last one.
*/
if (datalen == length + fraggap)
- alloclen += rt->u.dst.trailer_len;
+ alloclen += rt->dst.trailer_len;
/*
* We just reserve space for fragment header.
@@ -1358,7 +1358,7 @@ alloc_new_skb:
if (copy > length)
copy = length;
- if (!(rt->u.dst.dev->features&NETIF_F_SG)) {
+ if (!(rt->dst.dev->features&NETIF_F_SG)) {
unsigned int off;
off = skb->len;
@@ -1503,7 +1503,7 @@ int ip6_push_pending_frames(struct sock *sk)
skb->priority = sk->sk_priority;
skb->mark = sk->sk_mark;
- skb_dst_set(skb, dst_clone(&rt->u.dst));
+ skb_dst_set(skb, dst_clone(&rt->dst));
IP6_UPD_PO_STATS(net, rt->rt6i_idev, IPSTATS_MIB_OUT, skb->len);
if (proto == IPPROTO_ICMPV6) {
struct inet6_dev *idev = ip6_dst_idev(skb_dst(skb));
diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c
index 8f39893d808..0fd027f3f47 100644
--- a/net/ipv6/ip6_tunnel.c
+++ b/net/ipv6/ip6_tunnel.c
@@ -552,7 +552,7 @@ ip4ip6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
if (ip_route_output_key(dev_net(skb->dev), &rt, &fl))
goto out;
- skb2->dev = rt->u.dst.dev;
+ skb2->dev = rt->dst.dev;
/* route "incoming" packet */
if (rt->rt_flags & RTCF_LOCAL) {
@@ -562,7 +562,7 @@ ip4ip6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
fl.fl4_src = eiph->saddr;
fl.fl4_tos = eiph->tos;
if (ip_route_output_key(dev_net(skb->dev), &rt, &fl) ||
- rt->u.dst.dev->type != ARPHRD_TUNNEL) {
+ rt->dst.dev->type != ARPHRD_TUNNEL) {
ip_rt_put(rt);
goto out;
}
@@ -626,7 +626,7 @@ ip6ip6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
icmpv6_send(skb2, rel_type, rel_code, rel_info);
if (rt)
- dst_release(&rt->u.dst);
+ dst_release(&rt->dst);
kfree_skb(skb2);
}
@@ -1135,7 +1135,7 @@ static void ip6_tnl_link_config(struct ip6_tnl *t)
if (dev->mtu < IPV6_MIN_MTU)
dev->mtu = IPV6_MIN_MTU;
}
- dst_release(&rt->u.dst);
+ dst_release(&rt->dst);
}
}
diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c
index bd43f0152c2..a7f66bc8f0b 100644
--- a/net/ipv6/ipv6_sockglue.c
+++ b/net/ipv6/ipv6_sockglue.c
@@ -55,8 +55,6 @@
#include <asm/uaccess.h>
-DEFINE_SNMP_STAT(struct ipstats_mib, ipv6_statistics) __read_mostly;
-
struct ip6_ra_chain *ip6_ra_chain;
DEFINE_RWLOCK(ip6_ra_lock);
diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c
index ab1622d7d40..d1444b95ad7 100644
--- a/net/ipv6/mcast.c
+++ b/net/ipv6/mcast.c
@@ -152,18 +152,19 @@ int ipv6_sock_mc_join(struct sock *sk, int ifindex, const struct in6_addr *addr)
mc_lst->next = NULL;
ipv6_addr_copy(&mc_lst->addr, addr);
+ rcu_read_lock();
if (ifindex == 0) {
struct rt6_info *rt;
rt = rt6_lookup(net, addr, NULL, 0, 0);
if (rt) {
dev = rt->rt6i_dev;
- dev_hold(dev);
- dst_release(&rt->u.dst);
+ dst_release(&rt->dst);
}
} else
- dev = dev_get_by_index(net, ifindex);
+ dev = dev_get_by_index_rcu(net, ifindex);
if (dev == NULL) {
+ rcu_read_unlock();
sock_kfree_s(sk, mc_lst, sizeof(*mc_lst));
return -ENODEV;
}
@@ -180,8 +181,8 @@ int ipv6_sock_mc_join(struct sock *sk, int ifindex, const struct in6_addr *addr)
err = ipv6_dev_mc_inc(dev, addr);
if (err) {
+ rcu_read_unlock();
sock_kfree_s(sk, mc_lst, sizeof(*mc_lst));
- dev_put(dev);
return err;
}
@@ -190,7 +191,7 @@ int ipv6_sock_mc_join(struct sock *sk, int ifindex, const struct in6_addr *addr)
np->ipv6_mc_list = mc_lst;
write_unlock_bh(&ipv6_sk_mc_lock);
- dev_put(dev);
+ rcu_read_unlock();
return 0;
}
@@ -213,18 +214,17 @@ int ipv6_sock_mc_drop(struct sock *sk, int ifindex, const struct in6_addr *addr)
*lnk = mc_lst->next;
write_unlock_bh(&ipv6_sk_mc_lock);
- dev = dev_get_by_index(net, mc_lst->ifindex);
+ rcu_read_lock();
+ dev = dev_get_by_index_rcu(net, mc_lst->ifindex);
if (dev != NULL) {
- struct inet6_dev *idev = in6_dev_get(dev);
+ struct inet6_dev *idev = __in6_dev_get(dev);
(void) ip6_mc_leave_src(sk, mc_lst, idev);
- if (idev) {
+ if (idev)
__ipv6_dev_mc_dec(idev, &mc_lst->addr);
- in6_dev_put(idev);
- }
- dev_put(dev);
} else
(void) ip6_mc_leave_src(sk, mc_lst, NULL);
+ rcu_read_unlock();
sock_kfree_s(sk, mc_lst, sizeof(*mc_lst));
return 0;
}
@@ -234,43 +234,36 @@ int ipv6_sock_mc_drop(struct sock *sk, int ifindex, const struct in6_addr *addr)
return -EADDRNOTAVAIL;
}
-static struct inet6_dev *ip6_mc_find_dev(struct net *net,
- struct in6_addr *group,
- int ifindex)
+/* called with rcu_read_lock() */
+static struct inet6_dev *ip6_mc_find_dev_rcu(struct net *net,
+ struct in6_addr *group,
+ int ifindex)
{
struct net_device *dev = NULL;
struct inet6_dev *idev = NULL;
if (ifindex == 0) {
- struct rt6_info *rt;
+ struct rt6_info *rt = rt6_lookup(net, group, NULL, 0, 0);
- rt = rt6_lookup(net, group, NULL, 0, 0);
if (rt) {
dev = rt->rt6i_dev;
dev_hold(dev);
- dst_release(&rt->u.dst);
+ dst_release(&rt->dst);
}
} else
- dev = dev_get_by_index(net, ifindex);
+ dev = dev_get_by_index_rcu(net, ifindex);
if (!dev)
- goto nodev;
- idev = in6_dev_get(dev);
+ return NULL;
+ idev = __in6_dev_get(dev);
if (!idev)
- goto release;
+ return NULL;;
read_lock_bh(&idev->lock);
- if (idev->dead)
- goto unlock_release;
-
+ if (idev->dead) {
+ read_unlock_bh(&idev->lock);
+ return NULL;
+ }
return idev;
-
-unlock_release:
- read_unlock_bh(&idev->lock);
- in6_dev_put(idev);
-release:
- dev_put(dev);
-nodev:
- return NULL;
}
void ipv6_sock_mc_close(struct sock *sk)
@@ -286,19 +279,17 @@ void ipv6_sock_mc_close(struct sock *sk)
np->ipv6_mc_list = mc_lst->next;
write_unlock_bh(&ipv6_sk_mc_lock);
- dev = dev_get_by_index(net, mc_lst->ifindex);
+ rcu_read_lock();
+ dev = dev_get_by_index_rcu(net, mc_lst->ifindex);
if (dev) {
- struct inet6_dev *idev = in6_dev_get(dev);
+ struct inet6_dev *idev = __in6_dev_get(dev);
(void) ip6_mc_leave_src(sk, mc_lst, idev);
- if (idev) {
+ if (idev)
__ipv6_dev_mc_dec(idev, &mc_lst->addr);
- in6_dev_put(idev);
- }
- dev_put(dev);
} else
(void) ip6_mc_leave_src(sk, mc_lst, NULL);
-
+ rcu_read_unlock();
sock_kfree_s(sk, mc_lst, sizeof(*mc_lst));
write_lock_bh(&ipv6_sk_mc_lock);
@@ -327,14 +318,17 @@ int ip6_mc_source(int add, int omode, struct sock *sk,
if (!ipv6_addr_is_multicast(group))
return -EINVAL;
- idev = ip6_mc_find_dev(net, group, pgsr->gsr_interface);
- if (!idev)
+ rcu_read_lock();
+ idev = ip6_mc_find_dev_rcu(net, group, pgsr->gsr_interface);
+ if (!idev) {
+ rcu_read_unlock();
return -ENODEV;
+ }
dev = idev->dev;
err = -EADDRNOTAVAIL;
- read_lock_bh(&ipv6_sk_mc_lock);
+ read_lock(&ipv6_sk_mc_lock);
for (pmc=inet6->ipv6_mc_list; pmc; pmc=pmc->next) {
if (pgsr->gsr_interface && pmc->ifindex != pgsr->gsr_interface)
continue;
@@ -358,7 +352,7 @@ int ip6_mc_source(int add, int omode, struct sock *sk,
pmc->sfmode = omode;
}
- write_lock_bh(&pmc->sflock);
+ write_lock(&pmc->sflock);
pmclocked = 1;
psl = pmc->sflist;
@@ -433,11 +427,10 @@ int ip6_mc_source(int add, int omode, struct sock *sk,
ip6_mc_add_src(idev, group, omode, 1, source, 1);
done:
if (pmclocked)
- write_unlock_bh(&pmc->sflock);
- read_unlock_bh(&ipv6_sk_mc_lock);
+ write_unlock(&pmc->sflock);
+ read_unlock(&ipv6_sk_mc_lock);
read_unlock_bh(&idev->lock);
- in6_dev_put(idev);
- dev_put(dev);
+ rcu_read_unlock();
if (leavegroup)
return ipv6_sock_mc_drop(sk, pgsr->gsr_interface, group);
return err;
@@ -463,14 +456,17 @@ int ip6_mc_msfilter(struct sock *sk, struct group_filter *gsf)
gsf->gf_fmode != MCAST_EXCLUDE)
return -EINVAL;
- idev = ip6_mc_find_dev(net, group, gsf->gf_interface);
+ rcu_read_lock();
+ idev = ip6_mc_find_dev_rcu(net, group, gsf->gf_interface);
- if (!idev)
+ if (!idev) {
+ rcu_read_unlock();
return -ENODEV;
+ }
dev = idev->dev;
err = 0;
- read_lock_bh(&ipv6_sk_mc_lock);
+ read_lock(&ipv6_sk_mc_lock);
if (gsf->gf_fmode == MCAST_INCLUDE && gsf->gf_numsrc == 0) {
leavegroup = 1;
@@ -512,7 +508,7 @@ int ip6_mc_msfilter(struct sock *sk, struct group_filter *gsf)
(void) ip6_mc_add_src(idev, group, gsf->gf_fmode, 0, NULL, 0);
}
- write_lock_bh(&pmc->sflock);
+ write_lock(&pmc->sflock);
psl = pmc->sflist;
if (psl) {
(void) ip6_mc_del_src(idev, group, pmc->sfmode,
@@ -522,13 +518,12 @@ int ip6_mc_msfilter(struct sock *sk, struct group_filter *gsf)
(void) ip6_mc_del_src(idev, group, pmc->sfmode, 0, NULL, 0);
pmc->sflist = newpsl;
pmc->sfmode = gsf->gf_fmode;
- write_unlock_bh(&pmc->sflock);
+ write_unlock(&pmc->sflock);
err = 0;
done:
- read_unlock_bh(&ipv6_sk_mc_lock);
+ read_unlock(&ipv6_sk_mc_lock);
read_unlock_bh(&idev->lock);
- in6_dev_put(idev);
- dev_put(dev);
+ rcu_read_unlock();
if (leavegroup)
err = ipv6_sock_mc_drop(sk, gsf->gf_interface, group);
return err;
@@ -551,11 +546,13 @@ int ip6_mc_msfget(struct sock *sk, struct group_filter *gsf,
if (!ipv6_addr_is_multicast(group))
return -EINVAL;
- idev = ip6_mc_find_dev(net, group, gsf->gf_interface);
+ rcu_read_lock();
+ idev = ip6_mc_find_dev_rcu(net, group, gsf->gf_interface);
- if (!idev)
+ if (!idev) {
+ rcu_read_unlock();
return -ENODEV;
-
+ }
dev = idev->dev;
err = -EADDRNOTAVAIL;
@@ -577,8 +574,7 @@ int ip6_mc_msfget(struct sock *sk, struct group_filter *gsf,
psl = pmc->sflist;
count = psl ? psl->sl_count : 0;
read_unlock_bh(&idev->lock);
- in6_dev_put(idev);
- dev_put(dev);
+ rcu_read_unlock();
copycount = count < gsf->gf_numsrc ? count : gsf->gf_numsrc;
gsf->gf_numsrc = count;
@@ -604,8 +600,7 @@ int ip6_mc_msfget(struct sock *sk, struct group_filter *gsf,
return 0;
done:
read_unlock_bh(&idev->lock);
- in6_dev_put(idev);
- dev_put(dev);
+ rcu_read_unlock();
return err;
}
@@ -822,6 +817,7 @@ int ipv6_dev_mc_inc(struct net_device *dev, const struct in6_addr *addr)
struct ifmcaddr6 *mc;
struct inet6_dev *idev;
+ /* we need to take a reference on idev */
idev = in6_dev_get(dev);
if (idev == NULL)
@@ -860,7 +856,7 @@ int ipv6_dev_mc_inc(struct net_device *dev, const struct in6_addr *addr)
setup_timer(&mc->mca_timer, igmp6_timer_handler, (unsigned long)mc);
ipv6_addr_copy(&mc->mca_addr, addr);
- mc->idev = idev;
+ mc->idev = idev; /* (reference taken) */
mc->mca_users = 1;
/* mca_stamp should be updated upon changes */
mc->mca_cstamp = mc->mca_tstamp = jiffies;
@@ -915,16 +911,18 @@ int __ipv6_dev_mc_dec(struct inet6_dev *idev, const struct in6_addr *addr)
int ipv6_dev_mc_dec(struct net_device *dev, const struct in6_addr *addr)
{
- struct inet6_dev *idev = in6_dev_get(dev);
+ struct inet6_dev *idev;
int err;
- if (!idev)
- return -ENODEV;
-
- err = __ipv6_dev_mc_dec(idev, addr);
+ rcu_read_lock();
- in6_dev_put(idev);
+ idev = __in6_dev_get(dev);
+ if (!idev)
+ err = -ENODEV;
+ else
+ err = __ipv6_dev_mc_dec(idev, addr);
+ rcu_read_unlock();
return err;
}
@@ -965,7 +963,8 @@ int ipv6_chk_mcast_addr(struct net_device *dev, const struct in6_addr *group,
struct ifmcaddr6 *mc;
int rv = 0;
- idev = in6_dev_get(dev);
+ rcu_read_lock();
+ idev = __in6_dev_get(dev);
if (idev) {
read_lock_bh(&idev->lock);
for (mc = idev->mc_list; mc; mc=mc->next) {
@@ -992,8 +991,8 @@ int ipv6_chk_mcast_addr(struct net_device *dev, const struct in6_addr *group,
rv = 1; /* don't filter unspecified source */
}
read_unlock_bh(&idev->lock);
- in6_dev_put(idev);
}
+ rcu_read_unlock();
return rv;
}
@@ -1104,6 +1103,7 @@ static int mld_marksources(struct ifmcaddr6 *pmc, int nsrcs,
return 1;
}
+/* called with rcu_read_lock() */
int igmp6_event_query(struct sk_buff *skb)
{
struct mld2_query *mlh2 = NULL;
@@ -1127,7 +1127,7 @@ int igmp6_event_query(struct sk_buff *skb)
if (!(ipv6_addr_type(&ipv6_hdr(skb)->saddr) & IPV6_ADDR_LINKLOCAL))
return -EINVAL;
- idev = in6_dev_get(skb->dev);
+ idev = __in6_dev_get(skb->dev);
if (idev == NULL)
return 0;
@@ -1137,10 +1137,8 @@ int igmp6_event_query(struct sk_buff *skb)
group_type = ipv6_addr_type(group);
if (group_type != IPV6_ADDR_ANY &&
- !(group_type&IPV6_ADDR_MULTICAST)) {
- in6_dev_put(idev);
+ !(group_type&IPV6_ADDR_MULTICAST))
return -EINVAL;
- }
if (len == 24) {
int switchback;
@@ -1161,10 +1159,9 @@ int igmp6_event_query(struct sk_buff *skb)
} else if (len >= 28) {
int srcs_offset = sizeof(struct mld2_query) -
sizeof(struct icmp6hdr);
- if (!pskb_may_pull(skb, srcs_offset)) {
- in6_dev_put(idev);
+ if (!pskb_may_pull(skb, srcs_offset))
return -EINVAL;
- }
+
mlh2 = (struct mld2_query *)skb_transport_header(skb);
max_delay = (MLDV2_MRC(ntohs(mlh2->mld2q_mrc))*HZ)/1000;
if (!max_delay)
@@ -1173,28 +1170,23 @@ int igmp6_event_query(struct sk_buff *skb)
if (mlh2->mld2q_qrv)
idev->mc_qrv = mlh2->mld2q_qrv;
if (group_type == IPV6_ADDR_ANY) { /* general query */
- if (mlh2->mld2q_nsrcs) {
- in6_dev_put(idev);
+ if (mlh2->mld2q_nsrcs)
return -EINVAL; /* no sources allowed */
- }
+
mld_gq_start_timer(idev);
- in6_dev_put(idev);
return 0;
}
/* mark sources to include, if group & source-specific */
if (mlh2->mld2q_nsrcs != 0) {
if (!pskb_may_pull(skb, srcs_offset +
- ntohs(mlh2->mld2q_nsrcs) * sizeof(struct in6_addr))) {
- in6_dev_put(idev);
+ ntohs(mlh2->mld2q_nsrcs) * sizeof(struct in6_addr)))
return -EINVAL;
- }
+
mlh2 = (struct mld2_query *)skb_transport_header(skb);
mark = 1;
}
- } else {
- in6_dev_put(idev);
+ } else
return -EINVAL;
- }
read_lock_bh(&idev->lock);
if (group_type == IPV6_ADDR_ANY) {
@@ -1227,12 +1219,11 @@ int igmp6_event_query(struct sk_buff *skb)
}
}
read_unlock_bh(&idev->lock);
- in6_dev_put(idev);
return 0;
}
-
+/* called with rcu_read_lock() */
int igmp6_event_report(struct sk_buff *skb)
{
struct ifmcaddr6 *ma;
@@ -1260,7 +1251,7 @@ int igmp6_event_report(struct sk_buff *skb)
!(addr_type&IPV6_ADDR_LINKLOCAL))
return -EINVAL;
- idev = in6_dev_get(skb->dev);
+ idev = __in6_dev_get(skb->dev);
if (idev == NULL)
return -ENODEV;
@@ -1280,7 +1271,6 @@ int igmp6_event_report(struct sk_buff *skb)
}
}
read_unlock_bh(&idev->lock);
- in6_dev_put(idev);
return 0;
}
@@ -1396,12 +1386,14 @@ static void mld_sendpack(struct sk_buff *skb)
struct mld2_report *pmr =
(struct mld2_report *)skb_transport_header(skb);
int payload_len, mldlen;
- struct inet6_dev *idev = in6_dev_get(skb->dev);
+ struct inet6_dev *idev;
struct net *net = dev_net(skb->dev);
int err;
struct flowi fl;
struct dst_entry *dst;
+ rcu_read_lock();
+ idev = __in6_dev_get(skb->dev);
IP6_UPD_PO_STATS(net, idev, IPSTATS_MIB_OUT, skb->len);
payload_len = (skb->tail - skb->network_header) - sizeof(*pip6);
@@ -1441,8 +1433,7 @@ out:
} else
IP6_INC_STATS_BH(net, idev, IPSTATS_MIB_OUTDISCARDS);
- if (likely(idev != NULL))
- in6_dev_put(idev);
+ rcu_read_unlock();
return;
err_out:
@@ -1779,7 +1770,8 @@ static void igmp6_send(struct in6_addr *addr, struct net_device *dev, int type)
IPPROTO_ICMPV6,
csum_partial(hdr, len, 0));
- idev = in6_dev_get(skb->dev);
+ rcu_read_lock();
+ idev = __in6_dev_get(skb->dev);
dst = icmp6_dst_alloc(skb->dev, NULL, &ipv6_hdr(skb)->daddr);
if (!dst) {
@@ -1806,8 +1798,7 @@ out:
} else
IP6_INC_STATS(net, idev, IPSTATS_MIB_OUTDISCARDS);
- if (likely(idev != NULL))
- in6_dev_put(idev);
+ rcu_read_unlock();
return;
err_out:
@@ -1998,8 +1989,7 @@ static int sf_setstate(struct ifmcaddr6 *pmc)
&psf->sf_addr))
break;
if (!dpsf) {
- dpsf = (struct ip6_sf_list *)
- kmalloc(sizeof(*dpsf), GFP_ATOMIC);
+ dpsf = kmalloc(sizeof(*dpsf), GFP_ATOMIC);
if (!dpsf)
continue;
*dpsf = *psf;
diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c
index 2efef52fb46..58841c4ae94 100644
--- a/net/ipv6/ndisc.c
+++ b/net/ipv6/ndisc.c
@@ -1229,7 +1229,7 @@ static void ndisc_router_discovery(struct sk_buff *skb)
ND_PRINTK0(KERN_ERR
"ICMPv6 RA: %s() got default router without neighbour.\n",
__func__);
- dst_release(&rt->u.dst);
+ dst_release(&rt->dst);
in6_dev_put(in6_dev);
return;
}
@@ -1244,7 +1244,7 @@ static void ndisc_router_discovery(struct sk_buff *skb)
if (ra_msg->icmph.icmp6_hop_limit) {
in6_dev->cnf.hop_limit = ra_msg->icmph.icmp6_hop_limit;
if (rt)
- rt->u.dst.metrics[RTAX_HOPLIMIT-1] = ra_msg->icmph.icmp6_hop_limit;
+ rt->dst.metrics[RTAX_HOPLIMIT-1] = ra_msg->icmph.icmp6_hop_limit;
}
skip_defrtr:
@@ -1363,7 +1363,7 @@ skip_linkparms:
in6_dev->cnf.mtu6 = mtu;
if (rt)
- rt->u.dst.metrics[RTAX_MTU-1] = mtu;
+ rt->dst.metrics[RTAX_MTU-1] = mtu;
rt6_mtu_change(skb->dev, mtu);
}
@@ -1384,7 +1384,7 @@ skip_linkparms:
}
out:
if (rt)
- dst_release(&rt->u.dst);
+ dst_release(&rt->dst);
else if (neigh)
neigh_release(neigh);
in6_dev_put(in6_dev);
diff --git a/net/ipv6/netfilter.c b/net/ipv6/netfilter.c
index a74951c039b..7155b2451d7 100644
--- a/net/ipv6/netfilter.c
+++ b/net/ipv6/netfilter.c
@@ -151,9 +151,7 @@ static __sum16 nf_ip6_checksum_partial(struct sk_buff *skb, unsigned int hook,
protocol,
csum_sub(0, hsum)));
skb->ip_summed = CHECKSUM_NONE;
- csum = __skb_checksum_complete_head(skb, dataoff + len);
- if (!csum)
- skb->ip_summed = CHECKSUM_UNNECESSARY;
+ return __skb_checksum_complete_head(skb, dataoff + len);
}
return csum;
};
diff --git a/net/ipv6/netfilter/ip6_queue.c b/net/ipv6/netfilter/ip6_queue.c
index 8c201743d96..413ab0754e1 100644
--- a/net/ipv6/netfilter/ip6_queue.c
+++ b/net/ipv6/netfilter/ip6_queue.c
@@ -43,7 +43,7 @@ typedef int (*ipq_cmpfn)(struct nf_queue_entry *, unsigned long);
static unsigned char copy_mode __read_mostly = IPQ_COPY_NONE;
static unsigned int queue_maxlen __read_mostly = IPQ_QMAX_DEFAULT;
-static DEFINE_RWLOCK(queue_lock);
+static DEFINE_SPINLOCK(queue_lock);
static int peer_pid __read_mostly;
static unsigned int copy_range __read_mostly;
static unsigned int queue_total;
@@ -73,10 +73,10 @@ __ipq_set_mode(unsigned char mode, unsigned int range)
break;
case IPQ_COPY_PACKET:
- copy_mode = mode;
+ if (range > 0xFFFF)
+ range = 0xFFFF;
copy_range = range;
- if (copy_range > 0xFFFF)
- copy_range = 0xFFFF;
+ copy_mode = mode;
break;
default:
@@ -102,7 +102,7 @@ ipq_find_dequeue_entry(unsigned long id)
{
struct nf_queue_entry *entry = NULL, *i;
- write_lock_bh(&queue_lock);
+ spin_lock_bh(&queue_lock);
list_for_each_entry(i, &queue_list, list) {
if ((unsigned long)i == id) {
@@ -116,7 +116,7 @@ ipq_find_dequeue_entry(unsigned long id)
queue_total--;
}
- write_unlock_bh(&queue_lock);
+ spin_unlock_bh(&queue_lock);
return entry;
}
@@ -137,9 +137,9 @@ __ipq_flush(ipq_cmpfn cmpfn, unsigned long data)
static void
ipq_flush(ipq_cmpfn cmpfn, unsigned long data)
{
- write_lock_bh(&queue_lock);
+ spin_lock_bh(&queue_lock);
__ipq_flush(cmpfn, data);
- write_unlock_bh(&queue_lock);
+ spin_unlock_bh(&queue_lock);
}
static struct sk_buff *
@@ -153,9 +153,7 @@ ipq_build_packet_message(struct nf_queue_entry *entry, int *errp)
struct nlmsghdr *nlh;
struct timeval tv;
- read_lock_bh(&queue_lock);
-
- switch (copy_mode) {
+ switch (ACCESS_ONCE(copy_mode)) {
case IPQ_COPY_META:
case IPQ_COPY_NONE:
size = NLMSG_SPACE(sizeof(*pmsg));
@@ -163,26 +161,21 @@ ipq_build_packet_message(struct nf_queue_entry *entry, int *errp)
case IPQ_COPY_PACKET:
if (entry->skb->ip_summed == CHECKSUM_PARTIAL &&
- (*errp = skb_checksum_help(entry->skb))) {
- read_unlock_bh(&queue_lock);
+ (*errp = skb_checksum_help(entry->skb)))
return NULL;
- }
- if (copy_range == 0 || copy_range > entry->skb->len)
+
+ data_len = ACCESS_ONCE(copy_range);
+ if (data_len == 0 || data_len > entry->skb->len)
data_len = entry->skb->len;
- else
- data_len = copy_range;
size = NLMSG_SPACE(sizeof(*pmsg) + data_len);
break;
default:
*errp = -EINVAL;
- read_unlock_bh(&queue_lock);
return NULL;
}
- read_unlock_bh(&queue_lock);
-
skb = alloc_skb(size, GFP_ATOMIC);
if (!skb)
goto nlmsg_failure;
@@ -242,7 +235,7 @@ ipq_enqueue_packet(struct nf_queue_entry *entry, unsigned int queuenum)
if (nskb == NULL)
return status;
- write_lock_bh(&queue_lock);
+ spin_lock_bh(&queue_lock);
if (!peer_pid)
goto err_out_free_nskb;
@@ -266,14 +259,14 @@ ipq_enqueue_packet(struct nf_queue_entry *entry, unsigned int queuenum)
__ipq_enqueue_entry(entry);
- write_unlock_bh(&queue_lock);
+ spin_unlock_bh(&queue_lock);
return status;
err_out_free_nskb:
kfree_skb(nskb);
err_out_unlock:
- write_unlock_bh(&queue_lock);
+ spin_unlock_bh(&queue_lock);
return status;
}
@@ -342,9 +335,9 @@ ipq_set_mode(unsigned char mode, unsigned int range)
{
int status;
- write_lock_bh(&queue_lock);
+ spin_lock_bh(&queue_lock);
status = __ipq_set_mode(mode, range);
- write_unlock_bh(&queue_lock);
+ spin_unlock_bh(&queue_lock);
return status;
}
@@ -441,11 +434,11 @@ __ipq_rcv_skb(struct sk_buff *skb)
if (security_netlink_recv(skb, CAP_NET_ADMIN))
RCV_SKB_FAIL(-EPERM);
- write_lock_bh(&queue_lock);
+ spin_lock_bh(&queue_lock);
if (peer_pid) {
if (peer_pid != pid) {
- write_unlock_bh(&queue_lock);
+ spin_unlock_bh(&queue_lock);
RCV_SKB_FAIL(-EBUSY);
}
} else {
@@ -453,7 +446,7 @@ __ipq_rcv_skb(struct sk_buff *skb)
peer_pid = pid;
}
- write_unlock_bh(&queue_lock);
+ spin_unlock_bh(&queue_lock);
status = ipq_receive_peer(NLMSG_DATA(nlh), type,
nlmsglen - NLMSG_LENGTH(0));
@@ -498,10 +491,10 @@ ipq_rcv_nl_event(struct notifier_block *this,
struct netlink_notify *n = ptr;
if (event == NETLINK_URELEASE && n->protocol == NETLINK_IP6_FW) {
- write_lock_bh(&queue_lock);
+ spin_lock_bh(&queue_lock);
if ((net_eq(n->net, &init_net)) && (n->pid == peer_pid))
__ipq_reset();
- write_unlock_bh(&queue_lock);
+ spin_unlock_bh(&queue_lock);
}
return NOTIFY_DONE;
}
@@ -528,7 +521,7 @@ static ctl_table ipq_table[] = {
#ifdef CONFIG_PROC_FS
static int ip6_queue_show(struct seq_file *m, void *v)
{
- read_lock_bh(&queue_lock);
+ spin_lock_bh(&queue_lock);
seq_printf(m,
"Peer PID : %d\n"
@@ -546,7 +539,7 @@ static int ip6_queue_show(struct seq_file *m, void *v)
queue_dropped,
queue_user_dropped);
- read_unlock_bh(&queue_lock);
+ spin_unlock_bh(&queue_lock);
return 0;
}
diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c
index 9d2d68f0e60..5359ef4daac 100644
--- a/net/ipv6/netfilter/ip6_tables.c
+++ b/net/ipv6/netfilter/ip6_tables.c
@@ -387,9 +387,7 @@ ip6t_do_table(struct sk_buff *skb,
goto no_match;
}
- ADD_COUNTER(e->counters,
- ntohs(ipv6_hdr(skb)->payload_len) +
- sizeof(struct ipv6hdr), 1);
+ ADD_COUNTER(e->counters, skb->len, 1);
t = ip6t_get_target_c(e);
IP_NF_ASSERT(t->u.kernel.target);
@@ -899,7 +897,7 @@ get_counters(const struct xt_table_info *t,
struct ip6t_entry *iter;
unsigned int cpu;
unsigned int i;
- unsigned int curcpu;
+ unsigned int curcpu = get_cpu();
/* Instead of clearing (by a previous call to memset())
* the counters and using adds, we set the counters
@@ -909,14 +907,16 @@ get_counters(const struct xt_table_info *t,
* if new softirq were to run and call ipt_do_table
*/
local_bh_disable();
- curcpu = smp_processor_id();
-
i = 0;
xt_entry_foreach(iter, t->entries[curcpu], t->size) {
SET_COUNTER(counters[i], iter->counters.bcnt,
iter->counters.pcnt);
++i;
}
+ local_bh_enable();
+ /* Processing counters from other cpus, we can let bottom half enabled,
+ * (preemption is disabled)
+ */
for_each_possible_cpu(cpu) {
if (cpu == curcpu)
@@ -930,7 +930,7 @@ get_counters(const struct xt_table_info *t,
}
xt_info_wrunlock(cpu);
}
- local_bh_enable();
+ put_cpu();
}
static struct xt_counters *alloc_counters(const struct xt_table *table)
@@ -943,7 +943,7 @@ static struct xt_counters *alloc_counters(const struct xt_table *table)
(other than comefrom, which userspace doesn't care
about). */
countersize = sizeof(struct xt_counters) * private->number;
- counters = vmalloc_node(countersize, numa_node_id());
+ counters = vmalloc(countersize);
if (counters == NULL)
return ERR_PTR(-ENOMEM);
@@ -1213,8 +1213,7 @@ __do_replace(struct net *net, const char *name, unsigned int valid_hooks,
struct ip6t_entry *iter;
ret = 0;
- counters = vmalloc_node(num_counters * sizeof(struct xt_counters),
- numa_node_id());
+ counters = vmalloc(num_counters * sizeof(struct xt_counters));
if (!counters) {
ret = -ENOMEM;
goto out;
@@ -1368,7 +1367,7 @@ do_add_counters(struct net *net, const void __user *user, unsigned int len,
if (len != size + num_counters * sizeof(struct xt_counters))
return -EINVAL;
- paddc = vmalloc_node(len - size, numa_node_id());
+ paddc = vmalloc(len - size);
if (!paddc)
return -ENOMEM;
diff --git a/net/ipv6/netfilter/ip6t_LOG.c b/net/ipv6/netfilter/ip6t_LOG.c
index af4ee11f206..0a07ae7b933 100644
--- a/net/ipv6/netfilter/ip6t_LOG.c
+++ b/net/ipv6/netfilter/ip6t_LOG.c
@@ -373,6 +373,56 @@ static void dump_packet(const struct nf_loginfo *info,
printk("MARK=0x%x ", skb->mark);
}
+static void dump_mac_header(const struct nf_loginfo *info,
+ const struct sk_buff *skb)
+{
+ struct net_device *dev = skb->dev;
+ unsigned int logflags = 0;
+
+ if (info->type == NF_LOG_TYPE_LOG)
+ logflags = info->u.log.logflags;
+
+ if (!(logflags & IP6T_LOG_MACDECODE))
+ goto fallback;
+
+ switch (dev->type) {
+ case ARPHRD_ETHER:
+ printk("MACSRC=%pM MACDST=%pM MACPROTO=%04x ",
+ eth_hdr(skb)->h_source, eth_hdr(skb)->h_dest,
+ ntohs(eth_hdr(skb)->h_proto));
+ return;
+ default:
+ break;
+ }
+
+fallback:
+ printk("MAC=");
+ if (dev->hard_header_len &&
+ skb->mac_header != skb->network_header) {
+ const unsigned char *p = skb_mac_header(skb);
+ unsigned int len = dev->hard_header_len;
+ unsigned int i;
+
+ if (dev->type == ARPHRD_SIT &&
+ (p -= ETH_HLEN) < skb->head)
+ p = NULL;
+
+ if (p != NULL) {
+ printk("%02x", *p++);
+ for (i = 1; i < len; i++)
+ printk(":%02x", p[i]);
+ }
+ printk(" ");
+
+ if (dev->type == ARPHRD_SIT) {
+ const struct iphdr *iph =
+ (struct iphdr *)skb_mac_header(skb);
+ printk("TUNNEL=%pI4->%pI4 ", &iph->saddr, &iph->daddr);
+ }
+ } else
+ printk(" ");
+}
+
static struct nf_loginfo default_loginfo = {
.type = NF_LOG_TYPE_LOG,
.u = {
@@ -400,35 +450,10 @@ ip6t_log_packet(u_int8_t pf,
prefix,
in ? in->name : "",
out ? out->name : "");
- if (in && !out) {
- unsigned int len;
- /* MAC logging for input chain only. */
- printk("MAC=");
- if (skb->dev && (len = skb->dev->hard_header_len) &&
- skb->mac_header != skb->network_header) {
- const unsigned char *p = skb_mac_header(skb);
- int i;
-
- if (skb->dev->type == ARPHRD_SIT &&
- (p -= ETH_HLEN) < skb->head)
- p = NULL;
-
- if (p != NULL) {
- for (i = 0; i < len; i++)
- printk("%02x%s", p[i],
- i == len - 1 ? "" : ":");
- }
- printk(" ");
- if (skb->dev->type == ARPHRD_SIT) {
- const struct iphdr *iph =
- (struct iphdr *)skb_mac_header(skb);
- printk("TUNNEL=%pI4->%pI4 ",
- &iph->saddr, &iph->daddr);
- }
- } else
- printk(" ");
- }
+ /* MAC logging for input path only. */
+ if (in && !out)
+ dump_mac_header(loginfo, skb);
dump_packet(loginfo, skb, skb_network_offset(skb), 1);
printk("\n");
diff --git a/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c b/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c
index 9be81776415..1df3c8b6bf4 100644
--- a/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c
+++ b/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c
@@ -208,7 +208,7 @@ icmpv6_error(struct net *net, struct nf_conn *tmpl,
type = icmp6h->icmp6_type - 130;
if (type >= 0 && type < sizeof(noct_valid_new) &&
noct_valid_new[type]) {
- skb->nfct = &nf_conntrack_untracked.ct_general;
+ skb->nfct = &nf_ct_untracked_get()->ct_general;
skb->nfctinfo = IP_CT_NEW;
nf_conntrack_get(skb->nfct);
return NF_ACCEPT;
diff --git a/net/ipv6/netfilter/nf_conntrack_reasm.c b/net/ipv6/netfilter/nf_conntrack_reasm.c
index 6fb890187de..13ef5bc05cf 100644
--- a/net/ipv6/netfilter/nf_conntrack_reasm.c
+++ b/net/ipv6/netfilter/nf_conntrack_reasm.c
@@ -114,10 +114,8 @@ static void nf_skb_free(struct sk_buff *skb)
}
/* Memory Tracking Functions. */
-static inline void frag_kfree_skb(struct sk_buff *skb, unsigned int *work)
+static void frag_kfree_skb(struct sk_buff *skb)
{
- if (work)
- *work -= skb->truesize;
atomic_sub(skb->truesize, &nf_init_frags.mem);
nf_skb_free(skb);
kfree_skb(skb);
@@ -201,7 +199,7 @@ static int nf_ct_frag6_queue(struct nf_ct_frag6_queue *fq, struct sk_buff *skb,
int offset, end;
if (fq->q.last_in & INET_FRAG_COMPLETE) {
- pr_debug("Allready completed\n");
+ pr_debug("Already completed\n");
goto err;
}
@@ -271,6 +269,11 @@ static int nf_ct_frag6_queue(struct nf_ct_frag6_queue *fq, struct sk_buff *skb,
* in the chain of fragments so far. We must know where to put
* this fragment, right?
*/
+ prev = fq->q.fragments_tail;
+ if (!prev || NFCT_FRAG6_CB(prev)->offset < offset) {
+ next = NULL;
+ goto found;
+ }
prev = NULL;
for (next = fq->q.fragments; next != NULL; next = next->next) {
if (NFCT_FRAG6_CB(next)->offset >= offset)
@@ -278,6 +281,7 @@ static int nf_ct_frag6_queue(struct nf_ct_frag6_queue *fq, struct sk_buff *skb,
prev = next;
}
+found:
/* We found where to put this one. Check for overlap with
* preceding fragment, and, if needed, align things so that
* any overlaps are eliminated.
@@ -335,7 +339,7 @@ static int nf_ct_frag6_queue(struct nf_ct_frag6_queue *fq, struct sk_buff *skb,
fq->q.fragments = next;
fq->q.meat -= free_it->len;
- frag_kfree_skb(free_it, NULL);
+ frag_kfree_skb(free_it);
}
}
@@ -343,6 +347,8 @@ static int nf_ct_frag6_queue(struct nf_ct_frag6_queue *fq, struct sk_buff *skb,
/* Insert this fragment in the chain of fragments. */
skb->next = next;
+ if (!next)
+ fq->q.fragments_tail = skb;
if (prev)
prev->next = skb;
else
@@ -442,7 +448,6 @@ nf_ct_frag6_reasm(struct nf_ct_frag6_queue *fq, struct net_device *dev)
skb_shinfo(head)->frag_list = head->next;
skb_reset_transport_header(head);
skb_push(head, head->data - skb_network_header(head));
- atomic_sub(head->truesize, &nf_init_frags.mem);
for (fp=head->next; fp; fp = fp->next) {
head->data_len += fp->len;
@@ -452,8 +457,8 @@ nf_ct_frag6_reasm(struct nf_ct_frag6_queue *fq, struct net_device *dev)
else if (head->ip_summed == CHECKSUM_COMPLETE)
head->csum = csum_add(head->csum, fp->csum);
head->truesize += fp->truesize;
- atomic_sub(fp->truesize, &nf_init_frags.mem);
}
+ atomic_sub(head->truesize, &nf_init_frags.mem);
head->next = NULL;
head->dev = dev;
@@ -467,6 +472,7 @@ nf_ct_frag6_reasm(struct nf_ct_frag6_queue *fq, struct net_device *dev)
head->csum);
fq->q.fragments = NULL;
+ fq->q.fragments_tail = NULL;
/* all original skbs are linked into the NFCT_FRAG6_CB(head).orig */
fp = skb_shinfo(head)->frag_list;
diff --git a/net/ipv6/proc.c b/net/ipv6/proc.c
index 566798d69f3..d082eaeefa2 100644
--- a/net/ipv6/proc.c
+++ b/net/ipv6/proc.c
@@ -174,17 +174,28 @@ static void snmp6_seq_show_item(struct seq_file *seq, void __percpu **mib,
const struct snmp_mib *itemlist)
{
int i;
- for (i=0; itemlist[i].name; i++)
+
+ for (i = 0; itemlist[i].name; i++)
seq_printf(seq, "%-32s\t%lu\n", itemlist[i].name,
snmp_fold_field(mib, itemlist[i].entry));
}
+static void snmp6_seq_show_item64(struct seq_file *seq, void __percpu **mib,
+ const struct snmp_mib *itemlist, size_t syncpoff)
+{
+ int i;
+
+ for (i = 0; itemlist[i].name; i++)
+ seq_printf(seq, "%-32s\t%llu\n", itemlist[i].name,
+ snmp_fold_field64(mib, itemlist[i].entry, syncpoff));
+}
+
static int snmp6_seq_show(struct seq_file *seq, void *v)
{
struct net *net = (struct net *)seq->private;
- snmp6_seq_show_item(seq, (void __percpu **)net->mib.ipv6_statistics,
- snmp6_ipstats_list);
+ snmp6_seq_show_item64(seq, (void __percpu **)net->mib.ipv6_statistics,
+ snmp6_ipstats_list, offsetof(struct ipstats_mib, syncp));
snmp6_seq_show_item(seq, (void __percpu **)net->mib.icmpv6_statistics,
snmp6_icmp6_list);
snmp6_seq_show_icmpv6msg(seq,
diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c
index 4a4dcbe4f8b..e677937a07f 100644
--- a/net/ipv6/raw.c
+++ b/net/ipv6/raw.c
@@ -602,31 +602,33 @@ out:
}
static int rawv6_send_hdrinc(struct sock *sk, void *from, int length,
- struct flowi *fl, struct rt6_info *rt,
+ struct flowi *fl, struct dst_entry **dstp,
unsigned int flags)
{
struct ipv6_pinfo *np = inet6_sk(sk);
struct ipv6hdr *iph;
struct sk_buff *skb;
int err;
+ struct rt6_info *rt = (struct rt6_info *)*dstp;
- if (length > rt->u.dst.dev->mtu) {
- ipv6_local_error(sk, EMSGSIZE, fl, rt->u.dst.dev->mtu);
+ if (length > rt->dst.dev->mtu) {
+ ipv6_local_error(sk, EMSGSIZE, fl, rt->dst.dev->mtu);
return -EMSGSIZE;
}
if (flags&MSG_PROBE)
goto out;
skb = sock_alloc_send_skb(sk,
- length + LL_ALLOCATED_SPACE(rt->u.dst.dev) + 15,
+ length + LL_ALLOCATED_SPACE(rt->dst.dev) + 15,
flags & MSG_DONTWAIT, &err);
if (skb == NULL)
goto error;
- skb_reserve(skb, LL_RESERVED_SPACE(rt->u.dst.dev));
+ skb_reserve(skb, LL_RESERVED_SPACE(rt->dst.dev));
skb->priority = sk->sk_priority;
skb->mark = sk->sk_mark;
- skb_dst_set(skb, dst_clone(&rt->u.dst));
+ skb_dst_set(skb, &rt->dst);
+ *dstp = NULL;
skb_put(skb, length);
skb_reset_network_header(skb);
@@ -641,7 +643,7 @@ static int rawv6_send_hdrinc(struct sock *sk, void *from, int length,
IP6_UPD_PO_STATS(sock_net(sk), rt->rt6i_idev, IPSTATS_MIB_OUT, skb->len);
err = NF_HOOK(NFPROTO_IPV6, NF_INET_LOCAL_OUT, skb, NULL,
- rt->u.dst.dev, dst_output);
+ rt->dst.dev, dst_output);
if (err > 0)
err = net_xmit_errno(err);
if (err)
@@ -725,7 +727,7 @@ static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk,
{
struct ipv6_txoptions opt_space;
struct sockaddr_in6 * sin6 = (struct sockaddr_in6 *) msg->msg_name;
- struct in6_addr *daddr, *final_p = NULL, final;
+ struct in6_addr *daddr, *final_p, final;
struct inet_sock *inet = inet_sk(sk);
struct ipv6_pinfo *np = inet6_sk(sk);
struct raw6_sock *rp = raw6_sk(sk);
@@ -847,13 +849,7 @@ static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk,
if (ipv6_addr_any(&fl.fl6_src) && !ipv6_addr_any(&np->saddr))
ipv6_addr_copy(&fl.fl6_src, &np->saddr);
- /* merge ip6_build_xmit from ip6_output */
- if (opt && opt->srcrt) {
- struct rt0_hdr *rt0 = (struct rt0_hdr *) opt->srcrt;
- ipv6_addr_copy(&final, &fl.fl6_dst);
- ipv6_addr_copy(&fl.fl6_dst, rt0->addr);
- final_p = &final;
- }
+ final_p = fl6_update_dst(&fl, opt, &final);
if (!fl.oif && ipv6_addr_is_multicast(&fl.fl6_dst))
fl.oif = np->mcast_oif;
@@ -892,9 +888,9 @@ static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk,
goto do_confirm;
back_from_confirm:
- if (inet->hdrincl) {
- err = rawv6_send_hdrinc(sk, msg->msg_iov, len, &fl, (struct rt6_info*)dst, msg->msg_flags);
- } else {
+ if (inet->hdrincl)
+ err = rawv6_send_hdrinc(sk, msg->msg_iov, len, &fl, &dst, msg->msg_flags);
+ else {
lock_sock(sk);
err = ip6_append_data(sk, ip_generic_getfrag, msg->msg_iov,
len, 0, hlimit, tclass, opt, &fl, (struct rt6_info*)dst,
diff --git a/net/ipv6/reassembly.c b/net/ipv6/reassembly.c
index 6d4292ff585..545c4141b75 100644
--- a/net/ipv6/reassembly.c
+++ b/net/ipv6/reassembly.c
@@ -150,11 +150,8 @@ int ip6_frag_match(struct inet_frag_queue *q, void *a)
EXPORT_SYMBOL(ip6_frag_match);
/* Memory Tracking Functions. */
-static inline void frag_kfree_skb(struct netns_frags *nf,
- struct sk_buff *skb, int *work)
+static void frag_kfree_skb(struct netns_frags *nf, struct sk_buff *skb)
{
- if (work)
- *work -= skb->truesize;
atomic_sub(skb->truesize, &nf->mem);
kfree_skb(skb);
}
@@ -336,6 +333,11 @@ static int ip6_frag_queue(struct frag_queue *fq, struct sk_buff *skb,
* in the chain of fragments so far. We must know where to put
* this fragment, right?
*/
+ prev = fq->q.fragments_tail;
+ if (!prev || FRAG6_CB(prev)->offset < offset) {
+ next = NULL;
+ goto found;
+ }
prev = NULL;
for(next = fq->q.fragments; next != NULL; next = next->next) {
if (FRAG6_CB(next)->offset >= offset)
@@ -343,6 +345,7 @@ static int ip6_frag_queue(struct frag_queue *fq, struct sk_buff *skb,
prev = next;
}
+found:
/* We found where to put this one. Check for overlap with
* preceding fragment, and, if needed, align things so that
* any overlaps are eliminated.
@@ -392,7 +395,7 @@ static int ip6_frag_queue(struct frag_queue *fq, struct sk_buff *skb,
fq->q.fragments = next;
fq->q.meat -= free_it->len;
- frag_kfree_skb(fq->q.net, free_it, NULL);
+ frag_kfree_skb(fq->q.net, free_it);
}
}
@@ -400,6 +403,8 @@ static int ip6_frag_queue(struct frag_queue *fq, struct sk_buff *skb,
/* Insert this fragment in the chain of fragments. */
skb->next = next;
+ if (!next)
+ fq->q.fragments_tail = skb;
if (prev)
prev->next = skb;
else
@@ -466,6 +471,8 @@ static int ip6_frag_reasm(struct frag_queue *fq, struct sk_buff *prev,
goto out_oom;
fp->next = head->next;
+ if (!fp->next)
+ fq->q.fragments_tail = fp;
prev->next = fp;
skb_morph(head, fq->q.fragments);
@@ -524,7 +531,6 @@ static int ip6_frag_reasm(struct frag_queue *fq, struct sk_buff *prev,
skb_shinfo(head)->frag_list = head->next;
skb_reset_transport_header(head);
skb_push(head, head->data - skb_network_header(head));
- atomic_sub(head->truesize, &fq->q.net->mem);
for (fp=head->next; fp; fp = fp->next) {
head->data_len += fp->len;
@@ -534,8 +540,8 @@ static int ip6_frag_reasm(struct frag_queue *fq, struct sk_buff *prev,
else if (head->ip_summed == CHECKSUM_COMPLETE)
head->csum = csum_add(head->csum, fp->csum);
head->truesize += fp->truesize;
- atomic_sub(fp->truesize, &fq->q.net->mem);
}
+ atomic_sub(head->truesize, &fq->q.net->mem);
head->next = NULL;
head->dev = dev;
@@ -553,6 +559,7 @@ static int ip6_frag_reasm(struct frag_queue *fq, struct sk_buff *prev,
IP6_INC_STATS_BH(net, __in6_dev_get(dev), IPSTATS_MIB_REASMOKS);
rcu_read_unlock();
fq->q.fragments = NULL;
+ fq->q.fragments_tail = NULL;
return 1;
out_oversize:
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index 252d76199c4..8f2d0400cf8 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -126,16 +126,14 @@ static struct dst_ops ip6_dst_blackhole_ops = {
};
static struct rt6_info ip6_null_entry_template = {
- .u = {
- .dst = {
- .__refcnt = ATOMIC_INIT(1),
- .__use = 1,
- .obsolete = -1,
- .error = -ENETUNREACH,
- .metrics = { [RTAX_HOPLIMIT - 1] = 255, },
- .input = ip6_pkt_discard,
- .output = ip6_pkt_discard_out,
- }
+ .dst = {
+ .__refcnt = ATOMIC_INIT(1),
+ .__use = 1,
+ .obsolete = -1,
+ .error = -ENETUNREACH,
+ .metrics = { [RTAX_HOPLIMIT - 1] = 255, },
+ .input = ip6_pkt_discard,
+ .output = ip6_pkt_discard_out,
},
.rt6i_flags = (RTF_REJECT | RTF_NONEXTHOP),
.rt6i_protocol = RTPROT_KERNEL,
@@ -149,16 +147,14 @@ static int ip6_pkt_prohibit(struct sk_buff *skb);
static int ip6_pkt_prohibit_out(struct sk_buff *skb);
static struct rt6_info ip6_prohibit_entry_template = {
- .u = {
- .dst = {
- .__refcnt = ATOMIC_INIT(1),
- .__use = 1,
- .obsolete = -1,
- .error = -EACCES,
- .metrics = { [RTAX_HOPLIMIT - 1] = 255, },
- .input = ip6_pkt_prohibit,
- .output = ip6_pkt_prohibit_out,
- }
+ .dst = {
+ .__refcnt = ATOMIC_INIT(1),
+ .__use = 1,
+ .obsolete = -1,
+ .error = -EACCES,
+ .metrics = { [RTAX_HOPLIMIT - 1] = 255, },
+ .input = ip6_pkt_prohibit,
+ .output = ip6_pkt_prohibit_out,
},
.rt6i_flags = (RTF_REJECT | RTF_NONEXTHOP),
.rt6i_protocol = RTPROT_KERNEL,
@@ -167,16 +163,14 @@ static struct rt6_info ip6_prohibit_entry_template = {
};
static struct rt6_info ip6_blk_hole_entry_template = {
- .u = {
- .dst = {
- .__refcnt = ATOMIC_INIT(1),
- .__use = 1,
- .obsolete = -1,
- .error = -EINVAL,
- .metrics = { [RTAX_HOPLIMIT - 1] = 255, },
- .input = dst_discard,
- .output = dst_discard,
- }
+ .dst = {
+ .__refcnt = ATOMIC_INIT(1),
+ .__use = 1,
+ .obsolete = -1,
+ .error = -EINVAL,
+ .metrics = { [RTAX_HOPLIMIT - 1] = 255, },
+ .input = dst_discard,
+ .output = dst_discard,
},
.rt6i_flags = (RTF_REJECT | RTF_NONEXTHOP),
.rt6i_protocol = RTPROT_KERNEL,
@@ -249,7 +243,7 @@ static inline struct rt6_info *rt6_device_match(struct net *net,
if (!oif && ipv6_addr_any(saddr))
goto out;
- for (sprt = rt; sprt; sprt = sprt->u.dst.rt6_next) {
+ for (sprt = rt; sprt; sprt = sprt->dst.rt6_next) {
struct net_device *dev = sprt->rt6i_dev;
if (oif) {
@@ -407,10 +401,10 @@ static struct rt6_info *find_rr_leaf(struct fib6_node *fn,
match = NULL;
for (rt = rr_head; rt && rt->rt6i_metric == metric;
- rt = rt->u.dst.rt6_next)
+ rt = rt->dst.rt6_next)
match = find_match(rt, oif, strict, &mpri, match);
for (rt = fn->leaf; rt && rt != rr_head && rt->rt6i_metric == metric;
- rt = rt->u.dst.rt6_next)
+ rt = rt->dst.rt6_next)
match = find_match(rt, oif, strict, &mpri, match);
return match;
@@ -432,7 +426,7 @@ static struct rt6_info *rt6_select(struct fib6_node *fn, int oif, int strict)
if (!match &&
(strict & RT6_LOOKUP_F_REACHABLE)) {
- struct rt6_info *next = rt0->u.dst.rt6_next;
+ struct rt6_info *next = rt0->dst.rt6_next;
/* no entries matched; do round-robin */
if (!next || next->rt6i_metric != rt0->rt6i_metric)
@@ -517,7 +511,7 @@ int rt6_route_rcv(struct net_device *dev, u8 *opt, int len,
rt->rt6i_expires = jiffies + HZ * lifetime;
rt->rt6i_flags |= RTF_EXPIRES;
}
- dst_release(&rt->u.dst);
+ dst_release(&rt->dst);
}
return 0;
}
@@ -555,7 +549,7 @@ restart:
rt = rt6_device_match(net, rt, &fl->fl6_src, fl->oif, flags);
BACKTRACK(net, &fl->fl6_src);
out:
- dst_use(&rt->u.dst, jiffies);
+ dst_use(&rt->dst, jiffies);
read_unlock_bh(&table->tb6_lock);
return rt;
@@ -643,7 +637,7 @@ static struct rt6_info *rt6_alloc_cow(struct rt6_info *ort, struct in6_addr *dad
ipv6_addr_copy(&rt->rt6i_dst.addr, daddr);
rt->rt6i_dst.plen = 128;
rt->rt6i_flags |= RTF_CACHE;
- rt->u.dst.flags |= DST_HOST;
+ rt->dst.flags |= DST_HOST;
#ifdef CONFIG_IPV6_SUBTREES
if (rt->rt6i_src.plen && saddr) {
@@ -677,7 +671,7 @@ static struct rt6_info *rt6_alloc_cow(struct rt6_info *ort, struct in6_addr *dad
if (net_ratelimit())
printk(KERN_WARNING
"Neighbour table overflow.\n");
- dst_free(&rt->u.dst);
+ dst_free(&rt->dst);
return NULL;
}
rt->rt6i_nexthop = neigh;
@@ -694,7 +688,7 @@ static struct rt6_info *rt6_alloc_clone(struct rt6_info *ort, struct in6_addr *d
ipv6_addr_copy(&rt->rt6i_dst.addr, daddr);
rt->rt6i_dst.plen = 128;
rt->rt6i_flags |= RTF_CACHE;
- rt->u.dst.flags |= DST_HOST;
+ rt->dst.flags |= DST_HOST;
rt->rt6i_nexthop = neigh_clone(ort->rt6i_nexthop);
}
return rt;
@@ -726,7 +720,7 @@ restart:
rt->rt6i_flags & RTF_CACHE)
goto out;
- dst_hold(&rt->u.dst);
+ dst_hold(&rt->dst);
read_unlock_bh(&table->tb6_lock);
if (!rt->rt6i_nexthop && !(rt->rt6i_flags & RTF_NONEXTHOP))
@@ -739,10 +733,10 @@ restart:
#endif
}
- dst_release(&rt->u.dst);
+ dst_release(&rt->dst);
rt = nrt ? : net->ipv6.ip6_null_entry;
- dst_hold(&rt->u.dst);
+ dst_hold(&rt->dst);
if (nrt) {
err = ip6_ins_rt(nrt);
if (!err)
@@ -756,7 +750,7 @@ restart:
* Race condition! In the gap, when table->tb6_lock was
* released someone could insert this route. Relookup.
*/
- dst_release(&rt->u.dst);
+ dst_release(&rt->dst);
goto relookup;
out:
@@ -764,11 +758,11 @@ out:
reachable = 0;
goto restart_2;
}
- dst_hold(&rt->u.dst);
+ dst_hold(&rt->dst);
read_unlock_bh(&table->tb6_lock);
out2:
- rt->u.dst.lastuse = jiffies;
- rt->u.dst.__use++;
+ rt->dst.lastuse = jiffies;
+ rt->dst.__use++;
return rt;
}
@@ -835,15 +829,15 @@ int ip6_dst_blackhole(struct sock *sk, struct dst_entry **dstp, struct flowi *fl
struct dst_entry *new = NULL;
if (rt) {
- new = &rt->u.dst;
+ new = &rt->dst;
atomic_set(&new->__refcnt, 1);
new->__use = 1;
new->input = dst_discard;
new->output = dst_discard;
- memcpy(new->metrics, ort->u.dst.metrics, RTAX_MAX*sizeof(u32));
- new->dev = ort->u.dst.dev;
+ memcpy(new->metrics, ort->dst.metrics, RTAX_MAX*sizeof(u32));
+ new->dev = ort->dst.dev;
if (new->dev)
dev_hold(new->dev);
rt->rt6i_idev = ort->rt6i_idev;
@@ -912,7 +906,7 @@ static void ip6_link_failure(struct sk_buff *skb)
rt = (struct rt6_info *) skb_dst(skb);
if (rt) {
if (rt->rt6i_flags&RTF_CACHE) {
- dst_set_expires(&rt->u.dst, 0);
+ dst_set_expires(&rt->dst, 0);
rt->rt6i_flags |= RTF_EXPIRES;
} else if (rt->rt6i_node && (rt->rt6i_flags & RTF_DEFAULT))
rt->rt6i_node->fn_sernum = -1;
@@ -986,14 +980,14 @@ struct dst_entry *icmp6_dst_alloc(struct net_device *dev,
rt->rt6i_dev = dev;
rt->rt6i_idev = idev;
rt->rt6i_nexthop = neigh;
- atomic_set(&rt->u.dst.__refcnt, 1);
- rt->u.dst.metrics[RTAX_HOPLIMIT-1] = 255;
- rt->u.dst.metrics[RTAX_MTU-1] = ipv6_get_mtu(rt->rt6i_dev);
- rt->u.dst.metrics[RTAX_ADVMSS-1] = ipv6_advmss(net, dst_mtu(&rt->u.dst));
- rt->u.dst.output = ip6_output;
+ atomic_set(&rt->dst.__refcnt, 1);
+ rt->dst.metrics[RTAX_HOPLIMIT-1] = 255;
+ rt->dst.metrics[RTAX_MTU-1] = ipv6_get_mtu(rt->rt6i_dev);
+ rt->dst.metrics[RTAX_ADVMSS-1] = ipv6_advmss(net, dst_mtu(&rt->dst));
+ rt->dst.output = ip6_output;
#if 0 /* there's no chance to use these for ndisc */
- rt->u.dst.flags = ipv6_addr_type(addr) & IPV6_ADDR_UNICAST
+ rt->dst.flags = ipv6_addr_type(addr) & IPV6_ADDR_UNICAST
? DST_HOST
: 0;
ipv6_addr_copy(&rt->rt6i_dst.addr, addr);
@@ -1001,14 +995,14 @@ struct dst_entry *icmp6_dst_alloc(struct net_device *dev,
#endif
spin_lock_bh(&icmp6_dst_lock);
- rt->u.dst.next = icmp6_dst_gc_list;
- icmp6_dst_gc_list = &rt->u.dst;
+ rt->dst.next = icmp6_dst_gc_list;
+ icmp6_dst_gc_list = &rt->dst;
spin_unlock_bh(&icmp6_dst_lock);
fib6_force_start_gc(net);
out:
- return &rt->u.dst;
+ return &rt->dst;
}
int icmp6_dst_gc(void)
@@ -1090,11 +1084,11 @@ static int ipv6_get_mtu(struct net_device *dev)
int mtu = IPV6_MIN_MTU;
struct inet6_dev *idev;
- idev = in6_dev_get(dev);
- if (idev) {
+ rcu_read_lock();
+ idev = __in6_dev_get(dev);
+ if (idev)
mtu = idev->cnf.mtu6;
- in6_dev_put(idev);
- }
+ rcu_read_unlock();
return mtu;
}
@@ -1103,12 +1097,15 @@ int ip6_dst_hoplimit(struct dst_entry *dst)
int hoplimit = dst_metric(dst, RTAX_HOPLIMIT);
if (hoplimit < 0) {
struct net_device *dev = dst->dev;
- struct inet6_dev *idev = in6_dev_get(dev);
- if (idev) {
+ struct inet6_dev *idev;
+
+ rcu_read_lock();
+ idev = __in6_dev_get(dev);
+ if (idev)
hoplimit = idev->cnf.hop_limit;
- in6_dev_put(idev);
- } else
+ else
hoplimit = dev_net(dev)->ipv6.devconf_all->hop_limit;
+ rcu_read_unlock();
}
return hoplimit;
}
@@ -1159,7 +1156,7 @@ int ip6_route_add(struct fib6_config *cfg)
goto out;
}
- rt->u.dst.obsolete = -1;
+ rt->dst.obsolete = -1;
rt->rt6i_expires = (cfg->fc_flags & RTF_EXPIRES) ?
jiffies + clock_t_to_jiffies(cfg->fc_expires) :
0;
@@ -1171,16 +1168,16 @@ int ip6_route_add(struct fib6_config *cfg)
addr_type = ipv6_addr_type(&cfg->fc_dst);
if (addr_type & IPV6_ADDR_MULTICAST)
- rt->u.dst.input = ip6_mc_input;
+ rt->dst.input = ip6_mc_input;
else
- rt->u.dst.input = ip6_forward;
+ rt->dst.input = ip6_forward;
- rt->u.dst.output = ip6_output;
+ rt->dst.output = ip6_output;
ipv6_addr_prefix(&rt->rt6i_dst.addr, &cfg->fc_dst, cfg->fc_dst_len);
rt->rt6i_dst.plen = cfg->fc_dst_len;
if (rt->rt6i_dst.plen == 128)
- rt->u.dst.flags = DST_HOST;
+ rt->dst.flags = DST_HOST;
#ifdef CONFIG_IPV6_SUBTREES
ipv6_addr_prefix(&rt->rt6i_src.addr, &cfg->fc_src, cfg->fc_src_len);
@@ -1208,9 +1205,9 @@ int ip6_route_add(struct fib6_config *cfg)
goto out;
}
}
- rt->u.dst.output = ip6_pkt_discard_out;
- rt->u.dst.input = ip6_pkt_discard;
- rt->u.dst.error = -ENETUNREACH;
+ rt->dst.output = ip6_pkt_discard_out;
+ rt->dst.input = ip6_pkt_discard;
+ rt->dst.error = -ENETUNREACH;
rt->rt6i_flags = RTF_REJECT|RTF_NONEXTHOP;
goto install_route;
}
@@ -1244,7 +1241,7 @@ int ip6_route_add(struct fib6_config *cfg)
goto out;
if (dev) {
if (dev != grt->rt6i_dev) {
- dst_release(&grt->u.dst);
+ dst_release(&grt->dst);
goto out;
}
} else {
@@ -1255,7 +1252,7 @@ int ip6_route_add(struct fib6_config *cfg)
}
if (!(grt->rt6i_flags&RTF_GATEWAY))
err = 0;
- dst_release(&grt->u.dst);
+ dst_release(&grt->dst);
if (err)
goto out;
@@ -1294,18 +1291,18 @@ install_route:
goto out;
}
- rt->u.dst.metrics[type - 1] = nla_get_u32(nla);
+ rt->dst.metrics[type - 1] = nla_get_u32(nla);
}
}
}
- if (dst_metric(&rt->u.dst, RTAX_HOPLIMIT) == 0)
- rt->u.dst.metrics[RTAX_HOPLIMIT-1] = -1;
- if (!dst_mtu(&rt->u.dst))
- rt->u.dst.metrics[RTAX_MTU-1] = ipv6_get_mtu(dev);
- if (!dst_metric(&rt->u.dst, RTAX_ADVMSS))
- rt->u.dst.metrics[RTAX_ADVMSS-1] = ipv6_advmss(net, dst_mtu(&rt->u.dst));
- rt->u.dst.dev = dev;
+ if (dst_metric(&rt->dst, RTAX_HOPLIMIT) == 0)
+ rt->dst.metrics[RTAX_HOPLIMIT-1] = -1;
+ if (!dst_mtu(&rt->dst))
+ rt->dst.metrics[RTAX_MTU-1] = ipv6_get_mtu(dev);
+ if (!dst_metric(&rt->dst, RTAX_ADVMSS))
+ rt->dst.metrics[RTAX_ADVMSS-1] = ipv6_advmss(net, dst_mtu(&rt->dst));
+ rt->dst.dev = dev;
rt->rt6i_idev = idev;
rt->rt6i_table = table;
@@ -1319,7 +1316,7 @@ out:
if (idev)
in6_dev_put(idev);
if (rt)
- dst_free(&rt->u.dst);
+ dst_free(&rt->dst);
return err;
}
@@ -1336,7 +1333,7 @@ static int __ip6_del_rt(struct rt6_info *rt, struct nl_info *info)
write_lock_bh(&table->tb6_lock);
err = fib6_del(rt, info);
- dst_release(&rt->u.dst);
+ dst_release(&rt->dst);
write_unlock_bh(&table->tb6_lock);
@@ -1369,7 +1366,7 @@ static int ip6_route_del(struct fib6_config *cfg)
&cfg->fc_src, cfg->fc_src_len);
if (fn) {
- for (rt = fn->leaf; rt; rt = rt->u.dst.rt6_next) {
+ for (rt = fn->leaf; rt; rt = rt->dst.rt6_next) {
if (cfg->fc_ifindex &&
(rt->rt6i_dev == NULL ||
rt->rt6i_dev->ifindex != cfg->fc_ifindex))
@@ -1379,7 +1376,7 @@ static int ip6_route_del(struct fib6_config *cfg)
continue;
if (cfg->fc_metric && cfg->fc_metric != rt->rt6i_metric)
continue;
- dst_hold(&rt->u.dst);
+ dst_hold(&rt->dst);
read_unlock_bh(&table->tb6_lock);
return __ip6_del_rt(rt, &cfg->fc_nlinfo);
@@ -1421,7 +1418,7 @@ static struct rt6_info *__ip6_route_redirect(struct net *net,
read_lock_bh(&table->tb6_lock);
fn = fib6_lookup(&table->tb6_root, &fl->fl6_dst, &fl->fl6_src);
restart:
- for (rt = fn->leaf; rt; rt = rt->u.dst.rt6_next) {
+ for (rt = fn->leaf; rt; rt = rt->dst.rt6_next) {
/*
* Current route is on-link; redirect is always invalid.
*
@@ -1445,7 +1442,7 @@ restart:
rt = net->ipv6.ip6_null_entry;
BACKTRACK(net, &fl->fl6_src);
out:
- dst_hold(&rt->u.dst);
+ dst_hold(&rt->dst);
read_unlock_bh(&table->tb6_lock);
@@ -1513,10 +1510,10 @@ void rt6_redirect(struct in6_addr *dest, struct in6_addr *src,
* Look, redirects are sent only in response to data packets,
* so that this nexthop apparently is reachable. --ANK
*/
- dst_confirm(&rt->u.dst);
+ dst_confirm(&rt->dst);
/* Duplicate redirect: silently ignore. */
- if (neigh == rt->u.dst.neighbour)
+ if (neigh == rt->dst.neighbour)
goto out;
nrt = ip6_rt_copy(rt);
@@ -1529,20 +1526,20 @@ void rt6_redirect(struct in6_addr *dest, struct in6_addr *src,
ipv6_addr_copy(&nrt->rt6i_dst.addr, dest);
nrt->rt6i_dst.plen = 128;
- nrt->u.dst.flags |= DST_HOST;
+ nrt->dst.flags |= DST_HOST;
ipv6_addr_copy(&nrt->rt6i_gateway, (struct in6_addr*)neigh->primary_key);
nrt->rt6i_nexthop = neigh_clone(neigh);
/* Reset pmtu, it may be better */
- nrt->u.dst.metrics[RTAX_MTU-1] = ipv6_get_mtu(neigh->dev);
- nrt->u.dst.metrics[RTAX_ADVMSS-1] = ipv6_advmss(dev_net(neigh->dev),
- dst_mtu(&nrt->u.dst));
+ nrt->dst.metrics[RTAX_MTU-1] = ipv6_get_mtu(neigh->dev);
+ nrt->dst.metrics[RTAX_ADVMSS-1] = ipv6_advmss(dev_net(neigh->dev),
+ dst_mtu(&nrt->dst));
if (ip6_ins_rt(nrt))
goto out;
- netevent.old = &rt->u.dst;
- netevent.new = &nrt->u.dst;
+ netevent.old = &rt->dst;
+ netevent.new = &nrt->dst;
call_netevent_notifiers(NETEVENT_REDIRECT, &netevent);
if (rt->rt6i_flags&RTF_CACHE) {
@@ -1551,7 +1548,7 @@ void rt6_redirect(struct in6_addr *dest, struct in6_addr *src,
}
out:
- dst_release(&rt->u.dst);
+ dst_release(&rt->dst);
}
/*
@@ -1570,7 +1567,7 @@ void rt6_pmtu_discovery(struct in6_addr *daddr, struct in6_addr *saddr,
if (rt == NULL)
return;
- if (pmtu >= dst_mtu(&rt->u.dst))
+ if (pmtu >= dst_mtu(&rt->dst))
goto out;
if (pmtu < IPV6_MIN_MTU) {
@@ -1588,7 +1585,7 @@ void rt6_pmtu_discovery(struct in6_addr *daddr, struct in6_addr *saddr,
They are sent only in response to data packets,
so that this nexthop apparently is reachable. --ANK
*/
- dst_confirm(&rt->u.dst);
+ dst_confirm(&rt->dst);
/* Host route. If it is static, it would be better
not to override it, but add new one, so that
@@ -1596,10 +1593,10 @@ void rt6_pmtu_discovery(struct in6_addr *daddr, struct in6_addr *saddr,
would return automatically.
*/
if (rt->rt6i_flags & RTF_CACHE) {
- rt->u.dst.metrics[RTAX_MTU-1] = pmtu;
+ rt->dst.metrics[RTAX_MTU-1] = pmtu;
if (allfrag)
- rt->u.dst.metrics[RTAX_FEATURES-1] |= RTAX_FEATURE_ALLFRAG;
- dst_set_expires(&rt->u.dst, net->ipv6.sysctl.ip6_rt_mtu_expires);
+ rt->dst.metrics[RTAX_FEATURES-1] |= RTAX_FEATURE_ALLFRAG;
+ dst_set_expires(&rt->dst, net->ipv6.sysctl.ip6_rt_mtu_expires);
rt->rt6i_flags |= RTF_MODIFIED|RTF_EXPIRES;
goto out;
}
@@ -1615,9 +1612,9 @@ void rt6_pmtu_discovery(struct in6_addr *daddr, struct in6_addr *saddr,
nrt = rt6_alloc_clone(rt, daddr);
if (nrt) {
- nrt->u.dst.metrics[RTAX_MTU-1] = pmtu;
+ nrt->dst.metrics[RTAX_MTU-1] = pmtu;
if (allfrag)
- nrt->u.dst.metrics[RTAX_FEATURES-1] |= RTAX_FEATURE_ALLFRAG;
+ nrt->dst.metrics[RTAX_FEATURES-1] |= RTAX_FEATURE_ALLFRAG;
/* According to RFC 1981, detecting PMTU increase shouldn't be
* happened within 5 mins, the recommended timer is 10 mins.
@@ -1625,13 +1622,13 @@ void rt6_pmtu_discovery(struct in6_addr *daddr, struct in6_addr *saddr,
* which is 10 mins. After 10 mins the decreased pmtu is expired
* and detecting PMTU increase will be automatically happened.
*/
- dst_set_expires(&nrt->u.dst, net->ipv6.sysctl.ip6_rt_mtu_expires);
+ dst_set_expires(&nrt->dst, net->ipv6.sysctl.ip6_rt_mtu_expires);
nrt->rt6i_flags |= RTF_DYNAMIC|RTF_EXPIRES;
ip6_ins_rt(nrt);
}
out:
- dst_release(&rt->u.dst);
+ dst_release(&rt->dst);
}
/*
@@ -1644,18 +1641,18 @@ static struct rt6_info * ip6_rt_copy(struct rt6_info *ort)
struct rt6_info *rt = ip6_dst_alloc(&net->ipv6.ip6_dst_ops);
if (rt) {
- rt->u.dst.input = ort->u.dst.input;
- rt->u.dst.output = ort->u.dst.output;
-
- memcpy(rt->u.dst.metrics, ort->u.dst.metrics, RTAX_MAX*sizeof(u32));
- rt->u.dst.error = ort->u.dst.error;
- rt->u.dst.dev = ort->u.dst.dev;
- if (rt->u.dst.dev)
- dev_hold(rt->u.dst.dev);
+ rt->dst.input = ort->dst.input;
+ rt->dst.output = ort->dst.output;
+
+ memcpy(rt->dst.metrics, ort->dst.metrics, RTAX_MAX*sizeof(u32));
+ rt->dst.error = ort->dst.error;
+ rt->dst.dev = ort->dst.dev;
+ if (rt->dst.dev)
+ dev_hold(rt->dst.dev);
rt->rt6i_idev = ort->rt6i_idev;
if (rt->rt6i_idev)
in6_dev_hold(rt->rt6i_idev);
- rt->u.dst.lastuse = jiffies;
+ rt->dst.lastuse = jiffies;
rt->rt6i_expires = 0;
ipv6_addr_copy(&rt->rt6i_gateway, &ort->rt6i_gateway);
@@ -1689,14 +1686,14 @@ static struct rt6_info *rt6_get_route_info(struct net *net,
if (!fn)
goto out;
- for (rt = fn->leaf; rt; rt = rt->u.dst.rt6_next) {
+ for (rt = fn->leaf; rt; rt = rt->dst.rt6_next) {
if (rt->rt6i_dev->ifindex != ifindex)
continue;
if ((rt->rt6i_flags & (RTF_ROUTEINFO|RTF_GATEWAY)) != (RTF_ROUTEINFO|RTF_GATEWAY))
continue;
if (!ipv6_addr_equal(&rt->rt6i_gateway, gwaddr))
continue;
- dst_hold(&rt->u.dst);
+ dst_hold(&rt->dst);
break;
}
out:
@@ -1744,14 +1741,14 @@ struct rt6_info *rt6_get_dflt_router(struct in6_addr *addr, struct net_device *d
return NULL;
write_lock_bh(&table->tb6_lock);
- for (rt = table->tb6_root.leaf; rt; rt=rt->u.dst.rt6_next) {
+ for (rt = table->tb6_root.leaf; rt; rt=rt->dst.rt6_next) {
if (dev == rt->rt6i_dev &&
((rt->rt6i_flags & (RTF_ADDRCONF | RTF_DEFAULT)) == (RTF_ADDRCONF | RTF_DEFAULT)) &&
ipv6_addr_equal(&rt->rt6i_gateway, addr))
break;
}
if (rt)
- dst_hold(&rt->u.dst);
+ dst_hold(&rt->dst);
write_unlock_bh(&table->tb6_lock);
return rt;
}
@@ -1790,9 +1787,9 @@ void rt6_purge_dflt_routers(struct net *net)
restart:
read_lock_bh(&table->tb6_lock);
- for (rt = table->tb6_root.leaf; rt; rt = rt->u.dst.rt6_next) {
+ for (rt = table->tb6_root.leaf; rt; rt = rt->dst.rt6_next) {
if (rt->rt6i_flags & (RTF_DEFAULT | RTF_ADDRCONF)) {
- dst_hold(&rt->u.dst);
+ dst_hold(&rt->dst);
read_unlock_bh(&table->tb6_lock);
ip6_del_rt(rt);
goto restart;
@@ -1930,15 +1927,15 @@ struct rt6_info *addrconf_dst_alloc(struct inet6_dev *idev,
dev_hold(net->loopback_dev);
in6_dev_hold(idev);
- rt->u.dst.flags = DST_HOST;
- rt->u.dst.input = ip6_input;
- rt->u.dst.output = ip6_output;
+ rt->dst.flags = DST_HOST;
+ rt->dst.input = ip6_input;
+ rt->dst.output = ip6_output;
rt->rt6i_dev = net->loopback_dev;
rt->rt6i_idev = idev;
- rt->u.dst.metrics[RTAX_MTU-1] = ipv6_get_mtu(rt->rt6i_dev);
- rt->u.dst.metrics[RTAX_ADVMSS-1] = ipv6_advmss(net, dst_mtu(&rt->u.dst));
- rt->u.dst.metrics[RTAX_HOPLIMIT-1] = -1;
- rt->u.dst.obsolete = -1;
+ rt->dst.metrics[RTAX_MTU-1] = ipv6_get_mtu(rt->rt6i_dev);
+ rt->dst.metrics[RTAX_ADVMSS-1] = ipv6_advmss(net, dst_mtu(&rt->dst));
+ rt->dst.metrics[RTAX_HOPLIMIT-1] = -1;
+ rt->dst.obsolete = -1;
rt->rt6i_flags = RTF_UP | RTF_NONEXTHOP;
if (anycast)
@@ -1947,7 +1944,7 @@ struct rt6_info *addrconf_dst_alloc(struct inet6_dev *idev,
rt->rt6i_flags |= RTF_LOCAL;
neigh = ndisc_get_neigh(rt->rt6i_dev, &rt->rt6i_gateway);
if (IS_ERR(neigh)) {
- dst_free(&rt->u.dst);
+ dst_free(&rt->dst);
/* We are casting this because that is the return
* value type. But an errno encoded pointer is the
@@ -1962,7 +1959,7 @@ struct rt6_info *addrconf_dst_alloc(struct inet6_dev *idev,
rt->rt6i_dst.plen = 128;
rt->rt6i_table = fib6_get_table(net, RT6_TABLE_LOCAL);
- atomic_set(&rt->u.dst.__refcnt, 1);
+ atomic_set(&rt->dst.__refcnt, 1);
return rt;
}
@@ -2033,12 +2030,12 @@ static int rt6_mtu_change_route(struct rt6_info *rt, void *p_arg)
PMTU discouvery.
*/
if (rt->rt6i_dev == arg->dev &&
- !dst_metric_locked(&rt->u.dst, RTAX_MTU) &&
- (dst_mtu(&rt->u.dst) >= arg->mtu ||
- (dst_mtu(&rt->u.dst) < arg->mtu &&
- dst_mtu(&rt->u.dst) == idev->cnf.mtu6))) {
- rt->u.dst.metrics[RTAX_MTU-1] = arg->mtu;
- rt->u.dst.metrics[RTAX_ADVMSS-1] = ipv6_advmss(net, arg->mtu);
+ !dst_metric_locked(&rt->dst, RTAX_MTU) &&
+ (dst_mtu(&rt->dst) >= arg->mtu ||
+ (dst_mtu(&rt->dst) < arg->mtu &&
+ dst_mtu(&rt->dst) == idev->cnf.mtu6))) {
+ rt->dst.metrics[RTAX_MTU-1] = arg->mtu;
+ rt->dst.metrics[RTAX_ADVMSS-1] = ipv6_advmss(net, arg->mtu);
}
return 0;
}
@@ -2252,20 +2249,20 @@ static int rt6_fill_node(struct net *net,
#endif
NLA_PUT_U32(skb, RTA_IIF, iif);
} else if (dst) {
- struct inet6_dev *idev = ip6_dst_idev(&rt->u.dst);
+ struct inet6_dev *idev = ip6_dst_idev(&rt->dst);
struct in6_addr saddr_buf;
if (ipv6_dev_get_saddr(net, idev ? idev->dev : NULL,
dst, 0, &saddr_buf) == 0)
NLA_PUT(skb, RTA_PREFSRC, 16, &saddr_buf);
}
- if (rtnetlink_put_metrics(skb, rt->u.dst.metrics) < 0)
+ if (rtnetlink_put_metrics(skb, rt->dst.metrics) < 0)
goto nla_put_failure;
- if (rt->u.dst.neighbour)
- NLA_PUT(skb, RTA_GATEWAY, 16, &rt->u.dst.neighbour->primary_key);
+ if (rt->dst.neighbour)
+ NLA_PUT(skb, RTA_GATEWAY, 16, &rt->dst.neighbour->primary_key);
- if (rt->u.dst.dev)
+ if (rt->dst.dev)
NLA_PUT_U32(skb, RTA_OIF, rt->rt6i_dev->ifindex);
NLA_PUT_U32(skb, RTA_PRIORITY, rt->rt6i_metric);
@@ -2277,8 +2274,8 @@ static int rt6_fill_node(struct net *net,
else
expires = INT_MAX;
- if (rtnl_put_cacheinfo(skb, &rt->u.dst, 0, 0, 0,
- expires, rt->u.dst.error) < 0)
+ if (rtnl_put_cacheinfo(skb, &rt->dst, 0, 0, 0,
+ expires, rt->dst.error) < 0)
goto nla_put_failure;
return nlmsg_end(skb, nlh);
@@ -2364,7 +2361,7 @@ static int inet6_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void
skb_reserve(skb, MAX_HEADER + sizeof(struct ipv6hdr));
rt = (struct rt6_info*) ip6_route_output(net, NULL, &fl);
- skb_dst_set(skb, &rt->u.dst);
+ skb_dst_set(skb, &rt->dst);
err = rt6_fill_node(net, skb, rt, &fl.fl6_dst, &fl.fl6_src, iif,
RTM_NEWROUTE, NETLINK_CB(in_skb).pid,
@@ -2416,12 +2413,12 @@ static int ip6_route_dev_notify(struct notifier_block *this,
struct net *net = dev_net(dev);
if (event == NETDEV_REGISTER && (dev->flags & IFF_LOOPBACK)) {
- net->ipv6.ip6_null_entry->u.dst.dev = dev;
+ net->ipv6.ip6_null_entry->dst.dev = dev;
net->ipv6.ip6_null_entry->rt6i_idev = in6_dev_get(dev);
#ifdef CONFIG_IPV6_MULTIPLE_TABLES
- net->ipv6.ip6_prohibit_entry->u.dst.dev = dev;
+ net->ipv6.ip6_prohibit_entry->dst.dev = dev;
net->ipv6.ip6_prohibit_entry->rt6i_idev = in6_dev_get(dev);
- net->ipv6.ip6_blk_hole_entry->u.dst.dev = dev;
+ net->ipv6.ip6_blk_hole_entry->dst.dev = dev;
net->ipv6.ip6_blk_hole_entry->rt6i_idev = in6_dev_get(dev);
#endif
}
@@ -2464,8 +2461,8 @@ static int rt6_info_route(struct rt6_info *rt, void *p_arg)
seq_puts(m, "00000000000000000000000000000000");
}
seq_printf(m, " %08x %08x %08x %08x %8s\n",
- rt->rt6i_metric, atomic_read(&rt->u.dst.__refcnt),
- rt->u.dst.__use, rt->rt6i_flags,
+ rt->rt6i_metric, atomic_read(&rt->dst.__refcnt),
+ rt->dst.__use, rt->rt6i_flags,
rt->rt6i_dev ? rt->rt6i_dev->name : "");
return 0;
}
@@ -2646,9 +2643,9 @@ static int __net_init ip6_route_net_init(struct net *net)
GFP_KERNEL);
if (!net->ipv6.ip6_null_entry)
goto out_ip6_dst_ops;
- net->ipv6.ip6_null_entry->u.dst.path =
+ net->ipv6.ip6_null_entry->dst.path =
(struct dst_entry *)net->ipv6.ip6_null_entry;
- net->ipv6.ip6_null_entry->u.dst.ops = &net->ipv6.ip6_dst_ops;
+ net->ipv6.ip6_null_entry->dst.ops = &net->ipv6.ip6_dst_ops;
#ifdef CONFIG_IPV6_MULTIPLE_TABLES
net->ipv6.ip6_prohibit_entry = kmemdup(&ip6_prohibit_entry_template,
@@ -2656,18 +2653,18 @@ static int __net_init ip6_route_net_init(struct net *net)
GFP_KERNEL);
if (!net->ipv6.ip6_prohibit_entry)
goto out_ip6_null_entry;
- net->ipv6.ip6_prohibit_entry->u.dst.path =
+ net->ipv6.ip6_prohibit_entry->dst.path =
(struct dst_entry *)net->ipv6.ip6_prohibit_entry;
- net->ipv6.ip6_prohibit_entry->u.dst.ops = &net->ipv6.ip6_dst_ops;
+ net->ipv6.ip6_prohibit_entry->dst.ops = &net->ipv6.ip6_dst_ops;
net->ipv6.ip6_blk_hole_entry = kmemdup(&ip6_blk_hole_entry_template,
sizeof(*net->ipv6.ip6_blk_hole_entry),
GFP_KERNEL);
if (!net->ipv6.ip6_blk_hole_entry)
goto out_ip6_prohibit_entry;
- net->ipv6.ip6_blk_hole_entry->u.dst.path =
+ net->ipv6.ip6_blk_hole_entry->dst.path =
(struct dst_entry *)net->ipv6.ip6_blk_hole_entry;
- net->ipv6.ip6_blk_hole_entry->u.dst.ops = &net->ipv6.ip6_dst_ops;
+ net->ipv6.ip6_blk_hole_entry->dst.ops = &net->ipv6.ip6_dst_ops;
#endif
net->ipv6.sysctl.flush_delay = 0;
@@ -2742,12 +2739,12 @@ int __init ip6_route_init(void)
/* Registering of the loopback is done before this portion of code,
* the loopback reference in rt6_info will not be taken, do it
* manually for init_net */
- init_net.ipv6.ip6_null_entry->u.dst.dev = init_net.loopback_dev;
+ init_net.ipv6.ip6_null_entry->dst.dev = init_net.loopback_dev;
init_net.ipv6.ip6_null_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev);
#ifdef CONFIG_IPV6_MULTIPLE_TABLES
- init_net.ipv6.ip6_prohibit_entry->u.dst.dev = init_net.loopback_dev;
+ init_net.ipv6.ip6_prohibit_entry->dst.dev = init_net.loopback_dev;
init_net.ipv6.ip6_prohibit_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev);
- init_net.ipv6.ip6_blk_hole_entry->u.dst.dev = init_net.loopback_dev;
+ init_net.ipv6.ip6_blk_hole_entry->dst.dev = init_net.loopback_dev;
init_net.ipv6.ip6_blk_hole_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev);
#endif
ret = fib6_init();
diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c
index e51e650ea80..4699cd3c311 100644
--- a/net/ipv6/sit.c
+++ b/net/ipv6/sit.c
@@ -249,8 +249,6 @@ failed:
return NULL;
}
-static DEFINE_SPINLOCK(ipip6_prl_lock);
-
#define for_each_prl_rcu(start) \
for (prl = rcu_dereference(start); \
prl; \
@@ -340,7 +338,7 @@ ipip6_tunnel_add_prl(struct ip_tunnel *t, struct ip_tunnel_prl *a, int chg)
if (a->addr == htonl(INADDR_ANY))
return -EINVAL;
- spin_lock(&ipip6_prl_lock);
+ ASSERT_RTNL();
for (p = t->prl; p; p = p->next) {
if (p->addr == a->addr) {
@@ -370,7 +368,6 @@ ipip6_tunnel_add_prl(struct ip_tunnel *t, struct ip_tunnel_prl *a, int chg)
t->prl_count++;
rcu_assign_pointer(t->prl, p);
out:
- spin_unlock(&ipip6_prl_lock);
return err;
}
@@ -397,7 +394,7 @@ ipip6_tunnel_del_prl(struct ip_tunnel *t, struct ip_tunnel_prl *a)
struct ip_tunnel_prl_entry *x, **p;
int err = 0;
- spin_lock(&ipip6_prl_lock);
+ ASSERT_RTNL();
if (a && a->addr != htonl(INADDR_ANY)) {
for (p = &t->prl; *p; p = &(*p)->next) {
@@ -419,7 +416,6 @@ ipip6_tunnel_del_prl(struct ip_tunnel *t, struct ip_tunnel_prl *a)
}
}
out:
- spin_unlock(&ipip6_prl_lock);
return err;
}
@@ -716,7 +712,7 @@ static netdev_tx_t ipip6_tunnel_xmit(struct sk_buff *skb,
stats->tx_carrier_errors++;
goto tx_error_icmp;
}
- tdev = rt->u.dst.dev;
+ tdev = rt->dst.dev;
if (tdev == dev) {
ip_rt_put(rt);
@@ -725,7 +721,7 @@ static netdev_tx_t ipip6_tunnel_xmit(struct sk_buff *skb,
}
if (df) {
- mtu = dst_mtu(&rt->u.dst) - sizeof(struct iphdr);
+ mtu = dst_mtu(&rt->dst) - sizeof(struct iphdr);
if (mtu < 68) {
stats->collisions++;
@@ -784,7 +780,7 @@ static netdev_tx_t ipip6_tunnel_xmit(struct sk_buff *skb,
memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt));
IPCB(skb)->flags = 0;
skb_dst_drop(skb);
- skb_dst_set(skb, &rt->u.dst);
+ skb_dst_set(skb, &rt->dst);
/*
* Push down and install the IPIP header.
@@ -833,7 +829,7 @@ static void ipip6_tunnel_bind_dev(struct net_device *dev)
.proto = IPPROTO_IPV6 };
struct rtable *rt;
if (!ip_route_output_key(dev_net(dev), &rt, &fl)) {
- tdev = rt->u.dst.dev;
+ tdev = rt->dst.dev;
ip_rt_put(rt);
}
dev->flags |= IFF_POINTOPOINT;
diff --git a/net/ipv6/syncookies.c b/net/ipv6/syncookies.c
index 34d1f0690d7..09fd34f0dbf 100644
--- a/net/ipv6/syncookies.c
+++ b/net/ipv6/syncookies.c
@@ -27,28 +27,17 @@ extern __u32 syncookie_secret[2][16-4+SHA_DIGEST_WORDS];
#define COOKIEBITS 24 /* Upper bits store count */
#define COOKIEMASK (((__u32)1 << COOKIEBITS) - 1)
-/*
- * This table has to be sorted and terminated with (__u16)-1.
- * XXX generate a better table.
- * Unresolved Issues: HIPPI with a 64k MSS is not well supported.
- *
- * Taken directly from ipv4 implementation.
- * Should this list be modified for ipv6 use or is it close enough?
- * rfc 2460 8.3 suggests mss values 20 bytes less than ipv4 counterpart
- */
+/* Table must be sorted. */
static __u16 const msstab[] = {
- 64 - 1,
- 256 - 1,
- 512 - 1,
- 536 - 1,
- 1024 - 1,
- 1440 - 1,
- 1460 - 1,
- 4312 - 1,
- (__u16)-1
+ 64,
+ 512,
+ 536,
+ 1280 - 60,
+ 1480 - 60,
+ 1500 - 60,
+ 4460 - 60,
+ 9000 - 60,
};
-/* The number doesn't include the -1 terminator */
-#define NUM_MSS (ARRAY_SIZE(msstab) - 1)
/*
* This (misnamed) value is the age of syncookie which is permitted.
@@ -134,9 +123,11 @@ __u32 cookie_v6_init_sequence(struct sock *sk, struct sk_buff *skb, __u16 *mssp)
tcp_synq_overflow(sk);
- for (mssind = 0; mss > msstab[mssind + 1]; mssind++)
- ;
- *mssp = msstab[mssind] + 1;
+ for (mssind = ARRAY_SIZE(msstab) - 1; mssind ; mssind--)
+ if (mss >= msstab[mssind])
+ break;
+
+ *mssp = msstab[mssind];
NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_SYNCOOKIESSENT);
@@ -154,7 +145,7 @@ static inline int cookie_check(struct sk_buff *skb, __u32 cookie)
th->source, th->dest, seq,
jiffies / (HZ * 60), COUNTER_TRIES);
- return mssind < NUM_MSS ? msstab[mssind] + 1 : 0;
+ return mssind < ARRAY_SIZE(msstab) ? msstab[mssind] : 0;
}
struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb)
@@ -173,8 +164,9 @@ struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb)
int mss;
struct dst_entry *dst;
__u8 rcv_wscale;
+ bool ecn_ok;
- if (!sysctl_tcp_syncookies || !th->ack)
+ if (!sysctl_tcp_syncookies || !th->ack || th->rst)
goto out;
if (tcp_synq_no_recent_overflow(sk) ||
@@ -189,8 +181,8 @@ struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb)
memset(&tcp_opt, 0, sizeof(tcp_opt));
tcp_parse_options(skb, &tcp_opt, &hash_location, 0);
- if (tcp_opt.saw_tstamp)
- cookie_check_timestamp(&tcp_opt);
+ if (!cookie_check_timestamp(&tcp_opt, &ecn_ok))
+ goto out;
ret = NULL;
req = inet6_reqsk_alloc(&tcp6_request_sock_ops);
@@ -224,9 +216,8 @@ struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb)
req->expires = 0UL;
req->retrans = 0;
- ireq->ecn_ok = 0;
+ ireq->ecn_ok = ecn_ok;
ireq->snd_wscale = tcp_opt.snd_wscale;
- ireq->rcv_wscale = tcp_opt.rcv_wscale;
ireq->sack_ok = tcp_opt.sack_ok;
ireq->wscale_ok = tcp_opt.wscale_ok;
ireq->tstamp_ok = tcp_opt.saw_tstamp;
@@ -240,17 +231,12 @@ struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb)
* me if there is a preferred way.
*/
{
- struct in6_addr *final_p = NULL, final;
+ struct in6_addr *final_p, final;
struct flowi fl;
memset(&fl, 0, sizeof(fl));
fl.proto = IPPROTO_TCP;
ipv6_addr_copy(&fl.fl6_dst, &ireq6->rmt_addr);
- if (np->opt && np->opt->srcrt) {
- struct rt0_hdr *rt0 = (struct rt0_hdr *) np->opt->srcrt;
- ipv6_addr_copy(&final, &fl.fl6_dst);
- ipv6_addr_copy(&fl.fl6_dst, rt0->addr);
- final_p = &final;
- }
+ final_p = fl6_update_dst(&fl, np->opt, &final);
ipv6_addr_copy(&fl.fl6_src, &ireq6->loc_addr);
fl.oif = sk->sk_bound_dev_if;
fl.mark = sk->sk_mark;
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
index 2b7c3a100e2..fe6d40418c0 100644
--- a/net/ipv6/tcp_ipv6.c
+++ b/net/ipv6/tcp_ipv6.c
@@ -129,7 +129,7 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
struct inet_connection_sock *icsk = inet_csk(sk);
struct ipv6_pinfo *np = inet6_sk(sk);
struct tcp_sock *tp = tcp_sk(sk);
- struct in6_addr *saddr = NULL, *final_p = NULL, final;
+ struct in6_addr *saddr = NULL, *final_p, final;
struct flowi fl;
struct dst_entry *dst;
int addr_type;
@@ -250,12 +250,7 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
fl.fl_ip_dport = usin->sin6_port;
fl.fl_ip_sport = inet->inet_sport;
- if (np->opt && np->opt->srcrt) {
- struct rt0_hdr *rt0 = (struct rt0_hdr *)np->opt->srcrt;
- ipv6_addr_copy(&final, &fl.fl6_dst);
- ipv6_addr_copy(&fl.fl6_dst, rt0->addr);
- final_p = &final;
- }
+ final_p = fl6_update_dst(&fl, np->opt, &final);
security_sk_classify_flow(sk, &fl);
@@ -477,7 +472,7 @@ static int tcp_v6_send_synack(struct sock *sk, struct request_sock *req,
struct ipv6_pinfo *np = inet6_sk(sk);
struct sk_buff * skb;
struct ipv6_txoptions *opt = NULL;
- struct in6_addr * final_p = NULL, final;
+ struct in6_addr * final_p, final;
struct flowi fl;
struct dst_entry *dst;
int err = -1;
@@ -494,12 +489,7 @@ static int tcp_v6_send_synack(struct sock *sk, struct request_sock *req,
security_req_classify_flow(req, &fl);
opt = np->opt;
- if (opt && opt->srcrt) {
- struct rt0_hdr *rt0 = (struct rt0_hdr *) opt->srcrt;
- ipv6_addr_copy(&final, &fl.fl6_dst);
- ipv6_addr_copy(&fl.fl6_dst, rt0->addr);
- final_p = &final;
- }
+ final_p = fl6_update_dst(&fl, opt, &final);
err = ip6_dst_lookup(sk, &dst, &fl);
if (err)
@@ -1167,7 +1157,7 @@ static struct sock *tcp_v6_hnd_req(struct sock *sk,struct sk_buff *skb)
}
#ifdef CONFIG_SYN_COOKIES
- if (!th->rst && !th->syn && th->ack)
+ if (!th->syn)
sk = cookie_v6_check(sk, skb);
#endif
return sk;
@@ -1279,13 +1269,10 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb)
treq = inet6_rsk(req);
ipv6_addr_copy(&treq->rmt_addr, &ipv6_hdr(skb)->saddr);
ipv6_addr_copy(&treq->loc_addr, &ipv6_hdr(skb)->daddr);
- if (!want_cookie)
+ if (!want_cookie || tmp_opt.tstamp_ok)
TCP_ECN_create_request(req, tcp_hdr(skb));
- if (want_cookie) {
- isn = cookie_v6_init_sequence(sk, skb, &req->mss);
- req->cookie_ts = tmp_opt.tstamp_ok;
- } else if (!isn) {
+ if (!isn) {
if (ipv6_opt_accepted(sk, skb) ||
np->rxopt.bits.rxinfo || np->rxopt.bits.rxoinfo ||
np->rxopt.bits.rxhlim || np->rxopt.bits.rxohlim) {
@@ -1298,8 +1285,12 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb)
if (!sk->sk_bound_dev_if &&
ipv6_addr_type(&treq->rmt_addr) & IPV6_ADDR_LINKLOCAL)
treq->iif = inet6_iif(skb);
-
- isn = tcp_v6_init_sequence(skb);
+ if (!want_cookie) {
+ isn = tcp_v6_init_sequence(skb);
+ } else {
+ isn = cookie_v6_init_sequence(sk, skb, &req->mss);
+ req->cookie_ts = tmp_opt.tstamp_ok;
+ }
}
tcp_rsk(req)->snt_isn = isn;
@@ -1392,18 +1383,13 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
goto out_overflow;
if (dst == NULL) {
- struct in6_addr *final_p = NULL, final;
+ struct in6_addr *final_p, final;
struct flowi fl;
memset(&fl, 0, sizeof(fl));
fl.proto = IPPROTO_TCP;
ipv6_addr_copy(&fl.fl6_dst, &treq->rmt_addr);
- if (opt && opt->srcrt) {
- struct rt0_hdr *rt0 = (struct rt0_hdr *) opt->srcrt;
- ipv6_addr_copy(&final, &fl.fl6_dst);
- ipv6_addr_copy(&fl.fl6_dst, rt0->addr);
- final_p = &final;
- }
+ final_p = fl6_update_dst(&fl, opt, &final);
ipv6_addr_copy(&fl.fl6_src, &treq->loc_addr);
fl.oif = sk->sk_bound_dev_if;
fl.mark = sk->sk_mark;
@@ -2156,6 +2142,8 @@ struct proto tcpv6_prot = {
.setsockopt = tcp_setsockopt,
.getsockopt = tcp_getsockopt,
.recvmsg = tcp_recvmsg,
+ .sendmsg = tcp_sendmsg,
+ .sendpage = tcp_sendpage,
.backlog_rcv = tcp_v6_do_rcv,
.hash = tcp_v6_hash,
.unhash = inet_unhash,
@@ -2174,6 +2162,7 @@ struct proto tcpv6_prot = {
.twsk_prot = &tcp6_timewait_sock_ops,
.rsk_prot = &tcp6_request_sock_ops,
.h.hashinfo = &tcp_hashinfo,
+ .no_autobind = true,
#ifdef CONFIG_COMPAT
.compat_setsockopt = compat_tcp_setsockopt,
.compat_getsockopt = compat_tcp_getsockopt,
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c
index 87be58673b5..1dd1affdead 100644
--- a/net/ipv6/udp.c
+++ b/net/ipv6/udp.c
@@ -927,7 +927,7 @@ int udpv6_sendmsg(struct kiocb *iocb, struct sock *sk,
struct inet_sock *inet = inet_sk(sk);
struct ipv6_pinfo *np = inet6_sk(sk);
struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) msg->msg_name;
- struct in6_addr *daddr, *final_p = NULL, final;
+ struct in6_addr *daddr, *final_p, final;
struct ipv6_txoptions *opt = NULL;
struct ip6_flowlabel *flowlabel = NULL;
struct flowi fl;
@@ -1097,14 +1097,9 @@ do_udp_sendmsg:
ipv6_addr_copy(&fl.fl6_src, &np->saddr);
fl.fl_ip_sport = inet->inet_sport;
- /* merge ip6_build_xmit from ip6_output */
- if (opt && opt->srcrt) {
- struct rt0_hdr *rt0 = (struct rt0_hdr *) opt->srcrt;
- ipv6_addr_copy(&final, &fl.fl6_dst);
- ipv6_addr_copy(&fl.fl6_dst, rt0->addr);
- final_p = &final;
+ final_p = fl6_update_dst(&fl, opt, &final);
+ if (final_p)
connected = 0;
- }
if (!fl.oif && ipv6_addr_is_multicast(&fl.fl6_dst)) {
fl.oif = np->mcast_oif;
diff --git a/net/irda/irnet/irnet_ppp.c b/net/irda/irnet/irnet_ppp.c
index 6a1a202710c..800bc53b7f6 100644
--- a/net/irda/irnet/irnet_ppp.c
+++ b/net/irda/irnet/irnet_ppp.c
@@ -527,7 +527,7 @@ static int
dev_irnet_close(struct inode * inode,
struct file * file)
{
- irnet_socket * ap = (struct irnet_socket *) file->private_data;
+ irnet_socket * ap = file->private_data;
DENTER(FS_TRACE, "(file=0x%p, ap=0x%p)\n",
file, ap);
@@ -564,7 +564,7 @@ dev_irnet_write(struct file * file,
size_t count,
loff_t * ppos)
{
- irnet_socket * ap = (struct irnet_socket *) file->private_data;
+ irnet_socket * ap = file->private_data;
DPASS(FS_TRACE, "(file=0x%p, ap=0x%p, count=%Zd)\n",
file, ap, count);
@@ -588,7 +588,7 @@ dev_irnet_read(struct file * file,
size_t count,
loff_t * ppos)
{
- irnet_socket * ap = (struct irnet_socket *) file->private_data;
+ irnet_socket * ap = file->private_data;
DPASS(FS_TRACE, "(file=0x%p, ap=0x%p, count=%Zd)\n",
file, ap, count);
@@ -609,7 +609,7 @@ static unsigned int
dev_irnet_poll(struct file * file,
poll_table * wait)
{
- irnet_socket * ap = (struct irnet_socket *) file->private_data;
+ irnet_socket * ap = file->private_data;
unsigned int mask;
DENTER(FS_TRACE, "(file=0x%p, ap=0x%p)\n",
@@ -638,7 +638,7 @@ dev_irnet_ioctl(
unsigned int cmd,
unsigned long arg)
{
- irnet_socket * ap = (struct irnet_socket *) file->private_data;
+ irnet_socket * ap = file->private_data;
int err;
int val;
void __user *argp = (void __user *)arg;
diff --git a/net/irda/irttp.c b/net/irda/irttp.c
index 47db1d8a0d9..285761e77d9 100644
--- a/net/irda/irttp.c
+++ b/net/irda/irttp.c
@@ -1853,23 +1853,23 @@ static int irttp_seq_show(struct seq_file *seq, void *v)
self->remote_credit);
seq_printf(seq, "send credit: %d\n",
self->send_credit);
- seq_printf(seq, " tx packets: %ld, ",
+ seq_printf(seq, " tx packets: %lu, ",
self->stats.tx_packets);
- seq_printf(seq, "rx packets: %ld, ",
+ seq_printf(seq, "rx packets: %lu, ",
self->stats.rx_packets);
- seq_printf(seq, "tx_queue len: %d ",
+ seq_printf(seq, "tx_queue len: %u ",
skb_queue_len(&self->tx_queue));
- seq_printf(seq, "rx_queue len: %d\n",
+ seq_printf(seq, "rx_queue len: %u\n",
skb_queue_len(&self->rx_queue));
seq_printf(seq, " tx_sdu_busy: %s, ",
self->tx_sdu_busy? "TRUE":"FALSE");
seq_printf(seq, "rx_sdu_busy: %s\n",
self->rx_sdu_busy? "TRUE":"FALSE");
- seq_printf(seq, " max_seg_size: %d, ",
+ seq_printf(seq, " max_seg_size: %u, ",
self->max_seg_size);
- seq_printf(seq, "tx_max_sdu_size: %d, ",
+ seq_printf(seq, "tx_max_sdu_size: %u, ",
self->tx_max_sdu_size);
- seq_printf(seq, "rx_max_sdu_size: %d\n",
+ seq_printf(seq, "rx_max_sdu_size: %u\n",
self->rx_max_sdu_size);
seq_printf(seq, " Used by (%s)\n\n",
diff --git a/net/iucv/iucv.c b/net/iucv/iucv.c
index f28ad2cc842..499c045d691 100644
--- a/net/iucv/iucv.c
+++ b/net/iucv/iucv.c
@@ -1463,7 +1463,7 @@ struct iucv_path_pending {
u32 res3;
u8 ippollfg;
u8 res4[3];
-} __attribute__ ((packed));
+} __packed;
static void iucv_path_pending(struct iucv_irq_data *data)
{
@@ -1524,7 +1524,7 @@ struct iucv_path_complete {
u32 res3;
u8 ippollfg;
u8 res4[3];
-} __attribute__ ((packed));
+} __packed;
static void iucv_path_complete(struct iucv_irq_data *data)
{
@@ -1554,7 +1554,7 @@ struct iucv_path_severed {
u32 res4;
u8 ippollfg;
u8 res5[3];
-} __attribute__ ((packed));
+} __packed;
static void iucv_path_severed(struct iucv_irq_data *data)
{
@@ -1590,7 +1590,7 @@ struct iucv_path_quiesced {
u32 res4;
u8 ippollfg;
u8 res5[3];
-} __attribute__ ((packed));
+} __packed;
static void iucv_path_quiesced(struct iucv_irq_data *data)
{
@@ -1618,7 +1618,7 @@ struct iucv_path_resumed {
u32 res4;
u8 ippollfg;
u8 res5[3];
-} __attribute__ ((packed));
+} __packed;
static void iucv_path_resumed(struct iucv_irq_data *data)
{
@@ -1649,7 +1649,7 @@ struct iucv_message_complete {
u32 ipbfln2f;
u8 ippollfg;
u8 res2[3];
-} __attribute__ ((packed));
+} __packed;
static void iucv_message_complete(struct iucv_irq_data *data)
{
@@ -1694,7 +1694,7 @@ struct iucv_message_pending {
u32 ipbfln2f;
u8 ippollfg;
u8 res2[3];
-} __attribute__ ((packed));
+} __packed;
static void iucv_message_pending(struct iucv_irq_data *data)
{
diff --git a/net/l2tp/l2tp_ip.c b/net/l2tp/l2tp_ip.c
index 0852512d392..226a0ae3bcf 100644
--- a/net/l2tp/l2tp_ip.c
+++ b/net/l2tp/l2tp_ip.c
@@ -348,7 +348,7 @@ static int l2tp_ip_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len
sk->sk_state = TCP_ESTABLISHED;
inet->inet_id = jiffies;
- sk_dst_set(sk, &rt->u.dst);
+ sk_dst_set(sk, &rt->dst);
write_lock_bh(&l2tp_ip_lock);
hlist_del_init(&sk->sk_bind_node);
@@ -496,9 +496,9 @@ static int l2tp_ip_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *m
if (ip_route_output_flow(sock_net(sk), &rt, &fl, sk, 0))
goto no_route;
}
- sk_setup_caps(sk, &rt->u.dst);
+ sk_setup_caps(sk, &rt->dst);
}
- skb_dst_set(skb, dst_clone(&rt->u.dst));
+ skb_dst_set(skb, dst_clone(&rt->dst));
/* Queue the packet to IP for output */
rc = ip_queue_xmit(skb);
diff --git a/net/mac80211/Kconfig b/net/mac80211/Kconfig
index 8a91f6c0bb1..4d6f8653ec8 100644
--- a/net/mac80211/Kconfig
+++ b/net/mac80211/Kconfig
@@ -33,6 +33,13 @@ config MAC80211_RC_MINSTREL
---help---
This option enables the 'minstrel' TX rate control algorithm
+config MAC80211_RC_MINSTREL_HT
+ bool "Minstrel 802.11n support" if EMBEDDED
+ depends on MAC80211_RC_MINSTREL
+ default y
+ ---help---
+ This option enables the 'minstrel_ht' TX rate control algorithm
+
choice
prompt "Default rate control algorithm"
depends on MAC80211_HAS_RC
@@ -62,6 +69,7 @@ endchoice
config MAC80211_RC_DEFAULT
string
+ default "minstrel_ht" if MAC80211_RC_DEFAULT_MINSTREL && MAC80211_RC_MINSTREL_HT
default "minstrel" if MAC80211_RC_DEFAULT_MINSTREL
default "pid" if MAC80211_RC_DEFAULT_PID
default ""
diff --git a/net/mac80211/Makefile b/net/mac80211/Makefile
index 84b48ba8a77..fdb54e61d63 100644
--- a/net/mac80211/Makefile
+++ b/net/mac80211/Makefile
@@ -51,7 +51,11 @@ rc80211_pid-$(CONFIG_MAC80211_DEBUGFS) += rc80211_pid_debugfs.o
rc80211_minstrel-y := rc80211_minstrel.o
rc80211_minstrel-$(CONFIG_MAC80211_DEBUGFS) += rc80211_minstrel_debugfs.o
+rc80211_minstrel_ht-y := rc80211_minstrel_ht.o
+rc80211_minstrel_ht-$(CONFIG_MAC80211_DEBUGFS) += rc80211_minstrel_ht_debugfs.o
+
mac80211-$(CONFIG_MAC80211_RC_PID) += $(rc80211_pid-y)
mac80211-$(CONFIG_MAC80211_RC_MINSTREL) += $(rc80211_minstrel-y)
+mac80211-$(CONFIG_MAC80211_RC_MINSTREL_HT) += $(rc80211_minstrel_ht-y)
ccflags-y += -D__CHECK_ENDIAN__
diff --git a/net/mac80211/agg-rx.c b/net/mac80211/agg-rx.c
index 6bb9a9a9496..965b272499f 100644
--- a/net/mac80211/agg-rx.c
+++ b/net/mac80211/agg-rx.c
@@ -6,39 +6,70 @@
* Copyright 2005-2006, Devicescape Software, Inc.
* Copyright 2006-2007 Jiri Benc <jbenc@suse.cz>
* Copyright 2007, Michael Wu <flamingice@sourmilk.net>
- * Copyright 2007-2008, Intel Corporation
+ * Copyright 2007-2010, Intel 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.
*/
+/**
+ * DOC: RX A-MPDU aggregation
+ *
+ * Aggregation on the RX side requires only implementing the
+ * @ampdu_action callback that is invoked to start/stop any
+ * block-ack sessions for RX aggregation.
+ *
+ * When RX aggregation is started by the peer, the driver is
+ * notified via @ampdu_action function, with the
+ * %IEEE80211_AMPDU_RX_START action, and may reject the request
+ * in which case a negative response is sent to the peer, if it
+ * accepts it a positive response is sent.
+ *
+ * While the session is active, the device/driver are required
+ * to de-aggregate frames and pass them up one by one to mac80211,
+ * which will handle the reorder buffer.
+ *
+ * When the aggregation session is stopped again by the peer or
+ * ourselves, the driver's @ampdu_action function will be called
+ * with the action %IEEE80211_AMPDU_RX_STOP. In this case, the
+ * call must not fail.
+ */
+
#include <linux/ieee80211.h>
#include <linux/slab.h>
#include <net/mac80211.h>
#include "ieee80211_i.h"
#include "driver-ops.h"
-static void ___ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid,
- u16 initiator, u16 reason,
- bool from_timer)
+static void ieee80211_free_tid_rx(struct rcu_head *h)
{
- struct ieee80211_local *local = sta->local;
- struct tid_ampdu_rx *tid_rx;
+ struct tid_ampdu_rx *tid_rx =
+ container_of(h, struct tid_ampdu_rx, rcu_head);
int i;
- spin_lock_bh(&sta->lock);
+ for (i = 0; i < tid_rx->buf_size; i++)
+ dev_kfree_skb(tid_rx->reorder_buf[i]);
+ kfree(tid_rx->reorder_buf);
+ kfree(tid_rx->reorder_time);
+ kfree(tid_rx);
+}
- /* check if TID is in operational state */
- if (!sta->ampdu_mlme.tid_active_rx[tid]) {
- spin_unlock_bh(&sta->lock);
- return;
- }
+void ___ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid,
+ u16 initiator, u16 reason)
+{
+ struct ieee80211_local *local = sta->local;
+ struct tid_ampdu_rx *tid_rx;
- sta->ampdu_mlme.tid_active_rx[tid] = false;
+ lockdep_assert_held(&sta->ampdu_mlme.mtx);
tid_rx = sta->ampdu_mlme.tid_rx[tid];
+ if (!tid_rx)
+ return;
+
+ rcu_assign_pointer(sta->ampdu_mlme.tid_rx[tid], NULL);
+
#ifdef CONFIG_MAC80211_HT_DEBUG
printk(KERN_DEBUG "Rx BA session stop requested for %pM tid %u\n",
sta->sta.addr, tid);
@@ -54,32 +85,17 @@ static void ___ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid,
ieee80211_send_delba(sta->sdata, sta->sta.addr,
tid, 0, reason);
- /* free the reordering buffer */
- for (i = 0; i < tid_rx->buf_size; i++) {
- if (tid_rx->reorder_buf[i]) {
- /* release the reordered frames */
- dev_kfree_skb(tid_rx->reorder_buf[i]);
- tid_rx->stored_mpdu_num--;
- tid_rx->reorder_buf[i] = NULL;
- }
- }
-
- /* free resources */
- kfree(tid_rx->reorder_buf);
- kfree(tid_rx->reorder_time);
- sta->ampdu_mlme.tid_rx[tid] = NULL;
-
- spin_unlock_bh(&sta->lock);
+ del_timer_sync(&tid_rx->session_timer);
- if (!from_timer)
- del_timer_sync(&tid_rx->session_timer);
- kfree(tid_rx);
+ call_rcu(&tid_rx->rcu_head, ieee80211_free_tid_rx);
}
void __ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid,
u16 initiator, u16 reason)
{
- ___ieee80211_stop_rx_ba_session(sta, tid, initiator, reason, false);
+ mutex_lock(&sta->ampdu_mlme.mtx);
+ ___ieee80211_stop_rx_ba_session(sta, tid, initiator, reason);
+ mutex_unlock(&sta->ampdu_mlme.mtx);
}
/*
@@ -100,8 +116,8 @@ static void sta_rx_agg_session_timer_expired(unsigned long data)
#ifdef CONFIG_MAC80211_HT_DEBUG
printk(KERN_DEBUG "rx session timer expired on tid %d\n", (u16)*ptid);
#endif
- ___ieee80211_stop_rx_ba_session(sta, *ptid, WLAN_BACK_RECIPIENT,
- WLAN_REASON_QSTA_TIMEOUT, true);
+ set_bit(*ptid, sta->ampdu_mlme.tid_rx_timer_expired);
+ ieee80211_queue_work(&sta->local->hw, &sta->ampdu_mlme.work);
}
static void ieee80211_send_addba_resp(struct ieee80211_sub_if_data *sdata, u8 *da, u16 tid,
@@ -212,9 +228,9 @@ void ieee80211_process_addba_request(struct ieee80211_local *local,
/* examine state machine */
- spin_lock_bh(&sta->lock);
+ mutex_lock(&sta->ampdu_mlme.mtx);
- if (sta->ampdu_mlme.tid_active_rx[tid]) {
+ if (sta->ampdu_mlme.tid_rx[tid]) {
#ifdef CONFIG_MAC80211_HT_DEBUG
if (net_ratelimit())
printk(KERN_DEBUG "unexpected AddBA Req from "
@@ -225,9 +241,8 @@ void ieee80211_process_addba_request(struct ieee80211_local *local,
}
/* prepare A-MPDU MLME for Rx aggregation */
- sta->ampdu_mlme.tid_rx[tid] =
- kmalloc(sizeof(struct tid_ampdu_rx), GFP_ATOMIC);
- if (!sta->ampdu_mlme.tid_rx[tid]) {
+ tid_agg_rx = kmalloc(sizeof(struct tid_ampdu_rx), GFP_ATOMIC);
+ if (!tid_agg_rx) {
#ifdef CONFIG_MAC80211_HT_DEBUG
if (net_ratelimit())
printk(KERN_ERR "allocate rx mlme to tid %d failed\n",
@@ -235,14 +250,11 @@ void ieee80211_process_addba_request(struct ieee80211_local *local,
#endif
goto end;
}
- /* rx timer */
- sta->ampdu_mlme.tid_rx[tid]->session_timer.function =
- sta_rx_agg_session_timer_expired;
- sta->ampdu_mlme.tid_rx[tid]->session_timer.data =
- (unsigned long)&sta->timer_to_tid[tid];
- init_timer(&sta->ampdu_mlme.tid_rx[tid]->session_timer);
- tid_agg_rx = sta->ampdu_mlme.tid_rx[tid];
+ /* rx timer */
+ tid_agg_rx->session_timer.function = sta_rx_agg_session_timer_expired;
+ tid_agg_rx->session_timer.data = (unsigned long)&sta->timer_to_tid[tid];
+ init_timer(&tid_agg_rx->session_timer);
/* prepare reordering buffer */
tid_agg_rx->reorder_buf =
@@ -257,8 +269,7 @@ void ieee80211_process_addba_request(struct ieee80211_local *local,
#endif
kfree(tid_agg_rx->reorder_buf);
kfree(tid_agg_rx->reorder_time);
- kfree(sta->ampdu_mlme.tid_rx[tid]);
- sta->ampdu_mlme.tid_rx[tid] = NULL;
+ kfree(tid_agg_rx);
goto end;
}
@@ -270,13 +281,12 @@ void ieee80211_process_addba_request(struct ieee80211_local *local,
if (ret) {
kfree(tid_agg_rx->reorder_buf);
+ kfree(tid_agg_rx->reorder_time);
kfree(tid_agg_rx);
- sta->ampdu_mlme.tid_rx[tid] = NULL;
goto end;
}
- /* change state and send addba resp */
- sta->ampdu_mlme.tid_active_rx[tid] = true;
+ /* update data */
tid_agg_rx->dialog_token = dialog_token;
tid_agg_rx->ssn = start_seq_num;
tid_agg_rx->head_seq_num = start_seq_num;
@@ -284,8 +294,15 @@ void ieee80211_process_addba_request(struct ieee80211_local *local,
tid_agg_rx->timeout = timeout;
tid_agg_rx->stored_mpdu_num = 0;
status = WLAN_STATUS_SUCCESS;
+
+ /* activate it for RX */
+ rcu_assign_pointer(sta->ampdu_mlme.tid_rx[tid], tid_agg_rx);
+
+ if (timeout)
+ mod_timer(&tid_agg_rx->session_timer, TU_TO_EXP_TIME(timeout));
+
end:
- spin_unlock_bh(&sta->lock);
+ mutex_unlock(&sta->ampdu_mlme.mtx);
end_no_lock:
ieee80211_send_addba_resp(sta->sdata, sta->sta.addr, tid,
diff --git a/net/mac80211/agg-tx.c b/net/mac80211/agg-tx.c
index 98258b7341e..c893f236ace 100644
--- a/net/mac80211/agg-tx.c
+++ b/net/mac80211/agg-tx.c
@@ -6,7 +6,7 @@
* Copyright 2005-2006, Devicescape Software, Inc.
* Copyright 2006-2007 Jiri Benc <jbenc@suse.cz>
* Copyright 2007, Michael Wu <flamingice@sourmilk.net>
- * Copyright 2007-2009, Intel Corporation
+ * Copyright 2007-2010, Intel 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
@@ -21,28 +21,39 @@
#include "wme.h"
/**
- * DOC: TX aggregation
+ * DOC: TX A-MPDU aggregation
*
* Aggregation on the TX side requires setting the hardware flag
- * %IEEE80211_HW_AMPDU_AGGREGATION as well as, if present, the @ampdu_queues
- * hardware parameter to the number of hardware AMPDU queues. If there are no
- * hardware queues then the driver will (currently) have to do all frame
- * buffering.
+ * %IEEE80211_HW_AMPDU_AGGREGATION. The driver will then be handed
+ * packets with a flag indicating A-MPDU aggregation. The driver
+ * or device is responsible for actually aggregating the frames,
+ * as well as deciding how many and which to aggregate.
*
- * When TX aggregation is started by some subsystem (usually the rate control
- * algorithm would be appropriate) by calling the
- * ieee80211_start_tx_ba_session() function, the driver will be notified via
- * its @ampdu_action function, with the %IEEE80211_AMPDU_TX_START action.
+ * When TX aggregation is started by some subsystem (usually the rate
+ * control algorithm would be appropriate) by calling the
+ * ieee80211_start_tx_ba_session() function, the driver will be
+ * notified via its @ampdu_action function, with the
+ * %IEEE80211_AMPDU_TX_START action.
*
* In response to that, the driver is later required to call the
- * ieee80211_start_tx_ba_cb() (or ieee80211_start_tx_ba_cb_irqsafe())
- * function, which will start the aggregation session.
+ * ieee80211_start_tx_ba_cb_irqsafe() function, which will really
+ * start the aggregation session after the peer has also responded.
+ * If the peer responds negatively, the session will be stopped
+ * again right away. Note that it is possible for the aggregation
+ * session to be stopped before the driver has indicated that it
+ * is done setting it up, in which case it must not indicate the
+ * setup completion.
*
- * Similarly, when the aggregation session is stopped by
- * ieee80211_stop_tx_ba_session(), the driver's @ampdu_action function will
- * be called with the action %IEEE80211_AMPDU_TX_STOP. In this case, the
- * call must not fail, and the driver must later call ieee80211_stop_tx_ba_cb()
- * (or ieee80211_stop_tx_ba_cb_irqsafe()).
+ * Also note that, since we also need to wait for a response from
+ * the peer, the driver is notified of the completion of the
+ * handshake by the %IEEE80211_AMPDU_TX_OPERATIONAL action to the
+ * @ampdu_action callback.
+ *
+ * Similarly, when the aggregation session is stopped by the peer
+ * or something calling ieee80211_stop_tx_ba_session(), the driver's
+ * @ampdu_action function will be called with the action
+ * %IEEE80211_AMPDU_TX_STOP. In this case, the call must not fail,
+ * and the driver must later call ieee80211_stop_tx_ba_cb_irqsafe().
*/
static void ieee80211_send_addba_request(struct ieee80211_sub_if_data *sdata,
@@ -125,25 +136,53 @@ void ieee80211_send_bar(struct ieee80211_sub_if_data *sdata, u8 *ra, u16 tid, u1
ieee80211_tx_skb(sdata, skb);
}
+static void kfree_tid_tx(struct rcu_head *rcu_head)
+{
+ struct tid_ampdu_tx *tid_tx =
+ container_of(rcu_head, struct tid_ampdu_tx, rcu_head);
+
+ kfree(tid_tx);
+}
+
int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid,
enum ieee80211_back_parties initiator)
{
struct ieee80211_local *local = sta->local;
+ struct tid_ampdu_tx *tid_tx = sta->ampdu_mlme.tid_tx[tid];
int ret;
- u8 *state;
+
+ lockdep_assert_held(&sta->ampdu_mlme.mtx);
+
+ if (!tid_tx)
+ return -ENOENT;
+
+ spin_lock_bh(&sta->lock);
+
+ if (test_bit(HT_AGG_STATE_WANT_START, &tid_tx->state)) {
+ /* not even started yet! */
+ rcu_assign_pointer(sta->ampdu_mlme.tid_tx[tid], NULL);
+ spin_unlock_bh(&sta->lock);
+ call_rcu(&tid_tx->rcu_head, kfree_tid_tx);
+ return 0;
+ }
+
+ spin_unlock_bh(&sta->lock);
#ifdef CONFIG_MAC80211_HT_DEBUG
printk(KERN_DEBUG "Tx BA session stop requested for %pM tid %u\n",
sta->sta.addr, tid);
#endif /* CONFIG_MAC80211_HT_DEBUG */
- state = &sta->ampdu_mlme.tid_state_tx[tid];
+ set_bit(HT_AGG_STATE_STOPPING, &tid_tx->state);
- if (*state == HT_AGG_STATE_OPERATIONAL)
- sta->ampdu_mlme.addba_req_num[tid] = 0;
+ /*
+ * After this packets are no longer handed right through
+ * to the driver but are put onto tid_tx->pending instead,
+ * with locking to ensure proper access.
+ */
+ clear_bit(HT_AGG_STATE_OPERATIONAL, &tid_tx->state);
- *state = HT_AGG_STATE_REQ_STOP_BA_MSK |
- (initiator << HT_AGG_STATE_INITIATOR_SHIFT);
+ tid_tx->stop_initiator = initiator;
ret = drv_ampdu_action(local, sta->sdata,
IEEE80211_AMPDU_TX_STOP,
@@ -174,16 +213,14 @@ static void sta_addba_resp_timer_expired(unsigned long data)
u16 tid = *(u8 *)data;
struct sta_info *sta = container_of((void *)data,
struct sta_info, timer_to_tid[tid]);
- u8 *state;
-
- state = &sta->ampdu_mlme.tid_state_tx[tid];
+ struct tid_ampdu_tx *tid_tx;
/* check if the TID waits for addBA response */
- spin_lock_bh(&sta->lock);
- if ((*state & (HT_ADDBA_REQUESTED_MSK | HT_ADDBA_RECEIVED_MSK |
- HT_AGG_STATE_REQ_STOP_BA_MSK)) !=
- HT_ADDBA_REQUESTED_MSK) {
- spin_unlock_bh(&sta->lock);
+ rcu_read_lock();
+ tid_tx = rcu_dereference(sta->ampdu_mlme.tid_tx[tid]);
+ if (!tid_tx ||
+ test_bit(HT_AGG_STATE_RESPONSE_RECEIVED, &tid_tx->state)) {
+ rcu_read_unlock();
#ifdef CONFIG_MAC80211_HT_DEBUG
printk(KERN_DEBUG "timer expired on tid %d but we are not "
"(or no longer) expecting addBA response there\n",
@@ -196,8 +233,8 @@ static void sta_addba_resp_timer_expired(unsigned long data)
printk(KERN_DEBUG "addBA response timer expired on tid %d\n", tid);
#endif
- ___ieee80211_stop_tx_ba_session(sta, tid, WLAN_BACK_INITIATOR);
- spin_unlock_bh(&sta->lock);
+ ieee80211_stop_tx_ba_session(&sta->sta, tid);
+ rcu_read_unlock();
}
static inline int ieee80211_ac_from_tid(int tid)
@@ -205,14 +242,112 @@ static inline int ieee80211_ac_from_tid(int tid)
return ieee802_1d_to_ac[tid & 7];
}
+/*
+ * When multiple aggregation sessions on multiple stations
+ * are being created/destroyed simultaneously, we need to
+ * refcount the global queue stop caused by that in order
+ * to not get into a situation where one of the aggregation
+ * setup or teardown re-enables queues before the other is
+ * ready to handle that.
+ *
+ * These two functions take care of this issue by keeping
+ * a global "agg_queue_stop" refcount.
+ */
+static void __acquires(agg_queue)
+ieee80211_stop_queue_agg(struct ieee80211_local *local, int tid)
+{
+ int queue = ieee80211_ac_from_tid(tid);
+
+ if (atomic_inc_return(&local->agg_queue_stop[queue]) == 1)
+ ieee80211_stop_queue_by_reason(
+ &local->hw, queue,
+ IEEE80211_QUEUE_STOP_REASON_AGGREGATION);
+ __acquire(agg_queue);
+}
+
+static void __releases(agg_queue)
+ieee80211_wake_queue_agg(struct ieee80211_local *local, int tid)
+{
+ int queue = ieee80211_ac_from_tid(tid);
+
+ if (atomic_dec_return(&local->agg_queue_stop[queue]) == 0)
+ ieee80211_wake_queue_by_reason(
+ &local->hw, queue,
+ IEEE80211_QUEUE_STOP_REASON_AGGREGATION);
+ __release(agg_queue);
+}
+
+void ieee80211_tx_ba_session_handle_start(struct sta_info *sta, int tid)
+{
+ struct tid_ampdu_tx *tid_tx = sta->ampdu_mlme.tid_tx[tid];
+ struct ieee80211_local *local = sta->local;
+ struct ieee80211_sub_if_data *sdata = sta->sdata;
+ u16 start_seq_num;
+ int ret;
+
+ lockdep_assert_held(&sta->ampdu_mlme.mtx);
+
+ /*
+ * While we're asking the driver about the aggregation,
+ * stop the AC queue so that we don't have to worry
+ * about frames that came in while we were doing that,
+ * which would require us to put them to the AC pending
+ * afterwards which just makes the code more complex.
+ */
+ ieee80211_stop_queue_agg(local, tid);
+
+ clear_bit(HT_AGG_STATE_WANT_START, &tid_tx->state);
+
+ /*
+ * make sure no packets are being processed to get
+ * valid starting sequence number
+ */
+ synchronize_net();
+
+ start_seq_num = sta->tid_seq[tid] >> 4;
+
+ ret = drv_ampdu_action(local, sdata, IEEE80211_AMPDU_TX_START,
+ &sta->sta, tid, &start_seq_num);
+ if (ret) {
+#ifdef CONFIG_MAC80211_HT_DEBUG
+ printk(KERN_DEBUG "BA request denied - HW unavailable for"
+ " tid %d\n", tid);
+#endif
+ spin_lock_bh(&sta->lock);
+ rcu_assign_pointer(sta->ampdu_mlme.tid_tx[tid], NULL);
+ spin_unlock_bh(&sta->lock);
+
+ ieee80211_wake_queue_agg(local, tid);
+ call_rcu(&tid_tx->rcu_head, kfree_tid_tx);
+ return;
+ }
+
+ /* we can take packets again now */
+ ieee80211_wake_queue_agg(local, tid);
+
+ /* activate the timer for the recipient's addBA response */
+ mod_timer(&tid_tx->addba_resp_timer, jiffies + ADDBA_RESP_INTERVAL);
+#ifdef CONFIG_MAC80211_HT_DEBUG
+ printk(KERN_DEBUG "activated addBA response timer on tid %d\n", tid);
+#endif
+
+ spin_lock_bh(&sta->lock);
+ sta->ampdu_mlme.addba_req_num[tid]++;
+ spin_unlock_bh(&sta->lock);
+
+ /* send AddBA request */
+ ieee80211_send_addba_request(sdata, sta->sta.addr, tid,
+ tid_tx->dialog_token, start_seq_num,
+ 0x40, 5000);
+}
+
int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid)
{
struct sta_info *sta = container_of(pubsta, struct sta_info, sta);
struct ieee80211_sub_if_data *sdata = sta->sdata;
struct ieee80211_local *local = sdata->local;
- u8 *state;
+ struct tid_ampdu_tx *tid_tx;
int ret = 0;
- u16 start_seq_num;
trace_api_start_tx_ba_session(pubsta, tid);
@@ -239,24 +374,15 @@ int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid)
sdata->vif.type != NL80211_IFTYPE_AP)
return -EINVAL;
- if (test_sta_flags(sta, WLAN_STA_DISASSOC)) {
-#ifdef CONFIG_MAC80211_HT_DEBUG
- printk(KERN_DEBUG "Disassociation is in progress. "
- "Denying BA session request\n");
-#endif
- return -EINVAL;
- }
-
if (test_sta_flags(sta, WLAN_STA_BLOCK_BA)) {
#ifdef CONFIG_MAC80211_HT_DEBUG
- printk(KERN_DEBUG "Suspend in progress. "
+ printk(KERN_DEBUG "BA sessions blocked. "
"Denying BA session request\n");
#endif
return -EINVAL;
}
spin_lock_bh(&sta->lock);
- spin_lock(&local->ampdu_lock);
/* we have tried too many times, receiver does not want A-MPDU */
if (sta->ampdu_mlme.addba_req_num[tid] > HT_AGG_MAX_RETRIES) {
@@ -264,9 +390,9 @@ int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid)
goto err_unlock_sta;
}
- state = &sta->ampdu_mlme.tid_state_tx[tid];
+ tid_tx = sta->ampdu_mlme.tid_tx[tid];
/* check if the TID is not in aggregation flow already */
- if (*state != HT_AGG_STATE_IDLE) {
+ if (tid_tx) {
#ifdef CONFIG_MAC80211_HT_DEBUG
printk(KERN_DEBUG "BA request denied - session is not "
"idle on tid %u\n", tid);
@@ -275,96 +401,37 @@ int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid)
goto err_unlock_sta;
}
- /*
- * While we're asking the driver about the aggregation,
- * stop the AC queue so that we don't have to worry
- * about frames that came in while we were doing that,
- * which would require us to put them to the AC pending
- * afterwards which just makes the code more complex.
- */
- ieee80211_stop_queue_by_reason(
- &local->hw, ieee80211_ac_from_tid(tid),
- IEEE80211_QUEUE_STOP_REASON_AGGREGATION);
-
/* prepare A-MPDU MLME for Tx aggregation */
- sta->ampdu_mlme.tid_tx[tid] =
- kmalloc(sizeof(struct tid_ampdu_tx), GFP_ATOMIC);
- if (!sta->ampdu_mlme.tid_tx[tid]) {
+ tid_tx = kzalloc(sizeof(struct tid_ampdu_tx), GFP_ATOMIC);
+ if (!tid_tx) {
#ifdef CONFIG_MAC80211_HT_DEBUG
if (net_ratelimit())
printk(KERN_ERR "allocate tx mlme to tid %d failed\n",
tid);
#endif
ret = -ENOMEM;
- goto err_wake_queue;
+ goto err_unlock_sta;
}
- skb_queue_head_init(&sta->ampdu_mlme.tid_tx[tid]->pending);
+ skb_queue_head_init(&tid_tx->pending);
+ __set_bit(HT_AGG_STATE_WANT_START, &tid_tx->state);
/* Tx timer */
- sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer.function =
- sta_addba_resp_timer_expired;
- sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer.data =
- (unsigned long)&sta->timer_to_tid[tid];
- init_timer(&sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer);
-
- /* Ok, the Addba frame hasn't been sent yet, but if the driver calls the
- * call back right away, it must see that the flow has begun */
- *state |= HT_ADDBA_REQUESTED_MSK;
-
- start_seq_num = sta->tid_seq[tid] >> 4;
-
- ret = drv_ampdu_action(local, sdata, IEEE80211_AMPDU_TX_START,
- pubsta, tid, &start_seq_num);
+ tid_tx->addba_resp_timer.function = sta_addba_resp_timer_expired;
+ tid_tx->addba_resp_timer.data = (unsigned long)&sta->timer_to_tid[tid];
+ init_timer(&tid_tx->addba_resp_timer);
- if (ret) {
-#ifdef CONFIG_MAC80211_HT_DEBUG
- printk(KERN_DEBUG "BA request denied - HW unavailable for"
- " tid %d\n", tid);
-#endif /* CONFIG_MAC80211_HT_DEBUG */
- *state = HT_AGG_STATE_IDLE;
- goto err_free;
- }
-
- /* Driver vetoed or OKed, but we can take packets again now */
- ieee80211_wake_queue_by_reason(
- &local->hw, ieee80211_ac_from_tid(tid),
- IEEE80211_QUEUE_STOP_REASON_AGGREGATION);
-
- spin_unlock(&local->ampdu_lock);
-
- /* prepare tid data */
+ /* assign a dialog token */
sta->ampdu_mlme.dialog_token_allocator++;
- sta->ampdu_mlme.tid_tx[tid]->dialog_token =
- sta->ampdu_mlme.dialog_token_allocator;
- sta->ampdu_mlme.tid_tx[tid]->ssn = start_seq_num;
+ tid_tx->dialog_token = sta->ampdu_mlme.dialog_token_allocator;
- spin_unlock_bh(&sta->lock);
+ /* finally, assign it to the array */
+ rcu_assign_pointer(sta->ampdu_mlme.tid_tx[tid], tid_tx);
- /* send AddBA request */
- ieee80211_send_addba_request(sdata, pubsta->addr, tid,
- sta->ampdu_mlme.tid_tx[tid]->dialog_token,
- sta->ampdu_mlme.tid_tx[tid]->ssn,
- 0x40, 5000);
- sta->ampdu_mlme.addba_req_num[tid]++;
- /* activate the timer for the recipient's addBA response */
- sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer.expires =
- jiffies + ADDBA_RESP_INTERVAL;
- add_timer(&sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer);
-#ifdef CONFIG_MAC80211_HT_DEBUG
- printk(KERN_DEBUG "activated addBA response timer on tid %d\n", tid);
-#endif
- return 0;
-
- err_free:
- kfree(sta->ampdu_mlme.tid_tx[tid]);
- sta->ampdu_mlme.tid_tx[tid] = NULL;
- err_wake_queue:
- ieee80211_wake_queue_by_reason(
- &local->hw, ieee80211_ac_from_tid(tid),
- IEEE80211_QUEUE_STOP_REASON_AGGREGATION);
+ ieee80211_queue_work(&local->hw, &sta->ampdu_mlme.work);
+
+ /* this flow continues off the work */
err_unlock_sta:
- spin_unlock(&local->ampdu_lock);
spin_unlock_bh(&sta->lock);
return ret;
}
@@ -372,69 +439,65 @@ EXPORT_SYMBOL(ieee80211_start_tx_ba_session);
/*
* splice packets from the STA's pending to the local pending,
- * requires a call to ieee80211_agg_splice_finish and holding
- * local->ampdu_lock across both calls.
+ * requires a call to ieee80211_agg_splice_finish later
*/
-static void ieee80211_agg_splice_packets(struct ieee80211_local *local,
- struct sta_info *sta, u16 tid)
+static void __acquires(agg_queue)
+ieee80211_agg_splice_packets(struct ieee80211_local *local,
+ struct tid_ampdu_tx *tid_tx, u16 tid)
{
+ int queue = ieee80211_ac_from_tid(tid);
unsigned long flags;
- u16 queue = ieee80211_ac_from_tid(tid);
-
- ieee80211_stop_queue_by_reason(
- &local->hw, queue,
- IEEE80211_QUEUE_STOP_REASON_AGGREGATION);
- if (!(sta->ampdu_mlme.tid_state_tx[tid] & HT_ADDBA_REQUESTED_MSK))
- return;
+ ieee80211_stop_queue_agg(local, tid);
- if (WARN(!sta->ampdu_mlme.tid_tx[tid],
- "TID %d gone but expected when splicing aggregates from"
- "the pending queue\n", tid))
+ if (WARN(!tid_tx, "TID %d gone but expected when splicing aggregates"
+ " from the pending queue\n", tid))
return;
- if (!skb_queue_empty(&sta->ampdu_mlme.tid_tx[tid]->pending)) {
+ if (!skb_queue_empty(&tid_tx->pending)) {
spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
/* copy over remaining packets */
- skb_queue_splice_tail_init(
- &sta->ampdu_mlme.tid_tx[tid]->pending,
- &local->pending[queue]);
+ skb_queue_splice_tail_init(&tid_tx->pending,
+ &local->pending[queue]);
spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
}
}
-static void ieee80211_agg_splice_finish(struct ieee80211_local *local,
- struct sta_info *sta, u16 tid)
+static void __releases(agg_queue)
+ieee80211_agg_splice_finish(struct ieee80211_local *local, u16 tid)
{
- u16 queue = ieee80211_ac_from_tid(tid);
-
- ieee80211_wake_queue_by_reason(
- &local->hw, queue,
- IEEE80211_QUEUE_STOP_REASON_AGGREGATION);
+ ieee80211_wake_queue_agg(local, tid);
}
-/* caller must hold sta->lock */
static void ieee80211_agg_tx_operational(struct ieee80211_local *local,
struct sta_info *sta, u16 tid)
{
+ lockdep_assert_held(&sta->ampdu_mlme.mtx);
+
#ifdef CONFIG_MAC80211_HT_DEBUG
printk(KERN_DEBUG "Aggregation is on for tid %d\n", tid);
#endif
- spin_lock(&local->ampdu_lock);
- ieee80211_agg_splice_packets(local, sta, tid);
- /*
- * NB: we rely on sta->lock being taken in the TX
- * processing here when adding to the pending queue,
- * otherwise we could only change the state of the
- * session to OPERATIONAL _here_.
- */
- ieee80211_agg_splice_finish(local, sta, tid);
- spin_unlock(&local->ampdu_lock);
-
drv_ampdu_action(local, sta->sdata,
IEEE80211_AMPDU_TX_OPERATIONAL,
&sta->sta, tid, NULL);
+
+ /*
+ * synchronize with TX path, while splicing the TX path
+ * should block so it won't put more packets onto pending.
+ */
+ spin_lock_bh(&sta->lock);
+
+ ieee80211_agg_splice_packets(local, sta->ampdu_mlme.tid_tx[tid], tid);
+ /*
+ * Now mark as operational. This will be visible
+ * in the TX path, and lets it go lock-free in
+ * the common case.
+ */
+ set_bit(HT_AGG_STATE_OPERATIONAL, &sta->ampdu_mlme.tid_tx[tid]->state);
+ ieee80211_agg_splice_finish(local, tid);
+
+ spin_unlock_bh(&sta->lock);
}
void ieee80211_start_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u16 tid)
@@ -442,7 +505,7 @@ void ieee80211_start_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u16 tid)
struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
struct ieee80211_local *local = sdata->local;
struct sta_info *sta;
- u8 *state;
+ struct tid_ampdu_tx *tid_tx;
trace_api_start_tx_ba_cb(sdata, ra, tid);
@@ -454,42 +517,36 @@ void ieee80211_start_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u16 tid)
return;
}
- rcu_read_lock();
+ mutex_lock(&local->sta_mtx);
sta = sta_info_get(sdata, ra);
if (!sta) {
- rcu_read_unlock();
+ mutex_unlock(&local->sta_mtx);
#ifdef CONFIG_MAC80211_HT_DEBUG
printk(KERN_DEBUG "Could not find station: %pM\n", ra);
#endif
return;
}
- state = &sta->ampdu_mlme.tid_state_tx[tid];
- spin_lock_bh(&sta->lock);
+ mutex_lock(&sta->ampdu_mlme.mtx);
+ tid_tx = sta->ampdu_mlme.tid_tx[tid];
- if (WARN_ON(!(*state & HT_ADDBA_REQUESTED_MSK))) {
+ if (WARN_ON(!tid_tx)) {
#ifdef CONFIG_MAC80211_HT_DEBUG
- printk(KERN_DEBUG "addBA was not requested yet, state is %d\n",
- *state);
+ printk(KERN_DEBUG "addBA was not requested!\n");
#endif
- spin_unlock_bh(&sta->lock);
- rcu_read_unlock();
- return;
+ goto unlock;
}
- if (WARN_ON(*state & HT_ADDBA_DRV_READY_MSK))
- goto out;
-
- *state |= HT_ADDBA_DRV_READY_MSK;
+ if (WARN_ON(test_and_set_bit(HT_AGG_STATE_DRV_READY, &tid_tx->state)))
+ goto unlock;
- if (*state == HT_AGG_STATE_OPERATIONAL)
+ if (test_bit(HT_AGG_STATE_RESPONSE_RECEIVED, &tid_tx->state))
ieee80211_agg_tx_operational(local, sta, tid);
- out:
- spin_unlock_bh(&sta->lock);
- rcu_read_unlock();
+ unlock:
+ mutex_unlock(&sta->ampdu_mlme.mtx);
+ mutex_unlock(&local->sta_mtx);
}
-EXPORT_SYMBOL(ieee80211_start_tx_ba_cb);
void ieee80211_start_tx_ba_cb_irqsafe(struct ieee80211_vif *vif,
const u8 *ra, u16 tid)
@@ -510,44 +567,36 @@ void ieee80211_start_tx_ba_cb_irqsafe(struct ieee80211_vif *vif,
ra_tid = (struct ieee80211_ra_tid *) &skb->cb;
memcpy(&ra_tid->ra, ra, ETH_ALEN);
ra_tid->tid = tid;
- ra_tid->vif = vif;
- skb->pkt_type = IEEE80211_ADDBA_MSG;
- skb_queue_tail(&local->skb_queue, skb);
- tasklet_schedule(&local->tasklet);
+ skb->pkt_type = IEEE80211_SDATA_QUEUE_AGG_START;
+ skb_queue_tail(&sdata->skb_queue, skb);
+ ieee80211_queue_work(&local->hw, &sdata->work);
}
EXPORT_SYMBOL(ieee80211_start_tx_ba_cb_irqsafe);
int __ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid,
enum ieee80211_back_parties initiator)
{
- u8 *state;
int ret;
- /* check if the TID is in aggregation */
- state = &sta->ampdu_mlme.tid_state_tx[tid];
- spin_lock_bh(&sta->lock);
-
- if (*state != HT_AGG_STATE_OPERATIONAL) {
- ret = -ENOENT;
- goto unlock;
- }
+ mutex_lock(&sta->ampdu_mlme.mtx);
ret = ___ieee80211_stop_tx_ba_session(sta, tid, initiator);
- unlock:
- spin_unlock_bh(&sta->lock);
+ mutex_unlock(&sta->ampdu_mlme.mtx);
+
return ret;
}
-int ieee80211_stop_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid,
- enum ieee80211_back_parties initiator)
+int ieee80211_stop_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid)
{
struct sta_info *sta = container_of(pubsta, struct sta_info, sta);
struct ieee80211_sub_if_data *sdata = sta->sdata;
struct ieee80211_local *local = sdata->local;
+ struct tid_ampdu_tx *tid_tx;
+ int ret = 0;
- trace_api_stop_tx_ba_session(pubsta, tid, initiator);
+ trace_api_stop_tx_ba_session(pubsta, tid);
if (!local->ops->ampdu_action)
return -EINVAL;
@@ -555,7 +604,26 @@ int ieee80211_stop_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid,
if (tid >= STA_TID_NUM)
return -EINVAL;
- return __ieee80211_stop_tx_ba_session(sta, tid, initiator);
+ spin_lock_bh(&sta->lock);
+ tid_tx = sta->ampdu_mlme.tid_tx[tid];
+
+ if (!tid_tx) {
+ ret = -ENOENT;
+ goto unlock;
+ }
+
+ if (test_bit(HT_AGG_STATE_STOPPING, &tid_tx->state)) {
+ /* already in progress stopping it */
+ ret = 0;
+ goto unlock;
+ }
+
+ set_bit(HT_AGG_STATE_WANT_STOP, &tid_tx->state);
+ ieee80211_queue_work(&local->hw, &sta->ampdu_mlme.work);
+
+ unlock:
+ spin_unlock_bh(&sta->lock);
+ return ret;
}
EXPORT_SYMBOL(ieee80211_stop_tx_ba_session);
@@ -564,7 +632,7 @@ void ieee80211_stop_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u8 tid)
struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
struct ieee80211_local *local = sdata->local;
struct sta_info *sta;
- u8 *state;
+ struct tid_ampdu_tx *tid_tx;
trace_api_stop_tx_ba_cb(sdata, ra, tid);
@@ -581,51 +649,56 @@ void ieee80211_stop_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u8 tid)
ra, tid);
#endif /* CONFIG_MAC80211_HT_DEBUG */
- rcu_read_lock();
+ mutex_lock(&local->sta_mtx);
+
sta = sta_info_get(sdata, ra);
if (!sta) {
#ifdef CONFIG_MAC80211_HT_DEBUG
printk(KERN_DEBUG "Could not find station: %pM\n", ra);
#endif
- rcu_read_unlock();
- return;
+ goto unlock;
}
- state = &sta->ampdu_mlme.tid_state_tx[tid];
- /* NOTE: no need to use sta->lock in this state check, as
- * ieee80211_stop_tx_ba_session will let only one stop call to
- * pass through per sta/tid
- */
- if ((*state & HT_AGG_STATE_REQ_STOP_BA_MSK) == 0) {
+ mutex_lock(&sta->ampdu_mlme.mtx);
+ spin_lock_bh(&sta->lock);
+ tid_tx = sta->ampdu_mlme.tid_tx[tid];
+
+ if (!tid_tx || !test_bit(HT_AGG_STATE_STOPPING, &tid_tx->state)) {
#ifdef CONFIG_MAC80211_HT_DEBUG
printk(KERN_DEBUG "unexpected callback to A-MPDU stop\n");
#endif
- rcu_read_unlock();
- return;
+ goto unlock_sta;
}
- if (*state & HT_AGG_STATE_INITIATOR_MSK)
+ if (tid_tx->stop_initiator == WLAN_BACK_INITIATOR)
ieee80211_send_delba(sta->sdata, ra, tid,
WLAN_BACK_INITIATOR, WLAN_REASON_QSTA_NOT_USE);
- spin_lock_bh(&sta->lock);
- spin_lock(&local->ampdu_lock);
+ /*
+ * When we get here, the TX path will not be lockless any more wrt.
+ * aggregation, since the OPERATIONAL bit has long been cleared.
+ * Thus it will block on getting the lock, if it occurs. So if we
+ * stop the queue now, we will not get any more packets, and any
+ * that might be being processed will wait for us here, thereby
+ * guaranteeing that no packets go to the tid_tx pending queue any
+ * more.
+ */
- ieee80211_agg_splice_packets(local, sta, tid);
+ ieee80211_agg_splice_packets(local, tid_tx, tid);
- *state = HT_AGG_STATE_IDLE;
- /* from now on packets are no longer put onto sta->pending */
- kfree(sta->ampdu_mlme.tid_tx[tid]);
- sta->ampdu_mlme.tid_tx[tid] = NULL;
+ /* future packets must not find the tid_tx struct any more */
+ rcu_assign_pointer(sta->ampdu_mlme.tid_tx[tid], NULL);
- ieee80211_agg_splice_finish(local, sta, tid);
+ ieee80211_agg_splice_finish(local, tid);
- spin_unlock(&local->ampdu_lock);
- spin_unlock_bh(&sta->lock);
+ call_rcu(&tid_tx->rcu_head, kfree_tid_tx);
- rcu_read_unlock();
+ unlock_sta:
+ spin_unlock_bh(&sta->lock);
+ mutex_unlock(&sta->ampdu_mlme.mtx);
+ unlock:
+ mutex_unlock(&local->sta_mtx);
}
-EXPORT_SYMBOL(ieee80211_stop_tx_ba_cb);
void ieee80211_stop_tx_ba_cb_irqsafe(struct ieee80211_vif *vif,
const u8 *ra, u16 tid)
@@ -646,11 +719,10 @@ void ieee80211_stop_tx_ba_cb_irqsafe(struct ieee80211_vif *vif,
ra_tid = (struct ieee80211_ra_tid *) &skb->cb;
memcpy(&ra_tid->ra, ra, ETH_ALEN);
ra_tid->tid = tid;
- ra_tid->vif = vif;
- skb->pkt_type = IEEE80211_DELBA_MSG;
- skb_queue_tail(&local->skb_queue, skb);
- tasklet_schedule(&local->tasklet);
+ skb->pkt_type = IEEE80211_SDATA_QUEUE_AGG_STOP;
+ skb_queue_tail(&sdata->skb_queue, skb);
+ ieee80211_queue_work(&local->hw, &sdata->work);
}
EXPORT_SYMBOL(ieee80211_stop_tx_ba_cb_irqsafe);
@@ -660,40 +732,40 @@ void ieee80211_process_addba_resp(struct ieee80211_local *local,
struct ieee80211_mgmt *mgmt,
size_t len)
{
+ struct tid_ampdu_tx *tid_tx;
u16 capab, tid;
- u8 *state;
capab = le16_to_cpu(mgmt->u.action.u.addba_resp.capab);
tid = (capab & IEEE80211_ADDBA_PARAM_TID_MASK) >> 2;
- state = &sta->ampdu_mlme.tid_state_tx[tid];
-
- spin_lock_bh(&sta->lock);
+ mutex_lock(&sta->ampdu_mlme.mtx);
- if (!(*state & HT_ADDBA_REQUESTED_MSK))
+ tid_tx = sta->ampdu_mlme.tid_tx[tid];
+ if (!tid_tx)
goto out;
- if (mgmt->u.action.u.addba_resp.dialog_token !=
- sta->ampdu_mlme.tid_tx[tid]->dialog_token) {
+ if (mgmt->u.action.u.addba_resp.dialog_token != tid_tx->dialog_token) {
#ifdef CONFIG_MAC80211_HT_DEBUG
printk(KERN_DEBUG "wrong addBA response token, tid %d\n", tid);
-#endif /* CONFIG_MAC80211_HT_DEBUG */
+#endif
goto out;
}
- del_timer(&sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer);
+ del_timer(&tid_tx->addba_resp_timer);
#ifdef CONFIG_MAC80211_HT_DEBUG
printk(KERN_DEBUG "switched off addBA timer for tid %d\n", tid);
-#endif /* CONFIG_MAC80211_HT_DEBUG */
+#endif
if (le16_to_cpu(mgmt->u.action.u.addba_resp.status)
== WLAN_STATUS_SUCCESS) {
- u8 curstate = *state;
-
- *state |= HT_ADDBA_RECEIVED_MSK;
+ if (test_and_set_bit(HT_AGG_STATE_RESPONSE_RECEIVED,
+ &tid_tx->state)) {
+ /* ignore duplicate response */
+ goto out;
+ }
- if (*state != curstate && *state == HT_AGG_STATE_OPERATIONAL)
+ if (test_bit(HT_AGG_STATE_DRV_READY, &tid_tx->state))
ieee80211_agg_tx_operational(local, sta, tid);
sta->ampdu_mlme.addba_req_num[tid] = 0;
@@ -702,5 +774,5 @@ void ieee80211_process_addba_resp(struct ieee80211_local *local,
}
out:
- spin_unlock_bh(&sta->lock);
+ mutex_unlock(&sta->ampdu_mlme.mtx);
}
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 67ee34f57df..29ac8e1a509 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -120,6 +120,9 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev,
struct ieee80211_key *key;
int err;
+ if (!netif_running(dev))
+ return -ENETDOWN;
+
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
switch (params->cipher) {
@@ -140,17 +143,22 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev,
return -EINVAL;
}
+ /* reject WEP and TKIP keys if WEP failed to initialize */
+ if ((alg == ALG_WEP || alg == ALG_TKIP) &&
+ IS_ERR(sdata->local->wep_tx_tfm))
+ return -EINVAL;
+
key = ieee80211_key_alloc(alg, key_idx, params->key_len, params->key,
params->seq_len, params->seq);
if (!key)
return -ENOMEM;
- rcu_read_lock();
+ mutex_lock(&sdata->local->sta_mtx);
if (mac_addr) {
sta = sta_info_get_bss(sdata, mac_addr);
if (!sta) {
- ieee80211_key_free(key);
+ ieee80211_key_free(sdata->local, key);
err = -ENOENT;
goto out_unlock;
}
@@ -160,7 +168,7 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev,
err = 0;
out_unlock:
- rcu_read_unlock();
+ mutex_unlock(&sdata->local->sta_mtx);
return err;
}
@@ -174,7 +182,7 @@ static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev,
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
- rcu_read_lock();
+ mutex_lock(&sdata->local->sta_mtx);
if (mac_addr) {
ret = -ENOENT;
@@ -184,7 +192,7 @@ static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev,
goto out_unlock;
if (sta->key) {
- ieee80211_key_free(sta->key);
+ ieee80211_key_free(sdata->local, sta->key);
WARN_ON(sta->key);
ret = 0;
}
@@ -197,12 +205,12 @@ static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev,
goto out_unlock;
}
- ieee80211_key_free(sdata->keys[key_idx]);
+ ieee80211_key_free(sdata->local, sdata->keys[key_idx]);
WARN_ON(sdata->keys[key_idx]);
ret = 0;
out_unlock:
- rcu_read_unlock();
+ mutex_unlock(&sdata->local->sta_mtx);
return ret;
}
@@ -305,15 +313,10 @@ static int ieee80211_config_default_key(struct wiphy *wiphy,
struct net_device *dev,
u8 key_idx)
{
- struct ieee80211_sub_if_data *sdata;
-
- rcu_read_lock();
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
- sdata = IEEE80211_DEV_TO_SUB_IF(dev);
ieee80211_set_default_key(sdata, key_idx);
- rcu_read_unlock();
-
return 0;
}
@@ -321,15 +324,10 @@ static int ieee80211_config_default_mgmt_key(struct wiphy *wiphy,
struct net_device *dev,
u8 key_idx)
{
- struct ieee80211_sub_if_data *sdata;
-
- rcu_read_lock();
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
- sdata = IEEE80211_DEV_TO_SUB_IF(dev);
ieee80211_set_default_mgmt_key(sdata, key_idx);
- rcu_read_unlock();
-
return 0;
}
@@ -415,9 +413,6 @@ static int ieee80211_dump_survey(struct wiphy *wiphy, struct net_device *dev,
{
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
- if (!local->ops->get_survey)
- return -EOPNOTSUPP;
-
return drv_get_survey(local, idx, survey);
}
@@ -600,7 +595,7 @@ struct iapp_layer2_update {
u8 ssap; /* 0 */
u8 control;
u8 xid_info[3];
-} __attribute__ ((packed));
+} __packed;
static void ieee80211_send_layer2_update(struct sta_info *sta)
{
@@ -1154,10 +1149,6 @@ static int ieee80211_set_txq_params(struct wiphy *wiphy,
return -EINVAL;
}
- /* enable WMM or activate new settings */
- local->hw.conf.flags |= IEEE80211_CONF_QOS;
- drv_config(local, IEEE80211_CONF_CHANGE_QOS);
-
return 0;
}
@@ -1331,28 +1322,28 @@ static int ieee80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)
}
static int ieee80211_set_tx_power(struct wiphy *wiphy,
- enum tx_power_setting type, int dbm)
+ enum nl80211_tx_power_setting type, int mbm)
{
struct ieee80211_local *local = wiphy_priv(wiphy);
struct ieee80211_channel *chan = local->hw.conf.channel;
u32 changes = 0;
switch (type) {
- case TX_POWER_AUTOMATIC:
+ case NL80211_TX_POWER_AUTOMATIC:
local->user_power_level = -1;
break;
- case TX_POWER_LIMITED:
- if (dbm < 0)
- return -EINVAL;
- local->user_power_level = dbm;
+ case NL80211_TX_POWER_LIMITED:
+ if (mbm < 0 || (mbm % 100))
+ return -EOPNOTSUPP;
+ local->user_power_level = MBM_TO_DBM(mbm);
break;
- case TX_POWER_FIXED:
- if (dbm < 0)
- return -EINVAL;
+ case NL80211_TX_POWER_FIXED:
+ if (mbm < 0 || (mbm % 100))
+ return -EOPNOTSUPP;
/* TODO: move to cfg80211 when it knows the channel */
- if (dbm > chan->max_power)
+ if (MBM_TO_DBM(mbm) > chan->max_power)
return -EINVAL;
- local->user_power_level = dbm;
+ local->user_power_level = MBM_TO_DBM(mbm);
break;
}
@@ -1448,7 +1439,6 @@ static int ieee80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev,
{
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
- struct ieee80211_conf *conf = &local->hw.conf;
if (sdata->vif.type != NL80211_IFTYPE_STATION)
return -EOPNOTSUPP;
@@ -1457,11 +1447,11 @@ static int ieee80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev,
return -EOPNOTSUPP;
if (enabled == sdata->u.mgd.powersave &&
- timeout == conf->dynamic_ps_forced_timeout)
+ timeout == local->dynamic_ps_forced_timeout)
return 0;
sdata->u.mgd.powersave = enabled;
- conf->dynamic_ps_forced_timeout = timeout;
+ local->dynamic_ps_forced_timeout = timeout;
/* no change, but if automatic follow powersave */
mutex_lock(&sdata->u.mgd.mtx);
@@ -1554,10 +1544,58 @@ static int ieee80211_cancel_remain_on_channel(struct wiphy *wiphy,
static int ieee80211_action(struct wiphy *wiphy, struct net_device *dev,
struct ieee80211_channel *chan,
enum nl80211_channel_type channel_type,
+ bool channel_type_valid,
const u8 *buf, size_t len, u64 *cookie)
{
- return ieee80211_mgd_action(IEEE80211_DEV_TO_SUB_IF(dev), chan,
- channel_type, buf, len, cookie);
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ struct ieee80211_local *local = sdata->local;
+ struct sk_buff *skb;
+ struct sta_info *sta;
+ const struct ieee80211_mgmt *mgmt = (void *)buf;
+ u32 flags = IEEE80211_TX_INTFL_NL80211_FRAME_TX |
+ IEEE80211_TX_CTL_REQ_TX_STATUS;
+
+ /* Check that we are on the requested channel for transmission */
+ if (chan != local->tmp_channel &&
+ chan != local->oper_channel)
+ return -EBUSY;
+ if (channel_type_valid &&
+ (channel_type != local->tmp_channel_type &&
+ channel_type != local->_oper_channel_type))
+ return -EBUSY;
+
+ switch (sdata->vif.type) {
+ case NL80211_IFTYPE_ADHOC:
+ if (mgmt->u.action.category == WLAN_CATEGORY_PUBLIC)
+ break;
+ rcu_read_lock();
+ sta = sta_info_get(sdata, mgmt->da);
+ rcu_read_unlock();
+ if (!sta)
+ return -ENOLINK;
+ break;
+ case NL80211_IFTYPE_STATION:
+ if (!(sdata->u.mgd.flags & IEEE80211_STA_MFP_ENABLED))
+ flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
+
+ skb = dev_alloc_skb(local->hw.extra_tx_headroom + len);
+ if (!skb)
+ return -ENOMEM;
+ skb_reserve(skb, local->hw.extra_tx_headroom);
+
+ memcpy(skb_put(skb, len), buf, len);
+
+ IEEE80211_SKB_CB(skb)->flags = flags;
+
+ skb->dev = sdata->dev;
+ ieee80211_tx_skb(sdata, skb);
+
+ *cookie = (unsigned long) skb;
+ return 0;
}
struct cfg80211_ops mac80211_config_ops = {
diff --git a/net/mac80211/debugfs.c b/net/mac80211/debugfs.c
index 637929b65cc..a694c593ff6 100644
--- a/net/mac80211/debugfs.c
+++ b/net/mac80211/debugfs.c
@@ -307,9 +307,6 @@ static const struct file_operations queues_ops = {
/* statistics stuff */
-#define DEBUGFS_STATS_FILE(name, buflen, fmt, value...) \
- DEBUGFS_READONLY_FILE(stats_ ##name, buflen, fmt, ##value)
-
static ssize_t format_devstat_counter(struct ieee80211_local *local,
char __user *userbuf,
size_t count, loff_t *ppos,
@@ -351,75 +348,16 @@ static const struct file_operations stats_ ##name## _ops = { \
.open = mac80211_open_file_generic, \
};
-#define DEBUGFS_STATS_ADD(name) \
+#define DEBUGFS_STATS_ADD(name, field) \
+ debugfs_create_u32(#name, 0400, statsd, (u32 *) &field);
+#define DEBUGFS_DEVSTATS_ADD(name) \
debugfs_create_file(#name, 0400, statsd, local, &stats_ ##name## _ops);
-DEBUGFS_STATS_FILE(transmitted_fragment_count, 20, "%u",
- local->dot11TransmittedFragmentCount);
-DEBUGFS_STATS_FILE(multicast_transmitted_frame_count, 20, "%u",
- local->dot11MulticastTransmittedFrameCount);
-DEBUGFS_STATS_FILE(failed_count, 20, "%u",
- local->dot11FailedCount);
-DEBUGFS_STATS_FILE(retry_count, 20, "%u",
- local->dot11RetryCount);
-DEBUGFS_STATS_FILE(multiple_retry_count, 20, "%u",
- local->dot11MultipleRetryCount);
-DEBUGFS_STATS_FILE(frame_duplicate_count, 20, "%u",
- local->dot11FrameDuplicateCount);
-DEBUGFS_STATS_FILE(received_fragment_count, 20, "%u",
- local->dot11ReceivedFragmentCount);
-DEBUGFS_STATS_FILE(multicast_received_frame_count, 20, "%u",
- local->dot11MulticastReceivedFrameCount);
-DEBUGFS_STATS_FILE(transmitted_frame_count, 20, "%u",
- local->dot11TransmittedFrameCount);
-#ifdef CONFIG_MAC80211_DEBUG_COUNTERS
-DEBUGFS_STATS_FILE(tx_handlers_drop, 20, "%u",
- local->tx_handlers_drop);
-DEBUGFS_STATS_FILE(tx_handlers_queued, 20, "%u",
- local->tx_handlers_queued);
-DEBUGFS_STATS_FILE(tx_handlers_drop_unencrypted, 20, "%u",
- local->tx_handlers_drop_unencrypted);
-DEBUGFS_STATS_FILE(tx_handlers_drop_fragment, 20, "%u",
- local->tx_handlers_drop_fragment);
-DEBUGFS_STATS_FILE(tx_handlers_drop_wep, 20, "%u",
- local->tx_handlers_drop_wep);
-DEBUGFS_STATS_FILE(tx_handlers_drop_not_assoc, 20, "%u",
- local->tx_handlers_drop_not_assoc);
-DEBUGFS_STATS_FILE(tx_handlers_drop_unauth_port, 20, "%u",
- local->tx_handlers_drop_unauth_port);
-DEBUGFS_STATS_FILE(rx_handlers_drop, 20, "%u",
- local->rx_handlers_drop);
-DEBUGFS_STATS_FILE(rx_handlers_queued, 20, "%u",
- local->rx_handlers_queued);
-DEBUGFS_STATS_FILE(rx_handlers_drop_nullfunc, 20, "%u",
- local->rx_handlers_drop_nullfunc);
-DEBUGFS_STATS_FILE(rx_handlers_drop_defrag, 20, "%u",
- local->rx_handlers_drop_defrag);
-DEBUGFS_STATS_FILE(rx_handlers_drop_short, 20, "%u",
- local->rx_handlers_drop_short);
-DEBUGFS_STATS_FILE(rx_handlers_drop_passive_scan, 20, "%u",
- local->rx_handlers_drop_passive_scan);
-DEBUGFS_STATS_FILE(tx_expand_skb_head, 20, "%u",
- local->tx_expand_skb_head);
-DEBUGFS_STATS_FILE(tx_expand_skb_head_cloned, 20, "%u",
- local->tx_expand_skb_head_cloned);
-DEBUGFS_STATS_FILE(rx_expand_skb_head, 20, "%u",
- local->rx_expand_skb_head);
-DEBUGFS_STATS_FILE(rx_expand_skb_head2, 20, "%u",
- local->rx_expand_skb_head2);
-DEBUGFS_STATS_FILE(rx_handlers_fragments, 20, "%u",
- local->rx_handlers_fragments);
-DEBUGFS_STATS_FILE(tx_status_drop, 20, "%u",
- local->tx_status_drop);
-
-#endif
-
DEBUGFS_DEVSTATS_FILE(dot11ACKFailureCount);
DEBUGFS_DEVSTATS_FILE(dot11RTSFailureCount);
DEBUGFS_DEVSTATS_FILE(dot11FCSErrorCount);
DEBUGFS_DEVSTATS_FILE(dot11RTSSuccessCount);
-
void debugfs_hw_add(struct ieee80211_local *local)
{
struct dentry *phyd = local->hw.wiphy->debugfsdir;
@@ -448,38 +386,60 @@ void debugfs_hw_add(struct ieee80211_local *local)
if (!statsd)
return;
- DEBUGFS_STATS_ADD(transmitted_fragment_count);
- DEBUGFS_STATS_ADD(multicast_transmitted_frame_count);
- DEBUGFS_STATS_ADD(failed_count);
- DEBUGFS_STATS_ADD(retry_count);
- DEBUGFS_STATS_ADD(multiple_retry_count);
- DEBUGFS_STATS_ADD(frame_duplicate_count);
- DEBUGFS_STATS_ADD(received_fragment_count);
- DEBUGFS_STATS_ADD(multicast_received_frame_count);
- DEBUGFS_STATS_ADD(transmitted_frame_count);
+ DEBUGFS_STATS_ADD(transmitted_fragment_count,
+ local->dot11TransmittedFragmentCount);
+ DEBUGFS_STATS_ADD(multicast_transmitted_frame_count,
+ local->dot11MulticastTransmittedFrameCount);
+ DEBUGFS_STATS_ADD(failed_count, local->dot11FailedCount);
+ DEBUGFS_STATS_ADD(retry_count, local->dot11RetryCount);
+ DEBUGFS_STATS_ADD(multiple_retry_count,
+ local->dot11MultipleRetryCount);
+ DEBUGFS_STATS_ADD(frame_duplicate_count,
+ local->dot11FrameDuplicateCount);
+ DEBUGFS_STATS_ADD(received_fragment_count,
+ local->dot11ReceivedFragmentCount);
+ DEBUGFS_STATS_ADD(multicast_received_frame_count,
+ local->dot11MulticastReceivedFrameCount);
+ DEBUGFS_STATS_ADD(transmitted_frame_count,
+ local->dot11TransmittedFrameCount);
#ifdef CONFIG_MAC80211_DEBUG_COUNTERS
- DEBUGFS_STATS_ADD(tx_handlers_drop);
- DEBUGFS_STATS_ADD(tx_handlers_queued);
- DEBUGFS_STATS_ADD(tx_handlers_drop_unencrypted);
- DEBUGFS_STATS_ADD(tx_handlers_drop_fragment);
- DEBUGFS_STATS_ADD(tx_handlers_drop_wep);
- DEBUGFS_STATS_ADD(tx_handlers_drop_not_assoc);
- DEBUGFS_STATS_ADD(tx_handlers_drop_unauth_port);
- DEBUGFS_STATS_ADD(rx_handlers_drop);
- DEBUGFS_STATS_ADD(rx_handlers_queued);
- DEBUGFS_STATS_ADD(rx_handlers_drop_nullfunc);
- DEBUGFS_STATS_ADD(rx_handlers_drop_defrag);
- DEBUGFS_STATS_ADD(rx_handlers_drop_short);
- DEBUGFS_STATS_ADD(rx_handlers_drop_passive_scan);
- DEBUGFS_STATS_ADD(tx_expand_skb_head);
- DEBUGFS_STATS_ADD(tx_expand_skb_head_cloned);
- DEBUGFS_STATS_ADD(rx_expand_skb_head);
- DEBUGFS_STATS_ADD(rx_expand_skb_head2);
- DEBUGFS_STATS_ADD(rx_handlers_fragments);
- DEBUGFS_STATS_ADD(tx_status_drop);
+ DEBUGFS_STATS_ADD(tx_handlers_drop, local->tx_handlers_drop);
+ DEBUGFS_STATS_ADD(tx_handlers_queued, local->tx_handlers_queued);
+ DEBUGFS_STATS_ADD(tx_handlers_drop_unencrypted,
+ local->tx_handlers_drop_unencrypted);
+ DEBUGFS_STATS_ADD(tx_handlers_drop_fragment,
+ local->tx_handlers_drop_fragment);
+ DEBUGFS_STATS_ADD(tx_handlers_drop_wep,
+ local->tx_handlers_drop_wep);
+ DEBUGFS_STATS_ADD(tx_handlers_drop_not_assoc,
+ local->tx_handlers_drop_not_assoc);
+ DEBUGFS_STATS_ADD(tx_handlers_drop_unauth_port,
+ local->tx_handlers_drop_unauth_port);
+ DEBUGFS_STATS_ADD(rx_handlers_drop, local->rx_handlers_drop);
+ DEBUGFS_STATS_ADD(rx_handlers_queued, local->rx_handlers_queued);
+ DEBUGFS_STATS_ADD(rx_handlers_drop_nullfunc,
+ local->rx_handlers_drop_nullfunc);
+ DEBUGFS_STATS_ADD(rx_handlers_drop_defrag,
+ local->rx_handlers_drop_defrag);
+ DEBUGFS_STATS_ADD(rx_handlers_drop_short,
+ local->rx_handlers_drop_short);
+ DEBUGFS_STATS_ADD(rx_handlers_drop_passive_scan,
+ local->rx_handlers_drop_passive_scan);
+ DEBUGFS_STATS_ADD(tx_expand_skb_head,
+ local->tx_expand_skb_head);
+ DEBUGFS_STATS_ADD(tx_expand_skb_head_cloned,
+ local->tx_expand_skb_head_cloned);
+ DEBUGFS_STATS_ADD(rx_expand_skb_head,
+ local->rx_expand_skb_head);
+ DEBUGFS_STATS_ADD(rx_expand_skb_head2,
+ local->rx_expand_skb_head2);
+ DEBUGFS_STATS_ADD(rx_handlers_fragments,
+ local->rx_handlers_fragments);
+ DEBUGFS_STATS_ADD(tx_status_drop,
+ local->tx_status_drop);
#endif
- DEBUGFS_STATS_ADD(dot11ACKFailureCount);
- DEBUGFS_STATS_ADD(dot11RTSFailureCount);
- DEBUGFS_STATS_ADD(dot11FCSErrorCount);
- DEBUGFS_STATS_ADD(dot11RTSSuccessCount);
+ DEBUGFS_DEVSTATS_ADD(dot11ACKFailureCount);
+ DEBUGFS_DEVSTATS_ADD(dot11RTSFailureCount);
+ DEBUGFS_DEVSTATS_ADD(dot11FCSErrorCount);
+ DEBUGFS_DEVSTATS_ADD(dot11RTSSuccessCount);
}
diff --git a/net/mac80211/debugfs_key.c b/net/mac80211/debugfs_key.c
index 97c9e46e859..fa5e76e658e 100644
--- a/net/mac80211/debugfs_key.c
+++ b/net/mac80211/debugfs_key.c
@@ -143,7 +143,7 @@ static ssize_t key_rx_spec_read(struct file *file, char __user *userbuf,
len = p - buf;
break;
case ALG_CCMP:
- for (i = 0; i < NUM_RX_DATA_QUEUES; i++) {
+ for (i = 0; i < NUM_RX_DATA_QUEUES + 1; i++) {
rpn = key->u.ccmp.rx_pn[i];
p += scnprintf(p, sizeof(buf)+buf-p,
"%02x%02x%02x%02x%02x%02x\n",
diff --git a/net/mac80211/debugfs_sta.c b/net/mac80211/debugfs_sta.c
index e763f1529dd..76839d4dfaa 100644
--- a/net/mac80211/debugfs_sta.c
+++ b/net/mac80211/debugfs_sta.c
@@ -30,7 +30,6 @@ static ssize_t sta_ ##name## _read(struct file *file, \
}
#define STA_READ_D(name, field) STA_READ(name, 20, field, "%d\n")
#define STA_READ_U(name, field) STA_READ(name, 20, field, "%u\n")
-#define STA_READ_LU(name, field) STA_READ(name, 20, field, "%lu\n")
#define STA_READ_S(name, field) STA_READ(name, 20, field, "%s\n")
#define STA_OPS(name) \
@@ -52,19 +51,7 @@ static const struct file_operations sta_ ##name## _ops = { \
STA_FILE(aid, sta.aid, D);
STA_FILE(dev, sdata->name, S);
-STA_FILE(rx_packets, rx_packets, LU);
-STA_FILE(tx_packets, tx_packets, LU);
-STA_FILE(rx_bytes, rx_bytes, LU);
-STA_FILE(tx_bytes, tx_bytes, LU);
-STA_FILE(rx_duplicates, num_duplicates, LU);
-STA_FILE(rx_fragments, rx_fragments, LU);
-STA_FILE(rx_dropped, rx_dropped, LU);
-STA_FILE(tx_fragments, tx_fragments, LU);
-STA_FILE(tx_filtered, tx_filtered_count, LU);
-STA_FILE(tx_retry_failed, tx_retry_failed, LU);
-STA_FILE(tx_retry_count, tx_retry_count, LU);
STA_FILE(last_signal, last_signal, D);
-STA_FILE(wep_weak_iv_count, wep_weak_iv_count, LU);
static ssize_t sta_flags_read(struct file *file, char __user *userbuf,
size_t count, loff_t *ppos)
@@ -134,28 +121,25 @@ static ssize_t sta_agg_status_read(struct file *file, char __user *userbuf,
p += scnprintf(p, sizeof(buf) + buf - p, "next dialog_token: %#02x\n",
sta->ampdu_mlme.dialog_token_allocator + 1);
p += scnprintf(p, sizeof(buf) + buf - p,
- "TID\t\tRX active\tDTKN\tSSN\t\tTX\tDTKN\tSSN\tpending\n");
+ "TID\t\tRX active\tDTKN\tSSN\t\tTX\tDTKN\tpending\n");
for (i = 0; i < STA_TID_NUM; i++) {
p += scnprintf(p, sizeof(buf) + buf - p, "%02d", i);
p += scnprintf(p, sizeof(buf) + buf - p, "\t\t%x",
- sta->ampdu_mlme.tid_active_rx[i]);
+ !!sta->ampdu_mlme.tid_rx[i]);
p += scnprintf(p, sizeof(buf) + buf - p, "\t%#.2x",
- sta->ampdu_mlme.tid_active_rx[i] ?
+ sta->ampdu_mlme.tid_rx[i] ?
sta->ampdu_mlme.tid_rx[i]->dialog_token : 0);
p += scnprintf(p, sizeof(buf) + buf - p, "\t%#.3x",
- sta->ampdu_mlme.tid_active_rx[i] ?
+ sta->ampdu_mlme.tid_rx[i] ?
sta->ampdu_mlme.tid_rx[i]->ssn : 0);
p += scnprintf(p, sizeof(buf) + buf - p, "\t\t%x",
- sta->ampdu_mlme.tid_state_tx[i]);
+ !!sta->ampdu_mlme.tid_tx[i]);
p += scnprintf(p, sizeof(buf) + buf - p, "\t%#.2x",
- sta->ampdu_mlme.tid_state_tx[i] ?
+ sta->ampdu_mlme.tid_tx[i] ?
sta->ampdu_mlme.tid_tx[i]->dialog_token : 0);
- p += scnprintf(p, sizeof(buf) + buf - p, "\t%#.3x",
- sta->ampdu_mlme.tid_state_tx[i] ?
- sta->ampdu_mlme.tid_tx[i]->ssn : 0);
p += scnprintf(p, sizeof(buf) + buf - p, "\t%03d",
- sta->ampdu_mlme.tid_state_tx[i] ?
+ sta->ampdu_mlme.tid_tx[i] ?
skb_queue_len(&sta->ampdu_mlme.tid_tx[i]->pending) : 0);
p += scnprintf(p, sizeof(buf) + buf - p, "\n");
}
@@ -210,8 +194,7 @@ static ssize_t sta_agg_status_write(struct file *file, const char __user *userbu
if (start)
ret = ieee80211_start_tx_ba_session(&sta->sta, tid);
else
- ret = ieee80211_stop_tx_ba_session(&sta->sta, tid,
- WLAN_BACK_RECIPIENT);
+ ret = ieee80211_stop_tx_ba_session(&sta->sta, tid);
} else {
__ieee80211_stop_rx_ba_session(sta, tid, WLAN_BACK_RECIPIENT, 3);
ret = 0;
@@ -307,6 +290,13 @@ STA_OPS(ht_capa);
debugfs_create_file(#name, 0400, \
sta->debugfs.dir, sta, &sta_ ##name## _ops);
+#define DEBUGFS_ADD_COUNTER(name, field) \
+ if (sizeof(sta->field) == sizeof(u32)) \
+ debugfs_create_u32(#name, 0400, sta->debugfs.dir, \
+ (u32 *) &sta->field); \
+ else \
+ debugfs_create_u64(#name, 0400, sta->debugfs.dir, \
+ (u64 *) &sta->field);
void ieee80211_sta_debugfs_add(struct sta_info *sta)
{
@@ -339,20 +329,21 @@ void ieee80211_sta_debugfs_add(struct sta_info *sta)
DEBUGFS_ADD(last_seq_ctrl);
DEBUGFS_ADD(agg_status);
DEBUGFS_ADD(dev);
- DEBUGFS_ADD(rx_packets);
- DEBUGFS_ADD(tx_packets);
- DEBUGFS_ADD(rx_bytes);
- DEBUGFS_ADD(tx_bytes);
- DEBUGFS_ADD(rx_duplicates);
- DEBUGFS_ADD(rx_fragments);
- DEBUGFS_ADD(rx_dropped);
- DEBUGFS_ADD(tx_fragments);
- DEBUGFS_ADD(tx_filtered);
- DEBUGFS_ADD(tx_retry_failed);
- DEBUGFS_ADD(tx_retry_count);
DEBUGFS_ADD(last_signal);
- DEBUGFS_ADD(wep_weak_iv_count);
DEBUGFS_ADD(ht_capa);
+
+ DEBUGFS_ADD_COUNTER(rx_packets, rx_packets);
+ DEBUGFS_ADD_COUNTER(tx_packets, tx_packets);
+ DEBUGFS_ADD_COUNTER(rx_bytes, rx_bytes);
+ DEBUGFS_ADD_COUNTER(tx_bytes, tx_bytes);
+ DEBUGFS_ADD_COUNTER(rx_duplicates, num_duplicates);
+ DEBUGFS_ADD_COUNTER(rx_fragments, rx_fragments);
+ DEBUGFS_ADD_COUNTER(rx_dropped, rx_dropped);
+ DEBUGFS_ADD_COUNTER(tx_fragments, tx_fragments);
+ DEBUGFS_ADD_COUNTER(tx_filtered, tx_filtered_count);
+ DEBUGFS_ADD_COUNTER(tx_retry_failed, tx_retry_failed);
+ DEBUGFS_ADD_COUNTER(tx_retry_count, tx_retry_count);
+ DEBUGFS_ADD_COUNTER(wep_weak_iv_count, wep_weak_iv_count);
}
void ieee80211_sta_debugfs_remove(struct sta_info *sta)
diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h
index 9c1da080916..14123dce544 100644
--- a/net/mac80211/driver-ops.h
+++ b/net/mac80211/driver-ops.h
@@ -16,10 +16,11 @@ static inline int drv_start(struct ieee80211_local *local)
might_sleep();
+ trace_drv_start(local);
local->started = true;
smp_mb();
ret = local->ops->start(&local->hw);
- trace_drv_start(local, ret);
+ trace_drv_return_int(local, ret);
return ret;
}
@@ -27,8 +28,9 @@ static inline void drv_stop(struct ieee80211_local *local)
{
might_sleep();
- local->ops->stop(&local->hw);
trace_drv_stop(local);
+ local->ops->stop(&local->hw);
+ trace_drv_return_void(local);
/* sync away all work on the tasklet before clearing started */
tasklet_disable(&local->tasklet);
@@ -46,8 +48,9 @@ static inline int drv_add_interface(struct ieee80211_local *local,
might_sleep();
+ trace_drv_add_interface(local, vif_to_sdata(vif));
ret = local->ops->add_interface(&local->hw, vif);
- trace_drv_add_interface(local, vif_to_sdata(vif), ret);
+ trace_drv_return_int(local, ret);
return ret;
}
@@ -56,8 +59,9 @@ static inline void drv_remove_interface(struct ieee80211_local *local,
{
might_sleep();
- local->ops->remove_interface(&local->hw, vif);
trace_drv_remove_interface(local, vif_to_sdata(vif));
+ local->ops->remove_interface(&local->hw, vif);
+ trace_drv_return_void(local);
}
static inline int drv_config(struct ieee80211_local *local, u32 changed)
@@ -66,8 +70,9 @@ static inline int drv_config(struct ieee80211_local *local, u32 changed)
might_sleep();
+ trace_drv_config(local, changed);
ret = local->ops->config(&local->hw, changed);
- trace_drv_config(local, changed, ret);
+ trace_drv_return_int(local, ret);
return ret;
}
@@ -78,9 +83,10 @@ static inline void drv_bss_info_changed(struct ieee80211_local *local,
{
might_sleep();
+ trace_drv_bss_info_changed(local, sdata, info, changed);
if (local->ops->bss_info_changed)
local->ops->bss_info_changed(&local->hw, &sdata->vif, info, changed);
- trace_drv_bss_info_changed(local, sdata, info, changed);
+ trace_drv_return_void(local);
}
static inline u64 drv_prepare_multicast(struct ieee80211_local *local,
@@ -88,10 +94,12 @@ static inline u64 drv_prepare_multicast(struct ieee80211_local *local,
{
u64 ret = 0;
+ trace_drv_prepare_multicast(local, mc_list->count);
+
if (local->ops->prepare_multicast)
ret = local->ops->prepare_multicast(&local->hw, mc_list);
- trace_drv_prepare_multicast(local, mc_list->count, ret);
+ trace_drv_return_u64(local, ret);
return ret;
}
@@ -103,19 +111,21 @@ static inline void drv_configure_filter(struct ieee80211_local *local,
{
might_sleep();
- local->ops->configure_filter(&local->hw, changed_flags, total_flags,
- multicast);
trace_drv_configure_filter(local, changed_flags, total_flags,
multicast);
+ local->ops->configure_filter(&local->hw, changed_flags, total_flags,
+ multicast);
+ trace_drv_return_void(local);
}
static inline int drv_set_tim(struct ieee80211_local *local,
struct ieee80211_sta *sta, bool set)
{
int ret = 0;
+ trace_drv_set_tim(local, sta, set);
if (local->ops->set_tim)
ret = local->ops->set_tim(&local->hw, sta, set);
- trace_drv_set_tim(local, sta, set, ret);
+ trace_drv_return_int(local, ret);
return ret;
}
@@ -129,8 +139,9 @@ static inline int drv_set_key(struct ieee80211_local *local,
might_sleep();
+ trace_drv_set_key(local, cmd, sdata, sta, key);
ret = local->ops->set_key(&local->hw, cmd, &sdata->vif, sta, key);
- trace_drv_set_key(local, cmd, sdata, sta, key, ret);
+ trace_drv_return_int(local, ret);
return ret;
}
@@ -145,10 +156,11 @@ static inline void drv_update_tkip_key(struct ieee80211_local *local,
if (sta)
ista = &sta->sta;
+ trace_drv_update_tkip_key(local, sdata, conf, ista, iv32);
if (local->ops->update_tkip_key)
local->ops->update_tkip_key(&local->hw, &sdata->vif, conf,
ista, iv32, phase1key);
- trace_drv_update_tkip_key(local, sdata, conf, ista, iv32);
+ trace_drv_return_void(local);
}
static inline int drv_hw_scan(struct ieee80211_local *local,
@@ -159,8 +171,9 @@ static inline int drv_hw_scan(struct ieee80211_local *local,
might_sleep();
+ trace_drv_hw_scan(local, sdata, req);
ret = local->ops->hw_scan(&local->hw, &sdata->vif, req);
- trace_drv_hw_scan(local, sdata, req, ret);
+ trace_drv_return_int(local, ret);
return ret;
}
@@ -168,18 +181,20 @@ static inline void drv_sw_scan_start(struct ieee80211_local *local)
{
might_sleep();
+ trace_drv_sw_scan_start(local);
if (local->ops->sw_scan_start)
local->ops->sw_scan_start(&local->hw);
- trace_drv_sw_scan_start(local);
+ trace_drv_return_void(local);
}
static inline void drv_sw_scan_complete(struct ieee80211_local *local)
{
might_sleep();
+ trace_drv_sw_scan_complete(local);
if (local->ops->sw_scan_complete)
local->ops->sw_scan_complete(&local->hw);
- trace_drv_sw_scan_complete(local);
+ trace_drv_return_void(local);
}
static inline int drv_get_stats(struct ieee80211_local *local,
@@ -211,9 +226,10 @@ static inline int drv_set_rts_threshold(struct ieee80211_local *local,
might_sleep();
+ trace_drv_set_rts_threshold(local, value);
if (local->ops->set_rts_threshold)
ret = local->ops->set_rts_threshold(&local->hw, value);
- trace_drv_set_rts_threshold(local, value, ret);
+ trace_drv_return_int(local, ret);
return ret;
}
@@ -223,12 +239,13 @@ static inline int drv_set_coverage_class(struct ieee80211_local *local,
int ret = 0;
might_sleep();
+ trace_drv_set_coverage_class(local, value);
if (local->ops->set_coverage_class)
local->ops->set_coverage_class(&local->hw, value);
else
ret = -EOPNOTSUPP;
- trace_drv_set_coverage_class(local, value, ret);
+ trace_drv_return_int(local, ret);
return ret;
}
@@ -237,9 +254,10 @@ static inline void drv_sta_notify(struct ieee80211_local *local,
enum sta_notify_cmd cmd,
struct ieee80211_sta *sta)
{
+ trace_drv_sta_notify(local, sdata, cmd, sta);
if (local->ops->sta_notify)
local->ops->sta_notify(&local->hw, &sdata->vif, cmd, sta);
- trace_drv_sta_notify(local, sdata, cmd, sta);
+ trace_drv_return_void(local);
}
static inline int drv_sta_add(struct ieee80211_local *local,
@@ -250,13 +268,11 @@ static inline int drv_sta_add(struct ieee80211_local *local,
might_sleep();
+ trace_drv_sta_add(local, sdata, sta);
if (local->ops->sta_add)
ret = local->ops->sta_add(&local->hw, &sdata->vif, sta);
- else if (local->ops->sta_notify)
- local->ops->sta_notify(&local->hw, &sdata->vif,
- STA_NOTIFY_ADD, sta);
- trace_drv_sta_add(local, sdata, sta, ret);
+ trace_drv_return_int(local, ret);
return ret;
}
@@ -267,13 +283,11 @@ static inline void drv_sta_remove(struct ieee80211_local *local,
{
might_sleep();
+ trace_drv_sta_remove(local, sdata, sta);
if (local->ops->sta_remove)
local->ops->sta_remove(&local->hw, &sdata->vif, sta);
- else if (local->ops->sta_notify)
- local->ops->sta_notify(&local->hw, &sdata->vif,
- STA_NOTIFY_REMOVE, sta);
- trace_drv_sta_remove(local, sdata, sta);
+ trace_drv_return_void(local);
}
static inline int drv_conf_tx(struct ieee80211_local *local, u16 queue,
@@ -283,9 +297,10 @@ static inline int drv_conf_tx(struct ieee80211_local *local, u16 queue,
might_sleep();
+ trace_drv_conf_tx(local, queue, params);
if (local->ops->conf_tx)
ret = local->ops->conf_tx(&local->hw, queue, params);
- trace_drv_conf_tx(local, queue, params, ret);
+ trace_drv_return_int(local, ret);
return ret;
}
@@ -295,9 +310,10 @@ static inline u64 drv_get_tsf(struct ieee80211_local *local)
might_sleep();
+ trace_drv_get_tsf(local);
if (local->ops->get_tsf)
ret = local->ops->get_tsf(&local->hw);
- trace_drv_get_tsf(local, ret);
+ trace_drv_return_u64(local, ret);
return ret;
}
@@ -305,18 +321,20 @@ static inline void drv_set_tsf(struct ieee80211_local *local, u64 tsf)
{
might_sleep();
+ trace_drv_set_tsf(local, tsf);
if (local->ops->set_tsf)
local->ops->set_tsf(&local->hw, tsf);
- trace_drv_set_tsf(local, tsf);
+ trace_drv_return_void(local);
}
static inline void drv_reset_tsf(struct ieee80211_local *local)
{
might_sleep();
+ trace_drv_reset_tsf(local);
if (local->ops->reset_tsf)
local->ops->reset_tsf(&local->hw);
- trace_drv_reset_tsf(local);
+ trace_drv_return_void(local);
}
static inline int drv_tx_last_beacon(struct ieee80211_local *local)
@@ -325,9 +343,10 @@ static inline int drv_tx_last_beacon(struct ieee80211_local *local)
might_sleep();
+ trace_drv_tx_last_beacon(local);
if (local->ops->tx_last_beacon)
ret = local->ops->tx_last_beacon(&local->hw);
- trace_drv_tx_last_beacon(local, ret);
+ trace_drv_return_int(local, ret);
return ret;
}
@@ -338,10 +357,17 @@ static inline int drv_ampdu_action(struct ieee80211_local *local,
u16 *ssn)
{
int ret = -EOPNOTSUPP;
+
+ might_sleep();
+
+ trace_drv_ampdu_action(local, sdata, action, sta, tid, ssn);
+
if (local->ops->ampdu_action)
ret = local->ops->ampdu_action(&local->hw, &sdata->vif, action,
sta, tid, ssn);
- trace_drv_ampdu_action(local, sdata, action, sta, tid, ssn, ret);
+
+ trace_drv_return_int(local, ret);
+
return ret;
}
@@ -349,9 +375,14 @@ static inline int drv_get_survey(struct ieee80211_local *local, int idx,
struct survey_info *survey)
{
int ret = -EOPNOTSUPP;
+
+ trace_drv_get_survey(local, idx, survey);
+
if (local->ops->get_survey)
ret = local->ops->get_survey(&local->hw, idx, survey);
- /* trace_drv_get_survey(local, idx, survey, ret); */
+
+ trace_drv_return_int(local, ret);
+
return ret;
}
@@ -370,6 +401,7 @@ static inline void drv_flush(struct ieee80211_local *local, bool drop)
trace_drv_flush(local, drop);
if (local->ops->flush)
local->ops->flush(&local->hw, drop);
+ trace_drv_return_void(local);
}
static inline void drv_channel_switch(struct ieee80211_local *local,
@@ -377,9 +409,9 @@ static inline void drv_channel_switch(struct ieee80211_local *local,
{
might_sleep();
- local->ops->channel_switch(&local->hw, ch_switch);
-
trace_drv_channel_switch(local, ch_switch);
+ local->ops->channel_switch(&local->hw, ch_switch);
+ trace_drv_return_void(local);
}
#endif /* __MAC80211_DRIVER_OPS */
diff --git a/net/mac80211/driver-trace.h b/net/mac80211/driver-trace.h
index 6a9b2342a9c..5d5d2a97466 100644
--- a/net/mac80211/driver-trace.h
+++ b/net/mac80211/driver-trace.h
@@ -36,20 +36,58 @@ static inline void trace_ ## name(proto) {}
* Tracing for driver callbacks.
*/
-TRACE_EVENT(drv_start,
- TP_PROTO(struct ieee80211_local *local, int ret),
+TRACE_EVENT(drv_return_void,
+ TP_PROTO(struct ieee80211_local *local),
+ TP_ARGS(local),
+ TP_STRUCT__entry(
+ LOCAL_ENTRY
+ ),
+ TP_fast_assign(
+ LOCAL_ASSIGN;
+ ),
+ TP_printk(LOCAL_PR_FMT, LOCAL_PR_ARG)
+);
+TRACE_EVENT(drv_return_int,
+ TP_PROTO(struct ieee80211_local *local, int ret),
TP_ARGS(local, ret),
-
TP_STRUCT__entry(
LOCAL_ENTRY
__field(int, ret)
),
+ TP_fast_assign(
+ LOCAL_ASSIGN;
+ __entry->ret = ret;
+ ),
+ TP_printk(LOCAL_PR_FMT " - %d", LOCAL_PR_ARG, __entry->ret)
+);
+TRACE_EVENT(drv_return_u64,
+ TP_PROTO(struct ieee80211_local *local, u64 ret),
+ TP_ARGS(local, ret),
+ TP_STRUCT__entry(
+ LOCAL_ENTRY
+ __field(u64, ret)
+ ),
TP_fast_assign(
LOCAL_ASSIGN;
__entry->ret = ret;
),
+ TP_printk(LOCAL_PR_FMT " - %llu", LOCAL_PR_ARG, __entry->ret)
+);
+
+TRACE_EVENT(drv_start,
+ TP_PROTO(struct ieee80211_local *local),
+
+ TP_ARGS(local),
+
+ TP_STRUCT__entry(
+ LOCAL_ENTRY
+ ),
+
+ TP_fast_assign(
+ LOCAL_ASSIGN;
+ ),
TP_printk(
LOCAL_PR_FMT, LOCAL_PR_ARG
@@ -76,28 +114,25 @@ TRACE_EVENT(drv_stop,
TRACE_EVENT(drv_add_interface,
TP_PROTO(struct ieee80211_local *local,
- struct ieee80211_sub_if_data *sdata,
- int ret),
+ struct ieee80211_sub_if_data *sdata),
- TP_ARGS(local, sdata, ret),
+ TP_ARGS(local, sdata),
TP_STRUCT__entry(
LOCAL_ENTRY
VIF_ENTRY
__array(char, addr, 6)
- __field(int, ret)
),
TP_fast_assign(
LOCAL_ASSIGN;
VIF_ASSIGN;
memcpy(__entry->addr, sdata->vif.addr, 6);
- __entry->ret = ret;
),
TP_printk(
- LOCAL_PR_FMT VIF_PR_FMT " addr:%pM ret:%d",
- LOCAL_PR_ARG, VIF_PR_ARG, __entry->addr, __entry->ret
+ LOCAL_PR_FMT VIF_PR_FMT " addr:%pM",
+ LOCAL_PR_ARG, VIF_PR_ARG, __entry->addr
)
);
@@ -126,15 +161,13 @@ TRACE_EVENT(drv_remove_interface,
TRACE_EVENT(drv_config,
TP_PROTO(struct ieee80211_local *local,
- u32 changed,
- int ret),
+ u32 changed),
- TP_ARGS(local, changed, ret),
+ TP_ARGS(local, changed),
TP_STRUCT__entry(
LOCAL_ENTRY
__field(u32, changed)
- __field(int, ret)
__field(u32, flags)
__field(int, power_level)
__field(int, dynamic_ps_timeout)
@@ -150,7 +183,6 @@ TRACE_EVENT(drv_config,
TP_fast_assign(
LOCAL_ASSIGN;
__entry->changed = changed;
- __entry->ret = ret;
__entry->flags = local->hw.conf.flags;
__entry->power_level = local->hw.conf.power_level;
__entry->dynamic_ps_timeout = local->hw.conf.dynamic_ps_timeout;
@@ -164,8 +196,8 @@ TRACE_EVENT(drv_config,
),
TP_printk(
- LOCAL_PR_FMT " ch:%#x freq:%d ret:%d",
- LOCAL_PR_ARG, __entry->changed, __entry->center_freq, __entry->ret
+ LOCAL_PR_FMT " ch:%#x freq:%d",
+ LOCAL_PR_ARG, __entry->changed, __entry->center_freq
)
);
@@ -220,26 +252,23 @@ TRACE_EVENT(drv_bss_info_changed,
);
TRACE_EVENT(drv_prepare_multicast,
- TP_PROTO(struct ieee80211_local *local, int mc_count, u64 ret),
+ TP_PROTO(struct ieee80211_local *local, int mc_count),
- TP_ARGS(local, mc_count, ret),
+ TP_ARGS(local, mc_count),
TP_STRUCT__entry(
LOCAL_ENTRY
__field(int, mc_count)
- __field(u64, ret)
),
TP_fast_assign(
LOCAL_ASSIGN;
__entry->mc_count = mc_count;
- __entry->ret = ret;
),
TP_printk(
- LOCAL_PR_FMT " prepare mc (%d): %llx",
- LOCAL_PR_ARG, __entry->mc_count,
- (unsigned long long) __entry->ret
+ LOCAL_PR_FMT " prepare mc (%d)",
+ LOCAL_PR_ARG, __entry->mc_count
)
);
@@ -273,27 +302,25 @@ TRACE_EVENT(drv_configure_filter,
TRACE_EVENT(drv_set_tim,
TP_PROTO(struct ieee80211_local *local,
- struct ieee80211_sta *sta, bool set, int ret),
+ struct ieee80211_sta *sta, bool set),
- TP_ARGS(local, sta, set, ret),
+ TP_ARGS(local, sta, set),
TP_STRUCT__entry(
LOCAL_ENTRY
STA_ENTRY
__field(bool, set)
- __field(int, ret)
),
TP_fast_assign(
LOCAL_ASSIGN;
STA_ASSIGN;
__entry->set = set;
- __entry->ret = ret;
),
TP_printk(
- LOCAL_PR_FMT STA_PR_FMT " set:%d ret:%d",
- LOCAL_PR_ARG, STA_PR_FMT, __entry->set, __entry->ret
+ LOCAL_PR_FMT STA_PR_FMT " set:%d",
+ LOCAL_PR_ARG, STA_PR_FMT, __entry->set
)
);
@@ -301,9 +328,9 @@ TRACE_EVENT(drv_set_key,
TP_PROTO(struct ieee80211_local *local,
enum set_key_cmd cmd, struct ieee80211_sub_if_data *sdata,
struct ieee80211_sta *sta,
- struct ieee80211_key_conf *key, int ret),
+ struct ieee80211_key_conf *key),
- TP_ARGS(local, cmd, sdata, sta, key, ret),
+ TP_ARGS(local, cmd, sdata, sta, key),
TP_STRUCT__entry(
LOCAL_ENTRY
@@ -313,7 +340,6 @@ TRACE_EVENT(drv_set_key,
__field(u8, hw_key_idx)
__field(u8, flags)
__field(s8, keyidx)
- __field(int, ret)
),
TP_fast_assign(
@@ -324,12 +350,11 @@ TRACE_EVENT(drv_set_key,
__entry->flags = key->flags;
__entry->keyidx = key->keyidx;
__entry->hw_key_idx = key->hw_key_idx;
- __entry->ret = ret;
),
TP_printk(
- LOCAL_PR_FMT VIF_PR_FMT STA_PR_FMT " ret:%d",
- LOCAL_PR_ARG, VIF_PR_ARG, STA_PR_ARG, __entry->ret
+ LOCAL_PR_FMT VIF_PR_FMT STA_PR_FMT,
+ LOCAL_PR_ARG, VIF_PR_ARG, STA_PR_ARG
)
);
@@ -364,25 +389,23 @@ TRACE_EVENT(drv_update_tkip_key,
TRACE_EVENT(drv_hw_scan,
TP_PROTO(struct ieee80211_local *local,
struct ieee80211_sub_if_data *sdata,
- struct cfg80211_scan_request *req, int ret),
+ struct cfg80211_scan_request *req),
- TP_ARGS(local, sdata, req, ret),
+ TP_ARGS(local, sdata, req),
TP_STRUCT__entry(
LOCAL_ENTRY
VIF_ENTRY
- __field(int, ret)
),
TP_fast_assign(
LOCAL_ASSIGN;
VIF_ASSIGN;
- __entry->ret = ret;
),
TP_printk(
- LOCAL_PR_FMT VIF_PR_FMT " ret:%d",
- LOCAL_PR_ARG,VIF_PR_ARG, __entry->ret
+ LOCAL_PR_FMT VIF_PR_FMT,
+ LOCAL_PR_ARG,VIF_PR_ARG
)
);
@@ -479,48 +502,44 @@ TRACE_EVENT(drv_get_tkip_seq,
);
TRACE_EVENT(drv_set_rts_threshold,
- TP_PROTO(struct ieee80211_local *local, u32 value, int ret),
+ TP_PROTO(struct ieee80211_local *local, u32 value),
- TP_ARGS(local, value, ret),
+ TP_ARGS(local, value),
TP_STRUCT__entry(
LOCAL_ENTRY
__field(u32, value)
- __field(int, ret)
),
TP_fast_assign(
LOCAL_ASSIGN;
- __entry->ret = ret;
__entry->value = value;
),
TP_printk(
- LOCAL_PR_FMT " value:%d ret:%d",
- LOCAL_PR_ARG, __entry->value, __entry->ret
+ LOCAL_PR_FMT " value:%d",
+ LOCAL_PR_ARG, __entry->value
)
);
TRACE_EVENT(drv_set_coverage_class,
- TP_PROTO(struct ieee80211_local *local, u8 value, int ret),
+ TP_PROTO(struct ieee80211_local *local, u8 value),
- TP_ARGS(local, value, ret),
+ TP_ARGS(local, value),
TP_STRUCT__entry(
LOCAL_ENTRY
__field(u8, value)
- __field(int, ret)
),
TP_fast_assign(
LOCAL_ASSIGN;
- __entry->ret = ret;
__entry->value = value;
),
TP_printk(
- LOCAL_PR_FMT " value:%d ret:%d",
- LOCAL_PR_ARG, __entry->value, __entry->ret
+ LOCAL_PR_FMT " value:%d",
+ LOCAL_PR_ARG, __entry->value
)
);
@@ -555,27 +574,25 @@ TRACE_EVENT(drv_sta_notify,
TRACE_EVENT(drv_sta_add,
TP_PROTO(struct ieee80211_local *local,
struct ieee80211_sub_if_data *sdata,
- struct ieee80211_sta *sta, int ret),
+ struct ieee80211_sta *sta),
- TP_ARGS(local, sdata, sta, ret),
+ TP_ARGS(local, sdata, sta),
TP_STRUCT__entry(
LOCAL_ENTRY
VIF_ENTRY
STA_ENTRY
- __field(int, ret)
),
TP_fast_assign(
LOCAL_ASSIGN;
VIF_ASSIGN;
STA_ASSIGN;
- __entry->ret = ret;
),
TP_printk(
- LOCAL_PR_FMT VIF_PR_FMT STA_PR_FMT " ret:%d",
- LOCAL_PR_ARG, VIF_PR_ARG, STA_PR_ARG, __entry->ret
+ LOCAL_PR_FMT VIF_PR_FMT STA_PR_FMT,
+ LOCAL_PR_ARG, VIF_PR_ARG, STA_PR_ARG
)
);
@@ -606,10 +623,9 @@ TRACE_EVENT(drv_sta_remove,
TRACE_EVENT(drv_conf_tx,
TP_PROTO(struct ieee80211_local *local, u16 queue,
- const struct ieee80211_tx_queue_params *params,
- int ret),
+ const struct ieee80211_tx_queue_params *params),
- TP_ARGS(local, queue, params, ret),
+ TP_ARGS(local, queue, params),
TP_STRUCT__entry(
LOCAL_ENTRY
@@ -618,13 +634,11 @@ TRACE_EVENT(drv_conf_tx,
__field(u16, cw_min)
__field(u16, cw_max)
__field(u8, aifs)
- __field(int, ret)
),
TP_fast_assign(
LOCAL_ASSIGN;
__entry->queue = queue;
- __entry->ret = ret;
__entry->txop = params->txop;
__entry->cw_max = params->cw_max;
__entry->cw_min = params->cw_min;
@@ -632,29 +646,27 @@ TRACE_EVENT(drv_conf_tx,
),
TP_printk(
- LOCAL_PR_FMT " queue:%d ret:%d",
- LOCAL_PR_ARG, __entry->queue, __entry->ret
+ LOCAL_PR_FMT " queue:%d",
+ LOCAL_PR_ARG, __entry->queue
)
);
TRACE_EVENT(drv_get_tsf,
- TP_PROTO(struct ieee80211_local *local, u64 ret),
+ TP_PROTO(struct ieee80211_local *local),
- TP_ARGS(local, ret),
+ TP_ARGS(local),
TP_STRUCT__entry(
LOCAL_ENTRY
- __field(u64, ret)
),
TP_fast_assign(
LOCAL_ASSIGN;
- __entry->ret = ret;
),
TP_printk(
- LOCAL_PR_FMT " ret:%llu",
- LOCAL_PR_ARG, (unsigned long long)__entry->ret
+ LOCAL_PR_FMT,
+ LOCAL_PR_ARG
)
);
@@ -698,23 +710,21 @@ TRACE_EVENT(drv_reset_tsf,
);
TRACE_EVENT(drv_tx_last_beacon,
- TP_PROTO(struct ieee80211_local *local, int ret),
+ TP_PROTO(struct ieee80211_local *local),
- TP_ARGS(local, ret),
+ TP_ARGS(local),
TP_STRUCT__entry(
LOCAL_ENTRY
- __field(int, ret)
),
TP_fast_assign(
LOCAL_ASSIGN;
- __entry->ret = ret;
),
TP_printk(
- LOCAL_PR_FMT " ret:%d",
- LOCAL_PR_ARG, __entry->ret
+ LOCAL_PR_FMT,
+ LOCAL_PR_ARG
)
);
@@ -723,9 +733,9 @@ TRACE_EVENT(drv_ampdu_action,
struct ieee80211_sub_if_data *sdata,
enum ieee80211_ampdu_mlme_action action,
struct ieee80211_sta *sta, u16 tid,
- u16 *ssn, int ret),
+ u16 *ssn),
- TP_ARGS(local, sdata, action, sta, tid, ssn, ret),
+ TP_ARGS(local, sdata, action, sta, tid, ssn),
TP_STRUCT__entry(
LOCAL_ENTRY
@@ -733,7 +743,6 @@ TRACE_EVENT(drv_ampdu_action,
__field(u32, action)
__field(u16, tid)
__field(u16, ssn)
- __field(int, ret)
VIF_ENTRY
),
@@ -741,15 +750,36 @@ TRACE_EVENT(drv_ampdu_action,
LOCAL_ASSIGN;
VIF_ASSIGN;
STA_ASSIGN;
- __entry->ret = ret;
__entry->action = action;
__entry->tid = tid;
__entry->ssn = ssn ? *ssn : 0;
),
TP_printk(
- LOCAL_PR_FMT VIF_PR_FMT STA_PR_FMT " action:%d tid:%d ret:%d",
- LOCAL_PR_ARG, VIF_PR_ARG, STA_PR_ARG, __entry->action, __entry->tid, __entry->ret
+ LOCAL_PR_FMT VIF_PR_FMT STA_PR_FMT " action:%d tid:%d",
+ LOCAL_PR_ARG, VIF_PR_ARG, STA_PR_ARG, __entry->action, __entry->tid
+ )
+);
+
+TRACE_EVENT(drv_get_survey,
+ TP_PROTO(struct ieee80211_local *local, int idx,
+ struct survey_info *survey),
+
+ TP_ARGS(local, idx, survey),
+
+ TP_STRUCT__entry(
+ LOCAL_ENTRY
+ __field(int, idx)
+ ),
+
+ TP_fast_assign(
+ LOCAL_ASSIGN;
+ __entry->idx = idx;
+ ),
+
+ TP_printk(
+ LOCAL_PR_FMT " idx:%d",
+ LOCAL_PR_ARG, __entry->idx
)
);
@@ -851,25 +881,23 @@ TRACE_EVENT(api_start_tx_ba_cb,
);
TRACE_EVENT(api_stop_tx_ba_session,
- TP_PROTO(struct ieee80211_sta *sta, u16 tid, u16 initiator),
+ TP_PROTO(struct ieee80211_sta *sta, u16 tid),
- TP_ARGS(sta, tid, initiator),
+ TP_ARGS(sta, tid),
TP_STRUCT__entry(
STA_ENTRY
__field(u16, tid)
- __field(u16, initiator)
),
TP_fast_assign(
STA_ASSIGN;
__entry->tid = tid;
- __entry->initiator = initiator;
),
TP_printk(
- STA_PR_FMT " tid:%d initiator:%d",
- STA_PR_ARG, __entry->tid, __entry->initiator
+ STA_PR_FMT " tid:%d",
+ STA_PR_ARG, __entry->tid
)
);
diff --git a/net/mac80211/ht.c b/net/mac80211/ht.c
index 2ab106a0a49..9d101fb3386 100644
--- a/net/mac80211/ht.c
+++ b/net/mac80211/ht.c
@@ -6,7 +6,7 @@
* Copyright 2005-2006, Devicescape Software, Inc.
* Copyright 2006-2007 Jiri Benc <jbenc@suse.cz>
* Copyright 2007, Michael Wu <flamingice@sourmilk.net>
- * Copyright 2007-2008, Intel Corporation
+ * Copyright 2007-2010, Intel 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
@@ -29,7 +29,7 @@ void ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_supported_band *sband,
memset(ht_cap, 0, sizeof(*ht_cap));
- if (!ht_cap_ie)
+ if (!ht_cap_ie || !sband->ht_cap.ht_supported)
return;
ht_cap->ht_supported = true;
@@ -105,6 +105,8 @@ void ieee80211_sta_tear_down_BA_sessions(struct sta_info *sta)
{
int i;
+ cancel_work_sync(&sta->ampdu_mlme.work);
+
for (i = 0; i < STA_TID_NUM; i++) {
__ieee80211_stop_tx_ba_session(sta, i, WLAN_BACK_INITIATOR);
__ieee80211_stop_rx_ba_session(sta, i, WLAN_BACK_RECIPIENT,
@@ -112,6 +114,43 @@ void ieee80211_sta_tear_down_BA_sessions(struct sta_info *sta)
}
}
+void ieee80211_ba_session_work(struct work_struct *work)
+{
+ struct sta_info *sta =
+ container_of(work, struct sta_info, ampdu_mlme.work);
+ struct tid_ampdu_tx *tid_tx;
+ int tid;
+
+ /*
+ * When this flag is set, new sessions should be
+ * blocked, and existing sessions will be torn
+ * down by the code that set the flag, so this
+ * need not run.
+ */
+ if (test_sta_flags(sta, WLAN_STA_BLOCK_BA))
+ return;
+
+ mutex_lock(&sta->ampdu_mlme.mtx);
+ for (tid = 0; tid < STA_TID_NUM; tid++) {
+ if (test_and_clear_bit(tid, sta->ampdu_mlme.tid_rx_timer_expired))
+ ___ieee80211_stop_rx_ba_session(
+ sta, tid, WLAN_BACK_RECIPIENT,
+ WLAN_REASON_QSTA_TIMEOUT);
+
+ tid_tx = sta->ampdu_mlme.tid_tx[tid];
+ if (!tid_tx)
+ continue;
+
+ if (test_bit(HT_AGG_STATE_WANT_START, &tid_tx->state))
+ ieee80211_tx_ba_session_handle_start(sta, tid);
+ else if (test_and_clear_bit(HT_AGG_STATE_WANT_STOP,
+ &tid_tx->state))
+ ___ieee80211_stop_tx_ba_session(sta, tid,
+ WLAN_BACK_INITIATOR);
+ }
+ mutex_unlock(&sta->ampdu_mlme.mtx);
+}
+
void ieee80211_send_delba(struct ieee80211_sub_if_data *sdata,
const u8 *da, u16 tid,
u16 initiator, u16 reason_code)
@@ -176,13 +215,8 @@ void ieee80211_process_delba(struct ieee80211_sub_if_data *sdata,
if (initiator == WLAN_BACK_INITIATOR)
__ieee80211_stop_rx_ba_session(sta, tid, WLAN_BACK_INITIATOR, 0);
- else { /* WLAN_BACK_RECIPIENT */
- spin_lock_bh(&sta->lock);
- if (sta->ampdu_mlme.tid_state_tx[tid] & HT_ADDBA_REQUESTED_MSK)
- ___ieee80211_stop_tx_ba_session(sta, tid,
- WLAN_BACK_RECIPIENT);
- spin_unlock_bh(&sta->lock);
- }
+ else
+ __ieee80211_stop_tx_ba_session(sta, tid, WLAN_BACK_RECIPIENT);
}
int ieee80211_send_smps_action(struct ieee80211_sub_if_data *sdata,
diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c
index b2cc1fda6cf..c691780725a 100644
--- a/net/mac80211/ibss.c
+++ b/net/mac80211/ibss.c
@@ -43,6 +43,8 @@ static void ieee80211_rx_mgmt_auth_ibss(struct ieee80211_sub_if_data *sdata,
{
u16 auth_alg, auth_transaction, status_code;
+ lockdep_assert_held(&sdata->u.ibss.mtx);
+
if (len < 24 + 6)
return;
@@ -78,6 +80,8 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
u32 bss_change;
u8 supp_rates[IEEE80211_MAX_SUPP_RATES];
+ lockdep_assert_held(&ifibss->mtx);
+
/* Reset own TSF to allow time synchronization work. */
drv_reset_tsf(local);
@@ -172,11 +176,13 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
rcu_assign_pointer(ifibss->presp, skb);
sdata->vif.bss_conf.beacon_int = beacon_int;
+ sdata->vif.bss_conf.basic_rates = basic_rates;
bss_change = BSS_CHANGED_BEACON_INT;
bss_change |= ieee80211_reset_erp_info(sdata);
bss_change |= BSS_CHANGED_BSSID;
bss_change |= BSS_CHANGED_BEACON;
bss_change |= BSS_CHANGED_BEACON_ENABLED;
+ bss_change |= BSS_CHANGED_BASIC_RATES;
bss_change |= BSS_CHANGED_IBSS;
sdata->vif.bss_conf.ibss_joined = true;
ieee80211_bss_info_change_notify(sdata, bss_change);
@@ -203,6 +209,8 @@ static void ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
int i, j;
u16 beacon_int = cbss->beacon_interval;
+ lockdep_assert_held(&sdata->u.ibss.mtx);
+
if (beacon_int < 10)
beacon_int = 10;
@@ -447,6 +455,8 @@ static int ieee80211_sta_active_ibss(struct ieee80211_sub_if_data *sdata)
int active = 0;
struct sta_info *sta;
+ lockdep_assert_held(&sdata->u.ibss.mtx);
+
rcu_read_lock();
list_for_each_entry_rcu(sta, &local->sta_list, list) {
@@ -471,6 +481,8 @@ static void ieee80211_sta_merge_ibss(struct ieee80211_sub_if_data *sdata)
{
struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
+ lockdep_assert_held(&ifibss->mtx);
+
mod_timer(&ifibss->timer,
round_jiffies(jiffies + IEEE80211_IBSS_MERGE_INTERVAL));
@@ -503,6 +515,8 @@ static void ieee80211_sta_create_ibss(struct ieee80211_sub_if_data *sdata)
u16 capability;
int i;
+ lockdep_assert_held(&ifibss->mtx);
+
if (ifibss->fixed_bssid) {
memcpy(bssid, ifibss->bssid, ETH_ALEN);
} else {
@@ -529,7 +543,7 @@ static void ieee80211_sta_create_ibss(struct ieee80211_sub_if_data *sdata)
sdata->drop_unencrypted = 0;
__ieee80211_sta_join_ibss(sdata, bssid, sdata->vif.bss_conf.beacon_int,
- ifibss->channel, 3, /* first two are basic */
+ ifibss->channel, ifibss->basic_rates,
capability, 0);
}
@@ -547,6 +561,8 @@ static void ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata)
int active_ibss;
u16 capability;
+ lockdep_assert_held(&ifibss->mtx);
+
active_ibss = ieee80211_sta_active_ibss(sdata);
#ifdef CONFIG_MAC80211_IBSS_DEBUG
printk(KERN_DEBUG "%s: sta_find_ibss (active_ibss=%d)\n",
@@ -635,6 +651,8 @@ static void ieee80211_rx_mgmt_probe_req(struct ieee80211_sub_if_data *sdata,
struct ieee80211_mgmt *resp;
u8 *pos, *end;
+ lockdep_assert_held(&ifibss->mtx);
+
if (ifibss->state != IEEE80211_IBSS_MLME_JOINED ||
len < 24 + 2 || !ifibss->presp)
return;
@@ -727,8 +745,8 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems, true);
}
-static void ieee80211_ibss_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
- struct sk_buff *skb)
+void ieee80211_ibss_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
+ struct sk_buff *skb)
{
struct ieee80211_rx_status *rx_status;
struct ieee80211_mgmt *mgmt;
@@ -738,6 +756,8 @@ static void ieee80211_ibss_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
mgmt = (struct ieee80211_mgmt *) skb->data;
fc = le16_to_cpu(mgmt->frame_control);
+ mutex_lock(&sdata->u.ibss.mtx);
+
switch (fc & IEEE80211_FCTL_STYPE) {
case IEEE80211_STYPE_PROBE_REQ:
ieee80211_rx_mgmt_probe_req(sdata, mgmt, skb->len);
@@ -755,35 +775,22 @@ static void ieee80211_ibss_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
break;
}
- kfree_skb(skb);
+ mutex_unlock(&sdata->u.ibss.mtx);
}
-static void ieee80211_ibss_work(struct work_struct *work)
+void ieee80211_ibss_work(struct ieee80211_sub_if_data *sdata)
{
- struct ieee80211_sub_if_data *sdata =
- container_of(work, struct ieee80211_sub_if_data, u.ibss.work);
- struct ieee80211_local *local = sdata->local;
- struct ieee80211_if_ibss *ifibss;
- struct sk_buff *skb;
-
- if (WARN_ON(local->suspended))
- return;
-
- if (!ieee80211_sdata_running(sdata))
- return;
-
- if (local->scanning)
- return;
-
- if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_ADHOC))
- return;
- ifibss = &sdata->u.ibss;
+ struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
- while ((skb = skb_dequeue(&ifibss->skb_queue)))
- ieee80211_ibss_rx_queued_mgmt(sdata, skb);
+ mutex_lock(&ifibss->mtx);
- if (!test_and_clear_bit(IEEE80211_IBSS_REQ_RUN, &ifibss->request))
- return;
+ /*
+ * Work could be scheduled after scan or similar
+ * when we aren't even joined (or trying) with a
+ * network.
+ */
+ if (!ifibss->ssid_len)
+ goto out;
switch (ifibss->state) {
case IEEE80211_IBSS_MLME_SEARCH:
@@ -796,6 +803,9 @@ static void ieee80211_ibss_work(struct work_struct *work)
WARN_ON(1);
break;
}
+
+ out:
+ mutex_unlock(&ifibss->mtx);
}
static void ieee80211_ibss_timer(unsigned long data)
@@ -810,8 +820,7 @@ static void ieee80211_ibss_timer(unsigned long data)
return;
}
- set_bit(IEEE80211_IBSS_REQ_RUN, &ifibss->request);
- ieee80211_queue_work(&local->hw, &ifibss->work);
+ ieee80211_queue_work(&local->hw, &sdata->work);
}
#ifdef CONFIG_PM
@@ -819,7 +828,6 @@ void ieee80211_ibss_quiesce(struct ieee80211_sub_if_data *sdata)
{
struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
- cancel_work_sync(&ifibss->work);
if (del_timer_sync(&ifibss->timer))
ifibss->timer_running = true;
}
@@ -839,10 +847,9 @@ void ieee80211_ibss_setup_sdata(struct ieee80211_sub_if_data *sdata)
{
struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
- INIT_WORK(&ifibss->work, ieee80211_ibss_work);
setup_timer(&ifibss->timer, ieee80211_ibss_timer,
(unsigned long) sdata);
- skb_queue_head_init(&ifibss->skb_queue);
+ mutex_init(&ifibss->mtx);
}
/* scan finished notification */
@@ -856,45 +863,28 @@ void ieee80211_ibss_notify_scan_completed(struct ieee80211_local *local)
continue;
if (sdata->vif.type != NL80211_IFTYPE_ADHOC)
continue;
- if (!sdata->u.ibss.ssid_len)
- continue;
sdata->u.ibss.last_scan_completed = jiffies;
- mod_timer(&sdata->u.ibss.timer, 0);
+ ieee80211_queue_work(&local->hw, &sdata->work);
}
mutex_unlock(&local->iflist_mtx);
}
-ieee80211_rx_result
-ieee80211_ibss_rx_mgmt(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb)
-{
- struct ieee80211_local *local = sdata->local;
- struct ieee80211_mgmt *mgmt;
- u16 fc;
-
- if (skb->len < 24)
- return RX_DROP_MONITOR;
-
- mgmt = (struct ieee80211_mgmt *) skb->data;
- fc = le16_to_cpu(mgmt->frame_control);
-
- switch (fc & IEEE80211_FCTL_STYPE) {
- case IEEE80211_STYPE_PROBE_RESP:
- case IEEE80211_STYPE_BEACON:
- case IEEE80211_STYPE_PROBE_REQ:
- case IEEE80211_STYPE_AUTH:
- skb_queue_tail(&sdata->u.ibss.skb_queue, skb);
- ieee80211_queue_work(&local->hw, &sdata->u.ibss.work);
- return RX_QUEUED;
- }
-
- return RX_DROP_MONITOR;
-}
-
int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata,
struct cfg80211_ibss_params *params)
{
struct sk_buff *skb;
+ skb = dev_alloc_skb(sdata->local->hw.extra_tx_headroom +
+ 36 /* bitrates */ +
+ 34 /* SSID */ +
+ 3 /* DS params */ +
+ 4 /* IBSS params */ +
+ params->ie_len);
+ if (!skb)
+ return -ENOMEM;
+
+ mutex_lock(&sdata->u.ibss.mtx);
+
if (params->bssid) {
memcpy(sdata->u.ibss.bssid, params->bssid, ETH_ALEN);
sdata->u.ibss.fixed_bssid = true;
@@ -902,6 +892,7 @@ int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata,
sdata->u.ibss.fixed_bssid = false;
sdata->u.ibss.privacy = params->privacy;
+ sdata->u.ibss.basic_rates = params->basic_rates;
sdata->vif.bss_conf.beacon_int = params->beacon_interval;
@@ -922,34 +913,18 @@ int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata,
sdata->u.ibss.ie_len = params->ie_len;
}
- skb = dev_alloc_skb(sdata->local->hw.extra_tx_headroom +
- 36 /* bitrates */ +
- 34 /* SSID */ +
- 3 /* DS params */ +
- 4 /* IBSS params */ +
- params->ie_len);
- if (!skb)
- return -ENOMEM;
-
sdata->u.ibss.skb = skb;
sdata->u.ibss.state = IEEE80211_IBSS_MLME_SEARCH;
sdata->u.ibss.ibss_join_req = jiffies;
memcpy(sdata->u.ibss.ssid, params->ssid, IEEE80211_MAX_SSID_LEN);
-
- /*
- * The ssid_len setting below is used to see whether
- * we are active, and we need all other settings
- * before that may get visible.
- */
- mb();
-
sdata->u.ibss.ssid_len = params->ssid_len;
ieee80211_recalc_idle(sdata->local);
- set_bit(IEEE80211_IBSS_REQ_RUN, &sdata->u.ibss.request);
- ieee80211_queue_work(&sdata->local->hw, &sdata->u.ibss.work);
+ ieee80211_queue_work(&sdata->local->hw, &sdata->work);
+
+ mutex_unlock(&sdata->u.ibss.mtx);
return 0;
}
@@ -957,11 +932,33 @@ int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata,
int ieee80211_ibss_leave(struct ieee80211_sub_if_data *sdata)
{
struct sk_buff *skb;
+ struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
+ struct ieee80211_local *local = sdata->local;
+ struct cfg80211_bss *cbss;
+ u16 capability;
+ int active_ibss;
- del_timer_sync(&sdata->u.ibss.timer);
- clear_bit(IEEE80211_IBSS_REQ_RUN, &sdata->u.ibss.request);
- cancel_work_sync(&sdata->u.ibss.work);
- clear_bit(IEEE80211_IBSS_REQ_RUN, &sdata->u.ibss.request);
+ mutex_lock(&sdata->u.ibss.mtx);
+
+ active_ibss = ieee80211_sta_active_ibss(sdata);
+
+ if (!active_ibss && !is_zero_ether_addr(ifibss->bssid)) {
+ capability = WLAN_CAPABILITY_IBSS;
+
+ if (ifibss->privacy)
+ capability |= WLAN_CAPABILITY_PRIVACY;
+
+ cbss = cfg80211_get_bss(local->hw.wiphy, ifibss->channel,
+ ifibss->bssid, ifibss->ssid,
+ ifibss->ssid_len, WLAN_CAPABILITY_IBSS |
+ WLAN_CAPABILITY_PRIVACY,
+ capability);
+
+ if (cbss) {
+ cfg80211_unlink_bss(local->hw.wiphy, cbss);
+ cfg80211_put_bss(cbss);
+ }
+ }
sta_info_flush(sdata->local, sdata);
@@ -975,10 +972,14 @@ int ieee80211_ibss_leave(struct ieee80211_sub_if_data *sdata)
synchronize_rcu();
kfree_skb(skb);
- skb_queue_purge(&sdata->u.ibss.skb_queue);
+ skb_queue_purge(&sdata->skb_queue);
memset(sdata->u.ibss.bssid, 0, ETH_ALEN);
sdata->u.ibss.ssid_len = 0;
+ del_timer_sync(&sdata->u.ibss.timer);
+
+ mutex_unlock(&sdata->u.ibss.mtx);
+
ieee80211_recalc_idle(sdata->local);
return 0;
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 1a9e2da37a9..65e0ed6c297 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -238,6 +238,7 @@ enum ieee80211_work_type {
IEEE80211_WORK_ABORT,
IEEE80211_WORK_DIRECT_PROBE,
IEEE80211_WORK_AUTH,
+ IEEE80211_WORK_ASSOC_BEACON_WAIT,
IEEE80211_WORK_ASSOC,
IEEE80211_WORK_REMAIN_ON_CHANNEL,
};
@@ -325,7 +326,6 @@ struct ieee80211_if_managed {
struct timer_list conn_mon_timer;
struct timer_list bcn_mon_timer;
struct timer_list chswitch_timer;
- struct work_struct work;
struct work_struct monitor_work;
struct work_struct chswitch_work;
struct work_struct beacon_connection_loss_work;
@@ -340,8 +340,6 @@ struct ieee80211_if_managed {
u16 aid;
- struct sk_buff_head skb_queue;
-
unsigned long timers_running; /* used for quiesce/restart */
bool powersave; /* powersave requested for this iface */
enum ieee80211_smps_mode req_smps, /* requested smps mode */
@@ -380,19 +378,15 @@ struct ieee80211_if_managed {
int last_cqm_event_signal;
};
-enum ieee80211_ibss_request {
- IEEE80211_IBSS_REQ_RUN = 0,
-};
-
struct ieee80211_if_ibss {
struct timer_list timer;
- struct work_struct work;
- struct sk_buff_head skb_queue;
+ struct mutex mtx;
- unsigned long request;
unsigned long last_scan_completed;
+ u32 basic_rates;
+
bool timer_running;
bool fixed_bssid;
@@ -416,11 +410,9 @@ struct ieee80211_if_ibss {
};
struct ieee80211_if_mesh {
- struct work_struct work;
struct timer_list housekeeping_timer;
struct timer_list mesh_path_timer;
struct timer_list mesh_path_root_timer;
- struct sk_buff_head skb_queue;
unsigned long timers_running;
@@ -517,6 +509,11 @@ struct ieee80211_sub_if_data {
u16 sequence_number;
+ struct work_struct work;
+ struct sk_buff_head skb_queue;
+
+ bool arp_filter_state;
+
/*
* AP this belongs to: self in AP mode and
* corresponding AP in VLAN mode, NULL for
@@ -569,11 +566,15 @@ ieee80211_sdata_set_mesh_id(struct ieee80211_sub_if_data *sdata,
#endif
}
+enum sdata_queue_type {
+ IEEE80211_SDATA_QUEUE_TYPE_FRAME = 0,
+ IEEE80211_SDATA_QUEUE_AGG_START = 1,
+ IEEE80211_SDATA_QUEUE_AGG_STOP = 2,
+};
+
enum {
IEEE80211_RX_MSG = 1,
IEEE80211_TX_STATUS_MSG = 2,
- IEEE80211_DELBA_MSG = 3,
- IEEE80211_ADDBA_MSG = 4,
};
enum queue_stop_reason {
@@ -724,13 +725,7 @@ struct ieee80211_local {
struct sk_buff_head pending[IEEE80211_MAX_QUEUES];
struct tasklet_struct tx_pending_tasklet;
- /*
- * This lock is used to prevent concurrent A-MPDU
- * session start/stop processing, this thus also
- * synchronises the ->ampdu_action() callback to
- * drivers and limits it to one at a time.
- */
- spinlock_t ampdu_lock;
+ atomic_t agg_queue_stop[IEEE80211_MAX_QUEUES];
/* number of interfaces with corresponding IFF_ flags */
atomic_t iff_allmultis, iff_promiscs;
@@ -746,10 +741,10 @@ struct ieee80211_local {
struct mutex iflist_mtx;
/*
- * Key lock, protects sdata's key_list and sta_info's
+ * Key mutex, protects sdata's key_list and sta_info's
* key pointers (write access, they're RCU.)
*/
- spinlock_t key_lock;
+ struct mutex key_mtx;
/* Scanning and BSS list */
@@ -851,6 +846,15 @@ struct ieee80211_local {
struct work_struct dynamic_ps_disable_work;
struct timer_list dynamic_ps_timer;
struct notifier_block network_latency_notifier;
+ struct notifier_block ifa_notifier;
+
+ /*
+ * The dynamic ps timeout configured from user space via WEXT -
+ * this will override whatever chosen by mac80211 internally.
+ */
+ int dynamic_ps_forced_timeout;
+ int dynamic_ps_user_timeout;
+ bool disable_dynamic_ps;
int user_power_level; /* in dBm */
int power_constr_level; /* in dBm */
@@ -874,9 +878,8 @@ IEEE80211_DEV_TO_SUB_IF(struct net_device *dev)
return netdev_priv(dev);
}
-/* this struct represents 802.11n's RA/TID combination along with our vif */
+/* this struct represents 802.11n's RA/TID combination */
struct ieee80211_ra_tid {
- struct ieee80211_vif *vif;
u8 ra[ETH_ALEN];
u16 tid;
};
@@ -985,29 +988,25 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata,
int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata,
struct cfg80211_disassoc_request *req,
void *cookie);
-int ieee80211_mgd_action(struct ieee80211_sub_if_data *sdata,
- struct ieee80211_channel *chan,
- enum nl80211_channel_type channel_type,
- const u8 *buf, size_t len, u64 *cookie);
-ieee80211_rx_result ieee80211_sta_rx_mgmt(struct ieee80211_sub_if_data *sdata,
- struct sk_buff *skb);
void ieee80211_send_pspoll(struct ieee80211_local *local,
struct ieee80211_sub_if_data *sdata);
void ieee80211_recalc_ps(struct ieee80211_local *local, s32 latency);
int ieee80211_max_network_latency(struct notifier_block *nb,
unsigned long data, void *dummy);
+int ieee80211_set_arp_filter(struct ieee80211_sub_if_data *sdata);
void ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
struct ieee80211_channel_sw_ie *sw_elem,
struct ieee80211_bss *bss,
u64 timestamp);
void ieee80211_sta_quiesce(struct ieee80211_sub_if_data *sdata);
void ieee80211_sta_restart(struct ieee80211_sub_if_data *sdata);
+void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata);
+void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
+ struct sk_buff *skb);
/* IBSS code */
void ieee80211_ibss_notify_scan_completed(struct ieee80211_local *local);
void ieee80211_ibss_setup_sdata(struct ieee80211_sub_if_data *sdata);
-ieee80211_rx_result
-ieee80211_ibss_rx_mgmt(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb);
struct sta_info *ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata,
u8 *bssid, u8 *addr, u32 supp_rates,
gfp_t gfp);
@@ -1016,6 +1015,14 @@ int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata,
int ieee80211_ibss_leave(struct ieee80211_sub_if_data *sdata);
void ieee80211_ibss_quiesce(struct ieee80211_sub_if_data *sdata);
void ieee80211_ibss_restart(struct ieee80211_sub_if_data *sdata);
+void ieee80211_ibss_work(struct ieee80211_sub_if_data *sdata);
+void ieee80211_ibss_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
+ struct sk_buff *skb);
+
+/* mesh code */
+void ieee80211_mesh_work(struct ieee80211_sub_if_data *sdata);
+void ieee80211_mesh_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
+ struct sk_buff *skb);
/* scan/BSS handling */
void ieee80211_scan_work(struct work_struct *work);
@@ -1084,7 +1091,7 @@ struct ieee80211_tx_status_rtap_hdr {
u8 padding_for_rate;
__le16 tx_flags;
u8 data_retries;
-} __attribute__ ((packed));
+} __packed;
/* HT */
@@ -1099,6 +1106,8 @@ int ieee80211_send_smps_action(struct ieee80211_sub_if_data *sdata,
enum ieee80211_smps_mode smps, const u8 *da,
const u8 *bssid);
+void ___ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid,
+ u16 initiator, u16 reason);
void __ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid,
u16 initiator, u16 reason);
void ieee80211_sta_tear_down_BA_sessions(struct sta_info *sta);
@@ -1118,6 +1127,10 @@ int __ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid,
enum ieee80211_back_parties initiator);
int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid,
enum ieee80211_back_parties initiator);
+void ieee80211_start_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u16 tid);
+void ieee80211_stop_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u8 tid);
+void ieee80211_ba_session_work(struct work_struct *work);
+void ieee80211_tx_ba_session_handle_start(struct sta_info *sta, int tid);
/* Spectrum management */
void ieee80211_process_measurement_req(struct ieee80211_sub_if_data *sdata,
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index 50deb017fd6..ebbe264e2b0 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -249,6 +249,8 @@ static int ieee80211_open(struct net_device *dev)
local->fif_other_bss++;
ieee80211_configure_filter(local);
+
+ netif_carrier_on(dev);
break;
default:
res = drv_add_interface(local, &sdata->vif);
@@ -268,7 +270,6 @@ static int ieee80211_open(struct net_device *dev)
changed |= ieee80211_reset_erp_info(sdata);
ieee80211_bss_info_change_notify(sdata, changed);
- ieee80211_enable_keys(sdata);
if (sdata->vif.type == NL80211_IFTYPE_STATION)
netif_carrier_off(dev);
@@ -321,15 +322,6 @@ static int ieee80211_open(struct net_device *dev)
ieee80211_recalc_ps(local, -1);
- /*
- * ieee80211_sta_work is disabled while network interface
- * is down. Therefore, some configuration changes may not
- * yet be effective. Trigger execution of ieee80211_sta_work
- * to fix this.
- */
- if (sdata->vif.type == NL80211_IFTYPE_STATION)
- ieee80211_queue_work(&local->hw, &sdata->u.mgd.work);
-
netif_tx_start_all_queues(dev);
return 0;
@@ -349,7 +341,6 @@ static int ieee80211_stop(struct net_device *dev)
{
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
struct ieee80211_local *local = sdata->local;
- struct sta_info *sta;
unsigned long flags;
struct sk_buff *skb, *tmp;
u32 hw_reconf_flags = 0;
@@ -366,18 +357,6 @@ static int ieee80211_stop(struct net_device *dev)
ieee80211_work_purge(sdata);
/*
- * Now delete all active aggregation sessions.
- */
- rcu_read_lock();
-
- list_for_each_entry_rcu(sta, &local->sta_list, list) {
- if (sta->sdata == sdata)
- ieee80211_sta_tear_down_BA_sessions(sta);
- }
-
- rcu_read_unlock();
-
- /*
* Remove all stations associated with this interface.
*
* This must be done before calling ops->remove_interface()
@@ -483,27 +462,14 @@ static int ieee80211_stop(struct net_device *dev)
* whether the interface is running, which, at this point,
* it no longer is.
*/
- cancel_work_sync(&sdata->u.mgd.work);
cancel_work_sync(&sdata->u.mgd.chswitch_work);
cancel_work_sync(&sdata->u.mgd.monitor_work);
cancel_work_sync(&sdata->u.mgd.beacon_connection_loss_work);
- /*
- * When we get here, the interface is marked down.
- * Call synchronize_rcu() to wait for the RX path
- * should it be using the interface and enqueuing
- * frames at this very time on another CPU.
- */
- synchronize_rcu();
- skb_queue_purge(&sdata->u.mgd.skb_queue);
/* fall through */
case NL80211_IFTYPE_ADHOC:
- if (sdata->vif.type == NL80211_IFTYPE_ADHOC) {
+ if (sdata->vif.type == NL80211_IFTYPE_ADHOC)
del_timer_sync(&sdata->u.ibss.timer);
- cancel_work_sync(&sdata->u.ibss.work);
- synchronize_rcu();
- skb_queue_purge(&sdata->u.ibss.skb_queue);
- }
/* fall through */
case NL80211_IFTYPE_MESH_POINT:
if (ieee80211_vif_is_mesh(&sdata->vif)) {
@@ -518,6 +484,16 @@ static int ieee80211_stop(struct net_device *dev)
}
/* fall through */
default:
+ flush_work(&sdata->work);
+ /*
+ * When we get here, the interface is marked down.
+ * Call synchronize_rcu() to wait for the RX path
+ * should it be using the interface and enqueuing
+ * frames at this very time on another CPU.
+ */
+ synchronize_rcu();
+ skb_queue_purge(&sdata->skb_queue);
+
if (local->scan_sdata == sdata)
ieee80211_scan_cancel(local);
@@ -531,8 +507,8 @@ static int ieee80211_stop(struct net_device *dev)
BSS_CHANGED_BEACON_ENABLED);
}
- /* disable all keys for as long as this netdev is down */
- ieee80211_disable_keys(sdata);
+ /* free all remaining keys, there shouldn't be any */
+ ieee80211_free_keys(sdata);
drv_remove_interface(local, &sdata->vif);
}
@@ -727,6 +703,136 @@ static void ieee80211_if_setup(struct net_device *dev)
dev->destructor = free_netdev;
}
+static void ieee80211_iface_work(struct work_struct *work)
+{
+ struct ieee80211_sub_if_data *sdata =
+ container_of(work, struct ieee80211_sub_if_data, work);
+ struct ieee80211_local *local = sdata->local;
+ struct sk_buff *skb;
+ struct sta_info *sta;
+ struct ieee80211_ra_tid *ra_tid;
+
+ if (!ieee80211_sdata_running(sdata))
+ return;
+
+ if (local->scanning)
+ return;
+
+ /*
+ * ieee80211_queue_work() should have picked up most cases,
+ * here we'll pick the rest.
+ */
+ if (WARN(local->suspended,
+ "interface work scheduled while going to suspend\n"))
+ return;
+
+ /* first process frames */
+ while ((skb = skb_dequeue(&sdata->skb_queue))) {
+ struct ieee80211_mgmt *mgmt = (void *)skb->data;
+
+ if (skb->pkt_type == IEEE80211_SDATA_QUEUE_AGG_START) {
+ ra_tid = (void *)&skb->cb;
+ ieee80211_start_tx_ba_cb(&sdata->vif, ra_tid->ra,
+ ra_tid->tid);
+ } else if (skb->pkt_type == IEEE80211_SDATA_QUEUE_AGG_STOP) {
+ ra_tid = (void *)&skb->cb;
+ ieee80211_stop_tx_ba_cb(&sdata->vif, ra_tid->ra,
+ ra_tid->tid);
+ } else if (ieee80211_is_action(mgmt->frame_control) &&
+ mgmt->u.action.category == WLAN_CATEGORY_BACK) {
+ int len = skb->len;
+
+ mutex_lock(&local->sta_mtx);
+ sta = sta_info_get_bss(sdata, mgmt->sa);
+ if (sta) {
+ switch (mgmt->u.action.u.addba_req.action_code) {
+ case WLAN_ACTION_ADDBA_REQ:
+ ieee80211_process_addba_request(
+ local, sta, mgmt, len);
+ break;
+ case WLAN_ACTION_ADDBA_RESP:
+ ieee80211_process_addba_resp(local, sta,
+ mgmt, len);
+ break;
+ case WLAN_ACTION_DELBA:
+ ieee80211_process_delba(sdata, sta,
+ mgmt, len);
+ break;
+ default:
+ WARN_ON(1);
+ break;
+ }
+ }
+ mutex_unlock(&local->sta_mtx);
+ } else if (ieee80211_is_data_qos(mgmt->frame_control)) {
+ struct ieee80211_hdr *hdr = (void *)mgmt;
+ /*
+ * So the frame isn't mgmt, but frame_control
+ * is at the right place anyway, of course, so
+ * the if statement is correct.
+ *
+ * Warn if we have other data frame types here,
+ * they must not get here.
+ */
+ WARN_ON(hdr->frame_control &
+ cpu_to_le16(IEEE80211_STYPE_NULLFUNC));
+ WARN_ON(!(hdr->seq_ctrl &
+ cpu_to_le16(IEEE80211_SCTL_FRAG)));
+ /*
+ * This was a fragment of a frame, received while
+ * a block-ack session was active. That cannot be
+ * right, so terminate the session.
+ */
+ mutex_lock(&local->sta_mtx);
+ sta = sta_info_get_bss(sdata, mgmt->sa);
+ if (sta) {
+ u16 tid = *ieee80211_get_qos_ctl(hdr) &
+ IEEE80211_QOS_CTL_TID_MASK;
+
+ __ieee80211_stop_rx_ba_session(
+ sta, tid, WLAN_BACK_RECIPIENT,
+ WLAN_REASON_QSTA_REQUIRE_SETUP);
+ }
+ mutex_unlock(&local->sta_mtx);
+ } else switch (sdata->vif.type) {
+ case NL80211_IFTYPE_STATION:
+ ieee80211_sta_rx_queued_mgmt(sdata, skb);
+ break;
+ case NL80211_IFTYPE_ADHOC:
+ ieee80211_ibss_rx_queued_mgmt(sdata, skb);
+ break;
+ case NL80211_IFTYPE_MESH_POINT:
+ if (!ieee80211_vif_is_mesh(&sdata->vif))
+ break;
+ ieee80211_mesh_rx_queued_mgmt(sdata, skb);
+ break;
+ default:
+ WARN(1, "frame for unexpected interface type");
+ break;
+ }
+
+ kfree_skb(skb);
+ }
+
+ /* then other type-dependent work */
+ switch (sdata->vif.type) {
+ case NL80211_IFTYPE_STATION:
+ ieee80211_sta_work(sdata);
+ break;
+ case NL80211_IFTYPE_ADHOC:
+ ieee80211_ibss_work(sdata);
+ break;
+ case NL80211_IFTYPE_MESH_POINT:
+ if (!ieee80211_vif_is_mesh(&sdata->vif))
+ break;
+ ieee80211_mesh_work(sdata);
+ break;
+ default:
+ break;
+ }
+}
+
+
/*
* Helper function to initialise an interface to a specific type.
*/
@@ -744,6 +850,9 @@ static void ieee80211_setup_sdata(struct ieee80211_sub_if_data *sdata,
/* only monitor differs */
sdata->dev->type = ARPHRD_ETHER;
+ skb_queue_head_init(&sdata->skb_queue);
+ INIT_WORK(&sdata->work, ieee80211_iface_work);
+
switch (type) {
case NL80211_IFTYPE_AP:
skb_queue_head_init(&sdata->u.ap.ps_bc_buf);
@@ -969,6 +1078,9 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name,
sdata->wdev.wiphy = local->hw.wiphy;
sdata->local = local;
sdata->dev = ndev;
+#ifdef CONFIG_INET
+ sdata->arp_filter_state = true;
+#endif
for (i = 0; i < IEEE80211_FRAGMENT_MAX; i++)
skb_queue_head_init(&sdata->fragments[i].skb_list);
diff --git a/net/mac80211/key.c b/net/mac80211/key.c
index e8f6e3b252d..1b9d87ed143 100644
--- a/net/mac80211/key.c
+++ b/net/mac80211/key.c
@@ -36,80 +36,20 @@
* There is currently no way of knowing this except by looking into
* debugfs.
*
- * All key operations are protected internally so you can call them at
- * any time.
+ * All key operations are protected internally.
*
* Within mac80211, key references are, just as STA structure references,
* protected by RCU. Note, however, that some things are unprotected,
* namely the key->sta dereferences within the hardware acceleration
- * functions. This means that sta_info_destroy() must flush the key todo
- * list.
- *
- * All the direct key list manipulation functions must not sleep because
- * they can operate on STA info structs that are protected by RCU.
+ * functions. This means that sta_info_destroy() must remove the key
+ * which waits for an RCU grace period.
*/
static const u8 bcast_addr[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
-/* key mutex: used to synchronise todo runners */
-static DEFINE_MUTEX(key_mutex);
-static DEFINE_SPINLOCK(todo_lock);
-static LIST_HEAD(todo_list);
-
-static void key_todo(struct work_struct *work)
-{
- ieee80211_key_todo();
-}
-
-static DECLARE_WORK(todo_work, key_todo);
-
-/**
- * add_todo - add todo item for a key
- *
- * @key: key to add to do item for
- * @flag: todo flag(s)
- *
- * Must be called with IRQs or softirqs disabled.
- */
-static void add_todo(struct ieee80211_key *key, u32 flag)
-{
- if (!key)
- return;
-
- spin_lock(&todo_lock);
- key->flags |= flag;
- /*
- * Remove again if already on the list so that we move it to the end.
- */
- if (!list_empty(&key->todo))
- list_del(&key->todo);
- list_add_tail(&key->todo, &todo_list);
- schedule_work(&todo_work);
- spin_unlock(&todo_lock);
-}
-
-/**
- * ieee80211_key_lock - lock the mac80211 key operation lock
- *
- * This locks the (global) mac80211 key operation lock, all
- * key operations must be done under this lock.
- */
-static void ieee80211_key_lock(void)
-{
- mutex_lock(&key_mutex);
-}
-
-/**
- * ieee80211_key_unlock - unlock the mac80211 key operation lock
- */
-static void ieee80211_key_unlock(void)
-{
- mutex_unlock(&key_mutex);
-}
-
-static void assert_key_lock(void)
+static void assert_key_lock(struct ieee80211_local *local)
{
- WARN_ON(!mutex_is_locked(&key_mutex));
+ WARN_ON(!mutex_is_locked(&local->key_mtx));
}
static struct ieee80211_sta *get_sta_for_key(struct ieee80211_key *key)
@@ -126,12 +66,13 @@ static void ieee80211_key_enable_hw_accel(struct ieee80211_key *key)
struct ieee80211_sta *sta;
int ret;
- assert_key_lock();
might_sleep();
if (!key->local->ops->set_key)
return;
+ assert_key_lock(key->local);
+
sta = get_sta_for_key(key);
sdata = key->sdata;
@@ -142,11 +83,8 @@ static void ieee80211_key_enable_hw_accel(struct ieee80211_key *key)
ret = drv_set_key(key->local, SET_KEY, sdata, sta, &key->conf);
- if (!ret) {
- spin_lock_bh(&todo_lock);
+ if (!ret)
key->flags |= KEY_FLAG_UPLOADED_TO_HARDWARE;
- spin_unlock_bh(&todo_lock);
- }
if (ret && ret != -ENOSPC && ret != -EOPNOTSUPP)
printk(KERN_ERR "mac80211-%s: failed to set key "
@@ -161,18 +99,15 @@ static void ieee80211_key_disable_hw_accel(struct ieee80211_key *key)
struct ieee80211_sta *sta;
int ret;
- assert_key_lock();
might_sleep();
if (!key || !key->local->ops->set_key)
return;
- spin_lock_bh(&todo_lock);
- if (!(key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE)) {
- spin_unlock_bh(&todo_lock);
+ assert_key_lock(key->local);
+
+ if (!(key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE))
return;
- }
- spin_unlock_bh(&todo_lock);
sta = get_sta_for_key(key);
sdata = key->sdata;
@@ -191,9 +126,7 @@ static void ieee80211_key_disable_hw_accel(struct ieee80211_key *key)
wiphy_name(key->local->hw.wiphy),
key->conf.keyidx, sta ? sta->addr : bcast_addr, ret);
- spin_lock_bh(&todo_lock);
key->flags &= ~KEY_FLAG_UPLOADED_TO_HARDWARE;
- spin_unlock_bh(&todo_lock);
}
static void __ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata,
@@ -201,22 +134,24 @@ static void __ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata,
{
struct ieee80211_key *key = NULL;
+ assert_key_lock(sdata->local);
+
if (idx >= 0 && idx < NUM_DEFAULT_KEYS)
key = sdata->keys[idx];
rcu_assign_pointer(sdata->default_key, key);
- if (key)
- add_todo(key, KEY_FLAG_TODO_DEFKEY);
+ if (key) {
+ ieee80211_debugfs_key_remove_default(key->sdata);
+ ieee80211_debugfs_key_add_default(key->sdata);
+ }
}
void ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata, int idx)
{
- unsigned long flags;
-
- spin_lock_irqsave(&sdata->local->key_lock, flags);
+ mutex_lock(&sdata->local->key_mtx);
__ieee80211_set_default_key(sdata, idx);
- spin_unlock_irqrestore(&sdata->local->key_lock, flags);
+ mutex_unlock(&sdata->local->key_mtx);
}
static void
@@ -224,24 +159,26 @@ __ieee80211_set_default_mgmt_key(struct ieee80211_sub_if_data *sdata, int idx)
{
struct ieee80211_key *key = NULL;
+ assert_key_lock(sdata->local);
+
if (idx >= NUM_DEFAULT_KEYS &&
idx < NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS)
key = sdata->keys[idx];
rcu_assign_pointer(sdata->default_mgmt_key, key);
- if (key)
- add_todo(key, KEY_FLAG_TODO_DEFMGMTKEY);
+ if (key) {
+ ieee80211_debugfs_key_remove_mgmt_default(key->sdata);
+ ieee80211_debugfs_key_add_mgmt_default(key->sdata);
+ }
}
void ieee80211_set_default_mgmt_key(struct ieee80211_sub_if_data *sdata,
int idx)
{
- unsigned long flags;
-
- spin_lock_irqsave(&sdata->local->key_lock, flags);
+ mutex_lock(&sdata->local->key_mtx);
__ieee80211_set_default_mgmt_key(sdata, idx);
- spin_unlock_irqrestore(&sdata->local->key_lock, flags);
+ mutex_unlock(&sdata->local->key_mtx);
}
@@ -336,7 +273,7 @@ struct ieee80211_key *ieee80211_key_alloc(enum ieee80211_key_alg alg,
key->conf.iv_len = CCMP_HDR_LEN;
key->conf.icv_len = CCMP_MIC_LEN;
if (seq) {
- for (i = 0; i < NUM_RX_DATA_QUEUES; i++)
+ for (i = 0; i < NUM_RX_DATA_QUEUES + 1; i++)
for (j = 0; j < CCMP_PN_LEN; j++)
key->u.ccmp.rx_pn[i][j] =
seq[CCMP_PN_LEN - j - 1];
@@ -352,7 +289,6 @@ struct ieee80211_key *ieee80211_key_alloc(enum ieee80211_key_alg alg,
}
memcpy(key->conf.key, key_data, key_len);
INIT_LIST_HEAD(&key->list);
- INIT_LIST_HEAD(&key->todo);
if (alg == ALG_CCMP) {
/*
@@ -382,12 +318,29 @@ struct ieee80211_key *ieee80211_key_alloc(enum ieee80211_key_alg alg,
return key;
}
+static void __ieee80211_key_destroy(struct ieee80211_key *key)
+{
+ if (!key)
+ return;
+
+ if (key->local)
+ ieee80211_key_disable_hw_accel(key);
+
+ if (key->conf.alg == ALG_CCMP)
+ ieee80211_aes_key_free(key->u.ccmp.tfm);
+ if (key->conf.alg == ALG_AES_CMAC)
+ ieee80211_aes_cmac_key_free(key->u.aes_cmac.tfm);
+ if (key->local)
+ ieee80211_debugfs_key_remove(key);
+
+ kfree(key);
+}
+
void ieee80211_key_link(struct ieee80211_key *key,
struct ieee80211_sub_if_data *sdata,
struct sta_info *sta)
{
struct ieee80211_key *old_key;
- unsigned long flags;
int idx;
BUG_ON(!sdata);
@@ -431,7 +384,7 @@ void ieee80211_key_link(struct ieee80211_key *key,
}
}
- spin_lock_irqsave(&sdata->local->key_lock, flags);
+ mutex_lock(&sdata->local->key_mtx);
if (sta)
old_key = sta->key;
@@ -439,15 +392,13 @@ void ieee80211_key_link(struct ieee80211_key *key,
old_key = sdata->keys[idx];
__ieee80211_key_replace(sdata, sta, old_key, key);
+ __ieee80211_key_destroy(old_key);
- /* free old key later */
- add_todo(old_key, KEY_FLAG_TODO_DELETE);
+ ieee80211_debugfs_key_add(key);
- add_todo(key, KEY_FLAG_TODO_ADD_DEBUGFS);
- if (ieee80211_sdata_running(sdata))
- add_todo(key, KEY_FLAG_TODO_HWACCEL_ADD);
+ ieee80211_key_enable_hw_accel(key);
- spin_unlock_irqrestore(&sdata->local->key_lock, flags);
+ mutex_unlock(&sdata->local->key_mtx);
}
static void __ieee80211_key_free(struct ieee80211_key *key)
@@ -458,170 +409,62 @@ static void __ieee80211_key_free(struct ieee80211_key *key)
if (key->sdata)
__ieee80211_key_replace(key->sdata, key->sta,
key, NULL);
-
- add_todo(key, KEY_FLAG_TODO_DELETE);
+ __ieee80211_key_destroy(key);
}
-void ieee80211_key_free(struct ieee80211_key *key)
+void ieee80211_key_free(struct ieee80211_local *local,
+ struct ieee80211_key *key)
{
- unsigned long flags;
-
if (!key)
return;
- if (!key->sdata) {
- /* The key has not been linked yet, simply free it
- * and don't Oops */
- if (key->conf.alg == ALG_CCMP)
- ieee80211_aes_key_free(key->u.ccmp.tfm);
- kfree(key);
- return;
- }
-
- spin_lock_irqsave(&key->sdata->local->key_lock, flags);
+ mutex_lock(&local->key_mtx);
__ieee80211_key_free(key);
- spin_unlock_irqrestore(&key->sdata->local->key_lock, flags);
+ mutex_unlock(&local->key_mtx);
}
-/*
- * To be safe against concurrent manipulations of the list (which shouldn't
- * actually happen) we need to hold the spinlock. But under the spinlock we
- * can't actually do much, so we defer processing to the todo list. Then run
- * the todo list to be sure the operation and possibly previously pending
- * operations are completed.
- */
-static void ieee80211_todo_for_each_key(struct ieee80211_sub_if_data *sdata,
- u32 todo_flags)
+void ieee80211_enable_keys(struct ieee80211_sub_if_data *sdata)
{
struct ieee80211_key *key;
- unsigned long flags;
-
- might_sleep();
-
- spin_lock_irqsave(&sdata->local->key_lock, flags);
- list_for_each_entry(key, &sdata->key_list, list)
- add_todo(key, todo_flags);
- spin_unlock_irqrestore(&sdata->local->key_lock, flags);
- ieee80211_key_todo();
-}
-
-void ieee80211_enable_keys(struct ieee80211_sub_if_data *sdata)
-{
ASSERT_RTNL();
if (WARN_ON(!ieee80211_sdata_running(sdata)))
return;
- ieee80211_todo_for_each_key(sdata, KEY_FLAG_TODO_HWACCEL_ADD);
-}
+ mutex_lock(&sdata->local->key_mtx);
-void ieee80211_disable_keys(struct ieee80211_sub_if_data *sdata)
-{
- ASSERT_RTNL();
-
- ieee80211_todo_for_each_key(sdata, KEY_FLAG_TODO_HWACCEL_REMOVE);
-}
-
-static void __ieee80211_key_destroy(struct ieee80211_key *key)
-{
- if (!key)
- return;
-
- ieee80211_key_disable_hw_accel(key);
-
- if (key->conf.alg == ALG_CCMP)
- ieee80211_aes_key_free(key->u.ccmp.tfm);
- if (key->conf.alg == ALG_AES_CMAC)
- ieee80211_aes_cmac_key_free(key->u.aes_cmac.tfm);
- ieee80211_debugfs_key_remove(key);
+ list_for_each_entry(key, &sdata->key_list, list)
+ ieee80211_key_enable_hw_accel(key);
- kfree(key);
+ mutex_unlock(&sdata->local->key_mtx);
}
-static void __ieee80211_key_todo(void)
+void ieee80211_disable_keys(struct ieee80211_sub_if_data *sdata)
{
struct ieee80211_key *key;
- bool work_done;
- u32 todoflags;
- /*
- * NB: sta_info_destroy relies on this!
- */
- synchronize_rcu();
-
- spin_lock_bh(&todo_lock);
- while (!list_empty(&todo_list)) {
- key = list_first_entry(&todo_list, struct ieee80211_key, todo);
- list_del_init(&key->todo);
- todoflags = key->flags & (KEY_FLAG_TODO_ADD_DEBUGFS |
- KEY_FLAG_TODO_DEFKEY |
- KEY_FLAG_TODO_DEFMGMTKEY |
- KEY_FLAG_TODO_HWACCEL_ADD |
- KEY_FLAG_TODO_HWACCEL_REMOVE |
- KEY_FLAG_TODO_DELETE);
- key->flags &= ~todoflags;
- spin_unlock_bh(&todo_lock);
-
- work_done = false;
-
- if (todoflags & KEY_FLAG_TODO_ADD_DEBUGFS) {
- ieee80211_debugfs_key_add(key);
- work_done = true;
- }
- if (todoflags & KEY_FLAG_TODO_DEFKEY) {
- ieee80211_debugfs_key_remove_default(key->sdata);
- ieee80211_debugfs_key_add_default(key->sdata);
- work_done = true;
- }
- if (todoflags & KEY_FLAG_TODO_DEFMGMTKEY) {
- ieee80211_debugfs_key_remove_mgmt_default(key->sdata);
- ieee80211_debugfs_key_add_mgmt_default(key->sdata);
- work_done = true;
- }
- if (todoflags & KEY_FLAG_TODO_HWACCEL_ADD) {
- ieee80211_key_enable_hw_accel(key);
- work_done = true;
- }
- if (todoflags & KEY_FLAG_TODO_HWACCEL_REMOVE) {
- ieee80211_key_disable_hw_accel(key);
- work_done = true;
- }
- if (todoflags & KEY_FLAG_TODO_DELETE) {
- __ieee80211_key_destroy(key);
- work_done = true;
- }
+ ASSERT_RTNL();
- WARN_ON(!work_done);
+ mutex_lock(&sdata->local->key_mtx);
- spin_lock_bh(&todo_lock);
- }
- spin_unlock_bh(&todo_lock);
-}
+ list_for_each_entry(key, &sdata->key_list, list)
+ ieee80211_key_disable_hw_accel(key);
-void ieee80211_key_todo(void)
-{
- ieee80211_key_lock();
- __ieee80211_key_todo();
- ieee80211_key_unlock();
+ mutex_unlock(&sdata->local->key_mtx);
}
void ieee80211_free_keys(struct ieee80211_sub_if_data *sdata)
{
struct ieee80211_key *key, *tmp;
- unsigned long flags;
- ieee80211_key_lock();
+ mutex_lock(&sdata->local->key_mtx);
ieee80211_debugfs_key_remove_default(sdata);
ieee80211_debugfs_key_remove_mgmt_default(sdata);
- spin_lock_irqsave(&sdata->local->key_lock, flags);
list_for_each_entry_safe(key, tmp, &sdata->key_list, list)
__ieee80211_key_free(key);
- spin_unlock_irqrestore(&sdata->local->key_lock, flags);
-
- __ieee80211_key_todo();
- ieee80211_key_unlock();
+ mutex_unlock(&sdata->local->key_mtx);
}
diff --git a/net/mac80211/key.h b/net/mac80211/key.h
index bdc2968c2bb..b665bbb7a47 100644
--- a/net/mac80211/key.h
+++ b/net/mac80211/key.h
@@ -38,25 +38,9 @@ struct sta_info;
*
* @KEY_FLAG_UPLOADED_TO_HARDWARE: Indicates that this key is present
* in the hardware for TX crypto hardware acceleration.
- * @KEY_FLAG_TODO_DELETE: Key is marked for deletion and will, after an
- * RCU grace period, no longer be reachable other than from the
- * todo list.
- * @KEY_FLAG_TODO_HWACCEL_ADD: Key needs to be added to hardware acceleration.
- * @KEY_FLAG_TODO_HWACCEL_REMOVE: Key needs to be removed from hardware
- * acceleration.
- * @KEY_FLAG_TODO_DEFKEY: Key is default key and debugfs needs to be updated.
- * @KEY_FLAG_TODO_ADD_DEBUGFS: Key needs to be added to debugfs.
- * @KEY_FLAG_TODO_DEFMGMTKEY: Key is default management key and debugfs needs
- * to be updated.
*/
enum ieee80211_internal_key_flags {
KEY_FLAG_UPLOADED_TO_HARDWARE = BIT(0),
- KEY_FLAG_TODO_DELETE = BIT(1),
- KEY_FLAG_TODO_HWACCEL_ADD = BIT(2),
- KEY_FLAG_TODO_HWACCEL_REMOVE = BIT(3),
- KEY_FLAG_TODO_DEFKEY = BIT(4),
- KEY_FLAG_TODO_ADD_DEBUGFS = BIT(5),
- KEY_FLAG_TODO_DEFMGMTKEY = BIT(6),
};
enum ieee80211_internal_tkip_state {
@@ -79,10 +63,8 @@ struct ieee80211_key {
/* for sdata list */
struct list_head list;
- /* for todo list */
- struct list_head todo;
- /* protected by todo lock! */
+ /* protected by key mutex */
unsigned int flags;
union {
@@ -95,7 +77,13 @@ struct ieee80211_key {
} tkip;
struct {
u8 tx_pn[6];
- u8 rx_pn[NUM_RX_DATA_QUEUES][6];
+ /*
+ * Last received packet number. The first
+ * NUM_RX_DATA_QUEUES counters are used with Data
+ * frames and the last counter is used with Robust
+ * Management frames.
+ */
+ u8 rx_pn[NUM_RX_DATA_QUEUES + 1][6];
struct crypto_cipher *tfm;
u32 replays; /* dot11RSNAStatsCCMPReplays */
/* scratch buffers for virt_to_page() (crypto API) */
@@ -147,7 +135,8 @@ struct ieee80211_key *ieee80211_key_alloc(enum ieee80211_key_alg alg,
void ieee80211_key_link(struct ieee80211_key *key,
struct ieee80211_sub_if_data *sdata,
struct sta_info *sta);
-void ieee80211_key_free(struct ieee80211_key *key);
+void ieee80211_key_free(struct ieee80211_local *local,
+ struct ieee80211_key *key);
void ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata, int idx);
void ieee80211_set_default_mgmt_key(struct ieee80211_sub_if_data *sdata,
int idx);
@@ -155,6 +144,4 @@ void ieee80211_free_keys(struct ieee80211_sub_if_data *sdata);
void ieee80211_enable_keys(struct ieee80211_sub_if_data *sdata);
void ieee80211_disable_keys(struct ieee80211_sub_if_data *sdata);
-void ieee80211_key_todo(void);
-
#endif /* IEEE80211_KEY_H */
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index 22a384dfab6..7cc4f913a43 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -20,6 +20,7 @@
#include <linux/rtnetlink.h>
#include <linux/bitmap.h>
#include <linux/pm_qos_params.h>
+#include <linux/inetdevice.h>
#include <net/net_namespace.h>
#include <net/cfg80211.h>
@@ -106,12 +107,15 @@ int ieee80211_hw_config(struct ieee80211_local *local, u32 changed)
if (scan_chan) {
chan = scan_chan;
channel_type = NL80211_CHAN_NO_HT;
+ local->hw.conf.flags |= IEEE80211_CONF_OFFCHANNEL;
} else if (local->tmp_channel) {
chan = scan_chan = local->tmp_channel;
channel_type = local->tmp_channel_type;
+ local->hw.conf.flags |= IEEE80211_CONF_OFFCHANNEL;
} else {
chan = local->oper_channel;
channel_type = local->_oper_channel_type;
+ local->hw.conf.flags &= ~IEEE80211_CONF_OFFCHANNEL;
}
if (chan != local->hw.conf.channel ||
@@ -259,7 +263,6 @@ static void ieee80211_tasklet_handler(unsigned long data)
{
struct ieee80211_local *local = (struct ieee80211_local *) data;
struct sk_buff *skb;
- struct ieee80211_ra_tid *ra_tid;
while ((skb = skb_dequeue(&local->skb_queue)) ||
(skb = skb_dequeue(&local->skb_queue_unreliable))) {
@@ -274,18 +277,6 @@ static void ieee80211_tasklet_handler(unsigned long data)
skb->pkt_type = 0;
ieee80211_tx_status(local_to_hw(local), skb);
break;
- case IEEE80211_DELBA_MSG:
- ra_tid = (struct ieee80211_ra_tid *) &skb->cb;
- ieee80211_stop_tx_ba_cb(ra_tid->vif, ra_tid->ra,
- ra_tid->tid);
- dev_kfree_skb(skb);
- break;
- case IEEE80211_ADDBA_MSG:
- ra_tid = (struct ieee80211_ra_tid *) &skb->cb;
- ieee80211_start_tx_ba_cb(ra_tid->vif, ra_tid->ra,
- ra_tid->tid);
- dev_kfree_skb(skb);
- break ;
default:
WARN(1, "mac80211: Packet is of unknown type %d\n",
skb->pkt_type);
@@ -329,6 +320,76 @@ static void ieee80211_recalc_smps_work(struct work_struct *work)
mutex_unlock(&local->iflist_mtx);
}
+#ifdef CONFIG_INET
+static int ieee80211_ifa_changed(struct notifier_block *nb,
+ unsigned long data, void *arg)
+{
+ struct in_ifaddr *ifa = arg;
+ struct ieee80211_local *local =
+ container_of(nb, struct ieee80211_local,
+ ifa_notifier);
+ struct net_device *ndev = ifa->ifa_dev->dev;
+ struct wireless_dev *wdev = ndev->ieee80211_ptr;
+ struct in_device *idev;
+ struct ieee80211_sub_if_data *sdata;
+ struct ieee80211_bss_conf *bss_conf;
+ struct ieee80211_if_managed *ifmgd;
+ int c = 0;
+
+ if (!netif_running(ndev))
+ return NOTIFY_DONE;
+
+ /* Make sure it's our interface that got changed */
+ if (!wdev)
+ return NOTIFY_DONE;
+
+ if (wdev->wiphy != local->hw.wiphy)
+ return NOTIFY_DONE;
+
+ sdata = IEEE80211_DEV_TO_SUB_IF(ndev);
+ bss_conf = &sdata->vif.bss_conf;
+
+ /* ARP filtering is only supported in managed mode */
+ if (sdata->vif.type != NL80211_IFTYPE_STATION)
+ return NOTIFY_DONE;
+
+ idev = sdata->dev->ip_ptr;
+ if (!idev)
+ return NOTIFY_DONE;
+
+ ifmgd = &sdata->u.mgd;
+ mutex_lock(&ifmgd->mtx);
+
+ /* Copy the addresses to the bss_conf list */
+ ifa = idev->ifa_list;
+ while (c < IEEE80211_BSS_ARP_ADDR_LIST_LEN && ifa) {
+ bss_conf->arp_addr_list[c] = ifa->ifa_address;
+ ifa = ifa->ifa_next;
+ c++;
+ }
+
+ /* If not all addresses fit the list, disable filtering */
+ if (ifa) {
+ sdata->arp_filter_state = false;
+ c = 0;
+ } else {
+ sdata->arp_filter_state = true;
+ }
+ bss_conf->arp_addr_cnt = c;
+
+ /* Configure driver only if associated */
+ if (ifmgd->associated) {
+ bss_conf->arp_filter_enabled = sdata->arp_filter_state;
+ ieee80211_bss_info_change_notify(sdata,
+ BSS_CHANGED_ARP_FILTER);
+ }
+
+ mutex_unlock(&ifmgd->mtx);
+
+ return NOTIFY_DONE;
+}
+#endif
+
struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
const struct ieee80211_ops *ops)
{
@@ -396,7 +457,7 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
mutex_init(&local->iflist_mtx);
mutex_init(&local->scan_mtx);
- spin_lock_init(&local->key_lock);
+ mutex_init(&local->key_mtx);
spin_lock_init(&local->filter_lock);
spin_lock_init(&local->queue_stop_reason_lock);
@@ -419,8 +480,10 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
sta_info_init(local);
- for (i = 0; i < IEEE80211_MAX_QUEUES; i++)
+ for (i = 0; i < IEEE80211_MAX_QUEUES; i++) {
skb_queue_head_init(&local->pending[i]);
+ atomic_set(&local->agg_queue_stop[i], 0);
+ }
tasklet_init(&local->tx_pending_tasklet, ieee80211_tx_pending,
(unsigned long)local);
@@ -431,8 +494,6 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
skb_queue_head_init(&local->skb_queue);
skb_queue_head_init(&local->skb_queue_unreliable);
- spin_lock_init(&local->ampdu_lock);
-
return local_to_hw(local);
}
EXPORT_SYMBOL(ieee80211_alloc_hw);
@@ -572,18 +633,16 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
local->hw.conf.listen_interval = local->hw.max_listen_interval;
- local->hw.conf.dynamic_ps_forced_timeout = -1;
+ local->dynamic_ps_forced_timeout = -1;
result = sta_info_start(local);
if (result < 0)
goto fail_sta_info;
result = ieee80211_wep_init(local);
- if (result < 0) {
+ if (result < 0)
printk(KERN_DEBUG "%s: Failed to initialize wep: %d\n",
wiphy_name(local->hw.wiphy), result);
- goto fail_wep;
- }
rtnl_lock();
@@ -612,21 +671,30 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
ieee80211_max_network_latency;
result = pm_qos_add_notifier(PM_QOS_NETWORK_LATENCY,
&local->network_latency_notifier);
-
if (result) {
rtnl_lock();
goto fail_pm_qos;
}
+#ifdef CONFIG_INET
+ local->ifa_notifier.notifier_call = ieee80211_ifa_changed;
+ result = register_inetaddr_notifier(&local->ifa_notifier);
+ if (result)
+ goto fail_ifa;
+#endif
+
return 0;
+ fail_ifa:
+ pm_qos_remove_notifier(PM_QOS_NETWORK_LATENCY,
+ &local->network_latency_notifier);
+ rtnl_lock();
fail_pm_qos:
ieee80211_led_exit(local);
ieee80211_remove_interfaces(local);
fail_rate:
rtnl_unlock();
ieee80211_wep_free(local);
- fail_wep:
sta_info_stop(local);
fail_sta_info:
destroy_workqueue(local->workqueue);
@@ -647,6 +715,9 @@ void ieee80211_unregister_hw(struct ieee80211_hw *hw)
pm_qos_remove_notifier(PM_QOS_NETWORK_LATENCY,
&local->network_latency_notifier);
+#ifdef CONFIG_INET
+ unregister_inetaddr_notifier(&local->ifa_notifier);
+#endif
rtnl_lock();
@@ -704,6 +775,10 @@ static int __init ieee80211_init(void)
if (ret)
return ret;
+ ret = rc80211_minstrel_ht_init();
+ if (ret)
+ goto err_minstrel;
+
ret = rc80211_pid_init();
if (ret)
goto err_pid;
@@ -716,6 +791,8 @@ static int __init ieee80211_init(void)
err_netdev:
rc80211_pid_exit();
err_pid:
+ rc80211_minstrel_ht_exit();
+ err_minstrel:
rc80211_minstrel_exit();
return ret;
@@ -724,6 +801,7 @@ static int __init ieee80211_init(void)
static void __exit ieee80211_exit(void)
{
rc80211_pid_exit();
+ rc80211_minstrel_ht_exit();
rc80211_minstrel_exit();
/*
diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c
index bde81031727..c8a4f19ed13 100644
--- a/net/mac80211/mesh.c
+++ b/net/mac80211/mesh.c
@@ -54,7 +54,7 @@ static void ieee80211_mesh_housekeeping_timer(unsigned long data)
return;
}
- ieee80211_queue_work(&local->hw, &ifmsh->work);
+ ieee80211_queue_work(&local->hw, &sdata->work);
}
/**
@@ -345,7 +345,7 @@ static void ieee80211_mesh_path_timer(unsigned long data)
return;
}
- ieee80211_queue_work(&local->hw, &ifmsh->work);
+ ieee80211_queue_work(&local->hw, &sdata->work);
}
static void ieee80211_mesh_path_root_timer(unsigned long data)
@@ -362,7 +362,7 @@ static void ieee80211_mesh_path_root_timer(unsigned long data)
return;
}
- ieee80211_queue_work(&local->hw, &ifmsh->work);
+ ieee80211_queue_work(&local->hw, &sdata->work);
}
void ieee80211_mesh_root_setup(struct ieee80211_if_mesh *ifmsh)
@@ -484,9 +484,6 @@ void ieee80211_mesh_quiesce(struct ieee80211_sub_if_data *sdata)
{
struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
- /* might restart the timer but that doesn't matter */
- cancel_work_sync(&ifmsh->work);
-
/* use atomic bitops in case both timers fire at the same time */
if (del_timer_sync(&ifmsh->housekeeping_timer))
@@ -518,7 +515,7 @@ void ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata)
set_bit(MESH_WORK_HOUSEKEEPING, &ifmsh->wrkq_flags);
ieee80211_mesh_root_setup(ifmsh);
- ieee80211_queue_work(&local->hw, &ifmsh->work);
+ ieee80211_queue_work(&local->hw, &sdata->work);
sdata->vif.bss_conf.beacon_int = MESH_DEFAULT_BEACON_INTERVAL;
ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON |
BSS_CHANGED_BEACON_ENABLED |
@@ -536,16 +533,7 @@ void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata)
* whether the interface is running, which, at this point,
* it no longer is.
*/
- cancel_work_sync(&sdata->u.mesh.work);
-
- /*
- * When we get here, the interface is marked down.
- * Call synchronize_rcu() to wait for the RX path
- * should it be using the interface and enqueuing
- * frames at this very time on another CPU.
- */
- rcu_barrier(); /* Wait for RX path and call_rcu()'s */
- skb_queue_purge(&sdata->u.mesh.skb_queue);
+ cancel_work_sync(&sdata->work);
}
static void ieee80211_mesh_rx_bcn_presp(struct ieee80211_sub_if_data *sdata,
@@ -608,8 +596,8 @@ static void ieee80211_mesh_rx_mgmt_action(struct ieee80211_sub_if_data *sdata,
}
}
-static void ieee80211_mesh_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
- struct sk_buff *skb)
+void ieee80211_mesh_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
+ struct sk_buff *skb)
{
struct ieee80211_rx_status *rx_status;
struct ieee80211_if_mesh *ifmsh;
@@ -632,26 +620,11 @@ static void ieee80211_mesh_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
ieee80211_mesh_rx_mgmt_action(sdata, mgmt, skb->len, rx_status);
break;
}
-
- kfree_skb(skb);
}
-static void ieee80211_mesh_work(struct work_struct *work)
+void ieee80211_mesh_work(struct ieee80211_sub_if_data *sdata)
{
- struct ieee80211_sub_if_data *sdata =
- container_of(work, struct ieee80211_sub_if_data, u.mesh.work);
- struct ieee80211_local *local = sdata->local;
struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
- struct sk_buff *skb;
-
- if (!ieee80211_sdata_running(sdata))
- return;
-
- if (local->scanning)
- return;
-
- while ((skb = skb_dequeue(&ifmsh->skb_queue)))
- ieee80211_mesh_rx_queued_mgmt(sdata, skb);
if (ifmsh->preq_queue_len &&
time_after(jiffies,
@@ -678,7 +651,7 @@ void ieee80211_mesh_notify_scan_completed(struct ieee80211_local *local)
rcu_read_lock();
list_for_each_entry_rcu(sdata, &local->interfaces, list)
if (ieee80211_vif_is_mesh(&sdata->vif))
- ieee80211_queue_work(&local->hw, &sdata->u.mesh.work);
+ ieee80211_queue_work(&local->hw, &sdata->work);
rcu_read_unlock();
}
@@ -686,11 +659,9 @@ void ieee80211_mesh_init_sdata(struct ieee80211_sub_if_data *sdata)
{
struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
- INIT_WORK(&ifmsh->work, ieee80211_mesh_work);
setup_timer(&ifmsh->housekeeping_timer,
ieee80211_mesh_housekeeping_timer,
(unsigned long) sdata);
- skb_queue_head_init(&sdata->u.mesh.skb_queue);
ifmsh->mshcfg.dot11MeshRetryTimeout = MESH_RET_T;
ifmsh->mshcfg.dot11MeshConfirmTimeout = MESH_CONF_T;
@@ -731,29 +702,3 @@ void ieee80211_mesh_init_sdata(struct ieee80211_sub_if_data *sdata)
INIT_LIST_HEAD(&ifmsh->preq_queue.list);
spin_lock_init(&ifmsh->mesh_preq_queue_lock);
}
-
-ieee80211_rx_result
-ieee80211_mesh_rx_mgmt(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb)
-{
- struct ieee80211_local *local = sdata->local;
- struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
- struct ieee80211_mgmt *mgmt;
- u16 fc;
-
- if (skb->len < 24)
- return RX_DROP_MONITOR;
-
- mgmt = (struct ieee80211_mgmt *) skb->data;
- fc = le16_to_cpu(mgmt->frame_control);
-
- switch (fc & IEEE80211_FCTL_STYPE) {
- case IEEE80211_STYPE_ACTION:
- case IEEE80211_STYPE_PROBE_RESP:
- case IEEE80211_STYPE_BEACON:
- skb_queue_tail(&ifmsh->skb_queue, skb);
- ieee80211_queue_work(&local->hw, &ifmsh->work);
- return RX_QUEUED;
- }
-
- return RX_CONTINUE;
-}
diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h
index c88087f1cd0..ebd3f1d9d88 100644
--- a/net/mac80211/mesh.h
+++ b/net/mac80211/mesh.h
@@ -237,8 +237,6 @@ void ieee80211s_update_metric(struct ieee80211_local *local,
struct sta_info *stainfo, struct sk_buff *skb);
void ieee80211s_stop(void);
void ieee80211_mesh_init_sdata(struct ieee80211_sub_if_data *sdata);
-ieee80211_rx_result
-ieee80211_mesh_rx_mgmt(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb);
void ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata);
void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata);
void ieee80211_mesh_root_setup(struct ieee80211_if_mesh *ifmsh);
diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c
index 0705018d8d1..829e08a657d 100644
--- a/net/mac80211/mesh_hwmp.c
+++ b/net/mac80211/mesh_hwmp.c
@@ -805,14 +805,14 @@ static void mesh_queue_preq(struct mesh_path *mpath, u8 flags)
spin_unlock(&ifmsh->mesh_preq_queue_lock);
if (time_after(jiffies, ifmsh->last_preq + min_preq_int_jiff(sdata)))
- ieee80211_queue_work(&sdata->local->hw, &ifmsh->work);
+ ieee80211_queue_work(&sdata->local->hw, &sdata->work);
else if (time_before(jiffies, ifmsh->last_preq)) {
/* avoid long wait if did not send preqs for a long time
* and jiffies wrapped around
*/
ifmsh->last_preq = jiffies - min_preq_int_jiff(sdata) - 1;
- ieee80211_queue_work(&sdata->local->hw, &ifmsh->work);
+ ieee80211_queue_work(&sdata->local->hw, &sdata->work);
} else
mod_timer(&ifmsh->mesh_path_timer, ifmsh->last_preq +
min_preq_int_jiff(sdata));
diff --git a/net/mac80211/mesh_pathtbl.c b/net/mac80211/mesh_pathtbl.c
index 181ffd6efd8..349e466cf08 100644
--- a/net/mac80211/mesh_pathtbl.c
+++ b/net/mac80211/mesh_pathtbl.c
@@ -315,7 +315,7 @@ int mesh_path_add(u8 *dst, struct ieee80211_sub_if_data *sdata)
read_unlock(&pathtbl_resize_lock);
if (grow) {
set_bit(MESH_WORK_GROW_MPATH_TABLE, &ifmsh->wrkq_flags);
- ieee80211_queue_work(&local->hw, &ifmsh->work);
+ ieee80211_queue_work(&local->hw, &sdata->work);
}
return 0;
@@ -425,7 +425,7 @@ int mpp_path_add(u8 *dst, u8 *mpp, struct ieee80211_sub_if_data *sdata)
read_unlock(&pathtbl_resize_lock);
if (grow) {
set_bit(MESH_WORK_GROW_MPP_TABLE, &ifmsh->wrkq_flags);
- ieee80211_queue_work(&local->hw, &ifmsh->work);
+ ieee80211_queue_work(&local->hw, &sdata->work);
}
return 0;
diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c
index 3cd5f7b5d69..ea13a80a476 100644
--- a/net/mac80211/mesh_plink.c
+++ b/net/mac80211/mesh_plink.c
@@ -65,7 +65,6 @@ void mesh_plink_inc_estab_count(struct ieee80211_sub_if_data *sdata)
{
atomic_inc(&sdata->u.mesh.mshstats.estab_plinks);
mesh_accept_plinks_update(sdata);
- ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON);
}
static inline
@@ -73,7 +72,6 @@ void mesh_plink_dec_estab_count(struct ieee80211_sub_if_data *sdata)
{
atomic_dec(&sdata->u.mesh.mshstats.estab_plinks);
mesh_accept_plinks_update(sdata);
- ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON);
}
/**
@@ -115,7 +113,7 @@ static struct sta_info *mesh_plink_alloc(struct ieee80211_sub_if_data *sdata,
}
/**
- * mesh_plink_deactivate - deactivate mesh peer link
+ * __mesh_plink_deactivate - deactivate mesh peer link
*
* @sta: mesh peer link to deactivate
*
@@ -123,18 +121,23 @@ static struct sta_info *mesh_plink_alloc(struct ieee80211_sub_if_data *sdata,
*
* Locking: the caller must hold sta->lock
*/
-static void __mesh_plink_deactivate(struct sta_info *sta)
+static bool __mesh_plink_deactivate(struct sta_info *sta)
{
struct ieee80211_sub_if_data *sdata = sta->sdata;
+ bool deactivated = false;
- if (sta->plink_state == PLINK_ESTAB)
+ if (sta->plink_state == PLINK_ESTAB) {
mesh_plink_dec_estab_count(sdata);
+ deactivated = true;
+ }
sta->plink_state = PLINK_BLOCKED;
mesh_path_flush_by_nexthop(sta);
+
+ return deactivated;
}
/**
- * __mesh_plink_deactivate - deactivate mesh peer link
+ * mesh_plink_deactivate - deactivate mesh peer link
*
* @sta: mesh peer link to deactivate
*
@@ -142,9 +145,15 @@ static void __mesh_plink_deactivate(struct sta_info *sta)
*/
void mesh_plink_deactivate(struct sta_info *sta)
{
+ struct ieee80211_sub_if_data *sdata = sta->sdata;
+ bool deactivated;
+
spin_lock_bh(&sta->lock);
- __mesh_plink_deactivate(sta);
+ deactivated = __mesh_plink_deactivate(sta);
spin_unlock_bh(&sta->lock);
+
+ if (deactivated)
+ ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON);
}
static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata,
@@ -381,10 +390,16 @@ int mesh_plink_open(struct sta_info *sta)
void mesh_plink_block(struct sta_info *sta)
{
+ struct ieee80211_sub_if_data *sdata = sta->sdata;
+ bool deactivated;
+
spin_lock_bh(&sta->lock);
- __mesh_plink_deactivate(sta);
+ deactivated = __mesh_plink_deactivate(sta);
sta->plink_state = PLINK_BLOCKED;
spin_unlock_bh(&sta->lock);
+
+ if (deactivated)
+ ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON);
}
@@ -397,6 +412,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m
enum plink_event event;
enum plink_frame_type ftype;
size_t baselen;
+ bool deactivated;
u8 ie_len;
u8 *baseaddr;
__le16 plid, llid, reason;
@@ -651,8 +667,9 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m
case CNF_ACPT:
del_timer(&sta->plink_timer);
sta->plink_state = PLINK_ESTAB;
- mesh_plink_inc_estab_count(sdata);
spin_unlock_bh(&sta->lock);
+ mesh_plink_inc_estab_count(sdata);
+ ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON);
mpl_dbg("Mesh plink with %pM ESTABLISHED\n",
sta->sta.addr);
break;
@@ -684,8 +701,9 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m
case OPN_ACPT:
del_timer(&sta->plink_timer);
sta->plink_state = PLINK_ESTAB;
- mesh_plink_inc_estab_count(sdata);
spin_unlock_bh(&sta->lock);
+ mesh_plink_inc_estab_count(sdata);
+ ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON);
mpl_dbg("Mesh plink with %pM ESTABLISHED\n",
sta->sta.addr);
mesh_plink_frame_tx(sdata, PLINK_CONFIRM, sta->sta.addr, llid,
@@ -702,11 +720,13 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m
case CLS_ACPT:
reason = cpu_to_le16(MESH_CLOSE_RCVD);
sta->reason = reason;
- __mesh_plink_deactivate(sta);
+ deactivated = __mesh_plink_deactivate(sta);
sta->plink_state = PLINK_HOLDING;
llid = sta->llid;
mod_plink_timer(sta, dot11MeshHoldingTimeout(sdata));
spin_unlock_bh(&sta->lock);
+ if (deactivated)
+ ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON);
mesh_plink_frame_tx(sdata, PLINK_CLOSE, sta->sta.addr, llid,
plid, reason);
break;
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index f803f8b72a9..b6c163ac22d 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -478,6 +478,39 @@ static void ieee80211_handle_pwr_constr(struct ieee80211_sub_if_data *sdata,
}
}
+void ieee80211_enable_dyn_ps(struct ieee80211_vif *vif)
+{
+ struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
+ struct ieee80211_local *local = sdata->local;
+ struct ieee80211_conf *conf = &local->hw.conf;
+
+ WARN_ON(sdata->vif.type != NL80211_IFTYPE_STATION ||
+ !(local->hw.flags & IEEE80211_HW_SUPPORTS_PS) ||
+ (local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_PS));
+
+ local->disable_dynamic_ps = false;
+ conf->dynamic_ps_timeout = local->dynamic_ps_user_timeout;
+}
+EXPORT_SYMBOL(ieee80211_enable_dyn_ps);
+
+void ieee80211_disable_dyn_ps(struct ieee80211_vif *vif)
+{
+ struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
+ struct ieee80211_local *local = sdata->local;
+ struct ieee80211_conf *conf = &local->hw.conf;
+
+ WARN_ON(sdata->vif.type != NL80211_IFTYPE_STATION ||
+ !(local->hw.flags & IEEE80211_HW_SUPPORTS_PS) ||
+ (local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_PS));
+
+ local->disable_dynamic_ps = true;
+ conf->dynamic_ps_timeout = 0;
+ del_timer_sync(&local->dynamic_ps_timer);
+ ieee80211_queue_work(&local->hw,
+ &local->dynamic_ps_enable_work);
+}
+EXPORT_SYMBOL(ieee80211_disable_dyn_ps);
+
/* powersave */
static void ieee80211_enable_ps(struct ieee80211_local *local,
struct ieee80211_sub_if_data *sdata)
@@ -553,6 +586,7 @@ void ieee80211_recalc_ps(struct ieee80211_local *local, s32 latency)
found->u.mgd.associated->beacon_ies &&
!(found->u.mgd.flags & (IEEE80211_STA_BEACON_POLL |
IEEE80211_STA_CONNECTION_POLL))) {
+ struct ieee80211_conf *conf = &local->hw.conf;
s32 beaconint_us;
if (latency < 0)
@@ -561,25 +595,24 @@ void ieee80211_recalc_ps(struct ieee80211_local *local, s32 latency)
beaconint_us = ieee80211_tu_to_usec(
found->vif.bss_conf.beacon_int);
- timeout = local->hw.conf.dynamic_ps_forced_timeout;
+ timeout = local->dynamic_ps_forced_timeout;
if (timeout < 0) {
/*
+ * Go to full PSM if the user configures a very low
+ * latency requirement.
* The 2 second value is there for compatibility until
* the PM_QOS_NETWORK_LATENCY is configured with real
* values.
*/
- if (latency == 2000000000)
- timeout = 100;
- else if (latency <= 50000)
- timeout = 300;
- else if (latency <= 100000)
- timeout = 100;
- else if (latency <= 500000)
- timeout = 50;
- else
+ if (latency > 1900000000 && latency != 2000000000)
timeout = 0;
+ else
+ timeout = 100;
}
- local->hw.conf.dynamic_ps_timeout = timeout;
+ local->dynamic_ps_user_timeout = timeout;
+ if (!local->disable_dynamic_ps)
+ conf->dynamic_ps_timeout =
+ local->dynamic_ps_user_timeout;
if (beaconint_us > latency) {
local->ps_sdata = NULL;
@@ -665,10 +698,11 @@ void ieee80211_dynamic_ps_timer(unsigned long data)
/* MLME */
static void ieee80211_sta_wmm_params(struct ieee80211_local *local,
- struct ieee80211_if_managed *ifmgd,
+ struct ieee80211_sub_if_data *sdata,
u8 *wmm_param, size_t wmm_param_len)
{
struct ieee80211_tx_queue_params params;
+ struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
size_t left;
int count;
u8 *pos, uapsd_queues = 0;
@@ -757,8 +791,8 @@ static void ieee80211_sta_wmm_params(struct ieee80211_local *local,
}
/* enable WMM or activate new settings */
- local->hw.conf.flags |= IEEE80211_CONF_QOS;
- drv_config(local, IEEE80211_CONF_CHANGE_QOS);
+ sdata->vif.bss_conf.qos = true;
+ ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_QOS);
}
static u32 ieee80211_handle_bss_capability(struct ieee80211_sub_if_data *sdata,
@@ -806,11 +840,12 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata,
{
struct ieee80211_bss *bss = (void *)cbss->priv;
struct ieee80211_local *local = sdata->local;
+ struct ieee80211_bss_conf *bss_conf = &sdata->vif.bss_conf;
bss_info_changed |= BSS_CHANGED_ASSOC;
/* set timing information */
- sdata->vif.bss_conf.beacon_int = cbss->beacon_interval;
- sdata->vif.bss_conf.timestamp = cbss->tsf;
+ bss_conf->beacon_int = cbss->beacon_interval;
+ bss_conf->timestamp = cbss->tsf;
bss_info_changed |= BSS_CHANGED_BEACON_INT;
bss_info_changed |= ieee80211_handle_bss_capability(sdata,
@@ -835,7 +870,12 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata,
ieee80211_led_assoc(local, 1);
- sdata->vif.bss_conf.assoc = 1;
+ if (local->hw.flags & IEEE80211_HW_NEED_DTIM_PERIOD)
+ bss_conf->dtim_period = bss->dtim_period;
+ else
+ bss_conf->dtim_period = 0;
+
+ bss_conf->assoc = 1;
/*
* For now just always ask the driver to update the basic rateset
* when we have associated, we aren't checking whether it actually
@@ -848,9 +888,15 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata,
/* Tell the driver to monitor connection quality (if supported) */
if ((local->hw.flags & IEEE80211_HW_SUPPORTS_CQM_RSSI) &&
- sdata->vif.bss_conf.cqm_rssi_thold)
+ bss_conf->cqm_rssi_thold)
bss_info_changed |= BSS_CHANGED_CQM;
+ /* Enable ARP filtering */
+ if (bss_conf->arp_filter_enabled != sdata->arp_filter_state) {
+ bss_conf->arp_filter_enabled = sdata->arp_filter_state;
+ bss_info_changed |= BSS_CHANGED_ARP_FILTER;
+ }
+
ieee80211_bss_info_change_notify(sdata, bss_info_changed);
mutex_lock(&local->iflist_mtx);
@@ -898,13 +944,13 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
netif_tx_stop_all_queues(sdata->dev);
netif_carrier_off(sdata->dev);
- rcu_read_lock();
+ mutex_lock(&local->sta_mtx);
sta = sta_info_get(sdata, bssid);
if (sta) {
- set_sta_flags(sta, WLAN_STA_DISASSOC);
+ set_sta_flags(sta, WLAN_STA_BLOCK_BA);
ieee80211_sta_tear_down_BA_sessions(sta);
}
- rcu_read_unlock();
+ mutex_unlock(&local->sta_mtx);
changed |= ieee80211_reset_erp_info(sdata);
@@ -932,6 +978,12 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
ieee80211_hw_config(local, config_changed);
+ /* Disable ARP filtering */
+ if (sdata->vif.bss_conf.arp_filter_enabled) {
+ sdata->vif.bss_conf.arp_filter_enabled = false;
+ changed |= BSS_CHANGED_ARP_FILTER;
+ }
+
/* The BSSID (not really interesting) and HT changed */
changed |= BSS_CHANGED_BSSID | BSS_CHANGED_HT;
ieee80211_bss_info_change_notify(sdata, changed);
@@ -1279,7 +1331,7 @@ static bool ieee80211_assoc_success(struct ieee80211_work *wk,
}
if (elems.wmm_param)
- ieee80211_sta_wmm_params(local, ifmgd, elems.wmm_param,
+ ieee80211_sta_wmm_params(local, sdata, elems.wmm_param,
elems.wmm_param_len);
else
ieee80211_set_wmm_default(sdata);
@@ -1551,7 +1603,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems,
true);
- ieee80211_sta_wmm_params(local, ifmgd, elems.wmm_param,
+ ieee80211_sta_wmm_params(local, sdata, elems.wmm_param,
elems.wmm_param_len);
}
@@ -1633,35 +1685,8 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
ieee80211_bss_info_change_notify(sdata, changed);
}
-ieee80211_rx_result ieee80211_sta_rx_mgmt(struct ieee80211_sub_if_data *sdata,
- struct sk_buff *skb)
-{
- struct ieee80211_local *local = sdata->local;
- struct ieee80211_mgmt *mgmt;
- u16 fc;
-
- if (skb->len < 24)
- return RX_DROP_MONITOR;
-
- mgmt = (struct ieee80211_mgmt *) skb->data;
- fc = le16_to_cpu(mgmt->frame_control);
-
- switch (fc & IEEE80211_FCTL_STYPE) {
- case IEEE80211_STYPE_PROBE_RESP:
- case IEEE80211_STYPE_BEACON:
- case IEEE80211_STYPE_DEAUTH:
- case IEEE80211_STYPE_DISASSOC:
- case IEEE80211_STYPE_ACTION:
- skb_queue_tail(&sdata->u.mgd.skb_queue, skb);
- ieee80211_queue_work(&local->hw, &sdata->u.mgd.work);
- return RX_QUEUED;
- }
-
- return RX_DROP_MONITOR;
-}
-
-static void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
- struct sk_buff *skb)
+void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
+ struct sk_buff *skb)
{
struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
struct ieee80211_rx_status *rx_status;
@@ -1693,44 +1718,6 @@ static void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
break;
case IEEE80211_STYPE_ACTION:
switch (mgmt->u.action.category) {
- case WLAN_CATEGORY_BACK: {
- struct ieee80211_local *local = sdata->local;
- int len = skb->len;
- struct sta_info *sta;
-
- rcu_read_lock();
- sta = sta_info_get(sdata, mgmt->sa);
- if (!sta) {
- rcu_read_unlock();
- break;
- }
-
- local_bh_disable();
-
- switch (mgmt->u.action.u.addba_req.action_code) {
- case WLAN_ACTION_ADDBA_REQ:
- if (len < (IEEE80211_MIN_ACTION_SIZE +
- sizeof(mgmt->u.action.u.addba_req)))
- break;
- ieee80211_process_addba_request(local, sta, mgmt, len);
- break;
- case WLAN_ACTION_ADDBA_RESP:
- if (len < (IEEE80211_MIN_ACTION_SIZE +
- sizeof(mgmt->u.action.u.addba_resp)))
- break;
- ieee80211_process_addba_resp(local, sta, mgmt, len);
- break;
- case WLAN_ACTION_DELBA:
- if (len < (IEEE80211_MIN_ACTION_SIZE +
- sizeof(mgmt->u.action.u.delba)))
- break;
- ieee80211_process_delba(sdata, sta, mgmt, len);
- break;
- }
- local_bh_enable();
- rcu_read_unlock();
- break;
- }
case WLAN_CATEGORY_SPECTRUM_MGMT:
ieee80211_sta_process_chanswitch(sdata,
&mgmt->u.action.u.chan_switch.sw_elem,
@@ -1754,7 +1741,7 @@ static void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
default:
WARN(1, "unexpected: %d", rma);
}
- goto out;
+ return;
}
mutex_unlock(&ifmgd->mtx);
@@ -1769,7 +1756,8 @@ static void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
if (wk->sdata != sdata)
continue;
- if (wk->type != IEEE80211_WORK_ASSOC)
+ if (wk->type != IEEE80211_WORK_ASSOC &&
+ wk->type != IEEE80211_WORK_ASSOC_BEACON_WAIT)
continue;
if (memcmp(mgmt->bssid, wk->filter_ta, ETH_ALEN))
@@ -1799,8 +1787,6 @@ static void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
cfg80211_send_deauth(sdata->dev, (u8 *)mgmt, skb->len);
}
- out:
- kfree_skb(skb);
}
static void ieee80211_sta_timer(unsigned long data)
@@ -1815,39 +1801,13 @@ static void ieee80211_sta_timer(unsigned long data)
return;
}
- ieee80211_queue_work(&local->hw, &ifmgd->work);
+ ieee80211_queue_work(&local->hw, &sdata->work);
}
-static void ieee80211_sta_work(struct work_struct *work)
+void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata)
{
- struct ieee80211_sub_if_data *sdata =
- container_of(work, struct ieee80211_sub_if_data, u.mgd.work);
struct ieee80211_local *local = sdata->local;
- struct ieee80211_if_managed *ifmgd;
- struct sk_buff *skb;
-
- if (!ieee80211_sdata_running(sdata))
- return;
-
- if (local->scanning)
- return;
-
- if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_STATION))
- return;
-
- /*
- * ieee80211_queue_work() should have picked up most cases,
- * here we'll pick the the rest.
- */
- if (WARN(local->suspended, "STA MLME work scheduled while "
- "going to suspend\n"))
- return;
-
- ifmgd = &sdata->u.mgd;
-
- /* first process frames to avoid timing out while a frame is pending */
- while ((skb = skb_dequeue(&ifmgd->skb_queue)))
- ieee80211_sta_rx_queued_mgmt(sdata, skb);
+ struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
/* then process the rest of the work */
mutex_lock(&ifmgd->mtx);
@@ -1942,8 +1902,7 @@ static void ieee80211_restart_sta_timer(struct ieee80211_sub_if_data *sdata)
ieee80211_queue_work(&sdata->local->hw,
&sdata->u.mgd.monitor_work);
/* and do all the other regular work too */
- ieee80211_queue_work(&sdata->local->hw,
- &sdata->u.mgd.work);
+ ieee80211_queue_work(&sdata->local->hw, &sdata->work);
}
}
@@ -1958,7 +1917,6 @@ void ieee80211_sta_quiesce(struct ieee80211_sub_if_data *sdata)
* time -- the code here is properly synchronised.
*/
- cancel_work_sync(&ifmgd->work);
cancel_work_sync(&ifmgd->beacon_connection_loss_work);
if (del_timer_sync(&ifmgd->timer))
set_bit(TMR_RUNNING_TIMER, &ifmgd->timers_running);
@@ -1990,7 +1948,6 @@ void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata)
struct ieee80211_if_managed *ifmgd;
ifmgd = &sdata->u.mgd;
- INIT_WORK(&ifmgd->work, ieee80211_sta_work);
INIT_WORK(&ifmgd->monitor_work, ieee80211_sta_monitor_work);
INIT_WORK(&ifmgd->chswitch_work, ieee80211_chswitch_work);
INIT_WORK(&ifmgd->beacon_connection_loss_work,
@@ -2003,7 +1960,6 @@ void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata)
(unsigned long) sdata);
setup_timer(&ifmgd->chswitch_timer, ieee80211_chswitch_timer,
(unsigned long) sdata);
- skb_queue_head_init(&ifmgd->skb_queue);
ifmgd->flags = 0;
@@ -2081,6 +2037,8 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata,
auth_alg = WLAN_AUTH_OPEN;
break;
case NL80211_AUTHTYPE_SHARED_KEY:
+ if (IS_ERR(sdata->local->wep_tx_tfm))
+ return -EOPNOTSUPP;
auth_alg = WLAN_AUTH_SHARED_KEY;
break;
case NL80211_AUTHTYPE_FT:
@@ -2134,6 +2092,8 @@ static enum work_done_result ieee80211_assoc_done(struct ieee80211_work *wk,
struct sk_buff *skb)
{
struct ieee80211_mgmt *mgmt;
+ struct ieee80211_rx_status *rx_status;
+ struct ieee802_11_elems elems;
u16 status;
if (!skb) {
@@ -2141,6 +2101,19 @@ static enum work_done_result ieee80211_assoc_done(struct ieee80211_work *wk,
return WORK_DONE_DESTROY;
}
+ if (wk->type == IEEE80211_WORK_ASSOC_BEACON_WAIT) {
+ mutex_lock(&wk->sdata->u.mgd.mtx);
+ rx_status = (void *) skb->cb;
+ ieee802_11_parse_elems(skb->data + 24 + 12, skb->len - 24 - 12, &elems);
+ ieee80211_rx_bss_info(wk->sdata, (void *)skb->data, skb->len, rx_status,
+ &elems, true);
+ mutex_unlock(&wk->sdata->u.mgd.mtx);
+
+ wk->type = IEEE80211_WORK_ASSOC;
+ /* not really done yet */
+ return WORK_DONE_REQUEUE;
+ }
+
mgmt = (void *)skb->data;
status = le16_to_cpu(mgmt->u.assoc_resp.status_code);
@@ -2153,6 +2126,7 @@ static enum work_done_result ieee80211_assoc_done(struct ieee80211_work *wk,
wk->filter_ta);
return WORK_DONE_DESTROY;
}
+
mutex_unlock(&wk->sdata->u.mgd.mtx);
}
@@ -2253,10 +2227,14 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
if (req->prev_bssid)
memcpy(wk->assoc.prev_bssid, req->prev_bssid, ETH_ALEN);
- wk->type = IEEE80211_WORK_ASSOC;
wk->chan = req->bss->channel;
wk->sdata = sdata;
wk->done = ieee80211_assoc_done;
+ if (!bss->dtim_period &&
+ sdata->local->hw.flags & IEEE80211_HW_NEED_DTIM_PERIOD)
+ wk->type = IEEE80211_WORK_ASSOC_BEACON_WAIT;
+ else
+ wk->type = IEEE80211_WORK_ASSOC;
if (req->use_mfp) {
ifmgd->mfp = IEEE80211_MFP_REQUIRED;
@@ -2282,14 +2260,16 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata,
struct ieee80211_local *local = sdata->local;
struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
struct ieee80211_work *wk;
- const u8 *bssid = req->bss->bssid;
+ u8 bssid[ETH_ALEN];
+ bool assoc_bss = false;
mutex_lock(&ifmgd->mtx);
+ memcpy(bssid, req->bss->bssid, ETH_ALEN);
if (ifmgd->associated == req->bss) {
- bssid = req->bss->bssid;
- ieee80211_set_disassoc(sdata, true);
+ ieee80211_set_disassoc(sdata, false);
mutex_unlock(&ifmgd->mtx);
+ assoc_bss = true;
} else {
bool not_auth_yet = false;
@@ -2302,7 +2282,8 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata,
if (wk->type != IEEE80211_WORK_DIRECT_PROBE &&
wk->type != IEEE80211_WORK_AUTH &&
- wk->type != IEEE80211_WORK_ASSOC)
+ wk->type != IEEE80211_WORK_ASSOC &&
+ wk->type != IEEE80211_WORK_ASSOC_BEACON_WAIT)
continue;
if (memcmp(req->bss->bssid, wk->filter_ta, ETH_ALEN))
@@ -2335,6 +2316,8 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata,
ieee80211_send_deauth_disassoc(sdata, bssid, IEEE80211_STYPE_DEAUTH,
req->reason_code, cookie,
!req->local_state_change);
+ if (assoc_bss)
+ sta_info_destroy_addr(sdata, bssid);
ieee80211_recalc_idle(sdata->local);
@@ -2379,41 +2362,6 @@ int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata,
return 0;
}
-int ieee80211_mgd_action(struct ieee80211_sub_if_data *sdata,
- struct ieee80211_channel *chan,
- enum nl80211_channel_type channel_type,
- const u8 *buf, size_t len, u64 *cookie)
-{
- struct ieee80211_local *local = sdata->local;
- struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
- struct sk_buff *skb;
-
- /* Check that we are on the requested channel for transmission */
- if ((chan != local->tmp_channel ||
- channel_type != local->tmp_channel_type) &&
- (chan != local->oper_channel ||
- channel_type != local->_oper_channel_type))
- return -EBUSY;
-
- skb = dev_alloc_skb(local->hw.extra_tx_headroom + len);
- if (!skb)
- return -ENOMEM;
- skb_reserve(skb, local->hw.extra_tx_headroom);
-
- memcpy(skb_put(skb, len), buf, len);
-
- if (!(ifmgd->flags & IEEE80211_STA_MFP_ENABLED))
- IEEE80211_SKB_CB(skb)->flags |=
- IEEE80211_TX_INTFL_DONT_ENCRYPT;
- IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_NL80211_FRAME_TX |
- IEEE80211_TX_CTL_REQ_TX_STATUS;
- skb->dev = sdata->dev;
- ieee80211_tx_skb(sdata, skb);
-
- *cookie = (unsigned long) skb;
- return 0;
-}
-
void ieee80211_cqm_rssi_notify(struct ieee80211_vif *vif,
enum nl80211_cqm_rssi_threshold_event rssi_event,
gfp_t gfp)
diff --git a/net/mac80211/pm.c b/net/mac80211/pm.c
index 75202b295a4..d287fde0431 100644
--- a/net/mac80211/pm.c
+++ b/net/mac80211/pm.c
@@ -40,22 +40,14 @@ int __ieee80211_suspend(struct ieee80211_hw *hw)
list_for_each_entry(sdata, &local->interfaces, list)
ieee80211_disable_keys(sdata);
- /* Tear down aggregation sessions */
-
- rcu_read_lock();
-
- if (hw->flags & IEEE80211_HW_AMPDU_AGGREGATION) {
- list_for_each_entry_rcu(sta, &local->sta_list, list) {
+ /* tear down aggregation sessions and remove STAs */
+ mutex_lock(&local->sta_mtx);
+ list_for_each_entry(sta, &local->sta_list, list) {
+ if (hw->flags & IEEE80211_HW_AMPDU_AGGREGATION) {
set_sta_flags(sta, WLAN_STA_BLOCK_BA);
ieee80211_sta_tear_down_BA_sessions(sta);
}
- }
- rcu_read_unlock();
-
- /* remove STAs */
- mutex_lock(&local->sta_mtx);
- list_for_each_entry(sta, &local->sta_list, list) {
if (sta->uploaded) {
sdata = sta->sdata;
if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
@@ -72,6 +64,8 @@ int __ieee80211_suspend(struct ieee80211_hw *hw)
/* remove all interfaces */
list_for_each_entry(sdata, &local->interfaces, list) {
+ cancel_work_sync(&sdata->work);
+
switch(sdata->vif.type) {
case NL80211_IFTYPE_STATION:
ieee80211_sta_quiesce(sdata);
diff --git a/net/mac80211/rate.h b/net/mac80211/rate.h
index 065a96190e3..168427b0ffd 100644
--- a/net/mac80211/rate.h
+++ b/net/mac80211/rate.h
@@ -147,5 +147,18 @@ static inline void rc80211_minstrel_exit(void)
}
#endif
+#ifdef CONFIG_MAC80211_RC_MINSTREL_HT
+extern int rc80211_minstrel_ht_init(void);
+extern void rc80211_minstrel_ht_exit(void);
+#else
+static inline int rc80211_minstrel_ht_init(void)
+{
+ return 0;
+}
+static inline void rc80211_minstrel_ht_exit(void)
+{
+}
+#endif
+
#endif /* IEEE80211_RATE_H */
diff --git a/net/mac80211/rc80211_minstrel.c b/net/mac80211/rc80211_minstrel.c
index f65ce6dcc8e..778c604d793 100644
--- a/net/mac80211/rc80211_minstrel.c
+++ b/net/mac80211/rc80211_minstrel.c
@@ -67,7 +67,6 @@ rix_to_ndx(struct minstrel_sta_info *mi, int rix)
for (i = rix; i >= 0; i--)
if (mi->r[i].rix == rix)
break;
- WARN_ON(i < 0);
return i;
}
diff --git a/net/mac80211/rc80211_minstrel_ht.c b/net/mac80211/rc80211_minstrel_ht.c
new file mode 100644
index 00000000000..c5b465904e3
--- /dev/null
+++ b/net/mac80211/rc80211_minstrel_ht.c
@@ -0,0 +1,827 @@
+/*
+ * Copyright (C) 2010 Felix Fietkau <nbd@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/netdevice.h>
+#include <linux/types.h>
+#include <linux/skbuff.h>
+#include <linux/debugfs.h>
+#include <linux/random.h>
+#include <linux/ieee80211.h>
+#include <net/mac80211.h>
+#include "rate.h"
+#include "rc80211_minstrel.h"
+#include "rc80211_minstrel_ht.h"
+
+#define AVG_PKT_SIZE 1200
+#define SAMPLE_COLUMNS 10
+#define EWMA_LEVEL 75
+
+/* Number of bits for an average sized packet */
+#define MCS_NBITS (AVG_PKT_SIZE << 3)
+
+/* Number of symbols for a packet with (bps) bits per symbol */
+#define MCS_NSYMS(bps) ((MCS_NBITS + (bps) - 1) / (bps))
+
+/* Transmission time for a packet containing (syms) symbols */
+#define MCS_SYMBOL_TIME(sgi, syms) \
+ (sgi ? \
+ ((syms) * 18 + 4) / 5 : /* syms * 3.6 us */ \
+ (syms) << 2 /* syms * 4 us */ \
+ )
+
+/* Transmit duration for the raw data part of an average sized packet */
+#define MCS_DURATION(streams, sgi, bps) MCS_SYMBOL_TIME(sgi, MCS_NSYMS((streams) * (bps)))
+
+/* MCS rate information for an MCS group */
+#define MCS_GROUP(_streams, _sgi, _ht40) { \
+ .streams = _streams, \
+ .flags = \
+ (_sgi ? IEEE80211_TX_RC_SHORT_GI : 0) | \
+ (_ht40 ? IEEE80211_TX_RC_40_MHZ_WIDTH : 0), \
+ .duration = { \
+ MCS_DURATION(_streams, _sgi, _ht40 ? 54 : 26), \
+ MCS_DURATION(_streams, _sgi, _ht40 ? 108 : 52), \
+ MCS_DURATION(_streams, _sgi, _ht40 ? 162 : 78), \
+ MCS_DURATION(_streams, _sgi, _ht40 ? 216 : 104), \
+ MCS_DURATION(_streams, _sgi, _ht40 ? 324 : 156), \
+ MCS_DURATION(_streams, _sgi, _ht40 ? 432 : 208), \
+ MCS_DURATION(_streams, _sgi, _ht40 ? 486 : 234), \
+ MCS_DURATION(_streams, _sgi, _ht40 ? 540 : 260) \
+ } \
+}
+
+/*
+ * To enable sufficiently targeted rate sampling, MCS rates are divided into
+ * groups, based on the number of streams and flags (HT40, SGI) that they
+ * use.
+ */
+const struct mcs_group minstrel_mcs_groups[] = {
+ MCS_GROUP(1, 0, 0),
+ MCS_GROUP(2, 0, 0),
+#if MINSTREL_MAX_STREAMS >= 3
+ MCS_GROUP(3, 0, 0),
+#endif
+
+ MCS_GROUP(1, 1, 0),
+ MCS_GROUP(2, 1, 0),
+#if MINSTREL_MAX_STREAMS >= 3
+ MCS_GROUP(3, 1, 0),
+#endif
+
+ MCS_GROUP(1, 0, 1),
+ MCS_GROUP(2, 0, 1),
+#if MINSTREL_MAX_STREAMS >= 3
+ MCS_GROUP(3, 0, 1),
+#endif
+
+ MCS_GROUP(1, 1, 1),
+ MCS_GROUP(2, 1, 1),
+#if MINSTREL_MAX_STREAMS >= 3
+ MCS_GROUP(3, 1, 1),
+#endif
+};
+
+static u8 sample_table[SAMPLE_COLUMNS][MCS_GROUP_RATES];
+
+/*
+ * Perform EWMA (Exponentially Weighted Moving Average) calculation
+ */
+static int
+minstrel_ewma(int old, int new, int weight)
+{
+ return (new * (100 - weight) + old * weight) / 100;
+}
+
+/*
+ * Look up an MCS group index based on mac80211 rate information
+ */
+static int
+minstrel_ht_get_group_idx(struct ieee80211_tx_rate *rate)
+{
+ int streams = (rate->idx / MCS_GROUP_RATES) + 1;
+ u32 flags = IEEE80211_TX_RC_SHORT_GI | IEEE80211_TX_RC_40_MHZ_WIDTH;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(minstrel_mcs_groups); i++) {
+ if (minstrel_mcs_groups[i].streams != streams)
+ continue;
+ if (minstrel_mcs_groups[i].flags != (rate->flags & flags))
+ continue;
+
+ return i;
+ }
+
+ WARN_ON(1);
+ return 0;
+}
+
+static inline struct minstrel_rate_stats *
+minstrel_get_ratestats(struct minstrel_ht_sta *mi, int index)
+{
+ return &mi->groups[index / MCS_GROUP_RATES].rates[index % MCS_GROUP_RATES];
+}
+
+
+/*
+ * Recalculate success probabilities and counters for a rate using EWMA
+ */
+static void
+minstrel_calc_rate_ewma(struct minstrel_priv *mp, struct minstrel_rate_stats *mr)
+{
+ if (unlikely(mr->attempts > 0)) {
+ mr->sample_skipped = 0;
+ mr->cur_prob = MINSTREL_FRAC(mr->success, mr->attempts);
+ if (!mr->att_hist)
+ mr->probability = mr->cur_prob;
+ else
+ mr->probability = minstrel_ewma(mr->probability,
+ mr->cur_prob, EWMA_LEVEL);
+ mr->att_hist += mr->attempts;
+ mr->succ_hist += mr->success;
+ } else {
+ mr->sample_skipped++;
+ }
+ mr->last_success = mr->success;
+ mr->last_attempts = mr->attempts;
+ mr->success = 0;
+ mr->attempts = 0;
+}
+
+/*
+ * Calculate throughput based on the average A-MPDU length, taking into account
+ * the expected number of retransmissions and their expected length
+ */
+static void
+minstrel_ht_calc_tp(struct minstrel_priv *mp, struct minstrel_ht_sta *mi,
+ int group, int rate)
+{
+ struct minstrel_rate_stats *mr;
+ unsigned int usecs;
+
+ mr = &mi->groups[group].rates[rate];
+
+ if (mr->probability < MINSTREL_FRAC(1, 10)) {
+ mr->cur_tp = 0;
+ return;
+ }
+
+ usecs = mi->overhead / MINSTREL_TRUNC(mi->avg_ampdu_len);
+ usecs += minstrel_mcs_groups[group].duration[rate];
+ mr->cur_tp = MINSTREL_TRUNC((1000000 / usecs) * mr->probability);
+}
+
+/*
+ * Update rate statistics and select new primary rates
+ *
+ * Rules for rate selection:
+ * - max_prob_rate must use only one stream, as a tradeoff between delivery
+ * probability and throughput during strong fluctuations
+ * - as long as the max prob rate has a probability of more than 3/4, pick
+ * higher throughput rates, even if the probablity is a bit lower
+ */
+static void
+minstrel_ht_update_stats(struct minstrel_priv *mp, struct minstrel_ht_sta *mi)
+{
+ struct minstrel_mcs_group_data *mg;
+ struct minstrel_rate_stats *mr;
+ int cur_prob, cur_prob_tp, cur_tp, cur_tp2;
+ int group, i, index;
+
+ if (mi->ampdu_packets > 0) {
+ mi->avg_ampdu_len = minstrel_ewma(mi->avg_ampdu_len,
+ MINSTREL_FRAC(mi->ampdu_len, mi->ampdu_packets), EWMA_LEVEL);
+ mi->ampdu_len = 0;
+ mi->ampdu_packets = 0;
+ }
+
+ mi->sample_slow = 0;
+ mi->sample_count = 0;
+ mi->max_tp_rate = 0;
+ mi->max_tp_rate2 = 0;
+ mi->max_prob_rate = 0;
+
+ for (group = 0; group < ARRAY_SIZE(minstrel_mcs_groups); group++) {
+ cur_prob = 0;
+ cur_prob_tp = 0;
+ cur_tp = 0;
+ cur_tp2 = 0;
+
+ mg = &mi->groups[group];
+ if (!mg->supported)
+ continue;
+
+ mg->max_tp_rate = 0;
+ mg->max_tp_rate2 = 0;
+ mg->max_prob_rate = 0;
+ mi->sample_count++;
+
+ for (i = 0; i < MCS_GROUP_RATES; i++) {
+ if (!(mg->supported & BIT(i)))
+ continue;
+
+ mr = &mg->rates[i];
+ mr->retry_updated = false;
+ index = MCS_GROUP_RATES * group + i;
+ minstrel_calc_rate_ewma(mp, mr);
+ minstrel_ht_calc_tp(mp, mi, group, i);
+
+ if (!mr->cur_tp)
+ continue;
+
+ /* ignore the lowest rate of each single-stream group */
+ if (!i && minstrel_mcs_groups[group].streams == 1)
+ continue;
+
+ if ((mr->cur_tp > cur_prob_tp && mr->probability >
+ MINSTREL_FRAC(3, 4)) || mr->probability > cur_prob) {
+ mg->max_prob_rate = index;
+ cur_prob = mr->probability;
+ cur_prob_tp = mr->cur_tp;
+ }
+
+ if (mr->cur_tp > cur_tp) {
+ swap(index, mg->max_tp_rate);
+ cur_tp = mr->cur_tp;
+ mr = minstrel_get_ratestats(mi, index);
+ }
+
+ if (index >= mg->max_tp_rate)
+ continue;
+
+ if (mr->cur_tp > cur_tp2) {
+ mg->max_tp_rate2 = index;
+ cur_tp2 = mr->cur_tp;
+ }
+ }
+ }
+
+ /* try to sample up to half of the availble rates during each interval */
+ mi->sample_count *= 4;
+
+ cur_prob = 0;
+ cur_prob_tp = 0;
+ cur_tp = 0;
+ cur_tp2 = 0;
+ for (group = 0; group < ARRAY_SIZE(minstrel_mcs_groups); group++) {
+ mg = &mi->groups[group];
+ if (!mg->supported)
+ continue;
+
+ mr = minstrel_get_ratestats(mi, mg->max_prob_rate);
+ if (cur_prob_tp < mr->cur_tp &&
+ minstrel_mcs_groups[group].streams == 1) {
+ mi->max_prob_rate = mg->max_prob_rate;
+ cur_prob = mr->cur_prob;
+ cur_prob_tp = mr->cur_tp;
+ }
+
+ mr = minstrel_get_ratestats(mi, mg->max_tp_rate);
+ if (cur_tp < mr->cur_tp) {
+ mi->max_tp_rate = mg->max_tp_rate;
+ cur_tp = mr->cur_tp;
+ }
+
+ mr = minstrel_get_ratestats(mi, mg->max_tp_rate2);
+ if (cur_tp2 < mr->cur_tp) {
+ mi->max_tp_rate2 = mg->max_tp_rate2;
+ cur_tp2 = mr->cur_tp;
+ }
+ }
+
+ mi->stats_update = jiffies;
+}
+
+static bool
+minstrel_ht_txstat_valid(struct ieee80211_tx_rate *rate)
+{
+ if (!rate->count)
+ return false;
+
+ if (rate->idx < 0)
+ return false;
+
+ return !!(rate->flags & IEEE80211_TX_RC_MCS);
+}
+
+static void
+minstrel_next_sample_idx(struct minstrel_ht_sta *mi)
+{
+ struct minstrel_mcs_group_data *mg;
+
+ for (;;) {
+ mi->sample_group++;
+ mi->sample_group %= ARRAY_SIZE(minstrel_mcs_groups);
+ mg = &mi->groups[mi->sample_group];
+
+ if (!mg->supported)
+ continue;
+
+ if (++mg->index >= MCS_GROUP_RATES) {
+ mg->index = 0;
+ if (++mg->column >= ARRAY_SIZE(sample_table))
+ mg->column = 0;
+ }
+ break;
+ }
+}
+
+static void
+minstrel_downgrade_rate(struct minstrel_ht_sta *mi, unsigned int *idx,
+ bool primary)
+{
+ int group, orig_group;
+
+ orig_group = group = *idx / MCS_GROUP_RATES;
+ while (group > 0) {
+ group--;
+
+ if (!mi->groups[group].supported)
+ continue;
+
+ if (minstrel_mcs_groups[group].streams >
+ minstrel_mcs_groups[orig_group].streams)
+ continue;
+
+ if (primary)
+ *idx = mi->groups[group].max_tp_rate;
+ else
+ *idx = mi->groups[group].max_tp_rate2;
+ break;
+ }
+}
+
+static void
+minstrel_aggr_check(struct minstrel_priv *mp, struct ieee80211_sta *pubsta, struct sk_buff *skb)
+{
+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+ struct sta_info *sta = container_of(pubsta, struct sta_info, sta);
+ u16 tid;
+
+ if (unlikely(!ieee80211_is_data_qos(hdr->frame_control)))
+ return;
+
+ if (unlikely(skb->protocol == cpu_to_be16(ETH_P_PAE)))
+ return;
+
+ tid = *ieee80211_get_qos_ctl(hdr) & IEEE80211_QOS_CTL_TID_MASK;
+ if (likely(sta->ampdu_mlme.tid_tx[tid]))
+ return;
+
+ ieee80211_start_tx_ba_session(pubsta, tid);
+}
+
+static void
+minstrel_ht_tx_status(void *priv, struct ieee80211_supported_band *sband,
+ struct ieee80211_sta *sta, void *priv_sta,
+ struct sk_buff *skb)
+{
+ struct minstrel_ht_sta_priv *msp = priv_sta;
+ struct minstrel_ht_sta *mi = &msp->ht;
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+ struct ieee80211_tx_rate *ar = info->status.rates;
+ struct minstrel_rate_stats *rate, *rate2;
+ struct minstrel_priv *mp = priv;
+ bool last = false;
+ int group;
+ int i = 0;
+
+ if (!msp->is_ht)
+ return mac80211_minstrel.tx_status(priv, sband, sta, &msp->legacy, skb);
+
+ /* This packet was aggregated but doesn't carry status info */
+ if ((info->flags & IEEE80211_TX_CTL_AMPDU) &&
+ !(info->flags & IEEE80211_TX_STAT_AMPDU))
+ return;
+
+ if (!info->status.ampdu_len) {
+ info->status.ampdu_ack_len = 1;
+ info->status.ampdu_len = 1;
+ }
+
+ mi->ampdu_packets++;
+ mi->ampdu_len += info->status.ampdu_len;
+
+ if (!mi->sample_wait && !mi->sample_tries && mi->sample_count > 0) {
+ mi->sample_wait = 4 + 2 * MINSTREL_TRUNC(mi->avg_ampdu_len);
+ mi->sample_tries = 3;
+ mi->sample_count--;
+ }
+
+ if (info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE) {
+ mi->sample_packets += info->status.ampdu_len;
+ minstrel_next_sample_idx(mi);
+ }
+
+ for (i = 0; !last; i++) {
+ last = (i == IEEE80211_TX_MAX_RATES - 1) ||
+ !minstrel_ht_txstat_valid(&ar[i + 1]);
+
+ if (!minstrel_ht_txstat_valid(&ar[i]))
+ break;
+
+ group = minstrel_ht_get_group_idx(&ar[i]);
+ rate = &mi->groups[group].rates[ar[i].idx % 8];
+
+ if (last && (info->flags & IEEE80211_TX_STAT_ACK))
+ rate->success += info->status.ampdu_ack_len;
+
+ rate->attempts += ar[i].count * info->status.ampdu_len;
+ }
+
+ /*
+ * check for sudden death of spatial multiplexing,
+ * downgrade to a lower number of streams if necessary.
+ */
+ rate = minstrel_get_ratestats(mi, mi->max_tp_rate);
+ if (rate->attempts > 30 &&
+ MINSTREL_FRAC(rate->success, rate->attempts) <
+ MINSTREL_FRAC(20, 100))
+ minstrel_downgrade_rate(mi, &mi->max_tp_rate, true);
+
+ rate2 = minstrel_get_ratestats(mi, mi->max_tp_rate2);
+ if (rate2->attempts > 30 &&
+ MINSTREL_FRAC(rate2->success, rate2->attempts) <
+ MINSTREL_FRAC(20, 100))
+ minstrel_downgrade_rate(mi, &mi->max_tp_rate2, false);
+
+ if (time_after(jiffies, mi->stats_update + (mp->update_interval / 2 * HZ) / 1000)) {
+ minstrel_ht_update_stats(mp, mi);
+ minstrel_aggr_check(mp, sta, skb);
+ }
+}
+
+static void
+minstrel_calc_retransmit(struct minstrel_priv *mp, struct minstrel_ht_sta *mi,
+ int index)
+{
+ struct minstrel_rate_stats *mr;
+ const struct mcs_group *group;
+ unsigned int tx_time, tx_time_rtscts, tx_time_data;
+ unsigned int cw = mp->cw_min;
+ unsigned int t_slot = 9; /* FIXME */
+ unsigned int ampdu_len = MINSTREL_TRUNC(mi->avg_ampdu_len);
+
+ mr = minstrel_get_ratestats(mi, index);
+ if (mr->probability < MINSTREL_FRAC(1, 10)) {
+ mr->retry_count = 1;
+ mr->retry_count_rtscts = 1;
+ return;
+ }
+
+ mr->retry_count = 2;
+ mr->retry_count_rtscts = 2;
+ mr->retry_updated = true;
+
+ group = &minstrel_mcs_groups[index / MCS_GROUP_RATES];
+ tx_time_data = group->duration[index % MCS_GROUP_RATES] * ampdu_len;
+ tx_time = 2 * (t_slot + mi->overhead + tx_time_data);
+ tx_time_rtscts = 2 * (t_slot + mi->overhead_rtscts + tx_time_data);
+ do {
+ cw = (cw << 1) | 1;
+ cw = min(cw, mp->cw_max);
+ tx_time += cw + t_slot + mi->overhead;
+ tx_time_rtscts += cw + t_slot + mi->overhead_rtscts;
+ if (tx_time_rtscts < mp->segment_size)
+ mr->retry_count_rtscts++;
+ } while ((tx_time < mp->segment_size) &&
+ (++mr->retry_count < mp->max_retry));
+}
+
+
+static void
+minstrel_ht_set_rate(struct minstrel_priv *mp, struct minstrel_ht_sta *mi,
+ struct ieee80211_tx_rate *rate, int index,
+ struct ieee80211_tx_rate_control *txrc,
+ bool sample, bool rtscts)
+{
+ const struct mcs_group *group = &minstrel_mcs_groups[index / MCS_GROUP_RATES];
+ struct minstrel_rate_stats *mr;
+
+ mr = minstrel_get_ratestats(mi, index);
+ if (!mr->retry_updated)
+ minstrel_calc_retransmit(mp, mi, index);
+
+ if (mr->probability < MINSTREL_FRAC(20, 100))
+ rate->count = 2;
+ else if (rtscts)
+ rate->count = mr->retry_count_rtscts;
+ else
+ rate->count = mr->retry_count;
+
+ rate->flags = IEEE80211_TX_RC_MCS | group->flags;
+ if (txrc->short_preamble)
+ rate->flags |= IEEE80211_TX_RC_USE_SHORT_PREAMBLE;
+ if (txrc->rts || rtscts)
+ rate->flags |= IEEE80211_TX_RC_USE_RTS_CTS;
+ rate->idx = index % MCS_GROUP_RATES + (group->streams - 1) * MCS_GROUP_RATES;
+}
+
+static inline int
+minstrel_get_duration(int index)
+{
+ const struct mcs_group *group = &minstrel_mcs_groups[index / MCS_GROUP_RATES];
+ return group->duration[index % MCS_GROUP_RATES];
+}
+
+static int
+minstrel_get_sample_rate(struct minstrel_priv *mp, struct minstrel_ht_sta *mi)
+{
+ struct minstrel_rate_stats *mr;
+ struct minstrel_mcs_group_data *mg;
+ int sample_idx = 0;
+
+ if (mi->sample_wait > 0) {
+ mi->sample_wait--;
+ return -1;
+ }
+
+ if (!mi->sample_tries)
+ return -1;
+
+ mi->sample_tries--;
+ mg = &mi->groups[mi->sample_group];
+ sample_idx = sample_table[mg->column][mg->index];
+ mr = &mg->rates[sample_idx];
+ sample_idx += mi->sample_group * MCS_GROUP_RATES;
+
+ /*
+ * When not using MRR, do not sample if the probability is already
+ * higher than 95% to avoid wasting airtime
+ */
+ if (!mp->has_mrr && (mr->probability > MINSTREL_FRAC(95, 100)))
+ goto next;
+
+ /*
+ * Make sure that lower rates get sampled only occasionally,
+ * if the link is working perfectly.
+ */
+ if (minstrel_get_duration(sample_idx) >
+ minstrel_get_duration(mi->max_tp_rate)) {
+ if (mr->sample_skipped < 10)
+ goto next;
+
+ if (mi->sample_slow++ > 2)
+ goto next;
+ }
+
+ return sample_idx;
+
+next:
+ minstrel_next_sample_idx(mi);
+ return -1;
+}
+
+static void
+minstrel_ht_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta,
+ struct ieee80211_tx_rate_control *txrc)
+{
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(txrc->skb);
+ struct ieee80211_tx_rate *ar = info->status.rates;
+ struct minstrel_ht_sta_priv *msp = priv_sta;
+ struct minstrel_ht_sta *mi = &msp->ht;
+ struct minstrel_priv *mp = priv;
+ int sample_idx;
+
+ if (rate_control_send_low(sta, priv_sta, txrc))
+ return;
+
+ if (!msp->is_ht)
+ return mac80211_minstrel.get_rate(priv, sta, &msp->legacy, txrc);
+
+ info->flags |= mi->tx_flags;
+ sample_idx = minstrel_get_sample_rate(mp, mi);
+ if (sample_idx >= 0) {
+ minstrel_ht_set_rate(mp, mi, &ar[0], sample_idx,
+ txrc, true, false);
+ minstrel_ht_set_rate(mp, mi, &ar[1], mi->max_tp_rate,
+ txrc, false, true);
+ info->flags |= IEEE80211_TX_CTL_RATE_CTRL_PROBE;
+ } else {
+ minstrel_ht_set_rate(mp, mi, &ar[0], mi->max_tp_rate,
+ txrc, false, false);
+ minstrel_ht_set_rate(mp, mi, &ar[1], mi->max_tp_rate2,
+ txrc, false, true);
+ }
+ minstrel_ht_set_rate(mp, mi, &ar[2], mi->max_prob_rate, txrc, false, true);
+
+ ar[3].count = 0;
+ ar[3].idx = -1;
+
+ mi->total_packets++;
+
+ /* wraparound */
+ if (mi->total_packets == ~0) {
+ mi->total_packets = 0;
+ mi->sample_packets = 0;
+ }
+}
+
+static void
+minstrel_ht_update_caps(void *priv, struct ieee80211_supported_band *sband,
+ struct ieee80211_sta *sta, void *priv_sta,
+ enum nl80211_channel_type oper_chan_type)
+{
+ struct minstrel_priv *mp = priv;
+ struct minstrel_ht_sta_priv *msp = priv_sta;
+ struct minstrel_ht_sta *mi = &msp->ht;
+ struct ieee80211_mcs_info *mcs = &sta->ht_cap.mcs;
+ struct ieee80211_local *local = hw_to_local(mp->hw);
+ u16 sta_cap = sta->ht_cap.cap;
+ int ack_dur;
+ int stbc;
+ int i;
+
+ /* fall back to the old minstrel for legacy stations */
+ if (!sta->ht_cap.ht_supported) {
+ msp->is_ht = false;
+ memset(&msp->legacy, 0, sizeof(msp->legacy));
+ msp->legacy.r = msp->ratelist;
+ msp->legacy.sample_table = msp->sample_table;
+ return mac80211_minstrel.rate_init(priv, sband, sta, &msp->legacy);
+ }
+
+ BUILD_BUG_ON(ARRAY_SIZE(minstrel_mcs_groups) !=
+ MINSTREL_MAX_STREAMS * MINSTREL_STREAM_GROUPS);
+
+ msp->is_ht = true;
+ memset(mi, 0, sizeof(*mi));
+ mi->stats_update = jiffies;
+
+ ack_dur = ieee80211_frame_duration(local, 10, 60, 1, 1);
+ mi->overhead = ieee80211_frame_duration(local, 0, 60, 1, 1) + ack_dur;
+ mi->overhead_rtscts = mi->overhead + 2 * ack_dur;
+
+ mi->avg_ampdu_len = MINSTREL_FRAC(1, 1);
+
+ /* When using MRR, sample more on the first attempt, without delay */
+ if (mp->has_mrr) {
+ mi->sample_count = 16;
+ mi->sample_wait = 0;
+ } else {
+ mi->sample_count = 8;
+ mi->sample_wait = 8;
+ }
+ mi->sample_tries = 4;
+
+ stbc = (sta_cap & IEEE80211_HT_CAP_RX_STBC) >>
+ IEEE80211_HT_CAP_RX_STBC_SHIFT;
+ mi->tx_flags |= stbc << IEEE80211_TX_CTL_STBC_SHIFT;
+
+ if (sta_cap & IEEE80211_HT_CAP_LDPC_CODING)
+ mi->tx_flags |= IEEE80211_TX_CTL_LDPC;
+
+ if (oper_chan_type != NL80211_CHAN_HT40MINUS &&
+ oper_chan_type != NL80211_CHAN_HT40PLUS)
+ sta_cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40;
+
+ for (i = 0; i < ARRAY_SIZE(mi->groups); i++) {
+ u16 req = 0;
+
+ mi->groups[i].supported = 0;
+ if (minstrel_mcs_groups[i].flags & IEEE80211_TX_RC_SHORT_GI) {
+ if (minstrel_mcs_groups[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH)
+ req |= IEEE80211_HT_CAP_SGI_40;
+ else
+ req |= IEEE80211_HT_CAP_SGI_20;
+ }
+
+ if (minstrel_mcs_groups[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH)
+ req |= IEEE80211_HT_CAP_SUP_WIDTH_20_40;
+
+ if ((sta_cap & req) != req)
+ continue;
+
+ mi->groups[i].supported =
+ mcs->rx_mask[minstrel_mcs_groups[i].streams - 1];
+ }
+}
+
+static void
+minstrel_ht_rate_init(void *priv, struct ieee80211_supported_band *sband,
+ struct ieee80211_sta *sta, void *priv_sta)
+{
+ struct minstrel_priv *mp = priv;
+
+ minstrel_ht_update_caps(priv, sband, sta, priv_sta, mp->hw->conf.channel_type);
+}
+
+static void
+minstrel_ht_rate_update(void *priv, struct ieee80211_supported_band *sband,
+ struct ieee80211_sta *sta, void *priv_sta,
+ u32 changed, enum nl80211_channel_type oper_chan_type)
+{
+ minstrel_ht_update_caps(priv, sband, sta, priv_sta, oper_chan_type);
+}
+
+static void *
+minstrel_ht_alloc_sta(void *priv, struct ieee80211_sta *sta, gfp_t gfp)
+{
+ struct ieee80211_supported_band *sband;
+ struct minstrel_ht_sta_priv *msp;
+ struct minstrel_priv *mp = priv;
+ struct ieee80211_hw *hw = mp->hw;
+ int max_rates = 0;
+ int i;
+
+ for (i = 0; i < IEEE80211_NUM_BANDS; i++) {
+ sband = hw->wiphy->bands[i];
+ if (sband && sband->n_bitrates > max_rates)
+ max_rates = sband->n_bitrates;
+ }
+
+ msp = kzalloc(sizeof(struct minstrel_ht_sta), gfp);
+ if (!msp)
+ return NULL;
+
+ msp->ratelist = kzalloc(sizeof(struct minstrel_rate) * max_rates, gfp);
+ if (!msp->ratelist)
+ goto error;
+
+ msp->sample_table = kmalloc(SAMPLE_COLUMNS * max_rates, gfp);
+ if (!msp->sample_table)
+ goto error1;
+
+ return msp;
+
+error1:
+ kfree(msp->ratelist);
+error:
+ kfree(msp);
+ return NULL;
+}
+
+static void
+minstrel_ht_free_sta(void *priv, struct ieee80211_sta *sta, void *priv_sta)
+{
+ struct minstrel_ht_sta_priv *msp = priv_sta;
+
+ kfree(msp->sample_table);
+ kfree(msp->ratelist);
+ kfree(msp);
+}
+
+static void *
+minstrel_ht_alloc(struct ieee80211_hw *hw, struct dentry *debugfsdir)
+{
+ return mac80211_minstrel.alloc(hw, debugfsdir);
+}
+
+static void
+minstrel_ht_free(void *priv)
+{
+ mac80211_minstrel.free(priv);
+}
+
+static struct rate_control_ops mac80211_minstrel_ht = {
+ .name = "minstrel_ht",
+ .tx_status = minstrel_ht_tx_status,
+ .get_rate = minstrel_ht_get_rate,
+ .rate_init = minstrel_ht_rate_init,
+ .rate_update = minstrel_ht_rate_update,
+ .alloc_sta = minstrel_ht_alloc_sta,
+ .free_sta = minstrel_ht_free_sta,
+ .alloc = minstrel_ht_alloc,
+ .free = minstrel_ht_free,
+#ifdef CONFIG_MAC80211_DEBUGFS
+ .add_sta_debugfs = minstrel_ht_add_sta_debugfs,
+ .remove_sta_debugfs = minstrel_ht_remove_sta_debugfs,
+#endif
+};
+
+
+static void
+init_sample_table(void)
+{
+ int col, i, new_idx;
+ u8 rnd[MCS_GROUP_RATES];
+
+ memset(sample_table, 0xff, sizeof(sample_table));
+ for (col = 0; col < SAMPLE_COLUMNS; col++) {
+ for (i = 0; i < MCS_GROUP_RATES; i++) {
+ get_random_bytes(rnd, sizeof(rnd));
+ new_idx = (i + rnd[i]) % MCS_GROUP_RATES;
+
+ while (sample_table[col][new_idx] != 0xff)
+ new_idx = (new_idx + 1) % MCS_GROUP_RATES;
+
+ sample_table[col][new_idx] = i;
+ }
+ }
+}
+
+int __init
+rc80211_minstrel_ht_init(void)
+{
+ init_sample_table();
+ return ieee80211_rate_control_register(&mac80211_minstrel_ht);
+}
+
+void
+rc80211_minstrel_ht_exit(void)
+{
+ ieee80211_rate_control_unregister(&mac80211_minstrel_ht);
+}
diff --git a/net/mac80211/rc80211_minstrel_ht.h b/net/mac80211/rc80211_minstrel_ht.h
new file mode 100644
index 00000000000..462d2b227ed
--- /dev/null
+++ b/net/mac80211/rc80211_minstrel_ht.h
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2010 Felix Fietkau <nbd@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.
+ */
+
+#ifndef __RC_MINSTREL_HT_H
+#define __RC_MINSTREL_HT_H
+
+/*
+ * The number of streams can be changed to 2 to reduce code
+ * size and memory footprint.
+ */
+#define MINSTREL_MAX_STREAMS 3
+#define MINSTREL_STREAM_GROUPS 4
+
+/* scaled fraction values */
+#define MINSTREL_SCALE 16
+#define MINSTREL_FRAC(val, div) (((val) << MINSTREL_SCALE) / div)
+#define MINSTREL_TRUNC(val) ((val) >> MINSTREL_SCALE)
+
+#define MCS_GROUP_RATES 8
+
+struct mcs_group {
+ u32 flags;
+ unsigned int streams;
+ unsigned int duration[MCS_GROUP_RATES];
+};
+
+extern const struct mcs_group minstrel_mcs_groups[];
+
+struct minstrel_rate_stats {
+ /* current / last sampling period attempts/success counters */
+ unsigned int attempts, last_attempts;
+ unsigned int success, last_success;
+
+ /* total attempts/success counters */
+ u64 att_hist, succ_hist;
+
+ /* current throughput */
+ unsigned int cur_tp;
+
+ /* packet delivery probabilities */
+ unsigned int cur_prob, probability;
+
+ /* maximum retry counts */
+ unsigned int retry_count;
+ unsigned int retry_count_rtscts;
+
+ bool retry_updated;
+ u8 sample_skipped;
+};
+
+struct minstrel_mcs_group_data {
+ u8 index;
+ u8 column;
+
+ /* bitfield of supported MCS rates of this group */
+ u8 supported;
+
+ /* selected primary rates */
+ unsigned int max_tp_rate;
+ unsigned int max_tp_rate2;
+ unsigned int max_prob_rate;
+
+ /* MCS rate statistics */
+ struct minstrel_rate_stats rates[MCS_GROUP_RATES];
+};
+
+struct minstrel_ht_sta {
+ /* ampdu length (average, per sampling interval) */
+ unsigned int ampdu_len;
+ unsigned int ampdu_packets;
+
+ /* ampdu length (EWMA) */
+ unsigned int avg_ampdu_len;
+
+ /* best throughput rate */
+ unsigned int max_tp_rate;
+
+ /* second best throughput rate */
+ unsigned int max_tp_rate2;
+
+ /* best probability rate */
+ unsigned int max_prob_rate;
+
+ /* time of last status update */
+ unsigned long stats_update;
+
+ /* overhead time in usec for each frame */
+ unsigned int overhead;
+ unsigned int overhead_rtscts;
+
+ unsigned int total_packets;
+ unsigned int sample_packets;
+
+ /* tx flags to add for frames for this sta */
+ u32 tx_flags;
+
+ u8 sample_wait;
+ u8 sample_tries;
+ u8 sample_count;
+ u8 sample_slow;
+
+ /* current MCS group to be sampled */
+ u8 sample_group;
+
+ /* MCS rate group info and statistics */
+ struct minstrel_mcs_group_data groups[MINSTREL_MAX_STREAMS * MINSTREL_STREAM_GROUPS];
+};
+
+struct minstrel_ht_sta_priv {
+ union {
+ struct minstrel_ht_sta ht;
+ struct minstrel_sta_info legacy;
+ };
+#ifdef CONFIG_MAC80211_DEBUGFS
+ struct dentry *dbg_stats;
+#endif
+ void *ratelist;
+ void *sample_table;
+ bool is_ht;
+};
+
+void minstrel_ht_add_sta_debugfs(void *priv, void *priv_sta, struct dentry *dir);
+void minstrel_ht_remove_sta_debugfs(void *priv, void *priv_sta);
+
+#endif
diff --git a/net/mac80211/rc80211_minstrel_ht_debugfs.c b/net/mac80211/rc80211_minstrel_ht_debugfs.c
new file mode 100644
index 00000000000..4a5a4b3e779
--- /dev/null
+++ b/net/mac80211/rc80211_minstrel_ht_debugfs.c
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2010 Felix Fietkau <nbd@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/netdevice.h>
+#include <linux/types.h>
+#include <linux/skbuff.h>
+#include <linux/debugfs.h>
+#include <linux/ieee80211.h>
+#include <net/mac80211.h>
+#include "rc80211_minstrel.h"
+#include "rc80211_minstrel_ht.h"
+
+static int
+minstrel_ht_stats_open(struct inode *inode, struct file *file)
+{
+ struct minstrel_ht_sta_priv *msp = inode->i_private;
+ struct minstrel_ht_sta *mi = &msp->ht;
+ struct minstrel_debugfs_info *ms;
+ unsigned int i, j, tp, prob, eprob;
+ char *p;
+ int ret;
+
+ if (!msp->is_ht) {
+ inode->i_private = &msp->legacy;
+ ret = minstrel_stats_open(inode, file);
+ inode->i_private = msp;
+ return ret;
+ }
+
+ ms = kmalloc(sizeof(*ms) + 8192, GFP_KERNEL);
+ if (!ms)
+ return -ENOMEM;
+
+ file->private_data = ms;
+ p = ms->buf;
+ p += sprintf(p, "type rate throughput ewma prob this prob "
+ "this succ/attempt success attempts\n");
+ for (i = 0; i < MINSTREL_MAX_STREAMS * MINSTREL_STREAM_GROUPS; i++) {
+ char htmode = '2';
+ char gimode = 'L';
+
+ if (!mi->groups[i].supported)
+ continue;
+
+ if (minstrel_mcs_groups[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH)
+ htmode = '4';
+ if (minstrel_mcs_groups[i].flags & IEEE80211_TX_RC_SHORT_GI)
+ gimode = 'S';
+
+ for (j = 0; j < MCS_GROUP_RATES; j++) {
+ struct minstrel_rate_stats *mr = &mi->groups[i].rates[j];
+ int idx = i * MCS_GROUP_RATES + j;
+
+ if (!(mi->groups[i].supported & BIT(j)))
+ continue;
+
+ p += sprintf(p, "HT%c0/%cGI ", htmode, gimode);
+
+ *(p++) = (idx == mi->max_tp_rate) ? 'T' : ' ';
+ *(p++) = (idx == mi->max_tp_rate2) ? 't' : ' ';
+ *(p++) = (idx == mi->max_prob_rate) ? 'P' : ' ';
+ p += sprintf(p, "MCS%-2u", (minstrel_mcs_groups[i].streams - 1) *
+ MCS_GROUP_RATES + j);
+
+ tp = mr->cur_tp / 10;
+ prob = MINSTREL_TRUNC(mr->cur_prob * 1000);
+ eprob = MINSTREL_TRUNC(mr->probability * 1000);
+
+ p += sprintf(p, " %6u.%1u %6u.%1u %6u.%1u "
+ "%3u(%3u) %8llu %8llu\n",
+ tp / 10, tp % 10,
+ eprob / 10, eprob % 10,
+ prob / 10, prob % 10,
+ mr->last_success,
+ mr->last_attempts,
+ (unsigned long long)mr->succ_hist,
+ (unsigned long long)mr->att_hist);
+ }
+ }
+ p += sprintf(p, "\nTotal packet count:: ideal %d "
+ "lookaround %d\n",
+ max(0, (int) mi->total_packets - (int) mi->sample_packets),
+ mi->sample_packets);
+ p += sprintf(p, "Average A-MPDU length: %d.%d\n",
+ MINSTREL_TRUNC(mi->avg_ampdu_len),
+ MINSTREL_TRUNC(mi->avg_ampdu_len * 10) % 10);
+ ms->len = p - ms->buf;
+
+ return 0;
+}
+
+static const struct file_operations minstrel_ht_stat_fops = {
+ .owner = THIS_MODULE,
+ .open = minstrel_ht_stats_open,
+ .read = minstrel_stats_read,
+ .release = minstrel_stats_release,
+};
+
+void
+minstrel_ht_add_sta_debugfs(void *priv, void *priv_sta, struct dentry *dir)
+{
+ struct minstrel_ht_sta_priv *msp = priv_sta;
+
+ msp->dbg_stats = debugfs_create_file("rc_stats", S_IRUGO, dir, msp,
+ &minstrel_ht_stat_fops);
+}
+
+void
+minstrel_ht_remove_sta_debugfs(void *priv, void *priv_sta)
+{
+ struct minstrel_ht_sta_priv *msp = priv_sta;
+
+ debugfs_remove(msp->dbg_stats);
+}
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index be9abc2e634..fa0f37e4afe 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -293,7 +293,7 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb,
skb2 = skb_clone(skb, GFP_ATOMIC);
if (skb2) {
skb2->dev = prev_dev;
- netif_rx(skb2);
+ netif_receive_skb(skb2);
}
}
@@ -304,7 +304,7 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb,
if (prev_dev) {
skb->dev = prev_dev;
- netif_rx(skb);
+ netif_receive_skb(skb);
} else
dev_kfree_skb(skb);
@@ -719,16 +719,13 @@ static void ieee80211_rx_reorder_ampdu(struct ieee80211_rx_data *rx,
tid = *ieee80211_get_qos_ctl(hdr) & IEEE80211_QOS_CTL_TID_MASK;
- spin_lock(&sta->lock);
-
- if (!sta->ampdu_mlme.tid_active_rx[tid])
- goto dont_reorder_unlock;
-
- tid_agg_rx = sta->ampdu_mlme.tid_rx[tid];
+ tid_agg_rx = rcu_dereference(sta->ampdu_mlme.tid_rx[tid]);
+ if (!tid_agg_rx)
+ goto dont_reorder;
/* qos null data frames are excluded */
if (unlikely(hdr->frame_control & cpu_to_le16(IEEE80211_STYPE_NULLFUNC)))
- goto dont_reorder_unlock;
+ goto dont_reorder;
/* new, potentially un-ordered, ampdu frame - process it */
@@ -740,20 +737,22 @@ static void ieee80211_rx_reorder_ampdu(struct ieee80211_rx_data *rx,
/* if this mpdu is fragmented - terminate rx aggregation session */
sc = le16_to_cpu(hdr->seq_ctrl);
if (sc & IEEE80211_SCTL_FRAG) {
- spin_unlock(&sta->lock);
- __ieee80211_stop_rx_ba_session(sta, tid, WLAN_BACK_RECIPIENT,
- WLAN_REASON_QSTA_REQUIRE_SETUP);
- dev_kfree_skb(skb);
+ skb->pkt_type = IEEE80211_SDATA_QUEUE_TYPE_FRAME;
+ skb_queue_tail(&rx->sdata->skb_queue, skb);
+ ieee80211_queue_work(&local->hw, &rx->sdata->work);
return;
}
- if (ieee80211_sta_manage_reorder_buf(hw, tid_agg_rx, skb, frames)) {
- spin_unlock(&sta->lock);
+ /*
+ * No locking needed -- we will only ever process one
+ * RX packet at a time, and thus own tid_agg_rx. All
+ * other code manipulating it needs to (and does) make
+ * sure that we cannot get to it any more before doing
+ * anything with it.
+ */
+ if (ieee80211_sta_manage_reorder_buf(hw, tid_agg_rx, skb, frames))
return;
- }
- dont_reorder_unlock:
- spin_unlock(&sta->lock);
dont_reorder:
__skb_queue_tail(frames, skb);
}
@@ -825,6 +824,7 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)
ieee80211_rx_result result = RX_DROP_UNUSABLE;
struct ieee80211_key *stakey = NULL;
int mmie_keyidx = -1;
+ __le16 fc;
/*
* Key selection 101
@@ -866,13 +866,15 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)
if (rx->sta)
stakey = rcu_dereference(rx->sta->key);
- if (!ieee80211_has_protected(hdr->frame_control))
+ fc = hdr->frame_control;
+
+ if (!ieee80211_has_protected(fc))
mmie_keyidx = ieee80211_get_mmie_keyidx(rx->skb);
if (!is_multicast_ether_addr(hdr->addr1) && stakey) {
rx->key = stakey;
/* Skip decryption if the frame is not protected. */
- if (!ieee80211_has_protected(hdr->frame_control))
+ if (!ieee80211_has_protected(fc))
return RX_CONTINUE;
} else if (mmie_keyidx >= 0) {
/* Broadcast/multicast robust management frame / BIP */
@@ -884,7 +886,7 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)
mmie_keyidx >= NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS)
return RX_DROP_MONITOR; /* unexpected BIP keyidx */
rx->key = rcu_dereference(rx->sdata->keys[mmie_keyidx]);
- } else if (!ieee80211_has_protected(hdr->frame_control)) {
+ } else if (!ieee80211_has_protected(fc)) {
/*
* The frame was not protected, so skip decryption. However, we
* need to set rx->key if there is a key that could have been
@@ -892,7 +894,7 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)
* have been expected.
*/
struct ieee80211_key *key = NULL;
- if (ieee80211_is_mgmt(hdr->frame_control) &&
+ if (ieee80211_is_mgmt(fc) &&
is_multicast_ether_addr(hdr->addr1) &&
(key = rcu_dereference(rx->sdata->default_mgmt_key)))
rx->key = key;
@@ -914,7 +916,7 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)
(status->flag & RX_FLAG_IV_STRIPPED))
return RX_CONTINUE;
- hdrlen = ieee80211_hdrlen(hdr->frame_control);
+ hdrlen = ieee80211_hdrlen(fc);
if (rx->skb->len < 8 + hdrlen)
return RX_DROP_UNUSABLE; /* TODO: count this? */
@@ -947,19 +949,17 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)
if (skb_linearize(rx->skb))
return RX_DROP_UNUSABLE;
-
- hdr = (struct ieee80211_hdr *)rx->skb->data;
-
- /* Check for weak IVs if possible */
- if (rx->sta && rx->key->conf.alg == ALG_WEP &&
- ieee80211_is_data(hdr->frame_control) &&
- (!(status->flag & RX_FLAG_IV_STRIPPED) ||
- !(status->flag & RX_FLAG_DECRYPTED)) &&
- ieee80211_wep_is_weak_iv(rx->skb, rx->key))
- rx->sta->wep_weak_iv_count++;
+ /* the hdr variable is invalid now! */
switch (rx->key->conf.alg) {
case ALG_WEP:
+ /* Check for weak IVs if possible */
+ if (rx->sta && ieee80211_is_data(fc) &&
+ (!(status->flag & RX_FLAG_IV_STRIPPED) ||
+ !(status->flag & RX_FLAG_DECRYPTED)) &&
+ ieee80211_wep_is_weak_iv(rx->skb, rx->key))
+ rx->sta->wep_weak_iv_count++;
+
result = ieee80211_crypto_wep_decrypt(rx);
break;
case ALG_TKIP:
@@ -1267,11 +1267,13 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx)
rx->queue, &(rx->skb));
if (rx->key && rx->key->conf.alg == ALG_CCMP &&
ieee80211_has_protected(fc)) {
+ int queue = ieee80211_is_mgmt(fc) ?
+ NUM_RX_DATA_QUEUES : rx->queue;
/* Store CCMP PN so that we can verify that the next
* fragment has a sequential PN value. */
entry->ccmp = 1;
memcpy(entry->last_pn,
- rx->key->u.ccmp.rx_pn[rx->queue],
+ rx->key->u.ccmp.rx_pn[queue],
CCMP_PN_LEN);
}
return RX_QUEUED;
@@ -1291,6 +1293,7 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx)
if (entry->ccmp) {
int i;
u8 pn[CCMP_PN_LEN], *rpn;
+ int queue;
if (!rx->key || rx->key->conf.alg != ALG_CCMP)
return RX_DROP_UNUSABLE;
memcpy(pn, entry->last_pn, CCMP_PN_LEN);
@@ -1299,7 +1302,9 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx)
if (pn[i])
break;
}
- rpn = rx->key->u.ccmp.rx_pn[rx->queue];
+ queue = ieee80211_is_mgmt(fc) ?
+ NUM_RX_DATA_QUEUES : rx->queue;
+ rpn = rx->key->u.ccmp.rx_pn[queue];
if (memcmp(pn, rpn, CCMP_PN_LEN))
return RX_DROP_UNUSABLE;
memcpy(entry->last_pn, pn, CCMP_PN_LEN);
@@ -1573,7 +1578,7 @@ ieee80211_deliver_skb(struct ieee80211_rx_data *rx)
/* deliver to local stack */
skb->protocol = eth_type_trans(skb, dev);
memset(skb->cb, 0, sizeof(skb->cb));
- netif_rx(skb);
+ netif_receive_skb(skb);
}
}
@@ -1829,13 +1834,11 @@ ieee80211_rx_h_ctrl(struct ieee80211_rx_data *rx, struct sk_buff_head *frames)
&bar_data, sizeof(bar_data)))
return RX_DROP_MONITOR;
- spin_lock(&rx->sta->lock);
tid = le16_to_cpu(bar_data.control) >> 12;
- if (!rx->sta->ampdu_mlme.tid_active_rx[tid]) {
- spin_unlock(&rx->sta->lock);
+
+ tid_agg_rx = rcu_dereference(rx->sta->ampdu_mlme.tid_rx[tid]);
+ if (!tid_agg_rx)
return RX_DROP_MONITOR;
- }
- tid_agg_rx = rx->sta->ampdu_mlme.tid_rx[tid];
start_seq_num = le16_to_cpu(bar_data.start_seq_num) >> 4;
@@ -1848,11 +1851,15 @@ ieee80211_rx_h_ctrl(struct ieee80211_rx_data *rx, struct sk_buff_head *frames)
ieee80211_release_reorder_frames(hw, tid_agg_rx, start_seq_num,
frames);
kfree_skb(skb);
- spin_unlock(&rx->sta->lock);
return RX_QUEUED;
}
- return RX_CONTINUE;
+ /*
+ * After this point, we only want management frames,
+ * so we can drop all remaining control frames to
+ * cooked monitor interfaces.
+ */
+ return RX_DROP_MONITOR;
}
static void ieee80211_process_sa_query_req(struct ieee80211_sub_if_data *sdata,
@@ -1944,30 +1951,27 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
if (len < IEEE80211_MIN_ACTION_SIZE + 1)
break;
- if (sdata->vif.type == NL80211_IFTYPE_STATION)
- return ieee80211_sta_rx_mgmt(sdata, rx->skb);
-
switch (mgmt->u.action.u.addba_req.action_code) {
case WLAN_ACTION_ADDBA_REQ:
if (len < (IEEE80211_MIN_ACTION_SIZE +
sizeof(mgmt->u.action.u.addba_req)))
- return RX_DROP_MONITOR;
- ieee80211_process_addba_request(local, rx->sta, mgmt, len);
- goto handled;
+ goto invalid;
+ break;
case WLAN_ACTION_ADDBA_RESP:
if (len < (IEEE80211_MIN_ACTION_SIZE +
sizeof(mgmt->u.action.u.addba_resp)))
- break;
- ieee80211_process_addba_resp(local, rx->sta, mgmt, len);
- goto handled;
+ goto invalid;
+ break;
case WLAN_ACTION_DELBA:
if (len < (IEEE80211_MIN_ACTION_SIZE +
sizeof(mgmt->u.action.u.delba)))
- break;
- ieee80211_process_delba(sdata, rx->sta, mgmt, len);
- goto handled;
+ goto invalid;
+ break;
+ default:
+ goto invalid;
}
- break;
+
+ goto queue;
case WLAN_CATEGORY_SPECTRUM_MGMT:
if (local->hw.conf.channel->band != IEEE80211_BAND_5GHZ)
break;
@@ -1997,7 +2001,7 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
if (memcmp(mgmt->bssid, sdata->u.mgd.bssid, ETH_ALEN))
break;
- return ieee80211_sta_rx_mgmt(sdata, rx->skb);
+ goto queue;
}
break;
case WLAN_CATEGORY_SA_QUERY:
@@ -2015,11 +2019,12 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
break;
case WLAN_CATEGORY_MESH_PLINK:
case WLAN_CATEGORY_MESH_PATH_SEL:
- if (ieee80211_vif_is_mesh(&sdata->vif))
- return ieee80211_mesh_rx_mgmt(sdata, rx->skb);
- break;
+ if (!ieee80211_vif_is_mesh(&sdata->vif))
+ break;
+ goto queue;
}
+ invalid:
/*
* For AP mode, hostapd is responsible for handling any action
* frames that we didn't handle, including returning unknown
@@ -2039,8 +2044,7 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
*/
status = IEEE80211_SKB_RXCB(rx->skb);
- if (sdata->vif.type == NL80211_IFTYPE_STATION &&
- cfg80211_rx_action(rx->sdata->dev, status->freq,
+ if (cfg80211_rx_action(rx->sdata->dev, status->freq,
rx->skb->data, rx->skb->len,
GFP_ATOMIC))
goto handled;
@@ -2052,11 +2056,11 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
nskb = skb_copy_expand(rx->skb, local->hw.extra_tx_headroom, 0,
GFP_ATOMIC);
if (nskb) {
- struct ieee80211_mgmt *mgmt = (void *)nskb->data;
+ struct ieee80211_mgmt *nmgmt = (void *)nskb->data;
- mgmt->u.action.category |= 0x80;
- memcpy(mgmt->da, mgmt->sa, ETH_ALEN);
- memcpy(mgmt->sa, rx->sdata->vif.addr, ETH_ALEN);
+ nmgmt->u.action.category |= 0x80;
+ memcpy(nmgmt->da, nmgmt->sa, ETH_ALEN);
+ memcpy(nmgmt->sa, rx->sdata->vif.addr, ETH_ALEN);
memset(nskb->cb, 0, sizeof(nskb->cb));
@@ -2068,6 +2072,14 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
rx->sta->rx_packets++;
dev_kfree_skb(rx->skb);
return RX_QUEUED;
+
+ queue:
+ rx->skb->pkt_type = IEEE80211_SDATA_QUEUE_TYPE_FRAME;
+ skb_queue_tail(&sdata->skb_queue, rx->skb);
+ ieee80211_queue_work(&local->hw, &sdata->work);
+ if (rx->sta)
+ rx->sta->rx_packets++;
+ return RX_QUEUED;
}
static ieee80211_rx_result debug_noinline
@@ -2075,10 +2087,15 @@ ieee80211_rx_h_mgmt(struct ieee80211_rx_data *rx)
{
struct ieee80211_sub_if_data *sdata = rx->sdata;
ieee80211_rx_result rxs;
+ struct ieee80211_mgmt *mgmt = (void *)rx->skb->data;
+ __le16 stype;
if (!(rx->flags & IEEE80211_RX_RA_MATCH))
return RX_DROP_MONITOR;
+ if (rx->skb->len < 24)
+ return RX_DROP_MONITOR;
+
if (ieee80211_drop_unencrypted_mgmt(rx))
return RX_DROP_UNUSABLE;
@@ -2086,16 +2103,42 @@ ieee80211_rx_h_mgmt(struct ieee80211_rx_data *rx)
if (rxs != RX_CONTINUE)
return rxs;
- if (ieee80211_vif_is_mesh(&sdata->vif))
- return ieee80211_mesh_rx_mgmt(sdata, rx->skb);
+ stype = mgmt->frame_control & cpu_to_le16(IEEE80211_FCTL_STYPE);
- if (sdata->vif.type == NL80211_IFTYPE_ADHOC)
- return ieee80211_ibss_rx_mgmt(sdata, rx->skb);
+ if (!ieee80211_vif_is_mesh(&sdata->vif) &&
+ sdata->vif.type != NL80211_IFTYPE_ADHOC &&
+ sdata->vif.type != NL80211_IFTYPE_STATION)
+ return RX_DROP_MONITOR;
+
+ switch (stype) {
+ case cpu_to_le16(IEEE80211_STYPE_BEACON):
+ case cpu_to_le16(IEEE80211_STYPE_PROBE_RESP):
+ /* process for all: mesh, mlme, ibss */
+ break;
+ case cpu_to_le16(IEEE80211_STYPE_DEAUTH):
+ case cpu_to_le16(IEEE80211_STYPE_DISASSOC):
+ /* process only for station */
+ if (sdata->vif.type != NL80211_IFTYPE_STATION)
+ return RX_DROP_MONITOR;
+ break;
+ case cpu_to_le16(IEEE80211_STYPE_PROBE_REQ):
+ case cpu_to_le16(IEEE80211_STYPE_AUTH):
+ /* process only for ibss */
+ if (sdata->vif.type != NL80211_IFTYPE_ADHOC)
+ return RX_DROP_MONITOR;
+ break;
+ default:
+ return RX_DROP_MONITOR;
+ }
- if (sdata->vif.type == NL80211_IFTYPE_STATION)
- return ieee80211_sta_rx_mgmt(sdata, rx->skb);
+ /* queue up frame and kick off work to process it */
+ rx->skb->pkt_type = IEEE80211_SDATA_QUEUE_TYPE_FRAME;
+ skb_queue_tail(&sdata->skb_queue, rx->skb);
+ ieee80211_queue_work(&rx->local->hw, &sdata->work);
+ if (rx->sta)
+ rx->sta->rx_packets++;
- return RX_DROP_MONITOR;
+ return RX_QUEUED;
}
static void ieee80211_rx_michael_mic_report(struct ieee80211_hdr *hdr,
@@ -2151,7 +2194,7 @@ static void ieee80211_rx_cooked_monitor(struct ieee80211_rx_data *rx,
u8 rate_or_pad;
__le16 chan_freq;
__le16 chan_flags;
- } __attribute__ ((packed)) *rthdr;
+ } __packed *rthdr;
struct sk_buff *skb = rx->skb, *skb2;
struct net_device *prev_dev = NULL;
struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
@@ -2201,7 +2244,7 @@ static void ieee80211_rx_cooked_monitor(struct ieee80211_rx_data *rx,
skb2 = skb_clone(skb, GFP_ATOMIC);
if (skb2) {
skb2->dev = prev_dev;
- netif_rx(skb2);
+ netif_receive_skb(skb2);
}
}
@@ -2212,7 +2255,7 @@ static void ieee80211_rx_cooked_monitor(struct ieee80211_rx_data *rx,
if (prev_dev) {
skb->dev = prev_dev;
- netif_rx(skb);
+ netif_receive_skb(skb);
skb = NULL;
} else
goto out_free_skb;
diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c
index e1b0be7a57b..41f20fb7e67 100644
--- a/net/mac80211/scan.c
+++ b/net/mac80211/scan.c
@@ -114,6 +114,10 @@ ieee80211_bss_info_update(struct ieee80211_local *local,
bss->dtim_period = tim_ie->dtim_period;
}
+ /* If the beacon had no TIM IE, or it was invalid, use 1 */
+ if (beacon && !bss->dtim_period)
+ bss->dtim_period = 1;
+
/* replace old supported rates if we get new values */
srlen = 0;
if (elems->supp_rates) {
@@ -734,7 +738,7 @@ int ieee80211_request_internal_scan(struct ieee80211_sub_if_data *sdata,
{
struct ieee80211_local *local = sdata->local;
int ret = -EBUSY;
- enum nl80211_band band;
+ enum ieee80211_band band;
mutex_lock(&local->scan_mtx);
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c
index ba9360a475b..6d86f0c1ad0 100644
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
@@ -235,6 +235,8 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata,
spin_lock_init(&sta->lock);
spin_lock_init(&sta->flaglock);
INIT_WORK(&sta->drv_unblock_wk, sta_unblock);
+ INIT_WORK(&sta->ampdu_mlme.work, ieee80211_ba_session_work);
+ mutex_init(&sta->ampdu_mlme.mtx);
memcpy(sta->sta.addr, addr, ETH_ALEN);
sta->local = local;
@@ -246,14 +248,12 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata,
}
for (i = 0; i < STA_TID_NUM; i++) {
- /* timer_to_tid must be initialized with identity mapping to
- * enable session_timer's data differentiation. refer to
- * sta_rx_agg_session_timer_expired for useage */
+ /*
+ * timer_to_tid must be initialized with identity mapping
+ * to enable session_timer's data differentiation. See
+ * sta_rx_agg_session_timer_expired for usage.
+ */
sta->timer_to_tid[i] = i;
- /* tx */
- sta->ampdu_mlme.tid_state_tx[i] = HT_AGG_STATE_IDLE;
- sta->ampdu_mlme.tid_tx[i] = NULL;
- sta->ampdu_mlme.addba_req_num[i] = 0;
}
skb_queue_head_init(&sta->ps_tx_buf);
skb_queue_head_init(&sta->tx_filtered);
@@ -647,15 +647,7 @@ static int __must_check __sta_info_destroy(struct sta_info *sta)
return ret;
if (sta->key) {
- ieee80211_key_free(sta->key);
- /*
- * We have only unlinked the key, and actually destroying it
- * may mean it is removed from hardware which requires that
- * the key->sta pointer is still valid, so flush the key todo
- * list here.
- */
- ieee80211_key_todo();
-
+ ieee80211_key_free(local, sta->key);
WARN_ON(sta->key);
}
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h
index df9d45544ca..54262e72376 100644
--- a/net/mac80211/sta_info.h
+++ b/net/mac80211/sta_info.h
@@ -42,9 +42,6 @@
* be in the queues
* @WLAN_STA_PSPOLL: Station sent PS-poll while driver was keeping
* station in power-save mode, reply when the driver unblocks.
- * @WLAN_STA_DISASSOC: Disassociation in progress.
- * This is used to reject TX BA session requests when disassociation
- * is in progress.
*/
enum ieee80211_sta_info_flags {
WLAN_STA_AUTH = 1<<0,
@@ -60,38 +57,44 @@ enum ieee80211_sta_info_flags {
WLAN_STA_BLOCK_BA = 1<<11,
WLAN_STA_PS_DRIVER = 1<<12,
WLAN_STA_PSPOLL = 1<<13,
- WLAN_STA_DISASSOC = 1<<14,
};
#define STA_TID_NUM 16
#define ADDBA_RESP_INTERVAL HZ
-#define HT_AGG_MAX_RETRIES (0x3)
+#define HT_AGG_MAX_RETRIES 0x3
-#define HT_AGG_STATE_INITIATOR_SHIFT (4)
-
-#define HT_ADDBA_REQUESTED_MSK BIT(0)
-#define HT_ADDBA_DRV_READY_MSK BIT(1)
-#define HT_ADDBA_RECEIVED_MSK BIT(2)
-#define HT_AGG_STATE_REQ_STOP_BA_MSK BIT(3)
-#define HT_AGG_STATE_INITIATOR_MSK BIT(HT_AGG_STATE_INITIATOR_SHIFT)
-#define HT_AGG_STATE_IDLE (0x0)
-#define HT_AGG_STATE_OPERATIONAL (HT_ADDBA_REQUESTED_MSK | \
- HT_ADDBA_DRV_READY_MSK | \
- HT_ADDBA_RECEIVED_MSK)
+#define HT_AGG_STATE_DRV_READY 0
+#define HT_AGG_STATE_RESPONSE_RECEIVED 1
+#define HT_AGG_STATE_OPERATIONAL 2
+#define HT_AGG_STATE_STOPPING 3
+#define HT_AGG_STATE_WANT_START 4
+#define HT_AGG_STATE_WANT_STOP 5
/**
* struct tid_ampdu_tx - TID aggregation information (Tx).
*
+ * @rcu_head: rcu head for freeing structure
* @addba_resp_timer: timer for peer's response to addba request
* @pending: pending frames queue -- use sta's spinlock to protect
- * @ssn: Starting Sequence Number expected to be aggregated.
* @dialog_token: dialog token for aggregation session
+ * @state: session state (see above)
+ * @stop_initiator: initiator of a session stop
+ *
+ * This structure is protected by RCU and the per-station
+ * spinlock. Assignments to the array holding it must hold
+ * the spinlock, only the TX path can access it under RCU
+ * lock-free if, and only if, the state has the flag
+ * %HT_AGG_STATE_OPERATIONAL set. Otherwise, the TX path
+ * must also acquire the spinlock and re-check the state,
+ * see comments in the tx code touching it.
*/
struct tid_ampdu_tx {
+ struct rcu_head rcu_head;
struct timer_list addba_resp_timer;
struct sk_buff_head pending;
- u16 ssn;
+ unsigned long state;
u8 dialog_token;
+ u8 stop_initiator;
};
/**
@@ -106,8 +109,18 @@ struct tid_ampdu_tx {
* @buf_size: buffer size for incoming A-MPDUs
* @timeout: reset timer value (in TUs).
* @dialog_token: dialog token for aggregation session
+ * @rcu_head: RCU head used for freeing this struct
+ *
+ * This structure is protected by RCU and the per-station
+ * spinlock. Assignments to the array holding it must hold
+ * the spinlock, only the RX path can access it under RCU
+ * lock-free. The RX path, since it is single-threaded,
+ * can even modify the structure without locking since the
+ * only other modifications to it are done when the struct
+ * can not yet or no longer be found by the RX path.
*/
struct tid_ampdu_rx {
+ struct rcu_head rcu_head;
struct sk_buff **reorder_buf;
unsigned long *reorder_time;
struct timer_list session_timer;
@@ -120,6 +133,32 @@ struct tid_ampdu_rx {
};
/**
+ * struct sta_ampdu_mlme - STA aggregation information.
+ *
+ * @tid_rx: aggregation info for Rx per TID -- RCU protected
+ * @tid_tx: aggregation info for Tx per TID
+ * @addba_req_num: number of times addBA request has been sent.
+ * @dialog_token_allocator: dialog token enumerator for each new session;
+ * @work: work struct for starting/stopping aggregation
+ * @tid_rx_timer_expired: bitmap indicating on which TIDs the
+ * RX timer expired until the work for it runs
+ * @mtx: mutex to protect all TX data (except non-NULL assignments
+ * to tid_tx[idx], which are protected by the sta spinlock)
+ */
+struct sta_ampdu_mlme {
+ struct mutex mtx;
+ /* rx */
+ struct tid_ampdu_rx *tid_rx[STA_TID_NUM];
+ unsigned long tid_rx_timer_expired[BITS_TO_LONGS(STA_TID_NUM)];
+ /* tx */
+ struct work_struct work;
+ struct tid_ampdu_tx *tid_tx[STA_TID_NUM];
+ u8 addba_req_num[STA_TID_NUM];
+ u8 dialog_token_allocator;
+};
+
+
+/**
* enum plink_state - state of a mesh peer link finite state machine
*
* @PLINK_LISTEN: initial state, considered the implicit state of non existant
@@ -143,28 +182,6 @@ enum plink_state {
};
/**
- * struct sta_ampdu_mlme - STA aggregation information.
- *
- * @tid_active_rx: TID's state in Rx session state machine.
- * @tid_rx: aggregation info for Rx per TID
- * @tid_state_tx: TID's state in Tx session state machine.
- * @tid_tx: aggregation info for Tx per TID
- * @addba_req_num: number of times addBA request has been sent.
- * @dialog_token_allocator: dialog token enumerator for each new session;
- */
-struct sta_ampdu_mlme {
- /* rx */
- bool tid_active_rx[STA_TID_NUM];
- struct tid_ampdu_rx *tid_rx[STA_TID_NUM];
- /* tx */
- u8 tid_state_tx[STA_TID_NUM];
- struct tid_ampdu_tx *tid_tx[STA_TID_NUM];
- u8 addba_req_num[STA_TID_NUM];
- u8 dialog_token_allocator;
-};
-
-
-/**
* struct sta_info - STA information
*
* This structure collects information about a station that
@@ -410,20 +427,20 @@ void for_each_sta_info_type_check(struct ieee80211_local *local,
{
}
-#define for_each_sta_info(local, _addr, sta, nxt) \
+#define for_each_sta_info(local, _addr, _sta, nxt) \
for ( /* initialise loop */ \
- sta = rcu_dereference(local->sta_hash[STA_HASH(_addr)]),\
- nxt = sta ? rcu_dereference(sta->hnext) : NULL; \
+ _sta = rcu_dereference(local->sta_hash[STA_HASH(_addr)]),\
+ nxt = _sta ? rcu_dereference(_sta->hnext) : NULL; \
/* typecheck */ \
- for_each_sta_info_type_check(local, (_addr), sta, nxt), \
+ for_each_sta_info_type_check(local, (_addr), _sta, nxt),\
/* continue condition */ \
- sta; \
+ _sta; \
/* advance loop */ \
- sta = nxt, \
- nxt = sta ? rcu_dereference(sta->hnext) : NULL \
+ _sta = nxt, \
+ nxt = _sta ? rcu_dereference(_sta->hnext) : NULL \
) \
/* compare address and run code only if it matches */ \
- if (memcmp(sta->sta.addr, (_addr), ETH_ALEN) == 0)
+ if (memcmp(_sta->sta.addr, (_addr), ETH_ALEN) == 0)
/*
* Get STA info by index, BROKEN!
diff --git a/net/mac80211/status.c b/net/mac80211/status.c
index 94613af009f..10caec5ea8f 100644
--- a/net/mac80211/status.c
+++ b/net/mac80211/status.c
@@ -47,7 +47,7 @@ static void ieee80211_handle_filtered_frame(struct ieee80211_local *local,
/*
* This skb 'survived' a round-trip through the driver, and
* hopefully the driver didn't mangle it too badly. However,
- * we can definitely not rely on the the control information
+ * we can definitely not rely on the control information
* being correct. Clear it so we don't get junk there, and
* indicate that it needs new processing, but must not be
* modified/encrypted again.
@@ -377,7 +377,7 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
skb2 = skb_clone(skb, GFP_ATOMIC);
if (skb2) {
skb2->dev = prev_dev;
- netif_rx(skb2);
+ netif_receive_skb(skb2);
}
}
@@ -386,7 +386,7 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
}
if (prev_dev) {
skb->dev = prev_dev;
- netif_rx(skb);
+ netif_receive_skb(skb);
skb = NULL;
}
rcu_read_unlock();
diff --git a/net/mac80211/tkip.c b/net/mac80211/tkip.c
index 7ef491e9d66..e840c9cd46d 100644
--- a/net/mac80211/tkip.c
+++ b/net/mac80211/tkip.c
@@ -202,9 +202,9 @@ EXPORT_SYMBOL(ieee80211_get_tkip_key);
* @payload_len is the length of payload (_not_ including IV/ICV length).
* @ta is the transmitter addresses.
*/
-void ieee80211_tkip_encrypt_data(struct crypto_blkcipher *tfm,
- struct ieee80211_key *key,
- u8 *pos, size_t payload_len, u8 *ta)
+int ieee80211_tkip_encrypt_data(struct crypto_blkcipher *tfm,
+ struct ieee80211_key *key,
+ u8 *pos, size_t payload_len, u8 *ta)
{
u8 rc4key[16];
struct tkip_ctx *ctx = &key->u.tkip.tx;
@@ -216,7 +216,7 @@ void ieee80211_tkip_encrypt_data(struct crypto_blkcipher *tfm,
tkip_mixing_phase2(tk, ctx, ctx->iv16, rc4key);
- ieee80211_wep_encrypt_data(tfm, rc4key, 16, pos, payload_len);
+ return ieee80211_wep_encrypt_data(tfm, rc4key, 16, pos, payload_len);
}
/* Decrypt packet payload with TKIP using @key. @pos is a pointer to the
diff --git a/net/mac80211/tkip.h b/net/mac80211/tkip.h
index d4714383f5f..7e83dee976f 100644
--- a/net/mac80211/tkip.h
+++ b/net/mac80211/tkip.h
@@ -15,7 +15,7 @@
u8 *ieee80211_tkip_add_iv(u8 *pos, struct ieee80211_key *key, u16 iv16);
-void ieee80211_tkip_encrypt_data(struct crypto_blkcipher *tfm,
+int ieee80211_tkip_encrypt_data(struct crypto_blkcipher *tfm,
struct ieee80211_key *key,
u8 *pos, size_t payload_len, u8 *ta);
enum {
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index 680bcb7093d..c54db966926 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -576,17 +576,6 @@ ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx)
}
static ieee80211_tx_result debug_noinline
-ieee80211_tx_h_sta(struct ieee80211_tx_data *tx)
-{
- struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb);
-
- if (tx->sta && tx->sta->uploaded)
- info->control.sta = &tx->sta->sta;
-
- return TX_CONTINUE;
-}
-
-static ieee80211_tx_result debug_noinline
ieee80211_tx_h_rate_ctrl(struct ieee80211_tx_data *tx)
{
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb);
@@ -1092,6 +1081,59 @@ static bool __ieee80211_parse_tx_radiotap(struct ieee80211_tx_data *tx,
return true;
}
+static bool ieee80211_tx_prep_agg(struct ieee80211_tx_data *tx,
+ struct sk_buff *skb,
+ struct ieee80211_tx_info *info,
+ struct tid_ampdu_tx *tid_tx,
+ int tid)
+{
+ bool queued = false;
+
+ if (test_bit(HT_AGG_STATE_OPERATIONAL, &tid_tx->state)) {
+ info->flags |= IEEE80211_TX_CTL_AMPDU;
+ } else if (test_bit(HT_AGG_STATE_WANT_START, &tid_tx->state)) {
+ /*
+ * nothing -- this aggregation session is being started
+ * but that might still fail with the driver
+ */
+ } else {
+ spin_lock(&tx->sta->lock);
+ /*
+ * Need to re-check now, because we may get here
+ *
+ * 1) in the window during which the setup is actually
+ * already done, but not marked yet because not all
+ * packets are spliced over to the driver pending
+ * queue yet -- if this happened we acquire the lock
+ * either before or after the splice happens, but
+ * need to recheck which of these cases happened.
+ *
+ * 2) during session teardown, if the OPERATIONAL bit
+ * was cleared due to the teardown but the pointer
+ * hasn't been assigned NULL yet (or we loaded it
+ * before it was assigned) -- in this case it may
+ * now be NULL which means we should just let the
+ * packet pass through because splicing the frames
+ * back is already done.
+ */
+ tid_tx = tx->sta->ampdu_mlme.tid_tx[tid];
+
+ if (!tid_tx) {
+ /* do nothing, let packet pass through */
+ } else if (test_bit(HT_AGG_STATE_OPERATIONAL, &tid_tx->state)) {
+ info->flags |= IEEE80211_TX_CTL_AMPDU;
+ } else {
+ queued = true;
+ info->control.vif = &tx->sdata->vif;
+ info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING;
+ __skb_queue_tail(&tid_tx->pending, skb);
+ }
+ spin_unlock(&tx->sta->lock);
+ }
+
+ return queued;
+}
+
/*
* initialises @tx
*/
@@ -1104,8 +1146,7 @@ ieee80211_tx_prepare(struct ieee80211_sub_if_data *sdata,
struct ieee80211_hdr *hdr;
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
int hdrlen, tid;
- u8 *qc, *state;
- bool queued = false;
+ u8 *qc;
memset(tx, 0, sizeof(*tx));
tx->skb = skb;
@@ -1157,35 +1198,16 @@ ieee80211_tx_prepare(struct ieee80211_sub_if_data *sdata,
qc = ieee80211_get_qos_ctl(hdr);
tid = *qc & IEEE80211_QOS_CTL_TID_MASK;
- spin_lock(&tx->sta->lock);
- /*
- * XXX: This spinlock could be fairly expensive, but see the
- * comment in agg-tx.c:ieee80211_agg_tx_operational().
- * One way to solve this would be to do something RCU-like
- * for managing the tid_tx struct and using atomic bitops
- * for the actual state -- by introducing an actual
- * 'operational' bit that would be possible. It would
- * require changing ieee80211_agg_tx_operational() to
- * set that bit, and changing the way tid_tx is managed
- * everywhere, including races between that bit and
- * tid_tx going away (tid_tx being added can be easily
- * committed to memory before the 'operational' bit).
- */
- tid_tx = tx->sta->ampdu_mlme.tid_tx[tid];
- state = &tx->sta->ampdu_mlme.tid_state_tx[tid];
- if (*state == HT_AGG_STATE_OPERATIONAL) {
- info->flags |= IEEE80211_TX_CTL_AMPDU;
- } else if (*state != HT_AGG_STATE_IDLE) {
- /* in progress */
- queued = true;
- info->control.vif = &sdata->vif;
- info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING;
- __skb_queue_tail(&tid_tx->pending, skb);
- }
- spin_unlock(&tx->sta->lock);
+ tid_tx = rcu_dereference(tx->sta->ampdu_mlme.tid_tx[tid]);
+ if (tid_tx) {
+ bool queued;
- if (unlikely(queued))
- return TX_QUEUED;
+ queued = ieee80211_tx_prep_agg(tx, skb, info,
+ tid_tx, tid);
+
+ if (unlikely(queued))
+ return TX_QUEUED;
+ }
}
if (is_multicast_ether_addr(hdr->addr1)) {
@@ -1274,6 +1296,11 @@ static int __ieee80211_tx(struct ieee80211_local *local,
break;
}
+ if (sta && sta->uploaded)
+ info->control.sta = &sta->sta;
+ else
+ info->control.sta = NULL;
+
ret = drv_tx(local, skb);
if (WARN_ON(ret != NETDEV_TX_OK && skb->len != len)) {
dev_kfree_skb(skb);
@@ -1313,7 +1340,6 @@ static int invoke_tx_handlers(struct ieee80211_tx_data *tx)
CALL_TXH(ieee80211_tx_h_check_assoc);
CALL_TXH(ieee80211_tx_h_ps_buf);
CALL_TXH(ieee80211_tx_h_select_key);
- CALL_TXH(ieee80211_tx_h_sta);
if (!(tx->local->hw.flags & IEEE80211_HW_HAS_RATE_CONTROL))
CALL_TXH(ieee80211_tx_h_rate_ctrl);
@@ -1909,11 +1935,13 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
h_pos += encaps_len;
}
+#ifdef CONFIG_MAC80211_MESH
if (meshhdrlen > 0) {
memcpy(skb_push(skb, meshhdrlen), &mesh_hdr, meshhdrlen);
nh_pos += meshhdrlen;
h_pos += meshhdrlen;
}
+#endif
if (ieee80211_is_data_qos(fc)) {
__le16 *qos_control;
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index 5b79d552780..748387d45bc 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -803,8 +803,12 @@ void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata)
/* after reinitialize QoS TX queues setting to default,
* disable QoS at all */
- local->hw.conf.flags &= ~IEEE80211_CONF_QOS;
- drv_config(local, IEEE80211_CONF_CHANGE_QOS);
+
+ if (sdata->vif.type != NL80211_IFTYPE_MONITOR) {
+ sdata->vif.bss_conf.qos =
+ sdata->vif.type != NL80211_IFTYPE_STATION;
+ ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_QOS);
+ }
}
void ieee80211_sta_def_wmm_params(struct ieee80211_sub_if_data *sdata,
@@ -1138,18 +1142,6 @@ int ieee80211_reconfig(struct ieee80211_local *local)
}
mutex_unlock(&local->sta_mtx);
- /* Clear Suspend state so that ADDBA requests can be processed */
-
- rcu_read_lock();
-
- if (hw->flags & IEEE80211_HW_AMPDU_AGGREGATION) {
- list_for_each_entry_rcu(sta, &local->sta_list, list) {
- clear_sta_flags(sta, WLAN_STA_BLOCK_BA);
- }
- }
-
- rcu_read_unlock();
-
/* setup RTS threshold */
drv_set_rts_threshold(local, hw->wiphy->rts_threshold);
@@ -1173,7 +1165,8 @@ int ieee80211_reconfig(struct ieee80211_local *local)
BSS_CHANGED_BASIC_RATES |
BSS_CHANGED_BEACON_INT |
BSS_CHANGED_BSSID |
- BSS_CHANGED_CQM;
+ BSS_CHANGED_CQM |
+ BSS_CHANGED_QOS;
switch (sdata->vif.type) {
case NL80211_IFTYPE_STATION:
@@ -1202,13 +1195,26 @@ int ieee80211_reconfig(struct ieee80211_local *local)
}
}
- rcu_read_lock();
+ /*
+ * Clear the WLAN_STA_BLOCK_BA flag so new aggregation
+ * sessions can be established after a resume.
+ *
+ * Also tear down aggregation sessions since reconfiguring
+ * them in a hardware restart scenario is not easily done
+ * right now, and the hardware will have lost information
+ * about the sessions, but we and the AP still think they
+ * are active. This is really a workaround though.
+ */
if (hw->flags & IEEE80211_HW_AMPDU_AGGREGATION) {
- list_for_each_entry_rcu(sta, &local->sta_list, list) {
+ mutex_lock(&local->sta_mtx);
+
+ list_for_each_entry(sta, &local->sta_list, list) {
ieee80211_sta_tear_down_BA_sessions(sta);
+ clear_sta_flags(sta, WLAN_STA_BLOCK_BA);
}
+
+ mutex_unlock(&local->sta_mtx);
}
- rcu_read_unlock();
/* add back keys */
list_for_each_entry(sdata, &local->interfaces, list)
diff --git a/net/mac80211/wep.c b/net/mac80211/wep.c
index 5f3a4113bda..9ebc8d8a1f5 100644
--- a/net/mac80211/wep.c
+++ b/net/mac80211/wep.c
@@ -32,13 +32,16 @@ int ieee80211_wep_init(struct ieee80211_local *local)
local->wep_tx_tfm = crypto_alloc_blkcipher("ecb(arc4)", 0,
CRYPTO_ALG_ASYNC);
- if (IS_ERR(local->wep_tx_tfm))
+ if (IS_ERR(local->wep_tx_tfm)) {
+ local->wep_rx_tfm = ERR_PTR(-EINVAL);
return PTR_ERR(local->wep_tx_tfm);
+ }
local->wep_rx_tfm = crypto_alloc_blkcipher("ecb(arc4)", 0,
CRYPTO_ALG_ASYNC);
if (IS_ERR(local->wep_rx_tfm)) {
crypto_free_blkcipher(local->wep_tx_tfm);
+ local->wep_tx_tfm = ERR_PTR(-EINVAL);
return PTR_ERR(local->wep_rx_tfm);
}
@@ -47,8 +50,10 @@ int ieee80211_wep_init(struct ieee80211_local *local)
void ieee80211_wep_free(struct ieee80211_local *local)
{
- crypto_free_blkcipher(local->wep_tx_tfm);
- crypto_free_blkcipher(local->wep_rx_tfm);
+ if (!IS_ERR(local->wep_tx_tfm))
+ crypto_free_blkcipher(local->wep_tx_tfm);
+ if (!IS_ERR(local->wep_rx_tfm))
+ crypto_free_blkcipher(local->wep_rx_tfm);
}
static inline bool ieee80211_wep_weak_iv(u32 iv, int keylen)
@@ -122,19 +127,24 @@ static void ieee80211_wep_remove_iv(struct ieee80211_local *local,
/* Perform WEP encryption using given key. data buffer must have tailroom
* for 4-byte ICV. data_len must not include this ICV. Note: this function
* does _not_ add IV. data = RC4(data | CRC32(data)) */
-void ieee80211_wep_encrypt_data(struct crypto_blkcipher *tfm, u8 *rc4key,
- size_t klen, u8 *data, size_t data_len)
+int ieee80211_wep_encrypt_data(struct crypto_blkcipher *tfm, u8 *rc4key,
+ size_t klen, u8 *data, size_t data_len)
{
struct blkcipher_desc desc = { .tfm = tfm };
struct scatterlist sg;
__le32 icv;
+ if (IS_ERR(tfm))
+ return -1;
+
icv = cpu_to_le32(~crc32_le(~0, data, data_len));
put_unaligned(icv, (__le32 *)(data + data_len));
crypto_blkcipher_setkey(tfm, rc4key, klen);
sg_init_one(&sg, data, data_len + WEP_ICV_LEN);
crypto_blkcipher_encrypt(&desc, &sg, &sg, sg.length);
+
+ return 0;
}
@@ -168,10 +178,8 @@ int ieee80211_wep_encrypt(struct ieee80211_local *local,
/* Add room for ICV */
skb_put(skb, WEP_ICV_LEN);
- ieee80211_wep_encrypt_data(local->wep_tx_tfm, rc4key, keylen + 3,
- iv + WEP_IV_LEN, len);
-
- return 0;
+ return ieee80211_wep_encrypt_data(local->wep_tx_tfm, rc4key, keylen + 3,
+ iv + WEP_IV_LEN, len);
}
@@ -185,6 +193,9 @@ int ieee80211_wep_decrypt_data(struct crypto_blkcipher *tfm, u8 *rc4key,
struct scatterlist sg;
__le32 crc;
+ if (IS_ERR(tfm))
+ return -1;
+
crypto_blkcipher_setkey(tfm, rc4key, klen);
sg_init_one(&sg, data, data_len + WEP_ICV_LEN);
crypto_blkcipher_decrypt(&desc, &sg, &sg, sg.length);
diff --git a/net/mac80211/wep.h b/net/mac80211/wep.h
index fe29d7e5759..58654ee3351 100644
--- a/net/mac80211/wep.h
+++ b/net/mac80211/wep.h
@@ -18,7 +18,7 @@
int ieee80211_wep_init(struct ieee80211_local *local);
void ieee80211_wep_free(struct ieee80211_local *local);
-void ieee80211_wep_encrypt_data(struct crypto_blkcipher *tfm, u8 *rc4key,
+int ieee80211_wep_encrypt_data(struct crypto_blkcipher *tfm, u8 *rc4key,
size_t klen, u8 *data, size_t data_len);
int ieee80211_wep_encrypt(struct ieee80211_local *local,
struct sk_buff *skb,
diff --git a/net/mac80211/work.c b/net/mac80211/work.c
index b025dc7bb0f..81d4ad64184 100644
--- a/net/mac80211/work.c
+++ b/net/mac80211/work.c
@@ -560,6 +560,22 @@ ieee80211_remain_on_channel_timeout(struct ieee80211_work *wk)
return WORK_ACT_TIMEOUT;
}
+static enum work_action __must_check
+ieee80211_assoc_beacon_wait(struct ieee80211_work *wk)
+{
+ if (wk->started)
+ return WORK_ACT_TIMEOUT;
+
+ /*
+ * Wait up to one beacon interval ...
+ * should this be more if we miss one?
+ */
+ printk(KERN_DEBUG "%s: waiting for beacon from %pM\n",
+ wk->sdata->name, wk->filter_ta);
+ wk->timeout = TU_TO_EXP_TIME(wk->assoc.bss->beacon_interval);
+ return WORK_ACT_NONE;
+}
+
static void ieee80211_auth_challenge(struct ieee80211_work *wk,
struct ieee80211_mgmt *mgmt,
size_t len)
@@ -709,6 +725,25 @@ ieee80211_rx_mgmt_probe_resp(struct ieee80211_work *wk,
return WORK_ACT_DONE;
}
+static enum work_action __must_check
+ieee80211_rx_mgmt_beacon(struct ieee80211_work *wk,
+ struct ieee80211_mgmt *mgmt, size_t len)
+{
+ struct ieee80211_sub_if_data *sdata = wk->sdata;
+ struct ieee80211_local *local = sdata->local;
+
+ ASSERT_WORK_MTX(local);
+
+ if (wk->type != IEEE80211_WORK_ASSOC_BEACON_WAIT)
+ return WORK_ACT_MISMATCH;
+
+ if (len < 24 + 12)
+ return WORK_ACT_NONE;
+
+ printk(KERN_DEBUG "%s: beacon received\n", sdata->name);
+ return WORK_ACT_DONE;
+}
+
static void ieee80211_work_rx_queued_mgmt(struct ieee80211_local *local,
struct sk_buff *skb)
{
@@ -731,6 +766,7 @@ static void ieee80211_work_rx_queued_mgmt(struct ieee80211_local *local,
case IEEE80211_WORK_DIRECT_PROBE:
case IEEE80211_WORK_AUTH:
case IEEE80211_WORK_ASSOC:
+ case IEEE80211_WORK_ASSOC_BEACON_WAIT:
bssid = wk->filter_ta;
break;
default:
@@ -745,6 +781,9 @@ static void ieee80211_work_rx_queued_mgmt(struct ieee80211_local *local,
continue;
switch (fc & IEEE80211_FCTL_STYPE) {
+ case IEEE80211_STYPE_BEACON:
+ rma = ieee80211_rx_mgmt_beacon(wk, mgmt, skb->len);
+ break;
case IEEE80211_STYPE_PROBE_RESP:
rma = ieee80211_rx_mgmt_probe_resp(wk, mgmt, skb->len,
rx_status);
@@ -840,7 +879,7 @@ static void ieee80211_work_work(struct work_struct *work)
/*
* ieee80211_queue_work() should have picked up most cases,
- * here we'll pick the the rest.
+ * here we'll pick the rest.
*/
if (WARN(local->suspended, "work scheduled while going to suspend\n"))
return;
@@ -916,6 +955,9 @@ static void ieee80211_work_work(struct work_struct *work)
case IEEE80211_WORK_REMAIN_ON_CHANNEL:
rma = ieee80211_remain_on_channel_timeout(wk);
break;
+ case IEEE80211_WORK_ASSOC_BEACON_WAIT:
+ rma = ieee80211_assoc_beacon_wait(wk);
+ break;
}
wk->started = started;
@@ -1065,6 +1107,7 @@ ieee80211_rx_result ieee80211_work_rx_mgmt(struct ieee80211_sub_if_data *sdata,
case IEEE80211_STYPE_PROBE_RESP:
case IEEE80211_STYPE_ASSOC_RESP:
case IEEE80211_STYPE_REASSOC_RESP:
+ case IEEE80211_STYPE_BEACON:
skb_queue_tail(&local->work_skb_queue, skb);
ieee80211_queue_work(&local->hw, &local->work_work);
return RX_QUEUED;
diff --git a/net/mac80211/wpa.c b/net/mac80211/wpa.c
index 0adbcc941ac..8d59d27d887 100644
--- a/net/mac80211/wpa.c
+++ b/net/mac80211/wpa.c
@@ -183,9 +183,8 @@ static int tkip_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb)
skb_put(skb, TKIP_ICV_LEN);
hdr = (struct ieee80211_hdr *) skb->data;
- ieee80211_tkip_encrypt_data(tx->local->wep_tx_tfm,
- key, pos, len, hdr->addr2);
- return 0;
+ return ieee80211_tkip_encrypt_data(tx->local->wep_tx_tfm,
+ key, pos, len, hdr->addr2);
}
@@ -436,6 +435,7 @@ ieee80211_crypto_ccmp_decrypt(struct ieee80211_rx_data *rx)
struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
u8 pn[CCMP_PN_LEN];
int data_len;
+ int queue;
hdrlen = ieee80211_hdrlen(hdr->frame_control);
@@ -453,7 +453,10 @@ ieee80211_crypto_ccmp_decrypt(struct ieee80211_rx_data *rx)
ccmp_hdr2pn(pn, skb->data + hdrlen);
- if (memcmp(pn, key->u.ccmp.rx_pn[rx->queue], CCMP_PN_LEN) <= 0) {
+ queue = ieee80211_is_mgmt(hdr->frame_control) ?
+ NUM_RX_DATA_QUEUES : rx->queue;
+
+ if (memcmp(pn, key->u.ccmp.rx_pn[queue], CCMP_PN_LEN) <= 0) {
key->u.ccmp.replays++;
return RX_DROP_UNUSABLE;
}
@@ -470,7 +473,7 @@ ieee80211_crypto_ccmp_decrypt(struct ieee80211_rx_data *rx)
return RX_DROP_UNUSABLE;
}
- memcpy(key->u.ccmp.rx_pn[rx->queue], pn, CCMP_PN_LEN);
+ memcpy(key->u.ccmp.rx_pn[queue], pn, CCMP_PN_LEN);
/* Remove CCMP header and MIC */
skb_trim(skb, skb->len - CCMP_MIC_LEN);
diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig
index 8593a77cfea..43288259f4a 100644
--- a/net/netfilter/Kconfig
+++ b/net/netfilter/Kconfig
@@ -40,27 +40,6 @@ config NF_CONNTRACK
if NF_CONNTRACK
-config NF_CT_ACCT
- bool "Connection tracking flow accounting"
- depends on NETFILTER_ADVANCED
- help
- If this option is enabled, the connection tracking code will
- keep per-flow packet and byte counters.
-
- Those counters can be used for flow-based accounting or the
- `connbytes' match.
-
- Please note that currently this option only sets a default state.
- You may change it at boot time with nf_conntrack.acct=0/1 kernel
- parameter or by loading the nf_conntrack module with acct=0/1.
-
- You may also disable/enable it on a running system with:
- sysctl net.netfilter.nf_conntrack_acct=0/1
-
- This option will be removed in 2.6.29.
-
- If unsure, say `N'.
-
config NF_CONNTRACK_MARK
bool 'Connection mark tracking support'
depends on NETFILTER_ADVANCED
@@ -347,6 +326,22 @@ config NETFILTER_XT_CONNMARK
comment "Xtables targets"
+config NETFILTER_XT_TARGET_CHECKSUM
+ tristate "CHECKSUM target support"
+ depends on IP_NF_MANGLE || IP6_NF_MANGLE
+ depends on NETFILTER_ADVANCED
+ ---help---
+ This option adds a `CHECKSUM' target, which can be used in the iptables mangle
+ table.
+
+ You can use this target to compute and fill in the checksum in
+ a packet that lacks a checksum. This is particularly useful,
+ if you need to work around old applications such as dhcp clients,
+ that do not work well with checksum offloads, but don't want to disable
+ checksum offload in your device.
+
+ To compile it as a module, choose M here. If unsure, say N.
+
config NETFILTER_XT_TARGET_CLASSIFY
tristate '"CLASSIFY" target support'
depends on NETFILTER_ADVANCED
@@ -424,6 +419,18 @@ config NETFILTER_XT_TARGET_HL
since you can easily create immortal packets that loop
forever on the network.
+config NETFILTER_XT_TARGET_IDLETIMER
+ tristate "IDLETIMER target support"
+ depends on NETFILTER_ADVANCED
+ help
+
+ This option adds the `IDLETIMER' target. Each matching packet
+ resets the timer associated with label specified when the rule is
+ added. When the timer expires, it triggers a sysfs notification.
+ The remaining time for expiration can be read via sysfs.
+
+ To compile it as a module, choose M here. If unsure, say N.
+
config NETFILTER_XT_TARGET_LED
tristate '"LED" target support'
depends on LEDS_CLASS && LEDS_TRIGGERS
@@ -503,7 +510,7 @@ config NETFILTER_XT_TARGET_RATEEST
To compile it as a module, choose M here. If unsure, say N.
config NETFILTER_XT_TARGET_TEE
- tristate '"TEE" - packet cloning to alternate destiantion'
+ tristate '"TEE" - packet cloning to alternate destination'
depends on NETFILTER_ADVANCED
depends on (IPV6 || IPV6=n)
depends on !NF_CONNTRACK || NF_CONNTRACK
@@ -618,7 +625,6 @@ config NETFILTER_XT_MATCH_CONNBYTES
tristate '"connbytes" per-connection counter match support'
depends on NF_CONNTRACK
depends on NETFILTER_ADVANCED
- select NF_CT_ACCT
help
This option adds a `connbytes' match, which allows you to match the
number of bytes and/or packets for each direction within a connection.
@@ -657,6 +663,15 @@ config NETFILTER_XT_MATCH_CONNTRACK
To compile it as a module, choose M here. If unsure, say N.
+config NETFILTER_XT_MATCH_CPU
+ tristate '"cpu" match support'
+ depends on NETFILTER_ADVANCED
+ help
+ CPU matching allows you to match packets based on the CPU
+ currently handling the packet.
+
+ To compile it as a module, choose M here. If unsure, say N.
+
config NETFILTER_XT_MATCH_DCCP
tristate '"dccp" protocol match support'
depends on NETFILTER_ADVANCED
@@ -736,6 +751,16 @@ config NETFILTER_XT_MATCH_IPRANGE
If unsure, say M.
+config NETFILTER_XT_MATCH_IPVS
+ tristate '"ipvs" match support'
+ depends on IP_VS
+ depends on NETFILTER_ADVANCED
+ depends on NF_CONNTRACK
+ help
+ This option allows you to match against IPVS properties of a packet.
+
+ If unsure, say N.
+
config NETFILTER_XT_MATCH_LENGTH
tristate '"length" match support'
depends on NETFILTER_ADVANCED
diff --git a/net/netfilter/Makefile b/net/netfilter/Makefile
index 14e3a8fd818..441050f3111 100644
--- a/net/netfilter/Makefile
+++ b/net/netfilter/Makefile
@@ -45,6 +45,7 @@ obj-$(CONFIG_NETFILTER_XT_MARK) += xt_mark.o
obj-$(CONFIG_NETFILTER_XT_CONNMARK) += xt_connmark.o
# targets
+obj-$(CONFIG_NETFILTER_XT_TARGET_CHECKSUM) += xt_CHECKSUM.o
obj-$(CONFIG_NETFILTER_XT_TARGET_CLASSIFY) += xt_CLASSIFY.o
obj-$(CONFIG_NETFILTER_XT_TARGET_CONNSECMARK) += xt_CONNSECMARK.o
obj-$(CONFIG_NETFILTER_XT_TARGET_CT) += xt_CT.o
@@ -61,6 +62,7 @@ obj-$(CONFIG_NETFILTER_XT_TARGET_TCPMSS) += xt_TCPMSS.o
obj-$(CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP) += xt_TCPOPTSTRIP.o
obj-$(CONFIG_NETFILTER_XT_TARGET_TEE) += xt_TEE.o
obj-$(CONFIG_NETFILTER_XT_TARGET_TRACE) += xt_TRACE.o
+obj-$(CONFIG_NETFILTER_XT_TARGET_IDLETIMER) += xt_IDLETIMER.o
# matches
obj-$(CONFIG_NETFILTER_XT_MATCH_CLUSTER) += xt_cluster.o
@@ -68,6 +70,7 @@ 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_CONNTRACK) += xt_conntrack.o
+obj-$(CONFIG_NETFILTER_XT_MATCH_CPU) += xt_cpu.o
obj-$(CONFIG_NETFILTER_XT_MATCH_DCCP) += xt_dccp.o
obj-$(CONFIG_NETFILTER_XT_MATCH_DSCP) += xt_dscp.o
obj-$(CONFIG_NETFILTER_XT_MATCH_ESP) += xt_esp.o
@@ -75,6 +78,7 @@ obj-$(CONFIG_NETFILTER_XT_MATCH_HASHLIMIT) += xt_hashlimit.o
obj-$(CONFIG_NETFILTER_XT_MATCH_HELPER) += xt_helper.o
obj-$(CONFIG_NETFILTER_XT_MATCH_HL) += xt_hl.o
obj-$(CONFIG_NETFILTER_XT_MATCH_IPRANGE) += xt_iprange.o
+obj-$(CONFIG_NETFILTER_XT_MATCH_IPVS) += xt_ipvs.o
obj-$(CONFIG_NETFILTER_XT_MATCH_LENGTH) += xt_length.o
obj-$(CONFIG_NETFILTER_XT_MATCH_LIMIT) += xt_limit.o
obj-$(CONFIG_NETFILTER_XT_MATCH_MAC) += xt_mac.o
diff --git a/net/netfilter/ipvs/Kconfig b/net/netfilter/ipvs/Kconfig
index 712ccad1334..46a77d5c388 100644
--- a/net/netfilter/ipvs/Kconfig
+++ b/net/netfilter/ipvs/Kconfig
@@ -3,7 +3,7 @@
#
menuconfig IP_VS
tristate "IP virtual server support"
- depends on NET && INET && NETFILTER
+ depends on NET && INET && NETFILTER && NF_CONNTRACK
---help---
IP Virtual Server support will let you build a high-performance
virtual server based on cluster of two or more real servers. This
@@ -26,7 +26,7 @@ if IP_VS
config IP_VS_IPV6
bool "IPv6 support for IPVS"
- depends on EXPERIMENTAL && (IPV6 = y || IP_VS = IPV6)
+ depends on IPV6 = y || IP_VS = IPV6
---help---
Add IPv6 support to IPVS. This is incomplete and might be dangerous.
@@ -87,19 +87,16 @@ config IP_VS_PROTO_UDP
protocol. Say Y if unsure.
config IP_VS_PROTO_AH_ESP
- bool
- depends on UNDEFINED
+ def_bool IP_VS_PROTO_ESP || IP_VS_PROTO_AH
config IP_VS_PROTO_ESP
bool "ESP load balancing support"
- select IP_VS_PROTO_AH_ESP
---help---
This option enables support for load balancing ESP (Encapsulation
Security Payload) transport protocol. Say Y if unsure.
config IP_VS_PROTO_AH
bool "AH load balancing support"
- select IP_VS_PROTO_AH_ESP
---help---
This option enables support for load balancing AH (Authentication
Header) transport protocol. Say Y if unsure.
@@ -238,7 +235,7 @@ comment 'IPVS application helper'
config IP_VS_FTP
tristate "FTP protocol helper"
- depends on IP_VS_PROTO_TCP
+ depends on IP_VS_PROTO_TCP && NF_NAT
---help---
FTP is a protocol that transfers IP address and/or port number in
the payload. In the virtual server via Network Address Translation,
diff --git a/net/netfilter/ipvs/ip_vs_app.c b/net/netfilter/ipvs/ip_vs_app.c
index 1cb0e834f8f..e76f87f4aca 100644
--- a/net/netfilter/ipvs/ip_vs_app.c
+++ b/net/netfilter/ipvs/ip_vs_app.c
@@ -569,49 +569,6 @@ static const struct file_operations ip_vs_app_fops = {
};
#endif
-
-/*
- * Replace a segment of data with a new segment
- */
-int ip_vs_skb_replace(struct sk_buff *skb, gfp_t pri,
- char *o_buf, int o_len, char *n_buf, int n_len)
-{
- int diff;
- int o_offset;
- int o_left;
-
- EnterFunction(9);
-
- diff = n_len - o_len;
- o_offset = o_buf - (char *)skb->data;
- /* The length of left data after o_buf+o_len in the skb data */
- o_left = skb->len - (o_offset + o_len);
-
- if (diff <= 0) {
- memmove(o_buf + n_len, o_buf + o_len, o_left);
- memcpy(o_buf, n_buf, n_len);
- skb_trim(skb, skb->len + diff);
- } else if (diff <= skb_tailroom(skb)) {
- skb_put(skb, diff);
- memmove(o_buf + n_len, o_buf + o_len, o_left);
- memcpy(o_buf, n_buf, n_len);
- } else {
- if (pskb_expand_head(skb, skb_headroom(skb), diff, pri))
- return -ENOMEM;
- skb_put(skb, diff);
- memmove(skb->data + o_offset + n_len,
- skb->data + o_offset + o_len, o_left);
- skb_copy_to_linear_data_offset(skb, o_offset, n_buf, n_len);
- }
-
- /* must update the iph total length here */
- ip_hdr(skb)->tot_len = htons(skb->len);
-
- LeaveFunction(9);
- return 0;
-}
-
-
int __init ip_vs_app_init(void)
{
/* we will replace it with proc_net_ipvs_create() soon */
diff --git a/net/netfilter/ipvs/ip_vs_conn.c b/net/netfilter/ipvs/ip_vs_conn.c
index ff04e9edbed..b71c69a2db1 100644
--- a/net/netfilter/ipvs/ip_vs_conn.c
+++ b/net/netfilter/ipvs/ip_vs_conn.c
@@ -158,6 +158,9 @@ static inline int ip_vs_conn_hash(struct ip_vs_conn *cp)
unsigned hash;
int ret;
+ if (cp->flags & IP_VS_CONN_F_ONE_PACKET)
+ return 0;
+
/* Hash by protocol, client address and port */
hash = ip_vs_conn_hashkey(cp->af, cp->protocol, &cp->caddr, cp->cport);
@@ -268,6 +271,29 @@ struct ip_vs_conn *ip_vs_conn_in_get
return cp;
}
+struct ip_vs_conn *
+ip_vs_conn_in_get_proto(int af, const struct sk_buff *skb,
+ struct ip_vs_protocol *pp,
+ const struct ip_vs_iphdr *iph,
+ unsigned int proto_off, int inverse)
+{
+ __be16 _ports[2], *pptr;
+
+ pptr = skb_header_pointer(skb, proto_off, sizeof(_ports), _ports);
+ if (pptr == NULL)
+ return NULL;
+
+ if (likely(!inverse))
+ return ip_vs_conn_in_get(af, iph->protocol,
+ &iph->saddr, pptr[0],
+ &iph->daddr, pptr[1]);
+ else
+ return ip_vs_conn_in_get(af, iph->protocol,
+ &iph->daddr, pptr[1],
+ &iph->saddr, pptr[0]);
+}
+EXPORT_SYMBOL_GPL(ip_vs_conn_in_get_proto);
+
/* Get reference to connection template */
struct ip_vs_conn *ip_vs_ct_in_get
(int af, int protocol, const union nf_inet_addr *s_addr, __be16 s_port,
@@ -353,14 +379,37 @@ struct ip_vs_conn *ip_vs_conn_out_get
return ret;
}
+struct ip_vs_conn *
+ip_vs_conn_out_get_proto(int af, const struct sk_buff *skb,
+ struct ip_vs_protocol *pp,
+ const struct ip_vs_iphdr *iph,
+ unsigned int proto_off, int inverse)
+{
+ __be16 _ports[2], *pptr;
+
+ pptr = skb_header_pointer(skb, proto_off, sizeof(_ports), _ports);
+ if (pptr == NULL)
+ return NULL;
+
+ if (likely(!inverse))
+ return ip_vs_conn_out_get(af, iph->protocol,
+ &iph->saddr, pptr[0],
+ &iph->daddr, pptr[1]);
+ else
+ return ip_vs_conn_out_get(af, iph->protocol,
+ &iph->daddr, pptr[1],
+ &iph->saddr, pptr[0]);
+}
+EXPORT_SYMBOL_GPL(ip_vs_conn_out_get_proto);
/*
* Put back the conn and restart its timer with its timeout
*/
void ip_vs_conn_put(struct ip_vs_conn *cp)
{
- /* reset it expire in its timeout */
- mod_timer(&cp->timer, jiffies+cp->timeout);
+ unsigned long t = (cp->flags & IP_VS_CONN_F_ONE_PACKET) ?
+ 0 : cp->timeout;
+ mod_timer(&cp->timer, jiffies+t);
__ip_vs_conn_put(cp);
}
@@ -653,7 +702,7 @@ static void ip_vs_conn_expire(unsigned long data)
/*
* unhash it if it is hashed in the conn table
*/
- if (!ip_vs_conn_unhash(cp))
+ if (!ip_vs_conn_unhash(cp) && !(cp->flags & IP_VS_CONN_F_ONE_PACKET))
goto expire_later;
/*
diff --git a/net/netfilter/ipvs/ip_vs_core.c b/net/netfilter/ipvs/ip_vs_core.c
index 1cd6e3fd058..4f8ddba4801 100644
--- a/net/netfilter/ipvs/ip_vs_core.c
+++ b/net/netfilter/ipvs/ip_vs_core.c
@@ -54,7 +54,6 @@
EXPORT_SYMBOL(register_ip_vs_scheduler);
EXPORT_SYMBOL(unregister_ip_vs_scheduler);
-EXPORT_SYMBOL(ip_vs_skb_replace);
EXPORT_SYMBOL(ip_vs_proto_name);
EXPORT_SYMBOL(ip_vs_conn_new);
EXPORT_SYMBOL(ip_vs_conn_in_get);
@@ -194,6 +193,7 @@ ip_vs_sched_persist(struct ip_vs_service *svc,
struct ip_vs_dest *dest;
struct ip_vs_conn *ct;
__be16 dport; /* destination port to forward */
+ __be16 flags;
union nf_inet_addr snet; /* source network of the client,
after masking */
@@ -340,6 +340,10 @@ ip_vs_sched_persist(struct ip_vs_service *svc,
dport = ports[1];
}
+ flags = (svc->flags & IP_VS_SVC_F_ONEPACKET
+ && iph.protocol == IPPROTO_UDP)?
+ IP_VS_CONN_F_ONE_PACKET : 0;
+
/*
* Create a new connection according to the template
*/
@@ -347,7 +351,7 @@ ip_vs_sched_persist(struct ip_vs_service *svc,
&iph.saddr, ports[0],
&iph.daddr, ports[1],
&dest->addr, dport,
- 0,
+ flags,
dest);
if (cp == NULL) {
ip_vs_conn_put(ct);
@@ -377,7 +381,7 @@ ip_vs_schedule(struct ip_vs_service *svc, const struct sk_buff *skb)
struct ip_vs_conn *cp = NULL;
struct ip_vs_iphdr iph;
struct ip_vs_dest *dest;
- __be16 _ports[2], *pptr;
+ __be16 _ports[2], *pptr, flags;
ip_vs_fill_iphdr(svc->af, skb_network_header(skb), &iph);
pptr = skb_header_pointer(skb, iph.len, sizeof(_ports), _ports);
@@ -407,6 +411,10 @@ ip_vs_schedule(struct ip_vs_service *svc, const struct sk_buff *skb)
return NULL;
}
+ flags = (svc->flags & IP_VS_SVC_F_ONEPACKET
+ && iph.protocol == IPPROTO_UDP)?
+ IP_VS_CONN_F_ONE_PACKET : 0;
+
/*
* Create a connection entry.
*/
@@ -414,7 +422,7 @@ ip_vs_schedule(struct ip_vs_service *svc, const struct sk_buff *skb)
&iph.saddr, pptr[0],
&iph.daddr, pptr[1],
&dest->addr, dest->port ? dest->port : pptr[1],
- 0,
+ flags,
dest);
if (cp == NULL)
return NULL;
@@ -464,6 +472,9 @@ int ip_vs_leave(struct ip_vs_service *svc, struct sk_buff *skb,
if (sysctl_ip_vs_cache_bypass && svc->fwmark && unicast) {
int ret, cs;
struct ip_vs_conn *cp;
+ __u16 flags = (svc->flags & IP_VS_SVC_F_ONEPACKET &&
+ iph.protocol == IPPROTO_UDP)?
+ IP_VS_CONN_F_ONE_PACKET : 0;
union nf_inet_addr daddr = { .all = { 0, 0, 0, 0 } };
ip_vs_service_put(svc);
@@ -474,7 +485,7 @@ int ip_vs_leave(struct ip_vs_service *svc, struct sk_buff *skb,
&iph.saddr, pptr[0],
&iph.daddr, pptr[1],
&daddr, 0,
- IP_VS_CONN_F_BYPASS,
+ IP_VS_CONN_F_BYPASS | flags,
NULL);
if (cp == NULL)
return NF_DROP;
@@ -524,26 +535,6 @@ int ip_vs_leave(struct ip_vs_service *svc, struct sk_buff *skb,
return NF_DROP;
}
-
-/*
- * It is hooked before NF_IP_PRI_NAT_SRC at the NF_INET_POST_ROUTING
- * chain, and is used for VS/NAT.
- * It detects packets for VS/NAT connections and sends the packets
- * immediately. This can avoid that iptable_nat mangles the packets
- * for VS/NAT.
- */
-static unsigned int ip_vs_post_routing(unsigned int hooknum,
- struct sk_buff *skb,
- const struct net_device *in,
- const struct net_device *out,
- int (*okfn)(struct sk_buff *))
-{
- if (!skb->ipvs_property)
- return NF_ACCEPT;
- /* The packet was sent from IPVS, exit this chain */
- return NF_STOP;
-}
-
__sum16 ip_vs_checksum_complete(struct sk_buff *skb, int offset)
{
return csum_fold(skb_checksum(skb, offset, skb->len - offset, 0));
@@ -1487,14 +1478,6 @@ static struct nf_hook_ops ip_vs_ops[] __read_mostly = {
.hooknum = NF_INET_FORWARD,
.priority = 99,
},
- /* Before the netfilter connection tracking, exit from POST_ROUTING */
- {
- .hook = ip_vs_post_routing,
- .owner = THIS_MODULE,
- .pf = PF_INET,
- .hooknum = NF_INET_POST_ROUTING,
- .priority = NF_IP_PRI_NAT_SRC-1,
- },
#ifdef CONFIG_IP_VS_IPV6
/* After packet filtering, forward packet through VS/DR, VS/TUN,
* or VS/NAT(change destination), so that filtering rules can be
@@ -1523,14 +1506,6 @@ static struct nf_hook_ops ip_vs_ops[] __read_mostly = {
.hooknum = NF_INET_FORWARD,
.priority = 99,
},
- /* Before the netfilter connection tracking, exit from POST_ROUTING */
- {
- .hook = ip_vs_post_routing,
- .owner = THIS_MODULE,
- .pf = PF_INET6,
- .hooknum = NF_INET_POST_ROUTING,
- .priority = NF_IP6_PRI_NAT_SRC-1,
- },
#endif
};
diff --git a/net/netfilter/ipvs/ip_vs_ctl.c b/net/netfilter/ipvs/ip_vs_ctl.c
index 36dc1d88c2f..0f0c079c422 100644
--- a/net/netfilter/ipvs/ip_vs_ctl.c
+++ b/net/netfilter/ipvs/ip_vs_ctl.c
@@ -1864,14 +1864,16 @@ static int ip_vs_info_seq_show(struct seq_file *seq, void *v)
svc->scheduler->name);
else
#endif
- seq_printf(seq, "%s %08X:%04X %s ",
+ seq_printf(seq, "%s %08X:%04X %s %s ",
ip_vs_proto_name(svc->protocol),
ntohl(svc->addr.ip),
ntohs(svc->port),
- svc->scheduler->name);
+ svc->scheduler->name,
+ (svc->flags & IP_VS_SVC_F_ONEPACKET)?"ops ":"");
} else {
- seq_printf(seq, "FWM %08X %s ",
- svc->fwmark, svc->scheduler->name);
+ seq_printf(seq, "FWM %08X %s %s",
+ svc->fwmark, svc->scheduler->name,
+ (svc->flags & IP_VS_SVC_F_ONEPACKET)?"ops ":"");
}
if (svc->flags & IP_VS_SVC_F_PERSISTENT)
diff --git a/net/netfilter/ipvs/ip_vs_ftp.c b/net/netfilter/ipvs/ip_vs_ftp.c
index 2ae747a376a..f228a17ec64 100644
--- a/net/netfilter/ipvs/ip_vs_ftp.c
+++ b/net/netfilter/ipvs/ip_vs_ftp.c
@@ -20,6 +20,17 @@
*
* Author: Wouter Gadeyne
*
+ *
+ * Code for ip_vs_expect_related and ip_vs_expect_callback is taken from
+ * http://www.ssi.bg/~ja/nfct/:
+ *
+ * ip_vs_nfct.c: Netfilter connection tracking support for IPVS
+ *
+ * Portions Copyright (C) 2001-2002
+ * Antefacto Ltd, 181 Parnell St, Dublin 1, Ireland.
+ *
+ * Portions Copyright (C) 2003-2008
+ * Julian Anastasov
*/
#define KMSG_COMPONENT "IPVS"
@@ -32,6 +43,9 @@
#include <linux/in.h>
#include <linux/ip.h>
#include <linux/netfilter.h>
+#include <net/netfilter/nf_conntrack.h>
+#include <net/netfilter/nf_conntrack_expect.h>
+#include <net/netfilter/nf_nat_helper.h>
#include <linux/gfp.h>
#include <net/protocol.h>
#include <net/tcp.h>
@@ -43,6 +57,16 @@
#define SERVER_STRING "227 Entering Passive Mode ("
#define CLIENT_STRING "PORT "
+#define FMT_TUPLE "%pI4:%u->%pI4:%u/%u"
+#define ARG_TUPLE(T) &(T)->src.u3.ip, ntohs((T)->src.u.all), \
+ &(T)->dst.u3.ip, ntohs((T)->dst.u.all), \
+ (T)->dst.protonum
+
+#define FMT_CONN "%pI4:%u->%pI4:%u->%pI4:%u/%u:%u"
+#define ARG_CONN(C) &((C)->caddr.ip), ntohs((C)->cport), \
+ &((C)->vaddr.ip), ntohs((C)->vport), \
+ &((C)->daddr.ip), ntohs((C)->dport), \
+ (C)->protocol, (C)->state
/*
* List of ports (up to IP_VS_APP_MAX_PORTS) to be handled by helper
@@ -123,6 +147,119 @@ static int ip_vs_ftp_get_addrport(char *data, char *data_limit,
return 1;
}
+/*
+ * Called from init_conntrack() as expectfn handler.
+ */
+static void
+ip_vs_expect_callback(struct nf_conn *ct,
+ struct nf_conntrack_expect *exp)
+{
+ struct nf_conntrack_tuple *orig, new_reply;
+ struct ip_vs_conn *cp;
+
+ if (exp->tuple.src.l3num != PF_INET)
+ return;
+
+ /*
+ * We assume that no NF locks are held before this callback.
+ * ip_vs_conn_out_get and ip_vs_conn_in_get should match their
+ * expectations even if they use wildcard values, now we provide the
+ * actual values from the newly created original conntrack direction.
+ * The conntrack is confirmed when packet reaches IPVS hooks.
+ */
+
+ /* RS->CLIENT */
+ orig = &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple;
+ cp = ip_vs_conn_out_get(exp->tuple.src.l3num, orig->dst.protonum,
+ &orig->src.u3, orig->src.u.tcp.port,
+ &orig->dst.u3, orig->dst.u.tcp.port);
+ if (cp) {
+ /* Change reply CLIENT->RS to CLIENT->VS */
+ new_reply = ct->tuplehash[IP_CT_DIR_REPLY].tuple;
+ IP_VS_DBG(7, "%s(): ct=%p, status=0x%lX, tuples=" FMT_TUPLE ", "
+ FMT_TUPLE ", found inout cp=" FMT_CONN "\n",
+ __func__, ct, ct->status,
+ ARG_TUPLE(orig), ARG_TUPLE(&new_reply),
+ ARG_CONN(cp));
+ new_reply.dst.u3 = cp->vaddr;
+ new_reply.dst.u.tcp.port = cp->vport;
+ IP_VS_DBG(7, "%s(): ct=%p, new tuples=" FMT_TUPLE ", " FMT_TUPLE
+ ", inout cp=" FMT_CONN "\n",
+ __func__, ct,
+ ARG_TUPLE(orig), ARG_TUPLE(&new_reply),
+ ARG_CONN(cp));
+ goto alter;
+ }
+
+ /* CLIENT->VS */
+ cp = ip_vs_conn_in_get(exp->tuple.src.l3num, orig->dst.protonum,
+ &orig->src.u3, orig->src.u.tcp.port,
+ &orig->dst.u3, orig->dst.u.tcp.port);
+ if (cp) {
+ /* Change reply VS->CLIENT to RS->CLIENT */
+ new_reply = ct->tuplehash[IP_CT_DIR_REPLY].tuple;
+ IP_VS_DBG(7, "%s(): ct=%p, status=0x%lX, tuples=" FMT_TUPLE ", "
+ FMT_TUPLE ", found outin cp=" FMT_CONN "\n",
+ __func__, ct, ct->status,
+ ARG_TUPLE(orig), ARG_TUPLE(&new_reply),
+ ARG_CONN(cp));
+ new_reply.src.u3 = cp->daddr;
+ new_reply.src.u.tcp.port = cp->dport;
+ IP_VS_DBG(7, "%s(): ct=%p, new tuples=" FMT_TUPLE ", "
+ FMT_TUPLE ", outin cp=" FMT_CONN "\n",
+ __func__, ct,
+ ARG_TUPLE(orig), ARG_TUPLE(&new_reply),
+ ARG_CONN(cp));
+ goto alter;
+ }
+
+ IP_VS_DBG(7, "%s(): ct=%p, status=0x%lX, tuple=" FMT_TUPLE
+ " - unknown expect\n",
+ __func__, ct, ct->status, ARG_TUPLE(orig));
+ return;
+
+alter:
+ /* Never alter conntrack for non-NAT conns */
+ if (IP_VS_FWD_METHOD(cp) == IP_VS_CONN_F_MASQ)
+ nf_conntrack_alter_reply(ct, &new_reply);
+ ip_vs_conn_put(cp);
+ return;
+}
+
+/*
+ * Create NF conntrack expectation with wildcard (optional) source port.
+ * Then the default callback function will alter the reply and will confirm
+ * the conntrack entry when the first packet comes.
+ */
+static void
+ip_vs_expect_related(struct sk_buff *skb, struct nf_conn *ct,
+ struct ip_vs_conn *cp, u_int8_t proto,
+ const __be16 *port, int from_rs)
+{
+ struct nf_conntrack_expect *exp;
+
+ BUG_ON(!ct || ct == &nf_conntrack_untracked);
+
+ exp = nf_ct_expect_alloc(ct);
+ if (!exp)
+ return;
+
+ if (from_rs)
+ nf_ct_expect_init(exp, NF_CT_EXPECT_CLASS_DEFAULT,
+ nf_ct_l3num(ct), &cp->daddr, &cp->caddr,
+ proto, port, &cp->cport);
+ else
+ nf_ct_expect_init(exp, NF_CT_EXPECT_CLASS_DEFAULT,
+ nf_ct_l3num(ct), &cp->caddr, &cp->vaddr,
+ proto, port, &cp->vport);
+
+ exp->expectfn = ip_vs_expect_callback;
+
+ IP_VS_DBG(7, "%s(): ct=%p, expect tuple=" FMT_TUPLE "\n",
+ __func__, ct, ARG_TUPLE(&exp->tuple));
+ nf_ct_expect_related(exp);
+ nf_ct_expect_put(exp);
+}
/*
* Look at outgoing ftp packets to catch the response to a PASV command
@@ -149,7 +286,9 @@ static int ip_vs_ftp_out(struct ip_vs_app *app, struct ip_vs_conn *cp,
struct ip_vs_conn *n_cp;
char buf[24]; /* xxx.xxx.xxx.xxx,ppp,ppp\000 */
unsigned buf_len;
- int ret;
+ int ret = 0;
+ enum ip_conntrack_info ctinfo;
+ struct nf_conn *ct;
#ifdef CONFIG_IP_VS_IPV6
/* This application helper doesn't work with IPv6 yet,
@@ -219,19 +358,26 @@ static int ip_vs_ftp_out(struct ip_vs_app *app, struct ip_vs_conn *cp,
buf_len = strlen(buf);
+ ct = nf_ct_get(skb, &ctinfo);
+ if (ct && !nf_ct_is_untracked(ct)) {
+ /* If mangling fails this function will return 0
+ * which will cause the packet to be dropped.
+ * Mangling can only fail under memory pressure,
+ * hopefully it will succeed on the retransmitted
+ * packet.
+ */
+ ret = nf_nat_mangle_tcp_packet(skb, ct, ctinfo,
+ start-data, end-start,
+ buf, buf_len);
+ if (ret)
+ ip_vs_expect_related(skb, ct, n_cp,
+ IPPROTO_TCP, NULL, 0);
+ }
+
/*
- * Calculate required delta-offset to keep TCP happy
+ * Not setting 'diff' is intentional, otherwise the sequence
+ * would be adjusted twice.
*/
- *diff = buf_len - (end-start);
-
- if (*diff == 0) {
- /* simply replace it with new passive address */
- memcpy(start, buf, buf_len);
- ret = 1;
- } else {
- ret = !ip_vs_skb_replace(skb, GFP_ATOMIC, start,
- end-start, buf, buf_len);
- }
cp->app_data = NULL;
ip_vs_tcp_conn_listen(n_cp);
@@ -263,6 +409,7 @@ static int ip_vs_ftp_in(struct ip_vs_app *app, struct ip_vs_conn *cp,
union nf_inet_addr to;
__be16 port;
struct ip_vs_conn *n_cp;
+ struct nf_conn *ct;
#ifdef CONFIG_IP_VS_IPV6
/* This application helper doesn't work with IPv6 yet,
@@ -349,6 +496,11 @@ static int ip_vs_ftp_in(struct ip_vs_app *app, struct ip_vs_conn *cp,
ip_vs_control_add(n_cp, cp);
}
+ ct = (struct nf_conn *)skb->nfct;
+ if (ct && ct != &nf_conntrack_untracked)
+ ip_vs_expect_related(skb, ct, n_cp,
+ IPPROTO_TCP, &n_cp->dport, 1);
+
/*
* Move tunnel to listen state
*/
diff --git a/net/netfilter/ipvs/ip_vs_lblc.c b/net/netfilter/ipvs/ip_vs_lblc.c
index 94a45213faa..9323f894419 100644
--- a/net/netfilter/ipvs/ip_vs_lblc.c
+++ b/net/netfilter/ipvs/ip_vs_lblc.c
@@ -11,7 +11,7 @@
* Changes:
* Martin Hamilton : fixed the terrible locking bugs
* *lock(tbl->lock) ==> *lock(&tbl->lock)
- * Wensong Zhang : fixed the uninitilized tbl->lock bug
+ * Wensong Zhang : fixed the uninitialized tbl->lock bug
* Wensong Zhang : added doing full expiration check to
* collect stale entries of 24+ hours when
* no partial expire check in a half hour
diff --git a/net/netfilter/ipvs/ip_vs_lblcr.c b/net/netfilter/ipvs/ip_vs_lblcr.c
index 535dc2b419d..dbeed8ea421 100644
--- a/net/netfilter/ipvs/ip_vs_lblcr.c
+++ b/net/netfilter/ipvs/ip_vs_lblcr.c
@@ -386,7 +386,7 @@ ip_vs_lblcr_new(struct ip_vs_lblcr_table *tbl, const union nf_inet_addr *daddr,
ip_vs_addr_copy(dest->af, &en->addr, daddr);
en->lastuse = jiffies;
- /* initilize its dest set */
+ /* initialize its dest set */
atomic_set(&(en->set.size), 0);
INIT_LIST_HEAD(&en->set.list);
rwlock_init(&en->set.lock);
diff --git a/net/netfilter/ipvs/ip_vs_proto.c b/net/netfilter/ipvs/ip_vs_proto.c
index 2d3d5e4b35f..027f654799f 100644
--- a/net/netfilter/ipvs/ip_vs_proto.c
+++ b/net/netfilter/ipvs/ip_vs_proto.c
@@ -98,6 +98,7 @@ struct ip_vs_protocol * ip_vs_proto_get(unsigned short proto)
return NULL;
}
+EXPORT_SYMBOL(ip_vs_proto_get);
/*
diff --git a/net/netfilter/ipvs/ip_vs_proto_sctp.c b/net/netfilter/ipvs/ip_vs_proto_sctp.c
index c9a3f7a21d5..4c0855cb006 100644
--- a/net/netfilter/ipvs/ip_vs_proto_sctp.c
+++ b/net/netfilter/ipvs/ip_vs_proto_sctp.c
@@ -8,55 +8,6 @@
#include <net/sctp/checksum.h>
#include <net/ip_vs.h>
-
-static struct ip_vs_conn *
-sctp_conn_in_get(int af,
- const struct sk_buff *skb,
- struct ip_vs_protocol *pp,
- const struct ip_vs_iphdr *iph,
- unsigned int proto_off,
- int inverse)
-{
- __be16 _ports[2], *pptr;
-
- pptr = skb_header_pointer(skb, proto_off, sizeof(_ports), _ports);
- if (pptr == NULL)
- return NULL;
-
- if (likely(!inverse))
- return ip_vs_conn_in_get(af, iph->protocol,
- &iph->saddr, pptr[0],
- &iph->daddr, pptr[1]);
- else
- return ip_vs_conn_in_get(af, iph->protocol,
- &iph->daddr, pptr[1],
- &iph->saddr, pptr[0]);
-}
-
-static struct ip_vs_conn *
-sctp_conn_out_get(int af,
- const struct sk_buff *skb,
- struct ip_vs_protocol *pp,
- const struct ip_vs_iphdr *iph,
- unsigned int proto_off,
- int inverse)
-{
- __be16 _ports[2], *pptr;
-
- pptr = skb_header_pointer(skb, proto_off, sizeof(_ports), _ports);
- if (pptr == NULL)
- return NULL;
-
- if (likely(!inverse))
- return ip_vs_conn_out_get(af, iph->protocol,
- &iph->saddr, pptr[0],
- &iph->daddr, pptr[1]);
- else
- return ip_vs_conn_out_get(af, iph->protocol,
- &iph->daddr, pptr[1],
- &iph->saddr, pptr[0]);
-}
-
static int
sctp_conn_schedule(int af, struct sk_buff *skb, struct ip_vs_protocol *pp,
int *verdict, struct ip_vs_conn **cpp)
@@ -173,7 +124,7 @@ sctp_dnat_handler(struct sk_buff *skb,
return 0;
/* Call application helper if needed */
- if (!ip_vs_app_pkt_out(cp, skb))
+ if (!ip_vs_app_pkt_in(cp, skb))
return 0;
}
@@ -1169,8 +1120,8 @@ struct ip_vs_protocol ip_vs_protocol_sctp = {
.register_app = sctp_register_app,
.unregister_app = sctp_unregister_app,
.conn_schedule = sctp_conn_schedule,
- .conn_in_get = sctp_conn_in_get,
- .conn_out_get = sctp_conn_out_get,
+ .conn_in_get = ip_vs_conn_in_get_proto,
+ .conn_out_get = ip_vs_conn_out_get_proto,
.snat_handler = sctp_snat_handler,
.dnat_handler = sctp_dnat_handler,
.csum_check = sctp_csum_check,
diff --git a/net/netfilter/ipvs/ip_vs_proto_tcp.c b/net/netfilter/ipvs/ip_vs_proto_tcp.c
index 91d28e07374..282d24de859 100644
--- a/net/netfilter/ipvs/ip_vs_proto_tcp.c
+++ b/net/netfilter/ipvs/ip_vs_proto_tcp.c
@@ -27,52 +27,6 @@
#include <net/ip_vs.h>
-
-static struct ip_vs_conn *
-tcp_conn_in_get(int af, const struct sk_buff *skb, struct ip_vs_protocol *pp,
- const struct ip_vs_iphdr *iph, unsigned int proto_off,
- int inverse)
-{
- __be16 _ports[2], *pptr;
-
- pptr = skb_header_pointer(skb, proto_off, sizeof(_ports), _ports);
- if (pptr == NULL)
- return NULL;
-
- if (likely(!inverse)) {
- return ip_vs_conn_in_get(af, iph->protocol,
- &iph->saddr, pptr[0],
- &iph->daddr, pptr[1]);
- } else {
- return ip_vs_conn_in_get(af, iph->protocol,
- &iph->daddr, pptr[1],
- &iph->saddr, pptr[0]);
- }
-}
-
-static struct ip_vs_conn *
-tcp_conn_out_get(int af, const struct sk_buff *skb, struct ip_vs_protocol *pp,
- const struct ip_vs_iphdr *iph, unsigned int proto_off,
- int inverse)
-{
- __be16 _ports[2], *pptr;
-
- pptr = skb_header_pointer(skb, proto_off, sizeof(_ports), _ports);
- if (pptr == NULL)
- return NULL;
-
- if (likely(!inverse)) {
- return ip_vs_conn_out_get(af, iph->protocol,
- &iph->saddr, pptr[0],
- &iph->daddr, pptr[1]);
- } else {
- return ip_vs_conn_out_get(af, iph->protocol,
- &iph->daddr, pptr[1],
- &iph->saddr, pptr[0]);
- }
-}
-
-
static int
tcp_conn_schedule(int af, struct sk_buff *skb, struct ip_vs_protocol *pp,
int *verdict, struct ip_vs_conn **cpp)
@@ -721,8 +675,8 @@ struct ip_vs_protocol ip_vs_protocol_tcp = {
.register_app = tcp_register_app,
.unregister_app = tcp_unregister_app,
.conn_schedule = tcp_conn_schedule,
- .conn_in_get = tcp_conn_in_get,
- .conn_out_get = tcp_conn_out_get,
+ .conn_in_get = ip_vs_conn_in_get_proto,
+ .conn_out_get = ip_vs_conn_out_get_proto,
.snat_handler = tcp_snat_handler,
.dnat_handler = tcp_dnat_handler,
.csum_check = tcp_csum_check,
diff --git a/net/netfilter/ipvs/ip_vs_proto_udp.c b/net/netfilter/ipvs/ip_vs_proto_udp.c
index e7a6885e016..8553231b5d4 100644
--- a/net/netfilter/ipvs/ip_vs_proto_udp.c
+++ b/net/netfilter/ipvs/ip_vs_proto_udp.c
@@ -27,58 +27,6 @@
#include <net/ip.h>
#include <net/ip6_checksum.h>
-static struct ip_vs_conn *
-udp_conn_in_get(int af, const struct sk_buff *skb, struct ip_vs_protocol *pp,
- const struct ip_vs_iphdr *iph, unsigned int proto_off,
- int inverse)
-{
- struct ip_vs_conn *cp;
- __be16 _ports[2], *pptr;
-
- pptr = skb_header_pointer(skb, proto_off, sizeof(_ports), _ports);
- if (pptr == NULL)
- return NULL;
-
- if (likely(!inverse)) {
- cp = ip_vs_conn_in_get(af, iph->protocol,
- &iph->saddr, pptr[0],
- &iph->daddr, pptr[1]);
- } else {
- cp = ip_vs_conn_in_get(af, iph->protocol,
- &iph->daddr, pptr[1],
- &iph->saddr, pptr[0]);
- }
-
- return cp;
-}
-
-
-static struct ip_vs_conn *
-udp_conn_out_get(int af, const struct sk_buff *skb, struct ip_vs_protocol *pp,
- const struct ip_vs_iphdr *iph, unsigned int proto_off,
- int inverse)
-{
- struct ip_vs_conn *cp;
- __be16 _ports[2], *pptr;
-
- pptr = skb_header_pointer(skb, proto_off, sizeof(_ports), _ports);
- if (pptr == NULL)
- return NULL;
-
- if (likely(!inverse)) {
- cp = ip_vs_conn_out_get(af, iph->protocol,
- &iph->saddr, pptr[0],
- &iph->daddr, pptr[1]);
- } else {
- cp = ip_vs_conn_out_get(af, iph->protocol,
- &iph->daddr, pptr[1],
- &iph->saddr, pptr[0]);
- }
-
- return cp;
-}
-
-
static int
udp_conn_schedule(int af, struct sk_buff *skb, struct ip_vs_protocol *pp,
int *verdict, struct ip_vs_conn **cpp)
@@ -520,8 +468,8 @@ struct ip_vs_protocol ip_vs_protocol_udp = {
.init = udp_init,
.exit = udp_exit,
.conn_schedule = udp_conn_schedule,
- .conn_in_get = udp_conn_in_get,
- .conn_out_get = udp_conn_out_get,
+ .conn_in_get = ip_vs_conn_in_get_proto,
+ .conn_out_get = ip_vs_conn_out_get_proto,
.snat_handler = udp_snat_handler,
.dnat_handler = udp_dnat_handler,
.csum_check = udp_csum_check,
diff --git a/net/netfilter/ipvs/ip_vs_xmit.c b/net/netfilter/ipvs/ip_vs_xmit.c
index 93c15a107b2..21e1a5e9b9d 100644
--- a/net/netfilter/ipvs/ip_vs_xmit.c
+++ b/net/netfilter/ipvs/ip_vs_xmit.c
@@ -28,6 +28,7 @@
#include <net/ip6_route.h>
#include <linux/icmpv6.h>
#include <linux/netfilter.h>
+#include <net/netfilter/nf_conntrack.h>
#include <linux/netfilter_ipv4.h>
#include <net/ip_vs.h>
@@ -90,10 +91,10 @@ __ip_vs_get_out_rt(struct ip_vs_conn *cp, u32 rtos)
&dest->addr.ip);
return NULL;
}
- __ip_vs_dst_set(dest, rtos, dst_clone(&rt->u.dst));
+ __ip_vs_dst_set(dest, rtos, dst_clone(&rt->dst));
IP_VS_DBG(10, "new dst %pI4, refcnt=%d, rtos=%X\n",
&dest->addr.ip,
- atomic_read(&rt->u.dst.__refcnt), rtos);
+ atomic_read(&rt->dst.__refcnt), rtos);
}
spin_unlock(&dest->dst_lock);
} else {
@@ -148,10 +149,10 @@ __ip_vs_get_out_rt_v6(struct ip_vs_conn *cp)
&dest->addr.in6);
return NULL;
}
- __ip_vs_dst_set(dest, 0, dst_clone(&rt->u.dst));
+ __ip_vs_dst_set(dest, 0, dst_clone(&rt->dst));
IP_VS_DBG(10, "new dst %pI6, refcnt=%d\n",
&dest->addr.in6,
- atomic_read(&rt->u.dst.__refcnt));
+ atomic_read(&rt->dst.__refcnt));
}
spin_unlock(&dest->dst_lock);
} else {
@@ -198,7 +199,7 @@ do { \
(skb)->ipvs_property = 1; \
skb_forward_csum(skb); \
NF_HOOK(pf, NF_INET_LOCAL_OUT, (skb), NULL, \
- (rt)->u.dst.dev, dst_output); \
+ (rt)->dst.dev, dst_output); \
} while (0)
@@ -245,7 +246,7 @@ ip_vs_bypass_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
}
/* MTU checking */
- mtu = dst_mtu(&rt->u.dst);
+ mtu = dst_mtu(&rt->dst);
if ((skb->len > mtu) && (iph->frag_off & htons(IP_DF))) {
ip_rt_put(rt);
icmp_send(skb, ICMP_DEST_UNREACH,ICMP_FRAG_NEEDED, htonl(mtu));
@@ -265,7 +266,7 @@ ip_vs_bypass_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
/* drop old route */
skb_dst_drop(skb);
- skb_dst_set(skb, &rt->u.dst);
+ skb_dst_set(skb, &rt->dst);
/* Another hack: avoid icmp_send in ip_fragment */
skb->local_df = 1;
@@ -309,9 +310,9 @@ ip_vs_bypass_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
}
/* MTU checking */
- mtu = dst_mtu(&rt->u.dst);
+ mtu = dst_mtu(&rt->dst);
if (skb->len > mtu) {
- dst_release(&rt->u.dst);
+ dst_release(&rt->dst);
icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu);
IP_VS_DBG_RL("%s(): frag needed\n", __func__);
goto tx_error;
@@ -323,13 +324,13 @@ ip_vs_bypass_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
*/
skb = skb_share_check(skb, GFP_ATOMIC);
if (unlikely(skb == NULL)) {
- dst_release(&rt->u.dst);
+ dst_release(&rt->dst);
return NF_STOLEN;
}
/* drop old route */
skb_dst_drop(skb);
- skb_dst_set(skb, &rt->u.dst);
+ skb_dst_set(skb, &rt->dst);
/* Another hack: avoid icmp_send in ip_fragment */
skb->local_df = 1;
@@ -348,6 +349,30 @@ ip_vs_bypass_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
}
#endif
+static void
+ip_vs_update_conntrack(struct sk_buff *skb, struct ip_vs_conn *cp)
+{
+ struct nf_conn *ct = (struct nf_conn *)skb->nfct;
+ struct nf_conntrack_tuple new_tuple;
+
+ if (ct == NULL || nf_ct_is_untracked(ct) || nf_ct_is_confirmed(ct))
+ return;
+
+ /*
+ * The connection is not yet in the hashtable, so we update it.
+ * CIP->VIP will remain the same, so leave the tuple in
+ * IP_CT_DIR_ORIGINAL untouched. When the reply comes back from the
+ * real-server we will see RIP->DIP.
+ */
+ new_tuple = ct->tuplehash[IP_CT_DIR_REPLY].tuple;
+ new_tuple.src.u3 = cp->daddr;
+ /*
+ * This will also take care of UDP and other protocols.
+ */
+ new_tuple.src.u.tcp.port = cp->dport;
+ nf_conntrack_alter_reply(ct, &new_tuple);
+}
+
/*
* NAT transmitter (only for outside-to-inside nat forwarding)
* Not used for related ICMP
@@ -376,7 +401,7 @@ ip_vs_nat_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
goto tx_error_icmp;
/* MTU checking */
- mtu = dst_mtu(&rt->u.dst);
+ mtu = dst_mtu(&rt->dst);
if ((skb->len > mtu) && (iph->frag_off & htons(IP_DF))) {
ip_rt_put(rt);
icmp_send(skb, ICMP_DEST_UNREACH,ICMP_FRAG_NEEDED, htonl(mtu));
@@ -388,12 +413,12 @@ ip_vs_nat_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
if (!skb_make_writable(skb, sizeof(struct iphdr)))
goto tx_error_put;
- if (skb_cow(skb, rt->u.dst.dev->hard_header_len))
+ if (skb_cow(skb, rt->dst.dev->hard_header_len))
goto tx_error_put;
/* drop old route */
skb_dst_drop(skb);
- skb_dst_set(skb, &rt->u.dst);
+ skb_dst_set(skb, &rt->dst);
/* mangle the packet */
if (pp->dnat_handler && !pp->dnat_handler(skb, pp, cp))
@@ -403,6 +428,8 @@ ip_vs_nat_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
IP_VS_DBG_PKT(10, pp, skb, 0, "After DNAT");
+ ip_vs_update_conntrack(skb, cp);
+
/* FIXME: when application helper enlarges the packet and the length
is larger than the MTU of outgoing device, there will be still
MTU problem. */
@@ -452,9 +479,9 @@ ip_vs_nat_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
goto tx_error_icmp;
/* MTU checking */
- mtu = dst_mtu(&rt->u.dst);
+ mtu = dst_mtu(&rt->dst);
if (skb->len > mtu) {
- dst_release(&rt->u.dst);
+ dst_release(&rt->dst);
icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu);
IP_VS_DBG_RL_PKT(0, pp, skb, 0,
"ip_vs_nat_xmit_v6(): frag needed for");
@@ -465,12 +492,12 @@ ip_vs_nat_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
if (!skb_make_writable(skb, sizeof(struct ipv6hdr)))
goto tx_error_put;
- if (skb_cow(skb, rt->u.dst.dev->hard_header_len))
+ if (skb_cow(skb, rt->dst.dev->hard_header_len))
goto tx_error_put;
/* drop old route */
skb_dst_drop(skb);
- skb_dst_set(skb, &rt->u.dst);
+ skb_dst_set(skb, &rt->dst);
/* mangle the packet */
if (pp->dnat_handler && !pp->dnat_handler(skb, pp, cp))
@@ -479,6 +506,8 @@ ip_vs_nat_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
IP_VS_DBG_PKT(10, pp, skb, 0, "After DNAT");
+ ip_vs_update_conntrack(skb, cp);
+
/* FIXME: when application helper enlarges the packet and the length
is larger than the MTU of outgoing device, there will be still
MTU problem. */
@@ -498,7 +527,7 @@ tx_error:
kfree_skb(skb);
return NF_STOLEN;
tx_error_put:
- dst_release(&rt->u.dst);
+ dst_release(&rt->dst);
goto tx_error;
}
#endif
@@ -549,9 +578,9 @@ ip_vs_tunnel_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
if (!(rt = __ip_vs_get_out_rt(cp, RT_TOS(tos))))
goto tx_error_icmp;
- tdev = rt->u.dst.dev;
+ tdev = rt->dst.dev;
- mtu = dst_mtu(&rt->u.dst) - sizeof(struct iphdr);
+ mtu = dst_mtu(&rt->dst) - sizeof(struct iphdr);
if (mtu < 68) {
ip_rt_put(rt);
IP_VS_DBG_RL("%s(): mtu less than 68\n", __func__);
@@ -601,7 +630,7 @@ ip_vs_tunnel_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
/* drop old route */
skb_dst_drop(skb);
- skb_dst_set(skb, &rt->u.dst);
+ skb_dst_set(skb, &rt->dst);
/*
* Push down and install the IPIP header.
@@ -615,7 +644,7 @@ ip_vs_tunnel_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
iph->daddr = rt->rt_dst;
iph->saddr = rt->rt_src;
iph->ttl = old_iph->ttl;
- ip_select_ident(iph, &rt->u.dst, NULL);
+ ip_select_ident(iph, &rt->dst, NULL);
/* Another hack: avoid icmp_send in ip_fragment */
skb->local_df = 1;
@@ -660,12 +689,12 @@ ip_vs_tunnel_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
if (!rt)
goto tx_error_icmp;
- tdev = rt->u.dst.dev;
+ tdev = rt->dst.dev;
- mtu = dst_mtu(&rt->u.dst) - sizeof(struct ipv6hdr);
+ mtu = dst_mtu(&rt->dst) - sizeof(struct ipv6hdr);
/* TODO IPv6: do we need this check in IPv6? */
if (mtu < 1280) {
- dst_release(&rt->u.dst);
+ dst_release(&rt->dst);
IP_VS_DBG_RL("%s(): mtu less than 1280\n", __func__);
goto tx_error;
}
@@ -674,7 +703,7 @@ ip_vs_tunnel_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
if (mtu < ntohs(old_iph->payload_len) + sizeof(struct ipv6hdr)) {
icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu);
- dst_release(&rt->u.dst);
+ dst_release(&rt->dst);
IP_VS_DBG_RL("%s(): frag needed\n", __func__);
goto tx_error;
}
@@ -689,7 +718,7 @@ ip_vs_tunnel_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
struct sk_buff *new_skb =
skb_realloc_headroom(skb, max_headroom);
if (!new_skb) {
- dst_release(&rt->u.dst);
+ dst_release(&rt->dst);
kfree_skb(skb);
IP_VS_ERR_RL("%s(): no memory\n", __func__);
return NF_STOLEN;
@@ -707,7 +736,7 @@ ip_vs_tunnel_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
/* drop old route */
skb_dst_drop(skb);
- skb_dst_set(skb, &rt->u.dst);
+ skb_dst_set(skb, &rt->dst);
/*
* Push down and install the IPIP header.
@@ -760,7 +789,7 @@ ip_vs_dr_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
goto tx_error_icmp;
/* MTU checking */
- mtu = dst_mtu(&rt->u.dst);
+ mtu = dst_mtu(&rt->dst);
if ((iph->frag_off & htons(IP_DF)) && skb->len > mtu) {
icmp_send(skb, ICMP_DEST_UNREACH,ICMP_FRAG_NEEDED, htonl(mtu));
ip_rt_put(rt);
@@ -780,7 +809,7 @@ ip_vs_dr_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
/* drop old route */
skb_dst_drop(skb);
- skb_dst_set(skb, &rt->u.dst);
+ skb_dst_set(skb, &rt->dst);
/* Another hack: avoid icmp_send in ip_fragment */
skb->local_df = 1;
@@ -813,10 +842,10 @@ ip_vs_dr_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
goto tx_error_icmp;
/* MTU checking */
- mtu = dst_mtu(&rt->u.dst);
+ mtu = dst_mtu(&rt->dst);
if (skb->len > mtu) {
icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu);
- dst_release(&rt->u.dst);
+ dst_release(&rt->dst);
IP_VS_DBG_RL("%s(): frag needed\n", __func__);
goto tx_error;
}
@@ -827,13 +856,13 @@ ip_vs_dr_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
*/
skb = skb_share_check(skb, GFP_ATOMIC);
if (unlikely(skb == NULL)) {
- dst_release(&rt->u.dst);
+ dst_release(&rt->dst);
return NF_STOLEN;
}
/* drop old route */
skb_dst_drop(skb);
- skb_dst_set(skb, &rt->u.dst);
+ skb_dst_set(skb, &rt->dst);
/* Another hack: avoid icmp_send in ip_fragment */
skb->local_df = 1;
@@ -888,7 +917,7 @@ ip_vs_icmp_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
goto tx_error_icmp;
/* MTU checking */
- mtu = dst_mtu(&rt->u.dst);
+ mtu = dst_mtu(&rt->dst);
if ((skb->len > mtu) && (ip_hdr(skb)->frag_off & htons(IP_DF))) {
ip_rt_put(rt);
icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED, htonl(mtu));
@@ -900,12 +929,12 @@ ip_vs_icmp_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
if (!skb_make_writable(skb, offset))
goto tx_error_put;
- if (skb_cow(skb, rt->u.dst.dev->hard_header_len))
+ if (skb_cow(skb, rt->dst.dev->hard_header_len))
goto tx_error_put;
/* drop the old route when skb is not shared */
skb_dst_drop(skb);
- skb_dst_set(skb, &rt->u.dst);
+ skb_dst_set(skb, &rt->dst);
ip_vs_nat_icmp(skb, pp, cp, 0);
@@ -963,9 +992,9 @@ ip_vs_icmp_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
goto tx_error_icmp;
/* MTU checking */
- mtu = dst_mtu(&rt->u.dst);
+ mtu = dst_mtu(&rt->dst);
if (skb->len > mtu) {
- dst_release(&rt->u.dst);
+ dst_release(&rt->dst);
icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu);
IP_VS_DBG_RL("%s(): frag needed\n", __func__);
goto tx_error;
@@ -975,12 +1004,12 @@ ip_vs_icmp_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
if (!skb_make_writable(skb, offset))
goto tx_error_put;
- if (skb_cow(skb, rt->u.dst.dev->hard_header_len))
+ if (skb_cow(skb, rt->dst.dev->hard_header_len))
goto tx_error_put;
/* drop the old route when skb is not shared */
skb_dst_drop(skb);
- skb_dst_set(skb, &rt->u.dst);
+ skb_dst_set(skb, &rt->dst);
ip_vs_nat_icmp_v6(skb, pp, cp, 0);
@@ -1001,7 +1030,7 @@ out:
LeaveFunction(10);
return rc;
tx_error_put:
- dst_release(&rt->u.dst);
+ dst_release(&rt->dst);
goto tx_error;
}
#endif
diff --git a/net/netfilter/nf_conntrack_acct.c b/net/netfilter/nf_conntrack_acct.c
index ab81b380eae..5178c691ecb 100644
--- a/net/netfilter/nf_conntrack_acct.c
+++ b/net/netfilter/nf_conntrack_acct.c
@@ -17,13 +17,7 @@
#include <net/netfilter/nf_conntrack_extend.h>
#include <net/netfilter/nf_conntrack_acct.h>
-#ifdef CONFIG_NF_CT_ACCT
-#define NF_CT_ACCT_DEFAULT 1
-#else
-#define NF_CT_ACCT_DEFAULT 0
-#endif
-
-static int nf_ct_acct __read_mostly = NF_CT_ACCT_DEFAULT;
+static int nf_ct_acct __read_mostly;
module_param_named(acct, nf_ct_acct, bool, 0644);
MODULE_PARM_DESC(acct, "Enable connection tracking flow accounting.");
@@ -114,12 +108,6 @@ int nf_conntrack_acct_init(struct net *net)
net->ct.sysctl_acct = nf_ct_acct;
if (net_eq(net, &init_net)) {
-#ifdef CONFIG_NF_CT_ACCT
- printk(KERN_WARNING "CONFIG_NF_CT_ACCT is deprecated and will be removed soon. Please use\n");
- printk(KERN_WARNING "nf_conntrack.acct=1 kernel parameter, acct=1 nf_conntrack module option or\n");
- printk(KERN_WARNING "sysctl net.netfilter.nf_conntrack_acct=1 to enable it.\n");
-#endif
-
ret = nf_ct_extend_register(&acct_extend);
if (ret < 0) {
printk(KERN_ERR "nf_conntrack_acct: Unable to register extension\n");
diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c
index eeeb8bc7398..df3eedb142f 100644
--- a/net/netfilter/nf_conntrack_core.c
+++ b/net/netfilter/nf_conntrack_core.c
@@ -62,8 +62,8 @@ EXPORT_SYMBOL_GPL(nf_conntrack_htable_size);
unsigned int nf_conntrack_max __read_mostly;
EXPORT_SYMBOL_GPL(nf_conntrack_max);
-struct nf_conn nf_conntrack_untracked __read_mostly;
-EXPORT_SYMBOL_GPL(nf_conntrack_untracked);
+DEFINE_PER_CPU(struct nf_conn, nf_conntrack_untracked);
+EXPORT_PER_CPU_SYMBOL(nf_conntrack_untracked);
static int nf_conntrack_hash_rnd_initted;
static unsigned int nf_conntrack_hash_rnd;
@@ -619,9 +619,7 @@ struct nf_conn *nf_conntrack_alloc(struct net *net, u16 zone,
ct->tuplehash[IP_CT_DIR_REPLY].hnnode.pprev = NULL;
/* Don't set timer yet: wait for confirmation */
setup_timer(&ct->timeout, death_by_timeout, (unsigned long)ct);
-#ifdef CONFIG_NET_NS
- ct->ct_net = net;
-#endif
+ write_pnet(&ct->ct_net, net);
#ifdef CONFIG_NF_CONNTRACK_ZONES
if (zone) {
struct nf_conntrack_zone *nf_ct_zone;
@@ -968,8 +966,7 @@ acct:
if (acct) {
spin_lock_bh(&ct->lock);
acct[CTINFO2DIR(ctinfo)].packets++;
- acct[CTINFO2DIR(ctinfo)].bytes +=
- skb->len - skb_network_offset(skb);
+ acct[CTINFO2DIR(ctinfo)].bytes += skb->len;
spin_unlock_bh(&ct->lock);
}
}
@@ -1183,10 +1180,21 @@ static void nf_ct_release_dying_list(struct net *net)
spin_unlock_bh(&nf_conntrack_lock);
}
+static int untrack_refs(void)
+{
+ int cnt = 0, cpu;
+
+ for_each_possible_cpu(cpu) {
+ struct nf_conn *ct = &per_cpu(nf_conntrack_untracked, cpu);
+
+ cnt += atomic_read(&ct->ct_general.use) - 1;
+ }
+ return cnt;
+}
+
static void nf_conntrack_cleanup_init_net(void)
{
- /* wait until all references to nf_conntrack_untracked are dropped */
- while (atomic_read(&nf_conntrack_untracked.ct_general.use) > 1)
+ while (untrack_refs() > 0)
schedule();
nf_conntrack_helper_fini();
@@ -1321,10 +1329,19 @@ EXPORT_SYMBOL_GPL(nf_conntrack_set_hashsize);
module_param_call(hashsize, nf_conntrack_set_hashsize, param_get_uint,
&nf_conntrack_htable_size, 0600);
+void nf_ct_untracked_status_or(unsigned long bits)
+{
+ int cpu;
+
+ for_each_possible_cpu(cpu)
+ per_cpu(nf_conntrack_untracked, cpu).status |= bits;
+}
+EXPORT_SYMBOL_GPL(nf_ct_untracked_status_or);
+
static int nf_conntrack_init_init_net(void)
{
int max_factor = 8;
- int ret;
+ int ret, cpu;
/* Idea from tcp.c: use 1/16384 of memory. On i386: 32MB
* machine has 512 buckets. >= 1GB machines have 16384 buckets. */
@@ -1363,13 +1380,13 @@ static int nf_conntrack_init_init_net(void)
goto err_extend;
#endif
/* Set up fake conntrack: to never be deleted, not in any hashes */
-#ifdef CONFIG_NET_NS
- nf_conntrack_untracked.ct_net = &init_net;
-#endif
- atomic_set(&nf_conntrack_untracked.ct_general.use, 1);
+ for_each_possible_cpu(cpu) {
+ struct nf_conn *ct = &per_cpu(nf_conntrack_untracked, cpu);
+ write_pnet(&ct->ct_net, &init_net);
+ atomic_set(&ct->ct_general.use, 1);
+ }
/* - and look it like as a confirmed connection */
- set_bit(IPS_CONFIRMED_BIT, &nf_conntrack_untracked.status);
-
+ nf_ct_untracked_status_or(IPS_CONFIRMED | IPS_UNTRACKED);
return 0;
#ifdef CONFIG_NF_CONNTRACK_ZONES
diff --git a/net/netfilter/nf_conntrack_extend.c b/net/netfilter/nf_conntrack_extend.c
index fdc8fb4ae10..7dcf7a40419 100644
--- a/net/netfilter/nf_conntrack_extend.c
+++ b/net/netfilter/nf_conntrack_extend.c
@@ -23,9 +23,10 @@ void __nf_ct_ext_destroy(struct nf_conn *ct)
{
unsigned int i;
struct nf_ct_ext_type *t;
+ struct nf_ct_ext *ext = ct->ext;
for (i = 0; i < NF_CT_EXT_NUM; i++) {
- if (!nf_ct_ext_exist(ct, i))
+ if (!__nf_ct_ext_exist(ext, i))
continue;
rcu_read_lock();
@@ -73,44 +74,45 @@ static void __nf_ct_ext_free_rcu(struct rcu_head *head)
void *__nf_ct_ext_add(struct nf_conn *ct, enum nf_ct_ext_id id, gfp_t gfp)
{
- struct nf_ct_ext *new;
+ struct nf_ct_ext *old, *new;
int i, newlen, newoff;
struct nf_ct_ext_type *t;
/* Conntrack must not be confirmed to avoid races on reallocation. */
NF_CT_ASSERT(!nf_ct_is_confirmed(ct));
- if (!ct->ext)
+ old = ct->ext;
+ if (!old)
return nf_ct_ext_create(&ct->ext, id, gfp);
- if (nf_ct_ext_exist(ct, id))
+ if (__nf_ct_ext_exist(old, 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);
+ newoff = ALIGN(old->len, t->align);
newlen = newoff + t->len;
rcu_read_unlock();
- new = __krealloc(ct->ext, newlen, gfp);
+ new = __krealloc(old, newlen, gfp);
if (!new)
return NULL;
- if (new != ct->ext) {
+ if (new != old) {
for (i = 0; i < NF_CT_EXT_NUM; i++) {
- if (!nf_ct_ext_exist(ct, i))
+ if (!__nf_ct_ext_exist(old, i))
continue;
rcu_read_lock();
t = rcu_dereference(nf_ct_ext_types[i]);
if (t && t->move)
t->move((void *)new + new->offset[i],
- (void *)ct->ext + ct->ext->offset[i]);
+ (void *)old + old->offset[i]);
rcu_read_unlock();
}
- call_rcu(&ct->ext->rcu, __nf_ct_ext_free_rcu);
+ call_rcu(&old->rcu, __nf_ct_ext_free_rcu);
ct->ext = new;
}
diff --git a/net/netfilter/nf_conntrack_h323_main.c b/net/netfilter/nf_conntrack_h323_main.c
index 6eaee7c8a33..b969025cf82 100644
--- a/net/netfilter/nf_conntrack_h323_main.c
+++ b/net/netfilter/nf_conntrack_h323_main.c
@@ -734,11 +734,11 @@ static int callforward_do_filter(const union nf_inet_addr *src,
if (!afinfo->route((struct dst_entry **)&rt1, &fl1)) {
if (!afinfo->route((struct dst_entry **)&rt2, &fl2)) {
if (rt1->rt_gateway == rt2->rt_gateway &&
- rt1->u.dst.dev == rt2->u.dst.dev)
+ rt1->dst.dev == rt2->dst.dev)
ret = 1;
- dst_release(&rt2->u.dst);
+ dst_release(&rt2->dst);
}
- dst_release(&rt1->u.dst);
+ dst_release(&rt1->dst);
}
break;
}
@@ -753,11 +753,11 @@ static int callforward_do_filter(const union nf_inet_addr *src,
if (!afinfo->route((struct dst_entry **)&rt2, &fl2)) {
if (!memcmp(&rt1->rt6i_gateway, &rt2->rt6i_gateway,
sizeof(rt1->rt6i_gateway)) &&
- rt1->u.dst.dev == rt2->u.dst.dev)
+ rt1->dst.dev == rt2->dst.dev)
ret = 1;
- dst_release(&rt2->u.dst);
+ dst_release(&rt2->dst);
}
- dst_release(&rt1->u.dst);
+ dst_release(&rt1->dst);
}
break;
}
diff --git a/net/netfilter/nf_conntrack_netbios_ns.c b/net/netfilter/nf_conntrack_netbios_ns.c
index 497b2224536..aadde018a07 100644
--- a/net/netfilter/nf_conntrack_netbios_ns.c
+++ b/net/netfilter/nf_conntrack_netbios_ns.c
@@ -61,7 +61,7 @@ static int help(struct sk_buff *skb, unsigned int protoff,
goto out;
rcu_read_lock();
- in_dev = __in_dev_get_rcu(rt->u.dst.dev);
+ in_dev = __in_dev_get_rcu(rt->dst.dev);
if (in_dev != NULL) {
for_primary_ifa(in_dev) {
if (ifa->ifa_broadcast == iph->daddr) {
diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c
index c42ff6aa441..5bae1cd15ee 100644
--- a/net/netfilter/nf_conntrack_netlink.c
+++ b/net/netfilter/nf_conntrack_netlink.c
@@ -480,7 +480,7 @@ ctnetlink_conntrack_event(unsigned int events, struct nf_ct_event *item)
int err;
/* ignore our fake conntrack entry */
- if (ct == &nf_conntrack_untracked)
+ if (nf_ct_is_untracked(ct))
return 0;
if (events & (1 << IPCT_DESTROY)) {
diff --git a/net/netfilter/nf_conntrack_proto_tcp.c b/net/netfilter/nf_conntrack_proto_tcp.c
index 9dd8cd4fb6e..c4c885dca3b 100644
--- a/net/netfilter/nf_conntrack_proto_tcp.c
+++ b/net/netfilter/nf_conntrack_proto_tcp.c
@@ -585,8 +585,16 @@ static bool tcp_in_window(const struct nf_conn *ct,
* Let's try to use the data from the packet.
*/
sender->td_end = end;
+ win <<= sender->td_scale;
sender->td_maxwin = (win == 0 ? 1 : win);
sender->td_maxend = end + sender->td_maxwin;
+ /*
+ * We haven't seen traffic in the other direction yet
+ * but we have to tweak window tracking to pass III
+ * and IV until that happens.
+ */
+ if (receiver->td_maxwin == 0)
+ receiver->td_end = receiver->td_maxend = sack;
}
} else if (((state->state == TCP_CONNTRACK_SYN_SENT
&& dir == IP_CT_DIR_ORIGINAL)
@@ -680,7 +688,7 @@ static bool tcp_in_window(const struct nf_conn *ct,
/*
* Update receiver data.
*/
- if (after(end, sender->td_maxend))
+ if (receiver->td_maxwin != 0 && after(end, sender->td_maxend))
receiver->td_maxwin += end - sender->td_maxend;
if (after(sack + win, receiver->td_maxend - 1)) {
receiver->td_maxend = sack + win;
@@ -736,27 +744,19 @@ static bool tcp_in_window(const struct nf_conn *ct,
return res;
}
-#define TH_FIN 0x01
-#define TH_SYN 0x02
-#define TH_RST 0x04
-#define TH_PUSH 0x08
-#define TH_ACK 0x10
-#define TH_URG 0x20
-#define TH_ECE 0x40
-#define TH_CWR 0x80
-
/* table of valid flag combinations - PUSH, ECE and CWR are always valid */
-static const u8 tcp_valid_flags[(TH_FIN|TH_SYN|TH_RST|TH_ACK|TH_URG) + 1] =
+static const u8 tcp_valid_flags[(TCPHDR_FIN|TCPHDR_SYN|TCPHDR_RST|TCPHDR_ACK|
+ TCPHDR_URG) + 1] =
{
- [TH_SYN] = 1,
- [TH_SYN|TH_URG] = 1,
- [TH_SYN|TH_ACK] = 1,
- [TH_RST] = 1,
- [TH_RST|TH_ACK] = 1,
- [TH_FIN|TH_ACK] = 1,
- [TH_FIN|TH_ACK|TH_URG] = 1,
- [TH_ACK] = 1,
- [TH_ACK|TH_URG] = 1,
+ [TCPHDR_SYN] = 1,
+ [TCPHDR_SYN|TCPHDR_URG] = 1,
+ [TCPHDR_SYN|TCPHDR_ACK] = 1,
+ [TCPHDR_RST] = 1,
+ [TCPHDR_RST|TCPHDR_ACK] = 1,
+ [TCPHDR_FIN|TCPHDR_ACK] = 1,
+ [TCPHDR_FIN|TCPHDR_ACK|TCPHDR_URG] = 1,
+ [TCPHDR_ACK] = 1,
+ [TCPHDR_ACK|TCPHDR_URG] = 1,
};
/* Protect conntrack agaist broken packets. Code taken from ipt_unclean.c. */
@@ -803,7 +803,7 @@ static int tcp_error(struct net *net, struct nf_conn *tmpl,
}
/* Check TCP flags. */
- tcpflags = (((u_int8_t *)th)[13] & ~(TH_ECE|TH_CWR|TH_PUSH));
+ tcpflags = (tcp_flag_byte(th) & ~(TCPHDR_ECE|TCPHDR_CWR|TCPHDR_PSH));
if (!tcp_valid_flags[tcpflags]) {
if (LOG_INVALID(net, IPPROTO_TCP))
nf_log_packet(pf, 0, skb, NULL, NULL, NULL,
diff --git a/net/netfilter/nfnetlink_log.c b/net/netfilter/nfnetlink_log.c
index fc9a211e629..6a1572b0ab4 100644
--- a/net/netfilter/nfnetlink_log.c
+++ b/net/netfilter/nfnetlink_log.c
@@ -66,9 +66,10 @@ struct nfulnl_instance {
u_int16_t group_num; /* number of this queue */
u_int16_t flags;
u_int8_t copy_mode;
+ struct rcu_head rcu;
};
-static DEFINE_RWLOCK(instances_lock);
+static DEFINE_SPINLOCK(instances_lock);
static atomic_t global_seq;
#define INSTANCE_BUCKETS 16
@@ -88,7 +89,7 @@ __instance_lookup(u_int16_t group_num)
struct nfulnl_instance *inst;
head = &instance_table[instance_hashfn(group_num)];
- hlist_for_each_entry(inst, pos, head, hlist) {
+ hlist_for_each_entry_rcu(inst, pos, head, hlist) {
if (inst->group_num == group_num)
return inst;
}
@@ -106,22 +107,26 @@ instance_lookup_get(u_int16_t group_num)
{
struct nfulnl_instance *inst;
- read_lock_bh(&instances_lock);
+ rcu_read_lock_bh();
inst = __instance_lookup(group_num);
- if (inst)
- instance_get(inst);
- read_unlock_bh(&instances_lock);
+ if (inst && !atomic_inc_not_zero(&inst->use))
+ inst = NULL;
+ rcu_read_unlock_bh();
return inst;
}
+static void nfulnl_instance_free_rcu(struct rcu_head *head)
+{
+ kfree(container_of(head, struct nfulnl_instance, rcu));
+ module_put(THIS_MODULE);
+}
+
static void
instance_put(struct nfulnl_instance *inst)
{
- if (inst && atomic_dec_and_test(&inst->use)) {
- kfree(inst);
- module_put(THIS_MODULE);
- }
+ if (inst && atomic_dec_and_test(&inst->use))
+ call_rcu_bh(&inst->rcu, nfulnl_instance_free_rcu);
}
static void nfulnl_timer(unsigned long data);
@@ -132,7 +137,7 @@ instance_create(u_int16_t group_num, int pid)
struct nfulnl_instance *inst;
int err;
- write_lock_bh(&instances_lock);
+ spin_lock_bh(&instances_lock);
if (__instance_lookup(group_num)) {
err = -EEXIST;
goto out_unlock;
@@ -166,32 +171,37 @@ instance_create(u_int16_t group_num, int pid)
inst->copy_mode = NFULNL_COPY_PACKET;
inst->copy_range = NFULNL_COPY_RANGE_MAX;
- hlist_add_head(&inst->hlist,
+ hlist_add_head_rcu(&inst->hlist,
&instance_table[instance_hashfn(group_num)]);
- write_unlock_bh(&instances_lock);
+ spin_unlock_bh(&instances_lock);
return inst;
out_unlock:
- write_unlock_bh(&instances_lock);
+ spin_unlock_bh(&instances_lock);
return ERR_PTR(err);
}
static void __nfulnl_flush(struct nfulnl_instance *inst);
+/* called with BH disabled */
static void
__instance_destroy(struct nfulnl_instance *inst)
{
/* first pull it out of the global list */
- hlist_del(&inst->hlist);
+ hlist_del_rcu(&inst->hlist);
/* then flush all pending packets from skb */
- spin_lock_bh(&inst->lock);
+ spin_lock(&inst->lock);
+
+ /* lockless readers wont be able to use us */
+ inst->copy_mode = NFULNL_COPY_DISABLED;
+
if (inst->skb)
__nfulnl_flush(inst);
- spin_unlock_bh(&inst->lock);
+ spin_unlock(&inst->lock);
/* and finally put the refcount */
instance_put(inst);
@@ -200,9 +210,9 @@ __instance_destroy(struct nfulnl_instance *inst)
static inline void
instance_destroy(struct nfulnl_instance *inst)
{
- write_lock_bh(&instances_lock);
+ spin_lock_bh(&instances_lock);
__instance_destroy(inst);
- write_unlock_bh(&instances_lock);
+ spin_unlock_bh(&instances_lock);
}
static int
@@ -403,8 +413,9 @@ __build_packet_message(struct nfulnl_instance *inst,
NLA_PUT_BE32(inst->skb, NFULA_IFINDEX_PHYSINDEV,
htonl(indev->ifindex));
/* this is the bridge group "brX" */
+ /* rcu_read_lock()ed by nf_hook_slow or nf_log_packet */
NLA_PUT_BE32(inst->skb, NFULA_IFINDEX_INDEV,
- htonl(indev->br_port->br->dev->ifindex));
+ htonl(br_port_get_rcu(indev)->br->dev->ifindex));
} else {
/* Case 2: indev is bridge group, we need to look for
* physical device (when called from ipv4) */
@@ -430,8 +441,9 @@ __build_packet_message(struct nfulnl_instance *inst,
NLA_PUT_BE32(inst->skb, NFULA_IFINDEX_PHYSOUTDEV,
htonl(outdev->ifindex));
/* this is the bridge group "brX" */
+ /* rcu_read_lock()ed by nf_hook_slow or nf_log_packet */
NLA_PUT_BE32(inst->skb, NFULA_IFINDEX_OUTDEV,
- htonl(outdev->br_port->br->dev->ifindex));
+ htonl(br_port_get_rcu(outdev)->br->dev->ifindex));
} else {
/* Case 2: indev is a bridge group, we need to look
* for physical device (when called from ipv4) */
@@ -619,6 +631,7 @@ nfulnl_log_packet(u_int8_t pf,
size += nla_total_size(data_len);
break;
+ case NFULNL_COPY_DISABLED:
default:
goto unlock_and_release;
}
@@ -672,7 +685,7 @@ nfulnl_rcv_nl_event(struct notifier_block *this,
int i;
/* destroy all instances for this pid */
- write_lock_bh(&instances_lock);
+ spin_lock_bh(&instances_lock);
for (i = 0; i < INSTANCE_BUCKETS; i++) {
struct hlist_node *tmp, *t2;
struct nfulnl_instance *inst;
@@ -684,7 +697,7 @@ nfulnl_rcv_nl_event(struct notifier_block *this,
__instance_destroy(inst);
}
}
- write_unlock_bh(&instances_lock);
+ spin_unlock_bh(&instances_lock);
}
return NOTIFY_DONE;
}
@@ -861,19 +874,19 @@ static struct hlist_node *get_first(struct iter_state *st)
for (st->bucket = 0; st->bucket < INSTANCE_BUCKETS; st->bucket++) {
if (!hlist_empty(&instance_table[st->bucket]))
- return instance_table[st->bucket].first;
+ return rcu_dereference_bh(instance_table[st->bucket].first);
}
return NULL;
}
static struct hlist_node *get_next(struct iter_state *st, struct hlist_node *h)
{
- h = h->next;
+ h = rcu_dereference_bh(h->next);
while (!h) {
if (++st->bucket >= INSTANCE_BUCKETS)
return NULL;
- h = instance_table[st->bucket].first;
+ h = rcu_dereference_bh(instance_table[st->bucket].first);
}
return h;
}
@@ -890,9 +903,9 @@ static struct hlist_node *get_idx(struct iter_state *st, loff_t pos)
}
static void *seq_start(struct seq_file *seq, loff_t *pos)
- __acquires(instances_lock)
+ __acquires(rcu_bh)
{
- read_lock_bh(&instances_lock);
+ rcu_read_lock_bh();
return get_idx(seq->private, *pos);
}
@@ -903,9 +916,9 @@ static void *seq_next(struct seq_file *s, void *v, loff_t *pos)
}
static void seq_stop(struct seq_file *s, void *v)
- __releases(instances_lock)
+ __releases(rcu_bh)
{
- read_unlock_bh(&instances_lock);
+ rcu_read_unlock_bh();
}
static int seq_show(struct seq_file *s, void *v)
diff --git a/net/netfilter/nfnetlink_queue.c b/net/netfilter/nfnetlink_queue.c
index 12e1ab37fcd..68e67d19724 100644
--- a/net/netfilter/nfnetlink_queue.c
+++ b/net/netfilter/nfnetlink_queue.c
@@ -46,17 +46,19 @@ struct nfqnl_instance {
int peer_pid;
unsigned int queue_maxlen;
unsigned int copy_range;
- unsigned int queue_total;
unsigned int queue_dropped;
unsigned int queue_user_dropped;
- unsigned int id_sequence; /* 'sequence' of pkt ids */
u_int16_t queue_num; /* number of this queue */
u_int8_t copy_mode;
-
- spinlock_t lock;
-
+/*
+ * Following fields are dirtied for each queued packet,
+ * keep them in same cache line if possible.
+ */
+ spinlock_t lock;
+ unsigned int queue_total;
+ atomic_t id_sequence; /* 'sequence' of pkt ids */
struct list_head queue_list; /* packets in queue */
};
@@ -238,32 +240,24 @@ nfqnl_build_packet_message(struct nfqnl_instance *queue,
outdev = entry->outdev;
- spin_lock_bh(&queue->lock);
-
- switch ((enum nfqnl_config_mode)queue->copy_mode) {
+ switch ((enum nfqnl_config_mode)ACCESS_ONCE(queue->copy_mode)) {
case NFQNL_COPY_META:
case NFQNL_COPY_NONE:
break;
case NFQNL_COPY_PACKET:
if (entskb->ip_summed == CHECKSUM_PARTIAL &&
- skb_checksum_help(entskb)) {
- spin_unlock_bh(&queue->lock);
+ skb_checksum_help(entskb))
return NULL;
- }
- if (queue->copy_range == 0
- || queue->copy_range > entskb->len)
+
+ data_len = ACCESS_ONCE(queue->copy_range);
+ if (data_len == 0 || data_len > entskb->len)
data_len = entskb->len;
- else
- data_len = queue->copy_range;
size += nla_total_size(data_len);
break;
}
- entry->id = queue->id_sequence++;
-
- spin_unlock_bh(&queue->lock);
skb = alloc_skb(size, GFP_ATOMIC);
if (!skb)
@@ -278,6 +272,7 @@ nfqnl_build_packet_message(struct nfqnl_instance *queue,
nfmsg->version = NFNETLINK_V0;
nfmsg->res_id = htons(queue->queue_num);
+ entry->id = atomic_inc_return(&queue->id_sequence);
pmsg.packet_id = htonl(entry->id);
pmsg.hw_protocol = entskb->protocol;
pmsg.hook = entry->hook;
@@ -296,8 +291,9 @@ nfqnl_build_packet_message(struct nfqnl_instance *queue,
NLA_PUT_BE32(skb, NFQA_IFINDEX_PHYSINDEV,
htonl(indev->ifindex));
/* this is the bridge group "brX" */
+ /* rcu_read_lock()ed by __nf_queue */
NLA_PUT_BE32(skb, NFQA_IFINDEX_INDEV,
- htonl(indev->br_port->br->dev->ifindex));
+ htonl(br_port_get_rcu(indev)->br->dev->ifindex));
} else {
/* Case 2: indev is bridge group, we need to look for
* physical device (when called from ipv4) */
@@ -321,8 +317,9 @@ nfqnl_build_packet_message(struct nfqnl_instance *queue,
NLA_PUT_BE32(skb, NFQA_IFINDEX_PHYSOUTDEV,
htonl(outdev->ifindex));
/* this is the bridge group "brX" */
+ /* rcu_read_lock()ed by __nf_queue */
NLA_PUT_BE32(skb, NFQA_IFINDEX_OUTDEV,
- htonl(outdev->br_port->br->dev->ifindex));
+ htonl(br_port_get_rcu(outdev)->br->dev->ifindex));
} else {
/* Case 2: outdev is bridge group, we need to look for
* physical output device (when called from ipv4) */
@@ -866,7 +863,7 @@ static int seq_show(struct seq_file *s, void *v)
inst->peer_pid, inst->queue_total,
inst->copy_mode, inst->copy_range,
inst->queue_dropped, inst->queue_user_dropped,
- inst->id_sequence, 1);
+ atomic_read(&inst->id_sequence), 1);
}
static const struct seq_operations nfqnl_seq_ops = {
diff --git a/net/netfilter/xt_CHECKSUM.c b/net/netfilter/xt_CHECKSUM.c
new file mode 100644
index 00000000000..0f642ef8cd2
--- /dev/null
+++ b/net/netfilter/xt_CHECKSUM.c
@@ -0,0 +1,70 @@
+/* iptables module for the packet checksum mangling
+ *
+ * (C) 2002 by Harald Welte <laforge@netfilter.org>
+ * (C) 2010 Red Hat, Inc.
+ *
+ * Author: Michael S. Tsirkin <mst@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+#include <linux/module.h>
+#include <linux/skbuff.h>
+
+#include <linux/netfilter/x_tables.h>
+#include <linux/netfilter/xt_CHECKSUM.h>
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Michael S. Tsirkin <mst@redhat.com>");
+MODULE_DESCRIPTION("Xtables: checksum modification");
+MODULE_ALIAS("ipt_CHECKSUM");
+MODULE_ALIAS("ip6t_CHECKSUM");
+
+static unsigned int
+checksum_tg(struct sk_buff *skb, const struct xt_action_param *par)
+{
+ if (skb->ip_summed == CHECKSUM_PARTIAL)
+ skb_checksum_help(skb);
+
+ return XT_CONTINUE;
+}
+
+static int checksum_tg_check(const struct xt_tgchk_param *par)
+{
+ const struct xt_CHECKSUM_info *einfo = par->targinfo;
+
+ if (einfo->operation & ~XT_CHECKSUM_OP_FILL) {
+ pr_info("unsupported CHECKSUM operation %x\n", einfo->operation);
+ return -EINVAL;
+ }
+ if (!einfo->operation) {
+ pr_info("no CHECKSUM operation enabled\n");
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static struct xt_target checksum_tg_reg __read_mostly = {
+ .name = "CHECKSUM",
+ .family = NFPROTO_UNSPEC,
+ .target = checksum_tg,
+ .targetsize = sizeof(struct xt_CHECKSUM_info),
+ .table = "mangle",
+ .checkentry = checksum_tg_check,
+ .me = THIS_MODULE,
+};
+
+static int __init checksum_tg_init(void)
+{
+ return xt_register_target(&checksum_tg_reg);
+}
+
+static void __exit checksum_tg_exit(void)
+{
+ xt_unregister_target(&checksum_tg_reg);
+}
+
+module_init(checksum_tg_init);
+module_exit(checksum_tg_exit);
diff --git a/net/netfilter/xt_CT.c b/net/netfilter/xt_CT.c
index 562bf3266e0..0cb6053f02f 100644
--- a/net/netfilter/xt_CT.c
+++ b/net/netfilter/xt_CT.c
@@ -67,7 +67,7 @@ static int xt_ct_tg_check(const struct xt_tgchk_param *par)
return -EINVAL;
if (info->flags & XT_CT_NOTRACK) {
- ct = &nf_conntrack_untracked;
+ ct = nf_ct_untracked_get();
atomic_inc(&ct->ct_general.use);
goto out;
}
@@ -132,7 +132,7 @@ static void xt_ct_tg_destroy(const struct xt_tgdtor_param *par)
struct nf_conn *ct = info->ct;
struct nf_conn_help *help;
- if (ct != &nf_conntrack_untracked) {
+ if (!nf_ct_is_untracked(ct)) {
help = nfct_help(ct);
if (help)
module_put(help->helper->me);
diff --git a/net/netfilter/xt_IDLETIMER.c b/net/netfilter/xt_IDLETIMER.c
new file mode 100644
index 00000000000..be1f22e1354
--- /dev/null
+++ b/net/netfilter/xt_IDLETIMER.c
@@ -0,0 +1,315 @@
+/*
+ * linux/net/netfilter/xt_IDLETIMER.c
+ *
+ * Netfilter module to trigger a timer when packet matches.
+ * After timer expires a kevent will be sent.
+ *
+ * Copyright (C) 2004, 2010 Nokia Corporation
+ * Written by Timo Teras <ext-timo.teras@nokia.com>
+ *
+ * Converted to x_tables and reworked for upstream inclusion
+ * by Luciano Coelho <luciano.coelho@nokia.com>
+ *
+ * Contact: Luciano Coelho <luciano.coelho@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/module.h>
+#include <linux/timer.h>
+#include <linux/list.h>
+#include <linux/mutex.h>
+#include <linux/netfilter.h>
+#include <linux/netfilter/x_tables.h>
+#include <linux/netfilter/xt_IDLETIMER.h>
+#include <linux/kdev_t.h>
+#include <linux/kobject.h>
+#include <linux/workqueue.h>
+#include <linux/sysfs.h>
+
+struct idletimer_tg_attr {
+ struct attribute attr;
+ ssize_t (*show)(struct kobject *kobj,
+ struct attribute *attr, char *buf);
+};
+
+struct idletimer_tg {
+ struct list_head entry;
+ struct timer_list timer;
+ struct work_struct work;
+
+ struct kobject *kobj;
+ struct idletimer_tg_attr attr;
+
+ unsigned int refcnt;
+};
+
+static LIST_HEAD(idletimer_tg_list);
+static DEFINE_MUTEX(list_mutex);
+
+static struct kobject *idletimer_tg_kobj;
+
+static
+struct idletimer_tg *__idletimer_tg_find_by_label(const char *label)
+{
+ struct idletimer_tg *entry;
+
+ BUG_ON(!label);
+
+ list_for_each_entry(entry, &idletimer_tg_list, entry) {
+ if (!strcmp(label, entry->attr.attr.name))
+ return entry;
+ }
+
+ return NULL;
+}
+
+static ssize_t idletimer_tg_show(struct kobject *kobj, struct attribute *attr,
+ char *buf)
+{
+ struct idletimer_tg *timer;
+ unsigned long expires = 0;
+
+ mutex_lock(&list_mutex);
+
+ timer = __idletimer_tg_find_by_label(attr->name);
+ if (timer)
+ expires = timer->timer.expires;
+
+ mutex_unlock(&list_mutex);
+
+ if (time_after(expires, jiffies))
+ return sprintf(buf, "%u\n",
+ jiffies_to_msecs(expires - jiffies) / 1000);
+
+ return sprintf(buf, "0\n");
+}
+
+static void idletimer_tg_work(struct work_struct *work)
+{
+ struct idletimer_tg *timer = container_of(work, struct idletimer_tg,
+ work);
+
+ sysfs_notify(idletimer_tg_kobj, NULL, timer->attr.attr.name);
+}
+
+static void idletimer_tg_expired(unsigned long data)
+{
+ struct idletimer_tg *timer = (struct idletimer_tg *) data;
+
+ pr_debug("timer %s expired\n", timer->attr.attr.name);
+
+ schedule_work(&timer->work);
+}
+
+static int idletimer_tg_create(struct idletimer_tg_info *info)
+{
+ int ret;
+
+ info->timer = kmalloc(sizeof(*info->timer), GFP_KERNEL);
+ if (!info->timer) {
+ pr_debug("couldn't alloc timer\n");
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ info->timer->attr.attr.name = kstrdup(info->label, GFP_KERNEL);
+ if (!info->timer->attr.attr.name) {
+ pr_debug("couldn't alloc attribute name\n");
+ ret = -ENOMEM;
+ goto out_free_timer;
+ }
+ info->timer->attr.attr.mode = S_IRUGO;
+ info->timer->attr.show = idletimer_tg_show;
+
+ ret = sysfs_create_file(idletimer_tg_kobj, &info->timer->attr.attr);
+ if (ret < 0) {
+ pr_debug("couldn't add file to sysfs");
+ goto out_free_attr;
+ }
+
+ list_add(&info->timer->entry, &idletimer_tg_list);
+
+ setup_timer(&info->timer->timer, idletimer_tg_expired,
+ (unsigned long) info->timer);
+ info->timer->refcnt = 1;
+
+ mod_timer(&info->timer->timer,
+ msecs_to_jiffies(info->timeout * 1000) + jiffies);
+
+ INIT_WORK(&info->timer->work, idletimer_tg_work);
+
+ return 0;
+
+out_free_attr:
+ kfree(info->timer->attr.attr.name);
+out_free_timer:
+ kfree(info->timer);
+out:
+ return ret;
+}
+
+/*
+ * The actual xt_tables plugin.
+ */
+static unsigned int idletimer_tg_target(struct sk_buff *skb,
+ const struct xt_action_param *par)
+{
+ const struct idletimer_tg_info *info = par->targinfo;
+
+ pr_debug("resetting timer %s, timeout period %u\n",
+ info->label, info->timeout);
+
+ BUG_ON(!info->timer);
+
+ mod_timer(&info->timer->timer,
+ msecs_to_jiffies(info->timeout * 1000) + jiffies);
+
+ return XT_CONTINUE;
+}
+
+static int idletimer_tg_checkentry(const struct xt_tgchk_param *par)
+{
+ struct idletimer_tg_info *info = par->targinfo;
+ int ret;
+
+ pr_debug("checkentry targinfo%s\n", info->label);
+
+ if (info->timeout == 0) {
+ pr_debug("timeout value is zero\n");
+ return -EINVAL;
+ }
+
+ if (info->label[0] == '\0' ||
+ strnlen(info->label,
+ MAX_IDLETIMER_LABEL_SIZE) == MAX_IDLETIMER_LABEL_SIZE) {
+ pr_debug("label is empty or not nul-terminated\n");
+ return -EINVAL;
+ }
+
+ mutex_lock(&list_mutex);
+
+ info->timer = __idletimer_tg_find_by_label(info->label);
+ if (info->timer) {
+ info->timer->refcnt++;
+ mod_timer(&info->timer->timer,
+ msecs_to_jiffies(info->timeout * 1000) + jiffies);
+
+ pr_debug("increased refcnt of timer %s to %u\n",
+ info->label, info->timer->refcnt);
+ } else {
+ ret = idletimer_tg_create(info);
+ if (ret < 0) {
+ pr_debug("failed to create timer\n");
+ mutex_unlock(&list_mutex);
+ return ret;
+ }
+ }
+
+ mutex_unlock(&list_mutex);
+ return 0;
+}
+
+static void idletimer_tg_destroy(const struct xt_tgdtor_param *par)
+{
+ const struct idletimer_tg_info *info = par->targinfo;
+
+ pr_debug("destroy targinfo %s\n", info->label);
+
+ mutex_lock(&list_mutex);
+
+ if (--info->timer->refcnt == 0) {
+ pr_debug("deleting timer %s\n", info->label);
+
+ list_del(&info->timer->entry);
+ del_timer_sync(&info->timer->timer);
+ sysfs_remove_file(idletimer_tg_kobj, &info->timer->attr.attr);
+ kfree(info->timer->attr.attr.name);
+ kfree(info->timer);
+ } else {
+ pr_debug("decreased refcnt of timer %s to %u\n",
+ info->label, info->timer->refcnt);
+ }
+
+ mutex_unlock(&list_mutex);
+}
+
+static struct xt_target idletimer_tg __read_mostly = {
+ .name = "IDLETIMER",
+ .family = NFPROTO_UNSPEC,
+ .target = idletimer_tg_target,
+ .targetsize = sizeof(struct idletimer_tg_info),
+ .checkentry = idletimer_tg_checkentry,
+ .destroy = idletimer_tg_destroy,
+ .me = THIS_MODULE,
+};
+
+static struct class *idletimer_tg_class;
+
+static struct device *idletimer_tg_device;
+
+static int __init idletimer_tg_init(void)
+{
+ int err;
+
+ idletimer_tg_class = class_create(THIS_MODULE, "xt_idletimer");
+ err = PTR_ERR(idletimer_tg_class);
+ if (IS_ERR(idletimer_tg_class)) {
+ pr_debug("couldn't register device class\n");
+ goto out;
+ }
+
+ idletimer_tg_device = device_create(idletimer_tg_class, NULL,
+ MKDEV(0, 0), NULL, "timers");
+ err = PTR_ERR(idletimer_tg_device);
+ if (IS_ERR(idletimer_tg_device)) {
+ pr_debug("couldn't register system device\n");
+ goto out_class;
+ }
+
+ idletimer_tg_kobj = &idletimer_tg_device->kobj;
+
+ err = xt_register_target(&idletimer_tg);
+ if (err < 0) {
+ pr_debug("couldn't register xt target\n");
+ goto out_dev;
+ }
+
+ return 0;
+out_dev:
+ device_destroy(idletimer_tg_class, MKDEV(0, 0));
+out_class:
+ class_destroy(idletimer_tg_class);
+out:
+ return err;
+}
+
+static void __exit idletimer_tg_exit(void)
+{
+ xt_unregister_target(&idletimer_tg);
+
+ device_destroy(idletimer_tg_class, MKDEV(0, 0));
+ class_destroy(idletimer_tg_class);
+}
+
+module_init(idletimer_tg_init);
+module_exit(idletimer_tg_exit);
+
+MODULE_AUTHOR("Timo Teras <ext-timo.teras@nokia.com>");
+MODULE_AUTHOR("Luciano Coelho <luciano.coelho@nokia.com>");
+MODULE_DESCRIPTION("Xtables: idle time monitor");
+MODULE_LICENSE("GPL v2");
diff --git a/net/netfilter/xt_NOTRACK.c b/net/netfilter/xt_NOTRACK.c
index 512b9123252..9d782181b6c 100644
--- a/net/netfilter/xt_NOTRACK.c
+++ b/net/netfilter/xt_NOTRACK.c
@@ -23,7 +23,7 @@ notrack_tg(struct sk_buff *skb, const struct xt_action_param *par)
If there is a real ct entry correspondig to this packet,
it'll hang aroun till timing out. We don't deal with it
for performance reasons. JK */
- skb->nfct = &nf_conntrack_untracked.ct_general;
+ skb->nfct = &nf_ct_untracked_get()->ct_general;
skb->nfctinfo = IP_CT_NEW;
nf_conntrack_get(skb->nfct);
diff --git a/net/netfilter/xt_RATEEST.c b/net/netfilter/xt_RATEEST.c
index 69c01e10f8a..de079abd5bc 100644
--- a/net/netfilter/xt_RATEEST.c
+++ b/net/netfilter/xt_RATEEST.c
@@ -60,13 +60,22 @@ struct xt_rateest *xt_rateest_lookup(const char *name)
}
EXPORT_SYMBOL_GPL(xt_rateest_lookup);
+static void xt_rateest_free_rcu(struct rcu_head *head)
+{
+ kfree(container_of(head, struct xt_rateest, rcu));
+}
+
void xt_rateest_put(struct xt_rateest *est)
{
mutex_lock(&xt_rateest_mutex);
if (--est->refcnt == 0) {
hlist_del(&est->list);
gen_kill_estimator(&est->bstats, &est->rstats);
- kfree(est);
+ /*
+ * gen_estimator est_timer() might access est->lock or bstats,
+ * wait a RCU grace period before freeing 'est'
+ */
+ call_rcu(&est->rcu, xt_rateest_free_rcu);
}
mutex_unlock(&xt_rateest_mutex);
}
@@ -179,6 +188,7 @@ static int __init xt_rateest_tg_init(void)
static void __exit xt_rateest_tg_fini(void)
{
xt_unregister_target(&xt_rateest_tg_reg);
+ rcu_barrier(); /* Wait for completion of call_rcu()'s (xt_rateest_free_rcu) */
}
diff --git a/net/netfilter/xt_TCPMSS.c b/net/netfilter/xt_TCPMSS.c
index 62ec021fbd5..eb81c380da1 100644
--- a/net/netfilter/xt_TCPMSS.c
+++ b/net/netfilter/xt_TCPMSS.c
@@ -165,8 +165,8 @@ static u_int32_t tcpmss_reverse_mtu(const struct sk_buff *skb,
rcu_read_unlock();
if (rt != NULL) {
- mtu = dst_mtu(&rt->u.dst);
- dst_release(&rt->u.dst);
+ mtu = dst_mtu(&rt->dst);
+ dst_release(&rt->dst);
}
return mtu;
}
@@ -220,15 +220,13 @@ tcpmss_tg6(struct sk_buff *skb, const struct xt_action_param *par)
}
#endif
-#define TH_SYN 0x02
-
/* Must specify -p tcp --syn */
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->flg_cmp & TCPHDR_SYN &&
!(tcpinfo->invflags & XT_TCP_INV_FLAGS))
return true;
diff --git a/net/netfilter/xt_TEE.c b/net/netfilter/xt_TEE.c
index 859d9fd429c..22a2d421e7e 100644
--- a/net/netfilter/xt_TEE.c
+++ b/net/netfilter/xt_TEE.c
@@ -77,8 +77,8 @@ tee_tg_route4(struct sk_buff *skb, const struct xt_tee_tginfo *info)
return false;
skb_dst_drop(skb);
- skb_dst_set(skb, &rt->u.dst);
- skb->dev = rt->u.dst.dev;
+ skb_dst_set(skb, &rt->dst);
+ skb->dev = rt->dst.dev;
skb->protocol = htons(ETH_P_IP);
return true;
}
@@ -104,7 +104,7 @@ tee_tg4(struct sk_buff *skb, const struct xt_action_param *par)
#ifdef WITH_CONNTRACK
/* Avoid counting cloned packets towards the original connection. */
nf_conntrack_put(skb->nfct);
- skb->nfct = &nf_conntrack_untracked.ct_general;
+ skb->nfct = &nf_ct_untracked_get()->ct_general;
skb->nfctinfo = IP_CT_NEW;
nf_conntrack_get(skb->nfct);
#endif
@@ -177,7 +177,7 @@ tee_tg6(struct sk_buff *skb, const struct xt_action_param *par)
#ifdef WITH_CONNTRACK
nf_conntrack_put(skb->nfct);
- skb->nfct = &nf_conntrack_untracked.ct_general;
+ skb->nfct = &nf_ct_untracked_get()->ct_general;
skb->nfctinfo = IP_CT_NEW;
nf_conntrack_get(skb->nfct);
#endif
diff --git a/net/netfilter/xt_TPROXY.c b/net/netfilter/xt_TPROXY.c
index e1a0dedac25..c61294d85fd 100644
--- a/net/netfilter/xt_TPROXY.c
+++ b/net/netfilter/xt_TPROXY.c
@@ -37,8 +37,10 @@ tproxy_tg(struct sk_buff *skb, const struct xt_action_param *par)
return NF_DROP;
sk = nf_tproxy_get_sock_v4(dev_net(skb->dev), iph->protocol,
- iph->saddr, tgi->laddr ? tgi->laddr : iph->daddr,
- hp->source, tgi->lport ? tgi->lport : hp->dest,
+ iph->saddr,
+ tgi->laddr ? tgi->laddr : iph->daddr,
+ hp->source,
+ tgi->lport ? tgi->lport : hp->dest,
par->in, true);
/* NOTE: assign_sock consumes our sk reference */
diff --git a/net/netfilter/xt_cluster.c b/net/netfilter/xt_cluster.c
index 30b95a1c1c8..f4af1bfafb1 100644
--- a/net/netfilter/xt_cluster.c
+++ b/net/netfilter/xt_cluster.c
@@ -120,7 +120,7 @@ xt_cluster_mt(const struct sk_buff *skb, struct xt_action_param *par)
if (ct == NULL)
return false;
- if (ct == &nf_conntrack_untracked)
+ if (nf_ct_is_untracked(ct))
return false;
if (ct->master)
diff --git a/net/netfilter/xt_connbytes.c b/net/netfilter/xt_connbytes.c
index 73517835303..5b138506690 100644
--- a/net/netfilter/xt_connbytes.c
+++ b/net/netfilter/xt_connbytes.c
@@ -112,6 +112,16 @@ static int connbytes_mt_check(const struct xt_mtchk_param *par)
if (ret < 0)
pr_info("cannot load conntrack support for proto=%u\n",
par->family);
+
+ /*
+ * This filter cannot function correctly unless connection tracking
+ * accounting is enabled, so complain in the hope that someone notices.
+ */
+ if (!nf_ct_acct_enabled(par->net)) {
+ pr_warning("Forcing CT accounting to be enabled\n");
+ nf_ct_set_acct(par->net, true);
+ }
+
return ret;
}
diff --git a/net/netfilter/xt_conntrack.c b/net/netfilter/xt_conntrack.c
index 39681f10291..e536710ad91 100644
--- a/net/netfilter/xt_conntrack.c
+++ b/net/netfilter/xt_conntrack.c
@@ -123,11 +123,12 @@ conntrack_mt(const struct sk_buff *skb, struct xt_action_param *par,
ct = nf_ct_get(skb, &ctinfo);
- if (ct == &nf_conntrack_untracked)
- statebit = XT_CONNTRACK_STATE_UNTRACKED;
- else if (ct != NULL)
- statebit = XT_CONNTRACK_STATE_BIT(ctinfo);
- else
+ if (ct) {
+ if (nf_ct_is_untracked(ct))
+ statebit = XT_CONNTRACK_STATE_UNTRACKED;
+ else
+ statebit = XT_CONNTRACK_STATE_BIT(ctinfo);
+ } else
statebit = XT_CONNTRACK_STATE_INVALID;
if (info->match_flags & XT_CONNTRACK_STATE) {
diff --git a/net/netfilter/xt_cpu.c b/net/netfilter/xt_cpu.c
new file mode 100644
index 00000000000..b39db8a5cba
--- /dev/null
+++ b/net/netfilter/xt_cpu.c
@@ -0,0 +1,63 @@
+/* Kernel module to match running CPU */
+
+/*
+ * Might be used to distribute connections on several daemons, if
+ * RPS (Remote Packet Steering) is enabled or NIC is multiqueue capable,
+ * each RX queue IRQ affined to one CPU (1:1 mapping)
+ *
+ */
+
+/* (C) 2010 Eric Dumazet
+ *
+ * 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/skbuff.h>
+#include <linux/netfilter/xt_cpu.h>
+#include <linux/netfilter/x_tables.h>
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Eric Dumazet <eric.dumazet@gmail.com>");
+MODULE_DESCRIPTION("Xtables: CPU match");
+
+static int cpu_mt_check(const struct xt_mtchk_param *par)
+{
+ const struct xt_cpu_info *info = par->matchinfo;
+
+ if (info->invert & ~1)
+ return -EINVAL;
+ return 0;
+}
+
+static bool cpu_mt(const struct sk_buff *skb, struct xt_action_param *par)
+{
+ const struct xt_cpu_info *info = par->matchinfo;
+
+ return (info->cpu == smp_processor_id()) ^ info->invert;
+}
+
+static struct xt_match cpu_mt_reg __read_mostly = {
+ .name = "cpu",
+ .revision = 0,
+ .family = NFPROTO_UNSPEC,
+ .checkentry = cpu_mt_check,
+ .match = cpu_mt,
+ .matchsize = sizeof(struct xt_cpu_info),
+ .me = THIS_MODULE,
+};
+
+static int __init cpu_mt_init(void)
+{
+ return xt_register_match(&cpu_mt_reg);
+}
+
+static void __exit cpu_mt_exit(void)
+{
+ xt_unregister_match(&cpu_mt_reg);
+}
+
+module_init(cpu_mt_init);
+module_exit(cpu_mt_exit);
diff --git a/net/netfilter/xt_ipvs.c b/net/netfilter/xt_ipvs.c
new file mode 100644
index 00000000000..7a4d66db95a
--- /dev/null
+++ b/net/netfilter/xt_ipvs.c
@@ -0,0 +1,189 @@
+/*
+ * xt_ipvs - kernel module to match IPVS connection properties
+ *
+ * Author: Hannes Eder <heder@google.com>
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/spinlock.h>
+#include <linux/skbuff.h>
+#ifdef CONFIG_IP_VS_IPV6
+#include <net/ipv6.h>
+#endif
+#include <linux/ip_vs.h>
+#include <linux/types.h>
+#include <linux/netfilter/x_tables.h>
+#include <linux/netfilter/x_tables.h>
+#include <linux/netfilter/xt_ipvs.h>
+#include <net/netfilter/nf_conntrack.h>
+
+#include <net/ip_vs.h>
+
+MODULE_AUTHOR("Hannes Eder <heder@google.com>");
+MODULE_DESCRIPTION("Xtables: match IPVS connection properties");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("ipt_ipvs");
+MODULE_ALIAS("ip6t_ipvs");
+
+/* borrowed from xt_conntrack */
+static bool ipvs_mt_addrcmp(const union nf_inet_addr *kaddr,
+ const union nf_inet_addr *uaddr,
+ const union nf_inet_addr *umask,
+ unsigned int l3proto)
+{
+ if (l3proto == NFPROTO_IPV4)
+ return ((kaddr->ip ^ uaddr->ip) & umask->ip) == 0;
+#ifdef CONFIG_IP_VS_IPV6
+ else if (l3proto == NFPROTO_IPV6)
+ return ipv6_masked_addr_cmp(&kaddr->in6, &umask->in6,
+ &uaddr->in6) == 0;
+#endif
+ else
+ return false;
+}
+
+static bool
+ipvs_mt(const struct sk_buff *skb, struct xt_action_param *par)
+{
+ const struct xt_ipvs_mtinfo *data = par->matchinfo;
+ /* ipvs_mt_check ensures that family is only NFPROTO_IPV[46]. */
+ const u_int8_t family = par->family;
+ struct ip_vs_iphdr iph;
+ struct ip_vs_protocol *pp;
+ struct ip_vs_conn *cp;
+ bool match = true;
+
+ if (data->bitmask == XT_IPVS_IPVS_PROPERTY) {
+ match = skb->ipvs_property ^
+ !!(data->invert & XT_IPVS_IPVS_PROPERTY);
+ goto out;
+ }
+
+ /* other flags than XT_IPVS_IPVS_PROPERTY are set */
+ if (!skb->ipvs_property) {
+ match = false;
+ goto out;
+ }
+
+ ip_vs_fill_iphdr(family, skb_network_header(skb), &iph);
+
+ if (data->bitmask & XT_IPVS_PROTO)
+ if ((iph.protocol == data->l4proto) ^
+ !(data->invert & XT_IPVS_PROTO)) {
+ match = false;
+ goto out;
+ }
+
+ pp = ip_vs_proto_get(iph.protocol);
+ if (unlikely(!pp)) {
+ match = false;
+ goto out;
+ }
+
+ /*
+ * Check if the packet belongs to an existing entry
+ */
+ cp = pp->conn_out_get(family, skb, pp, &iph, iph.len, 1 /* inverse */);
+ if (unlikely(cp == NULL)) {
+ match = false;
+ goto out;
+ }
+
+ /*
+ * We found a connection, i.e. ct != 0, make sure to call
+ * __ip_vs_conn_put before returning. In our case jump to out_put_con.
+ */
+
+ if (data->bitmask & XT_IPVS_VPORT)
+ if ((cp->vport == data->vport) ^
+ !(data->invert & XT_IPVS_VPORT)) {
+ match = false;
+ goto out_put_cp;
+ }
+
+ if (data->bitmask & XT_IPVS_VPORTCTL)
+ if ((cp->control != NULL &&
+ cp->control->vport == data->vportctl) ^
+ !(data->invert & XT_IPVS_VPORTCTL)) {
+ match = false;
+ goto out_put_cp;
+ }
+
+ if (data->bitmask & XT_IPVS_DIR) {
+ enum ip_conntrack_info ctinfo;
+ struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
+
+ if (ct == NULL || nf_ct_is_untracked(ct)) {
+ match = false;
+ goto out_put_cp;
+ }
+
+ if ((ctinfo >= IP_CT_IS_REPLY) ^
+ !!(data->invert & XT_IPVS_DIR)) {
+ match = false;
+ goto out_put_cp;
+ }
+ }
+
+ if (data->bitmask & XT_IPVS_METHOD)
+ if (((cp->flags & IP_VS_CONN_F_FWD_MASK) == data->fwd_method) ^
+ !(data->invert & XT_IPVS_METHOD)) {
+ match = false;
+ goto out_put_cp;
+ }
+
+ if (data->bitmask & XT_IPVS_VADDR) {
+ if (ipvs_mt_addrcmp(&cp->vaddr, &data->vaddr,
+ &data->vmask, family) ^
+ !(data->invert & XT_IPVS_VADDR)) {
+ match = false;
+ goto out_put_cp;
+ }
+ }
+
+out_put_cp:
+ __ip_vs_conn_put(cp);
+out:
+ pr_debug("match=%d\n", match);
+ return match;
+}
+
+static int ipvs_mt_check(const struct xt_mtchk_param *par)
+{
+ if (par->family != NFPROTO_IPV4
+#ifdef CONFIG_IP_VS_IPV6
+ && par->family != NFPROTO_IPV6
+#endif
+ ) {
+ pr_info("protocol family %u not supported\n", par->family);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static struct xt_match xt_ipvs_mt_reg __read_mostly = {
+ .name = "ipvs",
+ .revision = 0,
+ .family = NFPROTO_UNSPEC,
+ .match = ipvs_mt,
+ .checkentry = ipvs_mt_check,
+ .matchsize = XT_ALIGN(sizeof(struct xt_ipvs_mtinfo)),
+ .me = THIS_MODULE,
+};
+
+static int __init ipvs_mt_init(void)
+{
+ return xt_register_match(&xt_ipvs_mt_reg);
+}
+
+static void __exit ipvs_mt_exit(void)
+{
+ xt_unregister_match(&xt_ipvs_mt_reg);
+}
+
+module_init(ipvs_mt_init);
+module_exit(ipvs_mt_exit);
diff --git a/net/netfilter/xt_quota.c b/net/netfilter/xt_quota.c
index b4f7dfea598..70eb2b4984d 100644
--- a/net/netfilter/xt_quota.c
+++ b/net/netfilter/xt_quota.c
@@ -11,7 +11,8 @@
#include <linux/netfilter/xt_quota.h>
struct xt_quota_priv {
- uint64_t quota;
+ spinlock_t lock;
+ uint64_t quota;
};
MODULE_LICENSE("GPL");
@@ -20,8 +21,6 @@ MODULE_DESCRIPTION("Xtables: countdown quota match");
MODULE_ALIAS("ipt_quota");
MODULE_ALIAS("ip6t_quota");
-static DEFINE_SPINLOCK(quota_lock);
-
static bool
quota_mt(const struct sk_buff *skb, struct xt_action_param *par)
{
@@ -29,7 +28,7 @@ quota_mt(const struct sk_buff *skb, struct xt_action_param *par)
struct xt_quota_priv *priv = q->master;
bool ret = q->flags & XT_QUOTA_INVERT;
- spin_lock_bh(&quota_lock);
+ spin_lock_bh(&priv->lock);
if (priv->quota >= skb->len) {
priv->quota -= skb->len;
ret = !ret;
@@ -37,9 +36,7 @@ quota_mt(const struct sk_buff *skb, struct xt_action_param *par)
/* we do not allow even small packets from now on */
priv->quota = 0;
}
- /* Copy quota back to matchinfo so that iptables can display it */
- q->quota = priv->quota;
- spin_unlock_bh(&quota_lock);
+ spin_unlock_bh(&priv->lock);
return ret;
}
@@ -55,6 +52,7 @@ static int quota_mt_check(const struct xt_mtchk_param *par)
if (q->master == NULL)
return -ENOMEM;
+ spin_lock_init(&q->master->lock);
q->master->quota = q->quota;
return 0;
}
diff --git a/net/netfilter/xt_sctp.c b/net/netfilter/xt_sctp.c
index c04fcf385c5..ef36a56a02c 100644
--- a/net/netfilter/xt_sctp.c
+++ b/net/netfilter/xt_sctp.c
@@ -3,6 +3,7 @@
#include <linux/skbuff.h>
#include <net/ip.h>
#include <net/ipv6.h>
+#include <net/sctp/sctp.h>
#include <linux/sctp.h>
#include <linux/netfilter/x_tables.h>
@@ -67,7 +68,7 @@ match_packet(const struct sk_buff *skb,
++i, offset, sch->type, htons(sch->length),
sch->flags);
#endif
- offset += (ntohs(sch->length) + 3) & ~3;
+ offset += WORD_ROUND(ntohs(sch->length));
pr_debug("skb->len: %d\toffset: %d\n", skb->len, offset);
diff --git a/net/netfilter/xt_socket.c b/net/netfilter/xt_socket.c
index 3d54c236a1b..1ca89908cba 100644
--- a/net/netfilter/xt_socket.c
+++ b/net/netfilter/xt_socket.c
@@ -127,7 +127,7 @@ socket_match(const struct sk_buff *skb, struct xt_action_param *par,
* reply packet of an established SNAT-ted connection. */
ct = nf_ct_get(skb, &ctinfo);
- if (ct && (ct != &nf_conntrack_untracked) &&
+ if (ct && !nf_ct_is_untracked(ct) &&
((iph->protocol != IPPROTO_ICMP &&
ctinfo == IP_CT_IS_REPLY + IP_CT_ESTABLISHED) ||
(iph->protocol == IPPROTO_ICMP &&
diff --git a/net/netfilter/xt_state.c b/net/netfilter/xt_state.c
index e12e053d378..a507922d80c 100644
--- a/net/netfilter/xt_state.c
+++ b/net/netfilter/xt_state.c
@@ -26,14 +26,16 @@ state_mt(const struct sk_buff *skb, struct xt_action_param *par)
const struct xt_state_info *sinfo = par->matchinfo;
enum ip_conntrack_info ctinfo;
unsigned int statebit;
+ struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
- if (nf_ct_is_untracked(skb))
- statebit = XT_STATE_UNTRACKED;
- else if (!nf_ct_get(skb, &ctinfo))
+ if (!ct)
statebit = XT_STATE_INVALID;
- else
- statebit = XT_STATE_BIT(ctinfo);
-
+ else {
+ if (nf_ct_is_untracked(ct))
+ statebit = XT_STATE_UNTRACKED;
+ else
+ statebit = XT_STATE_BIT(ctinfo);
+ }
return (sinfo->statemask & statebit);
}
diff --git a/net/netfilter/xt_statistic.c b/net/netfilter/xt_statistic.c
index 96e62b8fd6b..42ecb71d445 100644
--- a/net/netfilter/xt_statistic.c
+++ b/net/netfilter/xt_statistic.c
@@ -18,8 +18,8 @@
#include <linux/netfilter/x_tables.h>
struct xt_statistic_priv {
- uint32_t count;
-};
+ atomic_t count;
+} ____cacheline_aligned_in_smp;
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
@@ -27,13 +27,12 @@ MODULE_DESCRIPTION("Xtables: statistics-based matching (\"Nth\", random)");
MODULE_ALIAS("ipt_statistic");
MODULE_ALIAS("ip6t_statistic");
-static DEFINE_SPINLOCK(nth_lock);
-
static bool
statistic_mt(const struct sk_buff *skb, struct xt_action_param *par)
{
const struct xt_statistic_info *info = par->matchinfo;
bool ret = info->flags & XT_STATISTIC_INVERT;
+ int nval, oval;
switch (info->mode) {
case XT_STATISTIC_MODE_RANDOM:
@@ -41,12 +40,12 @@ statistic_mt(const struct sk_buff *skb, struct xt_action_param *par)
ret = !ret;
break;
case XT_STATISTIC_MODE_NTH:
- spin_lock_bh(&nth_lock);
- if (info->master->count++ == info->u.nth.every) {
- info->master->count = 0;
+ do {
+ oval = atomic_read(&info->master->count);
+ nval = (oval == info->u.nth.every) ? 0 : oval + 1;
+ } while (atomic_cmpxchg(&info->master->count, oval, nval) != oval);
+ if (nval == 0)
ret = !ret;
- }
- spin_unlock_bh(&nth_lock);
break;
}
@@ -64,7 +63,7 @@ static int statistic_mt_check(const struct xt_mtchk_param *par)
info->master = kzalloc(sizeof(*info->master), GFP_KERNEL);
if (info->master == NULL)
return -ENOMEM;
- info->master->count = info->u.nth.count;
+ atomic_set(&info->master->count, info->u.nth.count);
return 0;
}
diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c
index a2eb965207d..2cbf380377d 100644
--- a/net/netlink/af_netlink.c
+++ b/net/netlink/af_netlink.c
@@ -1076,14 +1076,15 @@ int netlink_broadcast_filtered(struct sock *ssk, struct sk_buff *skb, u32 pid,
sk_for_each_bound(sk, node, &nl_table[ssk->sk_protocol].mc_list)
do_one_broadcast(sk, &info);
- kfree_skb(skb);
+ consume_skb(skb);
netlink_unlock_table();
- kfree_skb(info.skb2);
-
- if (info.delivery_failure)
+ if (info.delivery_failure) {
+ kfree_skb(info.skb2);
return -ENOBUFS;
+ } else
+ consume_skb(info.skb2);
if (info.delivered) {
if (info.congested && (allocation & __GFP_WAIT))
@@ -1323,19 +1324,23 @@ static int netlink_sendmsg(struct kiocb *kiocb, struct socket *sock,
if (msg->msg_flags&MSG_OOB)
return -EOPNOTSUPP;
- if (NULL == siocb->scm)
+ if (NULL == siocb->scm) {
siocb->scm = &scm;
+ memset(&scm, 0, sizeof(scm));
+ }
err = scm_send(sock, msg, siocb->scm);
if (err < 0)
return err;
if (msg->msg_namelen) {
+ err = -EINVAL;
if (addr->nl_family != AF_NETLINK)
- return -EINVAL;
+ goto out;
dst_pid = addr->nl_pid;
dst_group = ffs(addr->nl_groups);
+ err = -EPERM;
if (dst_group && !netlink_capable(sock, NL_NONROOT_SEND))
- return -EPERM;
+ goto out;
} else {
dst_pid = nlk->dst_pid;
dst_group = nlk->dst_group;
@@ -1387,6 +1392,7 @@ static int netlink_sendmsg(struct kiocb *kiocb, struct socket *sock,
err = netlink_unicast(sk, skb, dst_pid, msg->msg_flags&MSG_DONTWAIT);
out:
+ scm_destroy(siocb->scm);
return err;
}
@@ -1400,7 +1406,7 @@ static int netlink_recvmsg(struct kiocb *kiocb, struct socket *sock,
struct netlink_sock *nlk = nlk_sk(sk);
int noblock = flags&MSG_DONTWAIT;
size_t copied;
- struct sk_buff *skb, *frag __maybe_unused = NULL;
+ struct sk_buff *skb;
int err;
if (flags&MSG_OOB)
@@ -1435,7 +1441,21 @@ static int netlink_recvmsg(struct kiocb *kiocb, struct socket *sock,
kfree_skb(skb);
skb = compskb;
} else {
- frag = skb_shinfo(skb)->frag_list;
+ /*
+ * Before setting frag_list to NULL, we must get a
+ * private copy of skb if shared (because of MSG_PEEK)
+ */
+ if (skb_shared(skb)) {
+ struct sk_buff *nskb;
+
+ nskb = pskb_copy(skb, GFP_KERNEL);
+ kfree_skb(skb);
+ skb = nskb;
+ err = -ENOMEM;
+ if (!skb)
+ goto out;
+ }
+ kfree_skb(skb_shinfo(skb)->frag_list);
skb_shinfo(skb)->frag_list = NULL;
}
}
@@ -1472,10 +1492,6 @@ static int netlink_recvmsg(struct kiocb *kiocb, struct socket *sock,
if (flags & MSG_TRUNC)
copied = skb->len;
-#ifdef CONFIG_COMPAT_NETLINK_MESSAGES
- skb_shinfo(skb)->frag_list = frag;
-#endif
-
skb_free_datagram(sk, skb);
if (nlk->cb && atomic_read(&sk->sk_rmem_alloc) <= sk->sk_rcvbuf / 2)
diff --git a/net/netlink/genetlink.c b/net/netlink/genetlink.c
index aa4308afcc7..26ed3e8587c 100644
--- a/net/netlink/genetlink.c
+++ b/net/netlink/genetlink.c
@@ -303,6 +303,7 @@ int genl_register_ops(struct genl_family *family, struct genl_ops *ops)
errout:
return err;
}
+EXPORT_SYMBOL(genl_register_ops);
/**
* genl_unregister_ops - unregister generic netlink operations
@@ -337,6 +338,7 @@ int genl_unregister_ops(struct genl_family *family, struct genl_ops *ops)
return -ENOENT;
}
+EXPORT_SYMBOL(genl_unregister_ops);
/**
* genl_register_family - register a generic netlink family
@@ -405,6 +407,7 @@ errout_locked:
errout:
return err;
}
+EXPORT_SYMBOL(genl_register_family);
/**
* genl_register_family_with_ops - register a generic netlink family
@@ -485,6 +488,7 @@ int genl_unregister_family(struct genl_family *family)
return -ENOENT;
}
+EXPORT_SYMBOL(genl_unregister_family);
static int genl_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
{
@@ -873,11 +877,7 @@ static int __init genl_init(void)
for (i = 0; i < GENL_FAM_TAB_SIZE; i++)
INIT_LIST_HEAD(&family_ht[i]);
- err = genl_register_family(&genl_ctrl);
- if (err < 0)
- goto problem;
-
- err = genl_register_ops(&genl_ctrl, &genl_ctrl_ops);
+ err = genl_register_family_with_ops(&genl_ctrl, &genl_ctrl_ops, 1);
if (err < 0)
goto problem;
@@ -899,11 +899,6 @@ problem:
subsys_initcall(genl_init);
-EXPORT_SYMBOL(genl_register_ops);
-EXPORT_SYMBOL(genl_unregister_ops);
-EXPORT_SYMBOL(genl_register_family);
-EXPORT_SYMBOL(genl_unregister_family);
-
static int genlmsg_mcast(struct sk_buff *skb, u32 pid, unsigned long group,
gfp_t flags)
{
diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c
index 2078a277e06..9a17f28b125 100644
--- a/net/packet/af_packet.c
+++ b/net/packet/af_packet.c
@@ -83,6 +83,7 @@
#include <linux/if_vlan.h>
#include <linux/virtio_net.h>
#include <linux/errqueue.h>
+#include <linux/net_tstamp.h>
#ifdef CONFIG_INET
#include <net/inet_common.h>
@@ -202,6 +203,7 @@ struct packet_sock {
unsigned int tp_hdrlen;
unsigned int tp_reserve;
unsigned int tp_loss:1;
+ unsigned int tp_tstamp;
struct packet_type prot_hook ____cacheline_aligned_in_smp;
};
@@ -656,6 +658,7 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev,
struct sk_buff *copy_skb = NULL;
struct timeval tv;
struct timespec ts;
+ struct skb_shared_hwtstamps *shhwtstamps = skb_hwtstamps(skb);
if (skb->pkt_type == PACKET_LOOPBACK)
goto drop;
@@ -737,7 +740,13 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev,
h.h1->tp_snaplen = snaplen;
h.h1->tp_mac = macoff;
h.h1->tp_net = netoff;
- if (skb->tstamp.tv64)
+ if ((po->tp_tstamp & SOF_TIMESTAMPING_SYS_HARDWARE)
+ && shhwtstamps->syststamp.tv64)
+ tv = ktime_to_timeval(shhwtstamps->syststamp);
+ else if ((po->tp_tstamp & SOF_TIMESTAMPING_RAW_HARDWARE)
+ && shhwtstamps->hwtstamp.tv64)
+ tv = ktime_to_timeval(shhwtstamps->hwtstamp);
+ else if (skb->tstamp.tv64)
tv = ktime_to_timeval(skb->tstamp);
else
do_gettimeofday(&tv);
@@ -750,7 +759,13 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev,
h.h2->tp_snaplen = snaplen;
h.h2->tp_mac = macoff;
h.h2->tp_net = netoff;
- if (skb->tstamp.tv64)
+ if ((po->tp_tstamp & SOF_TIMESTAMPING_SYS_HARDWARE)
+ && shhwtstamps->syststamp.tv64)
+ ts = ktime_to_timespec(shhwtstamps->syststamp);
+ else if ((po->tp_tstamp & SOF_TIMESTAMPING_RAW_HARDWARE)
+ && shhwtstamps->hwtstamp.tv64)
+ ts = ktime_to_timespec(shhwtstamps->hwtstamp);
+ else if (skb->tstamp.tv64)
ts = ktime_to_timespec(skb->tstamp);
else
getnstimeofday(&ts);
@@ -2027,6 +2042,18 @@ packet_setsockopt(struct socket *sock, int level, int optname, char __user *optv
po->has_vnet_hdr = !!val;
return 0;
}
+ case PACKET_TIMESTAMP:
+ {
+ int val;
+
+ if (optlen != sizeof(val))
+ return -EINVAL;
+ if (copy_from_user(&val, optval, sizeof(val)))
+ return -EFAULT;
+
+ po->tp_tstamp = val;
+ return 0;
+ }
default:
return -ENOPROTOOPT;
}
@@ -2119,6 +2146,12 @@ static int packet_getsockopt(struct socket *sock, int level, int optname,
val = po->tp_loss;
data = &val;
break;
+ case PACKET_TIMESTAMP:
+ if (len > sizeof(int))
+ len = sizeof(int);
+ val = po->tp_tstamp;
+ data = &val;
+ break;
default:
return -ENOPROTOOPT;
}
diff --git a/net/phonet/pn_dev.c b/net/phonet/pn_dev.c
index c33da657694..b18e48fae97 100644
--- a/net/phonet/pn_dev.c
+++ b/net/phonet/pn_dev.c
@@ -162,6 +162,14 @@ int phonet_address_add(struct net_device *dev, u8 addr)
return err;
}
+static void phonet_device_rcu_free(struct rcu_head *head)
+{
+ struct phonet_device *pnd;
+
+ pnd = container_of(head, struct phonet_device, rcu);
+ kfree(pnd);
+}
+
int phonet_address_del(struct net_device *dev, u8 addr)
{
struct phonet_device_list *pndevs = phonet_device_list(dev_net(dev));
@@ -179,10 +187,9 @@ int phonet_address_del(struct net_device *dev, u8 addr)
pnd = NULL;
mutex_unlock(&pndevs->lock);
- if (pnd) {
- synchronize_rcu();
- kfree(pnd);
- }
+ if (pnd)
+ call_rcu(&pnd->rcu, phonet_device_rcu_free);
+
return err;
}
diff --git a/net/rose/rose_route.c b/net/rose/rose_route.c
index cbc244a128b..b4fdaac233f 100644
--- a/net/rose/rose_route.c
+++ b/net/rose/rose_route.c
@@ -109,7 +109,9 @@ static int __must_check rose_add_node(struct rose_route_struct *rose_route,
init_timer(&rose_neigh->t0timer);
if (rose_route->ndigis != 0) {
- if ((rose_neigh->digipeat = kmalloc(sizeof(ax25_digi), GFP_KERNEL)) == NULL) {
+ rose_neigh->digipeat =
+ kmalloc(sizeof(ax25_digi), GFP_ATOMIC);
+ if (rose_neigh->digipeat == NULL) {
kfree(rose_neigh);
res = -ENOMEM;
goto out;
diff --git a/net/rxrpc/ar-peer.c b/net/rxrpc/ar-peer.c
index f0f85b0123f..9f1729bd60d 100644
--- a/net/rxrpc/ar-peer.c
+++ b/net/rxrpc/ar-peer.c
@@ -64,8 +64,8 @@ static void rxrpc_assess_MTU_size(struct rxrpc_peer *peer)
return;
}
- peer->if_mtu = dst_mtu(&rt->u.dst);
- dst_release(&rt->u.dst);
+ peer->if_mtu = dst_mtu(&rt->dst);
+ dst_release(&rt->dst);
_leave(" [if_mtu %u]", peer->if_mtu);
}
diff --git a/net/sched/act_api.c b/net/sched/act_api.c
index 972378f47f3..23b25f89e7e 100644
--- a/net/sched/act_api.c
+++ b/net/sched/act_api.c
@@ -26,6 +26,11 @@
#include <net/act_api.h>
#include <net/netlink.h>
+static void tcf_common_free_rcu(struct rcu_head *head)
+{
+ kfree(container_of(head, struct tcf_common, tcfc_rcu));
+}
+
void tcf_hash_destroy(struct tcf_common *p, struct tcf_hashinfo *hinfo)
{
unsigned int h = tcf_hash(p->tcfc_index, hinfo->hmask);
@@ -38,7 +43,11 @@ void tcf_hash_destroy(struct tcf_common *p, struct tcf_hashinfo *hinfo)
write_unlock_bh(hinfo->lock);
gen_kill_estimator(&p->tcfc_bstats,
&p->tcfc_rate_est);
- kfree(p);
+ /*
+ * gen_estimator est_timer() might access p->tcfc_lock
+ * or bstats, wait a RCU grace period before freeing p
+ */
+ call_rcu(&p->tcfc_rcu, tcf_common_free_rcu);
return;
}
}
diff --git a/net/sched/act_mirred.c b/net/sched/act_mirred.c
index 1980b71c283..11f195af2da 100644
--- a/net/sched/act_mirred.c
+++ b/net/sched/act_mirred.c
@@ -165,6 +165,8 @@ static int tcf_mirred(struct sk_buff *skb, struct tc_action *a,
spin_lock(&m->tcf_lock);
m->tcf_tm.lastuse = jiffies;
+ m->tcf_bstats.bytes += qdisc_pkt_len(skb);
+ m->tcf_bstats.packets++;
dev = m->tcfm_dev;
if (!dev) {
@@ -179,13 +181,11 @@ static int tcf_mirred(struct sk_buff *skb, struct tc_action *a,
goto out;
}
- skb2 = skb_act_clone(skb, GFP_ATOMIC);
+ at = G_TC_AT(skb->tc_verd);
+ skb2 = skb_act_clone(skb, GFP_ATOMIC, m->tcf_action);
if (skb2 == NULL)
goto out;
- m->tcf_bstats.bytes += qdisc_pkt_len(skb2);
- m->tcf_bstats.packets++;
- at = G_TC_AT(skb->tc_verd);
if (!(at & AT_EGRESS)) {
if (m->tcfm_ok_push)
skb_push(skb2, skb2->dev->hard_header_len);
@@ -195,16 +195,14 @@ static int tcf_mirred(struct sk_buff *skb, struct tc_action *a,
if (m->tcfm_eaction != TCA_EGRESS_MIRROR)
skb2->tc_verd = SET_TC_FROM(skb2->tc_verd, at);
- skb2->dev = dev;
skb2->skb_iif = skb->dev->ifindex;
+ skb2->dev = dev;
dev_queue_xmit(skb2);
err = 0;
out:
if (err) {
m->tcf_qstats.overlimits++;
- m->tcf_bstats.bytes += qdisc_pkt_len(skb);
- m->tcf_bstats.packets++;
/* should we be asking for packet to be dropped?
* may make sense for redirect case only
*/
diff --git a/net/sched/act_nat.c b/net/sched/act_nat.c
index 724553e8ed7..d0386a413e8 100644
--- a/net/sched/act_nat.c
+++ b/net/sched/act_nat.c
@@ -218,6 +218,7 @@ static int tcf_nat(struct sk_buff *skb, struct tc_action *a,
if (!pskb_may_pull(skb, ihl + sizeof(*icmph) + sizeof(*iph)))
goto drop;
+ icmph = (void *)(skb_network_header(skb) + ihl);
iph = (void *)(icmph + 1);
if (egress)
addr = iph->daddr;
@@ -246,7 +247,7 @@ static int tcf_nat(struct sk_buff *skb, struct tc_action *a,
iph->saddr = new_addr;
inet_proto_csum_replace4(&icmph->checksum, skb, addr, new_addr,
- 1);
+ 0);
break;
}
default:
@@ -268,40 +269,29 @@ static int tcf_nat_dump(struct sk_buff *skb, struct tc_action *a,
{
unsigned char *b = skb_tail_pointer(skb);
struct tcf_nat *p = a->priv;
- struct tc_nat *opt;
+ struct tc_nat opt;
struct tcf_t t;
- int s;
-
- s = sizeof(*opt);
- /* netlink spinlocks held above us - must use ATOMIC */
- opt = kzalloc(s, GFP_ATOMIC);
- if (unlikely(!opt))
- return -ENOBUFS;
+ opt.old_addr = p->old_addr;
+ opt.new_addr = p->new_addr;
+ opt.mask = p->mask;
+ opt.flags = p->flags;
- opt->old_addr = p->old_addr;
- opt->new_addr = p->new_addr;
- opt->mask = p->mask;
- opt->flags = p->flags;
+ opt.index = p->tcf_index;
+ opt.action = p->tcf_action;
+ opt.refcnt = p->tcf_refcnt - ref;
+ opt.bindcnt = p->tcf_bindcnt - bind;
- opt->index = p->tcf_index;
- opt->action = p->tcf_action;
- opt->refcnt = p->tcf_refcnt - ref;
- opt->bindcnt = p->tcf_bindcnt - bind;
-
- NLA_PUT(skb, TCA_NAT_PARMS, s, opt);
+ NLA_PUT(skb, TCA_NAT_PARMS, sizeof(opt), &opt);
t.install = jiffies_to_clock_t(jiffies - p->tcf_tm.install);
t.lastuse = jiffies_to_clock_t(jiffies - p->tcf_tm.lastuse);
t.expires = jiffies_to_clock_t(p->tcf_tm.expires);
NLA_PUT(skb, TCA_NAT_TM, sizeof(t), &t);
- kfree(opt);
-
return skb->len;
nla_put_failure:
nlmsg_trim(skb, b);
- kfree(opt);
return -1;
}
diff --git a/net/sched/act_pedit.c b/net/sched/act_pedit.c
index 50e3d945e1f..a0593c9640d 100644
--- a/net/sched/act_pedit.c
+++ b/net/sched/act_pedit.c
@@ -127,8 +127,7 @@ static int tcf_pedit(struct sk_buff *skb, struct tc_action *a,
int i, munged = 0;
unsigned int off;
- if (!(skb->tc_verd & TC_OK2MUNGE)) {
- /* should we set skb->cloned? */
+ if (skb_cloned(skb)) {
if (pskb_expand_head(skb, 0, 0, GFP_ATOMIC)) {
return p->tcf_action;
}
diff --git a/net/sched/act_police.c b/net/sched/act_police.c
index 654f73dff7c..537a48732e9 100644
--- a/net/sched/act_police.c
+++ b/net/sched/act_police.c
@@ -97,6 +97,11 @@ nla_put_failure:
goto done;
}
+static void tcf_police_free_rcu(struct rcu_head *head)
+{
+ kfree(container_of(head, struct tcf_police, tcf_rcu));
+}
+
static void tcf_police_destroy(struct tcf_police *p)
{
unsigned int h = tcf_hash(p->tcf_index, POL_TAB_MASK);
@@ -113,7 +118,11 @@ static void tcf_police_destroy(struct tcf_police *p)
qdisc_put_rtab(p->tcfp_R_tab);
if (p->tcfp_P_tab)
qdisc_put_rtab(p->tcfp_P_tab);
- kfree(p);
+ /*
+ * gen_estimator est_timer() might access p->tcf_lock
+ * or bstats, wait a RCU grace period before freeing p
+ */
+ call_rcu(&p->tcf_rcu, tcf_police_free_rcu);
return;
}
}
@@ -397,6 +406,7 @@ static void __exit
police_cleanup_module(void)
{
tcf_unregister_action(&act_police_ops);
+ rcu_barrier(); /* Wait for completion of call_rcu()'s (tcf_police_free_rcu) */
}
module_init(police_init_module);
diff --git a/net/sched/act_simple.c b/net/sched/act_simple.c
index 1b4bc691d7d..4a1d640b0cf 100644
--- a/net/sched/act_simple.c
+++ b/net/sched/act_simple.c
@@ -73,10 +73,10 @@ static int tcf_simp_release(struct tcf_defact *d, int bind)
static int alloc_defdata(struct tcf_defact *d, char *defdata)
{
- d->tcfd_defdata = kstrndup(defdata, SIMP_MAX_DATA, GFP_KERNEL);
+ d->tcfd_defdata = kzalloc(SIMP_MAX_DATA, GFP_KERNEL);
if (unlikely(!d->tcfd_defdata))
return -ENOMEM;
-
+ strlcpy(d->tcfd_defdata, defdata, SIMP_MAX_DATA);
return 0;
}
diff --git a/net/sched/cls_u32.c b/net/sched/cls_u32.c
index 4f522143811..7416a5c73b2 100644
--- a/net/sched/cls_u32.c
+++ b/net/sched/cls_u32.c
@@ -134,10 +134,12 @@ next_knode:
#endif
for (i = n->sel.nkeys; i>0; i--, key++) {
- unsigned int toff;
+ int toff = off + key->off + (off2 & key->offmask);
__be32 *data, _data;
- toff = off + key->off + (off2 & key->offmask);
+ if (skb_headroom(skb) + toff < 0)
+ goto out;
+
data = skb_header_pointer(skb, toff, 4, &_data);
if (!data)
goto out;
diff --git a/net/sched/sch_atm.c b/net/sched/sch_atm.c
index fcbb86a486a..e114f23d5ea 100644
--- a/net/sched/sch_atm.c
+++ b/net/sched/sch_atm.c
@@ -52,7 +52,7 @@ struct atm_flow_data {
int ref; /* reference count */
struct gnet_stats_basic_packed bstats;
struct gnet_stats_queue qstats;
- struct atm_flow_data *next;
+ struct list_head list;
struct atm_flow_data *excess; /* flow for excess traffic;
NULL to set CLP instead */
int hdr_len;
@@ -61,34 +61,23 @@ struct atm_flow_data {
struct atm_qdisc_data {
struct atm_flow_data link; /* unclassified skbs go here */
- struct atm_flow_data *flows; /* NB: "link" is also on this
+ struct list_head flows; /* NB: "link" is also on this
list */
struct tasklet_struct task; /* dequeue tasklet */
};
/* ------------------------- Class/flow operations ------------------------- */
-static int find_flow(struct atm_qdisc_data *qdisc, struct atm_flow_data *flow)
-{
- struct atm_flow_data *walk;
-
- pr_debug("find_flow(qdisc %p,flow %p)\n", qdisc, flow);
- for (walk = qdisc->flows; walk; walk = walk->next)
- if (walk == flow)
- return 1;
- pr_debug("find_flow: not found\n");
- return 0;
-}
-
static inline struct atm_flow_data *lookup_flow(struct Qdisc *sch, u32 classid)
{
struct atm_qdisc_data *p = qdisc_priv(sch);
struct atm_flow_data *flow;
- for (flow = p->flows; flow; flow = flow->next)
+ list_for_each_entry(flow, &p->flows, list) {
if (flow->classid == classid)
- break;
- return flow;
+ return flow;
+ }
+ return NULL;
}
static int atm_tc_graft(struct Qdisc *sch, unsigned long arg,
@@ -99,7 +88,7 @@ static int atm_tc_graft(struct Qdisc *sch, unsigned long arg,
pr_debug("atm_tc_graft(sch %p,[qdisc %p],flow %p,new %p,old %p)\n",
sch, p, flow, new, old);
- if (!find_flow(p, flow))
+ if (list_empty(&flow->list))
return -EINVAL;
if (!new)
new = &noop_qdisc;
@@ -146,20 +135,12 @@ static void atm_tc_put(struct Qdisc *sch, unsigned long cl)
{
struct atm_qdisc_data *p = qdisc_priv(sch);
struct atm_flow_data *flow = (struct atm_flow_data *)cl;
- struct atm_flow_data **prev;
pr_debug("atm_tc_put(sch %p,[qdisc %p],flow %p)\n", sch, p, flow);
if (--flow->ref)
return;
pr_debug("atm_tc_put: destroying\n");
- for (prev = &p->flows; *prev; prev = &(*prev)->next)
- if (*prev == flow)
- break;
- if (!*prev) {
- printk(KERN_CRIT "atm_tc_put: class %p not found\n", flow);
- return;
- }
- *prev = flow->next;
+ list_del_init(&flow->list);
pr_debug("atm_tc_put: qdisc %p\n", flow->q);
qdisc_destroy(flow->q);
tcf_destroy_chain(&flow->filter_list);
@@ -274,7 +255,7 @@ static int atm_tc_change(struct Qdisc *sch, u32 classid, u32 parent,
error = -EINVAL;
goto err_out;
}
- if (find_flow(p, flow)) {
+ if (!list_empty(&flow->list)) {
error = -EEXIST;
goto err_out;
}
@@ -313,8 +294,7 @@ static int atm_tc_change(struct Qdisc *sch, u32 classid, u32 parent,
flow->classid = classid;
flow->ref = 1;
flow->excess = excess;
- flow->next = p->link.next;
- p->link.next = flow;
+ list_add(&flow->list, &p->link.list);
flow->hdr_len = hdr_len;
if (hdr)
memcpy(flow->hdr, hdr, hdr_len);
@@ -335,7 +315,7 @@ static int atm_tc_delete(struct Qdisc *sch, unsigned long arg)
struct atm_flow_data *flow = (struct atm_flow_data *)arg;
pr_debug("atm_tc_delete(sch %p,[qdisc %p],flow %p)\n", sch, p, flow);
- if (!find_flow(qdisc_priv(sch), flow))
+ if (list_empty(&flow->list))
return -EINVAL;
if (flow->filter_list || flow == &p->link)
return -EBUSY;
@@ -361,12 +341,12 @@ static void atm_tc_walk(struct Qdisc *sch, struct qdisc_walker *walker)
pr_debug("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) {
- walker->stop = 1;
- break;
- }
+ list_for_each_entry(flow, &p->flows, list) {
+ if (walker->count >= walker->skip &&
+ walker->fn(sch, (unsigned long)flow, walker) < 0) {
+ walker->stop = 1;
+ break;
+ }
walker->count++;
}
}
@@ -385,16 +365,17 @@ static struct tcf_proto **atm_tc_find_tcf(struct Qdisc *sch, unsigned long cl)
static int atm_tc_enqueue(struct sk_buff *skb, struct Qdisc *sch)
{
struct atm_qdisc_data *p = qdisc_priv(sch);
- struct atm_flow_data *flow = NULL; /* @@@ */
+ struct atm_flow_data *flow;
struct tcf_result res;
int result;
int ret = NET_XMIT_POLICED;
pr_debug("atm_tc_enqueue(skb %p,sch %p,[qdisc %p])\n", skb, sch, p);
result = TC_POLICE_OK; /* be nice to gcc */
+ flow = NULL;
if (TC_H_MAJ(skb->priority) != sch->handle ||
- !(flow = (struct atm_flow_data *)atm_tc_get(sch, skb->priority)))
- for (flow = p->flows; flow; flow = flow->next)
+ !(flow = (struct atm_flow_data *)atm_tc_get(sch, skb->priority))) {
+ list_for_each_entry(flow, &p->flows, list) {
if (flow->filter_list) {
result = tc_classify_compat(skb,
flow->filter_list,
@@ -404,8 +385,13 @@ static int atm_tc_enqueue(struct sk_buff *skb, struct Qdisc *sch)
flow = (struct atm_flow_data *)res.class;
if (!flow)
flow = lookup_flow(sch, res.classid);
- break;
+ goto done;
}
+ }
+ flow = NULL;
+ done:
+ ;
+ }
if (!flow)
flow = &p->link;
else {
@@ -477,7 +463,9 @@ static void sch_atm_dequeue(unsigned long data)
struct sk_buff *skb;
pr_debug("sch_atm_dequeue(sch %p,[qdisc %p])\n", sch, p);
- for (flow = p->link.next; flow; flow = flow->next)
+ list_for_each_entry(flow, &p->flows, list) {
+ if (flow == &p->link)
+ continue;
/*
* If traffic is properly shaped, this won't generate nasty
* little bursts. Otherwise, it may ... (but that's okay)
@@ -512,6 +500,7 @@ static void sch_atm_dequeue(unsigned long data)
/* atm.atm_options are already set by atm_tc_enqueue */
flow->vcc->send(flow->vcc, skb);
}
+ }
}
static struct sk_buff *atm_tc_dequeue(struct Qdisc *sch)
@@ -543,9 +532,10 @@ static unsigned int atm_tc_drop(struct Qdisc *sch)
unsigned int len;
pr_debug("atm_tc_drop(sch %p,[qdisc %p])\n", sch, p);
- for (flow = p->flows; flow; flow = flow->next)
+ list_for_each_entry(flow, &p->flows, list) {
if (flow->q->ops->drop && (len = flow->q->ops->drop(flow->q)))
return len;
+ }
return 0;
}
@@ -554,7 +544,9 @@ static int atm_tc_init(struct Qdisc *sch, struct nlattr *opt)
struct atm_qdisc_data *p = qdisc_priv(sch);
pr_debug("atm_tc_init(sch %p,[qdisc %p],opt %p)\n", sch, p, opt);
- p->flows = &p->link;
+ INIT_LIST_HEAD(&p->flows);
+ INIT_LIST_HEAD(&p->link.list);
+ list_add(&p->link.list, &p->flows);
p->link.q = qdisc_create_dflt(qdisc_dev(sch), sch->dev_queue,
&pfifo_qdisc_ops, sch->handle);
if (!p->link.q)
@@ -565,7 +557,6 @@ static int atm_tc_init(struct Qdisc *sch, struct nlattr *opt)
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);
return 0;
}
@@ -576,7 +567,7 @@ static void atm_tc_reset(struct Qdisc *sch)
struct atm_flow_data *flow;
pr_debug("atm_tc_reset(sch %p,[qdisc %p])\n", sch, p);
- for (flow = p->flows; flow; flow = flow->next)
+ list_for_each_entry(flow, &p->flows, list)
qdisc_reset(flow->q);
sch->q.qlen = 0;
}
@@ -584,24 +575,17 @@ static void atm_tc_reset(struct Qdisc *sch)
static void atm_tc_destroy(struct Qdisc *sch)
{
struct atm_qdisc_data *p = qdisc_priv(sch);
- struct atm_flow_data *flow;
+ struct atm_flow_data *flow, *tmp;
pr_debug("atm_tc_destroy(sch %p,[qdisc %p])\n", sch, p);
- for (flow = p->flows; flow; flow = flow->next)
+ list_for_each_entry(flow, &p->flows, list)
tcf_destroy_chain(&flow->filter_list);
- /* races ? */
- while ((flow = p->flows)) {
+ list_for_each_entry_safe(flow, tmp, &p->flows, list) {
if (flow->ref > 1)
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 */
- break;
- }
}
tasklet_kill(&p->task);
}
@@ -615,7 +599,7 @@ static int atm_tc_dump_class(struct Qdisc *sch, unsigned long cl,
pr_debug("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))
+ if (list_empty(&flow->list))
return -EINVAL;
tcm->tcm_handle = flow->classid;
tcm->tcm_info = flow->q->handle;
diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c
index a63029ef3ed..2aeb3a4386a 100644
--- a/net/sched/sch_generic.c
+++ b/net/sched/sch_generic.c
@@ -96,7 +96,7 @@ static inline int handle_dev_cpu_collision(struct sk_buff *skb,
* Another cpu is holding lock, requeue & delay xmits for
* some time.
*/
- __get_cpu_var(softnet_data).cpu_collision++;
+ __this_cpu_inc(softnet_data.cpu_collision);
ret = dev_requeue_skb(skb, q);
}
@@ -205,7 +205,7 @@ void __qdisc_run(struct Qdisc *q)
}
}
- clear_bit(__QDISC_STATE_RUNNING, &q->state);
+ qdisc_run_end(q);
}
unsigned long dev_trans_start(struct net_device *dev)
@@ -327,6 +327,24 @@ void netif_carrier_off(struct net_device *dev)
}
EXPORT_SYMBOL(netif_carrier_off);
+/**
+ * netif_notify_peers - notify network peers about existence of @dev
+ * @dev: network device
+ *
+ * Generate traffic such that interested network peers are aware of
+ * @dev, such as by generating a gratuitous ARP. This may be used when
+ * a device wants to inform the rest of the network about some sort of
+ * reconfiguration such as a failover event or virtual machine
+ * migration.
+ */
+void netif_notify_peers(struct net_device *dev)
+{
+ rtnl_lock();
+ call_netdevice_notifiers(NETDEV_NOTIFY_PEERS, dev);
+ rtnl_unlock();
+}
+EXPORT_SYMBOL(netif_notify_peers);
+
/* "NOOP" scheduler: the best scheduler, recommended for all interfaces
under all circumstances. It is difficult to invent anything faster or
cheaper.
@@ -543,6 +561,7 @@ struct Qdisc *qdisc_alloc(struct netdev_queue *dev_queue,
INIT_LIST_HEAD(&sch->list);
skb_queue_head_init(&sch->q);
+ spin_lock_init(&sch->busylock);
sch->ops = ops;
sch->enqueue = ops->enqueue;
sch->dequeue = ops->dequeue;
@@ -779,7 +798,7 @@ static bool some_qdisc_is_busy(struct net_device *dev)
spin_lock_bh(root_lock);
- val = (test_bit(__QDISC_STATE_RUNNING, &q->state) ||
+ val = (qdisc_is_running(q) ||
test_bit(__QDISC_STATE_SCHED, &q->state));
spin_unlock_bh(root_lock);
diff --git a/net/sched/sch_htb.c b/net/sched/sch_htb.c
index 0b52b8de562..4be8d04b262 100644
--- a/net/sched/sch_htb.c
+++ b/net/sched/sch_htb.c
@@ -1550,7 +1550,6 @@ static const struct Qdisc_class_ops htb_class_ops = {
};
static struct Qdisc_ops htb_qdisc_ops __read_mostly = {
- .next = NULL,
.cl_ops = &htb_class_ops,
.id = "htb",
.priv_size = sizeof(struct htb_sched),
@@ -1561,7 +1560,6 @@ static struct Qdisc_ops htb_qdisc_ops __read_mostly = {
.init = htb_init,
.reset = htb_reset,
.destroy = htb_destroy,
- .change = NULL /* htb_change */,
.dump = htb_dump,
.owner = THIS_MODULE,
};
diff --git a/net/sctp/associola.c b/net/sctp/associola.c
index e41feff19e4..0b85e525643 100644
--- a/net/sctp/associola.c
+++ b/net/sctp/associola.c
@@ -172,7 +172,7 @@ static struct sctp_association *sctp_association_init(struct sctp_association *a
asoc->timeouts[SCTP_EVENT_TIMEOUT_AUTOCLOSE] =
(unsigned long)sp->autoclose * HZ;
- /* Initilizes the timers */
+ /* Initializes the timers */
for (i = SCTP_EVENT_TIMEOUT_NONE; i < SCTP_NUM_TIMEOUT_TYPES; ++i)
setup_timer(&asoc->timers[i], sctp_timer_events[i],
(unsigned long)asoc);
diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c
index 182749867c7..5027b83f1cc 100644
--- a/net/sctp/protocol.c
+++ b/net/sctp/protocol.c
@@ -490,7 +490,7 @@ static struct dst_entry *sctp_v4_get_dst(struct sctp_association *asoc,
__func__, &fl.fl4_dst, &fl.fl4_src);
if (!ip_route_output_key(&init_net, &rt, &fl)) {
- dst = &rt->u.dst;
+ dst = &rt->dst;
}
/* If there is no association or if a source address is passed, no
@@ -534,7 +534,7 @@ static struct dst_entry *sctp_v4_get_dst(struct sctp_association *asoc,
fl.fl4_src = laddr->a.v4.sin_addr.s_addr;
fl.fl_ip_sport = laddr->a.v4.sin_port;
if (!ip_route_output_key(&init_net, &rt, &fl)) {
- dst = &rt->u.dst;
+ dst = &rt->dst;
goto out_unlock;
}
}
@@ -1002,7 +1002,8 @@ int sctp_register_pf(struct sctp_pf *pf, sa_family_t family)
static inline int init_sctp_mibs(void)
{
return snmp_mib_init((void __percpu **)sctp_statistics,
- sizeof(struct sctp_mib));
+ sizeof(struct sctp_mib),
+ __alignof__(struct sctp_mib));
}
static inline void cleanup_sctp_mibs(void)
@@ -1162,7 +1163,7 @@ SCTP_STATIC __init int sctp_init(void)
/* Set the pressure threshold to be a fraction of global memory that
* is up to 1/2 at 256 MB, decreasing toward zero with the amount of
* memory, with a floor of 128 pages.
- * Note this initalizes the data in sctpv6_prot too
+ * Note this initializes the data in sctpv6_prot too
* Unabashedly stolen from tcp_init
*/
nr_pages = totalram_pages - totalhigh_pages;
diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c
index bd2a50b482a..246f9292465 100644
--- a/net/sctp/sm_make_chunk.c
+++ b/net/sctp/sm_make_chunk.c
@@ -1817,7 +1817,7 @@ malformed:
struct __sctp_missing {
__be32 num_missing;
__be16 type;
-} __attribute__((packed));
+} __packed;
/*
* Report a missing mandatory parameter.
diff --git a/net/socket.c b/net/socket.c
index 367d5477d00..2270b941bcc 100644
--- a/net/socket.c
+++ b/net/socket.c
@@ -124,7 +124,7 @@ static int sock_fasync(int fd, struct file *filp, int on);
static ssize_t sock_sendpage(struct file *file, struct page *page,
int offset, size_t size, loff_t *ppos, int more);
static ssize_t sock_splice_read(struct file *file, loff_t *ppos,
- struct pipe_inode_info *pipe, size_t len,
+ struct pipe_inode_info *pipe, size_t len,
unsigned int flags);
/*
@@ -162,7 +162,7 @@ static const struct net_proto_family *net_families[NPROTO] __read_mostly;
* Statistics counters of the socket lists
*/
-static DEFINE_PER_CPU(int, sockets_in_use) = 0;
+static DEFINE_PER_CPU(int, sockets_in_use);
/*
* Support routines.
@@ -170,15 +170,6 @@ static DEFINE_PER_CPU(int, sockets_in_use) = 0;
* divide and look after the messy bits.
*/
-#define MAX_SOCK_ADDR 128 /* 108 for Unix domain -
- 16 for IP, 16 for IPX,
- 24 for IPv6,
- about 80 for AX.25
- must be at least one bigger than
- the AF_UNIX size (see net/unix/af_unix.c
- :unix_mkname()).
- */
-
/**
* move_addr_to_kernel - copy a socket address into kernel space
* @uaddr: Address in user space
@@ -309,9 +300,9 @@ static int init_inodecache(void)
}
static const struct super_operations sockfs_ops = {
- .alloc_inode = sock_alloc_inode,
- .destroy_inode =sock_destroy_inode,
- .statfs = simple_statfs,
+ .alloc_inode = sock_alloc_inode,
+ .destroy_inode = sock_destroy_inode,
+ .statfs = simple_statfs,
};
static int sockfs_get_sb(struct file_system_type *fs_type,
@@ -411,6 +402,7 @@ int sock_map_fd(struct socket *sock, int flags)
return fd;
}
+EXPORT_SYMBOL(sock_map_fd);
static struct socket *sock_from_file(struct file *file, int *err)
{
@@ -422,7 +414,7 @@ static struct socket *sock_from_file(struct file *file, int *err)
}
/**
- * sockfd_lookup - Go from a file number to its socket slot
+ * sockfd_lookup - Go from a file number to its socket slot
* @fd: file handle
* @err: pointer to an error code return
*
@@ -450,6 +442,7 @@ struct socket *sockfd_lookup(int fd, int *err)
fput(file);
return sock;
}
+EXPORT_SYMBOL(sockfd_lookup);
static struct socket *sockfd_lookup_light(int fd, int *err, int *fput_needed)
{
@@ -540,6 +533,7 @@ void sock_release(struct socket *sock)
}
sock->file = NULL;
}
+EXPORT_SYMBOL(sock_release);
int sock_tx_timestamp(struct msghdr *msg, struct sock *sk,
union skb_shared_tx *shtx)
@@ -586,6 +580,7 @@ int sock_sendmsg(struct socket *sock, struct msghdr *msg, size_t size)
ret = wait_on_sync_kiocb(&iocb);
return ret;
}
+EXPORT_SYMBOL(sock_sendmsg);
int kernel_sendmsg(struct socket *sock, struct msghdr *msg,
struct kvec *vec, size_t num, size_t size)
@@ -604,6 +599,7 @@ int kernel_sendmsg(struct socket *sock, struct msghdr *msg,
set_fs(oldfs);
return result;
}
+EXPORT_SYMBOL(kernel_sendmsg);
static int ktime2ts(ktime_t kt, struct timespec *ts)
{
@@ -664,7 +660,6 @@ void __sock_recv_timestamp(struct msghdr *msg, struct sock *sk,
put_cmsg(msg, SOL_SOCKET,
SCM_TIMESTAMPING, sizeof(ts), &ts);
}
-
EXPORT_SYMBOL_GPL(__sock_recv_timestamp);
inline void sock_recv_drops(struct msghdr *msg, struct sock *sk, struct sk_buff *skb)
@@ -720,6 +715,7 @@ int sock_recvmsg(struct socket *sock, struct msghdr *msg,
ret = wait_on_sync_kiocb(&iocb);
return ret;
}
+EXPORT_SYMBOL(sock_recvmsg);
static int sock_recvmsg_nosec(struct socket *sock, struct msghdr *msg,
size_t size, int flags)
@@ -752,6 +748,7 @@ int kernel_recvmsg(struct socket *sock, struct msghdr *msg,
set_fs(oldfs);
return result;
}
+EXPORT_SYMBOL(kernel_recvmsg);
static void sock_aio_dtor(struct kiocb *iocb)
{
@@ -774,7 +771,7 @@ static ssize_t sock_sendpage(struct file *file, struct page *page,
}
static ssize_t sock_splice_read(struct file *file, loff_t *ppos,
- struct pipe_inode_info *pipe, size_t len,
+ struct pipe_inode_info *pipe, size_t len,
unsigned int flags)
{
struct socket *sock = file->private_data;
@@ -887,7 +884,7 @@ static ssize_t sock_aio_write(struct kiocb *iocb, const struct iovec *iov,
*/
static DEFINE_MUTEX(br_ioctl_mutex);
-static int (*br_ioctl_hook) (struct net *, unsigned int cmd, void __user *arg) = NULL;
+static int (*br_ioctl_hook) (struct net *, unsigned int cmd, void __user *arg);
void brioctl_set(int (*hook) (struct net *, unsigned int, void __user *))
{
@@ -895,7 +892,6 @@ void brioctl_set(int (*hook) (struct net *, unsigned int, void __user *))
br_ioctl_hook = hook;
mutex_unlock(&br_ioctl_mutex);
}
-
EXPORT_SYMBOL(brioctl_set);
static DEFINE_MUTEX(vlan_ioctl_mutex);
@@ -907,7 +903,6 @@ void vlan_ioctl_set(int (*hook) (struct net *, void __user *))
vlan_ioctl_hook = hook;
mutex_unlock(&vlan_ioctl_mutex);
}
-
EXPORT_SYMBOL(vlan_ioctl_set);
static DEFINE_MUTEX(dlci_ioctl_mutex);
@@ -919,7 +914,6 @@ void dlci_ioctl_set(int (*hook) (unsigned int, void __user *))
dlci_ioctl_hook = hook;
mutex_unlock(&dlci_ioctl_mutex);
}
-
EXPORT_SYMBOL(dlci_ioctl_set);
static long sock_do_ioctl(struct net *net, struct socket *sock,
@@ -1047,6 +1041,7 @@ out_release:
sock = NULL;
goto out;
}
+EXPORT_SYMBOL(sock_create_lite);
/* No kernel lock held - perfect */
static unsigned int sock_poll(struct file *file, poll_table *wait)
@@ -1147,6 +1142,7 @@ call_kill:
rcu_read_unlock();
return 0;
}
+EXPORT_SYMBOL(sock_wake_async);
static int __sock_create(struct net *net, int family, int type, int protocol,
struct socket **res, int kern)
@@ -1265,11 +1261,13 @@ int sock_create(int family, int type, int protocol, struct socket **res)
{
return __sock_create(current->nsproxy->net_ns, family, type, protocol, res, 0);
}
+EXPORT_SYMBOL(sock_create);
int sock_create_kern(int family, int type, int protocol, struct socket **res)
{
return __sock_create(&init_net, family, type, protocol, res, 1);
}
+EXPORT_SYMBOL(sock_create_kern);
SYSCALL_DEFINE3(socket, int, family, int, type, int, protocol)
{
@@ -1474,7 +1472,8 @@ SYSCALL_DEFINE4(accept4, int, fd, struct sockaddr __user *, upeer_sockaddr,
goto out;
err = -ENFILE;
- if (!(newsock = sock_alloc()))
+ newsock = sock_alloc();
+ if (!newsock)
goto out_put;
newsock->type = sock->type;
@@ -1861,8 +1860,7 @@ SYSCALL_DEFINE3(sendmsg, int, fd, struct msghdr __user *, msg, unsigned, flags)
if (MSG_CMSG_COMPAT & flags) {
if (get_compat_msghdr(&msg_sys, msg_compat))
return -EFAULT;
- }
- else if (copy_from_user(&msg_sys, msg, sizeof(struct msghdr)))
+ } else if (copy_from_user(&msg_sys, msg, sizeof(struct msghdr)))
return -EFAULT;
sock = sockfd_lookup_light(fd, &err, &fput_needed);
@@ -1964,8 +1962,7 @@ static int __sys_recvmsg(struct socket *sock, struct msghdr __user *msg,
if (MSG_CMSG_COMPAT & flags) {
if (get_compat_msghdr(msg_sys, msg_compat))
return -EFAULT;
- }
- else if (copy_from_user(msg_sys, msg, sizeof(struct msghdr)))
+ } else if (copy_from_user(msg_sys, msg, sizeof(struct msghdr)))
return -EFAULT;
err = -EMSGSIZE;
@@ -2191,10 +2188,10 @@ SYSCALL_DEFINE5(recvmmsg, int, fd, struct mmsghdr __user *, mmsg,
/* Argument list sizes for sys_socketcall */
#define AL(x) ((x) * sizeof(unsigned long))
static const unsigned char nargs[20] = {
- AL(0),AL(3),AL(3),AL(3),AL(2),AL(3),
- AL(3),AL(3),AL(4),AL(4),AL(4),AL(6),
- AL(6),AL(2),AL(5),AL(5),AL(3),AL(3),
- AL(4),AL(5)
+ AL(0), AL(3), AL(3), AL(3), AL(2), AL(3),
+ AL(3), AL(3), AL(4), AL(4), AL(4), AL(6),
+ AL(6), AL(2), AL(5), AL(5), AL(3), AL(3),
+ AL(4), AL(5)
};
#undef AL
@@ -2340,6 +2337,7 @@ int sock_register(const struct net_proto_family *ops)
printk(KERN_INFO "NET: Registered protocol family %d\n", ops->family);
return err;
}
+EXPORT_SYMBOL(sock_register);
/**
* sock_unregister - remove a protocol handler
@@ -2366,6 +2364,7 @@ void sock_unregister(int family)
printk(KERN_INFO "NET: Unregistered protocol family %d\n", family);
}
+EXPORT_SYMBOL(sock_unregister);
static int __init sock_init(void)
{
@@ -2395,6 +2394,10 @@ static int __init sock_init(void)
netfilter_init();
#endif
+#ifdef CONFIG_NETWORK_PHY_TIMESTAMPING
+ skb_timestamping_init();
+#endif
+
return 0;
}
@@ -2490,13 +2493,13 @@ static int dev_ifconf(struct net *net, struct compat_ifconf __user *uifc32)
ifc.ifc_req = NULL;
uifc = compat_alloc_user_space(sizeof(struct ifconf));
} else {
- size_t len =((ifc32.ifc_len / sizeof (struct compat_ifreq)) + 1) *
- sizeof (struct ifreq);
+ size_t len = ((ifc32.ifc_len / sizeof(struct compat_ifreq)) + 1) *
+ sizeof(struct ifreq);
uifc = compat_alloc_user_space(sizeof(struct ifconf) + len);
ifc.ifc_len = len;
ifr = ifc.ifc_req = (void __user *)(uifc + 1);
ifr32 = compat_ptr(ifc32.ifcbuf);
- for (i = 0; i < ifc32.ifc_len; i += sizeof (struct compat_ifreq)) {
+ for (i = 0; i < ifc32.ifc_len; i += sizeof(struct compat_ifreq)) {
if (copy_in_user(ifr, ifr32, sizeof(struct compat_ifreq)))
return -EFAULT;
ifr++;
@@ -2516,9 +2519,9 @@ static int dev_ifconf(struct net *net, struct compat_ifconf __user *uifc32)
ifr = ifc.ifc_req;
ifr32 = compat_ptr(ifc32.ifcbuf);
for (i = 0, j = 0;
- i + sizeof (struct compat_ifreq) <= ifc32.ifc_len && j < ifc.ifc_len;
- i += sizeof (struct compat_ifreq), j += sizeof (struct ifreq)) {
- if (copy_in_user(ifr32, ifr, sizeof (struct compat_ifreq)))
+ i + sizeof(struct compat_ifreq) <= ifc32.ifc_len && j < ifc.ifc_len;
+ i += sizeof(struct compat_ifreq), j += sizeof(struct ifreq)) {
+ if (copy_in_user(ifr32, ifr, sizeof(struct compat_ifreq)))
return -EFAULT;
ifr32++;
ifr++;
@@ -2567,7 +2570,7 @@ static int compat_siocwandev(struct net *net, struct compat_ifreq __user *uifr32
compat_uptr_t uptr32;
struct ifreq __user *uifr;
- uifr = compat_alloc_user_space(sizeof (*uifr));
+ uifr = compat_alloc_user_space(sizeof(*uifr));
if (copy_in_user(uifr, uifr32, sizeof(struct compat_ifreq)))
return -EFAULT;
@@ -2601,9 +2604,9 @@ static int bond_ioctl(struct net *net, unsigned int cmd,
return -EFAULT;
old_fs = get_fs();
- set_fs (KERNEL_DS);
+ set_fs(KERNEL_DS);
err = dev_ioctl(net, cmd, &kifr);
- set_fs (old_fs);
+ set_fs(old_fs);
return err;
case SIOCBONDSLAVEINFOQUERY:
@@ -2710,9 +2713,9 @@ static int compat_sioc_ifmap(struct net *net, unsigned int cmd,
return -EFAULT;
old_fs = get_fs();
- set_fs (KERNEL_DS);
+ set_fs(KERNEL_DS);
err = dev_ioctl(net, cmd, (void __user *)&ifr);
- set_fs (old_fs);
+ set_fs(old_fs);
if (cmd == SIOCGIFMAP && !err) {
err = copy_to_user(uifr32, &ifr, sizeof(ifr.ifr_name));
@@ -2734,7 +2737,7 @@ static int compat_siocshwtstamp(struct net *net, struct compat_ifreq __user *uif
compat_uptr_t uptr32;
struct ifreq __user *uifr;
- uifr = compat_alloc_user_space(sizeof (*uifr));
+ uifr = compat_alloc_user_space(sizeof(*uifr));
if (copy_in_user(uifr, uifr32, sizeof(struct compat_ifreq)))
return -EFAULT;
@@ -2750,20 +2753,20 @@ static int compat_siocshwtstamp(struct net *net, struct compat_ifreq __user *uif
}
struct rtentry32 {
- u32 rt_pad1;
+ u32 rt_pad1;
struct sockaddr rt_dst; /* target address */
struct sockaddr rt_gateway; /* gateway addr (RTF_GATEWAY) */
struct sockaddr rt_genmask; /* target network mask (IP) */
- unsigned short rt_flags;
- short rt_pad2;
- u32 rt_pad3;
- unsigned char rt_tos;
- unsigned char rt_class;
- short rt_pad4;
- short rt_metric; /* +1 for binary compatibility! */
+ unsigned short rt_flags;
+ short rt_pad2;
+ u32 rt_pad3;
+ unsigned char rt_tos;
+ unsigned char rt_class;
+ short rt_pad4;
+ short rt_metric; /* +1 for binary compatibility! */
/* char * */ u32 rt_dev; /* forcing the device at add */
- u32 rt_mtu; /* per route MTU/Window */
- u32 rt_window; /* Window clamping */
+ u32 rt_mtu; /* per route MTU/Window */
+ u32 rt_window; /* Window clamping */
unsigned short rt_irtt; /* Initial RTT */
};
@@ -2793,29 +2796,29 @@ static int routing_ioctl(struct net *net, struct socket *sock,
if (sock && sock->sk && sock->sk->sk_family == AF_INET6) { /* ipv6 */
struct in6_rtmsg32 __user *ur6 = argp;
- ret = copy_from_user (&r6.rtmsg_dst, &(ur6->rtmsg_dst),
+ ret = copy_from_user(&r6.rtmsg_dst, &(ur6->rtmsg_dst),
3 * sizeof(struct in6_addr));
- ret |= __get_user (r6.rtmsg_type, &(ur6->rtmsg_type));
- ret |= __get_user (r6.rtmsg_dst_len, &(ur6->rtmsg_dst_len));
- ret |= __get_user (r6.rtmsg_src_len, &(ur6->rtmsg_src_len));
- ret |= __get_user (r6.rtmsg_metric, &(ur6->rtmsg_metric));
- ret |= __get_user (r6.rtmsg_info, &(ur6->rtmsg_info));
- ret |= __get_user (r6.rtmsg_flags, &(ur6->rtmsg_flags));
- ret |= __get_user (r6.rtmsg_ifindex, &(ur6->rtmsg_ifindex));
+ ret |= __get_user(r6.rtmsg_type, &(ur6->rtmsg_type));
+ ret |= __get_user(r6.rtmsg_dst_len, &(ur6->rtmsg_dst_len));
+ ret |= __get_user(r6.rtmsg_src_len, &(ur6->rtmsg_src_len));
+ ret |= __get_user(r6.rtmsg_metric, &(ur6->rtmsg_metric));
+ ret |= __get_user(r6.rtmsg_info, &(ur6->rtmsg_info));
+ ret |= __get_user(r6.rtmsg_flags, &(ur6->rtmsg_flags));
+ ret |= __get_user(r6.rtmsg_ifindex, &(ur6->rtmsg_ifindex));
r = (void *) &r6;
} else { /* ipv4 */
struct rtentry32 __user *ur4 = argp;
- ret = copy_from_user (&r4.rt_dst, &(ur4->rt_dst),
+ ret = copy_from_user(&r4.rt_dst, &(ur4->rt_dst),
3 * sizeof(struct sockaddr));
- ret |= __get_user (r4.rt_flags, &(ur4->rt_flags));
- ret |= __get_user (r4.rt_metric, &(ur4->rt_metric));
- ret |= __get_user (r4.rt_mtu, &(ur4->rt_mtu));
- ret |= __get_user (r4.rt_window, &(ur4->rt_window));
- ret |= __get_user (r4.rt_irtt, &(ur4->rt_irtt));
- ret |= __get_user (rtdev, &(ur4->rt_dev));
+ ret |= __get_user(r4.rt_flags, &(ur4->rt_flags));
+ ret |= __get_user(r4.rt_metric, &(ur4->rt_metric));
+ ret |= __get_user(r4.rt_mtu, &(ur4->rt_mtu));
+ ret |= __get_user(r4.rt_window, &(ur4->rt_window));
+ ret |= __get_user(r4.rt_irtt, &(ur4->rt_irtt));
+ ret |= __get_user(rtdev, &(ur4->rt_dev));
if (rtdev) {
- ret |= copy_from_user (devname, compat_ptr(rtdev), 15);
+ ret |= copy_from_user(devname, compat_ptr(rtdev), 15);
r4.rt_dev = devname; devname[15] = 0;
} else
r4.rt_dev = NULL;
@@ -2828,9 +2831,9 @@ static int routing_ioctl(struct net *net, struct socket *sock,
goto out;
}
- set_fs (KERNEL_DS);
+ set_fs(KERNEL_DS);
ret = sock_do_ioctl(net, sock, cmd, (unsigned long) r);
- set_fs (old_fs);
+ set_fs(old_fs);
out:
return ret;
@@ -2993,11 +2996,13 @@ int kernel_bind(struct socket *sock, struct sockaddr *addr, int addrlen)
{
return sock->ops->bind(sock, addr, addrlen);
}
+EXPORT_SYMBOL(kernel_bind);
int kernel_listen(struct socket *sock, int backlog)
{
return sock->ops->listen(sock, backlog);
}
+EXPORT_SYMBOL(kernel_listen);
int kernel_accept(struct socket *sock, struct socket **newsock, int flags)
{
@@ -3022,24 +3027,28 @@ int kernel_accept(struct socket *sock, struct socket **newsock, int flags)
done:
return err;
}
+EXPORT_SYMBOL(kernel_accept);
int kernel_connect(struct socket *sock, struct sockaddr *addr, int addrlen,
int flags)
{
return sock->ops->connect(sock, addr, addrlen, flags);
}
+EXPORT_SYMBOL(kernel_connect);
int kernel_getsockname(struct socket *sock, struct sockaddr *addr,
int *addrlen)
{
return sock->ops->getname(sock, addr, addrlen, 0);
}
+EXPORT_SYMBOL(kernel_getsockname);
int kernel_getpeername(struct socket *sock, struct sockaddr *addr,
int *addrlen)
{
return sock->ops->getname(sock, addr, addrlen, 1);
}
+EXPORT_SYMBOL(kernel_getpeername);
int kernel_getsockopt(struct socket *sock, int level, int optname,
char *optval, int *optlen)
@@ -3056,6 +3065,7 @@ int kernel_getsockopt(struct socket *sock, int level, int optname,
set_fs(oldfs);
return err;
}
+EXPORT_SYMBOL(kernel_getsockopt);
int kernel_setsockopt(struct socket *sock, int level, int optname,
char *optval, unsigned int optlen)
@@ -3072,6 +3082,7 @@ int kernel_setsockopt(struct socket *sock, int level, int optname,
set_fs(oldfs);
return err;
}
+EXPORT_SYMBOL(kernel_setsockopt);
int kernel_sendpage(struct socket *sock, struct page *page, int offset,
size_t size, int flags)
@@ -3083,6 +3094,7 @@ int kernel_sendpage(struct socket *sock, struct page *page, int offset,
return sock_no_sendpage(sock, page, offset, size, flags);
}
+EXPORT_SYMBOL(kernel_sendpage);
int kernel_sock_ioctl(struct socket *sock, int cmd, unsigned long arg)
{
@@ -3095,33 +3107,10 @@ int kernel_sock_ioctl(struct socket *sock, int cmd, unsigned long arg)
return err;
}
+EXPORT_SYMBOL(kernel_sock_ioctl);
int kernel_sock_shutdown(struct socket *sock, enum sock_shutdown_cmd how)
{
return sock->ops->shutdown(sock, how);
}
-
-EXPORT_SYMBOL(sock_create);
-EXPORT_SYMBOL(sock_create_kern);
-EXPORT_SYMBOL(sock_create_lite);
-EXPORT_SYMBOL(sock_map_fd);
-EXPORT_SYMBOL(sock_recvmsg);
-EXPORT_SYMBOL(sock_register);
-EXPORT_SYMBOL(sock_release);
-EXPORT_SYMBOL(sock_sendmsg);
-EXPORT_SYMBOL(sock_unregister);
-EXPORT_SYMBOL(sock_wake_async);
-EXPORT_SYMBOL(sockfd_lookup);
-EXPORT_SYMBOL(kernel_sendmsg);
-EXPORT_SYMBOL(kernel_recvmsg);
-EXPORT_SYMBOL(kernel_bind);
-EXPORT_SYMBOL(kernel_listen);
-EXPORT_SYMBOL(kernel_accept);
-EXPORT_SYMBOL(kernel_connect);
-EXPORT_SYMBOL(kernel_getsockname);
-EXPORT_SYMBOL(kernel_getpeername);
-EXPORT_SYMBOL(kernel_getsockopt);
-EXPORT_SYMBOL(kernel_setsockopt);
-EXPORT_SYMBOL(kernel_sendpage);
-EXPORT_SYMBOL(kernel_sock_ioctl);
EXPORT_SYMBOL(kernel_sock_shutdown);
diff --git a/net/sunrpc/auth.c b/net/sunrpc/auth.c
index 8dc47f1d000..880d0de3f50 100644
--- a/net/sunrpc/auth.c
+++ b/net/sunrpc/auth.c
@@ -19,6 +19,15 @@
# define RPCDBG_FACILITY RPCDBG_AUTH
#endif
+#define RPC_CREDCACHE_DEFAULT_HASHBITS (4)
+struct rpc_cred_cache {
+ struct hlist_head *hashtable;
+ unsigned int hashbits;
+ spinlock_t lock;
+};
+
+static unsigned int auth_hashbits = RPC_CREDCACHE_DEFAULT_HASHBITS;
+
static DEFINE_SPINLOCK(rpc_authflavor_lock);
static const struct rpc_authops *auth_flavors[RPC_AUTH_MAXFLAVOR] = {
&authnull_ops, /* AUTH_NULL */
@@ -29,6 +38,42 @@ static const struct rpc_authops *auth_flavors[RPC_AUTH_MAXFLAVOR] = {
static LIST_HEAD(cred_unused);
static unsigned long number_cred_unused;
+#define MAX_HASHTABLE_BITS (10)
+static int param_set_hashtbl_sz(const char *val, struct kernel_param *kp)
+{
+ unsigned long num;
+ unsigned int nbits;
+ int ret;
+
+ if (!val)
+ goto out_inval;
+ ret = strict_strtoul(val, 0, &num);
+ if (ret == -EINVAL)
+ goto out_inval;
+ nbits = fls(num);
+ if (num > (1U << nbits))
+ nbits++;
+ if (nbits > MAX_HASHTABLE_BITS || nbits < 2)
+ goto out_inval;
+ *(unsigned int *)kp->arg = nbits;
+ return 0;
+out_inval:
+ return -EINVAL;
+}
+
+static int param_get_hashtbl_sz(char *buffer, struct kernel_param *kp)
+{
+ unsigned int nbits;
+
+ nbits = *(unsigned int *)kp->arg;
+ return sprintf(buffer, "%u", 1U << nbits);
+}
+
+#define param_check_hashtbl_sz(name, p) __param_check(name, p, unsigned int);
+
+module_param_named(auth_hashtable_size, auth_hashbits, hashtbl_sz, 0644);
+MODULE_PARM_DESC(auth_hashtable_size, "RPC credential cache hashtable size");
+
static u32
pseudoflavor_to_flavor(u32 flavor) {
if (flavor >= RPC_AUTH_MAXFLAVOR)
@@ -145,16 +190,23 @@ int
rpcauth_init_credcache(struct rpc_auth *auth)
{
struct rpc_cred_cache *new;
- int i;
+ unsigned int hashsize;
new = kmalloc(sizeof(*new), GFP_KERNEL);
if (!new)
- return -ENOMEM;
- for (i = 0; i < RPC_CREDCACHE_NR; i++)
- INIT_HLIST_HEAD(&new->hashtable[i]);
+ goto out_nocache;
+ new->hashbits = auth_hashbits;
+ hashsize = 1U << new->hashbits;
+ new->hashtable = kcalloc(hashsize, sizeof(new->hashtable[0]), GFP_KERNEL);
+ if (!new->hashtable)
+ goto out_nohashtbl;
spin_lock_init(&new->lock);
auth->au_credcache = new;
return 0;
+out_nohashtbl:
+ kfree(new);
+out_nocache:
+ return -ENOMEM;
}
EXPORT_SYMBOL_GPL(rpcauth_init_credcache);
@@ -183,11 +235,12 @@ rpcauth_clear_credcache(struct rpc_cred_cache *cache)
LIST_HEAD(free);
struct hlist_head *head;
struct rpc_cred *cred;
+ unsigned int hashsize = 1U << cache->hashbits;
int i;
spin_lock(&rpc_credcache_lock);
spin_lock(&cache->lock);
- for (i = 0; i < RPC_CREDCACHE_NR; i++) {
+ for (i = 0; i < hashsize; i++) {
head = &cache->hashtable[i];
while (!hlist_empty(head)) {
cred = hlist_entry(head->first, struct rpc_cred, cr_hash);
@@ -216,6 +269,7 @@ rpcauth_destroy_credcache(struct rpc_auth *auth)
if (cache) {
auth->au_credcache = NULL;
rpcauth_clear_credcache(cache);
+ kfree(cache->hashtable);
kfree(cache);
}
}
@@ -297,7 +351,7 @@ rpcauth_lookup_credcache(struct rpc_auth *auth, struct auth_cred * acred,
*entry, *new;
unsigned int nr;
- nr = hash_long(acred->uid, RPC_CREDCACHE_HASHBITS);
+ nr = hash_long(acred->uid, cache->hashbits);
rcu_read_lock();
hlist_for_each_entry_rcu(entry, pos, &cache->hashtable[nr], cr_hash) {
@@ -390,16 +444,16 @@ rpcauth_init_cred(struct rpc_cred *cred, const struct auth_cred *acred,
}
EXPORT_SYMBOL_GPL(rpcauth_init_cred);
-void
+struct rpc_cred *
rpcauth_generic_bind_cred(struct rpc_task *task, struct rpc_cred *cred, int lookupflags)
{
- task->tk_msg.rpc_cred = get_rpccred(cred);
dprintk("RPC: %5u holding %s cred %p\n", task->tk_pid,
cred->cr_auth->au_ops->au_name, cred);
+ return get_rpccred(cred);
}
EXPORT_SYMBOL_GPL(rpcauth_generic_bind_cred);
-static void
+static struct rpc_cred *
rpcauth_bind_root_cred(struct rpc_task *task, int lookupflags)
{
struct rpc_auth *auth = task->tk_client->cl_auth;
@@ -407,45 +461,43 @@ rpcauth_bind_root_cred(struct rpc_task *task, int lookupflags)
.uid = 0,
.gid = 0,
};
- struct rpc_cred *ret;
dprintk("RPC: %5u looking up %s cred\n",
task->tk_pid, task->tk_client->cl_auth->au_ops->au_name);
- ret = auth->au_ops->lookup_cred(auth, &acred, lookupflags);
- if (!IS_ERR(ret))
- task->tk_msg.rpc_cred = ret;
- else
- task->tk_status = PTR_ERR(ret);
+ return auth->au_ops->lookup_cred(auth, &acred, lookupflags);
}
-static void
+static struct rpc_cred *
rpcauth_bind_new_cred(struct rpc_task *task, int lookupflags)
{
struct rpc_auth *auth = task->tk_client->cl_auth;
- struct rpc_cred *ret;
dprintk("RPC: %5u looking up %s cred\n",
task->tk_pid, auth->au_ops->au_name);
- ret = rpcauth_lookupcred(auth, lookupflags);
- if (!IS_ERR(ret))
- task->tk_msg.rpc_cred = ret;
- else
- task->tk_status = PTR_ERR(ret);
+ return rpcauth_lookupcred(auth, lookupflags);
}
-void
+static int
rpcauth_bindcred(struct rpc_task *task, struct rpc_cred *cred, int flags)
{
+ struct rpc_rqst *req = task->tk_rqstp;
+ struct rpc_cred *new;
int lookupflags = 0;
if (flags & RPC_TASK_ASYNC)
lookupflags |= RPCAUTH_LOOKUP_NEW;
if (cred != NULL)
- cred->cr_ops->crbind(task, cred, lookupflags);
+ new = cred->cr_ops->crbind(task, cred, lookupflags);
else if (flags & RPC_TASK_ROOTCREDS)
- rpcauth_bind_root_cred(task, lookupflags);
+ new = rpcauth_bind_root_cred(task, lookupflags);
else
- rpcauth_bind_new_cred(task, lookupflags);
+ new = rpcauth_bind_new_cred(task, lookupflags);
+ if (IS_ERR(new))
+ return PTR_ERR(new);
+ if (req->rq_cred != NULL)
+ put_rpccred(req->rq_cred);
+ req->rq_cred = new;
+ return 0;
}
void
@@ -484,22 +536,10 @@ out_nodestroy:
}
EXPORT_SYMBOL_GPL(put_rpccred);
-void
-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, cred->cr_auth->au_ops->au_name, cred);
-
- put_rpccred(cred);
- task->tk_msg.rpc_cred = NULL;
-}
-
__be32 *
rpcauth_marshcred(struct rpc_task *task, __be32 *p)
{
- struct rpc_cred *cred = task->tk_msg.rpc_cred;
+ struct rpc_cred *cred = task->tk_rqstp->rq_cred;
dprintk("RPC: %5u marshaling %s cred %p\n",
task->tk_pid, cred->cr_auth->au_ops->au_name, cred);
@@ -510,7 +550,7 @@ rpcauth_marshcred(struct rpc_task *task, __be32 *p)
__be32 *
rpcauth_checkverf(struct rpc_task *task, __be32 *p)
{
- struct rpc_cred *cred = task->tk_msg.rpc_cred;
+ struct rpc_cred *cred = task->tk_rqstp->rq_cred;
dprintk("RPC: %5u validating %s cred %p\n",
task->tk_pid, cred->cr_auth->au_ops->au_name, cred);
@@ -522,7 +562,7 @@ int
rpcauth_wrap_req(struct rpc_task *task, kxdrproc_t encode, void *rqstp,
__be32 *data, void *obj)
{
- struct rpc_cred *cred = task->tk_msg.rpc_cred;
+ struct rpc_cred *cred = task->tk_rqstp->rq_cred;
dprintk("RPC: %5u using %s cred %p to wrap rpc data\n",
task->tk_pid, cred->cr_ops->cr_name, cred);
@@ -536,7 +576,7 @@ int
rpcauth_unwrap_resp(struct rpc_task *task, kxdrproc_t decode, void *rqstp,
__be32 *data, void *obj)
{
- struct rpc_cred *cred = task->tk_msg.rpc_cred;
+ struct rpc_cred *cred = task->tk_rqstp->rq_cred;
dprintk("RPC: %5u using %s cred %p to unwrap rpc data\n",
task->tk_pid, cred->cr_ops->cr_name, cred);
@@ -550,13 +590,21 @@ rpcauth_unwrap_resp(struct rpc_task *task, kxdrproc_t decode, void *rqstp,
int
rpcauth_refreshcred(struct rpc_task *task)
{
- struct rpc_cred *cred = task->tk_msg.rpc_cred;
+ struct rpc_cred *cred = task->tk_rqstp->rq_cred;
int err;
+ cred = task->tk_rqstp->rq_cred;
+ if (cred == NULL) {
+ err = rpcauth_bindcred(task, task->tk_msg.rpc_cred, task->tk_flags);
+ if (err < 0)
+ goto out;
+ cred = task->tk_rqstp->rq_cred;
+ };
dprintk("RPC: %5u refreshing %s cred %p\n",
task->tk_pid, cred->cr_auth->au_ops->au_name, cred);
err = cred->cr_ops->crrefresh(task);
+out:
if (err < 0)
task->tk_status = err;
return err;
@@ -565,7 +613,7 @@ rpcauth_refreshcred(struct rpc_task *task)
void
rpcauth_invalcred(struct rpc_task *task)
{
- struct rpc_cred *cred = task->tk_msg.rpc_cred;
+ struct rpc_cred *cred = task->tk_rqstp->rq_cred;
dprintk("RPC: %5u invalidating %s cred %p\n",
task->tk_pid, cred->cr_auth->au_ops->au_name, cred);
@@ -576,7 +624,7 @@ rpcauth_invalcred(struct rpc_task *task)
int
rpcauth_uptodatecred(struct rpc_task *task)
{
- struct rpc_cred *cred = task->tk_msg.rpc_cred;
+ struct rpc_cred *cred = task->tk_rqstp->rq_cred;
return cred == NULL ||
test_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags) != 0;
@@ -587,14 +635,27 @@ static struct shrinker rpc_cred_shrinker = {
.seeks = DEFAULT_SEEKS,
};
-void __init rpcauth_init_module(void)
+int __init rpcauth_init_module(void)
{
- rpc_init_authunix();
- rpc_init_generic_auth();
+ int err;
+
+ err = rpc_init_authunix();
+ if (err < 0)
+ goto out1;
+ err = rpc_init_generic_auth();
+ if (err < 0)
+ goto out2;
register_shrinker(&rpc_cred_shrinker);
+ return 0;
+out2:
+ rpc_destroy_authunix();
+out1:
+ return err;
}
void __exit rpcauth_remove_module(void)
{
+ rpc_destroy_authunix();
+ rpc_destroy_generic_auth();
unregister_shrinker(&rpc_cred_shrinker);
}
diff --git a/net/sunrpc/auth_generic.c b/net/sunrpc/auth_generic.c
index 8f623b0f03d..43162bb3b78 100644
--- a/net/sunrpc/auth_generic.c
+++ b/net/sunrpc/auth_generic.c
@@ -27,7 +27,6 @@ struct generic_cred {
};
static struct rpc_auth generic_auth;
-static struct rpc_cred_cache generic_cred_cache;
static const struct rpc_credops generic_credops;
/*
@@ -55,18 +54,13 @@ struct rpc_cred *rpc_lookup_machine_cred(void)
}
EXPORT_SYMBOL_GPL(rpc_lookup_machine_cred);
-static void
-generic_bind_cred(struct rpc_task *task, struct rpc_cred *cred, int lookupflags)
+static struct rpc_cred *generic_bind_cred(struct rpc_task *task,
+ struct rpc_cred *cred, int lookupflags)
{
struct rpc_auth *auth = task->tk_client->cl_auth;
struct auth_cred *acred = &container_of(cred, struct generic_cred, gc_base)->acred;
- struct rpc_cred *ret;
- ret = auth->au_ops->lookup_cred(auth, acred, lookupflags);
- if (!IS_ERR(ret))
- task->tk_msg.rpc_cred = ret;
- else
- task->tk_status = PTR_ERR(ret);
+ return auth->au_ops->lookup_cred(auth, acred, lookupflags);
}
/*
@@ -159,20 +153,16 @@ out_nomatch:
return 0;
}
-void __init rpc_init_generic_auth(void)
+int __init rpc_init_generic_auth(void)
{
- spin_lock_init(&generic_cred_cache.lock);
+ return rpcauth_init_credcache(&generic_auth);
}
void __exit rpc_destroy_generic_auth(void)
{
- rpcauth_clear_credcache(&generic_cred_cache);
+ rpcauth_destroy_credcache(&generic_auth);
}
-static struct rpc_cred_cache generic_cred_cache = {
- {{ NULL, },},
-};
-
static const struct rpc_authops generic_auth_ops = {
.owner = THIS_MODULE,
.au_name = "Generic",
@@ -183,7 +173,6 @@ static const struct rpc_authops generic_auth_ops = {
static struct rpc_auth generic_auth = {
.au_ops = &generic_auth_ops,
.au_count = ATOMIC_INIT(0),
- .au_credcache = &generic_cred_cache,
};
static const struct rpc_credops generic_credops = {
diff --git a/net/sunrpc/auth_gss/auth_gss.c b/net/sunrpc/auth_gss/auth_gss.c
index 8da2a0e6857..dcfc66bab2b 100644
--- a/net/sunrpc/auth_gss/auth_gss.c
+++ b/net/sunrpc/auth_gss/auth_gss.c
@@ -373,7 +373,7 @@ gss_handle_downcall_result(struct gss_cred *gss_cred, struct gss_upcall_msg *gss
static void
gss_upcall_callback(struct rpc_task *task)
{
- struct gss_cred *gss_cred = container_of(task->tk_msg.rpc_cred,
+ struct gss_cred *gss_cred = container_of(task->tk_rqstp->rq_cred,
struct gss_cred, gc_base);
struct gss_upcall_msg *gss_msg = gss_cred->gc_upcall;
struct inode *inode = &gss_msg->inode->vfs_inode;
@@ -502,7 +502,7 @@ static void warn_gssd(void)
static inline int
gss_refresh_upcall(struct rpc_task *task)
{
- struct rpc_cred *cred = task->tk_msg.rpc_cred;
+ struct rpc_cred *cred = task->tk_rqstp->rq_cred;
struct gss_auth *gss_auth = container_of(cred->cr_auth,
struct gss_auth, rpc_auth);
struct gss_cred *gss_cred = container_of(cred,
@@ -928,6 +928,7 @@ gss_do_free_ctx(struct gss_cl_ctx *ctx)
{
dprintk("RPC: gss_free_ctx\n");
+ gss_delete_sec_context(&ctx->gc_gss_ctx);
kfree(ctx->gc_wire_ctx.data);
kfree(ctx);
}
@@ -942,13 +943,7 @@ gss_free_ctx_callback(struct rcu_head *head)
static void
gss_free_ctx(struct gss_cl_ctx *ctx)
{
- struct gss_ctx *gc_gss_ctx;
-
- gc_gss_ctx = rcu_dereference(ctx->gc_gss_ctx);
- rcu_assign_pointer(ctx->gc_gss_ctx, NULL);
call_rcu(&ctx->gc_rcu, gss_free_ctx_callback);
- if (gc_gss_ctx)
- gss_delete_sec_context(&gc_gss_ctx);
}
static void
@@ -1064,12 +1059,12 @@ out:
static __be32 *
gss_marshal(struct rpc_task *task, __be32 *p)
{
- struct rpc_cred *cred = task->tk_msg.rpc_cred;
+ struct rpc_rqst *req = task->tk_rqstp;
+ struct rpc_cred *cred = req->rq_cred;
struct gss_cred *gss_cred = container_of(cred, struct gss_cred,
gc_base);
struct gss_cl_ctx *ctx = gss_cred_get_ctx(cred);
__be32 *cred_len;
- struct rpc_rqst *req = task->tk_rqstp;
u32 maj_stat = 0;
struct xdr_netobj mic;
struct kvec iov;
@@ -1119,7 +1114,7 @@ out_put_ctx:
static int gss_renew_cred(struct rpc_task *task)
{
- struct rpc_cred *oldcred = task->tk_msg.rpc_cred;
+ struct rpc_cred *oldcred = task->tk_rqstp->rq_cred;
struct gss_cred *gss_cred = container_of(oldcred,
struct gss_cred,
gc_base);
@@ -1133,7 +1128,7 @@ static int gss_renew_cred(struct rpc_task *task)
new = gss_lookup_cred(auth, &acred, RPCAUTH_LOOKUP_NEW);
if (IS_ERR(new))
return PTR_ERR(new);
- task->tk_msg.rpc_cred = new;
+ task->tk_rqstp->rq_cred = new;
put_rpccred(oldcred);
return 0;
}
@@ -1161,7 +1156,7 @@ static int gss_cred_is_negative_entry(struct rpc_cred *cred)
static int
gss_refresh(struct rpc_task *task)
{
- struct rpc_cred *cred = task->tk_msg.rpc_cred;
+ struct rpc_cred *cred = task->tk_rqstp->rq_cred;
int ret = 0;
if (gss_cred_is_negative_entry(cred))
@@ -1172,7 +1167,7 @@ gss_refresh(struct rpc_task *task)
ret = gss_renew_cred(task);
if (ret < 0)
goto out;
- cred = task->tk_msg.rpc_cred;
+ cred = task->tk_rqstp->rq_cred;
}
if (test_bit(RPCAUTH_CRED_NEW, &cred->cr_flags))
@@ -1191,7 +1186,7 @@ gss_refresh_null(struct rpc_task *task)
static __be32 *
gss_validate(struct rpc_task *task, __be32 *p)
{
- struct rpc_cred *cred = task->tk_msg.rpc_cred;
+ struct rpc_cred *cred = task->tk_rqstp->rq_cred;
struct gss_cl_ctx *ctx = gss_cred_get_ctx(cred);
__be32 seq;
struct kvec iov;
@@ -1400,7 +1395,7 @@ static int
gss_wrap_req(struct rpc_task *task,
kxdrproc_t encode, void *rqstp, __be32 *p, void *obj)
{
- struct rpc_cred *cred = task->tk_msg.rpc_cred;
+ struct rpc_cred *cred = task->tk_rqstp->rq_cred;
struct gss_cred *gss_cred = container_of(cred, struct gss_cred,
gc_base);
struct gss_cl_ctx *ctx = gss_cred_get_ctx(cred);
@@ -1503,7 +1498,7 @@ static int
gss_unwrap_resp(struct rpc_task *task,
kxdrproc_t decode, void *rqstp, __be32 *p, void *obj)
{
- struct rpc_cred *cred = task->tk_msg.rpc_cred;
+ struct rpc_cred *cred = task->tk_rqstp->rq_cred;
struct gss_cred *gss_cred = container_of(cred, struct gss_cred,
gc_base);
struct gss_cl_ctx *ctx = gss_cred_get_ctx(cred);
diff --git a/net/sunrpc/auth_null.c b/net/sunrpc/auth_null.c
index 1db618f56ec..a5c36c01707 100644
--- a/net/sunrpc/auth_null.c
+++ b/net/sunrpc/auth_null.c
@@ -75,7 +75,7 @@ nul_marshal(struct rpc_task *task, __be32 *p)
static int
nul_refresh(struct rpc_task *task)
{
- set_bit(RPCAUTH_CRED_UPTODATE, &task->tk_msg.rpc_cred->cr_flags);
+ set_bit(RPCAUTH_CRED_UPTODATE, &task->tk_rqstp->rq_cred->cr_flags);
return 0;
}
diff --git a/net/sunrpc/auth_unix.c b/net/sunrpc/auth_unix.c
index aac2f8b4ee2..4cb70dc6e7a 100644
--- a/net/sunrpc/auth_unix.c
+++ b/net/sunrpc/auth_unix.c
@@ -29,7 +29,6 @@ struct unx_cred {
#endif
static struct rpc_auth unix_auth;
-static struct rpc_cred_cache unix_cred_cache;
static const struct rpc_credops unix_credops;
static struct rpc_auth *
@@ -141,7 +140,7 @@ static __be32 *
unx_marshal(struct rpc_task *task, __be32 *p)
{
struct rpc_clnt *clnt = task->tk_client;
- struct unx_cred *cred = container_of(task->tk_msg.rpc_cred, struct unx_cred, uc_base);
+ struct unx_cred *cred = container_of(task->tk_rqstp->rq_cred, struct unx_cred, uc_base);
__be32 *base, *hold;
int i;
@@ -174,7 +173,7 @@ unx_marshal(struct rpc_task *task, __be32 *p)
static int
unx_refresh(struct rpc_task *task)
{
- set_bit(RPCAUTH_CRED_UPTODATE, &task->tk_msg.rpc_cred->cr_flags);
+ set_bit(RPCAUTH_CRED_UPTODATE, &task->tk_rqstp->rq_cred->cr_flags);
return 0;
}
@@ -197,15 +196,20 @@ unx_validate(struct rpc_task *task, __be32 *p)
printk("RPC: giant verf size: %u\n", size);
return NULL;
}
- task->tk_msg.rpc_cred->cr_auth->au_rslack = (size >> 2) + 2;
+ task->tk_rqstp->rq_cred->cr_auth->au_rslack = (size >> 2) + 2;
p += (size >> 2);
return p;
}
-void __init rpc_init_authunix(void)
+int __init rpc_init_authunix(void)
{
- spin_lock_init(&unix_cred_cache.lock);
+ return rpcauth_init_credcache(&unix_auth);
+}
+
+void rpc_destroy_authunix(void)
+{
+ rpcauth_destroy_credcache(&unix_auth);
}
const struct rpc_authops authunix_ops = {
@@ -219,17 +223,12 @@ const struct rpc_authops authunix_ops = {
};
static
-struct rpc_cred_cache unix_cred_cache = {
-};
-
-static
struct rpc_auth unix_auth = {
.au_cslack = UNX_WRITESLACK,
.au_rslack = 2, /* assume AUTH_NULL verf */
.au_ops = &authunix_ops,
.au_flavor = RPC_AUTH_UNIX,
.au_count = ATOMIC_INIT(0),
- .au_credcache = &unix_cred_cache,
};
static
diff --git a/net/sunrpc/cache.c b/net/sunrpc/cache.c
index 58de76c8540..2b06410e584 100644
--- a/net/sunrpc/cache.c
+++ b/net/sunrpc/cache.c
@@ -34,7 +34,6 @@
#include <linux/sunrpc/cache.h>
#include <linux/sunrpc/stats.h>
#include <linux/sunrpc/rpc_pipe_fs.h>
-#include <linux/smp_lock.h>
#define RPCDBG_FACILITY RPCDBG_CACHE
@@ -320,7 +319,7 @@ static struct cache_detail *current_detail;
static int current_index;
static void do_cache_clean(struct work_struct *work);
-static DECLARE_DELAYED_WORK(cache_cleaner, do_cache_clean);
+static struct delayed_work cache_cleaner;
static void sunrpc_init_cache_detail(struct cache_detail *cd)
{
@@ -1504,6 +1503,11 @@ static int create_cache_proc_entries(struct cache_detail *cd)
}
#endif
+void __init cache_initialize(void)
+{
+ INIT_DELAYED_WORK_DEFERRABLE(&cache_cleaner, do_cache_clean);
+}
+
int cache_register(struct cache_detail *cd)
{
int ret;
diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c
index 756fc324db9..2388d83b68f 100644
--- a/net/sunrpc/clnt.c
+++ b/net/sunrpc/clnt.c
@@ -414,6 +414,35 @@ out_no_clnt:
EXPORT_SYMBOL_GPL(rpc_clone_client);
/*
+ * Kill all tasks for the given client.
+ * XXX: kill their descendants as well?
+ */
+void rpc_killall_tasks(struct rpc_clnt *clnt)
+{
+ struct rpc_task *rovr;
+
+
+ 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(&clnt->cl_lock);
+ list_for_each_entry(rovr, &clnt->cl_tasks, tk_task) {
+ if (!RPC_IS_ACTIVATED(rovr))
+ continue;
+ if (!(rovr->tk_flags & RPC_TASK_KILLED)) {
+ rovr->tk_flags |= RPC_TASK_KILLED;
+ rpc_exit(rovr, -EIO);
+ rpc_wake_up_queued_task(rovr->tk_waitqueue, rovr);
+ }
+ }
+ spin_unlock(&clnt->cl_lock);
+}
+EXPORT_SYMBOL_GPL(rpc_killall_tasks);
+
+/*
* Properly shut down an RPC client, terminating all outstanding
* requests.
*/
@@ -538,6 +567,49 @@ out:
}
EXPORT_SYMBOL_GPL(rpc_bind_new_program);
+void rpc_task_release_client(struct rpc_task *task)
+{
+ struct rpc_clnt *clnt = task->tk_client;
+
+ if (clnt != NULL) {
+ /* Remove from client task list */
+ spin_lock(&clnt->cl_lock);
+ list_del(&task->tk_task);
+ spin_unlock(&clnt->cl_lock);
+ task->tk_client = NULL;
+
+ rpc_release_client(clnt);
+ }
+}
+
+static
+void rpc_task_set_client(struct rpc_task *task, struct rpc_clnt *clnt)
+{
+ if (clnt != NULL) {
+ rpc_task_release_client(task);
+ task->tk_client = clnt;
+ kref_get(&clnt->cl_kref);
+ if (clnt->cl_softrtry)
+ task->tk_flags |= RPC_TASK_SOFT;
+ /* Add to the client's list of all tasks */
+ spin_lock(&clnt->cl_lock);
+ list_add_tail(&task->tk_task, &clnt->cl_tasks);
+ spin_unlock(&clnt->cl_lock);
+ }
+}
+
+static void
+rpc_task_set_rpc_message(struct rpc_task *task, const struct rpc_message *msg)
+{
+ if (msg != NULL) {
+ task->tk_msg.rpc_proc = msg->rpc_proc;
+ task->tk_msg.rpc_argp = msg->rpc_argp;
+ task->tk_msg.rpc_resp = msg->rpc_resp;
+ if (msg->rpc_cred != NULL)
+ task->tk_msg.rpc_cred = get_rpccred(msg->rpc_cred);
+ }
+}
+
/*
* Default callback for async RPC calls
*/
@@ -562,6 +634,18 @@ struct rpc_task *rpc_run_task(const struct rpc_task_setup *task_setup_data)
if (IS_ERR(task))
goto out;
+ rpc_task_set_client(task, task_setup_data->rpc_client);
+ rpc_task_set_rpc_message(task, task_setup_data->rpc_message);
+
+ if (task->tk_status != 0) {
+ int ret = task->tk_status;
+ rpc_put_task(task);
+ return ERR_PTR(ret);
+ }
+
+ if (task->tk_action == NULL)
+ rpc_call_start(task);
+
atomic_inc(&task->tk_count);
rpc_execute(task);
out:
@@ -756,12 +840,13 @@ EXPORT_SYMBOL_GPL(rpc_force_rebind);
* Restart an (async) RPC call from the call_prepare state.
* Usually called from within the exit handler.
*/
-void
+int
rpc_restart_call_prepare(struct rpc_task *task)
{
if (RPC_ASSASSINATED(task))
- return;
+ return 0;
task->tk_action = rpc_prepare_task;
+ return 1;
}
EXPORT_SYMBOL_GPL(rpc_restart_call_prepare);
@@ -769,13 +854,13 @@ EXPORT_SYMBOL_GPL(rpc_restart_call_prepare);
* Restart an (async) RPC call. Usually called from within the
* exit handler.
*/
-void
+int
rpc_restart_call(struct rpc_task *task)
{
if (RPC_ASSASSINATED(task))
- return;
-
+ return 0;
task->tk_action = call_start;
+ return 1;
}
EXPORT_SYMBOL_GPL(rpc_restart_call);
@@ -824,11 +909,6 @@ call_reserve(struct rpc_task *task)
{
dprint_status(task);
- if (!rpcauth_uptodatecred(task)) {
- task->tk_action = call_refresh;
- return;
- }
-
task->tk_status = 0;
task->tk_action = call_reserveresult;
xprt_reserve(task);
@@ -892,7 +972,7 @@ call_reserveresult(struct rpc_task *task)
static void
call_allocate(struct rpc_task *task)
{
- unsigned int slack = task->tk_msg.rpc_cred->cr_auth->au_cslack;
+ unsigned int slack = task->tk_client->cl_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;
@@ -900,7 +980,7 @@ call_allocate(struct rpc_task *task)
dprint_status(task);
task->tk_status = 0;
- task->tk_action = call_bind;
+ task->tk_action = call_refresh;
if (req->rq_buffer)
return;
@@ -937,6 +1017,47 @@ call_allocate(struct rpc_task *task)
rpc_exit(task, -ERESTARTSYS);
}
+/*
+ * 2a. Bind and/or refresh the credentials
+ */
+static void
+call_refresh(struct rpc_task *task)
+{
+ dprint_status(task);
+
+ task->tk_action = call_refreshresult;
+ task->tk_status = 0;
+ task->tk_client->cl_stats->rpcauthrefresh++;
+ rpcauth_refreshcred(task);
+}
+
+/*
+ * 2b. Process the results of a credential refresh
+ */
+static void
+call_refreshresult(struct rpc_task *task)
+{
+ int status = task->tk_status;
+
+ dprint_status(task);
+
+ task->tk_status = 0;
+ task->tk_action = call_bind;
+ if (status >= 0 && rpcauth_uptodatecred(task))
+ return;
+ switch (status) {
+ case -EACCES:
+ rpc_exit(task, -EACCES);
+ return;
+ case -ENOMEM:
+ rpc_exit(task, -ENOMEM);
+ return;
+ case -ETIMEDOUT:
+ rpc_delay(task, 3*HZ);
+ }
+ task->tk_action = call_refresh;
+}
+
static inline int
rpc_task_need_encode(struct rpc_task *task)
{
@@ -1472,43 +1593,6 @@ out_retry:
}
}
-/*
- * 8. Refresh the credentials if rejected by the server
- */
-static void
-call_refresh(struct rpc_task *task)
-{
- dprint_status(task);
-
- task->tk_action = call_refreshresult;
- task->tk_status = 0;
- task->tk_client->cl_stats->rpcauthrefresh++;
- rpcauth_refreshcred(task);
-}
-
-/*
- * 8a. Process the results of a credential refresh
- */
-static void
-call_refreshresult(struct rpc_task *task)
-{
- int status = task->tk_status;
-
- dprint_status(task);
-
- task->tk_status = 0;
- task->tk_action = call_reserve;
- if (status >= 0 && rpcauth_uptodatecred(task))
- return;
- if (status == -EACCES) {
- rpc_exit(task, -EACCES);
- return;
- }
- task->tk_action = call_refresh;
- if (status != -ETIMEDOUT)
- rpc_delay(task, 3*HZ);
-}
-
static __be32 *
rpc_encode_header(struct rpc_task *task)
{
diff --git a/net/sunrpc/sched.c b/net/sunrpc/sched.c
index 4a843b883b8..cace6049e4a 100644
--- a/net/sunrpc/sched.c
+++ b/net/sunrpc/sched.c
@@ -246,17 +246,8 @@ static inline void rpc_task_set_debuginfo(struct rpc_task *task)
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;
rpc_task_set_debuginfo(task);
- /* Add to global list of all tasks */
- 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);
- }
+ set_bit(RPC_TASK_ACTIVE, &task->tk_runstate);
}
/*
@@ -319,11 +310,6 @@ static void __rpc_sleep_on(struct rpc_wait_queue *q, struct rpc_task *task,
dprintk("RPC: %5u sleep_on(queue \"%s\" time %lu)\n",
task->tk_pid, rpc_qname(q), jiffies);
- if (!RPC_IS_ASYNC(task) && !RPC_IS_ACTIVATED(task)) {
- printk(KERN_ERR "RPC: Inactive synchronous task put to sleep!\n");
- return;
- }
-
__rpc_add_wait_queue(q, task);
BUG_ON(task->tk_callback != NULL);
@@ -334,8 +320,8 @@ static void __rpc_sleep_on(struct rpc_wait_queue *q, struct rpc_task *task,
void rpc_sleep_on(struct rpc_wait_queue *q, struct rpc_task *task,
rpc_action action)
{
- /* Mark the task as being activated if so needed */
- rpc_set_active(task);
+ /* We shouldn't ever put an inactive task to sleep */
+ BUG_ON(!RPC_IS_ACTIVATED(task));
/*
* Protect the queue operations.
@@ -406,14 +392,6 @@ void rpc_wake_up_queued_task(struct rpc_wait_queue *queue, struct rpc_task *task
EXPORT_SYMBOL_GPL(rpc_wake_up_queued_task);
/*
- * Wake up the specified task
- */
-static void rpc_wake_up_task(struct rpc_task *task)
-{
- rpc_wake_up_queued_task(task->tk_waitqueue, task);
-}
-
-/*
* Wake up the next task on a priority queue.
*/
static struct rpc_task * __rpc_wake_up_next_priority(struct rpc_wait_queue *queue)
@@ -600,7 +578,15 @@ void rpc_exit_task(struct rpc_task *task)
}
}
}
-EXPORT_SYMBOL_GPL(rpc_exit_task);
+
+void rpc_exit(struct rpc_task *task, int status)
+{
+ task->tk_status = status;
+ task->tk_action = rpc_exit_task;
+ if (RPC_IS_QUEUED(task))
+ rpc_wake_up_queued_task(task->tk_waitqueue, task);
+}
+EXPORT_SYMBOL_GPL(rpc_exit);
void rpc_release_calldata(const struct rpc_call_ops *ops, void *calldata)
{
@@ -690,7 +676,6 @@ static void __rpc_execute(struct rpc_task *task)
dprintk("RPC: %5u got signal\n", task->tk_pid);
task->tk_flags |= RPC_TASK_KILLED;
rpc_exit(task, -ERESTARTSYS);
- rpc_wake_up_task(task);
}
rpc_set_running(task);
dprintk("RPC: %5u sync task resuming\n", task->tk_pid);
@@ -714,8 +699,9 @@ static void __rpc_execute(struct rpc_task *task)
void rpc_execute(struct rpc_task *task)
{
rpc_set_active(task);
- rpc_set_running(task);
- __rpc_execute(task);
+ rpc_make_runnable(task);
+ if (!RPC_IS_ASYNC(task))
+ __rpc_execute(task);
}
static void rpc_async_schedule(struct work_struct *work)
@@ -808,26 +794,9 @@ static void rpc_init_task(struct rpc_task *task, const struct rpc_task_setup *ta
/* Initialize workqueue for async tasks */
task->tk_workqueue = task_setup_data->workqueue;
- task->tk_client = task_setup_data->rpc_client;
- if (task->tk_client != NULL) {
- kref_get(&task->tk_client->cl_kref);
- if (task->tk_client->cl_softrtry)
- task->tk_flags |= RPC_TASK_SOFT;
- }
-
if (task->tk_ops->rpc_call_prepare != NULL)
task->tk_action = rpc_prepare_task;
- if (task_setup_data->rpc_message != NULL) {
- task->tk_msg.rpc_proc = task_setup_data->rpc_message->rpc_proc;
- task->tk_msg.rpc_argp = task_setup_data->rpc_message->rpc_argp;
- task->tk_msg.rpc_resp = task_setup_data->rpc_message->rpc_resp;
- /* Bind the user cred */
- rpcauth_bindcred(task, task_setup_data->rpc_message->rpc_cred, task_setup_data->flags);
- if (task->tk_action == NULL)
- rpc_call_start(task);
- }
-
/* starting timestamp */
task->tk_start = ktime_get();
@@ -896,11 +865,8 @@ void rpc_put_task(struct rpc_task *task)
if (task->tk_rqstp)
xprt_release(task);
if (task->tk_msg.rpc_cred)
- rpcauth_unbindcred(task);
- if (task->tk_client) {
- rpc_release_client(task->tk_client);
- task->tk_client = NULL;
- }
+ put_rpccred(task->tk_msg.rpc_cred);
+ rpc_task_release_client(task);
if (task->tk_workqueue != NULL) {
INIT_WORK(&task->u.tk_work, rpc_async_release);
queue_work(task->tk_workqueue, &task->u.tk_work);
@@ -913,13 +879,6 @@ static void rpc_release_task(struct rpc_task *task)
{
dprintk("RPC: %5u release task\n", task->tk_pid);
- 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));
/* Wake up anyone who is waiting for task completion */
@@ -928,35 +887,6 @@ static void rpc_release_task(struct rpc_task *task)
rpc_put_task(task);
}
-/*
- * Kill all tasks for the given client.
- * XXX: kill their descendants as well?
- */
-void rpc_killall_tasks(struct rpc_clnt *clnt)
-{
- struct rpc_task *rovr;
-
-
- 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(&clnt->cl_lock);
- list_for_each_entry(rovr, &clnt->cl_tasks, tk_task) {
- if (! RPC_IS_ACTIVATED(rovr))
- continue;
- if (!(rovr->tk_flags & RPC_TASK_KILLED)) {
- rovr->tk_flags |= RPC_TASK_KILLED;
- rpc_exit(rovr, -EIO);
- rpc_wake_up_task(rovr);
- }
- }
- spin_unlock(&clnt->cl_lock);
-}
-EXPORT_SYMBOL_GPL(rpc_killall_tasks);
-
int rpciod_up(void)
{
return try_module_get(THIS_MODULE) ? 0 : -EINVAL;
diff --git a/net/sunrpc/sunrpc_syms.c b/net/sunrpc/sunrpc_syms.c
index f438347d817..c0d085013a2 100644
--- a/net/sunrpc/sunrpc_syms.c
+++ b/net/sunrpc/sunrpc_syms.c
@@ -33,21 +33,27 @@ init_sunrpc(void)
if (err)
goto out;
err = rpc_init_mempool();
- if (err) {
- unregister_rpc_pipefs();
- goto out;
- }
+ if (err)
+ goto out2;
+ err = rpcauth_init_module();
+ if (err)
+ goto out3;
#ifdef RPC_DEBUG
rpc_register_sysctl();
#endif
#ifdef CONFIG_PROC_FS
rpc_proc_init();
#endif
+ cache_initialize();
cache_register(&ip_map_cache);
cache_register(&unix_gid_cache);
svc_init_xprt_sock(); /* svc sock transport */
init_socket_xprt(); /* clnt sock transport */
- rpcauth_init_module();
+ return 0;
+out3:
+ rpc_destroy_mempool();
+out2:
+ unregister_rpc_pipefs();
out:
return err;
}
diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c
index dcd0132396b..970fb00f388 100644
--- a/net/sunrpc/xprt.c
+++ b/net/sunrpc/xprt.c
@@ -1032,6 +1032,8 @@ void xprt_release(struct rpc_task *task)
spin_unlock_bh(&xprt->transport_lock);
if (req->rq_buffer)
xprt->ops->buf_free(req->rq_buffer);
+ if (req->rq_cred != NULL)
+ put_rpccred(req->rq_cred);
task->tk_rqstp = NULL;
if (req->rq_release_snd_buf)
req->rq_release_snd_buf(req);
@@ -1129,6 +1131,7 @@ static void xprt_destroy(struct kref *kref)
rpc_destroy_wait_queue(&xprt->sending);
rpc_destroy_wait_queue(&xprt->resend);
rpc_destroy_wait_queue(&xprt->backlog);
+ cancel_work_sync(&xprt->task_cleanup);
/*
* Tear down transport state and free the rpc_xprt
*/
diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
index fef2cc5e9d2..4414a18c63b 100644
--- a/net/unix/af_unix.c
+++ b/net/unix/af_unix.c
@@ -282,7 +282,7 @@ static inline struct sock *unix_find_socket_byname(struct net *net,
return s;
}
-static struct sock *unix_find_socket_byinode(struct net *net, struct inode *i)
+static struct sock *unix_find_socket_byinode(struct inode *i)
{
struct sock *s;
struct hlist_node *node;
@@ -292,9 +292,6 @@ static struct sock *unix_find_socket_byinode(struct net *net, struct inode *i)
&unix_socket_table[i->i_ino & (UNIX_HASH_SIZE - 1)]) {
struct dentry *dentry = unix_sk(s)->dentry;
- if (!net_eq(sock_net(s), net))
- continue;
-
if (dentry && dentry->d_inode == i) {
sock_hold(s);
goto found;
@@ -450,11 +447,31 @@ static int unix_release_sock(struct sock *sk, int embrion)
return 0;
}
+static void init_peercred(struct sock *sk)
+{
+ put_pid(sk->sk_peer_pid);
+ if (sk->sk_peer_cred)
+ put_cred(sk->sk_peer_cred);
+ sk->sk_peer_pid = get_pid(task_tgid(current));
+ sk->sk_peer_cred = get_current_cred();
+}
+
+static void copy_peercred(struct sock *sk, struct sock *peersk)
+{
+ put_pid(sk->sk_peer_pid);
+ if (sk->sk_peer_cred)
+ put_cred(sk->sk_peer_cred);
+ sk->sk_peer_pid = get_pid(peersk->sk_peer_pid);
+ sk->sk_peer_cred = get_cred(peersk->sk_peer_cred);
+}
+
static int unix_listen(struct socket *sock, int backlog)
{
int err;
struct sock *sk = sock->sk;
struct unix_sock *u = unix_sk(sk);
+ struct pid *old_pid = NULL;
+ const struct cred *old_cred = NULL;
err = -EOPNOTSUPP;
if (sock->type != SOCK_STREAM && sock->type != SOCK_SEQPACKET)
@@ -470,12 +487,14 @@ static int unix_listen(struct socket *sock, int backlog)
sk->sk_max_ack_backlog = backlog;
sk->sk_state = TCP_LISTEN;
/* set credentials so connect can copy them */
- sk->sk_peercred.pid = task_tgid_vnr(current);
- current_euid_egid(&sk->sk_peercred.uid, &sk->sk_peercred.gid);
+ init_peercred(sk);
err = 0;
out_unlock:
unix_state_unlock(sk);
+ put_pid(old_pid);
+ if (old_cred)
+ put_cred(old_cred);
out:
return err;
}
@@ -736,7 +755,7 @@ static struct sock *unix_find_other(struct net *net,
err = -ECONNREFUSED;
if (!S_ISSOCK(inode->i_mode))
goto put_fail;
- u = unix_find_socket_byinode(net, inode);
+ u = unix_find_socket_byinode(inode);
if (!u)
goto put_fail;
@@ -1140,8 +1159,7 @@ restart:
unix_peer(newsk) = sk;
newsk->sk_state = TCP_ESTABLISHED;
newsk->sk_type = sk->sk_type;
- newsk->sk_peercred.pid = task_tgid_vnr(current);
- current_euid_egid(&newsk->sk_peercred.uid, &newsk->sk_peercred.gid);
+ init_peercred(newsk);
newu = unix_sk(newsk);
newsk->sk_wq = &newu->peer_wq;
otheru = unix_sk(other);
@@ -1157,7 +1175,7 @@ restart:
}
/* Set credentials */
- sk->sk_peercred = other->sk_peercred;
+ copy_peercred(sk, other);
sock->state = SS_CONNECTED;
sk->sk_state = TCP_ESTABLISHED;
@@ -1199,10 +1217,8 @@ static int unix_socketpair(struct socket *socka, struct socket *sockb)
sock_hold(skb);
unix_peer(ska) = skb;
unix_peer(skb) = ska;
- ska->sk_peercred.pid = skb->sk_peercred.pid = task_tgid_vnr(current);
- current_euid_egid(&skb->sk_peercred.uid, &skb->sk_peercred.gid);
- ska->sk_peercred.uid = skb->sk_peercred.uid;
- ska->sk_peercred.gid = skb->sk_peercred.gid;
+ init_peercred(ska);
+ init_peercred(skb);
if (ska->sk_type != SOCK_DGRAM) {
ska->sk_state = TCP_ESTABLISHED;
@@ -1297,18 +1313,20 @@ static void unix_detach_fds(struct scm_cookie *scm, struct sk_buff *skb)
int i;
scm->fp = UNIXCB(skb).fp;
- skb->destructor = sock_wfree;
UNIXCB(skb).fp = NULL;
for (i = scm->fp->count-1; i >= 0; i--)
unix_notinflight(scm->fp->fp[i]);
}
-static void unix_destruct_fds(struct sk_buff *skb)
+static void unix_destruct_scm(struct sk_buff *skb)
{
struct scm_cookie scm;
memset(&scm, 0, sizeof(scm));
- unix_detach_fds(&scm, skb);
+ scm.pid = UNIXCB(skb).pid;
+ scm.cred = UNIXCB(skb).cred;
+ if (UNIXCB(skb).fp)
+ unix_detach_fds(&scm, skb);
/* Alas, it calls VFS */
/* So fscking what? fput() had been SMP-safe since the last Summer */
@@ -1331,10 +1349,22 @@ static int unix_attach_fds(struct scm_cookie *scm, struct sk_buff *skb)
for (i = scm->fp->count-1; i >= 0; i--)
unix_inflight(scm->fp->fp[i]);
- skb->destructor = unix_destruct_fds;
return 0;
}
+static int unix_scm_to_skb(struct scm_cookie *scm, struct sk_buff *skb, bool send_fds)
+{
+ int err = 0;
+ UNIXCB(skb).pid = get_pid(scm->pid);
+ UNIXCB(skb).cred = get_cred(scm->cred);
+ UNIXCB(skb).fp = NULL;
+ if (scm->fp && send_fds)
+ err = unix_attach_fds(scm, skb);
+
+ skb->destructor = unix_destruct_scm;
+ return err;
+}
+
/*
* Send AF_UNIX data.
*/
@@ -1391,12 +1421,9 @@ static int unix_dgram_sendmsg(struct kiocb *kiocb, struct socket *sock,
if (skb == NULL)
goto out;
- memcpy(UNIXCREDS(skb), &siocb->scm->creds, sizeof(struct ucred));
- if (siocb->scm->fp) {
- err = unix_attach_fds(siocb->scm, skb);
- if (err)
- goto out_free;
- }
+ err = unix_scm_to_skb(siocb->scm, skb, true);
+ if (err)
+ goto out_free;
unix_get_secdata(siocb->scm, skb);
skb_reset_transport_header(skb);
@@ -1566,16 +1593,14 @@ static int unix_stream_sendmsg(struct kiocb *kiocb, struct socket *sock,
*/
size = min_t(int, size, skb_tailroom(skb));
- memcpy(UNIXCREDS(skb), &siocb->scm->creds, sizeof(struct ucred));
+
/* Only send the fds in the first buffer */
- if (siocb->scm->fp && !fds_sent) {
- err = unix_attach_fds(siocb->scm, skb);
- if (err) {
- kfree_skb(skb);
- goto out_err;
- }
- fds_sent = true;
+ err = unix_scm_to_skb(siocb->scm, skb, !fds_sent);
+ if (err) {
+ kfree_skb(skb);
+ goto out_err;
}
+ fds_sent = true;
err = memcpy_fromiovec(skb_put(skb, size), msg->msg_iov, size);
if (err) {
@@ -1692,7 +1717,7 @@ static int unix_dgram_recvmsg(struct kiocb *iocb, struct socket *sock,
siocb->scm = &tmp_scm;
memset(&tmp_scm, 0, sizeof(tmp_scm));
}
- siocb->scm->creds = *UNIXCREDS(skb);
+ scm_set_cred(siocb->scm, UNIXCB(skb).pid, UNIXCB(skb).cred);
unix_set_secdata(siocb->scm, skb);
if (!(flags & MSG_PEEK)) {
@@ -1841,14 +1866,14 @@ static int unix_stream_recvmsg(struct kiocb *iocb, struct socket *sock,
if (check_creds) {
/* Never glue messages from different writers */
- if (memcmp(UNIXCREDS(skb), &siocb->scm->creds,
- sizeof(siocb->scm->creds)) != 0) {
+ if ((UNIXCB(skb).pid != siocb->scm->pid) ||
+ (UNIXCB(skb).cred != siocb->scm->cred)) {
skb_queue_head(&sk->sk_receive_queue, skb);
break;
}
} else {
/* Copy credentials */
- siocb->scm->creds = *UNIXCREDS(skb);
+ scm_set_cred(siocb->scm, UNIXCB(skb).pid, UNIXCB(skb).cred);
check_creds = 1;
}
@@ -1881,7 +1906,7 @@ static int unix_stream_recvmsg(struct kiocb *iocb, struct socket *sock,
break;
}
- kfree_skb(skb);
+ consume_skb(skb);
if (siocb->scm->fp)
break;
diff --git a/net/wanrouter/wanmain.c b/net/wanrouter/wanmain.c
index 258daa80ad9..2bf23406637 100644
--- a/net/wanrouter/wanmain.c
+++ b/net/wanrouter/wanmain.c
@@ -48,7 +48,7 @@
#include <linux/kernel.h>
#include <linux/module.h> /* support for loadable modules */
#include <linux/slab.h> /* kmalloc(), kfree() */
-#include <linux/smp_lock.h>
+#include <linux/mutex.h>
#include <linux/mm.h>
#include <linux/string.h> /* inline mem*, str* functions */
@@ -71,6 +71,7 @@
* WAN device IOCTL handlers
*/
+static DEFINE_MUTEX(wanrouter_mutex);
static int wanrouter_device_setup(struct wan_device *wandev,
wandev_conf_t __user *u_conf);
static int wanrouter_device_stat(struct wan_device *wandev,
@@ -376,7 +377,7 @@ long wanrouter_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
if (wandev->magic != ROUTER_MAGIC)
return -EINVAL;
- lock_kernel();
+ mutex_lock(&wanrouter_mutex);
switch (cmd) {
case ROUTER_SETUP:
err = wanrouter_device_setup(wandev, data);
@@ -408,7 +409,7 @@ long wanrouter_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
err = wandev->ioctl(wandev, cmd, arg);
else err = -EINVAL;
}
- unlock_kernel();
+ mutex_unlock(&wanrouter_mutex);
return err;
}
diff --git a/net/wanrouter/wanproc.c b/net/wanrouter/wanproc.c
index c44d96b3a43..11f25c7a7a0 100644
--- a/net/wanrouter/wanproc.c
+++ b/net/wanrouter/wanproc.c
@@ -27,7 +27,7 @@
#include <linux/module.h>
#include <linux/wanrouter.h> /* WAN router API definitions */
#include <linux/seq_file.h>
-#include <linux/smp_lock.h>
+#include <linux/mutex.h>
#include <net/net_namespace.h>
#include <asm/io.h>
@@ -66,6 +66,7 @@
* /proc/net/router
*/
+static DEFINE_MUTEX(config_mutex);
static struct proc_dir_entry *proc_router;
/* Strings */
@@ -85,7 +86,7 @@ static void *r_start(struct seq_file *m, loff_t *pos)
struct wan_device *wandev;
loff_t l = *pos;
- lock_kernel();
+ mutex_lock(&config_mutex);
if (!l--)
return SEQ_START_TOKEN;
for (wandev = wanrouter_router_devlist; l-- && wandev;
@@ -104,7 +105,7 @@ static void *r_next(struct seq_file *m, void *v, loff_t *pos)
static void r_stop(struct seq_file *m, void *v)
__releases(kernel_lock)
{
- unlock_kernel();
+ mutex_unlock(&config_mutex);
}
static int config_show(struct seq_file *m, void *v)
diff --git a/net/wireless/chan.c b/net/wireless/chan.c
index b01a6f6397d..d0c92dddb26 100644
--- a/net/wireless/chan.c
+++ b/net/wireless/chan.c
@@ -35,8 +35,9 @@ rdev_freq_to_chan(struct cfg80211_registered_device *rdev,
if (!ht_cap->ht_supported)
return NULL;
- if (!(ht_cap->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) ||
- ht_cap->cap & IEEE80211_HT_CAP_40MHZ_INTOLERANT)
+ if (channel_type != NL80211_CHAN_HT20 &&
+ (!(ht_cap->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) ||
+ ht_cap->cap & IEEE80211_HT_CAP_40MHZ_INTOLERANT))
return NULL;
}
diff --git a/net/wireless/core.c b/net/wireless/core.c
index 37d0e0ab443..541e2fff5e9 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -472,24 +472,22 @@ int wiphy_register(struct wiphy *wiphy)
/* check and set up bitrates */
ieee80211_set_bitrate_flags(wiphy);
+ mutex_lock(&cfg80211_mutex);
+
res = device_add(&rdev->wiphy.dev);
if (res)
- return res;
+ goto out_unlock;
res = rfkill_register(rdev->rfkill);
if (res)
goto out_rm_dev;
- mutex_lock(&cfg80211_mutex);
-
/* set up regulatory info */
wiphy_update_regulatory(wiphy, NL80211_REGDOM_SET_BY_CORE);
list_add_rcu(&rdev->list, &cfg80211_rdev_list);
cfg80211_rdev_list_generation++;
- mutex_unlock(&cfg80211_mutex);
-
/* add to debugfs */
rdev->wiphy.debugfsdir =
debugfs_create_dir(wiphy_name(&rdev->wiphy),
@@ -509,11 +507,15 @@ int wiphy_register(struct wiphy *wiphy)
}
cfg80211_debugfs_rdev_add(rdev);
+ mutex_unlock(&cfg80211_mutex);
return 0;
- out_rm_dev:
+out_rm_dev:
device_del(&rdev->wiphy.dev);
+
+out_unlock:
+ mutex_unlock(&cfg80211_mutex);
return res;
}
EXPORT_SYMBOL(wiphy_register);
@@ -894,7 +896,7 @@ out_fail_pernet:
}
subsys_initcall(cfg80211_init);
-static void cfg80211_exit(void)
+static void __exit cfg80211_exit(void)
{
debugfs_remove(ieee80211_debugfs_dir);
nl80211_exit();
@@ -905,3 +907,52 @@ static void cfg80211_exit(void)
destroy_workqueue(cfg80211_wq);
}
module_exit(cfg80211_exit);
+
+static int ___wiphy_printk(const char *level, const struct wiphy *wiphy,
+ struct va_format *vaf)
+{
+ if (!wiphy)
+ return printk("%s(NULL wiphy *): %pV", level, vaf);
+
+ return printk("%s%s: %pV", level, wiphy_name(wiphy), vaf);
+}
+
+int __wiphy_printk(const char *level, const struct wiphy *wiphy,
+ const char *fmt, ...)
+{
+ struct va_format vaf;
+ va_list args;
+ int r;
+
+ va_start(args, fmt);
+
+ vaf.fmt = fmt;
+ vaf.va = &args;
+
+ r = ___wiphy_printk(level, wiphy, &vaf);
+ va_end(args);
+
+ return r;
+}
+EXPORT_SYMBOL(__wiphy_printk);
+
+#define define_wiphy_printk_level(func, kern_level) \
+int func(const struct wiphy *wiphy, const char *fmt, ...) \
+{ \
+ struct va_format vaf; \
+ va_list args; \
+ int r; \
+ \
+ va_start(args, fmt); \
+ \
+ vaf.fmt = fmt; \
+ vaf.va = &args; \
+ \
+ r = ___wiphy_printk(kern_level, wiphy, &vaf); \
+ va_end(args); \
+ \
+ return r; \
+} \
+EXPORT_SYMBOL(func);
+
+define_wiphy_printk_level(wiphy_debug, KERN_DEBUG);
diff --git a/net/wireless/core.h b/net/wireless/core.h
index ae930acf75e..63d57ae399c 100644
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
@@ -339,6 +339,7 @@ int cfg80211_mlme_action(struct cfg80211_registered_device *rdev,
struct net_device *dev,
struct ieee80211_channel *chan,
enum nl80211_channel_type channel_type,
+ bool channel_type_valid,
const u8 *buf, size_t len, u64 *cookie);
/* SME */
diff --git a/net/wireless/genregdb.awk b/net/wireless/genregdb.awk
index 3cc9e69880a..53c143f5e77 100644
--- a/net/wireless/genregdb.awk
+++ b/net/wireless/genregdb.awk
@@ -21,6 +21,7 @@ BEGIN {
print ""
print "#include <linux/nl80211.h>"
print "#include <net/cfg80211.h>"
+ print "#include \"regdb.h\""
print ""
regdb = "const struct ieee80211_regdomain *reg_regdb[] = {\n"
}
diff --git a/net/wireless/ibss.c b/net/wireless/ibss.c
index adcabba02e2..27a8ce9343c 100644
--- a/net/wireless/ibss.c
+++ b/net/wireless/ibss.c
@@ -247,8 +247,10 @@ int cfg80211_ibss_wext_join(struct cfg80211_registered_device *rdev,
if (!netif_running(wdev->netdev))
return 0;
- if (wdev->wext.keys)
+ if (wdev->wext.keys) {
wdev->wext.keys->def = wdev->wext.default_key;
+ wdev->wext.keys->defmgmt = wdev->wext.default_mgmt_key;
+ }
wdev->wext.ibss.privacy = wdev->wext.default_key != -1;
diff --git a/net/wireless/lib80211_crypt_ccmp.c b/net/wireless/lib80211_crypt_ccmp.c
index b7fa31d5fd1..dacb3b4b1bd 100644
--- a/net/wireless/lib80211_crypt_ccmp.c
+++ b/net/wireless/lib80211_crypt_ccmp.c
@@ -467,7 +467,6 @@ static struct lib80211_crypto_ops lib80211_crypt_ccmp = {
.name = "CCMP",
.init = lib80211_ccmp_init,
.deinit = lib80211_ccmp_deinit,
- .build_iv = lib80211_ccmp_hdr,
.encrypt_mpdu = lib80211_ccmp_encrypt,
.decrypt_mpdu = lib80211_ccmp_decrypt,
.encrypt_msdu = NULL,
diff --git a/net/wireless/lib80211_crypt_tkip.c b/net/wireless/lib80211_crypt_tkip.c
index 8cbdb32ff31..0fe40510e2c 100644
--- a/net/wireless/lib80211_crypt_tkip.c
+++ b/net/wireless/lib80211_crypt_tkip.c
@@ -578,7 +578,7 @@ static void michael_mic_hdr(struct sk_buff *skb, u8 * hdr)
}
if (ieee80211_is_data_qos(hdr11->frame_control)) {
- hdr[12] = le16_to_cpu(*ieee80211_get_qos_ctl(hdr11))
+ hdr[12] = le16_to_cpu(*((__le16 *)ieee80211_get_qos_ctl(hdr11)))
& IEEE80211_QOS_CTL_TID_MASK;
} else
hdr[12] = 0; /* priority */
@@ -757,7 +757,6 @@ static struct lib80211_crypto_ops lib80211_crypt_tkip = {
.name = "TKIP",
.init = lib80211_tkip_init,
.deinit = lib80211_tkip_deinit,
- .build_iv = lib80211_tkip_hdr,
.encrypt_mpdu = lib80211_tkip_encrypt,
.decrypt_mpdu = lib80211_tkip_decrypt,
.encrypt_msdu = lib80211_michael_mic_add,
diff --git a/net/wireless/lib80211_crypt_wep.c b/net/wireless/lib80211_crypt_wep.c
index 6d41e05ca33..e2e88878ba3 100644
--- a/net/wireless/lib80211_crypt_wep.c
+++ b/net/wireless/lib80211_crypt_wep.c
@@ -269,7 +269,6 @@ static struct lib80211_crypto_ops lib80211_crypt_wep = {
.name = "WEP",
.init = lib80211_wep_init,
.deinit = lib80211_wep_deinit,
- .build_iv = lib80211_wep_build_iv,
.encrypt_mpdu = lib80211_wep_encrypt,
.decrypt_mpdu = lib80211_wep_decrypt,
.encrypt_msdu = NULL,
diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c
index 48ead6f0426..e74a1a2119d 100644
--- a/net/wireless/mlme.c
+++ b/net/wireless/mlme.c
@@ -44,10 +44,10 @@ void cfg80211_send_rx_auth(struct net_device *dev, const u8 *buf, size_t len)
}
}
- WARN_ON(!done);
-
- nl80211_send_rx_auth(rdev, dev, buf, len, GFP_KERNEL);
- cfg80211_sme_rx_auth(dev, buf, len);
+ if (done) {
+ nl80211_send_rx_auth(rdev, dev, buf, len, GFP_KERNEL);
+ cfg80211_sme_rx_auth(dev, buf, len);
+ }
wdev_unlock(wdev);
}
@@ -827,6 +827,7 @@ int cfg80211_mlme_action(struct cfg80211_registered_device *rdev,
struct net_device *dev,
struct ieee80211_channel *chan,
enum nl80211_channel_type channel_type,
+ bool channel_type_valid,
const u8 *buf, size_t len, u64 *cookie)
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
@@ -845,8 +846,9 @@ int cfg80211_mlme_action(struct cfg80211_registered_device *rdev,
if (!wdev->current_bss ||
memcmp(wdev->current_bss->pub.bssid, mgmt->bssid,
ETH_ALEN) != 0 ||
- memcmp(wdev->current_bss->pub.bssid, mgmt->da,
- ETH_ALEN) != 0)
+ (wdev->iftype == NL80211_IFTYPE_STATION &&
+ memcmp(wdev->current_bss->pub.bssid, mgmt->da,
+ ETH_ALEN) != 0))
return -ENOTCONN;
}
@@ -855,7 +857,7 @@ int cfg80211_mlme_action(struct cfg80211_registered_device *rdev,
/* Transmit the Action frame as requested by user space */
return rdev->ops->action(&rdev->wiphy, dev, chan, channel_type,
- buf, len, cookie);
+ channel_type_valid, buf, len, cookie);
}
bool cfg80211_rx_action(struct net_device *dev, int freq, const u8 *buf,
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index db71150b804..37902a54e9c 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -153,6 +153,9 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = {
[NL80211_ATTR_CQM] = { .type = NLA_NESTED, },
[NL80211_ATTR_LOCAL_STATE_CHANGE] = { .type = NLA_FLAG },
[NL80211_ATTR_AP_ISOLATE] = { .type = NLA_U8 },
+
+ [NL80211_ATTR_WIPHY_TX_POWER_SETTING] = { .type = NLA_U32 },
+ [NL80211_ATTR_WIPHY_TX_POWER_LEVEL] = { .type = NLA_U32 },
};
/* policy for the attributes */
@@ -869,6 +872,34 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
goto bad_res;
}
+ if (info->attrs[NL80211_ATTR_WIPHY_TX_POWER_SETTING]) {
+ enum nl80211_tx_power_setting type;
+ int idx, mbm = 0;
+
+ if (!rdev->ops->set_tx_power) {
+ result = -EOPNOTSUPP;
+ goto bad_res;
+ }
+
+ idx = NL80211_ATTR_WIPHY_TX_POWER_SETTING;
+ type = nla_get_u32(info->attrs[idx]);
+
+ if (!info->attrs[NL80211_ATTR_WIPHY_TX_POWER_LEVEL] &&
+ (type != NL80211_TX_POWER_AUTOMATIC)) {
+ result = -EINVAL;
+ goto bad_res;
+ }
+
+ if (type != NL80211_TX_POWER_AUTOMATIC) {
+ idx = NL80211_ATTR_WIPHY_TX_POWER_LEVEL;
+ mbm = nla_get_u32(info->attrs[idx]);
+ }
+
+ result = rdev->ops->set_tx_power(&rdev->wiphy, type, mbm);
+ if (result)
+ goto bad_res;
+ }
+
changed = 0;
if (info->attrs[NL80211_ATTR_WIPHY_RETRY_SHORT]) {
@@ -1107,7 +1138,7 @@ static int nl80211_valid_4addr(struct cfg80211_registered_device *rdev,
enum nl80211_iftype iftype)
{
if (!use_4addr) {
- if (netdev && netdev->br_port)
+ if (netdev && (netdev->priv_flags & IFF_BRIDGE_PORT))
return -EBUSY;
return 0;
}
@@ -2738,6 +2769,7 @@ static int nl80211_get_mesh_params(struct sk_buff *skb,
nla_put_failure:
genlmsg_cancel(msg, hdr);
+ nlmsg_free(msg);
err = -EMSGSIZE;
out:
/* Cleanup */
@@ -2929,6 +2961,7 @@ static int nl80211_get_reg(struct sk_buff *skb, struct genl_info *info)
nla_put_failure:
genlmsg_cancel(msg, hdr);
+ nlmsg_free(msg);
err = -EMSGSIZE;
out:
mutex_unlock(&cfg80211_mutex);
@@ -3955,6 +3988,55 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info)
}
}
+ if (info->attrs[NL80211_ATTR_BSS_BASIC_RATES]) {
+ u8 *rates =
+ nla_data(info->attrs[NL80211_ATTR_BSS_BASIC_RATES]);
+ int n_rates =
+ nla_len(info->attrs[NL80211_ATTR_BSS_BASIC_RATES]);
+ struct ieee80211_supported_band *sband =
+ wiphy->bands[ibss.channel->band];
+ int i, j;
+
+ if (n_rates == 0) {
+ err = -EINVAL;
+ goto out;
+ }
+
+ for (i = 0; i < n_rates; i++) {
+ int rate = (rates[i] & 0x7f) * 5;
+ bool found = false;
+
+ for (j = 0; j < sband->n_bitrates; j++) {
+ if (sband->bitrates[j].bitrate == rate) {
+ found = true;
+ ibss.basic_rates |= BIT(j);
+ break;
+ }
+ }
+ if (!found) {
+ err = -EINVAL;
+ goto out;
+ }
+ }
+ } else {
+ /*
+ * If no rates were explicitly configured,
+ * use the mandatory rate set for 11b or
+ * 11a for maximum compatibility.
+ */
+ struct ieee80211_supported_band *sband =
+ wiphy->bands[ibss.channel->band];
+ int j;
+ u32 flag = ibss.channel->band == IEEE80211_BAND_5GHZ ?
+ IEEE80211_RATE_MANDATORY_A :
+ IEEE80211_RATE_MANDATORY_B;
+
+ for (j = 0; j < sband->n_bitrates; j++) {
+ if (sband->bitrates[j].flags & flag)
+ ibss.basic_rates |= BIT(j);
+ }
+ }
+
err = cfg80211_join_ibss(rdev, dev, &ibss, connkeys);
out:
@@ -4653,7 +4735,8 @@ static int nl80211_register_action(struct sk_buff *skb, struct genl_info *info)
if (err)
goto unlock_rtnl;
- if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION) {
+ if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION &&
+ dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC) {
err = -EOPNOTSUPP;
goto out;
}
@@ -4681,6 +4764,7 @@ static int nl80211_action(struct sk_buff *skb, struct genl_info *info)
struct net_device *dev;
struct ieee80211_channel *chan;
enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT;
+ bool channel_type_valid = false;
u32 freq;
int err;
void *hdr;
@@ -4702,7 +4786,8 @@ static int nl80211_action(struct sk_buff *skb, struct genl_info *info)
goto out;
}
- if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION) {
+ if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION &&
+ dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC) {
err = -EOPNOTSUPP;
goto out;
}
@@ -4722,6 +4807,7 @@ static int nl80211_action(struct sk_buff *skb, struct genl_info *info)
err = -EINVAL;
goto out;
}
+ channel_type_valid = true;
}
freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]);
@@ -4745,6 +4831,7 @@ static int nl80211_action(struct sk_buff *skb, struct genl_info *info)
goto free_msg;
}
err = cfg80211_mlme_action(rdev, dev, chan, channel_type,
+ channel_type_valid,
nla_data(info->attrs[NL80211_ATTR_FRAME]),
nla_len(info->attrs[NL80211_ATTR_FRAME]),
&cookie);
diff --git a/net/wireless/reg.c b/net/wireless/reg.c
index 8f0d97dd310..f180db0de66 100644
--- a/net/wireless/reg.c
+++ b/net/wireless/reg.c
@@ -67,20 +67,12 @@ static struct platform_device *reg_pdev;
const struct ieee80211_regdomain *cfg80211_regdomain;
/*
- * We use this as a place for the rd structure built from the
- * last parsed country IE to rest until CRDA gets back to us with
- * what it thinks should apply for the same country
- */
-static const struct ieee80211_regdomain *country_ie_regdomain;
-
-/*
* Protects static reg.c components:
* - cfg80211_world_regdom
* - cfg80211_regdom
- * - country_ie_regdomain
* - last_request
*/
-DEFINE_MUTEX(reg_mutex);
+static DEFINE_MUTEX(reg_mutex);
#define assert_reg_lock() WARN_ON(!mutex_is_locked(&reg_mutex))
/* Used to queue up regulatory hints */
@@ -275,25 +267,6 @@ static bool is_user_regdom_saved(void)
return true;
}
-/**
- * country_ie_integrity_changes - tells us if the country IE has changed
- * @checksum: checksum of country IE of fields we are interested in
- *
- * If the country IE has not changed you can ignore it safely. This is
- * useful to determine if two devices are seeing two different country IEs
- * even on the same alpha2. Note that this will return false if no IE has
- * been set on the wireless core yet.
- */
-static bool country_ie_integrity_changes(u32 checksum)
-{
- /* If no IE has been set then the checksum doesn't change */
- if (unlikely(!last_request->country_ie_checksum))
- return false;
- if (unlikely(last_request->country_ie_checksum != checksum))
- return true;
- return false;
-}
-
static int reg_copy_regd(const struct ieee80211_regdomain **dst_regd,
const struct ieee80211_regdomain *src_regd)
{
@@ -506,471 +479,6 @@ static bool freq_in_rule_band(const struct ieee80211_freq_range *freq_range,
}
/*
- * This is a work around for sanity checking ieee80211_channel_to_frequency()'s
- * work. ieee80211_channel_to_frequency() can for example currently provide a
- * 2 GHz channel when in fact a 5 GHz channel was desired. An example would be
- * an AP providing channel 8 on a country IE triplet when it sent this on the
- * 5 GHz band, that channel is designed to be channel 8 on 5 GHz, not a 2 GHz
- * channel.
- *
- * This can be removed once ieee80211_channel_to_frequency() takes in a band.
- */
-static bool chan_in_band(int chan, enum ieee80211_band band)
-{
- int center_freq = ieee80211_channel_to_frequency(chan);
-
- switch (band) {
- case IEEE80211_BAND_2GHZ:
- if (center_freq <= 2484)
- return true;
- return false;
- case IEEE80211_BAND_5GHZ:
- if (center_freq >= 5005)
- return true;
- return false;
- default:
- return false;
- }
-}
-
-/*
- * Some APs may send a country IE triplet for each channel they
- * support and while this is completely overkill and silly we still
- * need to support it. We avoid making a single rule for each channel
- * though and to help us with this we use this helper to find the
- * actual subband end channel. These type of country IE triplet
- * scenerios are handled then, all yielding two regulaotry rules from
- * parsing a country IE:
- *
- * [1]
- * [2]
- * [36]
- * [40]
- *
- * [1]
- * [2-4]
- * [5-12]
- * [36]
- * [40-44]
- *
- * [1-4]
- * [5-7]
- * [36-44]
- * [48-64]
- *
- * [36-36]
- * [40-40]
- * [44-44]
- * [48-48]
- * [52-52]
- * [56-56]
- * [60-60]
- * [64-64]
- * [100-100]
- * [104-104]
- * [108-108]
- * [112-112]
- * [116-116]
- * [120-120]
- * [124-124]
- * [128-128]
- * [132-132]
- * [136-136]
- * [140-140]
- *
- * Returns 0 if the IE has been found to be invalid in the middle
- * somewhere.
- */
-static int max_subband_chan(enum ieee80211_band band,
- int orig_cur_chan,
- int orig_end_channel,
- s8 orig_max_power,
- u8 **country_ie,
- u8 *country_ie_len)
-{
- u8 *triplets_start = *country_ie;
- u8 len_at_triplet = *country_ie_len;
- int end_subband_chan = orig_end_channel;
-
- /*
- * We'll deal with padding for the caller unless
- * its not immediate and we don't process any channels
- */
- if (*country_ie_len == 1) {
- *country_ie += 1;
- *country_ie_len -= 1;
- return orig_end_channel;
- }
-
- /* Move to the next triplet and then start search */
- *country_ie += 3;
- *country_ie_len -= 3;
-
- if (!chan_in_band(orig_cur_chan, band))
- return 0;
-
- while (*country_ie_len >= 3) {
- int end_channel = 0;
- struct ieee80211_country_ie_triplet *triplet =
- (struct ieee80211_country_ie_triplet *) *country_ie;
- int cur_channel = 0, next_expected_chan;
-
- /* means last triplet is completely unrelated to this one */
- if (triplet->ext.reg_extension_id >=
- IEEE80211_COUNTRY_EXTENSION_ID) {
- *country_ie -= 3;
- *country_ie_len += 3;
- break;
- }
-
- if (triplet->chans.first_channel == 0) {
- *country_ie += 1;
- *country_ie_len -= 1;
- if (*country_ie_len != 0)
- return 0;
- break;
- }
-
- if (triplet->chans.num_channels == 0)
- return 0;
-
- /* Monitonically increasing channel order */
- if (triplet->chans.first_channel <= end_subband_chan)
- return 0;
-
- if (!chan_in_band(triplet->chans.first_channel, band))
- return 0;
-
- /* 2 GHz */
- if (triplet->chans.first_channel <= 14) {
- end_channel = triplet->chans.first_channel +
- triplet->chans.num_channels - 1;
- }
- else {
- end_channel = triplet->chans.first_channel +
- (4 * (triplet->chans.num_channels - 1));
- }
-
- if (!chan_in_band(end_channel, band))
- return 0;
-
- if (orig_max_power != triplet->chans.max_power) {
- *country_ie -= 3;
- *country_ie_len += 3;
- break;
- }
-
- cur_channel = triplet->chans.first_channel;
-
- /* The key is finding the right next expected channel */
- if (band == IEEE80211_BAND_2GHZ)
- next_expected_chan = end_subband_chan + 1;
- else
- next_expected_chan = end_subband_chan + 4;
-
- if (cur_channel != next_expected_chan) {
- *country_ie -= 3;
- *country_ie_len += 3;
- break;
- }
-
- end_subband_chan = end_channel;
-
- /* Move to the next one */
- *country_ie += 3;
- *country_ie_len -= 3;
-
- /*
- * Padding needs to be dealt with if we processed
- * some channels.
- */
- if (*country_ie_len == 1) {
- *country_ie += 1;
- *country_ie_len -= 1;
- break;
- }
-
- /* If seen, the IE is invalid */
- if (*country_ie_len == 2)
- return 0;
- }
-
- if (end_subband_chan == orig_end_channel) {
- *country_ie = triplets_start;
- *country_ie_len = len_at_triplet;
- return orig_end_channel;
- }
-
- return end_subband_chan;
-}
-
-/*
- * Converts a country IE to a regulatory domain. A regulatory domain
- * structure has a lot of information which the IE doesn't yet have,
- * so for the other values we use upper max values as we will intersect
- * with our userspace regulatory agent to get lower bounds.
- */
-static struct ieee80211_regdomain *country_ie_2_rd(
- enum ieee80211_band band,
- u8 *country_ie,
- u8 country_ie_len,
- u32 *checksum)
-{
- struct ieee80211_regdomain *rd = NULL;
- unsigned int i = 0;
- char alpha2[2];
- u32 flags = 0;
- u32 num_rules = 0, size_of_regd = 0;
- u8 *triplets_start = NULL;
- u8 len_at_triplet = 0;
- /* the last channel we have registered in a subband (triplet) */
- int last_sub_max_channel = 0;
-
- *checksum = 0xDEADBEEF;
-
- /* Country IE requirements */
- BUG_ON(country_ie_len < IEEE80211_COUNTRY_IE_MIN_LEN ||
- country_ie_len & 0x01);
-
- alpha2[0] = country_ie[0];
- alpha2[1] = country_ie[1];
-
- /*
- * Third octet can be:
- * 'I' - Indoor
- * 'O' - Outdoor
- *
- * anything else we assume is no restrictions
- */
- if (country_ie[2] == 'I')
- flags = NL80211_RRF_NO_OUTDOOR;
- else if (country_ie[2] == 'O')
- flags = NL80211_RRF_NO_INDOOR;
-
- country_ie += 3;
- country_ie_len -= 3;
-
- triplets_start = country_ie;
- len_at_triplet = country_ie_len;
-
- *checksum ^= ((flags ^ alpha2[0] ^ alpha2[1]) << 8);
-
- /*
- * We need to build a reg rule for each triplet, but first we must
- * calculate the number of reg rules we will need. We will need one
- * for each channel subband
- */
- while (country_ie_len >= 3) {
- int end_channel = 0;
- struct ieee80211_country_ie_triplet *triplet =
- (struct ieee80211_country_ie_triplet *) country_ie;
- int cur_sub_max_channel = 0, cur_channel = 0;
-
- if (triplet->ext.reg_extension_id >=
- IEEE80211_COUNTRY_EXTENSION_ID) {
- country_ie += 3;
- country_ie_len -= 3;
- continue;
- }
-
- /*
- * APs can add padding to make length divisible
- * by two, required by the spec.
- */
- if (triplet->chans.first_channel == 0) {
- country_ie++;
- country_ie_len--;
- /* This is expected to be at the very end only */
- if (country_ie_len != 0)
- return NULL;
- break;
- }
-
- if (triplet->chans.num_channels == 0)
- return NULL;
-
- if (!chan_in_band(triplet->chans.first_channel, band))
- return NULL;
-
- /* 2 GHz */
- if (band == IEEE80211_BAND_2GHZ)
- end_channel = triplet->chans.first_channel +
- triplet->chans.num_channels - 1;
- else
- /*
- * 5 GHz -- For example in country IEs if the first
- * channel given is 36 and the number of channels is 4
- * then the individual channel numbers defined for the
- * 5 GHz PHY by these parameters are: 36, 40, 44, and 48
- * and not 36, 37, 38, 39.
- *
- * See: http://tinyurl.com/11d-clarification
- */
- end_channel = triplet->chans.first_channel +
- (4 * (triplet->chans.num_channels - 1));
-
- cur_channel = triplet->chans.first_channel;
-
- /*
- * Enhancement for APs that send a triplet for every channel
- * or for whatever reason sends triplets with multiple channels
- * separated when in fact they should be together.
- */
- end_channel = max_subband_chan(band,
- cur_channel,
- end_channel,
- triplet->chans.max_power,
- &country_ie,
- &country_ie_len);
- if (!end_channel)
- return NULL;
-
- if (!chan_in_band(end_channel, band))
- return NULL;
-
- cur_sub_max_channel = end_channel;
-
- /* Basic sanity check */
- if (cur_sub_max_channel < cur_channel)
- return NULL;
-
- /*
- * Do not allow overlapping channels. Also channels
- * passed in each subband must be monotonically
- * increasing
- */
- if (last_sub_max_channel) {
- if (cur_channel <= last_sub_max_channel)
- return NULL;
- if (cur_sub_max_channel <= last_sub_max_channel)
- return NULL;
- }
-
- /*
- * When dot11RegulatoryClassesRequired is supported
- * we can throw ext triplets as part of this soup,
- * for now we don't care when those change as we
- * don't support them
- */
- *checksum ^= ((cur_channel ^ cur_sub_max_channel) << 8) |
- ((cur_sub_max_channel ^ cur_sub_max_channel) << 16) |
- ((triplet->chans.max_power ^ cur_sub_max_channel) << 24);
-
- last_sub_max_channel = cur_sub_max_channel;
-
- num_rules++;
-
- if (country_ie_len >= 3) {
- country_ie += 3;
- country_ie_len -= 3;
- }
-
- /*
- * Note: this is not a IEEE requirement but
- * simply a memory requirement
- */
- if (num_rules > NL80211_MAX_SUPP_REG_RULES)
- return NULL;
- }
-
- country_ie = triplets_start;
- country_ie_len = len_at_triplet;
-
- size_of_regd = sizeof(struct ieee80211_regdomain) +
- (num_rules * sizeof(struct ieee80211_reg_rule));
-
- rd = kzalloc(size_of_regd, GFP_KERNEL);
- if (!rd)
- return NULL;
-
- rd->n_reg_rules = num_rules;
- rd->alpha2[0] = alpha2[0];
- rd->alpha2[1] = alpha2[1];
-
- /* This time around we fill in the rd */
- while (country_ie_len >= 3) {
- int end_channel = 0;
- struct ieee80211_country_ie_triplet *triplet =
- (struct ieee80211_country_ie_triplet *) country_ie;
- struct ieee80211_reg_rule *reg_rule = NULL;
- struct ieee80211_freq_range *freq_range = NULL;
- struct ieee80211_power_rule *power_rule = NULL;
-
- /*
- * Must parse if dot11RegulatoryClassesRequired is true,
- * we don't support this yet
- */
- if (triplet->ext.reg_extension_id >=
- IEEE80211_COUNTRY_EXTENSION_ID) {
- country_ie += 3;
- country_ie_len -= 3;
- continue;
- }
-
- if (triplet->chans.first_channel == 0) {
- country_ie++;
- country_ie_len--;
- break;
- }
-
- reg_rule = &rd->reg_rules[i];
- freq_range = &reg_rule->freq_range;
- power_rule = &reg_rule->power_rule;
-
- reg_rule->flags = flags;
-
- /* 2 GHz */
- if (band == IEEE80211_BAND_2GHZ)
- end_channel = triplet->chans.first_channel +
- triplet->chans.num_channels -1;
- else
- end_channel = triplet->chans.first_channel +
- (4 * (triplet->chans.num_channels - 1));
-
- end_channel = max_subband_chan(band,
- triplet->chans.first_channel,
- end_channel,
- triplet->chans.max_power,
- &country_ie,
- &country_ie_len);
-
- /*
- * The +10 is since the regulatory domain expects
- * the actual band edge, not the center of freq for
- * its start and end freqs, assuming 20 MHz bandwidth on
- * the channels passed
- */
- freq_range->start_freq_khz =
- MHZ_TO_KHZ(ieee80211_channel_to_frequency(
- triplet->chans.first_channel) - 10);
- freq_range->end_freq_khz =
- MHZ_TO_KHZ(ieee80211_channel_to_frequency(
- end_channel) + 10);
-
- /*
- * These are large arbitrary values we use to intersect later.
- * Increment this if we ever support >= 40 MHz channels
- * in IEEE 802.11
- */
- freq_range->max_bandwidth_khz = MHZ_TO_KHZ(40);
- power_rule->max_antenna_gain = DBI_TO_MBI(100);
- power_rule->max_eirp = DBM_TO_MBM(triplet->chans.max_power);
-
- i++;
-
- if (country_ie_len >= 3) {
- country_ie += 3;
- country_ie_len -= 3;
- }
-
- BUG_ON(i > NL80211_MAX_SUPP_REG_RULES);
- }
-
- return rd;
-}
-
-
-/*
* Helper for regdom_intersect(), this does the real
* mathematical intersection fun
*/
@@ -1191,7 +699,6 @@ static int freq_reg_info_regd(struct wiphy *wiphy,
return -EINVAL;
}
-EXPORT_SYMBOL(freq_reg_info);
int freq_reg_info(struct wiphy *wiphy,
u32 center_freq,
@@ -1205,6 +712,7 @@ int freq_reg_info(struct wiphy *wiphy,
reg_rule,
NULL);
}
+EXPORT_SYMBOL(freq_reg_info);
/*
* Note that right now we assume the desired channel bandwidth
@@ -1243,41 +751,8 @@ static void handle_channel(struct wiphy *wiphy, enum ieee80211_band band,
desired_bw_khz,
&reg_rule);
- if (r) {
- /*
- * This means no regulatory rule was found in the country IE
- * with a frequency range on the center_freq's band, since
- * IEEE-802.11 allows for a country IE to have a subset of the
- * regulatory information provided in a country we ignore
- * disabling the channel unless at least one reg rule was
- * found on the center_freq's band. For details see this
- * clarification:
- *
- * http://tinyurl.com/11d-clarification
- */
- if (r == -ERANGE &&
- last_request->initiator ==
- NL80211_REGDOM_SET_BY_COUNTRY_IE) {
- REG_DBG_PRINT("cfg80211: Leaving channel %d MHz "
- "intact on %s - no rule found in band on "
- "Country IE\n",
- chan->center_freq, wiphy_name(wiphy));
- } else {
- /*
- * In this case we know the country IE has at least one reg rule
- * for the band so we respect its band definitions
- */
- if (last_request->initiator ==
- NL80211_REGDOM_SET_BY_COUNTRY_IE)
- REG_DBG_PRINT("cfg80211: Disabling "
- "channel %d MHz on %s due to "
- "Country IE\n",
- chan->center_freq, wiphy_name(wiphy));
- flags |= IEEE80211_CHAN_DISABLED;
- chan->flags = flags;
- }
+ if (r)
return;
- }
power_rule = &reg_rule->power_rule;
freq_range = &reg_rule->freq_range;
@@ -1831,6 +1306,7 @@ static void reg_process_hint(struct regulatory_request *reg_request)
{
int r = 0;
struct wiphy *wiphy = NULL;
+ enum nl80211_reg_initiator initiator = reg_request->initiator;
BUG_ON(!reg_request->alpha2);
@@ -1850,7 +1326,7 @@ static void reg_process_hint(struct regulatory_request *reg_request)
/* This is required so that the orig_* parameters are saved */
if (r == -EALREADY && wiphy &&
wiphy->flags & WIPHY_FLAG_STRICT_REGULATORY)
- wiphy_update_regulatory(wiphy, reg_request->initiator);
+ wiphy_update_regulatory(wiphy, initiator);
out:
mutex_unlock(&reg_mutex);
mutex_unlock(&cfg80211_mutex);
@@ -2008,35 +1484,6 @@ int regulatory_hint(struct wiphy *wiphy, const char *alpha2)
}
EXPORT_SYMBOL(regulatory_hint);
-/* Caller must hold reg_mutex */
-static bool reg_same_country_ie_hint(struct wiphy *wiphy,
- u32 country_ie_checksum)
-{
- struct wiphy *request_wiphy;
-
- assert_reg_lock();
-
- if (unlikely(last_request->initiator !=
- NL80211_REGDOM_SET_BY_COUNTRY_IE))
- return false;
-
- request_wiphy = wiphy_idx_to_wiphy(last_request->wiphy_idx);
-
- if (!request_wiphy)
- return false;
-
- if (likely(request_wiphy != wiphy))
- return !country_ie_integrity_changes(country_ie_checksum);
- /*
- * We should not have let these through at this point, they
- * should have been picked up earlier by the first alpha2 check
- * on the device
- */
- if (WARN_ON(!country_ie_integrity_changes(country_ie_checksum)))
- return true;
- return false;
-}
-
/*
* We hold wdev_lock() here so we cannot hold cfg80211_mutex() and
* therefore cannot iterate over the rdev list here.
@@ -2046,9 +1493,7 @@ void regulatory_hint_11d(struct wiphy *wiphy,
u8 *country_ie,
u8 country_ie_len)
{
- struct ieee80211_regdomain *rd = NULL;
char alpha2[2];
- u32 checksum = 0;
enum environment_cap env = ENVIRON_ANY;
struct regulatory_request *request;
@@ -2064,14 +1509,6 @@ void regulatory_hint_11d(struct wiphy *wiphy,
if (country_ie_len < IEEE80211_COUNTRY_IE_MIN_LEN)
goto out;
- /*
- * Pending country IE processing, this can happen after we
- * call CRDA and wait for a response if a beacon was received before
- * we were able to process the last regulatory_hint_11d() call
- */
- if (country_ie_regdomain)
- goto out;
-
alpha2[0] = country_ie[0];
alpha2[1] = country_ie[1];
@@ -2090,39 +1527,14 @@ void regulatory_hint_11d(struct wiphy *wiphy,
wiphy_idx_valid(last_request->wiphy_idx)))
goto out;
- rd = country_ie_2_rd(band, country_ie, country_ie_len, &checksum);
- if (!rd) {
- REG_DBG_PRINT("cfg80211: Ignoring bogus country IE\n");
- goto out;
- }
-
- /*
- * This will not happen right now but we leave it here for the
- * the future when we want to add suspend/resume support and having
- * the user move to another country after doing so, or having the user
- * move to another AP. Right now we just trust the first AP.
- *
- * If we hit this before we add this support we want to be informed of
- * it as it would indicate a mistake in the current design
- */
- if (WARN_ON(reg_same_country_ie_hint(wiphy, checksum)))
- goto free_rd_out;
-
request = kzalloc(sizeof(struct regulatory_request), GFP_KERNEL);
if (!request)
- goto free_rd_out;
-
- /*
- * We keep this around for when CRDA comes back with a response so
- * we can intersect with that
- */
- country_ie_regdomain = rd;
+ goto out;
request->wiphy_idx = get_wiphy_idx(wiphy);
- request->alpha2[0] = rd->alpha2[0];
- request->alpha2[1] = rd->alpha2[1];
+ request->alpha2[0] = alpha2[0];
+ request->alpha2[1] = alpha2[1];
request->initiator = NL80211_REGDOM_SET_BY_COUNTRY_IE;
- request->country_ie_checksum = checksum;
request->country_ie_env = env;
mutex_unlock(&reg_mutex);
@@ -2131,8 +1543,6 @@ void regulatory_hint_11d(struct wiphy *wiphy,
return;
-free_rd_out:
- kfree(rd);
out:
mutex_unlock(&reg_mutex);
}
@@ -2383,33 +1793,6 @@ static void print_regdomain_info(const struct ieee80211_regdomain *rd)
print_rd_rules(rd);
}
-#ifdef CONFIG_CFG80211_REG_DEBUG
-static void reg_country_ie_process_debug(
- const struct ieee80211_regdomain *rd,
- const struct ieee80211_regdomain *country_ie_regdomain,
- const struct ieee80211_regdomain *intersected_rd)
-{
- printk(KERN_DEBUG "cfg80211: Received country IE:\n");
- print_regdomain_info(country_ie_regdomain);
- printk(KERN_DEBUG "cfg80211: CRDA thinks this should applied:\n");
- print_regdomain_info(rd);
- if (intersected_rd) {
- printk(KERN_DEBUG "cfg80211: We intersect both of these "
- "and get:\n");
- print_regdomain_info(intersected_rd);
- return;
- }
- printk(KERN_DEBUG "cfg80211: Intersection between both failed\n");
-}
-#else
-static inline void reg_country_ie_process_debug(
- const struct ieee80211_regdomain *rd,
- const struct ieee80211_regdomain *country_ie_regdomain,
- const struct ieee80211_regdomain *intersected_rd)
-{
-}
-#endif
-
/* Takes ownership of rd only if it doesn't fail */
static int __set_regdom(const struct ieee80211_regdomain *rd)
{
@@ -2521,34 +1904,6 @@ static int __set_regdom(const struct ieee80211_regdomain *rd)
return 0;
}
- /*
- * Country IE requests are handled a bit differently, we intersect
- * the country IE rd with what CRDA believes that country should have
- */
-
- /*
- * Userspace could have sent two replies with only
- * one kernel request. By the second reply we would have
- * already processed and consumed the country_ie_regdomain.
- */
- if (!country_ie_regdomain)
- return -EALREADY;
- BUG_ON(rd == country_ie_regdomain);
-
- /*
- * Intersect what CRDA returned and our what we
- * had built from the Country IE received
- */
-
- intersected_rd = regdom_intersect(rd, country_ie_regdomain);
-
- reg_country_ie_process_debug(rd,
- country_ie_regdomain,
- intersected_rd);
-
- kfree(country_ie_regdomain);
- country_ie_regdomain = NULL;
-
if (!intersected_rd)
return -EINVAL;
@@ -2630,7 +1985,7 @@ out:
mutex_unlock(&reg_mutex);
}
-int regulatory_init(void)
+int __init regulatory_init(void)
{
int err = 0;
@@ -2676,7 +2031,7 @@ int regulatory_init(void)
return 0;
}
-void regulatory_exit(void)
+void /* __init_or_exit */ regulatory_exit(void)
{
struct regulatory_request *reg_request, *tmp;
struct reg_beacon *reg_beacon, *btmp;
@@ -2688,9 +2043,6 @@ void regulatory_exit(void)
reset_regdomains();
- kfree(country_ie_regdomain);
- country_ie_regdomain = NULL;
-
kfree(last_request);
platform_device_unregister(reg_pdev);
diff --git a/net/wireless/reg.h b/net/wireless/reg.h
index b26224a9f3b..c4695d07af2 100644
--- a/net/wireless/reg.h
+++ b/net/wireless/reg.h
@@ -10,7 +10,7 @@ int regulatory_hint_user(const char *alpha2);
void reg_device_remove(struct wiphy *wiphy);
-int regulatory_init(void);
+int __init regulatory_init(void);
void regulatory_exit(void);
int set_regdom(const struct ieee80211_regdomain *rd);
diff --git a/net/wireless/scan.c b/net/wireless/scan.c
index 58401d246bd..5ca8c718014 100644
--- a/net/wireless/scan.c
+++ b/net/wireless/scan.c
@@ -275,6 +275,7 @@ struct cfg80211_bss *cfg80211_get_bss(struct wiphy *wiphy,
{
struct cfg80211_registered_device *dev = wiphy_to_dev(wiphy);
struct cfg80211_internal_bss *bss, *res = NULL;
+ unsigned long now = jiffies;
spin_lock_bh(&dev->bss_lock);
@@ -283,6 +284,10 @@ struct cfg80211_bss *cfg80211_get_bss(struct wiphy *wiphy,
continue;
if (channel && bss->pub.channel != channel)
continue;
+ /* Don't get expired BSS structs */
+ if (time_after(now, bss->ts + IEEE80211_SCAN_RESULT_EXPIRE) &&
+ !atomic_read(&bss->hold))
+ continue;
if (is_bss(&bss->pub, bssid, ssid, ssid_len)) {
res = bss;
kref_get(&res->ref);
diff --git a/net/wireless/sme.c b/net/wireless/sme.c
index 72222f0074d..a8c2d6b877a 100644
--- a/net/wireless/sme.c
+++ b/net/wireless/sme.c
@@ -35,7 +35,7 @@ struct cfg80211_conn {
bool auto_auth, prev_bssid_valid;
};
-bool cfg80211_is_all_idle(void)
+static bool cfg80211_is_all_idle(void)
{
struct cfg80211_registered_device *rdev;
struct wireless_dev *wdev;
diff --git a/net/wireless/util.c b/net/wireless/util.c
index 3416373a9c0..0c8a1e8b769 100644
--- a/net/wireless/util.c
+++ b/net/wireless/util.c
@@ -770,8 +770,8 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev,
return -EOPNOTSUPP;
/* if it's part of a bridge, reject changing type to station/ibss */
- if (dev->br_port && (ntype == NL80211_IFTYPE_ADHOC ||
- ntype == NL80211_IFTYPE_STATION))
+ if ((dev->priv_flags & IFF_BRIDGE_PORT) &&
+ (ntype == NL80211_IFTYPE_ADHOC || ntype == NL80211_IFTYPE_STATION))
return -EBUSY;
if (ntype != otype) {
diff --git a/net/wireless/wext-compat.c b/net/wireless/wext-compat.c
index 96342993cf9..bb5e0a5ecfa 100644
--- a/net/wireless/wext-compat.c
+++ b/net/wireless/wext-compat.c
@@ -829,7 +829,7 @@ int cfg80211_wext_siwtxpower(struct net_device *dev,
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
- enum tx_power_setting type;
+ enum nl80211_tx_power_setting type;
int dbm = 0;
if ((data->txpower.flags & IW_TXPOW_TYPE) != IW_TXPOW_DBM)
@@ -852,7 +852,7 @@ int cfg80211_wext_siwtxpower(struct net_device *dev,
if (data->txpower.value < 0)
return -EINVAL;
dbm = data->txpower.value;
- type = TX_POWER_FIXED;
+ type = NL80211_TX_POWER_FIXED;
/* TODO: do regulatory check! */
} else {
/*
@@ -860,10 +860,10 @@ int cfg80211_wext_siwtxpower(struct net_device *dev,
* passed in from userland.
*/
if (data->txpower.value < 0) {
- type = TX_POWER_AUTOMATIC;
+ type = NL80211_TX_POWER_AUTOMATIC;
} else {
dbm = data->txpower.value;
- type = TX_POWER_LIMITED;
+ type = NL80211_TX_POWER_LIMITED;
}
}
} else {
@@ -872,7 +872,7 @@ int cfg80211_wext_siwtxpower(struct net_device *dev,
return 0;
}
- return rdev->ops->set_tx_power(wdev->wiphy, type, dbm);
+ return rdev->ops->set_tx_power(wdev->wiphy, type, DBM_TO_MBM(dbm));
}
EXPORT_SYMBOL_GPL(cfg80211_wext_siwtxpower);
@@ -1471,6 +1471,7 @@ int cfg80211_wext_siwpmksa(struct net_device *dev,
return -EOPNOTSUPP;
}
}
+EXPORT_SYMBOL_GPL(cfg80211_wext_siwpmksa);
static const iw_handler cfg80211_handlers[] = {
[IW_IOCTL_IDX(SIOCGIWNAME)] = (iw_handler) cfg80211_wext_giwname,
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c
index a7ec5a8a238..2b3ed7ad493 100644
--- a/net/xfrm/xfrm_policy.c
+++ b/net/xfrm/xfrm_policy.c
@@ -2492,7 +2492,8 @@ static int __net_init xfrm_statistics_init(struct net *net)
int rv;
if (snmp_mib_init((void __percpu **)net->mib.xfrm_statistics,
- sizeof(struct linux_xfrm_mib)) < 0)
+ sizeof(struct linux_xfrm_mib),
+ __alignof__(struct linux_xfrm_mib)) < 0)
return -ENOMEM;
rv = xfrm_proc_init(net);
if (rv < 0)
diff --git a/samples/kprobes/kprobe_example.c b/samples/kprobes/kprobe_example.c
index a681998a871..ebf5e0c368e 100644
--- a/samples/kprobes/kprobe_example.c
+++ b/samples/kprobes/kprobe_example.c
@@ -32,6 +32,11 @@ static int handler_pre(struct kprobe *p, struct pt_regs *regs)
" msr = 0x%lx\n",
p->addr, regs->nip, regs->msr);
#endif
+#ifdef CONFIG_MIPS
+ printk(KERN_INFO "pre_handler: p->addr = 0x%p, epc = 0x%lx,"
+ " status = 0x%lx\n",
+ p->addr, regs->cp0_epc, regs->cp0_status);
+#endif
/* A dump_stack() here will give a stack backtrace */
return 0;
@@ -49,6 +54,10 @@ static void handler_post(struct kprobe *p, struct pt_regs *regs,
printk(KERN_INFO "post_handler: p->addr = 0x%p, msr = 0x%lx\n",
p->addr, regs->msr);
#endif
+#ifdef CONFIG_MIPS
+ printk(KERN_INFO "post_handler: p->addr = 0x%p, status = 0x%lx\n",
+ p->addr, regs->cp0_status);
+#endif
}
/*
diff --git a/scripts/Makefile.build b/scripts/Makefile.build
index e4deb73e9a8..a1a5cf95a68 100644
--- a/scripts/Makefile.build
+++ b/scripts/Makefile.build
@@ -115,7 +115,10 @@ endif
# ---------------------------------------------------------------------------
# Default is built-in, unless we know otherwise
-modkern_cflags = $(if $(part-of-module), $(CFLAGS_MODULE), $(CFLAGS_KERNEL))
+modkern_cflags = \
+ $(if $(part-of-module), \
+ $(KBUILD_CFLAGS_MODULE) $(CFLAGS_MODULE), \
+ $(KBUILD_CFLAGS_KERNEL) $(CFLAGS_KERNEL))
quiet_modtag := $(empty) $(empty)
$(real-objs-m) : part-of-module := y
@@ -156,14 +159,14 @@ $(obj)/%.i: $(src)/%.c FORCE
cmd_gensymtypes = \
$(CPP) -D__GENKSYMS__ $(c_flags) $< | \
- $(GENKSYMS) -T $@ -a $(ARCH) \
+ $(GENKSYMS) $(if $(1), -T $(2)) -a $(ARCH) \
$(if $(KBUILD_PRESERVE),-p) \
- $(if $(1),-r $(firstword $(wildcard $(@:.symtypes=.symref) /dev/null)))
+ -r $(firstword $(wildcard $(2:.symtypes=.symref) /dev/null))
quiet_cmd_cc_symtypes_c = SYM $(quiet_modtag) $@
cmd_cc_symtypes_c = \
set -e; \
- $(call cmd_gensymtypes, true) >/dev/null; \
+ $(call cmd_gensymtypes,true,$@) >/dev/null; \
test -s $@ || rm -f $@
$(obj)/%.symtypes : $(src)/%.c FORCE
@@ -192,16 +195,16 @@ else
# the actual value of the checksum generated by genksyms
cmd_cc_o_c = $(CC) $(c_flags) -c -o $(@D)/.tmp_$(@F) $<
-cmd_modversions = \
- if $(OBJDUMP) -h $(@D)/.tmp_$(@F) | grep -q __ksymtab; then \
- $(call cmd_gensymtypes, $(KBUILD_SYMTYPES)) \
- > $(@D)/.tmp_$(@F:.o=.ver); \
- \
- $(LD) $(LDFLAGS) -r -o $@ $(@D)/.tmp_$(@F) \
- -T $(@D)/.tmp_$(@F:.o=.ver); \
- rm -f $(@D)/.tmp_$(@F) $(@D)/.tmp_$(@F:.o=.ver); \
- else \
- mv -f $(@D)/.tmp_$(@F) $@; \
+cmd_modversions = \
+ if $(OBJDUMP) -h $(@D)/.tmp_$(@F) | grep -q __ksymtab; then \
+ $(call cmd_gensymtypes,$(KBUILD_SYMTYPES),$(@:.o=.symtypes)) \
+ > $(@D)/.tmp_$(@F:.o=.ver); \
+ \
+ $(LD) $(LDFLAGS) -r -o $@ $(@D)/.tmp_$(@F) \
+ -T $(@D)/.tmp_$(@F:.o=.ver); \
+ rm -f $(@D)/.tmp_$(@F) $(@D)/.tmp_$(@F:.o=.ver); \
+ else \
+ mv -f $(@D)/.tmp_$(@F) $@; \
fi;
endif
@@ -248,10 +251,10 @@ $(obj)/%.lst: $(src)/%.c FORCE
# Compile assembler sources (.S)
# ---------------------------------------------------------------------------
-modkern_aflags := $(AFLAGS_KERNEL)
+modkern_aflags := $(KBUILD_AFLAGS_KERNEL) $(AFLAGS_KERNEL)
-$(real-objs-m) : modkern_aflags := $(AFLAGS_MODULE)
-$(real-objs-m:.o=.s): modkern_aflags := $(AFLAGS_MODULE)
+$(real-objs-m) : modkern_aflags := $(KBUILD_AFLAGS_MODULE) $(AFLAGS_MODULE)
+$(real-objs-m:.o=.s): modkern_aflags := $(KBUILD_AFLAGS_MODULE) $(AFLAGS_MODULE)
quiet_cmd_as_s_S = CPP $(quiet_modtag) $@
cmd_as_s_S = $(CPP) $(a_flags) -o $@ $<
diff --git a/scripts/Makefile.help b/scripts/Makefile.help
new file mode 100644
index 00000000000..d03608f5db0
--- /dev/null
+++ b/scripts/Makefile.help
@@ -0,0 +1,3 @@
+
+checker-help:
+ @echo ' coccicheck - Check with Coccinelle.'
diff --git a/scripts/Makefile.modpost b/scripts/Makefile.modpost
index 8f14c81abbc..7d22056582c 100644
--- a/scripts/Makefile.modpost
+++ b/scripts/Makefile.modpost
@@ -30,7 +30,7 @@
# - See include/linux/module.h for more details
# Step 4 is solely used to allow module versioning in external modules,
-# where the CRC of each module is retrieved from the Module.symers file.
+# where the CRC of each module is retrieved from the Module.symvers file.
# KBUILD_MODPOST_WARN can be set to avoid error out in case of undefined
# symbols in the final module linking stage
@@ -107,7 +107,7 @@ $(modules:.ko=.mod.c): __modpost ;
modname = $(notdir $(@:.mod.o=))
quiet_cmd_cc_o_c = CC $@
- cmd_cc_o_c = $(CC) $(c_flags) $(CFLAGS_MODULE) \
+ cmd_cc_o_c = $(CC) $(c_flags) $(KBUILD_CFLAGS_MODULE) $(CFLAGS_MODULE) \
-c -o $@ $<
$(modules:.ko=.mod.o): %.mod.o: %.mod.c FORCE
@@ -117,8 +117,9 @@ targets += $(modules:.ko=.mod.o)
# Step 6), final link of the modules
quiet_cmd_ld_ko_o = LD [M] $@
- cmd_ld_ko_o = $(LD) -r $(LDFLAGS) $(LDFLAGS_MODULE) -o $@ \
- $(filter-out FORCE,$^)
+ cmd_ld_ko_o = $(LD) -r $(LDFLAGS) \
+ $(KBUILD_LDFLAGS_MODULE) $(LDFLAGS_MODULE) \
+ -o $@ $(filter-out FORCE,$^)
$(modules): %.ko :%.o %.mod.o FORCE
$(call if_changed,ld_ko_o)
diff --git a/scripts/checkkconfigsymbols.sh b/scripts/checkkconfigsymbols.sh
index 46be3c5a62b..2ca49bb31ef 100755
--- a/scripts/checkkconfigsymbols.sh
+++ b/scripts/checkkconfigsymbols.sh
@@ -14,7 +14,7 @@ find $paths -name '*.[chS]' -o -name 'Makefile' -o -name 'Makefile*[^~]'| while
do
# Output the bare Kconfig variable and the filename; the _MODULE part at
# the end is not removed here (would need perl an not-hungry regexp for that).
- sed -ne 's!^.*\<\(UML_\)\?CONFIG_\([0-9A-Z_]\+\).*!\2 '$i'!p' < $i
+ sed -ne 's!^.*\<\(UML_\)\?CONFIG_\([0-9A-Za-z_]\+\).*!\2 '$i'!p' < $i
done | \
# Smart "sort|uniq" implemented in awk and tuned to collect the names of all
# files which use a given symbol
diff --git a/scripts/coccicheck b/scripts/coccicheck
new file mode 100755
index 00000000000..b8bcf1f7bed
--- /dev/null
+++ b/scripts/coccicheck
@@ -0,0 +1,80 @@
+#!/bin/sh
+
+SPATCH="`which ${SPATCH:=spatch}`"
+
+if [ "$C" = "1" -o "$C" = "2" ]; then
+ ONLINE=1
+
+# This requires Coccinelle >= 0.2.3
+# FLAGS="-ignore_unknown_options -very_quiet"
+# OPTIONS=$*
+
+# Workaround for Coccinelle < 0.2.3
+ FLAGS="-I $srctree/include -very_quiet"
+ shift $(( $# - 1 ))
+ OPTIONS=$1
+else
+ ONLINE=0
+ FLAGS="-very_quiet"
+fi
+
+if [ ! -x "$SPATCH" ]; then
+ echo 'spatch is part of the Coccinelle project and is available at http://coccinelle.lip6.fr/'
+ exit 1
+fi
+
+if [ "$MODE" = "" ] ; then
+ if [ "$ONLINE" = "0" ] ; then
+ echo 'You have not explicitly specify the mode to use. Fallback to "report".'
+ echo 'You can specify the mode with "make coccicheck MODE=<mode>"'
+ echo 'Available modes are: report, patch, context, org'
+ fi
+ MODE="report"
+fi
+
+if [ "$ONLINE" = "0" ] ; then
+ echo ''
+ echo 'Please check for false positives in the output before submitting a patch.'
+ echo 'When using "patch" mode, carefully review the patch before submitting it.'
+ echo ''
+fi
+
+coccinelle () {
+ COCCI="$1"
+
+ OPT=`grep "Option" $COCCI | cut -d':' -f2`
+
+# The option '-parse_cocci' can be used to syntaxically check the SmPL files.
+#
+# $SPATCH -D $MODE $FLAGS -parse_cocci $COCCI $OPT > /dev/null
+
+ if [ "$ONLINE" = "0" ] ; then
+
+ FILE=`echo $COCCI | sed "s|$srctree/||"`
+
+ echo "Processing `basename $COCCI` with option(s) \"$OPT\""
+ echo 'Message example to submit a patch:'
+
+ sed -e '/\/\/\//!d' -e 's|^///||' $COCCI
+
+ echo ' The semantic patch that makes this change is available'
+ echo " in $FILE."
+ echo ''
+ echo ' More information about semantic patching is available at'
+ echo ' http://coccinelle.lip6.fr/'
+ echo ''
+
+ $SPATCH -D $MODE $FLAGS -sp_file $COCCI $OPT -dir $srctree || exit 1
+ else
+ $SPATCH -D $MODE $FLAGS -sp_file $COCCI $OPT $OPTIONS || exit 1
+ fi
+
+}
+
+if [ "$COCCI" = "" ] ; then
+ for f in `find $srctree/scripts/coccinelle/ -name '*.cocci' -type f | sort`; do
+ coccinelle $f
+ done
+else
+ coccinelle $COCCI
+fi
diff --git a/scripts/coccinelle/alloc/drop_kmalloc_cast.cocci b/scripts/coccinelle/alloc/drop_kmalloc_cast.cocci
new file mode 100644
index 00000000000..7d4771d449c
--- /dev/null
+++ b/scripts/coccinelle/alloc/drop_kmalloc_cast.cocci
@@ -0,0 +1,67 @@
+///
+/// Casting (void *) value returned by kmalloc is useless
+/// as mentioned in Documentation/CodingStyle, Chap 14.
+///
+// Confidence: High
+// Copyright: 2009,2010 Nicolas Palix, DIKU. GPLv2.
+// URL: http://coccinelle.lip6.fr/
+// Options: -no_includes -include_headers
+//
+// Keywords: kmalloc, kzalloc, kcalloc
+// Version min: < 2.6.12 kmalloc
+// Version min: < 2.6.12 kcalloc
+// Version min: 2.6.14 kzalloc
+//
+
+virtual context
+virtual patch
+virtual org
+virtual report
+
+//----------------------------------------------------------
+// For context mode
+//----------------------------------------------------------
+
+@depends on context@
+type T;
+@@
+
+* (T *)
+ \(kmalloc\|kzalloc\|kcalloc\)(...)
+
+//----------------------------------------------------------
+// For patch mode
+//----------------------------------------------------------
+
+@depends on patch@
+type T;
+@@
+
+- (T *)
+ \(kmalloc\|kzalloc\|kcalloc\)(...)
+
+//----------------------------------------------------------
+// For org and report mode
+//----------------------------------------------------------
+
+@r depends on org || report@
+type T;
+position p;
+@@
+
+ (T@p *)\(kmalloc\|kzalloc\|kcalloc\)(...)
+
+@script:python depends on org@
+p << r.p;
+t << r.T;
+@@
+
+coccilib.org.print_safe_todo(p[0], t)
+
+@script:python depends on report@
+p << r.p;
+t << r.T;
+@@
+
+msg="WARNING: casting value returned by k[cmz]alloc to (%s *) is useless." % (t)
+coccilib.report.print_report(p[0], msg)
diff --git a/scripts/coccinelle/alloc/kzalloc-simple.cocci b/scripts/coccinelle/alloc/kzalloc-simple.cocci
new file mode 100644
index 00000000000..2eae828fc65
--- /dev/null
+++ b/scripts/coccinelle/alloc/kzalloc-simple.cocci
@@ -0,0 +1,82 @@
+///
+/// kzalloc should be used rather than kmalloc followed by memset 0
+///
+// Confidence: High
+// Copyright: (C) 2009-2010 Julia Lawall, Nicolas Palix, DIKU. GPLv2.
+// Copyright: (C) 2009-2010 Gilles Muller, INRIA/LiP6. GPLv2.
+// URL: http://coccinelle.lip6.fr/rules/kzalloc.html
+// Options: -no_includes -include_headers
+//
+// Keywords: kmalloc, kzalloc
+// Version min: < 2.6.12 kmalloc
+// Version min: 2.6.14 kzalloc
+//
+
+virtual context
+virtual patch
+virtual org
+virtual report
+
+//----------------------------------------------------------
+// For context mode
+//----------------------------------------------------------
+
+@depends on context@
+type T, T2;
+expression x;
+expression E1,E2;
+statement S;
+@@
+
+* x = (T)kmalloc(E1,E2);
+ if ((x==NULL) || ...) S
+* memset((T2)x,0,E1);
+
+//----------------------------------------------------------
+// For patch mode
+//----------------------------------------------------------
+
+@depends on patch@
+type T, T2;
+expression x;
+expression E1,E2;
+statement S;
+@@
+
+- x = (T)kmalloc(E1,E2);
++ x = kzalloc(E1,E2);
+ if ((x==NULL) || ...) S
+- memset((T2)x,0,E1);
+
+//----------------------------------------------------------
+// For org mode
+//----------------------------------------------------------
+
+@r depends on org || report@
+type T, T2;
+expression x;
+expression E1,E2;
+statement S;
+position p;
+@@
+
+ x = (T)kmalloc@p(E1,E2);
+ if ((x==NULL) || ...) S
+ memset((T2)x,0,E1);
+
+@script:python depends on org@
+p << r.p;
+x << r.x;
+@@
+
+msg="%s" % (x)
+msg_safe=msg.replace("[","@(").replace("]",")")
+coccilib.org.print_todo(p[0], msg_safe)
+
+@script:python depends on report@
+p << r.p;
+x << r.x;
+@@
+
+msg="WARNING: kzalloc should be used for %s, instead of kmalloc/memset" % (x)
+coccilib.report.print_report(p[0], msg)
diff --git a/scripts/coccinelle/deref_null.cocci b/scripts/coccinelle/deref_null.cocci
new file mode 100644
index 00000000000..9969d76d0f4
--- /dev/null
+++ b/scripts/coccinelle/deref_null.cocci
@@ -0,0 +1,293 @@
+///
+/// A variable is dereference under a NULL test.
+/// Even though it is know to be NULL.
+///
+// Confidence: Moderate
+// Copyright: (C) 2010 Nicolas Palix, DIKU. GPLv2.
+// Copyright: (C) 2010 Julia Lawall, DIKU. GPLv2.
+// Copyright: (C) 2010 Gilles Muller, INRIA/LiP6. GPLv2.
+// URL: http://coccinelle.lip6.fr/
+// Comments: -I ... -all_includes can give more complete results
+// Options:
+
+virtual context
+virtual patch
+virtual org
+virtual report
+
+@initialize:python depends on !context && patch && !org && !report@
+
+import sys
+print >> sys.stderr, "This semantic patch does not support the 'patch' mode."
+
+@depends on patch@
+@@
+
+this_rule_should_never_matches();
+
+@ifm depends on !patch@
+expression *E;
+statement S1,S2;
+position p1;
+@@
+
+if@p1 ((E == NULL && ...) || ...) S1 else S2
+
+// The following two rules are separate, because both can match a single
+// expression in different ways
+@pr1 depends on !patch expression@
+expression *ifm.E;
+identifier f;
+position p1;
+@@
+
+ (E != NULL && ...) ? <+...E->f@p1...+> : ...
+
+@pr2 depends on !patch expression@
+expression *ifm.E;
+identifier f;
+position p2;
+@@
+
+(
+ (E != NULL) && ... && <+...E->f@p2...+>
+|
+ (E == NULL) || ... || <+...E->f@p2...+>
+|
+ sizeof(<+...E->f@p2...+>)
+)
+
+// For org and report modes
+
+@r depends on !context && !patch && (org || report) exists@
+expression subE <= ifm.E;
+expression *ifm.E;
+expression E1,E2;
+identifier f;
+statement S1,S2,S3,S4;
+iterator iter;
+position p!={pr1.p1,pr2.p2};
+position ifm.p1;
+@@
+
+if@p1 ((E == NULL && ...) || ...)
+{
+ ... when != if (...) S1 else S2
+(
+ iter(subE,...) S4 // no use
+|
+ list_remove_head(E2,subE,...)
+|
+ subE = E1
+|
+ for(subE = E1;...;...) S4
+|
+ subE++
+|
+ ++subE
+|
+ --subE
+|
+ subE--
+|
+ &subE
+|
+ E->f@p // bad use
+)
+ ... when any
+ return ...;
+}
+else S3
+
+@script:python depends on !context && !patch && !org && report@
+p << r.p;
+p1 << ifm.p1;
+x << ifm.E;
+@@
+
+msg="ERROR: %s is NULL but dereferenced." % (x)
+coccilib.report.print_report(p[0], msg)
+cocci.include_match(False)
+
+@script:python depends on !context && !patch && org && !report@
+p << r.p;
+p1 << ifm.p1;
+x << ifm.E;
+@@
+
+msg="ERROR: %s is NULL but dereferenced." % (x)
+msg_safe=msg.replace("[","@(").replace("]",")")
+cocci.print_main(msg_safe,p)
+cocci.include_match(False)
+
+@s depends on !context && !patch && (org || report) exists@
+expression subE <= ifm.E;
+expression *ifm.E;
+expression E1,E2;
+identifier f;
+statement S1,S2,S3,S4;
+iterator iter;
+position p!={pr1.p1,pr2.p2};
+position ifm.p1;
+@@
+
+if@p1 ((E == NULL && ...) || ...)
+{
+ ... when != if (...) S1 else S2
+(
+ iter(subE,...) S4 // no use
+|
+ list_remove_head(E2,subE,...)
+|
+ subE = E1
+|
+ for(subE = E1;...;...) S4
+|
+ subE++
+|
+ ++subE
+|
+ --subE
+|
+ subE--
+|
+ &subE
+|
+ E->f@p // bad use
+)
+ ... when any
+}
+else S3
+
+@script:python depends on !context && !patch && !org && report@
+p << s.p;
+p1 << ifm.p1;
+x << ifm.E;
+@@
+
+msg="ERROR: %s is NULL but dereferenced." % (x)
+coccilib.report.print_report(p[0], msg)
+
+@script:python depends on !context && !patch && org && !report@
+p << s.p;
+p1 << ifm.p1;
+x << ifm.E;
+@@
+
+msg="ERROR: %s is NULL but dereferenced." % (x)
+msg_safe=msg.replace("[","@(").replace("]",")")
+cocci.print_main(msg_safe,p)
+
+// For context mode
+
+@depends on context && !patch && !org && !report exists@
+expression subE <= ifm.E;
+expression *ifm.E;
+expression E1,E2;
+identifier f;
+statement S1,S2,S3,S4;
+iterator iter;
+position p!={pr1.p1,pr2.p2};
+position ifm.p1;
+@@
+
+if@p1 ((E == NULL && ...) || ...)
+{
+ ... when != if (...) S1 else S2
+(
+ iter(subE,...) S4 // no use
+|
+ list_remove_head(E2,subE,...)
+|
+ subE = E1
+|
+ for(subE = E1;...;...) S4
+|
+ subE++
+|
+ ++subE
+|
+ --subE
+|
+ subE--
+|
+ &subE
+|
+* E->f@p // bad use
+)
+ ... when any
+ return ...;
+}
+else S3
+
+// The following three rules are duplicates of ifm, pr1 and pr2 respectively.
+// It is need because the previous rule as already made a "change".
+
+@ifm1 depends on !patch@
+expression *E;
+statement S1,S2;
+position p1;
+@@
+
+if@p1 ((E == NULL && ...) || ...) S1 else S2
+
+@pr11 depends on !patch expression@
+expression *ifm1.E;
+identifier f;
+position p1;
+@@
+
+ (E != NULL && ...) ? <+...E->f@p1...+> : ...
+
+@pr12 depends on !patch expression@
+expression *ifm1.E;
+identifier f;
+position p2;
+@@
+
+(
+ (E != NULL) && ... && <+...E->f@p2...+>
+|
+ (E == NULL) || ... || <+...E->f@p2...+>
+|
+ sizeof(<+...E->f@p2...+>)
+)
+
+@depends on context && !patch && !org && !report exists@
+expression subE <= ifm1.E;
+expression *ifm1.E;
+expression E1,E2;
+identifier f;
+statement S1,S2,S3,S4;
+iterator iter;
+position p!={pr11.p1,pr12.p2};
+position ifm1.p1;
+@@
+
+if@p1 ((E == NULL && ...) || ...)
+{
+ ... when != if (...) S1 else S2
+(
+ iter(subE,...) S4 // no use
+|
+ list_remove_head(E2,subE,...)
+|
+ subE = E1
+|
+ for(subE = E1;...;...) S4
+|
+ subE++
+|
+ ++subE
+|
+ --subE
+|
+ subE--
+|
+ &subE
+|
+* E->f@p // bad use
+)
+ ... when any
+}
+else S3
diff --git a/scripts/coccinelle/err_cast.cocci b/scripts/coccinelle/err_cast.cocci
new file mode 100644
index 00000000000..2ce115000af
--- /dev/null
+++ b/scripts/coccinelle/err_cast.cocci
@@ -0,0 +1,56 @@
+///
+/// Use ERR_CAST inlined function instead of ERR_PTR(PTR_ERR(...))
+///
+// Confidence: High
+// Copyright: (C) 2009, 2010 Nicolas Palix, DIKU. GPLv2.
+// Copyright: (C) 2009, 2010 Julia Lawall, DIKU. GPLv2.
+// Copyright: (C) 2009, 2010 Gilles Muller, INRIA/LiP6. GPLv2.
+// URL: http://coccinelle.lip6.fr/
+// Options:
+//
+// Keywords: ERR_PTR, PTR_ERR, ERR_CAST
+// Version min: 2.6.25
+//
+
+virtual context
+virtual patch
+virtual org
+virtual report
+
+
+@ depends on context && !patch && !org && !report@
+expression x;
+@@
+
+* ERR_PTR(PTR_ERR(x))
+
+@ depends on !context && patch && !org && !report @
+expression x;
+@@
+
+- ERR_PTR(PTR_ERR(x))
++ ERR_CAST(x)
+
+@r depends on !context && !patch && (org || report)@
+expression x;
+position p;
+@@
+
+ ERR_PTR@p(PTR_ERR(x))
+
+@script:python depends on org@
+p << r.p;
+x << r.x;
+@@
+
+msg="WARNING ERR_CAST can be used with %s" % (x)
+msg_safe=msg.replace("[","@(").replace("]",")")
+coccilib.org.print_todo(p[0], msg_safe)
+
+@script:python depends on report@
+p << r.p;
+x << r.x;
+@@
+
+msg="WARNING: ERR_CAST can be used with %s" % (x)
+coccilib.report.print_report(p[0], msg)
diff --git a/scripts/coccinelle/resource_size.cocci b/scripts/coccinelle/resource_size.cocci
new file mode 100644
index 00000000000..1935a58b39d
--- /dev/null
+++ b/scripts/coccinelle/resource_size.cocci
@@ -0,0 +1,93 @@
+///
+/// Use resource_size function on resource object
+/// instead of explicit computation.
+///
+// Confidence: High
+// Copyright: (C) 2009, 2010 Nicolas Palix, DIKU. GPLv2.
+// Copyright: (C) 2009, 2010 Julia Lawall, DIKU. GPLv2.
+// Copyright: (C) 2009, 2010 Gilles Muller, INRIA/LiP6. GPLv2.
+// URL: http://coccinelle.lip6.fr/
+// Options:
+//
+// Keywords: resource_size
+// Version min: 2.6.27 resource_size
+//
+
+virtual context
+virtual patch
+virtual org
+virtual report
+
+//----------------------------------------------------------
+// For context mode
+//----------------------------------------------------------
+
+@r_context depends on context && !patch && !org@
+struct resource *res;
+@@
+
+* (res->end - res->start) + 1
+
+//----------------------------------------------------------
+// For patch mode
+//----------------------------------------------------------
+
+@r_patch depends on !context && patch && !org@
+struct resource *res;
+@@
+
+- (res->end - res->start) + 1
++ resource_size(res)
+
+//----------------------------------------------------------
+// For org mode
+//----------------------------------------------------------
+
+
+@r_org depends on !context && !patch && (org || report)@
+struct resource *res;
+position p;
+@@
+
+ (res->end@p - res->start) + 1
+
+@rbad_org depends on !context && !patch && (org || report)@
+struct resource *res;
+position p != r_org.p;
+@@
+
+ res->end@p - res->start
+
+@script:python depends on org@
+p << r_org.p;
+x << r_org.res;
+@@
+
+msg="ERROR with %s" % (x)
+msg_safe=msg.replace("[","@(").replace("]",")")
+coccilib.org.print_todo(p[0], msg_safe)
+
+@script:python depends on report@
+p << r_org.p;
+x << r_org.res;
+@@
+
+msg="ERROR: Missing resource_size with %s" % (x)
+coccilib.report.print_report(p[0], msg)
+
+@script:python depends on org@
+p << rbad_org.p;
+x << rbad_org.res;
+@@
+
+msg="WARNING with %s" % (x)
+msg_safe=msg.replace("[","@(").replace("]",")")
+coccilib.org.print_todo(p[0], msg_safe)
+
+@script:python depends on report@
+p << rbad_org.p;
+x << rbad_org.res;
+@@
+
+msg="WARNING: Suspicious code. resource_size is maybe missing with %s" % (x)
+coccilib.report.print_report(p[0], msg)
diff --git a/scripts/decodecode b/scripts/decodecode
index 8b30cc36744..18ba881c341 100755
--- a/scripts/decodecode
+++ b/scripts/decodecode
@@ -40,7 +40,7 @@ echo $code
code=`echo $code | sed -e 's/.*Code: //'`
width=`expr index "$code" ' '`
-width=$[($width-1)/2]
+width=$((($width-1)/2))
case $width in
1) type=byte ;;
2) type=2byte ;;
@@ -48,10 +48,10 @@ case $width in
esac
disas() {
- ${CROSS_COMPILE}as $AFLAGS -o $1.o $1.s &> /dev/null
+ ${CROSS_COMPILE}as $AFLAGS -o $1.o $1.s > /dev/null 2>&1
- if [ "$ARCH" == "arm" ]; then
- if [ $width == 2 ]; then
+ if [ "$ARCH" = "arm" ]; then
+ if [ $width -eq 2 ]; then
OBJDUMPFLAGS="-M force-thumb"
fi
@@ -59,7 +59,7 @@ disas() {
fi
${CROSS_COMPILE}objdump $OBJDUMPFLAGS -S $1.o | \
- grep -v "/tmp\|Disassembly\|\.text\|^$" &> $1.dis
+ grep -v "/tmp\|Disassembly\|\.text\|^$" > $1.dis 2>&1
}
marker=`expr index "$code" "\<"`
diff --git a/scripts/dtc/fstree.c b/scripts/dtc/fstree.c
index 766b2694d93..8fe1bdf239f 100644
--- a/scripts/dtc/fstree.c
+++ b/scripts/dtc/fstree.c
@@ -77,6 +77,7 @@ static struct node *read_fstree(const char *dirname)
free(tmpnam);
}
+ closedir(d);
return tree;
}
diff --git a/scripts/kconfig/.gitignore b/scripts/kconfig/.gitignore
index 6a36a76e660..624f6502e03 100644
--- a/scripts/kconfig/.gitignore
+++ b/scripts/kconfig/.gitignore
@@ -17,6 +17,7 @@ gconf.glade.h
#
conf
mconf
+nconf
qconf
gconf
kxgettext
diff --git a/scripts/kconfig/Makefile b/scripts/kconfig/Makefile
index 7ea649da194..de934def410 100644
--- a/scripts/kconfig/Makefile
+++ b/scripts/kconfig/Makefile
@@ -21,17 +21,17 @@ menuconfig: $(obj)/mconf
$< $(Kconfig)
config: $(obj)/conf
- $< $(Kconfig)
+ $< --oldaskconfig $(Kconfig)
nconfig: $(obj)/nconf
$< $(Kconfig)
oldconfig: $(obj)/conf
- $< -o $(Kconfig)
+ $< --$@ $(Kconfig)
silentoldconfig: $(obj)/conf
$(Q)mkdir -p include/generated
- $< -s $(Kconfig)
+ $< --$@ $(Kconfig)
# if no path is given, then use src directory to find file
ifdef LSMOD
@@ -44,15 +44,15 @@ endif
localmodconfig: $(obj)/streamline_config.pl $(obj)/conf
$(Q)mkdir -p include/generated
$(Q)perl $< $(srctree) $(Kconfig) $(LSMOD_F) > .tmp.config
- $(Q)if [ -f .config ]; then \
- cmp -s .tmp.config .config || \
- (mv -f .config .config.old.1; \
- mv -f .tmp.config .config; \
- $(obj)/conf -s $(Kconfig); \
- mv -f .config.old.1 .config.old) \
- else \
- mv -f .tmp.config .config; \
- $(obj)/conf -s $(Kconfig); \
+ $(Q)if [ -f .config ]; then \
+ cmp -s .tmp.config .config || \
+ (mv -f .config .config.old.1; \
+ mv -f .tmp.config .config; \
+ $(obj)/conf --silentoldconfig $(Kconfig); \
+ mv -f .config.old.1 .config.old) \
+ else \
+ mv -f .tmp.config .config; \
+ $(obj)/conf --silentoldconfig $(Kconfig); \
fi
$(Q)rm -f .tmp.config
@@ -60,15 +60,15 @@ localyesconfig: $(obj)/streamline_config.pl $(obj)/conf
$(Q)mkdir -p include/generated
$(Q)perl $< $(srctree) $(Kconfig) $(LSMOD_F) > .tmp.config
$(Q)sed -i s/=m/=y/ .tmp.config
- $(Q)if [ -f .config ]; then \
- cmp -s .tmp.config .config || \
- (mv -f .config .config.old.1; \
- mv -f .tmp.config .config; \
- $(obj)/conf -s $(Kconfig); \
- mv -f .config.old.1 .config.old) \
- else \
- mv -f .tmp.config .config; \
- $(obj)/conf -s $(Kconfig); \
+ $(Q)if [ -f .config ]; then \
+ cmp -s .tmp.config .config || \
+ (mv -f .config .config.old.1; \
+ mv -f .tmp.config .config; \
+ $(obj)/conf --silentoldconfig $(Kconfig); \
+ mv -f .config.old.1 .config.old) \
+ else \
+ mv -f .tmp.config .config; \
+ $(obj)/conf --silentoldconfig $(Kconfig); \
fi
$(Q)rm -f .tmp.config
@@ -95,30 +95,29 @@ update-po-config: $(obj)/kxgettext $(obj)/gconf.glade.h
$(Q)rm -f arch/um/Kconfig.arch
$(Q)rm -f $(obj)/config.pot
-PHONY += randconfig allyesconfig allnoconfig allmodconfig defconfig
+PHONY += allnoconfig allyesconfig allmodconfig alldefconfig randconfig
-randconfig: $(obj)/conf
- $< -r $(Kconfig)
+allnoconfig allyesconfig allmodconfig alldefconfig randconfig: $(obj)/conf
+ $< --$@ $(Kconfig)
-allyesconfig: $(obj)/conf
- $< -y $(Kconfig)
+PHONY += listnewconfig oldnoconfig savedefconfig defconfig
-allnoconfig: $(obj)/conf
- $< -n $(Kconfig)
+listnewconfig oldnoconfig: $(obj)/conf
+ $< --$@ $(Kconfig)
-allmodconfig: $(obj)/conf
- $< -m $(Kconfig)
+savedefconfig: $(obj)/conf
+ $< --$@=defconfig $(Kconfig)
defconfig: $(obj)/conf
ifeq ($(KBUILD_DEFCONFIG),)
- $< -d $(Kconfig)
+ $< --defconfig $(Kconfig)
else
@echo "*** Default configuration is based on '$(KBUILD_DEFCONFIG)'"
- $(Q)$< -D arch/$(SRCARCH)/configs/$(KBUILD_DEFCONFIG) $(Kconfig)
+ $(Q)$< --defconfig=arch/$(SRCARCH)/configs/$(KBUILD_DEFCONFIG) $(Kconfig)
endif
%_defconfig: $(obj)/conf
- $(Q)$< -D arch/$(SRCARCH)/configs/$@ $(Kconfig)
+ $(Q)$< --defconfig=arch/$(SRCARCH)/configs/$@ $(Kconfig)
# Help text used by make help
help:
@@ -131,11 +130,15 @@ help:
@echo ' localmodconfig - Update current config disabling modules not loaded'
@echo ' localyesconfig - Update current config converting local mods to core'
@echo ' silentoldconfig - Same as oldconfig, but quietly, additionally update deps'
- @echo ' randconfig - New config with random answer to all options'
- @echo ' defconfig - New config with default answer to all options'
- @echo ' allmodconfig - New config selecting modules when possible'
- @echo ' allyesconfig - New config where all options are accepted with yes'
+ @echo ' defconfig - New config with default from ARCH supplied defconfig'
+ @echo ' savedefconfig - Save current config as ./defconfig (minimal config)'
@echo ' allnoconfig - New config where all options are answered with no'
+ @echo ' allyesconfig - New config where all options are accepted with yes'
+ @echo ' allmodconfig - New config selecting modules when possible'
+ @echo ' alldefconfig - New config with all symbols set to default'
+ @echo ' randconfig - New config with random answer to all options'
+ @echo ' listnewconfig - List new options'
+ @echo ' oldnoconfig - Same as silentoldconfig but set new symbols to n (unset)'
# lxdialog stuff
check-lxdialog := $(srctree)/$(src)/lxdialog/check-lxdialog.sh
diff --git a/scripts/kconfig/conf.c b/scripts/kconfig/conf.c
index 9960d1c303f..274f2716b03 100644
--- a/scripts/kconfig/conf.c
+++ b/scripts/kconfig/conf.c
@@ -10,6 +10,7 @@
#include <string.h>
#include <time.h>
#include <unistd.h>
+#include <getopt.h>
#include <sys/stat.h>
#include <sys/time.h>
@@ -19,16 +20,21 @@
static void conf(struct menu *menu);
static void check_conf(struct menu *menu);
-enum {
- ask_all,
- ask_new,
- ask_silent,
- set_default,
- set_yes,
- set_mod,
- set_no,
- set_random
-} input_mode = ask_all;
+enum input_mode {
+ oldaskconfig,
+ silentoldconfig,
+ oldconfig,
+ allnoconfig,
+ allyesconfig,
+ allmodconfig,
+ alldefconfig,
+ randconfig,
+ defconfig,
+ savedefconfig,
+ listnewconfig,
+ oldnoconfig,
+} input_mode = oldaskconfig;
+
char *defconfig_file;
static int indent = 1;
@@ -93,14 +99,14 @@ static int conf_askvalue(struct symbol *sym, const char *def)
}
switch (input_mode) {
- case ask_new:
- case ask_silent:
+ case oldconfig:
+ case silentoldconfig:
if (sym_has_value(sym)) {
printf("%s\n", def);
return 0;
}
check_stdin();
- case ask_all:
+ case oldaskconfig:
fflush(stdout);
fgets(line, 128, stdin);
return 1;
@@ -156,14 +162,12 @@ static int conf_string(struct menu *menu)
static int conf_sym(struct menu *menu)
{
struct symbol *sym = menu->sym;
- int type;
tristate oldval, newval;
while (1) {
printf("%*s%s ", indent - 1, "", _(menu->prompt->text));
if (sym->name)
printf("(%s) ", sym->name);
- type = sym_get_type(sym);
putchar('[');
oldval = sym_get_tristate_value(sym);
switch (oldval) {
@@ -228,11 +232,9 @@ static int conf_choice(struct menu *menu)
{
struct symbol *sym, *def_sym;
struct menu *child;
- int type;
bool is_new;
sym = menu->sym;
- type = sym_get_type(sym);
is_new = !sym_has_value(sym);
if (sym_is_changable(sym)) {
conf_sym(menu);
@@ -294,15 +296,15 @@ static int conf_choice(struct menu *menu)
printf("?");
printf("]: ");
switch (input_mode) {
- case ask_new:
- case ask_silent:
+ case oldconfig:
+ case silentoldconfig:
if (!is_new) {
cnt = def;
printf("%d\n", cnt);
break;
}
check_stdin();
- case ask_all:
+ case oldaskconfig:
fflush(stdout);
fgets(line, 128, stdin);
strip(line);
@@ -360,7 +362,10 @@ static void conf(struct menu *menu)
switch (prop->type) {
case P_MENU:
- if (input_mode == ask_silent && rootEntry != menu) {
+ if ((input_mode == silentoldconfig ||
+ input_mode == listnewconfig ||
+ input_mode == oldnoconfig) &&
+ rootEntry != menu) {
check_conf(menu);
return;
}
@@ -418,10 +423,16 @@ static void check_conf(struct menu *menu)
if (sym && !sym_has_value(sym)) {
if (sym_is_changable(sym) ||
(sym_is_choice(sym) && sym_get_tristate_value(sym) == yes)) {
- if (!conf_cnt++)
- printf(_("*\n* Restart config...\n*\n"));
- rootEntry = menu_get_parent_menu(menu);
- conf(rootEntry);
+ if (input_mode == listnewconfig) {
+ if (sym->name && !sym_is_choice_value(sym)) {
+ printf("CONFIG_%s\n", sym->name);
+ }
+ } else {
+ if (!conf_cnt++)
+ printf(_("*\n* Restart config...\n*\n"));
+ rootEntry = menu_get_parent_menu(menu);
+ conf(rootEntry);
+ }
}
}
@@ -429,6 +440,22 @@ static void check_conf(struct menu *menu)
check_conf(child);
}
+static struct option long_opts[] = {
+ {"oldaskconfig", no_argument, NULL, oldaskconfig},
+ {"oldconfig", no_argument, NULL, oldconfig},
+ {"silentoldconfig", no_argument, NULL, silentoldconfig},
+ {"defconfig", optional_argument, NULL, defconfig},
+ {"savedefconfig", required_argument, NULL, savedefconfig},
+ {"allnoconfig", no_argument, NULL, allnoconfig},
+ {"allyesconfig", no_argument, NULL, allyesconfig},
+ {"allmodconfig", no_argument, NULL, allmodconfig},
+ {"alldefconfig", no_argument, NULL, alldefconfig},
+ {"randconfig", no_argument, NULL, randconfig},
+ {"listnewconfig", no_argument, NULL, listnewconfig},
+ {"oldnoconfig", no_argument, NULL, oldnoconfig},
+ {NULL, 0, NULL, 0}
+};
+
int main(int ac, char **av)
{
int opt;
@@ -439,32 +466,17 @@ int main(int ac, char **av)
bindtextdomain(PACKAGE, LOCALEDIR);
textdomain(PACKAGE);
- while ((opt = getopt(ac, av, "osdD:nmyrh")) != -1) {
+ while ((opt = getopt_long_only(ac, av, "", long_opts, NULL)) != -1) {
+ input_mode = (enum input_mode)opt;
switch (opt) {
- case 'o':
- input_mode = ask_silent;
- break;
- case 's':
- input_mode = ask_silent;
+ case silentoldconfig:
sync_kconfig = 1;
break;
- case 'd':
- input_mode = set_default;
- break;
- case 'D':
- input_mode = set_default;
+ case defconfig:
+ case savedefconfig:
defconfig_file = optarg;
break;
- case 'n':
- input_mode = set_no;
- break;
- case 'm':
- input_mode = set_mod;
- break;
- case 'y':
- input_mode = set_yes;
- break;
- case 'r':
+ case randconfig:
{
struct timeval now;
unsigned int seed;
@@ -477,17 +489,12 @@ int main(int ac, char **av)
seed = (unsigned int)((now.tv_sec + 1) * (now.tv_usec + 1));
srand(seed);
-
- input_mode = set_random;
break;
}
- case 'h':
- printf(_("See README for usage info\n"));
- exit(0);
- break;
- default:
+ case '?':
fprintf(stderr, _("See README for usage info\n"));
exit(1);
+ break;
}
}
if (ac == optind) {
@@ -512,7 +519,7 @@ int main(int ac, char **av)
}
switch (input_mode) {
- case set_default:
+ case defconfig:
if (!defconfig_file)
defconfig_file = conf_get_default_confname();
if (conf_read(defconfig_file)) {
@@ -522,25 +529,32 @@ int main(int ac, char **av)
exit(1);
}
break;
- case ask_silent:
- case ask_all:
- case ask_new:
+ case savedefconfig:
+ conf_read(NULL);
+ break;
+ case silentoldconfig:
+ case oldaskconfig:
+ case oldconfig:
+ case listnewconfig:
+ case oldnoconfig:
conf_read(NULL);
break;
- case set_no:
- case set_mod:
- case set_yes:
- case set_random:
+ case allnoconfig:
+ case allyesconfig:
+ case allmodconfig:
+ case alldefconfig:
+ case randconfig:
name = getenv("KCONFIG_ALLCONFIG");
if (name && !stat(name, &tmpstat)) {
conf_read_simple(name, S_DEF_USER);
break;
}
switch (input_mode) {
- case set_no: name = "allno.config"; break;
- case set_mod: name = "allmod.config"; break;
- case set_yes: name = "allyes.config"; break;
- case set_random: name = "allrandom.config"; break;
+ case allnoconfig: name = "allno.config"; break;
+ case allyesconfig: name = "allyes.config"; break;
+ case allmodconfig: name = "allmod.config"; break;
+ case alldefconfig: name = "alldef.config"; break;
+ case randconfig: name = "allrandom.config"; break;
default: break;
}
if (!stat(name, &tmpstat))
@@ -565,33 +579,42 @@ int main(int ac, char **av)
}
switch (input_mode) {
- case set_no:
+ case allnoconfig:
conf_set_all_new_symbols(def_no);
break;
- case set_yes:
+ case allyesconfig:
conf_set_all_new_symbols(def_yes);
break;
- case set_mod:
+ case allmodconfig:
conf_set_all_new_symbols(def_mod);
break;
- case set_random:
+ case alldefconfig:
+ conf_set_all_new_symbols(def_default);
+ break;
+ case randconfig:
conf_set_all_new_symbols(def_random);
break;
- case set_default:
+ case defconfig:
conf_set_all_new_symbols(def_default);
break;
- case ask_new:
- case ask_all:
+ case savedefconfig:
+ break;
+ case oldaskconfig:
rootEntry = &rootmenu;
conf(&rootmenu);
- input_mode = ask_silent;
+ input_mode = silentoldconfig;
/* fall through */
- case ask_silent:
+ case oldconfig:
+ case listnewconfig:
+ case oldnoconfig:
+ case silentoldconfig:
/* Update until a loop caused no more changes */
do {
conf_cnt = 0;
check_conf(&rootmenu);
- } while (conf_cnt);
+ } while (conf_cnt &&
+ (input_mode != listnewconfig &&
+ input_mode != oldnoconfig));
break;
}
@@ -607,7 +630,13 @@ int main(int ac, char **av)
fprintf(stderr, _("\n*** Error during update of the kernel configuration.\n\n"));
return 1;
}
- } else {
+ } else if (input_mode == savedefconfig) {
+ if (conf_write_defconfig(defconfig_file)) {
+ fprintf(stderr, _("n*** Error while saving defconfig to: %s\n\n"),
+ defconfig_file);
+ return 1;
+ }
+ } else if (input_mode != listnewconfig) {
if (conf_write(NULL)) {
fprintf(stderr, _("\n*** Error during writing of the kernel configuration.\n\n"));
exit(1);
diff --git a/scripts/kconfig/confdata.c b/scripts/kconfig/confdata.c
index c4dec80cfd8..f81f263b64f 100644
--- a/scripts/kconfig/confdata.c
+++ b/scripts/kconfig/confdata.c
@@ -170,8 +170,11 @@ int conf_read_simple(const char *name, int def)
if (in)
goto load;
sym_add_change_count(1);
- if (!sym_defconfig_list)
+ if (!sym_defconfig_list) {
+ if (modules_sym)
+ sym_calc_value(modules_sym);
return 1;
+ }
for_all_defaults(sym_defconfig_list, prop) {
if (expr_calc_value(prop->visible.expr) == no ||
@@ -396,15 +399,149 @@ int conf_read(const char *name)
return 0;
}
+/* Write a S_STRING */
+static void conf_write_string(bool headerfile, const char *name,
+ const char *str, FILE *out)
+{
+ int l;
+ if (headerfile)
+ fprintf(out, "#define CONFIG_%s \"", name);
+ else
+ fprintf(out, "CONFIG_%s=\"", name);
+
+ while (1) {
+ l = strcspn(str, "\"\\");
+ if (l) {
+ fwrite(str, l, 1, out);
+ str += l;
+ }
+ if (!*str)
+ break;
+ fprintf(out, "\\%c", *str++);
+ }
+ fputs("\"\n", out);
+}
+
+static void conf_write_symbol(struct symbol *sym, enum symbol_type type,
+ FILE *out, bool write_no)
+{
+ const char *str;
+
+ switch (type) {
+ case S_BOOLEAN:
+ case S_TRISTATE:
+ switch (sym_get_tristate_value(sym)) {
+ case no:
+ if (write_no)
+ fprintf(out, "# CONFIG_%s is not set\n", sym->name);
+ break;
+ case mod:
+ fprintf(out, "CONFIG_%s=m\n", sym->name);
+ break;
+ case yes:
+ fprintf(out, "CONFIG_%s=y\n", sym->name);
+ break;
+ }
+ break;
+ case S_STRING:
+ conf_write_string(false, sym->name, sym_get_string_value(sym), out);
+ break;
+ case S_HEX:
+ case S_INT:
+ str = sym_get_string_value(sym);
+ fprintf(out, "CONFIG_%s=%s\n", sym->name, str);
+ break;
+ case S_OTHER:
+ case S_UNKNOWN:
+ break;
+ }
+}
+
+/*
+ * Write out a minimal config.
+ * All values that has default values are skipped as this is redundant.
+ */
+int conf_write_defconfig(const char *filename)
+{
+ struct symbol *sym;
+ struct menu *menu;
+ FILE *out;
+
+ out = fopen(filename, "w");
+ if (!out)
+ return 1;
+
+ sym_clear_all_valid();
+
+ /* Traverse all menus to find all relevant symbols */
+ menu = rootmenu.list;
+
+ while (menu != NULL)
+ {
+ sym = menu->sym;
+ if (sym == NULL) {
+ if (!menu_is_visible(menu))
+ goto next_menu;
+ } else if (!sym_is_choice(sym)) {
+ sym_calc_value(sym);
+ if (!(sym->flags & SYMBOL_WRITE))
+ goto next_menu;
+ sym->flags &= ~SYMBOL_WRITE;
+ /* If we cannot change the symbol - skip */
+ if (!sym_is_changable(sym))
+ goto next_menu;
+ /* If symbol equals to default value - skip */
+ if (strcmp(sym_get_string_value(sym), sym_get_string_default(sym)) == 0)
+ goto next_menu;
+
+ /*
+ * If symbol is a choice value and equals to the
+ * default for a choice - skip.
+ * But only if value equal to "y".
+ */
+ if (sym_is_choice_value(sym)) {
+ struct symbol *cs;
+ struct symbol *ds;
+
+ cs = prop_get_symbol(sym_get_choice_prop(sym));
+ ds = sym_choice_default(cs);
+ if (sym == ds) {
+ if ((sym->type == S_BOOLEAN ||
+ sym->type == S_TRISTATE) &&
+ sym_get_tristate_value(sym) == yes)
+ goto next_menu;
+ }
+ }
+ conf_write_symbol(sym, sym->type, out, true);
+ }
+next_menu:
+ if (menu->list != NULL) {
+ menu = menu->list;
+ }
+ else if (menu->next != NULL) {
+ menu = menu->next;
+ } else {
+ while ((menu = menu->parent)) {
+ if (menu->next != NULL) {
+ menu = menu->next;
+ break;
+ }
+ }
+ }
+ }
+ fclose(out);
+ return 0;
+}
+
int conf_write(const char *name)
{
FILE *out;
struct symbol *sym;
struct menu *menu;
const char *basename;
- char dirname[128], tmpname[128], newname[128];
- int type, l;
const char *str;
+ char dirname[128], tmpname[128], newname[128];
+ enum symbol_type type;
time_t now;
int use_timestamp = 1;
char *env;
@@ -484,50 +621,11 @@ int conf_write(const char *name)
if (modules_sym->curr.tri == no)
type = S_BOOLEAN;
}
- switch (type) {
- case S_BOOLEAN:
- case S_TRISTATE:
- switch (sym_get_tristate_value(sym)) {
- case no:
- fprintf(out, "# CONFIG_%s is not set\n", sym->name);
- break;
- case mod:
- fprintf(out, "CONFIG_%s=m\n", sym->name);
- break;
- case yes:
- fprintf(out, "CONFIG_%s=y\n", sym->name);
- break;
- }
- break;
- case S_STRING:
- str = sym_get_string_value(sym);
- fprintf(out, "CONFIG_%s=\"", sym->name);
- while (1) {
- l = strcspn(str, "\"\\");
- if (l) {
- fwrite(str, l, 1, out);
- str += l;
- }
- if (!*str)
- break;
- fprintf(out, "\\%c", *str++);
- }
- fputs("\"\n", out);
- break;
- case S_HEX:
- str = sym_get_string_value(sym);
- if (str[0] != '0' || (str[1] != 'x' && str[1] != 'X')) {
- fprintf(out, "CONFIG_%s=%s\n", sym->name, str);
- break;
- }
- case S_INT:
- str = sym_get_string_value(sym);
- fprintf(out, "CONFIG_%s=%s\n", sym->name, str);
- break;
- }
+ /* Write config symbol to file */
+ conf_write_symbol(sym, type, out, true);
}
- next:
+next:
if (menu->list) {
menu = menu->list;
continue;
@@ -679,7 +777,7 @@ int conf_write_autoconf(void)
const char *name;
FILE *out, *tristate, *out_h;
time_t now;
- int i, l;
+ int i;
sym_clear_all_valid();
@@ -729,6 +827,11 @@ int conf_write_autoconf(void)
sym_calc_value(sym);
if (!(sym->flags & SYMBOL_WRITE) || !sym->name)
continue;
+
+ /* write symbol to config file */
+ conf_write_symbol(sym, sym->type, out, false);
+
+ /* update autoconf and tristate files */
switch (sym->type) {
case S_BOOLEAN:
case S_TRISTATE:
@@ -736,12 +839,10 @@ int conf_write_autoconf(void)
case no:
break;
case mod:
- fprintf(out, "CONFIG_%s=m\n", sym->name);
fprintf(tristate, "CONFIG_%s=M\n", sym->name);
fprintf(out_h, "#define CONFIG_%s_MODULE 1\n", sym->name);
break;
case yes:
- fprintf(out, "CONFIG_%s=y\n", sym->name);
if (sym->type == S_TRISTATE)
fprintf(tristate, "CONFIG_%s=Y\n",
sym->name);
@@ -750,35 +851,16 @@ int conf_write_autoconf(void)
}
break;
case S_STRING:
- str = sym_get_string_value(sym);
- fprintf(out, "CONFIG_%s=\"", sym->name);
- fprintf(out_h, "#define CONFIG_%s \"", sym->name);
- while (1) {
- l = strcspn(str, "\"\\");
- if (l) {
- fwrite(str, l, 1, out);
- fwrite(str, l, 1, out_h);
- str += l;
- }
- if (!*str)
- break;
- fprintf(out, "\\%c", *str);
- fprintf(out_h, "\\%c", *str);
- str++;
- }
- fputs("\"\n", out);
- fputs("\"\n", out_h);
+ conf_write_string(true, sym->name, sym_get_string_value(sym), out_h);
break;
case S_HEX:
str = sym_get_string_value(sym);
if (str[0] != '0' || (str[1] != 'x' && str[1] != 'X')) {
- fprintf(out, "CONFIG_%s=%s\n", sym->name, str);
fprintf(out_h, "#define CONFIG_%s 0x%s\n", sym->name, str);
break;
}
case S_INT:
str = sym_get_string_value(sym);
- fprintf(out, "CONFIG_%s=%s\n", sym->name, str);
fprintf(out_h, "#define CONFIG_%s %s\n", sym->name, str);
break;
default:
@@ -862,7 +944,8 @@ void conf_set_all_new_symbols(enum conf_def_mode mode)
sym->def[S_DEF_USER].tri = no;
break;
case def_random:
- sym->def[S_DEF_USER].tri = (tristate)(rand() % 3);
+ cnt = sym_get_type(sym) == S_TRISTATE ? 3 : 2;
+ sym->def[S_DEF_USER].tri = (tristate)(rand() % cnt);
break;
default:
continue;
diff --git a/scripts/kconfig/expr.c b/scripts/kconfig/expr.c
index d83f2322893..8f18e37892c 100644
--- a/scripts/kconfig/expr.c
+++ b/scripts/kconfig/expr.c
@@ -1121,7 +1121,7 @@ static void expr_print_gstr_helper(void *data, struct symbol *sym, const char *s
}
str_append(gs, str);
- if (sym)
+ if (sym && sym->type != S_UNKNOWN)
str_printf(gs, " [=%s]", sym_str);
}
diff --git a/scripts/kconfig/expr.h b/scripts/kconfig/expr.h
index 891cd9ce9ba..6ee2e4fb148 100644
--- a/scripts/kconfig/expr.h
+++ b/scripts/kconfig/expr.h
@@ -83,6 +83,7 @@ struct symbol {
tristate visible;
int flags;
struct property *prop;
+ struct expr_value dir_dep;
struct expr_value rev_dep;
};
@@ -131,6 +132,7 @@ enum prop_type {
P_SELECT, /* select BAR */
P_RANGE, /* range 7..100 (for a symbol) */
P_ENV, /* value from environment variable */
+ P_SYMBOL, /* where a symbol is defined */
};
struct property {
@@ -163,6 +165,7 @@ struct menu {
struct symbol *sym;
struct property *prompt;
struct expr *dep;
+ struct expr *dir_dep;
unsigned int flags;
char *help;
struct file *file;
diff --git a/scripts/kconfig/gconf.c b/scripts/kconfig/gconf.c
index bef10411837..d66988265f8 100644
--- a/scripts/kconfig/gconf.c
+++ b/scripts/kconfig/gconf.c
@@ -1114,7 +1114,7 @@ static gchar **fill_row(struct menu *menu)
row[COL_OPTION] =
g_strdup_printf("%s %s", _(menu_get_prompt(menu)),
- sym && sym_has_value(sym) ? "(NEW)" : "");
+ sym && !sym_has_value(sym) ? "(NEW)" : "");
if (opt_mode == OPT_ALL && !menu_is_visible(menu))
row[COL_COLOR] = g_strdup("DarkGray");
@@ -1343,7 +1343,8 @@ static void update_tree(struct menu *src, GtkTreeIter * dst)
#endif
if ((opt_mode == OPT_NORMAL && !menu_is_visible(child1)) ||
- (opt_mode == OPT_PROMPT && !menu_has_prompt(child1))) {
+ (opt_mode == OPT_PROMPT && !menu_has_prompt(child1)) ||
+ (opt_mode == OPT_ALL && !menu_get_prompt(child1))) {
/* remove node */
if (gtktree_iter_find_node(dst, menu1) != NULL) {
@@ -1425,7 +1426,7 @@ static void display_tree(struct menu *menu)
if ((opt_mode == OPT_NORMAL && menu_is_visible(child)) ||
(opt_mode == OPT_PROMPT && menu_has_prompt(child)) ||
- (opt_mode == OPT_ALL))
+ (opt_mode == OPT_ALL && menu_get_prompt(child)))
place_node(child, fill_row(child));
#ifdef DEBUG
printf("%*c%s: ", indent, ' ', menu_get_prompt(child));
diff --git a/scripts/kconfig/lkc.h b/scripts/kconfig/lkc.h
index ce6549cdacc..76db065ed72 100644
--- a/scripts/kconfig/lkc.h
+++ b/scripts/kconfig/lkc.h
@@ -126,6 +126,8 @@ void sym_init(void);
void sym_clear_all_valid(void);
void sym_set_all_changed(void);
void sym_set_changed(struct symbol *sym);
+struct symbol *sym_choice_default(struct symbol *sym);
+const char *sym_get_string_default(struct symbol *sym);
struct symbol *sym_check_deps(struct symbol *sym);
struct property *prop_alloc(enum prop_type type, struct symbol *sym);
struct symbol *prop_get_symbol(struct property *prop);
diff --git a/scripts/kconfig/lkc_proto.h b/scripts/kconfig/lkc_proto.h
index 7cadcad8233..9a948c9ce44 100644
--- a/scripts/kconfig/lkc_proto.h
+++ b/scripts/kconfig/lkc_proto.h
@@ -3,6 +3,7 @@
P(conf_parse,void,(const char *name));
P(conf_read,int,(const char *name));
P(conf_read_simple,int,(const char *name, int));
+P(conf_write_defconfig,int,(const char *name));
P(conf_write,int,(const char *name));
P(conf_write_autoconf,int,(void));
P(conf_get_changed,bool,(void));
diff --git a/scripts/kconfig/lxdialog/checklist.c b/scripts/kconfig/lxdialog/checklist.c
index bcc6f19c3a3..a2eb80fbc89 100644
--- a/scripts/kconfig/lxdialog/checklist.c
+++ b/scripts/kconfig/lxdialog/checklist.c
@@ -31,6 +31,10 @@ static int list_width, check_x, item_x;
static void print_item(WINDOW * win, int choice, int selected)
{
int i;
+ char *list_item = malloc(list_width + 1);
+
+ strncpy(list_item, item_str(), list_width - item_x);
+ list_item[list_width - item_x] = '\0';
/* Clear 'residue' of last item */
wattrset(win, dlg.menubox.atr);
@@ -45,13 +49,14 @@ static void print_item(WINDOW * win, int choice, int selected)
wprintw(win, "(%c)", item_is_tag('X') ? 'X' : ' ');
wattrset(win, selected ? dlg.tag_selected.atr : dlg.tag.atr);
- mvwaddch(win, choice, item_x, item_str()[0]);
+ mvwaddch(win, choice, item_x, list_item[0]);
wattrset(win, selected ? dlg.item_selected.atr : dlg.item.atr);
- waddstr(win, (char *)item_str() + 1);
+ waddstr(win, list_item + 1);
if (selected) {
wmove(win, choice, check_x + 1);
wrefresh(win);
}
+ free(list_item);
}
/*
@@ -175,6 +180,7 @@ do_resize:
check_x = 0;
item_foreach()
check_x = MAX(check_x, strlen(item_str()) + 4);
+ check_x = MIN(check_x, list_width);
check_x = (list_width - check_x) / 2;
item_x = check_x + 4;
diff --git a/scripts/kconfig/mconf.c b/scripts/kconfig/mconf.c
index 2c83d3234d3..d2f6e056c05 100644
--- a/scripts/kconfig/mconf.c
+++ b/scripts/kconfig/mconf.c
@@ -74,7 +74,7 @@ static const char mconf_readme[] = N_(
"\n"
" Shortcut: Press <H> or <?>.\n"
"\n"
-"o To show hidden options, press <Z>.\n"
+"o To toggle the display of hidden options, press <Z>.\n"
"\n"
"\n"
"Radiolists (Choice lists)\n"
diff --git a/scripts/kconfig/menu.c b/scripts/kconfig/menu.c
index 203632cc30b..4fb590247f3 100644
--- a/scripts/kconfig/menu.c
+++ b/scripts/kconfig/menu.c
@@ -58,6 +58,8 @@ void menu_add_entry(struct symbol *sym)
*last_entry_ptr = menu;
last_entry_ptr = &menu->next;
current_entry = menu;
+ if (sym)
+ menu_add_symbol(P_SYMBOL, sym, NULL);
}
void menu_end_entry(void)
@@ -105,6 +107,7 @@ static struct expr *menu_check_dep(struct expr *e)
void menu_add_dep(struct expr *dep)
{
current_entry->dep = expr_alloc_and(current_entry->dep, menu_check_dep(dep));
+ current_entry->dir_dep = current_entry->dep;
}
void menu_set_type(int type)
@@ -288,6 +291,10 @@ void menu_finalize(struct menu *parent)
for (menu = parent->list; menu; menu = menu->next)
menu_finalize(menu);
} else if (sym) {
+ /* ignore inherited dependencies for dir_dep */
+ sym->dir_dep.expr = expr_transform(expr_copy(parent->dir_dep));
+ sym->dir_dep.expr = expr_eliminate_dups(sym->dir_dep.expr);
+
basedep = parent->prompt ? parent->prompt->visible.expr : NULL;
basedep = expr_trans_compare(basedep, E_UNEQUAL, &symbol_no);
basedep = expr_eliminate_dups(expr_transform(basedep));
@@ -419,9 +426,13 @@ bool menu_is_visible(struct menu *menu)
if (!sym || sym_get_tristate_value(menu->sym) == no)
return false;
- for (child = menu->list; child; child = child->next)
- if (menu_is_visible(child))
+ for (child = menu->list; child; child = child->next) {
+ if (menu_is_visible(child)) {
+ if (sym)
+ sym->flags |= SYMBOL_DEF_USER;
return true;
+ }
+ }
return false;
}
@@ -501,9 +512,19 @@ void get_symbol_str(struct gstr *r, struct symbol *sym)
bool hit;
struct property *prop;
- if (sym && sym->name)
+ if (sym && sym->name) {
str_printf(r, "Symbol: %s [=%s]\n", sym->name,
sym_get_string_value(sym));
+ str_printf(r, "Type : %s\n", sym_type_name(sym->type));
+ if (sym->type == S_INT || sym->type == S_HEX) {
+ prop = sym_get_range_prop(sym);
+ if (prop) {
+ str_printf(r, "Range : ");
+ expr_gstr_print(prop->expr, r);
+ str_append(r, "\n");
+ }
+ }
+ }
for_all_prompts(sym, prop)
get_prompt_str(r, prop);
hit = false;
diff --git a/scripts/kconfig/qconf.cc b/scripts/kconfig/qconf.cc
index 00c51507cfc..820df2d1217 100644
--- a/scripts/kconfig/qconf.cc
+++ b/scripts/kconfig/qconf.cc
@@ -58,11 +58,10 @@ QValueList<int> ConfigSettings::readSizes(const QString& key, bool *ok)
{
QValueList<int> result;
QStringList entryList = readListEntry(key, ok);
- if (ok) {
- QStringList::Iterator it;
- for (it = entryList.begin(); it != entryList.end(); ++it)
- result.push_back((*it).toInt());
- }
+ QStringList::Iterator it;
+
+ for (it = entryList.begin(); it != entryList.end(); ++it)
+ result.push_back((*it).toInt());
return result;
}
@@ -149,7 +148,7 @@ void ConfigItem::updateMenu(void)
case S_TRISTATE:
char ch;
- if (!sym_is_changable(sym) && !list->showAll) {
+ if (!sym_is_changable(sym) && list->optMode == normalOpt) {
setPixmap(promptColIdx, 0);
setText(noColIdx, QString::null);
setText(modColIdx, QString::null);
@@ -320,7 +319,7 @@ ConfigList::ConfigList(ConfigView* p, const char *name)
symbolYesPix(xpm_symbol_yes), symbolModPix(xpm_symbol_mod), symbolNoPix(xpm_symbol_no),
choiceYesPix(xpm_choice_yes), choiceNoPix(xpm_choice_no),
menuPix(xpm_menu), menuInvPix(xpm_menu_inv), menuBackPix(xpm_menuback), voidPix(xpm_void),
- showAll(false), showName(false), showRange(false), showData(false),
+ showName(false), showRange(false), showData(false), optMode(normalOpt),
rootEntry(0), headerPopup(0)
{
int i;
@@ -337,10 +336,10 @@ ConfigList::ConfigList(ConfigView* p, const char *name)
if (name) {
configSettings->beginGroup(name);
- showAll = configSettings->readBoolEntry("/showAll", false);
showName = configSettings->readBoolEntry("/showName", false);
showRange = configSettings->readBoolEntry("/showRange", false);
showData = configSettings->readBoolEntry("/showData", false);
+ optMode = (enum optionMode)configSettings->readNumEntry("/optionMode", false);
configSettings->endGroup();
connect(configApp, SIGNAL(aboutToQuit()), SLOT(saveSettings()));
}
@@ -352,6 +351,17 @@ ConfigList::ConfigList(ConfigView* p, const char *name)
reinit();
}
+bool ConfigList::menuSkip(struct menu *menu)
+{
+ if (optMode == normalOpt && menu_is_visible(menu))
+ return false;
+ if (optMode == promptOpt && menu_has_prompt(menu))
+ return false;
+ if (optMode == allOpt)
+ return false;
+ return true;
+}
+
void ConfigList::reinit(void)
{
removeColumn(dataColIdx);
@@ -380,7 +390,7 @@ void ConfigList::saveSettings(void)
configSettings->writeEntry("/showName", showName);
configSettings->writeEntry("/showRange", showRange);
configSettings->writeEntry("/showData", showData);
- configSettings->writeEntry("/showAll", showAll);
+ configSettings->writeEntry("/optionMode", (int)optMode);
configSettings->endGroup();
}
}
@@ -606,7 +616,7 @@ void ConfigList::updateMenuList(P* parent, struct menu* menu)
}
visible = menu_is_visible(child);
- if (showAll || visible) {
+ if (!menuSkip(child)) {
if (!child->sym && !child->list && !child->prompt)
continue;
if (!item || item->menu != child)
@@ -835,7 +845,10 @@ void ConfigList::contextMenuEvent(QContextMenuEvent *e)
e->ignore();
}
-ConfigView* ConfigView::viewList;
+ConfigView*ConfigView::viewList;
+QAction *ConfigView::showNormalAction;
+QAction *ConfigView::showAllAction;
+QAction *ConfigView::showPromptAction;
ConfigView::ConfigView(QWidget* parent, const char *name)
: Parent(parent, name)
@@ -860,13 +873,16 @@ ConfigView::~ConfigView(void)
}
}
-void ConfigView::setShowAll(bool b)
+void ConfigView::setOptionMode(QAction *act)
{
- if (list->showAll != b) {
- list->showAll = b;
- list->updateListAll();
- emit showAllChanged(b);
- }
+ if (act == showNormalAction)
+ list->optMode = normalOpt;
+ else if (act == showAllAction)
+ list->optMode = allOpt;
+ else
+ list->optMode = promptOpt;
+
+ list->updateListAll();
}
void ConfigView::setShowName(bool b)
@@ -964,34 +980,6 @@ void ConfigInfoView::setInfo(struct menu *m)
menuInfo();
}
-void ConfigInfoView::setSource(const QString& name)
-{
- const char *p = name.latin1();
-
- menu = NULL;
- sym = NULL;
-
- switch (p[0]) {
- case 'm':
- struct menu *m;
-
- if (sscanf(p, "m%p", &m) == 1 && menu != m) {
- menu = m;
- menuInfo();
- emit menuSelected(menu);
- }
- break;
- case 's':
- struct symbol *s;
-
- if (sscanf(p, "s%p", &s) == 1 && sym != s) {
- sym = s;
- symbolInfo();
- }
- break;
- }
-}
-
void ConfigInfoView::symbolInfo(void)
{
QString str;
@@ -1349,11 +1337,24 @@ ConfigMainWindow::ConfigMainWindow(void)
connect(showDataAction, SIGNAL(toggled(bool)), configView, SLOT(setShowData(bool)));
connect(configView, SIGNAL(showDataChanged(bool)), showDataAction, SLOT(setOn(bool)));
showDataAction->setOn(configList->showData);
- QAction *showAllAction = new QAction(NULL, _("Show All Options"), 0, this);
- showAllAction->setToggleAction(TRUE);
- connect(showAllAction, SIGNAL(toggled(bool)), configView, SLOT(setShowAll(bool)));
- connect(showAllAction, SIGNAL(toggled(bool)), menuView, SLOT(setShowAll(bool)));
- showAllAction->setOn(configList->showAll);
+
+ QActionGroup *optGroup = new QActionGroup(this);
+ optGroup->setExclusive(TRUE);
+ connect(optGroup, SIGNAL(selected(QAction *)), configView,
+ SLOT(setOptionMode(QAction *)));
+ connect(optGroup, SIGNAL(selected(QAction *)), menuView,
+ SLOT(setOptionMode(QAction *)));
+
+ configView->showNormalAction = new QAction(NULL, _("Show Normal Options"), 0, optGroup);
+ configView->showAllAction = new QAction(NULL, _("Show All Options"), 0, optGroup);
+ configView->showPromptAction = new QAction(NULL, _("Show Prompt Options"), 0, optGroup);
+ configView->showNormalAction->setToggleAction(TRUE);
+ configView->showNormalAction->setOn(configList->optMode == normalOpt);
+ configView->showAllAction->setToggleAction(TRUE);
+ configView->showAllAction->setOn(configList->optMode == allOpt);
+ configView->showPromptAction->setToggleAction(TRUE);
+ configView->showPromptAction->setOn(configList->optMode == promptOpt);
+
QAction *showDebugAction = new QAction(NULL, _("Show Debug Info"), 0, this);
showDebugAction->setToggleAction(TRUE);
connect(showDebugAction, SIGNAL(toggled(bool)), helpText, SLOT(setShowDebug(bool)));
@@ -1396,7 +1397,8 @@ ConfigMainWindow::ConfigMainWindow(void)
showRangeAction->addTo(optionMenu);
showDataAction->addTo(optionMenu);
optionMenu->insertSeparator();
- showAllAction->addTo(optionMenu);
+ optGroup->addTo(optionMenu);
+ optionMenu->insertSeparator();
showDebugAction->addTo(optionMenu);
// create help menu
@@ -1491,7 +1493,7 @@ void ConfigMainWindow::setMenuLink(struct menu *menu)
ConfigList* list = NULL;
ConfigItem* item;
- if (!menu_is_visible(menu) && !configView->showAll())
+ if (configList->menuSkip(menu))
return;
switch (configList->mode) {
diff --git a/scripts/kconfig/qconf.h b/scripts/kconfig/qconf.h
index b3b5657b6b3..636a74b23bf 100644
--- a/scripts/kconfig/qconf.h
+++ b/scripts/kconfig/qconf.h
@@ -44,6 +44,9 @@ enum colIdx {
enum listMode {
singleMode, menuMode, symbolMode, fullMode, listMode
};
+enum optionMode {
+ normalOpt = 0, allOpt, promptOpt
+};
class ConfigList : public QListView {
Q_OBJECT
@@ -115,6 +118,8 @@ public:
void setAllOpen(bool open);
void setParentMenu(void);
+ bool menuSkip(struct menu *);
+
template <class P>
void updateMenuList(P*, struct menu*);
@@ -124,8 +129,9 @@ public:
QPixmap choiceYesPix, choiceNoPix;
QPixmap menuPix, menuInvPix, menuBackPix, voidPix;
- bool showAll, showName, showRange, showData;
+ bool showName, showRange, showData;
enum listMode mode;
+ enum optionMode optMode;
struct menu *rootEntry;
QColorGroup disabledColorGroup;
QColorGroup inactivedColorGroup;
@@ -222,17 +228,15 @@ public:
static void updateList(ConfigItem* item);
static void updateListAll(void);
- bool showAll(void) const { return list->showAll; }
bool showName(void) const { return list->showName; }
bool showRange(void) const { return list->showRange; }
bool showData(void) const { return list->showData; }
public slots:
- void setShowAll(bool);
void setShowName(bool);
void setShowRange(bool);
void setShowData(bool);
+ void setOptionMode(QAction *);
signals:
- void showAllChanged(bool);
void showNameChanged(bool);
void showRangeChanged(bool);
void showDataChanged(bool);
@@ -242,6 +246,10 @@ public:
static ConfigView* viewList;
ConfigView* nextView;
+
+ static QAction *showNormalAction;
+ static QAction *showAllAction;
+ static QAction *showPromptAction;
};
class ConfigInfoView : public QTextBrowser {
@@ -254,7 +262,6 @@ public:
public slots:
void setInfo(struct menu *menu);
void saveSettings(void);
- void setSource(const QString& name);
void setShowDebug(bool);
signals:
diff --git a/scripts/kconfig/symbol.c b/scripts/kconfig/symbol.c
index 2e7a048e0cf..e95718fea35 100644
--- a/scripts/kconfig/symbol.c
+++ b/scripts/kconfig/symbol.c
@@ -205,6 +205,16 @@ static void sym_calc_visibility(struct symbol *sym)
}
if (sym_is_choice_value(sym))
return;
+ /* defaulting to "yes" if no explicit "depends on" are given */
+ tri = yes;
+ if (sym->dir_dep.expr)
+ tri = expr_calc_value(sym->dir_dep.expr);
+ if (tri == mod)
+ tri = yes;
+ if (sym->dir_dep.tri != tri) {
+ sym->dir_dep.tri = tri;
+ sym_set_changed(sym);
+ }
tri = no;
if (sym->rev_dep.expr)
tri = expr_calc_value(sym->rev_dep.expr);
@@ -216,44 +226,63 @@ static void sym_calc_visibility(struct symbol *sym)
}
}
-static struct symbol *sym_calc_choice(struct symbol *sym)
+/*
+ * Find the default symbol for a choice.
+ * First try the default values for the choice symbol
+ * Next locate the first visible choice value
+ * Return NULL if none was found
+ */
+struct symbol *sym_choice_default(struct symbol *sym)
{
struct symbol *def_sym;
struct property *prop;
struct expr *e;
- /* is the user choice visible? */
- def_sym = sym->def[S_DEF_USER].val;
- if (def_sym) {
- sym_calc_visibility(def_sym);
- if (def_sym->visible != no)
- return def_sym;
- }
-
/* any of the defaults visible? */
for_all_defaults(sym, prop) {
prop->visible.tri = expr_calc_value(prop->visible.expr);
if (prop->visible.tri == no)
continue;
def_sym = prop_get_symbol(prop);
- sym_calc_visibility(def_sym);
if (def_sym->visible != no)
return def_sym;
}
/* just get the first visible value */
prop = sym_get_choice_prop(sym);
- expr_list_for_each_sym(prop->expr, e, def_sym) {
- sym_calc_visibility(def_sym);
+ expr_list_for_each_sym(prop->expr, e, def_sym)
if (def_sym->visible != no)
return def_sym;
- }
- /* no choice? reset tristate value */
- sym->curr.tri = no;
+ /* failed to locate any defaults */
return NULL;
}
+static struct symbol *sym_calc_choice(struct symbol *sym)
+{
+ struct symbol *def_sym;
+ struct property *prop;
+ struct expr *e;
+
+ /* first calculate all choice values' visibilities */
+ prop = sym_get_choice_prop(sym);
+ expr_list_for_each_sym(prop->expr, e, def_sym)
+ sym_calc_visibility(def_sym);
+
+ /* is the user choice visible? */
+ def_sym = sym->def[S_DEF_USER].val;
+ if (def_sym && def_sym->visible != no)
+ return def_sym;
+
+ def_sym = sym_choice_default(sym);
+
+ if (def_sym == NULL)
+ /* no choice? reset tristate value */
+ sym->curr.tri = no;
+
+ return def_sym;
+}
+
void sym_calc_value(struct symbol *sym)
{
struct symbol_value newval, oldval;
@@ -321,6 +350,14 @@ void sym_calc_value(struct symbol *sym)
}
}
calc_newval:
+ if (sym->dir_dep.tri == no && sym->rev_dep.tri != no) {
+ fprintf(stderr, "warning: (");
+ expr_fprint(sym->rev_dep.expr, stderr);
+ fprintf(stderr, ") selects %s which has unmet direct dependencies (",
+ sym->name);
+ expr_fprint(sym->dir_dep.expr, stderr);
+ fprintf(stderr, ")\n");
+ }
newval.tri = EXPR_OR(newval.tri, sym->rev_dep.tri);
}
if (newval.tri == mod && sym_get_type(sym) == S_BOOLEAN)
@@ -365,12 +402,13 @@ void sym_calc_value(struct symbol *sym)
if (sym_is_choice(sym)) {
struct symbol *choice_sym;
- int flags = sym->flags & (SYMBOL_CHANGED | SYMBOL_WRITE);
prop = sym_get_choice_prop(sym);
expr_list_for_each_sym(prop->expr, e, choice_sym) {
- choice_sym->flags |= flags;
- if (flags & SYMBOL_CHANGED)
+ if ((sym->flags & SYMBOL_WRITE) &&
+ choice_sym->visible != no)
+ choice_sym->flags |= SYMBOL_WRITE;
+ if (sym->flags & SYMBOL_CHANGED)
sym_set_changed(choice_sym);
}
}
@@ -623,6 +661,80 @@ bool sym_set_string_value(struct symbol *sym, const char *newval)
return true;
}
+/*
+ * Find the default value associated to a symbol.
+ * For tristate symbol handle the modules=n case
+ * in which case "m" becomes "y".
+ * If the symbol does not have any default then fallback
+ * to the fixed default values.
+ */
+const char *sym_get_string_default(struct symbol *sym)
+{
+ struct property *prop;
+ struct symbol *ds;
+ const char *str;
+ tristate val;
+
+ sym_calc_visibility(sym);
+ sym_calc_value(modules_sym);
+ val = symbol_no.curr.tri;
+ str = symbol_empty.curr.val;
+
+ /* If symbol has a default value look it up */
+ prop = sym_get_default_prop(sym);
+ if (prop != NULL) {
+ switch (sym->type) {
+ case S_BOOLEAN:
+ case S_TRISTATE:
+ /* The visibility imay limit the value from yes => mod */
+ val = EXPR_AND(expr_calc_value(prop->expr), prop->visible.tri);
+ break;
+ default:
+ /*
+ * The following fails to handle the situation
+ * where a default value is further limited by
+ * the valid range.
+ */
+ ds = prop_get_symbol(prop);
+ if (ds != NULL) {
+ sym_calc_value(ds);
+ str = (const char *)ds->curr.val;
+ }
+ }
+ }
+
+ /* Handle select statements */
+ val = EXPR_OR(val, sym->rev_dep.tri);
+
+ /* transpose mod to yes if modules are not enabled */
+ if (val == mod)
+ if (!sym_is_choice_value(sym) && modules_sym->curr.tri == no)
+ val = yes;
+
+ /* transpose mod to yes if type is bool */
+ if (sym->type == S_BOOLEAN && val == mod)
+ val = yes;
+
+ switch (sym->type) {
+ case S_BOOLEAN:
+ case S_TRISTATE:
+ switch (val) {
+ case no: return "n";
+ case mod: return "m";
+ case yes: return "y";
+ }
+ case S_INT:
+ case S_HEX:
+ return str;
+ case S_STRING:
+ return str;
+ case S_OTHER:
+ case S_UNKNOWN:
+ break;
+ }
+ return "";
+}
+
const char *sym_get_string_value(struct symbol *sym)
{
tristate val;
@@ -765,6 +877,110 @@ struct symbol **sym_re_search(const char *pattern)
return sym_arr;
}
+/*
+ * When we check for recursive dependencies we use a stack to save
+ * current state so we can print out relevant info to user.
+ * The entries are located on the call stack so no need to free memory.
+ * Note inser() remove() must always match to properly clear the stack.
+ */
+static struct dep_stack {
+ struct dep_stack *prev, *next;
+ struct symbol *sym;
+ struct property *prop;
+ struct expr *expr;
+} *check_top;
+
+static void dep_stack_insert(struct dep_stack *stack, struct symbol *sym)
+{
+ memset(stack, 0, sizeof(*stack));
+ if (check_top)
+ check_top->next = stack;
+ stack->prev = check_top;
+ stack->sym = sym;
+ check_top = stack;
+}
+
+static void dep_stack_remove(void)
+{
+ check_top = check_top->prev;
+ if (check_top)
+ check_top->next = NULL;
+}
+
+/*
+ * Called when we have detected a recursive dependency.
+ * check_top point to the top of the stact so we use
+ * the ->prev pointer to locate the bottom of the stack.
+ */
+static void sym_check_print_recursive(struct symbol *last_sym)
+{
+ struct dep_stack *stack;
+ struct symbol *sym, *next_sym;
+ struct menu *menu = NULL;
+ struct property *prop;
+ struct dep_stack cv_stack;
+
+ if (sym_is_choice_value(last_sym)) {
+ dep_stack_insert(&cv_stack, last_sym);
+ last_sym = prop_get_symbol(sym_get_choice_prop(last_sym));
+ }
+
+ for (stack = check_top; stack != NULL; stack = stack->prev)
+ if (stack->sym == last_sym)
+ break;
+ if (!stack) {
+ fprintf(stderr, "unexpected recursive dependency error\n");
+ return;
+ }
+
+ for (; stack; stack = stack->next) {
+ sym = stack->sym;
+ next_sym = stack->next ? stack->next->sym : last_sym;
+ prop = stack->prop;
+
+ /* for choice values find the menu entry (used below) */
+ if (sym_is_choice(sym) || sym_is_choice_value(sym)) {
+ for (prop = sym->prop; prop; prop = prop->next) {
+ menu = prop->menu;
+ if (prop->menu)
+ break;
+ }
+ }
+ if (stack->sym == last_sym)
+ fprintf(stderr, "%s:%d:error: recursive dependency detected!\n",
+ prop->file->name, prop->lineno);
+ if (stack->expr) {
+ fprintf(stderr, "%s:%d:\tsymbol %s %s value contains %s\n",
+ prop->file->name, prop->lineno,
+ sym->name ? sym->name : "<choice>",
+ prop_get_type_name(prop->type),
+ next_sym->name ? next_sym->name : "<choice>");
+ } else if (stack->prop) {
+ fprintf(stderr, "%s:%d:\tsymbol %s depends on %s\n",
+ prop->file->name, prop->lineno,
+ sym->name ? sym->name : "<choice>",
+ next_sym->name ? next_sym->name : "<choice>");
+ } else if (sym_is_choice(sym)) {
+ fprintf(stderr, "%s:%d:\tchoice %s contains symbol %s\n",
+ menu->file->name, menu->lineno,
+ sym->name ? sym->name : "<choice>",
+ next_sym->name ? next_sym->name : "<choice>");
+ } else if (sym_is_choice_value(sym)) {
+ fprintf(stderr, "%s:%d:\tsymbol %s is part of choice %s\n",
+ menu->file->name, menu->lineno,
+ sym->name ? sym->name : "<choice>",
+ next_sym->name ? next_sym->name : "<choice>");
+ } else {
+ fprintf(stderr, "%s:%d:\tsymbol %s is selected by %s\n",
+ prop->file->name, prop->lineno,
+ sym->name ? sym->name : "<choice>",
+ next_sym->name ? next_sym->name : "<choice>");
+ }
+ }
+
+ if (check_top == &cv_stack)
+ dep_stack_remove();
+}
static struct symbol *sym_check_expr_deps(struct expr *e)
{
@@ -801,24 +1017,33 @@ static struct symbol *sym_check_sym_deps(struct symbol *sym)
{
struct symbol *sym2;
struct property *prop;
+ struct dep_stack stack;
+
+ dep_stack_insert(&stack, sym);
sym2 = sym_check_expr_deps(sym->rev_dep.expr);
if (sym2)
- return sym2;
+ goto out;
for (prop = sym->prop; prop; prop = prop->next) {
if (prop->type == P_CHOICE || prop->type == P_SELECT)
continue;
+ stack.prop = prop;
sym2 = sym_check_expr_deps(prop->visible.expr);
if (sym2)
break;
if (prop->type != P_DEFAULT || sym_is_choice(sym))
continue;
+ stack.expr = prop->expr;
sym2 = sym_check_expr_deps(prop->expr);
if (sym2)
break;
+ stack.expr = NULL;
}
+out:
+ dep_stack_remove();
+
return sym2;
}
@@ -827,6 +1052,9 @@ static struct symbol *sym_check_choice_deps(struct symbol *choice)
struct symbol *sym, *sym2;
struct property *prop;
struct expr *e;
+ struct dep_stack stack;
+
+ dep_stack_insert(&stack, choice);
prop = sym_get_choice_prop(choice);
expr_list_for_each_sym(prop->expr, e, sym)
@@ -840,10 +1068,8 @@ static struct symbol *sym_check_choice_deps(struct symbol *choice)
expr_list_for_each_sym(prop->expr, e, sym) {
sym2 = sym_check_sym_deps(sym);
- if (sym2) {
- fprintf(stderr, " -> %s", sym->name);
+ if (sym2)
break;
- }
}
out:
expr_list_for_each_sym(prop->expr, e, sym)
@@ -853,6 +1079,8 @@ out:
prop_get_symbol(sym_get_choice_prop(sym2)) == choice)
sym2 = choice;
+ dep_stack_remove();
+
return sym2;
}
@@ -862,18 +1090,20 @@ struct symbol *sym_check_deps(struct symbol *sym)
struct property *prop;
if (sym->flags & SYMBOL_CHECK) {
- fprintf(stderr, "%s:%d:error: found recursive dependency: %s",
- sym->prop->file->name, sym->prop->lineno,
- sym->name ? sym->name : "<choice>");
+ sym_check_print_recursive(sym);
return sym;
}
if (sym->flags & SYMBOL_CHECKED)
return NULL;
if (sym_is_choice_value(sym)) {
+ struct dep_stack stack;
+
/* for choice groups start the check with main choice symbol */
+ dep_stack_insert(&stack, sym);
prop = sym_get_choice_prop(sym);
sym2 = sym_check_deps(prop_get_symbol(prop));
+ dep_stack_remove();
} else if (sym_is_choice(sym)) {
sym2 = sym_check_choice_deps(sym);
} else {
@@ -882,14 +1112,8 @@ struct symbol *sym_check_deps(struct symbol *sym)
sym->flags &= ~SYMBOL_CHECK;
}
- if (sym2) {
- fprintf(stderr, " -> %s", sym->name ? sym->name : "<choice>");
- if (sym2 == sym) {
- fprintf(stderr, "\n");
- zconfnerrs++;
- sym2 = NULL;
- }
- }
+ if (sym2 && sym2 == sym)
+ sym2 = NULL;
return sym2;
}
@@ -943,6 +1167,8 @@ const char *prop_get_type_name(enum prop_type type)
return "select";
case P_RANGE:
return "range";
+ case P_SYMBOL:
+ return "symbol";
case P_UNKNOWN:
break;
}
diff --git a/scripts/mod/file2alias.c b/scripts/mod/file2alias.c
index 5758aab0d8b..88f3f07205f 100644
--- a/scripts/mod/file2alias.c
+++ b/scripts/mod/file2alias.c
@@ -884,16 +884,16 @@ void handle_moddevtable(struct module *mod, struct elf_info *info,
char *zeros = NULL;
/* We're looking for a section relative symbol */
- if (!sym->st_shndx || sym->st_shndx >= info->hdr->e_shnum)
+ if (!sym->st_shndx || get_secindex(info, sym) >= info->num_sections)
return;
/* Handle all-NULL symbols allocated into .bss */
- if (info->sechdrs[sym->st_shndx].sh_type & SHT_NOBITS) {
+ if (info->sechdrs[get_secindex(info, sym)].sh_type & SHT_NOBITS) {
zeros = calloc(1, sym->st_size);
symval = zeros;
} else {
symval = (void *)info->hdr
- + info->sechdrs[sym->st_shndx].sh_offset
+ + info->sechdrs[get_secindex(info, sym)].sh_offset
+ sym->st_value;
}
diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c
index f6127b9f5ac..c827309c29c 100644
--- a/scripts/mod/modpost.c
+++ b/scripts/mod/modpost.c
@@ -253,7 +253,7 @@ static enum export export_no(const char *s)
return export_unknown;
}
-static enum export export_from_sec(struct elf_info *elf, Elf_Section sec)
+static enum export export_from_sec(struct elf_info *elf, unsigned int sec)
{
if (sec == elf->export_sec)
return export_plain;
@@ -373,6 +373,8 @@ static int parse_elf(struct elf_info *info, const char *filename)
Elf_Ehdr *hdr;
Elf_Shdr *sechdrs;
Elf_Sym *sym;
+ const char *secstrings;
+ unsigned int symtab_idx = ~0U, symtab_shndx_idx = ~0U;
hdr = grab_file(filename, &info->size);
if (!hdr) {
@@ -417,8 +419,27 @@ static int parse_elf(struct elf_info *info, const char *filename)
return 0;
}
+ if (hdr->e_shnum == 0) {
+ /*
+ * There are more than 64k sections,
+ * read count from .sh_size.
+ * note: it doesn't need shndx2secindex()
+ */
+ info->num_sections = TO_NATIVE(sechdrs[0].sh_size);
+ }
+ else {
+ info->num_sections = hdr->e_shnum;
+ }
+ if (hdr->e_shstrndx == SHN_XINDEX) {
+ info->secindex_strings =
+ shndx2secindex(TO_NATIVE(sechdrs[0].sh_link));
+ }
+ else {
+ info->secindex_strings = hdr->e_shstrndx;
+ }
+
/* Fix endianness in section headers */
- for (i = 0; i < hdr->e_shnum; i++) {
+ for (i = 0; i < info->num_sections; i++) {
sechdrs[i].sh_name = TO_NATIVE(sechdrs[i].sh_name);
sechdrs[i].sh_type = TO_NATIVE(sechdrs[i].sh_type);
sechdrs[i].sh_flags = TO_NATIVE(sechdrs[i].sh_flags);
@@ -431,9 +452,8 @@ static int parse_elf(struct elf_info *info, const char *filename)
sechdrs[i].sh_entsize = TO_NATIVE(sechdrs[i].sh_entsize);
}
/* Find symbol table. */
- for (i = 1; i < hdr->e_shnum; i++) {
- const char *secstrings
- = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset;
+ secstrings = (void *)hdr + sechdrs[info->secindex_strings].sh_offset;
+ for (i = 1; i < info->num_sections; i++) {
const char *secname;
int nobits = sechdrs[i].sh_type == SHT_NOBITS;
@@ -461,14 +481,26 @@ static int parse_elf(struct elf_info *info, const char *filename)
else if (strcmp(secname, "__ksymtab_gpl_future") == 0)
info->export_gpl_future_sec = i;
- if (sechdrs[i].sh_type != SHT_SYMTAB)
- continue;
+ if (sechdrs[i].sh_type == SHT_SYMTAB) {
+ unsigned int sh_link_idx;
+ symtab_idx = i;
+ info->symtab_start = (void *)hdr +
+ sechdrs[i].sh_offset;
+ info->symtab_stop = (void *)hdr +
+ sechdrs[i].sh_offset + sechdrs[i].sh_size;
+ sh_link_idx = shndx2secindex(sechdrs[i].sh_link);
+ info->strtab = (void *)hdr +
+ sechdrs[sh_link_idx].sh_offset;
+ }
- info->symtab_start = (void *)hdr + sechdrs[i].sh_offset;
- info->symtab_stop = (void *)hdr + sechdrs[i].sh_offset
- + sechdrs[i].sh_size;
- info->strtab = (void *)hdr +
- sechdrs[sechdrs[i].sh_link].sh_offset;
+ /* 32bit section no. table? ("more than 64k sections") */
+ if (sechdrs[i].sh_type == SHT_SYMTAB_SHNDX) {
+ symtab_shndx_idx = i;
+ info->symtab_shndx_start = (void *)hdr +
+ sechdrs[i].sh_offset;
+ info->symtab_shndx_stop = (void *)hdr +
+ sechdrs[i].sh_offset + sechdrs[i].sh_size;
+ }
}
if (!info->symtab_start)
fatal("%s has no symtab?\n", filename);
@@ -480,6 +512,21 @@ static int parse_elf(struct elf_info *info, const char *filename)
sym->st_value = TO_NATIVE(sym->st_value);
sym->st_size = TO_NATIVE(sym->st_size);
}
+
+ if (symtab_shndx_idx != ~0U) {
+ Elf32_Word *p;
+ if (symtab_idx !=
+ shndx2secindex(sechdrs[symtab_shndx_idx].sh_link))
+ fatal("%s: SYMTAB_SHNDX has bad sh_link: %u!=%u\n",
+ filename,
+ shndx2secindex(sechdrs[symtab_shndx_idx].sh_link),
+ symtab_idx);
+ /* Fix endianness */
+ for (p = info->symtab_shndx_start; p < info->symtab_shndx_stop;
+ p++)
+ *p = TO_NATIVE(*p);
+ }
+
return 1;
}
@@ -519,7 +566,7 @@ static void handle_modversions(struct module *mod, struct elf_info *info,
Elf_Sym *sym, const char *symname)
{
unsigned int crc;
- enum export export = export_from_sec(info, sym->st_shndx);
+ enum export export = export_from_sec(info, get_secindex(info, sym));
switch (sym->st_shndx) {
case SHN_COMMON:
@@ -661,19 +708,19 @@ static const char *sym_name(struct elf_info *elf, Elf_Sym *sym)
return "(unknown)";
}
-static const char *sec_name(struct elf_info *elf, int shndx)
+static const char *sec_name(struct elf_info *elf, int secindex)
{
Elf_Shdr *sechdrs = elf->sechdrs;
return (void *)elf->hdr +
- elf->sechdrs[elf->hdr->e_shstrndx].sh_offset +
- sechdrs[shndx].sh_name;
+ elf->sechdrs[elf->secindex_strings].sh_offset +
+ sechdrs[secindex].sh_name;
}
static const char *sech_name(struct elf_info *elf, Elf_Shdr *sechdr)
{
return (void *)elf->hdr +
- elf->sechdrs[elf->hdr->e_shstrndx].sh_offset +
- sechdr->sh_name;
+ elf->sechdrs[elf->secindex_strings].sh_offset +
+ sechdr->sh_name;
}
/* if sym is empty or point to a string
@@ -1052,11 +1099,14 @@ static Elf_Sym *find_elf_symbol(struct elf_info *elf, Elf64_Sword addr,
Elf_Sym *near = NULL;
Elf64_Sword distance = 20;
Elf64_Sword d;
+ unsigned int relsym_secindex;
if (relsym->st_name != 0)
return relsym;
+
+ relsym_secindex = get_secindex(elf, relsym);
for (sym = elf->symtab_start; sym < elf->symtab_stop; sym++) {
- if (sym->st_shndx != relsym->st_shndx)
+ if (get_secindex(elf, sym) != relsym_secindex)
continue;
if (ELF_ST_TYPE(sym->st_info) == STT_SECTION)
continue;
@@ -1118,9 +1168,9 @@ static Elf_Sym *find_elf_symbol2(struct elf_info *elf, Elf_Addr addr,
for (sym = elf->symtab_start; sym < elf->symtab_stop; sym++) {
const char *symsec;
- if (sym->st_shndx >= SHN_LORESERVE)
+ if (is_shndx_special(sym->st_shndx))
continue;
- symsec = sec_name(elf, sym->st_shndx);
+ symsec = sec_name(elf, get_secindex(elf, sym));
if (strcmp(symsec, sec) != 0)
continue;
if (!is_valid_name(elf, sym))
@@ -1316,7 +1366,7 @@ static void check_section_mismatch(const char *modname, struct elf_info *elf,
const char *tosec;
const struct sectioncheck *mismatch;
- tosec = sec_name(elf, sym->st_shndx);
+ tosec = sec_name(elf, get_secindex(elf, sym));
mismatch = section_mismatch(fromsec, tosec);
if (mismatch) {
Elf_Sym *to;
@@ -1344,7 +1394,7 @@ static unsigned int *reloc_location(struct elf_info *elf,
Elf_Shdr *sechdr, Elf_Rela *r)
{
Elf_Shdr *sechdrs = elf->sechdrs;
- int section = sechdr->sh_info;
+ int section = shndx2secindex(sechdr->sh_info);
return (void *)elf->hdr + sechdrs[section].sh_offset +
r->r_offset - sechdrs[section].sh_addr;
@@ -1452,7 +1502,7 @@ static void section_rela(const char *modname, struct elf_info *elf,
r.r_addend = TO_NATIVE(rela->r_addend);
sym = elf->symtab_start + r_sym;
/* Skip special sections */
- if (sym->st_shndx >= SHN_LORESERVE)
+ if (is_shndx_special(sym->st_shndx))
continue;
check_section_mismatch(modname, elf, &r, sym, fromsec);
}
@@ -1510,7 +1560,7 @@ static void section_rel(const char *modname, struct elf_info *elf,
}
sym = elf->symtab_start + r_sym;
/* Skip special sections */
- if (sym->st_shndx >= SHN_LORESERVE)
+ if (is_shndx_special(sym->st_shndx))
continue;
check_section_mismatch(modname, elf, &r, sym, fromsec);
}
@@ -1535,7 +1585,7 @@ static void check_sec_ref(struct module *mod, const char *modname,
Elf_Shdr *sechdrs = elf->sechdrs;
/* Walk through all sections */
- for (i = 0; i < elf->hdr->e_shnum; i++) {
+ for (i = 0; i < elf->num_sections; i++) {
check_section(modname, elf, &elf->sechdrs[i]);
/* We want to process only relocation sections and not .init */
if (sechdrs[i].sh_type == SHT_RELA)
diff --git a/scripts/mod/modpost.h b/scripts/mod/modpost.h
index be987a44f25..0388cfccac8 100644
--- a/scripts/mod/modpost.h
+++ b/scripts/mod/modpost.h
@@ -129,8 +129,51 @@ struct elf_info {
const char *strtab;
char *modinfo;
unsigned int modinfo_len;
+
+ /* support for 32bit section numbers */
+
+ unsigned int num_sections; /* max_secindex + 1 */
+ unsigned int secindex_strings;
+ /* if Nth symbol table entry has .st_shndx = SHN_XINDEX,
+ * take shndx from symtab_shndx_start[N] instead */
+ Elf32_Word *symtab_shndx_start;
+ Elf32_Word *symtab_shndx_stop;
};
+static inline int is_shndx_special(unsigned int i)
+{
+ return i != SHN_XINDEX && i >= SHN_LORESERVE && i <= SHN_HIRESERVE;
+}
+
+/* shndx is in [0..SHN_LORESERVE) U (SHN_HIRESERVE, 0xfffffff], thus:
+ * shndx == 0 <=> sechdrs[0]
+ * ......
+ * shndx == SHN_LORESERVE-1 <=> sechdrs[SHN_LORESERVE-1]
+ * shndx == SHN_HIRESERVE+1 <=> sechdrs[SHN_LORESERVE]
+ * shndx == SHN_HIRESERVE+2 <=> sechdrs[SHN_LORESERVE+1]
+ * ......
+ * fyi: sym->st_shndx is uint16, SHN_LORESERVE = ff00, SHN_HIRESERVE = ffff,
+ * so basically we map 0000..feff -> 0000..feff
+ * ff00..ffff -> (you are a bad boy, dont do it)
+ * 10000..xxxx -> ff00..(xxxx-0x100)
+ */
+static inline unsigned int shndx2secindex(unsigned int i)
+{
+ if (i <= SHN_HIRESERVE)
+ return i;
+ return i - (SHN_HIRESERVE + 1 - SHN_LORESERVE);
+}
+
+/* Accessor for sym->st_shndx, hides ugliness of "64k sections" */
+static inline unsigned int get_secindex(const struct elf_info *info,
+ const Elf_Sym *sym)
+{
+ if (sym->st_shndx != SHN_XINDEX)
+ return sym->st_shndx;
+ return shndx2secindex(info->symtab_shndx_start[sym -
+ info->symtab_start]);
+}
+
/* file2alias.c */
extern unsigned int cross_build;
void handle_moddevtable(struct module *mod, struct elf_info *info,
diff --git a/scripts/package/Makefile b/scripts/package/Makefile
index d2c29b63add..d0b931b994f 100644
--- a/scripts/package/Makefile
+++ b/scripts/package/Makefile
@@ -111,13 +111,38 @@ tar%pkg: FORCE
clean-dirs += $(objtree)/tar-install/
+# perf-pkg - generate a source tarball with perf source
+# ---------------------------------------------------------------------------
+
+perf-tar=perf-$(KERNELVERSION)
+
+quiet_cmd_perf_tar = TAR
+ cmd_perf_tar = \
+git archive --prefix=$(perf-tar)/ HEAD^{tree} \
+ $$(cat $(srctree)/tools/perf/MANIFEST) -o $(perf-tar).tar; \
+mkdir -p $(perf-tar); \
+git rev-parse HEAD > $(perf-tar)/HEAD; \
+tar rf $(perf-tar).tar $(perf-tar)/HEAD; \
+rm -r $(perf-tar); \
+$(if $(findstring tar-src,$@),, \
+$(if $(findstring bz2,$@),bzip2, \
+$(if $(findstring gz,$@),gzip, \
+$(error unknown target $@))) \
+ -f -9 $(perf-tar).tar)
+
+perf-%pkg: FORCE
+ $(call cmd,perf_tar)
+
# Help text displayed when executing 'make help'
# ---------------------------------------------------------------------------
help: FORCE
- @echo ' rpm-pkg - Build both source and binary RPM kernel packages'
- @echo ' binrpm-pkg - Build only the binary kernel package'
- @echo ' deb-pkg - Build the kernel as an deb package'
- @echo ' tar-pkg - Build the kernel as an uncompressed tarball'
- @echo ' targz-pkg - Build the kernel as a gzip compressed tarball'
- @echo ' tarbz2-pkg - Build the kernel as a bzip2 compressed tarball'
+ @echo ' rpm-pkg - Build both source and binary RPM kernel packages'
+ @echo ' binrpm-pkg - Build only the binary kernel package'
+ @echo ' deb-pkg - Build the kernel as an deb package'
+ @echo ' tar-pkg - Build the kernel as an uncompressed tarball'
+ @echo ' targz-pkg - Build the kernel as a gzip compressed tarball'
+ @echo ' tarbz2-pkg - Build the kernel as a bzip2 compressed tarball'
+ @echo ' perf-tar-src-pkg - Build $(perf-tar).tar source tarball'
+ @echo ' perf-targz-src-pkg - Build $(perf-tar).tar.gz source tarball'
+ @echo ' perf-tarbz2-src-pkg - Build $(perf-tar).tar.bz2 source tarball'
diff --git a/scripts/package/builddeb b/scripts/package/builddeb
index 07f2fbde2ab..5f1e2fc7f17 100644
--- a/scripts/package/builddeb
+++ b/scripts/package/builddeb
@@ -148,10 +148,11 @@ EOF
# Generate a control file
cat <<EOF > debian/control
Source: linux-upstream
-Section: admin
+Section: kernel
Priority: optional
Maintainer: $maintainer
-Standards-Version: 3.8.1
+Standards-Version: 3.8.4
+Homepage: http://www.kernel.org/
EOF
if [ "$ARCH" = "um" ]; then
diff --git a/scripts/recordmcount.pl b/scripts/recordmcount.pl
index f3c9c0a90b9..0171060b5fd 100755
--- a/scripts/recordmcount.pl
+++ b/scripts/recordmcount.pl
@@ -326,7 +326,7 @@ if ($arch eq "x86_64") {
# 14: R_MIPS_NONE *ABS*
# 18: 00020021 nop
if ($is_module eq "0") {
- $mcount_regex = "^\\s*([0-9a-fA-F]+):.*\\s_mcount\$";
+ $mcount_regex = "^\\s*([0-9a-fA-F]+): R_MIPS_26\\s+_mcount\$";
} else {
$mcount_regex = "^\\s*([0-9a-fA-F]+): R_MIPS_HI16\\s+_mcount\$";
}
diff --git a/security/Kconfig b/security/Kconfig
index 226b9556b25..bd72ae62349 100644
--- a/security/Kconfig
+++ b/security/Kconfig
@@ -140,6 +140,7 @@ config LSM_MMAP_MIN_ADDR
source security/selinux/Kconfig
source security/smack/Kconfig
source security/tomoyo/Kconfig
+source security/apparmor/Kconfig
source security/integrity/ima/Kconfig
@@ -148,6 +149,7 @@ choice
default DEFAULT_SECURITY_SELINUX if SECURITY_SELINUX
default DEFAULT_SECURITY_SMACK if SECURITY_SMACK
default DEFAULT_SECURITY_TOMOYO if SECURITY_TOMOYO
+ default DEFAULT_SECURITY_APPARMOR if SECURITY_APPARMOR
default DEFAULT_SECURITY_DAC
help
@@ -163,6 +165,9 @@ choice
config DEFAULT_SECURITY_TOMOYO
bool "TOMOYO" if SECURITY_TOMOYO=y
+ config DEFAULT_SECURITY_APPARMOR
+ bool "AppArmor" if SECURITY_APPARMOR=y
+
config DEFAULT_SECURITY_DAC
bool "Unix Discretionary Access Controls"
@@ -173,6 +178,7 @@ config DEFAULT_SECURITY
default "selinux" if DEFAULT_SECURITY_SELINUX
default "smack" if DEFAULT_SECURITY_SMACK
default "tomoyo" if DEFAULT_SECURITY_TOMOYO
+ default "apparmor" if DEFAULT_SECURITY_APPARMOR
default "" if DEFAULT_SECURITY_DAC
endmenu
diff --git a/security/Makefile b/security/Makefile
index da20a193c8d..8bb0fe9e1ca 100644
--- a/security/Makefile
+++ b/security/Makefile
@@ -6,6 +6,7 @@ obj-$(CONFIG_KEYS) += keys/
subdir-$(CONFIG_SECURITY_SELINUX) += selinux
subdir-$(CONFIG_SECURITY_SMACK) += smack
subdir-$(CONFIG_SECURITY_TOMOYO) += tomoyo
+subdir-$(CONFIG_SECURITY_APPARMOR) += apparmor
# always enable default capabilities
obj-y += commoncap.o
@@ -19,6 +20,7 @@ obj-$(CONFIG_SECURITY_SELINUX) += selinux/built-in.o
obj-$(CONFIG_SECURITY_SMACK) += smack/built-in.o
obj-$(CONFIG_AUDIT) += lsm_audit.o
obj-$(CONFIG_SECURITY_TOMOYO) += tomoyo/built-in.o
+obj-$(CONFIG_SECURITY_APPARMOR) += apparmor/built-in.o
obj-$(CONFIG_CGROUP_DEVICE) += device_cgroup.o
# Object integrity file lists
diff --git a/security/apparmor/.gitignore b/security/apparmor/.gitignore
new file mode 100644
index 00000000000..0a0a99f3b08
--- /dev/null
+++ b/security/apparmor/.gitignore
@@ -0,0 +1,5 @@
+#
+# Generated include files
+#
+af_names.h
+capability_names.h
diff --git a/security/apparmor/Kconfig b/security/apparmor/Kconfig
new file mode 100644
index 00000000000..9b9013b2e32
--- /dev/null
+++ b/security/apparmor/Kconfig
@@ -0,0 +1,31 @@
+config SECURITY_APPARMOR
+ bool "AppArmor support"
+ depends on SECURITY && NET
+ select AUDIT
+ select SECURITY_PATH
+ select SECURITYFS
+ select SECURITY_NETWORK
+ default n
+ help
+ This enables the AppArmor security module.
+ Required userspace tools (if they are not included in your
+ distribution) and further information may be found at
+ http://apparmor.wiki.kernel.org
+
+ If you are unsure how to answer this question, answer N.
+
+config SECURITY_APPARMOR_BOOTPARAM_VALUE
+ int "AppArmor boot parameter default value"
+ depends on SECURITY_APPARMOR
+ range 0 1
+ default 1
+ help
+ This option sets the default value for the kernel parameter
+ 'apparmor', which allows AppArmor to be enabled or disabled
+ at boot. If this option is set to 0 (zero), the AppArmor
+ kernel parameter will default to 0, disabling AppArmor at
+ boot. If this option is set to 1 (one), the AppArmor
+ kernel parameter will default to 1, enabling AppArmor at
+ boot.
+
+ If you are unsure how to answer this question, answer 1.
diff --git a/security/apparmor/Makefile b/security/apparmor/Makefile
new file mode 100644
index 00000000000..f204869399e
--- /dev/null
+++ b/security/apparmor/Makefile
@@ -0,0 +1,24 @@
+# Makefile for AppArmor Linux Security Module
+#
+obj-$(CONFIG_SECURITY_APPARMOR) += apparmor.o
+
+apparmor-y := apparmorfs.o audit.o capability.o context.o ipc.o lib.o match.o \
+ path.o domain.o policy.o policy_unpack.o procattr.o lsm.o \
+ resource.o sid.o file.o
+
+clean-files: capability_names.h af_names.h
+
+quiet_cmd_make-caps = GEN $@
+cmd_make-caps = echo "static const char *capability_names[] = {" > $@ ; sed -n -e "/CAP_FS_MASK/d" -e "s/^\#define[ \\t]\\+CAP_\\([A-Z0-9_]\\+\\)[ \\t]\\+\\([0-9]\\+\\)\$$/[\\2] = \"\\1\",/p" $< | tr A-Z a-z >> $@ ; echo "};" >> $@
+
+quiet_cmd_make-rlim = GEN $@
+cmd_make-rlim = echo "static const char *rlim_names[] = {" > $@ ; sed -n --e "/AF_MAX/d" -e "s/^\# \\?define[ \\t]\\+RLIMIT_\\([A-Z0-9_]\\+\\)[ \\t]\\+\\([0-9]\\+\\)\\(.*\\)\$$/[\\2] = \"\\1\",/p" $< | tr A-Z a-z >> $@ ; echo "};" >> $@ ; echo "static const int rlim_map[] = {" >> $@ ; sed -n -e "/AF_MAX/d" -e "s/^\# \\?define[ \\t]\\+\\(RLIMIT_[A-Z0-9_]\\+\\)[ \\t]\\+\\([0-9]\\+\\)\\(.*\\)\$$/\\1,/p" $< >> $@ ; echo "};" >> $@
+
+$(obj)/capability.o : $(obj)/capability_names.h
+$(obj)/resource.o : $(obj)/rlim_names.h
+$(obj)/capability_names.h : $(srctree)/include/linux/capability.h
+ $(call cmd,make-caps)
+$(obj)/af_names.h : $(srctree)/include/linux/socket.h
+ $(call cmd,make-af)
+$(obj)/rlim_names.h : $(srctree)/include/asm-generic/resource.h
+ $(call cmd,make-rlim)
diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c
new file mode 100644
index 00000000000..7320331b44a
--- /dev/null
+++ b/security/apparmor/apparmorfs.c
@@ -0,0 +1,239 @@
+/*
+ * AppArmor security module
+ *
+ * This file contains AppArmor /sys/kernel/security/apparmor interface functions
+ *
+ * Copyright (C) 1998-2008 Novell/SUSE
+ * Copyright 2009-2010 Canonical Ltd.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2 of the
+ * License.
+ */
+
+#include <linux/security.h>
+#include <linux/vmalloc.h>
+#include <linux/module.h>
+#include <linux/seq_file.h>
+#include <linux/uaccess.h>
+#include <linux/namei.h>
+
+#include "include/apparmor.h"
+#include "include/apparmorfs.h"
+#include "include/audit.h"
+#include "include/context.h"
+#include "include/policy.h"
+
+/**
+ * aa_simple_write_to_buffer - common routine for getting policy from user
+ * @op: operation doing the user buffer copy
+ * @userbuf: user buffer to copy data from (NOT NULL)
+ * @alloc_size: size of user buffer
+ * @copy_size: size of data to copy from user buffer
+ * @pos: position write is at in the file (NOT NULL)
+ *
+ * Returns: kernel buffer containing copy of user buffer data or an
+ * ERR_PTR on failure.
+ */
+static char *aa_simple_write_to_buffer(int op, const char __user *userbuf,
+ size_t alloc_size, size_t copy_size,
+ loff_t *pos)
+{
+ char *data;
+
+ if (*pos != 0)
+ /* only writes from pos 0, that is complete writes */
+ return ERR_PTR(-ESPIPE);
+
+ /*
+ * Don't allow profile load/replace/remove from profiles that don't
+ * have CAP_MAC_ADMIN
+ */
+ if (!aa_may_manage_policy(op))
+ return ERR_PTR(-EACCES);
+
+ /* freed by caller to simple_write_to_buffer */
+ data = kvmalloc(alloc_size);
+ if (data == NULL)
+ return ERR_PTR(-ENOMEM);
+
+ if (copy_from_user(data, userbuf, copy_size)) {
+ kvfree(data);
+ return ERR_PTR(-EFAULT);
+ }
+
+ return data;
+}
+
+
+/* .load file hook fn to load policy */
+static ssize_t profile_load(struct file *f, const char __user *buf, size_t size,
+ loff_t *pos)
+{
+ char *data;
+ ssize_t error;
+
+ data = aa_simple_write_to_buffer(OP_PROF_LOAD, buf, size, size, pos);
+
+ error = PTR_ERR(data);
+ if (!IS_ERR(data)) {
+ error = aa_replace_profiles(data, size, PROF_ADD);
+ kvfree(data);
+ }
+
+ return error;
+}
+
+static const struct file_operations aa_fs_profile_load = {
+ .write = profile_load
+};
+
+/* .replace file hook fn to load and/or replace policy */
+static ssize_t profile_replace(struct file *f, const char __user *buf,
+ size_t size, loff_t *pos)
+{
+ char *data;
+ ssize_t error;
+
+ data = aa_simple_write_to_buffer(OP_PROF_REPL, buf, size, size, pos);
+ error = PTR_ERR(data);
+ if (!IS_ERR(data)) {
+ error = aa_replace_profiles(data, size, PROF_REPLACE);
+ kvfree(data);
+ }
+
+ return error;
+}
+
+static const struct file_operations aa_fs_profile_replace = {
+ .write = profile_replace
+};
+
+/* .remove file hook fn to remove loaded policy */
+static ssize_t profile_remove(struct file *f, const char __user *buf,
+ size_t size, loff_t *pos)
+{
+ char *data;
+ ssize_t error;
+
+ /*
+ * aa_remove_profile needs a null terminated string so 1 extra
+ * byte is allocated and the copied data is null terminated.
+ */
+ data = aa_simple_write_to_buffer(OP_PROF_RM, buf, size + 1, size, pos);
+
+ error = PTR_ERR(data);
+ if (!IS_ERR(data)) {
+ data[size] = 0;
+ error = aa_remove_profiles(data, size);
+ kvfree(data);
+ }
+
+ return error;
+}
+
+static const struct file_operations aa_fs_profile_remove = {
+ .write = profile_remove
+};
+
+/** Base file system setup **/
+
+static struct dentry *aa_fs_dentry __initdata;
+
+static void __init aafs_remove(const char *name)
+{
+ struct dentry *dentry;
+
+ dentry = lookup_one_len(name, aa_fs_dentry, strlen(name));
+ if (!IS_ERR(dentry)) {
+ securityfs_remove(dentry);
+ dput(dentry);
+ }
+}
+
+/**
+ * aafs_create - create an entry in the apparmor filesystem
+ * @name: name of the entry (NOT NULL)
+ * @mask: file permission mask of the file
+ * @fops: file operations for the file (NOT NULL)
+ *
+ * Used aafs_remove to remove entries created with this fn.
+ */
+static int __init aafs_create(const char *name, int mask,
+ const struct file_operations *fops)
+{
+ struct dentry *dentry;
+
+ dentry = securityfs_create_file(name, S_IFREG | mask, aa_fs_dentry,
+ NULL, fops);
+
+ return IS_ERR(dentry) ? PTR_ERR(dentry) : 0;
+}
+
+/**
+ * aa_destroy_aafs - cleanup and free aafs
+ *
+ * releases dentries allocated by aa_create_aafs
+ */
+void __init aa_destroy_aafs(void)
+{
+ if (aa_fs_dentry) {
+ aafs_remove(".remove");
+ aafs_remove(".replace");
+ aafs_remove(".load");
+
+ securityfs_remove(aa_fs_dentry);
+ aa_fs_dentry = NULL;
+ }
+}
+
+/**
+ * aa_create_aafs - create the apparmor security filesystem
+ *
+ * dentries created here are released by aa_destroy_aafs
+ *
+ * Returns: error on failure
+ */
+int __init aa_create_aafs(void)
+{
+ int error;
+
+ if (!apparmor_initialized)
+ return 0;
+
+ if (aa_fs_dentry) {
+ AA_ERROR("%s: AppArmor securityfs already exists\n", __func__);
+ return -EEXIST;
+ }
+
+ aa_fs_dentry = securityfs_create_dir("apparmor", NULL);
+ if (IS_ERR(aa_fs_dentry)) {
+ error = PTR_ERR(aa_fs_dentry);
+ aa_fs_dentry = NULL;
+ goto error;
+ }
+
+ error = aafs_create(".load", 0640, &aa_fs_profile_load);
+ if (error)
+ goto error;
+ error = aafs_create(".replace", 0640, &aa_fs_profile_replace);
+ if (error)
+ goto error;
+ error = aafs_create(".remove", 0640, &aa_fs_profile_remove);
+ if (error)
+ goto error;
+
+ /* TODO: add support for apparmorfs_null and apparmorfs_mnt */
+
+ /* Report that AppArmor fs is enabled */
+ aa_info_message("AppArmor Filesystem Enabled");
+ return 0;
+
+error:
+ aa_destroy_aafs();
+ AA_ERROR("Error creating AppArmor securityfs\n");
+ return error;
+}
+
+fs_initcall(aa_create_aafs);
diff --git a/security/apparmor/audit.c b/security/apparmor/audit.c
new file mode 100644
index 00000000000..96502b22b26
--- /dev/null
+++ b/security/apparmor/audit.c
@@ -0,0 +1,215 @@
+/*
+ * AppArmor security module
+ *
+ * This file contains AppArmor auditing functions
+ *
+ * Copyright (C) 1998-2008 Novell/SUSE
+ * Copyright 2009-2010 Canonical Ltd.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2 of the
+ * License.
+ */
+
+#include <linux/audit.h>
+#include <linux/socket.h>
+
+#include "include/apparmor.h"
+#include "include/audit.h"
+#include "include/policy.h"
+
+const char *op_table[] = {
+ "null",
+
+ "sysctl",
+ "capable",
+
+ "unlink",
+ "mkdir",
+ "rmdir",
+ "mknod",
+ "truncate",
+ "link",
+ "symlink",
+ "rename_src",
+ "rename_dest",
+ "chmod",
+ "chown",
+ "getattr",
+ "open",
+
+ "file_perm",
+ "file_lock",
+ "file_mmap",
+ "file_mprotect",
+
+ "create",
+ "post_create",
+ "bind",
+ "connect",
+ "listen",
+ "accept",
+ "sendmsg",
+ "recvmsg",
+ "getsockname",
+ "getpeername",
+ "getsockopt",
+ "setsockopt",
+ "socket_shutdown",
+
+ "ptrace",
+
+ "exec",
+ "change_hat",
+ "change_profile",
+ "change_onexec",
+
+ "setprocattr",
+ "setrlimit",
+
+ "profile_replace",
+ "profile_load",
+ "profile_remove"
+};
+
+const char *audit_mode_names[] = {
+ "normal",
+ "quiet_denied",
+ "quiet",
+ "noquiet",
+ "all"
+};
+
+static char *aa_audit_type[] = {
+ "AUDIT",
+ "ALLOWED",
+ "DENIED",
+ "HINT",
+ "STATUS",
+ "ERROR",
+ "KILLED"
+};
+
+/*
+ * Currently AppArmor auditing is fed straight into the audit framework.
+ *
+ * TODO:
+ * netlink interface for complain mode
+ * user auditing, - send user auditing to netlink interface
+ * system control of whether user audit messages go to system log
+ */
+
+/**
+ * audit_base - core AppArmor function.
+ * @ab: audit buffer to fill (NOT NULL)
+ * @ca: audit structure containing data to audit (NOT NULL)
+ *
+ * Record common AppArmor audit data from @sa
+ */
+static void audit_pre(struct audit_buffer *ab, void *ca)
+{
+ struct common_audit_data *sa = ca;
+ struct task_struct *tsk = sa->tsk ? sa->tsk : current;
+
+ if (aa_g_audit_header) {
+ audit_log_format(ab, "apparmor=");
+ audit_log_string(ab, aa_audit_type[sa->aad.type]);
+ }
+
+ if (sa->aad.op) {
+ audit_log_format(ab, " operation=");
+ audit_log_string(ab, op_table[sa->aad.op]);
+ }
+
+ if (sa->aad.info) {
+ audit_log_format(ab, " info=");
+ audit_log_string(ab, sa->aad.info);
+ if (sa->aad.error)
+ audit_log_format(ab, " error=%d", sa->aad.error);
+ }
+
+ if (sa->aad.profile) {
+ struct aa_profile *profile = sa->aad.profile;
+ pid_t pid;
+ rcu_read_lock();
+ pid = tsk->real_parent->pid;
+ rcu_read_unlock();
+ audit_log_format(ab, " parent=%d", pid);
+ if (profile->ns != root_ns) {
+ audit_log_format(ab, " namespace=");
+ audit_log_untrustedstring(ab, profile->ns->base.hname);
+ }
+ audit_log_format(ab, " profile=");
+ audit_log_untrustedstring(ab, profile->base.hname);
+ }
+
+ if (sa->aad.name) {
+ audit_log_format(ab, " name=");
+ audit_log_untrustedstring(ab, sa->aad.name);
+ }
+}
+
+/**
+ * aa_audit_msg - Log a message to the audit subsystem
+ * @sa: audit event structure (NOT NULL)
+ * @cb: optional callback fn for type specific fields (MAYBE NULL)
+ */
+void aa_audit_msg(int type, struct common_audit_data *sa,
+ void (*cb) (struct audit_buffer *, void *))
+{
+ sa->aad.type = type;
+ sa->lsm_pre_audit = audit_pre;
+ sa->lsm_post_audit = cb;
+ common_lsm_audit(sa);
+}
+
+/**
+ * aa_audit - Log a profile based audit event to the audit subsystem
+ * @type: audit type for the message
+ * @profile: profile to check against (NOT NULL)
+ * @gfp: allocation flags to use
+ * @sa: audit event (NOT NULL)
+ * @cb: optional callback fn for type specific fields (MAYBE NULL)
+ *
+ * Handle default message switching based off of audit mode flags
+ *
+ * Returns: error on failure
+ */
+int aa_audit(int type, struct aa_profile *profile, gfp_t gfp,
+ struct common_audit_data *sa,
+ void (*cb) (struct audit_buffer *, void *))
+{
+ BUG_ON(!profile);
+
+ if (type == AUDIT_APPARMOR_AUTO) {
+ if (likely(!sa->aad.error)) {
+ if (AUDIT_MODE(profile) != AUDIT_ALL)
+ return 0;
+ type = AUDIT_APPARMOR_AUDIT;
+ } else if (COMPLAIN_MODE(profile))
+ type = AUDIT_APPARMOR_ALLOWED;
+ else
+ type = AUDIT_APPARMOR_DENIED;
+ }
+ if (AUDIT_MODE(profile) == AUDIT_QUIET ||
+ (type == AUDIT_APPARMOR_DENIED &&
+ AUDIT_MODE(profile) == AUDIT_QUIET))
+ return sa->aad.error;
+
+ if (KILL_MODE(profile) && type == AUDIT_APPARMOR_DENIED)
+ type = AUDIT_APPARMOR_KILL;
+
+ if (!unconfined(profile))
+ sa->aad.profile = profile;
+
+ aa_audit_msg(type, sa, cb);
+
+ if (sa->aad.type == AUDIT_APPARMOR_KILL)
+ (void)send_sig_info(SIGKILL, NULL, sa->tsk ? sa->tsk : current);
+
+ if (sa->aad.type == AUDIT_APPARMOR_ALLOWED)
+ return complain_error(sa->aad.error);
+
+ return sa->aad.error;
+}
diff --git a/security/apparmor/capability.c b/security/apparmor/capability.c
new file mode 100644
index 00000000000..9982c48def4
--- /dev/null
+++ b/security/apparmor/capability.c
@@ -0,0 +1,141 @@
+/*
+ * AppArmor security module
+ *
+ * This file contains AppArmor capability mediation functions
+ *
+ * Copyright (C) 1998-2008 Novell/SUSE
+ * Copyright 2009-2010 Canonical Ltd.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2 of the
+ * License.
+ */
+
+#include <linux/capability.h>
+#include <linux/errno.h>
+#include <linux/gfp.h>
+
+#include "include/apparmor.h"
+#include "include/capability.h"
+#include "include/context.h"
+#include "include/policy.h"
+#include "include/audit.h"
+
+/*
+ * Table of capability names: we generate it from capabilities.h.
+ */
+#include "capability_names.h"
+
+struct audit_cache {
+ struct aa_profile *profile;
+ kernel_cap_t caps;
+};
+
+static DEFINE_PER_CPU(struct audit_cache, audit_cache);
+
+/**
+ * audit_cb - call back for capability components of audit struct
+ * @ab - audit buffer (NOT NULL)
+ * @va - audit struct to audit data from (NOT NULL)
+ */
+static void audit_cb(struct audit_buffer *ab, void *va)
+{
+ struct common_audit_data *sa = va;
+ audit_log_format(ab, " capname=");
+ audit_log_untrustedstring(ab, capability_names[sa->u.cap]);
+}
+
+/**
+ * audit_caps - audit a capability
+ * @profile: profile confining task (NOT NULL)
+ * @task: task capability test was performed against (NOT NULL)
+ * @cap: capability tested
+ * @error: error code returned by test
+ *
+ * Do auditing of capability and handle, audit/complain/kill modes switching
+ * and duplicate message elimination.
+ *
+ * Returns: 0 or sa->error on success, error code on failure
+ */
+static int audit_caps(struct aa_profile *profile, struct task_struct *task,
+ int cap, int error)
+{
+ struct audit_cache *ent;
+ int type = AUDIT_APPARMOR_AUTO;
+ struct common_audit_data sa;
+ COMMON_AUDIT_DATA_INIT(&sa, CAP);
+ sa.tsk = task;
+ sa.u.cap = cap;
+ sa.aad.op = OP_CAPABLE;
+ sa.aad.error = error;
+
+ if (likely(!error)) {
+ /* test if auditing is being forced */
+ if (likely((AUDIT_MODE(profile) != AUDIT_ALL) &&
+ !cap_raised(profile->caps.audit, cap)))
+ return 0;
+ type = AUDIT_APPARMOR_AUDIT;
+ } else if (KILL_MODE(profile) ||
+ cap_raised(profile->caps.kill, cap)) {
+ type = AUDIT_APPARMOR_KILL;
+ } else if (cap_raised(profile->caps.quiet, cap) &&
+ AUDIT_MODE(profile) != AUDIT_NOQUIET &&
+ AUDIT_MODE(profile) != AUDIT_ALL) {
+ /* quiet auditing */
+ return error;
+ }
+
+ /* Do simple duplicate message elimination */
+ ent = &get_cpu_var(audit_cache);
+ if (profile == ent->profile && cap_raised(ent->caps, cap)) {
+ put_cpu_var(audit_cache);
+ if (COMPLAIN_MODE(profile))
+ return complain_error(error);
+ return error;
+ } else {
+ aa_put_profile(ent->profile);
+ ent->profile = aa_get_profile(profile);
+ cap_raise(ent->caps, cap);
+ }
+ put_cpu_var(audit_cache);
+
+ return aa_audit(type, profile, GFP_ATOMIC, &sa, audit_cb);
+}
+
+/**
+ * profile_capable - test if profile allows use of capability @cap
+ * @profile: profile being enforced (NOT NULL, NOT unconfined)
+ * @cap: capability to test if allowed
+ *
+ * Returns: 0 if allowed else -EPERM
+ */
+static int profile_capable(struct aa_profile *profile, int cap)
+{
+ return cap_raised(profile->caps.allow, cap) ? 0 : -EPERM;
+}
+
+/**
+ * aa_capable - test permission to use capability
+ * @task: task doing capability test against (NOT NULL)
+ * @profile: profile confining @task (NOT NULL)
+ * @cap: capability to be tested
+ * @audit: whether an audit record should be generated
+ *
+ * Look up capability in profile capability set.
+ *
+ * Returns: 0 on success, or else an error code.
+ */
+int aa_capable(struct task_struct *task, struct aa_profile *profile, int cap,
+ int audit)
+{
+ int error = profile_capable(profile, cap);
+
+ if (!audit) {
+ if (COMPLAIN_MODE(profile))
+ return complain_error(error);
+ return error;
+ }
+
+ return audit_caps(profile, task, cap, error);
+}
diff --git a/security/apparmor/context.c b/security/apparmor/context.c
new file mode 100644
index 00000000000..8a9b5027c81
--- /dev/null
+++ b/security/apparmor/context.c
@@ -0,0 +1,216 @@
+/*
+ * AppArmor security module
+ *
+ * This file contains AppArmor functions used to manipulate object security
+ * contexts.
+ *
+ * Copyright (C) 1998-2008 Novell/SUSE
+ * Copyright 2009-2010 Canonical Ltd.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2 of the
+ * License.
+ *
+ *
+ * AppArmor sets confinement on every task, via the the aa_task_cxt and
+ * the aa_task_cxt.profile, both of which are required and are not allowed
+ * to be NULL. The aa_task_cxt is not reference counted and is unique
+ * to each cred (which is reference count). The profile pointed to by
+ * the task_cxt is reference counted.
+ *
+ * TODO
+ * If a task uses change_hat it currently does not return to the old
+ * cred or task context but instead creates a new one. Ideally the task
+ * should return to the previous cred if it has not been modified.
+ *
+ */
+
+#include "include/context.h"
+#include "include/policy.h"
+
+/**
+ * aa_alloc_task_context - allocate a new task_cxt
+ * @flags: gfp flags for allocation
+ *
+ * Returns: allocated buffer or NULL on failure
+ */
+struct aa_task_cxt *aa_alloc_task_context(gfp_t flags)
+{
+ return kzalloc(sizeof(struct aa_task_cxt), flags);
+}
+
+/**
+ * aa_free_task_context - free a task_cxt
+ * @cxt: task_cxt to free (MAYBE NULL)
+ */
+void aa_free_task_context(struct aa_task_cxt *cxt)
+{
+ if (cxt) {
+ aa_put_profile(cxt->profile);
+ aa_put_profile(cxt->previous);
+ aa_put_profile(cxt->onexec);
+
+ kzfree(cxt);
+ }
+}
+
+/**
+ * aa_dup_task_context - duplicate a task context, incrementing reference counts
+ * @new: a blank task context (NOT NULL)
+ * @old: the task context to copy (NOT NULL)
+ */
+void aa_dup_task_context(struct aa_task_cxt *new, const struct aa_task_cxt *old)
+{
+ *new = *old;
+ aa_get_profile(new->profile);
+ aa_get_profile(new->previous);
+ aa_get_profile(new->onexec);
+}
+
+/**
+ * aa_replace_current_profile - replace the current tasks profiles
+ * @profile: new profile (NOT NULL)
+ *
+ * Returns: 0 or error on failure
+ */
+int aa_replace_current_profile(struct aa_profile *profile)
+{
+ struct aa_task_cxt *cxt = current_cred()->security;
+ struct cred *new;
+ BUG_ON(!profile);
+
+ if (cxt->profile == profile)
+ return 0;
+
+ new = prepare_creds();
+ if (!new)
+ return -ENOMEM;
+
+ cxt = new->security;
+ if (unconfined(profile) || (cxt->profile->ns != profile->ns)) {
+ /* if switching to unconfined or a different profile namespace
+ * clear out context state
+ */
+ aa_put_profile(cxt->previous);
+ aa_put_profile(cxt->onexec);
+ cxt->previous = NULL;
+ cxt->onexec = NULL;
+ cxt->token = 0;
+ }
+ /* be careful switching cxt->profile, when racing replacement it
+ * is possible that cxt->profile->replacedby is the reference keeping
+ * @profile valid, so make sure to get its reference before dropping
+ * the reference on cxt->profile */
+ aa_get_profile(profile);
+ aa_put_profile(cxt->profile);
+ cxt->profile = profile;
+
+ commit_creds(new);
+ return 0;
+}
+
+/**
+ * aa_set_current_onexec - set the tasks change_profile to happen onexec
+ * @profile: system profile to set at exec (MAYBE NULL to clear value)
+ *
+ * Returns: 0 or error on failure
+ */
+int aa_set_current_onexec(struct aa_profile *profile)
+{
+ struct aa_task_cxt *cxt;
+ struct cred *new = prepare_creds();
+ if (!new)
+ return -ENOMEM;
+
+ cxt = new->security;
+ aa_get_profile(profile);
+ aa_put_profile(cxt->onexec);
+ cxt->onexec = profile;
+
+ commit_creds(new);
+ return 0;
+}
+
+/**
+ * aa_set_current_hat - set the current tasks hat
+ * @profile: profile to set as the current hat (NOT NULL)
+ * @token: token value that must be specified to change from the hat
+ *
+ * Do switch of tasks hat. If the task is currently in a hat
+ * validate the token to match.
+ *
+ * Returns: 0 or error on failure
+ */
+int aa_set_current_hat(struct aa_profile *profile, u64 token)
+{
+ struct aa_task_cxt *cxt;
+ struct cred *new = prepare_creds();
+ if (!new)
+ return -ENOMEM;
+ BUG_ON(!profile);
+
+ cxt = new->security;
+ if (!cxt->previous) {
+ /* transfer refcount */
+ cxt->previous = cxt->profile;
+ cxt->token = token;
+ } else if (cxt->token == token) {
+ aa_put_profile(cxt->profile);
+ } else {
+ /* previous_profile && cxt->token != token */
+ abort_creds(new);
+ return -EACCES;
+ }
+ cxt->profile = aa_get_profile(aa_newest_version(profile));
+ /* clear exec on switching context */
+ aa_put_profile(cxt->onexec);
+ cxt->onexec = NULL;
+
+ commit_creds(new);
+ return 0;
+}
+
+/**
+ * aa_restore_previous_profile - exit from hat context restoring the profile
+ * @token: the token that must be matched to exit hat context
+ *
+ * Attempt to return out of a hat to the previous profile. The token
+ * must match the stored token value.
+ *
+ * Returns: 0 or error of failure
+ */
+int aa_restore_previous_profile(u64 token)
+{
+ struct aa_task_cxt *cxt;
+ struct cred *new = prepare_creds();
+ if (!new)
+ return -ENOMEM;
+
+ cxt = new->security;
+ if (cxt->token != token) {
+ abort_creds(new);
+ return -EACCES;
+ }
+ /* ignore restores when there is no saved profile */
+ if (!cxt->previous) {
+ abort_creds(new);
+ return 0;
+ }
+
+ aa_put_profile(cxt->profile);
+ cxt->profile = aa_newest_version(cxt->previous);
+ BUG_ON(!cxt->profile);
+ if (unlikely(cxt->profile != cxt->previous)) {
+ aa_get_profile(cxt->profile);
+ aa_put_profile(cxt->previous);
+ }
+ /* clear exec && prev information when restoring to previous context */
+ cxt->previous = NULL;
+ cxt->token = 0;
+ aa_put_profile(cxt->onexec);
+ cxt->onexec = NULL;
+
+ commit_creds(new);
+ return 0;
+}
diff --git a/security/apparmor/domain.c b/security/apparmor/domain.c
new file mode 100644
index 00000000000..c825c6e0b63
--- /dev/null
+++ b/security/apparmor/domain.c
@@ -0,0 +1,823 @@
+/*
+ * AppArmor security module
+ *
+ * This file contains AppArmor policy attachment and domain transitions
+ *
+ * Copyright (C) 2002-2008 Novell/SUSE
+ * Copyright 2009-2010 Canonical Ltd.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2 of the
+ * License.
+ */
+
+#include <linux/errno.h>
+#include <linux/fdtable.h>
+#include <linux/file.h>
+#include <linux/mount.h>
+#include <linux/syscalls.h>
+#include <linux/tracehook.h>
+#include <linux/personality.h>
+
+#include "include/audit.h"
+#include "include/apparmorfs.h"
+#include "include/context.h"
+#include "include/domain.h"
+#include "include/file.h"
+#include "include/ipc.h"
+#include "include/match.h"
+#include "include/path.h"
+#include "include/policy.h"
+
+/**
+ * aa_free_domain_entries - free entries in a domain table
+ * @domain: the domain table to free (MAYBE NULL)
+ */
+void aa_free_domain_entries(struct aa_domain *domain)
+{
+ int i;
+ if (domain) {
+ if (!domain->table)
+ return;
+
+ for (i = 0; i < domain->size; i++)
+ kzfree(domain->table[i]);
+ kzfree(domain->table);
+ domain->table = NULL;
+ }
+}
+
+/**
+ * may_change_ptraced_domain - check if can change profile on ptraced task
+ * @task: task we want to change profile of (NOT NULL)
+ * @to_profile: profile to change to (NOT NULL)
+ *
+ * Check if the task is ptraced and if so if the tracing task is allowed
+ * to trace the new domain
+ *
+ * Returns: %0 or error if change not allowed
+ */
+static int may_change_ptraced_domain(struct task_struct *task,
+ struct aa_profile *to_profile)
+{
+ struct task_struct *tracer;
+ const struct cred *cred = NULL;
+ struct aa_profile *tracerp = NULL;
+ int error = 0;
+
+ rcu_read_lock();
+ tracer = tracehook_tracer_task(task);
+ if (tracer) {
+ /* released below */
+ cred = get_task_cred(tracer);
+ tracerp = aa_cred_profile(cred);
+ }
+ rcu_read_unlock();
+
+ /* not ptraced */
+ if (!tracer || unconfined(tracerp))
+ goto out;
+
+ error = aa_may_ptrace(tracer, tracerp, to_profile, PTRACE_MODE_ATTACH);
+
+out:
+ if (cred)
+ put_cred(cred);
+
+ return error;
+}
+
+/**
+ * change_profile_perms - find permissions for change_profile
+ * @profile: the current profile (NOT NULL)
+ * @ns: the namespace being switched to (NOT NULL)
+ * @name: the name of the profile to change to (NOT NULL)
+ * @request: requested perms
+ * @start: state to start matching in
+ *
+ * Returns: permission set
+ */
+static struct file_perms change_profile_perms(struct aa_profile *profile,
+ struct aa_namespace *ns,
+ const char *name, u32 request,
+ unsigned int start)
+{
+ struct file_perms perms;
+ struct path_cond cond = { };
+ unsigned int state;
+
+ if (unconfined(profile)) {
+ perms.allow = AA_MAY_CHANGE_PROFILE | AA_MAY_ONEXEC;
+ perms.audit = perms.quiet = perms.kill = 0;
+ return perms;
+ } else if (!profile->file.dfa) {
+ return nullperms;
+ } else if ((ns == profile->ns)) {
+ /* try matching against rules with out namespace prepended */
+ aa_str_perms(profile->file.dfa, start, name, &cond, &perms);
+ if (COMBINED_PERM_MASK(perms) & request)
+ return perms;
+ }
+
+ /* try matching with namespace name and then profile */
+ state = aa_dfa_match(profile->file.dfa, start, ns->base.name);
+ state = aa_dfa_match_len(profile->file.dfa, state, ":", 1);
+ aa_str_perms(profile->file.dfa, state, name, &cond, &perms);
+
+ return perms;
+}
+
+/**
+ * __attach_match_ - find an attachment match
+ * @name - to match against (NOT NULL)
+ * @head - profile list to walk (NOT NULL)
+ *
+ * Do a linear search on the profiles in the list. There is a matching
+ * preference where an exact match is preferred over a name which uses
+ * expressions to match, and matching expressions with the greatest
+ * xmatch_len are preferred.
+ *
+ * Requires: @head not be shared or have appropriate locks held
+ *
+ * Returns: profile or NULL if no match found
+ */
+static struct aa_profile *__attach_match(const char *name,
+ struct list_head *head)
+{
+ int len = 0;
+ struct aa_profile *profile, *candidate = NULL;
+
+ list_for_each_entry(profile, head, base.list) {
+ if (profile->flags & PFLAG_NULL)
+ continue;
+ if (profile->xmatch && profile->xmatch_len > len) {
+ unsigned int state = aa_dfa_match(profile->xmatch,
+ DFA_START, name);
+ u32 perm = dfa_user_allow(profile->xmatch, state);
+ /* any accepting state means a valid match. */
+ if (perm & MAY_EXEC) {
+ candidate = profile;
+ len = profile->xmatch_len;
+ }
+ } else if (!strcmp(profile->base.name, name))
+ /* exact non-re match, no more searching required */
+ return profile;
+ }
+
+ return candidate;
+}
+
+/**
+ * find_attach - do attachment search for unconfined processes
+ * @ns: the current namespace (NOT NULL)
+ * @list: list to search (NOT NULL)
+ * @name: the executable name to match against (NOT NULL)
+ *
+ * Returns: profile or NULL if no match found
+ */
+static struct aa_profile *find_attach(struct aa_namespace *ns,
+ struct list_head *list, const char *name)
+{
+ struct aa_profile *profile;
+
+ read_lock(&ns->lock);
+ profile = aa_get_profile(__attach_match(name, list));
+ read_unlock(&ns->lock);
+
+ return profile;
+}
+
+/**
+ * separate_fqname - separate the namespace and profile names
+ * @fqname: the fqname name to split (NOT NULL)
+ * @ns_name: the namespace name if it exists (NOT NULL)
+ *
+ * This is the xtable equivalent routine of aa_split_fqname. It finds the
+ * split in an xtable fqname which contains an embedded \0 instead of a :
+ * if a namespace is specified. This is done so the xtable is constant and
+ * isn't re-split on every lookup.
+ *
+ * Either the profile or namespace name may be optional but if the namespace
+ * is specified the profile name termination must be present. This results
+ * in the following possible encodings:
+ * profile_name\0
+ * :ns_name\0profile_name\0
+ * :ns_name\0\0
+ *
+ * NOTE: the xtable fqname is pre-validated at load time in unpack_trans_table
+ *
+ * Returns: profile name if it is specified else NULL
+ */
+static const char *separate_fqname(const char *fqname, const char **ns_name)
+{
+ const char *name;
+
+ if (fqname[0] == ':') {
+ /* In this case there is guaranteed to be two \0 terminators
+ * in the string. They are verified at load time by
+ * by unpack_trans_table
+ */
+ *ns_name = fqname + 1; /* skip : */
+ name = *ns_name + strlen(*ns_name) + 1;
+ if (!*name)
+ name = NULL;
+ } else {
+ *ns_name = NULL;
+ name = fqname;
+ }
+
+ return name;
+}
+
+static const char *next_name(int xtype, const char *name)
+{
+ return NULL;
+}
+
+/**
+ * x_table_lookup - lookup an x transition name via transition table
+ * @profile: current profile (NOT NULL)
+ * @xindex: index into x transition table
+ *
+ * Returns: refcounted profile, or NULL on failure (MAYBE NULL)
+ */
+static struct aa_profile *x_table_lookup(struct aa_profile *profile, u32 xindex)
+{
+ struct aa_profile *new_profile = NULL;
+ struct aa_namespace *ns = profile->ns;
+ u32 xtype = xindex & AA_X_TYPE_MASK;
+ int index = xindex & AA_X_INDEX_MASK;
+ const char *name;
+
+ /* index is guaranteed to be in range, validated at load time */
+ for (name = profile->file.trans.table[index]; !new_profile && name;
+ name = next_name(xtype, name)) {
+ struct aa_namespace *new_ns;
+ const char *xname = NULL;
+
+ new_ns = NULL;
+ if (xindex & AA_X_CHILD) {
+ /* release by caller */
+ new_profile = aa_find_child(profile, name);
+ continue;
+ } else if (*name == ':') {
+ /* switching namespace */
+ const char *ns_name;
+ xname = name = separate_fqname(name, &ns_name);
+ if (!xname)
+ /* no name so use profile name */
+ xname = profile->base.hname;
+ if (*ns_name == '@') {
+ /* TODO: variable support */
+ ;
+ }
+ /* released below */
+ new_ns = aa_find_namespace(ns, ns_name);
+ if (!new_ns)
+ continue;
+ } else if (*name == '@') {
+ /* TODO: variable support */
+ continue;
+ } else {
+ /* basic namespace lookup */
+ xname = name;
+ }
+
+ /* released by caller */
+ new_profile = aa_lookup_profile(new_ns ? new_ns : ns, xname);
+ aa_put_namespace(new_ns);
+ }
+
+ /* released by caller */
+ return new_profile;
+}
+
+/**
+ * x_to_profile - get target profile for a given xindex
+ * @profile: current profile (NOT NULL)
+ * @name: name to lookup (NOT NULL)
+ * @xindex: index into x transition table
+ *
+ * find profile for a transition index
+ *
+ * Returns: refcounted profile or NULL if not found available
+ */
+static struct aa_profile *x_to_profile(struct aa_profile *profile,
+ const char *name, u32 xindex)
+{
+ struct aa_profile *new_profile = NULL;
+ struct aa_namespace *ns = profile->ns;
+ u32 xtype = xindex & AA_X_TYPE_MASK;
+
+ switch (xtype) {
+ case AA_X_NONE:
+ /* fail exec unless ix || ux fallback - handled by caller */
+ return NULL;
+ case AA_X_NAME:
+ if (xindex & AA_X_CHILD)
+ /* released by caller */
+ new_profile = find_attach(ns, &profile->base.profiles,
+ name);
+ else
+ /* released by caller */
+ new_profile = find_attach(ns, &ns->base.profiles,
+ name);
+ break;
+ case AA_X_TABLE:
+ /* released by caller */
+ new_profile = x_table_lookup(profile, xindex);
+ break;
+ }
+
+ /* released by caller */
+ return new_profile;
+}
+
+/**
+ * apparmor_bprm_set_creds - set the new creds on the bprm struct
+ * @bprm: binprm for the exec (NOT NULL)
+ *
+ * Returns: %0 or error on failure
+ */
+int apparmor_bprm_set_creds(struct linux_binprm *bprm)
+{
+ struct aa_task_cxt *cxt;
+ struct aa_profile *profile, *new_profile = NULL;
+ struct aa_namespace *ns;
+ char *buffer = NULL;
+ unsigned int state;
+ struct file_perms perms = {};
+ struct path_cond cond = {
+ bprm->file->f_path.dentry->d_inode->i_uid,
+ bprm->file->f_path.dentry->d_inode->i_mode
+ };
+ const char *name = NULL, *target = NULL, *info = NULL;
+ int error = cap_bprm_set_creds(bprm);
+ if (error)
+ return error;
+
+ if (bprm->cred_prepared)
+ return 0;
+
+ cxt = bprm->cred->security;
+ BUG_ON(!cxt);
+
+ profile = aa_get_profile(aa_newest_version(cxt->profile));
+ /*
+ * get the namespace from the replacement profile as replacement
+ * can change the namespace
+ */
+ ns = profile->ns;
+ state = profile->file.start;
+
+ /* buffer freed below, name is pointer into buffer */
+ error = aa_get_name(&bprm->file->f_path, profile->path_flags, &buffer,
+ &name);
+ if (error) {
+ if (profile->flags &
+ (PFLAG_IX_ON_NAME_ERROR | PFLAG_UNCONFINED))
+ error = 0;
+ info = "Exec failed name resolution";
+ name = bprm->filename;
+ goto audit;
+ }
+
+ /* Test for onexec first as onexec directives override other
+ * x transitions.
+ */
+ if (unconfined(profile)) {
+ /* unconfined task */
+ if (cxt->onexec)
+ /* change_profile on exec already been granted */
+ new_profile = aa_get_profile(cxt->onexec);
+ else
+ new_profile = find_attach(ns, &ns->base.profiles, name);
+ if (!new_profile)
+ goto cleanup;
+ goto apply;
+ }
+
+ /* find exec permissions for name */
+ state = aa_str_perms(profile->file.dfa, state, name, &cond, &perms);
+ if (cxt->onexec) {
+ struct file_perms cp;
+ info = "change_profile onexec";
+ if (!(perms.allow & AA_MAY_ONEXEC))
+ goto audit;
+
+ /* test if this exec can be paired with change_profile onexec.
+ * onexec permission is linked to exec with a standard pairing
+ * exec\0change_profile
+ */
+ state = aa_dfa_null_transition(profile->file.dfa, state);
+ cp = change_profile_perms(profile, cxt->onexec->ns, name,
+ AA_MAY_ONEXEC, state);
+
+ if (!(cp.allow & AA_MAY_ONEXEC))
+ goto audit;
+ new_profile = aa_get_profile(aa_newest_version(cxt->onexec));
+ goto apply;
+ }
+
+ if (perms.allow & MAY_EXEC) {
+ /* exec permission determine how to transition */
+ new_profile = x_to_profile(profile, name, perms.xindex);
+ if (!new_profile) {
+ if (perms.xindex & AA_X_INHERIT) {
+ /* (p|c|n)ix - don't change profile but do
+ * use the newest version, which was picked
+ * up above when getting profile
+ */
+ info = "ix fallback";
+ new_profile = aa_get_profile(profile);
+ goto x_clear;
+ } else if (perms.xindex & AA_X_UNCONFINED) {
+ new_profile = aa_get_profile(ns->unconfined);
+ info = "ux fallback";
+ } else {
+ error = -ENOENT;
+ info = "profile not found";
+ }
+ }
+ } else if (COMPLAIN_MODE(profile)) {
+ /* no exec permission - are we in learning mode */
+ new_profile = aa_new_null_profile(profile, 0);
+ if (!new_profile) {
+ error = -ENOMEM;
+ info = "could not create null profile";
+ } else {
+ error = -EACCES;
+ target = new_profile->base.hname;
+ }
+ perms.xindex |= AA_X_UNSAFE;
+ } else
+ /* fail exec */
+ error = -EACCES;
+
+ if (!new_profile)
+ goto audit;
+
+ if (bprm->unsafe & LSM_UNSAFE_SHARE) {
+ /* FIXME: currently don't mediate shared state */
+ ;
+ }
+
+ if (bprm->unsafe & (LSM_UNSAFE_PTRACE | LSM_UNSAFE_PTRACE_CAP)) {
+ error = may_change_ptraced_domain(current, new_profile);
+ if (error) {
+ aa_put_profile(new_profile);
+ goto audit;
+ }
+ }
+
+ /* Determine if secure exec is needed.
+ * Can be at this point for the following reasons:
+ * 1. unconfined switching to confined
+ * 2. confined switching to different confinement
+ * 3. confined switching to unconfined
+ *
+ * Cases 2 and 3 are marked as requiring secure exec
+ * (unless policy specified "unsafe exec")
+ *
+ * bprm->unsafe is used to cache the AA_X_UNSAFE permission
+ * to avoid having to recompute in secureexec
+ */
+ if (!(perms.xindex & AA_X_UNSAFE)) {
+ AA_DEBUG("scrubbing environment variables for %s profile=%s\n",
+ name, new_profile->base.hname);
+ bprm->unsafe |= AA_SECURE_X_NEEDED;
+ }
+apply:
+ target = new_profile->base.hname;
+ /* when transitioning profiles clear unsafe personality bits */
+ bprm->per_clear |= PER_CLEAR_ON_SETID;
+
+x_clear:
+ aa_put_profile(cxt->profile);
+ /* transfer new profile reference will be released when cxt is freed */
+ cxt->profile = new_profile;
+
+ /* clear out all temporary/transitional state from the context */
+ aa_put_profile(cxt->previous);
+ aa_put_profile(cxt->onexec);
+ cxt->previous = NULL;
+ cxt->onexec = NULL;
+ cxt->token = 0;
+
+audit:
+ error = aa_audit_file(profile, &perms, GFP_KERNEL, OP_EXEC, MAY_EXEC,
+ name, target, cond.uid, info, error);
+
+cleanup:
+ aa_put_profile(profile);
+ kfree(buffer);
+
+ return error;
+}
+
+/**
+ * apparmor_bprm_secureexec - determine if secureexec is needed
+ * @bprm: binprm for exec (NOT NULL)
+ *
+ * Returns: %1 if secureexec is needed else %0
+ */
+int apparmor_bprm_secureexec(struct linux_binprm *bprm)
+{
+ int ret = cap_bprm_secureexec(bprm);
+
+ /* the decision to use secure exec is computed in set_creds
+ * and stored in bprm->unsafe.
+ */
+ if (!ret && (bprm->unsafe & AA_SECURE_X_NEEDED))
+ ret = 1;
+
+ return ret;
+}
+
+/**
+ * apparmor_bprm_committing_creds - do task cleanup on committing new creds
+ * @bprm: binprm for the exec (NOT NULL)
+ */
+void apparmor_bprm_committing_creds(struct linux_binprm *bprm)
+{
+ struct aa_profile *profile = __aa_current_profile();
+ struct aa_task_cxt *new_cxt = bprm->cred->security;
+
+ /* bail out if unconfined or not changing profile */
+ if ((new_cxt->profile == profile) ||
+ (unconfined(new_cxt->profile)))
+ return;
+
+ current->pdeath_signal = 0;
+
+ /* reset soft limits and set hard limits for the new profile */
+ __aa_transition_rlimits(profile, new_cxt->profile);
+}
+
+/**
+ * apparmor_bprm_commited_cred - do cleanup after new creds committed
+ * @bprm: binprm for the exec (NOT NULL)
+ */
+void apparmor_bprm_committed_creds(struct linux_binprm *bprm)
+{
+ /* TODO: cleanup signals - ipc mediation */
+ return;
+}
+
+/*
+ * Functions for self directed profile change
+ */
+
+/**
+ * new_compound_name - create an hname with @n2 appended to @n1
+ * @n1: base of hname (NOT NULL)
+ * @n2: name to append (NOT NULL)
+ *
+ * Returns: new name or NULL on error
+ */
+static char *new_compound_name(const char *n1, const char *n2)
+{
+ char *name = kmalloc(strlen(n1) + strlen(n2) + 3, GFP_KERNEL);
+ if (name)
+ sprintf(name, "%s//%s", n1, n2);
+ return name;
+}
+
+/**
+ * aa_change_hat - change hat to/from subprofile
+ * @hats: vector of hat names to try changing into (MAYBE NULL if @count == 0)
+ * @count: number of hat names in @hats
+ * @token: magic value to validate the hat change
+ * @permtest: true if this is just a permission test
+ *
+ * Change to the first profile specified in @hats that exists, and store
+ * the @hat_magic in the current task context. If the count == 0 and the
+ * @token matches that stored in the current task context, return to the
+ * top level profile.
+ *
+ * Returns %0 on success, error otherwise.
+ */
+int aa_change_hat(const char *hats[], int count, u64 token, bool permtest)
+{
+ const struct cred *cred;
+ struct aa_task_cxt *cxt;
+ struct aa_profile *profile, *previous_profile, *hat = NULL;
+ char *name = NULL;
+ int i;
+ struct file_perms perms = {};
+ const char *target = NULL, *info = NULL;
+ int error = 0;
+
+ /* released below */
+ cred = get_current_cred();
+ cxt = cred->security;
+ profile = aa_cred_profile(cred);
+ previous_profile = cxt->previous;
+
+ if (unconfined(profile)) {
+ info = "unconfined";
+ error = -EPERM;
+ goto audit;
+ }
+
+ if (count) {
+ /* attempting to change into a new hat or switch to a sibling */
+ struct aa_profile *root;
+ root = PROFILE_IS_HAT(profile) ? profile->parent : profile;
+
+ /* find first matching hat */
+ for (i = 0; i < count && !hat; i++)
+ /* released below */
+ hat = aa_find_child(root, hats[i]);
+ if (!hat) {
+ if (!COMPLAIN_MODE(root) || permtest) {
+ if (list_empty(&root->base.profiles))
+ error = -ECHILD;
+ else
+ error = -ENOENT;
+ goto out;
+ }
+
+ /*
+ * In complain mode and failed to match any hats.
+ * Audit the failure is based off of the first hat
+ * supplied. This is done due how userspace
+ * interacts with change_hat.
+ *
+ * TODO: Add logging of all failed hats
+ */
+
+ /* freed below */
+ name = new_compound_name(root->base.hname, hats[0]);
+ target = name;
+ /* released below */
+ hat = aa_new_null_profile(profile, 1);
+ if (!hat) {
+ info = "failed null profile create";
+ error = -ENOMEM;
+ goto audit;
+ }
+ } else {
+ target = hat->base.hname;
+ if (!PROFILE_IS_HAT(hat)) {
+ info = "target not hat";
+ error = -EPERM;
+ goto audit;
+ }
+ }
+
+ error = may_change_ptraced_domain(current, hat);
+ if (error) {
+ info = "ptraced";
+ error = -EPERM;
+ goto audit;
+ }
+
+ if (!permtest) {
+ error = aa_set_current_hat(hat, token);
+ if (error == -EACCES)
+ /* kill task in case of brute force attacks */
+ perms.kill = AA_MAY_CHANGEHAT;
+ else if (name && !error)
+ /* reset error for learning of new hats */
+ error = -ENOENT;
+ }
+ } else if (previous_profile) {
+ /* Return to saved profile. Kill task if restore fails
+ * to avoid brute force attacks
+ */
+ target = previous_profile->base.hname;
+ error = aa_restore_previous_profile(token);
+ perms.kill = AA_MAY_CHANGEHAT;
+ } else
+ /* ignore restores when there is no saved profile */
+ goto out;
+
+audit:
+ if (!permtest)
+ error = aa_audit_file(profile, &perms, GFP_KERNEL,
+ OP_CHANGE_HAT, AA_MAY_CHANGEHAT, NULL,
+ target, 0, info, error);
+
+out:
+ aa_put_profile(hat);
+ kfree(name);
+ put_cred(cred);
+
+ return error;
+}
+
+/**
+ * aa_change_profile - perform a one-way profile transition
+ * @ns_name: name of the profile namespace to change to (MAYBE NULL)
+ * @hname: name of profile to change to (MAYBE NULL)
+ * @onexec: whether this transition is to take place immediately or at exec
+ * @permtest: true if this is just a permission test
+ *
+ * Change to new profile @name. Unlike with hats, there is no way
+ * to change back. If @name isn't specified the current profile name is
+ * used.
+ * If @onexec then the transition is delayed until
+ * the next exec.
+ *
+ * Returns %0 on success, error otherwise.
+ */
+int aa_change_profile(const char *ns_name, const char *hname, bool onexec,
+ bool permtest)
+{
+ const struct cred *cred;
+ struct aa_task_cxt *cxt;
+ struct aa_profile *profile, *target = NULL;
+ struct aa_namespace *ns = NULL;
+ struct file_perms perms = {};
+ const char *name = NULL, *info = NULL;
+ int op, error = 0;
+ u32 request;
+
+ if (!hname && !ns_name)
+ return -EINVAL;
+
+ if (onexec) {
+ request = AA_MAY_ONEXEC;
+ op = OP_CHANGE_ONEXEC;
+ } else {
+ request = AA_MAY_CHANGE_PROFILE;
+ op = OP_CHANGE_PROFILE;
+ }
+
+ cred = get_current_cred();
+ cxt = cred->security;
+ profile = aa_cred_profile(cred);
+
+ if (ns_name) {
+ /* released below */
+ ns = aa_find_namespace(profile->ns, ns_name);
+ if (!ns) {
+ /* we don't create new namespace in complain mode */
+ name = ns_name;
+ info = "namespace not found";
+ error = -ENOENT;
+ goto audit;
+ }
+ } else
+ /* released below */
+ ns = aa_get_namespace(profile->ns);
+
+ /* if the name was not specified, use the name of the current profile */
+ if (!hname) {
+ if (unconfined(profile))
+ hname = ns->unconfined->base.hname;
+ else
+ hname = profile->base.hname;
+ }
+
+ perms = change_profile_perms(profile, ns, hname, request,
+ profile->file.start);
+ if (!(perms.allow & request)) {
+ error = -EACCES;
+ goto audit;
+ }
+
+ /* released below */
+ target = aa_lookup_profile(ns, hname);
+ if (!target) {
+ info = "profile not found";
+ error = -ENOENT;
+ if (permtest || !COMPLAIN_MODE(profile))
+ goto audit;
+ /* released below */
+ target = aa_new_null_profile(profile, 0);
+ if (!target) {
+ info = "failed null profile create";
+ error = -ENOMEM;
+ goto audit;
+ }
+ }
+
+ /* check if tracing task is allowed to trace target domain */
+ error = may_change_ptraced_domain(current, target);
+ if (error) {
+ info = "ptrace prevents transition";
+ goto audit;
+ }
+
+ if (permtest)
+ goto audit;
+
+ if (onexec)
+ error = aa_set_current_onexec(target);
+ else
+ error = aa_replace_current_profile(target);
+
+audit:
+ if (!permtest)
+ error = aa_audit_file(profile, &perms, GFP_KERNEL, op, request,
+ name, hname, 0, info, error);
+
+ aa_put_namespace(ns);
+ aa_put_profile(target);
+ put_cred(cred);
+
+ return error;
+}
diff --git a/security/apparmor/file.c b/security/apparmor/file.c
new file mode 100644
index 00000000000..7312db74121
--- /dev/null
+++ b/security/apparmor/file.c
@@ -0,0 +1,457 @@
+/*
+ * AppArmor security module
+ *
+ * This file contains AppArmor mediation of files
+ *
+ * Copyright (C) 1998-2008 Novell/SUSE
+ * Copyright 2009-2010 Canonical Ltd.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2 of the
+ * License.
+ */
+
+#include "include/apparmor.h"
+#include "include/audit.h"
+#include "include/file.h"
+#include "include/match.h"
+#include "include/path.h"
+#include "include/policy.h"
+
+struct file_perms nullperms;
+
+
+/**
+ * audit_file_mask - convert mask to permission string
+ * @buffer: buffer to write string to (NOT NULL)
+ * @mask: permission mask to convert
+ */
+static void audit_file_mask(struct audit_buffer *ab, u32 mask)
+{
+ char str[10];
+
+ char *m = str;
+
+ if (mask & AA_EXEC_MMAP)
+ *m++ = 'm';
+ if (mask & (MAY_READ | AA_MAY_META_READ))
+ *m++ = 'r';
+ if (mask & (MAY_WRITE | AA_MAY_META_WRITE | AA_MAY_CHMOD |
+ AA_MAY_CHOWN))
+ *m++ = 'w';
+ else if (mask & MAY_APPEND)
+ *m++ = 'a';
+ if (mask & AA_MAY_CREATE)
+ *m++ = 'c';
+ if (mask & AA_MAY_DELETE)
+ *m++ = 'd';
+ if (mask & AA_MAY_LINK)
+ *m++ = 'l';
+ if (mask & AA_MAY_LOCK)
+ *m++ = 'k';
+ if (mask & MAY_EXEC)
+ *m++ = 'x';
+ *m = '\0';
+
+ audit_log_string(ab, str);
+}
+
+/**
+ * file_audit_cb - call back for file specific audit fields
+ * @ab: audit_buffer (NOT NULL)
+ * @va: audit struct to audit values of (NOT NULL)
+ */
+static void file_audit_cb(struct audit_buffer *ab, void *va)
+{
+ struct common_audit_data *sa = va;
+ uid_t fsuid = current_fsuid();
+
+ if (sa->aad.fs.request & AA_AUDIT_FILE_MASK) {
+ audit_log_format(ab, " requested_mask=");
+ audit_file_mask(ab, sa->aad.fs.request);
+ }
+ if (sa->aad.fs.denied & AA_AUDIT_FILE_MASK) {
+ audit_log_format(ab, " denied_mask=");
+ audit_file_mask(ab, sa->aad.fs.denied);
+ }
+ if (sa->aad.fs.request & AA_AUDIT_FILE_MASK) {
+ audit_log_format(ab, " fsuid=%d", fsuid);
+ audit_log_format(ab, " ouid=%d", sa->aad.fs.ouid);
+ }
+
+ if (sa->aad.fs.target) {
+ audit_log_format(ab, " target=");
+ audit_log_untrustedstring(ab, sa->aad.fs.target);
+ }
+}
+
+/**
+ * aa_audit_file - handle the auditing of file operations
+ * @profile: the profile being enforced (NOT NULL)
+ * @perms: the permissions computed for the request (NOT NULL)
+ * @gfp: allocation flags
+ * @op: operation being mediated
+ * @request: permissions requested
+ * @name: name of object being mediated (MAYBE NULL)
+ * @target: name of target (MAYBE NULL)
+ * @ouid: object uid
+ * @info: extra information message (MAYBE NULL)
+ * @error: 0 if operation allowed else failure error code
+ *
+ * Returns: %0 or error on failure
+ */
+int aa_audit_file(struct aa_profile *profile, struct file_perms *perms,
+ gfp_t gfp, int op, u32 request, const char *name,
+ const char *target, uid_t ouid, const char *info, int error)
+{
+ int type = AUDIT_APPARMOR_AUTO;
+ struct common_audit_data sa;
+ COMMON_AUDIT_DATA_INIT(&sa, NONE);
+ sa.aad.op = op,
+ sa.aad.fs.request = request;
+ sa.aad.name = name;
+ sa.aad.fs.target = target;
+ sa.aad.fs.ouid = ouid;
+ sa.aad.info = info;
+ sa.aad.error = error;
+
+ if (likely(!sa.aad.error)) {
+ u32 mask = perms->audit;
+
+ if (unlikely(AUDIT_MODE(profile) == AUDIT_ALL))
+ mask = 0xffff;
+
+ /* mask off perms that are not being force audited */
+ sa.aad.fs.request &= mask;
+
+ if (likely(!sa.aad.fs.request))
+ return 0;
+ type = AUDIT_APPARMOR_AUDIT;
+ } else {
+ /* only report permissions that were denied */
+ sa.aad.fs.request = sa.aad.fs.request & ~perms->allow;
+
+ if (sa.aad.fs.request & perms->kill)
+ type = AUDIT_APPARMOR_KILL;
+
+ /* quiet known rejects, assumes quiet and kill do not overlap */
+ if ((sa.aad.fs.request & perms->quiet) &&
+ AUDIT_MODE(profile) != AUDIT_NOQUIET &&
+ AUDIT_MODE(profile) != AUDIT_ALL)
+ sa.aad.fs.request &= ~perms->quiet;
+
+ if (!sa.aad.fs.request)
+ return COMPLAIN_MODE(profile) ? 0 : sa.aad.error;
+ }
+
+ sa.aad.fs.denied = sa.aad.fs.request & ~perms->allow;
+ return aa_audit(type, profile, gfp, &sa, file_audit_cb);
+}
+
+/**
+ * map_old_perms - map old file perms layout to the new layout
+ * @old: permission set in old mapping
+ *
+ * Returns: new permission mapping
+ */
+static u32 map_old_perms(u32 old)
+{
+ u32 new = old & 0xf;
+ if (old & MAY_READ)
+ new |= AA_MAY_META_READ;
+ if (old & MAY_WRITE)
+ new |= AA_MAY_META_WRITE | AA_MAY_CREATE | AA_MAY_DELETE |
+ AA_MAY_CHMOD | AA_MAY_CHOWN;
+ if (old & 0x10)
+ new |= AA_MAY_LINK;
+ /* the old mapping lock and link_subset flags where overlaid
+ * and use was determined by part of a pair that they were in
+ */
+ if (old & 0x20)
+ new |= AA_MAY_LOCK | AA_LINK_SUBSET;
+ if (old & 0x40) /* AA_EXEC_MMAP */
+ new |= AA_EXEC_MMAP;
+
+ new |= AA_MAY_META_READ;
+
+ return new;
+}
+
+/**
+ * compute_perms - convert dfa compressed perms to internal perms
+ * @dfa: dfa to compute perms for (NOT NULL)
+ * @state: state in dfa
+ * @cond: conditions to consider (NOT NULL)
+ *
+ * TODO: convert from dfa + state to permission entry, do computation conversion
+ * at load time.
+ *
+ * Returns: computed permission set
+ */
+static struct file_perms compute_perms(struct aa_dfa *dfa, unsigned int state,
+ struct path_cond *cond)
+{
+ struct file_perms perms;
+
+ /* FIXME: change over to new dfa format
+ * currently file perms are encoded in the dfa, new format
+ * splits the permissions from the dfa. This mapping can be
+ * done at profile load
+ */
+ perms.kill = 0;
+
+ if (current_fsuid() == cond->uid) {
+ perms.allow = map_old_perms(dfa_user_allow(dfa, state));
+ perms.audit = map_old_perms(dfa_user_audit(dfa, state));
+ perms.quiet = map_old_perms(dfa_user_quiet(dfa, state));
+ perms.xindex = dfa_user_xindex(dfa, state);
+ } else {
+ perms.allow = map_old_perms(dfa_other_allow(dfa, state));
+ perms.audit = map_old_perms(dfa_other_audit(dfa, state));
+ perms.quiet = map_old_perms(dfa_other_quiet(dfa, state));
+ perms.xindex = dfa_other_xindex(dfa, state);
+ }
+
+ /* change_profile wasn't determined by ownership in old mapping */
+ if (ACCEPT_TABLE(dfa)[state] & 0x80000000)
+ perms.allow |= AA_MAY_CHANGE_PROFILE;
+
+ return perms;
+}
+
+/**
+ * aa_str_perms - find permission that match @name
+ * @dfa: to match against (MAYBE NULL)
+ * @state: state to start matching in
+ * @name: string to match against dfa (NOT NULL)
+ * @cond: conditions to consider for permission set computation (NOT NULL)
+ * @perms: Returns - the permissions found when matching @name
+ *
+ * Returns: the final state in @dfa when beginning @start and walking @name
+ */
+unsigned int aa_str_perms(struct aa_dfa *dfa, unsigned int start,
+ const char *name, struct path_cond *cond,
+ struct file_perms *perms)
+{
+ unsigned int state;
+ if (!dfa) {
+ *perms = nullperms;
+ return DFA_NOMATCH;
+ }
+
+ state = aa_dfa_match(dfa, start, name);
+ *perms = compute_perms(dfa, state, cond);
+
+ return state;
+}
+
+/**
+ * is_deleted - test if a file has been completely unlinked
+ * @dentry: dentry of file to test for deletion (NOT NULL)
+ *
+ * Returns: %1 if deleted else %0
+ */
+static inline bool is_deleted(struct dentry *dentry)
+{
+ if (d_unlinked(dentry) && dentry->d_inode->i_nlink == 0)
+ return 1;
+ return 0;
+}
+
+/**
+ * aa_path_perm - do permissions check & audit for @path
+ * @op: operation being checked
+ * @profile: profile being enforced (NOT NULL)
+ * @path: path to check permissions of (NOT NULL)
+ * @flags: any additional path flags beyond what the profile specifies
+ * @request: requested permissions
+ * @cond: conditional info for this request (NOT NULL)
+ *
+ * Returns: %0 else error if access denied or other error
+ */
+int aa_path_perm(int op, struct aa_profile *profile, struct path *path,
+ int flags, u32 request, struct path_cond *cond)
+{
+ char *buffer = NULL;
+ struct file_perms perms = {};
+ const char *name, *info = NULL;
+ int error;
+
+ flags |= profile->path_flags | (S_ISDIR(cond->mode) ? PATH_IS_DIR : 0);
+ error = aa_get_name(path, flags, &buffer, &name);
+ if (error) {
+ if (error == -ENOENT && is_deleted(path->dentry)) {
+ /* Access to open files that are deleted are
+ * give a pass (implicit delegation)
+ */
+ error = 0;
+ perms.allow = request;
+ } else if (error == -ENOENT)
+ info = "Failed name lookup - deleted entry";
+ else if (error == -ESTALE)
+ info = "Failed name lookup - disconnected path";
+ else if (error == -ENAMETOOLONG)
+ info = "Failed name lookup - name too long";
+ else
+ info = "Failed name lookup";
+ } else {
+ aa_str_perms(profile->file.dfa, profile->file.start, name, cond,
+ &perms);
+ if (request & ~perms.allow)
+ error = -EACCES;
+ }
+ error = aa_audit_file(profile, &perms, GFP_KERNEL, op, request, name,
+ NULL, cond->uid, info, error);
+ kfree(buffer);
+
+ return error;
+}
+
+/**
+ * xindex_is_subset - helper for aa_path_link
+ * @link: link permission set
+ * @target: target permission set
+ *
+ * test target x permissions are equal OR a subset of link x permissions
+ * this is done as part of the subset test, where a hardlink must have
+ * a subset of permissions that the target has.
+ *
+ * Returns: %1 if subset else %0
+ */
+static inline bool xindex_is_subset(u32 link, u32 target)
+{
+ if (((link & ~AA_X_UNSAFE) != (target & ~AA_X_UNSAFE)) ||
+ ((link & AA_X_UNSAFE) && !(target & AA_X_UNSAFE)))
+ return 0;
+
+ return 1;
+}
+
+/**
+ * aa_path_link - Handle hard link permission check
+ * @profile: the profile being enforced (NOT NULL)
+ * @old_dentry: the target dentry (NOT NULL)
+ * @new_dir: directory the new link will be created in (NOT NULL)
+ * @new_dentry: the link being created (NOT NULL)
+ *
+ * Handle the permission test for a link & target pair. Permission
+ * is encoded as a pair where the link permission is determined
+ * first, and if allowed, the target is tested. The target test
+ * is done from the point of the link match (not start of DFA)
+ * making the target permission dependent on the link permission match.
+ *
+ * The subset test if required forces that permissions granted
+ * on link are a subset of the permission granted to target.
+ *
+ * Returns: %0 if allowed else error
+ */
+int aa_path_link(struct aa_profile *profile, struct dentry *old_dentry,
+ struct path *new_dir, struct dentry *new_dentry)
+{
+ struct path link = { new_dir->mnt, new_dentry };
+ struct path target = { new_dir->mnt, old_dentry };
+ struct path_cond cond = {
+ old_dentry->d_inode->i_uid,
+ old_dentry->d_inode->i_mode
+ };
+ char *buffer = NULL, *buffer2 = NULL;
+ const char *lname, *tname = NULL, *info = NULL;
+ struct file_perms lperms, perms;
+ u32 request = AA_MAY_LINK;
+ unsigned int state;
+ int error;
+
+ lperms = nullperms;
+
+ /* buffer freed below, lname is pointer in buffer */
+ error = aa_get_name(&link, profile->path_flags, &buffer, &lname);
+ if (error)
+ goto audit;
+
+ /* buffer2 freed below, tname is pointer in buffer2 */
+ error = aa_get_name(&target, profile->path_flags, &buffer2, &tname);
+ if (error)
+ goto audit;
+
+ error = -EACCES;
+ /* aa_str_perms - handles the case of the dfa being NULL */
+ state = aa_str_perms(profile->file.dfa, profile->file.start, lname,
+ &cond, &lperms);
+
+ if (!(lperms.allow & AA_MAY_LINK))
+ goto audit;
+
+ /* test to see if target can be paired with link */
+ state = aa_dfa_null_transition(profile->file.dfa, state);
+ aa_str_perms(profile->file.dfa, state, tname, &cond, &perms);
+
+ /* force audit/quiet masks for link are stored in the second entry
+ * in the link pair.
+ */
+ lperms.audit = perms.audit;
+ lperms.quiet = perms.quiet;
+ lperms.kill = perms.kill;
+
+ if (!(perms.allow & AA_MAY_LINK)) {
+ info = "target restricted";
+ goto audit;
+ }
+
+ /* done if link subset test is not required */
+ if (!(perms.allow & AA_LINK_SUBSET))
+ goto done_tests;
+
+ /* Do link perm subset test requiring allowed permission on link are a
+ * subset of the allowed permissions on target.
+ */
+ aa_str_perms(profile->file.dfa, profile->file.start, tname, &cond,
+ &perms);
+
+ /* AA_MAY_LINK is not considered in the subset test */
+ request = lperms.allow & ~AA_MAY_LINK;
+ lperms.allow &= perms.allow | AA_MAY_LINK;
+
+ request |= AA_AUDIT_FILE_MASK & (lperms.allow & ~perms.allow);
+ if (request & ~lperms.allow) {
+ goto audit;
+ } else if ((lperms.allow & MAY_EXEC) &&
+ !xindex_is_subset(lperms.xindex, perms.xindex)) {
+ lperms.allow &= ~MAY_EXEC;
+ request |= MAY_EXEC;
+ info = "link not subset of target";
+ goto audit;
+ }
+
+done_tests:
+ error = 0;
+
+audit:
+ error = aa_audit_file(profile, &lperms, GFP_KERNEL, OP_LINK, request,
+ lname, tname, cond.uid, info, error);
+ kfree(buffer);
+ kfree(buffer2);
+
+ return error;
+}
+
+/**
+ * aa_file_perm - do permission revalidation check & audit for @file
+ * @op: operation being checked
+ * @profile: profile being enforced (NOT NULL)
+ * @file: file to revalidate access permissions on (NOT NULL)
+ * @request: requested permissions
+ *
+ * Returns: %0 if access allowed else error
+ */
+int aa_file_perm(int op, struct aa_profile *profile, struct file *file,
+ u32 request)
+{
+ struct path_cond cond = {
+ .uid = file->f_path.dentry->d_inode->i_uid,
+ .mode = file->f_path.dentry->d_inode->i_mode
+ };
+
+ return aa_path_perm(op, profile, &file->f_path, PATH_DELEGATE_DELETED,
+ request, &cond);
+}
diff --git a/security/apparmor/include/apparmor.h b/security/apparmor/include/apparmor.h
new file mode 100644
index 00000000000..38ccaea0820
--- /dev/null
+++ b/security/apparmor/include/apparmor.h
@@ -0,0 +1,92 @@
+/*
+ * AppArmor security module
+ *
+ * This file contains AppArmor basic global and lib definitions
+ *
+ * Copyright (C) 1998-2008 Novell/SUSE
+ * Copyright 2009-2010 Canonical Ltd.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2 of the
+ * License.
+ */
+
+#ifndef __APPARMOR_H
+#define __APPARMOR_H
+
+#include <linux/fs.h>
+
+#include "match.h"
+
+/* Control parameters settable through module/boot flags */
+extern enum audit_mode aa_g_audit;
+extern int aa_g_audit_header;
+extern int aa_g_debug;
+extern int aa_g_lock_policy;
+extern int aa_g_logsyscall;
+extern int aa_g_paranoid_load;
+extern unsigned int aa_g_path_max;
+
+/*
+ * DEBUG remains global (no per profile flag) since it is mostly used in sysctl
+ * which is not related to profile accesses.
+ */
+
+#define AA_DEBUG(fmt, args...) \
+ do { \
+ if (aa_g_debug && printk_ratelimit()) \
+ printk(KERN_DEBUG "AppArmor: " fmt, ##args); \
+ } while (0)
+
+#define AA_ERROR(fmt, args...) \
+ do { \
+ if (printk_ratelimit()) \
+ printk(KERN_ERR "AppArmor: " fmt, ##args); \
+ } while (0)
+
+/* Flag indicating whether initialization completed */
+extern int apparmor_initialized __initdata;
+
+/* fn's in lib */
+char *aa_split_fqname(char *args, char **ns_name);
+void aa_info_message(const char *str);
+void *kvmalloc(size_t size);
+void kvfree(void *buffer);
+
+
+/**
+ * aa_strneq - compare null terminated @str to a non null terminated substring
+ * @str: a null terminated string
+ * @sub: a substring, not necessarily null terminated
+ * @len: length of @sub to compare
+ *
+ * The @str string must be full consumed for this to be considered a match
+ */
+static inline bool aa_strneq(const char *str, const char *sub, int len)
+{
+ return !strncmp(str, sub, len) && !str[len];
+}
+
+/**
+ * aa_dfa_null_transition - step to next state after null character
+ * @dfa: the dfa to match against
+ * @start: the state of the dfa to start matching in
+ *
+ * aa_dfa_null_transition transitions to the next state after a null
+ * character which is not used in standard matching and is only
+ * used to separate pairs.
+ */
+static inline unsigned int aa_dfa_null_transition(struct aa_dfa *dfa,
+ unsigned int start)
+{
+ /* the null transition only needs the string's null terminator byte */
+ return aa_dfa_match_len(dfa, start, "", 1);
+}
+
+static inline bool mediated_filesystem(struct inode *inode)
+{
+ return !(inode->i_sb->s_flags & MS_NOUSER);
+}
+
+#endif /* __APPARMOR_H */
diff --git a/security/apparmor/include/apparmorfs.h b/security/apparmor/include/apparmorfs.h
new file mode 100644
index 00000000000..cb1e93a114d
--- /dev/null
+++ b/security/apparmor/include/apparmorfs.h
@@ -0,0 +1,20 @@
+/*
+ * AppArmor security module
+ *
+ * This file contains AppArmor filesystem definitions.
+ *
+ * Copyright (C) 1998-2008 Novell/SUSE
+ * Copyright 2009-2010 Canonical Ltd.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2 of the
+ * License.
+ */
+
+#ifndef __AA_APPARMORFS_H
+#define __AA_APPARMORFS_H
+
+extern void __init aa_destroy_aafs(void);
+
+#endif /* __AA_APPARMORFS_H */
diff --git a/security/apparmor/include/audit.h b/security/apparmor/include/audit.h
new file mode 100644
index 00000000000..1951786d32e
--- /dev/null
+++ b/security/apparmor/include/audit.h
@@ -0,0 +1,123 @@
+/*
+ * AppArmor security module
+ *
+ * This file contains AppArmor auditing function definitions.
+ *
+ * Copyright (C) 1998-2008 Novell/SUSE
+ * Copyright 2009-2010 Canonical Ltd.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2 of the
+ * License.
+ */
+
+#ifndef __AA_AUDIT_H
+#define __AA_AUDIT_H
+
+#include <linux/audit.h>
+#include <linux/fs.h>
+#include <linux/lsm_audit.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+
+#include "file.h"
+
+struct aa_profile;
+
+extern const char *audit_mode_names[];
+#define AUDIT_MAX_INDEX 5
+
+#define AUDIT_APPARMOR_AUTO 0 /* auto choose audit message type */
+
+enum audit_mode {
+ AUDIT_NORMAL, /* follow normal auditing of accesses */
+ AUDIT_QUIET_DENIED, /* quiet all denied access messages */
+ AUDIT_QUIET, /* quiet all messages */
+ AUDIT_NOQUIET, /* do not quiet audit messages */
+ AUDIT_ALL /* audit all accesses */
+};
+
+enum audit_type {
+ AUDIT_APPARMOR_AUDIT,
+ AUDIT_APPARMOR_ALLOWED,
+ AUDIT_APPARMOR_DENIED,
+ AUDIT_APPARMOR_HINT,
+ AUDIT_APPARMOR_STATUS,
+ AUDIT_APPARMOR_ERROR,
+ AUDIT_APPARMOR_KILL
+};
+
+extern const char *op_table[];
+enum aa_ops {
+ OP_NULL,
+
+ OP_SYSCTL,
+ OP_CAPABLE,
+
+ OP_UNLINK,
+ OP_MKDIR,
+ OP_RMDIR,
+ OP_MKNOD,
+ OP_TRUNC,
+ OP_LINK,
+ OP_SYMLINK,
+ OP_RENAME_SRC,
+ OP_RENAME_DEST,
+ OP_CHMOD,
+ OP_CHOWN,
+ OP_GETATTR,
+ OP_OPEN,
+
+ OP_FPERM,
+ OP_FLOCK,
+ OP_FMMAP,
+ OP_FMPROT,
+
+ OP_CREATE,
+ OP_POST_CREATE,
+ OP_BIND,
+ OP_CONNECT,
+ OP_LISTEN,
+ OP_ACCEPT,
+ OP_SENDMSG,
+ OP_RECVMSG,
+ OP_GETSOCKNAME,
+ OP_GETPEERNAME,
+ OP_GETSOCKOPT,
+ OP_SETSOCKOPT,
+ OP_SOCK_SHUTDOWN,
+
+ OP_PTRACE,
+
+ OP_EXEC,
+ OP_CHANGE_HAT,
+ OP_CHANGE_PROFILE,
+ OP_CHANGE_ONEXEC,
+
+ OP_SETPROCATTR,
+ OP_SETRLIMIT,
+
+ OP_PROF_REPL,
+ OP_PROF_LOAD,
+ OP_PROF_RM,
+};
+
+
+/* define a short hand for apparmor_audit_data portion of common_audit_data */
+#define aad apparmor_audit_data
+
+void aa_audit_msg(int type, struct common_audit_data *sa,
+ void (*cb) (struct audit_buffer *, void *));
+int aa_audit(int type, struct aa_profile *profile, gfp_t gfp,
+ struct common_audit_data *sa,
+ void (*cb) (struct audit_buffer *, void *));
+
+static inline int complain_error(int error)
+{
+ if (error == -EPERM || error == -EACCES)
+ return 0;
+ return error;
+}
+
+#endif /* __AA_AUDIT_H */
diff --git a/security/apparmor/include/capability.h b/security/apparmor/include/capability.h
new file mode 100644
index 00000000000..c24d2959ea0
--- /dev/null
+++ b/security/apparmor/include/capability.h
@@ -0,0 +1,45 @@
+/*
+ * AppArmor security module
+ *
+ * This file contains AppArmor capability mediation definitions.
+ *
+ * Copyright (C) 1998-2008 Novell/SUSE
+ * Copyright 2009-2010 Canonical Ltd.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2 of the
+ * License.
+ */
+
+#ifndef __AA_CAPABILITY_H
+#define __AA_CAPABILITY_H
+
+#include <linux/sched.h>
+
+struct aa_profile;
+
+/* aa_caps - confinement data for capabilities
+ * @allowed: capabilities mask
+ * @audit: caps that are to be audited
+ * @quiet: caps that should not be audited
+ * @kill: caps that when requested will result in the task being killed
+ * @extended: caps that are subject finer grained mediation
+ */
+struct aa_caps {
+ kernel_cap_t allow;
+ kernel_cap_t audit;
+ kernel_cap_t quiet;
+ kernel_cap_t kill;
+ kernel_cap_t extended;
+};
+
+int aa_capable(struct task_struct *task, struct aa_profile *profile, int cap,
+ int audit);
+
+static inline void aa_free_cap_rules(struct aa_caps *caps)
+{
+ /* NOP */
+}
+
+#endif /* __AA_CAPBILITY_H */
diff --git a/security/apparmor/include/context.h b/security/apparmor/include/context.h
new file mode 100644
index 00000000000..a9cbee4d9e4
--- /dev/null
+++ b/security/apparmor/include/context.h
@@ -0,0 +1,154 @@
+/*
+ * AppArmor security module
+ *
+ * This file contains AppArmor contexts used to associate "labels" to objects.
+ *
+ * Copyright (C) 1998-2008 Novell/SUSE
+ * Copyright 2009-2010 Canonical Ltd.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2 of the
+ * License.
+ */
+
+#ifndef __AA_CONTEXT_H
+#define __AA_CONTEXT_H
+
+#include <linux/cred.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+
+#include "policy.h"
+
+/* struct aa_file_cxt - the AppArmor context the file was opened in
+ * @perms: the permission the file was opened with
+ *
+ * The file_cxt could currently be directly stored in file->f_security
+ * as the profile reference is now stored in the f_cred. However the
+ * cxt struct will expand in the future so we keep the struct.
+ */
+struct aa_file_cxt {
+ u16 allow;
+};
+
+/**
+ * aa_alloc_file_context - allocate file_cxt
+ * @gfp: gfp flags for allocation
+ *
+ * Returns: file_cxt or NULL on failure
+ */
+static inline struct aa_file_cxt *aa_alloc_file_context(gfp_t gfp)
+{
+ return kzalloc(sizeof(struct aa_file_cxt), gfp);
+}
+
+/**
+ * aa_free_file_context - free a file_cxt
+ * @cxt: file_cxt to free (MAYBE_NULL)
+ */
+static inline void aa_free_file_context(struct aa_file_cxt *cxt)
+{
+ if (cxt)
+ kzfree(cxt);
+}
+
+/**
+ * struct aa_task_cxt - primary label for confined tasks
+ * @profile: the current profile (NOT NULL)
+ * @exec: profile to transition to on next exec (MAYBE NULL)
+ * @previous: profile the task may return to (MAYBE NULL)
+ * @token: magic value the task must know for returning to @previous_profile
+ *
+ * Contains the task's current profile (which could change due to
+ * change_hat). Plus the hat_magic needed during change_hat.
+ *
+ * TODO: make so a task can be confined by a stack of contexts
+ */
+struct aa_task_cxt {
+ struct aa_profile *profile;
+ struct aa_profile *onexec;
+ struct aa_profile *previous;
+ u64 token;
+};
+
+struct aa_task_cxt *aa_alloc_task_context(gfp_t flags);
+void aa_free_task_context(struct aa_task_cxt *cxt);
+void aa_dup_task_context(struct aa_task_cxt *new,
+ const struct aa_task_cxt *old);
+int aa_replace_current_profile(struct aa_profile *profile);
+int aa_set_current_onexec(struct aa_profile *profile);
+int aa_set_current_hat(struct aa_profile *profile, u64 token);
+int aa_restore_previous_profile(u64 cookie);
+
+/**
+ * __aa_task_is_confined - determine if @task has any confinement
+ * @task: task to check confinement of (NOT NULL)
+ *
+ * If @task != current needs to be called in RCU safe critical section
+ */
+static inline bool __aa_task_is_confined(struct task_struct *task)
+{
+ struct aa_task_cxt *cxt = __task_cred(task)->security;
+
+ BUG_ON(!cxt || !cxt->profile);
+ if (unconfined(aa_newest_version(cxt->profile)))
+ return 0;
+
+ return 1;
+}
+
+/**
+ * aa_cred_profile - obtain cred's profiles
+ * @cred: cred to obtain profiles from (NOT NULL)
+ *
+ * Returns: confining profile
+ *
+ * does NOT increment reference count
+ */
+static inline struct aa_profile *aa_cred_profile(const struct cred *cred)
+{
+ struct aa_task_cxt *cxt = cred->security;
+ BUG_ON(!cxt || !cxt->profile);
+ return aa_newest_version(cxt->profile);
+}
+
+/**
+ * __aa_current_profile - find the current tasks confining profile
+ *
+ * Returns: up to date confining profile or the ns unconfined profile (NOT NULL)
+ *
+ * This fn will not update the tasks cred to the most up to date version
+ * of the profile so it is safe to call when inside of locks.
+ */
+static inline struct aa_profile *__aa_current_profile(void)
+{
+ return aa_cred_profile(current_cred());
+}
+
+/**
+ * aa_current_profile - find the current tasks confining profile and do updates
+ *
+ * Returns: up to date confining profile or the ns unconfined profile (NOT NULL)
+ *
+ * This fn will update the tasks cred structure if the profile has been
+ * replaced. Not safe to call inside locks
+ */
+static inline struct aa_profile *aa_current_profile(void)
+{
+ const struct aa_task_cxt *cxt = current_cred()->security;
+ struct aa_profile *profile;
+ BUG_ON(!cxt || !cxt->profile);
+
+ profile = aa_newest_version(cxt->profile);
+ /*
+ * Whether or not replacement succeeds, use newest profile so
+ * there is no need to update it after replacement.
+ */
+ if (unlikely((cxt->profile != profile)))
+ aa_replace_current_profile(profile);
+
+ return profile;
+}
+
+#endif /* __AA_CONTEXT_H */
diff --git a/security/apparmor/include/domain.h b/security/apparmor/include/domain.h
new file mode 100644
index 00000000000..de04464f0a3
--- /dev/null
+++ b/security/apparmor/include/domain.h
@@ -0,0 +1,36 @@
+/*
+ * AppArmor security module
+ *
+ * This file contains AppArmor security domain transition function definitions.
+ *
+ * Copyright (C) 1998-2008 Novell/SUSE
+ * Copyright 2009-2010 Canonical Ltd.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2 of the
+ * License.
+ */
+
+#include <linux/binfmts.h>
+#include <linux/types.h>
+
+#ifndef __AA_DOMAIN_H
+#define __AA_DOMAIN_H
+
+struct aa_domain {
+ int size;
+ char **table;
+};
+
+int apparmor_bprm_set_creds(struct linux_binprm *bprm);
+int apparmor_bprm_secureexec(struct linux_binprm *bprm);
+void apparmor_bprm_committing_creds(struct linux_binprm *bprm);
+void apparmor_bprm_committed_creds(struct linux_binprm *bprm);
+
+void aa_free_domain_entries(struct aa_domain *domain);
+int aa_change_hat(const char *hats[], int count, u64 token, bool permtest);
+int aa_change_profile(const char *ns_name, const char *name, bool onexec,
+ bool permtest);
+
+#endif /* __AA_DOMAIN_H */
diff --git a/security/apparmor/include/file.h b/security/apparmor/include/file.h
new file mode 100644
index 00000000000..be36feabb16
--- /dev/null
+++ b/security/apparmor/include/file.h
@@ -0,0 +1,217 @@
+/*
+ * AppArmor security module
+ *
+ * This file contains AppArmor file mediation function definitions.
+ *
+ * Copyright (C) 1998-2008 Novell/SUSE
+ * Copyright 2009-2010 Canonical Ltd.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2 of the
+ * License.
+ */
+
+#ifndef __AA_FILE_H
+#define __AA_FILE_H
+
+#include <linux/path.h>
+
+#include "domain.h"
+#include "match.h"
+
+struct aa_profile;
+
+/*
+ * We use MAY_EXEC, MAY_WRITE, MAY_READ, MAY_APPEND and the following flags
+ * for profile permissions
+ */
+#define AA_MAY_CREATE 0x0010
+#define AA_MAY_DELETE 0x0020
+#define AA_MAY_META_WRITE 0x0040
+#define AA_MAY_META_READ 0x0080
+
+#define AA_MAY_CHMOD 0x0100
+#define AA_MAY_CHOWN 0x0200
+#define AA_MAY_LOCK 0x0400
+#define AA_EXEC_MMAP 0x0800
+
+#define AA_MAY_LINK 0x1000
+#define AA_LINK_SUBSET AA_MAY_LOCK /* overlaid */
+#define AA_MAY_ONEXEC 0x40000000 /* exec allows onexec */
+#define AA_MAY_CHANGE_PROFILE 0x80000000
+#define AA_MAY_CHANGEHAT 0x80000000 /* ctrl auditing only */
+
+#define AA_AUDIT_FILE_MASK (MAY_READ | MAY_WRITE | MAY_EXEC | MAY_APPEND |\
+ AA_MAY_CREATE | AA_MAY_DELETE | \
+ AA_MAY_META_READ | AA_MAY_META_WRITE | \
+ AA_MAY_CHMOD | AA_MAY_CHOWN | AA_MAY_LOCK | \
+ AA_EXEC_MMAP | AA_MAY_LINK)
+
+/*
+ * The xindex is broken into 3 parts
+ * - index - an index into either the exec name table or the variable table
+ * - exec type - which determines how the executable name and index are used
+ * - flags - which modify how the destination name is applied
+ */
+#define AA_X_INDEX_MASK 0x03ff
+
+#define AA_X_TYPE_MASK 0x0c00
+#define AA_X_TYPE_SHIFT 10
+#define AA_X_NONE 0x0000
+#define AA_X_NAME 0x0400 /* use executable name px */
+#define AA_X_TABLE 0x0800 /* use a specified name ->n# */
+
+#define AA_X_UNSAFE 0x1000
+#define AA_X_CHILD 0x2000 /* make >AA_X_NONE apply to children */
+#define AA_X_INHERIT 0x4000
+#define AA_X_UNCONFINED 0x8000
+
+/* AA_SECURE_X_NEEDED - is passed in the bprm->unsafe field */
+#define AA_SECURE_X_NEEDED 0x8000
+
+/* need to make conditional which ones are being set */
+struct path_cond {
+ uid_t uid;
+ umode_t mode;
+};
+
+/* struct file_perms - file permission
+ * @allow: mask of permissions that are allowed
+ * @audit: mask of permissions to force an audit message for
+ * @quiet: mask of permissions to quiet audit messages for
+ * @kill: mask of permissions that when matched will kill the task
+ * @xindex: exec transition index if @allow contains MAY_EXEC
+ *
+ * The @audit and @queit mask should be mutually exclusive.
+ */
+struct file_perms {
+ u32 allow;
+ u32 audit;
+ u32 quiet;
+ u32 kill;
+ u16 xindex;
+};
+
+extern struct file_perms nullperms;
+
+#define COMBINED_PERM_MASK(X) ((X).allow | (X).audit | (X).quiet | (X).kill)
+
+/* FIXME: split perms from dfa and match this to description
+ * also add delegation info.
+ */
+static inline u16 dfa_map_xindex(u16 mask)
+{
+ u16 old_index = (mask >> 10) & 0xf;
+ u16 index = 0;
+
+ if (mask & 0x100)
+ index |= AA_X_UNSAFE;
+ if (mask & 0x200)
+ index |= AA_X_INHERIT;
+ if (mask & 0x80)
+ index |= AA_X_UNCONFINED;
+
+ if (old_index == 1) {
+ index |= AA_X_UNCONFINED;
+ } else if (old_index == 2) {
+ index |= AA_X_NAME;
+ } else if (old_index == 3) {
+ index |= AA_X_NAME | AA_X_CHILD;
+ } else {
+ index |= AA_X_TABLE;
+ index |= old_index - 4;
+ }
+
+ return index;
+}
+
+/*
+ * map old dfa inline permissions to new format
+ */
+#define dfa_user_allow(dfa, state) (((ACCEPT_TABLE(dfa)[state]) & 0x7f) | \
+ ((ACCEPT_TABLE(dfa)[state]) & 0x80000000))
+#define dfa_user_audit(dfa, state) ((ACCEPT_TABLE2(dfa)[state]) & 0x7f)
+#define dfa_user_quiet(dfa, state) (((ACCEPT_TABLE2(dfa)[state]) >> 7) & 0x7f)
+#define dfa_user_xindex(dfa, state) \
+ (dfa_map_xindex(ACCEPT_TABLE(dfa)[state] & 0x3fff))
+
+#define dfa_other_allow(dfa, state) ((((ACCEPT_TABLE(dfa)[state]) >> 14) & \
+ 0x7f) | \
+ ((ACCEPT_TABLE(dfa)[state]) & 0x80000000))
+#define dfa_other_audit(dfa, state) (((ACCEPT_TABLE2(dfa)[state]) >> 14) & 0x7f)
+#define dfa_other_quiet(dfa, state) \
+ ((((ACCEPT_TABLE2(dfa)[state]) >> 7) >> 14) & 0x7f)
+#define dfa_other_xindex(dfa, state) \
+ dfa_map_xindex((ACCEPT_TABLE(dfa)[state] >> 14) & 0x3fff)
+
+int aa_audit_file(struct aa_profile *profile, struct file_perms *perms,
+ gfp_t gfp, int op, u32 request, const char *name,
+ const char *target, uid_t ouid, const char *info, int error);
+
+/**
+ * struct aa_file_rules - components used for file rule permissions
+ * @dfa: dfa to match path names and conditionals against
+ * @perms: permission table indexed by the matched state accept entry of @dfa
+ * @trans: transition table for indexed by named x transitions
+ *
+ * File permission are determined by matching a path against @dfa and then
+ * then using the value of the accept entry for the matching state as
+ * an index into @perms. If a named exec transition is required it is
+ * looked up in the transition table.
+ */
+struct aa_file_rules {
+ unsigned int start;
+ struct aa_dfa *dfa;
+ /* struct perms perms; */
+ struct aa_domain trans;
+ /* TODO: add delegate table */
+};
+
+unsigned int aa_str_perms(struct aa_dfa *dfa, unsigned int start,
+ const char *name, struct path_cond *cond,
+ struct file_perms *perms);
+
+int aa_path_perm(int op, struct aa_profile *profile, struct path *path,
+ int flags, u32 request, struct path_cond *cond);
+
+int aa_path_link(struct aa_profile *profile, struct dentry *old_dentry,
+ struct path *new_dir, struct dentry *new_dentry);
+
+int aa_file_perm(int op, struct aa_profile *profile, struct file *file,
+ u32 request);
+
+static inline void aa_free_file_rules(struct aa_file_rules *rules)
+{
+ aa_put_dfa(rules->dfa);
+ aa_free_domain_entries(&rules->trans);
+}
+
+#define ACC_FMODE(x) (("\000\004\002\006"[(x)&O_ACCMODE]) | (((x) << 1) & 0x40))
+
+/* from namei.c */
+#define MAP_OPEN_FLAGS(x) ((((x) + 1) & O_ACCMODE) ? (x) + 1 : (x))
+
+/**
+ * aa_map_file_perms - map file flags to AppArmor permissions
+ * @file: open file to map flags to AppArmor permissions
+ *
+ * Returns: apparmor permission set for the file
+ */
+static inline u32 aa_map_file_to_perms(struct file *file)
+{
+ int flags = MAP_OPEN_FLAGS(file->f_flags);
+ u32 perms = ACC_FMODE(file->f_mode);
+
+ if ((flags & O_APPEND) && (perms & MAY_WRITE))
+ perms = (perms & ~MAY_WRITE) | MAY_APPEND;
+ /* trunc implies write permission */
+ if (flags & O_TRUNC)
+ perms |= MAY_WRITE;
+ if (flags & O_CREAT)
+ perms |= AA_MAY_CREATE;
+
+ return perms;
+}
+
+#endif /* __AA_FILE_H */
diff --git a/security/apparmor/include/ipc.h b/security/apparmor/include/ipc.h
new file mode 100644
index 00000000000..aeda0fbc8b2
--- /dev/null
+++ b/security/apparmor/include/ipc.h
@@ -0,0 +1,28 @@
+/*
+ * AppArmor security module
+ *
+ * This file contains AppArmor ipc mediation function definitions.
+ *
+ * Copyright (C) 1998-2008 Novell/SUSE
+ * Copyright 2009-2010 Canonical Ltd.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2 of the
+ * License.
+ */
+
+#ifndef __AA_IPC_H
+#define __AA_IPC_H
+
+#include <linux/sched.h>
+
+struct aa_profile;
+
+int aa_may_ptrace(struct task_struct *tracer_task, struct aa_profile *tracer,
+ struct aa_profile *tracee, unsigned int mode);
+
+int aa_ptrace(struct task_struct *tracer, struct task_struct *tracee,
+ unsigned int mode);
+
+#endif /* __AA_IPC_H */
diff --git a/security/apparmor/include/match.h b/security/apparmor/include/match.h
new file mode 100644
index 00000000000..734a6d35112
--- /dev/null
+++ b/security/apparmor/include/match.h
@@ -0,0 +1,132 @@
+/*
+ * AppArmor security module
+ *
+ * This file contains AppArmor policy dfa matching engine definitions.
+ *
+ * Copyright (C) 1998-2008 Novell/SUSE
+ * Copyright 2009-2010 Canonical Ltd.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2 of the
+ * License.
+ */
+
+#ifndef __AA_MATCH_H
+#define __AA_MATCH_H
+
+#include <linux/workqueue.h>
+
+#define DFA_NOMATCH 0
+#define DFA_START 1
+
+#define DFA_VALID_PERM_MASK 0xffffffff
+#define DFA_VALID_PERM2_MASK 0xffffffff
+
+/**
+ * The format used for transition tables is based on the GNU flex table
+ * file format (--tables-file option; see Table File Format in the flex
+ * info pages and the flex sources for documentation). The magic number
+ * used in the header is 0x1B5E783D insted of 0xF13C57B1 though, because
+ * the YY_ID_CHK (check) and YY_ID_DEF (default) tables are used
+ * slightly differently (see the apparmor-parser package).
+ */
+
+#define YYTH_MAGIC 0x1B5E783D
+#define YYTH_DEF_RECURSE 0x1 /* DEF Table is recursive */
+
+struct table_set_header {
+ u32 th_magic; /* YYTH_MAGIC */
+ u32 th_hsize;
+ u32 th_ssize;
+ u16 th_flags;
+ char th_version[];
+};
+
+/* The YYTD_ID are one less than flex table mappings. The flex id
+ * has 1 subtracted at table load time, this allows us to directly use the
+ * ID's as indexes.
+ */
+#define YYTD_ID_ACCEPT 0
+#define YYTD_ID_BASE 1
+#define YYTD_ID_CHK 2
+#define YYTD_ID_DEF 3
+#define YYTD_ID_EC 4
+#define YYTD_ID_META 5
+#define YYTD_ID_ACCEPT2 6
+#define YYTD_ID_NXT 7
+#define YYTD_ID_TSIZE 8
+
+#define YYTD_DATA8 1
+#define YYTD_DATA16 2
+#define YYTD_DATA32 4
+#define YYTD_DATA64 8
+
+/* Each ACCEPT2 table gets 6 dedicated flags, YYTD_DATAX define the
+ * first flags
+ */
+#define ACCEPT1_FLAGS(X) ((X) & 0x3f)
+#define ACCEPT2_FLAGS(X) ACCEPT1_FLAGS((X) >> YYTD_ID_ACCEPT2)
+#define TO_ACCEPT1_FLAG(X) ACCEPT1_FLAGS(X)
+#define TO_ACCEPT2_FLAG(X) (ACCEPT1_FLAGS(X) << YYTD_ID_ACCEPT2)
+#define DFA_FLAG_VERIFY_STATES 0x1000
+
+struct table_header {
+ u16 td_id;
+ u16 td_flags;
+ u32 td_hilen;
+ u32 td_lolen;
+ char td_data[];
+};
+
+#define DEFAULT_TABLE(DFA) ((u16 *)((DFA)->tables[YYTD_ID_DEF]->td_data))
+#define BASE_TABLE(DFA) ((u32 *)((DFA)->tables[YYTD_ID_BASE]->td_data))
+#define NEXT_TABLE(DFA) ((u16 *)((DFA)->tables[YYTD_ID_NXT]->td_data))
+#define CHECK_TABLE(DFA) ((u16 *)((DFA)->tables[YYTD_ID_CHK]->td_data))
+#define EQUIV_TABLE(DFA) ((u8 *)((DFA)->tables[YYTD_ID_EC]->td_data))
+#define ACCEPT_TABLE(DFA) ((u32 *)((DFA)->tables[YYTD_ID_ACCEPT]->td_data))
+#define ACCEPT_TABLE2(DFA) ((u32 *)((DFA)->tables[YYTD_ID_ACCEPT2]->td_data))
+
+struct aa_dfa {
+ struct kref count;
+ u16 flags;
+ struct table_header *tables[YYTD_ID_TSIZE];
+};
+
+#define byte_to_byte(X) (X)
+
+#define UNPACK_ARRAY(TABLE, BLOB, LEN, TYPE, NTOHX) \
+ do { \
+ typeof(LEN) __i; \
+ TYPE *__t = (TYPE *) TABLE; \
+ TYPE *__b = (TYPE *) BLOB; \
+ for (__i = 0; __i < LEN; __i++) { \
+ __t[__i] = NTOHX(__b[__i]); \
+ } \
+ } while (0)
+
+static inline size_t table_size(size_t len, size_t el_size)
+{
+ return ALIGN(sizeof(struct table_header) + len * el_size, 8);
+}
+
+struct aa_dfa *aa_dfa_unpack(void *blob, size_t size, int flags);
+unsigned int aa_dfa_match_len(struct aa_dfa *dfa, unsigned int start,
+ const char *str, int len);
+unsigned int aa_dfa_match(struct aa_dfa *dfa, unsigned int start,
+ const char *str);
+void aa_dfa_free_kref(struct kref *kref);
+
+/**
+ * aa_put_dfa - put a dfa refcount
+ * @dfa: dfa to put refcount (MAYBE NULL)
+ *
+ * Requires: if @dfa != NULL that a valid refcount be held
+ */
+static inline void aa_put_dfa(struct aa_dfa *dfa)
+{
+ if (dfa)
+ kref_put(&dfa->count, aa_dfa_free_kref);
+}
+
+#endif /* __AA_MATCH_H */
diff --git a/security/apparmor/include/path.h b/security/apparmor/include/path.h
new file mode 100644
index 00000000000..27b327a7fae
--- /dev/null
+++ b/security/apparmor/include/path.h
@@ -0,0 +1,31 @@
+/*
+ * AppArmor security module
+ *
+ * This file contains AppArmor basic path manipulation function definitions.
+ *
+ * Copyright (C) 1998-2008 Novell/SUSE
+ * Copyright 2009-2010 Canonical Ltd.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2 of the
+ * License.
+ */
+
+#ifndef __AA_PATH_H
+#define __AA_PATH_H
+
+
+enum path_flags {
+ PATH_IS_DIR = 0x1, /* path is a directory */
+ PATH_CONNECT_PATH = 0x4, /* connect disconnected paths to / */
+ PATH_CHROOT_REL = 0x8, /* do path lookup relative to chroot */
+ PATH_CHROOT_NSCONNECT = 0x10, /* connect paths that are at ns root */
+
+ PATH_DELEGATE_DELETED = 0x08000, /* delegate deleted files */
+ PATH_MEDIATE_DELETED = 0x10000, /* mediate deleted paths */
+};
+
+int aa_get_name(struct path *path, int flags, char **buffer, const char **name);
+
+#endif /* __AA_PATH_H */
diff --git a/security/apparmor/include/policy.h b/security/apparmor/include/policy.h
new file mode 100644
index 00000000000..aeda5cf5690
--- /dev/null
+++ b/security/apparmor/include/policy.h
@@ -0,0 +1,305 @@
+/*
+ * AppArmor security module
+ *
+ * This file contains AppArmor policy definitions.
+ *
+ * Copyright (C) 1998-2008 Novell/SUSE
+ * Copyright 2009-2010 Canonical Ltd.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2 of the
+ * License.
+ */
+
+#ifndef __AA_POLICY_H
+#define __AA_POLICY_H
+
+#include <linux/capability.h>
+#include <linux/cred.h>
+#include <linux/kref.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/socket.h>
+
+#include "apparmor.h"
+#include "audit.h"
+#include "capability.h"
+#include "domain.h"
+#include "file.h"
+#include "resource.h"
+
+extern const char *profile_mode_names[];
+#define APPARMOR_NAMES_MAX_INDEX 3
+
+#define COMPLAIN_MODE(_profile) \
+ ((aa_g_profile_mode == APPARMOR_COMPLAIN) || \
+ ((_profile)->mode == APPARMOR_COMPLAIN))
+
+#define KILL_MODE(_profile) \
+ ((aa_g_profile_mode == APPARMOR_KILL) || \
+ ((_profile)->mode == APPARMOR_KILL))
+
+#define PROFILE_IS_HAT(_profile) ((_profile)->flags & PFLAG_HAT)
+
+/*
+ * FIXME: currently need a clean way to replace and remove profiles as a
+ * set. It should be done at the namespace level.
+ * Either, with a set of profiles loaded at the namespace level or via
+ * a mark and remove marked interface.
+ */
+enum profile_mode {
+ APPARMOR_ENFORCE, /* enforce access rules */
+ APPARMOR_COMPLAIN, /* allow and log access violations */
+ APPARMOR_KILL, /* kill task on access violation */
+};
+
+enum profile_flags {
+ PFLAG_HAT = 1, /* profile is a hat */
+ PFLAG_UNCONFINED = 2, /* profile is an unconfined profile */
+ PFLAG_NULL = 4, /* profile is null learning profile */
+ PFLAG_IX_ON_NAME_ERROR = 8, /* fallback to ix on name lookup fail */
+ PFLAG_IMMUTABLE = 0x10, /* don't allow changes/replacement */
+ PFLAG_USER_DEFINED = 0x20, /* user based profile - lower privs */
+ PFLAG_NO_LIST_REF = 0x40, /* list doesn't keep profile ref */
+ PFLAG_OLD_NULL_TRANS = 0x100, /* use // as the null transition */
+
+ /* These flags must correspond with PATH_flags */
+ PFLAG_MEDIATE_DELETED = 0x10000, /* mediate instead delegate deleted */
+};
+
+struct aa_profile;
+
+/* struct aa_policy - common part of both namespaces and profiles
+ * @name: name of the object
+ * @hname - The hierarchical name
+ * @count: reference count of the obj
+ * @list: list policy object is on
+ * @profiles: head of the profiles list contained in the object
+ */
+struct aa_policy {
+ char *name;
+ char *hname;
+ struct kref count;
+ struct list_head list;
+ struct list_head profiles;
+};
+
+/* struct aa_ns_acct - accounting of profiles in namespace
+ * @max_size: maximum space allowed for all profiles in namespace
+ * @max_count: maximum number of profiles that can be in this namespace
+ * @size: current size of profiles
+ * @count: current count of profiles (includes null profiles)
+ */
+struct aa_ns_acct {
+ int max_size;
+ int max_count;
+ int size;
+ int count;
+};
+
+/* struct aa_namespace - namespace for a set of profiles
+ * @base: common policy
+ * @parent: parent of namespace
+ * @lock: lock for modifying the object
+ * @acct: accounting for the namespace
+ * @unconfined: special unconfined profile for the namespace
+ * @sub_ns: list of namespaces under the current namespace.
+ *
+ * An aa_namespace defines the set profiles that are searched to determine
+ * which profile to attach to a task. Profiles can not be shared between
+ * aa_namespaces and profile names within a namespace are guaranteed to be
+ * unique. When profiles in separate namespaces have the same name they
+ * are NOT considered to be equivalent.
+ *
+ * Namespaces are hierarchical and only namespaces and profiles below the
+ * current namespace are visible.
+ *
+ * Namespace names must be unique and can not contain the characters :/\0
+ *
+ * FIXME TODO: add vserver support of namespaces (can it all be done in
+ * userspace?)
+ */
+struct aa_namespace {
+ struct aa_policy base;
+ struct aa_namespace *parent;
+ rwlock_t lock;
+ struct aa_ns_acct acct;
+ struct aa_profile *unconfined;
+ struct list_head sub_ns;
+};
+
+/* struct aa_profile - basic confinement data
+ * @base - base components of the profile (name, refcount, lists, lock ...)
+ * @parent: parent of profile
+ * @ns: namespace the profile is in
+ * @replacedby: is set to the profile that replaced this profile
+ * @rename: optional profile name that this profile renamed
+ * @xmatch: optional extended matching for unconfined executables names
+ * @xmatch_len: xmatch prefix len, used to determine xmatch priority
+ * @sid: the unique security id number of this profile
+ * @audit: the auditing mode of the profile
+ * @mode: the enforcement mode of the profile
+ * @flags: flags controlling profile behavior
+ * @path_flags: flags controlling path generation behavior
+ * @size: the memory consumed by this profiles rules
+ * @file: The set of rules governing basic file access and domain transitions
+ * @caps: capabilities for the profile
+ * @rlimits: rlimits for the profile
+ *
+ * The AppArmor profile contains the basic confinement data. Each profile
+ * has a name, and exists in a namespace. The @name and @exec_match are
+ * used to determine profile attachment against unconfined tasks. All other
+ * attachments are determined by profile X transition rules.
+ *
+ * The @replacedby field is write protected by the profile lock. Reads
+ * are assumed to be atomic, and are done without locking.
+ *
+ * Profiles have a hierarchy where hats and children profiles keep
+ * a reference to their parent.
+ *
+ * Profile names can not begin with a : and can not contain the \0
+ * character. If a profile name begins with / it will be considered when
+ * determining profile attachment on "unconfined" tasks.
+ */
+struct aa_profile {
+ struct aa_policy base;
+ struct aa_profile *parent;
+
+ struct aa_namespace *ns;
+ struct aa_profile *replacedby;
+ const char *rename;
+
+ struct aa_dfa *xmatch;
+ int xmatch_len;
+ u32 sid;
+ enum audit_mode audit;
+ enum profile_mode mode;
+ u32 flags;
+ u32 path_flags;
+ int size;
+
+ struct aa_file_rules file;
+ struct aa_caps caps;
+ struct aa_rlimit rlimits;
+};
+
+extern struct aa_namespace *root_ns;
+extern enum profile_mode aa_g_profile_mode;
+
+void aa_add_profile(struct aa_policy *common, struct aa_profile *profile);
+
+bool aa_ns_visible(struct aa_namespace *curr, struct aa_namespace *view);
+const char *aa_ns_name(struct aa_namespace *parent, struct aa_namespace *child);
+int aa_alloc_root_ns(void);
+void aa_free_root_ns(void);
+void aa_free_namespace_kref(struct kref *kref);
+
+struct aa_namespace *aa_find_namespace(struct aa_namespace *root,
+ const char *name);
+
+static inline struct aa_policy *aa_get_common(struct aa_policy *c)
+{
+ if (c)
+ kref_get(&c->count);
+
+ return c;
+}
+
+/**
+ * aa_get_namespace - increment references count on @ns
+ * @ns: namespace to increment reference count of (MAYBE NULL)
+ *
+ * Returns: pointer to @ns, if @ns is NULL returns NULL
+ * Requires: @ns must be held with valid refcount when called
+ */
+static inline struct aa_namespace *aa_get_namespace(struct aa_namespace *ns)
+{
+ if (ns)
+ kref_get(&(ns->base.count));
+
+ return ns;
+}
+
+/**
+ * aa_put_namespace - decrement refcount on @ns
+ * @ns: namespace to put reference of
+ *
+ * Decrement reference count of @ns and if no longer in use free it
+ */
+static inline void aa_put_namespace(struct aa_namespace *ns)
+{
+ if (ns)
+ kref_put(&ns->base.count, aa_free_namespace_kref);
+}
+
+struct aa_profile *aa_alloc_profile(const char *name);
+struct aa_profile *aa_new_null_profile(struct aa_profile *parent, int hat);
+void aa_free_profile_kref(struct kref *kref);
+struct aa_profile *aa_find_child(struct aa_profile *parent, const char *name);
+struct aa_profile *aa_lookup_profile(struct aa_namespace *ns, const char *name);
+struct aa_profile *aa_match_profile(struct aa_namespace *ns, const char *name);
+
+ssize_t aa_replace_profiles(void *udata, size_t size, bool noreplace);
+ssize_t aa_remove_profiles(char *name, size_t size);
+
+#define PROF_ADD 1
+#define PROF_REPLACE 0
+
+#define unconfined(X) ((X)->flags & PFLAG_UNCONFINED)
+
+/**
+ * aa_newest_version - find the newest version of @profile
+ * @profile: the profile to check for newer versions of (NOT NULL)
+ *
+ * Returns: newest version of @profile, if @profile is the newest version
+ * return @profile.
+ *
+ * NOTE: the profile returned is not refcounted, The refcount on @profile
+ * must be held until the caller decides what to do with the returned newest
+ * version.
+ */
+static inline struct aa_profile *aa_newest_version(struct aa_profile *profile)
+{
+ while (profile->replacedby)
+ profile = profile->replacedby;
+
+ return profile;
+}
+
+/**
+ * aa_get_profile - increment refcount on profile @p
+ * @p: profile (MAYBE NULL)
+ *
+ * Returns: pointer to @p if @p is NULL will return NULL
+ * Requires: @p must be held with valid refcount when called
+ */
+static inline struct aa_profile *aa_get_profile(struct aa_profile *p)
+{
+ if (p)
+ kref_get(&(p->base.count));
+
+ return p;
+}
+
+/**
+ * aa_put_profile - decrement refcount on profile @p
+ * @p: profile (MAYBE NULL)
+ */
+static inline void aa_put_profile(struct aa_profile *p)
+{
+ if (p)
+ kref_put(&p->base.count, aa_free_profile_kref);
+}
+
+static inline int AUDIT_MODE(struct aa_profile *profile)
+{
+ if (aa_g_audit != AUDIT_NORMAL)
+ return aa_g_audit;
+
+ return profile->audit;
+}
+
+bool aa_may_manage_policy(int op);
+
+#endif /* __AA_POLICY_H */
diff --git a/security/apparmor/include/policy_unpack.h b/security/apparmor/include/policy_unpack.h
new file mode 100644
index 00000000000..a2dcccac45a
--- /dev/null
+++ b/security/apparmor/include/policy_unpack.h
@@ -0,0 +1,20 @@
+/*
+ * AppArmor security module
+ *
+ * This file contains AppArmor policy loading interface function definitions.
+ *
+ * Copyright (C) 1998-2008 Novell/SUSE
+ * Copyright 2009-2010 Canonical Ltd.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2 of the
+ * License.
+ */
+
+#ifndef __POLICY_INTERFACE_H
+#define __POLICY_INTERFACE_H
+
+struct aa_profile *aa_unpack(void *udata, size_t size, const char **ns);
+
+#endif /* __POLICY_INTERFACE_H */
diff --git a/security/apparmor/include/procattr.h b/security/apparmor/include/procattr.h
new file mode 100644
index 00000000000..544aa6b766a
--- /dev/null
+++ b/security/apparmor/include/procattr.h
@@ -0,0 +1,26 @@
+/*
+ * AppArmor security module
+ *
+ * This file contains AppArmor /proc/<pid>/attr/ interface function definitions.
+ *
+ * Copyright (C) 1998-2008 Novell/SUSE
+ * Copyright 2009-2010 Canonical Ltd.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2 of the
+ * License.
+ */
+
+#ifndef __AA_PROCATTR_H
+#define __AA_PROCATTR_H
+
+#define AA_DO_TEST 1
+#define AA_ONEXEC 1
+
+int aa_getprocattr(struct aa_profile *profile, char **string);
+int aa_setprocattr_changehat(char *args, size_t size, int test);
+int aa_setprocattr_changeprofile(char *fqname, bool onexec, int test);
+int aa_setprocattr_permipc(char *fqname);
+
+#endif /* __AA_PROCATTR_H */
diff --git a/security/apparmor/include/resource.h b/security/apparmor/include/resource.h
new file mode 100644
index 00000000000..3c88be94649
--- /dev/null
+++ b/security/apparmor/include/resource.h
@@ -0,0 +1,46 @@
+/*
+ * AppArmor security module
+ *
+ * This file contains AppArmor resource limits function definitions.
+ *
+ * Copyright (C) 1998-2008 Novell/SUSE
+ * Copyright 2009-2010 Canonical Ltd.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2 of the
+ * License.
+ */
+
+#ifndef __AA_RESOURCE_H
+#define __AA_RESOURCE_H
+
+#include <linux/resource.h>
+#include <linux/sched.h>
+
+struct aa_profile;
+
+/* struct aa_rlimit - rlimit settings for the profile
+ * @mask: which hard limits to set
+ * @limits: rlimit values that override task limits
+ *
+ * AppArmor rlimits are used to set confined task rlimits. Only the
+ * limits specified in @mask will be controlled by apparmor.
+ */
+struct aa_rlimit {
+ unsigned int mask;
+ struct rlimit limits[RLIM_NLIMITS];
+};
+
+int aa_map_resource(int resource);
+int aa_task_setrlimit(struct aa_profile *profile, unsigned int resource,
+ struct rlimit *new_rlim);
+
+void __aa_transition_rlimits(struct aa_profile *old, struct aa_profile *new);
+
+static inline void aa_free_rlimit_rules(struct aa_rlimit *rlims)
+{
+ /* NOP */
+}
+
+#endif /* __AA_RESOURCE_H */
diff --git a/security/apparmor/include/sid.h b/security/apparmor/include/sid.h
new file mode 100644
index 00000000000..020db35c301
--- /dev/null
+++ b/security/apparmor/include/sid.h
@@ -0,0 +1,24 @@
+/*
+ * AppArmor security module
+ *
+ * This file contains AppArmor security identifier (sid) definitions
+ *
+ * Copyright 2009-2010 Canonical Ltd.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2 of the
+ * License.
+ */
+
+#ifndef __AA_SID_H
+#define __AA_SID_H
+
+#include <linux/types.h>
+
+struct aa_profile;
+
+u32 aa_alloc_sid(void);
+void aa_free_sid(u32 sid);
+
+#endif /* __AA_SID_H */
diff --git a/security/apparmor/ipc.c b/security/apparmor/ipc.c
new file mode 100644
index 00000000000..649fad88869
--- /dev/null
+++ b/security/apparmor/ipc.c
@@ -0,0 +1,114 @@
+/*
+ * AppArmor security module
+ *
+ * This file contains AppArmor ipc mediation
+ *
+ * Copyright (C) 1998-2008 Novell/SUSE
+ * Copyright 2009-2010 Canonical Ltd.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2 of the
+ * License.
+ */
+
+#include <linux/gfp.h>
+#include <linux/ptrace.h>
+
+#include "include/audit.h"
+#include "include/capability.h"
+#include "include/context.h"
+#include "include/policy.h"
+
+/* call back to audit ptrace fields */
+static void audit_cb(struct audit_buffer *ab, void *va)
+{
+ struct common_audit_data *sa = va;
+ audit_log_format(ab, " target=");
+ audit_log_untrustedstring(ab, sa->aad.target);
+}
+
+/**
+ * aa_audit_ptrace - do auditing for ptrace
+ * @profile: profile being enforced (NOT NULL)
+ * @target: profile being traced (NOT NULL)
+ * @error: error condition
+ *
+ * Returns: %0 or error code
+ */
+static int aa_audit_ptrace(struct aa_profile *profile,
+ struct aa_profile *target, int error)
+{
+ struct common_audit_data sa;
+ COMMON_AUDIT_DATA_INIT(&sa, NONE);
+ sa.aad.op = OP_PTRACE;
+ sa.aad.target = target;
+ sa.aad.error = error;
+
+ return aa_audit(AUDIT_APPARMOR_AUTO, profile, GFP_ATOMIC, &sa,
+ audit_cb);
+}
+
+/**
+ * aa_may_ptrace - test if tracer task can trace the tracee
+ * @tracer_task: task who will do the tracing (NOT NULL)
+ * @tracer: profile of the task doing the tracing (NOT NULL)
+ * @tracee: task to be traced
+ * @mode: whether PTRACE_MODE_READ || PTRACE_MODE_ATTACH
+ *
+ * Returns: %0 else error code if permission denied or error
+ */
+int aa_may_ptrace(struct task_struct *tracer_task, struct aa_profile *tracer,
+ struct aa_profile *tracee, unsigned int mode)
+{
+ /* TODO: currently only based on capability, not extended ptrace
+ * rules,
+ * Test mode for PTRACE_MODE_READ || PTRACE_MODE_ATTACH
+ */
+
+ if (unconfined(tracer) || tracer == tracee)
+ return 0;
+ /* log this capability request */
+ return aa_capable(tracer_task, tracer, CAP_SYS_PTRACE, 1);
+}
+
+/**
+ * aa_ptrace - do ptrace permission check and auditing
+ * @tracer: task doing the tracing (NOT NULL)
+ * @tracee: task being traced (NOT NULL)
+ * @mode: ptrace mode either PTRACE_MODE_READ || PTRACE_MODE_ATTACH
+ *
+ * Returns: %0 else error code if permission denied or error
+ */
+int aa_ptrace(struct task_struct *tracer, struct task_struct *tracee,
+ unsigned int mode)
+{
+ /*
+ * tracer can ptrace tracee when
+ * - tracer is unconfined ||
+ * - tracer is in complain mode
+ * - tracer has rules allowing it to trace tracee currently this is:
+ * - confined by the same profile ||
+ * - tracer profile has CAP_SYS_PTRACE
+ */
+
+ struct aa_profile *tracer_p;
+ /* cred released below */
+ const struct cred *cred = get_task_cred(tracer);
+ int error = 0;
+ tracer_p = aa_cred_profile(cred);
+
+ if (!unconfined(tracer_p)) {
+ /* lcred released below */
+ const struct cred *lcred = get_task_cred(tracee);
+ struct aa_profile *tracee_p = aa_cred_profile(lcred);
+
+ error = aa_may_ptrace(tracer, tracer_p, tracee_p, mode);
+ error = aa_audit_ptrace(tracer_p, tracee_p, error);
+
+ put_cred(lcred);
+ }
+ put_cred(cred);
+
+ return error;
+}
diff --git a/security/apparmor/lib.c b/security/apparmor/lib.c
new file mode 100644
index 00000000000..6e85cdb4303
--- /dev/null
+++ b/security/apparmor/lib.c
@@ -0,0 +1,133 @@
+/*
+ * AppArmor security module
+ *
+ * This file contains basic common functions used in AppArmor
+ *
+ * Copyright (C) 1998-2008 Novell/SUSE
+ * Copyright 2009-2010 Canonical Ltd.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2 of the
+ * License.
+ */
+
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/vmalloc.h>
+
+#include "include/audit.h"
+
+
+/**
+ * aa_split_fqname - split a fqname into a profile and namespace name
+ * @fqname: a full qualified name in namespace profile format (NOT NULL)
+ * @ns_name: pointer to portion of the string containing the ns name (NOT NULL)
+ *
+ * Returns: profile name or NULL if one is not specified
+ *
+ * Split a namespace name from a profile name (see policy.c for naming
+ * description). If a portion of the name is missing it returns NULL for
+ * that portion.
+ *
+ * NOTE: may modify the @fqname string. The pointers returned point
+ * into the @fqname string.
+ */
+char *aa_split_fqname(char *fqname, char **ns_name)
+{
+ char *name = strim(fqname);
+
+ *ns_name = NULL;
+ if (name[0] == ':') {
+ char *split = strchr(&name[1], ':');
+ if (split) {
+ /* overwrite ':' with \0 */
+ *split = 0;
+ name = skip_spaces(split + 1);
+ } else
+ /* a ns name without a following profile is allowed */
+ name = NULL;
+ *ns_name = &name[1];
+ }
+ if (name && *name == 0)
+ name = NULL;
+
+ return name;
+}
+
+/**
+ * aa_info_message - log a none profile related status message
+ * @str: message to log
+ */
+void aa_info_message(const char *str)
+{
+ if (audit_enabled) {
+ struct common_audit_data sa;
+ COMMON_AUDIT_DATA_INIT(&sa, NONE);
+ sa.aad.info = str;
+ aa_audit_msg(AUDIT_APPARMOR_STATUS, &sa, NULL);
+ }
+ printk(KERN_INFO "AppArmor: %s\n", str);
+}
+
+/**
+ * kvmalloc - do allocation preferring kmalloc but falling back to vmalloc
+ * @size: size of allocation
+ *
+ * Return: allocated buffer or NULL if failed
+ *
+ * It is possible that policy being loaded from the user is larger than
+ * what can be allocated by kmalloc, in those cases fall back to vmalloc.
+ */
+void *kvmalloc(size_t size)
+{
+ void *buffer = NULL;
+
+ if (size == 0)
+ return NULL;
+
+ /* do not attempt kmalloc if we need more than 16 pages at once */
+ if (size <= (16*PAGE_SIZE))
+ buffer = kmalloc(size, GFP_NOIO | __GFP_NOWARN);
+ if (!buffer) {
+ /* see kvfree for why size must be at least work_struct size
+ * when allocated via vmalloc
+ */
+ if (size < sizeof(struct work_struct))
+ size = sizeof(struct work_struct);
+ buffer = vmalloc(size);
+ }
+ return buffer;
+}
+
+/**
+ * do_vfree - workqueue routine for freeing vmalloced memory
+ * @work: data to be freed
+ *
+ * The work_struct is overlaid to the data being freed, as at the point
+ * the work is scheduled the data is no longer valid, be its freeing
+ * needs to be delayed until safe.
+ */
+static void do_vfree(struct work_struct *work)
+{
+ vfree(work);
+}
+
+/**
+ * kvfree - free an allocation do by kvmalloc
+ * @buffer: buffer to free (MAYBE_NULL)
+ *
+ * Free a buffer allocated by kvmalloc
+ */
+void kvfree(void *buffer)
+{
+ if (is_vmalloc_addr(buffer)) {
+ /* Data is no longer valid so just use the allocated space
+ * as the work_struct
+ */
+ struct work_struct *work = (struct work_struct *) buffer;
+ INIT_WORK(work, do_vfree);
+ schedule_work(work);
+ } else
+ kfree(buffer);
+}
diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c
new file mode 100644
index 00000000000..8db33a8b50c
--- /dev/null
+++ b/security/apparmor/lsm.c
@@ -0,0 +1,938 @@
+/*
+ * AppArmor security module
+ *
+ * This file contains AppArmor LSM hooks.
+ *
+ * Copyright (C) 1998-2008 Novell/SUSE
+ * Copyright 2009-2010 Canonical Ltd.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2 of the
+ * License.
+ */
+
+#include <linux/security.h>
+#include <linux/moduleparam.h>
+#include <linux/mm.h>
+#include <linux/mman.h>
+#include <linux/mount.h>
+#include <linux/namei.h>
+#include <linux/ptrace.h>
+#include <linux/ctype.h>
+#include <linux/sysctl.h>
+#include <linux/audit.h>
+#include <net/sock.h>
+
+#include "include/apparmor.h"
+#include "include/apparmorfs.h"
+#include "include/audit.h"
+#include "include/capability.h"
+#include "include/context.h"
+#include "include/file.h"
+#include "include/ipc.h"
+#include "include/path.h"
+#include "include/policy.h"
+#include "include/procattr.h"
+
+/* Flag indicating whether initialization completed */
+int apparmor_initialized __initdata;
+
+/*
+ * LSM hook functions
+ */
+
+/*
+ * free the associated aa_task_cxt and put its profiles
+ */
+static void apparmor_cred_free(struct cred *cred)
+{
+ aa_free_task_context(cred->security);
+ cred->security = NULL;
+}
+
+/*
+ * allocate the apparmor part of blank credentials
+ */
+static int apparmor_cred_alloc_blank(struct cred *cred, gfp_t gfp)
+{
+ /* freed by apparmor_cred_free */
+ struct aa_task_cxt *cxt = aa_alloc_task_context(gfp);
+ if (!cxt)
+ return -ENOMEM;
+
+ cred->security = cxt;
+ return 0;
+}
+
+/*
+ * prepare new aa_task_cxt for modification by prepare_cred block
+ */
+static int apparmor_cred_prepare(struct cred *new, const struct cred *old,
+ gfp_t gfp)
+{
+ /* freed by apparmor_cred_free */
+ struct aa_task_cxt *cxt = aa_alloc_task_context(gfp);
+ if (!cxt)
+ return -ENOMEM;
+
+ aa_dup_task_context(cxt, old->security);
+ new->security = cxt;
+ return 0;
+}
+
+/*
+ * transfer the apparmor data to a blank set of creds
+ */
+static void apparmor_cred_transfer(struct cred *new, const struct cred *old)
+{
+ const struct aa_task_cxt *old_cxt = old->security;
+ struct aa_task_cxt *new_cxt = new->security;
+
+ aa_dup_task_context(new_cxt, old_cxt);
+}
+
+static int apparmor_ptrace_access_check(struct task_struct *child,
+ unsigned int mode)
+{
+ int error = cap_ptrace_access_check(child, mode);
+ if (error)
+ return error;
+
+ return aa_ptrace(current, child, mode);
+}
+
+static int apparmor_ptrace_traceme(struct task_struct *parent)
+{
+ int error = cap_ptrace_traceme(parent);
+ if (error)
+ return error;
+
+ return aa_ptrace(parent, current, PTRACE_MODE_ATTACH);
+}
+
+/* Derived from security/commoncap.c:cap_capget */
+static int apparmor_capget(struct task_struct *target, kernel_cap_t *effective,
+ kernel_cap_t *inheritable, kernel_cap_t *permitted)
+{
+ struct aa_profile *profile;
+ const struct cred *cred;
+
+ rcu_read_lock();
+ cred = __task_cred(target);
+ profile = aa_cred_profile(cred);
+
+ *effective = cred->cap_effective;
+ *inheritable = cred->cap_inheritable;
+ *permitted = cred->cap_permitted;
+
+ if (!unconfined(profile)) {
+ *effective = cap_intersect(*effective, profile->caps.allow);
+ *permitted = cap_intersect(*permitted, profile->caps.allow);
+ }
+ rcu_read_unlock();
+
+ return 0;
+}
+
+static int apparmor_capable(struct task_struct *task, const struct cred *cred,
+ int cap, int audit)
+{
+ struct aa_profile *profile;
+ /* cap_capable returns 0 on success, else -EPERM */
+ int error = cap_capable(task, cred, cap, audit);
+ if (!error) {
+ profile = aa_cred_profile(cred);
+ if (!unconfined(profile))
+ error = aa_capable(task, profile, cap, audit);
+ }
+ return error;
+}
+
+/**
+ * common_perm - basic common permission check wrapper fn for paths
+ * @op: operation being checked
+ * @path: path to check permission of (NOT NULL)
+ * @mask: requested permissions mask
+ * @cond: conditional info for the permission request (NOT NULL)
+ *
+ * Returns: %0 else error code if error or permission denied
+ */
+static int common_perm(int op, struct path *path, u32 mask,
+ struct path_cond *cond)
+{
+ struct aa_profile *profile;
+ int error = 0;
+
+ profile = __aa_current_profile();
+ if (!unconfined(profile))
+ error = aa_path_perm(op, profile, path, 0, mask, cond);
+
+ return error;
+}
+
+/**
+ * common_perm_dir_dentry - common permission wrapper when path is dir, dentry
+ * @op: operation being checked
+ * @dir: directory of the dentry (NOT NULL)
+ * @dentry: dentry to check (NOT NULL)
+ * @mask: requested permissions mask
+ * @cond: conditional info for the permission request (NOT NULL)
+ *
+ * Returns: %0 else error code if error or permission denied
+ */
+static int common_perm_dir_dentry(int op, struct path *dir,
+ struct dentry *dentry, u32 mask,
+ struct path_cond *cond)
+{
+ struct path path = { dir->mnt, dentry };
+
+ return common_perm(op, &path, mask, cond);
+}
+
+/**
+ * common_perm_mnt_dentry - common permission wrapper when mnt, dentry
+ * @op: operation being checked
+ * @mnt: mount point of dentry (NOT NULL)
+ * @dentry: dentry to check (NOT NULL)
+ * @mask: requested permissions mask
+ *
+ * Returns: %0 else error code if error or permission denied
+ */
+static int common_perm_mnt_dentry(int op, struct vfsmount *mnt,
+ struct dentry *dentry, u32 mask)
+{
+ struct path path = { mnt, dentry };
+ struct path_cond cond = { dentry->d_inode->i_uid,
+ dentry->d_inode->i_mode
+ };
+
+ return common_perm(op, &path, mask, &cond);
+}
+
+/**
+ * common_perm_rm - common permission wrapper for operations doing rm
+ * @op: operation being checked
+ * @dir: directory that the dentry is in (NOT NULL)
+ * @dentry: dentry being rm'd (NOT NULL)
+ * @mask: requested permission mask
+ *
+ * Returns: %0 else error code if error or permission denied
+ */
+static int common_perm_rm(int op, struct path *dir,
+ struct dentry *dentry, u32 mask)
+{
+ struct inode *inode = dentry->d_inode;
+ struct path_cond cond = { };
+
+ if (!inode || !dir->mnt || !mediated_filesystem(inode))
+ return 0;
+
+ cond.uid = inode->i_uid;
+ cond.mode = inode->i_mode;
+
+ return common_perm_dir_dentry(op, dir, dentry, mask, &cond);
+}
+
+/**
+ * common_perm_create - common permission wrapper for operations doing create
+ * @op: operation being checked
+ * @dir: directory that dentry will be created in (NOT NULL)
+ * @dentry: dentry to create (NOT NULL)
+ * @mask: request permission mask
+ * @mode: created file mode
+ *
+ * Returns: %0 else error code if error or permission denied
+ */
+static int common_perm_create(int op, struct path *dir, struct dentry *dentry,
+ u32 mask, umode_t mode)
+{
+ struct path_cond cond = { current_fsuid(), mode };
+
+ if (!dir->mnt || !mediated_filesystem(dir->dentry->d_inode))
+ return 0;
+
+ return common_perm_dir_dentry(op, dir, dentry, mask, &cond);
+}
+
+static int apparmor_path_unlink(struct path *dir, struct dentry *dentry)
+{
+ return common_perm_rm(OP_UNLINK, dir, dentry, AA_MAY_DELETE);
+}
+
+static int apparmor_path_mkdir(struct path *dir, struct dentry *dentry,
+ int mode)
+{
+ return common_perm_create(OP_MKDIR, dir, dentry, AA_MAY_CREATE,
+ S_IFDIR);
+}
+
+static int apparmor_path_rmdir(struct path *dir, struct dentry *dentry)
+{
+ return common_perm_rm(OP_RMDIR, dir, dentry, AA_MAY_DELETE);
+}
+
+static int apparmor_path_mknod(struct path *dir, struct dentry *dentry,
+ int mode, unsigned int dev)
+{
+ return common_perm_create(OP_MKNOD, dir, dentry, AA_MAY_CREATE, mode);
+}
+
+static int apparmor_path_truncate(struct path *path)
+{
+ struct path_cond cond = { path->dentry->d_inode->i_uid,
+ path->dentry->d_inode->i_mode
+ };
+
+ if (!path->mnt || !mediated_filesystem(path->dentry->d_inode))
+ return 0;
+
+ return common_perm(OP_TRUNC, path, MAY_WRITE | AA_MAY_META_WRITE,
+ &cond);
+}
+
+static int apparmor_path_symlink(struct path *dir, struct dentry *dentry,
+ const char *old_name)
+{
+ return common_perm_create(OP_SYMLINK, dir, dentry, AA_MAY_CREATE,
+ S_IFLNK);
+}
+
+static int apparmor_path_link(struct dentry *old_dentry, struct path *new_dir,
+ struct dentry *new_dentry)
+{
+ struct aa_profile *profile;
+ int error = 0;
+
+ if (!mediated_filesystem(old_dentry->d_inode))
+ return 0;
+
+ profile = aa_current_profile();
+ if (!unconfined(profile))
+ error = aa_path_link(profile, old_dentry, new_dir, new_dentry);
+ return error;
+}
+
+static int apparmor_path_rename(struct path *old_dir, struct dentry *old_dentry,
+ struct path *new_dir, struct dentry *new_dentry)
+{
+ struct aa_profile *profile;
+ int error = 0;
+
+ if (!mediated_filesystem(old_dentry->d_inode))
+ return 0;
+
+ profile = aa_current_profile();
+ if (!unconfined(profile)) {
+ struct path old_path = { old_dir->mnt, old_dentry };
+ struct path new_path = { new_dir->mnt, new_dentry };
+ struct path_cond cond = { old_dentry->d_inode->i_uid,
+ old_dentry->d_inode->i_mode
+ };
+
+ error = aa_path_perm(OP_RENAME_SRC, profile, &old_path, 0,
+ MAY_READ | AA_MAY_META_READ | MAY_WRITE |
+ AA_MAY_META_WRITE | AA_MAY_DELETE,
+ &cond);
+ if (!error)
+ error = aa_path_perm(OP_RENAME_DEST, profile, &new_path,
+ 0, MAY_WRITE | AA_MAY_META_WRITE |
+ AA_MAY_CREATE, &cond);
+
+ }
+ return error;
+}
+
+static int apparmor_path_chmod(struct dentry *dentry, struct vfsmount *mnt,
+ mode_t mode)
+{
+ if (!mediated_filesystem(dentry->d_inode))
+ return 0;
+
+ return common_perm_mnt_dentry(OP_CHMOD, mnt, dentry, AA_MAY_CHMOD);
+}
+
+static int apparmor_path_chown(struct path *path, uid_t uid, gid_t gid)
+{
+ struct path_cond cond = { path->dentry->d_inode->i_uid,
+ path->dentry->d_inode->i_mode
+ };
+
+ if (!mediated_filesystem(path->dentry->d_inode))
+ return 0;
+
+ return common_perm(OP_CHOWN, path, AA_MAY_CHOWN, &cond);
+}
+
+static int apparmor_inode_getattr(struct vfsmount *mnt, struct dentry *dentry)
+{
+ if (!mediated_filesystem(dentry->d_inode))
+ return 0;
+
+ return common_perm_mnt_dentry(OP_GETATTR, mnt, dentry,
+ AA_MAY_META_READ);
+}
+
+static int apparmor_dentry_open(struct file *file, const struct cred *cred)
+{
+ struct aa_file_cxt *fcxt = file->f_security;
+ struct aa_profile *profile;
+ int error = 0;
+
+ if (!mediated_filesystem(file->f_path.dentry->d_inode))
+ return 0;
+
+ /* If in exec, permission is handled by bprm hooks.
+ * Cache permissions granted by the previous exec check, with
+ * implicit read and executable mmap which are required to
+ * actually execute the image.
+ */
+ if (current->in_execve) {
+ fcxt->allow = MAY_EXEC | MAY_READ | AA_EXEC_MMAP;
+ return 0;
+ }
+
+ profile = aa_cred_profile(cred);
+ if (!unconfined(profile)) {
+ struct inode *inode = file->f_path.dentry->d_inode;
+ struct path_cond cond = { inode->i_uid, inode->i_mode };
+
+ error = aa_path_perm(OP_OPEN, profile, &file->f_path, 0,
+ aa_map_file_to_perms(file), &cond);
+ /* todo cache full allowed permissions set and state */
+ fcxt->allow = aa_map_file_to_perms(file);
+ }
+
+ return error;
+}
+
+static int apparmor_file_alloc_security(struct file *file)
+{
+ /* freed by apparmor_file_free_security */
+ file->f_security = aa_alloc_file_context(GFP_KERNEL);
+ if (!file->f_security)
+ return -ENOMEM;
+ return 0;
+
+}
+
+static void apparmor_file_free_security(struct file *file)
+{
+ struct aa_file_cxt *cxt = file->f_security;
+
+ aa_free_file_context(cxt);
+}
+
+static int common_file_perm(int op, struct file *file, u32 mask)
+{
+ struct aa_file_cxt *fcxt = file->f_security;
+ struct aa_profile *profile, *fprofile = aa_cred_profile(file->f_cred);
+ int error = 0;
+
+ BUG_ON(!fprofile);
+
+ if (!file->f_path.mnt ||
+ !mediated_filesystem(file->f_path.dentry->d_inode))
+ return 0;
+
+ profile = __aa_current_profile();
+
+ /* revalidate access, if task is unconfined, or the cached cred
+ * doesn't match or if the request is for more permissions than
+ * was granted.
+ *
+ * Note: the test for !unconfined(fprofile) is to handle file
+ * delegation from unconfined tasks
+ */
+ if (!unconfined(profile) && !unconfined(fprofile) &&
+ ((fprofile != profile) || (mask & ~fcxt->allow)))
+ error = aa_file_perm(op, profile, file, mask);
+
+ return error;
+}
+
+static int apparmor_file_permission(struct file *file, int mask)
+{
+ return common_file_perm(OP_FPERM, file, mask);
+}
+
+static int apparmor_file_lock(struct file *file, unsigned int cmd)
+{
+ u32 mask = AA_MAY_LOCK;
+
+ if (cmd == F_WRLCK)
+ mask |= MAY_WRITE;
+
+ return common_file_perm(OP_FLOCK, file, mask);
+}
+
+static int common_mmap(int op, struct file *file, unsigned long prot,
+ unsigned long flags)
+{
+ struct dentry *dentry;
+ int mask = 0;
+
+ if (!file || !file->f_security)
+ return 0;
+
+ if (prot & PROT_READ)
+ mask |= MAY_READ;
+ /*
+ * Private mappings don't require write perms since they don't
+ * write back to the files
+ */
+ if ((prot & PROT_WRITE) && !(flags & MAP_PRIVATE))
+ mask |= MAY_WRITE;
+ if (prot & PROT_EXEC)
+ mask |= AA_EXEC_MMAP;
+
+ dentry = file->f_path.dentry;
+ return common_file_perm(op, file, mask);
+}
+
+static int apparmor_file_mmap(struct file *file, unsigned long reqprot,
+ unsigned long prot, unsigned long flags,
+ unsigned long addr, unsigned long addr_only)
+{
+ int rc = 0;
+
+ /* do DAC check */
+ rc = cap_file_mmap(file, reqprot, prot, flags, addr, addr_only);
+ if (rc || addr_only)
+ return rc;
+
+ return common_mmap(OP_FMMAP, file, prot, flags);
+}
+
+static int apparmor_file_mprotect(struct vm_area_struct *vma,
+ unsigned long reqprot, unsigned long prot)
+{
+ return common_mmap(OP_FMPROT, vma->vm_file, prot,
+ !(vma->vm_flags & VM_SHARED) ? MAP_PRIVATE : 0);
+}
+
+static int apparmor_getprocattr(struct task_struct *task, char *name,
+ char **value)
+{
+ int error = -ENOENT;
+ struct aa_profile *profile;
+ /* released below */
+ const struct cred *cred = get_task_cred(task);
+ struct aa_task_cxt *cxt = cred->security;
+ profile = aa_cred_profile(cred);
+
+ if (strcmp(name, "current") == 0)
+ error = aa_getprocattr(aa_newest_version(cxt->profile),
+ value);
+ else if (strcmp(name, "prev") == 0 && cxt->previous)
+ error = aa_getprocattr(aa_newest_version(cxt->previous),
+ value);
+ else if (strcmp(name, "exec") == 0 && cxt->onexec)
+ error = aa_getprocattr(aa_newest_version(cxt->onexec),
+ value);
+ else
+ error = -EINVAL;
+
+ put_cred(cred);
+
+ return error;
+}
+
+static int apparmor_setprocattr(struct task_struct *task, char *name,
+ void *value, size_t size)
+{
+ char *command, *args = value;
+ size_t arg_size;
+ int error;
+
+ if (size == 0)
+ return -EINVAL;
+ /* args points to a PAGE_SIZE buffer, AppArmor requires that
+ * the buffer must be null terminated or have size <= PAGE_SIZE -1
+ * so that AppArmor can null terminate them
+ */
+ if (args[size - 1] != '\0') {
+ if (size == PAGE_SIZE)
+ return -EINVAL;
+ args[size] = '\0';
+ }
+
+ /* task can only write its own attributes */
+ if (current != task)
+ return -EACCES;
+
+ args = value;
+ args = strim(args);
+ command = strsep(&args, " ");
+ if (!args)
+ return -EINVAL;
+ args = skip_spaces(args);
+ if (!*args)
+ return -EINVAL;
+
+ arg_size = size - (args - (char *) value);
+ if (strcmp(name, "current") == 0) {
+ if (strcmp(command, "changehat") == 0) {
+ error = aa_setprocattr_changehat(args, arg_size,
+ !AA_DO_TEST);
+ } else if (strcmp(command, "permhat") == 0) {
+ error = aa_setprocattr_changehat(args, arg_size,
+ AA_DO_TEST);
+ } else if (strcmp(command, "changeprofile") == 0) {
+ error = aa_setprocattr_changeprofile(args, !AA_ONEXEC,
+ !AA_DO_TEST);
+ } else if (strcmp(command, "permprofile") == 0) {
+ error = aa_setprocattr_changeprofile(args, !AA_ONEXEC,
+ AA_DO_TEST);
+ } else if (strcmp(command, "permipc") == 0) {
+ error = aa_setprocattr_permipc(args);
+ } else {
+ struct common_audit_data sa;
+ COMMON_AUDIT_DATA_INIT(&sa, NONE);
+ sa.aad.op = OP_SETPROCATTR;
+ sa.aad.info = name;
+ sa.aad.error = -EINVAL;
+ return aa_audit(AUDIT_APPARMOR_DENIED, NULL, GFP_KERNEL,
+ &sa, NULL);
+ }
+ } else if (strcmp(name, "exec") == 0) {
+ error = aa_setprocattr_changeprofile(args, AA_ONEXEC,
+ !AA_DO_TEST);
+ } else {
+ /* only support the "current" and "exec" process attributes */
+ return -EINVAL;
+ }
+ if (!error)
+ error = size;
+ return error;
+}
+
+static int apparmor_task_setrlimit(unsigned int resource,
+ struct rlimit *new_rlim)
+{
+ struct aa_profile *profile = aa_current_profile();
+ int error = 0;
+
+ if (!unconfined(profile))
+ error = aa_task_setrlimit(profile, resource, new_rlim);
+
+ return error;
+}
+
+static struct security_operations apparmor_ops = {
+ .name = "apparmor",
+
+ .ptrace_access_check = apparmor_ptrace_access_check,
+ .ptrace_traceme = apparmor_ptrace_traceme,
+ .capget = apparmor_capget,
+ .capable = apparmor_capable,
+
+ .path_link = apparmor_path_link,
+ .path_unlink = apparmor_path_unlink,
+ .path_symlink = apparmor_path_symlink,
+ .path_mkdir = apparmor_path_mkdir,
+ .path_rmdir = apparmor_path_rmdir,
+ .path_mknod = apparmor_path_mknod,
+ .path_rename = apparmor_path_rename,
+ .path_chmod = apparmor_path_chmod,
+ .path_chown = apparmor_path_chown,
+ .path_truncate = apparmor_path_truncate,
+ .dentry_open = apparmor_dentry_open,
+ .inode_getattr = apparmor_inode_getattr,
+
+ .file_permission = apparmor_file_permission,
+ .file_alloc_security = apparmor_file_alloc_security,
+ .file_free_security = apparmor_file_free_security,
+ .file_mmap = apparmor_file_mmap,
+ .file_mprotect = apparmor_file_mprotect,
+ .file_lock = apparmor_file_lock,
+
+ .getprocattr = apparmor_getprocattr,
+ .setprocattr = apparmor_setprocattr,
+
+ .cred_alloc_blank = apparmor_cred_alloc_blank,
+ .cred_free = apparmor_cred_free,
+ .cred_prepare = apparmor_cred_prepare,
+ .cred_transfer = apparmor_cred_transfer,
+
+ .bprm_set_creds = apparmor_bprm_set_creds,
+ .bprm_committing_creds = apparmor_bprm_committing_creds,
+ .bprm_committed_creds = apparmor_bprm_committed_creds,
+ .bprm_secureexec = apparmor_bprm_secureexec,
+
+ .task_setrlimit = apparmor_task_setrlimit,
+};
+
+/*
+ * AppArmor sysfs module parameters
+ */
+
+static int param_set_aabool(const char *val, struct kernel_param *kp);
+static int param_get_aabool(char *buffer, struct kernel_param *kp);
+#define param_check_aabool(name, p) __param_check(name, p, int)
+
+static int param_set_aauint(const char *val, struct kernel_param *kp);
+static int param_get_aauint(char *buffer, struct kernel_param *kp);
+#define param_check_aauint(name, p) __param_check(name, p, int)
+
+static int param_set_aalockpolicy(const char *val, struct kernel_param *kp);
+static int param_get_aalockpolicy(char *buffer, struct kernel_param *kp);
+#define param_check_aalockpolicy(name, p) __param_check(name, p, int)
+
+static int param_set_audit(const char *val, struct kernel_param *kp);
+static int param_get_audit(char *buffer, struct kernel_param *kp);
+#define param_check_audit(name, p) __param_check(name, p, int)
+
+static int param_set_mode(const char *val, struct kernel_param *kp);
+static int param_get_mode(char *buffer, struct kernel_param *kp);
+#define param_check_mode(name, p) __param_check(name, p, int)
+
+/* Flag values, also controllable via /sys/module/apparmor/parameters
+ * We define special types as we want to do additional mediation.
+ */
+
+/* AppArmor global enforcement switch - complain, enforce, kill */
+enum profile_mode aa_g_profile_mode = APPARMOR_ENFORCE;
+module_param_call(mode, param_set_mode, param_get_mode,
+ &aa_g_profile_mode, S_IRUSR | S_IWUSR);
+
+/* Debug mode */
+int aa_g_debug;
+module_param_named(debug, aa_g_debug, aabool, S_IRUSR | S_IWUSR);
+
+/* Audit mode */
+enum audit_mode aa_g_audit;
+module_param_call(audit, param_set_audit, param_get_audit,
+ &aa_g_audit, S_IRUSR | S_IWUSR);
+
+/* Determines if audit header is included in audited messages. This
+ * provides more context if the audit daemon is not running
+ */
+int aa_g_audit_header = 1;
+module_param_named(audit_header, aa_g_audit_header, aabool,
+ S_IRUSR | S_IWUSR);
+
+/* lock out loading/removal of policy
+ * TODO: add in at boot loading of policy, which is the only way to
+ * load policy, if lock_policy is set
+ */
+int aa_g_lock_policy;
+module_param_named(lock_policy, aa_g_lock_policy, aalockpolicy,
+ S_IRUSR | S_IWUSR);
+
+/* Syscall logging mode */
+int aa_g_logsyscall;
+module_param_named(logsyscall, aa_g_logsyscall, aabool, S_IRUSR | S_IWUSR);
+
+/* Maximum pathname length before accesses will start getting rejected */
+unsigned int aa_g_path_max = 2 * PATH_MAX;
+module_param_named(path_max, aa_g_path_max, aauint, S_IRUSR | S_IWUSR);
+
+/* Determines how paranoid loading of policy is and how much verification
+ * on the loaded policy is done.
+ */
+int aa_g_paranoid_load = 1;
+module_param_named(paranoid_load, aa_g_paranoid_load, aabool,
+ S_IRUSR | S_IWUSR);
+
+/* Boot time disable flag */
+static unsigned int apparmor_enabled = CONFIG_SECURITY_APPARMOR_BOOTPARAM_VALUE;
+module_param_named(enabled, apparmor_enabled, aabool, S_IRUSR);
+
+static int __init apparmor_enabled_setup(char *str)
+{
+ unsigned long enabled;
+ int error = strict_strtoul(str, 0, &enabled);
+ if (!error)
+ apparmor_enabled = enabled ? 1 : 0;
+ return 1;
+}
+
+__setup("apparmor=", apparmor_enabled_setup);
+
+/* set global flag turning off the ability to load policy */
+static int param_set_aalockpolicy(const char *val, struct kernel_param *kp)
+{
+ if (!capable(CAP_MAC_ADMIN))
+ return -EPERM;
+ if (aa_g_lock_policy)
+ return -EACCES;
+ return param_set_bool(val, kp);
+}
+
+static int param_get_aalockpolicy(char *buffer, struct kernel_param *kp)
+{
+ if (!capable(CAP_MAC_ADMIN))
+ return -EPERM;
+ return param_get_bool(buffer, kp);
+}
+
+static int param_set_aabool(const char *val, struct kernel_param *kp)
+{
+ if (!capable(CAP_MAC_ADMIN))
+ return -EPERM;
+ return param_set_bool(val, kp);
+}
+
+static int param_get_aabool(char *buffer, struct kernel_param *kp)
+{
+ if (!capable(CAP_MAC_ADMIN))
+ return -EPERM;
+ return param_get_bool(buffer, kp);
+}
+
+static int param_set_aauint(const char *val, struct kernel_param *kp)
+{
+ if (!capable(CAP_MAC_ADMIN))
+ return -EPERM;
+ return param_set_uint(val, kp);
+}
+
+static int param_get_aauint(char *buffer, struct kernel_param *kp)
+{
+ if (!capable(CAP_MAC_ADMIN))
+ return -EPERM;
+ return param_get_uint(buffer, kp);
+}
+
+static int param_get_audit(char *buffer, struct kernel_param *kp)
+{
+ if (!capable(CAP_MAC_ADMIN))
+ return -EPERM;
+
+ if (!apparmor_enabled)
+ return -EINVAL;
+
+ return sprintf(buffer, "%s", audit_mode_names[aa_g_audit]);
+}
+
+static int param_set_audit(const char *val, struct kernel_param *kp)
+{
+ int i;
+ if (!capable(CAP_MAC_ADMIN))
+ return -EPERM;
+
+ if (!apparmor_enabled)
+ return -EINVAL;
+
+ if (!val)
+ return -EINVAL;
+
+ for (i = 0; i < AUDIT_MAX_INDEX; i++) {
+ if (strcmp(val, audit_mode_names[i]) == 0) {
+ aa_g_audit = i;
+ return 0;
+ }
+ }
+
+ return -EINVAL;
+}
+
+static int param_get_mode(char *buffer, struct kernel_param *kp)
+{
+ if (!capable(CAP_MAC_ADMIN))
+ return -EPERM;
+
+ if (!apparmor_enabled)
+ return -EINVAL;
+
+ return sprintf(buffer, "%s", profile_mode_names[aa_g_profile_mode]);
+}
+
+static int param_set_mode(const char *val, struct kernel_param *kp)
+{
+ int i;
+ if (!capable(CAP_MAC_ADMIN))
+ return -EPERM;
+
+ if (!apparmor_enabled)
+ return -EINVAL;
+
+ if (!val)
+ return -EINVAL;
+
+ for (i = 0; i < APPARMOR_NAMES_MAX_INDEX; i++) {
+ if (strcmp(val, profile_mode_names[i]) == 0) {
+ aa_g_profile_mode = i;
+ return 0;
+ }
+ }
+
+ return -EINVAL;
+}
+
+/*
+ * AppArmor init functions
+ */
+
+/**
+ * set_init_cxt - set a task context and profile on the first task.
+ *
+ * TODO: allow setting an alternate profile than unconfined
+ */
+static int __init set_init_cxt(void)
+{
+ struct cred *cred = (struct cred *)current->real_cred;
+ struct aa_task_cxt *cxt;
+
+ cxt = aa_alloc_task_context(GFP_KERNEL);
+ if (!cxt)
+ return -ENOMEM;
+
+ cxt->profile = aa_get_profile(root_ns->unconfined);
+ cred->security = cxt;
+
+ return 0;
+}
+
+static int __init apparmor_init(void)
+{
+ int error;
+
+ if (!apparmor_enabled || !security_module_enable(&apparmor_ops)) {
+ aa_info_message("AppArmor disabled by boot time parameter");
+ apparmor_enabled = 0;
+ return 0;
+ }
+
+ error = aa_alloc_root_ns();
+ if (error) {
+ AA_ERROR("Unable to allocate default profile namespace\n");
+ goto alloc_out;
+ }
+
+ error = set_init_cxt();
+ if (error) {
+ AA_ERROR("Failed to set context on init task\n");
+ goto register_security_out;
+ }
+
+ error = register_security(&apparmor_ops);
+ if (error) {
+ AA_ERROR("Unable to register AppArmor\n");
+ goto register_security_out;
+ }
+
+ /* Report that AppArmor successfully initialized */
+ apparmor_initialized = 1;
+ if (aa_g_profile_mode == APPARMOR_COMPLAIN)
+ aa_info_message("AppArmor initialized: complain mode enabled");
+ else if (aa_g_profile_mode == APPARMOR_KILL)
+ aa_info_message("AppArmor initialized: kill mode enabled");
+ else
+ aa_info_message("AppArmor initialized");
+
+ return error;
+
+register_security_out:
+ aa_free_root_ns();
+
+alloc_out:
+ aa_destroy_aafs();
+
+ apparmor_enabled = 0;
+ return error;
+
+}
+
+security_initcall(apparmor_init);
diff --git a/security/apparmor/match.c b/security/apparmor/match.c
new file mode 100644
index 00000000000..5cb4dc1f699
--- /dev/null
+++ b/security/apparmor/match.c
@@ -0,0 +1,353 @@
+/*
+ * AppArmor security module
+ *
+ * This file contains AppArmor dfa based regular expression matching engine
+ *
+ * Copyright (C) 1998-2008 Novell/SUSE
+ * Copyright 2009-2010 Canonical Ltd.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2 of the
+ * License.
+ */
+
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <linux/err.h>
+#include <linux/kref.h>
+
+#include "include/apparmor.h"
+#include "include/match.h"
+
+/**
+ * unpack_table - unpack a dfa table (one of accept, default, base, next check)
+ * @blob: data to unpack (NOT NULL)
+ * @bsize: size of blob
+ *
+ * Returns: pointer to table else NULL on failure
+ *
+ * NOTE: must be freed by kvfree (not kmalloc)
+ */
+static struct table_header *unpack_table(char *blob, size_t bsize)
+{
+ struct table_header *table = NULL;
+ struct table_header th;
+ size_t tsize;
+
+ if (bsize < sizeof(struct table_header))
+ goto out;
+
+ /* loaded td_id's start at 1, subtract 1 now to avoid doing
+ * it every time we use td_id as an index
+ */
+ th.td_id = be16_to_cpu(*(u16 *) (blob)) - 1;
+ th.td_flags = be16_to_cpu(*(u16 *) (blob + 2));
+ th.td_lolen = be32_to_cpu(*(u32 *) (blob + 8));
+ blob += sizeof(struct table_header);
+
+ if (!(th.td_flags == YYTD_DATA16 || th.td_flags == YYTD_DATA32 ||
+ th.td_flags == YYTD_DATA8))
+ goto out;
+
+ tsize = table_size(th.td_lolen, th.td_flags);
+ if (bsize < tsize)
+ goto out;
+
+ table = kvmalloc(tsize);
+ if (table) {
+ *table = th;
+ if (th.td_flags == YYTD_DATA8)
+ UNPACK_ARRAY(table->td_data, blob, th.td_lolen,
+ u8, byte_to_byte);
+ else if (th.td_flags == YYTD_DATA16)
+ UNPACK_ARRAY(table->td_data, blob, th.td_lolen,
+ u16, be16_to_cpu);
+ else if (th.td_flags == YYTD_DATA32)
+ UNPACK_ARRAY(table->td_data, blob, th.td_lolen,
+ u32, be32_to_cpu);
+ else
+ goto fail;
+ }
+
+out:
+ /* if table was vmalloced make sure the page tables are synced
+ * before it is used, as it goes live to all cpus.
+ */
+ if (is_vmalloc_addr(table))
+ vm_unmap_aliases();
+ return table;
+fail:
+ kvfree(table);
+ return NULL;
+}
+
+/**
+ * verify_dfa - verify that transitions and states in the tables are in bounds.
+ * @dfa: dfa to test (NOT NULL)
+ * @flags: flags controlling what type of accept table are acceptable
+ *
+ * Assumes dfa has gone through the first pass verification done by unpacking
+ * NOTE: this does not valid accept table values
+ *
+ * Returns: %0 else error code on failure to verify
+ */
+static int verify_dfa(struct aa_dfa *dfa, int flags)
+{
+ size_t i, state_count, trans_count;
+ int error = -EPROTO;
+
+ /* check that required tables exist */
+ if (!(dfa->tables[YYTD_ID_DEF] &&
+ dfa->tables[YYTD_ID_BASE] &&
+ dfa->tables[YYTD_ID_NXT] && dfa->tables[YYTD_ID_CHK]))
+ goto out;
+
+ /* accept.size == default.size == base.size */
+ state_count = dfa->tables[YYTD_ID_BASE]->td_lolen;
+ if (ACCEPT1_FLAGS(flags)) {
+ if (!dfa->tables[YYTD_ID_ACCEPT])
+ goto out;
+ if (state_count != dfa->tables[YYTD_ID_ACCEPT]->td_lolen)
+ goto out;
+ }
+ if (ACCEPT2_FLAGS(flags)) {
+ if (!dfa->tables[YYTD_ID_ACCEPT2])
+ goto out;
+ if (state_count != dfa->tables[YYTD_ID_ACCEPT2]->td_lolen)
+ goto out;
+ }
+ if (state_count != dfa->tables[YYTD_ID_DEF]->td_lolen)
+ goto out;
+
+ /* next.size == chk.size */
+ trans_count = dfa->tables[YYTD_ID_NXT]->td_lolen;
+ if (trans_count != dfa->tables[YYTD_ID_CHK]->td_lolen)
+ goto out;
+
+ /* if equivalence classes then its table size must be 256 */
+ if (dfa->tables[YYTD_ID_EC] &&
+ dfa->tables[YYTD_ID_EC]->td_lolen != 256)
+ goto out;
+
+ if (flags & DFA_FLAG_VERIFY_STATES) {
+ for (i = 0; i < state_count; i++) {
+ if (DEFAULT_TABLE(dfa)[i] >= state_count)
+ goto out;
+ /* TODO: do check that DEF state recursion terminates */
+ if (BASE_TABLE(dfa)[i] + 255 >= trans_count) {
+ printk(KERN_ERR "AppArmor DFA next/check upper "
+ "bounds error\n");
+ goto out;
+ }
+ }
+
+ for (i = 0; i < trans_count; i++) {
+ if (NEXT_TABLE(dfa)[i] >= state_count)
+ goto out;
+ if (CHECK_TABLE(dfa)[i] >= state_count)
+ goto out;
+ }
+ }
+
+ error = 0;
+out:
+ return error;
+}
+
+/**
+ * dfa_free - free a dfa allocated by aa_dfa_unpack
+ * @dfa: the dfa to free (MAYBE NULL)
+ *
+ * Requires: reference count to dfa == 0
+ */
+static void dfa_free(struct aa_dfa *dfa)
+{
+ if (dfa) {
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(dfa->tables); i++) {
+ kvfree(dfa->tables[i]);
+ dfa->tables[i] = NULL;
+ }
+ kfree(dfa);
+ }
+}
+
+/**
+ * aa_dfa_free_kref - free aa_dfa by kref (called by aa_put_dfa)
+ * @kr: kref callback for freeing of a dfa (NOT NULL)
+ */
+void aa_dfa_free_kref(struct kref *kref)
+{
+ struct aa_dfa *dfa = container_of(kref, struct aa_dfa, count);
+ dfa_free(dfa);
+}
+
+/**
+ * aa_dfa_unpack - unpack the binary tables of a serialized dfa
+ * @blob: aligned serialized stream of data to unpack (NOT NULL)
+ * @size: size of data to unpack
+ * @flags: flags controlling what type of accept tables are acceptable
+ *
+ * Unpack a dfa that has been serialized. To find information on the dfa
+ * format look in Documentation/apparmor.txt
+ * Assumes the dfa @blob stream has been aligned on a 8 byte boundry
+ *
+ * Returns: an unpacked dfa ready for matching or ERR_PTR on failure
+ */
+struct aa_dfa *aa_dfa_unpack(void *blob, size_t size, int flags)
+{
+ int hsize;
+ int error = -ENOMEM;
+ char *data = blob;
+ struct table_header *table = NULL;
+ struct aa_dfa *dfa = kzalloc(sizeof(struct aa_dfa), GFP_KERNEL);
+ if (!dfa)
+ goto fail;
+
+ kref_init(&dfa->count);
+
+ error = -EPROTO;
+
+ /* get dfa table set header */
+ if (size < sizeof(struct table_set_header))
+ goto fail;
+
+ if (ntohl(*(u32 *) data) != YYTH_MAGIC)
+ goto fail;
+
+ hsize = ntohl(*(u32 *) (data + 4));
+ if (size < hsize)
+ goto fail;
+
+ dfa->flags = ntohs(*(u16 *) (data + 12));
+ data += hsize;
+ size -= hsize;
+
+ while (size > 0) {
+ table = unpack_table(data, size);
+ if (!table)
+ goto fail;
+
+ switch (table->td_id) {
+ case YYTD_ID_ACCEPT:
+ if (!(table->td_flags & ACCEPT1_FLAGS(flags)))
+ goto fail;
+ break;
+ case YYTD_ID_ACCEPT2:
+ if (!(table->td_flags & ACCEPT2_FLAGS(flags)))
+ goto fail;
+ break;
+ case YYTD_ID_BASE:
+ if (table->td_flags != YYTD_DATA32)
+ goto fail;
+ break;
+ case YYTD_ID_DEF:
+ case YYTD_ID_NXT:
+ case YYTD_ID_CHK:
+ if (table->td_flags != YYTD_DATA16)
+ goto fail;
+ break;
+ case YYTD_ID_EC:
+ if (table->td_flags != YYTD_DATA8)
+ goto fail;
+ break;
+ default:
+ goto fail;
+ }
+ /* check for duplicate table entry */
+ if (dfa->tables[table->td_id])
+ goto fail;
+ dfa->tables[table->td_id] = table;
+ data += table_size(table->td_lolen, table->td_flags);
+ size -= table_size(table->td_lolen, table->td_flags);
+ table = NULL;
+ }
+
+ error = verify_dfa(dfa, flags);
+ if (error)
+ goto fail;
+
+ return dfa;
+
+fail:
+ kvfree(table);
+ dfa_free(dfa);
+ return ERR_PTR(error);
+}
+
+/**
+ * aa_dfa_match_len - traverse @dfa to find state @str stops at
+ * @dfa: the dfa to match @str against (NOT NULL)
+ * @start: the state of the dfa to start matching in
+ * @str: the string of bytes to match against the dfa (NOT NULL)
+ * @len: length of the string of bytes to match
+ *
+ * aa_dfa_match_len will match @str against the dfa and return the state it
+ * finished matching in. The final state can be used to look up the accepting
+ * label, or as the start state of a continuing match.
+ *
+ * This function will happily match again the 0 byte and only finishes
+ * when @len input is consumed.
+ *
+ * Returns: final state reached after input is consumed
+ */
+unsigned int aa_dfa_match_len(struct aa_dfa *dfa, unsigned int start,
+ const char *str, int len)
+{
+ u16 *def = DEFAULT_TABLE(dfa);
+ u32 *base = BASE_TABLE(dfa);
+ u16 *next = NEXT_TABLE(dfa);
+ u16 *check = CHECK_TABLE(dfa);
+ unsigned int state = start, pos;
+
+ if (state == 0)
+ return 0;
+
+ /* current state is <state>, matching character *str */
+ if (dfa->tables[YYTD_ID_EC]) {
+ /* Equivalence class table defined */
+ u8 *equiv = EQUIV_TABLE(dfa);
+ /* default is direct to next state */
+ for (; len; len--) {
+ pos = base[state] + equiv[(u8) *str++];
+ if (check[pos] == state)
+ state = next[pos];
+ else
+ state = def[state];
+ }
+ } else {
+ /* default is direct to next state */
+ for (; len; len--) {
+ pos = base[state] + (u8) *str++;
+ if (check[pos] == state)
+ state = next[pos];
+ else
+ state = def[state];
+ }
+ }
+
+ return state;
+}
+
+/**
+ * aa_dfa_next_state - traverse @dfa to find state @str stops at
+ * @dfa: the dfa to match @str against (NOT NULL)
+ * @start: the state of the dfa to start matching in
+ * @str: the null terminated string of bytes to match against the dfa (NOT NULL)
+ *
+ * aa_dfa_next_state will match @str against the dfa and return the state it
+ * finished matching in. The final state can be used to look up the accepting
+ * label, or as the start state of a continuing match.
+ *
+ * Returns: final state reached after input is consumed
+ */
+unsigned int aa_dfa_match(struct aa_dfa *dfa, unsigned int start,
+ const char *str)
+{
+ return aa_dfa_match_len(dfa, start, str, strlen(str));
+}
diff --git a/security/apparmor/path.c b/security/apparmor/path.c
new file mode 100644
index 00000000000..96bab9469d4
--- /dev/null
+++ b/security/apparmor/path.c
@@ -0,0 +1,235 @@
+/*
+ * AppArmor security module
+ *
+ * This file contains AppArmor function for pathnames
+ *
+ * Copyright (C) 1998-2008 Novell/SUSE
+ * Copyright 2009-2010 Canonical Ltd.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2 of the
+ * License.
+ */
+
+#include <linux/magic.h>
+#include <linux/mnt_namespace.h>
+#include <linux/mount.h>
+#include <linux/namei.h>
+#include <linux/nsproxy.h>
+#include <linux/path.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/fs_struct.h>
+
+#include "include/apparmor.h"
+#include "include/path.h"
+#include "include/policy.h"
+
+
+/* modified from dcache.c */
+static int prepend(char **buffer, int buflen, const char *str, int namelen)
+{
+ buflen -= namelen;
+ if (buflen < 0)
+ return -ENAMETOOLONG;
+ *buffer -= namelen;
+ memcpy(*buffer, str, namelen);
+ return 0;
+}
+
+#define CHROOT_NSCONNECT (PATH_CHROOT_REL | PATH_CHROOT_NSCONNECT)
+
+/**
+ * d_namespace_path - lookup a name associated with a given path
+ * @path: path to lookup (NOT NULL)
+ * @buf: buffer to store path to (NOT NULL)
+ * @buflen: length of @buf
+ * @name: Returns - pointer for start of path name with in @buf (NOT NULL)
+ * @flags: flags controlling path lookup
+ *
+ * Handle path name lookup.
+ *
+ * Returns: %0 else error code if path lookup fails
+ * When no error the path name is returned in @name which points to
+ * to a position in @buf
+ */
+static int d_namespace_path(struct path *path, char *buf, int buflen,
+ char **name, int flags)
+{
+ struct path root, tmp;
+ char *res;
+ int deleted, connected;
+ int error = 0;
+
+ /* Get the root we want to resolve too */
+ if (flags & PATH_CHROOT_REL) {
+ /* resolve paths relative to chroot */
+ read_lock(&current->fs->lock);
+ root = current->fs->root;
+ /* released below */
+ path_get(&root);
+ read_unlock(&current->fs->lock);
+ } else {
+ /* resolve paths relative to namespace */
+ root.mnt = current->nsproxy->mnt_ns->root;
+ root.dentry = root.mnt->mnt_root;
+ /* released below */
+ path_get(&root);
+ }
+
+ spin_lock(&dcache_lock);
+ /* There is a race window between path lookup here and the
+ * need to strip the " (deleted) string that __d_path applies
+ * Detect the race and relookup the path
+ *
+ * The stripping of (deleted) is a hack that could be removed
+ * with an updated __d_path
+ */
+ do {
+ tmp = root;
+ deleted = d_unlinked(path->dentry);
+ res = __d_path(path, &tmp, buf, buflen);
+
+ } while (deleted != d_unlinked(path->dentry));
+ spin_unlock(&dcache_lock);
+
+ *name = res;
+ /* handle error conditions - and still allow a partial path to
+ * be returned.
+ */
+ if (IS_ERR(res)) {
+ error = PTR_ERR(res);
+ *name = buf;
+ goto out;
+ }
+ if (deleted) {
+ /* On some filesystems, newly allocated dentries appear to the
+ * security_path hooks as a deleted dentry except without an
+ * inode allocated.
+ *
+ * Remove the appended deleted text and return as string for
+ * normal mediation, or auditing. The (deleted) string is
+ * guaranteed to be added in this case, so just strip it.
+ */
+ buf[buflen - 11] = 0; /* - (len(" (deleted)") +\0) */
+
+ if (path->dentry->d_inode && !(flags & PATH_MEDIATE_DELETED)) {
+ error = -ENOENT;
+ goto out;
+ }
+ }
+
+ /* Determine if the path is connected to the expected root */
+ connected = tmp.dentry == root.dentry && tmp.mnt == root.mnt;
+
+ /* If the path is not connected,
+ * check if it is a sysctl and handle specially else remove any
+ * leading / that __d_path may have returned.
+ * Unless
+ * specifically directed to connect the path,
+ * OR
+ * if in a chroot and doing chroot relative paths and the path
+ * resolves to the namespace root (would be connected outside
+ * of chroot) and specifically directed to connect paths to
+ * namespace root.
+ */
+ if (!connected) {
+ /* is the disconnect path a sysctl? */
+ if (tmp.dentry->d_sb->s_magic == PROC_SUPER_MAGIC &&
+ strncmp(*name, "/sys/", 5) == 0) {
+ /* TODO: convert over to using a per namespace
+ * control instead of hard coded /proc
+ */
+ error = prepend(name, *name - buf, "/proc", 5);
+ } else if (!(flags & PATH_CONNECT_PATH) &&
+ !(((flags & CHROOT_NSCONNECT) == CHROOT_NSCONNECT) &&
+ (tmp.mnt == current->nsproxy->mnt_ns->root &&
+ tmp.dentry == tmp.mnt->mnt_root))) {
+ /* disconnected path, don't return pathname starting
+ * with '/'
+ */
+ error = -ESTALE;
+ if (*res == '/')
+ *name = res + 1;
+ }
+ }
+
+out:
+ path_put(&root);
+
+ return error;
+}
+
+/**
+ * get_name_to_buffer - get the pathname to a buffer ensure dir / is appended
+ * @path: path to get name for (NOT NULL)
+ * @flags: flags controlling path lookup
+ * @buffer: buffer to put name in (NOT NULL)
+ * @size: size of buffer
+ * @name: Returns - contains position of path name in @buffer (NOT NULL)
+ *
+ * Returns: %0 else error on failure
+ */
+static int get_name_to_buffer(struct path *path, int flags, char *buffer,
+ int size, char **name)
+{
+ int adjust = (flags & PATH_IS_DIR) ? 1 : 0;
+ int error = d_namespace_path(path, buffer, size - adjust, name, flags);
+
+ if (!error && (flags & PATH_IS_DIR) && (*name)[1] != '\0')
+ /*
+ * Append "/" to the pathname. The root directory is a special
+ * case; it already ends in slash.
+ */
+ strcpy(&buffer[size - 2], "/");
+
+ return error;
+}
+
+/**
+ * aa_get_name - compute the pathname of a file
+ * @path: path the file (NOT NULL)
+ * @flags: flags controlling path name generation
+ * @buffer: buffer that aa_get_name() allocated (NOT NULL)
+ * @name: Returns - the generated path name if !error (NOT NULL)
+ *
+ * @name is a pointer to the beginning of the pathname (which usually differs
+ * from the beginning of the buffer), or NULL. If there is an error @name
+ * may contain a partial or invalid name that can be used for audit purposes,
+ * but it can not be used for mediation.
+ *
+ * We need PATH_IS_DIR to indicate whether the file is a directory or not
+ * because the file may not yet exist, and so we cannot check the inode's
+ * file type.
+ *
+ * Returns: %0 else error code if could retrieve name
+ */
+int aa_get_name(struct path *path, int flags, char **buffer, const char **name)
+{
+ char *buf, *str = NULL;
+ int size = 256;
+ int error;
+
+ *name = NULL;
+ *buffer = NULL;
+ for (;;) {
+ /* freed by caller */
+ buf = kmalloc(size, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ error = get_name_to_buffer(path, flags, buf, size, &str);
+ if (error != -ENAMETOOLONG)
+ break;
+
+ kfree(buf);
+ size <<= 1;
+ if (size > aa_g_path_max)
+ return -ENAMETOOLONG;
+ }
+ *buffer = buf;
+ *name = str;
+
+ return error;
+}
diff --git a/security/apparmor/policy.c b/security/apparmor/policy.c
new file mode 100644
index 00000000000..3cdc1ad0787
--- /dev/null
+++ b/security/apparmor/policy.c
@@ -0,0 +1,1184 @@
+/*
+ * AppArmor security module
+ *
+ * This file contains AppArmor policy manipulation functions
+ *
+ * Copyright (C) 1998-2008 Novell/SUSE
+ * Copyright 2009-2010 Canonical Ltd.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2 of the
+ * License.
+ *
+ *
+ * AppArmor policy is based around profiles, which contain the rules a
+ * task is confined by. Every task in the system has a profile attached
+ * to it determined either by matching "unconfined" tasks against the
+ * visible set of profiles or by following a profiles attachment rules.
+ *
+ * Each profile exists in a profile namespace which is a container of
+ * visible profiles. Each namespace contains a special "unconfined" profile,
+ * which doesn't enforce any confinement on a task beyond DAC.
+ *
+ * Namespace and profile names can be written together in either
+ * of two syntaxes.
+ * :namespace:profile - used by kernel interfaces for easy detection
+ * namespace://profile - used by policy
+ *
+ * Profile names can not start with : or @ or ^ and may not contain \0
+ *
+ * Reserved profile names
+ * unconfined - special automatically generated unconfined profile
+ * inherit - special name to indicate profile inheritance
+ * null-XXXX-YYYY - special automatically generated learning profiles
+ *
+ * Namespace names may not start with / or @ and may not contain \0 or :
+ * Reserved namespace names
+ * user-XXXX - user defined profiles
+ *
+ * a // in a profile or namespace name indicates a hierarchical name with the
+ * name before the // being the parent and the name after the child.
+ *
+ * Profile and namespace hierarchies serve two different but similar purposes.
+ * The namespace contains the set of visible profiles that are considered
+ * for attachment. The hierarchy of namespaces allows for virtualizing
+ * the namespace so that for example a chroot can have its own set of profiles
+ * which may define some local user namespaces.
+ * The profile hierarchy severs two distinct purposes,
+ * - it allows for sub profiles or hats, which allows an application to run
+ * subprograms under its own profile with different restriction than it
+ * self, and not have it use the system profile.
+ * eg. if a mail program starts an editor, the policy might make the
+ * restrictions tighter on the editor tighter than the mail program,
+ * and definitely different than general editor restrictions
+ * - it allows for binary hierarchy of profiles, so that execution history
+ * is preserved. This feature isn't exploited by AppArmor reference policy
+ * but is allowed. NOTE: this is currently suboptimal because profile
+ * aliasing is not currently implemented so that a profile for each
+ * level must be defined.
+ * eg. /bin/bash///bin/ls as a name would indicate /bin/ls was started
+ * from /bin/bash
+ *
+ * A profile or namespace name that can contain one or more // separators
+ * is referred to as an hname (hierarchical).
+ * eg. /bin/bash//bin/ls
+ *
+ * An fqname is a name that may contain both namespace and profile hnames.
+ * eg. :ns:/bin/bash//bin/ls
+ *
+ * NOTES:
+ * - locking of profile lists is currently fairly coarse. All profile
+ * lists within a namespace use the namespace lock.
+ * FIXME: move profile lists to using rcu_lists
+ */
+
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/string.h>
+
+#include "include/apparmor.h"
+#include "include/capability.h"
+#include "include/context.h"
+#include "include/file.h"
+#include "include/ipc.h"
+#include "include/match.h"
+#include "include/path.h"
+#include "include/policy.h"
+#include "include/policy_unpack.h"
+#include "include/resource.h"
+#include "include/sid.h"
+
+
+/* root profile namespace */
+struct aa_namespace *root_ns;
+
+const char *profile_mode_names[] = {
+ "enforce",
+ "complain",
+ "kill",
+};
+
+/**
+ * hname_tail - find the last component of an hname
+ * @name: hname to find the base profile name component of (NOT NULL)
+ *
+ * Returns: the tail (base profile name) name component of an hname
+ */
+static const char *hname_tail(const char *hname)
+{
+ char *split;
+ hname = strim((char *)hname);
+ for (split = strstr(hname, "//"); split; split = strstr(hname, "//"))
+ hname = split + 2;
+
+ return hname;
+}
+
+/**
+ * policy_init - initialize a policy structure
+ * @policy: policy to initialize (NOT NULL)
+ * @prefix: prefix name if any is required. (MAYBE NULL)
+ * @name: name of the policy, init will make a copy of it (NOT NULL)
+ *
+ * Note: this fn creates a copy of strings passed in
+ *
+ * Returns: true if policy init successful
+ */
+static bool policy_init(struct aa_policy *policy, const char *prefix,
+ const char *name)
+{
+ /* freed by policy_free */
+ if (prefix) {
+ policy->hname = kmalloc(strlen(prefix) + strlen(name) + 3,
+ GFP_KERNEL);
+ if (policy->hname)
+ sprintf(policy->hname, "%s//%s", prefix, name);
+ } else
+ policy->hname = kstrdup(name, GFP_KERNEL);
+ if (!policy->hname)
+ return 0;
+ /* base.name is a substring of fqname */
+ policy->name = (char *)hname_tail(policy->hname);
+ INIT_LIST_HEAD(&policy->list);
+ INIT_LIST_HEAD(&policy->profiles);
+ kref_init(&policy->count);
+
+ return 1;
+}
+
+/**
+ * policy_destroy - free the elements referenced by @policy
+ * @policy: policy that is to have its elements freed (NOT NULL)
+ */
+static void policy_destroy(struct aa_policy *policy)
+{
+ /* still contains profiles -- invalid */
+ if (!list_empty(&policy->profiles)) {
+ AA_ERROR("%s: internal error, "
+ "policy '%s' still contains profiles\n",
+ __func__, policy->name);
+ BUG();
+ }
+ if (!list_empty(&policy->list)) {
+ AA_ERROR("%s: internal error, policy '%s' still on list\n",
+ __func__, policy->name);
+ BUG();
+ }
+
+ /* don't free name as its a subset of hname */
+ kzfree(policy->hname);
+}
+
+/**
+ * __policy_find - find a policy by @name on a policy list
+ * @head: list to search (NOT NULL)
+ * @name: name to search for (NOT NULL)
+ *
+ * Requires: correct locks for the @head list be held
+ *
+ * Returns: unrefcounted policy that match @name or NULL if not found
+ */
+static struct aa_policy *__policy_find(struct list_head *head, const char *name)
+{
+ struct aa_policy *policy;
+
+ list_for_each_entry(policy, head, list) {
+ if (!strcmp(policy->name, name))
+ return policy;
+ }
+ return NULL;
+}
+
+/**
+ * __policy_strn_find - find a policy that's name matches @len chars of @str
+ * @head: list to search (NOT NULL)
+ * @str: string to search for (NOT NULL)
+ * @len: length of match required
+ *
+ * Requires: correct locks for the @head list be held
+ *
+ * Returns: unrefcounted policy that match @str or NULL if not found
+ *
+ * if @len == strlen(@strlen) then this is equiv to __policy_find
+ * other wise it allows searching for policy by a partial match of name
+ */
+static struct aa_policy *__policy_strn_find(struct list_head *head,
+ const char *str, int len)
+{
+ struct aa_policy *policy;
+
+ list_for_each_entry(policy, head, list) {
+ if (aa_strneq(policy->name, str, len))
+ return policy;
+ }
+
+ return NULL;
+}
+
+/*
+ * Routines for AppArmor namespaces
+ */
+
+static const char *hidden_ns_name = "---";
+/**
+ * aa_ns_visible - test if @view is visible from @curr
+ * @curr: namespace to treat as the parent (NOT NULL)
+ * @view: namespace to test if visible from @curr (NOT NULL)
+ *
+ * Returns: true if @view is visible from @curr else false
+ */
+bool aa_ns_visible(struct aa_namespace *curr, struct aa_namespace *view)
+{
+ if (curr == view)
+ return true;
+
+ for ( ; view; view = view->parent) {
+ if (view->parent == curr)
+ return true;
+ }
+ return false;
+}
+
+/**
+ * aa_na_name - Find the ns name to display for @view from @curr
+ * @curr - current namespace (NOT NULL)
+ * @view - namespace attempting to view (NOT NULL)
+ *
+ * Returns: name of @view visible from @curr
+ */
+const char *aa_ns_name(struct aa_namespace *curr, struct aa_namespace *view)
+{
+ /* if view == curr then the namespace name isn't displayed */
+ if (curr == view)
+ return "";
+
+ if (aa_ns_visible(curr, view)) {
+ /* at this point if a ns is visible it is in a view ns
+ * thus the curr ns.hname is a prefix of its name.
+ * Only output the virtualized portion of the name
+ * Add + 2 to skip over // separating curr hname prefix
+ * from the visible tail of the views hname
+ */
+ return view->base.hname + strlen(curr->base.hname) + 2;
+ } else
+ return hidden_ns_name;
+}
+
+/**
+ * alloc_namespace - allocate, initialize and return a new namespace
+ * @prefix: parent namespace name (MAYBE NULL)
+ * @name: a preallocated name (NOT NULL)
+ *
+ * Returns: refcounted namespace or NULL on failure.
+ */
+static struct aa_namespace *alloc_namespace(const char *prefix,
+ const char *name)
+{
+ struct aa_namespace *ns;
+
+ ns = kzalloc(sizeof(*ns), GFP_KERNEL);
+ AA_DEBUG("%s(%p)\n", __func__, ns);
+ if (!ns)
+ return NULL;
+ if (!policy_init(&ns->base, prefix, name))
+ goto fail_ns;
+
+ INIT_LIST_HEAD(&ns->sub_ns);
+ rwlock_init(&ns->lock);
+
+ /* released by free_namespace */
+ ns->unconfined = aa_alloc_profile("unconfined");
+ if (!ns->unconfined)
+ goto fail_unconfined;
+
+ ns->unconfined->sid = aa_alloc_sid();
+ ns->unconfined->flags = PFLAG_UNCONFINED | PFLAG_IX_ON_NAME_ERROR |
+ PFLAG_IMMUTABLE;
+
+ /*
+ * released by free_namespace, however __remove_namespace breaks
+ * the cyclic references (ns->unconfined, and unconfined->ns) and
+ * replaces with refs to parent namespace unconfined
+ */
+ ns->unconfined->ns = aa_get_namespace(ns);
+
+ return ns;
+
+fail_unconfined:
+ kzfree(ns->base.name);
+fail_ns:
+ kzfree(ns);
+ return NULL;
+}
+
+/**
+ * free_namespace - free a profile namespace
+ * @ns: the namespace to free (MAYBE NULL)
+ *
+ * Requires: All references to the namespace must have been put, if the
+ * namespace was referenced by a profile confining a task,
+ */
+static void free_namespace(struct aa_namespace *ns)
+{
+ if (!ns)
+ return;
+
+ policy_destroy(&ns->base);
+ aa_put_namespace(ns->parent);
+
+ if (ns->unconfined && ns->unconfined->ns == ns)
+ ns->unconfined->ns = NULL;
+
+ aa_put_profile(ns->unconfined);
+ kzfree(ns);
+}
+
+/**
+ * aa_free_namespace_kref - free aa_namespace by kref (see aa_put_namespace)
+ * @kr: kref callback for freeing of a namespace (NOT NULL)
+ */
+void aa_free_namespace_kref(struct kref *kref)
+{
+ free_namespace(container_of(kref, struct aa_namespace, base.count));
+}
+
+/**
+ * __aa_find_namespace - find a namespace on a list by @name
+ * @head: list to search for namespace on (NOT NULL)
+ * @name: name of namespace to look for (NOT NULL)
+ *
+ * Returns: unrefcounted namespace
+ *
+ * Requires: ns lock be held
+ */
+static struct aa_namespace *__aa_find_namespace(struct list_head *head,
+ const char *name)
+{
+ return (struct aa_namespace *)__policy_find(head, name);
+}
+
+/**
+ * aa_find_namespace - look up a profile namespace on the namespace list
+ * @root: namespace to search in (NOT NULL)
+ * @name: name of namespace to find (NOT NULL)
+ *
+ * Returns: a refcounted namespace on the list, or NULL if no namespace
+ * called @name exists.
+ *
+ * refcount released by caller
+ */
+struct aa_namespace *aa_find_namespace(struct aa_namespace *root,
+ const char *name)
+{
+ struct aa_namespace *ns = NULL;
+
+ read_lock(&root->lock);
+ ns = aa_get_namespace(__aa_find_namespace(&root->sub_ns, name));
+ read_unlock(&root->lock);
+
+ return ns;
+}
+
+/**
+ * aa_prepare_namespace - find an existing or create a new namespace of @name
+ * @name: the namespace to find or add (MAYBE NULL)
+ *
+ * Returns: refcounted namespace or NULL if failed to create one
+ */
+static struct aa_namespace *aa_prepare_namespace(const char *name)
+{
+ struct aa_namespace *ns, *root;
+
+ root = aa_current_profile()->ns;
+
+ write_lock(&root->lock);
+
+ /* if name isn't specified the profile is loaded to the current ns */
+ if (!name) {
+ /* released by caller */
+ ns = aa_get_namespace(root);
+ goto out;
+ }
+
+ /* try and find the specified ns and if it doesn't exist create it */
+ /* released by caller */
+ ns = aa_get_namespace(__aa_find_namespace(&root->sub_ns, name));
+ if (!ns) {
+ /* namespace not found */
+ struct aa_namespace *new_ns;
+ write_unlock(&root->lock);
+ new_ns = alloc_namespace(root->base.hname, name);
+ if (!new_ns)
+ return NULL;
+ write_lock(&root->lock);
+ /* test for race when new_ns was allocated */
+ ns = __aa_find_namespace(&root->sub_ns, name);
+ if (!ns) {
+ /* add parent ref */
+ new_ns->parent = aa_get_namespace(root);
+
+ list_add(&new_ns->base.list, &root->sub_ns);
+ /* add list ref */
+ ns = aa_get_namespace(new_ns);
+ } else {
+ /* raced so free the new one */
+ free_namespace(new_ns);
+ /* get reference on namespace */
+ aa_get_namespace(ns);
+ }
+ }
+out:
+ write_unlock(&root->lock);
+
+ /* return ref */
+ return ns;
+}
+
+/**
+ * __list_add_profile - add a profile to a list
+ * @list: list to add it to (NOT NULL)
+ * @profile: the profile to add (NOT NULL)
+ *
+ * refcount @profile, should be put by __list_remove_profile
+ *
+ * Requires: namespace lock be held, or list not be shared
+ */
+static void __list_add_profile(struct list_head *list,
+ struct aa_profile *profile)
+{
+ list_add(&profile->base.list, list);
+ /* get list reference */
+ aa_get_profile(profile);
+}
+
+/**
+ * __list_remove_profile - remove a profile from the list it is on
+ * @profile: the profile to remove (NOT NULL)
+ *
+ * remove a profile from the list, warning generally removal should
+ * be done with __replace_profile as most profile removals are
+ * replacements to the unconfined profile.
+ *
+ * put @profile list refcount
+ *
+ * Requires: namespace lock be held, or list not have been live
+ */
+static void __list_remove_profile(struct aa_profile *profile)
+{
+ list_del_init(&profile->base.list);
+ if (!(profile->flags & PFLAG_NO_LIST_REF))
+ /* release list reference */
+ aa_put_profile(profile);
+}
+
+/**
+ * __replace_profile - replace @old with @new on a list
+ * @old: profile to be replaced (NOT NULL)
+ * @new: profile to replace @old with (NOT NULL)
+ *
+ * Will duplicate and refcount elements that @new inherits from @old
+ * and will inherit @old children.
+ *
+ * refcount @new for list, put @old list refcount
+ *
+ * Requires: namespace list lock be held, or list not be shared
+ */
+static void __replace_profile(struct aa_profile *old, struct aa_profile *new)
+{
+ struct aa_policy *policy;
+ struct aa_profile *child, *tmp;
+
+ if (old->parent)
+ policy = &old->parent->base;
+ else
+ policy = &old->ns->base;
+
+ /* released when @new is freed */
+ new->parent = aa_get_profile(old->parent);
+ new->ns = aa_get_namespace(old->ns);
+ new->sid = old->sid;
+ __list_add_profile(&policy->profiles, new);
+ /* inherit children */
+ list_for_each_entry_safe(child, tmp, &old->base.profiles, base.list) {
+ aa_put_profile(child->parent);
+ child->parent = aa_get_profile(new);
+ /* list refcount transferred to @new*/
+ list_move(&child->base.list, &new->base.profiles);
+ }
+
+ /* released by free_profile */
+ old->replacedby = aa_get_profile(new);
+ __list_remove_profile(old);
+}
+
+static void __profile_list_release(struct list_head *head);
+
+/**
+ * __remove_profile - remove old profile, and children
+ * @profile: profile to be replaced (NOT NULL)
+ *
+ * Requires: namespace list lock be held, or list not be shared
+ */
+static void __remove_profile(struct aa_profile *profile)
+{
+ /* release any children lists first */
+ __profile_list_release(&profile->base.profiles);
+ /* released by free_profile */
+ profile->replacedby = aa_get_profile(profile->ns->unconfined);
+ __list_remove_profile(profile);
+}
+
+/**
+ * __profile_list_release - remove all profiles on the list and put refs
+ * @head: list of profiles (NOT NULL)
+ *
+ * Requires: namespace lock be held
+ */
+static void __profile_list_release(struct list_head *head)
+{
+ struct aa_profile *profile, *tmp;
+ list_for_each_entry_safe(profile, tmp, head, base.list)
+ __remove_profile(profile);
+}
+
+static void __ns_list_release(struct list_head *head);
+
+/**
+ * destroy_namespace - remove everything contained by @ns
+ * @ns: namespace to have it contents removed (NOT NULL)
+ */
+static void destroy_namespace(struct aa_namespace *ns)
+{
+ if (!ns)
+ return;
+
+ write_lock(&ns->lock);
+ /* release all profiles in this namespace */
+ __profile_list_release(&ns->base.profiles);
+
+ /* release all sub namespaces */
+ __ns_list_release(&ns->sub_ns);
+
+ write_unlock(&ns->lock);
+}
+
+/**
+ * __remove_namespace - remove a namespace and all its children
+ * @ns: namespace to be removed (NOT NULL)
+ *
+ * Requires: ns->parent->lock be held and ns removed from parent.
+ */
+static void __remove_namespace(struct aa_namespace *ns)
+{
+ struct aa_profile *unconfined = ns->unconfined;
+
+ /* remove ns from namespace list */
+ list_del_init(&ns->base.list);
+
+ /*
+ * break the ns, unconfined profile cyclic reference and forward
+ * all new unconfined profiles requests to the parent namespace
+ * This will result in all confined tasks that have a profile
+ * being removed, inheriting the parent->unconfined profile.
+ */
+ if (ns->parent)
+ ns->unconfined = aa_get_profile(ns->parent->unconfined);
+
+ destroy_namespace(ns);
+
+ /* release original ns->unconfined ref */
+ aa_put_profile(unconfined);
+ /* release ns->base.list ref, from removal above */
+ aa_put_namespace(ns);
+}
+
+/**
+ * __ns_list_release - remove all profile namespaces on the list put refs
+ * @head: list of profile namespaces (NOT NULL)
+ *
+ * Requires: namespace lock be held
+ */
+static void __ns_list_release(struct list_head *head)
+{
+ struct aa_namespace *ns, *tmp;
+ list_for_each_entry_safe(ns, tmp, head, base.list)
+ __remove_namespace(ns);
+
+}
+
+/**
+ * aa_alloc_root_ns - allocate the root profile namespace
+ *
+ * Returns: %0 on success else error
+ *
+ */
+int __init aa_alloc_root_ns(void)
+{
+ /* released by aa_free_root_ns - used as list ref*/
+ root_ns = alloc_namespace(NULL, "root");
+ if (!root_ns)
+ return -ENOMEM;
+
+ return 0;
+}
+
+ /**
+ * aa_free_root_ns - free the root profile namespace
+ */
+void __init aa_free_root_ns(void)
+ {
+ struct aa_namespace *ns = root_ns;
+ root_ns = NULL;
+
+ destroy_namespace(ns);
+ aa_put_namespace(ns);
+}
+
+/**
+ * aa_alloc_profile - allocate, initialize and return a new profile
+ * @hname: name of the profile (NOT NULL)
+ *
+ * Returns: refcount profile or NULL on failure
+ */
+struct aa_profile *aa_alloc_profile(const char *hname)
+{
+ struct aa_profile *profile;
+
+ /* freed by free_profile - usually through aa_put_profile */
+ profile = kzalloc(sizeof(*profile), GFP_KERNEL);
+ if (!profile)
+ return NULL;
+
+ if (!policy_init(&profile->base, NULL, hname)) {
+ kzfree(profile);
+ return NULL;
+ }
+
+ /* refcount released by caller */
+ return profile;
+}
+
+/**
+ * aa_new_null_profile - create a new null-X learning profile
+ * @parent: profile that caused this profile to be created (NOT NULL)
+ * @hat: true if the null- learning profile is a hat
+ *
+ * Create a null- complain mode profile used in learning mode. The name of
+ * the profile is unique and follows the format of parent//null-sid.
+ *
+ * null profiles are added to the profile list but the list does not
+ * hold a count on them so that they are automatically released when
+ * not in use.
+ *
+ * Returns: new refcounted profile else NULL on failure
+ */
+struct aa_profile *aa_new_null_profile(struct aa_profile *parent, int hat)
+{
+ struct aa_profile *profile = NULL;
+ char *name;
+ u32 sid = aa_alloc_sid();
+
+ /* freed below */
+ name = kmalloc(strlen(parent->base.hname) + 2 + 7 + 8, GFP_KERNEL);
+ if (!name)
+ goto fail;
+ sprintf(name, "%s//null-%x", parent->base.hname, sid);
+
+ profile = aa_alloc_profile(name);
+ kfree(name);
+ if (!profile)
+ goto fail;
+
+ profile->sid = sid;
+ profile->mode = APPARMOR_COMPLAIN;
+ profile->flags = PFLAG_NULL;
+ if (hat)
+ profile->flags |= PFLAG_HAT;
+
+ /* released on free_profile */
+ profile->parent = aa_get_profile(parent);
+ profile->ns = aa_get_namespace(parent->ns);
+
+ write_lock(&profile->ns->lock);
+ __list_add_profile(&parent->base.profiles, profile);
+ write_unlock(&profile->ns->lock);
+
+ /* refcount released by caller */
+ return profile;
+
+fail:
+ aa_free_sid(sid);
+ return NULL;
+}
+
+/**
+ * free_profile - free a profile
+ * @profile: the profile to free (MAYBE NULL)
+ *
+ * Free a profile, its hats and null_profile. All references to the profile,
+ * its hats and null_profile must have been put.
+ *
+ * If the profile was referenced from a task context, free_profile() will
+ * be called from an rcu callback routine, so we must not sleep here.
+ */
+static void free_profile(struct aa_profile *profile)
+{
+ AA_DEBUG("%s(%p)\n", __func__, profile);
+
+ if (!profile)
+ return;
+
+ if (!list_empty(&profile->base.list)) {
+ AA_ERROR("%s: internal error, "
+ "profile '%s' still on ns list\n",
+ __func__, profile->base.name);
+ BUG();
+ }
+
+ /* free children profiles */
+ policy_destroy(&profile->base);
+ aa_put_profile(profile->parent);
+
+ aa_put_namespace(profile->ns);
+ kzfree(profile->rename);
+
+ aa_free_file_rules(&profile->file);
+ aa_free_cap_rules(&profile->caps);
+ aa_free_rlimit_rules(&profile->rlimits);
+
+ aa_free_sid(profile->sid);
+ aa_put_dfa(profile->xmatch);
+
+ aa_put_profile(profile->replacedby);
+
+ kzfree(profile);
+}
+
+/**
+ * aa_free_profile_kref - free aa_profile by kref (called by aa_put_profile)
+ * @kr: kref callback for freeing of a profile (NOT NULL)
+ */
+void aa_free_profile_kref(struct kref *kref)
+{
+ struct aa_profile *p = container_of(kref, struct aa_profile,
+ base.count);
+
+ free_profile(p);
+}
+
+/* TODO: profile accounting - setup in remove */
+
+/**
+ * __find_child - find a profile on @head list with a name matching @name
+ * @head: list to search (NOT NULL)
+ * @name: name of profile (NOT NULL)
+ *
+ * Requires: ns lock protecting list be held
+ *
+ * Returns: unrefcounted profile ptr, or NULL if not found
+ */
+static struct aa_profile *__find_child(struct list_head *head, const char *name)
+{
+ return (struct aa_profile *)__policy_find(head, name);
+}
+
+/**
+ * __strn_find_child - find a profile on @head list using substring of @name
+ * @head: list to search (NOT NULL)
+ * @name: name of profile (NOT NULL)
+ * @len: length of @name substring to match
+ *
+ * Requires: ns lock protecting list be held
+ *
+ * Returns: unrefcounted profile ptr, or NULL if not found
+ */
+static struct aa_profile *__strn_find_child(struct list_head *head,
+ const char *name, int len)
+{
+ return (struct aa_profile *)__policy_strn_find(head, name, len);
+}
+
+/**
+ * aa_find_child - find a profile by @name in @parent
+ * @parent: profile to search (NOT NULL)
+ * @name: profile name to search for (NOT NULL)
+ *
+ * Returns: a refcounted profile or NULL if not found
+ */
+struct aa_profile *aa_find_child(struct aa_profile *parent, const char *name)
+{
+ struct aa_profile *profile;
+
+ read_lock(&parent->ns->lock);
+ profile = aa_get_profile(__find_child(&parent->base.profiles, name));
+ read_unlock(&parent->ns->lock);
+
+ /* refcount released by caller */
+ return profile;
+}
+
+/**
+ * __lookup_parent - lookup the parent of a profile of name @hname
+ * @ns: namespace to lookup profile in (NOT NULL)
+ * @hname: hierarchical profile name to find parent of (NOT NULL)
+ *
+ * Lookups up the parent of a fully qualified profile name, the profile
+ * that matches hname does not need to exist, in general this
+ * is used to load a new profile.
+ *
+ * Requires: ns->lock be held
+ *
+ * Returns: unrefcounted policy or NULL if not found
+ */
+static struct aa_policy *__lookup_parent(struct aa_namespace *ns,
+ const char *hname)
+{
+ struct aa_policy *policy;
+ struct aa_profile *profile = NULL;
+ char *split;
+
+ policy = &ns->base;
+
+ for (split = strstr(hname, "//"); split;) {
+ profile = __strn_find_child(&policy->profiles, hname,
+ split - hname);
+ if (!profile)
+ return NULL;
+ policy = &profile->base;
+ hname = split + 2;
+ split = strstr(hname, "//");
+ }
+ if (!profile)
+ return &ns->base;
+ return &profile->base;
+}
+
+/**
+ * __lookup_profile - lookup the profile matching @hname
+ * @base: base list to start looking up profile name from (NOT NULL)
+ * @hname: hierarchical profile name (NOT NULL)
+ *
+ * Requires: ns->lock be held
+ *
+ * Returns: unrefcounted profile pointer or NULL if not found
+ *
+ * Do a relative name lookup, recursing through profile tree.
+ */
+static struct aa_profile *__lookup_profile(struct aa_policy *base,
+ const char *hname)
+{
+ struct aa_profile *profile = NULL;
+ char *split;
+
+ for (split = strstr(hname, "//"); split;) {
+ profile = __strn_find_child(&base->profiles, hname,
+ split - hname);
+ if (!profile)
+ return NULL;
+
+ base = &profile->base;
+ hname = split + 2;
+ split = strstr(hname, "//");
+ }
+
+ profile = __find_child(&base->profiles, hname);
+
+ return profile;
+}
+
+/**
+ * aa_lookup_profile - find a profile by its full or partial name
+ * @ns: the namespace to start from (NOT NULL)
+ * @hname: name to do lookup on. Does not contain namespace prefix (NOT NULL)
+ *
+ * Returns: refcounted profile or NULL if not found
+ */
+struct aa_profile *aa_lookup_profile(struct aa_namespace *ns, const char *hname)
+{
+ struct aa_profile *profile;
+
+ read_lock(&ns->lock);
+ profile = aa_get_profile(__lookup_profile(&ns->base, hname));
+ read_unlock(&ns->lock);
+
+ /* refcount released by caller */
+ return profile;
+}
+
+/**
+ * replacement_allowed - test to see if replacement is allowed
+ * @profile: profile to test if it can be replaced (MAYBE NULL)
+ * @noreplace: true if replacement shouldn't be allowed but addition is okay
+ * @info: Returns - info about why replacement failed (NOT NULL)
+ *
+ * Returns: %0 if replacement allowed else error code
+ */
+static int replacement_allowed(struct aa_profile *profile, int noreplace,
+ const char **info)
+{
+ if (profile) {
+ if (profile->flags & PFLAG_IMMUTABLE) {
+ *info = "cannot replace immutible profile";
+ return -EPERM;
+ } else if (noreplace) {
+ *info = "profile already exists";
+ return -EEXIST;
+ }
+ }
+ return 0;
+}
+
+/**
+ * __add_new_profile - simple wrapper around __list_add_profile
+ * @ns: namespace that profile is being added to (NOT NULL)
+ * @policy: the policy container to add the profile to (NOT NULL)
+ * @profile: profile to add (NOT NULL)
+ *
+ * add a profile to a list and do other required basic allocations
+ */
+static void __add_new_profile(struct aa_namespace *ns, struct aa_policy *policy,
+ struct aa_profile *profile)
+{
+ if (policy != &ns->base)
+ /* released on profile replacement or free_profile */
+ profile->parent = aa_get_profile((struct aa_profile *) policy);
+ __list_add_profile(&policy->profiles, profile);
+ /* released on free_profile */
+ profile->sid = aa_alloc_sid();
+ profile->ns = aa_get_namespace(ns);
+}
+
+/**
+ * aa_audit_policy - Do auditing of policy changes
+ * @op: policy operation being performed
+ * @gfp: memory allocation flags
+ * @name: name of profile being manipulated (NOT NULL)
+ * @info: any extra information to be audited (MAYBE NULL)
+ * @error: error code
+ *
+ * Returns: the error to be returned after audit is done
+ */
+static int audit_policy(int op, gfp_t gfp, const char *name, const char *info,
+ int error)
+{
+ struct common_audit_data sa;
+ COMMON_AUDIT_DATA_INIT(&sa, NONE);
+ sa.aad.op = op;
+ sa.aad.name = name;
+ sa.aad.info = info;
+ sa.aad.error = error;
+
+ return aa_audit(AUDIT_APPARMOR_STATUS, __aa_current_profile(), gfp,
+ &sa, NULL);
+}
+
+/**
+ * aa_may_manage_policy - can the current task manage policy
+ * @op: the policy manipulation operation being done
+ *
+ * Returns: true if the task is allowed to manipulate policy
+ */
+bool aa_may_manage_policy(int op)
+{
+ /* check if loading policy is locked out */
+ if (aa_g_lock_policy) {
+ audit_policy(op, GFP_KERNEL, NULL, "policy_locked", -EACCES);
+ return 0;
+ }
+
+ if (!capable(CAP_MAC_ADMIN)) {
+ audit_policy(op, GFP_KERNEL, NULL, "not policy admin", -EACCES);
+ return 0;
+ }
+
+ return 1;
+}
+
+/**
+ * aa_replace_profiles - replace profile(s) on the profile list
+ * @udata: serialized data stream (NOT NULL)
+ * @size: size of the serialized data stream
+ * @noreplace: true if only doing addition, no replacement allowed
+ *
+ * unpack and replace a profile on the profile list and uses of that profile
+ * by any aa_task_cxt. If the profile does not exist on the profile list
+ * it is added.
+ *
+ * Returns: size of data consumed else error code on failure.
+ */
+ssize_t aa_replace_profiles(void *udata, size_t size, bool noreplace)
+{
+ struct aa_policy *policy;
+ struct aa_profile *old_profile = NULL, *new_profile = NULL;
+ struct aa_profile *rename_profile = NULL;
+ struct aa_namespace *ns = NULL;
+ const char *ns_name, *name = NULL, *info = NULL;
+ int op = OP_PROF_REPL;
+ ssize_t error;
+
+ /* released below */
+ new_profile = aa_unpack(udata, size, &ns_name);
+ if (IS_ERR(new_profile)) {
+ error = PTR_ERR(new_profile);
+ new_profile = NULL;
+ goto fail;
+ }
+
+ /* released below */
+ ns = aa_prepare_namespace(ns_name);
+ if (!ns) {
+ info = "failed to prepare namespace";
+ error = -ENOMEM;
+ name = ns_name;
+ goto fail;
+ }
+
+ name = new_profile->base.hname;
+
+ write_lock(&ns->lock);
+ /* no ref on policy only use inside lock */
+ policy = __lookup_parent(ns, new_profile->base.hname);
+
+ if (!policy) {
+ info = "parent does not exist";
+ error = -ENOENT;
+ goto audit;
+ }
+
+ old_profile = __find_child(&policy->profiles, new_profile->base.name);
+ /* released below */
+ aa_get_profile(old_profile);
+
+ if (new_profile->rename) {
+ rename_profile = __lookup_profile(&ns->base,
+ new_profile->rename);
+ /* released below */
+ aa_get_profile(rename_profile);
+
+ if (!rename_profile) {
+ info = "profile to rename does not exist";
+ name = new_profile->rename;
+ error = -ENOENT;
+ goto audit;
+ }
+ }
+
+ error = replacement_allowed(old_profile, noreplace, &info);
+ if (error)
+ goto audit;
+
+ error = replacement_allowed(rename_profile, noreplace, &info);
+ if (error)
+ goto audit;
+
+audit:
+ if (!old_profile && !rename_profile)
+ op = OP_PROF_LOAD;
+
+ error = audit_policy(op, GFP_ATOMIC, name, info, error);
+
+ if (!error) {
+ if (rename_profile)
+ __replace_profile(rename_profile, new_profile);
+ if (old_profile) {
+ /* when there are both rename and old profiles
+ * inherit old profiles sid
+ */
+ if (rename_profile)
+ aa_free_sid(new_profile->sid);
+ __replace_profile(old_profile, new_profile);
+ }
+ if (!(old_profile || rename_profile))
+ __add_new_profile(ns, policy, new_profile);
+ }
+ write_unlock(&ns->lock);
+
+out:
+ aa_put_namespace(ns);
+ aa_put_profile(rename_profile);
+ aa_put_profile(old_profile);
+ aa_put_profile(new_profile);
+ if (error)
+ return error;
+ return size;
+
+fail:
+ error = audit_policy(op, GFP_KERNEL, name, info, error);
+ goto out;
+}
+
+/**
+ * aa_remove_profiles - remove profile(s) from the system
+ * @fqname: name of the profile or namespace to remove (NOT NULL)
+ * @size: size of the name
+ *
+ * Remove a profile or sub namespace from the current namespace, so that
+ * they can not be found anymore and mark them as replaced by unconfined
+ *
+ * NOTE: removing confinement does not restore rlimits to preconfinemnet values
+ *
+ * Returns: size of data consume else error code if fails
+ */
+ssize_t aa_remove_profiles(char *fqname, size_t size)
+{
+ struct aa_namespace *root, *ns = NULL;
+ struct aa_profile *profile = NULL;
+ const char *name = fqname, *info = NULL;
+ ssize_t error = 0;
+
+ if (*fqname == 0) {
+ info = "no profile specified";
+ error = -ENOENT;
+ goto fail;
+ }
+
+ root = aa_current_profile()->ns;
+
+ if (fqname[0] == ':') {
+ char *ns_name;
+ name = aa_split_fqname(fqname, &ns_name);
+ if (ns_name) {
+ /* released below */
+ ns = aa_find_namespace(root, ns_name);
+ if (!ns) {
+ info = "namespace does not exist";
+ error = -ENOENT;
+ goto fail;
+ }
+ }
+ } else
+ /* released below */
+ ns = aa_get_namespace(root);
+
+ write_lock(&ns->lock);
+ if (!name) {
+ /* remove namespace - can only happen if fqname[0] == ':' */
+ __remove_namespace(ns);
+ } else {
+ /* remove profile */
+ profile = aa_get_profile(__lookup_profile(&ns->base, name));
+ if (!profile) {
+ error = -ENOENT;
+ info = "profile does not exist";
+ goto fail_ns_lock;
+ }
+ name = profile->base.hname;
+ __remove_profile(profile);
+ }
+ write_unlock(&ns->lock);
+
+ /* don't fail removal if audit fails */
+ (void) audit_policy(OP_PROF_RM, GFP_KERNEL, name, info, error);
+ aa_put_namespace(ns);
+ aa_put_profile(profile);
+ return size;
+
+fail_ns_lock:
+ write_unlock(&ns->lock);
+ aa_put_namespace(ns);
+
+fail:
+ (void) audit_policy(OP_PROF_RM, GFP_KERNEL, name, info, error);
+ return error;
+}
diff --git a/security/apparmor/policy_unpack.c b/security/apparmor/policy_unpack.c
new file mode 100644
index 00000000000..eb3700e9fd3
--- /dev/null
+++ b/security/apparmor/policy_unpack.c
@@ -0,0 +1,703 @@
+/*
+ * AppArmor security module
+ *
+ * This file contains AppArmor functions for unpacking policy loaded from
+ * userspace.
+ *
+ * Copyright (C) 1998-2008 Novell/SUSE
+ * Copyright 2009-2010 Canonical Ltd.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2 of the
+ * License.
+ *
+ * AppArmor uses a serialized binary format for loading policy.
+ * To find policy format documentation look in Documentation/apparmor.txt
+ * All policy is validated before it is used.
+ */
+
+#include <asm/unaligned.h>
+#include <linux/ctype.h>
+#include <linux/errno.h>
+
+#include "include/apparmor.h"
+#include "include/audit.h"
+#include "include/context.h"
+#include "include/match.h"
+#include "include/policy.h"
+#include "include/policy_unpack.h"
+#include "include/sid.h"
+
+/*
+ * The AppArmor interface treats data as a type byte followed by the
+ * actual data. The interface has the notion of a a named entry
+ * which has a name (AA_NAME typecode followed by name string) followed by
+ * the entries typecode and data. Named types allow for optional
+ * elements and extensions to be added and tested for without breaking
+ * backwards compatibility.
+ */
+
+enum aa_code {
+ AA_U8,
+ AA_U16,
+ AA_U32,
+ AA_U64,
+ AA_NAME, /* same as string except it is items name */
+ AA_STRING,
+ AA_BLOB,
+ AA_STRUCT,
+ AA_STRUCTEND,
+ AA_LIST,
+ AA_LISTEND,
+ AA_ARRAY,
+ AA_ARRAYEND,
+};
+
+/*
+ * aa_ext is the read of the buffer containing the serialized profile. The
+ * data is copied into a kernel buffer in apparmorfs and then handed off to
+ * the unpack routines.
+ */
+struct aa_ext {
+ void *start;
+ void *end;
+ void *pos; /* pointer to current position in the buffer */
+ u32 version;
+};
+
+/* audit callback for unpack fields */
+static void audit_cb(struct audit_buffer *ab, void *va)
+{
+ struct common_audit_data *sa = va;
+ if (sa->aad.iface.target) {
+ struct aa_profile *name = sa->aad.iface.target;
+ audit_log_format(ab, " name=");
+ audit_log_untrustedstring(ab, name->base.hname);
+ }
+ if (sa->aad.iface.pos)
+ audit_log_format(ab, " offset=%ld", sa->aad.iface.pos);
+}
+
+/**
+ * audit_iface - do audit message for policy unpacking/load/replace/remove
+ * @new: profile if it has been allocated (MAYBE NULL)
+ * @name: name of the profile being manipulated (MAYBE NULL)
+ * @info: any extra info about the failure (MAYBE NULL)
+ * @e: buffer position info (NOT NULL)
+ * @error: error code
+ *
+ * Returns: %0 or error
+ */
+static int audit_iface(struct aa_profile *new, const char *name,
+ const char *info, struct aa_ext *e, int error)
+{
+ struct aa_profile *profile = __aa_current_profile();
+ struct common_audit_data sa;
+ COMMON_AUDIT_DATA_INIT(&sa, NONE);
+ sa.aad.iface.pos = e->pos - e->start;
+ sa.aad.iface.target = new;
+ sa.aad.name = name;
+ sa.aad.info = info;
+ sa.aad.error = error;
+
+ return aa_audit(AUDIT_APPARMOR_STATUS, profile, GFP_KERNEL, &sa,
+ audit_cb);
+}
+
+/* test if read will be in packed data bounds */
+static bool inbounds(struct aa_ext *e, size_t size)
+{
+ return (size <= e->end - e->pos);
+}
+
+/**
+ * aa_u16_chunck - test and do bounds checking for a u16 size based chunk
+ * @e: serialized data read head (NOT NULL)
+ * @chunk: start address for chunk of data (NOT NULL)
+ *
+ * Returns: the size of chunk found with the read head at the end of the chunk.
+ */
+static size_t unpack_u16_chunk(struct aa_ext *e, char **chunk)
+{
+ size_t size = 0;
+
+ if (!inbounds(e, sizeof(u16)))
+ return 0;
+ size = le16_to_cpu(get_unaligned((u16 *) e->pos));
+ e->pos += sizeof(u16);
+ if (!inbounds(e, size))
+ return 0;
+ *chunk = e->pos;
+ e->pos += size;
+ return size;
+}
+
+/* unpack control byte */
+static bool unpack_X(struct aa_ext *e, enum aa_code code)
+{
+ if (!inbounds(e, 1))
+ return 0;
+ if (*(u8 *) e->pos != code)
+ return 0;
+ e->pos++;
+ return 1;
+}
+
+/**
+ * unpack_nameX - check is the next element is of type X with a name of @name
+ * @e: serialized data extent information (NOT NULL)
+ * @code: type code
+ * @name: name to match to the serialized element. (MAYBE NULL)
+ *
+ * check that the next serialized data element is of type X and has a tag
+ * name @name. If @name is specified then there must be a matching
+ * name element in the stream. If @name is NULL any name element will be
+ * skipped and only the typecode will be tested.
+ *
+ * Returns 1 on success (both type code and name tests match) and the read
+ * head is advanced past the headers
+ *
+ * Returns: 0 if either match fails, the read head does not move
+ */
+static bool unpack_nameX(struct aa_ext *e, enum aa_code code, const char *name)
+{
+ /*
+ * May need to reset pos if name or type doesn't match
+ */
+ void *pos = e->pos;
+ /*
+ * Check for presence of a tagname, and if present name size
+ * AA_NAME tag value is a u16.
+ */
+ if (unpack_X(e, AA_NAME)) {
+ char *tag = NULL;
+ size_t size = unpack_u16_chunk(e, &tag);
+ /* if a name is specified it must match. otherwise skip tag */
+ if (name && (!size || strcmp(name, tag)))
+ goto fail;
+ } else if (name) {
+ /* if a name is specified and there is no name tag fail */
+ goto fail;
+ }
+
+ /* now check if type code matches */
+ if (unpack_X(e, code))
+ return 1;
+
+fail:
+ e->pos = pos;
+ return 0;
+}
+
+static bool unpack_u32(struct aa_ext *e, u32 *data, const char *name)
+{
+ if (unpack_nameX(e, AA_U32, name)) {
+ if (!inbounds(e, sizeof(u32)))
+ return 0;
+ if (data)
+ *data = le32_to_cpu(get_unaligned((u32 *) e->pos));
+ e->pos += sizeof(u32);
+ return 1;
+ }
+ return 0;
+}
+
+static bool unpack_u64(struct aa_ext *e, u64 *data, const char *name)
+{
+ if (unpack_nameX(e, AA_U64, name)) {
+ if (!inbounds(e, sizeof(u64)))
+ return 0;
+ if (data)
+ *data = le64_to_cpu(get_unaligned((u64 *) e->pos));
+ e->pos += sizeof(u64);
+ return 1;
+ }
+ return 0;
+}
+
+static size_t unpack_array(struct aa_ext *e, const char *name)
+{
+ if (unpack_nameX(e, AA_ARRAY, name)) {
+ int size;
+ if (!inbounds(e, sizeof(u16)))
+ return 0;
+ size = (int)le16_to_cpu(get_unaligned((u16 *) e->pos));
+ e->pos += sizeof(u16);
+ return size;
+ }
+ return 0;
+}
+
+static size_t unpack_blob(struct aa_ext *e, char **blob, const char *name)
+{
+ if (unpack_nameX(e, AA_BLOB, name)) {
+ u32 size;
+ if (!inbounds(e, sizeof(u32)))
+ return 0;
+ size = le32_to_cpu(get_unaligned((u32 *) e->pos));
+ e->pos += sizeof(u32);
+ if (inbounds(e, (size_t) size)) {
+ *blob = e->pos;
+ e->pos += size;
+ return size;
+ }
+ }
+ return 0;
+}
+
+static int unpack_str(struct aa_ext *e, const char **string, const char *name)
+{
+ char *src_str;
+ size_t size = 0;
+ void *pos = e->pos;
+ *string = NULL;
+ if (unpack_nameX(e, AA_STRING, name)) {
+ size = unpack_u16_chunk(e, &src_str);
+ if (size) {
+ /* strings are null terminated, length is size - 1 */
+ if (src_str[size - 1] != 0)
+ goto fail;
+ *string = src_str;
+ }
+ }
+ return size;
+
+fail:
+ e->pos = pos;
+ return 0;
+}
+
+static int unpack_strdup(struct aa_ext *e, char **string, const char *name)
+{
+ const char *tmp;
+ void *pos = e->pos;
+ int res = unpack_str(e, &tmp, name);
+ *string = NULL;
+
+ if (!res)
+ return 0;
+
+ *string = kmemdup(tmp, res, GFP_KERNEL);
+ if (!*string) {
+ e->pos = pos;
+ return 0;
+ }
+
+ return res;
+}
+
+/**
+ * verify_accept - verify the accept tables of a dfa
+ * @dfa: dfa to verify accept tables of (NOT NULL)
+ * @flags: flags governing dfa
+ *
+ * Returns: 1 if valid accept tables else 0 if error
+ */
+static bool verify_accept(struct aa_dfa *dfa, int flags)
+{
+ int i;
+
+ /* verify accept permissions */
+ for (i = 0; i < dfa->tables[YYTD_ID_ACCEPT]->td_lolen; i++) {
+ int mode = ACCEPT_TABLE(dfa)[i];
+
+ if (mode & ~DFA_VALID_PERM_MASK)
+ return 0;
+
+ if (ACCEPT_TABLE2(dfa)[i] & ~DFA_VALID_PERM2_MASK)
+ return 0;
+ }
+ return 1;
+}
+
+/**
+ * unpack_dfa - unpack a file rule dfa
+ * @e: serialized data extent information (NOT NULL)
+ *
+ * returns dfa or ERR_PTR or NULL if no dfa
+ */
+static struct aa_dfa *unpack_dfa(struct aa_ext *e)
+{
+ char *blob = NULL;
+ size_t size;
+ struct aa_dfa *dfa = NULL;
+
+ size = unpack_blob(e, &blob, "aadfa");
+ if (size) {
+ /*
+ * The dfa is aligned with in the blob to 8 bytes
+ * from the beginning of the stream.
+ */
+ size_t sz = blob - (char *)e->start;
+ size_t pad = ALIGN(sz, 8) - sz;
+ int flags = TO_ACCEPT1_FLAG(YYTD_DATA32) |
+ TO_ACCEPT2_FLAG(YYTD_DATA32);
+
+
+ if (aa_g_paranoid_load)
+ flags |= DFA_FLAG_VERIFY_STATES;
+
+ dfa = aa_dfa_unpack(blob + pad, size - pad, flags);
+
+ if (IS_ERR(dfa))
+ return dfa;
+
+ if (!verify_accept(dfa, flags))
+ goto fail;
+ }
+
+ return dfa;
+
+fail:
+ aa_put_dfa(dfa);
+ return ERR_PTR(-EPROTO);
+}
+
+/**
+ * unpack_trans_table - unpack a profile transition table
+ * @e: serialized data extent information (NOT NULL)
+ * @profile: profile to add the accept table to (NOT NULL)
+ *
+ * Returns: 1 if table succesfully unpacked
+ */
+static bool unpack_trans_table(struct aa_ext *e, struct aa_profile *profile)
+{
+ void *pos = e->pos;
+
+ /* exec table is optional */
+ if (unpack_nameX(e, AA_STRUCT, "xtable")) {
+ int i, size;
+
+ size = unpack_array(e, NULL);
+ /* currently 4 exec bits and entries 0-3 are reserved iupcx */
+ if (size > 16 - 4)
+ goto fail;
+ profile->file.trans.table = kzalloc(sizeof(char *) * size,
+ GFP_KERNEL);
+ if (!profile->file.trans.table)
+ goto fail;
+
+ profile->file.trans.size = size;
+ for (i = 0; i < size; i++) {
+ char *str;
+ int c, j, size = unpack_strdup(e, &str, NULL);
+ /* unpack_strdup verifies that the last character is
+ * null termination byte.
+ */
+ if (!size)
+ goto fail;
+ profile->file.trans.table[i] = str;
+ /* verify that name doesn't start with space */
+ if (isspace(*str))
+ goto fail;
+
+ /* count internal # of internal \0 */
+ for (c = j = 0; j < size - 2; j++) {
+ if (!str[j])
+ c++;
+ }
+ if (*str == ':') {
+ /* beginning with : requires an embedded \0,
+ * verify that exactly 1 internal \0 exists
+ * trailing \0 already verified by unpack_strdup
+ */
+ if (c != 1)
+ goto fail;
+ /* first character after : must be valid */
+ if (!str[1])
+ goto fail;
+ } else if (c)
+ /* fail - all other cases with embedded \0 */
+ goto fail;
+ }
+ if (!unpack_nameX(e, AA_ARRAYEND, NULL))
+ goto fail;
+ if (!unpack_nameX(e, AA_STRUCTEND, NULL))
+ goto fail;
+ }
+ return 1;
+
+fail:
+ aa_free_domain_entries(&profile->file.trans);
+ e->pos = pos;
+ return 0;
+}
+
+static bool unpack_rlimits(struct aa_ext *e, struct aa_profile *profile)
+{
+ void *pos = e->pos;
+
+ /* rlimits are optional */
+ if (unpack_nameX(e, AA_STRUCT, "rlimits")) {
+ int i, size;
+ u32 tmp = 0;
+ if (!unpack_u32(e, &tmp, NULL))
+ goto fail;
+ profile->rlimits.mask = tmp;
+
+ size = unpack_array(e, NULL);
+ if (size > RLIM_NLIMITS)
+ goto fail;
+ for (i = 0; i < size; i++) {
+ u64 tmp = 0;
+ int a = aa_map_resource(i);
+ if (!unpack_u64(e, &tmp, NULL))
+ goto fail;
+ profile->rlimits.limits[a].rlim_max = tmp;
+ }
+ if (!unpack_nameX(e, AA_ARRAYEND, NULL))
+ goto fail;
+ if (!unpack_nameX(e, AA_STRUCTEND, NULL))
+ goto fail;
+ }
+ return 1;
+
+fail:
+ e->pos = pos;
+ return 0;
+}
+
+/**
+ * unpack_profile - unpack a serialized profile
+ * @e: serialized data extent information (NOT NULL)
+ *
+ * NOTE: unpack profile sets audit struct if there is a failure
+ */
+static struct aa_profile *unpack_profile(struct aa_ext *e)
+{
+ struct aa_profile *profile = NULL;
+ const char *name = NULL;
+ int error = -EPROTO;
+ kernel_cap_t tmpcap;
+ u32 tmp;
+
+ /* check that we have the right struct being passed */
+ if (!unpack_nameX(e, AA_STRUCT, "profile"))
+ goto fail;
+ if (!unpack_str(e, &name, NULL))
+ goto fail;
+
+ profile = aa_alloc_profile(name);
+ if (!profile)
+ return ERR_PTR(-ENOMEM);
+
+ /* profile renaming is optional */
+ (void) unpack_str(e, &profile->rename, "rename");
+
+ /* xmatch is optional and may be NULL */
+ profile->xmatch = unpack_dfa(e);
+ if (IS_ERR(profile->xmatch)) {
+ error = PTR_ERR(profile->xmatch);
+ profile->xmatch = NULL;
+ goto fail;
+ }
+ /* xmatch_len is not optional if xmatch is set */
+ if (profile->xmatch) {
+ if (!unpack_u32(e, &tmp, NULL))
+ goto fail;
+ profile->xmatch_len = tmp;
+ }
+
+ /* per profile debug flags (complain, audit) */
+ if (!unpack_nameX(e, AA_STRUCT, "flags"))
+ goto fail;
+ if (!unpack_u32(e, &tmp, NULL))
+ goto fail;
+ if (tmp)
+ profile->flags |= PFLAG_HAT;
+ if (!unpack_u32(e, &tmp, NULL))
+ goto fail;
+ if (tmp)
+ profile->mode = APPARMOR_COMPLAIN;
+ if (!unpack_u32(e, &tmp, NULL))
+ goto fail;
+ if (tmp)
+ profile->audit = AUDIT_ALL;
+
+ if (!unpack_nameX(e, AA_STRUCTEND, NULL))
+ goto fail;
+
+ /* path_flags is optional */
+ if (unpack_u32(e, &profile->path_flags, "path_flags"))
+ profile->path_flags |= profile->flags & PFLAG_MEDIATE_DELETED;
+ else
+ /* set a default value if path_flags field is not present */
+ profile->path_flags = PFLAG_MEDIATE_DELETED;
+
+ if (!unpack_u32(e, &(profile->caps.allow.cap[0]), NULL))
+ goto fail;
+ if (!unpack_u32(e, &(profile->caps.audit.cap[0]), NULL))
+ goto fail;
+ if (!unpack_u32(e, &(profile->caps.quiet.cap[0]), NULL))
+ goto fail;
+ if (!unpack_u32(e, &tmpcap.cap[0], NULL))
+ goto fail;
+
+ if (unpack_nameX(e, AA_STRUCT, "caps64")) {
+ /* optional upper half of 64 bit caps */
+ if (!unpack_u32(e, &(profile->caps.allow.cap[1]), NULL))
+ goto fail;
+ if (!unpack_u32(e, &(profile->caps.audit.cap[1]), NULL))
+ goto fail;
+ if (!unpack_u32(e, &(profile->caps.quiet.cap[1]), NULL))
+ goto fail;
+ if (!unpack_u32(e, &(tmpcap.cap[1]), NULL))
+ goto fail;
+ if (!unpack_nameX(e, AA_STRUCTEND, NULL))
+ goto fail;
+ }
+
+ if (unpack_nameX(e, AA_STRUCT, "capsx")) {
+ /* optional extended caps mediation mask */
+ if (!unpack_u32(e, &(profile->caps.extended.cap[0]), NULL))
+ goto fail;
+ if (!unpack_u32(e, &(profile->caps.extended.cap[1]), NULL))
+ goto fail;
+ }
+
+ if (!unpack_rlimits(e, profile))
+ goto fail;
+
+ /* get file rules */
+ profile->file.dfa = unpack_dfa(e);
+ if (IS_ERR(profile->file.dfa)) {
+ error = PTR_ERR(profile->file.dfa);
+ profile->file.dfa = NULL;
+ goto fail;
+ }
+
+ if (!unpack_u32(e, &profile->file.start, "dfa_start"))
+ /* default start state */
+ profile->file.start = DFA_START;
+
+ if (!unpack_trans_table(e, profile))
+ goto fail;
+
+ if (!unpack_nameX(e, AA_STRUCTEND, NULL))
+ goto fail;
+
+ return profile;
+
+fail:
+ if (profile)
+ name = NULL;
+ else if (!name)
+ name = "unknown";
+ audit_iface(profile, name, "failed to unpack profile", e, error);
+ aa_put_profile(profile);
+
+ return ERR_PTR(error);
+}
+
+/**
+ * verify_head - unpack serialized stream header
+ * @e: serialized data read head (NOT NULL)
+ * @ns: Returns - namespace if one is specified else NULL (NOT NULL)
+ *
+ * Returns: error or 0 if header is good
+ */
+static int verify_header(struct aa_ext *e, const char **ns)
+{
+ int error = -EPROTONOSUPPORT;
+ /* get the interface version */
+ if (!unpack_u32(e, &e->version, "version")) {
+ audit_iface(NULL, NULL, "invalid profile format", e, error);
+ return error;
+ }
+
+ /* check that the interface version is currently supported */
+ if (e->version != 5) {
+ audit_iface(NULL, NULL, "unsupported interface version", e,
+ error);
+ return error;
+ }
+
+ /* read the namespace if present */
+ if (!unpack_str(e, ns, "namespace"))
+ *ns = NULL;
+
+ return 0;
+}
+
+static bool verify_xindex(int xindex, int table_size)
+{
+ int index, xtype;
+ xtype = xindex & AA_X_TYPE_MASK;
+ index = xindex & AA_X_INDEX_MASK;
+ if (xtype == AA_X_TABLE && index > table_size)
+ return 0;
+ return 1;
+}
+
+/* verify dfa xindexes are in range of transition tables */
+static bool verify_dfa_xindex(struct aa_dfa *dfa, int table_size)
+{
+ int i;
+ for (i = 0; i < dfa->tables[YYTD_ID_ACCEPT]->td_lolen; i++) {
+ if (!verify_xindex(dfa_user_xindex(dfa, i), table_size))
+ return 0;
+ if (!verify_xindex(dfa_other_xindex(dfa, i), table_size))
+ return 0;
+ }
+ return 1;
+}
+
+/**
+ * verify_profile - Do post unpack analysis to verify profile consistency
+ * @profile: profile to verify (NOT NULL)
+ *
+ * Returns: 0 if passes verification else error
+ */
+static int verify_profile(struct aa_profile *profile)
+{
+ if (aa_g_paranoid_load) {
+ if (profile->file.dfa &&
+ !verify_dfa_xindex(profile->file.dfa,
+ profile->file.trans.size)) {
+ audit_iface(profile, NULL, "Invalid named transition",
+ NULL, -EPROTO);
+ return -EPROTO;
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * aa_unpack - unpack packed binary profile data loaded from user space
+ * @udata: user data copied to kmem (NOT NULL)
+ * @size: the size of the user data
+ * @ns: Returns namespace profile is in if specified else NULL (NOT NULL)
+ *
+ * Unpack user data and return refcounted allocated profile or ERR_PTR
+ *
+ * Returns: profile else error pointer if fails to unpack
+ */
+struct aa_profile *aa_unpack(void *udata, size_t size, const char **ns)
+{
+ struct aa_profile *profile = NULL;
+ int error;
+ struct aa_ext e = {
+ .start = udata,
+ .end = udata + size,
+ .pos = udata,
+ };
+
+ error = verify_header(&e, ns);
+ if (error)
+ return ERR_PTR(error);
+
+ profile = unpack_profile(&e);
+ if (IS_ERR(profile))
+ return profile;
+
+ error = verify_profile(profile);
+ if (error) {
+ aa_put_profile(profile);
+ profile = ERR_PTR(error);
+ }
+
+ /* return refcount */
+ return profile;
+}
diff --git a/security/apparmor/procattr.c b/security/apparmor/procattr.c
new file mode 100644
index 00000000000..04a2cf8d1b6
--- /dev/null
+++ b/security/apparmor/procattr.c
@@ -0,0 +1,170 @@
+/*
+ * AppArmor security module
+ *
+ * This file contains AppArmor /proc/<pid>/attr/ interface functions
+ *
+ * Copyright (C) 1998-2008 Novell/SUSE
+ * Copyright 2009-2010 Canonical Ltd.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2 of the
+ * License.
+ */
+
+#include "include/apparmor.h"
+#include "include/context.h"
+#include "include/policy.h"
+#include "include/domain.h"
+
+
+/**
+ * aa_getprocattr - Return the profile information for @profile
+ * @profile: the profile to print profile info about (NOT NULL)
+ * @string: Returns - string containing the profile info (NOT NULL)
+ *
+ * Returns: length of @string on success else error on failure
+ *
+ * Requires: profile != NULL
+ *
+ * Creates a string containing the namespace_name://profile_name for
+ * @profile.
+ *
+ * Returns: size of string placed in @string else error code on failure
+ */
+int aa_getprocattr(struct aa_profile *profile, char **string)
+{
+ char *str;
+ int len = 0, mode_len = 0, ns_len = 0, name_len;
+ const char *mode_str = profile_mode_names[profile->mode];
+ const char *ns_name = NULL;
+ struct aa_namespace *ns = profile->ns;
+ struct aa_namespace *current_ns = __aa_current_profile()->ns;
+ char *s;
+
+ if (!aa_ns_visible(current_ns, ns))
+ return -EACCES;
+
+ ns_name = aa_ns_name(current_ns, ns);
+ ns_len = strlen(ns_name);
+
+ /* if the visible ns_name is > 0 increase size for : :// seperator */
+ if (ns_len)
+ ns_len += 4;
+
+ /* unconfined profiles don't have a mode string appended */
+ if (!unconfined(profile))
+ mode_len = strlen(mode_str) + 3; /* + 3 for _() */
+
+ name_len = strlen(profile->base.hname);
+ len = mode_len + ns_len + name_len + 1; /* + 1 for \n */
+ s = str = kmalloc(len + 1, GFP_KERNEL); /* + 1 \0 */
+ if (!str)
+ return -ENOMEM;
+
+ if (ns_len) {
+ /* skip over prefix current_ns->base.hname and separating // */
+ sprintf(s, ":%s://", ns_name);
+ s += ns_len;
+ }
+ if (unconfined(profile))
+ /* mode string not being appended */
+ sprintf(s, "%s\n", profile->base.hname);
+ else
+ sprintf(s, "%s (%s)\n", profile->base.hname, mode_str);
+ *string = str;
+
+ /* NOTE: len does not include \0 of string, not saved as part of file */
+ return len;
+}
+
+/**
+ * split_token_from_name - separate a string of form <token>^<name>
+ * @op: operation being checked
+ * @args: string to parse (NOT NULL)
+ * @token: stores returned parsed token value (NOT NULL)
+ *
+ * Returns: start position of name after token else NULL on failure
+ */
+static char *split_token_from_name(int op, char *args, u64 * token)
+{
+ char *name;
+
+ *token = simple_strtoull(args, &name, 16);
+ if ((name == args) || *name != '^') {
+ AA_ERROR("%s: Invalid input '%s'", op_table[op], args);
+ return ERR_PTR(-EINVAL);
+ }
+
+ name++; /* skip ^ */
+ if (!*name)
+ name = NULL;
+ return name;
+}
+
+/**
+ * aa_setprocattr_chagnehat - handle procattr interface to change_hat
+ * @args: args received from writing to /proc/<pid>/attr/current (NOT NULL)
+ * @size: size of the args
+ * @test: true if this is a test of change_hat permissions
+ *
+ * Returns: %0 or error code if change_hat fails
+ */
+int aa_setprocattr_changehat(char *args, size_t size, int test)
+{
+ char *hat;
+ u64 token;
+ const char *hats[16]; /* current hard limit on # of names */
+ int count = 0;
+
+ hat = split_token_from_name(OP_CHANGE_HAT, args, &token);
+ if (IS_ERR(hat))
+ return PTR_ERR(hat);
+
+ if (!hat && !token) {
+ AA_ERROR("change_hat: Invalid input, NULL hat and NULL magic");
+ return -EINVAL;
+ }
+
+ if (hat) {
+ /* set up hat name vector, args guaranteed null terminated
+ * at args[size] by setprocattr.
+ *
+ * If there are multiple hat names in the buffer each is
+ * separated by a \0. Ie. userspace writes them pre tokenized
+ */
+ char *end = args + size;
+ for (count = 0; (hat < end) && count < 16; ++count) {
+ char *next = hat + strlen(hat) + 1;
+ hats[count] = hat;
+ hat = next;
+ }
+ }
+
+ AA_DEBUG("%s: Magic 0x%llx Hat '%s'\n",
+ __func__, token, hat ? hat : NULL);
+
+ return aa_change_hat(hats, count, token, test);
+}
+
+/**
+ * aa_setprocattr_changeprofile - handle procattr interface to changeprofile
+ * @fqname: args received from writting to /proc/<pid>/attr/current (NOT NULL)
+ * @onexec: true if change_profile should be delayed until exec
+ * @test: true if this is a test of change_profile permissions
+ *
+ * Returns: %0 or error code if change_profile fails
+ */
+int aa_setprocattr_changeprofile(char *fqname, bool onexec, int test)
+{
+ char *name, *ns_name;
+
+ name = aa_split_fqname(fqname, &ns_name);
+ return aa_change_profile(ns_name, name, onexec, test);
+}
+
+int aa_setprocattr_permipc(char *fqname)
+{
+ /* TODO: add ipc permission querying */
+ return -ENOTSUPP;
+}
diff --git a/security/apparmor/resource.c b/security/apparmor/resource.c
new file mode 100644
index 00000000000..4a368f1fd36
--- /dev/null
+++ b/security/apparmor/resource.c
@@ -0,0 +1,134 @@
+/*
+ * AppArmor security module
+ *
+ * This file contains AppArmor resource mediation and attachment
+ *
+ * Copyright (C) 1998-2008 Novell/SUSE
+ * Copyright 2009-2010 Canonical Ltd.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2 of the
+ * License.
+ */
+
+#include <linux/audit.h>
+
+#include "include/audit.h"
+#include "include/resource.h"
+#include "include/policy.h"
+
+/*
+ * Table of rlimit names: we generate it from resource.h.
+ */
+#include "rlim_names.h"
+
+/* audit callback for resource specific fields */
+static void audit_cb(struct audit_buffer *ab, void *va)
+{
+ struct common_audit_data *sa = va;
+
+ audit_log_format(ab, " rlimit=%s value=%lu",
+ rlim_names[sa->aad.rlim.rlim], sa->aad.rlim.max);
+}
+
+/**
+ * audit_resource - audit setting resource limit
+ * @profile: profile being enforced (NOT NULL)
+ * @resoure: rlimit being auditing
+ * @value: value being set
+ * @error: error value
+ *
+ * Returns: 0 or sa->error else other error code on failure
+ */
+static int audit_resource(struct aa_profile *profile, unsigned int resource,
+ unsigned long value, int error)
+{
+ struct common_audit_data sa;
+
+ COMMON_AUDIT_DATA_INIT(&sa, NONE);
+ sa.aad.op = OP_SETRLIMIT,
+ sa.aad.rlim.rlim = resource;
+ sa.aad.rlim.max = value;
+ sa.aad.error = error;
+ return aa_audit(AUDIT_APPARMOR_AUTO, profile, GFP_KERNEL, &sa,
+ audit_cb);
+}
+
+/**
+ * aa_map_resouce - map compiled policy resource to internal #
+ * @resource: flattened policy resource number
+ *
+ * Returns: resource # for the current architecture.
+ *
+ * rlimit resource can vary based on architecture, map the compiled policy
+ * resource # to the internal representation for the architecture.
+ */
+int aa_map_resource(int resource)
+{
+ return rlim_map[resource];
+}
+
+/**
+ * aa_task_setrlimit - test permission to set an rlimit
+ * @profile - profile confining the task (NOT NULL)
+ * @resource - the resource being set
+ * @new_rlim - the new resource limit (NOT NULL)
+ *
+ * Control raising the processes hard limit.
+ *
+ * Returns: 0 or error code if setting resource failed
+ */
+int aa_task_setrlimit(struct aa_profile *profile, unsigned int resource,
+ struct rlimit *new_rlim)
+{
+ int error = 0;
+
+ if (profile->rlimits.mask & (1 << resource) &&
+ new_rlim->rlim_max > profile->rlimits.limits[resource].rlim_max)
+
+ error = audit_resource(profile, resource, new_rlim->rlim_max,
+ -EACCES);
+
+ return error;
+}
+
+/**
+ * __aa_transition_rlimits - apply new profile rlimits
+ * @old: old profile on task (NOT NULL)
+ * @new: new profile with rlimits to apply (NOT NULL)
+ */
+void __aa_transition_rlimits(struct aa_profile *old, struct aa_profile *new)
+{
+ unsigned int mask = 0;
+ struct rlimit *rlim, *initrlim;
+ int i;
+
+ /* for any rlimits the profile controlled reset the soft limit
+ * to the less of the tasks hard limit and the init tasks soft limit
+ */
+ if (old->rlimits.mask) {
+ for (i = 0, mask = 1; i < RLIM_NLIMITS; i++, mask <<= 1) {
+ if (old->rlimits.mask & mask) {
+ rlim = current->signal->rlim + i;
+ initrlim = init_task.signal->rlim + i;
+ rlim->rlim_cur = min(rlim->rlim_max,
+ initrlim->rlim_cur);
+ }
+ }
+ }
+
+ /* set any new hard limits as dictated by the new profile */
+ if (!new->rlimits.mask)
+ return;
+ for (i = 0, mask = 1; i < RLIM_NLIMITS; i++, mask <<= 1) {
+ if (!(new->rlimits.mask & mask))
+ continue;
+
+ rlim = current->signal->rlim + i;
+ rlim->rlim_max = min(rlim->rlim_max,
+ new->rlimits.limits[i].rlim_max);
+ /* soft limit should not exceed hard limit */
+ rlim->rlim_cur = min(rlim->rlim_cur, rlim->rlim_max);
+ }
+}
diff --git a/security/apparmor/sid.c b/security/apparmor/sid.c
new file mode 100644
index 00000000000..f0b34f76ebe
--- /dev/null
+++ b/security/apparmor/sid.c
@@ -0,0 +1,55 @@
+/*
+ * AppArmor security module
+ *
+ * This file contains AppArmor security identifier (sid) manipulation fns
+ *
+ * Copyright 2009-2010 Canonical Ltd.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2 of the
+ * License.
+ *
+ *
+ * AppArmor allocates a unique sid for every profile loaded. If a profile
+ * is replaced it receives the sid of the profile it is replacing.
+ *
+ * The sid value of 0 is invalid.
+ */
+
+#include <linux/spinlock.h>
+#include <linux/errno.h>
+#include <linux/err.h>
+
+#include "include/sid.h"
+
+/* global counter from which sids are allocated */
+static u32 global_sid;
+static DEFINE_SPINLOCK(sid_lock);
+
+/* TODO FIXME: add sid to profile mapping, and sid recycling */
+
+/**
+ * aa_alloc_sid - allocate a new sid for a profile
+ */
+u32 aa_alloc_sid(void)
+{
+ u32 sid;
+
+ /*
+ * TODO FIXME: sid recycling - part of profile mapping table
+ */
+ spin_lock(&sid_lock);
+ sid = (++global_sid);
+ spin_unlock(&sid_lock);
+ return sid;
+}
+
+/**
+ * aa_free_sid - free a sid
+ * @sid: sid to free
+ */
+void aa_free_sid(u32 sid)
+{
+ ; /* NOP ATM */
+}
diff --git a/security/capability.c b/security/capability.c
index 8168e3ecd5b..a0bbf30fb6d 100644
--- a/security/capability.c
+++ b/security/capability.c
@@ -27,7 +27,7 @@ static int cap_quota_on(struct dentry *dentry)
return 0;
}
-static int cap_bprm_check_security (struct linux_binprm *bprm)
+static int cap_bprm_check_security(struct linux_binprm *bprm)
{
return 0;
}
@@ -268,8 +268,7 @@ static int cap_path_rename(struct path *old_path, struct dentry *old_dentry,
return 0;
}
-static int cap_path_truncate(struct path *path, loff_t length,
- unsigned int time_attrs)
+static int cap_path_truncate(struct path *path)
{
return 0;
}
diff --git a/security/inode.c b/security/inode.c
index 1c812e87450..8c777f022ad 100644
--- a/security/inode.c
+++ b/security/inode.c
@@ -86,7 +86,7 @@ static int mknod(struct inode *dir, struct dentry *dentry,
int mode, dev_t dev)
{
struct inode *inode;
- int error = -EPERM;
+ int error = -ENOMEM;
if (dentry->d_inode)
return -EEXIST;
@@ -166,6 +166,8 @@ static int create_by_name(const char *name, mode_t mode,
error = mkdir(parent->d_inode, *dentry, mode);
else
error = create(parent->d_inode, *dentry, mode);
+ if (error)
+ dput(*dentry);
} else
error = PTR_ERR(*dentry);
mutex_unlock(&parent->d_inode->i_mutex);
diff --git a/security/integrity/ima/ima_fs.c b/security/integrity/ima/ima_fs.c
index 8fe736aabe7..ef21b96a0b4 100644
--- a/security/integrity/ima/ima_fs.c
+++ b/security/integrity/ima/ima_fs.c
@@ -45,7 +45,8 @@ static ssize_t ima_show_htable_violations(struct file *filp,
}
static const struct file_operations ima_htable_violations_ops = {
- .read = ima_show_htable_violations
+ .read = ima_show_htable_violations,
+ .llseek = generic_file_llseek,
};
static ssize_t ima_show_measurements_count(struct file *filp,
@@ -57,7 +58,8 @@ static ssize_t ima_show_measurements_count(struct file *filp,
}
static const struct file_operations ima_measurements_count_ops = {
- .read = ima_show_measurements_count
+ .read = ima_show_measurements_count,
+ .llseek = generic_file_llseek,
};
/* returns pointer to hlist_node */
@@ -319,7 +321,8 @@ static int ima_release_policy(struct inode *inode, struct file *file)
static const struct file_operations ima_measure_policy_ops = {
.open = ima_open_policy,
.write = ima_write_policy,
- .release = ima_release_policy
+ .release = ima_release_policy,
+ .llseek = generic_file_llseek,
};
int __init ima_fs_init(void)
diff --git a/security/keys/internal.h b/security/keys/internal.h
index 38783dcf6c6..addb67b169f 100644
--- a/security/keys/internal.h
+++ b/security/keys/internal.h
@@ -114,6 +114,10 @@ extern key_ref_t keyring_search_aux(key_ref_t keyring_ref,
const void *description,
key_match_func_t match);
+extern key_ref_t search_my_process_keyrings(struct key_type *type,
+ const void *description,
+ key_match_func_t match,
+ const struct cred *cred);
extern key_ref_t search_process_keyrings(struct key_type *type,
const void *description,
key_match_func_t match,
@@ -134,6 +138,7 @@ extern struct key *request_key_and_link(struct key_type *type,
struct key *dest_keyring,
unsigned long flags);
+extern int lookup_user_key_possessed(const struct key *key, const void *target);
extern key_ref_t lookup_user_key(key_serial_t id, unsigned long flags,
key_perm_t perm);
#define KEY_LOOKUP_CREATE 0x01
diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c
index 6261745e445..b2b0998d6ab 100644
--- a/security/keys/keyctl.c
+++ b/security/keys/keyctl.c
@@ -505,13 +505,11 @@ okay:
ret = snprintf(tmpbuf, PAGE_SIZE - 1,
"%s;%d;%d;%08x;%s",
- key_ref_to_ptr(key_ref)->type->name,
- key_ref_to_ptr(key_ref)->uid,
- key_ref_to_ptr(key_ref)->gid,
- key_ref_to_ptr(key_ref)->perm,
- key_ref_to_ptr(key_ref)->description ?
- key_ref_to_ptr(key_ref)->description : ""
- );
+ key->type->name,
+ key->uid,
+ key->gid,
+ key->perm,
+ key->description ?: "");
/* include a NUL char at the end of the data */
if (ret > PAGE_SIZE - 1)
@@ -1091,7 +1089,7 @@ error:
long keyctl_set_timeout(key_serial_t id, unsigned timeout)
{
struct timespec now;
- struct key *key;
+ struct key *key, *instkey;
key_ref_t key_ref;
time_t expiry;
long ret;
@@ -1099,10 +1097,25 @@ long keyctl_set_timeout(key_serial_t id, unsigned timeout)
key_ref = lookup_user_key(id, KEY_LOOKUP_CREATE | KEY_LOOKUP_PARTIAL,
KEY_SETATTR);
if (IS_ERR(key_ref)) {
+ /* setting the timeout on a key under construction is permitted
+ * if we have the authorisation token handy */
+ if (PTR_ERR(key_ref) == -EACCES) {
+ instkey = key_get_instantiation_authkey(id);
+ if (!IS_ERR(instkey)) {
+ key_put(instkey);
+ key_ref = lookup_user_key(id,
+ KEY_LOOKUP_PARTIAL,
+ 0);
+ if (!IS_ERR(key_ref))
+ goto okay;
+ }
+ }
+
ret = PTR_ERR(key_ref);
goto error;
}
+okay:
key = key_ref_to_ptr(key_ref);
/* make the changes with the locks held to prevent races */
diff --git a/security/keys/proc.c b/security/keys/proc.c
index 068b66ea2f1..70373966816 100644
--- a/security/keys/proc.c
+++ b/security/keys/proc.c
@@ -184,20 +184,36 @@ static void proc_keys_stop(struct seq_file *p, void *v)
static int proc_keys_show(struct seq_file *m, void *v)
{
+ const struct cred *cred = current_cred();
struct rb_node *_p = v;
struct key *key = rb_entry(_p, struct key, serial_node);
struct timespec now;
unsigned long timo;
+ key_ref_t key_ref, skey_ref;
char xbuf[12];
int rc;
+ key_ref = make_key_ref(key, 0);
+
+ /* determine if the key is possessed by this process (a test we can
+ * skip if the key does not indicate the possessor can view it
+ */
+ if (key->perm & KEY_POS_VIEW) {
+ skey_ref = search_my_process_keyrings(key->type, key,
+ lookup_user_key_possessed,
+ cred);
+ if (!IS_ERR(skey_ref)) {
+ key_ref_put(skey_ref);
+ key_ref = make_key_ref(key, 1);
+ }
+ }
+
/* check whether the current task is allowed to view the key (assuming
* non-possession)
* - the caller holds a spinlock, and thus the RCU read lock, making our
* access to __current_cred() safe
*/
- rc = key_task_permission(make_key_ref(key, 0), current_cred(),
- KEY_VIEW);
+ rc = key_task_permission(key_ref, cred, KEY_VIEW);
if (rc < 0)
return 0;
diff --git a/security/keys/process_keys.c b/security/keys/process_keys.c
index 6b8e4ff4cc6..f8e7251ae2c 100644
--- a/security/keys/process_keys.c
+++ b/security/keys/process_keys.c
@@ -309,22 +309,19 @@ void key_fsgid_changed(struct task_struct *tsk)
/*****************************************************************************/
/*
- * search the process keyrings for the first matching key
+ * search only my process keyrings for the first matching key
* - we use the supplied match function to see if the description (or other
* feature of interest) matches
* - we return -EAGAIN if we didn't find any matching key
* - we return -ENOKEY if we found only negative matching keys
*/
-key_ref_t search_process_keyrings(struct key_type *type,
- const void *description,
- key_match_func_t match,
- const struct cred *cred)
+key_ref_t search_my_process_keyrings(struct key_type *type,
+ const void *description,
+ key_match_func_t match,
+ const struct cred *cred)
{
- struct request_key_auth *rka;
key_ref_t key_ref, ret, err;
- might_sleep();
-
/* we want to return -EAGAIN or -ENOKEY if any of the keyrings were
* searchable, but we failed to find a key or we found a negative key;
* otherwise we want to return a sample error (probably -EACCES) if
@@ -424,6 +421,36 @@ key_ref_t search_process_keyrings(struct key_type *type,
}
}
+ /* no key - decide on the error we're going to go for */
+ key_ref = ret ? ret : err;
+
+found:
+ return key_ref;
+}
+
+/*****************************************************************************/
+/*
+ * search the process keyrings for the first matching key
+ * - we use the supplied match function to see if the description (or other
+ * feature of interest) matches
+ * - we return -EAGAIN if we didn't find any matching key
+ * - we return -ENOKEY if we found only negative matching keys
+ */
+key_ref_t search_process_keyrings(struct key_type *type,
+ const void *description,
+ key_match_func_t match,
+ const struct cred *cred)
+{
+ struct request_key_auth *rka;
+ key_ref_t key_ref, ret = ERR_PTR(-EACCES), err;
+
+ might_sleep();
+
+ key_ref = search_my_process_keyrings(type, description, match, cred);
+ if (!IS_ERR(key_ref))
+ goto found;
+ err = key_ref;
+
/* if this process has an instantiation authorisation key, then we also
* search the keyrings of the process mentioned there
* - we don't permit access to request_key auth keys via this method
@@ -446,24 +473,19 @@ key_ref_t search_process_keyrings(struct key_type *type,
if (!IS_ERR(key_ref))
goto found;
- switch (PTR_ERR(key_ref)) {
- case -EAGAIN: /* no key */
- if (ret)
- break;
- case -ENOKEY: /* negative key */
- ret = key_ref;
- break;
- default:
- err = key_ref;
- break;
- }
+ ret = key_ref;
} else {
up_read(&cred->request_key_auth->sem);
}
}
/* no key - decide on the error we're going to go for */
- key_ref = ret ? ret : err;
+ if (err == ERR_PTR(-ENOKEY) || ret == ERR_PTR(-ENOKEY))
+ key_ref = ERR_PTR(-ENOKEY);
+ else if (err == ERR_PTR(-EACCES))
+ key_ref = ret;
+ else
+ key_ref = err;
found:
return key_ref;
@@ -474,7 +496,7 @@ found:
/*
* see if the key we're looking at is the target key
*/
-static int lookup_user_key_possessed(const struct key *key, const void *target)
+int lookup_user_key_possessed(const struct key *key, const void *target)
{
return key == target;
diff --git a/security/keys/request_key.c b/security/keys/request_key.c
index f5ec9ac5d57..0088dd8bf68 100644
--- a/security/keys/request_key.c
+++ b/security/keys/request_key.c
@@ -144,6 +144,7 @@ static int call_sbin_request_key(struct key_construction *cons,
prkey = 0;
if (cred->tgcred->process_keyring)
prkey = cred->tgcred->process_keyring->serial;
+ sprintf(keyring_str[1], "%d", prkey);
rcu_read_lock();
session = rcu_dereference(cred->tgcred->session_keyring);
@@ -536,6 +537,8 @@ int wait_for_key_construction(struct key *key, bool intr)
intr ? TASK_INTERRUPTIBLE : TASK_UNINTERRUPTIBLE);
if (ret < 0)
return ret;
+ if (test_bit(KEY_FLAG_NEGATIVE, &key->flags))
+ return -ENOKEY;
return key_validate(key);
}
EXPORT_SYMBOL(wait_for_key_construction);
diff --git a/security/security.c b/security/security.c
index 351942a4ca0..e8c87b8601b 100644
--- a/security/security.c
+++ b/security/security.c
@@ -417,12 +417,11 @@ int security_path_rename(struct path *old_dir, struct dentry *old_dentry,
new_dentry);
}
-int security_path_truncate(struct path *path, loff_t length,
- unsigned int time_attrs)
+int security_path_truncate(struct path *path)
{
if (unlikely(IS_PRIVATE(path->dentry->d_inode)))
return 0;
- return security_ops->path_truncate(path, length, time_attrs);
+ return security_ops->path_truncate(path);
}
int security_path_chmod(struct dentry *dentry, struct vfsmount *mnt,
diff --git a/security/selinux/Makefile b/security/selinux/Makefile
index f013982df41..58d80f3bd6f 100644
--- a/security/selinux/Makefile
+++ b/security/selinux/Makefile
@@ -25,6 +25,6 @@ $(obj)/avc.o: $(obj)/flask.h
quiet_cmd_flask = GEN $(obj)/flask.h $(obj)/av_permissions.h
cmd_flask = scripts/selinux/genheaders/genheaders $(obj)/flask.h $(obj)/av_permissions.h
-targets += flask.h
+targets += flask.h av_permissions.h
$(obj)/flask.h: $(src)/include/classmap.h FORCE
$(call if_changed,flask)
diff --git a/security/selinux/avc.c b/security/selinux/avc.c
index 7f1a304712a..9da6420e205 100644
--- a/security/selinux/avc.c
+++ b/security/selinux/avc.c
@@ -288,7 +288,6 @@ static struct avc_node *avc_alloc_node(void)
if (!node)
goto out;
- INIT_RCU_HEAD(&node->rhead);
INIT_HLIST_NODE(&node->list);
avc_cache_stats_incr(allocations);
@@ -489,9 +488,29 @@ void avc_audit(u32 ssid, u32 tsid,
struct common_audit_data stack_data;
u32 denied, audited;
denied = requested & ~avd->allowed;
- if (denied)
+ if (denied) {
audited = denied & avd->auditdeny;
- else if (result)
+ /*
+ * a->selinux_audit_data.auditdeny is TRICKY! Setting a bit in
+ * this field means that ANY denials should NOT be audited if
+ * the policy contains an explicit dontaudit rule for that
+ * permission. Take notice that this is unrelated to the
+ * actual permissions that were denied. As an example lets
+ * assume:
+ *
+ * denied == READ
+ * avd.auditdeny & ACCESS == 0 (not set means explicit rule)
+ * selinux_audit_data.auditdeny & ACCESS == 1
+ *
+ * We will NOT audit the denial even though the denied
+ * permission was READ and the auditdeny checks were for
+ * ACCESS
+ */
+ if (a &&
+ a->selinux_audit_data.auditdeny &&
+ !(a->selinux_audit_data.auditdeny & avd->auditdeny))
+ audited = 0;
+ } else if (result)
audited = denied = requested;
else
audited = requested & avd->auditallow;
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 5c9f25ba1c9..9b40f4c0ac7 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -87,9 +87,6 @@
#include "netlabel.h"
#include "audit.h"
-#define XATTR_SELINUX_SUFFIX "selinux"
-#define XATTR_NAME_SELINUX XATTR_SECURITY_PREFIX XATTR_SELINUX_SUFFIX
-
#define NUM_SEL_MNT_OPTS 5
extern int selinux_nlmsg_lookup(u16 sclass, u16 nlmsg_type, u32 *perm);
@@ -188,7 +185,7 @@ static inline u32 task_sid(const struct task_struct *task)
*/
static inline u32 current_sid(void)
{
- const struct task_security_struct *tsec = current_cred()->security;
+ const struct task_security_struct *tsec = current_security();
return tsec->sid;
}
@@ -279,32 +276,6 @@ static void superblock_free_security(struct super_block *sb)
kfree(sbsec);
}
-static int sk_alloc_security(struct sock *sk, int family, gfp_t priority)
-{
- struct sk_security_struct *sksec;
-
- sksec = kzalloc(sizeof(*sksec), priority);
- if (!sksec)
- return -ENOMEM;
-
- sksec->peer_sid = SECINITSID_UNLABELED;
- sksec->sid = SECINITSID_UNLABELED;
- sk->sk_security = sksec;
-
- selinux_netlbl_sk_security_reset(sksec);
-
- return 0;
-}
-
-static void sk_free_security(struct sock *sk)
-{
- struct sk_security_struct *sksec = sk->sk_security;
-
- sk->sk_security = NULL;
- selinux_netlbl_sk_security_free(sksec);
- kfree(sksec);
-}
-
/* The security server must be initialized before
any labeling or access decisions can be provided. */
extern int ss_initialized;
@@ -1584,8 +1555,7 @@ static int may_create(struct inode *dir,
struct dentry *dentry,
u16 tclass)
{
- const struct cred *cred = current_cred();
- const struct task_security_struct *tsec = cred->security;
+ const struct task_security_struct *tsec = current_security();
struct inode_security_struct *dsec;
struct superblock_security_struct *sbsec;
u32 sid, newsid;
@@ -1806,27 +1776,9 @@ static inline u32 open_file_to_av(struct file *file)
{
u32 av = file_to_av(file);
- if (selinux_policycap_openperm) {
- mode_t mode = file->f_path.dentry->d_inode->i_mode;
- /*
- * lnk files and socks do not really have an 'open'
- */
- if (S_ISREG(mode))
- av |= FILE__OPEN;
- else if (S_ISCHR(mode))
- av |= CHR_FILE__OPEN;
- else if (S_ISBLK(mode))
- av |= BLK_FILE__OPEN;
- else if (S_ISFIFO(mode))
- av |= FIFO_FILE__OPEN;
- else if (S_ISDIR(mode))
- av |= DIR__OPEN;
- else if (S_ISSOCK(mode))
- av |= SOCK_FILE__OPEN;
- else
- printk(KERN_ERR "SELinux: WARNING: inside %s with "
- "unknown mode:%o\n", __func__, mode);
- }
+ if (selinux_policycap_openperm)
+ av |= FILE__OPEN;
+
return av;
}
@@ -2183,8 +2135,7 @@ static int selinux_bprm_set_creds(struct linux_binprm *bprm)
static int selinux_bprm_secureexec(struct linux_binprm *bprm)
{
- const struct cred *cred = current_cred();
- const struct task_security_struct *tsec = cred->security;
+ const struct task_security_struct *tsec = current_security();
u32 sid, osid;
int atsecure = 0;
@@ -2559,8 +2510,7 @@ static int selinux_inode_init_security(struct inode *inode, struct inode *dir,
char **name, void **value,
size_t *len)
{
- const struct cred *cred = current_cred();
- const struct task_security_struct *tsec = cred->security;
+ const struct task_security_struct *tsec = current_security();
struct inode_security_struct *dsec;
struct superblock_security_struct *sbsec;
u32 sid, newsid, clen;
@@ -2676,14 +2626,26 @@ static int selinux_inode_follow_link(struct dentry *dentry, struct nameidata *na
static int selinux_inode_permission(struct inode *inode, int mask)
{
const struct cred *cred = current_cred();
+ struct common_audit_data ad;
+ u32 perms;
+ bool from_access;
- if (!mask) {
- /* No permission to check. Existence test. */
+ from_access = mask & MAY_ACCESS;
+ mask &= (MAY_READ|MAY_WRITE|MAY_EXEC|MAY_APPEND);
+
+ /* No permission to check. Existence test. */
+ if (!mask)
return 0;
- }
- return inode_has_perm(cred, inode,
- file_mask_to_av(inode->i_mode, mask), NULL);
+ COMMON_AUDIT_DATA_INIT(&ad, FS);
+ ad.u.fs.inode = inode;
+
+ if (from_access)
+ ad.selinux_audit_data.auditdeny |= FILE__AUDIT_ACCESS;
+
+ perms = file_mask_to_av(inode->i_mode, mask);
+
+ return inode_has_perm(cred, inode, perms, &ad);
}
static int selinux_inode_setattr(struct dentry *dentry, struct iattr *iattr)
@@ -3671,71 +3633,54 @@ static int selinux_skb_peerlbl_sid(struct sk_buff *skb, u16 family, u32 *sid)
}
/* socket security operations */
-static int socket_has_perm(struct task_struct *task, struct socket *sock,
- u32 perms)
+
+static u32 socket_sockcreate_sid(const struct task_security_struct *tsec)
{
- struct inode_security_struct *isec;
- struct common_audit_data ad;
- u32 sid;
- int err = 0;
+ return tsec->sockcreate_sid ? : tsec->sid;
+}
- isec = SOCK_INODE(sock)->i_security;
+static int sock_has_perm(struct task_struct *task, struct sock *sk, u32 perms)
+{
+ struct sk_security_struct *sksec = sk->sk_security;
+ struct common_audit_data ad;
+ u32 tsid = task_sid(task);
- if (isec->sid == SECINITSID_KERNEL)
- goto out;
- sid = task_sid(task);
+ if (sksec->sid == SECINITSID_KERNEL)
+ return 0;
COMMON_AUDIT_DATA_INIT(&ad, NET);
- ad.u.net.sk = sock->sk;
- err = avc_has_perm(sid, isec->sid, isec->sclass, perms, &ad);
+ ad.u.net.sk = sk;
-out:
- return err;
+ return avc_has_perm(tsid, sksec->sid, sksec->sclass, perms, &ad);
}
static int selinux_socket_create(int family, int type,
int protocol, int kern)
{
- const struct cred *cred = current_cred();
- const struct task_security_struct *tsec = cred->security;
- u32 sid, newsid;
+ const struct task_security_struct *tsec = current_security();
+ u32 newsid;
u16 secclass;
- int err = 0;
if (kern)
- goto out;
-
- sid = tsec->sid;
- newsid = tsec->sockcreate_sid ?: sid;
+ return 0;
+ newsid = socket_sockcreate_sid(tsec);
secclass = socket_type_to_security_class(family, type, protocol);
- err = avc_has_perm(sid, newsid, secclass, SOCKET__CREATE, NULL);
-
-out:
- return err;
+ return avc_has_perm(tsec->sid, newsid, secclass, SOCKET__CREATE, NULL);
}
static int selinux_socket_post_create(struct socket *sock, int family,
int type, int protocol, int kern)
{
- const struct cred *cred = current_cred();
- const struct task_security_struct *tsec = cred->security;
- struct inode_security_struct *isec;
+ const struct task_security_struct *tsec = current_security();
+ struct inode_security_struct *isec = SOCK_INODE(sock)->i_security;
struct sk_security_struct *sksec;
- u32 sid, newsid;
int err = 0;
- sid = tsec->sid;
- newsid = tsec->sockcreate_sid;
-
- isec = SOCK_INODE(sock)->i_security;
-
if (kern)
isec->sid = SECINITSID_KERNEL;
- else if (newsid)
- isec->sid = newsid;
else
- isec->sid = sid;
+ isec->sid = socket_sockcreate_sid(tsec);
isec->sclass = socket_type_to_security_class(family, type, protocol);
isec->initialized = 1;
@@ -3756,10 +3701,11 @@ static int selinux_socket_post_create(struct socket *sock, int family,
static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, int addrlen)
{
+ struct sock *sk = sock->sk;
u16 family;
int err;
- err = socket_has_perm(current, sock, SOCKET__BIND);
+ err = sock_has_perm(current, sk, SOCKET__BIND);
if (err)
goto out;
@@ -3768,19 +3714,16 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in
* Multiple address binding for SCTP is not supported yet: we just
* check the first address now.
*/
- family = sock->sk->sk_family;
+ family = sk->sk_family;
if (family == PF_INET || family == PF_INET6) {
char *addrp;
- struct inode_security_struct *isec;
+ struct sk_security_struct *sksec = sk->sk_security;
struct common_audit_data ad;
struct sockaddr_in *addr4 = NULL;
struct sockaddr_in6 *addr6 = NULL;
unsigned short snum;
- struct sock *sk = sock->sk;
u32 sid, node_perm;
- isec = SOCK_INODE(sock)->i_security;
-
if (family == PF_INET) {
addr4 = (struct sockaddr_in *)address;
snum = ntohs(addr4->sin_port);
@@ -3804,15 +3747,15 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in
COMMON_AUDIT_DATA_INIT(&ad, NET);
ad.u.net.sport = htons(snum);
ad.u.net.family = family;
- err = avc_has_perm(isec->sid, sid,
- isec->sclass,
+ err = avc_has_perm(sksec->sid, sid,
+ sksec->sclass,
SOCKET__NAME_BIND, &ad);
if (err)
goto out;
}
}
- switch (isec->sclass) {
+ switch (sksec->sclass) {
case SECCLASS_TCP_SOCKET:
node_perm = TCP_SOCKET__NODE_BIND;
break;
@@ -3843,8 +3786,8 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in
else
ipv6_addr_copy(&ad.u.net.v6info.saddr, &addr6->sin6_addr);
- err = avc_has_perm(isec->sid, sid,
- isec->sclass, node_perm, &ad);
+ err = avc_has_perm(sksec->sid, sid,
+ sksec->sclass, node_perm, &ad);
if (err)
goto out;
}
@@ -3855,19 +3798,18 @@ out:
static int selinux_socket_connect(struct socket *sock, struct sockaddr *address, int addrlen)
{
struct sock *sk = sock->sk;
- struct inode_security_struct *isec;
+ struct sk_security_struct *sksec = sk->sk_security;
int err;
- err = socket_has_perm(current, sock, SOCKET__CONNECT);
+ err = sock_has_perm(current, sk, SOCKET__CONNECT);
if (err)
return err;
/*
* If a TCP or DCCP socket, check name_connect permission for the port.
*/
- isec = SOCK_INODE(sock)->i_security;
- if (isec->sclass == SECCLASS_TCP_SOCKET ||
- isec->sclass == SECCLASS_DCCP_SOCKET) {
+ if (sksec->sclass == SECCLASS_TCP_SOCKET ||
+ sksec->sclass == SECCLASS_DCCP_SOCKET) {
struct common_audit_data ad;
struct sockaddr_in *addr4 = NULL;
struct sockaddr_in6 *addr6 = NULL;
@@ -3890,13 +3832,13 @@ static int selinux_socket_connect(struct socket *sock, struct sockaddr *address,
if (err)
goto out;
- perm = (isec->sclass == SECCLASS_TCP_SOCKET) ?
+ perm = (sksec->sclass == SECCLASS_TCP_SOCKET) ?
TCP_SOCKET__NAME_CONNECT : DCCP_SOCKET__NAME_CONNECT;
COMMON_AUDIT_DATA_INIT(&ad, NET);
ad.u.net.dport = htons(snum);
ad.u.net.family = sk->sk_family;
- err = avc_has_perm(isec->sid, sid, isec->sclass, perm, &ad);
+ err = avc_has_perm(sksec->sid, sid, sksec->sclass, perm, &ad);
if (err)
goto out;
}
@@ -3909,7 +3851,7 @@ out:
static int selinux_socket_listen(struct socket *sock, int backlog)
{
- return socket_has_perm(current, sock, SOCKET__LISTEN);
+ return sock_has_perm(current, sock->sk, SOCKET__LISTEN);
}
static int selinux_socket_accept(struct socket *sock, struct socket *newsock)
@@ -3918,7 +3860,7 @@ static int selinux_socket_accept(struct socket *sock, struct socket *newsock)
struct inode_security_struct *isec;
struct inode_security_struct *newisec;
- err = socket_has_perm(current, sock, SOCKET__ACCEPT);
+ err = sock_has_perm(current, sock->sk, SOCKET__ACCEPT);
if (err)
return err;
@@ -3935,30 +3877,30 @@ static int selinux_socket_accept(struct socket *sock, struct socket *newsock)
static int selinux_socket_sendmsg(struct socket *sock, struct msghdr *msg,
int size)
{
- return socket_has_perm(current, sock, SOCKET__WRITE);
+ return sock_has_perm(current, sock->sk, SOCKET__WRITE);
}
static int selinux_socket_recvmsg(struct socket *sock, struct msghdr *msg,
int size, int flags)
{
- return socket_has_perm(current, sock, SOCKET__READ);
+ return sock_has_perm(current, sock->sk, SOCKET__READ);
}
static int selinux_socket_getsockname(struct socket *sock)
{
- return socket_has_perm(current, sock, SOCKET__GETATTR);
+ return sock_has_perm(current, sock->sk, SOCKET__GETATTR);
}
static int selinux_socket_getpeername(struct socket *sock)
{
- return socket_has_perm(current, sock, SOCKET__GETATTR);
+ return sock_has_perm(current, sock->sk, SOCKET__GETATTR);
}
static int selinux_socket_setsockopt(struct socket *sock, int level, int optname)
{
int err;
- err = socket_has_perm(current, sock, SOCKET__SETOPT);
+ err = sock_has_perm(current, sock->sk, SOCKET__SETOPT);
if (err)
return err;
@@ -3968,68 +3910,58 @@ static int selinux_socket_setsockopt(struct socket *sock, int level, int optname
static int selinux_socket_getsockopt(struct socket *sock, int level,
int optname)
{
- return socket_has_perm(current, sock, SOCKET__GETOPT);
+ return sock_has_perm(current, sock->sk, SOCKET__GETOPT);
}
static int selinux_socket_shutdown(struct socket *sock, int how)
{
- return socket_has_perm(current, sock, SOCKET__SHUTDOWN);
+ return sock_has_perm(current, sock->sk, SOCKET__SHUTDOWN);
}
static int selinux_socket_unix_stream_connect(struct socket *sock,
struct socket *other,
struct sock *newsk)
{
- struct sk_security_struct *sksec;
- struct inode_security_struct *isec;
- struct inode_security_struct *other_isec;
+ struct sk_security_struct *sksec_sock = sock->sk->sk_security;
+ struct sk_security_struct *sksec_other = other->sk->sk_security;
+ struct sk_security_struct *sksec_new = newsk->sk_security;
struct common_audit_data ad;
int err;
- isec = SOCK_INODE(sock)->i_security;
- other_isec = SOCK_INODE(other)->i_security;
-
COMMON_AUDIT_DATA_INIT(&ad, NET);
ad.u.net.sk = other->sk;
- err = avc_has_perm(isec->sid, other_isec->sid,
- isec->sclass,
+ err = avc_has_perm(sksec_sock->sid, sksec_other->sid,
+ sksec_other->sclass,
UNIX_STREAM_SOCKET__CONNECTTO, &ad);
if (err)
return err;
- /* connecting socket */
- sksec = sock->sk->sk_security;
- sksec->peer_sid = other_isec->sid;
-
/* server child socket */
- sksec = newsk->sk_security;
- sksec->peer_sid = isec->sid;
- err = security_sid_mls_copy(other_isec->sid, sksec->peer_sid, &sksec->sid);
+ sksec_new->peer_sid = sksec_sock->sid;
+ err = security_sid_mls_copy(sksec_other->sid, sksec_sock->sid,
+ &sksec_new->sid);
+ if (err)
+ return err;
- return err;
+ /* connecting socket */
+ sksec_sock->peer_sid = sksec_new->sid;
+
+ return 0;
}
static int selinux_socket_unix_may_send(struct socket *sock,
struct socket *other)
{
- struct inode_security_struct *isec;
- struct inode_security_struct *other_isec;
+ struct sk_security_struct *ssec = sock->sk->sk_security;
+ struct sk_security_struct *osec = other->sk->sk_security;
struct common_audit_data ad;
- int err;
-
- isec = SOCK_INODE(sock)->i_security;
- other_isec = SOCK_INODE(other)->i_security;
COMMON_AUDIT_DATA_INIT(&ad, NET);
ad.u.net.sk = other->sk;
- err = avc_has_perm(isec->sid, other_isec->sid,
- isec->sclass, SOCKET__SENDTO, &ad);
- if (err)
- return err;
-
- return 0;
+ return avc_has_perm(ssec->sid, osec->sid, osec->sclass, SOCKET__SENDTO,
+ &ad);
}
static int selinux_inet_sys_rcv_skb(int ifindex, char *addrp, u16 family,
@@ -4168,26 +4100,18 @@ static int selinux_socket_getpeersec_stream(struct socket *sock, char __user *op
int err = 0;
char *scontext;
u32 scontext_len;
- struct sk_security_struct *sksec;
- struct inode_security_struct *isec;
+ struct sk_security_struct *sksec = sock->sk->sk_security;
u32 peer_sid = SECSID_NULL;
- isec = SOCK_INODE(sock)->i_security;
-
- if (isec->sclass == SECCLASS_UNIX_STREAM_SOCKET ||
- isec->sclass == SECCLASS_TCP_SOCKET) {
- sksec = sock->sk->sk_security;
+ if (sksec->sclass == SECCLASS_UNIX_STREAM_SOCKET ||
+ sksec->sclass == SECCLASS_TCP_SOCKET)
peer_sid = sksec->peer_sid;
- }
- if (peer_sid == SECSID_NULL) {
- err = -ENOPROTOOPT;
- goto out;
- }
+ if (peer_sid == SECSID_NULL)
+ return -ENOPROTOOPT;
err = security_sid_to_context(peer_sid, &scontext, &scontext_len);
-
if (err)
- goto out;
+ return err;
if (scontext_len > len) {
err = -ERANGE;
@@ -4200,9 +4124,7 @@ static int selinux_socket_getpeersec_stream(struct socket *sock, char __user *op
out_len:
if (put_user(scontext_len, optlen))
err = -EFAULT;
-
kfree(scontext);
-out:
return err;
}
@@ -4234,12 +4156,27 @@ out:
static int selinux_sk_alloc_security(struct sock *sk, int family, gfp_t priority)
{
- return sk_alloc_security(sk, family, priority);
+ struct sk_security_struct *sksec;
+
+ sksec = kzalloc(sizeof(*sksec), priority);
+ if (!sksec)
+ return -ENOMEM;
+
+ sksec->peer_sid = SECINITSID_UNLABELED;
+ sksec->sid = SECINITSID_UNLABELED;
+ selinux_netlbl_sk_security_reset(sksec);
+ sk->sk_security = sksec;
+
+ return 0;
}
static void selinux_sk_free_security(struct sock *sk)
{
- sk_free_security(sk);
+ struct sk_security_struct *sksec = sk->sk_security;
+
+ sk->sk_security = NULL;
+ selinux_netlbl_sk_security_free(sksec);
+ kfree(sksec);
}
static void selinux_sk_clone_security(const struct sock *sk, struct sock *newsk)
@@ -4399,8 +4336,7 @@ static int selinux_nlmsg_perm(struct sock *sk, struct sk_buff *skb)
int err = 0;
u32 perm;
struct nlmsghdr *nlh;
- struct socket *sock = sk->sk_socket;
- struct inode_security_struct *isec = SOCK_INODE(sock)->i_security;
+ struct sk_security_struct *sksec = sk->sk_security;
if (skb->len < NLMSG_SPACE(0)) {
err = -EINVAL;
@@ -4408,13 +4344,13 @@ static int selinux_nlmsg_perm(struct sock *sk, struct sk_buff *skb)
}
nlh = nlmsg_hdr(skb);
- err = selinux_nlmsg_lookup(isec->sclass, nlh->nlmsg_type, &perm);
+ err = selinux_nlmsg_lookup(sksec->sclass, nlh->nlmsg_type, &perm);
if (err) {
if (err == -EINVAL) {
audit_log(current->audit_context, GFP_KERNEL, AUDIT_SELINUX_ERR,
"SELinux: unrecognized netlink message"
" type=%hu for sclass=%hu\n",
- nlh->nlmsg_type, isec->sclass);
+ nlh->nlmsg_type, sksec->sclass);
if (!selinux_enforcing || security_get_allow_unknown())
err = 0;
}
@@ -4425,7 +4361,7 @@ static int selinux_nlmsg_perm(struct sock *sk, struct sk_buff *skb)
goto out;
}
- err = socket_has_perm(current, sock, perm);
+ err = sock_has_perm(current, sk, perm);
out:
return err;
}
diff --git a/security/selinux/include/classmap.h b/security/selinux/include/classmap.h
index 8b32e959bb2..b4c9eb4bd6f 100644
--- a/security/selinux/include/classmap.h
+++ b/security/selinux/include/classmap.h
@@ -2,7 +2,8 @@
"getattr", "setattr", "lock", "relabelfrom", "relabelto", "append"
#define COMMON_FILE_PERMS COMMON_FILE_SOCK_PERMS, "unlink", "link", \
- "rename", "execute", "swapon", "quotaon", "mounton"
+ "rename", "execute", "swapon", "quotaon", "mounton", "audit_access", \
+ "open", "execmod"
#define COMMON_SOCK_PERMS COMMON_FILE_SOCK_PERMS, "bind", "connect", \
"listen", "accept", "getopt", "setopt", "shutdown", "recvfrom", \
@@ -43,22 +44,21 @@ struct security_class_mapping secclass_map[] = {
"quotaget", NULL } },
{ "file",
{ COMMON_FILE_PERMS,
- "execute_no_trans", "entrypoint", "execmod", "open", NULL } },
+ "execute_no_trans", "entrypoint", NULL } },
{ "dir",
{ COMMON_FILE_PERMS, "add_name", "remove_name",
- "reparent", "search", "rmdir", "open", NULL } },
+ "reparent", "search", "rmdir", NULL } },
{ "fd", { "use", NULL } },
{ "lnk_file",
{ COMMON_FILE_PERMS, NULL } },
{ "chr_file",
- { COMMON_FILE_PERMS,
- "execute_no_trans", "entrypoint", "execmod", "open", NULL } },
+ { COMMON_FILE_PERMS, NULL } },
{ "blk_file",
- { COMMON_FILE_PERMS, "open", NULL } },
+ { COMMON_FILE_PERMS, NULL } },
{ "sock_file",
- { COMMON_FILE_PERMS, "open", NULL } },
+ { COMMON_FILE_PERMS, NULL } },
{ "fifo_file",
- { COMMON_FILE_PERMS, "open", NULL } },
+ { COMMON_FILE_PERMS, NULL } },
{ "socket",
{ COMMON_SOCK_PERMS, NULL } },
{ "tcp_socket",
diff --git a/security/selinux/netnode.c b/security/selinux/netnode.c
index dc92792271f..65ebfe954f8 100644
--- a/security/selinux/netnode.c
+++ b/security/selinux/netnode.c
@@ -183,8 +183,6 @@ static void sel_netnode_insert(struct sel_netnode *node)
BUG();
}
- INIT_RCU_HEAD(&node->rcu);
-
/* we need to impose a limit on the growth of the hash table so check
* this bucket to make sure it is within the specified bounds */
list_add_rcu(&node->list, &sel_netnode_hash[idx].list);
diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c
index 0293843f7ed..79a1bb63566 100644
--- a/security/selinux/selinuxfs.c
+++ b/security/selinux/selinuxfs.c
@@ -184,6 +184,7 @@ out:
static const struct file_operations sel_enforce_ops = {
.read = sel_read_enforce,
.write = sel_write_enforce,
+ .llseek = generic_file_llseek,
};
static ssize_t sel_read_handle_unknown(struct file *filp, char __user *buf,
@@ -201,6 +202,7 @@ static ssize_t sel_read_handle_unknown(struct file *filp, char __user *buf,
static const struct file_operations sel_handle_unknown_ops = {
.read = sel_read_handle_unknown,
+ .llseek = generic_file_llseek,
};
#ifdef CONFIG_SECURITY_SELINUX_DISABLE
@@ -251,6 +253,7 @@ out:
static const struct file_operations sel_disable_ops = {
.write = sel_write_disable,
+ .llseek = generic_file_llseek,
};
static ssize_t sel_read_policyvers(struct file *filp, char __user *buf,
@@ -265,6 +268,7 @@ static ssize_t sel_read_policyvers(struct file *filp, char __user *buf,
static const struct file_operations sel_policyvers_ops = {
.read = sel_read_policyvers,
+ .llseek = generic_file_llseek,
};
/* declaration for sel_write_load */
@@ -289,6 +293,7 @@ static ssize_t sel_read_mls(struct file *filp, char __user *buf,
static const struct file_operations sel_mls_ops = {
.read = sel_read_mls,
+ .llseek = generic_file_llseek,
};
static ssize_t sel_write_load(struct file *file, const char __user *buf,
@@ -356,6 +361,7 @@ out:
static const struct file_operations sel_load_ops = {
.write = sel_write_load,
+ .llseek = generic_file_llseek,
};
static ssize_t sel_write_context(struct file *file, char *buf, size_t size)
@@ -437,6 +443,7 @@ out:
static const struct file_operations sel_checkreqprot_ops = {
.read = sel_read_checkreqprot,
.write = sel_write_checkreqprot,
+ .llseek = generic_file_llseek,
};
/*
@@ -482,6 +489,7 @@ static const struct file_operations transaction_ops = {
.write = selinux_transaction_write,
.read = simple_transaction_read,
.release = simple_transaction_release,
+ .llseek = generic_file_llseek,
};
/*
@@ -883,6 +891,7 @@ out:
static const struct file_operations sel_bool_ops = {
.read = sel_read_bool,
.write = sel_write_bool,
+ .llseek = generic_file_llseek,
};
static ssize_t sel_commit_bools_write(struct file *filep,
@@ -935,6 +944,7 @@ out:
static const struct file_operations sel_commit_bools_ops = {
.write = sel_commit_bools_write,
+ .llseek = generic_file_llseek,
};
static void sel_remove_entries(struct dentry *de)
@@ -1127,10 +1137,12 @@ out:
static const struct file_operations sel_avc_cache_threshold_ops = {
.read = sel_read_avc_cache_threshold,
.write = sel_write_avc_cache_threshold,
+ .llseek = generic_file_llseek,
};
static const struct file_operations sel_avc_hash_stats_ops = {
.read = sel_read_avc_hash_stats,
+ .llseek = generic_file_llseek,
};
#ifdef CONFIG_SECURITY_SELINUX_AVC_STATS
@@ -1255,6 +1267,7 @@ static ssize_t sel_read_initcon(struct file *file, char __user *buf,
static const struct file_operations sel_initcon_ops = {
.read = sel_read_initcon,
+ .llseek = generic_file_llseek,
};
static int sel_make_initcon_files(struct dentry *dir)
@@ -1330,6 +1343,7 @@ out:
static const struct file_operations sel_class_ops = {
.read = sel_read_class,
+ .llseek = generic_file_llseek,
};
static ssize_t sel_read_perm(struct file *file, char __user *buf,
@@ -1354,6 +1368,7 @@ out:
static const struct file_operations sel_perm_ops = {
.read = sel_read_perm,
+ .llseek = generic_file_llseek,
};
static ssize_t sel_read_policycap(struct file *file, char __user *buf,
@@ -1372,6 +1387,7 @@ static ssize_t sel_read_policycap(struct file *file, char __user *buf,
static const struct file_operations sel_policycap_ops = {
.read = sel_read_policycap,
+ .llseek = generic_file_llseek,
};
static int sel_make_perm_files(char *objclass, int classvalue,
diff --git a/security/selinux/ss/avtab.c b/security/selinux/ss/avtab.c
index 1215b8e47db..929480c6c43 100644
--- a/security/selinux/ss/avtab.c
+++ b/security/selinux/ss/avtab.c
@@ -342,20 +342,20 @@ int avtab_read_item(struct avtab *a, void *fp, struct policydb *pol,
if (vers < POLICYDB_VERSION_AVTAB) {
rc = next_entry(buf32, fp, sizeof(u32));
- if (rc < 0) {
+ if (rc) {
printk(KERN_ERR "SELinux: avtab: truncated entry\n");
- return -1;
+ return rc;
}
items2 = le32_to_cpu(buf32[0]);
if (items2 > ARRAY_SIZE(buf32)) {
printk(KERN_ERR "SELinux: avtab: entry overflow\n");
- return -1;
+ return -EINVAL;
}
rc = next_entry(buf32, fp, sizeof(u32)*items2);
- if (rc < 0) {
+ if (rc) {
printk(KERN_ERR "SELinux: avtab: truncated entry\n");
- return -1;
+ return rc;
}
items = 0;
@@ -363,19 +363,19 @@ int avtab_read_item(struct avtab *a, void *fp, struct policydb *pol,
key.source_type = (u16)val;
if (key.source_type != val) {
printk(KERN_ERR "SELinux: avtab: truncated source type\n");
- return -1;
+ return -EINVAL;
}
val = le32_to_cpu(buf32[items++]);
key.target_type = (u16)val;
if (key.target_type != val) {
printk(KERN_ERR "SELinux: avtab: truncated target type\n");
- return -1;
+ return -EINVAL;
}
val = le32_to_cpu(buf32[items++]);
key.target_class = (u16)val;
if (key.target_class != val) {
printk(KERN_ERR "SELinux: avtab: truncated target class\n");
- return -1;
+ return -EINVAL;
}
val = le32_to_cpu(buf32[items++]);
@@ -383,12 +383,12 @@ int avtab_read_item(struct avtab *a, void *fp, struct policydb *pol,
if (!(val & (AVTAB_AV | AVTAB_TYPE))) {
printk(KERN_ERR "SELinux: avtab: null entry\n");
- return -1;
+ return -EINVAL;
}
if ((val & AVTAB_AV) &&
(val & AVTAB_TYPE)) {
printk(KERN_ERR "SELinux: avtab: entry has both access vectors and types\n");
- return -1;
+ return -EINVAL;
}
for (i = 0; i < ARRAY_SIZE(spec_order); i++) {
@@ -403,15 +403,15 @@ int avtab_read_item(struct avtab *a, void *fp, struct policydb *pol,
if (items != items2) {
printk(KERN_ERR "SELinux: avtab: entry only had %d items, expected %d\n", items2, items);
- return -1;
+ return -EINVAL;
}
return 0;
}
rc = next_entry(buf16, fp, sizeof(u16)*4);
- if (rc < 0) {
+ if (rc) {
printk(KERN_ERR "SELinux: avtab: truncated entry\n");
- return -1;
+ return rc;
}
items = 0;
@@ -424,7 +424,7 @@ int avtab_read_item(struct avtab *a, void *fp, struct policydb *pol,
!policydb_type_isvalid(pol, key.target_type) ||
!policydb_class_isvalid(pol, key.target_class)) {
printk(KERN_ERR "SELinux: avtab: invalid type or class\n");
- return -1;
+ return -EINVAL;
}
set = 0;
@@ -434,19 +434,19 @@ int avtab_read_item(struct avtab *a, void *fp, struct policydb *pol,
}
if (!set || set > 1) {
printk(KERN_ERR "SELinux: avtab: more than one specifier\n");
- return -1;
+ return -EINVAL;
}
rc = next_entry(buf32, fp, sizeof(u32));
- if (rc < 0) {
+ if (rc) {
printk(KERN_ERR "SELinux: avtab: truncated entry\n");
- return -1;
+ return rc;
}
datum.data = le32_to_cpu(*buf32);
if ((key.specified & AVTAB_TYPE) &&
!policydb_type_isvalid(pol, datum.data)) {
printk(KERN_ERR "SELinux: avtab: invalid type\n");
- return -1;
+ return -EINVAL;
}
return insertf(a, &key, &datum, p);
}
@@ -487,8 +487,7 @@ int avtab_read(struct avtab *a, void *fp, struct policydb *pol)
printk(KERN_ERR "SELinux: avtab: out of memory\n");
else if (rc == -EEXIST)
printk(KERN_ERR "SELinux: avtab: duplicate entry\n");
- else
- rc = -EINVAL;
+
goto bad;
}
}
diff --git a/security/selinux/ss/conditional.c b/security/selinux/ss/conditional.c
index 4a4e35cac22..c91e150c308 100644
--- a/security/selinux/ss/conditional.c
+++ b/security/selinux/ss/conditional.c
@@ -117,10 +117,14 @@ int evaluate_cond_node(struct policydb *p, struct cond_node *node)
int cond_policydb_init(struct policydb *p)
{
+ int rc;
+
p->bool_val_to_struct = NULL;
p->cond_list = NULL;
- if (avtab_init(&p->te_cond_avtab))
- return -1;
+
+ rc = avtab_init(&p->te_cond_avtab);
+ if (rc)
+ return rc;
return 0;
}
@@ -219,34 +223,37 @@ int cond_read_bool(struct policydb *p, struct hashtab *h, void *fp)
booldatum = kzalloc(sizeof(struct cond_bool_datum), GFP_KERNEL);
if (!booldatum)
- return -1;
+ return -ENOMEM;
rc = next_entry(buf, fp, sizeof buf);
- if (rc < 0)
+ if (rc)
goto err;
booldatum->value = le32_to_cpu(buf[0]);
booldatum->state = le32_to_cpu(buf[1]);
+ rc = -EINVAL;
if (!bool_isvalid(booldatum))
goto err;
len = le32_to_cpu(buf[2]);
+ rc = -ENOMEM;
key = kmalloc(len + 1, GFP_KERNEL);
if (!key)
goto err;
rc = next_entry(key, fp, len);
- if (rc < 0)
+ if (rc)
goto err;
key[len] = '\0';
- if (hashtab_insert(h, key, booldatum))
+ rc = hashtab_insert(h, key, booldatum);
+ if (rc)
goto err;
return 0;
err:
cond_destroy_bool(key, booldatum, NULL);
- return -1;
+ return rc;
}
struct cond_insertf_data {
@@ -263,7 +270,7 @@ static int cond_insertf(struct avtab *a, struct avtab_key *k, struct avtab_datum
struct cond_av_list *other = data->other, *list, *cur;
struct avtab_node *node_ptr;
u8 found;
-
+ int rc = -EINVAL;
/*
* For type rules we have to make certain there aren't any
@@ -313,12 +320,15 @@ static int cond_insertf(struct avtab *a, struct avtab_key *k, struct avtab_datum
node_ptr = avtab_insert_nonunique(&p->te_cond_avtab, k, d);
if (!node_ptr) {
printk(KERN_ERR "SELinux: could not insert rule.\n");
+ rc = -ENOMEM;
goto err;
}
list = kzalloc(sizeof(struct cond_av_list), GFP_KERNEL);
- if (!list)
+ if (!list) {
+ rc = -ENOMEM;
goto err;
+ }
list->node = node_ptr;
if (!data->head)
@@ -331,7 +341,7 @@ static int cond_insertf(struct avtab *a, struct avtab_key *k, struct avtab_datum
err:
cond_av_list_destroy(data->head);
data->head = NULL;
- return -1;
+ return rc;
}
static int cond_read_av_list(struct policydb *p, void *fp, struct cond_av_list **ret_list, struct cond_av_list *other)
@@ -345,8 +355,8 @@ static int cond_read_av_list(struct policydb *p, void *fp, struct cond_av_list *
len = 0;
rc = next_entry(buf, fp, sizeof(u32));
- if (rc < 0)
- return -1;
+ if (rc)
+ return rc;
len = le32_to_cpu(buf[0]);
if (len == 0)
@@ -361,7 +371,6 @@ static int cond_read_av_list(struct policydb *p, void *fp, struct cond_av_list *
&data);
if (rc)
return rc;
-
}
*ret_list = data.head;
@@ -390,24 +399,25 @@ static int cond_read_node(struct policydb *p, struct cond_node *node, void *fp)
struct cond_expr *expr = NULL, *last = NULL;
rc = next_entry(buf, fp, sizeof(u32));
- if (rc < 0)
- return -1;
+ if (rc)
+ return rc;
node->cur_state = le32_to_cpu(buf[0]);
len = 0;
rc = next_entry(buf, fp, sizeof(u32));
- if (rc < 0)
- return -1;
+ if (rc)
+ return rc;
/* expr */
len = le32_to_cpu(buf[0]);
for (i = 0; i < len; i++) {
rc = next_entry(buf, fp, sizeof(u32) * 2);
- if (rc < 0)
+ if (rc)
goto err;
+ rc = -ENOMEM;
expr = kzalloc(sizeof(struct cond_expr), GFP_KERNEL);
if (!expr)
goto err;
@@ -416,6 +426,7 @@ static int cond_read_node(struct policydb *p, struct cond_node *node, void *fp)
expr->bool = le32_to_cpu(buf[1]);
if (!expr_isvalid(p, expr)) {
+ rc = -EINVAL;
kfree(expr);
goto err;
}
@@ -427,14 +438,16 @@ static int cond_read_node(struct policydb *p, struct cond_node *node, void *fp)
last = expr;
}
- if (cond_read_av_list(p, fp, &node->true_list, NULL) != 0)
+ rc = cond_read_av_list(p, fp, &node->true_list, NULL);
+ if (rc)
goto err;
- if (cond_read_av_list(p, fp, &node->false_list, node->true_list) != 0)
+ rc = cond_read_av_list(p, fp, &node->false_list, node->true_list);
+ if (rc)
goto err;
return 0;
err:
cond_node_destroy(node);
- return -1;
+ return rc;
}
int cond_read_list(struct policydb *p, void *fp)
@@ -445,8 +458,8 @@ int cond_read_list(struct policydb *p, void *fp)
int rc;
rc = next_entry(buf, fp, sizeof buf);
- if (rc < 0)
- return -1;
+ if (rc)
+ return rc;
len = le32_to_cpu(buf[0]);
@@ -455,11 +468,13 @@ int cond_read_list(struct policydb *p, void *fp)
goto err;
for (i = 0; i < len; i++) {
+ rc = -ENOMEM;
node = kzalloc(sizeof(struct cond_node), GFP_KERNEL);
if (!node)
goto err;
- if (cond_read_node(p, node, fp) != 0)
+ rc = cond_read_node(p, node, fp);
+ if (rc)
goto err;
if (i == 0)
@@ -472,7 +487,7 @@ int cond_read_list(struct policydb *p, void *fp)
err:
cond_list_destroy(p->cond_list);
p->cond_list = NULL;
- return -1;
+ return rc;
}
/* Determine whether additional permissions are granted by the conditional
diff --git a/security/selinux/ss/policydb.c b/security/selinux/ss/policydb.c
index c57802a164d..3a29704be8c 100644
--- a/security/selinux/ss/policydb.c
+++ b/security/selinux/ss/policydb.c
@@ -31,6 +31,7 @@
#include <linux/string.h>
#include <linux/errno.h>
#include <linux/audit.h>
+#include <linux/flex_array.h>
#include "security.h"
#include "policydb.h"
@@ -655,6 +656,9 @@ static int range_tr_destroy(void *key, void *datum, void *p)
static void ocontext_destroy(struct ocontext *c, int i)
{
+ if (!c)
+ return;
+
context_destroy(&c->context[0]);
context_destroy(&c->context[1]);
if (i == OCON_ISID || i == OCON_FS ||
@@ -736,11 +740,17 @@ void policydb_destroy(struct policydb *p)
hashtab_map(p->range_tr, range_tr_destroy, NULL);
hashtab_destroy(p->range_tr);
- if (p->type_attr_map) {
- for (i = 0; i < p->p_types.nprim; i++)
- ebitmap_destroy(&p->type_attr_map[i]);
+ if (p->type_attr_map_array) {
+ for (i = 0; i < p->p_types.nprim; i++) {
+ struct ebitmap *e;
+
+ e = flex_array_get(p->type_attr_map_array, i);
+ if (!e)
+ continue;
+ ebitmap_destroy(e);
+ }
+ flex_array_free(p->type_attr_map_array);
}
- kfree(p->type_attr_map);
ebitmap_destroy(&p->policycaps);
ebitmap_destroy(&p->permissive_map);
@@ -1701,6 +1711,333 @@ u32 string_to_av_perm(struct policydb *p, u16 tclass, const char *name)
return 1U << (perdatum->value-1);
}
+static int range_read(struct policydb *p, void *fp)
+{
+ struct range_trans *rt = NULL;
+ struct mls_range *r = NULL;
+ int i, rc;
+ __le32 buf[2];
+ u32 nel;
+
+ if (p->policyvers < POLICYDB_VERSION_MLS)
+ return 0;
+
+ rc = next_entry(buf, fp, sizeof(u32));
+ if (rc)
+ goto out;
+
+ nel = le32_to_cpu(buf[0]);
+ for (i = 0; i < nel; i++) {
+ rc = -ENOMEM;
+ rt = kzalloc(sizeof(*rt), GFP_KERNEL);
+ if (!rt)
+ goto out;
+
+ rc = next_entry(buf, fp, (sizeof(u32) * 2));
+ if (rc)
+ goto out;
+
+ rt->source_type = le32_to_cpu(buf[0]);
+ rt->target_type = le32_to_cpu(buf[1]);
+ if (p->policyvers >= POLICYDB_VERSION_RANGETRANS) {
+ rc = next_entry(buf, fp, sizeof(u32));
+ if (rc)
+ goto out;
+ rt->target_class = le32_to_cpu(buf[0]);
+ } else
+ rt->target_class = p->process_class;
+
+ rc = -EINVAL;
+ if (!policydb_type_isvalid(p, rt->source_type) ||
+ !policydb_type_isvalid(p, rt->target_type) ||
+ !policydb_class_isvalid(p, rt->target_class))
+ goto out;
+
+ rc = -ENOMEM;
+ r = kzalloc(sizeof(*r), GFP_KERNEL);
+ if (!r)
+ goto out;
+
+ rc = mls_read_range_helper(r, fp);
+ if (rc)
+ goto out;
+
+ rc = -EINVAL;
+ if (!mls_range_isvalid(p, r)) {
+ printk(KERN_WARNING "SELinux: rangetrans: invalid range\n");
+ goto out;
+ }
+
+ rc = hashtab_insert(p->range_tr, rt, r);
+ if (rc)
+ goto out;
+
+ rt = NULL;
+ r = NULL;
+ }
+ rangetr_hash_eval(p->range_tr);
+ rc = 0;
+out:
+ kfree(rt);
+ kfree(r);
+ return rc;
+}
+
+static int genfs_read(struct policydb *p, void *fp)
+{
+ int i, j, rc;
+ u32 nel, nel2, len, len2;
+ __le32 buf[1];
+ struct ocontext *l, *c;
+ struct ocontext *newc = NULL;
+ struct genfs *genfs_p, *genfs;
+ struct genfs *newgenfs = NULL;
+
+ rc = next_entry(buf, fp, sizeof(u32));
+ if (rc)
+ goto out;
+ nel = le32_to_cpu(buf[0]);
+
+ for (i = 0; i < nel; i++) {
+ rc = next_entry(buf, fp, sizeof(u32));
+ if (rc)
+ goto out;
+ len = le32_to_cpu(buf[0]);
+
+ rc = -ENOMEM;
+ newgenfs = kzalloc(sizeof(*newgenfs), GFP_KERNEL);
+ if (!newgenfs)
+ goto out;
+
+ rc = -ENOMEM;
+ newgenfs->fstype = kmalloc(len + 1, GFP_KERNEL);
+ if (!newgenfs->fstype)
+ goto out;
+
+ rc = next_entry(newgenfs->fstype, fp, len);
+ if (rc)
+ goto out;
+
+ newgenfs->fstype[len] = 0;
+
+ for (genfs_p = NULL, genfs = p->genfs; genfs;
+ genfs_p = genfs, genfs = genfs->next) {
+ rc = -EINVAL;
+ if (strcmp(newgenfs->fstype, genfs->fstype) == 0) {
+ printk(KERN_ERR "SELinux: dup genfs fstype %s\n",
+ newgenfs->fstype);
+ goto out;
+ }
+ if (strcmp(newgenfs->fstype, genfs->fstype) < 0)
+ break;
+ }
+ newgenfs->next = genfs;
+ if (genfs_p)
+ genfs_p->next = newgenfs;
+ else
+ p->genfs = newgenfs;
+ genfs = newgenfs;
+ newgenfs = NULL;
+
+ rc = next_entry(buf, fp, sizeof(u32));
+ if (rc)
+ goto out;
+
+ nel2 = le32_to_cpu(buf[0]);
+ for (j = 0; j < nel2; j++) {
+ rc = next_entry(buf, fp, sizeof(u32));
+ if (rc)
+ goto out;
+ len = le32_to_cpu(buf[0]);
+
+ rc = -ENOMEM;
+ newc = kzalloc(sizeof(*newc), GFP_KERNEL);
+ if (!newc)
+ goto out;
+
+ rc = -ENOMEM;
+ newc->u.name = kmalloc(len + 1, GFP_KERNEL);
+ if (!newc->u.name)
+ goto out;
+
+ rc = next_entry(newc->u.name, fp, len);
+ if (rc)
+ goto out;
+ newc->u.name[len] = 0;
+
+ rc = next_entry(buf, fp, sizeof(u32));
+ if (rc)
+ goto out;
+
+ newc->v.sclass = le32_to_cpu(buf[0]);
+ rc = context_read_and_validate(&newc->context[0], p, fp);
+ if (rc)
+ goto out;
+
+ for (l = NULL, c = genfs->head; c;
+ l = c, c = c->next) {
+ rc = -EINVAL;
+ if (!strcmp(newc->u.name, c->u.name) &&
+ (!c->v.sclass || !newc->v.sclass ||
+ newc->v.sclass == c->v.sclass)) {
+ printk(KERN_ERR "SELinux: dup genfs entry (%s,%s)\n",
+ genfs->fstype, c->u.name);
+ goto out;
+ }
+ len = strlen(newc->u.name);
+ len2 = strlen(c->u.name);
+ if (len > len2)
+ break;
+ }
+
+ newc->next = c;
+ if (l)
+ l->next = newc;
+ else
+ genfs->head = newc;
+ newc = NULL;
+ }
+ }
+ rc = 0;
+out:
+ if (newgenfs)
+ kfree(newgenfs->fstype);
+ kfree(newgenfs);
+ ocontext_destroy(newc, OCON_FSUSE);
+
+ return rc;
+}
+
+static int ocontext_read(struct policydb *p, struct policydb_compat_info *info,
+ void *fp)
+{
+ int i, j, rc;
+ u32 nel, len;
+ __le32 buf[3];
+ struct ocontext *l, *c;
+ u32 nodebuf[8];
+
+ for (i = 0; i < info->ocon_num; i++) {
+ rc = next_entry(buf, fp, sizeof(u32));
+ if (rc)
+ goto out;
+ nel = le32_to_cpu(buf[0]);
+
+ l = NULL;
+ for (j = 0; j < nel; j++) {
+ rc = -ENOMEM;
+ c = kzalloc(sizeof(*c), GFP_KERNEL);
+ if (!c)
+ goto out;
+ if (l)
+ l->next = c;
+ else
+ p->ocontexts[i] = c;
+ l = c;
+
+ switch (i) {
+ case OCON_ISID:
+ rc = next_entry(buf, fp, sizeof(u32));
+ if (rc)
+ goto out;
+
+ c->sid[0] = le32_to_cpu(buf[0]);
+ rc = context_read_and_validate(&c->context[0], p, fp);
+ if (rc)
+ goto out;
+ break;
+ case OCON_FS:
+ case OCON_NETIF:
+ rc = next_entry(buf, fp, sizeof(u32));
+ if (rc)
+ goto out;
+ len = le32_to_cpu(buf[0]);
+
+ rc = -ENOMEM;
+ c->u.name = kmalloc(len + 1, GFP_KERNEL);
+ if (!c->u.name)
+ goto out;
+
+ rc = next_entry(c->u.name, fp, len);
+ if (rc)
+ goto out;
+
+ c->u.name[len] = 0;
+ rc = context_read_and_validate(&c->context[0], p, fp);
+ if (rc)
+ goto out;
+ rc = context_read_and_validate(&c->context[1], p, fp);
+ if (rc)
+ goto out;
+ break;
+ case OCON_PORT:
+ rc = next_entry(buf, fp, sizeof(u32)*3);
+ if (rc)
+ goto out;
+ c->u.port.protocol = le32_to_cpu(buf[0]);
+ c->u.port.low_port = le32_to_cpu(buf[1]);
+ c->u.port.high_port = le32_to_cpu(buf[2]);
+ rc = context_read_and_validate(&c->context[0], p, fp);
+ if (rc)
+ goto out;
+ break;
+ case OCON_NODE:
+ rc = next_entry(nodebuf, fp, sizeof(u32) * 2);
+ if (rc)
+ goto out;
+ c->u.node.addr = nodebuf[0]; /* network order */
+ c->u.node.mask = nodebuf[1]; /* network order */
+ rc = context_read_and_validate(&c->context[0], p, fp);
+ if (rc)
+ goto out;
+ break;
+ case OCON_FSUSE:
+ rc = next_entry(buf, fp, sizeof(u32)*2);
+ if (rc)
+ goto out;
+
+ rc = -EINVAL;
+ c->v.behavior = le32_to_cpu(buf[0]);
+ if (c->v.behavior > SECURITY_FS_USE_NONE)
+ goto out;
+
+ rc = -ENOMEM;
+ len = le32_to_cpu(buf[1]);
+ c->u.name = kmalloc(len + 1, GFP_KERNEL);
+ if (!c->u.name)
+ goto out;
+
+ rc = next_entry(c->u.name, fp, len);
+ if (rc)
+ goto out;
+ c->u.name[len] = 0;
+ rc = context_read_and_validate(&c->context[0], p, fp);
+ if (rc)
+ goto out;
+ break;
+ case OCON_NODE6: {
+ int k;
+
+ rc = next_entry(nodebuf, fp, sizeof(u32) * 8);
+ if (rc)
+ goto out;
+ for (k = 0; k < 4; k++)
+ c->u.node6.addr[k] = nodebuf[k];
+ for (k = 0; k < 4; k++)
+ c->u.node6.mask[k] = nodebuf[k+4];
+ rc = context_read_and_validate(&c->context[0], p, fp);
+ if (rc)
+ goto out;
+ break;
+ }
+ }
+ }
+ }
+ rc = 0;
+out:
+ return rc;
+}
+
/*
* Read the configuration data from a policy database binary
* representation file into a policy database structure.
@@ -1709,16 +2046,12 @@ int policydb_read(struct policydb *p, void *fp)
{
struct role_allow *ra, *lra;
struct role_trans *tr, *ltr;
- struct ocontext *l, *c, *newc;
- struct genfs *genfs_p, *genfs, *newgenfs;
int i, j, rc;
__le32 buf[4];
- u32 nodebuf[8];
- u32 len, len2, nprim, nel, nel2;
+ u32 len, nprim, nel;
+
char *policydb_str;
struct policydb_compat_info *info;
- struct range_trans *rt;
- struct mls_range *r;
rc = policydb_init(p);
if (rc)
@@ -1919,294 +2252,45 @@ int policydb_read(struct policydb *p, void *fp)
if (!p->process_trans_perms)
goto bad;
- for (i = 0; i < info->ocon_num; i++) {
- rc = next_entry(buf, fp, sizeof(u32));
- if (rc < 0)
- goto bad;
- nel = le32_to_cpu(buf[0]);
- l = NULL;
- for (j = 0; j < nel; j++) {
- c = kzalloc(sizeof(*c), GFP_KERNEL);
- if (!c) {
- rc = -ENOMEM;
- goto bad;
- }
- if (l)
- l->next = c;
- else
- p->ocontexts[i] = c;
- l = c;
- rc = -EINVAL;
- switch (i) {
- case OCON_ISID:
- rc = next_entry(buf, fp, sizeof(u32));
- if (rc < 0)
- goto bad;
- c->sid[0] = le32_to_cpu(buf[0]);
- rc = context_read_and_validate(&c->context[0], p, fp);
- if (rc)
- goto bad;
- break;
- case OCON_FS:
- case OCON_NETIF:
- rc = next_entry(buf, fp, sizeof(u32));
- if (rc < 0)
- goto bad;
- len = le32_to_cpu(buf[0]);
- c->u.name = kmalloc(len + 1, GFP_KERNEL);
- if (!c->u.name) {
- rc = -ENOMEM;
- goto bad;
- }
- rc = next_entry(c->u.name, fp, len);
- if (rc < 0)
- goto bad;
- c->u.name[len] = 0;
- rc = context_read_and_validate(&c->context[0], p, fp);
- if (rc)
- goto bad;
- rc = context_read_and_validate(&c->context[1], p, fp);
- if (rc)
- goto bad;
- break;
- case OCON_PORT:
- rc = next_entry(buf, fp, sizeof(u32)*3);
- if (rc < 0)
- goto bad;
- c->u.port.protocol = le32_to_cpu(buf[0]);
- c->u.port.low_port = le32_to_cpu(buf[1]);
- c->u.port.high_port = le32_to_cpu(buf[2]);
- rc = context_read_and_validate(&c->context[0], p, fp);
- if (rc)
- goto bad;
- break;
- case OCON_NODE:
- rc = next_entry(nodebuf, fp, sizeof(u32) * 2);
- if (rc < 0)
- goto bad;
- c->u.node.addr = nodebuf[0]; /* network order */
- c->u.node.mask = nodebuf[1]; /* network order */
- rc = context_read_and_validate(&c->context[0], p, fp);
- if (rc)
- goto bad;
- break;
- case OCON_FSUSE:
- rc = next_entry(buf, fp, sizeof(u32)*2);
- if (rc < 0)
- goto bad;
- c->v.behavior = le32_to_cpu(buf[0]);
- if (c->v.behavior > SECURITY_FS_USE_NONE)
- goto bad;
- len = le32_to_cpu(buf[1]);
- c->u.name = kmalloc(len + 1, GFP_KERNEL);
- if (!c->u.name) {
- rc = -ENOMEM;
- goto bad;
- }
- rc = next_entry(c->u.name, fp, len);
- if (rc < 0)
- goto bad;
- c->u.name[len] = 0;
- rc = context_read_and_validate(&c->context[0], p, fp);
- if (rc)
- goto bad;
- break;
- case OCON_NODE6: {
- int k;
-
- rc = next_entry(nodebuf, fp, sizeof(u32) * 8);
- if (rc < 0)
- goto bad;
- for (k = 0; k < 4; k++)
- c->u.node6.addr[k] = nodebuf[k];
- for (k = 0; k < 4; k++)
- c->u.node6.mask[k] = nodebuf[k+4];
- if (context_read_and_validate(&c->context[0], p, fp))
- goto bad;
- break;
- }
- }
- }
- }
-
- rc = next_entry(buf, fp, sizeof(u32));
- if (rc < 0)
+ rc = ocontext_read(p, info, fp);
+ if (rc)
goto bad;
- nel = le32_to_cpu(buf[0]);
- genfs_p = NULL;
- rc = -EINVAL;
- for (i = 0; i < nel; i++) {
- rc = next_entry(buf, fp, sizeof(u32));
- if (rc < 0)
- goto bad;
- len = le32_to_cpu(buf[0]);
- newgenfs = kzalloc(sizeof(*newgenfs), GFP_KERNEL);
- if (!newgenfs) {
- rc = -ENOMEM;
- goto bad;
- }
- newgenfs->fstype = kmalloc(len + 1, GFP_KERNEL);
- if (!newgenfs->fstype) {
- rc = -ENOMEM;
- kfree(newgenfs);
- goto bad;
- }
- rc = next_entry(newgenfs->fstype, fp, len);
- if (rc < 0) {
- kfree(newgenfs->fstype);
- kfree(newgenfs);
- goto bad;
- }
- newgenfs->fstype[len] = 0;
- for (genfs_p = NULL, genfs = p->genfs; genfs;
- genfs_p = genfs, genfs = genfs->next) {
- if (strcmp(newgenfs->fstype, genfs->fstype) == 0) {
- printk(KERN_ERR "SELinux: dup genfs "
- "fstype %s\n", newgenfs->fstype);
- kfree(newgenfs->fstype);
- kfree(newgenfs);
- goto bad;
- }
- if (strcmp(newgenfs->fstype, genfs->fstype) < 0)
- break;
- }
- newgenfs->next = genfs;
- if (genfs_p)
- genfs_p->next = newgenfs;
- else
- p->genfs = newgenfs;
- rc = next_entry(buf, fp, sizeof(u32));
- if (rc < 0)
- goto bad;
- nel2 = le32_to_cpu(buf[0]);
- for (j = 0; j < nel2; j++) {
- rc = next_entry(buf, fp, sizeof(u32));
- if (rc < 0)
- goto bad;
- len = le32_to_cpu(buf[0]);
-
- newc = kzalloc(sizeof(*newc), GFP_KERNEL);
- if (!newc) {
- rc = -ENOMEM;
- goto bad;
- }
-
- newc->u.name = kmalloc(len + 1, GFP_KERNEL);
- if (!newc->u.name) {
- rc = -ENOMEM;
- goto bad_newc;
- }
- rc = next_entry(newc->u.name, fp, len);
- if (rc < 0)
- goto bad_newc;
- newc->u.name[len] = 0;
- rc = next_entry(buf, fp, sizeof(u32));
- if (rc < 0)
- goto bad_newc;
- newc->v.sclass = le32_to_cpu(buf[0]);
- if (context_read_and_validate(&newc->context[0], p, fp))
- goto bad_newc;
- for (l = NULL, c = newgenfs->head; c;
- l = c, c = c->next) {
- if (!strcmp(newc->u.name, c->u.name) &&
- (!c->v.sclass || !newc->v.sclass ||
- newc->v.sclass == c->v.sclass)) {
- printk(KERN_ERR "SELinux: dup genfs "
- "entry (%s,%s)\n",
- newgenfs->fstype, c->u.name);
- goto bad_newc;
- }
- len = strlen(newc->u.name);
- len2 = strlen(c->u.name);
- if (len > len2)
- break;
- }
+ rc = genfs_read(p, fp);
+ if (rc)
+ goto bad;
- newc->next = c;
- if (l)
- l->next = newc;
- else
- newgenfs->head = newc;
- }
- }
+ rc = range_read(p, fp);
+ if (rc)
+ goto bad;
- if (p->policyvers >= POLICYDB_VERSION_MLS) {
- int new_rangetr = p->policyvers >= POLICYDB_VERSION_RANGETRANS;
- rc = next_entry(buf, fp, sizeof(u32));
- if (rc < 0)
- goto bad;
- nel = le32_to_cpu(buf[0]);
- for (i = 0; i < nel; i++) {
- rt = kzalloc(sizeof(*rt), GFP_KERNEL);
- if (!rt) {
- rc = -ENOMEM;
- goto bad;
- }
- rc = next_entry(buf, fp, (sizeof(u32) * 2));
- if (rc < 0) {
- kfree(rt);
- goto bad;
- }
- rt->source_type = le32_to_cpu(buf[0]);
- rt->target_type = le32_to_cpu(buf[1]);
- if (new_rangetr) {
- rc = next_entry(buf, fp, sizeof(u32));
- if (rc < 0) {
- kfree(rt);
- goto bad;
- }
- rt->target_class = le32_to_cpu(buf[0]);
- } else
- rt->target_class = p->process_class;
- if (!policydb_type_isvalid(p, rt->source_type) ||
- !policydb_type_isvalid(p, rt->target_type) ||
- !policydb_class_isvalid(p, rt->target_class)) {
- kfree(rt);
- rc = -EINVAL;
- goto bad;
- }
- r = kzalloc(sizeof(*r), GFP_KERNEL);
- if (!r) {
- kfree(rt);
- rc = -ENOMEM;
- goto bad;
- }
- rc = mls_read_range_helper(r, fp);
- if (rc) {
- kfree(rt);
- kfree(r);
- goto bad;
- }
- if (!mls_range_isvalid(p, r)) {
- printk(KERN_WARNING "SELinux: rangetrans: invalid range\n");
- kfree(rt);
- kfree(r);
- goto bad;
- }
- rc = hashtab_insert(p->range_tr, rt, r);
- if (rc) {
- kfree(rt);
- kfree(r);
- goto bad;
- }
- }
- rangetr_hash_eval(p->range_tr);
- }
+ rc = -ENOMEM;
+ p->type_attr_map_array = flex_array_alloc(sizeof(struct ebitmap),
+ p->p_types.nprim,
+ GFP_KERNEL | __GFP_ZERO);
+ if (!p->type_attr_map_array)
+ goto bad;
- p->type_attr_map = kmalloc(p->p_types.nprim * sizeof(struct ebitmap), GFP_KERNEL);
- if (!p->type_attr_map)
+ /* preallocate so we don't have to worry about the put ever failing */
+ rc = flex_array_prealloc(p->type_attr_map_array, 0, p->p_types.nprim - 1,
+ GFP_KERNEL | __GFP_ZERO);
+ if (rc)
goto bad;
for (i = 0; i < p->p_types.nprim; i++) {
- ebitmap_init(&p->type_attr_map[i]);
+ struct ebitmap *e = flex_array_get(p->type_attr_map_array, i);
+
+ BUG_ON(!e);
+ ebitmap_init(e);
if (p->policyvers >= POLICYDB_VERSION_AVTAB) {
- if (ebitmap_read(&p->type_attr_map[i], fp))
+ rc = ebitmap_read(e, fp);
+ if (rc)
goto bad;
}
/* add the type itself as the degenerate case */
- if (ebitmap_set_bit(&p->type_attr_map[i], i, 1))
- goto bad;
+ rc = ebitmap_set_bit(e, i, 1);
+ if (rc)
+ goto bad;
}
rc = policydb_bounds_sanity_check(p);
@@ -2216,8 +2300,6 @@ int policydb_read(struct policydb *p, void *fp)
rc = 0;
out:
return rc;
-bad_newc:
- ocontext_destroy(newc, OCON_FSUSE);
bad:
if (!rc)
rc = -EINVAL;
diff --git a/security/selinux/ss/policydb.h b/security/selinux/ss/policydb.h
index 26d9adf8542..310e94442cb 100644
--- a/security/selinux/ss/policydb.h
+++ b/security/selinux/ss/policydb.h
@@ -24,6 +24,8 @@
#ifndef _SS_POLICYDB_H_
#define _SS_POLICYDB_H_
+#include <linux/flex_array.h>
+
#include "symtab.h"
#include "avtab.h"
#include "sidtab.h"
@@ -246,7 +248,7 @@ struct policydb {
struct hashtab *range_tr;
/* type -> attribute reverse mapping */
- struct ebitmap *type_attr_map;
+ struct flex_array *type_attr_map_array;
struct ebitmap policycaps;
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c
index 1de60ce90d9..9ea2feca3cd 100644
--- a/security/selinux/ss/services.c
+++ b/security/selinux/ss/services.c
@@ -50,6 +50,7 @@
#include <linux/audit.h>
#include <linux/mutex.h>
#include <linux/selinux.h>
+#include <linux/flex_array.h>
#include <net/netlabel.h>
#include "flask.h"
@@ -626,8 +627,10 @@ static void context_struct_compute_av(struct context *scontext,
*/
avkey.target_class = tclass;
avkey.specified = AVTAB_AV;
- sattr = &policydb.type_attr_map[scontext->type - 1];
- tattr = &policydb.type_attr_map[tcontext->type - 1];
+ sattr = flex_array_get(policydb.type_attr_map_array, scontext->type - 1);
+ BUG_ON(!sattr);
+ tattr = flex_array_get(policydb.type_attr_map_array, tcontext->type - 1);
+ BUG_ON(!tattr);
ebitmap_for_each_positive_bit(sattr, snode, i) {
ebitmap_for_each_positive_bit(tattr, tnode, j) {
avkey.source_type = i + 1;
diff --git a/security/selinux/ss/symtab.c b/security/selinux/ss/symtab.c
index bcf9f620426..160326ee99e 100644
--- a/security/selinux/ss/symtab.c
+++ b/security/selinux/ss/symtab.c
@@ -36,7 +36,7 @@ int symtab_init(struct symtab *s, unsigned int size)
{
s->table = hashtab_create(symhash, symcmp, size);
if (!s->table)
- return -1;
+ return -ENOMEM;
s->nprim = 0;
return 0;
}
diff --git a/security/smack/smack.h b/security/smack/smack.h
index c6e9acae72e..43ae747a5aa 100644
--- a/security/smack/smack.h
+++ b/security/smack/smack.h
@@ -123,16 +123,6 @@ struct smack_known {
#define SMK_FSHAT "smackfshat="
#define SMK_FSROOT "smackfsroot="
-/*
- * xattr names
- */
-#define XATTR_SMACK_SUFFIX "SMACK64"
-#define XATTR_SMACK_IPIN "SMACK64IPIN"
-#define XATTR_SMACK_IPOUT "SMACK64IPOUT"
-#define XATTR_NAME_SMACK XATTR_SECURITY_PREFIX XATTR_SMACK_SUFFIX
-#define XATTR_NAME_SMACKIPIN XATTR_SECURITY_PREFIX XATTR_SMACK_IPIN
-#define XATTR_NAME_SMACKIPOUT XATTR_SECURITY_PREFIX XATTR_SMACK_IPOUT
-
#define SMACK_CIPSO_OPTION "-CIPSO"
/*
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index 0f2fc480fc6..c448d57ae2b 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -598,6 +598,8 @@ static int smack_inode_rename(struct inode *old_inode,
static int smack_inode_permission(struct inode *inode, int mask)
{
struct smk_audit_info ad;
+
+ mask &= (MAY_READ|MAY_WRITE|MAY_EXEC|MAY_APPEND);
/*
* No permission to check. Existence test. Yup, it's there.
*/
@@ -2191,7 +2193,7 @@ static void smack_ipc_getsecid(struct kern_ipc_perm *ipp, u32 *secid)
/**
* smack_d_instantiate - Make sure the blob is correct on an inode
- * @opt_dentry: unused
+ * @opt_dentry: dentry where inode will be attached
* @inode: the object
*
* Set the inode's security blob if it hasn't been done already.
@@ -2310,20 +2312,10 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode)
/*
* Get the dentry for xattr.
*/
- if (opt_dentry == NULL) {
- dp = d_find_alias(inode);
- if (dp == NULL)
- break;
- } else {
- dp = dget(opt_dentry);
- if (dp == NULL)
- break;
- }
-
+ dp = dget(opt_dentry);
fetched = smk_fetch(inode, dp);
if (fetched != NULL)
final = fetched;
-
dput(dp);
break;
}
@@ -3227,7 +3219,7 @@ static __init int smack_init(void)
cred = (struct cred *) current->cred;
cred->security = &smack_known_floor.smk_known;
- /* initilize the smack_know_list */
+ /* initialize the smack_know_list */
init_smack_know_list();
/*
* Initialize locks
diff --git a/security/tomoyo/Makefile b/security/tomoyo/Makefile
index 4fb39030f6b..91640e96bd0 100644
--- a/security/tomoyo/Makefile
+++ b/security/tomoyo/Makefile
@@ -1 +1 @@
-obj-y = common.o realpath.o tomoyo.o domain.o file.o gc.o path_group.o
+obj-y = common.o domain.o file.o gc.o group.o load_policy.o memory.o mount.o realpath.o securityfs_if.o tomoyo.o util.o
diff --git a/security/tomoyo/common.c b/security/tomoyo/common.c
index b5dbdc9ff73..ef43995119a 100644
--- a/security/tomoyo/common.c
+++ b/security/tomoyo/common.c
@@ -3,974 +3,424 @@
*
* Common functions for TOMOYO.
*
- * Copyright (C) 2005-2009 NTT DATA CORPORATION
- *
- * Version: 2.2.0 2009/04/01
- *
+ * Copyright (C) 2005-2010 NTT DATA CORPORATION
*/
#include <linux/uaccess.h>
#include <linux/slab.h>
#include <linux/security.h>
-#include <linux/hardirq.h>
#include "common.h"
-/* Lock for protecting policy. */
-DEFINE_MUTEX(tomoyo_policy_lock);
+static struct tomoyo_profile tomoyo_default_profile = {
+ .learning = &tomoyo_default_profile.preference,
+ .permissive = &tomoyo_default_profile.preference,
+ .enforcing = &tomoyo_default_profile.preference,
+ .preference.enforcing_verbose = true,
+ .preference.learning_max_entry = 2048,
+ .preference.learning_verbose = false,
+ .preference.permissive_verbose = true
+};
+
+/* Profile version. Currently only 20090903 is defined. */
+static unsigned int tomoyo_profile_version;
-/* Has loading policy done? */
-bool tomoyo_policy_loaded;
+/* Profile table. Memory is allocated as needed. */
+static struct tomoyo_profile *tomoyo_profile_ptr[TOMOYO_MAX_PROFILES];
/* String table for functionality that takes 4 modes. */
-static const char *tomoyo_mode_4[4] = {
+static const char *tomoyo_mode[4] = {
"disabled", "learning", "permissive", "enforcing"
};
-/* String table for functionality that takes 2 modes. */
-static const char *tomoyo_mode_2[4] = {
- "disabled", "enabled", "enabled", "enabled"
-};
-/*
- * tomoyo_control_array is a static data which contains
- *
- * (1) functionality name used by /sys/kernel/security/tomoyo/profile .
- * (2) initial values for "struct tomoyo_profile".
- * (3) max values for "struct tomoyo_profile".
- */
-static struct {
- const char *keyword;
- unsigned int current_value;
- const unsigned int max_value;
-} tomoyo_control_array[TOMOYO_MAX_CONTROL_INDEX] = {
- [TOMOYO_MAC_FOR_FILE] = { "MAC_FOR_FILE", 0, 3 },
- [TOMOYO_MAX_ACCEPT_ENTRY] = { "MAX_ACCEPT_ENTRY", 2048, INT_MAX },
- [TOMOYO_VERBOSE] = { "TOMOYO_VERBOSE", 1, 1 },
+/* String table for /sys/kernel/security/tomoyo/profile */
+static const char *tomoyo_mac_keywords[TOMOYO_MAX_MAC_INDEX
+ + TOMOYO_MAX_MAC_CATEGORY_INDEX] = {
+ [TOMOYO_MAC_FILE_EXECUTE] = "file::execute",
+ [TOMOYO_MAC_FILE_OPEN] = "file::open",
+ [TOMOYO_MAC_FILE_CREATE] = "file::create",
+ [TOMOYO_MAC_FILE_UNLINK] = "file::unlink",
+ [TOMOYO_MAC_FILE_MKDIR] = "file::mkdir",
+ [TOMOYO_MAC_FILE_RMDIR] = "file::rmdir",
+ [TOMOYO_MAC_FILE_MKFIFO] = "file::mkfifo",
+ [TOMOYO_MAC_FILE_MKSOCK] = "file::mksock",
+ [TOMOYO_MAC_FILE_TRUNCATE] = "file::truncate",
+ [TOMOYO_MAC_FILE_SYMLINK] = "file::symlink",
+ [TOMOYO_MAC_FILE_REWRITE] = "file::rewrite",
+ [TOMOYO_MAC_FILE_MKBLOCK] = "file::mkblock",
+ [TOMOYO_MAC_FILE_MKCHAR] = "file::mkchar",
+ [TOMOYO_MAC_FILE_LINK] = "file::link",
+ [TOMOYO_MAC_FILE_RENAME] = "file::rename",
+ [TOMOYO_MAC_FILE_CHMOD] = "file::chmod",
+ [TOMOYO_MAC_FILE_CHOWN] = "file::chown",
+ [TOMOYO_MAC_FILE_CHGRP] = "file::chgrp",
+ [TOMOYO_MAC_FILE_IOCTL] = "file::ioctl",
+ [TOMOYO_MAC_FILE_CHROOT] = "file::chroot",
+ [TOMOYO_MAC_FILE_MOUNT] = "file::mount",
+ [TOMOYO_MAC_FILE_UMOUNT] = "file::umount",
+ [TOMOYO_MAC_FILE_PIVOT_ROOT] = "file::pivot_root",
+ [TOMOYO_MAX_MAC_INDEX + TOMOYO_MAC_CATEGORY_FILE] = "file",
};
-/*
- * tomoyo_profile is a structure which is used for holding the mode of access
- * controls. TOMOYO has 4 modes: disabled, learning, permissive, enforcing.
- * An administrator can define up to 256 profiles.
- * The ->profile of "struct tomoyo_domain_info" is used for remembering
- * the profile's number (0 - 255) assigned to that domain.
- */
-static struct tomoyo_profile {
- unsigned int value[TOMOYO_MAX_CONTROL_INDEX];
- const struct tomoyo_path_info *comment;
-} *tomoyo_profile_ptr[TOMOYO_MAX_PROFILES];
-
/* Permit policy management by non-root user? */
static bool tomoyo_manage_by_non_root;
/* Utility functions. */
-/* Open operation for /sys/kernel/security/tomoyo/ interface. */
-static int tomoyo_open_control(const u8 type, struct file *file);
-/* Close /sys/kernel/security/tomoyo/ interface. */
-static int tomoyo_close_control(struct file *file);
-/* Read operation for /sys/kernel/security/tomoyo/ interface. */
-static int tomoyo_read_control(struct file *file, char __user *buffer,
- const int buffer_len);
-/* Write operation for /sys/kernel/security/tomoyo/ interface. */
-static int tomoyo_write_control(struct file *file, const char __user *buffer,
- const int buffer_len);
-
/**
- * tomoyo_parse_name_union - Parse a tomoyo_name_union.
+ * tomoyo_yesno - Return "yes" or "no".
*
- * @filename: Name or name group.
- * @ptr: Pointer to "struct tomoyo_name_union".
- *
- * Returns true on success, false otherwise.
+ * @value: Bool value.
*/
-bool tomoyo_parse_name_union(const char *filename,
- struct tomoyo_name_union *ptr)
+static const char *tomoyo_yesno(const unsigned int value)
{
- if (!tomoyo_is_correct_path(filename, 0, 0, 0))
- return false;
- if (filename[0] == '@') {
- ptr->group = tomoyo_get_path_group(filename + 1);
- ptr->is_group = true;
- return ptr->group != NULL;
- }
- ptr->filename = tomoyo_get_name(filename);
- ptr->is_group = false;
- return ptr->filename != NULL;
+ return value ? "yes" : "no";
}
-/**
- * tomoyo_print_name_union - Print a tomoyo_name_union.
- *
- * @head: Pointer to "struct tomoyo_io_buffer".
- * @ptr: Pointer to "struct tomoyo_name_union".
- *
- * Returns true on success, false otherwise.
- */
-static bool tomoyo_print_name_union(struct tomoyo_io_buffer *head,
- const struct tomoyo_name_union *ptr)
+static void tomoyo_addprintf(char *buffer, int len, const char *fmt, ...)
{
- int pos = head->read_avail;
- if (pos && head->read_buf[pos - 1] == ' ')
- head->read_avail--;
- if (ptr->is_group)
- return tomoyo_io_printf(head, " @%s",
- ptr->group->group_name->name);
- return tomoyo_io_printf(head, " %s", ptr->filename->name);
+ va_list args;
+ const int pos = strlen(buffer);
+ va_start(args, fmt);
+ vsnprintf(buffer + pos, len - pos - 1, fmt, args);
+ va_end(args);
}
/**
- * tomoyo_is_byte_range - Check whether the string isa \ooo style octal value.
- *
- * @str: Pointer to the string.
+ * tomoyo_flush - Flush queued string to userspace's buffer.
*
- * Returns true if @str is a \ooo style octal value, false otherwise.
+ * @head: Pointer to "struct tomoyo_io_buffer".
*
- * TOMOYO uses \ooo style representation for 0x01 - 0x20 and 0x7F - 0xFF.
- * This function verifies that \ooo is in valid range.
+ * Returns true if all data was flushed, false otherwise.
*/
-static inline bool tomoyo_is_byte_range(const char *str)
+static bool tomoyo_flush(struct tomoyo_io_buffer *head)
{
- return *str >= '0' && *str++ <= '3' &&
- *str >= '0' && *str++ <= '7' &&
- *str >= '0' && *str <= '7';
+ while (head->r.w_pos) {
+ const char *w = head->r.w[0];
+ int len = strlen(w);
+ if (len) {
+ if (len > head->read_user_buf_avail)
+ len = head->read_user_buf_avail;
+ if (!len)
+ return false;
+ if (copy_to_user(head->read_user_buf, w, len))
+ return false;
+ head->read_user_buf_avail -= len;
+ head->read_user_buf += len;
+ w += len;
+ }
+ if (*w) {
+ head->r.w[0] = w;
+ return false;
+ }
+ /* Add '\0' for query. */
+ if (head->poll) {
+ if (!head->read_user_buf_avail ||
+ copy_to_user(head->read_user_buf, "", 1))
+ return false;
+ head->read_user_buf_avail--;
+ head->read_user_buf++;
+ }
+ head->r.w_pos--;
+ for (len = 0; len < head->r.w_pos; len++)
+ head->r.w[len] = head->r.w[len + 1];
+ }
+ head->r.avail = 0;
+ return true;
}
/**
- * tomoyo_is_alphabet_char - Check whether the character is an alphabet.
+ * tomoyo_set_string - Queue string to "struct tomoyo_io_buffer" structure.
*
- * @c: The character to check.
+ * @head: Pointer to "struct tomoyo_io_buffer".
+ * @string: String to print.
*
- * Returns true if @c is an alphabet character, false otherwise.
+ * Note that @string has to be kept valid until @head is kfree()d.
+ * This means that char[] allocated on stack memory cannot be passed to
+ * this function. Use tomoyo_io_printf() for char[] allocated on stack memory.
*/
-static inline bool tomoyo_is_alphabet_char(const char c)
+static void tomoyo_set_string(struct tomoyo_io_buffer *head, const char *string)
{
- return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z');
+ if (head->r.w_pos < TOMOYO_MAX_IO_READ_QUEUE) {
+ head->r.w[head->r.w_pos++] = string;
+ tomoyo_flush(head);
+ } else
+ WARN_ON(1);
}
/**
- * tomoyo_make_byte - Make byte value from three octal characters.
+ * tomoyo_io_printf - printf() to "struct tomoyo_io_buffer" structure.
*
- * @c1: The first character.
- * @c2: The second character.
- * @c3: The third character.
- *
- * Returns byte value.
+ * @head: Pointer to "struct tomoyo_io_buffer".
+ * @fmt: The printf()'s format string, followed by parameters.
*/
-static inline u8 tomoyo_make_byte(const u8 c1, const u8 c2, const u8 c3)
+void tomoyo_io_printf(struct tomoyo_io_buffer *head, const char *fmt, ...)
{
- return ((c1 - '0') << 6) + ((c2 - '0') << 3) + (c3 - '0');
+ va_list args;
+ int len;
+ int pos = head->r.avail;
+ int size = head->readbuf_size - pos;
+ if (size <= 0)
+ return;
+ va_start(args, fmt);
+ len = vsnprintf(head->read_buf + pos, size, fmt, args) + 1;
+ va_end(args);
+ if (pos + len >= head->readbuf_size) {
+ WARN_ON(1);
+ return;
+ }
+ head->r.avail += len;
+ tomoyo_set_string(head, head->read_buf + pos);
}
-/**
- * tomoyo_str_starts - Check whether the given string starts with the given keyword.
- *
- * @src: Pointer to pointer to the string.
- * @find: Pointer to the keyword.
- *
- * Returns true if @src starts with @find, false otherwise.
- *
- * The @src is updated to point the first character after the @find
- * if @src starts with @find.
- */
-static bool tomoyo_str_starts(char **src, const char *find)
+static void tomoyo_set_space(struct tomoyo_io_buffer *head)
{
- const int len = strlen(find);
- char *tmp = *src;
-
- if (strncmp(tmp, find, len))
- return false;
- tmp += len;
- *src = tmp;
- return true;
+ tomoyo_set_string(head, " ");
}
-/**
- * tomoyo_normalize_line - Format string.
- *
- * @buffer: The line to normalize.
- *
- * Leading and trailing whitespaces are removed.
- * Multiple whitespaces are packed into single space.
- *
- * Returns nothing.
- */
-static void tomoyo_normalize_line(unsigned char *buffer)
+static bool tomoyo_set_lf(struct tomoyo_io_buffer *head)
{
- unsigned char *sp = buffer;
- unsigned char *dp = buffer;
- bool first = true;
-
- while (tomoyo_is_invalid(*sp))
- sp++;
- while (*sp) {
- if (!first)
- *dp++ = ' ';
- first = false;
- while (tomoyo_is_valid(*sp))
- *dp++ = *sp++;
- while (tomoyo_is_invalid(*sp))
- sp++;
- }
- *dp = '\0';
+ tomoyo_set_string(head, "\n");
+ return !head->r.w_pos;
}
/**
- * tomoyo_tokenize - Tokenize string.
- *
- * @buffer: The line to tokenize.
- * @w: Pointer to "char *".
- * @size: Sizeof @w .
+ * tomoyo_print_name_union - Print a tomoyo_name_union.
*
- * Returns true on success, false otherwise.
+ * @head: Pointer to "struct tomoyo_io_buffer".
+ * @ptr: Pointer to "struct tomoyo_name_union".
*/
-bool tomoyo_tokenize(char *buffer, char *w[], size_t size)
+static void tomoyo_print_name_union(struct tomoyo_io_buffer *head,
+ const struct tomoyo_name_union *ptr)
{
- int count = size / sizeof(char *);
- int i;
- for (i = 0; i < count; i++)
- w[i] = "";
- for (i = 0; i < count; i++) {
- char *cp = strchr(buffer, ' ');
- if (cp)
- *cp = '\0';
- w[i] = buffer;
- if (!cp)
- break;
- buffer = cp + 1;
+ tomoyo_set_space(head);
+ if (ptr->is_group) {
+ tomoyo_set_string(head, "@");
+ tomoyo_set_string(head, ptr->group->group_name->name);
+ } else {
+ tomoyo_set_string(head, ptr->filename->name);
}
- return i < count || !*buffer;
}
/**
- * tomoyo_is_correct_path - Validate a pathname.
- * @filename: The pathname to check.
- * @start_type: Should the pathname start with '/'?
- * 1 = must / -1 = must not / 0 = don't care
- * @pattern_type: Can the pathname contain a wildcard?
- * 1 = must / -1 = must not / 0 = don't care
- * @end_type: Should the pathname end with '/'?
- * 1 = must / -1 = must not / 0 = don't care
- *
- * Check whether the given filename follows the naming rules.
- * Returns true if @filename follows the naming rules, false otherwise.
+ * tomoyo_print_number_union - Print a tomoyo_number_union.
+ *
+ * @head: Pointer to "struct tomoyo_io_buffer".
+ * @ptr: Pointer to "struct tomoyo_number_union".
*/
-bool tomoyo_is_correct_path(const char *filename, const s8 start_type,
- const s8 pattern_type, const s8 end_type)
+static void tomoyo_print_number_union(struct tomoyo_io_buffer *head,
+ const struct tomoyo_number_union *ptr)
{
- const char *const start = filename;
- bool in_repetition = false;
- bool contains_pattern = false;
- unsigned char c;
- unsigned char d;
- unsigned char e;
-
- if (!filename)
- goto out;
- c = *filename;
- if (start_type == 1) { /* Must start with '/' */
- if (c != '/')
- goto out;
- } else if (start_type == -1) { /* Must not start with '/' */
- if (c == '/')
- goto out;
- }
- if (c)
- c = *(filename + strlen(filename) - 1);
- if (end_type == 1) { /* Must end with '/' */
- if (c != '/')
- goto out;
- } else if (end_type == -1) { /* Must not end with '/' */
- if (c == '/')
- goto out;
- }
- while (1) {
- c = *filename++;
- if (!c)
- break;
- if (c == '\\') {
- c = *filename++;
- switch (c) {
- case '\\': /* "\\" */
- continue;
- case '$': /* "\$" */
- case '+': /* "\+" */
- case '?': /* "\?" */
- case '*': /* "\*" */
- case '@': /* "\@" */
- case 'x': /* "\x" */
- case 'X': /* "\X" */
- case 'a': /* "\a" */
- case 'A': /* "\A" */
- case '-': /* "\-" */
- if (pattern_type == -1)
- break; /* Must not contain pattern */
- contains_pattern = true;
- continue;
- case '{': /* "/\{" */
- if (filename - 3 < start ||
- *(filename - 3) != '/')
- break;
- if (pattern_type == -1)
- break; /* Must not contain pattern */
- contains_pattern = true;
- in_repetition = true;
- continue;
- case '}': /* "\}/" */
- if (*filename != '/')
- break;
- if (!in_repetition)
- break;
- in_repetition = false;
- continue;
- case '0': /* "\ooo" */
- case '1':
- case '2':
- case '3':
- d = *filename++;
- if (d < '0' || d > '7')
- break;
- e = *filename++;
- if (e < '0' || e > '7')
- break;
- c = tomoyo_make_byte(c, d, e);
- if (tomoyo_is_invalid(c))
- continue; /* pattern is not \000 */
+ tomoyo_set_space(head);
+ if (ptr->is_group) {
+ tomoyo_set_string(head, "@");
+ tomoyo_set_string(head, ptr->group->group_name->name);
+ } else {
+ int i;
+ unsigned long min = ptr->values[0];
+ const unsigned long max = ptr->values[1];
+ u8 min_type = ptr->min_type;
+ const u8 max_type = ptr->max_type;
+ char buffer[128];
+ buffer[0] = '\0';
+ for (i = 0; i < 2; i++) {
+ switch (min_type) {
+ case TOMOYO_VALUE_TYPE_HEXADECIMAL:
+ tomoyo_addprintf(buffer, sizeof(buffer),
+ "0x%lX", min);
+ break;
+ case TOMOYO_VALUE_TYPE_OCTAL:
+ tomoyo_addprintf(buffer, sizeof(buffer),
+ "0%lo", min);
+ break;
+ default:
+ tomoyo_addprintf(buffer, sizeof(buffer),
+ "%lu", min);
+ break;
}
- goto out;
- } else if (in_repetition && c == '/') {
- goto out;
- } else if (tomoyo_is_invalid(c)) {
- goto out;
+ if (min == max && min_type == max_type)
+ break;
+ tomoyo_addprintf(buffer, sizeof(buffer), "-");
+ min_type = max_type;
+ min = max;
}
+ tomoyo_io_printf(head, "%s", buffer);
}
- if (pattern_type == 1) { /* Must contain pattern */
- if (!contains_pattern)
- goto out;
- }
- if (in_repetition)
- goto out;
- return true;
- out:
- return false;
}
/**
- * tomoyo_is_correct_domain - Check whether the given domainname follows the naming rules.
- * @domainname: The domainname to check.
+ * tomoyo_assign_profile - Create a new profile.
*
- * Returns true if @domainname follows the naming rules, false otherwise.
+ * @profile: Profile number to create.
+ *
+ * Returns pointer to "struct tomoyo_profile" on success, NULL otherwise.
*/
-bool tomoyo_is_correct_domain(const unsigned char *domainname)
+static struct tomoyo_profile *tomoyo_assign_profile(const unsigned int profile)
{
- unsigned char c;
- unsigned char d;
- unsigned char e;
-
- if (!domainname || strncmp(domainname, TOMOYO_ROOT_NAME,
- TOMOYO_ROOT_NAME_LEN))
+ struct tomoyo_profile *ptr;
+ struct tomoyo_profile *entry;
+ if (profile >= TOMOYO_MAX_PROFILES)
+ return NULL;
+ ptr = tomoyo_profile_ptr[profile];
+ if (ptr)
+ return ptr;
+ entry = kzalloc(sizeof(*entry), GFP_NOFS);
+ if (mutex_lock_interruptible(&tomoyo_policy_lock))
goto out;
- domainname += TOMOYO_ROOT_NAME_LEN;
- if (!*domainname)
- return true;
- do {
- if (*domainname++ != ' ')
- goto out;
- if (*domainname++ != '/')
- goto out;
- while ((c = *domainname) != '\0' && c != ' ') {
- domainname++;
- if (c == '\\') {
- c = *domainname++;
- switch ((c)) {
- case '\\': /* "\\" */
- continue;
- case '0': /* "\ooo" */
- case '1':
- case '2':
- case '3':
- d = *domainname++;
- if (d < '0' || d > '7')
- break;
- e = *domainname++;
- if (e < '0' || e > '7')
- break;
- c = tomoyo_make_byte(c, d, e);
- if (tomoyo_is_invalid(c))
- /* pattern is not \000 */
- continue;
- }
- goto out;
- } else if (tomoyo_is_invalid(c)) {
- goto out;
- }
- }
- } while (*domainname);
- return true;
+ ptr = tomoyo_profile_ptr[profile];
+ if (!ptr && tomoyo_memory_ok(entry)) {
+ ptr = entry;
+ ptr->learning = &tomoyo_default_profile.preference;
+ ptr->permissive = &tomoyo_default_profile.preference;
+ ptr->enforcing = &tomoyo_default_profile.preference;
+ ptr->default_config = TOMOYO_CONFIG_DISABLED;
+ memset(ptr->config, TOMOYO_CONFIG_USE_DEFAULT,
+ sizeof(ptr->config));
+ mb(); /* Avoid out-of-order execution. */
+ tomoyo_profile_ptr[profile] = ptr;
+ entry = NULL;
+ }
+ mutex_unlock(&tomoyo_policy_lock);
out:
- return false;
+ kfree(entry);
+ return ptr;
}
/**
- * tomoyo_is_domain_def - Check whether the given token can be a domainname.
+ * tomoyo_profile - Find a profile.
*
- * @buffer: The token to check.
+ * @profile: Profile number to find.
*
- * Returns true if @buffer possibly be a domainname, false otherwise.
+ * Returns pointer to "struct tomoyo_profile".
*/
-bool tomoyo_is_domain_def(const unsigned char *buffer)
+struct tomoyo_profile *tomoyo_profile(const u8 profile)
{
- return !strncmp(buffer, TOMOYO_ROOT_NAME, TOMOYO_ROOT_NAME_LEN);
+ struct tomoyo_profile *ptr = tomoyo_profile_ptr[profile];
+ if (!tomoyo_policy_loaded)
+ return &tomoyo_default_profile;
+ BUG_ON(!ptr);
+ return ptr;
}
-/**
- * tomoyo_find_domain - Find a domain by the given name.
- *
- * @domainname: The domainname to find.
- *
- * Returns pointer to "struct tomoyo_domain_info" if found, NULL otherwise.
- *
- * Caller holds tomoyo_read_lock().
- */
-struct tomoyo_domain_info *tomoyo_find_domain(const char *domainname)
+static s8 tomoyo_find_yesno(const char *string, const char *find)
{
- struct tomoyo_domain_info *domain;
- struct tomoyo_path_info name;
-
- name.name = domainname;
- tomoyo_fill_path_info(&name);
- list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) {
- if (!domain->is_deleted &&
- !tomoyo_pathcmp(&name, domain->domainname))
- return domain;
+ const char *cp = strstr(string, find);
+ if (cp) {
+ cp += strlen(find);
+ if (!strncmp(cp, "=yes", 4))
+ return 1;
+ else if (!strncmp(cp, "=no", 3))
+ return 0;
}
- return NULL;
+ return -1;
}
-/**
- * tomoyo_const_part_length - Evaluate the initial length without a pattern in a token.
- *
- * @filename: The string to evaluate.
- *
- * Returns the initial length without a pattern in @filename.
- */
-static int tomoyo_const_part_length(const char *filename)
+static void tomoyo_set_bool(bool *b, const char *string, const char *find)
{
- char c;
- int len = 0;
-
- if (!filename)
- return 0;
- while ((c = *filename++) != '\0') {
- if (c != '\\') {
- len++;
- continue;
- }
- c = *filename++;
- switch (c) {
- case '\\': /* "\\" */
- len += 2;
- continue;
- case '0': /* "\ooo" */
- case '1':
- case '2':
- case '3':
- c = *filename++;
- if (c < '0' || c > '7')
- break;
- c = *filename++;
- if (c < '0' || c > '7')
- break;
- len += 4;
- continue;
- }
+ switch (tomoyo_find_yesno(string, find)) {
+ case 1:
+ *b = true;
+ break;
+ case 0:
+ *b = false;
break;
}
- return len;
}
-/**
- * tomoyo_fill_path_info - Fill in "struct tomoyo_path_info" members.
- *
- * @ptr: Pointer to "struct tomoyo_path_info" to fill in.
- *
- * The caller sets "struct tomoyo_path_info"->name.
- */
-void tomoyo_fill_path_info(struct tomoyo_path_info *ptr)
+static void tomoyo_set_uint(unsigned int *i, const char *string,
+ const char *find)
{
- const char *name = ptr->name;
- const int len = strlen(name);
-
- ptr->const_len = tomoyo_const_part_length(name);
- ptr->is_dir = len && (name[len - 1] == '/');
- ptr->is_patterned = (ptr->const_len < len);
- ptr->hash = full_name_hash(name, len);
+ const char *cp = strstr(string, find);
+ if (cp)
+ sscanf(cp + strlen(find), "=%u", i);
}
-/**
- * tomoyo_file_matches_pattern2 - Pattern matching without '/' character
- * and "\-" pattern.
- *
- * @filename: The start of string to check.
- * @filename_end: The end of string to check.
- * @pattern: The start of pattern to compare.
- * @pattern_end: The end of pattern to compare.
- *
- * Returns true if @filename matches @pattern, false otherwise.
- */
-static bool tomoyo_file_matches_pattern2(const char *filename,
- const char *filename_end,
- const char *pattern,
- const char *pattern_end)
+static void tomoyo_set_pref(const char *name, const char *value,
+ const bool use_default,
+ struct tomoyo_profile *profile)
{
- while (filename < filename_end && pattern < pattern_end) {
- char c;
- if (*pattern != '\\') {
- if (*filename++ != *pattern++)
- return false;
- continue;
+ struct tomoyo_preference **pref;
+ bool *verbose;
+ if (!strcmp(name, "enforcing")) {
+ if (use_default) {
+ pref = &profile->enforcing;
+ goto set_default;
}
- c = *filename;
- pattern++;
- switch (*pattern) {
- int i;
- int j;
- case '?':
- if (c == '/') {
- return false;
- } else if (c == '\\') {
- if (filename[1] == '\\')
- filename++;
- else if (tomoyo_is_byte_range(filename + 1))
- filename += 3;
- else
- return false;
- }
- break;
- case '\\':
- if (c != '\\')
- return false;
- if (*++filename != '\\')
- return false;
- break;
- case '+':
- if (!isdigit(c))
- return false;
- break;
- case 'x':
- if (!isxdigit(c))
- return false;
- break;
- case 'a':
- if (!tomoyo_is_alphabet_char(c))
- return false;
- break;
- case '0':
- case '1':
- case '2':
- case '3':
- if (c == '\\' && tomoyo_is_byte_range(filename + 1)
- && strncmp(filename + 1, pattern, 3) == 0) {
- filename += 3;
- pattern += 2;
- break;
- }
- return false; /* Not matched. */
- case '*':
- case '@':
- for (i = 0; i <= filename_end - filename; i++) {
- if (tomoyo_file_matches_pattern2(
- filename + i, filename_end,
- pattern + 1, pattern_end))
- return true;
- c = filename[i];
- if (c == '.' && *pattern == '@')
- break;
- if (c != '\\')
- continue;
- if (filename[i + 1] == '\\')
- i++;
- else if (tomoyo_is_byte_range(filename + i + 1))
- i += 3;
- else
- break; /* Bad pattern. */
- }
- return false; /* Not matched. */
- default:
- j = 0;
- c = *pattern;
- if (c == '$') {
- while (isdigit(filename[j]))
- j++;
- } else if (c == 'X') {
- while (isxdigit(filename[j]))
- j++;
- } else if (c == 'A') {
- while (tomoyo_is_alphabet_char(filename[j]))
- j++;
- }
- for (i = 1; i <= j; i++) {
- if (tomoyo_file_matches_pattern2(
- filename + i, filename_end,
- pattern + 1, pattern_end))
- return true;
- }
- return false; /* Not matched or bad pattern. */
- }
- filename++;
- pattern++;
- }
- while (*pattern == '\\' &&
- (*(pattern + 1) == '*' || *(pattern + 1) == '@'))
- pattern += 2;
- return filename == filename_end && pattern == pattern_end;
-}
-
-/**
- * tomoyo_file_matches_pattern - Pattern matching without without '/' character.
- *
- * @filename: The start of string to check.
- * @filename_end: The end of string to check.
- * @pattern: The start of pattern to compare.
- * @pattern_end: The end of pattern to compare.
- *
- * Returns true if @filename matches @pattern, false otherwise.
- */
-static bool tomoyo_file_matches_pattern(const char *filename,
- const char *filename_end,
- const char *pattern,
- const char *pattern_end)
-{
- const char *pattern_start = pattern;
- bool first = true;
- bool result;
-
- while (pattern < pattern_end - 1) {
- /* Split at "\-" pattern. */
- if (*pattern++ != '\\' || *pattern++ != '-')
- continue;
- result = tomoyo_file_matches_pattern2(filename,
- filename_end,
- pattern_start,
- pattern - 2);
- if (first)
- result = !result;
- if (result)
- return false;
- first = false;
- pattern_start = pattern;
+ profile->enforcing = &profile->preference;
+ verbose = &profile->preference.enforcing_verbose;
+ goto set_verbose;
}
- result = tomoyo_file_matches_pattern2(filename, filename_end,
- pattern_start, pattern_end);
- return first ? result : !result;
-}
-
-/**
- * tomoyo_path_matches_pattern2 - Do pathname pattern matching.
- *
- * @f: The start of string to check.
- * @p: The start of pattern to compare.
- *
- * Returns true if @f matches @p, false otherwise.
- */
-static bool tomoyo_path_matches_pattern2(const char *f, const char *p)
-{
- const char *f_delimiter;
- const char *p_delimiter;
-
- while (*f && *p) {
- f_delimiter = strchr(f, '/');
- if (!f_delimiter)
- f_delimiter = f + strlen(f);
- p_delimiter = strchr(p, '/');
- if (!p_delimiter)
- p_delimiter = p + strlen(p);
- if (*p == '\\' && *(p + 1) == '{')
- goto recursive;
- if (!tomoyo_file_matches_pattern(f, f_delimiter, p,
- p_delimiter))
- return false;
- f = f_delimiter;
- if (*f)
- f++;
- p = p_delimiter;
- if (*p)
- p++;
+ if (!strcmp(name, "permissive")) {
+ if (use_default) {
+ pref = &profile->permissive;
+ goto set_default;
+ }
+ profile->permissive = &profile->preference;
+ verbose = &profile->preference.permissive_verbose;
+ goto set_verbose;
}
- /* Ignore trailing "\*" and "\@" in @pattern. */
- while (*p == '\\' &&
- (*(p + 1) == '*' || *(p + 1) == '@'))
- p += 2;
- return !*f && !*p;
- recursive:
- /*
- * The "\{" pattern is permitted only after '/' character.
- * This guarantees that below "*(p - 1)" is safe.
- * Also, the "\}" pattern is permitted only before '/' character
- * so that "\{" + "\}" pair will not break the "\-" operator.
- */
- if (*(p - 1) != '/' || p_delimiter <= p + 3 || *p_delimiter != '/' ||
- *(p_delimiter - 1) != '}' || *(p_delimiter - 2) != '\\')
- return false; /* Bad pattern. */
- do {
- /* Compare current component with pattern. */
- if (!tomoyo_file_matches_pattern(f, f_delimiter, p + 2,
- p_delimiter - 2))
- break;
- /* Proceed to next component. */
- f = f_delimiter;
- if (!*f)
- break;
- f++;
- /* Continue comparison. */
- if (tomoyo_path_matches_pattern2(f, p_delimiter + 1))
- return true;
- f_delimiter = strchr(f, '/');
- } while (f_delimiter);
- return false; /* Not matched. */
-}
-
-/**
- * tomoyo_path_matches_pattern - Check whether the given filename matches the given pattern.
- *
- * @filename: The filename to check.
- * @pattern: The pattern to compare.
- *
- * Returns true if matches, false otherwise.
- *
- * The following patterns are available.
- * \\ \ itself.
- * \ooo Octal representation of a byte.
- * \* Zero or more repetitions of characters other than '/'.
- * \@ Zero or more repetitions of characters other than '/' or '.'.
- * \? 1 byte character other than '/'.
- * \$ One or more repetitions of decimal digits.
- * \+ 1 decimal digit.
- * \X One or more repetitions of hexadecimal digits.
- * \x 1 hexadecimal digit.
- * \A One or more repetitions of alphabet characters.
- * \a 1 alphabet character.
- *
- * \- Subtraction operator.
- *
- * /\{dir\}/ '/' + 'One or more repetitions of dir/' (e.g. /dir/ /dir/dir/
- * /dir/dir/dir/ ).
- */
-bool tomoyo_path_matches_pattern(const struct tomoyo_path_info *filename,
- const struct tomoyo_path_info *pattern)
-{
- const char *f = filename->name;
- const char *p = pattern->name;
- const int len = pattern->const_len;
-
- /* If @pattern doesn't contain pattern, I can use strcmp(). */
- if (!pattern->is_patterned)
- return !tomoyo_pathcmp(filename, pattern);
- /* Don't compare directory and non-directory. */
- if (filename->is_dir != pattern->is_dir)
- return false;
- /* Compare the initial length without patterns. */
- if (strncmp(f, p, len))
- return false;
- f += len;
- p += len;
- return tomoyo_path_matches_pattern2(f, p);
-}
-
-/**
- * tomoyo_io_printf - Transactional printf() to "struct tomoyo_io_buffer" structure.
- *
- * @head: Pointer to "struct tomoyo_io_buffer".
- * @fmt: The printf()'s format string, followed by parameters.
- *
- * Returns true if output was written, false otherwise.
- *
- * The snprintf() will truncate, but tomoyo_io_printf() won't.
- */
-bool tomoyo_io_printf(struct tomoyo_io_buffer *head, const char *fmt, ...)
-{
- va_list args;
- int len;
- int pos = head->read_avail;
- int size = head->readbuf_size - pos;
-
- if (size <= 0)
- return false;
- va_start(args, fmt);
- len = vsnprintf(head->read_buf + pos, size, fmt, args);
- va_end(args);
- if (pos + len >= head->readbuf_size)
- return false;
- head->read_avail += len;
- return true;
-}
-
-/**
- * tomoyo_get_exe - Get tomoyo_realpath() of current process.
- *
- * Returns the tomoyo_realpath() of current process on success, NULL otherwise.
- *
- * This function uses kzalloc(), so the caller must call kfree()
- * if this function didn't return NULL.
- */
-static const char *tomoyo_get_exe(void)
-{
- struct mm_struct *mm = current->mm;
- struct vm_area_struct *vma;
- const char *cp = NULL;
-
- if (!mm)
- return NULL;
- down_read(&mm->mmap_sem);
- for (vma = mm->mmap; vma; vma = vma->vm_next) {
- if ((vma->vm_flags & VM_EXECUTABLE) && vma->vm_file) {
- cp = tomoyo_realpath_from_path(&vma->vm_file->f_path);
- break;
+ if (!strcmp(name, "learning")) {
+ if (use_default) {
+ pref = &profile->learning;
+ goto set_default;
}
+ profile->learning = &profile->preference;
+ tomoyo_set_uint(&profile->preference.learning_max_entry, value,
+ "max_entry");
+ verbose = &profile->preference.learning_verbose;
+ goto set_verbose;
}
- up_read(&mm->mmap_sem);
- return cp;
+ return;
+ set_default:
+ *pref = &tomoyo_default_profile.preference;
+ return;
+ set_verbose:
+ tomoyo_set_bool(verbose, value, "verbose");
}
-/**
- * tomoyo_get_msg - Get warning message.
- *
- * @is_enforce: Is it enforcing mode?
- *
- * Returns "ERROR" or "WARNING".
- */
-const char *tomoyo_get_msg(const bool is_enforce)
+static int tomoyo_set_mode(char *name, const char *value,
+ const bool use_default,
+ struct tomoyo_profile *profile)
{
- if (is_enforce)
- return "ERROR";
- else
- return "WARNING";
-}
-
-/**
- * tomoyo_check_flags - Check mode for specified functionality.
- *
- * @domain: Pointer to "struct tomoyo_domain_info".
- * @index: The functionality to check mode.
- *
- * TOMOYO checks only process context.
- * This code disables TOMOYO's enforcement in case the function is called from
- * interrupt context.
- */
-unsigned int tomoyo_check_flags(const struct tomoyo_domain_info *domain,
- const u8 index)
-{
- const u8 profile = domain->profile;
-
- if (WARN_ON(in_interrupt()))
- return 0;
- return tomoyo_policy_loaded && index < TOMOYO_MAX_CONTROL_INDEX
-#if TOMOYO_MAX_PROFILES != 256
- && profile < TOMOYO_MAX_PROFILES
-#endif
- && tomoyo_profile_ptr[profile] ?
- tomoyo_profile_ptr[profile]->value[index] : 0;
-}
-
-/**
- * tomoyo_verbose_mode - Check whether TOMOYO is verbose mode.
- *
- * @domain: Pointer to "struct tomoyo_domain_info".
- *
- * Returns true if domain policy violation warning should be printed to
- * console.
- */
-bool tomoyo_verbose_mode(const struct tomoyo_domain_info *domain)
-{
- return tomoyo_check_flags(domain, TOMOYO_VERBOSE) != 0;
-}
-
-/**
- * tomoyo_domain_quota_is_ok - Check for domain's quota.
- *
- * @domain: Pointer to "struct tomoyo_domain_info".
- *
- * Returns true if the domain is not exceeded quota, false otherwise.
- *
- * Caller holds tomoyo_read_lock().
- */
-bool tomoyo_domain_quota_is_ok(struct tomoyo_domain_info * const domain)
-{
- unsigned int count = 0;
- struct tomoyo_acl_info *ptr;
-
- if (!domain)
- return true;
- list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) {
- switch (ptr->type) {
- struct tomoyo_path_acl *acl;
- u32 perm;
- u8 i;
- case TOMOYO_TYPE_PATH_ACL:
- acl = container_of(ptr, struct tomoyo_path_acl, head);
- perm = acl->perm | (((u32) acl->perm_high) << 16);
- for (i = 0; i < TOMOYO_MAX_PATH_OPERATION; i++)
- if (perm & (1 << i))
- count++;
- if (perm & (1 << TOMOYO_TYPE_READ_WRITE))
- count -= 2;
- break;
- case TOMOYO_TYPE_PATH2_ACL:
- perm = container_of(ptr, struct tomoyo_path2_acl, head)
- ->perm;
- for (i = 0; i < TOMOYO_MAX_PATH2_OPERATION; i++)
- if (perm & (1 << i))
- count++;
+ u8 i;
+ u8 config;
+ if (!strcmp(name, "CONFIG")) {
+ i = TOMOYO_MAX_MAC_INDEX + TOMOYO_MAX_MAC_CATEGORY_INDEX;
+ config = profile->default_config;
+ } else if (tomoyo_str_starts(&name, "CONFIG::")) {
+ config = 0;
+ for (i = 0; i < TOMOYO_MAX_MAC_INDEX
+ + TOMOYO_MAX_MAC_CATEGORY_INDEX; i++) {
+ if (strcmp(name, tomoyo_mac_keywords[i]))
+ continue;
+ config = profile->config[i];
break;
}
+ if (i == TOMOYO_MAX_MAC_INDEX + TOMOYO_MAX_MAC_CATEGORY_INDEX)
+ return -EINVAL;
+ } else {
+ return -EINVAL;
}
- if (count < tomoyo_check_flags(domain, TOMOYO_MAX_ACCEPT_ENTRY))
- return true;
- if (!domain->quota_warned) {
- domain->quota_warned = true;
- printk(KERN_WARNING "TOMOYO-WARNING: "
- "Domain '%s' has so many ACLs to hold. "
- "Stopped learning mode.\n", domain->domainname->name);
- }
- return false;
-}
-
-/**
- * tomoyo_find_or_assign_new_profile - Create a new profile.
- *
- * @profile: Profile number to create.
- *
- * Returns pointer to "struct tomoyo_profile" on success, NULL otherwise.
- */
-static struct tomoyo_profile *tomoyo_find_or_assign_new_profile(const unsigned
- int profile)
-{
- struct tomoyo_profile *ptr = NULL;
- int i;
-
- if (profile >= TOMOYO_MAX_PROFILES)
- return NULL;
- if (mutex_lock_interruptible(&tomoyo_policy_lock))
- return NULL;
- ptr = tomoyo_profile_ptr[profile];
- if (ptr)
- goto ok;
- ptr = kmalloc(sizeof(*ptr), GFP_NOFS);
- if (!tomoyo_memory_ok(ptr)) {
- kfree(ptr);
- ptr = NULL;
- goto ok;
+ if (use_default) {
+ config = TOMOYO_CONFIG_USE_DEFAULT;
+ } else {
+ u8 mode;
+ for (mode = 0; mode < 4; mode++)
+ if (strstr(value, tomoyo_mode[mode]))
+ /*
+ * Update lower 3 bits in order to distinguish
+ * 'config' from 'TOMOYO_CONFIG_USE_DEAFULT'.
+ */
+ config = (config & ~7) | mode;
}
- for (i = 0; i < TOMOYO_MAX_CONTROL_INDEX; i++)
- ptr->value[i] = tomoyo_control_array[i].current_value;
- mb(); /* Avoid out-of-order execution. */
- tomoyo_profile_ptr[profile] = ptr;
- ok:
- mutex_unlock(&tomoyo_policy_lock);
- return ptr;
+ if (i < TOMOYO_MAX_MAC_INDEX + TOMOYO_MAX_MAC_CATEGORY_INDEX)
+ profile->config[i] = config;
+ else if (config != TOMOYO_CONFIG_USE_DEFAULT)
+ profile->default_config = config;
+ return 0;
}
/**
- * tomoyo_write_profile - Write to profile table.
+ * tomoyo_write_profile - Write profile table.
*
* @head: Pointer to "struct tomoyo_io_buffer".
*
@@ -980,153 +430,165 @@ static int tomoyo_write_profile(struct tomoyo_io_buffer *head)
{
char *data = head->write_buf;
unsigned int i;
- unsigned int value;
+ bool use_default = false;
char *cp;
struct tomoyo_profile *profile;
- unsigned long num;
-
- cp = strchr(data, '-');
- if (cp)
- *cp = '\0';
- if (strict_strtoul(data, 10, &num))
- return -EINVAL;
- if (cp)
+ if (sscanf(data, "PROFILE_VERSION=%u", &tomoyo_profile_version) == 1)
+ return 0;
+ i = simple_strtoul(data, &cp, 10);
+ if (data == cp) {
+ profile = &tomoyo_default_profile;
+ } else {
+ if (*cp != '-')
+ return -EINVAL;
data = cp + 1;
- profile = tomoyo_find_or_assign_new_profile(num);
- if (!profile)
- return -EINVAL;
+ profile = tomoyo_assign_profile(i);
+ if (!profile)
+ return -EINVAL;
+ }
cp = strchr(data, '=');
if (!cp)
return -EINVAL;
- *cp = '\0';
+ *cp++ = '\0';
+ if (profile != &tomoyo_default_profile)
+ use_default = strstr(cp, "use_default") != NULL;
+ if (tomoyo_str_starts(&data, "PREFERENCE::")) {
+ tomoyo_set_pref(data, cp, use_default, profile);
+ return 0;
+ }
+ if (profile == &tomoyo_default_profile)
+ return -EINVAL;
if (!strcmp(data, "COMMENT")) {
const struct tomoyo_path_info *old_comment = profile->comment;
- profile->comment = tomoyo_get_name(cp + 1);
+ profile->comment = tomoyo_get_name(cp);
tomoyo_put_name(old_comment);
return 0;
}
- for (i = 0; i < TOMOYO_MAX_CONTROL_INDEX; i++) {
- if (strcmp(data, tomoyo_control_array[i].keyword))
- continue;
- if (sscanf(cp + 1, "%u", &value) != 1) {
- int j;
- const char **modes;
- switch (i) {
- case TOMOYO_VERBOSE:
- modes = tomoyo_mode_2;
- break;
- default:
- modes = tomoyo_mode_4;
- break;
- }
- for (j = 0; j < 4; j++) {
- if (strcmp(cp + 1, modes[j]))
- continue;
- value = j;
- break;
- }
- if (j == 4)
- return -EINVAL;
- } else if (value > tomoyo_control_array[i].max_value) {
- value = tomoyo_control_array[i].max_value;
- }
- profile->value[i] = value;
- return 0;
+ return tomoyo_set_mode(data, cp, use_default, profile);
+}
+
+static void tomoyo_print_preference(struct tomoyo_io_buffer *head,
+ const int idx)
+{
+ struct tomoyo_preference *pref = &tomoyo_default_profile.preference;
+ const struct tomoyo_profile *profile = idx >= 0 ?
+ tomoyo_profile_ptr[idx] : NULL;
+ char buffer[16] = "";
+ if (profile) {
+ buffer[sizeof(buffer) - 1] = '\0';
+ snprintf(buffer, sizeof(buffer) - 1, "%u-", idx);
}
- return -EINVAL;
+ if (profile) {
+ pref = profile->learning;
+ if (pref == &tomoyo_default_profile.preference)
+ goto skip1;
+ }
+ tomoyo_io_printf(head, "%sPREFERENCE::%s={ "
+ "verbose=%s max_entry=%u }\n",
+ buffer, "learning",
+ tomoyo_yesno(pref->learning_verbose),
+ pref->learning_max_entry);
+ skip1:
+ if (profile) {
+ pref = profile->permissive;
+ if (pref == &tomoyo_default_profile.preference)
+ goto skip2;
+ }
+ tomoyo_io_printf(head, "%sPREFERENCE::%s={ verbose=%s }\n",
+ buffer, "permissive",
+ tomoyo_yesno(pref->permissive_verbose));
+ skip2:
+ if (profile) {
+ pref = profile->enforcing;
+ if (pref == &tomoyo_default_profile.preference)
+ return;
+ }
+ tomoyo_io_printf(head, "%sPREFERENCE::%s={ verbose=%s }\n",
+ buffer, "enforcing",
+ tomoyo_yesno(pref->enforcing_verbose));
+}
+
+static void tomoyo_print_config(struct tomoyo_io_buffer *head, const u8 config)
+{
+ tomoyo_io_printf(head, "={ mode=%s }\n", tomoyo_mode[config & 3]);
}
/**
- * tomoyo_read_profile - Read from profile table.
+ * tomoyo_read_profile - Read profile table.
*
* @head: Pointer to "struct tomoyo_io_buffer".
- *
- * Returns 0.
*/
-static int tomoyo_read_profile(struct tomoyo_io_buffer *head)
+static void tomoyo_read_profile(struct tomoyo_io_buffer *head)
{
- static const int total = TOMOYO_MAX_CONTROL_INDEX + 1;
- int step;
-
- if (head->read_eof)
- return 0;
- for (step = head->read_step; step < TOMOYO_MAX_PROFILES * total;
- step++) {
- const u8 index = step / total;
- u8 type = step % total;
- const struct tomoyo_profile *profile
- = tomoyo_profile_ptr[index];
- head->read_step = step;
- if (!profile)
- continue;
- if (!type) { /* Print profile' comment tag. */
- if (!tomoyo_io_printf(head, "%u-COMMENT=%s\n",
- index, profile->comment ?
- profile->comment->name : ""))
+ u8 index;
+ const struct tomoyo_profile *profile;
+ next:
+ index = head->r.index;
+ profile = tomoyo_profile_ptr[index];
+ switch (head->r.step) {
+ case 0:
+ tomoyo_io_printf(head, "PROFILE_VERSION=%s\n", "20090903");
+ tomoyo_print_preference(head, -1);
+ head->r.step++;
+ break;
+ case 1:
+ for ( ; head->r.index < TOMOYO_MAX_PROFILES;
+ head->r.index++)
+ if (tomoyo_profile_ptr[head->r.index])
break;
- continue;
+ if (head->r.index == TOMOYO_MAX_PROFILES)
+ return;
+ head->r.step++;
+ break;
+ case 2:
+ {
+ const struct tomoyo_path_info *comment =
+ profile->comment;
+ tomoyo_io_printf(head, "%u-COMMENT=", index);
+ tomoyo_set_string(head, comment ? comment->name : "");
+ tomoyo_set_lf(head);
+ head->r.step++;
}
- type--;
- if (type < TOMOYO_MAX_CONTROL_INDEX) {
- const unsigned int value = profile->value[type];
- const char **modes = NULL;
- const char *keyword
- = tomoyo_control_array[type].keyword;
- switch (tomoyo_control_array[type].max_value) {
- case 3:
- modes = tomoyo_mode_4;
- break;
- case 1:
- modes = tomoyo_mode_2;
- break;
- }
- if (modes) {
- if (!tomoyo_io_printf(head, "%u-%s=%s\n", index,
- keyword, modes[value]))
- break;
- } else {
- if (!tomoyo_io_printf(head, "%u-%s=%u\n", index,
- keyword, value))
- break;
- }
+ break;
+ case 3:
+ {
+ tomoyo_io_printf(head, "%u-%s", index, "CONFIG");
+ tomoyo_print_config(head, profile->default_config);
+ head->r.bit = 0;
+ head->r.step++;
+ }
+ break;
+ case 4:
+ for ( ; head->r.bit < TOMOYO_MAX_MAC_INDEX
+ + TOMOYO_MAX_MAC_CATEGORY_INDEX; head->r.bit++) {
+ const u8 i = head->r.bit;
+ const u8 config = profile->config[i];
+ if (config == TOMOYO_CONFIG_USE_DEFAULT)
+ continue;
+ tomoyo_io_printf(head, "%u-%s%s", index, "CONFIG::",
+ tomoyo_mac_keywords[i]);
+ tomoyo_print_config(head, config);
+ head->r.bit++;
+ break;
+ }
+ if (head->r.bit == TOMOYO_MAX_MAC_INDEX
+ + TOMOYO_MAX_MAC_CATEGORY_INDEX) {
+ tomoyo_print_preference(head, index);
+ head->r.index++;
+ head->r.step = 1;
}
+ break;
}
- if (step == TOMOYO_MAX_PROFILES * total)
- head->read_eof = true;
- return 0;
+ if (tomoyo_flush(head))
+ goto next;
}
-/*
- * tomoyo_policy_manager_list is used for holding list of domainnames or
- * programs which are permitted to modify configuration via
- * /sys/kernel/security/tomoyo/ interface.
- *
- * An entry is added by
- *
- * # echo '<kernel> /sbin/mingetty /bin/login /bin/bash' > \
- * /sys/kernel/security/tomoyo/manager
- * (if you want to specify by a domainname)
- *
- * or
- *
- * # echo '/usr/lib/ccs/editpolicy' > /sys/kernel/security/tomoyo/manager
- * (if you want to specify by a program's location)
- *
- * and is deleted by
- *
- * # echo 'delete <kernel> /sbin/mingetty /bin/login /bin/bash' > \
- * /sys/kernel/security/tomoyo/manager
- *
- * or
- *
- * # echo 'delete /usr/lib/ccs/editpolicy' > \
- * /sys/kernel/security/tomoyo/manager
- *
- * and all entries are retrieved by
- *
- * # cat /sys/kernel/security/tomoyo/manager
- */
-LIST_HEAD(tomoyo_policy_manager_list);
+static bool tomoyo_same_manager(const struct tomoyo_acl_head *a,
+ const struct tomoyo_acl_head *b)
+{
+ return container_of(a, struct tomoyo_manager, head)->manager ==
+ container_of(b, struct tomoyo_manager, head)->manager;
+}
/**
* tomoyo_update_manager_entry - Add a manager entry.
@@ -1141,47 +603,29 @@ LIST_HEAD(tomoyo_policy_manager_list);
static int tomoyo_update_manager_entry(const char *manager,
const bool is_delete)
{
- struct tomoyo_policy_manager_entry *ptr;
- struct tomoyo_policy_manager_entry e = { };
- int error = is_delete ? -ENOENT : -ENOMEM;
+ struct tomoyo_manager e = { };
+ int error;
- if (tomoyo_is_domain_def(manager)) {
- if (!tomoyo_is_correct_domain(manager))
+ if (tomoyo_domain_def(manager)) {
+ if (!tomoyo_correct_domain(manager))
return -EINVAL;
e.is_domain = true;
} else {
- if (!tomoyo_is_correct_path(manager, 1, -1, -1))
+ if (!tomoyo_correct_path(manager))
return -EINVAL;
}
e.manager = tomoyo_get_name(manager);
if (!e.manager)
return -ENOMEM;
- if (mutex_lock_interruptible(&tomoyo_policy_lock))
- goto out;
- list_for_each_entry_rcu(ptr, &tomoyo_policy_manager_list, list) {
- if (ptr->manager != e.manager)
- continue;
- ptr->is_deleted = is_delete;
- error = 0;
- break;
- }
- if (!is_delete && error) {
- struct tomoyo_policy_manager_entry *entry =
- tomoyo_commit_ok(&e, sizeof(e));
- if (entry) {
- list_add_tail_rcu(&entry->list,
- &tomoyo_policy_manager_list);
- error = 0;
- }
- }
- mutex_unlock(&tomoyo_policy_lock);
- out:
+ error = tomoyo_update_policy(&e.head, sizeof(e), is_delete,
+ &tomoyo_policy_list[TOMOYO_ID_MANAGER],
+ tomoyo_same_manager);
tomoyo_put_name(e.manager);
return error;
}
/**
- * tomoyo_write_manager_policy - Write manager policy.
+ * tomoyo_write_manager - Write manager policy.
*
* @head: Pointer to "struct tomoyo_io_buffer".
*
@@ -1189,7 +633,7 @@ static int tomoyo_update_manager_entry(const char *manager,
*
* Caller holds tomoyo_read_lock().
*/
-static int tomoyo_write_manager_policy(struct tomoyo_io_buffer *head)
+static int tomoyo_write_manager(struct tomoyo_io_buffer *head)
{
char *data = head->write_buf;
bool is_delete = tomoyo_str_starts(&data, TOMOYO_KEYWORD_DELETE);
@@ -1202,47 +646,41 @@ static int tomoyo_write_manager_policy(struct tomoyo_io_buffer *head)
}
/**
- * tomoyo_read_manager_policy - Read manager policy.
+ * tomoyo_read_manager - Read manager policy.
*
* @head: Pointer to "struct tomoyo_io_buffer".
*
- * Returns 0.
- *
* Caller holds tomoyo_read_lock().
*/
-static int tomoyo_read_manager_policy(struct tomoyo_io_buffer *head)
+static void tomoyo_read_manager(struct tomoyo_io_buffer *head)
{
- struct list_head *pos;
- bool done = true;
-
- if (head->read_eof)
- return 0;
- list_for_each_cookie(pos, head->read_var2,
- &tomoyo_policy_manager_list) {
- struct tomoyo_policy_manager_entry *ptr;
- ptr = list_entry(pos, struct tomoyo_policy_manager_entry,
- list);
- if (ptr->is_deleted)
+ if (head->r.eof)
+ return;
+ list_for_each_cookie(head->r.acl,
+ &tomoyo_policy_list[TOMOYO_ID_MANAGER]) {
+ struct tomoyo_manager *ptr =
+ list_entry(head->r.acl, typeof(*ptr), head.list);
+ if (ptr->head.is_deleted)
continue;
- done = tomoyo_io_printf(head, "%s\n", ptr->manager->name);
- if (!done)
- break;
+ if (!tomoyo_flush(head))
+ return;
+ tomoyo_set_string(head, ptr->manager->name);
+ tomoyo_set_lf(head);
}
- head->read_eof = done;
- return 0;
+ head->r.eof = true;
}
/**
- * tomoyo_is_policy_manager - Check whether the current process is a policy manager.
+ * tomoyo_manager - Check whether the current process is a policy manager.
*
* Returns true if the current process is permitted to modify policy
* via /sys/kernel/security/tomoyo/ interface.
*
* Caller holds tomoyo_read_lock().
*/
-static bool tomoyo_is_policy_manager(void)
+static bool tomoyo_manager(void)
{
- struct tomoyo_policy_manager_entry *ptr;
+ struct tomoyo_manager *ptr;
const char *exe;
const struct task_struct *task = current;
const struct tomoyo_path_info *domainname = tomoyo_domain()->domainname;
@@ -1252,8 +690,9 @@ static bool tomoyo_is_policy_manager(void)
return true;
if (!tomoyo_manage_by_non_root && (task->cred->uid || task->cred->euid))
return false;
- list_for_each_entry_rcu(ptr, &tomoyo_policy_manager_list, list) {
- if (!ptr->is_deleted && ptr->is_domain
+ list_for_each_entry_rcu(ptr, &tomoyo_policy_list[TOMOYO_ID_MANAGER],
+ head.list) {
+ if (!ptr->head.is_deleted && ptr->is_domain
&& !tomoyo_pathcmp(domainname, ptr->manager)) {
found = true;
break;
@@ -1264,8 +703,9 @@ static bool tomoyo_is_policy_manager(void)
exe = tomoyo_get_exe();
if (!exe)
return false;
- list_for_each_entry_rcu(ptr, &tomoyo_policy_manager_list, list) {
- if (!ptr->is_deleted && !ptr->is_domain
+ list_for_each_entry_rcu(ptr, &tomoyo_policy_list[TOMOYO_ID_MANAGER],
+ head.list) {
+ if (!ptr->head.is_deleted && !ptr->is_domain
&& !strcmp(exe, ptr->manager->name)) {
found = true;
break;
@@ -1285,7 +725,7 @@ static bool tomoyo_is_policy_manager(void)
}
/**
- * tomoyo_is_select_one - Parse select command.
+ * tomoyo_select_one - Parse select command.
*
* @head: Pointer to "struct tomoyo_io_buffer".
* @data: String to parse.
@@ -1294,23 +734,31 @@ static bool tomoyo_is_policy_manager(void)
*
* Caller holds tomoyo_read_lock().
*/
-static bool tomoyo_is_select_one(struct tomoyo_io_buffer *head,
- const char *data)
+static bool tomoyo_select_one(struct tomoyo_io_buffer *head, const char *data)
{
unsigned int pid;
struct tomoyo_domain_info *domain = NULL;
+ bool global_pid = false;
- if (sscanf(data, "pid=%u", &pid) == 1) {
+ if (!strcmp(data, "allow_execute")) {
+ head->r.print_execute_only = true;
+ return true;
+ }
+ if (sscanf(data, "pid=%u", &pid) == 1 ||
+ (global_pid = true, sscanf(data, "global-pid=%u", &pid) == 1)) {
struct task_struct *p;
rcu_read_lock();
read_lock(&tasklist_lock);
- p = find_task_by_vpid(pid);
+ if (global_pid)
+ p = find_task_by_pid_ns(pid, &init_pid_ns);
+ else
+ p = find_task_by_vpid(pid);
if (p)
domain = tomoyo_real_domain(p);
read_unlock(&tasklist_lock);
rcu_read_unlock();
} else if (!strncmp(data, "domain=", 7)) {
- if (tomoyo_is_domain_def(data + 7))
+ if (tomoyo_domain_def(data + 7))
domain = tomoyo_find_domain(data + 7);
} else
return false;
@@ -1318,24 +766,13 @@ static bool tomoyo_is_select_one(struct tomoyo_io_buffer *head,
/* Accessing read_buf is safe because head->io_sem is held. */
if (!head->read_buf)
return true; /* Do nothing if open(O_WRONLY). */
- head->read_avail = 0;
+ memset(&head->r, 0, sizeof(head->r));
+ head->r.print_this_domain_only = true;
+ head->r.eof = !domain;
+ head->r.domain = &domain->list;
tomoyo_io_printf(head, "# select %s\n", data);
- head->read_single_domain = true;
- head->read_eof = !domain;
- if (domain) {
- struct tomoyo_domain_info *d;
- head->read_var1 = NULL;
- list_for_each_entry_rcu(d, &tomoyo_domain_list, list) {
- if (d == domain)
- break;
- head->read_var1 = &d->list;
- }
- head->read_var2 = NULL;
- head->read_bit = 0;
- head->read_step = 0;
- if (domain->is_deleted)
- tomoyo_io_printf(head, "# This is a deleted domain.\n");
- }
+ if (domain && domain->is_deleted)
+ tomoyo_io_printf(head, "# This is a deleted domain.\n");
return true;
}
@@ -1373,7 +810,7 @@ static int tomoyo_delete_domain(char *domainname)
}
/**
- * tomoyo_write_domain_policy - Write domain policy.
+ * tomoyo_write_domain2 - Write domain policy.
*
* @head: Pointer to "struct tomoyo_io_buffer".
*
@@ -1381,7 +818,24 @@ static int tomoyo_delete_domain(char *domainname)
*
* Caller holds tomoyo_read_lock().
*/
-static int tomoyo_write_domain_policy(struct tomoyo_io_buffer *head)
+static int tomoyo_write_domain2(char *data, struct tomoyo_domain_info *domain,
+ const bool is_delete)
+{
+ if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_ALLOW_MOUNT))
+ return tomoyo_write_mount(data, domain, is_delete);
+ return tomoyo_write_file(data, domain, is_delete);
+}
+
+/**
+ * tomoyo_write_domain - Write domain policy.
+ *
+ * @head: Pointer to "struct tomoyo_io_buffer".
+ *
+ * Returns 0 on success, negative value otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
+ */
+static int tomoyo_write_domain(struct tomoyo_io_buffer *head)
{
char *data = head->write_buf;
struct tomoyo_domain_info *domain = head->write_var1;
@@ -1393,19 +847,19 @@ static int tomoyo_write_domain_policy(struct tomoyo_io_buffer *head)
is_delete = true;
else if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_SELECT))
is_select = true;
- if (is_select && tomoyo_is_select_one(head, data))
+ if (is_select && tomoyo_select_one(head, data))
return 0;
/* Don't allow updating policies by non manager programs. */
- if (!tomoyo_is_policy_manager())
+ if (!tomoyo_manager())
return -EPERM;
- if (tomoyo_is_domain_def(data)) {
+ if (tomoyo_domain_def(data)) {
domain = NULL;
if (is_delete)
tomoyo_delete_domain(data);
else if (is_select)
domain = tomoyo_find_domain(data);
else
- domain = tomoyo_find_or_assign_new_domain(data, 0);
+ domain = tomoyo_assign_domain(data, 0);
head->write_var1 = domain;
return 0;
}
@@ -1422,179 +876,198 @@ static int tomoyo_write_domain_policy(struct tomoyo_io_buffer *head)
domain->ignore_global_allow_read = !is_delete;
return 0;
}
- return tomoyo_write_file_policy(data, domain, is_delete);
+ if (!strcmp(data, TOMOYO_KEYWORD_QUOTA_EXCEEDED)) {
+ domain->quota_warned = !is_delete;
+ return 0;
+ }
+ if (!strcmp(data, TOMOYO_KEYWORD_TRANSITION_FAILED)) {
+ domain->transition_failed = !is_delete;
+ return 0;
+ }
+ return tomoyo_write_domain2(data, domain, is_delete);
}
/**
- * tomoyo_print_path_acl - Print a single path ACL entry.
+ * tomoyo_fns - Find next set bit.
*
- * @head: Pointer to "struct tomoyo_io_buffer".
- * @ptr: Pointer to "struct tomoyo_path_acl".
+ * @perm: 8 bits value.
+ * @bit: First bit to find.
*
- * Returns true on success, false otherwise.
+ * Returns next on-bit on success, 8 otherwise.
*/
-static bool tomoyo_print_path_acl(struct tomoyo_io_buffer *head,
- struct tomoyo_path_acl *ptr)
+static u8 tomoyo_fns(const u8 perm, u8 bit)
{
- int pos;
- u8 bit;
- const u32 perm = ptr->perm | (((u32) ptr->perm_high) << 16);
-
- for (bit = head->read_bit; bit < TOMOYO_MAX_PATH_OPERATION; bit++) {
- if (!(perm & (1 << bit)))
- continue;
- /* Print "read/write" instead of "read" and "write". */
- if ((bit == TOMOYO_TYPE_READ || bit == TOMOYO_TYPE_WRITE)
- && (perm & (1 << TOMOYO_TYPE_READ_WRITE)))
- continue;
- pos = head->read_avail;
- if (!tomoyo_io_printf(head, "allow_%s ",
- tomoyo_path2keyword(bit)) ||
- !tomoyo_print_name_union(head, &ptr->name) ||
- !tomoyo_io_printf(head, "\n"))
- goto out;
- }
- head->read_bit = 0;
- return true;
- out:
- head->read_bit = bit;
- head->read_avail = pos;
- return false;
+ for ( ; bit < 8; bit++)
+ if (perm & (1 << bit))
+ break;
+ return bit;
}
/**
- * tomoyo_print_path2_acl - Print a double path ACL entry.
+ * tomoyo_print_entry - Print an ACL entry.
*
* @head: Pointer to "struct tomoyo_io_buffer".
- * @ptr: Pointer to "struct tomoyo_path2_acl".
+ * @acl: Pointer to an ACL entry.
*
* Returns true on success, false otherwise.
*/
-static bool tomoyo_print_path2_acl(struct tomoyo_io_buffer *head,
- struct tomoyo_path2_acl *ptr)
+static bool tomoyo_print_entry(struct tomoyo_io_buffer *head,
+ struct tomoyo_acl_info *acl)
{
- int pos;
- const u8 perm = ptr->perm;
+ const u8 acl_type = acl->type;
u8 bit;
- for (bit = head->read_bit; bit < TOMOYO_MAX_PATH2_OPERATION; bit++) {
- if (!(perm & (1 << bit)))
- continue;
- pos = head->read_avail;
- if (!tomoyo_io_printf(head, "allow_%s ",
- tomoyo_path22keyword(bit)) ||
- !tomoyo_print_name_union(head, &ptr->name1) ||
- !tomoyo_print_name_union(head, &ptr->name2) ||
- !tomoyo_io_printf(head, "\n"))
- goto out;
+ if (acl->is_deleted)
+ return true;
+ next:
+ bit = head->r.bit;
+ if (!tomoyo_flush(head))
+ return false;
+ else if (acl_type == TOMOYO_TYPE_PATH_ACL) {
+ struct tomoyo_path_acl *ptr =
+ container_of(acl, typeof(*ptr), head);
+ const u16 perm = ptr->perm;
+ for ( ; bit < TOMOYO_MAX_PATH_OPERATION; bit++) {
+ if (!(perm & (1 << bit)))
+ continue;
+ if (head->r.print_execute_only &&
+ bit != TOMOYO_TYPE_EXECUTE)
+ continue;
+ /* Print "read/write" instead of "read" and "write". */
+ if ((bit == TOMOYO_TYPE_READ ||
+ bit == TOMOYO_TYPE_WRITE)
+ && (perm & (1 << TOMOYO_TYPE_READ_WRITE)))
+ continue;
+ break;
+ }
+ if (bit >= TOMOYO_MAX_PATH_OPERATION)
+ goto done;
+ tomoyo_io_printf(head, "allow_%s", tomoyo_path_keyword[bit]);
+ tomoyo_print_name_union(head, &ptr->name);
+ } else if (head->r.print_execute_only) {
+ return true;
+ } else if (acl_type == TOMOYO_TYPE_PATH2_ACL) {
+ struct tomoyo_path2_acl *ptr =
+ container_of(acl, typeof(*ptr), head);
+ bit = tomoyo_fns(ptr->perm, bit);
+ if (bit >= TOMOYO_MAX_PATH2_OPERATION)
+ goto done;
+ tomoyo_io_printf(head, "allow_%s", tomoyo_path2_keyword[bit]);
+ tomoyo_print_name_union(head, &ptr->name1);
+ tomoyo_print_name_union(head, &ptr->name2);
+ } else if (acl_type == TOMOYO_TYPE_PATH_NUMBER_ACL) {
+ struct tomoyo_path_number_acl *ptr =
+ container_of(acl, typeof(*ptr), head);
+ bit = tomoyo_fns(ptr->perm, bit);
+ if (bit >= TOMOYO_MAX_PATH_NUMBER_OPERATION)
+ goto done;
+ tomoyo_io_printf(head, "allow_%s",
+ tomoyo_path_number_keyword[bit]);
+ tomoyo_print_name_union(head, &ptr->name);
+ tomoyo_print_number_union(head, &ptr->number);
+ } else if (acl_type == TOMOYO_TYPE_MKDEV_ACL) {
+ struct tomoyo_mkdev_acl *ptr =
+ container_of(acl, typeof(*ptr), head);
+ bit = tomoyo_fns(ptr->perm, bit);
+ if (bit >= TOMOYO_MAX_MKDEV_OPERATION)
+ goto done;
+ tomoyo_io_printf(head, "allow_%s", tomoyo_mkdev_keyword[bit]);
+ tomoyo_print_name_union(head, &ptr->name);
+ tomoyo_print_number_union(head, &ptr->mode);
+ tomoyo_print_number_union(head, &ptr->major);
+ tomoyo_print_number_union(head, &ptr->minor);
+ } else if (acl_type == TOMOYO_TYPE_MOUNT_ACL) {
+ struct tomoyo_mount_acl *ptr =
+ container_of(acl, typeof(*ptr), head);
+ tomoyo_io_printf(head, "allow_mount");
+ tomoyo_print_name_union(head, &ptr->dev_name);
+ tomoyo_print_name_union(head, &ptr->dir_name);
+ tomoyo_print_name_union(head, &ptr->fs_type);
+ tomoyo_print_number_union(head, &ptr->flags);
}
- head->read_bit = 0;
+ head->r.bit = bit + 1;
+ tomoyo_io_printf(head, "\n");
+ if (acl_type != TOMOYO_TYPE_MOUNT_ACL)
+ goto next;
+ done:
+ head->r.bit = 0;
return true;
- out:
- head->read_bit = bit;
- head->read_avail = pos;
- return false;
}
/**
- * tomoyo_print_entry - Print an ACL entry.
+ * tomoyo_read_domain2 - Read domain policy.
*
- * @head: Pointer to "struct tomoyo_io_buffer".
- * @ptr: Pointer to an ACL entry.
+ * @head: Pointer to "struct tomoyo_io_buffer".
+ * @domain: Pointer to "struct tomoyo_domain_info".
+ *
+ * Caller holds tomoyo_read_lock().
*
* Returns true on success, false otherwise.
*/
-static bool tomoyo_print_entry(struct tomoyo_io_buffer *head,
- struct tomoyo_acl_info *ptr)
+static bool tomoyo_read_domain2(struct tomoyo_io_buffer *head,
+ struct tomoyo_domain_info *domain)
{
- const u8 acl_type = ptr->type;
-
- if (acl_type == TOMOYO_TYPE_PATH_ACL) {
- struct tomoyo_path_acl *acl
- = container_of(ptr, struct tomoyo_path_acl, head);
- return tomoyo_print_path_acl(head, acl);
- }
- if (acl_type == TOMOYO_TYPE_PATH2_ACL) {
- struct tomoyo_path2_acl *acl
- = container_of(ptr, struct tomoyo_path2_acl, head);
- return tomoyo_print_path2_acl(head, acl);
+ list_for_each_cookie(head->r.acl, &domain->acl_info_list) {
+ struct tomoyo_acl_info *ptr =
+ list_entry(head->r.acl, typeof(*ptr), list);
+ if (!tomoyo_print_entry(head, ptr))
+ return false;
}
- BUG(); /* This must not happen. */
- return false;
+ head->r.acl = NULL;
+ return true;
}
/**
- * tomoyo_read_domain_policy - Read domain policy.
+ * tomoyo_read_domain - Read domain policy.
*
* @head: Pointer to "struct tomoyo_io_buffer".
*
- * Returns 0.
- *
* Caller holds tomoyo_read_lock().
*/
-static int tomoyo_read_domain_policy(struct tomoyo_io_buffer *head)
+static void tomoyo_read_domain(struct tomoyo_io_buffer *head)
{
- struct list_head *dpos;
- struct list_head *apos;
- bool done = true;
-
- if (head->read_eof)
- return 0;
- if (head->read_step == 0)
- head->read_step = 1;
- list_for_each_cookie(dpos, head->read_var1, &tomoyo_domain_list) {
- struct tomoyo_domain_info *domain;
- const char *quota_exceeded = "";
- const char *transition_failed = "";
- const char *ignore_global_allow_read = "";
- domain = list_entry(dpos, struct tomoyo_domain_info, list);
- if (head->read_step != 1)
- goto acl_loop;
- if (domain->is_deleted && !head->read_single_domain)
- continue;
- /* Print domainname and flags. */
- if (domain->quota_warned)
- quota_exceeded = "quota_exceeded\n";
- if (domain->transition_failed)
- transition_failed = "transition_failed\n";
- if (domain->ignore_global_allow_read)
- ignore_global_allow_read
- = TOMOYO_KEYWORD_IGNORE_GLOBAL_ALLOW_READ "\n";
- done = tomoyo_io_printf(head, "%s\n" TOMOYO_KEYWORD_USE_PROFILE
- "%u\n%s%s%s\n",
- domain->domainname->name,
- domain->profile, quota_exceeded,
- transition_failed,
- ignore_global_allow_read);
- if (!done)
- break;
- head->read_step = 2;
-acl_loop:
- if (head->read_step == 3)
- goto tail_mark;
- /* Print ACL entries in the domain. */
- list_for_each_cookie(apos, head->read_var2,
- &domain->acl_info_list) {
- struct tomoyo_acl_info *ptr
- = list_entry(apos, struct tomoyo_acl_info,
- list);
- done = tomoyo_print_entry(head, ptr);
- if (!done)
- break;
+ if (head->r.eof)
+ return;
+ list_for_each_cookie(head->r.domain, &tomoyo_domain_list) {
+ struct tomoyo_domain_info *domain =
+ list_entry(head->r.domain, typeof(*domain), list);
+ switch (head->r.step) {
+ case 0:
+ if (domain->is_deleted &&
+ !head->r.print_this_domain_only)
+ continue;
+ /* Print domainname and flags. */
+ tomoyo_set_string(head, domain->domainname->name);
+ tomoyo_set_lf(head);
+ tomoyo_io_printf(head,
+ TOMOYO_KEYWORD_USE_PROFILE "%u\n",
+ domain->profile);
+ if (domain->quota_warned)
+ tomoyo_set_string(head, "quota_exceeded\n");
+ if (domain->transition_failed)
+ tomoyo_set_string(head, "transition_failed\n");
+ if (domain->ignore_global_allow_read)
+ tomoyo_set_string(head,
+ TOMOYO_KEYWORD_IGNORE_GLOBAL_ALLOW_READ
+ "\n");
+ head->r.step++;
+ tomoyo_set_lf(head);
+ /* fall through */
+ case 1:
+ if (!tomoyo_read_domain2(head, domain))
+ return;
+ head->r.step++;
+ if (!tomoyo_set_lf(head))
+ return;
+ /* fall through */
+ case 2:
+ head->r.step = 0;
+ if (head->r.print_this_domain_only)
+ goto done;
}
- if (!done)
- break;
- head->read_step = 3;
-tail_mark:
- done = tomoyo_io_printf(head, "\n");
- if (!done)
- break;
- head->read_step = 1;
- if (head->read_single_domain)
- break;
}
- head->read_eof = done;
- return 0;
+ done:
+ head->r.eof = true;
}
/**
@@ -1607,7 +1080,7 @@ tail_mark:
* This is equivalent to doing
*
* ( echo "select " $domainname; echo "use_profile " $profile ) |
- * /usr/lib/ccs/loadpolicy -d
+ * /usr/sbin/tomoyo-loadpolicy -d
*
* Caller holds tomoyo_read_lock().
*/
@@ -1646,25 +1119,22 @@ static int tomoyo_write_domain_profile(struct tomoyo_io_buffer *head)
*
* Caller holds tomoyo_read_lock().
*/
-static int tomoyo_read_domain_profile(struct tomoyo_io_buffer *head)
+static void tomoyo_read_domain_profile(struct tomoyo_io_buffer *head)
{
- struct list_head *pos;
- bool done = true;
-
- if (head->read_eof)
- return 0;
- list_for_each_cookie(pos, head->read_var1, &tomoyo_domain_list) {
- struct tomoyo_domain_info *domain;
- domain = list_entry(pos, struct tomoyo_domain_info, list);
+ if (head->r.eof)
+ return;
+ list_for_each_cookie(head->r.domain, &tomoyo_domain_list) {
+ struct tomoyo_domain_info *domain =
+ list_entry(head->r.domain, typeof(*domain), list);
if (domain->is_deleted)
continue;
- done = tomoyo_io_printf(head, "%u %s\n", domain->profile,
- domain->domainname->name);
- if (!done)
- break;
+ if (!tomoyo_flush(head))
+ return;
+ tomoyo_io_printf(head, "%u ", domain->profile);
+ tomoyo_set_string(head, domain->domainname->name);
+ tomoyo_set_lf(head);
}
- head->read_eof = done;
- return 0;
+ head->r.eof = true;
}
/**
@@ -1676,11 +1146,7 @@ static int tomoyo_read_domain_profile(struct tomoyo_io_buffer *head)
*/
static int tomoyo_write_pid(struct tomoyo_io_buffer *head)
{
- unsigned long pid;
- /* No error check. */
- strict_strtoul(head->write_buf, 10, &pid);
- head->read_step = (int) pid;
- head->read_eof = false;
+ head->r.eof = false;
return 0;
}
@@ -1694,29 +1160,57 @@ static int tomoyo_write_pid(struct tomoyo_io_buffer *head)
* The PID is specified by tomoyo_write_pid() so that the user can obtain
* using read()/write() interface rather than sysctl() interface.
*/
-static int tomoyo_read_pid(struct tomoyo_io_buffer *head)
+static void tomoyo_read_pid(struct tomoyo_io_buffer *head)
{
- if (head->read_avail == 0 && !head->read_eof) {
- const int pid = head->read_step;
- struct task_struct *p;
- struct tomoyo_domain_info *domain = NULL;
- rcu_read_lock();
- read_lock(&tasklist_lock);
- p = find_task_by_vpid(pid);
- if (p)
- domain = tomoyo_real_domain(p);
- read_unlock(&tasklist_lock);
- rcu_read_unlock();
- if (domain)
- tomoyo_io_printf(head, "%d %u %s", pid, domain->profile,
- domain->domainname->name);
- head->read_eof = true;
+ char *buf = head->write_buf;
+ bool global_pid = false;
+ unsigned int pid;
+ struct task_struct *p;
+ struct tomoyo_domain_info *domain = NULL;
+
+ /* Accessing write_buf is safe because head->io_sem is held. */
+ if (!buf) {
+ head->r.eof = true;
+ return; /* Do nothing if open(O_RDONLY). */
}
- return 0;
+ if (head->r.w_pos || head->r.eof)
+ return;
+ head->r.eof = true;
+ if (tomoyo_str_starts(&buf, "global-pid "))
+ global_pid = true;
+ pid = (unsigned int) simple_strtoul(buf, NULL, 10);
+ rcu_read_lock();
+ read_lock(&tasklist_lock);
+ if (global_pid)
+ p = find_task_by_pid_ns(pid, &init_pid_ns);
+ else
+ p = find_task_by_vpid(pid);
+ if (p)
+ domain = tomoyo_real_domain(p);
+ read_unlock(&tasklist_lock);
+ rcu_read_unlock();
+ if (!domain)
+ return;
+ tomoyo_io_printf(head, "%u %u ", pid, domain->profile);
+ tomoyo_set_string(head, domain->domainname->name);
}
+static const char *tomoyo_transition_type[TOMOYO_MAX_TRANSITION_TYPE] = {
+ [TOMOYO_TRANSITION_CONTROL_NO_INITIALIZE]
+ = TOMOYO_KEYWORD_NO_INITIALIZE_DOMAIN,
+ [TOMOYO_TRANSITION_CONTROL_INITIALIZE]
+ = TOMOYO_KEYWORD_INITIALIZE_DOMAIN,
+ [TOMOYO_TRANSITION_CONTROL_NO_KEEP] = TOMOYO_KEYWORD_NO_KEEP_DOMAIN,
+ [TOMOYO_TRANSITION_CONTROL_KEEP] = TOMOYO_KEYWORD_KEEP_DOMAIN
+};
+
+static const char *tomoyo_group_name[TOMOYO_MAX_GROUP] = {
+ [TOMOYO_PATH_GROUP] = TOMOYO_KEYWORD_PATH_GROUP,
+ [TOMOYO_NUMBER_GROUP] = TOMOYO_KEYWORD_NUMBER_GROUP
+};
+
/**
- * tomoyo_write_exception_policy - Write exception policy.
+ * tomoyo_write_exception - Write exception policy.
*
* @head: Pointer to "struct tomoyo_io_buffer".
*
@@ -1724,186 +1218,523 @@ static int tomoyo_read_pid(struct tomoyo_io_buffer *head)
*
* Caller holds tomoyo_read_lock().
*/
-static int tomoyo_write_exception_policy(struct tomoyo_io_buffer *head)
+static int tomoyo_write_exception(struct tomoyo_io_buffer *head)
{
char *data = head->write_buf;
bool is_delete = tomoyo_str_starts(&data, TOMOYO_KEYWORD_DELETE);
-
- if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_KEEP_DOMAIN))
- return tomoyo_write_domain_keeper_policy(data, false,
- is_delete);
- if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_NO_KEEP_DOMAIN))
- return tomoyo_write_domain_keeper_policy(data, true, is_delete);
- if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_INITIALIZE_DOMAIN))
- return tomoyo_write_domain_initializer_policy(data, false,
- is_delete);
- if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_NO_INITIALIZE_DOMAIN))
- return tomoyo_write_domain_initializer_policy(data, true,
- is_delete);
- if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_ALIAS))
- return tomoyo_write_alias_policy(data, is_delete);
- if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_ALLOW_READ))
- return tomoyo_write_globally_readable_policy(data, is_delete);
- if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_FILE_PATTERN))
- return tomoyo_write_pattern_policy(data, is_delete);
- if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_DENY_REWRITE))
- return tomoyo_write_no_rewrite_policy(data, is_delete);
- if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_PATH_GROUP))
- return tomoyo_write_path_group_policy(data, is_delete);
+ u8 i;
+ static const struct {
+ const char *keyword;
+ int (*write) (char *, const bool);
+ } tomoyo_callback[4] = {
+ { TOMOYO_KEYWORD_AGGREGATOR, tomoyo_write_aggregator },
+ { TOMOYO_KEYWORD_FILE_PATTERN, tomoyo_write_pattern },
+ { TOMOYO_KEYWORD_DENY_REWRITE, tomoyo_write_no_rewrite },
+ { TOMOYO_KEYWORD_ALLOW_READ, tomoyo_write_globally_readable },
+ };
+
+ for (i = 0; i < TOMOYO_MAX_TRANSITION_TYPE; i++)
+ if (tomoyo_str_starts(&data, tomoyo_transition_type[i]))
+ return tomoyo_write_transition_control(data, is_delete,
+ i);
+ for (i = 0; i < 4; i++)
+ if (tomoyo_str_starts(&data, tomoyo_callback[i].keyword))
+ return tomoyo_callback[i].write(data, is_delete);
+ for (i = 0; i < TOMOYO_MAX_GROUP; i++)
+ if (tomoyo_str_starts(&data, tomoyo_group_name[i]))
+ return tomoyo_write_group(data, is_delete, i);
return -EINVAL;
}
/**
- * tomoyo_read_exception_policy - Read exception policy.
+ * tomoyo_read_group - Read "struct tomoyo_path_group"/"struct tomoyo_number_group" list.
*
* @head: Pointer to "struct tomoyo_io_buffer".
+ * @idx: Index number.
*
- * Returns 0 on success, -EINVAL otherwise.
+ * Returns true on success, false otherwise.
*
* Caller holds tomoyo_read_lock().
*/
-static int tomoyo_read_exception_policy(struct tomoyo_io_buffer *head)
+static bool tomoyo_read_group(struct tomoyo_io_buffer *head, const int idx)
{
- if (!head->read_eof) {
- switch (head->read_step) {
- case 0:
- head->read_var2 = NULL;
- head->read_step = 1;
- case 1:
- if (!tomoyo_read_domain_keeper_policy(head))
- break;
- head->read_var2 = NULL;
- head->read_step = 2;
- case 2:
- if (!tomoyo_read_globally_readable_policy(head))
- break;
- head->read_var2 = NULL;
- head->read_step = 3;
- case 3:
- head->read_var2 = NULL;
- head->read_step = 4;
- case 4:
- if (!tomoyo_read_domain_initializer_policy(head))
- break;
- head->read_var2 = NULL;
- head->read_step = 5;
- case 5:
- if (!tomoyo_read_alias_policy(head))
- break;
- head->read_var2 = NULL;
- head->read_step = 6;
- case 6:
- head->read_var2 = NULL;
- head->read_step = 7;
- case 7:
- if (!tomoyo_read_file_pattern(head))
- break;
- head->read_var2 = NULL;
- head->read_step = 8;
- case 8:
- if (!tomoyo_read_no_rewrite_policy(head))
- break;
- head->read_var2 = NULL;
- head->read_step = 9;
- case 9:
- if (!tomoyo_read_path_group_policy(head))
- break;
- head->read_var1 = NULL;
- head->read_var2 = NULL;
- head->read_step = 10;
- case 10:
- head->read_eof = true;
+ list_for_each_cookie(head->r.group, &tomoyo_group_list[idx]) {
+ struct tomoyo_group *group =
+ list_entry(head->r.group, typeof(*group), list);
+ list_for_each_cookie(head->r.acl, &group->member_list) {
+ struct tomoyo_acl_head *ptr =
+ list_entry(head->r.acl, typeof(*ptr), list);
+ if (ptr->is_deleted)
+ continue;
+ if (!tomoyo_flush(head))
+ return false;
+ tomoyo_set_string(head, tomoyo_group_name[idx]);
+ tomoyo_set_string(head, group->group_name->name);
+ if (idx == TOMOYO_PATH_GROUP) {
+ tomoyo_set_space(head);
+ tomoyo_set_string(head, container_of
+ (ptr, struct tomoyo_path_group,
+ head)->member_name->name);
+ } else if (idx == TOMOYO_NUMBER_GROUP) {
+ tomoyo_print_number_union(head, &container_of
+ (ptr,
+ struct tomoyo_number_group,
+ head)->number);
+ }
+ tomoyo_set_lf(head);
+ }
+ head->r.acl = NULL;
+ }
+ head->r.group = NULL;
+ return true;
+}
+
+/**
+ * tomoyo_read_policy - Read "struct tomoyo_..._entry" list.
+ *
+ * @head: Pointer to "struct tomoyo_io_buffer".
+ * @idx: Index number.
+ *
+ * Returns true on success, false otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
+ */
+static bool tomoyo_read_policy(struct tomoyo_io_buffer *head, const int idx)
+{
+ list_for_each_cookie(head->r.acl, &tomoyo_policy_list[idx]) {
+ struct tomoyo_acl_head *acl =
+ container_of(head->r.acl, typeof(*acl), list);
+ if (acl->is_deleted)
+ continue;
+ if (!tomoyo_flush(head))
+ return false;
+ switch (idx) {
+ case TOMOYO_ID_TRANSITION_CONTROL:
+ {
+ struct tomoyo_transition_control *ptr =
+ container_of(acl, typeof(*ptr), head);
+ tomoyo_set_string(head,
+ tomoyo_transition_type
+ [ptr->type]);
+ if (ptr->program)
+ tomoyo_set_string(head,
+ ptr->program->name);
+ if (ptr->program && ptr->domainname)
+ tomoyo_set_string(head, " from ");
+ if (ptr->domainname)
+ tomoyo_set_string(head,
+ ptr->domainname->
+ name);
+ }
+ break;
+ case TOMOYO_ID_GLOBALLY_READABLE:
+ {
+ struct tomoyo_readable_file *ptr =
+ container_of(acl, typeof(*ptr), head);
+ tomoyo_set_string(head,
+ TOMOYO_KEYWORD_ALLOW_READ);
+ tomoyo_set_string(head, ptr->filename->name);
+ }
+ break;
+ case TOMOYO_ID_AGGREGATOR:
+ {
+ struct tomoyo_aggregator *ptr =
+ container_of(acl, typeof(*ptr), head);
+ tomoyo_set_string(head,
+ TOMOYO_KEYWORD_AGGREGATOR);
+ tomoyo_set_string(head,
+ ptr->original_name->name);
+ tomoyo_set_space(head);
+ tomoyo_set_string(head,
+ ptr->aggregated_name->name);
+ }
+ break;
+ case TOMOYO_ID_PATTERN:
+ {
+ struct tomoyo_no_pattern *ptr =
+ container_of(acl, typeof(*ptr), head);
+ tomoyo_set_string(head,
+ TOMOYO_KEYWORD_FILE_PATTERN);
+ tomoyo_set_string(head, ptr->pattern->name);
+ }
+ break;
+ case TOMOYO_ID_NO_REWRITE:
+ {
+ struct tomoyo_no_rewrite *ptr =
+ container_of(acl, typeof(*ptr), head);
+ tomoyo_set_string(head,
+ TOMOYO_KEYWORD_DENY_REWRITE);
+ tomoyo_set_string(head, ptr->pattern->name);
+ }
break;
default:
- return -EINVAL;
+ continue;
}
+ tomoyo_set_lf(head);
}
- return 0;
+ head->r.acl = NULL;
+ return true;
}
-/* path to policy loader */
-static const char *tomoyo_loader = "/sbin/tomoyo-init";
+/**
+ * tomoyo_read_exception - Read exception policy.
+ *
+ * @head: Pointer to "struct tomoyo_io_buffer".
+ *
+ * Caller holds tomoyo_read_lock().
+ */
+static void tomoyo_read_exception(struct tomoyo_io_buffer *head)
+{
+ if (head->r.eof)
+ return;
+ while (head->r.step < TOMOYO_MAX_POLICY &&
+ tomoyo_read_policy(head, head->r.step))
+ head->r.step++;
+ if (head->r.step < TOMOYO_MAX_POLICY)
+ return;
+ while (head->r.step < TOMOYO_MAX_POLICY + TOMOYO_MAX_GROUP &&
+ tomoyo_read_group(head, head->r.step - TOMOYO_MAX_POLICY))
+ head->r.step++;
+ if (head->r.step < TOMOYO_MAX_POLICY + TOMOYO_MAX_GROUP)
+ return;
+ head->r.eof = true;
+}
/**
- * tomoyo_policy_loader_exists - Check whether /sbin/tomoyo-init exists.
+ * tomoyo_print_header - Get header line of audit log.
+ *
+ * @r: Pointer to "struct tomoyo_request_info".
*
- * Returns true if /sbin/tomoyo-init exists, false otherwise.
+ * Returns string representation.
+ *
+ * This function uses kmalloc(), so caller must kfree() if this function
+ * didn't return NULL.
*/
-static bool tomoyo_policy_loader_exists(void)
+static char *tomoyo_print_header(struct tomoyo_request_info *r)
{
- /*
- * Don't activate MAC if the policy loader doesn't exist.
- * If the initrd includes /sbin/init but real-root-dev has not
- * mounted on / yet, activating MAC will block the system since
- * policies are not loaded yet.
- * Thus, let do_execve() call this function everytime.
- */
- struct path path;
+ struct timeval tv;
+ const pid_t gpid = task_pid_nr(current);
+ static const int tomoyo_buffer_len = 4096;
+ char *buffer = kmalloc(tomoyo_buffer_len, GFP_NOFS);
+ if (!buffer)
+ return NULL;
+ do_gettimeofday(&tv);
+ snprintf(buffer, tomoyo_buffer_len - 1,
+ "#timestamp=%lu profile=%u mode=%s (global-pid=%u)"
+ " task={ pid=%u ppid=%u uid=%u gid=%u euid=%u"
+ " egid=%u suid=%u sgid=%u fsuid=%u fsgid=%u }",
+ tv.tv_sec, r->profile, tomoyo_mode[r->mode], gpid,
+ (pid_t) sys_getpid(), (pid_t) sys_getppid(),
+ current_uid(), current_gid(), current_euid(),
+ current_egid(), current_suid(), current_sgid(),
+ current_fsuid(), current_fsgid());
+ return buffer;
+}
- if (kern_path(tomoyo_loader, LOOKUP_FOLLOW, &path)) {
- printk(KERN_INFO "Not activating Mandatory Access Control now "
- "since %s doesn't exist.\n", tomoyo_loader);
- return false;
+/**
+ * tomoyo_init_audit_log - Allocate buffer for audit logs.
+ *
+ * @len: Required size.
+ * @r: Pointer to "struct tomoyo_request_info".
+ *
+ * Returns pointer to allocated memory.
+ *
+ * The @len is updated to add the header lines' size on success.
+ *
+ * This function uses kzalloc(), so caller must kfree() if this function
+ * didn't return NULL.
+ */
+static char *tomoyo_init_audit_log(int *len, struct tomoyo_request_info *r)
+{
+ char *buf = NULL;
+ const char *header;
+ const char *domainname;
+ if (!r->domain)
+ r->domain = tomoyo_domain();
+ domainname = r->domain->domainname->name;
+ header = tomoyo_print_header(r);
+ if (!header)
+ return NULL;
+ *len += strlen(domainname) + strlen(header) + 10;
+ buf = kzalloc(*len, GFP_NOFS);
+ if (buf)
+ snprintf(buf, (*len) - 1, "%s\n%s\n", header, domainname);
+ kfree(header);
+ return buf;
+}
+
+/* Wait queue for tomoyo_query_list. */
+static DECLARE_WAIT_QUEUE_HEAD(tomoyo_query_wait);
+
+/* Lock for manipulating tomoyo_query_list. */
+static DEFINE_SPINLOCK(tomoyo_query_list_lock);
+
+/* Structure for query. */
+struct tomoyo_query {
+ struct list_head list;
+ char *query;
+ int query_len;
+ unsigned int serial;
+ int timer;
+ int answer;
+};
+
+/* The list for "struct tomoyo_query". */
+static LIST_HEAD(tomoyo_query_list);
+
+/*
+ * Number of "struct file" referring /sys/kernel/security/tomoyo/query
+ * interface.
+ */
+static atomic_t tomoyo_query_observers = ATOMIC_INIT(0);
+
+/**
+ * tomoyo_supervisor - Ask for the supervisor's decision.
+ *
+ * @r: Pointer to "struct tomoyo_request_info".
+ * @fmt: The printf()'s format string, followed by parameters.
+ *
+ * Returns 0 if the supervisor decided to permit the access request which
+ * violated the policy in enforcing mode, TOMOYO_RETRY_REQUEST if the
+ * supervisor decided to retry the access request which violated the policy in
+ * enforcing mode, 0 if it is not in enforcing mode, -EPERM otherwise.
+ */
+int tomoyo_supervisor(struct tomoyo_request_info *r, const char *fmt, ...)
+{
+ va_list args;
+ int error = -EPERM;
+ int pos;
+ int len;
+ static unsigned int tomoyo_serial;
+ struct tomoyo_query *entry = NULL;
+ bool quota_exceeded = false;
+ char *header;
+ switch (r->mode) {
+ char *buffer;
+ case TOMOYO_CONFIG_LEARNING:
+ if (!tomoyo_domain_quota_is_ok(r))
+ return 0;
+ va_start(args, fmt);
+ len = vsnprintf((char *) &pos, sizeof(pos) - 1, fmt, args) + 4;
+ va_end(args);
+ buffer = kmalloc(len, GFP_NOFS);
+ if (!buffer)
+ return 0;
+ va_start(args, fmt);
+ vsnprintf(buffer, len - 1, fmt, args);
+ va_end(args);
+ tomoyo_normalize_line(buffer);
+ tomoyo_write_domain2(buffer, r->domain, false);
+ kfree(buffer);
+ /* fall through */
+ case TOMOYO_CONFIG_PERMISSIVE:
+ return 0;
}
- path_put(&path);
- return true;
+ if (!r->domain)
+ r->domain = tomoyo_domain();
+ if (!atomic_read(&tomoyo_query_observers))
+ return -EPERM;
+ va_start(args, fmt);
+ len = vsnprintf((char *) &pos, sizeof(pos) - 1, fmt, args) + 32;
+ va_end(args);
+ header = tomoyo_init_audit_log(&len, r);
+ if (!header)
+ goto out;
+ entry = kzalloc(sizeof(*entry), GFP_NOFS);
+ if (!entry)
+ goto out;
+ entry->query = kzalloc(len, GFP_NOFS);
+ if (!entry->query)
+ goto out;
+ len = ksize(entry->query);
+ spin_lock(&tomoyo_query_list_lock);
+ if (tomoyo_quota_for_query && tomoyo_query_memory_size + len +
+ sizeof(*entry) >= tomoyo_quota_for_query) {
+ quota_exceeded = true;
+ } else {
+ tomoyo_query_memory_size += len + sizeof(*entry);
+ entry->serial = tomoyo_serial++;
+ }
+ spin_unlock(&tomoyo_query_list_lock);
+ if (quota_exceeded)
+ goto out;
+ pos = snprintf(entry->query, len - 1, "Q%u-%hu\n%s",
+ entry->serial, r->retry, header);
+ kfree(header);
+ header = NULL;
+ va_start(args, fmt);
+ vsnprintf(entry->query + pos, len - 1 - pos, fmt, args);
+ entry->query_len = strlen(entry->query) + 1;
+ va_end(args);
+ spin_lock(&tomoyo_query_list_lock);
+ list_add_tail(&entry->list, &tomoyo_query_list);
+ spin_unlock(&tomoyo_query_list_lock);
+ /* Give 10 seconds for supervisor's opinion. */
+ for (entry->timer = 0;
+ atomic_read(&tomoyo_query_observers) && entry->timer < 100;
+ entry->timer++) {
+ wake_up(&tomoyo_query_wait);
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule_timeout(HZ / 10);
+ if (entry->answer)
+ break;
+ }
+ spin_lock(&tomoyo_query_list_lock);
+ list_del(&entry->list);
+ tomoyo_query_memory_size -= len + sizeof(*entry);
+ spin_unlock(&tomoyo_query_list_lock);
+ switch (entry->answer) {
+ case 3: /* Asked to retry by administrator. */
+ error = TOMOYO_RETRY_REQUEST;
+ r->retry++;
+ break;
+ case 1:
+ /* Granted by administrator. */
+ error = 0;
+ break;
+ case 0:
+ /* Timed out. */
+ break;
+ default:
+ /* Rejected by administrator. */
+ break;
+ }
+ out:
+ if (entry)
+ kfree(entry->query);
+ kfree(entry);
+ kfree(header);
+ return error;
}
/**
- * tomoyo_load_policy - Run external policy loader to load policy.
+ * tomoyo_poll_query - poll() for /sys/kernel/security/tomoyo/query.
*
- * @filename: The program about to start.
+ * @file: Pointer to "struct file".
+ * @wait: Pointer to "poll_table".
*
- * This function checks whether @filename is /sbin/init , and if so
- * invoke /sbin/tomoyo-init and wait for the termination of /sbin/tomoyo-init
- * and then continues invocation of /sbin/init.
- * /sbin/tomoyo-init reads policy files in /etc/tomoyo/ directory and
- * writes to /sys/kernel/security/tomoyo/ interfaces.
+ * Returns POLLIN | POLLRDNORM when ready to read, 0 otherwise.
*
- * Returns nothing.
+ * Waits for access requests which violated policy in enforcing mode.
*/
-void tomoyo_load_policy(const char *filename)
+static int tomoyo_poll_query(struct file *file, poll_table *wait)
{
- char *argv[2];
- char *envp[3];
+ struct list_head *tmp;
+ bool found = false;
+ u8 i;
+ for (i = 0; i < 2; i++) {
+ spin_lock(&tomoyo_query_list_lock);
+ list_for_each(tmp, &tomoyo_query_list) {
+ struct tomoyo_query *ptr =
+ list_entry(tmp, typeof(*ptr), list);
+ if (ptr->answer)
+ continue;
+ found = true;
+ break;
+ }
+ spin_unlock(&tomoyo_query_list_lock);
+ if (found)
+ return POLLIN | POLLRDNORM;
+ if (i)
+ break;
+ poll_wait(file, &tomoyo_query_wait, wait);
+ }
+ return 0;
+}
- if (tomoyo_policy_loaded)
+/**
+ * tomoyo_read_query - Read access requests which violated policy in enforcing mode.
+ *
+ * @head: Pointer to "struct tomoyo_io_buffer".
+ */
+static void tomoyo_read_query(struct tomoyo_io_buffer *head)
+{
+ struct list_head *tmp;
+ int pos = 0;
+ int len = 0;
+ char *buf;
+ if (head->r.w_pos)
return;
- /*
- * Check filename is /sbin/init or /sbin/tomoyo-start.
- * /sbin/tomoyo-start is a dummy filename in case where /sbin/init can't
- * be passed.
- * You can create /sbin/tomoyo-start by
- * "ln -s /bin/true /sbin/tomoyo-start".
- */
- if (strcmp(filename, "/sbin/init") &&
- strcmp(filename, "/sbin/tomoyo-start"))
+ if (head->read_buf) {
+ kfree(head->read_buf);
+ head->read_buf = NULL;
+ }
+ spin_lock(&tomoyo_query_list_lock);
+ list_for_each(tmp, &tomoyo_query_list) {
+ struct tomoyo_query *ptr = list_entry(tmp, typeof(*ptr), list);
+ if (ptr->answer)
+ continue;
+ if (pos++ != head->r.query_index)
+ continue;
+ len = ptr->query_len;
+ break;
+ }
+ spin_unlock(&tomoyo_query_list_lock);
+ if (!len) {
+ head->r.query_index = 0;
return;
- if (!tomoyo_policy_loader_exists())
+ }
+ buf = kzalloc(len, GFP_NOFS);
+ if (!buf)
return;
+ pos = 0;
+ spin_lock(&tomoyo_query_list_lock);
+ list_for_each(tmp, &tomoyo_query_list) {
+ struct tomoyo_query *ptr = list_entry(tmp, typeof(*ptr), list);
+ if (ptr->answer)
+ continue;
+ if (pos++ != head->r.query_index)
+ continue;
+ /*
+ * Some query can be skipped because tomoyo_query_list
+ * can change, but I don't care.
+ */
+ if (len == ptr->query_len)
+ memmove(buf, ptr->query, len);
+ break;
+ }
+ spin_unlock(&tomoyo_query_list_lock);
+ if (buf[0]) {
+ head->read_buf = buf;
+ head->r.w[head->r.w_pos++] = buf;
+ head->r.query_index++;
+ } else {
+ kfree(buf);
+ }
+}
- printk(KERN_INFO "Calling %s to load policy. Please wait.\n",
- tomoyo_loader);
- argv[0] = (char *) tomoyo_loader;
- argv[1] = NULL;
- envp[0] = "HOME=/";
- envp[1] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";
- envp[2] = NULL;
- call_usermodehelper(argv[0], argv, envp, 1);
-
- printk(KERN_INFO "TOMOYO: 2.2.0 2009/04/01\n");
- printk(KERN_INFO "Mandatory Access Control activated.\n");
- tomoyo_policy_loaded = true;
- { /* Check all profiles currently assigned to domains are defined. */
- struct tomoyo_domain_info *domain;
- list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) {
- const u8 profile = domain->profile;
- if (tomoyo_profile_ptr[profile])
- continue;
- panic("Profile %u (used by '%s') not defined.\n",
- profile, domain->domainname->name);
- }
+/**
+ * tomoyo_write_answer - Write the supervisor's decision.
+ *
+ * @head: Pointer to "struct tomoyo_io_buffer".
+ *
+ * Returns 0 on success, -EINVAL otherwise.
+ */
+static int tomoyo_write_answer(struct tomoyo_io_buffer *head)
+{
+ char *data = head->write_buf;
+ struct list_head *tmp;
+ unsigned int serial;
+ unsigned int answer;
+ spin_lock(&tomoyo_query_list_lock);
+ list_for_each(tmp, &tomoyo_query_list) {
+ struct tomoyo_query *ptr = list_entry(tmp, typeof(*ptr), list);
+ ptr->timer = 0;
+ }
+ spin_unlock(&tomoyo_query_list_lock);
+ if (sscanf(data, "A%u=%u", &serial, &answer) != 2)
+ return -EINVAL;
+ spin_lock(&tomoyo_query_list_lock);
+ list_for_each(tmp, &tomoyo_query_list) {
+ struct tomoyo_query *ptr = list_entry(tmp, typeof(*ptr), list);
+ if (ptr->serial != serial)
+ continue;
+ if (!ptr->answer)
+ ptr->answer = answer;
+ break;
}
+ spin_unlock(&tomoyo_query_list_lock);
+ return 0;
}
/**
@@ -1913,13 +1744,12 @@ void tomoyo_load_policy(const char *filename)
*
* Returns version information.
*/
-static int tomoyo_read_version(struct tomoyo_io_buffer *head)
+static void tomoyo_read_version(struct tomoyo_io_buffer *head)
{
- if (!head->read_eof) {
- tomoyo_io_printf(head, "2.2.0");
- head->read_eof = true;
+ if (!head->r.eof) {
+ tomoyo_io_printf(head, "2.3.0");
+ head->r.eof = true;
}
- return 0;
}
/**
@@ -1929,18 +1759,17 @@ static int tomoyo_read_version(struct tomoyo_io_buffer *head)
*
* Returns the current process's domainname.
*/
-static int tomoyo_read_self_domain(struct tomoyo_io_buffer *head)
+static void tomoyo_read_self_domain(struct tomoyo_io_buffer *head)
{
- if (!head->read_eof) {
+ if (!head->r.eof) {
/*
* tomoyo_domain()->domainname != NULL
* because every process belongs to a domain and
* the domain's name cannot be NULL.
*/
tomoyo_io_printf(head, "%s", tomoyo_domain()->domainname->name);
- head->read_eof = true;
+ head->r.eof = true;
}
- return 0;
}
/**
@@ -1953,23 +1782,24 @@ static int tomoyo_read_self_domain(struct tomoyo_io_buffer *head)
*
* Caller acquires tomoyo_read_lock().
*/
-static int tomoyo_open_control(const u8 type, struct file *file)
+int tomoyo_open_control(const u8 type, struct file *file)
{
struct tomoyo_io_buffer *head = kzalloc(sizeof(*head), GFP_NOFS);
if (!head)
return -ENOMEM;
mutex_init(&head->io_sem);
+ head->type = type;
switch (type) {
case TOMOYO_DOMAINPOLICY:
/* /sys/kernel/security/tomoyo/domain_policy */
- head->write = tomoyo_write_domain_policy;
- head->read = tomoyo_read_domain_policy;
+ head->write = tomoyo_write_domain;
+ head->read = tomoyo_read_domain;
break;
case TOMOYO_EXCEPTIONPOLICY:
/* /sys/kernel/security/tomoyo/exception_policy */
- head->write = tomoyo_write_exception_policy;
- head->read = tomoyo_read_exception_policy;
+ head->write = tomoyo_write_exception;
+ head->read = tomoyo_read_exception;
break;
case TOMOYO_SELFDOMAIN:
/* /sys/kernel/security/tomoyo/self_domain */
@@ -2001,10 +1831,15 @@ static int tomoyo_open_control(const u8 type, struct file *file)
head->write = tomoyo_write_profile;
head->read = tomoyo_read_profile;
break;
+ case TOMOYO_QUERY: /* /sys/kernel/security/tomoyo/query */
+ head->poll = tomoyo_poll_query;
+ head->write = tomoyo_write_answer;
+ head->read = tomoyo_read_query;
+ break;
case TOMOYO_MANAGER:
/* /sys/kernel/security/tomoyo/manager */
- head->write = tomoyo_write_manager_policy;
- head->read = tomoyo_read_manager_policy;
+ head->write = tomoyo_write_manager;
+ head->read = tomoyo_read_manager;
break;
}
if (!(file->f_mode & FMODE_READ)) {
@@ -2013,7 +1848,9 @@ static int tomoyo_open_control(const u8 type, struct file *file)
* for reading.
*/
head->read = NULL;
- } else {
+ head->poll = NULL;
+ } else if (!head->poll) {
+ /* Don't allocate read_buf for poll() access. */
if (!head->readbuf_size)
head->readbuf_size = 4096 * 2;
head->read_buf = kzalloc(head->readbuf_size, GFP_NOFS);
@@ -2037,7 +1874,8 @@ static int tomoyo_open_control(const u8 type, struct file *file)
return -ENOMEM;
}
}
- head->reader_idx = tomoyo_read_lock();
+ if (type != TOMOYO_QUERY)
+ head->reader_idx = tomoyo_read_lock();
file->private_data = head;
/*
* Call the handler now if the file is
@@ -2048,10 +1886,35 @@ static int tomoyo_open_control(const u8 type, struct file *file)
*/
if (type == TOMOYO_SELFDOMAIN)
tomoyo_read_control(file, NULL, 0);
+ /*
+ * If the file is /sys/kernel/security/tomoyo/query , increment the
+ * observer counter.
+ * The obserber counter is used by tomoyo_supervisor() to see if
+ * there is some process monitoring /sys/kernel/security/tomoyo/query.
+ */
+ else if (type == TOMOYO_QUERY)
+ atomic_inc(&tomoyo_query_observers);
return 0;
}
/**
+ * tomoyo_poll_control - poll() for /sys/kernel/security/tomoyo/ interface.
+ *
+ * @file: Pointer to "struct file".
+ * @wait: Pointer to "poll_table".
+ *
+ * Waits for read readiness.
+ * /sys/kernel/security/tomoyo/query is handled by /usr/sbin/tomoyo-queryd .
+ */
+int tomoyo_poll_control(struct file *file, poll_table *wait)
+{
+ struct tomoyo_io_buffer *head = file->private_data;
+ if (!head->poll)
+ return -ENOSYS;
+ return head->poll(file, wait);
+}
+
+/**
* tomoyo_read_control - read() for /sys/kernel/security/tomoyo/ interface.
*
* @file: Pointer to "struct file".
@@ -2062,36 +1925,23 @@ static int tomoyo_open_control(const u8 type, struct file *file)
*
* Caller holds tomoyo_read_lock().
*/
-static int tomoyo_read_control(struct file *file, char __user *buffer,
- const int buffer_len)
+int tomoyo_read_control(struct file *file, char __user *buffer,
+ const int buffer_len)
{
- int len = 0;
+ int len;
struct tomoyo_io_buffer *head = file->private_data;
- char *cp;
if (!head->read)
return -ENOSYS;
if (mutex_lock_interruptible(&head->io_sem))
return -EINTR;
- /* Call the policy handler. */
- len = head->read(head);
- if (len < 0)
- goto out;
- /* Write to buffer. */
- len = head->read_avail;
- if (len > buffer_len)
- len = buffer_len;
- if (!len)
- goto out;
- /* head->read_buf changes by some functions. */
- cp = head->read_buf;
- if (copy_to_user(buffer, cp, len)) {
- len = -EFAULT;
- goto out;
- }
- head->read_avail -= len;
- memmove(cp, cp + len, head->read_avail);
- out:
+ head->read_user_buf = buffer;
+ head->read_user_buf_avail = buffer_len;
+ if (tomoyo_flush(head))
+ /* Call the policy handler. */
+ head->read(head);
+ tomoyo_flush(head);
+ len = head->read_user_buf - buffer;
mutex_unlock(&head->io_sem);
return len;
}
@@ -2107,8 +1957,8 @@ static int tomoyo_read_control(struct file *file, char __user *buffer,
*
* Caller holds tomoyo_read_lock().
*/
-static int tomoyo_write_control(struct file *file, const char __user *buffer,
- const int buffer_len)
+int tomoyo_write_control(struct file *file, const char __user *buffer,
+ const int buffer_len)
{
struct tomoyo_io_buffer *head = file->private_data;
int error = buffer_len;
@@ -2121,8 +1971,7 @@ static int tomoyo_write_control(struct file *file, const char __user *buffer,
return -EFAULT;
/* Don't allow updating policies by non manager programs. */
if (head->write != tomoyo_write_pid &&
- head->write != tomoyo_write_domain_policy &&
- !tomoyo_is_policy_manager())
+ head->write != tomoyo_write_domain && !tomoyo_manager())
return -EPERM;
if (mutex_lock_interruptible(&head->io_sem))
return -EINTR;
@@ -2159,12 +2008,19 @@ static int tomoyo_write_control(struct file *file, const char __user *buffer,
*
* Caller looses tomoyo_read_lock().
*/
-static int tomoyo_close_control(struct file *file)
+int tomoyo_close_control(struct file *file)
{
struct tomoyo_io_buffer *head = file->private_data;
const bool is_write = !!head->write_buf;
- tomoyo_read_unlock(head->reader_idx);
+ /*
+ * If the file is /sys/kernel/security/tomoyo/query , decrement the
+ * observer counter.
+ */
+ if (head->type == TOMOYO_QUERY)
+ atomic_dec(&tomoyo_query_observers);
+ else
+ tomoyo_read_unlock(head->reader_idx);
/* Release memory used for policy I/O. */
kfree(head->read_buf);
head->read_buf = NULL;
@@ -2179,129 +2035,25 @@ static int tomoyo_close_control(struct file *file)
}
/**
- * tomoyo_open - open() for /sys/kernel/security/tomoyo/ interface.
- *
- * @inode: Pointer to "struct inode".
- * @file: Pointer to "struct file".
- *
- * Returns 0 on success, negative value otherwise.
- */
-static int tomoyo_open(struct inode *inode, struct file *file)
-{
- const int key = ((u8 *) file->f_path.dentry->d_inode->i_private)
- - ((u8 *) NULL);
- return tomoyo_open_control(key, file);
-}
-
-/**
- * tomoyo_release - close() for /sys/kernel/security/tomoyo/ interface.
- *
- * @inode: Pointer to "struct inode".
- * @file: Pointer to "struct file".
- *
- * Returns 0 on success, negative value otherwise.
- */
-static int tomoyo_release(struct inode *inode, struct file *file)
-{
- return tomoyo_close_control(file);
-}
-
-/**
- * tomoyo_read - read() for /sys/kernel/security/tomoyo/ interface.
- *
- * @file: Pointer to "struct file".
- * @buf: Pointer to buffer.
- * @count: Size of @buf.
- * @ppos: Unused.
- *
- * Returns bytes read on success, negative value otherwise.
+ * tomoyo_check_profile - Check all profiles currently assigned to domains are defined.
*/
-static ssize_t tomoyo_read(struct file *file, char __user *buf, size_t count,
- loff_t *ppos)
+void tomoyo_check_profile(void)
{
- return tomoyo_read_control(file, buf, count);
-}
-
-/**
- * tomoyo_write - write() for /sys/kernel/security/tomoyo/ interface.
- *
- * @file: Pointer to "struct file".
- * @buf: Pointer to buffer.
- * @count: Size of @buf.
- * @ppos: Unused.
- *
- * Returns @count on success, negative value otherwise.
- */
-static ssize_t tomoyo_write(struct file *file, const char __user *buf,
- size_t count, loff_t *ppos)
-{
- return tomoyo_write_control(file, buf, count);
-}
-
-/*
- * tomoyo_operations is a "struct file_operations" which is used for handling
- * /sys/kernel/security/tomoyo/ interface.
- *
- * Some files under /sys/kernel/security/tomoyo/ directory accept open(O_RDWR).
- * See tomoyo_io_buffer for internals.
- */
-static const struct file_operations tomoyo_operations = {
- .open = tomoyo_open,
- .release = tomoyo_release,
- .read = tomoyo_read,
- .write = tomoyo_write,
-};
-
-/**
- * tomoyo_create_entry - Create interface files under /sys/kernel/security/tomoyo/ directory.
- *
- * @name: The name of the interface file.
- * @mode: The permission of the interface file.
- * @parent: The parent directory.
- * @key: Type of interface.
- *
- * Returns nothing.
- */
-static void __init tomoyo_create_entry(const char *name, const mode_t mode,
- struct dentry *parent, const u8 key)
-{
- securityfs_create_file(name, mode, parent, ((u8 *) NULL) + key,
- &tomoyo_operations);
-}
-
-/**
- * tomoyo_initerface_init - Initialize /sys/kernel/security/tomoyo/ interface.
- *
- * Returns 0.
- */
-static int __init tomoyo_initerface_init(void)
-{
- struct dentry *tomoyo_dir;
-
- /* Don't create securityfs entries unless registered. */
- if (current_cred()->security != &tomoyo_kernel_domain)
- return 0;
-
- tomoyo_dir = securityfs_create_dir("tomoyo", NULL);
- tomoyo_create_entry("domain_policy", 0600, tomoyo_dir,
- TOMOYO_DOMAINPOLICY);
- tomoyo_create_entry("exception_policy", 0600, tomoyo_dir,
- TOMOYO_EXCEPTIONPOLICY);
- tomoyo_create_entry("self_domain", 0400, tomoyo_dir,
- TOMOYO_SELFDOMAIN);
- tomoyo_create_entry(".domain_status", 0600, tomoyo_dir,
- TOMOYO_DOMAIN_STATUS);
- tomoyo_create_entry(".process_status", 0600, tomoyo_dir,
- TOMOYO_PROCESS_STATUS);
- tomoyo_create_entry("meminfo", 0600, tomoyo_dir,
- TOMOYO_MEMINFO);
- tomoyo_create_entry("profile", 0600, tomoyo_dir,
- TOMOYO_PROFILE);
- tomoyo_create_entry("manager", 0600, tomoyo_dir,
- TOMOYO_MANAGER);
- tomoyo_create_entry("version", 0400, tomoyo_dir,
- TOMOYO_VERSION);
- return 0;
+ struct tomoyo_domain_info *domain;
+ const int idx = tomoyo_read_lock();
+ tomoyo_policy_loaded = true;
+ /* Check all profiles currently assigned to domains are defined. */
+ list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) {
+ const u8 profile = domain->profile;
+ if (tomoyo_profile_ptr[profile])
+ continue;
+ panic("Profile %u (used by '%s') not defined.\n",
+ profile, domain->domainname->name);
+ }
+ tomoyo_read_unlock(idx);
+ if (tomoyo_profile_version != 20090903)
+ panic("Profile version %u is not supported.\n",
+ tomoyo_profile_version);
+ printk(KERN_INFO "TOMOYO: 2.3.0\n");
+ printk(KERN_INFO "Mandatory Access Control activated.\n");
}
-
-fs_initcall(tomoyo_initerface_init);
diff --git a/security/tomoyo/common.h b/security/tomoyo/common.h
index 9f1ae5e3ba5..04454cb7b24 100644
--- a/security/tomoyo/common.h
+++ b/security/tomoyo/common.h
@@ -20,6 +20,7 @@
#include <linux/mount.h>
#include <linux/list.h>
#include <linux/cred.h>
+#include <linux/poll.h>
struct linux_binprm;
/********** Constants definitions. **********/
@@ -32,20 +33,44 @@ struct linux_binprm;
#define TOMOYO_HASH_BITS 8
#define TOMOYO_MAX_HASH (1u<<TOMOYO_HASH_BITS)
-/*
- * This is the max length of a token.
- *
- * A token consists of only ASCII printable characters.
- * Non printable characters in a token is represented in \ooo style
- * octal string. Thus, \ itself is represented as \\.
- */
-#define TOMOYO_MAX_PATHNAME_LEN 4000
+#define TOMOYO_EXEC_TMPSIZE 4096
/* Profile number is an integer between 0 and 255. */
#define TOMOYO_MAX_PROFILES 256
+enum tomoyo_mode_index {
+ TOMOYO_CONFIG_DISABLED,
+ TOMOYO_CONFIG_LEARNING,
+ TOMOYO_CONFIG_PERMISSIVE,
+ TOMOYO_CONFIG_ENFORCING,
+ TOMOYO_CONFIG_USE_DEFAULT = 255
+};
+
+enum tomoyo_policy_id {
+ TOMOYO_ID_GROUP,
+ TOMOYO_ID_PATH_GROUP,
+ TOMOYO_ID_NUMBER_GROUP,
+ TOMOYO_ID_TRANSITION_CONTROL,
+ TOMOYO_ID_AGGREGATOR,
+ TOMOYO_ID_GLOBALLY_READABLE,
+ TOMOYO_ID_PATTERN,
+ TOMOYO_ID_NO_REWRITE,
+ TOMOYO_ID_MANAGER,
+ TOMOYO_ID_NAME,
+ TOMOYO_ID_ACL,
+ TOMOYO_ID_DOMAIN,
+ TOMOYO_MAX_POLICY
+};
+
+enum tomoyo_group_id {
+ TOMOYO_PATH_GROUP,
+ TOMOYO_NUMBER_GROUP,
+ TOMOYO_MAX_GROUP
+};
+
/* Keywords for ACLs. */
-#define TOMOYO_KEYWORD_ALIAS "alias "
+#define TOMOYO_KEYWORD_AGGREGATOR "aggregator "
+#define TOMOYO_KEYWORD_ALLOW_MOUNT "allow_mount "
#define TOMOYO_KEYWORD_ALLOW_READ "allow_read "
#define TOMOYO_KEYWORD_DELETE "delete "
#define TOMOYO_KEYWORD_DENY_REWRITE "deny_rewrite "
@@ -55,36 +80,51 @@ struct linux_binprm;
#define TOMOYO_KEYWORD_NO_INITIALIZE_DOMAIN "no_initialize_domain "
#define TOMOYO_KEYWORD_NO_KEEP_DOMAIN "no_keep_domain "
#define TOMOYO_KEYWORD_PATH_GROUP "path_group "
+#define TOMOYO_KEYWORD_NUMBER_GROUP "number_group "
#define TOMOYO_KEYWORD_SELECT "select "
#define TOMOYO_KEYWORD_USE_PROFILE "use_profile "
#define TOMOYO_KEYWORD_IGNORE_GLOBAL_ALLOW_READ "ignore_global_allow_read"
+#define TOMOYO_KEYWORD_QUOTA_EXCEEDED "quota_exceeded"
+#define TOMOYO_KEYWORD_TRANSITION_FAILED "transition_failed"
/* A domain definition starts with <kernel>. */
#define TOMOYO_ROOT_NAME "<kernel>"
#define TOMOYO_ROOT_NAME_LEN (sizeof(TOMOYO_ROOT_NAME) - 1)
-/* Index numbers for Access Controls. */
-enum tomoyo_mac_index {
- TOMOYO_MAC_FOR_FILE, /* domain_policy.conf */
- TOMOYO_MAX_ACCEPT_ENTRY,
- TOMOYO_VERBOSE,
- TOMOYO_MAX_CONTROL_INDEX
+/* Value type definition. */
+#define TOMOYO_VALUE_TYPE_INVALID 0
+#define TOMOYO_VALUE_TYPE_DECIMAL 1
+#define TOMOYO_VALUE_TYPE_OCTAL 2
+#define TOMOYO_VALUE_TYPE_HEXADECIMAL 3
+
+enum tomoyo_transition_type {
+ /* Do not change this order, */
+ TOMOYO_TRANSITION_CONTROL_NO_INITIALIZE,
+ TOMOYO_TRANSITION_CONTROL_INITIALIZE,
+ TOMOYO_TRANSITION_CONTROL_NO_KEEP,
+ TOMOYO_TRANSITION_CONTROL_KEEP,
+ TOMOYO_MAX_TRANSITION_TYPE
};
/* Index numbers for Access Controls. */
enum tomoyo_acl_entry_type_index {
TOMOYO_TYPE_PATH_ACL,
TOMOYO_TYPE_PATH2_ACL,
+ TOMOYO_TYPE_PATH_NUMBER_ACL,
+ TOMOYO_TYPE_MKDEV_ACL,
+ TOMOYO_TYPE_MOUNT_ACL,
};
/* Index numbers for File Controls. */
/*
- * TYPE_READ_WRITE_ACL is special. TYPE_READ_WRITE_ACL is automatically set
- * if both TYPE_READ_ACL and TYPE_WRITE_ACL are set. Both TYPE_READ_ACL and
- * TYPE_WRITE_ACL are automatically set if TYPE_READ_WRITE_ACL is set.
- * TYPE_READ_WRITE_ACL is automatically cleared if either TYPE_READ_ACL or
- * TYPE_WRITE_ACL is cleared. Both TYPE_READ_ACL and TYPE_WRITE_ACL are
- * automatically cleared if TYPE_READ_WRITE_ACL is cleared.
+ * TOMOYO_TYPE_READ_WRITE is special. TOMOYO_TYPE_READ_WRITE is automatically
+ * set if both TOMOYO_TYPE_READ and TOMOYO_TYPE_WRITE are set.
+ * Both TOMOYO_TYPE_READ and TOMOYO_TYPE_WRITE are automatically set if
+ * TOMOYO_TYPE_READ_WRITE is set.
+ * TOMOYO_TYPE_READ_WRITE is automatically cleared if either TOMOYO_TYPE_READ
+ * or TOMOYO_TYPE_WRITE is cleared.
+ * Both TOMOYO_TYPE_READ and TOMOYO_TYPE_WRITE are automatically cleared if
+ * TOMOYO_TYPE_READ_WRITE is cleared.
*/
enum tomoyo_path_acl_index {
@@ -92,27 +132,24 @@ enum tomoyo_path_acl_index {
TOMOYO_TYPE_EXECUTE,
TOMOYO_TYPE_READ,
TOMOYO_TYPE_WRITE,
- TOMOYO_TYPE_CREATE,
TOMOYO_TYPE_UNLINK,
- TOMOYO_TYPE_MKDIR,
TOMOYO_TYPE_RMDIR,
- TOMOYO_TYPE_MKFIFO,
- TOMOYO_TYPE_MKSOCK,
- TOMOYO_TYPE_MKBLOCK,
- TOMOYO_TYPE_MKCHAR,
TOMOYO_TYPE_TRUNCATE,
TOMOYO_TYPE_SYMLINK,
TOMOYO_TYPE_REWRITE,
- TOMOYO_TYPE_IOCTL,
- TOMOYO_TYPE_CHMOD,
- TOMOYO_TYPE_CHOWN,
- TOMOYO_TYPE_CHGRP,
TOMOYO_TYPE_CHROOT,
- TOMOYO_TYPE_MOUNT,
TOMOYO_TYPE_UMOUNT,
TOMOYO_MAX_PATH_OPERATION
};
+#define TOMOYO_RW_MASK ((1 << TOMOYO_TYPE_READ) | (1 << TOMOYO_TYPE_WRITE))
+
+enum tomoyo_mkdev_acl_index {
+ TOMOYO_TYPE_MKBLOCK,
+ TOMOYO_TYPE_MKCHAR,
+ TOMOYO_MAX_MKDEV_OPERATION
+};
+
enum tomoyo_path2_acl_index {
TOMOYO_TYPE_LINK,
TOMOYO_TYPE_RENAME,
@@ -120,6 +157,18 @@ enum tomoyo_path2_acl_index {
TOMOYO_MAX_PATH2_OPERATION
};
+enum tomoyo_path_number_acl_index {
+ TOMOYO_TYPE_CREATE,
+ TOMOYO_TYPE_MKDIR,
+ TOMOYO_TYPE_MKFIFO,
+ TOMOYO_TYPE_MKSOCK,
+ TOMOYO_TYPE_IOCTL,
+ TOMOYO_TYPE_CHMOD,
+ TOMOYO_TYPE_CHOWN,
+ TOMOYO_TYPE_CHGRP,
+ TOMOYO_MAX_PATH_NUMBER_OPERATION
+};
+
enum tomoyo_securityfs_interface_index {
TOMOYO_DOMAINPOLICY,
TOMOYO_EXCEPTIONPOLICY,
@@ -129,20 +178,109 @@ enum tomoyo_securityfs_interface_index {
TOMOYO_SELFDOMAIN,
TOMOYO_VERSION,
TOMOYO_PROFILE,
+ TOMOYO_QUERY,
TOMOYO_MANAGER
};
+enum tomoyo_mac_index {
+ TOMOYO_MAC_FILE_EXECUTE,
+ TOMOYO_MAC_FILE_OPEN,
+ TOMOYO_MAC_FILE_CREATE,
+ TOMOYO_MAC_FILE_UNLINK,
+ TOMOYO_MAC_FILE_MKDIR,
+ TOMOYO_MAC_FILE_RMDIR,
+ TOMOYO_MAC_FILE_MKFIFO,
+ TOMOYO_MAC_FILE_MKSOCK,
+ TOMOYO_MAC_FILE_TRUNCATE,
+ TOMOYO_MAC_FILE_SYMLINK,
+ TOMOYO_MAC_FILE_REWRITE,
+ TOMOYO_MAC_FILE_MKBLOCK,
+ TOMOYO_MAC_FILE_MKCHAR,
+ TOMOYO_MAC_FILE_LINK,
+ TOMOYO_MAC_FILE_RENAME,
+ TOMOYO_MAC_FILE_CHMOD,
+ TOMOYO_MAC_FILE_CHOWN,
+ TOMOYO_MAC_FILE_CHGRP,
+ TOMOYO_MAC_FILE_IOCTL,
+ TOMOYO_MAC_FILE_CHROOT,
+ TOMOYO_MAC_FILE_MOUNT,
+ TOMOYO_MAC_FILE_UMOUNT,
+ TOMOYO_MAC_FILE_PIVOT_ROOT,
+ TOMOYO_MAX_MAC_INDEX
+};
+
+enum tomoyo_mac_category_index {
+ TOMOYO_MAC_CATEGORY_FILE,
+ TOMOYO_MAX_MAC_CATEGORY_INDEX
+};
+
+#define TOMOYO_RETRY_REQUEST 1 /* Retry this request. */
+
/********** Structure definitions. **********/
/*
- * tomoyo_page_buffer is a structure which is used for holding a pathname
- * obtained from "struct dentry" and "struct vfsmount" pair.
- * As of now, it is 4096 bytes. If users complain that 4096 bytes is too small
- * (because TOMOYO escapes non ASCII printable characters using \ooo format),
- * we will make the buffer larger.
+ * tomoyo_acl_head is a structure which is used for holding elements not in
+ * domain policy.
+ * It has following fields.
+ *
+ * (1) "list" which is linked to tomoyo_policy_list[] .
+ * (2) "is_deleted" is a bool which is true if marked as deleted, false
+ * otherwise.
*/
-struct tomoyo_page_buffer {
- char buffer[4096];
+struct tomoyo_acl_head {
+ struct list_head list;
+ bool is_deleted;
+} __packed;
+
+/*
+ * tomoyo_request_info is a structure which is used for holding
+ *
+ * (1) Domain information of current process.
+ * (2) How many retries are made for this request.
+ * (3) Profile number used for this request.
+ * (4) Access control mode of the profile.
+ */
+struct tomoyo_request_info {
+ struct tomoyo_domain_info *domain;
+ /* For holding parameters. */
+ union {
+ struct {
+ const struct tomoyo_path_info *filename;
+ /* For using wildcards at tomoyo_find_next_domain(). */
+ const struct tomoyo_path_info *matched_path;
+ u8 operation;
+ } path;
+ struct {
+ const struct tomoyo_path_info *filename1;
+ const struct tomoyo_path_info *filename2;
+ u8 operation;
+ } path2;
+ struct {
+ const struct tomoyo_path_info *filename;
+ unsigned int mode;
+ unsigned int major;
+ unsigned int minor;
+ u8 operation;
+ } mkdev;
+ struct {
+ const struct tomoyo_path_info *filename;
+ unsigned long number;
+ u8 operation;
+ } path_number;
+ struct {
+ const struct tomoyo_path_info *type;
+ const struct tomoyo_path_info *dir;
+ const struct tomoyo_path_info *dev;
+ unsigned long flags;
+ int need_dev;
+ } mount;
+ } param;
+ u8 param_type;
+ bool granted;
+ u8 retry;
+ u8 profile;
+ u8 mode; /* One of tomoyo_mode_index . */
+ u8 type;
};
/*
@@ -174,45 +312,31 @@ struct tomoyo_path_info {
};
/*
- * tomoyo_name_entry is a structure which is used for linking
+ * tomoyo_name is a structure which is used for linking
* "struct tomoyo_path_info" into tomoyo_name_list .
*/
-struct tomoyo_name_entry {
+struct tomoyo_name {
struct list_head list;
atomic_t users;
struct tomoyo_path_info entry;
};
-/*
- * tomoyo_path_info_with_data is a structure which is used for holding a
- * pathname obtained from "struct dentry" and "struct vfsmount" pair.
- *
- * "struct tomoyo_path_info_with_data" consists of "struct tomoyo_path_info"
- * and buffer for the pathname, while "struct tomoyo_page_buffer" consists of
- * buffer for the pathname only.
- *
- * "struct tomoyo_path_info_with_data" is intended to allow TOMOYO to release
- * both "struct tomoyo_path_info" and buffer for the pathname by single kfree()
- * so that we don't need to return two pointers to the caller. If the caller
- * puts "struct tomoyo_path_info" on stack memory, we will be able to remove
- * "struct tomoyo_path_info_with_data".
- */
-struct tomoyo_path_info_with_data {
- /* Keep "head" first, for this pointer is passed to kfree(). */
- struct tomoyo_path_info head;
- char barrier1[16]; /* Safeguard for overrun. */
- char body[TOMOYO_MAX_PATHNAME_LEN];
- char barrier2[16]; /* Safeguard for overrun. */
-};
-
struct tomoyo_name_union {
const struct tomoyo_path_info *filename;
- struct tomoyo_path_group *group;
+ struct tomoyo_group *group;
u8 is_group;
};
-/* Structure for "path_group" directive. */
-struct tomoyo_path_group {
+struct tomoyo_number_union {
+ unsigned long values[2];
+ struct tomoyo_group *group;
+ u8 min_type;
+ u8 max_type;
+ u8 is_group;
+};
+
+/* Structure for "path_group"/"number_group" directive. */
+struct tomoyo_group {
struct list_head list;
const struct tomoyo_path_info *group_name;
struct list_head member_list;
@@ -220,28 +344,35 @@ struct tomoyo_path_group {
};
/* Structure for "path_group" directive. */
-struct tomoyo_path_group_member {
- struct list_head list;
- bool is_deleted;
+struct tomoyo_path_group {
+ struct tomoyo_acl_head head;
const struct tomoyo_path_info *member_name;
};
+/* Structure for "number_group" directive. */
+struct tomoyo_number_group {
+ struct tomoyo_acl_head head;
+ struct tomoyo_number_union number;
+};
+
/*
* tomoyo_acl_info is a structure which is used for holding
*
* (1) "list" which is linked to the ->acl_info_list of
* "struct tomoyo_domain_info"
- * (2) "type" which tells type of the entry (either
- * "struct tomoyo_path_acl" or "struct tomoyo_path2_acl").
+ * (2) "is_deleted" is a bool which is true if this domain is marked as
+ * "deleted", false otherwise.
+ * (3) "type" which tells type of the entry.
*
* Packing "struct tomoyo_acl_info" allows
- * "struct tomoyo_path_acl" to embed "u8" + "u16" and
- * "struct tomoyo_path2_acl" to embed "u8"
- * without enlarging their structure size.
+ * "struct tomoyo_path_acl" to embed "u16" and "struct tomoyo_path2_acl"
+ * "struct tomoyo_path_number_acl" "struct tomoyo_mkdev_acl" to embed
+ * "u8" without enlarging their structure size.
*/
struct tomoyo_acl_info {
struct list_head list;
- u8 type;
+ bool is_deleted;
+ u8 type; /* = one of values in "enum tomoyo_acl_entry_type_index". */
} __packed;
/*
@@ -299,20 +430,62 @@ struct tomoyo_domain_info {
* (3) "name" is the pathname.
*
* Directives held by this structure are "allow_read/write", "allow_execute",
- * "allow_read", "allow_write", "allow_create", "allow_unlink", "allow_mkdir",
- * "allow_rmdir", "allow_mkfifo", "allow_mksock", "allow_mkblock",
- * "allow_mkchar", "allow_truncate", "allow_symlink", "allow_rewrite",
- * "allow_chmod", "allow_chown", "allow_chgrp", "allow_chroot", "allow_mount"
- * and "allow_unmount".
+ * "allow_read", "allow_write", "allow_unlink", "allow_rmdir",
+ * "allow_truncate", "allow_symlink", "allow_rewrite", "allow_chroot" and
+ * "allow_unmount".
*/
struct tomoyo_path_acl {
struct tomoyo_acl_info head; /* type = TOMOYO_TYPE_PATH_ACL */
- u8 perm_high;
u16 perm;
struct tomoyo_name_union name;
};
/*
+ * tomoyo_path_number_acl is a structure which is used for holding an
+ * entry with one pathname and one number operation.
+ * It has following fields.
+ *
+ * (1) "head" which is a "struct tomoyo_acl_info".
+ * (2) "perm" which is a bitmask of permitted operations.
+ * (3) "name" is the pathname.
+ * (4) "number" is the numeric value.
+ *
+ * Directives held by this structure are "allow_create", "allow_mkdir",
+ * "allow_ioctl", "allow_mkfifo", "allow_mksock", "allow_chmod", "allow_chown"
+ * and "allow_chgrp".
+ *
+ */
+struct tomoyo_path_number_acl {
+ struct tomoyo_acl_info head; /* type = TOMOYO_TYPE_PATH_NUMBER_ACL */
+ u8 perm;
+ struct tomoyo_name_union name;
+ struct tomoyo_number_union number;
+};
+
+/*
+ * tomoyo_mkdev_acl is a structure which is used for holding an
+ * entry with one pathname and three numbers operation.
+ * It has following fields.
+ *
+ * (1) "head" which is a "struct tomoyo_acl_info".
+ * (2) "perm" which is a bitmask of permitted operations.
+ * (3) "mode" is the create mode.
+ * (4) "major" is the major number of device node.
+ * (5) "minor" is the minor number of device node.
+ *
+ * Directives held by this structure are "allow_mkchar", "allow_mkblock".
+ *
+ */
+struct tomoyo_mkdev_acl {
+ struct tomoyo_acl_info head; /* type = TOMOYO_TYPE_MKDEV_ACL */
+ u8 perm;
+ struct tomoyo_name_union name;
+ struct tomoyo_number_union mode;
+ struct tomoyo_number_union major;
+ struct tomoyo_number_union minor;
+};
+
+/*
* tomoyo_path2_acl is a structure which is used for holding an
* entry with two pathnames operation (i.e. link(), rename() and pivot_root()).
* It has following fields.
@@ -333,53 +506,61 @@ struct tomoyo_path2_acl {
};
/*
- * tomoyo_io_buffer is a structure which is used for reading and modifying
- * configuration via /sys/kernel/security/tomoyo/ interface.
- * It has many fields. ->read_var1 , ->read_var2 , ->write_var1 are used as
- * cursors.
+ * tomoyo_mount_acl is a structure which is used for holding an
+ * entry for mount operation.
+ * It has following fields.
*
- * Since the content of /sys/kernel/security/tomoyo/domain_policy is a list of
- * "struct tomoyo_domain_info" entries and each "struct tomoyo_domain_info"
- * entry has a list of "struct tomoyo_acl_info", we need two cursors when
- * reading (one is for traversing tomoyo_domain_list and the other is for
- * traversing "struct tomoyo_acl_info"->acl_info_list ).
+ * (1) "head" which is a "struct tomoyo_acl_info".
+ * (2) "dev_name" is the device name.
+ * (3) "dir_name" is the mount point.
+ * (4) "fs_type" is the filesystem type.
+ * (5) "flags" is the mount flags.
*
- * If a line written to /sys/kernel/security/tomoyo/domain_policy starts with
- * "select ", TOMOYO seeks the cursor ->read_var1 and ->write_var1 to the
- * domain with the domainname specified by the rest of that line (NULL is set
- * if seek failed).
- * If a line written to /sys/kernel/security/tomoyo/domain_policy starts with
- * "delete ", TOMOYO deletes an entry or a domain specified by the rest of that
- * line (->write_var1 is set to NULL if a domain was deleted).
- * If a line written to /sys/kernel/security/tomoyo/domain_policy starts with
- * neither "select " nor "delete ", an entry or a domain specified by that line
- * is appended.
+ * Directive held by this structure is "allow_mount".
+ */
+struct tomoyo_mount_acl {
+ struct tomoyo_acl_info head; /* type = TOMOYO_TYPE_MOUNT_ACL */
+ struct tomoyo_name_union dev_name;
+ struct tomoyo_name_union dir_name;
+ struct tomoyo_name_union fs_type;
+ struct tomoyo_number_union flags;
+};
+
+#define TOMOYO_MAX_IO_READ_QUEUE 32
+
+/*
+ * Structure for reading/writing policy via /sys/kernel/security/tomoyo
+ * interfaces.
*/
struct tomoyo_io_buffer {
- int (*read) (struct tomoyo_io_buffer *);
+ void (*read) (struct tomoyo_io_buffer *);
int (*write) (struct tomoyo_io_buffer *);
+ int (*poll) (struct file *file, poll_table *wait);
/* Exclusive lock for this structure. */
struct mutex io_sem;
/* Index returned by tomoyo_read_lock(). */
int reader_idx;
- /* The position currently reading from. */
- struct list_head *read_var1;
- /* Extra variables for reading. */
- struct list_head *read_var2;
+ char __user *read_user_buf;
+ int read_user_buf_avail;
+ struct {
+ struct list_head *domain;
+ struct list_head *group;
+ struct list_head *acl;
+ int avail;
+ int step;
+ int query_index;
+ u16 index;
+ u8 bit;
+ u8 w_pos;
+ bool eof;
+ bool print_this_domain_only;
+ bool print_execute_only;
+ const char *w[TOMOYO_MAX_IO_READ_QUEUE];
+ } r;
/* The position currently writing to. */
struct tomoyo_domain_info *write_var1;
- /* The step for reading. */
- int read_step;
/* Buffer for reading. */
char *read_buf;
- /* EOF flag for reading. */
- bool read_eof;
- /* Read domain ACL of specified PID? */
- bool read_single_domain;
- /* Extra variable for reading. */
- u8 read_bit;
- /* Bytes available for reading. */
- int read_avail;
/* Size of read buffer. */
int readbuf_size;
/* Buffer for writing. */
@@ -388,215 +569,203 @@ struct tomoyo_io_buffer {
int write_avail;
/* Size of write buffer. */
int writebuf_size;
+ /* Type of this interface. */
+ u8 type;
};
/*
- * tomoyo_globally_readable_file_entry is a structure which is used for holding
+ * tomoyo_readable_file is a structure which is used for holding
* "allow_read" entries.
* It has following fields.
*
- * (1) "list" which is linked to tomoyo_globally_readable_list .
+ * (1) "head" is "struct tomoyo_acl_head".
* (2) "filename" is a pathname which is allowed to open(O_RDONLY).
- * (3) "is_deleted" is a bool which is true if marked as deleted, false
- * otherwise.
*/
-struct tomoyo_globally_readable_file_entry {
- struct list_head list;
+struct tomoyo_readable_file {
+ struct tomoyo_acl_head head;
const struct tomoyo_path_info *filename;
- bool is_deleted;
};
/*
- * tomoyo_pattern_entry is a structure which is used for holding
- * "tomoyo_pattern_list" entries.
+ * tomoyo_no_pattern is a structure which is used for holding
+ * "file_pattern" entries.
* It has following fields.
*
- * (1) "list" which is linked to tomoyo_pattern_list .
+ * (1) "head" is "struct tomoyo_acl_head".
* (2) "pattern" is a pathname pattern which is used for converting pathnames
* to pathname patterns during learning mode.
- * (3) "is_deleted" is a bool which is true if marked as deleted, false
- * otherwise.
*/
-struct tomoyo_pattern_entry {
- struct list_head list;
+struct tomoyo_no_pattern {
+ struct tomoyo_acl_head head;
const struct tomoyo_path_info *pattern;
- bool is_deleted;
};
/*
- * tomoyo_no_rewrite_entry is a structure which is used for holding
+ * tomoyo_no_rewrite is a structure which is used for holding
* "deny_rewrite" entries.
* It has following fields.
*
- * (1) "list" which is linked to tomoyo_no_rewrite_list .
+ * (1) "head" is "struct tomoyo_acl_head".
* (2) "pattern" is a pathname which is by default not permitted to modify
* already existing content.
- * (3) "is_deleted" is a bool which is true if marked as deleted, false
- * otherwise.
*/
-struct tomoyo_no_rewrite_entry {
- struct list_head list;
+struct tomoyo_no_rewrite {
+ struct tomoyo_acl_head head;
const struct tomoyo_path_info *pattern;
- bool is_deleted;
};
/*
- * tomoyo_domain_initializer_entry is a structure which is used for holding
- * "initialize_domain" and "no_initialize_domain" entries.
+ * tomoyo_transition_control is a structure which is used for holding
+ * "initialize_domain"/"no_initialize_domain"/"keep_domain"/"no_keep_domain"
+ * entries.
* It has following fields.
*
- * (1) "list" which is linked to tomoyo_domain_initializer_list .
- * (2) "domainname" which is "a domainname" or "the last component of a
- * domainname". This field is NULL if "from" clause is not specified.
- * (3) "program" which is a program's pathname.
- * (4) "is_deleted" is a bool which is true if marked as deleted, false
- * otherwise.
- * (5) "is_not" is a bool which is true if "no_initialize_domain", false
- * otherwise.
- * (6) "is_last_name" is a bool which is true if "domainname" is "the last
+ * (1) "head" is "struct tomoyo_acl_head".
+ * (2) "type" is type of this entry.
+ * (3) "is_last_name" is a bool which is true if "domainname" is "the last
* component of a domainname", false otherwise.
- */
-struct tomoyo_domain_initializer_entry {
- struct list_head list;
- const struct tomoyo_path_info *domainname; /* This may be NULL */
- const struct tomoyo_path_info *program;
- bool is_deleted;
- bool is_not; /* True if this entry is "no_initialize_domain". */
- /* True if the domainname is tomoyo_get_last_name(). */
- bool is_last_name;
-};
-
-/*
- * tomoyo_domain_keeper_entry is a structure which is used for holding
- * "keep_domain" and "no_keep_domain" entries.
- * It has following fields.
- *
- * (1) "list" which is linked to tomoyo_domain_keeper_list .
- * (2) "domainname" which is "a domainname" or "the last component of a
+ * (4) "domainname" which is "a domainname" or "the last component of a
* domainname".
- * (3) "program" which is a program's pathname.
- * This field is NULL if "from" clause is not specified.
- * (4) "is_deleted" is a bool which is true if marked as deleted, false
- * otherwise.
- * (5) "is_not" is a bool which is true if "no_initialize_domain", false
- * otherwise.
- * (6) "is_last_name" is a bool which is true if "domainname" is "the last
- * component of a domainname", false otherwise.
+ * (5) "program" which is a program's pathname.
*/
-struct tomoyo_domain_keeper_entry {
- struct list_head list;
- const struct tomoyo_path_info *domainname;
- const struct tomoyo_path_info *program; /* This may be NULL */
- bool is_deleted;
- bool is_not; /* True if this entry is "no_keep_domain". */
+struct tomoyo_transition_control {
+ struct tomoyo_acl_head head;
+ u8 type; /* One of values in "enum tomoyo_transition_type". */
/* True if the domainname is tomoyo_get_last_name(). */
bool is_last_name;
+ const struct tomoyo_path_info *domainname; /* Maybe NULL */
+ const struct tomoyo_path_info *program; /* Maybe NULL */
};
/*
- * tomoyo_alias_entry is a structure which is used for holding "alias" entries.
+ * tomoyo_aggregator is a structure which is used for holding
+ * "aggregator" entries.
* It has following fields.
*
- * (1) "list" which is linked to tomoyo_alias_list .
- * (2) "original_name" which is a dereferenced pathname.
- * (3) "aliased_name" which is a symlink's pathname.
- * (4) "is_deleted" is a bool which is true if marked as deleted, false
- * otherwise.
+ * (1) "head" is "struct tomoyo_acl_head".
+ * (2) "original_name" which is originally requested name.
+ * (3) "aggregated_name" which is name to rewrite.
*/
-struct tomoyo_alias_entry {
- struct list_head list;
+struct tomoyo_aggregator {
+ struct tomoyo_acl_head head;
const struct tomoyo_path_info *original_name;
- const struct tomoyo_path_info *aliased_name;
- bool is_deleted;
+ const struct tomoyo_path_info *aggregated_name;
};
/*
- * tomoyo_policy_manager_entry is a structure which is used for holding list of
+ * tomoyo_manager is a structure which is used for holding list of
* domainnames or programs which are permitted to modify configuration via
* /sys/kernel/security/tomoyo/ interface.
* It has following fields.
*
- * (1) "list" which is linked to tomoyo_policy_manager_list .
- * (2) "manager" is a domainname or a program's pathname.
- * (3) "is_domain" is a bool which is true if "manager" is a domainname, false
- * otherwise.
- * (4) "is_deleted" is a bool which is true if marked as deleted, false
+ * (1) "head" is "struct tomoyo_acl_head".
+ * (2) "is_domain" is a bool which is true if "manager" is a domainname, false
* otherwise.
+ * (3) "manager" is a domainname or a program's pathname.
*/
-struct tomoyo_policy_manager_entry {
- struct list_head list;
+struct tomoyo_manager {
+ struct tomoyo_acl_head head;
+ bool is_domain; /* True if manager is a domainname. */
/* A path to program or a domainname. */
const struct tomoyo_path_info *manager;
- bool is_domain; /* True if manager is a domainname. */
- bool is_deleted; /* True if this entry is deleted. */
+};
+
+struct tomoyo_preference {
+ unsigned int learning_max_entry;
+ bool enforcing_verbose;
+ bool learning_verbose;
+ bool permissive_verbose;
+};
+
+struct tomoyo_profile {
+ const struct tomoyo_path_info *comment;
+ struct tomoyo_preference *learning;
+ struct tomoyo_preference *permissive;
+ struct tomoyo_preference *enforcing;
+ struct tomoyo_preference preference;
+ u8 default_config;
+ u8 config[TOMOYO_MAX_MAC_INDEX + TOMOYO_MAX_MAC_CATEGORY_INDEX];
};
/********** Function prototypes. **********/
-/* Check whether the given name matches the given name_union. */
-bool tomoyo_compare_name_union(const struct tomoyo_path_info *name,
- const struct tomoyo_name_union *ptr);
+extern asmlinkage long sys_getpid(void);
+extern asmlinkage long sys_getppid(void);
+
+/* Check whether the given string starts with the given keyword. */
+bool tomoyo_str_starts(char **src, const char *find);
+/* Get tomoyo_realpath() of current process. */
+const char *tomoyo_get_exe(void);
+/* Format string. */
+void tomoyo_normalize_line(unsigned char *buffer);
+/* Print warning or error message on console. */
+void tomoyo_warn_log(struct tomoyo_request_info *r, const char *fmt, ...)
+ __attribute__ ((format(printf, 2, 3)));
+/* Check all profiles currently assigned to domains are defined. */
+void tomoyo_check_profile(void);
+/* Open operation for /sys/kernel/security/tomoyo/ interface. */
+int tomoyo_open_control(const u8 type, struct file *file);
+/* Close /sys/kernel/security/tomoyo/ interface. */
+int tomoyo_close_control(struct file *file);
+/* Poll operation for /sys/kernel/security/tomoyo/ interface. */
+int tomoyo_poll_control(struct file *file, poll_table *wait);
+/* Read operation for /sys/kernel/security/tomoyo/ interface. */
+int tomoyo_read_control(struct file *file, char __user *buffer,
+ const int buffer_len);
+/* Write operation for /sys/kernel/security/tomoyo/ interface. */
+int tomoyo_write_control(struct file *file, const char __user *buffer,
+ const int buffer_len);
/* Check whether the domain has too many ACL entries to hold. */
-bool tomoyo_domain_quota_is_ok(struct tomoyo_domain_info * const domain);
-/* Transactional sprintf() for policy dump. */
-bool tomoyo_io_printf(struct tomoyo_io_buffer *head, const char *fmt, ...)
+bool tomoyo_domain_quota_is_ok(struct tomoyo_request_info *r);
+/* Print out of memory warning message. */
+void tomoyo_warn_oom(const char *function);
+/* Check whether the given name matches the given name_union. */
+const struct tomoyo_path_info *
+tomoyo_compare_name_union(const struct tomoyo_path_info *name,
+ const struct tomoyo_name_union *ptr);
+/* Check whether the given number matches the given number_union. */
+bool tomoyo_compare_number_union(const unsigned long value,
+ const struct tomoyo_number_union *ptr);
+int tomoyo_get_mode(const u8 profile, const u8 index);
+void tomoyo_io_printf(struct tomoyo_io_buffer *head, const char *fmt, ...)
__attribute__ ((format(printf, 2, 3)));
/* Check whether the domainname is correct. */
-bool tomoyo_is_correct_domain(const unsigned char *domainname);
+bool tomoyo_correct_domain(const unsigned char *domainname);
/* Check whether the token is correct. */
-bool tomoyo_is_correct_path(const char *filename, const s8 start_type,
- const s8 pattern_type, const s8 end_type);
+bool tomoyo_correct_path(const char *filename);
+bool tomoyo_correct_word(const char *string);
/* Check whether the token can be a domainname. */
-bool tomoyo_is_domain_def(const unsigned char *buffer);
+bool tomoyo_domain_def(const unsigned char *buffer);
bool tomoyo_parse_name_union(const char *filename,
struct tomoyo_name_union *ptr);
/* Check whether the given filename matches the given path_group. */
-bool tomoyo_path_matches_group(const struct tomoyo_path_info *pathname,
- const struct tomoyo_path_group *group,
- const bool may_use_pattern);
+const struct tomoyo_path_info *
+tomoyo_path_matches_group(const struct tomoyo_path_info *pathname,
+ const struct tomoyo_group *group);
+/* Check whether the given value matches the given number_group. */
+bool tomoyo_number_matches_group(const unsigned long min,
+ const unsigned long max,
+ const struct tomoyo_group *group);
/* Check whether the given filename matches the given pattern. */
bool tomoyo_path_matches_pattern(const struct tomoyo_path_info *filename,
const struct tomoyo_path_info *pattern);
-/* Read "alias" entry in exception policy. */
-bool tomoyo_read_alias_policy(struct tomoyo_io_buffer *head);
-/*
- * Read "initialize_domain" and "no_initialize_domain" entry
- * in exception policy.
- */
-bool tomoyo_read_domain_initializer_policy(struct tomoyo_io_buffer *head);
-/* Read "keep_domain" and "no_keep_domain" entry in exception policy. */
-bool tomoyo_read_domain_keeper_policy(struct tomoyo_io_buffer *head);
-/* Read "file_pattern" entry in exception policy. */
-bool tomoyo_read_file_pattern(struct tomoyo_io_buffer *head);
-/* Read "path_group" entry in exception policy. */
-bool tomoyo_read_path_group_policy(struct tomoyo_io_buffer *head);
-/* Read "allow_read" entry in exception policy. */
-bool tomoyo_read_globally_readable_policy(struct tomoyo_io_buffer *head);
-/* Read "deny_rewrite" entry in exception policy. */
-bool tomoyo_read_no_rewrite_policy(struct tomoyo_io_buffer *head);
+
+bool tomoyo_parse_number_union(char *data, struct tomoyo_number_union *num);
/* Tokenize a line. */
bool tomoyo_tokenize(char *buffer, char *w[], size_t size);
/* Write domain policy violation warning message to console? */
bool tomoyo_verbose_mode(const struct tomoyo_domain_info *domain);
-/* Convert double path operation to operation name. */
-const char *tomoyo_path22keyword(const u8 operation);
-/* Get the last component of the given domainname. */
-const char *tomoyo_get_last_name(const struct tomoyo_domain_info *domain);
-/* Get warning message. */
-const char *tomoyo_get_msg(const bool is_enforce);
-/* Convert single path operation to operation name. */
-const char *tomoyo_path2keyword(const u8 operation);
-/* Create "alias" entry in exception policy. */
-int tomoyo_write_alias_policy(char *data, const bool is_delete);
-/*
- * Create "initialize_domain" and "no_initialize_domain" entry
- * in exception policy.
- */
-int tomoyo_write_domain_initializer_policy(char *data, const bool is_not,
- const bool is_delete);
-/* Create "keep_domain" and "no_keep_domain" entry in exception policy. */
-int tomoyo_write_domain_keeper_policy(char *data, const bool is_not,
- const bool is_delete);
+/* Fill "struct tomoyo_request_info". */
+int tomoyo_init_request_info(struct tomoyo_request_info *r,
+ struct tomoyo_domain_info *domain,
+ const u8 index);
+/* Check permission for mount operation. */
+int tomoyo_mount_permission(char *dev_name, struct path *path, char *type,
+ unsigned long flags, void *data_page);
+/* Create "aggregator" entry in exception policy. */
+int tomoyo_write_aggregator(char *data, const bool is_delete);
+int tomoyo_write_transition_control(char *data, const bool is_delete,
+ const u8 type);
/*
* Create "allow_read/write", "allow_execute", "allow_read", "allow_write",
* "allow_create", "allow_unlink", "allow_mkdir", "allow_rmdir",
@@ -604,25 +773,31 @@ int tomoyo_write_domain_keeper_policy(char *data, const bool is_not,
* "allow_truncate", "allow_symlink", "allow_rewrite", "allow_rename" and
* "allow_link" entry in domain policy.
*/
-int tomoyo_write_file_policy(char *data, struct tomoyo_domain_info *domain,
- const bool is_delete);
+int tomoyo_write_file(char *data, struct tomoyo_domain_info *domain,
+ const bool is_delete);
/* Create "allow_read" entry in exception policy. */
-int tomoyo_write_globally_readable_policy(char *data, const bool is_delete);
+int tomoyo_write_globally_readable(char *data, const bool is_delete);
+/* Create "allow_mount" entry in domain policy. */
+int tomoyo_write_mount(char *data, struct tomoyo_domain_info *domain,
+ const bool is_delete);
/* Create "deny_rewrite" entry in exception policy. */
-int tomoyo_write_no_rewrite_policy(char *data, const bool is_delete);
+int tomoyo_write_no_rewrite(char *data, const bool is_delete);
/* Create "file_pattern" entry in exception policy. */
-int tomoyo_write_pattern_policy(char *data, const bool is_delete);
-/* Create "path_group" entry in exception policy. */
-int tomoyo_write_path_group_policy(char *data, const bool is_delete);
+int tomoyo_write_pattern(char *data, const bool is_delete);
+/* Create "path_group"/"number_group" entry in exception policy. */
+int tomoyo_write_group(char *data, const bool is_delete, const u8 type);
+int tomoyo_supervisor(struct tomoyo_request_info *r, const char *fmt, ...)
+ __attribute__ ((format(printf, 2, 3)));
/* Find a domain by the given name. */
struct tomoyo_domain_info *tomoyo_find_domain(const char *domainname);
/* Find or create a domain by the given name. */
-struct tomoyo_domain_info *tomoyo_find_or_assign_new_domain(const char *
- domainname,
- const u8 profile);
-
-/* Allocate memory for "struct tomoyo_path_group". */
-struct tomoyo_path_group *tomoyo_get_path_group(const char *group_name);
+struct tomoyo_domain_info *tomoyo_assign_domain(const char *domainname,
+ const u8 profile);
+struct tomoyo_profile *tomoyo_profile(const u8 profile);
+/*
+ * Allocate memory for "struct tomoyo_path_group"/"struct tomoyo_number_group".
+ */
+struct tomoyo_group *tomoyo_get_group(const char *group_name, const u8 type);
/* Check mode for specified functionality. */
unsigned int tomoyo_check_flags(const struct tomoyo_domain_info *domain,
@@ -632,25 +807,23 @@ void tomoyo_fill_path_info(struct tomoyo_path_info *ptr);
/* Run policy loader when /sbin/init starts. */
void tomoyo_load_policy(const char *filename);
-/* Convert binary string to ascii string. */
-int tomoyo_encode(char *buffer, int buflen, const char *str);
+void tomoyo_put_number_union(struct tomoyo_number_union *ptr);
-/* Returns realpath(3) of the given pathname but ignores chroot'ed root. */
-int tomoyo_realpath_from_path2(struct path *path, char *newname,
- int newname_len);
+/* Convert binary string to ascii string. */
+char *tomoyo_encode(const char *str);
/*
- * Returns realpath(3) of the given pathname but ignores chroot'ed root.
- * These functions use kzalloc(), so the caller must call kfree()
- * if these functions didn't return NULL.
+ * Returns realpath(3) of the given pathname except that
+ * ignores chroot'ed root and does not follow the final symlink.
*/
-char *tomoyo_realpath(const char *pathname);
+char *tomoyo_realpath_nofollow(const char *pathname);
/*
- * Same with tomoyo_realpath() except that it doesn't follow the final symlink.
+ * Returns realpath(3) of the given pathname except that
+ * ignores chroot'ed root and the pathname is already solved.
*/
-char *tomoyo_realpath_nofollow(const char *pathname);
-/* Same with tomoyo_realpath() except that the pathname is already solved. */
char *tomoyo_realpath_from_path(struct path *path);
+/* Get patterned pathname. */
+const char *tomoyo_pattern(const struct tomoyo_path_info *filename);
/* Check memory quota. */
bool tomoyo_memory_ok(void *ptr);
@@ -663,23 +836,29 @@ void *tomoyo_commit_ok(void *data, const unsigned int size);
const struct tomoyo_path_info *tomoyo_get_name(const char *name);
/* Check for memory usage. */
-int tomoyo_read_memory_counter(struct tomoyo_io_buffer *head);
+void tomoyo_read_memory_counter(struct tomoyo_io_buffer *head);
/* Set memory quota. */
int tomoyo_write_memory_quota(struct tomoyo_io_buffer *head);
-/* Initialize realpath related code. */
-void __init tomoyo_realpath_init(void);
-int tomoyo_check_exec_perm(struct tomoyo_domain_info *domain,
+/* Initialize mm related code. */
+void __init tomoyo_mm_init(void);
+int tomoyo_path_permission(struct tomoyo_request_info *r, u8 operation,
const struct tomoyo_path_info *filename);
int tomoyo_check_open_permission(struct tomoyo_domain_info *domain,
struct path *path, const int flag);
+int tomoyo_path_number_perm(const u8 operation, struct path *path,
+ unsigned long number);
+int tomoyo_mkdev_perm(const u8 operation, struct path *path,
+ const unsigned int mode, unsigned int dev);
int tomoyo_path_perm(const u8 operation, struct path *path);
int tomoyo_path2_perm(const u8 operation, struct path *path1,
struct path *path2);
-int tomoyo_check_rewrite_permission(struct file *filp);
int tomoyo_find_next_domain(struct linux_binprm *bprm);
+void tomoyo_print_ulong(char *buffer, const int buffer_len,
+ const unsigned long value, const u8 type);
+
/* Drop refcount on tomoyo_name_union. */
void tomoyo_put_name_union(struct tomoyo_name_union *ptr);
@@ -688,6 +867,25 @@ void tomoyo_run_gc(void);
void tomoyo_memory_free(void *ptr);
+int tomoyo_update_domain(struct tomoyo_acl_info *new_entry, const int size,
+ bool is_delete, struct tomoyo_domain_info *domain,
+ bool (*check_duplicate) (const struct tomoyo_acl_info
+ *,
+ const struct tomoyo_acl_info
+ *),
+ bool (*merge_duplicate) (struct tomoyo_acl_info *,
+ struct tomoyo_acl_info *,
+ const bool));
+int tomoyo_update_policy(struct tomoyo_acl_head *new_entry, const int size,
+ bool is_delete, struct list_head *list,
+ bool (*check_duplicate) (const struct tomoyo_acl_head
+ *,
+ const struct tomoyo_acl_head
+ *));
+void tomoyo_check_acl(struct tomoyo_request_info *r,
+ bool (*check_entry) (struct tomoyo_request_info *,
+ const struct tomoyo_acl_info *));
+
/********** External variable definitions. **********/
/* Lock for GC. */
@@ -696,14 +894,8 @@ extern struct srcu_struct tomoyo_ss;
/* The list for "struct tomoyo_domain_info". */
extern struct list_head tomoyo_domain_list;
-extern struct list_head tomoyo_path_group_list;
-extern struct list_head tomoyo_domain_initializer_list;
-extern struct list_head tomoyo_domain_keeper_list;
-extern struct list_head tomoyo_alias_list;
-extern struct list_head tomoyo_globally_readable_list;
-extern struct list_head tomoyo_pattern_list;
-extern struct list_head tomoyo_no_rewrite_list;
-extern struct list_head tomoyo_policy_manager_list;
+extern struct list_head tomoyo_policy_list[TOMOYO_MAX_POLICY];
+extern struct list_head tomoyo_group_list[TOMOYO_MAX_GROUP];
extern struct list_head tomoyo_name_list[TOMOYO_MAX_HASH];
/* Lock for protecting policy. */
@@ -715,6 +907,14 @@ extern bool tomoyo_policy_loaded;
/* The kernel's domain. */
extern struct tomoyo_domain_info tomoyo_kernel_domain;
+extern const char *tomoyo_path_keyword[TOMOYO_MAX_PATH_OPERATION];
+extern const char *tomoyo_mkdev_keyword[TOMOYO_MAX_MKDEV_OPERATION];
+extern const char *tomoyo_path2_keyword[TOMOYO_MAX_PATH2_OPERATION];
+extern const char *tomoyo_path_number_keyword[TOMOYO_MAX_PATH_NUMBER_OPERATION];
+
+extern unsigned int tomoyo_quota_for_query;
+extern unsigned int tomoyo_query_memory_size;
+
/********** Inlined functions. **********/
static inline int tomoyo_read_lock(void)
@@ -735,25 +935,25 @@ static inline bool tomoyo_pathcmp(const struct tomoyo_path_info *a,
}
/**
- * tomoyo_is_valid - Check whether the character is a valid char.
+ * tomoyo_valid - Check whether the character is a valid char.
*
* @c: The character to check.
*
* Returns true if @c is a valid character, false otherwise.
*/
-static inline bool tomoyo_is_valid(const unsigned char c)
+static inline bool tomoyo_valid(const unsigned char c)
{
return c > ' ' && c < 127;
}
/**
- * tomoyo_is_invalid - Check whether the character is an invalid char.
+ * tomoyo_invalid - Check whether the character is an invalid char.
*
* @c: The character to check.
*
* Returns true if @c is an invalid character, false otherwise.
*/
-static inline bool tomoyo_is_invalid(const unsigned char c)
+static inline bool tomoyo_invalid(const unsigned char c)
{
return c && (c <= ' ' || c >= 127);
}
@@ -761,13 +961,13 @@ static inline bool tomoyo_is_invalid(const unsigned char c)
static inline void tomoyo_put_name(const struct tomoyo_path_info *name)
{
if (name) {
- struct tomoyo_name_entry *ptr =
- container_of(name, struct tomoyo_name_entry, entry);
+ struct tomoyo_name *ptr =
+ container_of(name, typeof(*ptr), entry);
atomic_dec(&ptr->users);
}
}
-static inline void tomoyo_put_path_group(struct tomoyo_path_group *group)
+static inline void tomoyo_put_group(struct tomoyo_group *group)
{
if (group)
atomic_dec(&group->users);
@@ -784,75 +984,35 @@ static inline struct tomoyo_domain_info *tomoyo_real_domain(struct task_struct
return task_cred_xxx(task, security);
}
-static inline bool tomoyo_is_same_acl_head(const struct tomoyo_acl_info *p1,
+static inline bool tomoyo_same_acl_head(const struct tomoyo_acl_info *p1,
const struct tomoyo_acl_info *p2)
{
return p1->type == p2->type;
}
-static inline bool tomoyo_is_same_name_union
+static inline bool tomoyo_same_name_union
(const struct tomoyo_name_union *p1, const struct tomoyo_name_union *p2)
{
return p1->filename == p2->filename && p1->group == p2->group &&
p1->is_group == p2->is_group;
}
-static inline bool tomoyo_is_same_path_acl(const struct tomoyo_path_acl *p1,
- const struct tomoyo_path_acl *p2)
-{
- return tomoyo_is_same_acl_head(&p1->head, &p2->head) &&
- tomoyo_is_same_name_union(&p1->name, &p2->name);
-}
-
-static inline bool tomoyo_is_same_path2_acl(const struct tomoyo_path2_acl *p1,
- const struct tomoyo_path2_acl *p2)
+static inline bool tomoyo_same_number_union
+(const struct tomoyo_number_union *p1, const struct tomoyo_number_union *p2)
{
- return tomoyo_is_same_acl_head(&p1->head, &p2->head) &&
- tomoyo_is_same_name_union(&p1->name1, &p2->name1) &&
- tomoyo_is_same_name_union(&p1->name2, &p2->name2);
-}
-
-static inline bool tomoyo_is_same_domain_initializer_entry
-(const struct tomoyo_domain_initializer_entry *p1,
- const struct tomoyo_domain_initializer_entry *p2)
-{
- return p1->is_not == p2->is_not && p1->is_last_name == p2->is_last_name
- && p1->domainname == p2->domainname
- && p1->program == p2->program;
-}
-
-static inline bool tomoyo_is_same_domain_keeper_entry
-(const struct tomoyo_domain_keeper_entry *p1,
- const struct tomoyo_domain_keeper_entry *p2)
-{
- return p1->is_not == p2->is_not && p1->is_last_name == p2->is_last_name
- && p1->domainname == p2->domainname
- && p1->program == p2->program;
-}
-
-static inline bool tomoyo_is_same_alias_entry
-(const struct tomoyo_alias_entry *p1, const struct tomoyo_alias_entry *p2)
-{
- return p1->original_name == p2->original_name &&
- p1->aliased_name == p2->aliased_name;
+ return p1->values[0] == p2->values[0] && p1->values[1] == p2->values[1]
+ && p1->group == p2->group && p1->min_type == p2->min_type &&
+ p1->max_type == p2->max_type && p1->is_group == p2->is_group;
}
/**
* list_for_each_cookie - iterate over a list with cookie.
* @pos: the &struct list_head to use as a loop cursor.
- * @cookie: the &struct list_head to use as a cookie.
* @head: the head for your list.
- *
- * Same with list_for_each_rcu() except that this primitive uses @cookie
- * so that we can continue iteration.
- * @cookie must be NULL when iteration starts, and @cookie will become
- * NULL when iteration finishes.
*/
-#define list_for_each_cookie(pos, cookie, head) \
- for (({ if (!cookie) \
- cookie = head; }), \
- pos = rcu_dereference((cookie)->next); \
- prefetch(pos->next), pos != (head) || ((cookie) = NULL); \
- (cookie) = pos, pos = rcu_dereference(pos->next))
+#define list_for_each_cookie(pos, head) \
+ if (!pos) \
+ pos = srcu_dereference((head)->next, &tomoyo_ss); \
+ for ( ; pos != (head); pos = srcu_dereference(pos->next, &tomoyo_ss))
#endif /* !defined(_SECURITY_TOMOYO_COMMON_H) */
diff --git a/security/tomoyo/domain.c b/security/tomoyo/domain.c
index cd8ba444676..35388408e47 100644
--- a/security/tomoyo/domain.c
+++ b/security/tomoyo/domain.c
@@ -1,12 +1,9 @@
/*
* security/tomoyo/domain.c
*
- * Implementation of the Domain-Based Mandatory Access Control.
- *
- * Copyright (C) 2005-2009 NTT DATA CORPORATION
- *
- * Version: 2.2.0 2009/04/01
+ * Domain transition functions for TOMOYO.
*
+ * Copyright (C) 2005-2010 NTT DATA CORPORATION
*/
#include "common.h"
@@ -18,366 +15,191 @@
/* The initial domain. */
struct tomoyo_domain_info tomoyo_kernel_domain;
-/*
- * tomoyo_domain_list is used for holding list of domains.
- * The ->acl_info_list of "struct tomoyo_domain_info" is used for holding
- * permissions (e.g. "allow_read /lib/libc-2.5.so") given to each domain.
- *
- * An entry is added by
- *
- * # ( echo "<kernel>"; echo "allow_execute /sbin/init" ) > \
- * /sys/kernel/security/tomoyo/domain_policy
- *
- * and is deleted by
- *
- * # ( echo "<kernel>"; echo "delete allow_execute /sbin/init" ) > \
- * /sys/kernel/security/tomoyo/domain_policy
- *
- * and all entries are retrieved by
- *
- * # cat /sys/kernel/security/tomoyo/domain_policy
- *
- * A domain is added by
- *
- * # echo "<kernel>" > /sys/kernel/security/tomoyo/domain_policy
- *
- * and is deleted by
- *
- * # echo "delete <kernel>" > /sys/kernel/security/tomoyo/domain_policy
- *
- * and all domains are retrieved by
- *
- * # grep '^<kernel>' /sys/kernel/security/tomoyo/domain_policy
- *
- * Normally, a domainname is monotonically getting longer because a domainname
- * which the process will belong to if an execve() operation succeeds is
- * defined as a concatenation of "current domainname" + "pathname passed to
- * execve()".
- * See tomoyo_domain_initializer_list and tomoyo_domain_keeper_list for
- * exceptions.
- */
-LIST_HEAD(tomoyo_domain_list);
-
/**
- * tomoyo_get_last_name - Get last component of a domainname.
- *
- * @domain: Pointer to "struct tomoyo_domain_info".
- *
- * Returns the last component of the domainname.
- */
-const char *tomoyo_get_last_name(const struct tomoyo_domain_info *domain)
-{
- const char *cp0 = domain->domainname->name;
- const char *cp1 = strrchr(cp0, ' ');
-
- if (cp1)
- return cp1 + 1;
- return cp0;
-}
-
-/*
- * tomoyo_domain_initializer_list is used for holding list of programs which
- * triggers reinitialization of domainname. Normally, a domainname is
- * monotonically getting longer. But sometimes, we restart daemon programs.
- * It would be convenient for us that "a daemon started upon system boot" and
- * "the daemon restarted from console" belong to the same domain. Thus, TOMOYO
- * provides a way to shorten domainnames.
+ * tomoyo_update_policy - Update an entry for exception policy.
*
- * An entry is added by
- *
- * # echo 'initialize_domain /usr/sbin/httpd' > \
- * /sys/kernel/security/tomoyo/exception_policy
- *
- * and is deleted by
- *
- * # echo 'delete initialize_domain /usr/sbin/httpd' > \
- * /sys/kernel/security/tomoyo/exception_policy
- *
- * and all entries are retrieved by
- *
- * # grep ^initialize_domain /sys/kernel/security/tomoyo/exception_policy
- *
- * In the example above, /usr/sbin/httpd will belong to
- * "<kernel> /usr/sbin/httpd" domain.
- *
- * You may specify a domainname using "from" keyword.
- * "initialize_domain /usr/sbin/httpd from <kernel> /etc/rc.d/init.d/httpd"
- * will cause "/usr/sbin/httpd" executed from "<kernel> /etc/rc.d/init.d/httpd"
- * domain to belong to "<kernel> /usr/sbin/httpd" domain.
- *
- * You may add "no_" prefix to "initialize_domain".
- * "initialize_domain /usr/sbin/httpd" and
- * "no_initialize_domain /usr/sbin/httpd from <kernel> /etc/rc.d/init.d/httpd"
- * will cause "/usr/sbin/httpd" to belong to "<kernel> /usr/sbin/httpd" domain
- * unless executed from "<kernel> /etc/rc.d/init.d/httpd" domain.
- */
-LIST_HEAD(tomoyo_domain_initializer_list);
-
-/**
- * tomoyo_update_domain_initializer_entry - Update "struct tomoyo_domain_initializer_entry" list.
- *
- * @domainname: The name of domain. May be NULL.
- * @program: The name of program.
- * @is_not: True if it is "no_initialize_domain" entry.
- * @is_delete: True if it is a delete request.
+ * @new_entry: Pointer to "struct tomoyo_acl_info".
+ * @size: Size of @new_entry in bytes.
+ * @is_delete: True if it is a delete request.
+ * @list: Pointer to "struct list_head".
+ * @check_duplicate: Callback function to find duplicated entry.
*
* Returns 0 on success, negative value otherwise.
*
* Caller holds tomoyo_read_lock().
*/
-static int tomoyo_update_domain_initializer_entry(const char *domainname,
- const char *program,
- const bool is_not,
- const bool is_delete)
+int tomoyo_update_policy(struct tomoyo_acl_head *new_entry, const int size,
+ bool is_delete, struct list_head *list,
+ bool (*check_duplicate) (const struct tomoyo_acl_head
+ *,
+ const struct tomoyo_acl_head
+ *))
{
- struct tomoyo_domain_initializer_entry *ptr;
- struct tomoyo_domain_initializer_entry e = { .is_not = is_not };
int error = is_delete ? -ENOENT : -ENOMEM;
+ struct tomoyo_acl_head *entry;
- if (!tomoyo_is_correct_path(program, 1, -1, -1))
- return -EINVAL; /* No patterns allowed. */
- if (domainname) {
- if (!tomoyo_is_domain_def(domainname) &&
- tomoyo_is_correct_path(domainname, 1, -1, -1))
- e.is_last_name = true;
- else if (!tomoyo_is_correct_domain(domainname))
- return -EINVAL;
- e.domainname = tomoyo_get_name(domainname);
- if (!e.domainname)
- goto out;
- }
- e.program = tomoyo_get_name(program);
- if (!e.program)
- goto out;
if (mutex_lock_interruptible(&tomoyo_policy_lock))
- goto out;
- list_for_each_entry_rcu(ptr, &tomoyo_domain_initializer_list, list) {
- if (!tomoyo_is_same_domain_initializer_entry(ptr, &e))
+ return -ENOMEM;
+ list_for_each_entry_rcu(entry, list, list) {
+ if (!check_duplicate(entry, new_entry))
continue;
- ptr->is_deleted = is_delete;
+ entry->is_deleted = is_delete;
error = 0;
break;
}
- if (!is_delete && error) {
- struct tomoyo_domain_initializer_entry *entry =
- tomoyo_commit_ok(&e, sizeof(e));
+ if (error && !is_delete) {
+ entry = tomoyo_commit_ok(new_entry, size);
if (entry) {
- list_add_tail_rcu(&entry->list,
- &tomoyo_domain_initializer_list);
+ list_add_tail_rcu(&entry->list, list);
error = 0;
}
}
mutex_unlock(&tomoyo_policy_lock);
- out:
- tomoyo_put_name(e.domainname);
- tomoyo_put_name(e.program);
return error;
}
/**
- * tomoyo_read_domain_initializer_policy - Read "struct tomoyo_domain_initializer_entry" list.
+ * tomoyo_update_domain - Update an entry for domain policy.
*
- * @head: Pointer to "struct tomoyo_io_buffer".
+ * @new_entry: Pointer to "struct tomoyo_acl_info".
+ * @size: Size of @new_entry in bytes.
+ * @is_delete: True if it is a delete request.
+ * @domain: Pointer to "struct tomoyo_domain_info".
+ * @check_duplicate: Callback function to find duplicated entry.
+ * @merge_duplicate: Callback function to merge duplicated entry.
*
- * Returns true on success, false otherwise.
+ * Returns 0 on success, negative value otherwise.
*
* Caller holds tomoyo_read_lock().
*/
-bool tomoyo_read_domain_initializer_policy(struct tomoyo_io_buffer *head)
+int tomoyo_update_domain(struct tomoyo_acl_info *new_entry, const int size,
+ bool is_delete, struct tomoyo_domain_info *domain,
+ bool (*check_duplicate) (const struct tomoyo_acl_info
+ *,
+ const struct tomoyo_acl_info
+ *),
+ bool (*merge_duplicate) (struct tomoyo_acl_info *,
+ struct tomoyo_acl_info *,
+ const bool))
{
- struct list_head *pos;
- bool done = true;
+ int error = is_delete ? -ENOENT : -ENOMEM;
+ struct tomoyo_acl_info *entry;
- list_for_each_cookie(pos, head->read_var2,
- &tomoyo_domain_initializer_list) {
- const char *no;
- const char *from = "";
- const char *domain = "";
- struct tomoyo_domain_initializer_entry *ptr;
- ptr = list_entry(pos, struct tomoyo_domain_initializer_entry,
- list);
- if (ptr->is_deleted)
+ if (mutex_lock_interruptible(&tomoyo_policy_lock))
+ return error;
+ list_for_each_entry_rcu(entry, &domain->acl_info_list, list) {
+ if (!check_duplicate(entry, new_entry))
continue;
- no = ptr->is_not ? "no_" : "";
- if (ptr->domainname) {
- from = " from ";
- domain = ptr->domainname->name;
+ if (merge_duplicate)
+ entry->is_deleted = merge_duplicate(entry, new_entry,
+ is_delete);
+ else
+ entry->is_deleted = is_delete;
+ error = 0;
+ break;
+ }
+ if (error && !is_delete) {
+ entry = tomoyo_commit_ok(new_entry, size);
+ if (entry) {
+ list_add_tail_rcu(&entry->list, &domain->acl_info_list);
+ error = 0;
}
- done = tomoyo_io_printf(head,
- "%s" TOMOYO_KEYWORD_INITIALIZE_DOMAIN
- "%s%s%s\n", no, ptr->program->name,
- from, domain);
- if (!done)
- break;
}
- return done;
+ mutex_unlock(&tomoyo_policy_lock);
+ return error;
}
-/**
- * tomoyo_write_domain_initializer_policy - Write "struct tomoyo_domain_initializer_entry" list.
- *
- * @data: String to parse.
- * @is_not: True if it is "no_initialize_domain" entry.
- * @is_delete: True if it is a delete request.
- *
- * Returns 0 on success, negative value otherwise.
- *
- * Caller holds tomoyo_read_lock().
- */
-int tomoyo_write_domain_initializer_policy(char *data, const bool is_not,
- const bool is_delete)
+void tomoyo_check_acl(struct tomoyo_request_info *r,
+ bool (*check_entry) (struct tomoyo_request_info *,
+ const struct tomoyo_acl_info *))
{
- char *cp = strstr(data, " from ");
+ const struct tomoyo_domain_info *domain = r->domain;
+ struct tomoyo_acl_info *ptr;
- if (cp) {
- *cp = '\0';
- return tomoyo_update_domain_initializer_entry(cp + 6, data,
- is_not,
- is_delete);
+ list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) {
+ if (ptr->is_deleted || ptr->type != r->param_type)
+ continue;
+ if (check_entry(r, ptr)) {
+ r->granted = true;
+ return;
+ }
}
- return tomoyo_update_domain_initializer_entry(NULL, data, is_not,
- is_delete);
+ r->granted = false;
}
+/* The list for "struct tomoyo_domain_info". */
+LIST_HEAD(tomoyo_domain_list);
+
+struct list_head tomoyo_policy_list[TOMOYO_MAX_POLICY];
+struct list_head tomoyo_group_list[TOMOYO_MAX_GROUP];
+
/**
- * tomoyo_is_domain_initializer - Check whether the given program causes domainname reinitialization.
- *
- * @domainname: The name of domain.
- * @program: The name of program.
- * @last_name: The last component of @domainname.
+ * tomoyo_last_word - Get last component of a domainname.
*
- * Returns true if executing @program reinitializes domain transition,
- * false otherwise.
+ * @domainname: Domainname to check.
*
- * Caller holds tomoyo_read_lock().
+ * Returns the last word of @domainname.
*/
-static bool tomoyo_is_domain_initializer(const struct tomoyo_path_info *
- domainname,
- const struct tomoyo_path_info *program,
- const struct tomoyo_path_info *
- last_name)
+static const char *tomoyo_last_word(const char *name)
{
- struct tomoyo_domain_initializer_entry *ptr;
- bool flag = false;
-
- list_for_each_entry_rcu(ptr, &tomoyo_domain_initializer_list, list) {
- if (ptr->is_deleted)
- continue;
- if (ptr->domainname) {
- if (!ptr->is_last_name) {
- if (ptr->domainname != domainname)
- continue;
- } else {
- if (tomoyo_pathcmp(ptr->domainname, last_name))
- continue;
- }
- }
- if (tomoyo_pathcmp(ptr->program, program))
- continue;
- if (ptr->is_not) {
- flag = false;
- break;
- }
- flag = true;
- }
- return flag;
+ const char *cp = strrchr(name, ' ');
+ if (cp)
+ return cp + 1;
+ return name;
}
-/*
- * tomoyo_domain_keeper_list is used for holding list of domainnames which
- * suppresses domain transition. Normally, a domainname is monotonically
- * getting longer. But sometimes, we want to suppress domain transition.
- * It would be convenient for us that programs executed from a login session
- * belong to the same domain. Thus, TOMOYO provides a way to suppress domain
- * transition.
- *
- * An entry is added by
- *
- * # echo 'keep_domain <kernel> /usr/sbin/sshd /bin/bash' > \
- * /sys/kernel/security/tomoyo/exception_policy
- *
- * and is deleted by
- *
- * # echo 'delete keep_domain <kernel> /usr/sbin/sshd /bin/bash' > \
- * /sys/kernel/security/tomoyo/exception_policy
- *
- * and all entries are retrieved by
- *
- * # grep ^keep_domain /sys/kernel/security/tomoyo/exception_policy
- *
- * In the example above, any process which belongs to
- * "<kernel> /usr/sbin/sshd /bin/bash" domain will remain in that domain,
- * unless explicitly specified by "initialize_domain" or "no_keep_domain".
- *
- * You may specify a program using "from" keyword.
- * "keep_domain /bin/pwd from <kernel> /usr/sbin/sshd /bin/bash"
- * will cause "/bin/pwd" executed from "<kernel> /usr/sbin/sshd /bin/bash"
- * domain to remain in "<kernel> /usr/sbin/sshd /bin/bash" domain.
- *
- * You may add "no_" prefix to "keep_domain".
- * "keep_domain <kernel> /usr/sbin/sshd /bin/bash" and
- * "no_keep_domain /usr/bin/passwd from <kernel> /usr/sbin/sshd /bin/bash" will
- * cause "/usr/bin/passwd" to belong to
- * "<kernel> /usr/sbin/sshd /bin/bash /usr/bin/passwd" domain, unless
- * explicitly specified by "initialize_domain".
- */
-LIST_HEAD(tomoyo_domain_keeper_list);
+static bool tomoyo_same_transition_control(const struct tomoyo_acl_head *a,
+ const struct tomoyo_acl_head *b)
+{
+ const struct tomoyo_transition_control *p1 = container_of(a,
+ typeof(*p1),
+ head);
+ const struct tomoyo_transition_control *p2 = container_of(b,
+ typeof(*p2),
+ head);
+ return p1->type == p2->type && p1->is_last_name == p2->is_last_name
+ && p1->domainname == p2->domainname
+ && p1->program == p2->program;
+}
/**
- * tomoyo_update_domain_keeper_entry - Update "struct tomoyo_domain_keeper_entry" list.
+ * tomoyo_update_transition_control_entry - Update "struct tomoyo_transition_control" list.
*
- * @domainname: The name of domain.
- * @program: The name of program. May be NULL.
- * @is_not: True if it is "no_keep_domain" entry.
+ * @domainname: The name of domain. Maybe NULL.
+ * @program: The name of program. Maybe NULL.
+ * @type: Type of transition.
* @is_delete: True if it is a delete request.
*
* Returns 0 on success, negative value otherwise.
- *
- * Caller holds tomoyo_read_lock().
*/
-static int tomoyo_update_domain_keeper_entry(const char *domainname,
- const char *program,
- const bool is_not,
- const bool is_delete)
+static int tomoyo_update_transition_control_entry(const char *domainname,
+ const char *program,
+ const u8 type,
+ const bool is_delete)
{
- struct tomoyo_domain_keeper_entry *ptr;
- struct tomoyo_domain_keeper_entry e = { .is_not = is_not };
+ struct tomoyo_transition_control e = { .type = type };
int error = is_delete ? -ENOENT : -ENOMEM;
-
- if (!tomoyo_is_domain_def(domainname) &&
- tomoyo_is_correct_path(domainname, 1, -1, -1))
- e.is_last_name = true;
- else if (!tomoyo_is_correct_domain(domainname))
- return -EINVAL;
if (program) {
- if (!tomoyo_is_correct_path(program, 1, -1, -1))
+ if (!tomoyo_correct_path(program))
return -EINVAL;
e.program = tomoyo_get_name(program);
if (!e.program)
goto out;
}
- e.domainname = tomoyo_get_name(domainname);
- if (!e.domainname)
- goto out;
- if (mutex_lock_interruptible(&tomoyo_policy_lock))
- goto out;
- list_for_each_entry_rcu(ptr, &tomoyo_domain_keeper_list, list) {
- if (!tomoyo_is_same_domain_keeper_entry(ptr, &e))
- continue;
- ptr->is_deleted = is_delete;
- error = 0;
- break;
- }
- if (!is_delete && error) {
- struct tomoyo_domain_keeper_entry *entry =
- tomoyo_commit_ok(&e, sizeof(e));
- if (entry) {
- list_add_tail_rcu(&entry->list,
- &tomoyo_domain_keeper_list);
- error = 0;
+ if (domainname) {
+ if (!tomoyo_correct_domain(domainname)) {
+ if (!tomoyo_correct_path(domainname))
+ goto out;
+ e.is_last_name = true;
}
+ e.domainname = tomoyo_get_name(domainname);
+ if (!e.domainname)
+ goto out;
}
- mutex_unlock(&tomoyo_policy_lock);
+ error = tomoyo_update_policy(&e.head, sizeof(e), is_delete,
+ &tomoyo_policy_list
+ [TOMOYO_ID_TRANSITION_CONTROL],
+ tomoyo_same_transition_control);
out:
tomoyo_put_name(e.domainname);
tomoyo_put_name(e.program);
@@ -385,219 +207,133 @@ static int tomoyo_update_domain_keeper_entry(const char *domainname,
}
/**
- * tomoyo_write_domain_keeper_policy - Write "struct tomoyo_domain_keeper_entry" list.
+ * tomoyo_write_transition_control - Write "struct tomoyo_transition_control" list.
*
* @data: String to parse.
- * @is_not: True if it is "no_keep_domain" entry.
* @is_delete: True if it is a delete request.
+ * @type: Type of this entry.
*
- * Caller holds tomoyo_read_lock().
- */
-int tomoyo_write_domain_keeper_policy(char *data, const bool is_not,
- const bool is_delete)
-{
- char *cp = strstr(data, " from ");
-
- if (cp) {
- *cp = '\0';
- return tomoyo_update_domain_keeper_entry(cp + 6, data, is_not,
- is_delete);
- }
- return tomoyo_update_domain_keeper_entry(data, NULL, is_not, is_delete);
-}
-
-/**
- * tomoyo_read_domain_keeper_policy - Read "struct tomoyo_domain_keeper_entry" list.
- *
- * @head: Pointer to "struct tomoyo_io_buffer".
- *
- * Returns true on success, false otherwise.
- *
- * Caller holds tomoyo_read_lock().
+ * Returns 0 on success, negative value otherwise.
*/
-bool tomoyo_read_domain_keeper_policy(struct tomoyo_io_buffer *head)
+int tomoyo_write_transition_control(char *data, const bool is_delete,
+ const u8 type)
{
- struct list_head *pos;
- bool done = true;
-
- list_for_each_cookie(pos, head->read_var2,
- &tomoyo_domain_keeper_list) {
- struct tomoyo_domain_keeper_entry *ptr;
- const char *no;
- const char *from = "";
- const char *program = "";
-
- ptr = list_entry(pos, struct tomoyo_domain_keeper_entry, list);
- if (ptr->is_deleted)
- continue;
- no = ptr->is_not ? "no_" : "";
- if (ptr->program) {
- from = " from ";
- program = ptr->program->name;
- }
- done = tomoyo_io_printf(head,
- "%s" TOMOYO_KEYWORD_KEEP_DOMAIN
- "%s%s%s\n", no, program, from,
- ptr->domainname->name);
- if (!done)
- break;
+ char *domainname = strstr(data, " from ");
+ if (domainname) {
+ *domainname = '\0';
+ domainname += 6;
+ } else if (type == TOMOYO_TRANSITION_CONTROL_NO_KEEP ||
+ type == TOMOYO_TRANSITION_CONTROL_KEEP) {
+ domainname = data;
+ data = NULL;
}
- return done;
+ return tomoyo_update_transition_control_entry(domainname, data, type,
+ is_delete);
}
/**
- * tomoyo_is_domain_keeper - Check whether the given program causes domain transition suppression.
+ * tomoyo_transition_type - Get domain transition type.
*
* @domainname: The name of domain.
* @program: The name of program.
- * @last_name: The last component of @domainname.
*
- * Returns true if executing @program supresses domain transition,
- * false otherwise.
+ * Returns TOMOYO_TRANSITION_CONTROL_INITIALIZE if executing @program
+ * reinitializes domain transition, TOMOYO_TRANSITION_CONTROL_KEEP if executing
+ * @program suppresses domain transition, others otherwise.
*
* Caller holds tomoyo_read_lock().
*/
-static bool tomoyo_is_domain_keeper(const struct tomoyo_path_info *domainname,
- const struct tomoyo_path_info *program,
- const struct tomoyo_path_info *last_name)
+static u8 tomoyo_transition_type(const struct tomoyo_path_info *domainname,
+ const struct tomoyo_path_info *program)
{
- struct tomoyo_domain_keeper_entry *ptr;
- bool flag = false;
-
- list_for_each_entry_rcu(ptr, &tomoyo_domain_keeper_list, list) {
- if (ptr->is_deleted)
- continue;
- if (!ptr->is_last_name) {
- if (ptr->domainname != domainname)
+ const struct tomoyo_transition_control *ptr;
+ const char *last_name = tomoyo_last_word(domainname->name);
+ u8 type;
+ for (type = 0; type < TOMOYO_MAX_TRANSITION_TYPE; type++) {
+ next:
+ list_for_each_entry_rcu(ptr, &tomoyo_policy_list
+ [TOMOYO_ID_TRANSITION_CONTROL],
+ head.list) {
+ if (ptr->head.is_deleted || ptr->type != type)
continue;
- } else {
- if (tomoyo_pathcmp(ptr->domainname, last_name))
+ if (ptr->domainname) {
+ if (!ptr->is_last_name) {
+ if (ptr->domainname != domainname)
+ continue;
+ } else {
+ /*
+ * Use direct strcmp() since this is
+ * unlikely used.
+ */
+ if (strcmp(ptr->domainname->name,
+ last_name))
+ continue;
+ }
+ }
+ if (ptr->program &&
+ tomoyo_pathcmp(ptr->program, program))
continue;
+ if (type == TOMOYO_TRANSITION_CONTROL_NO_INITIALIZE) {
+ /*
+ * Do not check for initialize_domain if
+ * no_initialize_domain matched.
+ */
+ type = TOMOYO_TRANSITION_CONTROL_NO_KEEP;
+ goto next;
+ }
+ goto done;
}
- if (ptr->program && tomoyo_pathcmp(ptr->program, program))
- continue;
- if (ptr->is_not) {
- flag = false;
- break;
- }
- flag = true;
}
- return flag;
+ done:
+ return type;
}
-/*
- * tomoyo_alias_list is used for holding list of symlink's pathnames which are
- * allowed to be passed to an execve() request. Normally, the domainname which
- * the current process will belong to after execve() succeeds is calculated
- * using dereferenced pathnames. But some programs behave differently depending
- * on the name passed to argv[0]. For busybox, calculating domainname using
- * dereferenced pathnames will cause all programs in the busybox to belong to
- * the same domain. Thus, TOMOYO provides a way to allow use of symlink's
- * pathname for checking execve()'s permission and calculating domainname which
- * the current process will belong to after execve() succeeds.
- *
- * An entry is added by
- *
- * # echo 'alias /bin/busybox /bin/cat' > \
- * /sys/kernel/security/tomoyo/exception_policy
- *
- * and is deleted by
- *
- * # echo 'delete alias /bin/busybox /bin/cat' > \
- * /sys/kernel/security/tomoyo/exception_policy
- *
- * and all entries are retrieved by
- *
- * # grep ^alias /sys/kernel/security/tomoyo/exception_policy
- *
- * In the example above, if /bin/cat is a symlink to /bin/busybox and execution
- * of /bin/cat is requested, permission is checked for /bin/cat rather than
- * /bin/busybox and domainname which the current process will belong to after
- * execve() succeeds is calculated using /bin/cat rather than /bin/busybox .
- */
-LIST_HEAD(tomoyo_alias_list);
+static bool tomoyo_same_aggregator(const struct tomoyo_acl_head *a,
+ const struct tomoyo_acl_head *b)
+{
+ const struct tomoyo_aggregator *p1 = container_of(a, typeof(*p1), head);
+ const struct tomoyo_aggregator *p2 = container_of(b, typeof(*p2), head);
+ return p1->original_name == p2->original_name &&
+ p1->aggregated_name == p2->aggregated_name;
+}
/**
- * tomoyo_update_alias_entry - Update "struct tomoyo_alias_entry" list.
+ * tomoyo_update_aggregator_entry - Update "struct tomoyo_aggregator" list.
*
- * @original_name: The original program's real name.
- * @aliased_name: The symbolic program's symbolic link's name.
- * @is_delete: True if it is a delete request.
+ * @original_name: The original program's name.
+ * @aggregated_name: The program name to use.
+ * @is_delete: True if it is a delete request.
*
* Returns 0 on success, negative value otherwise.
*
* Caller holds tomoyo_read_lock().
*/
-static int tomoyo_update_alias_entry(const char *original_name,
- const char *aliased_name,
- const bool is_delete)
+static int tomoyo_update_aggregator_entry(const char *original_name,
+ const char *aggregated_name,
+ const bool is_delete)
{
- struct tomoyo_alias_entry *ptr;
- struct tomoyo_alias_entry e = { };
+ struct tomoyo_aggregator e = { };
int error = is_delete ? -ENOENT : -ENOMEM;
- if (!tomoyo_is_correct_path(original_name, 1, -1, -1) ||
- !tomoyo_is_correct_path(aliased_name, 1, -1, -1))
- return -EINVAL; /* No patterns allowed. */
+ if (!tomoyo_correct_path(original_name) ||
+ !tomoyo_correct_path(aggregated_name))
+ return -EINVAL;
e.original_name = tomoyo_get_name(original_name);
- e.aliased_name = tomoyo_get_name(aliased_name);
- if (!e.original_name || !e.aliased_name)
+ e.aggregated_name = tomoyo_get_name(aggregated_name);
+ if (!e.original_name || !e.aggregated_name ||
+ e.aggregated_name->is_patterned) /* No patterns allowed. */
goto out;
- if (mutex_lock_interruptible(&tomoyo_policy_lock))
- goto out;
- list_for_each_entry_rcu(ptr, &tomoyo_alias_list, list) {
- if (!tomoyo_is_same_alias_entry(ptr, &e))
- continue;
- ptr->is_deleted = is_delete;
- error = 0;
- break;
- }
- if (!is_delete && error) {
- struct tomoyo_alias_entry *entry =
- tomoyo_commit_ok(&e, sizeof(e));
- if (entry) {
- list_add_tail_rcu(&entry->list, &tomoyo_alias_list);
- error = 0;
- }
- }
- mutex_unlock(&tomoyo_policy_lock);
+ error = tomoyo_update_policy(&e.head, sizeof(e), is_delete,
+ &tomoyo_policy_list[TOMOYO_ID_AGGREGATOR],
+ tomoyo_same_aggregator);
out:
tomoyo_put_name(e.original_name);
- tomoyo_put_name(e.aliased_name);
+ tomoyo_put_name(e.aggregated_name);
return error;
}
/**
- * tomoyo_read_alias_policy - Read "struct tomoyo_alias_entry" list.
- *
- * @head: Pointer to "struct tomoyo_io_buffer".
- *
- * Returns true on success, false otherwise.
- *
- * Caller holds tomoyo_read_lock().
- */
-bool tomoyo_read_alias_policy(struct tomoyo_io_buffer *head)
-{
- struct list_head *pos;
- bool done = true;
-
- list_for_each_cookie(pos, head->read_var2, &tomoyo_alias_list) {
- struct tomoyo_alias_entry *ptr;
-
- ptr = list_entry(pos, struct tomoyo_alias_entry, list);
- if (ptr->is_deleted)
- continue;
- done = tomoyo_io_printf(head, TOMOYO_KEYWORD_ALIAS "%s %s\n",
- ptr->original_name->name,
- ptr->aliased_name->name);
- if (!done)
- break;
- }
- return done;
-}
-
-/**
- * tomoyo_write_alias_policy - Write "struct tomoyo_alias_entry" list.
+ * tomoyo_write_aggregator - Write "struct tomoyo_aggregator" list.
*
* @data: String to parse.
* @is_delete: True if it is a delete request.
@@ -606,18 +342,18 @@ bool tomoyo_read_alias_policy(struct tomoyo_io_buffer *head)
*
* Caller holds tomoyo_read_lock().
*/
-int tomoyo_write_alias_policy(char *data, const bool is_delete)
+int tomoyo_write_aggregator(char *data, const bool is_delete)
{
char *cp = strchr(data, ' ');
if (!cp)
return -EINVAL;
*cp++ = '\0';
- return tomoyo_update_alias_entry(data, cp, is_delete);
+ return tomoyo_update_aggregator_entry(data, cp, is_delete);
}
/**
- * tomoyo_find_or_assign_new_domain - Create a domain.
+ * tomoyo_assign_domain - Create a domain.
*
* @domainname: The name of domain.
* @profile: Profile number to assign if the domain was newly created.
@@ -626,16 +362,15 @@ int tomoyo_write_alias_policy(char *data, const bool is_delete)
*
* Caller holds tomoyo_read_lock().
*/
-struct tomoyo_domain_info *tomoyo_find_or_assign_new_domain(const char *
- domainname,
- const u8 profile)
+struct tomoyo_domain_info *tomoyo_assign_domain(const char *domainname,
+ const u8 profile)
{
struct tomoyo_domain_info *entry;
struct tomoyo_domain_info *domain = NULL;
const struct tomoyo_path_info *saved_domainname;
bool found = false;
- if (!tomoyo_is_correct_domain(domainname))
+ if (!tomoyo_correct_domain(domainname))
return NULL;
saved_domainname = tomoyo_get_name(domainname);
if (!saved_domainname)
@@ -678,116 +413,118 @@ struct tomoyo_domain_info *tomoyo_find_or_assign_new_domain(const char *
*/
int tomoyo_find_next_domain(struct linux_binprm *bprm)
{
- /*
- * This function assumes that the size of buffer returned by
- * tomoyo_realpath() = TOMOYO_MAX_PATHNAME_LEN.
- */
- struct tomoyo_page_buffer *tmp = kzalloc(sizeof(*tmp), GFP_NOFS);
+ struct tomoyo_request_info r;
+ char *tmp = kzalloc(TOMOYO_EXEC_TMPSIZE, GFP_NOFS);
struct tomoyo_domain_info *old_domain = tomoyo_domain();
struct tomoyo_domain_info *domain = NULL;
- const char *old_domain_name = old_domain->domainname->name;
const char *original_name = bprm->filename;
- char *new_domain_name = NULL;
- char *real_program_name = NULL;
- char *symlink_program_name = NULL;
- const u8 mode = tomoyo_check_flags(old_domain, TOMOYO_MAC_FOR_FILE);
- const bool is_enforce = (mode == 3);
+ u8 mode;
+ bool is_enforce;
int retval = -ENOMEM;
- struct tomoyo_path_info r; /* real name */
- struct tomoyo_path_info s; /* symlink name */
- struct tomoyo_path_info l; /* last name */
- static bool initialized;
+ bool need_kfree = false;
+ struct tomoyo_path_info rn = { }; /* real name */
+ mode = tomoyo_init_request_info(&r, NULL, TOMOYO_MAC_FILE_EXECUTE);
+ is_enforce = (mode == TOMOYO_CONFIG_ENFORCING);
if (!tmp)
goto out;
- if (!initialized) {
- /*
- * Built-in initializers. This is needed because policies are
- * not loaded until starting /sbin/init.
- */
- tomoyo_update_domain_initializer_entry(NULL, "/sbin/hotplug",
- false, false);
- tomoyo_update_domain_initializer_entry(NULL, "/sbin/modprobe",
- false, false);
- initialized = true;
+ retry:
+ if (need_kfree) {
+ kfree(rn.name);
+ need_kfree = false;
}
-
- /* Get tomoyo_realpath of program. */
+ /* Get symlink's pathname of program. */
retval = -ENOENT;
- /* I hope tomoyo_realpath() won't fail with -ENOMEM. */
- real_program_name = tomoyo_realpath(original_name);
- if (!real_program_name)
- goto out;
- /* Get tomoyo_realpath of symbolic link. */
- symlink_program_name = tomoyo_realpath_nofollow(original_name);
- if (!symlink_program_name)
+ rn.name = tomoyo_realpath_nofollow(original_name);
+ if (!rn.name)
goto out;
-
- r.name = real_program_name;
- tomoyo_fill_path_info(&r);
- s.name = symlink_program_name;
- tomoyo_fill_path_info(&s);
- l.name = tomoyo_get_last_name(old_domain);
- tomoyo_fill_path_info(&l);
-
- /* Check 'alias' directive. */
- if (tomoyo_pathcmp(&r, &s)) {
- struct tomoyo_alias_entry *ptr;
- /* Is this program allowed to be called via symbolic links? */
- list_for_each_entry_rcu(ptr, &tomoyo_alias_list, list) {
- if (ptr->is_deleted ||
- tomoyo_pathcmp(&r, ptr->original_name) ||
- tomoyo_pathcmp(&s, ptr->aliased_name))
+ tomoyo_fill_path_info(&rn);
+ need_kfree = true;
+
+ /* Check 'aggregator' directive. */
+ {
+ struct tomoyo_aggregator *ptr;
+ list_for_each_entry_rcu(ptr, &tomoyo_policy_list
+ [TOMOYO_ID_AGGREGATOR], head.list) {
+ if (ptr->head.is_deleted ||
+ !tomoyo_path_matches_pattern(&rn,
+ ptr->original_name))
continue;
- memset(real_program_name, 0, TOMOYO_MAX_PATHNAME_LEN);
- strncpy(real_program_name, ptr->aliased_name->name,
- TOMOYO_MAX_PATHNAME_LEN - 1);
- tomoyo_fill_path_info(&r);
+ kfree(rn.name);
+ need_kfree = false;
+ /* This is OK because it is read only. */
+ rn = *ptr->aggregated_name;
break;
}
}
/* Check execute permission. */
- retval = tomoyo_check_exec_perm(old_domain, &r);
+ retval = tomoyo_path_permission(&r, TOMOYO_TYPE_EXECUTE, &rn);
+ if (retval == TOMOYO_RETRY_REQUEST)
+ goto retry;
if (retval < 0)
goto out;
+ /*
+ * To be able to specify domainnames with wildcards, use the
+ * pathname specified in the policy (which may contain
+ * wildcard) rather than the pathname passed to execve()
+ * (which never contains wildcard).
+ */
+ if (r.param.path.matched_path) {
+ if (need_kfree)
+ kfree(rn.name);
+ need_kfree = false;
+ /* This is OK because it is read only. */
+ rn = *r.param.path.matched_path;
+ }
- new_domain_name = tmp->buffer;
- if (tomoyo_is_domain_initializer(old_domain->domainname, &r, &l)) {
+ /* Calculate domain to transit to. */
+ switch (tomoyo_transition_type(old_domain->domainname, &rn)) {
+ case TOMOYO_TRANSITION_CONTROL_INITIALIZE:
/* Transit to the child of tomoyo_kernel_domain domain. */
- snprintf(new_domain_name, TOMOYO_MAX_PATHNAME_LEN + 1,
- TOMOYO_ROOT_NAME " " "%s", real_program_name);
- } else if (old_domain == &tomoyo_kernel_domain &&
- !tomoyo_policy_loaded) {
- /*
- * Needn't to transit from kernel domain before starting
- * /sbin/init. But transit from kernel domain if executing
- * initializers because they might start before /sbin/init.
- */
- domain = old_domain;
- } else if (tomoyo_is_domain_keeper(old_domain->domainname, &r, &l)) {
+ snprintf(tmp, TOMOYO_EXEC_TMPSIZE - 1, TOMOYO_ROOT_NAME " "
+ "%s", rn.name);
+ break;
+ case TOMOYO_TRANSITION_CONTROL_KEEP:
/* Keep current domain. */
domain = old_domain;
- } else {
- /* Normal domain transition. */
- snprintf(new_domain_name, TOMOYO_MAX_PATHNAME_LEN + 1,
- "%s %s", old_domain_name, real_program_name);
+ break;
+ default:
+ if (old_domain == &tomoyo_kernel_domain &&
+ !tomoyo_policy_loaded) {
+ /*
+ * Needn't to transit from kernel domain before
+ * starting /sbin/init. But transit from kernel domain
+ * if executing initializers because they might start
+ * before /sbin/init.
+ */
+ domain = old_domain;
+ } else {
+ /* Normal domain transition. */
+ snprintf(tmp, TOMOYO_EXEC_TMPSIZE - 1, "%s %s",
+ old_domain->domainname->name, rn.name);
+ }
+ break;
}
- if (domain || strlen(new_domain_name) >= TOMOYO_MAX_PATHNAME_LEN)
+ if (domain || strlen(tmp) >= TOMOYO_EXEC_TMPSIZE - 10)
goto done;
- domain = tomoyo_find_domain(new_domain_name);
+ domain = tomoyo_find_domain(tmp);
if (domain)
goto done;
- if (is_enforce)
- goto done;
- domain = tomoyo_find_or_assign_new_domain(new_domain_name,
- old_domain->profile);
+ if (is_enforce) {
+ int error = tomoyo_supervisor(&r, "# wants to create domain\n"
+ "%s\n", tmp);
+ if (error == TOMOYO_RETRY_REQUEST)
+ goto retry;
+ if (error < 0)
+ goto done;
+ }
+ domain = tomoyo_assign_domain(tmp, old_domain->profile);
done:
if (domain)
goto out;
- printk(KERN_WARNING "TOMOYO-ERROR: Domain '%s' not defined.\n",
- new_domain_name);
+ printk(KERN_WARNING "TOMOYO-ERROR: Domain '%s' not defined.\n", tmp);
if (is_enforce)
retval = -EPERM;
else
@@ -798,8 +535,8 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm)
/* Update reference count on "struct tomoyo_domain_info". */
atomic_inc(&domain->users);
bprm->cred->security = domain;
- kfree(real_program_name);
- kfree(symlink_program_name);
+ if (need_kfree)
+ kfree(rn.name);
kfree(tmp);
return retval;
}
diff --git a/security/tomoyo/file.c b/security/tomoyo/file.c
index 1c6f8238ec4..9d32f182301 100644
--- a/security/tomoyo/file.c
+++ b/security/tomoyo/file.c
@@ -1,48 +1,88 @@
/*
* security/tomoyo/file.c
*
- * Implementation of the Domain-Based Mandatory Access Control.
- *
- * Copyright (C) 2005-2009 NTT DATA CORPORATION
- *
- * Version: 2.2.0 2009/04/01
+ * Pathname restriction functions.
*
+ * Copyright (C) 2005-2010 NTT DATA CORPORATION
*/
#include "common.h"
#include <linux/slab.h>
-/* Keyword array for single path operations. */
-static const char *tomoyo_path_keyword[TOMOYO_MAX_PATH_OPERATION] = {
+/* Keyword array for operations with one pathname. */
+const char *tomoyo_path_keyword[TOMOYO_MAX_PATH_OPERATION] = {
[TOMOYO_TYPE_READ_WRITE] = "read/write",
[TOMOYO_TYPE_EXECUTE] = "execute",
[TOMOYO_TYPE_READ] = "read",
[TOMOYO_TYPE_WRITE] = "write",
- [TOMOYO_TYPE_CREATE] = "create",
[TOMOYO_TYPE_UNLINK] = "unlink",
- [TOMOYO_TYPE_MKDIR] = "mkdir",
[TOMOYO_TYPE_RMDIR] = "rmdir",
- [TOMOYO_TYPE_MKFIFO] = "mkfifo",
- [TOMOYO_TYPE_MKSOCK] = "mksock",
- [TOMOYO_TYPE_MKBLOCK] = "mkblock",
- [TOMOYO_TYPE_MKCHAR] = "mkchar",
[TOMOYO_TYPE_TRUNCATE] = "truncate",
[TOMOYO_TYPE_SYMLINK] = "symlink",
[TOMOYO_TYPE_REWRITE] = "rewrite",
+ [TOMOYO_TYPE_CHROOT] = "chroot",
+ [TOMOYO_TYPE_UMOUNT] = "unmount",
+};
+
+/* Keyword array for operations with one pathname and three numbers. */
+const char *tomoyo_mkdev_keyword[TOMOYO_MAX_MKDEV_OPERATION] = {
+ [TOMOYO_TYPE_MKBLOCK] = "mkblock",
+ [TOMOYO_TYPE_MKCHAR] = "mkchar",
+};
+
+/* Keyword array for operations with two pathnames. */
+const char *tomoyo_path2_keyword[TOMOYO_MAX_PATH2_OPERATION] = {
+ [TOMOYO_TYPE_LINK] = "link",
+ [TOMOYO_TYPE_RENAME] = "rename",
+ [TOMOYO_TYPE_PIVOT_ROOT] = "pivot_root",
+};
+
+/* Keyword array for operations with one pathname and one number. */
+const char *tomoyo_path_number_keyword[TOMOYO_MAX_PATH_NUMBER_OPERATION] = {
+ [TOMOYO_TYPE_CREATE] = "create",
+ [TOMOYO_TYPE_MKDIR] = "mkdir",
+ [TOMOYO_TYPE_MKFIFO] = "mkfifo",
+ [TOMOYO_TYPE_MKSOCK] = "mksock",
[TOMOYO_TYPE_IOCTL] = "ioctl",
[TOMOYO_TYPE_CHMOD] = "chmod",
[TOMOYO_TYPE_CHOWN] = "chown",
[TOMOYO_TYPE_CHGRP] = "chgrp",
- [TOMOYO_TYPE_CHROOT] = "chroot",
- [TOMOYO_TYPE_MOUNT] = "mount",
- [TOMOYO_TYPE_UMOUNT] = "unmount",
};
-/* Keyword array for double path operations. */
-static const char *tomoyo_path2_keyword[TOMOYO_MAX_PATH2_OPERATION] = {
- [TOMOYO_TYPE_LINK] = "link",
- [TOMOYO_TYPE_RENAME] = "rename",
- [TOMOYO_TYPE_PIVOT_ROOT] = "pivot_root",
+static const u8 tomoyo_p2mac[TOMOYO_MAX_PATH_OPERATION] = {
+ [TOMOYO_TYPE_READ_WRITE] = TOMOYO_MAC_FILE_OPEN,
+ [TOMOYO_TYPE_EXECUTE] = TOMOYO_MAC_FILE_EXECUTE,
+ [TOMOYO_TYPE_READ] = TOMOYO_MAC_FILE_OPEN,
+ [TOMOYO_TYPE_WRITE] = TOMOYO_MAC_FILE_OPEN,
+ [TOMOYO_TYPE_UNLINK] = TOMOYO_MAC_FILE_UNLINK,
+ [TOMOYO_TYPE_RMDIR] = TOMOYO_MAC_FILE_RMDIR,
+ [TOMOYO_TYPE_TRUNCATE] = TOMOYO_MAC_FILE_TRUNCATE,
+ [TOMOYO_TYPE_SYMLINK] = TOMOYO_MAC_FILE_SYMLINK,
+ [TOMOYO_TYPE_REWRITE] = TOMOYO_MAC_FILE_REWRITE,
+ [TOMOYO_TYPE_CHROOT] = TOMOYO_MAC_FILE_CHROOT,
+ [TOMOYO_TYPE_UMOUNT] = TOMOYO_MAC_FILE_UMOUNT,
+};
+
+static const u8 tomoyo_pnnn2mac[TOMOYO_MAX_MKDEV_OPERATION] = {
+ [TOMOYO_TYPE_MKBLOCK] = TOMOYO_MAC_FILE_MKBLOCK,
+ [TOMOYO_TYPE_MKCHAR] = TOMOYO_MAC_FILE_MKCHAR,
+};
+
+static const u8 tomoyo_pp2mac[TOMOYO_MAX_PATH2_OPERATION] = {
+ [TOMOYO_TYPE_LINK] = TOMOYO_MAC_FILE_LINK,
+ [TOMOYO_TYPE_RENAME] = TOMOYO_MAC_FILE_RENAME,
+ [TOMOYO_TYPE_PIVOT_ROOT] = TOMOYO_MAC_FILE_PIVOT_ROOT,
+};
+
+static const u8 tomoyo_pn2mac[TOMOYO_MAX_PATH_NUMBER_OPERATION] = {
+ [TOMOYO_TYPE_CREATE] = TOMOYO_MAC_FILE_CREATE,
+ [TOMOYO_TYPE_MKDIR] = TOMOYO_MAC_FILE_MKDIR,
+ [TOMOYO_TYPE_MKFIFO] = TOMOYO_MAC_FILE_MKFIFO,
+ [TOMOYO_TYPE_MKSOCK] = TOMOYO_MAC_FILE_MKSOCK,
+ [TOMOYO_TYPE_IOCTL] = TOMOYO_MAC_FILE_IOCTL,
+ [TOMOYO_TYPE_CHMOD] = TOMOYO_MAC_FILE_CHMOD,
+ [TOMOYO_TYPE_CHOWN] = TOMOYO_MAC_FILE_CHOWN,
+ [TOMOYO_TYPE_CHGRP] = TOMOYO_MAC_FILE_CHGRP,
};
void tomoyo_put_name_union(struct tomoyo_name_union *ptr)
@@ -50,56 +90,45 @@ void tomoyo_put_name_union(struct tomoyo_name_union *ptr)
if (!ptr)
return;
if (ptr->is_group)
- tomoyo_put_path_group(ptr->group);
+ tomoyo_put_group(ptr->group);
else
tomoyo_put_name(ptr->filename);
}
-bool tomoyo_compare_name_union(const struct tomoyo_path_info *name,
- const struct tomoyo_name_union *ptr)
+const struct tomoyo_path_info *
+tomoyo_compare_name_union(const struct tomoyo_path_info *name,
+ const struct tomoyo_name_union *ptr)
{
if (ptr->is_group)
- return tomoyo_path_matches_group(name, ptr->group, 1);
- return tomoyo_path_matches_pattern(name, ptr->filename);
+ return tomoyo_path_matches_group(name, ptr->group);
+ if (tomoyo_path_matches_pattern(name, ptr->filename))
+ return ptr->filename;
+ return NULL;
}
-static bool tomoyo_compare_name_union_pattern(const struct tomoyo_path_info
- *name,
- const struct tomoyo_name_union
- *ptr, const bool may_use_pattern)
+void tomoyo_put_number_union(struct tomoyo_number_union *ptr)
{
- if (ptr->is_group)
- return tomoyo_path_matches_group(name, ptr->group,
- may_use_pattern);
- if (may_use_pattern || !ptr->filename->is_patterned)
- return tomoyo_path_matches_pattern(name, ptr->filename);
- return false;
+ if (ptr && ptr->is_group)
+ tomoyo_put_group(ptr->group);
}
-/**
- * tomoyo_path2keyword - Get the name of single path operation.
- *
- * @operation: Type of operation.
- *
- * Returns the name of single path operation.
- */
-const char *tomoyo_path2keyword(const u8 operation)
+bool tomoyo_compare_number_union(const unsigned long value,
+ const struct tomoyo_number_union *ptr)
{
- return (operation < TOMOYO_MAX_PATH_OPERATION)
- ? tomoyo_path_keyword[operation] : NULL;
+ if (ptr->is_group)
+ return tomoyo_number_matches_group(value, value, ptr->group);
+ return value >= ptr->values[0] && value <= ptr->values[1];
}
-/**
- * tomoyo_path22keyword - Get the name of double path operation.
- *
- * @operation: Type of operation.
- *
- * Returns the name of double path operation.
- */
-const char *tomoyo_path22keyword(const u8 operation)
+static void tomoyo_add_slash(struct tomoyo_path_info *buf)
{
- return (operation < TOMOYO_MAX_PATH2_OPERATION)
- ? tomoyo_path2_keyword[operation] : NULL;
+ if (buf->is_dir)
+ return;
+ /*
+ * This is OK because tomoyo_encode() reserves space for appending "/".
+ */
+ strcat((char *) buf->name, "/");
+ tomoyo_fill_path_info(buf);
}
/**
@@ -121,69 +150,134 @@ static bool tomoyo_strendswith(const char *name, const char *tail)
}
/**
- * tomoyo_get_path - Get realpath.
+ * tomoyo_get_realpath - Get realpath.
*
+ * @buf: Pointer to "struct tomoyo_path_info".
* @path: Pointer to "struct path".
*
- * Returns pointer to "struct tomoyo_path_info" on success, NULL otherwise.
+ * Returns true on success, false otherwise.
*/
-static struct tomoyo_path_info *tomoyo_get_path(struct path *path)
+static bool tomoyo_get_realpath(struct tomoyo_path_info *buf, struct path *path)
{
- int error;
- struct tomoyo_path_info_with_data *buf = kzalloc(sizeof(*buf),
- GFP_NOFS);
-
- if (!buf)
- return NULL;
- /* Reserve one byte for appending "/". */
- error = tomoyo_realpath_from_path2(path, buf->body,
- sizeof(buf->body) - 2);
- if (!error) {
- buf->head.name = buf->body;
- tomoyo_fill_path_info(&buf->head);
- return &buf->head;
+ buf->name = tomoyo_realpath_from_path(path);
+ if (buf->name) {
+ tomoyo_fill_path_info(buf);
+ return true;
}
- kfree(buf);
- return NULL;
+ return false;
}
-static int tomoyo_update_path2_acl(const u8 type, const char *filename1,
- const char *filename2,
- struct tomoyo_domain_info *const domain,
- const bool is_delete);
-static int tomoyo_update_path_acl(const u8 type, const char *filename,
- struct tomoyo_domain_info *const domain,
- const bool is_delete);
-
-/*
- * tomoyo_globally_readable_list is used for holding list of pathnames which
- * are by default allowed to be open()ed for reading by any process.
+/**
+ * tomoyo_audit_path_log - Audit path request log.
+ *
+ * @r: Pointer to "struct tomoyo_request_info".
*
- * An entry is added by
+ * Returns 0 on success, negative value otherwise.
+ */
+static int tomoyo_audit_path_log(struct tomoyo_request_info *r)
+{
+ const char *operation = tomoyo_path_keyword[r->param.path.operation];
+ const struct tomoyo_path_info *filename = r->param.path.filename;
+ if (r->granted)
+ return 0;
+ tomoyo_warn_log(r, "%s %s", operation, filename->name);
+ return tomoyo_supervisor(r, "allow_%s %s\n", operation,
+ tomoyo_pattern(filename));
+}
+
+/**
+ * tomoyo_audit_path2_log - Audit path/path request log.
*
- * # echo 'allow_read /lib/libc-2.5.so' > \
- * /sys/kernel/security/tomoyo/exception_policy
+ * @r: Pointer to "struct tomoyo_request_info".
*
- * and is deleted by
+ * Returns 0 on success, negative value otherwise.
+ */
+static int tomoyo_audit_path2_log(struct tomoyo_request_info *r)
+{
+ const char *operation = tomoyo_path2_keyword[r->param.path2.operation];
+ const struct tomoyo_path_info *filename1 = r->param.path2.filename1;
+ const struct tomoyo_path_info *filename2 = r->param.path2.filename2;
+ if (r->granted)
+ return 0;
+ tomoyo_warn_log(r, "%s %s %s", operation, filename1->name,
+ filename2->name);
+ return tomoyo_supervisor(r, "allow_%s %s %s\n", operation,
+ tomoyo_pattern(filename1),
+ tomoyo_pattern(filename2));
+}
+
+/**
+ * tomoyo_audit_mkdev_log - Audit path/number/number/number request log.
*
- * # echo 'delete allow_read /lib/libc-2.5.so' > \
- * /sys/kernel/security/tomoyo/exception_policy
+ * @r: Pointer to "struct tomoyo_request_info".
*
- * and all entries are retrieved by
+ * Returns 0 on success, negative value otherwise.
+ */
+static int tomoyo_audit_mkdev_log(struct tomoyo_request_info *r)
+{
+ const char *operation = tomoyo_mkdev_keyword[r->param.mkdev.operation];
+ const struct tomoyo_path_info *filename = r->param.mkdev.filename;
+ const unsigned int major = r->param.mkdev.major;
+ const unsigned int minor = r->param.mkdev.minor;
+ const unsigned int mode = r->param.mkdev.mode;
+ if (r->granted)
+ return 0;
+ tomoyo_warn_log(r, "%s %s 0%o %u %u", operation, filename->name, mode,
+ major, minor);
+ return tomoyo_supervisor(r, "allow_%s %s 0%o %u %u\n", operation,
+ tomoyo_pattern(filename), mode, major, minor);
+}
+
+/**
+ * tomoyo_audit_path_number_log - Audit path/number request log.
*
- * # grep ^allow_read /sys/kernel/security/tomoyo/exception_policy
+ * @r: Pointer to "struct tomoyo_request_info".
+ * @error: Error code.
*
- * In the example above, any process is allowed to
- * open("/lib/libc-2.5.so", O_RDONLY).
- * One exception is, if the domain which current process belongs to is marked
- * as "ignore_global_allow_read", current process can't do so unless explicitly
- * given "allow_read /lib/libc-2.5.so" to the domain which current process
- * belongs to.
+ * Returns 0 on success, negative value otherwise.
*/
-LIST_HEAD(tomoyo_globally_readable_list);
+static int tomoyo_audit_path_number_log(struct tomoyo_request_info *r)
+{
+ const u8 type = r->param.path_number.operation;
+ u8 radix;
+ const struct tomoyo_path_info *filename = r->param.path_number.filename;
+ const char *operation = tomoyo_path_number_keyword[type];
+ char buffer[64];
+ if (r->granted)
+ return 0;
+ switch (type) {
+ case TOMOYO_TYPE_CREATE:
+ case TOMOYO_TYPE_MKDIR:
+ case TOMOYO_TYPE_MKFIFO:
+ case TOMOYO_TYPE_MKSOCK:
+ case TOMOYO_TYPE_CHMOD:
+ radix = TOMOYO_VALUE_TYPE_OCTAL;
+ break;
+ case TOMOYO_TYPE_IOCTL:
+ radix = TOMOYO_VALUE_TYPE_HEXADECIMAL;
+ break;
+ default:
+ radix = TOMOYO_VALUE_TYPE_DECIMAL;
+ break;
+ }
+ tomoyo_print_ulong(buffer, sizeof(buffer), r->param.path_number.number,
+ radix);
+ tomoyo_warn_log(r, "%s %s %s", operation, filename->name, buffer);
+ return tomoyo_supervisor(r, "allow_%s %s %s\n", operation,
+ tomoyo_pattern(filename), buffer);
+}
+
+static bool tomoyo_same_globally_readable(const struct tomoyo_acl_head *a,
+ const struct tomoyo_acl_head *b)
+{
+ return container_of(a, struct tomoyo_readable_file,
+ head)->filename ==
+ container_of(b, struct tomoyo_readable_file,
+ head)->filename;
+}
/**
- * tomoyo_update_globally_readable_entry - Update "struct tomoyo_globally_readable_file_entry" list.
+ * tomoyo_update_globally_readable_entry - Update "struct tomoyo_readable_file" list.
*
* @filename: Filename unconditionally permitted to open() for reading.
* @is_delete: True if it is a delete request.
@@ -195,41 +289,24 @@ LIST_HEAD(tomoyo_globally_readable_list);
static int tomoyo_update_globally_readable_entry(const char *filename,
const bool is_delete)
{
- struct tomoyo_globally_readable_file_entry *ptr;
- struct tomoyo_globally_readable_file_entry e = { };
- int error = is_delete ? -ENOENT : -ENOMEM;
+ struct tomoyo_readable_file e = { };
+ int error;
- if (!tomoyo_is_correct_path(filename, 1, 0, -1))
+ if (!tomoyo_correct_word(filename))
return -EINVAL;
e.filename = tomoyo_get_name(filename);
if (!e.filename)
return -ENOMEM;
- if (mutex_lock_interruptible(&tomoyo_policy_lock))
- goto out;
- list_for_each_entry_rcu(ptr, &tomoyo_globally_readable_list, list) {
- if (ptr->filename != e.filename)
- continue;
- ptr->is_deleted = is_delete;
- error = 0;
- break;
- }
- if (!is_delete && error) {
- struct tomoyo_globally_readable_file_entry *entry =
- tomoyo_commit_ok(&e, sizeof(e));
- if (entry) {
- list_add_tail_rcu(&entry->list,
- &tomoyo_globally_readable_list);
- error = 0;
- }
- }
- mutex_unlock(&tomoyo_policy_lock);
- out:
+ error = tomoyo_update_policy(&e.head, sizeof(e), is_delete,
+ &tomoyo_policy_list
+ [TOMOYO_ID_GLOBALLY_READABLE],
+ tomoyo_same_globally_readable);
tomoyo_put_name(e.filename);
return error;
}
/**
- * tomoyo_is_globally_readable_file - Check if the file is unconditionnaly permitted to be open()ed for reading.
+ * tomoyo_globally_readable_file - Check if the file is unconditionnaly permitted to be open()ed for reading.
*
* @filename: The filename to check.
*
@@ -237,14 +314,15 @@ static int tomoyo_update_globally_readable_entry(const char *filename,
*
* Caller holds tomoyo_read_lock().
*/
-static bool tomoyo_is_globally_readable_file(const struct tomoyo_path_info *
+static bool tomoyo_globally_readable_file(const struct tomoyo_path_info *
filename)
{
- struct tomoyo_globally_readable_file_entry *ptr;
+ struct tomoyo_readable_file *ptr;
bool found = false;
- list_for_each_entry_rcu(ptr, &tomoyo_globally_readable_list, list) {
- if (!ptr->is_deleted &&
+ list_for_each_entry_rcu(ptr, &tomoyo_policy_list
+ [TOMOYO_ID_GLOBALLY_READABLE], head.list) {
+ if (!ptr->head.is_deleted &&
tomoyo_path_matches_pattern(filename, ptr->filename)) {
found = true;
break;
@@ -254,7 +332,7 @@ static bool tomoyo_is_globally_readable_file(const struct tomoyo_path_info *
}
/**
- * tomoyo_write_globally_readable_policy - Write "struct tomoyo_globally_readable_file_entry" list.
+ * tomoyo_write_globally_readable - Write "struct tomoyo_readable_file" list.
*
* @data: String to parse.
* @is_delete: True if it is a delete request.
@@ -263,74 +341,20 @@ static bool tomoyo_is_globally_readable_file(const struct tomoyo_path_info *
*
* Caller holds tomoyo_read_lock().
*/
-int tomoyo_write_globally_readable_policy(char *data, const bool is_delete)
+int tomoyo_write_globally_readable(char *data, const bool is_delete)
{
return tomoyo_update_globally_readable_entry(data, is_delete);
}
-/**
- * tomoyo_read_globally_readable_policy - Read "struct tomoyo_globally_readable_file_entry" list.
- *
- * @head: Pointer to "struct tomoyo_io_buffer".
- *
- * Returns true on success, false otherwise.
- *
- * Caller holds tomoyo_read_lock().
- */
-bool tomoyo_read_globally_readable_policy(struct tomoyo_io_buffer *head)
+static bool tomoyo_same_pattern(const struct tomoyo_acl_head *a,
+ const struct tomoyo_acl_head *b)
{
- struct list_head *pos;
- bool done = true;
-
- list_for_each_cookie(pos, head->read_var2,
- &tomoyo_globally_readable_list) {
- struct tomoyo_globally_readable_file_entry *ptr;
- ptr = list_entry(pos,
- struct tomoyo_globally_readable_file_entry,
- list);
- if (ptr->is_deleted)
- continue;
- done = tomoyo_io_printf(head, TOMOYO_KEYWORD_ALLOW_READ "%s\n",
- ptr->filename->name);
- if (!done)
- break;
- }
- return done;
+ return container_of(a, struct tomoyo_no_pattern, head)->pattern ==
+ container_of(b, struct tomoyo_no_pattern, head)->pattern;
}
-/* tomoyo_pattern_list is used for holding list of pathnames which are used for
- * converting pathnames to pathname patterns during learning mode.
- *
- * An entry is added by
- *
- * # echo 'file_pattern /proc/\$/mounts' > \
- * /sys/kernel/security/tomoyo/exception_policy
- *
- * and is deleted by
- *
- * # echo 'delete file_pattern /proc/\$/mounts' > \
- * /sys/kernel/security/tomoyo/exception_policy
- *
- * and all entries are retrieved by
- *
- * # grep ^file_pattern /sys/kernel/security/tomoyo/exception_policy
- *
- * In the example above, if a process which belongs to a domain which is in
- * learning mode requested open("/proc/1/mounts", O_RDONLY),
- * "allow_read /proc/\$/mounts" is automatically added to the domain which that
- * process belongs to.
- *
- * It is not a desirable behavior that we have to use /proc/\$/ instead of
- * /proc/self/ when current process needs to access only current process's
- * information. As of now, LSM version of TOMOYO is using __d_path() for
- * calculating pathname. Non LSM version of TOMOYO is using its own function
- * which pretends as if /proc/self/ is not a symlink; so that we can forbid
- * current process from accessing other process's information.
- */
-LIST_HEAD(tomoyo_pattern_list);
-
/**
- * tomoyo_update_file_pattern_entry - Update "struct tomoyo_pattern_entry" list.
+ * tomoyo_update_file_pattern_entry - Update "struct tomoyo_no_pattern" list.
*
* @pattern: Pathname pattern.
* @is_delete: True if it is a delete request.
@@ -342,39 +366,23 @@ LIST_HEAD(tomoyo_pattern_list);
static int tomoyo_update_file_pattern_entry(const char *pattern,
const bool is_delete)
{
- struct tomoyo_pattern_entry *ptr;
- struct tomoyo_pattern_entry e = { .pattern = tomoyo_get_name(pattern) };
- int error = is_delete ? -ENOENT : -ENOMEM;
+ struct tomoyo_no_pattern e = { };
+ int error;
+ if (!tomoyo_correct_word(pattern))
+ return -EINVAL;
+ e.pattern = tomoyo_get_name(pattern);
if (!e.pattern)
- return error;
- if (!e.pattern->is_patterned)
- goto out;
- if (mutex_lock_interruptible(&tomoyo_policy_lock))
- goto out;
- list_for_each_entry_rcu(ptr, &tomoyo_pattern_list, list) {
- if (e.pattern != ptr->pattern)
- continue;
- ptr->is_deleted = is_delete;
- error = 0;
- break;
- }
- if (!is_delete && error) {
- struct tomoyo_pattern_entry *entry =
- tomoyo_commit_ok(&e, sizeof(e));
- if (entry) {
- list_add_tail_rcu(&entry->list, &tomoyo_pattern_list);
- error = 0;
- }
- }
- mutex_unlock(&tomoyo_policy_lock);
- out:
+ return -ENOMEM;
+ error = tomoyo_update_policy(&e.head, sizeof(e), is_delete,
+ &tomoyo_policy_list[TOMOYO_ID_PATTERN],
+ tomoyo_same_pattern);
tomoyo_put_name(e.pattern);
return error;
}
/**
- * tomoyo_get_file_pattern - Get patterned pathname.
+ * tomoyo_pattern - Get patterned pathname.
*
* @filename: The filename to find patterned pathname.
*
@@ -382,14 +390,14 @@ static int tomoyo_update_file_pattern_entry(const char *pattern,
*
* Caller holds tomoyo_read_lock().
*/
-static const struct tomoyo_path_info *
-tomoyo_get_file_pattern(const struct tomoyo_path_info *filename)
+const char *tomoyo_pattern(const struct tomoyo_path_info *filename)
{
- struct tomoyo_pattern_entry *ptr;
+ struct tomoyo_no_pattern *ptr;
const struct tomoyo_path_info *pattern = NULL;
- list_for_each_entry_rcu(ptr, &tomoyo_pattern_list, list) {
- if (ptr->is_deleted)
+ list_for_each_entry_rcu(ptr, &tomoyo_policy_list[TOMOYO_ID_PATTERN],
+ head.list) {
+ if (ptr->head.is_deleted)
continue;
if (!tomoyo_path_matches_pattern(filename, ptr->pattern))
continue;
@@ -403,11 +411,11 @@ tomoyo_get_file_pattern(const struct tomoyo_path_info *filename)
}
if (pattern)
filename = pattern;
- return filename;
+ return filename->name;
}
/**
- * tomoyo_write_pattern_policy - Write "struct tomoyo_pattern_entry" list.
+ * tomoyo_write_pattern - Write "struct tomoyo_no_pattern" list.
*
* @data: String to parse.
* @is_delete: True if it is a delete request.
@@ -416,71 +424,21 @@ tomoyo_get_file_pattern(const struct tomoyo_path_info *filename)
*
* Caller holds tomoyo_read_lock().
*/
-int tomoyo_write_pattern_policy(char *data, const bool is_delete)
+int tomoyo_write_pattern(char *data, const bool is_delete)
{
return tomoyo_update_file_pattern_entry(data, is_delete);
}
-/**
- * tomoyo_read_file_pattern - Read "struct tomoyo_pattern_entry" list.
- *
- * @head: Pointer to "struct tomoyo_io_buffer".
- *
- * Returns true on success, false otherwise.
- *
- * Caller holds tomoyo_read_lock().
- */
-bool tomoyo_read_file_pattern(struct tomoyo_io_buffer *head)
+static bool tomoyo_same_no_rewrite(const struct tomoyo_acl_head *a,
+ const struct tomoyo_acl_head *b)
{
- struct list_head *pos;
- bool done = true;
-
- list_for_each_cookie(pos, head->read_var2, &tomoyo_pattern_list) {
- struct tomoyo_pattern_entry *ptr;
- ptr = list_entry(pos, struct tomoyo_pattern_entry, list);
- if (ptr->is_deleted)
- continue;
- done = tomoyo_io_printf(head, TOMOYO_KEYWORD_FILE_PATTERN
- "%s\n", ptr->pattern->name);
- if (!done)
- break;
- }
- return done;
+ return container_of(a, struct tomoyo_no_rewrite, head)->pattern
+ == container_of(b, struct tomoyo_no_rewrite, head)
+ ->pattern;
}
-/*
- * tomoyo_no_rewrite_list is used for holding list of pathnames which are by
- * default forbidden to modify already written content of a file.
- *
- * An entry is added by
- *
- * # echo 'deny_rewrite /var/log/messages' > \
- * /sys/kernel/security/tomoyo/exception_policy
- *
- * and is deleted by
- *
- * # echo 'delete deny_rewrite /var/log/messages' > \
- * /sys/kernel/security/tomoyo/exception_policy
- *
- * and all entries are retrieved by
- *
- * # grep ^deny_rewrite /sys/kernel/security/tomoyo/exception_policy
- *
- * In the example above, if a process requested to rewrite /var/log/messages ,
- * the process can't rewrite unless the domain which that process belongs to
- * has "allow_rewrite /var/log/messages" entry.
- *
- * It is not a desirable behavior that we have to add "\040(deleted)" suffix
- * when we want to allow rewriting already unlink()ed file. As of now,
- * LSM version of TOMOYO is using __d_path() for calculating pathname.
- * Non LSM version of TOMOYO is using its own function which doesn't append
- * " (deleted)" suffix if the file is already unlink()ed; so that we don't
- * need to worry whether the file is already unlink()ed or not.
- */
-LIST_HEAD(tomoyo_no_rewrite_list);
-
/**
- * tomoyo_update_no_rewrite_entry - Update "struct tomoyo_no_rewrite_entry" list.
+ * tomoyo_update_no_rewrite_entry - Update "struct tomoyo_no_rewrite" list.
*
* @pattern: Pathname pattern that are not rewritable by default.
* @is_delete: True if it is a delete request.
@@ -492,41 +450,23 @@ LIST_HEAD(tomoyo_no_rewrite_list);
static int tomoyo_update_no_rewrite_entry(const char *pattern,
const bool is_delete)
{
- struct tomoyo_no_rewrite_entry *ptr;
- struct tomoyo_no_rewrite_entry e = { };
- int error = is_delete ? -ENOENT : -ENOMEM;
+ struct tomoyo_no_rewrite e = { };
+ int error;
- if (!tomoyo_is_correct_path(pattern, 0, 0, 0))
+ if (!tomoyo_correct_word(pattern))
return -EINVAL;
e.pattern = tomoyo_get_name(pattern);
if (!e.pattern)
- return error;
- if (mutex_lock_interruptible(&tomoyo_policy_lock))
- goto out;
- list_for_each_entry_rcu(ptr, &tomoyo_no_rewrite_list, list) {
- if (ptr->pattern != e.pattern)
- continue;
- ptr->is_deleted = is_delete;
- error = 0;
- break;
- }
- if (!is_delete && error) {
- struct tomoyo_no_rewrite_entry *entry =
- tomoyo_commit_ok(&e, sizeof(e));
- if (entry) {
- list_add_tail_rcu(&entry->list,
- &tomoyo_no_rewrite_list);
- error = 0;
- }
- }
- mutex_unlock(&tomoyo_policy_lock);
- out:
+ return -ENOMEM;
+ error = tomoyo_update_policy(&e.head, sizeof(e), is_delete,
+ &tomoyo_policy_list[TOMOYO_ID_NO_REWRITE],
+ tomoyo_same_no_rewrite);
tomoyo_put_name(e.pattern);
return error;
}
/**
- * tomoyo_is_no_rewrite_file - Check if the given pathname is not permitted to be rewrited.
+ * tomoyo_no_rewrite_file - Check if the given pathname is not permitted to be rewrited.
*
* @filename: Filename to check.
*
@@ -535,13 +475,14 @@ static int tomoyo_update_no_rewrite_entry(const char *pattern,
*
* Caller holds tomoyo_read_lock().
*/
-static bool tomoyo_is_no_rewrite_file(const struct tomoyo_path_info *filename)
+static bool tomoyo_no_rewrite_file(const struct tomoyo_path_info *filename)
{
- struct tomoyo_no_rewrite_entry *ptr;
+ struct tomoyo_no_rewrite *ptr;
bool found = false;
- list_for_each_entry_rcu(ptr, &tomoyo_no_rewrite_list, list) {
- if (ptr->is_deleted)
+ list_for_each_entry_rcu(ptr, &tomoyo_policy_list[TOMOYO_ID_NO_REWRITE],
+ head.list) {
+ if (ptr->head.is_deleted)
continue;
if (!tomoyo_path_matches_pattern(filename, ptr->pattern))
continue;
@@ -552,7 +493,7 @@ static bool tomoyo_is_no_rewrite_file(const struct tomoyo_path_info *filename)
}
/**
- * tomoyo_write_no_rewrite_policy - Write "struct tomoyo_no_rewrite_entry" list.
+ * tomoyo_write_no_rewrite - Write "struct tomoyo_no_rewrite" list.
*
* @data: String to parse.
* @is_delete: True if it is a delete request.
@@ -561,214 +502,103 @@ static bool tomoyo_is_no_rewrite_file(const struct tomoyo_path_info *filename)
*
* Caller holds tomoyo_read_lock().
*/
-int tomoyo_write_no_rewrite_policy(char *data, const bool is_delete)
+int tomoyo_write_no_rewrite(char *data, const bool is_delete)
{
return tomoyo_update_no_rewrite_entry(data, is_delete);
}
-/**
- * tomoyo_read_no_rewrite_policy - Read "struct tomoyo_no_rewrite_entry" list.
- *
- * @head: Pointer to "struct tomoyo_io_buffer".
- *
- * Returns true on success, false otherwise.
- *
- * Caller holds tomoyo_read_lock().
- */
-bool tomoyo_read_no_rewrite_policy(struct tomoyo_io_buffer *head)
+static bool tomoyo_check_path_acl(struct tomoyo_request_info *r,
+ const struct tomoyo_acl_info *ptr)
{
- struct list_head *pos;
- bool done = true;
-
- list_for_each_cookie(pos, head->read_var2, &tomoyo_no_rewrite_list) {
- struct tomoyo_no_rewrite_entry *ptr;
- ptr = list_entry(pos, struct tomoyo_no_rewrite_entry, list);
- if (ptr->is_deleted)
- continue;
- done = tomoyo_io_printf(head, TOMOYO_KEYWORD_DENY_REWRITE
- "%s\n", ptr->pattern->name);
- if (!done)
- break;
+ const struct tomoyo_path_acl *acl = container_of(ptr, typeof(*acl),
+ head);
+ if (acl->perm & (1 << r->param.path.operation)) {
+ r->param.path.matched_path =
+ tomoyo_compare_name_union(r->param.path.filename,
+ &acl->name);
+ return r->param.path.matched_path != NULL;
}
- return done;
+ return false;
}
-/**
- * tomoyo_update_file_acl - Update file's read/write/execute ACL.
- *
- * @filename: Filename.
- * @perm: Permission (between 1 to 7).
- * @domain: Pointer to "struct tomoyo_domain_info".
- * @is_delete: True if it is a delete request.
- *
- * Returns 0 on success, negative value otherwise.
- *
- * This is legacy support interface for older policy syntax.
- * Current policy syntax uses "allow_read/write" instead of "6",
- * "allow_read" instead of "4", "allow_write" instead of "2",
- * "allow_execute" instead of "1".
- *
- * Caller holds tomoyo_read_lock().
- */
-static int tomoyo_update_file_acl(const char *filename, u8 perm,
- struct tomoyo_domain_info * const domain,
- const bool is_delete)
+static bool tomoyo_check_path_number_acl(struct tomoyo_request_info *r,
+ const struct tomoyo_acl_info *ptr)
{
- if (perm > 7 || !perm) {
- printk(KERN_DEBUG "%s: Invalid permission '%d %s'\n",
- __func__, perm, filename);
- return -EINVAL;
- }
- if (filename[0] != '@' && tomoyo_strendswith(filename, "/"))
- /*
- * Only 'allow_mkdir' and 'allow_rmdir' are valid for
- * directory permissions.
- */
- return 0;
- if (perm & 4)
- tomoyo_update_path_acl(TOMOYO_TYPE_READ, filename, domain,
- is_delete);
- if (perm & 2)
- tomoyo_update_path_acl(TOMOYO_TYPE_WRITE, filename, domain,
- is_delete);
- if (perm & 1)
- tomoyo_update_path_acl(TOMOYO_TYPE_EXECUTE, filename, domain,
- is_delete);
- return 0;
+ const struct tomoyo_path_number_acl *acl =
+ container_of(ptr, typeof(*acl), head);
+ return (acl->perm & (1 << r->param.path_number.operation)) &&
+ tomoyo_compare_number_union(r->param.path_number.number,
+ &acl->number) &&
+ tomoyo_compare_name_union(r->param.path_number.filename,
+ &acl->name);
}
-/**
- * tomoyo_path_acl2 - Check permission for single path operation.
- *
- * @domain: Pointer to "struct tomoyo_domain_info".
- * @filename: Filename to check.
- * @perm: Permission.
- * @may_use_pattern: True if patterned ACL is permitted.
- *
- * Returns 0 on success, -EPERM otherwise.
- *
- * Caller holds tomoyo_read_lock().
- */
-static int tomoyo_path_acl2(const struct tomoyo_domain_info *domain,
- const struct tomoyo_path_info *filename,
- const u32 perm, const bool may_use_pattern)
+static bool tomoyo_check_path2_acl(struct tomoyo_request_info *r,
+ const struct tomoyo_acl_info *ptr)
{
- struct tomoyo_acl_info *ptr;
- int error = -EPERM;
-
- list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) {
- struct tomoyo_path_acl *acl;
- if (ptr->type != TOMOYO_TYPE_PATH_ACL)
- continue;
- acl = container_of(ptr, struct tomoyo_path_acl, head);
- if (perm <= 0xFFFF) {
- if (!(acl->perm & perm))
- continue;
- } else {
- if (!(acl->perm_high & (perm >> 16)))
- continue;
- }
- if (!tomoyo_compare_name_union_pattern(filename, &acl->name,
- may_use_pattern))
- continue;
- error = 0;
- break;
- }
- return error;
+ const struct tomoyo_path2_acl *acl =
+ container_of(ptr, typeof(*acl), head);
+ return (acl->perm & (1 << r->param.path2.operation)) &&
+ tomoyo_compare_name_union(r->param.path2.filename1, &acl->name1)
+ && tomoyo_compare_name_union(r->param.path2.filename2,
+ &acl->name2);
}
-/**
- * tomoyo_check_file_acl - Check permission for opening files.
- *
- * @domain: Pointer to "struct tomoyo_domain_info".
- * @filename: Filename to check.
- * @operation: Mode ("read" or "write" or "read/write" or "execute").
- *
- * Returns 0 on success, -EPERM otherwise.
- *
- * Caller holds tomoyo_read_lock().
- */
-static int tomoyo_check_file_acl(const struct tomoyo_domain_info *domain,
- const struct tomoyo_path_info *filename,
- const u8 operation)
+static bool tomoyo_check_mkdev_acl(struct tomoyo_request_info *r,
+ const struct tomoyo_acl_info *ptr)
{
- u32 perm = 0;
-
- if (!tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE))
- return 0;
- if (operation == 6)
- perm = 1 << TOMOYO_TYPE_READ_WRITE;
- else if (operation == 4)
- perm = 1 << TOMOYO_TYPE_READ;
- else if (operation == 2)
- perm = 1 << TOMOYO_TYPE_WRITE;
- else if (operation == 1)
- perm = 1 << TOMOYO_TYPE_EXECUTE;
- else
- BUG();
- return tomoyo_path_acl2(domain, filename, perm, operation != 1);
+ const struct tomoyo_mkdev_acl *acl =
+ container_of(ptr, typeof(*acl), head);
+ return (acl->perm & (1 << r->param.mkdev.operation)) &&
+ tomoyo_compare_number_union(r->param.mkdev.mode,
+ &acl->mode) &&
+ tomoyo_compare_number_union(r->param.mkdev.major,
+ &acl->major) &&
+ tomoyo_compare_number_union(r->param.mkdev.minor,
+ &acl->minor) &&
+ tomoyo_compare_name_union(r->param.mkdev.filename,
+ &acl->name);
}
-/**
- * tomoyo_check_file_perm2 - Check permission for opening files.
- *
- * @domain: Pointer to "struct tomoyo_domain_info".
- * @filename: Filename to check.
- * @perm: Mode ("read" or "write" or "read/write" or "execute").
- * @operation: Operation name passed used for verbose mode.
- * @mode: Access control mode.
- *
- * Returns 0 on success, negative value otherwise.
- *
- * Caller holds tomoyo_read_lock().
- */
-static int tomoyo_check_file_perm2(struct tomoyo_domain_info * const domain,
- const struct tomoyo_path_info *filename,
- const u8 perm, const char *operation,
- const u8 mode)
+static bool tomoyo_same_path_acl(const struct tomoyo_acl_info *a,
+ const struct tomoyo_acl_info *b)
{
- const bool is_enforce = (mode == 3);
- const char *msg = "<unknown>";
- int error = 0;
+ const struct tomoyo_path_acl *p1 = container_of(a, typeof(*p1), head);
+ const struct tomoyo_path_acl *p2 = container_of(b, typeof(*p2), head);
+ return tomoyo_same_acl_head(&p1->head, &p2->head) &&
+ tomoyo_same_name_union(&p1->name, &p2->name);
+}
- if (!filename)
- return 0;
- error = tomoyo_check_file_acl(domain, filename, perm);
- if (error && perm == 4 && !domain->ignore_global_allow_read
- && tomoyo_is_globally_readable_file(filename))
- error = 0;
- if (perm == 6)
- msg = tomoyo_path2keyword(TOMOYO_TYPE_READ_WRITE);
- else if (perm == 4)
- msg = tomoyo_path2keyword(TOMOYO_TYPE_READ);
- else if (perm == 2)
- msg = tomoyo_path2keyword(TOMOYO_TYPE_WRITE);
- else if (perm == 1)
- msg = tomoyo_path2keyword(TOMOYO_TYPE_EXECUTE);
- else
- BUG();
- if (!error)
- return 0;
- if (tomoyo_verbose_mode(domain))
- printk(KERN_WARNING "TOMOYO-%s: Access '%s(%s) %s' denied "
- "for %s\n", tomoyo_get_msg(is_enforce), msg, operation,
- filename->name, tomoyo_get_last_name(domain));
- if (is_enforce)
- return error;
- if (mode == 1 && tomoyo_domain_quota_is_ok(domain)) {
- /* Don't use patterns for execute permission. */
- const struct tomoyo_path_info *patterned_file = (perm != 1) ?
- tomoyo_get_file_pattern(filename) : filename;
- tomoyo_update_file_acl(patterned_file->name, perm,
- domain, false);
+static bool tomoyo_merge_path_acl(struct tomoyo_acl_info *a,
+ struct tomoyo_acl_info *b,
+ const bool is_delete)
+{
+ u16 * const a_perm = &container_of(a, struct tomoyo_path_acl, head)
+ ->perm;
+ u16 perm = *a_perm;
+ const u16 b_perm = container_of(b, struct tomoyo_path_acl, head)->perm;
+ if (is_delete) {
+ perm &= ~b_perm;
+ if ((perm & TOMOYO_RW_MASK) != TOMOYO_RW_MASK)
+ perm &= ~(1 << TOMOYO_TYPE_READ_WRITE);
+ else if (!(perm & (1 << TOMOYO_TYPE_READ_WRITE)))
+ perm &= ~TOMOYO_RW_MASK;
+ } else {
+ perm |= b_perm;
+ if ((perm & TOMOYO_RW_MASK) == TOMOYO_RW_MASK)
+ perm |= (1 << TOMOYO_TYPE_READ_WRITE);
+ else if (perm & (1 << TOMOYO_TYPE_READ_WRITE))
+ perm |= TOMOYO_RW_MASK;
}
- return 0;
+ *a_perm = perm;
+ return !perm;
}
/**
- * tomoyo_write_file_policy - Update file related list.
+ * tomoyo_update_path_acl - Update "struct tomoyo_path_acl" list.
*
- * @data: String to parse.
+ * @type: Type of operation.
+ * @filename: Filename.
* @domain: Pointer to "struct tomoyo_domain_info".
* @is_delete: True if it is a delete request.
*
@@ -776,48 +606,65 @@ static int tomoyo_check_file_perm2(struct tomoyo_domain_info * const domain,
*
* Caller holds tomoyo_read_lock().
*/
-int tomoyo_write_file_policy(char *data, struct tomoyo_domain_info *domain,
- const bool is_delete)
+static int tomoyo_update_path_acl(const u8 type, const char *filename,
+ struct tomoyo_domain_info * const domain,
+ const bool is_delete)
{
- char *filename = strchr(data, ' ');
- char *filename2;
- unsigned int perm;
- u8 type;
-
- if (!filename)
+ struct tomoyo_path_acl e = {
+ .head.type = TOMOYO_TYPE_PATH_ACL,
+ .perm = 1 << type
+ };
+ int error;
+ if (e.perm == (1 << TOMOYO_TYPE_READ_WRITE))
+ e.perm |= TOMOYO_RW_MASK;
+ if (!tomoyo_parse_name_union(filename, &e.name))
return -EINVAL;
- *filename++ = '\0';
- if (sscanf(data, "%u", &perm) == 1)
- return tomoyo_update_file_acl(filename, (u8) perm, domain,
- is_delete);
- if (strncmp(data, "allow_", 6))
- goto out;
- data += 6;
- for (type = 0; type < TOMOYO_MAX_PATH_OPERATION; type++) {
- if (strcmp(data, tomoyo_path_keyword[type]))
- continue;
- return tomoyo_update_path_acl(type, filename, domain,
- is_delete);
- }
- filename2 = strchr(filename, ' ');
- if (!filename2)
- goto out;
- *filename2++ = '\0';
- for (type = 0; type < TOMOYO_MAX_PATH2_OPERATION; type++) {
- if (strcmp(data, tomoyo_path2_keyword[type]))
- continue;
- return tomoyo_update_path2_acl(type, filename, filename2,
- domain, is_delete);
- }
- out:
- return -EINVAL;
+ error = tomoyo_update_domain(&e.head, sizeof(e), is_delete, domain,
+ tomoyo_same_path_acl,
+ tomoyo_merge_path_acl);
+ tomoyo_put_name_union(&e.name);
+ return error;
+}
+
+static bool tomoyo_same_mkdev_acl(const struct tomoyo_acl_info *a,
+ const struct tomoyo_acl_info *b)
+{
+ const struct tomoyo_mkdev_acl *p1 = container_of(a, typeof(*p1),
+ head);
+ const struct tomoyo_mkdev_acl *p2 = container_of(b, typeof(*p2),
+ head);
+ return tomoyo_same_acl_head(&p1->head, &p2->head)
+ && tomoyo_same_name_union(&p1->name, &p2->name)
+ && tomoyo_same_number_union(&p1->mode, &p2->mode)
+ && tomoyo_same_number_union(&p1->major, &p2->major)
+ && tomoyo_same_number_union(&p1->minor, &p2->minor);
+}
+
+static bool tomoyo_merge_mkdev_acl(struct tomoyo_acl_info *a,
+ struct tomoyo_acl_info *b,
+ const bool is_delete)
+{
+ u8 *const a_perm = &container_of(a, struct tomoyo_mkdev_acl,
+ head)->perm;
+ u8 perm = *a_perm;
+ const u8 b_perm = container_of(b, struct tomoyo_mkdev_acl, head)
+ ->perm;
+ if (is_delete)
+ perm &= ~b_perm;
+ else
+ perm |= b_perm;
+ *a_perm = perm;
+ return !perm;
}
/**
- * tomoyo_update_path_acl - Update "struct tomoyo_path_acl" list.
+ * tomoyo_update_mkdev_acl - Update "struct tomoyo_mkdev_acl" list.
*
* @type: Type of operation.
* @filename: Filename.
+ * @mode: Create mode.
+ * @major: Device major number.
+ * @minor: Device minor number.
* @domain: Pointer to "struct tomoyo_domain_info".
* @is_delete: True if it is a delete request.
*
@@ -825,71 +672,58 @@ int tomoyo_write_file_policy(char *data, struct tomoyo_domain_info *domain,
*
* Caller holds tomoyo_read_lock().
*/
-static int tomoyo_update_path_acl(const u8 type, const char *filename,
- struct tomoyo_domain_info *const domain,
- const bool is_delete)
+static int tomoyo_update_mkdev_acl(const u8 type, const char *filename,
+ char *mode, char *major, char *minor,
+ struct tomoyo_domain_info * const
+ domain, const bool is_delete)
{
- static const u32 tomoyo_rw_mask =
- (1 << TOMOYO_TYPE_READ) | (1 << TOMOYO_TYPE_WRITE);
- const u32 perm = 1 << type;
- struct tomoyo_acl_info *ptr;
- struct tomoyo_path_acl e = {
- .head.type = TOMOYO_TYPE_PATH_ACL,
- .perm_high = perm >> 16,
- .perm = perm
+ struct tomoyo_mkdev_acl e = {
+ .head.type = TOMOYO_TYPE_MKDEV_ACL,
+ .perm = 1 << type
};
int error = is_delete ? -ENOENT : -ENOMEM;
-
- if (type == TOMOYO_TYPE_READ_WRITE)
- e.perm |= tomoyo_rw_mask;
- if (!domain)
- return -EINVAL;
- if (!tomoyo_parse_name_union(filename, &e.name))
- return -EINVAL;
- if (mutex_lock_interruptible(&tomoyo_policy_lock))
+ if (!tomoyo_parse_name_union(filename, &e.name) ||
+ !tomoyo_parse_number_union(mode, &e.mode) ||
+ !tomoyo_parse_number_union(major, &e.major) ||
+ !tomoyo_parse_number_union(minor, &e.minor))
goto out;
- list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) {
- struct tomoyo_path_acl *acl =
- container_of(ptr, struct tomoyo_path_acl, head);
- if (!tomoyo_is_same_path_acl(acl, &e))
- continue;
- if (is_delete) {
- if (perm <= 0xFFFF)
- acl->perm &= ~perm;
- else
- acl->perm_high &= ~(perm >> 16);
- if ((acl->perm & tomoyo_rw_mask) != tomoyo_rw_mask)
- acl->perm &= ~(1 << TOMOYO_TYPE_READ_WRITE);
- else if (!(acl->perm & (1 << TOMOYO_TYPE_READ_WRITE)))
- acl->perm &= ~tomoyo_rw_mask;
- } else {
- if (perm <= 0xFFFF)
- acl->perm |= perm;
- else
- acl->perm_high |= (perm >> 16);
- if ((acl->perm & tomoyo_rw_mask) == tomoyo_rw_mask)
- acl->perm |= 1 << TOMOYO_TYPE_READ_WRITE;
- else if (acl->perm & (1 << TOMOYO_TYPE_READ_WRITE))
- acl->perm |= tomoyo_rw_mask;
- }
- error = 0;
- break;
- }
- if (!is_delete && error) {
- struct tomoyo_path_acl *entry =
- tomoyo_commit_ok(&e, sizeof(e));
- if (entry) {
- list_add_tail_rcu(&entry->head.list,
- &domain->acl_info_list);
- error = 0;
- }
- }
- mutex_unlock(&tomoyo_policy_lock);
+ error = tomoyo_update_domain(&e.head, sizeof(e), is_delete, domain,
+ tomoyo_same_mkdev_acl,
+ tomoyo_merge_mkdev_acl);
out:
tomoyo_put_name_union(&e.name);
+ tomoyo_put_number_union(&e.mode);
+ tomoyo_put_number_union(&e.major);
+ tomoyo_put_number_union(&e.minor);
return error;
}
+static bool tomoyo_same_path2_acl(const struct tomoyo_acl_info *a,
+ const struct tomoyo_acl_info *b)
+{
+ const struct tomoyo_path2_acl *p1 = container_of(a, typeof(*p1), head);
+ const struct tomoyo_path2_acl *p2 = container_of(b, typeof(*p2), head);
+ return tomoyo_same_acl_head(&p1->head, &p2->head)
+ && tomoyo_same_name_union(&p1->name1, &p2->name1)
+ && tomoyo_same_name_union(&p1->name2, &p2->name2);
+}
+
+static bool tomoyo_merge_path2_acl(struct tomoyo_acl_info *a,
+ struct tomoyo_acl_info *b,
+ const bool is_delete)
+{
+ u8 * const a_perm = &container_of(a, struct tomoyo_path2_acl, head)
+ ->perm;
+ u8 perm = *a_perm;
+ const u8 b_perm = container_of(b, struct tomoyo_path2_acl, head)->perm;
+ if (is_delete)
+ perm &= ~b_perm;
+ else
+ perm |= b_perm;
+ *a_perm = perm;
+ return !perm;
+}
+
/**
* tomoyo_update_path2_acl - Update "struct tomoyo_path2_acl" list.
*
@@ -905,46 +739,20 @@ static int tomoyo_update_path_acl(const u8 type, const char *filename,
*/
static int tomoyo_update_path2_acl(const u8 type, const char *filename1,
const char *filename2,
- struct tomoyo_domain_info *const domain,
+ struct tomoyo_domain_info * const domain,
const bool is_delete)
{
- const u8 perm = 1 << type;
struct tomoyo_path2_acl e = {
.head.type = TOMOYO_TYPE_PATH2_ACL,
- .perm = perm
+ .perm = 1 << type
};
- struct tomoyo_acl_info *ptr;
int error = is_delete ? -ENOENT : -ENOMEM;
-
- if (!domain)
- return -EINVAL;
if (!tomoyo_parse_name_union(filename1, &e.name1) ||
!tomoyo_parse_name_union(filename2, &e.name2))
goto out;
- if (mutex_lock_interruptible(&tomoyo_policy_lock))
- goto out;
- list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) {
- struct tomoyo_path2_acl *acl =
- container_of(ptr, struct tomoyo_path2_acl, head);
- if (!tomoyo_is_same_path2_acl(acl, &e))
- continue;
- if (is_delete)
- acl->perm &= ~perm;
- else
- acl->perm |= perm;
- error = 0;
- break;
- }
- if (!is_delete && error) {
- struct tomoyo_path2_acl *entry =
- tomoyo_commit_ok(&e, sizeof(e));
- if (entry) {
- list_add_tail_rcu(&entry->head.list,
- &domain->acl_info_list);
- error = 0;
- }
- }
- mutex_unlock(&tomoyo_policy_lock);
+ error = tomoyo_update_domain(&e.head, sizeof(e), is_delete, domain,
+ tomoyo_same_path2_acl,
+ tomoyo_merge_path2_acl);
out:
tomoyo_put_name_union(&e.name1);
tomoyo_put_name_union(&e.name2);
@@ -952,134 +760,158 @@ static int tomoyo_update_path2_acl(const u8 type, const char *filename1,
}
/**
- * tomoyo_path_acl - Check permission for single path operation.
- *
- * @domain: Pointer to "struct tomoyo_domain_info".
- * @type: Type of operation.
- * @filename: Filename to check.
- *
- * Returns 0 on success, negative value otherwise.
- *
- * Caller holds tomoyo_read_lock().
- */
-static int tomoyo_path_acl(struct tomoyo_domain_info *domain, const u8 type,
- const struct tomoyo_path_info *filename)
-{
- if (!tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE))
- return 0;
- return tomoyo_path_acl2(domain, filename, 1 << type, 1);
-}
-
-/**
- * tomoyo_path2_acl - Check permission for double path operation.
+ * tomoyo_path_permission - Check permission for single path operation.
*
- * @domain: Pointer to "struct tomoyo_domain_info".
- * @type: Type of operation.
- * @filename1: First filename to check.
- * @filename2: Second filename to check.
- *
- * Returns 0 on success, -EPERM otherwise.
- *
- * Caller holds tomoyo_read_lock().
- */
-static int tomoyo_path2_acl(const struct tomoyo_domain_info *domain,
- const u8 type,
- const struct tomoyo_path_info *filename1,
- const struct tomoyo_path_info *filename2)
-{
- struct tomoyo_acl_info *ptr;
- const u8 perm = 1 << type;
- int error = -EPERM;
-
- if (!tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE))
- return 0;
- list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) {
- struct tomoyo_path2_acl *acl;
- if (ptr->type != TOMOYO_TYPE_PATH2_ACL)
- continue;
- acl = container_of(ptr, struct tomoyo_path2_acl, head);
- if (!(acl->perm & perm))
- continue;
- if (!tomoyo_compare_name_union(filename1, &acl->name1))
- continue;
- if (!tomoyo_compare_name_union(filename2, &acl->name2))
- continue;
- error = 0;
- break;
- }
- return error;
-}
-
-/**
- * tomoyo_path_permission2 - Check permission for single path operation.
- *
- * @domain: Pointer to "struct tomoyo_domain_info".
+ * @r: Pointer to "struct tomoyo_request_info".
* @operation: Type of operation.
* @filename: Filename to check.
- * @mode: Access control mode.
*
* Returns 0 on success, negative value otherwise.
*
* Caller holds tomoyo_read_lock().
*/
-static int tomoyo_path_permission2(struct tomoyo_domain_info *const domain,
- u8 operation,
- const struct tomoyo_path_info *filename,
- const u8 mode)
+int tomoyo_path_permission(struct tomoyo_request_info *r, u8 operation,
+ const struct tomoyo_path_info *filename)
{
- const char *msg;
int error;
- const bool is_enforce = (mode == 3);
- if (!mode)
- return 0;
next:
- error = tomoyo_path_acl(domain, operation, filename);
- msg = tomoyo_path2keyword(operation);
- if (!error)
- goto ok;
- if (tomoyo_verbose_mode(domain))
- printk(KERN_WARNING "TOMOYO-%s: Access '%s %s' denied for %s\n",
- tomoyo_get_msg(is_enforce), msg, filename->name,
- tomoyo_get_last_name(domain));
- if (mode == 1 && tomoyo_domain_quota_is_ok(domain)) {
- const char *name = tomoyo_get_file_pattern(filename)->name;
- tomoyo_update_path_acl(operation, name, domain, false);
- }
- if (!is_enforce)
- error = 0;
- ok:
+ r->type = tomoyo_p2mac[operation];
+ r->mode = tomoyo_get_mode(r->profile, r->type);
+ if (r->mode == TOMOYO_CONFIG_DISABLED)
+ return 0;
+ r->param_type = TOMOYO_TYPE_PATH_ACL;
+ r->param.path.filename = filename;
+ r->param.path.operation = operation;
+ do {
+ tomoyo_check_acl(r, tomoyo_check_path_acl);
+ if (!r->granted && operation == TOMOYO_TYPE_READ &&
+ !r->domain->ignore_global_allow_read &&
+ tomoyo_globally_readable_file(filename))
+ r->granted = true;
+ error = tomoyo_audit_path_log(r);
+ /*
+ * Do not retry for execute request, for alias may have
+ * changed.
+ */
+ } while (error == TOMOYO_RETRY_REQUEST &&
+ operation != TOMOYO_TYPE_EXECUTE);
/*
* Since "allow_truncate" doesn't imply "allow_rewrite" permission,
* we need to check "allow_rewrite" permission if the filename is
* specified by "deny_rewrite" keyword.
*/
if (!error && operation == TOMOYO_TYPE_TRUNCATE &&
- tomoyo_is_no_rewrite_file(filename)) {
+ tomoyo_no_rewrite_file(filename)) {
operation = TOMOYO_TYPE_REWRITE;
goto next;
}
return error;
}
+static bool tomoyo_same_path_number_acl(const struct tomoyo_acl_info *a,
+ const struct tomoyo_acl_info *b)
+{
+ const struct tomoyo_path_number_acl *p1 = container_of(a, typeof(*p1),
+ head);
+ const struct tomoyo_path_number_acl *p2 = container_of(b, typeof(*p2),
+ head);
+ return tomoyo_same_acl_head(&p1->head, &p2->head)
+ && tomoyo_same_name_union(&p1->name, &p2->name)
+ && tomoyo_same_number_union(&p1->number, &p2->number);
+}
+
+static bool tomoyo_merge_path_number_acl(struct tomoyo_acl_info *a,
+ struct tomoyo_acl_info *b,
+ const bool is_delete)
+{
+ u8 * const a_perm = &container_of(a, struct tomoyo_path_number_acl,
+ head)->perm;
+ u8 perm = *a_perm;
+ const u8 b_perm = container_of(b, struct tomoyo_path_number_acl, head)
+ ->perm;
+ if (is_delete)
+ perm &= ~b_perm;
+ else
+ perm |= b_perm;
+ *a_perm = perm;
+ return !perm;
+}
+
/**
- * tomoyo_check_exec_perm - Check permission for "execute".
+ * tomoyo_update_path_number_acl - Update ioctl/chmod/chown/chgrp ACL.
+ *
+ * @type: Type of operation.
+ * @filename: Filename.
+ * @number: Number.
+ * @domain: Pointer to "struct tomoyo_domain_info".
+ * @is_delete: True if it is a delete request.
*
- * @domain: Pointer to "struct tomoyo_domain_info".
- * @filename: Check permission for "execute".
+ * Returns 0 on success, negative value otherwise.
+ */
+static int tomoyo_update_path_number_acl(const u8 type, const char *filename,
+ char *number,
+ struct tomoyo_domain_info * const
+ domain,
+ const bool is_delete)
+{
+ struct tomoyo_path_number_acl e = {
+ .head.type = TOMOYO_TYPE_PATH_NUMBER_ACL,
+ .perm = 1 << type
+ };
+ int error = is_delete ? -ENOENT : -ENOMEM;
+ if (!tomoyo_parse_name_union(filename, &e.name))
+ return -EINVAL;
+ if (!tomoyo_parse_number_union(number, &e.number))
+ goto out;
+ error = tomoyo_update_domain(&e.head, sizeof(e), is_delete, domain,
+ tomoyo_same_path_number_acl,
+ tomoyo_merge_path_number_acl);
+ out:
+ tomoyo_put_name_union(&e.name);
+ tomoyo_put_number_union(&e.number);
+ return error;
+}
+
+/**
+ * tomoyo_path_number_perm - Check permission for "create", "mkdir", "mkfifo", "mksock", "ioctl", "chmod", "chown", "chgrp".
*
- * Returns 0 on success, negativevalue otherwise.
+ * @type: Type of operation.
+ * @path: Pointer to "struct path".
+ * @number: Number.
*
- * Caller holds tomoyo_read_lock().
+ * Returns 0 on success, negative value otherwise.
*/
-int tomoyo_check_exec_perm(struct tomoyo_domain_info *domain,
- const struct tomoyo_path_info *filename)
+int tomoyo_path_number_perm(const u8 type, struct path *path,
+ unsigned long number)
{
- const u8 mode = tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE);
+ struct tomoyo_request_info r;
+ int error = -ENOMEM;
+ struct tomoyo_path_info buf;
+ int idx;
- if (!mode)
+ if (tomoyo_init_request_info(&r, NULL, tomoyo_pn2mac[type])
+ == TOMOYO_CONFIG_DISABLED || !path->mnt || !path->dentry)
return 0;
- return tomoyo_check_file_perm2(domain, filename, 1, "do_execve", mode);
+ idx = tomoyo_read_lock();
+ if (!tomoyo_get_realpath(&buf, path))
+ goto out;
+ if (type == TOMOYO_TYPE_MKDIR)
+ tomoyo_add_slash(&buf);
+ r.param_type = TOMOYO_TYPE_PATH_NUMBER_ACL;
+ r.param.path_number.operation = type;
+ r.param.path_number.filename = &buf;
+ r.param.path_number.number = number;
+ do {
+ tomoyo_check_acl(&r, tomoyo_check_path_number_acl);
+ error = tomoyo_audit_path_number_log(&r);
+ } while (error == TOMOYO_RETRY_REQUEST);
+ kfree(buf.name);
+ out:
+ tomoyo_read_unlock(idx);
+ if (r.mode != TOMOYO_CONFIG_ENFORCING)
+ error = 0;
+ return error;
}
/**
@@ -1096,24 +928,17 @@ int tomoyo_check_open_permission(struct tomoyo_domain_info *domain,
{
const u8 acc_mode = ACC_MODE(flag);
int error = -ENOMEM;
- struct tomoyo_path_info *buf;
- const u8 mode = tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE);
- const bool is_enforce = (mode == 3);
+ struct tomoyo_path_info buf;
+ struct tomoyo_request_info r;
int idx;
- if (!mode || !path->mnt)
- return 0;
- if (acc_mode == 0)
- return 0;
- if (path->dentry->d_inode && S_ISDIR(path->dentry->d_inode->i_mode))
- /*
- * I don't check directories here because mkdir() and rmdir()
- * don't call me.
- */
+ if (!path->mnt ||
+ (path->dentry->d_inode && S_ISDIR(path->dentry->d_inode->i_mode)))
return 0;
+ buf.name = NULL;
+ r.mode = TOMOYO_CONFIG_DISABLED;
idx = tomoyo_read_lock();
- buf = tomoyo_get_path(path);
- if (!buf)
+ if (!tomoyo_get_realpath(&buf, path))
goto out;
error = 0;
/*
@@ -1121,28 +946,43 @@ int tomoyo_check_open_permission(struct tomoyo_domain_info *domain,
* we need to check "allow_rewrite" permission when the filename is not
* opened for append mode or the filename is truncated at open time.
*/
- if ((acc_mode & MAY_WRITE) &&
- ((flag & O_TRUNC) || !(flag & O_APPEND)) &&
- (tomoyo_is_no_rewrite_file(buf))) {
- error = tomoyo_path_permission2(domain, TOMOYO_TYPE_REWRITE,
- buf, mode);
+ if ((acc_mode & MAY_WRITE) && !(flag & O_APPEND)
+ && tomoyo_init_request_info(&r, domain, TOMOYO_MAC_FILE_REWRITE)
+ != TOMOYO_CONFIG_DISABLED) {
+ if (!tomoyo_get_realpath(&buf, path)) {
+ error = -ENOMEM;
+ goto out;
+ }
+ if (tomoyo_no_rewrite_file(&buf))
+ error = tomoyo_path_permission(&r, TOMOYO_TYPE_REWRITE,
+ &buf);
+ }
+ if (!error && acc_mode &&
+ tomoyo_init_request_info(&r, domain, TOMOYO_MAC_FILE_OPEN)
+ != TOMOYO_CONFIG_DISABLED) {
+ u8 operation;
+ if (!buf.name && !tomoyo_get_realpath(&buf, path)) {
+ error = -ENOMEM;
+ goto out;
+ }
+ if (acc_mode == (MAY_READ | MAY_WRITE))
+ operation = TOMOYO_TYPE_READ_WRITE;
+ else if (acc_mode == MAY_READ)
+ operation = TOMOYO_TYPE_READ;
+ else
+ operation = TOMOYO_TYPE_WRITE;
+ error = tomoyo_path_permission(&r, operation, &buf);
}
- if (!error)
- error = tomoyo_check_file_perm2(domain, buf, acc_mode, "open",
- mode);
- if (!error && (flag & O_TRUNC))
- error = tomoyo_path_permission2(domain, TOMOYO_TYPE_TRUNCATE,
- buf, mode);
out:
- kfree(buf);
+ kfree(buf.name);
tomoyo_read_unlock(idx);
- if (!is_enforce)
+ if (r.mode != TOMOYO_CONFIG_ENFORCING)
error = 0;
return error;
}
/**
- * tomoyo_path_perm - Check permission for "create", "unlink", "mkdir", "rmdir", "mkfifo", "mksock", "mkblock", "mkchar", "truncate", "symlink", "ioctl", "chmod", "chown", "chgrp", "chroot", "mount" and "unmount".
+ * tomoyo_path_perm - Check permission for "unlink", "rmdir", "truncate", "symlink", "rewrite", "chroot" and "unmount".
*
* @operation: Type of operation.
* @path: Pointer to "struct path".
@@ -1152,71 +992,79 @@ int tomoyo_check_open_permission(struct tomoyo_domain_info *domain,
int tomoyo_path_perm(const u8 operation, struct path *path)
{
int error = -ENOMEM;
- struct tomoyo_path_info *buf;
- struct tomoyo_domain_info *domain = tomoyo_domain();
- const u8 mode = tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE);
- const bool is_enforce = (mode == 3);
+ struct tomoyo_path_info buf;
+ struct tomoyo_request_info r;
int idx;
- if (!mode || !path->mnt)
+ if (!path->mnt)
return 0;
+ if (tomoyo_init_request_info(&r, NULL, tomoyo_p2mac[operation])
+ == TOMOYO_CONFIG_DISABLED)
+ return 0;
+ buf.name = NULL;
idx = tomoyo_read_lock();
- buf = tomoyo_get_path(path);
- if (!buf)
+ if (!tomoyo_get_realpath(&buf, path))
goto out;
switch (operation) {
- case TOMOYO_TYPE_MKDIR:
+ case TOMOYO_TYPE_REWRITE:
+ if (!tomoyo_no_rewrite_file(&buf)) {
+ error = 0;
+ goto out;
+ }
+ break;
case TOMOYO_TYPE_RMDIR:
case TOMOYO_TYPE_CHROOT:
- if (!buf->is_dir) {
- /*
- * tomoyo_get_path() reserves space for appending "/."
- */
- strcat((char *) buf->name, "/");
- tomoyo_fill_path_info(buf);
- }
+ case TOMOYO_TYPE_UMOUNT:
+ tomoyo_add_slash(&buf);
+ break;
}
- error = tomoyo_path_permission2(domain, operation, buf, mode);
+ error = tomoyo_path_permission(&r, operation, &buf);
out:
- kfree(buf);
+ kfree(buf.name);
tomoyo_read_unlock(idx);
- if (!is_enforce)
+ if (r.mode != TOMOYO_CONFIG_ENFORCING)
error = 0;
return error;
}
/**
- * tomoyo_check_rewrite_permission - Check permission for "rewrite".
+ * tomoyo_mkdev_perm - Check permission for "mkblock" and "mkchar".
*
- * @filp: Pointer to "struct file".
+ * @operation: Type of operation. (TOMOYO_TYPE_MKCHAR or TOMOYO_TYPE_MKBLOCK)
+ * @path: Pointer to "struct path".
+ * @mode: Create mode.
+ * @dev: Device number.
*
* Returns 0 on success, negative value otherwise.
*/
-int tomoyo_check_rewrite_permission(struct file *filp)
+int tomoyo_mkdev_perm(const u8 operation, struct path *path,
+ const unsigned int mode, unsigned int dev)
{
+ struct tomoyo_request_info r;
int error = -ENOMEM;
- struct tomoyo_domain_info *domain = tomoyo_domain();
- const u8 mode = tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE);
- const bool is_enforce = (mode == 3);
- struct tomoyo_path_info *buf;
+ struct tomoyo_path_info buf;
int idx;
- if (!mode || !filp->f_path.mnt)
+ if (!path->mnt ||
+ tomoyo_init_request_info(&r, NULL, tomoyo_pnnn2mac[operation])
+ == TOMOYO_CONFIG_DISABLED)
return 0;
-
idx = tomoyo_read_lock();
- buf = tomoyo_get_path(&filp->f_path);
- if (!buf)
- goto out;
- if (!tomoyo_is_no_rewrite_file(buf)) {
- error = 0;
- goto out;
+ error = -ENOMEM;
+ if (tomoyo_get_realpath(&buf, path)) {
+ dev = new_decode_dev(dev);
+ r.param_type = TOMOYO_TYPE_MKDEV_ACL;
+ r.param.mkdev.filename = &buf;
+ r.param.mkdev.operation = operation;
+ r.param.mkdev.mode = mode;
+ r.param.mkdev.major = MAJOR(dev);
+ r.param.mkdev.minor = MINOR(dev);
+ tomoyo_check_acl(&r, tomoyo_check_mkdev_acl);
+ error = tomoyo_audit_mkdev_log(&r);
+ kfree(buf.name);
}
- error = tomoyo_path_permission2(domain, TOMOYO_TYPE_REWRITE, buf, mode);
- out:
- kfree(buf);
tomoyo_read_unlock(idx);
- if (!is_enforce)
+ if (r.mode != TOMOYO_CONFIG_ENFORCING)
error = 0;
return error;
}
@@ -1234,56 +1082,99 @@ int tomoyo_path2_perm(const u8 operation, struct path *path1,
struct path *path2)
{
int error = -ENOMEM;
- struct tomoyo_path_info *buf1, *buf2;
- struct tomoyo_domain_info *domain = tomoyo_domain();
- const u8 mode = tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE);
- const bool is_enforce = (mode == 3);
- const char *msg;
+ struct tomoyo_path_info buf1;
+ struct tomoyo_path_info buf2;
+ struct tomoyo_request_info r;
int idx;
- if (!mode || !path1->mnt || !path2->mnt)
+ if (!path1->mnt || !path2->mnt ||
+ tomoyo_init_request_info(&r, NULL, tomoyo_pp2mac[operation])
+ == TOMOYO_CONFIG_DISABLED)
return 0;
+ buf1.name = NULL;
+ buf2.name = NULL;
idx = tomoyo_read_lock();
- buf1 = tomoyo_get_path(path1);
- buf2 = tomoyo_get_path(path2);
- if (!buf1 || !buf2)
- goto out;
- {
- struct dentry *dentry = path1->dentry;
- if (dentry->d_inode && S_ISDIR(dentry->d_inode->i_mode)) {
- /*
- * tomoyo_get_path() reserves space for appending "/."
- */
- if (!buf1->is_dir) {
- strcat((char *) buf1->name, "/");
- tomoyo_fill_path_info(buf1);
- }
- if (!buf2->is_dir) {
- strcat((char *) buf2->name, "/");
- tomoyo_fill_path_info(buf2);
- }
- }
- }
- error = tomoyo_path2_acl(domain, operation, buf1, buf2);
- msg = tomoyo_path22keyword(operation);
- if (!error)
+ if (!tomoyo_get_realpath(&buf1, path1) ||
+ !tomoyo_get_realpath(&buf2, path2))
goto out;
- if (tomoyo_verbose_mode(domain))
- printk(KERN_WARNING "TOMOYO-%s: Access '%s %s %s' "
- "denied for %s\n", tomoyo_get_msg(is_enforce),
- msg, buf1->name, buf2->name,
- tomoyo_get_last_name(domain));
- if (mode == 1 && tomoyo_domain_quota_is_ok(domain)) {
- const char *name1 = tomoyo_get_file_pattern(buf1)->name;
- const char *name2 = tomoyo_get_file_pattern(buf2)->name;
- tomoyo_update_path2_acl(operation, name1, name2, domain,
- false);
- }
+ switch (operation) {
+ struct dentry *dentry;
+ case TOMOYO_TYPE_RENAME:
+ case TOMOYO_TYPE_LINK:
+ dentry = path1->dentry;
+ if (!dentry->d_inode || !S_ISDIR(dentry->d_inode->i_mode))
+ break;
+ /* fall through */
+ case TOMOYO_TYPE_PIVOT_ROOT:
+ tomoyo_add_slash(&buf1);
+ tomoyo_add_slash(&buf2);
+ break;
+ }
+ r.param_type = TOMOYO_TYPE_PATH2_ACL;
+ r.param.path2.operation = operation;
+ r.param.path2.filename1 = &buf1;
+ r.param.path2.filename2 = &buf2;
+ do {
+ tomoyo_check_acl(&r, tomoyo_check_path2_acl);
+ error = tomoyo_audit_path2_log(&r);
+ } while (error == TOMOYO_RETRY_REQUEST);
out:
- kfree(buf1);
- kfree(buf2);
+ kfree(buf1.name);
+ kfree(buf2.name);
tomoyo_read_unlock(idx);
- if (!is_enforce)
+ if (r.mode != TOMOYO_CONFIG_ENFORCING)
error = 0;
return error;
}
+
+/**
+ * tomoyo_write_file - Update file related list.
+ *
+ * @data: String to parse.
+ * @domain: Pointer to "struct tomoyo_domain_info".
+ * @is_delete: True if it is a delete request.
+ *
+ * Returns 0 on success, negative value otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
+ */
+int tomoyo_write_file(char *data, struct tomoyo_domain_info *domain,
+ const bool is_delete)
+{
+ char *w[5];
+ u8 type;
+ if (!tomoyo_tokenize(data, w, sizeof(w)) || !w[1][0])
+ return -EINVAL;
+ if (strncmp(w[0], "allow_", 6))
+ goto out;
+ w[0] += 6;
+ for (type = 0; type < TOMOYO_MAX_PATH_OPERATION; type++) {
+ if (strcmp(w[0], tomoyo_path_keyword[type]))
+ continue;
+ return tomoyo_update_path_acl(type, w[1], domain, is_delete);
+ }
+ if (!w[2][0])
+ goto out;
+ for (type = 0; type < TOMOYO_MAX_PATH2_OPERATION; type++) {
+ if (strcmp(w[0], tomoyo_path2_keyword[type]))
+ continue;
+ return tomoyo_update_path2_acl(type, w[1], w[2], domain,
+ is_delete);
+ }
+ for (type = 0; type < TOMOYO_MAX_PATH_NUMBER_OPERATION; type++) {
+ if (strcmp(w[0], tomoyo_path_number_keyword[type]))
+ continue;
+ return tomoyo_update_path_number_acl(type, w[1], w[2], domain,
+ is_delete);
+ }
+ if (!w[3][0] || !w[4][0])
+ goto out;
+ for (type = 0; type < TOMOYO_MAX_MKDEV_OPERATION; type++) {
+ if (strcmp(w[0], tomoyo_mkdev_keyword[type]))
+ continue;
+ return tomoyo_update_mkdev_acl(type, w[1], w[2], w[3],
+ w[4], domain, is_delete);
+ }
+ out:
+ return -EINVAL;
+}
diff --git a/security/tomoyo/gc.c b/security/tomoyo/gc.c
index b9cc71b0431..a877e4c3b10 100644
--- a/security/tomoyo/gc.c
+++ b/security/tomoyo/gc.c
@@ -11,83 +11,75 @@
#include <linux/kthread.h>
#include <linux/slab.h>
-enum tomoyo_gc_id {
- TOMOYO_ID_PATH_GROUP,
- TOMOYO_ID_PATH_GROUP_MEMBER,
- TOMOYO_ID_DOMAIN_INITIALIZER,
- TOMOYO_ID_DOMAIN_KEEPER,
- TOMOYO_ID_ALIAS,
- TOMOYO_ID_GLOBALLY_READABLE,
- TOMOYO_ID_PATTERN,
- TOMOYO_ID_NO_REWRITE,
- TOMOYO_ID_MANAGER,
- TOMOYO_ID_NAME,
- TOMOYO_ID_ACL,
- TOMOYO_ID_DOMAIN
-};
-
-struct tomoyo_gc_entry {
+struct tomoyo_gc {
struct list_head list;
int type;
- void *element;
+ struct list_head *element;
};
static LIST_HEAD(tomoyo_gc_queue);
static DEFINE_MUTEX(tomoyo_gc_mutex);
/* Caller holds tomoyo_policy_lock mutex. */
-static bool tomoyo_add_to_gc(const int type, void *element)
+static bool tomoyo_add_to_gc(const int type, struct list_head *element)
{
- struct tomoyo_gc_entry *entry = kzalloc(sizeof(*entry), GFP_ATOMIC);
+ struct tomoyo_gc *entry = kzalloc(sizeof(*entry), GFP_ATOMIC);
if (!entry)
return false;
entry->type = type;
entry->element = element;
list_add(&entry->list, &tomoyo_gc_queue);
+ list_del_rcu(element);
return true;
}
-static void tomoyo_del_allow_read
-(struct tomoyo_globally_readable_file_entry *ptr)
+static void tomoyo_del_allow_read(struct list_head *element)
{
+ struct tomoyo_readable_file *ptr =
+ container_of(element, typeof(*ptr), head.list);
tomoyo_put_name(ptr->filename);
}
-static void tomoyo_del_file_pattern(struct tomoyo_pattern_entry *ptr)
+static void tomoyo_del_file_pattern(struct list_head *element)
{
+ struct tomoyo_no_pattern *ptr =
+ container_of(element, typeof(*ptr), head.list);
tomoyo_put_name(ptr->pattern);
}
-static void tomoyo_del_no_rewrite(struct tomoyo_no_rewrite_entry *ptr)
+static void tomoyo_del_no_rewrite(struct list_head *element)
{
+ struct tomoyo_no_rewrite *ptr =
+ container_of(element, typeof(*ptr), head.list);
tomoyo_put_name(ptr->pattern);
}
-static void tomoyo_del_domain_initializer
-(struct tomoyo_domain_initializer_entry *ptr)
+static void tomoyo_del_transition_control(struct list_head *element)
{
+ struct tomoyo_transition_control *ptr =
+ container_of(element, typeof(*ptr), head.list);
tomoyo_put_name(ptr->domainname);
tomoyo_put_name(ptr->program);
}
-static void tomoyo_del_domain_keeper(struct tomoyo_domain_keeper_entry *ptr)
-{
- tomoyo_put_name(ptr->domainname);
- tomoyo_put_name(ptr->program);
-}
-
-static void tomoyo_del_alias(struct tomoyo_alias_entry *ptr)
+static void tomoyo_del_aggregator(struct list_head *element)
{
+ struct tomoyo_aggregator *ptr =
+ container_of(element, typeof(*ptr), head.list);
tomoyo_put_name(ptr->original_name);
- tomoyo_put_name(ptr->aliased_name);
+ tomoyo_put_name(ptr->aggregated_name);
}
-static void tomoyo_del_manager(struct tomoyo_policy_manager_entry *ptr)
+static void tomoyo_del_manager(struct list_head *element)
{
+ struct tomoyo_manager *ptr =
+ container_of(element, typeof(*ptr), head.list);
tomoyo_put_name(ptr->manager);
}
-static void tomoyo_del_acl(struct tomoyo_acl_info *acl)
+static void tomoyo_del_acl(struct list_head *element)
{
+ struct tomoyo_acl_info *acl =
+ container_of(element, typeof(*acl), list);
switch (acl->type) {
case TOMOYO_TYPE_PATH_ACL:
{
@@ -104,14 +96,41 @@ static void tomoyo_del_acl(struct tomoyo_acl_info *acl)
tomoyo_put_name_union(&entry->name2);
}
break;
- default:
- printk(KERN_WARNING "Unknown type\n");
+ case TOMOYO_TYPE_PATH_NUMBER_ACL:
+ {
+ struct tomoyo_path_number_acl *entry
+ = container_of(acl, typeof(*entry), head);
+ tomoyo_put_name_union(&entry->name);
+ tomoyo_put_number_union(&entry->number);
+ }
+ break;
+ case TOMOYO_TYPE_MKDEV_ACL:
+ {
+ struct tomoyo_mkdev_acl *entry
+ = container_of(acl, typeof(*entry), head);
+ tomoyo_put_name_union(&entry->name);
+ tomoyo_put_number_union(&entry->mode);
+ tomoyo_put_number_union(&entry->major);
+ tomoyo_put_number_union(&entry->minor);
+ }
+ break;
+ case TOMOYO_TYPE_MOUNT_ACL:
+ {
+ struct tomoyo_mount_acl *entry
+ = container_of(acl, typeof(*entry), head);
+ tomoyo_put_name_union(&entry->dev_name);
+ tomoyo_put_name_union(&entry->dir_name);
+ tomoyo_put_name_union(&entry->fs_type);
+ tomoyo_put_number_union(&entry->flags);
+ }
break;
}
}
-static bool tomoyo_del_domain(struct tomoyo_domain_info *domain)
+static bool tomoyo_del_domain(struct list_head *element)
{
+ struct tomoyo_domain_info *domain =
+ container_of(element, typeof(*domain), list);
struct tomoyo_acl_info *acl;
struct tomoyo_acl_info *tmp;
/*
@@ -139,7 +158,7 @@ static bool tomoyo_del_domain(struct tomoyo_domain_info *domain)
if (atomic_read(&domain->users))
return false;
list_for_each_entry_safe(acl, tmp, &domain->acl_info_list, list) {
- tomoyo_del_acl(acl);
+ tomoyo_del_acl(&acl->list);
tomoyo_memory_free(acl);
}
tomoyo_put_name(domain->domainname);
@@ -147,135 +166,70 @@ static bool tomoyo_del_domain(struct tomoyo_domain_info *domain)
}
-static void tomoyo_del_name(const struct tomoyo_name_entry *ptr)
+static void tomoyo_del_name(struct list_head *element)
{
+ const struct tomoyo_name *ptr =
+ container_of(element, typeof(*ptr), list);
}
-static void tomoyo_del_path_group_member(struct tomoyo_path_group_member
- *member)
+static void tomoyo_del_path_group(struct list_head *element)
{
+ struct tomoyo_path_group *member =
+ container_of(element, typeof(*member), head.list);
tomoyo_put_name(member->member_name);
}
-static void tomoyo_del_path_group(struct tomoyo_path_group *group)
+static void tomoyo_del_group(struct list_head *element)
{
+ struct tomoyo_group *group =
+ container_of(element, typeof(*group), list);
tomoyo_put_name(group->group_name);
}
+static void tomoyo_del_number_group(struct list_head *element)
+{
+ struct tomoyo_number_group *member =
+ container_of(element, typeof(*member), head.list);
+}
+
+static bool tomoyo_collect_member(struct list_head *member_list, int id)
+{
+ struct tomoyo_acl_head *member;
+ list_for_each_entry(member, member_list, list) {
+ if (!member->is_deleted)
+ continue;
+ if (!tomoyo_add_to_gc(id, &member->list))
+ return false;
+ }
+ return true;
+}
+
+static bool tomoyo_collect_acl(struct tomoyo_domain_info *domain)
+{
+ struct tomoyo_acl_info *acl;
+ list_for_each_entry(acl, &domain->acl_info_list, list) {
+ if (!acl->is_deleted)
+ continue;
+ if (!tomoyo_add_to_gc(TOMOYO_ID_ACL, &acl->list))
+ return false;
+ }
+ return true;
+}
+
static void tomoyo_collect_entry(void)
{
+ int i;
if (mutex_lock_interruptible(&tomoyo_policy_lock))
return;
- {
- struct tomoyo_globally_readable_file_entry *ptr;
- list_for_each_entry_rcu(ptr, &tomoyo_globally_readable_list,
- list) {
- if (!ptr->is_deleted)
- continue;
- if (tomoyo_add_to_gc(TOMOYO_ID_GLOBALLY_READABLE, ptr))
- list_del_rcu(&ptr->list);
- else
- break;
- }
- }
- {
- struct tomoyo_pattern_entry *ptr;
- list_for_each_entry_rcu(ptr, &tomoyo_pattern_list, list) {
- if (!ptr->is_deleted)
- continue;
- if (tomoyo_add_to_gc(TOMOYO_ID_PATTERN, ptr))
- list_del_rcu(&ptr->list);
- else
- break;
- }
- }
- {
- struct tomoyo_no_rewrite_entry *ptr;
- list_for_each_entry_rcu(ptr, &tomoyo_no_rewrite_list, list) {
- if (!ptr->is_deleted)
- continue;
- if (tomoyo_add_to_gc(TOMOYO_ID_NO_REWRITE, ptr))
- list_del_rcu(&ptr->list);
- else
- break;
- }
- }
- {
- struct tomoyo_domain_initializer_entry *ptr;
- list_for_each_entry_rcu(ptr, &tomoyo_domain_initializer_list,
- list) {
- if (!ptr->is_deleted)
- continue;
- if (tomoyo_add_to_gc(TOMOYO_ID_DOMAIN_INITIALIZER, ptr))
- list_del_rcu(&ptr->list);
- else
- break;
- }
- }
- {
- struct tomoyo_domain_keeper_entry *ptr;
- list_for_each_entry_rcu(ptr, &tomoyo_domain_keeper_list, list) {
- if (!ptr->is_deleted)
- continue;
- if (tomoyo_add_to_gc(TOMOYO_ID_DOMAIN_KEEPER, ptr))
- list_del_rcu(&ptr->list);
- else
- break;
- }
- }
- {
- struct tomoyo_alias_entry *ptr;
- list_for_each_entry_rcu(ptr, &tomoyo_alias_list, list) {
- if (!ptr->is_deleted)
- continue;
- if (tomoyo_add_to_gc(TOMOYO_ID_ALIAS, ptr))
- list_del_rcu(&ptr->list);
- else
- break;
- }
- }
- {
- struct tomoyo_policy_manager_entry *ptr;
- list_for_each_entry_rcu(ptr, &tomoyo_policy_manager_list,
- list) {
- if (!ptr->is_deleted)
- continue;
- if (tomoyo_add_to_gc(TOMOYO_ID_MANAGER, ptr))
- list_del_rcu(&ptr->list);
- else
- break;
- }
+ for (i = 0; i < TOMOYO_MAX_POLICY; i++) {
+ if (!tomoyo_collect_member(&tomoyo_policy_list[i], i))
+ goto unlock;
}
{
struct tomoyo_domain_info *domain;
list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) {
- struct tomoyo_acl_info *acl;
- list_for_each_entry_rcu(acl, &domain->acl_info_list,
- list) {
- switch (acl->type) {
- case TOMOYO_TYPE_PATH_ACL:
- if (container_of(acl,
- struct tomoyo_path_acl,
- head)->perm ||
- container_of(acl,
- struct tomoyo_path_acl,
- head)->perm_high)
- continue;
- break;
- case TOMOYO_TYPE_PATH2_ACL:
- if (container_of(acl,
- struct tomoyo_path2_acl,
- head)->perm)
- continue;
- break;
- default:
- continue;
- }
- if (tomoyo_add_to_gc(TOMOYO_ID_ACL, acl))
- list_del_rcu(&acl->list);
- else
- break;
- }
+ if (!tomoyo_collect_acl(domain))
+ goto unlock;
if (!domain->is_deleted || atomic_read(&domain->users))
continue;
/*
@@ -283,104 +237,92 @@ static void tomoyo_collect_entry(void)
* refer this domain after successful execve().
* We recheck domain->users after SRCU synchronization.
*/
- if (tomoyo_add_to_gc(TOMOYO_ID_DOMAIN, domain))
- list_del_rcu(&domain->list);
- else
- break;
+ if (!tomoyo_add_to_gc(TOMOYO_ID_DOMAIN, &domain->list))
+ goto unlock;
}
}
- {
- int i;
- for (i = 0; i < TOMOYO_MAX_HASH; i++) {
- struct tomoyo_name_entry *ptr;
- list_for_each_entry_rcu(ptr, &tomoyo_name_list[i],
- list) {
- if (atomic_read(&ptr->users))
- continue;
- if (tomoyo_add_to_gc(TOMOYO_ID_NAME, ptr))
- list_del_rcu(&ptr->list);
- else {
- i = TOMOYO_MAX_HASH;
- break;
- }
- }
+ for (i = 0; i < TOMOYO_MAX_HASH; i++) {
+ struct tomoyo_name *ptr;
+ list_for_each_entry_rcu(ptr, &tomoyo_name_list[i], list) {
+ if (atomic_read(&ptr->users))
+ continue;
+ if (!tomoyo_add_to_gc(TOMOYO_ID_NAME, &ptr->list))
+ goto unlock;
}
}
- {
- struct tomoyo_path_group *group;
- list_for_each_entry_rcu(group, &tomoyo_path_group_list, list) {
- struct tomoyo_path_group_member *member;
- list_for_each_entry_rcu(member, &group->member_list,
- list) {
- if (!member->is_deleted)
- continue;
- if (tomoyo_add_to_gc(TOMOYO_ID_PATH_GROUP_MEMBER,
- member))
- list_del_rcu(&member->list);
- else
- break;
- }
+ for (i = 0; i < TOMOYO_MAX_GROUP; i++) {
+ struct list_head *list = &tomoyo_group_list[i];
+ int id;
+ struct tomoyo_group *group;
+ switch (i) {
+ case 0:
+ id = TOMOYO_ID_PATH_GROUP;
+ break;
+ default:
+ id = TOMOYO_ID_NUMBER_GROUP;
+ break;
+ }
+ list_for_each_entry(group, list, list) {
+ if (!tomoyo_collect_member(&group->member_list, id))
+ goto unlock;
if (!list_empty(&group->member_list) ||
atomic_read(&group->users))
continue;
- if (tomoyo_add_to_gc(TOMOYO_ID_PATH_GROUP, group))
- list_del_rcu(&group->list);
- else
- break;
+ if (!tomoyo_add_to_gc(TOMOYO_ID_GROUP, &group->list))
+ goto unlock;
}
}
+ unlock:
mutex_unlock(&tomoyo_policy_lock);
}
static void tomoyo_kfree_entry(void)
{
- struct tomoyo_gc_entry *p;
- struct tomoyo_gc_entry *tmp;
+ struct tomoyo_gc *p;
+ struct tomoyo_gc *tmp;
list_for_each_entry_safe(p, tmp, &tomoyo_gc_queue, list) {
+ struct list_head *element = p->element;
switch (p->type) {
- case TOMOYO_ID_DOMAIN_INITIALIZER:
- tomoyo_del_domain_initializer(p->element);
- break;
- case TOMOYO_ID_DOMAIN_KEEPER:
- tomoyo_del_domain_keeper(p->element);
+ case TOMOYO_ID_TRANSITION_CONTROL:
+ tomoyo_del_transition_control(element);
break;
- case TOMOYO_ID_ALIAS:
- tomoyo_del_alias(p->element);
+ case TOMOYO_ID_AGGREGATOR:
+ tomoyo_del_aggregator(element);
break;
case TOMOYO_ID_GLOBALLY_READABLE:
- tomoyo_del_allow_read(p->element);
+ tomoyo_del_allow_read(element);
break;
case TOMOYO_ID_PATTERN:
- tomoyo_del_file_pattern(p->element);
+ tomoyo_del_file_pattern(element);
break;
case TOMOYO_ID_NO_REWRITE:
- tomoyo_del_no_rewrite(p->element);
+ tomoyo_del_no_rewrite(element);
break;
case TOMOYO_ID_MANAGER:
- tomoyo_del_manager(p->element);
+ tomoyo_del_manager(element);
break;
case TOMOYO_ID_NAME:
- tomoyo_del_name(p->element);
+ tomoyo_del_name(element);
break;
case TOMOYO_ID_ACL:
- tomoyo_del_acl(p->element);
+ tomoyo_del_acl(element);
break;
case TOMOYO_ID_DOMAIN:
- if (!tomoyo_del_domain(p->element))
+ if (!tomoyo_del_domain(element))
continue;
break;
- case TOMOYO_ID_PATH_GROUP_MEMBER:
- tomoyo_del_path_group_member(p->element);
- break;
case TOMOYO_ID_PATH_GROUP:
- tomoyo_del_path_group(p->element);
+ tomoyo_del_path_group(element);
break;
- default:
- printk(KERN_WARNING "Unknown type\n");
+ case TOMOYO_ID_GROUP:
+ tomoyo_del_group(element);
+ break;
+ case TOMOYO_ID_NUMBER_GROUP:
+ tomoyo_del_number_group(element);
break;
}
- tomoyo_memory_free(p->element);
+ tomoyo_memory_free(element);
list_del(&p->list);
kfree(p);
}
diff --git a/security/tomoyo/group.c b/security/tomoyo/group.c
new file mode 100644
index 00000000000..e94352ce723
--- /dev/null
+++ b/security/tomoyo/group.c
@@ -0,0 +1,130 @@
+/*
+ * security/tomoyo/group.c
+ *
+ * Copyright (C) 2005-2010 NTT DATA CORPORATION
+ */
+
+#include <linux/slab.h>
+#include "common.h"
+
+static bool tomoyo_same_path_group(const struct tomoyo_acl_head *a,
+ const struct tomoyo_acl_head *b)
+{
+ return container_of(a, struct tomoyo_path_group, head)->member_name ==
+ container_of(b, struct tomoyo_path_group, head)->member_name;
+}
+
+static bool tomoyo_same_number_group(const struct tomoyo_acl_head *a,
+ const struct tomoyo_acl_head *b)
+{
+ return !memcmp(&container_of(a, struct tomoyo_number_group, head)
+ ->number,
+ &container_of(b, struct tomoyo_number_group, head)
+ ->number,
+ sizeof(container_of(a, struct tomoyo_number_group, head)
+ ->number));
+}
+
+/**
+ * tomoyo_write_group - Write "struct tomoyo_path_group"/"struct tomoyo_number_group" list.
+ *
+ * @data: String to parse.
+ * @is_delete: True if it is a delete request.
+ * @type: Type of this group.
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
+int tomoyo_write_group(char *data, const bool is_delete, const u8 type)
+{
+ struct tomoyo_group *group;
+ struct list_head *member;
+ char *w[2];
+ int error = -EINVAL;
+ if (!tomoyo_tokenize(data, w, sizeof(w)) || !w[1][0])
+ return -EINVAL;
+ group = tomoyo_get_group(w[0], type);
+ if (!group)
+ return -ENOMEM;
+ member = &group->member_list;
+ if (type == TOMOYO_PATH_GROUP) {
+ struct tomoyo_path_group e = { };
+ e.member_name = tomoyo_get_name(w[1]);
+ if (!e.member_name) {
+ error = -ENOMEM;
+ goto out;
+ }
+ error = tomoyo_update_policy(&e.head, sizeof(e), is_delete,
+ member, tomoyo_same_path_group);
+ tomoyo_put_name(e.member_name);
+ } else if (type == TOMOYO_NUMBER_GROUP) {
+ struct tomoyo_number_group e = { };
+ if (w[1][0] == '@'
+ || !tomoyo_parse_number_union(w[1], &e.number)
+ || e.number.values[0] > e.number.values[1])
+ goto out;
+ error = tomoyo_update_policy(&e.head, sizeof(e), is_delete,
+ member, tomoyo_same_number_group);
+ /*
+ * tomoyo_put_number_union() is not needed because
+ * w[1][0] != '@'.
+ */
+ }
+ out:
+ tomoyo_put_group(group);
+ return error;
+}
+
+/**
+ * tomoyo_path_matches_group - Check whether the given pathname matches members of the given pathname group.
+ *
+ * @pathname: The name of pathname.
+ * @group: Pointer to "struct tomoyo_path_group".
+ *
+ * Returns matched member's pathname if @pathname matches pathnames in @group,
+ * NULL otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
+ */
+const struct tomoyo_path_info *
+tomoyo_path_matches_group(const struct tomoyo_path_info *pathname,
+ const struct tomoyo_group *group)
+{
+ struct tomoyo_path_group *member;
+ list_for_each_entry_rcu(member, &group->member_list, head.list) {
+ if (member->head.is_deleted)
+ continue;
+ if (!tomoyo_path_matches_pattern(pathname, member->member_name))
+ continue;
+ return member->member_name;
+ }
+ return NULL;
+}
+
+/**
+ * tomoyo_number_matches_group - Check whether the given number matches members of the given number group.
+ *
+ * @min: Min number.
+ * @max: Max number.
+ * @group: Pointer to "struct tomoyo_number_group".
+ *
+ * Returns true if @min and @max partially overlaps @group, false otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
+ */
+bool tomoyo_number_matches_group(const unsigned long min,
+ const unsigned long max,
+ const struct tomoyo_group *group)
+{
+ struct tomoyo_number_group *member;
+ bool matched = false;
+ list_for_each_entry_rcu(member, &group->member_list, head.list) {
+ if (member->head.is_deleted)
+ continue;
+ if (min > member->number.values[1] ||
+ max < member->number.values[0])
+ continue;
+ matched = true;
+ break;
+ }
+ return matched;
+}
diff --git a/security/tomoyo/load_policy.c b/security/tomoyo/load_policy.c
new file mode 100644
index 00000000000..bbada7ca1b9
--- /dev/null
+++ b/security/tomoyo/load_policy.c
@@ -0,0 +1,81 @@
+/*
+ * security/tomoyo/load_policy.c
+ *
+ * Policy loader launcher for TOMOYO.
+ *
+ * Copyright (C) 2005-2010 NTT DATA CORPORATION
+ */
+
+#include "common.h"
+
+/* path to policy loader */
+static const char *tomoyo_loader = "/sbin/tomoyo-init";
+
+/**
+ * tomoyo_policy_loader_exists - Check whether /sbin/tomoyo-init exists.
+ *
+ * Returns true if /sbin/tomoyo-init exists, false otherwise.
+ */
+static bool tomoyo_policy_loader_exists(void)
+{
+ /*
+ * Don't activate MAC if the policy loader doesn't exist.
+ * If the initrd includes /sbin/init but real-root-dev has not
+ * mounted on / yet, activating MAC will block the system since
+ * policies are not loaded yet.
+ * Thus, let do_execve() call this function everytime.
+ */
+ struct path path;
+
+ if (kern_path(tomoyo_loader, LOOKUP_FOLLOW, &path)) {
+ printk(KERN_INFO "Not activating Mandatory Access Control now "
+ "since %s doesn't exist.\n", tomoyo_loader);
+ return false;
+ }
+ path_put(&path);
+ return true;
+}
+
+/**
+ * tomoyo_load_policy - Run external policy loader to load policy.
+ *
+ * @filename: The program about to start.
+ *
+ * This function checks whether @filename is /sbin/init , and if so
+ * invoke /sbin/tomoyo-init and wait for the termination of /sbin/tomoyo-init
+ * and then continues invocation of /sbin/init.
+ * /sbin/tomoyo-init reads policy files in /etc/tomoyo/ directory and
+ * writes to /sys/kernel/security/tomoyo/ interfaces.
+ *
+ * Returns nothing.
+ */
+void tomoyo_load_policy(const char *filename)
+{
+ char *argv[2];
+ char *envp[3];
+
+ if (tomoyo_policy_loaded)
+ return;
+ /*
+ * Check filename is /sbin/init or /sbin/tomoyo-start.
+ * /sbin/tomoyo-start is a dummy filename in case where /sbin/init can't
+ * be passed.
+ * You can create /sbin/tomoyo-start by
+ * "ln -s /bin/true /sbin/tomoyo-start".
+ */
+ if (strcmp(filename, "/sbin/init") &&
+ strcmp(filename, "/sbin/tomoyo-start"))
+ return;
+ if (!tomoyo_policy_loader_exists())
+ return;
+
+ printk(KERN_INFO "Calling %s to load policy. Please wait.\n",
+ tomoyo_loader);
+ argv[0] = (char *) tomoyo_loader;
+ argv[1] = NULL;
+ envp[0] = "HOME=/";
+ envp[1] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";
+ envp[2] = NULL;
+ call_usermodehelper(argv[0], argv, envp, 1);
+ tomoyo_check_profile();
+}
diff --git a/security/tomoyo/memory.c b/security/tomoyo/memory.c
new file mode 100644
index 00000000000..297612669c7
--- /dev/null
+++ b/security/tomoyo/memory.c
@@ -0,0 +1,282 @@
+/*
+ * security/tomoyo/memory.c
+ *
+ * Memory management functions for TOMOYO.
+ *
+ * Copyright (C) 2005-2010 NTT DATA CORPORATION
+ */
+
+#include <linux/hash.h>
+#include <linux/slab.h>
+#include "common.h"
+
+/**
+ * tomoyo_warn_oom - Print out of memory warning message.
+ *
+ * @function: Function's name.
+ */
+void tomoyo_warn_oom(const char *function)
+{
+ /* Reduce error messages. */
+ static pid_t tomoyo_last_pid;
+ const pid_t pid = current->pid;
+ if (tomoyo_last_pid != pid) {
+ printk(KERN_WARNING "ERROR: Out of memory at %s.\n",
+ function);
+ tomoyo_last_pid = pid;
+ }
+ if (!tomoyo_policy_loaded)
+ panic("MAC Initialization failed.\n");
+}
+
+/* Memory allocated for policy. */
+static atomic_t tomoyo_policy_memory_size;
+/* Quota for holding policy. */
+static unsigned int tomoyo_quota_for_policy;
+
+/**
+ * tomoyo_memory_ok - Check memory quota.
+ *
+ * @ptr: Pointer to allocated memory.
+ *
+ * Returns true on success, false otherwise.
+ *
+ * Returns true if @ptr is not NULL and quota not exceeded, false otherwise.
+ */
+bool tomoyo_memory_ok(void *ptr)
+{
+ size_t s = ptr ? ksize(ptr) : 0;
+ atomic_add(s, &tomoyo_policy_memory_size);
+ if (ptr && (!tomoyo_quota_for_policy ||
+ atomic_read(&tomoyo_policy_memory_size)
+ <= tomoyo_quota_for_policy)) {
+ memset(ptr, 0, s);
+ return true;
+ }
+ atomic_sub(s, &tomoyo_policy_memory_size);
+ tomoyo_warn_oom(__func__);
+ return false;
+}
+
+/**
+ * tomoyo_commit_ok - Check memory quota.
+ *
+ * @data: Data to copy from.
+ * @size: Size in byte.
+ *
+ * Returns pointer to allocated memory on success, NULL otherwise.
+ * @data is zero-cleared on success.
+ */
+void *tomoyo_commit_ok(void *data, const unsigned int size)
+{
+ void *ptr = kzalloc(size, GFP_NOFS);
+ if (tomoyo_memory_ok(ptr)) {
+ memmove(ptr, data, size);
+ memset(data, 0, size);
+ return ptr;
+ }
+ return NULL;
+}
+
+/**
+ * tomoyo_memory_free - Free memory for elements.
+ *
+ * @ptr: Pointer to allocated memory.
+ */
+void tomoyo_memory_free(void *ptr)
+{
+ atomic_sub(ksize(ptr), &tomoyo_policy_memory_size);
+ kfree(ptr);
+}
+
+/**
+ * tomoyo_get_group - Allocate memory for "struct tomoyo_path_group"/"struct tomoyo_number_group".
+ *
+ * @group_name: The name of address group.
+ * @idx: Index number.
+ *
+ * Returns pointer to "struct tomoyo_group" on success, NULL otherwise.
+ */
+struct tomoyo_group *tomoyo_get_group(const char *group_name, const u8 idx)
+{
+ struct tomoyo_group e = { };
+ struct tomoyo_group *group = NULL;
+ bool found = false;
+ if (!tomoyo_correct_word(group_name) || idx >= TOMOYO_MAX_GROUP)
+ return NULL;
+ e.group_name = tomoyo_get_name(group_name);
+ if (!e.group_name)
+ return NULL;
+ if (mutex_lock_interruptible(&tomoyo_policy_lock))
+ goto out;
+ list_for_each_entry(group, &tomoyo_group_list[idx], list) {
+ if (e.group_name != group->group_name)
+ continue;
+ atomic_inc(&group->users);
+ found = true;
+ break;
+ }
+ if (!found) {
+ struct tomoyo_group *entry = tomoyo_commit_ok(&e, sizeof(e));
+ if (entry) {
+ INIT_LIST_HEAD(&entry->member_list);
+ atomic_set(&entry->users, 1);
+ list_add_tail_rcu(&entry->list,
+ &tomoyo_group_list[idx]);
+ group = entry;
+ found = true;
+ }
+ }
+ mutex_unlock(&tomoyo_policy_lock);
+ out:
+ tomoyo_put_name(e.group_name);
+ return found ? group : NULL;
+}
+
+/*
+ * tomoyo_name_list is used for holding string data used by TOMOYO.
+ * Since same string data is likely used for multiple times (e.g.
+ * "/lib/libc-2.5.so"), TOMOYO shares string data in the form of
+ * "const struct tomoyo_path_info *".
+ */
+struct list_head tomoyo_name_list[TOMOYO_MAX_HASH];
+
+/**
+ * tomoyo_get_name - Allocate permanent memory for string data.
+ *
+ * @name: The string to store into the permernent memory.
+ *
+ * Returns pointer to "struct tomoyo_path_info" on success, NULL otherwise.
+ */
+const struct tomoyo_path_info *tomoyo_get_name(const char *name)
+{
+ struct tomoyo_name *ptr;
+ unsigned int hash;
+ int len;
+ int allocated_len;
+ struct list_head *head;
+
+ if (!name)
+ return NULL;
+ len = strlen(name) + 1;
+ hash = full_name_hash((const unsigned char *) name, len - 1);
+ head = &tomoyo_name_list[hash_long(hash, TOMOYO_HASH_BITS)];
+ if (mutex_lock_interruptible(&tomoyo_policy_lock))
+ return NULL;
+ list_for_each_entry(ptr, head, list) {
+ if (hash != ptr->entry.hash || strcmp(name, ptr->entry.name))
+ continue;
+ atomic_inc(&ptr->users);
+ goto out;
+ }
+ ptr = kzalloc(sizeof(*ptr) + len, GFP_NOFS);
+ allocated_len = ptr ? ksize(ptr) : 0;
+ if (!ptr || (tomoyo_quota_for_policy &&
+ atomic_read(&tomoyo_policy_memory_size) + allocated_len
+ > tomoyo_quota_for_policy)) {
+ kfree(ptr);
+ ptr = NULL;
+ tomoyo_warn_oom(__func__);
+ goto out;
+ }
+ atomic_add(allocated_len, &tomoyo_policy_memory_size);
+ ptr->entry.name = ((char *) ptr) + sizeof(*ptr);
+ memmove((char *) ptr->entry.name, name, len);
+ atomic_set(&ptr->users, 1);
+ tomoyo_fill_path_info(&ptr->entry);
+ list_add_tail(&ptr->list, head);
+ out:
+ mutex_unlock(&tomoyo_policy_lock);
+ return ptr ? &ptr->entry : NULL;
+}
+
+/**
+ * tomoyo_mm_init - Initialize mm related code.
+ */
+void __init tomoyo_mm_init(void)
+{
+ int idx;
+
+ for (idx = 0; idx < TOMOYO_MAX_POLICY; idx++)
+ INIT_LIST_HEAD(&tomoyo_policy_list[idx]);
+ for (idx = 0; idx < TOMOYO_MAX_GROUP; idx++)
+ INIT_LIST_HEAD(&tomoyo_group_list[idx]);
+ for (idx = 0; idx < TOMOYO_MAX_HASH; idx++)
+ INIT_LIST_HEAD(&tomoyo_name_list[idx]);
+ INIT_LIST_HEAD(&tomoyo_kernel_domain.acl_info_list);
+ tomoyo_kernel_domain.domainname = tomoyo_get_name(TOMOYO_ROOT_NAME);
+ list_add_tail_rcu(&tomoyo_kernel_domain.list, &tomoyo_domain_list);
+ idx = tomoyo_read_lock();
+ if (tomoyo_find_domain(TOMOYO_ROOT_NAME) != &tomoyo_kernel_domain)
+ panic("Can't register tomoyo_kernel_domain");
+ {
+ /* Load built-in policy. */
+ tomoyo_write_transition_control("/sbin/hotplug", false,
+ TOMOYO_TRANSITION_CONTROL_INITIALIZE);
+ tomoyo_write_transition_control("/sbin/modprobe", false,
+ TOMOYO_TRANSITION_CONTROL_INITIALIZE);
+ }
+ tomoyo_read_unlock(idx);
+}
+
+
+/* Memory allocated for query lists. */
+unsigned int tomoyo_query_memory_size;
+/* Quota for holding query lists. */
+unsigned int tomoyo_quota_for_query;
+
+/**
+ * tomoyo_read_memory_counter - Check for memory usage in bytes.
+ *
+ * @head: Pointer to "struct tomoyo_io_buffer".
+ *
+ * Returns memory usage.
+ */
+void tomoyo_read_memory_counter(struct tomoyo_io_buffer *head)
+{
+ if (!head->r.eof) {
+ const unsigned int policy
+ = atomic_read(&tomoyo_policy_memory_size);
+ const unsigned int query = tomoyo_query_memory_size;
+ char buffer[64];
+
+ memset(buffer, 0, sizeof(buffer));
+ if (tomoyo_quota_for_policy)
+ snprintf(buffer, sizeof(buffer) - 1,
+ " (Quota: %10u)",
+ tomoyo_quota_for_policy);
+ else
+ buffer[0] = '\0';
+ tomoyo_io_printf(head, "Policy: %10u%s\n", policy,
+ buffer);
+ if (tomoyo_quota_for_query)
+ snprintf(buffer, sizeof(buffer) - 1,
+ " (Quota: %10u)",
+ tomoyo_quota_for_query);
+ else
+ buffer[0] = '\0';
+ tomoyo_io_printf(head, "Query lists: %10u%s\n", query,
+ buffer);
+ tomoyo_io_printf(head, "Total: %10u\n", policy + query);
+ head->r.eof = true;
+ }
+}
+
+/**
+ * tomoyo_write_memory_quota - Set memory quota.
+ *
+ * @head: Pointer to "struct tomoyo_io_buffer".
+ *
+ * Returns 0.
+ */
+int tomoyo_write_memory_quota(struct tomoyo_io_buffer *head)
+{
+ char *data = head->write_buf;
+ unsigned int size;
+
+ if (sscanf(data, "Policy: %u", &size) == 1)
+ tomoyo_quota_for_policy = size;
+ else if (sscanf(data, "Query lists: %u", &size) == 1)
+ tomoyo_quota_for_query = size;
+ return 0;
+}
diff --git a/security/tomoyo/mount.c b/security/tomoyo/mount.c
new file mode 100644
index 00000000000..82bf8c2390b
--- /dev/null
+++ b/security/tomoyo/mount.c
@@ -0,0 +1,284 @@
+/*
+ * security/tomoyo/mount.c
+ *
+ * Copyright (C) 2005-2010 NTT DATA CORPORATION
+ */
+
+#include <linux/slab.h>
+#include "common.h"
+
+/* Keywords for mount restrictions. */
+
+/* Allow to call 'mount --bind /source_dir /dest_dir' */
+#define TOMOYO_MOUNT_BIND_KEYWORD "--bind"
+/* Allow to call 'mount --move /old_dir /new_dir ' */
+#define TOMOYO_MOUNT_MOVE_KEYWORD "--move"
+/* Allow to call 'mount -o remount /dir ' */
+#define TOMOYO_MOUNT_REMOUNT_KEYWORD "--remount"
+/* Allow to call 'mount --make-unbindable /dir' */
+#define TOMOYO_MOUNT_MAKE_UNBINDABLE_KEYWORD "--make-unbindable"
+/* Allow to call 'mount --make-private /dir' */
+#define TOMOYO_MOUNT_MAKE_PRIVATE_KEYWORD "--make-private"
+/* Allow to call 'mount --make-slave /dir' */
+#define TOMOYO_MOUNT_MAKE_SLAVE_KEYWORD "--make-slave"
+/* Allow to call 'mount --make-shared /dir' */
+#define TOMOYO_MOUNT_MAKE_SHARED_KEYWORD "--make-shared"
+
+/**
+ * tomoyo_audit_mount_log - Audit mount log.
+ *
+ * @r: Pointer to "struct tomoyo_request_info".
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
+static int tomoyo_audit_mount_log(struct tomoyo_request_info *r)
+{
+ const char *dev = r->param.mount.dev->name;
+ const char *dir = r->param.mount.dir->name;
+ const char *type = r->param.mount.type->name;
+ const unsigned long flags = r->param.mount.flags;
+ if (r->granted)
+ return 0;
+ if (!strcmp(type, TOMOYO_MOUNT_REMOUNT_KEYWORD))
+ tomoyo_warn_log(r, "mount -o remount %s 0x%lX", dir, flags);
+ else if (!strcmp(type, TOMOYO_MOUNT_BIND_KEYWORD)
+ || !strcmp(type, TOMOYO_MOUNT_MOVE_KEYWORD))
+ tomoyo_warn_log(r, "mount %s %s %s 0x%lX", type, dev, dir,
+ flags);
+ else if (!strcmp(type, TOMOYO_MOUNT_MAKE_UNBINDABLE_KEYWORD) ||
+ !strcmp(type, TOMOYO_MOUNT_MAKE_PRIVATE_KEYWORD) ||
+ !strcmp(type, TOMOYO_MOUNT_MAKE_SLAVE_KEYWORD) ||
+ !strcmp(type, TOMOYO_MOUNT_MAKE_SHARED_KEYWORD))
+ tomoyo_warn_log(r, "mount %s %s 0x%lX", type, dir, flags);
+ else
+ tomoyo_warn_log(r, "mount -t %s %s %s 0x%lX", type, dev, dir,
+ flags);
+ return tomoyo_supervisor(r,
+ TOMOYO_KEYWORD_ALLOW_MOUNT "%s %s %s 0x%lX\n",
+ tomoyo_pattern(r->param.mount.dev),
+ tomoyo_pattern(r->param.mount.dir), type,
+ flags);
+}
+
+static bool tomoyo_check_mount_acl(struct tomoyo_request_info *r,
+ const struct tomoyo_acl_info *ptr)
+{
+ const struct tomoyo_mount_acl *acl =
+ container_of(ptr, typeof(*acl), head);
+ return tomoyo_compare_number_union(r->param.mount.flags, &acl->flags) &&
+ tomoyo_compare_name_union(r->param.mount.type, &acl->fs_type) &&
+ tomoyo_compare_name_union(r->param.mount.dir, &acl->dir_name) &&
+ (!r->param.mount.need_dev ||
+ tomoyo_compare_name_union(r->param.mount.dev, &acl->dev_name));
+}
+
+/**
+ * tomoyo_mount_acl - Check permission for mount() operation.
+ *
+ * @r: Pointer to "struct tomoyo_request_info".
+ * @dev_name: Name of device file.
+ * @dir: Pointer to "struct path".
+ * @type: Name of filesystem type.
+ * @flags: Mount options.
+ *
+ * Returns 0 on success, negative value otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
+ */
+static int tomoyo_mount_acl(struct tomoyo_request_info *r, char *dev_name,
+ struct path *dir, char *type, unsigned long flags)
+{
+ struct path path;
+ struct file_system_type *fstype = NULL;
+ const char *requested_type = NULL;
+ const char *requested_dir_name = NULL;
+ const char *requested_dev_name = NULL;
+ struct tomoyo_path_info rtype;
+ struct tomoyo_path_info rdev;
+ struct tomoyo_path_info rdir;
+ int need_dev = 0;
+ int error = -ENOMEM;
+
+ /* Get fstype. */
+ requested_type = tomoyo_encode(type);
+ if (!requested_type)
+ goto out;
+ rtype.name = requested_type;
+ tomoyo_fill_path_info(&rtype);
+
+ /* Get mount point. */
+ requested_dir_name = tomoyo_realpath_from_path(dir);
+ if (!requested_dir_name) {
+ error = -ENOMEM;
+ goto out;
+ }
+ rdir.name = requested_dir_name;
+ tomoyo_fill_path_info(&rdir);
+
+ /* Compare fs name. */
+ if (!strcmp(type, TOMOYO_MOUNT_REMOUNT_KEYWORD)) {
+ /* dev_name is ignored. */
+ } else if (!strcmp(type, TOMOYO_MOUNT_MAKE_UNBINDABLE_KEYWORD) ||
+ !strcmp(type, TOMOYO_MOUNT_MAKE_PRIVATE_KEYWORD) ||
+ !strcmp(type, TOMOYO_MOUNT_MAKE_SLAVE_KEYWORD) ||
+ !strcmp(type, TOMOYO_MOUNT_MAKE_SHARED_KEYWORD)) {
+ /* dev_name is ignored. */
+ } else if (!strcmp(type, TOMOYO_MOUNT_BIND_KEYWORD) ||
+ !strcmp(type, TOMOYO_MOUNT_MOVE_KEYWORD)) {
+ need_dev = -1; /* dev_name is a directory */
+ } else {
+ fstype = get_fs_type(type);
+ if (!fstype) {
+ error = -ENODEV;
+ goto out;
+ }
+ if (fstype->fs_flags & FS_REQUIRES_DEV)
+ /* dev_name is a block device file. */
+ need_dev = 1;
+ }
+ if (need_dev) {
+ /* Get mount point or device file. */
+ if (kern_path(dev_name, LOOKUP_FOLLOW, &path)) {
+ error = -ENOENT;
+ goto out;
+ }
+ requested_dev_name = tomoyo_realpath_from_path(&path);
+ if (!requested_dev_name) {
+ error = -ENOENT;
+ goto out;
+ }
+ } else {
+ /* Map dev_name to "<NULL>" if no dev_name given. */
+ if (!dev_name)
+ dev_name = "<NULL>";
+ requested_dev_name = tomoyo_encode(dev_name);
+ if (!requested_dev_name) {
+ error = -ENOMEM;
+ goto out;
+ }
+ }
+ rdev.name = requested_dev_name;
+ tomoyo_fill_path_info(&rdev);
+ r->param_type = TOMOYO_TYPE_MOUNT_ACL;
+ r->param.mount.need_dev = need_dev;
+ r->param.mount.dev = &rdev;
+ r->param.mount.dir = &rdir;
+ r->param.mount.type = &rtype;
+ r->param.mount.flags = flags;
+ do {
+ tomoyo_check_acl(r, tomoyo_check_mount_acl);
+ error = tomoyo_audit_mount_log(r);
+ } while (error == TOMOYO_RETRY_REQUEST);
+ out:
+ kfree(requested_dev_name);
+ kfree(requested_dir_name);
+ if (fstype)
+ put_filesystem(fstype);
+ kfree(requested_type);
+ return error;
+}
+
+/**
+ * tomoyo_mount_permission - Check permission for mount() operation.
+ *
+ * @dev_name: Name of device file.
+ * @path: Pointer to "struct path".
+ * @type: Name of filesystem type. May be NULL.
+ * @flags: Mount options.
+ * @data_page: Optional data. May be NULL.
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
+int tomoyo_mount_permission(char *dev_name, struct path *path, char *type,
+ unsigned long flags, void *data_page)
+{
+ struct tomoyo_request_info r;
+ int error;
+ int idx;
+
+ if (tomoyo_init_request_info(&r, NULL, TOMOYO_MAC_FILE_MOUNT)
+ == TOMOYO_CONFIG_DISABLED)
+ return 0;
+ if ((flags & MS_MGC_MSK) == MS_MGC_VAL)
+ flags &= ~MS_MGC_MSK;
+ if (flags & MS_REMOUNT) {
+ type = TOMOYO_MOUNT_REMOUNT_KEYWORD;
+ flags &= ~MS_REMOUNT;
+ }
+ if (flags & MS_MOVE) {
+ type = TOMOYO_MOUNT_MOVE_KEYWORD;
+ flags &= ~MS_MOVE;
+ }
+ if (flags & MS_BIND) {
+ type = TOMOYO_MOUNT_BIND_KEYWORD;
+ flags &= ~MS_BIND;
+ }
+ if (flags & MS_UNBINDABLE) {
+ type = TOMOYO_MOUNT_MAKE_UNBINDABLE_KEYWORD;
+ flags &= ~MS_UNBINDABLE;
+ }
+ if (flags & MS_PRIVATE) {
+ type = TOMOYO_MOUNT_MAKE_PRIVATE_KEYWORD;
+ flags &= ~MS_PRIVATE;
+ }
+ if (flags & MS_SLAVE) {
+ type = TOMOYO_MOUNT_MAKE_SLAVE_KEYWORD;
+ flags &= ~MS_SLAVE;
+ }
+ if (flags & MS_SHARED) {
+ type = TOMOYO_MOUNT_MAKE_SHARED_KEYWORD;
+ flags &= ~MS_SHARED;
+ }
+ if (!type)
+ type = "<NULL>";
+ idx = tomoyo_read_lock();
+ error = tomoyo_mount_acl(&r, dev_name, path, type, flags);
+ tomoyo_read_unlock(idx);
+ return error;
+}
+
+static bool tomoyo_same_mount_acl(const struct tomoyo_acl_info *a,
+ const struct tomoyo_acl_info *b)
+{
+ const struct tomoyo_mount_acl *p1 = container_of(a, typeof(*p1), head);
+ const struct tomoyo_mount_acl *p2 = container_of(b, typeof(*p2), head);
+ return tomoyo_same_acl_head(&p1->head, &p2->head) &&
+ tomoyo_same_name_union(&p1->dev_name, &p2->dev_name) &&
+ tomoyo_same_name_union(&p1->dir_name, &p2->dir_name) &&
+ tomoyo_same_name_union(&p1->fs_type, &p2->fs_type) &&
+ tomoyo_same_number_union(&p1->flags, &p2->flags);
+}
+
+/**
+ * tomoyo_write_mount - Write "struct tomoyo_mount_acl" list.
+ *
+ * @data: String to parse.
+ * @domain: Pointer to "struct tomoyo_domain_info".
+ * @is_delete: True if it is a delete request.
+ *
+ * Returns 0 on success, negative value otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
+ */
+int tomoyo_write_mount(char *data, struct tomoyo_domain_info *domain,
+ const bool is_delete)
+{
+ struct tomoyo_mount_acl e = { .head.type = TOMOYO_TYPE_MOUNT_ACL };
+ int error = is_delete ? -ENOENT : -ENOMEM;
+ char *w[4];
+ if (!tomoyo_tokenize(data, w, sizeof(w)) || !w[3][0])
+ return -EINVAL;
+ if (!tomoyo_parse_name_union(w[0], &e.dev_name) ||
+ !tomoyo_parse_name_union(w[1], &e.dir_name) ||
+ !tomoyo_parse_name_union(w[2], &e.fs_type) ||
+ !tomoyo_parse_number_union(w[3], &e.flags))
+ goto out;
+ error = tomoyo_update_domain(&e.head, sizeof(e), is_delete, domain,
+ tomoyo_same_mount_acl, NULL);
+ out:
+ tomoyo_put_name_union(&e.dev_name);
+ tomoyo_put_name_union(&e.dir_name);
+ tomoyo_put_name_union(&e.fs_type);
+ tomoyo_put_number_union(&e.flags);
+ return error;
+}
diff --git a/security/tomoyo/path_group.c b/security/tomoyo/path_group.c
deleted file mode 100644
index c988041c8e1..00000000000
--- a/security/tomoyo/path_group.c
+++ /dev/null
@@ -1,172 +0,0 @@
-/*
- * security/tomoyo/path_group.c
- *
- * Copyright (C) 2005-2009 NTT DATA CORPORATION
- */
-
-#include <linux/slab.h>
-#include "common.h"
-/* The list for "struct ccs_path_group". */
-LIST_HEAD(tomoyo_path_group_list);
-
-/**
- * tomoyo_get_path_group - Allocate memory for "struct tomoyo_path_group".
- *
- * @group_name: The name of pathname group.
- *
- * Returns pointer to "struct tomoyo_path_group" on success, NULL otherwise.
- */
-struct tomoyo_path_group *tomoyo_get_path_group(const char *group_name)
-{
- struct tomoyo_path_group *entry = NULL;
- struct tomoyo_path_group *group = NULL;
- const struct tomoyo_path_info *saved_group_name;
- int error = -ENOMEM;
- if (!tomoyo_is_correct_path(group_name, 0, 0, 0) ||
- !group_name[0])
- return NULL;
- saved_group_name = tomoyo_get_name(group_name);
- if (!saved_group_name)
- return NULL;
- entry = kzalloc(sizeof(*entry), GFP_NOFS);
- if (mutex_lock_interruptible(&tomoyo_policy_lock))
- goto out;
- list_for_each_entry_rcu(group, &tomoyo_path_group_list, list) {
- if (saved_group_name != group->group_name)
- continue;
- atomic_inc(&group->users);
- error = 0;
- break;
- }
- if (error && tomoyo_memory_ok(entry)) {
- INIT_LIST_HEAD(&entry->member_list);
- entry->group_name = saved_group_name;
- saved_group_name = NULL;
- atomic_set(&entry->users, 1);
- list_add_tail_rcu(&entry->list, &tomoyo_path_group_list);
- group = entry;
- entry = NULL;
- error = 0;
- }
- mutex_unlock(&tomoyo_policy_lock);
- out:
- tomoyo_put_name(saved_group_name);
- kfree(entry);
- return !error ? group : NULL;
-}
-
-/**
- * tomoyo_write_path_group_policy - Write "struct tomoyo_path_group" list.
- *
- * @data: String to parse.
- * @is_delete: True if it is a delete request.
- *
- * Returns 0 on success, nagative value otherwise.
- */
-int tomoyo_write_path_group_policy(char *data, const bool is_delete)
-{
- struct tomoyo_path_group *group;
- struct tomoyo_path_group_member *member;
- struct tomoyo_path_group_member e = { };
- int error = is_delete ? -ENOENT : -ENOMEM;
- char *w[2];
- if (!tomoyo_tokenize(data, w, sizeof(w)) || !w[1][0])
- return -EINVAL;
- group = tomoyo_get_path_group(w[0]);
- if (!group)
- return -ENOMEM;
- e.member_name = tomoyo_get_name(w[1]);
- if (!e.member_name)
- goto out;
- if (mutex_lock_interruptible(&tomoyo_policy_lock))
- goto out;
- list_for_each_entry_rcu(member, &group->member_list, list) {
- if (member->member_name != e.member_name)
- continue;
- member->is_deleted = is_delete;
- error = 0;
- break;
- }
- if (!is_delete && error) {
- struct tomoyo_path_group_member *entry =
- tomoyo_commit_ok(&e, sizeof(e));
- if (entry) {
- list_add_tail_rcu(&entry->list, &group->member_list);
- error = 0;
- }
- }
- mutex_unlock(&tomoyo_policy_lock);
- out:
- tomoyo_put_name(e.member_name);
- tomoyo_put_path_group(group);
- return error;
-}
-
-/**
- * tomoyo_read_path_group_policy - Read "struct tomoyo_path_group" list.
- *
- * @head: Pointer to "struct tomoyo_io_buffer".
- *
- * Returns true on success, false otherwise.
- *
- * Caller holds tomoyo_read_lock().
- */
-bool tomoyo_read_path_group_policy(struct tomoyo_io_buffer *head)
-{
- struct list_head *gpos;
- struct list_head *mpos;
- list_for_each_cookie(gpos, head->read_var1, &tomoyo_path_group_list) {
- struct tomoyo_path_group *group;
- group = list_entry(gpos, struct tomoyo_path_group, list);
- list_for_each_cookie(mpos, head->read_var2,
- &group->member_list) {
- struct tomoyo_path_group_member *member;
- member = list_entry(mpos,
- struct tomoyo_path_group_member,
- list);
- if (member->is_deleted)
- continue;
- if (!tomoyo_io_printf(head, TOMOYO_KEYWORD_PATH_GROUP
- "%s %s\n",
- group->group_name->name,
- member->member_name->name))
- return false;
- }
- }
- return true;
-}
-
-/**
- * tomoyo_path_matches_group - Check whether the given pathname matches members of the given pathname group.
- *
- * @pathname: The name of pathname.
- * @group: Pointer to "struct tomoyo_path_group".
- * @may_use_pattern: True if wild card is permitted.
- *
- * Returns true if @pathname matches pathnames in @group, false otherwise.
- *
- * Caller holds tomoyo_read_lock().
- */
-bool tomoyo_path_matches_group(const struct tomoyo_path_info *pathname,
- const struct tomoyo_path_group *group,
- const bool may_use_pattern)
-{
- struct tomoyo_path_group_member *member;
- bool matched = false;
- list_for_each_entry_rcu(member, &group->member_list, list) {
- if (member->is_deleted)
- continue;
- if (!member->member_name->is_patterned) {
- if (tomoyo_pathcmp(pathname, member->member_name))
- continue;
- } else if (may_use_pattern) {
- if (!tomoyo_path_matches_pattern(pathname,
- member->member_name))
- continue;
- } else
- continue;
- matched = true;
- break;
- }
- return matched;
-}
diff --git a/security/tomoyo/realpath.c b/security/tomoyo/realpath.c
index d1b96f01962..ed8ccd68010 100644
--- a/security/tomoyo/realpath.c
+++ b/security/tomoyo/realpath.c
@@ -1,174 +1,164 @@
/*
* security/tomoyo/realpath.c
*
- * Get the canonicalized absolute pathnames. The basis for TOMOYO.
- *
- * Copyright (C) 2005-2009 NTT DATA CORPORATION
- *
- * Version: 2.2.0 2009/04/01
+ * Pathname calculation functions for TOMOYO.
*
+ * Copyright (C) 2005-2010 NTT DATA CORPORATION
*/
#include <linux/types.h>
#include <linux/mount.h>
#include <linux/mnt_namespace.h>
#include <linux/fs_struct.h>
-#include <linux/hash.h>
#include <linux/magic.h>
#include <linux/slab.h>
+#include <net/sock.h>
#include "common.h"
/**
* tomoyo_encode: Convert binary string to ascii string.
*
- * @buffer: Buffer for ASCII string.
- * @buflen: Size of @buffer.
- * @str: Binary string.
+ * @str: String in binary format.
+ *
+ * Returns pointer to @str in ascii format on success, NULL otherwise.
*
- * Returns 0 on success, -ENOMEM otherwise.
+ * This function uses kzalloc(), so caller must kfree() if this function
+ * didn't return NULL.
*/
-int tomoyo_encode(char *buffer, int buflen, const char *str)
+char *tomoyo_encode(const char *str)
{
- while (1) {
- const unsigned char c = *(unsigned char *) str++;
+ int len = 0;
+ const char *p = str;
+ char *cp;
+ char *cp0;
- if (tomoyo_is_valid(c)) {
- if (--buflen <= 0)
- break;
- *buffer++ = (char) c;
- if (c != '\\')
- continue;
- if (--buflen <= 0)
- break;
- *buffer++ = (char) c;
- continue;
- }
- if (!c) {
- if (--buflen <= 0)
- break;
- *buffer = '\0';
- return 0;
+ if (!p)
+ return NULL;
+ while (*p) {
+ const unsigned char c = *p++;
+ if (c == '\\')
+ len += 2;
+ else if (c > ' ' && c < 127)
+ len++;
+ else
+ len += 4;
+ }
+ len++;
+ /* Reserve space for appending "/". */
+ cp = kzalloc(len + 10, GFP_NOFS);
+ if (!cp)
+ return NULL;
+ cp0 = cp;
+ p = str;
+ while (*p) {
+ const unsigned char c = *p++;
+
+ if (c == '\\') {
+ *cp++ = '\\';
+ *cp++ = '\\';
+ } else if (c > ' ' && c < 127) {
+ *cp++ = c;
+ } else {
+ *cp++ = '\\';
+ *cp++ = (c >> 6) + '0';
+ *cp++ = ((c >> 3) & 7) + '0';
+ *cp++ = (c & 7) + '0';
}
- buflen -= 4;
- if (buflen <= 0)
- break;
- *buffer++ = '\\';
- *buffer++ = (c >> 6) + '0';
- *buffer++ = ((c >> 3) & 7) + '0';
- *buffer++ = (c & 7) + '0';
}
- return -ENOMEM;
+ return cp0;
}
/**
- * tomoyo_realpath_from_path2 - Returns realpath(3) of the given dentry but ignores chroot'ed root.
+ * tomoyo_realpath_from_path - Returns realpath(3) of the given pathname but ignores chroot'ed root.
*
- * @path: Pointer to "struct path".
- * @newname: Pointer to buffer to return value in.
- * @newname_len: Size of @newname.
+ * @path: Pointer to "struct path".
*
- * Returns 0 on success, negative value otherwise.
+ * Returns the realpath of the given @path on success, NULL otherwise.
*
* If dentry is a directory, trailing '/' is appended.
* Characters out of 0x20 < c < 0x7F range are converted to
* \ooo style octal string.
* Character \ is converted to \\ string.
+ *
+ * These functions use kzalloc(), so the caller must call kfree()
+ * if these functions didn't return NULL.
*/
-int tomoyo_realpath_from_path2(struct path *path, char *newname,
- int newname_len)
+char *tomoyo_realpath_from_path(struct path *path)
{
- int error = -ENOMEM;
+ char *buf = NULL;
+ char *name = NULL;
+ unsigned int buf_len = PAGE_SIZE / 2;
struct dentry *dentry = path->dentry;
- char *sp;
-
- if (!dentry || !path->mnt || !newname || newname_len <= 2048)
- return -EINVAL;
- if (dentry->d_op && dentry->d_op->d_dname) {
+ bool is_dir;
+ if (!dentry)
+ return NULL;
+ is_dir = dentry->d_inode && S_ISDIR(dentry->d_inode->i_mode);
+ while (1) {
+ struct path ns_root = { .mnt = NULL, .dentry = NULL };
+ char *pos;
+ buf_len <<= 1;
+ kfree(buf);
+ buf = kmalloc(buf_len, GFP_NOFS);
+ if (!buf)
+ break;
+ /* Get better name for socket. */
+ if (dentry->d_sb && dentry->d_sb->s_magic == SOCKFS_MAGIC) {
+ struct inode *inode = dentry->d_inode;
+ struct socket *sock = inode ? SOCKET_I(inode) : NULL;
+ struct sock *sk = sock ? sock->sk : NULL;
+ if (sk) {
+ snprintf(buf, buf_len - 1, "socket:[family=%u:"
+ "type=%u:protocol=%u]", sk->sk_family,
+ sk->sk_type, sk->sk_protocol);
+ } else {
+ snprintf(buf, buf_len - 1, "socket:[unknown]");
+ }
+ name = tomoyo_encode(buf);
+ break;
+ }
/* For "socket:[\$]" and "pipe:[\$]". */
- static const int offset = 1536;
- sp = dentry->d_op->d_dname(dentry, newname + offset,
- newname_len - offset);
- } else {
- struct path ns_root = {.mnt = NULL, .dentry = NULL};
-
+ if (dentry->d_op && dentry->d_op->d_dname) {
+ pos = dentry->d_op->d_dname(dentry, buf, buf_len - 1);
+ if (IS_ERR(pos))
+ continue;
+ name = tomoyo_encode(pos);
+ break;
+ }
+ /* If we don't have a vfsmount, we can't calculate. */
+ if (!path->mnt)
+ break;
spin_lock(&dcache_lock);
/* go to whatever namespace root we are under */
- sp = __d_path(path, &ns_root, newname, newname_len);
+ pos = __d_path(path, &ns_root, buf, buf_len);
spin_unlock(&dcache_lock);
/* Prepend "/proc" prefix if using internal proc vfs mount. */
- if (!IS_ERR(sp) && (path->mnt->mnt_flags & MNT_INTERNAL) &&
+ if (!IS_ERR(pos) && (path->mnt->mnt_flags & MNT_INTERNAL) &&
(path->mnt->mnt_sb->s_magic == PROC_SUPER_MAGIC)) {
- sp -= 5;
- if (sp >= newname)
- memcpy(sp, "/proc", 5);
+ pos -= 5;
+ if (pos >= buf)
+ memcpy(pos, "/proc", 5);
else
- sp = ERR_PTR(-ENOMEM);
- }
- }
- if (IS_ERR(sp))
- error = PTR_ERR(sp);
- else
- error = tomoyo_encode(newname, sp - newname, sp);
- /* Append trailing '/' if dentry is a directory. */
- if (!error && dentry->d_inode && S_ISDIR(dentry->d_inode->i_mode)
- && *newname) {
- sp = newname + strlen(newname);
- if (*(sp - 1) != '/') {
- if (sp < newname + newname_len - 4) {
- *sp++ = '/';
- *sp = '\0';
- } else {
- error = -ENOMEM;
- }
+ pos = ERR_PTR(-ENOMEM);
}
+ if (IS_ERR(pos))
+ continue;
+ name = tomoyo_encode(pos);
+ break;
}
- if (error)
- printk(KERN_WARNING "tomoyo_realpath: Pathname too long.\n");
- return error;
-}
-
-/**
- * tomoyo_realpath_from_path - Returns realpath(3) of the given pathname but ignores chroot'ed root.
- *
- * @path: Pointer to "struct path".
- *
- * Returns the realpath of the given @path on success, NULL otherwise.
- *
- * These functions use kzalloc(), so the caller must call kfree()
- * if these functions didn't return NULL.
- */
-char *tomoyo_realpath_from_path(struct path *path)
-{
- char *buf = kzalloc(sizeof(struct tomoyo_page_buffer), GFP_NOFS);
-
- BUILD_BUG_ON(sizeof(struct tomoyo_page_buffer)
- <= TOMOYO_MAX_PATHNAME_LEN - 1);
- if (!buf)
- return NULL;
- if (tomoyo_realpath_from_path2(path, buf,
- TOMOYO_MAX_PATHNAME_LEN - 1) == 0)
- return buf;
kfree(buf);
- return NULL;
-}
-
-/**
- * tomoyo_realpath - Get realpath of a pathname.
- *
- * @pathname: The pathname to solve.
- *
- * Returns the realpath of @pathname on success, NULL otherwise.
- */
-char *tomoyo_realpath(const char *pathname)
-{
- struct path path;
-
- if (pathname && kern_path(pathname, LOOKUP_FOLLOW, &path) == 0) {
- char *buf = tomoyo_realpath_from_path(&path);
- path_put(&path);
- return buf;
+ if (!name)
+ tomoyo_warn_oom(__func__);
+ else if (is_dir && *name) {
+ /* Append trailing '/' if dentry is a directory. */
+ char *pos = name + strlen(name) - 1;
+ if (*pos != '/')
+ /*
+ * This is OK because tomoyo_encode() reserves space
+ * for appending "/".
+ */
+ *++pos = '/';
}
- return NULL;
+ return name;
}
/**
@@ -189,191 +179,3 @@ char *tomoyo_realpath_nofollow(const char *pathname)
}
return NULL;
}
-
-/* Memory allocated for non-string data. */
-static atomic_t tomoyo_policy_memory_size;
-/* Quota for holding policy. */
-static unsigned int tomoyo_quota_for_policy;
-
-/**
- * tomoyo_memory_ok - Check memory quota.
- *
- * @ptr: Pointer to allocated memory.
- *
- * Returns true on success, false otherwise.
- *
- * Caller holds tomoyo_policy_lock.
- * Memory pointed by @ptr will be zeroed on success.
- */
-bool tomoyo_memory_ok(void *ptr)
-{
- int allocated_len = ptr ? ksize(ptr) : 0;
- atomic_add(allocated_len, &tomoyo_policy_memory_size);
- if (ptr && (!tomoyo_quota_for_policy ||
- atomic_read(&tomoyo_policy_memory_size)
- <= tomoyo_quota_for_policy)) {
- memset(ptr, 0, allocated_len);
- return true;
- }
- printk(KERN_WARNING "ERROR: Out of memory "
- "for tomoyo_alloc_element().\n");
- if (!tomoyo_policy_loaded)
- panic("MAC Initialization failed.\n");
- return false;
-}
-
-/**
- * tomoyo_commit_ok - Check memory quota.
- *
- * @data: Data to copy from.
- * @size: Size in byte.
- *
- * Returns pointer to allocated memory on success, NULL otherwise.
- */
-void *tomoyo_commit_ok(void *data, const unsigned int size)
-{
- void *ptr = kzalloc(size, GFP_NOFS);
- if (tomoyo_memory_ok(ptr)) {
- memmove(ptr, data, size);
- memset(data, 0, size);
- return ptr;
- }
- return NULL;
-}
-
-/**
- * tomoyo_memory_free - Free memory for elements.
- *
- * @ptr: Pointer to allocated memory.
- */
-void tomoyo_memory_free(void *ptr)
-{
- atomic_sub(ksize(ptr), &tomoyo_policy_memory_size);
- kfree(ptr);
-}
-
-/*
- * tomoyo_name_list is used for holding string data used by TOMOYO.
- * Since same string data is likely used for multiple times (e.g.
- * "/lib/libc-2.5.so"), TOMOYO shares string data in the form of
- * "const struct tomoyo_path_info *".
- */
-struct list_head tomoyo_name_list[TOMOYO_MAX_HASH];
-
-/**
- * tomoyo_get_name - Allocate permanent memory for string data.
- *
- * @name: The string to store into the permernent memory.
- *
- * Returns pointer to "struct tomoyo_path_info" on success, NULL otherwise.
- */
-const struct tomoyo_path_info *tomoyo_get_name(const char *name)
-{
- struct tomoyo_name_entry *ptr;
- unsigned int hash;
- int len;
- int allocated_len;
- struct list_head *head;
-
- if (!name)
- return NULL;
- len = strlen(name) + 1;
- hash = full_name_hash((const unsigned char *) name, len - 1);
- head = &tomoyo_name_list[hash_long(hash, TOMOYO_HASH_BITS)];
- if (mutex_lock_interruptible(&tomoyo_policy_lock))
- return NULL;
- list_for_each_entry(ptr, head, list) {
- if (hash != ptr->entry.hash || strcmp(name, ptr->entry.name))
- continue;
- atomic_inc(&ptr->users);
- goto out;
- }
- ptr = kzalloc(sizeof(*ptr) + len, GFP_NOFS);
- allocated_len = ptr ? ksize(ptr) : 0;
- if (!ptr || (tomoyo_quota_for_policy &&
- atomic_read(&tomoyo_policy_memory_size) + allocated_len
- > tomoyo_quota_for_policy)) {
- kfree(ptr);
- printk(KERN_WARNING "ERROR: Out of memory "
- "for tomoyo_get_name().\n");
- if (!tomoyo_policy_loaded)
- panic("MAC Initialization failed.\n");
- ptr = NULL;
- goto out;
- }
- atomic_add(allocated_len, &tomoyo_policy_memory_size);
- ptr->entry.name = ((char *) ptr) + sizeof(*ptr);
- memmove((char *) ptr->entry.name, name, len);
- atomic_set(&ptr->users, 1);
- tomoyo_fill_path_info(&ptr->entry);
- list_add_tail(&ptr->list, head);
- out:
- mutex_unlock(&tomoyo_policy_lock);
- return ptr ? &ptr->entry : NULL;
-}
-
-/**
- * tomoyo_realpath_init - Initialize realpath related code.
- */
-void __init tomoyo_realpath_init(void)
-{
- int i;
-
- BUILD_BUG_ON(TOMOYO_MAX_PATHNAME_LEN > PATH_MAX);
- for (i = 0; i < TOMOYO_MAX_HASH; i++)
- INIT_LIST_HEAD(&tomoyo_name_list[i]);
- INIT_LIST_HEAD(&tomoyo_kernel_domain.acl_info_list);
- tomoyo_kernel_domain.domainname = tomoyo_get_name(TOMOYO_ROOT_NAME);
- /*
- * tomoyo_read_lock() is not needed because this function is
- * called before the first "delete" request.
- */
- list_add_tail_rcu(&tomoyo_kernel_domain.list, &tomoyo_domain_list);
- if (tomoyo_find_domain(TOMOYO_ROOT_NAME) != &tomoyo_kernel_domain)
- panic("Can't register tomoyo_kernel_domain");
-}
-
-/**
- * tomoyo_read_memory_counter - Check for memory usage in bytes.
- *
- * @head: Pointer to "struct tomoyo_io_buffer".
- *
- * Returns memory usage.
- */
-int tomoyo_read_memory_counter(struct tomoyo_io_buffer *head)
-{
- if (!head->read_eof) {
- const unsigned int policy
- = atomic_read(&tomoyo_policy_memory_size);
- char buffer[64];
-
- memset(buffer, 0, sizeof(buffer));
- if (tomoyo_quota_for_policy)
- snprintf(buffer, sizeof(buffer) - 1,
- " (Quota: %10u)",
- tomoyo_quota_for_policy);
- else
- buffer[0] = '\0';
- tomoyo_io_printf(head, "Policy: %10u%s\n", policy, buffer);
- tomoyo_io_printf(head, "Total: %10u\n", policy);
- head->read_eof = true;
- }
- return 0;
-}
-
-/**
- * tomoyo_write_memory_quota - Set memory quota.
- *
- * @head: Pointer to "struct tomoyo_io_buffer".
- *
- * Returns 0.
- */
-int tomoyo_write_memory_quota(struct tomoyo_io_buffer *head)
-{
- char *data = head->write_buf;
- unsigned int size;
-
- if (sscanf(data, "Policy: %u", &size) == 1)
- tomoyo_quota_for_policy = size;
- return 0;
-}
diff --git a/security/tomoyo/securityfs_if.c b/security/tomoyo/securityfs_if.c
new file mode 100644
index 00000000000..e43d5554b50
--- /dev/null
+++ b/security/tomoyo/securityfs_if.c
@@ -0,0 +1,155 @@
+/*
+ * security/tomoyo/common.c
+ *
+ * Securityfs interface for TOMOYO.
+ *
+ * Copyright (C) 2005-2010 NTT DATA CORPORATION
+ */
+
+#include <linux/security.h>
+#include "common.h"
+
+/**
+ * tomoyo_open - open() for /sys/kernel/security/tomoyo/ interface.
+ *
+ * @inode: Pointer to "struct inode".
+ * @file: Pointer to "struct file".
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
+static int tomoyo_open(struct inode *inode, struct file *file)
+{
+ const int key = ((u8 *) file->f_path.dentry->d_inode->i_private)
+ - ((u8 *) NULL);
+ return tomoyo_open_control(key, file);
+}
+
+/**
+ * tomoyo_release - close() for /sys/kernel/security/tomoyo/ interface.
+ *
+ * @inode: Pointer to "struct inode".
+ * @file: Pointer to "struct file".
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
+static int tomoyo_release(struct inode *inode, struct file *file)
+{
+ return tomoyo_close_control(file);
+}
+
+/**
+ * tomoyo_poll - poll() for /proc/ccs/ interface.
+ *
+ * @file: Pointer to "struct file".
+ * @wait: Pointer to "poll_table".
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
+static unsigned int tomoyo_poll(struct file *file, poll_table *wait)
+{
+ return tomoyo_poll_control(file, wait);
+}
+
+/**
+ * tomoyo_read - read() for /sys/kernel/security/tomoyo/ interface.
+ *
+ * @file: Pointer to "struct file".
+ * @buf: Pointer to buffer.
+ * @count: Size of @buf.
+ * @ppos: Unused.
+ *
+ * Returns bytes read on success, negative value otherwise.
+ */
+static ssize_t tomoyo_read(struct file *file, char __user *buf, size_t count,
+ loff_t *ppos)
+{
+ return tomoyo_read_control(file, buf, count);
+}
+
+/**
+ * tomoyo_write - write() for /sys/kernel/security/tomoyo/ interface.
+ *
+ * @file: Pointer to "struct file".
+ * @buf: Pointer to buffer.
+ * @count: Size of @buf.
+ * @ppos: Unused.
+ *
+ * Returns @count on success, negative value otherwise.
+ */
+static ssize_t tomoyo_write(struct file *file, const char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ return tomoyo_write_control(file, buf, count);
+}
+
+/*
+ * tomoyo_operations is a "struct file_operations" which is used for handling
+ * /sys/kernel/security/tomoyo/ interface.
+ *
+ * Some files under /sys/kernel/security/tomoyo/ directory accept open(O_RDWR).
+ * See tomoyo_io_buffer for internals.
+ */
+static const struct file_operations tomoyo_operations = {
+ .open = tomoyo_open,
+ .release = tomoyo_release,
+ .poll = tomoyo_poll,
+ .read = tomoyo_read,
+ .write = tomoyo_write,
+ .llseek = noop_llseek,
+};
+
+/**
+ * tomoyo_create_entry - Create interface files under /sys/kernel/security/tomoyo/ directory.
+ *
+ * @name: The name of the interface file.
+ * @mode: The permission of the interface file.
+ * @parent: The parent directory.
+ * @key: Type of interface.
+ *
+ * Returns nothing.
+ */
+static void __init tomoyo_create_entry(const char *name, const mode_t mode,
+ struct dentry *parent, const u8 key)
+{
+ securityfs_create_file(name, mode, parent, ((u8 *) NULL) + key,
+ &tomoyo_operations);
+}
+
+/**
+ * tomoyo_initerface_init - Initialize /sys/kernel/security/tomoyo/ interface.
+ *
+ * Returns 0.
+ */
+static int __init tomoyo_initerface_init(void)
+{
+ struct dentry *tomoyo_dir;
+
+ /* Don't create securityfs entries unless registered. */
+ if (current_cred()->security != &tomoyo_kernel_domain)
+ return 0;
+
+ tomoyo_dir = securityfs_create_dir("tomoyo", NULL);
+ tomoyo_create_entry("query", 0600, tomoyo_dir,
+ TOMOYO_QUERY);
+ tomoyo_create_entry("domain_policy", 0600, tomoyo_dir,
+ TOMOYO_DOMAINPOLICY);
+ tomoyo_create_entry("exception_policy", 0600, tomoyo_dir,
+ TOMOYO_EXCEPTIONPOLICY);
+ tomoyo_create_entry("self_domain", 0400, tomoyo_dir,
+ TOMOYO_SELFDOMAIN);
+ tomoyo_create_entry(".domain_status", 0600, tomoyo_dir,
+ TOMOYO_DOMAIN_STATUS);
+ tomoyo_create_entry(".process_status", 0600, tomoyo_dir,
+ TOMOYO_PROCESS_STATUS);
+ tomoyo_create_entry("meminfo", 0600, tomoyo_dir,
+ TOMOYO_MEMINFO);
+ tomoyo_create_entry("profile", 0600, tomoyo_dir,
+ TOMOYO_PROFILE);
+ tomoyo_create_entry("manager", 0600, tomoyo_dir,
+ TOMOYO_MANAGER);
+ tomoyo_create_entry("version", 0400, tomoyo_dir,
+ TOMOYO_VERSION);
+ return 0;
+}
+
+fs_initcall(tomoyo_initerface_init);
diff --git a/security/tomoyo/tomoyo.c b/security/tomoyo/tomoyo.c
index dedd97d0c16..95d3f957223 100644
--- a/security/tomoyo/tomoyo.c
+++ b/security/tomoyo/tomoyo.c
@@ -3,10 +3,7 @@
*
* LSM hooks for TOMOYO Linux.
*
- * Copyright (C) 2005-2009 NTT DATA CORPORATION
- *
- * Version: 2.2.0 2009/04/01
- *
+ * Copyright (C) 2005-2010 NTT DATA CORPORATION
*/
#include <linux/security.h>
@@ -96,8 +93,7 @@ static int tomoyo_bprm_check_security(struct linux_binprm *bprm)
return tomoyo_check_open_permission(domain, &bprm->file->f_path, O_RDONLY);
}
-static int tomoyo_path_truncate(struct path *path, loff_t length,
- unsigned int time_attrs)
+static int tomoyo_path_truncate(struct path *path)
{
return tomoyo_path_perm(TOMOYO_TYPE_TRUNCATE, path);
}
@@ -112,7 +108,8 @@ static int tomoyo_path_mkdir(struct path *parent, struct dentry *dentry,
int mode)
{
struct path path = { parent->mnt, dentry };
- return tomoyo_path_perm(TOMOYO_TYPE_MKDIR, &path);
+ return tomoyo_path_number_perm(TOMOYO_TYPE_MKDIR, &path,
+ mode & S_IALLUGO);
}
static int tomoyo_path_rmdir(struct path *parent, struct dentry *dentry)
@@ -133,6 +130,7 @@ static int tomoyo_path_mknod(struct path *parent, struct dentry *dentry,
{
struct path path = { parent->mnt, dentry };
int type = TOMOYO_TYPE_CREATE;
+ const unsigned int perm = mode & S_IALLUGO;
switch (mode & S_IFMT) {
case S_IFCHR:
@@ -141,6 +139,12 @@ static int tomoyo_path_mknod(struct path *parent, struct dentry *dentry,
case S_IFBLK:
type = TOMOYO_TYPE_MKBLOCK;
break;
+ default:
+ goto no_dev;
+ }
+ return tomoyo_mkdev_perm(type, &path, perm, dev);
+ no_dev:
+ switch (mode & S_IFMT) {
case S_IFIFO:
type = TOMOYO_TYPE_MKFIFO;
break;
@@ -148,7 +152,7 @@ static int tomoyo_path_mknod(struct path *parent, struct dentry *dentry,
type = TOMOYO_TYPE_MKSOCK;
break;
}
- return tomoyo_path_perm(type, &path);
+ return tomoyo_path_number_perm(type, &path, perm);
}
static int tomoyo_path_link(struct dentry *old_dentry, struct path *new_dir,
@@ -173,7 +177,7 @@ static int tomoyo_file_fcntl(struct file *file, unsigned int cmd,
unsigned long arg)
{
if (cmd == F_SETFL && ((arg ^ file->f_flags) & O_APPEND))
- return tomoyo_check_rewrite_permission(file);
+ return tomoyo_path_perm(TOMOYO_TYPE_REWRITE, &file->f_path);
return 0;
}
@@ -189,23 +193,24 @@ static int tomoyo_dentry_open(struct file *f, const struct cred *cred)
static int tomoyo_file_ioctl(struct file *file, unsigned int cmd,
unsigned long arg)
{
- return tomoyo_path_perm(TOMOYO_TYPE_IOCTL, &file->f_path);
+ return tomoyo_path_number_perm(TOMOYO_TYPE_IOCTL, &file->f_path, cmd);
}
static int tomoyo_path_chmod(struct dentry *dentry, struct vfsmount *mnt,
mode_t mode)
{
struct path path = { mnt, dentry };
- return tomoyo_path_perm(TOMOYO_TYPE_CHMOD, &path);
+ return tomoyo_path_number_perm(TOMOYO_TYPE_CHMOD, &path,
+ mode & S_IALLUGO);
}
static int tomoyo_path_chown(struct path *path, uid_t uid, gid_t gid)
{
int error = 0;
if (uid != (uid_t) -1)
- error = tomoyo_path_perm(TOMOYO_TYPE_CHOWN, path);
+ error = tomoyo_path_number_perm(TOMOYO_TYPE_CHOWN, path, uid);
if (!error && gid != (gid_t) -1)
- error = tomoyo_path_perm(TOMOYO_TYPE_CHGRP, path);
+ error = tomoyo_path_number_perm(TOMOYO_TYPE_CHGRP, path, gid);
return error;
}
@@ -217,7 +222,7 @@ static int tomoyo_path_chroot(struct path *path)
static int tomoyo_sb_mount(char *dev_name, struct path *path,
char *type, unsigned long flags, void *data)
{
- return tomoyo_path_perm(TOMOYO_TYPE_MOUNT, path);
+ return tomoyo_mount_permission(dev_name, path, type, flags, data);
}
static int tomoyo_sb_umount(struct vfsmount *mnt, int flags)
@@ -277,7 +282,7 @@ static int __init tomoyo_init(void)
panic("Failure registering TOMOYO Linux");
printk(KERN_INFO "TOMOYO Linux initialized\n");
cred->security = &tomoyo_kernel_domain;
- tomoyo_realpath_init();
+ tomoyo_mm_init();
return 0;
}
diff --git a/security/tomoyo/util.c b/security/tomoyo/util.c
new file mode 100644
index 00000000000..9bfc1ee8222
--- /dev/null
+++ b/security/tomoyo/util.c
@@ -0,0 +1,963 @@
+/*
+ * security/tomoyo/util.c
+ *
+ * Utility functions for TOMOYO.
+ *
+ * Copyright (C) 2005-2010 NTT DATA CORPORATION
+ */
+
+#include <linux/slab.h>
+#include "common.h"
+
+/* Lock for protecting policy. */
+DEFINE_MUTEX(tomoyo_policy_lock);
+
+/* Has /sbin/init started? */
+bool tomoyo_policy_loaded;
+
+/**
+ * tomoyo_parse_ulong - Parse an "unsigned long" value.
+ *
+ * @result: Pointer to "unsigned long".
+ * @str: Pointer to string to parse.
+ *
+ * Returns value type on success, 0 otherwise.
+ *
+ * The @src is updated to point the first character after the value
+ * on success.
+ */
+static u8 tomoyo_parse_ulong(unsigned long *result, char **str)
+{
+ const char *cp = *str;
+ char *ep;
+ int base = 10;
+ if (*cp == '0') {
+ char c = *(cp + 1);
+ if (c == 'x' || c == 'X') {
+ base = 16;
+ cp += 2;
+ } else if (c >= '0' && c <= '7') {
+ base = 8;
+ cp++;
+ }
+ }
+ *result = simple_strtoul(cp, &ep, base);
+ if (cp == ep)
+ return 0;
+ *str = ep;
+ switch (base) {
+ case 16:
+ return TOMOYO_VALUE_TYPE_HEXADECIMAL;
+ case 8:
+ return TOMOYO_VALUE_TYPE_OCTAL;
+ default:
+ return TOMOYO_VALUE_TYPE_DECIMAL;
+ }
+}
+
+/**
+ * tomoyo_print_ulong - Print an "unsigned long" value.
+ *
+ * @buffer: Pointer to buffer.
+ * @buffer_len: Size of @buffer.
+ * @value: An "unsigned long" value.
+ * @type: Type of @value.
+ *
+ * Returns nothing.
+ */
+void tomoyo_print_ulong(char *buffer, const int buffer_len,
+ const unsigned long value, const u8 type)
+{
+ if (type == TOMOYO_VALUE_TYPE_DECIMAL)
+ snprintf(buffer, buffer_len, "%lu", value);
+ else if (type == TOMOYO_VALUE_TYPE_OCTAL)
+ snprintf(buffer, buffer_len, "0%lo", value);
+ else if (type == TOMOYO_VALUE_TYPE_HEXADECIMAL)
+ snprintf(buffer, buffer_len, "0x%lX", value);
+ else
+ snprintf(buffer, buffer_len, "type(%u)", type);
+}
+
+/**
+ * tomoyo_parse_name_union - Parse a tomoyo_name_union.
+ *
+ * @filename: Name or name group.
+ * @ptr: Pointer to "struct tomoyo_name_union".
+ *
+ * Returns true on success, false otherwise.
+ */
+bool tomoyo_parse_name_union(const char *filename,
+ struct tomoyo_name_union *ptr)
+{
+ if (!tomoyo_correct_word(filename))
+ return false;
+ if (filename[0] == '@') {
+ ptr->group = tomoyo_get_group(filename + 1, TOMOYO_PATH_GROUP);
+ ptr->is_group = true;
+ return ptr->group != NULL;
+ }
+ ptr->filename = tomoyo_get_name(filename);
+ ptr->is_group = false;
+ return ptr->filename != NULL;
+}
+
+/**
+ * tomoyo_parse_number_union - Parse a tomoyo_number_union.
+ *
+ * @data: Number or number range or number group.
+ * @ptr: Pointer to "struct tomoyo_number_union".
+ *
+ * Returns true on success, false otherwise.
+ */
+bool tomoyo_parse_number_union(char *data, struct tomoyo_number_union *num)
+{
+ u8 type;
+ unsigned long v;
+ memset(num, 0, sizeof(*num));
+ if (data[0] == '@') {
+ if (!tomoyo_correct_word(data))
+ return false;
+ num->group = tomoyo_get_group(data + 1, TOMOYO_NUMBER_GROUP);
+ num->is_group = true;
+ return num->group != NULL;
+ }
+ type = tomoyo_parse_ulong(&v, &data);
+ if (!type)
+ return false;
+ num->values[0] = v;
+ num->min_type = type;
+ if (!*data) {
+ num->values[1] = v;
+ num->max_type = type;
+ return true;
+ }
+ if (*data++ != '-')
+ return false;
+ type = tomoyo_parse_ulong(&v, &data);
+ if (!type || *data)
+ return false;
+ num->values[1] = v;
+ num->max_type = type;
+ return true;
+}
+
+/**
+ * tomoyo_byte_range - Check whether the string is a \ooo style octal value.
+ *
+ * @str: Pointer to the string.
+ *
+ * Returns true if @str is a \ooo style octal value, false otherwise.
+ *
+ * TOMOYO uses \ooo style representation for 0x01 - 0x20 and 0x7F - 0xFF.
+ * This function verifies that \ooo is in valid range.
+ */
+static inline bool tomoyo_byte_range(const char *str)
+{
+ return *str >= '0' && *str++ <= '3' &&
+ *str >= '0' && *str++ <= '7' &&
+ *str >= '0' && *str <= '7';
+}
+
+/**
+ * tomoyo_alphabet_char - Check whether the character is an alphabet.
+ *
+ * @c: The character to check.
+ *
+ * Returns true if @c is an alphabet character, false otherwise.
+ */
+static inline bool tomoyo_alphabet_char(const char c)
+{
+ return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z');
+}
+
+/**
+ * tomoyo_make_byte - Make byte value from three octal characters.
+ *
+ * @c1: The first character.
+ * @c2: The second character.
+ * @c3: The third character.
+ *
+ * Returns byte value.
+ */
+static inline u8 tomoyo_make_byte(const u8 c1, const u8 c2, const u8 c3)
+{
+ return ((c1 - '0') << 6) + ((c2 - '0') << 3) + (c3 - '0');
+}
+
+/**
+ * tomoyo_str_starts - Check whether the given string starts with the given keyword.
+ *
+ * @src: Pointer to pointer to the string.
+ * @find: Pointer to the keyword.
+ *
+ * Returns true if @src starts with @find, false otherwise.
+ *
+ * The @src is updated to point the first character after the @find
+ * if @src starts with @find.
+ */
+bool tomoyo_str_starts(char **src, const char *find)
+{
+ const int len = strlen(find);
+ char *tmp = *src;
+
+ if (strncmp(tmp, find, len))
+ return false;
+ tmp += len;
+ *src = tmp;
+ return true;
+}
+
+/**
+ * tomoyo_normalize_line - Format string.
+ *
+ * @buffer: The line to normalize.
+ *
+ * Leading and trailing whitespaces are removed.
+ * Multiple whitespaces are packed into single space.
+ *
+ * Returns nothing.
+ */
+void tomoyo_normalize_line(unsigned char *buffer)
+{
+ unsigned char *sp = buffer;
+ unsigned char *dp = buffer;
+ bool first = true;
+
+ while (tomoyo_invalid(*sp))
+ sp++;
+ while (*sp) {
+ if (!first)
+ *dp++ = ' ';
+ first = false;
+ while (tomoyo_valid(*sp))
+ *dp++ = *sp++;
+ while (tomoyo_invalid(*sp))
+ sp++;
+ }
+ *dp = '\0';
+}
+
+/**
+ * tomoyo_tokenize - Tokenize string.
+ *
+ * @buffer: The line to tokenize.
+ * @w: Pointer to "char *".
+ * @size: Sizeof @w .
+ *
+ * Returns true on success, false otherwise.
+ */
+bool tomoyo_tokenize(char *buffer, char *w[], size_t size)
+{
+ int count = size / sizeof(char *);
+ int i;
+ for (i = 0; i < count; i++)
+ w[i] = "";
+ for (i = 0; i < count; i++) {
+ char *cp = strchr(buffer, ' ');
+ if (cp)
+ *cp = '\0';
+ w[i] = buffer;
+ if (!cp)
+ break;
+ buffer = cp + 1;
+ }
+ return i < count || !*buffer;
+}
+
+/**
+ * tomoyo_correct_word2 - Validate a string.
+ *
+ * @string: The string to check. May be non-'\0'-terminated.
+ * @len: Length of @string.
+ *
+ * Check whether the given string follows the naming rules.
+ * Returns true if @string follows the naming rules, false otherwise.
+ */
+static bool tomoyo_correct_word2(const char *string, size_t len)
+{
+ const char *const start = string;
+ bool in_repetition = false;
+ unsigned char c;
+ unsigned char d;
+ unsigned char e;
+ if (!len)
+ goto out;
+ while (len--) {
+ c = *string++;
+ if (c == '\\') {
+ if (!len--)
+ goto out;
+ c = *string++;
+ switch (c) {
+ case '\\': /* "\\" */
+ continue;
+ case '$': /* "\$" */
+ case '+': /* "\+" */
+ case '?': /* "\?" */
+ case '*': /* "\*" */
+ case '@': /* "\@" */
+ case 'x': /* "\x" */
+ case 'X': /* "\X" */
+ case 'a': /* "\a" */
+ case 'A': /* "\A" */
+ case '-': /* "\-" */
+ continue;
+ case '{': /* "/\{" */
+ if (string - 3 < start || *(string - 3) != '/')
+ break;
+ in_repetition = true;
+ continue;
+ case '}': /* "\}/" */
+ if (*string != '/')
+ break;
+ if (!in_repetition)
+ break;
+ in_repetition = false;
+ continue;
+ case '0': /* "\ooo" */
+ case '1':
+ case '2':
+ case '3':
+ if (!len-- || !len--)
+ break;
+ d = *string++;
+ e = *string++;
+ if (d < '0' || d > '7' || e < '0' || e > '7')
+ break;
+ c = tomoyo_make_byte(c, d, e);
+ if (tomoyo_invalid(c))
+ continue; /* pattern is not \000 */
+ }
+ goto out;
+ } else if (in_repetition && c == '/') {
+ goto out;
+ } else if (tomoyo_invalid(c)) {
+ goto out;
+ }
+ }
+ if (in_repetition)
+ goto out;
+ return true;
+ out:
+ return false;
+}
+
+/**
+ * tomoyo_correct_word - Validate a string.
+ *
+ * @string: The string to check.
+ *
+ * Check whether the given string follows the naming rules.
+ * Returns true if @string follows the naming rules, false otherwise.
+ */
+bool tomoyo_correct_word(const char *string)
+{
+ return tomoyo_correct_word2(string, strlen(string));
+}
+
+/**
+ * tomoyo_correct_path - Validate a pathname.
+ *
+ * @filename: The pathname to check.
+ *
+ * Check whether the given pathname follows the naming rules.
+ * Returns true if @filename follows the naming rules, false otherwise.
+ */
+bool tomoyo_correct_path(const char *filename)
+{
+ return *filename == '/' && tomoyo_correct_word(filename);
+}
+
+/**
+ * tomoyo_correct_domain - Check whether the given domainname follows the naming rules.
+ *
+ * @domainname: The domainname to check.
+ *
+ * Returns true if @domainname follows the naming rules, false otherwise.
+ */
+bool tomoyo_correct_domain(const unsigned char *domainname)
+{
+ if (!domainname || strncmp(domainname, TOMOYO_ROOT_NAME,
+ TOMOYO_ROOT_NAME_LEN))
+ goto out;
+ domainname += TOMOYO_ROOT_NAME_LEN;
+ if (!*domainname)
+ return true;
+ if (*domainname++ != ' ')
+ goto out;
+ while (1) {
+ const unsigned char *cp = strchr(domainname, ' ');
+ if (!cp)
+ break;
+ if (*domainname != '/' ||
+ !tomoyo_correct_word2(domainname, cp - domainname - 1))
+ goto out;
+ domainname = cp + 1;
+ }
+ return tomoyo_correct_path(domainname);
+ out:
+ return false;
+}
+
+/**
+ * tomoyo_domain_def - Check whether the given token can be a domainname.
+ *
+ * @buffer: The token to check.
+ *
+ * Returns true if @buffer possibly be a domainname, false otherwise.
+ */
+bool tomoyo_domain_def(const unsigned char *buffer)
+{
+ return !strncmp(buffer, TOMOYO_ROOT_NAME, TOMOYO_ROOT_NAME_LEN);
+}
+
+/**
+ * tomoyo_find_domain - Find a domain by the given name.
+ *
+ * @domainname: The domainname to find.
+ *
+ * Returns pointer to "struct tomoyo_domain_info" if found, NULL otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
+ */
+struct tomoyo_domain_info *tomoyo_find_domain(const char *domainname)
+{
+ struct tomoyo_domain_info *domain;
+ struct tomoyo_path_info name;
+
+ name.name = domainname;
+ tomoyo_fill_path_info(&name);
+ list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) {
+ if (!domain->is_deleted &&
+ !tomoyo_pathcmp(&name, domain->domainname))
+ return domain;
+ }
+ return NULL;
+}
+
+/**
+ * tomoyo_const_part_length - Evaluate the initial length without a pattern in a token.
+ *
+ * @filename: The string to evaluate.
+ *
+ * Returns the initial length without a pattern in @filename.
+ */
+static int tomoyo_const_part_length(const char *filename)
+{
+ char c;
+ int len = 0;
+
+ if (!filename)
+ return 0;
+ while ((c = *filename++) != '\0') {
+ if (c != '\\') {
+ len++;
+ continue;
+ }
+ c = *filename++;
+ switch (c) {
+ case '\\': /* "\\" */
+ len += 2;
+ continue;
+ case '0': /* "\ooo" */
+ case '1':
+ case '2':
+ case '3':
+ c = *filename++;
+ if (c < '0' || c > '7')
+ break;
+ c = *filename++;
+ if (c < '0' || c > '7')
+ break;
+ len += 4;
+ continue;
+ }
+ break;
+ }
+ return len;
+}
+
+/**
+ * tomoyo_fill_path_info - Fill in "struct tomoyo_path_info" members.
+ *
+ * @ptr: Pointer to "struct tomoyo_path_info" to fill in.
+ *
+ * The caller sets "struct tomoyo_path_info"->name.
+ */
+void tomoyo_fill_path_info(struct tomoyo_path_info *ptr)
+{
+ const char *name = ptr->name;
+ const int len = strlen(name);
+
+ ptr->const_len = tomoyo_const_part_length(name);
+ ptr->is_dir = len && (name[len - 1] == '/');
+ ptr->is_patterned = (ptr->const_len < len);
+ ptr->hash = full_name_hash(name, len);
+}
+
+/**
+ * tomoyo_file_matches_pattern2 - Pattern matching without '/' character and "\-" pattern.
+ *
+ * @filename: The start of string to check.
+ * @filename_end: The end of string to check.
+ * @pattern: The start of pattern to compare.
+ * @pattern_end: The end of pattern to compare.
+ *
+ * Returns true if @filename matches @pattern, false otherwise.
+ */
+static bool tomoyo_file_matches_pattern2(const char *filename,
+ const char *filename_end,
+ const char *pattern,
+ const char *pattern_end)
+{
+ while (filename < filename_end && pattern < pattern_end) {
+ char c;
+ if (*pattern != '\\') {
+ if (*filename++ != *pattern++)
+ return false;
+ continue;
+ }
+ c = *filename;
+ pattern++;
+ switch (*pattern) {
+ int i;
+ int j;
+ case '?':
+ if (c == '/') {
+ return false;
+ } else if (c == '\\') {
+ if (filename[1] == '\\')
+ filename++;
+ else if (tomoyo_byte_range(filename + 1))
+ filename += 3;
+ else
+ return false;
+ }
+ break;
+ case '\\':
+ if (c != '\\')
+ return false;
+ if (*++filename != '\\')
+ return false;
+ break;
+ case '+':
+ if (!isdigit(c))
+ return false;
+ break;
+ case 'x':
+ if (!isxdigit(c))
+ return false;
+ break;
+ case 'a':
+ if (!tomoyo_alphabet_char(c))
+ return false;
+ break;
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ if (c == '\\' && tomoyo_byte_range(filename + 1)
+ && strncmp(filename + 1, pattern, 3) == 0) {
+ filename += 3;
+ pattern += 2;
+ break;
+ }
+ return false; /* Not matched. */
+ case '*':
+ case '@':
+ for (i = 0; i <= filename_end - filename; i++) {
+ if (tomoyo_file_matches_pattern2(
+ filename + i, filename_end,
+ pattern + 1, pattern_end))
+ return true;
+ c = filename[i];
+ if (c == '.' && *pattern == '@')
+ break;
+ if (c != '\\')
+ continue;
+ if (filename[i + 1] == '\\')
+ i++;
+ else if (tomoyo_byte_range(filename + i + 1))
+ i += 3;
+ else
+ break; /* Bad pattern. */
+ }
+ return false; /* Not matched. */
+ default:
+ j = 0;
+ c = *pattern;
+ if (c == '$') {
+ while (isdigit(filename[j]))
+ j++;
+ } else if (c == 'X') {
+ while (isxdigit(filename[j]))
+ j++;
+ } else if (c == 'A') {
+ while (tomoyo_alphabet_char(filename[j]))
+ j++;
+ }
+ for (i = 1; i <= j; i++) {
+ if (tomoyo_file_matches_pattern2(
+ filename + i, filename_end,
+ pattern + 1, pattern_end))
+ return true;
+ }
+ return false; /* Not matched or bad pattern. */
+ }
+ filename++;
+ pattern++;
+ }
+ while (*pattern == '\\' &&
+ (*(pattern + 1) == '*' || *(pattern + 1) == '@'))
+ pattern += 2;
+ return filename == filename_end && pattern == pattern_end;
+}
+
+/**
+ * tomoyo_file_matches_pattern - Pattern matching without '/' character.
+ *
+ * @filename: The start of string to check.
+ * @filename_end: The end of string to check.
+ * @pattern: The start of pattern to compare.
+ * @pattern_end: The end of pattern to compare.
+ *
+ * Returns true if @filename matches @pattern, false otherwise.
+ */
+static bool tomoyo_file_matches_pattern(const char *filename,
+ const char *filename_end,
+ const char *pattern,
+ const char *pattern_end)
+{
+ const char *pattern_start = pattern;
+ bool first = true;
+ bool result;
+
+ while (pattern < pattern_end - 1) {
+ /* Split at "\-" pattern. */
+ if (*pattern++ != '\\' || *pattern++ != '-')
+ continue;
+ result = tomoyo_file_matches_pattern2(filename,
+ filename_end,
+ pattern_start,
+ pattern - 2);
+ if (first)
+ result = !result;
+ if (result)
+ return false;
+ first = false;
+ pattern_start = pattern;
+ }
+ result = tomoyo_file_matches_pattern2(filename, filename_end,
+ pattern_start, pattern_end);
+ return first ? result : !result;
+}
+
+/**
+ * tomoyo_path_matches_pattern2 - Do pathname pattern matching.
+ *
+ * @f: The start of string to check.
+ * @p: The start of pattern to compare.
+ *
+ * Returns true if @f matches @p, false otherwise.
+ */
+static bool tomoyo_path_matches_pattern2(const char *f, const char *p)
+{
+ const char *f_delimiter;
+ const char *p_delimiter;
+
+ while (*f && *p) {
+ f_delimiter = strchr(f, '/');
+ if (!f_delimiter)
+ f_delimiter = f + strlen(f);
+ p_delimiter = strchr(p, '/');
+ if (!p_delimiter)
+ p_delimiter = p + strlen(p);
+ if (*p == '\\' && *(p + 1) == '{')
+ goto recursive;
+ if (!tomoyo_file_matches_pattern(f, f_delimiter, p,
+ p_delimiter))
+ return false;
+ f = f_delimiter;
+ if (*f)
+ f++;
+ p = p_delimiter;
+ if (*p)
+ p++;
+ }
+ /* Ignore trailing "\*" and "\@" in @pattern. */
+ while (*p == '\\' &&
+ (*(p + 1) == '*' || *(p + 1) == '@'))
+ p += 2;
+ return !*f && !*p;
+ recursive:
+ /*
+ * The "\{" pattern is permitted only after '/' character.
+ * This guarantees that below "*(p - 1)" is safe.
+ * Also, the "\}" pattern is permitted only before '/' character
+ * so that "\{" + "\}" pair will not break the "\-" operator.
+ */
+ if (*(p - 1) != '/' || p_delimiter <= p + 3 || *p_delimiter != '/' ||
+ *(p_delimiter - 1) != '}' || *(p_delimiter - 2) != '\\')
+ return false; /* Bad pattern. */
+ do {
+ /* Compare current component with pattern. */
+ if (!tomoyo_file_matches_pattern(f, f_delimiter, p + 2,
+ p_delimiter - 2))
+ break;
+ /* Proceed to next component. */
+ f = f_delimiter;
+ if (!*f)
+ break;
+ f++;
+ /* Continue comparison. */
+ if (tomoyo_path_matches_pattern2(f, p_delimiter + 1))
+ return true;
+ f_delimiter = strchr(f, '/');
+ } while (f_delimiter);
+ return false; /* Not matched. */
+}
+
+/**
+ * tomoyo_path_matches_pattern - Check whether the given filename matches the given pattern.
+ *
+ * @filename: The filename to check.
+ * @pattern: The pattern to compare.
+ *
+ * Returns true if matches, false otherwise.
+ *
+ * The following patterns are available.
+ * \\ \ itself.
+ * \ooo Octal representation of a byte.
+ * \* Zero or more repetitions of characters other than '/'.
+ * \@ Zero or more repetitions of characters other than '/' or '.'.
+ * \? 1 byte character other than '/'.
+ * \$ One or more repetitions of decimal digits.
+ * \+ 1 decimal digit.
+ * \X One or more repetitions of hexadecimal digits.
+ * \x 1 hexadecimal digit.
+ * \A One or more repetitions of alphabet characters.
+ * \a 1 alphabet character.
+ *
+ * \- Subtraction operator.
+ *
+ * /\{dir\}/ '/' + 'One or more repetitions of dir/' (e.g. /dir/ /dir/dir/
+ * /dir/dir/dir/ ).
+ */
+bool tomoyo_path_matches_pattern(const struct tomoyo_path_info *filename,
+ const struct tomoyo_path_info *pattern)
+{
+ const char *f = filename->name;
+ const char *p = pattern->name;
+ const int len = pattern->const_len;
+
+ /* If @pattern doesn't contain pattern, I can use strcmp(). */
+ if (!pattern->is_patterned)
+ return !tomoyo_pathcmp(filename, pattern);
+ /* Don't compare directory and non-directory. */
+ if (filename->is_dir != pattern->is_dir)
+ return false;
+ /* Compare the initial length without patterns. */
+ if (strncmp(f, p, len))
+ return false;
+ f += len;
+ p += len;
+ return tomoyo_path_matches_pattern2(f, p);
+}
+
+/**
+ * tomoyo_get_exe - Get tomoyo_realpath() of current process.
+ *
+ * Returns the tomoyo_realpath() of current process on success, NULL otherwise.
+ *
+ * This function uses kzalloc(), so the caller must call kfree()
+ * if this function didn't return NULL.
+ */
+const char *tomoyo_get_exe(void)
+{
+ struct mm_struct *mm = current->mm;
+ struct vm_area_struct *vma;
+ const char *cp = NULL;
+
+ if (!mm)
+ return NULL;
+ down_read(&mm->mmap_sem);
+ for (vma = mm->mmap; vma; vma = vma->vm_next) {
+ if ((vma->vm_flags & VM_EXECUTABLE) && vma->vm_file) {
+ cp = tomoyo_realpath_from_path(&vma->vm_file->f_path);
+ break;
+ }
+ }
+ up_read(&mm->mmap_sem);
+ return cp;
+}
+
+/**
+ * tomoyo_get_mode - Get MAC mode.
+ *
+ * @profile: Profile number.
+ * @index: Index number of functionality.
+ *
+ * Returns mode.
+ */
+int tomoyo_get_mode(const u8 profile, const u8 index)
+{
+ u8 mode;
+ const u8 category = TOMOYO_MAC_CATEGORY_FILE;
+ if (!tomoyo_policy_loaded)
+ return TOMOYO_CONFIG_DISABLED;
+ mode = tomoyo_profile(profile)->config[index];
+ if (mode == TOMOYO_CONFIG_USE_DEFAULT)
+ mode = tomoyo_profile(profile)->config[category];
+ if (mode == TOMOYO_CONFIG_USE_DEFAULT)
+ mode = tomoyo_profile(profile)->default_config;
+ return mode & 3;
+}
+
+/**
+ * tomoyo_init_request_info - Initialize "struct tomoyo_request_info" members.
+ *
+ * @r: Pointer to "struct tomoyo_request_info" to initialize.
+ * @domain: Pointer to "struct tomoyo_domain_info". NULL for tomoyo_domain().
+ * @index: Index number of functionality.
+ *
+ * Returns mode.
+ */
+int tomoyo_init_request_info(struct tomoyo_request_info *r,
+ struct tomoyo_domain_info *domain, const u8 index)
+{
+ u8 profile;
+ memset(r, 0, sizeof(*r));
+ if (!domain)
+ domain = tomoyo_domain();
+ r->domain = domain;
+ profile = domain->profile;
+ r->profile = profile;
+ r->type = index;
+ r->mode = tomoyo_get_mode(profile, index);
+ return r->mode;
+}
+
+/**
+ * tomoyo_last_word - Get last component of a line.
+ *
+ * @line: A line.
+ *
+ * Returns the last word of a line.
+ */
+const char *tomoyo_last_word(const char *name)
+{
+ const char *cp = strrchr(name, ' ');
+ if (cp)
+ return cp + 1;
+ return name;
+}
+
+/**
+ * tomoyo_warn_log - Print warning or error message on console.
+ *
+ * @r: Pointer to "struct tomoyo_request_info".
+ * @fmt: The printf()'s format string, followed by parameters.
+ */
+void tomoyo_warn_log(struct tomoyo_request_info *r, const char *fmt, ...)
+{
+ va_list args;
+ char *buffer;
+ const struct tomoyo_domain_info * const domain = r->domain;
+ const struct tomoyo_profile *profile = tomoyo_profile(domain->profile);
+ switch (r->mode) {
+ case TOMOYO_CONFIG_ENFORCING:
+ if (!profile->enforcing->enforcing_verbose)
+ return;
+ break;
+ case TOMOYO_CONFIG_PERMISSIVE:
+ if (!profile->permissive->permissive_verbose)
+ return;
+ break;
+ case TOMOYO_CONFIG_LEARNING:
+ if (!profile->learning->learning_verbose)
+ return;
+ break;
+ }
+ buffer = kmalloc(4096, GFP_NOFS);
+ if (!buffer)
+ return;
+ va_start(args, fmt);
+ vsnprintf(buffer, 4095, fmt, args);
+ va_end(args);
+ buffer[4095] = '\0';
+ printk(KERN_WARNING "%s: Access %s denied for %s\n",
+ r->mode == TOMOYO_CONFIG_ENFORCING ? "ERROR" : "WARNING", buffer,
+ tomoyo_last_word(domain->domainname->name));
+ kfree(buffer);
+}
+
+/**
+ * tomoyo_domain_quota_is_ok - Check for domain's quota.
+ *
+ * @r: Pointer to "struct tomoyo_request_info".
+ *
+ * Returns true if the domain is not exceeded quota, false otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
+ */
+bool tomoyo_domain_quota_is_ok(struct tomoyo_request_info *r)
+{
+ unsigned int count = 0;
+ struct tomoyo_domain_info *domain = r->domain;
+ struct tomoyo_acl_info *ptr;
+
+ if (r->mode != TOMOYO_CONFIG_LEARNING)
+ return false;
+ if (!domain)
+ return true;
+ list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) {
+ if (ptr->is_deleted)
+ continue;
+ switch (ptr->type) {
+ u16 perm;
+ u8 i;
+ case TOMOYO_TYPE_PATH_ACL:
+ perm = container_of(ptr, struct tomoyo_path_acl, head)
+ ->perm;
+ for (i = 0; i < TOMOYO_MAX_PATH_OPERATION; i++)
+ if (perm & (1 << i))
+ count++;
+ if (perm & (1 << TOMOYO_TYPE_READ_WRITE))
+ count -= 2;
+ break;
+ case TOMOYO_TYPE_PATH2_ACL:
+ perm = container_of(ptr, struct tomoyo_path2_acl, head)
+ ->perm;
+ for (i = 0; i < TOMOYO_MAX_PATH2_OPERATION; i++)
+ if (perm & (1 << i))
+ count++;
+ break;
+ case TOMOYO_TYPE_PATH_NUMBER_ACL:
+ perm = container_of(ptr, struct tomoyo_path_number_acl,
+ head)->perm;
+ for (i = 0; i < TOMOYO_MAX_PATH_NUMBER_OPERATION; i++)
+ if (perm & (1 << i))
+ count++;
+ break;
+ case TOMOYO_TYPE_MKDEV_ACL:
+ perm = container_of(ptr, struct tomoyo_mkdev_acl,
+ head)->perm;
+ for (i = 0; i < TOMOYO_MAX_MKDEV_OPERATION; i++)
+ if (perm & (1 << i))
+ count++;
+ break;
+ default:
+ count++;
+ }
+ }
+ if (count < tomoyo_profile(domain->profile)->learning->
+ learning_max_entry)
+ return true;
+ if (!domain->quota_warned) {
+ domain->quota_warned = true;
+ printk(KERN_WARNING "TOMOYO-WARNING: "
+ "Domain '%s' has so many ACLs to hold. "
+ "Stopped learning mode.\n", domain->domainname->name);
+ }
+ return false;
+}
diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c
index e9d98be190c..e23e0e7ab26 100644
--- a/sound/core/pcm_lib.c
+++ b/sound/core/pcm_lib.c
@@ -67,6 +67,8 @@ void snd_pcm_playback_silence(struct snd_pcm_substream *substream, snd_pcm_ufram
} else {
if (new_hw_ptr == ULONG_MAX) { /* initialization */
snd_pcm_sframes_t avail = snd_pcm_playback_hw_avail(runtime);
+ if (avail > runtime->buffer_size)
+ avail = runtime->buffer_size;
runtime->silence_filled = avail > 0 ? avail : 0;
runtime->silence_start = (runtime->status->hw_ptr +
runtime->silence_filled) %
@@ -287,8 +289,11 @@ int snd_pcm_update_state(struct snd_pcm_substream *substream,
return -EPIPE;
}
}
- if (avail >= runtime->control->avail_min)
- wake_up(runtime->twake ? &runtime->tsleep : &runtime->sleep);
+ if (runtime->twake) {
+ if (avail >= runtime->twake)
+ wake_up(&runtime->tsleep);
+ } else if (avail >= runtime->control->avail_min)
+ wake_up(&runtime->sleep);
return 0;
}
@@ -1707,7 +1712,7 @@ EXPORT_SYMBOL(snd_pcm_period_elapsed);
* The available space is stored on availp. When err = 0 and avail = 0
* on the capture stream, it indicates the stream is in DRAINING state.
*/
-static int wait_for_avail_min(struct snd_pcm_substream *substream,
+static int wait_for_avail(struct snd_pcm_substream *substream,
snd_pcm_uframes_t *availp)
{
struct snd_pcm_runtime *runtime = substream->runtime;
@@ -1757,7 +1762,7 @@ static int wait_for_avail_min(struct snd_pcm_substream *substream,
avail = snd_pcm_playback_avail(runtime);
else
avail = snd_pcm_capture_avail(runtime);
- if (avail >= runtime->control->avail_min)
+ if (avail >= runtime->twake)
break;
}
_endloop:
@@ -1820,7 +1825,7 @@ static snd_pcm_sframes_t snd_pcm_lib_write1(struct snd_pcm_substream *substream,
goto _end_unlock;
}
- runtime->twake = 1;
+ runtime->twake = runtime->control->avail_min ? : 1;
while (size > 0) {
snd_pcm_uframes_t frames, appl_ptr, appl_ofs;
snd_pcm_uframes_t avail;
@@ -1833,7 +1838,9 @@ static snd_pcm_sframes_t snd_pcm_lib_write1(struct snd_pcm_substream *substream,
err = -EAGAIN;
goto _end_unlock;
}
- err = wait_for_avail_min(substream, &avail);
+ runtime->twake = min_t(snd_pcm_uframes_t, size,
+ runtime->control->avail_min ? : 1);
+ err = wait_for_avail(substream, &avail);
if (err < 0)
goto _end_unlock;
}
@@ -2042,7 +2049,7 @@ static snd_pcm_sframes_t snd_pcm_lib_read1(struct snd_pcm_substream *substream,
goto _end_unlock;
}
- runtime->twake = 1;
+ runtime->twake = runtime->control->avail_min ? : 1;
while (size > 0) {
snd_pcm_uframes_t frames, appl_ptr, appl_ofs;
snd_pcm_uframes_t avail;
@@ -2060,7 +2067,9 @@ static snd_pcm_sframes_t snd_pcm_lib_read1(struct snd_pcm_substream *substream,
err = -EAGAIN;
goto _end_unlock;
}
- err = wait_for_avail_min(substream, &avail);
+ runtime->twake = min_t(snd_pcm_uframes_t, size,
+ runtime->control->avail_min ? : 1);
+ err = wait_for_avail(substream, &avail);
if (err < 0)
goto _end_unlock;
if (!avail)
diff --git a/sound/core/pcm_misc.c b/sound/core/pcm_misc.c
index ea2bf82c937..434af3c56d5 100644
--- a/sound/core/pcm_misc.c
+++ b/sound/core/pcm_misc.c
@@ -128,6 +128,14 @@ static struct pcm_format_data pcm_formats[SNDRV_PCM_FORMAT_LAST+1] = {
.width = 4, .phys = 4, .le = -1, .signd = -1,
.silence = {},
},
+ [SNDRV_PCM_FORMAT_G723_24] = {
+ .width = 3, .phys = 3, .le = -1, .signd = -1,
+ .silence = {},
+ },
+ [SNDRV_PCM_FORMAT_G723_40] = {
+ .width = 5, .phys = 5, .le = -1, .signd = -1,
+ .silence = {},
+ },
/* FIXME: the following three formats are not defined properly yet */
[SNDRV_PCM_FORMAT_MPEG] = {
.le = -1, .signd = -1,
@@ -186,6 +194,14 @@ static struct pcm_format_data pcm_formats[SNDRV_PCM_FORMAT_LAST+1] = {
.width = 18, .phys = 24, .le = 0, .signd = 0,
.silence = { 0x02, 0x00, 0x00 },
},
+ [SNDRV_PCM_FORMAT_G723_24_1B] = {
+ .width = 3, .phys = 8, .le = -1, .signd = -1,
+ .silence = {},
+ },
+ [SNDRV_PCM_FORMAT_G723_40_1B] = {
+ .width = 5, .phys = 8, .le = -1, .signd = -1,
+ .silence = {},
+ },
};
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c
index 303ac04ff6e..a3b2a647924 100644
--- a/sound/core/pcm_native.c
+++ b/sound/core/pcm_native.c
@@ -451,13 +451,11 @@ static int snd_pcm_hw_params(struct snd_pcm_substream *substream,
snd_pcm_timer_resolution_change(substream);
runtime->status->state = SNDRV_PCM_STATE_SETUP;
- if (substream->latency_pm_qos_req) {
- pm_qos_remove_request(substream->latency_pm_qos_req);
- substream->latency_pm_qos_req = NULL;
- }
+ if (pm_qos_request_active(&substream->latency_pm_qos_req))
+ pm_qos_remove_request(&substream->latency_pm_qos_req);
if ((usecs = period_to_usecs(runtime)) >= 0)
- substream->latency_pm_qos_req = pm_qos_add_request(
- PM_QOS_CPU_DMA_LATENCY, usecs);
+ pm_qos_add_request(&substream->latency_pm_qos_req,
+ PM_QOS_CPU_DMA_LATENCY, usecs);
return 0;
_error:
/* hardware might be unuseable from this time,
@@ -512,8 +510,7 @@ static int snd_pcm_hw_free(struct snd_pcm_substream *substream)
if (substream->ops->hw_free)
result = substream->ops->hw_free(substream);
runtime->status->state = SNDRV_PCM_STATE_OPEN;
- pm_qos_remove_request(substream->latency_pm_qos_req);
- substream->latency_pm_qos_req = NULL;
+ pm_qos_remove_request(&substream->latency_pm_qos_req);
return result;
}
diff --git a/sound/drivers/Kconfig b/sound/drivers/Kconfig
index 84714a65e5c..480c38623da 100644
--- a/sound/drivers/Kconfig
+++ b/sound/drivers/Kconfig
@@ -155,7 +155,7 @@ config SND_ML403_AC97CR
select SND_AC97_CODEC
help
Say Y here to include support for the
- opb_ac97_controller_ref_v1_00_a ip core found in Xilinx' ML403
+ opb_ac97_controller_ref_v1_00_a ip core found in Xilinx's ML403
reference design.
To compile this driver as a module, choose M here: the module
@@ -170,9 +170,25 @@ config SND_AC97_POWER_SAVE
AC97 codecs. In this mode, the power-mode is dynamically
controlled at each open/close.
- The mode is activated by passing power_save=1 option to
- snd-ac97-codec driver. You can toggle it dynamically over
- sysfs, too.
+ The mode is activated by passing 'power_save=X' to the
+ snd-ac97-codec driver module, where 'X' is the time-out
+ value, a nonnegative integer that specifies how many
+ seconds of idle time the driver must count before it may
+ put the AC97 into power-save mode; a value of 0 (zero)
+ disables the use of this power-save mode.
+
+ After the snd-ac97-codec driver module has been loaded,
+ the 'power_save' parameter can be set via sysfs as follows:
+
+ echo 10 > /sys/module/snd_ac97_codec/parameters/power_save
+
+ In this case, the time-out is set to 10 seconds; setting
+ the time-out to 1 second (the minimum activation value)
+ isn't recommended because many applications try to reopen
+ the device frequently. A value of 10 seconds would be a
+ good choice for normal operations.
+
+ See Documentation/sound/alsa/powersave.txt for more details.
config SND_AC97_POWER_SAVE_DEFAULT
int "Default time-out for AC97 power-save mode"
@@ -182,4 +198,6 @@ config SND_AC97_POWER_SAVE_DEFAULT
The default time-out value in seconds for AC97 automatic
power-save mode. 0 means to disable the power-save mode.
+ See SND_AC97_POWER_SAVE for more details.
+
endif # SND_DRIVERS
diff --git a/sound/isa/msnd/msnd_pinnacle.c b/sound/isa/msnd/msnd_pinnacle.c
index 60b6abd7161..5f3e68401f9 100644
--- a/sound/isa/msnd/msnd_pinnacle.c
+++ b/sound/isa/msnd/msnd_pinnacle.c
@@ -549,7 +549,10 @@ static int __devinit snd_msnd_attach(struct snd_card *card)
printk(KERN_ERR LOGNAME ": Couldn't grab IRQ %d\n", chip->irq);
return err;
}
- request_region(chip->io, DSP_NUMIO, card->shortname);
+ if (request_region(chip->io, DSP_NUMIO, card->shortname) == NULL) {
+ free_irq(chip->irq, chip);
+ return -EBUSY;
+ }
if (!request_mem_region(chip->base, BUFFSIZE, card->shortname)) {
printk(KERN_ERR LOGNAME
diff --git a/sound/isa/sb/emu8000_pcm.c b/sound/isa/sb/emu8000_pcm.c
index ccedbfed061..2f85c66f8e3 100644
--- a/sound/isa/sb/emu8000_pcm.c
+++ b/sound/isa/sb/emu8000_pcm.c
@@ -433,7 +433,8 @@ static int emu8k_transfer_block(struct snd_emu8000 *emu, int offset, unsigned sh
while (count > 0) {
unsigned short sval;
CHECK_SCHEDULER();
- get_user(sval, buf);
+ if (get_user(sval, buf))
+ return -EFAULT;
EMU8000_SMLD_WRITE(emu, sval);
buf++;
count--;
@@ -525,12 +526,14 @@ static int emu8k_pcm_copy(struct snd_pcm_substream *subs,
while (count-- > 0) {
unsigned short sval;
CHECK_SCHEDULER();
- get_user(sval, buf);
+ if (get_user(sval, buf))
+ return -EFAULT;
EMU8000_SMLD_WRITE(emu, sval);
buf++;
if (rec->voices > 1) {
CHECK_SCHEDULER();
- get_user(sval, buf);
+ if (get_user(sval, buf))
+ return -EFAULT;
EMU8000_SMRD_WRITE(emu, sval);
buf++;
}
diff --git a/sound/oss/au1550_ac97.c b/sound/oss/au1550_ac97.c
index c1070e33b32..c4a4cdc07ab 100644
--- a/sound/oss/au1550_ac97.c
+++ b/sound/oss/au1550_ac97.c
@@ -43,6 +43,7 @@
#include <linux/sound.h>
#include <linux/slab.h>
#include <linux/soundcard.h>
+#include <linux/smp_lock.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
@@ -162,19 +163,10 @@ ld2(unsigned int x)
static void
au1550_delay(int msec)
{
- unsigned long tmo;
- signed long tmo2;
-
if (in_interrupt())
return;
- tmo = jiffies + (msec * HZ) / 1000;
- for (;;) {
- tmo2 = tmo - jiffies;
- if (tmo2 <= 0)
- break;
- schedule_timeout(tmo2);
- }
+ schedule_timeout_uninterruptible(msecs_to_jiffies(msec));
}
static u16
@@ -807,7 +799,9 @@ au1550_llseek(struct file *file, loff_t offset, int origin)
static int
au1550_open_mixdev(struct inode *inode, struct file *file)
{
+ lock_kernel();
file->private_data = &au1550_state;
+ unlock_kernel();
return 0;
}
@@ -824,22 +818,26 @@ mixdev_ioctl(struct ac97_codec *codec, unsigned int cmd,
return codec->mixer_ioctl(codec, cmd, arg);
}
-static int
-au1550_ioctl_mixdev(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg)
+static long
+au1550_ioctl_mixdev(struct file *file, unsigned int cmd, unsigned long arg)
{
struct au1550_state *s = (struct au1550_state *)file->private_data;
struct ac97_codec *codec = s->codec;
+ int ret;
- return mixdev_ioctl(codec, cmd, arg);
+ lock_kernel();
+ ret = mixdev_ioctl(codec, cmd, arg);
+ unlock_kernel();
+
+ return ret;
}
static /*const */ struct file_operations au1550_mixer_fops = {
- owner:THIS_MODULE,
- llseek:au1550_llseek,
- ioctl:au1550_ioctl_mixdev,
- open:au1550_open_mixdev,
- release:au1550_release_mixdev,
+ .owner = THIS_MODULE,
+ .llseek = au1550_llseek,
+ .unlocked_ioctl = au1550_ioctl_mixdev,
+ .open = au1550_open_mixdev,
+ .release = au1550_release_mixdev,
};
static int
@@ -1343,8 +1341,7 @@ dma_count_done(struct dmabuf *db)
static int
-au1550_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
- unsigned long arg)
+au1550_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
struct au1550_state *s = (struct au1550_state *)file->private_data;
unsigned long flags;
@@ -1780,6 +1777,17 @@ au1550_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
return mixdev_ioctl(s->codec, cmd, arg);
}
+static long
+au1550_unlocked_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+ int ret;
+
+ lock_kernel();
+ ret = au1550_ioctl(file, cmd, arg);
+ unlock_kernel();
+
+ return ret;
+}
static int
au1550_open(struct inode *inode, struct file *file)
@@ -1797,21 +1805,22 @@ au1550_open(struct inode *inode, struct file *file)
#endif
file->private_data = s;
+ lock_kernel();
/* wait for device to become free */
mutex_lock(&s->open_mutex);
while (s->open_mode & file->f_mode) {
- if (file->f_flags & O_NONBLOCK) {
- mutex_unlock(&s->open_mutex);
- return -EBUSY;
- }
+ ret = -EBUSY;
+ if (file->f_flags & O_NONBLOCK)
+ goto out;
add_wait_queue(&s->open_wait, &wait);
__set_current_state(TASK_INTERRUPTIBLE);
mutex_unlock(&s->open_mutex);
schedule();
remove_wait_queue(&s->open_wait, &wait);
set_current_state(TASK_RUNNING);
+ ret = -ERESTARTSYS;
if (signal_pending(current))
- return -ERESTARTSYS;
+ goto out2;
mutex_lock(&s->open_mutex);
}
@@ -1840,17 +1849,21 @@ au1550_open(struct inode *inode, struct file *file)
if (file->f_mode & FMODE_READ) {
if ((ret = prog_dmabuf_adc(s)))
- return ret;
+ goto out;
}
if (file->f_mode & FMODE_WRITE) {
if ((ret = prog_dmabuf_dac(s)))
- return ret;
+ goto out;
}
s->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE);
- mutex_unlock(&s->open_mutex);
mutex_init(&s->sem);
- return 0;
+ ret = 0;
+out:
+ mutex_unlock(&s->open_mutex);
+out2:
+ unlock_kernel();
+ return ret;
}
static int
@@ -1885,15 +1898,15 @@ au1550_release(struct inode *inode, struct file *file)
}
static /*const */ struct file_operations au1550_audio_fops = {
- owner: THIS_MODULE,
- llseek: au1550_llseek,
- read: au1550_read,
- write: au1550_write,
- poll: au1550_poll,
- ioctl: au1550_ioctl,
- mmap: au1550_mmap,
- open: au1550_open,
- release: au1550_release,
+ .owner = THIS_MODULE,
+ .llseek = au1550_llseek,
+ .read = au1550_read,
+ .write = au1550_write,
+ .poll = au1550_poll,
+ .unlocked_ioctl = au1550_unlocked_ioctl,
+ .mmap = au1550_mmap,
+ .open = au1550_open,
+ .release = au1550_release,
};
MODULE_AUTHOR("Advanced Micro Devices (AMD), dan@embeddededge.com");
diff --git a/sound/oss/dmasound/dmasound_core.c b/sound/oss/dmasound/dmasound_core.c
index 3f3c3f71db4..6ecd41abb06 100644
--- a/sound/oss/dmasound/dmasound_core.c
+++ b/sound/oss/dmasound/dmasound_core.c
@@ -323,9 +323,13 @@ static struct {
static int mixer_open(struct inode *inode, struct file *file)
{
- if (!try_module_get(dmasound.mach.owner))
+ lock_kernel();
+ if (!try_module_get(dmasound.mach.owner)) {
+ unlock_kernel();
return -ENODEV;
+ }
mixer.busy = 1;
+ unlock_kernel();
return 0;
}
@@ -337,8 +341,8 @@ static int mixer_release(struct inode *inode, struct file *file)
unlock_kernel();
return 0;
}
-static int mixer_ioctl(struct inode *inode, struct file *file, u_int cmd,
- u_long arg)
+
+static int mixer_ioctl(struct file *file, u_int cmd, u_long arg)
{
if (_SIOC_DIR(cmd) & _SIOC_WRITE)
mixer.modify_counter++;
@@ -362,11 +366,22 @@ static int mixer_ioctl(struct inode *inode, struct file *file, u_int cmd,
return -EINVAL;
}
+static long mixer_unlocked_ioctl(struct file *file, u_int cmd, u_long arg)
+{
+ int ret;
+
+ lock_kernel();
+ ret = mixer_ioctl(file, cmd, arg);
+ unlock_kernel();
+
+ return ret;
+}
+
static const struct file_operations mixer_fops =
{
.owner = THIS_MODULE,
.llseek = no_llseek,
- .ioctl = mixer_ioctl,
+ .unlocked_ioctl = mixer_unlocked_ioctl,
.open = mixer_open,
.release = mixer_release,
};
@@ -737,8 +752,11 @@ static int sq_open(struct inode *inode, struct file *file)
{
int rc;
- if (!try_module_get(dmasound.mach.owner))
+ lock_kernel();
+ if (!try_module_get(dmasound.mach.owner)) {
+ unlock_kernel();
return -ENODEV;
+ }
rc = write_sq_open(file); /* checks the f_mode */
if (rc)
@@ -781,10 +799,11 @@ static int sq_open(struct inode *inode, struct file *file)
sound_set_format(AFMT_MU_LAW);
}
#endif
-
+ unlock_kernel();
return 0;
out:
module_put(dmasound.mach.owner);
+ unlock_kernel();
return rc;
}
@@ -955,8 +974,7 @@ printk("dmasound_core: tried to set_queue_frags on a locked queue\n") ;
return 0 ;
}
-static int sq_ioctl(struct inode *inode, struct file *file, u_int cmd,
- u_long arg)
+static int sq_ioctl(struct file *file, u_int cmd, u_long arg)
{
int val, result;
u_long fmt;
@@ -1114,18 +1132,29 @@ static int sq_ioctl(struct inode *inode, struct file *file, u_int cmd,
return IOCTL_OUT(arg,val);
default:
- return mixer_ioctl(inode, file, cmd, arg);
+ return mixer_ioctl(file, cmd, arg);
}
return -EINVAL;
}
+static long sq_unlocked_ioctl(struct file *file, u_int cmd, u_long arg)
+{
+ int ret;
+
+ lock_kernel();
+ ret = sq_ioctl(file, cmd, arg);
+ unlock_kernel();
+
+ return ret;
+}
+
static const struct file_operations sq_fops =
{
.owner = THIS_MODULE,
.llseek = no_llseek,
.write = sq_write,
.poll = sq_poll,
- .ioctl = sq_ioctl,
+ .unlocked_ioctl = sq_unlocked_ioctl,
.open = sq_open,
.release = sq_release,
};
@@ -1226,12 +1255,17 @@ static int state_open(struct inode *inode, struct file *file)
{
char *buffer = state.buf;
int len = 0;
+ int ret;
+ lock_kernel();
+ ret = -EBUSY;
if (state.busy)
- return -EBUSY;
+ goto out;
+ ret = -ENODEV;
if (!try_module_get(dmasound.mach.owner))
- return -ENODEV;
+ goto out;
+
state.ptr = 0;
state.busy = 1;
@@ -1293,7 +1327,10 @@ printk("dmasound: stat buffer used %d bytes\n", len) ;
printk(KERN_ERR "dmasound_core: stat buffer overflowed!\n");
state.len = len;
- return 0;
+ ret = 0;
+out:
+ unlock_kernel();
+ return ret;
}
static int state_release(struct inode *inode, struct file *file)
diff --git a/sound/oss/midi_synth.c b/sound/oss/midi_synth.c
index 3bc7104c537..3c09374ea5b 100644
--- a/sound/oss/midi_synth.c
+++ b/sound/oss/midi_synth.c
@@ -523,7 +523,9 @@ midi_synth_load_patch(int dev, int format, const char __user *addr,
{
unsigned char data;
- get_user(*(unsigned char *) &data, (unsigned char __user *) &((addr)[hdr_size + i]));
+ if (get_user(data,
+ (unsigned char __user *)(addr + hdr_size + i)))
+ return -EFAULT;
eox_seen = (i > 0 && data & 0x80); /* End of sysex */
diff --git a/sound/oss/msnd_pinnacle.c b/sound/oss/msnd_pinnacle.c
index a1e3f9671be..2e48b17667d 100644
--- a/sound/oss/msnd_pinnacle.c
+++ b/sound/oss/msnd_pinnacle.c
@@ -639,21 +639,26 @@ static int mixer_ioctl(unsigned int cmd, unsigned long arg)
return -EINVAL;
}
-static int dev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+static long dev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
- int minor = iminor(inode);
+ int minor = iminor(file->f_path.dentry->d_inode);
+ int ret;
if (cmd == OSS_GETVERSION) {
int sound_version = SOUND_VERSION;
return put_user(sound_version, (int __user *)arg);
}
+ ret = -EINVAL;
+
+ lock_kernel();
if (minor == dev.dsp_minor)
- return dsp_ioctl(file, cmd, arg);
+ ret = dsp_ioctl(file, cmd, arg);
else if (minor == dev.mixer_minor)
- return mixer_ioctl(cmd, arg);
+ ret = mixer_ioctl(cmd, arg);
+ unlock_kernel();
- return -EINVAL;
+ return ret;
}
static void dsp_write_flush(void)
@@ -756,12 +761,15 @@ static int dev_open(struct inode *inode, struct file *file)
int minor = iminor(inode);
int err = 0;
+ lock_kernel();
if (minor == dev.dsp_minor) {
if ((file->f_mode & FMODE_WRITE &&
test_bit(F_AUDIO_WRITE_INUSE, &dev.flags)) ||
(file->f_mode & FMODE_READ &&
- test_bit(F_AUDIO_READ_INUSE, &dev.flags)))
- return -EBUSY;
+ test_bit(F_AUDIO_READ_INUSE, &dev.flags))) {
+ err = -EBUSY;
+ goto out;
+ }
if ((err = dsp_open(file)) >= 0) {
dev.nresets = 0;
@@ -782,7 +790,8 @@ static int dev_open(struct inode *inode, struct file *file)
/* nothing */
} else
err = -EINVAL;
-
+out:
+ unlock_kernel();
return err;
}
@@ -1105,7 +1114,7 @@ static const struct file_operations dev_fileops = {
.owner = THIS_MODULE,
.read = dev_read,
.write = dev_write,
- .ioctl = dev_ioctl,
+ .unlocked_ioctl = dev_ioctl,
.open = dev_open,
.release = dev_release,
};
@@ -1391,9 +1400,13 @@ static int __init attach_multisound(void)
printk(KERN_ERR LOGNAME ": Couldn't grab IRQ %d\n", dev.irq);
return err;
}
- request_region(dev.io, dev.numio, dev.name);
+ if (request_region(dev.io, dev.numio, dev.name) == NULL) {
+ free_irq(dev.irq, &dev);
+ return -EBUSY;
+ }
- if ((err = dsp_full_reset()) < 0) {
+ err = dsp_full_reset();
+ if (err < 0) {
release_region(dev.io, dev.numio);
free_irq(dev.irq, &dev);
return err;
diff --git a/sound/oss/sh_dac_audio.c b/sound/oss/sh_dac_audio.c
index 4153752507e..fdb58eb83d4 100644
--- a/sound/oss/sh_dac_audio.c
+++ b/sound/oss/sh_dac_audio.c
@@ -15,7 +15,9 @@
#include <linux/linkage.h>
#include <linux/slab.h>
#include <linux/fs.h>
+#include <linux/smp_lock.h>
#include <linux/sound.h>
+#include <linux/smp_lock.h>
#include <linux/soundcard.h>
#include <linux/interrupt.h>
#include <linux/hrtimer.h>
@@ -92,7 +94,7 @@ static void dac_audio_set_rate(void)
wakeups_per_second = ktime_set(0, 1000000000 / rate);
}
-static int dac_audio_ioctl(struct inode *inode, struct file *file,
+static int dac_audio_ioctl(struct file *file,
unsigned int cmd, unsigned long arg)
{
int val;
@@ -158,6 +160,17 @@ static int dac_audio_ioctl(struct inode *inode, struct file *file,
return -EINVAL;
}
+static long dac_audio_unlocked_ioctl(struct file *file, u_int cmd, u_long arg)
+{
+ int ret;
+
+ lock_kernel();
+ ret = dac_audio_ioctl(file, cmd, arg);
+ unlock_kernel();
+
+ return ret;
+}
+
static ssize_t dac_audio_write(struct file *file, const char *buf, size_t count,
loff_t * ppos)
{
@@ -216,13 +229,17 @@ static int dac_audio_open(struct inode *inode, struct file *file)
{
if (file->f_mode & FMODE_READ)
return -ENODEV;
- if (in_use)
+
+ lock_kernel();
+ if (in_use) {
+ unlock_kernel();
return -EBUSY;
+ }
in_use = 1;
dac_audio_start();
-
+ unlock_kernel();
return 0;
}
@@ -237,8 +254,8 @@ static int dac_audio_release(struct inode *inode, struct file *file)
const struct file_operations dac_audio_fops = {
.read = dac_audio_read,
- .write = dac_audio_write,
- .ioctl = dac_audio_ioctl,
+ .write = dac_audio_write,
+ .unlocked_ioctl = dac_audio_unlocked_ioctl,
.open = dac_audio_open,
.release = dac_audio_release,
};
diff --git a/sound/oss/soundcard.c b/sound/oss/soundcard.c
index 2d9c5131262..92aa762ffb7 100644
--- a/sound/oss/soundcard.c
+++ b/sound/oss/soundcard.c
@@ -210,42 +210,44 @@ static int sound_open(struct inode *inode, struct file *file)
printk(KERN_ERR "Invalid minor device %d\n", dev);
return -ENXIO;
}
+ lock_kernel();
switch (dev & 0x0f) {
case SND_DEV_CTL:
dev >>= 4;
if (dev >= 0 && dev < MAX_MIXER_DEV && mixer_devs[dev] == NULL) {
request_module("mixer%d", dev);
}
+ retval = -ENXIO;
if (dev && (dev >= num_mixers || mixer_devs[dev] == NULL))
- return -ENXIO;
+ break;
if (!try_module_get(mixer_devs[dev]->owner))
- return -ENXIO;
+ break;
+
+ retval = 0;
break;
case SND_DEV_SEQ:
case SND_DEV_SEQ2:
- if ((retval = sequencer_open(dev, file)) < 0)
- return retval;
+ retval = sequencer_open(dev, file);
break;
case SND_DEV_MIDIN:
- if ((retval = MIDIbuf_open(dev, file)) < 0)
- return retval;
+ retval = MIDIbuf_open(dev, file);
break;
case SND_DEV_DSP:
case SND_DEV_DSP16:
case SND_DEV_AUDIO:
- if ((retval = audio_open(dev, file)) < 0)
- return retval;
+ retval = audio_open(dev, file);
break;
default:
printk(KERN_ERR "Invalid minor device %d\n", dev);
- return -ENXIO;
+ retval = -ENXIO;
}
+ unlock_kernel();
return 0;
}
diff --git a/sound/oss/swarm_cs4297a.c b/sound/oss/swarm_cs4297a.c
index 3136c88eacd..b15840ad252 100644
--- a/sound/oss/swarm_cs4297a.c
+++ b/sound/oss/swarm_cs4297a.c
@@ -68,6 +68,7 @@
#include <linux/delay.h>
#include <linux/sound.h>
#include <linux/slab.h>
+#include <linux/smp_lock.h>
#include <linux/soundcard.h>
#include <linux/ac97_codec.h>
#include <linux/pci.h>
@@ -1534,6 +1535,7 @@ static int cs4297a_open_mixdev(struct inode *inode, struct file *file)
CS_DBGOUT(CS_FUNCTION | CS_OPEN, 4,
printk(KERN_INFO "cs4297a: cs4297a_open_mixdev()+\n"));
+ lock_kernel();
list_for_each(entry, &cs4297a_devs)
{
s = list_entry(entry, struct cs4297a_state, list);
@@ -1544,6 +1546,8 @@ static int cs4297a_open_mixdev(struct inode *inode, struct file *file)
{
CS_DBGOUT(CS_FUNCTION | CS_OPEN | CS_ERROR, 2,
printk(KERN_INFO "cs4297a: cs4297a_open_mixdev()- -ENODEV\n"));
+
+ unlock_kernel();
return -ENODEV;
}
VALIDATE_STATE(s);
@@ -1551,6 +1555,7 @@ static int cs4297a_open_mixdev(struct inode *inode, struct file *file)
CS_DBGOUT(CS_FUNCTION | CS_OPEN, 4,
printk(KERN_INFO "cs4297a: cs4297a_open_mixdev()- 0\n"));
+ unlock_kernel();
return nonseekable_open(inode, file);
}
@@ -1566,11 +1571,15 @@ static int cs4297a_release_mixdev(struct inode *inode, struct file *file)
}
-static int cs4297a_ioctl_mixdev(struct inode *inode, struct file *file,
+static int cs4297a_ioctl_mixdev(struct file *file,
unsigned int cmd, unsigned long arg)
{
- return mixer_ioctl((struct cs4297a_state *) file->private_data, cmd,
+ int ret;
+ lock_kernel();
+ ret = mixer_ioctl((struct cs4297a_state *) file->private_data, cmd,
arg);
+ unlock_kernel();
+ return ret;
}
@@ -1580,7 +1589,7 @@ static int cs4297a_ioctl_mixdev(struct inode *inode, struct file *file,
static const struct file_operations cs4297a_mixer_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
- .ioctl = cs4297a_ioctl_mixdev,
+ .unlocked_ioctl = cs4297a_ioctl_mixdev,
.open = cs4297a_open_mixdev,
.release = cs4297a_release_mixdev,
};
@@ -1944,7 +1953,7 @@ static int cs4297a_mmap(struct file *file, struct vm_area_struct *vma)
}
-static int cs4297a_ioctl(struct inode *inode, struct file *file,
+static int cs4297a_ioctl(struct file *file,
unsigned int cmd, unsigned long arg)
{
struct cs4297a_state *s =
@@ -2337,6 +2346,16 @@ static int cs4297a_ioctl(struct inode *inode, struct file *file,
return mixer_ioctl(s, cmd, arg);
}
+static long cs4297a_unlocked_ioctl(struct file *file, u_int cmd, u_long arg)
+{
+ int ret;
+
+ lock_kernel();
+ ret = cs4297a_ioctl(file, cmd, arg);
+ unlock_kernel();
+
+ return ret;
+}
static int cs4297a_release(struct inode *inode, struct file *file)
{
@@ -2369,7 +2388,7 @@ static int cs4297a_release(struct inode *inode, struct file *file)
return 0;
}
-static int cs4297a_open(struct inode *inode, struct file *file)
+static int cs4297a_locked_open(struct inode *inode, struct file *file)
{
int minor = iminor(inode);
struct cs4297a_state *s=NULL;
@@ -2486,6 +2505,16 @@ static int cs4297a_open(struct inode *inode, struct file *file)
return nonseekable_open(inode, file);
}
+static int cs4297a_open(struct inode *inode, struct file *file)
+{
+ int ret;
+
+ lock_kernel();
+ ret = cs4297a_open(inode, file);
+ unlock_kernel();
+
+ return ret;
+}
// ******************************************************************************************
// Wave (audio) file operations struct.
@@ -2496,7 +2525,7 @@ static const struct file_operations cs4297a_audio_fops = {
.read = cs4297a_read,
.write = cs4297a_write,
.poll = cs4297a_poll,
- .ioctl = cs4297a_ioctl,
+ .unlocked_ioctl = cs4297a_unlocked_ioctl,
.mmap = cs4297a_mmap,
.open = cs4297a_open,
.release = cs4297a_release,
diff --git a/sound/oss/vidc.c b/sound/oss/vidc.c
index ac39a531df1..f0e0caa5320 100644
--- a/sound/oss/vidc.c
+++ b/sound/oss/vidc.c
@@ -491,9 +491,6 @@ static void __init attach_vidc(struct address_info *hw_config)
vidc_adev = adev;
vidc_mixer_set(SOUND_MIXER_VOLUME, (85 | 85 << 8));
-#if defined(CONFIG_SOUND_SOFTOSS) || defined(CONFIG_SOUND_SOFTOSS_MODULE)
- softoss_dev = adev;
-#endif
return;
irq_failed:
diff --git a/sound/oss/vwsnd.c b/sound/oss/vwsnd.c
index 20b3b325aa8..8cd73cdd88a 100644
--- a/sound/oss/vwsnd.c
+++ b/sound/oss/vwsnd.c
@@ -2429,8 +2429,7 @@ static unsigned int vwsnd_audio_poll(struct file *file,
return mask;
}
-static int vwsnd_audio_do_ioctl(struct inode *inode,
- struct file *file,
+static int vwsnd_audio_do_ioctl(struct file *file,
unsigned int cmd,
unsigned long arg)
{
@@ -2446,8 +2445,8 @@ static int vwsnd_audio_do_ioctl(struct inode *inode,
int ival;
- DBGEV("(inode=0x%p, file=0x%p, cmd=0x%x, arg=0x%lx)\n",
- inode, file, cmd, arg);
+ DBGEV("(file=0x%p, cmd=0x%x, arg=0x%lx)\n",
+ file, cmd, arg);
switch (cmd) {
case OSS_GETVERSION: /* _SIOR ('M', 118, int) */
DBGX("OSS_GETVERSION\n");
@@ -2885,17 +2884,19 @@ static int vwsnd_audio_do_ioctl(struct inode *inode,
return -EINVAL;
}
-static int vwsnd_audio_ioctl(struct inode *inode,
- struct file *file,
+static long vwsnd_audio_ioctl(struct file *file,
unsigned int cmd,
unsigned long arg)
{
vwsnd_dev_t *devc = (vwsnd_dev_t *) file->private_data;
int ret;
+ lock_kernel();
mutex_lock(&devc->io_mutex);
- ret = vwsnd_audio_do_ioctl(inode, file, cmd, arg);
+ ret = vwsnd_audio_do_ioctl(file, cmd, arg);
mutex_unlock(&devc->io_mutex);
+ unlock_kernel();
+
return ret;
}
@@ -2921,6 +2922,7 @@ static int vwsnd_audio_open(struct inode *inode, struct file *file)
DBGE("(inode=0x%p, file=0x%p)\n", inode, file);
+ lock_kernel();
INC_USE_COUNT;
for (devc = vwsnd_dev_list; devc; devc = devc->next_dev)
if ((devc->audio_minor & ~0x0F) == (minor & ~0x0F))
@@ -2928,6 +2930,7 @@ static int vwsnd_audio_open(struct inode *inode, struct file *file)
if (devc == NULL) {
DEC_USE_COUNT;
+ unlock_kernel();
return -ENODEV;
}
@@ -2936,11 +2939,13 @@ static int vwsnd_audio_open(struct inode *inode, struct file *file)
mutex_unlock(&devc->open_mutex);
if (file->f_flags & O_NONBLOCK) {
DEC_USE_COUNT;
+ unlock_kernel();
return -EBUSY;
}
interruptible_sleep_on(&devc->open_wait);
if (signal_pending(current)) {
DEC_USE_COUNT;
+ unlock_kernel();
return -ERESTARTSYS;
}
mutex_lock(&devc->open_mutex);
@@ -2993,6 +2998,7 @@ static int vwsnd_audio_open(struct inode *inode, struct file *file)
file->private_data = devc;
DBGRV();
+ unlock_kernel();
return 0;
}
@@ -3044,7 +3050,7 @@ static const struct file_operations vwsnd_audio_fops = {
.read = vwsnd_audio_read,
.write = vwsnd_audio_write,
.poll = vwsnd_audio_poll,
- .ioctl = vwsnd_audio_ioctl,
+ .unlocked_ioctl = vwsnd_audio_ioctl,
.mmap = vwsnd_audio_mmap,
.open = vwsnd_audio_open,
.release = vwsnd_audio_release,
@@ -3062,15 +3068,18 @@ static int vwsnd_mixer_open(struct inode *inode, struct file *file)
DBGEV("(inode=0x%p, file=0x%p)\n", inode, file);
INC_USE_COUNT;
+ lock_kernel();
for (devc = vwsnd_dev_list; devc; devc = devc->next_dev)
if (devc->mixer_minor == iminor(inode))
break;
if (devc == NULL) {
DEC_USE_COUNT;
+ unlock_kernel();
return -ENODEV;
}
file->private_data = devc;
+ unlock_kernel();
return 0;
}
@@ -3203,8 +3212,7 @@ static int mixer_write_ioctl(vwsnd_dev_t *devc, unsigned int nr, void __user *ar
/* This is the ioctl entry to the mixer driver. */
-static int vwsnd_mixer_ioctl(struct inode *ioctl,
- struct file *file,
+static long vwsnd_mixer_ioctl(struct file *file,
unsigned int cmd,
unsigned long arg)
{
@@ -3215,6 +3223,7 @@ static int vwsnd_mixer_ioctl(struct inode *ioctl,
DBGEV("(devc=0x%p, cmd=0x%x, arg=0x%lx)\n", devc, cmd, arg);
+ lock_kernel();
mutex_lock(&devc->mix_mutex);
{
if ((cmd & ~nrmask) == MIXER_READ(0))
@@ -3225,13 +3234,14 @@ static int vwsnd_mixer_ioctl(struct inode *ioctl,
retval = -EINVAL;
}
mutex_unlock(&devc->mix_mutex);
+ unlock_kernel();
return retval;
}
static const struct file_operations vwsnd_mixer_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
- .ioctl = vwsnd_mixer_ioctl,
+ .unlocked_ioctl = vwsnd_mixer_ioctl,
.open = vwsnd_mixer_open,
.release = vwsnd_mixer_release,
};
diff --git a/sound/oss/waveartist.c b/sound/oss/waveartist.c
index e688dde6bbd..52468742d9f 100644
--- a/sound/oss/waveartist.c
+++ b/sound/oss/waveartist.c
@@ -184,14 +184,8 @@ waveartist_iack(wavnc_info *devc)
static inline int
waveartist_sleep(int timeout_ms)
{
- unsigned int timeout = timeout_ms * 10 * HZ / 100;
-
- do {
- set_current_state(TASK_INTERRUPTIBLE);
- timeout = schedule_timeout(timeout);
- } while (timeout);
-
- return 0;
+ unsigned int timeout = msecs_to_jiffies(timeout_ms*100);
+ return schedule_timeout_interruptible(timeout);
}
static int
diff --git a/sound/pci/als4000.c b/sound/pci/als4000.c
index 6cf1de8042e..0e247cb90ec 100644
--- a/sound/pci/als4000.c
+++ b/sound/pci/als4000.c
@@ -763,9 +763,9 @@ static void snd_als4000_configure(struct snd_sb *chip)
/* SPECS_PAGE: 39 */
for (i = ALS4K_GCR91_DMA0_ADDR; i <= ALS4K_GCR96_DMA3_MODE_COUNT; ++i)
snd_als4k_gcr_write(chip, i, 0);
-
+ /* enable burst mode to prevent dropouts during high PCI bus usage */
snd_als4k_gcr_write(chip, ALS4K_GCR99_DMA_EMULATION_CTRL,
- snd_als4k_gcr_read(chip, ALS4K_GCR99_DMA_EMULATION_CTRL));
+ (snd_als4k_gcr_read(chip, ALS4K_GCR99_DMA_EMULATION_CTRL) & ~0x07) | 0x04);
spin_unlock_irq(&chip->reg_lock);
}
diff --git a/sound/pci/asihpi/asihpi.c b/sound/pci/asihpi/asihpi.c
index 1db586af4f9..c80b0b863c5 100644
--- a/sound/pci/asihpi/asihpi.c
+++ b/sound/pci/asihpi/asihpi.c
@@ -460,6 +460,7 @@ static int snd_card_asihpi_pcm_hw_params(struct snd_pcm_substream *substream,
struct snd_card_asihpi *card = snd_pcm_substream_chip(substream);
int err;
u16 format;
+ int width;
unsigned int bytes_per_sec;
print_hwparams(params);
@@ -512,9 +513,10 @@ static int snd_card_asihpi_pcm_hw_params(struct snd_pcm_substream *substream,
dpcm->hpi_buffer_attached);
}
bytes_per_sec = params_rate(params) * params_channels(params);
- bytes_per_sec *= snd_pcm_format_width(params_format(params));
+ width = snd_pcm_format_width(params_format(params));
+ bytes_per_sec *= width;
bytes_per_sec /= 8;
- if (bytes_per_sec <= 0)
+ if (width < 0 || bytes_per_sec == 0)
return -EINVAL;
dpcm->bytes_per_sec = bytes_per_sec;
@@ -1383,7 +1385,7 @@ static char *asihpi_src_names[] =
compile_time_assert(
(ARRAY_SIZE(asihpi_src_names) ==
- (HPI_SOURCENODE_LAST_INDEX-HPI_SOURCENODE_BASE+1)),
+ (HPI_SOURCENODE_LAST_INDEX-HPI_SOURCENODE_NONE+1)),
assert_src_names_size);
#if ASI_STYLE_NAMES
@@ -1414,7 +1416,7 @@ static char *asihpi_dst_names[] =
compile_time_assert(
(ARRAY_SIZE(asihpi_dst_names) ==
- (HPI_DESTNODE_LAST_INDEX-HPI_DESTNODE_BASE+1)),
+ (HPI_DESTNODE_LAST_INDEX-HPI_DESTNODE_NONE+1)),
assert_dst_names_size);
static inline int ctl_add(struct snd_card *card, struct snd_kcontrol_new *ctl,
@@ -2171,7 +2173,7 @@ static int snd_asihpi_mux_info(struct snd_kcontrol *kcontrol,
&src_node_type, &src_node_index);
sprintf(uinfo->value.enumerated.name, "%s %d",
- asihpi_src_names[src_node_type - HPI_SOURCENODE_BASE],
+ asihpi_src_names[src_node_type - HPI_SOURCENODE_NONE],
src_node_index);
return 0;
}
@@ -2603,8 +2605,8 @@ static int __devinit snd_card_asihpi_mixer_new(struct snd_card_asihpi *asihpi)
}
- hpi_ctl.src_node_type -= HPI_SOURCENODE_BASE;
- hpi_ctl.dst_node_type -= HPI_DESTNODE_BASE;
+ hpi_ctl.src_node_type -= HPI_SOURCENODE_NONE;
+ hpi_ctl.dst_node_type -= HPI_DESTNODE_NONE;
/* ASI50xx in SSX mode has multiple meters on the same node.
Use subindex to create distinct ALSA controls
diff --git a/sound/pci/asihpi/hpi.h b/sound/pci/asihpi/hpi.h
index 0173bbe62b6..23399d02f66 100644
--- a/sound/pci/asihpi/hpi.h
+++ b/sound/pci/asihpi/hpi.h
@@ -50,7 +50,8 @@ i.e 3.05.02 is a development version
#define HPI_VER_RELEASE(v) ((int)(v & 0xFF))
/* Use single digits for versions less that 10 to avoid octal. */
-#define HPI_VER HPI_VERSION_CONSTRUCTOR(4L, 3, 25)
+#define HPI_VER HPI_VERSION_CONSTRUCTOR(4L, 4, 1)
+#define HPI_VER_STRING "4.04.01"
/* Library version as documented in hpi-api-versions.txt */
#define HPI_LIB_VER HPI_VERSION_CONSTRUCTOR(9, 0, 0)
@@ -203,8 +204,6 @@ enum HPI_SOURCENODES {
exists on a destination node can be searched for using a source
node value of either 0, or HPI_SOURCENODE_NONE */
HPI_SOURCENODE_NONE = 100,
- /** \deprecated Use HPI_SOURCENODE_NONE instead. */
- HPI_SOURCENODE_BASE = 100,
/** Out Stream (Play) node. */
HPI_SOURCENODE_OSTREAM = 101,
/** Line in node - could be analog, AES/EBU or network. */
@@ -235,8 +234,6 @@ enum HPI_DESTNODES {
exists on a source node can be searched for using a destination
node value of either 0, or HPI_DESTNODE_NONE */
HPI_DESTNODE_NONE = 200,
- /** \deprecated Use HPI_DESTNODE_NONE instead. */
- HPI_DESTNODE_BASE = 200,
/** In Stream (Record) node. */
HPI_DESTNODE_ISTREAM = 201,
HPI_DESTNODE_LINEOUT = 202, /**< line out node. */
@@ -432,7 +429,18 @@ Property 2 - adapter can do stream grouping (supports SSX2)
Property 1 - adapter can do samplerate conversion (MRX)
Property 2 - adapter can do timestretch (TSX)
*/
- HPI_ADAPTER_PROPERTY_CAPS2 = 269
+ HPI_ADAPTER_PROPERTY_CAPS2 = 269,
+
+/** Readonly adapter sync header connection count.
+*/
+ HPI_ADAPTER_PROPERTY_SYNC_HEADER_CONNECTIONS = 270,
+/** Readonly supports SSX2 property.
+Indicates the adapter supports SSX2 in some mode setting. The
+return value is true (1) or false (0). If the current adapter
+mode is MONO SSX2 is disabled, even though this property will
+return true.
+*/
+ HPI_ADAPTER_PROPERTY_SUPPORTS_SSX2 = 271
};
/** Adapter mode commands
@@ -813,8 +821,6 @@ enum HPI_SAMPLECLOCK_SOURCES {
/** The sampleclock output is derived from its local samplerate generator.
The local samplerate may be set using HPI_SampleClock_SetLocalRate(). */
HPI_SAMPLECLOCK_SOURCE_LOCAL = 1,
-/** \deprecated Use HPI_SAMPLECLOCK_SOURCE_LOCAL instead */
- HPI_SAMPLECLOCK_SOURCE_ADAPTER = 1,
/** The adapter is clocked from a dedicated AES/EBU SampleClock input.*/
HPI_SAMPLECLOCK_SOURCE_AESEBU_SYNC = 2,
/** From external wordclock connector */
@@ -825,10 +831,6 @@ enum HPI_SAMPLECLOCK_SOURCES {
HPI_SAMPLECLOCK_SOURCE_SMPTE = 5,
/** One of the aesebu inputs */
HPI_SAMPLECLOCK_SOURCE_AESEBU_INPUT = 6,
-/** \deprecated The first aesebu input with a valid signal
-Superseded by separate Auto enable flag
-*/
- HPI_SAMPLECLOCK_SOURCE_AESEBU_AUTO = 7,
/** From a network interface e.g. Cobranet or Livewire at either 48 or 96kHz */
HPI_SAMPLECLOCK_SOURCE_NETWORK = 8,
/** From previous adjacent module (ASI2416 only)*/
@@ -1015,8 +1017,6 @@ enum HPI_ERROR_CODES {
HPI_ERROR_CONTROL_DISABLED = 404,
/** I2C transaction failed due to a missing ACK. */
HPI_ERROR_CONTROL_I2C_MISSING_ACK = 405,
- /** Control attribute is valid, but not supported by this hardware. */
- HPI_ERROR_UNSUPPORTED_CONTROL_ATTRIBUTE = 406,
/** Control is busy, or coming out of
reset and cannot be accessed at this time. */
HPI_ERROR_CONTROL_NOT_READY = 407,
@@ -1827,13 +1827,41 @@ u16 hpi_parametricEQ__get_coeffs(const struct hpi_hsubsys *ph_subsys,
Compressor Expander control
*******************************/
-u16 hpi_compander_set(const struct hpi_hsubsys *ph_subsys, u32 h_control,
- u16 attack, u16 decay, short ratio100, short threshold0_01dB,
- short makeup_gain0_01dB);
+u16 hpi_compander_set_enable(const struct hpi_hsubsys *ph_subsys,
+ u32 h_control, u32 on);
+
+u16 hpi_compander_get_enable(const struct hpi_hsubsys *ph_subsys,
+ u32 h_control, u32 *pon);
+
+u16 hpi_compander_set_makeup_gain(const struct hpi_hsubsys *ph_subsys,
+ u32 h_control, short makeup_gain0_01dB);
+
+u16 hpi_compander_get_makeup_gain(const struct hpi_hsubsys *ph_subsys,
+ u32 h_control, short *pn_makeup_gain0_01dB);
+
+u16 hpi_compander_set_attack_time_constant(const struct hpi_hsubsys
+ *ph_subsys, u32 h_control, u32 index, u32 attack);
+
+u16 hpi_compander_get_attack_time_constant(const struct hpi_hsubsys
+ *ph_subsys, u32 h_control, u32 index, u32 *pw_attack);
+
+u16 hpi_compander_set_decay_time_constant(const struct hpi_hsubsys *ph_subsys,
+ u32 h_control, u32 index, u32 decay);
+
+u16 hpi_compander_get_decay_time_constant(const struct hpi_hsubsys *ph_subsys,
+ u32 h_control, u32 index, u32 *pw_decay);
+
+u16 hpi_compander_set_threshold(const struct hpi_hsubsys *ph_subsys,
+ u32 h_control, u32 index, short threshold0_01dB);
+
+u16 hpi_compander_get_threshold(const struct hpi_hsubsys *ph_subsys,
+ u32 h_control, u32 index, short *pn_threshold0_01dB);
+
+u16 hpi_compander_set_ratio(const struct hpi_hsubsys *ph_subsys,
+ u32 h_control, u32 index, u32 ratio100);
-u16 hpi_compander_get(const struct hpi_hsubsys *ph_subsys, u32 h_control,
- u16 *pw_attack, u16 *pw_decay, short *pw_ratio100,
- short *pn_threshold0_01dB, short *pn_makeup_gain0_01dB);
+u16 hpi_compander_get_ratio(const struct hpi_hsubsys *ph_subsys,
+ u32 h_control, u32 index, u32 *pw_ratio100);
/*******************************
Cobranet HMI control
diff --git a/sound/pci/asihpi/hpi6000.c b/sound/pci/asihpi/hpi6000.c
index 12dab5e4892..f7e374ec441 100644
--- a/sound/pci/asihpi/hpi6000.c
+++ b/sound/pci/asihpi/hpi6000.c
@@ -687,6 +687,7 @@ static short hpi6000_adapter_boot_load_dsp(struct hpi_adapter_obj *pao,
switch (pao->pci.subsys_device_id) {
case 0x5100:
case 0x5110: /* ASI5100 revB or higher with C6711D */
+ case 0x5200: /* ASI5200 PC_ie version of ASI5100 */
case 0x6100:
case 0x6200:
boot_load_family = HPI_ADAPTER_FAMILY_ASI(0x6200);
@@ -1133,6 +1134,12 @@ static short hpi6000_adapter_boot_load_dsp(struct hpi_adapter_obj *pao,
subsys_device_id) ==
HPI_ADAPTER_FAMILY_ASI(0x5100))
mask = 0x00000000L;
+ /* ASI5200 uses AX6 code, */
+ /* but has no PLD r/w register to test */
+ if (HPI_ADAPTER_FAMILY_ASI(pao->pci.
+ subsys_device_id) ==
+ HPI_ADAPTER_FAMILY_ASI(0x5200))
+ mask = 0x00000000L;
break;
case HPI_ADAPTER_FAMILY_ASI(0x8800):
/* ASI8800 has 16bit path to FPGA */
diff --git a/sound/pci/asihpi/hpi_internal.h b/sound/pci/asihpi/hpi_internal.h
index fdd0ce02aa6..16f502d459d 100644
--- a/sound/pci/asihpi/hpi_internal.h
+++ b/sound/pci/asihpi/hpi_internal.h
@@ -104,9 +104,9 @@ typedef void hpi_handler_func(struct hpi_message *, struct hpi_response *);
#define STR_ROLE_FIELD_MAX 255U
struct hpi_entity_str {
- uint16_t size;
- uint8_t type;
- uint8_t role;
+ u16 size;
+ u8 type;
+ u8 role;
};
#if defined(_MSC_VER)
@@ -119,11 +119,11 @@ struct hpi_entity {
#if ! defined(HPI_OS_DSP_C6000) || (defined(HPI_OS_DSP_C6000) && (__TI_COMPILER_VERSION__ > 6000008))
/* DSP C6000 compiler v6.0.8 and lower
do not support flexible array member */
- uint8_t value[];
+ u8 value[];
#else
/* NOTE! Using sizeof(struct hpi_entity) will give erroneous results */
#define HPI_INTERNAL_WARN_ABOUT_ENTITY_VALUE
- uint8_t value[1];
+ u8 value[1];
#endif
};
@@ -142,12 +142,15 @@ enum HPI_BUSES {
/******************************************* CONTROL ATTRIBUTES ****/
/* (in order of control type ID */
- /* This allows for 255 control types, 256 unique attributes each */
+/* This allows for 255 control types, 256 unique attributes each */
#define HPI_CTL_ATTR(ctl, ai) (HPI_CONTROL_##ctl * 0x100 + ai)
/* Get the sub-index of the attribute for a control type */
#define HPI_CTL_ATTR_INDEX(i) (i&0xff)
+/* Extract the control from the control attribute */
+#define HPI_CTL_ATTR_CONTROL(i) (i>>8)
+
/* Generic control attributes. */
/** Enable a control.
@@ -311,8 +314,7 @@ Used for HPI_ChannelModeSet/Get()
/* Microphone control attributes */
#define HPI_MICROPHONE_PHANTOM_POWER HPI_CTL_ATTR(MICROPHONE, 1)
-/** Equalizer control attributes
-*/
+/** Equalizer control attributes */
/** Used to get number of filters in an EQ. (Can't set) */
#define HPI_EQUALIZER_NUM_FILTERS HPI_CTL_ATTR(EQUALIZER, 1)
/** Set/get the filter by type, freq, Q, gain */
@@ -320,13 +322,15 @@ Used for HPI_ChannelModeSet/Get()
/** Get the biquad coefficients */
#define HPI_EQUALIZER_COEFFICIENTS HPI_CTL_ATTR(EQUALIZER, 3)
-#define HPI_COMPANDER_PARAMS HPI_CTL_ATTR(COMPANDER, 1)
+/* Note compander also uses HPI_GENERIC_ENABLE */
+#define HPI_COMPANDER_PARAMS HPI_CTL_ATTR(COMPANDER, 1)
+#define HPI_COMPANDER_MAKEUPGAIN HPI_CTL_ATTR(COMPANDER, 2)
+#define HPI_COMPANDER_THRESHOLD HPI_CTL_ATTR(COMPANDER, 3)
+#define HPI_COMPANDER_RATIO HPI_CTL_ATTR(COMPANDER, 4)
+#define HPI_COMPANDER_ATTACK HPI_CTL_ATTR(COMPANDER, 5)
+#define HPI_COMPANDER_DECAY HPI_CTL_ATTR(COMPANDER, 6)
-/* Cobranet control attributes.
- MUST be distinct from all other control attributes.
- This is so that host side processing can easily identify a Cobranet control
- and apply additional host side operations (like copying data) as required.
-*/
+/* Cobranet control attributes. */
#define HPI_COBRANET_SET HPI_CTL_ATTR(COBRANET, 1)
#define HPI_COBRANET_GET HPI_CTL_ATTR(COBRANET, 2)
#define HPI_COBRANET_SET_DATA HPI_CTL_ATTR(COBRANET, 3)
@@ -1512,11 +1516,11 @@ struct hpi_control_cache_single {
struct hpi_control_cache_info i;
union {
struct { /* volume */
- u16 an_log[2];
+ short an_log[2];
} v;
struct { /* peak meter */
- u16 an_log_peak[2];
- u16 an_logRMS[2];
+ short an_log_peak[2];
+ short an_logRMS[2];
} p;
struct { /* channel mode */
u16 mode;
@@ -1526,7 +1530,7 @@ struct hpi_control_cache_single {
u16 source_node_index;
} x;
struct { /* level/trim */
- u16 an_log[2];
+ short an_log[2];
} l;
struct { /* tuner - partial caching.
some attributes go to the DSP. */
diff --git a/sound/pci/asihpi/hpicmn.c b/sound/pci/asihpi/hpicmn.c
index fcd64539d9e..dda4f1c6f65 100644
--- a/sound/pci/asihpi/hpicmn.c
+++ b/sound/pci/asihpi/hpicmn.c
@@ -353,7 +353,12 @@ short hpi_check_control_cache(struct hpi_control_cache *p_cache,
phr->u.c.param1 = pC->u.t.band;
else if ((phm->u.c.attribute == HPI_TUNER_LEVEL)
&& (phm->u.c.param1 == HPI_TUNER_LEVEL_AVERAGE))
- phr->u.c.param1 = pC->u.t.level;
+ if (pC->u.t.level == HPI_ERROR_ILLEGAL_CACHE_VALUE) {
+ phr->u.c.param1 = 0;
+ phr->error =
+ HPI_ERROR_INVALID_CONTROL_ATTRIBUTE;
+ } else
+ phr->u.c.param1 = pC->u.t.level;
else
found = 0;
break;
@@ -397,7 +402,8 @@ short hpi_check_control_cache(struct hpi_control_cache *p_cache,
if (pC->u.clk.source_index ==
HPI_ERROR_ILLEGAL_CACHE_VALUE) {
phr->u.c.param1 = 0;
- phr->error = HPI_ERROR_INVALID_OPERATION;
+ phr->error =
+ HPI_ERROR_INVALID_CONTROL_ATTRIBUTE;
} else
phr->u.c.param1 = pC->u.clk.source_index;
} else if (phm->u.c.attribute == HPI_SAMPLECLOCK_SAMPLERATE)
diff --git a/sound/pci/asihpi/hpidebug.c b/sound/pci/asihpi/hpidebug.c
index 4cd85a401b3..949836ec913 100644
--- a/sound/pci/asihpi/hpidebug.c
+++ b/sound/pci/asihpi/hpidebug.c
@@ -111,7 +111,7 @@ make_treenode_from_array(hpi_control_type_strings, HPI_CONTROL_TYPE_STRINGS)
&hpi_profile_strings,\
&hpi_control_strings, \
&hpi_asyncevent_strings \
-};
+}
make_treenode_from_array(hpi_function_strings, HPI_FUNCTION_STRINGS)
compile_time_assert(HPI_OBJ_MAXINDEX == 14, obj_list_doesnt_match);
diff --git a/sound/pci/asihpi/hpidebug.h b/sound/pci/asihpi/hpidebug.h
index 44dccadcc25..a2f0952a99f 100644
--- a/sound/pci/asihpi/hpidebug.h
+++ b/sound/pci/asihpi/hpidebug.h
@@ -356,7 +356,7 @@ compile_time_assert((HPI_CONTROL_LAST_INDEX + 1 == 27),
"HPI_SOURCENODE_ADAPTER" \
}
-compile_time_assert((HPI_SOURCENODE_LAST_INDEX - HPI_SOURCENODE_BASE + 1) ==
+compile_time_assert((HPI_SOURCENODE_LAST_INDEX - HPI_SOURCENODE_NONE + 1) ==
(12), sourcenode_strings_match_defs);
#define HPI_DESTNODE_STRINGS \
@@ -370,7 +370,7 @@ compile_time_assert((HPI_SOURCENODE_LAST_INDEX - HPI_SOURCENODE_BASE + 1) ==
"HPI_DESTNODE_COBRANET", \
"HPI_DESTNODE_ANALOG" \
}
-compile_time_assert((HPI_DESTNODE_LAST_INDEX - HPI_DESTNODE_BASE + 1) == (8),
+compile_time_assert((HPI_DESTNODE_LAST_INDEX - HPI_DESTNODE_NONE + 1) == (8),
destnode_strings_match_defs);
#define HPI_CONTROL_CHANNEL_MODE_STRINGS \
diff --git a/sound/pci/asihpi/hpifunc.c b/sound/pci/asihpi/hpifunc.c
index 298eef3e20e..1e92eb6dd50 100644
--- a/sound/pci/asihpi/hpifunc.c
+++ b/sound/pci/asihpi/hpifunc.c
@@ -96,8 +96,7 @@ void hpi_stream_response_to_legacy(struct hpi_stream_res *pSR)
static struct hpi_hsubsys gh_subsys;
-struct hpi_hsubsys *hpi_subsys_create(void
- )
+struct hpi_hsubsys *hpi_subsys_create(void)
{
struct hpi_message hm;
struct hpi_response hr;
@@ -302,6 +301,7 @@ u16 hpi_adapter_set_mode_ex(const struct hpi_hsubsys *ph_subsys,
{
struct hpi_message hm;
struct hpi_response hr;
+
hpi_init_message_response(&hm, &hr, HPI_OBJ_ADAPTER,
HPI_ADAPTER_SET_MODE);
hm.adapter_index = adapter_index;
@@ -510,7 +510,7 @@ u16 hpi_adapter_debug_read(const struct hpi_hsubsys *ph_subsys,
hm.adapter_index = adapter_index;
hm.u.ax.debug_read.dsp_address = dsp_address;
- if (*count_bytes > sizeof(hr.u.bytes))
+ if (*count_bytes > (int)sizeof(hr.u.bytes))
*count_bytes = sizeof(hr.u.bytes);
hm.u.ax.debug_read.count_bytes = *count_bytes;
@@ -976,6 +976,7 @@ u16 hpi_outstream_ancillary_read(const struct hpi_hsubsys *ph_subsys,
{
struct hpi_message hm;
struct hpi_response hr;
+
hpi_init_message_response(&hm, &hr, HPI_OBJ_OSTREAM,
HPI_OSTREAM_ANC_READ);
u32TOINDEXES(h_outstream, &hm.adapter_index, &hm.obj_index);
@@ -1581,6 +1582,7 @@ u16 hpi_control_param_set(const struct hpi_hsubsys *ph_subsys,
{
struct hpi_message hm;
struct hpi_response hr;
+
hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL,
HPI_CONTROL_SET_STATE);
u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index);
@@ -1591,6 +1593,22 @@ u16 hpi_control_param_set(const struct hpi_hsubsys *ph_subsys,
return hr.error;
}
+static u16 hpi_control_log_set2(u32 h_control, u16 attrib, short sv0,
+ short sv1)
+{
+ struct hpi_message hm;
+ struct hpi_response hr;
+
+ hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL,
+ HPI_CONTROL_SET_STATE);
+ u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index);
+ hm.u.c.attribute = attrib;
+ hm.u.c.an_log_value[0] = sv0;
+ hm.u.c.an_log_value[1] = sv1;
+ hpi_send_recv(&hm, &hr);
+ return hr.error;
+}
+
static
u16 hpi_control_param_get(const struct hpi_hsubsys *ph_subsys,
const u32 h_control, const u16 attrib, u32 param1, u32 param2,
@@ -1598,6 +1616,7 @@ u16 hpi_control_param_get(const struct hpi_hsubsys *ph_subsys,
{
struct hpi_message hm;
struct hpi_response hr;
+
hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL,
HPI_CONTROL_GET_STATE);
u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index);
@@ -1605,8 +1624,8 @@ u16 hpi_control_param_get(const struct hpi_hsubsys *ph_subsys,
hm.u.c.param1 = param1;
hm.u.c.param2 = param2;
hpi_send_recv(&hm, &hr);
- if (pparam1)
- *pparam1 = hr.u.c.param1;
+
+ *pparam1 = hr.u.c.param1;
if (pparam2)
*pparam2 = hr.u.c.param2;
@@ -1617,10 +1636,23 @@ u16 hpi_control_param_get(const struct hpi_hsubsys *ph_subsys,
hpi_control_param_get(s, h, a, 0, 0, p1, NULL)
#define hpi_control_param2_get(s, h, a, p1, p2) \
hpi_control_param_get(s, h, a, 0, 0, p1, p2)
-#define hpi_control_ex_param1_get(s, h, a, p1) \
- hpi_control_ex_param_get(s, h, a, 0, 0, p1, NULL)
-#define hpi_control_ex_param2_get(s, h, a, p1, p2) \
- hpi_control_ex_param_get(s, h, a, 0, 0, p1, p2)
+
+static u16 hpi_control_log_get2(const struct hpi_hsubsys *ph_subsys,
+ u32 h_control, u16 attrib, short *sv0, short *sv1)
+{
+ struct hpi_message hm;
+ struct hpi_response hr;
+ hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL,
+ HPI_CONTROL_GET_STATE);
+ u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index);
+ hm.u.c.attribute = attrib;
+
+ hpi_send_recv(&hm, &hr);
+ *sv0 = hr.u.c.an_log_value[0];
+ if (sv1)
+ *sv1 = hr.u.c.an_log_value[1];
+ return hr.error;
+}
static
u16 hpi_control_query(const struct hpi_hsubsys *ph_subsys,
@@ -1629,6 +1661,7 @@ u16 hpi_control_query(const struct hpi_hsubsys *ph_subsys,
{
struct hpi_message hm;
struct hpi_response hr;
+
hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL,
HPI_CONTROL_GET_INFO);
u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index);
@@ -1643,9 +1676,8 @@ u16 hpi_control_query(const struct hpi_hsubsys *ph_subsys,
return hr.error;
}
-static u16 hpi_control_get_string(const struct hpi_hsubsys *ph_subsys,
- const u32 h_control, const u16 attribute, char *psz_string,
- const u32 string_length)
+static u16 hpi_control_get_string(const u32 h_control, const u16 attribute,
+ char *psz_string, const u32 string_length)
{
unsigned int sub_string_index = 0, j = 0;
char c = 0;
@@ -1916,6 +1948,7 @@ u16 hpi_cobranet_hmi_write(const struct hpi_hsubsys *ph_subsys, u32 h_control,
{
struct hpi_message hm;
struct hpi_response hr;
+
hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROLEX,
HPI_CONTROL_SET_STATE);
u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index);
@@ -1941,6 +1974,7 @@ u16 hpi_cobranet_hmi_read(const struct hpi_hsubsys *ph_subsys, u32 h_control,
{
struct hpi_message hm;
struct hpi_response hr;
+
hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROLEX,
HPI_CONTROL_GET_STATE);
u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index);
@@ -1980,6 +2014,7 @@ u16 hpi_cobranet_hmi_get_status(const struct hpi_hsubsys *ph_subsys,
{
struct hpi_message hm;
struct hpi_response hr;
+
hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROLEX,
HPI_CONTROL_GET_STATE);
u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index);
@@ -2006,6 +2041,7 @@ u16 hpi_cobranet_getI_paddress(const struct hpi_hsubsys *ph_subsys,
u32 byte_count;
u32 iP;
u16 error;
+
error = hpi_cobranet_hmi_read(ph_subsys, h_control,
HPI_COBRANET_HMI_cobra_ip_mon_currentIP, 4, &byte_count,
(u8 *)&iP);
@@ -2082,6 +2118,7 @@ u16 hpi_cobranet_getMA_caddress(const struct hpi_hsubsys *ph_subsys,
u32 byte_count;
u16 error;
u32 mAC;
+
error = hpi_cobranet_hmi_read(ph_subsys, h_control,
HPI_COBRANET_HMI_cobra_if_phy_address, 4, &byte_count,
(u8 *)&mAC);
@@ -2103,53 +2140,111 @@ u16 hpi_cobranet_getMA_caddress(const struct hpi_hsubsys *ph_subsys,
return error;
}
-u16 hpi_compander_set(const struct hpi_hsubsys *ph_subsys, u32 h_control,
- u16 attack, u16 decay, short ratio100, short threshold0_01dB,
- short makeup_gain0_01dB)
+u16 hpi_compander_set_enable(const struct hpi_hsubsys *ph_subsys,
+ u32 h_control, u32 enable)
+{
+ return hpi_control_param_set(ph_subsys, h_control, HPI_GENERIC_ENABLE,
+ enable, 0);
+}
+
+u16 hpi_compander_get_enable(const struct hpi_hsubsys *ph_subsys,
+ u32 h_control, u32 *enable)
+{
+ return hpi_control_param1_get(ph_subsys, h_control,
+ HPI_GENERIC_ENABLE, enable);
+}
+
+u16 hpi_compander_set_makeup_gain(const struct hpi_hsubsys *ph_subsys,
+ u32 h_control, short makeup_gain0_01dB)
+{
+ return hpi_control_log_set2(h_control, HPI_COMPANDER_MAKEUPGAIN,
+ makeup_gain0_01dB, 0);
+}
+
+u16 hpi_compander_get_makeup_gain(const struct hpi_hsubsys *ph_subsys,
+ u32 h_control, short *makeup_gain0_01dB)
+{
+ return hpi_control_log_get2(ph_subsys, h_control,
+ HPI_COMPANDER_MAKEUPGAIN, makeup_gain0_01dB, NULL);
+}
+
+u16 hpi_compander_set_attack_time_constant(const struct hpi_hsubsys
+ *ph_subsys, u32 h_control, unsigned int index, u32 attack)
+{
+ return hpi_control_param_set(ph_subsys, h_control,
+ HPI_COMPANDER_ATTACK, attack, index);
+}
+
+u16 hpi_compander_get_attack_time_constant(const struct hpi_hsubsys
+ *ph_subsys, u32 h_control, unsigned int index, u32 *attack)
+{
+ return hpi_control_param_get(ph_subsys, h_control,
+ HPI_COMPANDER_ATTACK, 0, index, attack, NULL);
+}
+
+u16 hpi_compander_set_decay_time_constant(const struct hpi_hsubsys *ph_subsys,
+ u32 h_control, unsigned int index, u32 decay)
+{
+ return hpi_control_param_set(ph_subsys, h_control,
+ HPI_COMPANDER_DECAY, decay, index);
+}
+
+u16 hpi_compander_get_decay_time_constant(const struct hpi_hsubsys *ph_subsys,
+ u32 h_control, unsigned int index, u32 *decay)
+{
+ return hpi_control_param_get(ph_subsys, h_control,
+ HPI_COMPANDER_DECAY, 0, index, decay, NULL);
+
+}
+
+u16 hpi_compander_set_threshold(const struct hpi_hsubsys *ph_subsys,
+ u32 h_control, unsigned int index, short threshold0_01dB)
{
struct hpi_message hm;
struct hpi_response hr;
+
hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL,
HPI_CONTROL_SET_STATE);
u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index);
-
- hm.u.c.param1 = attack + ((u32)ratio100 << 16);
- hm.u.c.param2 = (decay & 0xFFFFL);
+ hm.u.c.attribute = HPI_COMPANDER_THRESHOLD;
+ hm.u.c.param2 = index;
hm.u.c.an_log_value[0] = threshold0_01dB;
- hm.u.c.an_log_value[1] = makeup_gain0_01dB;
- hm.u.c.attribute = HPI_COMPANDER_PARAMS;
hpi_send_recv(&hm, &hr);
return hr.error;
}
-u16 hpi_compander_get(const struct hpi_hsubsys *ph_subsys, u32 h_control,
- u16 *pw_attack, u16 *pw_decay, short *pw_ratio100,
- short *pn_threshold0_01dB, short *pn_makeup_gain0_01dB)
+u16 hpi_compander_get_threshold(const struct hpi_hsubsys *ph_subsys,
+ u32 h_control, unsigned int index, short *threshold0_01dB)
{
struct hpi_message hm;
struct hpi_response hr;
+
hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL,
HPI_CONTROL_GET_STATE);
u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index);
- hm.u.c.attribute = HPI_COMPANDER_PARAMS;
+ hm.u.c.attribute = HPI_COMPANDER_THRESHOLD;
+ hm.u.c.param2 = index;
hpi_send_recv(&hm, &hr);
+ *threshold0_01dB = hr.u.c.an_log_value[0];
- if (pw_attack)
- *pw_attack = (short)(hr.u.c.param1 & 0xFFFF);
- if (pw_decay)
- *pw_decay = (short)(hr.u.c.param2 & 0xFFFF);
- if (pw_ratio100)
- *pw_ratio100 = (short)(hr.u.c.param1 >> 16);
+ return hr.error;
+}
- if (pn_threshold0_01dB)
- *pn_threshold0_01dB = hr.u.c.an_log_value[0];
- if (pn_makeup_gain0_01dB)
- *pn_makeup_gain0_01dB = hr.u.c.an_log_value[1];
+u16 hpi_compander_set_ratio(const struct hpi_hsubsys *ph_subsys,
+ u32 h_control, u32 index, u32 ratio100)
+{
+ return hpi_control_param_set(ph_subsys, h_control,
+ HPI_COMPANDER_RATIO, ratio100, index);
+}
- return hr.error;
+u16 hpi_compander_get_ratio(const struct hpi_hsubsys *ph_subsys,
+ u32 h_control, u32 index, u32 *ratio100)
+{
+ return hpi_control_param_get(ph_subsys, h_control,
+ HPI_COMPANDER_RATIO, 0, index, ratio100, NULL);
}
u16 hpi_level_query_range(const struct hpi_hsubsys *ph_subsys, u32 h_control,
@@ -2157,6 +2252,7 @@ u16 hpi_level_query_range(const struct hpi_hsubsys *ph_subsys, u32 h_control,
{
struct hpi_message hm;
struct hpi_response hr;
+
hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL,
HPI_CONTROL_GET_STATE);
u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index);
@@ -2181,37 +2277,16 @@ u16 hpi_level_set_gain(const struct hpi_hsubsys *ph_subsys, u32 h_control,
short an_gain0_01dB[HPI_MAX_CHANNELS]
)
{
- struct hpi_message hm;
- struct hpi_response hr;
-
- hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL,
- HPI_CONTROL_SET_STATE);
- u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index);
- memcpy(hm.u.c.an_log_value, an_gain0_01dB,
- sizeof(short) * HPI_MAX_CHANNELS);
- hm.u.c.attribute = HPI_LEVEL_GAIN;
-
- hpi_send_recv(&hm, &hr);
-
- return hr.error;
+ return hpi_control_log_set2(h_control, HPI_LEVEL_GAIN,
+ an_gain0_01dB[0], an_gain0_01dB[1]);
}
u16 hpi_level_get_gain(const struct hpi_hsubsys *ph_subsys, u32 h_control,
short an_gain0_01dB[HPI_MAX_CHANNELS]
)
{
- struct hpi_message hm;
- struct hpi_response hr;
- hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL,
- HPI_CONTROL_GET_STATE);
- u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index);
- hm.u.c.attribute = HPI_LEVEL_GAIN;
-
- hpi_send_recv(&hm, &hr);
-
- memcpy(an_gain0_01dB, hr.u.c.an_log_value,
- sizeof(short) * HPI_MAX_CHANNELS);
- return hr.error;
+ return hpi_control_log_get2(ph_subsys, h_control, HPI_LEVEL_GAIN,
+ &an_gain0_01dB[0], &an_gain0_01dB[1]);
}
u16 hpi_meter_query_channels(const struct hpi_hsubsys *ph_subsys,
@@ -2413,6 +2488,7 @@ u16 hpi_parametricEQ__get_band(const struct hpi_hsubsys *ph_subsys,
{
struct hpi_message hm;
struct hpi_response hr;
+
hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL,
HPI_CONTROL_GET_STATE);
u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index);
@@ -2439,6 +2515,7 @@ u16 hpi_parametricEQ__set_band(const struct hpi_hsubsys *ph_subsys,
{
struct hpi_message hm;
struct hpi_response hr;
+
hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL,
HPI_CONTROL_SET_STATE);
u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index);
@@ -2460,6 +2537,7 @@ u16 hpi_parametricEQ__get_coeffs(const struct hpi_hsubsys *ph_subsys,
{
struct hpi_message hm;
struct hpi_response hr;
+
hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL,
HPI_CONTROL_GET_STATE);
u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index);
@@ -2623,8 +2701,8 @@ u16 hpi_tone_detector_get_frequency(const struct hpi_hsubsys *ph_subsys,
u16 hpi_tone_detector_get_state(const struct hpi_hsubsys *ph_subsys,
u32 h_control, u32 *state)
{
- return hpi_control_param_get(ph_subsys, h_control,
- HPI_TONEDETECTOR_STATE, 0, 0, (u32 *)state, NULL);
+ return hpi_control_param1_get(ph_subsys, h_control,
+ HPI_TONEDETECTOR_STATE, state);
}
u16 hpi_tone_detector_set_enable(const struct hpi_hsubsys *ph_subsys,
@@ -2637,8 +2715,8 @@ u16 hpi_tone_detector_set_enable(const struct hpi_hsubsys *ph_subsys,
u16 hpi_tone_detector_get_enable(const struct hpi_hsubsys *ph_subsys,
u32 h_control, u32 *enable)
{
- return hpi_control_param_get(ph_subsys, h_control, HPI_GENERIC_ENABLE,
- 0, 0, (u32 *)enable, NULL);
+ return hpi_control_param1_get(ph_subsys, h_control,
+ HPI_GENERIC_ENABLE, enable);
}
u16 hpi_tone_detector_set_event_enable(const struct hpi_hsubsys *ph_subsys,
@@ -2651,8 +2729,8 @@ u16 hpi_tone_detector_set_event_enable(const struct hpi_hsubsys *ph_subsys,
u16 hpi_tone_detector_get_event_enable(const struct hpi_hsubsys *ph_subsys,
u32 h_control, u32 *event_enable)
{
- return hpi_control_param_get(ph_subsys, h_control,
- HPI_GENERIC_EVENT_ENABLE, 0, 0, (u32 *)event_enable, NULL);
+ return hpi_control_param1_get(ph_subsys, h_control,
+ HPI_GENERIC_EVENT_ENABLE, event_enable);
}
u16 hpi_tone_detector_set_threshold(const struct hpi_hsubsys *ph_subsys,
@@ -2665,15 +2743,15 @@ u16 hpi_tone_detector_set_threshold(const struct hpi_hsubsys *ph_subsys,
u16 hpi_tone_detector_get_threshold(const struct hpi_hsubsys *ph_subsys,
u32 h_control, int *threshold)
{
- return hpi_control_param_get(ph_subsys, h_control,
- HPI_TONEDETECTOR_THRESHOLD, 0, 0, (u32 *)threshold, NULL);
+ return hpi_control_param1_get(ph_subsys, h_control,
+ HPI_TONEDETECTOR_THRESHOLD, (u32 *)threshold);
}
u16 hpi_silence_detector_get_state(const struct hpi_hsubsys *ph_subsys,
u32 h_control, u32 *state)
{
- return hpi_control_param_get(ph_subsys, h_control,
- HPI_SILENCEDETECTOR_STATE, 0, 0, (u32 *)state, NULL);
+ return hpi_control_param1_get(ph_subsys, h_control,
+ HPI_SILENCEDETECTOR_STATE, state);
}
u16 hpi_silence_detector_set_enable(const struct hpi_hsubsys *ph_subsys,
@@ -2686,50 +2764,50 @@ u16 hpi_silence_detector_set_enable(const struct hpi_hsubsys *ph_subsys,
u16 hpi_silence_detector_get_enable(const struct hpi_hsubsys *ph_subsys,
u32 h_control, u32 *enable)
{
- return hpi_control_param_get(ph_subsys, h_control, HPI_GENERIC_ENABLE,
- 0, 0, (u32 *)enable, NULL);
+ return hpi_control_param1_get(ph_subsys, h_control,
+ HPI_GENERIC_ENABLE, enable);
}
u16 hpi_silence_detector_set_event_enable(const struct hpi_hsubsys *ph_subsys,
u32 h_control, u32 event_enable)
{
return hpi_control_param_set(ph_subsys, h_control,
- HPI_GENERIC_EVENT_ENABLE, (u32)event_enable, 0);
+ HPI_GENERIC_EVENT_ENABLE, event_enable, 0);
}
u16 hpi_silence_detector_get_event_enable(const struct hpi_hsubsys *ph_subsys,
u32 h_control, u32 *event_enable)
{
- return hpi_control_param_get(ph_subsys, h_control,
- HPI_GENERIC_EVENT_ENABLE, 0, 0, (u32 *)event_enable, NULL);
+ return hpi_control_param1_get(ph_subsys, h_control,
+ HPI_GENERIC_EVENT_ENABLE, event_enable);
}
u16 hpi_silence_detector_set_delay(const struct hpi_hsubsys *ph_subsys,
u32 h_control, u32 delay)
{
return hpi_control_param_set(ph_subsys, h_control,
- HPI_SILENCEDETECTOR_DELAY, (u32)delay, 0);
+ HPI_SILENCEDETECTOR_DELAY, delay, 0);
}
u16 hpi_silence_detector_get_delay(const struct hpi_hsubsys *ph_subsys,
u32 h_control, u32 *delay)
{
- return hpi_control_param_get(ph_subsys, h_control,
- HPI_SILENCEDETECTOR_DELAY, 0, 0, (u32 *)delay, NULL);
+ return hpi_control_param1_get(ph_subsys, h_control,
+ HPI_SILENCEDETECTOR_DELAY, delay);
}
u16 hpi_silence_detector_set_threshold(const struct hpi_hsubsys *ph_subsys,
u32 h_control, int threshold)
{
return hpi_control_param_set(ph_subsys, h_control,
- HPI_SILENCEDETECTOR_THRESHOLD, (u32)threshold, 0);
+ HPI_SILENCEDETECTOR_THRESHOLD, threshold, 0);
}
u16 hpi_silence_detector_get_threshold(const struct hpi_hsubsys *ph_subsys,
u32 h_control, int *threshold)
{
- return hpi_control_param_get(ph_subsys, h_control,
- HPI_SILENCEDETECTOR_THRESHOLD, 0, 0, (u32 *)threshold, NULL);
+ return hpi_control_param1_get(ph_subsys, h_control,
+ HPI_SILENCEDETECTOR_THRESHOLD, (u32 *)threshold);
}
u16 hpi_tuner_query_band(const struct hpi_hsubsys *ph_subsys,
@@ -2822,6 +2900,7 @@ u16 hpi_tuner_getRF_level(const struct hpi_hsubsys *ph_subsys, u32 h_control,
{
struct hpi_message hm;
struct hpi_response hr;
+
hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL,
HPI_CONTROL_GET_STATE);
u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index);
@@ -2838,6 +2917,7 @@ u16 hpi_tuner_get_rawRF_level(const struct hpi_hsubsys *ph_subsys,
{
struct hpi_message hm;
struct hpi_response hr;
+
hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL,
HPI_CONTROL_GET_STATE);
u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index);
@@ -2894,14 +2974,14 @@ u16 hpi_tuner_get_program(const struct hpi_hsubsys *ph_subsys, u32 h_control,
u16 hpi_tuner_get_hd_radio_dsp_version(const struct hpi_hsubsys *ph_subsys,
u32 h_control, char *psz_dsp_version, const u32 string_size)
{
- return hpi_control_get_string(ph_subsys, h_control,
+ return hpi_control_get_string(h_control,
HPI_TUNER_HDRADIO_DSP_VERSION, psz_dsp_version, string_size);
}
u16 hpi_tuner_get_hd_radio_sdk_version(const struct hpi_hsubsys *ph_subsys,
u32 h_control, char *psz_sdk_version, const u32 string_size)
{
- return hpi_control_get_string(ph_subsys, h_control,
+ return hpi_control_get_string(h_control,
HPI_TUNER_HDRADIO_SDK_VERSION, psz_sdk_version, string_size);
}
@@ -2942,15 +3022,15 @@ u16 hpi_tuner_get_mode(const struct hpi_hsubsys *ph_subsys, u32 h_control,
u16 hpi_tuner_get_hd_radio_signal_quality(const struct hpi_hsubsys *ph_subsys,
u32 h_control, u32 *pquality)
{
- return hpi_control_param_get(ph_subsys, h_control,
- HPI_TUNER_HDRADIO_SIGNAL_QUALITY, 0, 0, pquality, NULL);
+ return hpi_control_param1_get(ph_subsys, h_control,
+ HPI_TUNER_HDRADIO_SIGNAL_QUALITY, pquality);
}
u16 hpi_tuner_get_hd_radio_signal_blend(const struct hpi_hsubsys *ph_subsys,
u32 h_control, u32 *pblend)
{
- return hpi_control_param_get(ph_subsys, h_control,
- HPI_TUNER_HDRADIO_BLEND, 0, 0, pblend, NULL);
+ return hpi_control_param1_get(ph_subsys, h_control,
+ HPI_TUNER_HDRADIO_BLEND, pblend);
}
u16 hpi_tuner_set_hd_radio_signal_blend(const struct hpi_hsubsys *ph_subsys,
@@ -2965,6 +3045,7 @@ u16 hpi_tuner_getRDS(const struct hpi_hsubsys *ph_subsys, u32 h_control,
{
struct hpi_message hm;
struct hpi_response hr;
+
hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL,
HPI_CONTROL_GET_STATE);
u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index);
@@ -2981,43 +3062,43 @@ u16 hpi_tuner_getRDS(const struct hpi_hsubsys *ph_subsys, u32 h_control,
u16 HPI_PAD__get_channel_name(const struct hpi_hsubsys *ph_subsys,
u32 h_control, char *psz_string, const u32 data_length)
{
- return hpi_control_get_string(ph_subsys, h_control,
- HPI_PAD_CHANNEL_NAME, psz_string, data_length);
+ return hpi_control_get_string(h_control, HPI_PAD_CHANNEL_NAME,
+ psz_string, data_length);
}
u16 HPI_PAD__get_artist(const struct hpi_hsubsys *ph_subsys, u32 h_control,
char *psz_string, const u32 data_length)
{
- return hpi_control_get_string(ph_subsys, h_control, HPI_PAD_ARTIST,
- psz_string, data_length);
+ return hpi_control_get_string(h_control, HPI_PAD_ARTIST, psz_string,
+ data_length);
}
u16 HPI_PAD__get_title(const struct hpi_hsubsys *ph_subsys, u32 h_control,
char *psz_string, const u32 data_length)
{
- return hpi_control_get_string(ph_subsys, h_control, HPI_PAD_TITLE,
- psz_string, data_length);
+ return hpi_control_get_string(h_control, HPI_PAD_TITLE, psz_string,
+ data_length);
}
u16 HPI_PAD__get_comment(const struct hpi_hsubsys *ph_subsys, u32 h_control,
char *psz_string, const u32 data_length)
{
- return hpi_control_get_string(ph_subsys, h_control, HPI_PAD_COMMENT,
- psz_string, data_length);
+ return hpi_control_get_string(h_control, HPI_PAD_COMMENT, psz_string,
+ data_length);
}
u16 HPI_PAD__get_program_type(const struct hpi_hsubsys *ph_subsys,
u32 h_control, u32 *ppTY)
{
- return hpi_control_param_get(ph_subsys, h_control,
- HPI_PAD_PROGRAM_TYPE, 0, 0, ppTY, NULL);
+ return hpi_control_param1_get(ph_subsys, h_control,
+ HPI_PAD_PROGRAM_TYPE, ppTY);
}
u16 HPI_PAD__get_rdsPI(const struct hpi_hsubsys *ph_subsys, u32 h_control,
u32 *ppI)
{
- return hpi_control_param_get(ph_subsys, h_control, HPI_PAD_PROGRAM_ID,
- 0, 0, ppI, NULL);
+ return hpi_control_param1_get(ph_subsys, h_control,
+ HPI_PAD_PROGRAM_ID, ppI);
}
u16 hpi_volume_query_channels(const struct hpi_hsubsys *ph_subsys,
@@ -3031,36 +3112,16 @@ u16 hpi_volume_set_gain(const struct hpi_hsubsys *ph_subsys, u32 h_control,
short an_log_gain[HPI_MAX_CHANNELS]
)
{
- struct hpi_message hm;
- struct hpi_response hr;
- hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL,
- HPI_CONTROL_SET_STATE);
- u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index);
- memcpy(hm.u.c.an_log_value, an_log_gain,
- sizeof(short) * HPI_MAX_CHANNELS);
- hm.u.c.attribute = HPI_VOLUME_GAIN;
-
- hpi_send_recv(&hm, &hr);
-
- return hr.error;
+ return hpi_control_log_set2(h_control, HPI_VOLUME_GAIN,
+ an_log_gain[0], an_log_gain[1]);
}
u16 hpi_volume_get_gain(const struct hpi_hsubsys *ph_subsys, u32 h_control,
short an_log_gain[HPI_MAX_CHANNELS]
)
{
- struct hpi_message hm;
- struct hpi_response hr;
- hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL,
- HPI_CONTROL_GET_STATE);
- u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index);
- hm.u.c.attribute = HPI_VOLUME_GAIN;
-
- hpi_send_recv(&hm, &hr);
-
- memcpy(an_log_gain, hr.u.c.an_log_value,
- sizeof(short) * HPI_MAX_CHANNELS);
- return hr.error;
+ return hpi_control_log_get2(ph_subsys, h_control, HPI_VOLUME_GAIN,
+ &an_log_gain[0], &an_log_gain[1]);
}
u16 hpi_volume_query_range(const struct hpi_hsubsys *ph_subsys, u32 h_control,
@@ -3068,6 +3129,7 @@ u16 hpi_volume_query_range(const struct hpi_hsubsys *ph_subsys, u32 h_control,
{
struct hpi_message hm;
struct hpi_response hr;
+
hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL,
HPI_CONTROL_GET_STATE);
u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index);
@@ -3094,6 +3156,7 @@ u16 hpi_volume_auto_fade_profile(const struct hpi_hsubsys *ph_subsys,
{
struct hpi_message hm;
struct hpi_response hr;
+
hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL,
HPI_CONTROL_SET_STATE);
u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index);
@@ -3170,43 +3233,42 @@ static size_t entity_type_to_size[LAST_ENTITY_TYPE] = {
6 * sizeof(char),
};
-inline size_t hpi_entity_size(struct hpi_entity *entity_ptr)
+static inline size_t hpi_entity_size(struct hpi_entity *entity_ptr)
{
return entity_ptr->header.size;
}
-inline size_t hpi_entity_header_size(struct hpi_entity *entity_ptr)
+static inline size_t hpi_entity_header_size(struct hpi_entity *entity_ptr)
{
return sizeof(entity_ptr->header);
}
-inline size_t hpi_entity_value_size(struct hpi_entity *entity_ptr)
+static inline size_t hpi_entity_value_size(struct hpi_entity *entity_ptr)
{
return hpi_entity_size(entity_ptr) -
hpi_entity_header_size(entity_ptr);
}
-inline size_t hpi_entity_item_count(struct hpi_entity *entity_ptr)
+static inline size_t hpi_entity_item_count(struct hpi_entity *entity_ptr)
{
return hpi_entity_value_size(entity_ptr) /
entity_type_to_size[entity_ptr->header.type];
}
-inline struct hpi_entity *hpi_entity_ptr_to_next(struct hpi_entity
+static inline struct hpi_entity *hpi_entity_ptr_to_next(struct hpi_entity
*entity_ptr)
{
- return (void *)(((uint8_t *) entity_ptr) +
- hpi_entity_size(entity_ptr));
+ return (void *)(((u8 *)entity_ptr) + hpi_entity_size(entity_ptr));
}
-inline u16 hpi_entity_check_type(const enum e_entity_type t)
+static inline u16 hpi_entity_check_type(const enum e_entity_type t)
{
if (t >= 0 && t < STR_TYPE_FIELD_MAX)
return 0;
return HPI_ERROR_ENTITY_TYPE_INVALID;
}
-inline u16 hpi_entity_check_role(const enum e_entity_role r)
+static inline u16 hpi_entity_check_role(const enum e_entity_role r)
{
if (r >= 0 && r < STR_ROLE_FIELD_MAX)
return 0;
@@ -3624,6 +3686,7 @@ u16 hpi_async_event_wait(const struct hpi_hsubsys *ph_subsys, u32 h_async,
u16 maximum_events, struct hpi_async_event *p_events,
u16 *pw_number_returned)
{
+
return 0;
}
diff --git a/sound/pci/asihpi/hpimsgx.c b/sound/pci/asihpi/hpimsgx.c
index 2ee90dc3d89..f01ab964f60 100644
--- a/sound/pci/asihpi/hpimsgx.c
+++ b/sound/pci/asihpi/hpimsgx.c
@@ -741,7 +741,7 @@ static void HPIMSGX__reset(u16 adapter_index)
hpi_init_response(&hr, HPI_OBJ_SUBSYSTEM,
HPI_SUBSYS_FIND_ADAPTERS, 0);
memcpy(&gRESP_HPI_SUBSYS_FIND_ADAPTERS, &hr,
- sizeof(&gRESP_HPI_SUBSYS_FIND_ADAPTERS));
+ sizeof(gRESP_HPI_SUBSYS_FIND_ADAPTERS));
for (adapter = 0; adapter < HPI_MAX_ADAPTERS; adapter++) {
diff --git a/sound/pci/asihpi/hpioctl.c b/sound/pci/asihpi/hpioctl.c
index 7396ac54e99..62895a719fc 100644
--- a/sound/pci/asihpi/hpioctl.c
+++ b/sound/pci/asihpi/hpioctl.c
@@ -121,11 +121,17 @@ long asihpi_hpi_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
phpi_ioctl_data = (struct hpi_ioctl_linux __user *)arg;
/* Read the message and response pointers from user space. */
- get_user(puhm, &phpi_ioctl_data->phm);
- get_user(puhr, &phpi_ioctl_data->phr);
+ if (get_user(puhm, &phpi_ioctl_data->phm) ||
+ get_user(puhr, &phpi_ioctl_data->phr)) {
+ err = -EFAULT;
+ goto out;
+ }
/* Now read the message size and data from user space. */
- get_user(hm->h.size, (u16 __user *)puhm);
+ if (get_user(hm->h.size, (u16 __user *)puhm)) {
+ err = -EFAULT;
+ goto out;
+ }
if (hm->h.size > sizeof(*hm))
hm->h.size = sizeof(*hm);
@@ -138,7 +144,10 @@ long asihpi_hpi_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
goto out;
}
- get_user(res_max_size, (u16 __user *)puhr);
+ if (get_user(res_max_size, (u16 __user *)puhr)) {
+ err = -EFAULT;
+ goto out;
+ }
/* printk(KERN_INFO "user response size %d\n", res_max_size); */
if (res_max_size < sizeof(struct hpi_response_header)) {
HPI_DEBUG_LOG(WARNING, "small res size %d\n", res_max_size);
@@ -464,9 +473,7 @@ void __init asihpi_init(void)
memset(adapters, 0, sizeof(adapters));
- printk(KERN_INFO "ASIHPI driver %d.%02d.%02d\n",
- HPI_VER_MAJOR(HPI_VER), HPI_VER_MINOR(HPI_VER),
- HPI_VER_RELEASE(HPI_VER));
+ printk(KERN_INFO "ASIHPI driver " HPI_VER_STRING "\n");
hpi_init_message_response(&hm, &hr, HPI_OBJ_SUBSYSTEM,
HPI_SUBSYS_DRIVER_LOAD);
diff --git a/sound/pci/echoaudio/echoaudio.c b/sound/pci/echoaudio/echoaudio.c
index 668a5ec0449..20763dd03fa 100644
--- a/sound/pci/echoaudio/echoaudio.c
+++ b/sound/pci/echoaudio/echoaudio.c
@@ -2250,6 +2250,8 @@ static int snd_echo_resume(struct pci_dev *pci)
DE_INIT(("resume start\n"));
pci_restore_state(pci);
commpage_bak = kmalloc(sizeof(struct echoaudio), GFP_KERNEL);
+ if (commpage_bak == NULL)
+ return -ENOMEM;
commpage = chip->comm_page;
memcpy(commpage_bak, commpage, sizeof(struct comm_page));
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c
index ba2098d20cc..a7802b99436 100644
--- a/sound/pci/hda/hda_codec.c
+++ b/sound/pci/hda/hda_codec.c
@@ -396,15 +396,18 @@ int snd_hda_get_connections(struct hda_codec *codec, hda_nid_t nid,
}
for (n = prev_nid + 1; n <= val; n++) {
if (conns >= max_conns) {
- snd_printk(KERN_ERR
- "Too many connections\n");
+ snd_printk(KERN_ERR "hda_codec: "
+ "Too many connections %d for NID 0x%x\n",
+ conns, nid);
return -EINVAL;
}
conn_list[conns++] = n;
}
} else {
if (conns >= max_conns) {
- snd_printk(KERN_ERR "Too many connections\n");
+ snd_printk(KERN_ERR "hda_codec: "
+ "Too many connections %d for NID 0x%x\n",
+ conns, nid);
return -EINVAL;
}
conn_list[conns++] = val;
@@ -730,15 +733,17 @@ static void /*__devinit*/ setup_fg_nodes(struct hda_codec *codec)
total_nodes = snd_hda_get_sub_nodes(codec, AC_NODE_ROOT, &nid);
for (i = 0; i < total_nodes; i++, nid++) {
function_id = snd_hda_param_read(codec, nid,
- AC_PAR_FUNCTION_TYPE) & 0xff;
- switch (function_id) {
+ AC_PAR_FUNCTION_TYPE);
+ switch (function_id & 0xff) {
case AC_GRP_AUDIO_FUNCTION:
codec->afg = nid;
- codec->function_id = function_id;
+ codec->afg_function_id = function_id & 0xff;
+ codec->afg_unsol = (function_id >> 8) & 1;
break;
case AC_GRP_MODEM_FUNCTION:
codec->mfg = nid;
- codec->function_id = function_id;
+ codec->mfg_function_id = function_id & 0xff;
+ codec->mfg_unsol = (function_id >> 8) & 1;
break;
default:
break;
@@ -1565,6 +1570,17 @@ void snd_hda_codec_resume_amp(struct hda_codec *codec)
EXPORT_SYMBOL_HDA(snd_hda_codec_resume_amp);
#endif /* SND_HDA_NEEDS_RESUME */
+static u32 get_amp_max_value(struct hda_codec *codec, hda_nid_t nid, int dir,
+ unsigned int ofs)
+{
+ u32 caps = query_amp_caps(codec, nid, dir);
+ /* get num steps */
+ caps = (caps & AC_AMPCAP_NUM_STEPS) >> AC_AMPCAP_NUM_STEPS_SHIFT;
+ if (ofs < caps)
+ caps -= ofs;
+ return caps;
+}
+
/**
* snd_hda_mixer_amp_volume_info - Info callback for a standard AMP mixer
*
@@ -1579,23 +1595,17 @@ int snd_hda_mixer_amp_volume_info(struct snd_kcontrol *kcontrol,
u8 chs = get_amp_channels(kcontrol);
int dir = get_amp_direction(kcontrol);
unsigned int ofs = get_amp_offset(kcontrol);
- u32 caps;
- caps = query_amp_caps(codec, nid, dir);
- /* num steps */
- caps = (caps & AC_AMPCAP_NUM_STEPS) >> AC_AMPCAP_NUM_STEPS_SHIFT;
- if (!caps) {
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->count = chs == 3 ? 2 : 1;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = get_amp_max_value(codec, nid, dir, ofs);
+ if (!uinfo->value.integer.max) {
printk(KERN_WARNING "hda_codec: "
"num_steps = 0 for NID=0x%x (ctl = %s)\n", nid,
kcontrol->id.name);
return -EINVAL;
}
- if (ofs < caps)
- caps -= ofs;
- uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
- uinfo->count = chs == 3 ? 2 : 1;
- uinfo->value.integer.min = 0;
- uinfo->value.integer.max = caps;
return 0;
}
EXPORT_SYMBOL_HDA(snd_hda_mixer_amp_volume_info);
@@ -1620,8 +1630,14 @@ update_amp_value(struct hda_codec *codec, hda_nid_t nid,
int ch, int dir, int idx, unsigned int ofs,
unsigned int val)
{
+ unsigned int maxval;
+
if (val > 0)
val += ofs;
+ /* ofs = 0: raw max value */
+ maxval = get_amp_max_value(codec, nid, dir, 0);
+ if (val > maxval)
+ val = maxval;
return snd_hda_codec_amp_update(codec, nid, ch, dir, idx,
HDA_AMP_VOLMASK, val);
}
@@ -2999,26 +3015,31 @@ struct hda_rate_tbl {
unsigned int hda_fmt;
};
+/* rate = base * mult / div */
+#define HDA_RATE(base, mult, div) \
+ (AC_FMT_BASE_##base##K | (((mult) - 1) << AC_FMT_MULT_SHIFT) | \
+ (((div) - 1) << AC_FMT_DIV_SHIFT))
+
static struct hda_rate_tbl rate_bits[] = {
/* rate in Hz, ALSA rate bitmask, HDA format value */
/* autodetected value used in snd_hda_query_supported_pcm */
- { 8000, SNDRV_PCM_RATE_8000, 0x0500 }, /* 1/6 x 48 */
- { 11025, SNDRV_PCM_RATE_11025, 0x4300 }, /* 1/4 x 44 */
- { 16000, SNDRV_PCM_RATE_16000, 0x0200 }, /* 1/3 x 48 */
- { 22050, SNDRV_PCM_RATE_22050, 0x4100 }, /* 1/2 x 44 */
- { 32000, SNDRV_PCM_RATE_32000, 0x0a00 }, /* 2/3 x 48 */
- { 44100, SNDRV_PCM_RATE_44100, 0x4000 }, /* 44 */
- { 48000, SNDRV_PCM_RATE_48000, 0x0000 }, /* 48 */
- { 88200, SNDRV_PCM_RATE_88200, 0x4800 }, /* 2 x 44 */
- { 96000, SNDRV_PCM_RATE_96000, 0x0800 }, /* 2 x 48 */
- { 176400, SNDRV_PCM_RATE_176400, 0x5800 },/* 4 x 44 */
- { 192000, SNDRV_PCM_RATE_192000, 0x1800 }, /* 4 x 48 */
+ { 8000, SNDRV_PCM_RATE_8000, HDA_RATE(48, 1, 6) },
+ { 11025, SNDRV_PCM_RATE_11025, HDA_RATE(44, 1, 4) },
+ { 16000, SNDRV_PCM_RATE_16000, HDA_RATE(48, 1, 3) },
+ { 22050, SNDRV_PCM_RATE_22050, HDA_RATE(44, 1, 2) },
+ { 32000, SNDRV_PCM_RATE_32000, HDA_RATE(48, 2, 3) },
+ { 44100, SNDRV_PCM_RATE_44100, HDA_RATE(44, 1, 1) },
+ { 48000, SNDRV_PCM_RATE_48000, HDA_RATE(48, 1, 1) },
+ { 88200, SNDRV_PCM_RATE_88200, HDA_RATE(44, 2, 1) },
+ { 96000, SNDRV_PCM_RATE_96000, HDA_RATE(48, 2, 1) },
+ { 176400, SNDRV_PCM_RATE_176400, HDA_RATE(44, 4, 1) },
+ { 192000, SNDRV_PCM_RATE_192000, HDA_RATE(48, 4, 1) },
#define AC_PAR_PCM_RATE_BITS 11
/* up to bits 10, 384kHZ isn't supported properly */
/* not autodetected value */
- { 9600, SNDRV_PCM_RATE_KNOT, 0x0400 }, /* 1/5 x 48 */
+ { 9600, SNDRV_PCM_RATE_KNOT, HDA_RATE(48, 1, 5) },
{ 0 } /* terminator */
};
@@ -3037,7 +3058,8 @@ static struct hda_rate_tbl rate_bits[] = {
unsigned int snd_hda_calc_stream_format(unsigned int rate,
unsigned int channels,
unsigned int format,
- unsigned int maxbps)
+ unsigned int maxbps,
+ unsigned short spdif_ctls)
{
int i;
unsigned int val = 0;
@@ -3060,20 +3082,20 @@ unsigned int snd_hda_calc_stream_format(unsigned int rate,
switch (snd_pcm_format_width(format)) {
case 8:
- val |= 0x00;
+ val |= AC_FMT_BITS_8;
break;
case 16:
- val |= 0x10;
+ val |= AC_FMT_BITS_16;
break;
case 20:
case 24:
case 32:
if (maxbps >= 32 || format == SNDRV_PCM_FORMAT_FLOAT_LE)
- val |= 0x40;
+ val |= AC_FMT_BITS_32;
else if (maxbps >= 24)
- val |= 0x30;
+ val |= AC_FMT_BITS_24;
else
- val |= 0x20;
+ val |= AC_FMT_BITS_20;
break;
default:
snd_printdd("invalid format width %d\n",
@@ -3081,6 +3103,9 @@ unsigned int snd_hda_calc_stream_format(unsigned int rate,
return 0;
}
+ if (spdif_ctls & AC_DIG1_NONAUDIO)
+ val |= AC_FMT_TYPE_NON_PCM;
+
return val;
}
EXPORT_SYMBOL_HDA(snd_hda_calc_stream_format);
diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h
index 5991d14e1ec..0328cf55cdb 100644
--- a/sound/pci/hda/hda_codec.h
+++ b/sound/pci/hda/hda_codec.h
@@ -224,6 +224,27 @@ enum {
/* Input converter SDI select */
#define AC_SDI_SELECT (0xf<<0)
+/* stream format id */
+#define AC_FMT_CHAN_SHIFT 0
+#define AC_FMT_CHAN_MASK (0x0f << 0)
+#define AC_FMT_BITS_SHIFT 4
+#define AC_FMT_BITS_MASK (7 << 4)
+#define AC_FMT_BITS_8 (0 << 4)
+#define AC_FMT_BITS_16 (1 << 4)
+#define AC_FMT_BITS_20 (2 << 4)
+#define AC_FMT_BITS_24 (3 << 4)
+#define AC_FMT_BITS_32 (4 << 4)
+#define AC_FMT_DIV_SHIFT 8
+#define AC_FMT_DIV_MASK (7 << 8)
+#define AC_FMT_MULT_SHIFT 11
+#define AC_FMT_MULT_MASK (7 << 11)
+#define AC_FMT_BASE_SHIFT 14
+#define AC_FMT_BASE_48K (0 << 14)
+#define AC_FMT_BASE_44K (1 << 14)
+#define AC_FMT_TYPE_SHIFT 15
+#define AC_FMT_TYPE_PCM (0 << 15)
+#define AC_FMT_TYPE_NON_PCM (1 << 15)
+
/* Unsolicited response control */
#define AC_UNSOL_TAG (0x3f<<0)
#define AC_UNSOL_ENABLED (1<<7)
@@ -364,6 +385,9 @@ enum {
#define AC_DIG2_CC (0x7f<<0)
/* Pin widget control - 8bit */
+#define AC_PINCTL_EPT (0x3<<0)
+#define AC_PINCTL_EPT_NATIVE 0
+#define AC_PINCTL_EPT_HBR 3
#define AC_PINCTL_VREFEN (0x7<<0)
#define AC_PINCTL_VREF_HIZ 0 /* Hi-Z */
#define AC_PINCTL_VREF_50 1 /* 50% */
@@ -760,7 +784,10 @@ struct hda_codec {
hda_nid_t mfg; /* MFG node id */
/* ids */
- u32 function_id;
+ u8 afg_function_id;
+ u8 mfg_function_id;
+ u8 afg_unsol;
+ u8 mfg_unsol;
u32 vendor_id;
u32 subsystem_id;
u32 revision_id;
@@ -928,7 +955,8 @@ void snd_hda_codec_cleanup_stream(struct hda_codec *codec, hda_nid_t nid);
unsigned int snd_hda_calc_stream_format(unsigned int rate,
unsigned int channels,
unsigned int format,
- unsigned int maxbps);
+ unsigned int maxbps,
+ unsigned short spdif_ctls);
int snd_hda_is_supported_format(struct hda_codec *codec, hda_nid_t nid,
unsigned int format);
diff --git a/sound/pci/hda/hda_hwdep.c b/sound/pci/hda/hda_hwdep.c
index a1fc83753cc..bf3ced51e0f 100644
--- a/sound/pci/hda/hda_hwdep.c
+++ b/sound/pci/hda/hda_hwdep.c
@@ -649,7 +649,9 @@ static void parse_codec_mode(char *buf, struct hda_bus *bus,
*codecp = NULL;
if (sscanf(buf, "%i %i %i", &vendorid, &subid, &caddr) == 3) {
list_for_each_entry(codec, &bus->codec_list, list) {
- if (codec->addr == caddr) {
+ if (codec->vendor_id == vendorid &&
+ codec->subsystem_id == subid &&
+ codec->addr == caddr) {
*codecp = codec;
break;
}
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c
index 1df25cf5ce3..66d420212d9 100644
--- a/sound/pci/hda/hda_intel.c
+++ b/sound/pci/hda/hda_intel.c
@@ -1653,7 +1653,8 @@ static int azx_pcm_prepare(struct snd_pcm_substream *substream)
format_val = snd_hda_calc_stream_format(runtime->rate,
runtime->channels,
runtime->format,
- hinfo->maxbps);
+ hinfo->maxbps,
+ apcm->codec->spdif_ctls);
if (!format_val) {
snd_printk(KERN_ERR SFX
"invalid format_val, rate=%d, ch=%d, format=%d\n",
@@ -1960,7 +1961,7 @@ static void azx_irq_pending_work(struct work_struct *work)
spin_unlock_irq(&chip->reg_lock);
if (!pending)
return;
- cond_resched();
+ msleep(1);
}
}
diff --git a/sound/pci/hda/hda_proc.c b/sound/pci/hda/hda_proc.c
index f97d35de66c..f025200f2a6 100644
--- a/sound/pci/hda/hda_proc.c
+++ b/sound/pci/hda/hda_proc.c
@@ -557,7 +557,12 @@ static void print_codec_info(struct snd_info_entry *entry,
else
snd_iprintf(buffer, "Not Set\n");
snd_iprintf(buffer, "Address: %d\n", codec->addr);
- snd_iprintf(buffer, "Function Id: 0x%x\n", codec->function_id);
+ if (codec->afg)
+ snd_iprintf(buffer, "AFG Function Id: 0x%x (unsol %u)\n",
+ codec->afg_function_id, codec->afg_unsol);
+ if (codec->mfg)
+ snd_iprintf(buffer, "MFG Function Id: 0x%x (unsol %u)\n",
+ codec->mfg_function_id, codec->mfg_unsol);
snd_iprintf(buffer, "Vendor Id: 0x%08x\n", codec->vendor_id);
snd_iprintf(buffer, "Subsystem Id: 0x%08x\n", codec->subsystem_id);
snd_iprintf(buffer, "Revision Id: 0x%x\n", codec->revision_id);
diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c
index afbe314a5bf..b697fd2a6f8 100644
--- a/sound/pci/hda/patch_analog.c
+++ b/sound/pci/hda/patch_analog.c
@@ -3662,7 +3662,12 @@ static int patch_ad1984(struct hda_codec *codec)
codec->patch_ops.build_pcms = ad1984_build_pcms;
break;
case AD1984_THINKPAD:
- spec->multiout.dig_out_nid = AD1884_SPDIF_OUT;
+ if (codec->subsystem_id == 0x17aa20fb) {
+ /* Thinpad X300 does not have the ability to do SPDIF,
+ or attach to docking station to use SPDIF */
+ spec->multiout.dig_out_nid = 0;
+ } else
+ spec->multiout.dig_out_nid = AD1884_SPDIF_OUT;
spec->input_mux = &ad1984_thinkpad_capture_source;
spec->mixers[0] = ad1984_thinkpad_mixers;
spec->init_verbs[spec->num_init_verbs++] = ad1984_thinkpad_init_verbs;
diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c
index 2bf2cb5da95..df8b19b1730 100644
--- a/sound/pci/hda/patch_conexant.c
+++ b/sound/pci/hda/patch_conexant.c
@@ -131,6 +131,8 @@ struct conexant_spec {
unsigned int dc_enable;
unsigned int dc_input_bias; /* offset into cxt5066_olpc_dc_bias */
unsigned int mic_boost; /* offset into cxt5066_analog_mic_boost */
+
+ unsigned int beep_amp;
};
static int conexant_playback_pcm_open(struct hda_pcm_stream *hinfo,
@@ -515,6 +517,15 @@ static struct snd_kcontrol_new cxt_capture_mixers[] = {
{}
};
+#ifdef CONFIG_SND_HDA_INPUT_BEEP
+/* additional beep mixers; the actual parameters are overwritten at build */
+static struct snd_kcontrol_new cxt_beep_mixer[] = {
+ HDA_CODEC_VOLUME_MONO("Beep Playback Volume", 0, 1, 0, HDA_OUTPUT),
+ HDA_CODEC_MUTE_BEEP_MONO("Beep Playback Switch", 0, 1, 0, HDA_OUTPUT),
+ { } /* end */
+};
+#endif
+
static const char *slave_vols[] = {
"Headphone Playback Volume",
"Speaker Playback Volume",
@@ -580,16 +591,52 @@ static int conexant_build_controls(struct hda_codec *codec)
return err;
}
+#ifdef CONFIG_SND_HDA_INPUT_BEEP
+ /* create beep controls if needed */
+ if (spec->beep_amp) {
+ struct snd_kcontrol_new *knew;
+ for (knew = cxt_beep_mixer; knew->name; knew++) {
+ struct snd_kcontrol *kctl;
+ kctl = snd_ctl_new1(knew, codec);
+ if (!kctl)
+ return -ENOMEM;
+ kctl->private_value = spec->beep_amp;
+ err = snd_hda_ctl_add(codec, 0, kctl);
+ if (err < 0)
+ return err;
+ }
+ }
+#endif
+
+ return 0;
+}
+
+#ifdef CONFIG_SND_HDA_POWER_SAVE
+static int conexant_suspend(struct hda_codec *codec, pm_message_t state)
+{
+ snd_hda_shutup_pins(codec);
return 0;
}
+#endif
static struct hda_codec_ops conexant_patch_ops = {
.build_controls = conexant_build_controls,
.build_pcms = conexant_build_pcms,
.init = conexant_init,
.free = conexant_free,
+#ifdef CONFIG_SND_HDA_POWER_SAVE
+ .suspend = conexant_suspend,
+#endif
+ .reboot_notify = snd_hda_shutup_pins,
};
+#ifdef CONFIG_SND_HDA_INPUT_BEEP
+#define set_beep_amp(spec, nid, idx, dir) \
+ ((spec)->beep_amp = HDA_COMPOSE_AMP_VAL(nid, 1, idx, dir))
+#else
+#define set_beep_amp(spec, nid, idx, dir) /* NOP */
+#endif
+
/*
* EAPD control
* the private value = nid | (invert << 8)
@@ -1130,9 +1177,10 @@ static int patch_cxt5045(struct hda_codec *codec)
spec->num_init_verbs = 1;
spec->init_verbs[0] = cxt5045_init_verbs;
spec->spdif_route = 0;
- spec->num_channel_mode = ARRAY_SIZE(cxt5045_modes),
- spec->channel_mode = cxt5045_modes,
+ spec->num_channel_mode = ARRAY_SIZE(cxt5045_modes);
+ spec->channel_mode = cxt5045_modes;
+ set_beep_amp(spec, 0x16, 0, 1);
codec->patch_ops = conexant_patch_ops;
@@ -1211,6 +1259,9 @@ static int patch_cxt5045(struct hda_codec *codec)
break;
}
+ if (spec->beep_amp)
+ snd_hda_attach_beep_device(codec, spec->beep_amp);
+
return 0;
}
@@ -1632,6 +1683,11 @@ static void cxt5051_update_speaker(struct hda_codec *codec)
pinctl = (!spec->hp_present && spec->cur_eapd) ? PIN_OUT : 0;
snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
pinctl);
+ /* on ideapad there is an aditional speaker (subwoofer) to mute */
+ if (spec->ideapad)
+ snd_hda_codec_write(codec, 0x1b, 0,
+ AC_VERB_SET_PIN_WIDGET_CONTROL,
+ pinctl);
}
/* turn on/off EAPD (+ mute HP) as a master switch */
@@ -1888,6 +1944,13 @@ static void cxt5051_init_mic_port(struct hda_codec *codec, hda_nid_t nid,
#endif
}
+static struct hda_verb cxt5051_ideapad_init_verbs[] = {
+ /* Subwoofer */
+ {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+ {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
+ { } /* end */
+};
+
/* initialize jack-sensing, too */
static int cxt5051_init(struct hda_codec *codec)
{
@@ -1917,6 +1980,7 @@ enum {
CXT5051_LENOVO_X200, /* Lenovo X200 laptop, also used for Advanced Mini Dock 250410 */
CXT5051_F700, /* HP Compaq Presario F700 */
CXT5051_TOSHIBA, /* Toshiba M300 & co */
+ CXT5051_IDEAPAD, /* Lenovo IdeaPad Y430 */
CXT5051_MODELS
};
@@ -1927,6 +1991,7 @@ static const char *cxt5051_models[CXT5051_MODELS] = {
[CXT5051_LENOVO_X200] = "lenovo-x200",
[CXT5051_F700] = "hp-700",
[CXT5051_TOSHIBA] = "toshiba",
+ [CXT5051_IDEAPAD] = "ideapad",
};
static struct snd_pci_quirk cxt5051_cfg_tbl[] = {
@@ -1938,6 +2003,7 @@ static struct snd_pci_quirk cxt5051_cfg_tbl[] = {
CXT5051_LAPTOP),
SND_PCI_QUIRK(0x14f1, 0x5051, "HP Spartan 1.1", CXT5051_HP),
SND_PCI_QUIRK(0x17aa, 0x20f2, "Lenovo X200", CXT5051_LENOVO_X200),
+ SND_PCI_QUIRK(0x17aa, 0x3a0d, "Lenovo IdeaPad", CXT5051_IDEAPAD),
{}
};
@@ -1972,6 +2038,8 @@ static int patch_cxt5051(struct hda_codec *codec)
spec->cur_adc = 0;
spec->cur_adc_idx = 0;
+ set_beep_amp(spec, 0x13, 0, HDA_OUTPUT);
+
codec->patch_ops.unsol_event = cxt5051_hp_unsol_event;
board_config = snd_hda_check_board_config(codec, CXT5051_MODELS,
@@ -1989,6 +2057,10 @@ static int patch_cxt5051(struct hda_codec *codec)
break;
case CXT5051_LENOVO_X200:
spec->init_verbs[0] = cxt5051_lenovo_x200_init_verbs;
+ /* Thinkpad X301 does not have S/PDIF wired and no ability
+ to use a docking station. */
+ if (codec->subsystem_id == 0x17aa211f)
+ spec->multiout.dig_out_nid = 0;
break;
case CXT5051_F700:
spec->init_verbs[0] = cxt5051_f700_init_verbs;
@@ -1999,8 +2071,16 @@ static int patch_cxt5051(struct hda_codec *codec)
spec->mixers[0] = cxt5051_toshiba_mixers;
spec->auto_mic = AUTO_MIC_PORTB;
break;
+ case CXT5051_IDEAPAD:
+ spec->init_verbs[spec->num_init_verbs++] =
+ cxt5051_ideapad_init_verbs;
+ spec->ideapad = 1;
+ break;
}
+ if (spec->beep_amp)
+ snd_hda_attach_beep_device(codec, spec->beep_amp);
+
return 0;
}
@@ -2616,7 +2696,6 @@ static struct snd_kcontrol_new cxt5066_vostro_mixers[] = {
.put = cxt5066_mic_boost_mux_enum_put,
.private_value = 0x23 | 0x100,
},
- HDA_CODEC_VOLUME_MONO("Beep Playback Volume", 0x13, 1, 0x0, HDA_OUTPUT),
{}
};
@@ -2977,8 +3056,10 @@ static struct snd_pci_quirk cxt5066_cfg_tbl[] = {
SND_PCI_QUIRK(0x17aa, 0x21b2, "Thinkpad X100e", CXT5066_IDEAPAD),
SND_PCI_QUIRK(0x17aa, 0x21b3, "Thinkpad Edge 13 (197)", CXT5066_IDEAPAD),
SND_PCI_QUIRK(0x17aa, 0x21b4, "Thinkpad Edge", CXT5066_IDEAPAD),
+ SND_PCI_QUIRK(0x17aa, 0x215e, "Lenovo Thinkpad", CXT5066_THINKPAD),
+ SND_PCI_QUIRK(0x17aa, 0x38af, "Lenovo G series", CXT5066_IDEAPAD),
+ SND_PCI_QUIRK(0x17aa, 0x3938, "Lenovo G series (AMD)", CXT5066_IDEAPAD),
SND_PCI_QUIRK(0x17aa, 0x3a0d, "ideapad", CXT5066_IDEAPAD),
- SND_PCI_QUIRK(0x17aa, 0x215e, "Lenovo Thinkpad", CXT5066_THINKPAD),
{}
};
@@ -3014,6 +3095,8 @@ static int patch_cxt5066(struct hda_codec *codec)
spec->cur_adc = 0;
spec->cur_adc_idx = 0;
+ set_beep_amp(spec, 0x13, 0, HDA_OUTPUT);
+
board_config = snd_hda_check_board_config(codec, CXT5066_MODELS,
cxt5066_models, cxt5066_cfg_tbl);
switch (board_config) {
@@ -3062,7 +3145,6 @@ static int patch_cxt5066(struct hda_codec *codec)
spec->port_d_mode = 0;
spec->dell_vostro = 1;
spec->mic_boost = 3; /* default 30dB gain */
- snd_hda_attach_beep_device(codec, 0x13);
/* no S/PDIF out */
spec->multiout.dig_out_nid = 0;
@@ -3104,6 +3186,9 @@ static int patch_cxt5066(struct hda_codec *codec)
break;
}
+ if (spec->beep_amp)
+ snd_hda_attach_beep_device(codec, spec->beep_amp);
+
return 0;
}
diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c
index 2fc53961054..522e0748ee9 100644
--- a/sound/pci/hda/patch_hdmi.c
+++ b/sound/pci/hda/patch_hdmi.c
@@ -698,11 +698,51 @@ static void hdmi_unsol_event(struct hda_codec *codec, unsigned int res)
* Callbacks
*/
-static void hdmi_setup_stream(struct hda_codec *codec, hda_nid_t nid,
+/* HBR should be Non-PCM, 8 channels */
+#define is_hbr_format(format) \
+ ((format & AC_FMT_TYPE_NON_PCM) && (format & AC_FMT_CHAN_MASK) == 7)
+
+static int hdmi_setup_stream(struct hda_codec *codec, hda_nid_t nid,
u32 stream_tag, int format)
{
+ struct hdmi_spec *spec = codec->spec;
int tag;
int fmt;
+ int pinctl;
+ int new_pinctl = 0;
+ int i;
+
+ for (i = 0; i < spec->num_pins; i++) {
+ if (spec->pin_cvt[i] != nid)
+ continue;
+ if (!(snd_hda_query_pin_caps(codec, spec->pin[i]) & AC_PINCAP_HBR))
+ continue;
+
+ pinctl = snd_hda_codec_read(codec, spec->pin[i], 0,
+ AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
+
+ new_pinctl = pinctl & ~AC_PINCTL_EPT;
+ if (is_hbr_format(format))
+ new_pinctl |= AC_PINCTL_EPT_HBR;
+ else
+ new_pinctl |= AC_PINCTL_EPT_NATIVE;
+
+ snd_printdd("hdmi_setup_stream: "
+ "NID=0x%x, %spinctl=0x%x\n",
+ spec->pin[i],
+ pinctl == new_pinctl ? "" : "new-",
+ new_pinctl);
+
+ if (pinctl != new_pinctl)
+ snd_hda_codec_write(codec, spec->pin[i], 0,
+ AC_VERB_SET_PIN_WIDGET_CONTROL,
+ new_pinctl);
+ }
+
+ if (is_hbr_format(format) && !new_pinctl) {
+ snd_printdd("hdmi_setup_stream: HBR is not supported\n");
+ return -EINVAL;
+ }
tag = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONV, 0) >> 4;
fmt = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_STREAM_FORMAT, 0);
@@ -722,6 +762,7 @@ static void hdmi_setup_stream(struct hda_codec *codec, hda_nid_t nid,
if (fmt != format)
snd_hda_codec_write(codec, nid, 0,
AC_VERB_SET_STREAM_FORMAT, format);
+ return 0;
}
/*
diff --git a/sound/pci/hda/patch_intelhdmi.c b/sound/pci/hda/patch_intelhdmi.c
index b81d23e42ac..5972d5e7d01 100644
--- a/sound/pci/hda/patch_intelhdmi.c
+++ b/sound/pci/hda/patch_intelhdmi.c
@@ -66,8 +66,7 @@ static int intel_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
hdmi_setup_audio_infoframe(codec, hinfo->nid, substream);
- hdmi_setup_stream(codec, hinfo->nid, stream_tag, format);
- return 0;
+ return hdmi_setup_stream(codec, hinfo->nid, stream_tag, format);
}
static int intel_hdmi_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
diff --git a/sound/pci/hda/patch_nvhdmi.c b/sound/pci/hda/patch_nvhdmi.c
index b0652acee9b..a281836fd47 100644
--- a/sound/pci/hda/patch_nvhdmi.c
+++ b/sound/pci/hda/patch_nvhdmi.c
@@ -202,8 +202,7 @@ static int nvhdmi_dig_playback_pcm_prepare_8ch_89(struct hda_pcm_stream *hinfo,
hdmi_setup_audio_infoframe(codec, hinfo->nid, substream);
- hdmi_setup_stream(codec, hinfo->nid, stream_tag, format);
- return 0;
+ return hdmi_setup_stream(codec, hinfo->nid, stream_tag, format);
}
static int nvhdmi_dig_playback_pcm_prepare_8ch(struct hda_pcm_stream *hinfo,
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
index 596ea2f12cf..6ac53f7de54 100644
--- a/sound/pci/hda/patch_realtek.c
+++ b/sound/pci/hda/patch_realtek.c
@@ -256,6 +256,13 @@ enum {
ALC882_MODEL_LAST,
};
+/* ALC680 models */
+enum {
+ ALC680_BASE,
+ ALC680_AUTO,
+ ALC680_MODEL_LAST,
+};
+
/* for GPIO Poll */
#define GPIO_MASK 0x03
@@ -326,6 +333,12 @@ struct alc_spec {
hda_nid_t *capsrc_nids;
hda_nid_t dig_in_nid; /* digital-in NID; optional */
+ /* capture setup for dynamic dual-adc switch */
+ unsigned int cur_adc_idx;
+ hda_nid_t cur_adc;
+ unsigned int cur_adc_stream_tag;
+ unsigned int cur_adc_format;
+
/* capture source */
unsigned int num_mux_defs;
const struct hda_input_mux *input_mux;
@@ -367,6 +380,7 @@ struct alc_spec {
/* other flags */
unsigned int no_analog :1; /* digital I/O only */
+ unsigned int dual_adc_switch:1; /* switch ADCs (for ALC275) */
int init_amp;
/* for virtual master */
@@ -833,9 +847,13 @@ static void alc_set_input_pin(struct hda_codec *codec, hda_nid_t nid,
if (auto_pin_type <= AUTO_PIN_FRONT_MIC) {
unsigned int pincap;
+ unsigned int oldval;
+ oldval = snd_hda_codec_read(codec, nid, 0,
+ AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
pincap = snd_hda_query_pin_caps(codec, nid);
pincap = (pincap & AC_PINCAP_VREF) >> AC_PINCAP_VREF_SHIFT;
- if (pincap & AC_PINCAP_VREF_80)
+ /* if the default pin setup is vref50, we give it priority */
+ if ((pincap & AC_PINCAP_VREF_80) && oldval != PIN_VREF50)
val = PIN_VREF80;
else if (pincap & AC_PINCAP_VREF_50)
val = PIN_VREF50;
@@ -1003,6 +1021,29 @@ static int get_connection_index(struct hda_codec *codec, hda_nid_t mux,
return -1;
}
+/* switch the current ADC according to the jack state */
+static void alc_dual_mic_adc_auto_switch(struct hda_codec *codec)
+{
+ struct alc_spec *spec = codec->spec;
+ unsigned int present;
+ hda_nid_t new_adc;
+
+ present = snd_hda_jack_detect(codec, spec->ext_mic.pin);
+ if (present)
+ spec->cur_adc_idx = 1;
+ else
+ spec->cur_adc_idx = 0;
+ new_adc = spec->adc_nids[spec->cur_adc_idx];
+ if (spec->cur_adc && spec->cur_adc != new_adc) {
+ /* stream is running, let's swap the current ADC */
+ snd_hda_codec_cleanup_stream(codec, spec->cur_adc);
+ spec->cur_adc = new_adc;
+ snd_hda_codec_setup_stream(codec, new_adc,
+ spec->cur_adc_stream_tag, 0,
+ spec->cur_adc_format);
+ }
+}
+
static void alc_mic_automute(struct hda_codec *codec)
{
struct alc_spec *spec = codec->spec;
@@ -1017,6 +1058,11 @@ static void alc_mic_automute(struct hda_codec *codec)
if (snd_BUG_ON(!spec->adc_nids))
return;
+ if (spec->dual_adc_switch) {
+ alc_dual_mic_adc_auto_switch(codec);
+ return;
+ }
+
cap_nid = spec->capsrc_nids ? spec->capsrc_nids[0] : spec->adc_nids[0];
present = snd_hda_jack_detect(codec, spec->ext_mic.pin);
@@ -1499,6 +1545,63 @@ static int alc_read_coef_idx(struct hda_codec *codec,
return val;
}
+/* set right pin controls for digital I/O */
+static void alc_auto_init_digital(struct hda_codec *codec)
+{
+ struct alc_spec *spec = codec->spec;
+ int i;
+ hda_nid_t pin;
+
+ for (i = 0; i < spec->autocfg.dig_outs; i++) {
+ pin = spec->autocfg.dig_out_pins[i];
+ if (pin) {
+ snd_hda_codec_write(codec, pin, 0,
+ AC_VERB_SET_PIN_WIDGET_CONTROL,
+ PIN_OUT);
+ }
+ }
+ pin = spec->autocfg.dig_in_pin;
+ if (pin)
+ snd_hda_codec_write(codec, pin, 0,
+ AC_VERB_SET_PIN_WIDGET_CONTROL,
+ PIN_IN);
+}
+
+/* parse digital I/Os and set up NIDs in BIOS auto-parse mode */
+static void alc_auto_parse_digital(struct hda_codec *codec)
+{
+ struct alc_spec *spec = codec->spec;
+ int i, err;
+ hda_nid_t dig_nid;
+
+ /* support multiple SPDIFs; the secondary is set up as a slave */
+ for (i = 0; i < spec->autocfg.dig_outs; i++) {
+ err = snd_hda_get_connections(codec,
+ spec->autocfg.dig_out_pins[i],
+ &dig_nid, 1);
+ if (err < 0)
+ continue;
+ if (!i) {
+ spec->multiout.dig_out_nid = dig_nid;
+ spec->dig_out_type = spec->autocfg.dig_out_type[0];
+ } else {
+ spec->multiout.slave_dig_outs = spec->slave_dig_outs;
+ if (i >= ARRAY_SIZE(spec->slave_dig_outs) - 1)
+ break;
+ spec->slave_dig_outs[i - 1] = dig_nid;
+ }
+ }
+
+ if (spec->autocfg.dig_in_pin) {
+ hda_nid_t dig_nid;
+ err = snd_hda_get_connections(codec,
+ spec->autocfg.dig_in_pin,
+ &dig_nid, 1);
+ if (err > 0)
+ spec->dig_in_nid = dig_nid;
+ }
+}
+
/*
* ALC888
*/
@@ -3607,6 +3710,41 @@ static int alc880_alt_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
return 0;
}
+/* analog capture with dynamic dual-adc changes */
+static int dualmic_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
+ struct hda_codec *codec,
+ unsigned int stream_tag,
+ unsigned int format,
+ struct snd_pcm_substream *substream)
+{
+ struct alc_spec *spec = codec->spec;
+ spec->cur_adc = spec->adc_nids[spec->cur_adc_idx];
+ spec->cur_adc_stream_tag = stream_tag;
+ spec->cur_adc_format = format;
+ snd_hda_codec_setup_stream(codec, spec->cur_adc, stream_tag, 0, format);
+ return 0;
+}
+
+static int dualmic_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
+ struct hda_codec *codec,
+ struct snd_pcm_substream *substream)
+{
+ struct alc_spec *spec = codec->spec;
+ snd_hda_codec_cleanup_stream(codec, spec->cur_adc);
+ spec->cur_adc = 0;
+ return 0;
+}
+
+static struct hda_pcm_stream dualmic_pcm_analog_capture = {
+ .substreams = 1,
+ .channels_min = 2,
+ .channels_max = 2,
+ .nid = 0, /* fill later */
+ .ops = {
+ .prepare = dualmic_capture_pcm_prepare,
+ .cleanup = dualmic_capture_pcm_cleanup
+ },
+};
/*
*/
@@ -4936,7 +5074,7 @@ static void alc880_auto_init_input_src(struct hda_codec *codec)
static int alc880_parse_auto_config(struct hda_codec *codec)
{
struct alc_spec *spec = codec->spec;
- int i, err;
+ int err;
static hda_nid_t alc880_ignore[] = { 0x1d, 0 };
err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
@@ -4967,25 +5105,7 @@ static int alc880_parse_auto_config(struct hda_codec *codec)
spec->multiout.max_channels = spec->multiout.num_dacs * 2;
- /* check multiple SPDIF-out (for recent codecs) */
- for (i = 0; i < spec->autocfg.dig_outs; i++) {
- hda_nid_t dig_nid;
- err = snd_hda_get_connections(codec,
- spec->autocfg.dig_out_pins[i],
- &dig_nid, 1);
- if (err < 0)
- continue;
- if (!i)
- spec->multiout.dig_out_nid = dig_nid;
- else {
- spec->multiout.slave_dig_outs = spec->slave_dig_outs;
- if (i >= ARRAY_SIZE(spec->slave_dig_outs) - 1)
- break;
- spec->slave_dig_outs[i - 1] = dig_nid;
- }
- }
- if (spec->autocfg.dig_in_pin)
- spec->dig_in_nid = ALC880_DIGIN_NID;
+ alc_auto_parse_digital(codec);
if (spec->kctls.list)
add_mixer(spec, spec->kctls.list);
@@ -5008,6 +5128,7 @@ static void alc880_auto_init(struct hda_codec *codec)
alc880_auto_init_extra_out(codec);
alc880_auto_init_analog_input(codec);
alc880_auto_init_input_src(codec);
+ alc_auto_init_digital(codec);
if (spec->unsol_event)
alc_inithook(codec);
}
@@ -5045,6 +5166,39 @@ static void fixup_automic_adc(struct hda_codec *codec)
spec->auto_mic = 0; /* disable auto-mic to be sure */
}
+/* select or unmute the given capsrc route */
+static void select_or_unmute_capsrc(struct hda_codec *codec, hda_nid_t cap,
+ int idx)
+{
+ if (get_wcaps_type(get_wcaps(codec, cap)) == AC_WID_AUD_MIX) {
+ snd_hda_codec_amp_stereo(codec, cap, HDA_INPUT, idx,
+ HDA_AMP_MUTE, 0);
+ } else {
+ snd_hda_codec_write_cache(codec, cap, 0,
+ AC_VERB_SET_CONNECT_SEL, idx);
+ }
+}
+
+/* set the default connection to that pin */
+static int init_capsrc_for_pin(struct hda_codec *codec, hda_nid_t pin)
+{
+ struct alc_spec *spec = codec->spec;
+ int i;
+
+ for (i = 0; i < spec->num_adc_nids; i++) {
+ hda_nid_t cap = spec->capsrc_nids ?
+ spec->capsrc_nids[i] : spec->adc_nids[i];
+ int idx;
+
+ idx = get_connection_index(codec, cap, pin);
+ if (idx < 0)
+ continue;
+ select_or_unmute_capsrc(codec, cap, idx);
+ return i; /* return the found index */
+ }
+ return -1; /* not found */
+}
+
/* choose the ADC/MUX containing the input pin and initialize the setup */
static void fixup_single_adc(struct hda_codec *codec)
{
@@ -5061,33 +5215,24 @@ static void fixup_single_adc(struct hda_codec *codec)
}
if (!pin)
return;
-
- /* set the default connection to that pin */
- for (i = 0; i < spec->num_adc_nids; i++) {
- hda_nid_t cap = spec->capsrc_nids ?
- spec->capsrc_nids[i] : spec->adc_nids[i];
- int idx;
-
- idx = get_connection_index(codec, cap, pin);
- if (idx < 0)
- continue;
+ i = init_capsrc_for_pin(codec, pin);
+ if (i >= 0) {
/* use only this ADC */
if (spec->capsrc_nids)
spec->capsrc_nids += i;
spec->adc_nids += i;
spec->num_adc_nids = 1;
- /* select or unmute this route */
- if (get_wcaps_type(get_wcaps(codec, cap)) == AC_WID_AUD_MIX) {
- snd_hda_codec_amp_stereo(codec, cap, HDA_INPUT, idx,
- HDA_AMP_MUTE, 0);
- } else {
- snd_hda_codec_write_cache(codec, cap, 0,
- AC_VERB_SET_CONNECT_SEL, idx);
- }
- return;
}
}
+/* initialize dual adcs */
+static void fixup_dual_adc_switch(struct hda_codec *codec)
+{
+ struct alc_spec *spec = codec->spec;
+ init_capsrc_for_pin(codec, spec->ext_mic.pin);
+ init_capsrc_for_pin(codec, spec->int_mic.pin);
+}
+
static void set_capture_mixer(struct hda_codec *codec)
{
struct alc_spec *spec = codec->spec;
@@ -5101,7 +5246,10 @@ static void set_capture_mixer(struct hda_codec *codec)
};
if (spec->num_adc_nids > 0 && spec->num_adc_nids <= 3) {
int mux = 0;
- if (spec->auto_mic)
+ int num_adcs = spec->num_adc_nids;
+ if (spec->dual_adc_switch)
+ fixup_dual_adc_switch(codec);
+ else if (spec->auto_mic)
fixup_automic_adc(codec);
else if (spec->input_mux) {
if (spec->input_mux->num_items > 1)
@@ -5109,7 +5257,9 @@ static void set_capture_mixer(struct hda_codec *codec)
else if (spec->input_mux->num_items == 1)
fixup_single_adc(codec);
}
- spec->cap_mixer = caps[mux][spec->num_adc_nids - 1];
+ if (spec->dual_adc_switch)
+ num_adcs = 1;
+ spec->cap_mixer = caps[mux][num_adcs - 1];
}
}
@@ -5183,6 +5333,7 @@ static void fillup_priv_adc_nids(struct hda_codec *codec, hda_nid_t *nids,
static struct snd_pci_quirk beep_white_list[] = {
SND_PCI_QUIRK(0x1043, 0x829f, "ASUS", 1),
+ SND_PCI_QUIRK(0x8086, 0xd613, "Intel", 1),
{}
};
@@ -6624,6 +6775,7 @@ static void alc260_auto_init(struct hda_codec *codec)
alc260_auto_init_multi_out(codec);
alc260_auto_init_analog_input(codec);
alc260_auto_init_input_src(codec);
+ alc_auto_init_digital(codec);
if (spec->unsol_event)
alc_inithook(codec);
}
@@ -6640,6 +6792,29 @@ static struct hda_amp_list alc260_loopbacks[] = {
#endif
/*
+ * Pin config fixes
+ */
+enum {
+ PINFIX_HP_DC5750,
+};
+
+static struct alc_pincfg alc260_hp_dc5750_pinfix[] = {
+ { 0x11, 0x90130110 }, /* speaker */
+ { }
+};
+
+static const struct alc_fixup alc260_fixups[] = {
+ [PINFIX_HP_DC5750] = {
+ .pins = alc260_hp_dc5750_pinfix
+ },
+};
+
+static struct snd_pci_quirk alc260_fixup_tbl[] = {
+ SND_PCI_QUIRK(0x103c, 0x280a, "HP dc5750", PINFIX_HP_DC5750),
+ {}
+};
+
+/*
* ALC260 configurations
*/
static const char *alc260_models[ALC260_MODEL_LAST] = {
@@ -6838,6 +7013,9 @@ static int patch_alc260(struct hda_codec *codec)
board_config = ALC260_AUTO;
}
+ if (board_config == ALC260_AUTO)
+ alc_pick_fixup(codec, alc260_fixup_tbl, alc260_fixups, 1);
+
if (board_config == ALC260_AUTO) {
/* automatic parse from the BIOS config */
err = alc260_parse_auto_config(codec);
@@ -6883,6 +7061,9 @@ static int patch_alc260(struct hda_codec *codec)
set_capture_mixer(codec);
set_beep_amp(spec, 0x07, 0x05, HDA_INPUT);
+ if (board_config == ALC260_AUTO)
+ alc_pick_fixup(codec, alc260_fixup_tbl, alc260_fixups, 0);
+
spec->vmaster_nid = 0x08;
codec->patch_ops = alc_patch_ops;
@@ -7003,7 +7184,7 @@ static struct hda_input_mux alc883_lenovo_nb0763_capture_source = {
.num_items = 4,
.items = {
{ "Mic", 0x0 },
- { "iMic", 0x1 },
+ { "Int Mic", 0x1 },
{ "Line", 0x2 },
{ "CD", 0x4 },
},
@@ -8573,8 +8754,8 @@ static struct snd_kcontrol_new alc883_lenovo_nb0763_mixer[] = {
HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, 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("iMic Playback Volume", 0x0b, 0x1, HDA_INPUT),
- HDA_CODEC_MUTE("iMic Playback Switch", 0x0b, 0x1, HDA_INPUT),
+ HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
+ HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
{ } /* end */
};
@@ -10265,7 +10446,8 @@ static struct alc_config_preset alc882_presets[] = {
* Pin config fixes
*/
enum {
- PINFIX_ABIT_AW9D_MAX
+ PINFIX_ABIT_AW9D_MAX,
+ PINFIX_PB_M5210,
};
static struct alc_pincfg alc882_abit_aw9d_pinfix[] = {
@@ -10275,13 +10457,22 @@ static struct alc_pincfg alc882_abit_aw9d_pinfix[] = {
{ }
};
+static const struct hda_verb pb_m5210_verbs[] = {
+ { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50 },
+ {}
+};
+
static const struct alc_fixup alc882_fixups[] = {
[PINFIX_ABIT_AW9D_MAX] = {
.pins = alc882_abit_aw9d_pinfix
},
+ [PINFIX_PB_M5210] = {
+ .verbs = pb_m5210_verbs
+ },
};
static struct snd_pci_quirk alc882_fixup_tbl[] = {
+ SND_PCI_QUIRK(0x1025, 0x0155, "Packard-Bell M5120", PINFIX_PB_M5210),
SND_PCI_QUIRK(0x147b, 0x107a, "Abit AW9D-MAX", PINFIX_ABIT_AW9D_MAX),
{}
};
@@ -10446,7 +10637,7 @@ static int alc882_parse_auto_config(struct hda_codec *codec)
{
struct alc_spec *spec = codec->spec;
static hda_nid_t alc882_ignore[] = { 0x1d, 0 };
- int i, err;
+ int err;
err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
alc882_ignore);
@@ -10476,25 +10667,7 @@ static int alc882_parse_auto_config(struct hda_codec *codec)
spec->multiout.max_channels = spec->multiout.num_dacs * 2;
- /* check multiple SPDIF-out (for recent codecs) */
- for (i = 0; i < spec->autocfg.dig_outs; i++) {
- hda_nid_t dig_nid;
- err = snd_hda_get_connections(codec,
- spec->autocfg.dig_out_pins[i],
- &dig_nid, 1);
- if (err < 0)
- continue;
- if (!i)
- spec->multiout.dig_out_nid = dig_nid;
- else {
- spec->multiout.slave_dig_outs = spec->slave_dig_outs;
- if (i >= ARRAY_SIZE(spec->slave_dig_outs) - 1)
- break;
- spec->slave_dig_outs[i - 1] = dig_nid;
- }
- }
- if (spec->autocfg.dig_in_pin)
- spec->dig_in_nid = ALC880_DIGIN_NID;
+ alc_auto_parse_digital(codec);
if (spec->kctls.list)
add_mixer(spec, spec->kctls.list);
@@ -10524,6 +10697,7 @@ static void alc882_auto_init(struct hda_codec *codec)
alc882_auto_init_hp_out(codec);
alc882_auto_init_analog_input(codec);
alc882_auto_init_input_src(codec);
+ alc_auto_init_digital(codec);
if (spec->unsol_event)
alc_inithook(codec);
}
@@ -12054,12 +12228,7 @@ static int alc262_parse_auto_config(struct hda_codec *codec)
spec->multiout.max_channels = spec->multiout.num_dacs * 2;
dig_only:
- if (spec->autocfg.dig_outs) {
- spec->multiout.dig_out_nid = ALC262_DIGOUT_NID;
- spec->dig_out_type = spec->autocfg.dig_out_type[0];
- }
- if (spec->autocfg.dig_in_pin)
- spec->dig_in_nid = ALC262_DIGIN_NID;
+ alc_auto_parse_digital(codec);
if (spec->kctls.list)
add_mixer(spec, spec->kctls.list);
@@ -12091,6 +12260,7 @@ static void alc262_auto_init(struct hda_codec *codec)
alc262_auto_init_hp_out(codec);
alc262_auto_init_analog_input(codec);
alc262_auto_init_input_src(codec);
+ alc_auto_init_digital(codec);
if (spec->unsol_event)
alc_inithook(codec);
}
@@ -13024,10 +13194,14 @@ static int alc268_new_analog_output(struct alc_spec *spec, hda_nid_t nid,
dac = 0x02;
break;
case 0x15:
+ case 0x1a: /* ALC259/269 only */
+ case 0x1b: /* ALC259/269 only */
case 0x21: /* ALC269vb has this pin, too */
dac = 0x03;
break;
default:
+ snd_printd(KERN_WARNING "hda_codec: "
+ "ignoring pin 0x%x as unknown\n", nid);
return 0;
}
if (spec->multiout.dac_nids[0] != dac &&
@@ -13078,7 +13252,7 @@ static int alc268_auto_create_multi_out_ctls(struct alc_spec *spec,
HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT));
if (err < 0)
return err;
- } else {
+ } else if (nid) {
err = alc268_new_analog_output(spec, nid, "Speaker", 0);
if (err < 0)
return err;
@@ -13227,10 +13401,7 @@ static int alc268_parse_auto_config(struct hda_codec *codec)
dig_only:
/* digital only support output */
- if (spec->autocfg.dig_outs) {
- spec->multiout.dig_out_nid = ALC268_DIGOUT_NID;
- spec->dig_out_type = spec->autocfg.dig_out_type[0];
- }
+ alc_auto_parse_digital(codec);
if (spec->kctls.list)
add_mixer(spec, spec->kctls.list);
@@ -13260,6 +13431,7 @@ static void alc268_auto_init(struct hda_codec *codec)
alc268_auto_init_hp_out(codec);
alc268_auto_init_mono_speaker_out(codec);
alc268_auto_init_analog_input(codec);
+ alc_auto_init_digital(codec);
if (spec->unsol_event)
alc_inithook(codec);
}
@@ -14152,6 +14324,36 @@ static int alc269_mic2_mute_check_ps(struct hda_codec *codec, hda_nid_t nid)
}
#endif /* CONFIG_SND_HDA_POWER_SAVE */
+static int alc275_setup_dual_adc(struct hda_codec *codec)
+{
+ struct alc_spec *spec = codec->spec;
+
+ if (codec->vendor_id != 0x10ec0275 || !spec->auto_mic)
+ return 0;
+ if ((spec->ext_mic.pin >= 0x18 && spec->int_mic.pin <= 0x13) ||
+ (spec->ext_mic.pin <= 0x12 && spec->int_mic.pin >= 0x18)) {
+ if (spec->ext_mic.pin <= 0x12) {
+ spec->private_adc_nids[0] = 0x08;
+ spec->private_adc_nids[1] = 0x11;
+ spec->private_capsrc_nids[0] = 0x23;
+ spec->private_capsrc_nids[1] = 0x22;
+ } else {
+ spec->private_adc_nids[0] = 0x11;
+ spec->private_adc_nids[1] = 0x08;
+ spec->private_capsrc_nids[0] = 0x22;
+ spec->private_capsrc_nids[1] = 0x23;
+ }
+ spec->adc_nids = spec->private_adc_nids;
+ spec->capsrc_nids = spec->private_capsrc_nids;
+ spec->num_adc_nids = 2;
+ spec->dual_adc_switch = 1;
+ snd_printdd("realtek: enabling dual ADC switchg (%02x:%02x)\n",
+ spec->adc_nids[0], spec->adc_nids[1]);
+ return 1;
+ }
+ return 0;
+}
+
/*
* BIOS auto configuration
*/
@@ -14175,8 +14377,7 @@ static int alc269_parse_auto_config(struct hda_codec *codec)
spec->multiout.max_channels = spec->multiout.num_dacs * 2;
- if (spec->autocfg.dig_outs)
- spec->multiout.dig_out_nid = ALC269_DIGOUT_NID;
+ alc_auto_parse_digital(codec);
if (spec->kctls.list)
add_mixer(spec, spec->kctls.list);
@@ -14191,13 +14392,15 @@ static int alc269_parse_auto_config(struct hda_codec *codec)
spec->num_mux_defs = 1;
spec->input_mux = &spec->private_imux[0];
- fillup_priv_adc_nids(codec, alc269_adc_candidates,
- sizeof(alc269_adc_candidates));
+
+ if (!alc275_setup_dual_adc(codec))
+ fillup_priv_adc_nids(codec, alc269_adc_candidates,
+ sizeof(alc269_adc_candidates));
/* set default input source */
- snd_hda_codec_write_cache(codec, spec->capsrc_nids[0],
- 0, AC_VERB_SET_CONNECT_SEL,
- spec->input_mux->items[0].index);
+ if (!spec->dual_adc_switch)
+ select_or_unmute_capsrc(codec, spec->capsrc_nids[0],
+ spec->input_mux->items[0].index);
err = alc_auto_add_mic_boost(codec);
if (err < 0)
@@ -14221,6 +14424,7 @@ static void alc269_auto_init(struct hda_codec *codec)
alc269_auto_init_multi_out(codec);
alc269_auto_init_hp_out(codec);
alc269_auto_init_analog_input(codec);
+ alc_auto_init_digital(codec);
if (spec->unsol_event)
alc_inithook(codec);
}
@@ -14493,6 +14697,10 @@ static int patch_alc269(struct hda_codec *codec)
*/
spec->stream_analog_playback = &alc269_44k_pcm_analog_playback;
spec->stream_analog_capture = &alc269_44k_pcm_analog_capture;
+ } else if (spec->dual_adc_switch) {
+ spec->stream_analog_playback = &alc269_pcm_analog_playback;
+ /* switch ADC dynamically */
+ spec->stream_analog_capture = &dualmic_pcm_analog_capture;
} else {
spec->stream_analog_playback = &alc269_pcm_analog_playback;
spec->stream_analog_capture = &alc269_pcm_analog_capture;
@@ -15378,8 +15586,7 @@ static int alc861_parse_auto_config(struct hda_codec *codec)
spec->multiout.max_channels = spec->multiout.num_dacs * 2;
- if (spec->autocfg.dig_outs)
- spec->multiout.dig_out_nid = ALC861_DIGOUT_NID;
+ alc_auto_parse_digital(codec);
if (spec->kctls.list)
add_mixer(spec, spec->kctls.list);
@@ -15405,6 +15612,7 @@ static void alc861_auto_init(struct hda_codec *codec)
alc861_auto_init_multi_out(codec);
alc861_auto_init_hp_out(codec);
alc861_auto_init_analog_input(codec);
+ alc_auto_init_digital(codec);
if (spec->unsol_event)
alc_inithook(codec);
}
@@ -16509,8 +16717,7 @@ static int alc861vd_parse_auto_config(struct hda_codec *codec)
spec->multiout.max_channels = spec->multiout.num_dacs * 2;
- if (spec->autocfg.dig_outs)
- spec->multiout.dig_out_nid = ALC861VD_DIGOUT_NID;
+ alc_auto_parse_digital(codec);
if (spec->kctls.list)
add_mixer(spec, spec->kctls.list);
@@ -16537,6 +16744,7 @@ static void alc861vd_auto_init(struct hda_codec *codec)
alc861vd_auto_init_hp_out(codec);
alc861vd_auto_init_analog_input(codec);
alc861vd_auto_init_input_src(codec);
+ alc_auto_init_digital(codec);
if (spec->unsol_event)
alc_inithook(codec);
}
@@ -18520,7 +18728,7 @@ static void alc662_auto_set_output_and_unmute(struct hda_codec *codec,
hda_nid_t dac)
{
int i, num;
- hda_nid_t srcs[4];
+ hda_nid_t srcs[HDA_MAX_CONNECTIONS];
alc_set_pin_output(codec, nid, pin_type);
/* need the manual connection? */
@@ -18624,8 +18832,7 @@ static int alc662_parse_auto_config(struct hda_codec *codec)
spec->multiout.max_channels = spec->multiout.num_dacs * 2;
- if (spec->autocfg.dig_outs)
- spec->multiout.dig_out_nid = ALC880_DIGOUT_NID;
+ alc_auto_parse_digital(codec);
if (spec->kctls.list)
add_mixer(spec, spec->kctls.list);
@@ -18635,7 +18842,7 @@ static int alc662_parse_auto_config(struct hda_codec *codec)
add_verb(spec, alc662_init_verbs);
if (codec->vendor_id == 0x10ec0272 || codec->vendor_id == 0x10ec0663 ||
- codec->vendor_id == 0x10ec0665)
+ codec->vendor_id == 0x10ec0665 || codec->vendor_id == 0x10ec0670)
add_verb(spec, alc663_init_verbs);
if (codec->vendor_id == 0x10ec0272)
@@ -18662,6 +18869,7 @@ static void alc662_auto_init(struct hda_codec *codec)
alc662_auto_init_hp_out(codec);
alc662_auto_init_analog_input(codec);
alc662_auto_init_input_src(codec);
+ alc_auto_init_digital(codec);
if (spec->unsol_event)
alc_inithook(codec);
}
@@ -18781,6 +18989,333 @@ static int patch_alc888(struct hda_codec *codec)
}
/*
+ * ALC680 support
+ */
+#define ALC680_DIGOUT_NID ALC880_DIGOUT_NID
+#define alc680_modes alc260_modes
+
+static hda_nid_t alc680_dac_nids[3] = {
+ /* Lout1, Lout2, hp */
+ 0x02, 0x03, 0x04
+};
+
+static hda_nid_t alc680_adc_nids[3] = {
+ /* ADC0-2 */
+ /* DMIC, MIC, Line-in*/
+ 0x07, 0x08, 0x09
+};
+
+static struct snd_kcontrol_new alc680_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", 0x4, 0x0, HDA_OUTPUT),
+ HDA_CODEC_MUTE("Headphone Playback Switch", 0x16, 0x0, HDA_OUTPUT),
+ HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
+ { }
+};
+
+static struct snd_kcontrol_new alc680_capture_mixer[] = {
+ HDA_CODEC_VOLUME("Capture Volume", 0x07, 0x0, HDA_INPUT),
+ HDA_CODEC_MUTE("Capture Switch", 0x07, 0x0, HDA_INPUT),
+ HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x08, 0x0, HDA_INPUT),
+ HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x08, 0x0, HDA_INPUT),
+ HDA_CODEC_VOLUME_IDX("Capture Volume", 2, 0x09, 0x0, HDA_INPUT),
+ HDA_CODEC_MUTE_IDX("Capture Switch", 2, 0x09, 0x0, HDA_INPUT),
+ { } /* end */
+};
+
+/*
+ * generic initialization of ADC, input mixers and output mixers
+ */
+static struct hda_verb alc680_init_verbs[] = {
+ /* Unmute DAC0-1 and set vol = 0 */
+ {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+ {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+ {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+
+ {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
+ {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
+ {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
+ {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
+ {0x19, 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},
+ { }
+};
+
+/* create input playback/capture controls for the given pin */
+static int alc680_new_analog_output(struct alc_spec *spec, hda_nid_t nid,
+ const char *ctlname, int idx)
+{
+ hda_nid_t dac;
+ int err;
+
+ switch (nid) {
+ case 0x14:
+ dac = 0x02;
+ break;
+ case 0x15:
+ dac = 0x03;
+ break;
+ case 0x16:
+ dac = 0x04;
+ break;
+ default:
+ return 0;
+ }
+ if (spec->multiout.dac_nids[0] != dac &&
+ spec->multiout.dac_nids[1] != dac) {
+ err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, ctlname,
+ HDA_COMPOSE_AMP_VAL(dac, 3, idx,
+ HDA_OUTPUT));
+ if (err < 0)
+ return err;
+
+ err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, ctlname,
+ HDA_COMPOSE_AMP_VAL(nid, 3, idx, HDA_OUTPUT));
+
+ if (err < 0)
+ return err;
+ spec->multiout.dac_nids[spec->multiout.num_dacs++] = dac;
+ }
+
+ return 0;
+}
+
+/* add playback controls from the parsed DAC table */
+static int alc680_auto_create_multi_out_ctls(struct alc_spec *spec,
+ const struct auto_pin_cfg *cfg)
+{
+ hda_nid_t nid;
+ int err;
+
+ spec->multiout.dac_nids = spec->private_dac_nids;
+
+ nid = cfg->line_out_pins[0];
+ if (nid) {
+ const char *name;
+ if (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
+ name = "Speaker";
+ else
+ name = "Front";
+ err = alc680_new_analog_output(spec, nid, name, 0);
+ if (err < 0)
+ return err;
+ }
+
+ nid = cfg->speaker_pins[0];
+ if (nid) {
+ err = alc680_new_analog_output(spec, nid, "Speaker", 0);
+ if (err < 0)
+ return err;
+ }
+ nid = cfg->hp_pins[0];
+ if (nid) {
+ err = alc680_new_analog_output(spec, nid, "Headphone", 0);
+ if (err < 0)
+ return err;
+ }
+
+ return 0;
+}
+
+static void alc680_auto_set_output_and_unmute(struct hda_codec *codec,
+ hda_nid_t nid, int pin_type)
+{
+ alc_set_pin_output(codec, nid, pin_type);
+}
+
+static void alc680_auto_init_multi_out(struct hda_codec *codec)
+{
+ struct alc_spec *spec = codec->spec;
+ hda_nid_t nid = spec->autocfg.line_out_pins[0];
+ if (nid) {
+ int pin_type = get_pin_type(spec->autocfg.line_out_type);
+ alc680_auto_set_output_and_unmute(codec, nid, pin_type);
+ }
+}
+
+static void alc680_auto_init_hp_out(struct hda_codec *codec)
+{
+ struct alc_spec *spec = codec->spec;
+ hda_nid_t pin;
+
+ pin = spec->autocfg.hp_pins[0];
+ if (pin)
+ alc680_auto_set_output_and_unmute(codec, pin, PIN_HP);
+ pin = spec->autocfg.speaker_pins[0];
+ if (pin)
+ alc680_auto_set_output_and_unmute(codec, pin, PIN_OUT);
+}
+
+/* pcm configuration: identical with ALC880 */
+#define alc680_pcm_analog_playback alc880_pcm_analog_playback
+#define alc680_pcm_analog_capture alc880_pcm_analog_capture
+#define alc680_pcm_analog_alt_capture alc880_pcm_analog_alt_capture
+#define alc680_pcm_digital_playback alc880_pcm_digital_playback
+
+static struct hda_input_mux alc680_capture_source = {
+ .num_items = 1,
+ .items = {
+ { "Mic", 0x0 },
+ },
+};
+
+/*
+ * BIOS auto configuration
+ */
+static int alc680_parse_auto_config(struct hda_codec *codec)
+{
+ struct alc_spec *spec = codec->spec;
+ int err;
+ static hda_nid_t alc680_ignore[] = { 0 };
+
+ err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
+ alc680_ignore);
+ if (err < 0)
+ return err;
+ if (!spec->autocfg.line_outs) {
+ if (spec->autocfg.dig_outs || spec->autocfg.dig_in_pin) {
+ spec->multiout.max_channels = 2;
+ spec->no_analog = 1;
+ goto dig_only;
+ }
+ return 0; /* can't find valid BIOS pin config */
+ }
+ err = alc680_auto_create_multi_out_ctls(spec, &spec->autocfg);
+ if (err < 0)
+ return err;
+
+ spec->multiout.max_channels = 2;
+
+ dig_only:
+ /* digital only support output */
+ alc_auto_parse_digital(codec);
+ if (spec->kctls.list)
+ add_mixer(spec, spec->kctls.list);
+
+ add_verb(spec, alc680_init_verbs);
+ spec->num_mux_defs = 1;
+ spec->input_mux = &alc680_capture_source;
+
+ err = alc_auto_add_mic_boost(codec);
+ if (err < 0)
+ return err;
+
+ return 1;
+}
+
+#define alc680_auto_init_analog_input alc882_auto_init_analog_input
+
+/* init callback for auto-configuration model -- overriding the default init */
+static void alc680_auto_init(struct hda_codec *codec)
+{
+ struct alc_spec *spec = codec->spec;
+ alc680_auto_init_multi_out(codec);
+ alc680_auto_init_hp_out(codec);
+ alc680_auto_init_analog_input(codec);
+ alc_auto_init_digital(codec);
+ if (spec->unsol_event)
+ alc_inithook(codec);
+}
+
+/*
+ * configuration and preset
+ */
+static const char *alc680_models[ALC680_MODEL_LAST] = {
+ [ALC680_BASE] = "base",
+ [ALC680_AUTO] = "auto",
+};
+
+static struct snd_pci_quirk alc680_cfg_tbl[] = {
+ SND_PCI_QUIRK(0x1043, 0x12f3, "ASUS NX90", ALC680_BASE),
+ {}
+};
+
+static struct alc_config_preset alc680_presets[] = {
+ [ALC680_BASE] = {
+ .mixers = { alc680_base_mixer },
+ .cap_mixer = alc680_capture_mixer,
+ .init_verbs = { alc680_init_verbs },
+ .num_dacs = ARRAY_SIZE(alc680_dac_nids),
+ .dac_nids = alc680_dac_nids,
+ .num_adc_nids = ARRAY_SIZE(alc680_adc_nids),
+ .adc_nids = alc680_adc_nids,
+ .hp_nid = 0x04,
+ .dig_out_nid = ALC680_DIGOUT_NID,
+ .num_channel_mode = ARRAY_SIZE(alc680_modes),
+ .channel_mode = alc680_modes,
+ .input_mux = &alc680_capture_source,
+ },
+};
+
+static int patch_alc680(struct hda_codec *codec)
+{
+ struct alc_spec *spec;
+ int board_config;
+ int err;
+
+ spec = kzalloc(sizeof(*spec), GFP_KERNEL);
+ if (spec == NULL)
+ return -ENOMEM;
+
+ codec->spec = spec;
+
+ board_config = snd_hda_check_board_config(codec, ALC680_MODEL_LAST,
+ alc680_models,
+ alc680_cfg_tbl);
+
+ if (board_config < 0 || board_config >= ALC680_MODEL_LAST) {
+ printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
+ codec->chip_name);
+ board_config = ALC680_AUTO;
+ }
+
+ if (board_config == ALC680_AUTO) {
+ /* automatic parse from the BIOS config */
+ err = alc680_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 = ALC680_BASE;
+ }
+ }
+
+ if (board_config != ALC680_AUTO)
+ setup_preset(codec, &alc680_presets[board_config]);
+
+ spec->stream_analog_playback = &alc680_pcm_analog_playback;
+ spec->stream_analog_capture = &alc680_pcm_analog_capture;
+ spec->stream_analog_alt_capture = &alc680_pcm_analog_alt_capture;
+ spec->stream_digital_playback = &alc680_pcm_digital_playback;
+
+ if (!spec->adc_nids) {
+ spec->adc_nids = alc680_adc_nids;
+ spec->num_adc_nids = ARRAY_SIZE(alc680_adc_nids);
+ }
+
+ if (!spec->cap_mixer)
+ set_capture_mixer(codec);
+
+ spec->vmaster_nid = 0x02;
+
+ codec->patch_ops = alc_patch_ops;
+ if (board_config == ALC680_AUTO)
+ spec->init_hook = alc680_auto_init;
+
+ return 0;
+}
+
+/*
* patch entries
*/
static struct hda_codec_preset snd_hda_preset_realtek[] = {
@@ -18804,6 +19339,7 @@ static struct hda_codec_preset snd_hda_preset_realtek[] = {
{ .id = 0x10ec0663, .name = "ALC663", .patch = patch_alc662 },
{ .id = 0x10ec0665, .name = "ALC665", .patch = patch_alc662 },
{ .id = 0x10ec0670, .name = "ALC670", .patch = patch_alc662 },
+ { .id = 0x10ec0680, .name = "ALC680", .patch = patch_alc680 },
{ .id = 0x10ec0880, .name = "ALC880", .patch = patch_alc880 },
{ .id = 0x10ec0882, .name = "ALC882", .patch = patch_alc882 },
{ .id = 0x10ec0883, .name = "ALC883", .patch = patch_alc882 },
diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c
index f1e7babd692..b8d730c47df 100644
--- a/sound/pci/hda/patch_sigmatel.c
+++ b/sound/pci/hda/patch_sigmatel.c
@@ -202,6 +202,7 @@ struct sigmatel_spec {
unsigned int spdif_mute: 1;
unsigned int check_volume_offset:1;
unsigned int auto_mic:1;
+ unsigned int linear_tone_beep:1;
/* gpio lines */
unsigned int eapd_mask;
@@ -3802,7 +3803,7 @@ static int stac92xx_parse_auto_config(struct hda_codec *codec, hda_nid_t dig_out
return err;
if (codec->beep) {
/* IDT/STAC codecs have linear beep tone parameter */
- codec->beep->linear_tone = 1;
+ codec->beep->linear_tone = spec->linear_tone_beep;
/* if no beep switch is available, make its own one */
caps = query_amp_caps(codec, nid, HDA_OUTPUT);
if (!(caps & AC_AMPCAP_MUTE)) {
@@ -5005,6 +5006,7 @@ static int patch_stac9200(struct hda_codec *codec)
codec->no_trigger_sense = 1;
codec->spec = spec;
+ spec->linear_tone_beep = 1;
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,
@@ -5068,6 +5070,7 @@ static int patch_stac925x(struct hda_codec *codec)
codec->no_trigger_sense = 1;
codec->spec = spec;
+ spec->linear_tone_beep = 1;
spec->num_pins = ARRAY_SIZE(stac925x_pin_nids);
spec->pin_nids = stac925x_pin_nids;
@@ -5153,6 +5156,7 @@ static int patch_stac92hd73xx(struct hda_codec *codec)
codec->no_trigger_sense = 1;
codec->spec = spec;
+ spec->linear_tone_beep = 0;
codec->slave_dig_outs = stac92hd73xx_slave_dig_outs;
spec->num_pins = ARRAY_SIZE(stac92hd73xx_pin_nids);
spec->pin_nids = stac92hd73xx_pin_nids;
@@ -5300,6 +5304,7 @@ static int patch_stac92hd83xxx(struct hda_codec *codec)
codec->no_trigger_sense = 1;
codec->spec = spec;
+ spec->linear_tone_beep = 1;
codec->slave_dig_outs = stac92hd83xxx_slave_dig_outs;
spec->digbeep_nid = 0x21;
spec->mux_nids = stac92hd83xxx_mux_nids;
@@ -5522,6 +5527,7 @@ static int patch_stac92hd71bxx(struct hda_codec *codec)
codec->no_trigger_sense = 1;
codec->spec = spec;
+ spec->linear_tone_beep = 0;
codec->patch_ops = stac92xx_patch_ops;
spec->num_pins = STAC92HD71BXX_NUM_PINS;
switch (codec->vendor_id) {
@@ -5779,6 +5785,7 @@ static int patch_stac922x(struct hda_codec *codec)
codec->no_trigger_sense = 1;
codec->spec = spec;
+ spec->linear_tone_beep = 1;
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,
@@ -5883,6 +5890,7 @@ static int patch_stac927x(struct hda_codec *codec)
codec->no_trigger_sense = 1;
codec->spec = spec;
+ spec->linear_tone_beep = 1;
codec->slave_dig_outs = stac927x_slave_dig_outs;
spec->num_pins = ARRAY_SIZE(stac927x_pin_nids);
spec->pin_nids = stac927x_pin_nids;
@@ -6018,6 +6026,7 @@ static int patch_stac9205(struct hda_codec *codec)
codec->no_trigger_sense = 1;
codec->spec = spec;
+ spec->linear_tone_beep = 1;
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,
@@ -6174,6 +6183,7 @@ static int patch_stac9872(struct hda_codec *codec)
return -ENOMEM;
codec->no_trigger_sense = 1;
codec->spec = spec;
+ spec->linear_tone_beep = 1;
spec->num_pins = ARRAY_SIZE(stac9872_pin_nids);
spec->pin_nids = stac9872_pin_nids;
diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c
index 73453814e09..ae3acb2b42d 100644
--- a/sound/pci/hda/patch_via.c
+++ b/sound/pci/hda/patch_via.c
@@ -552,24 +552,30 @@ static void via_auto_init_hp_out(struct hda_codec *codec)
}
}
+static int is_smart51_pins(struct via_spec *spec, hda_nid_t pin);
+
static void via_auto_init_analog_input(struct hda_codec *codec)
{
struct via_spec *spec = codec->spec;
+ unsigned int ctl;
int i;
for (i = 0; i < AUTO_PIN_LAST; i++) {
hda_nid_t nid = spec->autocfg.input_pins[i];
+ if (!nid)
+ continue;
+ if (spec->smart51_enabled && is_smart51_pins(spec, nid))
+ ctl = PIN_OUT;
+ else if (i <= AUTO_PIN_FRONT_MIC)
+ ctl = PIN_VREF50;
+ else
+ ctl = PIN_IN;
snd_hda_codec_write(codec, nid, 0,
- AC_VERB_SET_PIN_WIDGET_CONTROL,
- (i <= AUTO_PIN_FRONT_MIC ?
- PIN_VREF50 : PIN_IN));
-
+ AC_VERB_SET_PIN_WIDGET_CONTROL, ctl);
}
}
-static int is_smart51_pins(struct via_spec *spec, hda_nid_t pin);
-
static void set_pin_power_state(struct hda_codec *codec, hda_nid_t nid,
unsigned int *affected_parm)
{
@@ -658,6 +664,8 @@ static void set_jack_power_state(struct hda_codec *codec)
/* PW0 (19h), SW1 (18h), AOW1 (11h) */
parm = AC_PWRST_D3;
set_pin_power_state(codec, 0x19, &parm);
+ if (spec->smart51_enabled)
+ parm = AC_PWRST_D0;
snd_hda_codec_write(codec, 0x18, 0, AC_VERB_SET_POWER_STATE,
parm);
snd_hda_codec_write(codec, 0x11, 0, AC_VERB_SET_POWER_STATE,
@@ -667,6 +675,8 @@ static void set_jack_power_state(struct hda_codec *codec)
if (is_8ch) {
parm = AC_PWRST_D3;
set_pin_power_state(codec, 0x22, &parm);
+ if (spec->smart51_enabled)
+ parm = AC_PWRST_D0;
snd_hda_codec_write(codec, 0x26, 0,
AC_VERB_SET_POWER_STATE, parm);
snd_hda_codec_write(codec, 0x24, 0,
@@ -3915,6 +3925,13 @@ static int vt1708S_auto_fill_dac_nids(struct via_spec *spec,
}
}
+ /* for Smart 5.1, line/mic inputs double as output pins */
+ if (cfg->line_outs == 1) {
+ spec->multiout.num_dacs = 3;
+ spec->multiout.dac_nids[AUTO_SEQ_SURROUND] = 0x11;
+ spec->multiout.dac_nids[AUTO_SEQ_CENLFE] = 0x24;
+ }
+
return 0;
}
@@ -3932,7 +3949,8 @@ static int vt1708S_auto_create_multi_out_ctls(struct via_spec *spec,
for (i = 0; i <= AUTO_SEQ_SIDE; i++) {
nid = cfg->line_out_pins[i];
- if (!nid)
+ /* for Smart 5.1, there are always at least six channels */
+ if (!nid && i > AUTO_SEQ_CENLFE)
continue;
nid_vol = nid_vols[i];
diff --git a/sound/pci/riptide/riptide.c b/sound/pci/riptide/riptide.c
index ad446267761..f64fb7d988c 100644
--- a/sound/pci/riptide/riptide.c
+++ b/sound/pci/riptide/riptide.c
@@ -97,6 +97,7 @@
#include <linux/gameport.h>
#include <linux/device.h>
#include <linux/firmware.h>
+#include <linux/kernel.h>
#include <asm/io.h>
#include <sound/core.h>
#include <sound/info.h>
@@ -667,13 +668,12 @@ static u32 atoh(const unsigned char *in, unsigned int len)
unsigned char c;
while (len) {
+ int value;
+
c = in[len - 1];
- if ((c >= '0') && (c <= '9'))
- sum += mult * (c - '0');
- else if ((c >= 'A') && (c <= 'F'))
- sum += mult * (c - ('A' - 10));
- else if ((c >= 'a') && (c <= 'f'))
- sum += mult * (c - ('a' - 10));
+ value = hex_to_bin(c);
+ if (value >= 0)
+ sum += mult * value;
mult *= 16;
--len;
}
@@ -1615,7 +1615,10 @@ static int snd_riptide_playback_open(struct snd_pcm_substream *substream)
chip->playback_substream[sub_num] = substream;
runtime->hw = snd_riptide_playback;
+
data = kzalloc(sizeof(struct pcmhw), GFP_KERNEL);
+ if (data == NULL)
+ return -ENOMEM;
data->paths = lbus_play_paths[sub_num];
data->id = play_ids[sub_num];
data->source = play_sources[sub_num];
@@ -1635,7 +1638,10 @@ static int snd_riptide_capture_open(struct snd_pcm_substream *substream)
chip->capture_substream = substream;
runtime->hw = snd_riptide_capture;
+
data = kzalloc(sizeof(struct pcmhw), GFP_KERNEL);
+ if (data == NULL)
+ return -ENOMEM;
data->paths = lbus_rec_path;
data->id = PADC;
data->source = ACLNK2PADC;
diff --git a/sound/pci/sis7019.c b/sound/pci/sis7019.c
index 9cc1b5aa014..1b8f6742b5f 100644
--- a/sound/pci/sis7019.c
+++ b/sound/pci/sis7019.c
@@ -264,11 +264,13 @@ static void sis_update_voice(struct voice *voice)
* if using small periods.
*
* If we're less than 9 samples behind, we're on target.
+ * Otherwise, shorten the next vperiod by the amount we've
+ * been delayed.
*/
if (sync > -9)
voice->vperiod = voice->sync_period_size + 1;
else
- voice->vperiod = voice->sync_period_size - 4;
+ voice->vperiod = voice->sync_period_size + sync + 10;
if (voice->vperiod < voice->buffer_size) {
sis_update_sso(voice, voice->vperiod);
@@ -736,7 +738,7 @@ static void sis_prepare_timing_voice(struct voice *voice,
period_size = buffer_size;
/* Initially, we want to interrupt just a bit behind the end of
- * the period we're clocking out. 10 samples seems to give a good
+ * the period we're clocking out. 12 samples seems to give a good
* delay.
*
* We want to spread our interrupts throughout the virtual period,
@@ -747,7 +749,7 @@ static void sis_prepare_timing_voice(struct voice *voice,
*
* This is all moot if we don't need to use virtual periods.
*/
- vperiod = runtime->period_size + 10;
+ vperiod = runtime->period_size + 12;
if (vperiod > period_size) {
u16 tail = vperiod % period_size;
u16 quarter_period = period_size / 4;
@@ -776,7 +778,7 @@ static void sis_prepare_timing_voice(struct voice *voice,
*/
timing->flags |= VOICE_SYNC_TIMING;
timing->sync_base = voice->ctrl_base;
- timing->sync_cso = runtime->period_size - 1;
+ timing->sync_cso = runtime->period_size;
timing->sync_period_size = runtime->period_size;
timing->sync_buffer_size = runtime->buffer_size;
timing->period_size = period_size;
@@ -1047,7 +1049,7 @@ static int sis_chip_free(struct sis7019 *sis)
/* Reset the chip, and disable all interrputs.
*/
outl(SIS_GCR_SOFTWARE_RESET, sis->ioport + SIS_GCR);
- udelay(10);
+ udelay(25);
outl(0, sis->ioport + SIS_GCR);
outl(0, sis->ioport + SIS_GIER);
@@ -1083,7 +1085,7 @@ static int sis_chip_init(struct sis7019 *sis)
/* Reset the audio controller
*/
outl(SIS_GCR_SOFTWARE_RESET, io + SIS_GCR);
- udelay(10);
+ udelay(25);
outl(0, io + SIS_GCR);
/* Get the AC-link semaphore, and reset the codecs
@@ -1096,7 +1098,7 @@ static int sis_chip_init(struct sis7019 *sis)
return -EIO;
outl(SIS_AC97_CMD_CODEC_COLD_RESET, io + SIS_AC97_CMD);
- udelay(10);
+ udelay(250);
count = 0xffff;
while ((inw(io + SIS_AC97_STATUS) & SIS_AC97_STATUS_BUSY) && --count)
diff --git a/sound/pci/trident/trident_main.c b/sound/pci/trident/trident_main.c
index 6d943f6f6b7..2870a4fdc13 100644
--- a/sound/pci/trident/trident_main.c
+++ b/sound/pci/trident/trident_main.c
@@ -1055,7 +1055,7 @@ static int snd_trident_capture_prepare(struct snd_pcm_substream *substream)
spin_lock_irq(&trident->reg_lock);
- // Initilize the channel and set channel Mode
+ // Initialize the channel and set channel Mode
outb(0, TRID_REG(trident, LEGACY_DMAR15));
// Set DMA channel operation mode register
diff --git a/sound/pci/via82xx.c b/sound/pci/via82xx.c
index 7e494b6a1d0..8c5f8b5a59f 100644
--- a/sound/pci/via82xx.c
+++ b/sound/pci/via82xx.c
@@ -85,6 +85,7 @@ static int joystick;
static int ac97_clock = 48000;
static char *ac97_quirk;
static int dxs_support;
+static int dxs_init_volume = 31;
static int nodelay;
module_param(index, int, 0444);
@@ -103,6 +104,8 @@ module_param(ac97_quirk, charp, 0444);
MODULE_PARM_DESC(ac97_quirk, "AC'97 workaround for strange hardware.");
module_param(dxs_support, int, 0444);
MODULE_PARM_DESC(dxs_support, "Support for DXS channels (0 = auto, 1 = enable, 2 = disable, 3 = 48k only, 4 = no VRA, 5 = enable any sample rate)");
+module_param(dxs_init_volume, int, 0644);
+MODULE_PARM_DESC(dxs_init_volume, "initial DXS volume (0-31)");
module_param(nodelay, int, 0444);
MODULE_PARM_DESC(nodelay, "Disable 500ms init delay");
@@ -1245,8 +1248,10 @@ static int snd_via8233_playback_open(struct snd_pcm_substream *substream)
return err;
stream = viadev->reg_offset / 0x10;
if (chip->dxs_controls[stream]) {
- chip->playback_volume[stream][0] = 0;
- chip->playback_volume[stream][1] = 0;
+ chip->playback_volume[stream][0] =
+ VIA_DXS_MAX_VOLUME - (dxs_init_volume & 31);
+ chip->playback_volume[stream][1] =
+ VIA_DXS_MAX_VOLUME - (dxs_init_volume & 31);
chip->dxs_controls[stream]->vd[0].access &=
~SNDRV_CTL_ELEM_ACCESS_INACTIVE;
snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE |
diff --git a/sound/pcmcia/pdaudiocf/pdaudiocf.c b/sound/pcmcia/pdaudiocf/pdaudiocf.c
index df110df52a8..7ab9174a8a8 100644
--- a/sound/pcmcia/pdaudiocf/pdaudiocf.c
+++ b/sound/pcmcia/pdaudiocf/pdaudiocf.c
@@ -139,8 +139,8 @@ static int snd_pdacf_probe(struct pcmcia_device *link)
pdacf->p_dev = link;
link->priv = pdacf;
- link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
- link->io.NumPorts1 = 16;
+ link->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO;
+ link->resource[0]->end = 16;
link->conf.Attributes = CONF_ENABLE_IRQ | CONF_ENABLE_PULSE_IRQ;
link->conf.IntType = INT_MEMORY_AND_IO;
@@ -219,7 +219,7 @@ static int pdacf_config(struct pcmcia_device *link)
snd_printdd(KERN_DEBUG "pdacf_config called\n");
link->conf.ConfigIndex = 0x5;
- ret = pcmcia_request_io(link, &link->io);
+ ret = pcmcia_request_io(link);
if (ret)
goto failed;
@@ -231,7 +231,8 @@ static int pdacf_config(struct pcmcia_device *link)
if (ret)
goto failed;
- if (snd_pdacf_assign_resources(pdacf, link->io.BasePort1, link->irq) < 0)
+ if (snd_pdacf_assign_resources(pdacf, link->resource[0]->start,
+ link->irq) < 0)
goto failed;
return 0;
diff --git a/sound/pcmcia/pdaudiocf/pdaudiocf.h b/sound/pcmcia/pdaudiocf/pdaudiocf.h
index a0a7ec64222..5cc3e457307 100644
--- a/sound/pcmcia/pdaudiocf/pdaudiocf.h
+++ b/sound/pcmcia/pdaudiocf/pdaudiocf.h
@@ -24,7 +24,6 @@
#include <sound/pcm.h>
#include <asm/io.h>
#include <linux/interrupt.h>
-#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/cistpl.h>
#include <pcmcia/ds.h>
diff --git a/sound/pcmcia/vx/vxpocket.c b/sound/pcmcia/vx/vxpocket.c
index 624b47a85f0..a6edfc3be29 100644
--- a/sound/pcmcia/vx/vxpocket.c
+++ b/sound/pcmcia/vx/vxpocket.c
@@ -159,8 +159,8 @@ static int snd_vxpocket_new(struct snd_card *card, int ibl,
vxp->p_dev = link;
link->priv = chip;
- link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
- link->io.NumPorts1 = 16;
+ link->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO;
+ link->resource[0]->end = 16;
link->conf.Attributes = CONF_ENABLE_IRQ;
link->conf.IntType = INT_MEMORY_AND_IO;
@@ -226,7 +226,7 @@ static int vxpocket_config(struct pcmcia_device *link)
strcpy(chip->card->driver, vxp440_hw.name);
}
- ret = pcmcia_request_io(link, &link->io);
+ ret = pcmcia_request_io(link);
if (ret)
goto failed;
@@ -241,7 +241,8 @@ static int vxpocket_config(struct pcmcia_device *link)
chip->dev = &link->dev;
snd_card_set_dev(chip->card, chip->dev);
- if (snd_vxpocket_assign_resources(chip, link->io.BasePort1, link->irq) < 0)
+ if (snd_vxpocket_assign_resources(chip, link->resource[0]->start,
+ link->irq) < 0)
goto failed;
return 0;
diff --git a/sound/pcmcia/vx/vxpocket.h b/sound/pcmcia/vx/vxpocket.h
index ea4df16a28e..d9110669d04 100644
--- a/sound/pcmcia/vx/vxpocket.h
+++ b/sound/pcmcia/vx/vxpocket.h
@@ -23,7 +23,6 @@
#include <sound/vx_core.h>
-#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/cistpl.h>
#include <pcmcia/ds.h>
diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig
index b1749bc6797..3e598e756e5 100644
--- a/sound/soc/Kconfig
+++ b/sound/soc/Kconfig
@@ -28,9 +28,13 @@ source "sound/soc/atmel/Kconfig"
source "sound/soc/au1x/Kconfig"
source "sound/soc/blackfin/Kconfig"
source "sound/soc/davinci/Kconfig"
+source "sound/soc/ep93xx/Kconfig"
source "sound/soc/fsl/Kconfig"
source "sound/soc/imx/Kconfig"
+source "sound/soc/jz4740/Kconfig"
+source "sound/soc/nuc900/Kconfig"
source "sound/soc/omap/Kconfig"
+source "sound/soc/kirkwood/Kconfig"
source "sound/soc/pxa/Kconfig"
source "sound/soc/s3c24xx/Kconfig"
source "sound/soc/s6000/Kconfig"
diff --git a/sound/soc/Makefile b/sound/soc/Makefile
index 1470141d416..eb183443eee 100644
--- a/sound/soc/Makefile
+++ b/sound/soc/Makefile
@@ -6,9 +6,13 @@ obj-$(CONFIG_SND_SOC) += atmel/
obj-$(CONFIG_SND_SOC) += au1x/
obj-$(CONFIG_SND_SOC) += blackfin/
obj-$(CONFIG_SND_SOC) += davinci/
+obj-$(CONFIG_SND_SOC) += ep93xx/
obj-$(CONFIG_SND_SOC) += fsl/
obj-$(CONFIG_SND_SOC) += imx/
+obj-$(CONFIG_SND_SOC) += jz4740/
+obj-$(CONFIG_SND_SOC) += nuc900/
obj-$(CONFIG_SND_SOC) += omap/
+obj-$(CONFIG_SND_SOC) += kirkwood/
obj-$(CONFIG_SND_SOC) += pxa/
obj-$(CONFIG_SND_SOC) += s3c24xx/
obj-$(CONFIG_SND_SOC) += s6000/
diff --git a/sound/soc/atmel/atmel-pcm.c b/sound/soc/atmel/atmel-pcm.c
index f6b3cc04b34..dc5249fba85 100644
--- a/sound/soc/atmel/atmel-pcm.c
+++ b/sound/soc/atmel/atmel-pcm.c
@@ -77,7 +77,6 @@ struct atmel_runtime_data {
size_t period_size;
dma_addr_t period_ptr; /* physical address of next period */
- int periods; /* period index of period_ptr */
/* PDC register save */
u32 pdc_xpr_save;
diff --git a/sound/soc/atmel/atmel_ssc_dai.c b/sound/soc/atmel/atmel_ssc_dai.c
index 0b59806905d..c85844d4845 100644
--- a/sound/soc/atmel/atmel_ssc_dai.c
+++ b/sound/soc/atmel/atmel_ssc_dai.c
@@ -549,7 +549,6 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream,
printk(KERN_WARNING "atmel_ssc_dai: unsupported DAI format 0x%x\n",
ssc_p->daifmt);
return -EINVAL;
- break;
}
pr_debug("atmel_ssc_hw_params: "
"RCMR=%08x RFMR=%08x TCMR=%08x TFMR=%08x\n",
diff --git a/sound/soc/au1x/psc-ac97.c b/sound/soc/au1x/psc-ac97.c
index a61ccd2d505..d14a5a91a46 100644
--- a/sound/soc/au1x/psc-ac97.c
+++ b/sound/soc/au1x/psc-ac97.c
@@ -375,12 +375,10 @@ static int __devinit au1xpsc_ac97_drvprobe(struct platform_device *pdev)
}
ret = -EBUSY;
- wd->ioarea = request_mem_region(r->start, r->end - r->start + 1,
- "au1xpsc_ac97");
- if (!wd->ioarea)
+ if (!request_mem_region(r->start, resource_size(r), pdev->name))
goto out0;
- wd->mmio = ioremap(r->start, 0xffff);
+ wd->mmio = ioremap(r->start, resource_size(r));
if (!wd->mmio)
goto out1;
@@ -410,8 +408,7 @@ static int __devinit au1xpsc_ac97_drvprobe(struct platform_device *pdev)
snd_soc_unregister_dai(&au1xpsc_ac97_dai);
out1:
- release_resource(wd->ioarea);
- kfree(wd->ioarea);
+ release_mem_region(r->start, resource_size(r));
out0:
kfree(wd);
return ret;
@@ -420,6 +417,7 @@ out0:
static int __devexit au1xpsc_ac97_drvremove(struct platform_device *pdev)
{
struct au1xpsc_audio_data *wd = platform_get_drvdata(pdev);
+ struct resource *r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (wd->dmapd)
au1xpsc_pcm_destroy(wd->dmapd);
@@ -433,8 +431,7 @@ static int __devexit au1xpsc_ac97_drvremove(struct platform_device *pdev)
au_sync();
iounmap(wd->mmio);
- release_resource(wd->ioarea);
- kfree(wd->ioarea);
+ release_mem_region(r->start, resource_size(r));
kfree(wd);
au1xpsc_ac97_workdata = NULL; /* MDEV */
diff --git a/sound/soc/au1x/psc-i2s.c b/sound/soc/au1x/psc-i2s.c
index 24454c98d0e..6083fe7799f 100644
--- a/sound/soc/au1x/psc-i2s.c
+++ b/sound/soc/au1x/psc-i2s.c
@@ -321,12 +321,10 @@ static int __devinit au1xpsc_i2s_drvprobe(struct platform_device *pdev)
}
ret = -EBUSY;
- wd->ioarea = request_mem_region(r->start, r->end - r->start + 1,
- "au1xpsc_i2s");
- if (!wd->ioarea)
+ if (!request_mem_region(r->start, resource_size(r), pdev->name))
goto out0;
- wd->mmio = ioremap(r->start, 0xffff);
+ wd->mmio = ioremap(r->start, resource_size(r));
if (!wd->mmio)
goto out1;
@@ -362,8 +360,7 @@ static int __devinit au1xpsc_i2s_drvprobe(struct platform_device *pdev)
snd_soc_unregister_dai(&au1xpsc_i2s_dai);
out1:
- release_resource(wd->ioarea);
- kfree(wd->ioarea);
+ release_mem_region(r->start, resource_size(r));
out0:
kfree(wd);
return ret;
@@ -372,6 +369,7 @@ out0:
static int __devexit au1xpsc_i2s_drvremove(struct platform_device *pdev)
{
struct au1xpsc_audio_data *wd = platform_get_drvdata(pdev);
+ struct resource *r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (wd->dmapd)
au1xpsc_pcm_destroy(wd->dmapd);
@@ -384,8 +382,7 @@ static int __devexit au1xpsc_i2s_drvremove(struct platform_device *pdev)
au_sync();
iounmap(wd->mmio);
- release_resource(wd->ioarea);
- kfree(wd->ioarea);
+ release_mem_region(r->start, resource_size(r));
kfree(wd);
au1xpsc_i2s_workdata = NULL; /* MDEV */
diff --git a/sound/soc/au1x/psc.h b/sound/soc/au1x/psc.h
index 32d3807d3f5..093775d4dc3 100644
--- a/sound/soc/au1x/psc.h
+++ b/sound/soc/au1x/psc.h
@@ -32,7 +32,6 @@ struct au1xpsc_audio_data {
unsigned long rate;
unsigned long pm[2];
- struct resource *ioarea;
struct mutex lock;
struct platform_device *dmapd;
};
diff --git a/sound/soc/blackfin/bf5xx-ac97.c b/sound/soc/blackfin/bf5xx-ac97.c
index 523b7fc33f4..c0eba510998 100644
--- a/sound/soc/blackfin/bf5xx-ac97.c
+++ b/sound/soc/blackfin/bf5xx-ac97.c
@@ -255,8 +255,7 @@ EXPORT_SYMBOL_GPL(soc_ac97_ops);
#ifdef CONFIG_PM
static int bf5xx_ac97_suspend(struct snd_soc_dai *dai)
{
- struct sport_device *sport =
- (struct sport_device *)dai->private_data;
+ struct sport_device *sport = dai->private_data;
pr_debug("%s : sport %d\n", __func__, dai->id);
if (!dai->active)
@@ -271,8 +270,7 @@ static int bf5xx_ac97_suspend(struct snd_soc_dai *dai)
static int bf5xx_ac97_resume(struct snd_soc_dai *dai)
{
int ret;
- struct sport_device *sport =
- (struct sport_device *)dai->private_data;
+ struct sport_device *sport = dai->private_data;
pr_debug("%s : sport %d\n", __func__, dai->id);
if (!dai->active)
diff --git a/sound/soc/blackfin/bf5xx-tdm.c b/sound/soc/blackfin/bf5xx-tdm.c
index 4b360124083..24c14269f4b 100644
--- a/sound/soc/blackfin/bf5xx-tdm.c
+++ b/sound/soc/blackfin/bf5xx-tdm.c
@@ -210,8 +210,7 @@ static int bf5xx_tdm_set_channel_map(struct snd_soc_dai *dai,
#ifdef CONFIG_PM
static int bf5xx_tdm_suspend(struct snd_soc_dai *dai)
{
- struct sport_device *sport =
- (struct sport_device *)dai->private_data;
+ struct sport_device *sport = dai->private_data;
if (!dai->active)
return 0;
@@ -225,8 +224,7 @@ static int bf5xx_tdm_suspend(struct snd_soc_dai *dai)
static int bf5xx_tdm_resume(struct snd_soc_dai *dai)
{
int ret;
- struct sport_device *sport =
- (struct sport_device *)dai->private_data;
+ struct sport_device *sport = dai->private_data;
if (!dai->active)
return 0;
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index 5da30eb6ad0..83f5c67d3c4 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -22,9 +22,11 @@ config SND_SOC_ALL_CODECS
select SND_SOC_AK4642 if I2C
select SND_SOC_AK4671 if I2C
select SND_SOC_CQ0093VC if MFD_DAVINCI_VOICECODEC
+ select SND_SOC_CS42L51 if I2C
select SND_SOC_CS4270 if I2C
- select SND_SOC_MAX9877 if I2C
select SND_SOC_DA7210 if I2C
+ select SND_SOC_JZ4740 if SOC_JZ4740
+ select SND_SOC_MAX9877 if I2C
select SND_SOC_PCM3008
select SND_SOC_SPDIF
select SND_SOC_SSM2602 if I2C
@@ -48,6 +50,7 @@ config SND_SOC_ALL_CODECS
select SND_SOC_WM8727
select SND_SOC_WM8728 if SND_SOC_I2C_AND_SPI
select SND_SOC_WM8731 if SND_SOC_I2C_AND_SPI
+ select SND_SOC_WM8741 if SND_SOC_I2C_AND_SPI
select SND_SOC_WM8750 if SND_SOC_I2C_AND_SPI
select SND_SOC_WM8753 if SND_SOC_I2C_AND_SPI
select SND_SOC_WM8776 if SND_SOC_I2C_AND_SPI
@@ -120,13 +123,13 @@ config SND_SOC_AK4671
config SND_SOC_CQ0093VC
tristate
+config SND_SOC_CS42L51
+ tristate
+
# Cirrus Logic CS4270 Codec
config SND_SOC_CS4270
tristate
-config SND_SOC_DA7210
- tristate
-
# Cirrus Logic CS4270 Codec VD = 3.3V Errata
# Select if you are affected by the errata where the part will not function
# if MCLK divide-by-1.5 is selected and VD is set to 3.3V. The driver will
@@ -138,9 +141,15 @@ config SND_SOC_CS4270_VD33_ERRATA
config SND_SOC_CX20442
tristate
+config SND_SOC_JZ4740_CODEC
+ tristate
+
config SND_SOC_L3
tristate
+config SND_SOC_DA7210
+ tristate
+
config SND_SOC_PCM3008
tristate
@@ -206,6 +215,9 @@ config SND_SOC_WM8728
config SND_SOC_WM8731
tristate
+config SND_SOC_WM8741
+ tristate
+
config SND_SOC_WM8750
tristate
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index 91429eab070..53524095759 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -9,6 +9,7 @@ snd-soc-ak4535-objs := ak4535.o
snd-soc-ak4642-objs := ak4642.o
snd-soc-ak4671-objs := ak4671.o
snd-soc-cq93vc-objs := cq93vc.o
+snd-soc-cs42l51-objs := cs42l51.o
snd-soc-cs4270-objs := cs4270.o
snd-soc-cx20442-objs := cx20442.o
snd-soc-da7210-objs := da7210.o
@@ -34,6 +35,7 @@ snd-soc-wm8711-objs := wm8711.o
snd-soc-wm8727-objs := wm8727.o
snd-soc-wm8728-objs := wm8728.o
snd-soc-wm8731-objs := wm8731.o
+snd-soc-wm8741-objs := wm8741.o
snd-soc-wm8750-objs := wm8750.o
snd-soc-wm8753-objs := wm8753.o
snd-soc-wm8776-objs := wm8776.o
@@ -56,6 +58,7 @@ snd-soc-wm9705-objs := wm9705.o
snd-soc-wm9712-objs := wm9712.o
snd-soc-wm9713-objs := wm9713.o
snd-soc-wm-hubs-objs := wm_hubs.o
+snd-soc-jz4740-codec-objs := jz4740.o
# Amp
snd-soc-max9877-objs := max9877.o
@@ -74,10 +77,12 @@ obj-$(CONFIG_SND_SOC_AK4535) += snd-soc-ak4535.o
obj-$(CONFIG_SND_SOC_AK4642) += snd-soc-ak4642.o
obj-$(CONFIG_SND_SOC_AK4671) += snd-soc-ak4671.o
obj-$(CONFIG_SND_SOC_CQ0093VC) += snd-soc-cq93vc.o
+obj-$(CONFIG_SND_SOC_CS42L51) += snd-soc-cs42l51.o
obj-$(CONFIG_SND_SOC_CS4270) += snd-soc-cs4270.o
obj-$(CONFIG_SND_SOC_CX20442) += snd-soc-cx20442.o
obj-$(CONFIG_SND_SOC_DA7210) += snd-soc-da7210.o
obj-$(CONFIG_SND_SOC_L3) += snd-soc-l3.o
+obj-$(CONFIG_SND_SOC_JZ4740_CODEC) += snd-soc-jz4740-codec.o
obj-$(CONFIG_SND_SOC_PCM3008) += snd-soc-pcm3008.o
obj-$(CONFIG_SND_SOC_SPDIF) += snd-soc-spdif.o
obj-$(CONFIG_SND_SOC_SSM2602) += snd-soc-ssm2602.o
@@ -99,6 +104,7 @@ obj-$(CONFIG_SND_SOC_WM8711) += snd-soc-wm8711.o
obj-$(CONFIG_SND_SOC_WM8727) += snd-soc-wm8727.o
obj-$(CONFIG_SND_SOC_WM8728) += snd-soc-wm8728.o
obj-$(CONFIG_SND_SOC_WM8731) += snd-soc-wm8731.o
+obj-$(CONFIG_SND_SOC_WM8741) += snd-soc-wm8741.o
obj-$(CONFIG_SND_SOC_WM8750) += snd-soc-wm8750.o
obj-$(CONFIG_SND_SOC_WM8753) += snd-soc-wm8753.o
obj-$(CONFIG_SND_SOC_WM8776) += snd-soc-wm8776.o
diff --git a/sound/soc/codecs/ad1836.c b/sound/soc/codecs/ad1836.c
index 21753842322..a01006c8c60 100644
--- a/sound/soc/codecs/ad1836.c
+++ b/sound/soc/codecs/ad1836.c
@@ -272,6 +272,7 @@ static int ad1836_register(struct ad1836_priv *ad1836)
if (ad1836_codec) {
dev_err(codec->dev, "Another ad1836 is registered\n");
+ kfree(ad1836);
return -EINVAL;
}
diff --git a/sound/soc/codecs/ad193x.c b/sound/soc/codecs/ad193x.c
index c8ca1142b2f..1def75e4862 100644
--- a/sound/soc/codecs/ad193x.c
+++ b/sound/soc/codecs/ad193x.c
@@ -24,6 +24,7 @@
/* codec private data */
struct ad193x_priv {
+ unsigned int sysclk;
struct snd_soc_codec codec;
u8 reg_cache[AD193X_NUM_REGS];
};
@@ -251,15 +252,32 @@ static int ad193x_set_dai_fmt(struct snd_soc_dai *codec_dai,
return 0;
}
+static int ad193x_set_dai_sysclk(struct snd_soc_dai *codec_dai,
+ int clk_id, unsigned int freq, int dir)
+{
+ struct snd_soc_codec *codec = codec_dai->codec;
+ struct ad193x_priv *ad193x = snd_soc_codec_get_drvdata(codec);
+ switch (freq) {
+ case 12288000:
+ case 18432000:
+ case 24576000:
+ case 36864000:
+ ad193x->sysclk = freq;
+ return 0;
+ }
+ return -EINVAL;
+}
+
static int ad193x_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
- int word_len = 0, reg = 0;
+ int word_len = 0, reg = 0, master_rate = 0;
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_device *socdev = rtd->socdev;
struct snd_soc_codec *codec = socdev->card->codec;
+ struct ad193x_priv *ad193x = snd_soc_codec_get_drvdata(codec);
/* bit size */
switch (params_format(params)) {
@@ -275,6 +293,25 @@ static int ad193x_hw_params(struct snd_pcm_substream *substream,
break;
}
+ switch (ad193x->sysclk) {
+ case 12288000:
+ master_rate = AD193X_PLL_INPUT_256;
+ break;
+ case 18432000:
+ master_rate = AD193X_PLL_INPUT_384;
+ break;
+ case 24576000:
+ master_rate = AD193X_PLL_INPUT_512;
+ break;
+ case 36864000:
+ master_rate = AD193X_PLL_INPUT_768;
+ break;
+ }
+
+ reg = snd_soc_read(codec, AD193X_PLL_CLK_CTRL0);
+ reg = (reg & AD193X_PLL_INPUT_MASK) | master_rate;
+ snd_soc_write(codec, AD193X_PLL_CLK_CTRL0, reg);
+
reg = snd_soc_read(codec, AD193X_DAC_CTRL2);
reg = (reg & (~AD193X_DAC_WORD_LEN_MASK)) | word_len;
snd_soc_write(codec, AD193X_DAC_CTRL2, reg);
@@ -348,6 +385,7 @@ static int ad193x_bus_probe(struct device *dev, void *ctrl_data, int bus_type)
/* pll input: mclki/xi */
snd_soc_write(codec, AD193X_PLL_CLK_CTRL0, 0x99); /* mclk=24.576Mhz: 0x9D; mclk=12.288Mhz: 0x99 */
snd_soc_write(codec, AD193X_PLL_CLK_CTRL1, 0x04);
+ ad193x->sysclk = 12288000;
ret = snd_soc_register_codec(codec);
if (ret != 0) {
@@ -383,6 +421,7 @@ static struct snd_soc_dai_ops ad193x_dai_ops = {
.hw_params = ad193x_hw_params,
.digital_mute = ad193x_mute,
.set_tdm_slot = ad193x_set_tdm_slot,
+ .set_sysclk = ad193x_set_dai_sysclk,
.set_fmt = ad193x_set_dai_fmt,
};
diff --git a/sound/soc/codecs/ad193x.h b/sound/soc/codecs/ad193x.h
index a03c880d52f..654ba64ae04 100644
--- a/sound/soc/codecs/ad193x.h
+++ b/sound/soc/codecs/ad193x.h
@@ -11,6 +11,11 @@
#define AD193X_PLL_CLK_CTRL0 0x800
#define AD193X_PLL_POWERDOWN 0x01
+#define AD193X_PLL_INPUT_MASK (~0x6)
+#define AD193X_PLL_INPUT_256 (0 << 1)
+#define AD193X_PLL_INPUT_384 (1 << 1)
+#define AD193X_PLL_INPUT_512 (2 << 1)
+#define AD193X_PLL_INPUT_768 (3 << 1)
#define AD193X_PLL_CLK_CTRL1 0x801
#define AD193X_DAC_CTRL0 0x802
#define AD193X_DAC_POWERDOWN 0x01
diff --git a/sound/soc/codecs/ak4642.c b/sound/soc/codecs/ak4642.c
index 7528a54102b..3d7dc55305e 100644
--- a/sound/soc/codecs/ak4642.c
+++ b/sound/soc/codecs/ak4642.c
@@ -22,20 +22,13 @@
* AK4643 is tested.
*/
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/init.h>
#include <linux/delay.h>
-#include <linux/pm.h>
#include <linux/i2c.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-#include <sound/soc.h>
#include <sound/soc-dapm.h>
#include <sound/initval.h>
+#include <sound/tlv.h>
#include "ak4642.h"
@@ -111,6 +104,23 @@
struct snd_soc_codec_device soc_codec_dev_ak4642;
+/*
+ * Playback Volume (table 39)
+ *
+ * max : 0x00 : +12.0 dB
+ * ( 0.5 dB step )
+ * min : 0xFE : -115.0 dB
+ * mute: 0xFF
+ */
+static const DECLARE_TLV_DB_SCALE(out_tlv, -11500, 50, 1);
+
+static const struct snd_kcontrol_new ak4642_snd_controls[] = {
+
+ SOC_DOUBLE_R_TLV("Digital Playback Volume", L_DVC, R_DVC,
+ 0, 0xFF, 1, out_tlv),
+};
+
+
/* codec private data */
struct ak4642_priv {
struct snd_soc_codec codec;
@@ -204,7 +214,6 @@ static int ak4642_dai_startup(struct snd_pcm_substream *substream,
*
* PLL, Master Mode
* Audio I/F Format :MSB justified (ADC & DAC)
- * Digital Volume: -8dB
* Bass Boost Level : Middle
*
* This operation came from example code of
@@ -214,8 +223,6 @@ static int ak4642_dai_startup(struct snd_pcm_substream *substream,
ak4642_write(codec, 0x0e, 0x19);
ak4642_write(codec, 0x09, 0x91);
ak4642_write(codec, 0x0c, 0x91);
- ak4642_write(codec, 0x0a, 0x28);
- ak4642_write(codec, 0x0d, 0x28);
ak4642_write(codec, 0x00, 0x64);
snd_soc_update_bits(codec, PW_MGMT2, PMHP_MASK, PMHP);
snd_soc_update_bits(codec, PW_MGMT2, HPMTN, HPMTN);
@@ -491,8 +498,10 @@ static int ak4642_i2c_probe(struct i2c_client *i2c,
codec->control_data = i2c;
ret = ak4642_init(ak4642);
- if (ret < 0)
+ if (ret < 0) {
printk(KERN_ERR "failed to initialise AK4642\n");
+ kfree(ak4642);
+ }
return ret;
}
@@ -548,6 +557,9 @@ static int ak4642_probe(struct platform_device *pdev)
goto pcm_err;
}
+ snd_soc_add_controls(ak4642_codec, ak4642_snd_controls,
+ ARRAY_SIZE(ak4642_snd_controls));
+
dev_info(&pdev->dev, "AK4642 Audio Codec %s", AK4642_VERSION);
return ret;
diff --git a/sound/soc/codecs/cs42l51.c b/sound/soc/codecs/cs42l51.c
new file mode 100644
index 00000000000..dd9b8550c40
--- /dev/null
+++ b/sound/soc/codecs/cs42l51.c
@@ -0,0 +1,763 @@
+/*
+ * cs42l51.c
+ *
+ * ASoC Driver for Cirrus Logic CS42L51 codecs
+ *
+ * Copyright (c) 2010 Arnaud Patard <apatard@mandriva.com>
+ *
+ * Based on cs4270.c - Copyright (c) Freescale Semiconductor
+ *
+ * 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.
+ *
+ * For now:
+ * - Only I2C is support. Not SPI
+ * - master mode *NOT* supported
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/tlv.h>
+#include <sound/initval.h>
+#include <sound/pcm_params.h>
+#include <sound/pcm.h>
+#include <linux/i2c.h>
+
+#include "cs42l51.h"
+
+enum master_slave_mode {
+ MODE_SLAVE,
+ MODE_SLAVE_AUTO,
+ MODE_MASTER,
+};
+
+struct cs42l51_private {
+ unsigned int mclk;
+ unsigned int audio_mode; /* The mode (I2S or left-justified) */
+ enum master_slave_mode func;
+ struct snd_soc_codec codec;
+ u8 reg_cache[CS42L51_NUMREGS];
+};
+
+static struct snd_soc_codec *cs42l51_codec;
+
+#define CS42L51_FORMATS ( \
+ SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE | \
+ SNDRV_PCM_FMTBIT_S18_3LE | SNDRV_PCM_FMTBIT_S18_3BE | \
+ SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S20_3BE | \
+ SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S24_BE)
+
+static int cs42l51_fill_cache(struct snd_soc_codec *codec)
+{
+ u8 *cache = codec->reg_cache + 1;
+ struct i2c_client *i2c_client = codec->control_data;
+ s32 length;
+
+ length = i2c_smbus_read_i2c_block_data(i2c_client,
+ CS42L51_FIRSTREG | 0x80, CS42L51_NUMREGS, cache);
+ if (length != CS42L51_NUMREGS) {
+ dev_err(&i2c_client->dev,
+ "I2C read failure, addr=0x%x (ret=%d vs %d)\n",
+ i2c_client->addr, length, CS42L51_NUMREGS);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int cs42l51_i2c_probe(struct i2c_client *i2c_client,
+ const struct i2c_device_id *id)
+{
+ struct snd_soc_codec *codec;
+ struct cs42l51_private *cs42l51;
+ int ret = 0;
+ int reg;
+
+ if (cs42l51_codec)
+ return -EBUSY;
+
+ /* Verify that we have a CS42L51 */
+ ret = i2c_smbus_read_byte_data(i2c_client, CS42L51_CHIP_REV_ID);
+ if (ret < 0) {
+ dev_err(&i2c_client->dev, "failed to read I2C\n");
+ goto error;
+ }
+
+ if ((ret != CS42L51_MK_CHIP_REV(CS42L51_CHIP_ID, CS42L51_CHIP_REV_A)) &&
+ (ret != CS42L51_MK_CHIP_REV(CS42L51_CHIP_ID, CS42L51_CHIP_REV_B))) {
+ dev_err(&i2c_client->dev, "Invalid chip id\n");
+ ret = -ENODEV;
+ goto error;
+ }
+
+ dev_info(&i2c_client->dev, "found device cs42l51 rev %d\n",
+ ret & 7);
+
+ cs42l51 = kzalloc(sizeof(struct cs42l51_private), GFP_KERNEL);
+ if (!cs42l51) {
+ dev_err(&i2c_client->dev, "could not allocate codec\n");
+ return -ENOMEM;
+ }
+ codec = &cs42l51->codec;
+
+ mutex_init(&codec->mutex);
+ INIT_LIST_HEAD(&codec->dapm_widgets);
+ INIT_LIST_HEAD(&codec->dapm_paths);
+
+ codec->dev = &i2c_client->dev;
+ codec->name = "CS42L51";
+ codec->owner = THIS_MODULE;
+ codec->dai = &cs42l51_dai;
+ codec->num_dai = 1;
+ snd_soc_codec_set_drvdata(codec, cs42l51);
+
+ codec->control_data = i2c_client;
+ codec->reg_cache = cs42l51->reg_cache;
+ codec->reg_cache_size = CS42L51_NUMREGS;
+ i2c_set_clientdata(i2c_client, codec);
+
+ ret = cs42l51_fill_cache(codec);
+ if (ret < 0) {
+ dev_err(&i2c_client->dev, "failed to fill register cache\n");
+ goto error_alloc;
+ }
+
+ ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_I2C);
+ if (ret < 0) {
+ dev_err(&i2c_client->dev, "Failed to set cache I/O: %d\n", ret);
+ goto error_alloc;
+ }
+
+ /*
+ * DAC configuration
+ * - Use signal processor
+ * - auto mute
+ * - vol changes immediate
+ * - no de-emphasize
+ */
+ reg = CS42L51_DAC_CTL_DATA_SEL(1)
+ | CS42L51_DAC_CTL_AMUTE | CS42L51_DAC_CTL_DACSZ(0);
+ ret = snd_soc_write(codec, CS42L51_DAC_CTL, reg);
+ if (ret < 0)
+ goto error_alloc;
+
+ cs42l51_dai.dev = codec->dev;
+ cs42l51_codec = codec;
+
+ ret = snd_soc_register_codec(codec);
+ if (ret != 0) {
+ dev_err(codec->dev, "Failed to register codec: %d\n", ret);
+ goto error_alloc;
+ }
+
+ ret = snd_soc_register_dai(&cs42l51_dai);
+ if (ret < 0) {
+ dev_err(&i2c_client->dev, "failed to register DAIe\n");
+ goto error_reg;
+ }
+
+ return 0;
+
+error_reg:
+ snd_soc_unregister_codec(codec);
+error_alloc:
+ kfree(cs42l51);
+error:
+ return ret;
+}
+
+static int cs42l51_i2c_remove(struct i2c_client *client)
+{
+ struct cs42l51_private *cs42l51 = i2c_get_clientdata(client);
+ snd_soc_unregister_dai(&cs42l51_dai);
+ snd_soc_unregister_codec(cs42l51_codec);
+ cs42l51_codec = NULL;
+ kfree(cs42l51);
+ return 0;
+}
+
+
+static const struct i2c_device_id cs42l51_id[] = {
+ {"cs42l51", 0},
+ {}
+};
+MODULE_DEVICE_TABLE(i2c, cs42l51_id);
+
+static struct i2c_driver cs42l51_i2c_driver = {
+ .driver = {
+ .name = "CS42L51 I2C",
+ .owner = THIS_MODULE,
+ },
+ .id_table = cs42l51_id,
+ .probe = cs42l51_i2c_probe,
+ .remove = cs42l51_i2c_remove,
+};
+
+static int cs42l51_get_chan_mix(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ unsigned long value = snd_soc_read(codec, CS42L51_PCM_MIXER)&3;
+
+ switch (value) {
+ default:
+ case 0:
+ ucontrol->value.integer.value[0] = 0;
+ break;
+ /* same value : (L+R)/2 and (R+L)/2 */
+ case 1:
+ case 2:
+ ucontrol->value.integer.value[0] = 1;
+ break;
+ case 3:
+ ucontrol->value.integer.value[0] = 2;
+ break;
+ }
+
+ return 0;
+}
+
+#define CHAN_MIX_NORMAL 0x00
+#define CHAN_MIX_BOTH 0x55
+#define CHAN_MIX_SWAP 0xFF
+
+static int cs42l51_set_chan_mix(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ unsigned char val;
+
+ switch (ucontrol->value.integer.value[0]) {
+ default:
+ case 0:
+ val = CHAN_MIX_NORMAL;
+ break;
+ case 1:
+ val = CHAN_MIX_BOTH;
+ break;
+ case 2:
+ val = CHAN_MIX_SWAP;
+ break;
+ }
+
+ snd_soc_write(codec, CS42L51_PCM_MIXER, val);
+
+ return 1;
+}
+
+static const DECLARE_TLV_DB_SCALE(adc_pcm_tlv, -5150, 50, 0);
+static const DECLARE_TLV_DB_SCALE(tone_tlv, -1050, 150, 0);
+/* This is a lie. after -102 db, it stays at -102 */
+/* maybe a range would be better */
+static const DECLARE_TLV_DB_SCALE(aout_tlv, -11550, 50, 0);
+
+static const DECLARE_TLV_DB_SCALE(boost_tlv, 1600, 1600, 0);
+static const char *chan_mix[] = {
+ "L R",
+ "L+R",
+ "R L",
+};
+
+static const struct soc_enum cs42l51_chan_mix =
+ SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(chan_mix), chan_mix);
+
+static const struct snd_kcontrol_new cs42l51_snd_controls[] = {
+ SOC_DOUBLE_R_SX_TLV("PCM Playback Volume",
+ CS42L51_PCMA_VOL, CS42L51_PCMB_VOL,
+ 7, 0xffffff99, 0x18, adc_pcm_tlv),
+ SOC_DOUBLE_R("PCM Playback Switch",
+ CS42L51_PCMA_VOL, CS42L51_PCMB_VOL, 7, 1, 1),
+ SOC_DOUBLE_R_SX_TLV("Analog Playback Volume",
+ CS42L51_AOUTA_VOL, CS42L51_AOUTB_VOL,
+ 8, 0xffffff19, 0x18, aout_tlv),
+ SOC_DOUBLE_R_SX_TLV("ADC Mixer Volume",
+ CS42L51_ADCA_VOL, CS42L51_ADCB_VOL,
+ 7, 0xffffff99, 0x18, adc_pcm_tlv),
+ SOC_DOUBLE_R("ADC Mixer Switch",
+ CS42L51_ADCA_VOL, CS42L51_ADCB_VOL, 7, 1, 1),
+ SOC_SINGLE("Playback Deemphasis Switch", CS42L51_DAC_CTL, 3, 1, 0),
+ SOC_SINGLE("Auto-Mute Switch", CS42L51_DAC_CTL, 2, 1, 0),
+ SOC_SINGLE("Soft Ramp Switch", CS42L51_DAC_CTL, 1, 1, 0),
+ SOC_SINGLE("Zero Cross Switch", CS42L51_DAC_CTL, 0, 0, 0),
+ SOC_DOUBLE_TLV("Mic Boost Volume",
+ CS42L51_MIC_CTL, 0, 1, 1, 0, boost_tlv),
+ SOC_SINGLE_TLV("Bass Volume", CS42L51_TONE_CTL, 0, 0xf, 1, tone_tlv),
+ SOC_SINGLE_TLV("Treble Volume", CS42L51_TONE_CTL, 4, 0xf, 1, tone_tlv),
+ SOC_ENUM_EXT("PCM channel mixer",
+ cs42l51_chan_mix,
+ cs42l51_get_chan_mix, cs42l51_set_chan_mix),
+};
+
+/*
+ * to power down, one must:
+ * 1.) Enable the PDN bit
+ * 2.) enable power-down for the select channels
+ * 3.) disable the PDN bit.
+ */
+static int cs42l51_pdn_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ unsigned long value;
+
+ value = snd_soc_read(w->codec, CS42L51_POWER_CTL1);
+ value &= ~CS42L51_POWER_CTL1_PDN;
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMD:
+ value |= CS42L51_POWER_CTL1_PDN;
+ break;
+ default:
+ case SND_SOC_DAPM_POST_PMD:
+ break;
+ }
+ snd_soc_update_bits(w->codec, CS42L51_POWER_CTL1,
+ CS42L51_POWER_CTL1_PDN, value);
+
+ return 0;
+}
+
+static const char *cs42l51_dac_names[] = {"Direct PCM",
+ "DSP PCM", "ADC"};
+static const struct soc_enum cs42l51_dac_mux_enum =
+ SOC_ENUM_SINGLE(CS42L51_DAC_CTL, 6, 3, cs42l51_dac_names);
+static const struct snd_kcontrol_new cs42l51_dac_mux_controls =
+ SOC_DAPM_ENUM("Route", cs42l51_dac_mux_enum);
+
+static const char *cs42l51_adcl_names[] = {"AIN1 Left", "AIN2 Left",
+ "MIC Left", "MIC+preamp Left"};
+static const struct soc_enum cs42l51_adcl_mux_enum =
+ SOC_ENUM_SINGLE(CS42L51_ADC_INPUT, 4, 4, cs42l51_adcl_names);
+static const struct snd_kcontrol_new cs42l51_adcl_mux_controls =
+ SOC_DAPM_ENUM("Route", cs42l51_adcl_mux_enum);
+
+static const char *cs42l51_adcr_names[] = {"AIN1 Right", "AIN2 Right",
+ "MIC Right", "MIC+preamp Right"};
+static const struct soc_enum cs42l51_adcr_mux_enum =
+ SOC_ENUM_SINGLE(CS42L51_ADC_INPUT, 6, 4, cs42l51_adcr_names);
+static const struct snd_kcontrol_new cs42l51_adcr_mux_controls =
+ SOC_DAPM_ENUM("Route", cs42l51_adcr_mux_enum);
+
+static const struct snd_soc_dapm_widget cs42l51_dapm_widgets[] = {
+ SND_SOC_DAPM_MICBIAS("Mic Bias", CS42L51_MIC_POWER_CTL, 1, 1),
+ SND_SOC_DAPM_PGA_E("Left PGA", CS42L51_POWER_CTL1, 3, 1, NULL, 0,
+ cs42l51_pdn_event, SND_SOC_DAPM_PRE_POST_PMD),
+ SND_SOC_DAPM_PGA_E("Right PGA", CS42L51_POWER_CTL1, 4, 1, NULL, 0,
+ cs42l51_pdn_event, SND_SOC_DAPM_PRE_POST_PMD),
+ SND_SOC_DAPM_ADC_E("Left ADC", "Left HiFi Capture",
+ CS42L51_POWER_CTL1, 1, 1,
+ cs42l51_pdn_event, SND_SOC_DAPM_PRE_POST_PMD),
+ SND_SOC_DAPM_ADC_E("Right ADC", "Right HiFi Capture",
+ CS42L51_POWER_CTL1, 2, 1,
+ cs42l51_pdn_event, SND_SOC_DAPM_PRE_POST_PMD),
+ SND_SOC_DAPM_DAC_E("Left DAC", "Left HiFi Playback",
+ CS42L51_POWER_CTL1, 5, 1,
+ cs42l51_pdn_event, SND_SOC_DAPM_PRE_POST_PMD),
+ SND_SOC_DAPM_DAC_E("Right DAC", "Right HiFi Playback",
+ CS42L51_POWER_CTL1, 6, 1,
+ cs42l51_pdn_event, SND_SOC_DAPM_PRE_POST_PMD),
+
+ /* analog/mic */
+ SND_SOC_DAPM_INPUT("AIN1L"),
+ SND_SOC_DAPM_INPUT("AIN1R"),
+ SND_SOC_DAPM_INPUT("AIN2L"),
+ SND_SOC_DAPM_INPUT("AIN2R"),
+ SND_SOC_DAPM_INPUT("MICL"),
+ SND_SOC_DAPM_INPUT("MICR"),
+
+ SND_SOC_DAPM_MIXER("Mic Preamp Left",
+ CS42L51_MIC_POWER_CTL, 2, 1, NULL, 0),
+ SND_SOC_DAPM_MIXER("Mic Preamp Right",
+ CS42L51_MIC_POWER_CTL, 3, 1, NULL, 0),
+
+ /* HP */
+ SND_SOC_DAPM_OUTPUT("HPL"),
+ SND_SOC_DAPM_OUTPUT("HPR"),
+
+ /* mux */
+ SND_SOC_DAPM_MUX("DAC Mux", SND_SOC_NOPM, 0, 0,
+ &cs42l51_dac_mux_controls),
+ SND_SOC_DAPM_MUX("PGA-ADC Mux Left", SND_SOC_NOPM, 0, 0,
+ &cs42l51_adcl_mux_controls),
+ SND_SOC_DAPM_MUX("PGA-ADC Mux Right", SND_SOC_NOPM, 0, 0,
+ &cs42l51_adcr_mux_controls),
+};
+
+static const struct snd_soc_dapm_route cs42l51_routes[] = {
+ {"HPL", NULL, "Left DAC"},
+ {"HPR", NULL, "Right DAC"},
+
+ {"Left ADC", NULL, "Left PGA"},
+ {"Right ADC", NULL, "Right PGA"},
+
+ {"Mic Preamp Left", NULL, "MICL"},
+ {"Mic Preamp Right", NULL, "MICR"},
+
+ {"PGA-ADC Mux Left", "AIN1 Left", "AIN1L" },
+ {"PGA-ADC Mux Left", "AIN2 Left", "AIN2L" },
+ {"PGA-ADC Mux Left", "MIC Left", "MICL" },
+ {"PGA-ADC Mux Left", "MIC+preamp Left", "Mic Preamp Left" },
+ {"PGA-ADC Mux Right", "AIN1 Right", "AIN1R" },
+ {"PGA-ADC Mux Right", "AIN2 Right", "AIN2R" },
+ {"PGA-ADC Mux Right", "MIC Right", "MICR" },
+ {"PGA-ADC Mux Right", "MIC+preamp Right", "Mic Preamp Right" },
+
+ {"Left PGA", NULL, "PGA-ADC Mux Left"},
+ {"Right PGA", NULL, "PGA-ADC Mux Right"},
+};
+
+static int cs42l51_set_dai_fmt(struct snd_soc_dai *codec_dai,
+ unsigned int format)
+{
+ struct snd_soc_codec *codec = codec_dai->codec;
+ struct cs42l51_private *cs42l51 = snd_soc_codec_get_drvdata(codec);
+ int ret = 0;
+
+ switch (format & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ case SND_SOC_DAIFMT_LEFT_J:
+ case SND_SOC_DAIFMT_RIGHT_J:
+ cs42l51->audio_mode = format & SND_SOC_DAIFMT_FORMAT_MASK;
+ break;
+ default:
+ dev_err(codec->dev, "invalid DAI format\n");
+ ret = -EINVAL;
+ }
+
+ switch (format & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBM_CFM:
+ cs42l51->func = MODE_MASTER;
+ break;
+ case SND_SOC_DAIFMT_CBS_CFS:
+ cs42l51->func = MODE_SLAVE_AUTO;
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+struct cs42l51_ratios {
+ unsigned int ratio;
+ unsigned char speed_mode;
+ unsigned char mclk;
+};
+
+static struct cs42l51_ratios slave_ratios[] = {
+ { 512, CS42L51_QSM_MODE, 0 }, { 768, CS42L51_QSM_MODE, 0 },
+ { 1024, CS42L51_QSM_MODE, 0 }, { 1536, CS42L51_QSM_MODE, 0 },
+ { 2048, CS42L51_QSM_MODE, 0 }, { 3072, CS42L51_QSM_MODE, 0 },
+ { 256, CS42L51_HSM_MODE, 0 }, { 384, CS42L51_HSM_MODE, 0 },
+ { 512, CS42L51_HSM_MODE, 0 }, { 768, CS42L51_HSM_MODE, 0 },
+ { 1024, CS42L51_HSM_MODE, 0 }, { 1536, CS42L51_HSM_MODE, 0 },
+ { 128, CS42L51_SSM_MODE, 0 }, { 192, CS42L51_SSM_MODE, 0 },
+ { 256, CS42L51_SSM_MODE, 0 }, { 384, CS42L51_SSM_MODE, 0 },
+ { 512, CS42L51_SSM_MODE, 0 }, { 768, CS42L51_SSM_MODE, 0 },
+ { 128, CS42L51_DSM_MODE, 0 }, { 192, CS42L51_DSM_MODE, 0 },
+ { 256, CS42L51_DSM_MODE, 0 }, { 384, CS42L51_DSM_MODE, 0 },
+};
+
+static struct cs42l51_ratios slave_auto_ratios[] = {
+ { 1024, CS42L51_QSM_MODE, 0 }, { 1536, CS42L51_QSM_MODE, 0 },
+ { 2048, CS42L51_QSM_MODE, 1 }, { 3072, CS42L51_QSM_MODE, 1 },
+ { 512, CS42L51_HSM_MODE, 0 }, { 768, CS42L51_HSM_MODE, 0 },
+ { 1024, CS42L51_HSM_MODE, 1 }, { 1536, CS42L51_HSM_MODE, 1 },
+ { 256, CS42L51_SSM_MODE, 0 }, { 384, CS42L51_SSM_MODE, 0 },
+ { 512, CS42L51_SSM_MODE, 1 }, { 768, CS42L51_SSM_MODE, 1 },
+ { 128, CS42L51_DSM_MODE, 0 }, { 192, CS42L51_DSM_MODE, 0 },
+ { 256, CS42L51_DSM_MODE, 1 }, { 384, CS42L51_DSM_MODE, 1 },
+};
+
+static int cs42l51_set_dai_sysclk(struct snd_soc_dai *codec_dai,
+ int clk_id, unsigned int freq, int dir)
+{
+ struct snd_soc_codec *codec = codec_dai->codec;
+ struct cs42l51_private *cs42l51 = snd_soc_codec_get_drvdata(codec);
+ struct cs42l51_ratios *ratios = NULL;
+ int nr_ratios = 0;
+ unsigned int rates = 0;
+ unsigned int rate_min = -1;
+ unsigned int rate_max = 0;
+ int i;
+
+ cs42l51->mclk = freq;
+
+ switch (cs42l51->func) {
+ case MODE_MASTER:
+ return -EINVAL;
+ case MODE_SLAVE:
+ ratios = slave_ratios;
+ nr_ratios = ARRAY_SIZE(slave_ratios);
+ break;
+ case MODE_SLAVE_AUTO:
+ ratios = slave_auto_ratios;
+ nr_ratios = ARRAY_SIZE(slave_auto_ratios);
+ break;
+ }
+
+ for (i = 0; i < nr_ratios; i++) {
+ unsigned int rate = freq / ratios[i].ratio;
+ rates |= snd_pcm_rate_to_rate_bit(rate);
+ if (rate < rate_min)
+ rate_min = rate;
+ if (rate > rate_max)
+ rate_max = rate;
+ }
+ rates &= ~SNDRV_PCM_RATE_KNOT;
+
+ if (!rates) {
+ dev_err(codec->dev, "could not find a valid sample rate\n");
+ return -EINVAL;
+ }
+
+ codec_dai->playback.rates = rates;
+ codec_dai->playback.rate_min = rate_min;
+ codec_dai->playback.rate_max = rate_max;
+
+ codec_dai->capture.rates = rates;
+ codec_dai->capture.rate_min = rate_min;
+ codec_dai->capture.rate_max = rate_max;
+
+ return 0;
+}
+
+static int cs42l51_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_device *socdev = rtd->socdev;
+ struct snd_soc_codec *codec = socdev->card->codec;
+ struct cs42l51_private *cs42l51 = snd_soc_codec_get_drvdata(codec);
+ int ret;
+ unsigned int i;
+ unsigned int rate;
+ unsigned int ratio;
+ struct cs42l51_ratios *ratios = NULL;
+ int nr_ratios = 0;
+ int intf_ctl, power_ctl, fmt;
+
+ switch (cs42l51->func) {
+ case MODE_MASTER:
+ return -EINVAL;
+ case MODE_SLAVE:
+ ratios = slave_ratios;
+ nr_ratios = ARRAY_SIZE(slave_ratios);
+ break;
+ case MODE_SLAVE_AUTO:
+ ratios = slave_auto_ratios;
+ nr_ratios = ARRAY_SIZE(slave_auto_ratios);
+ break;
+ }
+
+ /* Figure out which MCLK/LRCK ratio to use */
+ rate = params_rate(params); /* Sampling rate, in Hz */
+ ratio = cs42l51->mclk / rate; /* MCLK/LRCK ratio */
+ for (i = 0; i < nr_ratios; i++) {
+ if (ratios[i].ratio == ratio)
+ break;
+ }
+
+ if (i == nr_ratios) {
+ /* We did not find a matching ratio */
+ dev_err(codec->dev, "could not find matching ratio\n");
+ return -EINVAL;
+ }
+
+ intf_ctl = snd_soc_read(codec, CS42L51_INTF_CTL);
+ power_ctl = snd_soc_read(codec, CS42L51_MIC_POWER_CTL);
+
+ intf_ctl &= ~(CS42L51_INTF_CTL_MASTER | CS42L51_INTF_CTL_ADC_I2S
+ | CS42L51_INTF_CTL_DAC_FORMAT(7));
+ power_ctl &= ~(CS42L51_MIC_POWER_CTL_SPEED(3)
+ | CS42L51_MIC_POWER_CTL_MCLK_DIV2);
+
+ switch (cs42l51->func) {
+ case MODE_MASTER:
+ intf_ctl |= CS42L51_INTF_CTL_MASTER;
+ power_ctl |= CS42L51_MIC_POWER_CTL_SPEED(ratios[i].speed_mode);
+ break;
+ case MODE_SLAVE:
+ power_ctl |= CS42L51_MIC_POWER_CTL_SPEED(ratios[i].speed_mode);
+ break;
+ case MODE_SLAVE_AUTO:
+ power_ctl |= CS42L51_MIC_POWER_CTL_AUTO;
+ break;
+ }
+
+ switch (cs42l51->audio_mode) {
+ case SND_SOC_DAIFMT_I2S:
+ intf_ctl |= CS42L51_INTF_CTL_ADC_I2S;
+ intf_ctl |= CS42L51_INTF_CTL_DAC_FORMAT(CS42L51_DAC_DIF_I2S);
+ break;
+ case SND_SOC_DAIFMT_LEFT_J:
+ intf_ctl |= CS42L51_INTF_CTL_DAC_FORMAT(CS42L51_DAC_DIF_LJ24);
+ break;
+ case SND_SOC_DAIFMT_RIGHT_J:
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_S16_LE:
+ case SNDRV_PCM_FORMAT_S16_BE:
+ fmt = CS42L51_DAC_DIF_RJ16;
+ break;
+ case SNDRV_PCM_FORMAT_S18_3LE:
+ case SNDRV_PCM_FORMAT_S18_3BE:
+ fmt = CS42L51_DAC_DIF_RJ18;
+ break;
+ case SNDRV_PCM_FORMAT_S20_3LE:
+ case SNDRV_PCM_FORMAT_S20_3BE:
+ fmt = CS42L51_DAC_DIF_RJ20;
+ break;
+ case SNDRV_PCM_FORMAT_S24_LE:
+ case SNDRV_PCM_FORMAT_S24_BE:
+ fmt = CS42L51_DAC_DIF_RJ24;
+ break;
+ default:
+ dev_err(codec->dev, "unknown format\n");
+ return -EINVAL;
+ }
+ intf_ctl |= CS42L51_INTF_CTL_DAC_FORMAT(fmt);
+ break;
+ default:
+ dev_err(codec->dev, "unknown format\n");
+ return -EINVAL;
+ }
+
+ if (ratios[i].mclk)
+ power_ctl |= CS42L51_MIC_POWER_CTL_MCLK_DIV2;
+
+ ret = snd_soc_write(codec, CS42L51_INTF_CTL, intf_ctl);
+ if (ret < 0)
+ return ret;
+
+ ret = snd_soc_write(codec, CS42L51_MIC_POWER_CTL, power_ctl);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static int cs42l51_dai_mute(struct snd_soc_dai *dai, int mute)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ int reg;
+ int mask = CS42L51_DAC_OUT_CTL_DACA_MUTE|CS42L51_DAC_OUT_CTL_DACB_MUTE;
+
+ reg = snd_soc_read(codec, CS42L51_DAC_OUT_CTL);
+
+ if (mute)
+ reg |= mask;
+ else
+ reg &= ~mask;
+
+ return snd_soc_write(codec, CS42L51_DAC_OUT_CTL, reg);
+}
+
+static struct snd_soc_dai_ops cs42l51_dai_ops = {
+ .hw_params = cs42l51_hw_params,
+ .set_sysclk = cs42l51_set_dai_sysclk,
+ .set_fmt = cs42l51_set_dai_fmt,
+ .digital_mute = cs42l51_dai_mute,
+};
+
+struct snd_soc_dai cs42l51_dai = {
+ .name = "CS42L51 HiFi",
+ .playback = {
+ .stream_name = "Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000_96000,
+ .formats = CS42L51_FORMATS,
+ },
+ .capture = {
+ .stream_name = "Capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000_96000,
+ .formats = CS42L51_FORMATS,
+ },
+ .ops = &cs42l51_dai_ops,
+};
+EXPORT_SYMBOL_GPL(cs42l51_dai);
+
+
+static int cs42l51_probe(struct platform_device *pdev)
+{
+ struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+ struct snd_soc_codec *codec;
+ int ret = 0;
+
+ if (!cs42l51_codec) {
+ dev_err(&pdev->dev, "CS42L51 codec not yet registered\n");
+ return -EINVAL;
+ }
+
+ socdev->card->codec = cs42l51_codec;
+ codec = socdev->card->codec;
+
+ /* Register PCMs */
+ ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "failed to create PCMs\n");
+ return ret;
+ }
+
+ snd_soc_add_controls(codec, cs42l51_snd_controls,
+ ARRAY_SIZE(cs42l51_snd_controls));
+ snd_soc_dapm_new_controls(codec, cs42l51_dapm_widgets,
+ ARRAY_SIZE(cs42l51_dapm_widgets));
+ snd_soc_dapm_add_routes(codec, cs42l51_routes,
+ ARRAY_SIZE(cs42l51_routes));
+
+ return 0;
+}
+
+
+static int cs42l51_remove(struct platform_device *pdev)
+{
+ struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+
+ snd_soc_free_pcms(socdev);
+ snd_soc_dapm_free(socdev);
+
+ return 0;
+}
+
+struct snd_soc_codec_device soc_codec_device_cs42l51 = {
+ .probe = cs42l51_probe,
+ .remove = cs42l51_remove
+};
+EXPORT_SYMBOL_GPL(soc_codec_device_cs42l51);
+
+static int __init cs42l51_init(void)
+{
+ int ret;
+
+ ret = i2c_add_driver(&cs42l51_i2c_driver);
+ if (ret != 0) {
+ printk(KERN_ERR "%s: can't add i2c driver\n", __func__);
+ return ret;
+ }
+ return 0;
+}
+module_init(cs42l51_init);
+
+static void __exit cs42l51_exit(void)
+{
+ i2c_del_driver(&cs42l51_i2c_driver);
+}
+module_exit(cs42l51_exit);
+
+MODULE_AUTHOR("Arnaud Patard <apatard@mandriva.com>");
+MODULE_DESCRIPTION("Cirrus Logic CS42L51 ALSA SoC Codec Driver");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/cs42l51.h b/sound/soc/codecs/cs42l51.h
new file mode 100644
index 00000000000..8f0bd9786ad
--- /dev/null
+++ b/sound/soc/codecs/cs42l51.h
@@ -0,0 +1,163 @@
+/*
+ * cs42l51.h
+ *
+ * ASoC Driver for Cirrus Logic CS42L51 codecs
+ *
+ * Copyright (c) 2010 Arnaud Patard <apatard@mandriva.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.
+ */
+#ifndef _CS42L51_H
+#define _CS42L51_H
+
+#define CS42L51_CHIP_ID 0x1B
+#define CS42L51_CHIP_REV_A 0x00
+#define CS42L51_CHIP_REV_B 0x01
+
+#define CS42L51_CHIP_REV_ID 0x01
+#define CS42L51_MK_CHIP_REV(a, b) ((a)<<3|(b))
+
+#define CS42L51_POWER_CTL1 0x02
+#define CS42L51_POWER_CTL1_PDN_DACB (1<<6)
+#define CS42L51_POWER_CTL1_PDN_DACA (1<<5)
+#define CS42L51_POWER_CTL1_PDN_PGAB (1<<4)
+#define CS42L51_POWER_CTL1_PDN_PGAA (1<<3)
+#define CS42L51_POWER_CTL1_PDN_ADCB (1<<2)
+#define CS42L51_POWER_CTL1_PDN_ADCA (1<<1)
+#define CS42L51_POWER_CTL1_PDN (1<<0)
+
+#define CS42L51_MIC_POWER_CTL 0x03
+#define CS42L51_MIC_POWER_CTL_AUTO (1<<7)
+#define CS42L51_MIC_POWER_CTL_SPEED(x) (((x)&3)<<5)
+#define CS42L51_QSM_MODE 3
+#define CS42L51_HSM_MODE 2
+#define CS42L51_SSM_MODE 1
+#define CS42L51_DSM_MODE 0
+#define CS42L51_MIC_POWER_CTL_3ST_SP (1<<4)
+#define CS42L51_MIC_POWER_CTL_PDN_MICB (1<<3)
+#define CS42L51_MIC_POWER_CTL_PDN_MICA (1<<2)
+#define CS42L51_MIC_POWER_CTL_PDN_BIAS (1<<1)
+#define CS42L51_MIC_POWER_CTL_MCLK_DIV2 (1<<0)
+
+#define CS42L51_INTF_CTL 0x04
+#define CS42L51_INTF_CTL_LOOPBACK (1<<7)
+#define CS42L51_INTF_CTL_MASTER (1<<6)
+#define CS42L51_INTF_CTL_DAC_FORMAT(x) (((x)&7)<<3)
+#define CS42L51_DAC_DIF_LJ24 0x00
+#define CS42L51_DAC_DIF_I2S 0x01
+#define CS42L51_DAC_DIF_RJ24 0x02
+#define CS42L51_DAC_DIF_RJ20 0x03
+#define CS42L51_DAC_DIF_RJ18 0x04
+#define CS42L51_DAC_DIF_RJ16 0x05
+#define CS42L51_INTF_CTL_ADC_I2S (1<<2)
+#define CS42L51_INTF_CTL_DIGMIX (1<<1)
+#define CS42L51_INTF_CTL_MICMIX (1<<0)
+
+#define CS42L51_MIC_CTL 0x05
+#define CS42L51_MIC_CTL_ADC_SNGVOL (1<<7)
+#define CS42L51_MIC_CTL_ADCD_DBOOST (1<<6)
+#define CS42L51_MIC_CTL_ADCA_DBOOST (1<<5)
+#define CS42L51_MIC_CTL_MICBIAS_SEL (1<<4)
+#define CS42L51_MIC_CTL_MICBIAS_LVL(x) (((x)&3)<<2)
+#define CS42L51_MIC_CTL_MICB_BOOST (1<<1)
+#define CS42L51_MIC_CTL_MICA_BOOST (1<<0)
+
+#define CS42L51_ADC_CTL 0x06
+#define CS42L51_ADC_CTL_ADCB_HPFEN (1<<7)
+#define CS42L51_ADC_CTL_ADCB_HPFRZ (1<<6)
+#define CS42L51_ADC_CTL_ADCA_HPFEN (1<<5)
+#define CS42L51_ADC_CTL_ADCA_HPFRZ (1<<4)
+#define CS42L51_ADC_CTL_SOFTB (1<<3)
+#define CS42L51_ADC_CTL_ZCROSSB (1<<2)
+#define CS42L51_ADC_CTL_SOFTA (1<<1)
+#define CS42L51_ADC_CTL_ZCROSSA (1<<0)
+
+#define CS42L51_ADC_INPUT 0x07
+#define CS42L51_ADC_INPUT_AINB_MUX(x) (((x)&3)<<6)
+#define CS42L51_ADC_INPUT_AINA_MUX(x) (((x)&3)<<4)
+#define CS42L51_ADC_INPUT_INV_ADCB (1<<3)
+#define CS42L51_ADC_INPUT_INV_ADCA (1<<2)
+#define CS42L51_ADC_INPUT_ADCB_MUTE (1<<1)
+#define CS42L51_ADC_INPUT_ADCA_MUTE (1<<0)
+
+#define CS42L51_DAC_OUT_CTL 0x08
+#define CS42L51_DAC_OUT_CTL_HP_GAIN(x) (((x)&7)<<5)
+#define CS42L51_DAC_OUT_CTL_DAC_SNGVOL (1<<4)
+#define CS42L51_DAC_OUT_CTL_INV_PCMB (1<<3)
+#define CS42L51_DAC_OUT_CTL_INV_PCMA (1<<2)
+#define CS42L51_DAC_OUT_CTL_DACB_MUTE (1<<1)
+#define CS42L51_DAC_OUT_CTL_DACA_MUTE (1<<0)
+
+#define CS42L51_DAC_CTL 0x09
+#define CS42L51_DAC_CTL_DATA_SEL(x) (((x)&3)<<6)
+#define CS42L51_DAC_CTL_FREEZE (1<<5)
+#define CS42L51_DAC_CTL_DEEMPH (1<<3)
+#define CS42L51_DAC_CTL_AMUTE (1<<2)
+#define CS42L51_DAC_CTL_DACSZ(x) (((x)&3)<<0)
+
+#define CS42L51_ALC_PGA_CTL 0x0A
+#define CS42L51_ALC_PGB_CTL 0x0B
+#define CS42L51_ALC_PGX_ALCX_SRDIS (1<<7)
+#define CS42L51_ALC_PGX_ALCX_ZCDIS (1<<6)
+#define CS42L51_ALC_PGX_PGX_VOL(x) (((x)&0x1f)<<0)
+
+#define CS42L51_ADCA_ATT 0x0C
+#define CS42L51_ADCB_ATT 0x0D
+
+#define CS42L51_ADCA_VOL 0x0E
+#define CS42L51_ADCB_VOL 0x0F
+#define CS42L51_PCMA_VOL 0x10
+#define CS42L51_PCMB_VOL 0x11
+#define CS42L51_MIX_MUTE_ADCMIX (1<<7)
+#define CS42L51_MIX_VOLUME(x) (((x)&0x7f)<<0)
+
+#define CS42L51_BEEP_FREQ 0x12
+#define CS42L51_BEEP_VOL 0x13
+#define CS42L51_BEEP_CONF 0x14
+
+#define CS42L51_TONE_CTL 0x15
+#define CS42L51_TONE_CTL_TREB(x) (((x)&0xf)<<4)
+#define CS42L51_TONE_CTL_BASS(x) (((x)&0xf)<<0)
+
+#define CS42L51_AOUTA_VOL 0x16
+#define CS42L51_AOUTB_VOL 0x17
+#define CS42L51_PCM_MIXER 0x18
+#define CS42L51_LIMIT_THRES_DIS 0x19
+#define CS42L51_LIMIT_REL 0x1A
+#define CS42L51_LIMIT_ATT 0x1B
+#define CS42L51_ALC_EN 0x1C
+#define CS42L51_ALC_REL 0x1D
+#define CS42L51_ALC_THRES 0x1E
+#define CS42L51_NOISE_CONF 0x1F
+
+#define CS42L51_STATUS 0x20
+#define CS42L51_STATUS_SP_CLKERR (1<<6)
+#define CS42L51_STATUS_SPEA_OVFL (1<<5)
+#define CS42L51_STATUS_SPEB_OVFL (1<<4)
+#define CS42L51_STATUS_PCMA_OVFL (1<<3)
+#define CS42L51_STATUS_PCMB_OVFL (1<<2)
+#define CS42L51_STATUS_ADCA_OVFL (1<<1)
+#define CS42L51_STATUS_ADCB_OVFL (1<<0)
+
+#define CS42L51_CHARGE_FREQ 0x21
+
+#define CS42L51_FIRSTREG 0x01
+/*
+ * Hack: with register 0x21, it makes 33 registers. Looks like someone in the
+ * i2c layer doesn't like i2c smbus block read of 33 regs. Workaround by using
+ * 32 regs
+ */
+#define CS42L51_LASTREG 0x20
+#define CS42L51_NUMREGS (CS42L51_LASTREG - CS42L51_FIRSTREG + 1)
+
+extern struct snd_soc_dai cs42l51_dai;
+extern struct snd_soc_codec_device soc_codec_device_cs42l51;
+#endif
diff --git a/sound/soc/codecs/da7210.c b/sound/soc/codecs/da7210.c
index 75af2d6e0e7..3c51d6a5752 100644
--- a/sound/soc/codecs/da7210.c
+++ b/sound/soc/codecs/da7210.c
@@ -15,23 +15,15 @@
* option) any later version.
*/
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
#include <linux/delay.h>
-#include <linux/pm.h>
#include <linux/i2c.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
-#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
-#include <sound/soc.h>
#include <sound/soc-dapm.h>
-#include <sound/tlv.h>
#include <sound/initval.h>
-#include <asm/div64.h>
+#include <sound/tlv.h>
#include "da7210.h"
@@ -145,6 +137,29 @@
#define DA7210_VERSION "0.0.1"
+/*
+ * Playback Volume
+ *
+ * max : 0x3F (+15.0 dB)
+ * (1.5 dB step)
+ * min : 0x11 (-54.0 dB)
+ * mute : 0x10
+ * reserved : 0x00 - 0x0F
+ *
+ * ** FIXME **
+ *
+ * Reserved area are considered as "mute".
+ * -> min = -79.5 dB
+ */
+static const DECLARE_TLV_DB_SCALE(hp_out_tlv, -7950, 150, 1);
+
+static const struct snd_kcontrol_new da7210_snd_controls[] = {
+
+ SOC_DOUBLE_R_TLV("HeadPhone Playback Volume",
+ DA7210_HP_L_VOL, DA7210_HP_R_VOL,
+ 0, 0x3F, 0, hp_out_tlv),
+};
+
/* Codec private data */
struct da7210_priv {
struct snd_soc_codec codec;
@@ -227,10 +242,6 @@ static int da7210_startup(struct snd_pcm_substream *substream,
struct snd_soc_codec *codec = dai->codec;
if (is_play) {
- /* PlayBack Volume 40 */
- snd_soc_update_bits(codec, DA7210_HP_L_VOL, 0x3F, 40);
- snd_soc_update_bits(codec, DA7210_HP_R_VOL, 0x3F, 40);
-
/* Enable Out */
snd_soc_update_bits(codec, DA7210_OUTMIX_L, 0x1F, 0x10);
snd_soc_update_bits(codec, DA7210_OUTMIX_R, 0x1F, 0x10);
@@ -488,7 +499,7 @@ static int da7210_init(struct da7210_priv *da7210)
ret = snd_soc_register_dai(&da7210_dai);
if (ret) {
dev_err(codec->dev, "Failed to register DAI: %d\n", ret);
- goto init_err;
+ goto codec_err;
}
/* FIXME
@@ -574,6 +585,8 @@ static int da7210_init(struct da7210_priv *da7210)
return ret;
+codec_err:
+ snd_soc_unregister_codec(codec);
init_err:
kfree(codec->reg_cache);
codec->reg_cache = NULL;
@@ -601,8 +614,10 @@ static int __devinit da7210_i2c_probe(struct i2c_client *i2c,
codec->control_data = i2c;
ret = da7210_init(da7210);
- if (ret < 0)
+ if (ret < 0) {
pr_err("Failed to initialise da7210 audio codec\n");
+ kfree(da7210);
+ }
return ret;
}
@@ -656,6 +671,9 @@ static int da7210_probe(struct platform_device *pdev)
if (ret < 0)
goto pcm_err;
+ snd_soc_add_controls(da7210_codec, da7210_snd_controls,
+ ARRAY_SIZE(da7210_snd_controls));
+
dev_info(&pdev->dev, "DA7210 Audio Codec %s\n", DA7210_VERSION);
pcm_err:
diff --git a/sound/soc/codecs/jz4740.c b/sound/soc/codecs/jz4740.c
new file mode 100644
index 00000000000..66557de1e4f
--- /dev/null
+++ b/sound/soc/codecs/jz4740.c
@@ -0,0 +1,511 @@
+/*
+ * Copyright (C) 2009-2010, Lars-Peter Clausen <lars@metafoo.de>
+ *
+ * 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.
+ *
+ * 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/platform_device.h>
+#include <linux/slab.h>
+
+#include <linux/delay.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/initval.h>
+#include <sound/soc-dapm.h>
+#include <sound/soc.h>
+
+#define JZ4740_REG_CODEC_1 0x0
+#define JZ4740_REG_CODEC_2 0x1
+
+#define JZ4740_CODEC_1_LINE_ENABLE BIT(29)
+#define JZ4740_CODEC_1_MIC_ENABLE BIT(28)
+#define JZ4740_CODEC_1_SW1_ENABLE BIT(27)
+#define JZ4740_CODEC_1_ADC_ENABLE BIT(26)
+#define JZ4740_CODEC_1_SW2_ENABLE BIT(25)
+#define JZ4740_CODEC_1_DAC_ENABLE BIT(24)
+#define JZ4740_CODEC_1_VREF_DISABLE BIT(20)
+#define JZ4740_CODEC_1_VREF_AMP_DISABLE BIT(19)
+#define JZ4740_CODEC_1_VREF_PULLDOWN BIT(18)
+#define JZ4740_CODEC_1_VREF_LOW_CURRENT BIT(17)
+#define JZ4740_CODEC_1_VREF_HIGH_CURRENT BIT(16)
+#define JZ4740_CODEC_1_HEADPHONE_DISABLE BIT(14)
+#define JZ4740_CODEC_1_HEADPHONE_AMP_CHANGE_ANY BIT(13)
+#define JZ4740_CODEC_1_HEADPHONE_CHARGE BIT(12)
+#define JZ4740_CODEC_1_HEADPHONE_PULLDOWN (BIT(11) | BIT(10))
+#define JZ4740_CODEC_1_HEADPHONE_POWERDOWN_M BIT(9)
+#define JZ4740_CODEC_1_HEADPHONE_POWERDOWN BIT(8)
+#define JZ4740_CODEC_1_SUSPEND BIT(1)
+#define JZ4740_CODEC_1_RESET BIT(0)
+
+#define JZ4740_CODEC_1_LINE_ENABLE_OFFSET 29
+#define JZ4740_CODEC_1_MIC_ENABLE_OFFSET 28
+#define JZ4740_CODEC_1_SW1_ENABLE_OFFSET 27
+#define JZ4740_CODEC_1_ADC_ENABLE_OFFSET 26
+#define JZ4740_CODEC_1_SW2_ENABLE_OFFSET 25
+#define JZ4740_CODEC_1_DAC_ENABLE_OFFSET 24
+#define JZ4740_CODEC_1_HEADPHONE_DISABLE_OFFSET 14
+#define JZ4740_CODEC_1_HEADPHONE_POWERDOWN_OFFSET 8
+
+#define JZ4740_CODEC_2_INPUT_VOLUME_MASK 0x1f0000
+#define JZ4740_CODEC_2_SAMPLE_RATE_MASK 0x000f00
+#define JZ4740_CODEC_2_MIC_BOOST_GAIN_MASK 0x000030
+#define JZ4740_CODEC_2_HEADPHONE_VOLUME_MASK 0x000003
+
+#define JZ4740_CODEC_2_INPUT_VOLUME_OFFSET 16
+#define JZ4740_CODEC_2_SAMPLE_RATE_OFFSET 8
+#define JZ4740_CODEC_2_MIC_BOOST_GAIN_OFFSET 4
+#define JZ4740_CODEC_2_HEADPHONE_VOLUME_OFFSET 0
+
+static const uint32_t jz4740_codec_regs[] = {
+ 0x021b2302, 0x00170803,
+};
+
+struct jz4740_codec {
+ void __iomem *base;
+ struct resource *mem;
+
+ uint32_t reg_cache[2];
+ struct snd_soc_codec codec;
+};
+
+static inline struct jz4740_codec *codec_to_jz4740(struct snd_soc_codec *codec)
+{
+ return container_of(codec, struct jz4740_codec, codec);
+}
+
+static unsigned int jz4740_codec_read(struct snd_soc_codec *codec,
+ unsigned int reg)
+{
+ struct jz4740_codec *jz4740_codec = codec_to_jz4740(codec);
+ return readl(jz4740_codec->base + (reg << 2));
+}
+
+static int jz4740_codec_write(struct snd_soc_codec *codec, unsigned int reg,
+ unsigned int val)
+{
+ struct jz4740_codec *jz4740_codec = codec_to_jz4740(codec);
+
+ jz4740_codec->reg_cache[reg] = val;
+ writel(val, jz4740_codec->base + (reg << 2));
+
+ return 0;
+}
+
+static const struct snd_kcontrol_new jz4740_codec_controls[] = {
+ SOC_SINGLE("Master Playback Volume", JZ4740_REG_CODEC_2,
+ JZ4740_CODEC_2_HEADPHONE_VOLUME_OFFSET, 3, 0),
+ SOC_SINGLE("Master Capture Volume", JZ4740_REG_CODEC_2,
+ JZ4740_CODEC_2_INPUT_VOLUME_OFFSET, 31, 0),
+ SOC_SINGLE("Master Playback Switch", JZ4740_REG_CODEC_1,
+ JZ4740_CODEC_1_HEADPHONE_DISABLE_OFFSET, 1, 1),
+ SOC_SINGLE("Mic Capture Volume", JZ4740_REG_CODEC_2,
+ JZ4740_CODEC_2_MIC_BOOST_GAIN_OFFSET, 3, 0),
+};
+
+static const struct snd_kcontrol_new jz4740_codec_output_controls[] = {
+ SOC_DAPM_SINGLE("Bypass Switch", JZ4740_REG_CODEC_1,
+ JZ4740_CODEC_1_SW1_ENABLE_OFFSET, 1, 0),
+ SOC_DAPM_SINGLE("DAC Switch", JZ4740_REG_CODEC_1,
+ JZ4740_CODEC_1_SW2_ENABLE_OFFSET, 1, 0),
+};
+
+static const struct snd_kcontrol_new jz4740_codec_input_controls[] = {
+ SOC_DAPM_SINGLE("Line Capture Switch", JZ4740_REG_CODEC_1,
+ JZ4740_CODEC_1_LINE_ENABLE_OFFSET, 1, 0),
+ SOC_DAPM_SINGLE("Mic Capture Switch", JZ4740_REG_CODEC_1,
+ JZ4740_CODEC_1_MIC_ENABLE_OFFSET, 1, 0),
+};
+
+static const struct snd_soc_dapm_widget jz4740_codec_dapm_widgets[] = {
+ SND_SOC_DAPM_ADC("ADC", "Capture", JZ4740_REG_CODEC_1,
+ JZ4740_CODEC_1_ADC_ENABLE_OFFSET, 0),
+ SND_SOC_DAPM_DAC("DAC", "Playback", JZ4740_REG_CODEC_1,
+ JZ4740_CODEC_1_DAC_ENABLE_OFFSET, 0),
+
+ SND_SOC_DAPM_MIXER("Output Mixer", JZ4740_REG_CODEC_1,
+ JZ4740_CODEC_1_HEADPHONE_POWERDOWN_OFFSET, 1,
+ jz4740_codec_output_controls,
+ ARRAY_SIZE(jz4740_codec_output_controls)),
+
+ SND_SOC_DAPM_MIXER_NAMED_CTL("Input Mixer", SND_SOC_NOPM, 0, 0,
+ jz4740_codec_input_controls,
+ ARRAY_SIZE(jz4740_codec_input_controls)),
+ SND_SOC_DAPM_MIXER("Line Input", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+ SND_SOC_DAPM_OUTPUT("LOUT"),
+ SND_SOC_DAPM_OUTPUT("ROUT"),
+
+ SND_SOC_DAPM_INPUT("MIC"),
+ SND_SOC_DAPM_INPUT("LIN"),
+ SND_SOC_DAPM_INPUT("RIN"),
+};
+
+static const struct snd_soc_dapm_route jz4740_codec_dapm_routes[] = {
+ {"Line Input", NULL, "LIN"},
+ {"Line Input", NULL, "RIN"},
+
+ {"Input Mixer", "Line Capture Switch", "Line Input"},
+ {"Input Mixer", "Mic Capture Switch", "MIC"},
+
+ {"ADC", NULL, "Input Mixer"},
+
+ {"Output Mixer", "Bypass Switch", "Input Mixer"},
+ {"Output Mixer", "DAC Switch", "DAC"},
+
+ {"LOUT", NULL, "Output Mixer"},
+ {"ROUT", NULL, "Output Mixer"},
+};
+
+static int jz4740_codec_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
+{
+ uint32_t val;
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_device *socdev = rtd->socdev;
+ struct snd_soc_codec *codec = socdev->card->codec;
+
+ switch (params_rate(params)) {
+ case 8000:
+ val = 0;
+ break;
+ case 11025:
+ val = 1;
+ break;
+ case 12000:
+ val = 2;
+ break;
+ case 16000:
+ val = 3;
+ break;
+ case 22050:
+ val = 4;
+ break;
+ case 24000:
+ val = 5;
+ break;
+ case 32000:
+ val = 6;
+ break;
+ case 44100:
+ val = 7;
+ break;
+ case 48000:
+ val = 8;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ val <<= JZ4740_CODEC_2_SAMPLE_RATE_OFFSET;
+
+ snd_soc_update_bits(codec, JZ4740_REG_CODEC_2,
+ JZ4740_CODEC_2_SAMPLE_RATE_MASK, val);
+
+ return 0;
+}
+
+static struct snd_soc_dai_ops jz4740_codec_dai_ops = {
+ .hw_params = jz4740_codec_hw_params,
+};
+
+struct snd_soc_dai jz4740_codec_dai = {
+ .name = "jz4740",
+ .playback = {
+ .stream_name = "Playback",
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8,
+ },
+ .capture = {
+ .stream_name = "Capture",
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8,
+ },
+ .ops = &jz4740_codec_dai_ops,
+ .symmetric_rates = 1,
+};
+EXPORT_SYMBOL_GPL(jz4740_codec_dai);
+
+static void jz4740_codec_wakeup(struct snd_soc_codec *codec)
+{
+ int i;
+ uint32_t *cache = codec->reg_cache;
+
+ snd_soc_update_bits(codec, JZ4740_REG_CODEC_1,
+ JZ4740_CODEC_1_RESET, JZ4740_CODEC_1_RESET);
+ udelay(2);
+
+ snd_soc_update_bits(codec, JZ4740_REG_CODEC_1,
+ JZ4740_CODEC_1_SUSPEND | JZ4740_CODEC_1_RESET, 0);
+
+ for (i = 0; i < ARRAY_SIZE(jz4740_codec_regs); ++i)
+ jz4740_codec_write(codec, i, cache[i]);
+}
+
+static int jz4740_codec_set_bias_level(struct snd_soc_codec *codec,
+ enum snd_soc_bias_level level)
+{
+ unsigned int mask;
+ unsigned int value;
+
+ switch (level) {
+ case SND_SOC_BIAS_ON:
+ break;
+ case SND_SOC_BIAS_PREPARE:
+ mask = JZ4740_CODEC_1_VREF_DISABLE |
+ JZ4740_CODEC_1_VREF_AMP_DISABLE |
+ JZ4740_CODEC_1_HEADPHONE_POWERDOWN_M;
+ value = 0;
+
+ snd_soc_update_bits(codec, JZ4740_REG_CODEC_1, mask, value);
+ break;
+ case SND_SOC_BIAS_STANDBY:
+ /* The only way to clear the suspend flag is to reset the codec */
+ if (codec->bias_level == SND_SOC_BIAS_OFF)
+ jz4740_codec_wakeup(codec);
+
+ mask = JZ4740_CODEC_1_VREF_DISABLE |
+ JZ4740_CODEC_1_VREF_AMP_DISABLE |
+ JZ4740_CODEC_1_HEADPHONE_POWERDOWN_M;
+ value = JZ4740_CODEC_1_VREF_DISABLE |
+ JZ4740_CODEC_1_VREF_AMP_DISABLE |
+ JZ4740_CODEC_1_HEADPHONE_POWERDOWN_M;
+
+ snd_soc_update_bits(codec, JZ4740_REG_CODEC_1, mask, value);
+ break;
+ case SND_SOC_BIAS_OFF:
+ mask = JZ4740_CODEC_1_SUSPEND;
+ value = JZ4740_CODEC_1_SUSPEND;
+
+ snd_soc_update_bits(codec, JZ4740_REG_CODEC_1, mask, value);
+ break;
+ default:
+ break;
+ }
+
+ codec->bias_level = level;
+
+ return 0;
+}
+
+static struct snd_soc_codec *jz4740_codec_codec;
+
+static int jz4740_codec_dev_probe(struct platform_device *pdev)
+{
+ int ret;
+ struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+ struct snd_soc_codec *codec = jz4740_codec_codec;
+
+ BUG_ON(!codec);
+
+ socdev->card->codec = codec;
+
+ ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to create pcms: %d\n", ret);
+ return ret;
+ }
+
+ snd_soc_add_controls(codec, jz4740_codec_controls,
+ ARRAY_SIZE(jz4740_codec_controls));
+
+ snd_soc_dapm_new_controls(codec, jz4740_codec_dapm_widgets,
+ ARRAY_SIZE(jz4740_codec_dapm_widgets));
+
+ snd_soc_dapm_add_routes(codec, jz4740_codec_dapm_routes,
+ ARRAY_SIZE(jz4740_codec_dapm_routes));
+
+ snd_soc_dapm_new_widgets(codec);
+
+ return 0;
+}
+
+static int jz4740_codec_dev_remove(struct platform_device *pdev)
+{
+ struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+
+ snd_soc_free_pcms(socdev);
+ snd_soc_dapm_free(socdev);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+
+static int jz4740_codec_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+ struct snd_soc_codec *codec = socdev->card->codec;
+
+ return jz4740_codec_set_bias_level(codec, SND_SOC_BIAS_OFF);
+}
+
+static int jz4740_codec_resume(struct platform_device *pdev)
+{
+ struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+ struct snd_soc_codec *codec = socdev->card->codec;
+
+ return jz4740_codec_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+}
+
+#else
+#define jz4740_codec_suspend NULL
+#define jz4740_codec_resume NULL
+#endif
+
+struct snd_soc_codec_device soc_codec_dev_jz4740_codec = {
+ .probe = jz4740_codec_dev_probe,
+ .remove = jz4740_codec_dev_remove,
+ .suspend = jz4740_codec_suspend,
+ .resume = jz4740_codec_resume,
+};
+EXPORT_SYMBOL_GPL(soc_codec_dev_jz4740_codec);
+
+static int __devinit jz4740_codec_probe(struct platform_device *pdev)
+{
+ int ret;
+ struct jz4740_codec *jz4740_codec;
+ struct snd_soc_codec *codec;
+ struct resource *mem;
+
+ jz4740_codec = kzalloc(sizeof(*jz4740_codec), GFP_KERNEL);
+ if (!jz4740_codec)
+ return -ENOMEM;
+
+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!mem) {
+ dev_err(&pdev->dev, "Failed to get mmio memory resource\n");
+ ret = -ENOENT;
+ goto err_free_codec;
+ }
+
+ mem = request_mem_region(mem->start, resource_size(mem), pdev->name);
+ if (!mem) {
+ dev_err(&pdev->dev, "Failed to request mmio memory region\n");
+ ret = -EBUSY;
+ goto err_free_codec;
+ }
+
+ jz4740_codec->base = ioremap(mem->start, resource_size(mem));
+ if (!jz4740_codec->base) {
+ dev_err(&pdev->dev, "Failed to ioremap mmio memory\n");
+ ret = -EBUSY;
+ goto err_release_mem_region;
+ }
+ jz4740_codec->mem = mem;
+
+ jz4740_codec_dai.dev = &pdev->dev;
+
+ codec = &jz4740_codec->codec;
+
+ codec->dev = &pdev->dev;
+ codec->name = "jz4740";
+ codec->owner = THIS_MODULE;
+
+ codec->read = jz4740_codec_read;
+ codec->write = jz4740_codec_write;
+ codec->set_bias_level = jz4740_codec_set_bias_level;
+ codec->bias_level = SND_SOC_BIAS_OFF;
+
+ codec->dai = &jz4740_codec_dai;
+ codec->num_dai = 1;
+
+ codec->reg_cache = jz4740_codec->reg_cache;
+ codec->reg_cache_size = 2;
+ memcpy(codec->reg_cache, jz4740_codec_regs, sizeof(jz4740_codec_regs));
+
+ mutex_init(&codec->mutex);
+ INIT_LIST_HEAD(&codec->dapm_widgets);
+ INIT_LIST_HEAD(&codec->dapm_paths);
+
+ jz4740_codec_codec = codec;
+
+ snd_soc_update_bits(codec, JZ4740_REG_CODEC_1,
+ JZ4740_CODEC_1_SW2_ENABLE, JZ4740_CODEC_1_SW2_ENABLE);
+
+ platform_set_drvdata(pdev, jz4740_codec);
+
+ ret = snd_soc_register_codec(codec);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to register codec\n");
+ goto err_iounmap;
+ }
+
+ ret = snd_soc_register_dai(&jz4740_codec_dai);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to register codec dai\n");
+ goto err_unregister_codec;
+ }
+
+ jz4740_codec_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
+ return 0;
+
+err_unregister_codec:
+ snd_soc_unregister_codec(codec);
+err_iounmap:
+ iounmap(jz4740_codec->base);
+err_release_mem_region:
+ release_mem_region(mem->start, resource_size(mem));
+err_free_codec:
+ kfree(jz4740_codec);
+
+ return ret;
+}
+
+static int __devexit jz4740_codec_remove(struct platform_device *pdev)
+{
+ struct jz4740_codec *jz4740_codec = platform_get_drvdata(pdev);
+ struct resource *mem = jz4740_codec->mem;
+
+ snd_soc_unregister_dai(&jz4740_codec_dai);
+ snd_soc_unregister_codec(&jz4740_codec->codec);
+
+ iounmap(jz4740_codec->base);
+ release_mem_region(mem->start, resource_size(mem));
+
+ platform_set_drvdata(pdev, NULL);
+ kfree(jz4740_codec);
+
+ return 0;
+}
+
+static struct platform_driver jz4740_codec_driver = {
+ .probe = jz4740_codec_probe,
+ .remove = __devexit_p(jz4740_codec_remove),
+ .driver = {
+ .name = "jz4740-codec",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init jz4740_codec_init(void)
+{
+ return platform_driver_register(&jz4740_codec_driver);
+}
+module_init(jz4740_codec_init);
+
+static void __exit jz4740_codec_exit(void)
+{
+ platform_driver_unregister(&jz4740_codec_driver);
+}
+module_exit(jz4740_codec_exit);
+
+MODULE_DESCRIPTION("JZ4740 SoC internal codec driver");
+MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:jz4740-codec");
diff --git a/sound/soc/codecs/jz4740.h b/sound/soc/codecs/jz4740.h
new file mode 100644
index 00000000000..b5a0691be76
--- /dev/null
+++ b/sound/soc/codecs/jz4740.h
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2009, Lars-Peter Clausen <lars@metafoo.de>
+ *
+ * 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.
+ *
+ * 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 __SND_SOC_CODECS_JZ4740_CODEC_H__
+#define __SND_SOC_CODECS_JZ4740_CODEC_H__
+
+extern struct snd_soc_dai jz4740_codec_dai;
+extern struct snd_soc_codec_device soc_codec_dev_jz4740_codec;
+
+#endif
diff --git a/sound/soc/codecs/spdif_transciever.c b/sound/soc/codecs/spdif_transciever.c
index a6319114105..9119836051a 100644
--- a/sound/soc/codecs/spdif_transciever.c
+++ b/sound/soc/codecs/spdif_transciever.c
@@ -16,8 +16,10 @@
#include <linux/module.h>
#include <linux/moduleparam.h>
+#include <linux/slab.h>
#include <sound/soc.h>
#include <sound/pcm.h>
+#include <sound/initval.h>
#include "spdif_transciever.h"
@@ -26,6 +28,48 @@ MODULE_LICENSE("GPL");
#define STUB_RATES SNDRV_PCM_RATE_8000_96000
#define STUB_FORMATS SNDRV_PCM_FMTBIT_S16_LE
+static struct snd_soc_codec *spdif_dit_codec;
+
+static int spdif_dit_codec_probe(struct platform_device *pdev)
+{
+ struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+ struct snd_soc_codec *codec;
+ int ret;
+
+ if (spdif_dit_codec == NULL) {
+ dev_err(&pdev->dev, "Codec device not registered\n");
+ return -ENODEV;
+ }
+
+ socdev->card->codec = spdif_dit_codec;
+ codec = spdif_dit_codec;
+
+ ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
+ if (ret < 0) {
+ dev_err(codec->dev, "failed to create pcms: %d\n", ret);
+ goto err_create_pcms;
+ }
+
+ return 0;
+
+err_create_pcms:
+ return ret;
+}
+
+static int spdif_dit_codec_remove(struct platform_device *pdev)
+{
+ struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+
+ snd_soc_free_pcms(socdev);
+
+ return 0;
+}
+
+struct snd_soc_codec_device soc_codec_dev_spdif_dit = {
+ .probe = spdif_dit_codec_probe,
+ .remove = spdif_dit_codec_remove,
+}; EXPORT_SYMBOL_GPL(soc_codec_dev_spdif_dit);
+
struct snd_soc_dai dit_stub_dai = {
.name = "DIT",
.playback = {
@@ -40,13 +84,61 @@ EXPORT_SYMBOL_GPL(dit_stub_dai);
static int spdif_dit_probe(struct platform_device *pdev)
{
+ struct snd_soc_codec *codec;
+ int ret;
+
+ if (spdif_dit_codec) {
+ dev_err(&pdev->dev, "Another Codec is registered\n");
+ ret = -EINVAL;
+ goto err_reg_codec;
+ }
+
+ codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
+ if (codec == NULL)
+ return -ENOMEM;
+
+ codec->dev = &pdev->dev;
+
+ mutex_init(&codec->mutex);
+
+ INIT_LIST_HEAD(&codec->dapm_widgets);
+ INIT_LIST_HEAD(&codec->dapm_paths);
+
+ codec->name = "spdif-dit";
+ codec->owner = THIS_MODULE;
+ codec->dai = &dit_stub_dai;
+ codec->num_dai = 1;
+
+ spdif_dit_codec = codec;
+
+ ret = snd_soc_register_codec(codec);
+ if (ret < 0) {
+ dev_err(codec->dev, "Failed to register codec: %d\n", ret);
+ goto err_reg_codec;
+ }
+
dit_stub_dai.dev = &pdev->dev;
- return snd_soc_register_dai(&dit_stub_dai);
+ ret = snd_soc_register_dai(&dit_stub_dai);
+ if (ret < 0) {
+ dev_err(codec->dev, "Failed to register dai: %d\n", ret);
+ goto err_reg_dai;
+ }
+
+ return 0;
+
+err_reg_dai:
+ snd_soc_unregister_codec(codec);
+err_reg_codec:
+ kfree(spdif_dit_codec);
+ return ret;
}
static int spdif_dit_remove(struct platform_device *pdev)
{
snd_soc_unregister_dai(&dit_stub_dai);
+ snd_soc_unregister_codec(spdif_dit_codec);
+ kfree(spdif_dit_codec);
+ spdif_dit_codec = NULL;
return 0;
}
diff --git a/sound/soc/codecs/spdif_transciever.h b/sound/soc/codecs/spdif_transciever.h
index 296f2eb6c4e..1e102124f54 100644
--- a/sound/soc/codecs/spdif_transciever.h
+++ b/sound/soc/codecs/spdif_transciever.h
@@ -12,6 +12,7 @@
#ifndef CODEC_STUBS_H
#define CODEC_STUBS_H
+extern struct snd_soc_codec_device soc_codec_dev_spdif_dit;
extern struct snd_soc_dai dit_stub_dai;
#endif /* CODEC_STUBS_H */
diff --git a/sound/soc/codecs/tlv320aic23.c b/sound/soc/codecs/tlv320aic23.c
index b0bae3508b2..0a4b0fef335 100644
--- a/sound/soc/codecs/tlv320aic23.c
+++ b/sound/soc/codecs/tlv320aic23.c
@@ -560,13 +560,16 @@ static int tlv320aic23_set_bias_level(struct snd_soc_codec *codec,
switch (level) {
case SND_SOC_BIAS_ON:
/* vref/mid, osc on, dac unmute */
+ reg &= ~(TLV320AIC23_DEVICE_PWR_OFF | TLV320AIC23_OSC_OFF | \
+ TLV320AIC23_DAC_OFF);
tlv320aic23_write(codec, TLV320AIC23_PWR, reg);
break;
case SND_SOC_BIAS_PREPARE:
break;
case SND_SOC_BIAS_STANDBY:
/* everything off except vref/vmid, */
- tlv320aic23_write(codec, TLV320AIC23_PWR, reg | 0x0040);
+ tlv320aic23_write(codec, TLV320AIC23_PWR, reg | \
+ TLV320AIC23_CLK_OFF);
break;
case SND_SOC_BIAS_OFF:
/* everything off, dac mute, inactive */
@@ -615,7 +618,6 @@ static int tlv320aic23_suspend(struct platform_device *pdev,
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
struct snd_soc_codec *codec = socdev->card->codec;
- tlv320aic23_write(codec, TLV320AIC23_ACTIVE, 0x0);
tlv320aic23_set_bias_level(codec, SND_SOC_BIAS_OFF);
return 0;
@@ -632,7 +634,6 @@ static int tlv320aic23_resume(struct platform_device *pdev)
u16 val = tlv320aic23_read_reg_cache(codec, reg);
tlv320aic23_write(codec, reg, val);
}
-
tlv320aic23_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
return 0;
diff --git a/sound/soc/codecs/tlv320dac33.c b/sound/soc/codecs/tlv320dac33.c
index 65adc77eada..8651b01ed22 100644
--- a/sound/soc/codecs/tlv320dac33.c
+++ b/sound/soc/codecs/tlv320dac33.c
@@ -49,8 +49,6 @@
#define NSAMPLE_MAX 5700
-#define LATENCY_TIME_MS 20
-
#define MODE7_LTHR 10
#define MODE7_UTHR (DAC33_BUFFER_SIZE_SAMPLES - 10)
@@ -62,6 +60,9 @@
#define US_TO_SAMPLES(rate, us) \
(rate / (1000000 / us))
+#define UTHR_FROM_PERIOD_SIZE(samples, playrate, burstrate) \
+ ((samples * 5000) / ((burstrate * 5000) / (burstrate - playrate)))
+
static void dac33_calculate_times(struct snd_pcm_substream *substream);
static int dac33_prepare_chip(struct snd_pcm_substream *substream);
@@ -107,6 +108,10 @@ struct tlv320dac33_priv {
* this */
enum dac33_fifo_modes fifo_mode;/* FIFO mode selection */
unsigned int nsample; /* burst read amount from host */
+ int mode1_latency; /* latency caused by the i2c writes in
+ * us */
+ int auto_fifo_config; /* Configure the FIFO based on the
+ * period size */
u8 burst_bclkdiv; /* BCLK divider value in burst mode */
unsigned int burst_rate; /* Interface speed in Burst modes */
@@ -120,6 +125,8 @@ struct tlv320dac33_priv {
* samples */
unsigned int mode7_us_to_lthr; /* Time to reach lthr from uthr */
+ unsigned int uthr;
+
enum dac33_state state;
};
@@ -442,6 +449,39 @@ static int dac33_set_nsample(struct snd_kcontrol *kcontrol,
return ret;
}
+static int dac33_get_uthr(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
+
+ ucontrol->value.integer.value[0] = dac33->uthr;
+
+ return 0;
+}
+
+static int dac33_set_uthr(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
+ int ret = 0;
+
+ if (dac33->substream)
+ return -EBUSY;
+
+ if (dac33->uthr == ucontrol->value.integer.value[0])
+ return 0;
+
+ if (ucontrol->value.integer.value[0] < (MODE7_LTHR + 10) ||
+ ucontrol->value.integer.value[0] > MODE7_UTHR)
+ ret = -EINVAL;
+ else
+ dac33->uthr = ucontrol->value.integer.value[0];
+
+ return ret;
+}
+
static int dac33_get_fifo_mode(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
@@ -503,13 +543,18 @@ static const struct snd_kcontrol_new dac33_snd_controls[] = {
DAC33_LINEL_TO_LLO_VOL, DAC33_LINER_TO_RLO_VOL, 0, 127, 1),
};
-static const struct snd_kcontrol_new dac33_nsample_snd_controls[] = {
- SOC_SINGLE_EXT("nSample", 0, 0, 5900, 0,
- dac33_get_nsample, dac33_set_nsample),
+static const struct snd_kcontrol_new dac33_mode_snd_controls[] = {
SOC_ENUM_EXT("FIFO Mode", dac33_fifo_mode_enum,
dac33_get_fifo_mode, dac33_set_fifo_mode),
};
+static const struct snd_kcontrol_new dac33_fifo_snd_controls[] = {
+ SOC_SINGLE_EXT("nSample", 0, 0, 5900, 0,
+ dac33_get_nsample, dac33_set_nsample),
+ SOC_SINGLE_EXT("UTHR", 0, 0, MODE7_UTHR, 0,
+ dac33_get_uthr, dac33_set_uthr),
+};
+
/* Analog bypass */
static const struct snd_kcontrol_new dac33_dapm_abypassl_control =
SOC_DAPM_SINGLE("Switch", DAC33_LINEL_TO_LLO_VOL, 7, 1, 1);
@@ -612,7 +657,7 @@ static inline void dac33_prefill_handler(struct tlv320dac33_priv *dac33)
switch (dac33->fifo_mode) {
case DAC33_FIFO_MODE1:
dac33_write16(codec, DAC33_NSAMPLE_MSB,
- DAC33_THRREG(dac33->nsample + dac33->alarm_threshold));
+ DAC33_THRREG(dac33->nsample));
/* Take the timestamps */
spin_lock_irq(&dac33->lock);
@@ -761,6 +806,10 @@ static void dac33_shutdown(struct snd_pcm_substream *substream,
struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
dac33->substream = NULL;
+
+ /* Reset the nSample restrictions */
+ dac33->nsample_min = 0;
+ dac33->nsample_max = NSAMPLE_MAX;
}
static int dac33_hw_params(struct snd_pcm_substream *substream,
@@ -985,7 +1034,7 @@ static int dac33_prepare_chip(struct snd_pcm_substream *substream)
* Configure the threshold levels, and leave 10 sample space
* at the bottom, and also at the top of the FIFO
*/
- dac33_write16(codec, DAC33_UTHR_MSB, DAC33_THRREG(MODE7_UTHR));
+ dac33_write16(codec, DAC33_UTHR_MSB, DAC33_THRREG(dac33->uthr));
dac33_write16(codec, DAC33_LTHR_MSB, DAC33_THRREG(MODE7_LTHR));
break;
default:
@@ -1003,57 +1052,71 @@ static void dac33_calculate_times(struct snd_pcm_substream *substream)
struct snd_soc_device *socdev = rtd->socdev;
struct snd_soc_codec *codec = socdev->card->codec;
struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
+ unsigned int period_size = substream->runtime->period_size;
+ unsigned int rate = substream->runtime->rate;
unsigned int nsample_limit;
/* In bypass mode we don't need to calculate */
if (!dac33->fifo_mode)
return;
- /* Number of samples (16bit, stereo) in one period */
- dac33->nsample_min = snd_pcm_lib_period_bytes(substream) / 4;
-
- /* Number of samples (16bit, stereo) in ALSA buffer */
- dac33->nsample_max = snd_pcm_lib_buffer_bytes(substream) / 4;
- /* Subtract one period from the total */
- dac33->nsample_max -= dac33->nsample_min;
-
- /* Number of samples for LATENCY_TIME_MS / 2 */
- dac33->alarm_threshold = substream->runtime->rate /
- (1000 / (LATENCY_TIME_MS / 2));
-
- /* Find and fix up the lowest nsmaple limit */
- nsample_limit = substream->runtime->rate / (1000 / LATENCY_TIME_MS);
-
- if (dac33->nsample_min < nsample_limit)
- dac33->nsample_min = nsample_limit;
-
- if (dac33->nsample < dac33->nsample_min)
- dac33->nsample = dac33->nsample_min;
-
- /*
- * Find and fix up the highest nsmaple limit
- * In order to not overflow the DAC33 buffer substract the
- * alarm_threshold value from the size of the DAC33 buffer
- */
- nsample_limit = DAC33_BUFFER_SIZE_SAMPLES - dac33->alarm_threshold;
-
- if (dac33->nsample_max > nsample_limit)
- dac33->nsample_max = nsample_limit;
-
- if (dac33->nsample > dac33->nsample_max)
- dac33->nsample = dac33->nsample_max;
-
switch (dac33->fifo_mode) {
case DAC33_FIFO_MODE1:
+ /* Number of samples under i2c latency */
+ dac33->alarm_threshold = US_TO_SAMPLES(rate,
+ dac33->mode1_latency);
+ if (dac33->auto_fifo_config) {
+ if (period_size <= dac33->alarm_threshold)
+ /*
+ * Configure nSamaple to number of periods,
+ * which covers the latency requironment.
+ */
+ dac33->nsample = period_size *
+ ((dac33->alarm_threshold / period_size) +
+ (dac33->alarm_threshold % period_size ?
+ 1 : 0));
+ else
+ dac33->nsample = period_size;
+ } else {
+ /* nSample time shall not be shorter than i2c latency */
+ dac33->nsample_min = dac33->alarm_threshold;
+ /*
+ * nSample should not be bigger than alsa buffer minus
+ * size of one period to avoid overruns
+ */
+ dac33->nsample_max = substream->runtime->buffer_size -
+ period_size;
+ nsample_limit = DAC33_BUFFER_SIZE_SAMPLES -
+ dac33->alarm_threshold;
+ if (dac33->nsample_max > nsample_limit)
+ dac33->nsample_max = nsample_limit;
+
+ /* Correct the nSample if it is outside of the ranges */
+ if (dac33->nsample < dac33->nsample_min)
+ dac33->nsample = dac33->nsample_min;
+ if (dac33->nsample > dac33->nsample_max)
+ dac33->nsample = dac33->nsample_max;
+ }
+
dac33->mode1_us_burst = SAMPLES_TO_US(dac33->burst_rate,
dac33->nsample);
dac33->t_stamp1 = 0;
dac33->t_stamp2 = 0;
break;
case DAC33_FIFO_MODE7:
+ if (dac33->auto_fifo_config) {
+ dac33->uthr = UTHR_FROM_PERIOD_SIZE(
+ period_size,
+ rate,
+ dac33->burst_rate) + 9;
+ if (dac33->uthr > MODE7_UTHR)
+ dac33->uthr = MODE7_UTHR;
+ if (dac33->uthr < (MODE7_LTHR + 10))
+ dac33->uthr = (MODE7_LTHR + 10);
+ }
dac33->mode7_us_to_lthr =
- SAMPLES_TO_US(substream->runtime->rate,
- MODE7_UTHR - MODE7_LTHR + 1);
+ SAMPLES_TO_US(substream->runtime->rate,
+ dac33->uthr - MODE7_LTHR + 1);
dac33->t_stamp1 = 0;
break;
default:
@@ -1104,7 +1167,7 @@ static snd_pcm_sframes_t dac33_dai_delay(
struct snd_soc_codec *codec = socdev->card->codec;
struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
unsigned long long t0, t1, t_now;
- unsigned int time_delta;
+ unsigned int time_delta, uthr;
int samples_out, samples_in, samples;
snd_pcm_sframes_t delay = 0;
@@ -1182,6 +1245,7 @@ static snd_pcm_sframes_t dac33_dai_delay(
case DAC33_FIFO_MODE7:
spin_lock(&dac33->lock);
t0 = dac33->t_stamp1;
+ uthr = dac33->uthr;
spin_unlock(&dac33->lock);
t_now = ktime_to_us(ktime_get());
@@ -1194,7 +1258,7 @@ static snd_pcm_sframes_t dac33_dai_delay(
* Either the timestamps are messed or equal. Report
* maximum delay
*/
- delay = MODE7_UTHR;
+ delay = uthr;
goto out;
}
@@ -1208,8 +1272,8 @@ static snd_pcm_sframes_t dac33_dai_delay(
substream->runtime->rate,
time_delta);
- if (likely(MODE7_UTHR > samples_out))
- delay = MODE7_UTHR - samples_out;
+ if (likely(uthr > samples_out))
+ delay = uthr - samples_out;
else
delay = 0;
} else {
@@ -1227,8 +1291,8 @@ static snd_pcm_sframes_t dac33_dai_delay(
time_delta);
delay = MODE7_LTHR + samples_in - samples_out;
- if (unlikely(delay > MODE7_UTHR))
- delay = MODE7_UTHR;
+ if (unlikely(delay > uthr))
+ delay = uthr;
}
break;
default:
@@ -1347,10 +1411,15 @@ static int dac33_soc_probe(struct platform_device *pdev)
snd_soc_add_controls(codec, dac33_snd_controls,
ARRAY_SIZE(dac33_snd_controls));
- /* Only add the nSample controls, if we have valid IRQ number */
- if (dac33->irq >= 0)
- snd_soc_add_controls(codec, dac33_nsample_snd_controls,
- ARRAY_SIZE(dac33_nsample_snd_controls));
+ /* Only add the FIFO controls, if we have valid IRQ number */
+ if (dac33->irq >= 0) {
+ snd_soc_add_controls(codec, dac33_mode_snd_controls,
+ ARRAY_SIZE(dac33_mode_snd_controls));
+ /* FIFO usage controls only, if autoio config is not selected */
+ if (!dac33->auto_fifo_config)
+ snd_soc_add_controls(codec, dac33_fifo_snd_controls,
+ ARRAY_SIZE(dac33_fifo_snd_controls));
+ }
dac33_add_widgets(codec);
@@ -1481,9 +1550,14 @@ static int __devinit dac33_i2c_probe(struct i2c_client *client,
/* Pre calculate the burst rate */
dac33->burst_rate = BURST_BASEFREQ_HZ / dac33->burst_bclkdiv / 32;
dac33->keep_bclk = pdata->keep_bclk;
+ dac33->auto_fifo_config = pdata->auto_fifo_config;
+ dac33->mode1_latency = pdata->mode1_latency;
+ if (!dac33->mode1_latency)
+ dac33->mode1_latency = 10000; /* 10ms */
dac33->irq = client->irq;
dac33->nsample = NSAMPLE_MAX;
dac33->nsample_max = NSAMPLE_MAX;
+ dac33->uthr = MODE7_UTHR;
/* Disable FIFO use by default */
dac33->fifo_mode = DAC33_FIFO_BYPASS;
diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c
index b4fcdb01fc4..7b618bbff88 100644
--- a/sound/soc/codecs/twl4030.c
+++ b/sound/soc/codecs/twl4030.c
@@ -43,37 +43,37 @@
*/
static const u8 twl4030_reg[TWL4030_CACHEREGNUM] = {
0x00, /* this register not used */
- 0x91, /* REG_CODEC_MODE (0x1) */
- 0xc3, /* REG_OPTION (0x2) */
+ 0x00, /* REG_CODEC_MODE (0x1) */
+ 0x00, /* REG_OPTION (0x2) */
0x00, /* REG_UNKNOWN (0x3) */
0x00, /* REG_MICBIAS_CTL (0x4) */
- 0x20, /* REG_ANAMICL (0x5) */
+ 0x00, /* REG_ANAMICL (0x5) */
0x00, /* REG_ANAMICR (0x6) */
0x00, /* REG_AVADC_CTL (0x7) */
0x00, /* REG_ADCMICSEL (0x8) */
0x00, /* REG_DIGMIXING (0x9) */
- 0x0c, /* REG_ATXL1PGA (0xA) */
- 0x0c, /* REG_ATXR1PGA (0xB) */
- 0x00, /* REG_AVTXL2PGA (0xC) */
- 0x00, /* REG_AVTXR2PGA (0xD) */
+ 0x0f, /* REG_ATXL1PGA (0xA) */
+ 0x0f, /* REG_ATXR1PGA (0xB) */
+ 0x0f, /* REG_AVTXL2PGA (0xC) */
+ 0x0f, /* REG_AVTXR2PGA (0xD) */
0x00, /* REG_AUDIO_IF (0xE) */
0x00, /* REG_VOICE_IF (0xF) */
- 0x00, /* REG_ARXR1PGA (0x10) */
- 0x00, /* REG_ARXL1PGA (0x11) */
- 0x6c, /* REG_ARXR2PGA (0x12) */
- 0x6c, /* REG_ARXL2PGA (0x13) */
- 0x00, /* REG_VRXPGA (0x14) */
+ 0x3f, /* REG_ARXR1PGA (0x10) */
+ 0x3f, /* REG_ARXL1PGA (0x11) */
+ 0x3f, /* REG_ARXR2PGA (0x12) */
+ 0x3f, /* REG_ARXL2PGA (0x13) */
+ 0x25, /* REG_VRXPGA (0x14) */
0x00, /* REG_VSTPGA (0x15) */
0x00, /* REG_VRX2ARXPGA (0x16) */
0x00, /* REG_AVDAC_CTL (0x17) */
0x00, /* REG_ARX2VTXPGA (0x18) */
- 0x00, /* REG_ARXL1_APGA_CTL (0x19) */
- 0x00, /* REG_ARXR1_APGA_CTL (0x1A) */
- 0x4a, /* REG_ARXL2_APGA_CTL (0x1B) */
- 0x4a, /* REG_ARXR2_APGA_CTL (0x1C) */
+ 0x32, /* REG_ARXL1_APGA_CTL (0x19) */
+ 0x32, /* REG_ARXR1_APGA_CTL (0x1A) */
+ 0x32, /* REG_ARXL2_APGA_CTL (0x1B) */
+ 0x32, /* REG_ARXR2_APGA_CTL (0x1C) */
0x00, /* REG_ATX2ARXPGA (0x1D) */
0x00, /* REG_BT_IF (0x1E) */
- 0x00, /* REG_BTPGA (0x1F) */
+ 0x55, /* REG_BTPGA (0x1F) */
0x00, /* REG_BTSTPGA (0x20) */
0x00, /* REG_EAR_CTL (0x21) */
0x00, /* REG_HS_SEL (0x22) */
@@ -85,32 +85,32 @@ static const u8 twl4030_reg[TWL4030_CACHEREGNUM] = {
0x00, /* REG_PRECKR_CTL (0x28) */
0x00, /* REG_HFL_CTL (0x29) */
0x00, /* REG_HFR_CTL (0x2A) */
- 0x00, /* REG_ALC_CTL (0x2B) */
+ 0x05, /* REG_ALC_CTL (0x2B) */
0x00, /* REG_ALC_SET1 (0x2C) */
0x00, /* REG_ALC_SET2 (0x2D) */
0x00, /* REG_BOOST_CTL (0x2E) */
0x00, /* REG_SOFTVOL_CTL (0x2F) */
- 0x00, /* REG_DTMF_FREQSEL (0x30) */
+ 0x13, /* REG_DTMF_FREQSEL (0x30) */
0x00, /* REG_DTMF_TONEXT1H (0x31) */
0x00, /* REG_DTMF_TONEXT1L (0x32) */
0x00, /* REG_DTMF_TONEXT2H (0x33) */
0x00, /* REG_DTMF_TONEXT2L (0x34) */
- 0x00, /* REG_DTMF_TONOFF (0x35) */
- 0x00, /* REG_DTMF_WANONOFF (0x36) */
+ 0x79, /* REG_DTMF_TONOFF (0x35) */
+ 0x11, /* REG_DTMF_WANONOFF (0x36) */
0x00, /* REG_I2S_RX_SCRAMBLE_H (0x37) */
0x00, /* REG_I2S_RX_SCRAMBLE_M (0x38) */
0x00, /* REG_I2S_RX_SCRAMBLE_L (0x39) */
0x06, /* REG_APLL_CTL (0x3A) */
0x00, /* REG_DTMF_CTL (0x3B) */
- 0x00, /* REG_DTMF_PGA_CTL2 (0x3C) */
- 0x00, /* REG_DTMF_PGA_CTL1 (0x3D) */
+ 0x44, /* REG_DTMF_PGA_CTL2 (0x3C) */
+ 0x69, /* REG_DTMF_PGA_CTL1 (0x3D) */
0x00, /* REG_MISC_SET_1 (0x3E) */
0x00, /* REG_PCMBTMUX (0x3F) */
0x00, /* not used (0x40) */
0x00, /* not used (0x41) */
0x00, /* not used (0x42) */
0x00, /* REG_RX_PATH_SEL (0x43) */
- 0x00, /* REG_VDL_APGA_CTL (0x44) */
+ 0x32, /* REG_VDL_APGA_CTL (0x44) */
0x00, /* REG_VIBRA_CTL (0x45) */
0x00, /* REG_VIBRA_SET (0x46) */
0x00, /* REG_VIBRA_PWM_SET (0x47) */
@@ -143,6 +143,9 @@ struct twl4030_priv {
u8 earpiece_enabled;
u8 predrivel_enabled, predriver_enabled;
u8 carkitl_enabled, carkitr_enabled;
+
+ /* Delay needed after enabling the digimic interface */
+ unsigned int digimic_delay;
};
/*
@@ -244,58 +247,95 @@ static void twl4030_codec_enable(struct snd_soc_codec *codec, int enable)
udelay(10);
}
-static void twl4030_init_chip(struct snd_soc_codec *codec)
+static inline void twl4030_check_defaults(struct snd_soc_codec *codec)
{
- u8 *cache = codec->reg_cache;
- int i;
+ int i, difference = 0;
+ u8 val;
+
+ dev_dbg(codec->dev, "Checking TWL audio default configuration\n");
+ for (i = 1; i <= TWL4030_REG_MISC_SET_2; i++) {
+ twl_i2c_read_u8(TWL4030_MODULE_AUDIO_VOICE, &val, i);
+ if (val != twl4030_reg[i]) {
+ difference++;
+ dev_dbg(codec->dev,
+ "Reg 0x%02x: chip: 0x%02x driver: 0x%02x\n",
+ i, val, twl4030_reg[i]);
+ }
+ }
+ dev_dbg(codec->dev, "Found %d non maching registers. %s\n",
+ difference, difference ? "Not OK" : "OK");
+}
- /* clear CODECPDZ prior to setting register defaults */
- twl4030_codec_enable(codec, 0);
+static inline void twl4030_reset_registers(struct snd_soc_codec *codec)
+{
+ int i;
/* set all audio section registers to reasonable defaults */
for (i = TWL4030_REG_OPTION; i <= TWL4030_REG_MISC_SET_2; i++)
if (i != TWL4030_REG_APLL_CTL)
- twl4030_write(codec, i, cache[i]);
+ twl4030_write(codec, i, twl4030_reg[i]);
}
-static void twl4030_apll_enable(struct snd_soc_codec *codec, int enable)
+static void twl4030_init_chip(struct platform_device *pdev)
{
+ struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+ struct twl4030_setup_data *setup = socdev->codec_data;
+ struct snd_soc_codec *codec = socdev->card->codec;
struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
- int status = -1;
+ u8 reg, byte;
+ int i = 0;
- if (enable) {
- twl4030->apll_enabled++;
- if (twl4030->apll_enabled == 1)
- status = twl4030_codec_enable_resource(
- TWL4030_CODEC_RES_APLL);
- } else {
- twl4030->apll_enabled--;
- if (!twl4030->apll_enabled)
- status = twl4030_codec_disable_resource(
- TWL4030_CODEC_RES_APLL);
- }
+ /* Check defaults, if instructed before anything else */
+ if (setup && setup->check_defaults)
+ twl4030_check_defaults(codec);
- if (status >= 0)
- twl4030_write_reg_cache(codec, TWL4030_REG_APLL_CTL, status);
-}
+ /* Reset registers, if no setup data or if instructed to do so */
+ if (!setup || (setup && setup->reset_registers))
+ twl4030_reset_registers(codec);
-static void twl4030_power_up(struct snd_soc_codec *codec)
-{
- struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
- u8 anamicl, regmisc1, byte;
- int i = 0;
+ /* Refresh APLL_CTL register from HW */
+ twl_i2c_read_u8(TWL4030_MODULE_AUDIO_VOICE, &byte,
+ TWL4030_REG_APLL_CTL);
+ twl4030_write_reg_cache(codec, TWL4030_REG_APLL_CTL, byte);
+
+ /* anti-pop when changing analog gain */
+ reg = twl4030_read_reg_cache(codec, TWL4030_REG_MISC_SET_1);
+ twl4030_write(codec, TWL4030_REG_MISC_SET_1,
+ reg | TWL4030_SMOOTH_ANAVOL_EN);
- if (twl4030->codec_powered)
+ twl4030_write(codec, TWL4030_REG_OPTION,
+ TWL4030_ATXL1_EN | TWL4030_ATXR1_EN |
+ TWL4030_ARXL2_EN | TWL4030_ARXR2_EN);
+
+ /* REG_ARXR2_APGA_CTL reset according to the TRM: 0dB, DA_EN */
+ twl4030_write(codec, TWL4030_REG_ARXR2_APGA_CTL, 0x32);
+
+ /* Machine dependent setup */
+ if (!setup)
return;
- /* set CODECPDZ to turn on codec */
- twl4030_codec_enable(codec, 1);
+ twl4030->digimic_delay = setup->digimic_delay;
+
+ /* Configuration for headset ramp delay from setup data */
+ if (setup->sysclk != twl4030->sysclk)
+ dev_warn(codec->dev,
+ "Mismatch in APLL mclk: %u (configured: %u)\n",
+ setup->sysclk, twl4030->sysclk);
+
+ reg = twl4030_read_reg_cache(codec, TWL4030_REG_HS_POPN_SET);
+ reg &= ~TWL4030_RAMP_DELAY;
+ reg |= (setup->ramp_delay_value << 2);
+ twl4030_write_reg_cache(codec, TWL4030_REG_HS_POPN_SET, reg);
/* initiate offset cancellation */
- anamicl = twl4030_read_reg_cache(codec, TWL4030_REG_ANAMICL);
+ twl4030_codec_enable(codec, 1);
+
+ reg = twl4030_read_reg_cache(codec, TWL4030_REG_ANAMICL);
+ reg &= ~TWL4030_OFFSET_CNCL_SEL;
+ reg |= setup->offset_cncl_path;
twl4030_write(codec, TWL4030_REG_ANAMICL,
- anamicl | TWL4030_CNCL_OFFSET_START);
+ reg | TWL4030_CNCL_OFFSET_START);
/* wait for offset cancellation to complete */
do {
@@ -310,23 +350,28 @@ static void twl4030_power_up(struct snd_soc_codec *codec)
/* Make sure that the reg_cache has the same value as the HW */
twl4030_write_reg_cache(codec, TWL4030_REG_ANAMICL, byte);
- /* anti-pop when changing analog gain */
- regmisc1 = twl4030_read_reg_cache(codec, TWL4030_REG_MISC_SET_1);
- twl4030_write(codec, TWL4030_REG_MISC_SET_1,
- regmisc1 | TWL4030_SMOOTH_ANAVOL_EN);
-
- /* toggle CODECPDZ as per TRM */
twl4030_codec_enable(codec, 0);
- twl4030_codec_enable(codec, 1);
}
-/*
- * Unconditional power down
- */
-static void twl4030_power_down(struct snd_soc_codec *codec)
+static void twl4030_apll_enable(struct snd_soc_codec *codec, int enable)
{
- /* power down */
- twl4030_codec_enable(codec, 0);
+ struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
+ int status = -1;
+
+ if (enable) {
+ twl4030->apll_enabled++;
+ if (twl4030->apll_enabled == 1)
+ status = twl4030_codec_enable_resource(
+ TWL4030_CODEC_RES_APLL);
+ } else {
+ twl4030->apll_enabled--;
+ if (!twl4030->apll_enabled)
+ status = twl4030_codec_disable_resource(
+ TWL4030_CODEC_RES_APLL);
+ }
+
+ if (status >= 0)
+ twl4030_write_reg_cache(codec, TWL4030_REG_APLL_CTL, status);
}
/* Earpiece */
@@ -500,10 +545,11 @@ static const struct snd_kcontrol_new twl4030_dapm_abypassl2_control =
static const struct snd_kcontrol_new twl4030_dapm_abypassv_control =
SOC_DAPM_SINGLE("Switch", TWL4030_REG_VDL_APGA_CTL, 2, 1, 0);
-/* Digital bypass gain, 0 mutes the bypass */
+/* Digital bypass gain, mute instead of -30dB */
static const unsigned int twl4030_dapm_dbypass_tlv[] = {
- TLV_DB_RANGE_HEAD(2),
- 0, 3, TLV_DB_SCALE_ITEM(-2400, 0, 1),
+ TLV_DB_RANGE_HEAD(3),
+ 0, 1, TLV_DB_SCALE_ITEM(-3000, 600, 1),
+ 2, 3, TLV_DB_SCALE_ITEM(-2400, 0, 0),
4, 7, TLV_DB_SCALE_ITEM(-1800, 600, 0),
};
@@ -531,36 +577,6 @@ static const struct snd_kcontrol_new twl4030_dapm_dbypassv_control =
TWL4030_REG_VSTPGA, 0, 0x29, 0,
twl4030_dapm_dbypassv_tlv);
-static int micpath_event(struct snd_soc_dapm_widget *w,
- struct snd_kcontrol *kcontrol, int event)
-{
- struct soc_enum *e = (struct soc_enum *)w->kcontrols->private_value;
- unsigned char adcmicsel, micbias_ctl;
-
- adcmicsel = twl4030_read_reg_cache(w->codec, TWL4030_REG_ADCMICSEL);
- micbias_ctl = twl4030_read_reg_cache(w->codec, TWL4030_REG_MICBIAS_CTL);
- /* Prepare the bits for the given TX path:
- * shift_l == 0: TX1 microphone path
- * shift_l == 2: TX2 microphone path */
- if (e->shift_l) {
- /* TX2 microphone path */
- if (adcmicsel & TWL4030_TX2IN_SEL)
- micbias_ctl |= TWL4030_MICBIAS2_CTL; /* digimic */
- else
- micbias_ctl &= ~TWL4030_MICBIAS2_CTL;
- } else {
- /* TX1 microphone path */
- if (adcmicsel & TWL4030_TX1IN_SEL)
- micbias_ctl |= TWL4030_MICBIAS1_CTL; /* digimic */
- else
- micbias_ctl &= ~TWL4030_MICBIAS1_CTL;
- }
-
- twl4030_write(w->codec, TWL4030_REG_MICBIAS_CTL, micbias_ctl);
-
- return 0;
-}
-
/*
* Output PGA builder:
* Handle the muting and unmuting of the given output (turning off the
@@ -814,6 +830,16 @@ static int headsetrpga_event(struct snd_soc_dapm_widget *w,
return 0;
}
+static int digimic_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(w->codec);
+
+ if (twl4030->digimic_delay)
+ mdelay(twl4030->digimic_delay);
+ return 0;
+}
+
/*
* Some of the gain controls in TWL (mostly those which are associated with
* the outputs) are implemented in an interesting way:
@@ -1374,14 +1400,10 @@ static const struct snd_soc_dapm_widget twl4030_dapm_widgets[] = {
/* Analog/Digital mic path selection.
TX1 Left/Right: either analog Left/Right or Digimic0
TX2 Left/Right: either analog Left/Right or Digimic1 */
- SND_SOC_DAPM_MUX_E("TX1 Capture Route", SND_SOC_NOPM, 0, 0,
- &twl4030_dapm_micpathtx1_control, micpath_event,
- SND_SOC_DAPM_POST_PMU|SND_SOC_DAPM_POST_PMD|
- SND_SOC_DAPM_POST_REG),
- SND_SOC_DAPM_MUX_E("TX2 Capture Route", SND_SOC_NOPM, 0, 0,
- &twl4030_dapm_micpathtx2_control, micpath_event,
- SND_SOC_DAPM_POST_PMU|SND_SOC_DAPM_POST_PMD|
- SND_SOC_DAPM_POST_REG),
+ SND_SOC_DAPM_MUX("TX1 Capture Route", SND_SOC_NOPM, 0, 0,
+ &twl4030_dapm_micpathtx1_control),
+ SND_SOC_DAPM_MUX("TX2 Capture Route", SND_SOC_NOPM, 0, 0,
+ &twl4030_dapm_micpathtx2_control),
/* Analog input mixers for the capture amplifiers */
SND_SOC_DAPM_MIXER("Analog Left",
@@ -1398,10 +1420,17 @@ static const struct snd_soc_dapm_widget twl4030_dapm_widgets[] = {
SND_SOC_DAPM_PGA("ADC Physical Right",
TWL4030_REG_AVADC_CTL, 1, 0, NULL, 0),
- SND_SOC_DAPM_PGA("Digimic0 Enable",
- TWL4030_REG_ADCMICSEL, 1, 0, NULL, 0),
- SND_SOC_DAPM_PGA("Digimic1 Enable",
- TWL4030_REG_ADCMICSEL, 3, 0, NULL, 0),
+ SND_SOC_DAPM_PGA_E("Digimic0 Enable",
+ TWL4030_REG_ADCMICSEL, 1, 0, NULL, 0,
+ digimic_event, SND_SOC_DAPM_POST_PMU),
+ SND_SOC_DAPM_PGA_E("Digimic1 Enable",
+ TWL4030_REG_ADCMICSEL, 3, 0, NULL, 0,
+ digimic_event, SND_SOC_DAPM_POST_PMU),
+
+ SND_SOC_DAPM_SUPPLY("micbias1 select", TWL4030_REG_MICBIAS_CTL, 5, 0,
+ NULL, 0),
+ SND_SOC_DAPM_SUPPLY("micbias2 select", TWL4030_REG_MICBIAS_CTL, 6, 0,
+ NULL, 0),
SND_SOC_DAPM_MICBIAS("Mic Bias 1", TWL4030_REG_MICBIAS_CTL, 0, 0),
SND_SOC_DAPM_MICBIAS("Mic Bias 2", TWL4030_REG_MICBIAS_CTL, 1, 0),
@@ -1419,8 +1448,11 @@ static const struct snd_soc_dapm_route intercon[] = {
/* Supply for the digital part (APLL) */
{"Digital Voice Playback Mixer", NULL, "APLL Enable"},
- {"Digital R1 Playback Mixer", NULL, "AIF Enable"},
- {"Digital L1 Playback Mixer", NULL, "AIF Enable"},
+ {"DAC Left1", NULL, "AIF Enable"},
+ {"DAC Right1", NULL, "AIF Enable"},
+ {"DAC Left2", NULL, "AIF Enable"},
+ {"DAC Right1", NULL, "AIF Enable"},
+
{"Digital R2 Playback Mixer", NULL, "AIF Enable"},
{"Digital L2 Playback Mixer", NULL, "AIF Enable"},
@@ -1491,10 +1523,10 @@ static const struct snd_soc_dapm_route intercon[] = {
/* outputs */
/* Must be always connected (for AIF and APLL) */
- {"Virtual HiFi OUT", NULL, "Digital L1 Playback Mixer"},
- {"Virtual HiFi OUT", NULL, "Digital R1 Playback Mixer"},
- {"Virtual HiFi OUT", NULL, "Digital L2 Playback Mixer"},
- {"Virtual HiFi OUT", NULL, "Digital R2 Playback Mixer"},
+ {"Virtual HiFi OUT", NULL, "DAC Left1"},
+ {"Virtual HiFi OUT", NULL, "DAC Right1"},
+ {"Virtual HiFi OUT", NULL, "DAC Left2"},
+ {"Virtual HiFi OUT", NULL, "DAC Right2"},
/* Must be always connected (for APLL) */
{"Virtual Voice OUT", NULL, "Digital Voice Playback Mixer"},
/* Physical outputs */
@@ -1531,6 +1563,9 @@ static const struct snd_soc_dapm_route intercon[] = {
{"Digimic0 Enable", NULL, "DIGIMIC0"},
{"Digimic1 Enable", NULL, "DIGIMIC1"},
+ {"DIGIMIC0", NULL, "micbias1 select"},
+ {"DIGIMIC1", NULL, "micbias2 select"},
+
/* TX1 Left capture path */
{"TX1 Capture Route", "Analog", "ADC Physical Left"},
{"TX1 Capture Route", "Digimic0", "Digimic0 Enable"},
@@ -1605,10 +1640,10 @@ static int twl4030_set_bias_level(struct snd_soc_codec *codec,
break;
case SND_SOC_BIAS_STANDBY:
if (codec->bias_level == SND_SOC_BIAS_OFF)
- twl4030_power_up(codec);
+ twl4030_codec_enable(codec, 1);
break;
case SND_SOC_BIAS_OFF:
- twl4030_power_down(codec);
+ twl4030_codec_enable(codec, 0);
break;
}
codec->bias_level = level;
@@ -1794,13 +1829,6 @@ static int twl4030_hw_params(struct snd_pcm_substream *substream,
return -EINVAL;
}
- if (mode != old_mode) {
- /* change rate and set CODECPDZ */
- twl4030_codec_enable(codec, 0);
- twl4030_write(codec, TWL4030_REG_CODEC_MODE, mode);
- twl4030_codec_enable(codec, 1);
- }
-
/* sample size */
old_format = twl4030_read_reg_cache(codec, TWL4030_REG_AUDIO_IF);
format = old_format;
@@ -1818,16 +1846,20 @@ static int twl4030_hw_params(struct snd_pcm_substream *substream,
return -EINVAL;
}
- if (format != old_format) {
-
- /* clear CODECPDZ before changing format (codec requirement) */
- twl4030_codec_enable(codec, 0);
-
- /* change format */
- twl4030_write(codec, TWL4030_REG_AUDIO_IF, format);
-
- /* set CODECPDZ afterwards */
- twl4030_codec_enable(codec, 1);
+ if (format != old_format || mode != old_mode) {
+ if (twl4030->codec_powered) {
+ /*
+ * If the codec is powered, than we need to toggle the
+ * codec power.
+ */
+ twl4030_codec_enable(codec, 0);
+ twl4030_write(codec, TWL4030_REG_CODEC_MODE, mode);
+ twl4030_write(codec, TWL4030_REG_AUDIO_IF, format);
+ twl4030_codec_enable(codec, 1);
+ } else {
+ twl4030_write(codec, TWL4030_REG_CODEC_MODE, mode);
+ twl4030_write(codec, TWL4030_REG_AUDIO_IF, format);
+ }
}
/* Store the important parameters for the DAI configuration and set
@@ -1877,6 +1909,7 @@ static int twl4030_set_dai_fmt(struct snd_soc_dai *codec_dai,
unsigned int fmt)
{
struct snd_soc_codec *codec = codec_dai->codec;
+ struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
u8 old_format, format;
/* get format */
@@ -1911,15 +1944,17 @@ static int twl4030_set_dai_fmt(struct snd_soc_dai *codec_dai,
}
if (format != old_format) {
-
- /* clear CODECPDZ before changing format (codec requirement) */
- twl4030_codec_enable(codec, 0);
-
- /* change format */
- twl4030_write(codec, TWL4030_REG_AUDIO_IF, format);
-
- /* set CODECPDZ afterwards */
- twl4030_codec_enable(codec, 1);
+ if (twl4030->codec_powered) {
+ /*
+ * If the codec is powered, than we need to toggle the
+ * codec power.
+ */
+ twl4030_codec_enable(codec, 0);
+ twl4030_write(codec, TWL4030_REG_AUDIO_IF, format);
+ twl4030_codec_enable(codec, 1);
+ } else {
+ twl4030_write(codec, TWL4030_REG_AUDIO_IF, format);
+ }
}
return 0;
@@ -2011,6 +2046,7 @@ static int twl4030_voice_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_device *socdev = rtd->socdev;
struct snd_soc_codec *codec = socdev->card->codec;
+ struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
u8 old_mode, mode;
/* Enable voice digital filters */
@@ -2035,10 +2071,17 @@ static int twl4030_voice_hw_params(struct snd_pcm_substream *substream,
}
if (mode != old_mode) {
- /* change rate and set CODECPDZ */
- twl4030_codec_enable(codec, 0);
- twl4030_write(codec, TWL4030_REG_CODEC_MODE, mode);
- twl4030_codec_enable(codec, 1);
+ if (twl4030->codec_powered) {
+ /*
+ * If the codec is powered, than we need to toggle the
+ * codec power.
+ */
+ twl4030_codec_enable(codec, 0);
+ twl4030_write(codec, TWL4030_REG_CODEC_MODE, mode);
+ twl4030_codec_enable(codec, 1);
+ } else {
+ twl4030_write(codec, TWL4030_REG_CODEC_MODE, mode);
+ }
}
return 0;
@@ -2068,6 +2111,7 @@ static int twl4030_voice_set_dai_fmt(struct snd_soc_dai *codec_dai,
unsigned int fmt)
{
struct snd_soc_codec *codec = codec_dai->codec;
+ struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
u8 old_format, format;
/* get format */
@@ -2099,10 +2143,17 @@ static int twl4030_voice_set_dai_fmt(struct snd_soc_dai *codec_dai,
}
if (format != old_format) {
- /* change format and set CODECPDZ */
- twl4030_codec_enable(codec, 0);
- twl4030_write(codec, TWL4030_REG_VOICE_IF, format);
- twl4030_codec_enable(codec, 1);
+ if (twl4030->codec_powered) {
+ /*
+ * If the codec is powered, than we need to toggle the
+ * codec power.
+ */
+ twl4030_codec_enable(codec, 0);
+ twl4030_write(codec, TWL4030_REG_VOICE_IF, format);
+ twl4030_codec_enable(codec, 1);
+ } else {
+ twl4030_write(codec, TWL4030_REG_VOICE_IF, format);
+ }
}
return 0;
@@ -2202,31 +2253,15 @@ static struct snd_soc_codec *twl4030_codec;
static int twl4030_soc_probe(struct platform_device *pdev)
{
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct twl4030_setup_data *setup = socdev->codec_data;
struct snd_soc_codec *codec;
- struct twl4030_priv *twl4030;
int ret;
BUG_ON(!twl4030_codec);
codec = twl4030_codec;
- twl4030 = snd_soc_codec_get_drvdata(codec);
socdev->card->codec = codec;
- /* Configuration for headset ramp delay from setup data */
- if (setup) {
- unsigned char hs_pop;
-
- if (setup->sysclk != twl4030->sysclk)
- dev_warn(&pdev->dev,
- "Mismatch in APLL mclk: %u (configured: %u)\n",
- setup->sysclk, twl4030->sysclk);
-
- hs_pop = twl4030_read_reg_cache(codec, TWL4030_REG_HS_POPN_SET);
- hs_pop &= ~TWL4030_RAMP_DELAY;
- hs_pop |= (setup->ramp_delay_value << 2);
- twl4030_write_reg_cache(codec, TWL4030_REG_HS_POPN_SET, hs_pop);
- }
+ twl4030_init_chip(pdev);
/* register pcms */
ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
@@ -2247,6 +2282,8 @@ static int twl4030_soc_remove(struct platform_device *pdev)
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
struct snd_soc_codec *codec = socdev->card->codec;
+ /* Reset registers to their chip default before leaving */
+ twl4030_reset_registers(codec);
twl4030_set_bias_level(codec, SND_SOC_BIAS_OFF);
snd_soc_free_pcms(socdev);
snd_soc_dapm_free(socdev);
@@ -2287,6 +2324,7 @@ static int __devinit twl4030_codec_probe(struct platform_device *pdev)
codec->read = twl4030_read_reg_cache;
codec->write = twl4030_write;
codec->set_bias_level = twl4030_set_bias_level;
+ codec->idle_bias_off = 1;
codec->dai = twl4030_dai;
codec->num_dai = ARRAY_SIZE(twl4030_dai);
codec->reg_cache_size = sizeof(twl4030_reg);
@@ -2302,9 +2340,7 @@ static int __devinit twl4030_codec_probe(struct platform_device *pdev)
/* Set the defaults, and power up the codec */
twl4030->sysclk = twl4030_codec_get_mclk() / 1000;
- twl4030_init_chip(codec);
codec->bias_level = SND_SOC_BIAS_OFF;
- twl4030_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
ret = snd_soc_register_codec(codec);
if (ret != 0) {
@@ -2322,7 +2358,7 @@ static int __devinit twl4030_codec_probe(struct platform_device *pdev)
return 0;
error_codec:
- twl4030_power_down(codec);
+ twl4030_codec_enable(codec, 0);
kfree(codec->reg_cache);
error_cache:
kfree(twl4030);
diff --git a/sound/soc/codecs/twl4030.h b/sound/soc/codecs/twl4030.h
index f206d242ca3..6c57430f6e2 100644
--- a/sound/soc/codecs/twl4030.h
+++ b/sound/soc/codecs/twl4030.h
@@ -41,7 +41,11 @@ extern struct snd_soc_codec_device soc_codec_dev_twl4030;
struct twl4030_setup_data {
unsigned int ramp_delay_value;
+ unsigned int digimic_delay; /* in ms */
unsigned int sysclk;
+ unsigned int offset_cncl_path;
+ unsigned int check_defaults:1;
+ unsigned int reset_registers:1;
unsigned int hs_extmute:1;
void (*set_hs_extmute)(int mute);
};
diff --git a/sound/soc/codecs/twl6040.c b/sound/soc/codecs/twl6040.c
index af36346ff33..64a807f1a8a 100644
--- a/sound/soc/codecs/twl6040.c
+++ b/sound/soc/codecs/twl6040.c
@@ -360,6 +360,13 @@ static int headset_power_mode(struct snd_soc_codec *codec, int high_perf)
return 0;
}
+static int twl6040_hs_dac_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ msleep(1);
+ return 0;
+}
+
static int twl6040_power_mode_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
@@ -371,6 +378,8 @@ static int twl6040_power_mode_event(struct snd_soc_dapm_widget *w,
else
priv->non_lp--;
+ msleep(1);
+
return 0;
}
@@ -471,20 +480,6 @@ static const struct snd_kcontrol_new hfdacl_switch_controls =
static const struct snd_kcontrol_new hfdacr_switch_controls =
SOC_DAPM_SINGLE("Switch", TWL6040_REG_HFRCTL, 2, 1, 0);
-/* Headset driver switches */
-static const struct snd_kcontrol_new hsl_driver_switch_controls =
- SOC_DAPM_SINGLE("Switch", TWL6040_REG_HSLCTL, 2, 1, 0);
-
-static const struct snd_kcontrol_new hsr_driver_switch_controls =
- SOC_DAPM_SINGLE("Switch", TWL6040_REG_HSRCTL, 2, 1, 0);
-
-/* Handsfree driver switches */
-static const struct snd_kcontrol_new hfl_driver_switch_controls =
- SOC_DAPM_SINGLE("Switch", TWL6040_REG_HFLCTL, 4, 1, 0);
-
-static const struct snd_kcontrol_new hfr_driver_switch_controls =
- SOC_DAPM_SINGLE("Switch", TWL6040_REG_HFRCTL, 4, 1, 0);
-
static const struct snd_kcontrol_new ep_driver_switch_controls =
SOC_DAPM_SINGLE("Switch", TWL6040_REG_EARCTL, 0, 1, 0);
@@ -548,10 +543,14 @@ static const struct snd_soc_dapm_widget twl6040_dapm_widgets[] = {
TWL6040_REG_DMICBCTL, 4, 0),
/* DACs */
- SND_SOC_DAPM_DAC("HSDAC Left", "Headset Playback",
- TWL6040_REG_HSLCTL, 0, 0),
- SND_SOC_DAPM_DAC("HSDAC Right", "Headset Playback",
- TWL6040_REG_HSRCTL, 0, 0),
+ SND_SOC_DAPM_DAC_E("HSDAC Left", "Headset Playback",
+ TWL6040_REG_HSLCTL, 0, 0,
+ twl6040_hs_dac_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_DAC_E("HSDAC Right", "Headset Playback",
+ TWL6040_REG_HSRCTL, 0, 0,
+ twl6040_hs_dac_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
SND_SOC_DAPM_DAC_E("HFDAC Left", "Handsfree Playback",
TWL6040_REG_HFLCTL, 0, 0,
twl6040_power_mode_event,
@@ -571,18 +570,19 @@ static const struct snd_soc_dapm_widget twl6040_dapm_widgets[] = {
SND_SOC_DAPM_SWITCH("HFDAC Right Playback",
SND_SOC_NOPM, 0, 0, &hfdacr_switch_controls),
- SND_SOC_DAPM_SWITCH("Headset Left Driver",
- SND_SOC_NOPM, 0, 0, &hsl_driver_switch_controls),
- SND_SOC_DAPM_SWITCH("Headset Right Driver",
- SND_SOC_NOPM, 0, 0, &hsr_driver_switch_controls),
- SND_SOC_DAPM_SWITCH_E("Handsfree Left Driver",
- SND_SOC_NOPM, 0, 0, &hfl_driver_switch_controls,
+ /* Analog playback drivers */
+ SND_SOC_DAPM_PGA_E("Handsfree Left Driver",
+ TWL6040_REG_HFLCTL, 4, 0, NULL, 0,
twl6040_power_mode_event,
SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
- SND_SOC_DAPM_SWITCH_E("Handsfree Right Driver",
- SND_SOC_NOPM, 0, 0, &hfr_driver_switch_controls,
+ SND_SOC_DAPM_PGA_E("Handsfree Right Driver",
+ TWL6040_REG_HFRCTL, 4, 0, NULL, 0,
twl6040_power_mode_event,
SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_PGA("Headset Left Driver",
+ TWL6040_REG_HSLCTL, 2, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("Headset Right Driver",
+ TWL6040_REG_HSRCTL, 2, 0, NULL, 0),
SND_SOC_DAPM_SWITCH_E("Earphone Driver",
SND_SOC_NOPM, 0, 0, &ep_driver_switch_controls,
twl6040_power_mode_event,
@@ -616,8 +616,8 @@ static const struct snd_soc_dapm_route intercon[] = {
{"HSDAC Left Playback", "Switch", "HSDAC Left"},
{"HSDAC Right Playback", "Switch", "HSDAC Right"},
- {"Headset Left Driver", "Switch", "HSDAC Left Playback"},
- {"Headset Right Driver", "Switch", "HSDAC Right Playback"},
+ {"Headset Left Driver", NULL, "HSDAC Left Playback"},
+ {"Headset Right Driver", NULL, "HSDAC Right Playback"},
{"HSOL", NULL, "Headset Left Driver"},
{"HSOR", NULL, "Headset Right Driver"},
@@ -928,7 +928,7 @@ static int twl6040_set_dai_sysclk(struct snd_soc_dai *codec_dai,
case 19200000:
/* mclk input, pll disabled */
hppllctl |= TWL6040_MCLK_19200KHZ |
- TWL6040_HPLLSQRBP |
+ TWL6040_HPLLSQRENA |
TWL6040_HPLLBP;
break;
case 26000000:
diff --git a/sound/soc/codecs/uda134x.c b/sound/soc/codecs/uda134x.c
index 28aac53c97b..f3b4c1d6a82 100644
--- a/sound/soc/codecs/uda134x.c
+++ b/sound/soc/codecs/uda134x.c
@@ -28,19 +28,6 @@
#include "uda134x.h"
-#define POWER_OFF_ON_STANDBY 1
-/*
- ALSA SOC usually puts the device in standby mode when it's not used
- for sometime. If you define POWER_OFF_ON_STANDBY the driver will
- turn off the ADC/DAC when this callback is invoked and turn it back
- on when needed. Unfortunately this will result in a very light bump
- (it can be audible only with good earphones). If this bothers you
- just comment this line, you will have slightly higher power
- consumption . Please note that sending the L3 command for ADC is
- enough to make the bump, so it doesn't make difference if you
- completely take off power from the codec.
- */
-
#define UDA134X_RATES SNDRV_PCM_RATE_8000_48000
#define UDA134X_FORMATS (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE | \
SNDRV_PCM_FMTBIT_S18_3LE | SNDRV_PCM_FMTBIT_S20_3LE)
@@ -58,7 +45,7 @@ static const char uda134x_reg[UDA134X_REGS_NUM] = {
/* Extended address registers */
0x04, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00,
/* Status, data regs */
- 0x00, 0x83, 0x00, 0x40, 0x80, 0x00,
+ 0x00, 0x83, 0x00, 0x40, 0x80, 0xC0, 0x00,
};
/*
@@ -117,6 +104,7 @@ static int uda134x_write(struct snd_soc_codec *codec, unsigned int reg,
case UDA134X_DATA000:
case UDA134X_DATA001:
case UDA134X_DATA010:
+ case UDA134X_DATA011:
addr = UDA134X_DATA0_ADDR;
break;
case UDA134X_DATA1:
@@ -353,8 +341,22 @@ static int uda134x_set_bias_level(struct snd_soc_codec *codec,
switch (level) {
case SND_SOC_BIAS_ON:
/* ADC, DAC on */
- reg = uda134x_read_reg_cache(codec, UDA134X_STATUS1);
- uda134x_write(codec, UDA134X_STATUS1, reg | 0x03);
+ switch (pd->model) {
+ case UDA134X_UDA1340:
+ case UDA134X_UDA1344:
+ case UDA134X_UDA1345:
+ reg = uda134x_read_reg_cache(codec, UDA134X_DATA011);
+ uda134x_write(codec, UDA134X_DATA011, reg | 0x03);
+ break;
+ case UDA134X_UDA1341:
+ reg = uda134x_read_reg_cache(codec, UDA134X_STATUS1);
+ uda134x_write(codec, UDA134X_STATUS1, reg | 0x03);
+ break;
+ default:
+ printk(KERN_ERR "UDA134X SoC codec: "
+ "unsupported model %d\n", pd->model);
+ return -EINVAL;
+ }
break;
case SND_SOC_BIAS_PREPARE:
/* power on */
@@ -367,8 +369,22 @@ static int uda134x_set_bias_level(struct snd_soc_codec *codec,
break;
case SND_SOC_BIAS_STANDBY:
/* ADC, DAC power off */
- reg = uda134x_read_reg_cache(codec, UDA134X_STATUS1);
- uda134x_write(codec, UDA134X_STATUS1, reg & ~(0x03));
+ switch (pd->model) {
+ case UDA134X_UDA1340:
+ case UDA134X_UDA1344:
+ case UDA134X_UDA1345:
+ reg = uda134x_read_reg_cache(codec, UDA134X_DATA011);
+ uda134x_write(codec, UDA134X_DATA011, reg & ~(0x03));
+ break;
+ case UDA134X_UDA1341:
+ reg = uda134x_read_reg_cache(codec, UDA134X_STATUS1);
+ uda134x_write(codec, UDA134X_STATUS1, reg & ~(0x03));
+ break;
+ default:
+ printk(KERN_ERR "UDA134X SoC codec: "
+ "unsupported model %d\n", pd->model);
+ return -EINVAL;
+ }
break;
case SND_SOC_BIAS_OFF:
/* power off */
@@ -531,9 +547,7 @@ static int uda134x_soc_probe(struct platform_device *pdev)
codec->num_dai = 1;
codec->read = uda134x_read_reg_cache;
codec->write = uda134x_write;
-#ifdef POWER_OFF_ON_STANDBY
- codec->set_bias_level = uda134x_set_bias_level;
-#endif
+
INIT_LIST_HEAD(&codec->dapm_widgets);
INIT_LIST_HEAD(&codec->dapm_paths);
@@ -544,6 +558,14 @@ static int uda134x_soc_probe(struct platform_device *pdev)
uda134x_reset(codec);
+ if (pd->is_powered_on_standby) {
+ codec->set_bias_level = NULL;
+ uda134x_set_bias_level(codec, SND_SOC_BIAS_ON);
+ } else {
+ codec->set_bias_level = uda134x_set_bias_level;
+ uda134x_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+ }
+
/* register pcms */
ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
if (ret < 0) {
diff --git a/sound/soc/codecs/uda134x.h b/sound/soc/codecs/uda134x.h
index 94f440490b3..205f03b3eaf 100644
--- a/sound/soc/codecs/uda134x.h
+++ b/sound/soc/codecs/uda134x.h
@@ -23,9 +23,10 @@
#define UDA134X_DATA000 10
#define UDA134X_DATA001 11
#define UDA134X_DATA010 12
-#define UDA134X_DATA1 13
+#define UDA134X_DATA011 13
+#define UDA134X_DATA1 14
-#define UDA134X_REGS_NUM 14
+#define UDA134X_REGS_NUM 15
#define STATUS0_DAIFMT_MASK (~(7<<1))
#define STATUS0_SYSCLK_MASK (~(3<<4))
diff --git a/sound/soc/codecs/wm2000.c b/sound/soc/codecs/wm2000.c
index 002e289d125..4bcd168794e 100644
--- a/sound/soc/codecs/wm2000.c
+++ b/sound/soc/codecs/wm2000.c
@@ -795,6 +795,8 @@ static int __devinit wm2000_i2c_probe(struct i2c_client *i2c,
dev_set_drvdata(&i2c->dev, wm2000);
wm2000->anc_eng_ena = 1;
+ wm2000->anc_active = 1;
+ wm2000->spk_ena = 1;
wm2000->i2c = i2c;
wm2000_reset(wm2000);
diff --git a/sound/soc/codecs/wm8523.c b/sound/soc/codecs/wm8523.c
index 37242a7d307..0ad039b4adf 100644
--- a/sound/soc/codecs/wm8523.c
+++ b/sound/soc/codecs/wm8523.c
@@ -482,7 +482,8 @@ static int wm8523_register(struct wm8523_priv *wm8523,
if (wm8523_codec) {
dev_err(codec->dev, "Another WM8523 is registered\n");
- return -EINVAL;
+ ret = -EINVAL;
+ goto err;
}
mutex_init(&codec->mutex);
@@ -570,18 +571,19 @@ static int wm8523_register(struct wm8523_priv *wm8523,
ret = snd_soc_register_codec(codec);
if (ret != 0) {
dev_err(codec->dev, "Failed to register codec: %d\n", ret);
- return ret;
+ goto err_enable;
}
ret = snd_soc_register_dai(&wm8523_dai);
if (ret != 0) {
dev_err(codec->dev, "Failed to register DAI: %d\n", ret);
- snd_soc_unregister_codec(codec);
- return ret;
+ goto err_codec;
}
return 0;
+err_codec:
+ snd_soc_unregister_codec(codec);
err_enable:
regulator_bulk_disable(ARRAY_SIZE(wm8523->supplies), wm8523->supplies);
err_get:
diff --git a/sound/soc/codecs/wm8711.c b/sound/soc/codecs/wm8711.c
index effb14eee7d..e2dba07f026 100644
--- a/sound/soc/codecs/wm8711.c
+++ b/sound/soc/codecs/wm8711.c
@@ -439,7 +439,8 @@ static int wm8711_register(struct wm8711_priv *wm8711,
if (wm8711_codec) {
dev_err(codec->dev, "Another WM8711 is registered\n");
- return -EINVAL;
+ ret = -EINVAL;
+ goto err;
}
mutex_init(&codec->mutex);
diff --git a/sound/soc/codecs/wm8741.c b/sound/soc/codecs/wm8741.c
new file mode 100644
index 00000000000..b9ea8904ad4
--- /dev/null
+++ b/sound/soc/codecs/wm8741.c
@@ -0,0 +1,579 @@
+/*
+ * wm8741.c -- WM8741 ALSA SoC Audio driver
+ *
+ * Copyright 2010 Wolfson Microelectronics plc
+ *
+ * Author: Ian Lartey <ian@opensource.wolfsonmicro.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/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+
+#include "wm8741.h"
+
+static struct snd_soc_codec *wm8741_codec;
+struct snd_soc_codec_device soc_codec_dev_wm8741;
+
+#define WM8741_NUM_SUPPLIES 2
+static const char *wm8741_supply_names[WM8741_NUM_SUPPLIES] = {
+ "AVDD",
+ "DVDD",
+};
+
+#define WM8741_NUM_RATES 4
+
+/* codec private data */
+struct wm8741_priv {
+ struct snd_soc_codec codec;
+ u16 reg_cache[WM8741_REGISTER_COUNT];
+ struct regulator_bulk_data supplies[WM8741_NUM_SUPPLIES];
+ unsigned int sysclk;
+ unsigned int rate_constraint_list[WM8741_NUM_RATES];
+ struct snd_pcm_hw_constraint_list rate_constraint;
+};
+
+static const u16 wm8741_reg_defaults[WM8741_REGISTER_COUNT] = {
+ 0x0000, /* R0 - DACLLSB Attenuation */
+ 0x0000, /* R1 - DACLMSB Attenuation */
+ 0x0000, /* R2 - DACRLSB Attenuation */
+ 0x0000, /* R3 - DACRMSB Attenuation */
+ 0x0000, /* R4 - Volume Control */
+ 0x000A, /* R5 - Format Control */
+ 0x0000, /* R6 - Filter Control */
+ 0x0000, /* R7 - Mode Control 1 */
+ 0x0002, /* R8 - Mode Control 2 */
+ 0x0000, /* R9 - Reset */
+ 0x0002, /* R32 - ADDITONAL_CONTROL_1 */
+};
+
+
+static int wm8741_reset(struct snd_soc_codec *codec)
+{
+ return snd_soc_write(codec, WM8741_RESET, 0);
+}
+
+static const DECLARE_TLV_DB_SCALE(dac_tlv_fine, -12700, 13, 0);
+static const DECLARE_TLV_DB_SCALE(dac_tlv, -12700, 400, 0);
+
+static const struct snd_kcontrol_new wm8741_snd_controls[] = {
+SOC_DOUBLE_R_TLV("Fine Playback Volume", WM8741_DACLLSB_ATTENUATION,
+ WM8741_DACRLSB_ATTENUATION, 1, 255, 1, dac_tlv_fine),
+SOC_DOUBLE_R_TLV("Playback Volume", WM8741_DACLMSB_ATTENUATION,
+ WM8741_DACRMSB_ATTENUATION, 0, 511, 1, dac_tlv),
+};
+
+static const struct snd_soc_dapm_widget wm8741_dapm_widgets[] = {
+SND_SOC_DAPM_DAC("DACL", "Playback", SND_SOC_NOPM, 0, 0),
+SND_SOC_DAPM_DAC("DACR", "Playback", SND_SOC_NOPM, 0, 0),
+SND_SOC_DAPM_OUTPUT("VOUTLP"),
+SND_SOC_DAPM_OUTPUT("VOUTLN"),
+SND_SOC_DAPM_OUTPUT("VOUTRP"),
+SND_SOC_DAPM_OUTPUT("VOUTRN"),
+};
+
+static const struct snd_soc_dapm_route intercon[] = {
+ { "VOUTLP", NULL, "DACL" },
+ { "VOUTLN", NULL, "DACL" },
+ { "VOUTRP", NULL, "DACR" },
+ { "VOUTRN", NULL, "DACR" },
+};
+
+static int wm8741_add_widgets(struct snd_soc_codec *codec)
+{
+ snd_soc_dapm_new_controls(codec, wm8741_dapm_widgets,
+ ARRAY_SIZE(wm8741_dapm_widgets));
+
+ snd_soc_dapm_add_routes(codec, intercon, ARRAY_SIZE(intercon));
+
+ return 0;
+}
+
+static struct {
+ int value;
+ int ratio;
+} lrclk_ratios[WM8741_NUM_RATES] = {
+ { 1, 256 },
+ { 2, 384 },
+ { 3, 512 },
+ { 4, 768 },
+};
+
+
+static int wm8741_startup(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ struct wm8741_priv *wm8741 = snd_soc_codec_get_drvdata(codec);
+
+ /* The set of sample rates that can be supported depends on the
+ * MCLK supplied to the CODEC - enforce this.
+ */
+ if (!wm8741->sysclk) {
+ dev_err(codec->dev,
+ "No MCLK configured, call set_sysclk() on init\n");
+ return -EINVAL;
+ }
+
+ snd_pcm_hw_constraint_list(substream->runtime, 0,
+ SNDRV_PCM_HW_PARAM_RATE,
+ &wm8741->rate_constraint);
+
+ return 0;
+}
+
+static int wm8741_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_device *socdev = rtd->socdev;
+ struct snd_soc_codec *codec = socdev->card->codec;
+ struct wm8741_priv *wm8741 = snd_soc_codec_get_drvdata(codec);
+ u16 iface = snd_soc_read(codec, WM8741_FORMAT_CONTROL) & 0x1FC;
+ int i;
+
+ /* Find a supported LRCLK ratio */
+ for (i = 0; i < ARRAY_SIZE(lrclk_ratios); i++) {
+ if (wm8741->sysclk / params_rate(params) ==
+ lrclk_ratios[i].ratio)
+ break;
+ }
+
+ /* Should never happen, should be handled by constraints */
+ if (i == ARRAY_SIZE(lrclk_ratios)) {
+ dev_err(codec->dev, "MCLK/fs ratio %d unsupported\n",
+ wm8741->sysclk / params_rate(params));
+ return -EINVAL;
+ }
+
+ /* bit size */
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_S16_LE:
+ break;
+ case SNDRV_PCM_FORMAT_S20_3LE:
+ iface |= 0x0001;
+ break;
+ case SNDRV_PCM_FORMAT_S24_LE:
+ iface |= 0x0002;
+ break;
+ case SNDRV_PCM_FORMAT_S32_LE:
+ iface |= 0x0003;
+ break;
+ default:
+ dev_dbg(codec->dev, "wm8741_hw_params: Unsupported bit size param = %d",
+ params_format(params));
+ return -EINVAL;
+ }
+
+ dev_dbg(codec->dev, "wm8741_hw_params: bit size param = %d",
+ params_format(params));
+
+ snd_soc_write(codec, WM8741_FORMAT_CONTROL, iface);
+ return 0;
+}
+
+static int wm8741_set_dai_sysclk(struct snd_soc_dai *codec_dai,
+ int clk_id, unsigned int freq, int dir)
+{
+ struct snd_soc_codec *codec = codec_dai->codec;
+ struct wm8741_priv *wm8741 = snd_soc_codec_get_drvdata(codec);
+ unsigned int val;
+ int i;
+
+ dev_dbg(codec->dev, "wm8741_set_dai_sysclk info: freq=%dHz\n", freq);
+
+ wm8741->sysclk = freq;
+
+ wm8741->rate_constraint.count = 0;
+
+ for (i = 0; i < ARRAY_SIZE(lrclk_ratios); i++) {
+ dev_dbg(codec->dev, "index = %d, ratio = %d, freq = %d",
+ i, lrclk_ratios[i].ratio, freq);
+
+ val = freq / lrclk_ratios[i].ratio;
+ /* Check that it's a standard rate since core can't
+ * cope with others and having the odd rates confuses
+ * constraint matching.
+ */
+ switch (val) {
+ case 32000:
+ case 44100:
+ case 48000:
+ case 64000:
+ case 88200:
+ case 96000:
+ dev_dbg(codec->dev, "Supported sample rate: %dHz\n",
+ val);
+ wm8741->rate_constraint_list[i] = val;
+ wm8741->rate_constraint.count++;
+ break;
+ default:
+ dev_dbg(codec->dev, "Skipping sample rate: %dHz\n",
+ val);
+ }
+ }
+
+ /* Need at least one supported rate... */
+ if (wm8741->rate_constraint.count == 0)
+ return -EINVAL;
+
+ return 0;
+}
+
+static int wm8741_set_dai_fmt(struct snd_soc_dai *codec_dai,
+ unsigned int fmt)
+{
+ struct snd_soc_codec *codec = codec_dai->codec;
+ u16 iface = snd_soc_read(codec, WM8741_FORMAT_CONTROL) & 0x1C3;
+
+ /* check master/slave audio interface */
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBS_CFS:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* interface format */
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ iface |= 0x0008;
+ break;
+ case SND_SOC_DAIFMT_RIGHT_J:
+ break;
+ case SND_SOC_DAIFMT_LEFT_J:
+ iface |= 0x0004;
+ break;
+ case SND_SOC_DAIFMT_DSP_A:
+ iface |= 0x0003;
+ break;
+ case SND_SOC_DAIFMT_DSP_B:
+ iface |= 0x0013;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* clock inversion */
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+ case SND_SOC_DAIFMT_NB_NF:
+ break;
+ case SND_SOC_DAIFMT_IB_IF:
+ iface |= 0x0010;
+ break;
+ case SND_SOC_DAIFMT_IB_NF:
+ iface |= 0x0020;
+ break;
+ case SND_SOC_DAIFMT_NB_IF:
+ iface |= 0x0030;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+
+ dev_dbg(codec->dev, "wm8741_set_dai_fmt: Format=%x, Clock Inv=%x\n",
+ fmt & SND_SOC_DAIFMT_FORMAT_MASK,
+ ((fmt & SND_SOC_DAIFMT_INV_MASK)));
+
+ snd_soc_write(codec, WM8741_FORMAT_CONTROL, iface);
+ return 0;
+}
+
+#define WM8741_RATES (SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \
+ SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | \
+ SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 | \
+ SNDRV_PCM_RATE_192000)
+
+#define WM8741_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
+ SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
+
+static struct snd_soc_dai_ops wm8741_dai_ops = {
+ .startup = wm8741_startup,
+ .hw_params = wm8741_hw_params,
+ .set_sysclk = wm8741_set_dai_sysclk,
+ .set_fmt = wm8741_set_dai_fmt,
+};
+
+struct snd_soc_dai wm8741_dai = {
+ .name = "WM8741",
+ .playback = {
+ .stream_name = "Playback",
+ .channels_min = 2, /* Mono modes not yet supported */
+ .channels_max = 2,
+ .rates = WM8741_RATES,
+ .formats = WM8741_FORMATS,
+ },
+ .ops = &wm8741_dai_ops,
+};
+EXPORT_SYMBOL_GPL(wm8741_dai);
+
+#ifdef CONFIG_PM
+static int wm8741_resume(struct platform_device *pdev)
+{
+ struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+ struct snd_soc_codec *codec = socdev->card->codec;
+ u16 *cache = codec->reg_cache;
+ int i;
+
+ /* RESTORE REG Cache */
+ for (i = 0; i < WM8741_REGISTER_COUNT; i++) {
+ if (cache[i] == wm8741_reg_defaults[i] || WM8741_RESET == i)
+ continue;
+ snd_soc_write(codec, i, cache[i]);
+ }
+ return 0;
+}
+#else
+#define wm8741_suspend NULL
+#define wm8741_resume NULL
+#endif
+
+static int wm8741_probe(struct platform_device *pdev)
+{
+ struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+ struct snd_soc_codec *codec;
+ int ret = 0;
+
+ if (wm8741_codec == NULL) {
+ dev_err(&pdev->dev, "Codec device not registered\n");
+ return -ENODEV;
+ }
+
+ socdev->card->codec = wm8741_codec;
+ codec = wm8741_codec;
+
+ /* register pcms */
+ ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
+ if (ret < 0) {
+ dev_err(codec->dev, "failed to create pcms: %d\n", ret);
+ goto pcm_err;
+ }
+
+ snd_soc_add_controls(codec, wm8741_snd_controls,
+ ARRAY_SIZE(wm8741_snd_controls));
+ wm8741_add_widgets(codec);
+
+ return ret;
+
+pcm_err:
+ return ret;
+}
+
+static int wm8741_remove(struct platform_device *pdev)
+{
+ struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+
+ snd_soc_free_pcms(socdev);
+ snd_soc_dapm_free(socdev);
+
+ return 0;
+}
+
+struct snd_soc_codec_device soc_codec_dev_wm8741 = {
+ .probe = wm8741_probe,
+ .remove = wm8741_remove,
+ .resume = wm8741_resume,
+};
+EXPORT_SYMBOL_GPL(soc_codec_dev_wm8741);
+
+static int wm8741_register(struct wm8741_priv *wm8741,
+ enum snd_soc_control_type control)
+{
+ int ret;
+ struct snd_soc_codec *codec = &wm8741->codec;
+ int i;
+
+ if (wm8741_codec) {
+ dev_err(codec->dev, "Another WM8741 is registered\n");
+ return -EINVAL;
+ }
+
+ mutex_init(&codec->mutex);
+ INIT_LIST_HEAD(&codec->dapm_widgets);
+ INIT_LIST_HEAD(&codec->dapm_paths);
+
+ snd_soc_codec_set_drvdata(codec, wm8741);
+ codec->name = "WM8741";
+ codec->owner = THIS_MODULE;
+ codec->bias_level = SND_SOC_BIAS_OFF;
+ codec->set_bias_level = NULL;
+ codec->dai = &wm8741_dai;
+ codec->num_dai = 1;
+ codec->reg_cache_size = WM8741_REGISTER_COUNT;
+ codec->reg_cache = &wm8741->reg_cache;
+
+ wm8741->rate_constraint.list = &wm8741->rate_constraint_list[0];
+ wm8741->rate_constraint.count =
+ ARRAY_SIZE(wm8741->rate_constraint_list);
+
+ memcpy(codec->reg_cache, wm8741_reg_defaults,
+ sizeof(wm8741->reg_cache));
+
+ ret = snd_soc_codec_set_cache_io(codec, 7, 9, control);
+ if (ret != 0) {
+ dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
+ goto err;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(wm8741->supplies); i++)
+ wm8741->supplies[i].supply = wm8741_supply_names[i];
+
+ ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(wm8741->supplies),
+ wm8741->supplies);
+ if (ret != 0) {
+ dev_err(codec->dev, "Failed to request supplies: %d\n", ret);
+ goto err;
+ }
+
+ ret = regulator_bulk_enable(ARRAY_SIZE(wm8741->supplies),
+ wm8741->supplies);
+ if (ret != 0) {
+ dev_err(codec->dev, "Failed to enable supplies: %d\n", ret);
+ goto err_get;
+ }
+
+ ret = wm8741_reset(codec);
+ if (ret < 0) {
+ dev_err(codec->dev, "Failed to issue reset\n");
+ goto err_enable;
+ }
+
+ wm8741_dai.dev = codec->dev;
+
+ /* Change some default settings - latch VU */
+ wm8741->reg_cache[WM8741_DACLLSB_ATTENUATION] |= WM8741_UPDATELL;
+ wm8741->reg_cache[WM8741_DACLMSB_ATTENUATION] |= WM8741_UPDATELM;
+ wm8741->reg_cache[WM8741_DACRLSB_ATTENUATION] |= WM8741_UPDATERL;
+ wm8741->reg_cache[WM8741_DACRLSB_ATTENUATION] |= WM8741_UPDATERM;
+
+ wm8741_codec = codec;
+
+ ret = snd_soc_register_codec(codec);
+ if (ret != 0) {
+ dev_err(codec->dev, "Failed to register codec: %d\n", ret);
+ return ret;
+ }
+
+ ret = snd_soc_register_dai(&wm8741_dai);
+ if (ret != 0) {
+ dev_err(codec->dev, "Failed to register DAI: %d\n", ret);
+ snd_soc_unregister_codec(codec);
+ return ret;
+ }
+
+ dev_dbg(codec->dev, "Successful registration\n");
+ return 0;
+
+err_enable:
+ regulator_bulk_disable(ARRAY_SIZE(wm8741->supplies), wm8741->supplies);
+
+err_get:
+ regulator_bulk_free(ARRAY_SIZE(wm8741->supplies), wm8741->supplies);
+
+err:
+ kfree(wm8741);
+ return ret;
+}
+
+static void wm8741_unregister(struct wm8741_priv *wm8741)
+{
+ regulator_bulk_free(ARRAY_SIZE(wm8741->supplies), wm8741->supplies);
+
+ snd_soc_unregister_dai(&wm8741_dai);
+ snd_soc_unregister_codec(&wm8741->codec);
+ kfree(wm8741);
+ wm8741_codec = NULL;
+}
+
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+static __devinit int wm8741_i2c_probe(struct i2c_client *i2c,
+ const struct i2c_device_id *id)
+{
+ struct wm8741_priv *wm8741;
+ struct snd_soc_codec *codec;
+
+ wm8741 = kzalloc(sizeof(struct wm8741_priv), GFP_KERNEL);
+ if (wm8741 == NULL)
+ return -ENOMEM;
+
+ codec = &wm8741->codec;
+ codec->hw_write = (hw_write_t)i2c_master_send;
+
+ i2c_set_clientdata(i2c, wm8741);
+ codec->control_data = i2c;
+
+ codec->dev = &i2c->dev;
+
+ return wm8741_register(wm8741, SND_SOC_I2C);
+}
+
+static __devexit int wm8741_i2c_remove(struct i2c_client *client)
+{
+ struct wm8741_priv *wm8741 = i2c_get_clientdata(client);
+ wm8741_unregister(wm8741);
+ return 0;
+}
+
+static const struct i2c_device_id wm8741_i2c_id[] = {
+ { "wm8741", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, wm8741_i2c_id);
+
+
+static struct i2c_driver wm8741_i2c_driver = {
+ .driver = {
+ .name = "WM8741",
+ .owner = THIS_MODULE,
+ },
+ .probe = wm8741_i2c_probe,
+ .remove = __devexit_p(wm8741_i2c_remove),
+ .id_table = wm8741_i2c_id,
+};
+#endif
+
+static int __init wm8741_modinit(void)
+{
+ int ret;
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+ ret = i2c_add_driver(&wm8741_i2c_driver);
+ if (ret != 0) {
+ printk(KERN_ERR "Failed to register WM8741 I2C driver: %d\n",
+ ret);
+ }
+#endif
+ return 0;
+}
+module_init(wm8741_modinit);
+
+static void __exit wm8741_exit(void)
+{
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+ i2c_del_driver(&wm8741_i2c_driver);
+#endif
+}
+module_exit(wm8741_exit);
+
+MODULE_DESCRIPTION("ASoC WM8741 driver");
+MODULE_AUTHOR("Ian Lartey <ian@opensource.wolfsonmicro.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/wm8741.h b/sound/soc/codecs/wm8741.h
new file mode 100644
index 00000000000..fdef6ecd1f6
--- /dev/null
+++ b/sound/soc/codecs/wm8741.h
@@ -0,0 +1,214 @@
+/*
+ * wm8741.h -- WM8423 ASoC driver
+ *
+ * Copyright 2010 Wolfson Microelectronics, plc
+ *
+ * Author: Ian Lartey <ian@opensource.wolfsonmicro.com>
+ *
+ * Based on wm8753.h
+ *
+ * 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 _WM8741_H
+#define _WM8741_H
+
+/*
+ * Register values.
+ */
+#define WM8741_DACLLSB_ATTENUATION 0x00
+#define WM8741_DACLMSB_ATTENUATION 0x01
+#define WM8741_DACRLSB_ATTENUATION 0x02
+#define WM8741_DACRMSB_ATTENUATION 0x03
+#define WM8741_VOLUME_CONTROL 0x04
+#define WM8741_FORMAT_CONTROL 0x05
+#define WM8741_FILTER_CONTROL 0x06
+#define WM8741_MODE_CONTROL_1 0x07
+#define WM8741_MODE_CONTROL_2 0x08
+#define WM8741_RESET 0x09
+#define WM8741_ADDITIONAL_CONTROL_1 0x20
+
+#define WM8741_REGISTER_COUNT 11
+#define WM8741_MAX_REGISTER 0x20
+
+/*
+ * Field Definitions.
+ */
+
+/*
+ * R0 (0x00) - DACLLSB_ATTENUATION
+ */
+#define WM8741_UPDATELL 0x0020 /* UPDATELL */
+#define WM8741_UPDATELL_MASK 0x0020 /* UPDATELL */
+#define WM8741_UPDATELL_SHIFT 5 /* UPDATELL */
+#define WM8741_UPDATELL_WIDTH 1 /* UPDATELL */
+#define WM8741_LAT_4_0_MASK 0x001F /* LAT[4:0] - [4:0] */
+#define WM8741_LAT_4_0_SHIFT 0 /* LAT[4:0] - [4:0] */
+#define WM8741_LAT_4_0_WIDTH 5 /* LAT[4:0] - [4:0] */
+
+/*
+ * R1 (0x01) - DACLMSB_ATTENUATION
+ */
+#define WM8741_UPDATELM 0x0020 /* UPDATELM */
+#define WM8741_UPDATELM_MASK 0x0020 /* UPDATELM */
+#define WM8741_UPDATELM_SHIFT 5 /* UPDATELM */
+#define WM8741_UPDATELM_WIDTH 1 /* UPDATELM */
+#define WM8741_LAT_9_5_0_MASK 0x001F /* LAT[9:5] - [4:0] */
+#define WM8741_LAT_9_5_0_SHIFT 0 /* LAT[9:5] - [4:0] */
+#define WM8741_LAT_9_5_0_WIDTH 5 /* LAT[9:5] - [4:0] */
+
+/*
+ * R2 (0x02) - DACRLSB_ATTENUATION
+ */
+#define WM8741_UPDATERL 0x0020 /* UPDATERL */
+#define WM8741_UPDATERL_MASK 0x0020 /* UPDATERL */
+#define WM8741_UPDATERL_SHIFT 5 /* UPDATERL */
+#define WM8741_UPDATERL_WIDTH 1 /* UPDATERL */
+#define WM8741_RAT_4_0_MASK 0x001F /* RAT[4:0] - [4:0] */
+#define WM8741_RAT_4_0_SHIFT 0 /* RAT[4:0] - [4:0] */
+#define WM8741_RAT_4_0_WIDTH 5 /* RAT[4:0] - [4:0] */
+
+/*
+ * R3 (0x03) - DACRMSB_ATTENUATION
+ */
+#define WM8741_UPDATERM 0x0020 /* UPDATERM */
+#define WM8741_UPDATERM_MASK 0x0020 /* UPDATERM */
+#define WM8741_UPDATERM_SHIFT 5 /* UPDATERM */
+#define WM8741_UPDATERM_WIDTH 1 /* UPDATERM */
+#define WM8741_RAT_9_5_0_MASK 0x001F /* RAT[9:5] - [4:0] */
+#define WM8741_RAT_9_5_0_SHIFT 0 /* RAT[9:5] - [4:0] */
+#define WM8741_RAT_9_5_0_WIDTH 5 /* RAT[9:5] - [4:0] */
+
+/*
+ * R4 (0x04) - VOLUME_CONTROL
+ */
+#define WM8741_AMUTE 0x0080 /* AMUTE */
+#define WM8741_AMUTE_MASK 0x0080 /* AMUTE */
+#define WM8741_AMUTE_SHIFT 7 /* AMUTE */
+#define WM8741_AMUTE_WIDTH 1 /* AMUTE */
+#define WM8741_ZFLAG_MASK 0x0060 /* ZFLAG - [6:5] */
+#define WM8741_ZFLAG_SHIFT 5 /* ZFLAG - [6:5] */
+#define WM8741_ZFLAG_WIDTH 2 /* ZFLAG - [6:5] */
+#define WM8741_IZD 0x0010 /* IZD */
+#define WM8741_IZD_MASK 0x0010 /* IZD */
+#define WM8741_IZD_SHIFT 4 /* IZD */
+#define WM8741_IZD_WIDTH 1 /* IZD */
+#define WM8741_SOFT 0x0008 /* SOFT MUTE */
+#define WM8741_SOFT_MASK 0x0008 /* SOFT MUTE */
+#define WM8741_SOFT_SHIFT 3 /* SOFT MUTE */
+#define WM8741_SOFT_WIDTH 1 /* SOFT MUTE */
+#define WM8741_ATC 0x0004 /* ATC */
+#define WM8741_ATC_MASK 0x0004 /* ATC */
+#define WM8741_ATC_SHIFT 2 /* ATC */
+#define WM8741_ATC_WIDTH 1 /* ATC */
+#define WM8741_ATT2DB 0x0002 /* ATT2DB */
+#define WM8741_ATT2DB_MASK 0x0002 /* ATT2DB */
+#define WM8741_ATT2DB_SHIFT 1 /* ATT2DB */
+#define WM8741_ATT2DB_WIDTH 1 /* ATT2DB */
+#define WM8741_VOL_RAMP 0x0001 /* VOL_RAMP */
+#define WM8741_VOL_RAMP_MASK 0x0001 /* VOL_RAMP */
+#define WM8741_VOL_RAMP_SHIFT 0 /* VOL_RAMP */
+#define WM8741_VOL_RAMP_WIDTH 1 /* VOL_RAMP */
+
+/*
+ * R5 (0x05) - FORMAT_CONTROL
+ */
+#define WM8741_PWDN 0x0080 /* PWDN */
+#define WM8741_PWDN_MASK 0x0080 /* PWDN */
+#define WM8741_PWDN_SHIFT 7 /* PWDN */
+#define WM8741_PWDN_WIDTH 1 /* PWDN */
+#define WM8741_REV 0x0040 /* REV */
+#define WM8741_REV_MASK 0x0040 /* REV */
+#define WM8741_REV_SHIFT 6 /* REV */
+#define WM8741_REV_WIDTH 1 /* REV */
+#define WM8741_BCP 0x0020 /* BCP */
+#define WM8741_BCP_MASK 0x0020 /* BCP */
+#define WM8741_BCP_SHIFT 5 /* BCP */
+#define WM8741_BCP_WIDTH 1 /* BCP */
+#define WM8741_LRP 0x0010 /* LRP */
+#define WM8741_LRP_MASK 0x0010 /* LRP */
+#define WM8741_LRP_SHIFT 4 /* LRP */
+#define WM8741_LRP_WIDTH 1 /* LRP */
+#define WM8741_FMT_MASK 0x000C /* FMT - [3:2] */
+#define WM8741_FMT_SHIFT 2 /* FMT - [3:2] */
+#define WM8741_FMT_WIDTH 2 /* FMT - [3:2] */
+#define WM8741_IWL_MASK 0x0003 /* IWL - [1:0] */
+#define WM8741_IWL_SHIFT 0 /* IWL - [1:0] */
+#define WM8741_IWL_WIDTH 2 /* IWL - [1:0] */
+
+/*
+ * R6 (0x06) - FILTER_CONTROL
+ */
+#define WM8741_ZFLAG_HI 0x0080 /* ZFLAG_HI */
+#define WM8741_ZFLAG_HI_MASK 0x0080 /* ZFLAG_HI */
+#define WM8741_ZFLAG_HI_SHIFT 7 /* ZFLAG_HI */
+#define WM8741_ZFLAG_HI_WIDTH 1 /* ZFLAG_HI */
+#define WM8741_DEEMPH_MASK 0x0060 /* DEEMPH - [6:5] */
+#define WM8741_DEEMPH_SHIFT 5 /* DEEMPH - [6:5] */
+#define WM8741_DEEMPH_WIDTH 2 /* DEEMPH - [6:5] */
+#define WM8741_DSDFILT_MASK 0x0018 /* DSDFILT - [4:3] */
+#define WM8741_DSDFILT_SHIFT 3 /* DSDFILT - [4:3] */
+#define WM8741_DSDFILT_WIDTH 2 /* DSDFILT - [4:3] */
+#define WM8741_FIRSEL_MASK 0x0007 /* FIRSEL - [2:0] */
+#define WM8741_FIRSEL_SHIFT 0 /* FIRSEL - [2:0] */
+#define WM8741_FIRSEL_WIDTH 3 /* FIRSEL - [2:0] */
+
+/*
+ * R7 (0x07) - MODE_CONTROL_1
+ */
+#define WM8741_MODE8X 0x0080 /* MODE8X */
+#define WM8741_MODE8X_MASK 0x0080 /* MODE8X */
+#define WM8741_MODE8X_SHIFT 7 /* MODE8X */
+#define WM8741_MODE8X_WIDTH 1 /* MODE8X */
+#define WM8741_OSR_MASK 0x0060 /* OSR - [6:5] */
+#define WM8741_OSR_SHIFT 5 /* OSR - [6:5] */
+#define WM8741_OSR_WIDTH 2 /* OSR - [6:5] */
+#define WM8741_SR_MASK 0x001C /* SR - [4:2] */
+#define WM8741_SR_SHIFT 2 /* SR - [4:2] */
+#define WM8741_SR_WIDTH 3 /* SR - [4:2] */
+#define WM8741_MODESEL_MASK 0x0003 /* MODESEL - [1:0] */
+#define WM8741_MODESEL_SHIFT 0 /* MODESEL - [1:0] */
+#define WM8741_MODESEL_WIDTH 2 /* MODESEL - [1:0] */
+
+/*
+ * R8 (0x08) - MODE_CONTROL_2
+ */
+#define WM8741_DSD_GAIN 0x0040 /* DSD_GAIN */
+#define WM8741_DSD_GAIN_MASK 0x0040 /* DSD_GAIN */
+#define WM8741_DSD_GAIN_SHIFT 6 /* DSD_GAIN */
+#define WM8741_DSD_GAIN_WIDTH 1 /* DSD_GAIN */
+#define WM8741_SDOUT 0x0020 /* SDOUT */
+#define WM8741_SDOUT_MASK 0x0020 /* SDOUT */
+#define WM8741_SDOUT_SHIFT 5 /* SDOUT */
+#define WM8741_SDOUT_WIDTH 1 /* SDOUT */
+#define WM8741_DOUT 0x0010 /* DOUT */
+#define WM8741_DOUT_MASK 0x0010 /* DOUT */
+#define WM8741_DOUT_SHIFT 4 /* DOUT */
+#define WM8741_DOUT_WIDTH 1 /* DOUT */
+#define WM8741_DIFF_MASK 0x000C /* DIFF - [3:2] */
+#define WM8741_DIFF_SHIFT 2 /* DIFF - [3:2] */
+#define WM8741_DIFF_WIDTH 2 /* DIFF - [3:2] */
+#define WM8741_DITHER_MASK 0x0003 /* DITHER - [1:0] */
+#define WM8741_DITHER_SHIFT 0 /* DITHER - [1:0] */
+#define WM8741_DITHER_WIDTH 2 /* DITHER - [1:0] */
+
+/*
+ * R32 (0x20) - ADDITONAL_CONTROL_1
+ */
+#define WM8741_DSD_LEVEL 0x0002 /* DSD_LEVEL */
+#define WM8741_DSD_LEVEL_MASK 0x0002 /* DSD_LEVEL */
+#define WM8741_DSD_LEVEL_SHIFT 1 /* DSD_LEVEL */
+#define WM8741_DSD_LEVEL_WIDTH 1 /* DSD_LEVEL */
+#define WM8741_DSD_NO_NOTCH 0x0001 /* DSD_NO_NOTCH */
+#define WM8741_DSD_NO_NOTCH_MASK 0x0001 /* DSD_NO_NOTCH */
+#define WM8741_DSD_NO_NOTCH_SHIFT 0 /* DSD_NO_NOTCH */
+#define WM8741_DSD_NO_NOTCH_WIDTH 1 /* DSD_NO_NOTCH */
+
+#define WM8741_SYSCLK 0
+
+extern struct snd_soc_dai wm8741_dai;
+extern struct snd_soc_codec_device soc_codec_dev_wm8741;
+
+#endif
diff --git a/sound/soc/codecs/wm8750.c b/sound/soc/codecs/wm8750.c
index 9407e193fcc..e2c05e3e323 100644
--- a/sound/soc/codecs/wm8750.c
+++ b/sound/soc/codecs/wm8750.c
@@ -884,6 +884,7 @@ static int wm8750_i2c_remove(struct i2c_client *client)
static const struct i2c_device_id wm8750_i2c_id[] = {
{ "wm8750", 0 },
+ { "wm8987", 0 }, /* WM8987 is register compatible with WM8750 */
{ }
};
MODULE_DEVICE_TABLE(i2c, wm8750_i2c_id);
@@ -925,14 +926,22 @@ static int __devexit wm8750_spi_remove(struct spi_device *spi)
return 0;
}
+static const struct spi_device_id wm8750_spi_id[] = {
+ { "wm8750", 0 },
+ { "wm8987", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(spi, wm8750_spi_id);
+
static struct spi_driver wm8750_spi_driver = {
.driver = {
- .name = "wm8750",
+ .name = "WM8750 SPI Codec",
.bus = &spi_bus_type,
.owner = THIS_MODULE,
},
.probe = wm8750_spi_probe,
.remove = __devexit_p(wm8750_spi_remove),
+ .id_table = wm8750_spi_id,
};
#endif
diff --git a/sound/soc/codecs/wm8904.c b/sound/soc/codecs/wm8904.c
index 87f14f8675f..f7dcabf6283 100644
--- a/sound/soc/codecs/wm8904.c
+++ b/sound/soc/codecs/wm8904.c
@@ -2433,7 +2433,8 @@ static int wm8904_register(struct wm8904_priv *wm8904,
if (wm8904_codec) {
dev_err(codec->dev, "Another WM8904 is registered\n");
- return -EINVAL;
+ ret = -EINVAL;
+ goto err;
}
mutex_init(&codec->mutex);
@@ -2462,7 +2463,8 @@ static int wm8904_register(struct wm8904_priv *wm8904,
default:
dev_err(codec->dev, "Unknown device type %d\n",
wm8904->devtype);
- return -EINVAL;
+ ret = -EINVAL;
+ goto err;
}
memcpy(codec->reg_cache, wm8904_reg, sizeof(wm8904_reg));
@@ -2566,18 +2568,19 @@ static int wm8904_register(struct wm8904_priv *wm8904,
ret = snd_soc_register_codec(codec);
if (ret != 0) {
dev_err(codec->dev, "Failed to register codec: %d\n", ret);
- return ret;
+ goto err_enable;
}
ret = snd_soc_register_dai(&wm8904_dai);
if (ret != 0) {
dev_err(codec->dev, "Failed to register DAI: %d\n", ret);
- snd_soc_unregister_codec(codec);
- return ret;
+ goto err_codec;
}
return 0;
+err_codec:
+ snd_soc_unregister_codec(codec);
err_enable:
regulator_bulk_disable(ARRAY_SIZE(wm8904->supplies), wm8904->supplies);
err_get:
diff --git a/sound/soc/codecs/wm8940.c b/sound/soc/codecs/wm8940.c
index e3c4bbfaae2..f0c11138e61 100644
--- a/sound/soc/codecs/wm8940.c
+++ b/sound/soc/codecs/wm8940.c
@@ -845,6 +845,7 @@ static void wm8940_unregister(struct wm8940_priv *wm8940)
static int wm8940_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
+ int ret;
struct wm8940_priv *wm8940;
struct snd_soc_codec *codec;
@@ -858,7 +859,11 @@ static int wm8940_i2c_probe(struct i2c_client *i2c,
codec->control_data = i2c;
codec->dev = &i2c->dev;
- return wm8940_register(wm8940, SND_SOC_I2C);
+ ret = wm8940_register(wm8940, SND_SOC_I2C);
+ if (ret < 0)
+ kfree(wm8940);
+
+ return ret;
}
static int __devexit wm8940_i2c_remove(struct i2c_client *client)
diff --git a/sound/soc/codecs/wm8955.c b/sound/soc/codecs/wm8955.c
index fedb76452f1..5f025593d84 100644
--- a/sound/soc/codecs/wm8955.c
+++ b/sound/soc/codecs/wm8955.c
@@ -964,7 +964,8 @@ static int wm8955_register(struct wm8955_priv *wm8955,
if (wm8955_codec) {
dev_err(codec->dev, "Another WM8955 is registered\n");
- return -EINVAL;
+ ret = -EINVAL;
+ goto err;
}
mutex_init(&codec->mutex);
@@ -1047,18 +1048,19 @@ static int wm8955_register(struct wm8955_priv *wm8955,
ret = snd_soc_register_codec(codec);
if (ret != 0) {
dev_err(codec->dev, "Failed to register codec: %d\n", ret);
- return ret;
+ goto err_enable;
}
ret = snd_soc_register_dai(&wm8955_dai);
if (ret != 0) {
dev_err(codec->dev, "Failed to register DAI: %d\n", ret);
- snd_soc_unregister_codec(codec);
- return ret;
+ goto err_codec;
}
return 0;
+err_codec:
+ snd_soc_unregister_codec(codec);
err_enable:
regulator_bulk_disable(ARRAY_SIZE(wm8955->supplies), wm8955->supplies);
err_get:
diff --git a/sound/soc/codecs/wm8960.c b/sound/soc/codecs/wm8960.c
index 7233cc68435..3c6ee61f6c9 100644
--- a/sound/soc/codecs/wm8960.c
+++ b/sound/soc/codecs/wm8960.c
@@ -79,12 +79,13 @@ struct wm8960_priv {
struct snd_soc_dapm_widget *lout1;
struct snd_soc_dapm_widget *rout1;
struct snd_soc_dapm_widget *out3;
+ bool deemph;
+ int playback_fs;
};
#define wm8960_reset(c) snd_soc_write(c, WM8960_RESET, 0)
/* enumerated controls */
-static const char *wm8960_deemph[] = {"None", "32Khz", "44.1Khz", "48Khz"};
static const char *wm8960_polarity[] = {"No Inversion", "Left Inverted",
"Right Inverted", "Stereo Inversion"};
static const char *wm8960_3d_upper_cutoff[] = {"High", "Low"};
@@ -93,7 +94,6 @@ static const char *wm8960_alcfunc[] = {"Off", "Right", "Left", "Stereo"};
static const char *wm8960_alcmode[] = {"ALC", "Limiter"};
static const struct soc_enum wm8960_enum[] = {
- SOC_ENUM_SINGLE(WM8960_DACCTL1, 1, 4, wm8960_deemph),
SOC_ENUM_SINGLE(WM8960_DACCTL1, 5, 4, wm8960_polarity),
SOC_ENUM_SINGLE(WM8960_DACCTL2, 5, 4, wm8960_polarity),
SOC_ENUM_SINGLE(WM8960_3D, 6, 2, wm8960_3d_upper_cutoff),
@@ -102,6 +102,59 @@ static const struct soc_enum wm8960_enum[] = {
SOC_ENUM_SINGLE(WM8960_ALC3, 8, 2, wm8960_alcmode),
};
+static const int deemph_settings[] = { 0, 32000, 44100, 48000 };
+
+static int wm8960_set_deemph(struct snd_soc_codec *codec)
+{
+ struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec);
+ int val, i, best;
+
+ /* If we're using deemphasis select the nearest available sample
+ * rate.
+ */
+ if (wm8960->deemph) {
+ best = 1;
+ for (i = 2; i < ARRAY_SIZE(deemph_settings); i++) {
+ if (abs(deemph_settings[i] - wm8960->playback_fs) <
+ abs(deemph_settings[best] - wm8960->playback_fs))
+ best = i;
+ }
+
+ val = best << 1;
+ } else {
+ val = 0;
+ }
+
+ dev_dbg(codec->dev, "Set deemphasis %d\n", val);
+
+ return snd_soc_update_bits(codec, WM8960_DACCTL1,
+ 0x6, val);
+}
+
+static int wm8960_get_deemph(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec);
+
+ return wm8960->deemph;
+}
+
+static int wm8960_put_deemph(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec);
+ int deemph = ucontrol->value.enumerated.item[0];
+
+ if (deemph > 1)
+ return -EINVAL;
+
+ wm8960->deemph = deemph;
+
+ return wm8960_set_deemph(codec);
+}
+
static const DECLARE_TLV_DB_SCALE(adc_tlv, -9700, 50, 0);
static const DECLARE_TLV_DB_SCALE(dac_tlv, -12700, 50, 1);
static const DECLARE_TLV_DB_SCALE(bypass_tlv, -2100, 300, 0);
@@ -131,23 +184,24 @@ SOC_SINGLE("Speaker DC Volume", WM8960_CLASSD3, 3, 5, 0),
SOC_SINGLE("Speaker AC Volume", WM8960_CLASSD3, 0, 5, 0),
SOC_SINGLE("PCM Playback -6dB Switch", WM8960_DACCTL1, 7, 1, 0),
-SOC_ENUM("ADC Polarity", wm8960_enum[1]),
-SOC_ENUM("Playback De-emphasis", wm8960_enum[0]),
+SOC_ENUM("ADC Polarity", wm8960_enum[0]),
SOC_SINGLE("ADC High Pass Filter Switch", WM8960_DACCTL1, 0, 1, 0),
SOC_ENUM("DAC Polarity", wm8960_enum[2]),
+SOC_SINGLE_BOOL_EXT("DAC Deemphasis Switch", 0,
+ wm8960_get_deemph, wm8960_put_deemph),
-SOC_ENUM("3D Filter Upper Cut-Off", wm8960_enum[3]),
-SOC_ENUM("3D Filter Lower Cut-Off", wm8960_enum[4]),
+SOC_ENUM("3D Filter Upper Cut-Off", wm8960_enum[2]),
+SOC_ENUM("3D Filter Lower Cut-Off", wm8960_enum[3]),
SOC_SINGLE("3D Volume", WM8960_3D, 1, 15, 0),
SOC_SINGLE("3D Switch", WM8960_3D, 0, 1, 0),
-SOC_ENUM("ALC Function", wm8960_enum[5]),
+SOC_ENUM("ALC Function", wm8960_enum[4]),
SOC_SINGLE("ALC Max Gain", WM8960_ALC1, 4, 7, 0),
SOC_SINGLE("ALC Target", WM8960_ALC1, 0, 15, 1),
SOC_SINGLE("ALC Min Gain", WM8960_ALC2, 4, 7, 0),
SOC_SINGLE("ALC Hold Time", WM8960_ALC2, 0, 15, 0),
-SOC_ENUM("ALC Mode", wm8960_enum[6]),
+SOC_ENUM("ALC Mode", wm8960_enum[5]),
SOC_SINGLE("ALC Decay", WM8960_ALC3, 4, 15, 0),
SOC_SINGLE("ALC Attack", WM8960_ALC3, 0, 15, 0),
@@ -433,6 +487,21 @@ static int wm8960_set_dai_fmt(struct snd_soc_dai *codec_dai,
return 0;
}
+static struct {
+ int rate;
+ unsigned int val;
+} alc_rates[] = {
+ { 48000, 0 },
+ { 44100, 0 },
+ { 32000, 1 },
+ { 22050, 2 },
+ { 24000, 2 },
+ { 16000, 3 },
+ { 11250, 4 },
+ { 12000, 4 },
+ { 8000, 5 },
+};
+
static int wm8960_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
@@ -440,7 +509,9 @@ static int wm8960_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_device *socdev = rtd->socdev;
struct snd_soc_codec *codec = socdev->card->codec;
+ struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec);
u16 iface = snd_soc_read(codec, WM8960_IFACE1) & 0xfff3;
+ int i;
/* bit size */
switch (params_format(params)) {
@@ -454,6 +525,18 @@ static int wm8960_hw_params(struct snd_pcm_substream *substream,
break;
}
+ /* Update filters for the new rate */
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ wm8960->playback_fs = params_rate(params);
+ wm8960_set_deemph(codec);
+ } else {
+ for (i = 0; i < ARRAY_SIZE(alc_rates); i++)
+ if (alc_rates[i].rate == params_rate(params))
+ snd_soc_update_bits(codec,
+ WM8960_ADDCTL3, 0x7,
+ alc_rates[i].val);
+ }
+
/* set iface */
snd_soc_write(codec, WM8960_IFACE1, iface);
return 0;
diff --git a/sound/soc/codecs/wm8961.c b/sound/soc/codecs/wm8961.c
index 5b9a756242f..2549d3a297a 100644
--- a/sound/soc/codecs/wm8961.c
+++ b/sound/soc/codecs/wm8961.c
@@ -1102,7 +1102,7 @@ static int wm8961_register(struct wm8961_priv *wm8961)
ret = wm8961_reset(codec);
if (ret < 0) {
dev_err(codec->dev, "Failed to issue reset\n");
- return ret;
+ goto err;
}
/* Enable class W */
@@ -1147,18 +1147,19 @@ static int wm8961_register(struct wm8961_priv *wm8961)
ret = snd_soc_register_codec(codec);
if (ret != 0) {
dev_err(codec->dev, "Failed to register codec: %d\n", ret);
- return ret;
+ goto err;
}
ret = snd_soc_register_dai(&wm8961_dai);
if (ret != 0) {
dev_err(codec->dev, "Failed to register DAI: %d\n", ret);
- snd_soc_unregister_codec(codec);
- return ret;
+ goto err_codec;
}
return 0;
+err_codec:
+ snd_soc_unregister_codec(codec);
err:
kfree(wm8961);
return ret;
diff --git a/sound/soc/codecs/wm8974.c b/sound/soc/codecs/wm8974.c
index a2c4b2f37cc..1468fe10cbb 100644
--- a/sound/soc/codecs/wm8974.c
+++ b/sound/soc/codecs/wm8974.c
@@ -670,7 +670,8 @@ static __devinit int wm8974_register(struct wm8974_priv *wm8974)
if (wm8974_codec) {
dev_err(codec->dev, "Another WM8974 is registered\n");
- return -EINVAL;
+ ret = -EINVAL;
+ goto err;
}
mutex_init(&codec->mutex);
diff --git a/sound/soc/codecs/wm8978.c b/sound/soc/codecs/wm8978.c
index 51d5f433215..8a1ad778e7e 100644
--- a/sound/soc/codecs/wm8978.c
+++ b/sound/soc/codecs/wm8978.c
@@ -1076,7 +1076,6 @@ static __devinit int wm8978_register(struct wm8978_priv *wm8978)
err_codec:
snd_soc_unregister_codec(codec);
err:
- kfree(wm8978);
return ret;
}
@@ -1085,13 +1084,13 @@ static __devexit void wm8978_unregister(struct wm8978_priv *wm8978)
wm8978_set_bias_level(&wm8978->codec, SND_SOC_BIAS_OFF);
snd_soc_unregister_dai(&wm8978_dai);
snd_soc_unregister_codec(&wm8978->codec);
- kfree(wm8978);
wm8978_codec = NULL;
}
static __devinit int wm8978_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
+ int ret;
struct wm8978_priv *wm8978;
struct snd_soc_codec *codec;
@@ -1107,13 +1106,18 @@ static __devinit int wm8978_i2c_probe(struct i2c_client *i2c,
codec->dev = &i2c->dev;
- return wm8978_register(wm8978);
+ ret = wm8978_register(wm8978);
+ if (ret < 0)
+ kfree(wm8978);
+
+ return ret;
}
static __devexit int wm8978_i2c_remove(struct i2c_client *client)
{
struct wm8978_priv *wm8978 = i2c_get_clientdata(client);
wm8978_unregister(wm8978);
+ kfree(wm8978);
return 0;
}
diff --git a/sound/soc/codecs/wm8990.c b/sound/soc/codecs/wm8990.c
index c018772cc43..dd8d909788c 100644
--- a/sound/soc/codecs/wm8990.c
+++ b/sound/soc/codecs/wm8990.c
@@ -30,8 +30,6 @@
#include "wm8990.h"
-#define WM8990_VERSION "0.2"
-
/* codec private data */
struct wm8990_priv {
unsigned int sysclk;
@@ -1511,8 +1509,6 @@ static int wm8990_probe(struct platform_device *pdev)
struct wm8990_priv *wm8990;
int ret;
- pr_info("WM8990 Audio Codec %s\n", WM8990_VERSION);
-
setup = socdev->codec_data;
codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
if (codec == NULL)
diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c
index e84a1177f35..a87046a96f2 100644
--- a/sound/soc/codecs/wm8994.c
+++ b/sound/soc/codecs/wm8994.c
@@ -1677,6 +1677,26 @@ static struct {
static int wm8994_readable(unsigned int reg)
{
+ switch (reg) {
+ case WM8994_GPIO_1:
+ case WM8994_GPIO_2:
+ case WM8994_GPIO_3:
+ case WM8994_GPIO_4:
+ case WM8994_GPIO_5:
+ case WM8994_GPIO_6:
+ case WM8994_GPIO_7:
+ case WM8994_GPIO_8:
+ case WM8994_GPIO_9:
+ case WM8994_GPIO_10:
+ case WM8994_GPIO_11:
+ case WM8994_INTERRUPT_STATUS_1:
+ case WM8994_INTERRUPT_STATUS_2:
+ case WM8994_INTERRUPT_RAW_STATUS_2:
+ return 1;
+ default:
+ break;
+ }
+
if (reg >= ARRAY_SIZE(access_masks))
return 0;
return access_masks[reg].readable != 0;
@@ -2341,6 +2361,20 @@ SOC_DAPM_SINGLE("AIF2 Switch", WM8994_AIF1_ADC1_RIGHT_MIXER_ROUTING,
0, 1, 0),
};
+static const struct snd_kcontrol_new aif1adc2l_mix[] = {
+SOC_DAPM_SINGLE("DMIC Switch", WM8994_AIF1_ADC2_LEFT_MIXER_ROUTING,
+ 1, 1, 0),
+SOC_DAPM_SINGLE("AIF2 Switch", WM8994_AIF1_ADC2_LEFT_MIXER_ROUTING,
+ 0, 1, 0),
+};
+
+static const struct snd_kcontrol_new aif1adc2r_mix[] = {
+SOC_DAPM_SINGLE("DMIC Switch", WM8994_AIF1_ADC2_RIGHT_MIXER_ROUTING,
+ 1, 1, 0),
+SOC_DAPM_SINGLE("AIF2 Switch", WM8994_AIF1_ADC2_RIGHT_MIXER_ROUTING,
+ 0, 1, 0),
+};
+
static const struct snd_kcontrol_new aif2dac2l_mix[] = {
SOC_DAPM_SINGLE("Right Sidetone Switch", WM8994_DAC2_LEFT_MIXER_ROUTING,
5, 1, 0),
@@ -2472,6 +2506,7 @@ static const struct snd_kcontrol_new aif3adc_mux =
static const struct snd_soc_dapm_widget wm8994_dapm_widgets[] = {
SND_SOC_DAPM_INPUT("DMIC1DAT"),
SND_SOC_DAPM_INPUT("DMIC2DAT"),
+SND_SOC_DAPM_INPUT("Clock"),
SND_SOC_DAPM_SUPPLY("CLK_SYS", SND_SOC_NOPM, 0, 0, clk_sys_event,
SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
@@ -2506,6 +2541,11 @@ SND_SOC_DAPM_MIXER("AIF1ADC1L Mixer", SND_SOC_NOPM, 0, 0,
SND_SOC_DAPM_MIXER("AIF1ADC1R Mixer", SND_SOC_NOPM, 0, 0,
aif1adc1r_mix, ARRAY_SIZE(aif1adc1r_mix)),
+SND_SOC_DAPM_MIXER("AIF1ADC2L Mixer", SND_SOC_NOPM, 0, 0,
+ aif1adc2l_mix, ARRAY_SIZE(aif1adc2l_mix)),
+SND_SOC_DAPM_MIXER("AIF1ADC2R Mixer", SND_SOC_NOPM, 0, 0,
+ aif1adc2r_mix, ARRAY_SIZE(aif1adc2r_mix)),
+
SND_SOC_DAPM_MIXER("AIF2DAC2L Mixer", SND_SOC_NOPM, 0, 0,
aif2dac2l_mix, ARRAY_SIZE(aif2dac2l_mix)),
SND_SOC_DAPM_MIXER("AIF2DAC2R Mixer", SND_SOC_NOPM, 0, 0,
@@ -2668,6 +2708,14 @@ static const struct snd_soc_dapm_route intercon[] = {
{ "AIF1ADC1R Mixer", "ADC/DMIC Switch", "ADCR Mux" },
{ "AIF1ADC1R Mixer", "AIF2 Switch", "AIF2DACR" },
+ { "AIF1ADC2L", NULL, "AIF1ADC2L Mixer" },
+ { "AIF1ADC2L Mixer", "DMIC Switch", "DMIC2L" },
+ { "AIF1ADC2L Mixer", "AIF2 Switch", "AIF2DACL" },
+
+ { "AIF1ADC2R", NULL, "AIF1ADC2R Mixer" },
+ { "AIF1ADC2R Mixer", "DMIC Switch", "DMIC2R" },
+ { "AIF1ADC2R Mixer", "AIF2 Switch", "AIF2DACR" },
+
/* Pin level routing for AIF3 */
{ "AIF1DAC1L", NULL, "AIF1DAC Mux" },
{ "AIF1DAC1R", NULL, "AIF1DAC Mux" },
@@ -2946,11 +2994,14 @@ static int wm8994_set_fll(struct snd_soc_dai *dai, int id, int src,
return 0;
}
+static int opclk_divs[] = { 10, 20, 30, 40, 55, 60, 80, 120, 160 };
+
static int wm8994_set_dai_sysclk(struct snd_soc_dai *dai,
int clk_id, unsigned int freq, int dir)
{
struct snd_soc_codec *codec = dai->codec;
struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+ int i;
switch (dai->id) {
case 1:
@@ -2988,6 +3039,25 @@ static int wm8994_set_dai_sysclk(struct snd_soc_dai *dai,
dev_dbg(dai->dev, "AIF%d using FLL2\n", dai->id);
break;
+ case WM8994_SYSCLK_OPCLK:
+ /* Special case - a division (times 10) is given and
+ * no effect on main clocking.
+ */
+ if (freq) {
+ for (i = 0; i < ARRAY_SIZE(opclk_divs); i++)
+ if (opclk_divs[i] == freq)
+ break;
+ if (i == ARRAY_SIZE(opclk_divs))
+ return -EINVAL;
+ snd_soc_update_bits(codec, WM8994_CLOCKING_2,
+ WM8994_OPCLK_DIV_MASK, i);
+ snd_soc_update_bits(codec, WM8994_POWER_MANAGEMENT_2,
+ WM8994_OPCLK_ENA, WM8994_OPCLK_ENA);
+ } else {
+ snd_soc_update_bits(codec, WM8994_POWER_MANAGEMENT_2,
+ WM8994_OPCLK_ENA, 0);
+ }
+
default:
return -EINVAL;
}
@@ -4004,6 +4074,11 @@ static int wm8994_codec_probe(struct platform_device *pdev)
1 << WM8994_AIF2DAC_3D_GAIN_SHIFT,
1 << WM8994_AIF2DAC_3D_GAIN_SHIFT);
+ /* Unconditionally enable AIF1 ADC TDM mode; it only affects
+ * behaviour on idle TDM clock cycles. */
+ snd_soc_update_bits(codec, WM8994_AIF1_CONTROL_1,
+ WM8994_AIF1ADC_TDM, WM8994_AIF1ADC_TDM);
+
wm8994_update_class_w(codec);
ret = snd_soc_register_codec(codec);
diff --git a/sound/soc/codecs/wm8994.h b/sound/soc/codecs/wm8994.h
index 7072dc53935..2e0ca67a8df 100644
--- a/sound/soc/codecs/wm8994.h
+++ b/sound/soc/codecs/wm8994.h
@@ -20,6 +20,9 @@ extern struct snd_soc_dai wm8994_dai[];
#define WM8994_SYSCLK_FLL1 3
#define WM8994_SYSCLK_FLL2 4
+/* OPCLK is also configured with set_dai_sysclk, specify division*10 as rate. */
+#define WM8994_SYSCLK_OPCLK 5
+
#define WM8994_FLL1 1
#define WM8994_FLL2 2
diff --git a/sound/soc/codecs/wm9081.c b/sound/soc/codecs/wm9081.c
index 13186fb4dcb..76b37ff6c26 100644
--- a/sound/soc/codecs/wm9081.c
+++ b/sound/soc/codecs/wm9081.c
@@ -1356,7 +1356,7 @@ static int wm9081_register(struct wm9081_priv *wm9081,
ret = snd_soc_codec_set_cache_io(codec, 8, 16, control);
if (ret != 0) {
dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
- return ret;
+ goto err;
}
reg = snd_soc_read(codec, WM9081_SOFTWARE_RESET);
@@ -1369,7 +1369,7 @@ static int wm9081_register(struct wm9081_priv *wm9081,
ret = wm9081_reset(codec);
if (ret < 0) {
dev_err(codec->dev, "Failed to issue reset\n");
- return ret;
+ goto err;
}
wm9081_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
@@ -1388,18 +1388,19 @@ static int wm9081_register(struct wm9081_priv *wm9081,
ret = snd_soc_register_codec(codec);
if (ret != 0) {
dev_err(codec->dev, "Failed to register codec: %d\n", ret);
- return ret;
+ goto err;
}
ret = snd_soc_register_dai(&wm9081_dai);
if (ret != 0) {
dev_err(codec->dev, "Failed to register DAI: %d\n", ret);
- snd_soc_unregister_codec(codec);
- return ret;
+ goto err_codec;
}
return 0;
+err_codec:
+ snd_soc_unregister_codec(codec);
err:
kfree(wm9081);
return ret;
diff --git a/sound/soc/codecs/wm_hubs.c b/sound/soc/codecs/wm_hubs.c
index 16f1a57da08..2cb81538cd9 100644
--- a/sound/soc/codecs/wm_hubs.c
+++ b/sound/soc/codecs/wm_hubs.c
@@ -410,6 +410,8 @@ static int hp_event(struct snd_soc_dapm_widget *w,
WM8993_HPOUT1L_DLY |
WM8993_HPOUT1R_DLY, 0);
+ snd_soc_write(codec, WM8993_DC_SERVO_0, 0);
+
snd_soc_update_bits(codec, WM8993_POWER_MANAGEMENT_1,
WM8993_HPOUT1L_ENA | WM8993_HPOUT1R_ENA,
0);
diff --git a/sound/soc/davinci/davinci-i2s.c b/sound/soc/davinci/davinci-i2s.c
index adadcd3aa1b..9e8932abf15 100644
--- a/sound/soc/davinci/davinci-i2s.c
+++ b/sound/soc/davinci/davinci-i2s.c
@@ -26,6 +26,7 @@
#include <mach/asp.h>
#include "davinci-pcm.h"
+#include "davinci-i2s.h"
/*
@@ -68,16 +69,21 @@
#define DAVINCI_MCBSP_RCR_RDATDLY(v) ((v) << 16)
#define DAVINCI_MCBSP_RCR_RFIG (1 << 18)
#define DAVINCI_MCBSP_RCR_RWDLEN2(v) ((v) << 21)
+#define DAVINCI_MCBSP_RCR_RFRLEN2(v) ((v) << 24)
+#define DAVINCI_MCBSP_RCR_RPHASE BIT(31)
#define DAVINCI_MCBSP_XCR_XWDLEN1(v) ((v) << 5)
#define DAVINCI_MCBSP_XCR_XFRLEN1(v) ((v) << 8)
#define DAVINCI_MCBSP_XCR_XDATDLY(v) ((v) << 16)
#define DAVINCI_MCBSP_XCR_XFIG (1 << 18)
#define DAVINCI_MCBSP_XCR_XWDLEN2(v) ((v) << 21)
+#define DAVINCI_MCBSP_XCR_XFRLEN2(v) ((v) << 24)
+#define DAVINCI_MCBSP_XCR_XPHASE BIT(31)
#define DAVINCI_MCBSP_SRGR_FWID(v) ((v) << 8)
#define DAVINCI_MCBSP_SRGR_FPER(v) ((v) << 16)
#define DAVINCI_MCBSP_SRGR_FSGM (1 << 28)
+#define DAVINCI_MCBSP_SRGR_CLKSM BIT(29)
#define DAVINCI_MCBSP_PCR_CLKRP (1 << 0)
#define DAVINCI_MCBSP_PCR_CLKXP (1 << 1)
@@ -116,6 +122,7 @@ static const unsigned char double_fmt[SNDRV_PCM_FORMAT_S32_LE + 1] = {
};
struct davinci_mcbsp_dev {
+ struct device *dev;
struct davinci_pcm_dma_params dma_params[2];
void __iomem *base;
#define MOD_DSP_A 0
@@ -144,6 +151,11 @@ struct davinci_mcbsp_dev {
* won't end up being swapped because of the underrun.
*/
unsigned enable_channel_combine:1;
+
+ unsigned int fmt;
+ int clk_div;
+ int clk_input_pin;
+ bool i2s_accurate_sck;
};
static inline void davinci_mcbsp_write_reg(struct davinci_mcbsp_dev *dev,
@@ -254,10 +266,12 @@ static int davinci_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai,
struct davinci_mcbsp_dev *dev = cpu_dai->private_data;
unsigned int pcr;
unsigned int srgr;
+ /* Attention srgr is updated by hw_params! */
srgr = DAVINCI_MCBSP_SRGR_FSGM |
DAVINCI_MCBSP_SRGR_FPER(DEFAULT_BITPERSAMPLE * 2 - 1) |
DAVINCI_MCBSP_SRGR_FWID(DEFAULT_BITPERSAMPLE - 1);
+ dev->fmt = fmt;
/* set master/slave audio interface */
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
case SND_SOC_DAIFMT_CBS_CFS:
@@ -268,11 +282,26 @@ static int davinci_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai,
DAVINCI_MCBSP_PCR_CLKRM;
break;
case SND_SOC_DAIFMT_CBM_CFS:
- /* McBSP CLKR pin is the input for the Sample Rate Generator.
- * McBSP FSR and FSX are driven by the Sample Rate Generator. */
- pcr = DAVINCI_MCBSP_PCR_SCLKME |
- DAVINCI_MCBSP_PCR_FSXM |
- DAVINCI_MCBSP_PCR_FSRM;
+ pcr = DAVINCI_MCBSP_PCR_FSRM | DAVINCI_MCBSP_PCR_FSXM;
+ /*
+ * Selection of the clock input pin that is the
+ * input for the Sample Rate Generator.
+ * McBSP FSR and FSX are driven by the Sample Rate
+ * Generator.
+ */
+ switch (dev->clk_input_pin) {
+ case MCBSP_CLKS:
+ pcr |= DAVINCI_MCBSP_PCR_CLKXM |
+ DAVINCI_MCBSP_PCR_CLKRM;
+ break;
+ case MCBSP_CLKR:
+ pcr |= DAVINCI_MCBSP_PCR_SCLKME;
+ break;
+ default:
+ dev_err(dev->dev, "bad clk_input_pin\n");
+ return -EINVAL;
+ }
+
break;
case SND_SOC_DAIFMT_CBM_CFM:
/* codec is master */
@@ -372,6 +401,18 @@ static int davinci_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai,
return 0;
}
+static int davinci_i2s_dai_set_clkdiv(struct snd_soc_dai *cpu_dai,
+ int div_id, int div)
+{
+ struct davinci_mcbsp_dev *dev = cpu_dai->private_data;
+
+ if (div_id != DAVINCI_MCBSP_CLKGDV)
+ return -ENODEV;
+
+ dev->clk_div = div;
+ return 0;
+}
+
static int davinci_i2s_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
@@ -380,8 +421,8 @@ static int davinci_i2s_hw_params(struct snd_pcm_substream *substream,
struct davinci_pcm_dma_params *dma_params =
&dev->dma_params[substream->stream];
struct snd_interval *i = NULL;
- int mcbsp_word_length;
- unsigned int rcr, xcr, srgr;
+ int mcbsp_word_length, master;
+ unsigned int rcr, xcr, srgr, clk_div, freq, framesize;
u32 spcr;
snd_pcm_format_t fmt;
unsigned element_cnt = 1;
@@ -396,12 +437,59 @@ static int davinci_i2s_hw_params(struct snd_pcm_substream *substream,
davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, spcr);
}
- i = hw_param_interval(params, SNDRV_PCM_HW_PARAM_SAMPLE_BITS);
- srgr = DAVINCI_MCBSP_SRGR_FSGM;
- srgr |= DAVINCI_MCBSP_SRGR_FWID(snd_interval_value(i) - 1);
+ master = dev->fmt & SND_SOC_DAIFMT_MASTER_MASK;
+ fmt = params_format(params);
+ mcbsp_word_length = asp_word_length[fmt];
- i = hw_param_interval(params, SNDRV_PCM_HW_PARAM_FRAME_BITS);
- srgr |= DAVINCI_MCBSP_SRGR_FPER(snd_interval_value(i) - 1);
+ switch (master) {
+ case SND_SOC_DAIFMT_CBS_CFS:
+ freq = clk_get_rate(dev->clk);
+ srgr = DAVINCI_MCBSP_SRGR_FSGM |
+ DAVINCI_MCBSP_SRGR_CLKSM;
+ srgr |= DAVINCI_MCBSP_SRGR_FWID(mcbsp_word_length *
+ 8 - 1);
+ if (dev->i2s_accurate_sck) {
+ clk_div = 256;
+ do {
+ framesize = (freq / (--clk_div)) /
+ params->rate_num *
+ params->rate_den;
+ } while (((framesize < 33) || (framesize > 4095)) &&
+ (clk_div));
+ clk_div--;
+ srgr |= DAVINCI_MCBSP_SRGR_FPER(framesize - 1);
+ } else {
+ /* symmetric waveforms */
+ clk_div = freq / (mcbsp_word_length * 16) /
+ params->rate_num * params->rate_den;
+ srgr |= DAVINCI_MCBSP_SRGR_FPER(mcbsp_word_length *
+ 16 - 1);
+ }
+ clk_div &= 0xFF;
+ srgr |= clk_div;
+ break;
+ case SND_SOC_DAIFMT_CBM_CFS:
+ srgr = DAVINCI_MCBSP_SRGR_FSGM;
+ clk_div = dev->clk_div - 1;
+ srgr |= DAVINCI_MCBSP_SRGR_FWID(mcbsp_word_length * 8 - 1);
+ srgr |= DAVINCI_MCBSP_SRGR_FPER(mcbsp_word_length * 16 - 1);
+ clk_div &= 0xFF;
+ srgr |= clk_div;
+ break;
+ case SND_SOC_DAIFMT_CBM_CFM:
+ /* Clock and frame sync given from external sources */
+ i = hw_param_interval(params, SNDRV_PCM_HW_PARAM_SAMPLE_BITS);
+ srgr = DAVINCI_MCBSP_SRGR_FSGM;
+ srgr |= DAVINCI_MCBSP_SRGR_FWID(snd_interval_value(i) - 1);
+ pr_debug("%s - %d FWID set: re-read srgr = %X\n",
+ __func__, __LINE__, snd_interval_value(i) - 1);
+
+ i = hw_param_interval(params, SNDRV_PCM_HW_PARAM_FRAME_BITS);
+ srgr |= DAVINCI_MCBSP_SRGR_FPER(snd_interval_value(i) - 1);
+ break;
+ default:
+ return -EINVAL;
+ }
davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SRGR_REG, srgr);
rcr = DAVINCI_MCBSP_RCR_RFIG;
@@ -426,12 +514,41 @@ static int davinci_i2s_hw_params(struct snd_pcm_substream *substream,
element_cnt = 1;
fmt = double_fmt[fmt];
}
+ switch (master) {
+ case SND_SOC_DAIFMT_CBS_CFS:
+ case SND_SOC_DAIFMT_CBS_CFM:
+ rcr |= DAVINCI_MCBSP_RCR_RFRLEN2(0);
+ xcr |= DAVINCI_MCBSP_XCR_XFRLEN2(0);
+ rcr |= DAVINCI_MCBSP_RCR_RPHASE;
+ xcr |= DAVINCI_MCBSP_XCR_XPHASE;
+ break;
+ case SND_SOC_DAIFMT_CBM_CFM:
+ case SND_SOC_DAIFMT_CBM_CFS:
+ rcr |= DAVINCI_MCBSP_RCR_RFRLEN2(element_cnt - 1);
+ xcr |= DAVINCI_MCBSP_XCR_XFRLEN2(element_cnt - 1);
+ break;
+ default:
+ return -EINVAL;
+ }
}
dma_params->acnt = dma_params->data_type = data_type[fmt];
dma_params->fifo_level = 0;
mcbsp_word_length = asp_word_length[fmt];
- rcr |= DAVINCI_MCBSP_RCR_RFRLEN1(element_cnt - 1);
- xcr |= DAVINCI_MCBSP_XCR_XFRLEN1(element_cnt - 1);
+
+ switch (master) {
+ case SND_SOC_DAIFMT_CBS_CFS:
+ case SND_SOC_DAIFMT_CBS_CFM:
+ rcr |= DAVINCI_MCBSP_RCR_RFRLEN1(0);
+ xcr |= DAVINCI_MCBSP_XCR_XFRLEN1(0);
+ break;
+ case SND_SOC_DAIFMT_CBM_CFM:
+ case SND_SOC_DAIFMT_CBM_CFS:
+ rcr |= DAVINCI_MCBSP_RCR_RFRLEN1(element_cnt - 1);
+ xcr |= DAVINCI_MCBSP_XCR_XFRLEN1(element_cnt - 1);
+ break;
+ default:
+ return -EINVAL;
+ }
rcr |= DAVINCI_MCBSP_RCR_RWDLEN1(mcbsp_word_length) |
DAVINCI_MCBSP_RCR_RWDLEN2(mcbsp_word_length);
@@ -442,6 +559,10 @@ static int davinci_i2s_hw_params(struct snd_pcm_substream *substream,
davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_XCR_REG, xcr);
else
davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_RCR_REG, rcr);
+
+ pr_debug("%s - %d srgr=%X\n", __func__, __LINE__, srgr);
+ pr_debug("%s - %d xcr=%X\n", __func__, __LINE__, xcr);
+ pr_debug("%s - %d rcr=%X\n", __func__, __LINE__, rcr);
return 0;
}
@@ -500,6 +621,7 @@ static struct snd_soc_dai_ops davinci_i2s_dai_ops = {
.trigger = davinci_i2s_trigger,
.hw_params = davinci_i2s_hw_params,
.set_fmt = davinci_i2s_set_dai_fmt,
+ .set_clkdiv = davinci_i2s_dai_set_clkdiv,
};
@@ -526,6 +648,8 @@ static int davinci_i2s_probe(struct platform_device *pdev)
struct snd_platform_data *pdata = pdev->dev.platform_data;
struct davinci_mcbsp_dev *dev;
struct resource *mem, *ioarea, *res;
+ enum dma_event_q asp_chan_q = EVENTQ_0;
+ enum dma_event_q ram_chan_q = EVENTQ_1;
int ret;
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -552,7 +676,17 @@ static int davinci_i2s_probe(struct platform_device *pdev)
pdata->sram_size_playback;
dev->dma_params[SNDRV_PCM_STREAM_CAPTURE].sram_size =
pdata->sram_size_capture;
+ dev->clk_input_pin = pdata->clk_input_pin;
+ dev->i2s_accurate_sck = pdata->i2s_accurate_sck;
+ asp_chan_q = pdata->asp_chan_q;
+ ram_chan_q = pdata->ram_chan_q;
}
+
+ dev->dma_params[SNDRV_PCM_STREAM_PLAYBACK].asp_chan_q = asp_chan_q;
+ dev->dma_params[SNDRV_PCM_STREAM_PLAYBACK].ram_chan_q = ram_chan_q;
+ dev->dma_params[SNDRV_PCM_STREAM_CAPTURE].asp_chan_q = asp_chan_q;
+ dev->dma_params[SNDRV_PCM_STREAM_CAPTURE].ram_chan_q = ram_chan_q;
+
dev->clk = clk_get(&pdev->dev, NULL);
if (IS_ERR(dev->clk)) {
ret = -ENODEV;
@@ -584,6 +718,7 @@ static int davinci_i2s_probe(struct platform_device *pdev)
goto err_free_mem;
}
dev->dma_params[SNDRV_PCM_STREAM_CAPTURE].channel = res->start;
+ dev->dev = &pdev->dev;
davinci_i2s_dai.private_data = dev;
davinci_i2s_dai.capture.dma_data = dev->dma_params;
diff --git a/sound/soc/davinci/davinci-i2s.h b/sound/soc/davinci/davinci-i2s.h
index 241648ce887..0b1e77b8c27 100644
--- a/sound/soc/davinci/davinci-i2s.h
+++ b/sound/soc/davinci/davinci-i2s.h
@@ -12,6 +12,11 @@
#ifndef _DAVINCI_I2S_H
#define _DAVINCI_I2S_H
+/* McBSP dividers */
+enum davinci_mcbsp_div {
+ DAVINCI_MCBSP_CLKGDV, /* Sample rate generator divider */
+};
+
extern struct snd_soc_dai davinci_i2s_dai;
#endif
diff --git a/sound/soc/davinci/davinci-mcasp.c b/sound/soc/davinci/davinci-mcasp.c
index d3955096d87..b24720894af 100644
--- a/sound/soc/davinci/davinci-mcasp.c
+++ b/sound/soc/davinci/davinci-mcasp.c
@@ -890,7 +890,8 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
dev->rxnumevt = pdata->rxnumevt;
dma_data = &dev->dma_params[SNDRV_PCM_STREAM_PLAYBACK];
- dma_data->eventq_no = pdata->eventq_no;
+ dma_data->asp_chan_q = pdata->asp_chan_q;
+ dma_data->ram_chan_q = pdata->ram_chan_q;
dma_data->dma_addr = (dma_addr_t) (pdata->tx_dma_offset +
io_v2p(dev->base));
@@ -904,7 +905,8 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
dma_data->channel = res->start;
dma_data = &dev->dma_params[SNDRV_PCM_STREAM_CAPTURE];
- dma_data->eventq_no = pdata->eventq_no;
+ dma_data->asp_chan_q = pdata->asp_chan_q;
+ dma_data->ram_chan_q = pdata->ram_chan_q;
dma_data->dma_addr = (dma_addr_t)(pdata->rx_dma_offset +
io_v2p(dev->base));
diff --git a/sound/soc/davinci/davinci-pcm.c b/sound/soc/davinci/davinci-pcm.c
index 2dc406f42fe..a7124116d2e 100644
--- a/sound/soc/davinci/davinci-pcm.c
+++ b/sound/soc/davinci/davinci-pcm.c
@@ -381,7 +381,7 @@ static int request_ping_pong(struct snd_pcm_substream *substream,
/* Request ram master channel */
link = prtd->ram_channel = edma_alloc_channel(EDMA_CHANNEL_ANY,
davinci_pcm_dma_irq, substream,
- EVENTQ_1);
+ prtd->params->ram_chan_q);
if (link < 0)
goto exit1;
@@ -477,7 +477,8 @@ static int davinci_pcm_dma_request(struct snd_pcm_substream *substream)
/* Request asp master DMA channel */
link = prtd->asp_channel = edma_alloc_channel(params->channel,
- davinci_pcm_dma_irq, substream, EVENTQ_0);
+ davinci_pcm_dma_irq, substream,
+ prtd->params->asp_chan_q);
if (link < 0)
goto exit1;
@@ -800,7 +801,7 @@ static void davinci_pcm_free(struct snd_pcm *pcm)
dma_free_writecombine(pcm->card->dev, buf->bytes,
buf->area, buf->addr);
buf->area = NULL;
- iram_dma = (struct snd_dma_buffer *)buf->private_data;
+ iram_dma = buf->private_data;
if (iram_dma) {
sram_free(iram_dma->area, iram_dma->bytes);
kfree(iram_dma);
diff --git a/sound/soc/davinci/davinci-pcm.h b/sound/soc/davinci/davinci-pcm.h
index 0764944cf10..b799a02333d 100644
--- a/sound/soc/davinci/davinci-pcm.h
+++ b/sound/soc/davinci/davinci-pcm.h
@@ -21,7 +21,8 @@ struct davinci_pcm_dma_params {
unsigned short acnt;
dma_addr_t dma_addr; /* device physical address for DMA */
unsigned sram_size;
- enum dma_event_q eventq_no; /* event queue number */
+ enum dma_event_q asp_chan_q; /* event queue number for ASP channel */
+ enum dma_event_q ram_chan_q; /* event queue number for RAM channel */
unsigned char data_type; /* xfer data type */
unsigned char convert_mono_stereo;
unsigned int fifo_level;
diff --git a/sound/soc/davinci/davinci-vcif.c b/sound/soc/davinci/davinci-vcif.c
index 9aa980d3823..48678533da7 100644
--- a/sound/soc/davinci/davinci-vcif.c
+++ b/sound/soc/davinci/davinci-vcif.c
@@ -203,7 +203,7 @@ static int davinci_vcif_probe(struct platform_device *pdev)
int ret;
davinci_vcif_dev = kzalloc(sizeof(struct davinci_vcif_dev), GFP_KERNEL);
- if (!davinci_vc) {
+ if (!davinci_vcif_dev) {
dev_dbg(&pdev->dev,
"could not allocate memory for private data\n");
return -ENOMEM;
diff --git a/sound/soc/ep93xx/Kconfig b/sound/soc/ep93xx/Kconfig
new file mode 100644
index 00000000000..f617f560f46
--- /dev/null
+++ b/sound/soc/ep93xx/Kconfig
@@ -0,0 +1,18 @@
+config SND_EP93XX_SOC
+ tristate "SoC Audio support for the Cirrus Logic EP93xx series"
+ depends on ARCH_EP93XX && SND_SOC
+ help
+ Say Y or M if you want to add support for codecs attached to
+ the EP93xx I2S interface.
+
+config SND_EP93XX_SOC_I2S
+ tristate
+
+config SND_EP93XX_SOC_SNAPPERCL15
+ tristate "SoC Audio support for Bluewater Systems Snapper CL15 module"
+ depends on SND_EP93XX_SOC && MACH_SNAPPER_CL15
+ select SND_EP93XX_SOC_I2S
+ select SND_SOC_TLV320AIC23
+ help
+ Say Y or M here if you want to add support for I2S audio on the
+ Bluewater Systems Snapper CL15 module.
diff --git a/sound/soc/ep93xx/Makefile b/sound/soc/ep93xx/Makefile
new file mode 100644
index 00000000000..272e60f57b9
--- /dev/null
+++ b/sound/soc/ep93xx/Makefile
@@ -0,0 +1,11 @@
+# EP93xx Platform Support
+snd-soc-ep93xx-objs := ep93xx-pcm.o
+snd-soc-ep93xx-i2s-objs := ep93xx-i2s.o
+
+obj-$(CONFIG_SND_EP93XX_SOC) += snd-soc-ep93xx.o
+obj-$(CONFIG_SND_EP93XX_SOC_I2S) += snd-soc-ep93xx-i2s.o
+
+# EP93XX Machine Support
+snd-soc-snappercl15-objs := snappercl15.o
+
+obj-$(CONFIG_SND_EP93XX_SOC_SNAPPERCL15) += snd-soc-snappercl15.o
diff --git a/sound/soc/ep93xx/ep93xx-i2s.c b/sound/soc/ep93xx/ep93xx-i2s.c
new file mode 100644
index 00000000000..00b94663218
--- /dev/null
+++ b/sound/soc/ep93xx/ep93xx-i2s.c
@@ -0,0 +1,487 @@
+/*
+ * linux/sound/soc/ep93xx-i2s.c
+ * EP93xx I2S driver
+ *
+ * Copyright (C) 2010 Ryan Mallon <ryan@bluewatersys.com>
+ *
+ * Based on the original driver by:
+ * Copyright (C) 2007 Chase Douglas <chasedouglas@gmail>
+ * Copyright (C) 2006 Lennert Buytenhek <buytenh@wantstofly.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/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/initval.h>
+#include <sound/soc.h>
+
+#include <mach/hardware.h>
+#include <mach/ep93xx-regs.h>
+#include <mach/dma.h>
+
+#include "ep93xx-pcm.h"
+#include "ep93xx-i2s.h"
+
+#define EP93XX_I2S_TXCLKCFG 0x00
+#define EP93XX_I2S_RXCLKCFG 0x04
+#define EP93XX_I2S_GLCTRL 0x0C
+
+#define EP93XX_I2S_TXLINCTRLDATA 0x28
+#define EP93XX_I2S_TXCTRL 0x2C
+#define EP93XX_I2S_TXWRDLEN 0x30
+#define EP93XX_I2S_TX0EN 0x34
+
+#define EP93XX_I2S_RXLINCTRLDATA 0x58
+#define EP93XX_I2S_RXCTRL 0x5C
+#define EP93XX_I2S_RXWRDLEN 0x60
+#define EP93XX_I2S_RX0EN 0x64
+
+#define EP93XX_I2S_WRDLEN_16 (0 << 0)
+#define EP93XX_I2S_WRDLEN_24 (1 << 0)
+#define EP93XX_I2S_WRDLEN_32 (2 << 0)
+
+#define EP93XX_I2S_LINCTRLDATA_R_JUST (1 << 2) /* Right justify */
+
+#define EP93XX_I2S_CLKCFG_LRS (1 << 0) /* lrclk polarity */
+#define EP93XX_I2S_CLKCFG_CKP (1 << 1) /* Bit clock polarity */
+#define EP93XX_I2S_CLKCFG_REL (1 << 2) /* First bit transition */
+#define EP93XX_I2S_CLKCFG_MASTER (1 << 3) /* Master mode */
+#define EP93XX_I2S_CLKCFG_NBCG (1 << 4) /* Not bit clock gating */
+
+struct ep93xx_i2s_info {
+ struct clk *mclk;
+ struct clk *sclk;
+ struct clk *lrclk;
+ struct ep93xx_pcm_dma_params *dma_params;
+ struct resource *mem;
+ void __iomem *regs;
+};
+
+struct ep93xx_pcm_dma_params ep93xx_i2s_dma_params[] = {
+ [SNDRV_PCM_STREAM_PLAYBACK] = {
+ .name = "i2s-pcm-out",
+ .dma_port = EP93XX_DMA_M2P_PORT_I2S1,
+ },
+ [SNDRV_PCM_STREAM_CAPTURE] = {
+ .name = "i2s-pcm-in",
+ .dma_port = EP93XX_DMA_M2P_PORT_I2S1,
+ },
+};
+
+static inline void ep93xx_i2s_write_reg(struct ep93xx_i2s_info *info,
+ unsigned reg, unsigned val)
+{
+ __raw_writel(val, info->regs + reg);
+}
+
+static inline unsigned ep93xx_i2s_read_reg(struct ep93xx_i2s_info *info,
+ unsigned reg)
+{
+ return __raw_readl(info->regs + reg);
+}
+
+static void ep93xx_i2s_enable(struct ep93xx_i2s_info *info, int stream)
+{
+ unsigned base_reg;
+ int i;
+
+ if ((ep93xx_i2s_read_reg(info, EP93XX_I2S_TX0EN) & 0x1) == 0 &&
+ (ep93xx_i2s_read_reg(info, EP93XX_I2S_RX0EN) & 0x1) == 0) {
+ /* Enable clocks */
+ clk_enable(info->mclk);
+ clk_enable(info->sclk);
+ clk_enable(info->lrclk);
+
+ /* Enable i2s */
+ ep93xx_i2s_write_reg(info, EP93XX_I2S_GLCTRL, 1);
+ }
+
+ /* Enable fifos */
+ if (stream == SNDRV_PCM_STREAM_PLAYBACK)
+ base_reg = EP93XX_I2S_TX0EN;
+ else
+ base_reg = EP93XX_I2S_RX0EN;
+ for (i = 0; i < 3; i++)
+ ep93xx_i2s_write_reg(info, base_reg + (i * 4), 1);
+}
+
+static void ep93xx_i2s_disable(struct ep93xx_i2s_info *info, int stream)
+{
+ unsigned base_reg;
+ int i;
+
+ /* Disable fifos */
+ if (stream == SNDRV_PCM_STREAM_PLAYBACK)
+ base_reg = EP93XX_I2S_TX0EN;
+ else
+ base_reg = EP93XX_I2S_RX0EN;
+ for (i = 0; i < 3; i++)
+ ep93xx_i2s_write_reg(info, base_reg + (i * 4), 0);
+
+ if ((ep93xx_i2s_read_reg(info, EP93XX_I2S_TX0EN) & 0x1) == 0 &&
+ (ep93xx_i2s_read_reg(info, EP93XX_I2S_RX0EN) & 0x1) == 0) {
+ /* Disable i2s */
+ ep93xx_i2s_write_reg(info, EP93XX_I2S_GLCTRL, 0);
+
+ /* Disable clocks */
+ clk_disable(info->lrclk);
+ clk_disable(info->sclk);
+ clk_disable(info->mclk);
+ }
+}
+
+static int ep93xx_i2s_startup(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+ struct ep93xx_i2s_info *info = rtd->dai->cpu_dai->private_data;
+
+ snd_soc_dai_set_dma_data(cpu_dai, substream,
+ &info->dma_params[substream->stream]);
+ return 0;
+}
+
+static void ep93xx_i2s_shutdown(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct ep93xx_i2s_info *info = rtd->dai->cpu_dai->private_data;
+
+ ep93xx_i2s_disable(info, substream->stream);
+}
+
+static int ep93xx_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai,
+ unsigned int fmt)
+{
+ struct ep93xx_i2s_info *info = cpu_dai->private_data;
+ unsigned int clk_cfg, lin_ctrl;
+
+ clk_cfg = ep93xx_i2s_read_reg(info, EP93XX_I2S_RXCLKCFG);
+ lin_ctrl = ep93xx_i2s_read_reg(info, EP93XX_I2S_RXLINCTRLDATA);
+
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ clk_cfg |= EP93XX_I2S_CLKCFG_REL;
+ lin_ctrl &= ~EP93XX_I2S_LINCTRLDATA_R_JUST;
+ break;
+
+ case SND_SOC_DAIFMT_LEFT_J:
+ clk_cfg &= ~EP93XX_I2S_CLKCFG_REL;
+ lin_ctrl &= ~EP93XX_I2S_LINCTRLDATA_R_JUST;
+ break;
+
+ case SND_SOC_DAIFMT_RIGHT_J:
+ clk_cfg &= ~EP93XX_I2S_CLKCFG_REL;
+ lin_ctrl |= EP93XX_I2S_LINCTRLDATA_R_JUST;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBS_CFS:
+ /* CPU is master */
+ clk_cfg |= EP93XX_I2S_CLKCFG_MASTER;
+ break;
+
+ case SND_SOC_DAIFMT_CBM_CFM:
+ /* Codec is master */
+ clk_cfg &= ~EP93XX_I2S_CLKCFG_MASTER;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+ case SND_SOC_DAIFMT_NB_NF:
+ /* Negative bit clock, lrclk low on left word */
+ clk_cfg &= ~(EP93XX_I2S_CLKCFG_CKP | EP93XX_I2S_CLKCFG_REL);
+ break;
+
+ case SND_SOC_DAIFMT_NB_IF:
+ /* Negative bit clock, lrclk low on right word */
+ clk_cfg &= ~EP93XX_I2S_CLKCFG_CKP;
+ clk_cfg |= EP93XX_I2S_CLKCFG_REL;
+ break;
+
+ case SND_SOC_DAIFMT_IB_NF:
+ /* Positive bit clock, lrclk low on left word */
+ clk_cfg |= EP93XX_I2S_CLKCFG_CKP;
+ clk_cfg &= ~EP93XX_I2S_CLKCFG_REL;
+ break;
+
+ case SND_SOC_DAIFMT_IB_IF:
+ /* Positive bit clock, lrclk low on right word */
+ clk_cfg |= EP93XX_I2S_CLKCFG_CKP | EP93XX_I2S_CLKCFG_REL;
+ break;
+ }
+
+ /* Write new register values */
+ ep93xx_i2s_write_reg(info, EP93XX_I2S_RXCLKCFG, clk_cfg);
+ ep93xx_i2s_write_reg(info, EP93XX_I2S_TXCLKCFG, clk_cfg);
+ ep93xx_i2s_write_reg(info, EP93XX_I2S_RXLINCTRLDATA, lin_ctrl);
+ ep93xx_i2s_write_reg(info, EP93XX_I2S_TXLINCTRLDATA, lin_ctrl);
+ return 0;
+}
+
+static int ep93xx_i2s_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+ struct ep93xx_i2s_info *info = cpu_dai->private_data;
+ unsigned word_len, div, sdiv, lrdiv;
+ int found = 0, err;
+
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_S16_LE:
+ word_len = EP93XX_I2S_WRDLEN_16;
+ break;
+
+ case SNDRV_PCM_FORMAT_S24_LE:
+ word_len = EP93XX_I2S_WRDLEN_24;
+ break;
+
+ case SNDRV_PCM_FORMAT_S32_LE:
+ word_len = EP93XX_I2S_WRDLEN_32;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ ep93xx_i2s_write_reg(info, EP93XX_I2S_TXWRDLEN, word_len);
+ else
+ ep93xx_i2s_write_reg(info, EP93XX_I2S_RXWRDLEN, word_len);
+
+ /*
+ * Calculate the sdiv (bit clock) and lrdiv (left/right clock) values.
+ * If the lrclk is pulse length is larger than the word size, then the
+ * bit clock will be gated for the unused bits.
+ */
+ div = (clk_get_rate(info->mclk) / params_rate(params)) *
+ params_channels(params);
+ for (sdiv = 2; sdiv <= 4; sdiv += 2)
+ for (lrdiv = 32; lrdiv <= 128; lrdiv <<= 1)
+ if (sdiv * lrdiv == div) {
+ found = 1;
+ goto out;
+ }
+out:
+ if (!found)
+ return -EINVAL;
+
+ err = clk_set_rate(info->sclk, clk_get_rate(info->mclk) / sdiv);
+ if (err)
+ return err;
+
+ err = clk_set_rate(info->lrclk, clk_get_rate(info->sclk) / lrdiv);
+ if (err)
+ return err;
+
+ ep93xx_i2s_enable(info, substream->stream);
+ return 0;
+}
+
+static int ep93xx_i2s_set_sysclk(struct snd_soc_dai *cpu_dai, int clk_id,
+ unsigned int freq, int dir)
+{
+ struct ep93xx_i2s_info *info = cpu_dai->private_data;
+
+ if (dir == SND_SOC_CLOCK_IN || clk_id != 0)
+ return -EINVAL;
+
+ return clk_set_rate(info->mclk, freq);
+}
+
+#ifdef CONFIG_PM
+static int ep93xx_i2s_suspend(struct snd_soc_dai *dai)
+{
+ struct ep93xx_i2s_info *info = dai->private_data;
+
+ if (!dai->active)
+ return;
+
+ ep93xx_i2s_disable(info, SNDRV_PCM_STREAM_PLAYBACK);
+ ep93xx_i2s_disable(info, SNDRV_PCM_STREAM_CAPTURE);
+}
+
+static int ep93xx_i2s_resume(struct snd_soc_dai *dai)
+{
+ struct ep93xx_i2s_info *info = dai->private_data;
+
+ if (!dai->active)
+ return;
+
+ ep93xx_i2s_enable(info, SNDRV_PCM_STREAM_PLAYBACK);
+ ep93xx_i2s_enable(info, SNDRV_PCM_STREAM_CAPTURE);
+}
+#else
+#define ep93xx_i2s_suspend NULL
+#define ep93xx_i2s_resume NULL
+#endif
+
+static struct snd_soc_dai_ops ep93xx_i2s_dai_ops = {
+ .startup = ep93xx_i2s_startup,
+ .shutdown = ep93xx_i2s_shutdown,
+ .hw_params = ep93xx_i2s_hw_params,
+ .set_sysclk = ep93xx_i2s_set_sysclk,
+ .set_fmt = ep93xx_i2s_set_dai_fmt,
+};
+
+#define EP93XX_I2S_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
+ SNDRV_PCM_FMTBIT_S24_LE | \
+ SNDRV_PCM_FMTBIT_S32_LE)
+
+struct snd_soc_dai ep93xx_i2s_dai = {
+ .name = "ep93xx-i2s",
+ .id = 0,
+ .symmetric_rates= 1,
+ .suspend = ep93xx_i2s_suspend,
+ .resume = ep93xx_i2s_resume,
+ .playback = {
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = EP93XX_I2S_FORMATS,
+ },
+ .capture = {
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = EP93XX_I2S_FORMATS,
+ },
+ .ops = &ep93xx_i2s_dai_ops,
+};
+EXPORT_SYMBOL_GPL(ep93xx_i2s_dai);
+
+static int ep93xx_i2s_probe(struct platform_device *pdev)
+{
+ struct ep93xx_i2s_info *info;
+ struct resource *res;
+ int err;
+
+ info = kzalloc(sizeof(struct ep93xx_i2s_info), GFP_KERNEL);
+ if (!info) {
+ err = -ENOMEM;
+ goto fail;
+ }
+
+ ep93xx_i2s_dai.dev = &pdev->dev;
+ ep93xx_i2s_dai.private_data = info;
+ info->dma_params = ep93xx_i2s_dma_params;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ err = -ENODEV;
+ goto fail;
+ }
+
+ info->mem = request_mem_region(res->start, resource_size(res),
+ pdev->name);
+ if (!info->mem) {
+ err = -EBUSY;
+ goto fail;
+ }
+
+ info->regs = ioremap(info->mem->start, resource_size(info->mem));
+ if (!info->regs) {
+ err = -ENXIO;
+ goto fail_release_mem;
+ }
+
+ info->mclk = clk_get(&pdev->dev, "mclk");
+ if (IS_ERR(info->mclk)) {
+ err = PTR_ERR(info->mclk);
+ goto fail_unmap_mem;
+ }
+
+ info->sclk = clk_get(&pdev->dev, "sclk");
+ if (IS_ERR(info->sclk)) {
+ err = PTR_ERR(info->sclk);
+ goto fail_put_mclk;
+ }
+
+ info->lrclk = clk_get(&pdev->dev, "lrclk");
+ if (IS_ERR(info->lrclk)) {
+ err = PTR_ERR(info->lrclk);
+ goto fail_put_sclk;
+ }
+
+ err = snd_soc_register_dai(&ep93xx_i2s_dai);
+ if (err)
+ goto fail_put_lrclk;
+
+ return 0;
+
+fail_put_lrclk:
+ clk_put(info->lrclk);
+fail_put_sclk:
+ clk_put(info->sclk);
+fail_put_mclk:
+ clk_put(info->mclk);
+fail_unmap_mem:
+ iounmap(info->regs);
+fail_release_mem:
+ release_mem_region(info->mem->start, resource_size(info->mem));
+ kfree(info);
+fail:
+ return err;
+}
+
+static int __devexit ep93xx_i2s_remove(struct platform_device *pdev)
+{
+ struct ep93xx_i2s_info *info = ep93xx_i2s_dai.private_data;
+
+ snd_soc_unregister_dai(&ep93xx_i2s_dai);
+ clk_put(info->lrclk);
+ clk_put(info->sclk);
+ clk_put(info->mclk);
+ iounmap(info->regs);
+ release_mem_region(info->mem->start, resource_size(info->mem));
+ kfree(info);
+ return 0;
+}
+
+static struct platform_driver ep93xx_i2s_driver = {
+ .probe = ep93xx_i2s_probe,
+ .remove = __devexit_p(ep93xx_i2s_remove),
+ .driver = {
+ .name = "ep93xx-i2s",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init ep93xx_i2s_init(void)
+{
+ return platform_driver_register(&ep93xx_i2s_driver);
+}
+
+static void __exit ep93xx_i2s_exit(void)
+{
+ platform_driver_unregister(&ep93xx_i2s_driver);
+}
+
+module_init(ep93xx_i2s_init);
+module_exit(ep93xx_i2s_exit);
+
+MODULE_ALIAS("platform:ep93xx-i2s");
+MODULE_AUTHOR("Ryan Mallon <ryan@bluewatersys.com>");
+MODULE_DESCRIPTION("EP93XX I2S driver");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/ep93xx/ep93xx-i2s.h b/sound/soc/ep93xx/ep93xx-i2s.h
new file mode 100644
index 00000000000..3bd4ebfaa1d
--- /dev/null
+++ b/sound/soc/ep93xx/ep93xx-i2s.h
@@ -0,0 +1,18 @@
+/*
+ * linux/sound/soc/ep93xx-i2s.h
+ * EP93xx I2S driver
+ *
+ * Copyright (C) 2010 Ryan Mallon <ryan@bluewatersys.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 _EP93XX_SND_SOC_I2S_H
+#define _EP93XX_SND_SOC_I2S_H
+
+extern struct snd_soc_dai ep93xx_i2s_dai;
+
+#endif /* _EP93XX_SND_SOC_I2S_H */
diff --git a/sound/soc/ep93xx/ep93xx-pcm.c b/sound/soc/ep93xx/ep93xx-pcm.c
new file mode 100644
index 00000000000..4ba93840079
--- /dev/null
+++ b/sound/soc/ep93xx/ep93xx-pcm.c
@@ -0,0 +1,319 @@
+/*
+ * linux/sound/arm/ep93xx-pcm.c - EP93xx ALSA PCM interface
+ *
+ * Copyright (C) 2006 Lennert Buytenhek <buytenh@wantstofly.org>
+ * Copyright (C) 2006 Applied Data Systems
+ *
+ * Rewritten for the SoC audio subsystem (Based on PXA2xx code):
+ * Copyright (c) 2008 Ryan Mallon <ryan@bluewatersys.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/module.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/slab.h>
+#include <linux/dma-mapping.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+#include <mach/dma.h>
+#include <mach/hardware.h>
+#include <mach/ep93xx-regs.h>
+
+#include "ep93xx-pcm.h"
+
+static const struct snd_pcm_hardware ep93xx_pcm_hardware = {
+ .info = (SNDRV_PCM_INFO_MMAP |
+ SNDRV_PCM_INFO_MMAP_VALID |
+ SNDRV_PCM_INFO_INTERLEAVED |
+ SNDRV_PCM_INFO_BLOCK_TRANSFER),
+
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .rate_min = SNDRV_PCM_RATE_8000,
+ .rate_max = SNDRV_PCM_RATE_48000,
+
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE),
+
+ .buffer_bytes_max = 131072,
+ .period_bytes_min = 32,
+ .period_bytes_max = 32768,
+ .periods_min = 1,
+ .periods_max = 32,
+ .fifo_size = 32,
+};
+
+struct ep93xx_runtime_data
+{
+ struct ep93xx_dma_m2p_client cl;
+ struct ep93xx_pcm_dma_params *params;
+ int pointer_bytes;
+ struct tasklet_struct period_tasklet;
+ int periods;
+ struct ep93xx_dma_buffer buf[32];
+};
+
+static void ep93xx_pcm_period_elapsed(unsigned long data)
+{
+ struct snd_pcm_substream *substream = (struct snd_pcm_substream *)data;
+ snd_pcm_period_elapsed(substream);
+}
+
+static void ep93xx_pcm_buffer_started(void *cookie,
+ struct ep93xx_dma_buffer *buf)
+{
+}
+
+static void ep93xx_pcm_buffer_finished(void *cookie,
+ struct ep93xx_dma_buffer *buf,
+ int bytes, int error)
+{
+ struct snd_pcm_substream *substream = cookie;
+ struct ep93xx_runtime_data *rtd = substream->runtime->private_data;
+
+ if (buf == rtd->buf + rtd->periods - 1)
+ rtd->pointer_bytes = 0;
+ else
+ rtd->pointer_bytes += buf->size;
+
+ if (!error) {
+ ep93xx_dma_m2p_submit_recursive(&rtd->cl, buf);
+ tasklet_schedule(&rtd->period_tasklet);
+ } else {
+ snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN);
+ }
+}
+
+static int ep93xx_pcm_open(struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *soc_rtd = substream->private_data;
+ struct snd_soc_dai *cpu_dai = soc_rtd->dai->cpu_dai;
+ struct ep93xx_pcm_dma_params *dma_params;
+ struct ep93xx_runtime_data *rtd;
+ int ret;
+
+ dma_params = snd_soc_dai_get_dma_data(cpu_dai, substream);
+ snd_soc_set_runtime_hwparams(substream, &ep93xx_pcm_hardware);
+
+ rtd = kmalloc(sizeof(*rtd), GFP_KERNEL);
+ if (!rtd)
+ return -ENOMEM;
+
+ memset(&rtd->period_tasklet, 0, sizeof(rtd->period_tasklet));
+ rtd->period_tasklet.func = ep93xx_pcm_period_elapsed;
+ rtd->period_tasklet.data = (unsigned long)substream;
+
+ rtd->cl.name = dma_params->name;
+ rtd->cl.flags = dma_params->dma_port | EP93XX_DMA_M2P_IGNORE_ERROR |
+ ((substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ?
+ EP93XX_DMA_M2P_TX : EP93XX_DMA_M2P_RX);
+ rtd->cl.cookie = substream;
+ rtd->cl.buffer_started = ep93xx_pcm_buffer_started;
+ rtd->cl.buffer_finished = ep93xx_pcm_buffer_finished;
+ ret = ep93xx_dma_m2p_client_register(&rtd->cl);
+ if (ret < 0) {
+ kfree(rtd);
+ return ret;
+ }
+
+ substream->runtime->private_data = rtd;
+ return 0;
+}
+
+static int ep93xx_pcm_close(struct snd_pcm_substream *substream)
+{
+ struct ep93xx_runtime_data *rtd = substream->runtime->private_data;
+
+ ep93xx_dma_m2p_client_unregister(&rtd->cl);
+ kfree(rtd);
+ return 0;
+}
+
+static int ep93xx_pcm_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct ep93xx_runtime_data *rtd = runtime->private_data;
+ size_t totsize = params_buffer_bytes(params);
+ size_t period = params_period_bytes(params);
+ int i;
+
+ snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
+ runtime->dma_bytes = totsize;
+
+ rtd->periods = (totsize + period - 1) / period;
+ for (i = 0; i < rtd->periods; i++) {
+ rtd->buf[i].bus_addr = runtime->dma_addr + (i * period);
+ rtd->buf[i].size = period;
+ if ((i + 1) * period > totsize)
+ rtd->buf[i].size = totsize - (i * period);
+ }
+
+ return 0;
+}
+
+static int ep93xx_pcm_hw_free(struct snd_pcm_substream *substream)
+{
+ snd_pcm_set_runtime_buffer(substream, NULL);
+ return 0;
+}
+
+static int ep93xx_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+ struct ep93xx_runtime_data *rtd = substream->runtime->private_data;
+ int ret;
+ int i;
+
+ ret = 0;
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_RESUME:
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ rtd->pointer_bytes = 0;
+ for (i = 0; i < rtd->periods; i++)
+ ep93xx_dma_m2p_submit(&rtd->cl, rtd->buf + i);
+ break;
+
+ case SNDRV_PCM_TRIGGER_STOP:
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ ep93xx_dma_m2p_flush(&rtd->cl);
+ break;
+
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+static snd_pcm_uframes_t ep93xx_pcm_pointer(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct ep93xx_runtime_data *rtd = substream->runtime->private_data;
+
+ /* FIXME: implement this with sub-period granularity */
+ return bytes_to_frames(runtime, rtd->pointer_bytes);
+}
+
+static int ep93xx_pcm_mmap(struct snd_pcm_substream *substream,
+ struct vm_area_struct *vma)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+
+ return dma_mmap_writecombine(substream->pcm->card->dev, vma,
+ runtime->dma_area,
+ runtime->dma_addr,
+ runtime->dma_bytes);
+}
+
+static struct snd_pcm_ops ep93xx_pcm_ops = {
+ .open = ep93xx_pcm_open,
+ .close = ep93xx_pcm_close,
+ .ioctl = snd_pcm_lib_ioctl,
+ .hw_params = ep93xx_pcm_hw_params,
+ .hw_free = ep93xx_pcm_hw_free,
+ .trigger = ep93xx_pcm_trigger,
+ .pointer = ep93xx_pcm_pointer,
+ .mmap = ep93xx_pcm_mmap,
+};
+
+static int ep93xx_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream)
+{
+ struct snd_pcm_substream *substream = pcm->streams[stream].substream;
+ struct snd_dma_buffer *buf = &substream->dma_buffer;
+ size_t size = ep93xx_pcm_hardware.buffer_bytes_max;
+
+ buf->dev.type = SNDRV_DMA_TYPE_DEV;
+ buf->dev.dev = pcm->card->dev;
+ buf->private_data = NULL;
+ buf->area = dma_alloc_writecombine(pcm->card->dev, size,
+ &buf->addr, GFP_KERNEL);
+ buf->bytes = size;
+
+ return (buf->area == NULL) ? -ENOMEM : 0;
+}
+
+static void ep93xx_pcm_free_dma_buffers(struct snd_pcm *pcm)
+{
+ struct snd_pcm_substream *substream;
+ struct snd_dma_buffer *buf;
+ int stream;
+
+ for (stream = 0; stream < 2; stream++) {
+ substream = pcm->streams[stream].substream;
+ if (!substream)
+ continue;
+
+ buf = &substream->dma_buffer;
+ if (!buf->area)
+ continue;
+
+ dma_free_writecombine(pcm->card->dev, buf->bytes, buf->area,
+ buf->addr);
+ buf->area = NULL;
+ }
+}
+
+static u64 ep93xx_pcm_dmamask = 0xffffffff;
+
+static int ep93xx_pcm_new(struct snd_card *card, struct snd_soc_dai *dai,
+ struct snd_pcm *pcm)
+{
+ int ret = 0;
+
+ if (!card->dev->dma_mask)
+ card->dev->dma_mask = &ep93xx_pcm_dmamask;
+ if (!card->dev->coherent_dma_mask)
+ card->dev->coherent_dma_mask = 0xffffffff;
+
+ if (dai->playback.channels_min) {
+ ret = ep93xx_pcm_preallocate_dma_buffer(pcm,
+ SNDRV_PCM_STREAM_PLAYBACK);
+ if (ret)
+ return ret;
+ }
+
+ if (dai->capture.channels_min) {
+ ret = ep93xx_pcm_preallocate_dma_buffer(pcm,
+ SNDRV_PCM_STREAM_CAPTURE);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+struct snd_soc_platform ep93xx_soc_platform = {
+ .name = "ep93xx-audio",
+ .pcm_ops = &ep93xx_pcm_ops,
+ .pcm_new = &ep93xx_pcm_new,
+ .pcm_free = &ep93xx_pcm_free_dma_buffers,
+};
+EXPORT_SYMBOL_GPL(ep93xx_soc_platform);
+
+static int __init ep93xx_soc_platform_init(void)
+{
+ return snd_soc_register_platform(&ep93xx_soc_platform);
+}
+
+static void __exit ep93xx_soc_platform_exit(void)
+{
+ snd_soc_unregister_platform(&ep93xx_soc_platform);
+}
+
+module_init(ep93xx_soc_platform_init);
+module_exit(ep93xx_soc_platform_exit);
+
+MODULE_AUTHOR("Ryan Mallon <ryan@bluewatersys.com>");
+MODULE_DESCRIPTION("EP93xx ALSA PCM interface");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/ep93xx/ep93xx-pcm.h b/sound/soc/ep93xx/ep93xx-pcm.h
new file mode 100644
index 00000000000..4ffdd3f62fe
--- /dev/null
+++ b/sound/soc/ep93xx/ep93xx-pcm.h
@@ -0,0 +1,22 @@
+/*
+ * sound/soc/ep93xx/ep93xx-pcm.h - EP93xx ALSA PCM interface
+ *
+ * Copyright (C) 2006 Lennert Buytenhek <buytenh@wantstofly.org>
+ * Copyright (C) 2006 Applied Data Systems
+ *
+ * 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 _EP93XX_SND_SOC_PCM_H
+#define _EP93XX_SND_SOC_PCM_H
+
+struct ep93xx_pcm_dma_params {
+ char *name;
+ int dma_port;
+};
+
+extern struct snd_soc_platform ep93xx_soc_platform;
+
+#endif /* _EP93XX_SND_SOC_PCM_H */
diff --git a/sound/soc/ep93xx/snappercl15.c b/sound/soc/ep93xx/snappercl15.c
new file mode 100644
index 00000000000..64955340ff7
--- /dev/null
+++ b/sound/soc/ep93xx/snappercl15.c
@@ -0,0 +1,150 @@
+/*
+ * snappercl15.c -- SoC audio for Bluewater Systems Snapper CL15 module
+ *
+ * Copyright (C) 2008 Bluewater Systems Ltd
+ * Author: Ryan Mallon <ryan@bluewatersys.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/platform_device.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+
+#include <asm/mach-types.h>
+#include <mach/hardware.h>
+
+#include "../codecs/tlv320aic23.h"
+#include "ep93xx-pcm.h"
+#include "ep93xx-i2s.h"
+
+#define CODEC_CLOCK 5644800
+
+static int snappercl15_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+ int err;
+
+ err = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
+ SND_SOC_DAIFMT_NB_IF |
+ SND_SOC_DAIFMT_CBS_CFS);
+
+ err = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
+ SND_SOC_DAIFMT_NB_IF |
+ SND_SOC_DAIFMT_CBS_CFS);
+ if (err)
+ return err;
+
+ err = snd_soc_dai_set_sysclk(codec_dai, 0, CODEC_CLOCK,
+ SND_SOC_CLOCK_IN);
+ if (err)
+ return err;
+
+ err = snd_soc_dai_set_sysclk(cpu_dai, 0, CODEC_CLOCK,
+ SND_SOC_CLOCK_OUT);
+ if (err)
+ return err;
+
+ return 0;
+}
+
+static struct snd_soc_ops snappercl15_ops = {
+ .hw_params = snappercl15_hw_params,
+};
+
+static const struct snd_soc_dapm_widget tlv320aic23_dapm_widgets[] = {
+ SND_SOC_DAPM_HP("Headphone Jack", NULL),
+ SND_SOC_DAPM_LINE("Line In", NULL),
+ SND_SOC_DAPM_MIC("Mic Jack", NULL),
+};
+
+static const struct snd_soc_dapm_route audio_map[] = {
+ {"Headphone Jack", NULL, "LHPOUT"},
+ {"Headphone Jack", NULL, "RHPOUT"},
+
+ {"LLINEIN", NULL, "Line In"},
+ {"RLINEIN", NULL, "Line In"},
+
+ {"MICIN", NULL, "Mic Jack"},
+};
+
+static int snappercl15_tlv320aic23_init(struct snd_soc_codec *codec)
+{
+ snd_soc_dapm_new_controls(codec, tlv320aic23_dapm_widgets,
+ ARRAY_SIZE(tlv320aic23_dapm_widgets));
+
+ snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
+ return 0;
+}
+
+static struct snd_soc_dai_link snappercl15_dai = {
+ .name = "tlv320aic23",
+ .stream_name = "AIC23",
+ .cpu_dai = &ep93xx_i2s_dai,
+ .codec_dai = &tlv320aic23_dai,
+ .init = snappercl15_tlv320aic23_init,
+ .ops = &snappercl15_ops,
+};
+
+static struct snd_soc_card snd_soc_snappercl15 = {
+ .name = "Snapper CL15",
+ .platform = &ep93xx_soc_platform,
+ .dai_link = &snappercl15_dai,
+ .num_links = 1,
+};
+
+static struct snd_soc_device snappercl15_snd_devdata = {
+ .card = &snd_soc_snappercl15,
+ .codec_dev = &soc_codec_dev_tlv320aic23,
+};
+
+static struct platform_device *snappercl15_snd_device;
+
+static int __init snappercl15_init(void)
+{
+ int ret;
+
+ if (!machine_is_snapper_cl15())
+ return -ENODEV;
+
+ ret = ep93xx_i2s_acquire(EP93XX_SYSCON_DEVCFG_I2SONAC97,
+ EP93XX_SYSCON_I2SCLKDIV_ORIDE |
+ EP93XX_SYSCON_I2SCLKDIV_SPOL);
+ if (ret)
+ return ret;
+
+ snappercl15_snd_device = platform_device_alloc("soc-audio", -1);
+ if (!snappercl15_snd_device)
+ return -ENOMEM;
+
+ platform_set_drvdata(snappercl15_snd_device, &snappercl15_snd_devdata);
+ snappercl15_snd_devdata.dev = &snappercl15_snd_device->dev;
+ ret = platform_device_add(snappercl15_snd_device);
+ if (ret)
+ platform_device_put(snappercl15_snd_device);
+
+ return ret;
+}
+
+static void __exit snappercl15_exit(void)
+{
+ platform_device_unregister(snappercl15_snd_device);
+ ep93xx_i2s_release();
+}
+
+module_init(snappercl15_init);
+module_exit(snappercl15_exit);
+
+MODULE_AUTHOR("Ryan Mallon <ryan@bluewatersys.com>");
+MODULE_DESCRIPTION("ALSA SoC Snapper CL15");
+MODULE_LICENSE("GPL");
+
diff --git a/sound/soc/fsl/mpc5200_psc_i2s.c b/sound/soc/fsl/mpc5200_psc_i2s.c
index 4f455bd6851..676841cbae9 100644
--- a/sound/soc/fsl/mpc5200_psc_i2s.c
+++ b/sound/soc/fsl/mpc5200_psc_i2s.c
@@ -16,7 +16,6 @@
#include <asm/mpc52xx_psc.h>
-#include "mpc5200_psc_i2s.h"
#include "mpc5200_dma.h"
/**
diff --git a/sound/soc/fsl/mpc5200_psc_i2s.h b/sound/soc/fsl/mpc5200_psc_i2s.h
deleted file mode 100644
index ce55e070fdf..00000000000
--- a/sound/soc/fsl/mpc5200_psc_i2s.h
+++ /dev/null
@@ -1,12 +0,0 @@
-/*
- * Freescale MPC5200 PSC in I2S mode
- * ALSA SoC Digital Audio Interface (DAI) driver
- *
- */
-
-#ifndef __SOUND_SOC_FSL_MPC52xx_PSC_I2S_H__
-#define __SOUND_SOC_FSL_MPC52xx_PSC_I2S_H__
-
-extern struct snd_soc_dai psc_i2s_dai[];
-
-#endif /* __SOUND_SOC_FSL_MPC52xx_PSC_I2S_H__ */
diff --git a/sound/soc/fsl/mpc8610_hpcd.c b/sound/soc/fsl/mpc8610_hpcd.c
index 6a2764ee820..3a501062c24 100644
--- a/sound/soc/fsl/mpc8610_hpcd.c
+++ b/sound/soc/fsl/mpc8610_hpcd.c
@@ -46,7 +46,7 @@ struct mpc8610_hpcd_data {
};
/**
- * mpc8610_hpcd_machine_probe: initalize the board
+ * mpc8610_hpcd_machine_probe: initialize the board
*
* This function is called when platform_device_add() is called. It is used
* to initialize the board-specific hardware.
diff --git a/sound/soc/imx/Kconfig b/sound/soc/imx/Kconfig
index 252defea93b..52dac5e3874 100644
--- a/sound/soc/imx/Kconfig
+++ b/sound/soc/imx/Kconfig
@@ -1,4 +1,4 @@
-config SND_IMX_SOC
+menuconfig SND_IMX_SOC
tristate "SoC Audio for Freescale i.MX CPUs"
depends on ARCH_MXC
select SND_PCM
@@ -8,14 +8,12 @@ config SND_IMX_SOC
Say Y or M if you want to add support for codecs attached to
the i.MX SSI interface.
-config SND_MXC_SOC_SSI
- tristate
+if SND_IMX_SOC
config SND_MXC_SOC_WM1133_EV1
tristate "Audio on the the i.MX31ADS with WM1133-EV1 fitted"
- depends on SND_IMX_SOC && MACH_MX31ADS_WM1133_EV1 && EXPERIMENTAL
+ depends on MACH_MX31ADS_WM1133_EV1 && EXPERIMENTAL
select SND_SOC_WM8350
- select SND_MXC_SOC_SSI
help
Enable support for audio on the i.MX31ADS with the WM1133-EV1
PMIC board with WM8835x fitted.
@@ -23,8 +21,17 @@ config SND_MXC_SOC_WM1133_EV1
config SND_SOC_PHYCORE_AC97
tristate "SoC Audio support for Phytec phyCORE (and phyCARD) boards"
depends on MACH_PCM043 || MACH_PCA100
- select SND_MXC_SOC_SSI
select SND_SOC_WM9712
help
Say Y if you want to add support for SoC audio on Phytec phyCORE
and phyCARD boards in AC97 mode
+
+config SND_SOC_EUKREA_TLV320
+ tristate "Eukrea TLV320"
+ depends on MACH_EUKREA_MBIMX27_BASEBOARD || MACH_EUKREA_MBIMXSD_BASEBOARD
+ select SND_SOC_TLV320AIC23
+ help
+ Enable I2S based access to the TLV320AIC23B codec attached
+ to the SSI interface
+
+endif # SND_IMX_SOC
diff --git a/sound/soc/imx/Makefile b/sound/soc/imx/Makefile
index 2d203635ac1..7bc57baf2b0 100644
--- a/sound/soc/imx/Makefile
+++ b/sound/soc/imx/Makefile
@@ -8,8 +8,10 @@ endif
obj-$(CONFIG_SND_IMX_SOC) += snd-soc-imx.o
# i.MX Machine Support
+snd-soc-eukrea-tlv320-objs := eukrea-tlv320.o
snd-soc-phycore-ac97-objs := phycore-ac97.o
snd-soc-wm1133-ev1-objs := wm1133-ev1.o
+obj-$(CONFIG_SND_SOC_EUKREA_TLV320) += snd-soc-eukrea-tlv320.o
obj-$(CONFIG_SND_SOC_PHYCORE_AC97) += snd-soc-phycore-ac97.o
obj-$(CONFIG_SND_MXC_SOC_WM1133_EV1) += snd-soc-wm1133-ev1.o
diff --git a/sound/soc/imx/eukrea-tlv320.c b/sound/soc/imx/eukrea-tlv320.c
new file mode 100644
index 00000000000..f15dfbdc47e
--- /dev/null
+++ b/sound/soc/imx/eukrea-tlv320.c
@@ -0,0 +1,137 @@
+/*
+ * eukrea-tlv320.c -- SoC audio for eukrea_cpuimxXX in I2S mode
+ *
+ * Copyright 2010 Eric Bénard, Eukréa Electromatique <eric@eukrea.com>
+ *
+ * based on sound/soc/s3c24xx/s3c24xx_simtec_tlv320aic23.c
+ * which is Copyright 2009 Simtec Electronics
+ * and on sound/soc/imx/phycore-ac97.c which is
+ * Copyright 2009 Sascha Hauer, Pengutronix <s.hauer@pengutronix.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 <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/device.h>
+#include <linux/i2c.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <asm/mach-types.h>
+
+#include "../codecs/tlv320aic23.h"
+#include "imx-ssi.h"
+
+#define CODEC_CLOCK 12000000
+
+static int eukrea_tlv320_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+ int ret;
+
+ ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
+ SND_SOC_DAIFMT_NB_NF |
+ SND_SOC_DAIFMT_CBM_CFM);
+ if (ret) {
+ pr_err("%s: failed set cpu dai format\n", __func__);
+ return ret;
+ }
+
+ ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
+ SND_SOC_DAIFMT_NB_NF |
+ SND_SOC_DAIFMT_CBM_CFM);
+ if (ret) {
+ pr_err("%s: failed set codec dai format\n", __func__);
+ return ret;
+ }
+
+ ret = snd_soc_dai_set_sysclk(codec_dai, 0,
+ CODEC_CLOCK, SND_SOC_CLOCK_OUT);
+ if (ret) {
+ pr_err("%s: failed setting codec sysclk\n", __func__);
+ return ret;
+ }
+ snd_soc_dai_set_tdm_slot(cpu_dai, 0xffffffc, 0xffffffc, 2, 0);
+
+ ret = snd_soc_dai_set_sysclk(cpu_dai, IMX_SSP_SYS_CLK, 0,
+ SND_SOC_CLOCK_IN);
+ if (ret) {
+ pr_err("can't set CPU system clock IMX_SSP_SYS_CLK\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static struct snd_soc_ops eukrea_tlv320_snd_ops = {
+ .hw_params = eukrea_tlv320_hw_params,
+};
+
+static struct snd_soc_dai_link eukrea_tlv320_dai = {
+ .name = "tlv320aic23",
+ .stream_name = "TLV320AIC23",
+ .codec_dai = &tlv320aic23_dai,
+ .ops = &eukrea_tlv320_snd_ops,
+};
+
+static struct snd_soc_card eukrea_tlv320 = {
+ .name = "cpuimx-audio",
+ .platform = &imx_soc_platform,
+ .dai_link = &eukrea_tlv320_dai,
+ .num_links = 1,
+};
+
+static struct snd_soc_device eukrea_tlv320_snd_devdata = {
+ .card = &eukrea_tlv320,
+ .codec_dev = &soc_codec_dev_tlv320aic23,
+};
+
+static struct platform_device *eukrea_tlv320_snd_device;
+
+static int __init eukrea_tlv320_init(void)
+{
+ int ret;
+
+ if (!machine_is_eukrea_cpuimx27() && !machine_is_eukrea_cpuimx25sd()
+ && !machine_is_eukrea_cpuimx35sd())
+ /* return happy. We might run on a totally different machine */
+ return 0;
+
+ eukrea_tlv320_snd_device = platform_device_alloc("soc-audio", -1);
+ if (!eukrea_tlv320_snd_device)
+ return -ENOMEM;
+
+ eukrea_tlv320_dai.cpu_dai = &imx_ssi_pcm_dai[0];
+
+ platform_set_drvdata(eukrea_tlv320_snd_device, &eukrea_tlv320_snd_devdata);
+ eukrea_tlv320_snd_devdata.dev = &eukrea_tlv320_snd_device->dev;
+ ret = platform_device_add(eukrea_tlv320_snd_device);
+
+ if (ret) {
+ printk(KERN_ERR "ASoC: Platform device allocation failed\n");
+ platform_device_put(eukrea_tlv320_snd_device);
+ }
+
+ return ret;
+}
+
+static void __exit eukrea_tlv320_exit(void)
+{
+ platform_device_unregister(eukrea_tlv320_snd_device);
+}
+
+module_init(eukrea_tlv320_init);
+module_exit(eukrea_tlv320_exit);
+
+MODULE_AUTHOR("Eric Bénard <eric@eukrea.com>");
+MODULE_DESCRIPTION("CPUIMX ALSA SoC driver");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/imx/imx-pcm-dma-mx2.c b/sound/soc/imx/imx-pcm-dma-mx2.c
index 05f19c9284f..0a595da4811 100644
--- a/sound/soc/imx/imx-pcm-dma-mx2.c
+++ b/sound/soc/imx/imx-pcm-dma-mx2.c
@@ -292,12 +292,16 @@ static int snd_imx_open(struct snd_pcm_substream *substream)
int ret;
iprtd = kzalloc(sizeof(*iprtd), GFP_KERNEL);
+ if (iprtd == NULL)
+ return -ENOMEM;
runtime->private_data = iprtd;
ret = snd_pcm_hw_constraint_integer(substream->runtime,
SNDRV_PCM_HW_PARAM_PERIODS);
- if (ret < 0)
+ if (ret < 0) {
+ kfree(iprtd);
return ret;
+ }
snd_soc_set_runtime_hwparams(substream, &snd_imx_hardware);
return 0;
diff --git a/sound/soc/imx/imx-pcm-fiq.c b/sound/soc/imx/imx-pcm-fiq.c
index 6b518e07eea..b2bf27282cd 100644
--- a/sound/soc/imx/imx-pcm-fiq.c
+++ b/sound/soc/imx/imx-pcm-fiq.c
@@ -192,6 +192,8 @@ static int snd_imx_open(struct snd_pcm_substream *substream)
int ret;
iprtd = kzalloc(sizeof(*iprtd), GFP_KERNEL);
+ if (iprtd == NULL)
+ return -ENOMEM;
runtime->private_data = iprtd;
iprtd->substream = substream;
@@ -202,8 +204,10 @@ static int snd_imx_open(struct snd_pcm_substream *substream)
ret = snd_pcm_hw_constraint_integer(substream->runtime,
SNDRV_PCM_HW_PARAM_PERIODS);
- if (ret < 0)
+ if (ret < 0) {
+ kfree(iprtd);
return ret;
+ }
snd_soc_set_runtime_hwparams(substream, &snd_imx_hardware);
return 0;
diff --git a/sound/soc/imx/imx-ssi.c b/sound/soc/imx/imx-ssi.c
index 80b4fee2442..a11daa1e905 100644
--- a/sound/soc/imx/imx-ssi.c
+++ b/sound/soc/imx/imx-ssi.c
@@ -23,7 +23,7 @@
* between pcm data and GPIO status data changes. Our FIQ handler is not
* able to handle this, hence this driver only works with 48000Hz sampling
* rate.
- * Reading and writing AC97 registers is another challange. The core
+ * Reading and writing AC97 registers is another challenge. The core
* provides us status bits when the read register is updated with *another*
* value. When we read the same register two times (and the register still
* contains the same value) these status bits are not set. We work
@@ -83,8 +83,6 @@ static int imx_ssi_set_dai_tdm_slot(struct snd_soc_dai *cpu_dai,
/*
* SSI DAI format configuration.
* Should only be called when port is inactive (i.e. SSIEN = 0).
- * Note: We don't use the I2S modes but instead manually configure the
- * SSI for I2S because the I2S mode is only a register preset.
*/
static int imx_ssi_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
{
@@ -99,6 +97,10 @@ static int imx_ssi_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
/* data on rising edge of bclk, frame low 1clk before data */
strcr |= SSI_STCR_TFSI | SSI_STCR_TEFS | SSI_STCR_TXBIT0;
scr |= SSI_SCR_NET;
+ if (ssi->flags & IMX_SSI_USE_I2S_SLAVE) {
+ scr &= ~SSI_I2S_MODE_MASK;
+ scr |= SSI_SCR_I2S_MODE_SLAVE;
+ }
break;
case SND_SOC_DAIFMT_LEFT_J:
/* data on rising edge of bclk, frame high with data */
@@ -143,6 +145,11 @@ static int imx_ssi_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
strcr |= SSI_STCR_TFEN0;
+ if (ssi->flags & IMX_SSI_NET)
+ scr |= SSI_SCR_NET;
+ if (ssi->flags & IMX_SSI_SYN)
+ scr |= SSI_SCR_SYN;
+
writel(strcr, ssi->base + SSI_STCR);
writel(strcr, ssi->base + SSI_SRCR);
writel(scr, ssi->base + SSI_SCR);
diff --git a/sound/soc/jz4740/Kconfig b/sound/soc/jz4740/Kconfig
new file mode 100644
index 00000000000..5351cba66c9
--- /dev/null
+++ b/sound/soc/jz4740/Kconfig
@@ -0,0 +1,23 @@
+config SND_JZ4740_SOC
+ tristate "SoC Audio for Ingenic JZ4740 SoC"
+ depends on MACH_JZ4740 && SND_SOC
+ help
+ Say Y or M if you want to add support for codecs attached to
+ the JZ4740 I2S interface. You will also need to select the audio
+ interfaces to support below.
+
+config SND_JZ4740_SOC_I2S
+ depends on SND_JZ4740_SOC
+ tristate "SoC Audio (I2S protocol) for Ingenic JZ4740 SoC"
+ help
+ Say Y if you want to use I2S protocol and I2S codec on Ingenic JZ4740
+ based boards.
+
+config SND_JZ4740_SOC_QI_LB60
+ tristate "SoC Audio support for Qi LB60"
+ depends on SND_JZ4740_SOC && JZ4740_QI_LB60
+ select SND_JZ4740_SOC_I2S
+ select SND_SOC_JZ4740_CODEC
+ help
+ Say Y if you want to add support for ASoC audio on the Qi LB60 board
+ a.k.a Qi Ben NanoNote.
diff --git a/sound/soc/jz4740/Makefile b/sound/soc/jz4740/Makefile
new file mode 100644
index 00000000000..be873c1b0c2
--- /dev/null
+++ b/sound/soc/jz4740/Makefile
@@ -0,0 +1,13 @@
+#
+# Jz4740 Platform Support
+#
+snd-soc-jz4740-objs := jz4740-pcm.o
+snd-soc-jz4740-i2s-objs := jz4740-i2s.o
+
+obj-$(CONFIG_SND_JZ4740_SOC) += snd-soc-jz4740.o
+obj-$(CONFIG_SND_JZ4740_SOC_I2S) += snd-soc-jz4740-i2s.o
+
+# Jz4740 Machine Support
+snd-soc-qi-lb60-objs := qi_lb60.o
+
+obj-$(CONFIG_SND_JZ4740_SOC_QI_LB60) += snd-soc-qi-lb60.o
diff --git a/sound/soc/jz4740/jz4740-i2s.c b/sound/soc/jz4740/jz4740-i2s.c
new file mode 100644
index 00000000000..eb518f0c5e0
--- /dev/null
+++ b/sound/soc/jz4740/jz4740-i2s.c
@@ -0,0 +1,540 @@
+/*
+ * Copyright (C) 2010, Lars-Peter Clausen <lars@metafoo.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.
+ *
+ * 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/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+
+#include <linux/dma-mapping.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+
+#include "jz4740-i2s.h"
+#include "jz4740-pcm.h"
+
+#define JZ_REG_AIC_CONF 0x00
+#define JZ_REG_AIC_CTRL 0x04
+#define JZ_REG_AIC_I2S_FMT 0x10
+#define JZ_REG_AIC_FIFO_STATUS 0x14
+#define JZ_REG_AIC_I2S_STATUS 0x1c
+#define JZ_REG_AIC_CLK_DIV 0x30
+#define JZ_REG_AIC_FIFO 0x34
+
+#define JZ_AIC_CONF_FIFO_RX_THRESHOLD_MASK (0xf << 12)
+#define JZ_AIC_CONF_FIFO_TX_THRESHOLD_MASK (0xf << 8)
+#define JZ_AIC_CONF_OVERFLOW_PLAY_LAST BIT(6)
+#define JZ_AIC_CONF_INTERNAL_CODEC BIT(5)
+#define JZ_AIC_CONF_I2S BIT(4)
+#define JZ_AIC_CONF_RESET BIT(3)
+#define JZ_AIC_CONF_BIT_CLK_MASTER BIT(2)
+#define JZ_AIC_CONF_SYNC_CLK_MASTER BIT(1)
+#define JZ_AIC_CONF_ENABLE BIT(0)
+
+#define JZ_AIC_CONF_FIFO_RX_THRESHOLD_OFFSET 12
+#define JZ_AIC_CONF_FIFO_TX_THRESHOLD_OFFSET 8
+
+#define JZ_AIC_CTRL_OUTPUT_SAMPLE_SIZE_MASK (0x7 << 19)
+#define JZ_AIC_CTRL_INPUT_SAMPLE_SIZE_MASK (0x7 << 16)
+#define JZ_AIC_CTRL_ENABLE_RX_DMA BIT(15)
+#define JZ_AIC_CTRL_ENABLE_TX_DMA BIT(14)
+#define JZ_AIC_CTRL_MONO_TO_STEREO BIT(11)
+#define JZ_AIC_CTRL_SWITCH_ENDIANNESS BIT(10)
+#define JZ_AIC_CTRL_SIGNED_TO_UNSIGNED BIT(9)
+#define JZ_AIC_CTRL_FLUSH BIT(8)
+#define JZ_AIC_CTRL_ENABLE_ROR_INT BIT(6)
+#define JZ_AIC_CTRL_ENABLE_TUR_INT BIT(5)
+#define JZ_AIC_CTRL_ENABLE_RFS_INT BIT(4)
+#define JZ_AIC_CTRL_ENABLE_TFS_INT BIT(3)
+#define JZ_AIC_CTRL_ENABLE_LOOPBACK BIT(2)
+#define JZ_AIC_CTRL_ENABLE_PLAYBACK BIT(1)
+#define JZ_AIC_CTRL_ENABLE_CAPTURE BIT(0)
+
+#define JZ_AIC_CTRL_OUTPUT_SAMPLE_SIZE_OFFSET 19
+#define JZ_AIC_CTRL_INPUT_SAMPLE_SIZE_OFFSET 16
+
+#define JZ_AIC_I2S_FMT_DISABLE_BIT_CLK BIT(12)
+#define JZ_AIC_I2S_FMT_ENABLE_SYS_CLK BIT(4)
+#define JZ_AIC_I2S_FMT_MSB BIT(0)
+
+#define JZ_AIC_I2S_STATUS_BUSY BIT(2)
+
+#define JZ_AIC_CLK_DIV_MASK 0xf
+
+struct jz4740_i2s {
+ struct resource *mem;
+ void __iomem *base;
+ dma_addr_t phys_base;
+
+ struct clk *clk_aic;
+ struct clk *clk_i2s;
+
+ struct jz4740_pcm_config pcm_config_playback;
+ struct jz4740_pcm_config pcm_config_capture;
+};
+
+static inline uint32_t jz4740_i2s_read(const struct jz4740_i2s *i2s,
+ unsigned int reg)
+{
+ return readl(i2s->base + reg);
+}
+
+static inline void jz4740_i2s_write(const struct jz4740_i2s *i2s,
+ unsigned int reg, uint32_t value)
+{
+ writel(value, i2s->base + reg);
+}
+
+static inline struct jz4740_i2s *jz4740_dai_to_i2s(struct snd_soc_dai *dai)
+{
+ return dai->private_data;
+}
+
+static int jz4740_i2s_startup(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct jz4740_i2s *i2s = jz4740_dai_to_i2s(dai);
+ uint32_t conf, ctrl;
+
+ if (dai->active)
+ return 0;
+
+ ctrl = jz4740_i2s_read(i2s, JZ_REG_AIC_CTRL);
+ ctrl |= JZ_AIC_CTRL_FLUSH;
+ jz4740_i2s_write(i2s, JZ_REG_AIC_CTRL, ctrl);
+
+ clk_enable(i2s->clk_i2s);
+
+ conf = jz4740_i2s_read(i2s, JZ_REG_AIC_CONF);
+ conf |= JZ_AIC_CONF_ENABLE;
+ jz4740_i2s_write(i2s, JZ_REG_AIC_CONF, conf);
+
+ return 0;
+}
+
+static void jz4740_i2s_shutdown(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct jz4740_i2s *i2s = jz4740_dai_to_i2s(dai);
+ uint32_t conf;
+
+ if (!dai->active)
+ return;
+
+ conf = jz4740_i2s_read(i2s, JZ_REG_AIC_CONF);
+ conf &= ~JZ_AIC_CONF_ENABLE;
+ jz4740_i2s_write(i2s, JZ_REG_AIC_CONF, conf);
+
+ clk_disable(i2s->clk_i2s);
+}
+
+static int jz4740_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
+ struct snd_soc_dai *dai)
+{
+ struct jz4740_i2s *i2s = jz4740_dai_to_i2s(dai);
+
+ uint32_t ctrl;
+ uint32_t mask;
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ mask = JZ_AIC_CTRL_ENABLE_PLAYBACK | JZ_AIC_CTRL_ENABLE_TX_DMA;
+ else
+ mask = JZ_AIC_CTRL_ENABLE_CAPTURE | JZ_AIC_CTRL_ENABLE_RX_DMA;
+
+ ctrl = jz4740_i2s_read(i2s, JZ_REG_AIC_CTRL);
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_RESUME:
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ ctrl |= mask;
+ break;
+ case SNDRV_PCM_TRIGGER_STOP:
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ ctrl &= ~mask;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ jz4740_i2s_write(i2s, JZ_REG_AIC_CTRL, ctrl);
+
+ return 0;
+}
+
+static int jz4740_i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+ struct jz4740_i2s *i2s = jz4740_dai_to_i2s(dai);
+
+ uint32_t format = 0;
+ uint32_t conf;
+
+ conf = jz4740_i2s_read(i2s, JZ_REG_AIC_CONF);
+
+ conf &= ~(JZ_AIC_CONF_BIT_CLK_MASTER | JZ_AIC_CONF_SYNC_CLK_MASTER);
+
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBS_CFS:
+ conf |= JZ_AIC_CONF_BIT_CLK_MASTER | JZ_AIC_CONF_SYNC_CLK_MASTER;
+ format |= JZ_AIC_I2S_FMT_ENABLE_SYS_CLK;
+ break;
+ case SND_SOC_DAIFMT_CBM_CFS:
+ conf |= JZ_AIC_CONF_SYNC_CLK_MASTER;
+ break;
+ case SND_SOC_DAIFMT_CBS_CFM:
+ conf |= JZ_AIC_CONF_BIT_CLK_MASTER;
+ break;
+ case SND_SOC_DAIFMT_CBM_CFM:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_MSB:
+ format |= JZ_AIC_I2S_FMT_MSB;
+ break;
+ case SND_SOC_DAIFMT_I2S:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+ case SND_SOC_DAIFMT_NB_NF:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ jz4740_i2s_write(i2s, JZ_REG_AIC_CONF, conf);
+ jz4740_i2s_write(i2s, JZ_REG_AIC_I2S_FMT, format);
+
+ return 0;
+}
+
+static int jz4740_i2s_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
+{
+ struct jz4740_i2s *i2s = jz4740_dai_to_i2s(dai);
+ enum jz4740_dma_width dma_width;
+ struct jz4740_pcm_config *pcm_config;
+ unsigned int sample_size;
+ uint32_t ctrl;
+
+ ctrl = jz4740_i2s_read(i2s, JZ_REG_AIC_CTRL);
+
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_S8:
+ sample_size = 0;
+ dma_width = JZ4740_DMA_WIDTH_8BIT;
+ break;
+ case SNDRV_PCM_FORMAT_S16:
+ sample_size = 1;
+ dma_width = JZ4740_DMA_WIDTH_16BIT;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ ctrl &= ~JZ_AIC_CTRL_OUTPUT_SAMPLE_SIZE_MASK;
+ ctrl |= sample_size << JZ_AIC_CTRL_OUTPUT_SAMPLE_SIZE_OFFSET;
+ if (params_channels(params) == 1)
+ ctrl |= JZ_AIC_CTRL_MONO_TO_STEREO;
+ else
+ ctrl &= ~JZ_AIC_CTRL_MONO_TO_STEREO;
+
+ pcm_config = &i2s->pcm_config_playback;
+ pcm_config->dma_config.dst_width = dma_width;
+
+ } else {
+ ctrl &= ~JZ_AIC_CTRL_INPUT_SAMPLE_SIZE_MASK;
+ ctrl |= sample_size << JZ_AIC_CTRL_INPUT_SAMPLE_SIZE_OFFSET;
+
+ pcm_config = &i2s->pcm_config_capture;
+ pcm_config->dma_config.src_width = dma_width;
+ }
+
+ jz4740_i2s_write(i2s, JZ_REG_AIC_CTRL, ctrl);
+
+ snd_soc_dai_set_dma_data(dai, substream, pcm_config);
+
+ return 0;
+}
+
+static int jz4740_i2s_set_sysclk(struct snd_soc_dai *dai, int clk_id,
+ unsigned int freq, int dir)
+{
+ struct jz4740_i2s *i2s = jz4740_dai_to_i2s(dai);
+ struct clk *parent;
+ int ret = 0;
+
+ switch (clk_id) {
+ case JZ4740_I2S_CLKSRC_EXT:
+ parent = clk_get(NULL, "ext");
+ clk_set_parent(i2s->clk_i2s, parent);
+ break;
+ case JZ4740_I2S_CLKSRC_PLL:
+ parent = clk_get(NULL, "pll half");
+ clk_set_parent(i2s->clk_i2s, parent);
+ ret = clk_set_rate(i2s->clk_i2s, freq);
+ break;
+ default:
+ return -EINVAL;
+ }
+ clk_put(parent);
+
+ return ret;
+}
+
+static int jz4740_i2s_suspend(struct snd_soc_dai *dai)
+{
+ struct jz4740_i2s *i2s = jz4740_dai_to_i2s(dai);
+ uint32_t conf;
+
+ if (dai->active) {
+ conf = jz4740_i2s_read(i2s, JZ_REG_AIC_CONF);
+ conf &= ~JZ_AIC_CONF_ENABLE;
+ jz4740_i2s_write(i2s, JZ_REG_AIC_CONF, conf);
+
+ clk_disable(i2s->clk_i2s);
+ }
+
+ clk_disable(i2s->clk_aic);
+
+ return 0;
+}
+
+static int jz4740_i2s_resume(struct snd_soc_dai *dai)
+{
+ struct jz4740_i2s *i2s = jz4740_dai_to_i2s(dai);
+ uint32_t conf;
+
+ clk_enable(i2s->clk_aic);
+
+ if (dai->active) {
+ clk_enable(i2s->clk_i2s);
+
+ conf = jz4740_i2s_read(i2s, JZ_REG_AIC_CONF);
+ conf |= JZ_AIC_CONF_ENABLE;
+ jz4740_i2s_write(i2s, JZ_REG_AIC_CONF, conf);
+ }
+
+ return 0;
+}
+
+static int jz4740_i2s_probe(struct platform_device *pdev, struct snd_soc_dai *dai)
+{
+ struct jz4740_i2s *i2s = jz4740_dai_to_i2s(dai);
+ uint32_t conf;
+
+ conf = (7 << JZ_AIC_CONF_FIFO_RX_THRESHOLD_OFFSET) |
+ (8 << JZ_AIC_CONF_FIFO_TX_THRESHOLD_OFFSET) |
+ JZ_AIC_CONF_OVERFLOW_PLAY_LAST |
+ JZ_AIC_CONF_I2S |
+ JZ_AIC_CONF_INTERNAL_CODEC;
+
+ jz4740_i2s_write(i2s, JZ_REG_AIC_CONF, JZ_AIC_CONF_RESET);
+ jz4740_i2s_write(i2s, JZ_REG_AIC_CONF, conf);
+
+ return 0;
+}
+
+static struct snd_soc_dai_ops jz4740_i2s_dai_ops = {
+ .startup = jz4740_i2s_startup,
+ .shutdown = jz4740_i2s_shutdown,
+ .trigger = jz4740_i2s_trigger,
+ .hw_params = jz4740_i2s_hw_params,
+ .set_fmt = jz4740_i2s_set_fmt,
+ .set_sysclk = jz4740_i2s_set_sysclk,
+};
+
+#define JZ4740_I2S_FMTS (SNDRV_PCM_FMTBIT_S8 | \
+ SNDRV_PCM_FMTBIT_S16_LE)
+
+struct snd_soc_dai jz4740_i2s_dai = {
+ .name = "jz4740-i2s",
+ .probe = jz4740_i2s_probe,
+ .playback = {
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = JZ4740_I2S_FMTS,
+ },
+ .capture = {
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = JZ4740_I2S_FMTS,
+ },
+ .symmetric_rates = 1,
+ .ops = &jz4740_i2s_dai_ops,
+ .suspend = jz4740_i2s_suspend,
+ .resume = jz4740_i2s_resume,
+};
+EXPORT_SYMBOL_GPL(jz4740_i2s_dai);
+
+static void __devinit jz4740_i2c_init_pcm_config(struct jz4740_i2s *i2s)
+{
+ struct jz4740_dma_config *dma_config;
+
+ /* Playback */
+ dma_config = &i2s->pcm_config_playback.dma_config;
+ dma_config->src_width = JZ4740_DMA_WIDTH_32BIT,
+ dma_config->transfer_size = JZ4740_DMA_TRANSFER_SIZE_16BYTE;
+ dma_config->request_type = JZ4740_DMA_TYPE_AIC_TRANSMIT;
+ dma_config->flags = JZ4740_DMA_SRC_AUTOINC;
+ dma_config->mode = JZ4740_DMA_MODE_SINGLE;
+ i2s->pcm_config_playback.fifo_addr = i2s->phys_base + JZ_REG_AIC_FIFO;
+
+ /* Capture */
+ dma_config = &i2s->pcm_config_capture.dma_config;
+ dma_config->dst_width = JZ4740_DMA_WIDTH_32BIT,
+ dma_config->transfer_size = JZ4740_DMA_TRANSFER_SIZE_16BYTE;
+ dma_config->request_type = JZ4740_DMA_TYPE_AIC_RECEIVE;
+ dma_config->flags = JZ4740_DMA_DST_AUTOINC;
+ dma_config->mode = JZ4740_DMA_MODE_SINGLE;
+ i2s->pcm_config_capture.fifo_addr = i2s->phys_base + JZ_REG_AIC_FIFO;
+}
+
+static int __devinit jz4740_i2s_dev_probe(struct platform_device *pdev)
+{
+ struct jz4740_i2s *i2s;
+ int ret;
+
+ i2s = kzalloc(sizeof(*i2s), GFP_KERNEL);
+
+ if (!i2s)
+ return -ENOMEM;
+
+ i2s->mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!i2s->mem) {
+ ret = -ENOENT;
+ goto err_free;
+ }
+
+ i2s->mem = request_mem_region(i2s->mem->start, resource_size(i2s->mem),
+ pdev->name);
+ if (!i2s->mem) {
+ ret = -EBUSY;
+ goto err_free;
+ }
+
+ i2s->base = ioremap_nocache(i2s->mem->start, resource_size(i2s->mem));
+ if (!i2s->base) {
+ ret = -EBUSY;
+ goto err_release_mem_region;
+ }
+
+ i2s->phys_base = i2s->mem->start;
+
+ i2s->clk_aic = clk_get(&pdev->dev, "aic");
+ if (IS_ERR(i2s->clk_aic)) {
+ ret = PTR_ERR(i2s->clk_aic);
+ goto err_iounmap;
+ }
+
+ i2s->clk_i2s = clk_get(&pdev->dev, "i2s");
+ if (IS_ERR(i2s->clk_i2s)) {
+ ret = PTR_ERR(i2s->clk_i2s);
+ goto err_clk_put_aic;
+ }
+
+ clk_enable(i2s->clk_aic);
+
+ jz4740_i2c_init_pcm_config(i2s);
+
+ jz4740_i2s_dai.private_data = i2s;
+ ret = snd_soc_register_dai(&jz4740_i2s_dai);
+
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to register DAI\n");
+ goto err_clk_put_i2s;
+ }
+
+ platform_set_drvdata(pdev, i2s);
+
+ return 0;
+
+err_clk_put_i2s:
+ clk_disable(i2s->clk_aic);
+ clk_put(i2s->clk_i2s);
+err_clk_put_aic:
+ clk_put(i2s->clk_aic);
+err_iounmap:
+ iounmap(i2s->base);
+err_release_mem_region:
+ release_mem_region(i2s->mem->start, resource_size(i2s->mem));
+err_free:
+ kfree(i2s);
+
+ return ret;
+}
+
+static int __devexit jz4740_i2s_dev_remove(struct platform_device *pdev)
+{
+ struct jz4740_i2s *i2s = platform_get_drvdata(pdev);
+
+ snd_soc_unregister_dai(&jz4740_i2s_dai);
+
+ clk_disable(i2s->clk_aic);
+ clk_put(i2s->clk_i2s);
+ clk_put(i2s->clk_aic);
+
+ iounmap(i2s->base);
+ release_mem_region(i2s->mem->start, resource_size(i2s->mem));
+
+ platform_set_drvdata(pdev, NULL);
+ kfree(i2s);
+
+ return 0;
+}
+
+static struct platform_driver jz4740_i2s_driver = {
+ .probe = jz4740_i2s_dev_probe,
+ .remove = __devexit_p(jz4740_i2s_dev_remove),
+ .driver = {
+ .name = "jz4740-i2s",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init jz4740_i2s_init(void)
+{
+ return platform_driver_register(&jz4740_i2s_driver);
+}
+module_init(jz4740_i2s_init);
+
+static void __exit jz4740_i2s_exit(void)
+{
+ platform_driver_unregister(&jz4740_i2s_driver);
+}
+module_exit(jz4740_i2s_exit);
+
+MODULE_AUTHOR("Lars-Peter Clausen, <lars@metafoo.de>");
+MODULE_DESCRIPTION("Ingenic JZ4740 SoC I2S driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:jz4740-i2s");
diff --git a/sound/soc/jz4740/jz4740-i2s.h b/sound/soc/jz4740/jz4740-i2s.h
new file mode 100644
index 00000000000..da22ed88a58
--- /dev/null
+++ b/sound/soc/jz4740/jz4740-i2s.h
@@ -0,0 +1,18 @@
+/*
+ * 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 _JZ4740_I2S_H
+#define _JZ4740_I2S_H
+
+/* I2S clock source */
+#define JZ4740_I2S_CLKSRC_EXT 0
+#define JZ4740_I2S_CLKSRC_PLL 1
+
+#define JZ4740_I2S_BIT_CLK 0
+
+extern struct snd_soc_dai jz4740_i2s_dai;
+
+#endif
diff --git a/sound/soc/jz4740/jz4740-pcm.c b/sound/soc/jz4740/jz4740-pcm.c
new file mode 100644
index 00000000000..ee68d850c8d
--- /dev/null
+++ b/sound/soc/jz4740/jz4740-pcm.c
@@ -0,0 +1,373 @@
+/*
+ * Copyright (C) 2010, Lars-Peter Clausen <lars@metafoo.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.
+ *
+ * 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/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+#include <linux/dma-mapping.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+#include <asm/mach-jz4740/dma.h>
+#include "jz4740-pcm.h"
+
+struct jz4740_runtime_data {
+ unsigned long dma_period;
+ dma_addr_t dma_start;
+ dma_addr_t dma_pos;
+ dma_addr_t dma_end;
+
+ struct jz4740_dma_chan *dma;
+
+ dma_addr_t fifo_addr;
+};
+
+/* identify hardware playback capabilities */
+static const struct snd_pcm_hardware jz4740_pcm_hardware = {
+ .info = SNDRV_PCM_INFO_MMAP |
+ SNDRV_PCM_INFO_MMAP_VALID |
+ SNDRV_PCM_INFO_INTERLEAVED |
+ SNDRV_PCM_INFO_BLOCK_TRANSFER,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8,
+
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .channels_min = 1,
+ .channels_max = 2,
+ .period_bytes_min = 16,
+ .period_bytes_max = 2 * PAGE_SIZE,
+ .periods_min = 2,
+ .periods_max = 128,
+ .buffer_bytes_max = 128 * 2 * PAGE_SIZE,
+ .fifo_size = 32,
+};
+
+static void jz4740_pcm_start_transfer(struct jz4740_runtime_data *prtd,
+ struct snd_pcm_substream *substream)
+{
+ unsigned long count;
+
+ if (prtd->dma_pos == prtd->dma_end)
+ prtd->dma_pos = prtd->dma_start;
+
+ if (prtd->dma_pos + prtd->dma_period > prtd->dma_end)
+ count = prtd->dma_end - prtd->dma_pos;
+ else
+ count = prtd->dma_period;
+
+ jz4740_dma_disable(prtd->dma);
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ jz4740_dma_set_src_addr(prtd->dma, prtd->dma_pos);
+ jz4740_dma_set_dst_addr(prtd->dma, prtd->fifo_addr);
+ } else {
+ jz4740_dma_set_src_addr(prtd->dma, prtd->fifo_addr);
+ jz4740_dma_set_dst_addr(prtd->dma, prtd->dma_pos);
+ }
+
+ jz4740_dma_set_transfer_count(prtd->dma, count);
+
+ prtd->dma_pos += count;
+
+ jz4740_dma_enable(prtd->dma);
+}
+
+static void jz4740_pcm_dma_transfer_done(struct jz4740_dma_chan *dma, int err,
+ void *dev_id)
+{
+ struct snd_pcm_substream *substream = dev_id;
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct jz4740_runtime_data *prtd = runtime->private_data;
+
+ snd_pcm_period_elapsed(substream);
+
+ jz4740_pcm_start_transfer(prtd, substream);
+}
+
+static int jz4740_pcm_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct jz4740_runtime_data *prtd = runtime->private_data;
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct jz4740_pcm_config *config;
+
+ config = snd_soc_dai_get_dma_data(rtd->dai->cpu_dai, substream);
+
+ if (!config)
+ return 0;
+
+ if (!prtd->dma) {
+ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+ prtd->dma = jz4740_dma_request(substream, "PCM Capture");
+ else
+ prtd->dma = jz4740_dma_request(substream, "PCM Playback");
+ }
+
+ if (!prtd->dma)
+ return -EBUSY;
+
+ jz4740_dma_configure(prtd->dma, &config->dma_config);
+ prtd->fifo_addr = config->fifo_addr;
+
+ jz4740_dma_set_complete_cb(prtd->dma, jz4740_pcm_dma_transfer_done);
+
+ snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
+ runtime->dma_bytes = params_buffer_bytes(params);
+
+ prtd->dma_period = params_period_bytes(params);
+ prtd->dma_start = runtime->dma_addr;
+ prtd->dma_pos = prtd->dma_start;
+ prtd->dma_end = prtd->dma_start + runtime->dma_bytes;
+
+ return 0;
+}
+
+static int jz4740_pcm_hw_free(struct snd_pcm_substream *substream)
+{
+ struct jz4740_runtime_data *prtd = substream->runtime->private_data;
+
+ snd_pcm_set_runtime_buffer(substream, NULL);
+ if (prtd->dma) {
+ jz4740_dma_free(prtd->dma);
+ prtd->dma = NULL;
+ }
+
+ return 0;
+}
+
+static int jz4740_pcm_prepare(struct snd_pcm_substream *substream)
+{
+ struct jz4740_runtime_data *prtd = substream->runtime->private_data;
+
+ if (!prtd->dma)
+ return -EBUSY;
+
+ prtd->dma_pos = prtd->dma_start;
+
+ return 0;
+}
+
+static int jz4740_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct jz4740_runtime_data *prtd = runtime->private_data;
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_RESUME:
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ jz4740_pcm_start_transfer(prtd, substream);
+ break;
+ case SNDRV_PCM_TRIGGER_STOP:
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ jz4740_dma_disable(prtd->dma);
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static snd_pcm_uframes_t jz4740_pcm_pointer(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct jz4740_runtime_data *prtd = runtime->private_data;
+ unsigned long byte_offset;
+ snd_pcm_uframes_t offset;
+ struct jz4740_dma_chan *dma = prtd->dma;
+
+ /* prtd->dma_pos points to the end of the current transfer. So by
+ * subtracting prdt->dma_start we get the offset to the end of the
+ * current period in bytes. By subtracting the residue of the transfer
+ * we get the current offset in bytes. */
+ byte_offset = prtd->dma_pos - prtd->dma_start;
+ byte_offset -= jz4740_dma_get_residue(dma);
+
+ offset = bytes_to_frames(runtime, byte_offset);
+ if (offset >= runtime->buffer_size)
+ offset = 0;
+
+ return offset;
+}
+
+static int jz4740_pcm_open(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct jz4740_runtime_data *prtd;
+
+ prtd = kzalloc(sizeof(*prtd), GFP_KERNEL);
+ if (prtd == NULL)
+ return -ENOMEM;
+
+ snd_soc_set_runtime_hwparams(substream, &jz4740_pcm_hardware);
+
+ runtime->private_data = prtd;
+
+ return 0;
+}
+
+static int jz4740_pcm_close(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct jz4740_runtime_data *prtd = runtime->private_data;
+
+ kfree(prtd);
+
+ return 0;
+}
+
+static int jz4740_pcm_mmap(struct snd_pcm_substream *substream,
+ struct vm_area_struct *vma)
+{
+ return remap_pfn_range(vma, vma->vm_start,
+ substream->dma_buffer.addr >> PAGE_SHIFT,
+ vma->vm_end - vma->vm_start, vma->vm_page_prot);
+}
+
+static struct snd_pcm_ops jz4740_pcm_ops = {
+ .open = jz4740_pcm_open,
+ .close = jz4740_pcm_close,
+ .ioctl = snd_pcm_lib_ioctl,
+ .hw_params = jz4740_pcm_hw_params,
+ .hw_free = jz4740_pcm_hw_free,
+ .prepare = jz4740_pcm_prepare,
+ .trigger = jz4740_pcm_trigger,
+ .pointer = jz4740_pcm_pointer,
+ .mmap = jz4740_pcm_mmap,
+};
+
+static int jz4740_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream)
+{
+ struct snd_pcm_substream *substream = pcm->streams[stream].substream;
+ struct snd_dma_buffer *buf = &substream->dma_buffer;
+ size_t size = jz4740_pcm_hardware.buffer_bytes_max;
+
+ buf->dev.type = SNDRV_DMA_TYPE_DEV;
+ buf->dev.dev = pcm->card->dev;
+ buf->private_data = NULL;
+
+ buf->area = dma_alloc_noncoherent(pcm->card->dev, size,
+ &buf->addr, GFP_KERNEL);
+ if (!buf->area)
+ return -ENOMEM;
+
+ buf->bytes = size;
+
+ return 0;
+}
+
+static void jz4740_pcm_free(struct snd_pcm *pcm)
+{
+ struct snd_pcm_substream *substream;
+ struct snd_dma_buffer *buf;
+ int stream;
+
+ for (stream = 0; stream < SNDRV_PCM_STREAM_LAST; ++stream) {
+ substream = pcm->streams[stream].substream;
+ if (!substream)
+ continue;
+
+ buf = &substream->dma_buffer;
+ if (!buf->area)
+ continue;
+
+ dma_free_noncoherent(pcm->card->dev, buf->bytes, buf->area,
+ buf->addr);
+ buf->area = NULL;
+ }
+}
+
+static u64 jz4740_pcm_dmamask = DMA_BIT_MASK(32);
+
+int jz4740_pcm_new(struct snd_card *card, struct snd_soc_dai *dai,
+ struct snd_pcm *pcm)
+{
+ int ret = 0;
+
+ if (!card->dev->dma_mask)
+ card->dev->dma_mask = &jz4740_pcm_dmamask;
+
+ if (!card->dev->coherent_dma_mask)
+ card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
+
+ if (dai->playback.channels_min) {
+ ret = jz4740_pcm_preallocate_dma_buffer(pcm,
+ SNDRV_PCM_STREAM_PLAYBACK);
+ if (ret)
+ goto err;
+ }
+
+ if (dai->capture.channels_min) {
+ ret = jz4740_pcm_preallocate_dma_buffer(pcm,
+ SNDRV_PCM_STREAM_CAPTURE);
+ if (ret)
+ goto err;
+ }
+
+err:
+ return ret;
+}
+
+struct snd_soc_platform jz4740_soc_platform = {
+ .name = "jz4740-pcm",
+ .pcm_ops = &jz4740_pcm_ops,
+ .pcm_new = jz4740_pcm_new,
+ .pcm_free = jz4740_pcm_free,
+};
+EXPORT_SYMBOL_GPL(jz4740_soc_platform);
+
+static int __devinit jz4740_pcm_probe(struct platform_device *pdev)
+{
+ return snd_soc_register_platform(&jz4740_soc_platform);
+}
+
+static int __devexit jz4740_pcm_remove(struct platform_device *pdev)
+{
+ snd_soc_unregister_platform(&jz4740_soc_platform);
+ return 0;
+}
+
+static struct platform_driver jz4740_pcm_driver = {
+ .probe = jz4740_pcm_probe,
+ .remove = __devexit_p(jz4740_pcm_remove),
+ .driver = {
+ .name = "jz4740-pcm",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init jz4740_soc_platform_init(void)
+{
+ return platform_driver_register(&jz4740_pcm_driver);
+}
+module_init(jz4740_soc_platform_init);
+
+static void __exit jz4740_soc_platform_exit(void)
+{
+ return platform_driver_unregister(&jz4740_pcm_driver);
+}
+module_exit(jz4740_soc_platform_exit);
+
+MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
+MODULE_DESCRIPTION("Ingenic SoC JZ4740 PCM driver");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/jz4740/jz4740-pcm.h b/sound/soc/jz4740/jz4740-pcm.h
new file mode 100644
index 00000000000..e3f221e2779
--- /dev/null
+++ b/sound/soc/jz4740/jz4740-pcm.h
@@ -0,0 +1,22 @@
+/*
+ *
+ * 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 _JZ4740_PCM_H
+#define _JZ4740_PCM_H
+
+#include <linux/dma-mapping.h>
+#include <asm/mach-jz4740/dma.h>
+
+/* platform data */
+extern struct snd_soc_platform jz4740_soc_platform;
+
+struct jz4740_pcm_config {
+ struct jz4740_dma_config dma_config;
+ phys_addr_t fifo_addr;
+};
+
+#endif
diff --git a/sound/soc/jz4740/qi_lb60.c b/sound/soc/jz4740/qi_lb60.c
new file mode 100644
index 00000000000..f15f4918f15
--- /dev/null
+++ b/sound/soc/jz4740/qi_lb60.c
@@ -0,0 +1,166 @@
+/*
+ * Copyright (C) 2009, Lars-Peter Clausen <lars@metafoo.de>
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <linux/gpio.h>
+
+#include "../codecs/jz4740.h"
+#include "jz4740-pcm.h"
+#include "jz4740-i2s.h"
+
+
+#define QI_LB60_SND_GPIO JZ_GPIO_PORTB(29)
+#define QI_LB60_AMP_GPIO JZ_GPIO_PORTD(4)
+
+static int qi_lb60_spk_event(struct snd_soc_dapm_widget *widget,
+ struct snd_kcontrol *ctrl, int event)
+{
+ int on = 0;
+ if (event & SND_SOC_DAPM_POST_PMU)
+ on = 1;
+ else if (event & SND_SOC_DAPM_PRE_PMD)
+ on = 0;
+
+ gpio_set_value(QI_LB60_SND_GPIO, on);
+ gpio_set_value(QI_LB60_AMP_GPIO, on);
+
+ return 0;
+}
+
+static const struct snd_soc_dapm_widget qi_lb60_widgets[] = {
+ SND_SOC_DAPM_SPK("Speaker", qi_lb60_spk_event),
+ SND_SOC_DAPM_MIC("Mic", NULL),
+};
+
+static const struct snd_soc_dapm_route qi_lb60_routes[] = {
+ {"Mic", NULL, "MIC"},
+ {"Speaker", NULL, "LOUT"},
+ {"Speaker", NULL, "ROUT"},
+};
+
+#define QI_LB60_DAIFMT (SND_SOC_DAIFMT_I2S | \
+ SND_SOC_DAIFMT_NB_NF | \
+ SND_SOC_DAIFMT_CBM_CFM)
+
+static int qi_lb60_codec_init(struct snd_soc_codec *codec)
+{
+ int ret;
+ struct snd_soc_dai *cpu_dai = codec->socdev->card->dai_link->cpu_dai;
+
+ snd_soc_dapm_nc_pin(codec, "LIN");
+ snd_soc_dapm_nc_pin(codec, "RIN");
+
+ ret = snd_soc_dai_set_fmt(cpu_dai, QI_LB60_DAIFMT);
+ if (ret < 0) {
+ dev_err(codec->dev, "Failed to set cpu dai format: %d\n", ret);
+ return ret;
+ }
+
+ snd_soc_dapm_new_controls(codec, qi_lb60_widgets, ARRAY_SIZE(qi_lb60_widgets));
+ snd_soc_dapm_add_routes(codec, qi_lb60_routes, ARRAY_SIZE(qi_lb60_routes));
+ snd_soc_dapm_sync(codec);
+
+ return 0;
+}
+
+static struct snd_soc_dai_link qi_lb60_dai = {
+ .name = "jz4740",
+ .stream_name = "jz4740",
+ .cpu_dai = &jz4740_i2s_dai,
+ .codec_dai = &jz4740_codec_dai,
+ .init = qi_lb60_codec_init,
+};
+
+static struct snd_soc_card qi_lb60 = {
+ .name = "QI LB60",
+ .dai_link = &qi_lb60_dai,
+ .num_links = 1,
+ .platform = &jz4740_soc_platform,
+};
+
+static struct snd_soc_device qi_lb60_snd_devdata = {
+ .card = &qi_lb60,
+ .codec_dev = &soc_codec_dev_jz4740_codec,
+};
+
+static struct platform_device *qi_lb60_snd_device;
+
+static int __init qi_lb60_init(void)
+{
+ int ret;
+
+ qi_lb60_snd_device = platform_device_alloc("soc-audio", -1);
+
+ if (!qi_lb60_snd_device)
+ return -ENOMEM;
+
+ ret = gpio_request(QI_LB60_SND_GPIO, "SND");
+ if (ret) {
+ pr_err("qi_lb60 snd: Failed to request SND GPIO(%d): %d\n",
+ QI_LB60_SND_GPIO, ret);
+ goto err_device_put;
+ }
+
+ ret = gpio_request(QI_LB60_AMP_GPIO, "AMP");
+ if (ret) {
+ pr_err("qi_lb60 snd: Failed to request AMP GPIO(%d): %d\n",
+ QI_LB60_AMP_GPIO, ret);
+ goto err_gpio_free_snd;
+ }
+
+ gpio_direction_output(QI_LB60_SND_GPIO, 0);
+ gpio_direction_output(QI_LB60_AMP_GPIO, 0);
+
+ platform_set_drvdata(qi_lb60_snd_device, &qi_lb60_snd_devdata);
+ qi_lb60_snd_devdata.dev = &qi_lb60_snd_device->dev;
+
+ ret = platform_device_add(qi_lb60_snd_device);
+ if (ret) {
+ pr_err("qi_lb60 snd: Failed to add snd soc device: %d\n", ret);
+ goto err_unset_pdata;
+ }
+
+ return 0;
+
+err_unset_pdata:
+ platform_set_drvdata(qi_lb60_snd_device, NULL);
+/*err_gpio_free_amp:*/
+ gpio_free(QI_LB60_AMP_GPIO);
+err_gpio_free_snd:
+ gpio_free(QI_LB60_SND_GPIO);
+err_device_put:
+ platform_device_put(qi_lb60_snd_device);
+
+ return ret;
+}
+module_init(qi_lb60_init);
+
+static void __exit qi_lb60_exit(void)
+{
+ gpio_free(QI_LB60_AMP_GPIO);
+ gpio_free(QI_LB60_SND_GPIO);
+ platform_device_unregister(qi_lb60_snd_device);
+}
+module_exit(qi_lb60_exit);
+
+MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
+MODULE_DESCRIPTION("ALSA SoC QI LB60 Audio support");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/kirkwood/Kconfig b/sound/soc/kirkwood/Kconfig
new file mode 100644
index 00000000000..16ec2a2dba4
--- /dev/null
+++ b/sound/soc/kirkwood/Kconfig
@@ -0,0 +1,20 @@
+config SND_KIRKWOOD_SOC
+ tristate "SoC Audio for the Marvell Kirkwood chip"
+ depends on ARCH_KIRKWOOD
+ help
+ Say Y or M if you want to add support for codecs attached to
+ the Kirkwood I2S interface. You will also need to select the
+ audio interfaces to support below.
+
+config SND_KIRKWOOD_SOC_I2S
+ tristate
+
+config SND_KIRKWOOD_SOC_OPENRD
+ tristate "SoC Audio support for Kirkwood Openrd Client"
+ depends on SND_KIRKWOOD_SOC && MACH_OPENRD_CLIENT
+ select SND_KIRKWOOD_SOC_I2S
+ select SND_SOC_CS42L51
+ help
+ Say Y if you want to add support for SoC audio on
+ Openrd Client.
+
diff --git a/sound/soc/kirkwood/Makefile b/sound/soc/kirkwood/Makefile
new file mode 100644
index 00000000000..33a16dcab5b
--- /dev/null
+++ b/sound/soc/kirkwood/Makefile
@@ -0,0 +1,9 @@
+snd-soc-kirkwood-objs := kirkwood-dma.o
+snd-soc-kirkwood-i2s-objs := kirkwood-i2s.o
+
+obj-$(CONFIG_SND_KIRKWOOD_SOC) += snd-soc-kirkwood.o
+obj-$(CONFIG_SND_KIRKWOOD_SOC_I2S) += snd-soc-kirkwood-i2s.o
+
+snd-soc-openrd-objs := kirkwood-openrd.o
+
+obj-$(CONFIG_SND_KIRKWOOD_SOC_OPENRD) += snd-soc-openrd.o
diff --git a/sound/soc/kirkwood/kirkwood-dma.c b/sound/soc/kirkwood/kirkwood-dma.c
new file mode 100644
index 00000000000..a30205be3e2
--- /dev/null
+++ b/sound/soc/kirkwood/kirkwood-dma.c
@@ -0,0 +1,383 @@
+/*
+ * kirkwood-dma.c
+ *
+ * (c) 2010 Arnaud Patard <apatard@mandriva.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/init.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/dma-mapping.h>
+#include <linux/mbus.h>
+#include <sound/soc.h>
+#include "kirkwood-dma.h"
+#include "kirkwood.h"
+
+#define KIRKWOOD_RATES \
+ (SNDRV_PCM_RATE_44100 | \
+ SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000)
+#define KIRKWOOD_FORMATS \
+ (SNDRV_PCM_FMTBIT_S16_LE | \
+ SNDRV_PCM_FMTBIT_S24_LE | \
+ SNDRV_PCM_FMTBIT_S32_LE)
+
+struct kirkwood_dma_priv {
+ struct snd_pcm_substream *play_stream;
+ struct snd_pcm_substream *rec_stream;
+ struct kirkwood_dma_data *data;
+};
+
+static struct snd_pcm_hardware kirkwood_dma_snd_hw = {
+ .info = (SNDRV_PCM_INFO_INTERLEAVED |
+ SNDRV_PCM_INFO_MMAP |
+ SNDRV_PCM_INFO_MMAP_VALID |
+ SNDRV_PCM_INFO_BLOCK_TRANSFER |
+ SNDRV_PCM_INFO_PAUSE),
+ .formats = KIRKWOOD_FORMATS,
+ .rates = KIRKWOOD_RATES,
+ .rate_min = 44100,
+ .rate_max = 96000,
+ .channels_min = 1,
+ .channels_max = 2,
+ .buffer_bytes_max = KIRKWOOD_SND_MAX_PERIOD_BYTES * KIRKWOOD_SND_MAX_PERIODS,
+ .period_bytes_min = KIRKWOOD_SND_MIN_PERIOD_BYTES,
+ .period_bytes_max = KIRKWOOD_SND_MAX_PERIOD_BYTES,
+ .periods_min = KIRKWOOD_SND_MIN_PERIODS,
+ .periods_max = KIRKWOOD_SND_MAX_PERIODS,
+ .fifo_size = 0,
+};
+
+static u64 kirkwood_dma_dmamask = 0xFFFFFFFFUL;
+
+static irqreturn_t kirkwood_dma_irq(int irq, void *dev_id)
+{
+ struct kirkwood_dma_priv *prdata = dev_id;
+ struct kirkwood_dma_data *priv = prdata->data;
+ unsigned long mask, status, cause;
+
+ mask = readl(priv->io + KIRKWOOD_INT_MASK);
+ status = readl(priv->io + KIRKWOOD_INT_CAUSE) & mask;
+
+ cause = readl(priv->io + KIRKWOOD_ERR_CAUSE);
+ if (unlikely(cause)) {
+ printk(KERN_WARNING "%s: got err interrupt 0x%lx\n",
+ __func__, cause);
+ writel(cause, priv->io + KIRKWOOD_ERR_CAUSE);
+ return IRQ_HANDLED;
+ }
+
+ /* we've enabled only bytes interrupts ... */
+ if (status & ~(KIRKWOOD_INT_CAUSE_PLAY_BYTES | \
+ KIRKWOOD_INT_CAUSE_REC_BYTES)) {
+ printk(KERN_WARNING "%s: unexpected interrupt %lx\n",
+ __func__, status);
+ return IRQ_NONE;
+ }
+
+ /* ack int */
+ writel(status, priv->io + KIRKWOOD_INT_CAUSE);
+
+ if (status & KIRKWOOD_INT_CAUSE_PLAY_BYTES)
+ snd_pcm_period_elapsed(prdata->play_stream);
+
+ if (status & KIRKWOOD_INT_CAUSE_REC_BYTES)
+ snd_pcm_period_elapsed(prdata->rec_stream);
+
+ return IRQ_HANDLED;
+}
+
+static void kirkwood_dma_conf_mbus_windows(void __iomem *base, int win,
+ unsigned long dma,
+ struct mbus_dram_target_info *dram)
+{
+ int i;
+
+ /* First disable and clear windows */
+ writel(0, base + KIRKWOOD_AUDIO_WIN_CTRL_REG(win));
+ writel(0, base + KIRKWOOD_AUDIO_WIN_BASE_REG(win));
+
+ /* try to find matching cs for current dma address */
+ for (i = 0; i < dram->num_cs; i++) {
+ struct mbus_dram_window *cs = dram->cs + i;
+ if ((cs->base & 0xffff0000) < (dma & 0xffff0000)) {
+ writel(cs->base & 0xffff0000,
+ base + KIRKWOOD_AUDIO_WIN_BASE_REG(win));
+ writel(((cs->size - 1) & 0xffff0000) |
+ (cs->mbus_attr << 8) |
+ (dram->mbus_dram_target_id << 4) | 1,
+ base + KIRKWOOD_AUDIO_WIN_CTRL_REG(win));
+ }
+ }
+}
+
+static int kirkwood_dma_open(struct snd_pcm_substream *substream)
+{
+ int err;
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
+ struct snd_soc_dai *cpu_dai = soc_runtime->dai->cpu_dai;
+ struct kirkwood_dma_data *priv;
+ struct kirkwood_dma_priv *prdata = cpu_dai->private_data;
+ unsigned long addr;
+
+ priv = snd_soc_dai_get_dma_data(cpu_dai, substream);
+ snd_soc_set_runtime_hwparams(substream, &kirkwood_dma_snd_hw);
+
+ /* Ensure that all constraints linked to dma burst are fullfilled */
+ err = snd_pcm_hw_constraint_minmax(runtime,
+ SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
+ priv->burst * 2,
+ KIRKWOOD_AUDIO_BUF_MAX-1);
+ if (err < 0)
+ return err;
+
+ err = snd_pcm_hw_constraint_step(runtime, 0,
+ SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
+ priv->burst);
+ if (err < 0)
+ return err;
+
+ err = snd_pcm_hw_constraint_step(substream->runtime, 0,
+ SNDRV_PCM_HW_PARAM_PERIOD_BYTES,
+ priv->burst);
+ if (err < 0)
+ return err;
+
+ if (soc_runtime->dai->cpu_dai->private_data == NULL) {
+ prdata = kzalloc(sizeof(struct kirkwood_dma_priv), GFP_KERNEL);
+ if (prdata == NULL)
+ return -ENOMEM;
+
+ prdata->data = priv;
+
+ err = request_irq(priv->irq, kirkwood_dma_irq, IRQF_SHARED,
+ "kirkwood-i2s", prdata);
+ if (err) {
+ kfree(prdata);
+ return -EBUSY;
+ }
+
+ soc_runtime->dai->cpu_dai->private_data = prdata;
+
+ /*
+ * Enable Error interrupts. We're only ack'ing them but
+ * it's usefull for diagnostics
+ */
+ writel((unsigned long)-1, priv->io + KIRKWOOD_ERR_MASK);
+ }
+
+ addr = virt_to_phys(substream->dma_buffer.area);
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ prdata->play_stream = substream;
+ kirkwood_dma_conf_mbus_windows(priv->io,
+ KIRKWOOD_PLAYBACK_WIN, addr, priv->dram);
+ } else {
+ prdata->rec_stream = substream;
+ kirkwood_dma_conf_mbus_windows(priv->io,
+ KIRKWOOD_RECORD_WIN, addr, priv->dram);
+ }
+
+ return 0;
+}
+
+static int kirkwood_dma_close(struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
+ struct snd_soc_dai *cpu_dai = soc_runtime->dai->cpu_dai;
+ struct kirkwood_dma_priv *prdata = cpu_dai->private_data;
+ struct kirkwood_dma_data *priv;
+
+ priv = snd_soc_dai_get_dma_data(cpu_dai, substream);
+
+ if (!prdata || !priv)
+ return 0;
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ prdata->play_stream = NULL;
+ else
+ prdata->rec_stream = NULL;
+
+ if (!prdata->play_stream && !prdata->rec_stream) {
+ writel(0, priv->io + KIRKWOOD_ERR_MASK);
+ free_irq(priv->irq, prdata);
+ kfree(prdata);
+ soc_runtime->dai->cpu_dai->private_data = NULL;
+ }
+
+ return 0;
+}
+
+static int kirkwood_dma_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+
+ snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
+ runtime->dma_bytes = params_buffer_bytes(params);
+
+ return 0;
+}
+
+static int kirkwood_dma_hw_free(struct snd_pcm_substream *substream)
+{
+ snd_pcm_set_runtime_buffer(substream, NULL);
+ return 0;
+}
+
+static int kirkwood_dma_prepare(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
+ struct snd_soc_dai *cpu_dai = soc_runtime->dai->cpu_dai;
+ struct kirkwood_dma_data *priv;
+ unsigned long size, count;
+
+ priv = snd_soc_dai_get_dma_data(cpu_dai, substream);
+
+ /* compute buffer size in term of "words" as requested in specs */
+ size = frames_to_bytes(runtime, runtime->buffer_size);
+ size = (size>>2)-1;
+ count = snd_pcm_lib_period_bytes(substream);
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ writel(count, priv->io + KIRKWOOD_PLAY_BYTE_INT_COUNT);
+ writel(runtime->dma_addr, priv->io + KIRKWOOD_PLAY_BUF_ADDR);
+ writel(size, priv->io + KIRKWOOD_PLAY_BUF_SIZE);
+ } else {
+ writel(count, priv->io + KIRKWOOD_REC_BYTE_INT_COUNT);
+ writel(runtime->dma_addr, priv->io + KIRKWOOD_REC_BUF_ADDR);
+ writel(size, priv->io + KIRKWOOD_REC_BUF_SIZE);
+ }
+
+
+ return 0;
+}
+
+static snd_pcm_uframes_t kirkwood_dma_pointer(struct snd_pcm_substream
+ *substream)
+{
+ struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
+ struct snd_soc_dai *cpu_dai = soc_runtime->dai->cpu_dai;
+ struct kirkwood_dma_data *priv;
+ snd_pcm_uframes_t count;
+
+ priv = snd_soc_dai_get_dma_data(cpu_dai, substream);
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ count = bytes_to_frames(substream->runtime,
+ readl(priv->io + KIRKWOOD_PLAY_BYTE_COUNT));
+ else
+ count = bytes_to_frames(substream->runtime,
+ readl(priv->io + KIRKWOOD_REC_BYTE_COUNT));
+
+ return count;
+}
+
+struct snd_pcm_ops kirkwood_dma_ops = {
+ .open = kirkwood_dma_open,
+ .close = kirkwood_dma_close,
+ .ioctl = snd_pcm_lib_ioctl,
+ .hw_params = kirkwood_dma_hw_params,
+ .hw_free = kirkwood_dma_hw_free,
+ .prepare = kirkwood_dma_prepare,
+ .pointer = kirkwood_dma_pointer,
+};
+
+static int kirkwood_dma_preallocate_dma_buffer(struct snd_pcm *pcm,
+ int stream)
+{
+ struct snd_pcm_substream *substream = pcm->streams[stream].substream;
+ struct snd_dma_buffer *buf = &substream->dma_buffer;
+ size_t size = kirkwood_dma_snd_hw.buffer_bytes_max;
+
+ buf->dev.type = SNDRV_DMA_TYPE_DEV;
+ buf->dev.dev = pcm->card->dev;
+ buf->area = dma_alloc_coherent(pcm->card->dev, size,
+ &buf->addr, GFP_KERNEL);
+ if (!buf->area)
+ return -ENOMEM;
+ buf->bytes = size;
+ buf->private_data = NULL;
+
+ return 0;
+}
+
+static int kirkwood_dma_new(struct snd_card *card,
+ struct snd_soc_dai *dai, struct snd_pcm *pcm)
+{
+ int ret;
+
+ if (!card->dev->dma_mask)
+ card->dev->dma_mask = &kirkwood_dma_dmamask;
+ if (!card->dev->coherent_dma_mask)
+ card->dev->coherent_dma_mask = 0xffffffff;
+
+ if (dai->playback.channels_min) {
+ ret = kirkwood_dma_preallocate_dma_buffer(pcm,
+ SNDRV_PCM_STREAM_PLAYBACK);
+ if (ret)
+ return ret;
+ }
+
+ if (dai->capture.channels_min) {
+ ret = kirkwood_dma_preallocate_dma_buffer(pcm,
+ SNDRV_PCM_STREAM_CAPTURE);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static void kirkwood_dma_free_dma_buffers(struct snd_pcm *pcm)
+{
+ struct snd_pcm_substream *substream;
+ struct snd_dma_buffer *buf;
+ int stream;
+
+ for (stream = 0; stream < 2; stream++) {
+ substream = pcm->streams[stream].substream;
+ if (!substream)
+ continue;
+ buf = &substream->dma_buffer;
+ if (!buf->area)
+ continue;
+
+ dma_free_coherent(pcm->card->dev, buf->bytes,
+ buf->area, buf->addr);
+ buf->area = NULL;
+ }
+}
+
+struct snd_soc_platform kirkwood_soc_platform = {
+ .name = "kirkwood-dma",
+ .pcm_ops = &kirkwood_dma_ops,
+ .pcm_new = kirkwood_dma_new,
+ .pcm_free = kirkwood_dma_free_dma_buffers,
+};
+EXPORT_SYMBOL_GPL(kirkwood_soc_platform);
+
+static int __init kirkwood_soc_platform_init(void)
+{
+ return snd_soc_register_platform(&kirkwood_soc_platform);
+}
+module_init(kirkwood_soc_platform_init);
+
+static void __exit kirkwood_soc_platform_exit(void)
+{
+ snd_soc_unregister_platform(&kirkwood_soc_platform);
+}
+module_exit(kirkwood_soc_platform_exit);
+
+MODULE_AUTHOR("Arnaud Patard <apatard@mandriva.com>");
+MODULE_DESCRIPTION("Marvell Kirkwood Audio DMA module");
+MODULE_LICENSE("GPL");
+
diff --git a/sound/soc/kirkwood/kirkwood-dma.h b/sound/soc/kirkwood/kirkwood-dma.h
new file mode 100644
index 00000000000..ba4454cd34f
--- /dev/null
+++ b/sound/soc/kirkwood/kirkwood-dma.h
@@ -0,0 +1,17 @@
+/*
+ * kirkwood-dma.h
+ *
+ * (c) 2010 Arnaud Patard <apatard@mandriva.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 _KIRKWOOD_DMA_H
+#define _KIRKWOOD_DMA_H
+
+extern struct snd_soc_platform kirkwood_soc_platform;
+
+#endif
diff --git a/sound/soc/kirkwood/kirkwood-i2s.c b/sound/soc/kirkwood/kirkwood-i2s.c
new file mode 100644
index 00000000000..981ffc2a13c
--- /dev/null
+++ b/sound/soc/kirkwood/kirkwood-i2s.c
@@ -0,0 +1,495 @@
+/*
+ * kirkwood-i2s.c
+ *
+ * (c) 2010 Arnaud Patard <apatard@mandriva.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/init.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/mbus.h>
+#include <linux/delay.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <plat/audio.h>
+#include "kirkwood-i2s.h"
+#include "kirkwood.h"
+
+#define DRV_NAME "kirkwood-i2s"
+
+#define KIRKWOOD_I2S_RATES \
+ (SNDRV_PCM_RATE_44100 | \
+ SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000)
+#define KIRKWOOD_I2S_FORMATS \
+ (SNDRV_PCM_FMTBIT_S16_LE | \
+ SNDRV_PCM_FMTBIT_S24_LE | \
+ SNDRV_PCM_FMTBIT_S32_LE)
+
+
+struct snd_soc_dai kirkwood_i2s_dai;
+static struct kirkwood_dma_data *priv;
+
+static int kirkwood_i2s_set_fmt(struct snd_soc_dai *cpu_dai,
+ unsigned int fmt)
+{
+ unsigned long mask;
+ unsigned long value;
+
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_RIGHT_J:
+ mask = KIRKWOOD_I2S_CTL_RJ;
+ break;
+ case SND_SOC_DAIFMT_LEFT_J:
+ mask = KIRKWOOD_I2S_CTL_LJ;
+ break;
+ case SND_SOC_DAIFMT_I2S:
+ mask = KIRKWOOD_I2S_CTL_I2S;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /*
+ * Set same format for playback and record
+ * This avoids some troubles.
+ */
+ value = readl(priv->io+KIRKWOOD_I2S_PLAYCTL);
+ value &= ~KIRKWOOD_I2S_CTL_JUST_MASK;
+ value |= mask;
+ writel(value, priv->io+KIRKWOOD_I2S_PLAYCTL);
+
+ value = readl(priv->io+KIRKWOOD_I2S_RECCTL);
+ value &= ~KIRKWOOD_I2S_CTL_JUST_MASK;
+ value |= mask;
+ writel(value, priv->io+KIRKWOOD_I2S_RECCTL);
+
+ return 0;
+}
+
+static inline void kirkwood_set_dco(void __iomem *io, unsigned long rate)
+{
+ unsigned long value;
+
+ value = KIRKWOOD_DCO_CTL_OFFSET_0;
+ switch (rate) {
+ default:
+ case 44100:
+ value |= KIRKWOOD_DCO_CTL_FREQ_11;
+ break;
+ case 48000:
+ value |= KIRKWOOD_DCO_CTL_FREQ_12;
+ break;
+ case 96000:
+ value |= KIRKWOOD_DCO_CTL_FREQ_24;
+ break;
+ }
+ writel(value, io + KIRKWOOD_DCO_CTL);
+
+ /* wait for dco locked */
+ do {
+ cpu_relax();
+ value = readl(io + KIRKWOOD_DCO_SPCR_STATUS);
+ value &= KIRKWOOD_DCO_SPCR_STATUS;
+ } while (value == 0);
+}
+
+static int kirkwood_i2s_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ unsigned int i2s_reg, reg;
+ unsigned long i2s_value, value;
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ i2s_reg = KIRKWOOD_I2S_PLAYCTL;
+ reg = KIRKWOOD_PLAYCTL;
+ } else {
+ i2s_reg = KIRKWOOD_I2S_RECCTL;
+ reg = KIRKWOOD_RECCTL;
+ }
+
+ /* set dco conf */
+ kirkwood_set_dco(priv->io, params_rate(params));
+
+ i2s_value = readl(priv->io+i2s_reg);
+ i2s_value &= ~KIRKWOOD_I2S_CTL_SIZE_MASK;
+
+ value = readl(priv->io+reg);
+ value &= ~KIRKWOOD_PLAYCTL_SIZE_MASK;
+
+ /*
+ * Size settings in play/rec i2s control regs and play/rec control
+ * regs must be the same.
+ */
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_S16_LE:
+ i2s_value |= KIRKWOOD_I2S_CTL_SIZE_16;
+ value |= KIRKWOOD_PLAYCTL_SIZE_16_C;
+ break;
+ /*
+ * doesn't work... S20_3LE != kirkwood 20bit format ?
+ *
+ case SNDRV_PCM_FORMAT_S20_3LE:
+ i2s_value |= KIRKWOOD_I2S_CTL_SIZE_20;
+ value |= KIRKWOOD_PLAYCTL_SIZE_20;
+ break;
+ */
+ case SNDRV_PCM_FORMAT_S24_LE:
+ i2s_value |= KIRKWOOD_I2S_CTL_SIZE_24;
+ value |= KIRKWOOD_PLAYCTL_SIZE_24;
+ break;
+ case SNDRV_PCM_FORMAT_S32_LE:
+ i2s_value |= KIRKWOOD_I2S_CTL_SIZE_32;
+ value |= KIRKWOOD_PLAYCTL_SIZE_32;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ value &= ~KIRKWOOD_PLAYCTL_MONO_MASK;
+ if (params_channels(params) == 1)
+ value |= KIRKWOOD_PLAYCTL_MONO_BOTH;
+ else
+ value |= KIRKWOOD_PLAYCTL_MONO_OFF;
+ }
+
+ writel(i2s_value, priv->io+i2s_reg);
+ writel(value, priv->io+reg);
+
+ return 0;
+}
+
+static int kirkwood_i2s_play_trigger(struct snd_pcm_substream *substream,
+ int cmd, struct snd_soc_dai *dai)
+{
+ unsigned long value;
+
+ /*
+ * specs says KIRKWOOD_PLAYCTL must be read 2 times before
+ * changing it. So read 1 time here and 1 later.
+ */
+ value = readl(priv->io + KIRKWOOD_PLAYCTL);
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ /* stop audio, enable interrupts */
+ value = readl(priv->io + KIRKWOOD_PLAYCTL);
+ value |= KIRKWOOD_PLAYCTL_PAUSE;
+ writel(value, priv->io + KIRKWOOD_PLAYCTL);
+
+ value = readl(priv->io + KIRKWOOD_INT_MASK);
+ value |= KIRKWOOD_INT_CAUSE_PLAY_BYTES;
+ writel(value, priv->io + KIRKWOOD_INT_MASK);
+
+ /* configure audio & enable i2s playback */
+ value = readl(priv->io + KIRKWOOD_PLAYCTL);
+ value &= ~KIRKWOOD_PLAYCTL_BURST_MASK;
+ value &= ~(KIRKWOOD_PLAYCTL_PAUSE | KIRKWOOD_PLAYCTL_I2S_MUTE
+ | KIRKWOOD_PLAYCTL_SPDIF_EN);
+
+ if (priv->burst == 32)
+ value |= KIRKWOOD_PLAYCTL_BURST_32;
+ else
+ value |= KIRKWOOD_PLAYCTL_BURST_128;
+ value |= KIRKWOOD_PLAYCTL_I2S_EN;
+ writel(value, priv->io + KIRKWOOD_PLAYCTL);
+ break;
+
+ case SNDRV_PCM_TRIGGER_STOP:
+ /* stop audio, disable interrupts */
+ value = readl(priv->io + KIRKWOOD_PLAYCTL);
+ value |= KIRKWOOD_PLAYCTL_PAUSE | KIRKWOOD_PLAYCTL_I2S_MUTE;
+ writel(value, priv->io + KIRKWOOD_PLAYCTL);
+
+ value = readl(priv->io + KIRKWOOD_INT_MASK);
+ value &= ~KIRKWOOD_INT_CAUSE_PLAY_BYTES;
+ writel(value, priv->io + KIRKWOOD_INT_MASK);
+
+ /* disable all playbacks */
+ value = readl(priv->io + KIRKWOOD_PLAYCTL);
+ value &= ~(KIRKWOOD_PLAYCTL_I2S_EN | KIRKWOOD_PLAYCTL_SPDIF_EN);
+ writel(value, priv->io + KIRKWOOD_PLAYCTL);
+ break;
+
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ value = readl(priv->io + KIRKWOOD_PLAYCTL);
+ value |= KIRKWOOD_PLAYCTL_PAUSE | KIRKWOOD_PLAYCTL_I2S_MUTE;
+ writel(value, priv->io + KIRKWOOD_PLAYCTL);
+ break;
+
+ case SNDRV_PCM_TRIGGER_RESUME:
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ value = readl(priv->io + KIRKWOOD_PLAYCTL);
+ value &= ~(KIRKWOOD_PLAYCTL_PAUSE | KIRKWOOD_PLAYCTL_I2S_MUTE);
+ writel(value, priv->io + KIRKWOOD_PLAYCTL);
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int kirkwood_i2s_rec_trigger(struct snd_pcm_substream *substream,
+ int cmd, struct snd_soc_dai *dai)
+{
+ unsigned long value;
+
+ value = readl(priv->io + KIRKWOOD_RECCTL);
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ /* stop audio, enable interrupts */
+ value = readl(priv->io + KIRKWOOD_RECCTL);
+ value |= KIRKWOOD_RECCTL_PAUSE;
+ writel(value, priv->io + KIRKWOOD_RECCTL);
+
+ value = readl(priv->io + KIRKWOOD_INT_MASK);
+ value |= KIRKWOOD_INT_CAUSE_REC_BYTES;
+ writel(value, priv->io + KIRKWOOD_INT_MASK);
+
+ /* configure audio & enable i2s record */
+ value = readl(priv->io + KIRKWOOD_RECCTL);
+ value &= ~KIRKWOOD_RECCTL_BURST_MASK;
+ value &= ~KIRKWOOD_RECCTL_MONO;
+ value &= ~(KIRKWOOD_RECCTL_PAUSE | KIRKWOOD_RECCTL_MUTE
+ | KIRKWOOD_RECCTL_SPDIF_EN);
+
+ if (priv->burst == 32)
+ value |= KIRKWOOD_RECCTL_BURST_32;
+ else
+ value |= KIRKWOOD_RECCTL_BURST_128;
+ value |= KIRKWOOD_RECCTL_I2S_EN;
+
+ writel(value, priv->io + KIRKWOOD_RECCTL);
+ break;
+
+ case SNDRV_PCM_TRIGGER_STOP:
+ /* stop audio, disable interrupts */
+ value = readl(priv->io + KIRKWOOD_RECCTL);
+ value |= KIRKWOOD_RECCTL_PAUSE | KIRKWOOD_RECCTL_MUTE;
+ writel(value, priv->io + KIRKWOOD_RECCTL);
+
+ value = readl(priv->io + KIRKWOOD_INT_MASK);
+ value &= ~KIRKWOOD_INT_CAUSE_REC_BYTES;
+ writel(value, priv->io + KIRKWOOD_INT_MASK);
+
+ /* disable all records */
+ value = readl(priv->io + KIRKWOOD_RECCTL);
+ value &= ~(KIRKWOOD_RECCTL_I2S_EN | KIRKWOOD_RECCTL_SPDIF_EN);
+ writel(value, priv->io + KIRKWOOD_RECCTL);
+ break;
+
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ value = readl(priv->io + KIRKWOOD_RECCTL);
+ value |= KIRKWOOD_RECCTL_PAUSE | KIRKWOOD_RECCTL_MUTE;
+ writel(value, priv->io + KIRKWOOD_RECCTL);
+ break;
+
+ case SNDRV_PCM_TRIGGER_RESUME:
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ value = readl(priv->io + KIRKWOOD_RECCTL);
+ value &= ~(KIRKWOOD_RECCTL_PAUSE | KIRKWOOD_RECCTL_MUTE);
+ writel(value, priv->io + KIRKWOOD_RECCTL);
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int kirkwood_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
+ struct snd_soc_dai *dai)
+{
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ return kirkwood_i2s_play_trigger(substream, cmd, dai);
+ else
+ return kirkwood_i2s_rec_trigger(substream, cmd, dai);
+
+ return 0;
+}
+
+static int kirkwood_i2s_probe(struct platform_device *pdev,
+ struct snd_soc_dai *dai)
+{
+ unsigned long value;
+ unsigned int reg_data;
+
+ /* put system in a "safe" state : */
+ /* disable audio interrupts */
+ writel(0xffffffff, priv->io + KIRKWOOD_INT_CAUSE);
+ writel(0, priv->io + KIRKWOOD_INT_MASK);
+
+ reg_data = readl(priv->io + 0x1200);
+ reg_data &= (~(0x333FF8));
+ reg_data |= 0x111D18;
+ writel(reg_data, priv->io + 0x1200);
+
+ msleep(500);
+
+ reg_data = readl(priv->io + 0x1200);
+ reg_data &= (~(0x333FF8));
+ reg_data |= 0x111D18;
+ writel(reg_data, priv->io + 0x1200);
+
+ /* disable playback/record */
+ value = readl(priv->io + KIRKWOOD_PLAYCTL);
+ value &= ~(KIRKWOOD_PLAYCTL_I2S_EN|KIRKWOOD_PLAYCTL_SPDIF_EN);
+ writel(value, priv->io + KIRKWOOD_PLAYCTL);
+
+ value = readl(priv->io + KIRKWOOD_RECCTL);
+ value &= ~(KIRKWOOD_RECCTL_I2S_EN | KIRKWOOD_RECCTL_SPDIF_EN);
+ writel(value, priv->io + KIRKWOOD_RECCTL);
+
+ return 0;
+
+}
+
+static void kirkwood_i2s_remove(struct platform_device *pdev,
+ struct snd_soc_dai *dai)
+{
+}
+
+static struct snd_soc_dai_ops kirkwood_i2s_dai_ops = {
+ .trigger = kirkwood_i2s_trigger,
+ .hw_params = kirkwood_i2s_hw_params,
+ .set_fmt = kirkwood_i2s_set_fmt,
+};
+
+
+struct snd_soc_dai kirkwood_i2s_dai = {
+ .name = DRV_NAME,
+ .id = 0,
+ .probe = kirkwood_i2s_probe,
+ .remove = kirkwood_i2s_remove,
+ .playback = {
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = KIRKWOOD_I2S_RATES,
+ .formats = KIRKWOOD_I2S_FORMATS,},
+ .capture = {
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = KIRKWOOD_I2S_RATES,
+ .formats = KIRKWOOD_I2S_FORMATS,},
+ .ops = &kirkwood_i2s_dai_ops,
+};
+EXPORT_SYMBOL_GPL(kirkwood_i2s_dai);
+
+static __devinit int kirkwood_i2s_dev_probe(struct platform_device *pdev)
+{
+ struct resource *mem;
+ struct kirkwood_asoc_platform_data *data =
+ pdev->dev.platform_data;
+ int err;
+
+ priv = kzalloc(sizeof(struct kirkwood_dma_data), GFP_KERNEL);
+ if (!priv) {
+ dev_err(&pdev->dev, "allocation failed\n");
+ err = -ENOMEM;
+ goto error;
+ }
+
+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!mem) {
+ dev_err(&pdev->dev, "platform_get_resource failed\n");
+ err = -ENXIO;
+ goto err_alloc;
+ }
+
+ priv->mem = request_mem_region(mem->start, SZ_16K, DRV_NAME);
+ if (!priv->mem) {
+ dev_err(&pdev->dev, "request_mem_region failed\n");
+ err = -EBUSY;
+ goto error;
+ }
+
+ priv->io = ioremap(priv->mem->start, SZ_16K);
+ if (!priv->io) {
+ dev_err(&pdev->dev, "ioremap failed\n");
+ err = -ENOMEM;
+ goto err_iomem;
+ }
+
+ priv->irq = platform_get_irq(pdev, 0);
+ if (priv->irq <= 0) {
+ dev_err(&pdev->dev, "platform_get_irq failed\n");
+ err = -ENXIO;
+ goto err_ioremap;
+ }
+
+ if (!data || !data->dram) {
+ dev_err(&pdev->dev, "no platform data ?!\n");
+ err = -EINVAL;
+ goto err_ioremap;
+ }
+
+ priv->dram = data->dram;
+ priv->burst = data->burst;
+
+ kirkwood_i2s_dai.capture.dma_data = priv;
+ kirkwood_i2s_dai.playback.dma_data = priv;
+
+ return snd_soc_register_dai(&kirkwood_i2s_dai);
+
+err_ioremap:
+ iounmap(priv->io);
+err_iomem:
+ release_mem_region(priv->mem->start, SZ_16K);
+err_alloc:
+ kfree(priv);
+error:
+ return err;
+}
+
+static __devexit int kirkwood_i2s_dev_remove(struct platform_device *pdev)
+{
+ if (priv) {
+ iounmap(priv->io);
+ release_mem_region(priv->mem->start, SZ_16K);
+ kfree(priv);
+ }
+ snd_soc_unregister_dai(&kirkwood_i2s_dai);
+ return 0;
+}
+
+static struct platform_driver kirkwood_i2s_driver = {
+ .probe = kirkwood_i2s_dev_probe,
+ .remove = kirkwood_i2s_dev_remove,
+ .driver = {
+ .name = DRV_NAME,
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init kirkwood_i2s_init(void)
+{
+ return platform_driver_register(&kirkwood_i2s_driver);
+}
+module_init(kirkwood_i2s_init);
+
+static void __exit kirkwood_i2s_exit(void)
+{
+ platform_driver_unregister(&kirkwood_i2s_driver);
+}
+module_exit(kirkwood_i2s_exit);
+
+/* Module information */
+MODULE_AUTHOR("Arnaud Patard, <apatard@mandriva.com>");
+MODULE_DESCRIPTION("Kirkwood I2S SoC Interface");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:kirkwood-i2s");
diff --git a/sound/soc/kirkwood/kirkwood-i2s.h b/sound/soc/kirkwood/kirkwood-i2s.h
new file mode 100644
index 00000000000..c5595c616d7
--- /dev/null
+++ b/sound/soc/kirkwood/kirkwood-i2s.h
@@ -0,0 +1,17 @@
+/*
+ * kirkwood-i2s.h
+ *
+ * (c) 2010 Arnaud Patard <apatard@mandriva.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 _KIRKWOOD_I2S_H
+#define _KIRKWOOD_I2S_H
+
+extern struct snd_soc_dai kirkwood_i2s_dai;
+
+#endif
diff --git a/sound/soc/kirkwood/kirkwood-openrd.c b/sound/soc/kirkwood/kirkwood-openrd.c
new file mode 100644
index 00000000000..0353d06bc41
--- /dev/null
+++ b/sound/soc/kirkwood/kirkwood-openrd.c
@@ -0,0 +1,126 @@
+/*
+ * kirkwood-openrd.c
+ *
+ * (c) 2010 Arnaud Patard <apatard@mandriva.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <sound/soc.h>
+#include <mach/kirkwood.h>
+#include <plat/audio.h>
+#include <asm/mach-types.h>
+#include "kirkwood-i2s.h"
+#include "kirkwood-dma.h"
+#include "../codecs/cs42l51.h"
+
+static int openrd_client_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+ int ret;
+ unsigned int freq, fmt;
+
+ fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS;
+ ret = snd_soc_dai_set_fmt(cpu_dai, fmt);
+ if (ret < 0)
+ return ret;
+
+ ret = snd_soc_dai_set_fmt(codec_dai, fmt);
+ if (ret < 0)
+ return ret;
+
+ switch (params_rate(params)) {
+ default:
+ case 44100:
+ freq = 11289600;
+ break;
+ case 48000:
+ freq = 12288000;
+ break;
+ case 96000:
+ freq = 24576000;
+ break;
+ }
+
+ return snd_soc_dai_set_sysclk(codec_dai, 0, freq, SND_SOC_CLOCK_IN);
+
+}
+
+static struct snd_soc_ops openrd_client_ops = {
+ .hw_params = openrd_client_hw_params,
+};
+
+
+static struct snd_soc_dai_link openrd_client_dai[] = {
+{
+ .name = "CS42L51",
+ .stream_name = "CS42L51 HiFi",
+ .cpu_dai = &kirkwood_i2s_dai,
+ .codec_dai = &cs42l51_dai,
+ .ops = &openrd_client_ops,
+},
+};
+
+
+static struct snd_soc_card openrd_client = {
+ .name = "OpenRD Client",
+ .platform = &kirkwood_soc_platform,
+ .dai_link = openrd_client_dai,
+ .num_links = ARRAY_SIZE(openrd_client_dai),
+};
+
+static struct snd_soc_device openrd_client_snd_devdata = {
+ .card = &openrd_client,
+ .codec_dev = &soc_codec_device_cs42l51,
+};
+
+static struct platform_device *openrd_client_snd_device;
+
+static int __init openrd_client_init(void)
+{
+ int ret;
+
+ if (!machine_is_openrd_client())
+ return 0;
+
+ openrd_client_snd_device = platform_device_alloc("soc-audio", -1);
+ if (!openrd_client_snd_device)
+ return -ENOMEM;
+
+ platform_set_drvdata(openrd_client_snd_device,
+ &openrd_client_snd_devdata);
+ openrd_client_snd_devdata.dev = &openrd_client_snd_device->dev;
+
+ ret = platform_device_add(openrd_client_snd_device);
+ if (ret) {
+ printk(KERN_ERR "%s: platform_device_add failed\n", __func__);
+ platform_device_put(openrd_client_snd_device);
+ }
+
+ return ret;
+}
+
+static void __exit openrd_client_exit(void)
+{
+ platform_device_unregister(openrd_client_snd_device);
+}
+
+module_init(openrd_client_init);
+module_exit(openrd_client_exit);
+
+/* Module information */
+MODULE_AUTHOR("Arnaud Patard <apatard@mandriva.com>");
+MODULE_DESCRIPTION("ALSA SoC OpenRD Client");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:soc-audio");
diff --git a/sound/soc/kirkwood/kirkwood.h b/sound/soc/kirkwood/kirkwood.h
new file mode 100644
index 00000000000..bb6e6a5648c
--- /dev/null
+++ b/sound/soc/kirkwood/kirkwood.h
@@ -0,0 +1,129 @@
+/*
+ * kirkwood.h
+ *
+ * (c) 2010 Arnaud Patard <apatard@mandriva.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 _KIRKWOOD_AUDIO_H
+#define _KIRKWOOD_AUDIO_H
+
+#define KIRKWOOD_RECORD_WIN 0
+#define KIRKWOOD_PLAYBACK_WIN 1
+#define KIRKWOOD_MAX_AUDIO_WIN 2
+
+#define KIRKWOOD_AUDIO_WIN_BASE_REG(win) (0xA00 + ((win)<<3))
+#define KIRKWOOD_AUDIO_WIN_CTRL_REG(win) (0xA04 + ((win)<<3))
+
+
+#define KIRKWOOD_RECCTL 0x1000
+#define KIRKWOOD_RECCTL_SPDIF_EN (1<<11)
+#define KIRKWOOD_RECCTL_I2S_EN (1<<10)
+#define KIRKWOOD_RECCTL_PAUSE (1<<9)
+#define KIRKWOOD_RECCTL_MUTE (1<<8)
+#define KIRKWOOD_RECCTL_BURST_MASK (3<<5)
+#define KIRKWOOD_RECCTL_BURST_128 (2<<5)
+#define KIRKWOOD_RECCTL_BURST_32 (1<<5)
+#define KIRKWOOD_RECCTL_MONO (1<<4)
+#define KIRKWOOD_RECCTL_MONO_CHAN_RIGHT (1<<3)
+#define KIRKWOOD_RECCTL_MONO_CHAN_LEFT (0<<3)
+#define KIRKWOOD_RECCTL_SIZE_MASK (7<<0)
+#define KIRKWOOD_RECCTL_SIZE_16 (7<<0)
+#define KIRKWOOD_RECCTL_SIZE_16_C (3<<0)
+#define KIRKWOOD_RECCTL_SIZE_20 (2<<0)
+#define KIRKWOOD_RECCTL_SIZE_24 (1<<0)
+#define KIRKWOOD_RECCTL_SIZE_32 (0<<0)
+
+#define KIRKWOOD_REC_BUF_ADDR 0x1004
+#define KIRKWOOD_REC_BUF_SIZE 0x1008
+#define KIRKWOOD_REC_BYTE_COUNT 0x100C
+
+#define KIRKWOOD_PLAYCTL 0x1100
+#define KIRKWOOD_PLAYCTL_PLAY_BUSY (1<<16)
+#define KIRKWOOD_PLAYCTL_BURST_MASK (3<<11)
+#define KIRKWOOD_PLAYCTL_BURST_128 (2<<11)
+#define KIRKWOOD_PLAYCTL_BURST_32 (1<<11)
+#define KIRKWOOD_PLAYCTL_PAUSE (1<<9)
+#define KIRKWOOD_PLAYCTL_SPDIF_MUTE (1<<8)
+#define KIRKWOOD_PLAYCTL_MONO_MASK (3<<5)
+#define KIRKWOOD_PLAYCTL_MONO_BOTH (3<<5)
+#define KIRKWOOD_PLAYCTL_MONO_OFF (0<<5)
+#define KIRKWOOD_PLAYCTL_I2S_MUTE (1<<7)
+#define KIRKWOOD_PLAYCTL_SPDIF_EN (1<<4)
+#define KIRKWOOD_PLAYCTL_I2S_EN (1<<3)
+#define KIRKWOOD_PLAYCTL_SIZE_MASK (7<<0)
+#define KIRKWOOD_PLAYCTL_SIZE_16 (7<<0)
+#define KIRKWOOD_PLAYCTL_SIZE_16_C (3<<0)
+#define KIRKWOOD_PLAYCTL_SIZE_20 (2<<0)
+#define KIRKWOOD_PLAYCTL_SIZE_24 (1<<0)
+#define KIRKWOOD_PLAYCTL_SIZE_32 (0<<0)
+
+#define KIRKWOOD_PLAY_BUF_ADDR 0x1104
+#define KIRKWOOD_PLAY_BUF_SIZE 0x1108
+#define KIRKWOOD_PLAY_BYTE_COUNT 0x110C
+
+#define KIRKWOOD_DCO_CTL 0x1204
+#define KIRKWOOD_DCO_CTL_OFFSET_MASK (0xFFF<<2)
+#define KIRKWOOD_DCO_CTL_OFFSET_0 (0x800<<2)
+#define KIRKWOOD_DCO_CTL_FREQ_MASK (3<<0)
+#define KIRKWOOD_DCO_CTL_FREQ_11 (0<<0)
+#define KIRKWOOD_DCO_CTL_FREQ_12 (1<<0)
+#define KIRKWOOD_DCO_CTL_FREQ_24 (2<<0)
+
+#define KIRKWOOD_DCO_SPCR_STATUS 0x120c
+#define KIRKWOOD_DCO_SPCR_STATUS_DCO_LOCK (1<<16)
+
+#define KIRKWOOD_ERR_CAUSE 0x1300
+#define KIRKWOOD_ERR_MASK 0x1304
+
+#define KIRKWOOD_INT_CAUSE 0x1308
+#define KIRKWOOD_INT_MASK 0x130C
+#define KIRKWOOD_INT_CAUSE_PLAY_BYTES (1<<14)
+#define KIRKWOOD_INT_CAUSE_REC_BYTES (1<<13)
+#define KIRKWOOD_INT_CAUSE_DMA_PLAY_END (1<<7)
+#define KIRKWOOD_INT_CAUSE_DMA_PLAY_3Q (1<<6)
+#define KIRKWOOD_INT_CAUSE_DMA_PLAY_HALF (1<<5)
+#define KIRKWOOD_INT_CAUSE_DMA_PLAY_1Q (1<<4)
+#define KIRKWOOD_INT_CAUSE_DMA_REC_END (1<<3)
+#define KIRKWOOD_INT_CAUSE_DMA_REC_3Q (1<<2)
+#define KIRKWOOD_INT_CAUSE_DMA_REC_HALF (1<<1)
+#define KIRKWOOD_INT_CAUSE_DMA_REC_1Q (1<<0)
+
+#define KIRKWOOD_REC_BYTE_INT_COUNT 0x1310
+#define KIRKWOOD_PLAY_BYTE_INT_COUNT 0x1314
+#define KIRKWOOD_BYTE_INT_COUNT_MASK 0xffffff
+
+#define KIRKWOOD_I2S_PLAYCTL 0x2508
+#define KIRKWOOD_I2S_RECCTL 0x2408
+#define KIRKWOOD_I2S_CTL_JUST_MASK (0xf<<26)
+#define KIRKWOOD_I2S_CTL_LJ (0<<26)
+#define KIRKWOOD_I2S_CTL_I2S (5<<26)
+#define KIRKWOOD_I2S_CTL_RJ (8<<26)
+#define KIRKWOOD_I2S_CTL_SIZE_MASK (3<<30)
+#define KIRKWOOD_I2S_CTL_SIZE_16 (3<<30)
+#define KIRKWOOD_I2S_CTL_SIZE_20 (2<<30)
+#define KIRKWOOD_I2S_CTL_SIZE_24 (1<<30)
+#define KIRKWOOD_I2S_CTL_SIZE_32 (0<<30)
+
+#define KIRKWOOD_AUDIO_BUF_MAX (16*1024*1024)
+
+/* Theses values come from the marvell alsa driver */
+/* need to find where they come from */
+#define KIRKWOOD_SND_MIN_PERIODS 8
+#define KIRKWOOD_SND_MAX_PERIODS 16
+#define KIRKWOOD_SND_MIN_PERIOD_BYTES 0x4000
+#define KIRKWOOD_SND_MAX_PERIOD_BYTES 0x4000
+
+struct kirkwood_dma_data {
+ struct resource *mem;
+ void __iomem *io;
+ int irq;
+ int burst;
+ struct mbus_dram_target_info *dram;
+};
+
+#endif
diff --git a/sound/soc/nuc900/Kconfig b/sound/soc/nuc900/Kconfig
new file mode 100644
index 00000000000..a0ed1c618f6
--- /dev/null
+++ b/sound/soc/nuc900/Kconfig
@@ -0,0 +1,27 @@
+##
+## NUC900 series AC97 API
+##
+config SND_SOC_NUC900
+ tristate "SoC Audio for NUC900 series"
+ depends on ARCH_W90X900
+ help
+ This option enables support for AC97 mode on the NUC900 SoC.
+
+config SND_SOC_NUC900_AC97
+ tristate
+ select AC97_BUS
+ select SND_AC97_CODEC
+ select SND_SOC_AC97_BUS
+
+
+##
+## Boards
+##
+config SND_SOC_NUC900EVB
+ tristate "NUC900 AC97 support for demo board"
+ depends on SND_SOC_NUC900
+ select SND_SOC_NUC900_AC97
+ select SND_SOC_AC97_CODEC
+ help
+ Select this option to enable audio (AC97) on the
+ NUC900 demoboard.
diff --git a/sound/soc/nuc900/Makefile b/sound/soc/nuc900/Makefile
new file mode 100644
index 00000000000..7e46c715031
--- /dev/null
+++ b/sound/soc/nuc900/Makefile
@@ -0,0 +1,11 @@
+# NUC900 series audio
+snd-soc-nuc900-pcm-objs := nuc900-pcm.o
+snd-soc-nuc900-ac97-objs := nuc900-ac97.o
+
+obj-$(CONFIG_SND_SOC_NUC900) += snd-soc-nuc900-pcm.o
+obj-$(CONFIG_SND_SOC_NUC900_AC97) += snd-soc-nuc900-ac97.o
+
+# Boards
+snd-soc-nuc900-audio-objs := nuc900-audio.o
+
+obj-$(CONFIG_SND_SOC_NUC900EVB) += snd-soc-nuc900-audio.o
diff --git a/sound/soc/nuc900/nuc900-ac97.c b/sound/soc/nuc900/nuc900-ac97.c
new file mode 100644
index 00000000000..caa7c901bc2
--- /dev/null
+++ b/sound/soc/nuc900/nuc900-ac97.c
@@ -0,0 +1,430 @@
+/*
+ * Copyright (c) 2009-2010 Nuvoton technology corporation.
+ *
+ * Wan ZongShun <mcuos.com@gmail.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.
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/mutex.h>
+#include <linux/suspend.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/initval.h>
+#include <sound/soc.h>
+#include <linux/device.h>
+#include <linux/clk.h>
+
+#include <mach/mfp.h>
+
+#include "nuc900-audio.h"
+
+static DEFINE_MUTEX(ac97_mutex);
+struct nuc900_audio *nuc900_ac97_data;
+
+static int nuc900_checkready(void)
+{
+ struct nuc900_audio *nuc900_audio = nuc900_ac97_data;
+
+ if (!(AUDIO_READ(nuc900_audio->mmio + ACTL_ACIS0) & CODEC_READY))
+ return -EPERM;
+
+ return 0;
+}
+
+/* AC97 controller reads codec register */
+static unsigned short nuc900_ac97_read(struct snd_ac97 *ac97,
+ unsigned short reg)
+{
+ struct nuc900_audio *nuc900_audio = nuc900_ac97_data;
+ unsigned long timeout = 0x10000, val;
+
+ mutex_lock(&ac97_mutex);
+
+ val = nuc900_checkready();
+ if (!!val) {
+ dev_err(nuc900_audio->dev, "AC97 codec is not ready\n");
+ goto out;
+ }
+
+ /* set the R_WB bit and write register index */
+ AUDIO_WRITE(nuc900_audio->mmio + ACTL_ACOS1, R_WB | reg);
+
+ /* set the valid frame bit and valid slots */
+ val = AUDIO_READ(nuc900_audio->mmio + ACTL_ACOS0);
+ val |= (VALID_FRAME | SLOT1_VALID);
+ AUDIO_WRITE(nuc900_audio->mmio + ACTL_ACOS0, val);
+
+ udelay(100);
+
+ /* polling the AC_R_FINISH */
+ while (!(AUDIO_READ(nuc900_audio->mmio + ACTL_ACCON) & AC_R_FINISH)
+ && timeout--)
+ mdelay(1);
+
+ if (!timeout) {
+ dev_err(nuc900_audio->dev, "AC97 read register time out !\n");
+ val = -EPERM;
+ goto out;
+ }
+
+ val = AUDIO_READ(nuc900_audio->mmio + ACTL_ACOS0) ;
+ val &= ~SLOT1_VALID;
+ AUDIO_WRITE(nuc900_audio->mmio + ACTL_ACOS0, val);
+
+ if (AUDIO_READ(nuc900_audio->mmio + ACTL_ACIS1) >> 2 != reg) {
+ dev_err(nuc900_audio->dev,
+ "R_INDEX of REG_ACTL_ACIS1 not match!\n");
+ }
+
+ udelay(100);
+ val = (AUDIO_READ(nuc900_audio->mmio + ACTL_ACIS2) & 0xFFFF);
+
+out:
+ mutex_unlock(&ac97_mutex);
+ return val;
+}
+
+/* AC97 controller writes to codec register */
+static void nuc900_ac97_write(struct snd_ac97 *ac97, unsigned short reg,
+ unsigned short val)
+{
+ struct nuc900_audio *nuc900_audio = nuc900_ac97_data;
+ unsigned long tmp, timeout = 0x10000;
+
+ mutex_lock(&ac97_mutex);
+
+ tmp = nuc900_checkready();
+ if (!!tmp)
+ dev_err(nuc900_audio->dev, "AC97 codec is not ready\n");
+
+ /* clear the R_WB bit and write register index */
+ AUDIO_WRITE(nuc900_audio->mmio + ACTL_ACOS1, reg);
+
+ /* write register value */
+ AUDIO_WRITE(nuc900_audio->mmio + ACTL_ACOS2, val);
+
+ /* set the valid frame bit and valid slots */
+ tmp = AUDIO_READ(nuc900_audio->mmio + ACTL_ACOS0);
+ tmp |= SLOT1_VALID | SLOT2_VALID | VALID_FRAME;
+ AUDIO_WRITE(nuc900_audio->mmio + ACTL_ACOS0, tmp);
+
+ udelay(100);
+
+ /* polling the AC_W_FINISH */
+ while ((AUDIO_READ(nuc900_audio->mmio + ACTL_ACCON) & AC_W_FINISH)
+ && timeout--)
+ mdelay(1);
+
+ if (!timeout)
+ dev_err(nuc900_audio->dev, "AC97 write register time out !\n");
+
+ tmp = AUDIO_READ(nuc900_audio->mmio + ACTL_ACOS0);
+ tmp &= ~(SLOT1_VALID | SLOT2_VALID);
+ AUDIO_WRITE(nuc900_audio->mmio + ACTL_ACOS0, tmp);
+
+ mutex_unlock(&ac97_mutex);
+
+}
+
+static void nuc900_ac97_warm_reset(struct snd_ac97 *ac97)
+{
+ struct nuc900_audio *nuc900_audio = nuc900_ac97_data;
+ unsigned long val;
+
+ mutex_lock(&ac97_mutex);
+
+ /* warm reset AC 97 */
+ val = AUDIO_READ(nuc900_audio->mmio + ACTL_ACCON);
+ val |= AC_W_RES;
+ AUDIO_WRITE(nuc900_audio->mmio + ACTL_ACCON, val);
+
+ udelay(100);
+
+ val = nuc900_checkready();
+ if (!!val)
+ dev_err(nuc900_audio->dev, "AC97 codec is not ready\n");
+
+ mutex_unlock(&ac97_mutex);
+}
+
+static void nuc900_ac97_cold_reset(struct snd_ac97 *ac97)
+{
+ struct nuc900_audio *nuc900_audio = nuc900_ac97_data;
+ unsigned long val;
+
+ mutex_lock(&ac97_mutex);
+
+ /* reset Audio Controller */
+ val = AUDIO_READ(nuc900_audio->mmio + ACTL_RESET);
+ val |= ACTL_RESET_BIT;
+ AUDIO_WRITE(nuc900_audio->mmio + ACTL_RESET, val);
+
+ val = AUDIO_READ(nuc900_audio->mmio + ACTL_RESET);
+ val &= (~ACTL_RESET_BIT);
+ AUDIO_WRITE(nuc900_audio->mmio + ACTL_RESET, val);
+
+ /* reset AC-link interface */
+
+ val = AUDIO_READ(nuc900_audio->mmio + ACTL_RESET);
+ val |= AC_RESET;
+ AUDIO_WRITE(nuc900_audio->mmio + ACTL_RESET, val);
+
+ val = AUDIO_READ(nuc900_audio->mmio + ACTL_RESET);
+ val &= ~AC_RESET;
+ AUDIO_WRITE(nuc900_audio->mmio + ACTL_RESET, val);
+
+ /* cold reset AC 97 */
+ val = AUDIO_READ(nuc900_audio->mmio + ACTL_ACCON);
+ val |= AC_C_RES;
+ AUDIO_WRITE(nuc900_audio->mmio + ACTL_ACCON, val);
+
+ val = AUDIO_READ(nuc900_audio->mmio + ACTL_ACCON);
+ val &= (~AC_C_RES);
+ AUDIO_WRITE(nuc900_audio->mmio + ACTL_ACCON, val);
+
+ udelay(100);
+
+ mutex_unlock(&ac97_mutex);
+
+}
+
+/* AC97 controller operations */
+struct snd_ac97_bus_ops soc_ac97_ops = {
+ .read = nuc900_ac97_read,
+ .write = nuc900_ac97_write,
+ .reset = nuc900_ac97_cold_reset,
+ .warm_reset = nuc900_ac97_warm_reset,
+}
+EXPORT_SYMBOL_GPL(soc_ac97_ops);
+
+static int nuc900_ac97_trigger(struct snd_pcm_substream *substream,
+ int cmd, struct snd_soc_dai *dai)
+{
+ struct nuc900_audio *nuc900_audio = nuc900_ac97_data;
+ int ret;
+ unsigned long val, tmp;
+
+ ret = 0;
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_RESUME:
+ val = AUDIO_READ(nuc900_audio->mmio + ACTL_RESET);
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ tmp = AUDIO_READ(nuc900_audio->mmio + ACTL_ACOS0);
+ tmp |= (SLOT3_VALID | SLOT4_VALID | VALID_FRAME);
+ AUDIO_WRITE(nuc900_audio->mmio + ACTL_ACOS0, tmp);
+
+ tmp = AUDIO_READ(nuc900_audio->mmio + ACTL_PSR);
+ tmp |= (P_DMA_END_IRQ | P_DMA_MIDDLE_IRQ);
+ AUDIO_WRITE(nuc900_audio->mmio + ACTL_PSR, tmp);
+ val |= AC_PLAY;
+ } else {
+ tmp = AUDIO_READ(nuc900_audio->mmio + ACTL_RSR);
+ tmp |= (R_DMA_END_IRQ | R_DMA_MIDDLE_IRQ);
+
+ AUDIO_WRITE(nuc900_audio->mmio + ACTL_RSR, tmp);
+ val |= AC_RECORD;
+ }
+
+ AUDIO_WRITE(nuc900_audio->mmio + ACTL_RESET, val);
+
+ break;
+ case SNDRV_PCM_TRIGGER_STOP:
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ val = AUDIO_READ(nuc900_audio->mmio + ACTL_RESET);
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ tmp = AUDIO_READ(nuc900_audio->mmio + ACTL_ACOS0);
+ tmp &= ~(SLOT3_VALID | SLOT4_VALID);
+ AUDIO_WRITE(nuc900_audio->mmio + ACTL_ACOS0, tmp);
+
+ AUDIO_WRITE(nuc900_audio->mmio + ACTL_PSR, RESET_PRSR);
+ val &= ~AC_PLAY;
+ } else {
+ AUDIO_WRITE(nuc900_audio->mmio + ACTL_RSR, RESET_PRSR);
+ val &= ~AC_RECORD;
+ }
+
+ AUDIO_WRITE(nuc900_audio->mmio + ACTL_RESET, val);
+
+ break;
+ default:
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+static int nuc900_ac97_probe(struct platform_device *pdev,
+ struct snd_soc_dai *dai)
+{
+ struct nuc900_audio *nuc900_audio = nuc900_ac97_data;
+ unsigned long val;
+
+ mutex_lock(&ac97_mutex);
+
+ /* enable unit clock */
+ clk_enable(nuc900_audio->clk);
+
+ /* enable audio controller and AC-link interface */
+ val = AUDIO_READ(nuc900_audio->mmio + ACTL_CON);
+ val |= (IIS_AC_PIN_SEL | ACLINK_EN);
+ AUDIO_WRITE(nuc900_audio->mmio + ACTL_CON, val);
+
+ mutex_unlock(&ac97_mutex);
+
+ return 0;
+}
+
+static void nuc900_ac97_remove(struct platform_device *pdev,
+ struct snd_soc_dai *dai)
+{
+ struct nuc900_audio *nuc900_audio = nuc900_ac97_data;
+
+ clk_disable(nuc900_audio->clk);
+}
+
+static struct snd_soc_dai_ops nuc900_ac97_dai_ops = {
+ .trigger = nuc900_ac97_trigger,
+};
+
+struct snd_soc_dai nuc900_ac97_dai = {
+ .name = "nuc900-ac97",
+ .probe = nuc900_ac97_probe,
+ .remove = nuc900_ac97_remove,
+ .ac97_control = 1,
+ .playback = {
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .channels_min = 1,
+ .channels_max = 2,
+ },
+ .capture = {
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .channels_min = 1,
+ .channels_max = 2,
+ },
+ .ops = &nuc900_ac97_dai_ops,
+}
+EXPORT_SYMBOL_GPL(nuc900_ac97_dai);
+
+static int __devinit nuc900_ac97_drvprobe(struct platform_device *pdev)
+{
+ struct nuc900_audio *nuc900_audio;
+ int ret;
+
+ if (nuc900_ac97_data)
+ return -EBUSY;
+
+ nuc900_audio = kzalloc(sizeof(struct nuc900_audio), GFP_KERNEL);
+ if (!nuc900_audio)
+ return -ENOMEM;
+
+ spin_lock_init(&nuc900_audio->lock);
+
+ nuc900_audio->res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!nuc900_audio->res) {
+ ret = -ENODEV;
+ goto out0;
+ }
+
+ if (!request_mem_region(nuc900_audio->res->start,
+ resource_size(nuc900_audio->res), pdev->name)) {
+ ret = -EBUSY;
+ goto out0;
+ }
+
+ nuc900_audio->mmio = ioremap(nuc900_audio->res->start,
+ resource_size(nuc900_audio->res));
+ if (!nuc900_audio->mmio) {
+ ret = -ENOMEM;
+ goto out1;
+ }
+
+ nuc900_audio->clk = clk_get(&pdev->dev, NULL);
+ if (IS_ERR(nuc900_audio->clk)) {
+ ret = PTR_ERR(nuc900_audio->clk);
+ goto out2;
+ }
+
+ nuc900_audio->irq_num = platform_get_irq(pdev, 0);
+ if (!nuc900_audio->irq_num) {
+ ret = -EBUSY;
+ goto out2;
+ }
+
+ nuc900_ac97_data = nuc900_audio;
+
+ nuc900_audio->dev = nuc900_ac97_dai.dev = &pdev->dev;
+
+ ret = snd_soc_register_dai(&nuc900_ac97_dai);
+ if (ret)
+ goto out3;
+
+ mfp_set_groupg(nuc900_audio->dev); /* enbale ac97 multifunction pin*/
+
+ return 0;
+
+out3:
+ clk_put(nuc900_audio->clk);
+out2:
+ iounmap(nuc900_audio->mmio);
+out1:
+ release_mem_region(nuc900_audio->res->start,
+ resource_size(nuc900_audio->res));
+out0:
+ kfree(nuc900_audio);
+ return ret;
+}
+
+static int __devexit nuc900_ac97_drvremove(struct platform_device *pdev)
+{
+
+ snd_soc_unregister_dai(&nuc900_ac97_dai);
+
+ clk_put(nuc900_ac97_data->clk);
+ iounmap(nuc900_ac97_data->mmio);
+ release_mem_region(nuc900_ac97_data->res->start,
+ resource_size(nuc900_ac97_data->res));
+
+ nuc900_ac97_data = NULL;
+
+ return 0;
+}
+
+static struct platform_driver nuc900_ac97_driver = {
+ .driver = {
+ .name = "nuc900-audio",
+ .owner = THIS_MODULE,
+ },
+ .probe = nuc900_ac97_drvprobe,
+ .remove = __devexit_p(nuc900_ac97_drvremove),
+};
+
+static int __init nuc900_ac97_init(void)
+{
+ return platform_driver_register(&nuc900_ac97_driver);
+}
+
+static void __exit nuc900_ac97_exit(void)
+{
+ platform_driver_unregister(&nuc900_ac97_driver);
+}
+
+module_init(nuc900_ac97_init);
+module_exit(nuc900_ac97_exit);
+
+MODULE_AUTHOR("Wan ZongShun <mcuos.com@gmail.com>");
+MODULE_DESCRIPTION("NUC900 AC97 SoC driver!");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:nuc900-ac97");
diff --git a/sound/soc/nuc900/nuc900-audio.c b/sound/soc/nuc900/nuc900-audio.c
new file mode 100644
index 00000000000..72e6f518f7b
--- /dev/null
+++ b/sound/soc/nuc900/nuc900-audio.c
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2010 Nuvoton technology corporation.
+ *
+ * Wan ZongShun <mcuos.com@gmail.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.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+
+#include "../codecs/ac97.h"
+#include "nuc900-audio.h"
+
+static struct snd_soc_dai_link nuc900evb_ac97_dai = {
+ .name = "AC97",
+ .stream_name = "AC97 HiFi",
+ .cpu_dai = &nuc900_ac97_dai,
+ .codec_dai = &ac97_dai,
+};
+
+static struct snd_soc_card nuc900evb_audio_machine = {
+ .name = "NUC900EVB_AC97",
+ .dai_link = &nuc900evb_ac97_dai,
+ .num_links = 1,
+ .platform = &nuc900_soc_platform,
+};
+
+static struct snd_soc_device nuc900evb_ac97_devdata = {
+ .card = &nuc900evb_audio_machine,
+ .codec_dev = &soc_codec_dev_ac97,
+};
+
+static struct platform_device *nuc900evb_asoc_dev;
+
+static int __init nuc900evb_audio_init(void)
+{
+ int ret;
+
+ ret = -ENOMEM;
+ nuc900evb_asoc_dev = platform_device_alloc("soc-audio", -1);
+ if (!nuc900evb_asoc_dev)
+ goto out;
+
+ /* nuc900 board audio device */
+ platform_set_drvdata(nuc900evb_asoc_dev, &nuc900evb_ac97_devdata);
+
+ nuc900evb_ac97_devdata.dev = &nuc900evb_asoc_dev->dev;
+ ret = platform_device_add(nuc900evb_asoc_dev);
+
+ if (ret) {
+ platform_device_put(nuc900evb_asoc_dev);
+ nuc900evb_asoc_dev = NULL;
+ }
+
+out:
+ return ret;
+}
+
+static void __exit nuc900evb_audio_exit(void)
+{
+ platform_device_unregister(nuc900evb_asoc_dev);
+}
+
+module_init(nuc900evb_audio_init);
+module_exit(nuc900evb_audio_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("NUC900 Series ASoC audio support");
+MODULE_AUTHOR("Wan ZongShun");
diff --git a/sound/soc/nuc900/nuc900-audio.h b/sound/soc/nuc900/nuc900-audio.h
new file mode 100644
index 00000000000..3038f519729
--- /dev/null
+++ b/sound/soc/nuc900/nuc900-audio.h
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) 2010 Nuvoton technology corporation.
+ *
+ * Wan ZongShun <mcuos.com@gmail.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.
+ *
+ */
+
+#ifndef _NUC900_AUDIO_H
+#define _NUC900_AUDIO_H
+
+#include <linux/io.h>
+
+/* Audio Control Registers */
+#define ACTL_CON 0x00
+#define ACTL_RESET 0x04
+#define ACTL_RDSTB 0x08
+#define ACTL_RDST_LENGTH 0x0C
+#define ACTL_RDSTC 0x10
+#define ACTL_RSR 0x14
+#define ACTL_PDSTB 0x18
+#define ACTL_PDST_LENGTH 0x1C
+#define ACTL_PDSTC 0x20
+#define ACTL_PSR 0x24
+#define ACTL_IISCON 0x28
+#define ACTL_ACCON 0x2C
+#define ACTL_ACOS0 0x30
+#define ACTL_ACOS1 0x34
+#define ACTL_ACOS2 0x38
+#define ACTL_ACIS0 0x3C
+#define ACTL_ACIS1 0x40
+#define ACTL_ACIS2 0x44
+#define ACTL_COUNTER 0x48
+
+/* bit definition of REG_ACTL_CON register */
+#define R_DMA_IRQ 0x1000
+#define T_DMA_IRQ 0x0800
+#define IIS_AC_PIN_SEL 0x0100
+#define FIFO_TH 0x0080
+#define ADC_EN 0x0010
+#define M80_EN 0x0008
+#define ACLINK_EN 0x0004
+#define IIS_EN 0x0002
+
+/* bit definition of REG_ACTL_RESET register */
+#define W5691_PLAY 0x20000
+#define ACTL_RESET_BIT 0x10000
+#define RECORD_RIGHT_CHNNEL 0x08000
+#define RECORD_LEFT_CHNNEL 0x04000
+#define PLAY_RIGHT_CHNNEL 0x02000
+#define PLAY_LEFT_CHNNEL 0x01000
+#define DAC_PLAY 0x00800
+#define ADC_RECORD 0x00400
+#define M80_PLAY 0x00200
+#define AC_RECORD 0x00100
+#define AC_PLAY 0x00080
+#define IIS_RECORD 0x00040
+#define IIS_PLAY 0x00020
+#define DAC_RESET 0x00010
+#define ADC_RESET 0x00008
+#define M80_RESET 0x00004
+#define AC_RESET 0x00002
+#define IIS_RESET 0x00001
+
+/* bit definition of REG_ACTL_ACCON register */
+#define AC_BCLK_PU_EN 0x20
+#define AC_R_FINISH 0x10
+#define AC_W_FINISH 0x08
+#define AC_W_RES 0x04
+#define AC_C_RES 0x02
+
+/* bit definition of ACTL_RSR register */
+#define R_FIFO_EMPTY 0x04
+#define R_DMA_END_IRQ 0x02
+#define R_DMA_MIDDLE_IRQ 0x01
+
+/* bit definition of ACTL_PSR register */
+#define P_FIFO_EMPTY 0x04
+#define P_DMA_END_IRQ 0x02
+#define P_DMA_MIDDLE_IRQ 0x01
+
+/* bit definition of ACTL_ACOS0 register */
+#define SLOT1_VALID 0x01
+#define SLOT2_VALID 0x02
+#define SLOT3_VALID 0x04
+#define SLOT4_VALID 0x08
+#define VALID_FRAME 0x10
+
+/* bit definition of ACTL_ACOS1 register */
+#define R_WB 0x80
+
+#define CODEC_READY 0x10
+#define RESET_PRSR 0x00
+#define AUDIO_WRITE(addr, val) __raw_writel(val, addr)
+#define AUDIO_READ(addr) __raw_readl(addr)
+
+struct nuc900_audio {
+ void __iomem *mmio;
+ spinlock_t lock;
+ dma_addr_t dma_addr[2];
+ unsigned long buffersize[2];
+ unsigned long irq_num;
+ struct snd_pcm_substream *substream;
+ struct resource *res;
+ struct clk *clk;
+ struct device *dev;
+
+};
+
+extern struct nuc900_audio *nuc900_ac97_data;
+extern struct snd_soc_dai nuc900_ac97_dai;
+extern struct snd_soc_platform nuc900_soc_platform;
+
+#endif /*end _NUC900_AUDIO_H */
diff --git a/sound/soc/nuc900/nuc900-pcm.c b/sound/soc/nuc900/nuc900-pcm.c
new file mode 100644
index 00000000000..e81e803b3a6
--- /dev/null
+++ b/sound/soc/nuc900/nuc900-pcm.c
@@ -0,0 +1,354 @@
+/*
+ * Copyright (c) 2010 Nuvoton technology corporation.
+ *
+ * Wan ZongShun <mcuos.com@gmail.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.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/dma-mapping.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+#include <mach/hardware.h>
+
+#include "nuc900-audio.h"
+
+static const struct snd_pcm_hardware nuc900_pcm_hardware = {
+ .info = SNDRV_PCM_INFO_INTERLEAVED |
+ SNDRV_PCM_INFO_BLOCK_TRANSFER |
+ SNDRV_PCM_INFO_MMAP |
+ SNDRV_PCM_INFO_MMAP_VALID |
+ SNDRV_PCM_INFO_PAUSE |
+ SNDRV_PCM_INFO_RESUME,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .channels_min = 1,
+ .channels_max = 2,
+ .buffer_bytes_max = 4*1024,
+ .period_bytes_min = 1*1024,
+ .period_bytes_max = 4*1024,
+ .periods_min = 1,
+ .periods_max = 1024,
+};
+
+static int nuc900_dma_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct nuc900_audio *nuc900_audio = runtime->private_data;
+ unsigned long flags;
+ int ret = 0;
+
+ spin_lock_irqsave(&nuc900_audio->lock, flags);
+
+ ret = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params));
+ if (ret < 0)
+ return ret;
+
+ nuc900_audio->substream = substream;
+ nuc900_audio->dma_addr[substream->stream] = runtime->dma_addr;
+ nuc900_audio->buffersize[substream->stream] =
+ params_buffer_bytes(params);
+
+ spin_unlock_irqrestore(&nuc900_audio->lock, flags);
+
+ return ret;
+}
+
+static void nuc900_update_dma_register(struct snd_pcm_substream *substream,
+ dma_addr_t dma_addr, size_t count)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct nuc900_audio *nuc900_audio = runtime->private_data;
+ void __iomem *mmio_addr, *mmio_len;
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ mmio_addr = nuc900_audio->mmio + ACTL_PDSTB;
+ mmio_len = nuc900_audio->mmio + ACTL_PDST_LENGTH;
+ } else {
+ mmio_addr = nuc900_audio->mmio + ACTL_RDSTB;
+ mmio_len = nuc900_audio->mmio + ACTL_RDST_LENGTH;
+ }
+
+ AUDIO_WRITE(mmio_addr, dma_addr);
+ AUDIO_WRITE(mmio_len, count);
+}
+
+static void nuc900_dma_start(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct nuc900_audio *nuc900_audio = runtime->private_data;
+ unsigned long val;
+
+ val = AUDIO_READ(nuc900_audio->mmio + ACTL_CON);
+ val |= (T_DMA_IRQ | R_DMA_IRQ);
+ AUDIO_WRITE(nuc900_audio->mmio + ACTL_CON, val);
+}
+
+static void nuc900_dma_stop(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct nuc900_audio *nuc900_audio = runtime->private_data;
+ unsigned long val;
+
+ val = AUDIO_READ(nuc900_audio->mmio + ACTL_CON);
+ val &= ~(T_DMA_IRQ | R_DMA_IRQ);
+ AUDIO_WRITE(nuc900_audio->mmio + ACTL_CON, val);
+}
+
+static irqreturn_t nuc900_dma_interrupt(int irq, void *dev_id)
+{
+ struct snd_pcm_substream *substream = dev_id;
+ struct nuc900_audio *nuc900_audio = substream->runtime->private_data;
+ unsigned long val;
+
+ spin_lock(&nuc900_audio->lock);
+
+ val = AUDIO_READ(nuc900_audio->mmio + ACTL_CON);
+
+ if (val & R_DMA_IRQ) {
+ AUDIO_WRITE(nuc900_audio->mmio + ACTL_CON, val | R_DMA_IRQ);
+
+ val = AUDIO_READ(nuc900_audio->mmio + ACTL_RSR);
+
+ if (val & R_DMA_MIDDLE_IRQ) {
+ val |= R_DMA_MIDDLE_IRQ;
+ AUDIO_WRITE(nuc900_audio->mmio + ACTL_RSR, val);
+ }
+
+ if (val & R_DMA_END_IRQ) {
+ val |= R_DMA_END_IRQ;
+ AUDIO_WRITE(nuc900_audio->mmio + ACTL_RSR, val);
+ }
+ } else if (val & T_DMA_IRQ) {
+ AUDIO_WRITE(nuc900_audio->mmio + ACTL_CON, val | T_DMA_IRQ);
+
+ val = AUDIO_READ(nuc900_audio->mmio + ACTL_PSR);
+
+ if (val & P_DMA_MIDDLE_IRQ) {
+ val |= P_DMA_MIDDLE_IRQ;
+ AUDIO_WRITE(nuc900_audio->mmio + ACTL_PSR, val);
+ }
+
+ if (val & P_DMA_END_IRQ) {
+ val |= P_DMA_END_IRQ;
+ AUDIO_WRITE(nuc900_audio->mmio + ACTL_PSR, val);
+ }
+ } else {
+ dev_err(nuc900_audio->dev, "Wrong DMA interrupt status!\n");
+ spin_unlock(&nuc900_audio->lock);
+ return IRQ_HANDLED;
+ }
+
+ spin_unlock(&nuc900_audio->lock);
+
+ snd_pcm_period_elapsed(substream);
+
+ return IRQ_HANDLED;
+}
+
+static int nuc900_dma_hw_free(struct snd_pcm_substream *substream)
+{
+ snd_pcm_lib_free_pages(substream);
+ return 0;
+}
+
+static int nuc900_dma_prepare(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct nuc900_audio *nuc900_audio = runtime->private_data;
+ unsigned long flags, val;
+
+ spin_lock_irqsave(&nuc900_audio->lock, flags);
+
+ nuc900_update_dma_register(substream,
+ nuc900_audio->dma_addr[substream->stream],
+ nuc900_audio->buffersize[substream->stream]);
+
+ val = AUDIO_READ(nuc900_audio->mmio + ACTL_RESET);
+
+ switch (runtime->channels) {
+ case 1:
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ val &= ~(PLAY_LEFT_CHNNEL | PLAY_RIGHT_CHNNEL);
+ val |= PLAY_RIGHT_CHNNEL;
+ } else {
+ val &= ~(RECORD_LEFT_CHNNEL | RECORD_RIGHT_CHNNEL);
+ val |= RECORD_RIGHT_CHNNEL;
+ }
+ AUDIO_WRITE(nuc900_audio->mmio + ACTL_RESET, val);
+ break;
+ case 2:
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ val |= (PLAY_LEFT_CHNNEL | PLAY_RIGHT_CHNNEL);
+ else
+ val |= (RECORD_LEFT_CHNNEL | RECORD_RIGHT_CHNNEL);
+ AUDIO_WRITE(nuc900_audio->mmio + ACTL_RESET, val);
+ break;
+ default:
+ return -EINVAL;
+ }
+ spin_unlock_irqrestore(&nuc900_audio->lock, flags);
+ return 0;
+}
+
+static int nuc900_dma_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+ int ret = 0;
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_RESUME:
+ nuc900_dma_start(substream);
+ break;
+
+ case SNDRV_PCM_TRIGGER_STOP:
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ nuc900_dma_stop(substream);
+ break;
+
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+int nuc900_dma_getposition(struct snd_pcm_substream *substream,
+ dma_addr_t *src, dma_addr_t *dst)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct nuc900_audio *nuc900_audio = runtime->private_data;
+
+ if (src != NULL)
+ *src = AUDIO_READ(nuc900_audio->mmio + ACTL_PDSTC);
+
+ if (dst != NULL)
+ *dst = AUDIO_READ(nuc900_audio->mmio + ACTL_RDSTC);
+
+ return 0;
+}
+
+static snd_pcm_uframes_t nuc900_dma_pointer(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ dma_addr_t src, dst;
+ unsigned long res;
+
+ nuc900_dma_getposition(substream, &src, &dst);
+
+ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+ res = dst - runtime->dma_addr;
+ else
+ res = src - runtime->dma_addr;
+
+ return bytes_to_frames(substream->runtime, res);
+}
+
+static int nuc900_dma_open(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct nuc900_audio *nuc900_audio;
+
+ snd_soc_set_runtime_hwparams(substream, &nuc900_pcm_hardware);
+
+ nuc900_audio = nuc900_ac97_data;
+
+ if (request_irq(nuc900_audio->irq_num, nuc900_dma_interrupt,
+ IRQF_DISABLED, "nuc900-dma", substream))
+ return -EBUSY;
+
+ runtime->private_data = nuc900_audio;
+
+ return 0;
+}
+
+static int nuc900_dma_close(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct nuc900_audio *nuc900_audio = runtime->private_data;
+
+ free_irq(nuc900_audio->irq_num, substream);
+
+ return 0;
+}
+
+static int nuc900_dma_mmap(struct snd_pcm_substream *substream,
+ struct vm_area_struct *vma)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+
+ return dma_mmap_writecombine(substream->pcm->card->dev, vma,
+ runtime->dma_area,
+ runtime->dma_addr,
+ runtime->dma_bytes);
+}
+
+static struct snd_pcm_ops nuc900_dma_ops = {
+ .open = nuc900_dma_open,
+ .close = nuc900_dma_close,
+ .ioctl = snd_pcm_lib_ioctl,
+ .hw_params = nuc900_dma_hw_params,
+ .hw_free = nuc900_dma_hw_free,
+ .prepare = nuc900_dma_prepare,
+ .trigger = nuc900_dma_trigger,
+ .pointer = nuc900_dma_pointer,
+ .mmap = nuc900_dma_mmap,
+};
+
+static void nuc900_dma_free_dma_buffers(struct snd_pcm *pcm)
+{
+ snd_pcm_lib_preallocate_free_for_all(pcm);
+}
+
+static u64 nuc900_pcm_dmamask = DMA_BIT_MASK(32);
+static int nuc900_dma_new(struct snd_card *card,
+ struct snd_soc_dai *dai, struct snd_pcm *pcm)
+{
+ if (!card->dev->dma_mask)
+ card->dev->dma_mask = &nuc900_pcm_dmamask;
+ if (!card->dev->coherent_dma_mask)
+ card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
+
+ snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
+ card->dev, 4 * 1024, (4 * 1024) - 1);
+
+ return 0;
+}
+
+struct snd_soc_platform nuc900_soc_platform = {
+ .name = "nuc900-dma",
+ .pcm_ops = &nuc900_dma_ops,
+ .pcm_new = nuc900_dma_new,
+ .pcm_free = nuc900_dma_free_dma_buffers,
+}
+EXPORT_SYMBOL_GPL(nuc900_soc_platform);
+
+static int __init nuc900_soc_platform_init(void)
+{
+ return snd_soc_register_platform(&nuc900_soc_platform);
+}
+
+static void __exit nuc900_soc_platform_exit(void)
+{
+ snd_soc_unregister_platform(&nuc900_soc_platform);
+}
+
+module_init(nuc900_soc_platform_init);
+module_exit(nuc900_soc_platform_exit);
+
+MODULE_AUTHOR("Wan ZongShun, <mcuos.com@gmail.com>");
+MODULE_DESCRIPTION("nuc900 Audio DMA module");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/omap/omap-mcbsp.c b/sound/soc/omap/omap-mcbsp.c
index 6f44cb4d30b..86f213905e2 100644
--- a/sound/soc/omap/omap-mcbsp.c
+++ b/sound/soc/omap/omap-mcbsp.c
@@ -59,6 +59,7 @@ struct omap_mcbsp_data {
int configured;
unsigned int in_freq;
int clk_div;
+ int wlen;
};
#define to_mcbsp(priv) container_of((priv), struct omap_mcbsp_data, bus_id)
@@ -154,20 +155,51 @@ static void omap_mcbsp_set_threshold(struct snd_pcm_substream *substream)
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
struct omap_mcbsp_data *mcbsp_data = to_mcbsp(cpu_dai->private_data);
+ struct omap_pcm_dma_data *dma_data;
int dma_op_mode = omap_mcbsp_get_dma_op_mode(mcbsp_data->bus_id);
- int samples;
+ int words;
+
+ dma_data = snd_soc_dai_get_dma_data(rtd->dai->cpu_dai, substream);
/* TODO: Currently, MODE_ELEMENT == MODE_FRAME */
if (dma_op_mode == MCBSP_DMA_MODE_THRESHOLD)
- samples = snd_pcm_lib_period_bytes(substream) >> 1;
+ /*
+ * Configure McBSP threshold based on either:
+ * packet_size, when the sDMA is in packet mode, or
+ * based on the period size.
+ */
+ if (dma_data->packet_size)
+ words = dma_data->packet_size;
+ else
+ words = snd_pcm_lib_period_bytes(substream) /
+ (mcbsp_data->wlen / 8);
else
- samples = 1;
+ words = 1;
/* Configure McBSP internal buffer usage */
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
- omap_mcbsp_set_tx_threshold(mcbsp_data->bus_id, samples - 1);
+ omap_mcbsp_set_tx_threshold(mcbsp_data->bus_id, words);
else
- omap_mcbsp_set_rx_threshold(mcbsp_data->bus_id, samples - 1);
+ omap_mcbsp_set_rx_threshold(mcbsp_data->bus_id, words);
+}
+
+static int omap_mcbsp_hwrule_min_buffersize(struct snd_pcm_hw_params *params,
+ struct snd_pcm_hw_rule *rule)
+{
+ struct snd_interval *buffer_size = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_BUFFER_SIZE);
+ struct snd_interval *channels = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_CHANNELS);
+ struct omap_mcbsp_data *mcbsp_data = rule->private;
+ struct snd_interval frames;
+ int size;
+
+ snd_interval_any(&frames);
+ size = omap_mcbsp_get_fifo_size(mcbsp_data->bus_id);
+
+ frames.min = size / channels->min;
+ frames.integer = 1;
+ return snd_interval_refine(buffer_size, &frames);
}
static int omap_mcbsp_dai_startup(struct snd_pcm_substream *substream,
@@ -182,33 +214,35 @@ static int omap_mcbsp_dai_startup(struct snd_pcm_substream *substream,
if (!cpu_dai->active)
err = omap_mcbsp_request(bus_id);
+ /*
+ * OMAP3 McBSP FIFO is word structured.
+ * McBSP2 has 1024 + 256 = 1280 word long buffer,
+ * McBSP1,3,4,5 has 128 word long buffer
+ * This means that the size of the FIFO depends on the sample format.
+ * For example on McBSP3:
+ * 16bit samples: size is 128 * 2 = 256 bytes
+ * 32bit samples: size is 128 * 4 = 512 bytes
+ * It is simpler to place constraint for buffer and period based on
+ * channels.
+ * McBSP3 as example again (16 or 32 bit samples):
+ * 1 channel (mono): size is 128 frames (128 words)
+ * 2 channels (stereo): size is 128 / 2 = 64 frames (2 * 64 words)
+ * 4 channels: size is 128 / 4 = 32 frames (4 * 32 words)
+ */
if (cpu_is_omap343x()) {
- int dma_op_mode = omap_mcbsp_get_dma_op_mode(bus_id);
- int max_period;
-
/*
- * McBSP2 in OMAP3 has 1024 * 32-bit internal audio buffer.
- * Set constraint for minimum buffer size to the same than FIFO
- * size in order to avoid underruns in playback startup because
- * HW is keeping the DMA request active until FIFO is filled.
- */
- if (bus_id == 1)
- snd_pcm_hw_constraint_minmax(substream->runtime,
- SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
- 4096, UINT_MAX);
-
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
- max_period = omap_mcbsp_get_max_tx_threshold(bus_id);
- else
- max_period = omap_mcbsp_get_max_rx_threshold(bus_id);
-
- max_period++;
- max_period <<= 1;
-
- if (dma_op_mode == MCBSP_DMA_MODE_THRESHOLD)
- snd_pcm_hw_constraint_minmax(substream->runtime,
- SNDRV_PCM_HW_PARAM_PERIOD_BYTES,
- 32, max_period);
+ * Rule for the buffer size. We should not allow
+ * smaller buffer than the FIFO size to avoid underruns
+ */
+ snd_pcm_hw_rule_add(substream->runtime, 0,
+ SNDRV_PCM_HW_PARAM_CHANNELS,
+ omap_mcbsp_hwrule_min_buffersize,
+ mcbsp_data,
+ SNDRV_PCM_HW_PARAM_BUFFER_SIZE, -1);
+
+ /* Make sure, that the period size is always even */
+ snd_pcm_hw_constraint_step(substream->runtime, 0,
+ SNDRV_PCM_HW_PARAM_PERIOD_SIZE, 2);
}
return err;
@@ -289,11 +323,14 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
struct omap_mcbsp_data *mcbsp_data = to_mcbsp(cpu_dai->private_data);
struct omap_mcbsp_reg_cfg *regs = &mcbsp_data->regs;
- int dma, bus_id = mcbsp_data->bus_id, id = cpu_dai->id;
+ struct omap_pcm_dma_data *dma_data;
+ int dma, bus_id = mcbsp_data->bus_id;
int wlen, channels, wpf, sync_mode = OMAP_DMA_SYNC_ELEMENT;
+ int pkt_size = 0;
unsigned long port;
unsigned int format, div, framesize, master;
+ dma_data = &omap_mcbsp_dai_dma_params[cpu_dai->id][substream->stream];
if (cpu_class_is_omap1()) {
dma = omap1_dma_reqs[bus_id][substream->stream];
port = omap1_mcbsp_port[bus_id][substream->stream];
@@ -306,35 +343,74 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream,
} else if (cpu_is_omap343x()) {
dma = omap24xx_dma_reqs[bus_id][substream->stream];
port = omap34xx_mcbsp_port[bus_id][substream->stream];
- omap_mcbsp_dai_dma_params[id][substream->stream].set_threshold =
- omap_mcbsp_set_threshold;
- /* TODO: Currently, MODE_ELEMENT == MODE_FRAME */
- if (omap_mcbsp_get_dma_op_mode(bus_id) ==
- MCBSP_DMA_MODE_THRESHOLD)
- sync_mode = OMAP_DMA_SYNC_FRAME;
} else {
return -ENODEV;
}
- omap_mcbsp_dai_dma_params[id][substream->stream].name =
- substream->stream ? "Audio Capture" : "Audio Playback";
- omap_mcbsp_dai_dma_params[id][substream->stream].dma_req = dma;
- omap_mcbsp_dai_dma_params[id][substream->stream].port_addr = port;
- omap_mcbsp_dai_dma_params[id][substream->stream].sync_mode = sync_mode;
switch (params_format(params)) {
case SNDRV_PCM_FORMAT_S16_LE:
- omap_mcbsp_dai_dma_params[id][substream->stream].data_type =
- OMAP_DMA_DATA_TYPE_S16;
+ dma_data->data_type = OMAP_DMA_DATA_TYPE_S16;
+ wlen = 16;
break;
case SNDRV_PCM_FORMAT_S32_LE:
- omap_mcbsp_dai_dma_params[id][substream->stream].data_type =
- OMAP_DMA_DATA_TYPE_S32;
+ dma_data->data_type = OMAP_DMA_DATA_TYPE_S32;
+ wlen = 32;
break;
default:
return -EINVAL;
}
+ if (cpu_is_omap343x()) {
+ dma_data->set_threshold = omap_mcbsp_set_threshold;
+ /* TODO: Currently, MODE_ELEMENT == MODE_FRAME */
+ if (omap_mcbsp_get_dma_op_mode(bus_id) ==
+ MCBSP_DMA_MODE_THRESHOLD) {
+ int period_words, max_thrsh;
+
+ period_words = params_period_bytes(params) / (wlen / 8);
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ max_thrsh = omap_mcbsp_get_max_tx_threshold(
+ mcbsp_data->bus_id);
+ else
+ max_thrsh = omap_mcbsp_get_max_rx_threshold(
+ mcbsp_data->bus_id);
+ /*
+ * If the period contains less or equal number of words,
+ * we are using the original threshold mode setup:
+ * McBSP threshold = sDMA frame size = period_size
+ * Otherwise we switch to sDMA packet mode:
+ * McBSP threshold = sDMA packet size
+ * sDMA frame size = period size
+ */
+ if (period_words > max_thrsh) {
+ int divider = 0;
+
+ /*
+ * Look for the biggest threshold value, which
+ * divides the period size evenly.
+ */
+ divider = period_words / max_thrsh;
+ if (period_words % max_thrsh)
+ divider++;
+ while (period_words % divider &&
+ divider < period_words)
+ divider++;
+ if (divider == period_words)
+ return -EINVAL;
+
+ pkt_size = period_words / divider;
+ sync_mode = OMAP_DMA_SYNC_PACKET;
+ } else {
+ sync_mode = OMAP_DMA_SYNC_FRAME;
+ }
+ }
+ }
- snd_soc_dai_set_dma_data(cpu_dai, substream,
- &omap_mcbsp_dai_dma_params[id][substream->stream]);
+ dma_data->name = substream->stream ? "Audio Capture" : "Audio Playback";
+ dma_data->dma_req = dma;
+ dma_data->port_addr = port;
+ dma_data->sync_mode = sync_mode;
+ dma_data->packet_size = pkt_size;
+
+ snd_soc_dai_set_dma_data(cpu_dai, substream, dma_data);
if (mcbsp_data->configured) {
/* McBSP already configured by another stream */
@@ -360,7 +436,6 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream,
switch (params_format(params)) {
case SNDRV_PCM_FORMAT_S16_LE:
/* Set word lengths */
- wlen = 16;
regs->rcr2 |= RWDLEN2(OMAP_MCBSP_WORD_16);
regs->rcr1 |= RWDLEN1(OMAP_MCBSP_WORD_16);
regs->xcr2 |= XWDLEN2(OMAP_MCBSP_WORD_16);
@@ -368,7 +443,6 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream,
break;
case SNDRV_PCM_FORMAT_S32_LE:
/* Set word lengths */
- wlen = 32;
regs->rcr2 |= RWDLEN2(OMAP_MCBSP_WORD_32);
regs->rcr1 |= RWDLEN1(OMAP_MCBSP_WORD_32);
regs->xcr2 |= XWDLEN2(OMAP_MCBSP_WORD_32);
@@ -409,6 +483,7 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream,
}
omap_mcbsp_config(bus_id, &mcbsp_data->regs);
+ mcbsp_data->wlen = wlen;
mcbsp_data->configured = 1;
return 0;
diff --git a/sound/soc/omap/omap3pandora.c b/sound/soc/omap/omap3pandora.c
index 87ce842fa2e..9eecac135bb 100644
--- a/sound/soc/omap/omap3pandora.c
+++ b/sound/soc/omap/omap3pandora.c
@@ -43,12 +43,14 @@
static struct regulator *omap3pandora_dac_reg;
-static int omap3pandora_cmn_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *params, unsigned int fmt)
+static int omap3pandora_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+ int fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+ SND_SOC_DAIFMT_CBS_CFS;
int ret;
/* Set codec DAI configuration */
@@ -91,24 +93,6 @@ static int omap3pandora_cmn_hw_params(struct snd_pcm_substream *substream,
return 0;
}
-static int omap3pandora_out_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *params)
-{
- return omap3pandora_cmn_hw_params(substream, params,
- SND_SOC_DAIFMT_I2S |
- SND_SOC_DAIFMT_IB_NF |
- SND_SOC_DAIFMT_CBS_CFS);
-}
-
-static int omap3pandora_in_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *params)
-{
- return omap3pandora_cmn_hw_params(substream, params,
- SND_SOC_DAIFMT_I2S |
- SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBS_CFS);
-}
-
static int omap3pandora_dac_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *k, int event)
{
@@ -231,12 +215,8 @@ static int omap3pandora_in_init(struct snd_soc_codec *codec)
return snd_soc_dapm_sync(codec);
}
-static struct snd_soc_ops omap3pandora_out_ops = {
- .hw_params = omap3pandora_out_hw_params,
-};
-
-static struct snd_soc_ops omap3pandora_in_ops = {
- .hw_params = omap3pandora_in_hw_params,
+static struct snd_soc_ops omap3pandora_ops = {
+ .hw_params = omap3pandora_hw_params,
};
/* Digital audio interface glue - connects codec <--> CPU */
@@ -246,14 +226,14 @@ static struct snd_soc_dai_link omap3pandora_dai[] = {
.stream_name = "HiFi Out",
.cpu_dai = &omap_mcbsp_dai[0],
.codec_dai = &twl4030_dai[TWL4030_DAI_HIFI],
- .ops = &omap3pandora_out_ops,
+ .ops = &omap3pandora_ops,
.init = omap3pandora_out_init,
}, {
.name = "TWL4030",
.stream_name = "Line/Mic In",
.cpu_dai = &omap_mcbsp_dai[1],
.codec_dai = &twl4030_dai[TWL4030_DAI_HIFI],
- .ops = &omap3pandora_in_ops,
+ .ops = &omap3pandora_ops,
.init = omap3pandora_in_init,
}
};
diff --git a/sound/soc/omap/rx51.c b/sound/soc/omap/rx51.c
index 47d831ef2db..88052d29617 100644
--- a/sound/soc/omap/rx51.c
+++ b/sound/soc/omap/rx51.c
@@ -27,6 +27,7 @@
#include <linux/gpio.h>
#include <linux/platform_device.h>
#include <sound/core.h>
+#include <sound/jack.h>
#include <sound/pcm.h>
#include <sound/soc.h>
#include <sound/soc-dapm.h>
@@ -37,14 +38,22 @@
#include "omap-pcm.h"
#include "../codecs/tlv320aic3x.h"
+#define RX51_TVOUT_SEL_GPIO 40
+#define RX51_JACK_DETECT_GPIO 177
/*
* REVISIT: TWL4030 GPIO base in RX-51. Now statically defined to 192. This
* gpio is reserved in arch/arm/mach-omap2/board-rx51-peripherals.c
*/
#define RX51_SPEAKER_AMP_TWL_GPIO (192 + 7)
+enum {
+ RX51_JACK_DISABLED,
+ RX51_JACK_TVOUT, /* tv-out */
+};
+
static int rx51_spk_func;
static int rx51_dmic_func;
+static int rx51_jack_func;
static void rx51_ext_control(struct snd_soc_codec *codec)
{
@@ -57,6 +66,9 @@ static void rx51_ext_control(struct snd_soc_codec *codec)
else
snd_soc_dapm_disable_pin(codec, "DMic");
+ gpio_set_value(RX51_TVOUT_SEL_GPIO,
+ rx51_jack_func == RX51_JACK_TVOUT);
+
snd_soc_dapm_sync(codec);
}
@@ -162,6 +174,40 @@ static int rx51_set_input(struct snd_kcontrol *kcontrol,
return 1;
}
+static int rx51_get_jack(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ ucontrol->value.integer.value[0] = rx51_jack_func;
+
+ return 0;
+}
+
+static int rx51_set_jack(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+
+ if (rx51_jack_func == ucontrol->value.integer.value[0])
+ return 0;
+
+ rx51_jack_func = ucontrol->value.integer.value[0];
+ rx51_ext_control(codec);
+
+ return 1;
+}
+
+static struct snd_soc_jack rx51_av_jack;
+
+static struct snd_soc_jack_gpio rx51_av_jack_gpios[] = {
+ {
+ .gpio = RX51_JACK_DETECT_GPIO,
+ .name = "avdet-gpio",
+ .report = SND_JACK_VIDEOOUT,
+ .invert = 1,
+ .debounce_time = 200,
+ },
+};
+
static const struct snd_soc_dapm_widget aic34_dapm_widgets[] = {
SND_SOC_DAPM_SPK("Ext Spk", rx51_spk_event),
SND_SOC_DAPM_MIC("DMic", NULL),
@@ -177,10 +223,12 @@ static const struct snd_soc_dapm_route audio_map[] = {
static const char *spk_function[] = {"Off", "On"};
static const char *input_function[] = {"ADC", "Digital Mic"};
+static const char *jack_function[] = {"Off", "TV-OUT"};
static const struct soc_enum rx51_enum[] = {
SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(spk_function), spk_function),
SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(input_function), input_function),
+ SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(jack_function), jack_function),
};
static const struct snd_kcontrol_new aic34_rx51_controls[] = {
@@ -188,10 +236,13 @@ static const struct snd_kcontrol_new aic34_rx51_controls[] = {
rx51_get_spk, rx51_set_spk),
SOC_ENUM_EXT("Input Select", rx51_enum[1],
rx51_get_input, rx51_set_input),
+ SOC_ENUM_EXT("Jack Function", rx51_enum[2],
+ rx51_get_jack, rx51_set_jack),
};
static int rx51_aic34_init(struct snd_soc_codec *codec)
{
+ struct snd_soc_card *card = codec->socdev->card;
int err;
/* Set up NC codec pins */
@@ -214,7 +265,16 @@ static int rx51_aic34_init(struct snd_soc_codec *codec)
snd_soc_dapm_sync(codec);
- return 0;
+ /* AV jack detection */
+ err = snd_soc_jack_new(card, "AV Jack",
+ SND_JACK_VIDEOOUT, &rx51_av_jack);
+ if (err)
+ return err;
+ err = snd_soc_jack_add_gpios(&rx51_av_jack,
+ ARRAY_SIZE(rx51_av_jack_gpios),
+ rx51_av_jack_gpios);
+
+ return err;
}
/* Digital audio interface glue - connects codec <--> CPU */
@@ -259,6 +319,11 @@ static int __init rx51_soc_init(void)
if (!machine_is_nokia_rx51())
return -ENODEV;
+ err = gpio_request(RX51_TVOUT_SEL_GPIO, "tvout_sel");
+ if (err)
+ goto err_gpio_tvout_sel;
+ gpio_direction_output(RX51_TVOUT_SEL_GPIO, 0);
+
rx51_snd_device = platform_device_alloc("soc-audio", -1);
if (!rx51_snd_device) {
err = -ENOMEM;
@@ -277,13 +342,19 @@ static int __init rx51_soc_init(void)
err2:
platform_device_put(rx51_snd_device);
err1:
+ gpio_free(RX51_TVOUT_SEL_GPIO);
+err_gpio_tvout_sel:
return err;
}
static void __exit rx51_soc_exit(void)
{
+ snd_soc_jack_free_gpios(&rx51_av_jack, ARRAY_SIZE(rx51_av_jack_gpios),
+ rx51_av_jack_gpios);
+
platform_device_unregister(rx51_snd_device);
+ gpio_free(RX51_TVOUT_SEL_GPIO);
}
module_init(rx51_soc_init);
diff --git a/sound/soc/s3c24xx/Kconfig b/sound/soc/s3c24xx/Kconfig
index 2a7cc222d09..213963ac3c2 100644
--- a/sound/soc/s3c24xx/Kconfig
+++ b/sound/soc/s3c24xx/Kconfig
@@ -1,6 +1,6 @@
config SND_S3C24XX_SOC
tristate "SoC Audio for the Samsung S3CXXXX chips"
- depends on ARCH_S3C2410 || ARCH_S3C64XX
+ depends on ARCH_S3C2410 || ARCH_S3C64XX || ARCH_S5PC100 || ARCH_S5PV210
select S3C64XX_DMA if ARCH_S3C64XX
help
Say Y or M if you want to add support for codecs attached to
@@ -120,8 +120,14 @@ config SND_S3C24XX_SOC_SIMTEC_HERMES
config SND_SOC_SMDK_WM9713
tristate "SoC AC97 Audio support for SMDK with WM9713"
- depends on SND_S3C24XX_SOC && MACH_SMDK6410
+ depends on SND_S3C24XX_SOC && (MACH_SMDK6410 || MACH_SMDKC100 || MACH_SMDKV210 || MACH_SMDKC110)
select SND_SOC_WM9713
select SND_S3C_SOC_AC97
help
Sat Y if you want to add support for SoC audio on the SMDK.
+
+config SND_S3C64XX_SOC_SMARTQ
+ tristate "SoC I2S Audio support for SmartQ board"
+ depends on SND_S3C24XX_SOC && MACH_SMARTQ
+ select SND_S3C64XX_SOC_I2S
+ select SND_SOC_WM8750
diff --git a/sound/soc/s3c24xx/Makefile b/sound/soc/s3c24xx/Makefile
index 81d8dc503f8..50172c385d9 100644
--- a/sound/soc/s3c24xx/Makefile
+++ b/sound/soc/s3c24xx/Makefile
@@ -29,6 +29,7 @@ snd-soc-s3c24xx-simtec-hermes-objs := s3c24xx_simtec_hermes.o
snd-soc-s3c24xx-simtec-tlv320aic23-objs := s3c24xx_simtec_tlv320aic23.o
snd-soc-smdk64xx-wm8580-objs := smdk64xx_wm8580.o
snd-soc-smdk-wm9713-objs := smdk_wm9713.o
+snd-soc-s3c64xx-smartq-wm8987-objs := smartq_wm8987.o
obj-$(CONFIG_SND_S3C24XX_SOC_JIVE_WM8750) += snd-soc-jive-wm8750.o
obj-$(CONFIG_SND_S3C24XX_SOC_NEO1973_WM8753) += snd-soc-neo1973-wm8753.o
@@ -41,3 +42,4 @@ obj-$(CONFIG_SND_S3C24XX_SOC_SIMTEC_HERMES) += snd-soc-s3c24xx-simtec-hermes.o
obj-$(CONFIG_SND_S3C24XX_SOC_SIMTEC_TLV320AIC23) += snd-soc-s3c24xx-simtec-tlv320aic23.o
obj-$(CONFIG_SND_S3C64XX_SOC_WM8580) += snd-soc-smdk64xx-wm8580.o
obj-$(CONFIG_SND_SOC_SMDK_WM9713) += snd-soc-smdk-wm9713.o
+obj-$(CONFIG_SND_S3C64XX_SOC_SMARTQ) += snd-soc-s3c64xx-smartq-wm8987.o
diff --git a/sound/soc/s3c24xx/s3c-ac97.c b/sound/soc/s3c24xx/s3c-ac97.c
index ecf4fd04ae9..31f6d45b638 100644
--- a/sound/soc/s3c24xx/s3c-ac97.c
+++ b/sound/soc/s3c24xx/s3c-ac97.c
@@ -31,7 +31,6 @@
#define AC_CMD_DATA(x) (x & 0xffff)
struct s3c_ac97_info {
- unsigned state;
struct clk *ac97_clk;
void __iomem *regs;
struct mutex lock;
diff --git a/sound/soc/s3c24xx/s3c-i2s-v2.c b/sound/soc/s3c24xx/s3c-i2s-v2.c
index 13311c8cf96..64376b2aac7 100644
--- a/sound/soc/s3c24xx/s3c-i2s-v2.c
+++ b/sound/soc/s3c24xx/s3c-i2s-v2.c
@@ -32,7 +32,8 @@
#undef S3C_IIS_V2_SUPPORTED
-#if defined(CONFIG_CPU_S3C2412) || defined(CONFIG_CPU_S3C2413)
+#if defined(CONFIG_CPU_S3C2412) || defined(CONFIG_CPU_S3C2413) \
+ || defined(CONFIG_CPU_S5PV210)
#define S3C_IIS_V2_SUPPORTED
#endif
diff --git a/sound/soc/s3c24xx/smartq_wm8987.c b/sound/soc/s3c24xx/smartq_wm8987.c
new file mode 100644
index 00000000000..b480348140b
--- /dev/null
+++ b/sound/soc/s3c24xx/smartq_wm8987.c
@@ -0,0 +1,295 @@
+/* sound/soc/s3c24xx/smartq_wm8987.c
+ *
+ * Copyright 2010 Maurus Cuelenaere <mcuelenaere@gmail.com>
+ *
+ * Based on smdk6410_wm8987.c
+ * Copyright 2007 Wolfson Microelectronics PLC. - linux@wolfsonmicro.com
+ * Graeme Gregory - graeme.gregory@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.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/gpio.h>
+
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc-dapm.h>
+#include <sound/jack.h>
+
+#include <asm/mach-types.h>
+
+#include "s3c-dma.h"
+#include "s3c64xx-i2s.h"
+
+#include "../codecs/wm8750.h"
+
+/*
+ * WM8987 is register compatible with WM8750, so using that as base driver.
+ */
+
+static struct snd_soc_card snd_soc_smartq;
+
+static int smartq_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_dai *codec_dai = rtd->dai->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+ struct s3c_i2sv2_rate_calc div;
+ unsigned int clk = 0;
+ int ret;
+
+ s3c_i2sv2_iis_calc_rate(&div, NULL, params_rate(params),
+ s3c_i2sv2_get_clock(cpu_dai));
+
+ switch (params_rate(params)) {
+ case 8000:
+ case 16000:
+ case 32000:
+ case 48000:
+ case 96000:
+ clk = 12288000;
+ break;
+ case 11025:
+ case 22050:
+ case 44100:
+ case 88200:
+ clk = 11289600;
+ break;
+ }
+
+ /* set codec DAI configuration */
+ ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
+ SND_SOC_DAIFMT_NB_NF |
+ SND_SOC_DAIFMT_CBS_CFS);
+ if (ret < 0)
+ return ret;
+
+ /* set cpu DAI configuration */
+ ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
+ SND_SOC_DAIFMT_NB_NF |
+ SND_SOC_DAIFMT_CBS_CFS);
+ if (ret < 0)
+ return ret;
+
+ /* set the codec system clock for DAC and ADC */
+ ret = snd_soc_dai_set_sysclk(codec_dai, WM8750_SYSCLK, clk,
+ SND_SOC_CLOCK_IN);
+ if (ret < 0)
+ return ret;
+
+ /* set MCLK division for sample rate */
+ ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C_I2SV2_DIV_RCLK, div.fs_div);
+ if (ret < 0)
+ return ret;
+
+ /* set prescaler division for sample rate */
+ ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C_I2SV2_DIV_PRESCALER,
+ div.clk_div - 1);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+/*
+ * SmartQ WM8987 HiFi DAI operations.
+ */
+static struct snd_soc_ops smartq_hifi_ops = {
+ .hw_params = smartq_hifi_hw_params,
+};
+
+static struct snd_soc_jack smartq_jack;
+
+static struct snd_soc_jack_pin smartq_jack_pins[] = {
+ /* Disable speaker when headphone is plugged in */
+ {
+ .pin = "Internal Speaker",
+ .mask = SND_JACK_HEADPHONE,
+ },
+};
+
+static struct snd_soc_jack_gpio smartq_jack_gpios[] = {
+ {
+ .gpio = S3C64XX_GPL(12),
+ .name = "headphone detect",
+ .report = SND_JACK_HEADPHONE,
+ .debounce_time = 200,
+ },
+};
+
+static const struct snd_kcontrol_new wm8987_smartq_controls[] = {
+ SOC_DAPM_PIN_SWITCH("Internal Speaker"),
+ SOC_DAPM_PIN_SWITCH("Headphone Jack"),
+ SOC_DAPM_PIN_SWITCH("Internal Mic"),
+};
+
+static int smartq_speaker_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *k,
+ int event)
+{
+ gpio_set_value(S3C64XX_GPK(12), SND_SOC_DAPM_EVENT_OFF(event));
+
+ return 0;
+}
+
+static const struct snd_soc_dapm_widget wm8987_dapm_widgets[] = {
+ SND_SOC_DAPM_SPK("Internal Speaker", smartq_speaker_event),
+ SND_SOC_DAPM_HP("Headphone Jack", NULL),
+ SND_SOC_DAPM_MIC("Internal Mic", NULL),
+};
+
+static const struct snd_soc_dapm_route audio_map[] = {
+ {"Headphone Jack", NULL, "LOUT2"},
+ {"Headphone Jack", NULL, "ROUT2"},
+
+ {"Internal Speaker", NULL, "LOUT2"},
+ {"Internal Speaker", NULL, "ROUT2"},
+
+ {"Mic Bias", NULL, "Internal Mic"},
+ {"LINPUT2", NULL, "Mic Bias"},
+};
+
+static int smartq_wm8987_init(struct snd_soc_codec *codec)
+{
+ int err = 0;
+
+ /* Add SmartQ specific widgets */
+ snd_soc_dapm_new_controls(codec, wm8987_dapm_widgets,
+ ARRAY_SIZE(wm8987_dapm_widgets));
+
+ /* add SmartQ specific controls */
+ err = snd_soc_add_controls(codec, wm8987_smartq_controls,
+ ARRAY_SIZE(wm8987_smartq_controls));
+
+ if (err < 0)
+ return err;
+
+ /* setup SmartQ specific audio path */
+ snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
+
+ /* set endpoints to not connected */
+ snd_soc_dapm_nc_pin(codec, "LINPUT1");
+ snd_soc_dapm_nc_pin(codec, "RINPUT1");
+ snd_soc_dapm_nc_pin(codec, "OUT3");
+ snd_soc_dapm_nc_pin(codec, "ROUT1");
+
+ /* set endpoints to default off mode */
+ snd_soc_dapm_enable_pin(codec, "Internal Speaker");
+ snd_soc_dapm_enable_pin(codec, "Internal Mic");
+ snd_soc_dapm_disable_pin(codec, "Headphone Jack");
+
+ err = snd_soc_dapm_sync(codec);
+ if (err)
+ return err;
+
+ /* Headphone jack detection */
+ err = snd_soc_jack_new(&snd_soc_smartq, "Headphone Jack",
+ SND_JACK_HEADPHONE, &smartq_jack);
+ if (err)
+ return err;
+
+ err = snd_soc_jack_add_pins(&smartq_jack, ARRAY_SIZE(smartq_jack_pins),
+ smartq_jack_pins);
+ if (err)
+ return err;
+
+ err = snd_soc_jack_add_gpios(&smartq_jack,
+ ARRAY_SIZE(smartq_jack_gpios),
+ smartq_jack_gpios);
+
+ return err;
+}
+
+static struct snd_soc_dai_link smartq_dai[] = {
+ {
+ .name = "wm8987",
+ .stream_name = "SmartQ Hi-Fi",
+ .cpu_dai = &s3c64xx_i2s_dai[0],
+ .codec_dai = &wm8750_dai,
+ .init = smartq_wm8987_init,
+ .ops = &smartq_hifi_ops,
+ },
+};
+
+static struct snd_soc_card snd_soc_smartq = {
+ .name = "SmartQ",
+ .platform = &s3c24xx_soc_platform,
+ .dai_link = smartq_dai,
+ .num_links = ARRAY_SIZE(smartq_dai),
+};
+
+static struct snd_soc_device smartq_snd_devdata = {
+ .card = &snd_soc_smartq,
+ .codec_dev = &soc_codec_dev_wm8750,
+};
+
+static struct platform_device *smartq_snd_device;
+
+static int __init smartq_init(void)
+{
+ int ret;
+
+ if (!machine_is_smartq7() && !machine_is_smartq5()) {
+ pr_info("Only SmartQ is supported by this ASoC driver\n");
+ return -ENODEV;
+ }
+
+ smartq_snd_device = platform_device_alloc("soc-audio", -1);
+ if (!smartq_snd_device)
+ return -ENOMEM;
+
+ platform_set_drvdata(smartq_snd_device, &smartq_snd_devdata);
+ smartq_snd_devdata.dev = &smartq_snd_device->dev;
+
+ ret = platform_device_add(smartq_snd_device);
+ if (ret) {
+ platform_device_put(smartq_snd_device);
+ return ret;
+ }
+
+ /* Initialise GPIOs used by amplifiers */
+ ret = gpio_request(S3C64XX_GPK(12), "amplifiers shutdown");
+ if (ret) {
+ dev_err(&smartq_snd_device->dev, "Failed to register GPK12\n");
+ goto err_unregister_device;
+ }
+
+ /* Disable amplifiers */
+ ret = gpio_direction_output(S3C64XX_GPK(12), 1);
+ if (ret) {
+ dev_err(&smartq_snd_device->dev, "Failed to configure GPK12\n");
+ goto err_free_gpio_amp_shut;
+ }
+
+ return 0;
+
+err_free_gpio_amp_shut:
+ gpio_free(S3C64XX_GPK(12));
+err_unregister_device:
+ platform_device_unregister(smartq_snd_device);
+
+ return ret;
+}
+
+static void __exit smartq_exit(void)
+{
+ snd_soc_jack_free_gpios(&smartq_jack, ARRAY_SIZE(smartq_jack_gpios),
+ smartq_jack_gpios);
+
+ platform_device_unregister(smartq_snd_device);
+}
+
+module_init(smartq_init);
+module_exit(smartq_exit);
+
+/* Module information */
+MODULE_AUTHOR("Maurus Cuelenaere <mcuelenaere@gmail.com>");
+MODULE_DESCRIPTION("ALSA SoC SmartQ WM8987");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/s3c24xx/smdk_wm9713.c b/sound/soc/s3c24xx/smdk_wm9713.c
index 24fd39f38cc..5527b9e88c9 100644
--- a/sound/soc/s3c24xx/smdk_wm9713.c
+++ b/sound/soc/s3c24xx/smdk_wm9713.c
@@ -25,6 +25,9 @@ static struct snd_soc_card smdk;
* Default CFG switch settings to use this driver:
*
* SMDK6410: Set CFG1 1-3 On, CFG2 1-4 Off
+ * SMDKC100: Set CFG6 1-3 On, CFG7 1 On
+ * SMDKC110: Set CFGB10 1-2 Off, CFGB12 1-3 On
+ * SMDKV210: Set CFGB10 1-2 Off, CFGB12 1-3 On
*/
/*
diff --git a/sound/soc/s6000/s6000-i2s.c b/sound/soc/s6000/s6000-i2s.c
index 5b9ac1759bd..59e3fa7bcb0 100644
--- a/sound/soc/s6000/s6000-i2s.c
+++ b/sound/soc/s6000/s6000-i2s.c
@@ -451,16 +451,15 @@ static int __devinit s6000_i2s_probe(struct platform_device *pdev)
goto err_release_none;
}
- region = request_mem_region(scbmem->start,
- scbmem->end - scbmem->start + 1,
- pdev->name);
+ region = request_mem_region(scbmem->start, resource_size(scbmem),
+ pdev->name);
if (!region) {
dev_err(&pdev->dev, "I2S SCB region already claimed\n");
ret = -EBUSY;
goto err_release_none;
}
- mmio = ioremap(scbmem->start, scbmem->end - scbmem->start + 1);
+ mmio = ioremap(scbmem->start, resource_size(scbmem));
if (!mmio) {
dev_err(&pdev->dev, "can't ioremap SCB region\n");
ret = -ENOMEM;
@@ -474,9 +473,8 @@ static int __devinit s6000_i2s_probe(struct platform_device *pdev)
goto err_release_map;
}
- region = request_mem_region(sifmem->start,
- sifmem->end - sifmem->start + 1,
- pdev->name);
+ region = request_mem_region(sifmem->start, resource_size(sifmem),
+ pdev->name);
if (!region) {
dev_err(&pdev->dev, "I2S SIF region already claimed\n");
ret = -EBUSY;
@@ -490,8 +488,8 @@ static int __devinit s6000_i2s_probe(struct platform_device *pdev)
goto err_release_sif;
}
- region = request_mem_region(dma1->start, dma1->end - dma1->start + 1,
- pdev->name);
+ region = request_mem_region(dma1->start, resource_size(dma1),
+ pdev->name);
if (!region) {
dev_err(&pdev->dev, "I2S DMA region already claimed\n");
ret = -EBUSY;
@@ -500,9 +498,8 @@ static int __devinit s6000_i2s_probe(struct platform_device *pdev)
dma2 = platform_get_resource(pdev, IORESOURCE_DMA, 1);
if (dma2) {
- region = request_mem_region(dma2->start,
- dma2->end - dma2->start + 1,
- pdev->name);
+ region = request_mem_region(dma2->start, resource_size(dma2),
+ pdev->name);
if (!region) {
dev_err(&pdev->dev,
"I2S DMA region already claimed\n");
@@ -561,15 +558,15 @@ err_release_dev:
kfree(dev);
err_release_dma2:
if (dma2)
- release_mem_region(dma2->start, dma2->end - dma2->start + 1);
+ release_mem_region(dma2->start, resource_size(dma2));
err_release_dma1:
- release_mem_region(dma1->start, dma1->end - dma1->start + 1);
+ release_mem_region(dma1->start, resource_size(dma1));
err_release_sif:
- release_mem_region(sifmem->start, (sifmem->end - sifmem->start) + 1);
+ release_mem_region(sifmem->start, resource_size(sifmem));
err_release_map:
iounmap(mmio);
err_release_scb:
- release_mem_region(scbmem->start, (scbmem->end - scbmem->start) + 1);
+ release_mem_region(scbmem->start, resource_size(scbmem));
err_release_none:
return ret;
}
@@ -590,19 +587,18 @@ static void __devexit s6000_i2s_remove(struct platform_device *pdev)
kfree(dev);
region = platform_get_resource(pdev, IORESOURCE_DMA, 0);
- release_mem_region(region->start, region->end - region->start + 1);
+ release_mem_region(region->start, resource_size(region));
region = platform_get_resource(pdev, IORESOURCE_DMA, 1);
if (region)
- release_mem_region(region->start,
- region->end - region->start + 1);
+ release_mem_region(region->start, resource_size(region));
region = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- release_mem_region(region->start, (region->end - region->start) + 1);
+ release_mem_region(region->start, resource_size(region));
iounmap(mmio);
region = platform_get_resource(pdev, IORESOURCE_IO, 0);
- release_mem_region(region->start, (region->end - region->start) + 1);
+ release_mem_region(region->start, resource_size(region));
}
static struct platform_driver s6000_i2s_driver = {
diff --git a/sound/soc/sh/Kconfig b/sound/soc/sh/Kconfig
index a1d14bc3c76..52d7e8ed9c1 100644
--- a/sound/soc/sh/Kconfig
+++ b/sound/soc/sh/Kconfig
@@ -48,7 +48,7 @@ config SND_SH7760_AC97
config SND_FSI_AK4642
bool "FSI-AK4642 sound support"
- depends on SND_SOC_SH4_FSI
+ depends on SND_SOC_SH4_FSI && I2C_SH_MOBILE
select SND_SOC_AK4642
help
This option enables generic sound support for the
@@ -56,7 +56,7 @@ config SND_FSI_AK4642
config SND_FSI_DA7210
bool "FSI-DA7210 sound support"
- depends on SND_SOC_SH4_FSI
+ depends on SND_SOC_SH4_FSI && I2C_SH_MOBILE
select SND_SOC_DA7210
help
This option enables generic sound support for the
diff --git a/sound/soc/sh/fsi-ak4642.c b/sound/soc/sh/fsi-ak4642.c
index be018542314..dad575a2262 100644
--- a/sound/soc/sh/fsi-ak4642.c
+++ b/sound/soc/sh/fsi-ak4642.c
@@ -9,16 +9,7 @@
* for more details.
*/
-#include <linux/module.h>
-#include <linux/moduleparam.h>
#include <linux/platform_device.h>
-#include <linux/i2c.h>
-#include <linux/io.h>
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/soc.h>
-#include <sound/soc-dapm.h>
-
#include <sound/sh_fsi.h>
#include <../sound/soc/codecs/ak4642.h>
@@ -38,7 +29,7 @@ static int fsi_ak4642_dai_init(struct snd_soc_codec *codec)
static struct snd_soc_dai_link fsi_dai_link = {
.name = "AK4642",
.stream_name = "AK4642",
- .cpu_dai = &fsi_soc_dai[0], /* fsi */
+ .cpu_dai = &fsi_soc_dai[FSI_PORT_A],
.codec_dai = &ak4642_dai,
.init = fsi_ak4642_dai_init,
.ops = NULL,
@@ -62,7 +53,7 @@ static int __init fsi_ak4642_init(void)
{
int ret = -ENOMEM;
- fsi_snd_device = platform_device_alloc("soc-audio", -1);
+ fsi_snd_device = platform_device_alloc("soc-audio", FSI_PORT_A);
if (!fsi_snd_device)
goto out;
diff --git a/sound/soc/sh/fsi-da7210.c b/sound/soc/sh/fsi-da7210.c
index 33b4d177f46..121bbb07bb0 100644
--- a/sound/soc/sh/fsi-da7210.c
+++ b/sound/soc/sh/fsi-da7210.c
@@ -10,16 +10,7 @@
* option) any later version.
*/
-#include <linux/interrupt.h>
#include <linux/platform_device.h>
-#include <linux/io.h>
-#include <linux/i2c.h>
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-#include <sound/soc.h>
-#include <sound/soc-dapm.h>
-
#include <sound/sh_fsi.h>
#include "../codecs/da7210.h"
@@ -33,7 +24,7 @@ static int fsi_da7210_init(struct snd_soc_codec *codec)
static struct snd_soc_dai_link fsi_da7210_dai = {
.name = "DA7210",
.stream_name = "DA7210",
- .cpu_dai = &fsi_soc_dai[1], /* FSI B */
+ .cpu_dai = &fsi_soc_dai[FSI_PORT_B],
.codec_dai = &da7210_dai,
.init = fsi_da7210_init,
};
@@ -56,7 +47,7 @@ static int __init fsi_da7210_sound_init(void)
{
int ret;
- fsi_da7210_snd_device = platform_device_alloc("soc-audio", -1);
+ fsi_da7210_snd_device = platform_device_alloc("soc-audio", FSI_PORT_B);
if (!fsi_da7210_snd_device)
return -ENOMEM;
diff --git a/sound/soc/sh/fsi.c b/sound/soc/sh/fsi.c
index ec4acac49eb..58c6bec642d 100644
--- a/sound/soc/sh/fsi.c
+++ b/sound/soc/sh/fsi.c
@@ -12,21 +12,12 @@
* published by the Free Software Foundation.
*/
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
#include <linux/delay.h>
-#include <linux/list.h>
#include <linux/pm_runtime.h>
#include <linux/io.h>
#include <linux/slab.h>
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/initval.h>
#include <sound/soc.h>
-#include <sound/pcm_params.h>
#include <sound/sh_fsi.h>
-#include <asm/atomic.h>
#define DO_FMT 0x0000
#define DOFF_CTL 0x0004
@@ -39,9 +30,11 @@
#define DIDT 0x0020
#define DODT 0x0024
#define MUTE_ST 0x0028
-#define REG_END MUTE_ST
-
+#define OUT_SEL 0x0030
+#define REG_END OUT_SEL
+#define A_MST_CTLR 0x0180
+#define B_MST_CTLR 0x01A0
#define CPU_INT_ST 0x01F4
#define CPU_IEMSK 0x01F8
#define CPU_IMSK 0x01FC
@@ -52,18 +45,18 @@
#define CLK_RST 0x0210
#define SOFT_RST 0x0214
#define FIFO_SZ 0x0218
-#define MREG_START CPU_INT_ST
+#define MREG_START A_MST_CTLR
#define MREG_END FIFO_SZ
/* DO_FMT */
/* DI_FMT */
-#define CR_FMT(param) ((param) << 4)
-# define CR_MONO 0x0
-# define CR_MONO_D 0x1
-# define CR_PCM 0x2
-# define CR_I2S 0x3
-# define CR_TDM 0x4
-# define CR_TDM_D 0x5
+#define CR_MONO (0x0 << 4)
+#define CR_MONO_D (0x1 << 4)
+#define CR_PCM (0x2 << 4)
+#define CR_I2S (0x3 << 4)
+#define CR_TDM (0x4 << 4)
+#define CR_TDM_D (0x5 << 4)
+#define CR_SPDIF 0x00100120
/* DOFF_CTL */
/* DIFF_CTL */
@@ -75,6 +68,14 @@
#define ERR_UNDER 0x00000001
#define ST_ERR (ERR_OVER | ERR_UNDER)
+/* CKG1 */
+#define ACKMD_MASK 0x00007000
+#define BPFMD_MASK 0x00000700
+
+/* A/B MST_CTLR */
+#define BP (1 << 4) /* Fix the signal of Biphase output */
+#define SE (1 << 0) /* Fix the master clock */
+
/* CLK_RST */
#define B_CLK 0x00000010
#define A_CLK 0x00000001
@@ -119,9 +120,13 @@ struct fsi_priv {
int period_len;
int buffer_len;
int periods;
+
+ u32 mst_ctrl;
};
-struct fsi_regs {
+struct fsi_core {
+ int ver;
+
u32 int_st;
u32 iemsk;
u32 imsk;
@@ -132,7 +137,7 @@ struct fsi_master {
int irq;
struct fsi_priv fsia;
struct fsi_priv fsib;
- struct fsi_regs *regs;
+ struct fsi_core *core;
struct sh_fsi_platform_info *info;
spinlock_t lock;
};
@@ -169,24 +174,30 @@ static void __fsi_reg_mask_set(u32 reg, u32 mask, u32 data)
static void fsi_reg_write(struct fsi_priv *fsi, u32 reg, u32 data)
{
- if (reg > REG_END)
+ if (reg > REG_END) {
+ pr_err("fsi: register access err (%s)\n", __func__);
return;
+ }
__fsi_reg_write((u32)(fsi->base + reg), data);
}
static u32 fsi_reg_read(struct fsi_priv *fsi, u32 reg)
{
- if (reg > REG_END)
+ if (reg > REG_END) {
+ pr_err("fsi: register access err (%s)\n", __func__);
return 0;
+ }
return __fsi_reg_read((u32)(fsi->base + reg));
}
static void fsi_reg_mask_set(struct fsi_priv *fsi, u32 reg, u32 mask, u32 data)
{
- if (reg > REG_END)
+ if (reg > REG_END) {
+ pr_err("fsi: register access err (%s)\n", __func__);
return;
+ }
__fsi_reg_mask_set((u32)(fsi->base + reg), mask, data);
}
@@ -196,8 +207,10 @@ static void fsi_master_write(struct fsi_master *master, u32 reg, u32 data)
unsigned long flags;
if ((reg < MREG_START) ||
- (reg > MREG_END))
+ (reg > MREG_END)) {
+ pr_err("fsi: register access err (%s)\n", __func__);
return;
+ }
spin_lock_irqsave(&master->lock, flags);
__fsi_reg_write((u32)(master->base + reg), data);
@@ -210,8 +223,10 @@ static u32 fsi_master_read(struct fsi_master *master, u32 reg)
unsigned long flags;
if ((reg < MREG_START) ||
- (reg > MREG_END))
+ (reg > MREG_END)) {
+ pr_err("fsi: register access err (%s)\n", __func__);
return 0;
+ }
spin_lock_irqsave(&master->lock, flags);
ret = __fsi_reg_read((u32)(master->base + reg));
@@ -226,8 +241,10 @@ static void fsi_master_mask_set(struct fsi_master *master,
unsigned long flags;
if ((reg < MREG_START) ||
- (reg > MREG_END))
+ (reg > MREG_END)) {
+ pr_err("fsi: register access err (%s)\n", __func__);
return;
+ }
spin_lock_irqsave(&master->lock, flags);
__fsi_reg_mask_set((u32)(master->base + reg), mask, data);
@@ -349,8 +366,8 @@ static void fsi_irq_enable(struct fsi_priv *fsi, int is_play)
u32 data = fsi_port_ab_io_bit(fsi, is_play);
struct fsi_master *master = fsi_get_master(fsi);
- fsi_master_mask_set(master, master->regs->imsk, data, data);
- fsi_master_mask_set(master, master->regs->iemsk, data, data);
+ fsi_master_mask_set(master, master->core->imsk, data, data);
+ fsi_master_mask_set(master, master->core->iemsk, data, data);
}
static void fsi_irq_disable(struct fsi_priv *fsi, int is_play)
@@ -358,18 +375,18 @@ static void fsi_irq_disable(struct fsi_priv *fsi, int is_play)
u32 data = fsi_port_ab_io_bit(fsi, is_play);
struct fsi_master *master = fsi_get_master(fsi);
- fsi_master_mask_set(master, master->regs->imsk, data, 0);
- fsi_master_mask_set(master, master->regs->iemsk, data, 0);
+ fsi_master_mask_set(master, master->core->imsk, data, 0);
+ fsi_master_mask_set(master, master->core->iemsk, data, 0);
}
static u32 fsi_irq_get_status(struct fsi_master *master)
{
- return fsi_master_read(master, master->regs->int_st);
+ return fsi_master_read(master, master->core->int_st);
}
static void fsi_irq_clear_all_status(struct fsi_master *master)
{
- fsi_master_write(master, master->regs->int_st, 0x0000000);
+ fsi_master_write(master, master->core->int_st, 0);
}
static void fsi_irq_clear_status(struct fsi_priv *fsi)
@@ -381,7 +398,30 @@ static void fsi_irq_clear_status(struct fsi_priv *fsi)
data |= fsi_port_ab_io_bit(fsi, 1);
/* clear interrupt factor */
- fsi_master_mask_set(master, master->regs->int_st, data, 0);
+ fsi_master_mask_set(master, master->core->int_st, data, 0);
+}
+
+/************************************************************************
+
+
+ SPDIF master clock function
+
+These functions are used later FSI2
+************************************************************************/
+static void fsi_spdif_clk_ctrl(struct fsi_priv *fsi, int enable)
+{
+ struct fsi_master *master = fsi_get_master(fsi);
+ u32 val = BP | SE;
+
+ if (master->core->ver < 2) {
+ pr_err("fsi: register access err (%s)\n", __func__);
+ return;
+ }
+
+ if (enable)
+ fsi_master_mask_set(master, fsi->mst_ctrl, val, val);
+ else
+ fsi_master_mask_set(master, fsi->mst_ctrl, val, 0);
}
/************************************************************************
@@ -662,8 +702,8 @@ static int fsi_dai_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct fsi_priv *fsi = fsi_get_priv(substream);
- const char *msg;
u32 flags = fsi_get_info_flags(fsi);
+ struct fsi_master *master = fsi_get_master(fsi);
u32 fmt;
u32 reg;
u32 data;
@@ -700,36 +740,40 @@ static int fsi_dai_startup(struct snd_pcm_substream *substream,
fmt = is_play ? SH_FSI_GET_OFMT(flags) : SH_FSI_GET_IFMT(flags);
switch (fmt) {
case SH_FSI_FMT_MONO:
- msg = "MONO";
- data = CR_FMT(CR_MONO);
+ data = CR_MONO;
fsi->chan = 1;
break;
case SH_FSI_FMT_MONO_DELAY:
- msg = "MONO Delay";
- data = CR_FMT(CR_MONO_D);
+ data = CR_MONO_D;
fsi->chan = 1;
break;
case SH_FSI_FMT_PCM:
- msg = "PCM";
- data = CR_FMT(CR_PCM);
+ data = CR_PCM;
fsi->chan = 2;
break;
case SH_FSI_FMT_I2S:
- msg = "I2S";
- data = CR_FMT(CR_I2S);
+ data = CR_I2S;
fsi->chan = 2;
break;
case SH_FSI_FMT_TDM:
- msg = "TDM";
fsi->chan = is_play ?
SH_FSI_GET_CH_O(flags) : SH_FSI_GET_CH_I(flags);
- data = CR_FMT(CR_TDM) | (fsi->chan - 1);
+ data = CR_TDM | (fsi->chan - 1);
break;
case SH_FSI_FMT_TDM_DELAY:
- msg = "TDM Delay";
fsi->chan = is_play ?
SH_FSI_GET_CH_O(flags) : SH_FSI_GET_CH_I(flags);
- data = CR_FMT(CR_TDM_D) | (fsi->chan - 1);
+ data = CR_TDM_D | (fsi->chan - 1);
+ break;
+ case SH_FSI_FMT_SPDIF:
+ if (master->core->ver < 2) {
+ dev_err(dai->dev, "This FSI can not use SPDIF\n");
+ return -EINVAL;
+ }
+ data = CR_SPDIF;
+ fsi->chan = 2;
+ fsi_spdif_clk_ctrl(fsi, 1);
+ fsi_reg_mask_set(fsi, OUT_SEL, 0x0010, 0x0010);
break;
default:
dev_err(dai->dev, "unknown format.\n");
@@ -737,12 +781,6 @@ static int fsi_dai_startup(struct snd_pcm_substream *substream,
}
fsi_reg_write(fsi, reg, data);
- /*
- * clear clk reset if master mode
- */
- if (is_master)
- fsi_clk_ctrl(fsi, 1);
-
/* irq clear */
fsi_irq_disable(fsi, is_play);
fsi_irq_clear_status(fsi);
@@ -789,10 +827,93 @@ static int fsi_dai_trigger(struct snd_pcm_substream *substream, int cmd,
return ret;
}
+static int fsi_dai_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct fsi_priv *fsi = fsi_get_priv(substream);
+ struct fsi_master *master = fsi_get_master(fsi);
+ int (*set_rate)(int is_porta, int rate) = master->info->set_rate;
+ int fsi_ver = master->core->ver;
+ int is_play = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
+ int ret;
+
+ /* if slave mode, set_rate is not needed */
+ if (!fsi_is_master_mode(fsi, is_play))
+ return 0;
+
+ /* it is error if no set_rate */
+ if (!set_rate)
+ return -EIO;
+
+ ret = set_rate(fsi_is_port_a(fsi), params_rate(params));
+ if (ret > 0) {
+ u32 data = 0;
+
+ switch (ret & SH_FSI_ACKMD_MASK) {
+ default:
+ /* FALL THROUGH */
+ case SH_FSI_ACKMD_512:
+ data |= (0x0 << 12);
+ break;
+ case SH_FSI_ACKMD_256:
+ data |= (0x1 << 12);
+ break;
+ case SH_FSI_ACKMD_128:
+ data |= (0x2 << 12);
+ break;
+ case SH_FSI_ACKMD_64:
+ data |= (0x3 << 12);
+ break;
+ case SH_FSI_ACKMD_32:
+ if (fsi_ver < 2)
+ dev_err(dai->dev, "unsupported ACKMD\n");
+ else
+ data |= (0x4 << 12);
+ break;
+ }
+
+ switch (ret & SH_FSI_BPFMD_MASK) {
+ default:
+ /* FALL THROUGH */
+ case SH_FSI_BPFMD_32:
+ data |= (0x0 << 8);
+ break;
+ case SH_FSI_BPFMD_64:
+ data |= (0x1 << 8);
+ break;
+ case SH_FSI_BPFMD_128:
+ data |= (0x2 << 8);
+ break;
+ case SH_FSI_BPFMD_256:
+ data |= (0x3 << 8);
+ break;
+ case SH_FSI_BPFMD_512:
+ data |= (0x4 << 8);
+ break;
+ case SH_FSI_BPFMD_16:
+ if (fsi_ver < 2)
+ dev_err(dai->dev, "unsupported ACKMD\n");
+ else
+ data |= (0x7 << 8);
+ break;
+ }
+
+ fsi_reg_mask_set(fsi, CKG1, (ACKMD_MASK | BPFMD_MASK) , data);
+ udelay(10);
+ fsi_clk_ctrl(fsi, 1);
+ ret = 0;
+ }
+
+ return ret;
+
+}
+
static struct snd_soc_dai_ops fsi_dai_ops = {
.startup = fsi_dai_startup,
.shutdown = fsi_dai_shutdown,
.trigger = fsi_dai_trigger,
+ .hw_params = fsi_dai_hw_params,
};
/************************************************************************
@@ -965,11 +1086,6 @@ static int fsi_probe(struct platform_device *pdev)
unsigned int irq;
int ret;
- if (0 != pdev->id) {
- dev_err(&pdev->dev, "current fsi support id 0 only now\n");
- return -ENODEV;
- }
-
id_entry = pdev->id_entry;
if (!id_entry) {
dev_err(&pdev->dev, "unknown fsi device\n");
@@ -998,14 +1114,21 @@ static int fsi_probe(struct platform_device *pdev)
goto exit_kfree;
}
+ /* master setting */
master->irq = irq;
master->info = pdev->dev.platform_data;
+ master->core = (struct fsi_core *)id_entry->driver_data;
+ spin_lock_init(&master->lock);
+
+ /* FSI A setting */
master->fsia.base = master->base;
master->fsia.master = master;
+ master->fsia.mst_ctrl = A_MST_CTLR;
+
+ /* FSI B setting */
master->fsib.base = master->base + 0x40;
master->fsib.master = master;
- master->regs = (struct fsi_regs *)id_entry->driver_data;
- spin_lock_init(&master->lock);
+ master->fsib.mst_ctrl = B_MST_CTLR;
pm_runtime_enable(&pdev->dev);
pm_runtime_resume(&pdev->dev);
@@ -1085,21 +1208,27 @@ static struct dev_pm_ops fsi_pm_ops = {
.runtime_resume = fsi_runtime_nop,
};
-static struct fsi_regs fsi_regs = {
+static struct fsi_core fsi1_core = {
+ .ver = 1,
+
+ /* Interrupt */
.int_st = INT_ST,
.iemsk = IEMSK,
.imsk = IMSK,
};
-static struct fsi_regs fsi2_regs = {
+static struct fsi_core fsi2_core = {
+ .ver = 2,
+
+ /* Interrupt */
.int_st = CPU_INT_ST,
.iemsk = CPU_IEMSK,
.imsk = CPU_IMSK,
};
static struct platform_device_id fsi_id_table[] = {
- { "sh_fsi", (kernel_ulong_t)&fsi_regs },
- { "sh_fsi2", (kernel_ulong_t)&fsi2_regs },
+ { "sh_fsi", (kernel_ulong_t)&fsi1_core },
+ { "sh_fsi2", (kernel_ulong_t)&fsi2_core },
};
static struct platform_driver fsi_driver = {
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index 998569d6033..844ae8221a3 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -84,7 +84,7 @@ static int run_delayed_work(struct delayed_work *dwork)
/* codec register dump */
static ssize_t soc_codec_reg_show(struct snd_soc_codec *codec, char *buf)
{
- int i, step = 1, count = 0;
+ int ret, i, step = 1, count = 0;
if (!codec->reg_cache_size)
return 0;
@@ -101,12 +101,24 @@ static ssize_t soc_codec_reg_show(struct snd_soc_codec *codec, char *buf)
if (count >= PAGE_SIZE - 1)
break;
- if (codec->display_register)
+ if (codec->display_register) {
count += codec->display_register(codec, buf + count,
PAGE_SIZE - count, i);
- else
- count += snprintf(buf + count, PAGE_SIZE - count,
- "%4x", codec->read(codec, i));
+ } else {
+ /* If the read fails it's almost certainly due to
+ * the register being volatile and the device being
+ * powered off.
+ */
+ ret = codec->read(codec, i);
+ if (ret >= 0)
+ count += snprintf(buf + count,
+ PAGE_SIZE - count,
+ "%4x", ret);
+ else
+ count += snprintf(buf + count,
+ PAGE_SIZE - count,
+ "<no data: %d>", ret);
+ }
if (count >= PAGE_SIZE - 1)
break;
@@ -1307,7 +1319,7 @@ cpu_dai_err:
}
/*
- * Attempt to initialise any uninitalised cards. Must be called with
+ * Attempt to initialise any uninitialised cards. Must be called with
* client_mutex.
*/
static void snd_soc_instantiate_cards(void)
@@ -2353,6 +2365,99 @@ int snd_soc_limit_volume(struct snd_soc_codec *codec,
EXPORT_SYMBOL_GPL(snd_soc_limit_volume);
/**
+ * snd_soc_info_volsw_2r_sx - double with tlv and variable data size
+ * mixer info callback
+ * @kcontrol: mixer control
+ * @uinfo: control element information
+ *
+ * Returns 0 for success.
+ */
+int snd_soc_info_volsw_2r_sx(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ struct soc_mixer_control *mc =
+ (struct soc_mixer_control *)kcontrol->private_value;
+ int max = mc->max;
+ int min = mc->min;
+
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->count = 2;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = max-min;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_info_volsw_2r_sx);
+
+/**
+ * snd_soc_get_volsw_2r_sx - double with tlv and variable data size
+ * mixer get callback
+ * @kcontrol: mixer control
+ * @uinfo: control element information
+ *
+ * Returns 0 for success.
+ */
+int snd_soc_get_volsw_2r_sx(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct soc_mixer_control *mc =
+ (struct soc_mixer_control *)kcontrol->private_value;
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ unsigned int mask = (1<<mc->shift)-1;
+ int min = mc->min;
+ int val = snd_soc_read(codec, mc->reg) & mask;
+ int valr = snd_soc_read(codec, mc->rreg) & mask;
+
+ ucontrol->value.integer.value[0] = ((val & 0xff)-min) & mask;
+ ucontrol->value.integer.value[1] = ((valr & 0xff)-min) & mask;
+ return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_get_volsw_2r_sx);
+
+/**
+ * snd_soc_put_volsw_2r_sx - double with tlv and variable data size
+ * mixer put callback
+ * @kcontrol: mixer control
+ * @uinfo: control element information
+ *
+ * Returns 0 for success.
+ */
+int snd_soc_put_volsw_2r_sx(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct soc_mixer_control *mc =
+ (struct soc_mixer_control *)kcontrol->private_value;
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ unsigned int mask = (1<<mc->shift)-1;
+ int min = mc->min;
+ int ret;
+ unsigned int val, valr, oval, ovalr;
+
+ val = ((ucontrol->value.integer.value[0]+min) & 0xff);
+ val &= mask;
+ valr = ((ucontrol->value.integer.value[1]+min) & 0xff);
+ valr &= mask;
+
+ oval = snd_soc_read(codec, mc->reg) & mask;
+ ovalr = snd_soc_read(codec, mc->rreg) & mask;
+
+ ret = 0;
+ if (oval != val) {
+ ret = snd_soc_write(codec, mc->reg, val);
+ if (ret < 0)
+ return ret;
+ }
+ if (ovalr != valr) {
+ ret = snd_soc_write(codec, mc->rreg, valr);
+ if (ret < 0)
+ return ret;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_put_volsw_2r_sx);
+
+/**
* snd_soc_dai_set_sysclk - configure DAI system or master clock.
* @dai: DAI
* @clk_id: DAI specific clock ID
diff --git a/sound/sound_core.c b/sound/sound_core.c
index 7c2d677a2df..cb61317df50 100644
--- a/sound/sound_core.c
+++ b/sound/sound_core.c
@@ -576,8 +576,6 @@ static int soundcore_open(struct inode *inode, struct file *file)
struct sound_unit *s;
const struct file_operations *new_fops = NULL;
- lock_kernel ();
-
chain=unit&0x0F;
if(chain==4 || chain==5) /* dsp/audio/dsp16 */
{
@@ -630,18 +628,19 @@ static int soundcore_open(struct inode *inode, struct file *file)
const struct file_operations *old_fops = file->f_op;
file->f_op = new_fops;
spin_unlock(&sound_loader_lock);
- if(file->f_op->open)
+
+ if (file->f_op->open)
err = file->f_op->open(inode,file);
+
if (err) {
fops_put(file->f_op);
file->f_op = fops_get(old_fops);
}
+
fops_put(old_fops);
- unlock_kernel();
return err;
}
spin_unlock(&sound_loader_lock);
- unlock_kernel();
return -ENODEV;
}
diff --git a/sound/sparc/amd7930.c b/sound/sparc/amd7930.c
index 71221fd2094..9eb1a4e0363 100644
--- a/sound/sparc/amd7930.c
+++ b/sound/sparc/amd7930.c
@@ -1010,7 +1010,7 @@ static int __devinit amd7930_sbus_probe(struct of_device *op, const struct of_de
struct snd_amd7930 *amd;
int err, irq;
- irq = op->irqs[0];
+ irq = op->archdata.irqs[0];
if (dev_num >= SNDRV_CARDS)
return -ENODEV;
@@ -1075,7 +1075,7 @@ static struct of_platform_driver amd7930_sbus_driver = {
static int __init amd7930_init(void)
{
- return of_register_driver(&amd7930_sbus_driver, &of_bus_type);
+ return of_register_platform_driver(&amd7930_sbus_driver);
}
static void __exit amd7930_exit(void)
@@ -1092,7 +1092,7 @@ static void __exit amd7930_exit(void)
amd7930_list = NULL;
- of_unregister_driver(&amd7930_sbus_driver);
+ of_unregister_platform_driver(&amd7930_sbus_driver);
}
module_init(amd7930_init);
diff --git a/sound/sparc/cs4231.c b/sound/sparc/cs4231.c
index fb4c6f2f29e..68570ee2c9b 100644
--- a/sound/sparc/cs4231.c
+++ b/sound/sparc/cs4231.c
@@ -1832,14 +1832,14 @@ static int __devinit snd_cs4231_sbus_create(struct snd_card *card,
chip->c_dma.request = sbus_dma_request;
chip->c_dma.address = sbus_dma_addr;
- if (request_irq(op->irqs[0], snd_cs4231_sbus_interrupt,
+ if (request_irq(op->archdata.irqs[0], snd_cs4231_sbus_interrupt,
IRQF_SHARED, "cs4231", chip)) {
snd_printdd("cs4231-%d: Unable to grab SBUS IRQ %d\n",
- dev, op->irqs[0]);
+ dev, op->archdata.irqs[0]);
snd_cs4231_sbus_free(chip);
return -EBUSY;
}
- chip->irq[0] = op->irqs[0];
+ chip->irq[0] = op->archdata.irqs[0];
if (snd_cs4231_probe(chip) < 0) {
snd_cs4231_sbus_free(chip);
@@ -1870,7 +1870,7 @@ static int __devinit cs4231_sbus_probe(struct of_device *op, const struct of_dev
card->shortname,
rp->flags & 0xffL,
(unsigned long long)rp->start,
- op->irqs[0]);
+ op->archdata.irqs[0]);
err = snd_cs4231_sbus_create(card, op, dev);
if (err < 0) {
@@ -1979,12 +1979,12 @@ static int __devinit snd_cs4231_ebus_create(struct snd_card *card,
chip->c_dma.ebus_info.flags = EBUS_DMA_FLAG_USE_EBDMA_HANDLER;
chip->c_dma.ebus_info.callback = snd_cs4231_ebus_capture_callback;
chip->c_dma.ebus_info.client_cookie = chip;
- chip->c_dma.ebus_info.irq = op->irqs[0];
+ chip->c_dma.ebus_info.irq = op->archdata.irqs[0];
strcpy(chip->p_dma.ebus_info.name, "cs4231(play)");
chip->p_dma.ebus_info.flags = EBUS_DMA_FLAG_USE_EBDMA_HANDLER;
chip->p_dma.ebus_info.callback = snd_cs4231_ebus_play_callback;
chip->p_dma.ebus_info.client_cookie = chip;
- chip->p_dma.ebus_info.irq = op->irqs[1];
+ chip->p_dma.ebus_info.irq = op->archdata.irqs[1];
chip->p_dma.prepare = _ebus_dma_prepare;
chip->p_dma.enable = _ebus_dma_enable;
@@ -2060,7 +2060,7 @@ static int __devinit cs4231_ebus_probe(struct of_device *op, const struct of_dev
sprintf(card->longname, "%s at 0x%llx, irq %d",
card->shortname,
op->resource[0].start,
- op->irqs[0]);
+ op->archdata.irqs[0]);
err = snd_cs4231_ebus_create(card, op, dev);
if (err < 0) {
@@ -2120,12 +2120,12 @@ static struct of_platform_driver cs4231_driver = {
static int __init cs4231_init(void)
{
- return of_register_driver(&cs4231_driver, &of_bus_type);
+ return of_register_platform_driver(&cs4231_driver);
}
static void __exit cs4231_exit(void)
{
- of_unregister_driver(&cs4231_driver);
+ of_unregister_platform_driver(&cs4231_driver);
}
module_init(cs4231_init);
diff --git a/sound/sparc/dbri.c b/sound/sparc/dbri.c
index 1557bf132e7..c421901c48d 100644
--- a/sound/sparc/dbri.c
+++ b/sound/sparc/dbri.c
@@ -2608,7 +2608,7 @@ static int __devinit dbri_probe(struct of_device *op, const struct of_device_id
return -ENOENT;
}
- irq = op->irqs[0];
+ irq = op->archdata.irqs[0];
if (irq <= 0) {
printk(KERN_ERR "DBRI-%d: No IRQ.\n", dev);
return -ENODEV;
@@ -2699,12 +2699,12 @@ static struct of_platform_driver dbri_sbus_driver = {
/* Probe for the dbri chip and then attach the driver. */
static int __init dbri_init(void)
{
- return of_register_driver(&dbri_sbus_driver, &of_bus_type);
+ return of_register_platform_driver(&dbri_sbus_driver);
}
static void __exit dbri_exit(void)
{
- of_unregister_driver(&dbri_sbus_driver);
+ of_unregister_platform_driver(&dbri_sbus_driver);
}
module_init(dbri_init);
diff --git a/sound/usb/card.c b/sound/usb/card.c
index 7a8ac1d81be..9feb00c831a 100644
--- a/sound/usb/card.c
+++ b/sound/usb/card.c
@@ -217,7 +217,7 @@ static int snd_usb_create_streams(struct snd_usb_audio *chip, int ctrlif)
switch (protocol) {
case UAC_VERSION_1: {
- struct uac_ac_header_descriptor_v1 *h1 = control_header;
+ struct uac1_ac_header_descriptor *h1 = control_header;
if (!h1->bInCollection) {
snd_printk(KERN_INFO "skipping empty audio interface (v1)\n");
diff --git a/sound/usb/clock.c b/sound/usb/clock.c
index b5855114667..b853f8df794 100644
--- a/sound/usb/clock.c
+++ b/sound/usb/clock.c
@@ -19,33 +19,19 @@
#include <linux/bitops.h>
#include <linux/init.h>
-#include <linux/list.h>
-#include <linux/slab.h>
#include <linux/string.h>
#include <linux/usb.h>
-#include <linux/moduleparam.h>
-#include <linux/mutex.h>
#include <linux/usb/audio.h>
#include <linux/usb/audio-v2.h>
#include <sound/core.h>
#include <sound/info.h>
#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-#include <sound/initval.h>
#include "usbaudio.h"
#include "card.h"
-#include "midi.h"
-#include "mixer.h"
-#include "proc.h"
-#include "quirks.h"
-#include "endpoint.h"
#include "helper.h"
-#include "debug.h"
-#include "pcm.h"
-#include "urb.h"
-#include "format.h"
+#include "clock.h"
static struct uac_clock_source_descriptor *
snd_usb_find_clock_source(struct usb_host_interface *ctrl_iface,
@@ -134,10 +120,7 @@ static bool uac_clock_source_is_valid(struct snd_usb_audio *chip, int source_id)
return !!data;
}
-/* Try to find the clock source ID of a given clock entity */
-
static int __uac_clock_find_source(struct snd_usb_audio *chip,
- struct usb_host_interface *host_iface,
int entity_id, unsigned long *visited)
{
struct uac_clock_source_descriptor *source;
@@ -154,11 +137,11 @@ static int __uac_clock_find_source(struct snd_usb_audio *chip,
}
/* first, see if the ID we're looking for is a clock source already */
- source = snd_usb_find_clock_source(host_iface, entity_id);
+ source = snd_usb_find_clock_source(chip->ctrl_intf, entity_id);
if (source)
return source->bClockID;
- selector = snd_usb_find_clock_selector(host_iface, entity_id);
+ selector = snd_usb_find_clock_selector(chip->ctrl_intf, entity_id);
if (selector) {
int ret;
@@ -168,6 +151,8 @@ static int __uac_clock_find_source(struct snd_usb_audio *chip,
if (ret < 0)
return ret;
+ /* Selector values are one-based */
+
if (ret > selector->bNrInPins || ret < 1) {
printk(KERN_ERR
"%s(): selector reported illegal value, id %d, ret %d\n",
@@ -176,27 +161,35 @@ static int __uac_clock_find_source(struct snd_usb_audio *chip,
return -EINVAL;
}
- return __uac_clock_find_source(chip, host_iface,
- selector->baCSourceID[ret-1],
+ return __uac_clock_find_source(chip, selector->baCSourceID[ret-1],
visited);
}
/* FIXME: multipliers only act as pass-thru element for now */
- multiplier = snd_usb_find_clock_multiplier(host_iface, entity_id);
+ multiplier = snd_usb_find_clock_multiplier(chip->ctrl_intf, entity_id);
if (multiplier)
- return __uac_clock_find_source(chip, host_iface,
- multiplier->bCSourceID, visited);
+ return __uac_clock_find_source(chip, multiplier->bCSourceID,
+ visited);
return -EINVAL;
}
-int snd_usb_clock_find_source(struct snd_usb_audio *chip,
- struct usb_host_interface *host_iface,
- int entity_id)
+/*
+ * For all kinds of sample rate settings and other device queries,
+ * the clock source (end-leaf) must be used. However, clock selectors,
+ * clock multipliers and sample rate converters may be specified as
+ * clock source input to terminal. This functions walks the clock path
+ * to its end and tries to find the source.
+ *
+ * The 'visited' bitfield is used internally to detect recursive loops.
+ *
+ * Returns the clock source UnitID (>=0) on success, or an error.
+ */
+int snd_usb_clock_find_source(struct snd_usb_audio *chip, int entity_id)
{
DECLARE_BITMAP(visited, 256);
memset(visited, 0, sizeof(visited));
- return __uac_clock_find_source(chip, host_iface, entity_id, visited);
+ return __uac_clock_find_source(chip, entity_id, visited);
}
static int set_sample_rate_v1(struct snd_usb_audio *chip, int iface,
@@ -211,11 +204,8 @@ static int set_sample_rate_v1(struct snd_usb_audio *chip, int iface,
ep = get_endpoint(alts, 0)->bEndpointAddress;
/* if endpoint doesn't have sampling rate control, bail out */
- if (!(fmt->attributes & UAC_EP_CS_ATTR_SAMPLE_RATE)) {
- snd_printk(KERN_WARNING "%d:%d:%d: endpoint lacks sample rate attribute bit, cannot set.\n",
- dev->devnum, iface, fmt->altsetting);
+ if (!(fmt->attributes & UAC_EP_CS_ATTR_SAMPLE_RATE))
return 0;
- }
data[0] = rate;
data[1] = rate >> 8;
@@ -254,12 +244,13 @@ static int set_sample_rate_v2(struct snd_usb_audio *chip, int iface,
struct usb_device *dev = chip->dev;
unsigned char data[4];
int err, crate;
- int clock = snd_usb_clock_find_source(chip, chip->ctrl_intf, fmt->clock);
+ int clock = snd_usb_clock_find_source(chip, fmt->clock);
if (clock < 0)
return clock;
if (!uac_clock_source_is_valid(chip, clock)) {
+ /* TODO: should we try to find valid clock setups by ourself? */
snd_printk(KERN_ERR "%d:%d:%d: clock source %d is not valid, cannot use\n",
dev->devnum, iface, fmt->altsetting, clock);
return -ENXIO;
diff --git a/sound/usb/clock.h b/sound/usb/clock.h
index beb253684e2..46630936d31 100644
--- a/sound/usb/clock.h
+++ b/sound/usb/clock.h
@@ -5,8 +5,6 @@ int snd_usb_init_sample_rate(struct snd_usb_audio *chip, int iface,
struct usb_host_interface *alts,
struct audioformat *fmt, int rate);
-int snd_usb_clock_find_source(struct snd_usb_audio *chip,
- struct usb_host_interface *host_iface,
- int entity_id);
+int snd_usb_clock_find_source(struct snd_usb_audio *chip, int entity_id);
#endif /* __USBAUDIO_CLOCK_H */
diff --git a/sound/usb/endpoint.c b/sound/usb/endpoint.c
index 6f6596cf2b1..1a701f1e8f5 100644
--- a/sound/usb/endpoint.c
+++ b/sound/usb/endpoint.c
@@ -33,6 +33,7 @@
#include "pcm.h"
#include "helper.h"
#include "format.h"
+#include "clock.h"
/*
* free a substream
@@ -275,7 +276,7 @@ int snd_usb_parse_audio_endpoints(struct snd_usb_audio *chip, int iface_no)
/* get audio formats */
switch (protocol) {
case UAC_VERSION_1: {
- struct uac_as_header_descriptor_v1 *as =
+ struct uac1_as_header_descriptor *as =
snd_usb_find_csint_desc(alts->extra, alts->extralen, NULL, UAC_AS_GENERAL);
if (!as) {
@@ -297,7 +298,7 @@ int snd_usb_parse_audio_endpoints(struct snd_usb_audio *chip, int iface_no)
case UAC_VERSION_2: {
struct uac2_input_terminal_descriptor *input_term;
struct uac2_output_terminal_descriptor *output_term;
- struct uac_as_header_descriptor_v2 *as =
+ struct uac2_as_header_descriptor *as =
snd_usb_find_csint_desc(alts->extra, alts->extralen, NULL, UAC_AS_GENERAL);
if (!as) {
diff --git a/sound/usb/format.c b/sound/usb/format.c
index 30364aba79c..4387f54d73d 100644
--- a/sound/usb/format.c
+++ b/sound/usb/format.c
@@ -264,13 +264,12 @@ static int parse_uac2_sample_rate_range(struct audioformat *fp, int nr_triplets,
* on the audioformat table (audio class v2).
*/
static int parse_audio_format_rates_v2(struct snd_usb_audio *chip,
- struct audioformat *fp,
- struct usb_host_interface *iface)
+ struct audioformat *fp)
{
struct usb_device *dev = chip->dev;
unsigned char tmp[2], *data;
int nr_triplets, data_size, ret = 0;
- int clock = snd_usb_clock_find_source(chip, chip->ctrl_intf, fp->clock);
+ int clock = snd_usb_clock_find_source(chip, fp->clock);
if (clock < 0) {
snd_printk(KERN_ERR "%s(): unable to find clock source (clock %d)\n",
@@ -391,7 +390,7 @@ static int parse_audio_format_i(struct snd_usb_audio *chip,
break;
case UAC_VERSION_2:
/* fp->channels is already set in this case */
- ret = parse_audio_format_rates_v2(chip, fp, iface);
+ ret = parse_audio_format_rates_v2(chip, fp);
break;
}
@@ -450,7 +449,7 @@ static int parse_audio_format_ii(struct snd_usb_audio *chip,
framesize = le16_to_cpu(fmt->wSamplesPerFrame);
snd_printd(KERN_INFO "found format II with max.bitrate = %d, frame size=%d\n", brate, framesize);
fp->frame_size = framesize;
- ret = parse_audio_format_rates_v2(chip, fp, iface);
+ ret = parse_audio_format_rates_v2(chip, fp);
break;
}
}
diff --git a/sound/usb/midi.c b/sound/usb/midi.c
index 46785643c66..b9c2bc65f51 100644
--- a/sound/usb/midi.c
+++ b/sound/usb/midi.c
@@ -434,7 +434,7 @@ static void snd_usbmidi_maudio_broken_running_status_input(
u8 cin = buffer[i] & 0x0f;
struct usbmidi_in_port *port = &ep->ports[cable];
int length;
-
+
length = snd_usbmidi_cin_length[cin];
if (cin == 0xf && buffer[i + 1] >= 0xf8)
; /* realtime msg: no running status change */
@@ -628,13 +628,13 @@ static struct usb_protocol_ops snd_usbmidi_standard_ops = {
static struct usb_protocol_ops snd_usbmidi_midiman_ops = {
.input = snd_usbmidi_midiman_input,
- .output = snd_usbmidi_standard_output,
+ .output = snd_usbmidi_standard_output,
.output_packet = snd_usbmidi_output_midiman_packet,
};
static struct usb_protocol_ops snd_usbmidi_maudio_broken_running_status_ops = {
.input = snd_usbmidi_maudio_broken_running_status_input,
- .output = snd_usbmidi_standard_output,
+ .output = snd_usbmidi_standard_output,
.output_packet = snd_usbmidi_output_standard_packet,
};
@@ -1248,7 +1248,7 @@ static void snd_usbmidi_out_endpoint_delete(struct snd_usb_midi_out_endpoint *ep
*/
static int snd_usbmidi_out_endpoint_create(struct snd_usb_midi* umidi,
struct snd_usb_midi_endpoint_info* ep_info,
- struct snd_usb_midi_endpoint* rep)
+ struct snd_usb_midi_endpoint* rep)
{
struct snd_usb_midi_out_endpoint* ep;
unsigned int i;
@@ -1398,7 +1398,7 @@ static void snd_usbmidi_rawmidi_free(struct snd_rawmidi *rmidi)
}
static struct snd_rawmidi_substream *snd_usbmidi_find_substream(struct snd_usb_midi* umidi,
- int stream, int number)
+ int stream, int number)
{
struct list_head* list;
@@ -1811,7 +1811,7 @@ static int snd_usbmidi_detect_endpoints(struct snd_usb_midi* umidi,
snd_usbmidi_switch_roland_altsetting(umidi);
if (endpoint[0].out_ep || endpoint[0].in_ep)
- return 0;
+ return 0;
intf = umidi->iface;
if (!intf || intf->num_altsetting < 1)
@@ -1849,7 +1849,7 @@ static int snd_usbmidi_detect_per_port_endpoints(struct snd_usb_midi* umidi,
struct snd_usb_midi_endpoint_info* endpoints)
{
int err, i;
-
+
err = snd_usbmidi_detect_endpoints(umidi, endpoints, MIDI_MAX_ENDPOINTS);
for (i = 0; i < MIDI_MAX_ENDPOINTS; ++i) {
if (endpoints[i].out_ep)
diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c
index 736d134cc03..c166db0057d 100644
--- a/sound/usb/mixer.c
+++ b/sound/usb/mixer.c
@@ -26,6 +26,22 @@
*
*/
+/*
+ * TODOs, for both the mixer and the streaming interfaces:
+ *
+ * - support for UAC2 effect units
+ * - support for graphical equalizers
+ * - RANGE and MEM set commands (UAC2)
+ * - RANGE and MEM interrupt dispatchers (UAC2)
+ * - audio channel clustering (UAC2)
+ * - audio sample rate converter units (UAC2)
+ * - proper handling of clock multipliers (UAC2)
+ * - dispatch clock change notifications (UAC2)
+ * - stop PCM streams which use a clock that became invalid
+ * - stop PCM streams which use a clock selector that has changed
+ * - parse available sample rates again when clock sources changed
+ */
+
#include <linux/bitops.h>
#include <linux/init.h>
#include <linux/list.h>
@@ -275,28 +291,28 @@ static int get_abs_value(struct usb_mixer_elem_info *cval, int val)
static int get_ctl_value_v1(struct usb_mixer_elem_info *cval, int request, int validx, int *value_ret)
{
+ struct snd_usb_audio *chip = cval->mixer->chip;
unsigned char buf[2];
int val_len = cval->val_type >= USB_MIXER_S16 ? 2 : 1;
int timeout = 10;
while (timeout-- > 0) {
- if (snd_usb_ctl_msg(cval->mixer->chip->dev,
- usb_rcvctrlpipe(cval->mixer->chip->dev, 0),
- request,
+ if (snd_usb_ctl_msg(chip->dev, usb_rcvctrlpipe(chip->dev, 0), request,
USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
- validx, cval->mixer->ctrlif | (cval->id << 8),
+ validx, snd_usb_ctrl_intf(chip) | (cval->id << 8),
buf, val_len, 100) >= val_len) {
*value_ret = convert_signed_value(cval, snd_usb_combine_bytes(buf, val_len));
return 0;
}
}
snd_printdd(KERN_ERR "cannot get ctl value: req = %#x, wValue = %#x, wIndex = %#x, type = %d\n",
- request, validx, cval->mixer->ctrlif | (cval->id << 8), cval->val_type);
+ request, validx, snd_usb_ctrl_intf(chip) | (cval->id << 8), cval->val_type);
return -EINVAL;
}
static int get_ctl_value_v2(struct usb_mixer_elem_info *cval, int request, int validx, int *value_ret)
{
+ struct snd_usb_audio *chip = cval->mixer->chip;
unsigned char buf[2 + 3*sizeof(__u16)]; /* enough space for one range */
unsigned char *val;
int ret, size;
@@ -312,16 +328,14 @@ static int get_ctl_value_v2(struct usb_mixer_elem_info *cval, int request, int v
memset(buf, 0, sizeof(buf));
- ret = snd_usb_ctl_msg(cval->mixer->chip->dev,
- usb_rcvctrlpipe(cval->mixer->chip->dev, 0),
- bRequest,
+ ret = snd_usb_ctl_msg(chip->dev, usb_rcvctrlpipe(chip->dev, 0), bRequest,
USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
- validx, cval->mixer->ctrlif | (cval->id << 8),
+ validx, snd_usb_ctrl_intf(chip) | (cval->id << 8),
buf, size, 1000);
if (ret < 0) {
snd_printk(KERN_ERR "cannot get ctl value: req = %#x, wValue = %#x, wIndex = %#x, type = %d\n",
- request, validx, cval->mixer->ctrlif | (cval->id << 8), cval->val_type);
+ request, validx, snd_usb_ctrl_intf(chip) | (cval->id << 8), cval->val_type);
return ret;
}
@@ -397,6 +411,7 @@ static int get_cur_mix_value(struct usb_mixer_elem_info *cval,
int snd_usb_mixer_set_ctl_value(struct usb_mixer_elem_info *cval,
int request, int validx, int value_set)
{
+ struct snd_usb_audio *chip = cval->mixer->chip;
unsigned char buf[2];
int val_len, timeout = 10;
@@ -419,15 +434,14 @@ int snd_usb_mixer_set_ctl_value(struct usb_mixer_elem_info *cval,
buf[0] = value_set & 0xff;
buf[1] = (value_set >> 8) & 0xff;
while (timeout-- > 0)
- if (snd_usb_ctl_msg(cval->mixer->chip->dev,
- usb_sndctrlpipe(cval->mixer->chip->dev, 0),
- request,
+ if (snd_usb_ctl_msg(chip->dev,
+ usb_sndctrlpipe(chip->dev, 0), request,
USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT,
- validx, cval->mixer->ctrlif | (cval->id << 8),
+ validx, snd_usb_ctrl_intf(chip) | (cval->id << 8),
buf, val_len, 100) >= 0)
return 0;
snd_printdd(KERN_ERR "cannot set ctl value: req = %#x, wValue = %#x, wIndex = %#x, type = %d, data = %#x/%#x\n",
- request, validx, cval->mixer->ctrlif | (cval->id << 8), cval->val_type, buf[0], buf[1]);
+ request, validx, snd_usb_ctrl_intf(chip) | (cval->id << 8), cval->val_type, buf[0], buf[1]);
return -EINVAL;
}
@@ -582,9 +596,9 @@ static int get_term_name(struct mixer_build *state, struct usb_audio_term *iterm
switch (iterm->type >> 16) {
case UAC_SELECTOR_UNIT:
strcpy(name, "Selector"); return 8;
- case UAC_PROCESSING_UNIT_V1:
+ case UAC1_PROCESSING_UNIT:
strcpy(name, "Process Unit"); return 12;
- case UAC_EXTENSION_UNIT_V1:
+ case UAC1_EXTENSION_UNIT:
strcpy(name, "Ext Unit"); return 8;
case UAC_MIXER_UNIT:
strcpy(name, "Mixer"); return 5;
@@ -672,8 +686,8 @@ static int check_input_term(struct mixer_build *state, int id, struct usb_audio_
term->name = uac_selector_unit_iSelector(d);
return 0;
}
- case UAC_PROCESSING_UNIT_V1:
- case UAC_EXTENSION_UNIT_V1: {
+ case UAC1_PROCESSING_UNIT:
+ case UAC1_EXTENSION_UNIT: {
struct uac_processing_unit_descriptor *d = p1;
if (d->bNrInPins) {
id = d->baSourceID[0];
@@ -745,6 +759,8 @@ static void usb_mixer_elem_free(struct snd_kcontrol *kctl)
*/
static int get_min_max(struct usb_mixer_elem_info *cval, int default_min)
{
+ struct snd_usb_audio *chip = cval->mixer->chip;
+
/* for failsafe */
cval->min = default_min;
cval->max = cval->min + 1;
@@ -767,7 +783,7 @@ static int get_min_max(struct usb_mixer_elem_info *cval, int default_min)
if (get_ctl_value(cval, UAC_GET_MAX, (cval->control << 8) | minchn, &cval->max) < 0 ||
get_ctl_value(cval, UAC_GET_MIN, (cval->control << 8) | minchn, &cval->min) < 0) {
snd_printd(KERN_ERR "%d:%d: cannot get min/max values for control %d (id %d)\n",
- cval->id, cval->mixer->ctrlif, cval->control, cval->id);
+ cval->id, snd_usb_ctrl_intf(chip), cval->control, cval->id);
return -EINVAL;
}
if (get_ctl_value(cval, UAC_GET_RES, (cval->control << 8) | minchn, &cval->res) < 0) {
@@ -1199,14 +1215,6 @@ static int parse_audio_feature_unit(struct mixer_build *state, int unitid, void
}
} else { /* UAC_VERSION_2 */
for (i = 0; i < 30/2; i++) {
- /* From the USB Audio spec v2.0:
- bmaControls() is a (ch+1)-element array of 4-byte bitmaps,
- each containing a set of bit pairs. If a Control is present,
- it must be Host readable. If a certain Control is not
- present then the bit pair must be set to 0b00.
- If a Control is present but read-only, the bit pair must be
- set to 0b01. If a Control is also Host programmable, the bit
- pair must be set to 0b11. The value 0b10 is not allowed. */
unsigned int ch_bits = 0;
unsigned int ch_read_only = 0;
@@ -1855,13 +1863,13 @@ static int parse_audio_unit(struct mixer_build *state, int unitid)
return parse_audio_selector_unit(state, unitid, p1);
case UAC_FEATURE_UNIT:
return parse_audio_feature_unit(state, unitid, p1);
- case UAC_PROCESSING_UNIT_V1:
+ case UAC1_PROCESSING_UNIT:
/* UAC2_EFFECT_UNIT has the same value */
if (state->mixer->protocol == UAC_VERSION_1)
return parse_audio_processing_unit(state, unitid, p1);
else
return 0; /* FIXME - effect units not implemented yet */
- case UAC_EXTENSION_UNIT_V1:
+ case UAC1_EXTENSION_UNIT:
/* UAC2_PROCESSING_UNIT_V2 has the same value */
if (state->mixer->protocol == UAC_VERSION_1)
return parse_audio_extension_unit(state, unitid, p1);
@@ -1905,7 +1913,7 @@ static int snd_usb_mixer_controls(struct usb_mixer_interface *mixer)
struct usb_host_interface *hostif;
void *p;
- hostif = &usb_ifnum_to_if(mixer->chip->dev, mixer->ctrlif)->altsetting[0];
+ hostif = mixer->chip->ctrl_intf;
memset(&state, 0, sizeof(state));
state.chip = mixer->chip;
state.mixer = mixer;
@@ -1925,7 +1933,7 @@ static int snd_usb_mixer_controls(struct usb_mixer_interface *mixer)
p = NULL;
while ((p = snd_usb_find_csint_desc(hostif->extra, hostif->extralen, p, UAC_OUTPUT_TERMINAL)) != NULL) {
if (mixer->protocol == UAC_VERSION_1) {
- struct uac_output_terminal_descriptor_v1 *desc = p;
+ struct uac1_output_terminal_descriptor *desc = p;
if (desc->bLength < sizeof(*desc))
continue; /* invalid descriptor? */
@@ -1997,7 +2005,7 @@ static void snd_usb_mixer_proc_read(struct snd_info_entry *entry,
list_for_each_entry(mixer, &chip->mixer_list, list) {
snd_iprintf(buffer,
"USB Mixer: usb_id=0x%08x, ctrlif=%i, ctlerr=%i\n",
- chip->usb_id, mixer->ctrlif,
+ chip->usb_id, snd_usb_ctrl_intf(chip),
mixer->ignore_ctl_error);
snd_iprintf(buffer, "Card: %s\n", chip->card->longname);
for (unitid = 0; unitid < MAX_ID_ELEMS; unitid++) {
@@ -2115,7 +2123,7 @@ static int snd_usb_mixer_status_create(struct usb_mixer_interface *mixer)
int buffer_length;
unsigned int epnum;
- hostif = &usb_ifnum_to_if(mixer->chip->dev, mixer->ctrlif)->altsetting[0];
+ hostif = mixer->chip->ctrl_intf;
/* we need one interrupt input endpoint */
if (get_iface_desc(hostif)->bNumEndpoints < 1)
return 0;
@@ -2158,7 +2166,6 @@ int snd_usb_create_mixer(struct snd_usb_audio *chip, int ctrlif,
if (!mixer)
return -ENOMEM;
mixer->chip = chip;
- mixer->ctrlif = ctrlif;
mixer->ignore_ctl_error = ignore_error;
mixer->id_elems = kcalloc(MAX_ID_ELEMS, sizeof(*mixer->id_elems),
GFP_KERNEL);
diff --git a/sound/usb/mixer.h b/sound/usb/mixer.h
index a7cf1007fbb..26c636c5c93 100644
--- a/sound/usb/mixer.h
+++ b/sound/usb/mixer.h
@@ -3,7 +3,6 @@
struct usb_mixer_interface {
struct snd_usb_audio *chip;
- unsigned int ctrlif;
struct list_head list;
unsigned int ignore_ctl_error;
struct urb *urb;
diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c
index 456829882f4..3634cedf930 100644
--- a/sound/usb/pcm.c
+++ b/sound/usb/pcm.c
@@ -636,7 +636,7 @@ static int hw_rule_period_time(struct snd_pcm_hw_params *params,
min_datainterval = min(min_datainterval, fp->datainterval);
}
if (min_datainterval == 0xff) {
- hwc_debug(" --> get emtpy\n");
+ hwc_debug(" --> get empty\n");
it->empty = 1;
return -EINVAL;
}
diff --git a/sound/usb/pcm.h b/sound/usb/pcm.h
index 1c931b68f3b..ed3e283f618 100644
--- a/sound/usb/pcm.h
+++ b/sound/usb/pcm.h
@@ -7,8 +7,5 @@ int snd_usb_init_pitch(struct snd_usb_audio *chip, int iface,
struct usb_host_interface *alts,
struct audioformat *fmt);
-int snd_usb_init_sample_rate(struct snd_usb_audio *chip, int iface,
- struct usb_host_interface *alts,
- struct audioformat *fmt, int rate);
#endif /* __USBAUDIO_PCM_H */
diff --git a/sound/usb/quirks-table.h b/sound/usb/quirks-table.h
index f8797f61a24..2e8003f98fc 100644
--- a/sound/usb/quirks-table.h
+++ b/sound/usb/quirks-table.h
@@ -2152,7 +2152,21 @@ YAMAHA_DEVICE(0x7010, "UB99"),
}
},
{
- USB_DEVICE_VENDOR_SPEC(0x2040, 0x7201),
+ USB_DEVICE_VENDOR_SPEC(0x2040, 0x7240),
+ .match_flags = USB_DEVICE_ID_MATCH_DEVICE |
+ USB_DEVICE_ID_MATCH_INT_CLASS |
+ USB_DEVICE_ID_MATCH_INT_SUBCLASS,
+ .bInterfaceClass = USB_CLASS_AUDIO,
+ .bInterfaceSubClass = USB_SUBCLASS_AUDIOCONTROL,
+ .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) {
+ .vendor_name = "Hauppauge",
+ .product_name = "HVR-850",
+ .ifnum = QUIRK_ANY_INTERFACE,
+ .type = QUIRK_AUDIO_ALIGN_TRANSFER,
+ }
+},
+{
+ USB_DEVICE_VENDOR_SPEC(0x2040, 0x7210),
.match_flags = USB_DEVICE_ID_MATCH_DEVICE |
USB_DEVICE_ID_MATCH_INT_CLASS |
USB_DEVICE_ID_MATCH_INT_SUBCLASS,
@@ -2166,7 +2180,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),
}
},
{
- USB_DEVICE_VENDOR_SPEC(0x2040, 0x7202),
+ USB_DEVICE_VENDOR_SPEC(0x2040, 0x7217),
.match_flags = USB_DEVICE_ID_MATCH_DEVICE |
USB_DEVICE_ID_MATCH_INT_CLASS |
USB_DEVICE_ID_MATCH_INT_SUBCLASS,
@@ -2180,7 +2194,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),
}
},
{
- USB_DEVICE_VENDOR_SPEC(0x2040, 0x7203),
+ USB_DEVICE_VENDOR_SPEC(0x2040, 0x721b),
.match_flags = USB_DEVICE_ID_MATCH_DEVICE |
USB_DEVICE_ID_MATCH_INT_CLASS |
USB_DEVICE_ID_MATCH_INT_SUBCLASS,
@@ -2194,7 +2208,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),
}
},
{
- USB_DEVICE_VENDOR_SPEC(0x2040, 0x7204),
+ USB_DEVICE_VENDOR_SPEC(0x2040, 0x721e),
.match_flags = USB_DEVICE_ID_MATCH_DEVICE |
USB_DEVICE_ID_MATCH_INT_CLASS |
USB_DEVICE_ID_MATCH_INT_SUBCLASS,
@@ -2208,7 +2222,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),
}
},
{
- USB_DEVICE_VENDOR_SPEC(0x2040, 0x7205),
+ USB_DEVICE_VENDOR_SPEC(0x2040, 0x721f),
.match_flags = USB_DEVICE_ID_MATCH_DEVICE |
USB_DEVICE_ID_MATCH_INT_CLASS |
USB_DEVICE_ID_MATCH_INT_SUBCLASS,
@@ -2222,7 +2236,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),
}
},
{
- USB_DEVICE_VENDOR_SPEC(0x2040, 0x7250),
+ USB_DEVICE_VENDOR_SPEC(0x2040, 0x7280),
.match_flags = USB_DEVICE_ID_MATCH_DEVICE |
USB_DEVICE_ID_MATCH_INT_CLASS |
USB_DEVICE_ID_MATCH_INT_SUBCLASS,
@@ -2236,7 +2250,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),
}
},
{
- USB_DEVICE_VENDOR_SPEC(0x2040, 0x7230),
+ USB_DEVICE_VENDOR_SPEC(0x0fd9, 0x0008),
.match_flags = USB_DEVICE_ID_MATCH_DEVICE |
USB_DEVICE_ID_MATCH_INT_CLASS |
USB_DEVICE_ID_MATCH_INT_SUBCLASS,
@@ -2244,7 +2258,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),
.bInterfaceSubClass = USB_SUBCLASS_AUDIOCONTROL,
.driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) {
.vendor_name = "Hauppauge",
- .product_name = "HVR-850",
+ .product_name = "HVR-950Q",
.ifnum = QUIRK_ANY_INTERFACE,
.type = QUIRK_AUDIO_ALIGN_TRANSFER,
}
diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c
index b45e54c09ba..9a9da09586a 100644
--- a/sound/usb/quirks.c
+++ b/sound/usb/quirks.c
@@ -32,6 +32,7 @@
#include "helper.h"
#include "endpoint.h"
#include "pcm.h"
+#include "clock.h"
/*
* handle the quirks for the contained interfaces
diff --git a/tools/firewire/Makefile b/tools/firewire/Makefile
new file mode 100644
index 00000000000..81767adaae7
--- /dev/null
+++ b/tools/firewire/Makefile
@@ -0,0 +1,19 @@
+prefix = /usr
+nosy-dump-version = 0.4
+
+CC = gcc
+
+all : nosy-dump
+
+nosy-dump : CFLAGS = -Wall -O2 -g
+nosy-dump : CPPFLAGS = -DVERSION=\"$(nosy-dump-version)\" -I../../drivers/firewire
+nosy-dump : LDFLAGS = -g
+nosy-dump : LDLIBS = -lpopt
+
+nosy-dump : nosy-dump.o decode-fcp.o
+
+clean :
+ rm -rf *.o nosy-dump
+
+install :
+ install nosy-dump $(prefix)/bin/nosy-dump
diff --git a/tools/firewire/decode-fcp.c b/tools/firewire/decode-fcp.c
new file mode 100644
index 00000000000..e41223b6a4c
--- /dev/null
+++ b/tools/firewire/decode-fcp.c
@@ -0,0 +1,213 @@
+#include <linux/firewire-constants.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "list.h"
+#include "nosy-dump.h"
+
+#define CSR_FCP_COMMAND 0xfffff0000b00ull
+#define CSR_FCP_RESPONSE 0xfffff0000d00ull
+
+static const char * const ctype_names[] = {
+ [0x0] = "control", [0x8] = "not implemented",
+ [0x1] = "status", [0x9] = "accepted",
+ [0x2] = "specific inquiry", [0xa] = "rejected",
+ [0x3] = "notify", [0xb] = "in transition",
+ [0x4] = "general inquiry", [0xc] = "stable",
+ [0x5] = "(reserved 0x05)", [0xd] = "changed",
+ [0x6] = "(reserved 0x06)", [0xe] = "(reserved 0x0e)",
+ [0x7] = "(reserved 0x07)", [0xf] = "interim",
+};
+
+static const char * const subunit_type_names[] = {
+ [0x00] = "monitor", [0x10] = "(reserved 0x10)",
+ [0x01] = "audio", [0x11] = "(reserved 0x11)",
+ [0x02] = "printer", [0x12] = "(reserved 0x12)",
+ [0x03] = "disc", [0x13] = "(reserved 0x13)",
+ [0x04] = "tape recorder/player",[0x14] = "(reserved 0x14)",
+ [0x05] = "tuner", [0x15] = "(reserved 0x15)",
+ [0x06] = "ca", [0x16] = "(reserved 0x16)",
+ [0x07] = "camera", [0x17] = "(reserved 0x17)",
+ [0x08] = "(reserved 0x08)", [0x18] = "(reserved 0x18)",
+ [0x09] = "panel", [0x19] = "(reserved 0x19)",
+ [0x0a] = "bulletin board", [0x1a] = "(reserved 0x1a)",
+ [0x0b] = "camera storage", [0x1b] = "(reserved 0x1b)",
+ [0x0c] = "(reserved 0x0c)", [0x1c] = "vendor unique",
+ [0x0d] = "(reserved 0x0d)", [0x1d] = "all subunit types",
+ [0x0e] = "(reserved 0x0e)", [0x1e] = "subunit_type extended to next byte",
+ [0x0f] = "(reserved 0x0f)", [0x1f] = "unit",
+};
+
+struct avc_enum {
+ int value;
+ const char *name;
+};
+
+struct avc_field {
+ const char *name; /* Short name for field. */
+ int offset; /* Location of field, specified in bits; */
+ /* negative means from end of packet. */
+ int width; /* Width of field, 0 means use data_length. */
+ struct avc_enum *names;
+};
+
+struct avc_opcode_info {
+ const char *name;
+ struct avc_field fields[8];
+};
+
+struct avc_enum power_field_names[] = {
+ { 0x70, "on" },
+ { 0x60, "off" },
+ { }
+};
+
+static const struct avc_opcode_info opcode_info[256] = {
+
+ /* TA Document 1999026 */
+ /* AV/C Digital Interface Command Set General Specification 4.0 */
+ [0xb2] = { "power", {
+ { "state", 0, 8, power_field_names }
+ }
+ },
+ [0x30] = { "unit info", {
+ { "foo", 0, 8 },
+ { "unit_type", 8, 5 },
+ { "unit", 13, 3 },
+ { "company id", 16, 24 },
+ }
+ },
+ [0x31] = { "subunit info" },
+ [0x01] = { "reserve" },
+ [0xb0] = { "version" },
+ [0x00] = { "vendor dependent" },
+ [0x02] = { "plug info" },
+ [0x12] = { "channel usage" },
+ [0x24] = { "connect" },
+ [0x20] = { "connect av" },
+ [0x22] = { "connections" },
+ [0x11] = { "digital input" },
+ [0x10] = { "digital output" },
+ [0x25] = { "disconnect" },
+ [0x21] = { "disconnect av" },
+ [0x19] = { "input plug signal format" },
+ [0x18] = { "output plug signal format" },
+ [0x1f] = { "general bus setup" },
+
+ /* TA Document 1999025 */
+ /* AV/C Descriptor Mechanism Specification Version 1.0 */
+ [0x0c] = { "create descriptor" },
+ [0x08] = { "open descriptor" },
+ [0x09] = { "read descriptor" },
+ [0x0a] = { "write descriptor" },
+ [0x05] = { "open info block" },
+ [0x06] = { "read info block" },
+ [0x07] = { "write info block" },
+ [0x0b] = { "search descriptor" },
+ [0x0d] = { "object number select" },
+
+ /* TA Document 1999015 */
+ /* AV/C Command Set for Rate Control of Isochronous Data Flow 1.0 */
+ [0xb3] = { "rate", {
+ { "subfunction", 0, 8 },
+ { "result", 8, 8 },
+ { "plug_type", 16, 8 },
+ { "plug_id", 16, 8 },
+ }
+ },
+
+ /* TA Document 1999008 */
+ /* AV/C Audio Subunit Specification 1.0 */
+ [0xb8] = { "function block" },
+
+ /* TA Document 2001001 */
+ /* AV/C Panel Subunit Specification 1.1 */
+ [0x7d] = { "gui update" },
+ [0x7e] = { "push gui data" },
+ [0x7f] = { "user action" },
+ [0x7c] = { "pass through" },
+
+ /* */
+ [0x26] = { "asynchronous connection" },
+};
+
+struct avc_frame {
+ uint32_t operand0:8;
+ uint32_t opcode:8;
+ uint32_t subunit_id:3;
+ uint32_t subunit_type:5;
+ uint32_t ctype:4;
+ uint32_t cts:4;
+};
+
+static void
+decode_avc(struct link_transaction *t)
+{
+ struct avc_frame *frame =
+ (struct avc_frame *) t->request->packet.write_block.data;
+ const struct avc_opcode_info *info;
+ const char *name;
+ char buffer[32];
+ int i;
+
+ info = &opcode_info[frame->opcode];
+ if (info->name == NULL) {
+ snprintf(buffer, sizeof(buffer),
+ "(unknown opcode 0x%02x)", frame->opcode);
+ name = buffer;
+ } else {
+ name = info->name;
+ }
+
+ printf("av/c %s, subunit_type=%s, subunit_id=%d, opcode=%s",
+ ctype_names[frame->ctype], subunit_type_names[frame->subunit_type],
+ frame->subunit_id, name);
+
+ for (i = 0; info->fields[i].name != NULL; i++)
+ printf(", %s", info->fields[i].name);
+
+ printf("\n");
+}
+
+int
+decode_fcp(struct link_transaction *t)
+{
+ struct avc_frame *frame =
+ (struct avc_frame *) t->request->packet.write_block.data;
+ unsigned long long offset =
+ ((unsigned long long) t->request->packet.common.offset_high << 32) |
+ t->request->packet.common.offset_low;
+
+ if (t->request->packet.common.tcode != TCODE_WRITE_BLOCK_REQUEST)
+ return 0;
+
+ if (offset == CSR_FCP_COMMAND || offset == CSR_FCP_RESPONSE) {
+ switch (frame->cts) {
+ case 0x00:
+ decode_avc(t);
+ break;
+ case 0x01:
+ printf("cal fcp frame (cts=0x01)\n");
+ break;
+ case 0x02:
+ printf("ehs fcp frame (cts=0x02)\n");
+ break;
+ case 0x03:
+ printf("havi fcp frame (cts=0x03)\n");
+ break;
+ case 0x0e:
+ printf("vendor specific fcp frame (cts=0x0e)\n");
+ break;
+ case 0x0f:
+ printf("extended cts\n");
+ break;
+ default:
+ printf("reserved fcp frame (ctx=0x%02x)\n", frame->cts);
+ break;
+ }
+ return 1;
+ }
+
+ return 0;
+}
+
diff --git a/tools/firewire/list.h b/tools/firewire/list.h
new file mode 100644
index 00000000000..41f4bdadf63
--- /dev/null
+++ b/tools/firewire/list.h
@@ -0,0 +1,62 @@
+struct list {
+ struct list *next, *prev;
+};
+
+static inline void
+list_init(struct list *list)
+{
+ list->next = list;
+ list->prev = list;
+}
+
+static inline int
+list_empty(struct list *list)
+{
+ return list->next == list;
+}
+
+static inline void
+list_insert(struct list *link, struct list *new_link)
+{
+ new_link->prev = link->prev;
+ new_link->next = link;
+ new_link->prev->next = new_link;
+ new_link->next->prev = new_link;
+}
+
+static inline void
+list_append(struct list *list, struct list *new_link)
+{
+ list_insert((struct list *)list, new_link);
+}
+
+static inline void
+list_prepend(struct list *list, struct list *new_link)
+{
+ list_insert(list->next, new_link);
+}
+
+static inline void
+list_remove(struct list *link)
+{
+ link->prev->next = link->next;
+ link->next->prev = link->prev;
+}
+
+#define list_entry(link, type, member) \
+ ((type *)((char *)(link)-(unsigned long)(&((type *)0)->member)))
+
+#define list_head(list, type, member) \
+ list_entry((list)->next, type, member)
+
+#define list_tail(list, type, member) \
+ list_entry((list)->prev, type, member)
+
+#define list_next(elm, member) \
+ list_entry((elm)->member.next, typeof(*elm), member)
+
+#define list_for_each_entry(pos, list, member) \
+ for (pos = list_head(list, typeof(*pos), member); \
+ &pos->member != (list); \
+ pos = list_next(pos, member))
+
diff --git a/tools/firewire/nosy-dump.c b/tools/firewire/nosy-dump.c
new file mode 100644
index 00000000000..f93b776370b
--- /dev/null
+++ b/tools/firewire/nosy-dump.c
@@ -0,0 +1,1031 @@
+/*
+ * nosy-dump - Interface to snoop mode driver for TI PCILynx 1394 controllers
+ * Copyright (C) 2002-2006 Kristian Høgsberg
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * 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 <byteswap.h>
+#include <endian.h>
+#include <fcntl.h>
+#include <linux/firewire-constants.h>
+#include <poll.h>
+#include <popt.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/time.h>
+#include <termios.h>
+#include <unistd.h>
+
+#include "list.h"
+#include "nosy-dump.h"
+#include "nosy-user.h"
+
+enum {
+ PACKET_FIELD_DETAIL = 0x01,
+ PACKET_FIELD_DATA_LENGTH = 0x02,
+ /* Marks the fields we print in transaction view. */
+ PACKET_FIELD_TRANSACTION = 0x04,
+};
+
+static void print_packet(uint32_t *data, size_t length);
+static void decode_link_packet(struct link_packet *packet, size_t length,
+ int include_flags, int exclude_flags);
+static int run = 1;
+sig_t sys_sigint_handler;
+
+static char *option_nosy_device = "/dev/nosy";
+static char *option_view = "packet";
+static char *option_output;
+static char *option_input;
+static int option_hex;
+static int option_iso;
+static int option_cycle_start;
+static int option_version;
+static int option_verbose;
+
+enum {
+ VIEW_TRANSACTION,
+ VIEW_PACKET,
+ VIEW_STATS,
+};
+
+static const struct poptOption options[] = {
+ {
+ .longName = "device",
+ .shortName = 'd',
+ .argInfo = POPT_ARG_STRING,
+ .arg = &option_nosy_device,
+ .descrip = "Path to nosy device.",
+ .argDescrip = "DEVICE"
+ },
+ {
+ .longName = "view",
+ .argInfo = POPT_ARG_STRING,
+ .arg = &option_view,
+ .descrip = "Specify view of bus traffic: packet, transaction or stats.",
+ .argDescrip = "VIEW"
+ },
+ {
+ .longName = "hex",
+ .shortName = 'x',
+ .argInfo = POPT_ARG_NONE,
+ .arg = &option_hex,
+ .descrip = "Print each packet in hex.",
+ },
+ {
+ .longName = "iso",
+ .argInfo = POPT_ARG_NONE,
+ .arg = &option_iso,
+ .descrip = "Print iso packets.",
+ },
+ {
+ .longName = "cycle-start",
+ .argInfo = POPT_ARG_NONE,
+ .arg = &option_cycle_start,
+ .descrip = "Print cycle start packets.",
+ },
+ {
+ .longName = "verbose",
+ .shortName = 'v',
+ .argInfo = POPT_ARG_NONE,
+ .arg = &option_verbose,
+ .descrip = "Verbose packet view.",
+ },
+ {
+ .longName = "output",
+ .shortName = 'o',
+ .argInfo = POPT_ARG_STRING,
+ .arg = &option_output,
+ .descrip = "Log to output file.",
+ .argDescrip = "FILENAME"
+ },
+ {
+ .longName = "input",
+ .shortName = 'i',
+ .argInfo = POPT_ARG_STRING,
+ .arg = &option_input,
+ .descrip = "Decode log from file.",
+ .argDescrip = "FILENAME"
+ },
+ {
+ .longName = "version",
+ .argInfo = POPT_ARG_NONE,
+ .arg = &option_version,
+ .descrip = "Specify print version info.",
+ },
+ POPT_AUTOHELP
+ POPT_TABLEEND
+};
+
+/* Allow all ^C except the first to interrupt the program in the usual way. */
+static void
+sigint_handler(int signal_num)
+{
+ if (run == 1) {
+ run = 0;
+ signal(SIGINT, SIG_DFL);
+ }
+}
+
+static struct subaction *
+subaction_create(uint32_t *data, size_t length)
+{
+ struct subaction *sa;
+
+ /* we put the ack in the subaction struct for easy access. */
+ sa = malloc(sizeof *sa - sizeof sa->packet + length);
+ sa->ack = data[length / 4 - 1];
+ sa->length = length;
+ memcpy(&sa->packet, data, length);
+
+ return sa;
+}
+
+static void
+subaction_destroy(struct subaction *sa)
+{
+ free(sa);
+}
+
+static struct list pending_transaction_list = {
+ &pending_transaction_list, &pending_transaction_list
+};
+
+static struct link_transaction *
+link_transaction_lookup(int request_node, int response_node, int tlabel)
+{
+ struct link_transaction *t;
+
+ list_for_each_entry(t, &pending_transaction_list, link) {
+ if (t->request_node == request_node &&
+ t->response_node == response_node &&
+ t->tlabel == tlabel)
+ return t;
+ }
+
+ t = malloc(sizeof *t);
+ t->request_node = request_node;
+ t->response_node = response_node;
+ t->tlabel = tlabel;
+ list_init(&t->request_list);
+ list_init(&t->response_list);
+
+ list_append(&pending_transaction_list, &t->link);
+
+ return t;
+}
+
+static void
+link_transaction_destroy(struct link_transaction *t)
+{
+ struct subaction *sa;
+
+ while (!list_empty(&t->request_list)) {
+ sa = list_head(&t->request_list, struct subaction, link);
+ list_remove(&sa->link);
+ subaction_destroy(sa);
+ }
+ while (!list_empty(&t->response_list)) {
+ sa = list_head(&t->response_list, struct subaction, link);
+ list_remove(&sa->link);
+ subaction_destroy(sa);
+ }
+ free(t);
+}
+
+struct protocol_decoder {
+ const char *name;
+ int (*decode)(struct link_transaction *t);
+};
+
+static const struct protocol_decoder protocol_decoders[] = {
+ { "FCP", decode_fcp }
+};
+
+static void
+handle_transaction(struct link_transaction *t)
+{
+ struct subaction *sa;
+ int i;
+
+ if (!t->request) {
+ printf("BUG in handle_transaction\n");
+ return;
+ }
+
+ for (i = 0; i < array_length(protocol_decoders); i++)
+ if (protocol_decoders[i].decode(t))
+ break;
+
+ /* HACK: decode only fcp right now. */
+ return;
+
+ decode_link_packet(&t->request->packet, t->request->length,
+ PACKET_FIELD_TRANSACTION, 0);
+ if (t->response)
+ decode_link_packet(&t->response->packet, t->request->length,
+ PACKET_FIELD_TRANSACTION, 0);
+ else
+ printf("[no response]");
+
+ if (option_verbose) {
+ list_for_each_entry(sa, &t->request_list, link)
+ print_packet((uint32_t *) &sa->packet, sa->length);
+ list_for_each_entry(sa, &t->response_list, link)
+ print_packet((uint32_t *) &sa->packet, sa->length);
+ }
+ printf("\r\n");
+
+ link_transaction_destroy(t);
+}
+
+static void
+clear_pending_transaction_list(void)
+{
+ struct link_transaction *t;
+
+ while (!list_empty(&pending_transaction_list)) {
+ t = list_head(&pending_transaction_list,
+ struct link_transaction, link);
+ list_remove(&t->link);
+ link_transaction_destroy(t);
+ /* print unfinished transactions */
+ }
+}
+
+static const char * const tcode_names[] = {
+ [0x0] = "write_quadlet_request", [0x6] = "read_quadlet_response",
+ [0x1] = "write_block_request", [0x7] = "read_block_response",
+ [0x2] = "write_response", [0x8] = "cycle_start",
+ [0x3] = "reserved", [0x9] = "lock_request",
+ [0x4] = "read_quadlet_request", [0xa] = "iso_data",
+ [0x5] = "read_block_request", [0xb] = "lock_response",
+};
+
+static const char * const ack_names[] = {
+ [0x0] = "no ack", [0x8] = "reserved (0x08)",
+ [0x1] = "ack_complete", [0x9] = "reserved (0x09)",
+ [0x2] = "ack_pending", [0xa] = "reserved (0x0a)",
+ [0x3] = "reserved (0x03)", [0xb] = "reserved (0x0b)",
+ [0x4] = "ack_busy_x", [0xc] = "reserved (0x0c)",
+ [0x5] = "ack_busy_a", [0xd] = "ack_data_error",
+ [0x6] = "ack_busy_b", [0xe] = "ack_type_error",
+ [0x7] = "reserved (0x07)", [0xf] = "reserved (0x0f)",
+};
+
+static const char * const rcode_names[] = {
+ [0x0] = "complete", [0x4] = "conflict_error",
+ [0x1] = "reserved (0x01)", [0x5] = "data_error",
+ [0x2] = "reserved (0x02)", [0x6] = "type_error",
+ [0x3] = "reserved (0x03)", [0x7] = "address_error",
+};
+
+static const char * const retry_names[] = {
+ [0x0] = "retry_1",
+ [0x1] = "retry_x",
+ [0x2] = "retry_a",
+ [0x3] = "retry_b",
+};
+
+enum {
+ PACKET_RESERVED,
+ PACKET_REQUEST,
+ PACKET_RESPONSE,
+ PACKET_OTHER,
+};
+
+struct packet_info {
+ const char *name;
+ int type;
+ int response_tcode;
+ const struct packet_field *fields;
+ int field_count;
+};
+
+struct packet_field {
+ const char *name; /* Short name for field. */
+ int offset; /* Location of field, specified in bits; */
+ /* negative means from end of packet. */
+ int width; /* Width of field, 0 means use data_length. */
+ int flags; /* Show options. */
+ const char * const *value_names;
+};
+
+#define COMMON_REQUEST_FIELDS \
+ { "dest", 0, 16, PACKET_FIELD_TRANSACTION }, \
+ { "tl", 16, 6 }, \
+ { "rt", 22, 2, PACKET_FIELD_DETAIL, retry_names }, \
+ { "tcode", 24, 4, PACKET_FIELD_TRANSACTION, tcode_names }, \
+ { "pri", 28, 4, PACKET_FIELD_DETAIL }, \
+ { "src", 32, 16, PACKET_FIELD_TRANSACTION }, \
+ { "offs", 48, 48, PACKET_FIELD_TRANSACTION }
+
+#define COMMON_RESPONSE_FIELDS \
+ { "dest", 0, 16 }, \
+ { "tl", 16, 6 }, \
+ { "rt", 22, 2, PACKET_FIELD_DETAIL, retry_names }, \
+ { "tcode", 24, 4, 0, tcode_names }, \
+ { "pri", 28, 4, PACKET_FIELD_DETAIL }, \
+ { "src", 32, 16 }, \
+ { "rcode", 48, 4, PACKET_FIELD_TRANSACTION, rcode_names }
+
+static const struct packet_field read_quadlet_request_fields[] = {
+ COMMON_REQUEST_FIELDS,
+ { "crc", 96, 32, PACKET_FIELD_DETAIL },
+ { "ack", 156, 4, 0, ack_names },
+};
+
+static const struct packet_field read_quadlet_response_fields[] = {
+ COMMON_RESPONSE_FIELDS,
+ { "data", 96, 32, PACKET_FIELD_TRANSACTION },
+ { "crc", 128, 32, PACKET_FIELD_DETAIL },
+ { "ack", 188, 4, 0, ack_names },
+};
+
+static const struct packet_field read_block_request_fields[] = {
+ COMMON_REQUEST_FIELDS,
+ { "data_length", 96, 16, PACKET_FIELD_TRANSACTION },
+ { "extended_tcode", 112, 16 },
+ { "crc", 128, 32, PACKET_FIELD_DETAIL },
+ { "ack", 188, 4, 0, ack_names },
+};
+
+static const struct packet_field block_response_fields[] = {
+ COMMON_RESPONSE_FIELDS,
+ { "data_length", 96, 16, PACKET_FIELD_DATA_LENGTH },
+ { "extended_tcode", 112, 16 },
+ { "crc", 128, 32, PACKET_FIELD_DETAIL },
+ { "data", 160, 0, PACKET_FIELD_TRANSACTION },
+ { "crc", -64, 32, PACKET_FIELD_DETAIL },
+ { "ack", -4, 4, 0, ack_names },
+};
+
+static const struct packet_field write_quadlet_request_fields[] = {
+ COMMON_REQUEST_FIELDS,
+ { "data", 96, 32, PACKET_FIELD_TRANSACTION },
+ { "ack", -4, 4, 0, ack_names },
+};
+
+static const struct packet_field block_request_fields[] = {
+ COMMON_REQUEST_FIELDS,
+ { "data_length", 96, 16, PACKET_FIELD_DATA_LENGTH | PACKET_FIELD_TRANSACTION },
+ { "extended_tcode", 112, 16, PACKET_FIELD_TRANSACTION },
+ { "crc", 128, 32, PACKET_FIELD_DETAIL },
+ { "data", 160, 0, PACKET_FIELD_TRANSACTION },
+ { "crc", -64, 32, PACKET_FIELD_DETAIL },
+ { "ack", -4, 4, 0, ack_names },
+};
+
+static const struct packet_field write_response_fields[] = {
+ COMMON_RESPONSE_FIELDS,
+ { "reserved", 64, 32, PACKET_FIELD_DETAIL },
+ { "ack", -4, 4, 0, ack_names },
+};
+
+static const struct packet_field iso_data_fields[] = {
+ { "data_length", 0, 16, PACKET_FIELD_DATA_LENGTH },
+ { "tag", 16, 2 },
+ { "channel", 18, 6 },
+ { "tcode", 24, 4, 0, tcode_names },
+ { "sy", 28, 4 },
+ { "crc", 32, 32, PACKET_FIELD_DETAIL },
+ { "data", 64, 0 },
+ { "crc", -64, 32, PACKET_FIELD_DETAIL },
+ { "ack", -4, 4, 0, ack_names },
+};
+
+static const struct packet_info packet_info[] = {
+ {
+ .name = "write_quadlet_request",
+ .type = PACKET_REQUEST,
+ .response_tcode = TCODE_WRITE_RESPONSE,
+ .fields = write_quadlet_request_fields,
+ .field_count = array_length(write_quadlet_request_fields)
+ },
+ {
+ .name = "write_block_request",
+ .type = PACKET_REQUEST,
+ .response_tcode = TCODE_WRITE_RESPONSE,
+ .fields = block_request_fields,
+ .field_count = array_length(block_request_fields)
+ },
+ {
+ .name = "write_response",
+ .type = PACKET_RESPONSE,
+ .fields = write_response_fields,
+ .field_count = array_length(write_response_fields)
+ },
+ {
+ .name = "reserved",
+ .type = PACKET_RESERVED,
+ },
+ {
+ .name = "read_quadlet_request",
+ .type = PACKET_REQUEST,
+ .response_tcode = TCODE_READ_QUADLET_RESPONSE,
+ .fields = read_quadlet_request_fields,
+ .field_count = array_length(read_quadlet_request_fields)
+ },
+ {
+ .name = "read_block_request",
+ .type = PACKET_REQUEST,
+ .response_tcode = TCODE_READ_BLOCK_RESPONSE,
+ .fields = read_block_request_fields,
+ .field_count = array_length(read_block_request_fields)
+ },
+ {
+ .name = "read_quadlet_response",
+ .type = PACKET_RESPONSE,
+ .fields = read_quadlet_response_fields,
+ .field_count = array_length(read_quadlet_response_fields)
+ },
+ {
+ .name = "read_block_response",
+ .type = PACKET_RESPONSE,
+ .fields = block_response_fields,
+ .field_count = array_length(block_response_fields)
+ },
+ {
+ .name = "cycle_start",
+ .type = PACKET_OTHER,
+ .fields = write_quadlet_request_fields,
+ .field_count = array_length(write_quadlet_request_fields)
+ },
+ {
+ .name = "lock_request",
+ .type = PACKET_REQUEST,
+ .fields = block_request_fields,
+ .field_count = array_length(block_request_fields)
+ },
+ {
+ .name = "iso_data",
+ .type = PACKET_OTHER,
+ .fields = iso_data_fields,
+ .field_count = array_length(iso_data_fields)
+ },
+ {
+ .name = "lock_response",
+ .type = PACKET_RESPONSE,
+ .fields = block_response_fields,
+ .field_count = array_length(block_response_fields)
+ },
+};
+
+static int
+handle_request_packet(uint32_t *data, size_t length)
+{
+ struct link_packet *p = (struct link_packet *) data;
+ struct subaction *sa, *prev;
+ struct link_transaction *t;
+
+ t = link_transaction_lookup(p->common.source, p->common.destination,
+ p->common.tlabel);
+ sa = subaction_create(data, length);
+ t->request = sa;
+
+ if (!list_empty(&t->request_list)) {
+ prev = list_tail(&t->request_list,
+ struct subaction, link);
+
+ if (!ACK_BUSY(prev->ack)) {
+ /*
+ * error, we should only see ack_busy_* before the
+ * ack_pending/ack_complete -- this is an ack_pending
+ * instead (ack_complete would have finished the
+ * transaction).
+ */
+ }
+
+ if (prev->packet.common.tcode != sa->packet.common.tcode ||
+ prev->packet.common.tlabel != sa->packet.common.tlabel) {
+ /* memcmp() ? */
+ /* error, these should match for retries. */
+ }
+ }
+
+ list_append(&t->request_list, &sa->link);
+
+ switch (sa->ack) {
+ case ACK_COMPLETE:
+ if (p->common.tcode != TCODE_WRITE_QUADLET_REQUEST &&
+ p->common.tcode != TCODE_WRITE_BLOCK_REQUEST)
+ /* error, unified transactions only allowed for write */;
+ list_remove(&t->link);
+ handle_transaction(t);
+ break;
+
+ case ACK_NO_ACK:
+ case ACK_DATA_ERROR:
+ case ACK_TYPE_ERROR:
+ list_remove(&t->link);
+ handle_transaction(t);
+ break;
+
+ case ACK_PENDING:
+ /* request subaction phase over, wait for response. */
+ break;
+
+ case ACK_BUSY_X:
+ case ACK_BUSY_A:
+ case ACK_BUSY_B:
+ /* ok, wait for retry. */
+ /* check that retry protocol is respected. */
+ break;
+ }
+
+ return 1;
+}
+
+static int
+handle_response_packet(uint32_t *data, size_t length)
+{
+ struct link_packet *p = (struct link_packet *) data;
+ struct subaction *sa, *prev;
+ struct link_transaction *t;
+
+ t = link_transaction_lookup(p->common.destination, p->common.source,
+ p->common.tlabel);
+ if (list_empty(&t->request_list)) {
+ /* unsolicited response */
+ }
+
+ sa = subaction_create(data, length);
+ t->response = sa;
+
+ if (!list_empty(&t->response_list)) {
+ prev = list_tail(&t->response_list, struct subaction, link);
+
+ if (!ACK_BUSY(prev->ack)) {
+ /*
+ * error, we should only see ack_busy_* before the
+ * ack_pending/ack_complete
+ */
+ }
+
+ if (prev->packet.common.tcode != sa->packet.common.tcode ||
+ prev->packet.common.tlabel != sa->packet.common.tlabel) {
+ /* use memcmp() instead? */
+ /* error, these should match for retries. */
+ }
+ } else {
+ prev = list_tail(&t->request_list, struct subaction, link);
+ if (prev->ack != ACK_PENDING) {
+ /*
+ * error, should not get response unless last request got
+ * ack_pending.
+ */
+ }
+
+ if (packet_info[prev->packet.common.tcode].response_tcode !=
+ sa->packet.common.tcode) {
+ /* error, tcode mismatch */
+ }
+ }
+
+ list_append(&t->response_list, &sa->link);
+
+ switch (sa->ack) {
+ case ACK_COMPLETE:
+ case ACK_NO_ACK:
+ case ACK_DATA_ERROR:
+ case ACK_TYPE_ERROR:
+ list_remove(&t->link);
+ handle_transaction(t);
+ /* transaction complete, remove t from pending list. */
+ break;
+
+ case ACK_PENDING:
+ /* error for responses. */
+ break;
+
+ case ACK_BUSY_X:
+ case ACK_BUSY_A:
+ case ACK_BUSY_B:
+ /* no problem, wait for next retry */
+ break;
+ }
+
+ return 1;
+}
+
+static int
+handle_packet(uint32_t *data, size_t length)
+{
+ if (length == 0) {
+ printf("bus reset\r\n");
+ clear_pending_transaction_list();
+ } else if (length > sizeof(struct phy_packet)) {
+ struct link_packet *p = (struct link_packet *) data;
+
+ switch (packet_info[p->common.tcode].type) {
+ case PACKET_REQUEST:
+ return handle_request_packet(data, length);
+
+ case PACKET_RESPONSE:
+ return handle_response_packet(data, length);
+
+ case PACKET_OTHER:
+ case PACKET_RESERVED:
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+static unsigned int
+get_bits(struct link_packet *packet, int offset, int width)
+{
+ uint32_t *data = (uint32_t *) packet;
+ uint32_t index, shift, mask;
+
+ index = offset / 32 + 1;
+ shift = 32 - (offset & 31) - width;
+ mask = width == 32 ? ~0 : (1 << width) - 1;
+
+ return (data[index] >> shift) & mask;
+}
+
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+#define byte_index(i) ((i) ^ 3)
+#elif __BYTE_ORDER == __BIG_ENDIAN
+#define byte_index(i) (i)
+#else
+#error unsupported byte order.
+#endif
+
+static void
+dump_data(unsigned char *data, int length)
+{
+ int i, print_length;
+
+ if (length > 128)
+ print_length = 128;
+ else
+ print_length = length;
+
+ for (i = 0; i < print_length; i++)
+ printf("%s%02hhx",
+ (i % 4 == 0 && i != 0) ? " " : "",
+ data[byte_index(i)]);
+
+ if (print_length < length)
+ printf(" (%d more bytes)", length - print_length);
+}
+
+static void
+decode_link_packet(struct link_packet *packet, size_t length,
+ int include_flags, int exclude_flags)
+{
+ const struct packet_info *pi;
+ int data_length = 0;
+ int i;
+
+ pi = &packet_info[packet->common.tcode];
+
+ for (i = 0; i < pi->field_count; i++) {
+ const struct packet_field *f = &pi->fields[i];
+ int offset;
+
+ if (f->flags & exclude_flags)
+ continue;
+ if (include_flags && !(f->flags & include_flags))
+ continue;
+
+ if (f->offset < 0)
+ offset = length * 8 + f->offset - 32;
+ else
+ offset = f->offset;
+
+ if (f->value_names != NULL) {
+ uint32_t bits;
+
+ bits = get_bits(packet, offset, f->width);
+ printf("%s", f->value_names[bits]);
+ } else if (f->width == 0) {
+ printf("%s=[", f->name);
+ dump_data((unsigned char *) packet + (offset / 8 + 4), data_length);
+ printf("]");
+ } else {
+ unsigned long long bits;
+ int high_width, low_width;
+
+ if ((offset & ~31) != ((offset + f->width - 1) & ~31)) {
+ /* Bit field spans quadlet boundary. */
+ high_width = ((offset + 31) & ~31) - offset;
+ low_width = f->width - high_width;
+
+ bits = get_bits(packet, offset, high_width);
+ bits = (bits << low_width) |
+ get_bits(packet, offset + high_width, low_width);
+ } else {
+ bits = get_bits(packet, offset, f->width);
+ }
+
+ printf("%s=0x%0*llx", f->name, (f->width + 3) / 4, bits);
+
+ if (f->flags & PACKET_FIELD_DATA_LENGTH)
+ data_length = bits;
+ }
+
+ if (i < pi->field_count - 1)
+ printf(", ");
+ }
+}
+
+static void
+print_packet(uint32_t *data, size_t length)
+{
+ int i;
+
+ printf("%6u ", data[0]);
+
+ if (length == 4) {
+ printf("bus reset");
+ } else if (length < sizeof(struct phy_packet)) {
+ printf("short packet: ");
+ for (i = 1; i < length / 4; i++)
+ printf("%s%08x", i == 0 ? "[" : " ", data[i]);
+ printf("]");
+
+ } else if (length == sizeof(struct phy_packet) && data[1] == ~data[2]) {
+ struct phy_packet *pp = (struct phy_packet *) data;
+
+ /* phy packet are 3 quadlets: the 1 quadlet payload,
+ * the bitwise inverse of the payload and the snoop
+ * mode ack */
+
+ switch (pp->common.identifier) {
+ case PHY_PACKET_CONFIGURATION:
+ if (!pp->phy_config.set_root && !pp->phy_config.set_gap_count) {
+ printf("ext phy config: phy_id=%02x", pp->phy_config.root_id);
+ } else {
+ printf("phy config:");
+ if (pp->phy_config.set_root)
+ printf(" set_root_id=%02x", pp->phy_config.root_id);
+ if (pp->phy_config.set_gap_count)
+ printf(" set_gap_count=%d", pp->phy_config.gap_count);
+ }
+ break;
+
+ case PHY_PACKET_LINK_ON:
+ printf("link-on packet, phy_id=%02x", pp->link_on.phy_id);
+ break;
+
+ case PHY_PACKET_SELF_ID:
+ if (pp->self_id.extended) {
+ printf("extended self id: phy_id=%02x, seq=%d",
+ pp->ext_self_id.phy_id, pp->ext_self_id.sequence);
+ } else {
+ static const char * const speed_names[] = {
+ "S100", "S200", "S400", "BETA"
+ };
+ printf("self id: phy_id=%02x, link %s, gap_count=%d, speed=%s%s%s",
+ pp->self_id.phy_id,
+ (pp->self_id.link_active ? "active" : "not active"),
+ pp->self_id.gap_count,
+ speed_names[pp->self_id.phy_speed],
+ (pp->self_id.contender ? ", irm contender" : ""),
+ (pp->self_id.initiated_reset ? ", initiator" : ""));
+ }
+ break;
+ default:
+ printf("unknown phy packet: ");
+ for (i = 1; i < length / 4; i++)
+ printf("%s%08x", i == 0 ? "[" : " ", data[i]);
+ printf("]");
+ break;
+ }
+ } else {
+ struct link_packet *packet = (struct link_packet *) data;
+
+ decode_link_packet(packet, length, 0,
+ option_verbose ? 0 : PACKET_FIELD_DETAIL);
+ }
+
+ if (option_hex) {
+ printf(" [");
+ dump_data((unsigned char *) data + 4, length - 4);
+ printf("]");
+ }
+
+ printf("\r\n");
+}
+
+#define HIDE_CURSOR "\033[?25l"
+#define SHOW_CURSOR "\033[?25h"
+#define CLEAR "\033[H\033[2J"
+
+static void
+print_stats(uint32_t *data, size_t length)
+{
+ static int bus_reset_count, short_packet_count, phy_packet_count;
+ static int tcode_count[16];
+ static struct timeval last_update;
+ struct timeval now;
+ int i;
+
+ if (length == 0)
+ bus_reset_count++;
+ else if (length < sizeof(struct phy_packet))
+ short_packet_count++;
+ else if (length == sizeof(struct phy_packet) && data[1] == ~data[2])
+ phy_packet_count++;
+ else {
+ struct link_packet *packet = (struct link_packet *) data;
+ tcode_count[packet->common.tcode]++;
+ }
+
+ gettimeofday(&now, NULL);
+ if (now.tv_sec <= last_update.tv_sec &&
+ now.tv_usec < last_update.tv_usec + 500000)
+ return;
+
+ last_update = now;
+ printf(CLEAR HIDE_CURSOR
+ " bus resets : %8d\n"
+ " short packets : %8d\n"
+ " phy packets : %8d\n",
+ bus_reset_count, short_packet_count, phy_packet_count);
+
+ for (i = 0; i < array_length(packet_info); i++)
+ if (packet_info[i].type != PACKET_RESERVED)
+ printf(" %-24s: %8d\n", packet_info[i].name, tcode_count[i]);
+ printf(SHOW_CURSOR "\n");
+}
+
+static struct termios saved_attributes;
+
+static void
+reset_input_mode(void)
+{
+ tcsetattr(STDIN_FILENO, TCSANOW, &saved_attributes);
+}
+
+static void
+set_input_mode(void)
+{
+ struct termios tattr;
+
+ /* Make sure stdin is a terminal. */
+ if (!isatty(STDIN_FILENO)) {
+ fprintf(stderr, "Not a terminal.\n");
+ exit(EXIT_FAILURE);
+ }
+
+ /* Save the terminal attributes so we can restore them later. */
+ tcgetattr(STDIN_FILENO, &saved_attributes);
+ atexit(reset_input_mode);
+
+ /* Set the funny terminal modes. */
+ tcgetattr(STDIN_FILENO, &tattr);
+ tattr.c_lflag &= ~(ICANON|ECHO); /* Clear ICANON and ECHO. */
+ tattr.c_cc[VMIN] = 1;
+ tattr.c_cc[VTIME] = 0;
+ tcsetattr(STDIN_FILENO, TCSAFLUSH, &tattr);
+}
+
+int main(int argc, const char *argv[])
+{
+ uint32_t buf[128 * 1024];
+ uint32_t filter;
+ int length, retval, view;
+ int fd = -1;
+ FILE *output = NULL, *input = NULL;
+ poptContext con;
+ char c;
+ struct pollfd pollfds[2];
+
+ sys_sigint_handler = signal(SIGINT, sigint_handler);
+
+ con = poptGetContext(NULL, argc, argv, options, 0);
+ retval = poptGetNextOpt(con);
+ if (retval < -1) {
+ poptPrintUsage(con, stdout, 0);
+ return -1;
+ }
+
+ if (option_version) {
+ printf("dump tool for nosy sniffer, version %s\n", VERSION);
+ return 0;
+ }
+
+ if (__BYTE_ORDER != __LITTLE_ENDIAN)
+ fprintf(stderr, "warning: nosy has only been tested on little "
+ "endian machines\n");
+
+ if (option_input != NULL) {
+ input = fopen(option_input, "r");
+ if (input == NULL) {
+ fprintf(stderr, "Could not open %s, %m\n", option_input);
+ return -1;
+ }
+ } else {
+ fd = open(option_nosy_device, O_RDWR);
+ if (fd < 0) {
+ fprintf(stderr, "Could not open %s, %m\n", option_nosy_device);
+ return -1;
+ }
+ set_input_mode();
+ }
+
+ if (strcmp(option_view, "transaction") == 0)
+ view = VIEW_TRANSACTION;
+ else if (strcmp(option_view, "stats") == 0)
+ view = VIEW_STATS;
+ else
+ view = VIEW_PACKET;
+
+ if (option_output) {
+ output = fopen(option_output, "w");
+ if (output == NULL) {
+ fprintf(stderr, "Could not open %s, %m\n", option_output);
+ return -1;
+ }
+ }
+
+ setvbuf(stdout, NULL, _IOLBF, BUFSIZ);
+
+ filter = ~0;
+ if (!option_iso)
+ filter &= ~(1 << TCODE_STREAM_DATA);
+ if (!option_cycle_start)
+ filter &= ~(1 << TCODE_CYCLE_START);
+ if (view == VIEW_STATS)
+ filter = ~(1 << TCODE_CYCLE_START);
+
+ ioctl(fd, NOSY_IOC_FILTER, filter);
+
+ ioctl(fd, NOSY_IOC_START);
+
+ pollfds[0].fd = fd;
+ pollfds[0].events = POLLIN;
+ pollfds[1].fd = STDIN_FILENO;
+ pollfds[1].events = POLLIN;
+
+ while (run) {
+ if (input != NULL) {
+ if (fread(&length, sizeof length, 1, input) != 1)
+ return 0;
+ fread(buf, 1, length, input);
+ } else {
+ poll(pollfds, 2, -1);
+ if (pollfds[1].revents) {
+ read(STDIN_FILENO, &c, sizeof c);
+ switch (c) {
+ case 'q':
+ if (output != NULL)
+ fclose(output);
+ return 0;
+ }
+ }
+
+ if (pollfds[0].revents)
+ length = read(fd, buf, sizeof buf);
+ else
+ continue;
+ }
+
+ if (output != NULL) {
+ fwrite(&length, sizeof length, 1, output);
+ fwrite(buf, 1, length, output);
+ }
+
+ switch (view) {
+ case VIEW_TRANSACTION:
+ handle_packet(buf, length);
+ break;
+ case VIEW_PACKET:
+ print_packet(buf, length);
+ break;
+ case VIEW_STATS:
+ print_stats(buf, length);
+ break;
+ }
+ }
+
+ if (output != NULL)
+ fclose(output);
+
+ close(fd);
+
+ poptFreeContext(con);
+
+ return 0;
+}
diff --git a/tools/firewire/nosy-dump.h b/tools/firewire/nosy-dump.h
new file mode 100644
index 00000000000..3a4b5b33ba5
--- /dev/null
+++ b/tools/firewire/nosy-dump.h
@@ -0,0 +1,173 @@
+#ifndef __nosy_dump_h__
+#define __nosy_dump_h__
+
+#define array_length(array) (sizeof(array) / sizeof(array[0]))
+
+#define ACK_NO_ACK 0x0
+#define ACK_DONE(a) ((a >> 2) == 0)
+#define ACK_BUSY(a) ((a >> 2) == 1)
+#define ACK_ERROR(a) ((a >> 2) == 3)
+
+#include <stdint.h>
+
+struct phy_packet {
+ uint32_t timestamp;
+ union {
+ struct {
+ uint32_t zero:24;
+ uint32_t phy_id:6;
+ uint32_t identifier:2;
+ } common, link_on;
+
+ struct {
+ uint32_t zero:16;
+ uint32_t gap_count:6;
+ uint32_t set_gap_count:1;
+ uint32_t set_root:1;
+ uint32_t root_id:6;
+ uint32_t identifier:2;
+ } phy_config;
+
+ struct {
+ uint32_t more_packets:1;
+ uint32_t initiated_reset:1;
+ uint32_t port2:2;
+ uint32_t port1:2;
+ uint32_t port0:2;
+ uint32_t power_class:3;
+ uint32_t contender:1;
+ uint32_t phy_delay:2;
+ uint32_t phy_speed:2;
+ uint32_t gap_count:6;
+ uint32_t link_active:1;
+ uint32_t extended:1;
+ uint32_t phy_id:6;
+ uint32_t identifier:2;
+ } self_id;
+
+ struct {
+ uint32_t more_packets:1;
+ uint32_t reserved1:1;
+ uint32_t porth:2;
+ uint32_t portg:2;
+ uint32_t portf:2;
+ uint32_t porte:2;
+ uint32_t portd:2;
+ uint32_t portc:2;
+ uint32_t portb:2;
+ uint32_t porta:2;
+ uint32_t reserved0:2;
+ uint32_t sequence:3;
+ uint32_t extended:1;
+ uint32_t phy_id:6;
+ uint32_t identifier:2;
+ } ext_self_id;
+ };
+ uint32_t inverted;
+ uint32_t ack;
+};
+
+#define TCODE_PHY_PACKET 0x10
+
+#define PHY_PACKET_CONFIGURATION 0x00
+#define PHY_PACKET_LINK_ON 0x01
+#define PHY_PACKET_SELF_ID 0x02
+
+struct link_packet {
+ uint32_t timestamp;
+ union {
+ struct {
+ uint32_t priority:4;
+ uint32_t tcode:4;
+ uint32_t rt:2;
+ uint32_t tlabel:6;
+ uint32_t destination:16;
+
+ uint32_t offset_high:16;
+ uint32_t source:16;
+
+ uint32_t offset_low;
+ } common;
+
+ struct {
+ uint32_t common[3];
+ uint32_t crc;
+ } read_quadlet;
+
+ struct {
+ uint32_t common[3];
+ uint32_t data;
+ uint32_t crc;
+ } read_quadlet_response;
+
+ struct {
+ uint32_t common[3];
+ uint32_t extended_tcode:16;
+ uint32_t data_length:16;
+ uint32_t crc;
+ } read_block;
+
+ struct {
+ uint32_t common[3];
+ uint32_t extended_tcode:16;
+ uint32_t data_length:16;
+ uint32_t crc;
+ uint32_t data[0];
+ /* crc and ack follows. */
+ } read_block_response;
+
+ struct {
+ uint32_t common[3];
+ uint32_t data;
+ uint32_t crc;
+ } write_quadlet;
+
+ struct {
+ uint32_t common[3];
+ uint32_t extended_tcode:16;
+ uint32_t data_length:16;
+ uint32_t crc;
+ uint32_t data[0];
+ /* crc and ack follows. */
+ } write_block;
+
+ struct {
+ uint32_t common[3];
+ uint32_t crc;
+ } write_response;
+
+ struct {
+ uint32_t common[3];
+ uint32_t data;
+ uint32_t crc;
+ } cycle_start;
+
+ struct {
+ uint32_t sy:4;
+ uint32_t tcode:4;
+ uint32_t channel:6;
+ uint32_t tag:2;
+ uint32_t data_length:16;
+
+ uint32_t crc;
+ } iso_data;
+ };
+};
+
+struct subaction {
+ uint32_t ack;
+ size_t length;
+ struct list link;
+ struct link_packet packet;
+};
+
+struct link_transaction {
+ int request_node, response_node, tlabel;
+ struct subaction *request, *response;
+ struct list request_list, response_list;
+ struct list link;
+};
+
+int decode_fcp(struct link_transaction *t);
+
+#endif /* __nosy_dump_h__ */
diff --git a/tools/perf/.gitignore b/tools/perf/.gitignore
index e1d60d78078..cb43289e447 100644
--- a/tools/perf/.gitignore
+++ b/tools/perf/.gitignore
@@ -18,3 +18,5 @@ perf-archive
tags
TAGS
cscope*
+config.mak
+config.mak.autogen
diff --git a/tools/perf/Documentation/perf-buildid-cache.txt b/tools/perf/Documentation/perf-buildid-cache.txt
index 5d1a9500277..c1057701a7d 100644
--- a/tools/perf/Documentation/perf-buildid-cache.txt
+++ b/tools/perf/Documentation/perf-buildid-cache.txt
@@ -12,9 +12,9 @@ SYNOPSIS
DESCRIPTION
-----------
-This command manages the build-id cache. It can add and remove files to the
-cache. In the future it should as well purge older entries, set upper limits
-for the space used by the cache, etc.
+This command manages the build-id cache. It can add and remove files to/from
+the cache. In the future it should as well purge older entries, set upper
+limits for the space used by the cache, etc.
OPTIONS
-------
@@ -23,7 +23,7 @@ OPTIONS
Add specified file to the cache.
-r::
--remove=::
- Remove specified file to the cache.
+ Remove specified file from the cache.
-v::
--verbose::
Be more verbose.
diff --git a/tools/perf/Documentation/perf-probe.txt b/tools/perf/Documentation/perf-probe.txt
index 94a258c96a4..27d52dae5a4 100644
--- a/tools/perf/Documentation/perf-probe.txt
+++ b/tools/perf/Documentation/perf-probe.txt
@@ -31,6 +31,10 @@ OPTIONS
--vmlinux=PATH::
Specify vmlinux path which has debuginfo (Dwarf binary).
+-s::
+--source=PATH::
+ Specify path to kernel source.
+
-v::
--verbose::
Be more verbose (show parsed arguments, etc).
@@ -90,8 +94,8 @@ Each probe argument follows below syntax.
[NAME=]LOCALVAR|$retval|%REG|@SYMBOL[:TYPE]
-'NAME' specifies the name of this argument (optional). You can use the name of local variable, local data structure member (e.g. var->field, var.field2), or kprobe-tracer argument format (e.g. $retval, %ax, etc). Note that the name of this argument will be set as the last member name if you specify a local data structure member (e.g. field2 for 'var->field1.field2'.)
-'TYPE' casts the type of this argument (optional). If omitted, perf probe automatically set the type based on debuginfo.
+'NAME' specifies the name of this argument (optional). You can use the name of local variable, local data structure member (e.g. var->field, var.field2), local array with fixed index (e.g. array[1], var->array[0], var->pointer[2]), or kprobe-tracer argument format (e.g. $retval, %ax, etc). Note that the name of this argument will be set as the last member name if you specify a local data structure member (e.g. field2 for 'var->field1.field2'.)
+'TYPE' casts the type of this argument (optional). If omitted, perf probe automatically set the type based on debuginfo. You can specify 'string' type only for the local variable or structure member which is an array of or a pointer to 'char' or 'unsigned char' type.
LINE SYNTAX
-----------
diff --git a/tools/perf/Documentation/perf-record.txt b/tools/perf/Documentation/perf-record.txt
index 34e255fc3e2..3ee27dccfde 100644
--- a/tools/perf/Documentation/perf-record.txt
+++ b/tools/perf/Documentation/perf-record.txt
@@ -103,6 +103,19 @@ OPTIONS
--raw-samples::
Collect raw sample records from all opened counters (default for tracepoint counters).
+-C::
+--cpu::
+Collect samples only on the list of cpus provided. Multiple CPUs can be provided as a
+comma-sperated list with no space: 0,1. Ranges of CPUs are specified with -: 0-2.
+In per-thread mode with inheritance mode on (default), samples are captured only when
+the thread executes on the designated CPUs. Default is to monitor all CPUs.
+
+-N::
+--no-buildid-cache::
+Do not update the builid cache. This saves some overhead in situations
+where the information in the perf.data file (which includes buildids)
+is sufficient.
+
SEE ALSO
--------
linkperf:perf-stat[1], linkperf:perf-list[1]
diff --git a/tools/perf/Documentation/perf-stat.txt b/tools/perf/Documentation/perf-stat.txt
index 909fa766fa1..4b3a2d46b43 100644
--- a/tools/perf/Documentation/perf-stat.txt
+++ b/tools/perf/Documentation/perf-stat.txt
@@ -46,6 +46,13 @@ OPTIONS
-B::
print large numbers with thousands' separators according to locale
+-C::
+--cpu=::
+Count only on the list of cpus provided. Multiple CPUs can be provided as a
+comma-sperated list with no space: 0,1. Ranges of CPUs are specified with -: 0-2.
+In per-thread mode, this option is ignored. The -a option is still necessary
+to activate system-wide monitoring. Default is to count on all CPUs.
+
EXAMPLES
--------
diff --git a/tools/perf/Documentation/perf-top.txt b/tools/perf/Documentation/perf-top.txt
index 785b9fc32a4..1f9687663f2 100644
--- a/tools/perf/Documentation/perf-top.txt
+++ b/tools/perf/Documentation/perf-top.txt
@@ -25,9 +25,11 @@ OPTIONS
--count=<count>::
Event period to sample.
--C <cpu>::
---CPU=<cpu>::
- CPU to profile.
+-C <cpu-list>::
+--cpu=<cpu>::
+Monitor only on the list of cpus provided. Multiple CPUs can be provided as a
+comma-sperated list with no space: 0,1. Ranges of CPUs are specified with -: 0-2.
+Default is to monitor all CPUS.
-d <seconds>::
--delay=<seconds>::
diff --git a/tools/perf/MANIFEST b/tools/perf/MANIFEST
new file mode 100644
index 00000000000..8c7fc0c8f0b
--- /dev/null
+++ b/tools/perf/MANIFEST
@@ -0,0 +1,12 @@
+tools/perf
+include/linux/perf_event.h
+include/linux/rbtree.h
+include/linux/list.h
+include/linux/hash.h
+include/linux/stringify.h
+lib/rbtree.c
+include/linux/swab.h
+arch/*/include/asm/unistd*.h
+include/linux/poison.h
+include/linux/magic.h
+include/linux/hw_breakpoint.h
diff --git a/tools/perf/Makefile b/tools/perf/Makefile
index d75c28a825f..26f626d45a9 100644
--- a/tools/perf/Makefile
+++ b/tools/perf/Makefile
@@ -285,14 +285,10 @@ else
QUIET_STDERR = ">/dev/null 2>&1"
endif
-BITBUCKET = "/dev/null"
+-include feature-tests.mak
-ifneq ($(shell sh -c "(echo '\#include <stdio.h>'; echo 'int main(void) { return puts(\"hi\"); }') | $(CC) -x c - $(ALL_CFLAGS) -o $(BITBUCKET) "$(QUIET_STDERR)" && echo y"), y)
- BITBUCKET = .perf.dev.null
-endif
-
-ifeq ($(shell sh -c "echo 'int foo(void) {char X[2]; return 3;}' | $(CC) -x c -c -Werror -fstack-protector-all - -o $(BITBUCKET) "$(QUIET_STDERR)" && echo y"), y)
- CFLAGS := $(CFLAGS) -fstack-protector-all
+ifeq ($(call try-cc,$(SOURCE_HELLO),-Werror -fstack-protector-all),y)
+ CFLAGS := $(CFLAGS) -fstack-protector-all
endif
@@ -508,7 +504,8 @@ PERFLIBS = $(LIB_FILE)
-include config.mak
ifndef NO_DWARF
-ifneq ($(shell sh -c "(echo '\#include <dwarf.h>'; echo '\#include <libdw.h>'; echo '\#include <version.h>'; echo '\#ifndef _ELFUTILS_PREREQ'; echo '\#error'; echo '\#endif'; echo 'int main(void) { Dwarf *dbg; dbg = dwarf_begin(0, DWARF_C_READ); return (long)dbg; }') | $(CC) -x c - $(ALL_CFLAGS) -I/usr/include/elfutils -ldw -lelf -o $(BITBUCKET) $(ALL_LDFLAGS) $(EXTLIBS) "$(QUIET_STDERR)" && echo y"), y)
+FLAGS_DWARF=$(ALL_CFLAGS) -I/usr/include/elfutils -ldw -lelf $(ALL_LDFLAGS) $(EXTLIBS)
+ifneq ($(call try-cc,$(SOURCE_DWARF),$(FLAGS_DWARF)),y)
msg := $(warning No libdw.h found or old libdw.h found or elfutils is older than 0.138, disables dwarf support. Please install new elfutils-devel/libdw-dev);
NO_DWARF := 1
endif # Dwarf support
@@ -536,16 +533,18 @@ ifneq ($(OUTPUT),)
BASIC_CFLAGS += -I$(OUTPUT)
endif
-ifeq ($(shell sh -c "(echo '\#include <libelf.h>'; echo 'int main(void) { Elf * elf = elf_begin(0, ELF_C_READ, 0); return (long)elf; }') | $(CC) -x c - $(ALL_CFLAGS) -o $(BITBUCKET) $(ALL_LDFLAGS) $(EXTLIBS) "$(QUIET_STDERR)" && echo y"), y)
-ifneq ($(shell sh -c "(echo '\#include <gnu/libc-version.h>'; echo 'int main(void) { const char * version = gnu_get_libc_version(); return (long)version; }') | $(CC) -x c - $(ALL_CFLAGS) -o $(BITBUCKET) $(ALL_LDFLAGS) $(EXTLIBS) "$(QUIET_STDERR)" && echo y"), y)
- msg := $(error No gnu/libc-version.h found, please install glibc-dev[el]/glibc-static);
+FLAGS_LIBELF=$(ALL_CFLAGS) $(ALL_LDFLAGS) $(EXTLIBS)
+ifneq ($(call try-cc,$(SOURCE_LIBELF),$(FLAGS_LIBELF)),y)
+ FLAGS_GLIBC=$(ALL_CFLAGS) $(ALL_LDFLAGS)
+ ifneq ($(call try-cc,$(SOURCE_GLIBC),$(FLAGS_GLIBC)),y)
+ msg := $(error No gnu/libc-version.h found, please install glibc-dev[el]/glibc-static);
+ else
+ msg := $(error No libelf.h/libelf found, please install libelf-dev/elfutils-libelf-devel);
+ endif
endif
- ifneq ($(shell sh -c "(echo '\#include <libelf.h>'; echo 'int main(void) { Elf * elf = elf_begin(0, ELF_C_READ_MMAP, 0); return (long)elf; }') | $(CC) -x c - $(ALL_CFLAGS) -o $(BITBUCKET) $(ALL_LDFLAGS) $(EXTLIBS) "$(QUIET_STDERR)" && echo y"), y)
- BASIC_CFLAGS += -DLIBELF_NO_MMAP
- endif
-else
- msg := $(error No libelf.h/libelf found, please install libelf-dev/elfutils-libelf-devel and glibc-dev[el]);
+ifneq ($(call try-cc,$(SOURCE_ELF_MMAP),$(FLAGS_COMMON)),y)
+ BASIC_CFLAGS += -DLIBELF_NO_MMAP
endif
ifndef NO_DWARF
@@ -561,64 +560,73 @@ endif # NO_DWARF
ifdef NO_NEWT
BASIC_CFLAGS += -DNO_NEWT_SUPPORT
else
-ifneq ($(shell sh -c "(echo '\#include <newt.h>'; echo 'int main(void) { newtInit(); newtCls(); return newtFinished(); }') | $(CC) -x c - $(ALL_CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -lnewt -o $(BITBUCKET) $(ALL_LDFLAGS) $(EXTLIBS) "$(QUIET_STDERR)" && echo y"), y)
- msg := $(warning newt not found, disables TUI support. Please install newt-devel or libnewt-dev);
- BASIC_CFLAGS += -DNO_NEWT_SUPPORT
-else
- # Fedora has /usr/include/slang/slang.h, but ubuntu /usr/include/slang.h
- BASIC_CFLAGS += -I/usr/include/slang
- EXTLIBS += -lnewt -lslang
- LIB_OBJS += $(OUTPUT)util/newt.o
-endif
-endif # NO_NEWT
-
-ifndef NO_LIBPERL
-PERL_EMBED_LDOPTS = `perl -MExtUtils::Embed -e ldopts 2>/dev/null`
-PERL_EMBED_CCOPTS = `perl -MExtUtils::Embed -e ccopts 2>/dev/null`
+ FLAGS_NEWT=$(ALL_CFLAGS) $(ALL_LDFLAGS) $(EXTLIBS) -lnewt
+ ifneq ($(call try-cc,$(SOURCE_NEWT),$(FLAGS_NEWT)),y)
+ msg := $(warning newt not found, disables TUI support. Please install newt-devel or libnewt-dev);
+ BASIC_CFLAGS += -DNO_NEWT_SUPPORT
+ else
+ # Fedora has /usr/include/slang/slang.h, but ubuntu /usr/include/slang.h
+ BASIC_CFLAGS += -I/usr/include/slang
+ EXTLIBS += -lnewt -lslang
+ LIB_OBJS += $(OUTPUT)util/newt.o
+ endif
endif
-ifneq ($(shell sh -c "(echo '\#include <EXTERN.h>'; echo '\#include <perl.h>'; echo 'int main(void) { perl_alloc(); return 0; }') | $(CC) -x c - $(PERL_EMBED_CCOPTS) -o $(BITBUCKET) $(PERL_EMBED_LDOPTS) > /dev/null 2>&1 && echo y"), y)
+ifdef NO_LIBPERL
BASIC_CFLAGS += -DNO_LIBPERL
else
- ALL_LDFLAGS += $(PERL_EMBED_LDOPTS)
- LIB_OBJS += $(OUTPUT)util/scripting-engines/trace-event-perl.o
- LIB_OBJS += $(OUTPUT)scripts/perl/Perf-Trace-Util/Context.o
-endif
+ PERL_EMBED_LDOPTS = `perl -MExtUtils::Embed -e ldopts 2>/dev/null`
+ PERL_EMBED_CCOPTS = `perl -MExtUtils::Embed -e ccopts 2>/dev/null`
+ FLAGS_PERL_EMBED=$(PERL_EMBED_CCOPTS) $(PERL_EMBED_LDOPTS)
-ifndef NO_LIBPYTHON
-PYTHON_EMBED_LDOPTS = `python-config --ldflags 2>/dev/null`
-PYTHON_EMBED_CCOPTS = `python-config --cflags 2>/dev/null`
+ ifneq ($(call try-cc,$(SOURCE_PERL_EMBED),$(FLAGS_PERL_EMBED)),y)
+ BASIC_CFLAGS += -DNO_LIBPERL
+ else
+ ALL_LDFLAGS += $(PERL_EMBED_LDOPTS)
+ LIB_OBJS += $(OUTPUT)util/scripting-engines/trace-event-perl.o
+ LIB_OBJS += $(OUTPUT)scripts/perl/Perf-Trace-Util/Context.o
+ endif
endif
-ifneq ($(shell sh -c "(echo '\#include <Python.h>'; echo 'int main(void) { Py_Initialize(); return 0; }') | $(CC) -x c - $(PYTHON_EMBED_CCOPTS) -o $(BITBUCKET) $(PYTHON_EMBED_LDOPTS) > /dev/null 2>&1 && echo y"), y)
+ifdef NO_LIBPYTHON
BASIC_CFLAGS += -DNO_LIBPYTHON
else
- ALL_LDFLAGS += $(PYTHON_EMBED_LDOPTS)
- LIB_OBJS += $(OUTPUT)util/scripting-engines/trace-event-python.o
- LIB_OBJS += $(OUTPUT)scripts/python/Perf-Trace-Util/Context.o
+ PYTHON_EMBED_LDOPTS = `python-config --ldflags 2>/dev/null`
+ PYTHON_EMBED_CCOPTS = `python-config --cflags 2>/dev/null`
+ FLAGS_PYTHON_EMBED=$(PYTHON_EMBED_CCOPTS) $(PYTHON_EMBED_LDOPTS)
+ ifneq ($(call try-cc,$(SOURCE_PYTHON_EMBED),$(FLAGS_PYTHON_EMBED)),y)
+ BASIC_CFLAGS += -DNO_LIBPYTHON
+ else
+ ALL_LDFLAGS += $(PYTHON_EMBED_LDOPTS)
+ LIB_OBJS += $(OUTPUT)util/scripting-engines/trace-event-python.o
+ LIB_OBJS += $(OUTPUT)scripts/python/Perf-Trace-Util/Context.o
+ endif
endif
ifdef NO_DEMANGLE
BASIC_CFLAGS += -DNO_DEMANGLE
else
- ifdef HAVE_CPLUS_DEMANGLE
+ ifdef HAVE_CPLUS_DEMANGLE
EXTLIBS += -liberty
BASIC_CFLAGS += -DHAVE_CPLUS_DEMANGLE
- else
- has_bfd := $(shell sh -c "(echo '\#include <bfd.h>'; echo 'int main(void) { bfd_demangle(0, 0, 0); return 0; }') | $(CC) -x c - $(ALL_CFLAGS) -o $(BITBUCKET) $(ALL_LDFLAGS) $(EXTLIBS) -lbfd "$(QUIET_STDERR)" && echo y")
-
+ else
+ FLAGS_BFD=$(ALL_CFLAGS) $(ALL_LDFLAGS) $(EXTLIBS) -lbfd
+ has_bfd := $(call try-cc,$(SOURCE_BFD),$(FLAGS_BFD))
ifeq ($(has_bfd),y)
EXTLIBS += -lbfd
else
- has_bfd_iberty := $(shell sh -c "(echo '\#include <bfd.h>'; echo 'int main(void) { bfd_demangle(0, 0, 0); return 0; }') | $(CC) -x c - $(ALL_CFLAGS) -o $(BITBUCKET) $(ALL_LDFLAGS) $(EXTLIBS) -lbfd -liberty "$(QUIET_STDERR)" && echo y")
+ FLAGS_BFD_IBERTY=$(FLAGS_BFD) -liberty
+ has_bfd_iberty := $(call try-cc,$(SOURCE_BFD),$(FLAGS_BFD_IBERTY))
ifeq ($(has_bfd_iberty),y)
EXTLIBS += -lbfd -liberty
else
- has_bfd_iberty_z := $(shell sh -c "(echo '\#include <bfd.h>'; echo 'int main(void) { bfd_demangle(0, 0, 0); return 0; }') | $(CC) -x c - $(ALL_CFLAGS) -o $(BITBUCKET) $(ALL_LDFLAGS) $(EXTLIBS) -lbfd -liberty -lz "$(QUIET_STDERR)" && echo y")
+ FLAGS_BFD_IBERTY_Z=$(FLAGS_BFD_IBERTY) -lz
+ has_bfd_iberty_z := $(call try-cc,$(SOURCE_BFD),$(FLAGS_BFD_IBERTY_Z))
ifeq ($(has_bfd_iberty_z),y)
EXTLIBS += -lbfd -liberty -lz
else
- has_cplus_demangle := $(shell sh -c "(echo 'extern char *cplus_demangle(const char *, int);'; echo 'int main(void) { cplus_demangle(0, 0); return 0; }') | $(CC) -x c - $(ALL_CFLAGS) -o $(BITBUCKET) $(ALL_LDFLAGS) $(EXTLIBS) -liberty "$(QUIET_STDERR)" && echo y")
+ FLAGS_CPLUS_DEMANGLE=$(ALL_CFLAGS) $(ALL_LDFLAGS) $(EXTLIBS) -liberty
+ has_cplus_demangle := $(call try-cc,$(SOURCE_CPLUS_DEMANGLE),$(FLAGS_CPLUS_DEMANGLE))
ifeq ($(has_cplus_demangle),y)
EXTLIBS += -liberty
BASIC_CFLAGS += -DHAVE_CPLUS_DEMANGLE
@@ -867,7 +875,7 @@ export TAR INSTALL DESTDIR SHELL_PATH
SHELL = $(SHELL_PATH)
-all:: .perf.dev.null shell_compatibility_test $(ALL_PROGRAMS) $(BUILT_INS) $(OTHER_PROGRAMS) $(OUTPUT)PERF-BUILD-OPTIONS
+all:: shell_compatibility_test $(ALL_PROGRAMS) $(BUILT_INS) $(OTHER_PROGRAMS) $(OUTPUT)PERF-BUILD-OPTIONS
ifneq (,$X)
$(foreach p,$(patsubst %$X,%,$(filter %$X,$(ALL_PROGRAMS) $(BUILT_INS) perf$X)), test '$p' -ef '$p$X' || $(RM) '$p';)
endif
@@ -1197,11 +1205,6 @@ clean:
.PHONY: .FORCE-PERF-VERSION-FILE TAGS tags cscope .FORCE-PERF-CFLAGS
.PHONY: .FORCE-PERF-BUILD-OPTIONS
-.perf.dev.null:
- touch .perf.dev.null
-
-.INTERMEDIATE: .perf.dev.null
-
### Make sure built-ins do not have dups and listed in perf.c
#
check-builtins::
diff --git a/tools/perf/arch/sh/Makefile b/tools/perf/arch/sh/Makefile
new file mode 100644
index 00000000000..15130b50dfe
--- /dev/null
+++ b/tools/perf/arch/sh/Makefile
@@ -0,0 +1,4 @@
+ifndef NO_DWARF
+PERF_HAVE_DWARF_REGS := 1
+LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/dwarf-regs.o
+endif
diff --git a/fs/nilfs2/bmap_union.h b/tools/perf/arch/sh/util/dwarf-regs.c
index d41509bff47..a11edb007a6 100644
--- a/fs/nilfs2/bmap_union.h
+++ b/tools/perf/arch/sh/util/dwarf-regs.c
@@ -1,7 +1,7 @@
/*
- * bmap_union.h - NILFS block mapping.
+ * Mapping of DWARF debug register numbers into register names.
*
- * Copyright (C) 2006-2008 Nippon Telegraph and Telephone Corporation.
+ * Copyright (C) 2010 Matt Fleming <matt@console-pimps.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
@@ -15,28 +15,41 @@
*
* 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
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
- * Written by Koji Sato <koji@osrg.net>.
*/
-#ifndef _NILFS_BMAP_UNION_H
-#define _NILFS_BMAP_UNION_H
+#include <libio.h>
+#include <dwarf-regs.h>
-#include "bmap.h"
-#include "direct.h"
-#include "btree.h"
-
-/**
- * nilfs_bmap_union -
- * @bi_bmap: bmap structure
- * @bi_btree: direct map structure
- * @bi_direct: B-tree structure
+/*
+ * Generic dwarf analysis helpers
*/
-union nilfs_bmap_union {
- struct nilfs_bmap bi_bmap;
- struct nilfs_direct bi_direct;
- struct nilfs_btree bi_btree;
+
+#define SH_MAX_REGS 18
+const char *sh_regs_table[SH_MAX_REGS] = {
+ "r0",
+ "r1",
+ "r2",
+ "r3",
+ "r4",
+ "r5",
+ "r6",
+ "r7",
+ "r8",
+ "r9",
+ "r10",
+ "r11",
+ "r12",
+ "r13",
+ "r14",
+ "r15",
+ "pc",
+ "pr",
};
-#endif /* _NILFS_BMAP_UNION_H */
+/* Return architecture dependent register string (for kprobe-tracer) */
+const char *get_arch_regstr(unsigned int n)
+{
+ return (n <= SH_MAX_REGS) ? sh_regs_table[n] : NULL;
+}
diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c
index 96db5248e99..fd20670ce98 100644
--- a/tools/perf/builtin-annotate.c
+++ b/tools/perf/builtin-annotate.c
@@ -61,11 +61,9 @@ static int hists__add_entry(struct hists *self, struct addr_location *al)
static int process_sample_event(event_t *event, struct perf_session *session)
{
struct addr_location al;
+ struct sample_data data;
- dump_printf("(IP, %d): %d: %#Lx\n", event->header.misc,
- event->ip.pid, event->ip.ip);
-
- if (event__preprocess_sample(event, session, &al, NULL) < 0) {
+ if (event__preprocess_sample(event, session, &al, &data, NULL) < 0) {
pr_warning("problem processing %d event, skipping it.\n",
event->header.type);
return -1;
diff --git a/tools/perf/builtin-buildid-cache.c b/tools/perf/builtin-buildid-cache.c
index f8e3d185202..29ad20e6791 100644
--- a/tools/perf/builtin-buildid-cache.c
+++ b/tools/perf/builtin-buildid-cache.c
@@ -78,8 +78,7 @@ static int __cmd_buildid_cache(void)
struct str_node *pos;
char debugdir[PATH_MAX];
- snprintf(debugdir, sizeof(debugdir), "%s/%s", getenv("HOME"),
- DEBUG_CACHE_DIR);
+ snprintf(debugdir, sizeof(debugdir), "%s", buildid_dir);
if (add_name_list_str) {
list = strlist__new(true, add_name_list_str);
diff --git a/tools/perf/builtin-buildid-list.c b/tools/perf/builtin-buildid-list.c
index 99890728409..44a47e13bd6 100644
--- a/tools/perf/builtin-buildid-list.c
+++ b/tools/perf/builtin-buildid-list.c
@@ -43,10 +43,8 @@ static int __cmd_buildid_list(void)
if (session == NULL)
return -1;
- if (with_hits) {
- symbol_conf.full_paths = true;
+ if (with_hits)
perf_session__process_events(session, &build_id__mark_dso_hit_ops);
- }
perf_session__fprintf_dsos_buildid(session, stdout, with_hits);
diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c
index a6e2fdc7a04..fca1d440291 100644
--- a/tools/perf/builtin-diff.c
+++ b/tools/perf/builtin-diff.c
@@ -35,10 +35,7 @@ static int diff__process_sample_event(event_t *event, struct perf_session *sessi
struct addr_location al;
struct sample_data data = { .period = 1, };
- dump_printf("(IP, %d): %d: %#Lx\n", event->header.misc,
- event->ip.pid, event->ip.ip);
-
- if (event__preprocess_sample(event, session, &al, NULL) < 0) {
+ if (event__preprocess_sample(event, session, &al, &data, NULL) < 0) {
pr_warning("problem processing %d event, skipping it.\n",
event->header.type);
return -1;
@@ -47,8 +44,6 @@ static int diff__process_sample_event(event_t *event, struct perf_session *sessi
if (al.filtered || al.sym == NULL)
return 0;
- event__parse_sample(event, session->sample_type, &data);
-
if (hists__add_entry(&session->hists, &al, data.period)) {
pr_warning("problem incrementing symbol period, skipping event\n");
return -1;
@@ -185,8 +180,6 @@ static const struct option options[] = {
OPT_BOOLEAN('f', "force", &force, "don't complain, do it"),
OPT_BOOLEAN('m', "modules", &symbol_conf.use_modules,
"load module symbols - WARNING: use only with -k and LIVE kernel"),
- OPT_BOOLEAN('P', "full-paths", &symbol_conf.full_paths,
- "Don't shorten the pathnames taking into account the cwd"),
OPT_STRING('d', "dsos", &symbol_conf.dso_list_str, "dso[,dso...]",
"only consider symbols in these dsos"),
OPT_STRING('C', "comms", &symbol_conf.comm_list_str, "comm[,comm...]",
diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c
index e4a4da32a56..199d5e19554 100644
--- a/tools/perf/builtin-probe.c
+++ b/tools/perf/builtin-probe.c
@@ -182,6 +182,8 @@ static const struct option options[] = {
"Show source code lines.", opt_show_lines),
OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name,
"file", "vmlinux pathname"),
+ OPT_STRING('s', "source", &symbol_conf.source_prefix,
+ "directory", "path to kernel source"),
#endif
OPT__DRY_RUN(&probe_event_dry_run),
OPT_INTEGER('\0', "max-probes", &params.max_probe_points,
@@ -265,4 +267,3 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used)
}
return 0;
}
-
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index 711745f56bb..ff77b805de7 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -49,7 +49,6 @@ static int group = 0;
static int realtime_prio = 0;
static bool raw_samples = false;
static bool system_wide = false;
-static int profile_cpu = -1;
static pid_t target_pid = -1;
static pid_t target_tid = -1;
static pid_t *all_tids = NULL;
@@ -61,6 +60,7 @@ static bool call_graph = false;
static bool inherit_stat = false;
static bool no_samples = false;
static bool sample_address = false;
+static bool no_buildid = false;
static long samples = 0;
static u64 bytes_written = 0;
@@ -74,6 +74,7 @@ static int file_new = 1;
static off_t post_processing_offset;
static struct perf_session *session;
+static const char *cpu_list;
struct mmap_data {
int counter;
@@ -268,12 +269,17 @@ static void create_counter(int counter, int cpu)
if (inherit_stat)
attr->inherit_stat = 1;
- if (sample_address)
+ if (sample_address) {
attr->sample_type |= PERF_SAMPLE_ADDR;
+ attr->mmap_data = track;
+ }
if (call_graph)
attr->sample_type |= PERF_SAMPLE_CALLCHAIN;
+ if (system_wide)
+ attr->sample_type |= PERF_SAMPLE_CPU;
+
if (raw_samples) {
attr->sample_type |= PERF_SAMPLE_TIME;
attr->sample_type |= PERF_SAMPLE_RAW;
@@ -300,7 +306,7 @@ try_again:
die("Permission error - are you root?\n"
"\t Consider tweaking"
" /proc/sys/kernel/perf_event_paranoid.\n");
- else if (err == ENODEV && profile_cpu != -1) {
+ else if (err == ENODEV && cpu_list) {
die("No such device - did you specify"
" an out-of-range profile CPU?\n");
}
@@ -433,14 +439,14 @@ static void atexit_header(void)
process_buildids();
perf_header__write(&session->header, output, true);
+ perf_session__delete(session);
+ symbol__exit();
}
}
static void event__synthesize_guest_os(struct machine *machine, void *data)
{
int err;
- char *guest_kallsyms;
- char path[PATH_MAX];
struct perf_session *psession = data;
if (machine__is_host(machine))
@@ -460,13 +466,6 @@ static void event__synthesize_guest_os(struct machine *machine, void *data)
pr_err("Couldn't record guest kernel [%d]'s reference"
" relocation symbol.\n", machine->pid);
- if (machine__is_default_guest(machine))
- guest_kallsyms = (char *) symbol_conf.default_guest_kallsyms;
- else {
- sprintf(path, "%s/proc/kallsyms", machine->root_dir);
- guest_kallsyms = path;
- }
-
/*
* We use _stext for guest kernel because guest kernel's /proc/kallsyms
* have no _text sometimes.
@@ -561,12 +560,15 @@ static int __cmd_record(int argc, const char **argv)
if (!file_new) {
err = perf_header__read(session, output);
if (err < 0)
- return err;
+ goto out_delete_session;
}
if (have_tracepoints(attrs, nr_counters))
perf_header__set_feat(&session->header, HEADER_TRACE_INFO);
+ /*
+ * perf_session__delete(session) will be called at atexit_header()
+ */
atexit(atexit_header);
if (forks) {
@@ -622,10 +624,15 @@ static int __cmd_record(int argc, const char **argv)
close(child_ready_pipe[0]);
}
- if ((!system_wide && no_inherit) || profile_cpu != -1) {
- open_counters(profile_cpu);
+ nr_cpus = read_cpu_map(cpu_list);
+ if (nr_cpus < 1) {
+ perror("failed to collect number of CPUs\n");
+ return -1;
+ }
+
+ if (!system_wide && no_inherit && !cpu_list) {
+ open_counters(-1);
} else {
- nr_cpus = read_cpu_map();
for (i = 0; i < nr_cpus; i++)
open_counters(cpumap[i]);
}
@@ -704,7 +711,7 @@ static int __cmd_record(int argc, const char **argv)
if (perf_guest)
perf_session__process_machines(session, event__synthesize_guest_os);
- if (!system_wide && profile_cpu == -1)
+ if (!system_wide)
event__synthesize_thread(target_tid, process_synthesized_event,
session);
else
@@ -766,6 +773,10 @@ static int __cmd_record(int argc, const char **argv)
bytes_written / 24);
return 0;
+
+out_delete_session:
+ perf_session__delete(session);
+ return err;
}
static const char * const record_usage[] = {
@@ -794,8 +805,8 @@ static const struct option options[] = {
"system-wide collection from all CPUs"),
OPT_BOOLEAN('A', "append", &append_file,
"append to the output file to do incremental profiling"),
- OPT_INTEGER('C', "profile_cpu", &profile_cpu,
- "CPU to profile on"),
+ OPT_STRING('C', "cpu", &cpu_list, "cpu",
+ "list of cpus to monitor"),
OPT_BOOLEAN('f', "force", &force,
"overwrite existing data file (deprecated)"),
OPT_U64('c', "count", &user_interval, "event period to sample"),
@@ -815,17 +826,19 @@ static const struct option options[] = {
"Sample addresses"),
OPT_BOOLEAN('n', "no-samples", &no_samples,
"don't sample"),
+ OPT_BOOLEAN('N', "no-buildid-cache", &no_buildid,
+ "do not update the buildid cache"),
OPT_END()
};
int cmd_record(int argc, const char **argv, const char *prefix __used)
{
- int i,j;
+ int i, j, err = -ENOMEM;
argc = parse_options(argc, argv, options, record_usage,
PARSE_OPT_STOP_AT_NON_OPTION);
if (!argc && target_pid == -1 && target_tid == -1 &&
- !system_wide && profile_cpu == -1)
+ !system_wide && !cpu_list)
usage_with_options(record_usage, options);
if (force && append_file) {
@@ -839,6 +852,8 @@ int cmd_record(int argc, const char **argv, const char *prefix __used)
}
symbol__init();
+ if (no_buildid)
+ disable_buildid_cache();
if (!nr_counters) {
nr_counters = 1;
@@ -857,7 +872,7 @@ int cmd_record(int argc, const char **argv, const char *prefix __used)
} else {
all_tids=malloc(sizeof(pid_t));
if (!all_tids)
- return -ENOMEM;
+ goto out_symbol_exit;
all_tids[0] = target_tid;
thread_num = 1;
@@ -867,13 +882,13 @@ int cmd_record(int argc, const char **argv, const char *prefix __used)
for (j = 0; j < MAX_COUNTERS; j++) {
fd[i][j] = malloc(sizeof(int)*thread_num);
if (!fd[i][j])
- return -ENOMEM;
+ goto out_free_fd;
}
}
event_array = malloc(
sizeof(struct pollfd)*MAX_NR_CPUS*MAX_COUNTERS*thread_num);
if (!event_array)
- return -ENOMEM;
+ goto out_free_fd;
if (user_interval != ULLONG_MAX)
default_interval = user_interval;
@@ -889,8 +904,22 @@ int cmd_record(int argc, const char **argv, const char *prefix __used)
default_interval = freq;
} else {
fprintf(stderr, "frequency and count are zero, aborting\n");
- exit(EXIT_FAILURE);
+ err = -EINVAL;
+ goto out_free_event_array;
}
- return __cmd_record(argc, argv);
+ err = __cmd_record(argc, argv);
+
+out_free_event_array:
+ free(event_array);
+out_free_fd:
+ for (i = 0; i < MAX_NR_CPUS; i++) {
+ for (j = 0; j < MAX_COUNTERS; j++)
+ free(fd[i][j]);
+ }
+ free(all_tids);
+ all_tids = NULL;
+out_symbol_exit:
+ symbol__exit();
+ return err;
}
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index fd7407c7205..2f4b92925b2 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -155,30 +155,7 @@ static int process_sample_event(event_t *event, struct perf_session *session)
struct addr_location al;
struct perf_event_attr *attr;
- event__parse_sample(event, session->sample_type, &data);
-
- dump_printf("(IP, %d): %d/%d: %#Lx period: %Ld\n", event->header.misc,
- data.pid, data.tid, data.ip, data.period);
-
- if (session->sample_type & PERF_SAMPLE_CALLCHAIN) {
- unsigned int i;
-
- dump_printf("... chain: nr:%Lu\n", data.callchain->nr);
-
- if (!ip_callchain__valid(data.callchain, event)) {
- pr_debug("call-chain problem with event, "
- "skipping it.\n");
- return 0;
- }
-
- if (dump_trace) {
- for (i = 0; i < data.callchain->nr; i++)
- dump_printf("..... %2d: %016Lx\n",
- i, data.callchain->ips[i]);
- }
- }
-
- if (event__preprocess_sample(event, session, &al, NULL) < 0) {
+ if (event__preprocess_sample(event, session, &al, &data, NULL) < 0) {
fprintf(stderr, "problem processing %d event, skipping it.\n",
event->header.type);
return -1;
@@ -464,8 +441,6 @@ static const struct option options[] = {
"pretty printing style key: normal raw"),
OPT_STRING('s', "sort", &sort_order, "key[,key2...]",
"sort by key(s): pid, comm, dso, symbol, parent"),
- OPT_BOOLEAN('P', "full-paths", &symbol_conf.full_paths,
- "Don't shorten the pathnames taking into account the cwd"),
OPT_BOOLEAN(0, "showcpuutilization", &symbol_conf.show_cpu_utilization,
"Show sample percentage for different cpu modes"),
OPT_STRING('p', "parent", &parent_pattern, "regex",
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c
index 9a39ca3c3ac..a6b4d44f950 100644
--- a/tools/perf/builtin-stat.c
+++ b/tools/perf/builtin-stat.c
@@ -69,7 +69,7 @@ static struct perf_event_attr default_attrs[] = {
};
static bool system_wide = false;
-static unsigned int nr_cpus = 0;
+static int nr_cpus = 0;
static int run_idx = 0;
static int run_count = 1;
@@ -82,6 +82,7 @@ static int thread_num = 0;
static pid_t child_pid = -1;
static bool null_run = false;
static bool big_num = false;
+static const char *cpu_list;
static int *fd[MAX_NR_CPUS][MAX_COUNTERS];
@@ -158,7 +159,7 @@ static int create_perf_stat_counter(int counter)
PERF_FORMAT_TOTAL_TIME_RUNNING;
if (system_wide) {
- unsigned int cpu;
+ int cpu;
for (cpu = 0; cpu < nr_cpus; cpu++) {
fd[cpu][counter][0] = sys_perf_event_open(attr,
@@ -208,7 +209,7 @@ static inline int nsec_counter(int counter)
static void read_counter(int counter)
{
u64 count[3], single_count[3];
- unsigned int cpu;
+ int cpu;
size_t res, nv;
int scaled;
int i, thread;
@@ -542,6 +543,8 @@ static const struct option options[] = {
"null run - dont start any counters"),
OPT_BOOLEAN('B', "big-num", &big_num,
"print large numbers with thousands\' separators"),
+ OPT_STRING('C', "cpu", &cpu_list, "cpu",
+ "list of cpus to monitor in system-wide"),
OPT_END()
};
@@ -566,10 +569,13 @@ int cmd_stat(int argc, const char **argv, const char *prefix __used)
}
if (system_wide)
- nr_cpus = read_cpu_map();
+ nr_cpus = read_cpu_map(cpu_list);
else
nr_cpus = 1;
+ if (nr_cpus < 1)
+ usage_with_options(stat_usage, options);
+
if (target_pid != -1) {
target_tid = target_pid;
thread_num = find_all_tid(target_pid, &all_tids);
diff --git a/tools/perf/builtin-timechart.c b/tools/perf/builtin-timechart.c
index 5a52ed9fc10..5161619d471 100644
--- a/tools/perf/builtin-timechart.c
+++ b/tools/perf/builtin-timechart.c
@@ -300,8 +300,9 @@ struct trace_entry {
struct power_entry {
struct trace_entry te;
- s64 type;
- s64 value;
+ u64 type;
+ u64 value;
+ u64 cpu_id;
};
#define TASK_COMM_LEN 16
@@ -498,13 +499,13 @@ static int process_sample_event(event_t *event, struct perf_session *session)
return 0;
if (strcmp(event_str, "power:power_start") == 0)
- c_state_start(data.cpu, data.time, pe->value);
+ c_state_start(pe->cpu_id, data.time, pe->value);
if (strcmp(event_str, "power:power_end") == 0)
- c_state_end(data.cpu, data.time);
+ c_state_end(pe->cpu_id, data.time);
if (strcmp(event_str, "power:power_frequency") == 0)
- p_state_change(data.cpu, data.time, pe->value);
+ p_state_change(pe->cpu_id, data.time, pe->value);
if (strcmp(event_str, "sched:sched_wakeup") == 0)
sched_wakeup(data.cpu, data.time, data.pid, te);
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index a66f4272b99..b513e40974f 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -102,6 +102,7 @@ struct sym_entry *sym_filter_entry_sched = NULL;
static int sym_pcnt_filter = 5;
static int sym_counter = 0;
static int display_weighted = -1;
+static const char *cpu_list;
/*
* Symbols
@@ -982,6 +983,7 @@ static void event__process_sample(const event_t *self,
u64 ip = self->ip.ip;
struct sym_entry *syme;
struct addr_location al;
+ struct sample_data data;
struct machine *machine;
u8 origin = self->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
@@ -1024,7 +1026,8 @@ static void event__process_sample(const event_t *self,
if (self->header.misc & PERF_RECORD_MISC_EXACT_IP)
exact_samples++;
- if (event__preprocess_sample(self, session, &al, symbol_filter) < 0 ||
+ if (event__preprocess_sample(self, session, &al, &data,
+ symbol_filter) < 0 ||
al.filtered)
return;
@@ -1079,26 +1082,6 @@ static void event__process_sample(const event_t *self,
}
}
-static int event__process(event_t *event, struct perf_session *session)
-{
- switch (event->header.type) {
- case PERF_RECORD_COMM:
- event__process_comm(event, session);
- break;
- case PERF_RECORD_MMAP:
- event__process_mmap(event, session);
- break;
- case PERF_RECORD_FORK:
- case PERF_RECORD_EXIT:
- event__process_task(event, session);
- break;
- default:
- break;
- }
-
- return 0;
-}
-
struct mmap_data {
int counter;
void *base;
@@ -1351,8 +1334,8 @@ static const struct option options[] = {
"profile events on existing thread id"),
OPT_BOOLEAN('a', "all-cpus", &system_wide,
"system-wide collection from all CPUs"),
- OPT_INTEGER('C', "CPU", &profile_cpu,
- "CPU to profile on"),
+ OPT_STRING('C', "cpu", &cpu_list, "cpu",
+ "list of cpus to monitor"),
OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name,
"file", "vmlinux pathname"),
OPT_BOOLEAN('K', "hide_kernel_symbols", &hide_kernel_symbols,
@@ -1428,10 +1411,10 @@ int cmd_top(int argc, const char **argv, const char *prefix __used)
return -ENOMEM;
/* CPU and PID are mutually exclusive */
- if (target_tid > 0 && profile_cpu != -1) {
+ if (target_tid > 0 && cpu_list) {
printf("WARNING: PID switch overriding CPU\n");
sleep(1);
- profile_cpu = -1;
+ cpu_list = NULL;
}
if (!nr_counters)
@@ -1469,10 +1452,13 @@ int cmd_top(int argc, const char **argv, const char *prefix __used)
attrs[counter].sample_period = default_interval;
}
- if (target_tid != -1 || profile_cpu != -1)
+ if (target_tid != -1)
nr_cpus = 1;
else
- nr_cpus = read_cpu_map();
+ nr_cpus = read_cpu_map(cpu_list);
+
+ if (nr_cpus < 1)
+ usage_with_options(top_usage, options);
get_term_dimensions(&winsize);
if (print_entries == 0) {
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c
index dddf3f01b5a..294da725a57 100644
--- a/tools/perf/builtin-trace.c
+++ b/tools/perf/builtin-trace.c
@@ -11,8 +11,9 @@
static char const *script_name;
static char const *generate_script_lang;
-static bool debug_ordering;
+static bool debug_mode;
static u64 last_timestamp;
+static u64 nr_unordered;
static int default_start_script(const char *script __unused,
int argc __unused,
@@ -91,13 +92,15 @@ static int process_sample_event(event_t *event, struct perf_session *session)
}
if (session->sample_type & PERF_SAMPLE_RAW) {
- if (debug_ordering) {
+ if (debug_mode) {
if (data.time < last_timestamp) {
pr_err("Samples misordered, previous: %llu "
"this: %llu\n", last_timestamp,
data.time);
+ nr_unordered++;
}
last_timestamp = data.time;
+ return 0;
}
/*
* FIXME: better resolve from pid from the struct trace_entry
@@ -113,6 +116,15 @@ static int process_sample_event(event_t *event, struct perf_session *session)
return 0;
}
+static u64 nr_lost;
+
+static int process_lost_event(event_t *event, struct perf_session *session __used)
+{
+ nr_lost += event->lost.lost;
+
+ return 0;
+}
+
static struct perf_event_ops event_ops = {
.sample = process_sample_event,
.comm = event__process_comm,
@@ -120,6 +132,7 @@ static struct perf_event_ops event_ops = {
.event_type = event__process_event_type,
.tracing_data = event__process_tracing_data,
.build_id = event__process_build_id,
+ .lost = process_lost_event,
.ordered_samples = true,
};
@@ -132,9 +145,18 @@ static void sig_handler(int sig __unused)
static int __cmd_trace(struct perf_session *session)
{
+ int ret;
+
signal(SIGINT, sig_handler);
- return perf_session__process_events(session, &event_ops);
+ ret = perf_session__process_events(session, &event_ops);
+
+ if (debug_mode) {
+ pr_err("Misordered timestamps: %llu\n", nr_unordered);
+ pr_err("Lost events: %llu\n", nr_lost);
+ }
+
+ return ret;
}
struct script_spec {
@@ -544,8 +566,8 @@ static const struct option options[] = {
"generate perf-trace.xx script in specified language"),
OPT_STRING('i', "input", &input_name, "file",
"input file name"),
- OPT_BOOLEAN('d', "debug-ordering", &debug_ordering,
- "check that samples time ordering is monotonic"),
+ OPT_BOOLEAN('d', "debug-mode", &debug_mode,
+ "do various checks like samples ordering and lost events"),
OPT_END()
};
diff --git a/tools/perf/feature-tests.mak b/tools/perf/feature-tests.mak
new file mode 100644
index 00000000000..ddb68e601f0
--- /dev/null
+++ b/tools/perf/feature-tests.mak
@@ -0,0 +1,119 @@
+define SOURCE_HELLO
+#include <stdio.h>
+int main(void)
+{
+ return puts(\"hi\");
+}
+endef
+
+ifndef NO_DWARF
+define SOURCE_DWARF
+#include <dwarf.h>
+#include <libdw.h>
+#include <version.h>
+#ifndef _ELFUTILS_PREREQ
+#error
+#endif
+
+int main(void)
+{
+ Dwarf *dbg = dwarf_begin(0, DWARF_C_READ);
+ return (long)dbg;
+}
+endef
+endif
+
+define SOURCE_LIBELF
+#include <libelf.h>
+
+int main(void)
+{
+ Elf *elf = elf_begin(0, ELF_C_READ, 0);
+ return (long)elf;
+}
+endef
+
+define SOURCE_GLIBC
+#include <gnu/libc-version.h>
+
+int main(void)
+{
+ const char *version = gnu_get_libc_version();
+ return (long)version;
+}
+endef
+
+define SOURCE_ELF_MMAP
+#include <libelf.h>
+int main(void)
+{
+ Elf *elf = elf_begin(0, ELF_C_READ_MMAP, 0);
+ return (long)elf;
+}
+endef
+
+ifndef NO_NEWT
+define SOURCE_NEWT
+#include <newt.h>
+
+int main(void)
+{
+ newtInit();
+ newtCls();
+ return newtFinished();
+}
+endef
+endif
+
+ifndef NO_LIBPERL
+define SOURCE_PERL_EMBED
+#include <EXTERN.h>
+#include <perl.h>
+
+int main(void)
+{
+perl_alloc();
+return 0;
+}
+endef
+endif
+
+ifndef NO_LIBPYTHON
+define SOURCE_PYTHON_EMBED
+#include <Python.h>
+
+int main(void)
+{
+ Py_Initialize();
+ return 0;
+}
+endef
+endif
+
+define SOURCE_BFD
+#include <bfd.h>
+
+int main(void)
+{
+ bfd_demangle(0, 0, 0);
+ return 0;
+}
+endef
+
+define SOURCE_CPLUS_DEMANGLE
+extern char *cplus_demangle(const char *, int);
+
+int main(void)
+{
+ cplus_demangle(0, 0);
+ return 0;
+}
+endef
+
+# try-cc
+# Usage: option = $(call try-cc, source-to-build, cc-options)
+try-cc = $(shell sh -c \
+ 'TMP="$(TMPOUT).$$$$"; \
+ echo "$(1)" | \
+ $(CC) -x c - $(2) -o "$$TMP" > /dev/null 2>&1 && echo y; \
+ rm -f "$$TMP"')
diff --git a/tools/perf/perf-archive.sh b/tools/perf/perf-archive.sh
index 2e7a4f417e2..677e59d62a8 100644
--- a/tools/perf/perf-archive.sh
+++ b/tools/perf/perf-archive.sh
@@ -7,7 +7,17 @@ if [ $# -ne 0 ] ; then
PERF_DATA=$1
fi
-DEBUGDIR=~/.debug/
+#
+# PERF_BUILDID_DIR environment variable set by perf
+# path to buildid directory, default to $HOME/.debug
+#
+if [ -z $PERF_BUILDID_DIR ]; then
+ PERF_BUILDID_DIR=~/.debug/
+else
+ # append / to make substitutions work
+ PERF_BUILDID_DIR=$PERF_BUILDID_DIR/
+fi
+
BUILDIDS=$(mktemp /tmp/perf-archive-buildids.XXXXXX)
NOBUILDID=0000000000000000000000000000000000000000
@@ -22,13 +32,13 @@ MANIFEST=$(mktemp /tmp/perf-archive-manifest.XXXXXX)
cut -d ' ' -f 1 $BUILDIDS | \
while read build_id ; do
- linkname=$DEBUGDIR.build-id/${build_id:0:2}/${build_id:2}
+ linkname=$PERF_BUILDID_DIR.build-id/${build_id:0:2}/${build_id:2}
filename=$(readlink -f $linkname)
- echo ${linkname#$DEBUGDIR} >> $MANIFEST
- echo ${filename#$DEBUGDIR} >> $MANIFEST
+ echo ${linkname#$PERF_BUILDID_DIR} >> $MANIFEST
+ echo ${filename#$PERF_BUILDID_DIR} >> $MANIFEST
done
-tar cfj $PERF_DATA.tar.bz2 -C $DEBUGDIR -T $MANIFEST
+tar cfj $PERF_DATA.tar.bz2 -C $PERF_BUILDID_DIR -T $MANIFEST
rm -f $MANIFEST $BUILDIDS
echo -e "Now please run:\n"
echo -e "$ tar xvf $PERF_DATA.tar.bz2 -C ~/.debug\n"
diff --git a/tools/perf/perf.c b/tools/perf/perf.c
index 6e487119113..cdd6c03f1e1 100644
--- a/tools/perf/perf.c
+++ b/tools/perf/perf.c
@@ -458,6 +458,8 @@ int main(int argc, const char **argv)
handle_options(&argv, &argc, NULL);
commit_pager_choice();
set_debugfs_path();
+ set_buildid_dir();
+
if (argc > 0) {
if (!prefixcmp(argv[0], "--"))
argv[0] += 2;
diff --git a/tools/perf/scripts/python/Perf-Trace-Util/lib/Perf/Trace/Core.py b/tools/perf/scripts/python/Perf-Trace-Util/lib/Perf/Trace/Core.py
index 1dc464ee2ca..aad7525bca1 100644
--- a/tools/perf/scripts/python/Perf-Trace-Util/lib/Perf/Trace/Core.py
+++ b/tools/perf/scripts/python/Perf-Trace-Util/lib/Perf/Trace/Core.py
@@ -89,3 +89,33 @@ def trace_flag_str(value):
value &= ~idx
return string
+
+
+def taskState(state):
+ states = {
+ 0 : "R",
+ 1 : "S",
+ 2 : "D",
+ 64: "DEAD"
+ }
+
+ if state not in states:
+ return "Unknown"
+
+ return states[state]
+
+
+class EventHeaders:
+ def __init__(self, common_cpu, common_secs, common_nsecs,
+ common_pid, common_comm):
+ self.cpu = common_cpu
+ self.secs = common_secs
+ self.nsecs = common_nsecs
+ self.pid = common_pid
+ self.comm = common_comm
+
+ def ts(self):
+ return (self.secs * (10 ** 9)) + self.nsecs
+
+ def ts_format(self):
+ return "%d.%d" % (self.secs, int(self.nsecs / 1000))
diff --git a/tools/perf/scripts/python/Perf-Trace-Util/lib/Perf/Trace/SchedGui.py b/tools/perf/scripts/python/Perf-Trace-Util/lib/Perf/Trace/SchedGui.py
new file mode 100644
index 00000000000..ae9a56e43e0
--- /dev/null
+++ b/tools/perf/scripts/python/Perf-Trace-Util/lib/Perf/Trace/SchedGui.py
@@ -0,0 +1,184 @@
+# SchedGui.py - Python extension for perf trace, basic GUI code for
+# traces drawing and overview.
+#
+# Copyright (C) 2010 by Frederic Weisbecker <fweisbec@gmail.com>
+#
+# This software is distributed under the terms of the GNU General
+# Public License ("GPL") version 2 as published by the Free Software
+# Foundation.
+
+
+try:
+ import wx
+except ImportError:
+ raise ImportError, "You need to install the wxpython lib for this script"
+
+
+class RootFrame(wx.Frame):
+ Y_OFFSET = 100
+ RECT_HEIGHT = 100
+ RECT_SPACE = 50
+ EVENT_MARKING_WIDTH = 5
+
+ def __init__(self, sched_tracer, title, parent = None, id = -1):
+ wx.Frame.__init__(self, parent, id, title)
+
+ (self.screen_width, self.screen_height) = wx.GetDisplaySize()
+ self.screen_width -= 10
+ self.screen_height -= 10
+ self.zoom = 0.5
+ self.scroll_scale = 20
+ self.sched_tracer = sched_tracer
+ self.sched_tracer.set_root_win(self)
+ (self.ts_start, self.ts_end) = sched_tracer.interval()
+ self.update_width_virtual()
+ self.nr_rects = sched_tracer.nr_rectangles() + 1
+ self.height_virtual = RootFrame.Y_OFFSET + (self.nr_rects * (RootFrame.RECT_HEIGHT + RootFrame.RECT_SPACE))
+
+ # whole window panel
+ self.panel = wx.Panel(self, size=(self.screen_width, self.screen_height))
+
+ # scrollable container
+ self.scroll = wx.ScrolledWindow(self.panel)
+ self.scroll.SetScrollbars(self.scroll_scale, self.scroll_scale, self.width_virtual / self.scroll_scale, self.height_virtual / self.scroll_scale)
+ self.scroll.EnableScrolling(True, True)
+ self.scroll.SetFocus()
+
+ # scrollable drawing area
+ self.scroll_panel = wx.Panel(self.scroll, size=(self.screen_width - 15, self.screen_height / 2))
+ self.scroll_panel.Bind(wx.EVT_PAINT, self.on_paint)
+ self.scroll_panel.Bind(wx.EVT_KEY_DOWN, self.on_key_press)
+ self.scroll_panel.Bind(wx.EVT_LEFT_DOWN, self.on_mouse_down)
+ self.scroll.Bind(wx.EVT_PAINT, self.on_paint)
+ self.scroll.Bind(wx.EVT_KEY_DOWN, self.on_key_press)
+ self.scroll.Bind(wx.EVT_LEFT_DOWN, self.on_mouse_down)
+
+ self.scroll.Fit()
+ self.Fit()
+
+ self.scroll_panel.SetDimensions(-1, -1, self.width_virtual, self.height_virtual, wx.SIZE_USE_EXISTING)
+
+ self.txt = None
+
+ self.Show(True)
+
+ def us_to_px(self, val):
+ return val / (10 ** 3) * self.zoom
+
+ def px_to_us(self, val):
+ return (val / self.zoom) * (10 ** 3)
+
+ def scroll_start(self):
+ (x, y) = self.scroll.GetViewStart()
+ return (x * self.scroll_scale, y * self.scroll_scale)
+
+ def scroll_start_us(self):
+ (x, y) = self.scroll_start()
+ return self.px_to_us(x)
+
+ def paint_rectangle_zone(self, nr, color, top_color, start, end):
+ offset_px = self.us_to_px(start - self.ts_start)
+ width_px = self.us_to_px(end - self.ts_start)
+
+ offset_py = RootFrame.Y_OFFSET + (nr * (RootFrame.RECT_HEIGHT + RootFrame.RECT_SPACE))
+ width_py = RootFrame.RECT_HEIGHT
+
+ dc = self.dc
+
+ if top_color is not None:
+ (r, g, b) = top_color
+ top_color = wx.Colour(r, g, b)
+ brush = wx.Brush(top_color, wx.SOLID)
+ dc.SetBrush(brush)
+ dc.DrawRectangle(offset_px, offset_py, width_px, RootFrame.EVENT_MARKING_WIDTH)
+ width_py -= RootFrame.EVENT_MARKING_WIDTH
+ offset_py += RootFrame.EVENT_MARKING_WIDTH
+
+ (r ,g, b) = color
+ color = wx.Colour(r, g, b)
+ brush = wx.Brush(color, wx.SOLID)
+ dc.SetBrush(brush)
+ dc.DrawRectangle(offset_px, offset_py, width_px, width_py)
+
+ def update_rectangles(self, dc, start, end):
+ start += self.ts_start
+ end += self.ts_start
+ self.sched_tracer.fill_zone(start, end)
+
+ def on_paint(self, event):
+ dc = wx.PaintDC(self.scroll_panel)
+ self.dc = dc
+
+ width = min(self.width_virtual, self.screen_width)
+ (x, y) = self.scroll_start()
+ start = self.px_to_us(x)
+ end = self.px_to_us(x + width)
+ self.update_rectangles(dc, start, end)
+
+ def rect_from_ypixel(self, y):
+ y -= RootFrame.Y_OFFSET
+ rect = y / (RootFrame.RECT_HEIGHT + RootFrame.RECT_SPACE)
+ height = y % (RootFrame.RECT_HEIGHT + RootFrame.RECT_SPACE)
+
+ if rect < 0 or rect > self.nr_rects - 1 or height > RootFrame.RECT_HEIGHT:
+ return -1
+
+ return rect
+
+ def update_summary(self, txt):
+ if self.txt:
+ self.txt.Destroy()
+ self.txt = wx.StaticText(self.panel, -1, txt, (0, (self.screen_height / 2) + 50))
+
+
+ def on_mouse_down(self, event):
+ (x, y) = event.GetPositionTuple()
+ rect = self.rect_from_ypixel(y)
+ if rect == -1:
+ return
+
+ t = self.px_to_us(x) + self.ts_start
+
+ self.sched_tracer.mouse_down(rect, t)
+
+
+ def update_width_virtual(self):
+ self.width_virtual = self.us_to_px(self.ts_end - self.ts_start)
+
+ def __zoom(self, x):
+ self.update_width_virtual()
+ (xpos, ypos) = self.scroll.GetViewStart()
+ xpos = self.us_to_px(x) / self.scroll_scale
+ self.scroll.SetScrollbars(self.scroll_scale, self.scroll_scale, self.width_virtual / self.scroll_scale, self.height_virtual / self.scroll_scale, xpos, ypos)
+ self.Refresh()
+
+ def zoom_in(self):
+ x = self.scroll_start_us()
+ self.zoom *= 2
+ self.__zoom(x)
+
+ def zoom_out(self):
+ x = self.scroll_start_us()
+ self.zoom /= 2
+ self.__zoom(x)
+
+
+ def on_key_press(self, event):
+ key = event.GetRawKeyCode()
+ if key == ord("+"):
+ self.zoom_in()
+ return
+ if key == ord("-"):
+ self.zoom_out()
+ return
+
+ key = event.GetKeyCode()
+ (x, y) = self.scroll.GetViewStart()
+ if key == wx.WXK_RIGHT:
+ self.scroll.Scroll(x + 1, y)
+ elif key == wx.WXK_LEFT:
+ self.scroll.Scroll(x - 1, y)
+ elif key == wx.WXK_DOWN:
+ self.scroll.Scroll(x, y + 1)
+ elif key == wx.WXK_UP:
+ self.scroll.Scroll(x, y - 1)
diff --git a/tools/perf/scripts/python/bin/sched-migration-record b/tools/perf/scripts/python/bin/sched-migration-record
new file mode 100644
index 00000000000..17a3e9bd9e8
--- /dev/null
+++ b/tools/perf/scripts/python/bin/sched-migration-record
@@ -0,0 +1,2 @@
+#!/bin/bash
+perf record -m 16384 -a -e sched:sched_wakeup -e sched:sched_wakeup_new -e sched:sched_switch -e sched:sched_migrate_task $@
diff --git a/tools/perf/scripts/python/bin/sched-migration-report b/tools/perf/scripts/python/bin/sched-migration-report
new file mode 100644
index 00000000000..61d05f72e44
--- /dev/null
+++ b/tools/perf/scripts/python/bin/sched-migration-report
@@ -0,0 +1,3 @@
+#!/bin/bash
+# description: sched migration overview
+perf trace $@ -s ~/libexec/perf-core/scripts/python/sched-migration.py
diff --git a/tools/perf/scripts/python/sched-migration.py b/tools/perf/scripts/python/sched-migration.py
new file mode 100644
index 00000000000..b934383c336
--- /dev/null
+++ b/tools/perf/scripts/python/sched-migration.py
@@ -0,0 +1,461 @@
+#!/usr/bin/python
+#
+# Cpu task migration overview toy
+#
+# Copyright (C) 2010 Frederic Weisbecker <fweisbec@gmail.com>
+#
+# perf trace event handlers have been generated by perf trace -g python
+#
+# This software is distributed under the terms of the GNU General
+# Public License ("GPL") version 2 as published by the Free Software
+# Foundation.
+
+
+import os
+import sys
+
+from collections import defaultdict
+from UserList import UserList
+
+sys.path.append(os.environ['PERF_EXEC_PATH'] + \
+ '/scripts/python/Perf-Trace-Util/lib/Perf/Trace')
+sys.path.append('scripts/python/Perf-Trace-Util/lib/Perf/Trace')
+
+from perf_trace_context import *
+from Core import *
+from SchedGui import *
+
+
+threads = { 0 : "idle"}
+
+def thread_name(pid):
+ return "%s:%d" % (threads[pid], pid)
+
+class RunqueueEventUnknown:
+ @staticmethod
+ def color():
+ return None
+
+ def __repr__(self):
+ return "unknown"
+
+class RunqueueEventSleep:
+ @staticmethod
+ def color():
+ return (0, 0, 0xff)
+
+ def __init__(self, sleeper):
+ self.sleeper = sleeper
+
+ def __repr__(self):
+ return "%s gone to sleep" % thread_name(self.sleeper)
+
+class RunqueueEventWakeup:
+ @staticmethod
+ def color():
+ return (0xff, 0xff, 0)
+
+ def __init__(self, wakee):
+ self.wakee = wakee
+
+ def __repr__(self):
+ return "%s woke up" % thread_name(self.wakee)
+
+class RunqueueEventFork:
+ @staticmethod
+ def color():
+ return (0, 0xff, 0)
+
+ def __init__(self, child):
+ self.child = child
+
+ def __repr__(self):
+ return "new forked task %s" % thread_name(self.child)
+
+class RunqueueMigrateIn:
+ @staticmethod
+ def color():
+ return (0, 0xf0, 0xff)
+
+ def __init__(self, new):
+ self.new = new
+
+ def __repr__(self):
+ return "task migrated in %s" % thread_name(self.new)
+
+class RunqueueMigrateOut:
+ @staticmethod
+ def color():
+ return (0xff, 0, 0xff)
+
+ def __init__(self, old):
+ self.old = old
+
+ def __repr__(self):
+ return "task migrated out %s" % thread_name(self.old)
+
+class RunqueueSnapshot:
+ def __init__(self, tasks = [0], event = RunqueueEventUnknown()):
+ self.tasks = tuple(tasks)
+ self.event = event
+
+ def sched_switch(self, prev, prev_state, next):
+ event = RunqueueEventUnknown()
+
+ if taskState(prev_state) == "R" and next in self.tasks \
+ and prev in self.tasks:
+ return self
+
+ if taskState(prev_state) != "R":
+ event = RunqueueEventSleep(prev)
+
+ next_tasks = list(self.tasks[:])
+ if prev in self.tasks:
+ if taskState(prev_state) != "R":
+ next_tasks.remove(prev)
+ elif taskState(prev_state) == "R":
+ next_tasks.append(prev)
+
+ if next not in next_tasks:
+ next_tasks.append(next)
+
+ return RunqueueSnapshot(next_tasks, event)
+
+ def migrate_out(self, old):
+ if old not in self.tasks:
+ return self
+ next_tasks = [task for task in self.tasks if task != old]
+
+ return RunqueueSnapshot(next_tasks, RunqueueMigrateOut(old))
+
+ def __migrate_in(self, new, event):
+ if new in self.tasks:
+ self.event = event
+ return self
+ next_tasks = self.tasks[:] + tuple([new])
+
+ return RunqueueSnapshot(next_tasks, event)
+
+ def migrate_in(self, new):
+ return self.__migrate_in(new, RunqueueMigrateIn(new))
+
+ def wake_up(self, new):
+ return self.__migrate_in(new, RunqueueEventWakeup(new))
+
+ def wake_up_new(self, new):
+ return self.__migrate_in(new, RunqueueEventFork(new))
+
+ def load(self):
+ """ Provide the number of tasks on the runqueue.
+ Don't count idle"""
+ return len(self.tasks) - 1
+
+ def __repr__(self):
+ ret = self.tasks.__repr__()
+ ret += self.origin_tostring()
+
+ return ret
+
+class TimeSlice:
+ def __init__(self, start, prev):
+ self.start = start
+ self.prev = prev
+ self.end = start
+ # cpus that triggered the event
+ self.event_cpus = []
+ if prev is not None:
+ self.total_load = prev.total_load
+ self.rqs = prev.rqs.copy()
+ else:
+ self.rqs = defaultdict(RunqueueSnapshot)
+ self.total_load = 0
+
+ def __update_total_load(self, old_rq, new_rq):
+ diff = new_rq.load() - old_rq.load()
+ self.total_load += diff
+
+ def sched_switch(self, ts_list, prev, prev_state, next, cpu):
+ old_rq = self.prev.rqs[cpu]
+ new_rq = old_rq.sched_switch(prev, prev_state, next)
+
+ if old_rq is new_rq:
+ return
+
+ self.rqs[cpu] = new_rq
+ self.__update_total_load(old_rq, new_rq)
+ ts_list.append(self)
+ self.event_cpus = [cpu]
+
+ def migrate(self, ts_list, new, old_cpu, new_cpu):
+ if old_cpu == new_cpu:
+ return
+ old_rq = self.prev.rqs[old_cpu]
+ out_rq = old_rq.migrate_out(new)
+ self.rqs[old_cpu] = out_rq
+ self.__update_total_load(old_rq, out_rq)
+
+ new_rq = self.prev.rqs[new_cpu]
+ in_rq = new_rq.migrate_in(new)
+ self.rqs[new_cpu] = in_rq
+ self.__update_total_load(new_rq, in_rq)
+
+ ts_list.append(self)
+
+ if old_rq is not out_rq:
+ self.event_cpus.append(old_cpu)
+ self.event_cpus.append(new_cpu)
+
+ def wake_up(self, ts_list, pid, cpu, fork):
+ old_rq = self.prev.rqs[cpu]
+ if fork:
+ new_rq = old_rq.wake_up_new(pid)
+ else:
+ new_rq = old_rq.wake_up(pid)
+
+ if new_rq is old_rq:
+ return
+ self.rqs[cpu] = new_rq
+ self.__update_total_load(old_rq, new_rq)
+ ts_list.append(self)
+ self.event_cpus = [cpu]
+
+ def next(self, t):
+ self.end = t
+ return TimeSlice(t, self)
+
+class TimeSliceList(UserList):
+ def __init__(self, arg = []):
+ self.data = arg
+
+ def get_time_slice(self, ts):
+ if len(self.data) == 0:
+ slice = TimeSlice(ts, TimeSlice(-1, None))
+ else:
+ slice = self.data[-1].next(ts)
+ return slice
+
+ def find_time_slice(self, ts):
+ start = 0
+ end = len(self.data)
+ found = -1
+ searching = True
+ while searching:
+ if start == end or start == end - 1:
+ searching = False
+
+ i = (end + start) / 2
+ if self.data[i].start <= ts and self.data[i].end >= ts:
+ found = i
+ end = i
+ continue
+
+ if self.data[i].end < ts:
+ start = i
+
+ elif self.data[i].start > ts:
+ end = i
+
+ return found
+
+ def set_root_win(self, win):
+ self.root_win = win
+
+ def mouse_down(self, cpu, t):
+ idx = self.find_time_slice(t)
+ if idx == -1:
+ return
+
+ ts = self[idx]
+ rq = ts.rqs[cpu]
+ raw = "CPU: %d\n" % cpu
+ raw += "Last event : %s\n" % rq.event.__repr__()
+ raw += "Timestamp : %d.%06d\n" % (ts.start / (10 ** 9), (ts.start % (10 ** 9)) / 1000)
+ raw += "Duration : %6d us\n" % ((ts.end - ts.start) / (10 ** 6))
+ raw += "Load = %d\n" % rq.load()
+ for t in rq.tasks:
+ raw += "%s \n" % thread_name(t)
+
+ self.root_win.update_summary(raw)
+
+ def update_rectangle_cpu(self, slice, cpu):
+ rq = slice.rqs[cpu]
+
+ if slice.total_load != 0:
+ load_rate = rq.load() / float(slice.total_load)
+ else:
+ load_rate = 0
+
+ red_power = int(0xff - (0xff * load_rate))
+ color = (0xff, red_power, red_power)
+
+ top_color = None
+
+ if cpu in slice.event_cpus:
+ top_color = rq.event.color()
+
+ self.root_win.paint_rectangle_zone(cpu, color, top_color, slice.start, slice.end)
+
+ def fill_zone(self, start, end):
+ i = self.find_time_slice(start)
+ if i == -1:
+ return
+
+ for i in xrange(i, len(self.data)):
+ timeslice = self.data[i]
+ if timeslice.start > end:
+ return
+
+ for cpu in timeslice.rqs:
+ self.update_rectangle_cpu(timeslice, cpu)
+
+ def interval(self):
+ if len(self.data) == 0:
+ return (0, 0)
+
+ return (self.data[0].start, self.data[-1].end)
+
+ def nr_rectangles(self):
+ last_ts = self.data[-1]
+ max_cpu = 0
+ for cpu in last_ts.rqs:
+ if cpu > max_cpu:
+ max_cpu = cpu
+ return max_cpu
+
+
+class SchedEventProxy:
+ def __init__(self):
+ self.current_tsk = defaultdict(lambda : -1)
+ self.timeslices = TimeSliceList()
+
+ def sched_switch(self, headers, prev_comm, prev_pid, prev_prio, prev_state,
+ next_comm, next_pid, next_prio):
+ """ Ensure the task we sched out this cpu is really the one
+ we logged. Otherwise we may have missed traces """
+
+ on_cpu_task = self.current_tsk[headers.cpu]
+
+ if on_cpu_task != -1 and on_cpu_task != prev_pid:
+ print "Sched switch event rejected ts: %s cpu: %d prev: %s(%d) next: %s(%d)" % \
+ (headers.ts_format(), headers.cpu, prev_comm, prev_pid, next_comm, next_pid)
+
+ threads[prev_pid] = prev_comm
+ threads[next_pid] = next_comm
+ self.current_tsk[headers.cpu] = next_pid
+
+ ts = self.timeslices.get_time_slice(headers.ts())
+ ts.sched_switch(self.timeslices, prev_pid, prev_state, next_pid, headers.cpu)
+
+ def migrate(self, headers, pid, prio, orig_cpu, dest_cpu):
+ ts = self.timeslices.get_time_slice(headers.ts())
+ ts.migrate(self.timeslices, pid, orig_cpu, dest_cpu)
+
+ def wake_up(self, headers, comm, pid, success, target_cpu, fork):
+ if success == 0:
+ return
+ ts = self.timeslices.get_time_slice(headers.ts())
+ ts.wake_up(self.timeslices, pid, target_cpu, fork)
+
+
+def trace_begin():
+ global parser
+ parser = SchedEventProxy()
+
+def trace_end():
+ app = wx.App(False)
+ timeslices = parser.timeslices
+ frame = RootFrame(timeslices, "Migration")
+ app.MainLoop()
+
+def sched__sched_stat_runtime(event_name, context, common_cpu,
+ common_secs, common_nsecs, common_pid, common_comm,
+ comm, pid, runtime, vruntime):
+ pass
+
+def sched__sched_stat_iowait(event_name, context, common_cpu,
+ common_secs, common_nsecs, common_pid, common_comm,
+ comm, pid, delay):
+ pass
+
+def sched__sched_stat_sleep(event_name, context, common_cpu,
+ common_secs, common_nsecs, common_pid, common_comm,
+ comm, pid, delay):
+ pass
+
+def sched__sched_stat_wait(event_name, context, common_cpu,
+ common_secs, common_nsecs, common_pid, common_comm,
+ comm, pid, delay):
+ pass
+
+def sched__sched_process_fork(event_name, context, common_cpu,
+ common_secs, common_nsecs, common_pid, common_comm,
+ parent_comm, parent_pid, child_comm, child_pid):
+ pass
+
+def sched__sched_process_wait(event_name, context, common_cpu,
+ common_secs, common_nsecs, common_pid, common_comm,
+ comm, pid, prio):
+ pass
+
+def sched__sched_process_exit(event_name, context, common_cpu,
+ common_secs, common_nsecs, common_pid, common_comm,
+ comm, pid, prio):
+ pass
+
+def sched__sched_process_free(event_name, context, common_cpu,
+ common_secs, common_nsecs, common_pid, common_comm,
+ comm, pid, prio):
+ pass
+
+def sched__sched_migrate_task(event_name, context, common_cpu,
+ common_secs, common_nsecs, common_pid, common_comm,
+ comm, pid, prio, orig_cpu,
+ dest_cpu):
+ headers = EventHeaders(common_cpu, common_secs, common_nsecs,
+ common_pid, common_comm)
+ parser.migrate(headers, pid, prio, orig_cpu, dest_cpu)
+
+def sched__sched_switch(event_name, context, common_cpu,
+ common_secs, common_nsecs, common_pid, common_comm,
+ prev_comm, prev_pid, prev_prio, prev_state,
+ next_comm, next_pid, next_prio):
+
+ headers = EventHeaders(common_cpu, common_secs, common_nsecs,
+ common_pid, common_comm)
+ parser.sched_switch(headers, prev_comm, prev_pid, prev_prio, prev_state,
+ next_comm, next_pid, next_prio)
+
+def sched__sched_wakeup_new(event_name, context, common_cpu,
+ common_secs, common_nsecs, common_pid, common_comm,
+ comm, pid, prio, success,
+ target_cpu):
+ headers = EventHeaders(common_cpu, common_secs, common_nsecs,
+ common_pid, common_comm)
+ parser.wake_up(headers, comm, pid, success, target_cpu, 1)
+
+def sched__sched_wakeup(event_name, context, common_cpu,
+ common_secs, common_nsecs, common_pid, common_comm,
+ comm, pid, prio, success,
+ target_cpu):
+ headers = EventHeaders(common_cpu, common_secs, common_nsecs,
+ common_pid, common_comm)
+ parser.wake_up(headers, comm, pid, success, target_cpu, 0)
+
+def sched__sched_wait_task(event_name, context, common_cpu,
+ common_secs, common_nsecs, common_pid, common_comm,
+ comm, pid, prio):
+ pass
+
+def sched__sched_kthread_stop_ret(event_name, context, common_cpu,
+ common_secs, common_nsecs, common_pid, common_comm,
+ ret):
+ pass
+
+def sched__sched_kthread_stop(event_name, context, common_cpu,
+ common_secs, common_nsecs, common_pid, common_comm,
+ comm, pid):
+ pass
+
+def trace_unhandled(event_name, context, common_cpu, common_secs, common_nsecs,
+ common_pid, common_comm):
+ pass
diff --git a/tools/perf/util/build-id.c b/tools/perf/util/build-id.c
index 70c5cf87d02..e437edb7241 100644
--- a/tools/perf/util/build-id.c
+++ b/tools/perf/util/build-id.c
@@ -12,6 +12,7 @@
#include "event.h"
#include "symbol.h"
#include <linux/kernel.h>
+#include "debug.h"
static int build_id__mark_dso_hit(event_t *event, struct perf_session *session)
{
@@ -34,28 +35,43 @@ static int build_id__mark_dso_hit(event_t *event, struct perf_session *session)
return 0;
}
+static int event__exit_del_thread(event_t *self, struct perf_session *session)
+{
+ struct thread *thread = perf_session__findnew(session, self->fork.tid);
+
+ dump_printf("(%d:%d):(%d:%d)\n", self->fork.pid, self->fork.tid,
+ self->fork.ppid, self->fork.ptid);
+
+ if (thread) {
+ rb_erase(&thread->rb_node, &session->threads);
+ session->last_match = NULL;
+ thread__delete(thread);
+ }
+
+ return 0;
+}
+
struct perf_event_ops build_id__mark_dso_hit_ops = {
.sample = build_id__mark_dso_hit,
.mmap = event__process_mmap,
.fork = event__process_task,
+ .exit = event__exit_del_thread,
};
char *dso__build_id_filename(struct dso *self, char *bf, size_t size)
{
char build_id_hex[BUILD_ID_SIZE * 2 + 1];
- const char *home;
if (!self->has_build_id)
return NULL;
build_id__sprintf(self->build_id, sizeof(self->build_id), build_id_hex);
- home = getenv("HOME");
if (bf == NULL) {
- if (asprintf(&bf, "%s/%s/.build-id/%.2s/%s", home,
- DEBUG_CACHE_DIR, build_id_hex, build_id_hex + 2) < 0)
+ if (asprintf(&bf, "%s/.build-id/%.2s/%s", buildid_dir,
+ build_id_hex, build_id_hex + 2) < 0)
return NULL;
} else
- snprintf(bf, size, "%s/%s/.build-id/%.2s/%s", home,
- DEBUG_CACHE_DIR, build_id_hex, build_id_hex + 2);
+ snprintf(bf, size, "%s/.build-id/%.2s/%s", buildid_dir,
+ build_id_hex, build_id_hex + 2);
return bf;
}
diff --git a/tools/perf/util/cache.h b/tools/perf/util/cache.h
index 65fe664fddf..27e9ebe4076 100644
--- a/tools/perf/util/cache.h
+++ b/tools/perf/util/cache.h
@@ -23,6 +23,7 @@ extern int perf_config(config_fn_t fn, void *);
extern int perf_config_int(const char *, const char *);
extern int perf_config_bool(const char *, const char *);
extern int config_error_nonbool(const char *);
+extern const char *perf_config_dirname(const char *, const char *);
/* pager.c */
extern void setup_pager(void);
diff --git a/tools/perf/util/callchain.c b/tools/perf/util/callchain.c
index 52c777e451e..f231f43424d 100644
--- a/tools/perf/util/callchain.c
+++ b/tools/perf/util/callchain.c
@@ -18,7 +18,7 @@
#include "util.h"
#include "callchain.h"
-bool ip_callchain__valid(struct ip_callchain *chain, event_t *event)
+bool ip_callchain__valid(struct ip_callchain *chain, const event_t *event)
{
unsigned int chain_size = event->header.size;
chain_size -= (unsigned long)&event->ip.__more_data - (unsigned long)event;
diff --git a/tools/perf/util/callchain.h b/tools/perf/util/callchain.h
index f2e9ee164bd..624a96c636f 100644
--- a/tools/perf/util/callchain.h
+++ b/tools/perf/util/callchain.h
@@ -63,5 +63,5 @@ int register_callchain_param(struct callchain_param *param);
int append_chain(struct callchain_node *root, struct ip_callchain *chain,
struct map_symbol *syms, u64 period);
-bool ip_callchain__valid(struct ip_callchain *chain, event_t *event);
+bool ip_callchain__valid(struct ip_callchain *chain, const event_t *event);
#endif /* __PERF_CALLCHAIN_H */
diff --git a/tools/perf/util/config.c b/tools/perf/util/config.c
index dabe892d0e5..e02d78cae70 100644
--- a/tools/perf/util/config.c
+++ b/tools/perf/util/config.c
@@ -11,6 +11,11 @@
#define MAXNAME (256)
+#define DEBUG_CACHE_DIR ".debug"
+
+
+char buildid_dir[MAXPATHLEN]; /* root dir for buildid, binary cache */
+
static FILE *config_file;
static const char *config_file_name;
static int config_linenr;
@@ -127,7 +132,7 @@ static int get_value(config_fn_t fn, void *data, char *name, unsigned int len)
break;
if (!iskeychar(c))
break;
- name[len++] = tolower(c);
+ name[len++] = c;
if (len >= MAXNAME)
return -1;
}
@@ -327,6 +332,13 @@ int perf_config_bool(const char *name, const char *value)
return !!perf_config_bool_or_int(name, value, &discard);
}
+const char *perf_config_dirname(const char *name, const char *value)
+{
+ if (!name)
+ return NULL;
+ return value;
+}
+
static int perf_default_core_config(const char *var __used, const char *value __used)
{
/* Add other config variables here and to Documentation/config.txt. */
@@ -428,3 +440,53 @@ int config_error_nonbool(const char *var)
{
return error("Missing value for '%s'", var);
}
+
+struct buildid_dir_config {
+ char *dir;
+};
+
+static int buildid_dir_command_config(const char *var, const char *value,
+ void *data)
+{
+ struct buildid_dir_config *c = data;
+ const char *v;
+
+ /* same dir for all commands */
+ if (!prefixcmp(var, "buildid.") && !strcmp(var + 8, "dir")) {
+ v = perf_config_dirname(var, value);
+ if (!v)
+ return -1;
+ strncpy(c->dir, v, MAXPATHLEN-1);
+ c->dir[MAXPATHLEN-1] = '\0';
+ }
+ return 0;
+}
+
+static void check_buildid_dir_config(void)
+{
+ struct buildid_dir_config c;
+ c.dir = buildid_dir;
+ perf_config(buildid_dir_command_config, &c);
+}
+
+void set_buildid_dir(void)
+{
+ buildid_dir[0] = '\0';
+
+ /* try config file */
+ check_buildid_dir_config();
+
+ /* default to $HOME/.debug */
+ if (buildid_dir[0] == '\0') {
+ char *v = getenv("HOME");
+ if (v) {
+ snprintf(buildid_dir, MAXPATHLEN-1, "%s/%s",
+ v, DEBUG_CACHE_DIR);
+ } else {
+ strncpy(buildid_dir, DEBUG_CACHE_DIR, MAXPATHLEN-1);
+ }
+ buildid_dir[MAXPATHLEN-1] = '\0';
+ }
+ /* for communicating with external commands */
+ setenv("PERF_BUILDID_DIR", buildid_dir, 1);
+}
diff --git a/tools/perf/util/cpumap.c b/tools/perf/util/cpumap.c
index 4e01490e51e..0f9b8d7a7d7 100644
--- a/tools/perf/util/cpumap.c
+++ b/tools/perf/util/cpumap.c
@@ -20,7 +20,7 @@ static int default_cpu_map(void)
return nr_cpus;
}
-int read_cpu_map(void)
+static int read_all_cpu_map(void)
{
FILE *onlnf;
int nr_cpus = 0;
@@ -57,3 +57,58 @@ int read_cpu_map(void)
return default_cpu_map();
}
+
+int read_cpu_map(const char *cpu_list)
+{
+ unsigned long start_cpu, end_cpu = 0;
+ char *p = NULL;
+ int i, nr_cpus = 0;
+
+ if (!cpu_list)
+ return read_all_cpu_map();
+
+ if (!isdigit(*cpu_list))
+ goto invalid;
+
+ while (isdigit(*cpu_list)) {
+ p = NULL;
+ start_cpu = strtoul(cpu_list, &p, 0);
+ if (start_cpu >= INT_MAX
+ || (*p != '\0' && *p != ',' && *p != '-'))
+ goto invalid;
+
+ if (*p == '-') {
+ cpu_list = ++p;
+ p = NULL;
+ end_cpu = strtoul(cpu_list, &p, 0);
+
+ if (end_cpu >= INT_MAX || (*p != '\0' && *p != ','))
+ goto invalid;
+
+ if (end_cpu < start_cpu)
+ goto invalid;
+ } else {
+ end_cpu = start_cpu;
+ }
+
+ for (; start_cpu <= end_cpu; start_cpu++) {
+ /* check for duplicates */
+ for (i = 0; i < nr_cpus; i++)
+ if (cpumap[i] == (int)start_cpu)
+ goto invalid;
+
+ assert(nr_cpus < MAX_NR_CPUS);
+ cpumap[nr_cpus++] = (int)start_cpu;
+ }
+ if (*p)
+ ++p;
+
+ cpu_list = p;
+ }
+ if (nr_cpus > 0)
+ return nr_cpus;
+
+ return default_cpu_map();
+invalid:
+ return -1;
+}
diff --git a/tools/perf/util/cpumap.h b/tools/perf/util/cpumap.h
index 86c78bb3309..3e60f56e490 100644
--- a/tools/perf/util/cpumap.h
+++ b/tools/perf/util/cpumap.h
@@ -1,7 +1,7 @@
#ifndef __PERF_CPUMAP_H
#define __PERF_CPUMAP_H
-extern int read_cpu_map(void);
+extern int read_cpu_map(const char *cpu_list);
extern int cpumap[];
#endif /* __PERF_CPUMAP_H */
diff --git a/tools/perf/util/debug.c b/tools/perf/util/debug.c
index 6cddff2bc97..318dab15d17 100644
--- a/tools/perf/util/debug.c
+++ b/tools/perf/util/debug.c
@@ -86,12 +86,10 @@ void trace_event(event_t *event)
dump_printf_color(" ", color);
for (j = 0; j < 15-(i & 15); j++)
dump_printf_color(" ", color);
- for (j = 0; j < (i & 15); j++) {
- if (isprint(raw_event[i-15+j]))
- dump_printf_color("%c", color,
- raw_event[i-15+j]);
- else
- dump_printf_color(".", color);
+ for (j = i & ~15; j <= i; j++) {
+ dump_printf_color("%c", color,
+ isprint(raw_event[j]) ?
+ raw_event[j] : '.');
}
dump_printf_color("\n", color);
}
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c
index 2fbf6a463c8..dab9e754a28 100644
--- a/tools/perf/util/event.c
+++ b/tools/perf/util/event.c
@@ -151,7 +151,6 @@ static int event__synthesize_mmap_events(pid_t pid, pid_t tgid,
continue;
pbf += n + 3;
if (*pbf == 'x') { /* vm_exec */
- u64 vm_pgoff;
char *execname = strchr(bf, '/');
/* Catch VDSO */
@@ -162,12 +161,7 @@ static int event__synthesize_mmap_events(pid_t pid, pid_t tgid,
continue;
pbf += 3;
- n = hex2u64(pbf, &vm_pgoff);
- /* pgoff is in bytes, not pages */
- if (n >= 0)
- ev.mmap.pgoff = vm_pgoff << getpagesize();
- else
- ev.mmap.pgoff = 0;
+ n = hex2u64(pbf, &ev.mmap.pgoff);
size = strlen(execname);
execname[size - 1] = '\0'; /* Remove \n */
@@ -340,30 +334,29 @@ int event__synthesize_kernel_mmap(event__handler_t process,
return process(&ev, session);
}
-static void thread__comm_adjust(struct thread *self)
+static void thread__comm_adjust(struct thread *self, struct hists *hists)
{
char *comm = self->comm;
if (!symbol_conf.col_width_list_str && !symbol_conf.field_sep &&
(!symbol_conf.comm_list ||
strlist__has_entry(symbol_conf.comm_list, comm))) {
- unsigned int slen = strlen(comm);
+ u16 slen = strlen(comm);
- if (slen > comms__col_width) {
- comms__col_width = slen;
- threads__col_width = slen + 6;
- }
+ if (hists__new_col_len(hists, HISTC_COMM, slen))
+ hists__set_col_len(hists, HISTC_THREAD, slen + 6);
}
}
-static int thread__set_comm_adjust(struct thread *self, const char *comm)
+static int thread__set_comm_adjust(struct thread *self, const char *comm,
+ struct hists *hists)
{
int ret = thread__set_comm(self, comm);
if (ret)
return ret;
- thread__comm_adjust(self);
+ thread__comm_adjust(self, hists);
return 0;
}
@@ -374,7 +367,8 @@ int event__process_comm(event_t *self, struct perf_session *session)
dump_printf(": %s:%d\n", self->comm.comm, self->comm.tid);
- if (thread == NULL || thread__set_comm_adjust(thread, self->comm.comm)) {
+ if (thread == NULL || thread__set_comm_adjust(thread, self->comm.comm,
+ &session->hists)) {
dump_printf("problem processing PERF_RECORD_COMM, skipping event.\n");
return -1;
}
@@ -456,6 +450,7 @@ static int event__process_kernel_mmap(event_t *self,
goto out_problem;
map->dso->short_name = name;
+ map->dso->sname_alloc = 1;
map->end = map->start + self->mmap.len;
} else if (is_kernel_mmap) {
const char *symbol_name = (self->mmap.filename +
@@ -514,12 +509,13 @@ int event__process_mmap(event_t *self, struct perf_session *session)
if (machine == NULL)
goto out_problem;
thread = perf_session__findnew(session, self->mmap.pid);
+ if (thread == NULL)
+ goto out_problem;
map = map__new(&machine->user_dsos, self->mmap.start,
self->mmap.len, self->mmap.pgoff,
self->mmap.pid, self->mmap.filename,
- MAP__FUNCTION, session->cwd, session->cwdlen);
-
- if (thread == NULL || map == NULL)
+ MAP__FUNCTION);
+ if (map == NULL)
goto out_problem;
thread__insert_map(thread, map);
@@ -552,6 +548,26 @@ int event__process_task(event_t *self, struct perf_session *session)
return 0;
}
+int event__process(event_t *event, struct perf_session *session)
+{
+ switch (event->header.type) {
+ case PERF_RECORD_COMM:
+ event__process_comm(event, session);
+ break;
+ case PERF_RECORD_MMAP:
+ event__process_mmap(event, session);
+ break;
+ case PERF_RECORD_FORK:
+ case PERF_RECORD_EXIT:
+ event__process_task(event, session);
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
void thread__find_addr_map(struct thread *self,
struct perf_session *session, u8 cpumode,
enum map_type type, pid_t pid, u64 addr,
@@ -641,27 +657,49 @@ void thread__find_addr_location(struct thread *self,
al->sym = NULL;
}
-static void dso__calc_col_width(struct dso *self)
+static void dso__calc_col_width(struct dso *self, struct hists *hists)
{
if (!symbol_conf.col_width_list_str && !symbol_conf.field_sep &&
(!symbol_conf.dso_list ||
strlist__has_entry(symbol_conf.dso_list, self->name))) {
- u16 slen = self->short_name_len;
- if (verbose)
- slen = self->long_name_len;
- if (dsos__col_width < slen)
- dsos__col_width = slen;
+ u16 slen = dso__name_len(self);
+ hists__new_col_len(hists, HISTC_DSO, slen);
}
self->slen_calculated = 1;
}
int event__preprocess_sample(const event_t *self, struct perf_session *session,
- struct addr_location *al, symbol_filter_t filter)
+ struct addr_location *al, struct sample_data *data,
+ symbol_filter_t filter)
{
u8 cpumode = self->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
- struct thread *thread = perf_session__findnew(session, self->ip.pid);
+ struct thread *thread;
+ event__parse_sample(self, session->sample_type, data);
+
+ dump_printf("(IP, %d): %d/%d: %#Lx period: %Ld cpu:%d\n",
+ self->header.misc, data->pid, data->tid, data->ip,
+ data->period, data->cpu);
+
+ if (session->sample_type & PERF_SAMPLE_CALLCHAIN) {
+ unsigned int i;
+
+ dump_printf("... chain: nr:%Lu\n", data->callchain->nr);
+
+ if (!ip_callchain__valid(data->callchain, self)) {
+ pr_debug("call-chain problem with event, "
+ "skipping it.\n");
+ goto out_filtered;
+ }
+
+ if (dump_trace) {
+ for (i = 0; i < data->callchain->nr; i++)
+ dump_printf("..... %2d: %016Lx\n",
+ i, data->callchain->ips[i]);
+ }
+ }
+ thread = perf_session__findnew(session, self->ip.pid);
if (thread == NULL)
return -1;
@@ -687,6 +725,7 @@ int event__preprocess_sample(const event_t *self, struct perf_session *session,
al->map ? al->map->dso->long_name :
al->level == 'H' ? "[hypervisor]" : "<not found>");
al->sym = NULL;
+ al->cpu = data->cpu;
if (al->map) {
if (symbol_conf.dso_list &&
@@ -703,16 +742,17 @@ int event__preprocess_sample(const event_t *self, struct perf_session *session,
* sampled.
*/
if (!sort_dso.elide && !al->map->dso->slen_calculated)
- dso__calc_col_width(al->map->dso);
+ dso__calc_col_width(al->map->dso, &session->hists);
al->sym = map__find_symbol(al->map, al->addr, filter);
} else {
const unsigned int unresolved_col_width = BITS_PER_LONG / 4;
- if (dsos__col_width < unresolved_col_width &&
+ if (hists__col_len(&session->hists, HISTC_DSO) < unresolved_col_width &&
!symbol_conf.col_width_list_str && !symbol_conf.field_sep &&
!symbol_conf.dso_list)
- dsos__col_width = unresolved_col_width;
+ hists__set_col_len(&session->hists, HISTC_DSO,
+ unresolved_col_width);
}
if (symbol_conf.sym_list && al->sym &&
@@ -726,9 +766,9 @@ out_filtered:
return 0;
}
-int event__parse_sample(event_t *event, u64 type, struct sample_data *data)
+int event__parse_sample(const event_t *event, u64 type, struct sample_data *data)
{
- u64 *array = event->sample.array;
+ const u64 *array = event->sample.array;
if (type & PERF_SAMPLE_IP) {
data->ip = event->ip.ip;
@@ -767,7 +807,8 @@ int event__parse_sample(event_t *event, u64 type, struct sample_data *data)
u32 *p = (u32 *)array;
data->cpu = *p;
array++;
- }
+ } else
+ data->cpu = -1;
if (type & PERF_SAMPLE_PERIOD) {
data->period = *array;
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h
index 8577085db06..8e790dae702 100644
--- a/tools/perf/util/event.h
+++ b/tools/perf/util/event.h
@@ -154,11 +154,13 @@ int event__process_comm(event_t *self, struct perf_session *session);
int event__process_lost(event_t *self, struct perf_session *session);
int event__process_mmap(event_t *self, struct perf_session *session);
int event__process_task(event_t *self, struct perf_session *session);
+int event__process(event_t *event, struct perf_session *session);
struct addr_location;
int event__preprocess_sample(const event_t *self, struct perf_session *session,
- struct addr_location *al, symbol_filter_t filter);
-int event__parse_sample(event_t *event, u64 type, struct sample_data *data);
+ struct addr_location *al, struct sample_data *data,
+ symbol_filter_t filter);
+int event__parse_sample(const event_t *event, u64 type, struct sample_data *data);
extern const char *event__name[];
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index 1f62435f96c..d7e67b167ea 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -16,6 +16,8 @@
#include "symbol.h"
#include "debug.h"
+static bool no_buildid_cache = false;
+
/*
* Create new perf.data header attribute:
*/
@@ -385,8 +387,7 @@ static int perf_session__cache_build_ids(struct perf_session *self)
int ret;
char debugdir[PATH_MAX];
- snprintf(debugdir, sizeof(debugdir), "%s/%s", getenv("HOME"),
- DEBUG_CACHE_DIR);
+ snprintf(debugdir, sizeof(debugdir), "%s", buildid_dir);
if (mkdir(debugdir, 0755) != 0 && errno != EEXIST)
return -1;
@@ -471,7 +472,8 @@ static int perf_header__adds_write(struct perf_header *self, int fd)
}
buildid_sec->size = lseek(fd, 0, SEEK_CUR) -
buildid_sec->offset;
- perf_session__cache_build_ids(session);
+ if (!no_buildid_cache)
+ perf_session__cache_build_ids(session);
}
lseek(fd, sec_start, SEEK_SET);
@@ -1190,3 +1192,8 @@ int event__process_build_id(event_t *self,
session);
return 0;
}
+
+void disable_buildid_cache(void)
+{
+ no_buildid_cache = true;
+}
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c
index 784ee0bdda7..e7263d49bcf 100644
--- a/tools/perf/util/hist.c
+++ b/tools/perf/util/hist.c
@@ -5,11 +5,61 @@
#include "sort.h"
#include <math.h>
+enum hist_filter {
+ HIST_FILTER__DSO,
+ HIST_FILTER__THREAD,
+ HIST_FILTER__PARENT,
+};
+
struct callchain_param callchain_param = {
.mode = CHAIN_GRAPH_REL,
.min_percent = 0.5
};
+u16 hists__col_len(struct hists *self, enum hist_column col)
+{
+ return self->col_len[col];
+}
+
+void hists__set_col_len(struct hists *self, enum hist_column col, u16 len)
+{
+ self->col_len[col] = len;
+}
+
+bool hists__new_col_len(struct hists *self, enum hist_column col, u16 len)
+{
+ if (len > hists__col_len(self, col)) {
+ hists__set_col_len(self, col, len);
+ return true;
+ }
+ return false;
+}
+
+static void hists__reset_col_len(struct hists *self)
+{
+ enum hist_column col;
+
+ for (col = 0; col < HISTC_NR_COLS; ++col)
+ hists__set_col_len(self, col, 0);
+}
+
+static void hists__calc_col_len(struct hists *self, struct hist_entry *h)
+{
+ u16 len;
+
+ if (h->ms.sym)
+ hists__new_col_len(self, HISTC_SYMBOL, h->ms.sym->namelen);
+
+ len = thread__comm_len(h->thread);
+ if (hists__new_col_len(self, HISTC_COMM, len))
+ hists__set_col_len(self, HISTC_THREAD, len + 6);
+
+ if (h->ms.map) {
+ len = dso__name_len(h->ms.map->dso);
+ hists__new_col_len(self, HISTC_DSO, len);
+ }
+}
+
static void hist_entry__add_cpumode_period(struct hist_entry *self,
unsigned int cpumode, u64 period)
{
@@ -43,6 +93,8 @@ static struct hist_entry *hist_entry__new(struct hist_entry *template)
if (self != NULL) {
*self = *template;
self->nr_events = 1;
+ if (self->ms.map)
+ self->ms.map->referenced = true;
if (symbol_conf.use_callchain)
callchain_init(self->callchain);
}
@@ -50,11 +102,19 @@ static struct hist_entry *hist_entry__new(struct hist_entry *template)
return self;
}
-static void hists__inc_nr_entries(struct hists *self, struct hist_entry *entry)
+static void hists__inc_nr_entries(struct hists *self, struct hist_entry *h)
{
- if (entry->ms.sym && self->max_sym_namelen < entry->ms.sym->namelen)
- self->max_sym_namelen = entry->ms.sym->namelen;
- ++self->nr_entries;
+ if (!h->filtered) {
+ hists__calc_col_len(self, h);
+ ++self->nr_entries;
+ }
+}
+
+static u8 symbol__parent_filter(const struct symbol *parent)
+{
+ if (symbol_conf.exclude_other && parent == NULL)
+ return 1 << HIST_FILTER__PARENT;
+ return 0;
}
struct hist_entry *__hists__add_entry(struct hists *self,
@@ -70,10 +130,12 @@ struct hist_entry *__hists__add_entry(struct hists *self,
.map = al->map,
.sym = al->sym,
},
+ .cpu = al->cpu,
.ip = al->addr,
.level = al->level,
.period = period,
.parent = sym_parent,
+ .filtered = symbol__parent_filter(sym_parent),
};
int cmp;
@@ -191,7 +253,7 @@ void hists__collapse_resort(struct hists *self)
tmp = RB_ROOT;
next = rb_first(&self->entries);
self->nr_entries = 0;
- self->max_sym_namelen = 0;
+ hists__reset_col_len(self);
while (next) {
n = rb_entry(next, struct hist_entry, rb_node);
@@ -248,7 +310,7 @@ void hists__output_resort(struct hists *self)
next = rb_first(&self->entries);
self->nr_entries = 0;
- self->max_sym_namelen = 0;
+ hists__reset_col_len(self);
while (next) {
n = rb_entry(next, struct hist_entry, rb_node);
@@ -515,8 +577,9 @@ static size_t hist_entry_callchain__fprintf(FILE *fp, struct hist_entry *self,
}
int hist_entry__snprintf(struct hist_entry *self, char *s, size_t size,
- struct hists *pair_hists, bool show_displacement,
- long displacement, bool color, u64 session_total)
+ struct hists *hists, struct hists *pair_hists,
+ bool show_displacement, long displacement,
+ bool color, u64 session_total)
{
struct sort_entry *se;
u64 period, total, period_sys, period_us, period_guest_sys, period_guest_us;
@@ -620,29 +683,25 @@ int hist_entry__snprintf(struct hist_entry *self, char *s, size_t size,
ret += snprintf(s + ret, size - ret, "%s", sep ?: " ");
ret += se->se_snprintf(self, s + ret, size - ret,
- se->se_width ? *se->se_width : 0);
+ hists__col_len(hists, se->se_width_idx));
}
return ret;
}
-int hist_entry__fprintf(struct hist_entry *self, struct hists *pair_hists,
- bool show_displacement, long displacement, FILE *fp,
- u64 session_total)
+int hist_entry__fprintf(struct hist_entry *self, struct hists *hists,
+ struct hists *pair_hists, bool show_displacement,
+ long displacement, FILE *fp, u64 session_total)
{
char bf[512];
- int ret;
-
- ret = hist_entry__snprintf(self, bf, sizeof(bf), pair_hists,
- show_displacement, displacement,
- true, session_total);
- if (!ret)
- return 0;
-
+ hist_entry__snprintf(self, bf, sizeof(bf), hists, pair_hists,
+ show_displacement, displacement,
+ true, session_total);
return fprintf(fp, "%s\n", bf);
}
-static size_t hist_entry__fprintf_callchain(struct hist_entry *self, FILE *fp,
+static size_t hist_entry__fprintf_callchain(struct hist_entry *self,
+ struct hists *hists, FILE *fp,
u64 session_total)
{
int left_margin = 0;
@@ -650,7 +709,7 @@ static size_t hist_entry__fprintf_callchain(struct hist_entry *self, FILE *fp,
if (sort__first_dimension == SORT_COMM) {
struct sort_entry *se = list_first_entry(&hist_entry__sort_list,
typeof(*se), list);
- left_margin = se->se_width ? *se->se_width : 0;
+ left_margin = hists__col_len(hists, se->se_width_idx);
left_margin -= thread__comm_len(self->thread);
}
@@ -721,17 +780,17 @@ size_t hists__fprintf(struct hists *self, struct hists *pair,
continue;
}
width = strlen(se->se_header);
- if (se->se_width) {
- if (symbol_conf.col_width_list_str) {
- if (col_width) {
- *se->se_width = atoi(col_width);
- col_width = strchr(col_width, ',');
- if (col_width)
- ++col_width;
- }
+ if (symbol_conf.col_width_list_str) {
+ if (col_width) {
+ hists__set_col_len(self, se->se_width_idx,
+ atoi(col_width));
+ col_width = strchr(col_width, ',');
+ if (col_width)
+ ++col_width;
}
- width = *se->se_width = max(*se->se_width, width);
}
+ if (!hists__new_col_len(self, se->se_width_idx, width))
+ width = hists__col_len(self, se->se_width_idx);
fprintf(fp, " %*s", width, se->se_header);
}
fprintf(fp, "\n");
@@ -754,9 +813,8 @@ size_t hists__fprintf(struct hists *self, struct hists *pair,
continue;
fprintf(fp, " ");
- if (se->se_width)
- width = *se->se_width;
- else
+ width = hists__col_len(self, se->se_width_idx);
+ if (width == 0)
width = strlen(se->se_header);
for (i = 0; i < width; i++)
fprintf(fp, ".");
@@ -767,7 +825,6 @@ size_t hists__fprintf(struct hists *self, struct hists *pair,
print_entries:
for (nd = rb_first(&self->entries); nd; nd = rb_next(nd)) {
struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
- int cnt;
if (show_displacement) {
if (h->pair != NULL)
@@ -777,17 +834,12 @@ print_entries:
displacement = 0;
++position;
}
- cnt = hist_entry__fprintf(h, pair, show_displacement,
- displacement, fp, self->stats.total_period);
- /* Ignore those that didn't match the parent filter */
- if (!cnt)
- continue;
-
- ret += cnt;
+ ret += hist_entry__fprintf(h, self, pair, show_displacement,
+ displacement, fp, self->stats.total_period);
if (symbol_conf.use_callchain)
- ret += hist_entry__fprintf_callchain(h, fp, self->stats.total_period);
-
+ ret += hist_entry__fprintf_callchain(h, self, fp,
+ self->stats.total_period);
if (h->ms.map == NULL && verbose > 1) {
__map_groups__fprintf_maps(&h->thread->mg,
MAP__FUNCTION, verbose, fp);
@@ -800,10 +852,49 @@ print_entries:
return ret;
}
-enum hist_filter {
- HIST_FILTER__DSO,
- HIST_FILTER__THREAD,
-};
+/*
+ * See hists__fprintf to match the column widths
+ */
+unsigned int hists__sort_list_width(struct hists *self)
+{
+ struct sort_entry *se;
+ int ret = 9; /* total % */
+
+ if (symbol_conf.show_cpu_utilization) {
+ ret += 7; /* count_sys % */
+ ret += 6; /* count_us % */
+ if (perf_guest) {
+ ret += 13; /* count_guest_sys % */
+ ret += 12; /* count_guest_us % */
+ }
+ }
+
+ if (symbol_conf.show_nr_samples)
+ ret += 11;
+
+ list_for_each_entry(se, &hist_entry__sort_list, list)
+ if (!se->elide)
+ ret += 2 + hists__col_len(self, se->se_width_idx);
+
+ return ret;
+}
+
+static void hists__remove_entry_filter(struct hists *self, struct hist_entry *h,
+ enum hist_filter filter)
+{
+ h->filtered &= ~(1 << filter);
+ if (h->filtered)
+ return;
+
+ ++self->nr_entries;
+ if (h->ms.unfolded)
+ self->nr_entries += h->nr_rows;
+ h->row_offset = 0;
+ self->stats.total_period += h->period;
+ self->stats.nr_events[PERF_RECORD_SAMPLE] += h->nr_events;
+
+ hists__calc_col_len(self, h);
+}
void hists__filter_by_dso(struct hists *self, const struct dso *dso)
{
@@ -811,7 +902,7 @@ void hists__filter_by_dso(struct hists *self, const struct dso *dso)
self->nr_entries = self->stats.total_period = 0;
self->stats.nr_events[PERF_RECORD_SAMPLE] = 0;
- self->max_sym_namelen = 0;
+ hists__reset_col_len(self);
for (nd = rb_first(&self->entries); nd; nd = rb_next(nd)) {
struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
@@ -824,15 +915,7 @@ void hists__filter_by_dso(struct hists *self, const struct dso *dso)
continue;
}
- h->filtered &= ~(1 << HIST_FILTER__DSO);
- if (!h->filtered) {
- ++self->nr_entries;
- self->stats.total_period += h->period;
- self->stats.nr_events[PERF_RECORD_SAMPLE] += h->nr_events;
- if (h->ms.sym &&
- self->max_sym_namelen < h->ms.sym->namelen)
- self->max_sym_namelen = h->ms.sym->namelen;
- }
+ hists__remove_entry_filter(self, h, HIST_FILTER__DSO);
}
}
@@ -842,7 +925,7 @@ void hists__filter_by_thread(struct hists *self, const struct thread *thread)
self->nr_entries = self->stats.total_period = 0;
self->stats.nr_events[PERF_RECORD_SAMPLE] = 0;
- self->max_sym_namelen = 0;
+ hists__reset_col_len(self);
for (nd = rb_first(&self->entries); nd; nd = rb_next(nd)) {
struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
@@ -851,15 +934,8 @@ void hists__filter_by_thread(struct hists *self, const struct thread *thread)
h->filtered |= (1 << HIST_FILTER__THREAD);
continue;
}
- h->filtered &= ~(1 << HIST_FILTER__THREAD);
- if (!h->filtered) {
- ++self->nr_entries;
- self->stats.total_period += h->period;
- self->stats.nr_events[PERF_RECORD_SAMPLE] += h->nr_events;
- if (h->ms.sym &&
- self->max_sym_namelen < h->ms.sym->namelen)
- self->max_sym_namelen = h->ms.sym->namelen;
- }
+
+ hists__remove_entry_filter(self, h, HIST_FILTER__THREAD);
}
}
@@ -1052,7 +1128,7 @@ fallback:
dso, dso->long_name, sym, sym->name);
snprintf(command, sizeof(command),
- "objdump --start-address=0x%016Lx --stop-address=0x%016Lx -dS %s|grep -v %s|expand",
+ "objdump --start-address=0x%016Lx --stop-address=0x%016Lx -dS -C %s|grep -v %s|expand",
map__rip_2objdump(map, sym->start),
map__rip_2objdump(map, sym->end),
filename, filename);
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h
index 83fa33a7b38..65a48db46a2 100644
--- a/tools/perf/util/hist.h
+++ b/tools/perf/util/hist.h
@@ -56,6 +56,16 @@ struct events_stats {
u32 nr_unknown_events;
};
+enum hist_column {
+ HISTC_SYMBOL,
+ HISTC_DSO,
+ HISTC_THREAD,
+ HISTC_COMM,
+ HISTC_PARENT,
+ HISTC_CPU,
+ HISTC_NR_COLS, /* Last entry */
+};
+
struct hists {
struct rb_node rb_node;
struct rb_root entries;
@@ -64,7 +74,7 @@ struct hists {
u64 config;
u64 event_stream;
u32 type;
- u32 max_sym_namelen;
+ u16 col_len[HISTC_NR_COLS];
};
struct hist_entry *__hists__add_entry(struct hists *self,
@@ -72,12 +82,13 @@ struct hist_entry *__hists__add_entry(struct hists *self,
struct symbol *parent, u64 period);
extern int64_t hist_entry__cmp(struct hist_entry *, struct hist_entry *);
extern int64_t hist_entry__collapse(struct hist_entry *, struct hist_entry *);
-int hist_entry__fprintf(struct hist_entry *self, struct hists *pair_hists,
- bool show_displacement, long displacement, FILE *fp,
- u64 total);
+int hist_entry__fprintf(struct hist_entry *self, struct hists *hists,
+ struct hists *pair_hists, bool show_displacement,
+ long displacement, FILE *fp, u64 total);
int hist_entry__snprintf(struct hist_entry *self, char *bf, size_t size,
- struct hists *pair_hists, bool show_displacement,
- long displacement, bool color, u64 total);
+ struct hists *hists, struct hists *pair_hists,
+ bool show_displacement, long displacement,
+ bool color, u64 total);
void hist_entry__free(struct hist_entry *);
void hists__output_resort(struct hists *self);
@@ -95,6 +106,10 @@ int hist_entry__annotate(struct hist_entry *self, struct list_head *head);
void hists__filter_by_dso(struct hists *self, const struct dso *dso);
void hists__filter_by_thread(struct hists *self, const struct thread *thread);
+u16 hists__col_len(struct hists *self, enum hist_column col);
+void hists__set_col_len(struct hists *self, enum hist_column col, u16 len);
+bool hists__new_col_len(struct hists *self, enum hist_column col, u16 len);
+
#ifdef NO_NEWT_SUPPORT
static inline int hists__browse(struct hists *self __used,
const char *helpline __used,
@@ -126,4 +141,7 @@ int hist_entry__tui_annotate(struct hist_entry *self);
int hists__tui_browse_tree(struct rb_root *self, const char *help);
#endif
+
+unsigned int hists__sort_list_width(struct hists *self);
+
#endif /* __PERF_HIST_H */
diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c
index e672f2fef65..3a7eb6ec0ee 100644
--- a/tools/perf/util/map.c
+++ b/tools/perf/util/map.c
@@ -17,16 +17,6 @@ static inline int is_anon_memory(const char *filename)
return strcmp(filename, "//anon") == 0;
}
-static int strcommon(const char *pathname, char *cwd, int cwdlen)
-{
- int n = 0;
-
- while (n < cwdlen && pathname[n] == cwd[n])
- ++n;
-
- return n;
-}
-
void map__init(struct map *self, enum map_type type,
u64 start, u64 end, u64 pgoff, struct dso *dso)
{
@@ -39,11 +29,12 @@ void map__init(struct map *self, enum map_type type,
self->unmap_ip = map__unmap_ip;
RB_CLEAR_NODE(&self->rb_node);
self->groups = NULL;
+ self->referenced = false;
}
struct map *map__new(struct list_head *dsos__list, u64 start, u64 len,
u64 pgoff, u32 pid, char *filename,
- enum map_type type, char *cwd, int cwdlen)
+ enum map_type type)
{
struct map *self = malloc(sizeof(*self));
@@ -52,16 +43,6 @@ struct map *map__new(struct list_head *dsos__list, u64 start, u64 len,
struct dso *dso;
int anon;
- if (cwd) {
- int n = strcommon(filename, cwd, cwdlen);
-
- if (n == cwdlen) {
- snprintf(newfilename, sizeof(newfilename),
- ".%s", filename + n);
- filename = newfilename;
- }
- }
-
anon = is_anon_memory(filename);
if (anon) {
@@ -248,6 +229,39 @@ void map_groups__init(struct map_groups *self)
self->machine = NULL;
}
+static void maps__delete(struct rb_root *self)
+{
+ struct rb_node *next = rb_first(self);
+
+ while (next) {
+ struct map *pos = rb_entry(next, struct map, rb_node);
+
+ next = rb_next(&pos->rb_node);
+ rb_erase(&pos->rb_node, self);
+ map__delete(pos);
+ }
+}
+
+static void maps__delete_removed(struct list_head *self)
+{
+ struct map *pos, *n;
+
+ list_for_each_entry_safe(pos, n, self, node) {
+ list_del(&pos->node);
+ map__delete(pos);
+ }
+}
+
+void map_groups__exit(struct map_groups *self)
+{
+ int i;
+
+ for (i = 0; i < MAP__NR_TYPES; ++i) {
+ maps__delete(&self->maps[i]);
+ maps__delete_removed(&self->removed_maps[i]);
+ }
+}
+
void map_groups__flush(struct map_groups *self)
{
int type;
@@ -374,6 +388,7 @@ int map_groups__fixup_overlappings(struct map_groups *self, struct map *map,
{
struct rb_root *root = &self->maps[map->type];
struct rb_node *next = rb_first(root);
+ int err = 0;
while (next) {
struct map *pos = rb_entry(next, struct map, rb_node);
@@ -390,20 +405,16 @@ int map_groups__fixup_overlappings(struct map_groups *self, struct map *map,
rb_erase(&pos->rb_node, root);
/*
- * We may have references to this map, for instance in some
- * hist_entry instances, so just move them to a separate
- * list.
- */
- list_add_tail(&pos->node, &self->removed_maps[map->type]);
- /*
* Now check if we need to create new maps for areas not
* overlapped by the new map:
*/
if (map->start > pos->start) {
struct map *before = map__clone(pos);
- if (before == NULL)
- return -ENOMEM;
+ if (before == NULL) {
+ err = -ENOMEM;
+ goto move_map;
+ }
before->end = map->start - 1;
map_groups__insert(self, before);
@@ -414,14 +425,27 @@ int map_groups__fixup_overlappings(struct map_groups *self, struct map *map,
if (map->end < pos->end) {
struct map *after = map__clone(pos);
- if (after == NULL)
- return -ENOMEM;
+ if (after == NULL) {
+ err = -ENOMEM;
+ goto move_map;
+ }
after->start = map->end + 1;
map_groups__insert(self, after);
if (verbose >= 2)
map__fprintf(after, fp);
}
+move_map:
+ /*
+ * If we have references, just move them to a separate list.
+ */
+ if (pos->referenced)
+ list_add_tail(&pos->node, &self->removed_maps[map->type]);
+ else
+ map__delete(pos);
+
+ if (err)
+ return err;
}
return 0;
@@ -493,6 +517,11 @@ void maps__insert(struct rb_root *maps, struct map *map)
rb_insert_color(&map->rb_node, maps);
}
+void maps__remove(struct rb_root *self, struct map *map)
+{
+ rb_erase(&map->rb_node, self);
+}
+
struct map *maps__find(struct rb_root *maps, u64 ip)
{
struct rb_node **p = &maps->rb_node;
@@ -526,6 +555,31 @@ int machine__init(struct machine *self, const char *root_dir, pid_t pid)
return self->root_dir == NULL ? -ENOMEM : 0;
}
+static void dsos__delete(struct list_head *self)
+{
+ struct dso *pos, *n;
+
+ list_for_each_entry_safe(pos, n, self, node) {
+ list_del(&pos->node);
+ dso__delete(pos);
+ }
+}
+
+void machine__exit(struct machine *self)
+{
+ map_groups__exit(&self->kmaps);
+ dsos__delete(&self->user_dsos);
+ dsos__delete(&self->kernel_dsos);
+ free(self->root_dir);
+ self->root_dir = NULL;
+}
+
+void machine__delete(struct machine *self)
+{
+ machine__exit(self);
+ free(self);
+}
+
struct machine *machines__add(struct rb_root *self, pid_t pid,
const char *root_dir)
{
diff --git a/tools/perf/util/map.h b/tools/perf/util/map.h
index f3913451282..78575796d5f 100644
--- a/tools/perf/util/map.h
+++ b/tools/perf/util/map.h
@@ -29,7 +29,8 @@ struct map {
};
u64 start;
u64 end;
- enum map_type type;
+ u8 /* enum map_type */ type;
+ bool referenced;
u32 priv;
u64 pgoff;
@@ -106,7 +107,7 @@ void map__init(struct map *self, enum map_type type,
u64 start, u64 end, u64 pgoff, struct dso *dso);
struct map *map__new(struct list_head *dsos__list, u64 start, u64 len,
u64 pgoff, u32 pid, char *filename,
- enum map_type type, char *cwd, int cwdlen);
+ enum map_type type);
void map__delete(struct map *self);
struct map *map__clone(struct map *self);
int map__overlap(struct map *l, struct map *r);
@@ -125,8 +126,10 @@ void map__reloc_vmlinux(struct map *self);
size_t __map_groups__fprintf_maps(struct map_groups *self,
enum map_type type, int verbose, FILE *fp);
void maps__insert(struct rb_root *maps, struct map *map);
+void maps__remove(struct rb_root *self, struct map *map);
struct map *maps__find(struct rb_root *maps, u64 addr);
void map_groups__init(struct map_groups *self);
+void map_groups__exit(struct map_groups *self);
int map_groups__clone(struct map_groups *self,
struct map_groups *parent, enum map_type type);
size_t map_groups__fprintf(struct map_groups *self, int verbose, FILE *fp);
@@ -142,6 +145,8 @@ struct machine *machines__find(struct rb_root *self, pid_t pid);
struct machine *machines__findnew(struct rb_root *self, pid_t pid);
char *machine__mmap_name(struct machine *self, char *bf, size_t size);
int machine__init(struct machine *self, const char *root_dir, pid_t pid);
+void machine__exit(struct machine *self);
+void machine__delete(struct machine *self);
/*
* Default guest kernel is defined by parameter --guestkallsyms
@@ -163,6 +168,11 @@ static inline void map_groups__insert(struct map_groups *self, struct map *map)
map->groups = self;
}
+static inline void map_groups__remove(struct map_groups *self, struct map *map)
+{
+ maps__remove(&self->maps[map->type], map);
+}
+
static inline struct map *map_groups__find(struct map_groups *self,
enum map_type type, u64 addr)
{
diff --git a/tools/perf/util/newt.c b/tools/perf/util/newt.c
index 7537ca15900..91de99b5844 100644
--- a/tools/perf/util/newt.c
+++ b/tools/perf/util/newt.c
@@ -11,6 +11,7 @@
#define HAVE_LONG_LONG __GLIBC_HAVE_LONG_LONG
#endif
#include <slang.h>
+#include <signal.h>
#include <stdlib.h>
#include <newt.h>
#include <sys/ttydefaults.h>
@@ -278,9 +279,48 @@ struct ui_browser {
void *first_visible_entry, *entries;
u16 top, left, width, height;
void *priv;
+ unsigned int (*refresh_entries)(struct ui_browser *self);
+ void (*seek)(struct ui_browser *self,
+ off_t offset, int whence);
u32 nr_entries;
};
+static void ui_browser__list_head_seek(struct ui_browser *self,
+ off_t offset, int whence)
+{
+ struct list_head *head = self->entries;
+ struct list_head *pos;
+
+ switch (whence) {
+ case SEEK_SET:
+ pos = head->next;
+ break;
+ case SEEK_CUR:
+ pos = self->first_visible_entry;
+ break;
+ case SEEK_END:
+ pos = head->prev;
+ break;
+ default:
+ return;
+ }
+
+ if (offset > 0) {
+ while (offset-- != 0)
+ pos = pos->next;
+ } else {
+ while (offset++ != 0)
+ pos = pos->prev;
+ }
+
+ self->first_visible_entry = pos;
+}
+
+static bool ui_browser__is_current_entry(struct ui_browser *self, unsigned row)
+{
+ return (self->first_visible_entry_idx + row) == self->index;
+}
+
static void ui_browser__refresh_dimensions(struct ui_browser *self)
{
int cols, rows;
@@ -297,8 +337,36 @@ static void ui_browser__refresh_dimensions(struct ui_browser *self)
static void ui_browser__reset_index(struct ui_browser *self)
{
- self->index = self->first_visible_entry_idx = 0;
- self->first_visible_entry = NULL;
+ self->index = self->first_visible_entry_idx = 0;
+ self->seek(self, 0, SEEK_SET);
+}
+
+static int ui_browser__show(struct ui_browser *self, const char *title)
+{
+ if (self->form != NULL) {
+ newtFormDestroy(self->form);
+ newtPopWindow();
+ }
+ ui_browser__refresh_dimensions(self);
+ newtCenteredWindow(self->width, self->height, title);
+ self->form = newt_form__new();
+ if (self->form == NULL)
+ return -1;
+
+ self->sb = newtVerticalScrollbar(self->width, 0, self->height,
+ HE_COLORSET_NORMAL,
+ HE_COLORSET_SELECTED);
+ if (self->sb == NULL)
+ return -1;
+
+ newtFormAddHotKey(self->form, NEWT_KEY_UP);
+ newtFormAddHotKey(self->form, NEWT_KEY_DOWN);
+ newtFormAddHotKey(self->form, NEWT_KEY_PGUP);
+ newtFormAddHotKey(self->form, NEWT_KEY_PGDN);
+ newtFormAddHotKey(self->form, NEWT_KEY_HOME);
+ newtFormAddHotKey(self->form, NEWT_KEY_END);
+ newtFormAddComponent(self->form, self->sb);
+ return 0;
}
static int objdump_line__show(struct objdump_line *self, struct list_head *head,
@@ -352,26 +420,10 @@ static int objdump_line__show(struct objdump_line *self, struct list_head *head,
static int ui_browser__refresh_entries(struct ui_browser *self)
{
- struct objdump_line *pos;
- struct list_head *head = self->entries;
- struct hist_entry *he = self->priv;
- int row = 0;
- int len = he->ms.sym->end - he->ms.sym->start;
-
- if (self->first_visible_entry == NULL || self->first_visible_entry == self->entries)
- self->first_visible_entry = head->next;
-
- pos = list_entry(self->first_visible_entry, struct objdump_line, node);
-
- list_for_each_entry_from(pos, head, node) {
- bool current_entry = (self->first_visible_entry_idx + row) == self->index;
- SLsmg_gotorc(self->top + row, self->left);
- objdump_line__show(pos, head, self->width,
- he, len, current_entry);
- if (++row == self->height)
- break;
- }
+ int row;
+ newtScrollbarSet(self->sb, self->index, self->nr_entries - 1);
+ row = self->refresh_entries(self);
SLsmg_set_color(HE_COLORSET_NORMAL);
SLsmg_fill_region(self->top + row, self->left,
self->height - row, self->width, ' ');
@@ -379,42 +431,13 @@ static int ui_browser__refresh_entries(struct ui_browser *self)
return 0;
}
-static int ui_browser__run(struct ui_browser *self, const char *title,
- struct newtExitStruct *es)
+static int ui_browser__run(struct ui_browser *self, struct newtExitStruct *es)
{
- if (self->form) {
- newtFormDestroy(self->form);
- newtPopWindow();
- }
-
- ui_browser__refresh_dimensions(self);
- newtCenteredWindow(self->width + 2, self->height, title);
- self->form = newt_form__new();
- if (self->form == NULL)
- return -1;
-
- self->sb = newtVerticalScrollbar(self->width + 1, 0, self->height,
- HE_COLORSET_NORMAL,
- HE_COLORSET_SELECTED);
- if (self->sb == NULL)
- return -1;
-
- newtFormAddHotKey(self->form, NEWT_KEY_UP);
- newtFormAddHotKey(self->form, NEWT_KEY_DOWN);
- newtFormAddHotKey(self->form, NEWT_KEY_PGUP);
- newtFormAddHotKey(self->form, NEWT_KEY_PGDN);
- newtFormAddHotKey(self->form, ' ');
- newtFormAddHotKey(self->form, NEWT_KEY_HOME);
- newtFormAddHotKey(self->form, NEWT_KEY_END);
- newtFormAddHotKey(self->form, NEWT_KEY_TAB);
- newtFormAddHotKey(self->form, NEWT_KEY_RIGHT);
-
if (ui_browser__refresh_entries(self) < 0)
return -1;
- newtFormAddComponent(self->form, self->sb);
while (1) {
- unsigned int offset;
+ off_t offset;
newtFormRun(self->form, es);
@@ -428,9 +451,8 @@ static int ui_browser__run(struct ui_browser *self, const char *title,
break;
++self->index;
if (self->index == self->first_visible_entry_idx + self->height) {
- struct list_head *pos = self->first_visible_entry;
++self->first_visible_entry_idx;
- self->first_visible_entry = pos->next;
+ self->seek(self, +1, SEEK_CUR);
}
break;
case NEWT_KEY_UP:
@@ -438,9 +460,8 @@ static int ui_browser__run(struct ui_browser *self, const char *title,
break;
--self->index;
if (self->index < self->first_visible_entry_idx) {
- struct list_head *pos = self->first_visible_entry;
--self->first_visible_entry_idx;
- self->first_visible_entry = pos->prev;
+ self->seek(self, -1, SEEK_CUR);
}
break;
case NEWT_KEY_PGDN:
@@ -453,12 +474,7 @@ static int ui_browser__run(struct ui_browser *self, const char *title,
offset = self->nr_entries - 1 - self->index;
self->index += offset;
self->first_visible_entry_idx += offset;
-
- while (offset--) {
- struct list_head *pos = self->first_visible_entry;
- self->first_visible_entry = pos->next;
- }
-
+ self->seek(self, +offset, SEEK_CUR);
break;
case NEWT_KEY_PGUP:
if (self->first_visible_entry_idx == 0)
@@ -471,36 +487,22 @@ static int ui_browser__run(struct ui_browser *self, const char *title,
self->index -= offset;
self->first_visible_entry_idx -= offset;
-
- while (offset--) {
- struct list_head *pos = self->first_visible_entry;
- self->first_visible_entry = pos->prev;
- }
+ self->seek(self, -offset, SEEK_CUR);
break;
case NEWT_KEY_HOME:
ui_browser__reset_index(self);
break;
- case NEWT_KEY_END: {
- struct list_head *head = self->entries;
+ case NEWT_KEY_END:
offset = self->height - 1;
+ if (offset >= self->nr_entries)
+ offset = self->nr_entries - 1;
- if (offset > self->nr_entries)
- offset = self->nr_entries;
-
- self->index = self->first_visible_entry_idx = self->nr_entries - 1 - offset;
- self->first_visible_entry = head->prev;
- while (offset-- != 0) {
- struct list_head *pos = self->first_visible_entry;
- self->first_visible_entry = pos->prev;
- }
- }
+ self->index = self->nr_entries - 1;
+ self->first_visible_entry_idx = self->index - offset;
+ self->seek(self, -offset, SEEK_END);
break;
- case NEWT_KEY_RIGHT:
- case NEWT_KEY_LEFT:
- case NEWT_KEY_TAB:
- return es->u.key;
default:
- continue;
+ return es->u.key;
}
if (ui_browser__refresh_entries(self) < 0)
return -1;
@@ -508,38 +510,6 @@ static int ui_browser__run(struct ui_browser *self, const char *title,
return 0;
}
-/*
- * When debugging newt problems it was useful to be able to "unroll"
- * the calls to newtCheckBoxTreeAdd{Array,Item}, so that we can generate
- * a source file with the sequence of calls to these methods, to then
- * tweak the arrays to get the intended results, so I'm keeping this code
- * here, may be useful again in the future.
- */
-#undef NEWT_DEBUG
-
-static void newt_checkbox_tree__add(newtComponent tree, const char *str,
- void *priv, int *indexes)
-{
-#ifdef NEWT_DEBUG
- /* Print the newtCheckboxTreeAddArray to tinker with its index arrays */
- int i = 0, len = 40 - strlen(str);
-
- fprintf(stderr,
- "\tnewtCheckboxTreeAddItem(tree, %*.*s\"%s\", (void *)%p, 0, ",
- len, len, " ", str, priv);
- while (indexes[i] != NEWT_ARG_LAST) {
- if (indexes[i] != NEWT_ARG_APPEND)
- fprintf(stderr, " %d,", indexes[i]);
- else
- fprintf(stderr, " %s,", "NEWT_ARG_APPEND");
- ++i;
- }
- fprintf(stderr, " %s", " NEWT_ARG_LAST);\n");
- fflush(stderr);
-#endif
- newtCheckboxTreeAddArray(tree, str, priv, 0, indexes);
-}
-
static char *callchain_list__sym_name(struct callchain_list *self,
char *bf, size_t bfsize)
{
@@ -550,144 +520,29 @@ static char *callchain_list__sym_name(struct callchain_list *self,
return bf;
}
-static void __callchain__append_graph_browser(struct callchain_node *self,
- newtComponent tree, u64 total,
- int *indexes, int depth)
+static unsigned int hist_entry__annotate_browser_refresh(struct ui_browser *self)
{
- struct rb_node *node;
- u64 new_total, remaining;
- int idx = 0;
-
- if (callchain_param.mode == CHAIN_GRAPH_REL)
- new_total = self->children_hit;
- else
- new_total = total;
-
- remaining = new_total;
- node = rb_first(&self->rb_root);
- while (node) {
- struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
- struct rb_node *next = rb_next(node);
- u64 cumul = cumul_hits(child);
- struct callchain_list *chain;
- int first = true, printed = 0;
- int chain_idx = -1;
- remaining -= cumul;
-
- indexes[depth] = NEWT_ARG_APPEND;
- indexes[depth + 1] = NEWT_ARG_LAST;
-
- list_for_each_entry(chain, &child->val, list) {
- char ipstr[BITS_PER_LONG / 4 + 1],
- *alloc_str = NULL;
- const char *str = callchain_list__sym_name(chain, ipstr, sizeof(ipstr));
-
- if (first) {
- double percent = cumul * 100.0 / new_total;
-
- first = false;
- if (asprintf(&alloc_str, "%2.2f%% %s", percent, str) < 0)
- str = "Not enough memory!";
- else
- str = alloc_str;
- } else {
- indexes[depth] = idx;
- indexes[depth + 1] = NEWT_ARG_APPEND;
- indexes[depth + 2] = NEWT_ARG_LAST;
- ++chain_idx;
- }
- newt_checkbox_tree__add(tree, str, &chain->ms, indexes);
- free(alloc_str);
- ++printed;
- }
-
- indexes[depth] = idx;
- if (chain_idx != -1)
- indexes[depth + 1] = chain_idx;
- if (printed != 0)
- ++idx;
- __callchain__append_graph_browser(child, tree, new_total, indexes,
- depth + (chain_idx != -1 ? 2 : 1));
- node = next;
- }
-}
-
-static void callchain__append_graph_browser(struct callchain_node *self,
- newtComponent tree, u64 total,
- int *indexes, int parent_idx)
-{
- struct callchain_list *chain;
- int i = 0;
-
- indexes[1] = NEWT_ARG_APPEND;
- indexes[2] = NEWT_ARG_LAST;
-
- list_for_each_entry(chain, &self->val, list) {
- char ipstr[BITS_PER_LONG / 4 + 1], *str;
-
- if (chain->ip >= PERF_CONTEXT_MAX)
- continue;
-
- if (!i++ && sort__first_dimension == SORT_SYM)
- continue;
+ struct objdump_line *pos;
+ struct list_head *head = self->entries;
+ struct hist_entry *he = self->priv;
+ int row = 0;
+ int len = he->ms.sym->end - he->ms.sym->start;
- str = callchain_list__sym_name(chain, ipstr, sizeof(ipstr));
- newt_checkbox_tree__add(tree, str, &chain->ms, indexes);
- }
+ if (self->first_visible_entry == NULL || self->first_visible_entry == self->entries)
+ self->first_visible_entry = head->next;
- indexes[1] = parent_idx;
- indexes[2] = NEWT_ARG_APPEND;
- indexes[3] = NEWT_ARG_LAST;
- __callchain__append_graph_browser(self, tree, total, indexes, 2);
-}
+ pos = list_entry(self->first_visible_entry, struct objdump_line, node);
-static void hist_entry__append_callchain_browser(struct hist_entry *self,
- newtComponent tree, u64 total, int parent_idx)
-{
- struct rb_node *rb_node;
- int indexes[1024] = { [0] = parent_idx, };
- int idx = 0;
- struct callchain_node *chain;
-
- rb_node = rb_first(&self->sorted_chain);
- while (rb_node) {
- chain = rb_entry(rb_node, struct callchain_node, rb_node);
- switch (callchain_param.mode) {
- case CHAIN_FLAT:
- break;
- case CHAIN_GRAPH_ABS: /* falldown */
- case CHAIN_GRAPH_REL:
- callchain__append_graph_browser(chain, tree, total, indexes, idx++);
- break;
- case CHAIN_NONE:
- default:
+ list_for_each_entry_from(pos, head, node) {
+ bool current_entry = ui_browser__is_current_entry(self, row);
+ SLsmg_gotorc(self->top + row, self->left);
+ objdump_line__show(pos, head, self->width,
+ he, len, current_entry);
+ if (++row == self->height)
break;
- }
- rb_node = rb_next(rb_node);
}
-}
-
-static size_t hist_entry__append_browser(struct hist_entry *self,
- newtComponent tree, u64 total)
-{
- char s[256];
- size_t ret;
-
- if (symbol_conf.exclude_other && !self->parent)
- return 0;
- ret = hist_entry__snprintf(self, s, sizeof(s), NULL,
- false, 0, false, total);
- if (symbol_conf.use_callchain) {
- int indexes[2];
-
- indexes[0] = NEWT_ARG_APPEND;
- indexes[1] = NEWT_ARG_LAST;
- newt_checkbox_tree__add(tree, s, &self->ms, indexes);
- } else
- newtListboxAppendEntry(tree, s, &self->ms);
-
- return ret;
+ return row;
}
int hist_entry__tui_annotate(struct hist_entry *self)
@@ -712,7 +567,9 @@ int hist_entry__tui_annotate(struct hist_entry *self)
ui_helpline__push("Press <- or ESC to exit");
memset(&browser, 0, sizeof(browser));
- browser.entries = &head;
+ browser.entries = &head;
+ browser.refresh_entries = hist_entry__annotate_browser_refresh;
+ browser.seek = ui_browser__list_head_seek;
browser.priv = self;
list_for_each_entry(pos, &head, node) {
size_t line_len = strlen(pos->line);
@@ -722,7 +579,9 @@ int hist_entry__tui_annotate(struct hist_entry *self)
}
browser.width += 18; /* Percentage */
- ret = ui_browser__run(&browser, self->ms.sym->name, &es);
+ ui_browser__show(&browser, self->ms.sym->name);
+ newtFormAddHotKey(browser.form, ' ');
+ ret = ui_browser__run(&browser, &es);
newtFormDestroy(browser.form);
newtPopWindow();
list_for_each_entry_safe(pos, n, &head, node) {
@@ -733,157 +592,48 @@ int hist_entry__tui_annotate(struct hist_entry *self)
return ret;
}
-static const void *newt__symbol_tree_get_current(newtComponent self)
-{
- if (symbol_conf.use_callchain)
- return newtCheckboxTreeGetCurrent(self);
- return newtListboxGetCurrent(self);
-}
-
-static void hist_browser__selection(newtComponent self, void *data)
-{
- const struct map_symbol **symbol_ptr = data;
- *symbol_ptr = newt__symbol_tree_get_current(self);
-}
-
struct hist_browser {
- newtComponent form, tree;
- const struct map_symbol *selection;
+ struct ui_browser b;
+ struct hists *hists;
+ struct hist_entry *he_selection;
+ struct map_symbol *selection;
};
-static struct hist_browser *hist_browser__new(void)
+static void hist_browser__reset(struct hist_browser *self);
+static int hist_browser__run(struct hist_browser *self, const char *title,
+ struct newtExitStruct *es);
+static unsigned int hist_browser__refresh_entries(struct ui_browser *self);
+static void ui_browser__hists_seek(struct ui_browser *self,
+ off_t offset, int whence);
+
+static struct hist_browser *hist_browser__new(struct hists *hists)
{
- struct hist_browser *self = malloc(sizeof(*self));
+ struct hist_browser *self = zalloc(sizeof(*self));
- if (self != NULL)
- self->form = NULL;
+ if (self) {
+ self->hists = hists;
+ self->b.refresh_entries = hist_browser__refresh_entries;
+ self->b.seek = ui_browser__hists_seek;
+ }
return self;
}
static void hist_browser__delete(struct hist_browser *self)
{
- newtFormDestroy(self->form);
+ newtFormDestroy(self->b.form);
newtPopWindow();
free(self);
}
-static int hist_browser__populate(struct hist_browser *self, struct hists *hists,
- const char *title)
-{
- int max_len = 0, idx, cols, rows;
- struct ui_progress *progress;
- struct rb_node *nd;
- u64 curr_hist = 0;
- char seq[] = ".", unit;
- char str[256];
- unsigned long nr_events = hists->stats.nr_events[PERF_RECORD_SAMPLE];
-
- if (self->form) {
- newtFormDestroy(self->form);
- newtPopWindow();
- }
-
- nr_events = convert_unit(nr_events, &unit);
- snprintf(str, sizeof(str), "Events: %lu%c ",
- nr_events, unit);
- newtDrawRootText(0, 0, str);
-
- newtGetScreenSize(NULL, &rows);
-
- if (symbol_conf.use_callchain)
- self->tree = newtCheckboxTreeMulti(0, 0, rows - 5, seq,
- NEWT_FLAG_SCROLL);
- else
- self->tree = newtListbox(0, 0, rows - 5,
- (NEWT_FLAG_SCROLL |
- NEWT_FLAG_RETURNEXIT));
-
- newtComponentAddCallback(self->tree, hist_browser__selection,
- &self->selection);
-
- progress = ui_progress__new("Adding entries to the browser...",
- hists->nr_entries);
- if (progress == NULL)
- return -1;
-
- idx = 0;
- for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) {
- struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
- int len;
-
- if (h->filtered)
- continue;
-
- len = hist_entry__append_browser(h, self->tree, hists->stats.total_period);
- if (len > max_len)
- max_len = len;
- if (symbol_conf.use_callchain)
- hist_entry__append_callchain_browser(h, self->tree,
- hists->stats.total_period, idx++);
- ++curr_hist;
- if (curr_hist % 5)
- ui_progress__update(progress, curr_hist);
- }
-
- ui_progress__delete(progress);
-
- newtGetScreenSize(&cols, &rows);
-
- if (max_len > cols)
- max_len = cols - 3;
-
- if (!symbol_conf.use_callchain)
- newtListboxSetWidth(self->tree, max_len);
-
- newtCenteredWindow(max_len + (symbol_conf.use_callchain ? 5 : 0),
- rows - 5, title);
- self->form = newt_form__new();
- if (self->form == NULL)
- return -1;
-
- newtFormAddHotKey(self->form, 'A');
- newtFormAddHotKey(self->form, 'a');
- newtFormAddHotKey(self->form, 'D');
- newtFormAddHotKey(self->form, 'd');
- newtFormAddHotKey(self->form, 'T');
- newtFormAddHotKey(self->form, 't');
- newtFormAddHotKey(self->form, '?');
- newtFormAddHotKey(self->form, 'H');
- newtFormAddHotKey(self->form, 'h');
- newtFormAddHotKey(self->form, NEWT_KEY_F1);
- newtFormAddHotKey(self->form, NEWT_KEY_RIGHT);
- newtFormAddHotKey(self->form, NEWT_KEY_TAB);
- newtFormAddHotKey(self->form, NEWT_KEY_UNTAB);
- newtFormAddComponents(self->form, self->tree, NULL);
- self->selection = newt__symbol_tree_get_current(self->tree);
-
- return 0;
-}
-
static struct hist_entry *hist_browser__selected_entry(struct hist_browser *self)
{
- int *indexes;
-
- if (!symbol_conf.use_callchain)
- goto out;
-
- indexes = newtCheckboxTreeFindItem(self->tree, (void *)self->selection);
- if (indexes) {
- bool is_hist_entry = indexes[1] == NEWT_ARG_LAST;
- free(indexes);
- if (is_hist_entry)
- goto out;
- }
- return NULL;
-out:
- return container_of(self->selection, struct hist_entry, ms);
+ return self->he_selection;
}
static struct thread *hist_browser__selected_thread(struct hist_browser *self)
{
- struct hist_entry *he = hist_browser__selected_entry(self);
- return he ? he->thread : NULL;
+ return self->he_selection->thread;
}
static int hist_browser__title(char *bf, size_t size, const char *ev_name,
@@ -905,7 +655,7 @@ static int hist_browser__title(char *bf, size_t size, const char *ev_name,
int hists__browse(struct hists *self, const char *helpline, const char *ev_name)
{
- struct hist_browser *browser = hist_browser__new();
+ struct hist_browser *browser = hist_browser__new(self);
struct pstack *fstack;
const struct thread *thread_filter = NULL;
const struct dso *dso_filter = NULL;
@@ -924,8 +674,6 @@ int hists__browse(struct hists *self, const char *helpline, const char *ev_name)
hist_browser__title(msg, sizeof(msg), ev_name,
dso_filter, thread_filter);
- if (hist_browser__populate(browser, self, msg) < 0)
- goto out_free_stack;
while (1) {
const struct thread *thread;
@@ -934,7 +682,8 @@ int hists__browse(struct hists *self, const char *helpline, const char *ev_name)
int nr_options = 0, choice = 0, i,
annotate = -2, zoom_dso = -2, zoom_thread = -2;
- newtFormRun(browser->form, &es);
+ if (hist_browser__run(browser, msg, &es))
+ break;
thread = hist_browser__selected_thread(browser);
dso = browser->selection->map ? browser->selection->map->dso : NULL;
@@ -1069,8 +818,7 @@ zoom_out_dso:
hists__filter_by_dso(self, dso_filter);
hist_browser__title(msg, sizeof(msg), ev_name,
dso_filter, thread_filter);
- if (hist_browser__populate(browser, self, msg) < 0)
- goto out;
+ hist_browser__reset(browser);
} else if (choice == zoom_thread) {
zoom_thread:
if (thread_filter) {
@@ -1088,8 +836,7 @@ zoom_out_thread:
hists__filter_by_thread(self, thread_filter);
hist_browser__title(msg, sizeof(msg), ev_name,
dso_filter, thread_filter);
- if (hist_browser__populate(browser, self, msg) < 0)
- goto out;
+ hist_browser__reset(browser);
}
}
out_free_stack:
@@ -1145,6 +892,13 @@ static struct newtPercentTreeColors {
"blue", "lightgray",
};
+static void newt_suspend(void *d __used)
+{
+ newtSuspend();
+ raise(SIGTSTP);
+ newtResume();
+}
+
void setup_browser(void)
{
struct newtPercentTreeColors *c = &defaultPercentTreeColors;
@@ -1158,6 +912,7 @@ void setup_browser(void)
use_browser = 1;
newtInit();
newtCls();
+ newtSetSuspendCallback(newt_suspend, NULL);
ui_helpline__puts(" ");
sltt_set_color(HE_COLORSET_TOP, NULL, c->topColorFg, c->topColorBg);
sltt_set_color(HE_COLORSET_MEDIUM, NULL, c->mediumColorFg, c->mediumColorBg);
@@ -1176,3 +931,638 @@ void exit_browser(bool wait_for_ok)
newtFinished();
}
}
+
+static void hist_browser__refresh_dimensions(struct hist_browser *self)
+{
+ /* 3 == +/- toggle symbol before actual hist_entry rendering */
+ self->b.width = 3 + (hists__sort_list_width(self->hists) +
+ sizeof("[k]"));
+}
+
+static void hist_browser__reset(struct hist_browser *self)
+{
+ self->b.nr_entries = self->hists->nr_entries;
+ hist_browser__refresh_dimensions(self);
+ ui_browser__reset_index(&self->b);
+}
+
+static char tree__folded_sign(bool unfolded)
+{
+ return unfolded ? '-' : '+';
+}
+
+static char map_symbol__folded(const struct map_symbol *self)
+{
+ return self->has_children ? tree__folded_sign(self->unfolded) : ' ';
+}
+
+static char hist_entry__folded(const struct hist_entry *self)
+{
+ return map_symbol__folded(&self->ms);
+}
+
+static char callchain_list__folded(const struct callchain_list *self)
+{
+ return map_symbol__folded(&self->ms);
+}
+
+static bool map_symbol__toggle_fold(struct map_symbol *self)
+{
+ if (!self->has_children)
+ return false;
+
+ self->unfolded = !self->unfolded;
+ return true;
+}
+
+#define LEVEL_OFFSET_STEP 3
+
+static int hist_browser__show_callchain_node_rb_tree(struct hist_browser *self,
+ struct callchain_node *chain_node,
+ u64 total, int level,
+ unsigned short row,
+ off_t *row_offset,
+ bool *is_current_entry)
+{
+ struct rb_node *node;
+ int first_row = row, width, offset = level * LEVEL_OFFSET_STEP;
+ u64 new_total, remaining;
+
+ if (callchain_param.mode == CHAIN_GRAPH_REL)
+ new_total = chain_node->children_hit;
+ else
+ new_total = total;
+
+ remaining = new_total;
+ node = rb_first(&chain_node->rb_root);
+ while (node) {
+ struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
+ struct rb_node *next = rb_next(node);
+ u64 cumul = cumul_hits(child);
+ struct callchain_list *chain;
+ char folded_sign = ' ';
+ int first = true;
+ int extra_offset = 0;
+
+ remaining -= cumul;
+
+ list_for_each_entry(chain, &child->val, list) {
+ char ipstr[BITS_PER_LONG / 4 + 1], *alloc_str;
+ const char *str;
+ int color;
+ bool was_first = first;
+
+ if (first) {
+ first = false;
+ chain->ms.has_children = chain->list.next != &child->val ||
+ rb_first(&child->rb_root) != NULL;
+ } else {
+ extra_offset = LEVEL_OFFSET_STEP;
+ chain->ms.has_children = chain->list.next == &child->val &&
+ rb_first(&child->rb_root) != NULL;
+ }
+
+ folded_sign = callchain_list__folded(chain);
+ if (*row_offset != 0) {
+ --*row_offset;
+ goto do_next;
+ }
+
+ alloc_str = NULL;
+ str = callchain_list__sym_name(chain, ipstr, sizeof(ipstr));
+ if (was_first) {
+ double percent = cumul * 100.0 / new_total;
+
+ if (asprintf(&alloc_str, "%2.2f%% %s", percent, str) < 0)
+ str = "Not enough memory!";
+ else
+ str = alloc_str;
+ }
+
+ color = HE_COLORSET_NORMAL;
+ width = self->b.width - (offset + extra_offset + 2);
+ if (ui_browser__is_current_entry(&self->b, row)) {
+ self->selection = &chain->ms;
+ color = HE_COLORSET_SELECTED;
+ *is_current_entry = true;
+ }
+
+ SLsmg_set_color(color);
+ SLsmg_gotorc(self->b.top + row, self->b.left);
+ slsmg_write_nstring(" ", offset + extra_offset);
+ slsmg_printf("%c ", folded_sign);
+ slsmg_write_nstring(str, width);
+ free(alloc_str);
+
+ if (++row == self->b.height)
+ goto out;
+do_next:
+ if (folded_sign == '+')
+ break;
+ }
+
+ if (folded_sign == '-') {
+ const int new_level = level + (extra_offset ? 2 : 1);
+ row += hist_browser__show_callchain_node_rb_tree(self, child, new_total,
+ new_level, row, row_offset,
+ is_current_entry);
+ }
+ if (row == self->b.height)
+ goto out;
+ node = next;
+ }
+out:
+ return row - first_row;
+}
+
+static int hist_browser__show_callchain_node(struct hist_browser *self,
+ struct callchain_node *node,
+ int level, unsigned short row,
+ off_t *row_offset,
+ bool *is_current_entry)
+{
+ struct callchain_list *chain;
+ int first_row = row,
+ offset = level * LEVEL_OFFSET_STEP,
+ width = self->b.width - offset;
+ char folded_sign = ' ';
+
+ list_for_each_entry(chain, &node->val, list) {
+ char ipstr[BITS_PER_LONG / 4 + 1], *s;
+ int color;
+ /*
+ * FIXME: This should be moved to somewhere else,
+ * probably when the callchain is created, so as not to
+ * traverse it all over again
+ */
+ chain->ms.has_children = rb_first(&node->rb_root) != NULL;
+ folded_sign = callchain_list__folded(chain);
+
+ if (*row_offset != 0) {
+ --*row_offset;
+ continue;
+ }
+
+ color = HE_COLORSET_NORMAL;
+ if (ui_browser__is_current_entry(&self->b, row)) {
+ self->selection = &chain->ms;
+ color = HE_COLORSET_SELECTED;
+ *is_current_entry = true;
+ }
+
+ s = callchain_list__sym_name(chain, ipstr, sizeof(ipstr));
+ SLsmg_gotorc(self->b.top + row, self->b.left);
+ SLsmg_set_color(color);
+ slsmg_write_nstring(" ", offset);
+ slsmg_printf("%c ", folded_sign);
+ slsmg_write_nstring(s, width - 2);
+
+ if (++row == self->b.height)
+ goto out;
+ }
+
+ if (folded_sign == '-')
+ row += hist_browser__show_callchain_node_rb_tree(self, node,
+ self->hists->stats.total_period,
+ level + 1, row,
+ row_offset,
+ is_current_entry);
+out:
+ return row - first_row;
+}
+
+static int hist_browser__show_callchain(struct hist_browser *self,
+ struct rb_root *chain,
+ int level, unsigned short row,
+ off_t *row_offset,
+ bool *is_current_entry)
+{
+ struct rb_node *nd;
+ int first_row = row;
+
+ for (nd = rb_first(chain); nd; nd = rb_next(nd)) {
+ struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
+
+ row += hist_browser__show_callchain_node(self, node, level,
+ row, row_offset,
+ is_current_entry);
+ if (row == self->b.height)
+ break;
+ }
+
+ return row - first_row;
+}
+
+static int hist_browser__show_entry(struct hist_browser *self,
+ struct hist_entry *entry,
+ unsigned short row)
+{
+ char s[256];
+ double percent;
+ int printed = 0;
+ int color, width = self->b.width;
+ char folded_sign = ' ';
+ bool current_entry = ui_browser__is_current_entry(&self->b, row);
+ off_t row_offset = entry->row_offset;
+
+ if (current_entry) {
+ self->he_selection = entry;
+ self->selection = &entry->ms;
+ }
+
+ if (symbol_conf.use_callchain) {
+ entry->ms.has_children = !RB_EMPTY_ROOT(&entry->sorted_chain);
+ folded_sign = hist_entry__folded(entry);
+ }
+
+ if (row_offset == 0) {
+ hist_entry__snprintf(entry, s, sizeof(s), self->hists, NULL, false,
+ 0, false, self->hists->stats.total_period);
+ percent = (entry->period * 100.0) / self->hists->stats.total_period;
+
+ color = HE_COLORSET_SELECTED;
+ if (!current_entry) {
+ if (percent >= MIN_RED)
+ color = HE_COLORSET_TOP;
+ else if (percent >= MIN_GREEN)
+ color = HE_COLORSET_MEDIUM;
+ else
+ color = HE_COLORSET_NORMAL;
+ }
+
+ SLsmg_set_color(color);
+ SLsmg_gotorc(self->b.top + row, self->b.left);
+ if (symbol_conf.use_callchain) {
+ slsmg_printf("%c ", folded_sign);
+ width -= 2;
+ }
+ slsmg_write_nstring(s, width);
+ ++row;
+ ++printed;
+ } else
+ --row_offset;
+
+ if (folded_sign == '-' && row != self->b.height) {
+ printed += hist_browser__show_callchain(self, &entry->sorted_chain,
+ 1, row, &row_offset,
+ &current_entry);
+ if (current_entry)
+ self->he_selection = entry;
+ }
+
+ return printed;
+}
+
+static unsigned int hist_browser__refresh_entries(struct ui_browser *self)
+{
+ unsigned row = 0;
+ struct rb_node *nd;
+ struct hist_browser *hb = container_of(self, struct hist_browser, b);
+
+ if (self->first_visible_entry == NULL)
+ self->first_visible_entry = rb_first(&hb->hists->entries);
+
+ for (nd = self->first_visible_entry; nd; nd = rb_next(nd)) {
+ struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
+
+ if (h->filtered)
+ continue;
+
+ row += hist_browser__show_entry(hb, h, row);
+ if (row == self->height)
+ break;
+ }
+
+ return row;
+}
+
+static void callchain_node__init_have_children_rb_tree(struct callchain_node *self)
+{
+ struct rb_node *nd = rb_first(&self->rb_root);
+
+ for (nd = rb_first(&self->rb_root); nd; nd = rb_next(nd)) {
+ struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node);
+ struct callchain_list *chain;
+ int first = true;
+
+ list_for_each_entry(chain, &child->val, list) {
+ if (first) {
+ first = false;
+ chain->ms.has_children = chain->list.next != &child->val ||
+ rb_first(&child->rb_root) != NULL;
+ } else
+ chain->ms.has_children = chain->list.next == &child->val &&
+ rb_first(&child->rb_root) != NULL;
+ }
+
+ callchain_node__init_have_children_rb_tree(child);
+ }
+}
+
+static void callchain_node__init_have_children(struct callchain_node *self)
+{
+ struct callchain_list *chain;
+
+ list_for_each_entry(chain, &self->val, list)
+ chain->ms.has_children = rb_first(&self->rb_root) != NULL;
+
+ callchain_node__init_have_children_rb_tree(self);
+}
+
+static void callchain__init_have_children(struct rb_root *self)
+{
+ struct rb_node *nd;
+
+ for (nd = rb_first(self); nd; nd = rb_next(nd)) {
+ struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
+ callchain_node__init_have_children(node);
+ }
+}
+
+static void hist_entry__init_have_children(struct hist_entry *self)
+{
+ if (!self->init_have_children) {
+ callchain__init_have_children(&self->sorted_chain);
+ self->init_have_children = true;
+ }
+}
+
+static struct rb_node *hists__filter_entries(struct rb_node *nd)
+{
+ while (nd != NULL) {
+ struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
+ if (!h->filtered)
+ return nd;
+
+ nd = rb_next(nd);
+ }
+
+ return NULL;
+}
+
+static struct rb_node *hists__filter_prev_entries(struct rb_node *nd)
+{
+ while (nd != NULL) {
+ struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
+ if (!h->filtered)
+ return nd;
+
+ nd = rb_prev(nd);
+ }
+
+ return NULL;
+}
+
+static void ui_browser__hists_seek(struct ui_browser *self,
+ off_t offset, int whence)
+{
+ struct hist_entry *h;
+ struct rb_node *nd;
+ bool first = true;
+
+ switch (whence) {
+ case SEEK_SET:
+ nd = hists__filter_entries(rb_first(self->entries));
+ break;
+ case SEEK_CUR:
+ nd = self->first_visible_entry;
+ goto do_offset;
+ case SEEK_END:
+ nd = hists__filter_prev_entries(rb_last(self->entries));
+ first = false;
+ break;
+ default:
+ return;
+ }
+
+ /*
+ * Moves not relative to the first visible entry invalidates its
+ * row_offset:
+ */
+ h = rb_entry(self->first_visible_entry, struct hist_entry, rb_node);
+ h->row_offset = 0;
+
+ /*
+ * Here we have to check if nd is expanded (+), if it is we can't go
+ * the next top level hist_entry, instead we must compute an offset of
+ * what _not_ to show and not change the first visible entry.
+ *
+ * This offset increments when we are going from top to bottom and
+ * decreases when we're going from bottom to top.
+ *
+ * As we don't have backpointers to the top level in the callchains
+ * structure, we need to always print the whole hist_entry callchain,
+ * skipping the first ones that are before the first visible entry
+ * and stop when we printed enough lines to fill the screen.
+ */
+do_offset:
+ if (offset > 0) {
+ do {
+ h = rb_entry(nd, struct hist_entry, rb_node);
+ if (h->ms.unfolded) {
+ u16 remaining = h->nr_rows - h->row_offset;
+ if (offset > remaining) {
+ offset -= remaining;
+ h->row_offset = 0;
+ } else {
+ h->row_offset += offset;
+ offset = 0;
+ self->first_visible_entry = nd;
+ break;
+ }
+ }
+ nd = hists__filter_entries(rb_next(nd));
+ if (nd == NULL)
+ break;
+ --offset;
+ self->first_visible_entry = nd;
+ } while (offset != 0);
+ } else if (offset < 0) {
+ while (1) {
+ h = rb_entry(nd, struct hist_entry, rb_node);
+ if (h->ms.unfolded) {
+ if (first) {
+ if (-offset > h->row_offset) {
+ offset += h->row_offset;
+ h->row_offset = 0;
+ } else {
+ h->row_offset += offset;
+ offset = 0;
+ self->first_visible_entry = nd;
+ break;
+ }
+ } else {
+ if (-offset > h->nr_rows) {
+ offset += h->nr_rows;
+ h->row_offset = 0;
+ } else {
+ h->row_offset = h->nr_rows + offset;
+ offset = 0;
+ self->first_visible_entry = nd;
+ break;
+ }
+ }
+ }
+
+ nd = hists__filter_prev_entries(rb_prev(nd));
+ if (nd == NULL)
+ break;
+ ++offset;
+ self->first_visible_entry = nd;
+ if (offset == 0) {
+ /*
+ * Last unfiltered hist_entry, check if it is
+ * unfolded, if it is then we should have
+ * row_offset at its last entry.
+ */
+ h = rb_entry(nd, struct hist_entry, rb_node);
+ if (h->ms.unfolded)
+ h->row_offset = h->nr_rows;
+ break;
+ }
+ first = false;
+ }
+ } else {
+ self->first_visible_entry = nd;
+ h = rb_entry(nd, struct hist_entry, rb_node);
+ h->row_offset = 0;
+ }
+}
+
+static int callchain_node__count_rows_rb_tree(struct callchain_node *self)
+{
+ int n = 0;
+ struct rb_node *nd;
+
+ for (nd = rb_first(&self->rb_root); nd; nd = rb_next(nd)) {
+ struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node);
+ struct callchain_list *chain;
+ char folded_sign = ' '; /* No children */
+
+ list_for_each_entry(chain, &child->val, list) {
+ ++n;
+ /* We need this because we may not have children */
+ folded_sign = callchain_list__folded(chain);
+ if (folded_sign == '+')
+ break;
+ }
+
+ if (folded_sign == '-') /* Have children and they're unfolded */
+ n += callchain_node__count_rows_rb_tree(child);
+ }
+
+ return n;
+}
+
+static int callchain_node__count_rows(struct callchain_node *node)
+{
+ struct callchain_list *chain;
+ bool unfolded = false;
+ int n = 0;
+
+ list_for_each_entry(chain, &node->val, list) {
+ ++n;
+ unfolded = chain->ms.unfolded;
+ }
+
+ if (unfolded)
+ n += callchain_node__count_rows_rb_tree(node);
+
+ return n;
+}
+
+static int callchain__count_rows(struct rb_root *chain)
+{
+ struct rb_node *nd;
+ int n = 0;
+
+ for (nd = rb_first(chain); nd; nd = rb_next(nd)) {
+ struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
+ n += callchain_node__count_rows(node);
+ }
+
+ return n;
+}
+
+static bool hist_browser__toggle_fold(struct hist_browser *self)
+{
+ if (map_symbol__toggle_fold(self->selection)) {
+ struct hist_entry *he = self->he_selection;
+
+ hist_entry__init_have_children(he);
+ self->hists->nr_entries -= he->nr_rows;
+
+ if (he->ms.unfolded)
+ he->nr_rows = callchain__count_rows(&he->sorted_chain);
+ else
+ he->nr_rows = 0;
+ self->hists->nr_entries += he->nr_rows;
+ self->b.nr_entries = self->hists->nr_entries;
+
+ return true;
+ }
+
+ /* If it doesn't have children, no toggling performed */
+ return false;
+}
+
+static int hist_browser__run(struct hist_browser *self, const char *title,
+ struct newtExitStruct *es)
+{
+ char str[256], unit;
+ unsigned long nr_events = self->hists->stats.nr_events[PERF_RECORD_SAMPLE];
+
+ self->b.entries = &self->hists->entries;
+ self->b.nr_entries = self->hists->nr_entries;
+
+ hist_browser__refresh_dimensions(self);
+
+ nr_events = convert_unit(nr_events, &unit);
+ snprintf(str, sizeof(str), "Events: %lu%c ",
+ nr_events, unit);
+ newtDrawRootText(0, 0, str);
+
+ if (ui_browser__show(&self->b, title) < 0)
+ return -1;
+
+ newtFormAddHotKey(self->b.form, 'A');
+ newtFormAddHotKey(self->b.form, 'a');
+ newtFormAddHotKey(self->b.form, '?');
+ newtFormAddHotKey(self->b.form, 'h');
+ newtFormAddHotKey(self->b.form, 'H');
+ newtFormAddHotKey(self->b.form, 'd');
+
+ newtFormAddHotKey(self->b.form, NEWT_KEY_LEFT);
+ newtFormAddHotKey(self->b.form, NEWT_KEY_RIGHT);
+ newtFormAddHotKey(self->b.form, NEWT_KEY_ENTER);
+
+ while (1) {
+ ui_browser__run(&self->b, es);
+
+ if (es->reason != NEWT_EXIT_HOTKEY)
+ break;
+ switch (es->u.key) {
+ case 'd': { /* Debug */
+ static int seq;
+ struct hist_entry *h = rb_entry(self->b.first_visible_entry,
+ struct hist_entry, rb_node);
+ ui_helpline__pop();
+ ui_helpline__fpush("%d: nr_ent=(%d,%d), height=%d, idx=%d, fve: idx=%d, row_off=%d, nrows=%d",
+ seq++, self->b.nr_entries,
+ self->hists->nr_entries,
+ self->b.height,
+ self->b.index,
+ self->b.first_visible_entry_idx,
+ h->row_offset, h->nr_rows);
+ }
+ continue;
+ case NEWT_KEY_ENTER:
+ if (hist_browser__toggle_fold(self))
+ break;
+ /* fall thru */
+ default:
+ return 0;
+ }
+ }
+ return 0;
+}
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index 9bf0f402ca7..4af5bd59cfd 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -602,8 +602,15 @@ parse_breakpoint_event(const char **strp, struct perf_event_attr *attr)
return EVT_FAILED;
}
- /* We should find a nice way to override the access type */
- attr->bp_len = HW_BREAKPOINT_LEN_4;
+ /*
+ * We should find a nice way to override the access length
+ * Provide some defaults for now
+ */
+ if (attr->bp_type == HW_BREAKPOINT_X)
+ attr->bp_len = sizeof(long);
+ else
+ attr->bp_len = HW_BREAKPOINT_LEN_4;
+
attr->type = PERF_TYPE_BREAKPOINT;
return EVT_HANDLED;
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index 914c67095d9..2e665cb8405 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -1,5 +1,5 @@
/*
- * probe-event.c : perf-probe definition to kprobe_events format converter
+ * probe-event.c : perf-probe definition to probe_events format converter
*
* Written by Masami Hiramatsu <mhiramat@redhat.com>
*
@@ -120,8 +120,11 @@ static int open_vmlinux(void)
return open(machine.vmlinux_maps[MAP__FUNCTION]->dso->long_name, O_RDONLY);
}
-/* Convert trace point to probe point with debuginfo */
-static int convert_to_perf_probe_point(struct kprobe_trace_point *tp,
+/*
+ * Convert trace point to probe point with debuginfo
+ * Currently only handles kprobes.
+ */
+static int kprobe_convert_to_perf_probe(struct probe_trace_point *tp,
struct perf_probe_point *pp)
{
struct symbol *sym;
@@ -151,8 +154,8 @@ static int convert_to_perf_probe_point(struct kprobe_trace_point *tp,
}
/* Try to find perf_probe_event with debuginfo */
-static int try_to_find_kprobe_trace_events(struct perf_probe_event *pev,
- struct kprobe_trace_event **tevs,
+static int try_to_find_probe_trace_events(struct perf_probe_event *pev,
+ struct probe_trace_event **tevs,
int max_tevs)
{
bool need_dwarf = perf_probe_event_need_dwarf(pev);
@@ -169,11 +172,11 @@ static int try_to_find_kprobe_trace_events(struct perf_probe_event *pev,
}
/* Searching trace events corresponding to probe event */
- ntevs = find_kprobe_trace_events(fd, pev, tevs, max_tevs);
+ ntevs = find_probe_trace_events(fd, pev, tevs, max_tevs);
close(fd);
if (ntevs > 0) { /* Succeeded to find trace events */
- pr_debug("find %d kprobe_trace_events.\n", ntevs);
+ pr_debug("find %d probe_trace_events.\n", ntevs);
return ntevs;
}
@@ -195,6 +198,65 @@ static int try_to_find_kprobe_trace_events(struct perf_probe_event *pev,
return ntevs;
}
+/*
+ * Find a src file from a DWARF tag path. Prepend optional source path prefix
+ * and chop off leading directories that do not exist. Result is passed back as
+ * a newly allocated path on success.
+ * Return 0 if file was found and readable, -errno otherwise.
+ */
+static int get_real_path(const char *raw_path, const char *comp_dir,
+ char **new_path)
+{
+ const char *prefix = symbol_conf.source_prefix;
+
+ if (!prefix) {
+ if (raw_path[0] != '/' && comp_dir)
+ /* If not an absolute path, try to use comp_dir */
+ prefix = comp_dir;
+ else {
+ if (access(raw_path, R_OK) == 0) {
+ *new_path = strdup(raw_path);
+ return 0;
+ } else
+ return -errno;
+ }
+ }
+
+ *new_path = malloc((strlen(prefix) + strlen(raw_path) + 2));
+ if (!*new_path)
+ return -ENOMEM;
+
+ for (;;) {
+ sprintf(*new_path, "%s/%s", prefix, raw_path);
+
+ if (access(*new_path, R_OK) == 0)
+ return 0;
+
+ if (!symbol_conf.source_prefix)
+ /* In case of searching comp_dir, don't retry */
+ return -errno;
+
+ switch (errno) {
+ case ENAMETOOLONG:
+ case ENOENT:
+ case EROFS:
+ case EFAULT:
+ raw_path = strchr(++raw_path, '/');
+ if (!raw_path) {
+ free(*new_path);
+ *new_path = NULL;
+ return -ENOENT;
+ }
+ continue;
+
+ default:
+ free(*new_path);
+ *new_path = NULL;
+ return -errno;
+ }
+ }
+}
+
#define LINEBUF_SIZE 256
#define NR_ADDITIONAL_LINES 2
@@ -244,6 +306,7 @@ int show_line_range(struct line_range *lr)
struct line_node *ln;
FILE *fp;
int fd, ret;
+ char *tmp;
/* Search a line range */
ret = init_vmlinux();
@@ -266,6 +329,15 @@ int show_line_range(struct line_range *lr)
return ret;
}
+ /* Convert source file path */
+ tmp = lr->path;
+ ret = get_real_path(tmp, lr->comp_dir, &lr->path);
+ free(tmp); /* Free old path */
+ if (ret < 0) {
+ pr_warning("Failed to find source file. (%d)\n", ret);
+ return ret;
+ }
+
setup_pager();
if (lr->function)
@@ -308,8 +380,8 @@ end:
#else /* !DWARF_SUPPORT */
-static int convert_to_perf_probe_point(struct kprobe_trace_point *tp,
- struct perf_probe_point *pp)
+static int kprobe_convert_to_perf_probe(struct probe_trace_point *tp,
+ struct perf_probe_point *pp)
{
pp->function = strdup(tp->symbol);
if (pp->function == NULL)
@@ -320,8 +392,8 @@ static int convert_to_perf_probe_point(struct kprobe_trace_point *tp,
return 0;
}
-static int try_to_find_kprobe_trace_events(struct perf_probe_event *pev,
- struct kprobe_trace_event **tevs __unused,
+static int try_to_find_probe_trace_events(struct perf_probe_event *pev,
+ struct probe_trace_event **tevs __unused,
int max_tevs __unused)
{
if (perf_probe_event_need_dwarf(pev)) {
@@ -557,7 +629,7 @@ static int parse_perf_probe_point(char *arg, struct perf_probe_event *pev)
/* Parse perf-probe event argument */
static int parse_perf_probe_arg(char *str, struct perf_probe_arg *arg)
{
- char *tmp;
+ char *tmp, *goodname;
struct perf_probe_arg_field **fieldp;
pr_debug("parsing arg: %s into ", str);
@@ -580,7 +652,7 @@ static int parse_perf_probe_arg(char *str, struct perf_probe_arg *arg)
pr_debug("type:%s ", arg->type);
}
- tmp = strpbrk(str, "-.");
+ tmp = strpbrk(str, "-.[");
if (!is_c_varname(str) || !tmp) {
/* A variable, register, symbol or special value */
arg->var = strdup(str);
@@ -590,10 +662,11 @@ static int parse_perf_probe_arg(char *str, struct perf_probe_arg *arg)
return 0;
}
- /* Structure fields */
+ /* Structure fields or array element */
arg->var = strndup(str, tmp - str);
if (arg->var == NULL)
return -ENOMEM;
+ goodname = arg->var;
pr_debug("%s, ", arg->var);
fieldp = &arg->field;
@@ -601,22 +674,38 @@ static int parse_perf_probe_arg(char *str, struct perf_probe_arg *arg)
*fieldp = zalloc(sizeof(struct perf_probe_arg_field));
if (*fieldp == NULL)
return -ENOMEM;
- if (*tmp == '.') {
- str = tmp + 1;
- (*fieldp)->ref = false;
- } else if (tmp[1] == '>') {
- str = tmp + 2;
+ if (*tmp == '[') { /* Array */
+ str = tmp;
+ (*fieldp)->index = strtol(str + 1, &tmp, 0);
(*fieldp)->ref = true;
- } else {
- semantic_error("Argument parse error: %s\n", str);
- return -EINVAL;
+ if (*tmp != ']' || tmp == str + 1) {
+ semantic_error("Array index must be a"
+ " number.\n");
+ return -EINVAL;
+ }
+ tmp++;
+ if (*tmp == '\0')
+ tmp = NULL;
+ } else { /* Structure */
+ if (*tmp == '.') {
+ str = tmp + 1;
+ (*fieldp)->ref = false;
+ } else if (tmp[1] == '>') {
+ str = tmp + 2;
+ (*fieldp)->ref = true;
+ } else {
+ semantic_error("Argument parse error: %s\n",
+ str);
+ return -EINVAL;
+ }
+ tmp = strpbrk(str, "-.[");
}
-
- tmp = strpbrk(str, "-.");
if (tmp) {
(*fieldp)->name = strndup(str, tmp - str);
if ((*fieldp)->name == NULL)
return -ENOMEM;
+ if (*str != '[')
+ goodname = (*fieldp)->name;
pr_debug("%s(%d), ", (*fieldp)->name, (*fieldp)->ref);
fieldp = &(*fieldp)->next;
}
@@ -624,11 +713,13 @@ static int parse_perf_probe_arg(char *str, struct perf_probe_arg *arg)
(*fieldp)->name = strdup(str);
if ((*fieldp)->name == NULL)
return -ENOMEM;
+ if (*str != '[')
+ goodname = (*fieldp)->name;
pr_debug("%s(%d)\n", (*fieldp)->name, (*fieldp)->ref);
- /* If no name is specified, set the last field name */
+ /* If no name is specified, set the last field name (not array index)*/
if (!arg->name) {
- arg->name = strdup((*fieldp)->name);
+ arg->name = strdup(goodname);
if (arg->name == NULL)
return -ENOMEM;
}
@@ -693,16 +784,17 @@ bool perf_probe_event_need_dwarf(struct perf_probe_event *pev)
return false;
}
-/* Parse kprobe_events event into struct probe_point */
-int parse_kprobe_trace_command(const char *cmd, struct kprobe_trace_event *tev)
+/* Parse probe_events event into struct probe_point */
+static int parse_probe_trace_command(const char *cmd,
+ struct probe_trace_event *tev)
{
- struct kprobe_trace_point *tp = &tev->point;
+ struct probe_trace_point *tp = &tev->point;
char pr;
char *p;
int ret, i, argc;
char **argv;
- pr_debug("Parsing kprobe_events: %s\n", cmd);
+ pr_debug("Parsing probe_events: %s\n", cmd);
argv = argv_split(cmd, &argc);
if (!argv) {
pr_debug("Failed to split arguments.\n");
@@ -734,7 +826,7 @@ int parse_kprobe_trace_command(const char *cmd, struct kprobe_trace_event *tev)
tp->offset = 0;
tev->nargs = argc - 2;
- tev->args = zalloc(sizeof(struct kprobe_trace_arg) * tev->nargs);
+ tev->args = zalloc(sizeof(struct probe_trace_arg) * tev->nargs);
if (tev->args == NULL) {
ret = -ENOMEM;
goto out;
@@ -776,8 +868,11 @@ int synthesize_perf_probe_arg(struct perf_probe_arg *pa, char *buf, size_t len)
len -= ret;
while (field) {
- ret = e_snprintf(tmp, len, "%s%s", field->ref ? "->" : ".",
- field->name);
+ if (field->name[0] == '[')
+ ret = e_snprintf(tmp, len, "%s", field->name);
+ else
+ ret = e_snprintf(tmp, len, "%s%s",
+ field->ref ? "->" : ".", field->name);
if (ret <= 0)
goto error;
tmp += ret;
@@ -877,13 +972,13 @@ char *synthesize_perf_probe_command(struct perf_probe_event *pev)
}
#endif
-static int __synthesize_kprobe_trace_arg_ref(struct kprobe_trace_arg_ref *ref,
+static int __synthesize_probe_trace_arg_ref(struct probe_trace_arg_ref *ref,
char **buf, size_t *buflen,
int depth)
{
int ret;
if (ref->next) {
- depth = __synthesize_kprobe_trace_arg_ref(ref->next, buf,
+ depth = __synthesize_probe_trace_arg_ref(ref->next, buf,
buflen, depth + 1);
if (depth < 0)
goto out;
@@ -901,9 +996,10 @@ out:
}
-static int synthesize_kprobe_trace_arg(struct kprobe_trace_arg *arg,
+static int synthesize_probe_trace_arg(struct probe_trace_arg *arg,
char *buf, size_t buflen)
{
+ struct probe_trace_arg_ref *ref = arg->ref;
int ret, depth = 0;
char *tmp = buf;
@@ -917,16 +1013,24 @@ static int synthesize_kprobe_trace_arg(struct kprobe_trace_arg *arg,
buf += ret;
buflen -= ret;
+ /* Special case: @XXX */
+ if (arg->value[0] == '@' && arg->ref)
+ ref = ref->next;
+
/* Dereferencing arguments */
- if (arg->ref) {
- depth = __synthesize_kprobe_trace_arg_ref(arg->ref, &buf,
+ if (ref) {
+ depth = __synthesize_probe_trace_arg_ref(ref, &buf,
&buflen, 1);
if (depth < 0)
return depth;
}
/* Print argument value */
- ret = e_snprintf(buf, buflen, "%s", arg->value);
+ if (arg->value[0] == '@' && arg->ref)
+ ret = e_snprintf(buf, buflen, "%s%+ld", arg->value,
+ arg->ref->offset);
+ else
+ ret = e_snprintf(buf, buflen, "%s", arg->value);
if (ret < 0)
return ret;
buf += ret;
@@ -951,9 +1055,9 @@ static int synthesize_kprobe_trace_arg(struct kprobe_trace_arg *arg,
return buf - tmp;
}
-char *synthesize_kprobe_trace_command(struct kprobe_trace_event *tev)
+char *synthesize_probe_trace_command(struct probe_trace_event *tev)
{
- struct kprobe_trace_point *tp = &tev->point;
+ struct probe_trace_point *tp = &tev->point;
char *buf;
int i, len, ret;
@@ -969,7 +1073,7 @@ char *synthesize_kprobe_trace_command(struct kprobe_trace_event *tev)
goto error;
for (i = 0; i < tev->nargs; i++) {
- ret = synthesize_kprobe_trace_arg(&tev->args[i], buf + len,
+ ret = synthesize_probe_trace_arg(&tev->args[i], buf + len,
MAX_CMDLEN - len);
if (ret <= 0)
goto error;
@@ -982,7 +1086,7 @@ error:
return NULL;
}
-int convert_to_perf_probe_event(struct kprobe_trace_event *tev,
+static int convert_to_perf_probe_event(struct probe_trace_event *tev,
struct perf_probe_event *pev)
{
char buf[64] = "";
@@ -995,7 +1099,7 @@ int convert_to_perf_probe_event(struct kprobe_trace_event *tev,
return -ENOMEM;
/* Convert trace_point to probe_point */
- ret = convert_to_perf_probe_point(&tev->point, &pev->point);
+ ret = kprobe_convert_to_perf_probe(&tev->point, &pev->point);
if (ret < 0)
return ret;
@@ -1008,7 +1112,7 @@ int convert_to_perf_probe_event(struct kprobe_trace_event *tev,
if (tev->args[i].name)
pev->args[i].name = strdup(tev->args[i].name);
else {
- ret = synthesize_kprobe_trace_arg(&tev->args[i],
+ ret = synthesize_probe_trace_arg(&tev->args[i],
buf, 64);
pev->args[i].name = strdup(buf);
}
@@ -1059,9 +1163,9 @@ void clear_perf_probe_event(struct perf_probe_event *pev)
memset(pev, 0, sizeof(*pev));
}
-void clear_kprobe_trace_event(struct kprobe_trace_event *tev)
+static void clear_probe_trace_event(struct probe_trace_event *tev)
{
- struct kprobe_trace_arg_ref *ref, *next;
+ struct probe_trace_arg_ref *ref, *next;
int i;
if (tev->event)
@@ -1122,7 +1226,7 @@ static int open_kprobe_events(bool readwrite)
}
/* Get raw string list of current kprobe_events */
-static struct strlist *get_kprobe_trace_command_rawlist(int fd)
+static struct strlist *get_probe_trace_command_rawlist(int fd)
{
int ret, idx;
FILE *fp;
@@ -1190,7 +1294,7 @@ static int show_perf_probe_event(struct perf_probe_event *pev)
int show_perf_probe_events(void)
{
int fd, ret;
- struct kprobe_trace_event tev;
+ struct probe_trace_event tev;
struct perf_probe_event pev;
struct strlist *rawlist;
struct str_node *ent;
@@ -1207,20 +1311,20 @@ int show_perf_probe_events(void)
if (fd < 0)
return fd;
- rawlist = get_kprobe_trace_command_rawlist(fd);
+ rawlist = get_probe_trace_command_rawlist(fd);
close(fd);
if (!rawlist)
return -ENOENT;
strlist__for_each(ent, rawlist) {
- ret = parse_kprobe_trace_command(ent->s, &tev);
+ ret = parse_probe_trace_command(ent->s, &tev);
if (ret >= 0) {
ret = convert_to_perf_probe_event(&tev, &pev);
if (ret >= 0)
ret = show_perf_probe_event(&pev);
}
clear_perf_probe_event(&pev);
- clear_kprobe_trace_event(&tev);
+ clear_probe_trace_event(&tev);
if (ret < 0)
break;
}
@@ -1230,20 +1334,19 @@ int show_perf_probe_events(void)
}
/* Get current perf-probe event names */
-static struct strlist *get_kprobe_trace_event_names(int fd, bool include_group)
+static struct strlist *get_probe_trace_event_names(int fd, bool include_group)
{
char buf[128];
struct strlist *sl, *rawlist;
struct str_node *ent;
- struct kprobe_trace_event tev;
+ struct probe_trace_event tev;
int ret = 0;
memset(&tev, 0, sizeof(tev));
-
- rawlist = get_kprobe_trace_command_rawlist(fd);
+ rawlist = get_probe_trace_command_rawlist(fd);
sl = strlist__new(true, NULL);
strlist__for_each(ent, rawlist) {
- ret = parse_kprobe_trace_command(ent->s, &tev);
+ ret = parse_probe_trace_command(ent->s, &tev);
if (ret < 0)
break;
if (include_group) {
@@ -1253,7 +1356,7 @@ static struct strlist *get_kprobe_trace_event_names(int fd, bool include_group)
ret = strlist__add(sl, buf);
} else
ret = strlist__add(sl, tev.event);
- clear_kprobe_trace_event(&tev);
+ clear_probe_trace_event(&tev);
if (ret < 0)
break;
}
@@ -1266,13 +1369,13 @@ static struct strlist *get_kprobe_trace_event_names(int fd, bool include_group)
return sl;
}
-static int write_kprobe_trace_event(int fd, struct kprobe_trace_event *tev)
+static int write_probe_trace_event(int fd, struct probe_trace_event *tev)
{
int ret = 0;
- char *buf = synthesize_kprobe_trace_command(tev);
+ char *buf = synthesize_probe_trace_command(tev);
if (!buf) {
- pr_debug("Failed to synthesize kprobe trace event.\n");
+ pr_debug("Failed to synthesize probe trace event.\n");
return -EINVAL;
}
@@ -1325,12 +1428,12 @@ static int get_new_event_name(char *buf, size_t len, const char *base,
return ret;
}
-static int __add_kprobe_trace_events(struct perf_probe_event *pev,
- struct kprobe_trace_event *tevs,
+static int __add_probe_trace_events(struct perf_probe_event *pev,
+ struct probe_trace_event *tevs,
int ntevs, bool allow_suffix)
{
int i, fd, ret;
- struct kprobe_trace_event *tev = NULL;
+ struct probe_trace_event *tev = NULL;
char buf[64];
const char *event, *group;
struct strlist *namelist;
@@ -1339,7 +1442,7 @@ static int __add_kprobe_trace_events(struct perf_probe_event *pev,
if (fd < 0)
return fd;
/* Get current event names */
- namelist = get_kprobe_trace_event_names(fd, false);
+ namelist = get_probe_trace_event_names(fd, false);
if (!namelist) {
pr_debug("Failed to get current event list.\n");
return -EIO;
@@ -1374,7 +1477,7 @@ static int __add_kprobe_trace_events(struct perf_probe_event *pev,
ret = -ENOMEM;
break;
}
- ret = write_kprobe_trace_event(fd, tev);
+ ret = write_probe_trace_event(fd, tev);
if (ret < 0)
break;
/* Add added event name to namelist */
@@ -1411,21 +1514,21 @@ static int __add_kprobe_trace_events(struct perf_probe_event *pev,
return ret;
}
-static int convert_to_kprobe_trace_events(struct perf_probe_event *pev,
- struct kprobe_trace_event **tevs,
+static int convert_to_probe_trace_events(struct perf_probe_event *pev,
+ struct probe_trace_event **tevs,
int max_tevs)
{
struct symbol *sym;
int ret = 0, i;
- struct kprobe_trace_event *tev;
+ struct probe_trace_event *tev;
/* Convert perf_probe_event with debuginfo */
- ret = try_to_find_kprobe_trace_events(pev, tevs, max_tevs);
+ ret = try_to_find_probe_trace_events(pev, tevs, max_tevs);
if (ret != 0)
return ret;
/* Allocate trace event buffer */
- tev = *tevs = zalloc(sizeof(struct kprobe_trace_event));
+ tev = *tevs = zalloc(sizeof(struct probe_trace_event));
if (tev == NULL)
return -ENOMEM;
@@ -1438,7 +1541,7 @@ static int convert_to_kprobe_trace_events(struct perf_probe_event *pev,
tev->point.offset = pev->point.offset;
tev->nargs = pev->nargs;
if (tev->nargs) {
- tev->args = zalloc(sizeof(struct kprobe_trace_arg)
+ tev->args = zalloc(sizeof(struct probe_trace_arg)
* tev->nargs);
if (tev->args == NULL) {
ret = -ENOMEM;
@@ -1479,7 +1582,7 @@ static int convert_to_kprobe_trace_events(struct perf_probe_event *pev,
return 1;
error:
- clear_kprobe_trace_event(tev);
+ clear_probe_trace_event(tev);
free(tev);
*tevs = NULL;
return ret;
@@ -1487,7 +1590,7 @@ error:
struct __event_package {
struct perf_probe_event *pev;
- struct kprobe_trace_event *tevs;
+ struct probe_trace_event *tevs;
int ntevs;
};
@@ -1510,7 +1613,7 @@ int add_perf_probe_events(struct perf_probe_event *pevs, int npevs,
for (i = 0; i < npevs; i++) {
pkgs[i].pev = &pevs[i];
/* Convert with or without debuginfo */
- ret = convert_to_kprobe_trace_events(pkgs[i].pev,
+ ret = convert_to_probe_trace_events(pkgs[i].pev,
&pkgs[i].tevs, max_tevs);
if (ret < 0)
goto end;
@@ -1519,24 +1622,24 @@ int add_perf_probe_events(struct perf_probe_event *pevs, int npevs,
/* Loop 2: add all events */
for (i = 0; i < npevs && ret >= 0; i++)
- ret = __add_kprobe_trace_events(pkgs[i].pev, pkgs[i].tevs,
+ ret = __add_probe_trace_events(pkgs[i].pev, pkgs[i].tevs,
pkgs[i].ntevs, force_add);
end:
/* Loop 3: cleanup trace events */
for (i = 0; i < npevs; i++)
for (j = 0; j < pkgs[i].ntevs; j++)
- clear_kprobe_trace_event(&pkgs[i].tevs[j]);
+ clear_probe_trace_event(&pkgs[i].tevs[j]);
return ret;
}
-static int __del_trace_kprobe_event(int fd, struct str_node *ent)
+static int __del_trace_probe_event(int fd, struct str_node *ent)
{
char *p;
char buf[128];
int ret;
- /* Convert from perf-probe event to trace-kprobe event */
+ /* Convert from perf-probe event to trace-probe event */
ret = e_snprintf(buf, 128, "-:%s", ent->s);
if (ret < 0)
goto error;
@@ -1562,7 +1665,7 @@ error:
return ret;
}
-static int del_trace_kprobe_event(int fd, const char *group,
+static int del_trace_probe_event(int fd, const char *group,
const char *event, struct strlist *namelist)
{
char buf[128];
@@ -1579,7 +1682,7 @@ static int del_trace_kprobe_event(int fd, const char *group,
strlist__for_each_safe(ent, n, namelist)
if (strglobmatch(ent->s, buf)) {
found++;
- ret = __del_trace_kprobe_event(fd, ent);
+ ret = __del_trace_probe_event(fd, ent);
if (ret < 0)
break;
strlist__remove(namelist, ent);
@@ -1588,7 +1691,7 @@ static int del_trace_kprobe_event(int fd, const char *group,
ent = strlist__find(namelist, buf);
if (ent) {
found++;
- ret = __del_trace_kprobe_event(fd, ent);
+ ret = __del_trace_probe_event(fd, ent);
if (ret >= 0)
strlist__remove(namelist, ent);
}
@@ -1612,7 +1715,7 @@ int del_perf_probe_events(struct strlist *dellist)
return fd;
/* Get current event names */
- namelist = get_kprobe_trace_event_names(fd, true);
+ namelist = get_probe_trace_event_names(fd, true);
if (namelist == NULL)
return -EINVAL;
@@ -1633,7 +1736,7 @@ int del_perf_probe_events(struct strlist *dellist)
event = str;
}
pr_debug("Group: %s, Event: %s\n", group, event);
- ret = del_trace_kprobe_event(fd, group, event, namelist);
+ ret = del_trace_probe_event(fd, group, event, namelist);
free(str);
if (ret < 0)
break;
diff --git a/tools/perf/util/probe-event.h b/tools/perf/util/probe-event.h
index e9db1a214ca..5af39243a25 100644
--- a/tools/perf/util/probe-event.h
+++ b/tools/perf/util/probe-event.h
@@ -7,33 +7,33 @@
extern bool probe_event_dry_run;
/* kprobe-tracer tracing point */
-struct kprobe_trace_point {
+struct probe_trace_point {
char *symbol; /* Base symbol */
unsigned long offset; /* Offset from symbol */
bool retprobe; /* Return probe flag */
};
-/* kprobe-tracer tracing argument referencing offset */
-struct kprobe_trace_arg_ref {
- struct kprobe_trace_arg_ref *next; /* Next reference */
+/* probe-tracer tracing argument referencing offset */
+struct probe_trace_arg_ref {
+ struct probe_trace_arg_ref *next; /* Next reference */
long offset; /* Offset value */
};
/* kprobe-tracer tracing argument */
-struct kprobe_trace_arg {
+struct probe_trace_arg {
char *name; /* Argument name */
char *value; /* Base value */
char *type; /* Type name */
- struct kprobe_trace_arg_ref *ref; /* Referencing offset */
+ struct probe_trace_arg_ref *ref; /* Referencing offset */
};
/* kprobe-tracer tracing event (point + arg) */
-struct kprobe_trace_event {
+struct probe_trace_event {
char *event; /* Event name */
char *group; /* Group name */
- struct kprobe_trace_point point; /* Trace point */
+ struct probe_trace_point point; /* Trace point */
int nargs; /* Number of args */
- struct kprobe_trace_arg *args; /* Arguments */
+ struct probe_trace_arg *args; /* Arguments */
};
/* Perf probe probing point */
@@ -50,6 +50,7 @@ struct perf_probe_point {
struct perf_probe_arg_field {
struct perf_probe_arg_field *next; /* Next field */
char *name; /* Name of the field */
+ long index; /* Array index number */
bool ref; /* Referencing flag */
};
@@ -85,31 +86,25 @@ struct line_range {
int end; /* End line number */
int offset; /* Start line offset */
char *path; /* Real path name */
+ char *comp_dir; /* Compile directory */
struct list_head line_list; /* Visible lines */
};
/* Command string to events */
extern int parse_perf_probe_command(const char *cmd,
struct perf_probe_event *pev);
-extern int parse_kprobe_trace_command(const char *cmd,
- struct kprobe_trace_event *tev);
/* Events to command string */
extern char *synthesize_perf_probe_command(struct perf_probe_event *pev);
-extern char *synthesize_kprobe_trace_command(struct kprobe_trace_event *tev);
+extern char *synthesize_probe_trace_command(struct probe_trace_event *tev);
extern int synthesize_perf_probe_arg(struct perf_probe_arg *pa, char *buf,
size_t len);
/* Check the perf_probe_event needs debuginfo */
extern bool perf_probe_event_need_dwarf(struct perf_probe_event *pev);
-/* Convert from kprobe_trace_event to perf_probe_event */
-extern int convert_to_perf_probe_event(struct kprobe_trace_event *tev,
- struct perf_probe_event *pev);
-
/* Release event contents */
extern void clear_perf_probe_event(struct perf_probe_event *pev);
-extern void clear_kprobe_trace_event(struct kprobe_trace_event *tev);
/* Command string to line-range */
extern int parse_line_range_desc(const char *cmd, struct line_range *lr);
diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c
index d964cb199c6..840f1aabbb7 100644
--- a/tools/perf/util/probe-finder.c
+++ b/tools/perf/util/probe-finder.c
@@ -37,6 +37,7 @@
#include "event.h"
#include "debug.h"
#include "util.h"
+#include "symbol.h"
#include "probe-finder.h"
/* Kprobe tracer basic type is up to u64 */
@@ -143,12 +144,21 @@ static const char *cu_find_realpath(Dwarf_Die *cu_die, const char *fname)
return src;
}
+/* Get DW_AT_comp_dir (should be NULL with older gcc) */
+static const char *cu_get_comp_dir(Dwarf_Die *cu_die)
+{
+ Dwarf_Attribute attr;
+ if (dwarf_attr(cu_die, DW_AT_comp_dir, &attr) == NULL)
+ return NULL;
+ return dwarf_formstring(&attr);
+}
+
/* Compare diename and tname */
static bool die_compare_name(Dwarf_Die *dw_die, const char *tname)
{
const char *name;
name = dwarf_diename(dw_die);
- return name ? strcmp(tname, name) : -1;
+ return name ? (strcmp(tname, name) == 0) : false;
}
/* Get type die, but skip qualifiers and typedef */
@@ -319,7 +329,7 @@ static int __die_find_variable_cb(Dwarf_Die *die_mem, void *data)
tag = dwarf_tag(die_mem);
if ((tag == DW_TAG_formal_parameter ||
tag == DW_TAG_variable) &&
- (die_compare_name(die_mem, name) == 0))
+ die_compare_name(die_mem, name))
return DIE_FIND_CB_FOUND;
return DIE_FIND_CB_CONTINUE;
@@ -338,7 +348,7 @@ static int __die_find_member_cb(Dwarf_Die *die_mem, void *data)
const char *name = data;
if ((dwarf_tag(die_mem) == DW_TAG_member) &&
- (die_compare_name(die_mem, name) == 0))
+ die_compare_name(die_mem, name))
return DIE_FIND_CB_FOUND;
return DIE_FIND_CB_SIBLING;
@@ -356,14 +366,50 @@ static Dwarf_Die *die_find_member(Dwarf_Die *st_die, const char *name,
* Probe finder related functions
*/
+static struct probe_trace_arg_ref *alloc_trace_arg_ref(long offs)
+{
+ struct probe_trace_arg_ref *ref;
+ ref = zalloc(sizeof(struct probe_trace_arg_ref));
+ if (ref != NULL)
+ ref->offset = offs;
+ return ref;
+}
+
/* Show a location */
-static int convert_location(Dwarf_Op *op, struct probe_finder *pf)
+static int convert_variable_location(Dwarf_Die *vr_die, struct probe_finder *pf)
{
+ Dwarf_Attribute attr;
+ Dwarf_Op *op;
+ size_t nops;
unsigned int regn;
Dwarf_Word offs = 0;
bool ref = false;
const char *regs;
- struct kprobe_trace_arg *tvar = pf->tvar;
+ struct probe_trace_arg *tvar = pf->tvar;
+ int ret;
+
+ /* TODO: handle more than 1 exprs */
+ if (dwarf_attr(vr_die, DW_AT_location, &attr) == NULL ||
+ dwarf_getlocation_addr(&attr, pf->addr, &op, &nops, 1) <= 0 ||
+ nops == 0) {
+ /* TODO: Support const_value */
+ pr_err("Failed to find the location of %s at this address.\n"
+ " Perhaps, it has been optimized out.\n", pf->pvar->var);
+ return -ENOENT;
+ }
+
+ if (op->atom == DW_OP_addr) {
+ /* Static variables on memory (not stack), make @varname */
+ ret = strlen(dwarf_diename(vr_die));
+ tvar->value = zalloc(ret + 2);
+ if (tvar->value == NULL)
+ return -ENOMEM;
+ snprintf(tvar->value, ret + 2, "@%s", dwarf_diename(vr_die));
+ tvar->ref = alloc_trace_arg_ref((long)offs);
+ if (tvar->ref == NULL)
+ return -ENOMEM;
+ return 0;
+ }
/* If this is based on frame buffer, set the offset */
if (op->atom == DW_OP_fbreg) {
@@ -405,27 +451,72 @@ static int convert_location(Dwarf_Op *op, struct probe_finder *pf)
return -ENOMEM;
if (ref) {
- tvar->ref = zalloc(sizeof(struct kprobe_trace_arg_ref));
+ tvar->ref = alloc_trace_arg_ref((long)offs);
if (tvar->ref == NULL)
return -ENOMEM;
- tvar->ref->offset = (long)offs;
}
return 0;
}
static int convert_variable_type(Dwarf_Die *vr_die,
- struct kprobe_trace_arg *targ)
+ struct probe_trace_arg *tvar,
+ const char *cast)
{
+ struct probe_trace_arg_ref **ref_ptr = &tvar->ref;
Dwarf_Die type;
char buf[16];
int ret;
+ /* TODO: check all types */
+ if (cast && strcmp(cast, "string") != 0) {
+ /* Non string type is OK */
+ tvar->type = strdup(cast);
+ return (tvar->type == NULL) ? -ENOMEM : 0;
+ }
+
if (die_get_real_type(vr_die, &type) == NULL) {
pr_warning("Failed to get a type information of %s.\n",
dwarf_diename(vr_die));
return -ENOENT;
}
+ pr_debug("%s type is %s.\n",
+ dwarf_diename(vr_die), dwarf_diename(&type));
+
+ if (cast && strcmp(cast, "string") == 0) { /* String type */
+ ret = dwarf_tag(&type);
+ if (ret != DW_TAG_pointer_type &&
+ ret != DW_TAG_array_type) {
+ pr_warning("Failed to cast into string: "
+ "%s(%s) is not a pointer nor array.",
+ dwarf_diename(vr_die), dwarf_diename(&type));
+ return -EINVAL;
+ }
+ if (ret == DW_TAG_pointer_type) {
+ if (die_get_real_type(&type, &type) == NULL) {
+ pr_warning("Failed to get a type information.");
+ return -ENOENT;
+ }
+ while (*ref_ptr)
+ ref_ptr = &(*ref_ptr)->next;
+ /* Add new reference with offset +0 */
+ *ref_ptr = zalloc(sizeof(struct probe_trace_arg_ref));
+ if (*ref_ptr == NULL) {
+ pr_warning("Out of memory error\n");
+ return -ENOMEM;
+ }
+ }
+ if (!die_compare_name(&type, "char") &&
+ !die_compare_name(&type, "unsigned char")) {
+ pr_warning("Failed to cast into string: "
+ "%s is not (unsigned) char *.",
+ dwarf_diename(vr_die));
+ return -EINVAL;
+ }
+ tvar->type = strdup(cast);
+ return (tvar->type == NULL) ? -ENOMEM : 0;
+ }
+
ret = die_get_byte_size(&type) * 8;
if (ret) {
/* Check the bitwidth */
@@ -445,8 +536,8 @@ static int convert_variable_type(Dwarf_Die *vr_die,
strerror(-ret));
return ret;
}
- targ->type = strdup(buf);
- if (targ->type == NULL)
+ tvar->type = strdup(buf);
+ if (tvar->type == NULL)
return -ENOMEM;
}
return 0;
@@ -454,22 +545,50 @@ static int convert_variable_type(Dwarf_Die *vr_die,
static int convert_variable_fields(Dwarf_Die *vr_die, const char *varname,
struct perf_probe_arg_field *field,
- struct kprobe_trace_arg_ref **ref_ptr,
+ struct probe_trace_arg_ref **ref_ptr,
Dwarf_Die *die_mem)
{
- struct kprobe_trace_arg_ref *ref = *ref_ptr;
+ struct probe_trace_arg_ref *ref = *ref_ptr;
Dwarf_Die type;
Dwarf_Word offs;
- int ret;
+ int ret, tag;
pr_debug("converting %s in %s\n", field->name, varname);
if (die_get_real_type(vr_die, &type) == NULL) {
pr_warning("Failed to get the type of %s.\n", varname);
return -ENOENT;
}
-
- /* Check the pointer and dereference */
- if (dwarf_tag(&type) == DW_TAG_pointer_type) {
+ pr_debug2("Var real type: (%x)\n", (unsigned)dwarf_dieoffset(&type));
+ tag = dwarf_tag(&type);
+
+ if (field->name[0] == '[' &&
+ (tag == DW_TAG_array_type || tag == DW_TAG_pointer_type)) {
+ if (field->next)
+ /* Save original type for next field */
+ memcpy(die_mem, &type, sizeof(*die_mem));
+ /* Get the type of this array */
+ if (die_get_real_type(&type, &type) == NULL) {
+ pr_warning("Failed to get the type of %s.\n", varname);
+ return -ENOENT;
+ }
+ pr_debug2("Array real type: (%x)\n",
+ (unsigned)dwarf_dieoffset(&type));
+ if (tag == DW_TAG_pointer_type) {
+ ref = zalloc(sizeof(struct probe_trace_arg_ref));
+ if (ref == NULL)
+ return -ENOMEM;
+ if (*ref_ptr)
+ (*ref_ptr)->next = ref;
+ else
+ *ref_ptr = ref;
+ }
+ ref->offset += die_get_byte_size(&type) * field->index;
+ if (!field->next)
+ /* Save vr_die for converting types */
+ memcpy(die_mem, vr_die, sizeof(*die_mem));
+ goto next;
+ } else if (tag == DW_TAG_pointer_type) {
+ /* Check the pointer and dereference */
if (!field->ref) {
pr_err("Semantic error: %s must be referred by '->'\n",
field->name);
@@ -486,7 +605,7 @@ static int convert_variable_fields(Dwarf_Die *vr_die, const char *varname,
return -EINVAL;
}
- ref = zalloc(sizeof(struct kprobe_trace_arg_ref));
+ ref = zalloc(sizeof(struct probe_trace_arg_ref));
if (ref == NULL)
return -ENOMEM;
if (*ref_ptr)
@@ -495,10 +614,15 @@ static int convert_variable_fields(Dwarf_Die *vr_die, const char *varname,
*ref_ptr = ref;
} else {
/* Verify it is a data structure */
- if (dwarf_tag(&type) != DW_TAG_structure_type) {
+ if (tag != DW_TAG_structure_type) {
pr_warning("%s is not a data structure.\n", varname);
return -EINVAL;
}
+ if (field->name[0] == '[') {
+ pr_err("Semantic error: %s is not a pointor nor array.",
+ varname);
+ return -EINVAL;
+ }
if (field->ref) {
pr_err("Semantic error: %s must be referred by '.'\n",
field->name);
@@ -525,6 +649,7 @@ static int convert_variable_fields(Dwarf_Die *vr_die, const char *varname,
}
ref->offset += (long)offs;
+next:
/* Converting next field */
if (field->next)
return convert_variable_fields(die_mem, field->name,
@@ -536,51 +661,32 @@ static int convert_variable_fields(Dwarf_Die *vr_die, const char *varname,
/* Show a variables in kprobe event format */
static int convert_variable(Dwarf_Die *vr_die, struct probe_finder *pf)
{
- Dwarf_Attribute attr;
Dwarf_Die die_mem;
- Dwarf_Op *expr;
- size_t nexpr;
int ret;
- if (dwarf_attr(vr_die, DW_AT_location, &attr) == NULL)
- goto error;
- /* TODO: handle more than 1 exprs */
- ret = dwarf_getlocation_addr(&attr, pf->addr, &expr, &nexpr, 1);
- if (ret <= 0 || nexpr == 0)
- goto error;
+ pr_debug("Converting variable %s into trace event.\n",
+ dwarf_diename(vr_die));
- ret = convert_location(expr, pf);
+ ret = convert_variable_location(vr_die, pf);
if (ret == 0 && pf->pvar->field) {
ret = convert_variable_fields(vr_die, pf->pvar->var,
pf->pvar->field, &pf->tvar->ref,
&die_mem);
vr_die = &die_mem;
}
- if (ret == 0) {
- if (pf->pvar->type) {
- pf->tvar->type = strdup(pf->pvar->type);
- if (pf->tvar->type == NULL)
- ret = -ENOMEM;
- } else
- ret = convert_variable_type(vr_die, pf->tvar);
- }
+ if (ret == 0)
+ ret = convert_variable_type(vr_die, pf->tvar, pf->pvar->type);
/* *expr will be cached in libdw. Don't free it. */
return ret;
-error:
- /* TODO: Support const_value */
- pr_err("Failed to find the location of %s at this address.\n"
- " Perhaps, it has been optimized out.\n", pf->pvar->var);
- return -ENOENT;
}
/* Find a variable in a subprogram die */
static int find_variable(Dwarf_Die *sp_die, struct probe_finder *pf)
{
- Dwarf_Die vr_die;
+ Dwarf_Die vr_die, *scopes;
char buf[32], *ptr;
- int ret;
+ int ret, nscopes;
- /* TODO: Support arrays */
if (pf->pvar->name)
pf->tvar->name = strdup(pf->pvar->name);
else {
@@ -607,18 +713,32 @@ static int find_variable(Dwarf_Die *sp_die, struct probe_finder *pf)
pr_debug("Searching '%s' variable in context.\n",
pf->pvar->var);
/* Search child die for local variables and parameters. */
- if (!die_find_variable(sp_die, pf->pvar->var, &vr_die)) {
+ if (die_find_variable(sp_die, pf->pvar->var, &vr_die))
+ ret = convert_variable(&vr_die, pf);
+ else {
+ /* Search upper class */
+ nscopes = dwarf_getscopes_die(sp_die, &scopes);
+ if (nscopes > 0) {
+ ret = dwarf_getscopevar(scopes, nscopes, pf->pvar->var,
+ 0, NULL, 0, 0, &vr_die);
+ if (ret >= 0)
+ ret = convert_variable(&vr_die, pf);
+ else
+ ret = -ENOENT;
+ free(scopes);
+ } else
+ ret = -ENOENT;
+ }
+ if (ret < 0)
pr_warning("Failed to find '%s' in this function.\n",
pf->pvar->var);
- return -ENOENT;
- }
- return convert_variable(&vr_die, pf);
+ return ret;
}
/* Show a probe point to output buffer */
static int convert_probe_point(Dwarf_Die *sp_die, struct probe_finder *pf)
{
- struct kprobe_trace_event *tev;
+ struct probe_trace_event *tev;
Dwarf_Addr eaddr;
Dwarf_Die die_mem;
const char *name;
@@ -683,7 +803,7 @@ static int convert_probe_point(Dwarf_Die *sp_die, struct probe_finder *pf)
/* Find each argument */
tev->nargs = pf->pev->nargs;
- tev->args = zalloc(sizeof(struct kprobe_trace_arg) * tev->nargs);
+ tev->args = zalloc(sizeof(struct probe_trace_arg) * tev->nargs);
if (tev->args == NULL)
return -ENOMEM;
for (i = 0; i < pf->pev->nargs; i++) {
@@ -897,7 +1017,7 @@ static int probe_point_search_cb(Dwarf_Die *sp_die, void *data)
/* Check tag and diename */
if (dwarf_tag(sp_die) != DW_TAG_subprogram ||
- die_compare_name(sp_die, pp->function) != 0)
+ !die_compare_name(sp_die, pp->function))
return DWARF_CB_OK;
pf->fname = dwarf_decl_file(sp_die);
@@ -940,9 +1060,9 @@ static int find_probe_point_by_func(struct probe_finder *pf)
return _param.retval;
}
-/* Find kprobe_trace_events specified by perf_probe_event from debuginfo */
-int find_kprobe_trace_events(int fd, struct perf_probe_event *pev,
- struct kprobe_trace_event **tevs, int max_tevs)
+/* Find probe_trace_events specified by perf_probe_event from debuginfo */
+int find_probe_trace_events(int fd, struct perf_probe_event *pev,
+ struct probe_trace_event **tevs, int max_tevs)
{
struct probe_finder pf = {.pev = pev, .max_tevs = max_tevs};
struct perf_probe_point *pp = &pev->point;
@@ -952,7 +1072,7 @@ int find_kprobe_trace_events(int fd, struct perf_probe_event *pev,
Dwarf *dbg;
int ret = 0;
- pf.tevs = zalloc(sizeof(struct kprobe_trace_event) * max_tevs);
+ pf.tevs = zalloc(sizeof(struct probe_trace_event) * max_tevs);
if (pf.tevs == NULL)
return -ENOMEM;
*tevs = pf.tevs;
@@ -1096,7 +1216,7 @@ end:
static int line_range_add_line(const char *src, unsigned int lineno,
struct line_range *lr)
{
- /* Copy real path */
+ /* Copy source path */
if (!lr->path) {
lr->path = strdup(src);
if (lr->path == NULL)
@@ -1220,7 +1340,7 @@ static int line_range_search_cb(Dwarf_Die *sp_die, void *data)
struct line_range *lr = lf->lr;
if (dwarf_tag(sp_die) == DW_TAG_subprogram &&
- die_compare_name(sp_die, lr->function) == 0) {
+ die_compare_name(sp_die, lr->function)) {
lf->fname = dwarf_decl_file(sp_die);
dwarf_decl_line(sp_die, &lr->offset);
pr_debug("fname: %s, lineno:%d\n", lf->fname, lr->offset);
@@ -1263,6 +1383,7 @@ int find_line_range(int fd, struct line_range *lr)
size_t cuhl;
Dwarf_Die *diep;
Dwarf *dbg;
+ const char *comp_dir;
dbg = dwarf_begin(fd, DWARF_C_READ);
if (!dbg) {
@@ -1298,7 +1419,18 @@ int find_line_range(int fd, struct line_range *lr)
}
off = noff;
}
- pr_debug("path: %lx\n", (unsigned long)lr->path);
+
+ /* Store comp_dir */
+ if (lf.found) {
+ comp_dir = cu_get_comp_dir(&lf.cu_die);
+ if (comp_dir) {
+ lr->comp_dir = strdup(comp_dir);
+ if (!lr->comp_dir)
+ ret = -ENOMEM;
+ }
+ }
+
+ pr_debug("path: %s\n", lr->path);
dwarf_end(dbg);
return (ret < 0) ? ret : lf.found;
diff --git a/tools/perf/util/probe-finder.h b/tools/perf/util/probe-finder.h
index e1f61dcd18f..4507d519f18 100644
--- a/tools/perf/util/probe-finder.h
+++ b/tools/perf/util/probe-finder.h
@@ -16,9 +16,9 @@ static inline int is_c_varname(const char *name)
}
#ifdef DWARF_SUPPORT
-/* Find kprobe_trace_events specified by perf_probe_event from debuginfo */
-extern int find_kprobe_trace_events(int fd, struct perf_probe_event *pev,
- struct kprobe_trace_event **tevs,
+/* Find probe_trace_events specified by perf_probe_event from debuginfo */
+extern int find_probe_trace_events(int fd, struct perf_probe_event *pev,
+ struct probe_trace_event **tevs,
int max_tevs);
/* Find a perf_probe_point from debuginfo */
@@ -33,7 +33,7 @@ extern int find_line_range(int fd, struct line_range *lr);
struct probe_finder {
struct perf_probe_event *pev; /* Target probe event */
- struct kprobe_trace_event *tevs; /* Result trace events */
+ struct probe_trace_event *tevs; /* Result trace events */
int ntevs; /* Number of trace events */
int max_tevs; /* Max number of trace events */
@@ -50,7 +50,7 @@ struct probe_finder {
#endif
Dwarf_Op *fb_ops; /* Frame base attribute */
struct perf_probe_arg *pvar; /* Current target variable */
- struct kprobe_trace_arg *tvar; /* Current result variable */
+ struct probe_trace_arg *tvar; /* Current result variable */
};
struct line_finder {
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index c422cd67631..fa9d652c2dc 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -27,8 +27,10 @@ static int perf_session__open(struct perf_session *self, bool force)
self->fd = open(self->filename, O_RDONLY);
if (self->fd < 0) {
- pr_err("failed to open file: %s", self->filename);
- if (!strcmp(self->filename, "perf.data"))
+ int err = errno;
+
+ pr_err("failed to open %s: %s", self->filename, strerror(err));
+ if (err == ENOENT && !strcmp(self->filename, "perf.data"))
pr_err(" (try 'perf record' first)");
pr_err("\n");
return -errno;
@@ -77,6 +79,12 @@ int perf_session__create_kernel_maps(struct perf_session *self)
return ret;
}
+static void perf_session__destroy_kernel_maps(struct perf_session *self)
+{
+ machine__destroy_kernel_maps(&self->host_machine);
+ machines__destroy_guest_kernel_maps(&self->machines);
+}
+
struct perf_session *perf_session__new(const char *filename, int mode, bool force, bool repipe)
{
size_t len = filename ? strlen(filename) + 1 : 0;
@@ -94,8 +102,6 @@ struct perf_session *perf_session__new(const char *filename, int mode, bool forc
self->hists_tree = RB_ROOT;
self->last_match = NULL;
self->mmap_window = 32;
- self->cwd = NULL;
- self->cwdlen = 0;
self->machines = RB_ROOT;
self->repipe = repipe;
INIT_LIST_HEAD(&self->ordered_samples.samples_head);
@@ -124,16 +130,43 @@ out_delete:
return NULL;
}
+static void perf_session__delete_dead_threads(struct perf_session *self)
+{
+ struct thread *n, *t;
+
+ list_for_each_entry_safe(t, n, &self->dead_threads, node) {
+ list_del(&t->node);
+ thread__delete(t);
+ }
+}
+
+static void perf_session__delete_threads(struct perf_session *self)
+{
+ struct rb_node *nd = rb_first(&self->threads);
+
+ while (nd) {
+ struct thread *t = rb_entry(nd, struct thread, rb_node);
+
+ rb_erase(&t->rb_node, &self->threads);
+ nd = rb_next(nd);
+ thread__delete(t);
+ }
+}
+
void perf_session__delete(struct perf_session *self)
{
perf_header__exit(&self->header);
+ perf_session__destroy_kernel_maps(self);
+ perf_session__delete_dead_threads(self);
+ perf_session__delete_threads(self);
+ machine__exit(&self->host_machine);
close(self->fd);
- free(self->cwd);
free(self);
}
void perf_session__remove_thread(struct perf_session *self, struct thread *th)
{
+ self->last_match = NULL;
rb_erase(&th->rb_node, &self->threads);
/*
* We may have references to this thread, for instance in some hist_entry
@@ -830,23 +863,6 @@ int perf_session__process_events(struct perf_session *self,
if (perf_session__register_idle_thread(self) == NULL)
return -ENOMEM;
- if (!symbol_conf.full_paths) {
- char bf[PATH_MAX];
-
- if (getcwd(bf, sizeof(bf)) == NULL) {
- err = -errno;
-out_getcwd_err:
- pr_err("failed to get the current directory\n");
- goto out_err;
- }
- self->cwd = strdup(bf);
- if (self->cwd == NULL) {
- err = -ENOMEM;
- goto out_getcwd_err;
- }
- self->cwdlen = strlen(self->cwd);
- }
-
if (!self->fd_pipe)
err = __perf_session__process_events(self,
self->header.data_offset,
@@ -854,7 +870,7 @@ out_getcwd_err:
self->size, ops);
else
err = __perf_session__process_pipe_events(self, ops);
-out_err:
+
return err;
}
diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c
index 2316cb5a411..1c61a4f4aa8 100644
--- a/tools/perf/util/sort.c
+++ b/tools/perf/util/sort.c
@@ -1,4 +1,5 @@
#include "sort.h"
+#include "hist.h"
regex_t parent_regex;
const char default_parent_pattern[] = "^sys_|^do_page_fault";
@@ -10,10 +11,6 @@ int sort__has_parent = 0;
enum sort_type sort__first_dimension;
-unsigned int dsos__col_width;
-unsigned int comms__col_width;
-unsigned int threads__col_width;
-static unsigned int parent_symbol__col_width;
char * field_sep;
LIST_HEAD(hist_entry__sort_list);
@@ -28,12 +25,14 @@ static int hist_entry__sym_snprintf(struct hist_entry *self, char *bf,
size_t size, unsigned int width);
static int hist_entry__parent_snprintf(struct hist_entry *self, char *bf,
size_t size, unsigned int width);
+static int hist_entry__cpu_snprintf(struct hist_entry *self, char *bf,
+ size_t size, unsigned int width);
struct sort_entry sort_thread = {
.se_header = "Command: Pid",
.se_cmp = sort__thread_cmp,
.se_snprintf = hist_entry__thread_snprintf,
- .se_width = &threads__col_width,
+ .se_width_idx = HISTC_THREAD,
};
struct sort_entry sort_comm = {
@@ -41,27 +40,35 @@ struct sort_entry sort_comm = {
.se_cmp = sort__comm_cmp,
.se_collapse = sort__comm_collapse,
.se_snprintf = hist_entry__comm_snprintf,
- .se_width = &comms__col_width,
+ .se_width_idx = HISTC_COMM,
};
struct sort_entry sort_dso = {
.se_header = "Shared Object",
.se_cmp = sort__dso_cmp,
.se_snprintf = hist_entry__dso_snprintf,
- .se_width = &dsos__col_width,
+ .se_width_idx = HISTC_DSO,
};
struct sort_entry sort_sym = {
.se_header = "Symbol",
.se_cmp = sort__sym_cmp,
.se_snprintf = hist_entry__sym_snprintf,
+ .se_width_idx = HISTC_SYMBOL,
};
struct sort_entry sort_parent = {
.se_header = "Parent symbol",
.se_cmp = sort__parent_cmp,
.se_snprintf = hist_entry__parent_snprintf,
- .se_width = &parent_symbol__col_width,
+ .se_width_idx = HISTC_PARENT,
+};
+
+struct sort_entry sort_cpu = {
+ .se_header = "CPU",
+ .se_cmp = sort__cpu_cmp,
+ .se_snprintf = hist_entry__cpu_snprintf,
+ .se_width_idx = HISTC_CPU,
};
struct sort_dimension {
@@ -76,6 +83,7 @@ static struct sort_dimension sort_dimensions[] = {
{ .name = "dso", .entry = &sort_dso, },
{ .name = "symbol", .entry = &sort_sym, },
{ .name = "parent", .entry = &sort_parent, },
+ { .name = "cpu", .entry = &sort_cpu, },
};
int64_t cmp_null(void *l, void *r)
@@ -242,6 +250,20 @@ static int hist_entry__parent_snprintf(struct hist_entry *self, char *bf,
self->parent ? self->parent->name : "[other]");
}
+/* --sort cpu */
+
+int64_t
+sort__cpu_cmp(struct hist_entry *left, struct hist_entry *right)
+{
+ return right->cpu - left->cpu;
+}
+
+static int hist_entry__cpu_snprintf(struct hist_entry *self, char *bf,
+ size_t size, unsigned int width)
+{
+ return repsep_snprintf(bf, size, "%-*d", width, self->cpu);
+}
+
int sort_dimension__add(const char *tok)
{
unsigned int i;
@@ -281,6 +303,8 @@ int sort_dimension__add(const char *tok)
sort__first_dimension = SORT_SYM;
else if (!strcmp(sd->name, "parent"))
sort__first_dimension = SORT_PARENT;
+ else if (!strcmp(sd->name, "cpu"))
+ sort__first_dimension = SORT_CPU;
}
list_add_tail(&sd->entry->list, &hist_entry__sort_list);
diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h
index 0d61c4082f4..46e531d09e8 100644
--- a/tools/perf/util/sort.h
+++ b/tools/perf/util/sort.h
@@ -36,11 +36,14 @@ extern struct sort_entry sort_comm;
extern struct sort_entry sort_dso;
extern struct sort_entry sort_sym;
extern struct sort_entry sort_parent;
-extern unsigned int dsos__col_width;
-extern unsigned int comms__col_width;
-extern unsigned int threads__col_width;
extern enum sort_type sort__first_dimension;
+/**
+ * struct hist_entry - histogram entry
+ *
+ * @row_offset - offset from the first callchain expanded to appear on screen
+ * @nr_rows - rows expanded in callchain, recalculated on folding/unfolding
+ */
struct hist_entry {
struct rb_node rb_node;
u64 period;
@@ -51,7 +54,14 @@ struct hist_entry {
struct map_symbol ms;
struct thread *thread;
u64 ip;
+ s32 cpu;
u32 nr_events;
+
+ /* XXX These two should move to some tree widget lib */
+ u16 row_offset;
+ u16 nr_rows;
+
+ bool init_have_children;
char level;
u8 filtered;
struct symbol *parent;
@@ -68,7 +78,8 @@ enum sort_type {
SORT_COMM,
SORT_DSO,
SORT_SYM,
- SORT_PARENT
+ SORT_PARENT,
+ SORT_CPU,
};
/*
@@ -84,7 +95,7 @@ struct sort_entry {
int64_t (*se_collapse)(struct hist_entry *, struct hist_entry *);
int (*se_snprintf)(struct hist_entry *self, char *bf, size_t size,
unsigned int width);
- unsigned int *se_width;
+ u8 se_width_idx;
bool elide;
};
@@ -104,6 +115,7 @@ extern int64_t sort__comm_collapse(struct hist_entry *, struct hist_entry *);
extern int64_t sort__dso_cmp(struct hist_entry *, struct hist_entry *);
extern int64_t sort__sym_cmp(struct hist_entry *, struct hist_entry *);
extern int64_t sort__parent_cmp(struct hist_entry *, struct hist_entry *);
+int64_t sort__cpu_cmp(struct hist_entry *left, struct hist_entry *right);
extern size_t sort__parent_print(FILE *, struct hist_entry *, unsigned int);
extern int sort_dimension__add(const char *);
void sort_entry__setup_elide(struct sort_entry *self, struct strlist *list,
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index 5b276833e2b..6f0dd90c36c 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -12,6 +12,7 @@
#include <fcntl.h>
#include <unistd.h>
#include "build-id.h"
+#include "debug.h"
#include "symbol.h"
#include "strlist.h"
@@ -25,6 +26,8 @@
#define NT_GNU_BUILD_ID 3
#endif
+static bool dso__build_id_equal(const struct dso *self, u8 *build_id);
+static int elf_read_build_id(Elf *elf, void *bf, size_t size);
static void dsos__add(struct list_head *head, struct dso *dso);
static struct map *map__new2(u64 start, struct dso *dso, enum map_type type);
static int dso__load_kernel_sym(struct dso *self, struct map *map,
@@ -40,6 +43,14 @@ struct symbol_conf symbol_conf = {
.try_vmlinux_path = true,
};
+int dso__name_len(const struct dso *self)
+{
+ if (verbose)
+ return self->long_name_len;
+
+ return self->short_name_len;
+}
+
bool dso__loaded(const struct dso *self, enum map_type type)
{
return self->loaded & (1 << type);
@@ -215,7 +226,9 @@ void dso__delete(struct dso *self)
int i;
for (i = 0; i < MAP__NR_TYPES; ++i)
symbols__delete(&self->symbols[i]);
- if (self->long_name != self->name)
+ if (self->sname_alloc)
+ free((char *)self->short_name);
+ if (self->lname_alloc)
free(self->long_name);
free(self);
}
@@ -933,8 +946,28 @@ static bool elf_sec__is_a(GElf_Shdr *self, Elf_Data *secstrs, enum map_type type
}
}
+static size_t elf_addr_to_index(Elf *elf, GElf_Addr addr)
+{
+ Elf_Scn *sec = NULL;
+ GElf_Shdr shdr;
+ size_t cnt = 1;
+
+ while ((sec = elf_nextscn(elf, sec)) != NULL) {
+ gelf_getshdr(sec, &shdr);
+
+ if ((addr >= shdr.sh_addr) &&
+ (addr < (shdr.sh_addr + shdr.sh_size)))
+ return cnt;
+
+ ++cnt;
+ }
+
+ return -1;
+}
+
static int dso__load_sym(struct dso *self, struct map *map, const char *name,
- int fd, symbol_filter_t filter, int kmodule)
+ int fd, symbol_filter_t filter, int kmodule,
+ int want_symtab)
{
struct kmap *kmap = self->kernel ? map__kmap(map) : NULL;
struct map *curr_map = map;
@@ -944,31 +977,51 @@ static int dso__load_sym(struct dso *self, struct map *map, const char *name,
int err = -1;
uint32_t idx;
GElf_Ehdr ehdr;
- GElf_Shdr shdr;
- Elf_Data *syms;
+ GElf_Shdr shdr, opdshdr;
+ Elf_Data *syms, *opddata = NULL;
GElf_Sym sym;
- Elf_Scn *sec, *sec_strndx;
+ Elf_Scn *sec, *sec_strndx, *opdsec;
Elf *elf;
int nr = 0;
+ size_t opdidx = 0;
elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
if (elf == NULL) {
- pr_err("%s: cannot read %s ELF file.\n", __func__, name);
+ pr_debug("%s: cannot read %s ELF file.\n", __func__, name);
goto out_close;
}
if (gelf_getehdr(elf, &ehdr) == NULL) {
- pr_err("%s: cannot get elf header.\n", __func__);
+ pr_debug("%s: cannot get elf header.\n", __func__);
goto out_elf_end;
}
+ /* Always reject images with a mismatched build-id: */
+ if (self->has_build_id) {
+ u8 build_id[BUILD_ID_SIZE];
+
+ if (elf_read_build_id(elf, build_id,
+ BUILD_ID_SIZE) != BUILD_ID_SIZE)
+ goto out_elf_end;
+
+ if (!dso__build_id_equal(self, build_id))
+ goto out_elf_end;
+ }
+
sec = elf_section_by_name(elf, &ehdr, &shdr, ".symtab", NULL);
if (sec == NULL) {
+ if (want_symtab)
+ goto out_elf_end;
+
sec = elf_section_by_name(elf, &ehdr, &shdr, ".dynsym", NULL);
if (sec == NULL)
goto out_elf_end;
}
+ opdsec = elf_section_by_name(elf, &ehdr, &opdshdr, ".opd", &opdidx);
+ if (opdsec)
+ opddata = elf_rawdata(opdsec, NULL);
+
syms = elf_getdata(sec, NULL);
if (syms == NULL)
goto out_elf_end;
@@ -1013,6 +1066,13 @@ static int dso__load_sym(struct dso *self, struct map *map, const char *name,
if (!is_label && !elf_sym__is_a(&sym, map->type))
continue;
+ if (opdsec && sym.st_shndx == opdidx) {
+ u32 offset = sym.st_value - opdshdr.sh_addr;
+ u64 *opd = opddata->d_buf + offset;
+ sym.st_value = *opd;
+ sym.st_shndx = elf_addr_to_index(elf, sym.st_value);
+ }
+
sec = elf_getscn(elf, sym.st_shndx);
if (!sec)
goto out_elf_end;
@@ -1151,37 +1211,26 @@ bool __dsos__read_build_ids(struct list_head *head, bool with_hits)
*/
#define NOTE_ALIGN(n) (((n) + 3) & -4U)
-int filename__read_build_id(const char *filename, void *bf, size_t size)
+static int elf_read_build_id(Elf *elf, void *bf, size_t size)
{
- int fd, err = -1;
+ int err = -1;
GElf_Ehdr ehdr;
GElf_Shdr shdr;
Elf_Data *data;
Elf_Scn *sec;
Elf_Kind ek;
void *ptr;
- Elf *elf;
if (size < BUILD_ID_SIZE)
goto out;
- fd = open(filename, O_RDONLY);
- if (fd < 0)
- goto out;
-
- elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
- if (elf == NULL) {
- pr_debug2("%s: cannot read %s ELF file.\n", __func__, filename);
- goto out_close;
- }
-
ek = elf_kind(elf);
if (ek != ELF_K_ELF)
- goto out_elf_end;
+ goto out;
if (gelf_getehdr(elf, &ehdr) == NULL) {
pr_err("%s: cannot get elf header.\n", __func__);
- goto out_elf_end;
+ goto out;
}
sec = elf_section_by_name(elf, &ehdr, &shdr,
@@ -1190,12 +1239,12 @@ int filename__read_build_id(const char *filename, void *bf, size_t size)
sec = elf_section_by_name(elf, &ehdr, &shdr,
".notes", NULL);
if (sec == NULL)
- goto out_elf_end;
+ goto out;
}
data = elf_getdata(sec, NULL);
if (data == NULL)
- goto out_elf_end;
+ goto out;
ptr = data->d_buf;
while (ptr < (data->d_buf + data->d_size)) {
@@ -1217,7 +1266,31 @@ int filename__read_build_id(const char *filename, void *bf, size_t size)
}
ptr += descsz;
}
-out_elf_end:
+
+out:
+ return err;
+}
+
+int filename__read_build_id(const char *filename, void *bf, size_t size)
+{
+ int fd, err = -1;
+ Elf *elf;
+
+ if (size < BUILD_ID_SIZE)
+ goto out;
+
+ fd = open(filename, O_RDONLY);
+ if (fd < 0)
+ goto out;
+
+ elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
+ if (elf == NULL) {
+ pr_debug2("%s: cannot read %s ELF file.\n", __func__, filename);
+ goto out_close;
+ }
+
+ err = elf_read_build_id(elf, bf, size);
+
elf_end(elf);
out_close:
close(fd);
@@ -1293,11 +1366,11 @@ int dso__load(struct dso *self, struct map *map, symbol_filter_t filter)
{
int size = PATH_MAX;
char *name;
- u8 build_id[BUILD_ID_SIZE];
int ret = -1;
int fd;
struct machine *machine;
const char *root_dir;
+ int want_symtab;
dso__set_loaded(self, map->type);
@@ -1324,13 +1397,18 @@ int dso__load(struct dso *self, struct map *map, symbol_filter_t filter)
return ret;
}
- self->origin = DSO__ORIG_BUILD_ID_CACHE;
- if (dso__build_id_filename(self, name, size) != NULL)
- goto open_file;
-more:
- do {
- self->origin++;
+ /* Iterate over candidate debug images.
+ * On the first pass, only load images if they have a full symtab.
+ * Failing that, do a second pass where we accept .dynsym also
+ */
+ for (self->origin = DSO__ORIG_BUILD_ID_CACHE, want_symtab = 1;
+ self->origin != DSO__ORIG_NOT_FOUND;
+ self->origin++) {
switch (self->origin) {
+ case DSO__ORIG_BUILD_ID_CACHE:
+ if (dso__build_id_filename(self, name, size) == NULL)
+ continue;
+ break;
case DSO__ORIG_FEDORA:
snprintf(name, size, "/usr/lib/debug%s.debug",
self->long_name);
@@ -1339,21 +1417,20 @@ more:
snprintf(name, size, "/usr/lib/debug%s",
self->long_name);
break;
- case DSO__ORIG_BUILDID:
- if (filename__read_build_id(self->long_name, build_id,
- sizeof(build_id))) {
- char build_id_hex[BUILD_ID_SIZE * 2 + 1];
- build_id__sprintf(build_id, sizeof(build_id),
- build_id_hex);
- snprintf(name, size,
- "/usr/lib/debug/.build-id/%.2s/%s.debug",
- build_id_hex, build_id_hex + 2);
- if (self->has_build_id)
- goto compare_build_id;
- break;
+ case DSO__ORIG_BUILDID: {
+ char build_id_hex[BUILD_ID_SIZE * 2 + 1];
+
+ if (!self->has_build_id)
+ continue;
+
+ build_id__sprintf(self->build_id,
+ sizeof(self->build_id),
+ build_id_hex);
+ snprintf(name, size,
+ "/usr/lib/debug/.build-id/%.2s/%s.debug",
+ build_id_hex, build_id_hex + 2);
}
- self->origin++;
- /* Fall thru */
+ break;
case DSO__ORIG_DSO:
snprintf(name, size, "%s", self->long_name);
break;
@@ -1366,36 +1443,41 @@ more:
break;
default:
- goto out;
+ /*
+ * If we wanted a full symtab but no image had one,
+ * relax our requirements and repeat the search.
+ */
+ if (want_symtab) {
+ want_symtab = 0;
+ self->origin = DSO__ORIG_BUILD_ID_CACHE;
+ } else
+ continue;
}
- if (self->has_build_id) {
- if (filename__read_build_id(name, build_id,
- sizeof(build_id)) < 0)
- goto more;
-compare_build_id:
- if (!dso__build_id_equal(self, build_id))
- goto more;
- }
-open_file:
+ /* Name is now the name of the next image to try */
fd = open(name, O_RDONLY);
- } while (fd < 0);
+ if (fd < 0)
+ continue;
- ret = dso__load_sym(self, map, name, fd, filter, 0);
- close(fd);
+ ret = dso__load_sym(self, map, name, fd, filter, 0,
+ want_symtab);
+ close(fd);
- /*
- * Some people seem to have debuginfo files _WITHOUT_ debug info!?!?
- */
- if (!ret)
- goto more;
+ /*
+ * Some people seem to have debuginfo files _WITHOUT_ debug
+ * info!?!?
+ */
+ if (!ret)
+ continue;
- if (ret > 0) {
- int nr_plt = dso__synthesize_plt_symbols(self, map, filter);
- if (nr_plt > 0)
- ret += nr_plt;
+ if (ret > 0) {
+ int nr_plt = dso__synthesize_plt_symbols(self, map, filter);
+ if (nr_plt > 0)
+ ret += nr_plt;
+ break;
+ }
}
-out:
+
free(name);
if (ret < 0 && strstr(self->name, " (deleted)") != NULL)
return 0;
@@ -1494,6 +1576,7 @@ static int map_groups__set_modules_path_dir(struct map_groups *self,
goto out;
}
dso__set_long_name(map->dso, long_name);
+ map->dso->lname_alloc = 1;
dso__kernel_module_get_build_id(map->dso, "");
}
}
@@ -1656,36 +1739,12 @@ static int dso__load_vmlinux(struct dso *self, struct map *map,
{
int err = -1, fd;
- if (self->has_build_id) {
- u8 build_id[BUILD_ID_SIZE];
-
- if (filename__read_build_id(vmlinux, build_id,
- sizeof(build_id)) < 0) {
- pr_debug("No build_id in %s, ignoring it\n", vmlinux);
- return -1;
- }
- if (!dso__build_id_equal(self, build_id)) {
- char expected_build_id[BUILD_ID_SIZE * 2 + 1],
- vmlinux_build_id[BUILD_ID_SIZE * 2 + 1];
-
- build_id__sprintf(self->build_id,
- sizeof(self->build_id),
- expected_build_id);
- build_id__sprintf(build_id, sizeof(build_id),
- vmlinux_build_id);
- pr_debug("build_id in %s is %s while expected is %s, "
- "ignoring it\n", vmlinux, vmlinux_build_id,
- expected_build_id);
- return -1;
- }
- }
-
fd = open(vmlinux, O_RDONLY);
if (fd < 0)
return -1;
dso__set_loaded(self, map->type);
- err = dso__load_sym(self, map, vmlinux, fd, filter, 0);
+ err = dso__load_sym(self, map, vmlinux, fd, filter, 0, 0);
close(fd);
if (err > 0)
@@ -2048,6 +2107,36 @@ int __machine__create_kernel_maps(struct machine *self, struct dso *kernel)
return 0;
}
+void machine__destroy_kernel_maps(struct machine *self)
+{
+ enum map_type type;
+
+ for (type = 0; type < MAP__NR_TYPES; ++type) {
+ struct kmap *kmap;
+
+ if (self->vmlinux_maps[type] == NULL)
+ continue;
+
+ kmap = map__kmap(self->vmlinux_maps[type]);
+ map_groups__remove(&self->kmaps, self->vmlinux_maps[type]);
+ if (kmap->ref_reloc_sym) {
+ /*
+ * ref_reloc_sym is shared among all maps, so free just
+ * on one of them.
+ */
+ if (type == MAP__FUNCTION) {
+ free((char *)kmap->ref_reloc_sym->name);
+ kmap->ref_reloc_sym->name = NULL;
+ free(kmap->ref_reloc_sym);
+ }
+ kmap->ref_reloc_sym = NULL;
+ }
+
+ map__delete(self->vmlinux_maps[type]);
+ self->vmlinux_maps[type] = NULL;
+ }
+}
+
int machine__create_kernel_maps(struct machine *self)
{
struct dso *kernel = machine__create_kernel(self);
@@ -2189,6 +2278,15 @@ out_free_comm_list:
return -1;
}
+void symbol__exit(void)
+{
+ strlist__delete(symbol_conf.sym_list);
+ strlist__delete(symbol_conf.dso_list);
+ strlist__delete(symbol_conf.comm_list);
+ vmlinux_path__exit();
+ symbol_conf.sym_list = symbol_conf.dso_list = symbol_conf.comm_list = NULL;
+}
+
int machines__create_kernel_maps(struct rb_root *self, pid_t pid)
{
struct machine *machine = machines__findnew(self, pid);
@@ -2283,6 +2381,19 @@ failure:
return ret;
}
+void machines__destroy_guest_kernel_maps(struct rb_root *self)
+{
+ struct rb_node *next = rb_first(self);
+
+ while (next) {
+ struct machine *pos = rb_entry(next, struct machine, rb_node);
+
+ next = rb_next(&pos->rb_node);
+ rb_erase(&pos->rb_node, self);
+ machine__delete(pos);
+ }
+}
+
int machine__load_kallsyms(struct machine *self, const char *filename,
enum map_type type, symbol_filter_t filter)
{
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index 5e02d2c1715..906be20011d 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -9,8 +9,6 @@
#include <linux/rbtree.h>
#include <stdio.h>
-#define DEBUG_CACHE_DIR ".debug"
-
#ifdef HAVE_CPLUS_DEMANGLE
extern char *cplus_demangle(const char *, int);
@@ -70,9 +68,9 @@ struct symbol_conf {
show_nr_samples,
use_callchain,
exclude_other,
- full_paths,
show_cpu_utilization;
const char *vmlinux_name,
+ *source_prefix,
*field_sep;
const char *default_guest_vmlinux_name,
*default_guest_kallsyms,
@@ -103,6 +101,8 @@ struct ref_reloc_sym {
struct map_symbol {
struct map *map;
struct symbol *sym;
+ bool unfolded;
+ bool has_children;
};
struct addr_location {
@@ -112,7 +112,8 @@ struct addr_location {
u64 addr;
char level;
bool filtered;
- unsigned int cpumode;
+ u8 cpumode;
+ s32 cpu;
};
enum dso_kernel_type {
@@ -125,12 +126,14 @@ struct dso {
struct list_head node;
struct rb_root symbols[MAP__NR_TYPES];
struct rb_root symbol_names[MAP__NR_TYPES];
+ enum dso_kernel_type kernel;
u8 adjust_symbols:1;
u8 slen_calculated:1;
u8 has_build_id:1;
- enum dso_kernel_type kernel;
u8 hit:1;
u8 annotate_warned:1;
+ u8 sname_alloc:1;
+ u8 lname_alloc:1;
unsigned char origin;
u8 sorted_by_name;
u8 loaded;
@@ -146,6 +149,8 @@ struct dso *dso__new(const char *name);
struct dso *dso__new_kernel(const char *name);
void dso__delete(struct dso *self);
+int dso__name_len(const struct dso *self);
+
bool dso__loaded(const struct dso *self, enum map_type type);
bool dso__sorted_by_name(const struct dso *self, enum map_type type);
@@ -207,13 +212,16 @@ int kallsyms__parse(const char *filename, void *arg,
int (*process_symbol)(void *arg, const char *name,
char type, u64 start));
+void machine__destroy_kernel_maps(struct machine *self);
int __machine__create_kernel_maps(struct machine *self, struct dso *kernel);
int machine__create_kernel_maps(struct machine *self);
int machines__create_kernel_maps(struct rb_root *self, pid_t pid);
int machines__create_guest_kernel_maps(struct rb_root *self);
+void machines__destroy_guest_kernel_maps(struct rb_root *self);
int symbol__init(void);
+void symbol__exit(void);
bool symbol_type__is_a(char symbol_type, enum map_type map_type);
size_t machine__fprintf_vmlinux_path(struct machine *self, FILE *fp);
diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c
index 9a448b47400..8c72d888e44 100644
--- a/tools/perf/util/thread.c
+++ b/tools/perf/util/thread.c
@@ -62,6 +62,13 @@ static struct thread *thread__new(pid_t pid)
return self;
}
+void thread__delete(struct thread *self)
+{
+ map_groups__exit(&self->mg);
+ free(self->comm);
+ free(self);
+}
+
int thread__set_comm(struct thread *self, const char *comm)
{
int err;
diff --git a/tools/perf/util/thread.h b/tools/perf/util/thread.h
index ee6bbcf277c..688500ff826 100644
--- a/tools/perf/util/thread.h
+++ b/tools/perf/util/thread.h
@@ -20,6 +20,8 @@ struct thread {
struct perf_session;
+void thread__delete(struct thread *self);
+
int find_all_tid(int pid, pid_t ** all_tid);
int thread__set_comm(struct thread *self, const char *comm);
int thread__comm_len(struct thread *self);
diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h
index 4e8b6b0c551..f380fed7435 100644
--- a/tools/perf/util/util.h
+++ b/tools/perf/util/util.h
@@ -89,6 +89,7 @@
extern const char *graph_line;
extern const char *graph_dotted_line;
+extern char buildid_dir[];
/* On most systems <limits.h> would have given us this, but
* not on some systems (e.g. GNU/Hurd).
@@ -152,6 +153,8 @@ extern void warning(const char *err, ...) __attribute__((format (printf, 1, 2)))
extern void set_die_routine(void (*routine)(const char *err, va_list params) NORETURN);
extern int prefixcmp(const char *str, const char *prefix);
+extern void set_buildid_dir(void);
+extern void disable_buildid_cache(void);
static inline const char *skip_prefix(const char *str, const char *prefix)
{
diff --git a/virt/kvm/assigned-dev.c b/virt/kvm/assigned-dev.c
index 4d10b1e047f..7c98928b09d 100644
--- a/virt/kvm/assigned-dev.c
+++ b/virt/kvm/assigned-dev.c
@@ -1,7 +1,7 @@
/*
* Kernel-based Virtual Machine - device assignment support
*
- * Copyright (C) 2006-9 Red Hat, Inc
+ * Copyright (C) 2010 Red Hat, Inc. and/or its affiliates.
*
* This work is licensed under the terms of the GNU GPL, version 2. See
* the COPYING file in the top-level directory.
@@ -58,12 +58,10 @@ static int find_index_from_host_irq(struct kvm_assigned_dev_kernel
static void kvm_assigned_dev_interrupt_work_handler(struct work_struct *work)
{
struct kvm_assigned_dev_kernel *assigned_dev;
- struct kvm *kvm;
int i;
assigned_dev = container_of(work, struct kvm_assigned_dev_kernel,
interrupt_work);
- kvm = assigned_dev->kvm;
spin_lock_irq(&assigned_dev->assigned_dev_lock);
if (assigned_dev->irq_requested_type & KVM_DEV_IRQ_HOST_MSIX) {
@@ -448,9 +446,6 @@ static int kvm_vm_ioctl_assign_irq(struct kvm *kvm,
struct kvm_assigned_dev_kernel *match;
unsigned long host_irq_type, guest_irq_type;
- if (!capable(CAP_SYS_RAWIO))
- return -EPERM;
-
if (!irqchip_in_kernel(kvm))
return r;
diff --git a/virt/kvm/coalesced_mmio.c b/virt/kvm/coalesced_mmio.c
index 53850177163..fc8487564d1 100644
--- a/virt/kvm/coalesced_mmio.c
+++ b/virt/kvm/coalesced_mmio.c
@@ -2,6 +2,7 @@
* KVM coalesced MMIO
*
* Copyright (c) 2008 Bull S.A.S.
+ * Copyright 2009 Red Hat, Inc. and/or its affiliates.
*
* Author: Laurent Vivier <Laurent.Vivier@bull.net>
*
diff --git a/virt/kvm/eventfd.c b/virt/kvm/eventfd.c
index b81f0ebbaaa..66cf65b510b 100644
--- a/virt/kvm/eventfd.c
+++ b/virt/kvm/eventfd.c
@@ -2,6 +2,7 @@
* kvm eventfd support - use eventfd objects to signal various KVM events
*
* Copyright 2009 Novell. All Rights Reserved.
+ * Copyright 2010 Red Hat, Inc. and/or its affiliates.
*
* Author:
* Gregory Haskins <ghaskins@novell.com>
diff --git a/virt/kvm/ioapic.c b/virt/kvm/ioapic.c
index 3500dee9cf2..0b9df8303dc 100644
--- a/virt/kvm/ioapic.c
+++ b/virt/kvm/ioapic.c
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2001 MandrakeSoft S.A.
+ * Copyright 2010 Red Hat, Inc. and/or its affiliates.
*
* MandrakeSoft S.A.
* 43, rue d'Aboukir
@@ -151,7 +152,7 @@ static void ioapic_write_indirect(struct kvm_ioapic *ioapic, u32 val)
update_handled_vectors(ioapic);
mask_after = e->fields.mask;
if (mask_before != mask_after)
- kvm_fire_mask_notifiers(ioapic->kvm, index, mask_after);
+ kvm_fire_mask_notifiers(ioapic->kvm, KVM_IRQCHIP_IOAPIC, index, mask_after);
if (e->fields.trig_mode == IOAPIC_LEVEL_TRIG
&& ioapic->irr & (1 << index))
ioapic_service(ioapic, index);
diff --git a/virt/kvm/iommu.c b/virt/kvm/iommu.c
index 96048ee9e39..62a9caf0563 100644
--- a/virt/kvm/iommu.c
+++ b/virt/kvm/iommu.c
@@ -16,6 +16,8 @@
*
* Copyright (C) 2006-2008 Intel Corporation
* Copyright IBM Corporation, 2008
+ * Copyright 2010 Red Hat, Inc. and/or its affiliates.
+ *
* Author: Allen M. Kay <allen.m.kay@intel.com>
* Author: Weidong Han <weidong.han@intel.com>
* Author: Ben-Ami Yassour <benami@il.ibm.com>
@@ -106,7 +108,7 @@ int kvm_iommu_map_pages(struct kvm *kvm, struct kvm_memory_slot *slot)
get_order(page_size), flags);
if (r) {
printk(KERN_ERR "kvm_iommu_map_address:"
- "iommu failed to map pfn=%lx\n", pfn);
+ "iommu failed to map pfn=%llx\n", pfn);
goto unmap_pages;
}
@@ -124,9 +126,10 @@ unmap_pages:
static int kvm_iommu_map_memslots(struct kvm *kvm)
{
- int i, r = 0;
+ int i, idx, r = 0;
struct kvm_memslots *slots;
+ idx = srcu_read_lock(&kvm->srcu);
slots = kvm_memslots(kvm);
for (i = 0; i < slots->nmemslots; i++) {
@@ -134,6 +137,7 @@ static int kvm_iommu_map_memslots(struct kvm *kvm)
if (r)
break;
}
+ srcu_read_unlock(&kvm->srcu, idx);
return r;
}
@@ -283,15 +287,17 @@ static void kvm_iommu_put_pages(struct kvm *kvm,
static int kvm_iommu_unmap_memslots(struct kvm *kvm)
{
- int i;
+ int i, idx;
struct kvm_memslots *slots;
+ idx = srcu_read_lock(&kvm->srcu);
slots = kvm_memslots(kvm);
for (i = 0; i < slots->nmemslots; i++) {
kvm_iommu_put_pages(kvm, slots->memslots[i].base_gfn,
slots->memslots[i].npages);
}
+ srcu_read_unlock(&kvm->srcu, idx);
return 0;
}
diff --git a/virt/kvm/irq_comm.c b/virt/kvm/irq_comm.c
index a0e88809e45..369e38010ad 100644
--- a/virt/kvm/irq_comm.c
+++ b/virt/kvm/irq_comm.c
@@ -17,6 +17,7 @@
* Authors:
* Yaozu (Eddie) Dong <Eddie.dong@intel.com>
*
+ * Copyright 2010 Red Hat, Inc. and/or its affilates.
*/
#include <linux/kvm_host.h>
@@ -99,7 +100,7 @@ int kvm_irq_delivery_to_apic(struct kvm *kvm, struct kvm_lapic *src,
if (r < 0)
r = 0;
r += kvm_apic_set_irq(vcpu, irq);
- } else {
+ } else if (kvm_lapic_enabled(vcpu)) {
if (!lowest)
lowest = vcpu;
else if (kvm_apic_compare_prio(vcpu, lowest) < 0)
@@ -278,15 +279,19 @@ void kvm_unregister_irq_mask_notifier(struct kvm *kvm, int irq,
synchronize_rcu();
}
-void kvm_fire_mask_notifiers(struct kvm *kvm, int irq, bool mask)
+void kvm_fire_mask_notifiers(struct kvm *kvm, unsigned irqchip, unsigned pin,
+ bool mask)
{
struct kvm_irq_mask_notifier *kimn;
struct hlist_node *n;
+ int gsi;
rcu_read_lock();
- hlist_for_each_entry_rcu(kimn, n, &kvm->mask_notifier_list, link)
- if (kimn->irq == irq)
- kimn->func(kimn, mask);
+ gsi = rcu_dereference(kvm->irq_routing)->chip[irqchip][pin];
+ if (gsi != -1)
+ hlist_for_each_entry_rcu(kimn, n, &kvm->mask_notifier_list, link)
+ if (kimn->irq == gsi)
+ kimn->func(kimn, mask);
rcu_read_unlock();
}
diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
index f032806a212..b78b794c103 100644
--- a/virt/kvm/kvm_main.c
+++ b/virt/kvm/kvm_main.c
@@ -5,6 +5,7 @@
* machines without emulation or binary translation.
*
* Copyright (C) 2006 Qumranet, Inc.
+ * Copyright 2010 Red Hat, Inc. and/or its affilates.
*
* Authors:
* Avi Kivity <avi@qumranet.com>
@@ -92,6 +93,12 @@ static bool kvm_rebooting;
static bool largepages_enabled = true;
+static struct page *hwpoison_page;
+static pfn_t hwpoison_pfn;
+
+static struct page *fault_page;
+static pfn_t fault_pfn;
+
inline int kvm_is_mmio_pfn(pfn_t pfn)
{
if (pfn_valid(pfn)) {
@@ -141,7 +148,7 @@ static bool make_all_cpus_request(struct kvm *kvm, unsigned int req)
raw_spin_lock(&kvm->requests_lock);
me = smp_processor_id();
kvm_for_each_vcpu(i, vcpu, kvm) {
- if (test_and_set_bit(req, &vcpu->requests))
+ if (kvm_make_check_request(req, vcpu))
continue;
cpu = vcpu->cpu;
if (cpus != NULL && cpu != -1 && cpu != me)
@@ -566,6 +573,7 @@ int __kvm_set_memory_region(struct kvm *kvm,
new = old = *memslot;
+ new.id = mem->slot;
new.base_gfn = base_gfn;
new.npages = npages;
new.flags = mem->flags;
@@ -596,7 +604,7 @@ int __kvm_set_memory_region(struct kvm *kvm,
/* Allocate if a slot is being created */
#ifndef CONFIG_S390
if (npages && !new.rmap) {
- new.rmap = vmalloc(npages * sizeof(struct page *));
+ new.rmap = vmalloc(npages * sizeof(*new.rmap));
if (!new.rmap)
goto out_free;
@@ -621,9 +629,9 @@ int __kvm_set_memory_region(struct kvm *kvm,
if (new.lpage_info[i])
continue;
- lpages = 1 + (base_gfn + npages - 1) /
- KVM_PAGES_PER_HPAGE(level);
- lpages -= base_gfn / KVM_PAGES_PER_HPAGE(level);
+ lpages = 1 + ((base_gfn + npages - 1)
+ >> KVM_HPAGE_GFN_SHIFT(level));
+ lpages -= base_gfn >> KVM_HPAGE_GFN_SHIFT(level);
new.lpage_info[i] = vmalloc(lpages * sizeof(*new.lpage_info[i]));
@@ -633,9 +641,9 @@ int __kvm_set_memory_region(struct kvm *kvm,
memset(new.lpage_info[i], 0,
lpages * sizeof(*new.lpage_info[i]));
- if (base_gfn % KVM_PAGES_PER_HPAGE(level))
+ if (base_gfn & (KVM_PAGES_PER_HPAGE(level) - 1))
new.lpage_info[i][0].write_count = 1;
- if ((base_gfn+npages) % KVM_PAGES_PER_HPAGE(level))
+ if ((base_gfn+npages) & (KVM_PAGES_PER_HPAGE(level) - 1))
new.lpage_info[i][lpages - 1].write_count = 1;
ugfn = new.userspace_addr >> PAGE_SHIFT;
/*
@@ -810,16 +818,28 @@ EXPORT_SYMBOL_GPL(kvm_disable_largepages);
int is_error_page(struct page *page)
{
- return page == bad_page;
+ return page == bad_page || page == hwpoison_page || page == fault_page;
}
EXPORT_SYMBOL_GPL(is_error_page);
int is_error_pfn(pfn_t pfn)
{
- return pfn == bad_pfn;
+ return pfn == bad_pfn || pfn == hwpoison_pfn || pfn == fault_pfn;
}
EXPORT_SYMBOL_GPL(is_error_pfn);
+int is_hwpoison_pfn(pfn_t pfn)
+{
+ return pfn == hwpoison_pfn;
+}
+EXPORT_SYMBOL_GPL(is_hwpoison_pfn);
+
+int is_fault_pfn(pfn_t pfn)
+{
+ return pfn == fault_pfn;
+}
+EXPORT_SYMBOL_GPL(is_fault_pfn);
+
static inline unsigned long bad_hva(void)
{
return PAGE_OFFSET;
@@ -831,7 +851,7 @@ int kvm_is_error_hva(unsigned long addr)
}
EXPORT_SYMBOL_GPL(kvm_is_error_hva);
-struct kvm_memory_slot *gfn_to_memslot_unaliased(struct kvm *kvm, gfn_t gfn)
+struct kvm_memory_slot *gfn_to_memslot(struct kvm *kvm, gfn_t gfn)
{
int i;
struct kvm_memslots *slots = kvm_memslots(kvm);
@@ -845,20 +865,13 @@ struct kvm_memory_slot *gfn_to_memslot_unaliased(struct kvm *kvm, gfn_t gfn)
}
return NULL;
}
-EXPORT_SYMBOL_GPL(gfn_to_memslot_unaliased);
-
-struct kvm_memory_slot *gfn_to_memslot(struct kvm *kvm, gfn_t gfn)
-{
- gfn = unalias_gfn(kvm, gfn);
- return gfn_to_memslot_unaliased(kvm, gfn);
-}
+EXPORT_SYMBOL_GPL(gfn_to_memslot);
int kvm_is_visible_gfn(struct kvm *kvm, gfn_t gfn)
{
int i;
struct kvm_memslots *slots = kvm_memslots(kvm);
- gfn = unalias_gfn_instantiation(kvm, gfn);
for (i = 0; i < KVM_MEMORY_SLOTS; ++i) {
struct kvm_memory_slot *memslot = &slots->memslots[i];
@@ -903,7 +916,6 @@ int memslot_id(struct kvm *kvm, gfn_t gfn)
struct kvm_memslots *slots = kvm_memslots(kvm);
struct kvm_memory_slot *memslot = NULL;
- gfn = unalias_gfn(kvm, gfn);
for (i = 0; i < slots->nmemslots; ++i) {
memslot = &slots->memslots[i];
@@ -924,8 +936,7 @@ unsigned long gfn_to_hva(struct kvm *kvm, gfn_t gfn)
{
struct kvm_memory_slot *slot;
- gfn = unalias_gfn_instantiation(kvm, gfn);
- slot = gfn_to_memslot_unaliased(kvm, gfn);
+ slot = gfn_to_memslot(kvm, gfn);
if (!slot || slot->flags & KVM_MEMSLOT_INVALID)
return bad_hva();
return gfn_to_hva_memslot(slot, gfn);
@@ -946,13 +957,19 @@ static pfn_t hva_to_pfn(struct kvm *kvm, unsigned long addr)
struct vm_area_struct *vma;
down_read(&current->mm->mmap_sem);
+ if (is_hwpoison_address(addr)) {
+ up_read(&current->mm->mmap_sem);
+ get_page(hwpoison_page);
+ return page_to_pfn(hwpoison_page);
+ }
+
vma = find_vma(current->mm, addr);
if (vma == NULL || addr < vma->vm_start ||
!(vma->vm_flags & VM_PFNMAP)) {
up_read(&current->mm->mmap_sem);
- get_page(bad_page);
- return page_to_pfn(bad_page);
+ get_page(fault_page);
+ return page_to_pfn(fault_page);
}
pfn = ((addr - vma->vm_start) >> PAGE_SHIFT) + vma->vm_pgoff;
@@ -1187,8 +1204,7 @@ void mark_page_dirty(struct kvm *kvm, gfn_t gfn)
{
struct kvm_memory_slot *memslot;
- gfn = unalias_gfn(kvm, gfn);
- memslot = gfn_to_memslot_unaliased(kvm, gfn);
+ memslot = gfn_to_memslot(kvm, gfn);
if (memslot && memslot->dirty_bitmap) {
unsigned long rel_gfn = gfn - memslot->base_gfn;
@@ -1207,7 +1223,7 @@ void kvm_vcpu_block(struct kvm_vcpu *vcpu)
prepare_to_wait(&vcpu->wq, &wait, TASK_INTERRUPTIBLE);
if (kvm_arch_vcpu_runnable(vcpu)) {
- set_bit(KVM_REQ_UNHALT, &vcpu->requests);
+ kvm_make_request(KVM_REQ_UNHALT, vcpu);
break;
}
if (kvm_cpu_has_pending_timer(vcpu))
@@ -1378,6 +1394,18 @@ static long kvm_vcpu_ioctl(struct file *filp,
if (vcpu->kvm->mm != current->mm)
return -EIO;
+
+#if defined(CONFIG_S390) || defined(CONFIG_PPC)
+ /*
+ * Special cases: vcpu ioctls that are asynchronous to vcpu execution,
+ * so vcpu_load() would break it.
+ */
+ if (ioctl == KVM_S390_INTERRUPT || ioctl == KVM_INTERRUPT)
+ return kvm_arch_vcpu_ioctl(filp, ioctl, arg);
+#endif
+
+
+ vcpu_load(vcpu);
switch (ioctl) {
case KVM_RUN:
r = -EINVAL;
@@ -1520,7 +1548,7 @@ out_free2:
goto out;
p = &sigset;
}
- r = kvm_vcpu_ioctl_set_sigmask(vcpu, &sigset);
+ r = kvm_vcpu_ioctl_set_sigmask(vcpu, p);
break;
}
case KVM_GET_FPU: {
@@ -1555,6 +1583,7 @@ out_free2:
r = kvm_arch_vcpu_ioctl(filp, ioctl, arg);
}
out:
+ vcpu_put(vcpu);
kfree(fpu);
kfree(kvm_sregs);
return r;
@@ -2197,6 +2226,24 @@ int kvm_init(void *opaque, unsigned vcpu_size, unsigned vcpu_align,
bad_pfn = page_to_pfn(bad_page);
+ hwpoison_page = alloc_page(GFP_KERNEL | __GFP_ZERO);
+
+ if (hwpoison_page == NULL) {
+ r = -ENOMEM;
+ goto out_free_0;
+ }
+
+ hwpoison_pfn = page_to_pfn(hwpoison_page);
+
+ fault_page = alloc_page(GFP_KERNEL | __GFP_ZERO);
+
+ if (fault_page == NULL) {
+ r = -ENOMEM;
+ goto out_free_0;
+ }
+
+ fault_pfn = page_to_pfn(fault_page);
+
if (!zalloc_cpumask_var(&cpus_hardware_enabled, GFP_KERNEL)) {
r = -ENOMEM;
goto out_free_0;
@@ -2269,6 +2316,10 @@ out_free_1:
out_free_0a:
free_cpumask_var(cpus_hardware_enabled);
out_free_0:
+ if (fault_page)
+ __free_page(fault_page);
+ if (hwpoison_page)
+ __free_page(hwpoison_page);
__free_page(bad_page);
out:
kvm_arch_exit();
@@ -2290,6 +2341,7 @@ void kvm_exit(void)
kvm_arch_hardware_unsetup();
kvm_arch_exit();
free_cpumask_var(cpus_hardware_enabled);
+ __free_page(hwpoison_page);
__free_page(bad_page);
}
EXPORT_SYMBOL_GPL(kvm_exit);